From c54fd17e7285020aa9b05a166da1456296517750 Mon Sep 17 00:00:00 2001 From: CentOS Sources Date: Apr 10 2018 05:37:38 +0000 Subject: import ovmf-20171011-4.git92d07e48907f.el7 --- diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..61589a9 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +SOURCES/ovmf-92d07e48907f.tar.xz diff --git a/.ovmf.metadata b/.ovmf.metadata new file mode 100644 index 0000000..3c14cca --- /dev/null +++ b/.ovmf.metadata @@ -0,0 +1 @@ +b6db0f53d63dd71dae3c6af2696f86ad93b1c450 SOURCES/ovmf-92d07e48907f.tar.xz diff --git a/README.md b/README.md deleted file mode 100644 index 98f42b4..0000000 --- a/README.md +++ /dev/null @@ -1,4 +0,0 @@ -The master branch has no content - -Look at the c7 branch if you are working with CentOS-7, or the c4/c5/c6 branch for CentOS-4, 5 or 6 -If you find this file in a distro specific branch, it means that no content has been checked in yet diff --git a/SOURCES/0002-BuildEnv-override-set-C-noclobber-of-sourcing-env-RH.patch b/SOURCES/0002-BuildEnv-override-set-C-noclobber-of-sourcing-env-RH.patch new file mode 100644 index 0000000..be659b4 --- /dev/null +++ b/SOURCES/0002-BuildEnv-override-set-C-noclobber-of-sourcing-env-RH.patch @@ -0,0 +1,45 @@ +From e4133f594621fa9e8936348f4d0aa4bbd2976d2f Mon Sep 17 00:00:00 2001 +From: Laszlo Ersek +Date: Sun, 8 Jul 2012 11:55:50 +0200 +Subject: BuildEnv: override "set -C" (noclobber) of sourcing env (RHEL only) + +The BuildEnv utility is sourced (executed by the user's interactive shell) +when the user sets up the build session. Some users like to set -C +(noclobber) for some additional safety in their shells, which trips up +BuildEnv. Update the redirection operator so that it overrides noclobber. + +Notes about the c9e5618 -> b9ffeab rebase: + +- Adapted to new BaseTools feature (= out of tree modules). + +Notes about the 20160608b-988715a -> 20170228-c325e41585e3 rebase: + +- no changes + +Notes about the 20170228-c325e41585e3 -> 20171011-92d07e48907f rebase: + +- no changes + +Signed-off-by: Laszlo Ersek +(cherry picked from commit 7df892b6f1c0dead5b177b3866e127b684cdc001) +(cherry picked from commit 06d17db0523920d95fb18b3629f523dcd63d9499) +--- + BaseTools/BuildEnv | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/BaseTools/BuildEnv b/BaseTools/BuildEnv +index f748811..ff0c511 100755 +--- a/BaseTools/BuildEnv ++++ b/BaseTools/BuildEnv +@@ -90,7 +90,7 @@ StoreCurrentConfiguration() { + # + OUTPUT_FILE=$CONF_PATH/BuildEnv.sh + #echo Storing current configuration into $OUTPUT_FILE +- echo "# Auto-generated by ${BASH_SOURCE[0]}" > $OUTPUT_FILE ++ echo "# Auto-generated by ${BASH_SOURCE[0]}" >| $OUTPUT_FILE + GenerateShellCodeToSetVariable WORKSPACE $OUTPUT_FILE + GenerateShellCodeToSetVariable EDK_TOOLS_PATH $OUTPUT_FILE + GenerateShellCodeToUpdatePath $OUTPUT_FILE +-- +1.8.3.1 + diff --git a/SOURCES/0005-setup-the-tree-for-the-secure-boot-feature-RHEL-only.patch b/SOURCES/0005-setup-the-tree-for-the-secure-boot-feature-RHEL-only.patch new file mode 100644 index 0000000..ee3bdbd --- /dev/null +++ b/SOURCES/0005-setup-the-tree-for-the-secure-boot-feature-RHEL-only.patch @@ -0,0 +1,703775 @@ +From ba83defbb1e975ac4ff61e5b58c7d860bc2de614 Mon Sep 17 00:00:00 2001 +From: Laszlo Ersek +Date: Mon, 12 Sep 2016 20:14:35 +0200 +Subject: setup the tree for the secure boot feature (RHEL only) + +The file "CryptoPkg/Library/OpensslLib/Patch-HOWTO.txt" explains how to +download, embed and patch openssl-1.0.2* in edk2. Performing this step is +necessary for the secure boot feature. + +While it can be easily automated in (S)RPM build scripts, for the exploded +git repo it's best to include openssl in advance -- this way setting up an +interactive build session remains fast and lightweight. The patch follows +the instructions of "CryptoPkg/Library/OpensslLib/Patch-HOWTO.txt" and +captures the result in git. + +*** Notes wrt. the a618eaa -> 3facc08 rebase: + +- upstream updated from openssl-0.9.8w to openssl-0.9.8za in commit + a6908c9, take it into account here. + +*** Notes wrt. the 3facc08 -> 9ece15a rebase: + +- upstream updated from openssl-0.9.8za to openssl-0.9.8zb in commit + f61d69c, take it into account here. + +*** Notes wrt. the 9ece15a -> c9e5618 rebase: + +- upstream updated from openssl-0.9.8zb to openssl-0.9.8zf. + +*** Notes wrt. the c9e5618 -> b9ffeab rebase: + +- upstream updated from openssl-0.9.8zf to openssl-1.0.2d. + +*** Notes wrt. the b9ffeab -> d7c0dfa rebase: + +- upstream updated from openssl-1.0.2d to openssl-1.0.2e. + +*** Notes wrt. the d7c0dfa -> 90bb4c5 rebase: + +- upstream updated from openssl-1.0.2e to openssl-1.0.2g. + +*** Notes wrt. the downstream-only "rhel7master-20160608-988715a" --> + "rhel7master-20160608b-988715a" rebase (note the character "b" after + "20160608"), in reference to + : + +- This rebase does not affect the fork-off point from the upstream git + history; it remains 988715a. + +- This patch replaces the identically titled downstream-only commit + dde83a75b566. The reason is that we can't distribute pristine upstream + OpenSSL tarballs, given that some files in those tarballs are + patent-encumbered. Instead, we do the following, all in this same one + patch (so that OpenSSL embedding remains one atomic patch): + + * Step 1 of "CryptoPkg/Library/OpensslLib/Patch-HOWTO.txt" (i.e., the + downloading of the OpenSSL tarball) is replaced by the following + steps, in a separate directory. The goal is to embed / flatten + Fedora's pre-sanitized OpenSSL tarball from the "openssl" dist-git + tree rather than the upstream tarball: + + fedpkg clone -a openssl + + cd openssl + + fedpkg switch-branch master + + gitk -- sources + + Locate the oldest (chronologically first) dist-git commit that imports + the "hobbled" OpenSSL tarball matching edk2's OpenSSL version + requirement (1.0.2g). In this case, it is dist-git commit + + e7a0ff581f42 minor upstream release 1.0.2g fixing security issues + + Download and verify the matching hobbled 1.0.2g tarball: + + git checkout e7a0ff581f42 + ( + set -e + while read HASH FN; do + wget \ + http://pkgs.fedoraproject.org/repo/pkgs/openssl/$FN/$HASH/$FN + done 20170228-c325e41585e3 rebase: + +- Upstream has moved from 1.0.2g to 1.0.2k (see 14e3b94964ae, + "CryptoPkg/OpensslLib: Upgrade OpenSSL version to 1.0.2k", 2017-02-27, + and other similar commits in the 988715a..c325e41585e3 range), hence + this patch replaces the following downstream-only commits / modified + backports: + + - a1066aaf3ff4 setup the tree for the secure boot feature (RHEL only) + (which flattened 1.0.2g) + + - 180eb313bb44 CryptoPkg/OpensslLib: Upgrade OpenSSL version to 1.0.2h + (which flattened 1.0.2h) + +- The hobbling procedure is the same as above, under the last rebase to + 20160608b-988715a, with the following modifications: + + - Fedora's master branch no longer uses the 1.0.2* stream of OpenSSL (it + has switched to 1.1.0*), thus the hobbled 1.0.2k tarball is taken from + the following commit on the "f25" branch: + + c914702332cf Upload the new version of sources. + + - In addition, the tarball download / verification can either be done + with "fedkpkg sources", or else with wget + "sha512sum -c sources", + because Fedora has switched to SHA512 checksums. + +*** Notes about the 20170228-c325e41585e3 -> 20171011-92d07e48907f rebase: + +- In commit range 2ed235fc296b..113581e6f32d, upstream edk2 received + significant changes for OpenSSL: + + - the currently supported OpenSSL version is 1.1.0e; + + - edk2-side patching of OpenSSL no longer occurs, all edk2-related + patches have been merged into OpenSSL; + + - the new instructions are described in + "CryptoPkg/Library/OpensslLib/OpenSSL-HOWTO.txt" + +- For importing the hobbled OpenSSL tarball from Fedora, the following + steps are necessary. Note that both the "sources" file format and the + pkgs.fedoraproject.org directory structure have changed, accommodating + SHA512 checksums. + + # in a separate directory + fedpkg clone -a openssl + cd openssl + fedpkg switch-branch master + gitk -- sources + + # the commit that added the 1.1.0e hobbled tarball is c676ac32d544, + # subject "update to upstream version 1.1.0e" + git checkout c676ac32d544 + + # fetch the hobbled tarball and verify the checksum + ( + set -e + while read HASH_TYPE FN EQ HASH; do + # remove leading and trailing parens + FN="${FN#(*}" + FN="${FN%*)}" + wget \ + http://pkgs.fedoraproject.org/repo/pkgs/openssl/$FN/sha512/$HASH/$FN + done +--- + .../Library/OpensslLib/openssl/.gitattributes | 3 + + CryptoPkg/Library/OpensslLib/openssl/.gitignore | 178 + + .../OpensslLib/openssl/.travis-create-release.sh | 11 + + CryptoPkg/Library/OpensslLib/openssl/.travis.yml | 152 + + .../Library/OpensslLib/openssl/ACKNOWLEDGEMENTS | 2 + + CryptoPkg/Library/OpensslLib/openssl/AUTHORS | 21 + + CryptoPkg/Library/OpensslLib/openssl/CHANGES | 12454 +++++++++++++++++++ + CryptoPkg/Library/OpensslLib/openssl/CONTRIBUTING | 54 + + .../openssl/Configurations/00-base-templates.conf | 293 + + .../OpensslLib/openssl/Configurations/10-main.conf | 1894 +++ + .../openssl/Configurations/50-djgpp.conf | 15 + + .../openssl/Configurations/50-haiku.conf | 29 + + .../OpensslLib/openssl/Configurations/50-masm.conf | 17 + + .../OpensslLib/openssl/Configurations/90-team.conf | 112 + + .../openssl/Configurations/INTERNALS.Configure | 136 + + .../OpensslLib/openssl/Configurations/README | 655 + + .../openssl/Configurations/README.design | 641 + + .../OpensslLib/openssl/Configurations/common.tmpl | 231 + + .../openssl/Configurations/descrip.mms.tmpl | 767 ++ + .../openssl/Configurations/unix-Makefile.tmpl | 1124 ++ + .../openssl/Configurations/windows-makefile.tmpl | 601 + + CryptoPkg/Library/OpensslLib/openssl/Configure | 2766 ++++ + CryptoPkg/Library/OpensslLib/openssl/FAQ | 2 + + CryptoPkg/Library/OpensslLib/openssl/INSTALL | 951 ++ + CryptoPkg/Library/OpensslLib/openssl/LICENSE | 125 + + .../Library/OpensslLib/openssl/Makefile.shared | 622 + + CryptoPkg/Library/OpensslLib/openssl/NEWS | 852 ++ + CryptoPkg/Library/OpensslLib/openssl/NOTES.DJGPP | 48 + + CryptoPkg/Library/OpensslLib/openssl/NOTES.PERL | 119 + + CryptoPkg/Library/OpensslLib/openssl/NOTES.VMS | 81 + + CryptoPkg/Library/OpensslLib/openssl/NOTES.WIN | 138 + + CryptoPkg/Library/OpensslLib/openssl/README | 94 + + CryptoPkg/Library/OpensslLib/openssl/README.ECC | 61 + + CryptoPkg/Library/OpensslLib/openssl/README.ENGINE | 288 + + CryptoPkg/Library/OpensslLib/openssl/README.FIPS | 1 + + .../Library/OpensslLib/openssl/VMS/VMSify-conf.pl | 41 + + .../Library/OpensslLib/openssl/VMS/engine.opt | 2 + + .../OpensslLib/openssl/VMS/openssl_ivp.com.in | 50 + + .../OpensslLib/openssl/VMS/openssl_shutdown.com.in | 56 + + .../OpensslLib/openssl/VMS/openssl_startup.com.in | 123 + + .../OpensslLib/openssl/VMS/openssl_utils.com.in | 14 + + .../OpensslLib/openssl/VMS/test-includes.com | 28 + + .../OpensslLib/openssl/VMS/translatesyms.pl | 62 + + CryptoPkg/Library/OpensslLib/openssl/apps/CA.pl.in | 196 + + .../Library/OpensslLib/openssl/apps/app_rand.c | 115 + + CryptoPkg/Library/OpensslLib/openssl/apps/apps.c | 2653 ++++ + CryptoPkg/Library/OpensslLib/openssl/apps/apps.h | 569 + + .../Library/OpensslLib/openssl/apps/asn1pars.c | 330 + + .../Library/OpensslLib/openssl/apps/build.info | 22 + + .../Library/OpensslLib/openssl/apps/ca-cert.srl | 1 + + .../Library/OpensslLib/openssl/apps/ca-key.pem | 16 + + .../Library/OpensslLib/openssl/apps/ca-req.pem | 11 + + CryptoPkg/Library/OpensslLib/openssl/apps/ca.c | 2565 ++++ + CryptoPkg/Library/OpensslLib/openssl/apps/cert.pem | 11 + + .../Library/OpensslLib/openssl/apps/ciphers.c | 242 + + .../Library/OpensslLib/openssl/apps/client.pem | 52 + + CryptoPkg/Library/OpensslLib/openssl/apps/cms.c | 1294 ++ + CryptoPkg/Library/OpensslLib/openssl/apps/crl.c | 347 + + CryptoPkg/Library/OpensslLib/openssl/apps/crl2p7.c | 216 + + .../OpensslLib/openssl/apps/ct_log_list.cnf | 34 + + .../OpensslLib/openssl/apps/demoCA/cacert.pem | 14 + + .../OpensslLib/openssl/apps/demoCA/index.txt | 39 + + .../openssl/apps/demoCA/private/cakey.pem | 24 + + .../Library/OpensslLib/openssl/apps/demoCA/serial | 1 + + .../openssl/apps/demoSRP/srp_verifier.txt | 6 + + .../openssl/apps/demoSRP/srp_verifier.txt.attr | 1 + + CryptoPkg/Library/OpensslLib/openssl/apps/dgst.c | 480 + + .../Library/OpensslLib/openssl/apps/dh1024.pem | 10 + + .../Library/OpensslLib/openssl/apps/dh2048.pem | 14 + + .../Library/OpensslLib/openssl/apps/dh4096.pem | 19 + + .../Library/OpensslLib/openssl/apps/dhparam.c | 380 + + .../Library/OpensslLib/openssl/apps/dsa-ca.pem | 47 + + .../Library/OpensslLib/openssl/apps/dsa-pca.pem | 47 + + CryptoPkg/Library/OpensslLib/openssl/apps/dsa.c | 262 + + .../Library/OpensslLib/openssl/apps/dsa1024.pem | 9 + + .../Library/OpensslLib/openssl/apps/dsa512.pem | 6 + + CryptoPkg/Library/OpensslLib/openssl/apps/dsap.pem | 6 + + .../Library/OpensslLib/openssl/apps/dsaparam.c | 313 + + CryptoPkg/Library/OpensslLib/openssl/apps/ec.c | 281 + + .../Library/OpensslLib/openssl/apps/ecparam.c | 465 + + CryptoPkg/Library/OpensslLib/openssl/apps/enc.c | 604 + + CryptoPkg/Library/OpensslLib/openssl/apps/engine.c | 445 + + CryptoPkg/Library/OpensslLib/openssl/apps/errstr.c | 67 + + CryptoPkg/Library/OpensslLib/openssl/apps/gendsa.c | 147 + + .../Library/OpensslLib/openssl/apps/genpkey.c | 314 + + CryptoPkg/Library/OpensslLib/openssl/apps/genrsa.c | 192 + + CryptoPkg/Library/OpensslLib/openssl/apps/nseq.c | 113 + + CryptoPkg/Library/OpensslLib/openssl/apps/ocsp.c | 1290 ++ + .../OpensslLib/openssl/apps/openssl-vms.cnf | 346 + + .../Library/OpensslLib/openssl/apps/openssl.c | 695 ++ + .../Library/OpensslLib/openssl/apps/openssl.cnf | 346 + + CryptoPkg/Library/OpensslLib/openssl/apps/opt.c | 977 ++ + CryptoPkg/Library/OpensslLib/openssl/apps/passwd.c | 512 + + .../Library/OpensslLib/openssl/apps/pca-cert.srl | 1 + + .../Library/OpensslLib/openssl/apps/pca-key.pem | 16 + + .../Library/OpensslLib/openssl/apps/pca-req.pem | 11 + + CryptoPkg/Library/OpensslLib/openssl/apps/pkcs12.c | 935 ++ + CryptoPkg/Library/OpensslLib/openssl/apps/pkcs7.c | 197 + + CryptoPkg/Library/OpensslLib/openssl/apps/pkcs8.c | 353 + + CryptoPkg/Library/OpensslLib/openssl/apps/pkey.c | 190 + + .../Library/OpensslLib/openssl/apps/pkeyparam.c | 104 + + .../Library/OpensslLib/openssl/apps/pkeyutl.c | 489 + + CryptoPkg/Library/OpensslLib/openssl/apps/prime.c | 126 + + .../Library/OpensslLib/openssl/apps/privkey.pem | 16 + + CryptoPkg/Library/OpensslLib/openssl/apps/progs.h | 415 + + CryptoPkg/Library/OpensslLib/openssl/apps/progs.pl | 155 + + CryptoPkg/Library/OpensslLib/openssl/apps/rand.c | 132 + + CryptoPkg/Library/OpensslLib/openssl/apps/rehash.c | 480 + + CryptoPkg/Library/OpensslLib/openssl/apps/req.c | 1508 +++ + CryptoPkg/Library/OpensslLib/openssl/apps/req.pem | 11 + + CryptoPkg/Library/OpensslLib/openssl/apps/rsa.c | 310 + + .../Library/OpensslLib/openssl/apps/rsa8192.pem | 101 + + CryptoPkg/Library/OpensslLib/openssl/apps/rsautl.c | 278 + + .../Library/OpensslLib/openssl/apps/s1024key.pem | 15 + + .../Library/OpensslLib/openssl/apps/s1024req.pem | 11 + + .../Library/OpensslLib/openssl/apps/s512-key.pem | 9 + + .../Library/OpensslLib/openssl/apps/s512-req.pem | 8 + + CryptoPkg/Library/OpensslLib/openssl/apps/s_apps.h | 102 + + CryptoPkg/Library/OpensslLib/openssl/apps/s_cb.c | 1335 ++ + .../Library/OpensslLib/openssl/apps/s_client.c | 2747 ++++ + .../Library/OpensslLib/openssl/apps/s_server.c | 3301 +++++ + .../Library/OpensslLib/openssl/apps/s_socket.c | 201 + + CryptoPkg/Library/OpensslLib/openssl/apps/s_time.c | 422 + + .../Library/OpensslLib/openssl/apps/server.pem | 52 + + .../Library/OpensslLib/openssl/apps/server.srl | 1 + + .../Library/OpensslLib/openssl/apps/server2.pem | 52 + + .../Library/OpensslLib/openssl/apps/sess_id.c | 190 + + CryptoPkg/Library/OpensslLib/openssl/apps/smime.c | 656 + + CryptoPkg/Library/OpensslLib/openssl/apps/speed.c | 3144 +++++ + CryptoPkg/Library/OpensslLib/openssl/apps/spkac.c | 193 + + CryptoPkg/Library/OpensslLib/openssl/apps/srp.c | 609 + + .../Library/OpensslLib/openssl/apps/testCA.pem | 8 + + .../Library/OpensslLib/openssl/apps/testdsa.h | 290 + + .../Library/OpensslLib/openssl/apps/testrsa.h | 1960 +++ + .../Library/OpensslLib/openssl/apps/timeouts.h | 17 + + CryptoPkg/Library/OpensslLib/openssl/apps/ts.c | 995 ++ + CryptoPkg/Library/OpensslLib/openssl/apps/tsget.in | 201 + + CryptoPkg/Library/OpensslLib/openssl/apps/verify.c | 311 + + .../Library/OpensslLib/openssl/apps/version.c | 140 + + .../OpensslLib/openssl/apps/vms_decc_init.c | 214 + + .../OpensslLib/openssl/apps/vms_term_sock.c | 590 + + .../OpensslLib/openssl/apps/vms_term_sock.h | 30 + + .../Library/OpensslLib/openssl/apps/win32_init.c | 307 + + CryptoPkg/Library/OpensslLib/openssl/apps/x509.c | 1101 ++ + CryptoPkg/Library/OpensslLib/openssl/appveyor.yml | 53 + + CryptoPkg/Library/OpensslLib/openssl/build.info | 41 + + CryptoPkg/Library/OpensslLib/openssl/config | 924 ++ + CryptoPkg/Library/OpensslLib/openssl/config.com | 93 + + .../Library/OpensslLib/openssl/crypto/LPdir_nyi.c | 53 + + .../Library/OpensslLib/openssl/crypto/LPdir_unix.c | 131 + + .../Library/OpensslLib/openssl/crypto/LPdir_vms.c | 204 + + .../Library/OpensslLib/openssl/crypto/LPdir_win.c | 211 + + .../OpensslLib/openssl/crypto/LPdir_win32.c | 38 + + .../OpensslLib/openssl/crypto/LPdir_wince.c | 41 + + .../OpensslLib/openssl/crypto/aes/aes_cbc.c | 24 + + .../OpensslLib/openssl/crypto/aes/aes_cfb.c | 43 + + .../OpensslLib/openssl/crypto/aes/aes_core.c | 1367 ++ + .../OpensslLib/openssl/crypto/aes/aes_ecb.c | 26 + + .../OpensslLib/openssl/crypto/aes/aes_ige.c | 281 + + .../OpensslLib/openssl/crypto/aes/aes_locl.h | 42 + + .../OpensslLib/openssl/crypto/aes/aes_misc.c | 21 + + .../OpensslLib/openssl/crypto/aes/aes_ofb.c | 19 + + .../OpensslLib/openssl/crypto/aes/aes_wrap.c | 27 + + .../OpensslLib/openssl/crypto/aes/aes_x86core.c | 1075 ++ + .../OpensslLib/openssl/crypto/aes/asm/aes-586.pl | 3000 +++++ + .../OpensslLib/openssl/crypto/aes/asm/aes-armv4.pl | 1245 ++ + .../openssl/crypto/aes/asm/aes-c64xplus.pl | 1382 ++ + .../OpensslLib/openssl/crypto/aes/asm/aes-ia64.S | 1130 ++ + .../OpensslLib/openssl/crypto/aes/asm/aes-mips.pl | 2131 ++++ + .../openssl/crypto/aes/asm/aes-parisc.pl | 1029 ++ + .../OpensslLib/openssl/crypto/aes/asm/aes-ppc.pl | 1459 +++ + .../OpensslLib/openssl/crypto/aes/asm/aes-s390x.pl | 2235 ++++ + .../openssl/crypto/aes/asm/aes-sparcv9.pl | 1192 ++ + .../openssl/crypto/aes/asm/aes-x86_64.pl | 2820 +++++ + .../openssl/crypto/aes/asm/aesfx-sparcv9.pl | 1270 ++ + .../openssl/crypto/aes/asm/aesni-mb-x86_64.pl | 1402 +++ + .../openssl/crypto/aes/asm/aesni-sha1-x86_64.pl | 2066 +++ + .../openssl/crypto/aes/asm/aesni-sha256-x86_64.pl | 1713 +++ + .../OpensslLib/openssl/crypto/aes/asm/aesni-x86.pl | 3413 +++++ + .../openssl/crypto/aes/asm/aesni-x86_64.pl | 5060 ++++++++ + .../OpensslLib/openssl/crypto/aes/asm/aesp8-ppc.pl | 3805 ++++++ + .../openssl/crypto/aes/asm/aest4-sparcv9.pl | 929 ++ + .../openssl/crypto/aes/asm/aesv8-armx.pl | 1008 ++ + .../openssl/crypto/aes/asm/bsaes-armv7.pl | 2495 ++++ + .../openssl/crypto/aes/asm/bsaes-x86_64.pl | 3111 +++++ + .../openssl/crypto/aes/asm/vpaes-armv8.pl | 1259 ++ + .../OpensslLib/openssl/crypto/aes/asm/vpaes-ppc.pl | 1594 +++ + .../OpensslLib/openssl/crypto/aes/asm/vpaes-x86.pl | 916 ++ + .../openssl/crypto/aes/asm/vpaes-x86_64.pl | 1215 ++ + .../OpensslLib/openssl/crypto/aes/build.info | 57 + + .../OpensslLib/openssl/crypto/alphacpuid.pl | 257 + + .../OpensslLib/openssl/crypto/arm64cpuid.pl | 126 + + .../Library/OpensslLib/openssl/crypto/arm_arch.h | 83 + + .../Library/OpensslLib/openssl/crypto/armcap.c | 193 + + .../OpensslLib/openssl/crypto/armv4cpuid.pl | 296 + + .../OpensslLib/openssl/crypto/asn1/a_bitstr.c | 210 + + .../OpensslLib/openssl/crypto/asn1/a_d2i_fp.c | 235 + + .../OpensslLib/openssl/crypto/asn1/a_digest.c | 66 + + .../Library/OpensslLib/openssl/crypto/asn1/a_dup.c | 68 + + .../OpensslLib/openssl/crypto/asn1/a_gentm.c | 273 + + .../OpensslLib/openssl/crypto/asn1/a_i2d_fp.c | 108 + + .../Library/OpensslLib/openssl/crypto/asn1/a_int.c | 624 + + .../OpensslLib/openssl/crypto/asn1/a_mbstr.c | 395 + + .../OpensslLib/openssl/crypto/asn1/a_object.c | 370 + + .../OpensslLib/openssl/crypto/asn1/a_octet.c | 29 + + .../OpensslLib/openssl/crypto/asn1/a_print.c | 109 + + .../OpensslLib/openssl/crypto/asn1/a_sign.c | 228 + + .../OpensslLib/openssl/crypto/asn1/a_strex.c | 645 + + .../OpensslLib/openssl/crypto/asn1/a_strnid.c | 287 + + .../OpensslLib/openssl/crypto/asn1/a_time.c | 163 + + .../OpensslLib/openssl/crypto/asn1/a_type.c | 134 + + .../OpensslLib/openssl/crypto/asn1/a_utctm.c | 254 + + .../OpensslLib/openssl/crypto/asn1/a_utf8.c | 188 + + .../OpensslLib/openssl/crypto/asn1/a_verify.c | 182 + + .../OpensslLib/openssl/crypto/asn1/ameth_lib.c | 400 + + .../OpensslLib/openssl/crypto/asn1/asn1_err.c | 267 + + .../OpensslLib/openssl/crypto/asn1/asn1_gen.c | 789 ++ + .../OpensslLib/openssl/crypto/asn1/asn1_lib.c | 384 + + .../OpensslLib/openssl/crypto/asn1/asn1_locl.h | 78 + + .../OpensslLib/openssl/crypto/asn1/asn1_par.c | 375 + + .../OpensslLib/openssl/crypto/asn1/asn_mime.c | 980 ++ + .../OpensslLib/openssl/crypto/asn1/asn_moid.c | 105 + + .../OpensslLib/openssl/crypto/asn1/asn_mstbl.c | 114 + + .../OpensslLib/openssl/crypto/asn1/asn_pack.c | 62 + + .../OpensslLib/openssl/crypto/asn1/bio_asn1.c | 437 + + .../OpensslLib/openssl/crypto/asn1/bio_ndef.c | 199 + + .../OpensslLib/openssl/crypto/asn1/build.info | 16 + + .../OpensslLib/openssl/crypto/asn1/charmap.h | 34 + + .../OpensslLib/openssl/crypto/asn1/charmap.pl | 117 + + .../OpensslLib/openssl/crypto/asn1/d2i_pr.c | 125 + + .../OpensslLib/openssl/crypto/asn1/d2i_pu.c | 78 + + .../OpensslLib/openssl/crypto/asn1/evp_asn1.c | 115 + + .../Library/OpensslLib/openssl/crypto/asn1/f_int.c | 167 + + .../OpensslLib/openssl/crypto/asn1/f_string.c | 148 + + .../OpensslLib/openssl/crypto/asn1/i2d_pr.c | 33 + + .../OpensslLib/openssl/crypto/asn1/i2d_pu.c | 38 + + .../OpensslLib/openssl/crypto/asn1/n_pkey.c | 62 + + .../Library/OpensslLib/openssl/crypto/asn1/nsseq.c | 34 + + .../OpensslLib/openssl/crypto/asn1/p5_pbe.c | 96 + + .../OpensslLib/openssl/crypto/asn1/p5_pbev2.c | 221 + + .../OpensslLib/openssl/crypto/asn1/p5_scrypt.c | 283 + + .../OpensslLib/openssl/crypto/asn1/p8_pkey.c | 80 + + .../OpensslLib/openssl/crypto/asn1/t_bitst.c | 56 + + .../OpensslLib/openssl/crypto/asn1/t_pkey.c | 93 + + .../OpensslLib/openssl/crypto/asn1/t_spki.c | 56 + + .../OpensslLib/openssl/crypto/asn1/tasn_dec.c | 1142 ++ + .../OpensslLib/openssl/crypto/asn1/tasn_enc.c | 605 + + .../OpensslLib/openssl/crypto/asn1/tasn_fre.c | 207 + + .../OpensslLib/openssl/crypto/asn1/tasn_new.c | 337 + + .../OpensslLib/openssl/crypto/asn1/tasn_prn.c | 538 + + .../OpensslLib/openssl/crypto/asn1/tasn_scn.c | 65 + + .../OpensslLib/openssl/crypto/asn1/tasn_typ.c | 84 + + .../OpensslLib/openssl/crypto/asn1/tasn_utl.c | 240 + + .../OpensslLib/openssl/crypto/asn1/x_algor.c | 93 + + .../OpensslLib/openssl/crypto/asn1/x_bignum.c | 146 + + .../OpensslLib/openssl/crypto/asn1/x_info.c | 39 + + .../OpensslLib/openssl/crypto/asn1/x_long.c | 146 + + .../OpensslLib/openssl/crypto/asn1/x_pkey.c | 47 + + .../Library/OpensslLib/openssl/crypto/asn1/x_sig.c | 39 + + .../OpensslLib/openssl/crypto/asn1/x_spki.c | 33 + + .../Library/OpensslLib/openssl/crypto/asn1/x_val.c | 20 + + .../openssl/crypto/async/arch/async_null.c | 23 + + .../openssl/crypto/async/arch/async_null.h | 30 + + .../openssl/crypto/async/arch/async_posix.c | 58 + + .../openssl/crypto/async/arch/async_posix.h | 58 + + .../openssl/crypto/async/arch/async_win.c | 55 + + .../openssl/crypto/async/arch/async_win.h | 36 + + .../OpensslLib/openssl/crypto/async/async.c | 433 + + .../OpensslLib/openssl/crypto/async/async_err.c | 51 + + .../OpensslLib/openssl/crypto/async/async_locl.h | 77 + + .../OpensslLib/openssl/crypto/async/async_wait.c | 211 + + .../OpensslLib/openssl/crypto/async/build.info | 4 + + .../OpensslLib/openssl/crypto/bf/asm/bf-586.pl | 149 + + .../Library/OpensslLib/openssl/crypto/bf/bf_cbc.c | 86 + + .../OpensslLib/openssl/crypto/bf/bf_cfb64.c | 74 + + .../Library/OpensslLib/openssl/crypto/bf/bf_ecb.c | 43 + + .../Library/OpensslLib/openssl/crypto/bf/bf_enc.c | 179 + + .../Library/OpensslLib/openssl/crypto/bf/bf_locl.h | 70 + + .../OpensslLib/openssl/crypto/bf/bf_ofb64.c | 61 + + .../Library/OpensslLib/openssl/crypto/bf/bf_pi.h | 530 + + .../Library/OpensslLib/openssl/crypto/bf/bf_skey.c | 67 + + .../OpensslLib/openssl/crypto/bf/build.info | 6 + + .../Library/OpensslLib/openssl/crypto/bio/b_addr.c | 897 ++ + .../Library/OpensslLib/openssl/crypto/bio/b_dump.c | 158 + + .../OpensslLib/openssl/crypto/bio/b_print.c | 944 ++ + .../Library/OpensslLib/openssl/crypto/bio/b_sock.c | 381 + + .../OpensslLib/openssl/crypto/bio/b_sock2.c | 270 + + .../OpensslLib/openssl/crypto/bio/bf_buff.c | 455 + + .../OpensslLib/openssl/crypto/bio/bf_lbuf.c | 319 + + .../OpensslLib/openssl/crypto/bio/bf_nbio.c | 194 + + .../OpensslLib/openssl/crypto/bio/bf_null.c | 140 + + .../Library/OpensslLib/openssl/crypto/bio/bio_cb.c | 99 + + .../OpensslLib/openssl/crypto/bio/bio_err.c | 125 + + .../OpensslLib/openssl/crypto/bio/bio_lcl.h | 188 + + .../OpensslLib/openssl/crypto/bio/bio_lib.c | 600 + + .../OpensslLib/openssl/crypto/bio/bio_meth.c | 145 + + .../OpensslLib/openssl/crypto/bio/bss_acpt.c | 557 + + .../OpensslLib/openssl/crypto/bio/bss_bio.c | 805 ++ + .../OpensslLib/openssl/crypto/bio/bss_conn.c | 545 + + .../OpensslLib/openssl/crypto/bio/bss_dgram.c | 1944 +++ + .../Library/OpensslLib/openssl/crypto/bio/bss_fd.c | 273 + + .../OpensslLib/openssl/crypto/bio/bss_file.c | 419 + + .../OpensslLib/openssl/crypto/bio/bss_log.c | 406 + + .../OpensslLib/openssl/crypto/bio/bss_mem.c | 347 + + .../OpensslLib/openssl/crypto/bio/bss_null.c | 100 + + .../OpensslLib/openssl/crypto/bio/bss_sock.c | 231 + + .../OpensslLib/openssl/crypto/bio/build.info | 8 + + .../OpensslLib/openssl/crypto/blake2/blake2_impl.h | 130 + + .../OpensslLib/openssl/crypto/blake2/blake2_locl.h | 91 + + .../OpensslLib/openssl/crypto/blake2/blake2b.c | 270 + + .../OpensslLib/openssl/crypto/blake2/blake2s.c | 264 + + .../OpensslLib/openssl/crypto/blake2/build.info | 3 + + .../OpensslLib/openssl/crypto/blake2/m_blake2b.c | 59 + + .../OpensslLib/openssl/crypto/blake2/m_blake2s.c | 59 + + .../OpensslLib/openssl/crypto/bn/README.pod | 247 + + .../OpensslLib/openssl/crypto/bn/asm/alpha-mont.pl | 331 + + .../OpensslLib/openssl/crypto/bn/asm/armv4-gf2m.pl | 332 + + .../OpensslLib/openssl/crypto/bn/asm/armv4-mont.pl | 756 ++ + .../OpensslLib/openssl/crypto/bn/asm/armv8-mont.pl | 1510 +++ + .../OpensslLib/openssl/crypto/bn/asm/bn-586.pl | 785 ++ + .../openssl/crypto/bn/asm/bn-c64xplus.asm | 382 + + .../openssl/crypto/bn/asm/c64xplus-gf2m.pl | 160 + + .../OpensslLib/openssl/crypto/bn/asm/co-586.pl | 298 + + .../OpensslLib/openssl/crypto/bn/asm/ia64-mont.pl | 860 ++ + .../OpensslLib/openssl/crypto/bn/asm/ia64.S | 1562 +++ + .../OpensslLib/openssl/crypto/bn/asm/mips-mont.pl | 433 + + .../OpensslLib/openssl/crypto/bn/asm/mips.pl | 2241 ++++ + .../OpensslLib/openssl/crypto/bn/asm/pa-risc2.s | 1624 +++ + .../OpensslLib/openssl/crypto/bn/asm/pa-risc2W.s | 1612 +++ + .../openssl/crypto/bn/asm/parisc-mont.pl | 1002 ++ + .../OpensslLib/openssl/crypto/bn/asm/ppc-mont.pl | 342 + + .../OpensslLib/openssl/crypto/bn/asm/ppc.pl | 2014 +++ + .../OpensslLib/openssl/crypto/bn/asm/ppc64-mont.pl | 1635 +++ + .../OpensslLib/openssl/crypto/bn/asm/rsaz-avx2.pl | 1968 +++ + .../openssl/crypto/bn/asm/rsaz-x86_64.pl | 2358 ++++ + .../OpensslLib/openssl/crypto/bn/asm/s390x-gf2m.pl | 228 + + .../OpensslLib/openssl/crypto/bn/asm/s390x-mont.pl | 284 + + .../OpensslLib/openssl/crypto/bn/asm/s390x.S | 713 ++ + .../openssl/crypto/bn/asm/sparct4-mont.pl | 1232 ++ + .../OpensslLib/openssl/crypto/bn/asm/sparcv8.S | 1458 +++ + .../OpensslLib/openssl/crypto/bn/asm/sparcv8plus.S | 1562 +++ + .../openssl/crypto/bn/asm/sparcv9-gf2m.pl | 200 + + .../openssl/crypto/bn/asm/sparcv9-mont.pl | 616 + + .../openssl/crypto/bn/asm/sparcv9a-mont.pl | 887 ++ + .../OpensslLib/openssl/crypto/bn/asm/via-mont.pl | 254 + + .../OpensslLib/openssl/crypto/bn/asm/vis3-mont.pl | 384 + + .../OpensslLib/openssl/crypto/bn/asm/x86-gf2m.pl | 325 + + .../OpensslLib/openssl/crypto/bn/asm/x86-mont.pl | 629 + + .../OpensslLib/openssl/crypto/bn/asm/x86.pl | 38 + + .../OpensslLib/openssl/crypto/bn/asm/x86_64-gcc.c | 647 + + .../openssl/crypto/bn/asm/x86_64-gf2m.pl | 397 + + .../openssl/crypto/bn/asm/x86_64-mont.pl | 1521 +++ + .../openssl/crypto/bn/asm/x86_64-mont5.pl | 3827 ++++++ + .../Library/OpensslLib/openssl/crypto/bn/bn_add.c | 205 + + .../Library/OpensslLib/openssl/crypto/bn/bn_asm.c | 1039 ++ + .../OpensslLib/openssl/crypto/bn/bn_blind.c | 289 + + .../OpensslLib/openssl/crypto/bn/bn_const.c | 553 + + .../Library/OpensslLib/openssl/crypto/bn/bn_ctx.c | 353 + + .../Library/OpensslLib/openssl/crypto/bn/bn_depr.c | 68 + + .../Library/OpensslLib/openssl/crypto/bn/bn_dh.c | 220 + + .../Library/OpensslLib/openssl/crypto/bn/bn_div.c | 423 + + .../Library/OpensslLib/openssl/crypto/bn/bn_err.c | 107 + + .../Library/OpensslLib/openssl/crypto/bn/bn_exp.c | 1362 ++ + .../Library/OpensslLib/openssl/crypto/bn/bn_exp2.c | 201 + + .../Library/OpensslLib/openssl/crypto/bn/bn_gcd.c | 620 + + .../Library/OpensslLib/openssl/crypto/bn/bn_gf2m.c | 0 + .../OpensslLib/openssl/crypto/bn/bn_intern.c | 210 + + .../Library/OpensslLib/openssl/crypto/bn/bn_kron.c | 140 + + .../Library/OpensslLib/openssl/crypto/bn/bn_lcl.h | 689 + + .../Library/OpensslLib/openssl/crypto/bn/bn_lib.c | 1037 ++ + .../Library/OpensslLib/openssl/crypto/bn/bn_mod.c | 201 + + .../Library/OpensslLib/openssl/crypto/bn/bn_mont.c | 434 + + .../Library/OpensslLib/openssl/crypto/bn/bn_mpi.c | 86 + + .../Library/OpensslLib/openssl/crypto/bn/bn_mul.c | 1045 ++ + .../Library/OpensslLib/openssl/crypto/bn/bn_nist.c | 1239 ++ + .../OpensslLib/openssl/crypto/bn/bn_prime.c | 608 + + .../OpensslLib/openssl/crypto/bn/bn_prime.h | 274 + + .../OpensslLib/openssl/crypto/bn/bn_prime.pl | 46 + + .../OpensslLib/openssl/crypto/bn/bn_print.c | 345 + + .../Library/OpensslLib/openssl/crypto/bn/bn_rand.c | 258 + + .../Library/OpensslLib/openssl/crypto/bn/bn_recp.c | 199 + + .../OpensslLib/openssl/crypto/bn/bn_shift.c | 175 + + .../Library/OpensslLib/openssl/crypto/bn/bn_sqr.c | 235 + + .../Library/OpensslLib/openssl/crypto/bn/bn_sqrt.c | 358 + + .../Library/OpensslLib/openssl/crypto/bn/bn_srp.c | 545 + + .../Library/OpensslLib/openssl/crypto/bn/bn_word.c | 201 + + .../OpensslLib/openssl/crypto/bn/bn_x931p.c | 238 + + .../OpensslLib/openssl/crypto/bn/build.info | 84 + + .../OpensslLib/openssl/crypto/bn/rsaz_exp.c | 352 + + .../OpensslLib/openssl/crypto/bn/rsaz_exp.h | 77 + + .../OpensslLib/openssl/crypto/buffer/buf_err.c | 44 + + .../OpensslLib/openssl/crypto/buffer/buffer.c | 164 + + .../OpensslLib/openssl/crypto/buffer/build.info | 2 + + .../Library/OpensslLib/openssl/crypto/build.info | 37 + + .../OpensslLib/openssl/crypto/c64xpluscpuid.pl | 287 + + .../openssl/crypto/camellia/asm/cmll-x86.pl | 1150 ++ + .../openssl/crypto/camellia/asm/cmll-x86_64.pl | 1088 ++ + .../openssl/crypto/camellia/asm/cmllt4-sparcv9.pl | 939 ++ + .../OpensslLib/openssl/crypto/camellia/build.info | 11 + + .../OpensslLib/openssl/crypto/camellia/camellia.c | 541 + + .../OpensslLib/openssl/crypto/camellia/cmll_cbc.c | 24 + + .../OpensslLib/openssl/crypto/camellia/cmll_cfb.c | 43 + + .../OpensslLib/openssl/crypto/camellia/cmll_ctr.c | 22 + + .../OpensslLib/openssl/crypto/camellia/cmll_ecb.c | 20 + + .../OpensslLib/openssl/crypto/camellia/cmll_locl.h | 43 + + .../OpensslLib/openssl/crypto/camellia/cmll_misc.c | 35 + + .../OpensslLib/openssl/crypto/camellia/cmll_ofb.c | 24 + + .../OpensslLib/openssl/crypto/cast/asm/cast-586.pl | 192 + + .../OpensslLib/openssl/crypto/cast/build.info | 6 + + .../OpensslLib/openssl/crypto/cast/c_cfb64.c | 74 + + .../Library/OpensslLib/openssl/crypto/cast/c_ecb.c | 32 + + .../Library/OpensslLib/openssl/crypto/cast/c_enc.c | 151 + + .../OpensslLib/openssl/crypto/cast/c_ofb64.c | 61 + + .../OpensslLib/openssl/crypto/cast/c_skey.c | 118 + + .../OpensslLib/openssl/crypto/cast/cast_lcl.h | 176 + + .../OpensslLib/openssl/crypto/cast/cast_s.h | 544 + + .../openssl/crypto/chacha/asm/chacha-armv4.pl | 1158 ++ + .../openssl/crypto/chacha/asm/chacha-armv8.pl | 1135 ++ + .../openssl/crypto/chacha/asm/chacha-c64xplus.pl | 926 ++ + .../openssl/crypto/chacha/asm/chacha-ppc.pl | 953 ++ + .../openssl/crypto/chacha/asm/chacha-s390x.pl | 326 + + .../openssl/crypto/chacha/asm/chacha-x86.pl | 1154 ++ + .../openssl/crypto/chacha/asm/chacha-x86_64.pl | 2245 ++++ + .../OpensslLib/openssl/crypto/chacha/build.info | 17 + + .../OpensslLib/openssl/crypto/chacha/chacha_enc.c | 121 + + .../OpensslLib/openssl/crypto/cmac/build.info | 2 + + .../OpensslLib/openssl/crypto/cmac/cm_ameth.c | 51 + + .../OpensslLib/openssl/crypto/cmac/cm_pmeth.c | 161 + + .../Library/OpensslLib/openssl/crypto/cmac/cmac.c | 223 + + .../OpensslLib/openssl/crypto/cms/build.info | 5 + + .../OpensslLib/openssl/crypto/cms/cms_asn1.c | 402 + + .../OpensslLib/openssl/crypto/cms/cms_att.c | 152 + + .../Library/OpensslLib/openssl/crypto/cms/cms_cd.c | 82 + + .../Library/OpensslLib/openssl/crypto/cms/cms_dd.c | 99 + + .../OpensslLib/openssl/crypto/cms/cms_enc.c | 212 + + .../OpensslLib/openssl/crypto/cms/cms_env.c | 902 ++ + .../OpensslLib/openssl/crypto/cms/cms_err.c | 258 + + .../OpensslLib/openssl/crypto/cms/cms_ess.c | 337 + + .../Library/OpensslLib/openssl/crypto/cms/cms_io.c | 88 + + .../OpensslLib/openssl/crypto/cms/cms_kari.c | 411 + + .../OpensslLib/openssl/crypto/cms/cms_lcl.h | 444 + + .../OpensslLib/openssl/crypto/cms/cms_lib.c | 587 + + .../OpensslLib/openssl/crypto/cms/cms_pwri.c | 392 + + .../Library/OpensslLib/openssl/crypto/cms/cms_sd.c | 923 ++ + .../OpensslLib/openssl/crypto/cms/cms_smime.c | 844 ++ + .../OpensslLib/openssl/crypto/comp/build.info | 4 + + .../OpensslLib/openssl/crypto/comp/c_zlib.c | 615 + + .../OpensslLib/openssl/crypto/comp/comp_err.c | 48 + + .../OpensslLib/openssl/crypto/comp/comp_lcl.h | 30 + + .../OpensslLib/openssl/crypto/comp/comp_lib.c | 91 + + .../OpensslLib/openssl/crypto/conf/build.info | 4 + + .../OpensslLib/openssl/crypto/conf/conf_api.c | 214 + + .../OpensslLib/openssl/crypto/conf/conf_def.c | 630 + + .../OpensslLib/openssl/crypto/conf/conf_def.h | 129 + + .../OpensslLib/openssl/crypto/conf/conf_err.c | 79 + + .../OpensslLib/openssl/crypto/conf/conf_lib.c | 365 + + .../OpensslLib/openssl/crypto/conf/conf_mall.c | 29 + + .../OpensslLib/openssl/crypto/conf/conf_mod.c | 549 + + .../OpensslLib/openssl/crypto/conf/conf_sap.c | 60 + + .../OpensslLib/openssl/crypto/conf/keysets.pl | 141 + + .../Library/OpensslLib/openssl/crypto/cpt_err.c | 55 + + .../Library/OpensslLib/openssl/crypto/cryptlib.c | 341 + + .../OpensslLib/openssl/crypto/ct/build.info | 3 + + .../Library/OpensslLib/openssl/crypto/ct/ct_b64.c | 164 + + .../Library/OpensslLib/openssl/crypto/ct/ct_err.c | 87 + + .../Library/OpensslLib/openssl/crypto/ct/ct_locl.h | 216 + + .../Library/OpensslLib/openssl/crypto/ct/ct_log.c | 304 + + .../Library/OpensslLib/openssl/crypto/ct/ct_oct.c | 407 + + .../OpensslLib/openssl/crypto/ct/ct_policy.c | 98 + + .../Library/OpensslLib/openssl/crypto/ct/ct_prn.c | 127 + + .../Library/OpensslLib/openssl/crypto/ct/ct_sct.c | 393 + + .../OpensslLib/openssl/crypto/ct/ct_sct_ctx.c | 263 + + .../Library/OpensslLib/openssl/crypto/ct/ct_vfy.c | 140 + + .../OpensslLib/openssl/crypto/ct/ct_x509v3.c | 60 + + .../Library/OpensslLib/openssl/crypto/cversion.c | 65 + + .../OpensslLib/openssl/crypto/des/asm/crypt586.pl | 217 + + .../OpensslLib/openssl/crypto/des/asm/des-586.pl | 465 + + .../OpensslLib/openssl/crypto/des/asm/des_enc.m4 | 1972 +++ + .../OpensslLib/openssl/crypto/des/asm/desboth.pl | 86 + + .../openssl/crypto/des/asm/dest4-sparcv9.pl | 627 + + .../OpensslLib/openssl/crypto/des/build.info | 17 + + .../OpensslLib/openssl/crypto/des/cbc_cksm.c | 54 + + .../OpensslLib/openssl/crypto/des/cbc_enc.c | 12 + + .../OpensslLib/openssl/crypto/des/cfb64ede.c | 190 + + .../OpensslLib/openssl/crypto/des/cfb64enc.c | 73 + + .../OpensslLib/openssl/crypto/des/cfb_enc.c | 150 + + .../OpensslLib/openssl/crypto/des/des_enc.c | 301 + + .../OpensslLib/openssl/crypto/des/des_locl.h | 217 + + .../OpensslLib/openssl/crypto/des/ecb3_enc.c | 33 + + .../OpensslLib/openssl/crypto/des/ecb_enc.c | 51 + + .../Library/OpensslLib/openssl/crypto/des/fcrypt.c | 149 + + .../OpensslLib/openssl/crypto/des/fcrypt_b.c | 72 + + .../OpensslLib/openssl/crypto/des/ncbc_enc.c | 106 + + .../OpensslLib/openssl/crypto/des/ofb64ede.c | 62 + + .../OpensslLib/openssl/crypto/des/ofb64enc.c | 60 + + .../OpensslLib/openssl/crypto/des/ofb_enc.c | 82 + + .../OpensslLib/openssl/crypto/des/pcbc_enc.c | 66 + + .../OpensslLib/openssl/crypto/des/qud_cksm.c | 77 + + .../OpensslLib/openssl/crypto/des/rand_key.c | 21 + + .../OpensslLib/openssl/crypto/des/rpc_des.h | 76 + + .../OpensslLib/openssl/crypto/des/rpc_enc.c | 30 + + .../OpensslLib/openssl/crypto/des/set_key.c | 389 + + .../Library/OpensslLib/openssl/crypto/des/spr.h | 163 + + .../OpensslLib/openssl/crypto/des/str2key.c | 97 + + .../OpensslLib/openssl/crypto/des/xcbc_enc.c | 103 + + .../OpensslLib/openssl/crypto/dh/build.info | 4 + + .../OpensslLib/openssl/crypto/dh/dh1024.pem | 5 + + .../Library/OpensslLib/openssl/crypto/dh/dh192.pem | 3 + + .../OpensslLib/openssl/crypto/dh/dh2048.pem | 16 + + .../OpensslLib/openssl/crypto/dh/dh4096.pem | 14 + + .../Library/OpensslLib/openssl/crypto/dh/dh512.pem | 4 + + .../OpensslLib/openssl/crypto/dh/dh_ameth.c | 870 ++ + .../Library/OpensslLib/openssl/crypto/dh/dh_asn1.c | 138 + + .../OpensslLib/openssl/crypto/dh/dh_check.c | 183 + + .../Library/OpensslLib/openssl/crypto/dh/dh_depr.c | 46 + + .../Library/OpensslLib/openssl/crypto/dh/dh_err.c | 73 + + .../Library/OpensslLib/openssl/crypto/dh/dh_gen.c | 130 + + .../Library/OpensslLib/openssl/crypto/dh/dh_kdf.c | 150 + + .../Library/OpensslLib/openssl/crypto/dh/dh_key.c | 215 + + .../Library/OpensslLib/openssl/crypto/dh/dh_lib.c | 284 + + .../Library/OpensslLib/openssl/crypto/dh/dh_locl.h | 56 + + .../Library/OpensslLib/openssl/crypto/dh/dh_meth.c | 173 + + .../OpensslLib/openssl/crypto/dh/dh_pmeth.c | 501 + + .../Library/OpensslLib/openssl/crypto/dh/dh_prn.c | 30 + + .../OpensslLib/openssl/crypto/dh/dh_rfc5114.c | 41 + + .../Library/OpensslLib/openssl/crypto/dllmain.c | 60 + + .../OpensslLib/openssl/crypto/dsa/build.info | 5 + + .../OpensslLib/openssl/crypto/dsa/dsa_ameth.c | 567 + + .../OpensslLib/openssl/crypto/dsa/dsa_asn1.c | 155 + + .../OpensslLib/openssl/crypto/dsa/dsa_depr.c | 62 + + .../OpensslLib/openssl/crypto/dsa/dsa_err.c | 76 + + .../OpensslLib/openssl/crypto/dsa/dsa_gen.c | 601 + + .../OpensslLib/openssl/crypto/dsa/dsa_key.c | 77 + + .../OpensslLib/openssl/crypto/dsa/dsa_lib.c | 346 + + .../OpensslLib/openssl/crypto/dsa/dsa_locl.h | 76 + + .../OpensslLib/openssl/crypto/dsa/dsa_meth.c | 224 + + .../OpensslLib/openssl/crypto/dsa/dsa_ossl.c | 338 + + .../OpensslLib/openssl/crypto/dsa/dsa_pmeth.c | 273 + + .../OpensslLib/openssl/crypto/dsa/dsa_prn.c | 69 + + .../OpensslLib/openssl/crypto/dsa/dsa_sign.c | 24 + + .../OpensslLib/openssl/crypto/dsa/dsa_vrf.c | 19 + + .../OpensslLib/openssl/crypto/dso/build.info | 4 + + .../Library/OpensslLib/openssl/crypto/dso/dso_dl.c | 279 + + .../OpensslLib/openssl/crypto/dso/dso_dlfcn.c | 354 + + .../OpensslLib/openssl/crypto/dso/dso_err.c | 93 + + .../OpensslLib/openssl/crypto/dso/dso_lib.c | 349 + + .../OpensslLib/openssl/crypto/dso/dso_locl.h | 106 + + .../OpensslLib/openssl/crypto/dso/dso_openssl.c | 22 + + .../OpensslLib/openssl/crypto/dso/dso_vms.c | 468 + + .../OpensslLib/openssl/crypto/dso/dso_win32.c | 573 + + .../Library/OpensslLib/openssl/crypto/ebcdic.c | 366 + + .../openssl/crypto/ec/asm/ecp_nistz256-armv4.pl | 1865 +++ + .../openssl/crypto/ec/asm/ecp_nistz256-armv8.pl | 1558 +++ + .../openssl/crypto/ec/asm/ecp_nistz256-avx2.pl | 2100 ++++ + .../openssl/crypto/ec/asm/ecp_nistz256-sparcv9.pl | 3061 +++++ + .../openssl/crypto/ec/asm/ecp_nistz256-x86.pl | 1866 +++ + .../openssl/crypto/ec/asm/ecp_nistz256-x86_64.pl | 3087 +++++ + .../OpensslLib/openssl/crypto/ec/build.info | 28 + + .../OpensslLib/openssl/crypto/ec/curve25519.c | 3394 +++++ + .../OpensslLib/openssl/crypto/ec/ec2_mult.c | 0 + .../Library/OpensslLib/openssl/crypto/ec/ec2_oct.c | 0 + .../OpensslLib/openssl/crypto/ec/ec2_smpl.c | 0 + .../OpensslLib/openssl/crypto/ec/ec_ameth.c | 881 ++ + .../Library/OpensslLib/openssl/crypto/ec/ec_asn1.c | 1234 ++ + .../OpensslLib/openssl/crypto/ec/ec_check.c | 72 + + .../OpensslLib/openssl/crypto/ec/ec_curve.c | 0 + .../Library/OpensslLib/openssl/crypto/ec/ec_cvt.c | 95 + + .../Library/OpensslLib/openssl/crypto/ec/ec_err.c | 290 + + .../Library/OpensslLib/openssl/crypto/ec/ec_key.c | 637 + + .../OpensslLib/openssl/crypto/ec/ec_kmeth.c | 317 + + .../Library/OpensslLib/openssl/crypto/ec/ec_lcl.h | 613 + + .../Library/OpensslLib/openssl/crypto/ec/ec_lib.c | 1004 ++ + .../Library/OpensslLib/openssl/crypto/ec/ec_mult.c | 680 + + .../Library/OpensslLib/openssl/crypto/ec/ec_oct.c | 165 + + .../OpensslLib/openssl/crypto/ec/ec_pmeth.c | 463 + + .../OpensslLib/openssl/crypto/ec/ec_print.c | 119 + + .../OpensslLib/openssl/crypto/ec/ecdh_kdf.c | 68 + + .../OpensslLib/openssl/crypto/ec/ecdh_ossl.c | 143 + + .../OpensslLib/openssl/crypto/ec/ecdsa_ossl.c | 462 + + .../OpensslLib/openssl/crypto/ec/ecdsa_sign.c | 52 + + .../OpensslLib/openssl/crypto/ec/ecdsa_vrf.c | 43 + + .../Library/OpensslLib/openssl/crypto/ec/eck_prn.c | 273 + + .../OpensslLib/openssl/crypto/ec/ecp_mont.c | 242 + + .../OpensslLib/openssl/crypto/ec/ecp_nist.c | 167 + + .../OpensslLib/openssl/crypto/ec/ecp_nistp224.c | 1717 +++ + .../OpensslLib/openssl/crypto/ec/ecp_nistp256.c | 2350 ++++ + .../OpensslLib/openssl/crypto/ec/ecp_nistp521.c | 2146 ++++ + .../OpensslLib/openssl/crypto/ec/ecp_nistputil.c | 223 + + .../OpensslLib/openssl/crypto/ec/ecp_nistz256.c | 1559 +++ + .../openssl/crypto/ec/ecp_nistz256_table.c | 9542 ++++++++++++++ + .../Library/OpensslLib/openssl/crypto/ec/ecp_oct.c | 372 + + .../OpensslLib/openssl/crypto/ec/ecp_smpl.c | 1369 ++ + .../OpensslLib/openssl/crypto/ec/ecx_meth.c | 373 + + .../OpensslLib/openssl/crypto/engine/README | 211 + + .../OpensslLib/openssl/crypto/engine/build.info | 8 + + .../OpensslLib/openssl/crypto/engine/eng_all.c | 31 + + .../OpensslLib/openssl/crypto/engine/eng_cnf.c | 192 + + .../openssl/crypto/engine/eng_cryptodev.c | 1754 +++ + .../OpensslLib/openssl/crypto/engine/eng_ctrl.c | 338 + + .../OpensslLib/openssl/crypto/engine/eng_dyn.c | 510 + + .../OpensslLib/openssl/crypto/engine/eng_err.c | 123 + + .../OpensslLib/openssl/crypto/engine/eng_fat.c | 127 + + .../OpensslLib/openssl/crypto/engine/eng_init.c | 108 + + .../OpensslLib/openssl/crypto/engine/eng_int.h | 183 + + .../OpensslLib/openssl/crypto/engine/eng_lib.c | 295 + + .../OpensslLib/openssl/crypto/engine/eng_list.c | 354 + + .../OpensslLib/openssl/crypto/engine/eng_openssl.c | 652 + + .../OpensslLib/openssl/crypto/engine/eng_pkey.c | 140 + + .../OpensslLib/openssl/crypto/engine/eng_rdrand.c | 110 + + .../OpensslLib/openssl/crypto/engine/eng_table.c | 303 + + .../OpensslLib/openssl/crypto/engine/tb_asnmth.c | 207 + + .../OpensslLib/openssl/crypto/engine/tb_cipher.c | 91 + + .../OpensslLib/openssl/crypto/engine/tb_dh.c | 72 + + .../OpensslLib/openssl/crypto/engine/tb_digest.c | 91 + + .../OpensslLib/openssl/crypto/engine/tb_dsa.c | 72 + + .../OpensslLib/openssl/crypto/engine/tb_eckey.c | 72 + + .../OpensslLib/openssl/crypto/engine/tb_pkmeth.c | 114 + + .../OpensslLib/openssl/crypto/engine/tb_rand.c | 72 + + .../OpensslLib/openssl/crypto/engine/tb_rsa.c | 72 + + .../Library/OpensslLib/openssl/crypto/err/README | 44 + + .../OpensslLib/openssl/crypto/err/build.info | 3 + + .../Library/OpensslLib/openssl/crypto/err/err.c | 770 ++ + .../OpensslLib/openssl/crypto/err/err_all.c | 109 + + .../OpensslLib/openssl/crypto/err/err_prn.c | 66 + + .../OpensslLib/openssl/crypto/err/openssl.ec | 100 + + .../OpensslLib/openssl/crypto/evp/bio_b64.c | 542 + + .../OpensslLib/openssl/crypto/evp/bio_enc.c | 449 + + .../Library/OpensslLib/openssl/crypto/evp/bio_md.c | 231 + + .../Library/OpensslLib/openssl/crypto/evp/bio_ok.c | 604 + + .../OpensslLib/openssl/crypto/evp/build.info | 22 + + .../Library/OpensslLib/openssl/crypto/evp/c_allc.c | 220 + + .../Library/OpensslLib/openssl/crypto/evp/c_alld.c | 49 + + .../OpensslLib/openssl/crypto/evp/cmeth_lib.c | 151 + + .../Library/OpensslLib/openssl/crypto/evp/digest.c | 269 + + .../Library/OpensslLib/openssl/crypto/evp/e_aes.c | 2702 ++++ + .../openssl/crypto/evp/e_aes_cbc_hmac_sha1.c | 957 ++ + .../openssl/crypto/evp/e_aes_cbc_hmac_sha256.c | 939 ++ + .../Library/OpensslLib/openssl/crypto/evp/e_bf.c | 38 + + .../OpensslLib/openssl/crypto/evp/e_camellia.c | 364 + + .../Library/OpensslLib/openssl/crypto/evp/e_cast.c | 40 + + .../openssl/crypto/evp/e_chacha20_poly1305.c | 454 + + .../Library/OpensslLib/openssl/crypto/evp/e_des.c | 242 + + .../Library/OpensslLib/openssl/crypto/evp/e_des3.c | 424 + + .../Library/OpensslLib/openssl/crypto/evp/e_idea.c | 70 + + .../Library/OpensslLib/openssl/crypto/evp/e_null.c | 50 + + .../Library/OpensslLib/openssl/crypto/evp/e_old.c | 113 + + .../Library/OpensslLib/openssl/crypto/evp/e_rc2.c | 189 + + .../Library/OpensslLib/openssl/crypto/evp/e_rc4.c | 82 + + .../OpensslLib/openssl/crypto/evp/e_rc4_hmac_md5.c | 262 + + .../Library/OpensslLib/openssl/crypto/evp/e_rc5.c | 74 + + .../Library/OpensslLib/openssl/crypto/evp/e_seed.c | 39 + + .../OpensslLib/openssl/crypto/evp/e_xcbc_d.c | 83 + + .../Library/OpensslLib/openssl/crypto/evp/encode.c | 404 + + .../OpensslLib/openssl/crypto/evp/evp_cnf.c | 65 + + .../OpensslLib/openssl/crypto/evp/evp_enc.c | 641 + + .../OpensslLib/openssl/crypto/evp/evp_err.c | 180 + + .../OpensslLib/openssl/crypto/evp/evp_key.c | 150 + + .../OpensslLib/openssl/crypto/evp/evp_lib.c | 497 + + .../OpensslLib/openssl/crypto/evp/evp_locl.h | 68 + + .../OpensslLib/openssl/crypto/evp/evp_pbe.c | 259 + + .../OpensslLib/openssl/crypto/evp/evp_pkey.c | 150 + + .../Library/OpensslLib/openssl/crypto/evp/m_md2.c | 56 + + .../Library/OpensslLib/openssl/crypto/evp/m_md4.c | 55 + + .../Library/OpensslLib/openssl/crypto/evp/m_md5.c | 55 + + .../OpensslLib/openssl/crypto/evp/m_md5_sha1.c | 142 + + .../Library/OpensslLib/openssl/crypto/evp/m_mdc2.c | 55 + + .../Library/OpensslLib/openssl/crypto/evp/m_null.c | 49 + + .../OpensslLib/openssl/crypto/evp/m_ripemd.c | 55 + + .../Library/OpensslLib/openssl/crypto/evp/m_sha1.c | 233 + + .../OpensslLib/openssl/crypto/evp/m_sigver.c | 169 + + .../Library/OpensslLib/openssl/crypto/evp/m_wp.c | 54 + + .../Library/OpensslLib/openssl/crypto/evp/names.c | 178 + + .../OpensslLib/openssl/crypto/evp/p5_crpt.c | 103 + + .../OpensslLib/openssl/crypto/evp/p5_crpt2.c | 277 + + .../Library/OpensslLib/openssl/crypto/evp/p_dec.c | 36 + + .../Library/OpensslLib/openssl/crypto/evp/p_enc.c | 35 + + .../Library/OpensslLib/openssl/crypto/evp/p_lib.c | 484 + + .../Library/OpensslLib/openssl/crypto/evp/p_open.c | 73 + + .../Library/OpensslLib/openssl/crypto/evp/p_seal.c | 70 + + .../Library/OpensslLib/openssl/crypto/evp/p_sign.c | 61 + + .../OpensslLib/openssl/crypto/evp/p_verify.c | 55 + + .../OpensslLib/openssl/crypto/evp/pmeth_fn.c | 297 + + .../OpensslLib/openssl/crypto/evp/pmeth_gn.c | 169 + + .../OpensslLib/openssl/crypto/evp/pmeth_lib.c | 721 ++ + .../Library/OpensslLib/openssl/crypto/evp/scrypt.c | 248 + + .../Library/OpensslLib/openssl/crypto/ex_data.c | 384 + + .../OpensslLib/openssl/crypto/hmac/build.info | 3 + + .../OpensslLib/openssl/crypto/hmac/hm_ameth.c | 125 + + .../OpensslLib/openssl/crypto/hmac/hm_pmeth.c | 210 + + .../Library/OpensslLib/openssl/crypto/hmac/hmac.c | 240 + + .../OpensslLib/openssl/crypto/hmac/hmac_lcl.h | 33 + + .../Library/OpensslLib/openssl/crypto/ia64cpuid.S | 297 + + .../OpensslLib/openssl/crypto/idea/build.info | 3 + + .../Library/OpensslLib/openssl/crypto/idea/i_cbc.c | 122 + + .../OpensslLib/openssl/crypto/idea/i_cfb64.c | 74 + + .../Library/OpensslLib/openssl/crypto/idea/i_ecb.c | 34 + + .../OpensslLib/openssl/crypto/idea/i_ofb64.c | 61 + + .../OpensslLib/openssl/crypto/idea/i_skey.c | 112 + + .../OpensslLib/openssl/crypto/idea/idea_lcl.h | 103 + + .../openssl/crypto/include/internal/asn1_int.h | 94 + + .../openssl/crypto/include/internal/async.h | 14 + + .../openssl/crypto/include/internal/bn_conf.h.in | 27 + + .../openssl/crypto/include/internal/bn_dh.h | 17 + + .../openssl/crypto/include/internal/bn_int.h | 82 + + .../openssl/crypto/include/internal/bn_srp.h | 9 + + .../openssl/crypto/include/internal/chacha.h | 49 + + .../openssl/crypto/include/internal/cryptlib.h | 81 + + .../openssl/crypto/include/internal/cryptlib_int.h | 31 + + .../openssl/crypto/include/internal/dso_conf.h.in | 15 + + .../openssl/crypto/include/internal/engine.h | 20 + + .../openssl/crypto/include/internal/err_int.h | 17 + + .../openssl/crypto/include/internal/evp_int.h | 389 + + .../openssl/crypto/include/internal/md32_common.h | 383 + + .../openssl/crypto/include/internal/objects.h | 12 + + .../openssl/crypto/include/internal/poly1305.h | 19 + + .../openssl/crypto/include/internal/rand.h | 20 + + .../openssl/crypto/include/internal/x509_int.h | 267 + + CryptoPkg/Library/OpensslLib/openssl/crypto/init.c | 664 + + .../OpensslLib/openssl/crypto/kdf/build.info | 3 + + .../Library/OpensslLib/openssl/crypto/kdf/hkdf.c | 293 + + .../OpensslLib/openssl/crypto/kdf/kdf_err.c | 46 + + .../OpensslLib/openssl/crypto/kdf/tls1_prf.c | 265 + + .../OpensslLib/openssl/crypto/lhash/build.info | 3 + + .../OpensslLib/openssl/crypto/lhash/lh_stats.c | 118 + + .../OpensslLib/openssl/crypto/lhash/lhash.c | 349 + + .../OpensslLib/openssl/crypto/lhash/lhash_lcl.h | 42 + + .../Library/OpensslLib/openssl/crypto/lhash/num.pl | 23 + + .../OpensslLib/openssl/crypto/md2/build.info | 3 + + .../OpensslLib/openssl/crypto/md2/md2_dgst.c | 173 + + .../OpensslLib/openssl/crypto/md2/md2_one.c | 47 + + .../OpensslLib/openssl/crypto/md4/build.info | 3 + + .../OpensslLib/openssl/crypto/md4/md4_dgst.c | 147 + + .../OpensslLib/openssl/crypto/md4/md4_locl.h | 60 + + .../OpensslLib/openssl/crypto/md4/md4_one.c | 47 + + .../OpensslLib/openssl/crypto/md5/asm/md5-586.pl | 318 + + .../OpensslLib/openssl/crypto/md5/asm/md5-ia64.S | 1002 ++ + .../openssl/crypto/md5/asm/md5-sparcv9.pl | 437 + + .../openssl/crypto/md5/asm/md5-x86_64.pl | 380 + + .../OpensslLib/openssl/crypto/md5/build.info | 22 + + .../OpensslLib/openssl/crypto/md5/md5_dgst.c | 164 + + .../OpensslLib/openssl/crypto/md5/md5_locl.h | 80 + + .../OpensslLib/openssl/crypto/md5/md5_one.c | 47 + + .../OpensslLib/openssl/crypto/mdc2/build.info | 3 + + .../OpensslLib/openssl/crypto/mdc2/mdc2_one.c | 27 + + .../OpensslLib/openssl/crypto/mdc2/mdc2dgst.c | 147 + + CryptoPkg/Library/OpensslLib/openssl/crypto/mem.c | 190 + + .../Library/OpensslLib/openssl/crypto/mem_clr.c | 25 + + .../Library/OpensslLib/openssl/crypto/mem_dbg.c | 629 + + .../Library/OpensslLib/openssl/crypto/mem_sec.c | 585 + + .../openssl/crypto/modes/asm/aesni-gcm-x86_64.pl | 1106 ++ + .../openssl/crypto/modes/asm/ghash-alpha.pl | 467 + + .../openssl/crypto/modes/asm/ghash-armv4.pl | 554 + + .../openssl/crypto/modes/asm/ghash-c64xplus.pl | 247 + + .../openssl/crypto/modes/asm/ghash-ia64.pl | 470 + + .../openssl/crypto/modes/asm/ghash-parisc.pl | 738 ++ + .../openssl/crypto/modes/asm/ghash-s390x.pl | 267 + + .../openssl/crypto/modes/asm/ghash-sparcv9.pl | 581 + + .../openssl/crypto/modes/asm/ghash-x86.pl | 1405 +++ + .../openssl/crypto/modes/asm/ghash-x86_64.pl | 1762 +++ + .../openssl/crypto/modes/asm/ghashp8-ppc.pl | 670 + + .../openssl/crypto/modes/asm/ghashv8-armx.pl | 430 + + .../OpensslLib/openssl/crypto/modes/build.info | 27 + + .../OpensslLib/openssl/crypto/modes/cbc128.c | 155 + + .../OpensslLib/openssl/crypto/modes/ccm128.c | 432 + + .../OpensslLib/openssl/crypto/modes/cfb128.c | 198 + + .../OpensslLib/openssl/crypto/modes/ctr128.c | 209 + + .../OpensslLib/openssl/crypto/modes/cts128.c | 523 + + .../OpensslLib/openssl/crypto/modes/gcm128.c | 2302 ++++ + .../OpensslLib/openssl/crypto/modes/modes_lcl.h | 185 + + .../OpensslLib/openssl/crypto/modes/ocb128.c | 568 + + .../OpensslLib/openssl/crypto/modes/ofb128.c | 74 + + .../OpensslLib/openssl/crypto/modes/wrap128.c | 329 + + .../OpensslLib/openssl/crypto/modes/xts128.c | 157 + + .../Library/OpensslLib/openssl/crypto/o_dir.c | 36 + + .../Library/OpensslLib/openssl/crypto/o_fips.c | 34 + + .../Library/OpensslLib/openssl/crypto/o_fopen.c | 103 + + .../Library/OpensslLib/openssl/crypto/o_init.c | 34 + + .../Library/OpensslLib/openssl/crypto/o_str.c | 250 + + .../Library/OpensslLib/openssl/crypto/o_time.c | 360 + + .../OpensslLib/openssl/crypto/objects/README | 44 + + .../OpensslLib/openssl/crypto/objects/build.info | 3 + + .../OpensslLib/openssl/crypto/objects/o_names.c | 370 + + .../OpensslLib/openssl/crypto/objects/obj_dat.c | 728 ++ + .../OpensslLib/openssl/crypto/objects/obj_dat.h | 5101 ++++++++ + .../OpensslLib/openssl/crypto/objects/obj_dat.pl | 227 + + .../OpensslLib/openssl/crypto/objects/obj_err.c | 50 + + .../OpensslLib/openssl/crypto/objects/obj_lcl.h | 14 + + .../OpensslLib/openssl/crypto/objects/obj_lib.c | 66 + + .../OpensslLib/openssl/crypto/objects/obj_mac.num | 1060 ++ + .../OpensslLib/openssl/crypto/objects/obj_xref.c | 165 + + .../OpensslLib/openssl/crypto/objects/obj_xref.h | 118 + + .../OpensslLib/openssl/crypto/objects/obj_xref.txt | 60 + + .../OpensslLib/openssl/crypto/objects/objects.pl | 193 + + .../OpensslLib/openssl/crypto/objects/objects.txt | 1485 +++ + .../OpensslLib/openssl/crypto/objects/objxref.pl | 135 + + .../OpensslLib/openssl/crypto/ocsp/build.info | 4 + + .../OpensslLib/openssl/crypto/ocsp/ocsp_asn.c | 135 + + .../OpensslLib/openssl/crypto/ocsp/ocsp_cl.c | 365 + + .../OpensslLib/openssl/crypto/ocsp/ocsp_err.c | 91 + + .../OpensslLib/openssl/crypto/ocsp/ocsp_ext.c | 472 + + .../OpensslLib/openssl/crypto/ocsp/ocsp_ht.c | 499 + + .../OpensslLib/openssl/crypto/ocsp/ocsp_lcl.h | 216 + + .../OpensslLib/openssl/crypto/ocsp/ocsp_lib.c | 222 + + .../OpensslLib/openssl/crypto/ocsp/ocsp_prn.c | 246 + + .../OpensslLib/openssl/crypto/ocsp/ocsp_srv.c | 277 + + .../OpensslLib/openssl/crypto/ocsp/ocsp_vfy.c | 424 + + .../OpensslLib/openssl/crypto/ocsp/v3_ocsp.c | 264 + + .../Library/OpensslLib/openssl/crypto/pariscid.pl | 263 + + .../OpensslLib/openssl/crypto/pem/build.info | 4 + + .../OpensslLib/openssl/crypto/pem/pem_all.c | 181 + + .../OpensslLib/openssl/crypto/pem/pem_err.c | 115 + + .../OpensslLib/openssl/crypto/pem/pem_info.c | 334 + + .../OpensslLib/openssl/crypto/pem/pem_lib.c | 857 ++ + .../OpensslLib/openssl/crypto/pem/pem_oth.c | 36 + + .../OpensslLib/openssl/crypto/pem/pem_pk8.c | 213 + + .../OpensslLib/openssl/crypto/pem/pem_pkey.c | 243 + + .../OpensslLib/openssl/crypto/pem/pem_sign.c | 50 + + .../OpensslLib/openssl/crypto/pem/pem_x509.c | 18 + + .../OpensslLib/openssl/crypto/pem/pem_xaux.c | 18 + + .../Library/OpensslLib/openssl/crypto/pem/pvkfmt.c | 869 ++ + .../OpensslLib/openssl/crypto/perlasm/README | 124 + + .../OpensslLib/openssl/crypto/perlasm/arm-xlate.pl | 177 + + .../OpensslLib/openssl/crypto/perlasm/cbc.pl | 356 + + .../OpensslLib/openssl/crypto/perlasm/ppc-xlate.pl | 265 + + .../openssl/crypto/perlasm/sparcv9_modes.pl | 1702 +++ + .../openssl/crypto/perlasm/x86_64-xlate.pl | 1185 ++ + .../OpensslLib/openssl/crypto/perlasm/x86asm.pl | 310 + + .../OpensslLib/openssl/crypto/perlasm/x86gas.pl | 265 + + .../OpensslLib/openssl/crypto/perlasm/x86masm.pl | 207 + + .../OpensslLib/openssl/crypto/perlasm/x86nasm.pl | 186 + + .../OpensslLib/openssl/crypto/pkcs12/build.info | 5 + + .../OpensslLib/openssl/crypto/pkcs12/p12_add.c | 164 + + .../OpensslLib/openssl/crypto/pkcs12/p12_asn.c | 76 + + .../OpensslLib/openssl/crypto/pkcs12/p12_attr.c | 103 + + .../OpensslLib/openssl/crypto/pkcs12/p12_crpt.c | 70 + + .../OpensslLib/openssl/crypto/pkcs12/p12_crt.c | 291 + + .../OpensslLib/openssl/crypto/pkcs12/p12_decr.c | 155 + + .../OpensslLib/openssl/crypto/pkcs12/p12_init.c | 43 + + .../OpensslLib/openssl/crypto/pkcs12/p12_key.c | 205 + + .../OpensslLib/openssl/crypto/pkcs12/p12_kiss.c | 245 + + .../OpensslLib/openssl/crypto/pkcs12/p12_lcl.h | 43 + + .../OpensslLib/openssl/crypto/pkcs12/p12_mutl.c | 239 + + .../OpensslLib/openssl/crypto/pkcs12/p12_npas.c | 184 + + .../OpensslLib/openssl/crypto/pkcs12/p12_p8d.c | 23 + + .../OpensslLib/openssl/crypto/pkcs12/p12_p8e.c | 69 + + .../OpensslLib/openssl/crypto/pkcs12/p12_sbag.c | 170 + + .../OpensslLib/openssl/crypto/pkcs12/p12_utl.c | 237 + + .../OpensslLib/openssl/crypto/pkcs12/pk12err.c | 95 + + .../OpensslLib/openssl/crypto/pkcs7/bio_pk7.c | 24 + + .../OpensslLib/openssl/crypto/pkcs7/build.info | 4 + + .../OpensslLib/openssl/crypto/pkcs7/pk7_asn1.c | 201 + + .../OpensslLib/openssl/crypto/pkcs7/pk7_attr.c | 121 + + .../OpensslLib/openssl/crypto/pkcs7/pk7_dgst.c | 15 + + .../OpensslLib/openssl/crypto/pkcs7/pk7_doit.c | 1178 ++ + .../OpensslLib/openssl/crypto/pkcs7/pk7_enc.c | 25 + + .../OpensslLib/openssl/crypto/pkcs7/pk7_lib.c | 589 + + .../OpensslLib/openssl/crypto/pkcs7/pk7_mime.c | 49 + + .../OpensslLib/openssl/crypto/pkcs7/pk7_smime.c | 549 + + .../OpensslLib/openssl/crypto/pkcs7/pkcs7err.c | 131 + + .../openssl/crypto/poly1305/asm/poly1305-armv4.pl | 1252 ++ + .../openssl/crypto/poly1305/asm/poly1305-armv8.pl | 939 ++ + .../crypto/poly1305/asm/poly1305-c64xplus.pl | 331 + + .../openssl/crypto/poly1305/asm/poly1305-mips.pl | 425 + + .../openssl/crypto/poly1305/asm/poly1305-ppc.pl | 644 + + .../openssl/crypto/poly1305/asm/poly1305-ppcfp.pl | 739 ++ + .../openssl/crypto/poly1305/asm/poly1305-s390x.pl | 227 + + .../crypto/poly1305/asm/poly1305-sparcv9.pl | 1120 ++ + .../openssl/crypto/poly1305/asm/poly1305-x86.pl | 1814 +++ + .../openssl/crypto/poly1305/asm/poly1305-x86_64.pl | 2268 ++++ + .../OpensslLib/openssl/crypto/poly1305/build.info | 20 + + .../OpensslLib/openssl/crypto/poly1305/poly1305.c | 1037 ++ + .../openssl/crypto/poly1305/poly1305_ieee754.c | 472 + + .../Library/OpensslLib/openssl/crypto/ppc_arch.h | 26 + + .../Library/OpensslLib/openssl/crypto/ppccap.c | 317 + + .../Library/OpensslLib/openssl/crypto/ppccpuid.pl | 301 + + .../OpensslLib/openssl/crypto/rand/build.info | 4 + + .../OpensslLib/openssl/crypto/rand/md_rand.c | 666 + + .../OpensslLib/openssl/crypto/rand/rand_egd.c | 249 + + .../OpensslLib/openssl/crypto/rand/rand_err.c | 43 + + .../OpensslLib/openssl/crypto/rand/rand_lcl.h | 46 + + .../OpensslLib/openssl/crypto/rand/rand_lib.c | 126 + + .../OpensslLib/openssl/crypto/rand/rand_unix.c | 324 + + .../OpensslLib/openssl/crypto/rand/rand_vms.c | 133 + + .../OpensslLib/openssl/crypto/rand/rand_win.c | 135 + + .../OpensslLib/openssl/crypto/rand/randfile.c | 366 + + .../OpensslLib/openssl/crypto/rc2/build.info | 3 + + .../OpensslLib/openssl/crypto/rc2/rc2_cbc.c | 179 + + .../OpensslLib/openssl/crypto/rc2/rc2_ecb.c | 41 + + .../OpensslLib/openssl/crypto/rc2/rc2_locl.h | 106 + + .../OpensslLib/openssl/crypto/rc2/rc2_skey.c | 98 + + .../OpensslLib/openssl/crypto/rc2/rc2cfb64.c | 74 + + .../OpensslLib/openssl/crypto/rc2/rc2ofb64.c | 61 + + .../Library/OpensslLib/openssl/crypto/rc2/tab.c | 93 + + .../OpensslLib/openssl/crypto/rc4/asm/rc4-586.pl | 428 + + .../openssl/crypto/rc4/asm/rc4-c64xplus.pl | 190 + + .../OpensslLib/openssl/crypto/rc4/asm/rc4-ia64.pl | 767 ++ + .../openssl/crypto/rc4/asm/rc4-md5-x86_64.pl | 645 + + .../openssl/crypto/rc4/asm/rc4-parisc.pl | 321 + + .../OpensslLib/openssl/crypto/rc4/asm/rc4-s390x.pl | 241 + + .../openssl/crypto/rc4/asm/rc4-x86_64.pl | 687 + + .../OpensslLib/openssl/crypto/rc4/build.info | 33 + + .../OpensslLib/openssl/crypto/rc4/rc4_enc.c | 86 + + .../OpensslLib/openssl/crypto/rc4/rc4_locl.h | 16 + + .../OpensslLib/openssl/crypto/rc4/rc4_skey.c | 58 + + .../OpensslLib/openssl/crypto/rc5/asm/rc5-586.pl | 122 + + .../OpensslLib/openssl/crypto/rc5/build.info | 6 + + .../OpensslLib/openssl/crypto/rc5/rc5_ecb.c | 32 + + .../OpensslLib/openssl/crypto/rc5/rc5_enc.c | 160 + + .../OpensslLib/openssl/crypto/rc5/rc5_locl.h | 158 + + .../OpensslLib/openssl/crypto/rc5/rc5_skey.c | 61 + + .../OpensslLib/openssl/crypto/rc5/rc5cfb64.c | 74 + + .../OpensslLib/openssl/crypto/rc5/rc5ofb64.c | 61 + + .../openssl/crypto/ripemd/asm/rmd-586.pl | 603 + + .../OpensslLib/openssl/crypto/ripemd/build.info | 6 + + .../OpensslLib/openssl/crypto/ripemd/rmd_dgst.c | 282 + + .../OpensslLib/openssl/crypto/ripemd/rmd_locl.h | 88 + + .../OpensslLib/openssl/crypto/ripemd/rmd_one.c | 28 + + .../OpensslLib/openssl/crypto/ripemd/rmdconst.h | 350 + + .../OpensslLib/openssl/crypto/rsa/build.info | 6 + + .../OpensslLib/openssl/crypto/rsa/rsa_ameth.c | 866 ++ + .../OpensslLib/openssl/crypto/rsa/rsa_asn1.c | 81 + + .../OpensslLib/openssl/crypto/rsa/rsa_chk.c | 156 + + .../OpensslLib/openssl/crypto/rsa/rsa_crpt.c | 178 + + .../OpensslLib/openssl/crypto/rsa/rsa_depr.c | 61 + + .../OpensslLib/openssl/crypto/rsa/rsa_err.c | 185 + + .../OpensslLib/openssl/crypto/rsa/rsa_gen.c | 199 + + .../OpensslLib/openssl/crypto/rsa/rsa_lib.c | 310 + + .../OpensslLib/openssl/crypto/rsa/rsa_locl.h | 96 + + .../OpensslLib/openssl/crypto/rsa/rsa_meth.c | 273 + + .../OpensslLib/openssl/crypto/rsa/rsa_none.c | 43 + + .../OpensslLib/openssl/crypto/rsa/rsa_null.c | 93 + + .../OpensslLib/openssl/crypto/rsa/rsa_oaep.c | 286 + + .../OpensslLib/openssl/crypto/rsa/rsa_ossl.c | 790 ++ + .../OpensslLib/openssl/crypto/rsa/rsa_pk1.c | 245 + + .../OpensslLib/openssl/crypto/rsa/rsa_pmeth.c | 673 + + .../OpensslLib/openssl/crypto/rsa/rsa_prn.c | 42 + + .../OpensslLib/openssl/crypto/rsa/rsa_pss.c | 244 + + .../OpensslLib/openssl/crypto/rsa/rsa_saos.c | 94 + + .../OpensslLib/openssl/crypto/rsa/rsa_sign.c | 248 + + .../OpensslLib/openssl/crypto/rsa/rsa_ssl.c | 100 + + .../OpensslLib/openssl/crypto/rsa/rsa_x931.c | 116 + + .../OpensslLib/openssl/crypto/rsa/rsa_x931g.c | 195 + + .../Library/OpensslLib/openssl/crypto/s390xcap.c | 50 + + .../Library/OpensslLib/openssl/crypto/s390xcpuid.S | 180 + + .../OpensslLib/openssl/crypto/seed/build.info | 2 + + .../Library/OpensslLib/openssl/crypto/seed/seed.c | 590 + + .../OpensslLib/openssl/crypto/seed/seed_cbc.c | 23 + + .../OpensslLib/openssl/crypto/seed/seed_cfb.c | 20 + + .../OpensslLib/openssl/crypto/seed/seed_ecb.c | 19 + + .../OpensslLib/openssl/crypto/seed/seed_locl.h | 120 + + .../OpensslLib/openssl/crypto/seed/seed_ofb.c | 19 + + .../OpensslLib/openssl/crypto/sha/asm/sha1-586.pl | 1488 +++ + .../openssl/crypto/sha/asm/sha1-alpha.pl | 329 + + .../openssl/crypto/sha/asm/sha1-armv4-large.pl | 742 ++ + .../openssl/crypto/sha/asm/sha1-armv8.pl | 363 + + .../openssl/crypto/sha/asm/sha1-c64xplus.pl | 337 + + .../OpensslLib/openssl/crypto/sha/asm/sha1-ia64.pl | 314 + + .../openssl/crypto/sha/asm/sha1-mb-x86_64.pl | 1582 +++ + .../OpensslLib/openssl/crypto/sha/asm/sha1-mips.pl | 457 + + .../openssl/crypto/sha/asm/sha1-parisc.pl | 267 + + .../OpensslLib/openssl/crypto/sha/asm/sha1-ppc.pl | 351 + + .../openssl/crypto/sha/asm/sha1-s390x.pl | 251 + + .../openssl/crypto/sha/asm/sha1-sparcv9.pl | 434 + + .../openssl/crypto/sha/asm/sha1-sparcv9a.pl | 608 + + .../openssl/crypto/sha/asm/sha1-thumb.pl | 266 + + .../openssl/crypto/sha/asm/sha1-x86_64.pl | 2077 ++++ + .../openssl/crypto/sha/asm/sha256-586.pl | 1293 ++ + .../openssl/crypto/sha/asm/sha256-armv4.pl | 732 ++ + .../openssl/crypto/sha/asm/sha256-c64xplus.pl | 320 + + .../openssl/crypto/sha/asm/sha256-mb-x86_64.pl | 1568 +++ + .../openssl/crypto/sha/asm/sha512-586.pl | 924 ++ + .../openssl/crypto/sha/asm/sha512-armv4.pl | 668 + + .../openssl/crypto/sha/asm/sha512-armv8.pl | 446 + + .../openssl/crypto/sha/asm/sha512-c64xplus.pl | 438 + + .../openssl/crypto/sha/asm/sha512-ia64.pl | 692 ++ + .../openssl/crypto/sha/asm/sha512-mips.pl | 519 + + .../openssl/crypto/sha/asm/sha512-parisc.pl | 800 ++ + .../openssl/crypto/sha/asm/sha512-ppc.pl | 799 ++ + .../openssl/crypto/sha/asm/sha512-s390x.pl | 326 + + .../openssl/crypto/sha/asm/sha512-sparcv9.pl | 857 ++ + .../openssl/crypto/sha/asm/sha512-x86_64.pl | 2407 ++++ + .../openssl/crypto/sha/asm/sha512p8-ppc.pl | 431 + + .../OpensslLib/openssl/crypto/sha/build.info | 69 + + .../OpensslLib/openssl/crypto/sha/sha1_one.c | 28 + + .../OpensslLib/openssl/crypto/sha/sha1dgst.c | 17 + + .../Library/OpensslLib/openssl/crypto/sha/sha256.c | 386 + + .../Library/OpensslLib/openssl/crypto/sha/sha512.c | 678 + + .../OpensslLib/openssl/crypto/sha/sha_locl.h | 424 + + .../Library/OpensslLib/openssl/crypto/sparc_arch.h | 118 + + .../Library/OpensslLib/openssl/crypto/sparccpuid.S | 582 + + .../Library/OpensslLib/openssl/crypto/sparcv9cap.c | 294 + + .../OpensslLib/openssl/crypto/srp/build.info | 2 + + .../OpensslLib/openssl/crypto/srp/srp_lib.c | 0 + .../OpensslLib/openssl/crypto/srp/srp_vfy.c | 0 + .../OpensslLib/openssl/crypto/stack/build.info | 2 + + .../OpensslLib/openssl/crypto/stack/stack.c | 312 + + .../OpensslLib/openssl/crypto/threads_none.c | 124 + + .../OpensslLib/openssl/crypto/threads_pthread.c | 171 + + .../OpensslLib/openssl/crypto/threads_win.c | 136 + + .../OpensslLib/openssl/crypto/ts/build.info | 5 + + .../Library/OpensslLib/openssl/crypto/ts/ts_asn1.c | 259 + + .../Library/OpensslLib/openssl/crypto/ts/ts_conf.c | 468 + + .../Library/OpensslLib/openssl/crypto/ts/ts_err.c | 144 + + .../Library/OpensslLib/openssl/crypto/ts/ts_lcl.h | 183 + + .../Library/OpensslLib/openssl/crypto/ts/ts_lib.c | 93 + + .../OpensslLib/openssl/crypto/ts/ts_req_print.c | 51 + + .../OpensslLib/openssl/crypto/ts/ts_req_utils.c | 183 + + .../OpensslLib/openssl/crypto/ts/ts_rsp_print.c | 195 + + .../OpensslLib/openssl/crypto/ts/ts_rsp_sign.c | 904 ++ + .../OpensslLib/openssl/crypto/ts/ts_rsp_utils.c | 365 + + .../OpensslLib/openssl/crypto/ts/ts_rsp_verify.c | 635 + + .../OpensslLib/openssl/crypto/ts/ts_verify_ctx.c | 146 + + .../OpensslLib/openssl/crypto/txt_db/build.info | 2 + + .../OpensslLib/openssl/crypto/txt_db/txt_db.c | 301 + + .../OpensslLib/openssl/crypto/ui/build.info | 3 + + .../Library/OpensslLib/openssl/crypto/ui/ui_err.c | 72 + + .../Library/OpensslLib/openssl/crypto/ui/ui_lib.c | 826 ++ + .../Library/OpensslLib/openssl/crypto/ui/ui_locl.h | 97 + + .../OpensslLib/openssl/crypto/ui/ui_openssl.c | 700 ++ + .../Library/OpensslLib/openssl/crypto/ui/ui_util.c | 51 + + CryptoPkg/Library/OpensslLib/openssl/crypto/uid.c | 42 + + .../Library/OpensslLib/openssl/crypto/vms_rms.h | 58 + + .../openssl/crypto/whrlpool/asm/wp-mmx.pl | 507 + + .../openssl/crypto/whrlpool/asm/wp-x86_64.pl | 600 + + .../OpensslLib/openssl/crypto/whrlpool/build.info | 7 + + .../OpensslLib/openssl/crypto/whrlpool/wp_block.c | 792 ++ + .../OpensslLib/openssl/crypto/whrlpool/wp_dgst.c | 266 + + .../OpensslLib/openssl/crypto/whrlpool/wp_locl.h | 12 + + .../OpensslLib/openssl/crypto/x509/build.info | 10 + + .../OpensslLib/openssl/crypto/x509/by_dir.c | 388 + + .../OpensslLib/openssl/crypto/x509/by_file.c | 221 + + .../Library/OpensslLib/openssl/crypto/x509/t_crl.c | 89 + + .../Library/OpensslLib/openssl/crypto/x509/t_req.c | 198 + + .../OpensslLib/openssl/crypto/x509/t_x509.c | 376 + + .../OpensslLib/openssl/crypto/x509/x509_att.c | 329 + + .../OpensslLib/openssl/crypto/x509/x509_cmp.c | 459 + + .../OpensslLib/openssl/crypto/x509/x509_d2.c | 57 + + .../OpensslLib/openssl/crypto/x509/x509_def.c | 43 + + .../OpensslLib/openssl/crypto/x509/x509_err.c | 142 + + .../OpensslLib/openssl/crypto/x509/x509_ext.c | 160 + + .../OpensslLib/openssl/crypto/x509/x509_lcl.h | 142 + + .../OpensslLib/openssl/crypto/x509/x509_lu.c | 861 ++ + .../OpensslLib/openssl/crypto/x509/x509_obj.c | 182 + + .../OpensslLib/openssl/crypto/x509/x509_r2x.c | 67 + + .../OpensslLib/openssl/crypto/x509/x509_req.c | 298 + + .../OpensslLib/openssl/crypto/x509/x509_set.c | 159 + + .../OpensslLib/openssl/crypto/x509/x509_trs.c | 298 + + .../OpensslLib/openssl/crypto/x509/x509_txt.c | 177 + + .../OpensslLib/openssl/crypto/x509/x509_v3.c | 234 + + .../OpensslLib/openssl/crypto/x509/x509_vfy.c | 3275 +++++ + .../OpensslLib/openssl/crypto/x509/x509_vpm.c | 617 + + .../OpensslLib/openssl/crypto/x509/x509cset.c | 182 + + .../OpensslLib/openssl/crypto/x509/x509name.c | 358 + + .../OpensslLib/openssl/crypto/x509/x509rset.c | 40 + + .../OpensslLib/openssl/crypto/x509/x509spki.c | 75 + + .../OpensslLib/openssl/crypto/x509/x509type.c | 77 + + .../Library/OpensslLib/openssl/crypto/x509/x_all.c | 526 + + .../OpensslLib/openssl/crypto/x509/x_attrib.c | 55 + + .../Library/OpensslLib/openssl/crypto/x509/x_crl.c | 459 + + .../OpensslLib/openssl/crypto/x509/x_exten.c | 28 + + .../OpensslLib/openssl/crypto/x509/x_name.c | 557 + + .../OpensslLib/openssl/crypto/x509/x_pubkey.c | 374 + + .../Library/OpensslLib/openssl/crypto/x509/x_req.c | 68 + + .../OpensslLib/openssl/crypto/x509/x_x509.c | 224 + + .../OpensslLib/openssl/crypto/x509/x_x509a.c | 169 + + .../OpensslLib/openssl/crypto/x509v3/build.info | 8 + + .../OpensslLib/openssl/crypto/x509v3/ext_dat.h | 24 + + .../OpensslLib/openssl/crypto/x509v3/pcy_cache.c | 216 + + .../OpensslLib/openssl/crypto/x509v3/pcy_data.c | 77 + + .../OpensslLib/openssl/crypto/x509v3/pcy_int.h | 167 + + .../OpensslLib/openssl/crypto/x509v3/pcy_lib.c | 108 + + .../OpensslLib/openssl/crypto/x509v3/pcy_map.c | 81 + + .../OpensslLib/openssl/crypto/x509v3/pcy_node.c | 139 + + .../OpensslLib/openssl/crypto/x509v3/pcy_tree.c | 696 ++ + .../OpensslLib/openssl/crypto/x509v3/tabtest.c | 42 + + .../OpensslLib/openssl/crypto/x509v3/v3_addr.c | 1305 ++ + .../OpensslLib/openssl/crypto/x509v3/v3_akey.c | 160 + + .../OpensslLib/openssl/crypto/x509v3/v3_akeya.c | 23 + + .../OpensslLib/openssl/crypto/x509v3/v3_alt.c | 566 + + .../OpensslLib/openssl/crypto/x509v3/v3_asid.c | 852 ++ + .../OpensslLib/openssl/crypto/x509v3/v3_bcons.c | 84 + + .../OpensslLib/openssl/crypto/x509v3/v3_bitst.c | 93 + + .../OpensslLib/openssl/crypto/x509v3/v3_conf.c | 507 + + .../OpensslLib/openssl/crypto/x509v3/v3_cpols.c | 441 + + .../OpensslLib/openssl/crypto/x509v3/v3_crld.c | 509 + + .../OpensslLib/openssl/crypto/x509v3/v3_enum.c | 53 + + .../OpensslLib/openssl/crypto/x509v3/v3_extku.c | 100 + + .../OpensslLib/openssl/crypto/x509v3/v3_genn.c | 200 + + .../OpensslLib/openssl/crypto/x509v3/v3_ia5.c | 65 + + .../OpensslLib/openssl/crypto/x509v3/v3_info.c | 157 + + .../OpensslLib/openssl/crypto/x509v3/v3_int.c | 43 + + .../OpensslLib/openssl/crypto/x509v3/v3_lib.c | 360 + + .../OpensslLib/openssl/crypto/x509v3/v3_ncons.c | 513 + + .../OpensslLib/openssl/crypto/x509v3/v3_pci.c | 321 + + .../OpensslLib/openssl/crypto/x509v3/v3_pcia.c | 60 + + .../OpensslLib/openssl/crypto/x509v3/v3_pcons.c | 91 + + .../OpensslLib/openssl/crypto/x509v3/v3_pku.c | 65 + + .../OpensslLib/openssl/crypto/x509v3/v3_pmaps.c | 110 + + .../OpensslLib/openssl/crypto/x509v3/v3_prn.c | 210 + + .../OpensslLib/openssl/crypto/x509v3/v3_purp.c | 865 ++ + .../OpensslLib/openssl/crypto/x509v3/v3_skey.c | 106 + + .../OpensslLib/openssl/crypto/x509v3/v3_sxnet.c | 226 + + .../OpensslLib/openssl/crypto/x509v3/v3_tlsf.c | 137 + + .../OpensslLib/openssl/crypto/x509v3/v3_utl.c | 1195 ++ + .../OpensslLib/openssl/crypto/x509v3/v3conf.c | 79 + + .../OpensslLib/openssl/crypto/x509v3/v3err.c | 187 + + .../OpensslLib/openssl/crypto/x509v3/v3prin.c | 50 + + .../OpensslLib/openssl/crypto/x86_64cpuid.pl | 459 + + .../Library/OpensslLib/openssl/crypto/x86cpuid.pl | 561 + + CryptoPkg/Library/OpensslLib/openssl/demos/README | 9 + + .../Library/OpensslLib/openssl/demos/bio/Makefile | 30 + + .../Library/OpensslLib/openssl/demos/bio/README | 7 + + .../OpensslLib/openssl/demos/bio/accept.cnf | 17 + + .../OpensslLib/openssl/demos/bio/client-arg.c | 117 + + .../OpensslLib/openssl/demos/bio/client-conf.c | 126 + + .../Library/OpensslLib/openssl/demos/bio/cmod.cnf | 24 + + .../OpensslLib/openssl/demos/bio/connect.cnf | 9 + + .../OpensslLib/openssl/demos/bio/descrip.mms | 47 + + .../Library/OpensslLib/openssl/demos/bio/intca.pem | 23 + + .../Library/OpensslLib/openssl/demos/bio/root.pem | 22 + + .../Library/OpensslLib/openssl/demos/bio/saccept.c | 122 + + .../OpensslLib/openssl/demos/bio/sconnect.c | 131 + + .../OpensslLib/openssl/demos/bio/server-arg.c | 145 + + .../OpensslLib/openssl/demos/bio/server-cmod.c | 95 + + .../OpensslLib/openssl/demos/bio/server-conf.c | 140 + + .../OpensslLib/openssl/demos/bio/server-ec.pem | 17 + + .../OpensslLib/openssl/demos/bio/server.pem | 77 + + .../OpensslLib/openssl/demos/bio/shared.opt | 2 + + .../OpensslLib/openssl/demos/bio/static.opt | 2 + + .../Library/OpensslLib/openssl/demos/certs/README | 21 + + .../OpensslLib/openssl/demos/certs/apps/apps.cnf | 69 + + .../OpensslLib/openssl/demos/certs/apps/ckey.pem | 27 + + .../OpensslLib/openssl/demos/certs/apps/intkey.pem | 27 + + .../openssl/demos/certs/apps/mkacerts.sh | 45 + + .../openssl/demos/certs/apps/mkxcerts.sh | 29 + + .../openssl/demos/certs/apps/rootkey.pem | 27 + + .../OpensslLib/openssl/demos/certs/apps/skey.pem | 27 + + .../OpensslLib/openssl/demos/certs/apps/skey2.pem | 27 + + .../Library/OpensslLib/openssl/demos/certs/ca.cnf | 86 + + .../OpensslLib/openssl/demos/certs/mkcerts.sh | 96 + + .../OpensslLib/openssl/demos/certs/ocspquery.sh | 21 + + .../OpensslLib/openssl/demos/certs/ocsprun.sh | 14 + + .../OpensslLib/openssl/demos/cms/cacert.pem | 18 + + .../Library/OpensslLib/openssl/demos/cms/cakey.pem | 15 + + .../OpensslLib/openssl/demos/cms/cms_comp.c | 64 + + .../OpensslLib/openssl/demos/cms/cms_ddec.c | 88 + + .../Library/OpensslLib/openssl/demos/cms/cms_dec.c | 78 + + .../OpensslLib/openssl/demos/cms/cms_denc.c | 97 + + .../Library/OpensslLib/openssl/demos/cms/cms_enc.c | 92 + + .../OpensslLib/openssl/demos/cms/cms_sign.c | 88 + + .../OpensslLib/openssl/demos/cms/cms_sign2.c | 98 + + .../OpensslLib/openssl/demos/cms/cms_uncomp.c | 58 + + .../Library/OpensslLib/openssl/demos/cms/cms_ver.c | 85 + + .../Library/OpensslLib/openssl/demos/cms/comp.txt | 22 + + .../Library/OpensslLib/openssl/demos/cms/encr.txt | 3 + + .../Library/OpensslLib/openssl/demos/cms/sign.txt | 3 + + .../OpensslLib/openssl/demos/cms/signer.pem | 32 + + .../OpensslLib/openssl/demos/cms/signer2.pem | 32 + + .../Library/OpensslLib/openssl/demos/evp/aesccm.c | 125 + + .../Library/OpensslLib/openssl/demos/evp/aesgcm.c | 120 + + .../Library/OpensslLib/openssl/demos/pkcs12/README | 3 + + .../OpensslLib/openssl/demos/pkcs12/pkread.c | 68 + + .../OpensslLib/openssl/demos/pkcs12/pkwrite.c | 53 + + .../OpensslLib/openssl/demos/smime/cacert.pem | 18 + + .../OpensslLib/openssl/demos/smime/cakey.pem | 15 + + .../OpensslLib/openssl/demos/smime/encr.txt | 3 + + .../OpensslLib/openssl/demos/smime/sign.txt | 3 + + .../OpensslLib/openssl/demos/smime/signer.pem | 32 + + .../OpensslLib/openssl/demos/smime/signer2.pem | 32 + + .../Library/OpensslLib/openssl/demos/smime/smdec.c | 78 + + .../Library/OpensslLib/openssl/demos/smime/smenc.c | 91 + + .../OpensslLib/openssl/demos/smime/smsign.c | 88 + + .../OpensslLib/openssl/demos/smime/smsign2.c | 96 + + .../Library/OpensslLib/openssl/demos/smime/smver.c | 83 + + .../openssl/doc/CT_POLICY_EVAL_CTX_new.pod | 111 + + .../OpensslLib/openssl/doc/HOWTO/certificates.txt | 110 + + .../Library/OpensslLib/openssl/doc/HOWTO/keys.txt | 72 + + .../openssl/doc/HOWTO/proxy_certificates.txt | 319 + + CryptoPkg/Library/OpensslLib/openssl/doc/README | 20 + + .../OpensslLib/openssl/doc/SCT_validate.pod | 98 + + .../doc/SSL_CTX_set_ct_validation_callback.pod | 142 + + .../Library/OpensslLib/openssl/doc/apps/CA.pl.pod | 214 + + .../OpensslLib/openssl/doc/apps/asn1parse.pod | 208 + + .../Library/OpensslLib/openssl/doc/apps/ca.pod | 719 ++ + .../OpensslLib/openssl/doc/apps/ciphers.pod | 735 ++ + .../Library/OpensslLib/openssl/doc/apps/cms.pod | 737 ++ + .../Library/OpensslLib/openssl/doc/apps/config.pod | 386 + + .../Library/OpensslLib/openssl/doc/apps/crl.pod | 142 + + .../OpensslLib/openssl/doc/apps/crl2pkcs7.pod | 105 + + .../Library/OpensslLib/openssl/doc/apps/dgst.pod | 240 + + .../OpensslLib/openssl/doc/apps/dhparam.pod | 159 + + .../Library/OpensslLib/openssl/doc/apps/dsa.pod | 178 + + .../OpensslLib/openssl/doc/apps/dsaparam.pod | 124 + + .../Library/OpensslLib/openssl/doc/apps/ec.pod | 206 + + .../OpensslLib/openssl/doc/apps/ecparam.pod | 185 + + .../Library/OpensslLib/openssl/doc/apps/enc.pod | 353 + + .../Library/OpensslLib/openssl/doc/apps/engine.pod | 104 + + .../Library/OpensslLib/openssl/doc/apps/errstr.pod | 45 + + .../Library/OpensslLib/openssl/doc/apps/gendsa.pod | 91 + + .../OpensslLib/openssl/doc/apps/genpkey.pod | 277 + + .../Library/OpensslLib/openssl/doc/apps/genrsa.pod | 115 + + .../Library/OpensslLib/openssl/doc/apps/list.pod | 81 + + .../Library/OpensslLib/openssl/doc/apps/nseq.pod | 84 + + .../Library/OpensslLib/openssl/doc/apps/ocsp.pod | 466 + + .../OpensslLib/openssl/doc/apps/openssl.pod | 451 + + .../Library/OpensslLib/openssl/doc/apps/passwd.pod | 96 + + .../Library/OpensslLib/openssl/doc/apps/pkcs12.pod | 378 + + .../Library/OpensslLib/openssl/doc/apps/pkcs7.pod | 119 + + .../Library/OpensslLib/openssl/doc/apps/pkcs8.pod | 301 + + .../Library/OpensslLib/openssl/doc/apps/pkey.pod | 155 + + .../OpensslLib/openssl/doc/apps/pkeyparam.pod | 82 + + .../OpensslLib/openssl/doc/apps/pkeyutl.pod | 292 + + .../Library/OpensslLib/openssl/doc/apps/rand.pod | 69 + + .../Library/OpensslLib/openssl/doc/apps/rehash.pod | 139 + + .../Library/OpensslLib/openssl/doc/apps/req.pod | 658 + + .../Library/OpensslLib/openssl/doc/apps/rsa.pod | 216 + + .../Library/OpensslLib/openssl/doc/apps/rsautl.pod | 204 + + .../OpensslLib/openssl/doc/apps/s_client.pod | 603 + + .../OpensslLib/openssl/doc/apps/s_server.pod | 606 + + .../Library/OpensslLib/openssl/doc/apps/s_time.pod | 194 + + .../OpensslLib/openssl/doc/apps/sess_id.pod | 163 + + .../Library/OpensslLib/openssl/doc/apps/smime.pod | 515 + + .../Library/OpensslLib/openssl/doc/apps/speed.pod | 67 + + .../Library/OpensslLib/openssl/doc/apps/spkac.pod | 147 + + .../Library/OpensslLib/openssl/doc/apps/ts.pod | 650 + + .../Library/OpensslLib/openssl/doc/apps/tsget.pod | 199 + + .../Library/OpensslLib/openssl/doc/apps/verify.pod | 724 ++ + .../OpensslLib/openssl/doc/apps/version.pod | 80 + + .../Library/OpensslLib/openssl/doc/apps/x509.pod | 905 ++ + .../OpensslLib/openssl/doc/apps/x509v3_config.pod | 541 + + .../openssl/doc/crypto/ASN1_INTEGER_get_int64.pod | 132 + + .../openssl/doc/crypto/ASN1_OBJECT_new.pod | 51 + + .../openssl/doc/crypto/ASN1_STRING_length.pod | 93 + + .../openssl/doc/crypto/ASN1_STRING_new.pod | 52 + + .../openssl/doc/crypto/ASN1_STRING_print_ex.pod | 101 + + .../openssl/doc/crypto/ASN1_TIME_set.pod | 138 + + .../openssl/doc/crypto/ASN1_TYPE_get.pod | 100 + + .../openssl/doc/crypto/ASN1_generate_nconf.pod | 270 + + .../openssl/doc/crypto/ASYNC_WAIT_CTX_new.pod | 144 + + .../openssl/doc/crypto/ASYNC_start_job.pod | 330 + + .../OpensslLib/openssl/doc/crypto/BF_encrypt.pod | 117 + + .../OpensslLib/openssl/doc/crypto/BIO_ADDR.pod | 125 + + .../OpensslLib/openssl/doc/crypto/BIO_ADDRINFO.pod | 90 + + .../OpensslLib/openssl/doc/crypto/BIO_connect.pod | 112 + + .../OpensslLib/openssl/doc/crypto/BIO_ctrl.pod | 136 + + .../OpensslLib/openssl/doc/crypto/BIO_f_base64.pod | 91 + + .../OpensslLib/openssl/doc/crypto/BIO_f_buffer.pod | 92 + + .../OpensslLib/openssl/doc/crypto/BIO_f_cipher.pod | 81 + + .../OpensslLib/openssl/doc/crypto/BIO_f_md.pod | 156 + + .../OpensslLib/openssl/doc/crypto/BIO_f_null.pod | 39 + + .../OpensslLib/openssl/doc/crypto/BIO_f_ssl.pod | 298 + + .../openssl/doc/crypto/BIO_find_type.pod | 69 + + .../OpensslLib/openssl/doc/crypto/BIO_get_data.pod | 65 + + .../openssl/doc/crypto/BIO_get_ex_new_index.pod | 64 + + .../OpensslLib/openssl/doc/crypto/BIO_meth_new.pod | 131 + + .../OpensslLib/openssl/doc/crypto/BIO_new.pod | 72 + + .../OpensslLib/openssl/doc/crypto/BIO_new_CMS.pod | 75 + + .../openssl/doc/crypto/BIO_parse_hostserv.pod | 73 + + .../OpensslLib/openssl/doc/crypto/BIO_push.pod | 89 + + .../OpensslLib/openssl/doc/crypto/BIO_read.pod | 77 + + .../OpensslLib/openssl/doc/crypto/BIO_s_accept.pod | 222 + + .../OpensslLib/openssl/doc/crypto/BIO_s_bio.pod | 201 + + .../openssl/doc/crypto/BIO_s_connect.pod | 200 + + .../OpensslLib/openssl/doc/crypto/BIO_s_fd.pod | 98 + + .../OpensslLib/openssl/doc/crypto/BIO_s_file.pod | 159 + + .../OpensslLib/openssl/doc/crypto/BIO_s_mem.pod | 124 + + .../OpensslLib/openssl/doc/crypto/BIO_s_null.pod | 44 + + .../OpensslLib/openssl/doc/crypto/BIO_s_socket.pod | 54 + + .../openssl/doc/crypto/BIO_set_callback.pod | 221 + + .../openssl/doc/crypto/BIO_should_retry.pod | 132 + + .../openssl/doc/crypto/BN_BLINDING_new.pod | 126 + + .../OpensslLib/openssl/doc/crypto/BN_CTX_new.pod | 76 + + .../OpensslLib/openssl/doc/crypto/BN_CTX_start.pod | 57 + + .../OpensslLib/openssl/doc/crypto/BN_add.pod | 127 + + .../OpensslLib/openssl/doc/crypto/BN_add_word.pod | 61 + + .../OpensslLib/openssl/doc/crypto/BN_bn2bin.pod | 116 + + .../OpensslLib/openssl/doc/crypto/BN_cmp.pod | 51 + + .../OpensslLib/openssl/doc/crypto/BN_copy.pod | 69 + + .../openssl/doc/crypto/BN_generate_prime.pod | 194 + + .../openssl/doc/crypto/BN_mod_inverse.pod | 41 + + .../openssl/doc/crypto/BN_mod_mul_montgomery.pod | 90 + + .../openssl/doc/crypto/BN_mod_mul_reciprocal.pod | 76 + + .../OpensslLib/openssl/doc/crypto/BN_new.pod | 62 + + .../OpensslLib/openssl/doc/crypto/BN_num_bytes.pod | 61 + + .../OpensslLib/openssl/doc/crypto/BN_rand.pod | 68 + + .../OpensslLib/openssl/doc/crypto/BN_set_bit.pod | 69 + + .../OpensslLib/openssl/doc/crypto/BN_swap.pod | 28 + + .../OpensslLib/openssl/doc/crypto/BN_zero.pod | 67 + + .../OpensslLib/openssl/doc/crypto/BUF_MEM_new.pod | 77 + + .../openssl/doc/crypto/CMS_add0_cert.pod | 70 + + .../openssl/doc/crypto/CMS_add1_recipient_cert.pod | 66 + + .../openssl/doc/crypto/CMS_add1_signer.pod | 106 + + .../OpensslLib/openssl/doc/crypto/CMS_compress.pod | 81 + + .../OpensslLib/openssl/doc/crypto/CMS_decrypt.pod | 81 + + .../OpensslLib/openssl/doc/crypto/CMS_encrypt.pod | 104 + + .../OpensslLib/openssl/doc/crypto/CMS_final.pod | 46 + + .../openssl/doc/crypto/CMS_get0_RecipientInfos.pod | 130 + + .../openssl/doc/crypto/CMS_get0_SignerInfos.pod | 89 + + .../openssl/doc/crypto/CMS_get0_type.pod | 81 + + .../openssl/doc/crypto/CMS_get1_ReceiptRequest.pod | 72 + + .../OpensslLib/openssl/doc/crypto/CMS_sign.pod | 128 + + .../openssl/doc/crypto/CMS_sign_receipt.pod | 50 + + .../openssl/doc/crypto/CMS_uncompress.pod | 59 + + .../OpensslLib/openssl/doc/crypto/CMS_verify.pod | 131 + + .../openssl/doc/crypto/CMS_verify_receipt.pod | 52 + + .../openssl/doc/crypto/CONF_modules_free.pod | 62 + + .../openssl/doc/crypto/CONF_modules_load_file.pod | 136 + + .../openssl/doc/crypto/CRYPTO_THREAD_run_once.pod | 163 + + .../openssl/doc/crypto/CRYPTO_get_ex_new_index.pod | 161 + + .../doc/crypto/CTLOG_STORE_get0_log_by_id.pod | 49 + + .../openssl/doc/crypto/CTLOG_STORE_new.pod | 79 + + .../OpensslLib/openssl/doc/crypto/CTLOG_new.pod | 72 + + .../openssl/doc/crypto/CT_POLICY_EVAL_CTX_new.pod | 96 + + .../openssl/doc/crypto/DEFINE_STACK_OF.pod | 233 + + .../openssl/doc/crypto/DES_random_key.pod | 310 + + .../openssl/doc/crypto/DH_generate_key.pod | 54 + + .../openssl/doc/crypto/DH_generate_parameters.pod | 134 + + .../OpensslLib/openssl/doc/crypto/DH_get0_pqg.pod | 112 + + .../openssl/doc/crypto/DH_get_1024_160.pod | 74 + + .../OpensslLib/openssl/doc/crypto/DH_meth_new.pod | 156 + + .../OpensslLib/openssl/doc/crypto/DH_new.pod | 46 + + .../openssl/doc/crypto/DH_set_method.pod | 85 + + .../OpensslLib/openssl/doc/crypto/DH_size.pod | 47 + + .../OpensslLib/openssl/doc/crypto/DSA_SIG_new.pod | 58 + + .../OpensslLib/openssl/doc/crypto/DSA_do_sign.pod | 52 + + .../OpensslLib/openssl/doc/crypto/DSA_dup_DH.pod | 41 + + .../openssl/doc/crypto/DSA_generate_key.pod | 39 + + .../openssl/doc/crypto/DSA_generate_parameters.pod | 122 + + .../OpensslLib/openssl/doc/crypto/DSA_get0_pqg.pod | 102 + + .../OpensslLib/openssl/doc/crypto/DSA_meth_new.pod | 193 + + .../OpensslLib/openssl/doc/crypto/DSA_new.pod | 48 + + .../openssl/doc/crypto/DSA_set_method.pod | 85 + + .../OpensslLib/openssl/doc/crypto/DSA_sign.pod | 70 + + .../OpensslLib/openssl/doc/crypto/DSA_size.pod | 44 + + .../openssl/doc/crypto/ECDSA_SIG_new.pod | 207 + + .../openssl/doc/crypto/ECPKParameters_print.pod | 44 + + .../openssl/doc/crypto/EC_GFp_simple_method.pod | 69 + + .../openssl/doc/crypto/EC_GROUP_copy.pod | 206 + + .../OpensslLib/openssl/doc/crypto/EC_GROUP_new.pod | 120 + + .../openssl/doc/crypto/EC_KEY_get_enc_flags.pod | 59 + + .../OpensslLib/openssl/doc/crypto/EC_KEY_new.pod | 183 + + .../OpensslLib/openssl/doc/crypto/EC_POINT_add.pod | 80 + + .../OpensslLib/openssl/doc/crypto/EC_POINT_new.pod | 196 + + .../OpensslLib/openssl/doc/crypto/ENGINE_add.pod | 611 + + .../OpensslLib/openssl/doc/crypto/ERR_GET_LIB.pod | 66 + + .../openssl/doc/crypto/ERR_clear_error.pod | 34 + + .../openssl/doc/crypto/ERR_error_string.pod | 74 + + .../openssl/doc/crypto/ERR_get_error.pod | 79 + + .../openssl/doc/crypto/ERR_load_crypto_strings.pod | 62 + + .../openssl/doc/crypto/ERR_load_strings.pod | 58 + + .../openssl/doc/crypto/ERR_print_errors.pod | 60 + + .../openssl/doc/crypto/ERR_put_error.pod | 76 + + .../openssl/doc/crypto/ERR_remove_state.pod | 53 + + .../OpensslLib/openssl/doc/crypto/ERR_set_mark.pod | 43 + + .../openssl/doc/crypto/EVP_BytesToKey.pod | 78 + + .../doc/crypto/EVP_CIPHER_CTX_get_cipher_data.pod | 51 + + .../openssl/doc/crypto/EVP_CIPHER_meth_new.pod | 238 + + .../openssl/doc/crypto/EVP_DigestInit.pod | 259 + + .../openssl/doc/crypto/EVP_DigestSignInit.pod | 96 + + .../openssl/doc/crypto/EVP_DigestVerifyInit.pod | 91 + + .../openssl/doc/crypto/EVP_EncodeInit.pod | 162 + + .../openssl/doc/crypto/EVP_EncryptInit.pod | 662 + + .../openssl/doc/crypto/EVP_MD_meth_new.pod | 170 + + .../OpensslLib/openssl/doc/crypto/EVP_OpenInit.pod | 70 + + .../openssl/doc/crypto/EVP_PKEY_CTX_ctrl.pod | 154 + + .../openssl/doc/crypto/EVP_PKEY_CTX_new.pod | 62 + + .../doc/crypto/EVP_PKEY_CTX_set_hkdf_md.pod | 128 + + .../doc/crypto/EVP_PKEY_CTX_set_tls1_prf_md.pod | 108 + + .../OpensslLib/openssl/doc/crypto/EVP_PKEY_cmp.pod | 73 + + .../openssl/doc/crypto/EVP_PKEY_decrypt.pod | 102 + + .../openssl/doc/crypto/EVP_PKEY_derive.pod | 102 + + .../openssl/doc/crypto/EVP_PKEY_encrypt.pod | 108 + + .../doc/crypto/EVP_PKEY_get_default_digest_nid.pod | 50 + + .../openssl/doc/crypto/EVP_PKEY_keygen.pod | 175 + + .../OpensslLib/openssl/doc/crypto/EVP_PKEY_new.pod | 61 + + .../openssl/doc/crypto/EVP_PKEY_print_private.pod | 62 + + .../openssl/doc/crypto/EVP_PKEY_set1_RSA.pod | 120 + + .../openssl/doc/crypto/EVP_PKEY_sign.pod | 115 + + .../openssl/doc/crypto/EVP_PKEY_verify.pod | 100 + + .../openssl/doc/crypto/EVP_PKEY_verify_recover.pod | 112 + + .../OpensslLib/openssl/doc/crypto/EVP_SealInit.pod | 90 + + .../OpensslLib/openssl/doc/crypto/EVP_SignInit.pod | 110 + + .../openssl/doc/crypto/EVP_VerifyInit.pod | 99 + + .../Library/OpensslLib/openssl/doc/crypto/HMAC.pod | 151 + + .../Library/OpensslLib/openssl/doc/crypto/MD5.pod | 101 + + .../OpensslLib/openssl/doc/crypto/MDC2_Init.pod | 68 + + .../OpensslLib/openssl/doc/crypto/OBJ_nid2obj.pod | 198 + + .../openssl/doc/crypto/OCSP_REQUEST_new.pod | 118 + + .../openssl/doc/crypto/OCSP_cert_to_id.pod | 89 + + .../openssl/doc/crypto/OCSP_request_add1_nonce.pod | 84 + + .../openssl/doc/crypto/OCSP_resp_find_status.pod | 139 + + .../openssl/doc/crypto/OCSP_response_status.pod | 100 + + .../openssl/doc/crypto/OCSP_sendreq_new.pod | 122 + + .../openssl/doc/crypto/OPENSSL_Applink.pod | 31 + + .../openssl/doc/crypto/OPENSSL_LH_COMPFUNC.pod | 239 + + .../openssl/doc/crypto/OPENSSL_LH_stats.pod | 64 + + .../openssl/doc/crypto/OPENSSL_VERSION_NUMBER.pod | 106 + + .../openssl/doc/crypto/OPENSSL_config.pod | 74 + + .../openssl/doc/crypto/OPENSSL_ia32cap.pod | 140 + + .../openssl/doc/crypto/OPENSSL_init_crypto.pod | 245 + + .../openssl/doc/crypto/OPENSSL_instrument_bus.pod | 53 + + .../doc/crypto/OPENSSL_load_builtin_modules.pod | 56 + + .../openssl/doc/crypto/OPENSSL_malloc.pod | 207 + + .../openssl/doc/crypto/OPENSSL_secure_malloc.pod | 123 + + .../doc/crypto/OpenSSL_add_all_algorithms.pod | 90 + + .../OpensslLib/openssl/doc/crypto/PEM_read.pod | 127 + + .../OpensslLib/openssl/doc/crypto/PEM_read_CMS.pod | 97 + + .../openssl/doc/crypto/PEM_read_bio_PrivateKey.pod | 481 + + .../doc/crypto/PEM_write_bio_CMS_stream.pod | 50 + + .../doc/crypto/PEM_write_bio_PKCS7_stream.pod | 49 + + .../openssl/doc/crypto/PKCS12_create.pod | 76 + + .../openssl/doc/crypto/PKCS12_newpass.pod | 103 + + .../OpensslLib/openssl/doc/crypto/PKCS12_parse.pod | 62 + + .../openssl/doc/crypto/PKCS5_PBKDF2_HMAC.pod | 73 + + .../openssl/doc/crypto/PKCS7_decrypt.pod | 57 + + .../openssl/doc/crypto/PKCS7_encrypt.pod | 88 + + .../OpensslLib/openssl/doc/crypto/PKCS7_sign.pod | 124 + + .../openssl/doc/crypto/PKCS7_sign_add_signer.pod | 96 + + .../OpensslLib/openssl/doc/crypto/PKCS7_verify.pod | 128 + + .../OpensslLib/openssl/doc/crypto/RAND_add.pod | 79 + + .../OpensslLib/openssl/doc/crypto/RAND_bytes.pod | 58 + + .../OpensslLib/openssl/doc/crypto/RAND_cleanup.pod | 42 + + .../OpensslLib/openssl/doc/crypto/RAND_egd.pod | 87 + + .../openssl/doc/crypto/RAND_load_file.pod | 79 + + .../openssl/doc/crypto/RAND_set_rand_method.pod | 81 + + .../OpensslLib/openssl/doc/crypto/RC4_set_key.pod | 66 + + .../openssl/doc/crypto/RIPEMD160_Init.pod | 72 + + .../openssl/doc/crypto/RSA_blinding_on.pod | 44 + + .../openssl/doc/crypto/RSA_check_key.pod | 84 + + .../openssl/doc/crypto/RSA_generate_key.pod | 88 + + .../OpensslLib/openssl/doc/crypto/RSA_get0_key.pod | 108 + + .../OpensslLib/openssl/doc/crypto/RSA_meth_new.pod | 235 + + .../OpensslLib/openssl/doc/crypto/RSA_new.pod | 47 + + .../doc/crypto/RSA_padding_add_PKCS1_type_1.pod | 122 + + .../OpensslLib/openssl/doc/crypto/RSA_print.pod | 52 + + .../openssl/doc/crypto/RSA_private_encrypt.pod | 74 + + .../openssl/doc/crypto/RSA_public_encrypt.pod | 88 + + .../openssl/doc/crypto/RSA_set_method.pod | 180 + + .../OpensslLib/openssl/doc/crypto/RSA_sign.pod | 65 + + .../doc/crypto/RSA_sign_ASN1_OCTET_STRING.pod | 63 + + .../OpensslLib/openssl/doc/crypto/RSA_size.pod | 46 + + .../OpensslLib/openssl/doc/crypto/SCT_new.pod | 194 + + .../OpensslLib/openssl/doc/crypto/SCT_print.pod | 52 + + .../OpensslLib/openssl/doc/crypto/SCT_validate.pod | 96 + + .../OpensslLib/openssl/doc/crypto/SHA256_Init.pod | 108 + + .../openssl/doc/crypto/SMIME_read_CMS.pod | 75 + + .../openssl/doc/crypto/SMIME_read_PKCS7.pod | 78 + + .../openssl/doc/crypto/SMIME_write_CMS.pod | 69 + + .../openssl/doc/crypto/SMIME_write_PKCS7.pod | 70 + + .../OpensslLib/openssl/doc/crypto/SSL_set_bio.pod | 108 + + .../OpensslLib/openssl/doc/crypto/UI_new.pod | 186 + + .../openssl/doc/crypto/X509V3_get_d2i.pod | 241 + + .../openssl/doc/crypto/X509_ALGOR_dup.pod | 48 + + .../openssl/doc/crypto/X509_CRL_get0_by_serial.pod | 112 + + .../doc/crypto/X509_EXTENSION_set_object.pod | 96 + + .../openssl/doc/crypto/X509_LOOKUP_hash_dir.pod | 131 + + .../doc/crypto/X509_NAME_ENTRY_get_object.pod | 77 + + .../doc/crypto/X509_NAME_add_entry_by_txt.pod | 123 + + .../openssl/doc/crypto/X509_NAME_get0_der.pod | 40 + + .../doc/crypto/X509_NAME_get_index_by_NID.pod | 123 + + .../openssl/doc/crypto/X509_NAME_print_ex.pod | 112 + + .../openssl/doc/crypto/X509_PUBKEY_new.pod | 120 + + .../openssl/doc/crypto/X509_SIG_get0.pod | 36 + + .../doc/crypto/X509_STORE_CTX_get_error.pod | 338 + + .../openssl/doc/crypto/X509_STORE_CTX_new.pod | 174 + + .../doc/crypto/X509_STORE_CTX_set_verify_cb.pod | 215 + + .../openssl/doc/crypto/X509_STORE_get0_param.pod | 57 + + .../openssl/doc/crypto/X509_STORE_new.pod | 58 + + .../doc/crypto/X509_STORE_set_verify_cb_func.pod | 267 + + .../doc/crypto/X509_VERIFY_PARAM_set_flags.pod | 342 + + .../openssl/doc/crypto/X509_check_ca.pod | 45 + + .../openssl/doc/crypto/X509_check_host.pod | 157 + + .../openssl/doc/crypto/X509_check_issued.pod | 45 + + .../OpensslLib/openssl/doc/crypto/X509_digest.pod | 65 + + .../OpensslLib/openssl/doc/crypto/X509_dup.pod | 303 + + .../openssl/doc/crypto/X509_get0_signature.pod | 97 + + .../openssl/doc/crypto/X509_get0_uids.pod | 57 + + .../doc/crypto/X509_get_extension_flags.pod | 175 + + .../openssl/doc/crypto/X509_get_notBefore.pod | 103 + + .../openssl/doc/crypto/X509_get_pubkey.pod | 87 + + .../openssl/doc/crypto/X509_get_serialNumber.pod | 71 + + .../openssl/doc/crypto/X509_get_subject_name.pod | 86 + + .../openssl/doc/crypto/X509_get_version.pod | 83 + + .../OpensslLib/openssl/doc/crypto/X509_new.pod | 83 + + .../OpensslLib/openssl/doc/crypto/X509_sign.pod | 99 + + .../openssl/doc/crypto/X509_verify_cert.pod | 60 + + .../openssl/doc/crypto/X509v3_get_ext_by_NID.pod | 140 + + .../Library/OpensslLib/openssl/doc/crypto/bio.pod | 90 + + .../OpensslLib/openssl/doc/crypto/crypto.pod | 62 + + .../Library/OpensslLib/openssl/doc/crypto/ct.pod | 55 + + .../OpensslLib/openssl/doc/crypto/d2i_DHparams.pod | 35 + + .../openssl/doc/crypto/d2i_Netscape_RSA.pod | 38 + + .../openssl/doc/crypto/d2i_PKCS8PrivateKey_bio.pod | 61 + + .../openssl/doc/crypto/d2i_PrivateKey.pod | 71 + + .../OpensslLib/openssl/doc/crypto/d2i_X509.pod | 598 + + .../OpensslLib/openssl/doc/crypto/des_modes.pod | 263 + + .../Library/OpensslLib/openssl/doc/crypto/evp.pod | 116 + + .../openssl/doc/crypto/i2d_CMS_bio_stream.pod | 53 + + .../openssl/doc/crypto/i2d_PKCS7_bio_stream.pod | 53 + + .../openssl/doc/crypto/i2d_re_X509_tbs.pod | 79 + + .../OpensslLib/openssl/doc/crypto/o2i_SCT_LIST.pod | 48 + + .../Library/OpensslLib/openssl/doc/crypto/x509.pod | 75 + + .../OpensslLib/openssl/doc/dir-locals.example.el | 15 + + .../OpensslLib/openssl/doc/fingerprints.txt | 27 + + .../OpensslLib/openssl/doc/openssl-c-indent.el | 62 + + .../OpensslLib/openssl/doc/ssl/DTLSv1_listen.pod | 102 + + .../openssl/doc/ssl/OPENSSL_init_ssl.pod | 84 + + .../openssl/doc/ssl/SSL_CIPHER_get_name.pod | 128 + + .../doc/ssl/SSL_COMP_add_compression_method.pod | 116 + + .../openssl/doc/ssl/SSL_CONF_CTX_new.pod | 50 + + .../openssl/doc/ssl/SSL_CONF_CTX_set1_prefix.pod | 58 + + .../openssl/doc/ssl/SSL_CONF_CTX_set_flags.pod | 84 + + .../openssl/doc/ssl/SSL_CONF_CTX_set_ssl_ctx.pod | 56 + + .../OpensslLib/openssl/doc/ssl/SSL_CONF_cmd.pod | 553 + + .../openssl/doc/ssl/SSL_CONF_cmd_argv.pod | 51 + + .../openssl/doc/ssl/SSL_CTX_add1_chain_cert.pod | 158 + + .../doc/ssl/SSL_CTX_add_extra_chain_cert.pod | 80 + + .../openssl/doc/ssl/SSL_CTX_add_session.pod | 82 + + .../OpensslLib/openssl/doc/ssl/SSL_CTX_config.pod | 93 + + .../OpensslLib/openssl/doc/ssl/SSL_CTX_ctrl.pod | 43 + + .../openssl/doc/ssl/SSL_CTX_dane_enable.pod | 382 + + .../openssl/doc/ssl/SSL_CTX_flush_sessions.pod | 56 + + .../OpensslLib/openssl/doc/ssl/SSL_CTX_free.pod | 51 + + .../openssl/doc/ssl/SSL_CTX_get0_param.pod | 64 + + .../openssl/doc/ssl/SSL_CTX_get_verify_mode.pod | 59 + + .../doc/ssl/SSL_CTX_has_client_custom_ext.pod | 37 + + .../doc/ssl/SSL_CTX_load_verify_locations.pod | 161 + + .../OpensslLib/openssl/doc/ssl/SSL_CTX_new.pod | 218 + + .../openssl/doc/ssl/SSL_CTX_sess_number.pod | 85 + + .../doc/ssl/SSL_CTX_sess_set_cache_size.pod | 62 + + .../openssl/doc/ssl/SSL_CTX_sess_set_get_cb.pod | 96 + + .../openssl/doc/ssl/SSL_CTX_sessions.pod | 43 + + .../openssl/doc/ssl/SSL_CTX_set1_curves.pod | 90 + + .../openssl/doc/ssl/SSL_CTX_set1_sigalgs.pod | 113 + + .../doc/ssl/SSL_CTX_set1_verify_cert_store.pod | 100 + + .../openssl/doc/ssl/SSL_CTX_set_alpn_select_cb.pod | 136 + + .../openssl/doc/ssl/SSL_CTX_set_cert_cb.pod | 77 + + .../openssl/doc/ssl/SSL_CTX_set_cert_store.pod | 73 + + .../doc/ssl/SSL_CTX_set_cert_verify_callback.pod | 74 + + .../openssl/doc/ssl/SSL_CTX_set_cipher_list.pod | 74 + + .../openssl/doc/ssl/SSL_CTX_set_client_CA_list.pod | 103 + + .../openssl/doc/ssl/SSL_CTX_set_client_cert_cb.pod | 103 + + .../doc/ssl/SSL_CTX_set_ct_validation_callback.pod | 138 + + .../doc/ssl/SSL_CTX_set_ctlog_list_file.pod | 53 + + .../doc/ssl/SSL_CTX_set_default_passwd_cb.pod | 113 + + .../doc/ssl/SSL_CTX_set_generate_session_id.pod | 139 + + .../openssl/doc/ssl/SSL_CTX_set_info_callback.pod | 162 + + .../openssl/doc/ssl/SSL_CTX_set_max_cert_list.pod | 82 + + .../doc/ssl/SSL_CTX_set_min_proto_version.pod | 60 + + .../openssl/doc/ssl/SSL_CTX_set_mode.pod | 114 + + .../openssl/doc/ssl/SSL_CTX_set_msg_callback.pod | 103 + + .../openssl/doc/ssl/SSL_CTX_set_options.pod | 292 + + .../doc/ssl/SSL_CTX_set_psk_client_callback.pod | 63 + + .../openssl/doc/ssl/SSL_CTX_set_quiet_shutdown.pod | 72 + + .../openssl/doc/ssl/SSL_CTX_set_read_ahead.pod | 60 + + .../openssl/doc/ssl/SSL_CTX_set_security_level.pod | 169 + + .../doc/ssl/SSL_CTX_set_session_cache_mode.pod | 141 + + .../doc/ssl/SSL_CTX_set_session_id_context.pod | 92 + + .../doc/ssl/SSL_CTX_set_split_send_fragment.pod | 132 + + .../openssl/doc/ssl/SSL_CTX_set_ssl_version.pod | 70 + + .../openssl/doc/ssl/SSL_CTX_set_timeout.pod | 68 + + .../doc/ssl/SSL_CTX_set_tlsext_status_cb.pod | 125 + + .../doc/ssl/SSL_CTX_set_tlsext_ticket_key_cb.pod | 198 + + .../doc/ssl/SSL_CTX_set_tmp_dh_callback.pod | 137 + + .../openssl/doc/ssl/SSL_CTX_set_verify.pod | 298 + + .../openssl/doc/ssl/SSL_CTX_use_certificate.pod | 180 + + .../doc/ssl/SSL_CTX_use_psk_identity_hint.pod | 87 + + .../openssl/doc/ssl/SSL_CTX_use_serverinfo.pod | 56 + + .../openssl/doc/ssl/SSL_SESSION_free.pod | 65 + + .../openssl/doc/ssl/SSL_SESSION_get0_cipher.pod | 42 + + .../openssl/doc/ssl/SSL_SESSION_get0_hostname.pod | 37 + + .../doc/ssl/SSL_SESSION_get0_id_context.pod | 41 + + .../doc/ssl/SSL_SESSION_get_protocol_version.pod | 44 + + .../openssl/doc/ssl/SSL_SESSION_get_time.pod | 76 + + .../openssl/doc/ssl/SSL_SESSION_has_ticket.pod | 53 + + .../openssl/doc/ssl/SSL_SESSION_set1_id.pod | 41 + + .../OpensslLib/openssl/doc/ssl/SSL_accept.pod | 82 + + .../openssl/doc/ssl/SSL_alert_type_string.pod | 242 + + .../OpensslLib/openssl/doc/ssl/SSL_check_chain.pod | 94 + + .../OpensslLib/openssl/doc/ssl/SSL_clear.pod | 84 + + .../OpensslLib/openssl/doc/ssl/SSL_connect.pod | 82 + + .../openssl/doc/ssl/SSL_do_handshake.pod | 81 + + .../openssl/doc/ssl/SSL_extension_supported.pod | 145 + + .../OpensslLib/openssl/doc/ssl/SSL_free.pod | 54 + + .../openssl/doc/ssl/SSL_get0_peer_scts.pod | 45 + + .../OpensslLib/openssl/doc/ssl/SSL_get_SSL_CTX.pod | 35 + + .../openssl/doc/ssl/SSL_get_all_async_fds.pod | 88 + + .../OpensslLib/openssl/doc/ssl/SSL_get_ciphers.pod | 84 + + .../openssl/doc/ssl/SSL_get_client_CA_list.pod | 62 + + .../openssl/doc/ssl/SSL_get_client_random.pod | 88 + + .../openssl/doc/ssl/SSL_get_current_cipher.pod | 55 + + .../openssl/doc/ssl/SSL_get_default_timeout.pod | 50 + + .../OpensslLib/openssl/doc/ssl/SSL_get_error.pod | 143 + + .../openssl/doc/ssl/SSL_get_extms_support.pod | 40 + + .../OpensslLib/openssl/doc/ssl/SSL_get_fd.pod | 53 + + .../openssl/doc/ssl/SSL_get_peer_cert_chain.pod | 77 + + .../openssl/doc/ssl/SSL_get_peer_certificate.pod | 64 + + .../openssl/doc/ssl/SSL_get_psk_identity.pod | 44 + + .../OpensslLib/openssl/doc/ssl/SSL_get_rbio.pod | 49 + + .../OpensslLib/openssl/doc/ssl/SSL_get_session.pod | 82 + + .../openssl/doc/ssl/SSL_get_shared_sigalgs.pod | 86 + + .../openssl/doc/ssl/SSL_get_verify_result.pod | 66 + + .../OpensslLib/openssl/doc/ssl/SSL_get_version.pod | 67 + + .../openssl/doc/ssl/SSL_library_init.pod | 57 + + .../openssl/doc/ssl/SSL_load_client_CA_file.pod | 71 + + .../Library/OpensslLib/openssl/doc/ssl/SSL_new.pod | 61 + + .../OpensslLib/openssl/doc/ssl/SSL_pending.pod | 68 + + .../OpensslLib/openssl/doc/ssl/SSL_read.pod | 121 + + .../openssl/doc/ssl/SSL_rstate_string.pod | 68 + + .../openssl/doc/ssl/SSL_session_reused.pod | 54 + + .../OpensslLib/openssl/doc/ssl/SSL_set1_host.pod | 121 + + .../OpensslLib/openssl/doc/ssl/SSL_set_bio.pod | 108 + + .../openssl/doc/ssl/SSL_set_connect_state.pod | 64 + + .../OpensslLib/openssl/doc/ssl/SSL_set_fd.pod | 63 + + .../OpensslLib/openssl/doc/ssl/SSL_set_session.pod | 70 + + .../openssl/doc/ssl/SSL_set_shutdown.pod | 81 + + .../openssl/doc/ssl/SSL_set_verify_result.pod | 47 + + .../OpensslLib/openssl/doc/ssl/SSL_shutdown.pod | 132 + + .../openssl/doc/ssl/SSL_state_string.pod | 54 + + .../OpensslLib/openssl/doc/ssl/SSL_want.pod | 103 + + .../OpensslLib/openssl/doc/ssl/SSL_write.pod | 111 + + .../OpensslLib/openssl/doc/ssl/d2i_SSL_SESSION.pod | 49 + + .../Library/OpensslLib/openssl/doc/ssl/ssl.pod | 833 ++ + CryptoPkg/Library/OpensslLib/openssl/e_os.h | 520 + + .../OpensslLib/openssl/engines/afalg/build.info | 13 + + .../OpensslLib/openssl/engines/afalg/e_afalg.c | 834 ++ + .../OpensslLib/openssl/engines/afalg/e_afalg.ec | 1 + + .../OpensslLib/openssl/engines/afalg/e_afalg.h | 75 + + .../OpensslLib/openssl/engines/afalg/e_afalg_err.c | 111 + + .../OpensslLib/openssl/engines/afalg/e_afalg_err.h | 60 + + .../openssl/engines/asm/e_padlock-x86.pl | 618 + + .../openssl/engines/asm/e_padlock-x86_64.pl | 574 + + .../Library/OpensslLib/openssl/engines/build.info | 32 + + .../Library/OpensslLib/openssl/engines/e_capi.c | 1916 +++ + .../Library/OpensslLib/openssl/engines/e_capi.ec | 1 + + .../OpensslLib/openssl/engines/e_capi_err.c | 143 + + .../OpensslLib/openssl/engines/e_capi_err.h | 88 + + .../Library/OpensslLib/openssl/engines/e_chil.c | 1285 ++ + .../Library/OpensslLib/openssl/engines/e_chil.ec | 1 + + .../OpensslLib/openssl/engines/e_chil_err.c | 111 + + .../OpensslLib/openssl/engines/e_chil_err.h | 64 + + .../Library/OpensslLib/openssl/engines/e_dasync.c | 769 ++ + .../Library/OpensslLib/openssl/engines/e_dasync.ec | 1 + + .../OpensslLib/openssl/engines/e_dasync_err.c | 102 + + .../OpensslLib/openssl/engines/e_dasync_err.h | 52 + + .../OpensslLib/openssl/engines/e_ossltest.c | 568 + + .../OpensslLib/openssl/engines/e_ossltest.ec | 1 + + .../OpensslLib/openssl/engines/e_ossltest_err.c | 89 + + .../OpensslLib/openssl/engines/e_ossltest_err.h | 41 + + .../Library/OpensslLib/openssl/engines/e_padlock.c | 747 ++ + .../OpensslLib/openssl/engines/e_padlock.ec | 1 + + .../OpensslLib/openssl/engines/engine_vector.mar | 24 + + .../openssl/engines/vendor_defns/hwcryptohook.h | 509 + + .../openssl/external/perl/Downloaded.txt | 13 + + .../external/perl/Text-Template-1.46/Artistic | 131 + + .../external/perl/Text-Template-1.46/COPYING | 340 + + .../external/perl/Text-Template-1.46/INSTALL | 31 + + .../external/perl/Text-Template-1.46/MANIFEST | 25 + + .../external/perl/Text-Template-1.46/META.json | 39 + + .../external/perl/Text-Template-1.46/META.yml | 21 + + .../external/perl/Text-Template-1.46/Makefile.PL | 7 + + .../external/perl/Text-Template-1.46/README | 339 + + .../perl/Text-Template-1.46/lib/Text/Template.pm | 1973 +++ + .../lib/Text/Template/Preprocess.pm | 144 + + .../perl/Text-Template-1.46/t/00-version.t | 11 + + .../external/perl/Text-Template-1.46/t/01-basic.t | 266 + + .../external/perl/Text-Template-1.46/t/02-hash.t | 111 + + .../external/perl/Text-Template-1.46/t/03-out.t | 56 + + .../external/perl/Text-Template-1.46/t/04-safe.t | 161 + + .../external/perl/Text-Template-1.46/t/05-safe2.t | 105 + + .../external/perl/Text-Template-1.46/t/06-ofh.t | 39 + + .../external/perl/Text-Template-1.46/t/07-safe3.t | 91 + + .../perl/Text-Template-1.46/t/08-exported.t | 75 + + .../external/perl/Text-Template-1.46/t/09-error.t | 63 + + .../perl/Text-Template-1.46/t/10-delimiters.t | 99 + + .../perl/Text-Template-1.46/t/11-prepend.t | 94 + + .../perl/Text-Template-1.46/t/12-preprocess.t | 52 + + .../external/perl/Text-Template-1.46/t/13-taint.t | 119 + + .../external/perl/Text-Template-1.46/t/14-broken.t | 82 + + .../external/perl/transfer/Text/Template.pm | 20 + + .../Library/OpensslLib/openssl/fuzz/README.md | 66 + + CryptoPkg/Library/OpensslLib/openssl/fuzz/asn1.c | 222 + + .../Library/OpensslLib/openssl/fuzz/asn1parse.c | 33 + + CryptoPkg/Library/OpensslLib/openssl/fuzz/bignum.c | 94 + + CryptoPkg/Library/OpensslLib/openssl/fuzz/bndiv.c | 107 + + .../Library/OpensslLib/openssl/fuzz/build.info | 113 + + CryptoPkg/Library/OpensslLib/openssl/fuzz/cms.c | 36 + + CryptoPkg/Library/OpensslLib/openssl/fuzz/conf.c | 38 + + CryptoPkg/Library/OpensslLib/openssl/fuzz/crl.c | 35 + + CryptoPkg/Library/OpensslLib/openssl/fuzz/ct.c | 40 + + CryptoPkg/Library/OpensslLib/openssl/fuzz/driver.c | 52 + + CryptoPkg/Library/OpensslLib/openssl/fuzz/fuzzer.h | 12 + + .../Library/OpensslLib/openssl/fuzz/helper.py | 52 + + CryptoPkg/Library/OpensslLib/openssl/fuzz/server.c | 250 + + .../Library/OpensslLib/openssl/fuzz/test-corpus.c | 46 + + CryptoPkg/Library/OpensslLib/openssl/fuzz/x509.c | 36 + + .../OpensslLib/openssl/include/internal/bio.h | 26 + + .../OpensslLib/openssl/include/internal/comp.h | 12 + + .../OpensslLib/openssl/include/internal/conf.h | 32 + + .../openssl/include/internal/constant_time_locl.h | 185 + + .../OpensslLib/openssl/include/internal/dane.h | 103 + + .../OpensslLib/openssl/include/internal/dso.h | 239 + + .../OpensslLib/openssl/include/internal/err.h | 15 + + .../OpensslLib/openssl/include/internal/numbers.h | 68 + + .../OpensslLib/openssl/include/internal/o_dir.h | 63 + + .../OpensslLib/openssl/include/internal/o_str.h | 17 + + .../openssl/include/internal/thread_once.h | 45 + + .../include/openssl/__DECC_INCLUDE_EPILOGUE.H | 16 + + .../include/openssl/__DECC_INCLUDE_PROLOGUE.H | 20 + + .../OpensslLib/openssl/include/openssl/aes.h | 92 + + .../OpensslLib/openssl/include/openssl/asn1.h | 1096 ++ + .../OpensslLib/openssl/include/openssl/asn1t.h | 924 ++ + .../OpensslLib/openssl/include/openssl/async.h | 98 + + .../OpensslLib/openssl/include/openssl/bio.h | 854 ++ + .../OpensslLib/openssl/include/openssl/blowfish.h | 61 + + .../OpensslLib/openssl/include/openssl/bn.h | 575 + + .../OpensslLib/openssl/include/openssl/buffer.h | 76 + + .../OpensslLib/openssl/include/openssl/camellia.h | 83 + + .../OpensslLib/openssl/include/openssl/cast.h | 53 + + .../OpensslLib/openssl/include/openssl/cmac.h | 41 + + .../OpensslLib/openssl/include/openssl/cms.h | 512 + + .../OpensslLib/openssl/include/openssl/comp.h | 72 + + .../OpensslLib/openssl/include/openssl/conf.h | 216 + + .../OpensslLib/openssl/include/openssl/conf_api.h | 40 + + .../OpensslLib/openssl/include/openssl/crypto.h | 463 + + .../OpensslLib/openssl/include/openssl/ct.h | 533 + + .../OpensslLib/openssl/include/openssl/des.h | 174 + + .../OpensslLib/openssl/include/openssl/dh.h | 344 + + .../OpensslLib/openssl/include/openssl/dsa.h | 283 + + .../OpensslLib/openssl/include/openssl/dtls1.h | 56 + + .../OpensslLib/openssl/include/openssl/e_os2.h | 311 + + .../OpensslLib/openssl/include/openssl/ebcdic.h | 33 + + .../OpensslLib/openssl/include/openssl/ec.h | 1581 +++ + .../OpensslLib/openssl/include/openssl/ecdh.h | 10 + + .../OpensslLib/openssl/include/openssl/ecdsa.h | 10 + + .../OpensslLib/openssl/include/openssl/engine.h | 840 ++ + .../OpensslLib/openssl/include/openssl/err.h | 259 + + .../OpensslLib/openssl/include/openssl/evp.h | 1590 +++ + .../OpensslLib/openssl/include/openssl/hmac.h | 49 + + .../OpensslLib/openssl/include/openssl/idea.h | 64 + + .../OpensslLib/openssl/include/openssl/kdf.h | 75 + + .../OpensslLib/openssl/include/openssl/lhash.h | 204 + + .../OpensslLib/openssl/include/openssl/md2.h | 44 + + .../OpensslLib/openssl/include/openssl/md4.h | 51 + + .../OpensslLib/openssl/include/openssl/md5.h | 50 + + .../OpensslLib/openssl/include/openssl/mdc2.h | 42 + + .../OpensslLib/openssl/include/openssl/modes.h | 203 + + .../OpensslLib/openssl/include/openssl/obj_mac.h | 4577 +++++++ + .../OpensslLib/openssl/include/openssl/objects.h | 1097 ++ + .../OpensslLib/openssl/include/openssl/ocsp.h | 412 + + .../openssl/include/openssl/opensslconf.h.in | 141 + + .../OpensslLib/openssl/include/openssl/opensslv.h | 105 + + .../OpensslLib/openssl/include/openssl/ossl_typ.h | 190 + + .../OpensslLib/openssl/include/openssl/pem.h | 501 + + .../OpensslLib/openssl/include/openssl/pem2.h | 20 + + .../OpensslLib/openssl/include/openssl/pkcs12.h | 282 + + .../OpensslLib/openssl/include/openssl/pkcs7.h | 404 + + .../OpensslLib/openssl/include/openssl/rand.h | 89 + + .../OpensslLib/openssl/include/openssl/rc2.h | 51 + + .../OpensslLib/openssl/include/openssl/rc4.h | 36 + + .../OpensslLib/openssl/include/openssl/rc5.h | 63 + + .../OpensslLib/openssl/include/openssl/ripemd.h | 47 + + .../OpensslLib/openssl/include/openssl/rsa.h | 590 + + .../OpensslLib/openssl/include/openssl/safestack.h | 164 + + .../OpensslLib/openssl/include/openssl/seed.h | 98 + + .../OpensslLib/openssl/include/openssl/sha.h | 119 + + .../OpensslLib/openssl/include/openssl/srp.h | 131 + + .../OpensslLib/openssl/include/openssl/srtp.h | 50 + + .../OpensslLib/openssl/include/openssl/ssl.h | 2531 ++++ + .../OpensslLib/openssl/include/openssl/ssl2.h | 24 + + .../OpensslLib/openssl/include/openssl/ssl3.h | 310 + + .../OpensslLib/openssl/include/openssl/stack.h | 78 + + .../OpensslLib/openssl/include/openssl/symhacks.h | 52 + + .../OpensslLib/openssl/include/openssl/tls1.h | 972 ++ + .../OpensslLib/openssl/include/openssl/ts.h | 643 + + .../OpensslLib/openssl/include/openssl/txt_db.h | 57 + + .../OpensslLib/openssl/include/openssl/ui.h | 378 + + .../OpensslLib/openssl/include/openssl/whrlpool.h | 48 + + .../OpensslLib/openssl/include/openssl/x509.h | 1123 ++ + .../OpensslLib/openssl/include/openssl/x509_vfy.h | 545 + + .../OpensslLib/openssl/include/openssl/x509v3.h | 1006 ++ + CryptoPkg/Library/OpensslLib/openssl/ms/applink.c | 138 + + CryptoPkg/Library/OpensslLib/openssl/ms/cmp.pl | 53 + + .../Library/OpensslLib/openssl/ms/segrenam.pl | 71 + + CryptoPkg/Library/OpensslLib/openssl/ms/tlhelp32.h | 136 + + .../Library/OpensslLib/openssl/ms/uplink-common.pl | 28 + + .../Library/OpensslLib/openssl/ms/uplink-ia64.pl | 61 + + .../Library/OpensslLib/openssl/ms/uplink-x86.pl | 44 + + .../Library/OpensslLib/openssl/ms/uplink-x86_64.pl | 71 + + CryptoPkg/Library/OpensslLib/openssl/ms/uplink.c | 135 + + CryptoPkg/Library/OpensslLib/openssl/ms/uplink.h | 38 + + .../Library/OpensslLib/openssl/os-dep/haiku.h | 2 + + CryptoPkg/Library/OpensslLib/openssl/ssl/bio_ssl.c | 528 + + .../Library/OpensslLib/openssl/ssl/build.info | 14 + + CryptoPkg/Library/OpensslLib/openssl/ssl/d1_lib.c | 1087 ++ + CryptoPkg/Library/OpensslLib/openssl/ssl/d1_msg.c | 95 + + CryptoPkg/Library/OpensslLib/openssl/ssl/d1_srtp.c | 329 + + CryptoPkg/Library/OpensslLib/openssl/ssl/methods.c | 266 + + .../Library/OpensslLib/openssl/ssl/packet_locl.h | 555 + + CryptoPkg/Library/OpensslLib/openssl/ssl/pqueue.c | 154 + + .../Library/OpensslLib/openssl/ssl/record/README | 74 + + .../OpensslLib/openssl/ssl/record/dtls1_bitmap.c | 78 + + .../OpensslLib/openssl/ssl/record/rec_layer_d1.c | 1224 ++ + .../OpensslLib/openssl/ssl/record/rec_layer_s3.c | 1527 +++ + .../Library/OpensslLib/openssl/ssl/record/record.h | 242 + + .../OpensslLib/openssl/ssl/record/record_locl.h | 116 + + .../OpensslLib/openssl/ssl/record/ssl3_buffer.c | 163 + + .../OpensslLib/openssl/ssl/record/ssl3_record.c | 1634 +++ + CryptoPkg/Library/OpensslLib/openssl/ssl/s3_cbc.c | 529 + + CryptoPkg/Library/OpensslLib/openssl/ssl/s3_enc.c | 585 + + CryptoPkg/Library/OpensslLib/openssl/ssl/s3_lib.c | 4121 ++++++ + CryptoPkg/Library/OpensslLib/openssl/ssl/s3_msg.c | 125 + + .../Library/OpensslLib/openssl/ssl/ssl_asn1.c | 367 + + .../Library/OpensslLib/openssl/ssl/ssl_cert.c | 1090 ++ + .../Library/OpensslLib/openssl/ssl/ssl_ciph.c | 1965 +++ + .../Library/OpensslLib/openssl/ssl/ssl_conf.c | 880 ++ + CryptoPkg/Library/OpensslLib/openssl/ssl/ssl_err.c | 682 + + .../Library/OpensslLib/openssl/ssl/ssl_init.c | 210 + + CryptoPkg/Library/OpensslLib/openssl/ssl/ssl_lib.c | 4282 +++++++ + .../Library/OpensslLib/openssl/ssl/ssl_locl.h | 2101 ++++ + .../Library/OpensslLib/openssl/ssl/ssl_mcnf.c | 199 + + CryptoPkg/Library/OpensslLib/openssl/ssl/ssl_rsa.c | 966 ++ + .../Library/OpensslLib/openssl/ssl/ssl_sess.c | 1169 ++ + .../Library/OpensslLib/openssl/ssl/ssl_stat.c | 362 + + CryptoPkg/Library/OpensslLib/openssl/ssl/ssl_txt.c | 217 + + .../Library/OpensslLib/openssl/ssl/ssl_utst.c | 28 + + .../Library/OpensslLib/openssl/ssl/statem/README | 63 + + .../Library/OpensslLib/openssl/ssl/statem/statem.c | 875 ++ + .../Library/OpensslLib/openssl/ssl/statem/statem.h | 123 + + .../OpensslLib/openssl/ssl/statem/statem_clnt.c | 2971 +++++ + .../OpensslLib/openssl/ssl/statem/statem_dtls.c | 1193 ++ + .../OpensslLib/openssl/ssl/statem/statem_lib.c | 1092 ++ + .../OpensslLib/openssl/ssl/statem/statem_locl.h | 124 + + .../OpensslLib/openssl/ssl/statem/statem_srvr.c | 3375 +++++ + CryptoPkg/Library/OpensslLib/openssl/ssl/t1_enc.c | 703 ++ + CryptoPkg/Library/OpensslLib/openssl/ssl/t1_ext.c | 264 + + CryptoPkg/Library/OpensslLib/openssl/ssl/t1_lib.c | 4188 +++++++ + .../Library/OpensslLib/openssl/ssl/t1_reneg.c | 165 + + CryptoPkg/Library/OpensslLib/openssl/ssl/t1_trce.c | 1341 ++ + CryptoPkg/Library/OpensslLib/openssl/ssl/tls_srp.c | 469 + + CryptoPkg/Library/OpensslLib/openssl/test/CAss.cnf | 76 + + .../Library/OpensslLib/openssl/test/CAssdh.cnf | 24 + + .../Library/OpensslLib/openssl/test/CAssdsa.cnf | 23 + + .../Library/OpensslLib/openssl/test/CAssrsa.cnf | 24 + + .../Library/OpensslLib/openssl/test/CAtsa.cnf | 163 + + CryptoPkg/Library/OpensslLib/openssl/test/P1ss.cnf | 37 + + CryptoPkg/Library/OpensslLib/openssl/test/P2ss.cnf | 45 + + CryptoPkg/Library/OpensslLib/openssl/test/README | 107 + + .../OpensslLib/openssl/test/README.ssltest.md | 274 + + .../Library/OpensslLib/openssl/test/Sssdsa.cnf | 27 + + .../Library/OpensslLib/openssl/test/Sssrsa.cnf | 26 + + CryptoPkg/Library/OpensslLib/openssl/test/Uss.cnf | 41 + + .../Library/OpensslLib/openssl/test/aborttest.c | 16 + + .../Library/OpensslLib/openssl/test/afalgtest.c | 133 + + .../Library/OpensslLib/openssl/test/asynciotest.c | 381 + + .../Library/OpensslLib/openssl/test/asynctest.c | 292 + + .../OpensslLib/openssl/test/bad_dtls_test.c | 624 + + CryptoPkg/Library/OpensslLib/openssl/test/bftest.c | 484 + + .../Library/OpensslLib/openssl/test/bio_enc_test.c | 138 + + .../Library/OpensslLib/openssl/test/bioprinttest.c | 225 + + CryptoPkg/Library/OpensslLib/openssl/test/bntest.c | 2094 ++++ + .../Library/OpensslLib/openssl/test/build.info | 317 + + .../Library/OpensslLib/openssl/test/casttest.c | 163 + + .../OpensslLib/openssl/test/certs/alt1-cert.pem | 22 + + .../OpensslLib/openssl/test/certs/alt1-key.pem | 28 + + .../OpensslLib/openssl/test/certs/alt2-cert.pem | 20 + + .../OpensslLib/openssl/test/certs/alt2-key.pem | 28 + + .../OpensslLib/openssl/test/certs/alt3-cert.pem | 21 + + .../OpensslLib/openssl/test/certs/alt3-key.pem | 28 + + .../OpensslLib/openssl/test/certs/bad-pc3-cert.pem | 21 + + .../OpensslLib/openssl/test/certs/bad-pc3-key.pem | 28 + + .../OpensslLib/openssl/test/certs/bad-pc4-cert.pem | 21 + + .../OpensslLib/openssl/test/certs/bad-pc4-key.pem | 28 + + .../OpensslLib/openssl/test/certs/bad-pc6-cert.pem | 21 + + .../OpensslLib/openssl/test/certs/bad-pc6-key.pem | 28 + + .../Library/OpensslLib/openssl/test/certs/bad.key | 27 + + .../Library/OpensslLib/openssl/test/certs/bad.pem | 21 + + .../OpensslLib/openssl/test/certs/badalt1-cert.pem | 20 + + .../OpensslLib/openssl/test/certs/badalt1-key.pem | 28 + + .../openssl/test/certs/badalt10-cert.pem | 21 + + .../OpensslLib/openssl/test/certs/badalt10-key.pem | 28 + + .../OpensslLib/openssl/test/certs/badalt2-cert.pem | 20 + + .../OpensslLib/openssl/test/certs/badalt2-key.pem | 28 + + .../OpensslLib/openssl/test/certs/badalt3-cert.pem | 21 + + .../OpensslLib/openssl/test/certs/badalt3-key.pem | 28 + + .../OpensslLib/openssl/test/certs/badalt4-cert.pem | 21 + + .../OpensslLib/openssl/test/certs/badalt4-key.pem | 28 + + .../OpensslLib/openssl/test/certs/badalt5-cert.pem | 20 + + .../OpensslLib/openssl/test/certs/badalt5-key.pem | 28 + + .../OpensslLib/openssl/test/certs/badalt6-cert.pem | 22 + + .../OpensslLib/openssl/test/certs/badalt6-key.pem | 28 + + .../OpensslLib/openssl/test/certs/badalt7-cert.pem | 23 + + .../OpensslLib/openssl/test/certs/badalt7-key.pem | 28 + + .../OpensslLib/openssl/test/certs/badalt8-cert.pem | 21 + + .../OpensslLib/openssl/test/certs/badalt8-key.pem | 28 + + .../OpensslLib/openssl/test/certs/badalt9-cert.pem | 21 + + .../OpensslLib/openssl/test/certs/badalt9-key.pem | 28 + + .../OpensslLib/openssl/test/certs/ca+anyEKU.pem | 18 + + .../openssl/test/certs/ca+clientAuth.pem | 18 + + .../openssl/test/certs/ca+serverAuth.pem | 18 + + .../OpensslLib/openssl/test/certs/ca-anyEKU.pem | 18 + + .../OpensslLib/openssl/test/certs/ca-cert-768.pem | 15 + + .../OpensslLib/openssl/test/certs/ca-cert-768i.pem | 15 + + .../openssl/test/certs/ca-cert-md5-any.pem | 18 + + .../OpensslLib/openssl/test/certs/ca-cert-md5.pem | 18 + + .../OpensslLib/openssl/test/certs/ca-cert.pem | 18 + + .../OpensslLib/openssl/test/certs/ca-cert2.pem | 18 + + .../openssl/test/certs/ca-clientAuth.pem | 18 + + .../OpensslLib/openssl/test/certs/ca-expired.pem | 18 + + .../OpensslLib/openssl/test/certs/ca-key-768.pem | 13 + + .../OpensslLib/openssl/test/certs/ca-key.pem | 28 + + .../OpensslLib/openssl/test/certs/ca-key2.pem | 28 + + .../OpensslLib/openssl/test/certs/ca-name2.pem | 18 + + .../OpensslLib/openssl/test/certs/ca-nonbc.pem | 18 + + .../OpensslLib/openssl/test/certs/ca-nonca.pem | 19 + + .../OpensslLib/openssl/test/certs/ca-root2.pem | 18 + + .../openssl/test/certs/ca-serverAuth.pem | 18 + + .../OpensslLib/openssl/test/certs/cca+anyEKU.pem | 19 + + .../openssl/test/certs/cca+clientAuth.pem | 19 + + .../openssl/test/certs/cca+serverAuth.pem | 19 + + .../OpensslLib/openssl/test/certs/cca-anyEKU.pem | 19 + + .../OpensslLib/openssl/test/certs/cca-cert.pem | 19 + + .../openssl/test/certs/cca-clientAuth.pem | 19 + + .../openssl/test/certs/cca-serverAuth.pem | 19 + + .../OpensslLib/openssl/test/certs/croot+anyEKU.pem | 19 + + .../openssl/test/certs/croot+clientAuth.pem | 19 + + .../openssl/test/certs/croot+serverAuth.pem | 19 + + .../OpensslLib/openssl/test/certs/croot-anyEKU.pem | 19 + + .../OpensslLib/openssl/test/certs/croot-cert.pem | 19 + + .../openssl/test/certs/croot-clientAuth.pem | 19 + + .../openssl/test/certs/croot-serverAuth.pem | 19 + + .../openssl/test/certs/ee+clientAuth.pem | 20 + + .../openssl/test/certs/ee+serverAuth.pem | 20 + + .../OpensslLib/openssl/test/certs/ee-cert-768.pem | 16 + + .../OpensslLib/openssl/test/certs/ee-cert-768i.pem | 16 + + .../OpensslLib/openssl/test/certs/ee-cert-md5.pem | 19 + + .../OpensslLib/openssl/test/certs/ee-cert.pem | 19 + + .../OpensslLib/openssl/test/certs/ee-cert2.pem | 19 + + .../openssl/test/certs/ee-client-chain.pem | 37 + + .../OpensslLib/openssl/test/certs/ee-client.pem | 19 + + .../openssl/test/certs/ee-clientAuth.pem | 20 + + .../OpensslLib/openssl/test/certs/ee-expired.pem | 19 + + .../OpensslLib/openssl/test/certs/ee-key-768.pem | 13 + + .../OpensslLib/openssl/test/certs/ee-key.pem | 28 + + .../OpensslLib/openssl/test/certs/ee-name2.pem | 19 + + .../openssl/test/certs/ee-serverAuth.pem | 20 + + .../openssl/test/certs/embeddedSCTs1.pem | 20 + + .../openssl/test/certs/embeddedSCTs1.sct | 12 + + .../openssl/test/certs/embeddedSCTs1_issuer.pem | 18 + + .../openssl/test/certs/embeddedSCTs3.pem | 44 + + .../openssl/test/certs/embeddedSCTs3.sct | 36 + + .../openssl/test/certs/embeddedSCTs3_issuer.pem | 35 + + .../OpensslLib/openssl/test/certs/interCA.key | 27 + + .../OpensslLib/openssl/test/certs/interCA.pem | 21 + + .../Library/OpensslLib/openssl/test/certs/leaf.key | 27 + + .../Library/OpensslLib/openssl/test/certs/leaf.pem | 21 + + .../OpensslLib/openssl/test/certs/mkcert.sh | 254 + + .../OpensslLib/openssl/test/certs/nca+anyEKU.pem | 19 + + .../openssl/test/certs/nca+serverAuth.pem | 19 + + .../OpensslLib/openssl/test/certs/ncca-cert.pem | 21 + + .../OpensslLib/openssl/test/certs/ncca-key.pem | 28 + + .../OpensslLib/openssl/test/certs/ncca1-cert.pem | 20 + + .../OpensslLib/openssl/test/certs/ncca1-key.pem | 28 + + .../OpensslLib/openssl/test/certs/ncca2-cert.pem | 20 + + .../OpensslLib/openssl/test/certs/ncca2-key.pem | 28 + + .../OpensslLib/openssl/test/certs/ncca3-cert.pem | 20 + + .../OpensslLib/openssl/test/certs/ncca3-key.pem | 28 + + .../OpensslLib/openssl/test/certs/nroot+anyEKU.pem | 19 + + .../openssl/test/certs/nroot+serverAuth.pem | 19 + + .../OpensslLib/openssl/test/certs/pathlen.pem | 22 + + .../OpensslLib/openssl/test/certs/pc1-cert.pem | 20 + + .../OpensslLib/openssl/test/certs/pc1-key.pem | 28 + + .../OpensslLib/openssl/test/certs/pc2-cert.pem | 21 + + .../OpensslLib/openssl/test/certs/pc2-key.pem | 28 + + .../OpensslLib/openssl/test/certs/pc5-cert.pem | 21 + + .../OpensslLib/openssl/test/certs/pc5-key.pem | 28 + + .../OpensslLib/openssl/test/certs/root+anyEKU.pem | 18 + + .../openssl/test/certs/root+clientAuth.pem | 19 + + .../openssl/test/certs/root+serverAuth.pem | 19 + + .../OpensslLib/openssl/test/certs/root-anyEKU.pem | 18 + + .../openssl/test/certs/root-cert-768.pem | 11 + + .../openssl/test/certs/root-cert-md5.pem | 18 + + .../OpensslLib/openssl/test/certs/root-cert.pem | 18 + + .../OpensslLib/openssl/test/certs/root-cert2.pem | 18 + + .../openssl/test/certs/root-clientAuth.pem | 19 + + .../OpensslLib/openssl/test/certs/root-key-768.pem | 13 + + .../OpensslLib/openssl/test/certs/root-key.pem | 28 + + .../OpensslLib/openssl/test/certs/root-key2.pem | 28 + + .../OpensslLib/openssl/test/certs/root-name2.pem | 18 + + .../OpensslLib/openssl/test/certs/root-nonca.pem | 19 + + .../openssl/test/certs/root-noserver.pem | 19 + + .../openssl/test/certs/root-serverAuth.pem | 19 + + .../openssl/test/certs/root2+clientAuth.pem | 19 + + .../openssl/test/certs/root2+serverAuth.pem | 19 + + .../openssl/test/certs/root2-serverAuth.pem | 19 + + .../OpensslLib/openssl/test/certs/rootCA.key | 27 + + .../OpensslLib/openssl/test/certs/rootCA.pem | 21 + + .../OpensslLib/openssl/test/certs/rootcert.pem | 18 + + .../OpensslLib/openssl/test/certs/rootkey.pem | 28 + + .../OpensslLib/openssl/test/certs/roots.pem | 42 + + .../OpensslLib/openssl/test/certs/sca+anyEKU.pem | 19 + + .../openssl/test/certs/sca+clientAuth.pem | 19 + + .../openssl/test/certs/sca+serverAuth.pem | 19 + + .../OpensslLib/openssl/test/certs/sca-anyEKU.pem | 19 + + .../OpensslLib/openssl/test/certs/sca-cert.pem | 19 + + .../openssl/test/certs/sca-clientAuth.pem | 19 + + .../openssl/test/certs/sca-serverAuth.pem | 19 + + .../openssl/test/certs/server-trusted.pem | 20 + + .../OpensslLib/openssl/test/certs/servercert.pem | 19 + + .../OpensslLib/openssl/test/certs/serverkey.pem | 28 + + .../Library/OpensslLib/openssl/test/certs/setup.sh | 346 + + .../OpensslLib/openssl/test/certs/sroot+anyEKU.pem | 19 + + .../openssl/test/certs/sroot+clientAuth.pem | 19 + + .../openssl/test/certs/sroot+serverAuth.pem | 19 + + .../OpensslLib/openssl/test/certs/sroot-anyEKU.pem | 19 + + .../OpensslLib/openssl/test/certs/sroot-cert.pem | 19 + + .../openssl/test/certs/sroot-clientAuth.pem | 19 + + .../openssl/test/certs/sroot-serverAuth.pem | 19 + + .../openssl/test/certs/subinterCA-ss.pem | 21 + + .../OpensslLib/openssl/test/certs/subinterCA.key | 27 + + .../OpensslLib/openssl/test/certs/subinterCA.pem | 21 + + .../OpensslLib/openssl/test/certs/untrusted.pem | 42 + + .../OpensslLib/openssl/test/certs/wrongcert.pem | 19 + + .../OpensslLib/openssl/test/certs/wrongkey.pem | 28 + + .../OpensslLib/openssl/test/cipherlist_test.c | 199 + + .../OpensslLib/openssl/test/clienthellotest.c | 145 + + .../OpensslLib/openssl/test/cms-examples.pl | 365 + + .../OpensslLib/openssl/test/constant_time_test.c | 268 + + .../Library/OpensslLib/openssl/test/crltest.c | 378 + + .../OpensslLib/openssl/test/ct/log_list.conf | 38 + + .../Library/OpensslLib/openssl/test/ct/tls1.sct | 12 + + .../Library/OpensslLib/openssl/test/ct_test.c | 607 + + .../OpensslLib/openssl/test/d2i-tests/bad-cms.der | Bin 0 -> 24 bytes + .../openssl/test/d2i-tests/bad-int-pad0.der | Bin 0 -> 4 bytes + .../openssl/test/d2i-tests/bad-int-padminus1.der | Bin 0 -> 4 bytes + .../OpensslLib/openssl/test/d2i-tests/bad_bio.der | Bin 0 -> 7 bytes + .../OpensslLib/openssl/test/d2i-tests/bad_cert.der | Bin 0 -> 1007 bytes + .../openssl/test/d2i-tests/bad_generalname.der | Bin 0 -> 60 bytes + .../OpensslLib/openssl/test/d2i-tests/high_tag.der | Bin 0 -> 6 bytes + .../OpensslLib/openssl/test/d2i-tests/int0.der | Bin 0 -> 3 bytes + .../OpensslLib/openssl/test/d2i-tests/int1.der | Bin 0 -> 3 bytes + .../openssl/test/d2i-tests/intminus1.der | Bin 0 -> 3 bytes + .../Library/OpensslLib/openssl/test/d2i_test.c | 222 + + .../Library/OpensslLib/openssl/test/danetest.c | 504 + + .../Library/OpensslLib/openssl/test/danetest.in | 1878 +++ + .../Library/OpensslLib/openssl/test/danetest.pem | 14 + + .../Library/OpensslLib/openssl/test/destest.c | 804 ++ + CryptoPkg/Library/OpensslLib/openssl/test/dhtest.c | 598 + + .../Library/OpensslLib/openssl/test/dsatest.c | 196 + + .../Library/OpensslLib/openssl/test/dtlstest.c | 142 + + .../OpensslLib/openssl/test/dtlsv1listentest.c | 426 + + .../Library/OpensslLib/openssl/test/ecdhtest.c | 612 + + .../OpensslLib/openssl/test/ecdhtest_cavs.h | 1359 ++ + .../Library/OpensslLib/openssl/test/ecdsatest.c | 519 + + CryptoPkg/Library/OpensslLib/openssl/test/ectest.c | 0 + .../Library/OpensslLib/openssl/test/enginetest.c | 204 + + .../OpensslLib/openssl/test/evp_extra_test.c | 409 + + .../Library/OpensslLib/openssl/test/evp_test.c | 2019 +++ + .../Library/OpensslLib/openssl/test/evptests.txt | 3639 ++++++ + .../Library/OpensslLib/openssl/test/exdatatest.c | 104 + + .../Library/OpensslLib/openssl/test/exptest.c | 268 + + .../OpensslLib/openssl/test/generate_buildtest.pl | 34 + + .../OpensslLib/openssl/test/generate_ssl_tests.pl | 141 + + .../Library/OpensslLib/openssl/test/gmdifftest.c | 81 + + .../OpensslLib/openssl/test/handshake_helper.c | 1098 ++ + .../OpensslLib/openssl/test/handshake_helper.h | 59 + + .../OpensslLib/openssl/test/heartbeat_test.c | 378 + + .../Library/OpensslLib/openssl/test/hmactest.c | 312 + + .../Library/OpensslLib/openssl/test/ideatest.c | 178 + + .../Library/OpensslLib/openssl/test/igetest.c | 441 + + .../Library/OpensslLib/openssl/test/md2test.c | 92 + + .../Library/OpensslLib/openssl/test/md4test.c | 87 + + .../Library/OpensslLib/openssl/test/md5test.c | 88 + + .../Library/OpensslLib/openssl/test/mdc2test.c | 99 + + .../Library/OpensslLib/openssl/test/memleaktest.c | 46 + + .../Library/OpensslLib/openssl/test/methtest.c | 57 + + .../OpensslLib/openssl/test/ocsp-tests/D1.ors | 32 + + .../openssl/test/ocsp-tests/D1_Cert_EE.pem | 38 + + .../openssl/test/ocsp-tests/D1_Issuer_ICA.pem | 27 + + .../OpensslLib/openssl/test/ocsp-tests/D2.ors | 32 + + .../openssl/test/ocsp-tests/D2_Cert_ICA.pem | 26 + + .../openssl/test/ocsp-tests/D2_Issuer_Root.pem | 21 + + .../OpensslLib/openssl/test/ocsp-tests/D3.ors | 38 + + .../openssl/test/ocsp-tests/D3_Cert_EE.pem | 31 + + .../openssl/test/ocsp-tests/D3_Issuer_Root.pem | 83 + + .../openssl/test/ocsp-tests/ISDOSC_D1.ors | 32 + + .../openssl/test/ocsp-tests/ISDOSC_D2.ors | 32 + + .../openssl/test/ocsp-tests/ISDOSC_D3.ors | 38 + + .../openssl/test/ocsp-tests/ISIC_D1_Issuer_ICA.pem | 27 + + .../test/ocsp-tests/ISIC_D2_Issuer_Root.pem | 21 + + .../test/ocsp-tests/ISIC_D3_Issuer_Root.pem | 41 + + .../test/ocsp-tests/ISIC_ND1_Issuer_ICA.pem | 29 + + .../test/ocsp-tests/ISIC_ND2_Issuer_Root.pem | 23 + + .../test/ocsp-tests/ISIC_ND3_Issuer_Root.pem | 25 + + .../OpensslLib/openssl/test/ocsp-tests/ISOP_D1.ors | 32 + + .../OpensslLib/openssl/test/ocsp-tests/ISOP_D2.ors | 32 + + .../OpensslLib/openssl/test/ocsp-tests/ISOP_D3.ors | 38 + + .../openssl/test/ocsp-tests/ISOP_ND1.ors | 10 + + .../openssl/test/ocsp-tests/ISOP_ND2.ors | 10 + + .../openssl/test/ocsp-tests/ISOP_ND3.ors | 10 + + .../OpensslLib/openssl/test/ocsp-tests/ND1.ors | 10 + + .../openssl/test/ocsp-tests/ND1_Cert_EE.pem | 36 + + .../openssl/test/ocsp-tests/ND1_Issuer_ICA.pem | 29 + + .../OpensslLib/openssl/test/ocsp-tests/ND2.ors | 10 + + .../openssl/test/ocsp-tests/ND2_Cert_ICA.pem | 29 + + .../openssl/test/ocsp-tests/ND2_Issuer_Root.pem | 23 + + .../OpensslLib/openssl/test/ocsp-tests/ND3.ors | 10 + + .../openssl/test/ocsp-tests/ND3_Cert_EE.pem | 34 + + .../openssl/test/ocsp-tests/ND3_Issuer_Root.pem | 25 + + .../OpensslLib/openssl/test/ocsp-tests/WIKH_D1.ors | 32 + + .../OpensslLib/openssl/test/ocsp-tests/WIKH_D2.ors | 32 + + .../OpensslLib/openssl/test/ocsp-tests/WIKH_D3.ors | 38 + + .../openssl/test/ocsp-tests/WIKH_ND1.ors | 10 + + .../openssl/test/ocsp-tests/WIKH_ND2.ors | 10 + + .../openssl/test/ocsp-tests/WIKH_ND3.ors | 10 + + .../OpensslLib/openssl/test/ocsp-tests/WINH_D1.ors | 32 + + .../OpensslLib/openssl/test/ocsp-tests/WINH_D2.ors | 32 + + .../OpensslLib/openssl/test/ocsp-tests/WINH_D3.ors | 38 + + .../openssl/test/ocsp-tests/WINH_ND1.ors | 10 + + .../openssl/test/ocsp-tests/WINH_ND2.ors | 10 + + .../openssl/test/ocsp-tests/WINH_ND3.ors | 10 + + .../openssl/test/ocsp-tests/WKDOSC_D1.ors | 32 + + .../openssl/test/ocsp-tests/WKDOSC_D2.ors | 32 + + .../openssl/test/ocsp-tests/WKDOSC_D3.ors | 38 + + .../openssl/test/ocsp-tests/WKIC_D1_Issuer_ICA.pem | 27 + + .../test/ocsp-tests/WKIC_D2_Issuer_Root.pem | 21 + + .../test/ocsp-tests/WKIC_D3_Issuer_Root.pem | 41 + + .../test/ocsp-tests/WKIC_ND1_Issuer_ICA.pem | 29 + + .../test/ocsp-tests/WKIC_ND2_Issuer_Root.pem | 23 + + .../test/ocsp-tests/WKIC_ND3_Issuer_Root.pem | 25 + + .../OpensslLib/openssl/test/ocsp-tests/WRID_D1.ors | 32 + + .../OpensslLib/openssl/test/ocsp-tests/WRID_D2.ors | 32 + + .../OpensslLib/openssl/test/ocsp-tests/WRID_D3.ors | 38 + + .../openssl/test/ocsp-tests/WRID_ND1.ors | 10 + + .../openssl/test/ocsp-tests/WRID_ND2.ors | 10 + + .../openssl/test/ocsp-tests/WRID_ND3.ors | 10 + + .../test/ocsp-tests/WSNIC_D1_Issuer_ICA.pem | 27 + + .../test/ocsp-tests/WSNIC_D2_Issuer_Root.pem | 21 + + .../test/ocsp-tests/WSNIC_D3_Issuer_Root.pem | 41 + + .../test/ocsp-tests/WSNIC_ND1_Issuer_ICA.pem | 29 + + .../test/ocsp-tests/WSNIC_ND2_Issuer_Root.pem | 23 + + .../test/ocsp-tests/WSNIC_ND3_Issuer_Root.pem | 25 + + .../OpensslLib/openssl/test/p5_crpt2_test.c | 159 + + .../Library/OpensslLib/openssl/test/packettest.c | 537 + + .../Library/OpensslLib/openssl/test/pbelutest.c | 47 + + .../Library/OpensslLib/openssl/test/pkcs7-1.pem | 15 + + .../Library/OpensslLib/openssl/test/pkcs7.pem | 54 + + .../Library/OpensslLib/openssl/test/pkits-test.pl | 905 ++ + .../Library/OpensslLib/openssl/test/r160test.c | 9 + + .../Library/OpensslLib/openssl/test/randtest.c | 145 + + .../Library/OpensslLib/openssl/test/rc2test.c | 99 + + .../Library/OpensslLib/openssl/test/rc4test.c | 175 + + .../Library/OpensslLib/openssl/test/rc5test.c | 276 + + .../openssl/test/recipes/01-test_abort.t | 16 + + .../openssl/test/recipes/01-test_sanity.t | 12 + + .../openssl/test/recipes/01-test_symbol_presence.t | 116 + + .../openssl/test/recipes/02-test_ordinals.t | 58 + + .../OpensslLib/openssl/test/recipes/03-test_ui.t | 30 + + .../OpensslLib/openssl/test/recipes/05-test_bf.t | 12 + + .../OpensslLib/openssl/test/recipes/05-test_cast.t | 12 + + .../OpensslLib/openssl/test/recipes/05-test_des.t | 12 + + .../OpensslLib/openssl/test/recipes/05-test_hmac.t | 12 + + .../OpensslLib/openssl/test/recipes/05-test_idea.t | 12 + + .../OpensslLib/openssl/test/recipes/05-test_md2.t | 12 + + .../OpensslLib/openssl/test/recipes/05-test_md4.t | 12 + + .../OpensslLib/openssl/test/recipes/05-test_md5.t | 12 + + .../OpensslLib/openssl/test/recipes/05-test_mdc2.t | 12 + + .../OpensslLib/openssl/test/recipes/05-test_rand.t | 12 + + .../OpensslLib/openssl/test/recipes/05-test_rc2.t | 11 + + .../OpensslLib/openssl/test/recipes/05-test_rc4.t | 11 + + .../OpensslLib/openssl/test/recipes/05-test_rc5.t | 12 + + .../OpensslLib/openssl/test/recipes/05-test_rmd.t | 12 + + .../OpensslLib/openssl/test/recipes/05-test_sha1.t | 12 + + .../openssl/test/recipes/05-test_sha256.t | 12 + + .../openssl/test/recipes/05-test_sha512.t | 12 + + .../OpensslLib/openssl/test/recipes/05-test_wp.t | 12 + + .../OpensslLib/openssl/test/recipes/10-test_bn.t | 84 + + .../OpensslLib/openssl/test/recipes/10-test_exp.t | 12 + + .../OpensslLib/openssl/test/recipes/15-test_dh.t | 12 + + .../OpensslLib/openssl/test/recipes/15-test_dsa.t | 40 + + .../OpensslLib/openssl/test/recipes/15-test_ec.t | 38 + + .../OpensslLib/openssl/test/recipes/15-test_ecdh.t | 12 + + .../openssl/test/recipes/15-test_ecdsa.t | 12 + + .../OpensslLib/openssl/test/recipes/15-test_rsa.t | 41 + + .../OpensslLib/openssl/test/recipes/20-test_enc.t | 69 + + .../openssl/test/recipes/20-test_passwd.t | 39 + + .../OpensslLib/openssl/test/recipes/25-test_crl.t | 43 + + .../OpensslLib/openssl/test/recipes/25-test_d2i.t | 93 + + .../openssl/test/recipes/25-test_pkcs7.t | 27 + + .../OpensslLib/openssl/test/recipes/25-test_req.t | 76 + + .../OpensslLib/openssl/test/recipes/25-test_sid.t | 24 + + .../openssl/test/recipes/25-test_verify.t | 330 + + .../OpensslLib/openssl/test/recipes/25-test_x509.t | 34 + + .../openssl/test/recipes/30-test_afalg.t | 23 + + .../openssl/test/recipes/30-test_engine.t | 18 + + .../OpensslLib/openssl/test/recipes/30-test_evp.t | 19 + + .../openssl/test/recipes/30-test_evp_extra.t | 18 + + .../openssl/test/recipes/30-test_pbelu.t | 12 + + .../openssl/test/recipes/40-test_rehash.t | 99 + + .../openssl/test/recipes/70-test_asyncio.t | 21 + + .../openssl/test/recipes/70-test_bad_dtls.t | 20 + + .../openssl/test/recipes/70-test_clienthello.t | 20 + + .../openssl/test/recipes/70-test_packet.t | 12 + + .../openssl/test/recipes/70-test_sslcbcpadding.t | 110 + + .../openssl/test/recipes/70-test_sslcertstatus.t | 66 + + .../openssl/test/recipes/70-test_sslextension.t | 112 + + .../openssl/test/recipes/70-test_sslmessages.t | 147 + + .../openssl/test/recipes/70-test_sslrecords.t | 381 + + .../openssl/test/recipes/70-test_sslsessiontick.t | 268 + + .../openssl/test/recipes/70-test_sslskewith0p.t | 65 + + .../openssl/test/recipes/70-test_sslvertol.t | 67 + + .../openssl/test/recipes/70-test_tlsextms.t | 238 + + .../openssl/test/recipes/70-test_verify_extra.t | 19 + + .../OpensslLib/openssl/test/recipes/80-test_ca.t | 59 + + .../openssl/test/recipes/80-test_cipherlist.t | 26 + + .../OpensslLib/openssl/test/recipes/80-test_cms.t | 502 + + .../OpensslLib/openssl/test/recipes/80-test_ct.t | 17 + + .../OpensslLib/openssl/test/recipes/80-test_dane.t | 24 + + .../OpensslLib/openssl/test/recipes/80-test_dtls.t | 20 + + .../openssl/test/recipes/80-test_dtlsv1listen.t | 12 + + .../OpensslLib/openssl/test/recipes/80-test_ocsp.t | 206 + + .../openssl/test/recipes/80-test_pkcs12.t | 66 + + .../openssl/test/recipes/80-test_ssl_new.t | 131 + + .../openssl/test/recipes/80-test_ssl_old.t | 625 + + .../openssl/test/recipes/80-test_ssl_test_ctx.t | 19 + + .../openssl/test/recipes/80-test_sslcorrupt.t | 20 + + .../OpensslLib/openssl/test/recipes/80-test_tsa.t | 203 + + .../openssl/test/recipes/80-test_x509aux.t | 27 + + .../openssl/test/recipes/90-test_async.t | 12 + + .../openssl/test/recipes/90-test_bio_enc.t | 12 + + .../openssl/test/recipes/90-test_bioprint.t | 12 + + .../openssl/test/recipes/90-test_constant_time.t | 12 + + .../OpensslLib/openssl/test/recipes/90-test_fuzz.t | 40 + + .../openssl/test/recipes/90-test_gmdiff.t | 12 + + .../openssl/test/recipes/90-test_heartbeat.t | 12 + + .../OpensslLib/openssl/test/recipes/90-test_ige.t | 12 + + .../openssl/test/recipes/90-test_memleak.t | 15 + + .../openssl/test/recipes/90-test_p5_crpt2.t | 12 + + .../openssl/test/recipes/90-test_secmem.t | 12 + + .../openssl/test/recipes/90-test_shlibload.t | 36 + + .../OpensslLib/openssl/test/recipes/90-test_srp.t | 12 + + .../openssl/test/recipes/90-test_sslapi.t | 21 + + .../openssl/test/recipes/90-test_threads.t | 12 + + .../openssl/test/recipes/90-test_v3name.t | 12 + + .../Library/OpensslLib/openssl/test/recipes/bc.pl | 113 + + .../OpensslLib/openssl/test/recipes/tconversion.pl | 106 + + .../Library/OpensslLib/openssl/test/rmdtest.c | 92 + + .../Library/OpensslLib/openssl/test/rsa_test.c | 344 + + .../Library/OpensslLib/openssl/test/run_tests.pl | 65 + + .../Library/OpensslLib/openssl/test/sanitytest.c | 67 + + .../Library/OpensslLib/openssl/test/secmemtest.c | 103 + + .../Library/OpensslLib/openssl/test/serverinfo.pem | 16 + + .../Library/OpensslLib/openssl/test/sha1test.c | 111 + + .../Library/OpensslLib/openssl/test/sha256t.c | 177 + + .../Library/OpensslLib/openssl/test/sha512t.c | 199 + + .../Library/OpensslLib/openssl/test/shibboleth.pfx | Bin 0 -> 2519 bytes + .../OpensslLib/openssl/test/shlibloadtest.c | 231 + + .../Library/OpensslLib/openssl/test/smcont.txt | 1 + + .../OpensslLib/openssl/test/smime-certs/ca.cnf | 66 + + .../openssl/test/smime-certs/mksmime-certs.sh | 81 + + .../OpensslLib/openssl/test/smime-certs/smdh.pem | 33 + + .../OpensslLib/openssl/test/smime-certs/smdsa1.pem | 47 + + .../OpensslLib/openssl/test/smime-certs/smdsa2.pem | 47 + + .../OpensslLib/openssl/test/smime-certs/smdsa3.pem | 47 + + .../OpensslLib/openssl/test/smime-certs/smdsap.pem | 9 + + .../OpensslLib/openssl/test/smime-certs/smec1.pem | 22 + + .../OpensslLib/openssl/test/smime-certs/smec2.pem | 23 + + .../OpensslLib/openssl/test/smime-certs/smroot.pem | 49 + + .../OpensslLib/openssl/test/smime-certs/smrsa1.pem | 49 + + .../OpensslLib/openssl/test/smime-certs/smrsa2.pem | 49 + + .../OpensslLib/openssl/test/smime-certs/smrsa3.pem | 49 + + .../Library/OpensslLib/openssl/test/srptest.c | 312 + + .../openssl/test/ssl-tests/01-simple.conf | 78 + + .../openssl/test/ssl-tests/01-simple.conf.in | 42 + + .../test/ssl-tests/02-protocol-version.conf | 9975 +++++++++++++++ + .../test/ssl-tests/02-protocol-version.conf.in | 19 + + .../openssl/test/ssl-tests/03-custom_verify.conf | 238 + + .../test/ssl-tests/03-custom_verify.conf.in | 145 + + .../openssl/test/ssl-tests/04-client_auth.conf | 592 + + .../openssl/test/ssl-tests/04-client_auth.conf.in | 125 + + .../OpensslLib/openssl/test/ssl-tests/05-sni.conf | 203 + + .../openssl/test/ssl-tests/05-sni.conf.in | 112 + + .../openssl/test/ssl-tests/06-sni-ticket.conf | 734 ++ + .../openssl/test/ssl-tests/06-sni-ticket.conf.in | 95 + + .../test/ssl-tests/07-dtls-protocol-version.conf | 1820 +++ + .../ssl-tests/07-dtls-protocol-version.conf.in | 19 + + .../OpensslLib/openssl/test/ssl-tests/08-npn.conf | 794 ++ + .../openssl/test/ssl-tests/08-npn.conf.in | 420 + + .../OpensslLib/openssl/test/ssl-tests/09-alpn.conf | 619 + + .../openssl/test/ssl-tests/09-alpn.conf.in | 324 + + .../openssl/test/ssl-tests/10-resumption.conf | 1336 ++ + .../openssl/test/ssl-tests/10-resumption.conf.in | 19 + + .../openssl/test/ssl-tests/11-dtls_resumption.conf | 612 + + .../test/ssl-tests/11-dtls_resumption.conf.in | 19 + + .../OpensslLib/openssl/test/ssl-tests/12-ct.conf | 135 + + .../openssl/test/ssl-tests/12-ct.conf.in | 80 + + .../openssl/test/ssl-tests/13-fragmentation.conf | 397 + + .../test/ssl-tests/13-fragmentation.conf.in | 181 + + .../openssl/test/ssl-tests/14-curves.conf | 787 ++ + .../openssl/test/ssl-tests/14-curves.conf.in | 44 + + .../openssl/test/ssl-tests/15-certstatus.conf | 62 + + .../openssl/test/ssl-tests/15-certstatus.conf.in | 45 + + .../openssl/test/ssl-tests/16-certstatus.conf | 0 + .../openssl/test/ssl-tests/16-dtls-certstatus.conf | 62 + + .../test/ssl-tests/16-dtls-certstatus.conf.in | 45 + + .../openssl/test/ssl-tests/17-renegotiate.conf | 312 + + .../openssl/test/ssl-tests/17-renegotiate.conf.in | 182 + + .../test/ssl-tests/18-dtls-renegotiate.conf | 276 + + .../test/ssl-tests/18-dtls-renegotiate.conf.in | 170 + + .../openssl/test/ssl-tests/protocol_version.pm | 247 + + .../openssl/test/ssl-tests/ssltests_base.pm | 25 + + .../Library/OpensslLib/openssl/test/ssl_test.c | 359 + + .../Library/OpensslLib/openssl/test/ssl_test.tmpl | 126 + + .../Library/OpensslLib/openssl/test/ssl_test_ctx.c | 661 + + .../Library/OpensslLib/openssl/test/ssl_test_ctx.h | 191 + + .../OpensslLib/openssl/test/ssl_test_ctx_test.c | 338 + + .../OpensslLib/openssl/test/ssl_test_ctx_test.conf | 88 + + .../Library/OpensslLib/openssl/test/sslapitest.c | 1049 ++ + .../OpensslLib/openssl/test/sslcorrupttest.c | 282 + + .../Library/OpensslLib/openssl/test/ssltest_old.c | 3192 +++++ + .../Library/OpensslLib/openssl/test/ssltestlib.c | 682 + + .../Library/OpensslLib/openssl/test/ssltestlib.h | 40 + + CryptoPkg/Library/OpensslLib/openssl/test/test.cnf | 88 + + .../openssl/test/testlib/OpenSSL/Test.pm | 1014 ++ + .../openssl/test/testlib/OpenSSL/Test/Simple.pm | 91 + + .../openssl/test/testlib/OpenSSL/Test/Utils.pm | 239 + + .../Library/OpensslLib/openssl/test/testutil.c | 109 + + .../Library/OpensslLib/openssl/test/testutil.h | 111 + + .../Library/OpensslLib/openssl/test/threadstest.c | 246 + + .../Library/OpensslLib/openssl/test/v3-cert1.pem | 16 + + .../Library/OpensslLib/openssl/test/v3-cert2.pem | 16 + + CryptoPkg/Library/OpensslLib/openssl/test/v3ext.c | 42 + + .../Library/OpensslLib/openssl/test/v3nametest.c | 355 + + .../OpensslLib/openssl/test/verify_extra_test.c | 162 + + .../Library/OpensslLib/openssl/test/wp_test.c | 233 + + .../Library/OpensslLib/openssl/test/x509aux.c | 231 + + .../Library/OpensslLib/openssl/tools/build.info | 7 + + .../Library/OpensslLib/openssl/tools/c_rehash.in | 231 + + .../openssl/util/TLSProxy/ClientHello.pm | 242 + + .../OpensslLib/openssl/util/TLSProxy/Message.pm | 456 + + .../openssl/util/TLSProxy/NewSessionTicket.pm | 81 + + .../OpensslLib/openssl/util/TLSProxy/Proxy.pm | 525 + + .../OpensslLib/openssl/util/TLSProxy/Record.pm | 330 + + .../openssl/util/TLSProxy/ServerHello.pm | 210 + + .../openssl/util/TLSProxy/ServerKeyExchange.pm | 134 + + .../Library/OpensslLib/openssl/util/build.info | 8 + + .../Library/OpensslLib/openssl/util/ck_errf.pl | 70 + + CryptoPkg/Library/OpensslLib/openssl/util/copy.pl | 77 + + .../Library/OpensslLib/openssl/util/dofile.pl | 206 + + .../OpensslLib/openssl/util/find-doc-nits.pl | 196 + + .../OpensslLib/openssl/util/find-undoc-api.pl | 82 + + .../OpensslLib/openssl/util/find-unused-errs | 35 + + .../Library/OpensslLib/openssl/util/fipslink.pl | 115 + + CryptoPkg/Library/OpensslLib/openssl/util/incore | 454 + + .../Library/OpensslLib/openssl/util/indent.pro | 671 + + .../Library/OpensslLib/openssl/util/libcrypto.num | 4216 +++++++ + .../Library/OpensslLib/openssl/util/libssl.num | 407 + + .../Library/OpensslLib/openssl/util/mkbuildinf.pl | 41 + + .../Library/OpensslLib/openssl/util/mkcerts.sh | 220 + + CryptoPkg/Library/OpensslLib/openssl/util/mkdef.pl | 1694 +++ + .../Library/OpensslLib/openssl/util/mkdir-p.pl | 44 + + CryptoPkg/Library/OpensslLib/openssl/util/mkerr.pl | 771 ++ + CryptoPkg/Library/OpensslLib/openssl/util/mkrc.pl | 83 + + .../OpensslLib/openssl/util/openssl-format-source | 175 + + .../Library/OpensslLib/openssl/util/opensslwrap.sh | 26 + + .../openssl/util/perl/OpenSSL/Util/Pod.pm | 158 + + CryptoPkg/Library/OpensslLib/openssl/util/point.sh | 10 + + .../OpensslLib/openssl/util/process_docs.pl | 235 + + .../Library/OpensslLib/openssl/util/selftest.pl | 207 + + .../openssl/util/shareable_image_wrap.c.in | 113 + + .../OpensslLib/openssl/util/shlib_wrap.sh.in | 108 + + .../Library/OpensslLib/openssl/util/su-filter.pl | 264 + + .../OpensslLib/openssl/util/with_fallback.pm | 24 + + 2373 files changed, 684704 insertions(+) + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/.gitattributes + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/.gitignore + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/.travis-create-release.sh + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/.travis.yml + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/ACKNOWLEDGEMENTS + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/AUTHORS + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/CHANGES + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/CONTRIBUTING + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/Configurations/00-base-templates.conf + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/Configurations/10-main.conf + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/Configurations/50-djgpp.conf + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/Configurations/50-haiku.conf + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/Configurations/50-masm.conf + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/Configurations/90-team.conf + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/Configurations/INTERNALS.Configure + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/Configurations/README + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/Configurations/README.design + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/Configurations/common.tmpl + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/Configurations/descrip.mms.tmpl + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/Configurations/unix-Makefile.tmpl + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/Configurations/windows-makefile.tmpl + create mode 100755 CryptoPkg/Library/OpensslLib/openssl/Configure + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/FAQ + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/INSTALL + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/LICENSE + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/Makefile.shared + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/NEWS + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/NOTES.DJGPP + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/NOTES.PERL + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/NOTES.VMS + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/NOTES.WIN + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/README + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/README.ECC + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/README.ENGINE + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/README.FIPS + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/VMS/VMSify-conf.pl + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/VMS/engine.opt + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/VMS/openssl_ivp.com.in + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/VMS/openssl_shutdown.com.in + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/VMS/openssl_startup.com.in + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/VMS/openssl_utils.com.in + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/VMS/test-includes.com + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/VMS/translatesyms.pl + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/apps/CA.pl.in + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/apps/app_rand.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/apps/apps.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/apps/apps.h + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/apps/asn1pars.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/apps/build.info + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/apps/ca-cert.srl + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/apps/ca-key.pem + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/apps/ca-req.pem + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/apps/ca.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/apps/cert.pem + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/apps/ciphers.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/apps/client.pem + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/apps/cms.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/apps/crl.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/apps/crl2p7.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/apps/ct_log_list.cnf + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/apps/demoCA/cacert.pem + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/apps/demoCA/index.txt + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/apps/demoCA/private/cakey.pem + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/apps/demoCA/serial + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/apps/demoSRP/srp_verifier.txt + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/apps/demoSRP/srp_verifier.txt.attr + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/apps/dgst.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/apps/dh1024.pem + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/apps/dh2048.pem + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/apps/dh4096.pem + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/apps/dhparam.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/apps/dsa-ca.pem + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/apps/dsa-pca.pem + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/apps/dsa.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/apps/dsa1024.pem + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/apps/dsa512.pem + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/apps/dsap.pem + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/apps/dsaparam.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/apps/ec.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/apps/ecparam.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/apps/enc.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/apps/engine.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/apps/errstr.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/apps/gendsa.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/apps/genpkey.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/apps/genrsa.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/apps/nseq.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/apps/ocsp.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/apps/openssl-vms.cnf + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/apps/openssl.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/apps/openssl.cnf + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/apps/opt.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/apps/passwd.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/apps/pca-cert.srl + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/apps/pca-key.pem + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/apps/pca-req.pem + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/apps/pkcs12.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/apps/pkcs7.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/apps/pkcs8.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/apps/pkey.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/apps/pkeyparam.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/apps/pkeyutl.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/apps/prime.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/apps/privkey.pem + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/apps/progs.h + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/apps/progs.pl + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/apps/rand.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/apps/rehash.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/apps/req.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/apps/req.pem + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/apps/rsa.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/apps/rsa8192.pem + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/apps/rsautl.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/apps/s1024key.pem + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/apps/s1024req.pem + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/apps/s512-key.pem + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/apps/s512-req.pem + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/apps/s_apps.h + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/apps/s_cb.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/apps/s_client.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/apps/s_server.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/apps/s_socket.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/apps/s_time.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/apps/server.pem + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/apps/server.srl + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/apps/server2.pem + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/apps/sess_id.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/apps/smime.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/apps/speed.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/apps/spkac.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/apps/srp.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/apps/testCA.pem + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/apps/testdsa.h + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/apps/testrsa.h + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/apps/timeouts.h + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/apps/ts.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/apps/tsget.in + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/apps/verify.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/apps/version.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/apps/vms_decc_init.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/apps/vms_term_sock.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/apps/vms_term_sock.h + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/apps/win32_init.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/apps/x509.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/appveyor.yml + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/build.info + create mode 100755 CryptoPkg/Library/OpensslLib/openssl/config + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/config.com + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/LPdir_nyi.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/LPdir_unix.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/LPdir_vms.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/LPdir_win.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/LPdir_win32.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/LPdir_wince.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/aes/aes_cbc.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/aes/aes_cfb.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/aes/aes_core.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/aes/aes_ecb.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/aes/aes_ige.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/aes/aes_locl.h + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/aes/aes_misc.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/aes/aes_ofb.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/aes/aes_wrap.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/aes/aes_x86core.c + create mode 100755 CryptoPkg/Library/OpensslLib/openssl/crypto/aes/asm/aes-586.pl + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/aes/asm/aes-armv4.pl + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/aes/asm/aes-c64xplus.pl + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/aes/asm/aes-ia64.S + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/aes/asm/aes-mips.pl + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/aes/asm/aes-parisc.pl + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/aes/asm/aes-ppc.pl + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/aes/asm/aes-s390x.pl + create mode 100755 CryptoPkg/Library/OpensslLib/openssl/crypto/aes/asm/aes-sparcv9.pl + create mode 100755 CryptoPkg/Library/OpensslLib/openssl/crypto/aes/asm/aes-x86_64.pl + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/aes/asm/aesfx-sparcv9.pl + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/aes/asm/aesni-mb-x86_64.pl + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/aes/asm/aesni-sha1-x86_64.pl + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/aes/asm/aesni-sha256-x86_64.pl + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/aes/asm/aesni-x86.pl + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/aes/asm/aesni-x86_64.pl + create mode 100755 CryptoPkg/Library/OpensslLib/openssl/crypto/aes/asm/aesp8-ppc.pl + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/aes/asm/aest4-sparcv9.pl + create mode 100755 CryptoPkg/Library/OpensslLib/openssl/crypto/aes/asm/aesv8-armx.pl + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/aes/asm/bsaes-armv7.pl + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/aes/asm/bsaes-x86_64.pl + create mode 100755 CryptoPkg/Library/OpensslLib/openssl/crypto/aes/asm/vpaes-armv8.pl + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/aes/asm/vpaes-ppc.pl + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/aes/asm/vpaes-x86.pl + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/aes/asm/vpaes-x86_64.pl + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/aes/build.info + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/alphacpuid.pl + create mode 100755 CryptoPkg/Library/OpensslLib/openssl/crypto/arm64cpuid.pl + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/arm_arch.h + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/armcap.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/armv4cpuid.pl + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/asn1/a_bitstr.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/asn1/a_d2i_fp.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/asn1/a_digest.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/asn1/a_dup.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/asn1/a_gentm.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/asn1/a_i2d_fp.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/asn1/a_int.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/asn1/a_mbstr.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/asn1/a_object.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/asn1/a_octet.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/asn1/a_print.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/asn1/a_sign.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/asn1/a_strex.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/asn1/a_strnid.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/asn1/a_time.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/asn1/a_type.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/asn1/a_utctm.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/asn1/a_utf8.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/asn1/a_verify.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/asn1/ameth_lib.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/asn1/asn1_err.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/asn1/asn1_gen.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/asn1/asn1_lib.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/asn1/asn1_locl.h + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/asn1/asn1_par.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/asn1/asn_mime.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/asn1/asn_moid.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/asn1/asn_mstbl.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/asn1/asn_pack.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/asn1/bio_asn1.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/asn1/bio_ndef.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/asn1/build.info + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/asn1/charmap.h + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/asn1/charmap.pl + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/asn1/d2i_pr.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/asn1/d2i_pu.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/asn1/evp_asn1.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/asn1/f_int.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/asn1/f_string.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/asn1/i2d_pr.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/asn1/i2d_pu.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/asn1/n_pkey.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/asn1/nsseq.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/asn1/p5_pbe.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/asn1/p5_pbev2.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/asn1/p5_scrypt.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/asn1/p8_pkey.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/asn1/t_bitst.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/asn1/t_pkey.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/asn1/t_spki.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/asn1/tasn_dec.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/asn1/tasn_enc.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/asn1/tasn_fre.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/asn1/tasn_new.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/asn1/tasn_prn.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/asn1/tasn_scn.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/asn1/tasn_typ.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/asn1/tasn_utl.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/asn1/x_algor.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/asn1/x_bignum.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/asn1/x_info.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/asn1/x_long.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/asn1/x_pkey.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/asn1/x_sig.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/asn1/x_spki.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/asn1/x_val.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/async/arch/async_null.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/async/arch/async_null.h + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/async/arch/async_posix.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/async/arch/async_posix.h + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/async/arch/async_win.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/async/arch/async_win.h + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/async/async.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/async/async_err.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/async/async_locl.h + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/async/async_wait.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/async/build.info + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/bf/asm/bf-586.pl + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/bf/bf_cbc.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/bf/bf_cfb64.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/bf/bf_ecb.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/bf/bf_enc.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/bf/bf_locl.h + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/bf/bf_ofb64.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/bf/bf_pi.h + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/bf/bf_skey.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/bf/build.info + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/bio/b_addr.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/bio/b_dump.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/bio/b_print.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/bio/b_sock.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/bio/b_sock2.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/bio/bf_buff.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/bio/bf_lbuf.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/bio/bf_nbio.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/bio/bf_null.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/bio/bio_cb.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/bio/bio_err.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/bio/bio_lcl.h + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/bio/bio_lib.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/bio/bio_meth.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/bio/bss_acpt.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/bio/bss_bio.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/bio/bss_conn.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/bio/bss_dgram.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/bio/bss_fd.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/bio/bss_file.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/bio/bss_log.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/bio/bss_mem.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/bio/bss_null.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/bio/bss_sock.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/bio/build.info + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/blake2/blake2_impl.h + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/blake2/blake2_locl.h + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/blake2/blake2b.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/blake2/blake2s.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/blake2/build.info + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/blake2/m_blake2b.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/blake2/m_blake2s.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/bn/README.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/bn/asm/alpha-mont.pl + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/bn/asm/armv4-gf2m.pl + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/bn/asm/armv4-mont.pl + create mode 100755 CryptoPkg/Library/OpensslLib/openssl/crypto/bn/asm/armv8-mont.pl + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/bn/asm/bn-586.pl + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/bn/asm/bn-c64xplus.asm + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/bn/asm/c64xplus-gf2m.pl + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/bn/asm/co-586.pl + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/bn/asm/ia64-mont.pl + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/bn/asm/ia64.S + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/bn/asm/mips-mont.pl + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/bn/asm/mips.pl + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/bn/asm/pa-risc2.s + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/bn/asm/pa-risc2W.s + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/bn/asm/parisc-mont.pl + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/bn/asm/ppc-mont.pl + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/bn/asm/ppc.pl + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/bn/asm/ppc64-mont.pl + create mode 100755 CryptoPkg/Library/OpensslLib/openssl/crypto/bn/asm/rsaz-avx2.pl + create mode 100755 CryptoPkg/Library/OpensslLib/openssl/crypto/bn/asm/rsaz-x86_64.pl + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/bn/asm/s390x-gf2m.pl + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/bn/asm/s390x-mont.pl + create mode 100755 CryptoPkg/Library/OpensslLib/openssl/crypto/bn/asm/s390x.S + create mode 100755 CryptoPkg/Library/OpensslLib/openssl/crypto/bn/asm/sparct4-mont.pl + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/bn/asm/sparcv8.S + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/bn/asm/sparcv8plus.S + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/bn/asm/sparcv9-gf2m.pl + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/bn/asm/sparcv9-mont.pl + create mode 100755 CryptoPkg/Library/OpensslLib/openssl/crypto/bn/asm/sparcv9a-mont.pl + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/bn/asm/via-mont.pl + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/bn/asm/vis3-mont.pl + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/bn/asm/x86-gf2m.pl + create mode 100755 CryptoPkg/Library/OpensslLib/openssl/crypto/bn/asm/x86-mont.pl + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/bn/asm/x86.pl + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/bn/asm/x86_64-gcc.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/bn/asm/x86_64-gf2m.pl + create mode 100755 CryptoPkg/Library/OpensslLib/openssl/crypto/bn/asm/x86_64-mont.pl + create mode 100755 CryptoPkg/Library/OpensslLib/openssl/crypto/bn/asm/x86_64-mont5.pl + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/bn/bn_add.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/bn/bn_asm.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/bn/bn_blind.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/bn/bn_const.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/bn/bn_ctx.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/bn/bn_depr.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/bn/bn_dh.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/bn/bn_div.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/bn/bn_err.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/bn/bn_exp.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/bn/bn_exp2.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/bn/bn_gcd.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/bn/bn_gf2m.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/bn/bn_intern.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/bn/bn_kron.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/bn/bn_lcl.h + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/bn/bn_lib.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/bn/bn_mod.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/bn/bn_mont.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/bn/bn_mpi.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/bn/bn_mul.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/bn/bn_nist.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/bn/bn_prime.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/bn/bn_prime.h + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/bn/bn_prime.pl + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/bn/bn_print.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/bn/bn_rand.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/bn/bn_recp.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/bn/bn_shift.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/bn/bn_sqr.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/bn/bn_sqrt.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/bn/bn_srp.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/bn/bn_word.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/bn/bn_x931p.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/bn/build.info + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/bn/rsaz_exp.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/bn/rsaz_exp.h + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/buffer/buf_err.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/buffer/buffer.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/buffer/build.info + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/build.info + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/c64xpluscpuid.pl + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/camellia/asm/cmll-x86.pl + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/camellia/asm/cmll-x86_64.pl + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/camellia/asm/cmllt4-sparcv9.pl + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/camellia/build.info + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/camellia/camellia.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/camellia/cmll_cbc.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/camellia/cmll_cfb.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/camellia/cmll_ctr.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/camellia/cmll_ecb.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/camellia/cmll_locl.h + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/camellia/cmll_misc.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/camellia/cmll_ofb.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/cast/asm/cast-586.pl + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/cast/build.info + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/cast/c_cfb64.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/cast/c_ecb.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/cast/c_enc.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/cast/c_ofb64.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/cast/c_skey.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/cast/cast_lcl.h + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/cast/cast_s.h + create mode 100755 CryptoPkg/Library/OpensslLib/openssl/crypto/chacha/asm/chacha-armv4.pl + create mode 100755 CryptoPkg/Library/OpensslLib/openssl/crypto/chacha/asm/chacha-armv8.pl + create mode 100755 CryptoPkg/Library/OpensslLib/openssl/crypto/chacha/asm/chacha-c64xplus.pl + create mode 100755 CryptoPkg/Library/OpensslLib/openssl/crypto/chacha/asm/chacha-ppc.pl + create mode 100755 CryptoPkg/Library/OpensslLib/openssl/crypto/chacha/asm/chacha-s390x.pl + create mode 100755 CryptoPkg/Library/OpensslLib/openssl/crypto/chacha/asm/chacha-x86.pl + create mode 100755 CryptoPkg/Library/OpensslLib/openssl/crypto/chacha/asm/chacha-x86_64.pl + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/chacha/build.info + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/chacha/chacha_enc.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/cmac/build.info + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/cmac/cm_ameth.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/cmac/cm_pmeth.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/cmac/cmac.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/cms/build.info + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/cms/cms_asn1.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/cms/cms_att.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/cms/cms_cd.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/cms/cms_dd.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/cms/cms_enc.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/cms/cms_env.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/cms/cms_err.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/cms/cms_ess.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/cms/cms_io.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/cms/cms_kari.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/cms/cms_lcl.h + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/cms/cms_lib.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/cms/cms_pwri.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/cms/cms_sd.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/cms/cms_smime.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/comp/build.info + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/comp/c_zlib.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/comp/comp_err.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/comp/comp_lcl.h + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/comp/comp_lib.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/conf/build.info + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/conf/conf_api.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/conf/conf_def.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/conf/conf_def.h + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/conf/conf_err.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/conf/conf_lib.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/conf/conf_mall.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/conf/conf_mod.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/conf/conf_sap.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/conf/keysets.pl + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/cpt_err.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/cryptlib.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/ct/build.info + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/ct/ct_b64.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/ct/ct_err.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/ct/ct_locl.h + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/ct/ct_log.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/ct/ct_oct.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/ct/ct_policy.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/ct/ct_prn.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/ct/ct_sct.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/ct/ct_sct_ctx.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/ct/ct_vfy.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/ct/ct_x509v3.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/cversion.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/des/asm/crypt586.pl + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/des/asm/des-586.pl + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/des/asm/des_enc.m4 + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/des/asm/desboth.pl + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/des/asm/dest4-sparcv9.pl + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/des/build.info + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/des/cbc_cksm.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/des/cbc_enc.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/des/cfb64ede.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/des/cfb64enc.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/des/cfb_enc.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/des/des_enc.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/des/des_locl.h + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/des/ecb3_enc.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/des/ecb_enc.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/des/fcrypt.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/des/fcrypt_b.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/des/ncbc_enc.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/des/ofb64ede.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/des/ofb64enc.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/des/ofb_enc.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/des/pcbc_enc.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/des/qud_cksm.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/des/rand_key.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/des/rpc_des.h + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/des/rpc_enc.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/des/set_key.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/des/spr.h + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/des/str2key.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/des/xcbc_enc.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/dh/build.info + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/dh/dh1024.pem + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/dh/dh192.pem + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/dh/dh2048.pem + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/dh/dh4096.pem + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/dh/dh512.pem + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/dh/dh_ameth.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/dh/dh_asn1.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/dh/dh_check.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/dh/dh_depr.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/dh/dh_err.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/dh/dh_gen.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/dh/dh_kdf.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/dh/dh_key.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/dh/dh_lib.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/dh/dh_locl.h + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/dh/dh_meth.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/dh/dh_pmeth.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/dh/dh_prn.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/dh/dh_rfc5114.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/dllmain.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/dsa/build.info + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/dsa/dsa_ameth.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/dsa/dsa_asn1.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/dsa/dsa_depr.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/dsa/dsa_err.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/dsa/dsa_gen.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/dsa/dsa_key.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/dsa/dsa_lib.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/dsa/dsa_locl.h + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/dsa/dsa_meth.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/dsa/dsa_ossl.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/dsa/dsa_pmeth.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/dsa/dsa_prn.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/dsa/dsa_sign.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/dsa/dsa_vrf.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/dso/build.info + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/dso/dso_dl.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/dso/dso_dlfcn.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/dso/dso_err.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/dso/dso_lib.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/dso/dso_locl.h + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/dso/dso_openssl.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/dso/dso_vms.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/dso/dso_win32.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/ebcdic.c + create mode 100755 CryptoPkg/Library/OpensslLib/openssl/crypto/ec/asm/ecp_nistz256-armv4.pl + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/ec/asm/ecp_nistz256-armv8.pl + create mode 100755 CryptoPkg/Library/OpensslLib/openssl/crypto/ec/asm/ecp_nistz256-avx2.pl + create mode 100755 CryptoPkg/Library/OpensslLib/openssl/crypto/ec/asm/ecp_nistz256-sparcv9.pl + create mode 100755 CryptoPkg/Library/OpensslLib/openssl/crypto/ec/asm/ecp_nistz256-x86.pl + create mode 100755 CryptoPkg/Library/OpensslLib/openssl/crypto/ec/asm/ecp_nistz256-x86_64.pl + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/ec/build.info + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/ec/curve25519.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/ec/ec2_mult.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/ec/ec2_oct.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/ec/ec2_smpl.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/ec/ec_ameth.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/ec/ec_asn1.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/ec/ec_check.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/ec/ec_curve.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/ec/ec_cvt.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/ec/ec_err.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/ec/ec_key.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/ec/ec_kmeth.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/ec/ec_lcl.h + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/ec/ec_lib.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/ec/ec_mult.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/ec/ec_oct.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/ec/ec_pmeth.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/ec/ec_print.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/ec/ecdh_kdf.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/ec/ecdh_ossl.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/ec/ecdsa_ossl.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/ec/ecdsa_sign.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/ec/ecdsa_vrf.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/ec/eck_prn.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/ec/ecp_mont.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/ec/ecp_nist.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/ec/ecp_nistp224.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/ec/ecp_nistp256.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/ec/ecp_nistp521.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/ec/ecp_nistputil.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/ec/ecp_nistz256.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/ec/ecp_nistz256_table.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/ec/ecp_oct.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/ec/ecp_smpl.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/ec/ecx_meth.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/engine/README + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/engine/build.info + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/engine/eng_all.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/engine/eng_cnf.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/engine/eng_cryptodev.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/engine/eng_ctrl.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/engine/eng_dyn.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/engine/eng_err.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/engine/eng_fat.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/engine/eng_init.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/engine/eng_int.h + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/engine/eng_lib.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/engine/eng_list.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/engine/eng_openssl.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/engine/eng_pkey.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/engine/eng_rdrand.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/engine/eng_table.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/engine/tb_asnmth.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/engine/tb_cipher.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/engine/tb_dh.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/engine/tb_digest.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/engine/tb_dsa.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/engine/tb_eckey.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/engine/tb_pkmeth.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/engine/tb_rand.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/engine/tb_rsa.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/err/README + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/err/build.info + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/err/err.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/err/err_all.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/err/err_prn.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/err/openssl.ec + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/evp/bio_b64.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/evp/bio_enc.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/evp/bio_md.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/evp/bio_ok.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/evp/build.info + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/evp/c_allc.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/evp/c_alld.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/evp/cmeth_lib.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/evp/digest.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/evp/e_aes.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/evp/e_aes_cbc_hmac_sha1.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/evp/e_aes_cbc_hmac_sha256.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/evp/e_bf.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/evp/e_camellia.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/evp/e_cast.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/evp/e_chacha20_poly1305.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/evp/e_des.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/evp/e_des3.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/evp/e_idea.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/evp/e_null.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/evp/e_old.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/evp/e_rc2.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/evp/e_rc4.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/evp/e_rc4_hmac_md5.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/evp/e_rc5.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/evp/e_seed.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/evp/e_xcbc_d.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/evp/encode.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/evp/evp_cnf.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/evp/evp_enc.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/evp/evp_err.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/evp/evp_key.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/evp/evp_lib.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/evp/evp_locl.h + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/evp/evp_pbe.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/evp/evp_pkey.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/evp/m_md2.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/evp/m_md4.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/evp/m_md5.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/evp/m_md5_sha1.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/evp/m_mdc2.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/evp/m_null.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/evp/m_ripemd.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/evp/m_sha1.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/evp/m_sigver.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/evp/m_wp.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/evp/names.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/evp/p5_crpt.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/evp/p5_crpt2.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/evp/p_dec.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/evp/p_enc.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/evp/p_lib.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/evp/p_open.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/evp/p_seal.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/evp/p_sign.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/evp/p_verify.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/evp/pmeth_fn.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/evp/pmeth_gn.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/evp/pmeth_lib.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/evp/scrypt.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/ex_data.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/hmac/build.info + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/hmac/hm_ameth.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/hmac/hm_pmeth.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/hmac/hmac.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/hmac/hmac_lcl.h + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/ia64cpuid.S + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/idea/build.info + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/idea/i_cbc.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/idea/i_cfb64.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/idea/i_ecb.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/idea/i_ofb64.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/idea/i_skey.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/idea/idea_lcl.h + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/include/internal/asn1_int.h + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/include/internal/async.h + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/include/internal/bn_conf.h.in + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/include/internal/bn_dh.h + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/include/internal/bn_int.h + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/include/internal/bn_srp.h + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/include/internal/chacha.h + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/include/internal/cryptlib.h + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/include/internal/cryptlib_int.h + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/include/internal/dso_conf.h.in + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/include/internal/engine.h + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/include/internal/err_int.h + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/include/internal/evp_int.h + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/include/internal/md32_common.h + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/include/internal/objects.h + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/include/internal/poly1305.h + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/include/internal/rand.h + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/include/internal/x509_int.h + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/init.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/kdf/build.info + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/kdf/hkdf.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/kdf/kdf_err.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/kdf/tls1_prf.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/lhash/build.info + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/lhash/lh_stats.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/lhash/lhash.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/lhash/lhash_lcl.h + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/lhash/num.pl + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/md2/build.info + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/md2/md2_dgst.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/md2/md2_one.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/md4/build.info + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/md4/md4_dgst.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/md4/md4_locl.h + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/md4/md4_one.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/md5/asm/md5-586.pl + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/md5/asm/md5-ia64.S + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/md5/asm/md5-sparcv9.pl + create mode 100755 CryptoPkg/Library/OpensslLib/openssl/crypto/md5/asm/md5-x86_64.pl + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/md5/build.info + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/md5/md5_dgst.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/md5/md5_locl.h + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/md5/md5_one.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/mdc2/build.info + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/mdc2/mdc2_one.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/mdc2/mdc2dgst.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/mem.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/mem_clr.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/mem_dbg.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/mem_sec.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/modes/asm/aesni-gcm-x86_64.pl + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/modes/asm/ghash-alpha.pl + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/modes/asm/ghash-armv4.pl + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/modes/asm/ghash-c64xplus.pl + create mode 100755 CryptoPkg/Library/OpensslLib/openssl/crypto/modes/asm/ghash-ia64.pl + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/modes/asm/ghash-parisc.pl + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/modes/asm/ghash-s390x.pl + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/modes/asm/ghash-sparcv9.pl + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/modes/asm/ghash-x86.pl + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/modes/asm/ghash-x86_64.pl + create mode 100755 CryptoPkg/Library/OpensslLib/openssl/crypto/modes/asm/ghashp8-ppc.pl + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/modes/asm/ghashv8-armx.pl + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/modes/build.info + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/modes/cbc128.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/modes/ccm128.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/modes/cfb128.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/modes/ctr128.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/modes/cts128.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/modes/gcm128.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/modes/modes_lcl.h + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/modes/ocb128.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/modes/ofb128.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/modes/wrap128.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/modes/xts128.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/o_dir.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/o_fips.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/o_fopen.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/o_init.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/o_str.c + create mode 100755 CryptoPkg/Library/OpensslLib/openssl/crypto/o_time.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/objects/README + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/objects/build.info + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/objects/o_names.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/objects/obj_dat.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/objects/obj_dat.h + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/objects/obj_dat.pl + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/objects/obj_err.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/objects/obj_lcl.h + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/objects/obj_lib.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/objects/obj_mac.num + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/objects/obj_xref.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/objects/obj_xref.h + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/objects/obj_xref.txt + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/objects/objects.pl + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/objects/objects.txt + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/objects/objxref.pl + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/ocsp/build.info + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/ocsp/ocsp_asn.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/ocsp/ocsp_cl.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/ocsp/ocsp_err.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/ocsp/ocsp_ext.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/ocsp/ocsp_ht.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/ocsp/ocsp_lcl.h + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/ocsp/ocsp_lib.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/ocsp/ocsp_prn.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/ocsp/ocsp_srv.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/ocsp/ocsp_vfy.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/ocsp/v3_ocsp.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/pariscid.pl + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/pem/build.info + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/pem/pem_all.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/pem/pem_err.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/pem/pem_info.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/pem/pem_lib.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/pem/pem_oth.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/pem/pem_pk8.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/pem/pem_pkey.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/pem/pem_sign.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/pem/pem_x509.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/pem/pem_xaux.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/pem/pvkfmt.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/perlasm/README + create mode 100755 CryptoPkg/Library/OpensslLib/openssl/crypto/perlasm/arm-xlate.pl + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/perlasm/cbc.pl + create mode 100755 CryptoPkg/Library/OpensslLib/openssl/crypto/perlasm/ppc-xlate.pl + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/perlasm/sparcv9_modes.pl + create mode 100755 CryptoPkg/Library/OpensslLib/openssl/crypto/perlasm/x86_64-xlate.pl + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/perlasm/x86asm.pl + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/perlasm/x86gas.pl + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/perlasm/x86masm.pl + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/perlasm/x86nasm.pl + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/pkcs12/build.info + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/pkcs12/p12_add.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/pkcs12/p12_asn.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/pkcs12/p12_attr.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/pkcs12/p12_crpt.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/pkcs12/p12_crt.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/pkcs12/p12_decr.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/pkcs12/p12_init.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/pkcs12/p12_key.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/pkcs12/p12_kiss.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/pkcs12/p12_lcl.h + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/pkcs12/p12_mutl.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/pkcs12/p12_npas.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/pkcs12/p12_p8d.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/pkcs12/p12_p8e.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/pkcs12/p12_sbag.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/pkcs12/p12_utl.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/pkcs12/pk12err.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/pkcs7/bio_pk7.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/pkcs7/build.info + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/pkcs7/pk7_asn1.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/pkcs7/pk7_attr.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/pkcs7/pk7_dgst.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/pkcs7/pk7_doit.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/pkcs7/pk7_enc.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/pkcs7/pk7_lib.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/pkcs7/pk7_mime.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/pkcs7/pk7_smime.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/pkcs7/pkcs7err.c + create mode 100755 CryptoPkg/Library/OpensslLib/openssl/crypto/poly1305/asm/poly1305-armv4.pl + create mode 100755 CryptoPkg/Library/OpensslLib/openssl/crypto/poly1305/asm/poly1305-armv8.pl + create mode 100755 CryptoPkg/Library/OpensslLib/openssl/crypto/poly1305/asm/poly1305-c64xplus.pl + create mode 100755 CryptoPkg/Library/OpensslLib/openssl/crypto/poly1305/asm/poly1305-mips.pl + create mode 100755 CryptoPkg/Library/OpensslLib/openssl/crypto/poly1305/asm/poly1305-ppc.pl + create mode 100755 CryptoPkg/Library/OpensslLib/openssl/crypto/poly1305/asm/poly1305-ppcfp.pl + create mode 100755 CryptoPkg/Library/OpensslLib/openssl/crypto/poly1305/asm/poly1305-s390x.pl + create mode 100755 CryptoPkg/Library/OpensslLib/openssl/crypto/poly1305/asm/poly1305-sparcv9.pl + create mode 100755 CryptoPkg/Library/OpensslLib/openssl/crypto/poly1305/asm/poly1305-x86.pl + create mode 100755 CryptoPkg/Library/OpensslLib/openssl/crypto/poly1305/asm/poly1305-x86_64.pl + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/poly1305/build.info + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/poly1305/poly1305.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/poly1305/poly1305_ieee754.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/ppc_arch.h + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/ppccap.c + create mode 100755 CryptoPkg/Library/OpensslLib/openssl/crypto/ppccpuid.pl + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/rand/build.info + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/rand/md_rand.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/rand/rand_egd.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/rand/rand_err.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/rand/rand_lcl.h + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/rand/rand_lib.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/rand/rand_unix.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/rand/rand_vms.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/rand/rand_win.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/rand/randfile.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/rc2/build.info + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/rc2/rc2_cbc.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/rc2/rc2_ecb.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/rc2/rc2_locl.h + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/rc2/rc2_skey.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/rc2/rc2cfb64.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/rc2/rc2ofb64.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/rc2/tab.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/rc4/asm/rc4-586.pl + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/rc4/asm/rc4-c64xplus.pl + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/rc4/asm/rc4-ia64.pl + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/rc4/asm/rc4-md5-x86_64.pl + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/rc4/asm/rc4-parisc.pl + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/rc4/asm/rc4-s390x.pl + create mode 100755 CryptoPkg/Library/OpensslLib/openssl/crypto/rc4/asm/rc4-x86_64.pl + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/rc4/build.info + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/rc4/rc4_enc.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/rc4/rc4_locl.h + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/rc4/rc4_skey.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/rc5/asm/rc5-586.pl + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/rc5/build.info + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/rc5/rc5_ecb.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/rc5/rc5_enc.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/rc5/rc5_locl.h + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/rc5/rc5_skey.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/rc5/rc5cfb64.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/rc5/rc5ofb64.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/ripemd/asm/rmd-586.pl + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/ripemd/build.info + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/ripemd/rmd_dgst.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/ripemd/rmd_locl.h + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/ripemd/rmd_one.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/ripemd/rmdconst.h + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/rsa/build.info + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/rsa/rsa_ameth.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/rsa/rsa_asn1.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/rsa/rsa_chk.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/rsa/rsa_crpt.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/rsa/rsa_depr.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/rsa/rsa_err.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/rsa/rsa_gen.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/rsa/rsa_lib.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/rsa/rsa_locl.h + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/rsa/rsa_meth.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/rsa/rsa_none.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/rsa/rsa_null.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/rsa/rsa_oaep.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/rsa/rsa_ossl.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/rsa/rsa_pk1.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/rsa/rsa_pmeth.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/rsa/rsa_prn.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/rsa/rsa_pss.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/rsa/rsa_saos.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/rsa/rsa_sign.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/rsa/rsa_ssl.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/rsa/rsa_x931.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/rsa/rsa_x931g.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/s390xcap.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/s390xcpuid.S + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/seed/build.info + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/seed/seed.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/seed/seed_cbc.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/seed/seed_cfb.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/seed/seed_ecb.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/seed/seed_locl.h + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/seed/seed_ofb.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/sha/asm/sha1-586.pl + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/sha/asm/sha1-alpha.pl + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/sha/asm/sha1-armv4-large.pl + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/sha/asm/sha1-armv8.pl + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/sha/asm/sha1-c64xplus.pl + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/sha/asm/sha1-ia64.pl + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/sha/asm/sha1-mb-x86_64.pl + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/sha/asm/sha1-mips.pl + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/sha/asm/sha1-parisc.pl + create mode 100755 CryptoPkg/Library/OpensslLib/openssl/crypto/sha/asm/sha1-ppc.pl + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/sha/asm/sha1-s390x.pl + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/sha/asm/sha1-sparcv9.pl + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/sha/asm/sha1-sparcv9a.pl + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/sha/asm/sha1-thumb.pl + create mode 100755 CryptoPkg/Library/OpensslLib/openssl/crypto/sha/asm/sha1-x86_64.pl + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/sha/asm/sha256-586.pl + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/sha/asm/sha256-armv4.pl + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/sha/asm/sha256-c64xplus.pl + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/sha/asm/sha256-mb-x86_64.pl + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/sha/asm/sha512-586.pl + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/sha/asm/sha512-armv4.pl + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/sha/asm/sha512-armv8.pl + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/sha/asm/sha512-c64xplus.pl + create mode 100755 CryptoPkg/Library/OpensslLib/openssl/crypto/sha/asm/sha512-ia64.pl + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/sha/asm/sha512-mips.pl + create mode 100755 CryptoPkg/Library/OpensslLib/openssl/crypto/sha/asm/sha512-parisc.pl + create mode 100755 CryptoPkg/Library/OpensslLib/openssl/crypto/sha/asm/sha512-ppc.pl + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/sha/asm/sha512-s390x.pl + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/sha/asm/sha512-sparcv9.pl + create mode 100755 CryptoPkg/Library/OpensslLib/openssl/crypto/sha/asm/sha512-x86_64.pl + create mode 100755 CryptoPkg/Library/OpensslLib/openssl/crypto/sha/asm/sha512p8-ppc.pl + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/sha/build.info + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/sha/sha1_one.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/sha/sha1dgst.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/sha/sha256.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/sha/sha512.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/sha/sha_locl.h + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/sparc_arch.h + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/sparccpuid.S + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/sparcv9cap.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/srp/build.info + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/srp/srp_lib.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/srp/srp_vfy.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/stack/build.info + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/stack/stack.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/threads_none.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/threads_pthread.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/threads_win.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/ts/build.info + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/ts/ts_asn1.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/ts/ts_conf.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/ts/ts_err.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/ts/ts_lcl.h + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/ts/ts_lib.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/ts/ts_req_print.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/ts/ts_req_utils.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/ts/ts_rsp_print.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/ts/ts_rsp_sign.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/ts/ts_rsp_utils.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/ts/ts_rsp_verify.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/ts/ts_verify_ctx.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/txt_db/build.info + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/txt_db/txt_db.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/ui/build.info + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/ui/ui_err.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/ui/ui_lib.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/ui/ui_locl.h + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/ui/ui_openssl.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/ui/ui_util.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/uid.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/vms_rms.h + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/whrlpool/asm/wp-mmx.pl + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/whrlpool/asm/wp-x86_64.pl + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/whrlpool/build.info + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/whrlpool/wp_block.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/whrlpool/wp_dgst.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/whrlpool/wp_locl.h + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/x509/build.info + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/x509/by_dir.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/x509/by_file.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/x509/t_crl.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/x509/t_req.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/x509/t_x509.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/x509/x509_att.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/x509/x509_cmp.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/x509/x509_d2.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/x509/x509_def.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/x509/x509_err.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/x509/x509_ext.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/x509/x509_lcl.h + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/x509/x509_lu.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/x509/x509_obj.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/x509/x509_r2x.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/x509/x509_req.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/x509/x509_set.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/x509/x509_trs.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/x509/x509_txt.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/x509/x509_v3.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/x509/x509_vfy.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/x509/x509_vpm.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/x509/x509cset.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/x509/x509name.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/x509/x509rset.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/x509/x509spki.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/x509/x509type.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/x509/x_all.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/x509/x_attrib.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/x509/x_crl.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/x509/x_exten.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/x509/x_name.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/x509/x_pubkey.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/x509/x_req.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/x509/x_x509.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/x509/x_x509a.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/x509v3/build.info + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/x509v3/ext_dat.h + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/x509v3/pcy_cache.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/x509v3/pcy_data.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/x509v3/pcy_int.h + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/x509v3/pcy_lib.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/x509v3/pcy_map.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/x509v3/pcy_node.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/x509v3/pcy_tree.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/x509v3/tabtest.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/x509v3/v3_addr.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/x509v3/v3_akey.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/x509v3/v3_akeya.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/x509v3/v3_alt.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/x509v3/v3_asid.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/x509v3/v3_bcons.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/x509v3/v3_bitst.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/x509v3/v3_conf.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/x509v3/v3_cpols.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/x509v3/v3_crld.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/x509v3/v3_enum.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/x509v3/v3_extku.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/x509v3/v3_genn.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/x509v3/v3_ia5.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/x509v3/v3_info.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/x509v3/v3_int.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/x509v3/v3_lib.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/x509v3/v3_ncons.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/x509v3/v3_pci.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/x509v3/v3_pcia.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/x509v3/v3_pcons.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/x509v3/v3_pku.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/x509v3/v3_pmaps.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/x509v3/v3_prn.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/x509v3/v3_purp.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/x509v3/v3_skey.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/x509v3/v3_sxnet.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/x509v3/v3_tlsf.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/x509v3/v3_utl.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/x509v3/v3conf.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/x509v3/v3err.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/x509v3/v3prin.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/x86_64cpuid.pl + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/crypto/x86cpuid.pl + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/demos/README + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/demos/bio/Makefile + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/demos/bio/README + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/demos/bio/accept.cnf + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/demos/bio/client-arg.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/demos/bio/client-conf.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/demos/bio/cmod.cnf + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/demos/bio/connect.cnf + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/demos/bio/descrip.mms + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/demos/bio/intca.pem + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/demos/bio/root.pem + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/demos/bio/saccept.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/demos/bio/sconnect.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/demos/bio/server-arg.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/demos/bio/server-cmod.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/demos/bio/server-conf.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/demos/bio/server-ec.pem + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/demos/bio/server.pem + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/demos/bio/shared.opt + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/demos/bio/static.opt + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/demos/certs/README + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/demos/certs/apps/apps.cnf + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/demos/certs/apps/ckey.pem + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/demos/certs/apps/intkey.pem + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/demos/certs/apps/mkacerts.sh + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/demos/certs/apps/mkxcerts.sh + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/demos/certs/apps/rootkey.pem + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/demos/certs/apps/skey.pem + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/demos/certs/apps/skey2.pem + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/demos/certs/ca.cnf + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/demos/certs/mkcerts.sh + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/demos/certs/ocspquery.sh + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/demos/certs/ocsprun.sh + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/demos/cms/cacert.pem + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/demos/cms/cakey.pem + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/demos/cms/cms_comp.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/demos/cms/cms_ddec.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/demos/cms/cms_dec.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/demos/cms/cms_denc.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/demos/cms/cms_enc.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/demos/cms/cms_sign.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/demos/cms/cms_sign2.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/demos/cms/cms_uncomp.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/demos/cms/cms_ver.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/demos/cms/comp.txt + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/demos/cms/encr.txt + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/demos/cms/sign.txt + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/demos/cms/signer.pem + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/demos/cms/signer2.pem + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/demos/evp/aesccm.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/demos/evp/aesgcm.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/demos/pkcs12/README + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/demos/pkcs12/pkread.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/demos/pkcs12/pkwrite.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/demos/smime/cacert.pem + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/demos/smime/cakey.pem + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/demos/smime/encr.txt + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/demos/smime/sign.txt + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/demos/smime/signer.pem + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/demos/smime/signer2.pem + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/demos/smime/smdec.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/demos/smime/smenc.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/demos/smime/smsign.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/demos/smime/smsign2.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/demos/smime/smver.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/CT_POLICY_EVAL_CTX_new.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/HOWTO/certificates.txt + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/HOWTO/keys.txt + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/HOWTO/proxy_certificates.txt + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/README + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/SCT_validate.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/SSL_CTX_set_ct_validation_callback.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/apps/CA.pl.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/apps/asn1parse.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/apps/ca.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/apps/ciphers.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/apps/cms.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/apps/config.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/apps/crl.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/apps/crl2pkcs7.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/apps/dgst.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/apps/dhparam.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/apps/dsa.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/apps/dsaparam.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/apps/ec.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/apps/ecparam.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/apps/enc.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/apps/engine.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/apps/errstr.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/apps/gendsa.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/apps/genpkey.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/apps/genrsa.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/apps/list.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/apps/nseq.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/apps/ocsp.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/apps/openssl.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/apps/passwd.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/apps/pkcs12.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/apps/pkcs7.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/apps/pkcs8.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/apps/pkey.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/apps/pkeyparam.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/apps/pkeyutl.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/apps/rand.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/apps/rehash.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/apps/req.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/apps/rsa.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/apps/rsautl.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/apps/s_client.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/apps/s_server.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/apps/s_time.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/apps/sess_id.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/apps/smime.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/apps/speed.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/apps/spkac.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/apps/ts.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/apps/tsget.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/apps/verify.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/apps/version.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/apps/x509.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/apps/x509v3_config.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/crypto/ASN1_INTEGER_get_int64.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/crypto/ASN1_OBJECT_new.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/crypto/ASN1_STRING_length.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/crypto/ASN1_STRING_new.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/crypto/ASN1_STRING_print_ex.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/crypto/ASN1_TIME_set.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/crypto/ASN1_TYPE_get.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/crypto/ASN1_generate_nconf.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/crypto/ASYNC_WAIT_CTX_new.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/crypto/ASYNC_start_job.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/crypto/BF_encrypt.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/crypto/BIO_ADDR.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/crypto/BIO_ADDRINFO.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/crypto/BIO_connect.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/crypto/BIO_ctrl.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/crypto/BIO_f_base64.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/crypto/BIO_f_buffer.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/crypto/BIO_f_cipher.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/crypto/BIO_f_md.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/crypto/BIO_f_null.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/crypto/BIO_f_ssl.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/crypto/BIO_find_type.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/crypto/BIO_get_data.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/crypto/BIO_get_ex_new_index.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/crypto/BIO_meth_new.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/crypto/BIO_new.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/crypto/BIO_new_CMS.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/crypto/BIO_parse_hostserv.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/crypto/BIO_push.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/crypto/BIO_read.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/crypto/BIO_s_accept.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/crypto/BIO_s_bio.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/crypto/BIO_s_connect.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/crypto/BIO_s_fd.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/crypto/BIO_s_file.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/crypto/BIO_s_mem.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/crypto/BIO_s_null.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/crypto/BIO_s_socket.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/crypto/BIO_set_callback.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/crypto/BIO_should_retry.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/crypto/BN_BLINDING_new.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/crypto/BN_CTX_new.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/crypto/BN_CTX_start.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/crypto/BN_add.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/crypto/BN_add_word.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/crypto/BN_bn2bin.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/crypto/BN_cmp.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/crypto/BN_copy.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/crypto/BN_generate_prime.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/crypto/BN_mod_inverse.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/crypto/BN_mod_mul_montgomery.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/crypto/BN_mod_mul_reciprocal.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/crypto/BN_new.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/crypto/BN_num_bytes.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/crypto/BN_rand.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/crypto/BN_set_bit.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/crypto/BN_swap.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/crypto/BN_zero.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/crypto/BUF_MEM_new.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/crypto/CMS_add0_cert.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/crypto/CMS_add1_recipient_cert.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/crypto/CMS_add1_signer.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/crypto/CMS_compress.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/crypto/CMS_decrypt.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/crypto/CMS_encrypt.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/crypto/CMS_final.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/crypto/CMS_get0_RecipientInfos.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/crypto/CMS_get0_SignerInfos.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/crypto/CMS_get0_type.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/crypto/CMS_get1_ReceiptRequest.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/crypto/CMS_sign.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/crypto/CMS_sign_receipt.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/crypto/CMS_uncompress.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/crypto/CMS_verify.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/crypto/CMS_verify_receipt.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/crypto/CONF_modules_free.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/crypto/CONF_modules_load_file.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/crypto/CRYPTO_THREAD_run_once.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/crypto/CRYPTO_get_ex_new_index.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/crypto/CTLOG_STORE_get0_log_by_id.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/crypto/CTLOG_STORE_new.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/crypto/CTLOG_new.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/crypto/CT_POLICY_EVAL_CTX_new.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/crypto/DEFINE_STACK_OF.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/crypto/DES_random_key.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/crypto/DH_generate_key.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/crypto/DH_generate_parameters.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/crypto/DH_get0_pqg.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/crypto/DH_get_1024_160.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/crypto/DH_meth_new.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/crypto/DH_new.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/crypto/DH_set_method.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/crypto/DH_size.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/crypto/DSA_SIG_new.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/crypto/DSA_do_sign.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/crypto/DSA_dup_DH.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/crypto/DSA_generate_key.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/crypto/DSA_generate_parameters.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/crypto/DSA_get0_pqg.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/crypto/DSA_meth_new.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/crypto/DSA_new.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/crypto/DSA_set_method.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/crypto/DSA_sign.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/crypto/DSA_size.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/crypto/ECDSA_SIG_new.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/crypto/ECPKParameters_print.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/crypto/EC_GFp_simple_method.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/crypto/EC_GROUP_copy.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/crypto/EC_GROUP_new.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/crypto/EC_KEY_get_enc_flags.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/crypto/EC_KEY_new.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/crypto/EC_POINT_add.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/crypto/EC_POINT_new.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/crypto/ENGINE_add.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/crypto/ERR_GET_LIB.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/crypto/ERR_clear_error.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/crypto/ERR_error_string.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/crypto/ERR_get_error.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/crypto/ERR_load_crypto_strings.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/crypto/ERR_load_strings.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/crypto/ERR_print_errors.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/crypto/ERR_put_error.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/crypto/ERR_remove_state.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/crypto/ERR_set_mark.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/crypto/EVP_BytesToKey.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/crypto/EVP_CIPHER_CTX_get_cipher_data.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/crypto/EVP_CIPHER_meth_new.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/crypto/EVP_DigestInit.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/crypto/EVP_DigestSignInit.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/crypto/EVP_DigestVerifyInit.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/crypto/EVP_EncodeInit.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/crypto/EVP_EncryptInit.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/crypto/EVP_MD_meth_new.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/crypto/EVP_OpenInit.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/crypto/EVP_PKEY_CTX_ctrl.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/crypto/EVP_PKEY_CTX_new.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/crypto/EVP_PKEY_CTX_set_hkdf_md.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/crypto/EVP_PKEY_CTX_set_tls1_prf_md.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/crypto/EVP_PKEY_cmp.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/crypto/EVP_PKEY_decrypt.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/crypto/EVP_PKEY_derive.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/crypto/EVP_PKEY_encrypt.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/crypto/EVP_PKEY_get_default_digest_nid.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/crypto/EVP_PKEY_keygen.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/crypto/EVP_PKEY_new.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/crypto/EVP_PKEY_print_private.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/crypto/EVP_PKEY_set1_RSA.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/crypto/EVP_PKEY_sign.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/crypto/EVP_PKEY_verify.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/crypto/EVP_PKEY_verify_recover.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/crypto/EVP_SealInit.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/crypto/EVP_SignInit.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/crypto/EVP_VerifyInit.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/crypto/HMAC.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/crypto/MD5.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/crypto/MDC2_Init.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/crypto/OBJ_nid2obj.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/crypto/OCSP_REQUEST_new.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/crypto/OCSP_cert_to_id.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/crypto/OCSP_request_add1_nonce.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/crypto/OCSP_resp_find_status.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/crypto/OCSP_response_status.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/crypto/OCSP_sendreq_new.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/crypto/OPENSSL_Applink.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/crypto/OPENSSL_LH_COMPFUNC.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/crypto/OPENSSL_LH_stats.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/crypto/OPENSSL_VERSION_NUMBER.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/crypto/OPENSSL_config.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/crypto/OPENSSL_ia32cap.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/crypto/OPENSSL_init_crypto.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/crypto/OPENSSL_instrument_bus.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/crypto/OPENSSL_load_builtin_modules.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/crypto/OPENSSL_malloc.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/crypto/OPENSSL_secure_malloc.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/crypto/OpenSSL_add_all_algorithms.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/crypto/PEM_read.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/crypto/PEM_read_CMS.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/crypto/PEM_read_bio_PrivateKey.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/crypto/PEM_write_bio_CMS_stream.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/crypto/PEM_write_bio_PKCS7_stream.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/crypto/PKCS12_create.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/crypto/PKCS12_newpass.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/crypto/PKCS12_parse.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/crypto/PKCS5_PBKDF2_HMAC.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/crypto/PKCS7_decrypt.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/crypto/PKCS7_encrypt.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/crypto/PKCS7_sign.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/crypto/PKCS7_sign_add_signer.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/crypto/PKCS7_verify.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/crypto/RAND_add.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/crypto/RAND_bytes.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/crypto/RAND_cleanup.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/crypto/RAND_egd.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/crypto/RAND_load_file.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/crypto/RAND_set_rand_method.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/crypto/RC4_set_key.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/crypto/RIPEMD160_Init.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/crypto/RSA_blinding_on.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/crypto/RSA_check_key.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/crypto/RSA_generate_key.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/crypto/RSA_get0_key.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/crypto/RSA_meth_new.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/crypto/RSA_new.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/crypto/RSA_padding_add_PKCS1_type_1.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/crypto/RSA_print.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/crypto/RSA_private_encrypt.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/crypto/RSA_public_encrypt.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/crypto/RSA_set_method.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/crypto/RSA_sign.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/crypto/RSA_sign_ASN1_OCTET_STRING.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/crypto/RSA_size.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/crypto/SCT_new.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/crypto/SCT_print.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/crypto/SCT_validate.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/crypto/SHA256_Init.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/crypto/SMIME_read_CMS.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/crypto/SMIME_read_PKCS7.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/crypto/SMIME_write_CMS.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/crypto/SMIME_write_PKCS7.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/crypto/SSL_set_bio.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/crypto/UI_new.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/crypto/X509V3_get_d2i.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/crypto/X509_ALGOR_dup.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/crypto/X509_CRL_get0_by_serial.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/crypto/X509_EXTENSION_set_object.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/crypto/X509_LOOKUP_hash_dir.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/crypto/X509_NAME_ENTRY_get_object.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/crypto/X509_NAME_add_entry_by_txt.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/crypto/X509_NAME_get0_der.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/crypto/X509_NAME_get_index_by_NID.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/crypto/X509_NAME_print_ex.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/crypto/X509_PUBKEY_new.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/crypto/X509_SIG_get0.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/crypto/X509_STORE_CTX_get_error.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/crypto/X509_STORE_CTX_new.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/crypto/X509_STORE_CTX_set_verify_cb.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/crypto/X509_STORE_get0_param.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/crypto/X509_STORE_new.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/crypto/X509_STORE_set_verify_cb_func.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/crypto/X509_VERIFY_PARAM_set_flags.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/crypto/X509_check_ca.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/crypto/X509_check_host.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/crypto/X509_check_issued.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/crypto/X509_digest.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/crypto/X509_dup.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/crypto/X509_get0_signature.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/crypto/X509_get0_uids.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/crypto/X509_get_extension_flags.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/crypto/X509_get_notBefore.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/crypto/X509_get_pubkey.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/crypto/X509_get_serialNumber.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/crypto/X509_get_subject_name.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/crypto/X509_get_version.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/crypto/X509_new.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/crypto/X509_sign.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/crypto/X509_verify_cert.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/crypto/X509v3_get_ext_by_NID.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/crypto/bio.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/crypto/crypto.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/crypto/ct.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/crypto/d2i_DHparams.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/crypto/d2i_Netscape_RSA.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/crypto/d2i_PKCS8PrivateKey_bio.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/crypto/d2i_PrivateKey.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/crypto/d2i_X509.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/crypto/des_modes.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/crypto/evp.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/crypto/i2d_CMS_bio_stream.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/crypto/i2d_PKCS7_bio_stream.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/crypto/i2d_re_X509_tbs.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/crypto/o2i_SCT_LIST.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/crypto/x509.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/dir-locals.example.el + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/fingerprints.txt + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/openssl-c-indent.el + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/ssl/DTLSv1_listen.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/ssl/OPENSSL_init_ssl.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/ssl/SSL_CIPHER_get_name.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/ssl/SSL_COMP_add_compression_method.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/ssl/SSL_CONF_CTX_new.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/ssl/SSL_CONF_CTX_set1_prefix.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/ssl/SSL_CONF_CTX_set_flags.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/ssl/SSL_CONF_CTX_set_ssl_ctx.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/ssl/SSL_CONF_cmd.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/ssl/SSL_CONF_cmd_argv.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/ssl/SSL_CTX_add1_chain_cert.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/ssl/SSL_CTX_add_extra_chain_cert.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/ssl/SSL_CTX_add_session.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/ssl/SSL_CTX_config.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/ssl/SSL_CTX_ctrl.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/ssl/SSL_CTX_dane_enable.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/ssl/SSL_CTX_flush_sessions.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/ssl/SSL_CTX_free.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/ssl/SSL_CTX_get0_param.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/ssl/SSL_CTX_get_verify_mode.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/ssl/SSL_CTX_has_client_custom_ext.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/ssl/SSL_CTX_load_verify_locations.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/ssl/SSL_CTX_new.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/ssl/SSL_CTX_sess_number.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/ssl/SSL_CTX_sess_set_cache_size.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/ssl/SSL_CTX_sess_set_get_cb.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/ssl/SSL_CTX_sessions.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/ssl/SSL_CTX_set1_curves.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/ssl/SSL_CTX_set1_sigalgs.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/ssl/SSL_CTX_set1_verify_cert_store.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/ssl/SSL_CTX_set_alpn_select_cb.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/ssl/SSL_CTX_set_cert_cb.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/ssl/SSL_CTX_set_cert_store.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/ssl/SSL_CTX_set_cert_verify_callback.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/ssl/SSL_CTX_set_cipher_list.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/ssl/SSL_CTX_set_client_CA_list.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/ssl/SSL_CTX_set_client_cert_cb.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/ssl/SSL_CTX_set_ct_validation_callback.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/ssl/SSL_CTX_set_ctlog_list_file.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/ssl/SSL_CTX_set_default_passwd_cb.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/ssl/SSL_CTX_set_generate_session_id.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/ssl/SSL_CTX_set_info_callback.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/ssl/SSL_CTX_set_max_cert_list.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/ssl/SSL_CTX_set_min_proto_version.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/ssl/SSL_CTX_set_mode.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/ssl/SSL_CTX_set_msg_callback.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/ssl/SSL_CTX_set_options.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/ssl/SSL_CTX_set_psk_client_callback.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/ssl/SSL_CTX_set_quiet_shutdown.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/ssl/SSL_CTX_set_read_ahead.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/ssl/SSL_CTX_set_security_level.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/ssl/SSL_CTX_set_session_cache_mode.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/ssl/SSL_CTX_set_session_id_context.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/ssl/SSL_CTX_set_split_send_fragment.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/ssl/SSL_CTX_set_ssl_version.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/ssl/SSL_CTX_set_timeout.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/ssl/SSL_CTX_set_tlsext_status_cb.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/ssl/SSL_CTX_set_tlsext_ticket_key_cb.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/ssl/SSL_CTX_set_tmp_dh_callback.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/ssl/SSL_CTX_set_verify.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/ssl/SSL_CTX_use_certificate.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/ssl/SSL_CTX_use_psk_identity_hint.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/ssl/SSL_CTX_use_serverinfo.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/ssl/SSL_SESSION_free.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/ssl/SSL_SESSION_get0_cipher.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/ssl/SSL_SESSION_get0_hostname.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/ssl/SSL_SESSION_get0_id_context.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/ssl/SSL_SESSION_get_protocol_version.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/ssl/SSL_SESSION_get_time.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/ssl/SSL_SESSION_has_ticket.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/ssl/SSL_SESSION_set1_id.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/ssl/SSL_accept.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/ssl/SSL_alert_type_string.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/ssl/SSL_check_chain.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/ssl/SSL_clear.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/ssl/SSL_connect.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/ssl/SSL_do_handshake.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/ssl/SSL_extension_supported.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/ssl/SSL_free.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/ssl/SSL_get0_peer_scts.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/ssl/SSL_get_SSL_CTX.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/ssl/SSL_get_all_async_fds.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/ssl/SSL_get_ciphers.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/ssl/SSL_get_client_CA_list.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/ssl/SSL_get_client_random.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/ssl/SSL_get_current_cipher.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/ssl/SSL_get_default_timeout.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/ssl/SSL_get_error.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/ssl/SSL_get_extms_support.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/ssl/SSL_get_fd.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/ssl/SSL_get_peer_cert_chain.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/ssl/SSL_get_peer_certificate.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/ssl/SSL_get_psk_identity.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/ssl/SSL_get_rbio.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/ssl/SSL_get_session.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/ssl/SSL_get_shared_sigalgs.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/ssl/SSL_get_verify_result.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/ssl/SSL_get_version.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/ssl/SSL_library_init.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/ssl/SSL_load_client_CA_file.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/ssl/SSL_new.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/ssl/SSL_pending.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/ssl/SSL_read.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/ssl/SSL_rstate_string.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/ssl/SSL_session_reused.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/ssl/SSL_set1_host.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/ssl/SSL_set_bio.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/ssl/SSL_set_connect_state.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/ssl/SSL_set_fd.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/ssl/SSL_set_session.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/ssl/SSL_set_shutdown.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/ssl/SSL_set_verify_result.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/ssl/SSL_shutdown.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/ssl/SSL_state_string.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/ssl/SSL_want.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/ssl/SSL_write.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/ssl/d2i_SSL_SESSION.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/doc/ssl/ssl.pod + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/e_os.h + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/engines/afalg/build.info + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/engines/afalg/e_afalg.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/engines/afalg/e_afalg.ec + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/engines/afalg/e_afalg.h + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/engines/afalg/e_afalg_err.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/engines/afalg/e_afalg_err.h + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/engines/asm/e_padlock-x86.pl + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/engines/asm/e_padlock-x86_64.pl + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/engines/build.info + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/engines/e_capi.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/engines/e_capi.ec + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/engines/e_capi_err.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/engines/e_capi_err.h + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/engines/e_chil.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/engines/e_chil.ec + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/engines/e_chil_err.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/engines/e_chil_err.h + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/engines/e_dasync.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/engines/e_dasync.ec + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/engines/e_dasync_err.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/engines/e_dasync_err.h + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/engines/e_ossltest.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/engines/e_ossltest.ec + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/engines/e_ossltest_err.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/engines/e_ossltest_err.h + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/engines/e_padlock.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/engines/e_padlock.ec + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/engines/engine_vector.mar + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/engines/vendor_defns/hwcryptohook.h + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/external/perl/Downloaded.txt + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/external/perl/Text-Template-1.46/Artistic + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/external/perl/Text-Template-1.46/COPYING + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/external/perl/Text-Template-1.46/INSTALL + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/external/perl/Text-Template-1.46/MANIFEST + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/external/perl/Text-Template-1.46/META.json + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/external/perl/Text-Template-1.46/META.yml + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/external/perl/Text-Template-1.46/Makefile.PL + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/external/perl/Text-Template-1.46/README + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/external/perl/Text-Template-1.46/lib/Text/Template.pm + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/external/perl/Text-Template-1.46/lib/Text/Template/Preprocess.pm + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/external/perl/Text-Template-1.46/t/00-version.t + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/external/perl/Text-Template-1.46/t/01-basic.t + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/external/perl/Text-Template-1.46/t/02-hash.t + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/external/perl/Text-Template-1.46/t/03-out.t + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/external/perl/Text-Template-1.46/t/04-safe.t + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/external/perl/Text-Template-1.46/t/05-safe2.t + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/external/perl/Text-Template-1.46/t/06-ofh.t + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/external/perl/Text-Template-1.46/t/07-safe3.t + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/external/perl/Text-Template-1.46/t/08-exported.t + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/external/perl/Text-Template-1.46/t/09-error.t + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/external/perl/Text-Template-1.46/t/10-delimiters.t + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/external/perl/Text-Template-1.46/t/11-prepend.t + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/external/perl/Text-Template-1.46/t/12-preprocess.t + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/external/perl/Text-Template-1.46/t/13-taint.t + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/external/perl/Text-Template-1.46/t/14-broken.t + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/external/perl/transfer/Text/Template.pm + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/fuzz/README.md + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/fuzz/asn1.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/fuzz/asn1parse.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/fuzz/bignum.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/fuzz/bndiv.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/fuzz/build.info + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/fuzz/cms.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/fuzz/conf.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/fuzz/crl.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/fuzz/ct.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/fuzz/driver.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/fuzz/fuzzer.h + create mode 100755 CryptoPkg/Library/OpensslLib/openssl/fuzz/helper.py + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/fuzz/server.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/fuzz/test-corpus.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/fuzz/x509.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/include/internal/bio.h + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/include/internal/comp.h + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/include/internal/conf.h + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/include/internal/constant_time_locl.h + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/include/internal/dane.h + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/include/internal/dso.h + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/include/internal/err.h + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/include/internal/numbers.h + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/include/internal/o_dir.h + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/include/internal/o_str.h + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/include/internal/thread_once.h + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/include/openssl/__DECC_INCLUDE_EPILOGUE.H + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/include/openssl/__DECC_INCLUDE_PROLOGUE.H + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/include/openssl/aes.h + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/include/openssl/asn1.h + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/include/openssl/asn1t.h + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/include/openssl/async.h + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/include/openssl/bio.h + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/include/openssl/blowfish.h + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/include/openssl/bn.h + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/include/openssl/buffer.h + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/include/openssl/camellia.h + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/include/openssl/cast.h + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/include/openssl/cmac.h + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/include/openssl/cms.h + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/include/openssl/comp.h + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/include/openssl/conf.h + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/include/openssl/conf_api.h + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/include/openssl/crypto.h + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/include/openssl/ct.h + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/include/openssl/des.h + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/include/openssl/dh.h + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/include/openssl/dsa.h + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/include/openssl/dtls1.h + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/include/openssl/e_os2.h + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/include/openssl/ebcdic.h + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/include/openssl/ec.h + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/include/openssl/ecdh.h + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/include/openssl/ecdsa.h + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/include/openssl/engine.h + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/include/openssl/err.h + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/include/openssl/evp.h + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/include/openssl/hmac.h + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/include/openssl/idea.h + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/include/openssl/kdf.h + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/include/openssl/lhash.h + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/include/openssl/md2.h + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/include/openssl/md4.h + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/include/openssl/md5.h + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/include/openssl/mdc2.h + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/include/openssl/modes.h + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/include/openssl/obj_mac.h + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/include/openssl/objects.h + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/include/openssl/ocsp.h + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/include/openssl/opensslconf.h.in + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/include/openssl/opensslv.h + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/include/openssl/ossl_typ.h + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/include/openssl/pem.h + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/include/openssl/pem2.h + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/include/openssl/pkcs12.h + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/include/openssl/pkcs7.h + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/include/openssl/rand.h + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/include/openssl/rc2.h + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/include/openssl/rc4.h + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/include/openssl/rc5.h + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/include/openssl/ripemd.h + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/include/openssl/rsa.h + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/include/openssl/safestack.h + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/include/openssl/seed.h + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/include/openssl/sha.h + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/include/openssl/srp.h + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/include/openssl/srtp.h + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/include/openssl/ssl.h + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/include/openssl/ssl2.h + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/include/openssl/ssl3.h + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/include/openssl/stack.h + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/include/openssl/symhacks.h + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/include/openssl/tls1.h + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/include/openssl/ts.h + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/include/openssl/txt_db.h + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/include/openssl/ui.h + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/include/openssl/whrlpool.h + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/include/openssl/x509.h + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/include/openssl/x509_vfy.h + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/include/openssl/x509v3.h + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/ms/applink.c + create mode 100755 CryptoPkg/Library/OpensslLib/openssl/ms/cmp.pl + create mode 100755 CryptoPkg/Library/OpensslLib/openssl/ms/segrenam.pl + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/ms/tlhelp32.h + create mode 100755 CryptoPkg/Library/OpensslLib/openssl/ms/uplink-common.pl + create mode 100755 CryptoPkg/Library/OpensslLib/openssl/ms/uplink-ia64.pl + create mode 100755 CryptoPkg/Library/OpensslLib/openssl/ms/uplink-x86.pl + create mode 100755 CryptoPkg/Library/OpensslLib/openssl/ms/uplink-x86_64.pl + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/ms/uplink.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/ms/uplink.h + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/os-dep/haiku.h + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/ssl/bio_ssl.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/ssl/build.info + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/ssl/d1_lib.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/ssl/d1_msg.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/ssl/d1_srtp.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/ssl/methods.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/ssl/packet_locl.h + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/ssl/pqueue.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/ssl/record/README + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/ssl/record/dtls1_bitmap.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/ssl/record/rec_layer_d1.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/ssl/record/rec_layer_s3.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/ssl/record/record.h + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/ssl/record/record_locl.h + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/ssl/record/ssl3_buffer.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/ssl/record/ssl3_record.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/ssl/s3_cbc.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/ssl/s3_enc.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/ssl/s3_lib.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/ssl/s3_msg.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/ssl/ssl_asn1.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/ssl/ssl_cert.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/ssl/ssl_ciph.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/ssl/ssl_conf.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/ssl/ssl_err.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/ssl/ssl_init.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/ssl/ssl_lib.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/ssl/ssl_locl.h + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/ssl/ssl_mcnf.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/ssl/ssl_rsa.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/ssl/ssl_sess.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/ssl/ssl_stat.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/ssl/ssl_txt.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/ssl/ssl_utst.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/ssl/statem/README + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/ssl/statem/statem.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/ssl/statem/statem.h + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/ssl/statem/statem_clnt.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/ssl/statem/statem_dtls.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/ssl/statem/statem_lib.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/ssl/statem/statem_locl.h + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/ssl/statem/statem_srvr.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/ssl/t1_enc.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/ssl/t1_ext.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/ssl/t1_lib.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/ssl/t1_reneg.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/ssl/t1_trce.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/ssl/tls_srp.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/CAss.cnf + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/CAssdh.cnf + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/CAssdsa.cnf + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/CAssrsa.cnf + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/CAtsa.cnf + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/P1ss.cnf + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/P2ss.cnf + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/README + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/README.ssltest.md + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/Sssdsa.cnf + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/Sssrsa.cnf + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/Uss.cnf + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/aborttest.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/afalgtest.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/asynciotest.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/asynctest.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/bad_dtls_test.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/bftest.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/bio_enc_test.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/bioprinttest.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/bntest.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/build.info + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/casttest.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/certs/alt1-cert.pem + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/certs/alt1-key.pem + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/certs/alt2-cert.pem + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/certs/alt2-key.pem + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/certs/alt3-cert.pem + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/certs/alt3-key.pem + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/certs/bad-pc3-cert.pem + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/certs/bad-pc3-key.pem + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/certs/bad-pc4-cert.pem + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/certs/bad-pc4-key.pem + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/certs/bad-pc6-cert.pem + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/certs/bad-pc6-key.pem + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/certs/bad.key + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/certs/bad.pem + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/certs/badalt1-cert.pem + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/certs/badalt1-key.pem + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/certs/badalt10-cert.pem + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/certs/badalt10-key.pem + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/certs/badalt2-cert.pem + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/certs/badalt2-key.pem + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/certs/badalt3-cert.pem + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/certs/badalt3-key.pem + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/certs/badalt4-cert.pem + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/certs/badalt4-key.pem + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/certs/badalt5-cert.pem + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/certs/badalt5-key.pem + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/certs/badalt6-cert.pem + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/certs/badalt6-key.pem + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/certs/badalt7-cert.pem + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/certs/badalt7-key.pem + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/certs/badalt8-cert.pem + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/certs/badalt8-key.pem + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/certs/badalt9-cert.pem + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/certs/badalt9-key.pem + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/certs/ca+anyEKU.pem + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/certs/ca+clientAuth.pem + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/certs/ca+serverAuth.pem + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/certs/ca-anyEKU.pem + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/certs/ca-cert-768.pem + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/certs/ca-cert-768i.pem + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/certs/ca-cert-md5-any.pem + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/certs/ca-cert-md5.pem + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/certs/ca-cert.pem + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/certs/ca-cert2.pem + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/certs/ca-clientAuth.pem + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/certs/ca-expired.pem + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/certs/ca-key-768.pem + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/certs/ca-key.pem + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/certs/ca-key2.pem + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/certs/ca-name2.pem + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/certs/ca-nonbc.pem + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/certs/ca-nonca.pem + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/certs/ca-root2.pem + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/certs/ca-serverAuth.pem + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/certs/cca+anyEKU.pem + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/certs/cca+clientAuth.pem + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/certs/cca+serverAuth.pem + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/certs/cca-anyEKU.pem + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/certs/cca-cert.pem + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/certs/cca-clientAuth.pem + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/certs/cca-serverAuth.pem + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/certs/croot+anyEKU.pem + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/certs/croot+clientAuth.pem + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/certs/croot+serverAuth.pem + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/certs/croot-anyEKU.pem + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/certs/croot-cert.pem + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/certs/croot-clientAuth.pem + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/certs/croot-serverAuth.pem + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/certs/ee+clientAuth.pem + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/certs/ee+serverAuth.pem + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/certs/ee-cert-768.pem + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/certs/ee-cert-768i.pem + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/certs/ee-cert-md5.pem + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/certs/ee-cert.pem + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/certs/ee-cert2.pem + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/certs/ee-client-chain.pem + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/certs/ee-client.pem + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/certs/ee-clientAuth.pem + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/certs/ee-expired.pem + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/certs/ee-key-768.pem + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/certs/ee-key.pem + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/certs/ee-name2.pem + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/certs/ee-serverAuth.pem + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/certs/embeddedSCTs1.pem + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/certs/embeddedSCTs1.sct + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/certs/embeddedSCTs1_issuer.pem + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/certs/embeddedSCTs3.pem + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/certs/embeddedSCTs3.sct + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/certs/embeddedSCTs3_issuer.pem + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/certs/interCA.key + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/certs/interCA.pem + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/certs/leaf.key + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/certs/leaf.pem + create mode 100755 CryptoPkg/Library/OpensslLib/openssl/test/certs/mkcert.sh + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/certs/nca+anyEKU.pem + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/certs/nca+serverAuth.pem + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/certs/ncca-cert.pem + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/certs/ncca-key.pem + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/certs/ncca1-cert.pem + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/certs/ncca1-key.pem + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/certs/ncca2-cert.pem + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/certs/ncca2-key.pem + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/certs/ncca3-cert.pem + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/certs/ncca3-key.pem + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/certs/nroot+anyEKU.pem + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/certs/nroot+serverAuth.pem + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/certs/pathlen.pem + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/certs/pc1-cert.pem + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/certs/pc1-key.pem + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/certs/pc2-cert.pem + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/certs/pc2-key.pem + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/certs/pc5-cert.pem + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/certs/pc5-key.pem + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/certs/root+anyEKU.pem + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/certs/root+clientAuth.pem + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/certs/root+serverAuth.pem + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/certs/root-anyEKU.pem + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/certs/root-cert-768.pem + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/certs/root-cert-md5.pem + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/certs/root-cert.pem + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/certs/root-cert2.pem + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/certs/root-clientAuth.pem + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/certs/root-key-768.pem + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/certs/root-key.pem + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/certs/root-key2.pem + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/certs/root-name2.pem + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/certs/root-nonca.pem + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/certs/root-noserver.pem + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/certs/root-serverAuth.pem + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/certs/root2+clientAuth.pem + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/certs/root2+serverAuth.pem + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/certs/root2-serverAuth.pem + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/certs/rootCA.key + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/certs/rootCA.pem + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/certs/rootcert.pem + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/certs/rootkey.pem + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/certs/roots.pem + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/certs/sca+anyEKU.pem + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/certs/sca+clientAuth.pem + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/certs/sca+serverAuth.pem + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/certs/sca-anyEKU.pem + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/certs/sca-cert.pem + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/certs/sca-clientAuth.pem + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/certs/sca-serverAuth.pem + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/certs/server-trusted.pem + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/certs/servercert.pem + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/certs/serverkey.pem + create mode 100755 CryptoPkg/Library/OpensslLib/openssl/test/certs/setup.sh + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/certs/sroot+anyEKU.pem + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/certs/sroot+clientAuth.pem + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/certs/sroot+serverAuth.pem + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/certs/sroot-anyEKU.pem + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/certs/sroot-cert.pem + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/certs/sroot-clientAuth.pem + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/certs/sroot-serverAuth.pem + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/certs/subinterCA-ss.pem + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/certs/subinterCA.key + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/certs/subinterCA.pem + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/certs/untrusted.pem + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/certs/wrongcert.pem + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/certs/wrongkey.pem + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/cipherlist_test.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/clienthellotest.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/cms-examples.pl + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/constant_time_test.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/crltest.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/ct/log_list.conf + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/ct/tls1.sct + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/ct_test.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/d2i-tests/bad-cms.der + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/d2i-tests/bad-int-pad0.der + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/d2i-tests/bad-int-padminus1.der + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/d2i-tests/bad_bio.der + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/d2i-tests/bad_cert.der + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/d2i-tests/bad_generalname.der + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/d2i-tests/high_tag.der + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/d2i-tests/int0.der + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/d2i-tests/int1.der + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/d2i-tests/intminus1.der + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/d2i_test.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/danetest.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/danetest.in + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/danetest.pem + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/destest.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/dhtest.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/dsatest.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/dtlstest.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/dtlsv1listentest.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/ecdhtest.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/ecdhtest_cavs.h + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/ecdsatest.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/ectest.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/enginetest.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/evp_extra_test.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/evp_test.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/evptests.txt + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/exdatatest.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/exptest.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/generate_buildtest.pl + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/generate_ssl_tests.pl + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/gmdifftest.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/handshake_helper.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/handshake_helper.h + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/heartbeat_test.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/hmactest.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/ideatest.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/igetest.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/md2test.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/md4test.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/md5test.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/mdc2test.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/memleaktest.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/methtest.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/ocsp-tests/D1.ors + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/ocsp-tests/D1_Cert_EE.pem + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/ocsp-tests/D1_Issuer_ICA.pem + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/ocsp-tests/D2.ors + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/ocsp-tests/D2_Cert_ICA.pem + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/ocsp-tests/D2_Issuer_Root.pem + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/ocsp-tests/D3.ors + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/ocsp-tests/D3_Cert_EE.pem + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/ocsp-tests/D3_Issuer_Root.pem + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/ocsp-tests/ISDOSC_D1.ors + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/ocsp-tests/ISDOSC_D2.ors + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/ocsp-tests/ISDOSC_D3.ors + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/ocsp-tests/ISIC_D1_Issuer_ICA.pem + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/ocsp-tests/ISIC_D2_Issuer_Root.pem + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/ocsp-tests/ISIC_D3_Issuer_Root.pem + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/ocsp-tests/ISIC_ND1_Issuer_ICA.pem + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/ocsp-tests/ISIC_ND2_Issuer_Root.pem + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/ocsp-tests/ISIC_ND3_Issuer_Root.pem + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/ocsp-tests/ISOP_D1.ors + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/ocsp-tests/ISOP_D2.ors + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/ocsp-tests/ISOP_D3.ors + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/ocsp-tests/ISOP_ND1.ors + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/ocsp-tests/ISOP_ND2.ors + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/ocsp-tests/ISOP_ND3.ors + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/ocsp-tests/ND1.ors + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/ocsp-tests/ND1_Cert_EE.pem + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/ocsp-tests/ND1_Issuer_ICA.pem + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/ocsp-tests/ND2.ors + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/ocsp-tests/ND2_Cert_ICA.pem + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/ocsp-tests/ND2_Issuer_Root.pem + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/ocsp-tests/ND3.ors + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/ocsp-tests/ND3_Cert_EE.pem + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/ocsp-tests/ND3_Issuer_Root.pem + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/ocsp-tests/WIKH_D1.ors + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/ocsp-tests/WIKH_D2.ors + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/ocsp-tests/WIKH_D3.ors + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/ocsp-tests/WIKH_ND1.ors + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/ocsp-tests/WIKH_ND2.ors + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/ocsp-tests/WIKH_ND3.ors + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/ocsp-tests/WINH_D1.ors + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/ocsp-tests/WINH_D2.ors + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/ocsp-tests/WINH_D3.ors + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/ocsp-tests/WINH_ND1.ors + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/ocsp-tests/WINH_ND2.ors + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/ocsp-tests/WINH_ND3.ors + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/ocsp-tests/WKDOSC_D1.ors + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/ocsp-tests/WKDOSC_D2.ors + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/ocsp-tests/WKDOSC_D3.ors + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/ocsp-tests/WKIC_D1_Issuer_ICA.pem + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/ocsp-tests/WKIC_D2_Issuer_Root.pem + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/ocsp-tests/WKIC_D3_Issuer_Root.pem + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/ocsp-tests/WKIC_ND1_Issuer_ICA.pem + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/ocsp-tests/WKIC_ND2_Issuer_Root.pem + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/ocsp-tests/WKIC_ND3_Issuer_Root.pem + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/ocsp-tests/WRID_D1.ors + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/ocsp-tests/WRID_D2.ors + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/ocsp-tests/WRID_D3.ors + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/ocsp-tests/WRID_ND1.ors + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/ocsp-tests/WRID_ND2.ors + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/ocsp-tests/WRID_ND3.ors + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/ocsp-tests/WSNIC_D1_Issuer_ICA.pem + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/ocsp-tests/WSNIC_D2_Issuer_Root.pem + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/ocsp-tests/WSNIC_D3_Issuer_Root.pem + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/ocsp-tests/WSNIC_ND1_Issuer_ICA.pem + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/ocsp-tests/WSNIC_ND2_Issuer_Root.pem + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/ocsp-tests/WSNIC_ND3_Issuer_Root.pem + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/p5_crpt2_test.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/packettest.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/pbelutest.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/pkcs7-1.pem + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/pkcs7.pem + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/pkits-test.pl + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/r160test.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/randtest.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/rc2test.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/rc4test.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/rc5test.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/recipes/01-test_abort.t + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/recipes/01-test_sanity.t + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/recipes/01-test_symbol_presence.t + create mode 100755 CryptoPkg/Library/OpensslLib/openssl/test/recipes/02-test_ordinals.t + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/recipes/03-test_ui.t + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/recipes/05-test_bf.t + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/recipes/05-test_cast.t + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/recipes/05-test_des.t + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/recipes/05-test_hmac.t + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/recipes/05-test_idea.t + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/recipes/05-test_md2.t + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/recipes/05-test_md4.t + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/recipes/05-test_md5.t + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/recipes/05-test_mdc2.t + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/recipes/05-test_rand.t + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/recipes/05-test_rc2.t + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/recipes/05-test_rc4.t + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/recipes/05-test_rc5.t + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/recipes/05-test_rmd.t + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/recipes/05-test_sha1.t + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/recipes/05-test_sha256.t + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/recipes/05-test_sha512.t + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/recipes/05-test_wp.t + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/recipes/10-test_bn.t + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/recipes/10-test_exp.t + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/recipes/15-test_dh.t + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/recipes/15-test_dsa.t + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/recipes/15-test_ec.t + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/recipes/15-test_ecdh.t + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/recipes/15-test_ecdsa.t + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/recipes/15-test_rsa.t + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/recipes/20-test_enc.t + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/recipes/20-test_passwd.t + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/recipes/25-test_crl.t + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/recipes/25-test_d2i.t + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/recipes/25-test_pkcs7.t + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/recipes/25-test_req.t + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/recipes/25-test_sid.t + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/recipes/25-test_verify.t + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/recipes/25-test_x509.t + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/recipes/30-test_afalg.t + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/recipes/30-test_engine.t + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/recipes/30-test_evp.t + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/recipes/30-test_evp_extra.t + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/recipes/30-test_pbelu.t + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/recipes/40-test_rehash.t + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/recipes/70-test_asyncio.t + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/recipes/70-test_bad_dtls.t + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/recipes/70-test_clienthello.t + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/recipes/70-test_packet.t + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/recipes/70-test_sslcbcpadding.t + create mode 100755 CryptoPkg/Library/OpensslLib/openssl/test/recipes/70-test_sslcertstatus.t + create mode 100755 CryptoPkg/Library/OpensslLib/openssl/test/recipes/70-test_sslextension.t + create mode 100755 CryptoPkg/Library/OpensslLib/openssl/test/recipes/70-test_sslmessages.t + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/recipes/70-test_sslrecords.t + create mode 100755 CryptoPkg/Library/OpensslLib/openssl/test/recipes/70-test_sslsessiontick.t + create mode 100755 CryptoPkg/Library/OpensslLib/openssl/test/recipes/70-test_sslskewith0p.t + create mode 100755 CryptoPkg/Library/OpensslLib/openssl/test/recipes/70-test_sslvertol.t + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/recipes/70-test_tlsextms.t + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/recipes/70-test_verify_extra.t + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/recipes/80-test_ca.t + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/recipes/80-test_cipherlist.t + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/recipes/80-test_cms.t + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/recipes/80-test_ct.t + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/recipes/80-test_dane.t + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/recipes/80-test_dtls.t + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/recipes/80-test_dtlsv1listen.t + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/recipes/80-test_ocsp.t + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/recipes/80-test_pkcs12.t + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/recipes/80-test_ssl_new.t + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/recipes/80-test_ssl_old.t + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/recipes/80-test_ssl_test_ctx.t + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/recipes/80-test_sslcorrupt.t + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/recipes/80-test_tsa.t + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/recipes/80-test_x509aux.t + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/recipes/90-test_async.t + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/recipes/90-test_bio_enc.t + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/recipes/90-test_bioprint.t + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/recipes/90-test_constant_time.t + create mode 100755 CryptoPkg/Library/OpensslLib/openssl/test/recipes/90-test_fuzz.t + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/recipes/90-test_gmdiff.t + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/recipes/90-test_heartbeat.t + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/recipes/90-test_ige.t + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/recipes/90-test_memleak.t + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/recipes/90-test_p5_crpt2.t + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/recipes/90-test_secmem.t + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/recipes/90-test_shlibload.t + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/recipes/90-test_srp.t + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/recipes/90-test_sslapi.t + create mode 100755 CryptoPkg/Library/OpensslLib/openssl/test/recipes/90-test_threads.t + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/recipes/90-test_v3name.t + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/recipes/bc.pl + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/recipes/tconversion.pl + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/rmdtest.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/rsa_test.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/run_tests.pl + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/sanitytest.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/secmemtest.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/serverinfo.pem + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/sha1test.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/sha256t.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/sha512t.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/shibboleth.pfx + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/shlibloadtest.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/smcont.txt + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/smime-certs/ca.cnf + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/smime-certs/mksmime-certs.sh + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/smime-certs/smdh.pem + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/smime-certs/smdsa1.pem + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/smime-certs/smdsa2.pem + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/smime-certs/smdsa3.pem + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/smime-certs/smdsap.pem + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/smime-certs/smec1.pem + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/smime-certs/smec2.pem + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/smime-certs/smroot.pem + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/smime-certs/smrsa1.pem + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/smime-certs/smrsa2.pem + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/smime-certs/smrsa3.pem + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/srptest.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/ssl-tests/01-simple.conf + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/ssl-tests/01-simple.conf.in + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/ssl-tests/02-protocol-version.conf + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/ssl-tests/02-protocol-version.conf.in + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/ssl-tests/03-custom_verify.conf + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/ssl-tests/03-custom_verify.conf.in + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/ssl-tests/04-client_auth.conf + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/ssl-tests/04-client_auth.conf.in + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/ssl-tests/05-sni.conf + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/ssl-tests/05-sni.conf.in + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/ssl-tests/06-sni-ticket.conf + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/ssl-tests/06-sni-ticket.conf.in + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/ssl-tests/07-dtls-protocol-version.conf + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/ssl-tests/07-dtls-protocol-version.conf.in + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/ssl-tests/08-npn.conf + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/ssl-tests/08-npn.conf.in + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/ssl-tests/09-alpn.conf + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/ssl-tests/09-alpn.conf.in + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/ssl-tests/10-resumption.conf + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/ssl-tests/10-resumption.conf.in + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/ssl-tests/11-dtls_resumption.conf + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/ssl-tests/11-dtls_resumption.conf.in + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/ssl-tests/12-ct.conf + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/ssl-tests/12-ct.conf.in + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/ssl-tests/13-fragmentation.conf + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/ssl-tests/13-fragmentation.conf.in + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/ssl-tests/14-curves.conf + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/ssl-tests/14-curves.conf.in + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/ssl-tests/15-certstatus.conf + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/ssl-tests/15-certstatus.conf.in + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/ssl-tests/16-certstatus.conf + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/ssl-tests/16-dtls-certstatus.conf + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/ssl-tests/16-dtls-certstatus.conf.in + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/ssl-tests/17-renegotiate.conf + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/ssl-tests/17-renegotiate.conf.in + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/ssl-tests/18-dtls-renegotiate.conf + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/ssl-tests/18-dtls-renegotiate.conf.in + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/ssl-tests/protocol_version.pm + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/ssl-tests/ssltests_base.pm + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/ssl_test.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/ssl_test.tmpl + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/ssl_test_ctx.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/ssl_test_ctx.h + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/ssl_test_ctx_test.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/ssl_test_ctx_test.conf + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/sslapitest.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/sslcorrupttest.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/ssltest_old.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/ssltestlib.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/ssltestlib.h + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/test.cnf + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/testlib/OpenSSL/Test.pm + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/testlib/OpenSSL/Test/Simple.pm + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/testlib/OpenSSL/Test/Utils.pm + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/testutil.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/testutil.h + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/threadstest.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/v3-cert1.pem + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/v3-cert2.pem + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/v3ext.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/v3nametest.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/verify_extra_test.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/wp_test.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/x509aux.c + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/tools/build.info + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/tools/c_rehash.in + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/util/TLSProxy/ClientHello.pm + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/util/TLSProxy/Message.pm + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/util/TLSProxy/NewSessionTicket.pm + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/util/TLSProxy/Proxy.pm + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/util/TLSProxy/Record.pm + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/util/TLSProxy/ServerHello.pm + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/util/TLSProxy/ServerKeyExchange.pm + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/util/build.info + create mode 100755 CryptoPkg/Library/OpensslLib/openssl/util/ck_errf.pl + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/util/copy.pl + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/util/dofile.pl + create mode 100755 CryptoPkg/Library/OpensslLib/openssl/util/find-doc-nits.pl + create mode 100755 CryptoPkg/Library/OpensslLib/openssl/util/find-undoc-api.pl + create mode 100755 CryptoPkg/Library/OpensslLib/openssl/util/find-unused-errs + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/util/fipslink.pl + create mode 100755 CryptoPkg/Library/OpensslLib/openssl/util/incore + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/util/indent.pro + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/util/libcrypto.num + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/util/libssl.num + create mode 100755 CryptoPkg/Library/OpensslLib/openssl/util/mkbuildinf.pl + create mode 100755 CryptoPkg/Library/OpensslLib/openssl/util/mkcerts.sh + create mode 100755 CryptoPkg/Library/OpensslLib/openssl/util/mkdef.pl + create mode 100755 CryptoPkg/Library/OpensslLib/openssl/util/mkdir-p.pl + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/util/mkerr.pl + create mode 100755 CryptoPkg/Library/OpensslLib/openssl/util/mkrc.pl + create mode 100755 CryptoPkg/Library/OpensslLib/openssl/util/openssl-format-source + create mode 100755 CryptoPkg/Library/OpensslLib/openssl/util/opensslwrap.sh + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/util/perl/OpenSSL/Util/Pod.pm + create mode 100755 CryptoPkg/Library/OpensslLib/openssl/util/point.sh + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/util/process_docs.pl + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/util/selftest.pl + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/util/shareable_image_wrap.c.in + create mode 100755 CryptoPkg/Library/OpensslLib/openssl/util/shlib_wrap.sh.in + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/util/su-filter.pl + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/util/with_fallback.pm + +diff --git a/CryptoPkg/Library/OpensslLib/openssl/.travis-create-release.sh b/CryptoPkg/Library/OpensslLib/openssl/.travis-create-release.sh +new file mode 100644 +index 0000000..311cedd +--- /dev/null ++++ b/CryptoPkg/Library/OpensslLib/openssl/.travis-create-release.sh +@@ -0,0 +1,11 @@ ++#! /bin/sh ++ ++# $1 is expected to be $TRAVIS_OS_NAME ++ ++./Configure dist ++if [ "$1" == osx ]; then ++ make NAME='_srcdist' TARFILE='_srcdist.tar' \ ++ TAR_COMMAND='$(TAR) $(TARFLAGS) -cvf -' tar ++else ++ make TARFILE='_srcdist.tar' NAME='_srcdist' dist ++fi +diff --git a/CryptoPkg/Library/OpensslLib/openssl/.travis.yml b/CryptoPkg/Library/OpensslLib/openssl/.travis.yml +new file mode 100644 +index 0000000..24f62dd +--- /dev/null ++++ b/CryptoPkg/Library/OpensslLib/openssl/.travis.yml +@@ -0,0 +1,152 @@ ++dist: trusty ++sudo: required ++ ++language: c ++cache: ccache ++ ++before_install: ++ - pip install --user cpp-coveralls ++ ++addons: ++ apt: ++ packages: ++ - ccache ++ - clang-3.9 ++ - gcc-5 ++ - binutils-mingw-w64 ++ - gcc-mingw-w64 ++ sources: ++ - llvm-toolchain-trusty-3.9 ++ - ubuntu-toolchain-r-test ++ ++os: ++ - linux ++ - osx ++ ++compiler: ++ - clang ++ - gcc ++ ++env: ++ - CONFIG_OPTS="" DESTDIR="_install" ++ - CONFIG_OPTS="--debug no-shared enable-crypto-mdebug enable-rc5 enable-md2" ++ - CONFIG_OPTS="no-pic --strict-warnings" BUILDONLY="yes" ++ - CONFIG_OPTS="no-engine no-shared --strict-warnings" BUILDONLY="yes" ++ - CONFIG_OPTS="no-stdio --strict-warnings" BUILDONLY="yes" ++ - CONFIG_OPTS="no-ec" BUILDONLY="yes" ++ ++matrix: ++ include: ++ - os: linux ++ compiler: clang-3.9 ++ env: CONFIG_OPTS="--strict-warnings no-deprecated" BUILDONLY="yes" ++ - os: linux ++ compiler: gcc ++ env: CONFIG_OPTS="--debug --coverage no-asm enable-rc5 enable-md2 enable-ec_nistp_64_gcc_128 enable-ssl3 enable-ssl3-method enable-weak-ssl-ciphers" COVERALLS="yes" ++ - os: linux ++ compiler: clang-3.9 ++ env: CONFIG_OPTS="enable-asan" ++ - os: linux ++ compiler: clang-3.9 ++ env: CONFIG_OPTS="enable-msan" ++ - os: linux ++ compiler: clang-3.9 ++ env: CONFIG_OPTS="no-asm enable-ubsan enable-rc5 enable-md2 enable-ssl3 enable-ssl3-method -fno-sanitize=alignment" ++ - os: linux ++ compiler: clang-3.9 ++ env: CONFIG_OPTS="no-asm enable-asan enable-rc5 enable-md2" ++ - os: linux ++ compiler: clang-3.9 ++ env: CONFIG_OPTS="no-stdio" ++ - os: linux ++ compiler: gcc-5 ++ env: CONFIG_OPTS="no-asm enable-ubsan enable-rc5 enable-md2 -DPEDANTIC" ++ - os: linux ++ compiler: i686-w64-mingw32-gcc ++ env: CONFIG_OPTS="no-pic" ++ - os: linux ++ compiler: i686-w64-mingw32-gcc ++ env: CONFIG_OPTS="no-stdio" ++ - os: linux ++ compiler: x86_64-w64-mingw32-gcc ++ env: CONFIG_OPTS="no-pic" ++ - os: linux ++ compiler: x86_64-w64-mingw32-gcc ++ env: CONFIG_OPTS="no-stdio" ++ exclude: ++ - os: linux ++ compiler: clang ++ - os: osx ++ compiler: gcc ++ ++before_script: ++ - if [ -n "$DESTDIR" ]; then ++ sh .travis-create-release.sh $TRAVIS_OS_NAME; ++ tar -xvzf _srcdist.tar.gz; ++ mkdir _build; ++ cd _build; ++ srcdir=../_srcdist; ++ top=..; ++ else ++ srcdir=.; ++ top=.; ++ fi ++ - if [ "$CC" == i686-w64-mingw32-gcc ]; then ++ export CROSS_COMPILE=${CC%%gcc}; unset CC; ++ $srcdir/Configure mingw $CONFIG_OPTS -Wno-pedantic-ms-format; ++ elif [ "$CC" == x86_64-w64-mingw32-gcc ]; then ++ export CROSS_COMPILE=${CC%%gcc}; unset CC; ++ $srcdir/Configure mingw64 $CONFIG_OPTS -Wno-pedantic-ms-format; ++ else ++ if which ccache >/dev/null && [ "$CC" != clang-3.9 ]; then ++ CC="ccache $CC"; ++ fi; ++ $srcdir/config -v $CONFIG_OPTS; ++ fi ++ - if [ -z "$BUILDONLY" ]; then ++ if [ -n "$CROSS_COMPILE" ]; then ++ if [ "$TRAVIS_OS_NAME" == "linux" ]; then ++ sudo dpkg --add-architecture i386; ++ sudo apt-get update; ++ sudo apt-get -yq install wine; ++ fi; ++ fi; ++ fi ++ - cd $top ++ ++script: ++ - if [ -z "$BUILDONLY" ]; then ++ make="make -s"; ++ else ++ make="make"; ++ fi ++ - if [ -n "$DESTDIR" ]; then ++ cd _build; ++ top=..; ++ else ++ top=.; ++ fi ++ - $make update ++ - $make ++ - if [ -z "$BUILDONLY" ]; then ++ if [ -n "$CROSS_COMPILE" ]; then ++ export EXE_SHELL="wine" WINEPREFIX=`pwd`; ++ fi; ++ HARNESS_VERBOSE=yes make test; ++ else ++ $make build_tests; ++ fi ++ - if [ -n "$DESTDIR" ]; then ++ mkdir "../$DESTDIR"; ++ $make install install_docs DESTDIR="../$DESTDIR"; ++ fi ++ - cd $top ++ ++after_success: ++ - if [ -n "$COVERALLS" ]; then ++ coveralls -b . --gcov-options '\-lp'; ++ fi; ++ ++notifications: ++ email: ++ secure: "xeGNgWO7aoaDgRvcZubposqMsj36aU8c6F0oHfw+rUqltCQ14IgYCUwzocmR2O+Pa7B3Cx5VjMfBFHbQaajZsfod8vu7g+aGq/zkjwbhsr/SR4dljJjFJXLGZjIalm9KgP6KInmVDuINfCqP+MHIY5lZkNI7DMcyHDhVc5nSKvCXV7xTDNgmstvh8rB/z51WfHDqGqfBtiuK5FDNxmvYK8OFJ5W94Lu9LDlizcxwK3GAj7arOui7Z5w8bQ6p4seUE3IvJL1Zbj0pZHxvNb6Zeb2Pn8QF1qLlN8YmBktD4aiw0ce4wYRiL87uLgcOxZY7SVXtv2XYFIYWapU/FKjCqa6vK93V/H9eZWEIYNMKnN3wXm2beqVdnKek3OeGJ8v0y7MbSfuLfRtBqbTSNYnpU1Zuo4MQAvHvEPuwCAYkYQajOSRplMH5sULFKptuVqNtOMfjL8jHb8AEoL1acYIk43ydxeYrzzas4fqgCDJ52573/u0RNdF1lkQBLkuM365OB8VRqtpnoxcdEIY/qBc/8TzZ24fxyrs5qdHFcxGSgpN2EP6cJMqpvkemnCNSdhxUqfzm22N7a3O8+4LFSBGOnHto/PwdsvF/01yGYL0LoZTnoO1i6x7AMJPBh+eyDU0ZjGhj/msjmqeb9C8vRqQ+1WjHrIS1iqCD0Czib8tUPD4=" +diff --git a/CryptoPkg/Library/OpensslLib/openssl/ACKNOWLEDGEMENTS b/CryptoPkg/Library/OpensslLib/openssl/ACKNOWLEDGEMENTS +new file mode 100644 +index 0000000..d21dccb +--- /dev/null ++++ b/CryptoPkg/Library/OpensslLib/openssl/ACKNOWLEDGEMENTS +@@ -0,0 +1,2 @@ ++Please https://www.openssl.org/community/thanks.html for the current ++acknowledgements. +diff --git a/CryptoPkg/Library/OpensslLib/openssl/AUTHORS b/CryptoPkg/Library/OpensslLib/openssl/AUTHORS +new file mode 100644 +index 0000000..48211a2 +--- /dev/null ++++ b/CryptoPkg/Library/OpensslLib/openssl/AUTHORS +@@ -0,0 +1,21 @@ ++ Andy Polyakov ++ Ben Laurie ++ Bodo M�ller ++ Emilia K�sper ++ Eric Young ++ Geoff Thorpe ++ Holger Reif ++ Kurt Roeckx ++ Lutz J�nicke ++ Mark J. Cox ++ Matt Caswell ++ Nils Larsch ++ Paul C. Sutton ++ Ralf S. Engelschall ++ Rich Salz ++ Richard Levitte ++ Stephen Henson ++ Steve Marquess ++ Tim Hudson ++ Ulf M�ller ++ Viktor Dukhovni +diff --git a/CryptoPkg/Library/OpensslLib/openssl/CHANGES b/CryptoPkg/Library/OpensslLib/openssl/CHANGES +new file mode 100644 +index 0000000..cc06923 +--- /dev/null ++++ b/CryptoPkg/Library/OpensslLib/openssl/CHANGES +@@ -0,0 +1,12454 @@ ++ ++ OpenSSL CHANGES ++ _______________ ++ ++ Changes between 1.1.0d and 1.1.0e [16 Feb 2017] ++ ++ *) Encrypt-Then-Mac renegotiation crash ++ ++ During a renegotiation handshake if the Encrypt-Then-Mac extension is ++ negotiated where it was not in the original handshake (or vice-versa) then ++ this can cause OpenSSL to crash (dependant on ciphersuite). Both clients ++ and servers are affected. ++ ++ This issue was reported to OpenSSL by Joe Orton (Red Hat). ++ (CVE-2017-3733) ++ [Matt Caswell] ++ ++ Changes between 1.1.0c and 1.1.0d [26 Jan 2017] ++ ++ *) Truncated packet could crash via OOB read ++ ++ If one side of an SSL/TLS path is running on a 32-bit host and a specific ++ cipher is being used, then a truncated packet can cause that host to ++ perform an out-of-bounds read, usually resulting in a crash. ++ ++ This issue was reported to OpenSSL by Robert Święcki of Google. ++ (CVE-2017-3731) ++ [Andy Polyakov] ++ ++ *) Bad (EC)DHE parameters cause a client crash ++ ++ If a malicious server supplies bad parameters for a DHE or ECDHE key ++ exchange then this can result in the client attempting to dereference a ++ NULL pointer leading to a client crash. This could be exploited in a Denial ++ of Service attack. ++ ++ This issue was reported to OpenSSL by Guido Vranken. ++ (CVE-2017-3730) ++ [Matt Caswell] ++ ++ *) BN_mod_exp may produce incorrect results on x86_64 ++ ++ There is a carry propagating bug in the x86_64 Montgomery squaring ++ procedure. No EC algorithms are affected. Analysis suggests that attacks ++ against RSA and DSA as a result of this defect would be very difficult to ++ perform and are not believed likely. Attacks against DH are considered just ++ feasible (although very difficult) because most of the work necessary to ++ deduce information about a private key may be performed offline. The amount ++ of resources required for such an attack would be very significant and ++ likely only accessible to a limited number of attackers. An attacker would ++ additionally need online access to an unpatched system using the target ++ private key in a scenario with persistent DH parameters and a private ++ key that is shared between multiple clients. For example this can occur by ++ default in OpenSSL DHE based SSL/TLS ciphersuites. Note: This issue is very ++ similar to CVE-2015-3193 but must be treated as a separate problem. ++ ++ This issue was reported to OpenSSL by the OSS-Fuzz project. ++ (CVE-2017-3732) ++ [Andy Polyakov] ++ ++ Changes between 1.1.0b and 1.1.0c [10 Nov 2016] ++ ++ *) ChaCha20/Poly1305 heap-buffer-overflow ++ ++ TLS connections using *-CHACHA20-POLY1305 ciphersuites are susceptible to ++ a DoS attack by corrupting larger payloads. This can result in an OpenSSL ++ crash. This issue is not considered to be exploitable beyond a DoS. ++ ++ This issue was reported to OpenSSL by Robert Święcki (Google Security Team) ++ (CVE-2016-7054) ++ [Richard Levitte] ++ ++ *) CMS Null dereference ++ ++ Applications parsing invalid CMS structures can crash with a NULL pointer ++ dereference. This is caused by a bug in the handling of the ASN.1 CHOICE ++ type in OpenSSL 1.1.0 which can result in a NULL value being passed to the ++ structure callback if an attempt is made to free certain invalid encodings. ++ Only CHOICE structures using a callback which do not handle NULL value are ++ affected. ++ ++ This issue was reported to OpenSSL by Tyler Nighswander of ForAllSecure. ++ (CVE-2016-7053) ++ [Stephen Henson] ++ ++ *) Montgomery multiplication may produce incorrect results ++ ++ There is a carry propagating bug in the Broadwell-specific Montgomery ++ multiplication procedure that handles input lengths divisible by, but ++ longer than 256 bits. Analysis suggests that attacks against RSA, DSA ++ and DH private keys are impossible. This is because the subroutine in ++ question is not used in operations with the private key itself and an input ++ of the attacker's direct choice. Otherwise the bug can manifest itself as ++ transient authentication and key negotiation failures or reproducible ++ erroneous outcome of public-key operations with specially crafted input. ++ Among EC algorithms only Brainpool P-512 curves are affected and one ++ presumably can attack ECDH key negotiation. Impact was not analyzed in ++ detail, because pre-requisites for attack are considered unlikely. Namely ++ multiple clients have to choose the curve in question and the server has to ++ share the private key among them, neither of which is default behaviour. ++ Even then only clients that chose the curve will be affected. ++ ++ This issue was publicly reported as transient failures and was not ++ initially recognized as a security issue. Thanks to Richard Morgan for ++ providing reproducible case. ++ (CVE-2016-7055) ++ [Andy Polyakov] ++ ++ *) OpenSSL now fails if it receives an unrecognised record type in TLS1.0 ++ or TLS1.1. Previously this only happened in SSLv3 and TLS1.2. This is to ++ prevent issues where no progress is being made and the peer continually ++ sends unrecognised record types, using up resources processing them. ++ [Matt Caswell] ++ ++ *) Removed automatic addition of RPATH in shared libraries and executables, ++ as this was a remainder from OpenSSL 1.0.x and isn't needed any more. ++ [Richard Levitte] ++ ++ Changes between 1.1.0a and 1.1.0b [26 Sep 2016] ++ ++ *) Fix Use After Free for large message sizes ++ ++ The patch applied to address CVE-2016-6307 resulted in an issue where if a ++ message larger than approx 16k is received then the underlying buffer to ++ store the incoming message is reallocated and moved. Unfortunately a ++ dangling pointer to the old location is left which results in an attempt to ++ write to the previously freed location. This is likely to result in a ++ crash, however it could potentially lead to execution of arbitrary code. ++ ++ This issue only affects OpenSSL 1.1.0a. ++ ++ This issue was reported to OpenSSL by Robert Święcki. ++ (CVE-2016-6309) ++ [Matt Caswell] ++ ++ Changes between 1.1.0 and 1.1.0a [22 Sep 2016] ++ ++ *) OCSP Status Request extension unbounded memory growth ++ ++ A malicious client can send an excessively large OCSP Status Request ++ extension. If that client continually requests renegotiation, sending a ++ large OCSP Status Request extension each time, then there will be unbounded ++ memory growth on the server. This will eventually lead to a Denial Of ++ Service attack through memory exhaustion. Servers with a default ++ configuration are vulnerable even if they do not support OCSP. Builds using ++ the "no-ocsp" build time option are not affected. ++ ++ This issue was reported to OpenSSL by Shi Lei (Gear Team, Qihoo 360 Inc.) ++ (CVE-2016-6304) ++ [Matt Caswell] ++ ++ *) SSL_peek() hang on empty record ++ ++ OpenSSL 1.1.0 SSL/TLS will hang during a call to SSL_peek() if the peer ++ sends an empty record. This could be exploited by a malicious peer in a ++ Denial Of Service attack. ++ ++ This issue was reported to OpenSSL by Alex Gaynor. ++ (CVE-2016-6305) ++ [Matt Caswell] ++ ++ *) Excessive allocation of memory in tls_get_message_header() and ++ dtls1_preprocess_fragment() ++ ++ A (D)TLS message includes 3 bytes for its length in the header for the ++ message. This would allow for messages up to 16Mb in length. Messages of ++ this length are excessive and OpenSSL includes a check to ensure that a ++ peer is sending reasonably sized messages in order to avoid too much memory ++ being consumed to service a connection. A flaw in the logic of version ++ 1.1.0 means that memory for the message is allocated too early, prior to ++ the excessive message length check. Due to way memory is allocated in ++ OpenSSL this could mean an attacker could force up to 21Mb to be allocated ++ to service a connection. This could lead to a Denial of Service through ++ memory exhaustion. However, the excessive message length check still takes ++ place, and this would cause the connection to immediately fail. Assuming ++ that the application calls SSL_free() on the failed conneciton in a timely ++ manner then the 21Mb of allocated memory will then be immediately freed ++ again. Therefore the excessive memory allocation will be transitory in ++ nature. This then means that there is only a security impact if: ++ ++ 1) The application does not call SSL_free() in a timely manner in the event ++ that the connection fails ++ or ++ 2) The application is working in a constrained environment where there is ++ very little free memory ++ or ++ 3) The attacker initiates multiple connection attempts such that there are ++ multiple connections in a state where memory has been allocated for the ++ connection; SSL_free() has not yet been called; and there is insufficient ++ memory to service the multiple requests. ++ ++ Except in the instance of (1) above any Denial Of Service is likely to be ++ transitory because as soon as the connection fails the memory is ++ subsequently freed again in the SSL_free() call. However there is an ++ increased risk during this period of application crashes due to the lack of ++ memory - which would then mean a more serious Denial of Service. ++ ++ This issue was reported to OpenSSL by Shi Lei (Gear Team, Qihoo 360 Inc.) ++ (CVE-2016-6307 and CVE-2016-6308) ++ [Matt Caswell] ++ ++ *) solaris-x86-cc, i.e. 32-bit configuration with vendor compiler, ++ had to be removed. Primary reason is that vendor assembler can't ++ assemble our modules with -KPIC flag. As result it, assembly ++ support, was not even available as option. But its lack means ++ lack of side-channel resistant code, which is incompatible with ++ security by todays standards. Fortunately gcc is readily available ++ prepackaged option, which we firmly point at... ++ [Andy Polyakov] ++ ++ Changes between 1.0.2h and 1.1.0 [25 Aug 2016] ++ ++ *) Windows command-line tool supports UTF-8 opt-in option for arguments ++ and console input. Setting OPENSSL_WIN32_UTF8 environment variable ++ (to any value) allows Windows user to access PKCS#12 file generated ++ with Windows CryptoAPI and protected with non-ASCII password, as well ++ as files generated under UTF-8 locale on Linux also protected with ++ non-ASCII password. ++ [Andy Polyakov] ++ ++ *) To mitigate the SWEET32 attack (CVE-2016-2183), 3DES cipher suites ++ have been disabled by default and removed from DEFAULT, just like RC4. ++ See the RC4 item below to re-enable both. ++ [Rich Salz] ++ ++ *) The method for finding the storage location for the Windows RAND seed file ++ has changed. First we check %RANDFILE%. If that is not set then we check ++ the directories %HOME%, %USERPROFILE% and %SYSTEMROOT% in that order. If ++ all else fails we fall back to C:\. ++ [Matt Caswell] ++ ++ *) The EVP_EncryptUpdate() function has had its return type changed from void ++ to int. A return of 0 indicates and error while a return of 1 indicates ++ success. ++ [Matt Caswell] ++ ++ *) The flags RSA_FLAG_NO_CONSTTIME, DSA_FLAG_NO_EXP_CONSTTIME and ++ DH_FLAG_NO_EXP_CONSTTIME which previously provided the ability to switch ++ off the constant time implementation for RSA, DSA and DH have been made ++ no-ops and deprecated. ++ [Matt Caswell] ++ ++ *) Windows RAND implementation was simplified to only get entropy by ++ calling CryptGenRandom(). Various other RAND-related tickets ++ were also closed. ++ [Joseph Wylie Yandle, Rich Salz] ++ ++ *) The stack and lhash API's were renamed to start with OPENSSL_SK_ ++ and OPENSSL_LH_, respectively. The old names are available ++ with API compatibility. They new names are now completely documented. ++ [Rich Salz] ++ ++ *) Unify TYPE_up_ref(obj) methods signature. ++ SSL_CTX_up_ref(), SSL_up_ref(), X509_up_ref(), EVP_PKEY_up_ref(), ++ X509_CRL_up_ref(), X509_OBJECT_up_ref_count() methods are now returning an ++ int (instead of void) like all others TYPE_up_ref() methods. ++ So now these methods also check the return value of CRYPTO_atomic_add(), ++ and the validity of object reference counter. ++ [fdasilvayy@gmail.com] ++ ++ *) With Windows Visual Studio builds, the .pdb files are installed ++ alongside the installed libraries and executables. For a static ++ library installation, ossl_static.pdb is the associate compiler ++ generated .pdb file to be used when linking programs. ++ [Richard Levitte] ++ ++ *) Remove openssl.spec. Packaging files belong with the packagers. ++ [Richard Levitte] ++ ++ *) Automatic Darwin/OSX configuration has had a refresh, it will now ++ recognise x86_64 architectures automatically. You can still decide ++ to build for a different bitness with the environment variable ++ KERNEL_BITS (can be 32 or 64), for example: ++ ++ KERNEL_BITS=32 ./config ++ ++ [Richard Levitte] ++ ++ *) Change default algorithms in pkcs8 utility to use PKCS#5 v2.0, ++ 256 bit AES and HMAC with SHA256. ++ [Steve Henson] ++ ++ *) Remove support for MIPS o32 ABI on IRIX (and IRIX only). ++ [Andy Polyakov] ++ ++ *) Triple-DES ciphers have been moved from HIGH to MEDIUM. ++ [Rich Salz] ++ ++ *) To enable users to have their own config files and build file templates, ++ Configure looks in the directory indicated by the environment variable ++ OPENSSL_LOCAL_CONFIG_DIR as well as the in-source Configurations/ ++ directory. On VMS, OPENSSL_LOCAL_CONFIG_DIR is expected to be a logical ++ name and is used as is. ++ [Richard Levitte] ++ ++ *) The following datatypes were made opaque: X509_OBJECT, X509_STORE_CTX, ++ X509_STORE, X509_LOOKUP, and X509_LOOKUP_METHOD. The unused type ++ X509_CERT_FILE_CTX was removed. ++ [Rich Salz] ++ ++ *) "shared" builds are now the default. To create only static libraries use ++ the "no-shared" Configure option. ++ [Matt Caswell] ++ ++ *) Remove the no-aes, no-hmac, no-rsa, no-sha and no-md5 Configure options. ++ All of these option have not worked for some while and are fundamental ++ algorithms. ++ [Matt Caswell] ++ ++ *) Make various cleanup routines no-ops and mark them as deprecated. Most ++ global cleanup functions are no longer required because they are handled ++ via auto-deinit (see OPENSSL_init_crypto and OPENSSL_init_ssl man pages). ++ Explicitly de-initing can cause problems (e.g. where a library that uses ++ OpenSSL de-inits, but an application is still using it). The affected ++ functions are CONF_modules_free(), ENGINE_cleanup(), OBJ_cleanup(), ++ EVP_cleanup(), BIO_sock_cleanup(), CRYPTO_cleanup_all_ex_data(), ++ RAND_cleanup(), SSL_COMP_free_compression_methods(), ERR_free_strings() and ++ COMP_zlib_cleanup(). ++ [Matt Caswell] ++ ++ *) --strict-warnings no longer enables runtime debugging options ++ such as REF_DEBUG. Instead, debug options are automatically ++ enabled with '--debug' builds. ++ [Andy Polyakov, Emilia Käsper] ++ ++ *) Made DH and DH_METHOD opaque. The structures for managing DH objects ++ have been moved out of the public header files. New functions for managing ++ these have been added. ++ [Matt Caswell] ++ ++ *) Made RSA and RSA_METHOD opaque. The structures for managing RSA ++ objects have been moved out of the public header files. New ++ functions for managing these have been added. ++ [Richard Levitte] ++ ++ *) Made DSA and DSA_METHOD opaque. The structures for managing DSA objects ++ have been moved out of the public header files. New functions for managing ++ these have been added. ++ [Matt Caswell] ++ ++ *) Made BIO and BIO_METHOD opaque. The structures for managing BIOs have been ++ moved out of the public header files. New functions for managing these ++ have been added. ++ [Matt Caswell] ++ ++ *) Removed no-rijndael as a config option. Rijndael is an old name for AES. ++ [Matt Caswell] ++ ++ *) Removed the mk1mf build scripts. ++ [Richard Levitte] ++ ++ *) Headers are now wrapped, if necessary, with OPENSSL_NO_xxx, so ++ it is always safe to #include a header now. ++ [Rich Salz] ++ ++ *) Removed the aged BC-32 config and all its supporting scripts ++ [Richard Levitte] ++ ++ *) Removed support for Ultrix, Netware, and OS/2. ++ [Rich Salz] ++ ++ *) Add support for HKDF. ++ [Alessandro Ghedini] ++ ++ *) Add support for blake2b and blake2s ++ [Bill Cox] ++ ++ *) Added support for "pipelining". Ciphers that have the ++ EVP_CIPH_FLAG_PIPELINE flag set have a capability to process multiple ++ encryptions/decryptions simultaneously. There are currently no built-in ++ ciphers with this property but the expectation is that engines will be able ++ to offer it to significantly improve throughput. Support has been extended ++ into libssl so that multiple records for a single connection can be ++ processed in one go (for >=TLS 1.1). ++ [Matt Caswell] ++ ++ *) Added the AFALG engine. This is an async capable engine which is able to ++ offload work to the Linux kernel. In this initial version it only supports ++ AES128-CBC. The kernel must be version 4.1.0 or greater. ++ [Catriona Lucey] ++ ++ *) OpenSSL now uses a new threading API. It is no longer necessary to ++ set locking callbacks to use OpenSSL in a multi-threaded environment. There ++ are two supported threading models: pthreads and windows threads. It is ++ also possible to configure OpenSSL at compile time for "no-threads". The ++ old threading API should no longer be used. The functions have been ++ replaced with "no-op" compatibility macros. ++ [Alessandro Ghedini, Matt Caswell] ++ ++ *) Modify behavior of ALPN to invoke callback after SNI/servername ++ callback, such that updates to the SSL_CTX affect ALPN. ++ [Todd Short] ++ ++ *) Add SSL_CIPHER queries for authentication and key-exchange. ++ [Todd Short] ++ ++ *) Changes to the DEFAULT cipherlist: ++ - Prefer (EC)DHE handshakes over plain RSA. ++ - Prefer AEAD ciphers over legacy ciphers. ++ - Prefer ECDSA over RSA when both certificates are available. ++ - Prefer TLSv1.2 ciphers/PRF. ++ - Remove DSS, SEED, IDEA, CAMELLIA, and AES-CCM from the ++ default cipherlist. ++ [Emilia Käsper] ++ ++ *) Change the ECC default curve list to be this, in order: x25519, ++ secp256r1, secp521r1, secp384r1. ++ [Rich Salz] ++ ++ *) RC4 based libssl ciphersuites are now classed as "weak" ciphers and are ++ disabled by default. They can be re-enabled using the ++ enable-weak-ssl-ciphers option to Configure. ++ [Matt Caswell] ++ ++ *) If the server has ALPN configured, but supports no protocols that the ++ client advertises, send a fatal "no_application_protocol" alert. ++ This behaviour is SHALL in RFC 7301, though it isn't universally ++ implemented by other servers. ++ [Emilia Käsper] ++ ++ *) Add X25519 support. ++ Add ASN.1 and EVP_PKEY methods for X25519. This includes support ++ for public and private key encoding using the format documented in ++ draft-ietf-curdle-pkix-02. The coresponding EVP_PKEY method supports ++ key generation and key derivation. ++ ++ TLS support complies with draft-ietf-tls-rfc4492bis-08 and uses ++ X25519(29). ++ [Steve Henson] ++ ++ *) Deprecate SRP_VBASE_get_by_user. ++ SRP_VBASE_get_by_user had inconsistent memory management behaviour. ++ In order to fix an unavoidable memory leak (CVE-2016-0798), ++ SRP_VBASE_get_by_user was changed to ignore the "fake user" SRP ++ seed, even if the seed is configured. ++ ++ Users should use SRP_VBASE_get1_by_user instead. Note that in ++ SRP_VBASE_get1_by_user, caller must free the returned value. Note ++ also that even though configuring the SRP seed attempts to hide ++ invalid usernames by continuing the handshake with fake ++ credentials, this behaviour is not constant time and no strong ++ guarantees are made that the handshake is indistinguishable from ++ that of a valid user. ++ [Emilia Käsper] ++ ++ *) Configuration change; it's now possible to build dynamic engines ++ without having to build shared libraries and vice versa. This ++ only applies to the engines in engines/, those in crypto/engine/ ++ will always be built into libcrypto (i.e. "static"). ++ ++ Building dynamic engines is enabled by default; to disable, use ++ the configuration option "disable-dynamic-engine". ++ ++ The only requirements for building dynamic engines are the ++ presence of the DSO module and building with position independent ++ code, so they will also automatically be disabled if configuring ++ with "disable-dso" or "disable-pic". ++ ++ The macros OPENSSL_NO_STATIC_ENGINE and OPENSSL_NO_DYNAMIC_ENGINE ++ are also taken away from openssl/opensslconf.h, as they are ++ irrelevant. ++ [Richard Levitte] ++ ++ *) Configuration change; if there is a known flag to compile ++ position independent code, it will always be applied on the ++ libcrypto and libssl object files, and never on the application ++ object files. This means other libraries that use routines from ++ libcrypto / libssl can be made into shared libraries regardless ++ of how OpenSSL was configured. ++ ++ If this isn't desirable, the configuration options "disable-pic" ++ or "no-pic" can be used to disable the use of PIC. This will ++ also disable building shared libraries and dynamic engines. ++ [Richard Levitte] ++ ++ *) Removed JPAKE code. It was experimental and has no wide use. ++ [Rich Salz] ++ ++ *) The INSTALL_PREFIX Makefile variable has been renamed to ++ DESTDIR. That makes for less confusion on what this variable ++ is for. Also, the configuration option --install_prefix is ++ removed. ++ [Richard Levitte] ++ ++ *) Heartbeat for TLS has been removed and is disabled by default ++ for DTLS; configure with enable-heartbeats. Code that uses the ++ old #define's might need to be updated. ++ [Emilia Käsper, Rich Salz] ++ ++ *) Rename REF_CHECK to REF_DEBUG. ++ [Rich Salz] ++ ++ *) New "unified" build system ++ ++ The "unified" build system is aimed to be a common system for all ++ platforms we support. With it comes new support for VMS. ++ ++ This system builds supports building in a different directory tree ++ than the source tree. It produces one Makefile (for unix family ++ or lookalikes), or one descrip.mms (for VMS). ++ ++ The source of information to make the Makefile / descrip.mms is ++ small files called 'build.info', holding the necessary ++ information for each directory with source to compile, and a ++ template in Configurations, like unix-Makefile.tmpl or ++ descrip.mms.tmpl. ++ ++ With this change, the library names were also renamed on Windows ++ and on VMS. They now have names that are closer to the standard ++ on Unix, and include the major version number, and in certain ++ cases, the architecture they are built for. See "Notes on shared ++ libraries" in INSTALL. ++ ++ We rely heavily on the perl module Text::Template. ++ [Richard Levitte] ++ ++ *) Added support for auto-initialisation and de-initialisation of the library. ++ OpenSSL no longer requires explicit init or deinit routines to be called, ++ except in certain circumstances. See the OPENSSL_init_crypto() and ++ OPENSSL_init_ssl() man pages for further information. ++ [Matt Caswell] ++ ++ *) The arguments to the DTLSv1_listen function have changed. Specifically the ++ "peer" argument is now expected to be a BIO_ADDR object. ++ ++ *) Rewrite of BIO networking library. The BIO library lacked consistent ++ support of IPv6, and adding it required some more extensive ++ modifications. This introduces the BIO_ADDR and BIO_ADDRINFO types, ++ which hold all types of addresses and chains of address information. ++ It also introduces a new API, with functions like BIO_socket, ++ BIO_connect, BIO_listen, BIO_lookup and a rewrite of BIO_accept. ++ The source/sink BIOs BIO_s_connect, BIO_s_accept and BIO_s_datagram ++ have been adapted accordingly. ++ [Richard Levitte] ++ ++ *) RSA_padding_check_PKCS1_type_1 now accepts inputs with and without ++ the leading 0-byte. ++ [Emilia Käsper] ++ ++ *) CRIME protection: disable compression by default, even if OpenSSL is ++ compiled with zlib enabled. Applications can still enable compression ++ by calling SSL_CTX_clear_options(ctx, SSL_OP_NO_COMPRESSION), or by ++ using the SSL_CONF library to configure compression. ++ [Emilia Käsper] ++ ++ *) The signature of the session callback configured with ++ SSL_CTX_sess_set_get_cb was changed. The read-only input buffer ++ was explicitly marked as 'const unsigned char*' instead of ++ 'unsigned char*'. ++ [Emilia Käsper] ++ ++ *) Always DPURIFY. Remove the use of uninitialized memory in the ++ RNG, and other conditional uses of DPURIFY. This makes -DPURIFY a no-op. ++ [Emilia Käsper] ++ ++ *) Removed many obsolete configuration items, including ++ DES_PTR, DES_RISC1, DES_RISC2, DES_INT ++ MD2_CHAR, MD2_INT, MD2_LONG ++ BF_PTR, BF_PTR2 ++ IDEA_SHORT, IDEA_LONG ++ RC2_SHORT, RC2_LONG, RC4_LONG, RC4_CHUNK, RC4_INDEX ++ [Rich Salz, with advice from Andy Polyakov] ++ ++ *) Many BN internals have been moved to an internal header file. ++ [Rich Salz with help from Andy Polyakov] ++ ++ *) Configuration and writing out the results from it has changed. ++ Files such as Makefile include/openssl/opensslconf.h and are now ++ produced through general templates, such as Makefile.in and ++ crypto/opensslconf.h.in and some help from the perl module ++ Text::Template. ++ ++ Also, the center of configuration information is no longer ++ Makefile. Instead, Configure produces a perl module in ++ configdata.pm which holds most of the config data (in the hash ++ table %config), the target data that comes from the target ++ configuration in one of the Configurations/*.conf files (in ++ %target). ++ [Richard Levitte] ++ ++ *) To clarify their intended purposes, the Configure options ++ --prefix and --openssldir change their semantics, and become more ++ straightforward and less interdependent. ++ ++ --prefix shall be used exclusively to give the location INSTALLTOP ++ where programs, scripts, libraries, include files and manuals are ++ going to be installed. The default is now /usr/local. ++ ++ --openssldir shall be used exclusively to give the default ++ location OPENSSLDIR where certificates, private keys, CRLs are ++ managed. This is also where the default openssl.cnf gets ++ installed. ++ If the directory given with this option is a relative path, the ++ values of both the --prefix value and the --openssldir value will ++ be combined to become OPENSSLDIR. ++ The default for --openssldir is INSTALLTOP/ssl. ++ ++ Anyone who uses --openssldir to specify where OpenSSL is to be ++ installed MUST change to use --prefix instead. ++ [Richard Levitte] ++ ++ *) The GOST engine was out of date and therefore it has been removed. An up ++ to date GOST engine is now being maintained in an external repository. ++ See: https://wiki.openssl.org/index.php/Binaries. Libssl still retains ++ support for GOST ciphersuites (these are only activated if a GOST engine ++ is present). ++ [Matt Caswell] ++ ++ *) EGD is no longer supported by default; use enable-egd when ++ configuring. ++ [Ben Kaduk and Rich Salz] ++ ++ *) The distribution now has Makefile.in files, which are used to ++ create Makefile's when Configure is run. *Configure must be run ++ before trying to build now.* ++ [Rich Salz] ++ ++ *) The return value for SSL_CIPHER_description() for error conditions ++ has changed. ++ [Rich Salz] ++ ++ *) Support for RFC6698/RFC7671 DANE TLSA peer authentication. ++ ++ Obtaining and performing DNSSEC validation of TLSA records is ++ the application's responsibility. The application provides ++ the TLSA records of its choice to OpenSSL, and these are then ++ used to authenticate the peer. ++ ++ The TLSA records need not even come from DNS. They can, for ++ example, be used to implement local end-entity certificate or ++ trust-anchor "pinning", where the "pin" data takes the form ++ of TLSA records, which can augment or replace verification ++ based on the usual WebPKI public certification authorities. ++ [Viktor Dukhovni] ++ ++ *) Revert default OPENSSL_NO_DEPRECATED setting. Instead OpenSSL ++ continues to support deprecated interfaces in default builds. ++ However, applications are strongly advised to compile their ++ source files with -DOPENSSL_API_COMPAT=0x10100000L, which hides ++ the declarations of all interfaces deprecated in 0.9.8, 1.0.0 ++ or the 1.1.0 releases. ++ ++ In environments in which all applications have been ported to ++ not use any deprecated interfaces OpenSSL's Configure script ++ should be used with the --api=1.1.0 option to entirely remove ++ support for the deprecated features from the library and ++ unconditionally disable them in the installed headers. ++ Essentially the same effect can be achieved with the "no-deprecated" ++ argument to Configure, except that this will always restrict ++ the build to just the latest API, rather than a fixed API ++ version. ++ ++ As applications are ported to future revisions of the API, ++ they should update their compile-time OPENSSL_API_COMPAT define ++ accordingly, but in most cases should be able to continue to ++ compile with later releases. ++ ++ The OPENSSL_API_COMPAT versions for 1.0.0, and 0.9.8 are ++ 0x10000000L and 0x00908000L, respectively. However those ++ versions did not support the OPENSSL_API_COMPAT feature, and ++ so applications are not typically tested for explicit support ++ of just the undeprecated features of either release. ++ [Viktor Dukhovni] ++ ++ *) Add support for setting the minimum and maximum supported protocol. ++ It can bet set via the SSL_set_min_proto_version() and ++ SSL_set_max_proto_version(), or via the SSL_CONF's MinProtocol and ++ MaxProtcol. It's recommended to use the new APIs to disable ++ protocols instead of disabling individual protocols using ++ SSL_set_options() or SSL_CONF's Protocol. This change also ++ removes support for disabling TLS 1.2 in the OpenSSL TLS ++ client at compile time by defining OPENSSL_NO_TLS1_2_CLIENT. ++ [Kurt Roeckx] ++ ++ *) Support for ChaCha20 and Poly1305 added to libcrypto and libssl. ++ [Andy Polyakov] ++ ++ *) New EC_KEY_METHOD, this replaces the older ECDSA_METHOD and ECDH_METHOD ++ and integrates ECDSA and ECDH functionality into EC. Implementations can ++ now redirect key generation and no longer need to convert to or from ++ ECDSA_SIG format. ++ ++ Note: the ecdsa.h and ecdh.h headers are now no longer needed and just ++ include the ec.h header file instead. ++ [Steve Henson] ++ ++ *) Remove support for all 40 and 56 bit ciphers. This includes all the export ++ ciphers who are no longer supported and drops support the ephemeral RSA key ++ exchange. The LOW ciphers currently doesn't have any ciphers in it. ++ [Kurt Roeckx] ++ ++ *) Made EVP_MD_CTX, EVP_MD, EVP_CIPHER_CTX, EVP_CIPHER and HMAC_CTX ++ opaque. For HMAC_CTX, the following constructors and destructors ++ were added: ++ ++ HMAC_CTX *HMAC_CTX_new(void); ++ void HMAC_CTX_free(HMAC_CTX *ctx); ++ ++ For EVP_MD and EVP_CIPHER, complete APIs to create, fill and ++ destroy such methods has been added. See EVP_MD_meth_new(3) and ++ EVP_CIPHER_meth_new(3) for documentation. ++ ++ Additional changes: ++ 1) EVP_MD_CTX_cleanup(), EVP_CIPHER_CTX_cleanup() and ++ HMAC_CTX_cleanup() were removed. HMAC_CTX_reset() and ++ EVP_MD_CTX_reset() should be called instead to reinitialise ++ an already created structure. ++ 2) For consistency with the majority of our object creators and ++ destructors, EVP_MD_CTX_(create|destroy) were renamed to ++ EVP_MD_CTX_(new|free). The old names are retained as macros ++ for deprecated builds. ++ [Richard Levitte] ++ ++ *) Added ASYNC support. Libcrypto now includes the async sub-library to enable ++ cryptographic operations to be performed asynchronously as long as an ++ asynchronous capable engine is used. See the ASYNC_start_job() man page for ++ further details. Libssl has also had this capability integrated with the ++ introduction of the new mode SSL_MODE_ASYNC and associated error ++ SSL_ERROR_WANT_ASYNC. See the SSL_CTX_set_mode() and SSL_get_error() man ++ pages. This work was developed in partnership with Intel Corp. ++ [Matt Caswell] ++ ++ *) SSL_{CTX_}set_ecdh_auto() has been removed and ECDH is support is ++ always enabled now. If you want to disable the support you should ++ exclude it using the list of supported ciphers. This also means that the ++ "-no_ecdhe" option has been removed from s_server. ++ [Kurt Roeckx] ++ ++ *) SSL_{CTX}_set_tmp_ecdh() which can set 1 EC curve now internally calls ++ SSL_{CTX_}set1_curves() which can set a list. ++ [Kurt Roeckx] ++ ++ *) Remove support for SSL_{CTX_}set_tmp_ecdh_callback(). You should set the ++ curve you want to support using SSL_{CTX_}set1_curves(). ++ [Kurt Roeckx] ++ ++ *) State machine rewrite. The state machine code has been significantly ++ refactored in order to remove much duplication of code and solve issues ++ with the old code (see ssl/statem/README for further details). This change ++ does have some associated API changes. Notably the SSL_state() function ++ has been removed and replaced by SSL_get_state which now returns an ++ "OSSL_HANDSHAKE_STATE" instead of an int. SSL_set_state() has been removed ++ altogether. The previous handshake states defined in ssl.h and ssl3.h have ++ also been removed. ++ [Matt Caswell] ++ ++ *) All instances of the string "ssleay" in the public API were replaced ++ with OpenSSL (case-matching; e.g., OPENSSL_VERSION for #define's) ++ Some error codes related to internal RSA_eay API's were renamed. ++ [Rich Salz] ++ ++ *) The demo files in crypto/threads were moved to demo/threads. ++ [Rich Salz] ++ ++ *) Removed obsolete engines: 4758cca, aep, atalla, cswift, nuron, gmp, ++ sureware and ubsec. ++ [Matt Caswell, Rich Salz] ++ ++ *) New ASN.1 embed macro. ++ ++ New ASN.1 macro ASN1_EMBED. This is the same as ASN1_SIMPLE except the ++ structure is not allocated: it is part of the parent. That is instead of ++ ++ FOO *x; ++ ++ it must be: ++ ++ FOO x; ++ ++ This reduces memory fragmentation and make it impossible to accidentally ++ set a mandatory field to NULL. ++ ++ This currently only works for some fields specifically a SEQUENCE, CHOICE, ++ or ASN1_STRING type which is part of a parent SEQUENCE. Since it is ++ equivalent to ASN1_SIMPLE it cannot be tagged, OPTIONAL, SET OF or ++ SEQUENCE OF. ++ [Steve Henson] ++ ++ *) Remove EVP_CHECK_DES_KEY, a compile-time option that never compiled. ++ [Emilia Käsper] ++ ++ *) Removed DES and RC4 ciphersuites from DEFAULT. Also removed RC2 although ++ in 1.0.2 EXPORT was already removed and the only RC2 ciphersuite is also ++ an EXPORT one. COMPLEMENTOFDEFAULT has been updated accordingly to add ++ DES and RC4 ciphersuites. ++ [Matt Caswell] ++ ++ *) Rewrite EVP_DecodeUpdate (base64 decoding) to fix several bugs. ++ This changes the decoding behaviour for some invalid messages, ++ though the change is mostly in the more lenient direction, and ++ legacy behaviour is preserved as much as possible. ++ [Emilia Käsper] ++ ++ *) Fix no-stdio build. ++ [ David Woodhouse and also ++ Ivan Nestlerode ] ++ ++ *) New testing framework ++ The testing framework has been largely rewritten and is now using ++ perl and the perl modules Test::Harness and an extended variant of ++ Test::More called OpenSSL::Test to do its work. All test scripts in ++ test/ have been rewritten into test recipes, and all direct calls to ++ executables in test/Makefile have become individual recipes using the ++ simplified testing OpenSSL::Test::Simple. ++ ++ For documentation on our testing modules, do: ++ ++ perldoc test/testlib/OpenSSL/Test/Simple.pm ++ perldoc test/testlib/OpenSSL/Test.pm ++ ++ [Richard Levitte] ++ ++ *) Revamped memory debug; only -DCRYPTO_MDEBUG and -DCRYPTO_MDEBUG_ABORT ++ are used; the latter aborts on memory leaks (usually checked on exit). ++ Some undocumented "set malloc, etc., hooks" functions were removed ++ and others were changed. All are now documented. ++ [Rich Salz] ++ ++ *) In DSA_generate_parameters_ex, if the provided seed is too short, ++ return an error ++ [Rich Salz and Ismo Puustinen ] ++ ++ *) Rewrite PSK to support ECDHE_PSK, DHE_PSK and RSA_PSK. Add ciphersuites ++ from RFC4279, RFC4785, RFC5487, RFC5489. ++ ++ Thanks to Christian J. Dietrich and Giuseppe D'Angelo for the ++ original RSA_PSK patch. ++ [Steve Henson] ++ ++ *) Dropped support for the SSL3_FLAGS_DELAY_CLIENT_FINISHED flag. This SSLeay ++ era flag was never set throughout the codebase (only read). Also removed ++ SSL3_FLAGS_POP_BUFFER which was only used if ++ SSL3_FLAGS_DELAY_CLIENT_FINISHED was also set. ++ [Matt Caswell] ++ ++ *) Changed the default name options in the "ca", "crl", "req" and "x509" ++ to be "oneline" instead of "compat". ++ [Richard Levitte] ++ ++ *) Remove SSL_OP_TLS_BLOCK_PADDING_BUG. This is SSLeay legacy, we're ++ not aware of clients that still exhibit this bug, and the workaround ++ hasn't been working properly for a while. ++ [Emilia Käsper] ++ ++ *) The return type of BIO_number_read() and BIO_number_written() as well as ++ the corresponding num_read and num_write members in the BIO structure has ++ changed from unsigned long to uint64_t. On platforms where an unsigned ++ long is 32 bits (e.g. Windows) these counters could overflow if >4Gb is ++ transferred. ++ [Matt Caswell] ++ ++ *) Given the pervasive nature of TLS extensions it is inadvisable to run ++ OpenSSL without support for them. It also means that maintaining ++ the OPENSSL_NO_TLSEXT option within the code is very invasive (and probably ++ not well tested). Therefore the OPENSSL_NO_TLSEXT option has been removed. ++ [Matt Caswell] ++ ++ *) Removed support for the two export grade static DH ciphersuites ++ EXP-DH-RSA-DES-CBC-SHA and EXP-DH-DSS-DES-CBC-SHA. These two ciphersuites ++ were newly added (along with a number of other static DH ciphersuites) to ++ 1.0.2. However the two export ones have *never* worked since they were ++ introduced. It seems strange in any case to be adding new export ++ ciphersuites, and given "logjam" it also does not seem correct to fix them. ++ [Matt Caswell] ++ ++ *) Version negotiation has been rewritten. In particular SSLv23_method(), ++ SSLv23_client_method() and SSLv23_server_method() have been deprecated, ++ and turned into macros which simply call the new preferred function names ++ TLS_method(), TLS_client_method() and TLS_server_method(). All new code ++ should use the new names instead. Also as part of this change the ssl23.h ++ header file has been removed. ++ [Matt Caswell] ++ ++ *) Support for Kerberos ciphersuites in TLS (RFC2712) has been removed. This ++ code and the associated standard is no longer considered fit-for-purpose. ++ [Matt Caswell] ++ ++ *) RT2547 was closed. When generating a private key, try to make the ++ output file readable only by the owner. This behavior change might ++ be noticeable when interacting with other software. ++ ++ *) Documented all exdata functions. Added CRYPTO_free_ex_index. ++ Added a test. ++ [Rich Salz] ++ ++ *) Added HTTP GET support to the ocsp command. ++ [Rich Salz] ++ ++ *) Changed default digest for the dgst and enc commands from MD5 to ++ sha256 ++ [Rich Salz] ++ ++ *) RAND_pseudo_bytes has been deprecated. Users should use RAND_bytes instead. ++ [Matt Caswell] ++ ++ *) Added support for TLS extended master secret from ++ draft-ietf-tls-session-hash-03.txt. Thanks for Alfredo Pironti for an ++ initial patch which was a great help during development. ++ [Steve Henson] ++ ++ *) All libssl internal structures have been removed from the public header ++ files, and the OPENSSL_NO_SSL_INTERN option has been removed (since it is ++ now redundant). Users should not attempt to access internal structures ++ directly. Instead they should use the provided API functions. ++ [Matt Caswell] ++ ++ *) config has been changed so that by default OPENSSL_NO_DEPRECATED is used. ++ Access to deprecated functions can be re-enabled by running config with ++ "enable-deprecated". In addition applications wishing to use deprecated ++ functions must define OPENSSL_USE_DEPRECATED. Note that this new behaviour ++ will, by default, disable some transitive includes that previously existed ++ in the header files (e.g. ec.h will no longer, by default, include bn.h) ++ [Matt Caswell] ++ ++ *) Added support for OCB mode. OpenSSL has been granted a patent license ++ compatible with the OpenSSL license for use of OCB. Details are available ++ at https://www.openssl.org/source/OCB-patent-grant-OpenSSL.pdf. Support ++ for OCB can be removed by calling config with no-ocb. ++ [Matt Caswell] ++ ++ *) SSLv2 support has been removed. It still supports receiving a SSLv2 ++ compatible client hello. ++ [Kurt Roeckx] ++ ++ *) Increased the minimal RSA keysize from 256 to 512 bits [Rich Salz], ++ done while fixing the error code for the key-too-small case. ++ [Annie Yousar ] ++ ++ *) CA.sh has been removmed; use CA.pl instead. ++ [Rich Salz] ++ ++ *) Removed old DES API. ++ [Rich Salz] ++ ++ *) Remove various unsupported platforms: ++ Sony NEWS4 ++ BEOS and BEOS_R5 ++ NeXT ++ SUNOS ++ MPE/iX ++ Sinix/ReliantUNIX RM400 ++ DGUX ++ NCR ++ Tandem ++ Cray ++ 16-bit platforms such as WIN16 ++ [Rich Salz] ++ ++ *) Clean up OPENSSL_NO_xxx #define's ++ Use setbuf() and remove OPENSSL_NO_SETVBUF_IONBF ++ Rename OPENSSL_SYSNAME_xxx to OPENSSL_SYS_xxx ++ OPENSSL_NO_EC{DH,DSA} merged into OPENSSL_NO_EC ++ OPENSSL_NO_RIPEMD160, OPENSSL_NO_RIPEMD merged into OPENSSL_NO_RMD160 ++ OPENSSL_NO_FP_API merged into OPENSSL_NO_STDIO ++ Remove OPENSSL_NO_BIO OPENSSL_NO_BUFFER OPENSSL_NO_CHAIN_VERIFY ++ OPENSSL_NO_EVP OPENSSL_NO_FIPS_ERR OPENSSL_NO_HASH_COMP ++ OPENSSL_NO_LHASH OPENSSL_NO_OBJECT OPENSSL_NO_SPEED OPENSSL_NO_STACK ++ OPENSSL_NO_X509 OPENSSL_NO_X509_VERIFY ++ Remove MS_STATIC; it's a relic from platforms <32 bits. ++ [Rich Salz] ++ ++ *) Cleaned up dead code ++ Remove all but one '#ifdef undef' which is to be looked at. ++ [Rich Salz] ++ ++ *) Clean up calling of xxx_free routines. ++ Just like free(), fix most of the xxx_free routines to accept ++ NULL. Remove the non-null checks from callers. Save much code. ++ [Rich Salz] ++ ++ *) Add secure heap for storage of private keys (when possible). ++ Add BIO_s_secmem(), CBIGNUM, etc. ++ Contributed by Akamai Technologies under our Corporate CLA. ++ [Rich Salz] ++ ++ *) Experimental support for a new, fast, unbiased prime candidate generator, ++ bn_probable_prime_dh_coprime(). Not currently used by any prime generator. ++ [Felix Laurie von Massenbach ] ++ ++ *) New output format NSS in the sess_id command line tool. This allows ++ exporting the session id and the master key in NSS keylog format. ++ [Martin Kaiser ] ++ ++ *) Harmonize version and its documentation. -f flag is used to display ++ compilation flags. ++ [mancha ] ++ ++ *) Fix eckey_priv_encode so it immediately returns an error upon a failure ++ in i2d_ECPrivateKey. Thanks to Ted Unangst for feedback on this issue. ++ [mancha ] ++ ++ *) Fix some double frees. These are not thought to be exploitable. ++ [mancha ] ++ ++ *) A missing bounds check in the handling of the TLS heartbeat extension ++ can be used to reveal up to 64k of memory to a connected client or ++ server. ++ ++ Thanks for Neel Mehta of Google Security for discovering this bug and to ++ Adam Langley and Bodo Moeller for ++ preparing the fix (CVE-2014-0160) ++ [Adam Langley, Bodo Moeller] ++ ++ *) Fix for the attack described in the paper "Recovering OpenSSL ++ ECDSA Nonces Using the FLUSH+RELOAD Cache Side-channel Attack" ++ by Yuval Yarom and Naomi Benger. Details can be obtained from: ++ http://eprint.iacr.org/2014/140 ++ ++ Thanks to Yuval Yarom and Naomi Benger for discovering this ++ flaw and to Yuval Yarom for supplying a fix (CVE-2014-0076) ++ [Yuval Yarom and Naomi Benger] ++ ++ *) Use algorithm specific chains in SSL_CTX_use_certificate_chain_file(): ++ this fixes a limitation in previous versions of OpenSSL. ++ [Steve Henson] ++ ++ *) Experimental encrypt-then-mac support. ++ ++ Experimental support for encrypt then mac from ++ draft-gutmann-tls-encrypt-then-mac-02.txt ++ ++ To enable it set the appropriate extension number (0x42 for the test ++ server) using e.g. -DTLSEXT_TYPE_encrypt_then_mac=0x42 ++ ++ For non-compliant peers (i.e. just about everything) this should have no ++ effect. ++ ++ WARNING: EXPERIMENTAL, SUBJECT TO CHANGE. ++ ++ [Steve Henson] ++ ++ *) Add EVP support for key wrapping algorithms, to avoid problems with ++ existing code the flag EVP_CIPHER_CTX_WRAP_ALLOW has to be set in ++ the EVP_CIPHER_CTX or an error is returned. Add AES and DES3 wrap ++ algorithms and include tests cases. ++ [Steve Henson] ++ ++ *) Extend CMS code to support RSA-PSS signatures and RSA-OAEP for ++ enveloped data. ++ [Steve Henson] ++ ++ *) Extended RSA OAEP support via EVP_PKEY API. Options to specify digest, ++ MGF1 digest and OAEP label. ++ [Steve Henson] ++ ++ *) Make openssl verify return errors. ++ [Chris Palmer and Ben Laurie] ++ ++ *) New function ASN1_TIME_diff to calculate the difference between two ++ ASN1_TIME structures or one structure and the current time. ++ [Steve Henson] ++ ++ *) Update fips_test_suite to support multiple command line options. New ++ test to induce all self test errors in sequence and check expected ++ failures. ++ [Steve Henson] ++ ++ *) Add FIPS_{rsa,dsa,ecdsa}_{sign,verify} functions which digest and ++ sign or verify all in one operation. ++ [Steve Henson] ++ ++ *) Add fips_algvs: a multicall fips utility incorporating all the algorithm ++ test programs and fips_test_suite. Includes functionality to parse ++ the minimal script output of fipsalgest.pl directly. ++ [Steve Henson] ++ ++ *) Add authorisation parameter to FIPS_module_mode_set(). ++ [Steve Henson] ++ ++ *) Add FIPS selftest for ECDH algorithm using P-224 and B-233 curves. ++ [Steve Henson] ++ ++ *) Use separate DRBG fields for internal and external flags. New function ++ FIPS_drbg_health_check() to perform on demand health checking. Add ++ generation tests to fips_test_suite with reduced health check interval to ++ demonstrate periodic health checking. Add "nodh" option to ++ fips_test_suite to skip very slow DH test. ++ [Steve Henson] ++ ++ *) New function FIPS_get_cipherbynid() to lookup FIPS supported ciphers ++ based on NID. ++ [Steve Henson] ++ ++ *) More extensive health check for DRBG checking many more failure modes. ++ New function FIPS_selftest_drbg_all() to handle every possible DRBG ++ combination: call this in fips_test_suite. ++ [Steve Henson] ++ ++ *) Add support for canonical generation of DSA parameter 'g'. See ++ FIPS 186-3 A.2.3. ++ ++ *) Add support for HMAC DRBG from SP800-90. Update DRBG algorithm test and ++ POST to handle HMAC cases. ++ [Steve Henson] ++ ++ *) Add functions FIPS_module_version() and FIPS_module_version_text() ++ to return numerical and string versions of the FIPS module number. ++ [Steve Henson] ++ ++ *) Rename FIPS_mode_set and FIPS_mode to FIPS_module_mode_set and ++ FIPS_module_mode. FIPS_mode and FIPS_mode_set will be implemented ++ outside the validated module in the FIPS capable OpenSSL. ++ [Steve Henson] ++ ++ *) Minor change to DRBG entropy callback semantics. In some cases ++ there is no multiple of the block length between min_len and ++ max_len. Allow the callback to return more than max_len bytes ++ of entropy but discard any extra: it is the callback's responsibility ++ to ensure that the extra data discarded does not impact the ++ requested amount of entropy. ++ [Steve Henson] ++ ++ *) Add PRNG security strength checks to RSA, DSA and ECDSA using ++ information in FIPS186-3, SP800-57 and SP800-131A. ++ [Steve Henson] ++ ++ *) CCM support via EVP. Interface is very similar to GCM case except we ++ must supply all data in one chunk (i.e. no update, final) and the ++ message length must be supplied if AAD is used. Add algorithm test ++ support. ++ [Steve Henson] ++ ++ *) Initial version of POST overhaul. Add POST callback to allow the status ++ of POST to be monitored and/or failures induced. Modify fips_test_suite ++ to use callback. Always run all selftests even if one fails. ++ [Steve Henson] ++ ++ *) XTS support including algorithm test driver in the fips_gcmtest program. ++ Note: this does increase the maximum key length from 32 to 64 bytes but ++ there should be no binary compatibility issues as existing applications ++ will never use XTS mode. ++ [Steve Henson] ++ ++ *) Extensive reorganisation of FIPS PRNG behaviour. Remove all dependencies ++ to OpenSSL RAND code and replace with a tiny FIPS RAND API which also ++ performs algorithm blocking for unapproved PRNG types. Also do not ++ set PRNG type in FIPS_mode_set(): leave this to the application. ++ Add default OpenSSL DRBG handling: sets up FIPS PRNG and seeds with ++ the standard OpenSSL PRNG: set additional data to a date time vector. ++ [Steve Henson] ++ ++ *) Rename old X9.31 PRNG functions of the form FIPS_rand* to FIPS_x931*. ++ This shouldn't present any incompatibility problems because applications ++ shouldn't be using these directly and any that are will need to rethink ++ anyway as the X9.31 PRNG is now deprecated by FIPS 140-2 ++ [Steve Henson] ++ ++ *) Extensive self tests and health checking required by SP800-90 DRBG. ++ Remove strength parameter from FIPS_drbg_instantiate and always ++ instantiate at maximum supported strength. ++ [Steve Henson] ++ ++ *) Add ECDH code to fips module and fips_ecdhvs for primitives only testing. ++ [Steve Henson] ++ ++ *) New algorithm test program fips_dhvs to handle DH primitives only testing. ++ [Steve Henson] ++ ++ *) New function DH_compute_key_padded() to compute a DH key and pad with ++ leading zeroes if needed: this complies with SP800-56A et al. ++ [Steve Henson] ++ ++ *) Initial implementation of SP800-90 DRBGs for Hash and CTR. Not used by ++ anything, incomplete, subject to change and largely untested at present. ++ [Steve Henson] ++ ++ *) Modify fipscanisteronly build option to only build the necessary object ++ files by filtering FIPS_EX_OBJ through a perl script in crypto/Makefile. ++ [Steve Henson] ++ ++ *) Add experimental option FIPSSYMS to give all symbols in ++ fipscanister.o and FIPS or fips prefix. This will avoid ++ conflicts with future versions of OpenSSL. Add perl script ++ util/fipsas.pl to preprocess assembly language source files ++ and rename any affected symbols. ++ [Steve Henson] ++ ++ *) Add selftest checks and algorithm block of non-fips algorithms in ++ FIPS mode. Remove DES2 from selftests. ++ [Steve Henson] ++ ++ *) Add ECDSA code to fips module. Add tiny fips_ecdsa_check to just ++ return internal method without any ENGINE dependencies. Add new ++ tiny fips sign and verify functions. ++ [Steve Henson] ++ ++ *) New build option no-ec2m to disable characteristic 2 code. ++ [Steve Henson] ++ ++ *) New build option "fipscanisteronly". This only builds fipscanister.o ++ and (currently) associated fips utilities. Uses the file Makefile.fips ++ instead of Makefile.org as the prototype. ++ [Steve Henson] ++ ++ *) Add some FIPS mode restrictions to GCM. Add internal IV generator. ++ Update fips_gcmtest to use IV generator. ++ [Steve Henson] ++ ++ *) Initial, experimental EVP support for AES-GCM. AAD can be input by ++ setting output buffer to NULL. The *Final function must be ++ called although it will not retrieve any additional data. The tag ++ can be set or retrieved with a ctrl. The IV length is by default 12 ++ bytes (96 bits) but can be set to an alternative value. If the IV ++ length exceeds the maximum IV length (currently 16 bytes) it cannot be ++ set before the key. ++ [Steve Henson] ++ ++ *) New flag in ciphers: EVP_CIPH_FLAG_CUSTOM_CIPHER. This means the ++ underlying do_cipher function handles all cipher semantics itself ++ including padding and finalisation. This is useful if (for example) ++ an ENGINE cipher handles block padding itself. The behaviour of ++ do_cipher is subtly changed if this flag is set: the return value ++ is the number of characters written to the output buffer (zero is ++ no longer an error code) or a negative error code. Also if the ++ input buffer is NULL and length 0 finalisation should be performed. ++ [Steve Henson] ++ ++ *) If a candidate issuer certificate is already part of the constructed ++ path ignore it: new debug notification X509_V_ERR_PATH_LOOP for this case. ++ [Steve Henson] ++ ++ *) Improve forward-security support: add functions ++ ++ void SSL_CTX_set_not_resumable_session_callback(SSL_CTX *ctx, int (*cb)(SSL *ssl, int is_forward_secure)) ++ void SSL_set_not_resumable_session_callback(SSL *ssl, int (*cb)(SSL *ssl, int is_forward_secure)) ++ ++ for use by SSL/TLS servers; the callback function will be called whenever a ++ new session is created, and gets to decide whether the session may be ++ cached to make it resumable (return 0) or not (return 1). (As by the ++ SSL/TLS protocol specifications, the session_id sent by the server will be ++ empty to indicate that the session is not resumable; also, the server will ++ not generate RFC 4507 (RFC 5077) session tickets.) ++ ++ A simple reasonable callback implementation is to return is_forward_secure. ++ This parameter will be set to 1 or 0 depending on the ciphersuite selected ++ by the SSL/TLS server library, indicating whether it can provide forward ++ security. ++ [Emilia Käsper (Google)] ++ ++ *) New -verify_name option in command line utilities to set verification ++ parameters by name. ++ [Steve Henson] ++ ++ *) Initial CMAC implementation. WARNING: EXPERIMENTAL, API MAY CHANGE. ++ Add CMAC pkey methods. ++ [Steve Henson] ++ ++ *) Experimental renegotiation in s_server -www mode. If the client ++ browses /reneg connection is renegotiated. If /renegcert it is ++ renegotiated requesting a certificate. ++ [Steve Henson] ++ ++ *) Add an "external" session cache for debugging purposes to s_server. This ++ should help trace issues which normally are only apparent in deployed ++ multi-process servers. ++ [Steve Henson] ++ ++ *) Extensive audit of libcrypto with DEBUG_UNUSED. Fix many cases where ++ return value is ignored. NB. The functions RAND_add(), RAND_seed(), ++ BIO_set_cipher() and some obscure PEM functions were changed so they ++ can now return an error. The RAND changes required a change to the ++ RAND_METHOD structure. ++ [Steve Henson] ++ ++ *) New macro __owur for "OpenSSL Warn Unused Result". This makes use of ++ a gcc attribute to warn if the result of a function is ignored. This ++ is enable if DEBUG_UNUSED is set. Add to several functions in evp.h ++ whose return value is often ignored. ++ [Steve Henson] ++ ++ *) New -noct, -requestct, -requirect and -ctlogfile options for s_client. ++ These allow SCTs (signed certificate timestamps) to be requested and ++ validated when establishing a connection. ++ [Rob Percival ] ++ ++ Changes between 1.0.2g and 1.0.2h [3 May 2016] ++ ++ *) Prevent padding oracle in AES-NI CBC MAC check ++ ++ A MITM attacker can use a padding oracle attack to decrypt traffic ++ when the connection uses an AES CBC cipher and the server support ++ AES-NI. ++ ++ This issue was introduced as part of the fix for Lucky 13 padding ++ attack (CVE-2013-0169). The padding check was rewritten to be in ++ constant time by making sure that always the same bytes are read and ++ compared against either the MAC or padding bytes. But it no longer ++ checked that there was enough data to have both the MAC and padding ++ bytes. ++ ++ This issue was reported by Juraj Somorovsky using TLS-Attacker. ++ (CVE-2016-2107) ++ [Kurt Roeckx] ++ ++ *) Fix EVP_EncodeUpdate overflow ++ ++ An overflow can occur in the EVP_EncodeUpdate() function which is used for ++ Base64 encoding of binary data. If an attacker is able to supply very large ++ amounts of input data then a length check can overflow resulting in a heap ++ corruption. ++ ++ Internally to OpenSSL the EVP_EncodeUpdate() function is primarily used by ++ the PEM_write_bio* family of functions. These are mainly used within the ++ OpenSSL command line applications, so any application which processes data ++ from an untrusted source and outputs it as a PEM file should be considered ++ vulnerable to this issue. User applications that call these APIs directly ++ with large amounts of untrusted data may also be vulnerable. ++ ++ This issue was reported by Guido Vranken. ++ (CVE-2016-2105) ++ [Matt Caswell] ++ ++ *) Fix EVP_EncryptUpdate overflow ++ ++ An overflow can occur in the EVP_EncryptUpdate() function. If an attacker ++ is able to supply very large amounts of input data after a previous call to ++ EVP_EncryptUpdate() with a partial block then a length check can overflow ++ resulting in a heap corruption. Following an analysis of all OpenSSL ++ internal usage of the EVP_EncryptUpdate() function all usage is one of two ++ forms. The first form is where the EVP_EncryptUpdate() call is known to be ++ the first called function after an EVP_EncryptInit(), and therefore that ++ specific call must be safe. The second form is where the length passed to ++ EVP_EncryptUpdate() can be seen from the code to be some small value and ++ therefore there is no possibility of an overflow. Since all instances are ++ one of these two forms, it is believed that there can be no overflows in ++ internal code due to this problem. It should be noted that ++ EVP_DecryptUpdate() can call EVP_EncryptUpdate() in certain code paths. ++ Also EVP_CipherUpdate() is a synonym for EVP_EncryptUpdate(). All instances ++ of these calls have also been analysed too and it is believed there are no ++ instances in internal usage where an overflow could occur. ++ ++ This issue was reported by Guido Vranken. ++ (CVE-2016-2106) ++ [Matt Caswell] ++ ++ *) Prevent ASN.1 BIO excessive memory allocation ++ ++ When ASN.1 data is read from a BIO using functions such as d2i_CMS_bio() ++ a short invalid encoding can cause allocation of large amounts of memory ++ potentially consuming excessive resources or exhausting memory. ++ ++ Any application parsing untrusted data through d2i BIO functions is ++ affected. The memory based functions such as d2i_X509() are *not* affected. ++ Since the memory based functions are used by the TLS library, TLS ++ applications are not affected. ++ ++ This issue was reported by Brian Carpenter. ++ (CVE-2016-2109) ++ [Stephen Henson] ++ ++ *) EBCDIC overread ++ ++ ASN1 Strings that are over 1024 bytes can cause an overread in applications ++ using the X509_NAME_oneline() function on EBCDIC systems. This could result ++ in arbitrary stack data being returned in the buffer. ++ ++ This issue was reported by Guido Vranken. ++ (CVE-2016-2176) ++ [Matt Caswell] ++ ++ *) Modify behavior of ALPN to invoke callback after SNI/servername ++ callback, such that updates to the SSL_CTX affect ALPN. ++ [Todd Short] ++ ++ *) Remove LOW from the DEFAULT cipher list. This removes singles DES from the ++ default. ++ [Kurt Roeckx] ++ ++ *) Only remove the SSLv2 methods with the no-ssl2-method option. When the ++ methods are enabled and ssl2 is disabled the methods return NULL. ++ [Kurt Roeckx] ++ ++ Changes between 1.0.2f and 1.0.2g [1 Mar 2016] ++ ++ * Disable weak ciphers in SSLv3 and up in default builds of OpenSSL. ++ Builds that are not configured with "enable-weak-ssl-ciphers" will not ++ provide any "EXPORT" or "LOW" strength ciphers. ++ [Viktor Dukhovni] ++ ++ * Disable SSLv2 default build, default negotiation and weak ciphers. SSLv2 ++ is by default disabled at build-time. Builds that are not configured with ++ "enable-ssl2" will not support SSLv2. Even if "enable-ssl2" is used, ++ users who want to negotiate SSLv2 via the version-flexible SSLv23_method() ++ will need to explicitly call either of: ++ ++ SSL_CTX_clear_options(ctx, SSL_OP_NO_SSLv2); ++ or ++ SSL_clear_options(ssl, SSL_OP_NO_SSLv2); ++ ++ as appropriate. Even if either of those is used, or the application ++ explicitly uses the version-specific SSLv2_method() or its client and ++ server variants, SSLv2 ciphers vulnerable to exhaustive search key ++ recovery have been removed. Specifically, the SSLv2 40-bit EXPORT ++ ciphers, and SSLv2 56-bit DES are no longer available. ++ (CVE-2016-0800) ++ [Viktor Dukhovni] ++ ++ *) Fix a double-free in DSA code ++ ++ A double free bug was discovered when OpenSSL parses malformed DSA private ++ keys and could lead to a DoS attack or memory corruption for applications ++ that receive DSA private keys from untrusted sources. This scenario is ++ considered rare. ++ ++ This issue was reported to OpenSSL by Adam Langley(Google/BoringSSL) using ++ libFuzzer. ++ (CVE-2016-0705) ++ [Stephen Henson] ++ ++ *) Disable SRP fake user seed to address a server memory leak. ++ ++ Add a new method SRP_VBASE_get1_by_user that handles the seed properly. ++ ++ SRP_VBASE_get_by_user had inconsistent memory management behaviour. ++ In order to fix an unavoidable memory leak, SRP_VBASE_get_by_user ++ was changed to ignore the "fake user" SRP seed, even if the seed ++ is configured. ++ ++ Users should use SRP_VBASE_get1_by_user instead. Note that in ++ SRP_VBASE_get1_by_user, caller must free the returned value. Note ++ also that even though configuring the SRP seed attempts to hide ++ invalid usernames by continuing the handshake with fake ++ credentials, this behaviour is not constant time and no strong ++ guarantees are made that the handshake is indistinguishable from ++ that of a valid user. ++ (CVE-2016-0798) ++ [Emilia Käsper] ++ ++ *) Fix BN_hex2bn/BN_dec2bn NULL pointer deref/heap corruption ++ ++ In the BN_hex2bn function the number of hex digits is calculated using an ++ int value |i|. Later |bn_expand| is called with a value of |i * 4|. For ++ large values of |i| this can result in |bn_expand| not allocating any ++ memory because |i * 4| is negative. This can leave the internal BIGNUM data ++ field as NULL leading to a subsequent NULL ptr deref. For very large values ++ of |i|, the calculation |i * 4| could be a positive value smaller than |i|. ++ In this case memory is allocated to the internal BIGNUM data field, but it ++ is insufficiently sized leading to heap corruption. A similar issue exists ++ in BN_dec2bn. This could have security consequences if BN_hex2bn/BN_dec2bn ++ is ever called by user applications with very large untrusted hex/dec data. ++ This is anticipated to be a rare occurrence. ++ ++ All OpenSSL internal usage of these functions use data that is not expected ++ to be untrusted, e.g. config file data or application command line ++ arguments. If user developed applications generate config file data based ++ on untrusted data then it is possible that this could also lead to security ++ consequences. This is also anticipated to be rare. ++ ++ This issue was reported to OpenSSL by Guido Vranken. ++ (CVE-2016-0797) ++ [Matt Caswell] ++ ++ *) Fix memory issues in BIO_*printf functions ++ ++ The internal |fmtstr| function used in processing a "%s" format string in ++ the BIO_*printf functions could overflow while calculating the length of a ++ string and cause an OOB read when printing very long strings. ++ ++ Additionally the internal |doapr_outch| function can attempt to write to an ++ OOB memory location (at an offset from the NULL pointer) in the event of a ++ memory allocation failure. In 1.0.2 and below this could be caused where ++ the size of a buffer to be allocated is greater than INT_MAX. E.g. this ++ could be in processing a very long "%s" format string. Memory leaks can ++ also occur. ++ ++ The first issue may mask the second issue dependent on compiler behaviour. ++ These problems could enable attacks where large amounts of untrusted data ++ is passed to the BIO_*printf functions. If applications use these functions ++ in this way then they could be vulnerable. OpenSSL itself uses these ++ functions when printing out human-readable dumps of ASN.1 data. Therefore ++ applications that print this data could be vulnerable if the data is from ++ untrusted sources. OpenSSL command line applications could also be ++ vulnerable where they print out ASN.1 data, or if untrusted data is passed ++ as command line arguments. ++ ++ Libssl is not considered directly vulnerable. Additionally certificates etc ++ received via remote connections via libssl are also unlikely to be able to ++ trigger these issues because of message size limits enforced within libssl. ++ ++ This issue was reported to OpenSSL Guido Vranken. ++ (CVE-2016-0799) ++ [Matt Caswell] ++ ++ *) Side channel attack on modular exponentiation ++ ++ A side-channel attack was found which makes use of cache-bank conflicts on ++ the Intel Sandy-Bridge microarchitecture which could lead to the recovery ++ of RSA keys. The ability to exploit this issue is limited as it relies on ++ an attacker who has control of code in a thread running on the same ++ hyper-threaded core as the victim thread which is performing decryptions. ++ ++ This issue was reported to OpenSSL by Yuval Yarom, The University of ++ Adelaide and NICTA, Daniel Genkin, Technion and Tel Aviv University, and ++ Nadia Heninger, University of Pennsylvania with more information at ++ http://cachebleed.info. ++ (CVE-2016-0702) ++ [Andy Polyakov] ++ ++ *) Change the req app to generate a 2048-bit RSA/DSA key by default, ++ if no keysize is specified with default_bits. This fixes an ++ omission in an earlier change that changed all RSA/DSA key generation ++ apps to use 2048 bits by default. ++ [Emilia Käsper] ++ ++ Changes between 1.0.2e and 1.0.2f [28 Jan 2016] ++ *) DH small subgroups ++ ++ Historically OpenSSL only ever generated DH parameters based on "safe" ++ primes. More recently (in version 1.0.2) support was provided for ++ generating X9.42 style parameter files such as those required for RFC 5114 ++ support. The primes used in such files may not be "safe". Where an ++ application is using DH configured with parameters based on primes that are ++ not "safe" then an attacker could use this fact to find a peer's private ++ DH exponent. This attack requires that the attacker complete multiple ++ handshakes in which the peer uses the same private DH exponent. For example ++ this could be used to discover a TLS server's private DH exponent if it's ++ reusing the private DH exponent or it's using a static DH ciphersuite. ++ ++ OpenSSL provides the option SSL_OP_SINGLE_DH_USE for ephemeral DH (DHE) in ++ TLS. It is not on by default. If the option is not set then the server ++ reuses the same private DH exponent for the life of the server process and ++ would be vulnerable to this attack. It is believed that many popular ++ applications do set this option and would therefore not be at risk. ++ ++ The fix for this issue adds an additional check where a "q" parameter is ++ available (as is the case in X9.42 based parameters). This detects the ++ only known attack, and is the only possible defense for static DH ++ ciphersuites. This could have some performance impact. ++ ++ Additionally the SSL_OP_SINGLE_DH_USE option has been switched on by ++ default and cannot be disabled. This could have some performance impact. ++ ++ This issue was reported to OpenSSL by Antonio Sanso (Adobe). ++ (CVE-2016-0701) ++ [Matt Caswell] ++ ++ *) SSLv2 doesn't block disabled ciphers ++ ++ A malicious client can negotiate SSLv2 ciphers that have been disabled on ++ the server and complete SSLv2 handshakes even if all SSLv2 ciphers have ++ been disabled, provided that the SSLv2 protocol was not also disabled via ++ SSL_OP_NO_SSLv2. ++ ++ This issue was reported to OpenSSL on 26th December 2015 by Nimrod Aviram ++ and Sebastian Schinzel. ++ (CVE-2015-3197) ++ [Viktor Dukhovni] ++ ++ Changes between 1.0.2d and 1.0.2e [3 Dec 2015] ++ ++ *) BN_mod_exp may produce incorrect results on x86_64 ++ ++ There is a carry propagating bug in the x86_64 Montgomery squaring ++ procedure. No EC algorithms are affected. Analysis suggests that attacks ++ against RSA and DSA as a result of this defect would be very difficult to ++ perform and are not believed likely. Attacks against DH are considered just ++ feasible (although very difficult) because most of the work necessary to ++ deduce information about a private key may be performed offline. The amount ++ of resources required for such an attack would be very significant and ++ likely only accessible to a limited number of attackers. An attacker would ++ additionally need online access to an unpatched system using the target ++ private key in a scenario with persistent DH parameters and a private ++ key that is shared between multiple clients. For example this can occur by ++ default in OpenSSL DHE based SSL/TLS ciphersuites. ++ ++ This issue was reported to OpenSSL by Hanno Böck. ++ (CVE-2015-3193) ++ [Andy Polyakov] ++ ++ *) Certificate verify crash with missing PSS parameter ++ ++ The signature verification routines will crash with a NULL pointer ++ dereference if presented with an ASN.1 signature using the RSA PSS ++ algorithm and absent mask generation function parameter. Since these ++ routines are used to verify certificate signature algorithms this can be ++ used to crash any certificate verification operation and exploited in a ++ DoS attack. Any application which performs certificate verification is ++ vulnerable including OpenSSL clients and servers which enable client ++ authentication. ++ ++ This issue was reported to OpenSSL by Loïc Jonas Etienne (Qnective AG). ++ (CVE-2015-3194) ++ [Stephen Henson] ++ ++ *) X509_ATTRIBUTE memory leak ++ ++ When presented with a malformed X509_ATTRIBUTE structure OpenSSL will leak ++ memory. This structure is used by the PKCS#7 and CMS routines so any ++ application which reads PKCS#7 or CMS data from untrusted sources is ++ affected. SSL/TLS is not affected. ++ ++ This issue was reported to OpenSSL by Adam Langley (Google/BoringSSL) using ++ libFuzzer. ++ (CVE-2015-3195) ++ [Stephen Henson] ++ ++ *) Rewrite EVP_DecodeUpdate (base64 decoding) to fix several bugs. ++ This changes the decoding behaviour for some invalid messages, ++ though the change is mostly in the more lenient direction, and ++ legacy behaviour is preserved as much as possible. ++ [Emilia Käsper] ++ ++ *) In DSA_generate_parameters_ex, if the provided seed is too short, ++ return an error ++ [Rich Salz and Ismo Puustinen ] ++ ++ Changes between 1.0.2c and 1.0.2d [9 Jul 2015] ++ ++ *) Alternate chains certificate forgery ++ ++ During certificate verification, OpenSSL will attempt to find an ++ alternative certificate chain if the first attempt to build such a chain ++ fails. An error in the implementation of this logic can mean that an ++ attacker could cause certain checks on untrusted certificates to be ++ bypassed, such as the CA flag, enabling them to use a valid leaf ++ certificate to act as a CA and "issue" an invalid certificate. ++ ++ This issue was reported to OpenSSL by Adam Langley/David Benjamin ++ (Google/BoringSSL). ++ [Matt Caswell] ++ ++ Changes between 1.0.2b and 1.0.2c [12 Jun 2015] ++ ++ *) Fix HMAC ABI incompatibility. The previous version introduced an ABI ++ incompatibility in the handling of HMAC. The previous ABI has now been ++ restored. ++ [Matt Caswell] ++ ++ Changes between 1.0.2a and 1.0.2b [11 Jun 2015] ++ ++ *) Malformed ECParameters causes infinite loop ++ ++ When processing an ECParameters structure OpenSSL enters an infinite loop ++ if the curve specified is over a specially malformed binary polynomial ++ field. ++ ++ This can be used to perform denial of service against any ++ system which processes public keys, certificate requests or ++ certificates. This includes TLS clients and TLS servers with ++ client authentication enabled. ++ ++ This issue was reported to OpenSSL by Joseph Barr-Pixton. ++ (CVE-2015-1788) ++ [Andy Polyakov] ++ ++ *) Exploitable out-of-bounds read in X509_cmp_time ++ ++ X509_cmp_time does not properly check the length of the ASN1_TIME ++ string and can read a few bytes out of bounds. In addition, ++ X509_cmp_time accepts an arbitrary number of fractional seconds in the ++ time string. ++ ++ An attacker can use this to craft malformed certificates and CRLs of ++ various sizes and potentially cause a segmentation fault, resulting in ++ a DoS on applications that verify certificates or CRLs. TLS clients ++ that verify CRLs are affected. TLS clients and servers with client ++ authentication enabled may be affected if they use custom verification ++ callbacks. ++ ++ This issue was reported to OpenSSL by Robert Swiecki (Google), and ++ independently by Hanno Böck. ++ (CVE-2015-1789) ++ [Emilia Käsper] ++ ++ *) PKCS7 crash with missing EnvelopedContent ++ ++ The PKCS#7 parsing code does not handle missing inner EncryptedContent ++ correctly. An attacker can craft malformed ASN.1-encoded PKCS#7 blobs ++ with missing content and trigger a NULL pointer dereference on parsing. ++ ++ Applications that decrypt PKCS#7 data or otherwise parse PKCS#7 ++ structures from untrusted sources are affected. OpenSSL clients and ++ servers are not affected. ++ ++ This issue was reported to OpenSSL by Michal Zalewski (Google). ++ (CVE-2015-1790) ++ [Emilia Käsper] ++ ++ *) CMS verify infinite loop with unknown hash function ++ ++ When verifying a signedData message the CMS code can enter an infinite loop ++ if presented with an unknown hash function OID. This can be used to perform ++ denial of service against any system which verifies signedData messages using ++ the CMS code. ++ This issue was reported to OpenSSL by Johannes Bauer. ++ (CVE-2015-1792) ++ [Stephen Henson] ++ ++ *) Race condition handling NewSessionTicket ++ ++ If a NewSessionTicket is received by a multi-threaded client when attempting to ++ reuse a previous ticket then a race condition can occur potentially leading to ++ a double free of the ticket data. ++ (CVE-2015-1791) ++ [Matt Caswell] ++ ++ *) Only support 256-bit or stronger elliptic curves with the ++ 'ecdh_auto' setting (server) or by default (client). Of supported ++ curves, prefer P-256 (both). ++ [Emilia Kasper] ++ ++ Changes between 1.0.2 and 1.0.2a [19 Mar 2015] ++ ++ *) ClientHello sigalgs DoS fix ++ ++ If a client connects to an OpenSSL 1.0.2 server and renegotiates with an ++ invalid signature algorithms extension a NULL pointer dereference will ++ occur. This can be exploited in a DoS attack against the server. ++ ++ This issue was was reported to OpenSSL by David Ramos of Stanford ++ University. ++ (CVE-2015-0291) ++ [Stephen Henson and Matt Caswell] ++ ++ *) Multiblock corrupted pointer fix ++ ++ OpenSSL 1.0.2 introduced the "multiblock" performance improvement. This ++ feature only applies on 64 bit x86 architecture platforms that support AES ++ NI instructions. A defect in the implementation of "multiblock" can cause ++ OpenSSL's internal write buffer to become incorrectly set to NULL when ++ using non-blocking IO. Typically, when the user application is using a ++ socket BIO for writing, this will only result in a failed connection. ++ However if some other BIO is used then it is likely that a segmentation ++ fault will be triggered, thus enabling a potential DoS attack. ++ ++ This issue was reported to OpenSSL by Daniel Danner and Rainer Mueller. ++ (CVE-2015-0290) ++ [Matt Caswell] ++ ++ *) Segmentation fault in DTLSv1_listen fix ++ ++ The DTLSv1_listen function is intended to be stateless and processes the ++ initial ClientHello from many peers. It is common for user code to loop ++ over the call to DTLSv1_listen until a valid ClientHello is received with ++ an associated cookie. A defect in the implementation of DTLSv1_listen means ++ that state is preserved in the SSL object from one invocation to the next ++ that can lead to a segmentation fault. Errors processing the initial ++ ClientHello can trigger this scenario. An example of such an error could be ++ that a DTLS1.0 only client is attempting to connect to a DTLS1.2 only ++ server. ++ ++ This issue was reported to OpenSSL by Per Allansson. ++ (CVE-2015-0207) ++ [Matt Caswell] ++ ++ *) Segmentation fault in ASN1_TYPE_cmp fix ++ ++ The function ASN1_TYPE_cmp will crash with an invalid read if an attempt is ++ made to compare ASN.1 boolean types. Since ASN1_TYPE_cmp is used to check ++ certificate signature algorithm consistency this can be used to crash any ++ certificate verification operation and exploited in a DoS attack. Any ++ application which performs certificate verification is vulnerable including ++ OpenSSL clients and servers which enable client authentication. ++ (CVE-2015-0286) ++ [Stephen Henson] ++ ++ *) Segmentation fault for invalid PSS parameters fix ++ ++ The signature verification routines will crash with a NULL pointer ++ dereference if presented with an ASN.1 signature using the RSA PSS ++ algorithm and invalid parameters. Since these routines are used to verify ++ certificate signature algorithms this can be used to crash any ++ certificate verification operation and exploited in a DoS attack. Any ++ application which performs certificate verification is vulnerable including ++ OpenSSL clients and servers which enable client authentication. ++ ++ This issue was was reported to OpenSSL by Brian Carpenter. ++ (CVE-2015-0208) ++ [Stephen Henson] ++ ++ *) ASN.1 structure reuse memory corruption fix ++ ++ Reusing a structure in ASN.1 parsing may allow an attacker to cause ++ memory corruption via an invalid write. Such reuse is and has been ++ strongly discouraged and is believed to be rare. ++ ++ Applications that parse structures containing CHOICE or ANY DEFINED BY ++ components may be affected. Certificate parsing (d2i_X509 and related ++ functions) are however not affected. OpenSSL clients and servers are ++ not affected. ++ (CVE-2015-0287) ++ [Stephen Henson] ++ ++ *) PKCS7 NULL pointer dereferences fix ++ ++ The PKCS#7 parsing code does not handle missing outer ContentInfo ++ correctly. An attacker can craft malformed ASN.1-encoded PKCS#7 blobs with ++ missing content and trigger a NULL pointer dereference on parsing. ++ ++ Applications that verify PKCS#7 signatures, decrypt PKCS#7 data or ++ otherwise parse PKCS#7 structures from untrusted sources are ++ affected. OpenSSL clients and servers are not affected. ++ ++ This issue was reported to OpenSSL by Michal Zalewski (Google). ++ (CVE-2015-0289) ++ [Emilia Käsper] ++ ++ *) DoS via reachable assert in SSLv2 servers fix ++ ++ A malicious client can trigger an OPENSSL_assert (i.e., an abort) in ++ servers that both support SSLv2 and enable export cipher suites by sending ++ a specially crafted SSLv2 CLIENT-MASTER-KEY message. ++ ++ This issue was discovered by Sean Burford (Google) and Emilia Käsper ++ (OpenSSL development team). ++ (CVE-2015-0293) ++ [Emilia Käsper] ++ ++ *) Empty CKE with client auth and DHE fix ++ ++ If client auth is used then a server can seg fault in the event of a DHE ++ ciphersuite being selected and a zero length ClientKeyExchange message ++ being sent by the client. This could be exploited in a DoS attack. ++ (CVE-2015-1787) ++ [Matt Caswell] ++ ++ *) Handshake with unseeded PRNG fix ++ ++ Under certain conditions an OpenSSL 1.0.2 client can complete a handshake ++ with an unseeded PRNG. The conditions are: ++ - The client is on a platform where the PRNG has not been seeded ++ automatically, and the user has not seeded manually ++ - A protocol specific client method version has been used (i.e. not ++ SSL_client_methodv23) ++ - A ciphersuite is used that does not require additional random data from ++ the PRNG beyond the initial ClientHello client random (e.g. PSK-RC4-SHA). ++ ++ If the handshake succeeds then the client random that has been used will ++ have been generated from a PRNG with insufficient entropy and therefore the ++ output may be predictable. ++ ++ For example using the following command with an unseeded openssl will ++ succeed on an unpatched platform: ++ ++ openssl s_client -psk 1a2b3c4d -tls1_2 -cipher PSK-RC4-SHA ++ (CVE-2015-0285) ++ [Matt Caswell] ++ ++ *) Use After Free following d2i_ECPrivatekey error fix ++ ++ A malformed EC private key file consumed via the d2i_ECPrivateKey function ++ could cause a use after free condition. This, in turn, could cause a double ++ free in several private key parsing functions (such as d2i_PrivateKey ++ or EVP_PKCS82PKEY) and could lead to a DoS attack or memory corruption ++ for applications that receive EC private keys from untrusted ++ sources. This scenario is considered rare. ++ ++ This issue was discovered by the BoringSSL project and fixed in their ++ commit 517073cd4b. ++ (CVE-2015-0209) ++ [Matt Caswell] ++ ++ *) X509_to_X509_REQ NULL pointer deref fix ++ ++ The function X509_to_X509_REQ will crash with a NULL pointer dereference if ++ the certificate key is invalid. This function is rarely used in practice. ++ ++ This issue was discovered by Brian Carpenter. ++ (CVE-2015-0288) ++ [Stephen Henson] ++ ++ *) Removed the export ciphers from the DEFAULT ciphers ++ [Kurt Roeckx] ++ ++ Changes between 1.0.1l and 1.0.2 [22 Jan 2015] ++ ++ *) Facilitate "universal" ARM builds targeting range of ARM ISAs, e.g. ++ ARMv5 through ARMv8, as opposite to "locking" it to single one. ++ So far those who have to target multiple platforms would compromise ++ and argue that binary targeting say ARMv5 would still execute on ++ ARMv8. "Universal" build resolves this compromise by providing ++ near-optimal performance even on newer platforms. ++ [Andy Polyakov] ++ ++ *) Accelerated NIST P-256 elliptic curve implementation for x86_64 ++ (other platforms pending). ++ [Shay Gueron & Vlad Krasnov (Intel Corp), Andy Polyakov] ++ ++ *) Add support for the SignedCertificateTimestampList certificate and ++ OCSP response extensions from RFC6962. ++ [Rob Stradling] ++ ++ *) Fix ec_GFp_simple_points_make_affine (thus, EC_POINTs_mul etc.) ++ for corner cases. (Certain input points at infinity could lead to ++ bogus results, with non-infinity inputs mapped to infinity too.) ++ [Bodo Moeller] ++ ++ *) Initial support for PowerISA 2.0.7, first implemented in POWER8. ++ This covers AES, SHA256/512 and GHASH. "Initial" means that most ++ common cases are optimized and there still is room for further ++ improvements. Vector Permutation AES for Altivec is also added. ++ [Andy Polyakov] ++ ++ *) Add support for little-endian ppc64 Linux target. ++ [Marcelo Cerri (IBM)] ++ ++ *) Initial support for AMRv8 ISA crypto extensions. This covers AES, ++ SHA1, SHA256 and GHASH. "Initial" means that most common cases ++ are optimized and there still is room for further improvements. ++ Both 32- and 64-bit modes are supported. ++ [Andy Polyakov, Ard Biesheuvel (Linaro)] ++ ++ *) Improved ARMv7 NEON support. ++ [Andy Polyakov] ++ ++ *) Support for SPARC Architecture 2011 crypto extensions, first ++ implemented in SPARC T4. This covers AES, DES, Camellia, SHA1, ++ SHA256/512, MD5, GHASH and modular exponentiation. ++ [Andy Polyakov, David Miller] ++ ++ *) Accelerated modular exponentiation for Intel processors, a.k.a. ++ RSAZ. ++ [Shay Gueron & Vlad Krasnov (Intel Corp)] ++ ++ *) Support for new and upcoming Intel processors, including AVX2, ++ BMI and SHA ISA extensions. This includes additional "stitched" ++ implementations, AESNI-SHA256 and GCM, and multi-buffer support ++ for TLS encrypt. ++ ++ This work was sponsored by Intel Corp. ++ [Andy Polyakov] ++ ++ *) Support for DTLS 1.2. This adds two sets of DTLS methods: DTLS_*_method() ++ supports both DTLS 1.2 and 1.0 and should use whatever version the peer ++ supports and DTLSv1_2_*_method() which supports DTLS 1.2 only. ++ [Steve Henson] ++ ++ *) Use algorithm specific chains in SSL_CTX_use_certificate_chain_file(): ++ this fixes a limitation in previous versions of OpenSSL. ++ [Steve Henson] ++ ++ *) Extended RSA OAEP support via EVP_PKEY API. Options to specify digest, ++ MGF1 digest and OAEP label. ++ [Steve Henson] ++ ++ *) Add EVP support for key wrapping algorithms, to avoid problems with ++ existing code the flag EVP_CIPHER_CTX_WRAP_ALLOW has to be set in ++ the EVP_CIPHER_CTX or an error is returned. Add AES and DES3 wrap ++ algorithms and include tests cases. ++ [Steve Henson] ++ ++ *) Add functions to allocate and set the fields of an ECDSA_METHOD ++ structure. ++ [Douglas E. Engert, Steve Henson] ++ ++ *) New functions OPENSSL_gmtime_diff and ASN1_TIME_diff to find the ++ difference in days and seconds between two tm or ASN1_TIME structures. ++ [Steve Henson] ++ ++ *) Add -rev test option to s_server to just reverse order of characters ++ received by client and send back to server. Also prints an abbreviated ++ summary of the connection parameters. ++ [Steve Henson] ++ ++ *) New option -brief for s_client and s_server to print out a brief summary ++ of connection parameters. ++ [Steve Henson] ++ ++ *) Add callbacks for arbitrary TLS extensions. ++ [Trevor Perrin and Ben Laurie] ++ ++ *) New option -crl_download in several openssl utilities to download CRLs ++ from CRLDP extension in certificates. ++ [Steve Henson] ++ ++ *) New options -CRL and -CRLform for s_client and s_server for CRLs. ++ [Steve Henson] ++ ++ *) New function X509_CRL_diff to generate a delta CRL from the difference ++ of two full CRLs. Add support to "crl" utility. ++ [Steve Henson] ++ ++ *) New functions to set lookup_crls function and to retrieve ++ X509_STORE from X509_STORE_CTX. ++ [Steve Henson] ++ ++ *) Print out deprecated issuer and subject unique ID fields in ++ certificates. ++ [Steve Henson] ++ ++ *) Extend OCSP I/O functions so they can be used for simple general purpose ++ HTTP as well as OCSP. New wrapper function which can be used to download ++ CRLs using the OCSP API. ++ [Steve Henson] ++ ++ *) Delegate command line handling in s_client/s_server to SSL_CONF APIs. ++ [Steve Henson] ++ ++ *) SSL_CONF* functions. These provide a common framework for application ++ configuration using configuration files or command lines. ++ [Steve Henson] ++ ++ *) SSL/TLS tracing code. This parses out SSL/TLS records using the ++ message callback and prints the results. Needs compile time option ++ "enable-ssl-trace". New options to s_client and s_server to enable ++ tracing. ++ [Steve Henson] ++ ++ *) New ctrl and macro to retrieve supported points extensions. ++ Print out extension in s_server and s_client. ++ [Steve Henson] ++ ++ *) New functions to retrieve certificate signature and signature ++ OID NID. ++ [Steve Henson] ++ ++ *) Add functions to retrieve and manipulate the raw cipherlist sent by a ++ client to OpenSSL. ++ [Steve Henson] ++ ++ *) New Suite B modes for TLS code. These use and enforce the requirements ++ of RFC6460: restrict ciphersuites, only permit Suite B algorithms and ++ only use Suite B curves. The Suite B modes can be set by using the ++ strings "SUITEB128", "SUITEB192" or "SUITEB128ONLY" for the cipherstring. ++ [Steve Henson] ++ ++ *) New chain verification flags for Suite B levels of security. Check ++ algorithms are acceptable when flags are set in X509_verify_cert. ++ [Steve Henson] ++ ++ *) Make tls1_check_chain return a set of flags indicating checks passed ++ by a certificate chain. Add additional tests to handle client ++ certificates: checks for matching certificate type and issuer name ++ comparison. ++ [Steve Henson] ++ ++ *) If an attempt is made to use a signature algorithm not in the peer ++ preference list abort the handshake. If client has no suitable ++ signature algorithms in response to a certificate request do not ++ use the certificate. ++ [Steve Henson] ++ ++ *) If server EC tmp key is not in client preference list abort handshake. ++ [Steve Henson] ++ ++ *) Add support for certificate stores in CERT structure. This makes it ++ possible to have different stores per SSL structure or one store in ++ the parent SSL_CTX. Include distinct stores for certificate chain ++ verification and chain building. New ctrl SSL_CTRL_BUILD_CERT_CHAIN ++ to build and store a certificate chain in CERT structure: returning ++ an error if the chain cannot be built: this will allow applications ++ to test if a chain is correctly configured. ++ ++ Note: if the CERT based stores are not set then the parent SSL_CTX ++ store is used to retain compatibility with existing behaviour. ++ ++ [Steve Henson] ++ ++ *) New function ssl_set_client_disabled to set a ciphersuite disabled ++ mask based on the current session, check mask when sending client ++ hello and checking the requested ciphersuite. ++ [Steve Henson] ++ ++ *) New ctrls to retrieve and set certificate types in a certificate ++ request message. Print out received values in s_client. If certificate ++ types is not set with custom values set sensible values based on ++ supported signature algorithms. ++ [Steve Henson] ++ ++ *) Support for distinct client and server supported signature algorithms. ++ [Steve Henson] ++ ++ *) Add certificate callback. If set this is called whenever a certificate ++ is required by client or server. An application can decide which ++ certificate chain to present based on arbitrary criteria: for example ++ supported signature algorithms. Add very simple example to s_server. ++ This fixes many of the problems and restrictions of the existing client ++ certificate callback: for example you can now clear an existing ++ certificate and specify the whole chain. ++ [Steve Henson] ++ ++ *) Add new "valid_flags" field to CERT_PKEY structure which determines what ++ the certificate can be used for (if anything). Set valid_flags field ++ in new tls1_check_chain function. Simplify ssl_set_cert_masks which used ++ to have similar checks in it. ++ ++ Add new "cert_flags" field to CERT structure and include a "strict mode". ++ This enforces some TLS certificate requirements (such as only permitting ++ certificate signature algorithms contained in the supported algorithms ++ extension) which some implementations ignore: this option should be used ++ with caution as it could cause interoperability issues. ++ [Steve Henson] ++ ++ *) Update and tidy signature algorithm extension processing. Work out ++ shared signature algorithms based on preferences and peer algorithms ++ and print them out in s_client and s_server. Abort handshake if no ++ shared signature algorithms. ++ [Steve Henson] ++ ++ *) Add new functions to allow customised supported signature algorithms ++ for SSL and SSL_CTX structures. Add options to s_client and s_server ++ to support them. ++ [Steve Henson] ++ ++ *) New function SSL_certs_clear() to delete all references to certificates ++ from an SSL structure. Before this once a certificate had been added ++ it couldn't be removed. ++ [Steve Henson] ++ ++ *) Integrate hostname, email address and IP address checking with certificate ++ verification. New verify options supporting checking in openssl utility. ++ [Steve Henson] ++ ++ *) Fixes and wildcard matching support to hostname and email checking ++ functions. Add manual page. ++ [Florian Weimer (Red Hat Product Security Team)] ++ ++ *) New functions to check a hostname email or IP address against a ++ certificate. Add options x509 utility to print results of checks against ++ a certificate. ++ [Steve Henson] ++ ++ *) Fix OCSP checking. ++ [Rob Stradling and Ben Laurie] ++ ++ *) Initial experimental support for explicitly trusted non-root CAs. ++ OpenSSL still tries to build a complete chain to a root but if an ++ intermediate CA has a trust setting included that is used. The first ++ setting is used: whether to trust (e.g., -addtrust option to the x509 ++ utility) or reject. ++ [Steve Henson] ++ ++ *) Add -trusted_first option which attempts to find certificates in the ++ trusted store even if an untrusted chain is also supplied. ++ [Steve Henson] ++ ++ *) MIPS assembly pack updates: support for MIPS32r2 and SmartMIPS ASE, ++ platform support for Linux and Android. ++ [Andy Polyakov] ++ ++ *) Support for linux-x32, ILP32 environment in x86_64 framework. ++ [Andy Polyakov] ++ ++ *) Experimental multi-implementation support for FIPS capable OpenSSL. ++ When in FIPS mode the approved implementations are used as normal, ++ when not in FIPS mode the internal unapproved versions are used instead. ++ This means that the FIPS capable OpenSSL isn't forced to use the ++ (often lower performance) FIPS implementations outside FIPS mode. ++ [Steve Henson] ++ ++ *) Transparently support X9.42 DH parameters when calling ++ PEM_read_bio_DHparameters. This means existing applications can handle ++ the new parameter format automatically. ++ [Steve Henson] ++ ++ *) Initial experimental support for X9.42 DH parameter format: mainly ++ to support use of 'q' parameter for RFC5114 parameters. ++ [Steve Henson] ++ ++ *) Add DH parameters from RFC5114 including test data to dhtest. ++ [Steve Henson] ++ ++ *) Support for automatic EC temporary key parameter selection. If enabled ++ the most preferred EC parameters are automatically used instead of ++ hardcoded fixed parameters. Now a server just has to call: ++ SSL_CTX_set_ecdh_auto(ctx, 1) and the server will automatically ++ support ECDH and use the most appropriate parameters. ++ [Steve Henson] ++ ++ *) Enhance and tidy EC curve and point format TLS extension code. Use ++ static structures instead of allocation if default values are used. ++ New ctrls to set curves we wish to support and to retrieve shared curves. ++ Print out shared curves in s_server. New options to s_server and s_client ++ to set list of supported curves. ++ [Steve Henson] ++ ++ *) New ctrls to retrieve supported signature algorithms and ++ supported curve values as an array of NIDs. Extend openssl utility ++ to print out received values. ++ [Steve Henson] ++ ++ *) Add new APIs EC_curve_nist2nid and EC_curve_nid2nist which convert ++ between NIDs and the more common NIST names such as "P-256". Enhance ++ ecparam utility and ECC method to recognise the NIST names for curves. ++ [Steve Henson] ++ ++ *) Enhance SSL/TLS certificate chain handling to support different ++ chains for each certificate instead of one chain in the parent SSL_CTX. ++ [Steve Henson] ++ ++ *) Support for fixed DH ciphersuite client authentication: where both ++ server and client use DH certificates with common parameters. ++ [Steve Henson] ++ ++ *) Support for fixed DH ciphersuites: those requiring DH server ++ certificates. ++ [Steve Henson] ++ ++ *) New function i2d_re_X509_tbs for re-encoding the TBS portion of ++ the certificate. ++ Note: Related 1.0.2-beta specific macros X509_get_cert_info, ++ X509_CINF_set_modified, X509_CINF_get_issuer, X509_CINF_get_extensions and ++ X509_CINF_get_signature were reverted post internal team review. ++ ++ Changes between 1.0.1k and 1.0.1l [15 Jan 2015] ++ ++ *) Build fixes for the Windows and OpenVMS platforms ++ [Matt Caswell and Richard Levitte] ++ ++ Changes between 1.0.1j and 1.0.1k [8 Jan 2015] ++ ++ *) Fix DTLS segmentation fault in dtls1_get_record. A carefully crafted DTLS ++ message can cause a segmentation fault in OpenSSL due to a NULL pointer ++ dereference. This could lead to a Denial Of Service attack. Thanks to ++ Markus Stenberg of Cisco Systems, Inc. for reporting this issue. ++ (CVE-2014-3571) ++ [Steve Henson] ++ ++ *) Fix DTLS memory leak in dtls1_buffer_record. A memory leak can occur in the ++ dtls1_buffer_record function under certain conditions. In particular this ++ could occur if an attacker sent repeated DTLS records with the same ++ sequence number but for the next epoch. The memory leak could be exploited ++ by an attacker in a Denial of Service attack through memory exhaustion. ++ Thanks to Chris Mueller for reporting this issue. ++ (CVE-2015-0206) ++ [Matt Caswell] ++ ++ *) Fix issue where no-ssl3 configuration sets method to NULL. When openssl is ++ built with the no-ssl3 option and a SSL v3 ClientHello is received the ssl ++ method would be set to NULL which could later result in a NULL pointer ++ dereference. Thanks to Frank Schmirler for reporting this issue. ++ (CVE-2014-3569) ++ [Kurt Roeckx] ++ ++ *) Abort handshake if server key exchange message is omitted for ephemeral ++ ECDH ciphersuites. ++ ++ Thanks to Karthikeyan Bhargavan of the PROSECCO team at INRIA for ++ reporting this issue. ++ (CVE-2014-3572) ++ [Steve Henson] ++ ++ *) Remove non-export ephemeral RSA code on client and server. This code ++ violated the TLS standard by allowing the use of temporary RSA keys in ++ non-export ciphersuites and could be used by a server to effectively ++ downgrade the RSA key length used to a value smaller than the server ++ certificate. Thanks for Karthikeyan Bhargavan of the PROSECCO team at ++ INRIA or reporting this issue. ++ (CVE-2015-0204) ++ [Steve Henson] ++ ++ *) Fixed issue where DH client certificates are accepted without verification. ++ An OpenSSL server will accept a DH certificate for client authentication ++ without the certificate verify message. This effectively allows a client to ++ authenticate without the use of a private key. This only affects servers ++ which trust a client certificate authority which issues certificates ++ containing DH keys: these are extremely rare and hardly ever encountered. ++ Thanks for Karthikeyan Bhargavan of the PROSECCO team at INRIA or reporting ++ this issue. ++ (CVE-2015-0205) ++ [Steve Henson] ++ ++ *) Ensure that the session ID context of an SSL is updated when its ++ SSL_CTX is updated via SSL_set_SSL_CTX. ++ ++ The session ID context is typically set from the parent SSL_CTX, ++ and can vary with the CTX. ++ [Adam Langley] ++ ++ *) Fix various certificate fingerprint issues. ++ ++ By using non-DER or invalid encodings outside the signed portion of a ++ certificate the fingerprint can be changed without breaking the signature. ++ Although no details of the signed portion of the certificate can be changed ++ this can cause problems with some applications: e.g. those using the ++ certificate fingerprint for blacklists. ++ ++ 1. Reject signatures with non zero unused bits. ++ ++ If the BIT STRING containing the signature has non zero unused bits reject ++ the signature. All current signature algorithms require zero unused bits. ++ ++ 2. Check certificate algorithm consistency. ++ ++ Check the AlgorithmIdentifier inside TBS matches the one in the ++ certificate signature. NB: this will result in signature failure ++ errors for some broken certificates. ++ ++ Thanks to Konrad Kraszewski from Google for reporting this issue. ++ ++ 3. Check DSA/ECDSA signatures use DER. ++ ++ Re-encode DSA/ECDSA signatures and compare with the original received ++ signature. Return an error if there is a mismatch. ++ ++ This will reject various cases including garbage after signature ++ (thanks to Antti Karjalainen and Tuomo Untinen from the Codenomicon CROSS ++ program for discovering this case) and use of BER or invalid ASN.1 INTEGERs ++ (negative or with leading zeroes). ++ ++ Further analysis was conducted and fixes were developed by Stephen Henson ++ of the OpenSSL core team. ++ ++ (CVE-2014-8275) ++ [Steve Henson] ++ ++ *) Correct Bignum squaring. Bignum squaring (BN_sqr) may produce incorrect ++ results on some platforms, including x86_64. This bug occurs at random ++ with a very low probability, and is not known to be exploitable in any ++ way, though its exact impact is difficult to determine. Thanks to Pieter ++ Wuille (Blockstream) who reported this issue and also suggested an initial ++ fix. Further analysis was conducted by the OpenSSL development team and ++ Adam Langley of Google. The final fix was developed by Andy Polyakov of ++ the OpenSSL core team. ++ (CVE-2014-3570) ++ [Andy Polyakov] ++ ++ *) Do not resume sessions on the server if the negotiated protocol ++ version does not match the session's version. Resuming with a different ++ version, while not strictly forbidden by the RFC, is of questionable ++ sanity and breaks all known clients. ++ [David Benjamin, Emilia Käsper] ++ ++ *) Tighten handling of the ChangeCipherSpec (CCS) message: reject ++ early CCS messages during renegotiation. (Note that because ++ renegotiation is encrypted, this early CCS was not exploitable.) ++ [Emilia Käsper] ++ ++ *) Tighten client-side session ticket handling during renegotiation: ++ ensure that the client only accepts a session ticket if the server sends ++ the extension anew in the ServerHello. Previously, a TLS client would ++ reuse the old extension state and thus accept a session ticket if one was ++ announced in the initial ServerHello. ++ ++ Similarly, ensure that the client requires a session ticket if one ++ was advertised in the ServerHello. Previously, a TLS client would ++ ignore a missing NewSessionTicket message. ++ [Emilia Käsper] ++ ++ Changes between 1.0.1i and 1.0.1j [15 Oct 2014] ++ ++ *) SRTP Memory Leak. ++ ++ A flaw in the DTLS SRTP extension parsing code allows an attacker, who ++ sends a carefully crafted handshake message, to cause OpenSSL to fail ++ to free up to 64k of memory causing a memory leak. This could be ++ exploited in a Denial Of Service attack. This issue affects OpenSSL ++ 1.0.1 server implementations for both SSL/TLS and DTLS regardless of ++ whether SRTP is used or configured. Implementations of OpenSSL that ++ have been compiled with OPENSSL_NO_SRTP defined are not affected. ++ ++ The fix was developed by the OpenSSL team. ++ (CVE-2014-3513) ++ [OpenSSL team] ++ ++ *) Session Ticket Memory Leak. ++ ++ When an OpenSSL SSL/TLS/DTLS server receives a session ticket the ++ integrity of that ticket is first verified. In the event of a session ++ ticket integrity check failing, OpenSSL will fail to free memory ++ causing a memory leak. By sending a large number of invalid session ++ tickets an attacker could exploit this issue in a Denial Of Service ++ attack. ++ (CVE-2014-3567) ++ [Steve Henson] ++ ++ *) Build option no-ssl3 is incomplete. ++ ++ When OpenSSL is configured with "no-ssl3" as a build option, servers ++ could accept and complete a SSL 3.0 handshake, and clients could be ++ configured to send them. ++ (CVE-2014-3568) ++ [Akamai and the OpenSSL team] ++ ++ *) Add support for TLS_FALLBACK_SCSV. ++ Client applications doing fallback retries should call ++ SSL_set_mode(s, SSL_MODE_SEND_FALLBACK_SCSV). ++ (CVE-2014-3566) ++ [Adam Langley, Bodo Moeller] ++ ++ *) Add additional DigestInfo checks. ++ ++ Re-encode DigestInto in DER and check against the original when ++ verifying RSA signature: this will reject any improperly encoded ++ DigestInfo structures. ++ ++ Note: this is a precautionary measure and no attacks are currently known. ++ ++ [Steve Henson] ++ ++ Changes between 1.0.1h and 1.0.1i [6 Aug 2014] ++ ++ *) Fix SRP buffer overrun vulnerability. Invalid parameters passed to the ++ SRP code can be overrun an internal buffer. Add sanity check that ++ g, A, B < N to SRP code. ++ ++ Thanks to Sean Devlin and Watson Ladd of Cryptography Services, NCC ++ Group for discovering this issue. ++ (CVE-2014-3512) ++ [Steve Henson] ++ ++ *) A flaw in the OpenSSL SSL/TLS server code causes the server to negotiate ++ TLS 1.0 instead of higher protocol versions when the ClientHello message ++ is badly fragmented. This allows a man-in-the-middle attacker to force a ++ downgrade to TLS 1.0 even if both the server and the client support a ++ higher protocol version, by modifying the client's TLS records. ++ ++ Thanks to David Benjamin and Adam Langley (Google) for discovering and ++ researching this issue. ++ (CVE-2014-3511) ++ [David Benjamin] ++ ++ *) OpenSSL DTLS clients enabling anonymous (EC)DH ciphersuites are subject ++ to a denial of service attack. A malicious server can crash the client ++ with a null pointer dereference (read) by specifying an anonymous (EC)DH ++ ciphersuite and sending carefully crafted handshake messages. ++ ++ Thanks to Felix Gröbert (Google) for discovering and researching this ++ issue. ++ (CVE-2014-3510) ++ [Emilia Käsper] ++ ++ *) By sending carefully crafted DTLS packets an attacker could cause openssl ++ to leak memory. This can be exploited through a Denial of Service attack. ++ Thanks to Adam Langley for discovering and researching this issue. ++ (CVE-2014-3507) ++ [Adam Langley] ++ ++ *) An attacker can force openssl to consume large amounts of memory whilst ++ processing DTLS handshake messages. This can be exploited through a ++ Denial of Service attack. ++ Thanks to Adam Langley for discovering and researching this issue. ++ (CVE-2014-3506) ++ [Adam Langley] ++ ++ *) An attacker can force an error condition which causes openssl to crash ++ whilst processing DTLS packets due to memory being freed twice. This ++ can be exploited through a Denial of Service attack. ++ Thanks to Adam Langley and Wan-Teh Chang for discovering and researching ++ this issue. ++ (CVE-2014-3505) ++ [Adam Langley] ++ ++ *) If a multithreaded client connects to a malicious server using a resumed ++ session and the server sends an ec point format extension it could write ++ up to 255 bytes to freed memory. ++ ++ Thanks to Gabor Tyukasz (LogMeIn Inc) for discovering and researching this ++ issue. ++ (CVE-2014-3509) ++ [Gabor Tyukasz] ++ ++ *) A malicious server can crash an OpenSSL client with a null pointer ++ dereference (read) by specifying an SRP ciphersuite even though it was not ++ properly negotiated with the client. This can be exploited through a ++ Denial of Service attack. ++ ++ Thanks to Joonas Kuorilehto and Riku Hietamäki (Codenomicon) for ++ discovering and researching this issue. ++ (CVE-2014-5139) ++ [Steve Henson] ++ ++ *) A flaw in OBJ_obj2txt may cause pretty printing functions such as ++ X509_name_oneline, X509_name_print_ex et al. to leak some information ++ from the stack. Applications may be affected if they echo pretty printing ++ output to the attacker. ++ ++ Thanks to Ivan Fratric (Google) for discovering this issue. ++ (CVE-2014-3508) ++ [Emilia Käsper, and Steve Henson] ++ ++ *) Fix ec_GFp_simple_points_make_affine (thus, EC_POINTs_mul etc.) ++ for corner cases. (Certain input points at infinity could lead to ++ bogus results, with non-infinity inputs mapped to infinity too.) ++ [Bodo Moeller] ++ ++ Changes between 1.0.1g and 1.0.1h [5 Jun 2014] ++ ++ *) Fix for SSL/TLS MITM flaw. An attacker using a carefully crafted ++ handshake can force the use of weak keying material in OpenSSL ++ SSL/TLS clients and servers. ++ ++ Thanks to KIKUCHI Masashi (Lepidum Co. Ltd.) for discovering and ++ researching this issue. (CVE-2014-0224) ++ [KIKUCHI Masashi, Steve Henson] ++ ++ *) Fix DTLS recursion flaw. By sending an invalid DTLS handshake to an ++ OpenSSL DTLS client the code can be made to recurse eventually crashing ++ in a DoS attack. ++ ++ Thanks to Imre Rad (Search-Lab Ltd.) for discovering this issue. ++ (CVE-2014-0221) ++ [Imre Rad, Steve Henson] ++ ++ *) Fix DTLS invalid fragment vulnerability. A buffer overrun attack can ++ be triggered by sending invalid DTLS fragments to an OpenSSL DTLS ++ client or server. This is potentially exploitable to run arbitrary ++ code on a vulnerable client or server. ++ ++ Thanks to Jüri Aedla for reporting this issue. (CVE-2014-0195) ++ [Jüri Aedla, Steve Henson] ++ ++ *) Fix bug in TLS code where clients enable anonymous ECDH ciphersuites ++ are subject to a denial of service attack. ++ ++ Thanks to Felix Gröbert and Ivan Fratric at Google for discovering ++ this issue. (CVE-2014-3470) ++ [Felix Gröbert, Ivan Fratric, Steve Henson] ++ ++ *) Harmonize version and its documentation. -f flag is used to display ++ compilation flags. ++ [mancha ] ++ ++ *) Fix eckey_priv_encode so it immediately returns an error upon a failure ++ in i2d_ECPrivateKey. ++ [mancha ] ++ ++ *) Fix some double frees. These are not thought to be exploitable. ++ [mancha ] ++ ++ Changes between 1.0.1f and 1.0.1g [7 Apr 2014] ++ ++ *) A missing bounds check in the handling of the TLS heartbeat extension ++ can be used to reveal up to 64k of memory to a connected client or ++ server. ++ ++ Thanks for Neel Mehta of Google Security for discovering this bug and to ++ Adam Langley and Bodo Moeller for ++ preparing the fix (CVE-2014-0160) ++ [Adam Langley, Bodo Moeller] ++ ++ *) Fix for the attack described in the paper "Recovering OpenSSL ++ ECDSA Nonces Using the FLUSH+RELOAD Cache Side-channel Attack" ++ by Yuval Yarom and Naomi Benger. Details can be obtained from: ++ http://eprint.iacr.org/2014/140 ++ ++ Thanks to Yuval Yarom and Naomi Benger for discovering this ++ flaw and to Yuval Yarom for supplying a fix (CVE-2014-0076) ++ [Yuval Yarom and Naomi Benger] ++ ++ *) TLS pad extension: draft-agl-tls-padding-03 ++ ++ Workaround for the "TLS hang bug" (see FAQ and PR#2771): if the ++ TLS client Hello record length value would otherwise be > 255 and ++ less that 512 pad with a dummy extension containing zeroes so it ++ is at least 512 bytes long. ++ ++ [Adam Langley, Steve Henson] ++ ++ Changes between 1.0.1e and 1.0.1f [6 Jan 2014] ++ ++ *) Fix for TLS record tampering bug. A carefully crafted invalid ++ handshake could crash OpenSSL with a NULL pointer exception. ++ Thanks to Anton Johansson for reporting this issues. ++ (CVE-2013-4353) ++ ++ *) Keep original DTLS digest and encryption contexts in retransmission ++ structures so we can use the previous session parameters if they need ++ to be resent. (CVE-2013-6450) ++ [Steve Henson] ++ ++ *) Add option SSL_OP_SAFARI_ECDHE_ECDSA_BUG (part of SSL_OP_ALL) which ++ avoids preferring ECDHE-ECDSA ciphers when the client appears to be ++ Safari on OS X. Safari on OS X 10.8..10.8.3 advertises support for ++ several ECDHE-ECDSA ciphers, but fails to negotiate them. The bug ++ is fixed in OS X 10.8.4, but Apple have ruled out both hot fixing ++ 10.8..10.8.3 and forcing users to upgrade to 10.8.4 or newer. ++ [Rob Stradling, Adam Langley] ++ ++ Changes between 1.0.1d and 1.0.1e [11 Feb 2013] ++ ++ *) Correct fix for CVE-2013-0169. The original didn't work on AES-NI ++ supporting platforms or when small records were transferred. ++ [Andy Polyakov, Steve Henson] ++ ++ Changes between 1.0.1c and 1.0.1d [5 Feb 2013] ++ ++ *) Make the decoding of SSLv3, TLS and DTLS CBC records constant time. ++ ++ This addresses the flaw in CBC record processing discovered by ++ Nadhem Alfardan and Kenny Paterson. Details of this attack can be found ++ at: http://www.isg.rhul.ac.uk/tls/ ++ ++ Thanks go to Nadhem Alfardan and Kenny Paterson of the Information ++ Security Group at Royal Holloway, University of London ++ (www.isg.rhul.ac.uk) for discovering this flaw and Adam Langley and ++ Emilia Käsper for the initial patch. ++ (CVE-2013-0169) ++ [Emilia Käsper, Adam Langley, Ben Laurie, Andy Polyakov, Steve Henson] ++ ++ *) Fix flaw in AESNI handling of TLS 1.2 and 1.1 records for CBC mode ++ ciphersuites which can be exploited in a denial of service attack. ++ Thanks go to and to Adam Langley for discovering ++ and detecting this bug and to Wolfgang Ettlinger ++ for independently discovering this issue. ++ (CVE-2012-2686) ++ [Adam Langley] ++ ++ *) Return an error when checking OCSP signatures when key is NULL. ++ This fixes a DoS attack. (CVE-2013-0166) ++ [Steve Henson] ++ ++ *) Make openssl verify return errors. ++ [Chris Palmer and Ben Laurie] ++ ++ *) Call OCSP Stapling callback after ciphersuite has been chosen, so ++ the right response is stapled. Also change SSL_get_certificate() ++ so it returns the certificate actually sent. ++ See http://rt.openssl.org/Ticket/Display.html?id=2836. ++ [Rob Stradling ] ++ ++ *) Fix possible deadlock when decoding public keys. ++ [Steve Henson] ++ ++ *) Don't use TLS 1.0 record version number in initial client hello ++ if renegotiating. ++ [Steve Henson] ++ ++ Changes between 1.0.1b and 1.0.1c [10 May 2012] ++ ++ *) Sanity check record length before skipping explicit IV in TLS ++ 1.2, 1.1 and DTLS to fix DoS attack. ++ ++ Thanks to Codenomicon for discovering this issue using Fuzz-o-Matic ++ fuzzing as a service testing platform. ++ (CVE-2012-2333) ++ [Steve Henson] ++ ++ *) Initialise tkeylen properly when encrypting CMS messages. ++ Thanks to Solar Designer of Openwall for reporting this issue. ++ [Steve Henson] ++ ++ *) In FIPS mode don't try to use composite ciphers as they are not ++ approved. ++ [Steve Henson] ++ ++ Changes between 1.0.1a and 1.0.1b [26 Apr 2012] ++ ++ *) OpenSSL 1.0.0 sets SSL_OP_ALL to 0x80000FFFL and OpenSSL 1.0.1 and ++ 1.0.1a set SSL_OP_NO_TLSv1_1 to 0x00000400L which would unfortunately ++ mean any application compiled against OpenSSL 1.0.0 headers setting ++ SSL_OP_ALL would also set SSL_OP_NO_TLSv1_1, unintentionally disablng ++ TLS 1.1 also. Fix this by changing the value of SSL_OP_NO_TLSv1_1 to ++ 0x10000000L Any application which was previously compiled against ++ OpenSSL 1.0.1 or 1.0.1a headers and which cares about SSL_OP_NO_TLSv1_1 ++ will need to be recompiled as a result. Letting be results in ++ inability to disable specifically TLS 1.1 and in client context, ++ in unlike event, limit maximum offered version to TLS 1.0 [see below]. ++ [Steve Henson] ++ ++ *) In order to ensure interoperabilty SSL_OP_NO_protocolX does not ++ disable just protocol X, but all protocols above X *if* there are ++ protocols *below* X still enabled. In more practical terms it means ++ that if application wants to disable TLS1.0 in favor of TLS1.1 and ++ above, it's not sufficient to pass SSL_OP_NO_TLSv1, one has to pass ++ SSL_OP_NO_TLSv1|SSL_OP_NO_SSLv3|SSL_OP_NO_SSLv2. This applies to ++ client side. ++ [Andy Polyakov] ++ ++ Changes between 1.0.1 and 1.0.1a [19 Apr 2012] ++ ++ *) Check for potentially exploitable overflows in asn1_d2i_read_bio ++ BUF_mem_grow and BUF_mem_grow_clean. Refuse attempts to shrink buffer ++ in CRYPTO_realloc_clean. ++ ++ Thanks to Tavis Ormandy, Google Security Team, for discovering this ++ issue and to Adam Langley for fixing it. ++ (CVE-2012-2110) ++ [Adam Langley (Google), Tavis Ormandy, Google Security Team] ++ ++ *) Don't allow TLS 1.2 SHA-256 ciphersuites in TLS 1.0, 1.1 connections. ++ [Adam Langley] ++ ++ *) Workarounds for some broken servers that "hang" if a client hello ++ record length exceeds 255 bytes. ++ ++ 1. Do not use record version number > TLS 1.0 in initial client ++ hello: some (but not all) hanging servers will now work. ++ 2. If we set OPENSSL_MAX_TLS1_2_CIPHER_LENGTH this will truncate ++ the number of ciphers sent in the client hello. This should be ++ set to an even number, such as 50, for example by passing: ++ -DOPENSSL_MAX_TLS1_2_CIPHER_LENGTH=50 to config or Configure. ++ Most broken servers should now work. ++ 3. If all else fails setting OPENSSL_NO_TLS1_2_CLIENT will disable ++ TLS 1.2 client support entirely. ++ [Steve Henson] ++ ++ *) Fix SEGV in Vector Permutation AES module observed in OpenSSH. ++ [Andy Polyakov] ++ ++ Changes between 1.0.0h and 1.0.1 [14 Mar 2012] ++ ++ *) Add compatibility with old MDC2 signatures which use an ASN1 OCTET ++ STRING form instead of a DigestInfo. ++ [Steve Henson] ++ ++ *) The format used for MDC2 RSA signatures is inconsistent between EVP ++ and the RSA_sign/RSA_verify functions. This was made more apparent when ++ OpenSSL used RSA_sign/RSA_verify for some RSA signatures in particular ++ those which went through EVP_PKEY_METHOD in 1.0.0 and later. Detect ++ the correct format in RSA_verify so both forms transparently work. ++ [Steve Henson] ++ ++ *) Some servers which support TLS 1.0 can choke if we initially indicate ++ support for TLS 1.2 and later renegotiate using TLS 1.0 in the RSA ++ encrypted premaster secret. As a workaround use the maximum permitted ++ client version in client hello, this should keep such servers happy ++ and still work with previous versions of OpenSSL. ++ [Steve Henson] ++ ++ *) Add support for TLS/DTLS heartbeats. ++ [Robin Seggelmann ] ++ ++ *) Add support for SCTP. ++ [Robin Seggelmann ] ++ ++ *) Improved PRNG seeding for VOS. ++ [Paul Green ] ++ ++ *) Extensive assembler packs updates, most notably: ++ ++ - x86[_64]: AES-NI, PCLMULQDQ, RDRAND support; ++ - x86[_64]: SSSE3 support (SHA1, vector-permutation AES); ++ - x86_64: bit-sliced AES implementation; ++ - ARM: NEON support, contemporary platforms optimizations; ++ - s390x: z196 support; ++ - *: GHASH and GF(2^m) multiplication implementations; ++ ++ [Andy Polyakov] ++ ++ *) Make TLS-SRP code conformant with RFC 5054 API cleanup ++ (removal of unnecessary code) ++ [Peter Sylvester ] ++ ++ *) Add TLS key material exporter from RFC 5705. ++ [Eric Rescorla] ++ ++ *) Add DTLS-SRTP negotiation from RFC 5764. ++ [Eric Rescorla] ++ ++ *) Add Next Protocol Negotiation, ++ http://tools.ietf.org/html/draft-agl-tls-nextprotoneg-00. Can be ++ disabled with a no-npn flag to config or Configure. Code donated ++ by Google. ++ [Adam Langley and Ben Laurie] ++ ++ *) Add optional 64-bit optimized implementations of elliptic curves NIST-P224, ++ NIST-P256, NIST-P521, with constant-time single point multiplication on ++ typical inputs. Compiler support for the nonstandard type __uint128_t is ++ required to use this (present in gcc 4.4 and later, for 64-bit builds). ++ Code made available under Apache License version 2.0. ++ ++ Specify "enable-ec_nistp_64_gcc_128" on the Configure (or config) command ++ line to include this in your build of OpenSSL, and run "make depend" (or ++ "make update"). This enables the following EC_METHODs: ++ ++ EC_GFp_nistp224_method() ++ EC_GFp_nistp256_method() ++ EC_GFp_nistp521_method() ++ ++ EC_GROUP_new_by_curve_name() will automatically use these (while ++ EC_GROUP_new_curve_GFp() currently prefers the more flexible ++ implementations). ++ [Emilia Käsper, Adam Langley, Bodo Moeller (Google)] ++ ++ *) Use type ossl_ssize_t instad of ssize_t which isn't available on ++ all platforms. Move ssize_t definition from e_os.h to the public ++ header file e_os2.h as it now appears in public header file cms.h ++ [Steve Henson] ++ ++ *) New -sigopt option to the ca, req and x509 utilities. Additional ++ signature parameters can be passed using this option and in ++ particular PSS. ++ [Steve Henson] ++ ++ *) Add RSA PSS signing function. This will generate and set the ++ appropriate AlgorithmIdentifiers for PSS based on those in the ++ corresponding EVP_MD_CTX structure. No application support yet. ++ [Steve Henson] ++ ++ *) Support for companion algorithm specific ASN1 signing routines. ++ New function ASN1_item_sign_ctx() signs a pre-initialised ++ EVP_MD_CTX structure and sets AlgorithmIdentifiers based on ++ the appropriate parameters. ++ [Steve Henson] ++ ++ *) Add new algorithm specific ASN1 verification initialisation function ++ to EVP_PKEY_ASN1_METHOD: this is not in EVP_PKEY_METHOD since the ASN1 ++ handling will be the same no matter what EVP_PKEY_METHOD is used. ++ Add a PSS handler to support verification of PSS signatures: checked ++ against a number of sample certificates. ++ [Steve Henson] ++ ++ *) Add signature printing for PSS. Add PSS OIDs. ++ [Steve Henson, Martin Kaiser ] ++ ++ *) Add algorithm specific signature printing. An individual ASN1 method ++ can now print out signatures instead of the standard hex dump. ++ ++ More complex signatures (e.g. PSS) can print out more meaningful ++ information. Include DSA version that prints out the signature ++ parameters r, s. ++ [Steve Henson] ++ ++ *) Password based recipient info support for CMS library: implementing ++ RFC3211. ++ [Steve Henson] ++ ++ *) Split password based encryption into PBES2 and PBKDF2 functions. This ++ neatly separates the code into cipher and PBE sections and is required ++ for some algorithms that split PBES2 into separate pieces (such as ++ password based CMS). ++ [Steve Henson] ++ ++ *) Session-handling fixes: ++ - Fix handling of connections that are resuming with a session ID, ++ but also support Session Tickets. ++ - Fix a bug that suppressed issuing of a new ticket if the client ++ presented a ticket with an expired session. ++ - Try to set the ticket lifetime hint to something reasonable. ++ - Make tickets shorter by excluding irrelevant information. ++ - On the client side, don't ignore renewed tickets. ++ [Adam Langley, Bodo Moeller (Google)] ++ ++ *) Fix PSK session representation. ++ [Bodo Moeller] ++ ++ *) Add RC4-MD5 and AESNI-SHA1 "stitched" implementations. ++ ++ This work was sponsored by Intel. ++ [Andy Polyakov] ++ ++ *) Add GCM support to TLS library. Some custom code is needed to split ++ the IV between the fixed (from PRF) and explicit (from TLS record) ++ portions. This adds all GCM ciphersuites supported by RFC5288 and ++ RFC5289. Generalise some AES* cipherstrings to include GCM and ++ add a special AESGCM string for GCM only. ++ [Steve Henson] ++ ++ *) Expand range of ctrls for AES GCM. Permit setting invocation ++ field on decrypt and retrieval of invocation field only on encrypt. ++ [Steve Henson] ++ ++ *) Add HMAC ECC ciphersuites from RFC5289. Include SHA384 PRF support. ++ As required by RFC5289 these ciphersuites cannot be used if for ++ versions of TLS earlier than 1.2. ++ [Steve Henson] ++ ++ *) For FIPS capable OpenSSL interpret a NULL default public key method ++ as unset and return the appropriate default but do *not* set the default. ++ This means we can return the appropriate method in applications that ++ switch between FIPS and non-FIPS modes. ++ [Steve Henson] ++ ++ *) Redirect HMAC and CMAC operations to FIPS module in FIPS mode. If an ++ ENGINE is used then we cannot handle that in the FIPS module so we ++ keep original code iff non-FIPS operations are allowed. ++ [Steve Henson] ++ ++ *) Add -attime option to openssl utilities. ++ [Peter Eckersley , Ben Laurie and Steve Henson] ++ ++ *) Redirect DSA and DH operations to FIPS module in FIPS mode. ++ [Steve Henson] ++ ++ *) Redirect ECDSA and ECDH operations to FIPS module in FIPS mode. Also use ++ FIPS EC methods unconditionally for now. ++ [Steve Henson] ++ ++ *) New build option no-ec2m to disable characteristic 2 code. ++ [Steve Henson] ++ ++ *) Backport libcrypto audit of return value checking from 1.1.0-dev; not ++ all cases can be covered as some introduce binary incompatibilities. ++ [Steve Henson] ++ ++ *) Redirect RSA operations to FIPS module including keygen, ++ encrypt, decrypt, sign and verify. Block use of non FIPS RSA methods. ++ [Steve Henson] ++ ++ *) Add similar low level API blocking to ciphers. ++ [Steve Henson] ++ ++ *) Low level digest APIs are not approved in FIPS mode: any attempt ++ to use these will cause a fatal error. Applications that *really* want ++ to use them can use the private_* version instead. ++ [Steve Henson] ++ ++ *) Redirect cipher operations to FIPS module for FIPS builds. ++ [Steve Henson] ++ ++ *) Redirect digest operations to FIPS module for FIPS builds. ++ [Steve Henson] ++ ++ *) Update build system to add "fips" flag which will link in fipscanister.o ++ for static and shared library builds embedding a signature if needed. ++ [Steve Henson] ++ ++ *) Output TLS supported curves in preference order instead of numerical ++ order. This is currently hardcoded for the highest order curves first. ++ This should be configurable so applications can judge speed vs strength. ++ [Steve Henson] ++ ++ *) Add TLS v1.2 server support for client authentication. ++ [Steve Henson] ++ ++ *) Add support for FIPS mode in ssl library: disable SSLv3, non-FIPS ciphers ++ and enable MD5. ++ [Steve Henson] ++ ++ *) Functions FIPS_mode_set() and FIPS_mode() which call the underlying ++ FIPS modules versions. ++ [Steve Henson] ++ ++ *) Add TLS v1.2 client side support for client authentication. Keep cache ++ of handshake records longer as we don't know the hash algorithm to use ++ until after the certificate request message is received. ++ [Steve Henson] ++ ++ *) Initial TLS v1.2 client support. Add a default signature algorithms ++ extension including all the algorithms we support. Parse new signature ++ format in client key exchange. Relax some ECC signing restrictions for ++ TLS v1.2 as indicated in RFC5246. ++ [Steve Henson] ++ ++ *) Add server support for TLS v1.2 signature algorithms extension. Switch ++ to new signature format when needed using client digest preference. ++ All server ciphersuites should now work correctly in TLS v1.2. No client ++ support yet and no support for client certificates. ++ [Steve Henson] ++ ++ *) Initial TLS v1.2 support. Add new SHA256 digest to ssl code, switch ++ to SHA256 for PRF when using TLS v1.2 and later. Add new SHA256 based ++ ciphersuites. At present only RSA key exchange ciphersuites work with ++ TLS v1.2. Add new option for TLS v1.2 replacing the old and obsolete ++ SSL_OP_PKCS1_CHECK flags with SSL_OP_NO_TLSv1_2. New TLSv1.2 methods ++ and version checking. ++ [Steve Henson] ++ ++ *) New option OPENSSL_NO_SSL_INTERN. If an application can be compiled ++ with this defined it will not be affected by any changes to ssl internal ++ structures. Add several utility functions to allow openssl application ++ to work with OPENSSL_NO_SSL_INTERN defined. ++ [Steve Henson] ++ ++ *) Add SRP support. ++ [Tom Wu and Ben Laurie] ++ ++ *) Add functions to copy EVP_PKEY_METHOD and retrieve flags and id. ++ [Steve Henson] ++ ++ *) Permit abbreviated handshakes when renegotiating using the function ++ SSL_renegotiate_abbreviated(). ++ [Robin Seggelmann ] ++ ++ *) Add call to ENGINE_register_all_complete() to ++ ENGINE_load_builtin_engines(), so some implementations get used ++ automatically instead of needing explicit application support. ++ [Steve Henson] ++ ++ *) Add support for TLS key exporter as described in RFC5705. ++ [Robin Seggelmann , Steve Henson] ++ ++ *) Initial TLSv1.1 support. Since TLSv1.1 is very similar to TLS v1.0 only ++ a few changes are required: ++ ++ Add SSL_OP_NO_TLSv1_1 flag. ++ Add TLSv1_1 methods. ++ Update version checking logic to handle version 1.1. ++ Add explicit IV handling (ported from DTLS code). ++ Add command line options to s_client/s_server. ++ [Steve Henson] ++ ++ Changes between 1.0.0g and 1.0.0h [12 Mar 2012] ++ ++ *) Fix MMA (Bleichenbacher's attack on PKCS #1 v1.5 RSA padding) weakness ++ in CMS and PKCS7 code. When RSA decryption fails use a random key for ++ content decryption and always return the same error. Note: this attack ++ needs on average 2^20 messages so it only affects automated senders. The ++ old behaviour can be re-enabled in the CMS code by setting the ++ CMS_DEBUG_DECRYPT flag: this is useful for debugging and testing where ++ an MMA defence is not necessary. ++ Thanks to Ivan Nestlerode for discovering ++ this issue. (CVE-2012-0884) ++ [Steve Henson] ++ ++ *) Fix CVE-2011-4619: make sure we really are receiving a ++ client hello before rejecting multiple SGC restarts. Thanks to ++ Ivan Nestlerode for discovering this bug. ++ [Steve Henson] ++ ++ Changes between 1.0.0f and 1.0.0g [18 Jan 2012] ++ ++ *) Fix for DTLS DoS issue introduced by fix for CVE-2011-4109. ++ Thanks to Antonio Martin, Enterprise Secure Access Research and ++ Development, Cisco Systems, Inc. for discovering this bug and ++ preparing a fix. (CVE-2012-0050) ++ [Antonio Martin] ++ ++ Changes between 1.0.0e and 1.0.0f [4 Jan 2012] ++ ++ *) Nadhem Alfardan and Kenny Paterson have discovered an extension ++ of the Vaudenay padding oracle attack on CBC mode encryption ++ which enables an efficient plaintext recovery attack against ++ the OpenSSL implementation of DTLS. Their attack exploits timing ++ differences arising during decryption processing. A research ++ paper describing this attack can be found at: ++ http://www.isg.rhul.ac.uk/~kp/dtls.pdf ++ Thanks go to Nadhem Alfardan and Kenny Paterson of the Information ++ Security Group at Royal Holloway, University of London ++ (www.isg.rhul.ac.uk) for discovering this flaw and to Robin Seggelmann ++ and Michael Tuexen ++ for preparing the fix. (CVE-2011-4108) ++ [Robin Seggelmann, Michael Tuexen] ++ ++ *) Clear bytes used for block padding of SSL 3.0 records. ++ (CVE-2011-4576) ++ [Adam Langley (Google)] ++ ++ *) Only allow one SGC handshake restart for SSL/TLS. Thanks to George ++ Kadianakis for discovering this issue and ++ Adam Langley for preparing the fix. (CVE-2011-4619) ++ [Adam Langley (Google)] ++ ++ *) Check parameters are not NULL in GOST ENGINE. (CVE-2012-0027) ++ [Andrey Kulikov ] ++ ++ *) Prevent malformed RFC3779 data triggering an assertion failure. ++ Thanks to Andrew Chi, BBN Technologies, for discovering the flaw ++ and Rob Austein for fixing it. (CVE-2011-4577) ++ [Rob Austein ] ++ ++ *) Improved PRNG seeding for VOS. ++ [Paul Green ] ++ ++ *) Fix ssl_ciph.c set-up race. ++ [Adam Langley (Google)] ++ ++ *) Fix spurious failures in ecdsatest.c. ++ [Emilia Käsper (Google)] ++ ++ *) Fix the BIO_f_buffer() implementation (which was mixing different ++ interpretations of the '..._len' fields). ++ [Adam Langley (Google)] ++ ++ *) Fix handling of BN_BLINDING: now BN_BLINDING_invert_ex (rather than ++ BN_BLINDING_invert_ex) calls BN_BLINDING_update, ensuring that concurrent ++ threads won't reuse the same blinding coefficients. ++ ++ This also avoids the need to obtain the CRYPTO_LOCK_RSA_BLINDING ++ lock to call BN_BLINDING_invert_ex, and avoids one use of ++ BN_BLINDING_update for each BN_BLINDING structure (previously, ++ the last update always remained unused). ++ [Emilia Käsper (Google)] ++ ++ *) In ssl3_clear, preserve s3->init_extra along with s3->rbuf. ++ [Bob Buckholz (Google)] ++ ++ Changes between 1.0.0d and 1.0.0e [6 Sep 2011] ++ ++ *) Fix bug where CRLs with nextUpdate in the past are sometimes accepted ++ by initialising X509_STORE_CTX properly. (CVE-2011-3207) ++ [Kaspar Brand ] ++ ++ *) Fix SSL memory handling for (EC)DH ciphersuites, in particular ++ for multi-threaded use of ECDH. (CVE-2011-3210) ++ [Adam Langley (Google)] ++ ++ *) Fix x509_name_ex_d2i memory leak on bad inputs. ++ [Bodo Moeller] ++ ++ *) Remove hard coded ecdsaWithSHA1 signature tests in ssl code and check ++ signature public key algorithm by using OID xref utilities instead. ++ Before this you could only use some ECC ciphersuites with SHA1 only. ++ [Steve Henson] ++ ++ *) Add protection against ECDSA timing attacks as mentioned in the paper ++ by Billy Bob Brumley and Nicola Tuveri, see: ++ ++ http://eprint.iacr.org/2011/232.pdf ++ ++ [Billy Bob Brumley and Nicola Tuveri] ++ ++ Changes between 1.0.0c and 1.0.0d [8 Feb 2011] ++ ++ *) Fix parsing of OCSP stapling ClientHello extension. CVE-2011-0014 ++ [Neel Mehta, Adam Langley, Bodo Moeller (Google)] ++ ++ *) Fix bug in string printing code: if *any* escaping is enabled we must ++ escape the escape character (backslash) or the resulting string is ++ ambiguous. ++ [Steve Henson] ++ ++ Changes between 1.0.0b and 1.0.0c [2 Dec 2010] ++ ++ *) Disable code workaround for ancient and obsolete Netscape browsers ++ and servers: an attacker can use it in a ciphersuite downgrade attack. ++ Thanks to Martin Rex for discovering this bug. CVE-2010-4180 ++ [Steve Henson] ++ ++ *) Fixed J-PAKE implementation error, originally discovered by ++ Sebastien Martini, further info and confirmation from Stefan ++ Arentz and Feng Hao. Note that this fix is a security fix. CVE-2010-4252 ++ [Ben Laurie] ++ ++ Changes between 1.0.0a and 1.0.0b [16 Nov 2010] ++ ++ *) Fix extension code to avoid race conditions which can result in a buffer ++ overrun vulnerability: resumed sessions must not be modified as they can ++ be shared by multiple threads. CVE-2010-3864 ++ [Steve Henson] ++ ++ *) Fix WIN32 build system to correctly link an ENGINE directory into ++ a DLL. ++ [Steve Henson] ++ ++ Changes between 1.0.0 and 1.0.0a [01 Jun 2010] ++ ++ *) Check return value of int_rsa_verify in pkey_rsa_verifyrecover ++ (CVE-2010-1633) ++ [Steve Henson, Peter-Michael Hager ] ++ ++ Changes between 0.9.8n and 1.0.0 [29 Mar 2010] ++ ++ *) Add "missing" function EVP_CIPHER_CTX_copy(). This copies a cipher ++ context. The operation can be customised via the ctrl mechanism in ++ case ENGINEs want to include additional functionality. ++ [Steve Henson] ++ ++ *) Tolerate yet another broken PKCS#8 key format: private key value negative. ++ [Steve Henson] ++ ++ *) Add new -subject_hash_old and -issuer_hash_old options to x509 utility to ++ output hashes compatible with older versions of OpenSSL. ++ [Willy Weisz ] ++ ++ *) Fix compression algorithm handling: if resuming a session use the ++ compression algorithm of the resumed session instead of determining ++ it from client hello again. Don't allow server to change algorithm. ++ [Steve Henson] ++ ++ *) Add load_crls() function to apps tidying load_certs() too. Add option ++ to verify utility to allow additional CRLs to be included. ++ [Steve Henson] ++ ++ *) Update OCSP request code to permit adding custom headers to the request: ++ some responders need this. ++ [Steve Henson] ++ ++ *) The function EVP_PKEY_sign() returns <=0 on error: check return code ++ correctly. ++ [Julia Lawall ] ++ ++ *) Update verify callback code in apps/s_cb.c and apps/verify.c, it ++ needlessly dereferenced structures, used obsolete functions and ++ didn't handle all updated verify codes correctly. ++ [Steve Henson] ++ ++ *) Disable MD2 in the default configuration. ++ [Steve Henson] ++ ++ *) In BIO_pop() and BIO_push() use the ctrl argument (which was NULL) to ++ indicate the initial BIO being pushed or popped. This makes it possible ++ to determine whether the BIO is the one explicitly called or as a result ++ of the ctrl being passed down the chain. Fix BIO_pop() and SSL BIOs so ++ it handles reference counts correctly and doesn't zero out the I/O bio ++ when it is not being explicitly popped. WARNING: applications which ++ included workarounds for the old buggy behaviour will need to be modified ++ or they could free up already freed BIOs. ++ [Steve Henson] ++ ++ *) Extend the uni2asc/asc2uni => OPENSSL_uni2asc/OPENSSL_asc2uni ++ renaming to all platforms (within the 0.9.8 branch, this was ++ done conditionally on Netware platforms to avoid a name clash). ++ [Guenter ] ++ ++ *) Add ECDHE and PSK support to DTLS. ++ [Michael Tuexen ] ++ ++ *) Add CHECKED_STACK_OF macro to safestack.h, otherwise safestack can't ++ be used on C++. ++ [Steve Henson] ++ ++ *) Add "missing" function EVP_MD_flags() (without this the only way to ++ retrieve a digest flags is by accessing the structure directly. Update ++ EVP_MD_do_all*() and EVP_CIPHER_do_all*() to include the name a digest ++ or cipher is registered as in the "from" argument. Print out all ++ registered digests in the dgst usage message instead of manually ++ attempting to work them out. ++ [Steve Henson] ++ ++ *) If no SSLv2 ciphers are used don't use an SSLv2 compatible client hello: ++ this allows the use of compression and extensions. Change default cipher ++ string to remove SSLv2 ciphersuites. This effectively avoids ancient SSLv2 ++ by default unless an application cipher string requests it. ++ [Steve Henson] ++ ++ *) Alter match criteria in PKCS12_parse(). It used to try to use local ++ key ids to find matching certificates and keys but some PKCS#12 files ++ don't follow the (somewhat unwritten) rules and this strategy fails. ++ Now just gather all certificates together and the first private key ++ then look for the first certificate that matches the key. ++ [Steve Henson] ++ ++ *) Support use of registered digest and cipher names for dgst and cipher ++ commands instead of having to add each one as a special case. So now ++ you can do: ++ ++ openssl sha256 foo ++ ++ as well as: ++ ++ openssl dgst -sha256 foo ++ ++ and this works for ENGINE based algorithms too. ++ ++ [Steve Henson] ++ ++ *) Update Gost ENGINE to support parameter files. ++ [Victor B. Wagner ] ++ ++ *) Support GeneralizedTime in ca utility. ++ [Oliver Martin , Steve Henson] ++ ++ *) Enhance the hash format used for certificate directory links. The new ++ form uses the canonical encoding (meaning equivalent names will work ++ even if they aren't identical) and uses SHA1 instead of MD5. This form ++ is incompatible with the older format and as a result c_rehash should ++ be used to rebuild symbolic links. ++ [Steve Henson] ++ ++ *) Make PKCS#8 the default write format for private keys, replacing the ++ traditional format. This form is standardised, more secure and doesn't ++ include an implicit MD5 dependency. ++ [Steve Henson] ++ ++ *) Add a $gcc_devteam_warn option to Configure. The idea is that any code ++ committed to OpenSSL should pass this lot as a minimum. ++ [Steve Henson] ++ ++ *) Add session ticket override functionality for use by EAP-FAST. ++ [Jouni Malinen ] ++ ++ *) Modify HMAC functions to return a value. Since these can be implemented ++ in an ENGINE errors can occur. ++ [Steve Henson] ++ ++ *) Type-checked OBJ_bsearch_ex. ++ [Ben Laurie] ++ ++ *) Type-checked OBJ_bsearch. Also some constification necessitated ++ by type-checking. Still to come: TXT_DB, bsearch(?), ++ OBJ_bsearch_ex, qsort, CRYPTO_EX_DATA, ASN1_VALUE, ASN1_STRING, ++ CONF_VALUE. ++ [Ben Laurie] ++ ++ *) New function OPENSSL_gmtime_adj() to add a specific number of days and ++ seconds to a tm structure directly, instead of going through OS ++ specific date routines. This avoids any issues with OS routines such ++ as the year 2038 bug. New *_adj() functions for ASN1 time structures ++ and X509_time_adj_ex() to cover the extended range. The existing ++ X509_time_adj() is still usable and will no longer have any date issues. ++ [Steve Henson] ++ ++ *) Delta CRL support. New use deltas option which will attempt to locate ++ and search any appropriate delta CRLs available. ++ ++ This work was sponsored by Google. ++ [Steve Henson] ++ ++ *) Support for CRLs partitioned by reason code. Reorganise CRL processing ++ code and add additional score elements. Validate alternate CRL paths ++ as part of the CRL checking and indicate a new error "CRL path validation ++ error" in this case. Applications wanting additional details can use ++ the verify callback and check the new "parent" field. If this is not ++ NULL CRL path validation is taking place. Existing applications won't ++ see this because it requires extended CRL support which is off by ++ default. ++ ++ This work was sponsored by Google. ++ [Steve Henson] ++ ++ *) Support for freshest CRL extension. ++ ++ This work was sponsored by Google. ++ [Steve Henson] ++ ++ *) Initial indirect CRL support. Currently only supported in the CRLs ++ passed directly and not via lookup. Process certificate issuer ++ CRL entry extension and lookup CRL entries by bother issuer name ++ and serial number. Check and process CRL issuer entry in IDP extension. ++ ++ This work was sponsored by Google. ++ [Steve Henson] ++ ++ *) Add support for distinct certificate and CRL paths. The CRL issuer ++ certificate is validated separately in this case. Only enabled if ++ an extended CRL support flag is set: this flag will enable additional ++ CRL functionality in future. ++ ++ This work was sponsored by Google. ++ [Steve Henson] ++ ++ *) Add support for policy mappings extension. ++ ++ This work was sponsored by Google. ++ [Steve Henson] ++ ++ *) Fixes to pathlength constraint, self issued certificate handling, ++ policy processing to align with RFC3280 and PKITS tests. ++ ++ This work was sponsored by Google. ++ [Steve Henson] ++ ++ *) Support for name constraints certificate extension. DN, email, DNS ++ and URI types are currently supported. ++ ++ This work was sponsored by Google. ++ [Steve Henson] ++ ++ *) To cater for systems that provide a pointer-based thread ID rather ++ than numeric, deprecate the current numeric thread ID mechanism and ++ replace it with a structure and associated callback type. This ++ mechanism allows a numeric "hash" to be extracted from a thread ID in ++ either case, and on platforms where pointers are larger than 'long', ++ mixing is done to help ensure the numeric 'hash' is usable even if it ++ can't be guaranteed unique. The default mechanism is to use "&errno" ++ as a pointer-based thread ID to distinguish between threads. ++ ++ Applications that want to provide their own thread IDs should now use ++ CRYPTO_THREADID_set_callback() to register a callback that will call ++ either CRYPTO_THREADID_set_numeric() or CRYPTO_THREADID_set_pointer(). ++ ++ Note that ERR_remove_state() is now deprecated, because it is tied ++ to the assumption that thread IDs are numeric. ERR_remove_state(0) ++ to free the current thread's error state should be replaced by ++ ERR_remove_thread_state(NULL). ++ ++ (This new approach replaces the functions CRYPTO_set_idptr_callback(), ++ CRYPTO_get_idptr_callback(), and CRYPTO_thread_idptr() that existed in ++ OpenSSL 0.9.9-dev between June 2006 and August 2008. Also, if an ++ application was previously providing a numeric thread callback that ++ was inappropriate for distinguishing threads, then uniqueness might ++ have been obtained with &errno that happened immediately in the ++ intermediate development versions of OpenSSL; this is no longer the ++ case, the numeric thread callback will now override the automatic use ++ of &errno.) ++ [Geoff Thorpe, with help from Bodo Moeller] ++ ++ *) Initial support for different CRL issuing certificates. This covers a ++ simple case where the self issued certificates in the chain exist and ++ the real CRL issuer is higher in the existing chain. ++ ++ This work was sponsored by Google. ++ [Steve Henson] ++ ++ *) Removed effectively defunct crypto/store from the build. ++ [Ben Laurie] ++ ++ *) Revamp of STACK to provide stronger type-checking. Still to come: ++ TXT_DB, bsearch(?), OBJ_bsearch, qsort, CRYPTO_EX_DATA, ASN1_VALUE, ++ ASN1_STRING, CONF_VALUE. ++ [Ben Laurie] ++ ++ *) Add a new SSL_MODE_RELEASE_BUFFERS mode flag to release unused buffer ++ RAM on SSL connections. This option can save about 34k per idle SSL. ++ [Nick Mathewson] ++ ++ *) Revamp of LHASH to provide stronger type-checking. Still to come: ++ STACK, TXT_DB, bsearch, qsort. ++ [Ben Laurie] ++ ++ *) Initial support for Cryptographic Message Syntax (aka CMS) based ++ on RFC3850, RFC3851 and RFC3852. New cms directory and cms utility, ++ support for data, signedData, compressedData, digestedData and ++ encryptedData, envelopedData types included. Scripts to check against ++ RFC4134 examples draft and interop and consistency checks of many ++ content types and variants. ++ [Steve Henson] ++ ++ *) Add options to enc utility to support use of zlib compression BIO. ++ [Steve Henson] ++ ++ *) Extend mk1mf to support importing of options and assembly language ++ files from Configure script, currently only included in VC-WIN32. ++ The assembly language rules can now optionally generate the source ++ files from the associated perl scripts. ++ [Steve Henson] ++ ++ *) Implement remaining functionality needed to support GOST ciphersuites. ++ Interop testing has been performed using CryptoPro implementations. ++ [Victor B. Wagner ] ++ ++ *) s390x assembler pack. ++ [Andy Polyakov] ++ ++ *) ARMv4 assembler pack. ARMv4 refers to v4 and later ISA, not CPU ++ "family." ++ [Andy Polyakov] ++ ++ *) Implement Opaque PRF Input TLS extension as specified in ++ draft-rescorla-tls-opaque-prf-input-00.txt. Since this is not an ++ official specification yet and no extension type assignment by ++ IANA exists, this extension (for now) will have to be explicitly ++ enabled when building OpenSSL by providing the extension number ++ to use. For example, specify an option ++ ++ -DTLSEXT_TYPE_opaque_prf_input=0x9527 ++ ++ to the "config" or "Configure" script to enable the extension, ++ assuming extension number 0x9527 (which is a completely arbitrary ++ and unofficial assignment based on the MD5 hash of the Internet ++ Draft). Note that by doing so, you potentially lose ++ interoperability with other TLS implementations since these might ++ be using the same extension number for other purposes. ++ ++ SSL_set_tlsext_opaque_prf_input(ssl, src, len) is used to set the ++ opaque PRF input value to use in the handshake. This will create ++ an interal copy of the length-'len' string at 'src', and will ++ return non-zero for success. ++ ++ To get more control and flexibility, provide a callback function ++ by using ++ ++ SSL_CTX_set_tlsext_opaque_prf_input_callback(ctx, cb) ++ SSL_CTX_set_tlsext_opaque_prf_input_callback_arg(ctx, arg) ++ ++ where ++ ++ int (*cb)(SSL *, void *peerinput, size_t len, void *arg); ++ void *arg; ++ ++ Callback function 'cb' will be called in handshakes, and is ++ expected to use SSL_set_tlsext_opaque_prf_input() as appropriate. ++ Argument 'arg' is for application purposes (the value as given to ++ SSL_CTX_set_tlsext_opaque_prf_input_callback_arg() will directly ++ be provided to the callback function). The callback function ++ has to return non-zero to report success: usually 1 to use opaque ++ PRF input just if possible, or 2 to enforce use of the opaque PRF ++ input. In the latter case, the library will abort the handshake ++ if opaque PRF input is not successfully negotiated. ++ ++ Arguments 'peerinput' and 'len' given to the callback function ++ will always be NULL and 0 in the case of a client. A server will ++ see the client's opaque PRF input through these variables if ++ available (NULL and 0 otherwise). Note that if the server ++ provides an opaque PRF input, the length must be the same as the ++ length of the client's opaque PRF input. ++ ++ Note that the callback function will only be called when creating ++ a new session (session resumption can resume whatever was ++ previously negotiated), and will not be called in SSL 2.0 ++ handshakes; thus, SSL_CTX_set_options(ctx, SSL_OP_NO_SSLv2) or ++ SSL_set_options(ssl, SSL_OP_NO_SSLv2) is especially recommended ++ for applications that need to enforce opaque PRF input. ++ ++ [Bodo Moeller] ++ ++ *) Update ssl code to support digests other than SHA1+MD5 for handshake ++ MAC. ++ ++ [Victor B. Wagner ] ++ ++ *) Add RFC4507 support to OpenSSL. This includes the corrections in ++ RFC4507bis. The encrypted ticket format is an encrypted encoded ++ SSL_SESSION structure, that way new session features are automatically ++ supported. ++ ++ If a client application caches session in an SSL_SESSION structure ++ support is transparent because tickets are now stored in the encoded ++ SSL_SESSION. ++ ++ The SSL_CTX structure automatically generates keys for ticket ++ protection in servers so again support should be possible ++ with no application modification. ++ ++ If a client or server wishes to disable RFC4507 support then the option ++ SSL_OP_NO_TICKET can be set. ++ ++ Add a TLS extension debugging callback to allow the contents of any client ++ or server extensions to be examined. ++ ++ This work was sponsored by Google. ++ [Steve Henson] ++ ++ *) Final changes to avoid use of pointer pointer casts in OpenSSL. ++ OpenSSL should now compile cleanly on gcc 4.2 ++ [Peter Hartley , Steve Henson] ++ ++ *) Update SSL library to use new EVP_PKEY MAC API. Include generic MAC ++ support including streaming MAC support: this is required for GOST ++ ciphersuite support. ++ [Victor B. Wagner , Steve Henson] ++ ++ *) Add option -stream to use PKCS#7 streaming in smime utility. New ++ function i2d_PKCS7_bio_stream() and PEM_write_PKCS7_bio_stream() ++ to output in BER and PEM format. ++ [Steve Henson] ++ ++ *) Experimental support for use of HMAC via EVP_PKEY interface. This ++ allows HMAC to be handled via the EVP_DigestSign*() interface. The ++ EVP_PKEY "key" in this case is the HMAC key, potentially allowing ++ ENGINE support for HMAC keys which are unextractable. New -mac and ++ -macopt options to dgst utility. ++ [Steve Henson] ++ ++ *) New option -sigopt to dgst utility. Update dgst to use ++ EVP_Digest{Sign,Verify}*. These two changes make it possible to use ++ alternative signing parameters such as X9.31 or PSS in the dgst ++ utility. ++ [Steve Henson] ++ ++ *) Change ssl_cipher_apply_rule(), the internal function that does ++ the work each time a ciphersuite string requests enabling ++ ("foo+bar"), moving ("+foo+bar"), disabling ("-foo+bar", or ++ removing ("!foo+bar") a class of ciphersuites: Now it maintains ++ the order of disabled ciphersuites such that those ciphersuites ++ that most recently went from enabled to disabled not only stay ++ in order with respect to each other, but also have higher priority ++ than other disabled ciphersuites the next time ciphersuites are ++ enabled again. ++ ++ This means that you can now say, e.g., "PSK:-PSK:HIGH" to enable ++ the same ciphersuites as with "HIGH" alone, but in a specific ++ order where the PSK ciphersuites come first (since they are the ++ most recently disabled ciphersuites when "HIGH" is parsed). ++ ++ Also, change ssl_create_cipher_list() (using this new ++ funcionality) such that between otherwise identical ++ cihpersuites, ephemeral ECDH is preferred over ephemeral DH in ++ the default order. ++ [Bodo Moeller] ++ ++ *) Change ssl_create_cipher_list() so that it automatically ++ arranges the ciphersuites in reasonable order before starting ++ to process the rule string. Thus, the definition for "DEFAULT" ++ (SSL_DEFAULT_CIPHER_LIST) now is just "ALL:!aNULL:!eNULL", but ++ remains equivalent to "AES:ALL:!aNULL:!eNULL:+aECDH:+kRSA:+RC4:@STRENGTH". ++ This makes it much easier to arrive at a reasonable default order ++ in applications for which anonymous ciphers are OK (meaning ++ that you can't actually use DEFAULT). ++ [Bodo Moeller; suggested by Victor Duchovni] ++ ++ *) Split the SSL/TLS algorithm mask (as used for ciphersuite string ++ processing) into multiple integers instead of setting ++ "SSL_MKEY_MASK" bits, "SSL_AUTH_MASK" bits, "SSL_ENC_MASK", ++ "SSL_MAC_MASK", and "SSL_SSL_MASK" bits all in a single integer. ++ (These masks as well as the individual bit definitions are hidden ++ away into the non-exported interface ssl/ssl_locl.h, so this ++ change to the definition of the SSL_CIPHER structure shouldn't ++ affect applications.) This give us more bits for each of these ++ categories, so there is no longer a need to coagulate AES128 and ++ AES256 into a single algorithm bit, and to coagulate Camellia128 ++ and Camellia256 into a single algorithm bit, which has led to all ++ kinds of kludges. ++ ++ Thus, among other things, the kludge introduced in 0.9.7m and ++ 0.9.8e for masking out AES256 independently of AES128 or masking ++ out Camellia256 independently of AES256 is not needed here in 0.9.9. ++ ++ With the change, we also introduce new ciphersuite aliases that ++ so far were missing: "AES128", "AES256", "CAMELLIA128", and ++ "CAMELLIA256". ++ [Bodo Moeller] ++ ++ *) Add support for dsa-with-SHA224 and dsa-with-SHA256. ++ Use the leftmost N bytes of the signature input if the input is ++ larger than the prime q (with N being the size in bytes of q). ++ [Nils Larsch] ++ ++ *) Very *very* experimental PKCS#7 streaming encoder support. Nothing uses ++ it yet and it is largely untested. ++ [Steve Henson] ++ ++ *) Add support for the ecdsa-with-SHA224/256/384/512 signature types. ++ [Nils Larsch] ++ ++ *) Initial incomplete changes to avoid need for function casts in OpenSSL ++ some compilers (gcc 4.2 and later) reject their use. Safestack is ++ reimplemented. Update ASN1 to avoid use of legacy functions. ++ [Steve Henson] ++ ++ *) Win32/64 targets are linked with Winsock2. ++ [Andy Polyakov] ++ ++ *) Add an X509_CRL_METHOD structure to allow CRL processing to be redirected ++ to external functions. This can be used to increase CRL handling ++ efficiency especially when CRLs are very large by (for example) storing ++ the CRL revoked certificates in a database. ++ [Steve Henson] ++ ++ *) Overhaul of by_dir code. Add support for dynamic loading of CRLs so ++ new CRLs added to a directory can be used. New command line option ++ -verify_return_error to s_client and s_server. This causes real errors ++ to be returned by the verify callback instead of carrying on no matter ++ what. This reflects the way a "real world" verify callback would behave. ++ [Steve Henson] ++ ++ *) GOST engine, supporting several GOST algorithms and public key formats. ++ Kindly donated by Cryptocom. ++ [Cryptocom] ++ ++ *) Partial support for Issuing Distribution Point CRL extension. CRLs ++ partitioned by DP are handled but no indirect CRL or reason partitioning ++ (yet). Complete overhaul of CRL handling: now the most suitable CRL is ++ selected via a scoring technique which handles IDP and AKID in CRLs. ++ [Steve Henson] ++ ++ *) New X509_STORE_CTX callbacks lookup_crls() and lookup_certs() which ++ will ultimately be used for all verify operations: this will remove the ++ X509_STORE dependency on certificate verification and allow alternative ++ lookup methods. X509_STORE based implementations of these two callbacks. ++ [Steve Henson] ++ ++ *) Allow multiple CRLs to exist in an X509_STORE with matching issuer names. ++ Modify get_crl() to find a valid (unexpired) CRL if possible. ++ [Steve Henson] ++ ++ *) New function X509_CRL_match() to check if two CRLs are identical. Normally ++ this would be called X509_CRL_cmp() but that name is already used by ++ a function that just compares CRL issuer names. Cache several CRL ++ extensions in X509_CRL structure and cache CRLDP in X509. ++ [Steve Henson] ++ ++ *) Store a "canonical" representation of X509_NAME structure (ASN1 Name) ++ this maps equivalent X509_NAME structures into a consistent structure. ++ Name comparison can then be performed rapidly using memcmp(). ++ [Steve Henson] ++ ++ *) Non-blocking OCSP request processing. Add -timeout option to ocsp ++ utility. ++ [Steve Henson] ++ ++ *) Allow digests to supply their own micalg string for S/MIME type using ++ the ctrl EVP_MD_CTRL_MICALG. ++ [Steve Henson] ++ ++ *) During PKCS7 signing pass the PKCS7 SignerInfo structure to the ++ EVP_PKEY_METHOD before and after signing via the EVP_PKEY_CTRL_PKCS7_SIGN ++ ctrl. It can then customise the structure before and/or after signing ++ if necessary. ++ [Steve Henson] ++ ++ *) New function OBJ_add_sigid() to allow application defined signature OIDs ++ to be added to OpenSSLs internal tables. New function OBJ_sigid_free() ++ to free up any added signature OIDs. ++ [Steve Henson] ++ ++ *) New functions EVP_CIPHER_do_all(), EVP_CIPHER_do_all_sorted(), ++ EVP_MD_do_all() and EVP_MD_do_all_sorted() to enumerate internal ++ digest and cipher tables. New options added to openssl utility: ++ list-message-digest-algorithms and list-cipher-algorithms. ++ [Steve Henson] ++ ++ *) Change the array representation of binary polynomials: the list ++ of degrees of non-zero coefficients is now terminated with -1. ++ Previously it was terminated with 0, which was also part of the ++ value; thus, the array representation was not applicable to ++ polynomials where t^0 has coefficient zero. This change makes ++ the array representation useful in a more general context. ++ [Douglas Stebila] ++ ++ *) Various modifications and fixes to SSL/TLS cipher string ++ handling. For ECC, the code now distinguishes between fixed ECDH ++ with RSA certificates on the one hand and with ECDSA certificates ++ on the other hand, since these are separate ciphersuites. The ++ unused code for Fortezza ciphersuites has been removed. ++ ++ For consistency with EDH, ephemeral ECDH is now called "EECDH" ++ (not "ECDHE"). For consistency with the code for DH ++ certificates, use of ECDH certificates is now considered ECDH ++ authentication, not RSA or ECDSA authentication (the latter is ++ merely the CA's signing algorithm and not actively used in the ++ protocol). ++ ++ The temporary ciphersuite alias "ECCdraft" is no longer ++ available, and ECC ciphersuites are no longer excluded from "ALL" ++ and "DEFAULT". The following aliases now exist for RFC 4492 ++ ciphersuites, most of these by analogy with the DH case: ++ ++ kECDHr - ECDH cert, signed with RSA ++ kECDHe - ECDH cert, signed with ECDSA ++ kECDH - ECDH cert (signed with either RSA or ECDSA) ++ kEECDH - ephemeral ECDH ++ ECDH - ECDH cert or ephemeral ECDH ++ ++ aECDH - ECDH cert ++ aECDSA - ECDSA cert ++ ECDSA - ECDSA cert ++ ++ AECDH - anonymous ECDH ++ EECDH - non-anonymous ephemeral ECDH (equivalent to "kEECDH:-AECDH") ++ ++ [Bodo Moeller] ++ ++ *) Add additional S/MIME capabilities for AES and GOST ciphers if supported. ++ Use correct micalg parameters depending on digest(s) in signed message. ++ [Steve Henson] ++ ++ *) Add engine support for EVP_PKEY_ASN1_METHOD. Add functions to process ++ an ENGINE asn1 method. Support ENGINE lookups in the ASN1 code. ++ [Steve Henson] ++ ++ *) Initial engine support for EVP_PKEY_METHOD. New functions to permit ++ an engine to register a method. Add ENGINE lookups for methods and ++ functional reference processing. ++ [Steve Henson] ++ ++ *) New functions EVP_Digest{Sign,Verify)*. These are enchance versions of ++ EVP_{Sign,Verify}* which allow an application to customise the signature ++ process. ++ [Steve Henson] ++ ++ *) New -resign option to smime utility. This adds one or more signers ++ to an existing PKCS#7 signedData structure. Also -md option to use an ++ alternative message digest algorithm for signing. ++ [Steve Henson] ++ ++ *) Tidy up PKCS#7 routines and add new functions to make it easier to ++ create PKCS7 structures containing multiple signers. Update smime ++ application to support multiple signers. ++ [Steve Henson] ++ ++ *) New -macalg option to pkcs12 utility to allow setting of an alternative ++ digest MAC. ++ [Steve Henson] ++ ++ *) Initial support for PKCS#5 v2.0 PRFs other than default SHA1 HMAC. ++ Reorganize PBE internals to lookup from a static table using NIDs, ++ add support for HMAC PBE OID translation. Add a EVP_CIPHER ctrl: ++ EVP_CTRL_PBE_PRF_NID this allows a cipher to specify an alternative ++ PRF which will be automatically used with PBES2. ++ [Steve Henson] ++ ++ *) Replace the algorithm specific calls to generate keys in "req" with the ++ new API. ++ [Steve Henson] ++ ++ *) Update PKCS#7 enveloped data routines to use new API. This is now ++ supported by any public key method supporting the encrypt operation. A ++ ctrl is added to allow the public key algorithm to examine or modify ++ the PKCS#7 RecipientInfo structure if it needs to: for RSA this is ++ a no op. ++ [Steve Henson] ++ ++ *) Add a ctrl to asn1 method to allow a public key algorithm to express ++ a default digest type to use. In most cases this will be SHA1 but some ++ algorithms (such as GOST) need to specify an alternative digest. The ++ return value indicates how strong the preference is 1 means optional and ++ 2 is mandatory (that is it is the only supported type). Modify ++ ASN1_item_sign() to accept a NULL digest argument to indicate it should ++ use the default md. Update openssl utilities to use the default digest ++ type for signing if it is not explicitly indicated. ++ [Steve Henson] ++ ++ *) Use OID cross reference table in ASN1_sign() and ASN1_verify(). New ++ EVP_MD flag EVP_MD_FLAG_PKEY_METHOD_SIGNATURE. This uses the relevant ++ signing method from the key type. This effectively removes the link ++ between digests and public key types. ++ [Steve Henson] ++ ++ *) Add an OID cross reference table and utility functions. Its purpose is to ++ translate between signature OIDs such as SHA1WithrsaEncryption and SHA1, ++ rsaEncryption. This will allow some of the algorithm specific hackery ++ needed to use the correct OID to be removed. ++ [Steve Henson] ++ ++ *) Remove algorithm specific dependencies when setting PKCS7_SIGNER_INFO ++ structures for PKCS7_sign(). They are now set up by the relevant public ++ key ASN1 method. ++ [Steve Henson] ++ ++ *) Add provisional EC pkey method with support for ECDSA and ECDH. ++ [Steve Henson] ++ ++ *) Add support for key derivation (agreement) in the API, DH method and ++ pkeyutl. ++ [Steve Henson] ++ ++ *) Add DSA pkey method and DH pkey methods, extend DH ASN1 method to support ++ public and private key formats. As a side effect these add additional ++ command line functionality not previously available: DSA signatures can be ++ generated and verified using pkeyutl and DH key support and generation in ++ pkey, genpkey. ++ [Steve Henson] ++ ++ *) BeOS support. ++ [Oliver Tappe ] ++ ++ *) New make target "install_html_docs" installs HTML renditions of the ++ manual pages. ++ [Oliver Tappe ] ++ ++ *) New utility "genpkey" this is analogous to "genrsa" etc except it can ++ generate keys for any algorithm. Extend and update EVP_PKEY_METHOD to ++ support key and parameter generation and add initial key generation ++ functionality for RSA. ++ [Steve Henson] ++ ++ *) Add functions for main EVP_PKEY_method operations. The undocumented ++ functions EVP_PKEY_{encrypt,decrypt} have been renamed to ++ EVP_PKEY_{encrypt,decrypt}_old. ++ [Steve Henson] ++ ++ *) Initial definitions for EVP_PKEY_METHOD. This will be a high level public ++ key API, doesn't do much yet. ++ [Steve Henson] ++ ++ *) New function EVP_PKEY_asn1_get0_info() to retrieve information about ++ public key algorithms. New option to openssl utility: ++ "list-public-key-algorithms" to print out info. ++ [Steve Henson] ++ ++ *) Implement the Supported Elliptic Curves Extension for ++ ECC ciphersuites from draft-ietf-tls-ecc-12.txt. ++ [Douglas Stebila] ++ ++ *) Don't free up OIDs in OBJ_cleanup() if they are in use by EVP_MD or ++ EVP_CIPHER structures to avoid later problems in EVP_cleanup(). ++ [Steve Henson] ++ ++ *) New utilities pkey and pkeyparam. These are similar to algorithm specific ++ utilities such as rsa, dsa, dsaparam etc except they process any key ++ type. ++ [Steve Henson] ++ ++ *) Transfer public key printing routines to EVP_PKEY_ASN1_METHOD. New ++ functions EVP_PKEY_print_public(), EVP_PKEY_print_private(), ++ EVP_PKEY_print_param() to print public key data from an EVP_PKEY ++ structure. ++ [Steve Henson] ++ ++ *) Initial support for pluggable public key ASN1. ++ De-spaghettify the public key ASN1 handling. Move public and private ++ key ASN1 handling to a new EVP_PKEY_ASN1_METHOD structure. Relocate ++ algorithm specific handling to a single module within the relevant ++ algorithm directory. Add functions to allow (near) opaque processing ++ of public and private key structures. ++ [Steve Henson] ++ ++ *) Implement the Supported Point Formats Extension for ++ ECC ciphersuites from draft-ietf-tls-ecc-12.txt. ++ [Douglas Stebila] ++ ++ *) Add initial support for RFC 4279 PSK TLS ciphersuites. Add members ++ for the psk identity [hint] and the psk callback functions to the ++ SSL_SESSION, SSL and SSL_CTX structure. ++ ++ New ciphersuites: ++ PSK-RC4-SHA, PSK-3DES-EDE-CBC-SHA, PSK-AES128-CBC-SHA, ++ PSK-AES256-CBC-SHA ++ ++ New functions: ++ SSL_CTX_use_psk_identity_hint ++ SSL_get_psk_identity_hint ++ SSL_get_psk_identity ++ SSL_use_psk_identity_hint ++ ++ [Mika Kousa and Pasi Eronen of Nokia Corporation] ++ ++ *) Add RFC 3161 compliant time stamp request creation, response generation ++ and response verification functionality. ++ [Zoltán Glózik , The OpenTSA Project] ++ ++ *) Add initial support for TLS extensions, specifically for the server_name ++ extension so far. The SSL_SESSION, SSL_CTX, and SSL data structures now ++ have new members for a host name. The SSL data structure has an ++ additional member SSL_CTX *initial_ctx so that new sessions can be ++ stored in that context to allow for session resumption, even after the ++ SSL has been switched to a new SSL_CTX in reaction to a client's ++ server_name extension. ++ ++ New functions (subject to change): ++ ++ SSL_get_servername() ++ SSL_get_servername_type() ++ SSL_set_SSL_CTX() ++ ++ New CTRL codes and macros (subject to change): ++ ++ SSL_CTRL_SET_TLSEXT_SERVERNAME_CB ++ - SSL_CTX_set_tlsext_servername_callback() ++ SSL_CTRL_SET_TLSEXT_SERVERNAME_ARG ++ - SSL_CTX_set_tlsext_servername_arg() ++ SSL_CTRL_SET_TLSEXT_HOSTNAME - SSL_set_tlsext_host_name() ++ ++ openssl s_client has a new '-servername ...' option. ++ ++ openssl s_server has new options '-servername_host ...', '-cert2 ...', ++ '-key2 ...', '-servername_fatal' (subject to change). This allows ++ testing the HostName extension for a specific single host name ('-cert' ++ and '-key' remain fallbacks for handshakes without HostName ++ negotiation). If the unrecognized_name alert has to be sent, this by ++ default is a warning; it becomes fatal with the '-servername_fatal' ++ option. ++ ++ [Peter Sylvester, Remy Allais, Christophe Renou] ++ ++ *) Whirlpool hash implementation is added. ++ [Andy Polyakov] ++ ++ *) BIGNUM code on 64-bit SPARCv9 targets is switched from bn(64,64) to ++ bn(64,32). Because of instruction set limitations it doesn't have ++ any negative impact on performance. This was done mostly in order ++ to make it possible to share assembler modules, such as bn_mul_mont ++ implementations, between 32- and 64-bit builds without hassle. ++ [Andy Polyakov] ++ ++ *) Move code previously exiled into file crypto/ec/ec2_smpt.c ++ to ec2_smpl.c, and no longer require the OPENSSL_EC_BIN_PT_COMP ++ macro. ++ [Bodo Moeller] ++ ++ *) New candidate for BIGNUM assembler implementation, bn_mul_mont, ++ dedicated Montgomery multiplication procedure, is introduced. ++ BN_MONT_CTX is modified to allow bn_mul_mont to reach for higher ++ "64-bit" performance on certain 32-bit targets. ++ [Andy Polyakov] ++ ++ *) New option SSL_OP_NO_COMP to disable use of compression selectively ++ in SSL structures. New SSL ctrl to set maximum send fragment size. ++ Save memory by seeting the I/O buffer sizes dynamically instead of ++ using the maximum available value. ++ [Steve Henson] ++ ++ *) New option -V for 'openssl ciphers'. This prints the ciphersuite code ++ in addition to the text details. ++ [Bodo Moeller] ++ ++ *) Very, very preliminary EXPERIMENTAL support for printing of general ++ ASN1 structures. This currently produces rather ugly output and doesn't ++ handle several customised structures at all. ++ [Steve Henson] ++ ++ *) Integrated support for PVK file format and some related formats such ++ as MS PUBLICKEYBLOB and PRIVATEKEYBLOB. Command line switches to support ++ these in the 'rsa' and 'dsa' utilities. ++ [Steve Henson] ++ ++ *) Support for PKCS#1 RSAPublicKey format on rsa utility command line. ++ [Steve Henson] ++ ++ *) Remove the ancient ASN1_METHOD code. This was only ever used in one ++ place for the (very old) "NETSCAPE" format certificates which are now ++ handled using new ASN1 code equivalents. ++ [Steve Henson] ++ ++ *) Let the TLSv1_method() etc. functions return a 'const' SSL_METHOD ++ pointer and make the SSL_METHOD parameter in SSL_CTX_new, ++ SSL_CTX_set_ssl_version and SSL_set_ssl_method 'const'. ++ [Nils Larsch] ++ ++ *) Modify CRL distribution points extension code to print out previously ++ unsupported fields. Enhance extension setting code to allow setting of ++ all fields. ++ [Steve Henson] ++ ++ *) Add print and set support for Issuing Distribution Point CRL extension. ++ [Steve Henson] ++ ++ *) Change 'Configure' script to enable Camellia by default. ++ [NTT] ++ ++ Changes between 0.9.8m and 0.9.8n [24 Mar 2010] ++ ++ *) When rejecting SSL/TLS records due to an incorrect version number, never ++ update s->server with a new major version number. As of ++ - OpenSSL 0.9.8m if 'short' is a 16-bit type, ++ - OpenSSL 0.9.8f if 'short' is longer than 16 bits, ++ the previous behavior could result in a read attempt at NULL when ++ receiving specific incorrect SSL/TLS records once record payload ++ protection is active. (CVE-2010-0740) ++ [Bodo Moeller, Adam Langley ] ++ ++ *) Fix for CVE-2010-0433 where some kerberos enabled versions of OpenSSL ++ could be crashed if the relevant tables were not present (e.g. chrooted). ++ [Tomas Hoger ] ++ ++ Changes between 0.9.8l and 0.9.8m [25 Feb 2010] ++ ++ *) Always check bn_wexpend() return values for failure. (CVE-2009-3245) ++ [Martin Olsson, Neel Mehta] ++ ++ *) Fix X509_STORE locking: Every 'objs' access requires a lock (to ++ accommodate for stack sorting, always a write lock!). ++ [Bodo Moeller] ++ ++ *) On some versions of WIN32 Heap32Next is very slow. This can cause ++ excessive delays in the RAND_poll(): over a minute. As a workaround ++ include a time check in the inner Heap32Next loop too. ++ [Steve Henson] ++ ++ *) The code that handled flushing of data in SSL/TLS originally used the ++ BIO_CTRL_INFO ctrl to see if any data was pending first. This caused ++ the problem outlined in PR#1949. The fix suggested there however can ++ trigger problems with buggy BIO_CTRL_WPENDING (e.g. some versions ++ of Apache). So instead simplify the code to flush unconditionally. ++ This should be fine since flushing with no data to flush is a no op. ++ [Steve Henson] ++ ++ *) Handle TLS versions 2.0 and later properly and correctly use the ++ highest version of TLS/SSL supported. Although TLS >= 2.0 is some way ++ off ancient servers have a habit of sticking around for a while... ++ [Steve Henson] ++ ++ *) Modify compression code so it frees up structures without using the ++ ex_data callbacks. This works around a problem where some applications ++ call CRYPTO_cleanup_all_ex_data() before application exit (e.g. when ++ restarting) then use compression (e.g. SSL with compression) later. ++ This results in significant per-connection memory leaks and ++ has caused some security issues including CVE-2008-1678 and ++ CVE-2009-4355. ++ [Steve Henson] ++ ++ *) Constify crypto/cast (i.e., ): a CAST_KEY doesn't ++ change when encrypting or decrypting. ++ [Bodo Moeller] ++ ++ *) Add option SSL_OP_LEGACY_SERVER_CONNECT which will allow clients to ++ connect and renegotiate with servers which do not support RI. ++ Until RI is more widely deployed this option is enabled by default. ++ [Steve Henson] ++ ++ *) Add "missing" ssl ctrls to clear options and mode. ++ [Steve Henson] ++ ++ *) If client attempts to renegotiate and doesn't support RI respond with ++ a no_renegotiation alert as required by RFC5746. Some renegotiating ++ TLS clients will continue a connection gracefully when they receive ++ the alert. Unfortunately OpenSSL mishandled this alert and would hang ++ waiting for a server hello which it will never receive. Now we treat a ++ received no_renegotiation alert as a fatal error. This is because ++ applications requesting a renegotiation might well expect it to succeed ++ and would have no code in place to handle the server denying it so the ++ only safe thing to do is to terminate the connection. ++ [Steve Henson] ++ ++ *) Add ctrl macro SSL_get_secure_renegotiation_support() which returns 1 if ++ peer supports secure renegotiation and 0 otherwise. Print out peer ++ renegotiation support in s_client/s_server. ++ [Steve Henson] ++ ++ *) Replace the highly broken and deprecated SPKAC certification method with ++ the updated NID creation version. This should correctly handle UTF8. ++ [Steve Henson] ++ ++ *) Implement RFC5746. Re-enable renegotiation but require the extension ++ as needed. Unfortunately, SSL3_FLAGS_ALLOW_UNSAFE_LEGACY_RENEGOTIATION ++ turns out to be a bad idea. It has been replaced by ++ SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION which can be set with ++ SSL_CTX_set_options(). This is really not recommended unless you ++ know what you are doing. ++ [Eric Rescorla , Ben Laurie, Steve Henson] ++ ++ *) Fixes to stateless session resumption handling. Use initial_ctx when ++ issuing and attempting to decrypt tickets in case it has changed during ++ servername handling. Use a non-zero length session ID when attempting ++ stateless session resumption: this makes it possible to determine if ++ a resumption has occurred immediately after receiving server hello ++ (several places in OpenSSL subtly assume this) instead of later in ++ the handshake. ++ [Steve Henson] ++ ++ *) The functions ENGINE_ctrl(), OPENSSL_isservice(), ++ CMS_get1_RecipientRequest() and RAND_bytes() can return <=0 on error ++ fixes for a few places where the return code is not checked ++ correctly. ++ [Julia Lawall ] ++ ++ *) Add --strict-warnings option to Configure script to include devteam ++ warnings in other configurations. ++ [Steve Henson] ++ ++ *) Add support for --libdir option and LIBDIR variable in makefiles. This ++ makes it possible to install openssl libraries in locations which ++ have names other than "lib", for example "/usr/lib64" which some ++ systems need. ++ [Steve Henson, based on patch from Jeremy Utley] ++ ++ *) Don't allow the use of leading 0x80 in OIDs. This is a violation of ++ X690 8.9.12 and can produce some misleading textual output of OIDs. ++ [Steve Henson, reported by Dan Kaminsky] ++ ++ *) Delete MD2 from algorithm tables. This follows the recommendation in ++ several standards that it is not used in new applications due to ++ several cryptographic weaknesses. For binary compatibility reasons ++ the MD2 API is still compiled in by default. ++ [Steve Henson] ++ ++ *) Add compression id to {d2i,i2d}_SSL_SESSION so it is correctly saved ++ and restored. ++ [Steve Henson] ++ ++ *) Rename uni2asc and asc2uni functions to OPENSSL_uni2asc and ++ OPENSSL_asc2uni conditionally on Netware platforms to avoid a name ++ clash. ++ [Guenter ] ++ ++ *) Fix the server certificate chain building code to use X509_verify_cert(), ++ it used to have an ad-hoc builder which was unable to cope with anything ++ other than a simple chain. ++ [David Woodhouse , Steve Henson] ++ ++ *) Don't check self signed certificate signatures in X509_verify_cert() ++ by default (a flag can override this): it just wastes time without ++ adding any security. As a useful side effect self signed root CAs ++ with non-FIPS digests are now usable in FIPS mode. ++ [Steve Henson] ++ ++ *) In dtls1_process_out_of_seq_message() the check if the current message ++ is already buffered was missing. For every new message was memory ++ allocated, allowing an attacker to perform an denial of service attack ++ with sending out of seq handshake messages until there is no memory ++ left. Additionally every future messege was buffered, even if the ++ sequence number made no sense and would be part of another handshake. ++ So only messages with sequence numbers less than 10 in advance will be ++ buffered. (CVE-2009-1378) ++ [Robin Seggelmann, discovered by Daniel Mentz] ++ ++ *) Records are buffered if they arrive with a future epoch to be ++ processed after finishing the corresponding handshake. There is ++ currently no limitation to this buffer allowing an attacker to perform ++ a DOS attack with sending records with future epochs until there is no ++ memory left. This patch adds the pqueue_size() function to determine ++ the size of a buffer and limits the record buffer to 100 entries. ++ (CVE-2009-1377) ++ [Robin Seggelmann, discovered by Daniel Mentz] ++ ++ *) Keep a copy of frag->msg_header.frag_len so it can be used after the ++ parent structure is freed. (CVE-2009-1379) ++ [Daniel Mentz] ++ ++ *) Handle non-blocking I/O properly in SSL_shutdown() call. ++ [Darryl Miles ] ++ ++ *) Add 2.5.4.* OIDs ++ [Ilya O. ] ++ ++ Changes between 0.9.8k and 0.9.8l [5 Nov 2009] ++ ++ *) Disable renegotiation completely - this fixes a severe security ++ problem (CVE-2009-3555) at the cost of breaking all ++ renegotiation. Renegotiation can be re-enabled by setting ++ SSL3_FLAGS_ALLOW_UNSAFE_LEGACY_RENEGOTIATION in s3->flags at ++ run-time. This is really not recommended unless you know what ++ you're doing. ++ [Ben Laurie] ++ ++ Changes between 0.9.8j and 0.9.8k [25 Mar 2009] ++ ++ *) Don't set val to NULL when freeing up structures, it is freed up by ++ underlying code. If sizeof(void *) > sizeof(long) this can result in ++ zeroing past the valid field. (CVE-2009-0789) ++ [Paolo Ganci ] ++ ++ *) Fix bug where return value of CMS_SignerInfo_verify_content() was not ++ checked correctly. This would allow some invalid signed attributes to ++ appear to verify correctly. (CVE-2009-0591) ++ [Ivan Nestlerode ] ++ ++ *) Reject UniversalString and BMPString types with invalid lengths. This ++ prevents a crash in ASN1_STRING_print_ex() which assumes the strings have ++ a legal length. (CVE-2009-0590) ++ [Steve Henson] ++ ++ *) Set S/MIME signing as the default purpose rather than setting it ++ unconditionally. This allows applications to override it at the store ++ level. ++ [Steve Henson] ++ ++ *) Permit restricted recursion of ASN1 strings. This is needed in practice ++ to handle some structures. ++ [Steve Henson] ++ ++ *) Improve efficiency of mem_gets: don't search whole buffer each time ++ for a '\n' ++ [Jeremy Shapiro ] ++ ++ *) New -hex option for openssl rand. ++ [Matthieu Herrb] ++ ++ *) Print out UTF8String and NumericString when parsing ASN1. ++ [Steve Henson] ++ ++ *) Support NumericString type for name components. ++ [Steve Henson] ++ ++ *) Allow CC in the environment to override the automatically chosen ++ compiler. Note that nothing is done to ensure flags work with the ++ chosen compiler. ++ [Ben Laurie] ++ ++ Changes between 0.9.8i and 0.9.8j [07 Jan 2009] ++ ++ *) Properly check EVP_VerifyFinal() and similar return values ++ (CVE-2008-5077). ++ [Ben Laurie, Bodo Moeller, Google Security Team] ++ ++ *) Enable TLS extensions by default. ++ [Ben Laurie] ++ ++ *) Allow the CHIL engine to be loaded, whether the application is ++ multithreaded or not. (This does not release the developer from the ++ obligation to set up the dynamic locking callbacks.) ++ [Sander Temme ] ++ ++ *) Use correct exit code if there is an error in dgst command. ++ [Steve Henson; problem pointed out by Roland Dirlewanger] ++ ++ *) Tweak Configure so that you need to say "experimental-jpake" to enable ++ JPAKE, and need to use -DOPENSSL_EXPERIMENTAL_JPAKE in applications. ++ [Bodo Moeller] ++ ++ *) Add experimental JPAKE support, including demo authentication in ++ s_client and s_server. ++ [Ben Laurie] ++ ++ *) Set the comparison function in v3_addr_canonize(). ++ [Rob Austein ] ++ ++ *) Add support for XMPP STARTTLS in s_client. ++ [Philip Paeps ] ++ ++ *) Change the server-side SSL_OP_NETSCAPE_REUSE_CIPHER_CHANGE_BUG behavior ++ to ensure that even with this option, only ciphersuites in the ++ server's preference list will be accepted. (Note that the option ++ applies only when resuming a session, so the earlier behavior was ++ just about the algorithm choice for symmetric cryptography.) ++ [Bodo Moeller] ++ ++ Changes between 0.9.8h and 0.9.8i [15 Sep 2008] ++ ++ *) Fix NULL pointer dereference if a DTLS server received ++ ChangeCipherSpec as first record (CVE-2009-1386). ++ [PR #1679] ++ ++ *) Fix a state transition in s3_srvr.c and d1_srvr.c ++ (was using SSL3_ST_CW_CLNT_HELLO_B, should be ..._ST_SW_SRVR_...). ++ [Nagendra Modadugu] ++ ++ *) The fix in 0.9.8c that supposedly got rid of unsafe ++ double-checked locking was incomplete for RSA blinding, ++ addressing just one layer of what turns out to have been ++ doubly unsafe triple-checked locking. ++ ++ So now fix this for real by retiring the MONT_HELPER macro ++ in crypto/rsa/rsa_eay.c. ++ ++ [Bodo Moeller; problem pointed out by Marius Schilder] ++ ++ *) Various precautionary measures: ++ ++ - Avoid size_t integer overflow in HASH_UPDATE (md32_common.h). ++ ++ - Avoid a buffer overflow in d2i_SSL_SESSION() (ssl_asn1.c). ++ (NB: This would require knowledge of the secret session ticket key ++ to exploit, in which case you'd be SOL either way.) ++ ++ - Change bn_nist.c so that it will properly handle input BIGNUMs ++ outside the expected range. ++ ++ - Enforce the 'num' check in BN_div() (bn_div.c) for non-BN_DEBUG ++ builds. ++ ++ [Neel Mehta, Bodo Moeller] ++ ++ *) Allow engines to be "soft loaded" - i.e. optionally don't die if ++ the load fails. Useful for distros. ++ [Ben Laurie and the FreeBSD team] ++ ++ *) Add support for Local Machine Keyset attribute in PKCS#12 files. ++ [Steve Henson] ++ ++ *) Fix BN_GF2m_mod_arr() top-bit cleanup code. ++ [Huang Ying] ++ ++ *) Expand ENGINE to support engine supplied SSL client certificate functions. ++ ++ This work was sponsored by Logica. ++ [Steve Henson] ++ ++ *) Add CryptoAPI ENGINE to support use of RSA and DSA keys held in Windows ++ keystores. Support for SSL/TLS client authentication too. ++ Not compiled unless enable-capieng specified to Configure. ++ ++ This work was sponsored by Logica. ++ [Steve Henson] ++ ++ *) Fix bug in X509_ATTRIBUTE creation: don't set attribute using ++ ASN1_TYPE_set1 if MBSTRING flag set. This bug would crash certain ++ attribute creation routines such as certificate requests and PKCS#12 ++ files. ++ [Steve Henson] ++ ++ Changes between 0.9.8g and 0.9.8h [28 May 2008] ++ ++ *) Fix flaw if 'Server Key exchange message' is omitted from a TLS ++ handshake which could lead to a cilent crash as found using the ++ Codenomicon TLS test suite (CVE-2008-1672) ++ [Steve Henson, Mark Cox] ++ ++ *) Fix double free in TLS server name extensions which could lead to ++ a remote crash found by Codenomicon TLS test suite (CVE-2008-0891) ++ [Joe Orton] ++ ++ *) Clear error queue in SSL_CTX_use_certificate_chain_file() ++ ++ Clear the error queue to ensure that error entries left from ++ older function calls do not interfere with the correct operation. ++ [Lutz Jaenicke, Erik de Castro Lopo] ++ ++ *) Remove root CA certificates of commercial CAs: ++ ++ The OpenSSL project does not recommend any specific CA and does not ++ have any policy with respect to including or excluding any CA. ++ Therefore it does not make any sense to ship an arbitrary selection ++ of root CA certificates with the OpenSSL software. ++ [Lutz Jaenicke] ++ ++ *) RSA OAEP patches to fix two separate invalid memory reads. ++ The first one involves inputs when 'lzero' is greater than ++ 'SHA_DIGEST_LENGTH' (it would read about SHA_DIGEST_LENGTH bytes ++ before the beginning of from). The second one involves inputs where ++ the 'db' section contains nothing but zeroes (there is a one-byte ++ invalid read after the end of 'db'). ++ [Ivan Nestlerode ] ++ ++ *) Partial backport from 0.9.9-dev: ++ ++ Introduce bn_mul_mont (dedicated Montgomery multiplication ++ procedure) as a candidate for BIGNUM assembler implementation. ++ While 0.9.9-dev uses assembler for various architectures, only ++ x86_64 is available by default here in the 0.9.8 branch, and ++ 32-bit x86 is available through a compile-time setting. ++ ++ To try the 32-bit x86 assembler implementation, use Configure ++ option "enable-montasm" (which exists only for this backport). ++ ++ As "enable-montasm" for 32-bit x86 disclaims code stability ++ anyway, in this constellation we activate additional code ++ backported from 0.9.9-dev for further performance improvements, ++ namely BN_from_montgomery_word. (To enable this otherwise, ++ e.g. x86_64, try "-DMONT_FROM_WORD___NON_DEFAULT_0_9_8_BUILD".) ++ ++ [Andy Polyakov (backport partially by Bodo Moeller)] ++ ++ *) Add TLS session ticket callback. This allows an application to set ++ TLS ticket cipher and HMAC keys rather than relying on hardcoded fixed ++ values. This is useful for key rollover for example where several key ++ sets may exist with different names. ++ [Steve Henson] ++ ++ *) Reverse ENGINE-internal logic for caching default ENGINE handles. ++ This was broken until now in 0.9.8 releases, such that the only way ++ a registered ENGINE could be used (assuming it initialises ++ successfully on the host) was to explicitly set it as the default ++ for the relevant algorithms. This is in contradiction with 0.9.7 ++ behaviour and the documentation. With this fix, when an ENGINE is ++ registered into a given algorithm's table of implementations, the ++ 'uptodate' flag is reset so that auto-discovery will be used next ++ time a new context for that algorithm attempts to select an ++ implementation. ++ [Ian Lister (tweaked by Geoff Thorpe)] ++ ++ *) Backport of CMS code to OpenSSL 0.9.8. This differs from the 0.9.9 ++ implementation in the following ways: ++ ++ Lack of EVP_PKEY_ASN1_METHOD means algorithm parameters have to be ++ hard coded. ++ ++ Lack of BER streaming support means one pass streaming processing is ++ only supported if data is detached: setting the streaming flag is ++ ignored for embedded content. ++ ++ CMS support is disabled by default and must be explicitly enabled ++ with the enable-cms configuration option. ++ [Steve Henson] ++ ++ *) Update the GMP engine glue to do direct copies between BIGNUM and ++ mpz_t when openssl and GMP use the same limb size. Otherwise the ++ existing "conversion via a text string export" trick is still used. ++ [Paul Sheer ] ++ ++ *) Zlib compression BIO. This is a filter BIO which compressed and ++ uncompresses any data passed through it. ++ [Steve Henson] ++ ++ *) Add AES_wrap_key() and AES_unwrap_key() functions to implement ++ RFC3394 compatible AES key wrapping. ++ [Steve Henson] ++ ++ *) Add utility functions to handle ASN1 structures. ASN1_STRING_set0(): ++ sets string data without copying. X509_ALGOR_set0() and ++ X509_ALGOR_get0(): set and retrieve X509_ALGOR (AlgorithmIdentifier) ++ data. Attribute function X509at_get0_data_by_OBJ(): retrieves data ++ from an X509_ATTRIBUTE structure optionally checking it occurs only ++ once. ASN1_TYPE_set1(): set and ASN1_TYPE structure copying supplied ++ data. ++ [Steve Henson] ++ ++ *) Fix BN flag handling in RSA_eay_mod_exp() and BN_MONT_CTX_set() ++ to get the expected BN_FLG_CONSTTIME behavior. ++ [Bodo Moeller (Google)] ++ ++ *) Netware support: ++ ++ - fixed wrong usage of ioctlsocket() when build for LIBC BSD sockets ++ - fixed do_tests.pl to run the test suite with CLIB builds too (CLIB_OPT) ++ - added some more tests to do_tests.pl ++ - fixed RunningProcess usage so that it works with newer LIBC NDKs too ++ - removed usage of BN_LLONG for CLIB builds to avoid runtime dependency ++ - added new Configure targets netware-clib-bsdsock, netware-clib-gcc, ++ netware-clib-bsdsock-gcc, netware-libc-bsdsock-gcc ++ - various changes to netware.pl to enable gcc-cross builds on Win32 ++ platform ++ - changed crypto/bio/b_sock.c to work with macro functions (CLIB BSD) ++ - various changes to fix missing prototype warnings ++ - fixed x86nasm.pl to create correct asm files for NASM COFF output ++ - added AES, WHIRLPOOL and CPUID assembler code to build files ++ - added missing AES assembler make rules to mk1mf.pl ++ - fixed order of includes in apps/ocsp.c so that e_os.h settings apply ++ [Guenter Knauf ] ++ ++ *) Implement certificate status request TLS extension defined in RFC3546. ++ A client can set the appropriate parameters and receive the encoded ++ OCSP response via a callback. A server can query the supplied parameters ++ and set the encoded OCSP response in the callback. Add simplified examples ++ to s_client and s_server. ++ [Steve Henson] ++ ++ Changes between 0.9.8f and 0.9.8g [19 Oct 2007] ++ ++ *) Fix various bugs: ++ + Binary incompatibility of ssl_ctx_st structure ++ + DTLS interoperation with non-compliant servers ++ + Don't call get_session_cb() without proposed session ++ + Fix ia64 assembler code ++ [Andy Polyakov, Steve Henson] ++ ++ Changes between 0.9.8e and 0.9.8f [11 Oct 2007] ++ ++ *) DTLS Handshake overhaul. There were longstanding issues with ++ OpenSSL DTLS implementation, which were making it impossible for ++ RFC 4347 compliant client to communicate with OpenSSL server. ++ Unfortunately just fixing these incompatibilities would "cut off" ++ pre-0.9.8f clients. To allow for hassle free upgrade post-0.9.8e ++ server keeps tolerating non RFC compliant syntax. The opposite is ++ not true, 0.9.8f client can not communicate with earlier server. ++ This update even addresses CVE-2007-4995. ++ [Andy Polyakov] ++ ++ *) Changes to avoid need for function casts in OpenSSL: some compilers ++ (gcc 4.2 and later) reject their use. ++ [Kurt Roeckx , Peter Hartley , ++ Steve Henson] ++ ++ *) Add RFC4507 support to OpenSSL. This includes the corrections in ++ RFC4507bis. The encrypted ticket format is an encrypted encoded ++ SSL_SESSION structure, that way new session features are automatically ++ supported. ++ ++ If a client application caches session in an SSL_SESSION structure ++ support is transparent because tickets are now stored in the encoded ++ SSL_SESSION. ++ ++ The SSL_CTX structure automatically generates keys for ticket ++ protection in servers so again support should be possible ++ with no application modification. ++ ++ If a client or server wishes to disable RFC4507 support then the option ++ SSL_OP_NO_TICKET can be set. ++ ++ Add a TLS extension debugging callback to allow the contents of any client ++ or server extensions to be examined. ++ ++ This work was sponsored by Google. ++ [Steve Henson] ++ ++ *) Add initial support for TLS extensions, specifically for the server_name ++ extension so far. The SSL_SESSION, SSL_CTX, and SSL data structures now ++ have new members for a host name. The SSL data structure has an ++ additional member SSL_CTX *initial_ctx so that new sessions can be ++ stored in that context to allow for session resumption, even after the ++ SSL has been switched to a new SSL_CTX in reaction to a client's ++ server_name extension. ++ ++ New functions (subject to change): ++ ++ SSL_get_servername() ++ SSL_get_servername_type() ++ SSL_set_SSL_CTX() ++ ++ New CTRL codes and macros (subject to change): ++ ++ SSL_CTRL_SET_TLSEXT_SERVERNAME_CB ++ - SSL_CTX_set_tlsext_servername_callback() ++ SSL_CTRL_SET_TLSEXT_SERVERNAME_ARG ++ - SSL_CTX_set_tlsext_servername_arg() ++ SSL_CTRL_SET_TLSEXT_HOSTNAME - SSL_set_tlsext_host_name() ++ ++ openssl s_client has a new '-servername ...' option. ++ ++ openssl s_server has new options '-servername_host ...', '-cert2 ...', ++ '-key2 ...', '-servername_fatal' (subject to change). This allows ++ testing the HostName extension for a specific single host name ('-cert' ++ and '-key' remain fallbacks for handshakes without HostName ++ negotiation). If the unrecognized_name alert has to be sent, this by ++ default is a warning; it becomes fatal with the '-servername_fatal' ++ option. ++ ++ [Peter Sylvester, Remy Allais, Christophe Renou, Steve Henson] ++ ++ *) Add AES and SSE2 assembly language support to VC++ build. ++ [Steve Henson] ++ ++ *) Mitigate attack on final subtraction in Montgomery reduction. ++ [Andy Polyakov] ++ ++ *) Fix crypto/ec/ec_mult.c to work properly with scalars of value 0 ++ (which previously caused an internal error). ++ [Bodo Moeller] ++ ++ *) Squeeze another 10% out of IGE mode when in != out. ++ [Ben Laurie] ++ ++ *) AES IGE mode speedup. ++ [Dean Gaudet (Google)] ++ ++ *) Add the Korean symmetric 128-bit cipher SEED (see ++ http://www.kisa.or.kr/kisa/seed/jsp/seed_eng.jsp) and ++ add SEED ciphersuites from RFC 4162: ++ ++ TLS_RSA_WITH_SEED_CBC_SHA = "SEED-SHA" ++ TLS_DHE_DSS_WITH_SEED_CBC_SHA = "DHE-DSS-SEED-SHA" ++ TLS_DHE_RSA_WITH_SEED_CBC_SHA = "DHE-RSA-SEED-SHA" ++ TLS_DH_anon_WITH_SEED_CBC_SHA = "ADH-SEED-SHA" ++ ++ To minimize changes between patchlevels in the OpenSSL 0.9.8 ++ series, SEED remains excluded from compilation unless OpenSSL ++ is configured with 'enable-seed'. ++ [KISA, Bodo Moeller] ++ ++ *) Mitigate branch prediction attacks, which can be practical if a ++ single processor is shared, allowing a spy process to extract ++ information. For detailed background information, see ++ http://eprint.iacr.org/2007/039 (O. Aciicmez, S. Gueron, ++ J.-P. Seifert, "New Branch Prediction Vulnerabilities in OpenSSL ++ and Necessary Software Countermeasures"). The core of the change ++ are new versions BN_div_no_branch() and ++ BN_mod_inverse_no_branch() of BN_div() and BN_mod_inverse(), ++ respectively, which are slower, but avoid the security-relevant ++ conditional branches. These are automatically called by BN_div() ++ and BN_mod_inverse() if the flag BN_FLG_CONSTTIME is set for one ++ of the input BIGNUMs. Also, BN_is_bit_set() has been changed to ++ remove a conditional branch. ++ ++ BN_FLG_CONSTTIME is the new name for the previous ++ BN_FLG_EXP_CONSTTIME flag, since it now affects more than just ++ modular exponentiation. (Since OpenSSL 0.9.7h, setting this flag ++ in the exponent causes BN_mod_exp_mont() to use the alternative ++ implementation in BN_mod_exp_mont_consttime().) The old name ++ remains as a deprecated alias. ++ ++ Similarly, RSA_FLAG_NO_EXP_CONSTTIME is replaced by a more general ++ RSA_FLAG_NO_CONSTTIME flag since the RSA implementation now uses ++ constant-time implementations for more than just exponentiation. ++ Here too the old name is kept as a deprecated alias. ++ ++ BN_BLINDING_new() will now use BN_dup() for the modulus so that ++ the BN_BLINDING structure gets an independent copy of the ++ modulus. This means that the previous "BIGNUM *m" argument to ++ BN_BLINDING_new() and to BN_BLINDING_create_param() now ++ essentially becomes "const BIGNUM *m", although we can't actually ++ change this in the header file before 0.9.9. It allows ++ RSA_setup_blinding() to use BN_with_flags() on the modulus to ++ enable BN_FLG_CONSTTIME. ++ ++ [Matthew D Wood (Intel Corp)] ++ ++ *) In the SSL/TLS server implementation, be strict about session ID ++ context matching (which matters if an application uses a single ++ external cache for different purposes). Previously, ++ out-of-context reuse was forbidden only if SSL_VERIFY_PEER was ++ set. This did ensure strict client verification, but meant that, ++ with applications using a single external cache for quite ++ different requirements, clients could circumvent ciphersuite ++ restrictions for a given session ID context by starting a session ++ in a different context. ++ [Bodo Moeller] ++ ++ *) Include "!eNULL" in SSL_DEFAULT_CIPHER_LIST to make sure that ++ a ciphersuite string such as "DEFAULT:RSA" cannot enable ++ authentication-only ciphersuites. ++ [Bodo Moeller] ++ ++ *) Update the SSL_get_shared_ciphers() fix CVE-2006-3738 which was ++ not complete and could lead to a possible single byte overflow ++ (CVE-2007-5135) [Ben Laurie] ++ ++ Changes between 0.9.8d and 0.9.8e [23 Feb 2007] ++ ++ *) Since AES128 and AES256 (and similarly Camellia128 and ++ Camellia256) share a single mask bit in the logic of ++ ssl/ssl_ciph.c, the code for masking out disabled ciphers needs a ++ kludge to work properly if AES128 is available and AES256 isn't ++ (or if Camellia128 is available and Camellia256 isn't). ++ [Victor Duchovni] ++ ++ *) Fix the BIT STRING encoding generated by crypto/ec/ec_asn1.c ++ (within i2d_ECPrivateKey, i2d_ECPKParameters, i2d_ECParameters): ++ When a point or a seed is encoded in a BIT STRING, we need to ++ prevent the removal of trailing zero bits to get the proper DER ++ encoding. (By default, crypto/asn1/a_bitstr.c assumes the case ++ of a NamedBitList, for which trailing 0 bits need to be removed.) ++ [Bodo Moeller] ++ ++ *) Have SSL/TLS server implementation tolerate "mismatched" record ++ protocol version while receiving ClientHello even if the ++ ClientHello is fragmented. (The server can't insist on the ++ particular protocol version it has chosen before the ServerHello ++ message has informed the client about his choice.) ++ [Bodo Moeller] ++ ++ *) Add RFC 3779 support. ++ [Rob Austein for ARIN, Ben Laurie] ++ ++ *) Load error codes if they are not already present instead of using a ++ static variable. This allows them to be cleanly unloaded and reloaded. ++ Improve header file function name parsing. ++ [Steve Henson] ++ ++ *) extend SMTP and IMAP protocol emulation in s_client to use EHLO ++ or CAPABILITY handshake as required by RFCs. ++ [Goetz Babin-Ebell] ++ ++ Changes between 0.9.8c and 0.9.8d [28 Sep 2006] ++ ++ *) Introduce limits to prevent malicious keys being able to ++ cause a denial of service. (CVE-2006-2940) ++ [Steve Henson, Bodo Moeller] ++ ++ *) Fix ASN.1 parsing of certain invalid structures that can result ++ in a denial of service. (CVE-2006-2937) [Steve Henson] ++ ++ *) Fix buffer overflow in SSL_get_shared_ciphers() function. ++ (CVE-2006-3738) [Tavis Ormandy and Will Drewry, Google Security Team] ++ ++ *) Fix SSL client code which could crash if connecting to a ++ malicious SSLv2 server. (CVE-2006-4343) ++ [Tavis Ormandy and Will Drewry, Google Security Team] ++ ++ *) Since 0.9.8b, ciphersuite strings naming explicit ciphersuites ++ match only those. Before that, "AES256-SHA" would be interpreted ++ as a pattern and match "AES128-SHA" too (since AES128-SHA got ++ the same strength classification in 0.9.7h) as we currently only ++ have a single AES bit in the ciphersuite description bitmap. ++ That change, however, also applied to ciphersuite strings such as ++ "RC4-MD5" that intentionally matched multiple ciphersuites -- ++ namely, SSL 2.0 ciphersuites in addition to the more common ones ++ from SSL 3.0/TLS 1.0. ++ ++ So we change the selection algorithm again: Naming an explicit ++ ciphersuite selects this one ciphersuite, and any other similar ++ ciphersuite (same bitmap) from *other* protocol versions. ++ Thus, "RC4-MD5" again will properly select both the SSL 2.0 ++ ciphersuite and the SSL 3.0/TLS 1.0 ciphersuite. ++ ++ Since SSL 2.0 does not have any ciphersuites for which the ++ 128/256 bit distinction would be relevant, this works for now. ++ The proper fix will be to use different bits for AES128 and ++ AES256, which would have avoided the problems from the beginning; ++ however, bits are scarce, so we can only do this in a new release ++ (not just a patchlevel) when we can change the SSL_CIPHER ++ definition to split the single 'unsigned long mask' bitmap into ++ multiple values to extend the available space. ++ ++ [Bodo Moeller] ++ ++ Changes between 0.9.8b and 0.9.8c [05 Sep 2006] ++ ++ *) Avoid PKCS #1 v1.5 signature attack discovered by Daniel Bleichenbacher ++ (CVE-2006-4339) [Ben Laurie and Google Security Team] ++ ++ *) Add AES IGE and biIGE modes. ++ [Ben Laurie] ++ ++ *) Change the Unix randomness entropy gathering to use poll() when ++ possible instead of select(), since the latter has some ++ undesirable limitations. ++ [Darryl Miles via Richard Levitte and Bodo Moeller] ++ ++ *) Disable "ECCdraft" ciphersuites more thoroughly. Now special ++ treatment in ssl/ssl_ciph.s makes sure that these ciphersuites ++ cannot be implicitly activated as part of, e.g., the "AES" alias. ++ However, please upgrade to OpenSSL 0.9.9[-dev] for ++ non-experimental use of the ECC ciphersuites to get TLS extension ++ support, which is required for curve and point format negotiation ++ to avoid potential handshake problems. ++ [Bodo Moeller] ++ ++ *) Disable rogue ciphersuites: ++ ++ - SSLv2 0x08 0x00 0x80 ("RC4-64-MD5") ++ - SSLv3/TLSv1 0x00 0x61 ("EXP1024-RC2-CBC-MD5") ++ - SSLv3/TLSv1 0x00 0x60 ("EXP1024-RC4-MD5") ++ ++ The latter two were purportedly from ++ draft-ietf-tls-56-bit-ciphersuites-0[01].txt, but do not really ++ appear there. ++ ++ Also deactivate the remaining ciphersuites from ++ draft-ietf-tls-56-bit-ciphersuites-01.txt. These are just as ++ unofficial, and the ID has long expired. ++ [Bodo Moeller] ++ ++ *) Fix RSA blinding Heisenbug (problems sometimes occurred on ++ dual-core machines) and other potential thread-safety issues. ++ [Bodo Moeller] ++ ++ *) Add the symmetric cipher Camellia (128-bit, 192-bit, 256-bit key ++ versions), which is now available for royalty-free use ++ (see http://info.isl.ntt.co.jp/crypt/eng/info/chiteki.html). ++ Also, add Camellia TLS ciphersuites from RFC 4132. ++ ++ To minimize changes between patchlevels in the OpenSSL 0.9.8 ++ series, Camellia remains excluded from compilation unless OpenSSL ++ is configured with 'enable-camellia'. ++ [NTT] ++ ++ *) Disable the padding bug check when compression is in use. The padding ++ bug check assumes the first packet is of even length, this is not ++ necessarily true if compresssion is enabled and can result in false ++ positives causing handshake failure. The actual bug test is ancient ++ code so it is hoped that implementations will either have fixed it by ++ now or any which still have the bug do not support compression. ++ [Steve Henson] ++ ++ Changes between 0.9.8a and 0.9.8b [04 May 2006] ++ ++ *) When applying a cipher rule check to see if string match is an explicit ++ cipher suite and only match that one cipher suite if it is. ++ [Steve Henson] ++ ++ *) Link in manifests for VC++ if needed. ++ [Austin Ziegler ] ++ ++ *) Update support for ECC-based TLS ciphersuites according to ++ draft-ietf-tls-ecc-12.txt with proposed changes (but without ++ TLS extensions, which are supported starting with the 0.9.9 ++ branch, not in the OpenSSL 0.9.8 branch). ++ [Douglas Stebila] ++ ++ *) New functions EVP_CIPHER_CTX_new() and EVP_CIPHER_CTX_free() to support ++ opaque EVP_CIPHER_CTX handling. ++ [Steve Henson] ++ ++ *) Fixes and enhancements to zlib compression code. We now only use ++ "zlib1.dll" and use the default __cdecl calling convention on Win32 ++ to conform with the standards mentioned here: ++ http://www.zlib.net/DLL_FAQ.txt ++ Static zlib linking now works on Windows and the new --with-zlib-include ++ --with-zlib-lib options to Configure can be used to supply the location ++ of the headers and library. Gracefully handle case where zlib library ++ can't be loaded. ++ [Steve Henson] ++ ++ *) Several fixes and enhancements to the OID generation code. The old code ++ sometimes allowed invalid OIDs (1.X for X >= 40 for example), couldn't ++ handle numbers larger than ULONG_MAX, truncated printing and had a ++ non standard OBJ_obj2txt() behaviour. ++ [Steve Henson] ++ ++ *) Add support for building of engines under engine/ as shared libraries ++ under VC++ build system. ++ [Steve Henson] ++ ++ *) Corrected the numerous bugs in the Win32 path splitter in DSO. ++ Hopefully, we will not see any false combination of paths any more. ++ [Richard Levitte] ++ ++ Changes between 0.9.8 and 0.9.8a [11 Oct 2005] ++ ++ *) Remove the functionality of SSL_OP_MSIE_SSLV2_RSA_PADDING ++ (part of SSL_OP_ALL). This option used to disable the ++ countermeasure against man-in-the-middle protocol-version ++ rollback in the SSL 2.0 server implementation, which is a bad ++ idea. (CVE-2005-2969) ++ ++ [Bodo Moeller; problem pointed out by Yutaka Oiwa (Research Center ++ for Information Security, National Institute of Advanced Industrial ++ Science and Technology [AIST], Japan)] ++ ++ *) Add two function to clear and return the verify parameter flags. ++ [Steve Henson] ++ ++ *) Keep cipherlists sorted in the source instead of sorting them at ++ runtime, thus removing the need for a lock. ++ [Nils Larsch] ++ ++ *) Avoid some small subgroup attacks in Diffie-Hellman. ++ [Nick Mathewson and Ben Laurie] ++ ++ *) Add functions for well-known primes. ++ [Nick Mathewson] ++ ++ *) Extended Windows CE support. ++ [Satoshi Nakamura and Andy Polyakov] ++ ++ *) Initialize SSL_METHOD structures at compile time instead of during ++ runtime, thus removing the need for a lock. ++ [Steve Henson] ++ ++ *) Make PKCS7_decrypt() work even if no certificate is supplied by ++ attempting to decrypt each encrypted key in turn. Add support to ++ smime utility. ++ [Steve Henson] ++ ++ Changes between 0.9.7h and 0.9.8 [05 Jul 2005] ++ ++ [NB: OpenSSL 0.9.7i and later 0.9.7 patch levels were released after ++ OpenSSL 0.9.8.] ++ ++ *) Add libcrypto.pc and libssl.pc for those who feel they need them. ++ [Richard Levitte] ++ ++ *) Change CA.sh and CA.pl so they don't bundle the CSR and the private ++ key into the same file any more. ++ [Richard Levitte] ++ ++ *) Add initial support for Win64, both IA64 and AMD64/x64 flavors. ++ [Andy Polyakov] ++ ++ *) Add -utf8 command line and config file option to 'ca'. ++ [Stefan and Geoff Thorpe] ++ ++ *) Add attribute functions to EVP_PKEY structure. Modify ++ PKCS12_create() to recognize a CSP name attribute and ++ use it. Make -CSP option work again in pkcs12 utility. ++ [Steve Henson] ++ ++ *) Add new functionality to the bn blinding code: ++ - automatic re-creation of the BN_BLINDING parameters after ++ a fixed number of uses (currently 32) ++ - add new function for parameter creation ++ - introduce flags to control the update behaviour of the ++ BN_BLINDING parameters ++ - hide BN_BLINDING structure ++ Add a second BN_BLINDING slot to the RSA structure to improve ++ performance when a single RSA object is shared among several ++ threads. ++ [Nils Larsch] ++ ++ *) Add support for DTLS. ++ [Nagendra Modadugu and Ben Laurie] ++ ++ *) Add support for DER encoded private keys (SSL_FILETYPE_ASN1) ++ to SSL_CTX_use_PrivateKey_file() and SSL_use_PrivateKey_file() ++ [Walter Goulet] ++ ++ *) Remove buggy and incomplete DH cert support from ++ ssl/ssl_rsa.c and ssl/s3_both.c ++ [Nils Larsch] ++ ++ *) Use SHA-1 instead of MD5 as the default digest algorithm for ++ the apps/openssl applications. ++ [Nils Larsch] ++ ++ *) Compile clean with "-Wall -Wmissing-prototypes ++ -Wstrict-prototypes -Wmissing-declarations -Werror". Currently ++ DEBUG_SAFESTACK must also be set. ++ [Ben Laurie] ++ ++ *) Change ./Configure so that certain algorithms can be disabled by default. ++ The new counterpiece to "no-xxx" is "enable-xxx". ++ ++ The patented RC5 and MDC2 algorithms will now be disabled unless ++ "enable-rc5" and "enable-mdc2", respectively, are specified. ++ ++ (IDEA remains enabled despite being patented. This is because IDEA ++ is frequently required for interoperability, and there is no license ++ fee for non-commercial use. As before, "no-idea" can be used to ++ avoid this algorithm.) ++ ++ [Bodo Moeller] ++ ++ *) Add processing of proxy certificates (see RFC 3820). This work was ++ sponsored by KTH (The Royal Institute of Technology in Stockholm) and ++ EGEE (Enabling Grids for E-science in Europe). ++ [Richard Levitte] ++ ++ *) RC4 performance overhaul on modern architectures/implementations, such ++ as Intel P4, IA-64 and AMD64. ++ [Andy Polyakov] ++ ++ *) New utility extract-section.pl. This can be used specify an alternative ++ section number in a pod file instead of having to treat each file as ++ a separate case in Makefile. This can be done by adding two lines to the ++ pod file: ++ ++ =for comment openssl_section:XXX ++ ++ The blank line is mandatory. ++ ++ [Steve Henson] ++ ++ *) New arguments -certform, -keyform and -pass for s_client and s_server ++ to allow alternative format key and certificate files and passphrase ++ sources. ++ [Steve Henson] ++ ++ *) New structure X509_VERIFY_PARAM which combines current verify parameters, ++ update associated structures and add various utility functions. ++ ++ Add new policy related verify parameters, include policy checking in ++ standard verify code. Enhance 'smime' application with extra parameters ++ to support policy checking and print out. ++ [Steve Henson] ++ ++ *) Add a new engine to support VIA PadLock ACE extensions in the VIA C3 ++ Nehemiah processors. These extensions support AES encryption in hardware ++ as well as RNG (though RNG support is currently disabled). ++ [Michal Ludvig , with help from Andy Polyakov] ++ ++ *) Deprecate BN_[get|set]_params() functions (they were ignored internally). ++ [Geoff Thorpe] ++ ++ *) New FIPS 180-2 algorithms, SHA-224/-256/-384/-512 are implemented. ++ [Andy Polyakov and a number of other people] ++ ++ *) Improved PowerPC platform support. Most notably BIGNUM assembler ++ implementation contributed by IBM. ++ [Suresh Chari, Peter Waltenberg, Andy Polyakov] ++ ++ *) The new 'RSA_generate_key_ex' function now takes a BIGNUM for the public ++ exponent rather than 'unsigned long'. There is a corresponding change to ++ the new 'rsa_keygen' element of the RSA_METHOD structure. ++ [Jelte Jansen, Geoff Thorpe] ++ ++ *) Functionality for creating the initial serial number file is now ++ moved from CA.pl to the 'ca' utility with a new option -create_serial. ++ ++ (Before OpenSSL 0.9.7e, CA.pl used to initialize the serial ++ number file to 1, which is bound to cause problems. To avoid ++ the problems while respecting compatibility between different 0.9.7 ++ patchlevels, 0.9.7e employed 'openssl x509 -next_serial' in ++ CA.pl for serial number initialization. With the new release 0.9.8, ++ we can fix the problem directly in the 'ca' utility.) ++ [Steve Henson] ++ ++ *) Reduced header interdepencies by declaring more opaque objects in ++ ossl_typ.h. As a consequence, including some headers (eg. engine.h) will ++ give fewer recursive includes, which could break lazy source code - so ++ this change is covered by the OPENSSL_NO_DEPRECATED symbol. As always, ++ developers should define this symbol when building and using openssl to ++ ensure they track the recommended behaviour, interfaces, [etc], but ++ backwards-compatible behaviour prevails when this isn't defined. ++ [Geoff Thorpe] ++ ++ *) New function X509_POLICY_NODE_print() which prints out policy nodes. ++ [Steve Henson] ++ ++ *) Add new EVP function EVP_CIPHER_CTX_rand_key and associated functionality. ++ This will generate a random key of the appropriate length based on the ++ cipher context. The EVP_CIPHER can provide its own random key generation ++ routine to support keys of a specific form. This is used in the des and ++ 3des routines to generate a key of the correct parity. Update S/MIME ++ code to use new functions and hence generate correct parity DES keys. ++ Add EVP_CHECK_DES_KEY #define to return an error if the key is not ++ valid (weak or incorrect parity). ++ [Steve Henson] ++ ++ *) Add a local set of CRLs that can be used by X509_verify_cert() as well ++ as looking them up. This is useful when the verified structure may contain ++ CRLs, for example PKCS#7 signedData. Modify PKCS7_verify() to use any CRLs ++ present unless the new PKCS7_NO_CRL flag is asserted. ++ [Steve Henson] ++ ++ *) Extend ASN1 oid configuration module. It now additionally accepts the ++ syntax: ++ ++ shortName = some long name, 1.2.3.4 ++ [Steve Henson] ++ ++ *) Reimplemented the BN_CTX implementation. There is now no more static ++ limitation on the number of variables it can handle nor the depth of the ++ "stack" handling for BN_CTX_start()/BN_CTX_end() pairs. The stack ++ information can now expand as required, and rather than having a single ++ static array of bignums, BN_CTX now uses a linked-list of such arrays ++ allowing it to expand on demand whilst maintaining the usefulness of ++ BN_CTX's "bundling". ++ [Geoff Thorpe] ++ ++ *) Add a missing BN_CTX parameter to the 'rsa_mod_exp' callback in RSA_METHOD ++ to allow all RSA operations to function using a single BN_CTX. ++ [Geoff Thorpe] ++ ++ *) Preliminary support for certificate policy evaluation and checking. This ++ is initially intended to pass the tests outlined in "Conformance Testing ++ of Relying Party Client Certificate Path Processing Logic" v1.07. ++ [Steve Henson] ++ ++ *) bn_dup_expand() has been deprecated, it was introduced in 0.9.7 and ++ remained unused and not that useful. A variety of other little bignum ++ tweaks and fixes have also been made continuing on from the audit (see ++ below). ++ [Geoff Thorpe] ++ ++ *) Constify all or almost all d2i, c2i, s2i and r2i functions, along with ++ associated ASN1, EVP and SSL functions and old ASN1 macros. ++ [Richard Levitte] ++ ++ *) BN_zero() only needs to set 'top' and 'neg' to zero for correct results, ++ and this should never fail. So the return value from the use of ++ BN_set_word() (which can fail due to needless expansion) is now deprecated; ++ if OPENSSL_NO_DEPRECATED is defined, BN_zero() is a void macro. ++ [Geoff Thorpe] ++ ++ *) BN_CTX_get() should return zero-valued bignums, providing the same ++ initialised value as BN_new(). ++ [Geoff Thorpe, suggested by Ulf Möller] ++ ++ *) Support for inhibitAnyPolicy certificate extension. ++ [Steve Henson] ++ ++ *) An audit of the BIGNUM code is underway, for which debugging code is ++ enabled when BN_DEBUG is defined. This makes stricter enforcements on what ++ is considered valid when processing BIGNUMs, and causes execution to ++ assert() when a problem is discovered. If BN_DEBUG_RAND is defined, ++ further steps are taken to deliberately pollute unused data in BIGNUM ++ structures to try and expose faulty code further on. For now, openssl will ++ (in its default mode of operation) continue to tolerate the inconsistent ++ forms that it has tolerated in the past, but authors and packagers should ++ consider trying openssl and their own applications when compiled with ++ these debugging symbols defined. It will help highlight potential bugs in ++ their own code, and will improve the test coverage for OpenSSL itself. At ++ some point, these tighter rules will become openssl's default to improve ++ maintainability, though the assert()s and other overheads will remain only ++ in debugging configurations. See bn.h for more details. ++ [Geoff Thorpe, Nils Larsch, Ulf Möller] ++ ++ *) BN_CTX_init() has been deprecated, as BN_CTX is an opaque structure ++ that can only be obtained through BN_CTX_new() (which implicitly ++ initialises it). The presence of this function only made it possible ++ to overwrite an existing structure (and cause memory leaks). ++ [Geoff Thorpe] ++ ++ *) Because of the callback-based approach for implementing LHASH as a ++ template type, lh_insert() adds opaque objects to hash-tables and ++ lh_doall() or lh_doall_arg() are typically used with a destructor callback ++ to clean up those corresponding objects before destroying the hash table ++ (and losing the object pointers). So some over-zealous constifications in ++ LHASH have been relaxed so that lh_insert() does not take (nor store) the ++ objects as "const" and the lh_doall[_arg] callback wrappers are not ++ prototyped to have "const" restrictions on the object pointers they are ++ given (and so aren't required to cast them away any more). ++ [Geoff Thorpe] ++ ++ *) The tmdiff.h API was so ugly and minimal that our own timing utility ++ (speed) prefers to use its own implementation. The two implementations ++ haven't been consolidated as yet (volunteers?) but the tmdiff API has had ++ its object type properly exposed (MS_TM) instead of casting to/from "char ++ *". This may still change yet if someone realises MS_TM and "ms_time_***" ++ aren't necessarily the greatest nomenclatures - but this is what was used ++ internally to the implementation so I've used that for now. ++ [Geoff Thorpe] ++ ++ *) Ensure that deprecated functions do not get compiled when ++ OPENSSL_NO_DEPRECATED is defined. Some "openssl" subcommands and a few of ++ the self-tests were still using deprecated key-generation functions so ++ these have been updated also. ++ [Geoff Thorpe] ++ ++ *) Reorganise PKCS#7 code to separate the digest location functionality ++ into PKCS7_find_digest(), digest addition into PKCS7_bio_add_digest(). ++ New function PKCS7_set_digest() to set the digest type for PKCS#7 ++ digestedData type. Add additional code to correctly generate the ++ digestedData type and add support for this type in PKCS7 initialization ++ functions. ++ [Steve Henson] ++ ++ *) New function PKCS7_set0_type_other() this initializes a PKCS7 ++ structure of type "other". ++ [Steve Henson] ++ ++ *) Fix prime generation loop in crypto/bn/bn_prime.pl by making ++ sure the loop does correctly stop and breaking ("division by zero") ++ modulus operations are not performed. The (pre-generated) prime ++ table crypto/bn/bn_prime.h was already correct, but it could not be ++ re-generated on some platforms because of the "division by zero" ++ situation in the script. ++ [Ralf S. Engelschall] ++ ++ *) Update support for ECC-based TLS ciphersuites according to ++ draft-ietf-tls-ecc-03.txt: the KDF1 key derivation function with ++ SHA-1 now is only used for "small" curves (where the ++ representation of a field element takes up to 24 bytes); for ++ larger curves, the field element resulting from ECDH is directly ++ used as premaster secret. ++ [Douglas Stebila (Sun Microsystems Laboratories)] ++ ++ *) Add code for kP+lQ timings to crypto/ec/ectest.c, and add SEC2 ++ curve secp160r1 to the tests. ++ [Douglas Stebila (Sun Microsystems Laboratories)] ++ ++ *) Add the possibility to load symbols globally with DSO. ++ [Götz Babin-Ebell via Richard Levitte] ++ ++ *) Add the functions ERR_set_mark() and ERR_pop_to_mark() for better ++ control of the error stack. ++ [Richard Levitte] ++ ++ *) Add support for STORE in ENGINE. ++ [Richard Levitte] ++ ++ *) Add the STORE type. The intention is to provide a common interface ++ to certificate and key stores, be they simple file-based stores, or ++ HSM-type store, or LDAP stores, or... ++ NOTE: The code is currently UNTESTED and isn't really used anywhere. ++ [Richard Levitte] ++ ++ *) Add a generic structure called OPENSSL_ITEM. This can be used to ++ pass a list of arguments to any function as well as provide a way ++ for a function to pass data back to the caller. ++ [Richard Levitte] ++ ++ *) Add the functions BUF_strndup() and BUF_memdup(). BUF_strndup() ++ works like BUF_strdup() but can be used to duplicate a portion of ++ a string. The copy gets NUL-terminated. BUF_memdup() duplicates ++ a memory area. ++ [Richard Levitte] ++ ++ *) Add the function sk_find_ex() which works like sk_find(), but will ++ return an index to an element even if an exact match couldn't be ++ found. The index is guaranteed to point at the element where the ++ searched-for key would be inserted to preserve sorting order. ++ [Richard Levitte] ++ ++ *) Add the function OBJ_bsearch_ex() which works like OBJ_bsearch() but ++ takes an extra flags argument for optional functionality. Currently, ++ the following flags are defined: ++ ++ OBJ_BSEARCH_VALUE_ON_NOMATCH ++ This one gets OBJ_bsearch_ex() to return a pointer to the first ++ element where the comparing function returns a negative or zero ++ number. ++ ++ OBJ_BSEARCH_FIRST_VALUE_ON_MATCH ++ This one gets OBJ_bsearch_ex() to return a pointer to the first ++ element where the comparing function returns zero. This is useful ++ if there are more than one element where the comparing function ++ returns zero. ++ [Richard Levitte] ++ ++ *) Make it possible to create self-signed certificates with 'openssl ca' ++ in such a way that the self-signed certificate becomes part of the ++ CA database and uses the same mechanisms for serial number generation ++ as all other certificate signing. The new flag '-selfsign' enables ++ this functionality. Adapt CA.sh and CA.pl.in. ++ [Richard Levitte] ++ ++ *) Add functionality to check the public key of a certificate request ++ against a given private. This is useful to check that a certificate ++ request can be signed by that key (self-signing). ++ [Richard Levitte] ++ ++ *) Make it possible to have multiple active certificates with the same ++ subject in the CA index file. This is done only if the keyword ++ 'unique_subject' is set to 'no' in the main CA section (default ++ if 'CA_default') of the configuration file. The value is saved ++ with the database itself in a separate index attribute file, ++ named like the index file with '.attr' appended to the name. ++ [Richard Levitte] ++ ++ *) Generate muti valued AVAs using '+' notation in config files for ++ req and dirName. ++ [Steve Henson] ++ ++ *) Support for nameConstraints certificate extension. ++ [Steve Henson] ++ ++ *) Support for policyConstraints certificate extension. ++ [Steve Henson] ++ ++ *) Support for policyMappings certificate extension. ++ [Steve Henson] ++ ++ *) Make sure the default DSA_METHOD implementation only uses its ++ dsa_mod_exp() and/or bn_mod_exp() handlers if they are non-NULL, ++ and change its own handlers to be NULL so as to remove unnecessary ++ indirection. This lets alternative implementations fallback to the ++ default implementation more easily. ++ [Geoff Thorpe] ++ ++ *) Support for directoryName in GeneralName related extensions ++ in config files. ++ [Steve Henson] ++ ++ *) Make it possible to link applications using Makefile.shared. ++ Make that possible even when linking against static libraries! ++ [Richard Levitte] ++ ++ *) Support for single pass processing for S/MIME signing. This now ++ means that S/MIME signing can be done from a pipe, in addition ++ cleartext signing (multipart/signed type) is effectively streaming ++ and the signed data does not need to be all held in memory. ++ ++ This is done with a new flag PKCS7_STREAM. When this flag is set ++ PKCS7_sign() only initializes the PKCS7 structure and the actual signing ++ is done after the data is output (and digests calculated) in ++ SMIME_write_PKCS7(). ++ [Steve Henson] ++ ++ *) Add full support for -rpath/-R, both in shared libraries and ++ applications, at least on the platforms where it's known how ++ to do it. ++ [Richard Levitte] ++ ++ *) In crypto/ec/ec_mult.c, implement fast point multiplication with ++ precomputation, based on wNAF splitting: EC_GROUP_precompute_mult() ++ will now compute a table of multiples of the generator that ++ makes subsequent invocations of EC_POINTs_mul() or EC_POINT_mul() ++ faster (notably in the case of a single point multiplication, ++ scalar * generator). ++ [Nils Larsch, Bodo Moeller] ++ ++ *) IPv6 support for certificate extensions. The various extensions ++ which use the IP:a.b.c.d can now take IPv6 addresses using the ++ formats of RFC1884 2.2 . IPv6 addresses are now also displayed ++ correctly. ++ [Steve Henson] ++ ++ *) Added an ENGINE that implements RSA by performing private key ++ exponentiations with the GMP library. The conversions to and from ++ GMP's mpz_t format aren't optimised nor are any montgomery forms ++ cached, and on x86 it appears OpenSSL's own performance has caught up. ++ However there are likely to be other architectures where GMP could ++ provide a boost. This ENGINE is not built in by default, but it can be ++ specified at Configure time and should be accompanied by the necessary ++ linker additions, eg; ++ ./config -DOPENSSL_USE_GMP -lgmp ++ [Geoff Thorpe] ++ ++ *) "openssl engine" will not display ENGINE/DSO load failure errors when ++ testing availability of engines with "-t" - the old behaviour is ++ produced by increasing the feature's verbosity with "-tt". ++ [Geoff Thorpe] ++ ++ *) ECDSA routines: under certain error conditions uninitialized BN objects ++ could be freed. Solution: make sure initialization is performed early ++ enough. (Reported and fix supplied by Nils Larsch ++ via PR#459) ++ [Lutz Jaenicke] ++ ++ *) Key-generation can now be implemented in RSA_METHOD, DSA_METHOD ++ and DH_METHOD (eg. by ENGINE implementations) to override the normal ++ software implementations. For DSA and DH, parameter generation can ++ also be overridden by providing the appropriate method callbacks. ++ [Geoff Thorpe] ++ ++ *) Change the "progress" mechanism used in key-generation and ++ primality testing to functions that take a new BN_GENCB pointer in ++ place of callback/argument pairs. The new API functions have "_ex" ++ postfixes and the older functions are reimplemented as wrappers for ++ the new ones. The OPENSSL_NO_DEPRECATED symbol can be used to hide ++ declarations of the old functions to help (graceful) attempts to ++ migrate to the new functions. Also, the new key-generation API ++ functions operate on a caller-supplied key-structure and return ++ success/failure rather than returning a key or NULL - this is to ++ help make "keygen" another member function of RSA_METHOD etc. ++ ++ Example for using the new callback interface: ++ ++ int (*my_callback)(int a, int b, BN_GENCB *cb) = ...; ++ void *my_arg = ...; ++ BN_GENCB my_cb; ++ ++ BN_GENCB_set(&my_cb, my_callback, my_arg); ++ ++ return BN_is_prime_ex(some_bignum, BN_prime_checks, NULL, &cb); ++ /* For the meaning of a, b in calls to my_callback(), see the ++ * documentation of the function that calls the callback. ++ * cb will point to my_cb; my_arg can be retrieved as cb->arg. ++ * my_callback should return 1 if it wants BN_is_prime_ex() ++ * to continue, or 0 to stop. ++ */ ++ ++ [Geoff Thorpe] ++ ++ *) Change the ZLIB compression method to be stateful, and make it ++ available to TLS with the number defined in ++ draft-ietf-tls-compression-04.txt. ++ [Richard Levitte] ++ ++ *) Add the ASN.1 structures and functions for CertificatePair, which ++ is defined as follows (according to X.509_4thEditionDraftV6.pdf): ++ ++ CertificatePair ::= SEQUENCE { ++ forward [0] Certificate OPTIONAL, ++ reverse [1] Certificate OPTIONAL, ++ -- at least one of the pair shall be present -- } ++ ++ Also implement the PEM functions to read and write certificate ++ pairs, and defined the PEM tag as "CERTIFICATE PAIR". ++ ++ This needed to be defined, mostly for the sake of the LDAP ++ attribute crossCertificatePair, but may prove useful elsewhere as ++ well. ++ [Richard Levitte] ++ ++ *) Make it possible to inhibit symlinking of shared libraries in ++ Makefile.shared, for Cygwin's sake. ++ [Richard Levitte] ++ ++ *) Extend the BIGNUM API by creating a function ++ void BN_set_negative(BIGNUM *a, int neg); ++ and a macro that behave like ++ int BN_is_negative(const BIGNUM *a); ++ ++ to avoid the need to access 'a->neg' directly in applications. ++ [Nils Larsch] ++ ++ *) Implement fast modular reduction for pseudo-Mersenne primes ++ used in NIST curves (crypto/bn/bn_nist.c, crypto/ec/ecp_nist.c). ++ EC_GROUP_new_curve_GFp() will now automatically use this ++ if applicable. ++ [Nils Larsch ] ++ ++ *) Add new lock type (CRYPTO_LOCK_BN). ++ [Bodo Moeller] ++ ++ *) Change the ENGINE framework to automatically load engines ++ dynamically from specific directories unless they could be ++ found to already be built in or loaded. Move all the ++ current engines except for the cryptodev one to a new ++ directory engines/. ++ The engines in engines/ are built as shared libraries if ++ the "shared" options was given to ./Configure or ./config. ++ Otherwise, they are inserted in libcrypto.a. ++ /usr/local/ssl/engines is the default directory for dynamic ++ engines, but that can be overridden at configure time through ++ the usual use of --prefix and/or --openssldir, and at run ++ time with the environment variable OPENSSL_ENGINES. ++ [Geoff Thorpe and Richard Levitte] ++ ++ *) Add Makefile.shared, a helper makefile to build shared ++ libraries. Adapt Makefile.org. ++ [Richard Levitte] ++ ++ *) Add version info to Win32 DLLs. ++ [Peter 'Luna' Runestig" ] ++ ++ *) Add new 'medium level' PKCS#12 API. Certificates and keys ++ can be added using this API to created arbitrary PKCS#12 ++ files while avoiding the low level API. ++ ++ New options to PKCS12_create(), key or cert can be NULL and ++ will then be omitted from the output file. The encryption ++ algorithm NIDs can be set to -1 for no encryption, the mac ++ iteration count can be set to 0 to omit the mac. ++ ++ Enhance pkcs12 utility by making the -nokeys and -nocerts ++ options work when creating a PKCS#12 file. New option -nomac ++ to omit the mac, NONE can be set for an encryption algorithm. ++ New code is modified to use the enhanced PKCS12_create() ++ instead of the low level API. ++ [Steve Henson] ++ ++ *) Extend ASN1 encoder to support indefinite length constructed ++ encoding. This can output sequences tags and octet strings in ++ this form. Modify pk7_asn1.c to support indefinite length ++ encoding. This is experimental and needs additional code to ++ be useful, such as an ASN1 bio and some enhanced streaming ++ PKCS#7 code. ++ ++ Extend template encode functionality so that tagging is passed ++ down to the template encoder. ++ [Steve Henson] ++ ++ *) Let 'openssl req' fail if an argument to '-newkey' is not ++ recognized instead of using RSA as a default. ++ [Bodo Moeller] ++ ++ *) Add support for ECC-based ciphersuites from draft-ietf-tls-ecc-01.txt. ++ As these are not official, they are not included in "ALL"; ++ the "ECCdraft" ciphersuite group alias can be used to select them. ++ [Vipul Gupta and Sumit Gupta (Sun Microsystems Laboratories)] ++ ++ *) Add ECDH engine support. ++ [Nils Gura and Douglas Stebila (Sun Microsystems Laboratories)] ++ ++ *) Add ECDH in new directory crypto/ecdh/. ++ [Douglas Stebila (Sun Microsystems Laboratories)] ++ ++ *) Let BN_rand_range() abort with an error after 100 iterations ++ without success (which indicates a broken PRNG). ++ [Bodo Moeller] ++ ++ *) Change BN_mod_sqrt() so that it verifies that the input value ++ is really the square of the return value. (Previously, ++ BN_mod_sqrt would show GIGO behaviour.) ++ [Bodo Moeller] ++ ++ *) Add named elliptic curves over binary fields from X9.62, SECG, ++ and WAP/WTLS; add OIDs that were still missing. ++ ++ [Sheueling Chang Shantz and Douglas Stebila ++ (Sun Microsystems Laboratories)] ++ ++ *) Extend the EC library for elliptic curves over binary fields ++ (new files ec2_smpl.c, ec2_smpt.c, ec2_mult.c in crypto/ec/). ++ New EC_METHOD: ++ ++ EC_GF2m_simple_method ++ ++ New API functions: ++ ++ EC_GROUP_new_curve_GF2m ++ EC_GROUP_set_curve_GF2m ++ EC_GROUP_get_curve_GF2m ++ EC_POINT_set_affine_coordinates_GF2m ++ EC_POINT_get_affine_coordinates_GF2m ++ EC_POINT_set_compressed_coordinates_GF2m ++ ++ Point compression for binary fields is disabled by default for ++ patent reasons (compile with OPENSSL_EC_BIN_PT_COMP defined to ++ enable it). ++ ++ As binary polynomials are represented as BIGNUMs, various members ++ of the EC_GROUP and EC_POINT data structures can be shared ++ between the implementations for prime fields and binary fields; ++ the above ..._GF2m functions (except for EX_GROUP_new_curve_GF2m) ++ are essentially identical to their ..._GFp counterparts. ++ (For simplicity, the '..._GFp' prefix has been dropped from ++ various internal method names.) ++ ++ An internal 'field_div' method (similar to 'field_mul' and ++ 'field_sqr') has been added; this is used only for binary fields. ++ ++ [Sheueling Chang Shantz and Douglas Stebila ++ (Sun Microsystems Laboratories)] ++ ++ *) Optionally dispatch EC_POINT_mul(), EC_POINT_precompute_mult() ++ through methods ('mul', 'precompute_mult'). ++ ++ The generic implementations (now internally called 'ec_wNAF_mul' ++ and 'ec_wNAF_precomputed_mult') remain the default if these ++ methods are undefined. ++ ++ [Sheueling Chang Shantz and Douglas Stebila ++ (Sun Microsystems Laboratories)] ++ ++ *) New function EC_GROUP_get_degree, which is defined through ++ EC_METHOD. For curves over prime fields, this returns the bit ++ length of the modulus. ++ ++ [Sheueling Chang Shantz and Douglas Stebila ++ (Sun Microsystems Laboratories)] ++ ++ *) New functions EC_GROUP_dup, EC_POINT_dup. ++ (These simply call ..._new and ..._copy). ++ ++ [Sheueling Chang Shantz and Douglas Stebila ++ (Sun Microsystems Laboratories)] ++ ++ *) Add binary polynomial arithmetic software in crypto/bn/bn_gf2m.c. ++ Polynomials are represented as BIGNUMs (where the sign bit is not ++ used) in the following functions [macros]: ++ ++ BN_GF2m_add ++ BN_GF2m_sub [= BN_GF2m_add] ++ BN_GF2m_mod [wrapper for BN_GF2m_mod_arr] ++ BN_GF2m_mod_mul [wrapper for BN_GF2m_mod_mul_arr] ++ BN_GF2m_mod_sqr [wrapper for BN_GF2m_mod_sqr_arr] ++ BN_GF2m_mod_inv ++ BN_GF2m_mod_exp [wrapper for BN_GF2m_mod_exp_arr] ++ BN_GF2m_mod_sqrt [wrapper for BN_GF2m_mod_sqrt_arr] ++ BN_GF2m_mod_solve_quad [wrapper for BN_GF2m_mod_solve_quad_arr] ++ BN_GF2m_cmp [= BN_ucmp] ++ ++ (Note that only the 'mod' functions are actually for fields GF(2^m). ++ BN_GF2m_add() is misnomer, but this is for the sake of consistency.) ++ ++ For some functions, an the irreducible polynomial defining a ++ field can be given as an 'unsigned int[]' with strictly ++ decreasing elements giving the indices of those bits that are set; ++ i.e., p[] represents the polynomial ++ f(t) = t^p[0] + t^p[1] + ... + t^p[k] ++ where ++ p[0] > p[1] > ... > p[k] = 0. ++ This applies to the following functions: ++ ++ BN_GF2m_mod_arr ++ BN_GF2m_mod_mul_arr ++ BN_GF2m_mod_sqr_arr ++ BN_GF2m_mod_inv_arr [wrapper for BN_GF2m_mod_inv] ++ BN_GF2m_mod_div_arr [wrapper for BN_GF2m_mod_div] ++ BN_GF2m_mod_exp_arr ++ BN_GF2m_mod_sqrt_arr ++ BN_GF2m_mod_solve_quad_arr ++ BN_GF2m_poly2arr ++ BN_GF2m_arr2poly ++ ++ Conversion can be performed by the following functions: ++ ++ BN_GF2m_poly2arr ++ BN_GF2m_arr2poly ++ ++ bntest.c has additional tests for binary polynomial arithmetic. ++ ++ Two implementations for BN_GF2m_mod_div() are available. ++ The default algorithm simply uses BN_GF2m_mod_inv() and ++ BN_GF2m_mod_mul(). The alternative algorithm is compiled in only ++ if OPENSSL_SUN_GF2M_DIV is defined (patent pending; read the ++ copyright notice in crypto/bn/bn_gf2m.c before enabling it). ++ ++ [Sheueling Chang Shantz and Douglas Stebila ++ (Sun Microsystems Laboratories)] ++ ++ *) Add new error code 'ERR_R_DISABLED' that can be used when some ++ functionality is disabled at compile-time. ++ [Douglas Stebila ] ++ ++ *) Change default behaviour of 'openssl asn1parse' so that more ++ information is visible when viewing, e.g., a certificate: ++ ++ Modify asn1_parse2 (crypto/asn1/asn1_par.c) so that in non-'dump' ++ mode the content of non-printable OCTET STRINGs is output in a ++ style similar to INTEGERs, but with '[HEX DUMP]' prepended to ++ avoid the appearance of a printable string. ++ [Nils Larsch ] ++ ++ *) Add 'asn1_flag' and 'asn1_form' member to EC_GROUP with access ++ functions ++ EC_GROUP_set_asn1_flag() ++ EC_GROUP_get_asn1_flag() ++ EC_GROUP_set_point_conversion_form() ++ EC_GROUP_get_point_conversion_form() ++ These control ASN1 encoding details: ++ - Curves (i.e., groups) are encoded explicitly unless asn1_flag ++ has been set to OPENSSL_EC_NAMED_CURVE. ++ - Points are encoded in uncompressed form by default; options for ++ asn1_for are as for point2oct, namely ++ POINT_CONVERSION_COMPRESSED ++ POINT_CONVERSION_UNCOMPRESSED ++ POINT_CONVERSION_HYBRID ++ ++ Also add 'seed' and 'seed_len' members to EC_GROUP with access ++ functions ++ EC_GROUP_set_seed() ++ EC_GROUP_get0_seed() ++ EC_GROUP_get_seed_len() ++ This is used only for ASN1 purposes (so far). ++ [Nils Larsch ] ++ ++ *) Add 'field_type' member to EC_METHOD, which holds the NID ++ of the appropriate field type OID. The new function ++ EC_METHOD_get_field_type() returns this value. ++ [Nils Larsch ] ++ ++ *) Add functions ++ EC_POINT_point2bn() ++ EC_POINT_bn2point() ++ EC_POINT_point2hex() ++ EC_POINT_hex2point() ++ providing useful interfaces to EC_POINT_point2oct() and ++ EC_POINT_oct2point(). ++ [Nils Larsch ] ++ ++ *) Change internals of the EC library so that the functions ++ EC_GROUP_set_generator() ++ EC_GROUP_get_generator() ++ EC_GROUP_get_order() ++ EC_GROUP_get_cofactor() ++ are implemented directly in crypto/ec/ec_lib.c and not dispatched ++ to methods, which would lead to unnecessary code duplication when ++ adding different types of curves. ++ [Nils Larsch with input by Bodo Moeller] ++ ++ *) Implement compute_wNAF (crypto/ec/ec_mult.c) without BIGNUM ++ arithmetic, and such that modified wNAFs are generated ++ (which avoid length expansion in many cases). ++ [Bodo Moeller] ++ ++ *) Add a function EC_GROUP_check_discriminant() (defined via ++ EC_METHOD) that verifies that the curve discriminant is non-zero. ++ ++ Add a function EC_GROUP_check() that makes some sanity tests ++ on a EC_GROUP, its generator and order. This includes ++ EC_GROUP_check_discriminant(). ++ [Nils Larsch ] ++ ++ *) Add ECDSA in new directory crypto/ecdsa/. ++ ++ Add applications 'openssl ecparam' and 'openssl ecdsa' ++ (these are based on 'openssl dsaparam' and 'openssl dsa'). ++ ++ ECDSA support is also included in various other files across the ++ library. Most notably, ++ - 'openssl req' now has a '-newkey ecdsa:file' option; ++ - EVP_PKCS82PKEY (crypto/evp/evp_pkey.c) now can handle ECDSA; ++ - X509_PUBKEY_get (crypto/asn1/x_pubkey.c) and ++ d2i_PublicKey (crypto/asn1/d2i_pu.c) have been modified to make ++ them suitable for ECDSA where domain parameters must be ++ extracted before the specific public key; ++ - ECDSA engine support has been added. ++ [Nils Larsch ] ++ ++ *) Include some named elliptic curves, and add OIDs from X9.62, ++ SECG, and WAP/WTLS. Each curve can be obtained from the new ++ function ++ EC_GROUP_new_by_curve_name(), ++ and the list of available named curves can be obtained with ++ EC_get_builtin_curves(). ++ Also add a 'curve_name' member to EC_GROUP objects, which can be ++ accessed via ++ EC_GROUP_set_curve_name() ++ EC_GROUP_get_curve_name() ++ [Nils Larsch ] ++ ++ *) Include "!eNULL" in SSL_DEFAULT_CIPHER_LIST to make sure that ++ a ciphersuite string such as "DEFAULT:RSA" cannot enable ++ authentication-only ciphersuites. ++ [Bodo Moeller] ++ ++ *) Since AES128 and AES256 share a single mask bit in the logic of ++ ssl/ssl_ciph.c, the code for masking out disabled ciphers needs a ++ kludge to work properly if AES128 is available and AES256 isn't. ++ [Victor Duchovni] ++ ++ *) Expand security boundary to match 1.1.1 module. ++ [Steve Henson] ++ ++ *) Remove redundant features: hash file source, editing of test vectors ++ modify fipsld to use external fips_premain.c signature. ++ [Steve Henson] ++ ++ *) New perl script mkfipsscr.pl to create shell scripts or batch files to ++ run algorithm test programs. ++ [Steve Henson] ++ ++ *) Make algorithm test programs more tolerant of whitespace. ++ [Steve Henson] ++ ++ *) Have SSL/TLS server implementation tolerate "mismatched" record ++ protocol version while receiving ClientHello even if the ++ ClientHello is fragmented. (The server can't insist on the ++ particular protocol version it has chosen before the ServerHello ++ message has informed the client about his choice.) ++ [Bodo Moeller] ++ ++ *) Load error codes if they are not already present instead of using a ++ static variable. This allows them to be cleanly unloaded and reloaded. ++ [Steve Henson] ++ ++ Changes between 0.9.7k and 0.9.7l [28 Sep 2006] ++ ++ *) Introduce limits to prevent malicious keys being able to ++ cause a denial of service. (CVE-2006-2940) ++ [Steve Henson, Bodo Moeller] ++ ++ *) Fix ASN.1 parsing of certain invalid structures that can result ++ in a denial of service. (CVE-2006-2937) [Steve Henson] ++ ++ *) Fix buffer overflow in SSL_get_shared_ciphers() function. ++ (CVE-2006-3738) [Tavis Ormandy and Will Drewry, Google Security Team] ++ ++ *) Fix SSL client code which could crash if connecting to a ++ malicious SSLv2 server. (CVE-2006-4343) ++ [Tavis Ormandy and Will Drewry, Google Security Team] ++ ++ *) Change ciphersuite string processing so that an explicit ++ ciphersuite selects this one ciphersuite (so that "AES256-SHA" ++ will no longer include "AES128-SHA"), and any other similar ++ ciphersuite (same bitmap) from *other* protocol versions (so that ++ "RC4-MD5" will still include both the SSL 2.0 ciphersuite and the ++ SSL 3.0/TLS 1.0 ciphersuite). This is a backport combining ++ changes from 0.9.8b and 0.9.8d. ++ [Bodo Moeller] ++ ++ Changes between 0.9.7j and 0.9.7k [05 Sep 2006] ++ ++ *) Avoid PKCS #1 v1.5 signature attack discovered by Daniel Bleichenbacher ++ (CVE-2006-4339) [Ben Laurie and Google Security Team] ++ ++ *) Change the Unix randomness entropy gathering to use poll() when ++ possible instead of select(), since the latter has some ++ undesirable limitations. ++ [Darryl Miles via Richard Levitte and Bodo Moeller] ++ ++ *) Disable rogue ciphersuites: ++ ++ - SSLv2 0x08 0x00 0x80 ("RC4-64-MD5") ++ - SSLv3/TLSv1 0x00 0x61 ("EXP1024-RC2-CBC-MD5") ++ - SSLv3/TLSv1 0x00 0x60 ("EXP1024-RC4-MD5") ++ ++ The latter two were purportedly from ++ draft-ietf-tls-56-bit-ciphersuites-0[01].txt, but do not really ++ appear there. ++ ++ Also deactive the remaining ciphersuites from ++ draft-ietf-tls-56-bit-ciphersuites-01.txt. These are just as ++ unofficial, and the ID has long expired. ++ [Bodo Moeller] ++ ++ *) Fix RSA blinding Heisenbug (problems sometimes occurred on ++ dual-core machines) and other potential thread-safety issues. ++ [Bodo Moeller] ++ ++ Changes between 0.9.7i and 0.9.7j [04 May 2006] ++ ++ *) Adapt fipsld and the build system to link against the validated FIPS ++ module in FIPS mode. ++ [Steve Henson] ++ ++ *) Fixes for VC++ 2005 build under Windows. ++ [Steve Henson] ++ ++ *) Add new Windows build target VC-32-GMAKE for VC++. This uses GNU make ++ from a Windows bash shell such as MSYS. It is autodetected from the ++ "config" script when run from a VC++ environment. Modify standard VC++ ++ build to use fipscanister.o from the GNU make build. ++ [Steve Henson] ++ ++ Changes between 0.9.7h and 0.9.7i [14 Oct 2005] ++ ++ *) Wrapped the definition of EVP_MAX_MD_SIZE in a #ifdef OPENSSL_FIPS. ++ The value now differs depending on if you build for FIPS or not. ++ BEWARE! A program linked with a shared FIPSed libcrypto can't be ++ safely run with a non-FIPSed libcrypto, as it may crash because of ++ the difference induced by this change. ++ [Andy Polyakov] ++ ++ Changes between 0.9.7g and 0.9.7h [11 Oct 2005] ++ ++ *) Remove the functionality of SSL_OP_MSIE_SSLV2_RSA_PADDING ++ (part of SSL_OP_ALL). This option used to disable the ++ countermeasure against man-in-the-middle protocol-version ++ rollback in the SSL 2.0 server implementation, which is a bad ++ idea. (CVE-2005-2969) ++ ++ [Bodo Moeller; problem pointed out by Yutaka Oiwa (Research Center ++ for Information Security, National Institute of Advanced Industrial ++ Science and Technology [AIST], Japan)] ++ ++ *) Minimal support for X9.31 signatures and PSS padding modes. This is ++ mainly for FIPS compliance and not fully integrated at this stage. ++ [Steve Henson] ++ ++ *) For DSA signing, unless DSA_FLAG_NO_EXP_CONSTTIME is set, perform ++ the exponentiation using a fixed-length exponent. (Otherwise, ++ the information leaked through timing could expose the secret key ++ after many signatures; cf. Bleichenbacher's attack on DSA with ++ biased k.) ++ [Bodo Moeller] ++ ++ *) Make a new fixed-window mod_exp implementation the default for ++ RSA, DSA, and DH private-key operations so that the sequence of ++ squares and multiplies and the memory access pattern are ++ independent of the particular secret key. This will mitigate ++ cache-timing and potential related attacks. ++ ++ BN_mod_exp_mont_consttime() is the new exponentiation implementation, ++ and this is automatically used by BN_mod_exp_mont() if the new flag ++ BN_FLG_EXP_CONSTTIME is set for the exponent. RSA, DSA, and DH ++ will use this BN flag for private exponents unless the flag ++ RSA_FLAG_NO_EXP_CONSTTIME, DSA_FLAG_NO_EXP_CONSTTIME, or ++ DH_FLAG_NO_EXP_CONSTTIME, respectively, is set. ++ ++ [Matthew D Wood (Intel Corp), with some changes by Bodo Moeller] ++ ++ *) Change the client implementation for SSLv23_method() and ++ SSLv23_client_method() so that is uses the SSL 3.0/TLS 1.0 ++ Client Hello message format if the SSL_OP_NO_SSLv2 option is set. ++ (Previously, the SSL 2.0 backwards compatible Client Hello ++ message format would be used even with SSL_OP_NO_SSLv2.) ++ [Bodo Moeller] ++ ++ *) Add support for smime-type MIME parameter in S/MIME messages which some ++ clients need. ++ [Steve Henson] ++ ++ *) New function BN_MONT_CTX_set_locked() to set montgomery parameters in ++ a threadsafe manner. Modify rsa code to use new function and add calls ++ to dsa and dh code (which had race conditions before). ++ [Steve Henson] ++ ++ *) Include the fixed error library code in the C error file definitions ++ instead of fixing them up at runtime. This keeps the error code ++ structures constant. ++ [Steve Henson] ++ ++ Changes between 0.9.7f and 0.9.7g [11 Apr 2005] ++ ++ [NB: OpenSSL 0.9.7h and later 0.9.7 patch levels were released after ++ OpenSSL 0.9.8.] ++ ++ *) Fixes for newer kerberos headers. NB: the casts are needed because ++ the 'length' field is signed on one version and unsigned on another ++ with no (?) obvious way to tell the difference, without these VC++ ++ complains. Also the "definition" of FAR (blank) is no longer included ++ nor is the error ENOMEM. KRB5_PRIVATE has to be set to 1 to pick up ++ some needed definitions. ++ [Steve Henson] ++ ++ *) Undo Cygwin change. ++ [Ulf Möller] ++ ++ *) Added support for proxy certificates according to RFC 3820. ++ Because they may be a security thread to unaware applications, ++ they must be explicitly allowed in run-time. See ++ docs/HOWTO/proxy_certificates.txt for further information. ++ [Richard Levitte] ++ ++ Changes between 0.9.7e and 0.9.7f [22 Mar 2005] ++ ++ *) Use (SSL_RANDOM_VALUE - 4) bytes of pseudo random data when generating ++ server and client random values. Previously ++ (SSL_RANDOM_VALUE - sizeof(time_t)) would be used which would result in ++ less random data when sizeof(time_t) > 4 (some 64 bit platforms). ++ ++ This change has negligible security impact because: ++ ++ 1. Server and client random values still have 24 bytes of pseudo random ++ data. ++ ++ 2. Server and client random values are sent in the clear in the initial ++ handshake. ++ ++ 3. The master secret is derived using the premaster secret (48 bytes in ++ size for static RSA ciphersuites) as well as client server and random ++ values. ++ ++ The OpenSSL team would like to thank the UK NISCC for bringing this issue ++ to our attention. ++ ++ [Stephen Henson, reported by UK NISCC] ++ ++ *) Use Windows randomness collection on Cygwin. ++ [Ulf Möller] ++ ++ *) Fix hang in EGD/PRNGD query when communication socket is closed ++ prematurely by EGD/PRNGD. ++ [Darren Tucker via Lutz Jänicke, resolves #1014] ++ ++ *) Prompt for pass phrases when appropriate for PKCS12 input format. ++ [Steve Henson] ++ ++ *) Back-port of selected performance improvements from development ++ branch, as well as improved support for PowerPC platforms. ++ [Andy Polyakov] ++ ++ *) Add lots of checks for memory allocation failure, error codes to indicate ++ failure and freeing up memory if a failure occurs. ++ [Nauticus Networks SSL Team , Steve Henson] ++ ++ *) Add new -passin argument to dgst. ++ [Steve Henson] ++ ++ *) Perform some character comparisons of different types in X509_NAME_cmp: ++ this is needed for some certificates that re-encode DNs into UTF8Strings ++ (in violation of RFC3280) and can't or won't issue name rollover ++ certificates. ++ [Steve Henson] ++ ++ *) Make an explicit check during certificate validation to see that ++ the CA setting in each certificate on the chain is correct. As a ++ side effect always do the following basic checks on extensions, ++ not just when there's an associated purpose to the check: ++ ++ - if there is an unhandled critical extension (unless the user ++ has chosen to ignore this fault) ++ - if the path length has been exceeded (if one is set at all) ++ - that certain extensions fit the associated purpose (if one has ++ been given) ++ [Richard Levitte] ++ ++ Changes between 0.9.7d and 0.9.7e [25 Oct 2004] ++ ++ *) Avoid a race condition when CRLs are checked in a multi threaded ++ environment. This would happen due to the reordering of the revoked ++ entries during signature checking and serial number lookup. Now the ++ encoding is cached and the serial number sort performed under a lock. ++ Add new STACK function sk_is_sorted(). ++ [Steve Henson] ++ ++ *) Add Delta CRL to the extension code. ++ [Steve Henson] ++ ++ *) Various fixes to s3_pkt.c so alerts are sent properly. ++ [David Holmes ] ++ ++ *) Reduce the chances of duplicate issuer name and serial numbers (in ++ violation of RFC3280) using the OpenSSL certificate creation utilities. ++ This is done by creating a random 64 bit value for the initial serial ++ number when a serial number file is created or when a self signed ++ certificate is created using 'openssl req -x509'. The initial serial ++ number file is created using 'openssl x509 -next_serial' in CA.pl ++ rather than being initialized to 1. ++ [Steve Henson] ++ ++ Changes between 0.9.7c and 0.9.7d [17 Mar 2004] ++ ++ *) Fix null-pointer assignment in do_change_cipher_spec() revealed ++ by using the Codenomicon TLS Test Tool (CVE-2004-0079) ++ [Joe Orton, Steve Henson] ++ ++ *) Fix flaw in SSL/TLS handshaking when using Kerberos ciphersuites ++ (CVE-2004-0112) ++ [Joe Orton, Steve Henson] ++ ++ *) Make it possible to have multiple active certificates with the same ++ subject in the CA index file. This is done only if the keyword ++ 'unique_subject' is set to 'no' in the main CA section (default ++ if 'CA_default') of the configuration file. The value is saved ++ with the database itself in a separate index attribute file, ++ named like the index file with '.attr' appended to the name. ++ [Richard Levitte] ++ ++ *) X509 verify fixes. Disable broken certificate workarounds when ++ X509_V_FLAGS_X509_STRICT is set. Check CRL issuer has cRLSign set if ++ keyUsage extension present. Don't accept CRLs with unhandled critical ++ extensions: since verify currently doesn't process CRL extensions this ++ rejects a CRL with *any* critical extensions. Add new verify error codes ++ for these cases. ++ [Steve Henson] ++ ++ *) When creating an OCSP nonce use an OCTET STRING inside the extnValue. ++ A clarification of RFC2560 will require the use of OCTET STRINGs and ++ some implementations cannot handle the current raw format. Since OpenSSL ++ copies and compares OCSP nonces as opaque blobs without any attempt at ++ parsing them this should not create any compatibility issues. ++ [Steve Henson] ++ ++ *) New md flag EVP_MD_CTX_FLAG_REUSE this allows md_data to be reused when ++ calling EVP_MD_CTX_copy_ex() to avoid calling OPENSSL_malloc(). Without ++ this HMAC (and other) operations are several times slower than OpenSSL ++ < 0.9.7. ++ [Steve Henson] ++ ++ *) Print out GeneralizedTime and UTCTime in ASN1_STRING_print_ex(). ++ [Peter Sylvester ] ++ ++ *) Use the correct content when signing type "other". ++ [Steve Henson] ++ ++ Changes between 0.9.7b and 0.9.7c [30 Sep 2003] ++ ++ *) Fix various bugs revealed by running the NISCC test suite: ++ ++ Stop out of bounds reads in the ASN1 code when presented with ++ invalid tags (CVE-2003-0543 and CVE-2003-0544). ++ ++ Free up ASN1_TYPE correctly if ANY type is invalid (CVE-2003-0545). ++ ++ If verify callback ignores invalid public key errors don't try to check ++ certificate signature with the NULL public key. ++ ++ [Steve Henson] ++ ++ *) New -ignore_err option in ocsp application to stop the server ++ exiting on the first error in a request. ++ [Steve Henson] ++ ++ *) In ssl3_accept() (ssl/s3_srvr.c) only accept a client certificate ++ if the server requested one: as stated in TLS 1.0 and SSL 3.0 ++ specifications. ++ [Steve Henson] ++ ++ *) In ssl3_get_client_hello() (ssl/s3_srvr.c), tolerate additional ++ extra data after the compression methods not only for TLS 1.0 ++ but also for SSL 3.0 (as required by the specification). ++ [Bodo Moeller; problem pointed out by Matthias Loepfe] ++ ++ *) Change X509_certificate_type() to mark the key as exported/exportable ++ when it's 512 *bits* long, not 512 bytes. ++ [Richard Levitte] ++ ++ *) Change AES_cbc_encrypt() so it outputs exact multiple of ++ blocks during encryption. ++ [Richard Levitte] ++ ++ *) Various fixes to base64 BIO and non blocking I/O. On write ++ flushes were not handled properly if the BIO retried. On read ++ data was not being buffered properly and had various logic bugs. ++ This also affects blocking I/O when the data being decoded is a ++ certain size. ++ [Steve Henson] ++ ++ *) Various S/MIME bugfixes and compatibility changes: ++ output correct application/pkcs7 MIME type if ++ PKCS7_NOOLDMIMETYPE is set. Tolerate some broken signatures. ++ Output CR+LF for EOL if PKCS7_CRLFEOL is set (this makes opening ++ of files as .eml work). Correctly handle very long lines in MIME ++ parser. ++ [Steve Henson] ++ ++ Changes between 0.9.7a and 0.9.7b [10 Apr 2003] ++ ++ *) Countermeasure against the Klima-Pokorny-Rosa extension of ++ Bleichbacher's attack on PKCS #1 v1.5 padding: treat ++ a protocol version number mismatch like a decryption error ++ in ssl3_get_client_key_exchange (ssl/s3_srvr.c). ++ [Bodo Moeller] ++ ++ *) Turn on RSA blinding by default in the default implementation ++ to avoid a timing attack. Applications that don't want it can call ++ RSA_blinding_off() or use the new flag RSA_FLAG_NO_BLINDING. ++ They would be ill-advised to do so in most cases. ++ [Ben Laurie, Steve Henson, Geoff Thorpe, Bodo Moeller] ++ ++ *) Change RSA blinding code so that it works when the PRNG is not ++ seeded (in this case, the secret RSA exponent is abused as ++ an unpredictable seed -- if it is not unpredictable, there ++ is no point in blinding anyway). Make RSA blinding thread-safe ++ by remembering the creator's thread ID in rsa->blinding and ++ having all other threads use local one-time blinding factors ++ (this requires more computation than sharing rsa->blinding, but ++ avoids excessive locking; and if an RSA object is not shared ++ between threads, blinding will still be very fast). ++ [Bodo Moeller] ++ ++ *) Fixed a typo bug that would cause ENGINE_set_default() to set an ++ ENGINE as defaults for all supported algorithms irrespective of ++ the 'flags' parameter. 'flags' is now honoured, so applications ++ should make sure they are passing it correctly. ++ [Geoff Thorpe] ++ ++ *) Target "mingw" now allows native Windows code to be generated in ++ the Cygwin environment as well as with the MinGW compiler. ++ [Ulf Moeller] ++ ++ Changes between 0.9.7 and 0.9.7a [19 Feb 2003] ++ ++ *) In ssl3_get_record (ssl/s3_pkt.c), minimize information leaked ++ via timing by performing a MAC computation even if incorrect ++ block cipher padding has been found. This is a countermeasure ++ against active attacks where the attacker has to distinguish ++ between bad padding and a MAC verification error. (CVE-2003-0078) ++ ++ [Bodo Moeller; problem pointed out by Brice Canvel (EPFL), ++ Alain Hiltgen (UBS), Serge Vaudenay (EPFL), and ++ Martin Vuagnoux (EPFL, Ilion)] ++ ++ *) Make the no-err option work as intended. The intention with no-err ++ is not to have the whole error stack handling routines removed from ++ libcrypto, it's only intended to remove all the function name and ++ reason texts, thereby removing some of the footprint that may not ++ be interesting if those errors aren't displayed anyway. ++ ++ NOTE: it's still possible for any application or module to have it's ++ own set of error texts inserted. The routines are there, just not ++ used by default when no-err is given. ++ [Richard Levitte] ++ ++ *) Add support for FreeBSD on IA64. ++ [dirk.meyer@dinoex.sub.org via Richard Levitte, resolves #454] ++ ++ *) Adjust DES_cbc_cksum() so it returns the same value as the MIT ++ Kerberos function mit_des_cbc_cksum(). Before this change, ++ the value returned by DES_cbc_cksum() was like the one from ++ mit_des_cbc_cksum(), except the bytes were swapped. ++ [Kevin Greaney and Richard Levitte] ++ ++ *) Allow an application to disable the automatic SSL chain building. ++ Before this a rather primitive chain build was always performed in ++ ssl3_output_cert_chain(): an application had no way to send the ++ correct chain if the automatic operation produced an incorrect result. ++ ++ Now the chain builder is disabled if either: ++ ++ 1. Extra certificates are added via SSL_CTX_add_extra_chain_cert(). ++ ++ 2. The mode flag SSL_MODE_NO_AUTO_CHAIN is set. ++ ++ The reasoning behind this is that an application would not want the ++ auto chain building to take place if extra chain certificates are ++ present and it might also want a means of sending no additional ++ certificates (for example the chain has two certificates and the ++ root is omitted). ++ [Steve Henson] ++ ++ *) Add the possibility to build without the ENGINE framework. ++ [Steven Reddie via Richard Levitte] ++ ++ *) Under Win32 gmtime() can return NULL: check return value in ++ OPENSSL_gmtime(). Add error code for case where gmtime() fails. ++ [Steve Henson] ++ ++ *) DSA routines: under certain error conditions uninitialized BN objects ++ could be freed. Solution: make sure initialization is performed early ++ enough. (Reported and fix supplied by Ivan D Nestlerode , ++ Nils Larsch via PR#459) ++ [Lutz Jaenicke] ++ ++ *) Another fix for SSLv2 session ID handling: the session ID was incorrectly ++ checked on reconnect on the client side, therefore session resumption ++ could still fail with a "ssl session id is different" error. This ++ behaviour is masked when SSL_OP_ALL is used due to ++ SSL_OP_MICROSOFT_SESS_ID_BUG being set. ++ Behaviour observed by Crispin Flowerday as ++ followup to PR #377. ++ [Lutz Jaenicke] ++ ++ *) IA-32 assembler support enhancements: unified ELF targets, support ++ for SCO/Caldera platforms, fix for Cygwin shared build. ++ [Andy Polyakov] ++ ++ *) Add support for FreeBSD on sparc64. As a consequence, support for ++ FreeBSD on non-x86 processors is separate from x86 processors on ++ the config script, much like the NetBSD support. ++ [Richard Levitte & Kris Kennaway ] ++ ++ Changes between 0.9.6h and 0.9.7 [31 Dec 2002] ++ ++ [NB: OpenSSL 0.9.6i and later 0.9.6 patch levels were released after ++ OpenSSL 0.9.7.] ++ ++ *) Fix session ID handling in SSLv2 client code: the SERVER FINISHED ++ code (06) was taken as the first octet of the session ID and the last ++ octet was ignored consequently. As a result SSLv2 client side session ++ caching could not have worked due to the session ID mismatch between ++ client and server. ++ Behaviour observed by Crispin Flowerday as ++ PR #377. ++ [Lutz Jaenicke] ++ ++ *) Change the declaration of needed Kerberos libraries to use EX_LIBS ++ instead of the special (and badly supported) LIBKRB5. LIBKRB5 is ++ removed entirely. ++ [Richard Levitte] ++ ++ *) The hw_ncipher.c engine requires dynamic locks. Unfortunately, it ++ seems that in spite of existing for more than a year, many application ++ author have done nothing to provide the necessary callbacks, which ++ means that this particular engine will not work properly anywhere. ++ This is a very unfortunate situation which forces us, in the name ++ of usability, to give the hw_ncipher.c a static lock, which is part ++ of libcrypto. ++ NOTE: This is for the 0.9.7 series ONLY. This hack will never ++ appear in 0.9.8 or later. We EXPECT application authors to have ++ dealt properly with this when 0.9.8 is released (unless we actually ++ make such changes in the libcrypto locking code that changes will ++ have to be made anyway). ++ [Richard Levitte] ++ ++ *) In asn1_d2i_read_bio() repeatedly call BIO_read() until all content ++ octets have been read, EOF or an error occurs. Without this change ++ some truncated ASN1 structures will not produce an error. ++ [Steve Henson] ++ ++ *) Disable Heimdal support, since it hasn't been fully implemented. ++ Still give the possibility to force the use of Heimdal, but with ++ warnings and a request that patches get sent to openssl-dev. ++ [Richard Levitte] ++ ++ *) Add the VC-CE target, introduce the WINCE sysname, and add ++ INSTALL.WCE and appropriate conditionals to make it build. ++ [Steven Reddie via Richard Levitte] ++ ++ *) Change the DLL names for Cygwin to cygcrypto-x.y.z.dll and ++ cygssl-x.y.z.dll, where x, y and z are the major, minor and ++ edit numbers of the version. ++ [Corinna Vinschen and Richard Levitte] ++ ++ *) Introduce safe string copy and catenation functions ++ (BUF_strlcpy() and BUF_strlcat()). ++ [Ben Laurie (CHATS) and Richard Levitte] ++ ++ *) Avoid using fixed-size buffers for one-line DNs. ++ [Ben Laurie (CHATS)] ++ ++ *) Add BUF_MEM_grow_clean() to avoid information leakage when ++ resizing buffers containing secrets, and use where appropriate. ++ [Ben Laurie (CHATS)] ++ ++ *) Avoid using fixed size buffers for configuration file location. ++ [Ben Laurie (CHATS)] ++ ++ *) Avoid filename truncation for various CA files. ++ [Ben Laurie (CHATS)] ++ ++ *) Use sizeof in preference to magic numbers. ++ [Ben Laurie (CHATS)] ++ ++ *) Avoid filename truncation in cert requests. ++ [Ben Laurie (CHATS)] ++ ++ *) Add assertions to check for (supposedly impossible) buffer ++ overflows. ++ [Ben Laurie (CHATS)] ++ ++ *) Don't cache truncated DNS entries in the local cache (this could ++ potentially lead to a spoofing attack). ++ [Ben Laurie (CHATS)] ++ ++ *) Fix various buffers to be large enough for hex/decimal ++ representations in a platform independent manner. ++ [Ben Laurie (CHATS)] ++ ++ *) Add CRYPTO_realloc_clean() to avoid information leakage when ++ resizing buffers containing secrets, and use where appropriate. ++ [Ben Laurie (CHATS)] ++ ++ *) Add BIO_indent() to avoid much slightly worrying code to do ++ indents. ++ [Ben Laurie (CHATS)] ++ ++ *) Convert sprintf()/BIO_puts() to BIO_printf(). ++ [Ben Laurie (CHATS)] ++ ++ *) buffer_gets() could terminate with the buffer only half ++ full. Fixed. ++ [Ben Laurie (CHATS)] ++ ++ *) Add assertions to prevent user-supplied crypto functions from ++ overflowing internal buffers by having large block sizes, etc. ++ [Ben Laurie (CHATS)] ++ ++ *) New OPENSSL_assert() macro (similar to assert(), but enabled ++ unconditionally). ++ [Ben Laurie (CHATS)] ++ ++ *) Eliminate unused copy of key in RC4. ++ [Ben Laurie (CHATS)] ++ ++ *) Eliminate unused and incorrectly sized buffers for IV in pem.h. ++ [Ben Laurie (CHATS)] ++ ++ *) Fix off-by-one error in EGD path. ++ [Ben Laurie (CHATS)] ++ ++ *) If RANDFILE path is too long, ignore instead of truncating. ++ [Ben Laurie (CHATS)] ++ ++ *) Eliminate unused and incorrectly sized X.509 structure ++ CBCParameter. ++ [Ben Laurie (CHATS)] ++ ++ *) Eliminate unused and dangerous function knumber(). ++ [Ben Laurie (CHATS)] ++ ++ *) Eliminate unused and dangerous structure, KSSL_ERR. ++ [Ben Laurie (CHATS)] ++ ++ *) Protect against overlong session ID context length in an encoded ++ session object. Since these are local, this does not appear to be ++ exploitable. ++ [Ben Laurie (CHATS)] ++ ++ *) Change from security patch (see 0.9.6e below) that did not affect ++ the 0.9.6 release series: ++ ++ Remote buffer overflow in SSL3 protocol - an attacker could ++ supply an oversized master key in Kerberos-enabled versions. ++ (CVE-2002-0657) ++ [Ben Laurie (CHATS)] ++ ++ *) Change the SSL kerb5 codes to match RFC 2712. ++ [Richard Levitte] ++ ++ *) Make -nameopt work fully for req and add -reqopt switch. ++ [Michael Bell , Steve Henson] ++ ++ *) The "block size" for block ciphers in CFB and OFB mode should be 1. ++ [Steve Henson, reported by Yngve Nysaeter Pettersen ] ++ ++ *) Make sure tests can be performed even if the corresponding algorithms ++ have been removed entirely. This was also the last step to make ++ OpenSSL compilable with DJGPP under all reasonable conditions. ++ [Richard Levitte, Doug Kaufman ] ++ ++ *) Add cipher selection rules COMPLEMENTOFALL and COMPLEMENTOFDEFAULT ++ to allow version independent disabling of normally unselected ciphers, ++ which may be activated as a side-effect of selecting a single cipher. ++ ++ (E.g., cipher list string "RSA" enables ciphersuites that are left ++ out of "ALL" because they do not provide symmetric encryption. ++ "RSA:!COMPLEMEMENTOFALL" avoids these unsafe ciphersuites.) ++ [Lutz Jaenicke, Bodo Moeller] ++ ++ *) Add appropriate support for separate platform-dependent build ++ directories. The recommended way to make a platform-dependent ++ build directory is the following (tested on Linux), maybe with ++ some local tweaks: ++ ++ # Place yourself outside of the OpenSSL source tree. In ++ # this example, the environment variable OPENSSL_SOURCE ++ # is assumed to contain the absolute OpenSSL source directory. ++ mkdir -p objtree/"`uname -s`-`uname -r`-`uname -m`" ++ cd objtree/"`uname -s`-`uname -r`-`uname -m`" ++ (cd $OPENSSL_SOURCE; find . -type f) | while read F; do ++ mkdir -p `dirname $F` ++ ln -s $OPENSSL_SOURCE/$F $F ++ done ++ ++ To be absolutely sure not to disturb the source tree, a "make clean" ++ is a good thing. If it isn't successful, don't worry about it, ++ it probably means the source directory is very clean. ++ [Richard Levitte] ++ ++ *) Make sure any ENGINE control commands make local copies of string ++ pointers passed to them whenever necessary. Otherwise it is possible ++ the caller may have overwritten (or deallocated) the original string ++ data when a later ENGINE operation tries to use the stored values. ++ [Götz Babin-Ebell ] ++ ++ *) Improve diagnostics in file reading and command-line digests. ++ [Ben Laurie aided and abetted by Solar Designer ] ++ ++ *) Add AES modes CFB and OFB to the object database. Correct an ++ error in AES-CFB decryption. ++ [Richard Levitte] ++ ++ *) Remove most calls to EVP_CIPHER_CTX_cleanup() in evp_enc.c, this ++ allows existing EVP_CIPHER_CTX structures to be reused after ++ calling EVP_*Final(). This behaviour is used by encryption ++ BIOs and some applications. This has the side effect that ++ applications must explicitly clean up cipher contexts with ++ EVP_CIPHER_CTX_cleanup() or they will leak memory. ++ [Steve Henson] ++ ++ *) Check the values of dna and dnb in bn_mul_recursive before calling ++ bn_mul_comba (a non zero value means the a or b arrays do not contain ++ n2 elements) and fallback to bn_mul_normal if either is not zero. ++ [Steve Henson] ++ ++ *) Fix escaping of non-ASCII characters when using the -subj option ++ of the "openssl req" command line tool. (Robert Joop ) ++ [Lutz Jaenicke] ++ ++ *) Make object definitions compliant to LDAP (RFC2256): SN is the short ++ form for "surname", serialNumber has no short form. ++ Use "mail" as the short name for "rfc822Mailbox" according to RFC2798; ++ therefore remove "mail" short name for "internet 7". ++ The OID for unique identifiers in X509 certificates is ++ x500UniqueIdentifier, not uniqueIdentifier. ++ Some more OID additions. (Michael Bell ) ++ [Lutz Jaenicke] ++ ++ *) Add an "init" command to the ENGINE config module and auto initialize ++ ENGINEs. Without any "init" command the ENGINE will be initialized ++ after all ctrl commands have been executed on it. If init=1 the ++ ENGINE is initailized at that point (ctrls before that point are run ++ on the uninitialized ENGINE and after on the initialized one). If ++ init=0 then the ENGINE will not be iniatialized at all. ++ [Steve Henson] ++ ++ *) Fix the 'app_verify_callback' interface so that the user-defined ++ argument is actually passed to the callback: In the ++ SSL_CTX_set_cert_verify_callback() prototype, the callback ++ declaration has been changed from ++ int (*cb)() ++ into ++ int (*cb)(X509_STORE_CTX *,void *); ++ in ssl_verify_cert_chain (ssl/ssl_cert.c), the call ++ i=s->ctx->app_verify_callback(&ctx) ++ has been changed into ++ i=s->ctx->app_verify_callback(&ctx, s->ctx->app_verify_arg). ++ ++ To update applications using SSL_CTX_set_cert_verify_callback(), ++ a dummy argument can be added to their callback functions. ++ [D. K. Smetters ] ++ ++ *) Added the '4758cca' ENGINE to support IBM 4758 cards. ++ [Maurice Gittens , touchups by Geoff Thorpe] ++ ++ *) Add and OPENSSL_LOAD_CONF define which will cause ++ OpenSSL_add_all_algorithms() to load the openssl.cnf config file. ++ This allows older applications to transparently support certain ++ OpenSSL features: such as crypto acceleration and dynamic ENGINE loading. ++ Two new functions OPENSSL_add_all_algorithms_noconf() which will never ++ load the config file and OPENSSL_add_all_algorithms_conf() which will ++ always load it have also been added. ++ [Steve Henson] ++ ++ *) Add the OFB, CFB and CTR (all with 128 bit feedback) to AES. ++ Adjust NIDs and EVP layer. ++ [Stephen Sprunk and Richard Levitte] ++ ++ *) Config modules support in openssl utility. ++ ++ Most commands now load modules from the config file, ++ though in a few (such as version) this isn't done ++ because it couldn't be used for anything. ++ ++ In the case of ca and req the config file used is ++ the same as the utility itself: that is the -config ++ command line option can be used to specify an ++ alternative file. ++ [Steve Henson] ++ ++ *) Move default behaviour from OPENSSL_config(). If appname is NULL ++ use "openssl_conf" if filename is NULL use default openssl config file. ++ [Steve Henson] ++ ++ *) Add an argument to OPENSSL_config() to allow the use of an alternative ++ config section name. Add a new flag to tolerate a missing config file ++ and move code to CONF_modules_load_file(). ++ [Steve Henson] ++ ++ *) Support for crypto accelerator cards from Accelerated Encryption ++ Processing, www.aep.ie. (Use engine 'aep') ++ The support was copied from 0.9.6c [engine] and adapted/corrected ++ to work with the new engine framework. ++ [AEP Inc. and Richard Levitte] ++ ++ *) Support for SureWare crypto accelerator cards from Baltimore ++ Technologies. (Use engine 'sureware') ++ The support was copied from 0.9.6c [engine] and adapted ++ to work with the new engine framework. ++ [Richard Levitte] ++ ++ *) Have the CHIL engine fork-safe (as defined by nCipher) and actually ++ make the newer ENGINE framework commands for the CHIL engine work. ++ [Toomas Kiisk and Richard Levitte] ++ ++ *) Make it possible to produce shared libraries on ReliantUNIX. ++ [Robert Dahlem via Richard Levitte] ++ ++ *) Add the configuration target debug-linux-ppro. ++ Make 'openssl rsa' use the general key loading routines ++ implemented in apps.c, and make those routines able to ++ handle the key format FORMAT_NETSCAPE and the variant ++ FORMAT_IISSGC. ++ [Toomas Kiisk via Richard Levitte] ++ ++ *) Fix a crashbug and a logic bug in hwcrhk_load_pubkey(). ++ [Toomas Kiisk via Richard Levitte] ++ ++ *) Add -keyform to rsautl, and document -engine. ++ [Richard Levitte, inspired by Toomas Kiisk ] ++ ++ *) Change BIO_new_file (crypto/bio/bss_file.c) to use new ++ BIO_R_NO_SUCH_FILE error code rather than the generic ++ ERR_R_SYS_LIB error code if fopen() fails with ENOENT. ++ [Ben Laurie] ++ ++ *) Add new functions ++ ERR_peek_last_error ++ ERR_peek_last_error_line ++ ERR_peek_last_error_line_data. ++ These are similar to ++ ERR_peek_error ++ ERR_peek_error_line ++ ERR_peek_error_line_data, ++ but report on the latest error recorded rather than the first one ++ still in the error queue. ++ [Ben Laurie, Bodo Moeller] ++ ++ *) default_algorithms option in ENGINE config module. This allows things ++ like: ++ default_algorithms = ALL ++ default_algorithms = RSA, DSA, RAND, CIPHERS, DIGESTS ++ [Steve Henson] ++ ++ *) Preliminary ENGINE config module. ++ [Steve Henson] ++ ++ *) New experimental application configuration code. ++ [Steve Henson] ++ ++ *) Change the AES code to follow the same name structure as all other ++ symmetric ciphers, and behave the same way. Move everything to ++ the directory crypto/aes, thereby obsoleting crypto/rijndael. ++ [Stephen Sprunk and Richard Levitte] ++ ++ *) SECURITY: remove unsafe setjmp/signal interaction from ui_openssl.c. ++ [Ben Laurie and Theo de Raadt] ++ ++ *) Add option to output public keys in req command. ++ [Massimiliano Pala madwolf@openca.org] ++ ++ *) Use wNAFs in EC_POINTs_mul() for improved efficiency ++ (up to about 10% better than before for P-192 and P-224). ++ [Bodo Moeller] ++ ++ *) New functions/macros ++ ++ SSL_CTX_set_msg_callback(ctx, cb) ++ SSL_CTX_set_msg_callback_arg(ctx, arg) ++ SSL_set_msg_callback(ssl, cb) ++ SSL_set_msg_callback_arg(ssl, arg) ++ ++ to request calling a callback function ++ ++ void cb(int write_p, int version, int content_type, ++ const void *buf, size_t len, SSL *ssl, void *arg) ++ ++ whenever a protocol message has been completely received ++ (write_p == 0) or sent (write_p == 1). Here 'version' is the ++ protocol version according to which the SSL library interprets ++ the current protocol message (SSL2_VERSION, SSL3_VERSION, or ++ TLS1_VERSION). 'content_type' is 0 in the case of SSL 2.0, or ++ the content type as defined in the SSL 3.0/TLS 1.0 protocol ++ specification (change_cipher_spec(20), alert(21), handshake(22)). ++ 'buf' and 'len' point to the actual message, 'ssl' to the ++ SSL object, and 'arg' is the application-defined value set by ++ SSL[_CTX]_set_msg_callback_arg(). ++ ++ 'openssl s_client' and 'openssl s_server' have new '-msg' options ++ to enable a callback that displays all protocol messages. ++ [Bodo Moeller] ++ ++ *) Change the shared library support so shared libraries are built as ++ soon as the corresponding static library is finished, and thereby get ++ openssl and the test programs linked against the shared library. ++ This still only happens when the keyword "shard" has been given to ++ the configuration scripts. ++ ++ NOTE: shared library support is still an experimental thing, and ++ backward binary compatibility is still not guaranteed. ++ ["Maciej W. Rozycki" and Richard Levitte] ++ ++ *) Add support for Subject Information Access extension. ++ [Peter Sylvester ] ++ ++ *) Make BUF_MEM_grow() behaviour more consistent: Initialise to zero ++ additional bytes when new memory had to be allocated, not just ++ when reusing an existing buffer. ++ [Bodo Moeller] ++ ++ *) New command line and configuration option 'utf8' for the req command. ++ This allows field values to be specified as UTF8 strings. ++ [Steve Henson] ++ ++ *) Add -multi and -mr options to "openssl speed" - giving multiple parallel ++ runs for the former and machine-readable output for the latter. ++ [Ben Laurie] ++ ++ *) Add '-noemailDN' option to 'openssl ca'. This prevents inclusion ++ of the e-mail address in the DN (i.e., it will go into a certificate ++ extension only). The new configuration file option 'email_in_dn = no' ++ has the same effect. ++ [Massimiliano Pala madwolf@openca.org] ++ ++ *) Change all functions with names starting with des_ to be starting ++ with DES_ instead. Add wrappers that are compatible with libdes, ++ but are named _ossl_old_des_*. Finally, add macros that map the ++ des_* symbols to the corresponding _ossl_old_des_* if libdes ++ compatibility is desired. If OpenSSL 0.9.6c compatibility is ++ desired, the des_* symbols will be mapped to DES_*, with one ++ exception. ++ ++ Since we provide two compatibility mappings, the user needs to ++ define the macro OPENSSL_DES_LIBDES_COMPATIBILITY if libdes ++ compatibility is desired. The default (i.e., when that macro ++ isn't defined) is OpenSSL 0.9.6c compatibility. ++ ++ There are also macros that enable and disable the support of old ++ des functions altogether. Those are OPENSSL_ENABLE_OLD_DES_SUPPORT ++ and OPENSSL_DISABLE_OLD_DES_SUPPORT. If none or both of those ++ are defined, the default will apply: to support the old des routines. ++ ++ In either case, one must include openssl/des.h to get the correct ++ definitions. Do not try to just include openssl/des_old.h, that ++ won't work. ++ ++ NOTE: This is a major break of an old API into a new one. Software ++ authors are encouraged to switch to the DES_ style functions. Some ++ time in the future, des_old.h and the libdes compatibility functions ++ will be disable (i.e. OPENSSL_DISABLE_OLD_DES_SUPPORT will be the ++ default), and then completely removed. ++ [Richard Levitte] ++ ++ *) Test for certificates which contain unsupported critical extensions. ++ If such a certificate is found during a verify operation it is ++ rejected by default: this behaviour can be overridden by either ++ handling the new error X509_V_ERR_UNHANDLED_CRITICAL_EXTENSION or ++ by setting the verify flag X509_V_FLAG_IGNORE_CRITICAL. A new function ++ X509_supported_extension() has also been added which returns 1 if a ++ particular extension is supported. ++ [Steve Henson] ++ ++ *) Modify the behaviour of EVP cipher functions in similar way to digests ++ to retain compatibility with existing code. ++ [Steve Henson] ++ ++ *) Modify the behaviour of EVP_DigestInit() and EVP_DigestFinal() to retain ++ compatibility with existing code. In particular the 'ctx' parameter does ++ not have to be to be initialized before the call to EVP_DigestInit() and ++ it is tidied up after a call to EVP_DigestFinal(). New function ++ EVP_DigestFinal_ex() which does not tidy up the ctx. Similarly function ++ EVP_MD_CTX_copy() changed to not require the destination to be ++ initialized valid and new function EVP_MD_CTX_copy_ex() added which ++ requires the destination to be valid. ++ ++ Modify all the OpenSSL digest calls to use EVP_DigestInit_ex(), ++ EVP_DigestFinal_ex() and EVP_MD_CTX_copy_ex(). ++ [Steve Henson] ++ ++ *) Change ssl3_get_message (ssl/s3_both.c) and the functions using it ++ so that complete 'Handshake' protocol structures are kept in memory ++ instead of overwriting 'msg_type' and 'length' with 'body' data. ++ [Bodo Moeller] ++ ++ *) Add an implementation of SSL_add_dir_cert_subjects_to_stack for Win32. ++ [Massimo Santin via Richard Levitte] ++ ++ *) Major restructuring to the underlying ENGINE code. This includes ++ reduction of linker bloat, separation of pure "ENGINE" manipulation ++ (initialisation, etc) from functionality dealing with implementations ++ of specific crypto iterfaces. This change also introduces integrated ++ support for symmetric ciphers and digest implementations - so ENGINEs ++ can now accelerate these by providing EVP_CIPHER and EVP_MD ++ implementations of their own. This is detailed in crypto/engine/README ++ as it couldn't be adequately described here. However, there are a few ++ API changes worth noting - some RSA, DSA, DH, and RAND functions that ++ were changed in the original introduction of ENGINE code have now ++ reverted back - the hooking from this code to ENGINE is now a good ++ deal more passive and at run-time, operations deal directly with ++ RSA_METHODs, DSA_METHODs (etc) as they did before, rather than ++ dereferencing through an ENGINE pointer any more. Also, the ENGINE ++ functions dealing with BN_MOD_EXP[_CRT] handlers have been removed - ++ they were not being used by the framework as there is no concept of a ++ BIGNUM_METHOD and they could not be generalised to the new ++ 'ENGINE_TABLE' mechanism that underlies the new code. Similarly, ++ ENGINE_cpy() has been removed as it cannot be consistently defined in ++ the new code. ++ [Geoff Thorpe] ++ ++ *) Change ASN1_GENERALIZEDTIME_check() to allow fractional seconds. ++ [Steve Henson] ++ ++ *) Change mkdef.pl to sort symbols that get the same entry number, ++ and make sure the automatically generated functions ERR_load_* ++ become part of libeay.num as well. ++ [Richard Levitte] ++ ++ *) New function SSL_renegotiate_pending(). This returns true once ++ renegotiation has been requested (either SSL_renegotiate() call ++ or HelloRequest/ClientHello received from the peer) and becomes ++ false once a handshake has been completed. ++ (For servers, SSL_renegotiate() followed by SSL_do_handshake() ++ sends a HelloRequest, but does not ensure that a handshake takes ++ place. SSL_renegotiate_pending() is useful for checking if the ++ client has followed the request.) ++ [Bodo Moeller] ++ ++ *) New SSL option SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION. ++ By default, clients may request session resumption even during ++ renegotiation (if session ID contexts permit); with this option, ++ session resumption is possible only in the first handshake. ++ ++ SSL_OP_ALL is now 0x00000FFFL instead of 0x000FFFFFL. This makes ++ more bits available for options that should not be part of ++ SSL_OP_ALL (such as SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION). ++ [Bodo Moeller] ++ ++ *) Add some demos for certificate and certificate request creation. ++ [Steve Henson] ++ ++ *) Make maximum certificate chain size accepted from the peer application ++ settable (SSL*_get/set_max_cert_list()), as proposed by ++ "Douglas E. Engert" . ++ [Lutz Jaenicke] ++ ++ *) Add support for shared libraries for Unixware-7 ++ (Boyd Lynn Gerber ). ++ [Lutz Jaenicke] ++ ++ *) Add a "destroy" handler to ENGINEs that allows structural cleanup to ++ be done prior to destruction. Use this to unload error strings from ++ ENGINEs that load their own error strings. NB: This adds two new API ++ functions to "get" and "set" this destroy handler in an ENGINE. ++ [Geoff Thorpe] ++ ++ *) Alter all existing ENGINE implementations (except "openssl" and ++ "openbsd") to dynamically instantiate their own error strings. This ++ makes them more flexible to be built both as statically-linked ENGINEs ++ and self-contained shared-libraries loadable via the "dynamic" ENGINE. ++ Also, add stub code to each that makes building them as self-contained ++ shared-libraries easier (see README.ENGINE). ++ [Geoff Thorpe] ++ ++ *) Add a "dynamic" ENGINE that provides a mechanism for binding ENGINE ++ implementations into applications that are completely implemented in ++ self-contained shared-libraries. The "dynamic" ENGINE exposes control ++ commands that can be used to configure what shared-library to load and ++ to control aspects of the way it is handled. Also, made an update to ++ the README.ENGINE file that brings its information up-to-date and ++ provides some information and instructions on the "dynamic" ENGINE ++ (ie. how to use it, how to build "dynamic"-loadable ENGINEs, etc). ++ [Geoff Thorpe] ++ ++ *) Make it possible to unload ranges of ERR strings with a new ++ "ERR_unload_strings" function. ++ [Geoff Thorpe] ++ ++ *) Add a copy() function to EVP_MD. ++ [Ben Laurie] ++ ++ *) Make EVP_MD routines take a context pointer instead of just the ++ md_data void pointer. ++ [Ben Laurie] ++ ++ *) Add flags to EVP_MD and EVP_MD_CTX. EVP_MD_FLAG_ONESHOT indicates ++ that the digest can only process a single chunk of data ++ (typically because it is provided by a piece of ++ hardware). EVP_MD_CTX_FLAG_ONESHOT indicates that the application ++ is only going to provide a single chunk of data, and hence the ++ framework needn't accumulate the data for oneshot drivers. ++ [Ben Laurie] ++ ++ *) As with "ERR", make it possible to replace the underlying "ex_data" ++ functions. This change also alters the storage and management of global ++ ex_data state - it's now all inside ex_data.c and all "class" code (eg. ++ RSA, BIO, SSL_CTX, etc) no longer stores its own STACKS and per-class ++ index counters. The API functions that use this state have been changed ++ to take a "class_index" rather than pointers to the class's local STACK ++ and counter, and there is now an API function to dynamically create new ++ classes. This centralisation allows us to (a) plug a lot of the ++ thread-safety problems that existed, and (b) makes it possible to clean ++ up all allocated state using "CRYPTO_cleanup_all_ex_data()". W.r.t. (b) ++ such data would previously have always leaked in application code and ++ workarounds were in place to make the memory debugging turn a blind eye ++ to it. Application code that doesn't use this new function will still ++ leak as before, but their memory debugging output will announce it now ++ rather than letting it slide. ++ ++ Besides the addition of CRYPTO_cleanup_all_ex_data(), another API change ++ induced by the "ex_data" overhaul is that X509_STORE_CTX_init() now ++ has a return value to indicate success or failure. ++ [Geoff Thorpe] ++ ++ *) Make it possible to replace the underlying "ERR" functions such that the ++ global state (2 LHASH tables and 2 locks) is only used by the "default" ++ implementation. This change also adds two functions to "get" and "set" ++ the implementation prior to it being automatically set the first time ++ any other ERR function takes place. Ie. an application can call "get", ++ pass the return value to a module it has just loaded, and that module ++ can call its own "set" function using that value. This means the ++ module's "ERR" operations will use (and modify) the error state in the ++ application and not in its own statically linked copy of OpenSSL code. ++ [Geoff Thorpe] ++ ++ *) Give DH, DSA, and RSA types their own "**_up_ref()" function to increment ++ reference counts. This performs normal REF_PRINT/REF_CHECK macros on ++ the operation, and provides a more encapsulated way for external code ++ (crypto/evp/ and ssl/) to do this. Also changed the evp and ssl code ++ to use these functions rather than manually incrementing the counts. ++ ++ Also rename "DSO_up()" function to more descriptive "DSO_up_ref()". ++ [Geoff Thorpe] ++ ++ *) Add EVP test program. ++ [Ben Laurie] ++ ++ *) Add symmetric cipher support to ENGINE. Expect the API to change! ++ [Ben Laurie] ++ ++ *) New CRL functions: X509_CRL_set_version(), X509_CRL_set_issuer_name() ++ X509_CRL_set_lastUpdate(), X509_CRL_set_nextUpdate(), X509_CRL_sort(), ++ X509_REVOKED_set_serialNumber(), and X509_REVOKED_set_revocationDate(). ++ These allow a CRL to be built without having to access X509_CRL fields ++ directly. Modify 'ca' application to use new functions. ++ [Steve Henson] ++ ++ *) Move SSL_OP_TLS_ROLLBACK_BUG out of the SSL_OP_ALL list of recommended ++ bug workarounds. Rollback attack detection is a security feature. ++ The problem will only arise on OpenSSL servers when TLSv1 is not ++ available (sslv3_server_method() or SSL_OP_NO_TLSv1). ++ Software authors not wanting to support TLSv1 will have special reasons ++ for their choice and can explicitly enable this option. ++ [Bodo Moeller, Lutz Jaenicke] ++ ++ *) Rationalise EVP so it can be extended: don't include a union of ++ cipher/digest structures, add init/cleanup functions for EVP_MD_CTX ++ (similar to those existing for EVP_CIPHER_CTX). ++ Usage example: ++ ++ EVP_MD_CTX md; ++ ++ EVP_MD_CTX_init(&md); /* new function call */ ++ EVP_DigestInit(&md, EVP_sha1()); ++ EVP_DigestUpdate(&md, in, len); ++ EVP_DigestFinal(&md, out, NULL); ++ EVP_MD_CTX_cleanup(&md); /* new function call */ ++ ++ [Ben Laurie] ++ ++ *) Make DES key schedule conform to the usual scheme, as well as ++ correcting its structure. This means that calls to DES functions ++ now have to pass a pointer to a des_key_schedule instead of a ++ plain des_key_schedule (which was actually always a pointer ++ anyway): E.g., ++ ++ des_key_schedule ks; ++ ++ des_set_key_checked(..., &ks); ++ des_ncbc_encrypt(..., &ks, ...); ++ ++ (Note that a later change renames 'des_...' into 'DES_...'.) ++ [Ben Laurie] ++ ++ *) Initial reduction of linker bloat: the use of some functions, such as ++ PEM causes large amounts of unused functions to be linked in due to ++ poor organisation. For example pem_all.c contains every PEM function ++ which has a knock on effect of linking in large amounts of (unused) ++ ASN1 code. Grouping together similar functions and splitting unrelated ++ functions prevents this. ++ [Steve Henson] ++ ++ *) Cleanup of EVP macros. ++ [Ben Laurie] ++ ++ *) Change historical references to {NID,SN,LN}_des_ede and ede3 to add the ++ correct _ecb suffix. ++ [Ben Laurie] ++ ++ *) Add initial OCSP responder support to ocsp application. The ++ revocation information is handled using the text based index ++ use by the ca application. The responder can either handle ++ requests generated internally, supplied in files (for example ++ via a CGI script) or using an internal minimal server. ++ [Steve Henson] ++ ++ *) Add configuration choices to get zlib compression for TLS. ++ [Richard Levitte] ++ ++ *) Changes to Kerberos SSL for RFC 2712 compliance: ++ 1. Implemented real KerberosWrapper, instead of just using ++ KRB5 AP_REQ message. [Thanks to Simon Wilkinson ] ++ 2. Implemented optional authenticator field of KerberosWrapper. ++ ++ Added openssl-style ASN.1 macros for Kerberos ticket, ap_req, ++ and authenticator structs; see crypto/krb5/. ++ ++ Generalized Kerberos calls to support multiple Kerberos libraries. ++ [Vern Staats , ++ Jeffrey Altman ++ via Richard Levitte] ++ ++ *) Cause 'openssl speed' to use fully hard-coded DSA keys as it ++ already does with RSA. testdsa.h now has 'priv_key/pub_key' ++ values for each of the key sizes rather than having just ++ parameters (and 'speed' generating keys each time). ++ [Geoff Thorpe] ++ ++ *) Speed up EVP routines. ++ Before: ++encrypt ++type 8 bytes 64 bytes 256 bytes 1024 bytes 8192 bytes ++des-cbc 4408.85k 5560.51k 5778.46k 5862.20k 5825.16k ++des-cbc 4389.55k 5571.17k 5792.23k 5846.91k 5832.11k ++des-cbc 4394.32k 5575.92k 5807.44k 5848.37k 5841.30k ++decrypt ++des-cbc 3482.66k 5069.49k 5496.39k 5614.16k 5639.28k ++des-cbc 3480.74k 5068.76k 5510.34k 5609.87k 5635.52k ++des-cbc 3483.72k 5067.62k 5504.60k 5708.01k 5724.80k ++ After: ++encrypt ++des-cbc 4660.16k 5650.19k 5807.19k 5827.13k 5783.32k ++decrypt ++des-cbc 3624.96k 5258.21k 5530.91k 5624.30k 5628.26k ++ [Ben Laurie] ++ ++ *) Added the OS2-EMX target. ++ ["Brian Havard" and Richard Levitte] ++ ++ *) Rewrite apps to use NCONF routines instead of the old CONF. New functions ++ to support NCONF routines in extension code. New function CONF_set_nconf() ++ to allow functions which take an NCONF to also handle the old LHASH ++ structure: this means that the old CONF compatible routines can be ++ retained (in particular wrt extensions) without having to duplicate the ++ code. New function X509V3_add_ext_nconf_sk to add extensions to a stack. ++ [Steve Henson] ++ ++ *) Enhance the general user interface with mechanisms for inner control ++ and with possibilities to have yes/no kind of prompts. ++ [Richard Levitte] ++ ++ *) Change all calls to low level digest routines in the library and ++ applications to use EVP. Add missing calls to HMAC_cleanup() and ++ don't assume HMAC_CTX can be copied using memcpy(). ++ [Verdon Walker , Steve Henson] ++ ++ *) Add the possibility to control engines through control names but with ++ arbitrary arguments instead of just a string. ++ Change the key loaders to take a UI_METHOD instead of a callback ++ function pointer. NOTE: this breaks binary compatibility with earlier ++ versions of OpenSSL [engine]. ++ Adapt the nCipher code for these new conditions and add a card insertion ++ callback. ++ [Richard Levitte] ++ ++ *) Enhance the general user interface with mechanisms to better support ++ dialog box interfaces, application-defined prompts, the possibility ++ to use defaults (for example default passwords from somewhere else) ++ and interrupts/cancellations. ++ [Richard Levitte] ++ ++ *) Tidy up PKCS#12 attribute handling. Add support for the CSP name ++ attribute in PKCS#12 files, add new -CSP option to pkcs12 utility. ++ [Steve Henson] ++ ++ *) Fix a memory leak in 'sk_dup()' in the case reallocation fails. (Also ++ tidy up some unnecessarily weird code in 'sk_new()'). ++ [Geoff, reported by Diego Tartara ] ++ ++ *) Change the key loading routines for ENGINEs to use the same kind ++ callback (pem_password_cb) as all other routines that need this ++ kind of callback. ++ [Richard Levitte] ++ ++ *) Increase ENTROPY_NEEDED to 32 bytes, as Rijndael can operate with ++ 256 bit (=32 byte) keys. Of course seeding with more entropy bytes ++ than this minimum value is recommended. ++ [Lutz Jaenicke] ++ ++ *) New random seeder for OpenVMS, using the system process statistics ++ that are easily reachable. ++ [Richard Levitte] ++ ++ *) Windows apparently can't transparently handle global ++ variables defined in DLLs. Initialisations such as: ++ ++ const ASN1_ITEM *it = &ASN1_INTEGER_it; ++ ++ won't compile. This is used by the any applications that need to ++ declare their own ASN1 modules. This was fixed by adding the option ++ EXPORT_VAR_AS_FN to all Win32 platforms, although this isn't strictly ++ needed for static libraries under Win32. ++ [Steve Henson] ++ ++ *) New functions X509_PURPOSE_set() and X509_TRUST_set() to handle ++ setting of purpose and trust fields. New X509_STORE trust and ++ purpose functions and tidy up setting in other SSL functions. ++ [Steve Henson] ++ ++ *) Add copies of X509_STORE_CTX fields and callbacks to X509_STORE ++ structure. These are inherited by X509_STORE_CTX when it is ++ initialised. This allows various defaults to be set in the ++ X509_STORE structure (such as flags for CRL checking and custom ++ purpose or trust settings) for functions which only use X509_STORE_CTX ++ internally such as S/MIME. ++ ++ Modify X509_STORE_CTX_purpose_inherit() so it only sets purposes and ++ trust settings if they are not set in X509_STORE. This allows X509_STORE ++ purposes and trust (in S/MIME for example) to override any set by default. ++ ++ Add command line options for CRL checking to smime, s_client and s_server ++ applications. ++ [Steve Henson] ++ ++ *) Initial CRL based revocation checking. If the CRL checking flag(s) ++ are set then the CRL is looked up in the X509_STORE structure and ++ its validity and signature checked, then if the certificate is found ++ in the CRL the verify fails with a revoked error. ++ ++ Various new CRL related callbacks added to X509_STORE_CTX structure. ++ ++ Command line options added to 'verify' application to support this. ++ ++ This needs some additional work, such as being able to handle multiple ++ CRLs with different times, extension based lookup (rather than just ++ by subject name) and ultimately more complete V2 CRL extension ++ handling. ++ [Steve Henson] ++ ++ *) Add a general user interface API (crypto/ui/). This is designed ++ to replace things like des_read_password and friends (backward ++ compatibility functions using this new API are provided). ++ The purpose is to remove prompting functions from the DES code ++ section as well as provide for prompting through dialog boxes in ++ a window system and the like. ++ [Richard Levitte] ++ ++ *) Add "ex_data" support to ENGINE so implementations can add state at a ++ per-structure level rather than having to store it globally. ++ [Geoff] ++ ++ *) Make it possible for ENGINE structures to be copied when retrieved by ++ ENGINE_by_id() if the ENGINE specifies a new flag: ENGINE_FLAGS_BY_ID_COPY. ++ This causes the "original" ENGINE structure to act like a template, ++ analogous to the RSA vs. RSA_METHOD type of separation. Because of this ++ operational state can be localised to each ENGINE structure, despite the ++ fact they all share the same "methods". New ENGINE structures returned in ++ this case have no functional references and the return value is the single ++ structural reference. This matches the single structural reference returned ++ by ENGINE_by_id() normally, when it is incremented on the pre-existing ++ ENGINE structure. ++ [Geoff] ++ ++ *) Fix ASN1 decoder when decoding type ANY and V_ASN1_OTHER: since this ++ needs to match any other type at all we need to manually clear the ++ tag cache. ++ [Steve Henson] ++ ++ *) Changes to the "openssl engine" utility to include; ++ - verbosity levels ('-v', '-vv', and '-vvv') that provide information ++ about an ENGINE's available control commands. ++ - executing control commands from command line arguments using the ++ '-pre' and '-post' switches. '-post' is only used if '-t' is ++ specified and the ENGINE is successfully initialised. The syntax for ++ the individual commands are colon-separated, for example; ++ openssl engine chil -pre FORK_CHECK:0 -pre SO_PATH:/lib/test.so ++ [Geoff] ++ ++ *) New dynamic control command support for ENGINEs. ENGINEs can now ++ declare their own commands (numbers), names (strings), descriptions, ++ and input types for run-time discovery by calling applications. A ++ subset of these commands are implicitly classed as "executable" ++ depending on their input type, and only these can be invoked through ++ the new string-based API function ENGINE_ctrl_cmd_string(). (Eg. this ++ can be based on user input, config files, etc). The distinction is ++ that "executable" commands cannot return anything other than a boolean ++ result and can only support numeric or string input, whereas some ++ discoverable commands may only be for direct use through ++ ENGINE_ctrl(), eg. supporting the exchange of binary data, function ++ pointers, or other custom uses. The "executable" commands are to ++ support parameterisations of ENGINE behaviour that can be ++ unambiguously defined by ENGINEs and used consistently across any ++ OpenSSL-based application. Commands have been added to all the ++ existing hardware-supporting ENGINEs, noticeably "SO_PATH" to allow ++ control over shared-library paths without source code alterations. ++ [Geoff] ++ ++ *) Changed all ENGINE implementations to dynamically allocate their ++ ENGINEs rather than declaring them statically. Apart from this being ++ necessary with the removal of the ENGINE_FLAGS_MALLOCED distinction, ++ this also allows the implementations to compile without using the ++ internal engine_int.h header. ++ [Geoff] ++ ++ *) Minor adjustment to "rand" code. RAND_get_rand_method() now returns a ++ 'const' value. Any code that should be able to modify a RAND_METHOD ++ should already have non-const pointers to it (ie. they should only ++ modify their own ones). ++ [Geoff] ++ ++ *) Made a variety of little tweaks to the ENGINE code. ++ - "atalla" and "ubsec" string definitions were moved from header files ++ to C code. "nuron" string definitions were placed in variables ++ rather than hard-coded - allowing parameterisation of these values ++ later on via ctrl() commands. ++ - Removed unused "#if 0"'d code. ++ - Fixed engine list iteration code so it uses ENGINE_free() to release ++ structural references. ++ - Constified the RAND_METHOD element of ENGINE structures. ++ - Constified various get/set functions as appropriate and added ++ missing functions (including a catch-all ENGINE_cpy that duplicates ++ all ENGINE values onto a new ENGINE except reference counts/state). ++ - Removed NULL parameter checks in get/set functions. Setting a method ++ or function to NULL is a way of cancelling out a previously set ++ value. Passing a NULL ENGINE parameter is just plain stupid anyway ++ and doesn't justify the extra error symbols and code. ++ - Deprecate the ENGINE_FLAGS_MALLOCED define and move the area for ++ flags from engine_int.h to engine.h. ++ - Changed prototypes for ENGINE handler functions (init(), finish(), ++ ctrl(), key-load functions, etc) to take an (ENGINE*) parameter. ++ [Geoff] ++ ++ *) Implement binary inversion algorithm for BN_mod_inverse in addition ++ to the algorithm using long division. The binary algorithm can be ++ used only if the modulus is odd. On 32-bit systems, it is faster ++ only for relatively small moduli (roughly 20-30% for 128-bit moduli, ++ roughly 5-15% for 256-bit moduli), so we use it only for moduli ++ up to 450 bits. In 64-bit environments, the binary algorithm ++ appears to be advantageous for much longer moduli; here we use it ++ for moduli up to 2048 bits. ++ [Bodo Moeller] ++ ++ *) Rewrite CHOICE field setting in ASN1_item_ex_d2i(). The old code ++ could not support the combine flag in choice fields. ++ [Steve Henson] ++ ++ *) Add a 'copy_extensions' option to the 'ca' utility. This copies ++ extensions from a certificate request to the certificate. ++ [Steve Henson] ++ ++ *) Allow multiple 'certopt' and 'nameopt' options to be separated ++ by commas. Add 'namopt' and 'certopt' options to the 'ca' config ++ file: this allows the display of the certificate about to be ++ signed to be customised, to allow certain fields to be included ++ or excluded and extension details. The old system didn't display ++ multicharacter strings properly, omitted fields not in the policy ++ and couldn't display additional details such as extensions. ++ [Steve Henson] ++ ++ *) Function EC_POINTs_mul for multiple scalar multiplication ++ of an arbitrary number of elliptic curve points ++ \sum scalars[i]*points[i], ++ optionally including the generator defined for the EC_GROUP: ++ scalar*generator + \sum scalars[i]*points[i]. ++ ++ EC_POINT_mul is a simple wrapper function for the typical case ++ that the point list has just one item (besides the optional ++ generator). ++ [Bodo Moeller] ++ ++ *) First EC_METHODs for curves over GF(p): ++ ++ EC_GFp_simple_method() uses the basic BN_mod_mul and BN_mod_sqr ++ operations and provides various method functions that can also ++ operate with faster implementations of modular arithmetic. ++ ++ EC_GFp_mont_method() reuses most functions that are part of ++ EC_GFp_simple_method, but uses Montgomery arithmetic. ++ ++ [Bodo Moeller; point addition and point doubling ++ implementation directly derived from source code provided by ++ Lenka Fibikova ] ++ ++ *) Framework for elliptic curves (crypto/ec/ec.h, crypto/ec/ec_lcl.h, ++ crypto/ec/ec_lib.c): ++ ++ Curves are EC_GROUP objects (with an optional group generator) ++ based on EC_METHODs that are built into the library. ++ ++ Points are EC_POINT objects based on EC_GROUP objects. ++ ++ Most of the framework would be able to handle curves over arbitrary ++ finite fields, but as there are no obvious types for fields other ++ than GF(p), some functions are limited to that for now. ++ [Bodo Moeller] ++ ++ *) Add the -HTTP option to s_server. It is similar to -WWW, but requires ++ that the file contains a complete HTTP response. ++ [Richard Levitte] ++ ++ *) Add the ec directory to mkdef.pl and mkfiles.pl. In mkdef.pl ++ change the def and num file printf format specifier from "%-40sXXX" ++ to "%-39s XXX". The latter will always guarantee a space after the ++ field while the former will cause them to run together if the field ++ is 40 of more characters long. ++ [Steve Henson] ++ ++ *) Constify the cipher and digest 'method' functions and structures ++ and modify related functions to take constant EVP_MD and EVP_CIPHER ++ pointers. ++ [Steve Henson] ++ ++ *) Hide BN_CTX structure details in bn_lcl.h instead of publishing them ++ in . Also further increase BN_CTX_NUM to 32. ++ [Bodo Moeller] ++ ++ *) Modify EVP_Digest*() routines so they now return values. Although the ++ internal software routines can never fail additional hardware versions ++ might. ++ [Steve Henson] ++ ++ *) Clean up crypto/err/err.h and change some error codes to avoid conflicts: ++ ++ Previously ERR_R_FATAL was too small and coincided with ERR_LIB_PKCS7 ++ (= ERR_R_PKCS7_LIB); it is now 64 instead of 32. ++ ++ ASN1 error codes ++ ERR_R_NESTED_ASN1_ERROR ++ ... ++ ERR_R_MISSING_ASN1_EOS ++ were 4 .. 9, conflicting with ++ ERR_LIB_RSA (= ERR_R_RSA_LIB) ++ ... ++ ERR_LIB_PEM (= ERR_R_PEM_LIB). ++ They are now 58 .. 63 (i.e., just below ERR_R_FATAL). ++ ++ Add new error code 'ERR_R_INTERNAL_ERROR'. ++ [Bodo Moeller] ++ ++ *) Don't overuse locks in crypto/err/err.c: For data retrieval, CRYPTO_r_lock ++ suffices. ++ [Bodo Moeller] ++ ++ *) New option '-subj arg' for 'openssl req' and 'openssl ca'. This ++ sets the subject name for a new request or supersedes the ++ subject name in a given request. Formats that can be parsed are ++ 'CN=Some Name, OU=myOU, C=IT' ++ and ++ 'CN=Some Name/OU=myOU/C=IT'. ++ ++ Add options '-batch' and '-verbose' to 'openssl req'. ++ [Massimiliano Pala ] ++ ++ *) Introduce the possibility to access global variables through ++ functions on platform were that's the best way to handle exporting ++ global variables in shared libraries. To enable this functionality, ++ one must configure with "EXPORT_VAR_AS_FN" or defined the C macro ++ "OPENSSL_EXPORT_VAR_AS_FUNCTION" in crypto/opensslconf.h (the latter ++ is normally done by Configure or something similar). ++ ++ To implement a global variable, use the macro OPENSSL_IMPLEMENT_GLOBAL ++ in the source file (foo.c) like this: ++ ++ OPENSSL_IMPLEMENT_GLOBAL(int,foo)=1; ++ OPENSSL_IMPLEMENT_GLOBAL(double,bar); ++ ++ To declare a global variable, use the macros OPENSSL_DECLARE_GLOBAL ++ and OPENSSL_GLOBAL_REF in the header file (foo.h) like this: ++ ++ OPENSSL_DECLARE_GLOBAL(int,foo); ++ #define foo OPENSSL_GLOBAL_REF(foo) ++ OPENSSL_DECLARE_GLOBAL(double,bar); ++ #define bar OPENSSL_GLOBAL_REF(bar) ++ ++ The #defines are very important, and therefore so is including the ++ header file everywhere where the defined globals are used. ++ ++ The macro OPENSSL_EXPORT_VAR_AS_FUNCTION also affects the definition ++ of ASN.1 items, but that structure is a bit different. ++ ++ The largest change is in util/mkdef.pl which has been enhanced with ++ better and easier to understand logic to choose which symbols should ++ go into the Windows .def files as well as a number of fixes and code ++ cleanup (among others, algorithm keywords are now sorted ++ lexicographically to avoid constant rewrites). ++ [Richard Levitte] ++ ++ *) In BN_div() keep a copy of the sign of 'num' before writing the ++ result to 'rm' because if rm==num the value will be overwritten ++ and produce the wrong result if 'num' is negative: this caused ++ problems with BN_mod() and BN_nnmod(). ++ [Steve Henson] ++ ++ *) Function OCSP_request_verify(). This checks the signature on an ++ OCSP request and verifies the signer certificate. The signer ++ certificate is just checked for a generic purpose and OCSP request ++ trust settings. ++ [Steve Henson] ++ ++ *) Add OCSP_check_validity() function to check the validity of OCSP ++ responses. OCSP responses are prepared in real time and may only ++ be a few seconds old. Simply checking that the current time lies ++ between thisUpdate and nextUpdate max reject otherwise valid responses ++ caused by either OCSP responder or client clock inaccuracy. Instead ++ we allow thisUpdate and nextUpdate to fall within a certain period of ++ the current time. The age of the response can also optionally be ++ checked. Two new options -validity_period and -status_age added to ++ ocsp utility. ++ [Steve Henson] ++ ++ *) If signature or public key algorithm is unrecognized print out its ++ OID rather that just UNKNOWN. ++ [Steve Henson] ++ ++ *) Change OCSP_cert_to_id() to tolerate a NULL subject certificate and ++ OCSP_cert_id_new() a NULL serialNumber. This allows a partial certificate ++ ID to be generated from the issuer certificate alone which can then be ++ passed to OCSP_id_issuer_cmp(). ++ [Steve Henson] ++ ++ *) New compilation option ASN1_ITEM_FUNCTIONS. This causes the new ++ ASN1 modules to export functions returning ASN1_ITEM pointers ++ instead of the ASN1_ITEM structures themselves. This adds several ++ new macros which allow the underlying ASN1 function/structure to ++ be accessed transparently. As a result code should not use ASN1_ITEM ++ references directly (such as &X509_it) but instead use the relevant ++ macros (such as ASN1_ITEM_rptr(X509)). This option is to allow ++ use of the new ASN1 code on platforms where exporting structures ++ is problematical (for example in shared libraries) but exporting ++ functions returning pointers to structures is not. ++ [Steve Henson] ++ ++ *) Add support for overriding the generation of SSL/TLS session IDs. ++ These callbacks can be registered either in an SSL_CTX or per SSL. ++ The purpose of this is to allow applications to control, if they wish, ++ the arbitrary values chosen for use as session IDs, particularly as it ++ can be useful for session caching in multiple-server environments. A ++ command-line switch for testing this (and any client code that wishes ++ to use such a feature) has been added to "s_server". ++ [Geoff Thorpe, Lutz Jaenicke] ++ ++ *) Modify mkdef.pl to recognise and parse preprocessor conditionals ++ of the form '#if defined(...) || defined(...) || ...' and ++ '#if !defined(...) && !defined(...) && ...'. This also avoids ++ the growing number of special cases it was previously handling. ++ [Richard Levitte] ++ ++ *) Make all configuration macros available for application by making ++ sure they are available in opensslconf.h, by giving them names starting ++ with "OPENSSL_" to avoid conflicts with other packages and by making ++ sure e_os2.h will cover all platform-specific cases together with ++ opensslconf.h. ++ Additionally, it is now possible to define configuration/platform- ++ specific names (called "system identities"). In the C code, these ++ are prefixed with "OPENSSL_SYSNAME_". e_os2.h will create another ++ macro with the name beginning with "OPENSSL_SYS_", which is determined ++ from "OPENSSL_SYSNAME_*" or compiler-specific macros depending on ++ what is available. ++ [Richard Levitte] ++ ++ *) New option -set_serial to 'req' and 'x509' this allows the serial ++ number to use to be specified on the command line. Previously self ++ signed certificates were hard coded with serial number 0 and the ++ CA options of 'x509' had to use a serial number in a file which was ++ auto incremented. ++ [Steve Henson] ++ ++ *) New options to 'ca' utility to support V2 CRL entry extensions. ++ Currently CRL reason, invalidity date and hold instruction are ++ supported. Add new CRL extensions to V3 code and some new objects. ++ [Steve Henson] ++ ++ *) New function EVP_CIPHER_CTX_set_padding() this is used to ++ disable standard block padding (aka PKCS#5 padding) in the EVP ++ API, which was previously mandatory. This means that the data is ++ not padded in any way and so the total length much be a multiple ++ of the block size, otherwise an error occurs. ++ [Steve Henson] ++ ++ *) Initial (incomplete) OCSP SSL support. ++ [Steve Henson] ++ ++ *) New function OCSP_parse_url(). This splits up a URL into its host, ++ port and path components: primarily to parse OCSP URLs. New -url ++ option to ocsp utility. ++ [Steve Henson] ++ ++ *) New nonce behavior. The return value of OCSP_check_nonce() now ++ reflects the various checks performed. Applications can decide ++ whether to tolerate certain situations such as an absent nonce ++ in a response when one was present in a request: the ocsp application ++ just prints out a warning. New function OCSP_add1_basic_nonce() ++ this is to allow responders to include a nonce in a response even if ++ the request is nonce-less. ++ [Steve Henson] ++ ++ *) Disable stdin buffering in load_cert (apps/apps.c) so that no certs are ++ skipped when using openssl x509 multiple times on a single input file, ++ e.g. "(openssl x509 -out cert1; openssl x509 -out cert2) ] ++ ++ *) New OCSP verify flag OCSP_TRUSTOTHER. When set the "other" certificates ++ passed by the function are trusted implicitly. If any of them signed the ++ response then it is assumed to be valid and is not verified. ++ [Steve Henson] ++ ++ *) In PKCS7_set_type() initialise content_type in PKCS7_ENC_CONTENT ++ to data. This was previously part of the PKCS7 ASN1 code. This ++ was causing problems with OpenSSL created PKCS#12 and PKCS#7 structures. ++ [Steve Henson, reported by Kenneth R. Robinette ++ ] ++ ++ *) Add CRYPTO_push_info() and CRYPTO_pop_info() calls to new ASN1 ++ routines: without these tracing memory leaks is very painful. ++ Fix leaks in PKCS12 and PKCS7 routines. ++ [Steve Henson] ++ ++ *) Make X509_time_adj() cope with the new behaviour of ASN1_TIME_new(). ++ Previously it initialised the 'type' argument to V_ASN1_UTCTIME which ++ effectively meant GeneralizedTime would never be used. Now it ++ is initialised to -1 but X509_time_adj() now has to check the value ++ and use ASN1_TIME_set() if the value is not V_ASN1_UTCTIME or ++ V_ASN1_GENERALIZEDTIME, without this it always uses GeneralizedTime. ++ [Steve Henson, reported by Kenneth R. Robinette ++ ] ++ ++ *) Fixes to BN_to_ASN1_INTEGER when bn is zero. This would previously ++ result in a zero length in the ASN1_INTEGER structure which was ++ not consistent with the structure when d2i_ASN1_INTEGER() was used ++ and would cause ASN1_INTEGER_cmp() to fail. Enhance s2i_ASN1_INTEGER() ++ to cope with hex and negative integers. Fix bug in i2a_ASN1_INTEGER() ++ where it did not print out a minus for negative ASN1_INTEGER. ++ [Steve Henson] ++ ++ *) Add summary printout to ocsp utility. The various functions which ++ convert status values to strings have been renamed to: ++ OCSP_response_status_str(), OCSP_cert_status_str() and ++ OCSP_crl_reason_str() and are no longer static. New options ++ to verify nonce values and to disable verification. OCSP response ++ printout format cleaned up. ++ [Steve Henson] ++ ++ *) Add additional OCSP certificate checks. These are those specified ++ in RFC2560. This consists of two separate checks: the CA of the ++ certificate being checked must either be the OCSP signer certificate ++ or the issuer of the OCSP signer certificate. In the latter case the ++ OCSP signer certificate must contain the OCSP signing extended key ++ usage. This check is performed by attempting to match the OCSP ++ signer or the OCSP signer CA to the issuerNameHash and issuerKeyHash ++ in the OCSP_CERTID structures of the response. ++ [Steve Henson] ++ ++ *) Initial OCSP certificate verification added to OCSP_basic_verify() ++ and related routines. This uses the standard OpenSSL certificate ++ verify routines to perform initial checks (just CA validity) and ++ to obtain the certificate chain. Then additional checks will be ++ performed on the chain. Currently the root CA is checked to see ++ if it is explicitly trusted for OCSP signing. This is used to set ++ a root CA as a global signing root: that is any certificate that ++ chains to that CA is an acceptable OCSP signing certificate. ++ [Steve Henson] ++ ++ *) New '-extfile ...' option to 'openssl ca' for reading X.509v3 ++ extensions from a separate configuration file. ++ As when reading extensions from the main configuration file, ++ the '-extensions ...' option may be used for specifying the ++ section to use. ++ [Massimiliano Pala ] ++ ++ *) New OCSP utility. Allows OCSP requests to be generated or ++ read. The request can be sent to a responder and the output ++ parsed, outputed or printed in text form. Not complete yet: ++ still needs to check the OCSP response validity. ++ [Steve Henson] ++ ++ *) New subcommands for 'openssl ca': ++ 'openssl ca -status ' prints the status of the cert with ++ the given serial number (according to the index file). ++ 'openssl ca -updatedb' updates the expiry status of certificates ++ in the index file. ++ [Massimiliano Pala ] ++ ++ *) New '-newreq-nodes' command option to CA.pl. This is like ++ '-newreq', but calls 'openssl req' with the '-nodes' option ++ so that the resulting key is not encrypted. ++ [Damien Miller ] ++ ++ *) New configuration for the GNU Hurd. ++ [Jonathan Bartlett via Richard Levitte] ++ ++ *) Initial code to implement OCSP basic response verify. This ++ is currently incomplete. Currently just finds the signer's ++ certificate and verifies the signature on the response. ++ [Steve Henson] ++ ++ *) New SSLeay_version code SSLEAY_DIR to determine the compiled-in ++ value of OPENSSLDIR. This is available via the new '-d' option ++ to 'openssl version', and is also included in 'openssl version -a'. ++ [Bodo Moeller] ++ ++ *) Allowing defining memory allocation callbacks that will be given ++ file name and line number information in additional arguments ++ (a const char* and an int). The basic functionality remains, as ++ well as the original possibility to just replace malloc(), ++ realloc() and free() by functions that do not know about these ++ additional arguments. To register and find out the current ++ settings for extended allocation functions, the following ++ functions are provided: ++ ++ CRYPTO_set_mem_ex_functions ++ CRYPTO_set_locked_mem_ex_functions ++ CRYPTO_get_mem_ex_functions ++ CRYPTO_get_locked_mem_ex_functions ++ ++ These work the same way as CRYPTO_set_mem_functions and friends. ++ CRYPTO_get_[locked_]mem_functions now writes 0 where such an ++ extended allocation function is enabled. ++ Similarly, CRYPTO_get_[locked_]mem_ex_functions writes 0 where ++ a conventional allocation function is enabled. ++ [Richard Levitte, Bodo Moeller] ++ ++ *) Finish off removing the remaining LHASH function pointer casts. ++ There should no longer be any prototype-casting required when using ++ the LHASH abstraction, and any casts that remain are "bugs". See ++ the callback types and macros at the head of lhash.h for details ++ (and "OBJ_cleanup" in crypto/objects/obj_dat.c as an example). ++ [Geoff Thorpe] ++ ++ *) Add automatic query of EGD sockets in RAND_poll() for the unix variant. ++ If /dev/[u]random devices are not available or do not return enough ++ entropy, EGD style sockets (served by EGD or PRNGD) will automatically ++ be queried. ++ The locations /var/run/egd-pool, /dev/egd-pool, /etc/egd-pool, and ++ /etc/entropy will be queried once each in this sequence, querying stops ++ when enough entropy was collected without querying more sockets. ++ [Lutz Jaenicke] ++ ++ *) Change the Unix RAND_poll() variant to be able to poll several ++ random devices, as specified by DEVRANDOM, until a sufficient amount ++ of data has been collected. We spend at most 10 ms on each file ++ (select timeout) and read in non-blocking mode. DEVRANDOM now ++ defaults to the list "/dev/urandom", "/dev/random", "/dev/srandom" ++ (previously it was just the string "/dev/urandom"), so on typical ++ platforms the 10 ms delay will never occur. ++ Also separate out the Unix variant to its own file, rand_unix.c. ++ For VMS, there's a currently-empty rand_vms.c. ++ [Richard Levitte] ++ ++ *) Move OCSP client related routines to ocsp_cl.c. These ++ provide utility functions which an application needing ++ to issue a request to an OCSP responder and analyse the ++ response will typically need: as opposed to those which an ++ OCSP responder itself would need which will be added later. ++ ++ OCSP_request_sign() signs an OCSP request with an API similar ++ to PKCS7_sign(). OCSP_response_status() returns status of OCSP ++ response. OCSP_response_get1_basic() extracts basic response ++ from response. OCSP_resp_find_status(): finds and extracts status ++ information from an OCSP_CERTID structure (which will be created ++ when the request structure is built). These are built from lower ++ level functions which work on OCSP_SINGLERESP structures but ++ won't normally be used unless the application wishes to examine ++ extensions in the OCSP response for example. ++ ++ Replace nonce routines with a pair of functions. ++ OCSP_request_add1_nonce() adds a nonce value and optionally ++ generates a random value. OCSP_check_nonce() checks the ++ validity of the nonce in an OCSP response. ++ [Steve Henson] ++ ++ *) Change function OCSP_request_add() to OCSP_request_add0_id(). ++ This doesn't copy the supplied OCSP_CERTID and avoids the ++ need to free up the newly created id. Change return type ++ to OCSP_ONEREQ to return the internal OCSP_ONEREQ structure. ++ This can then be used to add extensions to the request. ++ Deleted OCSP_request_new(), since most of its functionality ++ is now in OCSP_REQUEST_new() (and the case insensitive name ++ clash) apart from the ability to set the request name which ++ will be added elsewhere. ++ [Steve Henson] ++ ++ *) Update OCSP API. Remove obsolete extensions argument from ++ various functions. Extensions are now handled using the new ++ OCSP extension code. New simple OCSP HTTP function which ++ can be used to send requests and parse the response. ++ [Steve Henson] ++ ++ *) Fix the PKCS#7 (S/MIME) code to work with new ASN1. Two new ++ ASN1_ITEM structures help with sign and verify. PKCS7_ATTR_SIGN ++ uses the special reorder version of SET OF to sort the attributes ++ and reorder them to match the encoded order. This resolves a long ++ standing problem: a verify on a PKCS7 structure just after signing ++ it used to fail because the attribute order did not match the ++ encoded order. PKCS7_ATTR_VERIFY does not reorder the attributes: ++ it uses the received order. This is necessary to tolerate some broken ++ software that does not order SET OF. This is handled by encoding ++ as a SEQUENCE OF but using implicit tagging (with UNIVERSAL class) ++ to produce the required SET OF. ++ [Steve Henson] ++ ++ *) Have mk1mf.pl generate the macros OPENSSL_BUILD_SHLIBCRYPTO and ++ OPENSSL_BUILD_SHLIBSSL and use them appropriately in the header ++ files to get correct declarations of the ASN.1 item variables. ++ [Richard Levitte] ++ ++ *) Rewrite of PKCS#12 code to use new ASN1 functionality. Replace many ++ PKCS#12 macros with real functions. Fix two unrelated ASN1 bugs: ++ asn1_check_tlen() would sometimes attempt to use 'ctx' when it was ++ NULL and ASN1_TYPE was not dereferenced properly in asn1_ex_c2i(). ++ New ASN1 macro: DECLARE_ASN1_ITEM() which just declares the relevant ++ ASN1_ITEM and no wrapper functions. ++ [Steve Henson] ++ ++ *) New functions or ASN1_item_d2i_fp() and ASN1_item_d2i_bio(). These ++ replace the old function pointer based I/O routines. Change most of ++ the *_d2i_bio() and *_d2i_fp() functions to use these. ++ [Steve Henson] ++ ++ *) Enhance mkdef.pl to be more accepting about spacing in C preprocessor ++ lines, recognice more "algorithms" that can be deselected, and make ++ it complain about algorithm deselection that isn't recognised. ++ [Richard Levitte] ++ ++ *) New ASN1 functions to handle dup, sign, verify, digest, pack and ++ unpack operations in terms of ASN1_ITEM. Modify existing wrappers ++ to use new functions. Add NO_ASN1_OLD which can be set to remove ++ some old style ASN1 functions: this can be used to determine if old ++ code will still work when these eventually go away. ++ [Steve Henson] ++ ++ *) New extension functions for OCSP structures, these follow the ++ same conventions as certificates and CRLs. ++ [Steve Henson] ++ ++ *) New function X509V3_add1_i2d(). This automatically encodes and ++ adds an extension. Its behaviour can be customised with various ++ flags to append, replace or delete. Various wrappers added for ++ certificates and CRLs. ++ [Steve Henson] ++ ++ *) Fix to avoid calling the underlying ASN1 print routine when ++ an extension cannot be parsed. Correct a typo in the ++ OCSP_SERVICELOC extension. Tidy up print OCSP format. ++ [Steve Henson] ++ ++ *) Make mkdef.pl parse some of the ASN1 macros and add appropriate ++ entries for variables. ++ [Steve Henson] ++ ++ *) Add functionality to apps/openssl.c for detecting locking ++ problems: As the program is single-threaded, all we have ++ to do is register a locking callback using an array for ++ storing which locks are currently held by the program. ++ [Bodo Moeller] ++ ++ *) Use a lock around the call to CRYPTO_get_ex_new_index() in ++ SSL_get_ex_data_X509_STORE_idx(), which is used in ++ ssl_verify_cert_chain() and thus can be called at any time ++ during TLS/SSL handshakes so that thread-safety is essential. ++ Unfortunately, the ex_data design is not at all suited ++ for multi-threaded use, so it probably should be abolished. ++ [Bodo Moeller] ++ ++ *) Added Broadcom "ubsec" ENGINE to OpenSSL. ++ [Broadcom, tweaked and integrated by Geoff Thorpe] ++ ++ *) Move common extension printing code to new function ++ X509V3_print_extensions(). Reorganise OCSP print routines and ++ implement some needed OCSP ASN1 functions. Add OCSP extensions. ++ [Steve Henson] ++ ++ *) New function X509_signature_print() to remove duplication in some ++ print routines. ++ [Steve Henson] ++ ++ *) Add a special meaning when SET OF and SEQUENCE OF flags are both ++ set (this was treated exactly the same as SET OF previously). This ++ is used to reorder the STACK representing the structure to match the ++ encoding. This will be used to get round a problem where a PKCS7 ++ structure which was signed could not be verified because the STACK ++ order did not reflect the encoded order. ++ [Steve Henson] ++ ++ *) Reimplement the OCSP ASN1 module using the new code. ++ [Steve Henson] ++ ++ *) Update the X509V3 code to permit the use of an ASN1_ITEM structure ++ for its ASN1 operations. The old style function pointers still exist ++ for now but they will eventually go away. ++ [Steve Henson] ++ ++ *) Merge in replacement ASN1 code from the ASN1 branch. This almost ++ completely replaces the old ASN1 functionality with a table driven ++ encoder and decoder which interprets an ASN1_ITEM structure describing ++ the ASN1 module. Compatibility with the existing ASN1 API (i2d,d2i) is ++ largely maintained. Almost all of the old asn1_mac.h macro based ASN1 ++ has also been converted to the new form. ++ [Steve Henson] ++ ++ *) Change BN_mod_exp_recp so that negative moduli are tolerated ++ (the sign is ignored). Similarly, ignore the sign in BN_MONT_CTX_set ++ so that BN_mod_exp_mont and BN_mod_exp_mont_word work ++ for negative moduli. ++ [Bodo Moeller] ++ ++ *) Fix BN_uadd and BN_usub: Always return non-negative results instead ++ of not touching the result's sign bit. ++ [Bodo Moeller] ++ ++ *) BN_div bugfix: If the result is 0, the sign (res->neg) must not be ++ set. ++ [Bodo Moeller] ++ ++ *) Changed the LHASH code to use prototypes for callbacks, and created ++ macros to declare and implement thin (optionally static) functions ++ that provide type-safety and avoid function pointer casting for the ++ type-specific callbacks. ++ [Geoff Thorpe] ++ ++ *) Added Kerberos Cipher Suites to be used with TLS, as written in ++ RFC 2712. ++ [Veers Staats , ++ Jeffrey Altman , via Richard Levitte] ++ ++ *) Reformat the FAQ so the different questions and answers can be divided ++ in sections depending on the subject. ++ [Richard Levitte] ++ ++ *) Have the zlib compression code load ZLIB.DLL dynamically under ++ Windows. ++ [Richard Levitte] ++ ++ *) New function BN_mod_sqrt for computing square roots modulo a prime ++ (using the probabilistic Tonelli-Shanks algorithm unless ++ p == 3 (mod 4) or p == 5 (mod 8), which are cases that can ++ be handled deterministically). ++ [Lenka Fibikova , Bodo Moeller] ++ ++ *) Make BN_mod_inverse faster by explicitly handling small quotients ++ in the Euclid loop. (Speed gain about 20% for small moduli [256 or ++ 512 bits], about 30% for larger ones [1024 or 2048 bits].) ++ [Bodo Moeller] ++ ++ *) New function BN_kronecker. ++ [Bodo Moeller] ++ ++ *) Fix BN_gcd so that it works on negative inputs; the result is ++ positive unless both parameters are zero. ++ Previously something reasonably close to an infinite loop was ++ possible because numbers could be growing instead of shrinking ++ in the implementation of Euclid's algorithm. ++ [Bodo Moeller] ++ ++ *) Fix BN_is_word() and BN_is_one() macros to take into account the ++ sign of the number in question. ++ ++ Fix BN_is_word(a,w) to work correctly for w == 0. ++ ++ The old BN_is_word(a,w) macro is now called BN_abs_is_word(a,w) ++ because its test if the absolute value of 'a' equals 'w'. ++ Note that BN_abs_is_word does *not* handle w == 0 reliably; ++ it exists mostly for use in the implementations of BN_is_zero(), ++ BN_is_one(), and BN_is_word(). ++ [Bodo Moeller] ++ ++ *) New function BN_swap. ++ [Bodo Moeller] ++ ++ *) Use BN_nnmod instead of BN_mod in crypto/bn/bn_exp.c so that ++ the exponentiation functions are more likely to produce reasonable ++ results on negative inputs. ++ [Bodo Moeller] ++ ++ *) Change BN_mod_mul so that the result is always non-negative. ++ Previously, it could be negative if one of the factors was negative; ++ I don't think anyone really wanted that behaviour. ++ [Bodo Moeller] ++ ++ *) Move BN_mod_... functions into new file crypto/bn/bn_mod.c ++ (except for exponentiation, which stays in crypto/bn/bn_exp.c, ++ and BN_mod_mul_reciprocal, which stays in crypto/bn/bn_recp.c) ++ and add new functions: ++ ++ BN_nnmod ++ BN_mod_sqr ++ BN_mod_add ++ BN_mod_add_quick ++ BN_mod_sub ++ BN_mod_sub_quick ++ BN_mod_lshift1 ++ BN_mod_lshift1_quick ++ BN_mod_lshift ++ BN_mod_lshift_quick ++ ++ These functions always generate non-negative results. ++ ++ BN_nnmod otherwise is like BN_mod (if BN_mod computes a remainder r ++ such that |m| < r < 0, BN_nnmod will output rem + |m| instead). ++ ++ BN_mod_XXX_quick(r, a, [b,] m) generates the same result as ++ BN_mod_XXX(r, a, [b,] m, ctx), but requires that a [and b] ++ be reduced modulo m. ++ [Lenka Fibikova , Bodo Moeller] ++ ++#if 0 ++ The following entry accidentally appeared in the CHANGES file ++ distributed with OpenSSL 0.9.7. The modifications described in ++ it do *not* apply to OpenSSL 0.9.7. ++ ++ *) Remove a few calls to bn_wexpand() in BN_sqr() (the one in there ++ was actually never needed) and in BN_mul(). The removal in BN_mul() ++ required a small change in bn_mul_part_recursive() and the addition ++ of the functions bn_cmp_part_words(), bn_sub_part_words() and ++ bn_add_part_words(), which do the same thing as bn_cmp_words(), ++ bn_sub_words() and bn_add_words() except they take arrays with ++ differing sizes. ++ [Richard Levitte] ++#endif ++ ++ *) In 'openssl passwd', verify passwords read from the terminal ++ unless the '-salt' option is used (which usually means that ++ verification would just waste user's time since the resulting ++ hash is going to be compared with some given password hash) ++ or the new '-noverify' option is used. ++ ++ This is an incompatible change, but it does not affect ++ non-interactive use of 'openssl passwd' (passwords on the command ++ line, '-stdin' option, '-in ...' option) and thus should not ++ cause any problems. ++ [Bodo Moeller] ++ ++ *) Remove all references to RSAref, since there's no more need for it. ++ [Richard Levitte] ++ ++ *) Make DSO load along a path given through an environment variable ++ (SHLIB_PATH) with shl_load(). ++ [Richard Levitte] ++ ++ *) Constify the ENGINE code as a result of BIGNUM constification. ++ Also constify the RSA code and most things related to it. In a ++ few places, most notable in the depth of the ASN.1 code, ugly ++ casts back to non-const were required (to be solved at a later ++ time) ++ [Richard Levitte] ++ ++ *) Make it so the openssl application has all engines loaded by default. ++ [Richard Levitte] ++ ++ *) Constify the BIGNUM routines a little more. ++ [Richard Levitte] ++ ++ *) Add the following functions: ++ ++ ENGINE_load_cswift() ++ ENGINE_load_chil() ++ ENGINE_load_atalla() ++ ENGINE_load_nuron() ++ ENGINE_load_builtin_engines() ++ ++ That way, an application can itself choose if external engines that ++ are built-in in OpenSSL shall ever be used or not. The benefit is ++ that applications won't have to be linked with libdl or other dso ++ libraries unless it's really needed. ++ ++ Changed 'openssl engine' to load all engines on demand. ++ Changed the engine header files to avoid the duplication of some ++ declarations (they differed!). ++ [Richard Levitte] ++ ++ *) 'openssl engine' can now list capabilities. ++ [Richard Levitte] ++ ++ *) Better error reporting in 'openssl engine'. ++ [Richard Levitte] ++ ++ *) Never call load_dh_param(NULL) in s_server. ++ [Bodo Moeller] ++ ++ *) Add engine application. It can currently list engines by name and ++ identity, and test if they are actually available. ++ [Richard Levitte] ++ ++ *) Improve RPM specification file by forcing symbolic linking and making ++ sure the installed documentation is also owned by root.root. ++ [Damien Miller ] ++ ++ *) Give the OpenSSL applications more possibilities to make use of ++ keys (public as well as private) handled by engines. ++ [Richard Levitte] ++ ++ *) Add OCSP code that comes from CertCo. ++ [Richard Levitte] ++ ++ *) Add VMS support for the Rijndael code. ++ [Richard Levitte] ++ ++ *) Added untested support for Nuron crypto accelerator. ++ [Ben Laurie] ++ ++ *) Add support for external cryptographic devices. This code was ++ previously distributed separately as the "engine" branch. ++ [Geoff Thorpe, Richard Levitte] ++ ++ *) Rework the filename-translation in the DSO code. It is now possible to ++ have far greater control over how a "name" is turned into a filename ++ depending on the operating environment and any oddities about the ++ different shared library filenames on each system. ++ [Geoff Thorpe] ++ ++ *) Support threads on FreeBSD-elf in Configure. ++ [Richard Levitte] ++ ++ *) Fix for SHA1 assembly problem with MASM: it produces ++ warnings about corrupt line number information when assembling ++ with debugging information. This is caused by the overlapping ++ of two sections. ++ [Bernd Matthes , Steve Henson] ++ ++ *) NCONF changes. ++ NCONF_get_number() has no error checking at all. As a replacement, ++ NCONF_get_number_e() is defined (_e for "error checking") and is ++ promoted strongly. The old NCONF_get_number is kept around for ++ binary backward compatibility. ++ Make it possible for methods to load from something other than a BIO, ++ by providing a function pointer that is given a name instead of a BIO. ++ For example, this could be used to load configuration data from an ++ LDAP server. ++ [Richard Levitte] ++ ++ *) Fix for non blocking accept BIOs. Added new I/O special reason ++ BIO_RR_ACCEPT to cover this case. Previously use of accept BIOs ++ with non blocking I/O was not possible because no retry code was ++ implemented. Also added new SSL code SSL_WANT_ACCEPT to cover ++ this case. ++ [Steve Henson] ++ ++ *) Added the beginnings of Rijndael support. ++ [Ben Laurie] ++ ++ *) Fix for bug in DirectoryString mask setting. Add support for ++ X509_NAME_print_ex() in 'req' and X509_print_ex() function ++ to allow certificate printing to more controllable, additional ++ 'certopt' option to 'x509' to allow new printing options to be ++ set. ++ [Steve Henson] ++ ++ *) Clean old EAY MD5 hack from e_os.h. ++ [Richard Levitte] ++ ++ Changes between 0.9.6l and 0.9.6m [17 Mar 2004] ++ ++ *) Fix null-pointer assignment in do_change_cipher_spec() revealed ++ by using the Codenomicon TLS Test Tool (CVE-2004-0079) ++ [Joe Orton, Steve Henson] ++ ++ Changes between 0.9.6k and 0.9.6l [04 Nov 2003] ++ ++ *) Fix additional bug revealed by the NISCC test suite: ++ ++ Stop bug triggering large recursion when presented with ++ certain ASN.1 tags (CVE-2003-0851) ++ [Steve Henson] ++ ++ Changes between 0.9.6j and 0.9.6k [30 Sep 2003] ++ ++ *) Fix various bugs revealed by running the NISCC test suite: ++ ++ Stop out of bounds reads in the ASN1 code when presented with ++ invalid tags (CVE-2003-0543 and CVE-2003-0544). ++ ++ If verify callback ignores invalid public key errors don't try to check ++ certificate signature with the NULL public key. ++ ++ [Steve Henson] ++ ++ *) In ssl3_accept() (ssl/s3_srvr.c) only accept a client certificate ++ if the server requested one: as stated in TLS 1.0 and SSL 3.0 ++ specifications. ++ [Steve Henson] ++ ++ *) In ssl3_get_client_hello() (ssl/s3_srvr.c), tolerate additional ++ extra data after the compression methods not only for TLS 1.0 ++ but also for SSL 3.0 (as required by the specification). ++ [Bodo Moeller; problem pointed out by Matthias Loepfe] ++ ++ *) Change X509_certificate_type() to mark the key as exported/exportable ++ when it's 512 *bits* long, not 512 bytes. ++ [Richard Levitte] ++ ++ Changes between 0.9.6i and 0.9.6j [10 Apr 2003] ++ ++ *) Countermeasure against the Klima-Pokorny-Rosa extension of ++ Bleichbacher's attack on PKCS #1 v1.5 padding: treat ++ a protocol version number mismatch like a decryption error ++ in ssl3_get_client_key_exchange (ssl/s3_srvr.c). ++ [Bodo Moeller] ++ ++ *) Turn on RSA blinding by default in the default implementation ++ to avoid a timing attack. Applications that don't want it can call ++ RSA_blinding_off() or use the new flag RSA_FLAG_NO_BLINDING. ++ They would be ill-advised to do so in most cases. ++ [Ben Laurie, Steve Henson, Geoff Thorpe, Bodo Moeller] ++ ++ *) Change RSA blinding code so that it works when the PRNG is not ++ seeded (in this case, the secret RSA exponent is abused as ++ an unpredictable seed -- if it is not unpredictable, there ++ is no point in blinding anyway). Make RSA blinding thread-safe ++ by remembering the creator's thread ID in rsa->blinding and ++ having all other threads use local one-time blinding factors ++ (this requires more computation than sharing rsa->blinding, but ++ avoids excessive locking; and if an RSA object is not shared ++ between threads, blinding will still be very fast). ++ [Bodo Moeller] ++ ++ Changes between 0.9.6h and 0.9.6i [19 Feb 2003] ++ ++ *) In ssl3_get_record (ssl/s3_pkt.c), minimize information leaked ++ via timing by performing a MAC computation even if incorrrect ++ block cipher padding has been found. This is a countermeasure ++ against active attacks where the attacker has to distinguish ++ between bad padding and a MAC verification error. (CVE-2003-0078) ++ ++ [Bodo Moeller; problem pointed out by Brice Canvel (EPFL), ++ Alain Hiltgen (UBS), Serge Vaudenay (EPFL), and ++ Martin Vuagnoux (EPFL, Ilion)] ++ ++ Changes between 0.9.6g and 0.9.6h [5 Dec 2002] ++ ++ *) New function OPENSSL_cleanse(), which is used to cleanse a section of ++ memory from it's contents. This is done with a counter that will ++ place alternating values in each byte. This can be used to solve ++ two issues: 1) the removal of calls to memset() by highly optimizing ++ compilers, and 2) cleansing with other values than 0, since those can ++ be read through on certain media, for example a swap space on disk. ++ [Geoff Thorpe] ++ ++ *) Bugfix: client side session caching did not work with external caching, ++ because the session->cipher setting was not restored when reloading ++ from the external cache. This problem was masked, when ++ SSL_OP_NETSCAPE_REUSE_CIPHER_CHANGE_BUG (part of SSL_OP_ALL) was set. ++ (Found by Steve Haslam .) ++ [Lutz Jaenicke] ++ ++ *) Fix client_certificate (ssl/s2_clnt.c): The permissible total ++ length of the REQUEST-CERTIFICATE message is 18 .. 34, not 17 .. 33. ++ [Zeev Lieber ] ++ ++ *) Undo an undocumented change introduced in 0.9.6e which caused ++ repeated calls to OpenSSL_add_all_ciphers() and ++ OpenSSL_add_all_digests() to be ignored, even after calling ++ EVP_cleanup(). ++ [Richard Levitte] ++ ++ *) Change the default configuration reader to deal with last line not ++ being properly terminated. ++ [Richard Levitte] ++ ++ *) Change X509_NAME_cmp() so it applies the special rules on handling ++ DN values that are of type PrintableString, as well as RDNs of type ++ emailAddress where the value has the type ia5String. ++ [stefank@valicert.com via Richard Levitte] ++ ++ *) Add a SSL_SESS_CACHE_NO_INTERNAL_STORE flag to take over half ++ the job SSL_SESS_CACHE_NO_INTERNAL_LOOKUP was inconsistently ++ doing, define a new flag (SSL_SESS_CACHE_NO_INTERNAL) to be ++ the bitwise-OR of the two for use by the majority of applications ++ wanting this behaviour, and update the docs. The documented ++ behaviour and actual behaviour were inconsistent and had been ++ changing anyway, so this is more a bug-fix than a behavioural ++ change. ++ [Geoff Thorpe, diagnosed by Nadav Har'El] ++ ++ *) Don't impose a 16-byte length minimum on session IDs in ssl/s3_clnt.c ++ (the SSL 3.0 and TLS 1.0 specifications allow any length up to 32 bytes). ++ [Bodo Moeller] ++ ++ *) Fix initialization code race conditions in ++ SSLv23_method(), SSLv23_client_method(), SSLv23_server_method(), ++ SSLv2_method(), SSLv2_client_method(), SSLv2_server_method(), ++ SSLv3_method(), SSLv3_client_method(), SSLv3_server_method(), ++ TLSv1_method(), TLSv1_client_method(), TLSv1_server_method(), ++ ssl2_get_cipher_by_char(), ++ ssl3_get_cipher_by_char(). ++ [Patrick McCormick , Bodo Moeller] ++ ++ *) Reorder cleanup sequence in SSL_CTX_free(): only remove the ex_data after ++ the cached sessions are flushed, as the remove_cb() might use ex_data ++ contents. Bug found by Sam Varshavchik ++ (see [openssl.org #212]). ++ [Geoff Thorpe, Lutz Jaenicke] ++ ++ *) Fix typo in OBJ_txt2obj which incorrectly passed the content ++ length, instead of the encoding length to d2i_ASN1_OBJECT. ++ [Steve Henson] ++ ++ Changes between 0.9.6f and 0.9.6g [9 Aug 2002] ++ ++ *) [In 0.9.6g-engine release:] ++ Fix crypto/engine/vendor_defns/cswift.h for WIN32 (use '_stdcall'). ++ [Lynn Gazis ] ++ ++ Changes between 0.9.6e and 0.9.6f [8 Aug 2002] ++ ++ *) Fix ASN1 checks. Check for overflow by comparing with LONG_MAX ++ and get fix the header length calculation. ++ [Florian Weimer , ++ Alon Kantor (and others), ++ Steve Henson] ++ ++ *) Use proper error handling instead of 'assertions' in buffer ++ overflow checks added in 0.9.6e. This prevents DoS (the ++ assertions could call abort()). ++ [Arne Ansper , Bodo Moeller] ++ ++ Changes between 0.9.6d and 0.9.6e [30 Jul 2002] ++ ++ *) Add various sanity checks to asn1_get_length() to reject ++ the ASN1 length bytes if they exceed sizeof(long), will appear ++ negative or the content length exceeds the length of the ++ supplied buffer. ++ [Steve Henson, Adi Stav , James Yonan ] ++ ++ *) Fix cipher selection routines: ciphers without encryption had no flags ++ for the cipher strength set and where therefore not handled correctly ++ by the selection routines (PR #130). ++ [Lutz Jaenicke] ++ ++ *) Fix EVP_dsa_sha macro. ++ [Nils Larsch] ++ ++ *) New option ++ SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS ++ for disabling the SSL 3.0/TLS 1.0 CBC vulnerability countermeasure ++ that was added in OpenSSL 0.9.6d. ++ ++ As the countermeasure turned out to be incompatible with some ++ broken SSL implementations, the new option is part of SSL_OP_ALL. ++ SSL_OP_ALL is usually employed when compatibility with weird SSL ++ implementations is desired (e.g. '-bugs' option to 's_client' and ++ 's_server'), so the new option is automatically set in many ++ applications. ++ [Bodo Moeller] ++ ++ *) Changes in security patch: ++ ++ Changes marked "(CHATS)" were sponsored by the Defense Advanced ++ Research Projects Agency (DARPA) and Air Force Research Laboratory, ++ Air Force Materiel Command, USAF, under agreement number ++ F30602-01-2-0537. ++ ++ *) Add various sanity checks to asn1_get_length() to reject ++ the ASN1 length bytes if they exceed sizeof(long), will appear ++ negative or the content length exceeds the length of the ++ supplied buffer. (CVE-2002-0659) ++ [Steve Henson, Adi Stav , James Yonan ] ++ ++ *) Assertions for various potential buffer overflows, not known to ++ happen in practice. ++ [Ben Laurie (CHATS)] ++ ++ *) Various temporary buffers to hold ASCII versions of integers were ++ too small for 64 bit platforms. (CVE-2002-0655) ++ [Matthew Byng-Maddick and Ben Laurie (CHATS)> ++ ++ *) Remote buffer overflow in SSL3 protocol - an attacker could ++ supply an oversized session ID to a client. (CVE-2002-0656) ++ [Ben Laurie (CHATS)] ++ ++ *) Remote buffer overflow in SSL2 protocol - an attacker could ++ supply an oversized client master key. (CVE-2002-0656) ++ [Ben Laurie (CHATS)] ++ ++ Changes between 0.9.6c and 0.9.6d [9 May 2002] ++ ++ *) Fix crypto/asn1/a_sign.c so that 'parameters' is omitted (not ++ encoded as NULL) with id-dsa-with-sha1. ++ [Nils Larsch ; problem pointed out by Bodo Moeller] ++ ++ *) Check various X509_...() return values in apps/req.c. ++ [Nils Larsch ] ++ ++ *) Fix BASE64 decode (EVP_DecodeUpdate) for data with CR/LF ended lines: ++ an end-of-file condition would erroneously be flagged, when the CRLF ++ was just at the end of a processed block. The bug was discovered when ++ processing data through a buffering memory BIO handing the data to a ++ BASE64-decoding BIO. Bug fund and patch submitted by Pavel Tsekov ++ and Nedelcho Stanev. ++ [Lutz Jaenicke] ++ ++ *) Implement a countermeasure against a vulnerability recently found ++ in CBC ciphersuites in SSL 3.0/TLS 1.0: Send an empty fragment ++ before application data chunks to avoid the use of known IVs ++ with data potentially chosen by the attacker. ++ [Bodo Moeller] ++ ++ *) Fix length checks in ssl3_get_client_hello(). ++ [Bodo Moeller] ++ ++ *) TLS/SSL library bugfix: use s->s3->in_read_app_data differently ++ to prevent ssl3_read_internal() from incorrectly assuming that ++ ssl3_read_bytes() found application data while handshake ++ processing was enabled when in fact s->s3->in_read_app_data was ++ merely automatically cleared during the initial handshake. ++ [Bodo Moeller; problem pointed out by Arne Ansper ] ++ ++ *) Fix object definitions for Private and Enterprise: they were not ++ recognized in their shortname (=lowercase) representation. Extend ++ obj_dat.pl to issue an error when using undefined keywords instead ++ of silently ignoring the problem (Svenning Sorensen ++ ). ++ [Lutz Jaenicke] ++ ++ *) Fix DH_generate_parameters() so that it works for 'non-standard' ++ generators, i.e. generators other than 2 and 5. (Previously, the ++ code did not properly initialise the 'add' and 'rem' values to ++ BN_generate_prime().) ++ ++ In the new general case, we do not insist that 'generator' is ++ actually a primitive root: This requirement is rather pointless; ++ a generator of the order-q subgroup is just as good, if not ++ better. ++ [Bodo Moeller] ++ ++ *) Map new X509 verification errors to alerts. Discovered and submitted by ++ Tom Wu . ++ [Lutz Jaenicke] ++ ++ *) Fix ssl3_pending() (ssl/s3_lib.c) to prevent SSL_pending() from ++ returning non-zero before the data has been completely received ++ when using non-blocking I/O. ++ [Bodo Moeller; problem pointed out by John Hughes] ++ ++ *) Some of the ciphers missed the strength entry (SSL_LOW etc). ++ [Ben Laurie, Lutz Jaenicke] ++ ++ *) Fix bug in SSL_clear(): bad sessions were not removed (found by ++ Yoram Zahavi ). ++ [Lutz Jaenicke] ++ ++ *) Add information about CygWin 1.3 and on, and preserve proper ++ configuration for the versions before that. ++ [Corinna Vinschen and Richard Levitte] ++ ++ *) Make removal from session cache (SSL_CTX_remove_session()) more robust: ++ check whether we deal with a copy of a session and do not delete from ++ the cache in this case. Problem reported by "Izhar Shoshani Levi" ++ . ++ [Lutz Jaenicke] ++ ++ *) Do not store session data into the internal session cache, if it ++ is never intended to be looked up (SSL_SESS_CACHE_NO_INTERNAL_LOOKUP ++ flag is set). Proposed by Aslam . ++ [Lutz Jaenicke] ++ ++ *) Have ASN1_BIT_STRING_set_bit() really clear a bit when the requested ++ value is 0. ++ [Richard Levitte] ++ ++ *) [In 0.9.6d-engine release:] ++ Fix a crashbug and a logic bug in hwcrhk_load_pubkey(). ++ [Toomas Kiisk via Richard Levitte] ++ ++ *) Add the configuration target linux-s390x. ++ [Neale Ferguson via Richard Levitte] ++ ++ *) The earlier bugfix for the SSL3_ST_SW_HELLO_REQ_C case of ++ ssl3_accept (ssl/s3_srvr.c) incorrectly used a local flag ++ variable as an indication that a ClientHello message has been ++ received. As the flag value will be lost between multiple ++ invocations of ssl3_accept when using non-blocking I/O, the ++ function may not be aware that a handshake has actually taken ++ place, thus preventing a new session from being added to the ++ session cache. ++ ++ To avoid this problem, we now set s->new_session to 2 instead of ++ using a local variable. ++ [Lutz Jaenicke, Bodo Moeller] ++ ++ *) Bugfix: Return -1 from ssl3_get_server_done (ssl3/s3_clnt.c) ++ if the SSL_R_LENGTH_MISMATCH error is detected. ++ [Geoff Thorpe, Bodo Moeller] ++ ++ *) New 'shared_ldflag' column in Configure platform table. ++ [Richard Levitte] ++ ++ *) Fix EVP_CIPHER_mode macro. ++ ["Dan S. Camper" ] ++ ++ *) Fix ssl3_read_bytes (ssl/s3_pkt.c): To ignore messages of unknown ++ type, we must throw them away by setting rr->length to 0. ++ [D P Chang ] ++ ++ Changes between 0.9.6b and 0.9.6c [21 dec 2001] ++ ++ *) Fix BN_rand_range bug pointed out by Dominikus Scherkl ++ . (The previous implementation ++ worked incorrectly for those cases where range = 10..._2 and ++ 3*range is two bits longer than range.) ++ [Bodo Moeller] ++ ++ *) Only add signing time to PKCS7 structures if it is not already ++ present. ++ [Steve Henson] ++ ++ *) Fix crypto/objects/objects.h: "ld-ce" should be "id-ce", ++ OBJ_ld_ce should be OBJ_id_ce. ++ Also some ip-pda OIDs in crypto/objects/objects.txt were ++ incorrect (cf. RFC 3039). ++ [Matt Cooper, Frederic Giudicelli, Bodo Moeller] ++ ++ *) Release CRYPTO_LOCK_DYNLOCK when CRYPTO_destroy_dynlockid() ++ returns early because it has nothing to do. ++ [Andy Schneider ] ++ ++ *) [In 0.9.6c-engine release:] ++ Fix mutex callback return values in crypto/engine/hw_ncipher.c. ++ [Andy Schneider ] ++ ++ *) [In 0.9.6c-engine release:] ++ Add support for Cryptographic Appliance's keyserver technology. ++ (Use engine 'keyclient') ++ [Cryptographic Appliances and Geoff Thorpe] ++ ++ *) Add a configuration entry for OS/390 Unix. The C compiler 'c89' ++ is called via tools/c89.sh because arguments have to be ++ rearranged (all '-L' options must appear before the first object ++ modules). ++ [Richard Shapiro ] ++ ++ *) [In 0.9.6c-engine release:] ++ Add support for Broadcom crypto accelerator cards, backported ++ from 0.9.7. ++ [Broadcom, Nalin Dahyabhai , Mark Cox] ++ ++ *) [In 0.9.6c-engine release:] ++ Add support for SureWare crypto accelerator cards from ++ Baltimore Technologies. (Use engine 'sureware') ++ [Baltimore Technologies and Mark Cox] ++ ++ *) [In 0.9.6c-engine release:] ++ Add support for crypto accelerator cards from Accelerated ++ Encryption Processing, www.aep.ie. (Use engine 'aep') ++ [AEP Inc. and Mark Cox] ++ ++ *) Add a configuration entry for gcc on UnixWare. ++ [Gary Benson ] ++ ++ *) Change ssl/s2_clnt.c and ssl/s2_srvr.c so that received handshake ++ messages are stored in a single piece (fixed-length part and ++ variable-length part combined) and fix various bugs found on the way. ++ [Bodo Moeller] ++ ++ *) Disable caching in BIO_gethostbyname(), directly use gethostbyname() ++ instead. BIO_gethostbyname() does not know what timeouts are ++ appropriate, so entries would stay in cache even when they have ++ become invalid. ++ [Bodo Moeller; problem pointed out by Rich Salz ++ ++ *) Change ssl23_get_client_hello (ssl/s23_srvr.c) behaviour when ++ faced with a pathologically small ClientHello fragment that does ++ not contain client_version: Instead of aborting with an error, ++ simply choose the highest available protocol version (i.e., ++ TLS 1.0 unless it is disabled). In practice, ClientHello ++ messages are never sent like this, but this change gives us ++ strictly correct behaviour at least for TLS. ++ [Bodo Moeller] ++ ++ *) Fix SSL handshake functions and SSL_clear() such that SSL_clear() ++ never resets s->method to s->ctx->method when called from within ++ one of the SSL handshake functions. ++ [Bodo Moeller; problem pointed out by Niko Baric] ++ ++ *) In ssl3_get_client_hello (ssl/s3_srvr.c), generate a fatal alert ++ (sent using the client's version number) if client_version is ++ smaller than the protocol version in use. Also change ++ ssl23_get_client_hello (ssl/s23_srvr.c) to select TLS 1.0 if ++ the client demanded SSL 3.0 but only TLS 1.0 is enabled; then ++ the client will at least see that alert. ++ [Bodo Moeller] ++ ++ *) Fix ssl3_get_message (ssl/s3_both.c) to handle message fragmentation ++ correctly. ++ [Bodo Moeller] ++ ++ *) Avoid infinite loop in ssl3_get_message (ssl/s3_both.c) if a ++ client receives HelloRequest while in a handshake. ++ [Bodo Moeller; bug noticed by Andy Schneider ] ++ ++ *) Bugfix in ssl3_accept (ssl/s3_srvr.c): Case SSL3_ST_SW_HELLO_REQ_C ++ should end in 'break', not 'goto end' which circumvents various ++ cleanups done in state SSL_ST_OK. But session related stuff ++ must be disabled for SSL_ST_OK in the case that we just sent a ++ HelloRequest. ++ ++ Also avoid some overhead by not calling ssl_init_wbio_buffer() ++ before just sending a HelloRequest. ++ [Bodo Moeller, Eric Rescorla ] ++ ++ *) Fix ssl/s3_enc.c, ssl/t1_enc.c and ssl/s3_pkt.c so that we don't ++ reveal whether illegal block cipher padding was found or a MAC ++ verification error occurred. (Neither SSLerr() codes nor alerts ++ are directly visible to potential attackers, but the information ++ may leak via logfiles.) ++ ++ Similar changes are not required for the SSL 2.0 implementation ++ because the number of padding bytes is sent in clear for SSL 2.0, ++ and the extra bytes are just ignored. However ssl/s2_pkt.c ++ failed to verify that the purported number of padding bytes is in ++ the legal range. ++ [Bodo Moeller] ++ ++ *) Add OpenUNIX-8 support including shared libraries ++ (Boyd Lynn Gerber ). ++ [Lutz Jaenicke] ++ ++ *) Improve RSA_padding_check_PKCS1_OAEP() check again to avoid ++ 'wristwatch attack' using huge encoding parameters (cf. ++ James H. Manger's CRYPTO 2001 paper). Note that the ++ RSA_PKCS1_OAEP_PADDING case of RSA_private_decrypt() does not use ++ encoding parameters and hence was not vulnerable. ++ [Bodo Moeller] ++ ++ *) BN_sqr() bug fix. ++ [Ulf Möller, reported by Jim Ellis ] ++ ++ *) Rabin-Miller test analyses assume uniformly distributed witnesses, ++ so use BN_pseudo_rand_range() instead of using BN_pseudo_rand() ++ followed by modular reduction. ++ [Bodo Moeller; pointed out by Adam Young ] ++ ++ *) Add BN_pseudo_rand_range() with obvious functionality: BN_rand_range() ++ equivalent based on BN_pseudo_rand() instead of BN_rand(). ++ [Bodo Moeller] ++ ++ *) s3_srvr.c: allow sending of large client certificate lists (> 16 kB). ++ This function was broken, as the check for a new client hello message ++ to handle SGC did not allow these large messages. ++ (Tracked down by "Douglas E. Engert" .) ++ [Lutz Jaenicke] ++ ++ *) Add alert descriptions for TLSv1 to SSL_alert_desc_string[_long](). ++ [Lutz Jaenicke] ++ ++ *) Fix buggy behaviour of BIO_get_num_renegotiates() and BIO_ctrl() ++ for BIO_C_GET_WRITE_BUF_SIZE ("Stephen Hinton" ). ++ [Lutz Jaenicke] ++ ++ *) Rework the configuration and shared library support for Tru64 Unix. ++ The configuration part makes use of modern compiler features and ++ still retains old compiler behavior for those that run older versions ++ of the OS. The shared library support part includes a variant that ++ uses the RPATH feature, and is available through the special ++ configuration target "alpha-cc-rpath", which will never be selected ++ automatically. ++ [Tim Mooney via Richard Levitte] ++ ++ *) In ssl3_get_key_exchange (ssl/s3_clnt.c), call ssl3_get_message() ++ with the same message size as in ssl3_get_certificate_request(). ++ Otherwise, if no ServerKeyExchange message occurs, CertificateRequest ++ messages might inadvertently be reject as too long. ++ [Petr Lampa ] ++ ++ *) Enhanced support for IA-64 Unix platforms (well, Linux and HP-UX). ++ [Andy Polyakov] ++ ++ *) Modified SSL library such that the verify_callback that has been set ++ specificly for an SSL object with SSL_set_verify() is actually being ++ used. Before the change, a verify_callback set with this function was ++ ignored and the verify_callback() set in the SSL_CTX at the time of ++ the call was used. New function X509_STORE_CTX_set_verify_cb() introduced ++ to allow the necessary settings. ++ [Lutz Jaenicke] ++ ++ *) Initialize static variable in crypto/dsa/dsa_lib.c and crypto/dh/dh_lib.c ++ explicitly to NULL, as at least on Solaris 8 this seems not always to be ++ done automatically (in contradiction to the requirements of the C ++ standard). This made problems when used from OpenSSH. ++ [Lutz Jaenicke] ++ ++ *) In OpenSSL 0.9.6a and 0.9.6b, crypto/dh/dh_key.c ignored ++ dh->length and always used ++ ++ BN_rand_range(priv_key, dh->p). ++ ++ BN_rand_range() is not necessary for Diffie-Hellman, and this ++ specific range makes Diffie-Hellman unnecessarily inefficient if ++ dh->length (recommended exponent length) is much smaller than the ++ length of dh->p. We could use BN_rand_range() if the order of ++ the subgroup was stored in the DH structure, but we only have ++ dh->length. ++ ++ So switch back to ++ ++ BN_rand(priv_key, l, ...) ++ ++ where 'l' is dh->length if this is defined, or BN_num_bits(dh->p)-1 ++ otherwise. ++ [Bodo Moeller] ++ ++ *) In ++ ++ RSA_eay_public_encrypt ++ RSA_eay_private_decrypt ++ RSA_eay_private_encrypt (signing) ++ RSA_eay_public_decrypt (signature verification) ++ ++ (default implementations for RSA_public_encrypt, ++ RSA_private_decrypt, RSA_private_encrypt, RSA_public_decrypt), ++ always reject numbers >= n. ++ [Bodo Moeller] ++ ++ *) In crypto/rand/md_rand.c, use a new short-time lock CRYPTO_LOCK_RAND2 ++ to synchronize access to 'locking_thread'. This is necessary on ++ systems where access to 'locking_thread' (an 'unsigned long' ++ variable) is not atomic. ++ [Bodo Moeller] ++ ++ *) In crypto/rand/md_rand.c, set 'locking_thread' to current thread's ID ++ *before* setting the 'crypto_lock_rand' flag. The previous code had ++ a race condition if 0 is a valid thread ID. ++ [Travis Vitek ] ++ ++ *) Add support for shared libraries under Irix. ++ [Albert Chin-A-Young ] ++ ++ *) Add configuration option to build on Linux on both big-endian and ++ little-endian MIPS. ++ [Ralf Baechle ] ++ ++ *) Add the possibility to create shared libraries on HP-UX. ++ [Richard Levitte] ++ ++ Changes between 0.9.6a and 0.9.6b [9 Jul 2001] ++ ++ *) Change ssleay_rand_bytes (crypto/rand/md_rand.c) ++ to avoid a SSLeay/OpenSSL PRNG weakness pointed out by ++ Markku-Juhani O. Saarinen : ++ PRNG state recovery was possible based on the output of ++ one PRNG request appropriately sized to gain knowledge on ++ 'md' followed by enough consecutive 1-byte PRNG requests ++ to traverse all of 'state'. ++ ++ 1. When updating 'md_local' (the current thread's copy of 'md') ++ during PRNG output generation, hash all of the previous ++ 'md_local' value, not just the half used for PRNG output. ++ ++ 2. Make the number of bytes from 'state' included into the hash ++ independent from the number of PRNG bytes requested. ++ ++ The first measure alone would be sufficient to avoid ++ Markku-Juhani's attack. (Actually it had never occurred ++ to me that the half of 'md_local' used for chaining was the ++ half from which PRNG output bytes were taken -- I had always ++ assumed that the secret half would be used.) The second ++ measure makes sure that additional data from 'state' is never ++ mixed into 'md_local' in small portions; this heuristically ++ further strengthens the PRNG. ++ [Bodo Moeller] ++ ++ *) Fix crypto/bn/asm/mips3.s. ++ [Andy Polyakov] ++ ++ *) When only the key is given to "enc", the IV is undefined. Print out ++ an error message in this case. ++ [Lutz Jaenicke] ++ ++ *) Handle special case when X509_NAME is empty in X509 printing routines. ++ [Steve Henson] ++ ++ *) In dsa_do_verify (crypto/dsa/dsa_ossl.c), verify that r and s are ++ positive and less than q. ++ [Bodo Moeller] ++ ++ *) Don't change *pointer in CRYPTO_add_lock() is add_lock_callback is ++ used: it isn't thread safe and the add_lock_callback should handle ++ that itself. ++ [Paul Rose ] ++ ++ *) Verify that incoming data obeys the block size in ++ ssl3_enc (ssl/s3_enc.c) and tls1_enc (ssl/t1_enc.c). ++ [Bodo Moeller] ++ ++ *) Fix OAEP check. ++ [Ulf Möller, Bodo Möller] ++ ++ *) The countermeasure against Bleichbacher's attack on PKCS #1 v1.5 ++ RSA encryption was accidentally removed in s3_srvr.c in OpenSSL 0.9.5 ++ when fixing the server behaviour for backwards-compatible 'client ++ hello' messages. (Note that the attack is impractical against ++ SSL 3.0 and TLS 1.0 anyway because length and version checking ++ means that the probability of guessing a valid ciphertext is ++ around 2^-40; see section 5 in Bleichenbacher's CRYPTO '98 ++ paper.) ++ ++ Before 0.9.5, the countermeasure (hide the error by generating a ++ random 'decryption result') did not work properly because ++ ERR_clear_error() was missing, meaning that SSL_get_error() would ++ detect the supposedly ignored error. ++ ++ Both problems are now fixed. ++ [Bodo Moeller] ++ ++ *) In crypto/bio/bf_buff.c, increase DEFAULT_BUFFER_SIZE to 4096 ++ (previously it was 1024). ++ [Bodo Moeller] ++ ++ *) Fix for compatibility mode trust settings: ignore trust settings ++ unless some valid trust or reject settings are present. ++ [Steve Henson] ++ ++ *) Fix for blowfish EVP: its a variable length cipher. ++ [Steve Henson] ++ ++ *) Fix various bugs related to DSA S/MIME verification. Handle missing ++ parameters in DSA public key structures and return an error in the ++ DSA routines if parameters are absent. ++ [Steve Henson] ++ ++ *) In versions up to 0.9.6, RAND_file_name() resorted to file ".rnd" ++ in the current directory if neither $RANDFILE nor $HOME was set. ++ RAND_file_name() in 0.9.6a returned NULL in this case. This has ++ caused some confusion to Windows users who haven't defined $HOME. ++ Thus RAND_file_name() is changed again: e_os.h can define a ++ DEFAULT_HOME, which will be used if $HOME is not set. ++ For Windows, we use "C:"; on other platforms, we still require ++ environment variables. ++ ++ *) Move 'if (!initialized) RAND_poll()' into regions protected by ++ CRYPTO_LOCK_RAND. This is not strictly necessary, but avoids ++ having multiple threads call RAND_poll() concurrently. ++ [Bodo Moeller] ++ ++ *) In crypto/rand/md_rand.c, replace 'add_do_not_lock' flag by a ++ combination of a flag and a thread ID variable. ++ Otherwise while one thread is in ssleay_rand_bytes (which sets the ++ flag), *other* threads can enter ssleay_add_bytes without obeying ++ the CRYPTO_LOCK_RAND lock (and may even illegally release the lock ++ that they do not hold after the first thread unsets add_do_not_lock). ++ [Bodo Moeller] ++ ++ *) Change bctest again: '-x' expressions are not available in all ++ versions of 'test'. ++ [Bodo Moeller] ++ ++ Changes between 0.9.6 and 0.9.6a [5 Apr 2001] ++ ++ *) Fix a couple of memory leaks in PKCS7_dataDecode() ++ [Steve Henson, reported by Heyun Zheng ] ++ ++ *) Change Configure and Makefiles to provide EXE_EXT, which will contain ++ the default extension for executables, if any. Also, make the perl ++ scripts that use symlink() to test if it really exists and use "cp" ++ if it doesn't. All this made OpenSSL compilable and installable in ++ CygWin. ++ [Richard Levitte] ++ ++ *) Fix for asn1_GetSequence() for indefinite length constructed data. ++ If SEQUENCE is length is indefinite just set c->slen to the total ++ amount of data available. ++ [Steve Henson, reported by shige@FreeBSD.org] ++ [This change does not apply to 0.9.7.] ++ ++ *) Change bctest to avoid here-documents inside command substitution ++ (workaround for FreeBSD /bin/sh bug). ++ For compatibility with Ultrix, avoid shell functions (introduced ++ in the bctest version that searches along $PATH). ++ [Bodo Moeller] ++ ++ *) Rename 'des_encrypt' to 'des_encrypt1'. This avoids the clashes ++ with des_encrypt() defined on some operating systems, like Solaris ++ and UnixWare. ++ [Richard Levitte] ++ ++ *) Check the result of RSA-CRT (see D. Boneh, R. DeMillo, R. Lipton: ++ On the Importance of Eliminating Errors in Cryptographic ++ Computations, J. Cryptology 14 (2001) 2, 101-119, ++ http://theory.stanford.edu/~dabo/papers/faults.ps.gz). ++ [Ulf Moeller] ++ ++ *) MIPS assembler BIGNUM division bug fix. ++ [Andy Polyakov] ++ ++ *) Disabled incorrect Alpha assembler code. ++ [Richard Levitte] ++ ++ *) Fix PKCS#7 decode routines so they correctly update the length ++ after reading an EOC for the EXPLICIT tag. ++ [Steve Henson] ++ [This change does not apply to 0.9.7.] ++ ++ *) Fix bug in PKCS#12 key generation routines. This was triggered ++ if a 3DES key was generated with a 0 initial byte. Include ++ PKCS12_BROKEN_KEYGEN compilation option to retain the old ++ (but broken) behaviour. ++ [Steve Henson] ++ ++ *) Enhance bctest to search for a working bc along $PATH and print ++ it when found. ++ [Tim Rice via Richard Levitte] ++ ++ *) Fix memory leaks in err.c: free err_data string if necessary; ++ don't write to the wrong index in ERR_set_error_data. ++ [Bodo Moeller] ++ ++ *) Implement ssl23_peek (analogous to ssl23_read), which previously ++ did not exist. ++ [Bodo Moeller] ++ ++ *) Replace rdtsc with _emit statements for VC++ version 5. ++ [Jeremy Cooper ] ++ ++ *) Make it possible to reuse SSLv2 sessions. ++ [Richard Levitte] ++ ++ *) In copy_email() check for >= 0 as a return value for ++ X509_NAME_get_index_by_NID() since 0 is a valid index. ++ [Steve Henson reported by Massimiliano Pala ] ++ ++ *) Avoid coredump with unsupported or invalid public keys by checking if ++ X509_get_pubkey() fails in PKCS7_verify(). Fix memory leak when ++ PKCS7_verify() fails with non detached data. ++ [Steve Henson] ++ ++ *) Don't use getenv in library functions when run as setuid/setgid. ++ New function OPENSSL_issetugid(). ++ [Ulf Moeller] ++ ++ *) Avoid false positives in memory leak detection code (crypto/mem_dbg.c) ++ due to incorrect handling of multi-threading: ++ ++ 1. Fix timing glitch in the MemCheck_off() portion of CRYPTO_mem_ctrl(). ++ ++ 2. Fix logical glitch in is_MemCheck_on() aka CRYPTO_is_mem_check_on(). ++ ++ 3. Count how many times MemCheck_off() has been called so that ++ nested use can be treated correctly. This also avoids ++ inband-signalling in the previous code (which relied on the ++ assumption that thread ID 0 is impossible). ++ [Bodo Moeller] ++ ++ *) Add "-rand" option also to s_client and s_server. ++ [Lutz Jaenicke] ++ ++ *) Fix CPU detection on Irix 6.x. ++ [Kurt Hockenbury and ++ "Bruce W. Forsberg" ] ++ ++ *) Fix X509_NAME bug which produced incorrect encoding if X509_NAME ++ was empty. ++ [Steve Henson] ++ [This change does not apply to 0.9.7.] ++ ++ *) Use the cached encoding of an X509_NAME structure rather than ++ copying it. This is apparently the reason for the libsafe "errors" ++ but the code is actually correct. ++ [Steve Henson] ++ ++ *) Add new function BN_rand_range(), and fix DSA_sign_setup() to prevent ++ Bleichenbacher's DSA attack. ++ Extend BN_[pseudo_]rand: As before, top=1 forces the highest two bits ++ to be set and top=0 forces the highest bit to be set; top=-1 is new ++ and leaves the highest bit random. ++ [Ulf Moeller, Bodo Moeller] ++ ++ *) In the NCONF_...-based implementations for CONF_... queries ++ (crypto/conf/conf_lib.c), if the input LHASH is NULL, avoid using ++ a temporary CONF structure with the data component set to NULL ++ (which gives segmentation faults in lh_retrieve). ++ Instead, use NULL for the CONF pointer in CONF_get_string and ++ CONF_get_number (which may use environment variables) and directly ++ return NULL from CONF_get_section. ++ [Bodo Moeller] ++ ++ *) Fix potential buffer overrun for EBCDIC. ++ [Ulf Moeller] ++ ++ *) Tolerate nonRepudiation as being valid for S/MIME signing and certSign ++ keyUsage if basicConstraints absent for a CA. ++ [Steve Henson] ++ ++ *) Make SMIME_write_PKCS7() write mail header values with a format that ++ is more generally accepted (no spaces before the semicolon), since ++ some programs can't parse those values properly otherwise. Also make ++ sure BIO's that break lines after each write do not create invalid ++ headers. ++ [Richard Levitte] ++ ++ *) Make the CRL encoding routines work with empty SEQUENCE OF. The ++ macros previously used would not encode an empty SEQUENCE OF ++ and break the signature. ++ [Steve Henson] ++ [This change does not apply to 0.9.7.] ++ ++ *) Zero the premaster secret after deriving the master secret in ++ DH ciphersuites. ++ [Steve Henson] ++ ++ *) Add some EVP_add_digest_alias registrations (as found in ++ OpenSSL_add_all_digests()) to SSL_library_init() ++ aka OpenSSL_add_ssl_algorithms(). This provides improved ++ compatibility with peers using X.509 certificates ++ with unconventional AlgorithmIdentifier OIDs. ++ [Bodo Moeller] ++ ++ *) Fix for Irix with NO_ASM. ++ ["Bruce W. Forsberg" ] ++ ++ *) ./config script fixes. ++ [Ulf Moeller, Richard Levitte] ++ ++ *) Fix 'openssl passwd -1'. ++ [Bodo Moeller] ++ ++ *) Change PKCS12_key_gen_asc() so it can cope with non null ++ terminated strings whose length is passed in the passlen ++ parameter, for example from PEM callbacks. This was done ++ by adding an extra length parameter to asc2uni(). ++ [Steve Henson, reported by ] ++ ++ *) Fix C code generated by 'openssl dsaparam -C': If a BN_bin2bn ++ call failed, free the DSA structure. ++ [Bodo Moeller] ++ ++ *) Fix to uni2asc() to cope with zero length Unicode strings. ++ These are present in some PKCS#12 files. ++ [Steve Henson] ++ ++ *) Increase s2->wbuf allocation by one byte in ssl2_new (ssl/s2_lib.c). ++ Otherwise do_ssl_write (ssl/s2_pkt.c) will write beyond buffer limits ++ when writing a 32767 byte record. ++ [Bodo Moeller; problem reported by Eric Day ] ++ ++ *) In RSA_eay_public_{en,ed}crypt and RSA_eay_mod_exp (rsa_eay.c), ++ obtain lock CRYPTO_LOCK_RSA before setting rsa->_method_mod_{n,p,q}. ++ ++ (RSA objects have a reference count access to which is protected ++ by CRYPTO_LOCK_RSA [see rsa_lib.c, s3_srvr.c, ssl_cert.c, ssl_rsa.c], ++ so they are meant to be shared between threads.) ++ [Bodo Moeller, Geoff Thorpe; original patch submitted by ++ "Reddie, Steven" ] ++ ++ *) Fix a deadlock in CRYPTO_mem_leaks(). ++ [Bodo Moeller] ++ ++ *) Use better test patterns in bntest. ++ [Ulf Möller] ++ ++ *) rand_win.c fix for Borland C. ++ [Ulf Möller] ++ ++ *) BN_rshift bugfix for n == 0. ++ [Bodo Moeller] ++ ++ *) Add a 'bctest' script that checks for some known 'bc' bugs ++ so that 'make test' does not abort just because 'bc' is broken. ++ [Bodo Moeller] ++ ++ *) Store verify_result within SSL_SESSION also for client side to ++ avoid potential security hole. (Re-used sessions on the client side ++ always resulted in verify_result==X509_V_OK, not using the original ++ result of the server certificate verification.) ++ [Lutz Jaenicke] ++ ++ *) Fix ssl3_pending: If the record in s->s3->rrec is not of type ++ SSL3_RT_APPLICATION_DATA, return 0. ++ Similarly, change ssl2_pending to return 0 if SSL_in_init(s) is true. ++ [Bodo Moeller] ++ ++ *) Fix SSL_peek: ++ Both ssl2_peek and ssl3_peek, which were totally broken in earlier ++ releases, have been re-implemented by renaming the previous ++ implementations of ssl2_read and ssl3_read to ssl2_read_internal ++ and ssl3_read_internal, respectively, and adding 'peek' parameters ++ to them. The new ssl[23]_{read,peek} functions are calls to ++ ssl[23]_read_internal with the 'peek' flag set appropriately. ++ A 'peek' parameter has also been added to ssl3_read_bytes, which ++ does the actual work for ssl3_read_internal. ++ [Bodo Moeller] ++ ++ *) Initialise "ex_data" member of RSA/DSA/DH structures prior to calling ++ the method-specific "init()" handler. Also clean up ex_data after ++ calling the method-specific "finish()" handler. Previously, this was ++ happening the other way round. ++ [Geoff Thorpe] ++ ++ *) Increase BN_CTX_NUM (the number of BIGNUMs in a BN_CTX) to 16. ++ The previous value, 12, was not always sufficient for BN_mod_exp(). ++ [Bodo Moeller] ++ ++ *) Make sure that shared libraries get the internal name engine with ++ the full version number and not just 0. This should mark the ++ shared libraries as not backward compatible. Of course, this should ++ be changed again when we can guarantee backward binary compatibility. ++ [Richard Levitte] ++ ++ *) Fix typo in get_cert_by_subject() in by_dir.c ++ [Jean-Marc Desperrier ] ++ ++ *) Rework the system to generate shared libraries: ++ ++ - Make note of the expected extension for the shared libraries and ++ if there is a need for symbolic links from for example libcrypto.so.0 ++ to libcrypto.so.0.9.7. There is extended info in Configure for ++ that. ++ ++ - Make as few rebuilds of the shared libraries as possible. ++ ++ - Still avoid linking the OpenSSL programs with the shared libraries. ++ ++ - When installing, install the shared libraries separately from the ++ static ones. ++ [Richard Levitte] ++ ++ *) Fix SSL_CTX_set_read_ahead macro to actually use its argument. ++ ++ Copy SSL_CTX's read_ahead flag to SSL object directly in SSL_new ++ and not in SSL_clear because the latter is also used by the ++ accept/connect functions; previously, the settings made by ++ SSL_set_read_ahead would be lost during the handshake. ++ [Bodo Moeller; problems reported by Anders Gertz ] ++ ++ *) Correct util/mkdef.pl to be selective about disabled algorithms. ++ Previously, it would create entries for disabled algorithms no ++ matter what. ++ [Richard Levitte] ++ ++ *) Added several new manual pages for SSL_* function. ++ [Lutz Jaenicke] ++ ++ Changes between 0.9.5a and 0.9.6 [24 Sep 2000] ++ ++ *) In ssl23_get_client_hello, generate an error message when faced ++ with an initial SSL 3.0/TLS record that is too small to contain the ++ first two bytes of the ClientHello message, i.e. client_version. ++ (Note that this is a pathologic case that probably has never happened ++ in real life.) The previous approach was to use the version number ++ from the record header as a substitute; but our protocol choice ++ should not depend on that one because it is not authenticated ++ by the Finished messages. ++ [Bodo Moeller] ++ ++ *) More robust randomness gathering functions for Windows. ++ [Jeffrey Altman ] ++ ++ *) For compatibility reasons if the flag X509_V_FLAG_ISSUER_CHECK is ++ not set then we don't setup the error code for issuer check errors ++ to avoid possibly overwriting other errors which the callback does ++ handle. If an application does set the flag then we assume it knows ++ what it is doing and can handle the new informational codes ++ appropriately. ++ [Steve Henson] ++ ++ *) Fix for a nasty bug in ASN1_TYPE handling. ASN1_TYPE is used for ++ a general "ANY" type, as such it should be able to decode anything ++ including tagged types. However it didn't check the class so it would ++ wrongly interpret tagged types in the same way as their universal ++ counterpart and unknown types were just rejected. Changed so that the ++ tagged and unknown types are handled in the same way as a SEQUENCE: ++ that is the encoding is stored intact. There is also a new type ++ "V_ASN1_OTHER" which is used when the class is not universal, in this ++ case we have no idea what the actual type is so we just lump them all ++ together. ++ [Steve Henson] ++ ++ *) On VMS, stdout may very well lead to a file that is written to ++ in a record-oriented fashion. That means that every write() will ++ write a separate record, which will be read separately by the ++ programs trying to read from it. This can be very confusing. ++ ++ The solution is to put a BIO filter in the way that will buffer ++ text until a linefeed is reached, and then write everything a ++ line at a time, so every record written will be an actual line, ++ not chunks of lines and not (usually doesn't happen, but I've ++ seen it once) several lines in one record. BIO_f_linebuffer() is ++ the answer. ++ ++ Currently, it's a VMS-only method, because that's where it has ++ been tested well enough. ++ [Richard Levitte] ++ ++ *) Remove 'optimized' squaring variant in BN_mod_mul_montgomery, ++ it can return incorrect results. ++ (Note: The buggy variant was not enabled in OpenSSL 0.9.5a, ++ but it was in 0.9.6-beta[12].) ++ [Bodo Moeller] ++ ++ *) Disable the check for content being present when verifying detached ++ signatures in pk7_smime.c. Some versions of Netscape (wrongly) ++ include zero length content when signing messages. ++ [Steve Henson] ++ ++ *) New BIO_shutdown_wr macro, which invokes the BIO_C_SHUTDOWN_WR ++ BIO_ctrl (for BIO pairs). ++ [Bodo Möller] ++ ++ *) Add DSO method for VMS. ++ [Richard Levitte] ++ ++ *) Bug fix: Montgomery multiplication could produce results with the ++ wrong sign. ++ [Ulf Möller] ++ ++ *) Add RPM specification openssl.spec and modify it to build three ++ packages. The default package contains applications, application ++ documentation and run-time libraries. The devel package contains ++ include files, static libraries and function documentation. The ++ doc package contains the contents of the doc directory. The original ++ openssl.spec was provided by Damien Miller . ++ [Richard Levitte] ++ ++ *) Add a large number of documentation files for many SSL routines. ++ [Lutz Jaenicke ] ++ ++ *) Add a configuration entry for Sony News 4. ++ [NAKAJI Hiroyuki ] ++ ++ *) Don't set the two most significant bits to one when generating a ++ random number < q in the DSA library. ++ [Ulf Möller] ++ ++ *) New SSL API mode 'SSL_MODE_AUTO_RETRY'. This disables the default ++ behaviour that SSL_read may result in SSL_ERROR_WANT_READ (even if ++ the underlying transport is blocking) if a handshake took place. ++ (The default behaviour is needed by applications such as s_client ++ and s_server that use select() to determine when to use SSL_read; ++ but for applications that know in advance when to expect data, it ++ just makes things more complicated.) ++ [Bodo Moeller] ++ ++ *) Add RAND_egd_bytes(), which gives control over the number of bytes read ++ from EGD. ++ [Ben Laurie] ++ ++ *) Add a few more EBCDIC conditionals that make `req' and `x509' ++ work better on such systems. ++ [Martin Kraemer ] ++ ++ *) Add two demo programs for PKCS12_parse() and PKCS12_create(). ++ Update PKCS12_parse() so it copies the friendlyName and the ++ keyid to the certificates aux info. ++ [Steve Henson] ++ ++ *) Fix bug in PKCS7_verify() which caused an infinite loop ++ if there was more than one signature. ++ [Sven Uszpelkat ] ++ ++ *) Major change in util/mkdef.pl to include extra information ++ about each symbol, as well as presenting variables as well ++ as functions. This change means that there's n more need ++ to rebuild the .num files when some algorithms are excluded. ++ [Richard Levitte] ++ ++ *) Allow the verify time to be set by an application, ++ rather than always using the current time. ++ [Steve Henson] ++ ++ *) Phase 2 verify code reorganisation. The certificate ++ verify code now looks up an issuer certificate by a ++ number of criteria: subject name, authority key id ++ and key usage. It also verifies self signed certificates ++ by the same criteria. The main comparison function is ++ X509_check_issued() which performs these checks. ++ ++ Lot of changes were necessary in order to support this ++ without completely rewriting the lookup code. ++ ++ Authority and subject key identifier are now cached. ++ ++ The LHASH 'certs' is X509_STORE has now been replaced ++ by a STACK_OF(X509_OBJECT). This is mainly because an ++ LHASH can't store or retrieve multiple objects with ++ the same hash value. ++ ++ As a result various functions (which were all internal ++ use only) have changed to handle the new X509_STORE ++ structure. This will break anything that messed round ++ with X509_STORE internally. ++ ++ The functions X509_STORE_add_cert() now checks for an ++ exact match, rather than just subject name. ++ ++ The X509_STORE API doesn't directly support the retrieval ++ of multiple certificates matching a given criteria, however ++ this can be worked round by performing a lookup first ++ (which will fill the cache with candidate certificates) ++ and then examining the cache for matches. This is probably ++ the best we can do without throwing out X509_LOOKUP ++ entirely (maybe later...). ++ ++ The X509_VERIFY_CTX structure has been enhanced considerably. ++ ++ All certificate lookup operations now go via a get_issuer() ++ callback. Although this currently uses an X509_STORE it ++ can be replaced by custom lookups. This is a simple way ++ to bypass the X509_STORE hackery necessary to make this ++ work and makes it possible to use more efficient techniques ++ in future. A very simple version which uses a simple ++ STACK for its trusted certificate store is also provided ++ using X509_STORE_CTX_trusted_stack(). ++ ++ The verify_cb() and verify() callbacks now have equivalents ++ in the X509_STORE_CTX structure. ++ ++ X509_STORE_CTX also has a 'flags' field which can be used ++ to customise the verify behaviour. ++ [Steve Henson] ++ ++ *) Add new PKCS#7 signing option PKCS7_NOSMIMECAP which ++ excludes S/MIME capabilities. ++ [Steve Henson] ++ ++ *) When a certificate request is read in keep a copy of the ++ original encoding of the signed data and use it when outputting ++ again. Signatures then use the original encoding rather than ++ a decoded, encoded version which may cause problems if the ++ request is improperly encoded. ++ [Steve Henson] ++ ++ *) For consistency with other BIO_puts implementations, call ++ buffer_write(b, ...) directly in buffer_puts instead of calling ++ BIO_write(b, ...). ++ ++ In BIO_puts, increment b->num_write as in BIO_write. ++ [Peter.Sylvester@EdelWeb.fr] ++ ++ *) Fix BN_mul_word for the case where the word is 0. (We have to use ++ BN_zero, we may not return a BIGNUM with an array consisting of ++ words set to zero.) ++ [Bodo Moeller] ++ ++ *) Avoid calling abort() from within the library when problems are ++ detected, except if preprocessor symbols have been defined ++ (such as REF_CHECK, BN_DEBUG etc.). ++ [Bodo Moeller] ++ ++ *) New openssl application 'rsautl'. This utility can be ++ used for low level RSA operations. DER public key ++ BIO/fp routines also added. ++ [Steve Henson] ++ ++ *) New Configure entry and patches for compiling on QNX 4. ++ [Andreas Schneider ] ++ ++ *) A demo state-machine implementation was sponsored by ++ Nuron (http://www.nuron.com/) and is now available in ++ demos/state_machine. ++ [Ben Laurie] ++ ++ *) New options added to the 'dgst' utility for signature ++ generation and verification. ++ [Steve Henson] ++ ++ *) Unrecognized PKCS#7 content types are now handled via a ++ catch all ASN1_TYPE structure. This allows unsupported ++ types to be stored as a "blob" and an application can ++ encode and decode it manually. ++ [Steve Henson] ++ ++ *) Fix various signed/unsigned issues to make a_strex.c ++ compile under VC++. ++ [Oscar Jacobsson ] ++ ++ *) ASN1 fixes. i2d_ASN1_OBJECT was not returning the correct ++ length if passed a buffer. ASN1_INTEGER_to_BN failed ++ if passed a NULL BN and its argument was negative. ++ [Steve Henson, pointed out by Sven Heiberg ] ++ ++ *) Modification to PKCS#7 encoding routines to output definite ++ length encoding. Since currently the whole structures are in ++ memory there's not real point in using indefinite length ++ constructed encoding. However if OpenSSL is compiled with ++ the flag PKCS7_INDEFINITE_ENCODING the old form is used. ++ [Steve Henson] ++ ++ *) Added BIO_vprintf() and BIO_vsnprintf(). ++ [Richard Levitte] ++ ++ *) Added more prefixes to parse for in the the strings written ++ through a logging bio, to cover all the levels that are available ++ through syslog. The prefixes are now: ++ ++ PANIC, EMERG, EMR => LOG_EMERG ++ ALERT, ALR => LOG_ALERT ++ CRIT, CRI => LOG_CRIT ++ ERROR, ERR => LOG_ERR ++ WARNING, WARN, WAR => LOG_WARNING ++ NOTICE, NOTE, NOT => LOG_NOTICE ++ INFO, INF => LOG_INFO ++ DEBUG, DBG => LOG_DEBUG ++ ++ and as before, if none of those prefixes are present at the ++ beginning of the string, LOG_ERR is chosen. ++ ++ On Win32, the LOG_* levels are mapped according to this: ++ ++ LOG_EMERG, LOG_ALERT, LOG_CRIT, LOG_ERR => EVENTLOG_ERROR_TYPE ++ LOG_WARNING => EVENTLOG_WARNING_TYPE ++ LOG_NOTICE, LOG_INFO, LOG_DEBUG => EVENTLOG_INFORMATION_TYPE ++ ++ [Richard Levitte] ++ ++ *) Made it possible to reconfigure with just the configuration ++ argument "reconf" or "reconfigure". The command line arguments ++ are stored in Makefile.ssl in the variable CONFIGURE_ARGS, ++ and are retrieved from there when reconfiguring. ++ [Richard Levitte] ++ ++ *) MD4 implemented. ++ [Assar Westerlund , Richard Levitte] ++ ++ *) Add the arguments -CAfile and -CApath to the pkcs12 utility. ++ [Richard Levitte] ++ ++ *) The obj_dat.pl script was messing up the sorting of object ++ names. The reason was that it compared the quoted version ++ of strings as a result "OCSP" > "OCSP Signing" because ++ " > SPACE. Changed script to store unquoted versions of ++ names and add quotes on output. It was also omitting some ++ names from the lookup table if they were given a default ++ value (that is if SN is missing it is given the same ++ value as LN and vice versa), these are now added on the ++ grounds that if an object has a name we should be able to ++ look it up. Finally added warning output when duplicate ++ short or long names are found. ++ [Steve Henson] ++ ++ *) Changes needed for Tandem NSK. ++ [Scott Uroff ] ++ ++ *) Fix SSL 2.0 rollback checking: Due to an off-by-one error in ++ RSA_padding_check_SSLv23(), special padding was never detected ++ and thus the SSL 3.0/TLS 1.0 countermeasure against protocol ++ version rollback attacks was not effective. ++ ++ In s23_clnt.c, don't use special rollback-attack detection padding ++ (RSA_SSLV23_PADDING) if SSL 2.0 is the only protocol enabled in the ++ client; similarly, in s23_srvr.c, don't do the rollback check if ++ SSL 2.0 is the only protocol enabled in the server. ++ [Bodo Moeller] ++ ++ *) Make it possible to get hexdumps of unprintable data with 'openssl ++ asn1parse'. By implication, the functions ASN1_parse_dump() and ++ BIO_dump_indent() are added. ++ [Richard Levitte] ++ ++ *) New functions ASN1_STRING_print_ex() and X509_NAME_print_ex() ++ these print out strings and name structures based on various ++ flags including RFC2253 support and proper handling of ++ multibyte characters. Added options to the 'x509' utility ++ to allow the various flags to be set. ++ [Steve Henson] ++ ++ *) Various fixes to use ASN1_TIME instead of ASN1_UTCTIME. ++ Also change the functions X509_cmp_current_time() and ++ X509_gmtime_adj() work with an ASN1_TIME structure, ++ this will enable certificates using GeneralizedTime in validity ++ dates to be checked. ++ [Steve Henson] ++ ++ *) Make the NEG_PUBKEY_BUG code (which tolerates invalid ++ negative public key encodings) on by default, ++ NO_NEG_PUBKEY_BUG can be set to disable it. ++ [Steve Henson] ++ ++ *) New function c2i_ASN1_OBJECT() which acts on ASN1_OBJECT ++ content octets. An i2c_ASN1_OBJECT is unnecessary because ++ the encoding can be trivially obtained from the structure. ++ [Steve Henson] ++ ++ *) crypto/err.c locking bugfix: Use write locks (CRYPTO_w_[un]lock), ++ not read locks (CRYPTO_r_[un]lock). ++ [Bodo Moeller] ++ ++ *) A first attempt at creating official support for shared ++ libraries through configuration. I've kept it so the ++ default is static libraries only, and the OpenSSL programs ++ are always statically linked for now, but there are ++ preparations for dynamic linking in place. ++ This has been tested on Linux and Tru64. ++ [Richard Levitte] ++ ++ *) Randomness polling function for Win9x, as described in: ++ Peter Gutmann, Software Generation of Practically Strong ++ Random Numbers. ++ [Ulf Möller] ++ ++ *) Fix so PRNG is seeded in req if using an already existing ++ DSA key. ++ [Steve Henson] ++ ++ *) New options to smime application. -inform and -outform ++ allow alternative formats for the S/MIME message including ++ PEM and DER. The -content option allows the content to be ++ specified separately. This should allow things like Netscape ++ form signing output easier to verify. ++ [Steve Henson] ++ ++ *) Fix the ASN1 encoding of tags using the 'long form'. ++ [Steve Henson] ++ ++ *) New ASN1 functions, i2c_* and c2i_* for INTEGER and BIT ++ STRING types. These convert content octets to and from the ++ underlying type. The actual tag and length octets are ++ already assumed to have been read in and checked. These ++ are needed because all other string types have virtually ++ identical handling apart from the tag. By having versions ++ of the ASN1 functions that just operate on content octets ++ IMPLICIT tagging can be handled properly. It also allows ++ the ASN1_ENUMERATED code to be cut down because ASN1_ENUMERATED ++ and ASN1_INTEGER are identical apart from the tag. ++ [Steve Henson] ++ ++ *) Change the handling of OID objects as follows: ++ ++ - New object identifiers are inserted in objects.txt, following ++ the syntax given in objects.README. ++ - objects.pl is used to process obj_mac.num and create a new ++ obj_mac.h. ++ - obj_dat.pl is used to create a new obj_dat.h, using the data in ++ obj_mac.h. ++ ++ This is currently kind of a hack, and the perl code in objects.pl ++ isn't very elegant, but it works as I intended. The simplest way ++ to check that it worked correctly is to look in obj_dat.h and ++ check the array nid_objs and make sure the objects haven't moved ++ around (this is important!). Additions are OK, as well as ++ consistent name changes. ++ [Richard Levitte] ++ ++ *) Add BSD-style MD5-based passwords to 'openssl passwd' (option '-1'). ++ [Bodo Moeller] ++ ++ *) Addition of the command line parameter '-rand file' to 'openssl req'. ++ The given file adds to whatever has already been seeded into the ++ random pool through the RANDFILE configuration file option or ++ environment variable, or the default random state file. ++ [Richard Levitte] ++ ++ *) mkstack.pl now sorts each macro group into lexical order. ++ Previously the output order depended on the order the files ++ appeared in the directory, resulting in needless rewriting ++ of safestack.h . ++ [Steve Henson] ++ ++ *) Patches to make OpenSSL compile under Win32 again. Mostly ++ work arounds for the VC++ problem that it treats func() as ++ func(void). Also stripped out the parts of mkdef.pl that ++ added extra typesafe functions: these no longer exist. ++ [Steve Henson] ++ ++ *) Reorganisation of the stack code. The macros are now all ++ collected in safestack.h . Each macro is defined in terms of ++ a "stack macro" of the form SKM_(type, a, b). The ++ DEBUG_SAFESTACK is now handled in terms of function casts, ++ this has the advantage of retaining type safety without the ++ use of additional functions. If DEBUG_SAFESTACK is not defined ++ then the non typesafe macros are used instead. Also modified the ++ mkstack.pl script to handle the new form. Needs testing to see ++ if which (if any) compilers it chokes and maybe make DEBUG_SAFESTACK ++ the default if no major problems. Similar behaviour for ASN1_SET_OF ++ and PKCS12_STACK_OF. ++ [Steve Henson] ++ ++ *) When some versions of IIS use the 'NET' form of private key the ++ key derivation algorithm is different. Normally MD5(password) is ++ used as a 128 bit RC4 key. In the modified case ++ MD5(MD5(password) + "SGCKEYSALT") is used instead. Added some ++ new functions i2d_RSA_NET(), d2i_RSA_NET() etc which are the same ++ as the old Netscape_RSA functions except they have an additional ++ 'sgckey' parameter which uses the modified algorithm. Also added ++ an -sgckey command line option to the rsa utility. Thanks to ++ Adrian Peck for posting details of the modified ++ algorithm to openssl-dev. ++ [Steve Henson] ++ ++ *) The evp_local.h macros were using 'c.##kname' which resulted in ++ invalid expansion on some systems (SCO 5.0.5 for example). ++ Corrected to 'c.kname'. ++ [Phillip Porch ] ++ ++ *) New X509_get1_email() and X509_REQ_get1_email() functions that return ++ a STACK of email addresses from a certificate or request, these look ++ in the subject name and the subject alternative name extensions and ++ omit any duplicate addresses. ++ [Steve Henson] ++ ++ *) Re-implement BN_mod_exp2_mont using independent (and larger) windows. ++ This makes DSA verification about 2 % faster. ++ [Bodo Moeller] ++ ++ *) Increase maximum window size in BN_mod_exp_... to 6 bits instead of 5 ++ (meaning that now 2^5 values will be precomputed, which is only 4 KB ++ plus overhead for 1024 bit moduli). ++ This makes exponentiations about 0.5 % faster for 1024 bit ++ exponents (as measured by "openssl speed rsa2048"). ++ [Bodo Moeller] ++ ++ *) Rename memory handling macros to avoid conflicts with other ++ software: ++ Malloc => OPENSSL_malloc ++ Malloc_locked => OPENSSL_malloc_locked ++ Realloc => OPENSSL_realloc ++ Free => OPENSSL_free ++ [Richard Levitte] ++ ++ *) New function BN_mod_exp_mont_word for small bases (roughly 15% ++ faster than BN_mod_exp_mont, i.e. 7% for a full DH exchange). ++ [Bodo Moeller] ++ ++ *) CygWin32 support. ++ [John Jarvie ] ++ ++ *) The type-safe stack code has been rejigged. It is now only compiled ++ in when OpenSSL is configured with the DEBUG_SAFESTACK option and ++ by default all type-specific stack functions are "#define"d back to ++ standard stack functions. This results in more streamlined output ++ but retains the type-safety checking possibilities of the original ++ approach. ++ [Geoff Thorpe] ++ ++ *) The STACK code has been cleaned up, and certain type declarations ++ that didn't make a lot of sense have been brought in line. This has ++ also involved a cleanup of sorts in safestack.h to more correctly ++ map type-safe stack functions onto their plain stack counterparts. ++ This work has also resulted in a variety of "const"ifications of ++ lots of the code, especially "_cmp" operations which should normally ++ be prototyped with "const" parameters anyway. ++ [Geoff Thorpe] ++ ++ *) When generating bytes for the first time in md_rand.c, 'stir the pool' ++ by seeding with STATE_SIZE dummy bytes (with zero entropy count). ++ (The PRNG state consists of two parts, the large pool 'state' and 'md', ++ where all of 'md' is used each time the PRNG is used, but 'state' ++ is used only indexed by a cyclic counter. As entropy may not be ++ well distributed from the beginning, 'md' is important as a ++ chaining variable. However, the output function chains only half ++ of 'md', i.e. 80 bits. ssleay_rand_add, on the other hand, chains ++ all of 'md', and seeding with STATE_SIZE dummy bytes will result ++ in all of 'state' being rewritten, with the new values depending ++ on virtually all of 'md'. This overcomes the 80 bit limitation.) ++ [Bodo Moeller] ++ ++ *) In ssl/s2_clnt.c and ssl/s3_clnt.c, call ERR_clear_error() when ++ the handshake is continued after ssl_verify_cert_chain(); ++ otherwise, if SSL_VERIFY_NONE is set, remaining error codes ++ can lead to 'unexplainable' connection aborts later. ++ [Bodo Moeller; problem tracked down by Lutz Jaenicke] ++ ++ *) Major EVP API cipher revision. ++ Add hooks for extra EVP features. This allows various cipher ++ parameters to be set in the EVP interface. Support added for variable ++ key length ciphers via the EVP_CIPHER_CTX_set_key_length() function and ++ setting of RC2 and RC5 parameters. ++ ++ Modify EVP_OpenInit() and EVP_SealInit() to cope with variable key length ++ ciphers. ++ ++ Remove lots of duplicated code from the EVP library. For example *every* ++ cipher init() function handles the 'iv' in the same way according to the ++ cipher mode. They also all do nothing if the 'key' parameter is NULL and ++ for CFB and OFB modes they zero ctx->num. ++ ++ New functionality allows removal of S/MIME code RC2 hack. ++ ++ Most of the routines have the same form and so can be declared in terms ++ of macros. ++ ++ By shifting this to the top level EVP_CipherInit() it can be removed from ++ all individual ciphers. If the cipher wants to handle IVs or keys ++ differently it can set the EVP_CIPH_CUSTOM_IV or EVP_CIPH_ALWAYS_CALL_INIT ++ flags. ++ ++ Change lots of functions like EVP_EncryptUpdate() to now return a ++ value: although software versions of the algorithms cannot fail ++ any installed hardware versions can. ++ [Steve Henson] ++ ++ *) Implement SSL_OP_TLS_ROLLBACK_BUG: In ssl3_get_client_key_exchange, if ++ this option is set, tolerate broken clients that send the negotiated ++ protocol version number instead of the requested protocol version ++ number. ++ [Bodo Moeller] ++ ++ *) Call dh_tmp_cb (set by ..._TMP_DH_CB) with correct 'is_export' flag; ++ i.e. non-zero for export ciphersuites, zero otherwise. ++ Previous versions had this flag inverted, inconsistent with ++ rsa_tmp_cb (..._TMP_RSA_CB). ++ [Bodo Moeller; problem reported by Amit Chopra] ++ ++ *) Add missing DSA library text string. Work around for some IIS ++ key files with invalid SEQUENCE encoding. ++ [Steve Henson] ++ ++ *) Add a document (doc/standards.txt) that list all kinds of standards ++ and so on that are implemented in OpenSSL. ++ [Richard Levitte] ++ ++ *) Enhance c_rehash script. Old version would mishandle certificates ++ with the same subject name hash and wouldn't handle CRLs at all. ++ Added -fingerprint option to crl utility, to support new c_rehash ++ features. ++ [Steve Henson] ++ ++ *) Eliminate non-ANSI declarations in crypto.h and stack.h. ++ [Ulf Möller] ++ ++ *) Fix for SSL server purpose checking. Server checking was ++ rejecting certificates which had extended key usage present ++ but no ssl client purpose. ++ [Steve Henson, reported by Rene Grosser ] ++ ++ *) Make PKCS#12 code work with no password. The PKCS#12 spec ++ is a little unclear about how a blank password is handled. ++ Since the password in encoded as a BMPString with terminating ++ double NULL a zero length password would end up as just the ++ double NULL. However no password at all is different and is ++ handled differently in the PKCS#12 key generation code. NS ++ treats a blank password as zero length. MSIE treats it as no ++ password on export: but it will try both on import. We now do ++ the same: PKCS12_parse() tries zero length and no password if ++ the password is set to "" or NULL (NULL is now a valid password: ++ it wasn't before) as does the pkcs12 application. ++ [Steve Henson] ++ ++ *) Bugfixes in apps/x509.c: Avoid a memory leak; and don't use ++ perror when PEM_read_bio_X509_REQ fails, the error message must ++ be obtained from the error queue. ++ [Bodo Moeller] ++ ++ *) Avoid 'thread_hash' memory leak in crypto/err/err.c by freeing ++ it in ERR_remove_state if appropriate, and change ERR_get_state ++ accordingly to avoid race conditions (this is necessary because ++ thread_hash is no longer constant once set). ++ [Bodo Moeller] ++ ++ *) Bugfix for linux-elf makefile.one. ++ [Ulf Möller] ++ ++ *) RSA_get_default_method() will now cause a default ++ RSA_METHOD to be chosen if one doesn't exist already. ++ Previously this was only set during a call to RSA_new() ++ or RSA_new_method(NULL) meaning it was possible for ++ RSA_get_default_method() to return NULL. ++ [Geoff Thorpe] ++ ++ *) Added native name translation to the existing DSO code ++ that will convert (if the flag to do so is set) filenames ++ that are sufficiently small and have no path information ++ into a canonical native form. Eg. "blah" converted to ++ "libblah.so" or "blah.dll" etc. ++ [Geoff Thorpe] ++ ++ *) New function ERR_error_string_n(e, buf, len) which is like ++ ERR_error_string(e, buf), but writes at most 'len' bytes ++ including the 0 terminator. For ERR_error_string_n, 'buf' ++ may not be NULL. ++ [Damien Miller , Bodo Moeller] ++ ++ *) CONF library reworked to become more general. A new CONF ++ configuration file reader "class" is implemented as well as a ++ new functions (NCONF_*, for "New CONF") to handle it. The now ++ old CONF_* functions are still there, but are reimplemented to ++ work in terms of the new functions. Also, a set of functions ++ to handle the internal storage of the configuration data is ++ provided to make it easier to write new configuration file ++ reader "classes" (I can definitely see something reading a ++ configuration file in XML format, for example), called _CONF_*, ++ or "the configuration storage API"... ++ ++ The new configuration file reading functions are: ++ ++ NCONF_new, NCONF_free, NCONF_load, NCONF_load_fp, NCONF_load_bio, ++ NCONF_get_section, NCONF_get_string, NCONF_get_numbre ++ ++ NCONF_default, NCONF_WIN32 ++ ++ NCONF_dump_fp, NCONF_dump_bio ++ ++ NCONF_default and NCONF_WIN32 are method (or "class") choosers, ++ NCONF_new creates a new CONF object. This works in the same way ++ as other interfaces in OpenSSL, like the BIO interface. ++ NCONF_dump_* dump the internal storage of the configuration file, ++ which is useful for debugging. All other functions take the same ++ arguments as the old CONF_* functions wth the exception of the ++ first that must be a `CONF *' instead of a `LHASH *'. ++ ++ To make it easer to use the new classes with the old CONF_* functions, ++ the function CONF_set_default_method is provided. ++ [Richard Levitte] ++ ++ *) Add '-tls1' option to 'openssl ciphers', which was already ++ mentioned in the documentation but had not been implemented. ++ (This option is not yet really useful because even the additional ++ experimental TLS 1.0 ciphers are currently treated as SSL 3.0 ciphers.) ++ [Bodo Moeller] ++ ++ *) Initial DSO code added into libcrypto for letting OpenSSL (and ++ OpenSSL-based applications) load shared libraries and bind to ++ them in a portable way. ++ [Geoff Thorpe, with contributions from Richard Levitte] ++ ++ Changes between 0.9.5 and 0.9.5a [1 Apr 2000] ++ ++ *) Make sure _lrotl and _lrotr are only used with MSVC. ++ ++ *) Use lock CRYPTO_LOCK_RAND correctly in ssleay_rand_status ++ (the default implementation of RAND_status). ++ ++ *) Rename openssl x509 option '-crlext', which was added in 0.9.5, ++ to '-clrext' (= clear extensions), as intended and documented. ++ [Bodo Moeller; inconsistency pointed out by Michael Attili ++ ] ++ ++ *) Fix for HMAC. It wasn't zeroing the rest of the block if the key length ++ was larger than the MD block size. ++ [Steve Henson, pointed out by Yost William ] ++ ++ *) Modernise PKCS12_parse() so it uses STACK_OF(X509) for its ca argument ++ fix a leak when the ca argument was passed as NULL. Stop X509_PUBKEY_set() ++ using the passed key: if the passed key was a private key the result ++ of X509_print(), for example, would be to print out all the private key ++ components. ++ [Steve Henson] ++ ++ *) des_quad_cksum() byte order bug fix. ++ [Ulf Möller, using the problem description in krb4-0.9.7, where ++ the solution is attributed to Derrick J Brashear ] ++ ++ *) Fix so V_ASN1_APP_CHOOSE works again: however its use is strongly ++ discouraged. ++ [Steve Henson, pointed out by Brian Korver ] ++ ++ *) For easily testing in shell scripts whether some command ++ 'openssl XXX' exists, the new pseudo-command 'openssl no-XXX' ++ returns with exit code 0 iff no command of the given name is available. ++ 'no-XXX' is printed in this case, 'XXX' otherwise. In both cases, ++ the output goes to stdout and nothing is printed to stderr. ++ Additional arguments are always ignored. ++ ++ Since for each cipher there is a command of the same name, ++ the 'no-cipher' compilation switches can be tested this way. ++ ++ ('openssl no-XXX' is not able to detect pseudo-commands such ++ as 'quit', 'list-XXX-commands', or 'no-XXX' itself.) ++ [Bodo Moeller] ++ ++ *) Update test suite so that 'make test' succeeds in 'no-rsa' configuration. ++ [Bodo Moeller] ++ ++ *) For SSL_[CTX_]set_tmp_dh, don't create a DH key if SSL_OP_SINGLE_DH_USE ++ is set; it will be thrown away anyway because each handshake creates ++ its own key. ++ ssl_cert_dup, which is used by SSL_new, now copies DH keys in addition ++ to parameters -- in previous versions (since OpenSSL 0.9.3) the ++ 'default key' from SSL_CTX_set_tmp_dh would always be lost, meaning ++ you effectivly got SSL_OP_SINGLE_DH_USE when using this macro. ++ [Bodo Moeller] ++ ++ *) New s_client option -ign_eof: EOF at stdin is ignored, and ++ 'Q' and 'R' lose their special meanings (quit/renegotiate). ++ This is part of what -quiet does; unlike -quiet, -ign_eof ++ does not suppress any output. ++ [Richard Levitte] ++ ++ *) Add compatibility options to the purpose and trust code. The ++ purpose X509_PURPOSE_ANY is "any purpose" which automatically ++ accepts a certificate or CA, this was the previous behaviour, ++ with all the associated security issues. ++ ++ X509_TRUST_COMPAT is the old trust behaviour: only and ++ automatically trust self signed roots in certificate store. A ++ new trust setting X509_TRUST_DEFAULT is used to specify that ++ a purpose has no associated trust setting and it should instead ++ use the value in the default purpose. ++ [Steve Henson] ++ ++ *) Fix the PKCS#8 DSA private key code so it decodes keys again ++ and fix a memory leak. ++ [Steve Henson] ++ ++ *) In util/mkerr.pl (which implements 'make errors'), preserve ++ reason strings from the previous version of the .c file, as ++ the default to have only downcase letters (and digits) in ++ automatically generated reasons codes is not always appropriate. ++ [Bodo Moeller] ++ ++ *) In ERR_load_ERR_strings(), build an ERR_LIB_SYS error reason table ++ using strerror. Previously, ERR_reason_error_string() returned ++ library names as reason strings for SYSerr; but SYSerr is a special ++ case where small numbers are errno values, not library numbers. ++ [Bodo Moeller] ++ ++ *) Add '-dsaparam' option to 'openssl dhparam' application. This ++ converts DSA parameters into DH parameters. (When creating parameters, ++ DSA_generate_parameters is used.) ++ [Bodo Moeller] ++ ++ *) Include 'length' (recommended exponent length) in C code generated ++ by 'openssl dhparam -C'. ++ [Bodo Moeller] ++ ++ *) The second argument to set_label in perlasm was already being used ++ so couldn't be used as a "file scope" flag. Moved to third argument ++ which was free. ++ [Steve Henson] ++ ++ *) In PEM_ASN1_write_bio and some other functions, use RAND_pseudo_bytes ++ instead of RAND_bytes for encryption IVs and salts. ++ [Bodo Moeller] ++ ++ *) Include RAND_status() into RAND_METHOD instead of implementing ++ it only for md_rand.c Otherwise replacing the PRNG by calling ++ RAND_set_rand_method would be impossible. ++ [Bodo Moeller] ++ ++ *) Don't let DSA_generate_key() enter an infinite loop if the random ++ number generation fails. ++ [Bodo Moeller] ++ ++ *) New 'rand' application for creating pseudo-random output. ++ [Bodo Moeller] ++ ++ *) Added configuration support for Linux/IA64 ++ [Rolf Haberrecker ] ++ ++ *) Assembler module support for Mingw32. ++ [Ulf Möller] ++ ++ *) Shared library support for HPUX (in shlib/). ++ [Lutz Jaenicke and Anonymous] ++ ++ *) Shared library support for Solaris gcc. ++ [Lutz Behnke ] ++ ++ Changes between 0.9.4 and 0.9.5 [28 Feb 2000] ++ ++ *) PKCS7_encrypt() was adding text MIME headers twice because they ++ were added manually and by SMIME_crlf_copy(). ++ [Steve Henson] ++ ++ *) In bntest.c don't call BN_rand with zero bits argument. ++ [Steve Henson, pointed out by Andrew W. Gray ] ++ ++ *) BN_mul bugfix: In bn_mul_part_recursion() only the a>a[n] && b>b[n] ++ case was implemented. This caused BN_div_recp() to fail occasionally. ++ [Ulf Möller] ++ ++ *) Add an optional second argument to the set_label() in the perl ++ assembly language builder. If this argument exists and is set ++ to 1 it signals that the assembler should use a symbol whose ++ scope is the entire file, not just the current function. This ++ is needed with MASM which uses the format label:: for this scope. ++ [Steve Henson, pointed out by Peter Runestig ] ++ ++ *) Change the ASN1 types so they are typedefs by default. Before ++ almost all types were #define'd to ASN1_STRING which was causing ++ STACK_OF() problems: you couldn't declare STACK_OF(ASN1_UTF8STRING) ++ for example. ++ [Steve Henson] ++ ++ *) Change names of new functions to the new get1/get0 naming ++ convention: After 'get1', the caller owns a reference count ++ and has to call ..._free; 'get0' returns a pointer to some ++ data structure without incrementing reference counters. ++ (Some of the existing 'get' functions increment a reference ++ counter, some don't.) ++ Similarly, 'set1' and 'add1' functions increase reference ++ counters or duplicate objects. ++ [Steve Henson] ++ ++ *) Allow for the possibility of temp RSA key generation failure: ++ the code used to assume it always worked and crashed on failure. ++ [Steve Henson] ++ ++ *) Fix potential buffer overrun problem in BIO_printf(). ++ [Ulf Möller, using public domain code by Patrick Powell; problem ++ pointed out by David Sacerdote ] ++ ++ *) Support EGD . New functions ++ RAND_egd() and RAND_status(). In the command line application, ++ the EGD socket can be specified like a seed file using RANDFILE ++ or -rand. ++ [Ulf Möller] ++ ++ *) Allow the string CERTIFICATE to be tolerated in PKCS#7 structures. ++ Some CAs (e.g. Verisign) distribute certificates in this form. ++ [Steve Henson] ++ ++ *) Remove the SSL_ALLOW_ADH compile option and set the default cipher ++ list to exclude them. This means that no special compilation option ++ is needed to use anonymous DH: it just needs to be included in the ++ cipher list. ++ [Steve Henson] ++ ++ *) Change the EVP_MD_CTX_type macro so its meaning consistent with ++ EVP_MD_type. The old functionality is available in a new macro called ++ EVP_MD_md(). Change code that uses it and update docs. ++ [Steve Henson] ++ ++ *) ..._ctrl functions now have corresponding ..._callback_ctrl functions ++ where the 'void *' argument is replaced by a function pointer argument. ++ Previously 'void *' was abused to point to functions, which works on ++ many platforms, but is not correct. As these functions are usually ++ called by macros defined in OpenSSL header files, most source code ++ should work without changes. ++ [Richard Levitte] ++ ++ *) (which is created by Configure) now contains ++ sections with information on -D... compiler switches used for ++ compiling the library so that applications can see them. To enable ++ one of these sections, a pre-processor symbol OPENSSL_..._DEFINES ++ must be defined. E.g., ++ #define OPENSSL_ALGORITHM_DEFINES ++ #include ++ defines all pertinent NO_ symbols, such as NO_IDEA, NO_RSA, etc. ++ [Richard Levitte, Ulf and Bodo Möller] ++ ++ *) Bugfix: Tolerate fragmentation and interleaving in the SSL 3/TLS ++ record layer. ++ [Bodo Moeller] ++ ++ *) Change the 'other' type in certificate aux info to a STACK_OF ++ X509_ALGOR. Although not an AlgorithmIdentifier as such it has ++ the required ASN1 format: arbitrary types determined by an OID. ++ [Steve Henson] ++ ++ *) Add some PEM_write_X509_REQ_NEW() functions and a command line ++ argument to 'req'. This is not because the function is newer or ++ better than others it just uses the work 'NEW' in the certificate ++ request header lines. Some software needs this. ++ [Steve Henson] ++ ++ *) Reorganise password command line arguments: now passwords can be ++ obtained from various sources. Delete the PEM_cb function and make ++ it the default behaviour: i.e. if the callback is NULL and the ++ usrdata argument is not NULL interpret it as a null terminated pass ++ phrase. If usrdata and the callback are NULL then the pass phrase ++ is prompted for as usual. ++ [Steve Henson] ++ ++ *) Add support for the Compaq Atalla crypto accelerator. If it is installed, ++ the support is automatically enabled. The resulting binaries will ++ autodetect the card and use it if present. ++ [Ben Laurie and Compaq Inc.] ++ ++ *) Work around for Netscape hang bug. This sends certificate request ++ and server done in one record. Since this is perfectly legal in the ++ SSL/TLS protocol it isn't a "bug" option and is on by default. See ++ the bugs/SSLv3 entry for more info. ++ [Steve Henson] ++ ++ *) HP-UX tune-up: new unified configs, HP C compiler bug workaround. ++ [Andy Polyakov] ++ ++ *) Add -rand argument to smime and pkcs12 applications and read/write ++ of seed file. ++ [Steve Henson] ++ ++ *) New 'passwd' tool for crypt(3) and apr1 password hashes. ++ [Bodo Moeller] ++ ++ *) Add command line password options to the remaining applications. ++ [Steve Henson] ++ ++ *) Bug fix for BN_div_recp() for numerators with an even number of ++ bits. ++ [Ulf Möller] ++ ++ *) More tests in bntest.c, and changed test_bn output. ++ [Ulf Möller] ++ ++ *) ./config recognizes MacOS X now. ++ [Andy Polyakov] ++ ++ *) Bug fix for BN_div() when the first words of num and divsor are ++ equal (it gave wrong results if (rem=(n1-q*d0)&BN_MASK2) < d0). ++ [Ulf Möller] ++ ++ *) Add support for various broken PKCS#8 formats, and command line ++ options to produce them. ++ [Steve Henson] ++ ++ *) New functions BN_CTX_start(), BN_CTX_get() and BT_CTX_end() to ++ get temporary BIGNUMs from a BN_CTX. ++ [Ulf Möller] ++ ++ *) Correct return values in BN_mod_exp_mont() and BN_mod_exp2_mont() ++ for p == 0. ++ [Ulf Möller] ++ ++ *) Change the SSLeay_add_all_*() functions to OpenSSL_add_all_*() and ++ include a #define from the old name to the new. The original intent ++ was that statically linked binaries could for example just call ++ SSLeay_add_all_ciphers() to just add ciphers to the table and not ++ link with digests. This never worked because SSLeay_add_all_digests() ++ and SSLeay_add_all_ciphers() were in the same source file so calling ++ one would link with the other. They are now in separate source files. ++ [Steve Henson] ++ ++ *) Add a new -notext option to 'ca' and a -pubkey option to 'spkac'. ++ [Steve Henson] ++ ++ *) Use a less unusual form of the Miller-Rabin primality test (it used ++ a binary algorithm for exponentiation integrated into the Miller-Rabin ++ loop, our standard modexp algorithms are faster). ++ [Bodo Moeller] ++ ++ *) Support for the EBCDIC character set completed. ++ [Martin Kraemer ] ++ ++ *) Source code cleanups: use const where appropriate, eliminate casts, ++ use void * instead of char * in lhash. ++ [Ulf Möller] ++ ++ *) Bugfix: ssl3_send_server_key_exchange was not restartable ++ (the state was not changed to SSL3_ST_SW_KEY_EXCH_B, and because of ++ this the server could overwrite ephemeral keys that the client ++ has already seen). ++ [Bodo Moeller] ++ ++ *) Turn DSA_is_prime into a macro that calls BN_is_prime, ++ using 50 iterations of the Rabin-Miller test. ++ ++ DSA_generate_parameters now uses BN_is_prime_fasttest (with 50 ++ iterations of the Rabin-Miller test as required by the appendix ++ to FIPS PUB 186[-1]) instead of DSA_is_prime. ++ As BN_is_prime_fasttest includes trial division, DSA parameter ++ generation becomes much faster. ++ ++ This implies a change for the callback functions in DSA_is_prime ++ and DSA_generate_parameters: The callback function is called once ++ for each positive witness in the Rabin-Miller test, not just ++ occasionally in the inner loop; and the parameters to the ++ callback function now provide an iteration count for the outer ++ loop rather than for the current invocation of the inner loop. ++ DSA_generate_parameters additionally can call the callback ++ function with an 'iteration count' of -1, meaning that a ++ candidate has passed the trial division test (when q is generated ++ from an application-provided seed, trial division is skipped). ++ [Bodo Moeller] ++ ++ *) New function BN_is_prime_fasttest that optionally does trial ++ division before starting the Rabin-Miller test and has ++ an additional BN_CTX * argument (whereas BN_is_prime always ++ has to allocate at least one BN_CTX). ++ 'callback(1, -1, cb_arg)' is called when a number has passed the ++ trial division stage. ++ [Bodo Moeller] ++ ++ *) Fix for bug in CRL encoding. The validity dates weren't being handled ++ as ASN1_TIME. ++ [Steve Henson] ++ ++ *) New -pkcs12 option to CA.pl script to write out a PKCS#12 file. ++ [Steve Henson] ++ ++ *) New function BN_pseudo_rand(). ++ [Ulf Möller] ++ ++ *) Clean up BN_mod_mul_montgomery(): replace the broken (and unreadable) ++ bignum version of BN_from_montgomery() with the working code from ++ SSLeay 0.9.0 (the word based version is faster anyway), and clean up ++ the comments. ++ [Ulf Möller] ++ ++ *) Avoid a race condition in s2_clnt.c (function get_server_hello) that ++ made it impossible to use the same SSL_SESSION data structure in ++ SSL2 clients in multiple threads. ++ [Bodo Moeller] ++ ++ *) The return value of RAND_load_file() no longer counts bytes obtained ++ by stat(). RAND_load_file(..., -1) is new and uses the complete file ++ to seed the PRNG (previously an explicit byte count was required). ++ [Ulf Möller, Bodo Möller] ++ ++ *) Clean up CRYPTO_EX_DATA functions, some of these didn't have prototypes ++ used (char *) instead of (void *) and had casts all over the place. ++ [Steve Henson] ++ ++ *) Make BN_generate_prime() return NULL on error if ret!=NULL. ++ [Ulf Möller] ++ ++ *) Retain source code compatibility for BN_prime_checks macro: ++ BN_is_prime(..., BN_prime_checks, ...) now uses ++ BN_prime_checks_for_size to determine the appropriate number of ++ Rabin-Miller iterations. ++ [Ulf Möller] ++ ++ *) Diffie-Hellman uses "safe" primes: DH_check() return code renamed to ++ DH_CHECK_P_NOT_SAFE_PRIME. ++ (Check if this is true? OpenPGP calls them "strong".) ++ [Ulf Möller] ++ ++ *) Merge the functionality of "dh" and "gendh" programs into a new program ++ "dhparam". The old programs are retained for now but will handle DH keys ++ (instead of parameters) in future. ++ [Steve Henson] ++ ++ *) Make the ciphers, s_server and s_client programs check the return values ++ when a new cipher list is set. ++ [Steve Henson] ++ ++ *) Enhance the SSL/TLS cipher mechanism to correctly handle the TLS 56bit ++ ciphers. Before when the 56bit ciphers were enabled the sorting was ++ wrong. ++ ++ The syntax for the cipher sorting has been extended to support sorting by ++ cipher-strength (using the strength_bits hard coded in the tables). ++ The new command is "@STRENGTH" (see also doc/apps/ciphers.pod). ++ ++ Fix a bug in the cipher-command parser: when supplying a cipher command ++ string with an "undefined" symbol (neither command nor alphanumeric ++ [A-Za-z0-9], ssl_set_cipher_list used to hang in an endless loop. Now ++ an error is flagged. ++ ++ Due to the strength-sorting extension, the code of the ++ ssl_create_cipher_list() function was completely rearranged. I hope that ++ the readability was also increased :-) ++ [Lutz Jaenicke ] ++ ++ *) Minor change to 'x509' utility. The -CAcreateserial option now uses 1 ++ for the first serial number and places 2 in the serial number file. This ++ avoids problems when the root CA is created with serial number zero and ++ the first user certificate has the same issuer name and serial number ++ as the root CA. ++ [Steve Henson] ++ ++ *) Fixes to X509_ATTRIBUTE utilities, change the 'req' program so it uses ++ the new code. Add documentation for this stuff. ++ [Steve Henson] ++ ++ *) Changes to X509_ATTRIBUTE utilities. These have been renamed from ++ X509_*() to X509at_*() on the grounds that they don't handle X509 ++ structures and behave in an analogous way to the X509v3 functions: ++ they shouldn't be called directly but wrapper functions should be used ++ instead. ++ ++ So we also now have some wrapper functions that call the X509at functions ++ when passed certificate requests. (TO DO: similar things can be done with ++ PKCS#7 signed and unsigned attributes, PKCS#12 attributes and a few other ++ things. Some of these need some d2i or i2d and print functionality ++ because they handle more complex structures.) ++ [Steve Henson] ++ ++ *) Add missing #ifndefs that caused missing symbols when building libssl ++ as a shared library without RSA. Use #ifndef NO_SSL2 instead of ++ NO_RSA in ssl/s2*.c. ++ [Kris Kennaway , modified by Ulf Möller] ++ ++ *) Precautions against using the PRNG uninitialized: RAND_bytes() now ++ has a return value which indicates the quality of the random data ++ (1 = ok, 0 = not seeded). Also an error is recorded on the thread's ++ error queue. New function RAND_pseudo_bytes() generates output that is ++ guaranteed to be unique but not unpredictable. RAND_add is like ++ RAND_seed, but takes an extra argument for an entropy estimate ++ (RAND_seed always assumes full entropy). ++ [Ulf Möller] ++ ++ *) Do more iterations of Rabin-Miller probable prime test (specifically, ++ 3 for 1024-bit primes, 6 for 512-bit primes, 12 for 256-bit primes ++ instead of only 2 for all lengths; see BN_prime_checks_for_size definition ++ in crypto/bn/bn_prime.c for the complete table). This guarantees a ++ false-positive rate of at most 2^-80 for random input. ++ [Bodo Moeller] ++ ++ *) Rewrite ssl3_read_n (ssl/s3_pkt.c) avoiding a couple of bugs. ++ [Bodo Moeller] ++ ++ *) New function X509_CTX_rget_chain() (renamed to X509_CTX_get1_chain ++ in the 0.9.5 release), this returns the chain ++ from an X509_CTX structure with a dup of the stack and all ++ the X509 reference counts upped: so the stack will exist ++ after X509_CTX_cleanup() has been called. Modify pkcs12.c ++ to use this. ++ ++ Also make SSL_SESSION_print() print out the verify return ++ code. ++ [Steve Henson] ++ ++ *) Add manpage for the pkcs12 command. Also change the default ++ behaviour so MAC iteration counts are used unless the new ++ -nomaciter option is used. This improves file security and ++ only older versions of MSIE (4.0 for example) need it. ++ [Steve Henson] ++ ++ *) Honor the no-xxx Configure options when creating .DEF files. ++ [Ulf Möller] ++ ++ *) Add PKCS#10 attributes to field table: challengePassword, ++ unstructuredName and unstructuredAddress. These are taken from ++ draft PKCS#9 v2.0 but are compatible with v1.2 provided no ++ international characters are used. ++ ++ More changes to X509_ATTRIBUTE code: allow the setting of types ++ based on strings. Remove the 'loc' parameter when adding ++ attributes because these will be a SET OF encoding which is sorted ++ in ASN1 order. ++ [Steve Henson] ++ ++ *) Initial changes to the 'req' utility to allow request generation ++ automation. This will allow an application to just generate a template ++ file containing all the field values and have req construct the ++ request. ++ ++ Initial support for X509_ATTRIBUTE handling. Stacks of these are ++ used all over the place including certificate requests and PKCS#7 ++ structures. They are currently handled manually where necessary with ++ some primitive wrappers for PKCS#7. The new functions behave in a ++ manner analogous to the X509 extension functions: they allow ++ attributes to be looked up by NID and added. ++ ++ Later something similar to the X509V3 code would be desirable to ++ automatically handle the encoding, decoding and printing of the ++ more complex types. The string types like challengePassword can ++ be handled by the string table functions. ++ ++ Also modified the multi byte string table handling. Now there is ++ a 'global mask' which masks out certain types. The table itself ++ can use the flag STABLE_NO_MASK to ignore the mask setting: this ++ is useful when for example there is only one permissible type ++ (as in countryName) and using the mask might result in no valid ++ types at all. ++ [Steve Henson] ++ ++ *) Clean up 'Finished' handling, and add functions SSL_get_finished and ++ SSL_get_peer_finished to allow applications to obtain the latest ++ Finished messages sent to the peer or expected from the peer, ++ respectively. (SSL_get_peer_finished is usually the Finished message ++ actually received from the peer, otherwise the protocol will be aborted.) ++ ++ As the Finished message are message digests of the complete handshake ++ (with a total of 192 bits for TLS 1.0 and more for SSL 3.0), they can ++ be used for external authentication procedures when the authentication ++ provided by SSL/TLS is not desired or is not enough. ++ [Bodo Moeller] ++ ++ *) Enhanced support for Alpha Linux is added. Now ./config checks if ++ the host supports BWX extension and if Compaq C is present on the ++ $PATH. Just exploiting of the BWX extension results in 20-30% ++ performance kick for some algorithms, e.g. DES and RC4 to mention ++ a couple. Compaq C in turn generates ~20% faster code for MD5 and ++ SHA1. ++ [Andy Polyakov] ++ ++ *) Add support for MS "fast SGC". This is arguably a violation of the ++ SSL3/TLS protocol. Netscape SGC does two handshakes: the first with ++ weak crypto and after checking the certificate is SGC a second one ++ with strong crypto. MS SGC stops the first handshake after receiving ++ the server certificate message and sends a second client hello. Since ++ a server will typically do all the time consuming operations before ++ expecting any further messages from the client (server key exchange ++ is the most expensive) there is little difference between the two. ++ ++ To get OpenSSL to support MS SGC we have to permit a second client ++ hello message after we have sent server done. In addition we have to ++ reset the MAC if we do get this second client hello. ++ [Steve Henson] ++ ++ *) Add a function 'd2i_AutoPrivateKey()' this will automatically decide ++ if a DER encoded private key is RSA or DSA traditional format. Changed ++ d2i_PrivateKey_bio() to use it. This is only needed for the "traditional" ++ format DER encoded private key. Newer code should use PKCS#8 format which ++ has the key type encoded in the ASN1 structure. Added DER private key ++ support to pkcs8 application. ++ [Steve Henson] ++ ++ *) SSL 3/TLS 1 servers now don't request certificates when an anonymous ++ ciphersuites has been selected (as required by the SSL 3/TLS 1 ++ specifications). Exception: When SSL_VERIFY_FAIL_IF_NO_PEER_CERT ++ is set, we interpret this as a request to violate the specification ++ (the worst that can happen is a handshake failure, and 'correct' ++ behaviour would result in a handshake failure anyway). ++ [Bodo Moeller] ++ ++ *) In SSL_CTX_add_session, take into account that there might be multiple ++ SSL_SESSION structures with the same session ID (e.g. when two threads ++ concurrently obtain them from an external cache). ++ The internal cache can handle only one SSL_SESSION with a given ID, ++ so if there's a conflict, we now throw out the old one to achieve ++ consistency. ++ [Bodo Moeller] ++ ++ *) Add OIDs for idea and blowfish in CBC mode. This will allow both ++ to be used in PKCS#5 v2.0 and S/MIME. Also add checking to ++ some routines that use cipher OIDs: some ciphers do not have OIDs ++ defined and so they cannot be used for S/MIME and PKCS#5 v2.0 for ++ example. ++ [Steve Henson] ++ ++ *) Simplify the trust setting structure and code. Now we just have ++ two sequences of OIDs for trusted and rejected settings. These will ++ typically have values the same as the extended key usage extension ++ and any application specific purposes. ++ ++ The trust checking code now has a default behaviour: it will just ++ check for an object with the same NID as the passed id. Functions can ++ be provided to override either the default behaviour or the behaviour ++ for a given id. SSL client, server and email already have functions ++ in place for compatibility: they check the NID and also return "trusted" ++ if the certificate is self signed. ++ [Steve Henson] ++ ++ *) Add d2i,i2d bio/fp functions for PrivateKey: these convert the ++ traditional format into an EVP_PKEY structure. ++ [Steve Henson] ++ ++ *) Add a password callback function PEM_cb() which either prompts for ++ a password if usr_data is NULL or otherwise assumes it is a null ++ terminated password. Allow passwords to be passed on command line ++ environment or config files in a few more utilities. ++ [Steve Henson] ++ ++ *) Add a bunch of DER and PEM functions to handle PKCS#8 format private ++ keys. Add some short names for PKCS#8 PBE algorithms and allow them ++ to be specified on the command line for the pkcs8 and pkcs12 utilities. ++ Update documentation. ++ [Steve Henson] ++ ++ *) Support for ASN1 "NULL" type. This could be handled before by using ++ ASN1_TYPE but there wasn't any function that would try to read a NULL ++ and produce an error if it couldn't. For compatibility we also have ++ ASN1_NULL_new() and ASN1_NULL_free() functions but these are faked and ++ don't allocate anything because they don't need to. ++ [Steve Henson] ++ ++ *) Initial support for MacOS is now provided. Examine INSTALL.MacOS ++ for details. ++ [Andy Polyakov, Roy Woods ] ++ ++ *) Rebuild of the memory allocation routines used by OpenSSL code and ++ possibly others as well. The purpose is to make an interface that ++ provide hooks so anyone can build a separate set of allocation and ++ deallocation routines to be used by OpenSSL, for example memory ++ pool implementations, or something else, which was previously hard ++ since Malloc(), Realloc() and Free() were defined as macros having ++ the values malloc, realloc and free, respectively (except for Win32 ++ compilations). The same is provided for memory debugging code. ++ OpenSSL already comes with functionality to find memory leaks, but ++ this gives people a chance to debug other memory problems. ++ ++ With these changes, a new set of functions and macros have appeared: ++ ++ CRYPTO_set_mem_debug_functions() [F] ++ CRYPTO_get_mem_debug_functions() [F] ++ CRYPTO_dbg_set_options() [F] ++ CRYPTO_dbg_get_options() [F] ++ CRYPTO_malloc_debug_init() [M] ++ ++ The memory debug functions are NULL by default, unless the library ++ is compiled with CRYPTO_MDEBUG or friends is defined. If someone ++ wants to debug memory anyway, CRYPTO_malloc_debug_init() (which ++ gives the standard debugging functions that come with OpenSSL) or ++ CRYPTO_set_mem_debug_functions() (tells OpenSSL to use functions ++ provided by the library user) must be used. When the standard ++ debugging functions are used, CRYPTO_dbg_set_options can be used to ++ request additional information: ++ CRYPTO_dbg_set_options(V_CYRPTO_MDEBUG_xxx) corresponds to setting ++ the CRYPTO_MDEBUG_xxx macro when compiling the library. ++ ++ Also, things like CRYPTO_set_mem_functions will always give the ++ expected result (the new set of functions is used for allocation ++ and deallocation) at all times, regardless of platform and compiler ++ options. ++ ++ To finish it up, some functions that were never use in any other ++ way than through macros have a new API and new semantic: ++ ++ CRYPTO_dbg_malloc() ++ CRYPTO_dbg_realloc() ++ CRYPTO_dbg_free() ++ ++ All macros of value have retained their old syntax. ++ [Richard Levitte and Bodo Moeller] ++ ++ *) Some S/MIME fixes. The OID for SMIMECapabilities was wrong, the ++ ordering of SMIMECapabilities wasn't in "strength order" and there ++ was a missing NULL in the AlgorithmIdentifier for the SHA1 signature ++ algorithm. ++ [Steve Henson] ++ ++ *) Some ASN1 types with illegal zero length encoding (INTEGER, ++ ENUMERATED and OBJECT IDENTIFIER) choked the ASN1 routines. ++ [Frans Heymans , modified by Steve Henson] ++ ++ *) Merge in my S/MIME library for OpenSSL. This provides a simple ++ S/MIME API on top of the PKCS#7 code, a MIME parser (with enough ++ functionality to handle multipart/signed properly) and a utility ++ called 'smime' to call all this stuff. This is based on code I ++ originally wrote for Celo who have kindly allowed it to be ++ included in OpenSSL. ++ [Steve Henson] ++ ++ *) Add variants des_set_key_checked and des_set_key_unchecked of ++ des_set_key (aka des_key_sched). Global variable des_check_key ++ decides which of these is called by des_set_key; this way ++ des_check_key behaves as it always did, but applications and ++ the library itself, which was buggy for des_check_key == 1, ++ have a cleaner way to pick the version they need. ++ [Bodo Moeller] ++ ++ *) New function PKCS12_newpass() which changes the password of a ++ PKCS12 structure. ++ [Steve Henson] ++ ++ *) Modify X509_TRUST and X509_PURPOSE so it also uses a static and ++ dynamic mix. In both cases the ids can be used as an index into the ++ table. Also modified the X509_TRUST_add() and X509_PURPOSE_add() ++ functions so they accept a list of the field values and the ++ application doesn't need to directly manipulate the X509_TRUST ++ structure. ++ [Steve Henson] ++ ++ *) Modify the ASN1_STRING_TABLE stuff so it also uses bsearch and doesn't ++ need initialising. ++ [Steve Henson] ++ ++ *) Modify the way the V3 extension code looks up extensions. This now ++ works in a similar way to the object code: we have some "standard" ++ extensions in a static table which is searched with OBJ_bsearch() ++ and the application can add dynamic ones if needed. The file ++ crypto/x509v3/ext_dat.h now has the info: this file needs to be ++ updated whenever a new extension is added to the core code and kept ++ in ext_nid order. There is a simple program 'tabtest.c' which checks ++ this. New extensions are not added too often so this file can readily ++ be maintained manually. ++ ++ There are two big advantages in doing things this way. The extensions ++ can be looked up immediately and no longer need to be "added" using ++ X509V3_add_standard_extensions(): this function now does nothing. ++ [Side note: I get *lots* of email saying the extension code doesn't ++ work because people forget to call this function] ++ Also no dynamic allocation is done unless new extensions are added: ++ so if we don't add custom extensions there is no need to call ++ X509V3_EXT_cleanup(). ++ [Steve Henson] ++ ++ *) Modify enc utility's salting as follows: make salting the default. Add a ++ magic header, so unsalted files fail gracefully instead of just decrypting ++ to garbage. This is because not salting is a big security hole, so people ++ should be discouraged from doing it. ++ [Ben Laurie] ++ ++ *) Fixes and enhancements to the 'x509' utility. It allowed a message ++ digest to be passed on the command line but it only used this ++ parameter when signing a certificate. Modified so all relevant ++ operations are affected by the digest parameter including the ++ -fingerprint and -x509toreq options. Also -x509toreq choked if a ++ DSA key was used because it didn't fix the digest. ++ [Steve Henson] ++ ++ *) Initial certificate chain verify code. Currently tests the untrusted ++ certificates for consistency with the verify purpose (which is set ++ when the X509_STORE_CTX structure is set up) and checks the pathlength. ++ ++ There is a NO_CHAIN_VERIFY compilation option to keep the old behaviour: ++ this is because it will reject chains with invalid extensions whereas ++ every previous version of OpenSSL and SSLeay made no checks at all. ++ ++ Trust code: checks the root CA for the relevant trust settings. Trust ++ settings have an initial value consistent with the verify purpose: e.g. ++ if the verify purpose is for SSL client use it expects the CA to be ++ trusted for SSL client use. However the default value can be changed to ++ permit custom trust settings: one example of this would be to only trust ++ certificates from a specific "secure" set of CAs. ++ ++ Also added X509_STORE_CTX_new() and X509_STORE_CTX_free() functions ++ which should be used for version portability: especially since the ++ verify structure is likely to change more often now. ++ ++ SSL integration. Add purpose and trust to SSL_CTX and SSL and functions ++ to set them. If not set then assume SSL clients will verify SSL servers ++ and vice versa. ++ ++ Two new options to the verify program: -untrusted allows a set of ++ untrusted certificates to be passed in and -purpose which sets the ++ intended purpose of the certificate. If a purpose is set then the ++ new chain verify code is used to check extension consistency. ++ [Steve Henson] ++ ++ *) Support for the authority information access extension. ++ [Steve Henson] ++ ++ *) Modify RSA and DSA PEM read routines to transparently handle ++ PKCS#8 format private keys. New *_PUBKEY_* functions that handle ++ public keys in a format compatible with certificate ++ SubjectPublicKeyInfo structures. Unfortunately there were already ++ functions called *_PublicKey_* which used various odd formats so ++ these are retained for compatibility: however the DSA variants were ++ never in a public release so they have been deleted. Changed dsa/rsa ++ utilities to handle the new format: note no releases ever handled public ++ keys so we should be OK. ++ ++ The primary motivation for this change is to avoid the same fiasco ++ that dogs private keys: there are several incompatible private key ++ formats some of which are standard and some OpenSSL specific and ++ require various evil hacks to allow partial transparent handling and ++ even then it doesn't work with DER formats. Given the option anything ++ other than PKCS#8 should be dumped: but the other formats have to ++ stay in the name of compatibility. ++ ++ With public keys and the benefit of hindsight one standard format ++ is used which works with EVP_PKEY, RSA or DSA structures: though ++ it clearly returns an error if you try to read the wrong kind of key. ++ ++ Added a -pubkey option to the 'x509' utility to output the public key. ++ Also rename the EVP_PKEY_get_*() to EVP_PKEY_rget_*() ++ (renamed to EVP_PKEY_get1_*() in the OpenSSL 0.9.5 release) and add ++ EVP_PKEY_rset_*() functions (renamed to EVP_PKEY_set1_*()) ++ that do the same as the EVP_PKEY_assign_*() except they up the ++ reference count of the added key (they don't "swallow" the ++ supplied key). ++ [Steve Henson] ++ ++ *) Fixes to crypto/x509/by_file.c the code to read in certificates and ++ CRLs would fail if the file contained no certificates or no CRLs: ++ added a new function to read in both types and return the number ++ read: this means that if none are read it will be an error. The ++ DER versions of the certificate and CRL reader would always fail ++ because it isn't possible to mix certificates and CRLs in DER format ++ without choking one or the other routine. Changed this to just read ++ a certificate: this is the best we can do. Also modified the code ++ in apps/verify.c to take notice of return codes: it was previously ++ attempting to read in certificates from NULL pointers and ignoring ++ any errors: this is one reason why the cert and CRL reader seemed ++ to work. It doesn't check return codes from the default certificate ++ routines: these may well fail if the certificates aren't installed. ++ [Steve Henson] ++ ++ *) Code to support otherName option in GeneralName. ++ [Steve Henson] ++ ++ *) First update to verify code. Change the verify utility ++ so it warns if it is passed a self signed certificate: ++ for consistency with the normal behaviour. X509_verify ++ has been modified to it will now verify a self signed ++ certificate if *exactly* the same certificate appears ++ in the store: it was previously impossible to trust a ++ single self signed certificate. This means that: ++ openssl verify ss.pem ++ now gives a warning about a self signed certificate but ++ openssl verify -CAfile ss.pem ss.pem ++ is OK. ++ [Steve Henson] ++ ++ *) For servers, store verify_result in SSL_SESSION data structure ++ (and add it to external session representation). ++ This is needed when client certificate verifications fails, ++ but an application-provided verification callback (set by ++ SSL_CTX_set_cert_verify_callback) allows accepting the session ++ anyway (i.e. leaves x509_store_ctx->error != X509_V_OK ++ but returns 1): When the session is reused, we have to set ++ ssl->verify_result to the appropriate error code to avoid ++ security holes. ++ [Bodo Moeller, problem pointed out by Lutz Jaenicke] ++ ++ *) Fix a bug in the new PKCS#7 code: it didn't consider the ++ case in PKCS7_dataInit() where the signed PKCS7 structure ++ didn't contain any existing data because it was being created. ++ [Po-Cheng Chen , slightly modified by Steve Henson] ++ ++ *) Add a salt to the key derivation routines in enc.c. This ++ forms the first 8 bytes of the encrypted file. Also add a ++ -S option to allow a salt to be input on the command line. ++ [Steve Henson] ++ ++ *) New function X509_cmp(). Oddly enough there wasn't a function ++ to compare two certificates. We do this by working out the SHA1 ++ hash and comparing that. X509_cmp() will be needed by the trust ++ code. ++ [Steve Henson] ++ ++ *) SSL_get1_session() is like SSL_get_session(), but increments ++ the reference count in the SSL_SESSION returned. ++ [Geoff Thorpe ] ++ ++ *) Fix for 'req': it was adding a null to request attributes. ++ Also change the X509_LOOKUP and X509_INFO code to handle ++ certificate auxiliary information. ++ [Steve Henson] ++ ++ *) Add support for 40 and 64 bit RC2 and RC4 algorithms: document ++ the 'enc' command. ++ [Steve Henson] ++ ++ *) Add the possibility to add extra information to the memory leak ++ detecting output, to form tracebacks, showing from where each ++ allocation was originated: CRYPTO_push_info("constant string") adds ++ the string plus current file name and line number to a per-thread ++ stack, CRYPTO_pop_info() does the obvious, CRYPTO_remove_all_info() ++ is like calling CYRPTO_pop_info() until the stack is empty. ++ Also updated memory leak detection code to be multi-thread-safe. ++ [Richard Levitte] ++ ++ *) Add options -text and -noout to pkcs7 utility and delete the ++ encryption options which never did anything. Update docs. ++ [Steve Henson] ++ ++ *) Add options to some of the utilities to allow the pass phrase ++ to be included on either the command line (not recommended on ++ OSes like Unix) or read from the environment. Update the ++ manpages and fix a few bugs. ++ [Steve Henson] ++ ++ *) Add a few manpages for some of the openssl commands. ++ [Steve Henson] ++ ++ *) Fix the -revoke option in ca. It was freeing up memory twice, ++ leaking and not finding already revoked certificates. ++ [Steve Henson] ++ ++ *) Extensive changes to support certificate auxiliary information. ++ This involves the use of X509_CERT_AUX structure and X509_AUX ++ functions. An X509_AUX function such as PEM_read_X509_AUX() ++ can still read in a certificate file in the usual way but it ++ will also read in any additional "auxiliary information". By ++ doing things this way a fair degree of compatibility can be ++ retained: existing certificates can have this information added ++ using the new 'x509' options. ++ ++ Current auxiliary information includes an "alias" and some trust ++ settings. The trust settings will ultimately be used in enhanced ++ certificate chain verification routines: currently a certificate ++ can only be trusted if it is self signed and then it is trusted ++ for all purposes. ++ [Steve Henson] ++ ++ *) Fix assembler for Alpha (tested only on DEC OSF not Linux or *BSD). ++ The problem was that one of the replacement routines had not been working ++ since SSLeay releases. For now the offending routine has been replaced ++ with non-optimised assembler. Even so, this now gives around 95% ++ performance improvement for 1024 bit RSA signs. ++ [Mark Cox] ++ ++ *) Hack to fix PKCS#7 decryption when used with some unorthodox RC2 ++ handling. Most clients have the effective key size in bits equal to ++ the key length in bits: so a 40 bit RC2 key uses a 40 bit (5 byte) key. ++ A few however don't do this and instead use the size of the decrypted key ++ to determine the RC2 key length and the AlgorithmIdentifier to determine ++ the effective key length. In this case the effective key length can still ++ be 40 bits but the key length can be 168 bits for example. This is fixed ++ by manually forcing an RC2 key into the EVP_PKEY structure because the ++ EVP code can't currently handle unusual RC2 key sizes: it always assumes ++ the key length and effective key length are equal. ++ [Steve Henson] ++ ++ *) Add a bunch of functions that should simplify the creation of ++ X509_NAME structures. Now you should be able to do: ++ X509_NAME_add_entry_by_txt(nm, "CN", MBSTRING_ASC, "Steve", -1, -1, 0); ++ and have it automatically work out the correct field type and fill in ++ the structures. The more adventurous can try: ++ X509_NAME_add_entry_by_txt(nm, field, MBSTRING_UTF8, str, -1, -1, 0); ++ and it will (hopefully) work out the correct multibyte encoding. ++ [Steve Henson] ++ ++ *) Change the 'req' utility to use the new field handling and multibyte ++ copy routines. Before the DN field creation was handled in an ad hoc ++ way in req, ca, and x509 which was rather broken and didn't support ++ BMPStrings or UTF8Strings. Since some software doesn't implement ++ BMPStrings or UTF8Strings yet, they can be enabled using the config file ++ using the dirstring_type option. See the new comment in the default ++ openssl.cnf for more info. ++ [Steve Henson] ++ ++ *) Make crypto/rand/md_rand.c more robust: ++ - Assure unique random numbers after fork(). ++ - Make sure that concurrent threads access the global counter and ++ md serializably so that we never lose entropy in them ++ or use exactly the same state in multiple threads. ++ Access to the large state is not always serializable because ++ the additional locking could be a performance killer, and ++ md should be large enough anyway. ++ [Bodo Moeller] ++ ++ *) New file apps/app_rand.c with commonly needed functionality ++ for handling the random seed file. ++ ++ Use the random seed file in some applications that previously did not: ++ ca, ++ dsaparam -genkey (which also ignored its '-rand' option), ++ s_client, ++ s_server, ++ x509 (when signing). ++ Except on systems with /dev/urandom, it is crucial to have a random ++ seed file at least for key creation, DSA signing, and for DH exchanges; ++ for RSA signatures we could do without one. ++ ++ gendh and gendsa (unlike genrsa) used to read only the first byte ++ of each file listed in the '-rand' option. The function as previously ++ found in genrsa is now in app_rand.c and is used by all programs ++ that support '-rand'. ++ [Bodo Moeller] ++ ++ *) In RAND_write_file, use mode 0600 for creating files; ++ don't just chmod when it may be too late. ++ [Bodo Moeller] ++ ++ *) Report an error from X509_STORE_load_locations ++ when X509_LOOKUP_load_file or X509_LOOKUP_add_dir failed. ++ [Bill Perry] ++ ++ *) New function ASN1_mbstring_copy() this copies a string in either ++ ASCII, Unicode, Universal (4 bytes per character) or UTF8 format ++ into an ASN1_STRING type. A mask of permissible types is passed ++ and it chooses the "minimal" type to use or an error if not type ++ is suitable. ++ [Steve Henson] ++ ++ *) Add function equivalents to the various macros in asn1.h. The old ++ macros are retained with an M_ prefix. Code inside the library can ++ use the M_ macros. External code (including the openssl utility) ++ should *NOT* in order to be "shared library friendly". ++ [Steve Henson] ++ ++ *) Add various functions that can check a certificate's extensions ++ to see if it usable for various purposes such as SSL client, ++ server or S/MIME and CAs of these types. This is currently ++ VERY EXPERIMENTAL but will ultimately be used for certificate chain ++ verification. Also added a -purpose flag to x509 utility to ++ print out all the purposes. ++ [Steve Henson] ++ ++ *) Add a CRYPTO_EX_DATA to X509 certificate structure and associated ++ functions. ++ [Steve Henson] ++ ++ *) New X509V3_{X509,CRL,REVOKED}_get_d2i() functions. These will search ++ for, obtain and decode and extension and obtain its critical flag. ++ This allows all the necessary extension code to be handled in a ++ single function call. ++ [Steve Henson] ++ ++ *) RC4 tune-up featuring 30-40% performance improvement on most RISC ++ platforms. See crypto/rc4/rc4_enc.c for further details. ++ [Andy Polyakov] ++ ++ *) New -noout option to asn1parse. This causes no output to be produced ++ its main use is when combined with -strparse and -out to extract data ++ from a file (which may not be in ASN.1 format). ++ [Steve Henson] ++ ++ *) Fix for pkcs12 program. It was hashing an invalid certificate pointer ++ when producing the local key id. ++ [Richard Levitte ] ++ ++ *) New option -dhparam in s_server. This allows a DH parameter file to be ++ stated explicitly. If it is not stated then it tries the first server ++ certificate file. The previous behaviour hard coded the filename ++ "server.pem". ++ [Steve Henson] ++ ++ *) Add -pubin and -pubout options to the rsa and dsa commands. These allow ++ a public key to be input or output. For example: ++ openssl rsa -in key.pem -pubout -out pubkey.pem ++ Also added necessary DSA public key functions to handle this. ++ [Steve Henson] ++ ++ *) Fix so PKCS7_dataVerify() doesn't crash if no certificates are contained ++ in the message. This was handled by allowing ++ X509_find_by_issuer_and_serial() to tolerate a NULL passed to it. ++ [Steve Henson, reported by Sampo Kellomaki ] ++ ++ *) Fix for bug in d2i_ASN1_bytes(): other ASN1 functions add an extra null ++ to the end of the strings whereas this didn't. This would cause problems ++ if strings read with d2i_ASN1_bytes() were later modified. ++ [Steve Henson, reported by Arne Ansper ] ++ ++ *) Fix for base64 decode bug. When a base64 bio reads only one line of ++ data and it contains EOF it will end up returning an error. This is ++ caused by input 46 bytes long. The cause is due to the way base64 ++ BIOs find the start of base64 encoded data. They do this by trying a ++ trial decode on each line until they find one that works. When they ++ do a flag is set and it starts again knowing it can pass all the ++ data directly through the decoder. Unfortunately it doesn't reset ++ the context it uses. This means that if EOF is reached an attempt ++ is made to pass two EOFs through the context and this causes the ++ resulting error. This can also cause other problems as well. As is ++ usual with these problems it takes *ages* to find and the fix is ++ trivial: move one line. ++ [Steve Henson, reported by ian@uns.ns.ac.yu (Ivan Nejgebauer) ] ++ ++ *) Ugly workaround to get s_client and s_server working under Windows. The ++ old code wouldn't work because it needed to select() on sockets and the ++ tty (for keypresses and to see if data could be written). Win32 only ++ supports select() on sockets so we select() with a 1s timeout on the ++ sockets and then see if any characters are waiting to be read, if none ++ are present then we retry, we also assume we can always write data to ++ the tty. This isn't nice because the code then blocks until we've ++ received a complete line of data and it is effectively polling the ++ keyboard at 1s intervals: however it's quite a bit better than not ++ working at all :-) A dedicated Windows application might handle this ++ with an event loop for example. ++ [Steve Henson] ++ ++ *) Enhance RSA_METHOD structure. Now there are two extra methods, rsa_sign ++ and rsa_verify. When the RSA_FLAGS_SIGN_VER option is set these functions ++ will be called when RSA_sign() and RSA_verify() are used. This is useful ++ if rsa_pub_dec() and rsa_priv_enc() equivalents are not available. ++ For this to work properly RSA_public_decrypt() and RSA_private_encrypt() ++ should *not* be used: RSA_sign() and RSA_verify() must be used instead. ++ This necessitated the support of an extra signature type NID_md5_sha1 ++ for SSL signatures and modifications to the SSL library to use it instead ++ of calling RSA_public_decrypt() and RSA_private_encrypt(). ++ [Steve Henson] ++ ++ *) Add new -verify -CAfile and -CApath options to the crl program, these ++ will lookup a CRL issuers certificate and verify the signature in a ++ similar way to the verify program. Tidy up the crl program so it ++ no longer accesses structures directly. Make the ASN1 CRL parsing a bit ++ less strict. It will now permit CRL extensions even if it is not ++ a V2 CRL: this will allow it to tolerate some broken CRLs. ++ [Steve Henson] ++ ++ *) Initialize all non-automatic variables each time one of the openssl ++ sub-programs is started (this is necessary as they may be started ++ multiple times from the "OpenSSL>" prompt). ++ [Lennart Bang, Bodo Moeller] ++ ++ *) Preliminary compilation option RSA_NULL which disables RSA crypto without ++ removing all other RSA functionality (this is what NO_RSA does). This ++ is so (for example) those in the US can disable those operations covered ++ by the RSA patent while allowing storage and parsing of RSA keys and RSA ++ key generation. ++ [Steve Henson] ++ ++ *) Non-copying interface to BIO pairs. ++ (still largely untested) ++ [Bodo Moeller] ++ ++ *) New function ANS1_tag2str() to convert an ASN1 tag to a descriptive ++ ASCII string. This was handled independently in various places before. ++ [Steve Henson] ++ ++ *) New functions UTF8_getc() and UTF8_putc() that parse and generate ++ UTF8 strings a character at a time. ++ [Steve Henson] ++ ++ *) Use client_version from client hello to select the protocol ++ (s23_srvr.c) and for RSA client key exchange verification ++ (s3_srvr.c), as required by the SSL 3.0/TLS 1.0 specifications. ++ [Bodo Moeller] ++ ++ *) Add various utility functions to handle SPKACs, these were previously ++ handled by poking round in the structure internals. Added new function ++ NETSCAPE_SPKI_print() to print out SPKAC and a new utility 'spkac' to ++ print, verify and generate SPKACs. Based on an original idea from ++ Massimiliano Pala but extensively modified. ++ [Steve Henson] ++ ++ *) RIPEMD160 is operational on all platforms and is back in 'make test'. ++ [Andy Polyakov] ++ ++ *) Allow the config file extension section to be overwritten on the ++ command line. Based on an original idea from Massimiliano Pala ++ . The new option is called -extensions ++ and can be applied to ca, req and x509. Also -reqexts to override ++ the request extensions in req and -crlexts to override the crl extensions ++ in ca. ++ [Steve Henson] ++ ++ *) Add new feature to the SPKAC handling in ca. Now you can include ++ the same field multiple times by preceding it by "XXXX." for example: ++ 1.OU="Unit name 1" ++ 2.OU="Unit name 2" ++ this is the same syntax as used in the req config file. ++ [Steve Henson] ++ ++ *) Allow certificate extensions to be added to certificate requests. These ++ are specified in a 'req_extensions' option of the req section of the ++ config file. They can be printed out with the -text option to req but ++ are otherwise ignored at present. ++ [Steve Henson] ++ ++ *) Fix a horrible bug in enc_read() in crypto/evp/bio_enc.c: if the first ++ data read consists of only the final block it would not decrypted because ++ EVP_CipherUpdate() would correctly report zero bytes had been decrypted. ++ A misplaced 'break' also meant the decrypted final block might not be ++ copied until the next read. ++ [Steve Henson] ++ ++ *) Initial support for DH_METHOD. Again based on RSA_METHOD. Also added ++ a few extra parameters to the DH structure: these will be useful if ++ for example we want the value of 'q' or implement X9.42 DH. ++ [Steve Henson] ++ ++ *) Initial support for DSA_METHOD. This is based on the RSA_METHOD and ++ provides hooks that allow the default DSA functions or functions on a ++ "per key" basis to be replaced. This allows hardware acceleration and ++ hardware key storage to be handled without major modification to the ++ library. Also added low level modexp hooks and CRYPTO_EX structure and ++ associated functions. ++ [Steve Henson] ++ ++ *) Add a new flag to memory BIOs, BIO_FLAG_MEM_RDONLY. This marks the BIO ++ as "read only": it can't be written to and the buffer it points to will ++ not be freed. Reading from a read only BIO is much more efficient than ++ a normal memory BIO. This was added because there are several times when ++ an area of memory needs to be read from a BIO. The previous method was ++ to create a memory BIO and write the data to it, this results in two ++ copies of the data and an O(n^2) reading algorithm. There is a new ++ function BIO_new_mem_buf() which creates a read only memory BIO from ++ an area of memory. Also modified the PKCS#7 routines to use read only ++ memory BIOs. ++ [Steve Henson] ++ ++ *) Bugfix: ssl23_get_client_hello did not work properly when called in ++ state SSL23_ST_SR_CLNT_HELLO_B, i.e. when the first 7 bytes of ++ a SSLv2-compatible client hello for SSLv3 or TLSv1 could be read, ++ but a retry condition occurred while trying to read the rest. ++ [Bodo Moeller] ++ ++ *) The PKCS7_ENC_CONTENT_new() function was setting the content type as ++ NID_pkcs7_encrypted by default: this was wrong since this should almost ++ always be NID_pkcs7_data. Also modified the PKCS7_set_type() to handle ++ the encrypted data type: this is a more sensible place to put it and it ++ allows the PKCS#12 code to be tidied up that duplicated this ++ functionality. ++ [Steve Henson] ++ ++ *) Changed obj_dat.pl script so it takes its input and output files on ++ the command line. This should avoid shell escape redirection problems ++ under Win32. ++ [Steve Henson] ++ ++ *) Initial support for certificate extension requests, these are included ++ in things like Xenroll certificate requests. Included functions to allow ++ extensions to be obtained and added. ++ [Steve Henson] ++ ++ *) -crlf option to s_client and s_server for sending newlines as ++ CRLF (as required by many protocols). ++ [Bodo Moeller] ++ ++ Changes between 0.9.3a and 0.9.4 [09 Aug 1999] ++ ++ *) Install libRSAglue.a when OpenSSL is built with RSAref. ++ [Ralf S. Engelschall] ++ ++ *) A few more ``#ifndef NO_FP_API / #endif'' pairs for consistency. ++ [Andrija Antonijevic ] ++ ++ *) Fix -startdate and -enddate (which was missing) arguments to 'ca' ++ program. ++ [Steve Henson] ++ ++ *) New function DSA_dup_DH, which duplicates DSA parameters/keys as ++ DH parameters/keys (q is lost during that conversion, but the resulting ++ DH parameters contain its length). ++ ++ For 1024-bit p, DSA_generate_parameters followed by DSA_dup_DH is ++ much faster than DH_generate_parameters (which creates parameters ++ where p = 2*q + 1), and also the smaller q makes DH computations ++ much more efficient (160-bit exponentiation instead of 1024-bit ++ exponentiation); so this provides a convenient way to support DHE ++ ciphersuites in SSL/TLS servers (see ssl/ssltest.c). It is of ++ utter importance to use ++ SSL_CTX_set_options(s_ctx, SSL_OP_SINGLE_DH_USE); ++ or ++ SSL_set_options(s_ctx, SSL_OP_SINGLE_DH_USE); ++ when such DH parameters are used, because otherwise small subgroup ++ attacks may become possible! ++ [Bodo Moeller] ++ ++ *) Avoid memory leak in i2d_DHparams. ++ [Bodo Moeller] ++ ++ *) Allow the -k option to be used more than once in the enc program: ++ this allows the same encrypted message to be read by multiple recipients. ++ [Steve Henson] ++ ++ *) New function OBJ_obj2txt(buf, buf_len, a, no_name), this converts ++ an ASN1_OBJECT to a text string. If the "no_name" parameter is set then ++ it will always use the numerical form of the OID, even if it has a short ++ or long name. ++ [Steve Henson] ++ ++ *) Added an extra RSA flag: RSA_FLAG_EXT_PKEY. Previously the rsa_mod_exp ++ method only got called if p,q,dmp1,dmq1,iqmp components were present, ++ otherwise bn_mod_exp was called. In the case of hardware keys for example ++ no private key components need be present and it might store extra data ++ in the RSA structure, which cannot be accessed from bn_mod_exp. ++ By setting RSA_FLAG_EXT_PKEY rsa_mod_exp will always be called for ++ private key operations. ++ [Steve Henson] ++ ++ *) Added support for SPARC Linux. ++ [Andy Polyakov] ++ ++ *) pem_password_cb function type incompatibly changed from ++ typedef int pem_password_cb(char *buf, int size, int rwflag); ++ to ++ ....(char *buf, int size, int rwflag, void *userdata); ++ so that applications can pass data to their callbacks: ++ The PEM[_ASN1]_{read,write}... functions and macros now take an ++ additional void * argument, which is just handed through whenever ++ the password callback is called. ++ [Damien Miller ; tiny changes by Bodo Moeller] ++ ++ New function SSL_CTX_set_default_passwd_cb_userdata. ++ ++ Compatibility note: As many C implementations push function arguments ++ onto the stack in reverse order, the new library version is likely to ++ interoperate with programs that have been compiled with the old ++ pem_password_cb definition (PEM_whatever takes some data that ++ happens to be on the stack as its last argument, and the callback ++ just ignores this garbage); but there is no guarantee whatsoever that ++ this will work. ++ ++ *) The -DPLATFORM="\"$(PLATFORM)\"" definition and the similar -DCFLAGS=... ++ (both in crypto/Makefile.ssl for use by crypto/cversion.c) caused ++ problems not only on Windows, but also on some Unix platforms. ++ To avoid problematic command lines, these definitions are now in an ++ auto-generated file crypto/buildinf.h (created by crypto/Makefile.ssl ++ for standard "make" builds, by util/mk1mf.pl for "mk1mf" builds). ++ [Bodo Moeller] ++ ++ *) MIPS III/IV assembler module is reimplemented. ++ [Andy Polyakov] ++ ++ *) More DES library cleanups: remove references to srand/rand and ++ delete an unused file. ++ [Ulf Möller] ++ ++ *) Add support for the the free Netwide assembler (NASM) under Win32, ++ since not many people have MASM (ml) and it can be hard to obtain. ++ This is currently experimental but it seems to work OK and pass all ++ the tests. Check out INSTALL.W32 for info. ++ [Steve Henson] ++ ++ *) Fix memory leaks in s3_clnt.c: All non-anonymous SSL3/TLS1 connections ++ without temporary keys kept an extra copy of the server key, ++ and connections with temporary keys did not free everything in case ++ of an error. ++ [Bodo Moeller] ++ ++ *) New function RSA_check_key and new openssl rsa option -check ++ for verifying the consistency of RSA keys. ++ [Ulf Moeller, Bodo Moeller] ++ ++ *) Various changes to make Win32 compile work: ++ 1. Casts to avoid "loss of data" warnings in p5_crpt2.c ++ 2. Change unsigned int to int in b_dump.c to avoid "signed/unsigned ++ comparison" warnings. ++ 3. Add sk__sort to DEF file generator and do make update. ++ [Steve Henson] ++ ++ *) Add a debugging option to PKCS#5 v2 key generation function: when ++ you #define DEBUG_PKCS5V2 passwords, salts, iteration counts and ++ derived keys are printed to stderr. ++ [Steve Henson] ++ ++ *) Copy the flags in ASN1_STRING_dup(). ++ [Roman E. Pavlov ] ++ ++ *) The x509 application mishandled signing requests containing DSA ++ keys when the signing key was also DSA and the parameters didn't match. ++ ++ It was supposed to omit the parameters when they matched the signing key: ++ the verifying software was then supposed to automatically use the CA's ++ parameters if they were absent from the end user certificate. ++ ++ Omitting parameters is no longer recommended. The test was also ++ the wrong way round! This was probably due to unusual behaviour in ++ EVP_cmp_parameters() which returns 1 if the parameters match. ++ This meant that parameters were omitted when they *didn't* match and ++ the certificate was useless. Certificates signed with 'ca' didn't have ++ this bug. ++ [Steve Henson, reported by Doug Erickson ] ++ ++ *) Memory leak checking (-DCRYPTO_MDEBUG) had some problems. ++ The interface is as follows: ++ Applications can use ++ CRYPTO_mem_ctrl(CRYPTO_MEM_CHECK_ON) aka MemCheck_start(), ++ CRYPTO_mem_ctrl(CRYPTO_MEM_CHECK_OFF) aka MemCheck_stop(); ++ "off" is now the default. ++ The library internally uses ++ CRYPTO_mem_ctrl(CRYPTO_MEM_CHECK_DISABLE) aka MemCheck_off(), ++ CRYPTO_mem_ctrl(CRYPTO_MEM_CHECK_ENABLE) aka MemCheck_on() ++ to disable memory-checking temporarily. ++ ++ Some inconsistent states that previously were possible (and were ++ even the default) are now avoided. ++ ++ -DCRYPTO_MDEBUG_TIME is new and additionally stores the current time ++ with each memory chunk allocated; this is occasionally more helpful ++ than just having a counter. ++ ++ -DCRYPTO_MDEBUG_THREAD is also new and adds the thread ID. ++ ++ -DCRYPTO_MDEBUG_ALL enables all of the above, plus any future ++ extensions. ++ [Bodo Moeller] ++ ++ *) Introduce "mode" for SSL structures (with defaults in SSL_CTX), ++ which largely parallels "options", but is for changing API behaviour, ++ whereas "options" are about protocol behaviour. ++ Initial "mode" flags are: ++ ++ SSL_MODE_ENABLE_PARTIAL_WRITE Allow SSL_write to report success when ++ a single record has been written. ++ SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER Don't insist that SSL_write ++ retries use the same buffer location. ++ (But all of the contents must be ++ copied!) ++ [Bodo Moeller] ++ ++ *) Bugfix: SSL_set_options ignored its parameter, only SSL_CTX_set_options ++ worked. ++ ++ *) Fix problems with no-hmac etc. ++ [Ulf Möller, pointed out by Brian Wellington ] ++ ++ *) New functions RSA_get_default_method(), RSA_set_method() and ++ RSA_get_method(). These allows replacement of RSA_METHODs without having ++ to mess around with the internals of an RSA structure. ++ [Steve Henson] ++ ++ *) Fix memory leaks in DSA_do_sign and DSA_is_prime. ++ Also really enable memory leak checks in openssl.c and in some ++ test programs. ++ [Chad C. Mulligan, Bodo Moeller] ++ ++ *) Fix a bug in d2i_ASN1_INTEGER() and i2d_ASN1_INTEGER() which can mess ++ up the length of negative integers. This has now been simplified to just ++ store the length when it is first determined and use it later, rather ++ than trying to keep track of where data is copied and updating it to ++ point to the end. ++ [Steve Henson, reported by Brien Wheeler ++ ] ++ ++ *) Add a new function PKCS7_signatureVerify. This allows the verification ++ of a PKCS#7 signature but with the signing certificate passed to the ++ function itself. This contrasts with PKCS7_dataVerify which assumes the ++ certificate is present in the PKCS#7 structure. This isn't always the ++ case: certificates can be omitted from a PKCS#7 structure and be ++ distributed by "out of band" means (such as a certificate database). ++ [Steve Henson] ++ ++ *) Complete the PEM_* macros with DECLARE_PEM versions to replace the ++ function prototypes in pem.h, also change util/mkdef.pl to add the ++ necessary function names. ++ [Steve Henson] ++ ++ *) mk1mf.pl (used by Windows builds) did not properly read the ++ options set by Configure in the top level Makefile, and Configure ++ was not even able to write more than one option correctly. ++ Fixed, now "no-idea no-rc5 -DCRYPTO_MDEBUG" etc. works as intended. ++ [Bodo Moeller] ++ ++ *) New functions CONF_load_bio() and CONF_load_fp() to allow a config ++ file to be loaded from a BIO or FILE pointer. The BIO version will ++ for example allow memory BIOs to contain config info. ++ [Steve Henson] ++ ++ *) New function "CRYPTO_num_locks" that returns CRYPTO_NUM_LOCKS. ++ Whoever hopes to achieve shared-library compatibility across versions ++ must use this, not the compile-time macro. ++ (Exercise 0.9.4: Which is the minimum library version required by ++ such programs?) ++ Note: All this applies only to multi-threaded programs, others don't ++ need locks. ++ [Bodo Moeller] ++ ++ *) Add missing case to s3_clnt.c state machine -- one of the new SSL tests ++ through a BIO pair triggered the default case, i.e. ++ SSLerr(...,SSL_R_UNKNOWN_STATE). ++ [Bodo Moeller] ++ ++ *) New "BIO pair" concept (crypto/bio/bss_bio.c) so that applications ++ can use the SSL library even if none of the specific BIOs is ++ appropriate. ++ [Bodo Moeller] ++ ++ *) Fix a bug in i2d_DSAPublicKey() which meant it returned the wrong value ++ for the encoded length. ++ [Jeon KyoungHo ] ++ ++ *) Add initial documentation of the X509V3 functions. ++ [Steve Henson] ++ ++ *) Add a new pair of functions PEM_write_PKCS8PrivateKey() and ++ PEM_write_bio_PKCS8PrivateKey() that are equivalent to ++ PEM_write_PrivateKey() and PEM_write_bio_PrivateKey() but use the more ++ secure PKCS#8 private key format with a high iteration count. ++ [Steve Henson] ++ ++ *) Fix determination of Perl interpreter: A perl or perl5 ++ _directory_ in $PATH was also accepted as the interpreter. ++ [Ralf S. Engelschall] ++ ++ *) Fix demos/sign/sign.c: well there wasn't anything strictly speaking ++ wrong with it but it was very old and did things like calling ++ PEM_ASN1_read() directly and used MD5 for the hash not to mention some ++ unusual formatting. ++ [Steve Henson] ++ ++ *) Fix demos/selfsign.c: it used obsolete and deleted functions, changed ++ to use the new extension code. ++ [Steve Henson] ++ ++ *) Implement the PEM_read/PEM_write functions in crypto/pem/pem_all.c ++ with macros. This should make it easier to change their form, add extra ++ arguments etc. Fix a few PEM prototypes which didn't have cipher as a ++ constant. ++ [Steve Henson] ++ ++ *) Add to configuration table a new entry that can specify an alternative ++ name for unistd.h (for pre-POSIX systems); we need this for NeXTstep, ++ according to Mark Crispin . ++ [Bodo Moeller] ++ ++#if 0 ++ *) DES CBC did not update the IV. Weird. ++ [Ben Laurie] ++#else ++ des_cbc_encrypt does not update the IV, but des_ncbc_encrypt does. ++ Changing the behaviour of the former might break existing programs -- ++ where IV updating is needed, des_ncbc_encrypt can be used. ++#endif ++ ++ *) When bntest is run from "make test" it drives bc to check its ++ calculations, as well as internally checking them. If an internal check ++ fails, it needs to cause bc to give a non-zero result or make test carries ++ on without noticing the failure. Fixed. ++ [Ben Laurie] ++ ++ *) DES library cleanups. ++ [Ulf Möller] ++ ++ *) Add support for PKCS#5 v2.0 PBE algorithms. This will permit PKCS#8 to be ++ used with any cipher unlike PKCS#5 v1.5 which can at most handle 64 bit ++ ciphers. NOTE: although the key derivation function has been verified ++ against some published test vectors it has not been extensively tested ++ yet. Added a -v2 "cipher" option to pkcs8 application to allow the use ++ of v2.0. ++ [Steve Henson] ++ ++ *) Instead of "mkdir -p", which is not fully portable, use new ++ Perl script "util/mkdir-p.pl". ++ [Bodo Moeller] ++ ++ *) Rewrite the way password based encryption (PBE) is handled. It used to ++ assume that the ASN1 AlgorithmIdentifier parameter was a PBEParameter ++ structure. This was true for the PKCS#5 v1.5 and PKCS#12 PBE algorithms ++ but doesn't apply to PKCS#5 v2.0 where it can be something else. Now ++ the 'parameter' field of the AlgorithmIdentifier is passed to the ++ underlying key generation function so it must do its own ASN1 parsing. ++ This has also changed the EVP_PBE_CipherInit() function which now has a ++ 'parameter' argument instead of literal salt and iteration count values ++ and the function EVP_PBE_ALGOR_CipherInit() has been deleted. ++ [Steve Henson] ++ ++ *) Support for PKCS#5 v1.5 compatible password based encryption algorithms ++ and PKCS#8 functionality. New 'pkcs8' application linked to openssl. ++ Needed to change the PEM_STRING_EVP_PKEY value which was just "PRIVATE ++ KEY" because this clashed with PKCS#8 unencrypted string. Since this ++ value was just used as a "magic string" and not used directly its ++ value doesn't matter. ++ [Steve Henson] ++ ++ *) Introduce some semblance of const correctness to BN. Shame C doesn't ++ support mutable. ++ [Ben Laurie] ++ ++ *) "linux-sparc64" configuration (ultrapenguin). ++ [Ray Miller ] ++ "linux-sparc" configuration. ++ [Christian Forster ] ++ ++ *) config now generates no-xxx options for missing ciphers. ++ [Ulf Möller] ++ ++ *) Support the EBCDIC character set (work in progress). ++ File ebcdic.c not yet included because it has a different license. ++ [Martin Kraemer ] ++ ++ *) Support BS2000/OSD-POSIX. ++ [Martin Kraemer ] ++ ++ *) Make callbacks for key generation use void * instead of char *. ++ [Ben Laurie] ++ ++ *) Make S/MIME samples compile (not yet tested). ++ [Ben Laurie] ++ ++ *) Additional typesafe stacks. ++ [Ben Laurie] ++ ++ *) New configuration variants "bsdi-elf-gcc" (BSD/OS 4.x). ++ [Bodo Moeller] ++ ++ ++ Changes between 0.9.3 and 0.9.3a [29 May 1999] ++ ++ *) New configuration variant "sco5-gcc". ++ ++ *) Updated some demos. ++ [Sean O Riordain, Wade Scholine] ++ ++ *) Add missing BIO_free at exit of pkcs12 application. ++ [Wu Zhigang] ++ ++ *) Fix memory leak in conf.c. ++ [Steve Henson] ++ ++ *) Updates for Win32 to assembler version of MD5. ++ [Steve Henson] ++ ++ *) Set #! path to perl in apps/der_chop to where we found it ++ instead of using a fixed path. ++ [Bodo Moeller] ++ ++ *) SHA library changes for irix64-mips4-cc. ++ [Andy Polyakov] ++ ++ *) Improvements for VMS support. ++ [Richard Levitte] ++ ++ ++ Changes between 0.9.2b and 0.9.3 [24 May 1999] ++ ++ *) Bignum library bug fix. IRIX 6 passes "make test" now! ++ This also avoids the problems with SC4.2 and unpatched SC5. ++ [Andy Polyakov ] ++ ++ *) New functions sk_num, sk_value and sk_set to replace the previous macros. ++ These are required because of the typesafe stack would otherwise break ++ existing code. If old code used a structure member which used to be STACK ++ and is now STACK_OF (for example cert in a PKCS7_SIGNED structure) with ++ sk_num or sk_value it would produce an error because the num, data members ++ are not present in STACK_OF. Now it just produces a warning. sk_set ++ replaces the old method of assigning a value to sk_value ++ (e.g. sk_value(x, i) = y) which the library used in a few cases. Any code ++ that does this will no longer work (and should use sk_set instead) but ++ this could be regarded as a "questionable" behaviour anyway. ++ [Steve Henson] ++ ++ *) Fix most of the other PKCS#7 bugs. The "experimental" code can now ++ correctly handle encrypted S/MIME data. ++ [Steve Henson] ++ ++ *) Change type of various DES function arguments from des_cblock ++ (which means, in function argument declarations, pointer to char) ++ to des_cblock * (meaning pointer to array with 8 char elements), ++ which allows the compiler to do more typechecking; it was like ++ that back in SSLeay, but with lots of ugly casts. ++ ++ Introduce new type const_des_cblock. ++ [Bodo Moeller] ++ ++ *) Reorganise the PKCS#7 library and get rid of some of the more obvious ++ problems: find RecipientInfo structure that matches recipient certificate ++ and initialise the ASN1 structures properly based on passed cipher. ++ [Steve Henson] ++ ++ *) Belatedly make the BN tests actually check the results. ++ [Ben Laurie] ++ ++ *) Fix the encoding and decoding of negative ASN1 INTEGERS and conversion ++ to and from BNs: it was completely broken. New compilation option ++ NEG_PUBKEY_BUG to allow for some broken certificates that encode public ++ key elements as negative integers. ++ [Steve Henson] ++ ++ *) Reorganize and speed up MD5. ++ [Andy Polyakov ] ++ ++ *) VMS support. ++ [Richard Levitte ] ++ ++ *) New option -out to asn1parse to allow the parsed structure to be ++ output to a file. This is most useful when combined with the -strparse ++ option to examine the output of things like OCTET STRINGS. ++ [Steve Henson] ++ ++ *) Make SSL library a little more fool-proof by not requiring any longer ++ that SSL_set_{accept,connect}_state be called before ++ SSL_{accept,connect} may be used (SSL_set_..._state is omitted ++ in many applications because usually everything *appeared* to work as ++ intended anyway -- now it really works as intended). ++ [Bodo Moeller] ++ ++ *) Move openssl.cnf out of lib/. ++ [Ulf Möller] ++ ++ *) Fix various things to let OpenSSL even pass ``egcc -pipe -O2 -Wall ++ -Wshadow -Wpointer-arith -Wcast-align -Wmissing-prototypes ++ -Wmissing-declarations -Wnested-externs -Winline'' with EGCS 1.1.2+ ++ [Ralf S. Engelschall] ++ ++ *) Various fixes to the EVP and PKCS#7 code. It may now be able to ++ handle PKCS#7 enveloped data properly. ++ [Sebastian Akerman , modified by Steve] ++ ++ *) Create a duplicate of the SSL_CTX's CERT in SSL_new instead of ++ copying pointers. The cert_st handling is changed by this in ++ various ways (and thus what used to be known as ctx->default_cert ++ is now called ctx->cert, since we don't resort to s->ctx->[default_]cert ++ any longer when s->cert does not give us what we need). ++ ssl_cert_instantiate becomes obsolete by this change. ++ As soon as we've got the new code right (possibly it already is?), ++ we have solved a couple of bugs of the earlier code where s->cert ++ was used as if it could not have been shared with other SSL structures. ++ ++ Note that using the SSL API in certain dirty ways now will result ++ in different behaviour than observed with earlier library versions: ++ Changing settings for an SSL_CTX *ctx after having done s = SSL_new(ctx) ++ does not influence s as it used to. ++ ++ In order to clean up things more thoroughly, inside SSL_SESSION ++ we don't use CERT any longer, but a new structure SESS_CERT ++ that holds per-session data (if available); currently, this is ++ the peer's certificate chain and, for clients, the server's certificate ++ and temporary key. CERT holds only those values that can have ++ meaningful defaults in an SSL_CTX. ++ [Bodo Moeller] ++ ++ *) New function X509V3_EXT_i2d() to create an X509_EXTENSION structure ++ from the internal representation. Various PKCS#7 fixes: remove some ++ evil casts and set the enc_dig_alg field properly based on the signing ++ key type. ++ [Steve Henson] ++ ++ *) Allow PKCS#12 password to be set from the command line or the ++ environment. Let 'ca' get its config file name from the environment ++ variables "OPENSSL_CONF" or "SSLEAY_CONF" (for consistency with 'req' ++ and 'x509'). ++ [Steve Henson] ++ ++ *) Allow certificate policies extension to use an IA5STRING for the ++ organization field. This is contrary to the PKIX definition but ++ VeriSign uses it and IE5 only recognises this form. Document 'x509' ++ extension option. ++ [Steve Henson] ++ ++ *) Add PEDANTIC compiler flag to allow compilation with gcc -pedantic, ++ without disallowing inline assembler and the like for non-pedantic builds. ++ [Ben Laurie] ++ ++ *) Support Borland C++ builder. ++ [Janez Jere , modified by Ulf Möller] ++ ++ *) Support Mingw32. ++ [Ulf Möller] ++ ++ *) SHA-1 cleanups and performance enhancements. ++ [Andy Polyakov ] ++ ++ *) Sparc v8plus assembler for the bignum library. ++ [Andy Polyakov ] ++ ++ *) Accept any -xxx and +xxx compiler options in Configure. ++ [Ulf Möller] ++ ++ *) Update HPUX configuration. ++ [Anonymous] ++ ++ *) Add missing sk__unshift() function to safestack.h ++ [Ralf S. Engelschall] ++ ++ *) New function SSL_CTX_use_certificate_chain_file that sets the ++ "extra_cert"s in addition to the certificate. (This makes sense ++ only for "PEM" format files, as chains as a whole are not ++ DER-encoded.) ++ [Bodo Moeller] ++ ++ *) Support verify_depth from the SSL API. ++ x509_vfy.c had what can be considered an off-by-one-error: ++ Its depth (which was not part of the external interface) ++ was actually counting the number of certificates in a chain; ++ now it really counts the depth. ++ [Bodo Moeller] ++ ++ *) Bugfix in crypto/x509/x509_cmp.c: The SSLerr macro was used ++ instead of X509err, which often resulted in confusing error ++ messages since the error codes are not globally unique ++ (e.g. an alleged error in ssl3_accept when a certificate ++ didn't match the private key). ++ ++ *) New function SSL_CTX_set_session_id_context that allows to set a default ++ value (so that you don't need SSL_set_session_id_context for each ++ connection using the SSL_CTX). ++ [Bodo Moeller] ++ ++ *) OAEP decoding bug fix. ++ [Ulf Möller] ++ ++ *) Support INSTALL_PREFIX for package builders, as proposed by ++ David Harris. ++ [Bodo Moeller] ++ ++ *) New Configure options "threads" and "no-threads". For systems ++ where the proper compiler options are known (currently Solaris ++ and Linux), "threads" is the default. ++ [Bodo Moeller] ++ ++ *) New script util/mklink.pl as a faster substitute for util/mklink.sh. ++ [Bodo Moeller] ++ ++ *) Install various scripts to $(OPENSSLDIR)/misc, not to ++ $(INSTALLTOP)/bin -- they shouldn't clutter directories ++ such as /usr/local/bin. ++ [Bodo Moeller] ++ ++ *) "make linux-shared" to build shared libraries. ++ [Niels Poppe ] ++ ++ *) New Configure option no- (rsa, idea, rc5, ...). ++ [Ulf Möller] ++ ++ *) Add the PKCS#12 API documentation to openssl.txt. Preliminary support for ++ extension adding in x509 utility. ++ [Steve Henson] ++ ++ *) Remove NOPROTO sections and error code comments. ++ [Ulf Möller] ++ ++ *) Partial rewrite of the DEF file generator to now parse the ANSI ++ prototypes. ++ [Steve Henson] ++ ++ *) New Configure options --prefix=DIR and --openssldir=DIR. ++ [Ulf Möller] ++ ++ *) Complete rewrite of the error code script(s). It is all now handled ++ by one script at the top level which handles error code gathering, ++ header rewriting and C source file generation. It should be much better ++ than the old method: it now uses a modified version of Ulf's parser to ++ read the ANSI prototypes in all header files (thus the old K&R definitions ++ aren't needed for error creation any more) and do a better job of ++ translating function codes into names. The old 'ASN1 error code imbedded ++ in a comment' is no longer necessary and it doesn't use .err files which ++ have now been deleted. Also the error code call doesn't have to appear all ++ on one line (which resulted in some large lines...). ++ [Steve Henson] ++ ++ *) Change #include filenames from to . ++ [Bodo Moeller] ++ ++ *) Change behaviour of ssl2_read when facing length-0 packets: Don't return ++ 0 (which usually indicates a closed connection), but continue reading. ++ [Bodo Moeller] ++ ++ *) Fix some race conditions. ++ [Bodo Moeller] ++ ++ *) Add support for CRL distribution points extension. Add Certificate ++ Policies and CRL distribution points documentation. ++ [Steve Henson] ++ ++ *) Move the autogenerated header file parts to crypto/opensslconf.h. ++ [Ulf Möller] ++ ++ *) Fix new 56-bit DES export ciphersuites: they were using 7 bytes instead of ++ 8 of keying material. Merlin has also confirmed interop with this fix ++ between OpenSSL and Baltimore C/SSL 2.0 and J/SSL 2.0. ++ [Merlin Hughes ] ++ ++ *) Fix lots of warnings. ++ [Richard Levitte ] ++ ++ *) In add_cert_dir() in crypto/x509/by_dir.c, break out of the loop if ++ the directory spec didn't end with a LIST_SEPARATOR_CHAR. ++ [Richard Levitte ] ++ ++ *) Fix problems with sizeof(long) == 8. ++ [Andy Polyakov ] ++ ++ *) Change functions to ANSI C. ++ [Ulf Möller] ++ ++ *) Fix typos in error codes. ++ [Martin Kraemer , Ulf Möller] ++ ++ *) Remove defunct assembler files from Configure. ++ [Ulf Möller] ++ ++ *) SPARC v8 assembler BIGNUM implementation. ++ [Andy Polyakov ] ++ ++ *) Support for Certificate Policies extension: both print and set. ++ Various additions to support the r2i method this uses. ++ [Steve Henson] ++ ++ *) A lot of constification, and fix a bug in X509_NAME_oneline() that could ++ return a const string when you are expecting an allocated buffer. ++ [Ben Laurie] ++ ++ *) Add support for ASN1 types UTF8String and VISIBLESTRING, also the CHOICE ++ types DirectoryString and DisplayText. ++ [Steve Henson] ++ ++ *) Add code to allow r2i extensions to access the configuration database, ++ add an LHASH database driver and add several ctx helper functions. ++ [Steve Henson] ++ ++ *) Fix an evil bug in bn_expand2() which caused various BN functions to ++ fail when they extended the size of a BIGNUM. ++ [Steve Henson] ++ ++ *) Various utility functions to handle SXNet extension. Modify mkdef.pl to ++ support typesafe stack. ++ [Steve Henson] ++ ++ *) Fix typo in SSL_[gs]et_options(). ++ [Nils Frostberg ] ++ ++ *) Delete various functions and files that belonged to the (now obsolete) ++ old X509V3 handling code. ++ [Steve Henson] ++ ++ *) New Configure option "rsaref". ++ [Ulf Möller] ++ ++ *) Don't auto-generate pem.h. ++ [Bodo Moeller] ++ ++ *) Introduce type-safe ASN.1 SETs. ++ [Ben Laurie] ++ ++ *) Convert various additional casted stacks to type-safe STACK_OF() variants. ++ [Ben Laurie, Ralf S. Engelschall, Steve Henson] ++ ++ *) Introduce type-safe STACKs. This will almost certainly break lots of code ++ that links with OpenSSL (well at least cause lots of warnings), but fear ++ not: the conversion is trivial, and it eliminates loads of evil casts. A ++ few STACKed things have been converted already. Feel free to convert more. ++ In the fullness of time, I'll do away with the STACK type altogether. ++ [Ben Laurie] ++ ++ *) Add `openssl ca -revoke ' facility which revokes a certificate ++ specified in by updating the entry in the index.txt file. ++ This way one no longer has to edit the index.txt file manually for ++ revoking a certificate. The -revoke option does the gory details now. ++ [Massimiliano Pala , Ralf S. Engelschall] ++ ++ *) Fix `openssl crl -noout -text' combination where `-noout' killed the ++ `-text' option at all and this way the `-noout -text' combination was ++ inconsistent in `openssl crl' with the friends in `openssl x509|rsa|dsa'. ++ [Ralf S. Engelschall] ++ ++ *) Make sure a corresponding plain text error message exists for the ++ X509_V_ERR_CERT_REVOKED/23 error number which can occur when a ++ verify callback function determined that a certificate was revoked. ++ [Ralf S. Engelschall] ++ ++ *) Bugfix: In test/testenc, don't test "openssl " for ++ ciphers that were excluded, e.g. by -DNO_IDEA. Also, test ++ all available cipers including rc5, which was forgotten until now. ++ In order to let the testing shell script know which algorithms ++ are available, a new (up to now undocumented) command ++ "openssl list-cipher-commands" is used. ++ [Bodo Moeller] ++ ++ *) Bugfix: s_client occasionally would sleep in select() when ++ it should have checked SSL_pending() first. ++ [Bodo Moeller] ++ ++ *) New functions DSA_do_sign and DSA_do_verify to provide access to ++ the raw DSA values prior to ASN.1 encoding. ++ [Ulf Möller] ++ ++ *) Tweaks to Configure ++ [Niels Poppe ] ++ ++ *) Add support for PKCS#5 v2.0 ASN1 PBES2 structures. No other support, ++ yet... ++ [Steve Henson] ++ ++ *) New variables $(RANLIB) and $(PERL) in the Makefiles. ++ [Ulf Möller] ++ ++ *) New config option to avoid instructions that are illegal on the 80386. ++ The default code is faster, but requires at least a 486. ++ [Ulf Möller] ++ ++ *) Got rid of old SSL2_CLIENT_VERSION (inconsistently used) and ++ SSL2_SERVER_VERSION (not used at all) macros, which are now the ++ same as SSL2_VERSION anyway. ++ [Bodo Moeller] ++ ++ *) New "-showcerts" option for s_client. ++ [Bodo Moeller] ++ ++ *) Still more PKCS#12 integration. Add pkcs12 application to openssl ++ application. Various cleanups and fixes. ++ [Steve Henson] ++ ++ *) More PKCS#12 integration. Add new pkcs12 directory with Makefile.ssl and ++ modify error routines to work internally. Add error codes and PBE init ++ to library startup routines. ++ [Steve Henson] ++ ++ *) Further PKCS#12 integration. Added password based encryption, PKCS#8 and ++ packing functions to asn1 and evp. Changed function names and error ++ codes along the way. ++ [Steve Henson] ++ ++ *) PKCS12 integration: and so it begins... First of several patches to ++ slowly integrate PKCS#12 functionality into OpenSSL. Add PKCS#12 ++ objects to objects.h ++ [Steve Henson] ++ ++ *) Add a new 'indent' option to some X509V3 extension code. Initial ASN1 ++ and display support for Thawte strong extranet extension. ++ [Steve Henson] ++ ++ *) Add LinuxPPC support. ++ [Jeff Dubrule ] ++ ++ *) Get rid of redundant BN file bn_mulw.c, and rename bn_div64 to ++ bn_div_words in alpha.s. ++ [Hannes Reinecke and Ben Laurie] ++ ++ *) Make sure the RSA OAEP test is skipped under -DRSAref because ++ OAEP isn't supported when OpenSSL is built with RSAref. ++ [Ulf Moeller ] ++ ++ *) Move definitions of IS_SET/IS_SEQUENCE inside crypto/asn1/asn1.h ++ so they no longer are missing under -DNOPROTO. ++ [Soren S. Jorvang ] ++ ++ ++ Changes between 0.9.1c and 0.9.2b [22 Mar 1999] ++ ++ *) Make SSL_get_peer_cert_chain() work in servers. Unfortunately, it still ++ doesn't work when the session is reused. Coming soon! ++ [Ben Laurie] ++ ++ *) Fix a security hole, that allows sessions to be reused in the wrong ++ context thus bypassing client cert protection! All software that uses ++ client certs and session caches in multiple contexts NEEDS PATCHING to ++ allow session reuse! A fuller solution is in the works. ++ [Ben Laurie, problem pointed out by Holger Reif, Bodo Moeller (and ???)] ++ ++ *) Some more source tree cleanups (removed obsolete files ++ crypto/bf/asm/bf586.pl, test/test.txt and crypto/sha/asm/f.s; changed ++ permission on "config" script to be executable) and a fix for the INSTALL ++ document. ++ [Ulf Moeller ] ++ ++ *) Remove some legacy and erroneous uses of malloc, free instead of ++ Malloc, Free. ++ [Lennart Bang , with minor changes by Steve] ++ ++ *) Make rsa_oaep_test return non-zero on error. ++ [Ulf Moeller ] ++ ++ *) Add support for native Solaris shared libraries. Configure ++ solaris-sparc-sc4-pic, make, then run shlib/solaris-sc4.sh. It'd be nice ++ if someone would make that last step automatic. ++ [Matthias Loepfe ] ++ ++ *) ctx_size was not built with the right compiler during "make links". Fixed. ++ [Ben Laurie] ++ ++ *) Change the meaning of 'ALL' in the cipher list. It now means "everything ++ except NULL ciphers". This means the default cipher list will no longer ++ enable NULL ciphers. They need to be specifically enabled e.g. with ++ the string "DEFAULT:eNULL". ++ [Steve Henson] ++ ++ *) Fix to RSA private encryption routines: if p < q then it would ++ occasionally produce an invalid result. This will only happen with ++ externally generated keys because OpenSSL (and SSLeay) ensure p > q. ++ [Steve Henson] ++ ++ *) Be less restrictive and allow also `perl util/perlpath.pl ++ /path/to/bin/perl' in addition to `perl util/perlpath.pl /path/to/bin', ++ because this way one can also use an interpreter named `perl5' (which is ++ usually the name of Perl 5.xxx on platforms where an Perl 4.x is still ++ installed as `perl'). ++ [Matthias Loepfe ] ++ ++ *) Let util/clean-depend.pl work also with older Perl 5.00x versions. ++ [Matthias Loepfe ] ++ ++ *) Fix Makefile.org so CC,CFLAG etc are passed to 'make links' add ++ advapi32.lib to Win32 build and change the pem test comparison ++ to fc.exe (thanks to Ulrich Kroener for the ++ suggestion). Fix misplaced ASNI prototypes and declarations in evp.h ++ and crypto/des/ede_cbcm_enc.c. ++ [Steve Henson] ++ ++ *) DES quad checksum was broken on big-endian architectures. Fixed. ++ [Ben Laurie] ++ ++ *) Comment out two functions in bio.h that aren't implemented. Fix up the ++ Win32 test batch file so it (might) work again. The Win32 test batch file ++ is horrible: I feel ill.... ++ [Steve Henson] ++ ++ *) Move various #ifdefs around so NO_SYSLOG, NO_DIRENT etc are now selected ++ in e_os.h. Audit of header files to check ANSI and non ANSI ++ sections: 10 functions were absent from non ANSI section and not exported ++ from Windows DLLs. Fixed up libeay.num for new functions. ++ [Steve Henson] ++ ++ *) Make `openssl version' output lines consistent. ++ [Ralf S. Engelschall] ++ ++ *) Fix Win32 symbol export lists for BIO functions: Added ++ BIO_get_ex_new_index, BIO_get_ex_num, BIO_get_ex_data and BIO_set_ex_data ++ to ms/libeay{16,32}.def. ++ [Ralf S. Engelschall] ++ ++ *) Second round of fixing the OpenSSL perl/ stuff. It now at least compiled ++ fine under Unix and passes some trivial tests I've now added. But the ++ whole stuff is horribly incomplete, so a README.1ST with a disclaimer was ++ added to make sure no one expects that this stuff really works in the ++ OpenSSL 0.9.2 release. Additionally I've started to clean the XS sources ++ up and fixed a few little bugs and inconsistencies in OpenSSL.{pm,xs} and ++ openssl_bio.xs. ++ [Ralf S. Engelschall] ++ ++ *) Fix the generation of two part addresses in perl. ++ [Kenji Miyake , integrated by Ben Laurie] ++ ++ *) Add config entry for Linux on MIPS. ++ [John Tobey ] ++ ++ *) Make links whenever Configure is run, unless we are on Windoze. ++ [Ben Laurie] ++ ++ *) Permit extensions to be added to CRLs using crl_section in openssl.cnf. ++ Currently only issuerAltName and AuthorityKeyIdentifier make any sense ++ in CRLs. ++ [Steve Henson] ++ ++ *) Add a useful kludge to allow package maintainers to specify compiler and ++ other platforms details on the command line without having to patch the ++ Configure script everytime: One now can use ``perl Configure ++ :
'', i.e. platform ids are allowed to have details appended ++ to them (separated by colons). This is treated as there would be a static ++ pre-configured entry in Configure's %table under key with value ++
and ``perl Configure '' is called. So, when you want to ++ perform a quick test-compile under FreeBSD 3.1 with pgcc and without ++ assembler stuff you can use ``perl Configure "FreeBSD-elf:pgcc:-O6:::"'' ++ now, which overrides the FreeBSD-elf entry on-the-fly. ++ [Ralf S. Engelschall] ++ ++ *) Disable new TLS1 ciphersuites by default: they aren't official yet. ++ [Ben Laurie] ++ ++ *) Allow DSO flags like -fpic, -fPIC, -KPIC etc. to be specified ++ on the `perl Configure ...' command line. This way one can compile ++ OpenSSL libraries with Position Independent Code (PIC) which is needed ++ for linking it into DSOs. ++ [Ralf S. Engelschall] ++ ++ *) Remarkably, export ciphers were totally broken and no-one had noticed! ++ Fixed. ++ [Ben Laurie] ++ ++ *) Cleaned up the LICENSE document: The official contact for any license ++ questions now is the OpenSSL core team under openssl-core@openssl.org. ++ And add a paragraph about the dual-license situation to make sure people ++ recognize that _BOTH_ the OpenSSL license _AND_ the SSLeay license apply ++ to the OpenSSL toolkit. ++ [Ralf S. Engelschall] ++ ++ *) General source tree makefile cleanups: Made `making xxx in yyy...' ++ display consistent in the source tree and replaced `/bin/rm' by `rm'. ++ Additionally cleaned up the `make links' target: Remove unnecessary ++ semicolons, subsequent redundant removes, inline point.sh into mklink.sh ++ to speed processing and no longer clutter the display with confusing ++ stuff. Instead only the actually done links are displayed. ++ [Ralf S. Engelschall] ++ ++ *) Permit null encryption ciphersuites, used for authentication only. It used ++ to be necessary to set the preprocessor define SSL_ALLOW_ENULL to do this. ++ It is now necessary to set SSL_FORBID_ENULL to prevent the use of null ++ encryption. ++ [Ben Laurie] ++ ++ *) Add a bunch of fixes to the PKCS#7 stuff. It used to sometimes reorder ++ signed attributes when verifying signatures (this would break them), ++ the detached data encoding was wrong and public keys obtained using ++ X509_get_pubkey() weren't freed. ++ [Steve Henson] ++ ++ *) Add text documentation for the BUFFER functions. Also added a work around ++ to a Win95 console bug. This was triggered by the password read stuff: the ++ last character typed gets carried over to the next fread(). If you were ++ generating a new cert request using 'req' for example then the last ++ character of the passphrase would be CR which would then enter the first ++ field as blank. ++ [Steve Henson] ++ ++ *) Added the new `Includes OpenSSL Cryptography Software' button as ++ doc/openssl_button.{gif,html} which is similar in style to the old SSLeay ++ button and can be used by applications based on OpenSSL to show the ++ relationship to the OpenSSL project. ++ [Ralf S. Engelschall] ++ ++ *) Remove confusing variables in function signatures in files ++ ssl/ssl_lib.c and ssl/ssl.h. ++ [Lennart Bong ] ++ ++ *) Don't install bss_file.c under PREFIX/include/ ++ [Lennart Bong ] ++ ++ *) Get the Win32 compile working again. Modify mkdef.pl so it can handle ++ functions that return function pointers and has support for NT specific ++ stuff. Fix mk1mf.pl and VC-32.pl to support NT differences also. Various ++ #ifdef WIN32 and WINNTs sprinkled about the place and some changes from ++ unsigned to signed types: this was killing the Win32 compile. ++ [Steve Henson] ++ ++ *) Add new certificate file to stack functions, ++ SSL_add_dir_cert_subjects_to_stack() and ++ SSL_add_file_cert_subjects_to_stack(). These largely supplant ++ SSL_load_client_CA_file(), and can be used to add multiple certs easily ++ to a stack (usually this is then handed to SSL_CTX_set_client_CA_list()). ++ This means that Apache-SSL and similar packages don't have to mess around ++ to add as many CAs as they want to the preferred list. ++ [Ben Laurie] ++ ++ *) Experiment with doxygen documentation. Currently only partially applied to ++ ssl/ssl_lib.c. ++ See http://www.stack.nl/~dimitri/doxygen/index.html, and run doxygen with ++ openssl.doxy as the configuration file. ++ [Ben Laurie] ++ ++ *) Get rid of remaining C++-style comments which strict C compilers hate. ++ [Ralf S. Engelschall, pointed out by Carlos Amengual] ++ ++ *) Changed BN_RECURSION in bn_mont.c to BN_RECURSION_MONT so it is not ++ compiled in by default: it has problems with large keys. ++ [Steve Henson] ++ ++ *) Add a bunch of SSL_xxx() functions for configuring the temporary RSA and ++ DH private keys and/or callback functions which directly correspond to ++ their SSL_CTX_xxx() counterparts but work on a per-connection basis. This ++ is needed for applications which have to configure certificates on a ++ per-connection basis (e.g. Apache+mod_ssl) instead of a per-context basis ++ (e.g. s_server). ++ For the RSA certificate situation is makes no difference, but ++ for the DSA certificate situation this fixes the "no shared cipher" ++ problem where the OpenSSL cipher selection procedure failed because the ++ temporary keys were not overtaken from the context and the API provided ++ no way to reconfigure them. ++ The new functions now let applications reconfigure the stuff and they ++ are in detail: SSL_need_tmp_RSA, SSL_set_tmp_rsa, SSL_set_tmp_dh, ++ SSL_set_tmp_rsa_callback and SSL_set_tmp_dh_callback. Additionally a new ++ non-public-API function ssl_cert_instantiate() is used as a helper ++ function and also to reduce code redundancy inside ssl_rsa.c. ++ [Ralf S. Engelschall] ++ ++ *) Move s_server -dcert and -dkey options out of the undocumented feature ++ area because they are useful for the DSA situation and should be ++ recognized by the users. ++ [Ralf S. Engelschall] ++ ++ *) Fix the cipher decision scheme for export ciphers: the export bits are ++ *not* within SSL_MKEY_MASK or SSL_AUTH_MASK, they are within ++ SSL_EXP_MASK. So, the original variable has to be used instead of the ++ already masked variable. ++ [Richard Levitte ] ++ ++ *) Fix 'port' variable from `int' to `unsigned int' in crypto/bio/b_sock.c ++ [Richard Levitte ] ++ ++ *) Change type of another md_len variable in pk7_doit.c:PKCS7_dataFinal() ++ from `int' to `unsigned int' because it's a length and initialized by ++ EVP_DigestFinal() which expects an `unsigned int *'. ++ [Richard Levitte ] ++ ++ *) Don't hard-code path to Perl interpreter on shebang line of Configure ++ script. Instead use the usual Shell->Perl transition trick. ++ [Ralf S. Engelschall] ++ ++ *) Make `openssl x509 -noout -modulus' functional also for DSA certificates ++ (in addition to RSA certificates) to match the behaviour of `openssl dsa ++ -noout -modulus' as it's already the case for `openssl rsa -noout ++ -modulus'. For RSA the -modulus is the real "modulus" while for DSA ++ currently the public key is printed (a decision which was already done by ++ `openssl dsa -modulus' in the past) which serves a similar purpose. ++ Additionally the NO_RSA no longer completely removes the whole -modulus ++ option; it now only avoids using the RSA stuff. Same applies to NO_DSA ++ now, too. ++ [Ralf S. Engelschall] ++ ++ *) Add Arne Ansper's reliable BIO - this is an encrypted, block-digested ++ BIO. See the source (crypto/evp/bio_ok.c) for more info. ++ [Arne Ansper ] ++ ++ *) Dump the old yucky req code that tried (and failed) to allow raw OIDs ++ to be added. Now both 'req' and 'ca' can use new objects defined in the ++ config file. ++ [Steve Henson] ++ ++ *) Add cool BIO that does syslog (or event log on NT). ++ [Arne Ansper , integrated by Ben Laurie] ++ ++ *) Add support for new TLS ciphersuites, TLS_RSA_EXPORT56_WITH_RC4_56_MD5, ++ TLS_RSA_EXPORT56_WITH_RC2_CBC_56_MD5 and ++ TLS_RSA_EXPORT56_WITH_DES_CBC_SHA, as specified in "56-bit Export Cipher ++ Suites For TLS", draft-ietf-tls-56-bit-ciphersuites-00.txt. ++ [Ben Laurie] ++ ++ *) Add preliminary config info for new extension code. ++ [Steve Henson] ++ ++ *) Make RSA_NO_PADDING really use no padding. ++ [Ulf Moeller ] ++ ++ *) Generate errors when private/public key check is done. ++ [Ben Laurie] ++ ++ *) Overhaul for 'crl' utility. New function X509_CRL_print. Partial support ++ for some CRL extensions and new objects added. ++ [Steve Henson] ++ ++ *) Really fix the ASN1 IMPLICIT bug this time... Partial support for private ++ key usage extension and fuller support for authority key id. ++ [Steve Henson] ++ ++ *) Add OAEP encryption for the OpenSSL crypto library. OAEP is the improved ++ padding method for RSA, which is recommended for new applications in PKCS ++ #1 v2.0 (RFC 2437, October 1998). ++ OAEP (Optimal Asymmetric Encryption Padding) has better theoretical ++ foundations than the ad-hoc padding used in PKCS #1 v1.5. It is secure ++ against Bleichbacher's attack on RSA. ++ [Ulf Moeller , reformatted, corrected and integrated by ++ Ben Laurie] ++ ++ *) Updates to the new SSL compression code ++ [Eric A. Young, (from changes to C2Net SSLeay, integrated by Mark Cox)] ++ ++ *) Fix so that the version number in the master secret, when passed ++ via RSA, checks that if TLS was proposed, but we roll back to SSLv3 ++ (because the server will not accept higher), that the version number ++ is 0x03,0x01, not 0x03,0x00 ++ [Eric A. Young, (from changes to C2Net SSLeay, integrated by Mark Cox)] ++ ++ *) Run extensive memory leak checks on SSL apps. Fixed *lots* of memory ++ leaks in ssl/ relating to new X509_get_pubkey() behaviour. Also fixes ++ in apps/ and an unrelated leak in crypto/dsa/dsa_vrf.c ++ [Steve Henson] ++ ++ *) Support for RAW extensions where an arbitrary extension can be ++ created by including its DER encoding. See apps/openssl.cnf for ++ an example. ++ [Steve Henson] ++ ++ *) Make sure latest Perl versions don't interpret some generated C array ++ code as Perl array code in the crypto/err/err_genc.pl script. ++ [Lars Weber <3weber@informatik.uni-hamburg.de>] ++ ++ *) Modify ms/do_ms.bat to not generate assembly language makefiles since ++ not many people have the assembler. Various Win32 compilation fixes and ++ update to the INSTALL.W32 file with (hopefully) more accurate Win32 ++ build instructions. ++ [Steve Henson] ++ ++ *) Modify configure script 'Configure' to automatically create crypto/date.h ++ file under Win32 and also build pem.h from pem.org. New script ++ util/mkfiles.pl to create the MINFO file on environments that can't do a ++ 'make files': perl util/mkfiles.pl >MINFO should work. ++ [Steve Henson] ++ ++ *) Major rework of DES function declarations, in the pursuit of correctness ++ and purity. As a result, many evil casts evaporated, and some weirdness, ++ too. You may find this causes warnings in your code. Zapping your evil ++ casts will probably fix them. Mostly. ++ [Ben Laurie] ++ ++ *) Fix for a typo in asn1.h. Bug fix to object creation script ++ obj_dat.pl. It considered a zero in an object definition to mean ++ "end of object": none of the objects in objects.h have any zeros ++ so it wasn't spotted. ++ [Steve Henson, reported by Erwann ABALEA ] ++ ++ *) Add support for Triple DES Cipher Block Chaining with Output Feedback ++ Masking (CBCM). In the absence of test vectors, the best I have been able ++ to do is check that the decrypt undoes the encrypt, so far. Send me test ++ vectors if you have them. ++ [Ben Laurie] ++ ++ *) Correct calculation of key length for export ciphers (too much space was ++ allocated for null ciphers). This has not been tested! ++ [Ben Laurie] ++ ++ *) Modifications to the mkdef.pl for Win32 DEF file creation. The usage ++ message is now correct (it understands "crypto" and "ssl" on its ++ command line). There is also now an "update" option. This will update ++ the util/ssleay.num and util/libeay.num files with any new functions. ++ If you do a: ++ perl util/mkdef.pl crypto ssl update ++ it will update them. ++ [Steve Henson] ++ ++ *) Overhauled the Perl interface (perl/*): ++ - ported BN stuff to OpenSSL's different BN library ++ - made the perl/ source tree CVS-aware ++ - renamed the package from SSLeay to OpenSSL (the files still contain ++ their history because I've copied them in the repository) ++ - removed obsolete files (the test scripts will be replaced ++ by better Test::Harness variants in the future) ++ [Ralf S. Engelschall] ++ ++ *) First cut for a very conservative source tree cleanup: ++ 1. merge various obsolete readme texts into doc/ssleay.txt ++ where we collect the old documents and readme texts. ++ 2. remove the first part of files where I'm already sure that we no ++ longer need them because of three reasons: either they are just temporary ++ files which were left by Eric or they are preserved original files where ++ I've verified that the diff is also available in the CVS via "cvs diff ++ -rSSLeay_0_8_1b" or they were renamed (as it was definitely the case for ++ the crypto/md/ stuff). ++ [Ralf S. Engelschall] ++ ++ *) More extension code. Incomplete support for subject and issuer alt ++ name, issuer and authority key id. Change the i2v function parameters ++ and add an extra 'crl' parameter in the X509V3_CTX structure: guess ++ what that's for :-) Fix to ASN1 macro which messed up ++ IMPLICIT tag and add f_enum.c which adds a2i, i2a for ENUMERATED. ++ [Steve Henson] ++ ++ *) Preliminary support for ENUMERATED type. This is largely copied from the ++ INTEGER code. ++ [Steve Henson] ++ ++ *) Add new function, EVP_MD_CTX_copy() to replace frequent use of memcpy. ++ [Eric A. Young, (from changes to C2Net SSLeay, integrated by Mark Cox)] ++ ++ *) Make sure `make rehash' target really finds the `openssl' program. ++ [Ralf S. Engelschall, Matthias Loepfe ] ++ ++ *) Squeeze another 7% of speed out of MD5 assembler, at least on a P2. I'd ++ like to hear about it if this slows down other processors. ++ [Ben Laurie] ++ ++ *) Add CygWin32 platform information to Configure script. ++ [Alan Batie ] ++ ++ *) Fixed ms/32all.bat script: `no_asm' -> `no-asm' ++ [Rainer W. Gerling ] ++ ++ *) New program nseq to manipulate netscape certificate sequences ++ [Steve Henson] ++ ++ *) Modify crl2pkcs7 so it supports multiple -certfile arguments. Fix a ++ few typos. ++ [Steve Henson] ++ ++ *) Fixes to BN code. Previously the default was to define BN_RECURSION ++ but the BN code had some problems that would cause failures when ++ doing certificate verification and some other functions. ++ [Eric A. Young, (from changes to C2Net SSLeay, integrated by Mark Cox)] ++ ++ *) Add ASN1 and PEM code to support netscape certificate sequences. ++ [Steve Henson] ++ ++ *) Add ASN1 and PEM code to support netscape certificate sequences. ++ [Steve Henson] ++ ++ *) Add several PKIX and private extended key usage OIDs. ++ [Steve Henson] ++ ++ *) Modify the 'ca' program to handle the new extension code. Modify ++ openssl.cnf for new extension format, add comments. ++ [Steve Henson] ++ ++ *) More X509 V3 changes. Fix typo in v3_bitstr.c. Add support to 'req' ++ and add a sample to openssl.cnf so req -x509 now adds appropriate ++ CA extensions. ++ [Steve Henson] ++ ++ *) Continued X509 V3 changes. Add to other makefiles, integrate with the ++ error code, add initial support to X509_print() and x509 application. ++ [Steve Henson] ++ ++ *) Takes a deep breath and start adding X509 V3 extension support code. Add ++ files in crypto/x509v3. Move original stuff to crypto/x509v3/old. All this ++ stuff is currently isolated and isn't even compiled yet. ++ [Steve Henson] ++ ++ *) Continuing patches for GeneralizedTime. Fix up certificate and CRL ++ ASN1 to use ASN1_TIME and modify print routines to use ASN1_TIME_print. ++ Removed the versions check from X509 routines when loading extensions: ++ this allows certain broken certificates that don't set the version ++ properly to be processed. ++ [Steve Henson] ++ ++ *) Deal with irritating shit to do with dependencies, in YAAHW (Yet Another ++ Ad Hoc Way) - Makefile.ssls now all contain local dependencies, which ++ can still be regenerated with "make depend". ++ [Ben Laurie] ++ ++ *) Spelling mistake in C version of CAST-128. ++ [Ben Laurie, reported by Jeremy Hylton ] ++ ++ *) Changes to the error generation code. The perl script err-code.pl ++ now reads in the old error codes and retains the old numbers, only ++ adding new ones if necessary. It also only changes the .err files if new ++ codes are added. The makefiles have been modified to only insert errors ++ when needed (to avoid needlessly modifying header files). This is done ++ by only inserting errors if the .err file is newer than the auto generated ++ C file. To rebuild all the error codes from scratch (the old behaviour) ++ either modify crypto/Makefile.ssl to pass the -regen flag to err_code.pl ++ or delete all the .err files. ++ [Steve Henson] ++ ++ *) CAST-128 was incorrectly implemented for short keys. The C version has ++ been fixed, but is untested. The assembler versions are also fixed, but ++ new assembler HAS NOT BEEN GENERATED FOR WIN32 - the Makefile needs fixing ++ to regenerate it if needed. ++ [Ben Laurie, reported (with fix for C version) by Jun-ichiro itojun ++ Hagino ] ++ ++ *) File was opened incorrectly in randfile.c. ++ [Ulf Möller ] ++ ++ *) Beginning of support for GeneralizedTime. d2i, i2d, check and print ++ functions. Also ASN1_TIME suite which is a CHOICE of UTCTime or ++ GeneralizedTime. ASN1_TIME is the proper type used in certificates et ++ al: it's just almost always a UTCTime. Note this patch adds new error ++ codes so do a "make errors" if there are problems. ++ [Steve Henson] ++ ++ *) Correct Linux 1 recognition in config. ++ [Ulf Möller ] ++ ++ *) Remove pointless MD5 hash when using DSA keys in ca. ++ [Anonymous ] ++ ++ *) Generate an error if given an empty string as a cert directory. Also ++ generate an error if handed NULL (previously returned 0 to indicate an ++ error, but didn't set one). ++ [Ben Laurie, reported by Anonymous ] ++ ++ *) Add prototypes to SSL methods. Make SSL_write's buffer const, at last. ++ [Ben Laurie] ++ ++ *) Fix the dummy function BN_ref_mod_exp() in rsaref.c to have the correct ++ parameters. This was causing a warning which killed off the Win32 compile. ++ [Steve Henson] ++ ++ *) Remove C++ style comments from crypto/bn/bn_local.h. ++ [Neil Costigan ] ++ ++ *) The function OBJ_txt2nid was broken. It was supposed to return a nid ++ based on a text string, looking up short and long names and finally ++ "dot" format. The "dot" format stuff didn't work. Added new function ++ OBJ_txt2obj to do the same but return an ASN1_OBJECT and rewrote ++ OBJ_txt2nid to use it. OBJ_txt2obj can also return objects even if the ++ OID is not part of the table. ++ [Steve Henson] ++ ++ *) Add prototypes to X509 lookup/verify methods, fixing a bug in ++ X509_LOOKUP_by_alias(). ++ [Ben Laurie] ++ ++ *) Sort openssl functions by name. ++ [Ben Laurie] ++ ++ *) Get the gendsa program working (hopefully) and add it to app list. Remove ++ encryption from sample DSA keys (in case anyone is interested the password ++ was "1234"). ++ [Steve Henson] ++ ++ *) Make _all_ *_free functions accept a NULL pointer. ++ [Frans Heymans ] ++ ++ *) If a DH key is generated in s3_srvr.c, don't blow it by trying to use ++ NULL pointers. ++ [Anonymous ] ++ ++ *) s_server should send the CAfile as acceptable CAs, not its own cert. ++ [Bodo Moeller <3moeller@informatik.uni-hamburg.de>] ++ ++ *) Don't blow it for numeric -newkey arguments to apps/req. ++ [Bodo Moeller <3moeller@informatik.uni-hamburg.de>] ++ ++ *) Temp key "for export" tests were wrong in s3_srvr.c. ++ [Anonymous ] ++ ++ *) Add prototype for temp key callback functions ++ SSL_CTX_set_tmp_{rsa,dh}_callback(). ++ [Ben Laurie] ++ ++ *) Make DH_free() tolerate being passed a NULL pointer (like RSA_free() and ++ DSA_free()). Make X509_PUBKEY_set() check for errors in d2i_PublicKey(). ++ [Steve Henson] ++ ++ *) X509_name_add_entry() freed the wrong thing after an error. ++ [Arne Ansper ] ++ ++ *) rsa_eay.c would attempt to free a NULL context. ++ [Arne Ansper ] ++ ++ *) BIO_s_socket() had a broken should_retry() on Windoze. ++ [Arne Ansper ] ++ ++ *) BIO_f_buffer() didn't pass on BIO_CTRL_FLUSH. ++ [Arne Ansper ] ++ ++ *) Make sure the already existing X509_STORE->depth variable is initialized ++ in X509_STORE_new(), but document the fact that this variable is still ++ unused in the certificate verification process. ++ [Ralf S. Engelschall] ++ ++ *) Fix the various library and apps files to free up pkeys obtained from ++ X509_PUBKEY_get() et al. Also allow x509.c to handle netscape extensions. ++ [Steve Henson] ++ ++ *) Fix reference counting in X509_PUBKEY_get(). This makes ++ demos/maurice/example2.c work, amongst others, probably. ++ [Steve Henson and Ben Laurie] ++ ++ *) First cut of a cleanup for apps/. First the `ssleay' program is now named ++ `openssl' and second, the shortcut symlinks for the `openssl ' ++ are no longer created. This way we have a single and consistent command ++ line interface `openssl ', similar to `cvs '. ++ [Ralf S. Engelschall, Paul Sutton and Ben Laurie] ++ ++ *) ca.c: move test for DSA keys inside #ifndef NO_DSA. Make pubkey ++ BIT STRING wrapper always have zero unused bits. ++ [Steve Henson] ++ ++ *) Add CA.pl, perl version of CA.sh, add extended key usage OID. ++ [Steve Henson] ++ ++ *) Make the top-level INSTALL documentation easier to understand. ++ [Paul Sutton] ++ ++ *) Makefiles updated to exit if an error occurs in a sub-directory ++ make (including if user presses ^C) [Paul Sutton] ++ ++ *) Make Montgomery context stuff explicit in RSA data structure. ++ [Ben Laurie] ++ ++ *) Fix build order of pem and err to allow for generated pem.h. ++ [Ben Laurie] ++ ++ *) Fix renumbering bug in X509_NAME_delete_entry(). ++ [Ben Laurie] ++ ++ *) Enhanced the err-ins.pl script so it makes the error library number ++ global and can add a library name. This is needed for external ASN1 and ++ other error libraries. ++ [Steve Henson] ++ ++ *) Fixed sk_insert which never worked properly. ++ [Steve Henson] ++ ++ *) Fix ASN1 macros so they can handle indefinite length constructed ++ EXPLICIT tags. Some non standard certificates use these: they can now ++ be read in. ++ [Steve Henson] ++ ++ *) Merged the various old/obsolete SSLeay documentation files (doc/xxx.doc) ++ into a single doc/ssleay.txt bundle. This way the information is still ++ preserved but no longer messes up this directory. Now it's new room for ++ the new set of documentation files. ++ [Ralf S. Engelschall] ++ ++ *) SETs were incorrectly DER encoded. This was a major pain, because they ++ shared code with SEQUENCEs, which aren't coded the same. This means that ++ almost everything to do with SETs or SEQUENCEs has either changed name or ++ number of arguments. ++ [Ben Laurie, based on a partial fix by GP Jayan ] ++ ++ *) Fix test data to work with the above. ++ [Ben Laurie] ++ ++ *) Fix the RSA header declarations that hid a bug I fixed in 0.9.0b but ++ was already fixed by Eric for 0.9.1 it seems. ++ [Ben Laurie - pointed out by Ulf Möller ] ++ ++ *) Autodetect FreeBSD3. ++ [Ben Laurie] ++ ++ *) Fix various bugs in Configure. This affects the following platforms: ++ nextstep ++ ncr-scde ++ unixware-2.0 ++ unixware-2.0-pentium ++ sco5-cc. ++ [Ben Laurie] ++ ++ *) Eliminate generated files from CVS. Reorder tests to regenerate files ++ before they are needed. ++ [Ben Laurie] ++ ++ *) Generate Makefile.ssl from Makefile.org (to keep CVS happy). ++ [Ben Laurie] ++ ++ ++ Changes between 0.9.1b and 0.9.1c [23-Dec-1998] ++ ++ *) Added OPENSSL_VERSION_NUMBER to crypto/crypto.h and ++ changed SSLeay to OpenSSL in version strings. ++ [Ralf S. Engelschall] ++ ++ *) Some fixups to the top-level documents. ++ [Paul Sutton] ++ ++ *) Fixed the nasty bug where rsaref.h was not found under compile-time ++ because the symlink to include/ was missing. ++ [Ralf S. Engelschall] ++ ++ *) Incorporated the popular no-RSA/DSA-only patches ++ which allow to compile a RSA-free SSLeay. ++ [Andrew Cooke / Interrader Ldt., Ralf S. Engelschall] ++ ++ *) Fixed nasty rehash problem under `make -f Makefile.ssl links' ++ when "ssleay" is still not found. ++ [Ralf S. Engelschall] ++ ++ *) Added more platforms to Configure: Cray T3E, HPUX 11, ++ [Ralf S. Engelschall, Beckmann ] ++ ++ *) Updated the README file. ++ [Ralf S. Engelschall] ++ ++ *) Added various .cvsignore files in the CVS repository subdirs ++ to make a "cvs update" really silent. ++ [Ralf S. Engelschall] ++ ++ *) Recompiled the error-definition header files and added ++ missing symbols to the Win32 linker tables. ++ [Ralf S. Engelschall] ++ ++ *) Cleaned up the top-level documents; ++ o new files: CHANGES and LICENSE ++ o merged VERSION, HISTORY* and README* files a CHANGES.SSLeay ++ o merged COPYRIGHT into LICENSE ++ o removed obsolete TODO file ++ o renamed MICROSOFT to INSTALL.W32 ++ [Ralf S. Engelschall] ++ ++ *) Removed dummy files from the 0.9.1b source tree: ++ crypto/asn1/x crypto/bio/cd crypto/bio/fg crypto/bio/grep crypto/bio/vi ++ crypto/bn/asm/......add.c crypto/bn/asm/a.out crypto/dsa/f crypto/md5/f ++ crypto/pem/gmon.out crypto/perlasm/f crypto/pkcs7/build crypto/rsa/f ++ crypto/sha/asm/f crypto/threads/f ms/zzz ssl/f ssl/f.mak test/f ++ util/f.mak util/pl/f util/pl/f.mak crypto/bf/bf_locl.old apps/f ++ [Ralf S. Engelschall] ++ ++ *) Added various platform portability fixes. ++ [Mark J. Cox] ++ ++ *) The Genesis of the OpenSSL rpject: ++ We start with the latest (unreleased) SSLeay version 0.9.1b which Eric A. ++ Young and Tim J. Hudson created while they were working for C2Net until ++ summer 1998. ++ [The OpenSSL Project] ++ ++ ++ Changes between 0.9.0b and 0.9.1b [not released] ++ ++ *) Updated a few CA certificates under certs/ ++ [Eric A. Young] ++ ++ *) Changed some BIGNUM api stuff. ++ [Eric A. Young] ++ ++ *) Various platform ports: OpenBSD, Ultrix, IRIX 64bit, NetBSD, ++ DGUX x86, Linux Alpha, etc. ++ [Eric A. Young] ++ ++ *) New COMP library [crypto/comp/] for SSL Record Layer Compression: ++ RLE (dummy implemented) and ZLIB (really implemented when ZLIB is ++ available). ++ [Eric A. Young] ++ ++ *) Add -strparse option to asn1pars program which parses nested ++ binary structures ++ [Dr Stephen Henson ] ++ ++ *) Added "oid_file" to ssleay.cnf for "ca" and "req" programs. ++ [Eric A. Young] ++ ++ *) DSA fix for "ca" program. ++ [Eric A. Young] ++ ++ *) Added "-genkey" option to "dsaparam" program. ++ [Eric A. Young] ++ ++ *) Added RIPE MD160 (rmd160) message digest. ++ [Eric A. Young] ++ ++ *) Added -a (all) option to "ssleay version" command. ++ [Eric A. Young] ++ ++ *) Added PLATFORM define which is the id given to Configure. ++ [Eric A. Young] ++ ++ *) Added MemCheck_XXXX functions to crypto/mem.c for memory checking. ++ [Eric A. Young] ++ ++ *) Extended the ASN.1 parser routines. ++ [Eric A. Young] ++ ++ *) Extended BIO routines to support REUSEADDR, seek, tell, etc. ++ [Eric A. Young] ++ ++ *) Added a BN_CTX to the BN library. ++ [Eric A. Young] ++ ++ *) Fixed the weak key values in DES library ++ [Eric A. Young] ++ ++ *) Changed API in EVP library for cipher aliases. ++ [Eric A. Young] ++ ++ *) Added support for RC2/64bit cipher. ++ [Eric A. Young] ++ ++ *) Converted the lhash library to the crypto/mem.c functions. ++ [Eric A. Young] ++ ++ *) Added more recognized ASN.1 object ids. ++ [Eric A. Young] ++ ++ *) Added more RSA padding checks for SSL/TLS. ++ [Eric A. Young] ++ ++ *) Added BIO proxy/filter functionality. ++ [Eric A. Young] ++ ++ *) Added extra_certs to SSL_CTX which can be used ++ send extra CA certificates to the client in the CA cert chain sending ++ process. It can be configured with SSL_CTX_add_extra_chain_cert(). ++ [Eric A. Young] ++ ++ *) Now Fortezza is denied in the authentication phase because ++ this is key exchange mechanism is not supported by SSLeay at all. ++ [Eric A. Young] ++ ++ *) Additional PKCS1 checks. ++ [Eric A. Young] ++ ++ *) Support the string "TLSv1" for all TLS v1 ciphers. ++ [Eric A. Young] ++ ++ *) Added function SSL_get_ex_data_X509_STORE_CTX_idx() which gives the ++ ex_data index of the SSL context in the X509_STORE_CTX ex_data. ++ [Eric A. Young] ++ ++ *) Fixed a few memory leaks. ++ [Eric A. Young] ++ ++ *) Fixed various code and comment typos. ++ [Eric A. Young] ++ ++ *) A minor bug in ssl/s3_clnt.c where there would always be 4 0 ++ bytes sent in the client random. ++ [Edward Bishop ] ++ +diff --git a/CryptoPkg/Library/OpensslLib/openssl/CONTRIBUTING b/CryptoPkg/Library/OpensslLib/openssl/CONTRIBUTING +new file mode 100644 +index 0000000..1eebaf3 +--- /dev/null ++++ b/CryptoPkg/Library/OpensslLib/openssl/CONTRIBUTING +@@ -0,0 +1,54 @@ ++HOW TO CONTRIBUTE PATCHES TO OpenSSL ++------------------------------------ ++ ++(Please visit https://www.openssl.org/community/getting-started.html for ++other ideas about how to contribute.) ++ ++Development is coordinated on the openssl-dev mailing list (see the ++above link or https://mta.openssl.org for information on subscribing). ++If you are unsure as to whether a feature will be useful for the general ++OpenSSL community you might want to discuss it on the openssl-dev mailing ++list first. Someone may be already working on the same thing or there ++may be a good reason as to why that feature isn't implemented. ++ ++To submit a patch, make a pull request on GitHub. If you think the patch ++could use feedback from the community, please start a thread on openssl-dev ++to discuss it. ++ ++Having addressed the following items before the PR will help make the ++acceptance and review process faster: ++ ++ 1. Anything other than trivial contributions will require a contributor ++ licensing agreement, giving us permission to use your code. See ++ https://www.openssl.org/policies/cla.html for details. ++ ++ 2. All source files should start with the following text (with ++ appropriate comment characters at the start of each line and the ++ year(s) updated): ++ ++ Copyright 20xx-20yy 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 ++ in the file LICENSE in the source distribution or at ++ https://www.openssl.org/source/license.html ++ ++ 3. Patches should be as current as possible; expect to have to rebase ++ often. We do not accept merge commits; You will be asked to remove ++ them before a patch is considered acceptable. ++ ++ 4. Patches should follow our coding style (see ++ https://www.openssl.org/policies/codingstyle.html) and compile without ++ warnings. Where gcc or clang is available you should use the ++ --strict-warnings Configure option. OpenSSL compiles on many varied ++ platforms: try to ensure you only use portable features. ++ Clean builds via Travis and AppVeyor are expected, and done whenever ++ a PR is created or updated. ++ ++ 5. When at all possible, patches should include tests. These can ++ either be added to an existing test, or completely new. Please see ++ test/README for information on the test framework. ++ ++ 6. New features or changed functionality must include ++ documentation. Please look at the "pod" files in doc/apps, doc/crypto ++ and doc/ssl for examples of our style. +diff --git a/CryptoPkg/Library/OpensslLib/openssl/Configurations/00-base-templates.conf b/CryptoPkg/Library/OpensslLib/openssl/Configurations/00-base-templates.conf +new file mode 100644 +index 0000000..3455b3a +--- /dev/null ++++ b/CryptoPkg/Library/OpensslLib/openssl/Configurations/00-base-templates.conf +@@ -0,0 +1,293 @@ ++# -*- Mode: perl -*- ++%targets=( ++ DEFAULTS => { ++ template => 1, ++ ++ cflags => "", ++ defines => [], ++ thread_scheme => "(unknown)", # Assume we don't know ++ thread_defines => [], ++ ++ apps_aux_src => "", ++ cpuid_asm_src => "mem_clr.c", ++ uplink_aux_src => "", ++ bn_asm_src => "bn_asm.c", ++ ec_asm_src => "", ++ des_asm_src => "des_enc.c fcrypt_b.c", ++ aes_asm_src => "aes_core.c aes_cbc.c", ++ bf_asm_src => "bf_enc.c", ++ md5_asm_src => "", ++ cast_asm_src => "c_enc.c", ++ rc4_asm_src => "rc4_enc.c rc4_skey.c", ++ rmd160_asm_src => "", ++ rc5_asm_src => "rc5_enc.c", ++ wp_asm_src => "wp_block.c", ++ cmll_asm_src => "camellia.c cmll_misc.c cmll_cbc.c", ++ modes_asm_src => "", ++ padlock_asm_src => "", ++ chacha_asm_src => "chacha_enc.c", ++ poly1305_asm_src => "", ++ ++ unistd => "", ++ shared_target => "", ++ shared_cflag => "", ++ shared_defines => [], ++ shared_ldflag => "", ++ shared_rcflag => "", ++ shared_extension => "", ++ ++ build_scheme => [ "unified", "unix" ], ++ build_file => "Makefile", ++ }, ++ ++ BASE_common => { ++ template => 1, ++ defines => ++ sub { ++ my @defs = (); ++ push @defs, "ZLIB" unless $disabled{zlib}; ++ push @defs, "ZLIB_SHARED" unless $disabled{"zlib-dynamic"}; ++ return [ @defs ]; ++ }, ++ }, ++ ++ BASE_unix => { ++ inherit_from => [ "BASE_common" ], ++ template => 1, ++ ++ ex_libs => ++ sub { ++ unless ($disabled{zlib}) { ++ if (defined($disabled{"zlib-dynamic"})) { ++ if (defined($withargs{zlib_lib})) { ++ return "-L".$withargs{zlib_lib}." -lz"; ++ } else { ++ return "-lz"; ++ } ++ } ++ } ++ return (); }, ++ ++ build_scheme => [ "unified", "unix" ], ++ build_file => "Makefile", ++ }, ++ ++ BASE_Windows => { ++ inherit_from => [ "BASE_common" ], ++ template => 1, ++ ++ ex_libs => ++ sub { ++ unless ($disabled{zlib}) { ++ if (defined($disabled{"zlib-dynamic"})) { ++ return $withargs{zlib_lib} // "ZLIB1"; ++ } ++ } ++ return (); ++ }, ++ ++ ld => "link", ++ lflags => "/nologo", ++ loutflag => "/out:", ++ ar => "lib", ++ arflags => "/nologo", ++ aroutflag => "/out:", ++ rc => "rc", ++ rcoutflag => "/fo", ++ mt => "mt", ++ mtflags => "-nologo", ++ mtinflag => "-manifest ", ++ mtoutflag => "-outputresource:", ++ ++ build_file => "makefile", ++ build_scheme => [ "unified", "windows" ], ++ }, ++ ++ BASE_VMS => { ++ inherit_from => [ "BASE_common" ], ++ template => 1, ++ ++ build_file => "descrip.mms", ++ build_scheme => [ "unified", "VMS" ], ++ }, ++ ++ uplink_common => { ++ template => 1, ++ apps_aux_src => add("../ms/applink.c"), ++ uplink_aux_src => add("../ms/uplink.c"), ++ defines => add("OPENSSL_USE_APPLINK"), ++ }, ++ x86_uplink => { ++ inherit_from => [ "uplink_common" ], ++ template => 1, ++ uplink_aux_src => add("uplink-x86.s"), ++ }, ++ x86_64_uplink => { ++ inherit_from => [ "uplink_common" ], ++ template => 1, ++ uplink_aux_src => add("uplink-x86_64.s"), ++ }, ++ ia64_uplink => { ++ inherit_from => [ "uplink_common" ], ++ template => 1, ++ uplink_aux_src => add("uplink-ia64.s"), ++ }, ++ ++ x86_asm => { ++ template => 1, ++ cpuid_asm_src => "x86cpuid.s", ++ bn_asm_src => "bn-586.s co-586.s x86-mont.s x86-gf2m.s", ++ ec_asm_src => "ecp_nistz256.c ecp_nistz256-x86.s", ++ des_asm_src => "des-586.s crypt586.s", ++ aes_asm_src => "aes-586.s vpaes-x86.s aesni-x86.s", ++ bf_asm_src => "bf-586.s", ++ md5_asm_src => "md5-586.s", ++ cast_asm_src => "cast-586.s", ++ sha1_asm_src => "sha1-586.s sha256-586.s sha512-586.s", ++ rc4_asm_src => "rc4-586.s", ++ rmd160_asm_src => "rmd-586.s", ++ rc5_asm_src => "rc5-586.s", ++ wp_asm_src => "wp_block.c wp-mmx.s", ++ cmll_asm_src => "cmll-x86.s", ++ modes_asm_src => "ghash-x86.s", ++ padlock_asm_src => "e_padlock-x86.s", ++ chacha_asm_src => "chacha-x86.s", ++ poly1305_asm_src=> "poly1305-x86.s", ++ }, ++ x86_elf_asm => { ++ template => 1, ++ inherit_from => [ "x86_asm" ], ++ perlasm_scheme => "elf" ++ }, ++ x86_64_asm => { ++ template => 1, ++ cpuid_asm_src => "x86_64cpuid.s", ++ bn_asm_src => "asm/x86_64-gcc.c x86_64-mont.s x86_64-mont5.s x86_64-gf2m.s rsaz_exp.c rsaz-x86_64.s rsaz-avx2.s", ++ ec_asm_src => "ecp_nistz256.c ecp_nistz256-x86_64.s", ++ aes_asm_src => "aes-x86_64.s vpaes-x86_64.s bsaes-x86_64.s aesni-x86_64.s aesni-sha1-x86_64.s aesni-sha256-x86_64.s aesni-mb-x86_64.s", ++ md5_asm_src => "md5-x86_64.s", ++ sha1_asm_src => "sha1-x86_64.s sha256-x86_64.s sha512-x86_64.s sha1-mb-x86_64.s sha256-mb-x86_64.s", ++ rc4_asm_src => "rc4-x86_64.s rc4-md5-x86_64.s", ++ wp_asm_src => "wp-x86_64.s", ++ cmll_asm_src => "cmll-x86_64.s cmll_misc.c", ++ modes_asm_src => "ghash-x86_64.s aesni-gcm-x86_64.s", ++ padlock_asm_src => "e_padlock-x86_64.s", ++ chacha_asm_src => "chacha-x86_64.s", ++ poly1305_asm_src=> "poly1305-x86_64.s", ++ }, ++ ia64_asm => { ++ template => 1, ++ cpuid_asm_src => "ia64cpuid.s", ++ bn_asm_src => "bn-ia64.s ia64-mont.s", ++ aes_asm_src => "aes_core.c aes_cbc.c aes-ia64.s", ++ md5_asm_src => "md5-ia64.s", ++ sha1_asm_src => "sha1-ia64.s sha256-ia64.s sha512-ia64.s", ++ rc4_asm_src => "rc4-ia64.s rc4_skey.c", ++ modes_asm_src => "ghash-ia64.s", ++ perlasm_scheme => "void" ++ }, ++ sparcv9_asm => { ++ template => 1, ++ cpuid_asm_src => "sparcv9cap.c sparccpuid.S", ++ bn_asm_src => "asm/sparcv8plus.S sparcv9-mont.S sparcv9a-mont.S vis3-mont.S sparct4-mont.S sparcv9-gf2m.S", ++ ec_asm_src => "ecp_nistz256.c ecp_nistz256-sparcv9.S", ++ des_asm_src => "des_enc-sparc.S fcrypt_b.c dest4-sparcv9.S", ++ aes_asm_src => "aes_core.c aes_cbc.c aes-sparcv9.S aest4-sparcv9.S aesfx-sparcv9.S", ++ md5_asm_src => "md5-sparcv9.S", ++ sha1_asm_src => "sha1-sparcv9.S sha256-sparcv9.S sha512-sparcv9.S", ++ cmll_asm_src => "camellia.c cmll_misc.c cmll_cbc.c cmllt4-sparcv9.S", ++ modes_asm_src => "ghash-sparcv9.S", ++ poly1305_asm_src=> "poly1305-sparcv9.S", ++ perlasm_scheme => "void" ++ }, ++ sparcv8_asm => { ++ template => 1, ++ cpuid_asm_src => "", ++ bn_asm_src => "asm/sparcv8.S", ++ des_asm_src => "des_enc-sparc.S fcrypt_b.c", ++ perlasm_scheme => "void" ++ }, ++ alpha_asm => { ++ template => 1, ++ cpuid_asm_src => "alphacpuid.s", ++ bn_asm_src => "bn_asm.c alpha-mont.S", ++ sha1_asm_src => "sha1-alpha.S", ++ modes_asm_src => "ghash-alpha.S", ++ perlasm_scheme => "void" ++ }, ++ mips32_asm => { ++ template => 1, ++ bn_asm_src => "bn-mips.s mips-mont.s", ++ aes_asm_src => "aes_cbc.c aes-mips.S", ++ sha1_asm_src => "sha1-mips.S sha256-mips.S", ++ }, ++ mips64_asm => { ++ inherit_from => [ "mips32_asm" ], ++ template => 1, ++ sha1_asm_src => add("sha512-mips.S"), ++ poly1305_asm_src=> "poly1305-mips.S", ++ }, ++ s390x_asm => { ++ template => 1, ++ cpuid_asm_src => "s390xcap.c s390xcpuid.S", ++ bn_asm_src => "asm/s390x.S s390x-mont.S s390x-gf2m.s", ++ aes_asm_src => "aes-s390x.S aes-ctr.fake aes-xts.fake", ++ sha1_asm_src => "sha1-s390x.S sha256-s390x.S sha512-s390x.S", ++ rc4_asm_src => "rc4-s390x.s", ++ modes_asm_src => "ghash-s390x.S", ++ chacha_asm_src => "chacha-s390x.S", ++ poly1305_asm_src=> "poly1305-s390x.S", ++ }, ++ armv4_asm => { ++ template => 1, ++ cpuid_asm_src => "armcap.c armv4cpuid.S", ++ bn_asm_src => "bn_asm.c armv4-mont.S armv4-gf2m.S", ++ ec_asm_src => "ecp_nistz256.c ecp_nistz256-armv4.S", ++ aes_asm_src => "aes_cbc.c aes-armv4.S bsaes-armv7.S aesv8-armx.S", ++ sha1_asm_src => "sha1-armv4-large.S sha256-armv4.S sha512-armv4.S", ++ modes_asm_src => "ghash-armv4.S ghashv8-armx.S", ++ chacha_asm_src => "chacha-armv4.S", ++ poly1305_asm_src=> "poly1305-armv4.S", ++ perlasm_scheme => "void" ++ }, ++ aarch64_asm => { ++ template => 1, ++ cpuid_asm_src => "armcap.c arm64cpuid.S", ++ ec_asm_src => "ecp_nistz256.c ecp_nistz256-armv8.S", ++ bn_asm_src => "bn_asm.c armv8-mont.S", ++ aes_asm_src => "aes_core.c aes_cbc.c aesv8-armx.S vpaes-armv8.S", ++ sha1_asm_src => "sha1-armv8.S sha256-armv8.S sha512-armv8.S", ++ modes_asm_src => "ghashv8-armx.S", ++ chacha_asm_src => "chacha-armv8.S", ++ poly1305_asm_src=> "poly1305-armv8.S", ++ }, ++ parisc11_asm => { ++ template => 1, ++ cpuid_asm_src => "pariscid.s", ++ bn_asm_src => "bn_asm.c parisc-mont.s", ++ aes_asm_src => "aes_core.c aes_cbc.c aes-parisc.s", ++ sha1_asm_src => "sha1-parisc.s sha256-parisc.s sha512-parisc.s", ++ rc4_asm_src => "rc4-parisc.s", ++ modes_asm_src => "ghash-parisc.s", ++ perlasm_scheme => "32" ++ }, ++ parisc20_64_asm => { ++ template => 1, ++ inherit_from => [ "parisc11_asm" ], ++ perlasm_scheme => "64", ++ }, ++ ppc64_asm => { ++ template => 1, ++ cpuid_asm_src => "ppccpuid.s ppccap.c", ++ bn_asm_src => "bn-ppc.s ppc-mont.s ppc64-mont.s", ++ aes_asm_src => "aes_core.c aes_cbc.c aes-ppc.s vpaes-ppc.s aesp8-ppc.s", ++ sha1_asm_src => "sha1-ppc.s sha256-ppc.s sha512-ppc.s sha256p8-ppc.s sha512p8-ppc.s", ++ modes_asm_src => "ghashp8-ppc.s", ++ chacha_asm_src => "chacha-ppc.s", ++ poly1305_asm_src=> "poly1305-ppc.s poly1305-ppcfp.s", ++ }, ++ ppc32_asm => { ++ inherit_from => [ "ppc64_asm" ], ++ template => 1 ++ }, ++); +diff --git a/CryptoPkg/Library/OpensslLib/openssl/Configurations/10-main.conf b/CryptoPkg/Library/OpensslLib/openssl/Configurations/10-main.conf +new file mode 100644 +index 0000000..985220f +--- /dev/null ++++ b/CryptoPkg/Library/OpensslLib/openssl/Configurations/10-main.conf +@@ -0,0 +1,1894 @@ ++## -*- mode: perl; -*- ++## Standard openssl configuration targets. ++ ++# Helper functions for the Windows configs ++my $vc_win64a_info = {}; ++sub vc_win64a_info { ++ unless (%$vc_win64a_info) { ++ if (`nasm -v 2>NUL` =~ /NASM version ([0-9]+\.[0-9]+)/ && $1 >= 2.0) { ++ $vc_win64a_info = { as => "nasm", ++ asflags => "-f win64 -DNEAR -Ox -g", ++ asoutflag => "-o" }; ++ } elsif ($disabled{asm}) { ++ $vc_win64a_info = { as => "ml64", ++ asflags => "/c /Cp /Cx /Zi", ++ asoutflag => "/Fo" }; ++ } else { ++ $die->("NASM not found - please read INSTALL and NOTES.WIN for further details\n"); ++ $vc_win64a_info = { as => "{unknown}", ++ asflags => "", ++ asoutflag => "" }; ++ } ++ } ++ return $vc_win64a_info; ++} ++ ++my $vc_win32_info = {}; ++sub vc_win32_info { ++ unless (%$vc_win32_info) { ++ my $ver=`nasm -v 2>NUL`; ++ my $vew=`nasmw -v 2>NUL`; ++ if ($ver ne "" || $vew ne "") { ++ $vc_win32_info = { as => $ver ge $vew ? "nasm" : "nasmw", ++ asflags => "-f win32", ++ asoutflag => "-o", ++ perlasm_scheme => "win32n" }; ++ } elsif ($disabled{asm}) { ++ $vc_win32_info = { as => "ml", ++ asflags => "/nologo /Cp /coff /c /Cx /Zi", ++ asoutflag => "/Fo", ++ perlasm_scheme => "win32" }; ++ } else { ++ $die->("NASM not found - please read INSTALL and NOTES.WIN for further details\n"); ++ $vc_win32_info = { as => "{unknown}", ++ asflags => "", ++ asoutflag => "", ++ perlasm_scheme => "win32" }; ++ } ++ } ++ return $vc_win32_info; ++} ++ ++my $vc_wince_info = {}; ++sub vc_wince_info { ++ unless (%$vc_wince_info) { ++ # sanity check ++ $die->('%OSVERSION% is not defined') if (!defined($ENV{'OSVERSION'})); ++ $die->('%PLATFORM% is not defined') if (!defined($ENV{'PLATFORM'})); ++ $die->('%TARGETCPU% is not defined') if (!defined($ENV{'TARGETCPU'})); ++ ++ # ++ # Idea behind this is to mimic flags set by eVC++ IDE... ++ # ++ my $wcevers = $ENV{'OSVERSION'}; # WCENNN ++ my $wcevernum; ++ my $wceverdotnum; ++ if ($wcevers =~ /^WCE([1-9])([0-9]{2})$/) { ++ $wcevernum = "$1$2"; ++ $wceverdotnum = "$1.$2"; ++ } else { ++ $die->('%OSVERSION% value is insane'); ++ $wcevernum = "{unknown}"; ++ $wceverdotnum = "{unknown}"; ++ } ++ my $wcecdefs = "-D_WIN32_WCE=$wcevernum -DUNDER_CE=$wcevernum"; # -D_WIN32_WCE=NNN ++ my $wcelflag = "/subsystem:windowsce,$wceverdotnum"; # ...,N.NN ++ ++ my $wceplatf = $ENV{'PLATFORM'}; ++ ++ $wceplatf =~ tr/a-z0-9 /A-Z0-9_/; ++ $wcecdefs .= " -DWCE_PLATFORM_$wceplatf"; ++ ++ my $wcetgt = $ENV{'TARGETCPU'}; # just shorter name... ++ SWITCH: for($wcetgt) { ++ /^X86/ && do { $wcecdefs.=" -Dx86 -D_X86_ -D_i386_ -Di_386_"; ++ $wcelflag.=" /machine:X86"; last; }; ++ /^ARMV4[IT]/ && do { $wcecdefs.=" -DARM -D_ARM_ -D$wcetgt"; ++ $wcecdefs.=" -DTHUMB -D_THUMB_" if($wcetgt=~/T$/); ++ $wcecdefs.=" -QRarch4T -QRinterwork-return"; ++ $wcelflag.=" /machine:THUMB"; last; }; ++ /^ARM/ && do { $wcecdefs.=" -DARM -D_ARM_ -D$wcetgt"; ++ $wcelflag.=" /machine:ARM"; last; }; ++ /^MIPSIV/ && do { $wcecdefs.=" -DMIPS -D_MIPS_ -DR4000 -D$wcetgt"; ++ $wcecdefs.=" -D_MIPS64 -QMmips4 -QMn32"; ++ $wcelflag.=" /machine:MIPSFPU"; last; }; ++ /^MIPS16/ && do { $wcecdefs.=" -DMIPS -D_MIPS_ -DR4000 -D$wcetgt"; ++ $wcecdefs.=" -DMIPSII -QMmips16"; ++ $wcelflag.=" /machine:MIPS16"; last; }; ++ /^MIPSII/ && do { $wcecdefs.=" -DMIPS -D_MIPS_ -DR4000 -D$wcetgt"; ++ $wcecdefs.=" -QMmips2"; ++ $wcelflag.=" /machine:MIPS"; last; }; ++ /^R4[0-9]{3}/ && do { $wcecdefs.=" -DMIPS -D_MIPS_ -DR4000"; ++ $wcelflag.=" /machine:MIPS"; last; }; ++ /^SH[0-9]/ && do { $wcecdefs.=" -D$wcetgt -D_${wcetgt}_ -DSHx"; ++ $wcecdefs.=" -Qsh4" if ($wcetgt =~ /^SH4/); ++ $wcelflag.=" /machine:$wcetgt"; last; }; ++ { $wcecdefs.=" -D$wcetgt -D_${wcetgt}_"; ++ $wcelflag.=" /machine:$wcetgt"; last; }; ++ } ++ ++ $vc_wince_info = { cflags => $wcecdefs, ++ lflags => $wcelflag }; ++ } ++ return $vc_wince_info; ++} ++ ++# Helper functions for the VMS configs ++my $vms_info = {}; ++sub vms_info { ++ unless (%$vms_info) { ++ my $pointer_size = shift; ++ my $pointer_size_str = $pointer_size == 0 ? "" : "$pointer_size"; ++ ++ $vms_info->{disable_warns} = [ ]; ++ $vms_info->{pointer_size} = $pointer_size_str; ++ if ($pointer_size == 64) { ++ `PIPE CC /NOCROSS_REFERENCE /NOLIST /NOOBJECT /WARNINGS = DISABLE = ( MAYLOSEDATA3, EMPTYFILE ) NL: 2> NL:`; ++ if ($? == 0) { ++ push @{$vms_info->{disable_warns}}, "MAYLOSEDATA3"; ++ } ++ } ++ ++ unless ($disabled{zlib}) { ++ my $default_zlib = 'GNV$LIBZSHR' . $pointer_size_str; ++ if (defined($disabled{"zlib-dynamic"})) { ++ $vms_info->{zlib} = $withargs{zlib_lib} || "$default_zlib/SHARE"; ++ } else { ++ $vms_info->{def_zlib} = $withargs{zlib_lib} || $default_zlib; ++ # In case the --with-zlib-lib value contains something like ++ # /SHARE or /LIB or so at the end, remove it. ++ $vms_info->{def_zlib} =~ s|/.*$||g; ++ } ++ } ++ } ++ return $vms_info; ++} ++ ++%targets = ( ++ ++#### Basic configs that should work on any 32-bit box ++ "gcc" => { ++ cc => "gcc", ++ cflags => picker(debug => "-O0 -g", ++ release => "-O3"), ++ thread_scheme => "(unknown)", ++ bn_ops => "BN_LLONG", ++ }, ++ "cc" => { ++ cc => "cc", ++ cflags => "-O", ++ thread_scheme => "(unknown)", ++ }, ++ ++#### VOS Configurations ++ "vos-gcc" => { ++ inherit_from => [ "BASE_unix" ], ++ cc => "gcc", ++ cflags => picker(default => "-Wall -DOPENSSL_SYS_VOS -D_POSIX_C_SOURCE=200112L -D_BSD -D_VOS_EXTENDED_NAMES -DB_ENDIAN", ++ debug => "-O0 -g", ++ release => "-O3"), ++ thread_scheme => "(unknown)", ++ sys_id => "VOS", ++ lflags => "-Wl,-map", ++ bn_ops => "BN_LLONG", ++ shared_extension => ".so", ++ }, ++ ++#### Solaris configurations ++ "solaris-common" => { ++ inherit_from => [ "BASE_unix" ], ++ template => 1, ++ cflags => "-DFILIO_H", ++ ex_libs => add("-lresolv -lsocket -lnsl -ldl"), ++ dso_scheme => "dlfcn", ++ thread_scheme => "pthreads", ++ shared_target => "solaris-shared", ++ shared_extension => ".so.\$(SHLIB_MAJOR).\$(SHLIB_MINOR)", ++ }, ++#### Solaris x86 with GNU C setups ++ "solaris-x86-gcc" => { ++ # NB. GNU C has to be configured to use GNU assembler, and not ++ # /usr/ccs/bin/as. Failure to comply will result in compile ++ # failures [at least] in 32-bit build. ++ # [Above statement is in direct contradition with one below. ++ # Latter is kept, because it's formally inappropriate to ++ # modify compile flags in letter release.] ++ # -DOPENSSL_NO_INLINE_ASM switches off inline assembler. We have ++ # to do it here because whenever GNU C instantiates an assembler ++ # template it surrounds it with #APP #NO_APP comment pair which ++ # (at least Solaris 7_x86) /usr/ccs/bin/as fails to assemble ++ # with "Illegal mnemonic" error message. ++ inherit_from => [ "solaris-common", asm("x86_elf_asm") ], ++ cc => "gcc", ++ cflags => add_before(picker(default => "-Wall -DL_ENDIAN -DOPENSSL_NO_INLINE_ASM", ++ debug => "-O0 -g", ++ release => "-O3 -fomit-frame-pointer"), ++ threads("-pthread")), ++ bn_ops => "BN_LLONG", ++ shared_cflag => "-fPIC", ++ shared_ldflag => "-shared -static-libgcc", ++ }, ++ "solaris64-x86_64-gcc" => { ++ # -shared -static-libgcc might appear controversial, but modules ++ # taken from static libgcc do not have relocations and linking ++ # them into our shared objects doesn't have any negative side ++ # effects. On the contrary, doing so makes it possible to use ++ # gcc shared build with Sun C. Given that gcc generates faster ++ # code [thanks to inline assembler], I would actually recommend ++ # to consider using gcc shared build even with vendor compiler:-) ++ # ++ inherit_from => [ "solaris-common", asm("x86_64_asm") ], ++ cc => "gcc", ++ cflags => add_before(picker(default => "-m64 -Wall -DL_ENDIAN", ++ debug => "-O0 -g", ++ release => "-O3"), ++ threads("-pthread")), ++ bn_ops => "SIXTY_FOUR_BIT_LONG", ++ perlasm_scheme => "elf", ++ shared_cflag => "-fPIC", ++ shared_ldflag => "-m64 -shared -static-libgcc", ++ multilib => "/64", ++ }, ++ ++#### Solaris x86 with Sun C setups ++ # There used to be solaris-x86-cc target, but it was removed, ++ # primarily because vendor assembler can't assemble our modules ++ # with -KPIC flag. As result it, assembly support, was not even ++ # available as option. But its lack means lack of side-channel ++ # resistant code, which is incompatible with security by todays ++ # standards. Fortunately gcc is readily available prepackaged ++ # option, which we can firmly point at... ++ # ++ # On related note, solaris64-x86_64-cc target won't compile code ++ # paths utilizing AVX and post-Haswell instruction extensions. ++ # Consider switching to solaris64-x86_64-gcc even here... ++ # ++ "solaris64-x86_64-cc" => { ++ inherit_from => [ "solaris-common", asm("x86_64_asm") ], ++ cc => "cc", ++ cflags => add_before(picker(default => "-xarch=generic64 -xstrconst -Xa -DL_ENDIAN", ++ debug => "-g", ++ release => "-xO5 -xdepend -xbuiltin"), ++ threads("-D_REENTRANT")), ++ thread_scheme => "pthreads", ++ lflags => add("-xarch=generic64",threads("-mt")), ++ ex_libs => add(threads("-lpthread")), ++ bn_ops => "SIXTY_FOUR_BIT_LONG", ++ perlasm_scheme => "elf", ++ shared_cflag => "-KPIC", ++ shared_ldflag => "-xarch=generic64 -G -dy -z text", ++ multilib => "/64", ++ }, ++ ++#### SPARC Solaris with GNU C setups ++ "solaris-sparcv7-gcc" => { ++ inherit_from => [ "solaris-common" ], ++ cc => "gcc", ++ cflags => add_before(picker(default => "-Wall -DB_ENDIAN -DBN_DIV2W", ++ debug => "-O0 -g", ++ release => "-O3"), ++ threads("-pthread")), ++ bn_ops => "BN_LLONG RC4_CHAR", ++ shared_cflag => "-fPIC", ++ shared_ldflag => "-shared", ++ }, ++ "solaris-sparcv8-gcc" => { ++ inherit_from => [ "solaris-sparcv7-gcc", asm("sparcv8_asm") ], ++ cflags => add_before("-mcpu=v8"), ++ }, ++ "solaris-sparcv9-gcc" => { ++ # -m32 should be safe to add as long as driver recognizes ++ # -mcpu=ultrasparc ++ inherit_from => [ "solaris-sparcv7-gcc", asm("sparcv9_asm") ], ++ cflags => add_before("-m32 -mcpu=ultrasparc"), ++ }, ++ "solaris64-sparcv9-gcc" => { ++ inherit_from => [ "solaris-sparcv9-gcc" ], ++ cflags => sub { my $f=join(" ",@_); $f =~ s/\-m32/-m64/; $f; }, ++ bn_ops => "BN_LLONG RC4_CHAR", ++ shared_ldflag => "-m64 -shared", ++ multilib => "/64", ++ }, ++ ++#### SPARC Solaris with Sun C setups ++# SC4.0 doesn't pass 'make test', upgrade to SC5.0 or SC4.2. ++# SC4.2 is ok, better than gcc even on bn as long as you tell it -xarch=v8 ++# SC5.0 note: Compiler common patch 107357-01 or later is required! ++ "solaris-sparcv7-cc" => { ++ inherit_from => [ "solaris-common" ], ++ cc => "cc", ++ cflags => add_before(picker(default => "-xstrconst -Xa -DB_ENDIAN -DBN_DIV2W", ++ debug => "-g", ++ release => "-xO5 -xdepend"), ++ threads("-D_REENTRANT")), ++ lflags => add(threads("-mt")), ++ ex_libs => add(threads("-lpthread")), ++ bn_ops => "BN_LLONG RC4_CHAR", ++ shared_cflag => "-KPIC", ++ shared_ldflag => "-G -dy -z text", ++ }, ++#### ++ "solaris-sparcv8-cc" => { ++ inherit_from => [ "solaris-sparcv7-cc", asm("sparcv8_asm") ], ++ cflags => add_before("-xarch=v8"), ++ }, ++ "solaris-sparcv9-cc" => { ++ inherit_from => [ "solaris-sparcv7-cc", asm("sparcv9_asm") ], ++ cflags => add_before("-xarch=v8plus"), ++ }, ++ "solaris64-sparcv9-cc" => { ++ inherit_from => [ "solaris-sparcv7-cc", asm("sparcv9_asm") ], ++ cflags => add_before("-xarch=v9"), ++ lflags => add_before("-xarch=v9"), ++ bn_ops => "BN_LLONG RC4_CHAR", ++ shared_ldflag => "-xarch=v9 -G -dy -z text", ++ multilib => "/64", ++ }, ++ ++#### IRIX 6.x configs ++# Only N32 and N64 ABIs are supported. ++ "irix-mips3-gcc" => { ++ inherit_from => [ "BASE_unix", asm("mips64_asm") ], ++ cc => "gcc", ++ cflags => combine(picker(default => "-mabi=n32 -DB_ENDIAN -DBN_DIV3W", ++ debug => "-g -O0", ++ release => "-O3"), ++ threads("-D_SGI_MP_SOURCE")), ++ ex_libs => add(threads("-lpthread")), ++ bn_ops => "RC4_CHAR SIXTY_FOUR_BIT", ++ thread_scheme => "pthreads", ++ perlasm_scheme => "n32", ++ dso_scheme => "dlfcn", ++ shared_target => "irix-shared", ++ shared_ldflag => "-mabi=n32", ++ shared_extension => ".so.\$(SHLIB_MAJOR).\$(SHLIB_MINOR)", ++ multilib => "32", ++ }, ++ "irix-mips3-cc" => { ++ inherit_from => [ "BASE_unix", asm("mips64_asm") ], ++ cc => "cc", ++ cflags => combine(picker(default => "-n32 -mips3 -use_readonly_const -G0 -rdata_shared -DB_ENDIAN -DBN_DIV3W", ++ debug => "-g -O0", ++ release => "-O2"), ++ threads("-D_SGI_MP_SOURCE")), ++ ex_libs => add(threads("-lpthread")), ++ bn_ops => "RC4_CHAR SIXTY_FOUR_BIT", ++ thread_scheme => "pthreads", ++ perlasm_scheme => "n32", ++ dso_scheme => "dlfcn", ++ shared_target => "irix-shared", ++ shared_ldflag => "-n32", ++ shared_extension => ".so.\$(SHLIB_MAJOR).\$(SHLIB_MINOR)", ++ multilib => "32", ++ }, ++ # N64 ABI builds. ++ "irix64-mips4-gcc" => { ++ inherit_from => [ "BASE_unix", asm("mips64_asm") ], ++ cc => "gcc", ++ cflags => combine(picker(default => "-mabi=64 -mips4 -DB_ENDIAN -DBN_DIV3W", ++ debug => "-g -O0", ++ release => "-O3"), ++ threads("-D_SGI_MP_SOURCE")), ++ ex_libs => add(threads("-lpthread")), ++ bn_ops => "RC4_CHAR SIXTY_FOUR_BIT_LONG", ++ thread_scheme => "pthreads", ++ perlasm_scheme => "64", ++ dso_scheme => "dlfcn", ++ shared_target => "irix-shared", ++ shared_ldflag => "-mabi=64", ++ shared_extension => ".so.\$(SHLIB_MAJOR).\$(SHLIB_MINOR)", ++ multilib => "64", ++ }, ++ "irix64-mips4-cc" => { ++ inherit_from => [ "BASE_unix", asm("mips64_asm") ], ++ cc => "cc", ++ cflags => combine(picker(default => "-64 -mips4 -use_readonly_const -G0 -rdata_shared -DB_ENDIAN -DBN_DIV3W", ++ debug => "-g -O0", ++ release => "-O2"), ++ threads("-D_SGI_MP_SOURCE")), ++ ex_libs => add(threads("-lpthread")), ++ bn_ops => "RC4_CHAR SIXTY_FOUR_BIT_LONG", ++ thread_scheme => "pthreads", ++ perlasm_scheme => "64", ++ dso_scheme => "dlfcn", ++ shared_target => "irix-shared", ++ shared_ldflag => "-64", ++ shared_extension => ".so.\$(SHLIB_MAJOR).\$(SHLIB_MINOR)", ++ multilib => "64", ++ }, ++ ++#### Unified HP-UX ANSI C configs. ++# Special notes: ++# - Originally we were optimizing at +O4 level. It should be noted ++# that the only difference between +O3 and +O4 is global inter- ++# procedural analysis. As it has to be performed during the link ++# stage the compiler leaves behind certain pseudo-code in lib*.a ++# which might be release or even patch level specific. Generating ++# the machine code for and analyzing the *whole* program appears ++# to be *extremely* memory demanding while the performance gain is ++# actually questionable. The situation is intensified by the default ++# HP-UX data set size limit (infamous 'maxdsiz' tunable) of 64MB ++# which is way too low for +O4. In other words, doesn't +O3 make ++# more sense? ++# - Keep in mind that the HP compiler by default generates code ++# suitable for execution on the host you're currently compiling at. ++# If the toolkit is meant to be used on various PA-RISC processors ++# consider './Configure hpux-parisc-[g]cc +DAportable'. ++# - -DMD32_XARRAY triggers workaround for compiler bug we ran into in ++# 32-bit message digests. (For the moment of this writing) HP C ++# doesn't seem to "digest" too many local variables (they make "him" ++# chew forever:-). For more details look-up MD32_XARRAY comment in ++# crypto/sha/sha_lcl.h. ++# - originally there were 32-bit hpux-parisc2-* targets. They were ++# scrapped, because a) they were not interchangeable with other 32-bit ++# targets; b) performance-critical 32-bit assembly modules implement ++# even PA-RISC 2.0-specific code paths, which are chosen at run-time, ++# thus adequate performance is provided even with PA-RISC 1.1 build. ++# ++ "hpux-parisc-gcc" => { ++ inherit_from => [ "BASE_unix" ], ++ cc => "gcc", ++ cflags => combine(picker(default => "-DB_ENDIAN -DBN_DIV2W", ++ debug => "-O0 -g", ++ release => "-O3"), ++ threads("-pthread")), ++ ex_libs => add("-Wl,+s -ldld"), ++ bn_ops => "BN_LLONG", ++ thread_scheme => "pthreads", ++ dso_scheme => "dl", ++ shared_target => "hpux-shared", ++ shared_cflag => "-fPIC", ++ shared_ldflag => "-shared", ++ shared_extension => ".sl.\$(SHLIB_MAJOR).\$(SHLIB_MINOR)", ++ }, ++ "hpux-parisc1_1-gcc" => { ++ inherit_from => [ "hpux-parisc-gcc", asm("parisc11_asm") ], ++ multilib => "/pa1.1", ++ }, ++ "hpux64-parisc2-gcc" => { ++ inherit_from => [ "BASE_unix", asm("parisc20_64_asm") ], ++ cc => "gcc", ++ cflags => combine(picker(default => "-DB_ENDIAN", ++ debug => "-O0 -g", ++ release => "-O3"), ++ threads("-D_REENTRANT")), ++ ex_libs => add("-ldl"), ++ bn_ops => "SIXTY_FOUR_BIT_LONG RC4_CHAR", ++ thread_scheme => "pthreads", ++ dso_scheme => "dlfcn", ++ shared_target => "hpux-shared", ++ shared_cflag => "-fpic", ++ shared_ldflag => "-shared", ++ shared_extension => ".sl.\$(SHLIB_MAJOR).\$(SHLIB_MINOR)", ++ multilib => "/pa20_64", ++ }, ++ ++ # More attempts at unified 10.X and 11.X targets for HP C compiler. ++ # ++ # Chris Ruemmler ++ # Kevin Steves ++ "hpux-parisc-cc" => { ++ inherit_from => [ "BASE_unix" ], ++ cc => "cc", ++ cflags => combine(picker(default => "+Optrs_strongly_typed -Ae +ESlit -DB_ENDIAN -DBN_DIV2W -DMD32_XARRAY", ++ debug => "+O0 +d -g", ++ release => "+O3"), ++ threads("-D_REENTRANT")), ++ ex_libs => add("-Wl,+s -ldld",threads("-lpthread")), ++ bn_ops => "RC4_CHAR", ++ thread_scheme => "pthreads", ++ dso_scheme => "dl", ++ shared_target => "hpux-shared", ++ shared_cflag => "+Z", ++ shared_ldflag => "-b", ++ shared_extension => ".sl.\$(SHLIB_MAJOR).\$(SHLIB_MINOR)", ++ }, ++ "hpux-parisc1_1-cc" => { ++ inherit_from => [ "hpux-parisc-cc", asm("parisc11_asm") ], ++ cflags => add_before("+DA1.1"), ++ multilib => "/pa1.1", ++ }, ++ "hpux64-parisc2-cc" => { ++ inherit_from => [ "BASE_unix", asm("parisc20_64_asm") ], ++ cc => "cc", ++ cflags => combine(picker(default => "+DD64 +Optrs_strongly_typed -Ae +ESlit -DB_ENDIAN -DMD32_XARRAY", ++ debug => "+O0 +d -g", ++ release => "+O3"), ++ threads("-D_REENTRANT")), ++ ex_libs => add("-ldl",threads("-lpthread")), ++ bn_ops => "SIXTY_FOUR_BIT_LONG RC4_CHAR", ++ thread_scheme => "pthreads", ++ dso_scheme => "dlfcn", ++ shared_target => "hpux-shared", ++ shared_cflag => "+Z", ++ shared_ldflag => "+DD64 -b", ++ shared_extension => ".sl.\$(SHLIB_MAJOR).\$(SHLIB_MINOR)", ++ multilib => "/pa20_64", ++ }, ++ ++ # HP/UX IA-64 targets ++ "hpux-ia64-cc" => { ++ inherit_from => [ "BASE_unix", asm("ia64_asm") ], ++ cc => "cc", ++ cflags => combine(picker(default => "-Ae +DD32 +Olit=all -z -DB_ENDIAN", ++ debug => "+O0 +d -g", ++ release => "+O2"), ++ threads("-D_REENTRANT")), ++ ex_libs => add("-ldl",threads("-lpthread")), ++ bn_ops => "SIXTY_FOUR_BIT", ++ thread_scheme => "pthreads", ++ dso_scheme => "dlfcn", ++ shared_target => "hpux-shared", ++ shared_cflag => "+Z", ++ shared_ldflag => "+DD32 -b", ++ shared_extension => ".so.\$(SHLIB_MAJOR).\$(SHLIB_MINOR)", ++ multilib => "/hpux32", ++ }, ++ # Frank Geurts has patiently assisted ++ # with debugging of the following config. ++ "hpux64-ia64-cc" => { ++ inherit_from => [ "BASE_unix", asm("ia64_asm") ], ++ cc => "cc", ++ cflags => combine(picker(default => "-Ae +DD64 +Olit=all -z -DB_ENDIAN", ++ debug => "+O0 +d -g", ++ release => "+O3"), ++ threads("-D_REENTRANT")), ++ ex_libs => add("-ldl", threads("-lpthread")), ++ bn_ops => "SIXTY_FOUR_BIT_LONG", ++ thread_scheme => "pthreads", ++ dso_scheme => "dlfcn", ++ shared_target => "hpux-shared", ++ shared_cflag => "+Z", ++ shared_ldflag => "+DD64 -b", ++ shared_extension => ".so.\$(SHLIB_MAJOR).\$(SHLIB_MINOR)", ++ multilib => "/hpux64", ++ }, ++ # GCC builds... ++ "hpux-ia64-gcc" => { ++ inherit_from => [ "BASE_unix", asm("ia64_asm") ], ++ cc => "gcc", ++ cflags => combine(picker(default => "-DB_ENDIAN", ++ debug => "-O0 -g", ++ release => "-O3"), ++ threads("-pthread")), ++ ex_libs => add("-ldl"), ++ bn_ops => "SIXTY_FOUR_BIT", ++ thread_scheme => "pthreads", ++ dso_scheme => "dlfcn", ++ shared_target => "hpux-shared", ++ shared_cflag => "-fpic", ++ shared_ldflag => "-shared", ++ shared_extension => ".so.\$(SHLIB_MAJOR).\$(SHLIB_MINOR)", ++ multilib => "/hpux32", ++ }, ++ "hpux64-ia64-gcc" => { ++ inherit_from => [ "BASE_unix", asm("ia64_asm") ], ++ cc => "gcc", ++ cflags => combine(picker(default => "-mlp64 -DB_ENDIAN", ++ debug => "-O0 -g", ++ release => "-O3"), ++ threads("-pthread")), ++ ex_libs => add("-ldl"), ++ bn_ops => "SIXTY_FOUR_BIT_LONG", ++ thread_scheme => "pthreads", ++ dso_scheme => "dlfcn", ++ shared_target => "hpux-shared", ++ shared_cflag => "-fpic", ++ shared_ldflag => "-mlp64 -shared", ++ shared_extension => ".so.\$(SHLIB_MAJOR).\$(SHLIB_MINOR)", ++ multilib => "/hpux64", ++ }, ++ ++#### HP MPE/iX http://jazz.external.hp.com/src/openssl/ ++ "MPE/iX-gcc" => { ++ inherit_from => [ "BASE_unix" ], ++ cc => "gcc", ++ cflags => "-D_ENDIAN -DBN_DIV2W -O3 -D_POSIX_SOURCE -D_SOCKET_SOURCE -I/SYSLOG/PUB", ++ sys_id => "MPE", ++ ex_libs => add("-L/SYSLOG/PUB -lsyslog -lsocket -lcurses"), ++ thread_scheme => "(unknown)", ++ bn_ops => "BN_LLONG", ++ }, ++ ++#### DEC Alpha Tru64 targets. Tru64 is marketing name for OSF/1 version 4 ++#### and forward. In reality 'uname -s' still returns "OSF1". Originally ++#### there were even osf1-* configs targeting prior versions provided, ++#### but not anymore... ++ "tru64-alpha-gcc" => { ++ inherit_from => [ "BASE_unix", asm("alpha_asm") ], ++ cc => "gcc", ++ cflags => combine("-std=c9x -D_XOPEN_SOURCE=500 -D_OSF_SOURCE -O3", ++ threads("-pthread")), ++ ex_libs => "-lrt", # for mlock(2) ++ bn_ops => "SIXTY_FOUR_BIT_LONG", ++ thread_scheme => "pthreads", ++ dso_scheme => "dlfcn", ++ shared_target => "alpha-osf1-shared", ++ shared_extension => ".so", ++ }, ++ "tru64-alpha-cc" => { ++ inherit_from => [ "BASE_unix", asm("alpha_asm") ], ++ cc => "cc", ++ cflags => combine("-std1 -D_XOPEN_SOURCE=500 -D_OSF_SOURCE -tune host -fast -readonly_strings", ++ threads("-pthread")), ++ ex_libs => "-lrt", # for mlock(2) ++ bn_ops => "SIXTY_FOUR_BIT_LONG", ++ thread_scheme => "pthreads", ++ dso_scheme => "dlfcn", ++ shared_target => "alpha-osf1-shared", ++ shared_ldflag => "-msym", ++ shared_extension => ".so", ++ }, ++ ++#### ++#### Variety of LINUX:-) ++#### ++# *-generic* is endian-neutral target, but ./config is free to ++# throw in -D[BL]_ENDIAN, whichever appropriate... ++ "linux-generic32" => { ++ inherit_from => [ "BASE_unix" ], ++ cc => "gcc", ++ cflags => combine(picker(default => "-Wall", ++ debug => "-O0 -g", ++ release => "-O3"), ++ threads("-pthread")), ++ ex_libs => add("-ldl"), ++ bn_ops => "BN_LLONG RC4_CHAR", ++ thread_scheme => "pthreads", ++ dso_scheme => "dlfcn", ++ shared_target => "linux-shared", ++ shared_cflag => "-fPIC -DOPENSSL_USE_NODELETE", ++ shared_ldflag => "-Wl,-znodelete", ++ shared_extension => ".so.\$(SHLIB_MAJOR).\$(SHLIB_MINOR)", ++ }, ++ "linux-generic64" => { ++ inherit_from => [ "linux-generic32" ], ++ bn_ops => "SIXTY_FOUR_BIT_LONG RC4_CHAR", ++ }, ++ ++ "linux-ppc" => { ++ inherit_from => [ "linux-generic32", asm("ppc32_asm") ], ++ perlasm_scheme => "linux32", ++ }, ++ "linux-ppc64" => { ++ inherit_from => [ "linux-generic64", asm("ppc64_asm") ], ++ cflags => add("-m64 -DB_ENDIAN"), ++ perlasm_scheme => "linux64", ++ shared_ldflag => add("-m64"), ++ multilib => "64", ++ }, ++ "linux-ppc64le" => { ++ inherit_from => [ "linux-generic64", asm("ppc64_asm") ], ++ cflags => add("-m64 -DL_ENDIAN"), ++ perlasm_scheme => "linux64le", ++ shared_ldflag => add("-m64"), ++ }, ++ ++ "linux-armv4" => { ++ ################################################################ ++ # Note that -march is not among compiler options in linux-armv4 ++ # target description. Not specifying one is intentional to give ++ # you choice to: ++ # ++ # a) rely on your compiler default by not specifying one; ++ # b) specify your target platform explicitly for optimal ++ # performance, e.g. -march=armv6 or -march=armv7-a; ++ # c) build "universal" binary that targets *range* of platforms ++ # by specifying minimum and maximum supported architecture; ++ # ++ # As for c) option. It actually makes no sense to specify ++ # maximum to be less than ARMv7, because it's the least ++ # requirement for run-time switch between platform-specific ++ # code paths. And without run-time switch performance would be ++ # equivalent to one for minimum. Secondly, there are some ++ # natural limitations that you'd have to accept and respect. ++ # Most notably you can *not* build "universal" binary for ++ # big-endian platform. This is because ARMv7 processor always ++ # picks instructions in little-endian order. Another similar ++ # limitation is that -mthumb can't "cross" -march=armv6t2 ++ # boundary, because that's where it became Thumb-2. Well, this ++ # limitation is a bit artificial, because it's not really ++ # impossible, but it's deemed too tricky to support. And of ++ # course you have to be sure that your binutils are actually ++ # up to the task of handling maximum target platform. With all ++ # this in mind here is an example of how to configure ++ # "universal" build: ++ # ++ # ./Configure linux-armv4 -march=armv6 -D__ARM_MAX_ARCH__=8 ++ # ++ inherit_from => [ "linux-generic32", asm("armv4_asm") ], ++ perlasm_scheme => "linux32", ++ }, ++ "linux-aarch64" => { ++ inherit_from => [ "linux-generic64", asm("aarch64_asm") ], ++ perlasm_scheme => "linux64", ++ }, ++ "linux-arm64ilp32" => { # https://wiki.linaro.org/Platform/arm64-ilp32 ++ inherit_from => [ "linux-generic32", asm("aarch64_asm") ], ++ cflags => add("-mabi=ilp32"), ++ bn_ops => "SIXTY_FOUR_BIT RC4_CHAR", ++ perlasm_scheme => "linux64", ++ shared_ldflag => add("-mabi=ilp32"), ++ }, ++ ++ "linux-mips32" => { ++ # Configure script adds minimally required -march for assembly ++ # support, if no -march was specified at command line. ++ inherit_from => [ "linux-generic32", asm("mips32_asm") ], ++ cflags => add("-mabi=32 -DBN_DIV3W"), ++ perlasm_scheme => "o32", ++ shared_ldflag => add("-mabi=32"), ++ }, ++ # mips32 and mips64 below refer to contemporary MIPS Architecture ++ # specifications, MIPS32 and MIPS64, rather than to kernel bitness. ++ "linux-mips64" => { ++ inherit_from => [ "linux-generic32", asm("mips64_asm") ], ++ cflags => add("-mabi=n32 -DBN_DIV3W"), ++ bn_ops => "SIXTY_FOUR_BIT RC4_CHAR", ++ perlasm_scheme => "n32", ++ shared_ldflag => add("-mabi=n32"), ++ multilib => "32", ++ }, ++ "linux64-mips64" => { ++ inherit_from => [ "linux-generic64", asm("mips64_asm") ], ++ cflags => add("-mabi=64 -DBN_DIV3W"), ++ perlasm_scheme => "64", ++ shared_ldflag => add("-mabi=64"), ++ multilib => "64", ++ }, ++ ++ #### IA-32 targets... ++ #### These two targets are a bit aged and are to be used on older Linux ++ #### machines where gcc doesn't understand -m32 and -m64 ++ "linux-elf" => { ++ inherit_from => [ "linux-generic32", asm("x86_elf_asm") ], ++ cflags => add(picker(default => "-DL_ENDIAN", ++ release => "-fomit-frame-pointer")), ++ bn_ops => "BN_LLONG", ++ }, ++ "linux-aout" => { ++ inherit_from => [ "BASE_unix", asm("x86_asm") ], ++ cc => "gcc", ++ cflags => add(picker(default => "-DL_ENDIAN -Wall", ++ debug => "-O0 -g", ++ release => "-O3 -fomit-frame-pointer")), ++ bn_ops => "BN_LLONG", ++ thread_scheme => "(unknown)", ++ perlasm_scheme => "a.out", ++ }, ++ ++ #### X86 / X86_64 targets ++ "linux-x86" => { ++ inherit_from => [ "linux-generic32", asm("x86_asm") ], ++ cflags => add(picker(default => "-m32 -DL_ENDIAN", ++ release => "-fomit-frame-pointer")), ++ bn_ops => "BN_LLONG", ++ perlasm_scheme => "elf", ++ shared_ldflag => add("-m32"), ++ }, ++ "linux-x86-clang" => { ++ inherit_from => [ "linux-x86" ], ++ cc => "clang", ++ cxx => "clang++", ++ cflags => add("-Wextra -Qunused-arguments"), ++ }, ++ "linux-x86_64" => { ++ inherit_from => [ "linux-generic64", asm("x86_64_asm") ], ++ cflags => add("-m64 -DL_ENDIAN"), ++ bn_ops => "SIXTY_FOUR_BIT_LONG", ++ perlasm_scheme => "elf", ++ shared_ldflag => add("-m64"), ++ multilib => "64", ++ }, ++ "linux-x86_64-clang" => { ++ inherit_from => [ "linux-x86_64" ], ++ cc => "clang", ++ cflags => add("-Wextra -Qunused-arguments"), ++ }, ++ "linux-x32" => { ++ inherit_from => [ "linux-generic32", asm("x86_64_asm") ], ++ cflags => add("-mx32 -DL_ENDIAN"), ++ bn_ops => "SIXTY_FOUR_BIT", ++ perlasm_scheme => "elf32", ++ shared_ldflag => add("-mx32"), ++ multilib => "x32", ++ }, ++ ++ "linux-ia64" => { ++ inherit_from => [ "linux-generic64", asm("ia64_asm") ], ++ bn_ops => "SIXTY_FOUR_BIT_LONG", ++ }, ++ ++ "linux64-s390x" => { ++ inherit_from => [ "linux-generic64", asm("s390x_asm") ], ++ cflags => add("-m64 -DB_ENDIAN"), ++ perlasm_scheme => "64", ++ shared_ldflag => add("-m64"), ++ multilib => "64", ++ }, ++ "linux32-s390x" => { ++ #### So called "highgprs" target for z/Architecture CPUs ++ # "Highgprs" is kernel feature first implemented in Linux ++ # 2.6.32, see /proc/cpuinfo. The idea is to preserve most ++ # significant bits of general purpose registers not only ++ # upon 32-bit process context switch, but even on ++ # asynchronous signal delivery to such process. This makes ++ # it possible to deploy 64-bit instructions even in legacy ++ # application context and achieve better [or should we say ++ # adequate] performance. The build is binary compatible with ++ # linux-generic32, and the idea is to be able to install the ++ # resulting libcrypto.so alongside generic one, e.g. as ++ # /lib/highgprs/libcrypto.so.x.y, for ldconfig and run-time ++ # linker to autodiscover. Unfortunately it doesn't work just ++ # yet, because of couple of bugs in glibc ++ # sysdeps/s390/dl-procinfo.c affecting ldconfig and ld.so.1... ++ # ++ inherit_from => [ "linux-generic32", asm("s390x_asm") ], ++ cflags => add("-m31 -Wa,-mzarch -DB_ENDIAN"), ++ bn_asm_src => sub { my $r=join(" ",@_); $r=~s|asm/s390x\.S|bn_asm.c|; $r; }, ++ perlasm_scheme => "31", ++ shared_ldflag => add("-m31"), ++ multilib => "/highgprs", ++ }, ++ ++ #### SPARC Linux setups ++ # Ray Miller has ++ # patiently assisted with debugging of following two configs. ++ "linux-sparcv8" => { ++ inherit_from => [ "linux-generic32", asm("sparcv8_asm") ], ++ cflags => add("-mcpu=v8 -DB_ENDIAN -DBN_DIV2W"), ++ }, ++ "linux-sparcv9" => { ++ # it's a real mess with -mcpu=ultrasparc option under Linux, ++ # but -Wa,-Av8plus should do the trick no matter what. ++ inherit_from => [ "linux-generic32", asm("sparcv9_asm") ], ++ cflags => add("-m32 -mcpu=ultrasparc -Wa,-Av8plus -DB_ENDIAN -DBN_DIV2W"), ++ shared_ldflag => add("-m32"), ++ }, ++ "linux64-sparcv9" => { ++ # GCC 3.1 is a requirement ++ inherit_from => [ "linux-generic64", asm("sparcv9_asm") ], ++ cflags => add("-m64 -mcpu=ultrasparc -DB_ENDIAN"), ++ bn_ops => "BN_LLONG RC4_CHAR", ++ shared_ldflag => add("-m64"), ++ multilib => "64", ++ }, ++ ++ "linux-alpha-gcc" => { ++ inherit_from => [ "linux-generic64", asm("alpha_asm") ], ++ cflags => add("-DL_ENDIAN"), ++ bn_ops => "SIXTY_FOUR_BIT_LONG", ++ }, ++ "linux-c64xplus" => { ++ inherit_from => [ "BASE_unix" ], ++ # TI_CGT_C6000_7.3.x is a requirement ++ cc => "cl6x", ++ cflags => combine("--linux -ea=.s -eo=.o -mv6400+ -o2 -ox -ms -pden -DOPENSSL_SMALL_FOOTPRINT", ++ threads("-D_REENTRANT")), ++ bn_ops => "BN_LLONG", ++ cpuid_asm_src => "c64xpluscpuid.s", ++ bn_asm_src => "asm/bn-c64xplus.asm c64xplus-gf2m.s", ++ aes_asm_src => "aes-c64xplus.s aes_cbc.c aes-ctr.fake", ++ sha1_asm_src => "sha1-c64xplus.s sha256-c64xplus.s sha512-c64xplus.s", ++ rc4_asm_src => "rc4-c64xplus.s", ++ modes_asm_src => "ghash-c64xplus.s", ++ chacha_asm_src => "chacha-c64xplus.s", ++ poly1305_asm_src => "poly1305-c64xplus.s", ++ thread_scheme => "pthreads", ++ perlasm_scheme => "void", ++ dso_scheme => "dlfcn", ++ shared_target => "linux-shared", ++ shared_cflag => "--pic", ++ shared_ldflag => add("-z --sysv --shared"), ++ shared_extension => ".so.\$(SHLIB_MAJOR).\$(SHLIB_MINOR)", ++ ranlib => "true", ++ }, ++ ++#### Android: linux-* but without pointers to headers and libs. ++ # ++ # It takes pair of prior-set environment variables to make it work: ++ # ++ # CROSS_SYSROOT=/some/where/android-ndk-/platforms/android-/arch- ++ # CROSS_COMPILE= ++ # ++ # As well as PATH adjusted to cover ${CROSS_COMPILE}gcc and company. ++ # For example to compile for ICS and ARM with NDK 10d, you'd: ++ # ++ # ANDROID_NDK=/some/where/android-ndk-10d ++ # CROSS_SYSROOT=$ANDROID_NDK/platforms/android-14/arch-arm ++ # CROSS_COMPILE=arm-linux-adroideabi- ++ # PATH=$ANDROID_NDK/toolchains/arm-linux-androideabi-4.8/prebuild/linux-x86_64/bin ++ # ++ "android" => { ++ inherit_from => [ "linux-generic32" ], ++ # Special note about unconditional -fPIC and -pie. The underlying ++ # reason is that Lollipop refuses to run non-PIE. But what about ++ # older systems and NDKs? -fPIC was never problem, so the only ++ # concern is -pie. Older toolchains, e.g. r4, appear to handle it ++ # and binaries turn mostly functional. "Mostly" means that oldest ++ # Androids, such as Froyo, fail to handle executable, but newer ++ # systems are perfectly capable of executing binaries targeting ++ # Froyo. Keep in mind that in the nutshell Android builds are ++ # about JNI, i.e. shared libraries, not applications. ++ cflags => add(picker(default => "-mandroid -fPIC --sysroot=\$(CROSS_SYSROOT) -Wa,--noexecstack")), ++ bin_cflags => "-pie", ++ }, ++ "android-x86" => { ++ inherit_from => [ "android", asm("x86_asm") ], ++ cflags => add(picker(release => "-fomit-frame-pointer")), ++ bn_ops => "BN_LLONG", ++ perlasm_scheme => "android", ++ }, ++ ################################################################ ++ # Contemporary Android applications can provide multiple JNI ++ # providers in .apk, targeting multiple architectures. Among ++ # them there is "place" for two ARM flavours: generic eabi and ++ # armv7-a/hard-float. However, it should be noted that OpenSSL's ++ # ability to engage NEON is not constrained by ABI choice, nor ++ # is your ability to call OpenSSL from your application code ++ # compiled with floating-point ABI other than default 'soft'. ++ # [Latter thanks to __attribute__((pcs("aapcs"))) declaration.] ++ # This means that choice of ARM libraries you provide in .apk ++ # is driven by application needs. For example if application ++ # itself benefits from NEON or is floating-point intensive, then ++ # it might be appropriate to provide both libraries. Otherwise ++ # just generic eabi would do. But in latter case it would be ++ # appropriate to ++ # ++ # ./Configure android-armeabi -D__ARM_MAX_ARCH__=8 ++ # ++ # in order to build "universal" binary and allow OpenSSL take ++ # advantage of NEON when it's available. ++ # ++ "android-armeabi" => { ++ inherit_from => [ "android", asm("armv4_asm") ], ++ }, ++ "android-mips" => { ++ inherit_from => [ "android", asm("mips32_asm") ], ++ perlasm_scheme => "o32", ++ }, ++ ++ "android64" => { ++ inherit_from => [ "linux-generic64" ], ++ cflags => add(picker(default => "-mandroid -fPIC --sysroot=\$(CROSS_SYSROOT) -Wa,--noexecstack")), ++ bin_cflags => "-pie", ++ }, ++ "android64-aarch64" => { ++ inherit_from => [ "android64", asm("aarch64_asm") ], ++ perlasm_scheme => "linux64", ++ }, ++ ++#### *BSD ++ "BSD-generic32" => { ++ # As for thread cflag. Idea is to maintain "collective" set of ++ # flags, which would cover all BSD flavors. -pthread applies ++ # to them all, but is treated differently. OpenBSD expands is ++ # as -D_POSIX_THREAD -lc_r, which is sufficient. FreeBSD 4.x ++ # expands it as -lc_r, which has to be accompanied by explicit ++ # -D_THREAD_SAFE and sometimes -D_REENTRANT. FreeBSD 5.x ++ # expands it as -lc_r, which seems to be sufficient? ++ inherit_from => [ "BASE_unix" ], ++ cc => "cc", ++ cflags => combine(picker(default => "-Wall", ++ debug => "-O0 -g", ++ release => "-O3"), ++ threads("-pthread -D_THREAD_SAFE -D_REENTRANT")), ++ bn_ops => "BN_LLONG", ++ thread_scheme => "pthreads", ++ dso_scheme => "dlfcn", ++ shared_target => "bsd-gcc-shared", ++ shared_cflag => "-fPIC", ++ shared_extension => ".so.\$(SHLIB_MAJOR).\$(SHLIB_MINOR)", ++ }, ++ "BSD-generic64" => { ++ inherit_from => [ "BSD-generic32" ], ++ bn_ops => "SIXTY_FOUR_BIT_LONG", ++ }, ++ ++ "BSD-x86" => { ++ inherit_from => [ "BSD-generic32", asm("x86_asm") ], ++ cflags => add(picker(default => "-DL_ENDIAN", ++ release => "-fomit-frame-pointer")), ++ bn_ops => "BN_LLONG", ++ shared_target => "bsd-shared", ++ perlasm_scheme => "a.out", ++ }, ++ "BSD-x86-elf" => { ++ inherit_from => [ "BSD-x86" ], ++ perlasm_scheme => "elf", ++ }, ++ ++ "BSD-sparcv8" => { ++ inherit_from => [ "BSD-generic32", asm("sparcv8_asm") ], ++ cflags => add("-mcpu=v8 -DB_ENDIAN"), ++ }, ++ "BSD-sparc64" => { ++ # -DMD32_REG_T=int doesn't actually belong in sparc64 target, it ++ # simply *happens* to work around a compiler bug in gcc 3.3.3, ++ # triggered by RIPEMD160 code. ++ inherit_from => [ "BSD-generic64", asm("sparcv9_asm") ], ++ cflags => add("-DB_ENDIAN -DMD32_REG_T=int"), ++ bn_ops => "BN_LLONG", ++ }, ++ ++ "BSD-ia64" => { ++ inherit_from => [ "BSD-generic64", asm("ia64_asm") ], ++ cflags => add_before("-DL_ENDIAN"), ++ bn_ops => "SIXTY_FOUR_BIT_LONG", ++ }, ++ ++ "BSD-x86_64" => { ++ inherit_from => [ "BSD-generic64", asm("x86_64_asm") ], ++ cflags => add_before("-DL_ENDIAN"), ++ bn_ops => "SIXTY_FOUR_BIT_LONG", ++ perlasm_scheme => "elf", ++ }, ++ ++ "bsdi-elf-gcc" => { ++ inherit_from => [ "BASE_unix", asm("x86_elf_asm") ], ++ cc => "gcc", ++ cflags => "-DPERL5 -DL_ENDIAN -fomit-frame-pointer -O3 -Wall", ++ ex_libs => add("-ldl"), ++ bn_ops => "BN_LLONG", ++ thread_scheme => "(unknown)", ++ dso_scheme => "dlfcn", ++ shared_target => "bsd-gcc-shared", ++ shared_cflag => "-fPIC", ++ shared_extension => ".so.\$(SHLIB_MAJOR).\$(SHLIB_MINOR)", ++ }, ++ ++ "nextstep" => { ++ inherit_from => [ "BASE_unix" ], ++ cc => "cc", ++ cflags => "-O -Wall", ++ unistd => "", ++ bn_ops => "BN_LLONG", ++ thread_scheme => "(unknown)", ++ }, ++ "nextstep3.3" => { ++ inherit_from => [ "BASE_unix" ], ++ cc => "cc", ++ cflags => "-O3 -Wall", ++ unistd => "", ++ bn_ops => "BN_LLONG", ++ thread_scheme => "(unknown)", ++ }, ++ ++# QNX ++ "qnx4" => { ++ inherit_from => [ "BASE_unix" ], ++ cc => "cc", ++ cflags => "-DL_ENDIAN -DTERMIO", ++ thread_scheme => "(unknown)", ++ }, ++ "QNX6" => { ++ inherit_from => [ "BASE_unix" ], ++ cc => "gcc", ++ ex_libs => add("-lsocket"), ++ dso_scheme => "dlfcn", ++ shared_target => "bsd-gcc-shared", ++ shared_cflag => "-fPIC", ++ shared_extension => ".so.\$(SHLIB_MAJOR).\$(SHLIB_MINOR)", ++ }, ++ "QNX6-i386" => { ++ inherit_from => [ "BASE_unix", asm("x86_elf_asm") ], ++ cc => "gcc", ++ cflags => "-DL_ENDIAN -O2 -Wall", ++ ex_libs => add("-lsocket"), ++ dso_scheme => "dlfcn", ++ shared_target => "bsd-gcc-shared", ++ shared_cflag => "-fPIC", ++ shared_extension => ".so.\$(SHLIB_MAJOR).\$(SHLIB_MINOR)", ++ }, ++ ++#### SCO/Caldera targets. ++# ++# Originally we had like unixware-*, unixware-*-pentium, unixware-*-p6, etc. ++# Now we only have blended unixware-* as it's the only one used by ./config. ++# If you want to optimize for particular microarchitecture, bypass ./config ++# and './Configure unixware-7 -Kpentium_pro' or whatever appropriate. ++# Note that not all targets include assembler support. Mostly because of ++# lack of motivation to support out-of-date platforms with out-of-date ++# compiler drivers and assemblers. Tim Rice has ++# patiently assisted to debug most of it. ++# ++# UnixWare 2.0x fails destest with -O. ++ "unixware-2.0" => { ++ inherit_from => [ "BASE_unix" ], ++ cc => "cc", ++ cflags => combine("-DFILIO_H -DNO_STRINGS_H", ++ threads("-Kthread")), ++ ex_libs => add("-lsocket -lnsl -lresolv -lx"), ++ thread_scheme => "uithreads", ++ }, ++ "unixware-2.1" => { ++ inherit_from => [ "BASE_unix" ], ++ cc => "cc", ++ cflags => combine("-O -DFILIO_H", ++ threads("-Kthread")), ++ ex_libs => add("-lsocket -lnsl -lresolv -lx"), ++ thread_scheme => "uithreads", ++ }, ++ "unixware-7" => { ++ inherit_from => [ "BASE_unix", asm("x86_elf_asm") ], ++ cc => "cc", ++ cflags => combine("-O -DFILIO_H -Kalloca", ++ threads("-Kthread")), ++ ex_libs => add("-lsocket -lnsl"), ++ thread_scheme => "uithreads", ++ bn_ops => "BN_LLONG", ++ perlasm_scheme => "elf-1", ++ dso_scheme => "dlfcn", ++ shared_target => "svr5-shared", ++ shared_cflag => "-Kpic", ++ shared_extension => ".so.\$(SHLIB_MAJOR).\$(SHLIB_MINOR)", ++ }, ++ "unixware-7-gcc" => { ++ inherit_from => [ "BASE_unix", asm("x86_elf_asm") ], ++ cc => "gcc", ++ cflags => combine("-DL_ENDIAN -DFILIO_H -O3 -fomit-frame-pointer -Wall", ++ threads("-D_REENTRANT")), ++ ex_libs => add("-lsocket -lnsl"), ++ bn_ops => "BN_LLONG", ++ thread_scheme => "pthreads", ++ perlasm_scheme => "elf-1", ++ dso_scheme => "dlfcn", ++ shared_target => "gnu-shared", ++ shared_cflag => "-fPIC", ++ shared_extension => ".so.\$(SHLIB_MAJOR).\$(SHLIB_MINOR)", ++ }, ++# SCO 5 - Ben Laurie says the -O breaks the SCO cc. ++ "sco5-cc" => { ++ inherit_from => [ "BASE_unix", asm("x86_elf_asm") ], ++ cc => "cc", ++ cflags => "-belf", ++ ex_libs => add("-lsocket -lnsl"), ++ thread_scheme => "(unknown)", ++ perlasm_scheme => "elf-1", ++ dso_scheme => "dlfcn", ++ shared_target => "svr3-shared", ++ shared_cflag => "-Kpic", ++ shared_extension => ".so.\$(SHLIB_MAJOR).\$(SHLIB_MINOR)", ++ }, ++ "sco5-gcc" => { ++ inherit_from => [ "BASE_unix", asm("x86_elf_asm") ], ++ cc => "gcc", ++ cflags => "-O3 -fomit-frame-pointer", ++ ex_libs => add("-lsocket -lnsl"), ++ bn_ops => "BN_LLONG", ++ thread_scheme => "(unknown)", ++ perlasm_scheme => "elf-1", ++ dso_scheme => "dlfcn", ++ shared_target => "svr3-shared", ++ shared_cflag => "-fPIC", ++ shared_extension => ".so.\$(SHLIB_MAJOR).\$(SHLIB_MINOR)", ++ }, ++ ++#### IBM's AIX. ++ # Below targets assume AIX >=5. Caveat lector. If you are accustomed ++ # to control compilation "bitness" by setting $OBJECT_MODE environment ++ # variable, then you should know that in OpenSSL case it's considered ++ # only in ./config. Once configured, build procedure remains "deaf" to ++ # current value of $OBJECT_MODE. ++ "aix-gcc" => { ++ inherit_from => [ "BASE_unix", asm("ppc32_asm") ], ++ cc => "gcc", ++ cflags => combine(picker(default => "-DB_ENDIAN", ++ debug => "-O0 -g", ++ release => "-O"), ++ threads("-pthread")), ++ sys_id => "AIX", ++ bn_ops => "BN_LLONG RC4_CHAR", ++ thread_scheme => "pthreads", ++ perlasm_scheme => "aix32", ++ dso_scheme => "dlfcn", ++ shared_target => "aix-shared", ++ shared_ldflag => "-shared -static-libgcc -Wl,-G", ++ shared_extension => ".so.\$(SHLIB_MAJOR).\$(SHLIB_MINOR)", ++ arflags => "-X32", ++ }, ++ "aix64-gcc" => { ++ inherit_from => [ "BASE_unix", asm("ppc64_asm") ], ++ cc => "gcc", ++ cflags => combine(picker(default => "-maix64 -DB_ENDIAN", ++ debug => "-O0 -g", ++ release => "-O"), ++ threads("-pthread")), ++ sys_id => "AIX", ++ bn_ops => "SIXTY_FOUR_BIT_LONG RC4_CHAR", ++ thread_scheme => "pthreads", ++ perlasm_scheme => "aix64", ++ dso_scheme => "dlfcn", ++ shared_target => "aix-shared", ++ shared_ldflag => "-maix64 -shared -static-libgcc -Wl,-G", ++ shared_extension => ".so.\$(SHLIB_MAJOR).\$(SHLIB_MINOR)", ++ arflags => "-X64", ++ }, ++ "aix-cc" => { ++ inherit_from => [ "BASE_unix", asm("ppc32_asm") ], ++ cc => "cc", ++ cflags => combine(picker(default => "-q32 -DB_ENDIAN -qmaxmem=16384 -qro -qroconst", ++ debug => "-O0 -g", ++ release => "-O"), ++ threads("-qthreaded -D_THREAD_SAFE")), ++ sys_id => "AIX", ++ bn_ops => "BN_LLONG RC4_CHAR", ++ thread_scheme => "pthreads", ++ ex_libs => threads("-lpthreads"), ++ perlasm_scheme => "aix32", ++ dso_scheme => "dlfcn", ++ shared_target => "aix-shared", ++ shared_ldflag => "-q32 -G", ++ shared_extension => ".so.\$(SHLIB_MAJOR).\$(SHLIB_MINOR)", ++ arflags => "-X 32", ++ }, ++ "aix64-cc" => { ++ inherit_from => [ "BASE_unix", asm("ppc64_asm") ], ++ cc => "cc", ++ cflags => combine(picker(default => "-q64 -DB_ENDIAN -qmaxmem=16384 -qro -qroconst", ++ debug => "-O0 -g", ++ release => "-O"), ++ threads("-qthreaded -D_THREAD_SAFE")), ++ sys_id => "AIX", ++ bn_ops => "SIXTY_FOUR_BIT_LONG RC4_CHAR", ++ thread_scheme => "pthreads", ++ ex_libs => threads("-lpthreads"), ++ perlasm_scheme => "aix64", ++ dso_scheme => "dlfcn", ++ shared_target => "aix-shared", ++ shared_ldflag => "-q64 -G", ++ shared_extension => ".so.\$(SHLIB_MAJOR).\$(SHLIB_MINOR)", ++ arflags => "-X 64", ++ }, ++ ++# SIEMENS BS2000/OSD: an EBCDIC-based mainframe ++ "BS2000-OSD" => { ++ inherit_from => [ "BASE_unix" ], ++ cc => "c89", ++ cflags => "-O -XLLML -XLLMK -XL -DB_ENDIAN -DCHARSET_EBCDIC", ++ ex_libs => add("-lsocket -lnsl"), ++ bn_ops => "THIRTY_TWO_BIT RC4_CHAR", ++ thread_scheme => "(unknown)", ++ }, ++ ++# OS/390 Unix an EBCDIC-based Unix system on IBM mainframe ++# You need to compile using the c89.sh wrapper in the tools directory, because the ++# IBM compiler does not like the -L switch after any object modules. ++# ++ "OS390-Unix" => { ++ inherit_from => [ "BASE_unix" ], ++ cc => "c89.sh", ++ cflags => "-O -DB_ENDIAN -DCHARSET_EBCDIC -DNO_SYS_PARAM_H -D_ALL_SOURCE", ++ bn_ops => "THIRTY_TWO_BIT RC4_CHAR", ++ thread_scheme => "(unknown)", ++ }, ++ ++#### Visual C targets ++# ++# Win64 targets, WIN64I denotes IA-64 and WIN64A - AMD64 ++# ++# Note about -wd4090, disable warning C4090. This warning returns false ++# positives in some situations. Disabling it altogether masks both ++# legitimate and false cases, but as we compile on multiple platforms, ++# we rely on other compilers to catch legitimate cases. ++# ++# Also note that we force threads no matter what. Configuring "no-threads" ++# is ignored. ++ "VC-common" => { ++ inherit_from => [ "BASE_Windows" ], ++ template => 1, ++ cc => "cl", ++ cflags => "-W3 -wd4090 -Gs0 -GF -Gy -nologo -DOPENSSL_SYS_WIN32 -DWIN32_LEAN_AND_MEAN -DL_ENDIAN -D_CRT_SECURE_NO_DEPRECATE", ++ defines => add(sub { my @defs = (); ++ unless ($disabled{"zlib-dynamic"}) { ++ my $zlib = ++ $withargs{zlib_lib} // "ZLIB1"; ++ push @defs, ++ quotify("perl", ++ 'LIBZ="' . $zlib . '"'); ++ } ++ return [ @defs ]; ++ }), ++ coutflag => "/Fo", ++ lib_cflags => add("/Zi /Fdossl_static"), ++ dso_cflags => "/Zi /Fddso", ++ bin_cflags => "/Zi /Fdapp", ++ lflags => add("/debug"), ++ shared_ldflag => "/dll", ++ shared_target => "win-shared", # meaningless except it gives Configure a hint ++ thread_scheme => "winthreads", ++ dso_scheme => "win32", ++ apps_aux_src => add("win32_init.c"), ++ }, ++ "VC-noCE-common" => { ++ inherit_from => [ "VC-common" ], ++ template => 1, ++ cflags => add(picker(default => "-DUNICODE -D_UNICODE", ++ debug => ++ sub { ++ ($disabled{shared} ? "" : "/MDd") ++ ." /Od -DDEBUG -D_DEBUG"; ++ }, ++ release => ++ sub { ++ ($disabled{shared} ? "" : "/MD") ++ ." /O2"; ++ })), ++ lib_cflags => add(sub { $disabled{shared} ? "/MT /Zl" : () }), ++ # Following might/should appears controversial, i.e. defining ++ # /MDd without evaluating $disabled{shared}. It works in ++ # non-shared build because static library is compiled with /Zl ++ # and bares no reference to specific RTL. And it works in ++ # shared build because multiple /MDd options are not prohibited. ++ # But why /MDd in static build? Well, basically this is just a ++ # reference point, which allows to catch eventual errors that ++ # would prevent those who want to wrap OpenSSL into own .DLL. ++ # Why not /MD in release build then? Well, some are likely to ++ # prefer [non-debug] openssl.exe to be free from Micorosoft RTL ++ # redistributable. ++ bin_cflags => add(picker(debug => "/MDd", ++ release => sub { $disabled{shared} ? "/MT" : () }, ++ )), ++ bin_lflags => add("/subsystem:console /opt:ref"), ++ ex_libs => add(sub { ++ my @ex_libs = (); ++ push @ex_libs, 'ws2_32.lib' unless $disabled{sock}; ++ push @ex_libs, 'gdi32.lib advapi32.lib crypt32.lib user32.lib'; ++ return join(" ", @ex_libs); ++ }), ++ }, ++ "VC-WIN64-common" => { ++ inherit_from => [ "VC-noCE-common" ], ++ template => 1, ++ ex_libs => add(sub { ++ my @ex_libs = (); ++ push @ex_libs, 'bufferoverflowu.lib' if (`cl 2>&1` =~ /14\.00\.4[0-9]{4}\./); ++ return join(" ", @_, @ex_libs); ++ }), ++ bn_ops => "SIXTY_FOUR_BIT EXPORT_VAR_AS_FN", ++ build_scheme => add("VC-W64", { separator => undef }), ++ }, ++ "VC-WIN64I" => { ++ inherit_from => [ "VC-WIN64-common", asm("ia64_asm"), ++ sub { $disabled{shared} ? () : "ia64_uplink" } ], ++ as => "ias", ++ asflags => "-d debug", ++ asoutflag => "-o", ++ sys_id => "WIN64I", ++ bn_asm_src => sub { return undef unless @_; ++ my $r=join(" ",@_); $r=~s|bn-ia64.s|bn_asm.c|; $r; }, ++ perlasm_scheme => "ias", ++ multilib => "-ia64", ++ }, ++ "VC-WIN64A" => { ++ inherit_from => [ "VC-WIN64-common", asm("x86_64_asm"), ++ sub { $disabled{shared} ? () : "x86_64_uplink" } ], ++ as => sub { vc_win64a_info()->{as} }, ++ asflags => sub { vc_win64a_info()->{asflags} }, ++ asoutflag => sub { vc_win64a_info()->{asoutflag} }, ++ sys_id => "WIN64A", ++ bn_asm_src => sub { return undef unless @_; ++ my $r=join(" ",@_); $r=~s|asm/x86_64-gcc|bn_asm|; $r; }, ++ perlasm_scheme => "auto", ++ multilib => "-x64", ++ }, ++ "VC-WIN32" => { ++ # x86 Win32 target defaults to ANSI API, if you want UNICODE, ++ # configure with 'perl Configure VC-WIN32 -DUNICODE -D_UNICODE' ++ inherit_from => [ "VC-noCE-common", asm("x86_asm"), ++ sub { $disabled{shared} ? () : "uplink_common" } ], ++ as => sub { vc_win32_info()->{as} }, ++ asflags => sub { vc_win32_info()->{asflags} }, ++ asoutflag => sub { vc_win32_info()->{asoutflag} }, ++ ex_libs => add(sub { ++ my @ex_libs = (); ++ # WIN32 UNICODE build gets linked with unicows.lib for ++ # backward compatibility with Win9x. ++ push @ex_libs, 'unicows.lib' ++ if (grep { $_ eq "UNICODE" } @user_defines); ++ return join(" ", @ex_libs, @_); ++ }), ++ sys_id => "WIN32", ++ bn_ops => "BN_LLONG EXPORT_VAR_AS_FN", ++ perlasm_scheme => sub { vc_win32_info()->{perlasm_scheme} }, ++ build_scheme => add("VC-W32", { separator => undef }), ++ }, ++ "VC-CE" => { ++ inherit_from => [ "VC-common" ], ++ as => "ml", ++ asflags => "/nologo /Cp /coff /c /Cx /Zi", ++ asoutflag => "/Fo", ++ cc => "cl", ++ cflags => ++ picker(default => ++ combine('/W3 /WX /GF /Gy /nologo -DUNICODE -D_UNICODE -DOPENSSL_SYS_WINCE -DWIN32_LEAN_AND_MEAN -DL_ENDIAN -DDSO_WIN32 -DNO_CHMOD -DOPENSSL_SMALL_FOOTPRINT', ++ sub { vc_wince_info()->{cflags}; }, ++ sub { defined($ENV{'WCECOMPAT'}) ++ ? '-I$(WCECOMPAT)/include' : (); }, ++ sub { defined($ENV{'PORTSDK_LIBPATH'}) ++ ? '-I$(PORTSDK_LIBPATH)/../../include' : (); }, ++ sub { `cl 2>&1` =~ /Version ([0-9]+)\./ && $1>=14 ++ ? ($disabled{shared} ? " /MT" : " /MD") ++ : " /MC"; }), ++ debug => "/Od -DDEBUG -D_DEBUG", ++ release => "/O1i"), ++ lflags => combine("/nologo /opt:ref", ++ sub { vc_wince_info()->{lflags}; }, ++ sub { defined($ENV{PORTSDK_LIBPATH}) ++ ? "/entry:mainCRTstartup" : (); }), ++ sys_id => "WINCE", ++ bn_ops => "BN_LLONG EXPORT_VAR_AS_FN", ++ ex_libs => add(sub { ++ my @ex_libs = (); ++ push @ex_libs, 'ws2.lib' unless $disabled{sock}; ++ push @ex_libs, 'crypt32.lib'; ++ if (defined($ENV{WCECOMPAT})) { ++ my $x = '$(WCECOMPAT)/lib'; ++ if (-f "$x/$ENV{TARGETCPU}/wcecompatex.lib") { ++ $x .= '/$(TARGETCPU)/wcecompatex.lib'; ++ } else { ++ $x .= '/wcecompatex.lib'; ++ } ++ push @ex_libs, $x; ++ } ++ push @ex_libs, '$(PORTSDK_LIBPATH)/portlib.lib' ++ if (defined($ENV{'PORTSDK_LIBPATH'})); ++ push @ex_libs, ' /nodefaultlib coredll.lib corelibc.lib' ++ if ($ENV{'TARGETCPU'} eq "X86"); ++ return @ex_libs; ++ }), ++ build_scheme => add("VC-WCE", { separator => undef }), ++ }, ++ ++#### MinGW ++ "mingw" => { ++ inherit_from => [ "BASE_unix", asm("x86_asm"), ++ sub { $disabled{shared} ? () : "x86_uplink" } ], ++ cc => "gcc", ++ cflags => combine(picker(default => "-DL_ENDIAN -DWIN32_LEAN_AND_MEAN -DUNICODE -D_UNICODE -m32 -Wall", ++ debug => "-g -O0", ++ release => "-O3 -fomit-frame-pointer"), ++ threads("-D_MT")), ++ sys_id => "MINGW32", ++ ex_libs => add("-lws2_32 -lgdi32 -lcrypt32"), ++ bn_ops => "BN_LLONG EXPORT_VAR_AS_FN", ++ thread_scheme => "winthreads", ++ perlasm_scheme => "coff", ++ dso_scheme => "win32", ++ shared_target => "mingw-shared", ++ shared_cflag => add("-D_WINDLL"), ++ shared_ldflag => "-static-libgcc", ++ shared_rcflag => "--target=pe-i386", ++ shared_extension => ".dll", ++ multilib => "", ++ apps_aux_src => add("win32_init.c"), ++ }, ++ "mingw64" => { ++ # As for OPENSSL_USE_APPLINK. Applink makes it possible to use ++ # .dll compiled with one compiler with application compiled with ++ # another compiler. It's possible to engage Applink support in ++ # mingw64 build, but it's not done, because till mingw64 ++ # supports structured exception handling, one can't seriously ++ # consider its binaries for using with non-mingw64 run-time ++ # environment. And as mingw64 is always consistent with itself, ++ # Applink is never engaged and can as well be omitted. ++ inherit_from => [ "BASE_unix", asm("x86_64_asm") ], ++ cc => "gcc", ++ cflags => combine(picker(default => "-DL_ENDIAN -DWIN32_LEAN_AND_MEAN -DUNICODE -D_UNICODE -m64 -Wall", ++ debug => "-g -O0", ++ release => "-O3"), ++ threads("-D_MT")), ++ sys_id => "MINGW64", ++ ex_libs => add("-lws2_32 -lgdi32 -lcrypt32"), ++ bn_ops => "SIXTY_FOUR_BIT EXPORT_VAR_AS_FN", ++ thread_scheme => "winthreads", ++ perlasm_scheme => "mingw64", ++ dso_scheme => "win32", ++ shared_target => "mingw-shared", ++ shared_cflag => add("-D_WINDLL"), ++ shared_ldflag => "-static-libgcc", ++ shared_rcflag => "--target=pe-x86-64", ++ shared_extension => ".dll", ++ multilib => "64", ++ apps_aux_src => add("win32_init.c"), ++ }, ++ ++#### UEFI ++ "UEFI" => { ++ inherit_from => [ "BASE_unix" ], ++ cc => "cc", ++ cflags => "-DL_ENDIAN -O", ++ sys_id => "UEFI", ++ }, ++ ++#### UWIN ++ "UWIN" => { ++ inherit_from => [ "BASE_unix" ], ++ cc => "cc", ++ cflags => "-DTERMIOS -DL_ENDIAN -O -Wall", ++ sys_id => "UWIN", ++ bn_ops => "BN_LLONG", ++ dso_scheme => "win32", ++ }, ++ ++#### Cygwin ++ "Cygwin-x86" => { ++ inherit_from => [ "BASE_unix", asm("x86_asm") ], ++ cc => "gcc", ++ cflags => picker(default => "-DTERMIOS -DL_ENDIAN -Wall", ++ debug => "-g -O0", ++ release => "-O3 -fomit-frame-pointer"), ++ sys_id => "CYGWIN", ++ bn_ops => "BN_LLONG", ++ thread_scheme => "pthread", ++ perlasm_scheme => "coff", ++ dso_scheme => "dlfcn", ++ shared_target => "cygwin-shared", ++ shared_cflag => "-D_WINDLL", ++ shared_ldflag => "-shared", ++ shared_extension => ".dll", ++ }, ++ "Cygwin-x86_64" => { ++ inherit_from => [ "BASE_unix", asm("x86_64_asm") ], ++ cc => "gcc", ++ cflags => picker(default => "-DTERMIOS -DL_ENDIAN -Wall", ++ debug => "-g -O0", ++ release => "-O3"), ++ sys_id => "CYGWIN", ++ bn_ops => "SIXTY_FOUR_BIT_LONG", ++ thread_scheme => "pthread", ++ perlasm_scheme => "mingw64", ++ dso_scheme => "dlfcn", ++ shared_target => "cygwin-shared", ++ shared_cflag => "-D_WINDLL", ++ shared_ldflag => "-shared", ++ shared_extension => ".dll", ++ }, ++ # Backward compatibility for those using this target ++ "Cygwin" => { ++ inherit_from => [ "Cygwin-x86" ] ++ }, ++ # In case someone constructs the Cygwin target name themself ++ "Cygwin-i386" => { ++ inherit_from => [ "Cygwin-x86" ] ++ }, ++ "Cygwin-i486" => { ++ inherit_from => [ "Cygwin-x86" ] ++ }, ++ "Cygwin-i586" => { ++ inherit_from => [ "Cygwin-x86" ] ++ }, ++ "Cygwin-i686" => { ++ inherit_from => [ "Cygwin-x86" ] ++ }, ++ ++##### MacOS X (a.k.a. Darwin) setup ++ "darwin-common" => { ++ inherit_from => [ "BASE_unix" ], ++ template => 1, ++ cc => "cc", ++ cflags => combine(picker(default => "", ++ debug => "-g -O0", ++ release => "-O3"), ++ threads("-D_REENTRANT")), ++ sys_id => "MACOSX", ++ plib_lflags => "-Wl,-search_paths_first", ++ bn_ops => "BN_LLONG RC4_CHAR", ++ thread_scheme => "pthreads", ++ perlasm_scheme => "osx32", ++ dso_scheme => "dlfcn", ++ ranlib => "ranlib -c", ++ shared_target => "darwin-shared", ++ shared_cflag => "-fPIC", ++ shared_ldflag => "-dynamiclib", ++ shared_extension => ".\$(SHLIB_MAJOR).\$(SHLIB_MINOR).dylib", ++ }, ++ # Option "freeze" such as -std=gnu9x can't negatively interfere ++ # with future defaults for below two targets, because MacOS X ++ # for PPC has no future, it was discontinued by vendor in 2009. ++ "darwin-ppc-cc" => { ++ inherit_from => [ "darwin-common", asm("ppc32_asm") ], ++ cflags => add("-arch ppc -std=gnu9x -DB_ENDIAN -Wa,-force_cpusubtype_ALL"), ++ perlasm_scheme => "osx32", ++ shared_ldflag => "-arch ppc -dynamiclib", ++ }, ++ "darwin64-ppc-cc" => { ++ inherit_from => [ "darwin-common", asm("ppc64_asm") ], ++ cflags => add("-arch ppc64 -std=gnu9x -DB_ENDIAN"), ++ bn_ops => "SIXTY_FOUR_BIT_LONG RC4_CHAR", ++ perlasm_scheme => "osx64", ++ shared_ldflag => "-arch ppc64 -dynamiclib", ++ }, ++ "darwin-i386-cc" => { ++ inherit_from => [ "darwin-common", asm("x86_asm") ], ++ cflags => add(picker(default => "-arch i386 -DL_ENDIAN", ++ release => "-fomit-frame-pointer")), ++ bn_ops => "BN_LLONG RC4_INT", ++ perlasm_scheme => "macosx", ++ shared_ldflag => "-arch i386 -dynamiclib", ++ }, ++ "darwin64-x86_64-cc" => { ++ inherit_from => [ "darwin-common", asm("x86_64_asm") ], ++ cflags => add("-arch x86_64 -DL_ENDIAN -Wall"), ++ bn_ops => "SIXTY_FOUR_BIT_LONG", ++ perlasm_scheme => "macosx", ++ shared_ldflag => "-arch x86_64 -dynamiclib", ++ }, ++ ++#### iPhoneOS/iOS ++# ++# It takes three prior-set environment variables to make it work: ++# ++# CROSS_COMPILE=/where/toolchain/is/usr/bin/ [note ending slash] ++# CROSS_TOP=/where/SDKs/are ++# CROSS_SDK=iPhoneOSx.y.sdk ++# ++# Exact paths vary with Xcode releases, but for couple of last ones ++# they would look like this: ++# ++# CROSS_COMPILE=`xcode-select --print-path`/Toolchains/XcodeDefault.xctoolchain/usr/bin/ ++# CROSS_TOP=`xcode-select --print-path`/Platforms/iPhoneOS.platform/Developer ++# CROSS_SDK=iPhoneOS.sdk ++# ++ "iphoneos-cross" => { ++ inherit_from => [ "darwin-common" ], ++ cflags => add("-isysroot \$(CROSS_TOP)/SDKs/\$(CROSS_SDK) -fno-common"), ++ sys_id => "iOS", ++ }, ++ "ios-cross" => { ++ inherit_from => [ "darwin-common", asm("armv4_asm") ], ++ # It should be possible to go below iOS 6 and even add -arch armv6, ++ # thus targeting iPhone pre-3GS, but it's assumed to be irrelevant ++ # at this point. ++ cflags => add("-arch armv7 -mios-version-min=6.0.0 -isysroot \$(CROSS_TOP)/SDKs/\$(CROSS_SDK) -fno-common"), ++ sys_id => "iOS", ++ perlasm_scheme => "ios32", ++ }, ++ "ios64-cross" => { ++ inherit_from => [ "darwin-common", asm("aarch64_asm") ], ++ cflags => add("-arch arm64 -mios-version-min=7.0.0 -isysroot \$(CROSS_TOP)/SDKs/\$(CROSS_SDK) -fno-common"), ++ sys_id => "iOS", ++ bn_ops => "SIXTY_FOUR_BIT_LONG RC4_CHAR", ++ perlasm_scheme => "ios64", ++ }, ++ ++##### GNU Hurd ++ "hurd-x86" => { ++ inherit_from => [ "BASE_unix" ], ++ inherit_from => [ asm("x86_elf_asm") ], ++ cc => "gcc", ++ cflags => combine("-DL_ENDIAN -O3 -fomit-frame-pointer -Wall", ++ threads("-pthread")), ++ ex_libs => add("-ldl"), ++ bn_ops => "BN_LLONG", ++ thread_scheme => "pthreads", ++ dso_scheme => "dlfcn", ++ shared_target => "linux-shared", ++ shared_cflag => "-fPIC", ++ shared_extension => ".so.\$(SHLIB_MAJOR).\$(SHLIB_MINOR)", ++ }, ++ ++##### VxWorks for various targets ++ "vxworks-ppc60x" => { ++ inherit_from => [ "BASE_unix" ], ++ cc => "ccppc", ++ cflags => "-D_REENTRANT -mrtp -mhard-float -mstrict-align -fno-implicit-fp -DPPC32_fp60x -O2 -fstrength-reduce -fno-builtin -fno-strict-aliasing -Wall -DCPU=PPC32 -DTOOL_FAMILY=gnu -DTOOL=gnu -I\$(WIND_BASE)/target/usr/h -I\$(WIND_BASE)/target/usr/h/wrn/coreip", ++ sys_id => "VXWORKS", ++ ex_libs => add("-Wl,--defsym,__wrs_rtp_base=0xe0000000 -L \$(WIND_BASE)/target/usr/lib/ppc/PPC32/common"), ++ }, ++ "vxworks-ppcgen" => { ++ inherit_from => [ "BASE_unix" ], ++ cc => "ccppc", ++ cflags => "-D_REENTRANT -mrtp -msoft-float -mstrict-align -O1 -fno-builtin -fno-strict-aliasing -Wall -DCPU=PPC32 -DTOOL_FAMILY=gnu -DTOOL=gnu -I\$(WIND_BASE)/target/usr/h -I\$(WIND_BASE)/target/usr/h/wrn/coreip", ++ sys_id => "VXWORKS", ++ ex_libs => add("-Wl,--defsym,__wrs_rtp_base=0xe0000000 -L \$(WIND_BASE)/target/usr/lib/ppc/PPC32/sfcommon"), ++ }, ++ "vxworks-ppc405" => { ++ inherit_from => [ "BASE_unix" ], ++ cc => "ccppc", ++ cflags => "-g -msoft-float -mlongcall -DCPU=PPC405 -I\$(WIND_BASE)/target/h", ++ sys_id => "VXWORKS", ++ lflags => "-r", ++ }, ++ "vxworks-ppc750" => { ++ inherit_from => [ "BASE_unix" ], ++ cc => "ccppc", ++ cflags => "-ansi -nostdinc -DPPC750 -D_REENTRANT -fvolatile -fno-builtin -fno-for-scope -fsigned-char -Wall -msoft-float -mlongcall -DCPU=PPC604 -I\$(WIND_BASE)/target/h \$(DEBUG_FLAG)", ++ sys_id => "VXWORKS", ++ lflags => "-r", ++ }, ++ "vxworks-ppc750-debug" => { ++ inherit_from => [ "BASE_unix" ], ++ cc => "ccppc", ++ cflags => "-ansi -nostdinc -DPPC750 -D_REENTRANT -fvolatile -fno-builtin -fno-for-scope -fsigned-char -Wall -msoft-float -mlongcall -DCPU=PPC604 -I\$(WIND_BASE)/target/h -DPEDANTIC -DDEBUG -g", ++ sys_id => "VXWORKS", ++ lflags => "-r", ++ }, ++ "vxworks-ppc860" => { ++ inherit_from => [ "BASE_unix" ], ++ cc => "ccppc", ++ cflags => "-nostdinc -msoft-float -DCPU=PPC860 -DNO_STRINGS_H -I\$(WIND_BASE)/target/h", ++ sys_id => "VXWORKS", ++ lflags => "-r", ++ }, ++ "vxworks-simlinux" => { ++ inherit_from => [ "BASE_unix" ], ++ cc => "ccpentium", ++ cflags => "-B\$(WIND_BASE)/host/\$(WIND_HOST_TYPE)/lib/gcc-lib/ -D_VSB_CONFIG_FILE=\"\$(WIND_BASE)/target/lib/h/config/vsbConfig.h\" -DL_ENDIAN -DCPU=SIMLINUX -DTOOL_FAMILY=gnu -DTOOL=gnu -fno-builtin -fno-defer-pop -DNO_STRINGS_H -I\$(WIND_BASE)/target/h -I\$(WIND_BASE)/target/h/wrn/coreip -DOPENSSL_NO_HW_PADLOCK", ++ sys_id => "VXWORKS", ++ lflags => "-r", ++ ranlib => "ranlibpentium", ++ }, ++ "vxworks-mips" => { ++ inherit_from => [ "BASE_unix", asm("mips32_asm") ], ++ cc => "ccmips", ++ cflags => combine("-mrtp -mips2 -O -G 0 -B\$(WIND_BASE)/host/\$(WIND_HOST_TYPE)/lib/gcc-lib/ -D_VSB_CONFIG_FILE=\"\$(WIND_BASE)/target/lib/h/config/vsbConfig.h\" -DCPU=MIPS32 -msoft-float -mno-branch-likely -DTOOL_FAMILY=gnu -DTOOL=gnu -fno-builtin -fno-defer-pop -DNO_STRINGS_H -I\$(WIND_BASE)/target/usr/h -I\$(WIND_BASE)/target/h/wrn/coreip", ++ threads("-D_REENTRANT")), ++ sys_id => "VXWORKS", ++ ex_libs => add("-Wl,--defsym,__wrs_rtp_base=0xe0000000 -L \$(WIND_BASE)/target/usr/lib/mips/MIPSI32/sfcommon"), ++ thread_scheme => "pthreads", ++ perlasm_scheme => "o32", ++ ranlib => "ranlibmips", ++ }, ++ ++#### uClinux ++ "uClinux-dist" => { ++ inherit_from => [ "BASE_unix" ], ++ cc => "$ENV{'CC'}", ++ cflags => combine("\$(CFLAGS)", ++ threads("-D_REENTRANT")), ++ plib_lflags => "\$(LDFLAGS)", ++ ex_libs => add("\$(LDLIBS)"), ++ bn_ops => "BN_LLONG", ++ thread_scheme => "pthreads", ++ dso_scheme => "$ENV{'LIBSSL_dlfcn'}", ++ shared_target => "linux-shared", ++ shared_cflag => "-fPIC", ++ shared_ldflag => "-shared", ++ shared_extension => ".so.\$(SHLIB_MAJOR).\$(SHLIB_MINOR)", ++ ranlib => "$ENV{'RANLIB'}", ++ }, ++ "uClinux-dist64" => { ++ inherit_from => [ "BASE_unix" ], ++ cc => "$ENV{'CC'}", ++ cflags => combine("\$(CFLAGS)", ++ threads("-D_REENTRANT")), ++ plib_lflags => "\$(LDFLAGS)", ++ ex_libs => add("\$(LDLIBS)"), ++ bn_ops => "SIXTY_FOUR_BIT_LONG", ++ thread_scheme => "pthreads", ++ dso_scheme => "$ENV{'LIBSSL_dlfcn'}", ++ shared_target => "linux-shared", ++ shared_cflag => "-fPIC", ++ shared_ldflag => "-shared", ++ shared_extension => ".so.\$(SHLIB_MAJOR).\$(SHLIB_MINOR)", ++ ranlib => "$ENV{'RANLIB'}", ++ }, ++ ++ ##### VMS ++ "vms-generic" => { ++ inherit_from => [ "BASE_VMS" ], ++ template => 1, ++ cc => "CC/DECC", ++ cflags => picker(default => "/STANDARD=(ISOC94,RELAXED)/NOLIST/PREFIX=ALL", ++ debug => "/NOOPTIMIZE/DEBUG", ++ release => "/OPTIMIZE/NODEBUG"), ++ defines => add("OPENSSL_USE_NODELETE"), ++ lflags => picker(default => "/MAP", ++ debug => "/DEBUG/TRACEBACK", ++ release => "/NODEBUG/NOTRACEBACK"), ++ lib_cflags => add("/NAMES=(AS_IS,SHORTENED)/EXTERN_MODEL=STRICT_REFDEF"), ++ dso_cflags => add("/NAMES=(AS_IS,SHORTENED)"), ++ shared_target => "vms-shared", ++ dso_scheme => "vms", ++ thread_scheme => "pthreads", ++ ++ apps_aux_src => "vms_decc_init.c vms_term_sock.c", ++ }, ++ ++ "vms-alpha" => { ++ inherit_from => [ "vms-generic" ], ++ cflags => add(sub { my @warnings = ++ @{vms_info(0)->{disable_warns}}; ++ @warnings ++ ? "/WARNINGS=DISABLE=(".join(",",@warnings).")" : (); }), ++ defines => ++ add(sub { ++ return vms_info(0)->{def_zlib} ++ ? "LIBZ=\"\"\"".vms_info(0)->{def_zlib}."\"\"\"" : (); ++ }), ++ ex_libs => add(sub { return vms_info(0)->{zlib} || (); }), ++ pointer_size => sub { return vms_info(0)->{pointer_size} }, ++ #as => "???", ++ #debug_aflags => "/NOOPTIMIZE/DEBUG", ++ #release_aflags => "/OPTIMIZE/NODEBUG", ++ bn_opts => "SIXTY_FOUR_BIT RC4_INT", ++ }, ++ "vms-alpha-p32" => { ++ inherit_from => [ "vms-generic" ], ++ cflags => ++ add("/POINTER_SIZE=32", ++ sub { my @warnings = ++ @{vms_info(32)->{disable_warns}}; ++ @warnings ++ ? "/WARNINGS=DISABLE=(".join(",",@warnings).")" : (); ++ } ), ++ defines => ++ add(sub { ++ return vms_info(32)->{def_zlib} ++ ? "LIBZ=\"\"\"".vms_info(32)->{def_zlib}."\"\"\"" : (); ++ }), ++ ex_libs => add(sub { return vms_info(32)->{zlib} || (); }), ++ pointer_size => sub { return vms_info(32)->{pointer_size} }, ++ }, ++ "vms-alpha-p64" => { ++ inherit_from => [ "vms-generic" ], ++ cflags => ++ add("/POINTER_SIZE=64=ARGV", ++ sub { my @warnings = ++ @{vms_info(64)->{disable_warns}}; ++ @warnings ++ ? "/WARNINGS=DISABLE=(".join(",",@warnings).")" : (); ++ } ), ++ defines => ++ add(sub { ++ return vms_info(64)->{def_zlib} ++ ? "LIBZ=\"\"\"".vms_info(64)->{def_zlib}."\"\"\"" : (); ++ }), ++ ex_libs => add(sub { return vms_info(64)->{zlib} || (); }), ++ pointer_size => sub { return vms_info(64)->{pointer_size} }, ++ }, ++ "vms-ia64" => { ++ inherit_from => [ "vms-generic" ], ++ cflags => add(sub { my @warnings = ++ @{vms_info(0)->{disable_warns}}; ++ @warnings ++ ? "/WARNINGS=DISABLE=(".join(",",@warnings).")" : (); }), ++ defines => ++ add(sub { ++ return vms_info(0)->{def_zlib} ++ ? "LIBZ=\"\"\"".vms_info(0)->{def_zlib}."\"\"\"" : (); ++ }), ++ ex_libs => add(sub { return vms_info(0)->{zlib} || (); }), ++ pointer_size => sub { return vms_info(0)->{pointer_size} }, ++ #as => "I4S", ++ #debug_aflags => "/NOOPTIMIZE/DEBUG", ++ #release_aflags => "/OPTIMIZE/NODEBUG", ++ bn_opts => "SIXTY_FOUR_BIT RC4_INT", ++ }, ++ "vms-ia64-p32" => { ++ inherit_from => [ "vms-generic" ], ++ cflags => ++ add("/POINTER_SIZE=32", ++ sub { my @warnings = ++ @{vms_info(32)->{disable_warns}}; ++ @warnings ++ ? "/WARNINGS=DISABLE=(".join(",",@warnings).")" : (); ++ } ), ++ defines => ++ add(sub { ++ return vms_info(32)->{def_zlib} ++ ? "LIBZ=\"\"\"".vms_info(32)->{def_zlib}."\"\"\"" : (); ++ }), ++ ex_libs => add(sub { return vms_info(32)->{zlib} || (); }), ++ pointer_size => sub { return vms_info(32)->{pointer_size} }, ++ }, ++ "vms-ia64-p64" => { ++ inherit_from => [ "vms-generic" ], ++ cflags => ++ add("/POINTER_SIZE=64=ARGV", ++ sub { my @warnings = ++ @{vms_info(64)->{disable_warns}}; ++ @warnings ++ ? "/WARNINGS=DISABLE=(".join(",",@warnings).")" : (); ++ } ), ++ defines => ++ add(sub { ++ return vms_info(64)->{def_zlib} ++ ? "LIBZ=\"\"\"".vms_info(64)->{def_zlib}."\"\"\"" : (); ++ }), ++ ex_libs => add(sub { return vms_info(64)->{zlib} || (); }), ++ pointer_size => sub { return vms_info(64)->{pointer_size} }, ++ }, ++ ++); +diff --git a/CryptoPkg/Library/OpensslLib/openssl/Configurations/50-djgpp.conf b/CryptoPkg/Library/OpensslLib/openssl/Configurations/50-djgpp.conf +new file mode 100644 +index 0000000..f532bd1 +--- /dev/null ++++ b/CryptoPkg/Library/OpensslLib/openssl/Configurations/50-djgpp.conf +@@ -0,0 +1,15 @@ ++# We can't make any commitment to support the DJGPP platform, ++# and rely entirely on the OpenSSL community to help is fine ++# tune and test. ++ ++%targets = ( ++ "DJGPP" => { ++ inherit_from => [ asm("x86_asm") ], ++ cc => "gcc", ++ cflags => "-I/dev/env/WATT_ROOT/inc -DTERMIOS -DL_ENDIAN -fomit-frame-pointer -O2 -Wall", ++ sys_id => "MSDOS", ++ ex_libs => add("-L/dev/env/WATT_ROOT/lib -lwatt"), ++ bn_ops => "BN_LLONG", ++ perlasm_scheme => "a.out", ++ }, ++); +diff --git a/CryptoPkg/Library/OpensslLib/openssl/Configurations/50-haiku.conf b/CryptoPkg/Library/OpensslLib/openssl/Configurations/50-haiku.conf +new file mode 100644 +index 0000000..f114666 +--- /dev/null ++++ b/CryptoPkg/Library/OpensslLib/openssl/Configurations/50-haiku.conf +@@ -0,0 +1,29 @@ ++%targets = ( ++ "haiku-common" => { ++ template => 1, ++ cc => "cc", ++ cflags => add_before(picker(default => "-DL_ENDIAN -Wall -include \$(SRCDIR)/os-dep/haiku.h", ++ debug => "-g -O0", ++ release => "-O2"), ++ threads("-D_REENTRANT")), ++ sys_id => "HAIKU", ++ ex_libs => "-lnetwork", ++ perlasm_scheme => "elf", ++ thread_scheme => "pthreads", ++ dso_scheme => "dlfcn", ++ shared_target => "gnu-shared", ++ shared_cflag => "-fPIC", ++ shared_ldflag => "-shared", ++ shared_extension => ".so.\$(SHLIB_MAJOR).\$(SHLIB_MINOR)", ++ }, ++ "haiku-x86" => { ++ inherit_from => [ "haiku-common", asm("x86_elf_asm") ], ++ cflags => add(picker(release => "-fomit-frame-pointer")), ++ bn_ops => "BN_LLONG", ++ }, ++ "haiku-x86_64" => { ++ inherit_from => [ "haiku-common" ], ++ cflags => add("-m64"), ++ bn_ops => "SIXTY_FOUR_BIT_LONG", ++ }, ++); +diff --git a/CryptoPkg/Library/OpensslLib/openssl/Configurations/50-masm.conf b/CryptoPkg/Library/OpensslLib/openssl/Configurations/50-masm.conf +new file mode 100644 +index 0000000..60a5507 +--- /dev/null ++++ b/CryptoPkg/Library/OpensslLib/openssl/Configurations/50-masm.conf +@@ -0,0 +1,17 @@ ++# We can't make commitment to supporting Microsoft assembler, ++# because it would mean supporting all masm versions. This in ++# in turn is because masm is not really an interchangeable option, ++# while users tend to have reasons to stick with specific Visual ++# Studio versions. It's usually lesser hassle to make it work ++# with latest assembler, but tweaking for older versions had ++# proven to be daunting task. This is experimental target, for ++# production builds stick with [up-to-date version of] nasm. ++ ++%targets = ( ++ "VC-WIN64A-masm" => { ++ inherit_from => [ "VC-WIN64A" ], ++ as => "ml64", ++ asflags => "/c /Cp /Cx /Zi", ++ asoutflag => "/Fo", ++ }, ++); +diff --git a/CryptoPkg/Library/OpensslLib/openssl/Configurations/90-team.conf b/CryptoPkg/Library/OpensslLib/openssl/Configurations/90-team.conf +new file mode 100644 +index 0000000..0a83c22 +--- /dev/null ++++ b/CryptoPkg/Library/OpensslLib/openssl/Configurations/90-team.conf +@@ -0,0 +1,112 @@ ++## -*- mode: perl; -*- ++## Build configuration targets for openssl-team members ++ ++%targets = ( ++ "purify" => { ++ cc => "purify gcc", ++ cflags => "-g -Wall", ++ thread_scheme => "(unknown)", ++ ex_libs => add(" ","-lsocket -lnsl"), ++ }, ++ "debug" => { ++ cc => "gcc", ++ cflags => "-DBN_DEBUG -DREF_DEBUG -DCONF_DEBUG -DBN_CTX_DEBUG -DOPENSSL_NO_ASM -ggdb -g2 -Wformat -Wshadow -Wmissing-prototypes -Wmissing-declarations -Werror", ++ thread_scheme => "(unknown)", ++ }, ++ "debug-erbridge" => { ++ inherit_from => [ "x86_64_asm" ], ++ cc => "gcc", ++ cflags => combine("$gcc_devteam_warn -DBN_DEBUG -DCONF_DEBUG -m64 -DL_ENDIAN -DTERMIO -g", ++ threads("-D_REENTRANT")), ++ ex_libs => add(" ","-ldl"), ++ bn_ops => "SIXTY_FOUR_BIT_LONG", ++ thread_scheme => "pthreads", ++ perlasm_scheme => "elf", ++ dso_scheme => "dlfcn", ++ shared_target => "linux-shared", ++ shared_cflag => "-fPIC", ++ shared_ldflag => "-m64", ++ shared_extension => ".so.\$(SHLIB_MAJOR).\$(SHLIB_MINOR)", ++ multilib => "64", ++ }, ++ "debug-linux-pentium" => { ++ inherit_from => [ "x86_elf_asm" ], ++ cc => "gcc", ++ cflags => combine("-DBN_DEBUG -DREF_DEBUG -DCONF_DEBUG -DBN_CTX_DEBUG -DL_ENDIAN -g -mcpu=pentium -Wall", ++ threads("-D_REENTRANT")), ++ ex_libs => add(" ","-ldl"), ++ bn_ops => "BN_LLONG", ++ thread_scheme => "pthreads", ++ dso_scheme => "dlfcn", ++ }, ++ "debug-linux-ppro" => { ++ inherit_from => [ "x86_elf_asm" ], ++ cc => "gcc", ++ cflags => combine("-DBN_DEBUG -DREF_DEBUG -DCONF_DEBUG -DBN_CTX_DEBUG -DL_ENDIAN -g -mcpu=pentiumpro -Wall", ++ threads("-D_REENTRANT")), ++ ex_libs => add(" ","-ldl"), ++ bn_ops => "BN_LLONG", ++ thread_scheme => "pthreads", ++ dso_scheme => "dlfcn", ++ }, ++ "debug-linux-ia32-aes" => { ++ cc => "gcc", ++ cflags => combine("-DL_ENDIAN -O3 -fomit-frame-pointer -Wall", ++ threads("-D_REENTRANT")), ++ ex_libs => add(" ","-ldl"), ++ bn_ops => "BN_LLONG", ++ cpuid_asm_src => "x86cpuid.s", ++ bn_asm_src => "bn-586.s co-586.s x86-mont.s", ++ des_asm_src => "des-586.s crypt586.s", ++ aes_asm_src => "aes_x86core.s aes_cbc.s aesni-x86.s", ++ bf_asm_src => "bf-586.s", ++ md5_asm_src => "md5-586.s", ++ sha1_asm_src => "sha1-586.s sha256-586.s sha512-586.s", ++ cast_asm_src => "cast-586.s", ++ rc4_asm_src => "rc4-586.s", ++ rmd160_asm_src => "rmd-586.s", ++ rc5_asm_src => "rc5-586.s", ++ wp_asm_src => "wp_block.s wp-mmx.s", ++ modes_asm_src => "ghash-x86.s", ++ padlock_asm_src => "e_padlock-x86.s", ++ thread_scheme => "pthreads", ++ perlasm_scheme => "elf", ++ dso_scheme => "dlfcn", ++ shared_target => "linux-shared", ++ shared_cflag => "-fPIC", ++ shared_extension => ".so.\$(SHLIB_MAJOR).\$(SHLIB_MINOR)", ++ }, ++ "dist" => { ++ cc => "cc", ++ cflags => "-O", ++ thread_scheme => "(unknown)", ++ }, ++ "debug-test-64-clang" => { ++ inherit_from => [ "x86_64_asm" ], ++ cc => "clang", ++ cflags => combine("$gcc_devteam_warn -Wno-error=overlength-strings -Wno-error=extended-offsetof -Wno-error=language-extension-token -Wno-error=unused-const-variable -Wstrict-overflow -Qunused-arguments -DBN_DEBUG -DCONF_DEBUG -DDEBUG_SAFESTACK -DDEBUG_UNUSED -g3 -O3 -pipe", ++ threads("${BSDthreads}")), ++ bn_ops => "SIXTY_FOUR_BIT_LONG", ++ thread_scheme => "pthreads", ++ perlasm_scheme => "elf", ++ dso_scheme => "dlfcn", ++ shared_target => "bsd-gcc-shared", ++ shared_cflag => "-fPIC", ++ shared_extension => ".so.\$(SHLIB_MAJOR).\$(SHLIB_MINOR)", ++ }, ++ "darwin64-debug-test-64-clang" => { ++ inherit_from => [ "x86_64_asm" ], ++ cc => "clang", ++ cflags => combine("-arch x86_64 -DL_ENDIAN $gcc_devteam_warn -Wno-error=overlength-strings -Wno-error=extended-offsetof -Wno-error=language-extension-token -Wno-error=unused-const-variable -Wstrict-overflow -Qunused-arguments -DBN_DEBUG -DCONF_DEBUG -DDEBUG_SAFESTACK -DDEBUG_UNUSED -g3 -O3 -pipe", ++ threads("${BSDthreads}")), ++ sys_id => "MACOSX", ++ bn_ops => "SIXTY_FOUR_BIT_LONG", ++ thread_scheme => "pthreads", ++ perlasm_scheme => "macosx", ++ dso_scheme => "dlfcn", ++ shared_target => "darwin-shared", ++ shared_cflag => "-fPIC -fno-common", ++ shared_ldflag => "-arch x86_64 -dynamiclib", ++ shared_extension => ".\$(SHLIB_MAJOR).\$(SHLIB_MINOR).dylib", ++ }, ++); +diff --git a/CryptoPkg/Library/OpensslLib/openssl/Configurations/INTERNALS.Configure b/CryptoPkg/Library/OpensslLib/openssl/Configurations/INTERNALS.Configure +new file mode 100644 +index 0000000..b28305d +--- /dev/null ++++ b/CryptoPkg/Library/OpensslLib/openssl/Configurations/INTERNALS.Configure +@@ -0,0 +1,136 @@ ++Configure Internals ++=================== ++ ++[ note: this file uses markdown for formatting ] ++ ++Intro ++----- ++ ++This is a collection of notes that are hopefully of interest to those ++who decide to dive into Configure and what it does. This is a living ++document and anyone is encouraged to add to it and submit changes. ++There's no claim for this document to be complete at any time, but it ++will hopefully reach such a point in time. ++ ++ ++---------------------------------------------------------------------- ++ ++Parsing build.info files, processing conditions ++----------------------------------------------- ++ ++Processing conditions in build.info files is done with the help of a ++condition stack that tell if a build.info should be processed or if it ++should just be skipped over. The possible states of the stack top are ++expressed in the following comment from Configure: ++ ++ # The top item of this stack has the following values ++ # -2 positive already run and we found ELSE (following ELSIF should fail) ++ # -1 positive already run (skip until ENDIF) ++ # 0 negatives so far (if we're at a condition, check it) ++ # 1 last was positive (don't skip lines until next ELSE, ELSIF or ENDIF) ++ # 2 positive ELSE (following ELSIF should fail) ++ ++Ground rule is that non-condition lines are skipped over if the ++stack top is > 0. Condition lines (IF, ELSIF, ELSE and ENDIF ++statements) need to be processed either way to keep track of the skip ++stack states, so they are a little more intricate. ++ ++Instead of trying to describe in words, here are some example of what ++the skip stack should look like after each line is processed: ++ ++Example 1: ++ ++| IF[1] | 1 | | ++| ... whatever ... | | this line is processed | ++| IF[1] | 1 1 | | ++| ... whatever ... | | this line is processed | ++| ELSIF[1] | 1 -1 | | ++| ... whatever ... | | this line is skipped over | ++| ELSE | 1 -2 | | ++| ... whatever ... | | this line is skipped over | ++| ENDIF | 1 | | ++| ... whatever ... | | this line is processed | ++| ELSIF[1] | -1 | | ++| ... whatever ... | | this line is skipped over | ++| IF[1] | -1 -1 | | ++| ... whatever ... | | this line is skipped over | ++| ELSIF[1] | -1 -1 | | ++| ... whatever ... | | this line is skipped over | ++| ELSE | -1 -2 | | ++| ... whatever ... | | this line is skipped over | ++| ENDIF | -1 | | ++| ... whatever ... | | this line is skipped over | ++| ENDIF | | | ++ ++Example 2: ++ ++| IF[0] | 0 | | ++| ... whatever ... | | this line is skipped over | ++| IF[1] | 0 -1 | | ++| ... whatever ... | | this line is skipped over | ++| ELSIF[1] | 0 -1 | | ++| ... whatever ... | | this line is skipped over | ++| ELSE | 0 -2 | | ++| ... whatever ... | | this line is skipped over | ++| ENDIF | 0 | | ++| ... whatever ... | | this line is skipped over | ++| ELSIF[1] | 1 | | ++| ... whatever ... | | this line is processed | ++| IF[1] | 1 1 | | ++| ... whatever ... | | this line is processed | ++| ELSIF[1] | 1 -1 | | ++| ... whatever ... | | this line is skipped over | ++| ELSE | 1 -2 | | ++| ... whatever ... | | this line is skipped over | ++| ENDIF | 1 | | ++| ... whatever ... | | this line is processed | ++| ENDIF | | | ++ ++Example 3: ++ ++| IF[0] | 0 | | ++| ... whatever ... | | this line is skipped over | ++| IF[0] | 0 -1 | | ++| ... whatever ... | | this line is skipped over | ++| ELSIF[1] | 0 -1 | | ++| ... whatever ... | | this line is skipped over | ++| ELSE | 0 -2 | | ++| ... whatever ... | | this line is skipped over | ++| ENDIF | 0 | | ++| ... whatever ... | | this line is skipped over | ++| ELSIF[1] | 1 | | ++| ... whatever ... | | this line is processed | ++| IF[0] | 1 0 | | ++| ... whatever ... | | this line is skipped over | ++| ELSIF[1] | 1 1 | | ++| ... whatever ... | | this line is processed | ++| ELSE | 1 -2 | | ++| ... whatever ... | | this line is skipped over | ++| ENDIF | 1 | | ++| ... whatever ... | | this line is processed | ++| ENDIF | | | ++ ++Example 4: ++ ++| IF[0] | 0 | | ++| ... whatever ... | | this line is skipped over | ++| IF[0] | 0 -1 | | ++| ... whatever ... | | this line is skipped over | ++| ELSIF[0] | 0 -1 | | ++| ... whatever ... | | this line is skipped over | ++| ELSE | 0 -2 | | ++| ... whatever ... | | this line is skipped over | ++| ENDIF | 0 | | ++| ... whatever ... | | this line is skipped over | ++| ELSIF[1] | 1 | | ++| ... whatever ... | | this line is processed | ++| IF[0] | 1 0 | | ++| ... whatever ... | | this line is skipped over | ++| ELSIF[0] | 1 0 | | ++| ... whatever ... | | this line is skipped over | ++| ELSE | 1 2 | | ++| ... whatever ... | | this line is processed | ++| ENDIF | 1 | | ++| ... whatever ... | | this line is processed | ++| ENDIF | | | ++ +diff --git a/CryptoPkg/Library/OpensslLib/openssl/Configurations/README b/CryptoPkg/Library/OpensslLib/openssl/Configurations/README +new file mode 100644 +index 0000000..da64e8c +--- /dev/null ++++ b/CryptoPkg/Library/OpensslLib/openssl/Configurations/README +@@ -0,0 +1,655 @@ ++Configurations of OpenSSL target platforms ++========================================== ++ ++Target configurations are a collection of facts that we know about ++different platforms and their capabilities. We organise them in a ++hash table, where each entry represent a specific target. ++ ++In each table entry, the following keys are significant: ++ ++ inherit_from => Other targets to inherit values from. ++ Explained further below. [1] ++ template => Set to 1 if this isn't really a platform ++ target. Instead, this target is a template ++ upon which other targets can be built. ++ Explained further below. [1] ++ ++ sys_id => System identity for systems where that ++ is difficult to determine automatically. ++ ++ cc => The compiler command, usually one of "cc", ++ "gcc" or "clang". This command is normally ++ also used to link object files and ++ libraries into the final program. ++ cflags => Flags that are used at all times when ++ compiling. ++ defines => As an alternative, macro definitions may be ++ present here instead of in `cflags'. If ++ given here, they MUST be as an array of the ++ string such as "MACRO=value", or just ++ "MACRO" for definitions without value. ++ shared_cflag => Extra compilation flags used when ++ compiling for shared libraries, typically ++ something like "-fPIC". ++ ++ (linking is a complex thing, see [3] below) ++ ld => Linker command, usually not defined ++ (meaning the compiler command is used ++ instead). ++ (NOTE: this is here for future use, it's ++ not implemented yet) ++ lflags => Flags that are used when linking apps. ++ shared_ldflag => Flags that are used when linking shared ++ or dynamic libraries. ++ plib_lflags => Extra linking flags to appear just before ++ the libraries on the command line. ++ ex_libs => Extra libraries that are needed when ++ linking. ++ ++ ar => The library archive command, the default is ++ "ar". ++ (NOTE: this is here for future use, it's ++ not implemented yet) ++ arflags => Flags to be used with the library archive ++ command. ++ ++ ranlib => The library archive indexing command, the ++ default is 'ranlib' it it exists. ++ ++ unistd => An alternative header to the typical ++ ''. This is very rarely needed. ++ ++ shared_extension => File name extension used for shared ++ libraries. ++ obj_extension => File name extension used for object files. ++ On unix, this defaults to ".o" (NOTE: this ++ is here for future use, it's not ++ implemented yet) ++ exe_extension => File name extension used for executable ++ files. On unix, this defaults to "" (NOTE: ++ this is here for future use, it's not ++ implemented yet) ++ ++ thread_scheme => The type of threads is used on the ++ configured platform. Currently known ++ values are "(unknown)", "pthreads", ++ "uithreads" (a.k.a solaris threads) and ++ "winthreads". Except for "(unknown)", the ++ actual value is currently ignored but may ++ be used in the future. See further notes ++ below [2]. ++ dso_scheme => The type of dynamic shared objects to build ++ for. This mostly comes into play with ++ engines, but can be used for other purposes ++ as well. Valid values are "DLFCN" ++ (dlopen() et al), "DLFCN_NO_H" (for systems ++ that use dlopen() et al but do not have ++ fcntl.h), "DL" (shl_load() et al), "WIN32" ++ and "VMS". ++ perlasm_scheme => The perlasm method used to created the ++ assembler files used when compiling with ++ assembler implementations. ++ shared_target => The shared library building method used. ++ This is a target found in Makefile.shared. ++ build_scheme => The scheme used to build up a Makefile. ++ In its simplest form, the value is a string ++ with the name of the build scheme. ++ The value may also take the form of a list ++ of strings, if the build_scheme is to have ++ some options. In this case, the first ++ string in the list is the name of the build ++ scheme. ++ Currently recognised build scheme is "unified". ++ For the "unified" build scheme, this item ++ *must* be an array with the first being the ++ word "unified" and the second being a word ++ to identify the platform family. ++ ++ multilib => On systems that support having multiple ++ implementations of a library (typically a ++ 32-bit and a 64-bit variant), this is used ++ to have the different variants in different ++ directories. ++ ++ bn_ops => Building options (was just bignum options ++ in the earlier history of this option, ++ hence the name). This a string of words ++ that describe properties on the designated ++ target platform, such as the type of ++ integers used to build up the bitnum, ++ different ways to implement certain ciphers ++ and so on. To fully comprehend the ++ meaning, the best is to read the affected ++ source. ++ The valid words are: ++ ++ BN_LLONG use 'unsigned long long' in ++ some bignum calculations. ++ This has no value when ++ SIXTY_FOUR_BIT or ++ SIXTY_FOUR_BIT_LONG is given. ++ RC4_CHAR makes the basic RC4 unit of ++ calculation an unsigned char. ++ SIXTY_FOUR_BIT processor registers ++ are 64 bits, long is ++ 32 bits, long long is ++ 64 bits. ++ SIXTY_FOUR_BIT_LONG processor registers ++ are 64 bits, long is ++ 64 bits. ++ THIRTY_TWO_BIT processor registers ++ are 32 bits. ++ EXPORT_VAR_AS_FN for shared libraries, ++ export vars as ++ accessor functions. ++ ++ apps_extra_src => Extra source to build apps/openssl, as ++ needed by the target. ++ cpuid_asm_src => assembler implementation of cpuid code as ++ well as OPENSSL_cleanse(). ++ Default to mem_clr.c ++ bn_asm_src => Assembler implementation of core bignum ++ functions. ++ Defaults to bn_asm.c ++ ec_asm_src => Assembler implementation of core EC ++ functions. ++ des_asm_src => Assembler implementation of core DES ++ encryption functions. ++ Defaults to 'des_enc.c fcrypt_b.c' ++ aes_asm_src => Assembler implementation of core AES ++ functions. ++ Defaults to 'aes_core.c aes_cbc.c' ++ bf_asm_src => Assembler implementation of core BlowFish ++ functions. ++ Defaults to 'bf_enc.c' ++ md5_asm_src => Assembler implementation of core MD5 ++ functions. ++ sha1_asm_src => Assembler implementation of core SHA1, ++ functions, and also possibly SHA256 and ++ SHA512 ones. ++ cast_asm_src => Assembler implementation of core CAST ++ functions. ++ Defaults to 'c_enc.c' ++ rc4_asm_src => Assembler implementation of core RC4 ++ functions. ++ Defaults to 'rc4_enc.c rc4_skey.c' ++ rmd160_asm_src => Assembler implementation of core RMD160 ++ functions. ++ rc5_asm_src => Assembler implementation of core RC5 ++ functions. ++ Defaults to 'rc5_enc.c' ++ wp_asm_src => Assembler implementation of core WHIRLPOOL ++ functions. ++ cmll_asm_src => Assembler implementation of core CAMELLIA ++ functions. ++ Defaults to 'camellia.c cmll_misc.c cmll_cbc.c' ++ modes_asm_src => Assembler implementation of cipher modes, ++ currently the functions gcm_gmult_4bit and ++ gcm_ghash_4bit. ++ padlock_asm_src => Assembler implementation of core parts of ++ the padlock engine. This is mandatory on ++ any platform where the padlock engine might ++ actually be built. ++ ++ ++[1] as part of the target configuration, one can have a key called ++ 'inherit_from' that indicate what other configurations to inherit ++ data from. These are resolved recursively. ++ ++ Inheritance works as a set of default values that can be overridden ++ by corresponding key values in the inheriting configuration. ++ ++ Note 1: any configuration table can be used as a template. ++ Note 2: pure templates have the attribute 'template => 1' and ++ cannot be used as build targets. ++ ++ If several configurations are given in the 'inherit_from' array, ++ the values of same attribute are concatenated with space ++ separation. With this, it's possible to have several smaller ++ templates for different configuration aspects that can be combined ++ into a complete configuration. ++ ++ instead of a scalar value or an array, a value can be a code block ++ of the form 'sub { /* your code here */ }'. This code block will ++ be called with the list of inherited values for that key as ++ arguments. In fact, the concatenation of strings is really done ++ by using 'sub { join(" ",@_) }' on the list of inherited values. ++ ++ An example: ++ ++ "foo" => { ++ template => 1, ++ haha => "ha ha", ++ hoho => "ho", ++ ignored => "This should not appear in the end result", ++ }, ++ "bar" => { ++ template => 1, ++ haha => "ah", ++ hoho => "haho", ++ hehe => "hehe" ++ }, ++ "laughter" => { ++ inherit_from => [ "foo", "bar" ], ++ hehe => sub { join(" ",(@_,"!!!")) }, ++ ignored => "", ++ } ++ ++ The entry for "laughter" will become as follows after processing: ++ ++ "laughter" => { ++ haha => "ha ha ah", ++ hoho => "ho haho", ++ hehe => "hehe !!!", ++ ignored => "" ++ } ++ ++[2] OpenSSL is built with threading capabilities unless the user ++ specifies 'no-threads'. The value of the key 'thread_scheme' may ++ be "(unknown)", in which case the user MUST give some compilation ++ flags to Configure. ++ ++[3] OpenSSL has three types of things to link from object files or ++ static libraries: ++ ++ - shared libraries; that would be libcrypto and libssl. ++ - shared objects (sometimes called dynamic libraries); that would ++ be the engines. ++ - applications; those are apps/openssl and all the test apps. ++ ++ Very roughly speaking, linking is done like this (words in braces ++ represent the configuration settings documented at the beginning ++ of this file): ++ ++ shared libraries: ++ {ld} $(CFLAGS) {shared_ldflag} -shared -o libfoo.so \ ++ -Wl,--whole-archive libfoo.a -Wl,--no-whole-archive \ ++ {plib_lflags} -lcrypto {ex_libs} ++ ++ shared objects: ++ {ld} $(CFLAGS) {shared_ldflag} -shared -o libeng.so \ ++ blah1.o blah2.o {plib_lflags} -lcrypto {ex_libs} ++ ++ applications: ++ {ld} $(CFLAGS) {lflags} -o app \ ++ app1.o utils.o {plib_lflags} -lssl -lcrypto {ex_libs} ++ ++ ++Historically, the target configurations came in form of a string with ++values separated by colons. This use is deprecated. The string form ++looked like this: ++ ++ "target" => "{cc}:{cflags}:{unistd}:{thread_cflag}:{sys_id}:{lflags}:{bn_ops}:{cpuid_obj}:{bn_obj}:{ec_obj}:{des_obj}:{aes_obj}:{bf_obj}:{md5_obj}:{sha1_obj}:{cast_obj}:{rc4_obj}:{rmd160_obj}:{rc5_obj}:{wp_obj}:{cmll_obj}:{modes_obj}:{padlock_obj}:{perlasm_scheme}:{dso_scheme}:{shared_target}:{shared_cflag}:{shared_ldflag}:{shared_extension}:{ranlib}:{arflags}:{multilib}" ++ ++ ++Build info files ++================ ++ ++The build.info files that are spread over the source tree contain the ++minimum information needed to build and distribute OpenSSL. It uses a ++simple and yet fairly powerful language to determine what needs to be ++built, from what sources, and other relationships between files. ++ ++For every build.info file, all file references are relative to the ++directory of the build.info file for source files, and the ++corresponding build directory for built files if the build tree ++differs from the source tree. ++ ++When processed, every line is processed with the perl module ++Text::Template, using the delimiters "{-" and "-}". The hashes ++%config and %target are passed to the perl fragments, along with ++$sourcedir and $builddir, which are the locations of the source ++directory for the current build.info file and the corresponding build ++directory, all relative to the top of the build tree. ++ ++To begin with, things to be built are declared by setting specific ++variables: ++ ++ PROGRAMS=foo bar ++ LIBS=libsomething ++ ENGINES=libeng ++ SCRIPTS=myhack ++ EXTRA=file1 file2 ++ ++Note that the files mentioned for PROGRAMS, LIBS and ENGINES *must* be ++without extensions. The build file templates will figure them out. ++ ++For each thing to be built, it is then possible to say what sources ++they are built from: ++ ++ PROGRAMS=foo bar ++ SOURCE[foo]=foo.c common.c ++ SOURCE[bar]=bar.c extra.c common.c ++ ++It's also possible to tell some other dependencies: ++ ++ DEPEND[foo]=libsomething ++ DEPEND[libbar]=libsomethingelse ++ ++(it could be argued that 'libsomething' and 'libsomethingelse' are ++source as well. However, the files given through SOURCE are expected ++to be located in the source tree while files given through DEPEND are ++expected to be located in the build tree) ++ ++For some libraries, we maintain files with public symbols and their ++slot in a transfer vector (important on some platforms). It can be ++declared like this: ++ ++ ORDINALS[libcrypto]=crypto ++ ++The value is not the name of the file in question, but rather the ++argument to util/mkdef.pl that indicates which file to use. ++ ++One some platforms, shared libraries come with a name that's different ++from their static counterpart. That's declared as follows: ++ ++ SHARED_NAME[libfoo]=cygfoo-{- $config{shlibver} -} ++ ++The example is from Cygwin, which has a required naming convention. ++ ++Sometimes, it makes sense to rename an output file, for example a ++library: ++ ++ RENAME[libfoo]=libbar ++ ++That lines has "libfoo" get renamed to "libbar". While it makes no ++sense at all to just have a rename like that (why not just use ++"libbar" everywhere?), it does make sense when it can be used ++conditionally. See a little further below for an example. ++ ++In some cases, it's desirable to include some source files in the ++shared form of a library only: ++ ++ SHARED_SOURCE[libfoo]=dllmain.c ++ ++For any file to be built, it's also possible to tell what extra ++include paths the build of their source files should use: ++ ++ INCLUDE[foo]=include ++ ++In some cases, one might want to generate some source files from ++others, that's done as follows: ++ ++ GENERATE[foo.s]=asm/something.pl $(CFLAGS) ++ GENERATE[bar.s]=asm/bar.S ++ ++The value of each GENERATE line is a command line or part of it. ++Configure places no rules on the command line, except the the first ++item muct be the generator file. It is, however, entirely up to the ++build file template to define exactly how those command lines should ++be handled, how the output is captured and so on. ++ ++Sometimes, the generator file itself depends on other files, for ++example if it is a perl script that depends on other perl modules. ++This can be expressed using DEPEND like this: ++ ++ DEPEND[asm/something.pl]=../perlasm/Foo.pm ++ ++There may also be cases where the exact file isn't easily specified, ++but an inclusion directory still needs to be specified. INCLUDE can ++be used in that case: ++ ++ INCLUDE[asm/something.pl]=../perlasm ++ ++NOTE: GENERATE lines are limited to one command only per GENERATE. ++ ++As a last resort, it's possible to have raw build file lines, between ++BEGINRAW and ENDRAW lines as follows: ++ ++ BEGINRAW[Makefile(unix)] ++ haha.h: {- $builddir -}/Makefile ++ echo "/* haha */" > haha.h ++ ENDRAW[Makefile(unix)] ++ ++The word within square brackets is the build_file configuration item ++or the build_file configuration item followed by the second word in the ++build_scheme configuration item for the configured target within ++parenthesis as shown above. For example, with the following relevant ++configuration items: ++ ++ build_file => "build.ninja" ++ build_scheme => [ "unified", "unix" ] ++ ++... these lines will be considered: ++ ++ BEGINRAW[build.ninja] ++ build haha.h: echo "/* haha */" > haha.h ++ ENDRAW[build.ninja] ++ ++ BEGINRAW[build.ninja(unix)] ++ build hoho.h: echo "/* hoho */" > hoho.h ++ ENDRAW[build.ninja(unix)] ++ ++Should it be needed because the recipes within a RAW section might ++clash with those generated by Configure, it's possible to tell it ++not to generate them with the use of OVERRIDES, for example: ++ ++ SOURCE[libfoo]=foo.c bar.c ++ ++ OVERRIDES=bar.o ++ BEGINRAW[Makefile(unix)] ++ bar.o: bar.c ++ $(CC) $(CFLAGS) -DSPECIAL -c -o $@ $< ++ ENDRAW[Makefile(unix)] ++ ++See the documentation further up for more information on configuration ++items. ++ ++Finally, you can have some simple conditional use of the build.info ++information, looking like this: ++ ++ IF[1] ++ something ++ ELSIF[2] ++ something other ++ ELSE ++ something else ++ ENDIF ++ ++The expression in square brackets is interpreted as a string in perl, ++and will be seen as true if perl thinks it is, otherwise false. For ++example, the above would have "something" used, since 1 is true. ++ ++Together with the use of Text::Template, this can be used as ++conditions based on something in the passed variables, for example: ++ ++ IF[{- $disabled{shared} -}] ++ LIBS=libcrypto ++ SOURCE[libcrypto]=... ++ ELSE ++ LIBS=libfoo ++ SOURCE[libfoo]=... ++ ENDIF ++ ++or: ++ ++ # VMS has a cultural standard where all libraries are prefixed. ++ # For OpenSSL, the choice is 'ossl_' ++ IF[{- $config{target} =~ /^vms/ -}] ++ RENAME[libcrypto]=ossl_libcrypto ++ RENAME[libssl]=ossl_libssl ++ ENDIF ++ ++ ++Build-file programming with the "unified" build system ++====================================================== ++ ++"Build files" are called "Makefile" on Unix-like operating systems, ++"descrip.mms" for MMS on VMS, "makefile" for nmake on Windows, etc. ++ ++To use the "unified" build system, the target configuration needs to ++set the three items 'build_scheme', 'build_file' and 'build_command'. ++In the rest of this section, we will assume that 'build_scheme' is set ++to "unified" (see the configurations documentation above for the ++details). ++ ++For any name given by 'build_file', the "unified" system expects a ++template file in Configurations/ named like the build file, with ++".tmpl" appended, or in case of possible ambiguity, a combination of ++the second 'build_scheme' list item and the 'build_file' name. For ++example, if 'build_file' is set to "Makefile", the template could be ++Configurations/Makefile.tmpl or Configurations/unix-Makefile.tmpl. ++In case both Configurations/unix-Makefile.tmpl and ++Configurations/Makefile.tmpl are present, the former takes ++precedence. ++ ++The build-file template is processed with the perl module ++Text::Template, using "{-" and "-}" as delimiters that enclose the ++perl code fragments that generate configuration-dependent content. ++Those perl fragments have access to all the hash variables from ++configdata.pem. ++ ++The build-file template is expected to define at least the following ++perl functions in a perl code fragment enclosed with "{-" and "-}". ++They are all expected to return a string with the lines they produce. ++ ++ generatesrc - function that produces build file lines to generate ++ a source file from some input. ++ ++ It's called like this: ++ ++ generatesrc(src => "PATH/TO/tobegenerated", ++ generator => [ "generatingfile", ... ] ++ generator_incs => [ "INCL/PATH", ... ] ++ generator_deps => [ "dep1", ... ] ++ generator => [ "generatingfile", ... ] ++ incs => [ "INCL/PATH", ... ], ++ deps => [ "dep1", ... ], ++ intent => one of "libs", "dso", "bin" ); ++ ++ 'src' has the name of the file to be generated. ++ 'generator' is the command or part of command to ++ generate the file, of which the first item is ++ expected to be the file to generate from. ++ generatesrc() is expected to analyse and figure out ++ exactly how to apply that file and how to capture ++ the result. 'generator_incs' and 'generator_deps' ++ are include directories and files that the generator ++ file itself depends on. 'incs' and 'deps' are ++ include directories and files that are used if $(CC) ++ is used as an intermediary step when generating the ++ end product (the file indicated by 'src'). 'intent' ++ indicates what the generated file is going to be ++ used for. ++ ++ src2obj - function that produces build file lines to build an ++ object file from source files and associated data. ++ ++ It's called like this: ++ ++ src2obj(obj => "PATH/TO/objectfile", ++ srcs => [ "PATH/TO/sourcefile", ... ], ++ deps => [ "dep1", ... ], ++ incs => [ "INCL/PATH", ... ] ++ intent => one of "lib", "dso", "bin" ); ++ ++ 'obj' has the intended object file *without* ++ extension, src2obj() is expected to add that. ++ 'srcs' has the list of source files to build the ++ object file, with the first item being the source ++ file that directly corresponds to the object file. ++ 'deps' is a list of explicit dependencies. 'incs' ++ is a list of include file directories. Finally, ++ 'intent' indicates what this object file is going ++ to be used for. ++ ++ obj2lib - function that produces build file lines to build a ++ static library file ("libfoo.a" in Unix terms) from ++ object files. ++ ++ called like this: ++ ++ obj2lib(lib => "PATH/TO/libfile", ++ objs => [ "PATH/TO/objectfile", ... ]); ++ ++ 'lib' has the intended library file name *without* ++ extension, obj2lib is expected to add that. 'objs' ++ has the list of object files (also *without* ++ extension) to build this library. ++ ++ libobj2shlib - function that produces build file lines to build a ++ shareable object library file ("libfoo.so" in Unix ++ terms) from the corresponding static library file ++ or object files. ++ ++ called like this: ++ ++ libobj2shlib(shlib => "PATH/TO/shlibfile", ++ lib => "PATH/TO/libfile", ++ objs => [ "PATH/TO/objectfile", ... ], ++ deps => [ "PATH/TO/otherlibfile", ... ], ++ ordinals => [ "word", "/PATH/TO/ordfile" ]); ++ ++ 'lib' has the intended library file name *without* ++ extension, libobj2shlib is expected to add that. ++ 'shlib' has the corresponding shared library name ++ *without* extension. 'deps' has the list of other ++ libraries (also *without* extension) this library ++ needs to be linked with. 'objs' has the list of ++ object files (also *without* extension) to build ++ this library. 'ordinals' MAY be present, and when ++ it is, its value is an array where the word is ++ "crypto" or "ssl" and the file is one of the ordinal ++ files util/libeay.num or util/ssleay.num in the ++ source directory. ++ ++ This function has a choice; it can use the ++ corresponding static library as input to make the ++ shared library, or the list of object files. ++ ++ obj2dso - function that produces build file lines to build a ++ dynamic shared object file from object files. ++ ++ called like this: ++ ++ obj2dso(lib => "PATH/TO/libfile", ++ objs => [ "PATH/TO/objectfile", ... ], ++ deps => [ "PATH/TO/otherlibfile", ++ ... ]); ++ ++ This is almost the same as libobj2shlib, but the ++ intent is to build a shareable library that can be ++ loaded in runtime (a "plugin"...). The differences ++ are subtle, one of the most visible ones is that the ++ resulting shareable library is produced from object ++ files only. ++ ++ obj2bin - function that produces build file lines to build an ++ executable file from object files. ++ ++ called like this: ++ ++ obj2bin(bin => "PATH/TO/binfile", ++ objs => [ "PATH/TO/objectfile", ... ], ++ deps => [ "PATH/TO/libfile", ... ]); ++ ++ 'bin' has the intended executable file name ++ *without* extension, obj2bin is expected to add ++ that. 'objs' has the list of object files (also ++ *without* extension) to build this library. 'deps' ++ has the list of library files (also *without* ++ extension) that the programs needs to be linked ++ with. ++ ++ in2script - function that produces build file lines to build a ++ script file from some input. ++ ++ called like this: ++ ++ in2script(script => "PATH/TO/scriptfile", ++ sources => [ "PATH/TO/infile", ... ]); ++ ++ 'script' has the intended script file name. ++ 'sources' has the list of source files to build the ++ resulting script from. ++ ++In all cases, file file paths are relative to the build tree top, and ++the build file actions run with the build tree top as current working ++directory. ++ ++Make sure to end the section with these functions with a string that ++you thing is appropriate for the resulting build file. If nothing ++else, end it like this: ++ ++ ""; # Make sure no lingering values end up in the Makefile ++ -} +diff --git a/CryptoPkg/Library/OpensslLib/openssl/Configurations/README.design b/CryptoPkg/Library/OpensslLib/openssl/Configurations/README.design +new file mode 100644 +index 0000000..bea9790 +--- /dev/null ++++ b/CryptoPkg/Library/OpensslLib/openssl/Configurations/README.design +@@ -0,0 +1,641 @@ ++Design document for the unified scheme data ++=========================================== ++ ++How are things connected? ++------------------------- ++ ++The unified scheme takes all its data from the build.info files seen ++throughout the source tree. These files hold the minimum information ++needed to build end product files from diverse sources. See the ++section on build.info files below. ++ ++From the information in build.info files, Configure builds up an ++information database as a hash table called %unified_info, which is ++stored in configdata.pm, found at the top of the build tree (which may ++or may not be the same as the source tree). ++ ++Configurations/common.tmpl uses the data from %unified_info to ++generate the rules for building end product files as well as ++intermediary files with the help of a few functions found in the ++build-file templates. See the section on build-file templates further ++down for more information. ++ ++build.info files ++---------------- ++ ++As mentioned earlier, build.info files are meant to hold the minimum ++information needed to build output files, and therefore only (with a ++few possible exceptions [1]) have information about end products (such ++as scripts, library files and programs) and source files (such as C ++files, C header files, assembler files, etc). Intermediate files such ++as object files are rarely directly referred to in build.info files (and ++when they are, it's always with the file name extension .o), they are ++inferred by Configure. By the same rule of minimalism, end product ++file name extensions (such as .so, .a, .exe, etc) are never mentioned ++in build.info. Their file name extensions will be inferred by the ++build-file templates, adapted for the platform they are meant for (see ++sections on %unified_info and build-file templates further down). ++ ++The variables PROGRAMS, LIBS, ENGINES and SCRIPTS are used to declare ++end products. There are variants for them with '_NO_INST' as suffix ++(PROGRAM_NO_INST etc) to specify end products that shouldn't get ++installed. ++ ++The variables SOURCE, DEPEND, INCLUDE and ORDINALS are indexed by a ++produced file, and their values are the source used to produce that ++particular produced file, extra dependencies, include directories ++needed, and ordinal files (explained further below. ++ ++All their values in all the build.info throughout the source tree are ++collected together and form a set of programs, libraries, engines and ++scripts to be produced, source files, dependencies, etc etc etc. ++ ++Let's have a pretend example, a very limited contraption of OpenSSL, ++composed of the program 'apps/openssl', the libraries 'libssl' and ++'libcrypto', an engine 'engines/ossltest' and their sources and ++dependencies. ++ ++ # build.info ++ LIBS=libcrypto libssl ++ ORDINALS[libcrypto]=crypto ++ ORDINALS[libssl]=ssl ++ INCLUDE[libcrypto]=include ++ INCLUDE[libssl]=include ++ DEPEND[libssl]=libcrypto ++ ++This is the top directory build.info file, and it tells us that two ++libraries are to be built, there are some ordinals to be used to ++declare what symbols in those libraries are seen as public, the ++include directory 'include/' shall be used throughout when building ++anything that will end up in each library, and that the library ++'libssl' depend on the library 'libcrypto' to function properly. ++ ++ # apps/build.info ++ PROGRAMS=openssl ++ SOURCE[openssl]=openssl.c ++ INCLUDE[openssl]=.. ../include ++ DEPEND[openssl]=../libssl ++ ++This is the build.info file in 'apps/', one may notice that all file ++paths mentioned are relative to the directory the build.info file is ++located in. This one tells us that there's a program to be built ++called 'apps/openssl' (the file name extension will depend on the ++platform and is therefore not mentioned in the build.info file). It's ++built from one source file, 'apps/openssl.c', and building it requires ++the use of '.' and 'include' include directories (both are declared ++from the point of view of the 'apps/' directory), and that the program ++depends on the library 'libssl' to function properly. ++ ++ # crypto/build.info ++ LIBS=../libcrypto ++ SOURCE[../libcrypto]=aes.c evp.c cversion.c ++ DEPEND[cversion.o]=buildinf.h ++ ++ GENERATE[buildinf.h]=../util/mkbuildinf.pl "$(CC) $(CFLAGS)" "$(PLATFORM)" ++ DEPEND[buildinf.h]=../Makefile ++ DEPEND[../util/mkbuildinf.pl]=../util/Foo.pm ++ ++This is the build.info file in 'crypto', and it tells us a little more ++about what's needed to produce 'libcrypto'. LIBS is used again to ++declare that 'libcrypto' is to be produced. This declaration is ++really unnecessary as it's already mentioned in the top build.info ++file, but can make the info file easier to understand. This is to ++show that duplicate information isn't an issue. ++ ++This build.info file informs us that 'libcrypto' is built from a few ++source files, 'crypto/aes.c', 'crypto/evp.c' and 'crypto/cversion.c'. ++It also shows us that building the object file inferred from ++'crypto/cversion.c' depends on 'crypto/buildinf.h'. Finally, it ++also shows the possibility to declare how some files are generated ++using some script, in this case a perl script, and how such scripts ++can be declared to depend on other files, in this case a perl module. ++ ++Two things are worth an extra note: ++ ++'DEPEND[cversion.o]' mentions an object file. DEPEND indexes is the ++only location where it's valid to mention them ++ ++Lines in 'BEGINRAW'..'ENDRAW' sections must always mention files as ++seen from the top directory, no exception. ++ ++ # ssl/build.info ++ LIBS=../libssl ++ SOURCE[../libssl]=tls.c ++ ++This is the build.info file in 'ssl/', and it tells us that the ++library 'libssl' is built from the source file 'ssl/tls.c'. ++ ++ # engines/build.info ++ ENGINES=dasync ++ SOURCE[dasync]=e_dasync.c ++ DEPEND[dasync]=../libcrypto ++ INCLUDE[dasync]=../include ++ ++ ENGINES_NO_INST=ossltest ++ SOURCE[ossltest]=e_ossltest.c ++ DEPEND[ossltest]=../libcrypto ++ INCLUDE[ossltest]=../include ++ ++This is the build.info file in 'engines/', telling us that two engines ++called 'engines/dasync' and 'engines/ossltest' shall be built, that ++dasync's source is 'engines/e_dasync.c' and ossltest's source is ++'engines/e_ossltest.c' and that the include directory 'include/' may ++be used when building anything that will be part of these engines. ++Also, both engines depend on the library 'libcrypto' to function ++properly. Finally, only dasync is being installed, as ossltest is ++only for internal testing. ++ ++When Configure digests these build.info files, the accumulated ++information comes down to this: ++ ++ LIBS=libcrypto libssl ++ ORDINALS[libcrypto]=crypto ++ SOURCE[libcrypto]=crypto/aes.c crypto/evp.c crypto/cversion.c ++ DEPEND[crypto/cversion.o]=crypto/buildinf.h ++ INCLUDE[libcrypto]=include ++ ORDINALS[libssl]=ssl ++ SOURCE[libssl]=ssl/tls.c ++ INCLUDE[libssl]=include ++ DEPEND[libssl]=libcrypto ++ ++ PROGRAMS=apps/openssl ++ SOURCE[apps/openssl]=apps/openssl.c ++ INCLUDE[apps/openssl]=. include ++ DEPEND[apps/openssl]=libssl ++ ++ ENGINES=engines/dasync ++ SOURCE[engines/dasync]=engines/e_dasync.c ++ DEPEND[engines/dasync]=libcrypto ++ INCLUDE[engines/dasync]=include ++ ++ ENGINES_NO_INST=engines/ossltest ++ SOURCE[engines/ossltest]=engines/e_ossltest.c ++ DEPEND[engines/ossltest]=libcrypto ++ INCLUDE[engines/ossltest]=include ++ ++ GENERATE[crypto/buildinf.h]=util/mkbuildinf.pl "$(CC) $(CFLAGS)" "$(PLATFORM)" ++ DEPEND[crypto/buildinf.h]=Makefile ++ DEPEND[util/mkbuildinf.pl]=util/Foo.pm ++ ++ ++A few notes worth mentioning: ++ ++LIBS may be used to declare routine libraries only. ++ ++PROGRAMS may be used to declare programs only. ++ ++ENGINES may be used to declare engines only. ++ ++The indexes for SOURCE and ORDINALS must only be end product files, ++such as libraries, programs or engines. The values of SOURCE ++variables must only be source files (possibly generated) ++ ++INCLUDE and DEPEND shows a relationship between different files ++(usually produced files) or between files and directories, such as a ++program depending on a library, or between an object file and some ++extra source file. ++ ++When Configure processes the build.info files, it will take it as ++truth without question, and will therefore perform very few checks. ++If the build tree is separate from the source tree, it will assume ++that all built files and up in the build directory and that all source ++files are to be found in the source tree, if they can be found there. ++Configure will assume that source files that can't be found in the ++source tree (such as 'crypto/bildinf.h' in the example above) are ++generated and will be found in the build tree. ++ ++ ++The %unified_info database ++-------------------------- ++ ++The information in all the build.info get digested by Configure and ++collected into the %unified_info database, divided into the following ++indexes: ++ ++ depends => a hash table containing 'file' => [ 'dependency' ... ] ++ pairs. These are directly inferred from the DEPEND ++ variables in build.info files. ++ ++ engines => a list of engines. These are directly inferred from ++ the ENGINES variable in build.info files. ++ ++ generate => a hash table containing 'file' => [ 'generator' ... ] ++ pairs. These are directly inferred from the GENERATE ++ variables in build.info files. ++ ++ includes => a hash table containing 'file' => [ 'include' ... ] ++ pairs. These are directly inferred from the INCLUDE ++ variables in build.info files. ++ ++ install => a hash table containing 'type' => [ 'file' ... ] pairs. ++ The types are 'programs', 'libraries', 'engines' and ++ 'scripts', and the array of files list the files of ++ that type that should be installed. ++ ++ libraries => a list of libraries. These are directly inferred from ++ the LIBS variable in build.info files. ++ ++ ordinals => a hash table containing 'file' => [ 'word', 'ordfile' ] ++ pairs. 'file' and 'word' are directly inferred from ++ the ORDINALS variables in build.info files, while the ++ file 'ofile' comes from internal knowledge in ++ Configure. ++ ++ programs => a list of programs. These are directly inferred from ++ the PROGRAMS variable in build.info files. ++ ++ rawlines => a list of build-file lines. These are a direct copy of ++ the BEGINRAW..ENDRAW lines in build.info files. Note: ++ only the BEGINRAW..ENDRAW section for the current ++ platform are copied, the rest are ignored. ++ ++ scripts => a list of scripts. There are directly inferred from ++ the SCRIPTS variable in build.info files. ++ ++ sources => a hash table containing 'file' => [ 'sourcefile' ... ] ++ pairs. These are indirectly inferred from the SOURCE ++ variables in build.info files. Object files are ++ mentioned in this hash table, with source files from ++ SOURCE variables, and AS source files for programs and ++ libraries. ++ ++ shared_sources => ++ a hash table just like 'sources', but only as source ++ files (object files) for building shared libraries. ++ ++As an example, here is how the build.info files example from the ++section above would be digested into a %unified_info table: ++ ++ our %unified_info = ( ++ "depends" => ++ { ++ "apps/openssl" => ++ [ ++ "libssl", ++ ], ++ "crypto/buildinf.h" => ++ [ ++ "Makefile", ++ ], ++ "crypto/cversion.o" => ++ [ ++ "crypto/buildinf.h", ++ ], ++ "engines/ossltest" => ++ [ ++ "libcrypto", ++ ], ++ "libssl" => ++ [ ++ "libcrypto", ++ ], ++ "util/mkbuildinf.pl" => ++ [ ++ "util/Foo.pm", ++ ], ++ }, ++ "engines" => ++ [ ++ "engines/dasync", ++ "engines/ossltest", ++ ], ++ "generate" => ++ { ++ "crypto/buildinf.h" => ++ [ ++ "util/mkbuildinf.pl", ++ "\"\$(CC)", ++ "\$(CFLAGS)\"", ++ "\"$(PLATFORM)\"", ++ ], ++ }, ++ "includes" => ++ { ++ "apps/openssl" => ++ [ ++ ".", ++ "include", ++ ], ++ "engines/ossltest" => ++ [ ++ "include" ++ ], ++ "libcrypto" => ++ [ ++ "include", ++ ], ++ "libssl" => ++ [ ++ "include", ++ ], ++ "util/mkbuildinf.pl" => ++ [ ++ "util", ++ ], ++ } ++ "install" => ++ { ++ "engines" => ++ [ ++ "engines/dasync", ++ ], ++ "libraries" => ++ [ ++ "libcrypto", ++ "libssl", ++ ], ++ "programs" => ++ [ ++ "apps/openssl", ++ ], ++ }, ++ "libraries" => ++ [ ++ "libcrypto", ++ "libssl", ++ ], ++ "ordinals" => ++ { ++ "libcrypto" => ++ [ ++ "crypto", ++ "util/libcrypto.num", ++ ], ++ "libssl" => ++ [ ++ "ssl", ++ "util/libssl.num", ++ ], ++ }, ++ "programs" => ++ [ ++ "apps/openssl", ++ ], ++ "rawlines" => ++ [ ++ ], ++ "sources" => ++ { ++ "apps/openssl" => ++ [ ++ "apps/openssl.o", ++ ], ++ "apps/openssl.o" => ++ [ ++ "apps/openssl.c", ++ ], ++ "crypto/aes.o" => ++ [ ++ "crypto/aes.c", ++ ], ++ "crypto/cversion.o" => ++ [ ++ "crypto/cversion.c", ++ ], ++ "crypto/evp.o" => ++ [ ++ "crypto/evp.c", ++ ], ++ "engines/e_ossltest.o" => ++ [ ++ "engines/e_ossltest.c", ++ ], ++ "engines/ossltest" => ++ [ ++ "engines/e_ossltest.o", ++ ], ++ "libcrypto" => ++ [ ++ "crypto/aes.c", ++ "crypto/cversion.c", ++ "crypto/evp.c", ++ ], ++ "libssl" => ++ [ ++ "ssl/tls.c", ++ ], ++ "ssl/tls.o" => ++ [ ++ "ssl/tls.c", ++ ], ++ }, ++ ); ++ ++As can be seen, everything in %unified_info is fairly simple suggest ++of information. Still, it tells us that to build all programs, we ++must build 'apps/openssl', and to build the latter, we will need to ++build all its sources ('apps/openssl.o' in this case) and all the ++other things it depends on (such as 'libssl'). All those dependencies ++need to be built as well, using the same logic, so to build 'libssl', ++we need to build 'ssl/tls.o' as well as 'libcrypto', and to build the ++latter... ++ ++ ++Build-file templates ++-------------------- ++ ++Build-file templates are essentially build-files (such as Makefile on ++Unix) with perl code fragments mixed in. Those perl code fragment ++will generate all the configuration dependent data, including all the ++rules needed to build end product files and intermediary files alike. ++At a minimum, there must be a perl code fragment that defines a set of ++functions that are used to generates specific build-file rules, to ++build static libraries from object files, to build shared libraries ++from static libraries, to programs from object files and libraries, ++etc. ++ ++ generatesrc - function that produces build file lines to generate ++ a source file from some input. ++ ++ It's called like this: ++ ++ generatesrc(src => "PATH/TO/tobegenerated", ++ generator => [ "generatingfile", ... ] ++ generator_incs => [ "INCL/PATH", ... ] ++ generator_deps => [ "dep1", ... ] ++ incs => [ "INCL/PATH", ... ], ++ deps => [ "dep1", ... ], ++ intent => one of "libs", "dso", "bin" ); ++ ++ 'src' has the name of the file to be generated. ++ 'generator' is the command or part of command to ++ generate the file, of which the first item is ++ expected to be the file to generate from. ++ generatesrc() is expected to analyse and figure out ++ exactly how to apply that file and how to capture ++ the result. 'generator_incs' and 'generator_deps' ++ are include directories and files that the generator ++ file itself depends on. 'incs' and 'deps' are ++ include directories and files that are used if $(CC) ++ is used as an intermediary step when generating the ++ end product (the file indicated by 'src'). 'intent' ++ indicates what the generated file is going to be ++ used for. ++ ++ src2obj - function that produces build file lines to build an ++ object file from source files and associated data. ++ ++ It's called like this: ++ ++ src2obj(obj => "PATH/TO/objectfile", ++ srcs => [ "PATH/TO/sourcefile", ... ], ++ deps => [ "dep1", ... ], ++ incs => [ "INCL/PATH", ... ] ++ intent => one of "lib", "dso", "bin" ); ++ ++ 'obj' has the intended object file *without* ++ extension, src2obj() is expected to add that. ++ 'srcs' has the list of source files to build the ++ object file, with the first item being the source ++ file that directly corresponds to the object file. ++ 'deps' is a list of explicit dependencies. 'incs' ++ is a list of include file directories. Finally, ++ 'intent' indicates what this object file is going ++ to be used for. ++ ++ obj2lib - function that produces build file lines to build a ++ static library file ("libfoo.a" in Unix terms) from ++ object files. ++ ++ called like this: ++ ++ obj2lib(lib => "PATH/TO/libfile", ++ objs => [ "PATH/TO/objectfile", ... ]); ++ ++ 'lib' has the intended library file name *without* ++ extension, obj2lib is expected to add that. 'objs' ++ has the list of object files (also *without* ++ extension) to build this library. ++ ++ libobj2shlib - function that produces build file lines to build a ++ shareable object library file ("libfoo.so" in Unix ++ terms) from the corresponding static library file ++ or object files. ++ ++ called like this: ++ ++ libobj2shlib(shlib => "PATH/TO/shlibfile", ++ lib => "PATH/TO/libfile", ++ objs => [ "PATH/TO/objectfile", ... ], ++ deps => [ "PATH/TO/otherlibfile", ... ], ++ ordinals => [ "word", "/PATH/TO/ordfile" ]); ++ ++ 'lib' has the intended library file name *without* ++ extension, libobj2shlib is expected to add that. ++ 'shlib' has the corresponding shared library name ++ *without* extension. 'deps' has the list of other ++ libraries (also *without* extension) this library ++ needs to be linked with. 'objs' has the list of ++ object files (also *without* extension) to build ++ this library. 'ordinals' MAY be present, and when ++ it is, its value is an array where the word is ++ "crypto" or "ssl" and the file is one of the ordinal ++ files util/libcrypto.num or util/libssl.num in the ++ source directory. ++ ++ This function has a choice; it can use the ++ corresponding static library as input to make the ++ shared library, or the list of object files. ++ ++ obj2dynlib - function that produces build file lines to build a ++ dynamically loadable library file ("libfoo.so" on ++ Unix) from object files. ++ ++ called like this: ++ ++ obj2dynlib(lib => "PATH/TO/libfile", ++ objs => [ "PATH/TO/objectfile", ... ], ++ deps => [ "PATH/TO/otherlibfile", ++ ... ]); ++ ++ This is almost the same as libobj2shlib, but the ++ intent is to build a shareable library that can be ++ loaded in runtime (a "plugin"...). The differences ++ are subtle, one of the most visible ones is that the ++ resulting shareable library is produced from object ++ files only. ++ ++ obj2bin - function that produces build file lines to build an ++ executable file from object files. ++ ++ called like this: ++ ++ obj2bin(bin => "PATH/TO/binfile", ++ objs => [ "PATH/TO/objectfile", ... ], ++ deps => [ "PATH/TO/libfile", ... ]); ++ ++ 'bin' has the intended executable file name ++ *without* extension, obj2bin is expected to add ++ that. 'objs' has the list of object files (also ++ *without* extension) to build this library. 'deps' ++ has the list of library files (also *without* ++ extension) that the programs needs to be linked ++ with. ++ ++ in2script - function that produces build file lines to build a ++ script file from some input. ++ ++ called like this: ++ ++ in2script(script => "PATH/TO/scriptfile", ++ sources => [ "PATH/TO/infile", ... ]); ++ ++ 'script' has the intended script file name. ++ 'sources' has the list of source files to build the ++ resulting script from. ++ ++Along with the build-file templates is the driving engine ++Configurations/common.tmpl, which looks through all the information in ++%unified_info and generates all the rulesets to build libraries, ++programs and all intermediate files, using the rule generating ++functions defined in the build-file template. ++ ++As an example with the smaller build.info set we've seen as an ++example, producing the rules to build 'libcrypto' would result in the ++following calls: ++ ++ # Note: libobj2shlib will only be called if shared libraries are ++ # to be produced. ++ # Note 2: libobj2shlib gets both the name of the static library ++ # and the names of all the object files that go into it. It's up ++ # to the implementation to decide which to use as input. ++ # Note 3: common.tmpl peals off the ".o" extension from all object ++ # files, as the platform at hand may have a different one. ++ libobj2shlib(shlib => "libcrypto", ++ lib => "libcrypto", ++ objs => [ "crypto/aes", "crypto/evp", "crypto/cversion" ], ++ deps => [ ] ++ ordinals => [ "crypto", "util/libcrypto.num" ]); ++ ++ obj2lib(lib => "libcrypto" ++ objs => [ "crypto/aes", "crypto/evp", "crypto/cversion" ]); ++ ++ src2obj(obj => "crypto/aes" ++ srcs => [ "crypto/aes.c" ], ++ deps => [ ], ++ incs => [ "include" ], ++ intent => "lib"); ++ ++ src2obj(obj => "crypto/evp" ++ srcs => [ "crypto/evp.c" ], ++ deps => [ ], ++ incs => [ "include" ], ++ intent => "lib"); ++ ++ src2obj(obj => "crypto/cversion" ++ srcs => [ "crypto/cversion.c" ], ++ deps => [ "crypto/buildinf.h" ], ++ incs => [ "include" ], ++ intent => "lib"); ++ ++ generatesrc(src => "crypto/buildinf.h", ++ generator => [ "util/mkbuildinf.pl", "\"$(CC)", ++ "$(CFLAGS)\"", "\"$(PLATFORM)\"" ], ++ generator_incs => [ "util" ], ++ generator_deps => [ "util/Foo.pm" ], ++ incs => [ ], ++ deps => [ ], ++ intent => "lib"); ++ ++The returned strings from all those calls are then concatenated ++together and written to the resulting build-file. +diff --git a/CryptoPkg/Library/OpensslLib/openssl/Configurations/common.tmpl b/CryptoPkg/Library/OpensslLib/openssl/Configurations/common.tmpl +new file mode 100644 +index 0000000..9d7fbf2 +--- /dev/null ++++ b/CryptoPkg/Library/OpensslLib/openssl/Configurations/common.tmpl +@@ -0,0 +1,231 @@ ++{- # -*- Mode: perl -*- ++ ++ use File::Basename; ++ ++ # A cache of objects for which a recipe has already been generated ++ my %cache; ++ ++ # resolvedepends and reducedepends work in tandem to make sure ++ # there are no duplicate dependencies and that they are in the ++ # right order. This is especially used to sort the list of ++ # libraries that a build depends on. ++ sub resolvedepends { ++ my $thing = shift; ++ my @listsofar = @_; # to check if we're looping ++ my @list = @{$unified_info{depends}->{$thing}}; ++ my @newlist = (); ++ if (scalar @list) { ++ foreach my $item (@list) { ++ # It's time to break off when the dependency list starts looping ++ next if grep { $_ eq $item } @listsofar; ++ push @newlist, $item, resolvedepends($item, @listsofar, $item); ++ } ++ } ++ @newlist; ++ } ++ sub reducedepends { ++ my @list = @_; ++ my @newlist = (); ++ while (@list) { ++ my $item = shift @list; ++ push @newlist, $item ++ unless grep { $item eq $_ } @list; ++ } ++ @newlist; ++ } ++ ++ # dogenerate is responsible for producing all the recipes that build ++ # generated source files. It recurses in case a dependency is also a ++ # generated source file. ++ sub dogenerate { ++ my $src = shift; ++ return "" if $cache{$src}; ++ my $obj = shift; ++ my $bin = shift; ++ my %opts = @_; ++ if ($unified_info{generate}->{$src}) { ++ die "$src is generated by Configure, should not appear in build file\n" ++ if ref $unified_info{generate}->{$src} eq ""; ++ my $script = $unified_info{generate}->{$src}->[0]; ++ $OUT .= generatesrc(src => $src, ++ generator => $unified_info{generate}->{$src}, ++ generator_incs => $unified_info{includes}->{$script}, ++ generator_deps => $unified_info{depends}->{$script}, ++ deps => $unified_info{depends}->{$src}, ++ incs => [ @{$unified_info{includes}->{$bin}}, ++ @{$unified_info{includes}->{$obj}} ], ++ %opts); ++ foreach (@{$unified_info{depends}->{$src}}) { ++ dogenerate($_, $obj, $bin, %opts); ++ } ++ } ++ $cache{$src} = 1; ++ } ++ ++ # doobj is responsible for producing all the recipes that build ++ # object files as well as dependency files. ++ sub doobj { ++ my $obj = shift; ++ return "" if $cache{$obj}; ++ (my $obj_no_o = $obj) =~ s|\.o$||; ++ my $bin = shift; ++ my %opts = @_; ++ if (@{$unified_info{sources}->{$obj}}) { ++ $OUT .= src2obj(obj => $obj_no_o, ++ srcs => $unified_info{sources}->{$obj}, ++ deps => $unified_info{depends}->{$obj}, ++ incs => [ @{$unified_info{includes}->{$bin}}, ++ @{$unified_info{includes}->{$obj}} ], ++ %opts); ++ foreach ((@{$unified_info{sources}->{$obj}}, ++ @{$unified_info{depends}->{$obj}})) { ++ dogenerate($_, $obj, $bin, %opts); ++ } ++ } ++ $cache{$obj} = 1; ++ } ++ ++ # dolib is responsible for building libraries. It will call ++ # libobj2shlib is shared libraries are produced, and obj2lib in all ++ # cases. It also makes sure all object files for the library are ++ # built. ++ sub dolib { ++ my $lib = shift; ++ return "" if $cache{$lib}; ++ unless ($disabled{shared}) { ++ my %ordinals = ++ $unified_info{ordinals}->{$lib} ++ ? (ordinals => $unified_info{ordinals}->{$lib}) : (); ++ $OUT .= libobj2shlib(shlib => $unified_info{sharednames}->{$lib}, ++ lib => $lib, ++ objs => [ map { (my $x = $_) =~ s|\.o$||; $x } ++ (@{$unified_info{sources}->{$lib}}, ++ @{$unified_info{shared_sources}->{$lib}}) ], ++ deps => [ reducedepends(resolvedepends($lib)) ], ++ %ordinals); ++ foreach (@{$unified_info{shared_sources}->{$lib}}) { ++ doobj($_, $lib, intent => "lib"); ++ } ++ } ++ $OUT .= obj2lib(lib => $lib, ++ objs => [ map { (my $x = $_) =~ s|\.o$||; $x } ++ @{$unified_info{sources}->{$lib}} ]); ++ foreach (@{$unified_info{sources}->{$lib}}) { ++ doobj($_, $lib, intent => "lib"); ++ } ++ $cache{$lib} = 1; ++ } ++ ++ # doengine is responsible for building engines. It will call ++ # obj2dso, and also makes sure all object files for the library ++ # are built. ++ sub doengine { ++ my $lib = shift; ++ return "" if $cache{$lib}; ++ $OUT .= obj2dso(lib => $lib, ++ objs => [ map { (my $x = $_) =~ s|\.o$||; $x } ++ (@{$unified_info{sources}->{$lib}}, ++ @{$unified_info{shared_sources}->{$lib}}) ], ++ deps => [ resolvedepends($lib) ]); ++ foreach ((@{$unified_info{sources}->{$lib}}, ++ @{$unified_info{shared_sources}->{$lib}})) { ++ doobj($_, $lib, intent => "dso"); ++ } ++ $cache{$lib} = 1; ++ } ++ ++ # dobin is responsible for building programs. It will call obj2bin, ++ # and also makes sure all object files for the library are built. ++ sub dobin { ++ my $bin = shift; ++ return "" if $cache{$bin}; ++ my $deps = [ reducedepends(resolvedepends($bin)) ]; ++ $OUT .= obj2bin(bin => $bin, ++ objs => [ map { (my $x = $_) =~ s|\.o$||; $x } ++ @{$unified_info{sources}->{$bin}} ], ++ deps => $deps); ++ foreach (@{$unified_info{sources}->{$bin}}) { ++ doobj($_, $bin, intent => "bin"); ++ } ++ $cache{$bin} = 1; ++ } ++ ++ # dobin is responsible for building scripts from templates. It will ++ # call in2script. ++ sub doscript { ++ my $script = shift; ++ return "" if $cache{$script}; ++ $OUT .= in2script(script => $script, ++ sources => $unified_info{sources}->{$script}); ++ $cache{$script} = 1; ++ } ++ ++ sub dodir { ++ my $dir = shift; ++ return "" if !exists(&generatedir) or $cache{$dir}; ++ $OUT .= generatedir(dir => $dir, ++ deps => $unified_info{dirinfo}->{$dir}->{deps}, ++ %{$unified_info{dirinfo}->{$_}->{products}}); ++ $cache{$dir} = 1; ++ } ++ ++ # Start with populating the cache with all the overrides ++ %cache = map { $_ => 1 } @{$unified_info{overrides}}; ++ ++ # For convenience collect information regarding directories where ++ # files are generated, those generated files and the end product ++ # they end up in where applicable. Then, add build rules for those ++ # directories ++ if (exists &generatedir) { ++ my %loopinfo = ( "dso" => [ @{$unified_info{engines}} ], ++ "lib" => [ @{$unified_info{libraries}} ], ++ "bin" => [ @{$unified_info{programs}} ], ++ "script" => [ @{$unified_info{scripts}} ] ); ++ foreach my $type (keys %loopinfo) { ++ foreach my $product (@{$loopinfo{$type}}) { ++ my %dirs = (); ++ my $pd = dirname($product); ++ ++ # We already have a "test" target, and the current directory ++ # is just silly to make a target for ++ $dirs{$pd} = 1 unless $pd eq "test" || $pd eq "."; ++ ++ foreach (@{$unified_info{sources}->{$product}}) { ++ my $d = dirname($_); ++ ++ # We don't want to create targets for source directories ++ # when building out of source ++ next if ($config{sourcedir} ne $config{builddir} ++ && $d =~ m|^\Q$config{sourcedir}\E|); ++ # We already have a "test" target, and the current directory ++ # is just silly to make a target for ++ next if $d eq "test" || $d eq "."; ++ ++ $dirs{$d} = 1; ++ push @{$unified_info{dirinfo}->{$d}->{deps}}, $_ ++ if $d ne $pd; ++ } ++ foreach (keys %dirs) { ++ push @{$unified_info{dirinfo}->{$_}->{products}->{$type}}, ++ $product; ++ } ++ } ++ } ++ } ++ ++ # Build mandatory generated headers ++ foreach (@{$unified_info{depends}->{""}}) { dogenerate($_); } ++ ++ # Build all known libraries, engines, programs and scripts. ++ # Everything else will be handled as a consequence. ++ foreach (@{$unified_info{libraries}}) { dolib($_); } ++ foreach (@{$unified_info{engines}}) { doengine($_); } ++ foreach (@{$unified_info{programs}}) { dobin($_); } ++ foreach (@{$unified_info{scripts}}) { doscript($_); } ++ ++ foreach (sort keys %{$unified_info{dirinfo}}) { dodir($_); } ++ ++ # Finally, should there be any applicable BEGINRAW/ENDRAW sections, ++ # they are added here. ++ $OUT .= $_."\n" foreach @{$unified_info{rawlines}}; ++-} +diff --git a/CryptoPkg/Library/OpensslLib/openssl/Configurations/descrip.mms.tmpl b/CryptoPkg/Library/OpensslLib/openssl/Configurations/descrip.mms.tmpl +new file mode 100644 +index 0000000..da57049 +--- /dev/null ++++ b/CryptoPkg/Library/OpensslLib/openssl/Configurations/descrip.mms.tmpl +@@ -0,0 +1,767 @@ ++## descrip.mms to build OpenSSL on OpenVMS ++## ++## {- join("\n## ", @autowarntext) -} ++{- ++ use File::Spec::Functions qw/:DEFAULT abs2rel rel2abs/; ++ ++ # Our prefix, claimed when speaking with the VSI folks Tuesday ++ # January 26th 2016 ++ our $osslprefix = 'OSSL$'; ++ (our $osslprefix_q = $osslprefix) =~ s/\$/\\\$/; ++ ++ our $sover = sprintf "%02d%02d", $config{shlib_major}, $config{shlib_minor}; ++ our $osslver = sprintf "%02d%02d", split(/\./, $config{version}); ++ ++ our $sourcedir = $config{sourcedir}; ++ our $builddir = $config{builddir}; ++ sub sourcefile { ++ catfile($sourcedir, @_); ++ } ++ sub buildfile { ++ catfile($builddir, @_); ++ } ++ sub sourcedir { ++ catdir($sourcedir, @_); ++ } ++ sub builddir { ++ catdir($builddir, @_); ++ } ++ sub tree { ++ (my $x = shift) =~ s|\]$|...]|; ++ $x ++ } ++ sub move { ++ my $f = catdir(@_); ++ my $b = abs2rel(rel2abs("."),rel2abs($f)); ++ $sourcedir = catdir($b,$sourcedir) ++ if !file_name_is_absolute($sourcedir); ++ $builddir = catdir($b,$builddir) ++ if !file_name_is_absolute($builddir); ++ ""; ++ } ++ ++ # Because we need to make two computations of these data, ++ # we store them in arrays for reuse ++ our @shlibs = map { $unified_info{sharednames}->{$_} || () } @{$unified_info{libraries}}; ++ our @install_shlibs = map { $unified_info{sharednames}->{$_} || () } @{$unified_info{install}->{libraries}}; ++ our @generated = ( ( map { (my $x = $_) =~ s|\.S$|\.s|; $x } ++ grep { defined $unified_info{generate}->{$_} } ++ map { @{$unified_info{sources}->{$_}} } ++ grep { /\.o$/ } keys %{$unified_info{sources}} ), ++ ( grep { /\.h$/ } keys %{$unified_info{generate}} ) ); ++ ++ # This is a horrible hack, but is needed because recursive inclusion of files ++ # in different directories does not work well with HP C. ++ my $sd = sourcedir("crypto", "async", "arch"); ++ foreach (grep /\[\.crypto\.async\.arch\].*\.o$/, keys %{$unified_info{sources}}) { ++ (my $x = $_) =~ s|\.o$|.OBJ|; ++ $unified_info{before}->{$x} ++ = qq(arch_include = F\$PARSE("$sd","A.;",,,"SYNTAX_ONLY") - "A.;" ++ define arch 'arch_include'); ++ $unified_info{after}->{$x} ++ = qq(deassign arch); ++ } ++ my $sd1 = sourcedir("ssl","record"); ++ my $sd2 = sourcedir("ssl","statem"); ++ $unified_info{before}->{"[.test]heartbeat_test.OBJ"} ++ = $unified_info{before}->{"[.test]ssltest_old.OBJ"} ++ = qq(record_include = F\$PARSE("$sd1","A.;",,,"SYNTAX_ONLY") - "A.;" ++ define record 'record_include' ++ statem_include = F\$PARSE("$sd2","A.;",,,"SYNTAX_ONLY") - "A.;" ++ define statem 'statem_include'); ++ $unified_info{after}->{"[.test]heartbeat_test.OBJ"} ++ = $unified_info{after}->{"[.test]ssltest.OBJ"} ++ = qq(deassign statem ++ deassign record); ++ foreach (grep /^\[\.ssl\.(?:record|statem)\].*\.o$/, keys %{$unified_info{sources}}) { ++ (my $x = $_) =~ s|\.o$|.OBJ|; ++ $unified_info{before}->{$x} ++ = qq(record_include = F\$PARSE("$sd1","A.;",,,"SYNTAX_ONLY") - "A.;" ++ define record 'record_include' ++ statem_include = F\$PARSE("$sd2","A.;",,,"SYNTAX_ONLY") - "A.;" ++ define statem 'statem_include'); ++ $unified_info{after}->{$x} ++ = qq(deassign statem ++ deassign record); ++ } ++ #use Data::Dumper; ++ #print STDERR "DEBUG: before:\n", Dumper($unified_info{before}); ++ #print STDERR "DEBUG: after:\n", Dumper($unified_info{after}); ++ ""; ++-} ++PLATFORM={- $config{target} -} ++OPTIONS={- $config{options} -} ++CONFIGURE_ARGS=({- join(", ",quotify_l(@{$config{perlargv}})) -}) ++SRCDIR={- $config{sourcedir} -} ++BLDDIR={- $config{builddir} -} ++ ++# Allow both V and VERBOSE to indicate verbosity. This only applies ++# to testing. ++VERBOSE=$(V) ++ ++VERSION={- $config{version} -} ++MAJOR={- $config{major} -} ++MINOR={- $config{minor} -} ++SHLIB_VERSION_NUMBER={- $config{shlib_version_number} -} ++SHLIB_VERSION_HISTORY={- $config{shlib_version_history} -} ++SHLIB_MAJOR={- $config{shlib_major} -} ++SHLIB_MINOR={- $config{shlib_minor} -} ++SHLIB_TARGET={- $target{shared_target} -} ++ ++EXE_EXT=.EXE ++LIB_EXT=.OLB ++SHLIB_EXT=.EXE ++OBJ_EXT=.OBJ ++DEP_EXT=.D ++ ++LIBS={- join(", ", map { "-\n\t".$_.".OLB" } @{$unified_info{libraries}}) -} ++SHLIBS={- join(", ", map { "-\n\t".$_.".EXE" } @shlibs) -} ++ENGINES={- join(", ", map { "-\n\t".$_.".EXE" } @{$unified_info{engines}}) -} ++PROGRAMS={- join(", ", map { "-\n\t".$_.".EXE" } @{$unified_info{programs}}) -} ++SCRIPTS={- join(", ", map { "-\n\t".$_ } @{$unified_info{scripts}}) -} ++{- output_off() if $disabled{makedepend}; "" -} ++DEPS={- our @deps = map { (my $x = $_) =~ s|\.o$|\$(DEP_EXT)|; $x; } ++ grep { $unified_info{sources}->{$_}->[0] =~ /\.c$/ } ++ keys %{$unified_info{sources}}; ++ join(", ", map { "-\n\t".$_ } @deps); -} ++{- output_on() if $disabled{makedepend}; "" -} ++GENERATED_MANDATORY={- join(", ", map { "-\n\t".$_ } @{$unified_info{depends}->{""}} ) -} ++GENERATED={- join(", ", map { "-\n\t".$_ } @generated) -} ++ ++INSTALL_LIBS={- join(", ", map { "-\n\t".$_.".OLB" } @{$unified_info{install}->{libraries}}) -} ++INSTALL_SHLIBS={- join(", ", map { "-\n\t".$_.".EXE" } @install_shlibs) -} ++INSTALL_ENGINES={- join(", ", map { "-\n\t".$_.".EXE" } @{$unified_info{install}->{engines}}) -} ++INSTALL_PROGRAMS={- join(", ", map { "-\n\t".$_.".EXE" } @{$unified_info{install}->{programs}}) -} ++{- output_off() if $disabled{apps}; "" -} ++BIN_SCRIPTS=[.tools]c_rehash.pl ++MISC_SCRIPTS=[.apps]CA.pl, [.apps]tsget.pl ++{- output_on() if $disabled{apps}; "" -} ++ ++# DESTDIR is for package builders so that they can configure for, say, ++# SYS$COMMON:[OPENSSL] and yet have everything installed in STAGING:[USER]. ++# In that case, configure with --prefix=SYS$COMMON:[OPENSSL] and then run ++# MMS with /MACROS=(DESTDIR=STAGING:[USER]). The result will end up in ++# STAGING:[USER.OPENSSL]. ++# Normally it is left empty. ++DESTDIR= ++ ++# Do not edit this manually. Use Configure --prefix=DIR to change this! ++INSTALLTOP={- our $installtop = ++ catdir($config{prefix}) || "SYS\$COMMON:[OPENSSL]"; ++ $installtop -} ++SYSTARTUP={- catdir($installtop, '[.SYS$STARTUP]'); -} ++# This is the standard central area to store certificates, private keys... ++OPENSSLDIR={- catdir($config{openssldir}) or ++ $config{prefix} ? catdir($config{prefix},"COMMON") ++ : "SYS\$COMMON:[OPENSSL-COMMON]" -} ++# The same, but for C ++OPENSSLDIR_C={- $osslprefix -}DATAROOT:[000000] ++# Where installed engines reside, for C ++ENGINESDIR_C={- $osslprefix -}ENGINES{- $sover.$target{pointer_size} -}: ++ ++CC= {- $target{cc} -} ++CFLAGS= /DEFINE=({- join(",", @{$target{defines}}, @{$config{defines}},"OPENSSLDIR=\"\"\"\$(OPENSSLDIR_C)\"\"\"","ENGINESDIR=\"\"\"\$(ENGINESDIR_C)\"\"\"") -}) {- $target{cflags} -} {- $config{cflags} -} ++CFLAGS_Q=$(CFLAGS) ++DEPFLAG= /DEFINE=({- join(",", @{$config{depdefines}}) -}) ++LDFLAGS= {- $target{lflags} -} ++EX_LIBS= {- $target{ex_libs} ? ",".$target{ex_libs} : "" -}{- $config{ex_libs} ? ",".$config{ex_libs} : "" -} ++LIB_CFLAGS={- $target{lib_cflags} || "" -} ++DSO_CFLAGS={- $target{dso_cflags} || "" -} ++BIN_CFLAGS={- $target{bin_cflags} || "" -} ++ ++PERL={- $config{perl} -} ++ ++# We let the C compiler driver to take care of .s files. This is done in ++# order to be excused from maintaining a separate set of architecture ++# dependent assembler flags. E.g. if you throw -mcpu=ultrasparc at SPARC ++# gcc, then the driver will automatically translate it to -xarch=v8plus ++# and pass it down to assembler. ++AS={- $target{as} -} ++ASFLAG={- $target{asflags} -} ++ ++# .FIRST and .LAST are special targets with MMS and MMK. ++# The defines in there are for C. includes that look like ++# this: ++# ++# #include ++# #include "internal/bar.h" ++# ++# will use the logical names to find the files. Expecting ++# DECompHP C to find files in subdirectories of whatever was ++# given with /INCLUDE is a fantasy, unfortunately. ++NODEBUG=@ ++.FIRST : ++ $(NODEBUG) openssl_inc1 = F$PARSE("[.include.openssl]","A.;",,,"syntax_only") - "A.;" ++ $(NODEBUG) openssl_inc2 = F$PARSE("{- catdir($config{sourcedir},"[.include.openssl]") -}","A.;",,,"SYNTAX_ONLY") - "A.;" ++ $(NODEBUG) internal_inc1 = F$PARSE("[.crypto.include.internal]","A.;",,,"SYNTAX_ONLY") - "A.;" ++ $(NODEBUG) internal_inc2 = F$PARSE("{- catdir($config{sourcedir},"[.include.internal]") -}","A.;",,,"SYNTAX_ONLY") - "A.;" ++ $(NODEBUG) internal_inc3 = F$PARSE("{- catdir($config{sourcedir},"[.crypto.include.internal]") -}","A.;",,,"SYNTAX_ONLY") - "A.;" ++ $(NODEBUG) DEFINE openssl 'openssl_inc1','openssl_inc2' ++ $(NODEBUG) DEFINE internal 'internal_inc1','internal_inc2','internal_inc3' ++ $(NODEBUG) staging_dir = "$(DESTDIR)" ++ $(NODEBUG) staging_instdir = "" ++ $(NODEBUG) staging_datadir = "" ++ $(NODEBUG) IF staging_dir .NES. "" THEN - ++ staging_instdir = F$PARSE("A.;",staging_dir,"[]",,"SYNTAX_ONLY") ++ $(NODEBUG) IF staging_instdir - "]A.;" .NES. staging_instdir THEN - ++ staging_instdir = staging_instdir - "]A.;" + ".OPENSSL-INSTALL]" ++ $(NODEBUG) IF staging_instdir - "A.;" .NES. staging_instdir THEN - ++ staging_instdir = staging_instdir - "A.;" + "[OPENSSL-INSTALL]" ++ $(NODEBUG) IF staging_dir .NES. "" THEN - ++ staging_datadir = F$PARSE("A.;",staging_dir,"[]",,"SYNTAX_ONLY") ++ $(NODEBUG) IF staging_datadir - "]A.;" .NES. staging_datadir THEN - ++ staging_datadir = staging_datadir - "]A.;" + ".OPENSSL-COMMON]" ++ $(NODEBUG) IF staging_datadir - "A.;" .NES. staging_datadir THEN - ++ staging_datadir = staging_datadir - "A.;" + "[OPENSSL-COMMON]" ++ $(NODEBUG) ! ++ $(NODEBUG) ! Installation logical names ++ $(NODEBUG) ! ++ $(NODEBUG) installtop = F$PARSE(staging_instdir,"$(INSTALLTOP)","[]A.;",,"SYNTAX_ONLY,NO_CONCEAL") - ".][000000" - "[000000." - "][" - "]A.;" + ".]" ++ $(NODEBUG) datatop = F$PARSE(staging_datadir,"$(OPENSSLDIR)","[]A.;",,"SYNTAX_ONLY,NO_CONCEAL") - ".][000000" - "[000000." - "][" - "]A.;" + ".]" ++ $(NODEBUG) DEFINE ossl_installroot 'installtop' ++ $(NODEBUG) DEFINE ossl_dataroot 'datatop' ++ $(NODEBUG) ! ++ $(NODEBUG) ! Figure out the architecture ++ $(NODEBUG) ! ++ $(NODEBUG) arch = f$edit( f$getsyi( "arch_name"), "upcase") ++ $(NODEBUG) ! ++ $(NODEBUG) ! Set up logical names for the libraries, so LINK and ++ $(NODEBUG) ! running programs can use them. ++ $(NODEBUG) ! ++ $(NODEBUG) {- join("\n\t\$(NODEBUG) ", map { "DEFINE ".uc($_)." 'F\$ENV(\"DEFAULT\")'".uc($_)."\$(SHLIB_EXT)" } map { $unified_info{sharednames}->{$_} || () } @{$unified_info{libraries}}) || "!" -} ++ ++.LAST : ++ $(NODEBUG) {- join("\n\t\$(NODEBUG) ", map { "DEASSIGN ".uc($_) } map { $unified_info{sharednames}->{$_} || () } @{$unified_info{libraries}}) || "!" -} ++ $(NODEBUG) DEASSIGN ossl_dataroot ++ $(NODEBUG) DEASSIGN ossl_installroot ++ $(NODEBUG) DEASSIGN internal ++ $(NODEBUG) DEASSIGN openssl ++.DEFAULT : ++ @ ! MMS cannot handle no actions... ++ ++# The main targets ################################################### ++ ++all : build_generated, - ++ build_libs_nodep, build_engines_nodep, build_programs_nodep, - ++ depend ++ ++build_libs : build_generated, build_libs_nodep, depend ++build_libs_nodep : $(LIBS), $(SHLIBS) ++build_engines : build_generated, build_engines_nodep, depend ++build_engines_nodep : $(ENGINES) ++build_programs : build_generated, build_programs_nodep, depend ++build_programs_nodep : $(PROGRAMS), $(SCRIPTS) ++ ++build_generated : $(GENERATED_MANDATORY) ++ ++# Kept around for backward compatibility ++build_apps build_tests : build_programs ++ ++test tests : build_generated, build_programs_nodep, build_engines_nodep, - ++ depend ++ @ ! {- output_off() if $disabled{tests}; "" -} ++ SET DEFAULT [.test]{- move("test") -} ++ DEFINE SRCTOP {- sourcedir() -} ++ DEFINE BLDTOP {- builddir() -} ++ DEFINE OPENSSL_ENGINES {- builddir("engines") -} ++ DEFINE OPENSSL_DEBUG_MEMORY "on" ++ IF "$(VERBOSE)" .NES. "" THEN DEFINE VERBOSE "$(VERBOSE)" ++ $(PERL) {- sourcefile("test", "run_tests.pl") -} $(TESTS) ++ DEASSIGN OPENSSL_DEBUG_MEMORY ++ DEASSIGN OPENSSL_ENGINES ++ DEASSIGN BLDTOP ++ DEASSIGN SRCTOP ++ SET DEFAULT [-]{- move("..") -} ++ @ ! {- if ($disabled{tests}) { output_on(); } else { output_off(); } "" -} ++ @ WRITE SYS$OUTPUT "Tests are not supported with your chosen Configure options" ++ @ ! {- output_on() if !$disabled{tests}; "" -} ++ ++list-tests : ++ @ ! {- output_off() if $disabled{tests}; "" -} ++ @ DEFINE SRCTOP {- sourcedir() -} ++ @ $(PERL) {- sourcefile("test", "run_tests.pl") -} list ++ @ DEASSIGN SRCTOP ++ @ ! {- if ($disabled{tests}) { output_on(); } else { output_off(); } "" -} ++ @ WRITE SYS$OUTPUT "Tests are not supported with your chosen Configure options" ++ @ ! {- output_on() if !$disabled{tests}; "" -} ++ ++install : install_sw install_ssldirs install_docs ++ @ WRITE SYS$OUTPUT "" ++ @ WRITE SYS$OUTPUT "######################################################################" ++ @ WRITE SYS$OUTPUT "" ++ @ IF "$(DESTDIR)" .EQS. "" THEN - ++ PIPE ( WRITE SYS$OUTPUT "Installation complete" ; - ++ WRITE SYS$OUTPUT "" ; - ++ WRITE SYS$OUTPUT "Run @$(SYSTARTUP)openssl_startup{- $osslver -} to set up logical names" ; - ++ WRITE SYS$OUTPUT "then run @$(SYSTARTUP)openssl_utils{- $osslver -} to define commands" ; - ++ WRITE SYS$OUTPUT "" ) ++ @ IF "$(DESTDIR)" .NES. "" THEN - ++ PIPE ( WRITE SYS$OUTPUT "Staging installation complete" ; - ++ WRITE SYS$OUTPUT "" ; - ++ WRITE SYS$OUTPUT "Finish or package in such a way that the contents of the directory tree" ; - ++ WRITE SYS$OUTPUT staging_instdir ; - ++ WRITE SYS$OUTPUT "ends up in $(INSTALLTOP)," ; - ++ WRITE SYS$OUTPUT "and that the contents of the contents of the directory tree" ; - ++ WRITE SYS$OUTPUT staging_datadir ; - ++ WRITE SYS$OUTPUT "ends up in $(OPENSSLDIR)" ; - ++ WRITE SYS$OUTPUT "" ; - ++ WRITE SYS$OUTPUT "When in its final destination," ; - ++ WRITE SYS$OUTPUT "Run @$(SYSTARTUP)openssl_startup{- $osslver -} to set up logical names" ; - ++ WRITE SYS$OUTPUT "then run @$(SYSTARTUP)openssl_utils{- $osslver -} to define commands" ; - ++ WRITE SYS$OUTPUT "" ) ++ ++check_install : ++ spawn/nolog @ossl_installroot:[SYSTEST]openssl_ivp{- $osslver -}.com ++ ++uninstall : uninstall_docs uninstall_sw ++ ++# Because VMS wants the generation number (or *) to delete files, we can't ++# use $(LIBS), $(PROGRAMS), $(GENERATED) and $(ENGINES)directly. ++libclean : ++ {- join("\n\t", map { "- DELETE $_.OLB;*" } @{$unified_info{libraries}}) || "@ !" -} ++ {- join("\n\t", map { "- DELETE $_.EXE;*,$_.MAP;*,$_.OPT;*" } @shlibs) || "@ !" -} ++ ++clean : libclean ++ {- join("\n\t", map { "- DELETE $_.EXE;*,$_.OPT;*" } @{$unified_info{programs}}) || "@ !" -} ++ {- join("\n\t", map { "- DELETE $_.EXE;*,$_.OPT;*" } @{$unified_info{engines}}) || "@ !" -} ++ {- join("\n\t", map { "- DELETE $_;*" } @{$unified_info{scripts}}) || "@ !" -} ++ {- join("\n\t", map { "- DELETE $_;*" } @generated) || "@ !" -} ++ - DELETE [...]*.MAP;* ++ - DELETE [...]*.D;* ++ - DELETE [...]*.OBJ;*,*.LIS;* ++ - DELETE []CXX$DEMANGLER_DB.;* ++ - DELETE [.VMS]openssl_startup.com;* ++ - DELETE [.VMS]openssl_shutdown.com;* ++ - DELETE []vmsconfig.pm;* ++ ++distclean : clean ++ - DELETE configdata.pm;* ++ - DELETE descrip.mms;* ++ ++depend : descrip.mms ++descrip.mms : FORCE ++ @ ! {- output_off() if $disabled{makedepend}; "" -} ++ @ $(PERL) -pe "if (/^# DO NOT DELETE.*/) { exit(0); }" - ++ < descrip.mms > descrip.mms-new ++ @ OPEN/APPEND DESCRIP descrip.mms-new ++ @ WRITE DESCRIP "# DO NOT DELETE THIS LINE -- make depend depends on it." ++ {- join("\n\t", map { "\@ IF F\$SEARCH(\"$_\") .NES. \"\" THEN TYPE $_ /OUTPUT=DESCRIP:" } @deps); -} ++ @ CLOSE DESCRIP ++ @ PIPE ( $(PERL) -e "use File::Compare qw/compare_text/; my $x = compare_text(""descrip.mms"",""descrip.mms-new""); exit(0x10000000 + ($x == 0));" || - ++ RENAME descrip.mms-new descrip.mms ) ++ @ IF F$SEARCH("descrip.mms-new") .NES. "" THEN DELETE descrip.mms-new;* ++ -@ SPAWN/OUTPUT=NLA0: PURGE/NOLOG descrip.mms ++ @ ! {- output_on() if $disabled{makedepend}; "" -} ++ ++# Install helper targets ############################################# ++ ++install_sw : all install_shared _install_dev_ns - ++ install_engines _install_runtime_ns - ++ install_startup install_ivp ++ ++uninstall_sw : uninstall_shared _uninstall_dev_ns - ++ uninstall_engines _uninstall_runtime_ns - ++ uninstall_startup uninstall_ivp ++ ++install_docs : install_html_docs ++ ++uninstall_docs : uninstall_html_docs ++ ++install_ssldirs : check_INSTALLTOP ++ - CREATE/DIR/PROT=(S:RWED,O:RWE,G:RE,W:RE) OSSL_DATAROOT:[000000] ++ IF F$SEARCH("OSSL_DATAROOT:[000000]CERTS.DIR;1") .EQS. "" THEN - ++ CREATE/DIR/PROT=(S:RWED,O:RWE,G:RE,W:RE) OSSL_DATAROOT:[CERTS] ++ IF F$SEARCH("OSSL_DATAROOT:[000000]PRIVATE.DIR;1") .EQS. "" THEN - ++ CREATE/DIR/PROT=(S:RWED,O:RWE,G,W) OSSL_DATAROOT:[PRIVATE] ++ IF F$SEARCH("OSSL_DATAROOT:[000000]MISC.DIR;1") .EQS. "" THEN - ++ CREATE/DIR/PROT=(S:RWED,O:RWE,G,W) OSSL_DATAROOT:[MISC] ++ COPY/PROT=W:RE $(MISC_SCRIPTS) OSSL_DATAROOT:[MISC] ++ @ ! Install configuration file ++ COPY/PROT=W:R {- sourcefile("apps", "openssl-vms.cnf") -} - ++ ossl_dataroot:[000000]openssl.cnf-dist ++ IF F$SEARCH("OSSL_DATAROOT:[000000]openssl.cnf") .EQS. "" THEN - ++ COPY/PROT=W:R {- sourcefile("apps", "openssl-vms.cnf") -} - ++ ossl_dataroot:[000000]openssl.cnf ++ ++install_shared : check_INSTALLTOP ++ @ {- output_off() if $disabled{shared}; "" -} ! ++ @ WRITE SYS$OUTPUT "*** Installing shareable images" ++ @ ! Install shared (runtime) libraries ++ - CREATE/DIR ossl_installroot:[LIB.'arch'] ++ {- join("\n ", ++ map { "COPY/PROT=W:R $_.EXE ossl_installroot:[LIB.'arch']" } ++ @install_shlibs) -} ++ @ {- output_on() if $disabled{shared}; "" -} ! ++ ++_install_dev_ns : check_INSTALLTOP ++ @ WRITE SYS$OUTPUT "*** Installing development files" ++ @ ! Install header files ++ - CREATE/DIR ossl_installroot:[include.openssl] ++ COPY/PROT=W:R openssl:*.h ossl_installroot:[include.openssl] ++ @ ! Install static (development) libraries ++ - CREATE/DIR ossl_installroot:[LIB.'arch'] ++ {- join("\n ", ++ map { "COPY/PROT=W:R $_.OLB ossl_installroot:[LIB.'arch']" } ++ @{$unified_info{install}->{libraries}}) -} ++ ++install_dev : install_shared _install_dev_ns ++ ++_install_runtime_ns : check_INSTALLTOP ++ @ ! Install the main program ++ - CREATE/DIR ossl_installroot:[EXE.'arch'] ++ COPY/PROT=W:RE [.APPS]openssl.EXE - ++ ossl_installroot:[EXE.'arch']openssl{- $osslver -}.EXE ++ @ ! Install scripts ++ COPY/PROT=W:RE $(BIN_SCRIPTS) ossl_installroot:[EXE] ++ @ ! {- output_on() if $disabled{apps}; "" -} ++ ++install_runtime : install_shared _install_runtime_ns ++ ++install_engines : check_INSTALLTOP ++ @ {- output_off() unless scalar @{$unified_info{engines}}; "" -} ! ++ @ WRITE SYS$OUTPUT "*** Installing engines" ++ - CREATE/DIR ossl_installroot:[ENGINES{- $sover.$target{pointer_size} -}.'arch'] ++ {- join("\n ", ++ map { "COPY/PROT=W:RE $_.EXE ossl_installroot:[ENGINES$sover$target{pointer_size}.'arch']" } ++ @{$unified_info{install}->{engines}}) -} ++ @ {- output_on() unless scalar @{$unified_info{engines}}; "" -} ! ++ ++install_startup : [.VMS]openssl_startup.com [.VMS]openssl_shutdown.com - ++ [.VMS]openssl_utils.com, check_INSTALLTOP ++ - CREATE/DIR ossl_installroot:[SYS$STARTUP] ++ COPY/PROT=W:RE [.VMS]openssl_startup.com - ++ ossl_installroot:[SYS$STARTUP]openssl_startup{- $osslver -}.com ++ COPY/PROT=W:RE [.VMS]openssl_shutdown.com - ++ ossl_installroot:[SYS$STARTUP]openssl_shutdown{- $osslver -}.com ++ COPY/PROT=W:RE [.VMS]openssl_utils.com - ++ ossl_installroot:[SYS$STARTUP]openssl_utils{- $osslver -}.com ++ ++install_ivp : [.VMS]openssl_ivp.com check_INSTALLTOP ++ - CREATE/DIR ossl_installroot:[SYSTEST] ++ COPY/PROT=W:RE [.VMS]openssl_ivp.com - ++ ossl_installroot:[SYSTEST]openssl_ivp{- $osslver -}.com ++ ++[.VMS]openssl_startup.com : vmsconfig.pm {- sourcefile("VMS", "openssl_startup.com.in") -} ++ - CREATE/DIR [.VMS] ++ $(PERL) "-I." "-Mvmsconfig" {- sourcefile("util", "dofile.pl") -} - ++ {- sourcefile("VMS", "openssl_startup.com.in") -} - ++ > [.VMS]openssl_startup.com ++ ++[.VMS]openssl_utils.com : vmsconfig.pm {- sourcefile("VMS", "openssl_utils.com.in") -} ++ - CREATE/DIR [.VMS] ++ $(PERL) "-I." "-Mvmsconfig" {- sourcefile("util", "dofile.pl") -} - ++ {- sourcefile("VMS", "openssl_utils.com.in") -} - ++ > [.VMS]openssl_utils.com ++ ++[.VMS]openssl_shutdown.com : vmsconfig.pm {- sourcefile("VMS", "openssl_shutdown.com.in") -} ++ - CREATE/DIR [.VMS] ++ $(PERL) "-I." "-Mvmsconfig" {- sourcefile("util", "dofile.pl") -} - ++ {- sourcefile("VMS", "openssl_shutdown.com.in") -} - ++ > [.VMS]openssl_shutdown.com ++ ++[.VMS]openssl_ivp.com : vmsconfig.pm {- sourcefile("VMS", "openssl_ivp.com.in") -} ++ - CREATE/DIR [.VMS] ++ $(PERL) "-I." "-Mvmsconfig" {- sourcefile("util", "dofile.pl") -} - ++ {- sourcefile("VMS", "openssl_ivp.com.in") -} - ++ > [.VMS]openssl_ivp.com ++ ++vmsconfig.pm : configdata.pm ++ OPEN/WRITE/SHARE=READ CONFIG []vmsconfig.pm ++ WRITE CONFIG "package vmsconfig;" ++ WRITE CONFIG "use strict; use warnings;" ++ WRITE CONFIG "use Exporter;" ++ WRITE CONFIG "our @ISA = qw(Exporter);" ++ WRITE CONFIG "our @EXPORT = qw(%config %target %withargs %unified_info %disabled);" ++ WRITE CONFIG "our %config = (" ++ WRITE CONFIG " target => '","{- $config{target} -}","'," ++ WRITE CONFIG " version => '","{- $config{version} -}","'," ++ WRITE CONFIG " shlib_major => '","{- $config{shlib_major} -}","'," ++ WRITE CONFIG " shlib_minor => '","{- $config{shlib_minor} -}","'," ++ WRITE CONFIG " no_shared => '","{- $disabled{shared} -}","'," ++ WRITE CONFIG " INSTALLTOP => '$(INSTALLTOP)'," ++ WRITE CONFIG " OPENSSLDIR => '$(OPENSSLDIR)'," ++ WRITE CONFIG " pointer_size => '","{- $target{pointer_size} -}","'," ++ WRITE CONFIG ");" ++ WRITE CONFIG "our %target = ();" ++ WRITE CONFIG "our %disabled = ();" ++ WRITE CONFIG "our %withargs = ();" ++ WRITE CONFIG "our %unified_info = ();" ++ WRITE CONFIG "1;" ++ CLOSE CONFIG ++ ++install_html_docs : check_INSTALLTOP ++ sourcedir = F$PARSE("{- $sourcedir -}A.;","[]") - "]A.;" + ".DOC]" ++ $(PERL) {- sourcefile("util", "process_docs.pl") -} - ++ --sourcedir='sourcedir' --destdir=ossl_installroot:[HTML] - ++ --type=html ++ ++check_INSTALLTOP : ++ @ IF "$(INSTALLTOP)" .EQS. "" THEN - ++ WRITE SYS$ERROR "INSTALLTOP should not be empty" ++ @ IF "$(INSTALLTOP)" .EQS. "" THEN - ++ EXIT %x10000002 ++ ++# Helper targets ##################################################### ++ ++# Developer targets ################################################## ++ ++debug_logicals : ++ SH LOGICAL/PROC openssl,internal,ossl_installroot,ossl_dataroot ++ ++# Building targets ################################################### ++ ++configdata.pm : $(SRCDIR)Configure $(SRCDIR)config.com {- join(" ", @{$config{build_file_templates}}, @{$config{build_infos}}, @{$config{conf_files}}) -} ++ @ WRITE SYS$OUTPUT "Reconfiguring..." ++ perl $(SRCDIR)Configure reconf ++ @ WRITE SYS$OUTPUT "*************************************************" ++ @ WRITE SYS$OUTPUT "*** ***" ++ @ WRITE SYS$OUTPUT "*** Please run the same mms command again ***" ++ @ WRITE SYS$OUTPUT "*** ***" ++ @ WRITE SYS$OUTPUT "*************************************************" ++ @ PIPE ( EXIT %X10000000 ) ++ ++{- ++ use File::Basename; ++ use File::Spec::Functions qw/abs2rel rel2abs catfile catdir/; ++ ++ sub generatesrc { ++ my %args = @_; ++ my $generator = join(" ", @{$args{generator}}); ++ my $generator_incs = join("", map { ' "-I'.$_.'"' } @{$args{generator_incs}}); ++ my $deps = join(", -\n\t\t", @{$args{generator_deps}}, @{$args{deps}}); ++ ++ if ($args{src} !~ /\.[sS]$/) { ++ if ($args{generator}->[0] =~ m|^.*\.in$|) { ++ my $dofile = abs2rel(rel2abs(catfile($config{sourcedir}, ++ "util", "dofile.pl")), ++ rel2abs($config{builddir})); ++ return <<"EOF"; ++$args{src} : $args{generator}->[0] $deps ++ \$(PERL) "-I\$(BLDDIR)" "-Mconfigdata" $dofile \\ ++ "-o$target{build_file}" $generator > \$@ ++EOF ++ } else { ++ return <<"EOF"; ++$args{src} : $args{generator}->[0] $deps ++ \$(PERL)$generator_incs $generator > \$@ ++EOF ++ } ++ } else { ++ die "No method to generate assembler source present.\n"; ++ } ++ } ++ ++ sub src2obj { ++ my %args = @_; ++ my $obj = $args{obj}; ++ my $deps = join(", -\n\t\t", @{$args{srcs}}, @{$args{deps}}); ++ ++ # Because VMS C isn't very good at combining a /INCLUDE path with ++ # #includes having a relative directory (like '#include "../foo.h"), ++ # the best choice is to move to the first source file's intended ++ # directory before compiling, and make sure to write the object file ++ # in the correct position (important when the object tree is other ++ # than the source tree). ++ my $forward = dirname($args{srcs}->[0]); ++ my $backward = abs2rel(rel2abs("."), rel2abs($forward)); ++ my $objd = abs2rel(rel2abs(dirname($obj)), rel2abs($forward)); ++ my $objn = basename($obj); ++ my $srcs = ++ join(", ", ++ map { abs2rel(rel2abs($_), rel2abs($forward)) } @{$args{srcs}}); ++ my $ecflags = { lib => '$(LIB_CFLAGS)', ++ dso => '$(DSO_CFLAGS)', ++ bin => '$(BIN_CFLAGS)' } -> {$args{intent}}; ++ my $incs_on = "\@ !"; ++ my $incs_off = "\@ !"; ++ my $incs = ""; ++ my @incs = (); ++ push @incs, @{$args{incs}} if @{$args{incs}}; ++ unless ($disabled{zlib}) { ++ # GNV$ZLIB_INCLUDE is the standard logical name for later zlib ++ # incarnations. ++ push @incs, ($withargs{zlib_include} || 'GNV$ZLIB_INCLUDE:'); ++ } ++ if (@incs) { ++ $incs_on = ++ "DEFINE tmp_includes " ++ .join(",-\n\t\t\t", map { ++ file_name_is_absolute($_) ++ ? $_ : catdir($backward,$_) ++ } @incs); ++ $incs_off = "DEASSIGN tmp_includes"; ++ $incs = " /INCLUDE=(tmp_includes:)"; ++ } ++ my $before = $unified_info{before}->{$obj.".OBJ"} || "\@ !"; ++ my $after = $unified_info{after}->{$obj.".OBJ"} || "\@ !"; ++ my $depbuild = $disabled{makedepend} ? "" ++ : " /MMS=(FILE=${objd}${objn}.tmp-D,TARGET=$obj.OBJ)"; ++ ++ return <<"EOF"; ++$obj.OBJ : $deps ++ ${before} ++ SET DEFAULT $forward ++ $incs_on ++ \$(CC) \$(CFLAGS)${ecflags}${incs}${depbuild} /OBJECT=${objd}${objn}.OBJ /REPOSITORY=$backward $srcs ++ $incs_off ++ SET DEFAULT $backward ++ ${after} ++ \@ PIPE ( \$(PERL) -e "use File::Compare qw/compare_text/; my \$x = compare_text(""$obj.D"",""$obj.tmp-D""); exit(0x10000000 + (\$x == 0));" || - ++ RENAME $obj.tmp-D $obj.d ) ++ \@ IF F\$SEARCH("$obj.tmp-D") .NES. "" THEN DELETE $obj.tmp-D;* ++ - PURGE $obj.OBJ ++EOF ++ } ++ sub libobj2shlib { ++ my %args = @_; ++ my $lib = $args{lib}; ++ my $shlib = $args{shlib}; ++ my $libd = dirname($lib); ++ my $libn = basename($lib); ++ (my $mkdef_key = $libn) =~ s/^${osslprefix_q}lib([^0-9]*)\d*/$1/i; ++ my @deps = map { ++ $disabled{shared} ? $_.".OLB" ++ : $unified_info{sharednames}->{$_}.".EXE"; } @{$args{deps}}; ++ my $deps = join(", -\n\t\t", @deps); ++ my $shlib_target = $disabled{shared} ? "" : $target{shared_target}; ++ my $ordinalsfile = defined($args{ordinals}) ? $args{ordinals}->[1] : ""; ++ my $engine_opt = abs2rel(rel2abs(catfile($config{sourcedir}, ++ "VMS", "engine.opt")), ++ rel2abs($config{builddir})); ++ my $mkdef_pl = abs2rel(rel2abs(catfile($config{sourcedir}, ++ "util", "mkdef.pl")), ++ rel2abs($config{builddir})); ++ my $translatesyms_pl = abs2rel(rel2abs(catfile($config{sourcedir}, ++ "VMS", "translatesyms.pl")), ++ rel2abs($config{builddir})); ++ # The "[]" hack is because in .OPT files, each line inherits the ++ # previous line's file spec as default, so if no directory spec ++ # is present in the current line and the previous line has one that ++ # doesn't apply, you're in for a surprise. ++ my $write_opt = ++ join("\n\t", map { my $x = $_ =~ /\[/ ? $_ : "[]".$_; ++ $x =~ s|(\.EXE)|$1/SHARE|; ++ $x =~ s|(\.OLB)|$1/LIB|; ++ "WRITE OPT_FILE \"$x\"" } @deps) ++ || "\@ !"; ++ return <<"EOF"; ++$shlib.EXE : $lib.OLB $deps $ordinalsfile ++ \$(PERL) $mkdef_pl "$mkdef_key" "VMS" > $shlib.SYMVEC-tmp ++ \$(PERL) $translatesyms_pl \$(BLDDIR)CXX\$DEMANGLER_DB. < $shlib.SYMVEC-tmp > $shlib.SYMVEC ++ DELETE $shlib.SYMVEC-tmp;* ++ OPEN/WRITE/SHARE=READ OPT_FILE $shlib.OPT ++ WRITE OPT_FILE "IDENTIFICATION=""V$config{version}""" ++ TYPE $shlib.SYMVEC /OUTPUT=OPT_FILE: ++ WRITE OPT_FILE "$lib.OLB/LIBRARY" ++ $write_opt ++ CLOSE OPT_FILE ++ LINK /MAP=$shlib.MAP /FULL/SHARE=$shlib.EXE $shlib.OPT/OPT \$(EX_LIBS) ++ DELETE $shlib.SYMVEC;* ++ PURGE $shlib.EXE,$shlib.OPT,$shlib.MAP ++EOF ++ } ++ sub obj2dso { ++ my %args = @_; ++ my $lib = $args{lib}; ++ my $libd = dirname($lib); ++ my $libn = basename($lib); ++ (my $libn_nolib = $libn) =~ s/^lib//; ++ my @objs = map { "$_.OBJ" } @{$args{objs}}; ++ my @deps = map { ++ $disabled{shared} ? $_.".OLB" ++ : $unified_info{sharednames}->{$_}.".EXE"; } @{$args{deps}}; ++ my $deps = join(", -\n\t\t", @objs, @deps); ++ my $shlib_target = $disabled{shared} ? "" : $target{shared_target}; ++ my $engine_opt = abs2rel(rel2abs(catfile($config{sourcedir}, ++ "VMS", "engine.opt")), ++ rel2abs($config{builddir})); ++ # The "[]" hack is because in .OPT files, each line inherits the ++ # previous line's file spec as default, so if no directory spec ++ # is present in the current line and the previous line has one that ++ # doesn't apply, you're in for a surprise. ++ my $write_opt1 = ++ join(",-\"\n\t", map { my $x = $_ =~ /\[/ ? $_ : "[]".$_; ++ "WRITE OPT_FILE \"$x" } @objs). ++ "\""; ++ my $write_opt2 = ++ join("\n\t", map { my $x = $_ =~ /\[/ ? $_ : "[]".$_; ++ $x =~ s|(\.EXE)|$1/SHARE|; ++ $x =~ s|(\.OLB)|$1/LIB|; ++ "WRITE OPT_FILE \"$x\"" } @deps) ++ || "\@ !"; ++ return <<"EOF"; ++$lib.EXE : $deps ++ OPEN/WRITE/SHARE=READ OPT_FILE $lib.OPT ++ TYPE $engine_opt /OUTPUT=OPT_FILE: ++ $write_opt1 ++ $write_opt2 ++ CLOSE OPT_FILE ++ LINK /MAP=$lib.MAP /FULL/SHARE=$lib.EXE $lib.OPT/OPT \$(EX_LIBS) ++ - PURGE $lib.EXE,$lib.OPT,$lib.MAP ++EOF ++ } ++ sub obj2lib { ++ my %args = @_; ++ my $lib = $args{lib}; ++ my $objs = join(", -\n\t\t", map { $_.".OBJ" } (@{$args{objs}})); ++ my $fill_lib = join("\n\t", (map { "LIBRARY/REPLACE $lib.OLB $_.OBJ" } ++ @{$args{objs}})); ++ return <<"EOF"; ++$lib.OLB : $objs ++ LIBRARY/CREATE/OBJECT $lib.OLB ++ $fill_lib ++ - PURGE $lib.OLB ++EOF ++ } ++ sub obj2bin { ++ my %args = @_; ++ my $bin = $args{bin}; ++ my $bind = dirname($bin); ++ my $binn = basename($bin); ++ my @objs = map { "$_.OBJ" } @{$args{objs}}; ++ my @deps = map { ++ $disabled{shared} ? $_.".OLB" ++ : $unified_info{sharednames}->{$_}.".EXE"; } @{$args{deps}}; ++ my $deps = join(", -\n\t\t", @objs, @deps); ++ # The "[]" hack is because in .OPT files, each line inherits the ++ # previous line's file spec as default, so if no directory spec ++ # is present in the current line and the previous line has one that ++ # doesn't apply, you're in for a surprise. ++ my $write_opt1 = ++ join(",-\"\n\t", map { my $x = $_ =~ /\[/ ? $_ : "[]".$_; ++ "WRITE OPT_FILE \"$x" } @objs). ++ "\""; ++ my $write_opt2 = ++ join("\n\t", map { my $x = $_ =~ /\[/ ? $_ : "[]".$_; ++ $x =~ s|(\.EXE)|$1/SHARE|; ++ $x =~ s|(\.OLB)|$1/LIB|; ++ "WRITE OPT_FILE \"$x\"" } @deps) ++ || "\@ !"; ++ return <<"EOF"; ++$bin.EXE : $deps ++ OPEN/WRITE/SHARE=READ OPT_FILE $bin.OPT ++ $write_opt1 ++ $write_opt2 ++ CLOSE OPT_FILE ++ LINK/EXEC=$bin.EXE \$(LDFLAGS) $bin.OPT/OPT \$(EX_LIBS) ++ - PURGE $bin.EXE,$bin.OPT ++EOF ++ } ++ sub in2script { ++ my %args = @_; ++ my $script = $args{script}; ++ return "" if grep { $_ eq $script } @{$args{sources}}; # No overwrite! ++ my $sources = join(" ", @{$args{sources}}); ++ my $dofile = abs2rel(rel2abs(catfile($config{sourcedir}, ++ "util", "dofile.pl")), ++ rel2abs($config{builddir})); ++ return <<"EOF"; ++$script : $sources ++ \$(PERL) "-I\$(BLDDIR)" "-Mconfigdata" $dofile - ++ "-o$target{build_file}" $sources > $script ++ SET FILE/PROT=(S:RWED,O:RWED,G:RE,W:RE) $script ++ PURGE $script ++EOF ++ } ++ "" # Important! This becomes part of the template result. ++-} +diff --git a/CryptoPkg/Library/OpensslLib/openssl/Configurations/unix-Makefile.tmpl b/CryptoPkg/Library/OpensslLib/openssl/Configurations/unix-Makefile.tmpl +new file mode 100644 +index 0000000..c029817 +--- /dev/null ++++ b/CryptoPkg/Library/OpensslLib/openssl/Configurations/unix-Makefile.tmpl +@@ -0,0 +1,1124 @@ ++## ++## Makefile for OpenSSL ++## ++## {- join("\n## ", @autowarntext) -} ++{- ++ our $objext = $target{obj_extension} || ".o"; ++ our $depext = $target{dep_extension} || ".d"; ++ our $exeext = $target{exe_extension} || ""; ++ our $libext = $target{lib_extension} || ".a"; ++ our $shlibext = $target{shared_extension} || ".so"; ++ our $shlibextsimple = $target{shared_extension_simple} || ".so"; ++ our $shlibextimport = $target{shared_import_extension} || ""; ++ our $dsoext = $target{dso_extension} || ".so"; ++ ++ sub windowsdll { $config{target} =~ /^(?:Cygwin|mingw)/ } ++ ++ our $sover = $config{target} =~ /^mingw/ ++ ? $config{shlib_major}."_".$config{shlib_minor} ++ : $config{shlib_major}.".".$config{shlib_minor}; ++ ++ # shlib and shlib_simple both take a static library name and figure ++ # out what the shlib name should be. ++ # ++ # When OpenSSL is configured "no-shared", these functions will just ++ # return empty lists, making them suitable to join(). ++ # ++ # With Windows DLL producers, shlib($libname) will return the shared ++ # library name (which usually is different from the static library ++ # name) with the default shared extension appended to it, while ++ # shlib_simple($libname) will return the static library name with ++ # the shared extension followed by ".a" appended to it. The former ++ # result is used as the runtime shared library while the latter is ++ # used as the DLL import library. ++ # ++ # On all Unix systems, shlib($libname) will return the library name ++ # with the default shared extension, while shlib_simple($libname) ++ # will return the name from shlib($libname) with any SO version number ++ # removed. On some systems, they may therefore return the exact same ++ # string. ++ sub shlib { ++ return () if $disabled{shared}; ++ my $lib = shift; ++ return $unified_info{sharednames}->{$lib} . $shlibext; ++ } ++ sub shlib_simple { ++ return () if $disabled{shared}; ++ ++ my $lib = shift; ++ if (windowsdll()) { ++ return $lib . $shlibextimport; ++ } ++ return $lib . $shlibextsimple; ++ } ++ ++ # dso is a complement to shlib / shlib_simple that returns the ++ # given libname with the simple shared extension (possible SO version ++ # removed). This differs from shlib_simple() by being unconditional. ++ sub dso { ++ my $engine = shift; ++ ++ return $engine . $dsoext; ++ } ++ # This makes sure things get built in the order they need ++ # to. You're welcome. ++ sub dependmagic { ++ my $target = shift; ++ ++ return "$target: build_generated\n\t\$(MAKE) depend && \$(MAKE) _$target\n_$target"; ++ } ++ ''; ++-} ++PLATFORM={- $config{target} -} ++OPTIONS={- $config{options} -} ++CONFIGURE_ARGS=({- join(", ",quotify_l(@{$config{perlargv}})) -}) ++SRCDIR={- $config{sourcedir} -} ++BLDDIR={- $config{builddir} -} ++ ++VERSION={- $config{version} -} ++MAJOR={- $config{major} -} ++MINOR={- $config{minor} -} ++SHLIB_VERSION_NUMBER={- $config{shlib_version_number} -} ++SHLIB_VERSION_HISTORY={- $config{shlib_version_history} -} ++SHLIB_MAJOR={- $config{shlib_major} -} ++SHLIB_MINOR={- $config{shlib_minor} -} ++SHLIB_TARGET={- $target{shared_target} -} ++ ++LIBS={- join(" ", map { $_.$libext } @{$unified_info{libraries}}) -} ++SHLIBS={- join(" ", map { shlib($_) } @{$unified_info{libraries}}) -} ++SHLIB_INFO={- join(" ", map { "\"".shlib($_).";".shlib_simple($_)."\"" } @{$unified_info{libraries}}) -} ++ENGINES={- join(" ", map { dso($_) } @{$unified_info{engines}}) -} ++PROGRAMS={- join(" ", map { $_.$exeext } @{$unified_info{programs}}) -} ++SCRIPTS={- join(" ", @{$unified_info{scripts}}) -} ++{- output_off() if $disabled{makedepend}; "" -} ++DEPS={- join(" ", map { (my $x = $_) =~ s|\.o$|$depext|; $x; } ++ grep { $unified_info{sources}->{$_}->[0] =~ /\.c$/ } ++ keys %{$unified_info{sources}}); -} ++{- output_on() if $disabled{makedepend}; "" -} ++GENERATED_MANDATORY={- join(" ", @{$unified_info{depends}->{""}} ) -} ++GENERATED={- join(" ", ++ ( map { (my $x = $_) =~ s|\.S$|\.s|; $x } ++ grep { defined $unified_info{generate}->{$_} } ++ map { @{$unified_info{sources}->{$_}} } ++ grep { /\.o$/ } keys %{$unified_info{sources}} ), ++ ( grep { /\.h$/ } keys %{$unified_info{generate}} )) -} ++ ++INSTALL_LIBS={- join(" ", map { $_.$libext } @{$unified_info{install}->{libraries}}) -} ++INSTALL_SHLIBS={- join(" ", map { shlib($_) } @{$unified_info{install}->{libraries}}) -} ++INSTALL_SHLIB_INFO={- join(" ", map { "\"".shlib($_).";".shlib_simple($_)."\"" } @{$unified_info{install}->{libraries}}) -} ++INSTALL_ENGINES={- join(" ", map { dso($_) } @{$unified_info{install}->{engines}}) -} ++INSTALL_PROGRAMS={- join(" ", map { $_.$exeext } @{$unified_info{install}->{programs}}) -} ++{- output_off() if $disabled{apps}; "" -} ++BIN_SCRIPTS=$(BLDDIR)/tools/c_rehash ++MISC_SCRIPTS=$(BLDDIR)/apps/CA.pl $(BLDDIR)/apps/tsget ++{- output_on() if $disabled{apps}; "" -} ++ ++# DESTDIR is for package builders so that they can configure for, say, ++# /usr/ and yet have everything installed to /tmp/somedir/usr/. ++# Normally it is left empty. ++DESTDIR= ++ ++# Do not edit these manually. Use Configure with --prefix or --openssldir ++# to change this! Short explanation in the top comment in Configure ++INSTALLTOP={- # $prefix is used in the OPENSSLDIR perl snippet ++ # ++ our $prefix = $config{prefix} || "/usr/local"; ++ $prefix -} ++OPENSSLDIR={- # ++ # The logic here is that if no --openssldir was given, ++ # OPENSSLDIR will get the value from $prefix plus "/ssl". ++ # If --openssldir was given and the value is an absolute ++ # path, OPENSSLDIR will get its value without change. ++ # If the value from --openssldir is a relative path, ++ # OPENSSLDIR will get $prefix with the --openssldir ++ # value appended as a subdirectory. ++ # ++ use File::Spec::Functions; ++ our $openssldir = ++ $config{openssldir} ? ++ (file_name_is_absolute($config{openssldir}) ? ++ $config{openssldir} ++ : catdir($prefix, $config{openssldir})) ++ : catdir($prefix, "ssl"); ++ $openssldir -} ++LIBDIR={- # ++ # if $prefix/lib$target{multilib} is not an existing ++ # directory, then assume that it's not searched by linker ++ # automatically, in which case adding $target{multilib} suffix ++ # causes more grief than we're ready to tolerate, so don't... ++ our $multilib = ++ -d "$prefix/lib$target{multilib}" ? $target{multilib} : ""; ++ our $libdir = $config{libdir} || "lib$multilib"; ++ $libdir -} ++ENGINESDIR={- use File::Spec::Functions; ++ catdir($prefix,$libdir,"engines-$sover") -} ++ ++# Convenience variable for those who want to set the rpath in shared ++# libraries and applications ++LIBRPATH=$(INSTALLTOP)/$(LIBDIR) ++ ++MANDIR=$(INSTALLTOP)/share/man ++DOCDIR=$(INSTALLTOP)/share/doc/$(BASENAME) ++HTMLDIR=$(DOCDIR)/html ++ ++# MANSUFFIX is for the benefit of anyone who may want to have a suffix ++# appended after the manpage file section number. "ssl" is popular, ++# resulting in files such as config.5ssl rather than config.5. ++MANSUFFIX= ++HTMLSUFFIX=html ++ ++ ++ ++CROSS_COMPILE= {- $config{cross_compile_prefix} -} ++CC= $(CROSS_COMPILE){- $target{cc} -} ++CFLAGS={- our $cflags2 = join(" ",(map { "-D".$_} @{$target{defines}}, @{$config{defines}}),"-DOPENSSLDIR=\"\\\"\$(OPENSSLDIR)\\\"\"","-DENGINESDIR=\"\\\"\$(ENGINESDIR)\\\"\"") -} {- $target{cflags} -} {- $config{cflags} -} ++CFLAGS_Q={- $cflags2 =~ s|([\\"])|\\$1|g; $cflags2 -} {- $config{cflags} -} ++LDFLAGS= {- $target{lflags} -} ++PLIB_LDFLAGS= {- $target{plib_lflags} -} ++EX_LIBS= {- $target{ex_libs} -} {- $config{ex_libs} -} ++LIB_CFLAGS={- $target{shared_cflag} || "" -} ++LIB_LDFLAGS={- $target{shared_ldflag}." ".$config{shared_ldflag} -} ++DSO_CFLAGS={- $target{shared_cflag} || "" -} ++DSO_LDFLAGS=$(LIB_LDFLAGS) ++BIN_CFLAGS={- $target{bin_cflags} -} ++ ++PERL={- $config{perl} -} ++ ++ARFLAGS= {- $target{arflags} -} ++AR=$(CROSS_COMPILE){- $target{ar} || "ar" -} $(ARFLAGS) r ++RANLIB= {- $target{ranlib} -} ++NM= $(CROSS_COMPILE){- $target{nm} || "nm" -} ++RCFLAGS={- $target{shared_rcflag} -} ++RC= $(CROSS_COMPILE){- $target{rc} || "windres" -} ++RM= rm -f ++RMDIR= rmdir ++TAR= {- $target{tar} || "tar" -} ++TARFLAGS= {- $target{tarflags} -} ++MAKEDEPEND={- $config{makedepprog} -} ++ ++BASENAME= openssl ++NAME= $(BASENAME)-$(VERSION) ++TARFILE= ../$(NAME).tar ++ ++# We let the C compiler driver to take care of .s files. This is done in ++# order to be excused from maintaining a separate set of architecture ++# dependent assembler flags. E.g. if you throw -mcpu=ultrasparc at SPARC ++# gcc, then the driver will automatically translate it to -xarch=v8plus ++# and pass it down to assembler. ++AS=$(CC) -c ++ASFLAG=$(CFLAGS) ++PERLASM_SCHEME= {- $target{perlasm_scheme} -} ++ ++# For x86 assembler: Set PROCESSOR to 386 if you want to support ++# the 80386. ++PROCESSOR= {- $config{processor} -} ++ ++# We want error [and other] messages in English. Trouble is that make(1) ++# doesn't pass macros down as environment variables unless there already ++# was corresponding variable originally set. In other words we can only ++# reassign environment variables, but not set new ones, not in portable ++# manner that is. That's why we reassign several, just to be sure... ++LC_ALL=C ++LC_MESSAGES=C ++LANG=C ++ ++# The main targets ################################################### ++ ++{- dependmagic('all'); -}: build_libs_nodep build_engines_nodep build_programs_nodep link-utils ++{- dependmagic('build_libs'); -}: build_libs_nodep ++{- dependmagic('build_engines'); -}: build_engines_nodep ++{- dependmagic('build_programs'); -}: build_programs_nodep ++ ++build_generated: $(GENERATED_MANDATORY) ++build_libs_nodep: libcrypto.pc libssl.pc openssl.pc ++build_engines_nodep: $(ENGINES) ++build_programs_nodep: $(PROGRAMS) $(SCRIPTS) ++ ++# Kept around for backward compatibility ++build_apps build_tests: build_programs ++ ++test: tests ++{- dependmagic('tests'); -}: build_programs_nodep build_engines_nodep link-utils ++ @ : {- output_off() if $disabled{tests}; "" -} ++ ( cd test; \ ++ SRCTOP=../$(SRCDIR) \ ++ BLDTOP=../$(BLDDIR) \ ++ PERL="$(PERL)" \ ++ EXE_EXT={- $exeext -} \ ++ OPENSSL_ENGINES=../$(BLDDIR)/engines \ ++ OPENSSL_DEBUG_MEMORY=on \ ++ $(PERL) ../$(SRCDIR)/test/run_tests.pl $(TESTS) ) ++ @ : {- if ($disabled{tests}) { output_on(); } else { output_off(); } "" -} ++ @echo "Tests are not supported with your chosen Configure options" ++ @ : {- output_on() if !$disabled{tests}; "" -} ++ ++list-tests: ++ @ : {- output_off() if $disabled{tests}; "" -} ++ @SRCTOP="$(SRCDIR)" \ ++ $(PERL) $(SRCDIR)/test/run_tests.pl list ++ @ : {- if ($disabled{tests}) { output_on(); } else { output_off(); } "" -} ++ @echo "Tests are not supported with your chosen Configure options" ++ @ : {- output_on() if !$disabled{tests}; "" -} ++ ++install: install_sw install_ssldirs install_docs ++ ++uninstall: uninstall_docs uninstall_sw ++ ++libclean: ++ @set -e; for s in $(SHLIB_INFO); do \ ++ s1=`echo "$$s" | cut -f1 -d";"`; \ ++ s2=`echo "$$s" | cut -f2 -d";"`; \ ++ echo $(RM) $$s1; \ ++ $(RM) $$s1; \ ++ if [ "$$s1" != "$$s2" ]; then \ ++ echo $(RM) $$s2; \ ++ $(RM) $$s2; \ ++ fi; \ ++ done ++ $(RM) $(LIBS) ++ $(RM) *.map ++ ++clean: libclean ++ $(RM) $(PROGRAMS) $(TESTPROGS) $(ENGINES) $(SCRIPTS) ++ $(RM) $(GENERATED) ++ -$(RM) `find . -name '*{- $depext -}' -a \! -path "./.git/*"` ++ -$(RM) `find . -name '*{- $objext -}' -a \! -path "./.git/*"` ++ $(RM) core ++ $(RM) tags TAGS ++ $(RM) test/.rnd ++ $(RM) openssl.pc libcrypto.pc libssl.pc ++ -$(RM) `find . -type l -a \! -path "./.git/*"` ++ $(RM) $(TARFILE) ++ ++distclean: clean ++ $(RM) configdata.pm ++ $(RM) Makefile ++ ++# We check if any depfile is newer than Makefile and decide to ++# concatenate only if that is true. ++depend: ++ @: {- output_off() if $disabled{makedepend}; "" -} ++ @if egrep "^# DO NOT DELETE THIS LINE" Makefile >/dev/null && [ -z "`find $(DEPS) -newer Makefile 2>/dev/null; exit 0`" ]; then :; else \ ++ ( $(PERL) -pe 'exit 0 if /^# DO NOT DELETE THIS LINE.*/' < Makefile; \ ++ echo '# DO NOT DELETE THIS LINE -- make depend depends on it.'; \ ++ echo; \ ++ for f in $(DEPS); do \ ++ if [ -f $$f ]; then cat $$f; fi; \ ++ done ) > Makefile.new; \ ++ if cmp Makefile.new Makefile >/dev/null 2>&1; then \ ++ rm -f Makefile.new; \ ++ else \ ++ mv -f Makefile.new Makefile; \ ++ fi; \ ++ fi ++ @: {- output_on() if $disabled{makedepend}; "" -} ++ ++# Install helper targets ############################################# ++ ++install_sw: all install_dev install_engines install_runtime ++ ++uninstall_sw: uninstall_runtime uninstall_engines uninstall_dev ++ ++install_docs: install_man_docs install_html_docs ++ ++uninstall_docs: uninstall_man_docs uninstall_html_docs ++ $(RM) -r -v $(DESTDIR)$(DOCDIR) ++ ++install_ssldirs: ++ @$(PERL) $(SRCDIR)/util/mkdir-p.pl $(DESTDIR)$(OPENSSLDIR)/certs ++ @$(PERL) $(SRCDIR)/util/mkdir-p.pl $(DESTDIR)$(OPENSSLDIR)/private ++ @$(PERL) $(SRCDIR)/util/mkdir-p.pl $(DESTDIR)$(OPENSSLDIR)/misc ++ @set -e; for x in dummy $(MISC_SCRIPTS); do \ ++ if [ "$$x" = "dummy" ]; then continue; fi; \ ++ fn=`basename $$x`; \ ++ echo "install $$x -> $(DESTDIR)$(OPENSSLDIR)/misc/$$fn"; \ ++ cp $$x $(DESTDIR)$(OPENSSLDIR)/misc/$$fn.new; \ ++ chmod 755 $(DESTDIR)$(OPENSSLDIR)/misc/$$fn.new; \ ++ mv -f $(DESTDIR)$(OPENSSLDIR)/misc/$$fn.new \ ++ $(DESTDIR)$(OPENSSLDIR)/misc/$$fn; \ ++ done ++ @echo "install $(SRCDIR)/apps/openssl.cnf -> $(DESTDIR)$(OPENSSLDIR)/openssl.cnf.dist" ++ @cp $(SRCDIR)/apps/openssl.cnf $(DESTDIR)$(OPENSSLDIR)/openssl.cnf.new ++ @chmod 644 $(DESTDIR)$(OPENSSLDIR)/openssl.cnf.new ++ @mv -f $(DESTDIR)$(OPENSSLDIR)/openssl.cnf.new $(DESTDIR)$(OPENSSLDIR)/openssl.cnf.dist ++ @if ! [ -f "$(DESTDIR)$(OPENSSLDIR)/openssl.cnf" ]; then \ ++ echo "install $(SRCDIR)/apps/openssl.cnf -> $(DESTDIR)$(OPENSSLDIR)/openssl.cnf"; \ ++ cp $(SRCDIR)/apps/openssl.cnf $(DESTDIR)$(OPENSSLDIR)/openssl.cnf; \ ++ chmod 644 $(DESTDIR)$(OPENSSLDIR)/openssl.cnf; \ ++ fi ++ ++install_dev: ++ @[ -n "$(INSTALLTOP)" ] || (echo INSTALLTOP should not be empty; exit 1) ++ @echo "*** Installing development files" ++ @$(PERL) $(SRCDIR)/util/mkdir-p.pl $(DESTDIR)$(INSTALLTOP)/include/openssl ++ @ : {- output_off() unless grep { $_ eq "OPENSSL_USE_APPLINK" } @{$target{defines}}; "" -} ++ @echo "install $(SRCDIR)/ms/applink.c -> $(DESTDIR)$(INSTALLTOP)/include/openssl/applink.c" ++ @cp $(SRCDIR)/ms/applink.c $(DESTDIR)$(INSTALLTOP)/include/openssl/applink.c ++ @chmod 644 $(DESTDIR)$(INSTALLTOP)/include/openssl/applink.c ++ @ : {- output_on() unless grep { $_ eq "OPENSSL_USE_APPLINK" } @{$target{defines}}; "" -} ++ @set -e; for i in $(SRCDIR)/include/openssl/*.h \ ++ $(BLDDIR)/include/openssl/*.h; do \ ++ fn=`basename $$i`; \ ++ echo "install $$i -> $(DESTDIR)$(INSTALLTOP)/include/openssl/$$fn"; \ ++ cp $$i $(DESTDIR)$(INSTALLTOP)/include/openssl/$$fn; \ ++ chmod 644 $(DESTDIR)$(INSTALLTOP)/include/openssl/$$fn; \ ++ done ++ @$(PERL) $(SRCDIR)/util/mkdir-p.pl $(DESTDIR)$(INSTALLTOP)/$(LIBDIR) ++ @set -e; for l in $(INSTALL_LIBS); do \ ++ fn=`basename $$l`; \ ++ echo "install $$l -> $(DESTDIR)$(INSTALLTOP)/$(LIBDIR)/$$fn"; \ ++ cp $$l $(DESTDIR)$(INSTALLTOP)/$(LIBDIR)/$$fn.new; \ ++ $(RANLIB) $(DESTDIR)$(INSTALLTOP)/$(LIBDIR)/$$fn.new; \ ++ chmod 644 $(DESTDIR)$(INSTALLTOP)/$(LIBDIR)/$$fn.new; \ ++ mv -f $(DESTDIR)$(INSTALLTOP)/$(LIBDIR)/$$fn.new \ ++ $(DESTDIR)$(INSTALLTOP)/$(LIBDIR)/$$fn; \ ++ done ++ @ : {- output_off() if $disabled{shared}; "" -} ++ @set -e; for s in $(INSTALL_SHLIB_INFO); do \ ++ s1=`echo "$$s" | cut -f1 -d";"`; \ ++ s2=`echo "$$s" | cut -f2 -d";"`; \ ++ fn1=`basename $$s1`; \ ++ fn2=`basename $$s2`; \ ++ : {- output_off() if windowsdll(); "" -}; \ ++ echo "install $$s1 -> $(DESTDIR)$(INSTALLTOP)/$(LIBDIR)/$$fn1"; \ ++ cp $$s1 $(DESTDIR)$(INSTALLTOP)/$(LIBDIR)/$$fn1.new; \ ++ chmod 755 $(DESTDIR)$(INSTALLTOP)/$(LIBDIR)/$$fn1.new; \ ++ mv -f $(DESTDIR)$(INSTALLTOP)/$(LIBDIR)/$$fn1.new \ ++ $(DESTDIR)$(INSTALLTOP)/$(LIBDIR)/$$fn1; \ ++ if [ "$$fn1" != "$$fn2" ]; then \ ++ echo "link $(DESTDIR)$(INSTALLTOP)/$(LIBDIR)/$$fn2 -> $(DESTDIR)$(INSTALLTOP)/$(LIBDIR)/$$fn1"; \ ++ ln -sf $$fn1 $(DESTDIR)$(INSTALLTOP)/$(LIBDIR)/$$fn2; \ ++ fi; \ ++ : {- output_on() if windowsdll(); "" -}{- output_off() unless windowsdll(); "" -}; \ ++ echo "install $$s2 -> $(DESTDIR)$(INSTALLTOP)/$(LIBDIR)/$$fn2"; \ ++ cp $$s2 $(DESTDIR)$(INSTALLTOP)/$(LIBDIR)/$$fn2.new; \ ++ chmod 755 $(DESTDIR)$(INSTALLTOP)/$(LIBDIR)/$$fn2.new; \ ++ mv -f $(DESTDIR)$(INSTALLTOP)/$(LIBDIR)/$$fn2.new \ ++ $(DESTDIR)$(INSTALLTOP)/$(LIBDIR)/$$fn2; \ ++ : {- output_on() unless windowsdll(); "" -}; \ ++ done ++ @ : {- output_on() if $disabled{shared}; "" -} ++ @$(PERL) $(SRCDIR)/util/mkdir-p.pl $(DESTDIR)$(INSTALLTOP)/$(LIBDIR)/pkgconfig ++ @echo "install libcrypto.pc -> $(DESTDIR)$(INSTALLTOP)/$(LIBDIR)/pkgconfig/libcrypto.pc" ++ @cp libcrypto.pc $(DESTDIR)$(INSTALLTOP)/$(LIBDIR)/pkgconfig ++ @chmod 644 $(DESTDIR)$(INSTALLTOP)/$(LIBDIR)/pkgconfig/libcrypto.pc ++ @echo "install libssl.pc -> $(DESTDIR)$(INSTALLTOP)/$(LIBDIR)/pkgconfig/libssl.pc" ++ @cp libssl.pc $(DESTDIR)$(INSTALLTOP)/$(LIBDIR)/pkgconfig ++ @chmod 644 $(DESTDIR)$(INSTALLTOP)/$(LIBDIR)/pkgconfig/libssl.pc ++ @echo "install openssl.pc -> $(DESTDIR)$(INSTALLTOP)/$(LIBDIR)/pkgconfig/openssl.pc" ++ @cp openssl.pc $(DESTDIR)$(INSTALLTOP)/$(LIBDIR)/pkgconfig ++ @chmod 644 $(DESTDIR)$(INSTALLTOP)/$(LIBDIR)/pkgconfig/openssl.pc ++ ++uninstall_dev: ++ @echo "*** Uninstalling development files" ++ @ : {- output_off() unless grep { $_ eq "OPENSSL_USE_APPLINK" } @{$target{defines}}; "" -} ++ @echo "$(RM) $(DESTDIR)$(INSTALLTOP)/include/openssl/applink.c" ++ @$(RM) $(DESTDIR)$(INSTALLTOP)/include/openssl/applink.c ++ @ : {- output_on() unless grep { $_ eq "OPENSSL_USE_APPLINK" } @{$target{defines}}; "" -} ++ @set -e; for i in $(SRCDIR)/include/openssl/*.h \ ++ $(BLDDIR)/include/openssl/*.h; do \ ++ fn=`basename $$i`; \ ++ echo "$(RM) $(DESTDIR)$(INSTALLTOP)/include/openssl/$$fn"; \ ++ $(RM) $(DESTDIR)$(INSTALLTOP)/include/openssl/$$fn; \ ++ done ++ -$(RMDIR) $(DESTDIR)$(INSTALLTOP)/include/openssl ++ -$(RMDIR) $(DESTDIR)$(INSTALLTOP)/include ++ @set -e; for l in $(INSTALL_LIBS); do \ ++ fn=`basename $$l`; \ ++ echo "$(RM) $(DESTDIR)$(INSTALLTOP)/$(LIBDIR)/$$fn"; \ ++ $(RM) $(DESTDIR)$(INSTALLTOP)/$(LIBDIR)/$$fn; \ ++ done ++ @ : {- output_off() if $disabled{shared}; "" -} ++ @set -e; for s in $(INSTALL_SHLIB_INFO); do \ ++ s1=`echo "$$s" | cut -f1 -d";"`; \ ++ s2=`echo "$$s" | cut -f2 -d";"`; \ ++ fn1=`basename $$s1`; \ ++ fn2=`basename $$s2`; \ ++ : {- output_off() if windowsdll(); "" -}; \ ++ echo "$(RM) $(DESTDIR)$(INSTALLTOP)/$(LIBDIR)/$$fn1"; \ ++ $(RM) $(DESTDIR)$(INSTALLTOP)/$(LIBDIR)/$$fn1; \ ++ if [ "$$fn1" != "$$fn2" ]; then \ ++ echo "$(RM) $(DESTDIR)$(INSTALLTOP)/$(LIBDIR)/$$fn2"; \ ++ $(RM) $(DESTDIR)$(INSTALLTOP)/$(LIBDIR)/$$fn2; \ ++ fi; \ ++ : {- output_on() if windowsdll(); "" -}{- output_off() unless windowsdll(); "" -}; \ ++ echo "$(RM) $(DESTDIR)$(INSTALLTOP)/$(LIBDIR)/$$fn2"; \ ++ $(RM) $(DESTDIR)$(INSTALLTOP)/$(LIBDIR)/$$fn2; \ ++ : {- output_on() unless windowsdll(); "" -}; \ ++ done ++ @ : {- output_on() if $disabled{shared}; "" -} ++ $(RM) $(DESTDIR)$(INSTALLTOP)/$(LIBDIR)/pkgconfig/libcrypto.pc ++ $(RM) $(DESTDIR)$(INSTALLTOP)/$(LIBDIR)/pkgconfig/libssl.pc ++ $(RM) $(DESTDIR)$(INSTALLTOP)/$(LIBDIR)/pkgconfig/openssl.pc ++ -$(RMDIR) $(DESTDIR)$(INSTALLTOP)/$(LIBDIR)/pkgconfig ++ -$(RMDIR) $(DESTDIR)$(INSTALLTOP)/$(LIBDIR) ++ ++install_engines: ++ @[ -n "$(INSTALLTOP)" ] || (echo INSTALLTOP should not be empty; exit 1) ++ @$(PERL) $(SRCDIR)/util/mkdir-p.pl $(DESTDIR)$(ENGINESDIR)/ ++ @echo "*** Installing engines" ++ @set -e; for e in dummy $(INSTALL_ENGINES); do \ ++ if [ "$$e" = "dummy" ]; then continue; fi; \ ++ fn=`basename $$e`; \ ++ echo "install $$e -> $(DESTDIR)$(ENGINESDIR)/$$fn"; \ ++ cp $$e $(DESTDIR)$(ENGINESDIR)/$$fn.new; \ ++ chmod 755 $(DESTDIR)$(ENGINESDIR)/$$fn.new; \ ++ mv -f $(DESTDIR)$(ENGINESDIR)/$$fn.new \ ++ $(DESTDIR)$(ENGINESDIR)/$$fn; \ ++ done ++ ++uninstall_engines: ++ @echo "*** Uninstalling engines" ++ @set -e; for e in dummy $(INSTALL_ENGINES); do \ ++ if [ "$$e" = "dummy" ]; then continue; fi; \ ++ fn=`basename $$e`; \ ++ if [ "$$fn" = '{- dso("ossltest") -}' ]; then \ ++ continue; \ ++ fi; \ ++ echo "$(RM) $(DESTDIR)$(ENGINESDIR)/$$fn"; \ ++ $(RM) $(DESTDIR)$(ENGINESDIR)/$$fn; \ ++ done ++ -$(RMDIR) $(DESTDIR)$(ENGINESDIR) ++ ++install_runtime: ++ @[ -n "$(INSTALLTOP)" ] || (echo INSTALLTOP should not be empty; exit 1) ++ @$(PERL) $(SRCDIR)/util/mkdir-p.pl $(DESTDIR)$(INSTALLTOP)/bin ++ @ : {- output_off() if windowsdll(); "" -} ++ @$(PERL) $(SRCDIR)/util/mkdir-p.pl $(DESTDIR)$(INSTALLTOP)/$(LIBDIR) ++ @ : {- output_on() if windowsdll(); "" -} ++ @echo "*** Installing runtime files" ++ @set -e; for s in dummy $(INSTALL_SHLIBS); do \ ++ if [ "$$s" = "dummy" ]; then continue; fi; \ ++ fn=`basename $$s`; \ ++ : {- output_off() unless windowsdll(); "" -}; \ ++ echo "install $$s -> $(DESTDIR)$(INSTALLTOP)/bin/$$fn"; \ ++ cp $$s $(DESTDIR)$(INSTALLTOP)/bin/$$fn.new; \ ++ chmod 644 $(DESTDIR)$(INSTALLTOP)/bin/$$fn.new; \ ++ mv -f $(DESTDIR)$(INSTALLTOP)/bin/$$fn.new \ ++ $(DESTDIR)$(INSTALLTOP)/bin/$$fn; \ ++ : {- output_on() unless windowsdll(); "" -}{- output_off() if windowsdll(); "" -}; \ ++ echo "install $$s -> $(DESTDIR)$(INSTALLTOP)/$(LIBDIR)/$$fn"; \ ++ cp $$s $(DESTDIR)$(INSTALLTOP)/$(LIBDIR)/$$fn.new; \ ++ chmod 755 $(DESTDIR)$(INSTALLTOP)/$(LIBDIR)/$$fn.new; \ ++ mv -f $(DESTDIR)$(INSTALLTOP)/$(LIBDIR)/$$fn.new \ ++ $(DESTDIR)$(INSTALLTOP)/$(LIBDIR)/$$fn; \ ++ : {- output_on() if windowsdll(); "" -}; \ ++ done ++ @set -e; for x in dummy $(INSTALL_PROGRAMS); do \ ++ if [ "$$x" = "dummy" ]; then continue; fi; \ ++ fn=`basename $$x`; \ ++ echo "install $$x -> $(DESTDIR)$(INSTALLTOP)/bin/$$fn"; \ ++ cp $$x $(DESTDIR)$(INSTALLTOP)/bin/$$fn.new; \ ++ chmod 755 $(DESTDIR)$(INSTALLTOP)/bin/$$fn.new; \ ++ mv -f $(DESTDIR)$(INSTALLTOP)/bin/$$fn.new \ ++ $(DESTDIR)$(INSTALLTOP)/bin/$$fn; \ ++ done ++ @set -e; for x in dummy $(BIN_SCRIPTS); do \ ++ if [ "$$x" = "dummy" ]; then continue; fi; \ ++ fn=`basename $$x`; \ ++ echo "install $$x -> $(DESTDIR)$(INSTALLTOP)/bin/$$fn"; \ ++ cp $$x $(DESTDIR)$(INSTALLTOP)/bin/$$fn.new; \ ++ chmod 755 $(DESTDIR)$(INSTALLTOP)/bin/$$fn.new; \ ++ mv -f $(DESTDIR)$(INSTALLTOP)/bin/$$fn.new \ ++ $(DESTDIR)$(INSTALLTOP)/bin/$$fn; \ ++ done ++ ++uninstall_runtime: ++ @echo "*** Uninstalling runtime files" ++ @set -e; for x in dummy $(INSTALL_PROGRAMS); \ ++ do \ ++ if [ "$$x" = "dummy" ]; then continue; fi; \ ++ fn=`basename $$x`; \ ++ echo "$(RM) $(DESTDIR)$(INSTALLTOP)/bin/$$fn"; \ ++ $(RM) $(DESTDIR)$(INSTALLTOP)/bin/$$fn; \ ++ done; ++ @set -e; for x in dummy $(BIN_SCRIPTS); \ ++ do \ ++ if [ "$$x" = "dummy" ]; then continue; fi; \ ++ fn=`basename $$x`; \ ++ echo "$(RM) $(DESTDIR)$(INSTALLTOP)/bin/$$fn"; \ ++ $(RM) $(DESTDIR)$(INSTALLTOP)/bin/$$fn; \ ++ done ++ @ : {- output_off() unless windowsdll(); "" -} ++ @set -e; for s in dummy $(INSTALL_SHLIBS); do \ ++ if [ "$$s" = "dummy" ]; then continue; fi; \ ++ fn=`basename $$s`; \ ++ echo "$(RM) $(DESTDIR)$(INSTALLTOP)/bin/$$fn"; \ ++ $(RM) $(DESTDIR)$(INSTALLTOP)/bin/$$fn; \ ++ done ++ @ : {- output_on() unless windowsdll(); "" -} ++ -$(RMDIR) $(DESTDIR)$(INSTALLTOP)/bin ++ ++# A method to extract all names from a .pod file ++# The first sed extracts everything between "=head1 NAME" and the next =head1 ++# The perl command joins all the lines into one ++# The second sed removes the description and turns all commas into spaces ++# Voilà, you have a space separated list of names! ++EXTRACT_NAMES=sed -e '1,/^=head1 *NAME *$$/d;/^=head1/,$$d' | \ ++ $(PERL) -p -0 -e 's/\n/ /g; END {print "\n"}' | \ ++ sed -e 's/ - .*$$//;s/,/ /g' ++PROCESS_PODS=\ ++ set -e; \ ++ here=`cd $(SRCDIR); pwd`; \ ++ point=$$here/util/point.sh; \ ++ for ds in apps:1 crypto:3 ssl:3; do \ ++ defdir=`echo $$ds | cut -f1 -d:`; \ ++ defsec=`echo $$ds | cut -f2 -d:`; \ ++ for p in $(SRCDIR)/doc/$$defdir/*.pod; do \ ++ SEC=`sed -ne 's/^=for *comment *openssl_manual_section: *\([0-9]\) *$$/\1/p' $$p`; \ ++ [ -z "$$SEC" ] && SEC=$$defsec; \ ++ fn=`basename $$p .pod`; \ ++ Name=$$fn; \ ++ NAME=`echo $$fn | tr '[a-z]' '[A-Z]'`; \ ++ suf=`eval "echo $$OUTSUFFIX"`; \ ++ top=`eval "echo $$OUTTOP"`; \ ++ $(PERL) $(SRCDIR)/util/mkdir-p.pl $$top/man$$SEC; \ ++ echo "install $$p -> $$top/man$$SEC/$$fn$$suf"; \ ++ cat $$p | eval "$$GENERATE" \ ++ > $$top/man$$SEC/$$fn$$suf; \ ++ names=`cat $$p | $(EXTRACT_NAMES)`; \ ++ ( cd $$top/man$$SEC; \ ++ for n in $$names; do \ ++ comp_n="$$n"; \ ++ comp_fn="$$fn"; \ ++ case "$(PLATFORM)" in DJGPP|Cygwin*|mingw*|darwin*-*-cc) \ ++ comp_n=`echo "$$n" | tr '[A-Z]' '[a-z]'`; \ ++ comp_fn=`echo "$$fn" | tr '[A-Z]' '[a-z]'`; \ ++ ;; \ ++ esac; \ ++ if [ "$$comp_n" != "$$comp_fn" ]; then \ ++ echo "link $$top/man$$SEC/$$n$$suf -> $$top/man$$SEC/$$fn$$suf"; \ ++ PLATFORM=$(PLATFORM) $$point $$fn$$suf $$n$$suf; \ ++ fi; \ ++ done ); \ ++ done; \ ++ done ++UNINSTALL_DOCS=\ ++ set -e; \ ++ here=`cd $(SRCDIR); pwd`; \ ++ for ds in apps:1 crypto:3 ssl:3; do \ ++ defdir=`echo $$ds | cut -f1 -d:`; \ ++ defsec=`echo $$ds | cut -f2 -d:`; \ ++ for p in $(SRCDIR)/doc/$$defdir/*.pod; do \ ++ SEC=`sed -ne 's/^=for *comment *openssl_manual_section: *\([0-9]\) *$$/\1/p' $$p`; \ ++ [ -z "$$SEC" ] && SEC=$$defsec; \ ++ fn=`basename $$p .pod`; \ ++ suf=`eval "echo $$OUTSUFFIX"`; \ ++ top=`eval "echo $$OUTTOP"`; \ ++ echo "$(RM) $$top/man$$SEC/$$fn$$suf"; \ ++ $(RM) $$top/man$$SEC/$$fn$$suf; \ ++ names=`cat $$p | $(EXTRACT_NAMES)`; \ ++ for n in $$names; do \ ++ comp_n="$$n"; \ ++ comp_fn="$$fn"; \ ++ case "$(PLATFORM)" in DJGPP|Cygwin*|mingw*|darwin*-*-cc) \ ++ comp_n=`echo "$$n" | tr '[A-Z]' '[a-z]'`; \ ++ comp_fn=`echo "$$fn" | tr '[A-Z]' '[a-z]'`; \ ++ ;; \ ++ esac; \ ++ if [ "$$comp_n" != "$$comp_fn" ]; then \ ++ echo "$(RM) $$top/man$$SEC/$$n$$suf"; \ ++ $(RM) $$top/man$$SEC/$$n$$suf; \ ++ fi; \ ++ done; \ ++ ( $(RMDIR) $$top/man$$SEC 2>/dev/null || exit 0 ); \ ++ done; \ ++ done ++ ++install_man_docs: ++ @[ -n "$(INSTALLTOP)" ] || (echo INSTALLTOP should not be empty; exit 1) ++ @echo "*** Installing manpages" ++ @\ ++ OUTSUFFIX='.$${SEC}$(MANSUFFIX)'; \ ++ OUTTOP="$(DESTDIR)$(MANDIR)"; \ ++ GENERATE='pod2man --name=$$NAME --section=$$SEC --center=OpenSSL --release=$(VERSION)'; \ ++ $(PROCESS_PODS) ++ ++uninstall_man_docs: ++ @echo "*** Uninstalling manpages" ++ @\ ++ OUTSUFFIX='.$${SEC}$(MANSUFFIX)'; \ ++ OUTTOP="$(DESTDIR)$(MANDIR)"; \ ++ $(UNINSTALL_DOCS) ++ ++install_html_docs: ++ @[ -n "$(INSTALLTOP)" ] || (echo INSTALLTOP should not be empty; exit 1) ++ @echo "*** Installing HTML manpages" ++ @\ ++ OUTSUFFIX='.$(HTMLSUFFIX)'; \ ++ OUTTOP="$(DESTDIR)$(HTMLDIR)"; \ ++ GENERATE="pod2html --podroot=$(SRCDIR)/doc --htmldir=.. \ ++ --podpath=apps:crypto:ssl --title=\$$Name \ ++ | perl -pe 's|href=\"http://man.he.net/man|href=\"../man|g; s|href=\"(.*/man.*)(?|href=\"\$$1.html\">|g;'"; \ ++ $(PROCESS_PODS) ++ ++uninstall_html_docs: ++ @echo "*** Uninstalling manpages" ++ @\ ++ OUTSUFFIX='.$(HTMLSUFFIX)'; \ ++ OUTTOP="$(DESTDIR)$(HTMLDIR)"; \ ++ $(UNINSTALL_DOCS) ++ ++ ++# Developer targets (note: these are only available on Unix) ######### ++ ++update: generate errors ordinals ++ ++generate: generate_apps generate_crypto_bn generate_crypto_objects \ ++ generate_crypto_conf generate_crypto_asn1 ++ ++# Test coverage is a good idea for the future ++#coverage: $(PROGRAMS) $(TESTPROGRAMS) ++# ... ++ ++lint: ++ lint -DLINT $(INCLUDES) $(SRCS) ++ ++{- # because the program apps/openssl has object files as sources, and ++ # they then have the corresponding C files as source, we need to chain ++ # the lookups in %unified_info ++ my $apps_openssl = catfile("apps","openssl"); ++ our @openssl_source = map { @{$unified_info{sources}->{$_}} } ++ @{$unified_info{sources}->{$apps_openssl}}; ++ ""; -} ++generate_apps: ++ ( cd $(SRCDIR); $(PERL) VMS/VMSify-conf.pl \ ++ < apps/openssl.cnf > apps/openssl-vms.cnf ) ++ ( b=`pwd`; cd $(SRCDIR); $(PERL) -I$$b apps/progs.pl \ ++ {- join(" ", @openssl_source) -} \ ++ > apps/progs.h ) ++ ++generate_crypto_bn: ++ ( cd $(SRCDIR); $(PERL) crypto/bn/bn_prime.pl > crypto/bn/bn_prime.h ) ++ ++generate_crypto_objects: ++ ( cd $(SRCDIR); $(PERL) crypto/objects/objects.pl \ ++ crypto/objects/objects.txt \ ++ crypto/objects/obj_mac.num \ ++ include/openssl/obj_mac.h ) ++ ( cd $(SRCDIR); $(PERL) crypto/objects/obj_dat.pl \ ++ include/openssl/obj_mac.h \ ++ crypto/objects/obj_dat.h ) ++ ( cd $(SRCDIR); $(PERL) crypto/objects/objxref.pl \ ++ crypto/objects/obj_mac.num \ ++ crypto/objects/obj_xref.txt \ ++ > crypto/objects/obj_xref.h ) ++ ++generate_crypto_conf: ++ ( cd $(SRCDIR); $(PERL) crypto/conf/keysets.pl \ ++ > crypto/conf/conf_def.h ) ++ ++generate_crypto_asn1: ++ ( cd $(SRCDIR); $(PERL) crypto/asn1/charmap.pl \ ++ > crypto/asn1/charmap.h ) ++ ++errors: ++ ( cd $(SRCDIR); $(PERL) util/ck_errf.pl -strict */*.c */*/*.c ) ++ ( cd $(SRCDIR); $(PERL) util/mkerr.pl -recurse -write ) ++ ( cd $(SRCDIR)/engines; \ ++ for e in *.ec; do \ ++ $(PERL) ../util/mkerr.pl -conf $$e \ ++ -nostatic -staticloader -write *.c; \ ++ done ) ++ ++ordinals: ++ ( b=`pwd`; cd $(SRCDIR); $(PERL) -I$$b util/mkdef.pl crypto update ) ++ ( b=`pwd`; cd $(SRCDIR); $(PERL) -I$$b util/mkdef.pl ssl update ) ++ ++test_ordinals: ++ ( cd test; \ ++ SRCTOP=../$(SRCDIR) \ ++ BLDTOP=../$(BLDDIR) \ ++ $(PERL) ../$(SRCDIR)/test/run_tests.pl test_ordinals ) ++ ++tags TAGS: FORCE ++ rm -f TAGS tags ++ -ctags -R . ++ -etags `find . -name '*.[ch]' -o -name '*.pm'` ++ ++# Release targets (note: only available on Unix) ##################### ++ ++TAR_COMMAND=$(TAR) $(TARFLAGS) --owner 0 --group 0 -cvf - ++PREPARE_CMD=: ++tar: ++ TMPDIR=/var/tmp/openssl-copy.$$$$; \ ++ DISTDIR=$(NAME); \ ++ mkdir -p $$TMPDIR/$$DISTDIR; \ ++ (cd $(SRCDIR); \ ++ git ls-tree -r --name-only --full-tree HEAD \ ++ | grep -v '^fuzz/corpora' \ ++ | while read F; do \ ++ mkdir -p $$TMPDIR/$$DISTDIR/`dirname $$F`; \ ++ cp $$F $$TMPDIR/$$DISTDIR/$$F; \ ++ done); \ ++ (cd $$TMPDIR; \ ++ $(PREPARE_CMD); \ ++ find $$TMPDIR/$$DISTDIR -type d -print | xargs chmod 755; \ ++ find $$TMPDIR/$$DISTDIR -type f -print | xargs chmod a+r; \ ++ find $$TMPDIR/$$DISTDIR -type f -perm -0100 -print | xargs chmod a+x; \ ++ $(TAR_COMMAND) $$DISTDIR) \ ++ | (cd $(SRCDIR); gzip --best > $(TARFILE).gz); \ ++ rm -rf $$TMPDIR ++ cd $(SRCDIR); ls -l $(TARFILE).gz ++ ++dist: ++ @$(MAKE) PREPARE_CMD='$(PERL) ./Configure dist' tar ++ ++# Helper targets ##################################################### ++ ++link-utils: $(BLDDIR)/util/opensslwrap.sh ++ ++$(BLDDIR)/util/opensslwrap.sh: configdata.pm ++ @if [ "$(SRCDIR)" != "$(BLDDIR)" ]; then \ ++ mkdir -p "$(BLDDIR)/util"; \ ++ ln -sf "../$(SRCDIR)/util/opensslwrap.sh" "$(BLDDIR)/util"; \ ++ fi ++ ++FORCE: ++ ++# Building targets ################################################### ++ ++libcrypto.pc libssl.pc openssl.pc: configdata.pm $(LIBS) {- join(" ",map { shlib_simple($_) } @{$unified_info{libraries}}) -} ++libcrypto.pc: ++ @ ( echo 'prefix=$(INSTALLTOP)'; \ ++ echo 'exec_prefix=$${prefix}'; \ ++ echo 'libdir=$${exec_prefix}/$(LIBDIR)'; \ ++ echo 'includedir=$${prefix}/include'; \ ++ echo 'enginesdir=$${libdir}/engines-{- $sover -}'; \ ++ echo ''; \ ++ echo 'Name: OpenSSL-libcrypto'; \ ++ echo 'Description: OpenSSL cryptography library'; \ ++ echo 'Version: '$(VERSION); \ ++ echo 'Libs: -L$${libdir} -lcrypto'; \ ++ echo 'Libs.private: $(EX_LIBS)'; \ ++ echo 'Cflags: -I$${includedir}' ) > libcrypto.pc ++ ++libssl.pc: ++ @ ( echo 'prefix=$(INSTALLTOP)'; \ ++ echo 'exec_prefix=$${prefix}'; \ ++ echo 'libdir=$${exec_prefix}/$(LIBDIR)'; \ ++ echo 'includedir=$${prefix}/include'; \ ++ echo ''; \ ++ echo 'Name: OpenSSL-libssl'; \ ++ echo 'Description: Secure Sockets Layer and cryptography libraries'; \ ++ echo 'Version: '$(VERSION); \ ++ echo 'Requires.private: libcrypto'; \ ++ echo 'Libs: -L$${libdir} -lssl'; \ ++ echo 'Libs.private: $(EX_LIBS)'; \ ++ echo 'Cflags: -I$${includedir}' ) > libssl.pc ++ ++openssl.pc: ++ @ ( echo 'prefix=$(INSTALLTOP)'; \ ++ echo 'exec_prefix=$${prefix}'; \ ++ echo 'libdir=$${exec_prefix}/$(LIBDIR)'; \ ++ echo 'includedir=$${prefix}/include'; \ ++ echo ''; \ ++ echo 'Name: OpenSSL'; \ ++ echo 'Description: Secure Sockets Layer and cryptography libraries and tools'; \ ++ echo 'Version: '$(VERSION); \ ++ echo 'Requires: libssl libcrypto' ) > openssl.pc ++ ++configdata.pm: $(SRCDIR)/Configure $(SRCDIR)/config {- join(" ", @{$config{build_file_templates}}, @{$config{build_infos}}, @{$config{conf_files}}) -} ++ @echo "Detected changed: $?" ++ @echo "Reconfiguring..." ++ $(PERL) $(SRCDIR)/Configure reconf ++ @echo "**************************************************" ++ @echo "*** ***" ++ @echo "*** Please run the same make command again ***" ++ @echo "*** ***" ++ @echo "**************************************************" ++ @false ++ ++{- ++ use File::Basename; ++ use File::Spec::Functions qw/:DEFAULT abs2rel rel2abs/; ++ ++ # Helper function to figure out dependencies on libraries ++ # It takes a list of library names and outputs a list of dependencies ++ sub compute_lib_depends { ++ if ($disabled{shared}) { ++ return map { $_.$libext } @_; ++ } ++ ++ # Depending on shared libraries: ++ # On Windows POSIX layers, we depend on {libname}.dll.a ++ # On Unix platforms, we depend on {shlibname}.so ++ return map { shlib_simple($_) } @_; ++ } ++ ++ sub generatesrc { ++ my %args = @_; ++ my $generator = join(" ", @{$args{generator}}); ++ my $generator_incs = join("", map { " -I".$_ } @{$args{generator_incs}}); ++ my $incs = join("", map { " -I".$_ } @{$args{incs}}); ++ my $deps = join(" ", @{$args{generator_deps}}, @{$args{deps}}); ++ ++ if ($args{src} !~ /\.[sS]$/) { ++ if ($args{generator}->[0] =~ m|^.*\.in$|) { ++ my $dofile = abs2rel(rel2abs(catfile($config{sourcedir}, ++ "util", "dofile.pl")), ++ rel2abs($config{builddir})); ++ return <<"EOF"; ++$args{src}: $args{generator}->[0] $deps ++ \$(PERL) "-I\$(BLDDIR)" -Mconfigdata "$dofile" \\ ++ "-o$target{build_file}" $generator > \$@ ++EOF ++ } else { ++ return <<"EOF"; ++$args{src}: $args{generator}->[0] $deps ++ \$(PERL)$generator_incs $generator > \$@ ++EOF ++ } ++ } else { ++ if ($args{generator}->[0] =~ /\.pl$/) { ++ $generator = 'CC="$(CC)" $(PERL)'.$generator_incs.' '.$generator; ++ } elsif ($args{generator}->[0] =~ /\.m4$/) { ++ $generator = 'm4 -B 8192'.$generator_incs.' '.$generator.' >' ++ } elsif ($args{generator}->[0] =~ /\.S$/) { ++ $generator = undef; ++ } else { ++ die "Generator type for $args{src} unknown: $generator\n"; ++ } ++ ++ if (defined($generator)) { ++ # If the target is named foo.S in build.info, we want to ++ # end up generating foo.s in two steps. ++ if ($args{src} =~ /\.S$/) { ++ (my $target = $args{src}) =~ s|\.S$|.s|; ++ return <<"EOF"; ++$target: $args{generator}->[0] $deps ++ ( trap "rm -f \$@.*" INT 0; \\ ++ $generator \$@.S; \\ ++ \$(CC) $incs \$(CFLAGS) -E \$@.S | \\ ++ \$(PERL) -ne '/^#(line)?\\s*[0-9]+/ or print' > \$@.i && \\ ++ mv -f \$@.i \$@ ) ++EOF ++ } ++ # Otherwise.... ++ return <<"EOF"; ++$args{src}: $args{generator}->[0] $deps ++ $generator \$@ ++EOF ++ } ++ return <<"EOF"; ++$args{src}: $args{generator}->[0] $deps ++ \$(CC) $incs \$(CFLAGS) -E \$< | \\ ++ \$(PERL) -ne '/^#(line)?\\s*[0-9]+/ or print' > \$@ ++EOF ++ } ++ } ++ ++ # Should one wonder about the end of the Perl snippet, it's because this ++ # second regexp eats up line endings as well, if the removed path is the ++ # last in the line. We may therefore need to put back a line ending. ++ sub src2obj { ++ my %args = @_; ++ my $obj = $args{obj}; ++ my @srcs = map { if ($unified_info{generate}->{$_}) { ++ (my $x = $_) =~ s/\.S$/.s/; $x ++ } else { ++ $_ ++ } ++ } ( @{$args{srcs}} ); ++ my $srcs = join(" ", @srcs); ++ my $deps = join(" ", @srcs, @{$args{deps}}); ++ my $incs = join("", map { " -I".$_ } @{$args{incs}}); ++ unless ($disabled{zlib}) { ++ if ($withargs{zlib_include}) { ++ $incs .= " -I".$withargs{zlib_include}; ++ } ++ } ++ my $ecflags = { lib => '$(LIB_CFLAGS)', ++ dso => '$(DSO_CFLAGS)', ++ bin => '$(BIN_CFLAGS)' } -> {$args{intent}}; ++ my $makedepprog = $config{makedepprog}; ++ my $recipe = <<"EOF"; ++$obj$objext: $deps ++EOF ++ if (!$disabled{makedepend} && $makedepprog !~ /\/makedepend/) { ++ $recipe .= <<"EOF"; ++ \$(CC) $incs \$(CFLAGS) $ecflags -MMD -MF $obj$depext.tmp -MT \$\@ -c -o \$\@ $srcs ++ \@touch $obj$depext.tmp ++ \@if cmp $obj$depext.tmp $obj$depext > /dev/null 2> /dev/null; then \\ ++ rm -f $obj$depext.tmp; \\ ++ else \\ ++ mv $obj$depext.tmp $obj$depext; \\ ++ fi ++EOF ++ } else { ++ $recipe .= <<"EOF"; ++ \$(CC) $incs \$(CFLAGS) $ecflags -c -o \$\@ $srcs ++EOF ++ if (!$disabled{makedepend} && $makedepprog =~ /\/makedepend/) { ++ $recipe .= <<"EOF"; ++ -\$(MAKEDEPEND) -f- -o"|\$\@" -- $incs \$(CFLAGS) $ecflags -- $srcs \\ ++ >$obj$depext.tmp 2>/dev/null ++ -\$(PERL) -i -pe 's/^.*\\|//; s/ \\/(\\\\.|[^ ])*//; \$\$_ = undef if (/: *\$\$/ || /^(#.*| *)\$\$/); \$\$_.="\\n" unless !defined(\$\$_) or /\\R\$\$/g;' $obj$depext.tmp ++ \@if cmp $obj$depext.tmp $obj$depext > /dev/null 2> /dev/null; then \\ ++ rm -f $obj$depext.tmp; \\ ++ else \\ ++ mv $obj$depext.tmp $obj$depext; \\ ++ fi ++EOF ++ } ++ } ++ return $recipe; ++ } ++ # On Unix, we build shlibs from static libs, so we're ignoring the ++ # object file array. We *know* this routine is only called when we've ++ # configure 'shared'. ++ sub libobj2shlib { ++ my %args = @_; ++ my $lib = $args{lib}; ++ my $shlib = $args{shlib}; ++ my $libd = dirname($lib); ++ my $libn = basename($lib); ++ (my $libname = $libn) =~ s/^lib//; ++ my $linklibs = join("", map { my $d = dirname($_); ++ my $f = basename($_); ++ (my $l = $f) =~ s/^lib//; ++ " -L$d -l$l" } @{$args{deps}}); ++ my $deps = join(" ",compute_lib_depends(@{$args{deps}})); ++ my $shlib_target = $target{shared_target}; ++ my $ordinalsfile = defined($args{ordinals}) ? $args{ordinals}->[1] : ""; ++ my $target = shlib_simple($lib); ++ return <<"EOF" ++# With a build on a Windows POSIX layer (Cygwin or Mingw), we know for a fact ++# that two files get produced, {shlibname}.dll and {libname}.dll.a. ++# With all other Unix platforms, we often build a shared library with the ++# SO version built into the file name and a symlink without the SO version ++# It's not necessary to have both as targets. The choice falls on the ++# simplest, {libname}$shlibextimport for Windows POSIX layers and ++# {libname}$shlibextsimple for the Unix platforms. ++$target: $lib$libext $deps $ordinalsfile ++ \$(MAKE) -f \$(SRCDIR)/Makefile.shared -e \\ ++ PLATFORM=\$(PLATFORM) \\ ++ PERL="\$(PERL)" SRCDIR='\$(SRCDIR)' DSTDIR="$libd" \\ ++ INSTALLTOP='\$(INSTALLTOP)' LIBDIR='\$(LIBDIR)' \\ ++ LIBDEPS='\$(PLIB_LDFLAGS) '"$linklibs"' \$(EX_LIBS)' \\ ++ LIBNAME=$libname LIBVERSION=\$(SHLIB_MAJOR).\$(SHLIB_MINOR) \\ ++ LIBCOMPATVERSIONS=';\$(SHLIB_VERSION_HISTORY)' \\ ++ CC='\$(CC)' CFLAGS='\$(CFLAGS) \$(LIB_CFLAGS)' \\ ++ LDFLAGS='\$(LDFLAGS)' \\ ++ SHARED_LDFLAGS='\$(LIB_LDFLAGS)' SHLIB_EXT=$shlibext \\ ++ RC='\$(RC)' SHARED_RCFLAGS='\$(RCFLAGS)' \\ ++ link_shlib.$shlib_target ++EOF ++ . (windowsdll() ? <<"EOF" : ""); ++ rm -f apps/$shlib$shlibext ++ rm -f test/$shlib$shlibext ++ cp -p $shlib$shlibext apps/ ++ cp -p $shlib$shlibext test/ ++EOF ++ } ++ sub obj2dso { ++ my %args = @_; ++ my $lib = $args{lib}; ++ my $libd = dirname($lib); ++ my $libn = basename($lib); ++ (my $libname = $libn) =~ s/^lib//; ++ my $shlibdeps = join("", map { my $d = dirname($_); ++ my $f = basename($_); ++ (my $l = $f) =~ s/^lib//; ++ " -L$d -l$l" } @{$args{deps}}); ++ my $deps = join(" ",compute_lib_depends(@{$args{deps}})); ++ my $shlib_target = $target{shared_target}; ++ my $objs = join(" ", map { $_.$objext } @{$args{objs}}); ++ my $target = dso($lib); ++ return <<"EOF"; ++$target: $objs $deps ++ \$(MAKE) -f \$(SRCDIR)/Makefile.shared -e \\ ++ PLATFORM=\$(PLATFORM) \\ ++ PERL="\$(PERL)" SRCDIR='\$(SRCDIR)' DSTDIR="$libd" \\ ++ LIBDEPS='\$(PLIB_LDFLAGS) '"$shlibdeps"' \$(EX_LIBS)' \\ ++ LIBNAME=$libname LDFLAGS='\$(LDFLAGS)' \\ ++ CC='\$(CC)' CFLAGS='\$(CFLAGS) \$(DSO_CFLAGS)' \\ ++ SHARED_LDFLAGS='\$(DSO_LDFLAGS)' \\ ++ SHLIB_EXT=$dsoext \\ ++ LIBEXTRAS="$objs" \\ ++ link_dso.$shlib_target ++EOF ++ } ++ sub obj2lib { ++ my %args = @_; ++ my $lib = $args{lib}; ++ my $objs = join(" ", map { $_.$objext } @{$args{objs}}); ++ return <<"EOF"; ++$lib$libext: $objs ++ \$(AR) \$\@ \$\? ++ \$(RANLIB) \$\@ || echo Never mind. ++EOF ++ } ++ sub obj2bin { ++ my %args = @_; ++ my $bin = $args{bin}; ++ my $bind = dirname($bin); ++ my $binn = basename($bin); ++ my $objs = join(" ", map { $_.$objext } @{$args{objs}}); ++ my $deps = join(" ",compute_lib_depends(@{$args{deps}})); ++ my $linklibs = join("", map { my $d = dirname($_); ++ my $f = basename($_); ++ $d = "." if $d eq $f; ++ (my $l = $f) =~ s/^lib//; ++ " -L$d -l$l" } @{$args{deps}}); ++ my $shlib_target = $disabled{shared} ? "" : $target{shared_target}; ++ return <<"EOF"; ++$bin$exeext: $objs $deps ++ \$(RM) $bin$exeext ++ \$(MAKE) -f \$(SRCDIR)/Makefile.shared -e \\ ++ PERL="\$(PERL)" SRCDIR=\$(SRCDIR) \\ ++ APPNAME=$bin$exeext OBJECTS="$objs" \\ ++ LIBDEPS='\$(PLIB_LDFLAGS) '"$linklibs"' \$(EX_LIBS)' \\ ++ CC='\$(CC)' CFLAGS='\$(CFLAGS) \$(BIN_CFLAGS)' \\ ++ LDFLAGS='\$(LDFLAGS)' \\ ++ link_app.$shlib_target ++EOF ++ } ++ sub in2script { ++ my %args = @_; ++ my $script = $args{script}; ++ my $sources = join(" ", @{$args{sources}}); ++ my $dofile = abs2rel(rel2abs(catfile($config{sourcedir}, ++ "util", "dofile.pl")), ++ rel2abs($config{builddir})); ++ return <<"EOF"; ++$script: $sources ++ \$(PERL) "-I\$(BLDDIR)" -Mconfigdata "$dofile" \\ ++ "-o$target{build_file}" $sources > "$script" ++ chmod a+x $script ++EOF ++ } ++ sub generatedir { ++ my %args = @_; ++ my $dir = $args{dir}; ++ my @deps = map { s|\.o$|$objext|; $_ } @{$args{deps}}; ++ my @actions = (); ++ my %extinfo = ( dso => $dsoext, ++ lib => $libext, ++ bin => $exeext ); ++ ++ foreach my $type (("dso", "lib", "bin", "script")) { ++ next unless defined($unified_info{dirinfo}->{$dir}->{products}->{$type}); ++ # For lib object files, we could update the library. However, it ++ # was decided that it's enough to build the directory local object ++ # files, so we don't need to add any actions, and the dependencies ++ # are already taken care of. ++ if ($type ne "lib") { ++ foreach my $prod (@{$unified_info{dirinfo}->{$dir}->{products}->{$type}}) { ++ if (dirname($prod) eq $dir) { ++ push @deps, $prod.$extinfo{$type}; ++ } else { ++ push @actions, "\t@ : No support to produce $type ".join(", ", @{$unified_info{dirinfo}->{$dir}->{products}->{$type}}); ++ } ++ } ++ } ++ } ++ ++ my $deps = join(" ", @deps); ++ my $actions = join("\n", "", @actions); ++ return <<"EOF"; ++$args{dir} $args{dir}/: $deps$actions ++EOF ++ } ++ "" # Important! This becomes part of the template result. ++-} +diff --git a/CryptoPkg/Library/OpensslLib/openssl/Configurations/windows-makefile.tmpl b/CryptoPkg/Library/OpensslLib/openssl/Configurations/windows-makefile.tmpl +new file mode 100644 +index 0000000..1d7e666 +--- /dev/null ++++ b/CryptoPkg/Library/OpensslLib/openssl/Configurations/windows-makefile.tmpl +@@ -0,0 +1,601 @@ ++## ++## Makefile for OpenSSL ++## ++## {- join("\n## ", @autowarntext) -} ++{- ++ our $objext = $target{obj_extension} || ".obj"; ++ our $depext = $target{dep_extension} || ".d"; ++ our $exeext = $target{exe_extension} || ".exe"; ++ our $libext = $target{lib_extension} || ".lib"; ++ our $shlibext = $target{shared_extension} || ".dll"; ++ our $shlibextimport = $target{shared_import_extension} || ".lib"; ++ our $dsoext = $target{dso_extension} || ".dll"; ++ ++ our $sover = $config{shlib_major}."_".$config{shlib_minor}; ++ ++ my $win_installenv = ++ $target{build_scheme}->[2] eq "VC-W32" ? ++ "ProgramFiles(x86)" : "ProgramW6432"; ++ my $win_commonenv = ++ $target{build_scheme}->[2] eq "VC-W32" ++ ? "CommonProgramFiles(x86)" : "CommonProgramW6432"; ++ our $win_installroot = ++ defined($ENV{$win_installenv}) ++ ? $win_installenv : 'ProgramFiles'; ++ our $win_commonroot = ++ defined($ENV{$win_commonenv}) ++ ? $win_commonenv : 'CommonProgramFiles'; ++ ++ # expand variables early ++ $win_installroot = $ENV{$win_installroot}; ++ $win_commonroot = $ENV{$win_commonroot}; ++ ++ sub shlib { ++ return () if $disabled{shared}; ++ my $lib = shift; ++ return $unified_info{sharednames}->{$lib} . $shlibext; ++ } ++ ++ sub shlib_import { ++ return () if $disabled{shared}; ++ my $lib = shift; ++ return $lib . $shlibextimport; ++ } ++ ++ sub dso { ++ my $dso = shift; ++ ++ return $dso . $dsoext; ++ } ++ ''; ++-} ++ ++PLATFORM={- $config{target} -} ++SRCDIR={- $config{sourcedir} -} ++BLDDIR={- $config{builddir} -} ++ ++VERSION={- $config{version} -} ++MAJOR={- $config{major} -} ++MINOR={- $config{minor} -} ++ ++SHLIB_VERSION_NUMBER={- $config{shlib_version_number} -} ++ ++LIBS={- join(" ", map { $_.$libext } @{$unified_info{libraries}}) -} ++SHLIBS={- join(" ", map { shlib($_) } @{$unified_info{libraries}}) -} ++SHLIBPDBS={- join(" ", map { local $shlibext = ".pdb"; shlib($_) } @{$unified_info{libraries}}) -} ++ENGINES={- join(" ", map { dso($_) } @{$unified_info{engines}}) -} ++ENGINEPDBS={- join(" ", map { local $dsoext = ".pdb"; dso($_) } @{$unified_info{engines}}) -} ++PROGRAMS={- join(" ", map { $_.$exeext } @{$unified_info{programs}}) -} ++PROGRAMPDBS={- join(" ", map { $_.".pdb" } @{$unified_info{programs}}) -} ++SCRIPTS={- join(" ", @{$unified_info{scripts}}) -} ++{- output_off() if $disabled{makedepend}; "" -} ++DEPS={- join(" ", map { (my $x = $_) =~ s|\.o$|$depext|; $x; } ++ grep { $unified_info{sources}->{$_}->[0] =~ /\.c$/ } ++ keys %{$unified_info{sources}}); -} ++{- output_on() if $disabled{makedepend}; "" -} ++GENERATED_MANDATORY={- join(" ", @{$unified_info{depends}->{""}} ) -} ++GENERATED={- join(" ", ++ ( map { (my $x = $_) =~ s|\.[sS]$|\.asm|; $x } ++ grep { defined $unified_info{generate}->{$_} } ++ map { @{$unified_info{sources}->{$_}} } ++ grep { /\.o$/ } keys %{$unified_info{sources}} ), ++ ( grep { /\.h$/ } keys %{$unified_info{generate}} )) -} ++ ++INSTALL_LIBS={- join(" ", map { $_.$libext } @{$unified_info{install}->{libraries}}) -} ++INSTALL_SHLIBS={- join(" ", map { shlib($_) } @{$unified_info{install}->{libraries}}) -} ++INSTALL_SHLIBPDBS={- join(" ", map { local $shlibext = ".pdb"; shlib($_) } @{$unified_info{install}->{libraries}}) -} ++INSTALL_ENGINES={- join(" ", map { dso($_) } @{$unified_info{install}->{engines}}) -} ++INSTALL_ENGINEPDBS={- join(" ", map { local $dsoext = ".pdb"; dso($_) } @{$unified_info{install}->{engines}}) -} ++INSTALL_PROGRAMS={- join(" ", map { $_.$exeext } grep { !m|^test\\| } @{$unified_info{install}->{programs}}) -} ++INSTALL_PROGRAMPDBS={- join(" ", map { $_.".pdb" } grep { !m|^test\\| } @{$unified_info{install}->{programs}}) -} ++{- output_off() if $disabled{apps}; "" -} ++BIN_SCRIPTS=$(BLDDIR)\tools\c_rehash.pl ++MISC_SCRIPTS=$(BLDDIR)\apps\CA.pl $(BLDDIR)\apps\tsget.pl ++{- output_on() if $disabled{apps}; "" -} ++ ++# Do not edit these manually. Use Configure with --prefix or --openssldir ++# to change this! Short explanation in the top comment in Configure ++INSTALLTOP_dev={- # $prefix is used in the OPENSSLDIR perl snippet ++ # ++ use File::Spec::Functions qw(:DEFAULT splitpath); ++ our $prefix = $config{prefix} || "$win_installroot\\OpenSSL"; ++ our ($prefix_dev, $prefix_dir, $prefix_file) = ++ splitpath($prefix, 1); ++ $prefix_dev -} ++INSTALLTOP_dir={- $prefix_dir -} ++OPENSSLDIR_dev={- # ++ # The logic here is that if no --openssldir was given, ++ # OPENSSLDIR will get the value from $prefix plus "/ssl". ++ # If --openssldir was given and the value is an absolute ++ # path, OPENSSLDIR will get its value without change. ++ # If the value from --openssldir is a relative path, ++ # OPENSSLDIR will get $prefix with the --openssldir ++ # value appended as a subdirectory. ++ # ++ use File::Spec::Functions qw(:DEFAULT splitpath); ++ our $openssldir = ++ $config{openssldir} ? ++ (file_name_is_absolute($config{openssldir}) ? ++ $config{openssldir} ++ : catdir($prefix, $config{openssldir})) ++ : "$win_commonroot\\SSL"; ++ our ($openssldir_dev, $openssldir_dir, $openssldir_file) = ++ splitpath($openssldir, 1); ++ $openssldir_dev -} ++OPENSSLDIR_dir={- $openssldir_dir -} ++LIBDIR={- our $libdir = $config{libdir} || "lib"; ++ $libdir -} ++ENGINESDIR_dev={- use File::Spec::Functions qw(:DEFAULT splitpath); ++ our $enginesdir = catdir($prefix,$libdir,"engines-$sover"); ++ our ($enginesdir_dev, $enginesdir_dir, $enginesdir_file) = ++ splitpath($enginesdir, 1); ++ $enginesdir_dev -} ++ENGINESDIR_dir={- $enginesdir_dir -} ++!IF "$(DESTDIR)" != "" ++INSTALLTOP=$(DESTDIR)$(INSTALLTOP_dir) ++OPENSSLDIR=$(DESTDIR)$(OPENSSLDIR_dir) ++ENGINESDIR=$(DESTDIR)$(ENGINESDIR_dir) ++!ELSE ++INSTALLTOP=$(INSTALLTOP_dev)$(INSTALLTOP_dir) ++OPENSSLDIR=$(OPENSSLDIR_dev)$(OPENSSLDIR_dir) ++ENGINESDIR=$(ENGINESDIR_dev)$(ENGINESDIR_dir) ++!ENDIF ++ ++CC={- $target{cc} -} ++CFLAGS={- join(" ",(map { "-D".$_} @{$target{defines}}, @{$config{defines}})) -} {- join(" ", quotify_l("-DENGINESDIR=\"$enginesdir\"", "-DOPENSSLDIR=\"$openssldir\"")) -} {- $target{cflags} -} {- $config{cflags} -} ++COUTFLAG={- $target{coutflag} || "/Fo" -}$(OSSL_EMPTY) ++RC={- $target{rc} || "rc" -} ++RCOUTFLAG={- $target{rcoutflag} || "/fo" -}$(OSSL_EMPTY) ++LD={- $target{ld} || "link" -} ++LDFLAGS={- $target{lflags} -} ++LDOUTFLAG={- $target{loutflag} || "/out:" -}$(OSSL_EMPTY) ++EX_LIBS={- $target{ex_libs} -} ++LIB_CFLAGS={- join(" ", $target{lib_cflags}, $target{shared_cflag}) || "" -} ++LIB_LDFLAGS={- $target{shared_ldflag} || "" -} ++DSO_CFLAGS={- join(" ", $target{dso_cflags}, $target{shared_cflag}) || "" -} ++DSO_LDFLAGS={- join(" ", $target{dso_lflags}, $target{shared_ldflag}) || "" -} ++BIN_CFLAGS={- $target{bin_cflags} -} ++BIN_LDFLAGS={- $target{bin_lflags} -} ++ ++PERL={- $config{perl} -} ++ ++AR={- $target{ar} -} ++ARFLAGS= {- $target{arflags} -} ++AROUTFLAG={- $target{aroutflag} || "/out:" -}$(OSSL_EMPTY) ++ ++MT={- $target{mt} -} ++MTFLAGS= {- $target{mtflags} -} ++MTINFLAG={- $target{mtinflag} || "-manifest " -}$(OSSL_EMPTY) ++MTOUTFLAG={- $target{mtoutflag} || "-outputresource:" -}$(OSSL_EMPTY) ++ ++AS={- $target{as} -} ++ASFLAGS={- $target{asflags} -} ++ASOUTFLAG={- $target{asoutflag} -}$(OSSL_EMPTY) ++PERLASM_SCHEME= {- $target{perlasm_scheme} -} ++ ++PROCESSOR= {- $config{processor} -} ++ ++# The main targets ################################################### ++ ++all: build_generated \ ++ build_libs_nodep build_engines_nodep build_programs_nodep depend ++ ++build_libs: build_generated build_libs_nodep depend ++build_libs_nodep: $(LIBS) {- join(" ",map { shlib_import($_) } @{$unified_info{libraries}}) -} ++build_engines: build_generated build_engines_nodep depend ++build_engines_nodep: $(ENGINES) ++build_programs: build_generated build_programs_nodep depend ++build_programs_nodep: $(PROGRAMS) $(SCRIPTS) ++ ++build_generated: $(GENERATED_MANDATORY) ++ ++# Kept around for backward compatibility ++build_apps build_tests: build_programs ++ ++test: tests ++tests: build_generated build_programs_nodep build_engines_nodep depend ++ @rem {- output_off() if $disabled{tests}; "" -} ++ set SRCTOP=$(SRCDIR) ++ set BLDTOP=$(BLDDIR) ++ set PERL=$(PERL) ++ set OPENSSL_DEBUG_MEMORY=on ++ "$(PERL)" "$(SRCDIR)\test\run_tests.pl" $(TESTS) ++ @rem {- if ($disabled{tests}) { output_on(); } else { output_off(); } "" -} ++ @echo "Tests are not supported with your chosen Configure options" ++ @rem {- output_on() if !$disabled{tests}; "" -} ++ ++list-tests: ++ @rem {- output_off() if $disabled{tests}; "" -} ++ @set SRCTOP=$(SRCDIR) ++ @"$(PERL)" "$(SRCDIR)\test\run_tests.pl" list ++ @rem {- if ($disabled{tests}) { output_on(); } else { output_off(); } "" -} ++ @echo "Tests are not supported with your chosen Configure options" ++ @rem {- output_on() if !$disabled{tests}; "" -} ++ ++install: install_sw install_ssldirs install_docs ++ ++uninstall: uninstall_docs uninstall_sw ++ ++libclean: ++ "$(PERL)" -e "map { m/(.*)\.dll$$/; unlink glob """$$1.*"""; } @ARGV" $(SHLIBS) ++ "$(PERL)" -e "map { m/(.*)\.dll$$/; unlink glob """apps/$$1.*"""; } @ARGV" $(SHLIBS) ++ "$(PERL)" -e "map { m/(.*)\.dll$$/; unlink glob """test/$$1.*"""; } @ARGV" $(SHLIBS) ++ -del /Q /F $(LIBS) ++ -del /Q ossl_static.pdb ++ ++clean: libclean ++ -del /Q /F $(PROGRAMS) $(ENGINES) $(SCRIPTS) ++ -del /Q /F $(GENERATED) ++ -del /Q /S /F *.d ++ -del /Q /S /F *.obj ++ -del /Q /S /F *.pdb ++ -del /Q /S /F *.exp ++ -del /Q /S /F engines\*.ilk ++ -del /Q /S /F engines\*.lib ++ -del /Q /S /F apps\*.lib ++ -del /Q /S /F engines\*.manifest ++ -del /Q /S /F apps\*.manifest ++ -del /Q /S /F test\*.manifest ++ ++distclean: clean ++ -del /Q /F configdata.pm ++ -del /Q /F makefile ++ ++depend: ++ ++# Install helper targets ############################################# ++ ++install_sw: all install_dev install_engines install_runtime ++ ++uninstall_sw: uninstall_runtime uninstall_engines uninstall_dev ++ ++install_docs: install_html_docs ++ ++uninstall_docs: uninstall_html_docs ++ ++install_ssldirs: ++ @"$(PERL)" "$(SRCDIR)\util\mkdir-p.pl" "$(OPENSSLDIR)\certs" ++ @"$(PERL)" "$(SRCDIR)\util\mkdir-p.pl" "$(OPENSSLDIR)\private" ++ @"$(PERL)" "$(SRCDIR)\util\mkdir-p.pl" "$(OPENSSLDIR)\misc" ++ @"$(PERL)" "$(SRCDIR)\util\copy.pl" "$(SRCDIR)\apps\openssl.cnf" \ ++ "$(OPENSSLDIR)\openssl.cnf.dist" ++ @IF NOT EXIST "$(OPENSSLDIR)\openssl.cnf" \ ++ "$(PERL)" "$(SRCDIR)\util\copy.pl" "$(SRCDIR)\apps\openssl.cnf" \ ++ "$(OPENSSLDIR)\openssl.cnf" ++ @"$(PERL)" "$(SRCDIR)\util\copy.pl" $(MISC_SCRIPTS) \ ++ "$(OPENSSLDIR)\misc" ++ ++install_dev: ++ @if "$(INSTALLTOP)"=="" ( echo INSTALLTOP should not be empty & exit 1 ) ++ @echo *** Installing development files ++ @"$(PERL)" "$(SRCDIR)\util\mkdir-p.pl" "$(INSTALLTOP)\include\openssl" ++ @rem {- output_off() unless grep { $_ eq "OPENSSL_USE_APPLINK" } @{$target{defines}}; "" -} ++ @"$(PERL)" "$(SRCDIR)\util\copy.pl" "$(SRCDIR)\ms\applink.c" \ ++ "$(INSTALLTOP)\include\openssl" ++ @rem {- output_on() unless grep { $_ eq "OPENSSL_USE_APPLINK" } @{$target{defines}}; "" -} ++ @"$(PERL)" "$(SRCDIR)\util\copy.pl" "$(SRCDIR)\include\openssl\*.h" \ ++ "$(INSTALLTOP)\include\openssl" ++ @"$(PERL)" "$(SRCDIR)\util\copy.pl" $(BLDDIR)\include\openssl\*.h \ ++ "$(INSTALLTOP)\include\openssl" ++ @"$(PERL)" "$(SRCDIR)\util\mkdir-p.pl" "$(INSTALLTOP)\$(LIBDIR)" ++ @"$(PERL)" "$(SRCDIR)\util\copy.pl" $(INSTALL_LIBS) \ ++ "$(INSTALLTOP)\$(LIBDIR)" ++ @if "$(SHLIBS)"=="" \ ++ "$(PERL)" "$(SRCDIR)\util\copy.pl" ossl_static.pdb \ ++ "$(INSTALLTOP)\$(LIBDIR)" ++ ++uninstall_dev: ++ ++install_engines: ++ @if "$(INSTALLTOP)"=="" ( echo INSTALLTOP should not be empty & exit 1 ) ++ @echo *** Installing engines ++ @"$(PERL)" "$(SRCDIR)\util\mkdir-p.pl" "$(ENGINESDIR)" ++ @if not "$(ENGINES)"=="" \ ++ "$(PERL)" "$(SRCDIR)\util\copy.pl" $(INSTALL_ENGINES) "$(ENGINESDIR)" ++ @if not "$(ENGINES)"=="" \ ++ "$(PERL)" "$(SRCDIR)\util\copy.pl" $(INSTALL_ENGINEPDBS) "$(ENGINESDIR)" ++ ++uninstall_engines: ++ ++install_runtime: ++ @if "$(INSTALLTOP)"=="" ( echo INSTALLTOP should not be empty & exit 1 ) ++ @echo *** Installing runtime files ++ @"$(PERL)" "$(SRCDIR)\util\mkdir-p.pl" "$(INSTALLTOP)\bin" ++ @if not "$(SHLIBS)"=="" \ ++ "$(PERL)" "$(SRCDIR)\util\copy.pl" $(INSTALL_SHLIBS) "$(INSTALLTOP)\bin" ++ @if not "$(SHLIBS)"=="" \ ++ "$(PERL)" "$(SRCDIR)\util\copy.pl" $(INSTALL_SHLIBPDBS) \ ++ "$(INSTALLTOP)\bin" ++ @"$(PERL)" "$(SRCDIR)\util\copy.pl" $(INSTALL_PROGRAMS) \ ++ "$(INSTALLTOP)\bin" ++ @"$(PERL)" "$(SRCDIR)\util\copy.pl" $(INSTALL_PROGRAMPDBS) \ ++ "$(INSTALLTOP)\bin" ++ @"$(PERL)" "$(SRCDIR)\util\copy.pl" $(BIN_SCRIPTS) \ ++ "$(INSTALLTOP)\bin" ++ ++uninstall_runtime: ++ ++install_html_docs: ++ "$(PERL)" "$(SRCDIR)\util\process_docs.pl" \ ++ "--destdir=$(INSTALLTOP)\html" --type=html ++ ++uninstall_html_docs: ++ ++# Building targets ################################################### ++ ++configdata.pm: "$(SRCDIR)\Configure" {- join(" ", map { '"'.$_.'"' } @{$config{build_file_templates}}, @{$config{build_infos}}, @{$config{conf_files}}) -} ++ @echo "Detected changed: $?" ++ @echo "Reconfiguring..." ++ "$(PERL)" "$(SRCDIR)\Configure" reconf ++ @echo "**************************************************" ++ @echo "*** ***" ++ @echo "*** Please run the same make command again ***" ++ @echo "*** ***" ++ @echo "**************************************************" ++ @exit 1 ++ ++{- ++ use File::Basename; ++ use File::Spec::Functions qw/:DEFAULT abs2rel rel2abs/; ++ ++ # Helper function to figure out dependencies on libraries ++ # It takes a list of library names and outputs a list of dependencies ++ sub compute_lib_depends { ++ if ($disabled{shared}) { ++ return map { $_.$libext } @_; ++ } ++ return map { shlib_import($_) } @_; ++ } ++ ++ sub generatesrc { ++ my %args = @_; ++ (my $target = $args{src}) =~ s/\.[sS]$/.asm/; ++ my $generator = '"'.join('" "', @{$args{generator}}).'"'; ++ my $generator_incs = join("", map { " -I \"$_\"" } @{$args{generator_incs}}); ++ my $incs = join("", map { " /I \"$_\"" } @{$args{incs}}); ++ my $deps = @{$args{deps}} ? ++ '"'.join('" "', @{$args{generator_deps}}, @{$args{deps}}).'"' : ''; ++ ++ if ($target !~ /\.asm$/) { ++ if ($args{generator}->[0] =~ m|^.*\.in$|) { ++ my $dofile = abs2rel(rel2abs(catfile($config{sourcedir}, ++ "util", "dofile.pl")), ++ rel2abs($config{builddir})); ++ return <<"EOF"; ++$target: "$args{generator}->[0]" $deps ++ "\$(PERL)" "-I\$(BLDDIR)" -Mconfigdata "$dofile" \\ ++ "-o$target{build_file}" $generator > \$@ ++EOF ++ } else { ++ return <<"EOF"; ++$target: "$args{generator}->[0]" $deps ++ "\$(PERL)"$generator_incs $generator > \$@ ++EOF ++ } ++ } else { ++ if ($args{generator}->[0] =~ /\.pl$/) { ++ $generator = '"$(PERL)"'.$generator_incs.' '.$generator; ++ } elsif ($args{generator}->[0] =~ /\.S$/) { ++ $generator = undef; ++ } else { ++ die "Generator type for $src unknown: $generator\n"; ++ } ++ ++ if (defined($generator)) { ++ # If the target is named foo.S in build.info, we want to ++ # end up generating foo.s in two steps. ++ if ($args{src} =~ /\.S$/) { ++ return <<"EOF"; ++$target: "$args{generator}->[0]" $deps ++ set ASM=\$(AS) ++ $generator \$@.S ++ \$(CC) $incs \$(CFLAGS) /EP /C \$@.S > \$@.i && move /Y \$@.i \$@ ++ del /Q \$@.S ++EOF ++ } ++ # Otherwise.... ++ return <<"EOF"; ++$target: "$args{generator}->[0]" $deps ++ set ASM=\$(AS) ++ $generator \$@ ++EOF ++ } ++ return <<"EOF"; ++$target: "$args{generator}->[0]" $deps ++ \$(CC) $incs \$(CFLAGS) /EP /C "$args{generator}->[0]" > \$@.i && move /Y \$@.i \$@ ++EOF ++ } ++ } ++ ++ sub src2obj { ++ my %args = @_; ++ my $obj = $args{obj}; ++ my @srcs = map { (my $x = $_) =~ s/\.s$/.asm/; $x ++ } ( @{$args{srcs}} ); ++ my $srcs = '"'.join('" "', @srcs).'"'; ++ my $deps = '"'.join('" "', @srcs, @{$args{deps}}).'"'; ++ my $incs = join("", map { ' /I "'.$_.'"' } @{$args{incs}}); ++ unless ($disabled{zlib}) { ++ if ($withargs{zlib_include}) { ++ $incs .= ' /I "'.$withargs{zlib_include}.'"'; ++ } ++ } ++ my $ecflags = { lib => '$(LIB_CFLAGS)', ++ dso => '$(DSO_CFLAGS)', ++ bin => '$(BIN_CFLAGS)' } -> {$args{intent}}; ++ my $makedepprog = $config{makedepprog}; ++ if ($srcs[0] =~ /\.asm$/) { ++ return <<"EOF"; ++$obj$objext: $deps ++ \$(AS) \$(ASFLAGS) \$(ASOUTFLAG)\$\@ $srcs ++EOF ++ } ++ return <<"EOF" if (!$disabled{makedepend}); ++$obj$depext: $deps ++ \$(CC) \$(CFLAGS) $ecflags$inc /Zs /showIncludes $srcs 2>&1 | \\ ++ "\$(PERL)" -n << > $obj$depext ++chomp; ++s/^Note: including file: *//; ++\$\$collect{\$\$_} = 1; ++END { print '$obj$objext: ',join(" ", sort keys \%collect),"\\n" } ++<< ++$obj$objext: $obj$depext ++ \$(CC) $incs \$(CFLAGS) $ecflags -c \$(COUTFLAG)\$\@ @<< ++$srcs ++<< ++EOF ++ return <<"EOF" if ($disabled{makedepend}); ++$obj$objext: $deps ++ \$(CC) $incs \$(CFLAGS) $ecflags -c \$(COUTFLAG)\$\@ $srcs ++EOF ++ } ++ ++ # On Unix, we build shlibs from static libs, so we're ignoring the ++ # object file array. We *know* this routine is only called when we've ++ # configure 'shared'. ++ sub libobj2shlib { ++ my %args = @_; ++ my $lib = $args{lib}; ++ my $shlib = $args{shlib}; ++ (my $mkdef_key = $lib) =~ s/^lib//i; ++ my $objs = join("\n", map { $_.$objext } @{$args{objs}}); ++ my $linklibs = join("", ++ map { "\n$_" } compute_lib_depends(@{$args{deps}})); ++ my $deps = join(" ", ++ (map { $_.$objext } @{$args{objs}}), ++ compute_lib_depends(@{$args{deps}})); ++ my $ordinalsfile = defined($args{ordinals}) ? $args{ordinals}->[1] : ""; ++ my $mkdef_pl = abs2rel(rel2abs(catfile($config{sourcedir}, ++ "util", "mkdef.pl")), ++ rel2abs($config{builddir})); ++ my $mkrc_pl = abs2rel(rel2abs(catfile($config{sourcedir}, ++ "util", "mkrc.pl")), ++ rel2abs($config{builddir})); ++ my $target = shlib_import($lib); ++ return <<"EOF" ++$target: $deps "$ordinalsfile" "$mkdef_pl" ++ "\$(PERL)" "$mkdef_pl" "$mkdef_key" 32 > $shlib.def ++ "\$(PERL)" -i.tmp -pe "s|^LIBRARY\\s+${mkdef_key}32|LIBRARY $shlib|;" $shlib.def ++ DEL $shlib.def.tmp ++ "\$(PERL)" "$mkrc_pl" $shlib$shlibext > $shlib.rc ++ \$(RC) \$(RCOUTFLAG)$shlib.res $shlib.rc ++ IF EXIST $shlib$shlibext.manifest DEL /F /Q $shlib$shlibext.manifest ++ \$(LD) \$(LDFLAGS) \$(LIB_LDFLAGS) \\ ++ /implib:\$@ \$(LDOUTFLAG)$shlib$shlibext /def:$shlib.def @<< || (DEL /Q \$(\@B).* $shlib.* && EXIT 1) ++$objs $shlib.res$linklibs \$(EX_LIBS) ++<< ++ IF EXIST $shlib$shlibext.manifest \\ ++ \$(MT) \$(MTFLAGS) \$(MTINFLAG)$shlib$shlibext.manifest \$(MTOUTFLAG)$shlib$shlibext ++ IF EXIST apps\\$shlib$shlibext DEL /Q /F apps\\$shlib$shlibext ++ IF EXIST test\\$shlib$shlibext DEL /Q /F test\\$shlib$shlibext ++ COPY $shlib$shlibext apps ++ COPY $shlib$shlibext test ++EOF ++ } ++ sub obj2dso { ++ my %args = @_; ++ my $dso = $args{lib}; ++ my $dso_n = basename($dso); ++ my $objs = join("\n", map { $_.$objext } @{$args{objs}}); ++ my $linklibs = join("", ++ map { "\n$_" } compute_lib_depends(@{$args{deps}})); ++ my $deps = join(" ", ++ (map { $_.$objext } @{$args{objs}}), ++ compute_lib_depends(@{$args{deps}})); ++ return <<"EOF"; ++$dso$dsoext: $deps ++ IF EXIST $dso$dsoext.manifest DEL /F /Q $dso$dsoext.manifest ++ \$(LD) \$(LDFLAGS) \$(DSO_LDFLAGS) \$(LDOUTFLAG)$dso$dsoext /def:<< @<< ++LIBRARY $dso_n ++EXPORTS ++ bind_engine @1 ++ v_check @2 ++<< ++$objs$linklibs \$(EX_LIBS) ++<< ++ IF EXIST $dso$dsoext.manifest \\ ++ \$(MT) \$(MTFLAGS) \$(MTINFLAG)$dso$dsoext.manifest \$(MTOUTFLAG)$dso$dsoext ++EOF ++ } ++ sub obj2lib { ++ # Because static libs and import libs are both named the same in native ++ # Windows, we can't have both. We skip the static lib in that case, ++ # as the shared libs are what we use anyway. ++ return "" unless $disabled{"shared"}; ++ ++ my %args = @_; ++ my $lib = $args{lib}; ++ my $objs = join("\n", map { $_.$objext } @{$args{objs}}); ++ my $deps = join(" ", map { $_.$objext } @{$args{objs}}); ++ return <<"EOF"; ++$lib$libext: $deps ++ \$(AR) \$(ARFLAGS) \$(AROUTFLAG)$lib$libext @<< ++\$** ++<< ++EOF ++ } ++ sub obj2bin { ++ my %args = @_; ++ my $bin = $args{bin}; ++ my $objs = join("\n", map { $_.$objext } @{$args{objs}}); ++ my $linklibs = join("", ++ map { "\n$_" } compute_lib_depends(@{$args{deps}})); ++ my $deps = join(" ", ++ (map { $_.$objext } @{$args{objs}}), ++ compute_lib_depends(@{$args{deps}})); ++ return <<"EOF"; ++$bin$exeext: $deps ++ IF EXIST $bin$exeext.manifest DEL /F /Q $bin$exeext.manifest ++ \$(LD) \$(LDFLAGS) \$(BIN_LDFLAGS) \$(LDOUTFLAG)$bin$exeext @<< ++$objs setargv.obj$linklibs \$(EX_LIBS) ++<< ++ IF EXIST $bin$exeext.manifest \\ ++ \$(MT) \$(MTFLAGS) \$(MTINFLAG)$bin$exeext.manifest \$(MTOUTFLAG)$bin$exeext ++EOF ++ } ++ sub in2script { ++ my %args = @_; ++ my $script = $args{script}; ++ my $sources = '"'.join('" "', @{$args{sources}}).'"'; ++ my $dofile = abs2rel(rel2abs(catfile($config{sourcedir}, ++ "util", "dofile.pl")), ++ rel2abs($config{builddir})); ++ return <<"EOF"; ++$script: $sources ++ "\$(PERL)" "-I\$(BLDDIR)" -Mconfigdata "$dofile" \\ ++ "-o$target{build_file}" $sources > "$script" ++EOF ++ } ++ sub generatedir { ++ my %args = @_; ++ my $dir = $args{dir}; ++ my @deps = map { s|\.o$|$objext|; $_ } @{$args{deps}}; ++ my @actions = (); ++ my %extinfo = ( dso => $dsoext, ++ lib => $libext, ++ bin => $exeext ); ++ ++ foreach my $type (("dso", "lib", "bin", "script")) { ++ next unless defined($unified_info{dirinfo}->{$dir}->{products}->{$type}); ++ # For lib object files, we could update the library. However, ++ # LIB on Windows doesn't work that way, so we won't create any ++ # actions for it, and the dependencies are already taken care of. ++ if ($type ne "lib") { ++ foreach my $prod (@{$unified_info{dirinfo}->{$dir}->{products}->{$type}}) { ++ if (dirname($prod) eq $dir) { ++ push @deps, $prod.$extinfo{$type}; ++ } else { ++ push @actions, "\t@rem No support to produce $type ".join(", ", @{$unified_info{dirinfo}->{$dir}->{products}->{$type}}); ++ } ++ } ++ } ++ } ++ ++ my $deps = join(" ", @deps); ++ my $actions = join("\n", "", @actions); ++ return <<"EOF"; ++$args{dir} $args{dir}\\ : $deps$actions ++EOF ++ } ++ "" # Important! This becomes part of the template result. ++-} +diff --git a/CryptoPkg/Library/OpensslLib/openssl/Configure b/CryptoPkg/Library/OpensslLib/openssl/Configure +new file mode 100755 +index 0000000..aee7cc3 +--- /dev/null ++++ b/CryptoPkg/Library/OpensslLib/openssl/Configure +@@ -0,0 +1,2766 @@ ++#! /usr/bin/env perl ++# -*- mode: perl; -*- ++# Copyright 2016 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 ++# in the file LICENSE in the source distribution or at ++# https://www.openssl.org/source/license.html ++ ++## Configure -- OpenSSL source tree configuration script ++ ++require 5.10.0; ++use strict; ++use File::Basename; ++use File::Spec::Functions qw/:DEFAULT abs2rel rel2abs/; ++use File::Path qw/mkpath/; ++use if $^O ne "VMS", 'File::Glob' => qw/glob/; ++ ++# see INSTALL for instructions. ++ ++my $usage="Usage: Configure [no- ...] [enable- ...] [-Dxxx] [-lxxx] [-Lxxx] [-fxxx] [-Kxxx] [no-hw-xxx|no-hw] [[no-]threads] [[no-]shared] [[no-]zlib|zlib-dynamic] [no-asm] [no-dso] [no-egd] [sctp] [386] [--prefix=DIR] [--openssldir=OPENSSLDIR] [--with-xxx[=vvv]] [--config=FILE] os/compiler[:flags]\n"; ++ ++# Options: ++# ++# --config add the given configuration file, which will be read after ++# any "Configurations*" files that are found in the same ++# directory as this script. ++# --prefix prefix for the OpenSSL installation, which includes the ++# directories bin, lib, include, share/man, share/doc/openssl ++# This becomes the value of INSTALLTOP in Makefile ++# (Default: /usr/local) ++# --openssldir OpenSSL data area, such as openssl.cnf, certificates and keys. ++# If it's a relative directory, it will be added on the directory ++# given with --prefix. ++# This becomes the value of OPENSSLDIR in Makefile and in C. ++# (Default: PREFIX/ssl) ++# ++# --cross-compile-prefix Add specified prefix to binutils components. ++# ++# --api One of 0.9.8, 1.0.0 or 1.1.0. Do not compile support for ++# interfaces deprecated as of the specified OpenSSL version. ++# ++# no-hw-xxx do not compile support for specific crypto hardware. ++# Generic OpenSSL-style methods relating to this support ++# are always compiled but return NULL if the hardware ++# support isn't compiled. ++# no-hw do not compile support for any crypto hardware. ++# [no-]threads [don't] try to create a library that is suitable for ++# multithreaded applications (default is "threads" if we ++# know how to do it) ++# [no-]shared [don't] try to create shared libraries when supported. ++# [no-]pic [don't] try to build position independent code when supported. ++# If disabled, it also disables shared and dynamic-engine. ++# no-asm do not use assembler ++# no-dso do not compile in any native shared-library methods. This ++# will ensure that all methods just return NULL. ++# no-egd do not compile support for the entropy-gathering daemon APIs ++# [no-]zlib [don't] compile support for zlib compression. ++# zlib-dynamic Like "zlib", but the zlib library is expected to be a shared ++# library and will be loaded in run-time by the OpenSSL library. ++# sctp include SCTP support ++# enable-weak-ssl-ciphers ++# Enable weak ciphers that are disabled by default. This currently ++# only includes RC4 based ciphers. ++# 386 generate 80386 code in assembly modules ++# no-sse2 disables IA-32 SSE2 code in assembly modules, the above ++# mentioned '386' option implies this one ++# no- build without specified algorithm (rsa, idea, rc5, ...) ++# - + compiler options are passed through ++# -static while -static is also a pass-through compiler option (and ++# as such is limited to environments where it's actually ++# meaningful), it triggers a number configuration options, ++# namely no-dso, no-pic, no-shared and no-threads. It is ++# argued that the only reason to produce statically linked ++# binaries (and in context it means executables linked with ++# -static flag, and not just executables linked with static ++# libcrypto.a) is to eliminate dependency on specific run-time, ++# a.k.a. libc version. The mentioned config options are meant ++# to achieve just that. Unfortunately on Linux it's impossible ++# to eliminate the dependency completely for openssl executable ++# because of getaddrinfo and gethostbyname calls, which can ++# invoke dynamically loadable library facility anyway to meet ++# the lookup requests. For this reason on Linux statically ++# linked openssl executable has rather debugging value than ++# production quality. ++# ++# DEBUG_SAFESTACK use type-safe stacks to enforce type-safety on stack items ++# provided to stack calls. Generates unique stack functions for ++# each possible stack type. ++# BN_LLONG use the type 'long long' in crypto/bn/bn.h ++# RC4_CHAR use 'char' instead of 'int' for RC4_INT in crypto/rc4/rc4.h ++# Following are set automatically by this script ++# ++# MD5_ASM use some extra md5 assembler, ++# SHA1_ASM use some extra sha1 assembler, must define L_ENDIAN for x86 ++# RMD160_ASM use some extra ripemd160 assembler, ++# SHA256_ASM sha256_block is implemented in assembler ++# SHA512_ASM sha512_block is implemented in assembler ++# AES_ASM AES_[en|de]crypt is implemented in assembler ++ ++# Minimum warning options... any contributions to OpenSSL should at least get ++# past these. ++ ++# DEBUG_UNUSED enables __owur (warn unused result) checks. ++my $gcc_devteam_warn = "-DDEBUG_UNUSED" ++ # -DPEDANTIC complements -pedantic and is meant to mask code that ++ # is not strictly standard-compliant and/or implementation-specific, ++ # e.g. inline assembly, disregards to alignment requirements, such ++ # that -pedantic would complain about. Incidentally -DPEDANTIC has ++ # to be used even in sanitized builds, because sanitizer too is ++ # supposed to and does take notice of non-standard behaviour. Then ++ # -pedantic with pre-C9x compiler would also complain about 'long ++ # long' not being supported. As 64-bit algorithms are common now, ++ # it grew impossible to resolve this without sizeable additional ++ # code, so we just tell compiler to be pedantic about everything ++ # but 'long long' type. ++ . " -DPEDANTIC -pedantic -Wno-long-long" ++ . " -Wall" ++ . " -Wsign-compare" ++ . " -Wmissing-prototypes" ++ . " -Wshadow" ++ . " -Wformat" ++ . " -Wtype-limits" ++ . " -Werror" ++ ; ++ ++# These are used in addition to $gcc_devteam_warn when the compiler is clang. ++# TODO(openssl-team): fix problems and investigate if (at least) the ++# following warnings can also be enabled: ++# -Wswitch-enum ++# -Wcast-align ++# -Wunreachable-code ++# -Wlanguage-extension-token -- no, we use asm() ++# -Wunused-macros -- no, too tricky for BN and _XOPEN_SOURCE etc ++# -Wextended-offsetof -- no, needed in CMS ASN1 code ++my $clang_devteam_warn = "" ++ . " -Qunused-arguments" ++ . " -Wextra" ++ . " -Wno-unused-parameter" ++ . " -Wno-missing-field-initializers" ++ . " -Wno-language-extension-token" ++ . " -Wno-extended-offsetof" ++ . " -Wconditional-uninitialized" ++ . " -Wincompatible-pointer-types-discards-qualifiers" ++ . " -Wmissing-variable-declarations" ++ ; ++ ++# This adds backtrace information to the memory leak info. Is only used ++# when crypto-mdebug-backtrace is enabled. ++my $memleak_devteam_backtrace = "-rdynamic"; ++ ++my $strict_warnings = 0; ++ ++# As for $BSDthreads. Idea is to maintain "collective" set of flags, ++# which would cover all BSD flavors. -pthread applies to them all, ++# but is treated differently. OpenBSD expands is as -D_POSIX_THREAD ++# -lc_r, which is sufficient. FreeBSD 4.x expands it as -lc_r, ++# which has to be accompanied by explicit -D_THREAD_SAFE and ++# sometimes -D_REENTRANT. FreeBSD 5.x expands it as -lc_r, which ++# seems to be sufficient? ++our $BSDthreads="-pthread -D_THREAD_SAFE -D_REENTRANT"; ++ ++# ++# API compatibility name to version number mapping. ++# ++my $maxapi = "1.1.0"; # API for "no-deprecated" builds ++my $apitable = { ++ "1.1.0" => "0x10100000L", ++ "1.0.0" => "0x10000000L", ++ "0.9.8" => "0x00908000L", ++}; ++ ++our %table = (); ++our %config = (); ++our %withargs = (); ++ ++# Forward declarations ############################################### ++ ++# read_config(filename) ++# ++# Reads a configuration file and populates %table with the contents ++# (which the configuration file places in %targets). ++sub read_config; ++ ++# resolve_config(target) ++# ++# Resolves all the late evaluations, inheritances and so on for the ++# chosen target and any target it inherits from. ++sub resolve_config; ++ ++ ++# Information collection ############################################# ++ ++# Unified build supports separate build dir ++my $srcdir = catdir(absolutedir(dirname($0))); # catdir ensures local syntax ++my $blddir = catdir(absolutedir(".")); # catdir ensures local syntax ++my $dofile = abs2rel(catfile($srcdir, "util/dofile.pl")); ++ ++my $local_config_envname = 'OPENSSL_LOCAL_CONFIG_DIR'; ++ ++$config{sourcedir} = abs2rel($srcdir); ++$config{builddir} = abs2rel($blddir); ++ ++# Collect reconfiguration information if needed ++my @argvcopy=@ARGV; ++ ++if (grep /^reconf(igure)?$/, @argvcopy) { ++ if (-f "./configdata.pm") { ++ my $file = "./configdata.pm"; ++ unless (my $return = do $file) { ++ die "couldn't parse $file: $@" if $@; ++ die "couldn't do $file: $!" unless defined $return; ++ die "couldn't run $file" unless $return; ++ } ++ ++ @argvcopy = defined($configdata::config{perlargv}) ? ++ @{$configdata::config{perlargv}} : (); ++ die "Incorrect data to reconfigure, please do a normal configuration\n" ++ if (grep(/^reconf/,@argvcopy)); ++ $ENV{CROSS_COMPILE} = $configdata::config{cross_compile_prefix} ++ if defined($configdata::config{cross_compile_prefix}); ++ $ENV{CC} = $configdata::config{cc} ++ if defined($configdata::config{cc}); ++ $ENV{BUILDFILE} = $configdata::config{build_file} ++ if defined($configdata::config{build_file}); ++ $ENV{$local_config_envname} = $configdata::config{local_config_dir} ++ if defined($configdata::config{local_config_dir}); ++ ++ print "Reconfiguring with: ", join(" ",@argvcopy), "\n"; ++ print " CROSS_COMPILE = ",$ENV{CROSS_COMPILE},"\n" ++ if $ENV{CROSS_COMPILE}; ++ print " CC = ",$ENV{CC},"\n" if $ENV{CC}; ++ print " BUILDFILE = ",$ENV{BUILDFILE},"\n" if $ENV{BUILDFILE}; ++ print " $local_config_envname = ",$ENV{$local_config_envname},"\n" ++ if $ENV{$local_config_envname}; ++ } else { ++ die "Insufficient data to reconfigure, please do a normal configuration\n"; ++ } ++} ++ ++$config{perlargv} = [ @argvcopy ]; ++ ++# Collect version numbers ++$config{version} = "unknown"; ++$config{version_num} = "unknown"; ++$config{shlib_version_number} = "unknown"; ++$config{shlib_version_history} = "unknown"; ++ ++collect_information( ++ collect_from_file(catfile($srcdir,'include/openssl/opensslv.h')), ++ qr/OPENSSL.VERSION.TEXT.*OpenSSL (\S+) / => sub { $config{version} = $1; }, ++ qr/OPENSSL.VERSION.NUMBER.*(0x\S+)/ => sub { $config{version_num}=$1 }, ++ qr/SHLIB_VERSION_NUMBER *"([^"]+)"/ => sub { $config{shlib_version_number}=$1 }, ++ qr/SHLIB_VERSION_HISTORY *"([^"]*)"/ => sub { $config{shlib_version_history}=$1 } ++ ); ++if ($config{shlib_version_history} ne "") { $config{shlib_version_history} .= ":"; } ++ ++($config{major}, $config{minor}) ++ = ($config{version} =~ /^([0-9]+)\.([0-9\.]+)/); ++($config{shlib_major}, $config{shlib_minor}) ++ = ($config{shlib_version_number} =~ /^([0-9]+)\.([0-9\.]+)/); ++die "erroneous version information in opensslv.h: ", ++ "$config{major}, $config{minor}, $config{shlib_major}, $config{shlib_minor}\n" ++ if ($config{major} eq "" || $config{minor} eq "" ++ || $config{shlib_major} eq "" || $config{shlib_minor} eq ""); ++ ++# Collect target configurations ++ ++my $pattern = catfile(dirname($0), "Configurations", "*.conf"); ++foreach (sort glob($pattern)) { ++ &read_config($_); ++} ++ ++if (defined $ENV{$local_config_envname}) { ++ if ($^O eq 'VMS') { ++ # VMS environment variables are logical names, ++ # which can be used as is ++ $pattern = $local_config_envname . ':' . '*.conf'; ++ } else { ++ $pattern = catfile($ENV{$local_config_envname}, '*.conf'); ++ } ++ ++ foreach (sort glob($pattern)) { ++ &read_config($_); ++ } ++} ++ ++ ++print "Configuring OpenSSL version $config{version} ($config{version_num})\n"; ++ ++$config{prefix}=""; ++$config{openssldir}=""; ++$config{processor}=""; ++$config{libdir}=""; ++$config{cross_compile_prefix}=""; ++$config{fipslibdir}="/usr/local/ssl/fips-2.0/lib/"; ++my $nofipscanistercheck=0; ++$config{baseaddr}="0xFB00000"; ++my $auto_threads=1; # enable threads automatically? true by default ++my $default_ranlib; ++$config{fips}=0; ++ ++# Top level directories to build ++$config{dirs} = [ "crypto", "ssl", "engines", "apps", "test", "util", "tools", "fuzz" ]; ++# crypto/ subdirectories to build ++$config{sdirs} = [ ++ "objects", ++ "md2", "md4", "md5", "sha", "mdc2", "hmac", "ripemd", "whrlpool", "poly1305", "blake2", ++ "des", "aes", "rc2", "rc4", "rc5", "idea", "bf", "cast", "camellia", "seed", "chacha", "modes", ++ "bn", "ec", "rsa", "dsa", "dh", "dso", "engine", ++ "buffer", "bio", "stack", "lhash", "rand", "err", ++ "evp", "asn1", "pem", "x509", "x509v3", "conf", "txt_db", "pkcs7", "pkcs12", "comp", "ocsp", "ui", ++ "cms", "ts", "srp", "cmac", "ct", "async", "kdf" ++ ]; ++ ++# Known TLS and DTLS protocols ++my @tls = qw(ssl3 tls1 tls1_1 tls1_2); ++my @dtls = qw(dtls1 dtls1_2); ++ ++# Explicitly known options that are possible to disable. They can ++# be regexps, and will be used like this: /^no-${option}$/ ++# For developers: keep it sorted alphabetically ++ ++my @disablables = ( ++ "afalgeng", ++ "asan", ++ "asm", ++ "async", ++ "autoalginit", ++ "autoerrinit", ++ "bf", ++ "blake2", ++ "camellia", ++ "capieng", ++ "cast", ++ "chacha", ++ "cmac", ++ "cms", ++ "comp", ++ "crypto-mdebug", ++ "crypto-mdebug-backtrace", ++ "ct", ++ "deprecated", ++ "des", ++ "dgram", ++ "dh", ++ "dsa", ++ "dso", ++ "dtls", ++ "dynamic-engine", ++ "ec", ++ "ec2m", ++ "ecdh", ++ "ecdsa", ++ "ec_nistp_64_gcc_128", ++ "egd", ++ "engine", ++ "err", ++ "filenames", ++ "fuzz-libfuzzer", ++ "fuzz-afl", ++ "gost", ++ "heartbeats", ++ "hw(-.+)?", ++ "idea", ++ "makedepend", ++ "md2", ++ "md4", ++ "mdc2", ++ "msan", ++ "multiblock", ++ "nextprotoneg", ++ "ocb", ++ "ocsp", ++ "pic", ++ "poly1305", ++ "posix-io", ++ "psk", ++ "rc2", ++ "rc4", ++ "rc5", ++ "rdrand", ++ "rfc3779", ++ "rmd160", ++ "scrypt", ++ "sctp", ++ "seed", ++ "shared", ++ "sock", ++ "srp", ++ "srtp", ++ "sse2", ++ "ssl", ++ "ssl-trace", ++ "static-engine", ++ "stdio", ++ "threads", ++ "tls", ++ "ts", ++ "ubsan", ++ "ui", ++ "unit-test", ++ "whirlpool", ++ "weak-ssl-ciphers", ++ "zlib", ++ "zlib-dynamic", ++ ); ++foreach my $proto ((@tls, @dtls)) ++ { ++ push(@disablables, $proto); ++ push(@disablables, "$proto-method"); ++ } ++ ++my %deprecated_disablables = ( ++ "ssl2" => undef, ++ "buf-freelists" => undef, ++ "ripemd" => "rmd160" ++ ); ++ ++# All of the following is disabled by default (RC5 was enabled before 0.9.8): ++ ++our %disabled = ( # "what" => "comment" ++ "asan" => "default", ++ "crypto-mdebug" => "default", ++ "crypto-mdebug-backtrace" => "default", ++ "ec_nistp_64_gcc_128" => "default", ++ "egd" => "default", ++ "fuzz-libfuzzer" => "default", ++ "fuzz-afl" => "default", ++ "heartbeats" => "default", ++ "md2" => "default", ++ "msan" => "default", ++ "rc5" => "default", ++ "sctp" => "default", ++ "ssl-trace" => "default", ++ "ssl3" => "default", ++ "ssl3-method" => "default", ++ "ubsan" => "default", ++ "unit-test" => "default", ++ "weak-ssl-ciphers" => "default", ++ "zlib" => "default", ++ "zlib-dynamic" => "default", ++ ); ++ ++# Note: => pair form used for aesthetics, not to truly make a hash table ++my @disable_cascades = ( ++ # "what" => [ "cascade", ... ] ++ sub { $config{processor} eq "386" } ++ => [ "sse2" ], ++ "ssl" => [ "ssl3" ], ++ "ssl3-method" => [ "ssl3" ], ++ "zlib" => [ "zlib-dynamic" ], ++ "des" => [ "mdc2" ], ++ "ec" => [ "ecdsa", "ecdh" ], ++ ++ "dgram" => [ "dtls", "sctp" ], ++ "sock" => [ "dgram" ], ++ "dtls" => [ @dtls ], ++ ++ # SSL 3.0, (D)TLS 1.0 and TLS 1.1 require MD5 and SHA ++ "md5" => [ "ssl", "tls1", "tls1_1", "dtls1" ], ++ "sha" => [ "ssl", "tls1", "tls1_1", "dtls1" ], ++ ++ # Additionally, SSL 3.0 requires either RSA or DSA+DH ++ sub { $disabled{rsa} ++ && ($disabled{dsa} || $disabled{dh}); } ++ => [ "ssl" ], ++ ++ # (D)TLS 1.0 and TLS 1.1 also require either RSA or DSA+DH ++ # or ECDSA + ECDH. (D)TLS 1.2 has this requirement as well. ++ # (XXX: We don't support PSK-only builds). ++ sub { $disabled{rsa} ++ && ($disabled{dsa} || $disabled{dh}) ++ && ($disabled{ecdsa} || $disabled{ecdh}); } ++ => [ "tls1", "tls1_1", "tls1_2", ++ "dtls1", "dtls1_2" ], ++ ++ "tls" => [ @tls ], ++ ++ # SRP and HEARTBEATS require TLSEXT ++ "tlsext" => [ "srp", "heartbeats" ], ++ ++ "crypto-mdebug" => [ "crypto-mdebug-backtrace" ], ++ ++ # Without DSO, we can't load dynamic engines, so don't build them dynamic ++ "dso" => [ "dynamic-engine" ], ++ ++ # Without position independent code, there can be no shared libraries or DSOs ++ "pic" => [ "shared" ], ++ "shared" => [ "dynamic-engine" ], ++ "engine" => [ "afalgeng" ], ++ ++ # no-autoalginit is only useful when building non-shared ++ "autoalginit" => [ "shared", "apps" ], ++ ++ "stdio" => [ "apps", "capieng" ], ++ "apps" => [ "tests" ], ++ "comp" => [ "zlib" ], ++ sub { !$disabled{"unit-test"} } => [ "heartbeats" ], ++ ++ sub { !$disabled{"msan"} } => [ "asm" ], ++ ); ++ ++# Avoid protocol support holes. Also disable all versions below N, if version ++# N is disabled while N+1 is enabled. ++# ++my @list = (reverse @tls); ++while ((my $first, my $second) = (shift @list, shift @list)) { ++ last unless @list; ++ push @disable_cascades, ( sub { !$disabled{$first} && $disabled{$second} } ++ => [ @list ] ); ++ unshift @list, $second; ++} ++my @list = (reverse @dtls); ++while ((my $first, my $second) = (shift @list, shift @list)) { ++ last unless @list; ++ push @disable_cascades, ( sub { !$disabled{$first} && $disabled{$second} } ++ => [ @list ] ); ++ unshift @list, $second; ++} ++ ++# Explicit "no-..." options will be collected in %disabled along with the defaults. ++# To remove something from %disabled, use "enable-foo". ++# For symmetry, "disable-foo" is a synonym for "no-foo". ++ ++my $no_sse2=0; ++ ++&usage if ($#ARGV < 0); ++ ++my $user_cflags=""; ++my @user_defines=(); ++$config{openssl_api_defines}=[]; ++$config{openssl_algorithm_defines}=[]; ++$config{openssl_thread_defines}=[]; ++$config{openssl_sys_defines}=[]; ++$config{openssl_other_defines}=[]; ++my $libs=""; ++my $target=""; ++$config{options}=""; ++$config{build_type} = "release"; ++ ++my %unsupported_options = (); ++my %deprecated_options = (); ++while (@argvcopy) ++ { ++ $_ = shift @argvcopy; ++ # VMS is a case insensitive environment, and depending on settings ++ # out of our control, we may receive options uppercased. Let's ++ # downcase at least the part before any equal sign. ++ if ($^O eq "VMS") ++ { ++ s/^([^=]*)/lc($1)/e; ++ } ++ s /^-no-/no-/; # some people just can't read the instructions ++ ++ # rewrite some options in "enable-..." form ++ s /^-?-?shared$/enable-shared/; ++ s /^sctp$/enable-sctp/; ++ s /^threads$/enable-threads/; ++ s /^zlib$/enable-zlib/; ++ s /^zlib-dynamic$/enable-zlib-dynamic/; ++ ++ if (/^(no|disable|enable)-(.+)$/) ++ { ++ my $word = $2; ++ if (!exists $deprecated_disablables{$word} ++ && !grep { $word =~ /^${_}$/ } @disablables) ++ { ++ $unsupported_options{$_} = 1; ++ next; ++ } ++ } ++ if (/^no-(.+)$/ || /^disable-(.+)$/) ++ { ++ foreach my $proto ((@tls, @dtls)) ++ { ++ if ($1 eq "$proto-method") ++ { ++ $disabled{"$proto"} = "option($proto-method)"; ++ last; ++ } ++ } ++ if ($1 eq "dtls") ++ { ++ foreach my $proto (@dtls) ++ { ++ $disabled{$proto} = "option(dtls)"; ++ } ++ $disabled{"dtls"} = "option(dtls)"; ++ } ++ elsif ($1 eq "ssl") ++ { ++ # Last one of its kind ++ $disabled{"ssl3"} = "option(ssl)"; ++ } ++ elsif ($1 eq "tls") ++ { ++ # XXX: Tests will fail if all SSL/TLS ++ # protocols are disabled. ++ foreach my $proto (@tls) ++ { ++ $disabled{$proto} = "option(tls)"; ++ } ++ } ++ elsif ($1 eq "static-engine") ++ { ++ delete $disabled{"dynamic-engine"}; ++ } ++ elsif ($1 eq "dynamic-engine") ++ { ++ $disabled{"dynamic-engine"} = "option"; ++ } ++ elsif (exists $deprecated_disablables{$1}) ++ { ++ $deprecated_options{$_} = 1; ++ if (defined $deprecated_disablables{$1}) ++ { ++ $disabled{$deprecated_disablables{$1}} = "option"; ++ } ++ } ++ else ++ { ++ $disabled{$1} = "option"; ++ } ++ # No longer an automatic choice ++ $auto_threads = 0 if ($1 eq "threads"); ++ } ++ elsif (/^enable-(.+)$/) ++ { ++ if ($1 eq "static-engine") ++ { ++ $disabled{"dynamic-engine"} = "option"; ++ } ++ elsif ($1 eq "dynamic-engine") ++ { ++ delete $disabled{"dynamic-engine"}; ++ } ++ elsif ($1 eq "zlib-dynamic") ++ { ++ delete $disabled{"zlib"}; ++ } ++ my $algo = $1; ++ delete $disabled{$algo}; ++ ++ # No longer an automatic choice ++ $auto_threads = 0 if ($1 eq "threads"); ++ } ++ elsif (/^--strict-warnings$/) ++ { ++ $strict_warnings = 1; ++ } ++ elsif (/^--debug$/) ++ { ++ $config{build_type} = "debug"; ++ } ++ elsif (/^--release$/) ++ { ++ $config{build_type} = "release"; ++ } ++ elsif (/^386$/) ++ { $config{processor}=386; } ++ elsif (/^fips$/) ++ { ++ $config{fips}=1; ++ } ++ elsif (/^rsaref$/) ++ { ++ # No RSAref support any more since it's not needed. ++ # The check for the option is there so scripts aren't ++ # broken ++ } ++ elsif (/^nofipscanistercheck$/) ++ { ++ $config{fips} = 1; ++ $nofipscanistercheck = 1; ++ } ++ elsif (/^[-+]/) ++ { ++ if (/^--prefix=(.*)$/) ++ { ++ $config{prefix}=$1; ++ die "Directory given with --prefix MUST be absolute\n" ++ unless file_name_is_absolute($config{prefix}); ++ } ++ elsif (/^--api=(.*)$/) ++ { ++ $config{api}=$1; ++ } ++ elsif (/^--libdir=(.*)$/) ++ { ++ $config{libdir}=$1; ++ } ++ elsif (/^--openssldir=(.*)$/) ++ { ++ $config{openssldir}=$1; ++ } ++ elsif (/^--with-zlib-lib=(.*)$/) ++ { ++ $withargs{zlib_lib}=$1; ++ } ++ elsif (/^--with-zlib-include=(.*)$/) ++ { ++ $withargs{zlib_include}=$1; ++ } ++ elsif (/^--with-fuzzer-lib=(.*)$/) ++ { ++ $withargs{fuzzer_lib}=$1; ++ } ++ elsif (/^--with-fuzzer-include=(.*)$/) ++ { ++ $withargs{fuzzer_include}=$1; ++ } ++ elsif (/^--with-fipslibdir=(.*)$/) ++ { ++ $config{fipslibdir}="$1/"; ++ } ++ elsif (/^--with-baseaddr=(.*)$/) ++ { ++ $config{baseaddr}="$1"; ++ } ++ elsif (/^--cross-compile-prefix=(.*)$/) ++ { ++ $config{cross_compile_prefix}=$1; ++ } ++ elsif (/^--config=(.*)$/) ++ { ++ read_config $1; ++ } ++ elsif (/^-[lL](.*)$/ or /^-Wl,/) ++ { ++ $libs.=$_." "; ++ } ++ elsif (/^-rpath$/ or /^-R$/) ++ # -rpath is the OSF1 rpath flag ++ # -R is the old Solaris rpath flag ++ { ++ my $rpath = shift(@argvcopy) || ""; ++ $rpath .= " " if $rpath ne ""; ++ $libs.=$_." ".$rpath; ++ } ++ elsif (/^-static$/) ++ { ++ $libs.=$_." "; ++ $disabled{"dso"} = "forced"; ++ $disabled{"pic"} = "forced"; ++ $disabled{"shared"} = "forced"; ++ $disabled{"threads"} = "forced"; ++ } ++ elsif (/^-D(.*)$/) ++ { ++ push @user_defines, $1; ++ } ++ else # common if (/^[-+]/), just pass down... ++ { ++ $_ =~ s/%([0-9a-f]{1,2})/chr(hex($1))/gei; ++ $user_cflags.=" ".$_; ++ } ++ } ++ else ++ { ++ die "target already defined - $target (offending arg: $_)\n" if ($target ne ""); ++ $target=$_; ++ } ++ unless ($_ eq $target || /^no-/ || /^disable-/) ++ { ++ # "no-..." follows later after implied disactivations ++ # have been derived. (Don't take this too seriously, ++ # we really only write OPTIONS to the Makefile out of ++ # nostalgia.) ++ ++ if ($config{options} eq "") ++ { $config{options} = $_; } ++ else ++ { $config{options} .= " ".$_; } ++ } ++ ++ if (defined($config{api}) && !exists $apitable->{$config{api}}) { ++ die "***** Unsupported api compatibility level: $config{api}\n", ++ } ++ ++ if (keys %deprecated_options) ++ { ++ warn "***** Deprecated options: ", ++ join(", ", keys %deprecated_options), "\n"; ++ } ++ if (keys %unsupported_options) ++ { ++ die "***** Unsupported options: ", ++ join(", ", keys %unsupported_options), "\n"; ++ } ++ } ++ ++if ($libs =~ /(^|\s)-Wl,-rpath,/ ++ && !$disabled{shared} ++ && !($disabled{asan} && $disabled{msan} && $disabled{ubsan})) { ++ die "***** Cannot simultaneously use -rpath, shared libraries, and\n", ++ "***** any of asan, msan or ubsan\n"; ++} ++ ++if ($config{fips}) ++ { ++ delete $disabled{"shared"} if ($disabled{"shared"} =~ /^default/); ++ } ++else ++ { ++ @{$config{dirs}} = grep !/^fips$/, @{$config{dirs}}; ++ } ++ ++my @tocheckfor = (keys %disabled); ++while (@tocheckfor) { ++ my %new_tocheckfor = (); ++ my @cascade_copy = (@disable_cascades); ++ while (@cascade_copy) { ++ my ($test, $descendents) = (shift @cascade_copy, shift @cascade_copy); ++ if (ref($test) eq "CODE" ? $test->() : defined($disabled{$test})) { ++ foreach(grep { !defined($disabled{$_}) } @$descendents) { ++ $new_tocheckfor{$_} = 1; $disabled{$_} = "forced"; ++ } ++ } ++ } ++ @tocheckfor = (keys %new_tocheckfor); ++} ++ ++our $die = sub { die @_; }; ++if ($target eq "TABLE") { ++ local $die = sub { warn @_; }; ++ foreach (sort keys %table) { ++ print_table_entry($_, "TABLE"); ++ } ++ exit 0; ++} ++ ++if ($target eq "LIST") { ++ foreach (sort keys %table) { ++ print $_,"\n" unless $table{$_}->{template}; ++ } ++ exit 0; ++} ++ ++if ($target eq "HASH") { ++ local $die = sub { warn @_; }; ++ print "%table = (\n"; ++ foreach (sort keys %table) { ++ print_table_entry($_, "HASH"); ++ } ++ exit 0; ++} ++ ++# Backward compatibility? ++if ($target =~ m/^CygWin32(-.*)$/) { ++ $target = "Cygwin".$1; ++} ++ ++foreach (sort (keys %disabled)) ++ { ++ $config{options} .= " no-$_"; ++ ++ printf " no-%-12s %-10s", $_, "[$disabled{$_}]"; ++ ++ if (/^dso$/) ++ { } ++ elsif (/^threads$/) ++ { } ++ elsif (/^shared$/) ++ { } ++ elsif (/^pic$/) ++ { } ++ elsif (/^zlib$/) ++ { } ++ elsif (/^dynamic-engine$/) ++ { } ++ elsif (/^makedepend$/) ++ { } ++ elsif (/^zlib-dynamic$/) ++ { } ++ elsif (/^sse2$/) ++ { $no_sse2 = 1; } ++ elsif (/^engine$/) ++ { ++ @{$config{dirs}} = grep !/^engines$/, @{$config{dirs}}; ++ @{$config{sdirs}} = grep !/^engine$/, @{$config{sdirs}}; ++ push @{$config{openssl_other_defines}}, "OPENSSL_NO_ENGINE"; ++ print " OPENSSL_NO_ENGINE (skip engines)"; ++ } ++ else ++ { ++ my ($WHAT, $what); ++ ++ ($WHAT = $what = $_) =~ tr/[\-a-z]/[_A-Z]/; ++ ++ # Fix up C macro end names ++ $WHAT = "RMD160" if $what eq "ripemd"; ++ ++ # fix-up crypto/directory name(s) ++ $what = "ripemd" if $what eq "rmd160"; ++ $what = "whrlpool" if $what eq "whirlpool"; ++ ++ if ($what ne "async" && $what ne "err" ++ && grep { $_ eq $what } @{$config{sdirs}}) ++ { ++ push @{$config{openssl_algorithm_defines}}, "OPENSSL_NO_$WHAT"; ++ @{$config{sdirs}} = grep { $_ ne $what} @{$config{sdirs}}; ++ ++ print " OPENSSL_NO_$WHAT (skip dir)"; ++ } ++ else ++ { ++ push @{$config{openssl_other_defines}}, "OPENSSL_NO_$WHAT"; ++ print " OPENSSL_NO_$WHAT"; ++ ++ if (/^err$/) { push @user_defines, "OPENSSL_NO_ERR"; } ++ } ++ } ++ ++ print "\n"; ++ } ++ ++print "Configuring for $target\n"; ++ ++# Support for legacy targets having a name starting with 'debug-' ++my ($d, $t) = $target =~ m/^(debug-)?(.*)$/; ++if ($d) { ++ $config{build_type} = "debug"; ++ ++ # If we do not find debug-foo in the table, the target is set to foo. ++ if (!$table{$target}) { ++ $target = $t; ++ } ++} ++$config{target} = $target; ++my %target = resolve_config($target); ++ ++&usage if (!%target || $target{template}); ++ ++my %conf_files = map { $_ => 1 } (@{$target{_conf_fname_int}}); ++$config{conf_files} = [ sort keys %conf_files ]; ++%target = ( %{$table{DEFAULTS}}, %target ); ++ ++$target{exe_extension}=""; ++$target{exe_extension}=".exe" if ($config{target} eq "DJGPP" ++ || $config{target} =~ /^(?:Cygwin|mingw)/); ++$target{exe_extension}=".pm" if ($config{target} =~ /vos/); ++ ++($target{shared_extension_simple}=$target{shared_extension}) ++ =~ s|\.\$\(SHLIB_MAJOR\)\.\$\(SHLIB_MINOR\)||; ++$target{dso_extension}=$target{shared_extension_simple}; ++($target{shared_import_extension}=$target{shared_extension_simple}.".a") ++ if ($config{target} =~ /^(?:Cygwin|mingw)/); ++ ++ ++$config{cross_compile_prefix} = $ENV{'CROSS_COMPILE'} ++ if $config{cross_compile_prefix} eq ""; ++ ++# Allow overriding the names of some tools. USE WITH CARE ++# Note: only Unix cares about HASHBANGPERL... that explains ++# the default string. ++$config{perl} = $ENV{'PERL'} || ($^O ne "VMS" ? $^X : "perl"); ++$config{hashbangperl} = ++ $ENV{'HASHBANGPERL'} || $ENV{'PERL'} || "/usr/bin/env perl"; ++$target{cc} = $ENV{'CC'} || $target{cc} || "cc"; ++$target{ranlib} = $ENV{'RANLIB'} || $target{ranlib} || ++ (which("$config{cross_compile_prefix}ranlib") ? ++ "\$(CROSS_COMPILE)ranlib" : "true"); ++$target{ar} = $ENV{'AR'} || $target{ar} || "ar"; ++$target{nm} = $ENV{'NM'} || $target{nm} || "nm"; ++$target{rc} = ++ $ENV{'RC'} || $ENV{'WINDRES'} || $target{rc} || "windres"; ++ ++# Allow overriding the build file name ++$target{build_file} = $ENV{BUILDFILE} || $target{build_file} || "Makefile"; ++ ++# Cache information necessary for reconfiguration ++$config{cc} = $target{cc}; ++$config{build_file} = $target{build_file}; ++ ++# For cflags, lflags, plib_lflags, ex_libs and defines, add the debug_ ++# or release_ attributes. ++# Do it in such a way that no spurious space is appended (hence the grep). ++$config{defines} = []; ++$config{cflags} = ""; ++$config{ex_libs} = ""; ++$config{shared_ldflag} = ""; ++ ++# Make sure build_scheme is consistent. ++$target{build_scheme} = [ $target{build_scheme} ] ++ if ref($target{build_scheme}) ne "ARRAY"; ++ ++my ($builder, $builder_platform, @builder_opts) = ++ @{$target{build_scheme}}; ++ ++push @{$config{defines}}, "NDEBUG" if $config{build_type} eq "release"; ++ ++if ($target =~ /^mingw/ && `$target{cc} --target-help 2>&1` =~ m/-mno-cygwin/m) ++ { ++ $config{cflags} .= " -mno-cygwin"; ++ $config{shared_ldflag} .= " -mno-cygwin"; ++ } ++ ++if ($target =~ /linux.*-mips/ && !$disabled{asm} && $user_cflags !~ /-m(ips|arch=)/) { ++ # minimally required architecture flags for assembly modules ++ $config{cflags}="-mips2 $config{cflags}" if ($target =~ /mips32/); ++ $config{cflags}="-mips3 $config{cflags}" if ($target =~ /mips64/); ++} ++ ++my $no_shared_warn=0; ++my $no_user_cflags=0; ++my $no_user_defines=0; ++ ++# The DSO code currently always implements all functions so that no ++# applications will have to worry about that from a compilation point ++# of view. However, the "method"s may return zero unless that platform ++# has support compiled in for them. Currently each method is enabled ++# by a define "DSO_" ... we translate the "dso_scheme" config ++# string entry into using the following logic; ++if (!$disabled{dso} && $target{dso_scheme} ne "") ++ { ++ $target{dso_scheme} =~ tr/[a-z]/[A-Z]/; ++ if ($target{dso_scheme} eq "DLFCN") ++ { ++ unshift @{$config{defines}}, "DSO_DLFCN", "HAVE_DLFCN_H"; ++ } ++ elsif ($target{dso_scheme} eq "DLFCN_NO_H") ++ { ++ unshift @{$config{defines}}, "DSO_DLFCN"; ++ } ++ else ++ { ++ unshift @{$config{defines}}, "DSO_$target{dso_scheme}"; ++ } ++ } ++ ++$config{ex_libs}="$libs$config{ex_libs}" if ($libs ne ""); ++ ++if ($disabled{asm}) ++ { ++ if ($config{fips}) ++ { ++ @{$config{defines}} = grep !/^[BL]_ENDIAN$/, @{$config{defines}}; ++ @{$target{defines}} = grep !/^[BL]_ENDIAN$/, @{$target{defines}}; ++ } ++ } ++ ++# If threads aren't disabled, check how possible they are ++unless ($disabled{threads}) { ++ if ($auto_threads) { ++ # Enabled by default, disable it forcibly if unavailable ++ if ($target{thread_scheme} eq "(unknown)") { ++ $disabled{threads} = "unavailable"; ++ } ++ } else { ++ # The user chose to enable threads explicitly, let's see ++ # if there's a chance that's possible ++ if ($target{thread_scheme} eq "(unknown)") { ++ # If the user asked for "threads" and we don't have internal ++ # knowledge how to do it, [s]he is expected to provide any ++ # system-dependent compiler options that are necessary. We ++ # can't truly check that the given options are correct, but ++ # we expect the user to know what [s]He is doing. ++ if ($no_user_cflags && $no_user_defines) { ++ die "You asked for multi-threading support, but didn't\n" ++ ,"provide any system-specific compiler options\n"; ++ } ++ } ++ } ++} ++ ++# If threads still aren't disabled, add a C macro to ensure the source ++# code knows about it. Any other flag is taken care of by the configs. ++unless($disabled{threads}) { ++ foreach (("defines", "openssl_thread_defines")) { ++ push @{$config{$_}}, "OPENSSL_THREADS"; ++ } ++} ++ ++# With "deprecated" disable all deprecated features. ++if (defined($disabled{"deprecated"})) { ++ $config{api} = $maxapi; ++} ++ ++if ($target{shared_target} eq "") ++ { ++ $no_shared_warn = 1 ++ if ((!$disabled{shared} || !$disabled{"dynamic-engine"}) ++ && !$config{fips}); ++ $disabled{shared} = "no-shared-target"; ++ $disabled{pic} = $disabled{shared} = $disabled{"dynamic-engine"} = ++ "no-shared-target"; ++ } ++ ++if ($disabled{"dynamic-engine"}) { ++ push @{$config{defines}}, "OPENSSL_NO_DYNAMIC_ENGINE"; ++ $config{dynamic_engines} = 0; ++} else { ++ push @{$config{defines}}, "OPENSSL_NO_STATIC_ENGINE"; ++ $config{dynamic_engines} = 1; ++} ++ ++unless ($disabled{"fuzz-libfuzzer"}) { ++ $config{cflags} .= "-fsanitize-coverage=edge,indirect-calls "; ++} ++ ++unless ($disabled{asan}) { ++ $config{cflags} .= "-fsanitize=address "; ++} ++ ++unless ($disabled{ubsan}) { ++ # -DPEDANTIC or -fnosanitize=alignment may also be required on some ++ # platforms. ++ $config{cflags} .= "-fsanitize=undefined -fno-sanitize-recover=all "; ++} ++ ++unless ($disabled{msan}) { ++ $config{cflags} .= "-fsanitize=memory "; ++} ++ ++unless ($disabled{"fuzz-libfuzzer"} && $disabled{"fuzz-afl"} ++ && $disabled{asan} && $disabled{ubsan} && $disabled{msan}) { ++ $config{cflags} .= "-fno-omit-frame-pointer -g "; ++} ++# ++# Platform fix-ups ++# ++ ++# This saves the build files from having to check ++if ($disabled{pic}) ++ { ++ $target{shared_cflag} = $target{shared_ldflag} = ++ $target{shared_rcflag} = ""; ++ } ++else ++ { ++ push @{$config{defines}}, "OPENSSL_PIC"; ++ } ++ ++if ($target{sys_id} ne "") ++ { ++ push @{$config{openssl_sys_defines}}, "OPENSSL_SYS_$target{sys_id}"; ++ } ++ ++unless ($disabled{asm}) { ++ $target{cpuid_asm_src}=$table{DEFAULTS}->{cpuid_asm_src} if ($config{processor} eq "386"); ++ $target{bn_asm_src} =~ s/\w+-gf2m.c// if (defined($disabled{ec2m})); ++ ++ # bn-586 is the only one implementing bn_*_part_words ++ push @{$config{defines}}, "OPENSSL_BN_ASM_PART_WORDS" if ($target{bn_asm_src} =~ /bn-586/); ++ push @{$config{defines}}, "OPENSSL_IA32_SSE2" if (!$no_sse2 && $target{bn_asm_src} =~ /86/); ++ ++ push @{$config{defines}}, "OPENSSL_BN_ASM_MONT" if ($target{bn_asm_src} =~ /-mont/); ++ push @{$config{defines}}, "OPENSSL_BN_ASM_MONT5" if ($target{bn_asm_src} =~ /-mont5/); ++ push @{$config{defines}}, "OPENSSL_BN_ASM_GF2m" if ($target{bn_asm_src} =~ /-gf2m/); ++ ++ if ($config{fips}) { ++ push @{$config{openssl_other_defines}}, "OPENSSL_FIPS"; ++ } ++ ++ if ($target{sha1_asm_src}) { ++ push @{$config{defines}}, "SHA1_ASM" if ($target{sha1_asm_src} =~ /sx86/ || $target{sha1_asm_src} =~ /sha1/); ++ push @{$config{defines}}, "SHA256_ASM" if ($target{sha1_asm_src} =~ /sha256/); ++ push @{$config{defines}}, "SHA512_ASM" if ($target{sha1_asm_src} =~ /sha512/); ++ } ++ if ($target{rc4_asm_src} ne $table{DEFAULTS}->{rc4_asm_src}) { ++ push @{$config{defines}}, "RC4_ASM"; ++ } ++ if ($target{md5_asm_src}) { ++ push @{$config{defines}}, "MD5_ASM"; ++ } ++ $target{cast_asm_src}=$table{DEFAULTS}->{cast_asm_src} unless $disabled{pic}; # CAST assembler is not PIC ++ if ($target{rmd160_asm_src}) { ++ push @{$config{defines}}, "RMD160_ASM"; ++ } ++ if ($target{aes_asm_src}) { ++ push @{$config{defines}}, "AES_ASM" if ($target{aes_asm_src} =~ m/\baes-/);; ++ # aes-ctr.fake is not a real file, only indication that assembler ++ # module implements AES_ctr32_encrypt... ++ push @{$config{defines}}, "AES_CTR_ASM" if ($target{aes_asm_src} =~ s/\s*aes-ctr\.fake//); ++ # aes-xts.fake indicates presence of AES_xts_[en|de]crypt... ++ push @{$config{defines}}, "AES_XTS_ASM" if ($target{aes_asm_src} =~ s/\s*aes-xts\.fake//); ++ $target{aes_asm_src} =~ s/\s*(vpaes|aesni)-x86\.s//g if ($no_sse2); ++ push @{$config{defines}}, "VPAES_ASM" if ($target{aes_asm_src} =~ m/vpaes/); ++ push @{$config{defines}}, "BSAES_ASM" if ($target{aes_asm_src} =~ m/bsaes/); ++ } ++ if ($target{wp_asm_src} =~ /mmx/) { ++ if ($config{processor} eq "386") { ++ $target{wp_asm_src}=$table{DEFAULTS}->{wp_asm_src}; ++ } elsif (!$disabled{"whirlpool"}) { ++ push @{$config{defines}}, "WHIRLPOOL_ASM"; ++ } ++ } ++ if ($target{modes_asm_src} =~ /ghash-/) { ++ push @{$config{defines}}, "GHASH_ASM"; ++ } ++ if ($target{ec_asm_src} =~ /ecp_nistz256/) { ++ push @{$config{defines}}, "ECP_NISTZ256_ASM"; ++ } ++ if ($target{padlock_asm_src} ne $table{DEFAULTS}->{padlock_asm_src}) { ++ push @{$config{defines}}, "PADLOCK_ASM"; ++ } ++ if ($target{poly1305_asm_src} ne "") { ++ push @{$config{defines}}, "POLY1305_ASM"; ++ } ++} ++ ++my $ecc = $target{cc}; ++if ($^O ne "VMS" && !$disabled{makedepend}) { ++ # Is the compiler gcc or clang? $ecc is used below to see if ++ # error-checking can be turned on. ++ my $ccpcc = "$config{cross_compile_prefix}$target{cc}"; ++ open(PIPE, "$ccpcc --version 2>&1 |"); ++ my $lines = 2; ++ while ( ) { ++ # Find the version number and save the major. ++ m|(?:.*)\b(\d+)\.\d+\.\d+\b(?:.*)|; ++ my $compiler_major = $1; ++ # We know that GNU C version 3 and up as well as all clang ++ # versions support dependency generation ++ $config{makedepprog} = $ccpcc ++ if (/clang/ || (/gcc/ && $compiler_major >= 3)); ++ $ecc = "clang" if /clang/; ++ $ecc = "gcc" if /gcc/; ++ last if ($config{makedepprog} || !$lines--); ++ } ++ close(PIPE); ++ ++ $config{makedepprog} = which('makedepend') unless $config{makedepprog}; ++ $disabled{makedepend} = "unavailable" unless $config{makedepprog}; ++} ++ ++ ++ ++# Deal with bn_ops ################################################### ++ ++$config{bn_ll} =0; ++$config{export_var_as_fn} =0; ++my $def_int="unsigned int"; ++$config{rc4_int} =$def_int; ++($config{b64l},$config{b64},$config{b32})=(0,0,1); ++ ++my $count = 0; ++foreach (sort split(/\s+/,$target{bn_ops})) { ++ $count++ if /SIXTY_FOUR_BIT|SIXTY_FOUR_BIT_LONG|THIRTY_TWO_BIT/; ++ $config{export_var_as_fn}=1 if $_ eq 'EXPORT_VAR_AS_FN'; ++ $config{bn_ll}=1 if $_ eq 'BN_LLONG'; ++ $config{rc4_int}="unsigned char" if $_ eq 'RC4_CHAR'; ++ ($config{b64l},$config{b64},$config{b32}) ++ =(0,1,0) if $_ eq 'SIXTY_FOUR_BIT'; ++ ($config{b64l},$config{b64},$config{b32}) ++ =(1,0,0) if $_ eq 'SIXTY_FOUR_BIT_LONG'; ++ ($config{b64l},$config{b64},$config{b32}) ++ =(0,0,1) if $_ eq 'THIRTY_TWO_BIT'; ++} ++die "Exactly one of SIXTY_FOUR_BIT|SIXTY_FOUR_BIT_LONG|THIRTY_TWO_BIT can be set in bn_ops\n" ++ if $count > 1; ++ ++ ++# Hack cflags for better warnings (dev option) ####################### ++ ++# "Stringify" the C flags string. This permits it to be made part of a string ++# and works as well on command lines. ++$config{cflags} =~ s/([\\\"])/\\$1/g; ++ ++if (defined($config{api})) { ++ $config{openssl_api_defines} = [ "OPENSSL_MIN_API=".$apitable->{$config{api}} ]; ++ my $apiflag = sprintf("OPENSSL_API_COMPAT=%s", $apitable->{$config{api}}); ++ push @{$config{defines}}, $apiflag; ++} ++ ++if ($strict_warnings) ++ { ++ my $wopt; ++ die "ERROR --strict-warnings requires gcc or clang" ++ unless $ecc eq 'gcc' || $ecc eq 'clang'; ++ foreach $wopt (split /\s+/, $gcc_devteam_warn) ++ { ++ $config{cflags} .= " $wopt" unless ($config{cflags} =~ /(?:^|\s)$wopt(?:\s|$)/) ++ } ++ if ($ecc eq "clang") ++ { ++ foreach $wopt (split /\s+/, $clang_devteam_warn) ++ { ++ $config{cflags} .= " $wopt" unless ($config{cflags} =~ /(?:^|\s)$wopt(?:\s|$)/) ++ } ++ } ++ } ++ ++unless ($disabled{"crypto-mdebug-backtrace"}) ++ { ++ foreach my $wopt (split /\s+/, $memleak_devteam_backtrace) ++ { ++ $config{cflags} .= " $wopt" unless ($config{cflags} =~ /(?:^|\s)$wopt(?:\s|$)/) ++ } ++ if ($target =~ /^BSD-/) ++ { ++ $config{ex_libs} .= " -lexecinfo"; ++ } ++ } ++ ++if ($user_cflags ne "") { $config{cflags}="$config{cflags}$user_cflags"; } ++else { $no_user_cflags=1; } ++if (@user_defines) { $config{defines}=[ @{$config{defines}}, @user_defines ]; } ++else { $no_user_defines=1; } ++ ++# ALL MODIFICATIONS TO %config and %target MUST BE DONE FROM HERE ON ++ ++unless ($disabled{afalgeng}) { ++ $config{afalgeng}=""; ++ if ($target =~ m/^linux/) { ++ my $minver = 4*10000 + 1*100 + 0; ++ if ($config{cross_compile_prefix} eq "") { ++ my $verstr = `uname -r`; ++ my ($ma, $mi1, $mi2) = split("\\.", $verstr); ++ ($mi2) = $mi2 =~ /(\d+)/; ++ my $ver = $ma*10000 + $mi1*100 + $mi2; ++ if ($ver < $minver) { ++ $disabled{afalgeng} = "too-old-kernel"; ++ } else { ++ push @{$config{engdirs}}, "afalg"; ++ } ++ } else { ++ $disabled{afalgeng} = "cross-compiling"; ++ } ++ } else { ++ $disabled{afalgeng} = "not-linux"; ++ } ++} ++ ++push @{$config{openssl_other_defines}}, "OPENSSL_NO_AFALGENG" if ($disabled{afalgeng}); ++ ++# If we use the unified build, collect information from build.info files ++my %unified_info = (); ++ ++my $buildinfo_debug = defined($ENV{CONFIGURE_DEBUG_BUILDINFO}); ++if ($builder eq "unified") { ++ use lib catdir(dirname(__FILE__),"util"); ++ use with_fallback qw(Text::Template); ++ ++ sub cleandir { ++ my $base = shift; ++ my $dir = shift; ++ my $relativeto = shift || "."; ++ ++ $dir = catdir($base,$dir) unless isabsolute($dir); ++ ++ # Make sure the directories we're building in exists ++ mkpath($dir); ++ ++ my $res = abs2rel(absolutedir($dir), rel2abs($relativeto)); ++ #print STDERR "DEBUG[cleandir]: $dir , $base => $res\n"; ++ return $res; ++ } ++ ++ sub cleanfile { ++ my $base = shift; ++ my $file = shift; ++ my $relativeto = shift || "."; ++ ++ $file = catfile($base,$file) unless isabsolute($file); ++ ++ my $d = dirname($file); ++ my $f = basename($file); ++ ++ # Make sure the directories we're building in exists ++ mkpath($d); ++ ++ my $res = abs2rel(catfile(absolutedir($d), $f), rel2abs($relativeto)); ++ #print STDERR "DEBUG[cleanfile]: $d , $f => $res\n"; ++ return $res; ++ } ++ ++ # Store the name of the template file we will build the build file from ++ # in %config. This may be useful for the build file itself. ++ my @build_file_template_names = ++ ( $builder_platform."-".$target{build_file}.".tmpl", ++ $target{build_file}.".tmpl" ); ++ my @build_file_templates = (); ++ ++ # First, look in the user provided directory, if given ++ if (defined $ENV{$local_config_envname}) { ++ @build_file_templates = ++ map { ++ if ($^O eq 'VMS') { ++ # VMS environment variables are logical names, ++ # which can be used as is ++ $local_config_envname . ':' . $_; ++ } else { ++ catfile($ENV{$local_config_envname}, $_); ++ } ++ } ++ @build_file_template_names; ++ } ++ # Then, look in our standard directory ++ push @build_file_templates, ++ ( map { cleanfile($srcdir, catfile("Configurations", $_), $blddir) } ++ @build_file_template_names ); ++ ++ my $build_file_template; ++ for $_ (@build_file_templates) { ++ $build_file_template = $_; ++ last if -f $build_file_template; ++ ++ $build_file_template = undef; ++ } ++ if (!defined $build_file_template) { ++ die "*** Couldn't find any of:\n", join("\n", @build_file_templates), "\n"; ++ } ++ $config{build_file_templates} ++ = [ $build_file_template, ++ cleanfile($srcdir, catfile("Configurations", "common.tmpl"), ++ $blddir) ]; ++ ++ my @build_infos = ( [ ".", "build.info" ] ); ++ foreach (@{$config{dirs}}) { ++ push @build_infos, [ $_, "build.info" ] ++ if (-f catfile($srcdir, $_, "build.info")); ++ } ++ foreach (@{$config{sdirs}}) { ++ push @build_infos, [ catdir("crypto", $_), "build.info" ] ++ if (-f catfile($srcdir, "crypto", $_, "build.info")); ++ } ++ foreach (@{$config{engdirs}}) { ++ push @build_infos, [ catdir("engines", $_), "build.info" ] ++ if (-f catfile($srcdir, "engines", $_, "build.info")); ++ } ++ ++ $config{build_infos} = [ ]; ++ ++ foreach (@build_infos) { ++ my $sourced = catdir($srcdir, $_->[0]); ++ my $buildd = catdir($blddir, $_->[0]); ++ ++ mkpath($buildd); ++ ++ my $f = $_->[1]; ++ # The basic things we're trying to build ++ my @programs = (); ++ my @programs_install = (); ++ my @libraries = (); ++ my @libraries_install = (); ++ my @engines = (); ++ my @engines_install = (); ++ my @scripts = (); ++ my @scripts_install = (); ++ my @extra = (); ++ my @overrides = (); ++ my @intermediates = (); ++ my @rawlines = (); ++ ++ my %ordinals = (); ++ my %sources = (); ++ my %shared_sources = (); ++ my %includes = (); ++ my %depends = (); ++ my %renames = (); ++ my %sharednames = (); ++ my %generate = (); ++ ++ push @{$config{build_infos}}, catfile(abs2rel($sourced, $blddir), $f); ++ my $template = Text::Template->new(TYPE => 'FILE', ++ SOURCE => catfile($sourced, $f)); ++ die "Something went wrong with $sourced/$f: $!\n" unless $template; ++ my @text = ++ split /^/m, ++ $template->fill_in(HASH => { config => \%config, ++ target => \%target, ++ disabled => \%disabled, ++ withargs => \%withargs, ++ builddir => abs2rel($buildd, $blddir), ++ sourcedir => abs2rel($sourced, $blddir), ++ buildtop => abs2rel($blddir, $blddir), ++ sourcetop => abs2rel($srcdir, $blddir) }, ++ DELIMITERS => [ "{-", "-}" ]); ++ ++ # The top item of this stack has the following values ++ # -2 positive already run and we found ELSE (following ELSIF should fail) ++ # -1 positive already run (skip until ENDIF) ++ # 0 negatives so far (if we're at a condition, check it) ++ # 1 last was positive (don't skip lines until next ELSE, ELSIF or ENDIF) ++ # 2 positive ELSE (following ELSIF should fail) ++ my @skip = (); ++ collect_information( ++ collect_from_array([ @text ], ++ qr/\\$/ => sub { my $l1 = shift; my $l2 = shift; ++ $l1 =~ s/\\$//; $l1.$l2 }), ++ # Info we're looking for ++ qr/^\s*IF\[((?:\\.|[^\\\]])*)\]\s*$/ ++ => sub { ++ if (! @skip || $skip[$#skip] > 0) { ++ push @skip, !! $1; ++ } else { ++ push @skip, -1; ++ } ++ }, ++ qr/^\s*ELSIF\[((?:\\.|[^\\\]])*)\]\s*$/ ++ => sub { die "ELSIF out of scope" if ! @skip; ++ die "ELSIF following ELSE" if abs($skip[$#skip]) == 2; ++ $skip[$#skip] = -1 if $skip[$#skip] != 0; ++ $skip[$#skip] = !! $1 ++ if $skip[$#skip] == 0; }, ++ qr/^\s*ELSE\s*$/ ++ => sub { die "ELSE out of scope" if ! @skip; ++ $skip[$#skip] = -2 if $skip[$#skip] != 0; ++ $skip[$#skip] = 2 if $skip[$#skip] == 0; }, ++ qr/^\s*ENDIF\s*$/ ++ => sub { die "ENDIF out of scope" if ! @skip; ++ pop @skip; }, ++ qr/^\s*PROGRAMS(_NO_INST)?\s*=\s*(.*)\s*$/ ++ => sub { ++ if (!@skip || $skip[$#skip] > 0) { ++ my $install = $1; ++ my @x = tokenize($2); ++ push @programs, @x; ++ push @programs_install, @x unless $install; ++ } ++ }, ++ qr/^\s*LIBS(_NO_INST)?\s*=\s*(.*)\s*$/ ++ => sub { ++ if (!@skip || $skip[$#skip] > 0) { ++ my $install = $1; ++ my @x = tokenize($2); ++ push @libraries, @x; ++ push @libraries_install, @x unless $install; ++ } ++ }, ++ qr/^\s*ENGINES(_NO_INST)?\s*=\s*(.*)\s*$/ ++ => sub { ++ if (!@skip || $skip[$#skip] > 0) { ++ my $install = $1; ++ my @x = tokenize($2); ++ push @engines, @x; ++ push @engines_install, @x unless $install; ++ } ++ }, ++ qr/^\s*SCRIPTS(_NO_INST)?\s*=\s*(.*)\s*$/ ++ => sub { ++ if (!@skip || $skip[$#skip] > 0) { ++ my $install = $1; ++ my @x = tokenize($2); ++ push @scripts, @x; ++ push @scripts_install, @x unless $install; ++ } ++ }, ++ qr/^\s*EXTRA\s*=\s*(.*)\s*$/ ++ => sub { push @extra, tokenize($1) ++ if !@skip || $skip[$#skip] > 0 }, ++ qr/^\s*OVERRIDES\s*=\s*(.*)\s*$/ ++ => sub { push @overrides, tokenize($1) ++ if !@skip || $skip[$#skip] > 0 }, ++ ++ qr/^\s*ORDINALS\[((?:\\.|[^\\\]])+)\]\s*=\s*(.*)\s*$/, ++ => sub { push @{$ordinals{$1}}, tokenize($2) ++ if !@skip || $skip[$#skip] > 0 }, ++ qr/^\s*SOURCE\[((?:\\.|[^\\\]])+)\]\s*=\s*(.*)\s*$/ ++ => sub { push @{$sources{$1}}, tokenize($2) ++ if !@skip || $skip[$#skip] > 0 }, ++ qr/^\s*SHARED_SOURCE\[((?:\\.|[^\\\]])+)\]\s*=\s*(.*)\s*$/ ++ => sub { push @{$shared_sources{$1}}, tokenize($2) ++ if !@skip || $skip[$#skip] > 0 }, ++ qr/^\s*INCLUDE\[((?:\\.|[^\\\]])+)\]\s*=\s*(.*)\s*$/ ++ => sub { push @{$includes{$1}}, tokenize($2) ++ if !@skip || $skip[$#skip] > 0 }, ++ qr/^\s*DEPEND\[((?:\\.|[^\\\]])*)\]\s*=\s*(.*)\s*$/ ++ => sub { push @{$depends{$1}}, tokenize($2) ++ if !@skip || $skip[$#skip] > 0 }, ++ qr/^\s*GENERATE\[((?:\\.|[^\\\]])+)\]\s*=\s*(.*)\s*$/ ++ => sub { push @{$generate{$1}}, $2 ++ if !@skip || $skip[$#skip] > 0 }, ++ qr/^\s*RENAME\[((?:\\.|[^\\\]])+)\]\s*=\s*(.*)\s*$/ ++ => sub { push @{$renames{$1}}, tokenize($2) ++ if !@skip || $skip[$#skip] > 0 }, ++ qr/^\s*SHARED_NAME\[((?:\\.|[^\\\]])+)\]\s*=\s*(.*)\s*$/ ++ => sub { push @{$sharednames{$1}}, tokenize($2) ++ if !@skip || $skip[$#skip] > 0 }, ++ qr/^\s*BEGINRAW\[((?:\\.|[^\\\]])+)\]\s*$/ ++ => sub { ++ my $lineiterator = shift; ++ my $target_kind = $1; ++ while (defined $lineiterator->()) { ++ s|\R$||; ++ if (/^\s*ENDRAW\[((?:\\.|[^\\\]])+)\]\s*$/) { ++ die "ENDRAW doesn't match BEGINRAW" ++ if $1 ne $target_kind; ++ last; ++ } ++ next if @skip && $skip[$#skip] <= 0; ++ push @rawlines, $_ ++ if ($target_kind eq $target{build_file} ++ || $target_kind eq $target{build_file}."(".$builder_platform.")"); ++ } ++ }, ++ qr/^(?:#.*|\s*)$/ => sub { }, ++ "OTHERWISE" => sub { die "Something wrong with this line:\n$_\nat $sourced/$f" }, ++ "BEFORE" => sub { ++ if ($buildinfo_debug) { ++ print STDERR "DEBUG: Parsing ",join(" ", @_),"\n"; ++ print STDERR "DEBUG: ... before parsing, skip stack is ",join(" ", map { int($_) } @skip),"\n"; ++ } ++ }, ++ "AFTER" => sub { ++ if ($buildinfo_debug) { ++ print STDERR "DEBUG: .... after parsing, skip stack is ",join(" ", map { int($_) } @skip),"\n"; ++ } ++ }, ++ ); ++ die "runaway IF?" if (@skip); ++ ++ foreach (keys %renames) { ++ die "$_ renamed to more than one thing: " ++ ,join(" ", @{$renames{$_}}),"\n" ++ if scalar @{$renames{$_}} > 1; ++ my $dest = cleanfile($buildd, $_, $blddir); ++ my $to = cleanfile($buildd, $renames{$_}->[0], $blddir); ++ die "$dest renamed to more than one thing: " ++ ,$unified_info{rename}->{$dest}, $to ++ unless !defined($unified_info{rename}->{$dest}) ++ or $unified_info{rename}->{$dest} eq $to; ++ $unified_info{rename}->{$dest} = $to; ++ } ++ ++ foreach (@programs) { ++ my $program = cleanfile($buildd, $_, $blddir); ++ if ($unified_info{rename}->{$program}) { ++ $program = $unified_info{rename}->{$program}; ++ } ++ $unified_info{programs}->{$program} = 1; ++ } ++ ++ foreach (@programs_install) { ++ my $program = cleanfile($buildd, $_, $blddir); ++ if ($unified_info{rename}->{$program}) { ++ $program = $unified_info{rename}->{$program}; ++ } ++ $unified_info{install}->{programs}->{$program} = 1; ++ } ++ ++ foreach (@libraries) { ++ my $library = cleanfile($buildd, $_, $blddir); ++ if ($unified_info{rename}->{$library}) { ++ $library = $unified_info{rename}->{$library}; ++ } ++ $unified_info{libraries}->{$library} = 1; ++ } ++ ++ foreach (@libraries_install) { ++ my $library = cleanfile($buildd, $_, $blddir); ++ if ($unified_info{rename}->{$library}) { ++ $library = $unified_info{rename}->{$library}; ++ } ++ $unified_info{install}->{libraries}->{$library} = 1; ++ } ++ ++ die <<"EOF" if scalar @engines and !$config{dynamic_engines}; ++ENGINES can only be used if configured with 'dynamic-engine'. ++This is usually a fault in a build.info file. ++EOF ++ foreach (@engines) { ++ my $library = cleanfile($buildd, $_, $blddir); ++ if ($unified_info{rename}->{$library}) { ++ $library = $unified_info{rename}->{$library}; ++ } ++ $unified_info{engines}->{$library} = 1; ++ } ++ ++ foreach (@engines_install) { ++ my $library = cleanfile($buildd, $_, $blddir); ++ if ($unified_info{rename}->{$library}) { ++ $library = $unified_info{rename}->{$library}; ++ } ++ $unified_info{install}->{engines}->{$library} = 1; ++ } ++ ++ foreach (@scripts) { ++ my $script = cleanfile($buildd, $_, $blddir); ++ if ($unified_info{rename}->{$script}) { ++ $script = $unified_info{rename}->{$script}; ++ } ++ $unified_info{scripts}->{$script} = 1; ++ } ++ ++ foreach (@scripts_install) { ++ my $script = cleanfile($buildd, $_, $blddir); ++ if ($unified_info{rename}->{$script}) { ++ $script = $unified_info{rename}->{$script}; ++ } ++ $unified_info{install}->{scripts}->{$script} = 1; ++ } ++ ++ foreach (@extra) { ++ my $extra = cleanfile($buildd, $_, $blddir); ++ $unified_info{extra}->{$extra} = 1; ++ } ++ ++ foreach (@overrides) { ++ my $override = cleanfile($buildd, $_, $blddir); ++ $unified_info{overrides}->{$override} = 1; ++ } ++ ++ push @{$unified_info{rawlines}}, @rawlines; ++ ++ unless ($disabled{shared}) { ++ # Check sharednames. ++ foreach (keys %sharednames) { ++ my $dest = cleanfile($buildd, $_, $blddir); ++ if ($unified_info{rename}->{$dest}) { ++ $dest = $unified_info{rename}->{$dest}; ++ } ++ die "shared_name for $dest with multiple values: " ++ ,join(" ", @{$sharednames{$_}}),"\n" ++ if scalar @{$sharednames{$_}} > 1; ++ my $to = cleanfile($buildd, $sharednames{$_}->[0], $blddir); ++ die "shared_name found for a library $dest that isn't defined\n" ++ unless $unified_info{libraries}->{$dest}; ++ die "shared_name for $dest with multiple values: " ++ ,$unified_info{sharednames}->{$dest}, ", ", $to ++ unless !defined($unified_info{sharednames}->{$dest}) ++ or $unified_info{sharednames}->{$dest} eq $to; ++ $unified_info{sharednames}->{$dest} = $to; ++ } ++ ++ # Additionally, we set up sharednames for libraries that don't ++ # have any, as themselves. ++ foreach (keys %{$unified_info{libraries}}) { ++ if (!defined $unified_info{sharednames}->{$_}) { ++ $unified_info{sharednames}->{$_} = $_ ++ } ++ } ++ } ++ ++ foreach (keys %ordinals) { ++ my $dest = $_; ++ my $ddest = cleanfile($buildd, $_, $blddir); ++ if ($unified_info{rename}->{$ddest}) { ++ $ddest = $unified_info{rename}->{$ddest}; ++ } ++ foreach (@{$ordinals{$dest}}) { ++ my %known_ordinals = ++ ( ++ crypto => ++ cleanfile($sourced, catfile("util", "libcrypto.num"), $blddir), ++ ssl => ++ cleanfile($sourced, catfile("util", "libssl.num"), $blddir) ++ ); ++ my $o = $known_ordinals{$_}; ++ die "Ordinals for $ddest defined more than once\n" ++ if $unified_info{ordinals}->{$ddest}; ++ $unified_info{ordinals}->{$ddest} = [ $_, $o ]; ++ } ++ } ++ ++ foreach (keys %sources) { ++ my $dest = $_; ++ my $ddest = cleanfile($buildd, $_, $blddir); ++ if ($unified_info{rename}->{$ddest}) { ++ $ddest = $unified_info{rename}->{$ddest}; ++ } ++ foreach (@{$sources{$dest}}) { ++ my $s = cleanfile($sourced, $_, $blddir); ++ ++ # If it isn't in the source tree, we assume it's generated ++ # in the build tree ++ if (! -f $s) { ++ $s = cleanfile($buildd, $_, $blddir); ++ } ++ # We recognise C and asm files ++ if ($s =~ /\.[csS]\b$/) { ++ (my $o = $_) =~ s/\.[csS]\b$/.o/; ++ $o = cleanfile($buildd, $o, $blddir); ++ $unified_info{sources}->{$ddest}->{$o} = 1; ++ $unified_info{sources}->{$o}->{$s} = 1; ++ } else { ++ $unified_info{sources}->{$ddest}->{$s} = 1; ++ } ++ } ++ } ++ ++ foreach (keys %shared_sources) { ++ my $dest = $_; ++ my $ddest = cleanfile($buildd, $_, $blddir); ++ if ($unified_info{rename}->{$ddest}) { ++ $ddest = $unified_info{rename}->{$ddest}; ++ } ++ foreach (@{$shared_sources{$dest}}) { ++ my $s = cleanfile($sourced, $_, $blddir); ++ ++ # If it isn't in the source tree, we assume it's generated ++ # in the build tree ++ if (! -f $s) { ++ $s = cleanfile($buildd, $_, $blddir); ++ } ++ # We recognise C and asm files ++ if ($s =~ /\.[csS]\b$/) { ++ (my $o = $_) =~ s/\.[csS]\b$/.o/; ++ $o = cleanfile($buildd, $o, $blddir); ++ $unified_info{shared_sources}->{$ddest}->{$o} = 1; ++ $unified_info{sources}->{$o}->{$s} = 1; ++ } else { ++ die "unrecognised source file type for shared library: $s\n"; ++ } ++ } ++ } ++ ++ foreach (keys %generate) { ++ my $dest = $_; ++ my $ddest = cleanfile($buildd, $_, $blddir); ++ if ($unified_info{rename}->{$ddest}) { ++ $ddest = $unified_info{rename}->{$ddest}; ++ } ++ die "more than one generator for $dest: " ++ ,join(" ", @{$generate{$_}}),"\n" ++ if scalar @{$generate{$_}} > 1; ++ my @generator = split /\s+/, $generate{$dest}->[0]; ++ $generator[0] = cleanfile($sourced, $generator[0], $blddir), ++ $unified_info{generate}->{$ddest} = [ @generator ]; ++ } ++ ++ foreach (keys %depends) { ++ my $dest = $_; ++ my $ddest = $dest eq "" ? "" : cleanfile($sourced, $_, $blddir); ++ ++ # If the destination doesn't exist in source, it can only be ++ # a generated file in the build tree. ++ if ($ddest ne "" && ! -f $ddest) { ++ $ddest = cleanfile($buildd, $_, $blddir); ++ if ($unified_info{rename}->{$ddest}) { ++ $ddest = $unified_info{rename}->{$ddest}; ++ } ++ } ++ foreach (@{$depends{$dest}}) { ++ my $d = cleanfile($sourced, $_, $blddir); ++ ++ # If we know it's generated, or assume it is because we can't ++ # find it in the source tree, we set file we depend on to be ++ # in the build tree rather than the source tree, and assume ++ # and that there are lines to build it in a BEGINRAW..ENDRAW ++ # section or in the Makefile template. ++ if (! -f $d ++ || (grep { $d eq $_ } ++ map { cleanfile($srcdir, $_, $blddir) } ++ grep { /\.h$/ } keys %{$unified_info{generate}})) { ++ $d = cleanfile($buildd, $_, $blddir); ++ } ++ # Take note if the file to depend on is being renamed ++ if ($unified_info{rename}->{$d}) { ++ $d = $unified_info{rename}->{$d}; ++ } ++ $unified_info{depends}->{$ddest}->{$d} = 1; ++ # If we depend on a header file or a perl module, let's make ++ # sure it can get included ++ if ($dest ne "" && $d =~ /\.(h|pm)$/) { ++ my $i = dirname($d); ++ push @{$unified_info{includes}->{$ddest}->{source}}, $i ++ unless grep { $_ eq $i } @{$unified_info{includes}->{$ddest}->{source}}; ++ } ++ } ++ } ++ ++ foreach (keys %includes) { ++ my $dest = $_; ++ my $ddest = cleanfile($sourced, $_, $blddir); ++ ++ # If the destination doesn't exist in source, it can only be ++ # a generated file in the build tree. ++ if (! -f $ddest) { ++ $ddest = cleanfile($buildd, $_, $blddir); ++ if ($unified_info{rename}->{$ddest}) { ++ $ddest = $unified_info{rename}->{$ddest}; ++ } ++ } ++ foreach (@{$includes{$dest}}) { ++ my $is = cleandir($sourced, $_, $blddir); ++ my $ib = cleandir($buildd, $_, $blddir); ++ push @{$unified_info{includes}->{$ddest}->{source}}, $is ++ unless grep { $_ eq $is } @{$unified_info{includes}->{$ddest}->{source}}; ++ push @{$unified_info{includes}->{$ddest}->{build}}, $ib ++ unless grep { $_ eq $ib } @{$unified_info{includes}->{$ddest}->{build}}; ++ } ++ } ++ } ++ ++ ### Make unified_info a bit more efficient ++ # One level structures ++ foreach (("programs", "libraries", "engines", "scripts", "extra", "overrides")) { ++ $unified_info{$_} = [ sort keys %{$unified_info{$_}} ]; ++ } ++ # Two level structures ++ foreach my $l1 (("install", "sources", "shared_sources", "ldadd", "depends")) { ++ foreach my $l2 (sort keys %{$unified_info{$l1}}) { ++ $unified_info{$l1}->{$l2} = ++ [ sort keys %{$unified_info{$l1}->{$l2}} ]; ++ } ++ } ++ # Includes ++ foreach my $dest (sort keys %{$unified_info{includes}}) { ++ if (defined($unified_info{includes}->{$dest}->{build})) { ++ my @source_includes = ++ ( @{$unified_info{includes}->{$dest}->{source}} ); ++ $unified_info{includes}->{$dest} = ++ [ @{$unified_info{includes}->{$dest}->{build}} ]; ++ foreach my $inc (@source_includes) { ++ push @{$unified_info{includes}->{$dest}}, $inc ++ unless grep { $_ eq $inc } @{$unified_info{includes}->{$dest}}; ++ } ++ } else { ++ $unified_info{includes}->{$dest} = ++ [ @{$unified_info{includes}->{$dest}->{source}} ]; ++ } ++ } ++} ++ ++# For the schemes that need it, we provide the old *_obj configs ++# from the *_asm_obj ones ++foreach (grep /_(asm|aux)_src$/, keys %target) { ++ my $src = $_; ++ (my $obj = $_) =~ s/_(asm|aux)_src$/_obj/; ++ ($target{$obj} = $target{$src}) =~ s/\.[csS]\b/.o/g; ++} ++ ++# Write down our configuration where it fits ######################### ++ ++open(OUT,">configdata.pm") || die "unable to create configdata.pm: $!\n"; ++print OUT <<"EOF"; ++package configdata; ++ ++use strict; ++use warnings; ++ ++use Exporter; ++#use vars qw(\@ISA \@EXPORT); ++our \@ISA = qw(Exporter); ++our \@EXPORT = qw(\%config \%target \%disabled \%withargs \%unified_info \@disablables); ++ ++EOF ++print OUT "our %config = (\n"; ++foreach (sort keys %config) { ++ if (ref($config{$_}) eq "ARRAY") { ++ print OUT " ", $_, " => [ ", join(", ", ++ map { quotify("perl", $_) } ++ @{$config{$_}}), " ],\n"; ++ } else { ++ print OUT " ", $_, " => ", quotify("perl", $config{$_}), ",\n" ++ } ++} ++print OUT <<"EOF"; ++); ++ ++EOF ++print OUT "our %target = (\n"; ++foreach (sort keys %target) { ++ if (ref($target{$_}) eq "ARRAY") { ++ print OUT " ", $_, " => [ ", join(", ", ++ map { quotify("perl", $_) } ++ @{$target{$_}}), " ],\n"; ++ } else { ++ print OUT " ", $_, " => ", quotify("perl", $target{$_}), ",\n" ++ } ++} ++print OUT <<"EOF"; ++); ++ ++EOF ++print OUT "our \%available_protocols = (\n"; ++print OUT " tls => [ ", join(", ", map { quotify("perl", $_) } @tls), " ],\n"; ++print OUT " dtls => [ ", join(", ", map { quotify("perl", $_) } @dtls), " ],\n"; ++print OUT <<"EOF"; ++); ++ ++EOF ++print OUT "our \@disablables = (\n"; ++foreach (@disablables) { ++ print OUT " ", quotify("perl", $_), ",\n"; ++} ++print OUT <<"EOF"; ++); ++ ++EOF ++print OUT "our \%disabled = (\n"; ++foreach (sort keys %disabled) { ++ print OUT " ", quotify("perl", $_), " => ", quotify("perl", $disabled{$_}), ",\n"; ++} ++print OUT <<"EOF"; ++); ++ ++EOF ++print OUT "our %withargs = (\n"; ++foreach (sort keys %withargs) { ++ if (ref($withargs{$_}) eq "ARRAY") { ++ print OUT " ", $_, " => [ ", join(", ", ++ map { quotify("perl", $_) } ++ @{$withargs{$_}}), " ],\n"; ++ } else { ++ print OUT " ", $_, " => ", quotify("perl", $withargs{$_}), ",\n" ++ } ++} ++print OUT <<"EOF"; ++); ++ ++EOF ++if ($builder eq "unified") { ++ my $recurse; ++ $recurse = sub { ++ my $indent = shift; ++ foreach (@_) { ++ if (ref $_ eq "ARRAY") { ++ print OUT " "x$indent, "[\n"; ++ foreach (@$_) { ++ $recurse->($indent + 4, $_); ++ } ++ print OUT " "x$indent, "],\n"; ++ } elsif (ref $_ eq "HASH") { ++ my %h = %$_; ++ print OUT " "x$indent, "{\n"; ++ foreach (sort keys %h) { ++ if (ref $h{$_} eq "") { ++ print OUT " "x($indent + 4), quotify("perl", $_), " => ", quotify("perl", $h{$_}), ",\n"; ++ } else { ++ print OUT " "x($indent + 4), quotify("perl", $_), " =>\n"; ++ $recurse->($indent + 8, $h{$_}); ++ } ++ } ++ print OUT " "x$indent, "},\n"; ++ } else { ++ print OUT " "x$indent, quotify("perl", $_), ",\n"; ++ } ++ } ++ }; ++ print OUT "our %unified_info = (\n"; ++ foreach (sort keys %unified_info) { ++ if (ref $unified_info{$_} eq "") { ++ print OUT " "x4, quotify("perl", $_), " => ", quotify("perl", $unified_info{$_}), ",\n"; ++ } else { ++ print OUT " "x4, quotify("perl", $_), " =>\n"; ++ $recurse->(8, $unified_info{$_}); ++ } ++ } ++ print OUT <<"EOF"; ++); ++ ++EOF ++} ++print OUT "1;\n"; ++close(OUT); ++ ++ ++print "CC =$config{cross_compile_prefix}$target{cc}\n"; ++print "CFLAG =$target{cflags} $config{cflags}\n"; ++print "SHARED_CFLAG =$target{shared_cflag}\n"; ++print "DEFINES =",join(" ", @{$target{defines}}, @{$config{defines}}),"\n"; ++print "LFLAG =$target{lflags}\n"; ++print "PLIB_LFLAG =$target{plib_lflags}\n"; ++print "EX_LIBS =$target{ex_libs} $config{ex_libs}\n"; ++print "APPS_OBJ =$target{apps_obj}\n"; ++print "CPUID_OBJ =$target{cpuid_obj}\n"; ++print "UPLINK_OBJ =$target{uplink_obj}\n"; ++print "BN_ASM =$target{bn_obj}\n"; ++print "EC_ASM =$target{ec_obj}\n"; ++print "DES_ENC =$target{des_obj}\n"; ++print "AES_ENC =$target{aes_obj}\n"; ++print "BF_ENC =$target{bf_obj}\n"; ++print "CAST_ENC =$target{cast_obj}\n"; ++print "RC4_ENC =$target{rc4_obj}\n"; ++print "RC5_ENC =$target{rc5_obj}\n"; ++print "MD5_OBJ_ASM =$target{md5_obj}\n"; ++print "SHA1_OBJ_ASM =$target{sha1_obj}\n"; ++print "RMD160_OBJ_ASM=$target{rmd160_obj}\n"; ++print "CMLL_ENC =$target{cmll_obj}\n"; ++print "MODES_OBJ =$target{modes_obj}\n"; ++print "PADLOCK_OBJ =$target{padlock_obj}\n"; ++print "CHACHA_ENC =$target{chacha_obj}\n"; ++print "POLY1305_OBJ =$target{poly1305_obj}\n"; ++print "BLAKE2_OBJ =$target{blake2_obj}\n"; ++print "PROCESSOR =$config{processor}\n"; ++print "RANLIB =", $target{ranlib} eq '$(CROSS_COMPILE)ranlib' ? ++ "$config{cross_compile_prefix}ranlib" : ++ "$target{ranlib}", "\n"; ++print "ARFLAGS =$target{arflags}\n"; ++print "PERL =$config{perl}\n"; ++print "\n"; ++print "SIXTY_FOUR_BIT_LONG mode\n" if $config{b64l}; ++print "SIXTY_FOUR_BIT mode\n" if $config{b64}; ++print "THIRTY_TWO_BIT mode\n" if $config{b32}; ++print "BN_LLONG mode\n" if $config{bn_ll}; ++print "RC4 uses $config{rc4_int}\n" if $config{rc4_int} ne $def_int; ++ ++my %builders = ( ++ unified => sub { ++ run_dofile(catfile($blddir, $target{build_file}), ++ @{$config{build_file_templates}}); ++ }, ++ ); ++ ++$builders{$builder}->($builder_platform, @builder_opts); ++ ++print <<"EOF"; ++ ++Configured for $target. ++EOF ++ ++print <<"EOF" if ($disabled{threads} eq "unavailable"); ++ ++The library could not be configured for supporting multi-threaded ++applications as the compiler options required on this system are not known. ++See file INSTALL for details if you need multi-threading. ++EOF ++ ++print <<"EOF" if ($no_shared_warn); ++ ++The options 'shared', 'pic' and 'dynamic-engine' aren't supported on this ++platform, so we will pretend you gave the option 'no-pic', which also disables ++'shared' and 'dynamic-engine'. If you know how to implement shared libraries ++or position independent code, please let us know (but please first make sure ++you have tried with a current version of OpenSSL). ++EOF ++ ++print <<"EOF" if (-f catfile($srcdir, "configdata.pm") && $srcdir ne $blddir); ++ ++WARNING: there are indications that another build was made in the source ++directory. This build may have picked up artifacts from that build, the ++safest course of action is to clean the source directory and redo this ++configuration. ++EOF ++ ++exit(0); ++ ++###################################################################### ++# ++# Helpers and utility functions ++# ++ ++# Configuration file reading ######################################### ++ ++# Note: All of the helper functions are for lazy evaluation. They all ++# return a CODE ref, which will return the intended value when evaluated. ++# Thus, whenever there's mention of a returned value, it's about that ++# intended value. ++ ++# Helper function to implement conditional inheritance depending on the ++# value of $disabled{asm}. Used in inherit_from values as follows: ++# ++# inherit_from => [ "template", asm("asm_tmpl") ] ++# ++sub asm { ++ my @x = @_; ++ sub { ++ $disabled{asm} ? () : @x; ++ } ++} ++ ++# Helper function to implement conditional value variants, with a default ++# plus additional values based on the value of $config{build_type}. ++# Arguments are given in hash table form: ++# ++# picker(default => "Basic string: ", ++# debug => "debug", ++# release => "release") ++# ++# When configuring with --debug, the resulting string will be ++# "Basic string: debug", and when not, it will be "Basic string: release" ++# ++# This can be used to create variants of sets of flags according to the ++# build type: ++# ++# cflags => picker(default => "-Wall", ++# debug => "-g -O0", ++# release => "-O3") ++# ++sub picker { ++ my %opts = @_; ++ return sub { add($opts{default} || (), ++ $opts{$config{build_type}} || ())->(); } ++} ++ ++# Helper function to combine several values of different types into one. ++# This is useful if you want to combine a string with the result of a ++# lazy function, such as: ++# ++# cflags => combine("-Wall", sub { $disabled{zlib} ? () : "-DZLIB" }) ++# ++sub combine { ++ my @stuff = @_; ++ return sub { add(@stuff)->(); } ++} ++ ++# Helper function to implement conditional values depending on the value ++# of $disabled{threads}. Can be used as follows: ++# ++# cflags => combine("-Wall", threads("-pthread")) ++# ++sub threads { ++ my @flags = @_; ++ return sub { add($disabled{threads} ? () : @flags)->(); } ++} ++ ++ ++ ++our $add_called = 0; ++# Helper function to implement adding values to already existing configuration ++# values. It handles elements that are ARRAYs, CODEs and scalars ++sub _add { ++ my $separator = shift; ++ ++ # If there's any ARRAY in the collection of values OR the separator ++ # is undef, we will return an ARRAY of combined values, otherwise a ++ # string of joined values with $separator as the separator. ++ my $found_array = !defined($separator); ++ ++ my @values = ++ map { ++ my $res = $_; ++ while (ref($res) eq "CODE") { ++ $res = $res->(); ++ } ++ if (defined($res)) { ++ if (ref($res) eq "ARRAY") { ++ $found_array = 1; ++ @$res; ++ } else { ++ $res; ++ } ++ } else { ++ (); ++ } ++ } (@_); ++ ++ $add_called = 1; ++ ++ if ($found_array) { ++ [ @values ]; ++ } else { ++ join($separator, grep { defined($_) && $_ ne "" } @values); ++ } ++} ++sub add_before { ++ my $separator = " "; ++ if (ref($_[$#_]) eq "HASH") { ++ my $opts = pop; ++ $separator = $opts->{separator}; ++ } ++ my @x = @_; ++ sub { _add($separator, @x, @_) }; ++} ++sub add { ++ my $separator = " "; ++ if (ref($_[$#_]) eq "HASH") { ++ my $opts = pop; ++ $separator = $opts->{separator}; ++ } ++ my @x = @_; ++ sub { _add($separator, @_, @x) }; ++} ++ ++# configuration reader, evaluates the input file as a perl script and expects ++# it to fill %targets with target configurations. Those are then added to ++# %table. ++sub read_config { ++ my $fname = shift; ++ open(CONFFILE, "< $fname") ++ or die "Can't open configuration file '$fname'!\n"; ++ my $x = $/; ++ undef $/; ++ my $content = ; ++ $/ = $x; ++ close(CONFFILE); ++ my %targets = (); ++ { ++ # Protect certain tables from tampering ++ local %table = %::table; ++ ++ eval $content; ++ warn $@ if $@; ++ } ++ ++ # For each target, check that it's configured with a hash table. ++ foreach (keys %targets) { ++ if (ref($targets{$_}) ne "HASH") { ++ if (ref($targets{$_}) eq "") { ++ warn "Deprecated target configuration for $_, ignoring...\n"; ++ } else { ++ warn "Misconfigured target configuration for $_ (should be a hash table), ignoring...\n"; ++ } ++ delete $targets{$_}; ++ } else { ++ $targets{$_}->{_conf_fname_int} = add([ $fname ]); ++ } ++ } ++ ++ %table = (%table, %targets); ++ ++} ++ ++# configuration resolver. Will only resolve all the lazy evaluation ++# codeblocks for the chosen target and all those it inherits from, ++# recursively ++sub resolve_config { ++ my $target = shift; ++ my @breadcrumbs = @_; ++ ++# my $extra_checks = defined($ENV{CONFIGURE_EXTRA_CHECKS}); ++ ++ if (grep { $_ eq $target } @breadcrumbs) { ++ die "inherit_from loop! target backtrace:\n " ++ ,$target,"\n ",join("\n ", @breadcrumbs),"\n"; ++ } ++ ++ if (!defined($table{$target})) { ++ warn "Warning! target $target doesn't exist!\n"; ++ return (); ++ } ++ # Recurse through all inheritances. They will be resolved on the ++ # fly, so when this operation is done, they will all just be a ++ # bunch of attributes with string values. ++ # What we get here, though, are keys with references to lists of ++ # the combined values of them all. We will deal with lists after ++ # this stage is done. ++ my %combined_inheritance = (); ++ if ($table{$target}->{inherit_from}) { ++ my @inherit_from = ++ map { ref($_) eq "CODE" ? $_->() : $_ } @{$table{$target}->{inherit_from}}; ++ foreach (@inherit_from) { ++ my %inherited_config = resolve_config($_, $target, @breadcrumbs); ++ ++ # 'template' is a marker that's considered private to ++ # the config that had it. ++ delete $inherited_config{template}; ++ ++ foreach (keys %inherited_config) { ++ if (!$combined_inheritance{$_}) { ++ $combined_inheritance{$_} = []; ++ } ++ push @{$combined_inheritance{$_}}, $inherited_config{$_}; ++ } ++ } ++ } ++ ++ # We won't need inherit_from in this target any more, since we've ++ # resolved all the inheritances that lead to this ++ delete $table{$target}->{inherit_from}; ++ ++ # Now is the time to deal with those lists. Here's the place to ++ # decide what shall be done with those lists, all based on the ++ # values of the target we're currently dealing with. ++ # - If a value is a coderef, it will be executed with the list of ++ # inherited values as arguments. ++ # - If the corresponding key doesn't have a value at all or is the ++ # empty string, the inherited value list will be run through the ++ # default combiner (below), and the result becomes this target's ++ # value. ++ # - Otherwise, this target's value is assumed to be a string that ++ # will simply override the inherited list of values. ++ my $default_combiner = add(); ++ ++ my %all_keys = ++ map { $_ => 1 } (keys %combined_inheritance, ++ keys %{$table{$target}}); ++ ++ sub process_values { ++ my $object = shift; ++ my $inherited = shift; # Always a [ list ] ++ my $target = shift; ++ my $entry = shift; ++ ++ $add_called = 0; ++ ++ while(ref($object) eq "CODE") { ++ $object = $object->(@$inherited); ++ } ++ if (!defined($object)) { ++ return (); ++ } ++ elsif (ref($object) eq "ARRAY") { ++ local $add_called; # To make sure recursive calls don't affect it ++ return [ map { process_values($_, $inherited, $target, $entry) } ++ @$object ]; ++ } elsif (ref($object) eq "") { ++ return $object; ++ } else { ++ die "cannot handle reference type ",ref($object) ++ ," found in target ",$target," -> ",$entry,"\n"; ++ } ++ } ++ ++ foreach (sort keys %all_keys) { ++ my $previous = $combined_inheritance{$_}; ++ ++ # Current target doesn't have a value for the current key? ++ # Assign it the default combiner, the rest of this loop body ++ # will handle it just like any other coderef. ++ if (!exists $table{$target}->{$_}) { ++ $table{$target}->{$_} = $default_combiner; ++ } ++ ++ $table{$target}->{$_} = process_values($table{$target}->{$_}, ++ $combined_inheritance{$_}, ++ $target, $_); ++ unless(defined($table{$target}->{$_})) { ++ delete $table{$target}->{$_}; ++ } ++# if ($extra_checks && ++# $previous && !($add_called || $previous ~~ $table{$target}->{$_})) { ++# warn "$_ got replaced in $target\n"; ++# } ++ } ++ ++ # Finally done, return the result. ++ return %{$table{$target}}; ++} ++ ++sub usage ++ { ++ print STDERR $usage; ++ print STDERR "\npick os/compiler from:\n"; ++ my $j=0; ++ my $i; ++ my $k=0; ++ foreach $i (sort keys %table) ++ { ++ next if $table{$i}->{template}; ++ next if $i =~ /^debug/; ++ $k += length($i) + 1; ++ if ($k > 78) ++ { ++ print STDERR "\n"; ++ $k=length($i); ++ } ++ print STDERR $i . " "; ++ } ++ foreach $i (sort keys %table) ++ { ++ next if $table{$i}->{template}; ++ next if $i !~ /^debug/; ++ $k += length($i) + 1; ++ if ($k > 78) ++ { ++ print STDERR "\n"; ++ $k=length($i); ++ } ++ print STDERR $i . " "; ++ } ++ print STDERR "\n\nNOTE: If in doubt, on Unix-ish systems use './config'.\n"; ++ exit(1); ++ } ++ ++sub run_dofile ++{ ++ my $out = shift; ++ my @templates = @_; ++ ++ unlink $out || warn "Can't remove $out, $!" ++ if -f $out; ++ foreach (@templates) { ++ die "Can't open $_, $!" unless -f $_; ++ } ++ my $perlcmd = (quotify("maybeshell", $config{perl}))[0]; ++ my $cmd = "$perlcmd \"-I.\" \"-Mconfigdata\" \"$dofile\" -o\"Configure\" \"".join("\" \"",@templates)."\" > \"$out.new\""; ++ #print STDERR "DEBUG[run_dofile]: \$cmd = $cmd\n"; ++ system($cmd); ++ exit 1 if $? != 0; ++ rename("$out.new", $out) || die "Can't rename $out.new, $!"; ++} ++ ++sub which ++{ ++ my ($name)=@_; ++ ++ if (eval { require IPC::Cmd; 1; }) { ++ IPC::Cmd->import(); ++ return scalar IPC::Cmd::can_run($name); ++ } else { ++ # if there is $directories component in splitpath, ++ # then it's not something to test with $PATH... ++ return $name if (File::Spec->splitpath($name))[1]; ++ ++ foreach (File::Spec->path()) { ++ my $fullpath = catfile($_, "$name$target{exe_extension}"); ++ if (-f $fullpath and -x $fullpath) { ++ return $fullpath; ++ } ++ } ++ } ++} ++ ++# Configuration printer ############################################## ++ ++sub print_table_entry ++{ ++ my $target = shift; ++ my %target = resolve_config($target); ++ my $type = shift; ++ ++ # Don't print the templates ++ return if $target{template}; ++ ++ my @sequence = ( ++ "sys_id", ++ "cc", ++ "cflags", ++ "defines", ++ "unistd", ++ "ld", ++ "lflags", ++ "loutflag", ++ "plib_lflags", ++ "ex_libs", ++ "bn_ops", ++ "apps_aux_src", ++ "cpuid_asm_src", ++ "uplink_aux_src", ++ "bn_asm_src", ++ "ec_asm_src", ++ "des_asm_src", ++ "aes_asm_src", ++ "bf_asm_src", ++ "md5_asm_src", ++ "cast_asm_src", ++ "sha1_asm_src", ++ "rc4_asm_src", ++ "rmd160_asm_src", ++ "rc5_asm_src", ++ "wp_asm_src", ++ "cmll_asm_src", ++ "modes_asm_src", ++ "padlock_asm_src", ++ "chacha_asm_src", ++ "poly1035_asm_src", ++ "thread_scheme", ++ "perlasm_scheme", ++ "dso_scheme", ++ "shared_target", ++ "shared_cflag", ++ "shared_defines", ++ "shared_ldflag", ++ "shared_rcflag", ++ "shared_extension", ++ "dso_extension", ++ "obj_extension", ++ "exe_extension", ++ "ranlib", ++ "ar", ++ "arflags", ++ "aroutflag", ++ "rc", ++ "rcflags", ++ "rcoutflag", ++ "mt", ++ "mtflags", ++ "mtinflag", ++ "mtoutflag", ++ "multilib", ++ "build_scheme", ++ ); ++ ++ if ($type eq "TABLE") { ++ print "\n"; ++ print "*** $target\n"; ++ foreach (@sequence) { ++ if (ref($target{$_}) eq "ARRAY") { ++ printf "\$%-12s = %s\n", $_, join(" ", @{$target{$_}}); ++ } else { ++ printf "\$%-12s = %s\n", $_, $target{$_}; ++ } ++ } ++ } elsif ($type eq "HASH") { ++ my $largest = ++ length((sort { length($a) <=> length($b) } @sequence)[-1]); ++ print " '$target' => {\n"; ++ foreach (@sequence) { ++ if ($target{$_}) { ++ if (ref($target{$_}) eq "ARRAY") { ++ print " '",$_,"'"," " x ($largest - length($_))," => [ ",join(", ", map { "'$_'" } @{$target{$_}})," ],\n"; ++ } else { ++ print " '",$_,"'"," " x ($largest - length($_))," => '",$target{$_},"',\n"; ++ } ++ } ++ } ++ print " },\n"; ++ } ++} ++ ++# Utility routines ################################################### ++ ++# On VMS, if the given file is a logical name, File::Spec::Functions ++# will consider it an absolute path. There are cases when we want a ++# purely syntactic check without checking the environment. ++sub isabsolute { ++ my $file = shift; ++ ++ # On non-platforms, we just use file_name_is_absolute(). ++ return file_name_is_absolute($file) unless $^O eq "VMS"; ++ ++ # If the file spec includes a device or a directpry spec, ++ # file_name_is_absolute() is perfectly safe. ++ return file_name_is_absolute($file) if $file =~ m|[:\[]|; ++ ++ # Here, we know the given file spec isn't absolute ++ return 0; ++} ++ ++# Makes a directory absolute and cleans out /../ in paths like foo/../bar ++# On some platforms, this uses rel2abs(), while on others, realpath() is used. ++# realpath() requires that at least all path components except the last is an ++# existing directory. On VMS, the last component of the directory spec must ++# exist. ++sub absolutedir { ++ my $dir = shift; ++ ++ # realpath() is quite buggy on VMS. It uses LIB$FID_TO_NAME, which ++ # will return the volume name for the device, no matter what. Also, ++ # it will return an incorrect directory spec if the argument is a ++ # directory that doesn't exist. ++ if ($^O eq "VMS") { ++ return rel2abs($dir); ++ } ++ ++ # We use realpath() on Unix, since no other will properly clean out ++ # a directory spec. ++ use Cwd qw/realpath/; ++ ++ return realpath($dir); ++} ++ ++sub quotify { ++ my %processors = ( ++ perl => sub { my $x = shift; ++ $x =~ s/([\\\$\@"])/\\$1/g; ++ return '"'.$x.'"'; }, ++ maybeshell => sub { my $x = shift; ++ (my $y = $x) =~ s/([\\\"])/\\$1/g; ++ if ($x ne $y || $x =~ m|\s|) { ++ return '"'.$y.'"'; ++ } else { ++ return $x; ++ } ++ }, ++ ); ++ my $for = shift; ++ my $processor = ++ defined($processors{$for}) ? $processors{$for} : sub { shift; }; ++ ++ return map { $processor->($_); } @_; ++} ++ ++# collect_from_file($filename, $line_concat_cond_re, $line_concat) ++# $filename is a file name to read from ++# $line_concat_cond_re is a regexp detecting a line continuation ending ++# $line_concat is a CODEref that takes care of concatenating two lines ++sub collect_from_file { ++ my $filename = shift; ++ my $line_concat_cond_re = shift; ++ my $line_concat = shift; ++ ++ open my $fh, $filename || die "unable to read $filename: $!\n"; ++ return sub { ++ my $saved_line = ""; ++ $_ = ""; ++ while (<$fh>) { ++ s|\R$||; ++ if (defined $line_concat) { ++ $_ = $line_concat->($saved_line, $_); ++ $saved_line = ""; ++ } ++ if (defined $line_concat_cond_re && /$line_concat_cond_re/) { ++ $saved_line = $_; ++ next; ++ } ++ return $_; ++ } ++ die "$filename ending with continuation line\n" if $_; ++ close $fh; ++ return undef; ++ } ++} ++ ++# collect_from_array($array, $line_concat_cond_re, $line_concat) ++# $array is an ARRAYref of lines ++# $line_concat_cond_re is a regexp detecting a line continuation ending ++# $line_concat is a CODEref that takes care of concatenating two lines ++sub collect_from_array { ++ my $array = shift; ++ my $line_concat_cond_re = shift; ++ my $line_concat = shift; ++ my @array = (@$array); ++ ++ return sub { ++ my $saved_line = ""; ++ $_ = ""; ++ while (defined($_ = shift @array)) { ++ s|\R$||; ++ if (defined $line_concat) { ++ $_ = $line_concat->($saved_line, $_); ++ $saved_line = ""; ++ } ++ if (defined $line_concat_cond_re && /$line_concat_cond_re/) { ++ $saved_line = $_; ++ next; ++ } ++ return $_; ++ } ++ die "input text ending with continuation line\n" if $_; ++ return undef; ++ } ++} ++ ++# collect_information($lineiterator, $line_continue, $regexp => $CODEref, ...) ++# $lineiterator is a CODEref that delivers one line at a time. ++# All following arguments are regex/CODEref pairs, where the regexp detects a ++# line and the CODEref does something with the result of the regexp. ++sub collect_information { ++ my $lineiterator = shift; ++ my %collectors = @_; ++ ++ while(defined($_ = $lineiterator->())) { ++ s|\R$||; ++ my $found = 0; ++ if ($collectors{"BEFORE"}) { ++ $collectors{"BEFORE"}->($_); ++ } ++ foreach my $re (keys %collectors) { ++ if ($re !~ /^OTHERWISE|BEFORE|AFTER$/ && /$re/) { ++ $collectors{$re}->($lineiterator); ++ $found = 1; ++ }; ++ } ++ if ($collectors{"OTHERWISE"}) { ++ $collectors{"OTHERWISE"}->($lineiterator, $_) ++ unless $found || !defined $collectors{"OTHERWISE"}; ++ } ++ if ($collectors{"AFTER"}) { ++ $collectors{"AFTER"}->($_); ++ } ++ } ++} ++ ++# tokenize($line) ++# $line is a line of text to split up into tokens ++# returns a list of tokens ++# ++# Tokens are divided by spaces. If the tokens include spaces, they ++# have to be quoted with single or double quotes. Double quotes ++# inside a double quoted token must be escaped. Escaping is done ++# with backslash. ++# Basically, the same quoting rules apply for " and ' as in any ++# Unix shell. ++sub tokenize { ++ my $line = my $debug_line = shift; ++ my @result = (); ++ ++ while ($line =~ s|^\s+||, $line ne "") { ++ my $token = ""; ++ while ($line ne "" && $line !~ m|^\s|) { ++ if ($line =~ m/^"((?:[^"\\]+|\\.)*)"/) { ++ $token .= $1; ++ $line = $'; ++ } elsif ($line =~ m/^'([^']*)'/) { ++ $token .= $1; ++ $line = $'; ++ } elsif ($line =~ m/^(\S+)/) { ++ $token .= $1; ++ $line = $'; ++ } ++ } ++ push @result, $token; ++ } ++ ++ if ($ENV{CONFIGURE_DEBUG_TOKENIZE}) { ++ print STDERR "DEBUG[tokenize]: Parsed '$debug_line' into:\n"; ++ print STDERR "DEBUG[tokenize]: ('", join("', '", @result), "')\n"; ++ } ++ return @result; ++} +diff --git a/CryptoPkg/Library/OpensslLib/openssl/FAQ b/CryptoPkg/Library/OpensslLib/openssl/FAQ +new file mode 100644 +index 0000000..22c5cf7 +--- /dev/null ++++ b/CryptoPkg/Library/OpensslLib/openssl/FAQ +@@ -0,0 +1,2 @@ ++The FAQ is now maintained on the web: ++ https://www.openssl.org/docs/faq.html +diff --git a/CryptoPkg/Library/OpensslLib/openssl/INSTALL b/CryptoPkg/Library/OpensslLib/openssl/INSTALL +new file mode 100644 +index 0000000..61b13c4 +--- /dev/null ++++ b/CryptoPkg/Library/OpensslLib/openssl/INSTALL +@@ -0,0 +1,951 @@ ++ ++ OPENSSL INSTALLATION ++ -------------------- ++ ++ This document describes installation on all supported operating ++ systems (the Linux/Unix family, OpenVMS and Windows) ++ ++ To install OpenSSL, you will need: ++ ++ * A make implementation ++ * Perl 5 with core modules (please read NOTES.PERL) ++ * The perl module Text::Template (please read NOTES.PERL) ++ * an ANSI C compiler ++ * a development environment in the form of development libraries and C ++ header files ++ * a supported operating system ++ ++ For additional platform specific requirements, solutions to specific ++ issues and other details, please read one of these: ++ ++ * NOTES.VMS (OpenVMS) ++ * NOTES.WIN (any supported Windows) ++ * NOTES.DJGPP (DOS platform with DJGPP) ++ ++ Notational conventions in this document ++ --------------------------------------- ++ ++ Throughout this document, we use the following conventions in command ++ examples: ++ ++ $ command Any line starting with a dollar sign ++ ($) is a command line. ++ ++ { word1 | word2 | word3 } This denotes a mandatory choice, to be ++ replaced with one of the given words. ++ A simple example would be this: ++ ++ $ echo { FOO | BAR | COOKIE } ++ ++ which is to be understood as one of ++ these: ++ ++ $ echo FOO ++ - or - ++ $ echo BAR ++ - or - ++ $ echo COOKIE ++ ++ [ word1 | word2 | word3 ] Similar to { word1 | word2 | word3 } ++ except it's optional to give any of ++ those. In addition to the examples ++ above, this would also be valid: ++ ++ $ echo ++ ++ {{ target }} This denotes a mandatory word or ++ sequence of words of some sort. A ++ simple example would be this: ++ ++ $ type {{ filename }} ++ ++ which is to be understood to use the ++ command 'type' on some file name ++ determined by the user. ++ ++ [[ options ]] Similar to {{ target }}, but is ++ optional. ++ ++ Note that the notation assumes spaces around {, }, [, ], {{, }} and ++ [[, ]]. This is to differentiate from OpenVMS directory ++ specifications, which also use [ and ], but without spaces. ++ ++ Quick Start ++ ----------- ++ ++ If you want to just get on with it, do: ++ ++ on Unix: ++ ++ $ ./config ++ $ make ++ $ make test ++ $ make install ++ ++ on OpenVMS: ++ ++ $ @config ++ $ mms ++ $ mms test ++ $ mms install ++ ++ on Windows (only pick one of the targets for configuration): ++ ++ $ perl Configure { VC-WIN32 | VC-WIN64A | VC-WIN64I | VC-CE } ++ $ nmake ++ $ nmake test ++ $ nmake install ++ ++ If any of these steps fails, see section Installation in Detail below. ++ ++ This will build and install OpenSSL in the default location, which is: ++ ++ Unix: normal installation directories under /usr/local ++ OpenVMS: SYS$COMMON:[OPENSSL-'version'...], where 'version' is the ++ OpenSSL version number with underscores instead of periods. ++ Windows: C:\Program Files\OpenSSL or C:\Program Files (x86)\OpenSSL ++ ++ If you want to install it anywhere else, run config like this: ++ ++ On Unix: ++ ++ $ ./config --prefix=/opt/openssl --openssldir=/usr/local/ssl ++ ++ On OpenVMS: ++ ++ $ @config --prefix=PROGRAM:[INSTALLS] --openssldir=SYS$MANAGER:[OPENSSL] ++ ++ ++ Configuration Options ++ --------------------- ++ ++ There are several options to ./config (or ./Configure) to customize ++ the build (note that for Windows, the defaults for --prefix and ++ --openssldir depend in what configuration is used and what Windows ++ implementation OpenSSL is built on. More notes on this in NOTES.WIN): ++ ++ --api=x.y.z ++ Don't build with support for deprecated APIs below the ++ specified version number. For example "--api=1.1.0" will ++ remove support for all APIS that were deprecated in OpenSSL ++ version 1.1.0 or below. ++ ++ --cross-compile-prefix=PREFIX ++ The PREFIX to include in front of commands for your ++ toolchain. It's likely to have to end with dash, e.g. ++ a-b-c- would invoke GNU compiler as a-b-c-gcc, etc. ++ Unfortunately cross-compiling is too case-specific to ++ put together one-size-fits-all instructions. You might ++ have to pass more flags or set up environment variables ++ to actually make it work. Android and iOS cases are ++ discussed in corresponding Configurations/10-main.cf ++ sections. But there are cases when this option alone is ++ sufficient. For example to build the mingw64 target on ++ Linux "--cross-compile-prefix=x86_64-w64-mingw32-" ++ works. Naturally provided that mingw packages are ++ installed. Today Debian and Ubuntu users have option to ++ install a number of prepackaged cross-compilers along ++ with corresponding run-time and development packages for ++ "alien" hardware. To give another example ++ "--cross-compile-prefix=mipsel-linux-gnu-" suffices ++ in such case. Needless to mention that you have to ++ invoke ./Configure, not ./config, and pass your target ++ name explicitly. ++ ++ --debug ++ Build OpenSSL with debugging symbols. ++ ++ --libdir=DIR ++ The name of the directory under the top of the installation ++ directory tree (see the --prefix option) where libraries will ++ be installed. By default this is "lib". Note that on Windows ++ only ".lib" files will be stored in this location. dll files ++ will always be installed to the "bin" directory. ++ ++ --openssldir=DIR ++ Directory for OpenSSL configuration files, and also the ++ default certificate and key store. Defaults are: ++ ++ Unix: /usr/local/ssl ++ Windows: C:\Program Files\Common Files\SSL ++ or C:\Program Files (x86)\Common Files\SSL ++ OpenVMS: SYS$COMMON:[OPENSSL-COMMON] ++ ++ --prefix=DIR ++ The top of the installation directory tree. Defaults are: ++ ++ Unix: /usr/local ++ Windows: C:\Program Files\OpenSSL ++ or C:\Program Files (x86)\OpenSSL ++ OpenVMS: SYS$COMMON:[OPENSSL-'version'] ++ ++ --release ++ Build OpenSSL without debugging symbols. This is the default. ++ ++ --strict-warnings ++ This is a developer flag that switches on various compiler ++ options recommended for OpenSSL development. It only works ++ when using gcc or clang as the compiler. If you are ++ developing a patch for OpenSSL then it is recommended that ++ you use this option where possible. ++ ++ --with-zlib-include=DIR ++ The directory for the location of the zlib include file. This ++ option is only necessary if enable-zlib (see below) is used ++ and the include file is not already on the system include ++ path. ++ ++ --with-zlib-lib=LIB ++ On Unix: this is the directory containing the zlib library. ++ If not provided the system library path will be used. ++ On Windows: this is the filename of the zlib library (with or ++ without a path). This flag must be provided if the ++ zlib-dynamic option is not also used. If zlib-dynamic is used ++ then this flag is optional and a default value ("ZLIB1") is ++ used if not provided. ++ On VMS: this is the filename of the zlib library (with or ++ without a path). This flag is optional and if not provided ++ then "GNV$LIBZSHR", "GNV$LIBZSHR32" or "GNV$LIBZSHR64" is ++ used by default depending on the pointer size chosen. ++ ++ no-afalgeng ++ Don't build the AFALG engine. This option will be forced if ++ on a platform that does not support AFALG. ++ ++ enable-asan ++ Build with the Address sanitiser. This is a developer option ++ only. It may not work on all platforms and should never be ++ used in production environments. It will only work when used ++ with gcc or clang and should be used in conjunction with the ++ no-shared option. ++ ++ no-asm ++ Do not use assembler code. On some platforms a small amount ++ of assembler code may still be used. ++ ++ no-async ++ Do not build support for async operations. ++ ++ no-autoalginit ++ Don't automatically load all supported ciphers and digests. ++ Typically OpenSSL will make available all of its supported ++ ciphers and digests. For a statically linked application this ++ may be undesirable if small executable size is an objective. ++ This only affects libcrypto. Ciphers and digests will have to ++ be loaded manually using EVP_add_cipher() and ++ EVP_add_digest() if this option is used. This option will ++ force a non-shared build. ++ ++ no-autoerrinit ++ Don't automatically load all libcrypto/libssl error strings. ++ Typically OpenSSL will automatically load human readable ++ error strings. For a statically linked application this may ++ be undesirable if small executable size is an objective. ++ ++ ++ no-capieng ++ Don't build the CAPI engine. This option will be forced if ++ on a platform that does not support CAPI. ++ ++ no-cms ++ Don't build support for CMS features ++ ++ no-comp ++ Don't build support for SSL/TLS compression. If this option ++ is left enabled (the default), then compression will only ++ work if the zlib or zlib-dynamic options are also chosen. ++ ++ enable-crypto-mdebug ++ Build support for debugging memory allocated via ++ OPENSSL_malloc() or OPENSSL_zalloc(). ++ ++ enable-crypto-mdebug-backtrace ++ As for crypto-mdebug, but additionally provide backtrace ++ information for allocated memory. ++ TO BE USED WITH CARE: this uses GNU C functionality, and ++ is therefore not usable for non-GNU config targets. If ++ your build complains about the use of '-rdynamic' or the ++ lack of header file execinfo.h, this option is not for you. ++ ALSO NOTE that even though execinfo.h is available on your ++ system (through Gnulib), the functions might just be stubs ++ that do nothing. ++ ++ no-ct ++ Don't build support for Certificate Transparency. ++ ++ no-deprecated ++ Don't build with support for any deprecated APIs. This is the ++ same as using "--api" and supplying the latest version ++ number. ++ ++ no-dgram ++ Don't build support for datagram based BIOs. Selecting this ++ option will also force the disabling of DTLS. ++ ++ no-dso ++ Don't build support for loading Dynamic Shared Objects. ++ ++ no-dynamic-engine ++ Don't build the dynamically loaded engines. This only has an ++ effect in a "shared" build ++ ++ no-ec ++ Don't build support for Elliptic Curves. ++ ++ no-ec2m ++ Don't build support for binary Elliptic Curves ++ ++ enable-ec_nistp_64_gcc_128 ++ Enable support for optimised implementations of some commonly ++ used NIST elliptic curves. This is only supported on some ++ platforms. ++ ++ enable-egd ++ Build support for gathering entropy from EGD (Entropy ++ Gathering Daemon). ++ ++ no-engine ++ Don't build support for loading engines. ++ ++ no-err ++ Don't compile in any error strings. ++ ++ no-filenames ++ Don't compile in filename and line number information (e.g. ++ for errors and memory allocation). ++ ++ enable-fuzz-libfuzzer, enable-fuzz-afl ++ Build with support for fuzzing using either libfuzzer or AFL. ++ These are developer options only. They may not work on all ++ platforms and should never be used in production environments. ++ See the file fuzz/README.md for further details. ++ ++ no-gost ++ Don't build support for GOST based ciphersuites. Note that ++ if this feature is enabled then GOST ciphersuites are only ++ available if the GOST algorithms are also available through ++ loading an externally supplied engine. ++ ++ enable-heartbeats ++ Build support for DTLS heartbeats. ++ ++ no-hw-padlock ++ Don't build the padlock engine. ++ ++ no-makedepend ++ Don't generate dependencies. ++ ++ no-multiblock ++ Don't build support for writing multiple records in one ++ go in libssl (Note: this is a different capability to the ++ pipelining functionality). ++ ++ no-nextprotoneg ++ Don't build support for the NPN TLS extension. ++ ++ no-ocsp ++ Don't build support for OCSP. ++ ++ no-pic ++ Don't build with support for Position Independent Code. ++ ++ no-posix-io ++ Don't use POSIX IO capabilities. ++ ++ no-psk ++ Don't build support for Pre-Shared Key based ciphersuites. ++ ++ no-rdrand ++ Don't use hardware RDRAND capabilities. ++ ++ no-rfc3779 ++ Don't build support for RFC3779 ("X.509 Extensions for IP ++ Addresses and AS Identifiers") ++ ++ sctp ++ Build support for SCTP ++ ++ no-shared ++ Do not create shared libraries, only static ones. See "Note ++ on shared libraries" below. ++ ++ no-sock ++ Don't build support for socket BIOs ++ ++ no-srp ++ Don't build support for SRP or SRP based ciphersuites. ++ ++ no-srtp ++ Don't build SRTP support ++ ++ no-sse2 ++ Exclude SSE2 code paths from 32-bit x86 assembly modules. ++ Normally SSE2 extension is detected at run-time, but the ++ decision whether or not the machine code will be executed ++ is taken solely on CPU capability vector. This means that ++ if you happen to run OS kernel which does not support SSE2 ++ extension on Intel P4 processor, then your application ++ might be exposed to "illegal instruction" exception. ++ There might be a way to enable support in kernel, e.g. ++ FreeBSD kernel can be compiled with CPU_ENABLE_SSE, and ++ there is a way to disengage SSE2 code paths upon application ++ start-up, but if you aim for wider "audience" running ++ such kernel, consider no-sse2. Both the 386 and ++ no-asm options imply no-sse2. ++ ++ enable-ssl-trace ++ Build with the SSL Trace capabilities (adds the "-trace" ++ option to s_client and s_server). ++ ++ no-static-engine ++ Don't build the statically linked engines. This only ++ has an impact when not built "shared". ++ ++ no-stdio ++ Don't use any C "stdio" features. Only libcrypto and libssl ++ can be built in this way. Using this option will suppress ++ building the command line applications. Additionally since ++ the OpenSSL tests also use the command line applications the ++ tests will also be skipped. ++ ++ no-threads ++ Don't try to build with support for multi-threaded ++ applications. ++ ++ threads ++ Build with support for multi-threaded applications. Most ++ platforms will enable this by default. However if on a ++ platform where this is not the case then this will usually ++ require additional system-dependent options! See "Note on ++ multi-threading" below. ++ ++ no-ts ++ Don't build Time Stamping Authority support. ++ ++ enable-ubsan ++ Build with the Undefined Behaviour sanitiser. This is a ++ developer option only. It may not work on all platforms and ++ should never be used in production environments. It will only ++ work when used with gcc or clang and should be used in ++ conjunction with the "-DPEDANTIC" option (or the ++ --strict-warnings option). ++ ++ no-ui ++ Don't build with the "UI" capability (i.e. the set of ++ features enabling text based prompts). ++ ++ enable-unit-test ++ Enable additional unit test APIs. This should not typically ++ be used in production deployments. ++ ++ enable-weak-ssl-ciphers ++ Build support for SSL/TLS ciphers that are considered "weak" ++ (e.g. RC4 based ciphersuites). ++ ++ zlib ++ Build with support for zlib compression/decompression. ++ ++ zlib-dynamic ++ Like "zlib", but has OpenSSL load the zlib library ++ dynamically when needed. This is only supported on systems ++ where loading of shared libraries is supported. ++ ++ 386 ++ In 32-bit x86 builds, when generating assembly modules, ++ use the 80386 instruction set only (the default x86 code ++ is more efficient, but requires at least a 486). Note: ++ This doesn't affect code generated by compiler, you're ++ likely to complement configuration command line with ++ suitable compiler-specific option. ++ ++ no- ++ Don't build support for negotiating the specified SSL/TLS ++ protocol (one of ssl, ssl3, tls, tls1, tls1_1, tls1_2, dtls, ++ dtls1 or dtls1_2). If "no-tls" is selected then all of tls1, ++ tls1_1 and tls1_2 are disabled. Similarly "no-dtls" will ++ disable dtls1 and dtls1_2. The "no-ssl" option is synonymous ++ with "no-ssl3". Note this only affects version negotiation. ++ OpenSSL will still provide the methods for applications to ++ explicitly select the individual protocol versions. ++ ++ no--method ++ As for no- but in addition do not build the methods for ++ applications to explicitly select individual protocol ++ versions. ++ ++ enable- ++ Build with support for the specified algorithm, where ++ is one of: md2 or rc5. ++ ++ no- ++ Build without support for the specified algorithm, where ++ is one of: bf, blake2, camellia, cast, chacha, cmac, ++ des, dh, dsa, ecdh, ecdsa, idea, md4, mdc2, ocb, poly1305, ++ rc2, rc4, rmd160, scrypt, seed or whirlpool. The "ripemd" ++ algorithm is deprecated and if used is synonymous with rmd160. ++ ++ -Dxxx, -lxxx, -Lxxx, -fxxx, -mXXX, -Kxxx ++ These system specific options will be passed through to the ++ compiler to allow you to define preprocessor symbols, specify ++ additional libraries, library directories or other compiler ++ options. It might be worth noting that some compilers ++ generate code specifically for processor the compiler ++ currently executes on. This is not necessarily what you might ++ have in mind, since it might be unsuitable for execution on ++ other, typically older, processor. Consult your compiler ++ documentation. ++ ++ ++ Installation in Detail ++ ---------------------- ++ ++ 1a. Configure OpenSSL for your operation system automatically: ++ ++ NOTE: This is not available on Windows. ++ ++ $ ./config [[ options ]] # Unix ++ ++ or ++ ++ $ @config [[ options ]] ! OpenVMS ++ ++ For the remainder of this text, the Unix form will be used in all ++ examples, please use the appropriate form for your platform. ++ ++ This guesses at your operating system (and compiler, if necessary) and ++ configures OpenSSL based on this guess. Run ./config -t to see ++ if it guessed correctly. If you want to use a different compiler, you ++ are cross-compiling for another platform, or the ./config guess was ++ wrong for other reasons, go to step 1b. Otherwise go to step 2. ++ ++ On some systems, you can include debugging information as follows: ++ ++ $ ./config -d [[ options ]] ++ ++ 1b. Configure OpenSSL for your operating system manually ++ ++ OpenSSL knows about a range of different operating system, hardware and ++ compiler combinations. To see the ones it knows about, run ++ ++ $ ./Configure # Unix ++ ++ or ++ ++ $ perl Configure # All other platforms ++ ++ For the remainder of this text, the Unix form will be used in all ++ examples, please use the appropriate form for your platform. ++ ++ Pick a suitable name from the list that matches your system. For most ++ operating systems there is a choice between using "cc" or "gcc". When ++ you have identified your system (and if necessary compiler) use this name ++ as the argument to Configure. For example, a "linux-elf" user would ++ run: ++ ++ $ ./Configure linux-elf [[ options ]] ++ ++ If your system isn't listed, you will have to create a configuration ++ file named Configurations/{{ something }}.conf and add the correct ++ configuration for your system. See the available configs as examples ++ and read Configurations/README and Configurations/README.design for ++ more information. ++ ++ The generic configurations "cc" or "gcc" should usually work on 32 bit ++ Unix-like systems. ++ ++ Configure creates a build file ("Makefile" on Unix, "makefile" on Windows ++ and "descrip.mms" on OpenVMS) from a suitable template in Configurations, ++ and defines various macros in include/openssl/opensslconf.h (generated from ++ include/openssl/opensslconf.h.in). ++ ++ 1c. Configure OpenSSL for building outside of the source tree. ++ ++ OpenSSL can be configured to build in a build directory separate from ++ the directory with the source code. It's done by placing yourself in ++ some other directory and invoking the configuration commands from ++ there. ++ ++ Unix example: ++ ++ $ mkdir /var/tmp/openssl-build ++ $ cd /var/tmp/openssl-build ++ $ /PATH/TO/OPENSSL/SOURCE/config [[ options ]] ++ ++ or ++ ++ $ /PATH/TO/OPENSSL/SOURCE/Configure {{ target }} [[ options ]] ++ ++ OpenVMS example: ++ ++ $ set default sys$login: ++ $ create/dir [.tmp.openssl-build] ++ $ set default [.tmp.openssl-build] ++ $ @[PATH.TO.OPENSSL.SOURCE]config [[ options ]] ++ ++ or ++ ++ $ @[PATH.TO.OPENSSL.SOURCE]Configure {{ target }} [[ options ]] ++ ++ Windows example: ++ ++ $ C: ++ $ mkdir \temp-openssl ++ $ cd \temp-openssl ++ $ perl d:\PATH\TO\OPENSSL\SOURCE\Configure {{ target }} [[ options ]] ++ ++ Paths can be relative just as well as absolute. Configure will ++ do its best to translate them to relative paths whenever possible. ++ ++ 2. Build OpenSSL by running: ++ ++ $ make # Unix ++ $ mms ! (or mmk) OpenVMS ++ $ nmake # Windows ++ ++ This will build the OpenSSL libraries (libcrypto.a and libssl.a on ++ Unix, corresponding on other platforms) and the OpenSSL binary ++ ("openssl"). The libraries will be built in the top-level directory, ++ and the binary will be in the "apps" subdirectory. ++ ++ If the build fails, look at the output. There may be reasons ++ for the failure that aren't problems in OpenSSL itself (like ++ missing standard headers). If you are having problems you can ++ get help by sending an email to the openssl-users email list (see ++ https://www.openssl.org/community/mailinglists.html for details). If ++ it is a bug with OpenSSL itself, please open an issue on GitHub, at ++ https://github.com/openssl/openssl/issues. Please review the existing ++ ones first; maybe the bug was already reported or has already been ++ fixed. ++ ++ (If you encounter assembler error messages, try the "no-asm" ++ configuration option as an immediate fix.) ++ ++ Compiling parts of OpenSSL with gcc and others with the system ++ compiler will result in unresolved symbols on some systems. ++ ++ 3. After a successful build, the libraries should be tested. Run: ++ ++ $ make test # Unix ++ $ mms test ! OpenVMS ++ $ nmake test # Windows ++ ++ NOTE: you MUST run the tests from an unprivileged account (or ++ disable your privileges temporarily if your platform allows it). ++ ++ If some tests fail, look at the output. There may be reasons for ++ the failure that isn't a problem in OpenSSL itself (like a ++ malfunction with Perl). You may want increased verbosity, that ++ can be accomplished like this: ++ ++ $ make VERBOSE=1 test # Unix ++ ++ $ mms /macro=(VERBOSE=1) test ! OpenVMS ++ ++ $ nmake VERBOSE=1 test # Windows ++ ++ If you want to run just one or a few specific tests, you can use ++ the make variable TESTS to specify them, like this: ++ ++ $ make TESTS='test_rsa test_dsa' test # Unix ++ $ mms/macro="TESTS=test_rsa test_dsa" test ! OpenVMS ++ $ nmake TESTS='test_rsa test_dsa' test # Windows ++ ++ And of course, you can combine (Unix example shown): ++ ++ $ make VERBOSE=1 TESTS='test_rsa test_dsa' test ++ ++ You can find the list of available tests like this: ++ ++ $ make list-tests # Unix ++ $ mms list-tests ! OpenVMS ++ $ nmake list-tests # Windows ++ ++ Have a look at the manual for the perl module Test::Harness to ++ see what other HARNESS_* variables there are. ++ ++ If you find a problem with OpenSSL itself, try removing any ++ compiler optimization flags from the CFLAGS line in Makefile and ++ run "make clean; make" or corresponding. ++ ++ Please send bug reports to . ++ ++ 4. If everything tests ok, install OpenSSL with ++ ++ $ make install # Unix ++ $ mms install ! OpenVMS ++ $ nmake install # Windows ++ ++ This will install all the software components in this directory ++ tree under PREFIX (the directory given with --prefix or its ++ default): ++ ++ Unix: ++ ++ bin/ Contains the openssl binary and a few other ++ utility scripts. ++ include/openssl ++ Contains the header files needed if you want ++ to build your own programs that use libcrypto ++ or libssl. ++ lib Contains the OpenSSL library files. ++ lib/engines Contains the OpenSSL dynamically loadable engines. ++ ++ share/man/man1 Contains the OpenSSL command line man-pages. ++ share/man/man3 Contains the OpenSSL library calls man-pages. ++ share/man/man5 Contains the OpenSSL configuration format man-pages. ++ share/man/man7 Contains the OpenSSL other misc man-pages. ++ ++ share/doc/openssl/html/man1 ++ share/doc/openssl/html/man3 ++ share/doc/openssl/html/man5 ++ share/doc/openssl/html/man7 ++ Contains the HTML rendition of the man-pages. ++ ++ OpenVMS ('arch' is replaced with the architecture name, "Alpha" ++ or "ia64", 'sover' is replaced with the shared library version ++ (0101 for 1.1), and 'pz' is replaced with the pointer size ++ OpenSSL was built with): ++ ++ [.EXE.'arch'] Contains the openssl binary. ++ [.EXE] Contains a few utility scripts. ++ [.include.openssl] ++ Contains the header files needed if you want ++ to build your own programs that use libcrypto ++ or libssl. ++ [.LIB.'arch'] Contains the OpenSSL library files. ++ [.ENGINES'sover''pz'.'arch'] ++ Contains the OpenSSL dynamically loadable engines. ++ [.SYS$STARTUP] Contains startup, login and shutdown scripts. ++ These define appropriate logical names and ++ command symbols. ++ [.SYSTEST] Contains the installation verification procedure. ++ [.HTML] Contains the HTML rendition of the manual pages. ++ ++ ++ Additionally, install will add the following directories under ++ OPENSSLDIR (the directory given with --openssldir or its default) ++ for you convenience: ++ ++ certs Initially empty, this is the default location ++ for certificate files. ++ private Initially empty, this is the default location ++ for private key files. ++ misc Various scripts. ++ ++ Package builders who want to configure the library for standard ++ locations, but have the package installed somewhere else so that ++ it can easily be packaged, can use ++ ++ $ make DESTDIR=/tmp/package-root install # Unix ++ $ mms/macro="DESTDIR=TMP:[PACKAGE-ROOT]" install ! OpenVMS ++ ++ The specified destination directory will be prepended to all ++ installation target paths. ++ ++ Compatibility issues with previous OpenSSL versions: ++ ++ * COMPILING existing applications ++ ++ OpenSSL 1.1.0 hides a number of structures that were previously ++ open. This includes all internal libssl structures and a number ++ of EVP types. Accessor functions have been added to allow ++ controlled access to the structures' data. ++ ++ This means that some software needs to be rewritten to adapt to ++ the new ways of doing things. This often amounts to allocating ++ an instance of a structure explicitly where you could previously ++ allocate them on the stack as automatic variables, and using the ++ provided accessor functions where you would previously access a ++ structure's field directly. ++ ++ Some APIs have changed as well. However, older APIs have been ++ preserved when possible. ++ ++ Environment Variables ++ --------------------- ++ ++ A number of environment variables can be used to provide additional control ++ over the build process. Typically these should be defined prior to running ++ config or Configure. Not all environment variables are relevant to all ++ platforms. ++ ++ AR ++ The name of the ar executable to use. ++ ++ BUILDFILE ++ Use a different build file name than the platform default ++ ("Makefile" on Unixly platforms, "makefile" on native Windows, ++ "descrip.mms" on OpenVMS). This requires that there is a ++ corresponding build file template. See Configurations/README ++ for further information. ++ ++ CC ++ The compiler to use. Configure will attempt to pick a default ++ compiler for your platform but this choice can be overridden ++ using this variable. Set it to the compiler executable you wish ++ to use, e.g. "gcc" or "clang". ++ ++ CROSS_COMPILE ++ This environment variable has the same meaning as for the ++ "--cross-compile-prefix" Configure flag described above. If both ++ are set then the Configure flag takes precedence. ++ ++ NM ++ The name of the nm executable to use. ++ ++ OPENSSL_LOCAL_CONFIG_DIR ++ OpenSSL comes with a database of information about how it ++ should be built on different platforms as well as build file ++ templates for those platforms. The database is comprised of ++ ".conf" files in the Configurations directory. The build ++ file templates reside there as well as ".tmpl" files. See the ++ file Configurations/README for further information about the ++ format of ".conf" files as well as information on the ".tmpl" ++ files. ++ In addition to the standard ".conf" and ".tmpl" files, it is ++ possible to create your own ".conf" and ".tmpl" files and store ++ them locally, outside the OpenSSL source tree. This environment ++ variable can be set to the directory where these files are held ++ and will have Configure to consider them in addition to the ++ standard ones. ++ ++ PERL ++ The name of the Perl executable to use when building OpenSSL. ++ ++ HASHBANGPERL ++ The command string for the Perl executable to insert in the ++ #! line of perl scripts that will be publically installed. ++ Default: /usr/bin/env perl ++ Note: the value of this variable is added to the same scripts ++ on all platforms, but it's only relevant on Unix-like platforms. ++ ++ RC ++ The name of the rc executable to use. The default will be as ++ defined for the target platform in the ".conf" file. If not ++ defined then "windres" will be used. The WINDRES environment ++ variable is synonymous to this. If both are defined then RC ++ takes precedence. ++ ++ RANLIB ++ The name of the ranlib executable to use. ++ ++ WINDRES ++ See RC. ++ ++ Makefile targets ++ ---------------- ++ ++ The Configure script generates a Makefile in a format relevant to the specific ++ platform. The Makefiles provide a number of targets that can be used. Not all ++ targets may be available on all platforms. Only the most common targets are ++ described here. Examine the Makefiles themselves for the full list. ++ ++ all ++ The default target to build all the software components. ++ ++ clean ++ Remove all build artefacts and return the directory to a "clean" ++ state. ++ ++ depend ++ Rebuild the dependencies in the Makefiles. This is a legacy ++ option that no longer needs to be used in OpenSSL 1.1.0. ++ ++ install ++ Install all OpenSSL components. ++ ++ install_sw ++ Only install the OpenSSL software components. ++ ++ install_docs ++ Only install the OpenSSL documentation components. ++ ++ install_man_docs ++ Only install the OpenSSL man pages (Unix only). ++ ++ install_html_docs ++ Only install the OpenSSL html documentation. ++ ++ list-tests ++ Prints a list of all the self test names. ++ ++ test ++ Build and run the OpenSSL self tests. ++ ++ uninstall ++ Uninstall all OpenSSL components. ++ ++ update ++ This is a developer option. If you are developing a patch for ++ OpenSSL you may need to use this if you want to update ++ automatically generated files; add new error codes or add new ++ (or change the visibility of) public API functions. (Unix only). ++ ++ Note on multi-threading ++ ----------------------- ++ ++ For some systems, the OpenSSL Configure script knows what compiler options ++ are needed to generate a library that is suitable for multi-threaded ++ applications. On these systems, support for multi-threading is enabled ++ by default; use the "no-threads" option to disable (this should never be ++ necessary). ++ ++ On other systems, to enable support for multi-threading, you will have ++ to specify at least two options: "threads", and a system-dependent option. ++ (The latter is "-D_REENTRANT" on various systems.) The default in this ++ case, obviously, is not to include support for multi-threading (but ++ you can still use "no-threads" to suppress an annoying warning message ++ from the Configure script.) ++ ++ OpenSSL provides built-in support for two threading models: pthreads (found on ++ most UNIX/Linux systems), and Windows threads. No other threading models are ++ supported. If your platform does not provide pthreads or Windows threads then ++ you should Configure with the "no-threads" option. ++ ++ Notes on shared libraries ++ ------------------------- ++ ++ For most systems the OpenSSL Configure script knows what is needed to ++ build shared libraries for libcrypto and libssl. On these systems ++ the shared libraries will be created by default. This can be suppressed and ++ only static libraries created by using the "no-shared" option. On systems ++ where OpenSSL does not know how to build shared libraries the "no-shared" ++ option will be forced and only static libraries will be created. ++ ++ Shared libraries are named a little differently on different platforms. ++ One way or another, they all have the major OpenSSL version number as ++ part of the file name, i.e. for OpenSSL 1.1.x, 1.1 is somehow part of ++ the name. ++ ++ On most POSIXly platforms, shared libraries are named libcrypto.so.1.1 ++ and libssl.so.1.1. ++ ++ on Cygwin, shared libraries are named cygcrypto-1.1.dll and cygssl-1.1.dll ++ with import libraries libcrypto.dll.a and libssl.dll.a. ++ ++ On Windows build with MSVC or using MingW, shared libraries are named ++ libcrypto-1_1.dll and libssl-1_1.dll for 32-bit Windows, libcrypto-1_1-x64.dll ++ and libssl-1_1-x64.dll for 64-bit x86_64 Windows, and libcrypto-1_1-ia64.dll ++ and libssl-1_1-ia64.dll for IA64 Windows. With MSVC, the import libraries ++ are named libcrypto.lib and libssl.lib, while with MingW, they are named ++ libcrypto.dll.a and libssl.dll.a. ++ ++ On VMS, shareable images (VMS speak for shared libraries) are named ++ ossl$libcrypto0101_shr.exe and ossl$libssl0101_shr.exe. However, when ++ OpenSSL is specifically built for 32-bit pointers, the shareable images ++ are named ossl$libcrypto0101_shr32.exe and ossl$libssl0101_shr32.exe ++ instead, and when built for 64-bit pointers, they are named ++ ossl$libcrypto0101_shr64.exe and ossl$libssl0101_shr64.exe. ++ ++ Note on random number generation ++ -------------------------------- ++ ++ Availability of cryptographically secure random numbers is required for ++ secret key generation. OpenSSL provides several options to seed the ++ internal PRNG. If not properly seeded, the internal PRNG will refuse ++ to deliver random bytes and a "PRNG not seeded error" will occur. ++ On systems without /dev/urandom (or similar) device, it may be necessary ++ to install additional support software to obtain a random seed. ++ Please check out the manual pages for RAND_add(), RAND_bytes(), RAND_egd(), ++ and the FAQ for more information. ++ +diff --git a/CryptoPkg/Library/OpensslLib/openssl/LICENSE b/CryptoPkg/Library/OpensslLib/openssl/LICENSE +new file mode 100644 +index 0000000..c6cc098 +--- /dev/null ++++ b/CryptoPkg/Library/OpensslLib/openssl/LICENSE +@@ -0,0 +1,125 @@ ++ ++ LICENSE ISSUES ++ ============== ++ ++ The OpenSSL toolkit stays under a dual license, i.e. both the conditions of ++ the OpenSSL License and the original SSLeay license apply to the toolkit. ++ See below for the actual license texts. ++ ++ OpenSSL License ++ --------------- ++ ++/* ==================================================================== ++ * Copyright (c) 1998-2016 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 ++ * openssl-core@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). ++ * ++ */ ++ ++ Original SSLeay License ++ ----------------------- ++ ++/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) ++ * All rights reserved. ++ * ++ * This package is an SSL implementation written ++ * by Eric Young (eay@cryptsoft.com). ++ * The implementation was written so as to conform with Netscapes SSL. ++ * ++ * This library is free for commercial and non-commercial use as long as ++ * the following conditions are aheared to. The following conditions ++ * apply to all code found in this distribution, be it the RC4, RSA, ++ * lhash, DES, etc., code; not just the SSL code. The SSL documentation ++ * included with this distribution is covered by the same copyright terms ++ * except that the holder is Tim Hudson (tjh@cryptsoft.com). ++ * ++ * Copyright remains Eric Young's, and as such any Copyright notices in ++ * the code are not to be removed. ++ * If this package is used in a product, Eric Young should be given attribution ++ * as the author of the parts of the library used. ++ * This can be in the form of a textual message at program startup or ++ * in documentation (online or textual) provided with the package. ++ * ++ * 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 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 acknowledgement: ++ * "This product includes cryptographic software written by ++ * Eric Young (eay@cryptsoft.com)" ++ * The word 'cryptographic' can be left out if the rouines from the library ++ * being used are not cryptographic related :-). ++ * 4. If you include any Windows specific code (or a derivative thereof) from ++ * the apps directory (application code) you must include an acknowledgement: ++ * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" ++ * ++ * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND ++ * ANY EXPRESS 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 AUTHOR OR 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. ++ * ++ * The licence and distribution terms for any publically available version or ++ * derivative of this code cannot be changed. i.e. this code cannot simply be ++ * copied and put under another distribution licence ++ * [including the GNU Public Licence.] ++ */ ++ +diff --git a/CryptoPkg/Library/OpensslLib/openssl/Makefile.shared b/CryptoPkg/Library/OpensslLib/openssl/Makefile.shared +new file mode 100644 +index 0000000..098e1ec +--- /dev/null ++++ b/CryptoPkg/Library/OpensslLib/openssl/Makefile.shared +@@ -0,0 +1,622 @@ ++# ++# Helper makefile to link shared libraries in a portable way. ++# This is much simpler than libtool, and hopefully not too error-prone. ++# ++# The following variables need to be set on the command line to build ++# properly ++ ++# CC contains the current compiler. This one MUST be defined ++CC=cc ++CFLAGS=$(CFLAG) ++# LDFLAGS contains flags to be used when temporary object files (when building ++# shared libraries) are created, or when an application is linked. ++# SHARED_LDFLAGS contains flags to be used when the shared library is created. ++LDFLAGS=$(LDFLAG) ++SHARED_LDFLAGS=$(SHARED_LDFLAG) ++ ++RC=windres ++# SHARED_RCFLAGS are flags used with windres, i.e. when build for Cygwin ++# or Mingw. ++SHARED_RCFLAGS=$(SHARED_RCFLAG) ++ ++NM=nm ++ ++# LIBNAME contains just the name of the library, without prefix ("lib" ++# on Unix, "cyg" for certain forms under Cygwin...) or suffix (.a, .so, ++# .dll, ...). This one MUST have a value when using this makefile to ++# build shared libraries. ++# For example, to build libfoo.so, you need to do the following: ++#LIBNAME=foo ++LIBNAME= ++ ++# APPNAME contains just the name of the application, without suffix ("" ++# on Unix, ".exe" on Windows, ...). This one MUST have a value when using ++# this makefile to build applications. ++# For example, to build foo, you need to do the following: ++#APPNAME=foo ++APPNAME= ++ ++# DSTDIR is the directory where the built file should end up in. ++DSTDIR=. ++ ++# SRCDIR is the top directory of the source tree. ++SRCDIR=. ++ ++# OBJECTS contains all the object files to link together into the application. ++# This must contain at least one object file. ++#OBJECTS=foo.o ++OBJECTS= ++ ++# LIBEXTRAS contains extra modules to link together with the library. ++# For example, if a second library, say libbar.a needs to be linked into ++# libfoo.so, you need to do the following: ++#LIBEXTRAS=libbar.a ++# Note that this MUST be used when using the link_dso targets, to hold the ++# names of all object files that go into the target shared object. ++LIBEXTRAS= ++ ++# LIBVERSION contains the current version of the library. ++# For example, to build libfoo.so.1.2, you need to do the following: ++#LIBVERSION=1.2 ++LIBVERSION= ++ ++# LIBCOMPATVERSIONS contains the compatibility versions (a list) of ++# the library. They MUST be in decreasing order. ++# For example, if libfoo.so.1.2.1 is backward compatible with libfoo.so.1.2 ++# and libfoo.so.1, you need to do the following: ++#LIBCOMPATVERSIONS=1.2 1 ++# Note that on systems that use sonames, the last number will appear as ++# part of it. ++# It's also possible, for systems that support it (Tru64, for example), ++# to add extra compatibility info with more precision, by adding a second ++# list of versions, separated from the first with a semicolon, like this: ++#LIBCOMPATVERSIONS=1.2 1;1.2.0 1.1.2 1.1.1 1.1.0 1.0.0 ++LIBCOMPATVERSIONS= ++ ++# LIBDEPS contains all the flags necessary to cover all necessary ++# dependencies to other libraries. ++LIBDEPS= ++ ++#------------------------------------------------------------------------------ ++# The rest is private to this makefile. ++ ++SET_X=: ++#SET_X=set -x ++ ++top: ++ echo "Trying to use this makefile interactively? Don't." ++ ++CALC_VERSIONS= \ ++ SHLIB_COMPAT=; SHLIB_SOVER=; \ ++ if [ -n "$(LIBVERSION)$(LIBCOMPATVERSIONS)" ]; then \ ++ prev=""; \ ++ for v in `echo "$(LIBVERSION) $(LIBCOMPATVERSIONS)" | cut -d';' -f1`; do \ ++ SHLIB_SOVER_NODOT=$$v; \ ++ SHLIB_SOVER=.$$v; \ ++ if [ -n "$$prev" ]; then \ ++ SHLIB_COMPAT="$$SHLIB_COMPAT .$$prev"; \ ++ fi; \ ++ prev=$$v; \ ++ done; \ ++ fi ++ ++LINK_APP= \ ++ ( $(SET_X); \ ++ LIBDEPS="$${LIBDEPS:-$(LIBDEPS)}"; \ ++ LDCMD="$${LDCMD:-$(CC)}"; LDFLAGS="$${LDFLAGS:-$(CFLAGS) $(LDFLAGS)}"; \ ++ LIBPATH=`for x in $$LIBDEPS; do echo $$x; done | sed -e 's/^ *-L//;t' -e d | uniq`; \ ++ LIBPATH=`echo $$LIBPATH | sed -e 's/ /:/g'`; \ ++ echo LD_LIBRARY_PATH=$$LIBPATH:$$LD_LIBRARY_PATH \ ++ $${LDCMD} $${LDFLAGS} -o $${APPNAME:=$(APPNAME)} $(OBJECTS) $${LIBDEPS}; \ ++ LD_LIBRARY_PATH=$$LIBPATH:$$LD_LIBRARY_PATH \ ++ $${LDCMD} $${LDFLAGS} -o $${APPNAME:=$(APPNAME)} $(OBJECTS) $${LIBDEPS} ) ++ ++LINK_SO= \ ++ ( $(SET_X); \ ++ LIBDEPS="$${LIBDEPS:-$(LIBDEPS)}"; \ ++ SHAREDCMD="$${SHAREDCMD:-$(CC)}"; \ ++ SHAREDFLAGS="$${SHAREDFLAGS:-$(CFLAGS) $(SHARED_LDFLAGS)}"; \ ++ LIBPATH=`for x in $$LIBDEPS; do echo $$x; done | sed -e 's/^ *-L//;t' -e d | uniq`; \ ++ LIBPATH=`echo $$LIBPATH | sed -e 's/ /:/g'`; \ ++ echo LD_LIBRARY_PATH=$$LIBPATH:$$LD_LIBRARY_PATH \ ++ $${SHAREDCMD} $${SHAREDFLAGS} \ ++ -o $(DSTDIR)/$$SHLIB$$SHLIB_SOVER$$SHLIB_SUFFIX \ ++ $$ALLSYMSFLAGS $$SHOBJECTS $$NOALLSYMSFLAGS $$LIBDEPS; \ ++ LD_LIBRARY_PATH=$$LIBPATH:$$LD_LIBRARY_PATH \ ++ $${SHAREDCMD} $${SHAREDFLAGS} \ ++ -o $(DSTDIR)/$$SHLIB$$SHLIB_SOVER$$SHLIB_SUFFIX \ ++ $$ALLSYMSFLAGS $$SHOBJECTS $$NOALLSYMSFLAGS $$LIBDEPS \ ++ ) && $(SYMLINK_SO) ++ ++SYMLINK_SO= \ ++ if [ -n "$$INHIBIT_SYMLINKS" ]; then :; else \ ++ prev=$$SHLIB$$SHLIB_SOVER$$SHLIB_SUFFIX; \ ++ if [ -n "$$SHLIB_COMPAT" ]; then \ ++ for x in $$SHLIB_COMPAT; do \ ++ ( $(SET_X); rm -f $(DSTDIR)/$$SHLIB$$x$$SHLIB_SUFFIX; \ ++ ln -s $$prev $(DSTDIR)/$$SHLIB$$x$$SHLIB_SUFFIX ); \ ++ prev=$$SHLIB$$x$$SHLIB_SUFFIX; \ ++ done; \ ++ fi; \ ++ if [ -n "$$SHLIB_SOVER" ]; then \ ++ ( $(SET_X); rm -f $(DSTDIR)/$$SHLIB$$SHLIB_SUFFIX; \ ++ ln -s $$prev $(DSTDIR)/$$SHLIB$$SHLIB_SUFFIX ); \ ++ fi; \ ++ fi ++ ++LINK_SO_SHLIB= SHOBJECTS="$(DSTDIR)/lib$(LIBNAME).a $(LIBEXTRAS)"; $(LINK_SO) ++LINK_SO_DSO= INHIBIT_SYMLINKS=yes; SHOBJECTS="$(LIBEXTRAS)"; $(LINK_SO) ++ ++LINK_SO_SHLIB_VIA_O= \ ++ SHOBJECTS=$(DSTDIR)/lib$(LIBNAME).o; \ ++ ALL=$$ALLSYMSFLAGS; ALLSYMSFLAGS=; NOALLSYMSFLAGS=; \ ++ ( echo ld $(LDFLAGS) -r -o $$SHOBJECTS $$ALL lib$(LIBNAME).a $(LIBEXTRAS); \ ++ ld $(LDFLAGS) -r -o $$SHOBJECTS $$ALL $(DSTDIR)/lib$(LIBNAME).a $(LIBEXTRAS) ); \ ++ $(LINK_SO) && ( echo rm -f $$SHOBJECTS; rm -f $$SHOBJECTS ) ++ ++LINK_SO_SHLIB_UNPACKED= \ ++ UNPACKDIR=link_tmp.$$$$; rm -rf $$UNPACKDIR; mkdir $$UNPACKDIR; \ ++ (cd $$UNPACKDIR; ar x ../$(DSTDIR)/lib$(LIBNAME).a) && \ ++ ([ -z "$(LIBEXTRAS)" ] || cp $(LIBEXTRAS) $$UNPACKDIR) && \ ++ SHOBJECTS=$$UNPACKDIR/*.o; \ ++ $(LINK_SO) && rm -rf $$UNPACKDIR ++ ++DETECT_GNU_LD=($(CC) -Wl,-V /dev/null 2>&1 | grep '^GNU ld' )>/dev/null ++ ++DO_GNU_SO_COMMON=\ ++ SHAREDFLAGS="$(CFLAGS) $(SHARED_LDFLAGS) -shared -Wl,-Bsymbolic -Wl,-soname=$$SHLIB$$SHLIB_SOVER$$SHLIB_SUFFIX" ++DO_GNU_DSO=\ ++ SHLIB=$(LIBNAME).so; \ ++ SHLIB_SOVER=; \ ++ SHLIB_SUFFIX=; \ ++ $(DO_GNU_SO_COMMON) ++DO_GNU_SO=\ ++ $(CALC_VERSIONS); \ ++ SHLIB=lib$(LIBNAME).so; \ ++ ALLSYMSFLAGS='-Wl,--whole-archive'; \ ++ NOALLSYMSFLAGS='-Wl,--no-whole-archive'; \ ++ $(DO_GNU_SO_COMMON) ++DO_GNU_APP=LDFLAGS="$(CFLAGS) $(LDFLAGS)" ++ ++#This is rather special. It's a special target with which one can link ++#applications without bothering with any features that have anything to ++#do with shared libraries, for example when linking against static ++#libraries. It's mostly here to avoid a lot of conditionals everywhere ++#else... ++link_app.: ++ $(LINK_APP) ++ ++link_dso.gnu: ++ @ $(DO_GNU_DSO); $(LINK_SO_DSO) ++link_shlib.gnu: ++ @ $(DO_GNU_SO); $(LINK_SO_SHLIB) ++link_app.gnu: ++ @ $(DO_GNU_APP); $(LINK_APP) ++ ++link_shlib.linux-shared: ++ @$(PERL) $(SRCDIR)/util/mkdef.pl $(LIBNAME) linux >$(LIBNAME).map; \ ++ $(DO_GNU_SO); \ ++ ALLSYMSFLAGS='-Wl,--whole-archive,--version-script=$(LIBNAME).map'; \ ++ $(LINK_SO_SHLIB) ++ ++link_dso.bsd: ++ @if $(DETECT_GNU_LD); then $(DO_GNU_DSO); else \ ++ SHLIB=$(LIBNAME).so; \ ++ SHLIB_SUFFIX=; \ ++ LIBDEPS=" "; \ ++ ALLSYMSFLAGS=; \ ++ NOALLSYMSFLAGS=; \ ++ SHAREDFLAGS="$(CFLAGS) $(SHARED_LDFLAGS) -shared -nostdlib"; \ ++ fi; $(LINK_SO_DSO) ++link_shlib.bsd: ++ @if $(DETECT_GNU_LD); then $(DO_GNU_SO); else \ ++ $(CALC_VERSIONS); \ ++ SHLIB=lib$(LIBNAME).so; \ ++ SHLIB_SUFFIX=; \ ++ LIBDEPS=" "; \ ++ ALLSYMSFLAGS="-Wl,-Bforcearchive"; \ ++ NOALLSYMSFLAGS=; \ ++ SHAREDFLAGS="$(CFLAGS) $(SHARED_LDFLAGS) -shared -nostdlib"; \ ++ fi; $(LINK_SO_SHLIB) ++link_app.bsd: ++ @if $(DETECT_GNU_LD); then $(DO_GNU_APP); else \ ++ LDFLAGS="$(CFLAGS) $(LDFLAGS)"; \ ++ fi; $(LINK_APP) ++ ++# For Darwin AKA Mac OS/X (dyld) ++# Originally link_dso.darwin produced .so, because it was hard-coded ++# in dso_dlfcn module. At later point dso_dlfcn switched to .dylib ++# extension in order to allow for run-time linking with vendor- ++# supplied shared libraries such as libz, so that link_dso.darwin had ++# to be harmonized with it. This caused minor controversy, because ++# it was believed that dlopen can't be used to dynamically load ++# .dylib-s, only so called bundle modules (ones linked with -bundle ++# flag). The belief seems to be originating from pre-10.4 release, ++# where dlfcn functionality was emulated by dlcompat add-on. In ++# 10.4 dlopen was rewritten as native part of dyld and is documented ++# to be capable of loading both dynamic libraries and bundles. In ++# order to provide compatibility with pre-10.4 dlopen, modules are ++# linked with -bundle flag, which makes .dylib extension misleading. ++# It works, because dlopen is [and always was] extension-agnostic. ++# Alternative to this heuristic approach is to develop specific ++# MacOS X dso module relying on whichever "native" dyld interface. ++link_dso.darwin: ++ @ SHLIB=$(LIBNAME); \ ++ SHLIB_SUFFIX=.dylib; \ ++ ALLSYMSFLAGS=''; \ ++ NOALLSYMSFLAGS=''; \ ++ SHAREDFLAGS="$(CFLAGS) `echo $(SHARED_LDFLAGS) | sed s/dynamiclib/bundle/`"; \ ++ $(LINK_SO_DSO) ++link_shlib.darwin: ++ @ $(CALC_VERSIONS); \ ++ SHLIB=lib$(LIBNAME); \ ++ SHLIB_SUFFIX=.dylib; \ ++ ALLSYMSFLAGS='-all_load'; \ ++ NOALLSYMSFLAGS=''; \ ++ SHAREDFLAGS="$(CFLAGS) $(SHARED_LDFLAGS)"; \ ++ if [ -n "$(LIBVERSION)" ]; then \ ++ SHAREDFLAGS="$$SHAREDFLAGS -current_version $(LIBVERSION)"; \ ++ fi; \ ++ if [ -n "$$SHLIB_SOVER_NODOT" ]; then \ ++ SHAREDFLAGS="$$SHAREDFLAGS -compatibility_version $$SHLIB_SOVER_NODOT"; \ ++ fi; \ ++ SHAREDFLAGS="$$SHAREDFLAGS -install_name $(INSTALLTOP)/$(LIBDIR)/$$SHLIB$(SHLIB_EXT)"; \ ++ $(LINK_SO_SHLIB) ++link_app.darwin: # is there run-path on darwin? ++ $(LINK_APP) ++ ++link_dso.cygwin: ++ @SHLIB=$(LIBNAME); \ ++ SHLIB_SUFFIX=.dll; \ ++ ALLSYMSFLAGS=''; \ ++ NOALLSYMSFLAGS=''; \ ++ base=-Wl,--enable-auto-image-base; \ ++ SHAREDFLAGS="$(CFLAGS) $(SHARED_LDFLAGS) -shared $$base -Wl,-Bsymbolic"; \ ++ $(LINK_SO_DSO) ++link_shlib.cygwin: ++ @ $(CALC_VERSIONS); \ ++ INHIBIT_SYMLINKS=yes; \ ++ SHLIB=cyg$(LIBNAME); SHLIB_SOVER=-$(LIBVERSION); SHLIB_SUFFIX=.dll; \ ++ dll_name=$$SHLIB$$SHLIB_SOVER$$SHLIB_SUFFIX; \ ++ echo "$(PERL) $(SRCDIR)/util/mkrc.pl $$dll_name |" \ ++ "$(RC) $(SHARED_RCFLAGS) -o rc.o"; \ ++ $(PERL) $(SRCDIR)/util/mkrc.pl $$dll_name | \ ++ $(RC) $(SHARED_RCFLAGS) -o rc.o; \ ++ ALLSYMSFLAGS='-Wl,--whole-archive'; \ ++ NOALLSYMSFLAGS='-Wl,--no-whole-archive'; \ ++ SHAREDFLAGS="$(CFLAGS) $(SHARED_LDFLAGS) -shared -Wl,--enable-auto-image-base -Wl,-Bsymbolic -Wl,--out-implib,lib$(LIBNAME).dll.a rc.o"; \ ++ $(LINK_SO_SHLIB) || exit 1; \ ++ rm rc.o ++link_app.cygwin: ++ $(LINK_APP) ++ ++# link_dso.mingw-shared and link_app.mingw-shared are mapped to the ++# corresponding cygwin targets, as they do the exact same thing. ++link_shlib.mingw: ++ @ $(CALC_VERSIONS); \ ++ INHIBIT_SYMLINKS=yes; \ ++ arch=; \ ++ if expr $(PLATFORM) : mingw64 > /dev/null; then arch=-x64; fi; \ ++ sover=`echo $(LIBVERSION) | sed -e 's/\./_/g'` ; \ ++ SHLIB=lib$(LIBNAME); \ ++ SHLIB_SOVER=-$$sover$$arch; \ ++ SHLIB_SUFFIX=.dll; \ ++ dll_name=$$SHLIB$$SHLIB_SOVER$$SHLIB_SUFFIX; \ ++ base=; [ $(LIBNAME) = "crypto" -a -n "$(FIPSCANLIB)" ] && base=-Wl,--image-base,0x63000000; \ ++ $(PERL) $(SRCDIR)/util/mkdef.pl 32 $(LIBNAME) \ ++ | sed -e 's|^\(LIBRARY *\)$(LIBNAME)32|\1'"$$dll_name"'|' \ ++ > $(LIBNAME).def; \ ++ echo "$(PERL) $(SRCDIR)/util/mkrc.pl $$dll_name |" \ ++ "$(RC) $(SHARED_RCFLAGS) -o rc.o"; \ ++ $(PERL) $(SRCDIR)/util/mkrc.pl $$dll_name | \ ++ $(RC) $(SHARED_RCFLAGS) -o rc.o; \ ++ ALLSYMSFLAGS='-Wl,--whole-archive'; \ ++ NOALLSYMSFLAGS='-Wl,--no-whole-archive'; \ ++ SHAREDFLAGS="$(CFLAGS) $(SHARED_LDFLAGS) -shared $$base -Wl,-Bsymbolic -Wl,--out-implib,lib$(LIBNAME).dll.a $(LIBNAME).def rc.o"; \ ++ $(LINK_SO_SHLIB) || exit 1; \ ++ rm $(LIBNAME).def rc.o ++ ++link_dso.alpha-osf1: ++ @ if $(DETECT_GNU_LD); then \ ++ $(DO_GNU_DSO); \ ++ else \ ++ SHLIB=$(LIBNAME).so; \ ++ SHLIB_SUFFIX=; \ ++ ALLSYMSFLAGS=''; \ ++ NOALLSYMSFLAGS=''; \ ++ SHAREDFLAGS="$(CFLAGS) $(SHARED_LDFLAGS) -shared -Wl,-B,symbolic"; \ ++ fi; \ ++ $(LINK_SO_DSO) ++link_shlib.alpha-osf1: ++ @ if $(DETECT_GNU_LD); then \ ++ $(DO_GNU_SO); \ ++ else \ ++ SHLIB=lib$(LIBNAME).so; \ ++ SHLIB_SUFFIX=; \ ++ SHLIB_HIST=`echo "$(LIBCOMPATVERSIONS)" | cut -d';' -f2 | sed -e 's/ */:/'`; \ ++ if [ -n "$$SHLIB_HIST" ]; then \ ++ SHLIB_HIST="$${SHLIB_HIST}:$(LIBVERSION)"; \ ++ else \ ++ SHLIB_HIST="$(LIBVERSION)"; \ ++ fi; \ ++ SHLIB_SOVER=; \ ++ ALLSYMSFLAGS='-all'; \ ++ NOALLSYMSFLAGS='-none'; \ ++ SHAREDFLAGS="$(CFLAGS) $(SHARED_LDFLAGS) -shared -Wl,-B,symbolic"; \ ++ if [ -n "$$SHLIB_HIST" ]; then \ ++ SHAREDFLAGS="$$SHAREDFLAGS -set_version $$SHLIB_HIST"; \ ++ fi; \ ++ fi; \ ++ $(LINK_SO_SHLIB) ++link_app.alpha-osf1: ++ @if $(DETECT_GNU_LD); then \ ++ $(DO_GNU_APP); \ ++ else \ ++ LDFLAGS="$(CFLAGS) $(LDFLAGS)"; \ ++ fi; \ ++ $(LINK_APP) ++ ++link_dso.solaris: ++ @ if $(DETECT_GNU_LD); then \ ++ $(DO_GNU_DSO); \ ++ else \ ++ $(CALC_VERSIONS); \ ++ SHLIB=$(LIBNAME).so; \ ++ SHLIB_SUFFIX=; \ ++ ALLSYMSFLAGS=""; \ ++ NOALLSYMSFLAGS=""; \ ++ SHAREDFLAGS="$(CFLAGS) $(SHARED_LDFLAGS) -h $$SHLIB$$SHLIB_SOVER$$SHLIB_SUFFIX -Wl,-Bsymbolic"; \ ++ fi; \ ++ $(LINK_SO_DSO) ++link_shlib.solaris: ++ @ if $(DETECT_GNU_LD); then \ ++ $(DO_GNU_SO); \ ++ else \ ++ $(CALC_VERSIONS); \ ++ SHLIB=lib$(LIBNAME).so; \ ++ SHLIB_SUFFIX=;\ ++ $(PERL) $(SRCDIR)/util/mkdef.pl $(LIBNAME) linux >$(LIBNAME).map; \ ++ ALLSYMSFLAGS="-Wl,-z,allextract,-M,$(LIBNAME).map"; \ ++ NOALLSYMSFLAGS="-Wl,-z,defaultextract"; \ ++ SHAREDFLAGS="$(CFLAGS) $(SHARED_LDFLAGS) -h $$SHLIB$$SHLIB_SOVER$$SHLIB_SUFFIX -Wl,-Bsymbolic"; \ ++ fi; \ ++ $(LINK_SO_SHLIB) ++link_app.solaris: ++ @ if $(DETECT_GNU_LD); then \ ++ $(DO_GNU_APP); \ ++ else \ ++ LDFLAGS="$(CFLAGS) $(LDFLAGS)"; \ ++ fi; \ ++ $(LINK_APP) ++ ++# OpenServer 5 native compilers used ++link_dso.svr3: ++ @ if $(DETECT_GNU_LD); then \ ++ $(DO_GNU_DSO); \ ++ else \ ++ $(CALC_VERSIONS); \ ++ SHLIB=$(LIBNAME).so; \ ++ SHLIB_SUFFIX=; \ ++ ALLSYMSFLAGS=''; \ ++ NOALLSYMSFLAGS=''; \ ++ SHAREDFLAGS="$(CFLAGS) -G -h $$SHLIB$$SHLIB_SUFFIX"; \ ++ fi; \ ++ $(LINK_SO_DSO) ++link_shlib.svr3: ++ @ if $(DETECT_GNU_LD); then \ ++ $(DO_GNU_SO); \ ++ else \ ++ $(CALC_VERSIONS); \ ++ SHLIB=lib$(LIBNAME).so; \ ++ SHLIB_SUFFIX=; \ ++ ALLSYMSFLAGS=''; \ ++ NOALLSYMSFLAGS=''; \ ++ SHAREDFLAGS="$(CFLAGS) -G -h $$SHLIB$$SHLIB_SOVER$$SHLIB_SUFFIX"; \ ++ fi; \ ++ $(LINK_SO_SHLIB_UNPACKED) ++link_app.svr3: ++ @$(DETECT_GNU_LD) && $(DO_GNU_APP); \ ++ $(LINK_APP) ++ ++# UnixWare 7 and OpenUNIX 8 native compilers used ++link_dso.svr5: ++ @ if $(DETECT_GNU_LD); then \ ++ $(DO_GNU_DSO); \ ++ else \ ++ SHARE_FLAG='-G'; \ ++ ($(CC) -v 2>&1 | grep gcc) > /dev/null && SHARE_FLAG='-shared'; \ ++ SHLIB=$(LIBNAME).so; \ ++ SHLIB_SUFFIX=; \ ++ ALLSYMSFLAGS=''; \ ++ NOALLSYMSFLAGS=''; \ ++ SHAREDFLAGS="$(CFLAGS) $${SHARE_FLAG} -h $$SHLIB$$SHLIB_SUFFIX"; \ ++ fi; \ ++ $(LINK_SO_DSO) ++link_shlib.svr5: ++ @ if $(DETECT_GNU_LD); then \ ++ $(DO_GNU_SO); \ ++ else \ ++ $(CALC_VERSIONS); \ ++ SHARE_FLAG='-G'; \ ++ ($(CC) -v 2>&1 | grep gcc) > /dev/null && SHARE_FLAG='-shared'; \ ++ SHLIB=lib$(LIBNAME).so; \ ++ SHLIB_SUFFIX=; \ ++ ALLSYMSFLAGS=''; \ ++ NOALLSYMSFLAGS=''; \ ++ SHAREDFLAGS="$(CFLAGS) $${SHARE_FLAG} -h $$SHLIB$$SHLIB_SOVER$$SHLIB_SUFFIX"; \ ++ fi; \ ++ $(LINK_SO_SHLIB_UNPACKED) ++link_app.svr5: ++ @$(DETECT_GNU_LD) && $(DO_GNU_APP); \ ++ $(LINK_APP) ++ ++link_dso.irix: ++ @ if $(DETECT_GNU_LD); then \ ++ $(DO_GNU_DSO); \ ++ else \ ++ SHLIB=$(LIBNAME).so; \ ++ SHLIB_SUFFIX=; \ ++ ALLSYMSFLAGS=""; \ ++ NOALLSYMSFLAGS=""; \ ++ SHAREDFLAGS="$(CFLAGS) $(SHARED_LDFLAGS) -shared -Wl,-soname,$$SHLIB$$SHLIB_SUFFIX,-B,symbolic"; \ ++ fi; \ ++ $(LINK_SO_DSO) ++link_shlib.irix: ++ @ if $(DETECT_GNU_LD); then \ ++ $(DO_GNU_SO); \ ++ else \ ++ $(CALC_VERSIONS); \ ++ SHLIB=lib$(LIBNAME).so; \ ++ SHLIB_SUFFIX=; \ ++ MINUSWL=""; \ ++ ($(CC) -v 2>&1 | grep gcc) > /dev/null && MINUSWL="-Wl,"; \ ++ ALLSYMSFLAGS="$${MINUSWL}-all"; \ ++ NOALLSYMSFLAGS="$${MINUSWL}-none"; \ ++ SHAREDFLAGS="$(CFLAGS) $(SHARED_LDFLAGS) -shared -Wl,-soname,$$SHLIB$$SHLIB_SOVER$$SHLIB_SUFFIX,-B,symbolic"; \ ++ fi; \ ++ $(LINK_SO_SHLIB) ++link_app.irix: ++ @LDFLAGS="$(CFLAGS) $(LDFLAGS)"; \ ++ $(LINK_APP) ++ ++# 32-bit PA-RISC HP-UX embeds the -L pathname of libs we link with, so ++# we compensate for it with +cdp ../: and +cdp ./:. Yes, these rewrite ++# rules imply that we can only link one level down in catalog structure, ++# but that's what takes place for the moment of this writing. +cdp option ++# was introduced in HP-UX 11.x and applies in 32-bit PA-RISC link ++# editor context only [it's simply ignored in other cases, which are all ++# ELFs by the way]. ++# ++link_dso.hpux: ++ @if $(DETECT_GNU_LD); then $(DO_GNU_DSO); else \ ++ SHLIB=$(LIBNAME).sl; \ ++ expr "$(CFLAGS)" : '.*DSO_DLFCN' > /dev/null && SHLIB=$(LIBNAME).so; \ ++ SHLIB_SUFFIX=; \ ++ ALLSYMSFLAGS=''; \ ++ NOALLSYMSFLAGS=''; \ ++ expr $(PLATFORM) : 'hpux64' > /dev/null && ALLSYMSFLAGS='-Wl,+forceload'; \ ++ SHAREDFLAGS="$(CFLAGS) $(SHARED_LDFLAGS) -Wl,-B,symbolic,+vnocompatwarnings,-z,+s,+h,$$SHLIB$$SHLIB_SUFFIX,+cdp,../:,+cdp,./:"; \ ++ fi; \ ++ rm -f $(DSTDIR)/$$SHLIB$$SHLIB_SUFFIX || :; \ ++ $(LINK_SO_DSO) && chmod a=rx $(DSTDIR)/$$SHLIB$$SHLIB_SUFFIX ++link_shlib.hpux: ++ @if $(DETECT_GNU_LD); then $(DO_GNU_SO); else \ ++ $(CALC_VERSIONS); \ ++ SHLIB=lib$(LIBNAME).sl; \ ++ expr $(PLATFORM) : '.*ia64' > /dev/null && SHLIB=lib$(LIBNAME).so; \ ++ SHLIB_SUFFIX=; \ ++ ALLSYMSFLAGS='-Wl,-Fl'; \ ++ NOALLSYMSFLAGS=''; \ ++ expr $(PLATFORM) : 'hpux64' > /dev/null && ALLSYMSFLAGS='-Wl,+forceload'; \ ++ SHAREDFLAGS="$(CFLAGS) $(SHARED_LDFLAGS) -Wl,-B,symbolic,+vnocompatwarnings,-z,+s,+h,$$SHLIB$$SHLIB_SOVER$$SHLIB_SUFFIX,+cdp,../:,+cdp,./:"; \ ++ fi; \ ++ rm -f $(DSTDIR)/$$SHLIB$$SHLIB_SOVER$$SHLIB_SUFFIX || :; \ ++ $(LINK_SO_SHLIB) && chmod a=rx $(DSTDIR)/$$SHLIB$$SHLIB_SOVER$$SHLIB_SUFFIX ++link_app.hpux: ++ @if $(DETECT_GNU_LD); then $(DO_GNU_APP); else \ ++ LDFLAGS="$(CFLAGS) $(LDFLAGS) -Wl,+s,+cdp,../:,+cdp,./:"; \ ++ fi; \ ++ $(LINK_APP) ++ ++link_dso.aix: ++ @OBJECT_MODE=`expr "x$(SHARED_LDFLAGS)" : 'x\-[a-z]*\(64\)'` || :; \ ++ OBJECT_MODE=$${OBJECT_MODE:-32}; export OBJECT_MODE; \ ++ SHLIB=$(LIBNAME).so; \ ++ SHLIB_SUFFIX=; \ ++ ALLSYMSFLAGS=''; \ ++ NOALLSYMSFLAGS=''; \ ++ SHAREDFLAGS='$(CFLAGS) $(SHARED_LDFLAGS) -Wl,-bexpall,-bnolibpath,-bM:SRE'; \ ++ rm -f $(DSTDIR)/$$SHLIB$$SHLIB_SOVER 2>&1 > /dev/null ; \ ++ $(LINK_SO_DSO); ++link_shlib.aix: ++ @ $(CALC_VERSIONS); \ ++ OBJECT_MODE=`expr "x$(SHARED_LDFLAGS)" : 'x\-[a-z]*\(64\)'` || : ; \ ++ OBJECT_MODE=$${OBJECT_MODE:-32}; export OBJECT_MODE; \ ++ SHLIB=lib$(LIBNAME).so; \ ++ SHLIB_SUFFIX=; \ ++ ALLSYMSFLAGS='-bnogc'; \ ++ NOALLSYMSFLAGS=''; \ ++ SHAREDFLAGS='$(CFLAGS) $(SHARED_LDFLAGS) -Wl,-bexpall,-bnolibpath,-bM:SRE'; \ ++ rm -f $(DSTDIR)/$$SHLIB$$SHLIB_SOVER 2>&1 > /dev/null ; \ ++ $(LINK_SO_SHLIB_VIA_O) ++link_app.aix: ++ LDFLAGS="$(CFLAGS) -Wl,-bsvr4 $(LDFLAGS)"; \ ++ $(LINK_APP) ++ ++ ++# Targets to build symbolic links when needed ++symlink.gnu symlink.solaris symlink.svr3 symlink.svr5 symlink.irix \ ++symlink.aix: ++ @ $(CALC_VERSIONS); \ ++ SHLIB=lib$(LIBNAME).so; \ ++ $(SYMLINK_SO) ++symlink.darwin: ++ @ $(CALC_VERSIONS); \ ++ SHLIB=lib$(LIBNAME); \ ++ SHLIB_SUFFIX=.dylib; \ ++ $(SYMLINK_SO) ++symlink.hpux: ++ @ $(CALC_VERSIONS); \ ++ SHLIB=lib$(LIBNAME).sl; \ ++ expr $(PLATFORM) : '.*ia64' > /dev/null && SHLIB=lib$(LIBNAME).so; \ ++ $(SYMLINK_SO) ++# The following lines means those specific architectures do no symlinks ++symlink.cygwin symlink.alpha-osf1 symlink.tru64 symlink.tru64-rpath: ++ ++# Compatibility targets ++link_dso.bsd-gcc-shared link_dso.linux-shared link_dso.gnu-shared: link_dso.gnu ++link_shlib.bsd-gcc-shared: link_shlib.linux-shared ++link_shlib.gnu-shared: link_shlib.gnu ++link_app.bsd-gcc-shared link_app.linux-shared link_app.gnu-shared: link_app.gnu ++symlink.bsd-gcc-shared symlink.bsd-shared symlink.linux-shared symlink.gnu-shared: symlink.gnu ++link_dso.bsd-shared: link_dso.bsd ++link_shlib.bsd-shared: link_shlib.bsd ++link_app.bsd-shared: link_app.bsd ++link_dso.darwin-shared: link_dso.darwin ++link_shlib.darwin-shared: link_shlib.darwin ++link_app.darwin-shared: link_app.darwin ++symlink.darwin-shared: symlink.darwin ++link_dso.cygwin-shared: link_dso.cygwin ++link_shlib.cygwin-shared: link_shlib.cygwin ++link_app.cygwin-shared: link_app.cygwin ++symlink.cygwin-shared: symlink.cygwin ++link_dso.mingw-shared: link_dso.cygwin ++link_shlib.mingw-shared: link_shlib.mingw ++link_app.mingw-shared: link_app.cygwin ++symlink.mingw-shared: symlink.cygwin ++link_dso.alpha-osf1-shared: link_dso.alpha-osf1 ++link_shlib.alpha-osf1-shared: link_shlib.alpha-osf1 ++link_app.alpha-osf1-shared: link_app.alpha-osf1 ++symlink.alpha-osf1-shared: symlink.alpha-osf1 ++link_dso.tru64-shared: link_dso.tru64 ++link_shlib.tru64-shared: link_shlib.tru64 ++link_app.tru64-shared: link_app.tru64 ++symlink.tru64-shared: symlink.tru64 ++link_dso.tru64-shared-rpath: link_dso.tru64-rpath ++link_shlib.tru64-shared-rpath: link_shlib.tru64-rpath ++link_app.tru64-shared-rpath: link_app.tru64-rpath ++symlink.tru64-shared-rpath: symlink.tru64-rpath ++link_dso.solaris-shared: link_dso.solaris ++link_shlib.solaris-shared: link_shlib.solaris ++link_app.solaris-shared: link_app.solaris ++symlink.solaris-shared: symlink.solaris ++link_dso.svr3-shared: link_dso.svr3 ++link_shlib.svr3-shared: link_shlib.svr3 ++link_app.svr3-shared: link_app.svr3 ++symlink.svr3-shared: symlink.svr3 ++link_dso.svr5-shared: link_dso.svr5 ++link_shlib.svr5-shared: link_shlib.svr5 ++link_app.svr5-shared: link_app.svr5 ++symlink.svr5-shared: symlink.svr5 ++link_dso.irix-shared: link_dso.irix ++link_shlib.irix-shared: link_shlib.irix ++link_app.irix-shared: link_app.irix ++symlink.irix-shared: symlink.irix ++link_dso.hpux-shared: link_dso.hpux ++link_shlib.hpux-shared: link_shlib.hpux ++link_app.hpux-shared: link_app.hpux ++symlink.hpux-shared: symlink.hpux ++link_dso.aix-shared: link_dso.aix ++link_shlib.aix-shared: link_shlib.aix ++link_app.aix-shared: link_app.aix ++symlink.aix-shared: symlink.aix +diff --git a/CryptoPkg/Library/OpensslLib/openssl/NEWS b/CryptoPkg/Library/OpensslLib/openssl/NEWS +new file mode 100644 +index 0000000..f331ec4 +--- /dev/null ++++ b/CryptoPkg/Library/OpensslLib/openssl/NEWS +@@ -0,0 +1,852 @@ ++ ++ NEWS ++ ==== ++ ++ This file gives a brief overview of the major changes between each OpenSSL ++ release. For more details please read the CHANGES file. ++ ++ Major changes between OpenSSL 1.1.0d and OpenSSL 1.1.0e [16 Feb 2017] ++ ++ o Encrypt-Then-Mac renegotiation crash (CVE-2017-3733) ++ ++ Major changes between OpenSSL 1.1.0c and OpenSSL 1.1.0d [26 Jan 2017] ++ ++ o Truncated packet could crash via OOB read (CVE-2017-3731) ++ o Bad (EC)DHE parameters cause a client crash (CVE-2017-3730) ++ o BN_mod_exp may produce incorrect results on x86_64 (CVE-2017-3732) ++ ++ Major changes between OpenSSL 1.1.0b and OpenSSL 1.1.0c [10 Nov 2016] ++ ++ o ChaCha20/Poly1305 heap-buffer-overflow (CVE-2016-7054) ++ o CMS Null dereference (CVE-2016-7053) ++ o Montgomery multiplication may produce incorrect results (CVE-2016-7055) ++ ++ Major changes between OpenSSL 1.1.0a and OpenSSL 1.1.0b [26 Sep 2016] ++ ++ o Fix Use After Free for large message sizes (CVE-2016-6309) ++ ++ Major changes between OpenSSL 1.1.0 and OpenSSL 1.1.0a [22 Sep 2016] ++ ++ o OCSP Status Request extension unbounded memory growth (CVE-2016-6304) ++ o SSL_peek() hang on empty record (CVE-2016-6305) ++ o Excessive allocation of memory in tls_get_message_header() ++ (CVE-2016-6307) ++ o Excessive allocation of memory in dtls1_preprocess_fragment() ++ (CVE-2016-6308) ++ ++ Major changes between OpenSSL 1.0.2h and OpenSSL 1.1.0 [25 Aug 2016] ++ ++ o Copyright text was shrunk to a boilerplate that points to the license ++ o "shared" builds are now the default when possible ++ o Added support for "pipelining" ++ o Added the AFALG engine ++ o New threading API implemented ++ o Support for ChaCha20 and Poly1305 added to libcrypto and libssl ++ o Support for extended master secret ++ o CCM ciphersuites ++ o Reworked test suite, now based on perl, Test::Harness and Test::More ++ o *Most* libcrypto and libssl public structures were made opaque, ++ including: ++ BIGNUM and associated types, EC_KEY and EC_KEY_METHOD, ++ DH and DH_METHOD, DSA and DSA_METHOD, RSA and RSA_METHOD, ++ BIO and BIO_METHOD, EVP_MD_CTX, EVP_MD, EVP_CIPHER_CTX, ++ EVP_CIPHER, EVP_PKEY and associated types, HMAC_CTX, ++ X509, X509_CRL, X509_OBJECT, X509_STORE_CTX, X509_STORE, ++ X509_LOOKUP, X509_LOOKUP_METHOD ++ o libssl internal structures made opaque ++ o SSLv2 support removed ++ o Kerberos ciphersuite support removed ++ o RC4 removed from DEFAULT ciphersuites in libssl ++ o 40 and 56 bit cipher support removed from libssl ++ o All public header files moved to include/openssl, no more symlinking ++ o SSL/TLS state machine, version negotiation and record layer rewritten ++ o EC revision: now operations use new EC_KEY_METHOD. ++ o Support for OCB mode added to libcrypto ++ o Support for asynchronous crypto operations added to libcrypto and libssl ++ o Deprecated interfaces can now be disabled at build time either ++ relative to the latest release via the "no-deprecated" Configure ++ argument, or via the "--api=1.1.0|1.0.0|0.9.8" option. ++ o Application software can be compiled with -DOPENSSL_API_COMPAT=version ++ to ensure that features deprecated in that version are not exposed. ++ o Support for RFC6698/RFC7671 DANE TLSA peer authentication ++ o Change of Configure to use --prefix as the main installation ++ directory location rather than --openssldir. The latter becomes ++ the directory for certs, private key and openssl.cnf exclusively. ++ o Reworked BIO networking library, with full support for IPv6. ++ o New "unified" build system ++ o New security levels ++ o Support for scrypt algorithm ++ o Support for X25519 ++ o Extended SSL_CONF support using configuration files ++ o KDF algorithm support. Implement TLS PRF as a KDF. ++ o Support for Certificate Transparency ++ o HKDF support. ++ ++ Major changes between OpenSSL 1.0.2g and OpenSSL 1.0.2h [3 May 2016] ++ ++ o Prevent padding oracle in AES-NI CBC MAC check (CVE-2016-2107) ++ o Fix EVP_EncodeUpdate overflow (CVE-2016-2105) ++ o Fix EVP_EncryptUpdate overflow (CVE-2016-2106) ++ o Prevent ASN.1 BIO excessive memory allocation (CVE-2016-2109) ++ o EBCDIC overread (CVE-2016-2176) ++ o Modify behavior of ALPN to invoke callback after SNI/servername ++ callback, such that updates to the SSL_CTX affect ALPN. ++ o Remove LOW from the DEFAULT cipher list. This removes singles DES from ++ the default. ++ o Only remove the SSLv2 methods with the no-ssl2-method option. ++ ++ Major changes between OpenSSL 1.0.2f and OpenSSL 1.0.2g [1 Mar 2016] ++ ++ o Disable weak ciphers in SSLv3 and up in default builds of OpenSSL. ++ o Disable SSLv2 default build, default negotiation and weak ciphers ++ (CVE-2016-0800) ++ o Fix a double-free in DSA code (CVE-2016-0705) ++ o Disable SRP fake user seed to address a server memory leak ++ (CVE-2016-0798) ++ o Fix BN_hex2bn/BN_dec2bn NULL pointer deref/heap corruption ++ (CVE-2016-0797) ++ o Fix memory issues in BIO_*printf functions (CVE-2016-0799) ++ o Fix side channel attack on modular exponentiation (CVE-2016-0702) ++ ++ Major changes between OpenSSL 1.0.2e and OpenSSL 1.0.2f [28 Jan 2016] ++ ++ o DH small subgroups (CVE-2016-0701) ++ o SSLv2 doesn't block disabled ciphers (CVE-2015-3197) ++ ++ Major changes between OpenSSL 1.0.2d and OpenSSL 1.0.2e [3 Dec 2015] ++ ++ o BN_mod_exp may produce incorrect results on x86_64 (CVE-2015-3193) ++ o Certificate verify crash with missing PSS parameter (CVE-2015-3194) ++ o X509_ATTRIBUTE memory leak (CVE-2015-3195) ++ o Rewrite EVP_DecodeUpdate (base64 decoding) to fix several bugs ++ o In DSA_generate_parameters_ex, if the provided seed is too short, ++ return an error ++ ++ Major changes between OpenSSL 1.0.2c and OpenSSL 1.0.2d [9 Jul 2015] ++ ++ o Alternate chains certificate forgery (CVE-2015-1793) ++ o Race condition handling PSK identify hint (CVE-2015-3196) ++ ++ Major changes between OpenSSL 1.0.2b and OpenSSL 1.0.2c [12 Jun 2015] ++ ++ o Fix HMAC ABI incompatibility ++ ++ Major changes between OpenSSL 1.0.2a and OpenSSL 1.0.2b [11 Jun 2015] ++ ++ o Malformed ECParameters causes infinite loop (CVE-2015-1788) ++ o Exploitable out-of-bounds read in X509_cmp_time (CVE-2015-1789) ++ o PKCS7 crash with missing EnvelopedContent (CVE-2015-1790) ++ o CMS verify infinite loop with unknown hash function (CVE-2015-1792) ++ o Race condition handling NewSessionTicket (CVE-2015-1791) ++ ++ Major changes between OpenSSL 1.0.2 and OpenSSL 1.0.2a [19 Mar 2015] ++ ++ o OpenSSL 1.0.2 ClientHello sigalgs DoS fix (CVE-2015-0291) ++ o Multiblock corrupted pointer fix (CVE-2015-0290) ++ o Segmentation fault in DTLSv1_listen fix (CVE-2015-0207) ++ o Segmentation fault in ASN1_TYPE_cmp fix (CVE-2015-0286) ++ o Segmentation fault for invalid PSS parameters fix (CVE-2015-0208) ++ o ASN.1 structure reuse memory corruption fix (CVE-2015-0287) ++ o PKCS7 NULL pointer dereferences fix (CVE-2015-0289) ++ o DoS via reachable assert in SSLv2 servers fix (CVE-2015-0293) ++ o Empty CKE with client auth and DHE fix (CVE-2015-1787) ++ o Handshake with unseeded PRNG fix (CVE-2015-0285) ++ o Use After Free following d2i_ECPrivatekey error fix (CVE-2015-0209) ++ o X509_to_X509_REQ NULL pointer deref fix (CVE-2015-0288) ++ o Removed the export ciphers from the DEFAULT ciphers ++ ++ Major changes between OpenSSL 1.0.1l and OpenSSL 1.0.2 [22 Jan 2015]: ++ ++ o Suite B support for TLS 1.2 and DTLS 1.2 ++ o Support for DTLS 1.2 ++ o TLS automatic EC curve selection. ++ o API to set TLS supported signature algorithms and curves ++ o SSL_CONF configuration API. ++ o TLS Brainpool support. ++ o ALPN support. ++ o CMS support for RSA-PSS, RSA-OAEP, ECDH and X9.42 DH. ++ ++ Major changes between OpenSSL 1.0.1k and OpenSSL 1.0.1l [15 Jan 2015] ++ ++ o Build fixes for the Windows and OpenVMS platforms ++ ++ Major changes between OpenSSL 1.0.1j and OpenSSL 1.0.1k [8 Jan 2015] ++ ++ o Fix for CVE-2014-3571 ++ o Fix for CVE-2015-0206 ++ o Fix for CVE-2014-3569 ++ o Fix for CVE-2014-3572 ++ o Fix for CVE-2015-0204 ++ o Fix for CVE-2015-0205 ++ o Fix for CVE-2014-8275 ++ o Fix for CVE-2014-3570 ++ ++ Major changes between OpenSSL 1.0.1i and OpenSSL 1.0.1j [15 Oct 2014] ++ ++ o Fix for CVE-2014-3513 ++ o Fix for CVE-2014-3567 ++ o Mitigation for CVE-2014-3566 (SSL protocol vulnerability) ++ o Fix for CVE-2014-3568 ++ ++ Major changes between OpenSSL 1.0.1h and OpenSSL 1.0.1i [6 Aug 2014] ++ ++ o Fix for CVE-2014-3512 ++ o Fix for CVE-2014-3511 ++ o Fix for CVE-2014-3510 ++ o Fix for CVE-2014-3507 ++ o Fix for CVE-2014-3506 ++ o Fix for CVE-2014-3505 ++ o Fix for CVE-2014-3509 ++ o Fix for CVE-2014-5139 ++ o Fix for CVE-2014-3508 ++ ++ Major changes between OpenSSL 1.0.1g and OpenSSL 1.0.1h [5 Jun 2014] ++ ++ o Fix for CVE-2014-0224 ++ o Fix for CVE-2014-0221 ++ o Fix for CVE-2014-0198 ++ o Fix for CVE-2014-0195 ++ o Fix for CVE-2014-3470 ++ o Fix for CVE-2010-5298 ++ ++ Major changes between OpenSSL 1.0.1f and OpenSSL 1.0.1g [7 Apr 2014] ++ ++ o Fix for CVE-2014-0160 ++ o Add TLS padding extension workaround for broken servers. ++ o Fix for CVE-2014-0076 ++ ++ Major changes between OpenSSL 1.0.1e and OpenSSL 1.0.1f [6 Jan 2014] ++ ++ o Don't include gmt_unix_time in TLS server and client random values ++ o Fix for TLS record tampering bug CVE-2013-4353 ++ o Fix for TLS version checking bug CVE-2013-6449 ++ o Fix for DTLS retransmission bug CVE-2013-6450 ++ ++ Major changes between OpenSSL 1.0.1d and OpenSSL 1.0.1e [11 Feb 2013]: ++ ++ o Corrected fix for CVE-2013-0169 ++ ++ Major changes between OpenSSL 1.0.1c and OpenSSL 1.0.1d [4 Feb 2013]: ++ ++ o Fix renegotiation in TLS 1.1, 1.2 by using the correct TLS version. ++ o Include the fips configuration module. ++ o Fix OCSP bad key DoS attack CVE-2013-0166 ++ o Fix for SSL/TLS/DTLS CBC plaintext recovery attack CVE-2013-0169 ++ o Fix for TLS AESNI record handling flaw CVE-2012-2686 ++ ++ Major changes between OpenSSL 1.0.1b and OpenSSL 1.0.1c [10 May 2012]: ++ ++ o Fix TLS/DTLS record length checking bug CVE-2012-2333 ++ o Don't attempt to use non-FIPS composite ciphers in FIPS mode. ++ ++ Major changes between OpenSSL 1.0.1a and OpenSSL 1.0.1b [26 Apr 2012]: ++ ++ o Fix compilation error on non-x86 platforms. ++ o Make FIPS capable OpenSSL ciphers work in non-FIPS mode. ++ o Fix SSL_OP_NO_TLSv1_1 clash with SSL_OP_ALL in OpenSSL 1.0.0 ++ ++ Major changes between OpenSSL 1.0.1 and OpenSSL 1.0.1a [19 Apr 2012]: ++ ++ o Fix for ASN1 overflow bug CVE-2012-2110 ++ o Workarounds for some servers that hang on long client hellos. ++ o Fix SEGV in AES code. ++ ++ Major changes between OpenSSL 1.0.0h and OpenSSL 1.0.1 [14 Mar 2012]: ++ ++ o TLS/DTLS heartbeat support. ++ o SCTP support. ++ o RFC 5705 TLS key material exporter. ++ o RFC 5764 DTLS-SRTP negotiation. ++ o Next Protocol Negotiation. ++ o PSS signatures in certificates, requests and CRLs. ++ o Support for password based recipient info for CMS. ++ o Support TLS v1.2 and TLS v1.1. ++ o Preliminary FIPS capability for unvalidated 2.0 FIPS module. ++ o SRP support. ++ ++ Major changes between OpenSSL 1.0.0g and OpenSSL 1.0.0h [12 Mar 2012]: ++ ++ o Fix for CMS/PKCS#7 MMA CVE-2012-0884 ++ o Corrected fix for CVE-2011-4619 ++ o Various DTLS fixes. ++ ++ Major changes between OpenSSL 1.0.0f and OpenSSL 1.0.0g [18 Jan 2012]: ++ ++ o Fix for DTLS DoS issue CVE-2012-0050 ++ ++ Major changes between OpenSSL 1.0.0e and OpenSSL 1.0.0f [4 Jan 2012]: ++ ++ o Fix for DTLS plaintext recovery attack CVE-2011-4108 ++ o Clear block padding bytes of SSL 3.0 records CVE-2011-4576 ++ o Only allow one SGC handshake restart for SSL/TLS CVE-2011-4619 ++ o Check parameters are not NULL in GOST ENGINE CVE-2012-0027 ++ o Check for malformed RFC3779 data CVE-2011-4577 ++ ++ Major changes between OpenSSL 1.0.0d and OpenSSL 1.0.0e [6 Sep 2011]: ++ ++ o Fix for CRL vulnerability issue CVE-2011-3207 ++ o Fix for ECDH crashes CVE-2011-3210 ++ o Protection against EC timing attacks. ++ o Support ECDH ciphersuites for certificates using SHA2 algorithms. ++ o Various DTLS fixes. ++ ++ Major changes between OpenSSL 1.0.0c and OpenSSL 1.0.0d [8 Feb 2011]: ++ ++ o Fix for security issue CVE-2011-0014 ++ ++ Major changes between OpenSSL 1.0.0b and OpenSSL 1.0.0c [2 Dec 2010]: ++ ++ o Fix for security issue CVE-2010-4180 ++ o Fix for CVE-2010-4252 ++ o Fix mishandling of absent EC point format extension. ++ o Fix various platform compilation issues. ++ o Corrected fix for security issue CVE-2010-3864. ++ ++ Major changes between OpenSSL 1.0.0a and OpenSSL 1.0.0b [16 Nov 2010]: ++ ++ o Fix for security issue CVE-2010-3864. ++ o Fix for CVE-2010-2939 ++ o Fix WIN32 build system for GOST ENGINE. ++ ++ Major changes between OpenSSL 1.0.0 and OpenSSL 1.0.0a [1 Jun 2010]: ++ ++ o Fix for security issue CVE-2010-1633. ++ o GOST MAC and CFB fixes. ++ ++ Major changes between OpenSSL 0.9.8n and OpenSSL 1.0.0 [29 Mar 2010]: ++ ++ o RFC3280 path validation: sufficient to process PKITS tests. ++ o Integrated support for PVK files and keyblobs. ++ o Change default private key format to PKCS#8. ++ o CMS support: able to process all examples in RFC4134 ++ o Streaming ASN1 encode support for PKCS#7 and CMS. ++ o Multiple signer and signer add support for PKCS#7 and CMS. ++ o ASN1 printing support. ++ o Whirlpool hash algorithm added. ++ o RFC3161 time stamp support. ++ o New generalised public key API supporting ENGINE based algorithms. ++ o New generalised public key API utilities. ++ o New ENGINE supporting GOST algorithms. ++ o SSL/TLS GOST ciphersuite support. ++ o PKCS#7 and CMS GOST support. ++ o RFC4279 PSK ciphersuite support. ++ o Supported points format extension for ECC ciphersuites. ++ o ecdsa-with-SHA224/256/384/512 signature types. ++ o dsa-with-SHA224 and dsa-with-SHA256 signature types. ++ o Opaque PRF Input TLS extension support. ++ o Updated time routines to avoid OS limitations. ++ ++ Major changes between OpenSSL 0.9.8m and OpenSSL 0.9.8n [24 Mar 2010]: ++ ++ o CFB cipher definition fixes. ++ o Fix security issues CVE-2010-0740 and CVE-2010-0433. ++ ++ Major changes between OpenSSL 0.9.8l and OpenSSL 0.9.8m [25 Feb 2010]: ++ ++ o Cipher definition fixes. ++ o Workaround for slow RAND_poll() on some WIN32 versions. ++ o Remove MD2 from algorithm tables. ++ o SPKAC handling fixes. ++ o Support for RFC5746 TLS renegotiation extension. ++ o Compression memory leak fixed. ++ o Compression session resumption fixed. ++ o Ticket and SNI coexistence fixes. ++ o Many fixes to DTLS handling. ++ ++ Major changes between OpenSSL 0.9.8k and OpenSSL 0.9.8l [5 Nov 2009]: ++ ++ o Temporary work around for CVE-2009-3555: disable renegotiation. ++ ++ Major changes between OpenSSL 0.9.8j and OpenSSL 0.9.8k [25 Mar 2009]: ++ ++ o Fix various build issues. ++ o Fix security issues (CVE-2009-0590, CVE-2009-0591, CVE-2009-0789) ++ ++ Major changes between OpenSSL 0.9.8i and OpenSSL 0.9.8j [7 Jan 2009]: ++ ++ o Fix security issue (CVE-2008-5077) ++ o Merge FIPS 140-2 branch code. ++ ++ Major changes between OpenSSL 0.9.8g and OpenSSL 0.9.8h [28 May 2008]: ++ ++ o CryptoAPI ENGINE support. ++ o Various precautionary measures. ++ o Fix for bugs affecting certificate request creation. ++ o Support for local machine keyset attribute in PKCS#12 files. ++ ++ Major changes between OpenSSL 0.9.8f and OpenSSL 0.9.8g [19 Oct 2007]: ++ ++ o Backport of CMS functionality to 0.9.8. ++ o Fixes for bugs introduced with 0.9.8f. ++ ++ Major changes between OpenSSL 0.9.8e and OpenSSL 0.9.8f [11 Oct 2007]: ++ ++ o Add gcc 4.2 support. ++ o Add support for AES and SSE2 assembly language optimization ++ for VC++ build. ++ o Support for RFC4507bis and server name extensions if explicitly ++ selected at compile time. ++ o DTLS improvements. ++ o RFC4507bis support. ++ o TLS Extensions support. ++ ++ Major changes between OpenSSL 0.9.8d and OpenSSL 0.9.8e [23 Feb 2007]: ++ ++ o Various ciphersuite selection fixes. ++ o RFC3779 support. ++ ++ Major changes between OpenSSL 0.9.8c and OpenSSL 0.9.8d [28 Sep 2006]: ++ ++ o Introduce limits to prevent malicious key DoS (CVE-2006-2940) ++ o Fix security issues (CVE-2006-2937, CVE-2006-3737, CVE-2006-4343) ++ o Changes to ciphersuite selection algorithm ++ ++ Major changes between OpenSSL 0.9.8b and OpenSSL 0.9.8c [5 Sep 2006]: ++ ++ o Fix Daniel Bleichenbacher forged signature attack, CVE-2006-4339 ++ o New cipher Camellia ++ ++ Major changes between OpenSSL 0.9.8a and OpenSSL 0.9.8b [4 May 2006]: ++ ++ o Cipher string fixes. ++ o Fixes for VC++ 2005. ++ o Updated ECC cipher suite support. ++ o New functions EVP_CIPHER_CTX_new() and EVP_CIPHER_CTX_free(). ++ o Zlib compression usage fixes. ++ o Built in dynamic engine compilation support on Win32. ++ o Fixes auto dynamic engine loading in Win32. ++ ++ Major changes between OpenSSL 0.9.8 and OpenSSL 0.9.8a [11 Oct 2005]: ++ ++ o Fix potential SSL 2.0 rollback, CVE-2005-2969 ++ o Extended Windows CE support ++ ++ Major changes between OpenSSL 0.9.7g and OpenSSL 0.9.8 [5 Jul 2005]: ++ ++ o Major work on the BIGNUM library for higher efficiency and to ++ make operations more streamlined and less contradictory. This ++ is the result of a major audit of the BIGNUM library. ++ o Addition of BIGNUM functions for fields GF(2^m) and NIST ++ curves, to support the Elliptic Crypto functions. ++ o Major work on Elliptic Crypto; ECDH and ECDSA added, including ++ the use through EVP, X509 and ENGINE. ++ o New ASN.1 mini-compiler that's usable through the OpenSSL ++ configuration file. ++ o Added support for ASN.1 indefinite length constructed encoding. ++ o New PKCS#12 'medium level' API to manipulate PKCS#12 files. ++ o Complete rework of shared library construction and linking ++ programs with shared or static libraries, through a separate ++ Makefile.shared. ++ o Rework of the passing of parameters from one Makefile to another. ++ o Changed ENGINE framework to load dynamic engine modules ++ automatically from specifically given directories. ++ o New structure and ASN.1 functions for CertificatePair. ++ o Changed the ZLIB compression method to be stateful. ++ o Changed the key-generation and primality testing "progress" ++ mechanism to take a structure that contains the ticker ++ function and an argument. ++ o New engine module: GMP (performs private key exponentiation). ++ o New engine module: VIA PadLOck ACE extension in VIA C3 ++ Nehemiah processors. ++ o Added support for IPv6 addresses in certificate extensions. ++ See RFC 1884, section 2.2. ++ o Added support for certificate policy mappings, policy ++ constraints and name constraints. ++ o Added support for multi-valued AVAs in the OpenSSL ++ configuration file. ++ o Added support for multiple certificates with the same subject ++ in the 'openssl ca' index file. ++ o Make it possible to create self-signed certificates using ++ 'openssl ca -selfsign'. ++ o Make it possible to generate a serial number file with ++ 'openssl ca -create_serial'. ++ o New binary search functions with extended functionality. ++ o New BUF functions. ++ o New STORE structure and library to provide an interface to all ++ sorts of data repositories. Supports storage of public and ++ private keys, certificates, CRLs, numbers and arbitrary blobs. ++ This library is unfortunately unfinished and unused within ++ OpenSSL. ++ o New control functions for the error stack. ++ o Changed the PKCS#7 library to support one-pass S/MIME ++ processing. ++ o Added the possibility to compile without old deprecated ++ functionality with the OPENSSL_NO_DEPRECATED macro or the ++ 'no-deprecated' argument to the config and Configure scripts. ++ o Constification of all ASN.1 conversion functions, and other ++ affected functions. ++ o Improved platform support for PowerPC. ++ o New FIPS 180-2 algorithms (SHA-224, -256, -384 and -512). ++ o New X509_VERIFY_PARAM structure to support parametrisation ++ of X.509 path validation. ++ o Major overhaul of RC4 performance on Intel P4, IA-64 and ++ AMD64. ++ o Changed the Configure script to have some algorithms disabled ++ by default. Those can be explicitly enabled with the new ++ argument form 'enable-xxx'. ++ o Change the default digest in 'openssl' commands from MD5 to ++ SHA-1. ++ o Added support for DTLS. ++ o New BIGNUM blinding. ++ o Added support for the RSA-PSS encryption scheme ++ o Added support for the RSA X.931 padding. ++ o Added support for BSD sockets on NetWare. ++ o Added support for files larger than 2GB. ++ o Added initial support for Win64. ++ o Added alternate pkg-config files. ++ ++ Major changes between OpenSSL 0.9.7l and OpenSSL 0.9.7m [23 Feb 2007]: ++ ++ o FIPS 1.1.1 module linking. ++ o Various ciphersuite selection fixes. ++ ++ Major changes between OpenSSL 0.9.7k and OpenSSL 0.9.7l [28 Sep 2006]: ++ ++ o Introduce limits to prevent malicious key DoS (CVE-2006-2940) ++ o Fix security issues (CVE-2006-2937, CVE-2006-3737, CVE-2006-4343) ++ ++ Major changes between OpenSSL 0.9.7j and OpenSSL 0.9.7k [5 Sep 2006]: ++ ++ o Fix Daniel Bleichenbacher forged signature attack, CVE-2006-4339 ++ ++ Major changes between OpenSSL 0.9.7i and OpenSSL 0.9.7j [4 May 2006]: ++ ++ o Visual C++ 2005 fixes. ++ o Update Windows build system for FIPS. ++ ++ Major changes between OpenSSL 0.9.7h and OpenSSL 0.9.7i [14 Oct 2005]: ++ ++ o Give EVP_MAX_MD_SIZE it's old value, except for a FIPS build. ++ ++ Major changes between OpenSSL 0.9.7g and OpenSSL 0.9.7h [11 Oct 2005]: ++ ++ o Fix SSL 2.0 Rollback, CVE-2005-2969 ++ o Allow use of fixed-length exponent on DSA signing ++ o Default fixed-window RSA, DSA, DH private-key operations ++ ++ Major changes between OpenSSL 0.9.7f and OpenSSL 0.9.7g [11 Apr 2005]: ++ ++ o More compilation issues fixed. ++ o Adaptation to more modern Kerberos API. ++ o Enhanced or corrected configuration for Solaris64, Mingw and Cygwin. ++ o Enhanced x86_64 assembler BIGNUM module. ++ o More constification. ++ o Added processing of proxy certificates (RFC 3820). ++ ++ Major changes between OpenSSL 0.9.7e and OpenSSL 0.9.7f [22 Mar 2005]: ++ ++ o Several compilation issues fixed. ++ o Many memory allocation failure checks added. ++ o Improved comparison of X509 Name type. ++ o Mandatory basic checks on certificates. ++ o Performance improvements. ++ ++ Major changes between OpenSSL 0.9.7d and OpenSSL 0.9.7e [25 Oct 2004]: ++ ++ o Fix race condition in CRL checking code. ++ o Fixes to PKCS#7 (S/MIME) code. ++ ++ Major changes between OpenSSL 0.9.7c and OpenSSL 0.9.7d [17 Mar 2004]: ++ ++ o Security: Fix Kerberos ciphersuite SSL/TLS handshaking bug ++ o Security: Fix null-pointer assignment in do_change_cipher_spec() ++ o Allow multiple active certificates with same subject in CA index ++ o Multiple X509 verification fixes ++ o Speed up HMAC and other operations ++ ++ Major changes between OpenSSL 0.9.7b and OpenSSL 0.9.7c [30 Sep 2003]: ++ ++ o Security: fix various ASN1 parsing bugs. ++ o New -ignore_err option to OCSP utility. ++ o Various interop and bug fixes in S/MIME code. ++ o SSL/TLS protocol fix for unrequested client certificates. ++ ++ Major changes between OpenSSL 0.9.7a and OpenSSL 0.9.7b [10 Apr 2003]: ++ ++ o Security: counter the Klima-Pokorny-Rosa extension of ++ Bleichbacher's attack ++ o Security: make RSA blinding default. ++ o Configuration: Irix fixes, AIX fixes, better mingw support. ++ o Support for new platforms: linux-ia64-ecc. ++ o Build: shared library support fixes. ++ o ASN.1: treat domainComponent correctly. ++ o Documentation: fixes and additions. ++ ++ Major changes between OpenSSL 0.9.7 and OpenSSL 0.9.7a [19 Feb 2003]: ++ ++ o Security: Important security related bugfixes. ++ o Enhanced compatibility with MIT Kerberos. ++ o Can be built without the ENGINE framework. ++ o IA32 assembler enhancements. ++ o Support for new platforms: FreeBSD/IA64 and FreeBSD/Sparc64. ++ o Configuration: the no-err option now works properly. ++ o SSL/TLS: now handles manual certificate chain building. ++ o SSL/TLS: certain session ID malfunctions corrected. ++ ++ Major changes between OpenSSL 0.9.6 and OpenSSL 0.9.7 [30 Dec 2002]: ++ ++ o New library section OCSP. ++ o Complete rewrite of ASN1 code. ++ o CRL checking in verify code and openssl utility. ++ o Extension copying in 'ca' utility. ++ o Flexible display options in 'ca' utility. ++ o Provisional support for international characters with UTF8. ++ o Support for external crypto devices ('engine') is no longer ++ a separate distribution. ++ o New elliptic curve library section. ++ o New AES (Rijndael) library section. ++ o Support for new platforms: Windows CE, Tandem OSS, A/UX, AIX 64-bit, ++ Linux x86_64, Linux 64-bit on Sparc v9 ++ o Extended support for some platforms: VxWorks ++ o Enhanced support for shared libraries. ++ o Now only builds PIC code when shared library support is requested. ++ o Support for pkg-config. ++ o Lots of new manuals. ++ o Makes symbolic links to or copies of manuals to cover all described ++ functions. ++ o Change DES API to clean up the namespace (some applications link also ++ against libdes providing similar functions having the same name). ++ Provide macros for backward compatibility (will be removed in the ++ future). ++ o Unify handling of cryptographic algorithms (software and engine) ++ to be available via EVP routines for asymmetric and symmetric ciphers. ++ o NCONF: new configuration handling routines. ++ o Change API to use more 'const' modifiers to improve error checking ++ and help optimizers. ++ o Finally remove references to RSAref. ++ o Reworked parts of the BIGNUM code. ++ o Support for new engines: Broadcom ubsec, Accelerated Encryption ++ Processing, IBM 4758. ++ o A few new engines added in the demos area. ++ o Extended and corrected OID (object identifier) table. ++ o PRNG: query at more locations for a random device, automatic query for ++ EGD style random sources at several locations. ++ o SSL/TLS: allow optional cipher choice according to server's preference. ++ o SSL/TLS: allow server to explicitly set new session ids. ++ o SSL/TLS: support Kerberos cipher suites (RFC2712). ++ Only supports MIT Kerberos for now. ++ o SSL/TLS: allow more precise control of renegotiations and sessions. ++ o SSL/TLS: add callback to retrieve SSL/TLS messages. ++ o SSL/TLS: support AES cipher suites (RFC3268). ++ ++ Major changes between OpenSSL 0.9.6j and OpenSSL 0.9.6k [30 Sep 2003]: ++ ++ o Security: fix various ASN1 parsing bugs. ++ o SSL/TLS protocol fix for unrequested client certificates. ++ ++ Major changes between OpenSSL 0.9.6i and OpenSSL 0.9.6j [10 Apr 2003]: ++ ++ o Security: counter the Klima-Pokorny-Rosa extension of ++ Bleichbacher's attack ++ o Security: make RSA blinding default. ++ o Build: shared library support fixes. ++ ++ Major changes between OpenSSL 0.9.6h and OpenSSL 0.9.6i [19 Feb 2003]: ++ ++ o Important security related bugfixes. ++ ++ Major changes between OpenSSL 0.9.6g and OpenSSL 0.9.6h [5 Dec 2002]: ++ ++ o New configuration targets for Tandem OSS and A/UX. ++ o New OIDs for Microsoft attributes. ++ o Better handling of SSL session caching. ++ o Better comparison of distinguished names. ++ o Better handling of shared libraries in a mixed GNU/non-GNU environment. ++ o Support assembler code with Borland C. ++ o Fixes for length problems. ++ o Fixes for uninitialised variables. ++ o Fixes for memory leaks, some unusual crashes and some race conditions. ++ o Fixes for smaller building problems. ++ o Updates of manuals, FAQ and other instructive documents. ++ ++ Major changes between OpenSSL 0.9.6f and OpenSSL 0.9.6g [9 Aug 2002]: ++ ++ o Important building fixes on Unix. ++ ++ Major changes between OpenSSL 0.9.6e and OpenSSL 0.9.6f [8 Aug 2002]: ++ ++ o Various important bugfixes. ++ ++ Major changes between OpenSSL 0.9.6d and OpenSSL 0.9.6e [30 Jul 2002]: ++ ++ o Important security related bugfixes. ++ o Various SSL/TLS library bugfixes. ++ ++ Major changes between OpenSSL 0.9.6c and OpenSSL 0.9.6d [9 May 2002]: ++ ++ o Various SSL/TLS library bugfixes. ++ o Fix DH parameter generation for 'non-standard' generators. ++ ++ Major changes between OpenSSL 0.9.6b and OpenSSL 0.9.6c [21 Dec 2001]: ++ ++ o Various SSL/TLS library bugfixes. ++ o BIGNUM library fixes. ++ o RSA OAEP and random number generation fixes. ++ o Object identifiers corrected and added. ++ o Add assembler BN routines for IA64. ++ o Add support for OS/390 Unix, UnixWare with gcc, OpenUNIX 8, ++ MIPS Linux; shared library support for Irix, HP-UX. ++ o Add crypto accelerator support for AEP, Baltimore SureWare, ++ Broadcom and Cryptographic Appliance's keyserver ++ [in 0.9.6c-engine release]. ++ ++ Major changes between OpenSSL 0.9.6a and OpenSSL 0.9.6b [9 Jul 2001]: ++ ++ o Security fix: PRNG improvements. ++ o Security fix: RSA OAEP check. ++ o Security fix: Reinsert and fix countermeasure to Bleichbacher's ++ attack. ++ o MIPS bug fix in BIGNUM. ++ o Bug fix in "openssl enc". ++ o Bug fix in X.509 printing routine. ++ o Bug fix in DSA verification routine and DSA S/MIME verification. ++ o Bug fix to make PRNG thread-safe. ++ o Bug fix in RAND_file_name(). ++ o Bug fix in compatibility mode trust settings. ++ o Bug fix in blowfish EVP. ++ o Increase default size for BIO buffering filter. ++ o Compatibility fixes in some scripts. ++ ++ Major changes between OpenSSL 0.9.6 and OpenSSL 0.9.6a [5 Apr 2001]: ++ ++ o Security fix: change behavior of OpenSSL to avoid using ++ environment variables when running as root. ++ o Security fix: check the result of RSA-CRT to reduce the ++ possibility of deducing the private key from an incorrectly ++ calculated signature. ++ o Security fix: prevent Bleichenbacher's DSA attack. ++ o Security fix: Zero the premaster secret after deriving the ++ master secret in DH ciphersuites. ++ o Reimplement SSL_peek(), which had various problems. ++ o Compatibility fix: the function des_encrypt() renamed to ++ des_encrypt1() to avoid clashes with some Unixen libc. ++ o Bug fixes for Win32, HP/UX and Irix. ++ o Bug fixes in BIGNUM, SSL, PKCS#7, PKCS#12, X.509, CONF and ++ memory checking routines. ++ o Bug fixes for RSA operations in threaded environments. ++ o Bug fixes in misc. openssl applications. ++ o Remove a few potential memory leaks. ++ o Add tighter checks of BIGNUM routines. ++ o Shared library support has been reworked for generality. ++ o More documentation. ++ o New function BN_rand_range(). ++ o Add "-rand" option to openssl s_client and s_server. ++ ++ Major changes between OpenSSL 0.9.5a and OpenSSL 0.9.6 [10 Oct 2000]: ++ ++ o Some documentation for BIO and SSL libraries. ++ o Enhanced chain verification using key identifiers. ++ o New sign and verify options to 'dgst' application. ++ o Support for DER and PEM encoded messages in 'smime' application. ++ o New 'rsautl' application, low level RSA utility. ++ o MD4 now included. ++ o Bugfix for SSL rollback padding check. ++ o Support for external crypto devices [1]. ++ o Enhanced EVP interface. ++ ++ [1] The support for external crypto devices is currently a separate ++ distribution. See the file README.ENGINE. ++ ++ Major changes between OpenSSL 0.9.5 and OpenSSL 0.9.5a [1 Apr 2000]: ++ ++ o Bug fixes for Win32, SuSE Linux, NeXTSTEP and FreeBSD 2.2.8 ++ o Shared library support for HPUX and Solaris-gcc ++ o Support of Linux/IA64 ++ o Assembler support for Mingw32 ++ o New 'rand' application ++ o New way to check for existence of algorithms from scripts ++ ++ Major changes between OpenSSL 0.9.4 and OpenSSL 0.9.5 [25 May 2000]: ++ ++ o S/MIME support in new 'smime' command ++ o Documentation for the OpenSSL command line application ++ o Automation of 'req' application ++ o Fixes to make s_client, s_server work under Windows ++ o Support for multiple fieldnames in SPKACs ++ o New SPKAC command line utilty and associated library functions ++ o Options to allow passwords to be obtained from various sources ++ o New public key PEM format and options to handle it ++ o Many other fixes and enhancements to command line utilities ++ o Usable certificate chain verification ++ o Certificate purpose checking ++ o Certificate trust settings ++ o Support of authority information access extension ++ o Extensions in certificate requests ++ o Simplified X509 name and attribute routines ++ o Initial (incomplete) support for international character sets ++ o New DH_METHOD, DSA_METHOD and enhanced RSA_METHOD ++ o Read only memory BIOs and simplified creation function ++ o TLS/SSL protocol bugfixes: Accept TLS 'client hello' in SSL 3.0 ++ record; allow fragmentation and interleaving of handshake and other ++ data ++ o TLS/SSL code now "tolerates" MS SGC ++ o Work around for Netscape client certificate hang bug ++ o RSA_NULL option that removes RSA patent code but keeps other ++ RSA functionality ++ o Memory leak detection now allows applications to add extra information ++ via a per-thread stack ++ o PRNG robustness improved ++ o EGD support ++ o BIGNUM library bug fixes ++ o Faster DSA parameter generation ++ o Enhanced support for Alpha Linux ++ o Experimental MacOS support ++ ++ Major changes between OpenSSL 0.9.3 and OpenSSL 0.9.4 [9 Aug 1999]: ++ ++ o Transparent support for PKCS#8 format private keys: these are used ++ by several software packages and are more secure than the standard ++ form ++ o PKCS#5 v2.0 implementation ++ o Password callbacks have a new void * argument for application data ++ o Avoid various memory leaks ++ o New pipe-like BIO that allows using the SSL library when actual I/O ++ must be handled by the application (BIO pair) ++ ++ Major changes between OpenSSL 0.9.2b and OpenSSL 0.9.3 [24 May 1999]: ++ o Lots of enhancements and cleanups to the Configuration mechanism ++ o RSA OEAP related fixes ++ o Added `openssl ca -revoke' option for revoking a certificate ++ o Source cleanups: const correctness, type-safe stacks and ASN.1 SETs ++ o Source tree cleanups: removed lots of obsolete files ++ o Thawte SXNet, certificate policies and CRL distribution points ++ extension support ++ o Preliminary (experimental) S/MIME support ++ o Support for ASN.1 UTF8String and VisibleString ++ o Full integration of PKCS#12 code ++ o Sparc assembler bignum implementation, optimized hash functions ++ o Option to disable selected ciphers ++ ++ Major changes between OpenSSL 0.9.1c and OpenSSL 0.9.2b [22 Mar 1999]: ++ o Fixed a security hole related to session resumption ++ o Fixed RSA encryption routines for the p < q case ++ o "ALL" in cipher lists now means "everything except NULL ciphers" ++ o Support for Triple-DES CBCM cipher ++ o Support of Optimal Asymmetric Encryption Padding (OAEP) for RSA ++ o First support for new TLSv1 ciphers ++ o Added a few new BIOs (syslog BIO, reliable BIO) ++ o Extended support for DSA certificate/keys. ++ o Extended support for Certificate Signing Requests (CSR) ++ o Initial support for X.509v3 extensions ++ o Extended support for compression inside the SSL record layer ++ o Overhauled Win32 builds ++ o Cleanups and fixes to the Big Number (BN) library ++ o Support for ASN.1 GeneralizedTime ++ o Splitted ASN.1 SETs from SEQUENCEs ++ o ASN1 and PEM support for Netscape Certificate Sequences ++ o Overhauled Perl interface ++ o Lots of source tree cleanups. ++ o Lots of memory leak fixes. ++ o Lots of bug fixes. ++ ++ Major changes between SSLeay 0.9.0b and OpenSSL 0.9.1c [23 Dec 1998]: ++ o Integration of the popular NO_RSA/NO_DSA patches ++ o Initial support for compression inside the SSL record layer ++ o Added BIO proxy and filtering functionality ++ o Extended Big Number (BN) library ++ o Added RIPE MD160 message digest ++ o Addeed support for RC2/64bit cipher ++ o Extended ASN.1 parser routines ++ o Adjustations of the source tree for CVS ++ o Support for various new platforms ++ +diff --git a/CryptoPkg/Library/OpensslLib/openssl/NOTES.DJGPP b/CryptoPkg/Library/OpensslLib/openssl/NOTES.DJGPP +new file mode 100644 +index 0000000..bbe63dc +--- /dev/null ++++ b/CryptoPkg/Library/OpensslLib/openssl/NOTES.DJGPP +@@ -0,0 +1,48 @@ ++ ++ ++ INSTALLATION ON THE DOS PLATFORM WITH DJGPP ++ ------------------------------------------- ++ ++ OpenSSL has been ported to DJGPP, a Unix look-alike 32-bit run-time ++ environment for 16-bit DOS, but only with long filename support. ++ If you wish to compile on native DOS with 8+3 filenames, you will ++ have to tweak the installation yourself, including renaming files ++ with illegal or duplicate names. ++ ++ You should have a full DJGPP environment installed, including the ++ latest versions of DJGPP, GCC, BINUTILS, BASH, etc. This package ++ requires that PERL and the PERL module Text::Template also be ++ installed (see NOTES.PERL). ++ ++ All of these can be obtained from the usual DJGPP mirror sites or ++ directly at "http://www.delorie.com/pub/djgpp". For help on which ++ files to download, see the DJGPP "ZIP PICKER" page at ++ "http://www.delorie.com/djgpp/zip-picker.html". You also need to have ++ the WATT-32 networking package installed before you try to compile ++ OpenSSL. This can be obtained from "http://www.watt-32.net/". ++ The Makefile assumes that the WATT-32 code is in the directory ++ specified by the environment variable WATT_ROOT. If you have watt-32 ++ in directory "watt32" under your main DJGPP directory, specify ++ WATT_ROOT="/dev/env/DJDIR/watt32". ++ ++ To compile OpenSSL, start your BASH shell, then configure for DJGPP by ++ running "./Configure" with appropriate arguments: ++ ++ ./Configure no-threads --prefix=/dev/env/DJDIR DJGPP ++ ++ And finally fire up "make". You may run out of DPMI selectors when ++ running in a DOS box under Windows. If so, just close the BASH ++ shell, go back to Windows, and restart BASH. Then run "make" again. ++ ++ RUN-TIME CAVEAT LECTOR ++ -------------- ++ ++ Quoting FAQ: ++ ++ "Cryptographic software needs a source of unpredictable data to work ++ correctly. Many open source operating systems provide a "randomness ++ device" (/dev/urandom or /dev/random) that serves this purpose." ++ ++ As of version 0.9.7f DJGPP port checks upon /dev/urandom$ for a 3rd ++ party "randomness" DOS driver. One such driver, NOISE.SYS, can be ++ obtained from "http://www.rahul.net/dkaufman/index.html". +diff --git a/CryptoPkg/Library/OpensslLib/openssl/NOTES.PERL b/CryptoPkg/Library/OpensslLib/openssl/NOTES.PERL +new file mode 100644 +index 0000000..46d585a +--- /dev/null ++++ b/CryptoPkg/Library/OpensslLib/openssl/NOTES.PERL +@@ -0,0 +1,119 @@ ++ TOC ++ === ++ ++ - Notes on Perl ++ - Notes on Perl on Windows ++ - Notes on Perl modules we use ++ - Notes on installing a perl module ++ ++ Notes on Perl ++ ------------- ++ ++ For our scripts, we rely quite a bit on Perl, and increasingly on ++ some core Perl modules. These Perl modules are part of the Perl ++ source, so if you build Perl on your own, you should be set. ++ ++ However, if you install Perl as binary packages, the outcome might ++ differ, and you may have to check that you do get the core modules ++ installed properly. We do not claim to know them all, but experience ++ has told us the following: ++ ++ - on Linux distributions based on Debian, the package 'perl' will ++ install the core Perl modules as well, so you will be fine. ++ - on Linux distributions based on RPMs, you will need to install ++ 'perl-core' rather than just 'perl'. ++ ++ You MUST have at least Perl version 5.10.0 installed. This minimum ++ requirement is due to our use of regexp backslash sequence \R among ++ other features that didn't exist in core Perl before that version. ++ ++ Notes on Perl on Windows ++ ------------------------ ++ ++ There are a number of build targets that can be viewed as "Windows". ++ Indeed, there are VC-* configs targeting VisualStudio C, as well as ++ MinGW and Cygwin. The key recommendation is to use "matching" Perl, ++ one that matches build environment. For example, if you will build ++ on Cygwin be sure to use the Cygwin package manager to install Perl. ++ For MSYS builds use the MSYS provided Perl. For VC-* builds we ++ recommend ActiveState Perl, available from ++ http://www.activestate.com/ActivePerl. ++ ++ Notes on Perl on VMS ++ -------------------- ++ ++ You will need to install Perl separately. One way to do so is to ++ download the source from http://perl.org/, unpacking it, reading ++ README.vms and follow the instructions. Another way is to download a ++ .PCSI file from http://www.vmsperl.com/ and install it using the ++ POLYCENTER install tool. ++ ++ Notes on Perl modules we use ++ ---------------------------- ++ ++ We make increasing use of Perl modules, and do our best to limit ++ ourselves to core Perl modules to keep the requirements down. There ++ are just a few exceptions: ++ ++ Test::More We require the minimum version to be 0.96, which ++ appeared in Perl 5.13.4, because that version was ++ the first to have all the features we're using. ++ This module is required for testing only! If you ++ don't plan on running the tests, you don't need to ++ bother with this one. ++ ++ Text::Template This module is not part of the core Perl modules. ++ As a matter of fact, the core Perl modules do not ++ include any templating module to date. ++ This module is absolutely needed, configuration ++ depends on it. ++ ++ To avoid unnecessary initial hurdles, we have bundled a copy of the ++ following modules in our source. They will work as fallbacks if ++ these modules aren't already installed on the system. ++ ++ Text::Template ++ ++ Notes on installing a perl module ++ --------------------------------- ++ ++ There are a number of ways to install a perl module. In all ++ descriptions below, Text::Template will server as an example. ++ ++ 1. for Linux users, the easiest is to install with the use of your ++ favorite package manager. Usually, all you need to do is search ++ for the module name and to install the package that comes up. ++ ++ On Debian based Linux distributions, it would go like this: ++ ++ $ apt-cache search Text::Template ++ ... ++ libtext-template-perl - perl module to process text templates ++ $ sudo apt-get install libtext-template-perl ++ ++ Perl modules in Debian based distributions use package names like ++ the name of the module in question, with "lib" prepended and ++ "-perl" appended. ++ ++ 2. Install using CPAN. This is very easy, but usually requires root ++ access: ++ ++ $ cpan -i Text::Template ++ ++ Note that this runs all the tests that the module to be installed ++ comes with. This is usually a smooth operation, but there are ++ platforms where a failure is indicated even though the actual tests ++ were successful. Should that happen, you can force an ++ installation regardless (that should be safe since you've already ++ seen the tests succeed!): ++ ++ $ cpan -f -i Text::Template ++ ++ Note: on VMS, you must quote any argument that contains upper case ++ characters, so the lines above would be: ++ ++ $ cpan -i "Text::Template" ++ ++ and: ++ ++ $ cpan -f -i "Text::Template" +diff --git a/CryptoPkg/Library/OpensslLib/openssl/NOTES.VMS b/CryptoPkg/Library/OpensslLib/openssl/NOTES.VMS +new file mode 100644 +index 0000000..3e9a57e +--- /dev/null ++++ b/CryptoPkg/Library/OpensslLib/openssl/NOTES.VMS +@@ -0,0 +1,81 @@ ++ ++ NOTES FOR THE OPENVMS PLATFORM ++ ============================== ++ ++ Requirement details ++ ------------------- ++ ++ In addition to the requirements and instructions listed in INSTALL, ++ this are required as well: ++ ++ * At least ODS-5 disk organization for source and build. ++ Installation can be done on any existing disk organization. ++ ++ ++ About ANSI C compiler ++ --------------------- ++ ++ An ANSI C compiled is needed among other things. This means that ++ VAX C is not and will not be supported. ++ ++ We have only tested with DEC C (a.k.a HP VMS C / VSI C) and require ++ version 7.1 or later. Compiling with a different ANSI C compiler may ++ require some work. ++ ++ Please avoid using C RTL feature logical names DECC$* when building ++ and testing OpenSSL. Most of all, they can be disruptive when ++ running the tests, as they affect the Perl interpreter. ++ ++ ++ About ODS-5 directory names and Perl ++ ------------------------------------ ++ ++ It seems that the perl function canonpath() in the File::Spec module ++ doesn't treat file specifications where the last directory name ++ contains periods very well. Unfortunately, some versions of VMS tar ++ will keep the periods in the OpenSSL source directory instead of ++ converting them to underscore, thereby leaving your source in ++ something like [.openssl-1^.1^.0]. This will lead to issues when ++ configuring and building OpenSSL. ++ ++ We have no replacement for Perl's canonpath(), so the best workaround ++ for now is to rename the OpenSSL source directory, as follows (please ++ adjust for the actual source directory name you have): ++ ++ $ rename openssl-1^.1^.0.DIR openssl-1_1_0.DIR ++ ++ ++ About MMS and DCL ++ ----------------- ++ ++ MMS has certain limitations when it comes to line length, and DCL has ++ certain limitations when it comes to total command length. We do ++ what we can to mitigate, but there is the possibility that it's not ++ enough. Should you run into issues, a very simple solution is to set ++ yourself up a few logical names for the directory trees you're going ++ to use. ++ ++ ++ Checking the distribution ++ ------------------------- ++ ++ There have been reports of places where the distribution didn't quite ++ get through, for example if you've copied the tree from a NFS-mounted ++ Unix mount point. ++ ++ The easiest way to check if everything got through as it should is to ++ check for one of the following files: ++ ++ [.crypto]opensslconf^.h.in ++ ++ The best way to get a correct distribution is to download the gzipped ++ tar file from ftp://ftp.openssl.org/source/, use GZIP -d to uncompress ++ it and VMSTAR to unpack the resulting tar file. ++ ++ Gzip and VMSTAR are available here: ++ ++ http://antinode.info/dec/index.html#Software ++ ++ Should you need it, you can find UnZip for VMS here: ++ ++ http://www.info-zip.org/UnZip.html +diff --git a/CryptoPkg/Library/OpensslLib/openssl/NOTES.WIN b/CryptoPkg/Library/OpensslLib/openssl/NOTES.WIN +new file mode 100644 +index 0000000..2a3c1e1 +--- /dev/null ++++ b/CryptoPkg/Library/OpensslLib/openssl/NOTES.WIN +@@ -0,0 +1,138 @@ ++ ++ NOTES FOR THE WINDOWS PLATFORMS ++ =============================== ++ ++ Requirement details for native (Visual C++) builds ++ -------------------------------------------------- ++ ++ In addition to the requirements and instructions listed in INSTALL, ++ this are required as well: ++ ++ - You need Perl. We recommend ActiveState Perl, available from ++ https://www.activestate.com/ActivePerl. ++ You also need the perl module Text::Template, available on CPAN. ++ Please read NOTES.PERL for more information. ++ ++ - You need a C compiler. OpenSSL has been tested to build with these: ++ ++ * Visual C++ ++ ++ - Netwide Assembler, a.k.a. NASM, available from http://www.nasm.us, ++ is required if you intend to utilize assembler modules. Note that NASM ++ is the only supported assembler. The Microsoft provided assembler is NOT ++ supported. ++ ++ ++ Visual C++ (native Windows) ++ --------------------------- ++ ++ Installation directories ++ ++ The default installation directories are derived from environment ++ variables. ++ ++ For VC-WIN32, the following defaults are use: ++ ++ PREFIX: %ProgramFiles(86)%\OpenSSL ++ OPENSSLDIR: %CommonProgramFiles(86)%\SSL ++ ++ For VC-WIN64, the following defaults are use: ++ ++ PREFIX: %ProgramW6432%\OpenSSL ++ OPENSSLDIR: %CommonProgramW6432%\SSL ++ ++ Should those environment variables not exist (on a pure Win32 ++ installation for examples), these fallbacks are used: ++ ++ PREFIX: %ProgramFiles%\OpenSSL ++ OPENSSLDIR: %CommonProgramFiles%\SSL ++ ++ ALSO NOTE that those directories are usually write protected, even if ++ your account is in the Administrators group. To work around that, ++ start the command prompt by right-clicking on it and choosing "Run as ++ Administrator" before running 'nmake install'. The other solution ++ is, of course, to choose a different set of directories by using ++ --prefix and --openssldir when configuring. ++ ++ GNU C (Cygwin) ++ -------------- ++ ++ Cygwin implements a Posix/Unix runtime system (cygwin1.dll) on top of the ++ Windows subsystem and provides a bash shell and GNU tools environment. ++ Consequently, a make of OpenSSL with Cygwin is virtually identical to the ++ Unix procedure. ++ ++ To build OpenSSL using Cygwin, you need to: ++ ++ * Install Cygwin (see https://cygwin.com/) ++ ++ * Install Cygwin Perl and ensure it is in the path. Recall that ++ as least 5.10.0 is required. ++ ++ * Run the Cygwin bash shell ++ ++ Apart from that, follow the Unix instructions in INSTALL. ++ ++ NOTE: "make test" and normal file operations may fail in directories ++ mounted as text (i.e. mount -t c:\somewhere /home) due to Cygwin ++ stripping of carriage returns. To avoid this ensure that a binary ++ mount is used, e.g. mount -b c:\somewhere /home. ++ ++ It is also possible to create "conventional" Windows binaries that use ++ the Microsoft C runtime system (msvcrt.dll or crtdll.dll) using MinGW ++ development add-on for Cygwin. MinGW is supported even as a standalone ++ setup as described in the following section. In the context you should ++ recognize that binaries targeting Cygwin itself are not interchangeable ++ with "conventional" Windows binaries you generate with/for MinGW. ++ ++ ++ GNU C (MinGW/MSYS) ++ ------------------ ++ ++ * Compiler and shell environment installation: ++ ++ MinGW and MSYS are available from http://www.mingw.org/, both are ++ required. Run the installers and do whatever magic they say it takes ++ to start MSYS bash shell with GNU tools and matching Perl on its PATH. ++ "Matching Perl" refers to chosen "shell environment", i.e. if built ++ under MSYS, then Perl compiled for MSYS must be used. ++ ++ Alternatively, one can use MSYS2 from https://msys2.github.io/, ++ which includes MingW (32-bit and 64-bit). ++ ++ * It is also possible to cross-compile it on Linux by configuring ++ with './Configure --cross-compile-prefix=i386-mingw32- mingw ...'. ++ Other possible cross compile prefixes include x86_64-w64-mingw32- ++ and i686-w64-mingw32-. ++ ++ ++ Linking your application ++ ------------------------ ++ ++ This section applies to non-Cygwin builds. ++ ++ If you link with static OpenSSL libraries then you're expected to ++ additionally link your application with WS2_32.LIB, GDI32.LIB, ++ ADVAPI32.LIB, CRYPT32.LIB and USER32.LIB. Those developing ++ non-interactive service applications might feel concerned about ++ linking with GDI32.LIB and USER32.LIB, as they are justly associated ++ with interactive desktop, which is not available to service ++ processes. The toolkit is designed to detect in which context it's ++ currently executed, GUI, console app or service, and act accordingly, ++ namely whether or not to actually make GUI calls. Additionally those ++ who wish to /DELAYLOAD:GDI32.DLL and /DELAYLOAD:USER32.DLL and ++ actually keep them off service process should consider implementing ++ and exporting from .exe image in question own _OPENSSL_isservice not ++ relying on USER32.DLL. E.g., on Windows Vista and later you could: ++ ++ __declspec(dllexport) __cdecl BOOL _OPENSSL_isservice(void) ++ { DWORD sess; ++ if (ProcessIdToSessionId(GetCurrentProcessId(),&sess)) ++ return sess==0; ++ return FALSE; ++ } ++ ++ If you link with OpenSSL .DLLs, then you're expected to include into ++ your application code small "shim" snippet, which provides glue between ++ OpenSSL BIO layer and your compiler run-time. See the OPENSSL_Applink ++ manual page for further details. +diff --git a/CryptoPkg/Library/OpensslLib/openssl/README b/CryptoPkg/Library/OpensslLib/openssl/README +new file mode 100644 +index 0000000..29979ab +--- /dev/null ++++ b/CryptoPkg/Library/OpensslLib/openssl/README +@@ -0,0 +1,94 @@ ++ ++ OpenSSL 1.1.0e 16 Feb 2017 ++ ++ Copyright (c) 1998-2016 The OpenSSL Project ++ Copyright (c) 1995-1998 Eric A. Young, Tim J. Hudson ++ All rights reserved. ++ ++ DESCRIPTION ++ ----------- ++ ++ The OpenSSL Project is a collaborative effort to develop a robust, ++ commercial-grade, fully featured, and Open Source toolkit implementing the ++ Transport Layer Security (TLS) protocols (including SSLv3) as well as a ++ full-strength general purpose cryptographic library. ++ ++ OpenSSL is descended from the SSLeay library developed by Eric A. Young ++ and Tim J. Hudson. The OpenSSL toolkit is licensed under a dual-license (the ++ OpenSSL license plus the SSLeay license), which means that you are free to ++ get and use it for commercial and non-commercial purposes as long as you ++ fulfill the conditions of both licenses. ++ ++ OVERVIEW ++ -------- ++ ++ The OpenSSL toolkit includes: ++ ++ libssl (with platform specific naming): ++ Provides the client and server-side implementations for SSLv3 and TLS. ++ ++ libcrypto (with platform specific naming): ++ Provides general cryptographic and X.509 support needed by SSL/TLS but ++ not logically part of it. ++ ++ openssl: ++ A command line tool that can be used for: ++ Creation of key parameters ++ Creation of X.509 certificates, CSRs and CRLs ++ Calculation of message digests ++ Encryption and decryption ++ SSL/TLS client and server tests ++ Handling of S/MIME signed or encrypted mail ++ And more... ++ ++ INSTALLATION ++ ------------ ++ ++ See the appropriate file: ++ INSTALL Linux, Unix, Windows, OpenVMS, ... ++ NOTES.* INSTALL addendums for different platforms ++ ++ SUPPORT ++ ------- ++ ++ See the OpenSSL website www.openssl.org for details on how to obtain ++ commercial technical support. Free community support is available through the ++ openssl-users email list (see ++ https://www.openssl.org/community/mailinglists.html for further details). ++ ++ If you have any problems with OpenSSL then please take the following steps ++ first: ++ ++ - Download the latest version from the repository ++ to see if the problem has already been addressed ++ - Configure with no-asm ++ - Remove compiler optimisation flags ++ ++ If you wish to report a bug then please include the following information ++ and create an issue on GitHub: ++ ++ - OpenSSL version: output of 'openssl version -a' ++ - Any "Configure" options that you selected during compilation of the ++ library if applicable (see INSTALL) ++ - OS Name, Version, Hardware platform ++ - Compiler Details (name, version) ++ - Application Details (name, version) ++ - Problem Description (steps that will reproduce the problem, if known) ++ - Stack Traceback (if the application dumps core) ++ ++ Just because something doesn't work the way you expect does not mean it ++ is necessarily a bug in OpenSSL. Use the openssl-users email list for this type ++ of query. ++ ++ HOW TO CONTRIBUTE TO OpenSSL ++ ---------------------------- ++ ++ See CONTRIBUTING ++ ++ LEGALITIES ++ ---------- ++ ++ A number of nations restrict the use or export of cryptography. If you ++ are potentially subject to such restrictions you should seek competent ++ professional legal advice before attempting to develop or distribute ++ cryptographic code. +diff --git a/CryptoPkg/Library/OpensslLib/openssl/README.ECC b/CryptoPkg/Library/OpensslLib/openssl/README.ECC +new file mode 100644 +index 0000000..fa3cad7 +--- /dev/null ++++ b/CryptoPkg/Library/OpensslLib/openssl/README.ECC +@@ -0,0 +1,61 @@ ++NOTE: The OpenSSL Software Foundation has executed a sublicense agreement ++entitled "Elliptic Curve Cryptography Patent License Agreement" with the ++National Security Agency/ Central Security Service Commercial Solutions ++Center (NCSC) dated 2010-11-04. That agreement permits implementation and ++distribution of software containing features covered by any or all of the ++following patents: ++ ++1.) U.S. Pat. No. 5,761,305 entitled "Key Agreement and Transport Protocol ++ with Implicit Signatures" issued on June 2, 1998; ++2.) Can. Pat. Appl. Ser. No. 2176972 entitled "Key Agreement and Transport ++ Protocol with Implicit Signature and Reduced Bandwidth" filed on May ++ 16, 1996; ++3.) U.S. Pat. No. 5,889,865 entitled "Key Agreement and Transport Protocol ++ with Implicit Signatures" issued on March 30, 1999; ++4.) U.S. Pat. No. 5,896,455 entitled "Key Agreement and Transport Protocol ++ with Implicit Signatures" issued on April 20, 1999; ++5.) U.S. Pat. No. 5,933,504 entitled "Strengthened Public Key Protocol" ++ issued on August 3, 1999; ++6.) Can. Pat. Appl. Ser. No. 2176866 entitled "Strengthened Public Key ++ Protocol" filed on May 17, 1996; ++7.) E.P. Pat. Appl. Ser. No. 96201322.3 entitled "Strengthened Public Key ++ Protocol" filed on May 17, 1996; ++8.) U.S. Pat. No. 5,999,626 entitled "Digital Signatures on a Smartcard" ++ issued on December 7, 1999; ++9.) Can. Pat. Appl. Ser. No. 2202566 entitled "Digital Signatures on a ++ Smartcard" filed on April 14, 1997; ++10.) E.P. Pat. Appl. No. 97106114.8 entitled "Digital Signatures on a ++ Smartcard" filed on April 15, 1997; ++11.) U.S Pat. No. 6,122,736 entitled "Key Agreement and Transport Protocol ++ with Implicit Signatures" issued on September 19, 2000; ++12.) Can. Pat. Appl. Ser. No. 2174261 entitled "Key Agreement and Transport ++ Protocol with Implicit Signatures" filed on April 16, 1996; ++13.) E.P. Pat. Appl. Ser. No. 96105920.1 entitled "Key Agreement and ++ Transport Protocol with Implicit Signatures" filed on April 16, 1996; ++14.) U.S. Pat. No. 6,141,420 entitled "Elliptic Curve Encryption Systems" ++ issued on October 31, 2000; ++15.) Can. Pat. Appl. Ser. No. 2155038 entitled "Elliptic Curve Encryption ++ Systems" filed on July 31, 1995; ++16.) E.P. Pat. Appl. Ser. No. 95926348.4 entitled "Elliptic Curve Encryption ++ Systems" filed on July 31, 1995; ++17.) U.S. Pat. No. 6,336,188 entitled "Authenticated Key Agreement" issued ++ on January 1, 2002; ++18.) U.S. Pat. No. 6,487,661 entitled "Key Agreement and Transport Protocol" ++ issued on November 26, 2002; ++19.) Can. Pat. Appl. Ser. No. 2174260 entitled "Key Agreement and Transport ++ Protocol" filed on April 16, 1996; ++20.) E.P. Pat. Appl. Ser. No. 96105921.9 entitled "Key Agreement and ++ Transport Protocol" filed on April 21, 1996; ++21.) U.S. Pat. No. 6,563,928 entitled "Strengthened Public Key Protocol" ++ issued on May 13, 2003; ++22.) U.S. Pat. No. 6,618,483 entitled "Elliptic Curve Encryption Systems" ++ issued September 9, 2003; ++23.) U.S. Pat. Appl. Ser. No. 09/434,247 entitled "Digital Signatures on a ++ Smartcard" filed on November 5, 1999; ++24.) U.S. Pat. Appl. Ser. No. 09/558,256 entitled "Key Agreement and ++ Transport Protocol with Implicit Signatures" filed on April 25, 2000; ++25.) U.S. Pat. Appl. Ser. No. 09/942,492 entitled "Digital Signatures on a ++ Smartcard" filed on August 29, 2001 and published on July 18, 2002; and, ++26.) U.S. Pat. Appl. Ser. No. 10/185,735 entitled "Strengthened Public Key ++ Protocol" filed on July 1, 2000. ++ +diff --git a/CryptoPkg/Library/OpensslLib/openssl/README.ENGINE b/CryptoPkg/Library/OpensslLib/openssl/README.ENGINE +new file mode 100644 +index 0000000..530a4ed +--- /dev/null ++++ b/CryptoPkg/Library/OpensslLib/openssl/README.ENGINE +@@ -0,0 +1,288 @@ ++ ENGINE ++ ====== ++ ++ With OpenSSL 0.9.6, a new component was added to support alternative ++ cryptography implementations, most commonly for interfacing with external ++ crypto devices (eg. accelerator cards). This component is called ENGINE, ++ and its presence in OpenSSL 0.9.6 (and subsequent bug-fix releases) ++ caused a little confusion as 0.9.6** releases were rolled in two ++ versions, a "standard" and an "engine" version. In development for 0.9.7, ++ the ENGINE code has been merged into the main branch and will be present ++ in the standard releases from 0.9.7 forwards. ++ ++ There are currently built-in ENGINE implementations for the following ++ crypto devices: ++ ++ o Cryptodev ++ o Microsoft CryptoAPI ++ o VIA Padlock ++ o nCipher CHIL ++ ++ In addition, dynamic binding to external ENGINE implementations is now ++ provided by a special ENGINE called "dynamic". See the "DYNAMIC ENGINE" ++ section below for details. ++ ++ At this stage, a number of things are still needed and are being worked on: ++ ++ 1 Integration of EVP support. ++ 2 Configuration support. ++ 3 Documentation! ++ ++1 With respect to EVP, this relates to support for ciphers and digests in ++ the ENGINE model so that alternative implementations of existing ++ algorithms/modes (or previously unimplemented ones) can be provided by ++ ENGINE implementations. ++ ++2 Configuration support currently exists in the ENGINE API itself, in the ++ form of "control commands". These allow an application to expose to the ++ user/admin the set of commands and parameter types a given ENGINE ++ implementation supports, and for an application to directly feed string ++ based input to those ENGINEs, in the form of name-value pairs. This is an ++ extensible way for ENGINEs to define their own "configuration" mechanisms ++ that are specific to a given ENGINE (eg. for a particular hardware ++ device) but that should be consistent across *all* OpenSSL-based ++ applications when they use that ENGINE. Work is in progress (or at least ++ in planning) for supporting these control commands from the CONF (or ++ NCONF) code so that applications using OpenSSL's existing configuration ++ file format can have ENGINE settings specified in much the same way. ++ Presently however, applications must use the ENGINE API itself to provide ++ such functionality. To see first hand the types of commands available ++ with the various compiled-in ENGINEs (see further down for dynamic ++ ENGINEs), use the "engine" openssl utility with full verbosity, ie; ++ openssl engine -vvvv ++ ++3 Documentation? Volunteers welcome! The source code is reasonably well ++ self-documenting, but some summaries and usage instructions are needed - ++ moreover, they are needed in the same POD format the existing OpenSSL ++ documentation is provided in. Any complete or incomplete contributions ++ would help make this happen. ++ ++ STABILITY & BUG-REPORTS ++ ======================= ++ ++ What already exists is fairly stable as far as it has been tested, but ++ the test base has been a bit small most of the time. For the most part, ++ the vendors of the devices these ENGINEs support have contributed to the ++ development and/or testing of the implementations, and *usually* (with no ++ guarantees) have experience in using the ENGINE support to drive their ++ devices from common OpenSSL-based applications. Bugs and/or inexplicable ++ behaviour in using a specific ENGINE implementation should be sent to the ++ author of that implementation (if it is mentioned in the corresponding C ++ file), and in the case of implementations for commercial hardware ++ devices, also through whatever vendor support channels are available. If ++ none of this is possible, or the problem seems to be something about the ++ ENGINE API itself (ie. not necessarily specific to a particular ENGINE ++ implementation) then you should mail complete details to the relevant ++ OpenSSL mailing list. For a definition of "complete details", refer to ++ the OpenSSL "README" file. As for which list to send it to; ++ ++ openssl-users: if you are *using* the ENGINE abstraction, either in an ++ pre-compiled application or in your own application code. ++ ++ openssl-dev: if you are discussing problems with OpenSSL source code. ++ ++ USAGE ++ ===== ++ ++ The default "openssl" ENGINE is always chosen when performing crypto ++ operations unless you specify otherwise. You must actively tell the ++ openssl utility commands to use anything else through a new command line ++ switch called "-engine". Also, if you want to use the ENGINE support in ++ your own code to do something similar, you must likewise explicitly ++ select the ENGINE implementation you want. ++ ++ Depending on the type of hardware, system, and configuration, "settings" ++ may need to be applied to an ENGINE for it to function as expected/hoped. ++ The recommended way of doing this is for the application to support ++ ENGINE "control commands" so that each ENGINE implementation can provide ++ whatever configuration primitives it might require and the application ++ can allow the user/admin (and thus the hardware vendor's support desk ++ also) to provide any such input directly to the ENGINE implementation. ++ This way, applications do not need to know anything specific to any ++ device, they only need to provide the means to carry such user/admin ++ input through to the ENGINE in question. Ie. this connects *you* (and ++ your helpdesk) to the specific ENGINE implementation (and device), and ++ allows application authors to not get buried in hassle supporting ++ arbitrary devices they know (and care) nothing about. ++ ++ A new "openssl" utility, "openssl engine", has been added in that allows ++ for testing and examination of ENGINE implementations. Basic usage ++ instructions are available by specifying the "-?" command line switch. ++ ++ DYNAMIC ENGINES ++ =============== ++ ++ The new "dynamic" ENGINE provides a low-overhead way to support ENGINE ++ implementations that aren't pre-compiled and linked into OpenSSL-based ++ applications. This could be because existing compiled-in implementations ++ have known problems and you wish to use a newer version with an existing ++ application. It could equally be because the application (or OpenSSL ++ library) you are using simply doesn't have support for the ENGINE you ++ wish to use, and the ENGINE provider (eg. hardware vendor) is providing ++ you with a self-contained implementation in the form of a shared-library. ++ The other use-case for "dynamic" is with applications that wish to ++ maintain the smallest foot-print possible and so do not link in various ++ ENGINE implementations from OpenSSL, but instead leaves you to provide ++ them, if you want them, in the form of "dynamic"-loadable ++ shared-libraries. It should be possible for hardware vendors to provide ++ their own shared-libraries to support arbitrary hardware to work with ++ applications based on OpenSSL 0.9.7 or later. If you're using an ++ application based on 0.9.7 (or later) and the support you desire is only ++ announced for versions later than the one you need, ask the vendor to ++ backport their ENGINE to the version you need. ++ ++ How does "dynamic" work? ++ ------------------------ ++ The dynamic ENGINE has a special flag in its implementation such that ++ every time application code asks for the 'dynamic' ENGINE, it in fact ++ gets its own copy of it. As such, multi-threaded code (or code that ++ multiplexes multiple uses of 'dynamic' in a single application in any ++ way at all) does not get confused by 'dynamic' being used to do many ++ independent things. Other ENGINEs typically don't do this so there is ++ only ever 1 ENGINE structure of its type (and reference counts are used ++ to keep order). The dynamic ENGINE itself provides absolutely no ++ cryptographic functionality, and any attempt to "initialise" the ENGINE ++ automatically fails. All it does provide are a few "control commands" ++ that can be used to control how it will load an external ENGINE ++ implementation from a shared-library. To see these control commands, ++ use the command-line; ++ ++ openssl engine -vvvv dynamic ++ ++ The "SO_PATH" control command should be used to identify the ++ shared-library that contains the ENGINE implementation, and "NO_VCHECK" ++ might possibly be useful if there is a minor version conflict and you ++ (or a vendor helpdesk) is convinced you can safely ignore it. ++ "ID" is probably only needed if a shared-library implements ++ multiple ENGINEs, but if you know the engine id you expect to be using, ++ it doesn't hurt to specify it (and this provides a sanity check if ++ nothing else). "LIST_ADD" is only required if you actually wish the ++ loaded ENGINE to be discoverable by application code later on using the ++ ENGINE's "id". For most applications, this isn't necessary - but some ++ application authors may have nifty reasons for using it. The "LOAD" ++ command is the only one that takes no parameters and is the command ++ that uses the settings from any previous commands to actually *load* ++ the shared-library ENGINE implementation. If this command succeeds, the ++ (copy of the) 'dynamic' ENGINE will magically morph into the ENGINE ++ that has been loaded from the shared-library. As such, any control ++ commands supported by the loaded ENGINE could then be executed as per ++ normal. Eg. if ENGINE "foo" is implemented in the shared-library ++ "libfoo.so" and it supports some special control command "CMD_FOO", the ++ following code would load and use it (NB: obviously this code has no ++ error checking); ++ ++ ENGINE *e = ENGINE_by_id("dynamic"); ++ ENGINE_ctrl_cmd_string(e, "SO_PATH", "/lib/libfoo.so", 0); ++ ENGINE_ctrl_cmd_string(e, "ID", "foo", 0); ++ ENGINE_ctrl_cmd_string(e, "LOAD", NULL, 0); ++ ENGINE_ctrl_cmd_string(e, "CMD_FOO", "some input data", 0); ++ ++ For testing, the "openssl engine" utility can be useful for this sort ++ of thing. For example the above code excerpt would achieve much the ++ same result as; ++ ++ openssl engine dynamic \ ++ -pre SO_PATH:/lib/libfoo.so \ ++ -pre ID:foo \ ++ -pre LOAD \ ++ -pre "CMD_FOO:some input data" ++ ++ Or to simply see the list of commands supported by the "foo" ENGINE; ++ ++ openssl engine -vvvv dynamic \ ++ -pre SO_PATH:/lib/libfoo.so \ ++ -pre ID:foo \ ++ -pre LOAD ++ ++ Applications that support the ENGINE API and more specifically, the ++ "control commands" mechanism, will provide some way for you to pass ++ such commands through to ENGINEs. As such, you would select "dynamic" ++ as the ENGINE to use, and the parameters/commands you pass would ++ control the *actual* ENGINE used. Each command is actually a name-value ++ pair and the value can sometimes be omitted (eg. the "LOAD" command). ++ Whilst the syntax demonstrated in "openssl engine" uses a colon to ++ separate the command name from the value, applications may provide ++ their own syntax for making that separation (eg. a win32 registry ++ key-value pair may be used by some applications). The reason for the ++ "-pre" syntax in the "openssl engine" utility is that some commands ++ might be issued to an ENGINE *after* it has been initialised for use. ++ Eg. if an ENGINE implementation requires a smart-card to be inserted ++ during initialisation (or a PIN to be typed, or whatever), there may be ++ a control command you can issue afterwards to "forget" the smart-card ++ so that additional initialisation is no longer possible. In ++ applications such as web-servers, where potentially volatile code may ++ run on the same host system, this may provide some arguable security ++ value. In such a case, the command would be passed to the ENGINE after ++ it has been initialised for use, and so the "-post" switch would be ++ used instead. Applications may provide a different syntax for ++ supporting this distinction, and some may simply not provide it at all ++ ("-pre" is almost always what you're after, in reality). ++ ++ How do I build a "dynamic" ENGINE? ++ ---------------------------------- ++ This question is trickier - currently OpenSSL bundles various ENGINE ++ implementations that are statically built in, and any application that ++ calls the "ENGINE_load_builtin_engines()" function will automatically ++ have all such ENGINEs available (and occupying memory). Applications ++ that don't call that function have no ENGINEs available like that and ++ would have to use "dynamic" to load any such ENGINE - but on the other ++ hand such applications would only have the memory footprint of any ++ ENGINEs explicitly loaded using user/admin provided control commands. ++ The main advantage of not statically linking ENGINEs and only using ++ "dynamic" for hardware support is that any installation using no ++ "external" ENGINE suffers no unnecessary memory footprint from unused ++ ENGINEs. Likewise, installations that do require an ENGINE incur the ++ overheads from only *that* ENGINE once it has been loaded. ++ ++ Sounds good? Maybe, but currently building an ENGINE implementation as ++ a shared-library that can be loaded by "dynamic" isn't automated in ++ OpenSSL's build process. It can be done manually quite easily however. ++ Such a shared-library can either be built with any OpenSSL code it ++ needs statically linked in, or it can link dynamically against OpenSSL ++ if OpenSSL itself is built as a shared library. The instructions are ++ the same in each case, but in the former (statically linked any ++ dependencies on OpenSSL) you must ensure OpenSSL is built with ++ position-independent code ("PIC"). The default OpenSSL compilation may ++ already specify the relevant flags to do this, but you should consult ++ with your compiler documentation if you are in any doubt. ++ ++ This example will show building the "atalla" ENGINE in the ++ crypto/engine/ directory as a shared-library for use via the "dynamic" ++ ENGINE. ++ 1) "cd" to the crypto/engine/ directory of a pre-compiled OpenSSL ++ source tree. ++ 2) Recompile at least one source file so you can see all the compiler ++ flags (and syntax) being used to build normally. Eg; ++ touch hw_atalla.c ; make ++ will rebuild "hw_atalla.o" using all such flags. ++ 3) Manually enter the same compilation line to compile the ++ "hw_atalla.c" file but with the following two changes; ++ (a) add "-DENGINE_DYNAMIC_SUPPORT" to the command line switches, ++ (b) change the output file from "hw_atalla.o" to something new, ++ eg. "tmp_atalla.o" ++ 4) Link "tmp_atalla.o" into a shared-library using the top-level ++ OpenSSL libraries to resolve any dependencies. The syntax for doing ++ this depends heavily on your system/compiler and is a nightmare ++ known well to anyone who has worked with shared-library portability ++ before. 'gcc' on Linux, for example, would use the following syntax; ++ gcc -shared -o dyn_atalla.so tmp_atalla.o -L../.. -lcrypto ++ 5) Test your shared library using "openssl engine" as explained in the ++ previous section. Eg. from the top-level directory, you might try; ++ apps/openssl engine -vvvv dynamic \ ++ -pre SO_PATH:./crypto/engine/dyn_atalla.so -pre LOAD ++ If the shared-library loads successfully, you will see both "-pre" ++ commands marked as "SUCCESS" and the list of control commands ++ displayed (because of "-vvvv") will be the control commands for the ++ *atalla* ENGINE (ie. *not* the 'dynamic' ENGINE). You can also add ++ the "-t" switch to the utility if you want it to try and initialise ++ the atalla ENGINE for use to test any possible hardware/driver ++ issues. ++ ++ PROBLEMS ++ ======== ++ ++ It seems like the ENGINE part doesn't work too well with CryptoSwift on Win32. ++ A quick test done right before the release showed that trying "openssl speed ++ -engine cswift" generated errors. If the DSO gets enabled, an attempt is made ++ to write at memory address 0x00000002. ++ +diff --git a/CryptoPkg/Library/OpensslLib/openssl/README.FIPS b/CryptoPkg/Library/OpensslLib/openssl/README.FIPS +new file mode 100644 +index 0000000..8593486 +--- /dev/null ++++ b/CryptoPkg/Library/OpensslLib/openssl/README.FIPS +@@ -0,0 +1 @@ ++This release does not support a FIPS 140-2 validated module. +diff --git a/CryptoPkg/Library/OpensslLib/openssl/VMS/VMSify-conf.pl b/CryptoPkg/Library/OpensslLib/openssl/VMS/VMSify-conf.pl +new file mode 100644 +index 0000000..21eff11 +--- /dev/null ++++ b/CryptoPkg/Library/OpensslLib/openssl/VMS/VMSify-conf.pl +@@ -0,0 +1,41 @@ ++#! /usr/bin/env perl ++# Copyright 2004-2016 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 ++# in the file LICENSE in the source distribution or at ++# https://www.openssl.org/source/license.html ++ ++ ++use strict; ++use warnings; ++ ++my @directory_vars = ( "dir", "certs", "crl_dir", "new_certs_dir" ); ++my @file_vars = ( "database", "certificate", "serial", "crlnumber", ++ "crl", "private_key", "RANDFILE" ); ++while() { ++ s|\R$||; ++ foreach my $d (@directory_vars) { ++ if (/^(\s*\#?\s*${d}\s*=\s*)\.\/([^\s\#]*)([\s\#].*)$/) { ++ $_ = "$1sys\\\$disk:\[.$2$3"; ++ } elsif (/^(\s*\#?\s*${d}\s*=\s*)(\w[^\s\#]*)([\s\#].*)$/) { ++ $_ = "$1sys\\\$disk:\[.$2$3"; ++ } ++ s/^(\s*\#?\s*${d}\s*=\s*\$\w+)\/([^\s\#]*)([\s\#].*)$/$1.$2\]$3/; ++ while(/^(\s*\#?\s*${d}\s*=\s*(\$\w+\.|sys\\\$disk:\[\.)[\w\.]+)\/([^\]]*)\](.*)$/) { ++ $_ = "$1.$3]$4"; ++ } ++ } ++ foreach my $f (@file_vars) { ++ s/^(\s*\#?\s*${f}\s*=\s*)\.\/(.*)$/$1sys\\\$disk:\[\/$2/; ++ while(/^(\s*\#?\s*${f}\s*=\s*(\$\w+|sys\\\$disk:\[)[^\/]*)\/(\w+\/[^\s\#]*)([\s\#].*)$/) { ++ $_ = "$1.$3$4"; ++ } ++ if (/^(\s*\#?\s*${f}\s*=\s*(\$\w+|sys\\\$disk:\[)[^\/]*)\/(\w+)([\s\#].*)$/) { ++ $_ = "$1]$3.$4"; ++ } elsif (/^(\s*\#?\s*${f}\s*=\s*(\$\w+|sys\\\$disk:\[)[^\/]*)\/([^\s\#]*)([\s\#].*)$/) { ++ $_ = "$1]$3$4"; ++ } ++ } ++ print $_,"\n"; ++} +diff --git a/CryptoPkg/Library/OpensslLib/openssl/VMS/engine.opt b/CryptoPkg/Library/OpensslLib/openssl/VMS/engine.opt +new file mode 100644 +index 0000000..1c73c80 +--- /dev/null ++++ b/CryptoPkg/Library/OpensslLib/openssl/VMS/engine.opt +@@ -0,0 +1,2 @@ ++CASE_SENSITIVE=YES ++SYMBOL_VECTOR=(bind_engine=PROCEDURE,v_check=PROCEDURE) +diff --git a/CryptoPkg/Library/OpensslLib/openssl/VMS/openssl_ivp.com.in b/CryptoPkg/Library/OpensslLib/openssl/VMS/openssl_ivp.com.in +new file mode 100644 +index 0000000..825a699 +--- /dev/null ++++ b/CryptoPkg/Library/OpensslLib/openssl/VMS/openssl_ivp.com.in +@@ -0,0 +1,50 @@ ++$ ! OpenSSL Internal Verification Procedure ++$ ! ++$ ! This script checks the consistency of a OpenSSL installation ++$ ! It had better be spawned, as it creates process logicals ++$ ++$ ! Generated information ++$ INSTALLTOP := {- $config{INSTALLTOP} -} ++$ OPENSSLDIR := {- $config{OPENSSLDIR} -} ++$ ++$ ! Make sure that INSTALLTOP and OPENSSLDIR become something one ++$ ! can use to call the startup procedure ++$ INSTALLTOP_ = F$PARSE("A.;",INSTALLTOP,,,"NO_CONCEAL") - ++ - ".][000000" - "[000000." - "][" - "]A.;" + "." ++$ OPENSSLDIR_ = F$PARSE("A.;",OPENSSLDIR,,,"NO_CONCEAL") - ++ - ".][000000" - "[000000." - "][" - "]A.;" + "." ++$ ++$ v := {- sprintf "%02d%02d", split(/\./, $config{version}) -} ++$ pz := {- $config{pointer_size} -} ++$ ++$ @'INSTALLTOP_'SYS$STARTUP]openssl_startup'v' ++$ @'INSTALLTOP_'SYS$STARTUP]openssl_utils'v' ++$ ++$ IF F$SEARCH("OSSL$LIBCRYPTO''pz'") .EQS. "" - ++ .OR. F$SEARCH("OSSL$LIBSSL''pz'") .EQS. "" {- output_off() if $config{no_shared}; "" -}- ++ .OR. F$SEARCH("OSSL$LIBCRYPTO_SHR''pz'") .EQS. "" - ++ .OR. F$SEARCH("OSSL$LIBSSL_SHR''pz'") .EQS. "" {- output_on() if $config{no_shared}; "" -}- ++ .OR. F$SEARCH("OSSL$INCLUDE:[OPENSSL]crypto.h") .EQS. "" - ++ .OR. F$SEARCH("OPENSSL:crypto.h") .EQS. "" - ++ .OR. F$SEARCH("OSSL$EXE:OPENSSL''v'.EXE") .EQS. "" ++$ THEN ++$ WRITE SYS$ERROR "Installation inconsistent" ++$ EXIT %x00018292 ! RMS$_FNF, file not found ++$ ENDIF ++$ ++$ ON ERROR THEN GOTO error ++$ ++$ ! If something else is wrong with the installation, we're likely ++$ ! to get an image activation error here ++$ openssl version -a ++$ ++$ ! FUTURE ENHANCEMENT: Verify that engines are where they should be. ++$ ! openssl engine -c -t checker ++$ ++$ WRITE SYS$ERROR "OpenSSL IVP passed" ++$ EXIT %x10000001 ++$ ++$ error: ++$ save_status = $STATUS ++$ WRITE SYS$ERROR "OpenSSL IVP failed" ++$ EXIT 'save_status' +diff --git a/CryptoPkg/Library/OpensslLib/openssl/VMS/openssl_shutdown.com.in b/CryptoPkg/Library/OpensslLib/openssl/VMS/openssl_shutdown.com.in +new file mode 100644 +index 0000000..f0df1c1 +--- /dev/null ++++ b/CryptoPkg/Library/OpensslLib/openssl/VMS/openssl_shutdown.com.in +@@ -0,0 +1,56 @@ ++$ ! OpenSSL shutdown script ++$ ! ++$ ! This script deassigns the logical names used by the installation ++$ ! of OpenSSL. It can do so at any level, defined by P1. ++$ ! ++$ ! P1 Qualifier(s) for DEASSIGN. ++$ ! Default: /PROCESS ++$ ! ++$ ! P2 If the value is "NOALIASES", no alias logical names are ++$ ! deassigned. ++$ ++$ status = %x10000001 ! Generic success ++$ ++$ ! In case there's a problem ++$ ON CONTROL_Y THEN GOTO bailout ++$ ON ERROR THEN GOTO bailout ++$ ++$ ! Find the architecture ++$ IF F$GETSYI("CPU") .LT. 128 ++$ THEN ++$ arch := VAX ++$ ELSE ++$ arch := F$EDIT(F$GETSYI("ARCH_NAME"),"UPCASE") ++$ IF arch .EQS. "" THEN GOTO unknown_arch ++$ ENDIF ++$ ++$ ! Abbrevs ++$ DEAS := DEASSIGN /NOLOG 'P1' ++$ sv := {- sprintf "%02d%02d", $config{shlib_major}, $config{shlib_minor} -} ++$ pz := {- $config{pointer_size} -} ++$ ++$ DEAS OSSL$DATAROOT ++$ DEAS OSSL$INSTROOT ++$ DEAS OSSL$INCLUDE ++$ DEAS OSSL$LIB ++$ DEAS OSSL$SHARE ++$ DEAS OSSL$ENGINES'sv' ++$ DEAS OSSL$EXE ++$ DEAS OSSL$LIBCRYPTO'pz' ++$ DEAS OSSL$LIBSSL'pz' ++${- output_off() if $config{no_shared}; "" -} ++$ DEAS OSSL$LIBCRYPTO'sv'_SHR'pz' ++$ DEAS OSSL$LIBSSL'sv'_SHR'pz' ++${- output_on() if $config{no_shared}; "" -} ++$ DEAS OPENSSL ++$ ++$ IF P2 .NES. "NOALIASES" ++$ THEN ++$ DEAS OSSL$ENGINES ++${- output_off() if $config{no_shared}; "" -} ++$ DEAS OSSL$LIBCRYPTO_SHR'pz' ++$ DEAS OSSL$LIBSSL_SHR'pz' ++${- output_on() if $config{no_shared}; "" -} ++$ ENDIF ++$ ++$ EXIT 'status' +diff --git a/CryptoPkg/Library/OpensslLib/openssl/VMS/openssl_startup.com.in b/CryptoPkg/Library/OpensslLib/openssl/VMS/openssl_startup.com.in +new file mode 100644 +index 0000000..9c8c09a +--- /dev/null ++++ b/CryptoPkg/Library/OpensslLib/openssl/VMS/openssl_startup.com.in +@@ -0,0 +1,123 @@ ++$ ! OpenSSL startup script ++$ ! ++$ ! This script defines the logical names used by the installation ++$ ! of OpenSSL. It can provide those logical names at any level, ++$ ! defined by P1. ++$ ! ++$ ! The logical names created are: ++$ ! ++$ ! OSSL$INSTROOT Installation root ++$ ! OSSL$DATAROOT Data root (common directory ++$ ! for certs etc) ++$ ! OSSL$INCLUDE Include directory root ++$ ! OSSL$LIB Where the static library files ++$ ! are located ++$ ! OSSL$SHARE Where the shareable image files ++$ ! are located ++$ ! OSSL$EXE Where the executables are located ++$ ! OSSL$ENGINESnnn Where the shareable images are located ++$ ! OSSL$LIBCRYPTO The static crypto library ++$ ! OSSL$LIBSSL The static ssl library ++$ ! OSSL$LIBCRYPTOnnn_SHR The shareable crypto image ++$ ! OSSL$LIBSSLnnn_SHR The shareable ssl image ++$ ! OPENSSL is OSSL$INCLUDE:[OPENSSL] ++$ ! ++$ ! In all these, nnn is the OpenSSL version number. This allows ++$ ! several OpenSSL versions to be installed simultaneously, which ++$ ! matters for applications that are linked to the shareable images ++$ ! or that depend on engines. ++$ ! ++$ ! In addition, unless P2 is "NOALIASES", these logical names are ++$ ! created: ++$ ! ++$ ! OSSL$ENGINES Alias for OSSL$ENGINESnnn ++$ ! OSSL$LIBCRYPTO_SHR Alias for OSSL$LIBCRYPTOnnn_SHR ++$ ! OSSL$LIBSSL_SHR Alias for OSSL$LIBSSLnnn_SHR ++$ ! ++$ ! P1 Qualifier(s) for DEFINE. "/SYSTEM" would be typical when ++$ ! calling this script from SYS$STARTUP:SYSTARTUP_VMS.COM, ++$ ! while "/PROCESS" would be typical for a personal install. ++$ ! Default: /PROCESS ++$ ! ++$ ! P2 If the value is "NOALIASES", no alias logical names are ++$ ! created. ++$ ++$ status = %x10000001 ! Generic success ++$ ++$ ! In case there's a problem ++$ ON CONTROL_Y THEN GOTO bailout ++$ ON ERROR THEN GOTO bailout ++$ ++$ ! Find the architecture ++$ IF F$GETSYI("CPU") .LT. 128 ++$ THEN ++$ arch := VAX ++$ ELSE ++$ arch = F$EDIT(F$GETSYI("ARCH_NAME"),"UPCASE") ++$ IF arch .EQS. "" THEN GOTO unknown_arch ++$ ENDIF ++$ ++$ ! Generated information ++$ INSTALLTOP := {- $config{INSTALLTOP} -} ++$ OPENSSLDIR := {- $config{OPENSSLDIR} -} ++$ ++$ ! Make sure that INSTALLTOP and OPENSSLDIR become something one ++$ ! can build concealed logical names on ++$ INSTALLTOP_ = F$PARSE("A.;",INSTALLTOP,,,"NO_CONCEAL") - ++ - ".][000000" - "[000000." - "][" - "]A.;" + "." ++$ OPENSSLDIR_ = F$PARSE("A.;",OPENSSLDIR,,,"NO_CONCEAL") - ++ - ".][000000" - "[000000." - "][" - "]A.;" + "." ++$ ++$ DEFINE /TRANSLATION=CONCEALED /NOLOG WRK_INSTALLTOP 'INSTALLTOP_'] ++$ DEFINE /TRANSLATION=CONCEALED /NOLOG WRK_OPENSSLDIR 'OPENSSLDIR_'] ++$ ++$ ! Check that things are in place, and specifically, the stuff ++$ ! belonging to this architecture ++$ IF F$SEARCH("WRK_INSTALLTOP:[000000]INCLUDE.DIR;1") .EQS. "" - ++ .OR. F$SEARCH("WRK_INSTALLTOP:[000000]LIB.DIR;1") .EQS. "" - ++ .OR. F$SEARCH("WRK_INSTALLTOP:[000000]EXE.DIR;1") .EQS. "" - ++ .OR. F$SEARCH("WRK_INSTALLTOP:[LIB]''arch'.DIR;1") .EQS. "" - ++ .OR. F$SEARCH("WRK_INSTALLTOP:[EXE]''arch'.DIR;1") .EQS. "" - ++ .OR. F$SEARCH("WRK_OPENSSLDIR:[000000]openssl.cnf") .EQS. "" ++$ THEN ++$ WRITE SYS$ERROR "''INSTALLTOP' doesn't look like an OpenSSL installation for ''arch'" ++$ status = %x00018292 ! RMS$_FNF, file not found ++$ GOTO bailout ++$ ENDIF ++$ ++$ ! Abbrevs ++$ DEFT := DEFINE /TRANSLATION=CONCEALED /NOLOG 'P1' ++$ DEF := DEFINE /NOLOG 'P1' ++$ sv := {- sprintf "%02d%02d", $config{shlib_major}, $config{shlib_minor} -} ++$ pz := {- $config{pointer_size} -} ++$ ++$ DEFT OSSL$DATAROOT 'OPENSSLDIR_'] ++$ DEFT OSSL$INSTROOT 'INSTALLTOP_'] ++$ DEFT OSSL$INCLUDE 'INSTALLTOP_'INCLUDE.] ++$ DEF OSSL$LIB OSSL$INSTROOT:[LIB.'arch'] ++$ DEF OSSL$SHARE OSSL$INSTROOT:[LIB.'arch'] ++$ DEF OSSL$ENGINES'sv''pz' OSSL$INSTROOT:[ENGINES'sv''pz'.'arch'] ++$ DEF OSSL$EXE OSSL$INSTROOT:[EXE.'arch'],- ++ OSSL$INSTROOT:[EXE] ++$ DEF OSSL$LIBCRYPTO'pz' OSSL$LIB:OSSL$LIBCRYPTO'pz'.OLB ++$ DEF OSSL$LIBSSL'pz' OSSL$LIB:OSSL$LIBSSL'pz'.OLB ++${- output_off() if $config{no_shared}; "" -} ++$ DEF OSSL$LIBCRYPTO'sv'_SHR'pz' OSSL$SHARE:OSSL$LIBCRYPTO'sv'_SHR'pz'.EXE ++$ DEF OSSL$LIBSSL'sv'_SHR'pz' OSSL$SHARE:OSSL$LIBSSL'sv'_SHR'pz'.EXE ++${- output_on() if $config{no_shared}; "" -} ++$ DEF OPENSSL OSSL$INCLUDE:[OPENSSL] ++$ ++$ IF P2 .NES. "NOALIASES" ++$ THEN ++$ DEF OSSL$ENGINES'pz' OSSL$ENGINES'sv''pz' ++${- output_off() if $config{no_shared}; "" -} ++$ DEF OSSL$LIBCRYPTO_SHR'pz' OSSL$LIBCRYPTO'sv'_SHR'pz' ++$ DEF OSSL$LIBSSL_SHR'pz' OSSL$LIBSSL'sv'_SHR'pz' ++${- output_on() if $config{no_shared}; "" -} ++$ ENDIF ++$ ++$ bailout: ++$ DEASSIGN WRK_INSTALLTOP ++$ DEASSIGN WRK_OPENSSLDIR ++$ ++$ EXIT 'status' +diff --git a/CryptoPkg/Library/OpensslLib/openssl/VMS/openssl_utils.com.in b/CryptoPkg/Library/OpensslLib/openssl/VMS/openssl_utils.com.in +new file mode 100644 +index 0000000..edd733d +--- /dev/null ++++ b/CryptoPkg/Library/OpensslLib/openssl/VMS/openssl_utils.com.in +@@ -0,0 +1,14 @@ ++$ ! OpenSSL utilities ++$ ! ++$ ++$ v := {- sprintf "%02d%02d", split(/\./, $config{version}) -} ++$ ++$ OPENSSL'v' :== $OSSL$EXE:OPENSSL'v' ++$ OPENSSL :== $OSSL$EXE:OPENSSL'v' ++$ ++$ IF F$TYPE(PERL) .EQS. "STRING" ++$ THEN ++$ C_REHASH :== 'PERL' OSSL$EXE:c_rehash.pl ++$ ELSE ++$ WRITE SYS$ERROR "NOTE: no perl => no C_REHASH" ++$ ENDIF +diff --git a/CryptoPkg/Library/OpensslLib/openssl/VMS/test-includes.com b/CryptoPkg/Library/OpensslLib/openssl/VMS/test-includes.com +new file mode 100644 +index 0000000..c1d7ccd +--- /dev/null ++++ b/CryptoPkg/Library/OpensslLib/openssl/VMS/test-includes.com +@@ -0,0 +1,28 @@ ++$! Quick script to check how well including individual header files works ++$! on VMS, even when the VMS macro isn't defined. ++$ ++$ sav_def = f$env("DEFAULT") ++$ here = f$parse("A.;0",f$ENV("PROCEDURE")) - "A.;0" ++$ set default 'here' ++$ set default [-.include.openssl] ++$ define openssl 'f$env("DEFAULT")' ++$ set default [--] ++$ ++$ loop: ++$ f = f$search("openssl:*.h") ++$ if f .eqs. "" then goto loop_end ++$ write sys$output "Checking ",f ++$ open/write foo foo.c ++$ write foo "#undef VMS" ++$ write foo "#include " ++$ write foo "#include " ++$ write foo "main()" ++$ write foo "{printf(""foo\n"");}" ++$ close foo ++$ cc/STANDARD=ANSI89/NOLIST/PREFIX=ALL foo.c ++$ delete foo.c; ++$ goto loop ++$ loop_end: ++$ set default 'save_def' ++$ exit ++ +diff --git a/CryptoPkg/Library/OpensslLib/openssl/VMS/translatesyms.pl b/CryptoPkg/Library/OpensslLib/openssl/VMS/translatesyms.pl +new file mode 100644 +index 0000000..f61d954 +--- /dev/null ++++ b/CryptoPkg/Library/OpensslLib/openssl/VMS/translatesyms.pl +@@ -0,0 +1,62 @@ ++#! /usr/bin/env perl ++# Copyright 2016 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 ++# in the file LICENSE in the source distribution or at ++# https://www.openssl.org/source/license.html ++ ++ ++# This script will translate any SYMBOL_VECTOR item that has a translation ++# in CXX$DEMANGLER_DB. The latter is generated by and CC/DECC command that ++# uses the qualifier /REPOSITORY with the build directory as value. When ++# /NAMES=SHORTENED has been used, this file will hold the translations from ++# the original symbols to the shortened variants. ++# ++# CXX$DEMAGLER_DB. is an ISAM file, but with the magic of RMS, it can be ++# read as a text file, with each record as one line. ++# ++# The lines will have the following syntax for any symbol found that's longer ++# than 31 characters: ++# ++# LONG_symbol_34567890123{cksum}$LONG_symbol_34567890123_more_than_31_chars ++# ++# $ is present at the end of the shortened symbol name, and is preceded by a ++# 7 character checksum. The $ makes it easy to separate the shortened name ++# from the original one. ++ ++use strict; ++use warnings; ++ ++usage() if scalar @ARGV < 1; ++ ++my %translations = (); ++ ++open DEMANGLER_DATA, $ARGV[0] ++ or die "Couldn't open $ARGV[0]: $!\n"; ++while() { ++ s|\R$||; ++ (my $translated, my $original) = split /\$/; ++ $translations{$original} = $translated.'$'; ++} ++close DEMANGLER_DATA; ++ ++$| = 1; # Autoflush ++while() { ++ s@ ++ ((?:[A-Za-z0-9_]+)\/)?([A-Za-z0-9_]+)=(PROCEDURE|DATA) ++ @ ++ if (defined($translations{$2})) { ++ my $trans = $translations{$2}; ++ my $trans_uc = uc $trans; ++ if (defined($1) && $trans ne $trans_uc) { ++ "$trans_uc/$trans=$3" ++ } else { ++ "$trans=$3" ++ } ++ } else { ++ $& ++ } ++ @gxe; ++ print $_; ++} +diff --git a/CryptoPkg/Library/OpensslLib/openssl/apps/CA.pl.in b/CryptoPkg/Library/OpensslLib/openssl/apps/CA.pl.in +new file mode 100644 +index 0000000..3187e47 +--- /dev/null ++++ b/CryptoPkg/Library/OpensslLib/openssl/apps/CA.pl.in +@@ -0,0 +1,196 @@ ++#!{- $config{hashbangperl} -} ++# Copyright 2000-2016 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 ++# in the file LICENSE in the source distribution or at ++# https://www.openssl.org/source/license.html ++ ++# ++# Wrapper around the ca to make it easier to use ++# ++# {- join("\n# ", @autowarntext) -} ++ ++use strict; ++use warnings; ++ ++my $openssl = "openssl"; ++if(defined $ENV{'OPENSSL'}) { ++ $openssl = $ENV{'OPENSSL'}; ++} else { ++ $ENV{'OPENSSL'} = $openssl; ++} ++ ++my $verbose = 1; ++ ++my $OPENSSL_CONFIG = $ENV{"OPENSSL_CONFIG"} || ""; ++my $DAYS = "-days 365"; ++my $CADAYS = "-days 1095"; # 3 years ++my $REQ = "$openssl req $OPENSSL_CONFIG"; ++my $CA = "$openssl ca $OPENSSL_CONFIG"; ++my $VERIFY = "$openssl verify"; ++my $X509 = "$openssl x509"; ++my $PKCS12 = "$openssl pkcs12"; ++ ++# default openssl.cnf file has setup as per the following ++my $CATOP = "./demoCA"; ++my $CAKEY = "cakey.pem"; ++my $CAREQ = "careq.pem"; ++my $CACERT = "cacert.pem"; ++my $CACRL = "crl.pem"; ++my $DIRMODE = 0777; ++ ++my $NEWKEY = "newkey.pem"; ++my $NEWREQ = "newreq.pem"; ++my $NEWCERT = "newcert.pem"; ++my $NEWP12 = "newcert.p12"; ++my $RET = 0; ++my $WHAT = shift @ARGV || ""; ++my $FILE; ++ ++# See if reason for a CRL entry is valid; exit if not. ++sub crl_reason_ok ++{ ++ my $r = shift; ++ ++ if ($r eq 'unspecified' || $r eq 'keyCompromise' ++ || $r eq 'CACompromise' || $r eq 'affiliationChanged' ++ || $r eq 'superseded' || $r eq 'cessationOfOperation' ++ || $r eq 'certificateHold' || $r eq 'removeFromCRL') { ++ return 1; ++ } ++ print STDERR "Invalid CRL reason; must be one of:\n"; ++ print STDERR " unspecified, keyCompromise, CACompromise,\n"; ++ print STDERR " affiliationChanged, superseded, cessationOfOperation\n"; ++ print STDERR " certificateHold, removeFromCRL"; ++ exit 1; ++} ++ ++# Copy a PEM-format file; return like exit status (zero means ok) ++sub copy_pemfile ++{ ++ my ($infile, $outfile, $bound) = @_; ++ my $found = 0; ++ ++ open IN, $infile || die "Cannot open $infile, $!"; ++ open OUT, ">$outfile" || die "Cannot write to $outfile, $!"; ++ while () { ++ $found = 1 if /^-----BEGIN.*$bound/; ++ print OUT $_ if $found; ++ $found = 2, last if /^-----END.*$bound/; ++ } ++ close IN; ++ close OUT; ++ return $found == 2 ? 0 : 1; ++} ++ ++# Wrapper around system; useful for debugging. Returns just the exit status ++sub run ++{ ++ my $cmd = shift; ++ print "====\n$cmd\n" if $verbose; ++ my $status = system($cmd); ++ print "==> $status\n====\n" if $verbose; ++ return $status >> 8; ++} ++ ++ ++if ( $WHAT =~ /^(-\?|-h|-help)$/ ) { ++ print STDERR "usage: CA -newcert|-newreq|-newreq-nodes|-newca|-sign|-signcert|-verify\n"; ++ print STDERR " CA -pkcs12 [certname]\n"; ++ print STDERR " CA -crl|-revoke cert-filename [reason]\n"; ++ exit 0; ++} ++if ($WHAT eq '-newcert' ) { ++ # create a certificate ++ $RET = run("$REQ -new -x509 -keyout $NEWKEY -out $NEWCERT $DAYS"); ++ print "Cert is in $NEWCERT, private key is in $NEWKEY\n" if $RET == 0; ++} elsif ($WHAT eq '-newreq' ) { ++ # create a certificate request ++ $RET = run("$REQ -new -keyout $NEWKEY -out $NEWREQ $DAYS"); ++ print "Request is in $NEWREQ, private key is in $NEWKEY\n" if $RET == 0; ++} elsif ($WHAT eq '-newreq-nodes' ) { ++ # create a certificate request ++ $RET = run("$REQ -new -nodes -keyout $NEWKEY -out $NEWREQ $DAYS"); ++ print "Request is in $NEWREQ, private key is in $NEWKEY\n" if $RET == 0; ++} elsif ($WHAT eq '-newca' ) { ++ # create the directory hierarchy ++ mkdir ${CATOP}, $DIRMODE; ++ mkdir "${CATOP}/certs", $DIRMODE; ++ mkdir "${CATOP}/crl", $DIRMODE ; ++ mkdir "${CATOP}/newcerts", $DIRMODE; ++ mkdir "${CATOP}/private", $DIRMODE; ++ open OUT, ">${CATOP}/index.txt"; ++ close OUT; ++ open OUT, ">${CATOP}/crlnumber"; ++ print OUT "01\n"; ++ close OUT; ++ # ask user for existing CA certificate ++ print "CA certificate filename (or enter to create)\n"; ++ $FILE = "" unless defined($FILE = ); ++ $FILE =~ s{\R$}{}; ++ if ($FILE ne "") { ++ copy_pemfile($FILE,"${CATOP}/private/$CAKEY", "PRIVATE"); ++ copy_pemfile($FILE,"${CATOP}/$CACERT", "CERTIFICATE"); ++ } else { ++ print "Making CA certificate ...\n"; ++ $RET = run("$REQ -new -keyout" ++ . " ${CATOP}/private/$CAKEY" ++ . " -out ${CATOP}/$CAREQ"); ++ $RET = run("$CA -create_serial" ++ . " -out ${CATOP}/$CACERT $CADAYS -batch" ++ . " -keyfile ${CATOP}/private/$CAKEY -selfsign" ++ . " -extensions v3_ca" ++ . " -infiles ${CATOP}/$CAREQ") if $RET == 0; ++ print "CA certificate is in ${CATOP}/$CACERT\n" if $RET == 0; ++ } ++} elsif ($WHAT eq '-pkcs12' ) { ++ my $cname = $ARGV[1]; ++ $cname = "My Certificate" unless defined $cname; ++ $RET = run("$PKCS12 -in $NEWCERT -inkey $NEWKEY" ++ . " -certfile ${CATOP}/$CACERT" ++ . " -out $NEWP12" ++ . " -export -name \"$cname\""); ++ print "PKCS #12 file is in $NEWP12\n" if $RET == 0; ++} elsif ($WHAT eq '-xsign' ) { ++ $RET = run("$CA -policy policy_anything -infiles $NEWREQ"); ++} elsif ($WHAT eq '-sign' ) { ++ $RET = run("$CA -policy policy_anything -out $NEWCERT -infiles $NEWREQ"); ++ print "Signed certificate is in $NEWCERT\n" if $RET == 0; ++} elsif ($WHAT eq '-signCA' ) { ++ $RET = run("$CA -policy policy_anything -out $NEWCERT" ++ . " -extensions v3_ca -infiles $NEWREQ"); ++ print "Signed CA certificate is in $NEWCERT\n" if $RET == 0; ++} elsif ($WHAT eq '-signcert' ) { ++ $RET = run("$X509 -x509toreq -in $NEWREQ -signkey $NEWREQ" ++ . " -out tmp.pem"); ++ $RET = run("$CA -policy policy_anything -out $NEWCERT" ++ . " -infiles tmp.pem") if $RET == 0; ++ print "Signed certificate is in $NEWCERT\n" if $RET == 0; ++} elsif ($WHAT eq '-verify' ) { ++ my @files = @ARGV ? @ARGV : ( $NEWCERT ); ++ my $file; ++ foreach $file (@files) { ++ my $status = run("$VERIFY \"-CAfile\" ${CATOP}/$CACERT $file"); ++ $RET = $status if $status != 0; ++ } ++} elsif ($WHAT eq '-crl' ) { ++ $RET = run("$CA -gencrl -out ${CATOP}/crl/$CACRL"); ++ print "Generated CRL is in ${CATOP}/crl/$CACRL\n" if $RET == 0; ++} elsif ($WHAT eq '-revoke' ) { ++ my $cname = $ARGV[1]; ++ if (!defined $cname) { ++ print "Certificate filename is required; reason optional.\n"; ++ exit 1; ++ } ++ my $reason = $ARGV[2]; ++ $reason = " -crl_reason $reason" ++ if defined $reason && crl_reason_ok($reason); ++ $RET = run("$CA -revoke \"$cname\"" . $reason); ++} else { ++ print STDERR "Unknown arg \"$WHAT\"\n"; ++ print STDERR "Use -help for help.\n"; ++ exit 1; ++} ++ ++exit $RET; +diff --git a/CryptoPkg/Library/OpensslLib/openssl/apps/app_rand.c b/CryptoPkg/Library/OpensslLib/openssl/apps/app_rand.c +new file mode 100644 +index 0000000..0d44af9 +--- /dev/null ++++ b/CryptoPkg/Library/OpensslLib/openssl/apps/app_rand.c +@@ -0,0 +1,115 @@ ++/* ++ * Copyright 1995-2016 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 ++ * in the file LICENSE in the source distribution or at ++ * https://www.openssl.org/source/license.html ++ */ ++ ++#include "apps.h" ++#include ++#include ++ ++static int seeded = 0; ++static int egdsocket = 0; ++ ++int app_RAND_load_file(const char *file, int dont_warn) ++{ ++ int consider_randfile = (file == NULL); ++ char buffer[200]; ++ ++ if (file == NULL) ++ file = RAND_file_name(buffer, sizeof buffer); ++#ifndef OPENSSL_NO_EGD ++ else if (RAND_egd(file) > 0) { ++ /* ++ * we try if the given filename is an EGD socket. if it is, we don't ++ * write anything back to the file. ++ */ ++ egdsocket = 1; ++ return 1; ++ } ++#endif ++ if (file == NULL || !RAND_load_file(file, -1)) { ++ if (RAND_status() == 0) { ++ if (!dont_warn) { ++ BIO_printf(bio_err, "unable to load 'random state'\n"); ++ BIO_printf(bio_err, ++ "This means that the random number generator has not been seeded\n"); ++ BIO_printf(bio_err, "with much random data.\n"); ++ if (consider_randfile) { /* explanation does not apply when a ++ * file is explicitly named */ ++ BIO_printf(bio_err, ++ "Consider setting the RANDFILE environment variable to point at a file that\n"); ++ BIO_printf(bio_err, ++ "'random' data can be kept in (the file will be overwritten).\n"); ++ } ++ } ++ return 0; ++ } ++ } ++ seeded = 1; ++ return 1; ++} ++ ++long app_RAND_load_files(char *name) ++{ ++ char *p, *n; ++ int last; ++ long tot = 0; ++#ifndef OPENSSL_NO_EGD ++ int egd; ++#endif ++ ++ for (;;) { ++ last = 0; ++ for (p = name; ((*p != '\0') && (*p != LIST_SEPARATOR_CHAR)); p++) ; ++ if (*p == '\0') ++ last = 1; ++ *p = '\0'; ++ n = name; ++ name = p + 1; ++ if (*n == '\0') ++ break; ++ ++#ifndef OPENSSL_NO_EGD ++ egd = RAND_egd(n); ++ if (egd > 0) ++ tot += egd; ++ else ++#endif ++ tot += RAND_load_file(n, -1); ++ if (last) ++ break; ++ } ++ if (tot > 512) ++ app_RAND_allow_write_file(); ++ return (tot); ++} ++ ++int app_RAND_write_file(const char *file) ++{ ++ char buffer[200]; ++ ++ if (egdsocket || !seeded) ++ /* ++ * If we did not manage to read the seed file, we should not write a ++ * low-entropy seed file back -- it would suppress a crucial warning ++ * the next time we want to use it. ++ */ ++ return 0; ++ ++ if (file == NULL) ++ file = RAND_file_name(buffer, sizeof buffer); ++ if (file == NULL || !RAND_write_file(file)) { ++ BIO_printf(bio_err, "unable to write 'random state'\n"); ++ return 0; ++ } ++ return 1; ++} ++ ++void app_RAND_allow_write_file(void) ++{ ++ seeded = 1; ++} +diff --git a/CryptoPkg/Library/OpensslLib/openssl/apps/apps.c b/CryptoPkg/Library/OpensslLib/openssl/apps/apps.c +new file mode 100644 +index 0000000..cbf4e90 +--- /dev/null ++++ b/CryptoPkg/Library/OpensslLib/openssl/apps/apps.c +@@ -0,0 +1,2653 @@ ++/* ++ * Copyright 1995-2016 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 ++ * in the file LICENSE in the source distribution or at ++ * https://www.openssl.org/source/license.html ++ */ ++ ++#if !defined(_POSIX_C_SOURCE) && defined(OPENSSL_SYS_VMS) ++/* ++ * On VMS, you need to define this to get the declaration of fileno(). The ++ * value 2 is to make sure no function defined in POSIX-2 is left undefined. ++ */ ++# define _POSIX_C_SOURCE 2 ++#endif ++ ++#include ++#include ++#include ++#ifndef NO_SYS_TYPES_H ++# include ++#endif ++#ifndef OPENSSL_NO_POSIX_IO ++# include ++# include ++#endif ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#ifndef OPENSSL_NO_ENGINE ++# include ++#endif ++#ifndef OPENSSL_NO_RSA ++# include ++#endif ++#include ++#include ++#include "s_apps.h" ++#include "apps.h" ++ ++#ifdef _WIN32 ++static int WIN32_rename(const char *from, const char *to); ++# define rename(from,to) WIN32_rename((from),(to)) ++#endif ++ ++typedef struct { ++ const char *name; ++ unsigned long flag; ++ unsigned long mask; ++} NAME_EX_TBL; ++ ++#if !defined(OPENSSL_NO_UI) || !defined(OPENSSL_NO_ENGINE) ++static UI_METHOD *ui_method = NULL; ++#endif ++ ++static int set_table_opts(unsigned long *flags, const char *arg, ++ const NAME_EX_TBL * in_tbl); ++static int set_multi_opts(unsigned long *flags, const char *arg, ++ const NAME_EX_TBL * in_tbl); ++ ++int app_init(long mesgwin); ++ ++int chopup_args(ARGS *arg, char *buf) ++{ ++ int quoted; ++ char c = '\0', *p = NULL; ++ ++ arg->argc = 0; ++ if (arg->size == 0) { ++ arg->size = 20; ++ arg->argv = app_malloc(sizeof(*arg->argv) * arg->size, "argv space"); ++ } ++ ++ for (p = buf;;) { ++ /* Skip whitespace. */ ++ while (*p && isspace(_UC(*p))) ++ p++; ++ if (!*p) ++ break; ++ ++ /* The start of something good :-) */ ++ if (arg->argc >= arg->size) { ++ char **tmp; ++ arg->size += 20; ++ tmp = OPENSSL_realloc(arg->argv, sizeof(*arg->argv) * arg->size); ++ if (tmp == NULL) ++ return 0; ++ arg->argv = tmp; ++ } ++ quoted = *p == '\'' || *p == '"'; ++ if (quoted) ++ c = *p++; ++ arg->argv[arg->argc++] = p; ++ ++ /* now look for the end of this */ ++ if (quoted) { ++ while (*p && *p != c) ++ p++; ++ *p++ = '\0'; ++ } else { ++ while (*p && !isspace(_UC(*p))) ++ p++; ++ if (*p) ++ *p++ = '\0'; ++ } ++ } ++ arg->argv[arg->argc] = NULL; ++ return (1); ++} ++ ++#ifndef APP_INIT ++int app_init(long mesgwin) ++{ ++ return (1); ++} ++#endif ++ ++int ctx_set_verify_locations(SSL_CTX *ctx, const char *CAfile, ++ const char *CApath, int noCAfile, int noCApath) ++{ ++ if (CAfile == NULL && CApath == NULL) { ++ if (!noCAfile && SSL_CTX_set_default_verify_file(ctx) <= 0) ++ return 0; ++ if (!noCApath && SSL_CTX_set_default_verify_dir(ctx) <= 0) ++ return 0; ++ ++ return 1; ++ } ++ return SSL_CTX_load_verify_locations(ctx, CAfile, CApath); ++} ++ ++#ifndef OPENSSL_NO_CT ++ ++int ctx_set_ctlog_list_file(SSL_CTX *ctx, const char *path) ++{ ++ if (path == NULL) { ++ return SSL_CTX_set_default_ctlog_list_file(ctx); ++ } ++ ++ return SSL_CTX_set_ctlog_list_file(ctx, path); ++} ++ ++#endif ++ ++int dump_cert_text(BIO *out, X509 *x) ++{ ++ char *p; ++ ++ p = X509_NAME_oneline(X509_get_subject_name(x), NULL, 0); ++ BIO_puts(out, "subject="); ++ BIO_puts(out, p); ++ OPENSSL_free(p); ++ ++ p = X509_NAME_oneline(X509_get_issuer_name(x), NULL, 0); ++ BIO_puts(out, "\nissuer="); ++ BIO_puts(out, p); ++ BIO_puts(out, "\n"); ++ OPENSSL_free(p); ++ ++ return 0; ++} ++ ++#ifndef OPENSSL_NO_UI ++static int ui_open(UI *ui) ++{ ++ return UI_method_get_opener(UI_OpenSSL())(ui); ++} ++ ++static int ui_read(UI *ui, UI_STRING *uis) ++{ ++ if (UI_get_input_flags(uis) & UI_INPUT_FLAG_DEFAULT_PWD ++ && UI_get0_user_data(ui)) { ++ switch (UI_get_string_type(uis)) { ++ case UIT_PROMPT: ++ case UIT_VERIFY: ++ { ++ const char *password = ++ ((PW_CB_DATA *)UI_get0_user_data(ui))->password; ++ if (password && password[0] != '\0') { ++ UI_set_result(ui, uis, password); ++ return 1; ++ } ++ } ++ default: ++ break; ++ } ++ } ++ return UI_method_get_reader(UI_OpenSSL())(ui, uis); ++} ++ ++static int ui_write(UI *ui, UI_STRING *uis) ++{ ++ if (UI_get_input_flags(uis) & UI_INPUT_FLAG_DEFAULT_PWD ++ && UI_get0_user_data(ui)) { ++ switch (UI_get_string_type(uis)) { ++ case UIT_PROMPT: ++ case UIT_VERIFY: ++ { ++ const char *password = ++ ((PW_CB_DATA *)UI_get0_user_data(ui))->password; ++ if (password && password[0] != '\0') ++ return 1; ++ } ++ default: ++ break; ++ } ++ } ++ return UI_method_get_writer(UI_OpenSSL())(ui, uis); ++} ++ ++static int ui_close(UI *ui) ++{ ++ return UI_method_get_closer(UI_OpenSSL())(ui); ++} ++ ++int setup_ui_method(void) ++{ ++ ui_method = UI_create_method("OpenSSL application user interface"); ++ UI_method_set_opener(ui_method, ui_open); ++ UI_method_set_reader(ui_method, ui_read); ++ UI_method_set_writer(ui_method, ui_write); ++ UI_method_set_closer(ui_method, ui_close); ++ return 0; ++} ++ ++void destroy_ui_method(void) ++{ ++ if (ui_method) { ++ UI_destroy_method(ui_method); ++ ui_method = NULL; ++ } ++} ++#endif ++ ++int password_callback(char *buf, int bufsiz, int verify, PW_CB_DATA *cb_tmp) ++{ ++ int res = 0; ++#ifndef OPENSSL_NO_UI ++ UI *ui = NULL; ++#endif ++ PW_CB_DATA *cb_data = (PW_CB_DATA *)cb_tmp; ++ ++#ifdef OPENSSL_NO_UI ++ if (cb_data != NULL && cb_data->password != NULL) { ++ res = strlen(cb_data->password); ++ if (res > bufsiz) ++ res = bufsiz; ++ memcpy(buf, cb_data->password, res); ++ } ++#else ++ ui = UI_new_method(ui_method); ++ if (ui) { ++ int ok = 0; ++ char *buff = NULL; ++ int ui_flags = 0; ++ const char *prompt_info = NULL; ++ char *prompt; ++ ++ if (cb_data != NULL && cb_data->prompt_info != NULL) ++ prompt_info = cb_data->prompt_info; ++ prompt = UI_construct_prompt(ui, "pass phrase", prompt_info); ++ if (!prompt) { ++ BIO_printf(bio_err, "Out of memory\n"); ++ UI_free(ui); ++ return 0; ++ } ++ ++ ui_flags |= UI_INPUT_FLAG_DEFAULT_PWD; ++ UI_ctrl(ui, UI_CTRL_PRINT_ERRORS, 1, 0, 0); ++ ++ /* We know that there is no previous user data to return to us */ ++ (void)UI_add_user_data(ui, cb_data); ++ ++ if (ok >= 0) ++ ok = UI_add_input_string(ui, prompt, ui_flags, buf, ++ PW_MIN_LENGTH, bufsiz - 1); ++ if (ok >= 0 && verify) { ++ buff = app_malloc(bufsiz, "password buffer"); ++ ok = UI_add_verify_string(ui, prompt, ui_flags, buff, ++ PW_MIN_LENGTH, bufsiz - 1, buf); ++ } ++ if (ok >= 0) ++ do { ++ ok = UI_process(ui); ++ } ++ while (ok < 0 && UI_ctrl(ui, UI_CTRL_IS_REDOABLE, 0, 0, 0)); ++ ++ OPENSSL_clear_free(buff, (unsigned int)bufsiz); ++ ++ if (ok >= 0) ++ res = strlen(buf); ++ if (ok == -1) { ++ BIO_printf(bio_err, "User interface error\n"); ++ ERR_print_errors(bio_err); ++ OPENSSL_cleanse(buf, (unsigned int)bufsiz); ++ res = 0; ++ } ++ if (ok == -2) { ++ BIO_printf(bio_err, "aborted!\n"); ++ OPENSSL_cleanse(buf, (unsigned int)bufsiz); ++ res = 0; ++ } ++ UI_free(ui); ++ OPENSSL_free(prompt); ++ } ++#endif ++ return res; ++} ++ ++static char *app_get_pass(const char *arg, int keepbio); ++ ++int app_passwd(const char *arg1, const char *arg2, char **pass1, char **pass2) ++{ ++ int same; ++ if (!arg2 || !arg1 || strcmp(arg1, arg2)) ++ same = 0; ++ else ++ same = 1; ++ if (arg1) { ++ *pass1 = app_get_pass(arg1, same); ++ if (!*pass1) ++ return 0; ++ } else if (pass1) ++ *pass1 = NULL; ++ if (arg2) { ++ *pass2 = app_get_pass(arg2, same ? 2 : 0); ++ if (!*pass2) ++ return 0; ++ } else if (pass2) ++ *pass2 = NULL; ++ return 1; ++} ++ ++static char *app_get_pass(const char *arg, int keepbio) ++{ ++ char *tmp, tpass[APP_PASS_LEN]; ++ static BIO *pwdbio = NULL; ++ int i; ++ ++ if (strncmp(arg, "pass:", 5) == 0) ++ return OPENSSL_strdup(arg + 5); ++ if (strncmp(arg, "env:", 4) == 0) { ++ tmp = getenv(arg + 4); ++ if (!tmp) { ++ BIO_printf(bio_err, "Can't read environment variable %s\n", arg + 4); ++ return NULL; ++ } ++ return OPENSSL_strdup(tmp); ++ } ++ if (!keepbio || !pwdbio) { ++ if (strncmp(arg, "file:", 5) == 0) { ++ pwdbio = BIO_new_file(arg + 5, "r"); ++ if (!pwdbio) { ++ BIO_printf(bio_err, "Can't open file %s\n", arg + 5); ++ return NULL; ++ } ++#if !defined(_WIN32) ++ /* ++ * Under _WIN32, which covers even Win64 and CE, file ++ * descriptors referenced by BIO_s_fd are not inherited ++ * by child process and therefore below is not an option. ++ * It could have been an option if bss_fd.c was operating ++ * on real Windows descriptors, such as those obtained ++ * with CreateFile. ++ */ ++ } else if (strncmp(arg, "fd:", 3) == 0) { ++ BIO *btmp; ++ i = atoi(arg + 3); ++ if (i >= 0) ++ pwdbio = BIO_new_fd(i, BIO_NOCLOSE); ++ if ((i < 0) || !pwdbio) { ++ BIO_printf(bio_err, "Can't access file descriptor %s\n", arg + 3); ++ return NULL; ++ } ++ /* ++ * Can't do BIO_gets on an fd BIO so add a buffering BIO ++ */ ++ btmp = BIO_new(BIO_f_buffer()); ++ pwdbio = BIO_push(btmp, pwdbio); ++#endif ++ } else if (strcmp(arg, "stdin") == 0) { ++ pwdbio = dup_bio_in(FORMAT_TEXT); ++ if (!pwdbio) { ++ BIO_printf(bio_err, "Can't open BIO for stdin\n"); ++ return NULL; ++ } ++ } else { ++ BIO_printf(bio_err, "Invalid password argument \"%s\"\n", arg); ++ return NULL; ++ } ++ } ++ i = BIO_gets(pwdbio, tpass, APP_PASS_LEN); ++ if (keepbio != 1) { ++ BIO_free_all(pwdbio); ++ pwdbio = NULL; ++ } ++ if (i <= 0) { ++ BIO_printf(bio_err, "Error reading password from BIO\n"); ++ return NULL; ++ } ++ tmp = strchr(tpass, '\n'); ++ if (tmp) ++ *tmp = 0; ++ return OPENSSL_strdup(tpass); ++} ++ ++static CONF *app_load_config_(BIO *in, const char *filename) ++{ ++ long errorline = -1; ++ CONF *conf; ++ int i; ++ ++ conf = NCONF_new(NULL); ++ i = NCONF_load_bio(conf, in, &errorline); ++ if (i > 0) ++ return conf; ++ ++ if (errorline <= 0) ++ BIO_printf(bio_err, "%s: Can't load config file \"%s\"\n", ++ opt_getprog(), filename); ++ else ++ BIO_printf(bio_err, "%s: Error on line %ld of config file \"%s\"\n", ++ opt_getprog(), errorline, filename); ++ NCONF_free(conf); ++ return NULL; ++} ++CONF *app_load_config(const char *filename) ++{ ++ BIO *in; ++ CONF *conf; ++ ++ in = bio_open_default(filename, 'r', FORMAT_TEXT); ++ if (in == NULL) ++ return NULL; ++ ++ conf = app_load_config_(in, filename); ++ BIO_free(in); ++ return conf; ++} ++CONF *app_load_config_quiet(const char *filename) ++{ ++ BIO *in; ++ CONF *conf; ++ ++ in = bio_open_default_quiet(filename, 'r', FORMAT_TEXT); ++ if (in == NULL) ++ return NULL; ++ ++ conf = app_load_config_(in, filename); ++ BIO_free(in); ++ return conf; ++} ++ ++int app_load_modules(const CONF *config) ++{ ++ CONF *to_free = NULL; ++ ++ if (config == NULL) ++ config = to_free = app_load_config_quiet(default_config_file); ++ if (config == NULL) ++ return 1; ++ ++ if (CONF_modules_load(config, NULL, 0) <= 0) { ++ BIO_printf(bio_err, "Error configuring OpenSSL modules\n"); ++ ERR_print_errors(bio_err); ++ NCONF_free(to_free); ++ return 0; ++ } ++ NCONF_free(to_free); ++ return 1; ++} ++ ++int add_oid_section(CONF *conf) ++{ ++ char *p; ++ STACK_OF(CONF_VALUE) *sktmp; ++ CONF_VALUE *cnf; ++ int i; ++ ++ if ((p = NCONF_get_string(conf, NULL, "oid_section")) == NULL) { ++ ERR_clear_error(); ++ return 1; ++ } ++ if ((sktmp = NCONF_get_section(conf, p)) == NULL) { ++ BIO_printf(bio_err, "problem loading oid section %s\n", p); ++ return 0; ++ } ++ for (i = 0; i < sk_CONF_VALUE_num(sktmp); i++) { ++ cnf = sk_CONF_VALUE_value(sktmp, i); ++ if (OBJ_create(cnf->value, cnf->name, cnf->name) == NID_undef) { ++ BIO_printf(bio_err, "problem creating object %s=%s\n", ++ cnf->name, cnf->value); ++ return 0; ++ } ++ } ++ return 1; ++} ++ ++static int load_pkcs12(BIO *in, const char *desc, ++ pem_password_cb *pem_cb, void *cb_data, ++ EVP_PKEY **pkey, X509 **cert, STACK_OF(X509) **ca) ++{ ++ const char *pass; ++ char tpass[PEM_BUFSIZE]; ++ int len, ret = 0; ++ PKCS12 *p12; ++ p12 = d2i_PKCS12_bio(in, NULL); ++ if (p12 == NULL) { ++ BIO_printf(bio_err, "Error loading PKCS12 file for %s\n", desc); ++ goto die; ++ } ++ /* See if an empty password will do */ ++ if (PKCS12_verify_mac(p12, "", 0) || PKCS12_verify_mac(p12, NULL, 0)) ++ pass = ""; ++ else { ++ if (!pem_cb) ++ pem_cb = (pem_password_cb *)password_callback; ++ len = pem_cb(tpass, PEM_BUFSIZE, 0, cb_data); ++ if (len < 0) { ++ BIO_printf(bio_err, "Passphrase callback error for %s\n", desc); ++ goto die; ++ } ++ if (len < PEM_BUFSIZE) ++ tpass[len] = 0; ++ if (!PKCS12_verify_mac(p12, tpass, len)) { ++ BIO_printf(bio_err, ++ "Mac verify error (wrong password?) in PKCS12 file for %s\n", ++ desc); ++ goto die; ++ } ++ pass = tpass; ++ } ++ ret = PKCS12_parse(p12, pass, pkey, cert, ca); ++ die: ++ PKCS12_free(p12); ++ return ret; ++} ++ ++#if !defined(OPENSSL_NO_OCSP) && !defined(OPENSSL_NO_SOCK) ++static int load_cert_crl_http(const char *url, X509 **pcert, X509_CRL **pcrl) ++{ ++ char *host = NULL, *port = NULL, *path = NULL; ++ BIO *bio = NULL; ++ OCSP_REQ_CTX *rctx = NULL; ++ int use_ssl, rv = 0; ++ if (!OCSP_parse_url(url, &host, &port, &path, &use_ssl)) ++ goto err; ++ if (use_ssl) { ++ BIO_puts(bio_err, "https not supported\n"); ++ goto err; ++ } ++ bio = BIO_new_connect(host); ++ if (!bio || !BIO_set_conn_port(bio, port)) ++ goto err; ++ rctx = OCSP_REQ_CTX_new(bio, 1024); ++ if (rctx == NULL) ++ goto err; ++ if (!OCSP_REQ_CTX_http(rctx, "GET", path)) ++ goto err; ++ if (!OCSP_REQ_CTX_add1_header(rctx, "Host", host)) ++ goto err; ++ if (pcert) { ++ do { ++ rv = X509_http_nbio(rctx, pcert); ++ } while (rv == -1); ++ } else { ++ do { ++ rv = X509_CRL_http_nbio(rctx, pcrl); ++ } while (rv == -1); ++ } ++ ++ err: ++ OPENSSL_free(host); ++ OPENSSL_free(path); ++ OPENSSL_free(port); ++ if (bio) ++ BIO_free_all(bio); ++ OCSP_REQ_CTX_free(rctx); ++ if (rv != 1) { ++ BIO_printf(bio_err, "Error loading %s from %s\n", ++ pcert ? "certificate" : "CRL", url); ++ ERR_print_errors(bio_err); ++ } ++ return rv; ++} ++#endif ++ ++X509 *load_cert(const char *file, int format, const char *cert_descrip) ++{ ++ X509 *x = NULL; ++ BIO *cert; ++ ++ if (format == FORMAT_HTTP) { ++#if !defined(OPENSSL_NO_OCSP) && !defined(OPENSSL_NO_SOCK) ++ load_cert_crl_http(file, &x, NULL); ++#endif ++ return x; ++ } ++ ++ if (file == NULL) { ++ unbuffer(stdin); ++ cert = dup_bio_in(format); ++ } else ++ cert = bio_open_default(file, 'r', format); ++ if (cert == NULL) ++ goto end; ++ ++ if (format == FORMAT_ASN1) ++ x = d2i_X509_bio(cert, NULL); ++ else if (format == FORMAT_PEM) ++ x = PEM_read_bio_X509_AUX(cert, NULL, ++ (pem_password_cb *)password_callback, NULL); ++ else if (format == FORMAT_PKCS12) { ++ if (!load_pkcs12(cert, cert_descrip, NULL, NULL, NULL, &x, NULL)) ++ goto end; ++ } else { ++ BIO_printf(bio_err, "bad input format specified for %s\n", cert_descrip); ++ goto end; ++ } ++ end: ++ if (x == NULL) { ++ BIO_printf(bio_err, "unable to load certificate\n"); ++ ERR_print_errors(bio_err); ++ } ++ BIO_free(cert); ++ return (x); ++} ++ ++X509_CRL *load_crl(const char *infile, int format) ++{ ++ X509_CRL *x = NULL; ++ BIO *in = NULL; ++ ++ if (format == FORMAT_HTTP) { ++#if !defined(OPENSSL_NO_OCSP) && !defined(OPENSSL_NO_SOCK) ++ load_cert_crl_http(infile, NULL, &x); ++#endif ++ return x; ++ } ++ ++ in = bio_open_default(infile, 'r', format); ++ if (in == NULL) ++ goto end; ++ if (format == FORMAT_ASN1) ++ x = d2i_X509_CRL_bio(in, NULL); ++ else if (format == FORMAT_PEM) ++ x = PEM_read_bio_X509_CRL(in, NULL, NULL, NULL); ++ else { ++ BIO_printf(bio_err, "bad input format specified for input crl\n"); ++ goto end; ++ } ++ if (x == NULL) { ++ BIO_printf(bio_err, "unable to load CRL\n"); ++ ERR_print_errors(bio_err); ++ goto end; ++ } ++ ++ end: ++ BIO_free(in); ++ return (x); ++} ++ ++EVP_PKEY *load_key(const char *file, int format, int maybe_stdin, ++ const char *pass, ENGINE *e, const char *key_descrip) ++{ ++ BIO *key = NULL; ++ EVP_PKEY *pkey = NULL; ++ PW_CB_DATA cb_data; ++ ++ cb_data.password = pass; ++ cb_data.prompt_info = file; ++ ++ if (file == NULL && (!maybe_stdin || format == FORMAT_ENGINE)) { ++ BIO_printf(bio_err, "no keyfile specified\n"); ++ goto end; ++ } ++ if (format == FORMAT_ENGINE) { ++ if (e == NULL) ++ BIO_printf(bio_err, "no engine specified\n"); ++ else { ++#ifndef OPENSSL_NO_ENGINE ++ if (ENGINE_init(e)) { ++ pkey = ENGINE_load_private_key(e, file, ui_method, &cb_data); ++ ENGINE_finish(e); ++ } ++ if (pkey == NULL) { ++ BIO_printf(bio_err, "cannot load %s from engine\n", key_descrip); ++ ERR_print_errors(bio_err); ++ } ++#else ++ BIO_printf(bio_err, "engines not supported\n"); ++#endif ++ } ++ goto end; ++ } ++ if (file == NULL && maybe_stdin) { ++ unbuffer(stdin); ++ key = dup_bio_in(format); ++ } else ++ key = bio_open_default(file, 'r', format); ++ if (key == NULL) ++ goto end; ++ if (format == FORMAT_ASN1) { ++ pkey = d2i_PrivateKey_bio(key, NULL); ++ } else if (format == FORMAT_PEM) { ++ pkey = PEM_read_bio_PrivateKey(key, NULL, ++ (pem_password_cb *)password_callback, ++ &cb_data); ++ } ++ else if (format == FORMAT_PKCS12) { ++ if (!load_pkcs12(key, key_descrip, ++ (pem_password_cb *)password_callback, &cb_data, ++ &pkey, NULL, NULL)) ++ goto end; ++ } ++#if !defined(OPENSSL_NO_RSA) && !defined(OPENSSL_NO_DSA) && !defined (OPENSSL_NO_RC4) ++ else if (format == FORMAT_MSBLOB) ++ pkey = b2i_PrivateKey_bio(key); ++ else if (format == FORMAT_PVK) ++ pkey = b2i_PVK_bio(key, (pem_password_cb *)password_callback, ++ &cb_data); ++#endif ++ else { ++ BIO_printf(bio_err, "bad input format specified for key file\n"); ++ goto end; ++ } ++ end: ++ BIO_free(key); ++ if (pkey == NULL) { ++ BIO_printf(bio_err, "unable to load %s\n", key_descrip); ++ ERR_print_errors(bio_err); ++ } ++ return (pkey); ++} ++ ++EVP_PKEY *load_pubkey(const char *file, int format, int maybe_stdin, ++ const char *pass, ENGINE *e, const char *key_descrip) ++{ ++ BIO *key = NULL; ++ EVP_PKEY *pkey = NULL; ++ PW_CB_DATA cb_data; ++ ++ cb_data.password = pass; ++ cb_data.prompt_info = file; ++ ++ if (file == NULL && (!maybe_stdin || format == FORMAT_ENGINE)) { ++ BIO_printf(bio_err, "no keyfile specified\n"); ++ goto end; ++ } ++ if (format == FORMAT_ENGINE) { ++ if (e == NULL) ++ BIO_printf(bio_err, "no engine specified\n"); ++ else { ++#ifndef OPENSSL_NO_ENGINE ++ pkey = ENGINE_load_public_key(e, file, ui_method, &cb_data); ++ if (pkey == NULL) { ++ BIO_printf(bio_err, "cannot load %s from engine\n", key_descrip); ++ ERR_print_errors(bio_err); ++ } ++#else ++ BIO_printf(bio_err, "engines not supported\n"); ++#endif ++ } ++ goto end; ++ } ++ if (file == NULL && maybe_stdin) { ++ unbuffer(stdin); ++ key = dup_bio_in(format); ++ } else ++ key = bio_open_default(file, 'r', format); ++ if (key == NULL) ++ goto end; ++ if (format == FORMAT_ASN1) { ++ pkey = d2i_PUBKEY_bio(key, NULL); ++ } ++ else if (format == FORMAT_ASN1RSA) { ++#ifndef OPENSSL_NO_RSA ++ RSA *rsa; ++ rsa = d2i_RSAPublicKey_bio(key, NULL); ++ if (rsa) { ++ pkey = EVP_PKEY_new(); ++ if (pkey != NULL) ++ EVP_PKEY_set1_RSA(pkey, rsa); ++ RSA_free(rsa); ++ } else ++#else ++ BIO_printf(bio_err, "RSA keys not supported\n"); ++#endif ++ pkey = NULL; ++ } else if (format == FORMAT_PEMRSA) { ++#ifndef OPENSSL_NO_RSA ++ RSA *rsa; ++ rsa = PEM_read_bio_RSAPublicKey(key, NULL, ++ (pem_password_cb *)password_callback, ++ &cb_data); ++ if (rsa != NULL) { ++ pkey = EVP_PKEY_new(); ++ if (pkey != NULL) ++ EVP_PKEY_set1_RSA(pkey, rsa); ++ RSA_free(rsa); ++ } else ++#else ++ BIO_printf(bio_err, "RSA keys not supported\n"); ++#endif ++ pkey = NULL; ++ } ++ else if (format == FORMAT_PEM) { ++ pkey = PEM_read_bio_PUBKEY(key, NULL, ++ (pem_password_cb *)password_callback, ++ &cb_data); ++ } ++#if !defined(OPENSSL_NO_RSA) && !defined(OPENSSL_NO_DSA) ++ else if (format == FORMAT_MSBLOB) ++ pkey = b2i_PublicKey_bio(key); ++#endif ++ end: ++ BIO_free(key); ++ if (pkey == NULL) ++ BIO_printf(bio_err, "unable to load %s\n", key_descrip); ++ return (pkey); ++} ++ ++static int load_certs_crls(const char *file, int format, ++ const char *pass, const char *desc, ++ STACK_OF(X509) **pcerts, ++ STACK_OF(X509_CRL) **pcrls) ++{ ++ int i; ++ BIO *bio; ++ STACK_OF(X509_INFO) *xis = NULL; ++ X509_INFO *xi; ++ PW_CB_DATA cb_data; ++ int rv = 0; ++ ++ cb_data.password = pass; ++ cb_data.prompt_info = file; ++ ++ if (format != FORMAT_PEM) { ++ BIO_printf(bio_err, "bad input format specified for %s\n", desc); ++ return 0; ++ } ++ ++ bio = bio_open_default(file, 'r', FORMAT_PEM); ++ if (bio == NULL) ++ return 0; ++ ++ xis = PEM_X509_INFO_read_bio(bio, NULL, ++ (pem_password_cb *)password_callback, ++ &cb_data); ++ ++ BIO_free(bio); ++ ++ if (pcerts && *pcerts == NULL) { ++ *pcerts = sk_X509_new_null(); ++ if (!*pcerts) ++ goto end; ++ } ++ ++ if (pcrls && *pcrls == NULL) { ++ *pcrls = sk_X509_CRL_new_null(); ++ if (!*pcrls) ++ goto end; ++ } ++ ++ for (i = 0; i < sk_X509_INFO_num(xis); i++) { ++ xi = sk_X509_INFO_value(xis, i); ++ if (xi->x509 && pcerts) { ++ if (!sk_X509_push(*pcerts, xi->x509)) ++ goto end; ++ xi->x509 = NULL; ++ } ++ if (xi->crl && pcrls) { ++ if (!sk_X509_CRL_push(*pcrls, xi->crl)) ++ goto end; ++ xi->crl = NULL; ++ } ++ } ++ ++ if (pcerts && sk_X509_num(*pcerts) > 0) ++ rv = 1; ++ ++ if (pcrls && sk_X509_CRL_num(*pcrls) > 0) ++ rv = 1; ++ ++ end: ++ ++ sk_X509_INFO_pop_free(xis, X509_INFO_free); ++ ++ if (rv == 0) { ++ if (pcerts) { ++ sk_X509_pop_free(*pcerts, X509_free); ++ *pcerts = NULL; ++ } ++ if (pcrls) { ++ sk_X509_CRL_pop_free(*pcrls, X509_CRL_free); ++ *pcrls = NULL; ++ } ++ BIO_printf(bio_err, "unable to load %s\n", ++ pcerts ? "certificates" : "CRLs"); ++ ERR_print_errors(bio_err); ++ } ++ return rv; ++} ++ ++void* app_malloc(int sz, const char *what) ++{ ++ void *vp = OPENSSL_malloc(sz); ++ ++ if (vp == NULL) { ++ BIO_printf(bio_err, "%s: Could not allocate %d bytes for %s\n", ++ opt_getprog(), sz, what); ++ ERR_print_errors(bio_err); ++ exit(1); ++ } ++ return vp; ++} ++ ++/* ++ * Initialize or extend, if *certs != NULL, a certificate stack. ++ */ ++int load_certs(const char *file, STACK_OF(X509) **certs, int format, ++ const char *pass, const char *desc) ++{ ++ return load_certs_crls(file, format, pass, desc, certs, NULL); ++} ++ ++/* ++ * Initialize or extend, if *crls != NULL, a certificate stack. ++ */ ++int load_crls(const char *file, STACK_OF(X509_CRL) **crls, int format, ++ const char *pass, const char *desc) ++{ ++ return load_certs_crls(file, format, pass, desc, NULL, crls); ++} ++ ++#define X509V3_EXT_UNKNOWN_MASK (0xfL << 16) ++/* Return error for unknown extensions */ ++#define X509V3_EXT_DEFAULT 0 ++/* Print error for unknown extensions */ ++#define X509V3_EXT_ERROR_UNKNOWN (1L << 16) ++/* ASN1 parse unknown extensions */ ++#define X509V3_EXT_PARSE_UNKNOWN (2L << 16) ++/* BIO_dump unknown extensions */ ++#define X509V3_EXT_DUMP_UNKNOWN (3L << 16) ++ ++#define X509_FLAG_CA (X509_FLAG_NO_ISSUER | X509_FLAG_NO_PUBKEY | \ ++ X509_FLAG_NO_HEADER | X509_FLAG_NO_VERSION) ++ ++int set_cert_ex(unsigned long *flags, const char *arg) ++{ ++ static const NAME_EX_TBL cert_tbl[] = { ++ {"compatible", X509_FLAG_COMPAT, 0xffffffffl}, ++ {"ca_default", X509_FLAG_CA, 0xffffffffl}, ++ {"no_header", X509_FLAG_NO_HEADER, 0}, ++ {"no_version", X509_FLAG_NO_VERSION, 0}, ++ {"no_serial", X509_FLAG_NO_SERIAL, 0}, ++ {"no_signame", X509_FLAG_NO_SIGNAME, 0}, ++ {"no_validity", X509_FLAG_NO_VALIDITY, 0}, ++ {"no_subject", X509_FLAG_NO_SUBJECT, 0}, ++ {"no_issuer", X509_FLAG_NO_ISSUER, 0}, ++ {"no_pubkey", X509_FLAG_NO_PUBKEY, 0}, ++ {"no_extensions", X509_FLAG_NO_EXTENSIONS, 0}, ++ {"no_sigdump", X509_FLAG_NO_SIGDUMP, 0}, ++ {"no_aux", X509_FLAG_NO_AUX, 0}, ++ {"no_attributes", X509_FLAG_NO_ATTRIBUTES, 0}, ++ {"ext_default", X509V3_EXT_DEFAULT, X509V3_EXT_UNKNOWN_MASK}, ++ {"ext_error", X509V3_EXT_ERROR_UNKNOWN, X509V3_EXT_UNKNOWN_MASK}, ++ {"ext_parse", X509V3_EXT_PARSE_UNKNOWN, X509V3_EXT_UNKNOWN_MASK}, ++ {"ext_dump", X509V3_EXT_DUMP_UNKNOWN, X509V3_EXT_UNKNOWN_MASK}, ++ {NULL, 0, 0} ++ }; ++ return set_multi_opts(flags, arg, cert_tbl); ++} ++ ++int set_name_ex(unsigned long *flags, const char *arg) ++{ ++ static const NAME_EX_TBL ex_tbl[] = { ++ {"esc_2253", ASN1_STRFLGS_ESC_2253, 0}, ++ {"esc_2254", ASN1_STRFLGS_ESC_2254, 0}, ++ {"esc_ctrl", ASN1_STRFLGS_ESC_CTRL, 0}, ++ {"esc_msb", ASN1_STRFLGS_ESC_MSB, 0}, ++ {"use_quote", ASN1_STRFLGS_ESC_QUOTE, 0}, ++ {"utf8", ASN1_STRFLGS_UTF8_CONVERT, 0}, ++ {"ignore_type", ASN1_STRFLGS_IGNORE_TYPE, 0}, ++ {"show_type", ASN1_STRFLGS_SHOW_TYPE, 0}, ++ {"dump_all", ASN1_STRFLGS_DUMP_ALL, 0}, ++ {"dump_nostr", ASN1_STRFLGS_DUMP_UNKNOWN, 0}, ++ {"dump_der", ASN1_STRFLGS_DUMP_DER, 0}, ++ {"compat", XN_FLAG_COMPAT, 0xffffffffL}, ++ {"sep_comma_plus", XN_FLAG_SEP_COMMA_PLUS, XN_FLAG_SEP_MASK}, ++ {"sep_comma_plus_space", XN_FLAG_SEP_CPLUS_SPC, XN_FLAG_SEP_MASK}, ++ {"sep_semi_plus_space", XN_FLAG_SEP_SPLUS_SPC, XN_FLAG_SEP_MASK}, ++ {"sep_multiline", XN_FLAG_SEP_MULTILINE, XN_FLAG_SEP_MASK}, ++ {"dn_rev", XN_FLAG_DN_REV, 0}, ++ {"nofname", XN_FLAG_FN_NONE, XN_FLAG_FN_MASK}, ++ {"sname", XN_FLAG_FN_SN, XN_FLAG_FN_MASK}, ++ {"lname", XN_FLAG_FN_LN, XN_FLAG_FN_MASK}, ++ {"align", XN_FLAG_FN_ALIGN, 0}, ++ {"oid", XN_FLAG_FN_OID, XN_FLAG_FN_MASK}, ++ {"space_eq", XN_FLAG_SPC_EQ, 0}, ++ {"dump_unknown", XN_FLAG_DUMP_UNKNOWN_FIELDS, 0}, ++ {"RFC2253", XN_FLAG_RFC2253, 0xffffffffL}, ++ {"oneline", XN_FLAG_ONELINE, 0xffffffffL}, ++ {"multiline", XN_FLAG_MULTILINE, 0xffffffffL}, ++ {"ca_default", XN_FLAG_MULTILINE, 0xffffffffL}, ++ {NULL, 0, 0} ++ }; ++ if (set_multi_opts(flags, arg, ex_tbl) == 0) ++ return 0; ++ if ((*flags & XN_FLAG_SEP_MASK) == 0) ++ *flags |= XN_FLAG_SEP_CPLUS_SPC; ++ return 1; ++} ++ ++int set_ext_copy(int *copy_type, const char *arg) ++{ ++ if (strcasecmp(arg, "none") == 0) ++ *copy_type = EXT_COPY_NONE; ++ else if (strcasecmp(arg, "copy") == 0) ++ *copy_type = EXT_COPY_ADD; ++ else if (strcasecmp(arg, "copyall") == 0) ++ *copy_type = EXT_COPY_ALL; ++ else ++ return 0; ++ return 1; ++} ++ ++int copy_extensions(X509 *x, X509_REQ *req, int copy_type) ++{ ++ STACK_OF(X509_EXTENSION) *exts = NULL; ++ X509_EXTENSION *ext, *tmpext; ++ ASN1_OBJECT *obj; ++ int i, idx, ret = 0; ++ if (!x || !req || (copy_type == EXT_COPY_NONE)) ++ return 1; ++ exts = X509_REQ_get_extensions(req); ++ ++ for (i = 0; i < sk_X509_EXTENSION_num(exts); i++) { ++ ext = sk_X509_EXTENSION_value(exts, i); ++ obj = X509_EXTENSION_get_object(ext); ++ idx = X509_get_ext_by_OBJ(x, obj, -1); ++ /* Does extension exist? */ ++ if (idx != -1) { ++ /* If normal copy don't override existing extension */ ++ if (copy_type == EXT_COPY_ADD) ++ continue; ++ /* Delete all extensions of same type */ ++ do { ++ tmpext = X509_get_ext(x, idx); ++ X509_delete_ext(x, idx); ++ X509_EXTENSION_free(tmpext); ++ idx = X509_get_ext_by_OBJ(x, obj, -1); ++ } while (idx != -1); ++ } ++ if (!X509_add_ext(x, ext, -1)) ++ goto end; ++ } ++ ++ ret = 1; ++ ++ end: ++ ++ sk_X509_EXTENSION_pop_free(exts, X509_EXTENSION_free); ++ ++ return ret; ++} ++ ++static int set_multi_opts(unsigned long *flags, const char *arg, ++ const NAME_EX_TBL * in_tbl) ++{ ++ STACK_OF(CONF_VALUE) *vals; ++ CONF_VALUE *val; ++ int i, ret = 1; ++ if (!arg) ++ return 0; ++ vals = X509V3_parse_list(arg); ++ for (i = 0; i < sk_CONF_VALUE_num(vals); i++) { ++ val = sk_CONF_VALUE_value(vals, i); ++ if (!set_table_opts(flags, val->name, in_tbl)) ++ ret = 0; ++ } ++ sk_CONF_VALUE_pop_free(vals, X509V3_conf_free); ++ return ret; ++} ++ ++static int set_table_opts(unsigned long *flags, const char *arg, ++ const NAME_EX_TBL * in_tbl) ++{ ++ char c; ++ const NAME_EX_TBL *ptbl; ++ c = arg[0]; ++ ++ if (c == '-') { ++ c = 0; ++ arg++; ++ } else if (c == '+') { ++ c = 1; ++ arg++; ++ } else ++ c = 1; ++ ++ for (ptbl = in_tbl; ptbl->name; ptbl++) { ++ if (strcasecmp(arg, ptbl->name) == 0) { ++ *flags &= ~ptbl->mask; ++ if (c) ++ *flags |= ptbl->flag; ++ else ++ *flags &= ~ptbl->flag; ++ return 1; ++ } ++ } ++ return 0; ++} ++ ++void print_name(BIO *out, const char *title, X509_NAME *nm, ++ unsigned long lflags) ++{ ++ char *buf; ++ char mline = 0; ++ int indent = 0; ++ ++ if (title) ++ BIO_puts(out, title); ++ if ((lflags & XN_FLAG_SEP_MASK) == XN_FLAG_SEP_MULTILINE) { ++ mline = 1; ++ indent = 4; ++ } ++ if (lflags == XN_FLAG_COMPAT) { ++ buf = X509_NAME_oneline(nm, 0, 0); ++ BIO_puts(out, buf); ++ BIO_puts(out, "\n"); ++ OPENSSL_free(buf); ++ } else { ++ if (mline) ++ BIO_puts(out, "\n"); ++ X509_NAME_print_ex(out, nm, indent, lflags); ++ BIO_puts(out, "\n"); ++ } ++} ++ ++void print_bignum_var(BIO *out, const BIGNUM *in, const char *var, ++ int len, unsigned char *buffer) ++{ ++ BIO_printf(out, " static unsigned char %s_%d[] = {", var, len); ++ if (BN_is_zero(in)) ++ BIO_printf(out, "\n\t0x00"); ++ else { ++ int i, l; ++ ++ l = BN_bn2bin(in, buffer); ++ for (i = 0; i < l; i++) { ++ if ((i % 10) == 0) ++ BIO_printf(out, "\n\t"); ++ if (i < l - 1) ++ BIO_printf(out, "0x%02X, ", buffer[i]); ++ else ++ BIO_printf(out, "0x%02X", buffer[i]); ++ } ++ } ++ BIO_printf(out, "\n };\n"); ++} ++void print_array(BIO *out, const char* title, int len, const unsigned char* d) ++{ ++ int i; ++ ++ BIO_printf(out, "unsigned char %s[%d] = {", title, len); ++ for (i = 0; i < len; i++) { ++ if ((i % 10) == 0) ++ BIO_printf(out, "\n "); ++ if (i < len - 1) ++ BIO_printf(out, "0x%02X, ", d[i]); ++ else ++ BIO_printf(out, "0x%02X", d[i]); ++ } ++ BIO_printf(out, "\n};\n"); ++} ++ ++X509_STORE *setup_verify(const char *CAfile, const char *CApath, int noCAfile, int noCApath) ++{ ++ X509_STORE *store = X509_STORE_new(); ++ X509_LOOKUP *lookup; ++ ++ if (store == NULL) ++ goto end; ++ ++ if (CAfile != NULL || !noCAfile) { ++ lookup = X509_STORE_add_lookup(store, X509_LOOKUP_file()); ++ if (lookup == NULL) ++ goto end; ++ if (CAfile) { ++ if (!X509_LOOKUP_load_file(lookup, CAfile, X509_FILETYPE_PEM)) { ++ BIO_printf(bio_err, "Error loading file %s\n", CAfile); ++ goto end; ++ } ++ } else ++ X509_LOOKUP_load_file(lookup, NULL, X509_FILETYPE_DEFAULT); ++ } ++ ++ if (CApath != NULL || !noCApath) { ++ lookup = X509_STORE_add_lookup(store, X509_LOOKUP_hash_dir()); ++ if (lookup == NULL) ++ goto end; ++ if (CApath) { ++ if (!X509_LOOKUP_add_dir(lookup, CApath, X509_FILETYPE_PEM)) { ++ BIO_printf(bio_err, "Error loading directory %s\n", CApath); ++ goto end; ++ } ++ } else ++ X509_LOOKUP_add_dir(lookup, NULL, X509_FILETYPE_DEFAULT); ++ } ++ ++ ERR_clear_error(); ++ return store; ++ end: ++ X509_STORE_free(store); ++ return NULL; ++} ++ ++#ifndef OPENSSL_NO_ENGINE ++/* Try to load an engine in a shareable library */ ++static ENGINE *try_load_engine(const char *engine) ++{ ++ ENGINE *e = ENGINE_by_id("dynamic"); ++ if (e) { ++ if (!ENGINE_ctrl_cmd_string(e, "SO_PATH", engine, 0) ++ || !ENGINE_ctrl_cmd_string(e, "LOAD", NULL, 0)) { ++ ENGINE_free(e); ++ e = NULL; ++ } ++ } ++ return e; ++} ++#endif ++ ++ENGINE *setup_engine(const char *engine, int debug) ++{ ++ ENGINE *e = NULL; ++ ++#ifndef OPENSSL_NO_ENGINE ++ if (engine) { ++ if (strcmp(engine, "auto") == 0) { ++ BIO_printf(bio_err, "enabling auto ENGINE support\n"); ++ ENGINE_register_all_complete(); ++ return NULL; ++ } ++ if ((e = ENGINE_by_id(engine)) == NULL ++ && (e = try_load_engine(engine)) == NULL) { ++ BIO_printf(bio_err, "invalid engine \"%s\"\n", engine); ++ ERR_print_errors(bio_err); ++ return NULL; ++ } ++ if (debug) { ++ ENGINE_ctrl(e, ENGINE_CTRL_SET_LOGSTREAM, 0, bio_err, 0); ++ } ++ ENGINE_ctrl_cmd(e, "SET_USER_INTERFACE", 0, ui_method, 0, 1); ++ if (!ENGINE_set_default(e, ENGINE_METHOD_ALL)) { ++ BIO_printf(bio_err, "can't use that engine\n"); ++ ERR_print_errors(bio_err); ++ ENGINE_free(e); ++ return NULL; ++ } ++ ++ BIO_printf(bio_err, "engine \"%s\" set.\n", ENGINE_get_id(e)); ++ } ++#endif ++ return e; ++} ++ ++void release_engine(ENGINE *e) ++{ ++#ifndef OPENSSL_NO_ENGINE ++ if (e != NULL) ++ /* Free our "structural" reference. */ ++ ENGINE_free(e); ++#endif ++} ++ ++static unsigned long index_serial_hash(const OPENSSL_CSTRING *a) ++{ ++ const char *n; ++ ++ n = a[DB_serial]; ++ while (*n == '0') ++ n++; ++ return OPENSSL_LH_strhash(n); ++} ++ ++static int index_serial_cmp(const OPENSSL_CSTRING *a, ++ const OPENSSL_CSTRING *b) ++{ ++ const char *aa, *bb; ++ ++ for (aa = a[DB_serial]; *aa == '0'; aa++) ; ++ for (bb = b[DB_serial]; *bb == '0'; bb++) ; ++ return (strcmp(aa, bb)); ++} ++ ++static int index_name_qual(char **a) ++{ ++ return (a[0][0] == 'V'); ++} ++ ++static unsigned long index_name_hash(const OPENSSL_CSTRING *a) ++{ ++ return OPENSSL_LH_strhash(a[DB_name]); ++} ++ ++int index_name_cmp(const OPENSSL_CSTRING *a, const OPENSSL_CSTRING *b) ++{ ++ return (strcmp(a[DB_name], b[DB_name])); ++} ++ ++static IMPLEMENT_LHASH_HASH_FN(index_serial, OPENSSL_CSTRING) ++static IMPLEMENT_LHASH_COMP_FN(index_serial, OPENSSL_CSTRING) ++static IMPLEMENT_LHASH_HASH_FN(index_name, OPENSSL_CSTRING) ++static IMPLEMENT_LHASH_COMP_FN(index_name, OPENSSL_CSTRING) ++#undef BSIZE ++#define BSIZE 256 ++BIGNUM *load_serial(const char *serialfile, int create, ASN1_INTEGER **retai) ++{ ++ BIO *in = NULL; ++ BIGNUM *ret = NULL; ++ char buf[1024]; ++ ASN1_INTEGER *ai = NULL; ++ ++ ai = ASN1_INTEGER_new(); ++ if (ai == NULL) ++ goto err; ++ ++ in = BIO_new_file(serialfile, "r"); ++ if (in == NULL) { ++ if (!create) { ++ perror(serialfile); ++ goto err; ++ } ++ ERR_clear_error(); ++ ret = BN_new(); ++ if (ret == NULL || !rand_serial(ret, ai)) ++ BIO_printf(bio_err, "Out of memory\n"); ++ } else { ++ if (!a2i_ASN1_INTEGER(in, ai, buf, 1024)) { ++ BIO_printf(bio_err, "unable to load number from %s\n", ++ serialfile); ++ goto err; ++ } ++ ret = ASN1_INTEGER_to_BN(ai, NULL); ++ if (ret == NULL) { ++ BIO_printf(bio_err, ++ "error converting number from bin to BIGNUM\n"); ++ goto err; ++ } ++ } ++ ++ if (ret && retai) { ++ *retai = ai; ++ ai = NULL; ++ } ++ err: ++ BIO_free(in); ++ ASN1_INTEGER_free(ai); ++ return (ret); ++} ++ ++int save_serial(const char *serialfile, const char *suffix, const BIGNUM *serial, ++ ASN1_INTEGER **retai) ++{ ++ char buf[1][BSIZE]; ++ BIO *out = NULL; ++ int ret = 0; ++ ASN1_INTEGER *ai = NULL; ++ int j; ++ ++ if (suffix == NULL) ++ j = strlen(serialfile); ++ else ++ j = strlen(serialfile) + strlen(suffix) + 1; ++ if (j >= BSIZE) { ++ BIO_printf(bio_err, "file name too long\n"); ++ goto err; ++ } ++ ++ if (suffix == NULL) ++ OPENSSL_strlcpy(buf[0], serialfile, BSIZE); ++ else { ++#ifndef OPENSSL_SYS_VMS ++ j = BIO_snprintf(buf[0], sizeof buf[0], "%s.%s", serialfile, suffix); ++#else ++ j = BIO_snprintf(buf[0], sizeof buf[0], "%s-%s", serialfile, suffix); ++#endif ++ } ++ out = BIO_new_file(buf[0], "w"); ++ if (out == NULL) { ++ ERR_print_errors(bio_err); ++ goto err; ++ } ++ ++ if ((ai = BN_to_ASN1_INTEGER(serial, NULL)) == NULL) { ++ BIO_printf(bio_err, "error converting serial to ASN.1 format\n"); ++ goto err; ++ } ++ i2a_ASN1_INTEGER(out, ai); ++ BIO_puts(out, "\n"); ++ ret = 1; ++ if (retai) { ++ *retai = ai; ++ ai = NULL; ++ } ++ err: ++ BIO_free_all(out); ++ ASN1_INTEGER_free(ai); ++ return (ret); ++} ++ ++int rotate_serial(const char *serialfile, const char *new_suffix, ++ const char *old_suffix) ++{ ++ char buf[2][BSIZE]; ++ int i, j; ++ ++ i = strlen(serialfile) + strlen(old_suffix); ++ j = strlen(serialfile) + strlen(new_suffix); ++ if (i > j) ++ j = i; ++ if (j + 1 >= BSIZE) { ++ BIO_printf(bio_err, "file name too long\n"); ++ goto err; ++ } ++#ifndef OPENSSL_SYS_VMS ++ j = BIO_snprintf(buf[0], sizeof buf[0], "%s.%s", serialfile, new_suffix); ++ j = BIO_snprintf(buf[1], sizeof buf[1], "%s.%s", serialfile, old_suffix); ++#else ++ j = BIO_snprintf(buf[0], sizeof buf[0], "%s-%s", serialfile, new_suffix); ++ j = BIO_snprintf(buf[1], sizeof buf[1], "%s-%s", serialfile, old_suffix); ++#endif ++ if (rename(serialfile, buf[1]) < 0 && errno != ENOENT ++#ifdef ENOTDIR ++ && errno != ENOTDIR ++#endif ++ ) { ++ BIO_printf(bio_err, ++ "unable to rename %s to %s\n", serialfile, buf[1]); ++ perror("reason"); ++ goto err; ++ } ++ if (rename(buf[0], serialfile) < 0) { ++ BIO_printf(bio_err, ++ "unable to rename %s to %s\n", buf[0], serialfile); ++ perror("reason"); ++ rename(buf[1], serialfile); ++ goto err; ++ } ++ return 1; ++ err: ++ return 0; ++} ++ ++int rand_serial(BIGNUM *b, ASN1_INTEGER *ai) ++{ ++ BIGNUM *btmp; ++ int ret = 0; ++ ++ if (b) ++ btmp = b; ++ else ++ btmp = BN_new(); ++ ++ if (btmp == NULL) ++ return 0; ++ ++ if (!BN_pseudo_rand(btmp, SERIAL_RAND_BITS, 0, 0)) ++ goto error; ++ if (ai && !BN_to_ASN1_INTEGER(btmp, ai)) ++ goto error; ++ ++ ret = 1; ++ ++ error: ++ ++ if (btmp != b) ++ BN_free(btmp); ++ ++ return ret; ++} ++ ++CA_DB *load_index(const char *dbfile, DB_ATTR *db_attr) ++{ ++ CA_DB *retdb = NULL; ++ TXT_DB *tmpdb = NULL; ++ BIO *in; ++ CONF *dbattr_conf = NULL; ++ char buf[BSIZE]; ++ ++ in = BIO_new_file(dbfile, "r"); ++ if (in == NULL) { ++ ERR_print_errors(bio_err); ++ goto err; ++ } ++ if ((tmpdb = TXT_DB_read(in, DB_NUMBER)) == NULL) ++ goto err; ++ ++#ifndef OPENSSL_SYS_VMS ++ BIO_snprintf(buf, sizeof buf, "%s.attr", dbfile); ++#else ++ BIO_snprintf(buf, sizeof buf, "%s-attr", dbfile); ++#endif ++ dbattr_conf = app_load_config(buf); ++ ++ retdb = app_malloc(sizeof(*retdb), "new DB"); ++ retdb->db = tmpdb; ++ tmpdb = NULL; ++ if (db_attr) ++ retdb->attributes = *db_attr; ++ else { ++ retdb->attributes.unique_subject = 1; ++ } ++ ++ if (dbattr_conf) { ++ char *p = NCONF_get_string(dbattr_conf, NULL, "unique_subject"); ++ if (p) { ++ retdb->attributes.unique_subject = parse_yesno(p, 1); ++ } ++ } ++ ++ err: ++ NCONF_free(dbattr_conf); ++ TXT_DB_free(tmpdb); ++ BIO_free_all(in); ++ return retdb; ++} ++ ++int index_index(CA_DB *db) ++{ ++ if (!TXT_DB_create_index(db->db, DB_serial, NULL, ++ LHASH_HASH_FN(index_serial), ++ LHASH_COMP_FN(index_serial))) { ++ BIO_printf(bio_err, ++ "error creating serial number index:(%ld,%ld,%ld)\n", ++ db->db->error, db->db->arg1, db->db->arg2); ++ return 0; ++ } ++ ++ if (db->attributes.unique_subject ++ && !TXT_DB_create_index(db->db, DB_name, index_name_qual, ++ LHASH_HASH_FN(index_name), ++ LHASH_COMP_FN(index_name))) { ++ BIO_printf(bio_err, "error creating name index:(%ld,%ld,%ld)\n", ++ db->db->error, db->db->arg1, db->db->arg2); ++ return 0; ++ } ++ return 1; ++} ++ ++int save_index(const char *dbfile, const char *suffix, CA_DB *db) ++{ ++ char buf[3][BSIZE]; ++ BIO *out; ++ int j; ++ ++ j = strlen(dbfile) + strlen(suffix); ++ if (j + 6 >= BSIZE) { ++ BIO_printf(bio_err, "file name too long\n"); ++ goto err; ++ } ++#ifndef OPENSSL_SYS_VMS ++ j = BIO_snprintf(buf[2], sizeof buf[2], "%s.attr", dbfile); ++ j = BIO_snprintf(buf[1], sizeof buf[1], "%s.attr.%s", dbfile, suffix); ++ j = BIO_snprintf(buf[0], sizeof buf[0], "%s.%s", dbfile, suffix); ++#else ++ j = BIO_snprintf(buf[2], sizeof buf[2], "%s-attr", dbfile); ++ j = BIO_snprintf(buf[1], sizeof buf[1], "%s-attr-%s", dbfile, suffix); ++ j = BIO_snprintf(buf[0], sizeof buf[0], "%s-%s", dbfile, suffix); ++#endif ++ out = BIO_new_file(buf[0], "w"); ++ if (out == NULL) { ++ perror(dbfile); ++ BIO_printf(bio_err, "unable to open '%s'\n", dbfile); ++ goto err; ++ } ++ j = TXT_DB_write(out, db->db); ++ BIO_free(out); ++ if (j <= 0) ++ goto err; ++ ++ out = BIO_new_file(buf[1], "w"); ++ if (out == NULL) { ++ perror(buf[2]); ++ BIO_printf(bio_err, "unable to open '%s'\n", buf[2]); ++ goto err; ++ } ++ BIO_printf(out, "unique_subject = %s\n", ++ db->attributes.unique_subject ? "yes" : "no"); ++ BIO_free(out); ++ ++ return 1; ++ err: ++ return 0; ++} ++ ++int rotate_index(const char *dbfile, const char *new_suffix, ++ const char *old_suffix) ++{ ++ char buf[5][BSIZE]; ++ int i, j; ++ ++ i = strlen(dbfile) + strlen(old_suffix); ++ j = strlen(dbfile) + strlen(new_suffix); ++ if (i > j) ++ j = i; ++ if (j + 6 >= BSIZE) { ++ BIO_printf(bio_err, "file name too long\n"); ++ goto err; ++ } ++#ifndef OPENSSL_SYS_VMS ++ j = BIO_snprintf(buf[4], sizeof buf[4], "%s.attr", dbfile); ++ j = BIO_snprintf(buf[3], sizeof buf[3], "%s.attr.%s", dbfile, old_suffix); ++ j = BIO_snprintf(buf[2], sizeof buf[2], "%s.attr.%s", dbfile, new_suffix); ++ j = BIO_snprintf(buf[1], sizeof buf[1], "%s.%s", dbfile, old_suffix); ++ j = BIO_snprintf(buf[0], sizeof buf[0], "%s.%s", dbfile, new_suffix); ++#else ++ j = BIO_snprintf(buf[4], sizeof buf[4], "%s-attr", dbfile); ++ j = BIO_snprintf(buf[3], sizeof buf[3], "%s-attr-%s", dbfile, old_suffix); ++ j = BIO_snprintf(buf[2], sizeof buf[2], "%s-attr-%s", dbfile, new_suffix); ++ j = BIO_snprintf(buf[1], sizeof buf[1], "%s-%s", dbfile, old_suffix); ++ j = BIO_snprintf(buf[0], sizeof buf[0], "%s-%s", dbfile, new_suffix); ++#endif ++ if (rename(dbfile, buf[1]) < 0 && errno != ENOENT ++#ifdef ENOTDIR ++ && errno != ENOTDIR ++#endif ++ ) { ++ BIO_printf(bio_err, "unable to rename %s to %s\n", dbfile, buf[1]); ++ perror("reason"); ++ goto err; ++ } ++ if (rename(buf[0], dbfile) < 0) { ++ BIO_printf(bio_err, "unable to rename %s to %s\n", buf[0], dbfile); ++ perror("reason"); ++ rename(buf[1], dbfile); ++ goto err; ++ } ++ if (rename(buf[4], buf[3]) < 0 && errno != ENOENT ++#ifdef ENOTDIR ++ && errno != ENOTDIR ++#endif ++ ) { ++ BIO_printf(bio_err, "unable to rename %s to %s\n", buf[4], buf[3]); ++ perror("reason"); ++ rename(dbfile, buf[0]); ++ rename(buf[1], dbfile); ++ goto err; ++ } ++ if (rename(buf[2], buf[4]) < 0) { ++ BIO_printf(bio_err, "unable to rename %s to %s\n", buf[2], buf[4]); ++ perror("reason"); ++ rename(buf[3], buf[4]); ++ rename(dbfile, buf[0]); ++ rename(buf[1], dbfile); ++ goto err; ++ } ++ return 1; ++ err: ++ return 0; ++} ++ ++void free_index(CA_DB *db) ++{ ++ if (db) { ++ TXT_DB_free(db->db); ++ OPENSSL_free(db); ++ } ++} ++ ++int parse_yesno(const char *str, int def) ++{ ++ if (str) { ++ switch (*str) { ++ case 'f': /* false */ ++ case 'F': /* FALSE */ ++ case 'n': /* no */ ++ case 'N': /* NO */ ++ case '0': /* 0 */ ++ return 0; ++ case 't': /* true */ ++ case 'T': /* TRUE */ ++ case 'y': /* yes */ ++ case 'Y': /* YES */ ++ case '1': /* 1 */ ++ return 1; ++ } ++ } ++ return def; ++} ++ ++/* ++ * name is expected to be in the format /type0=value0/type1=value1/type2=... ++ * where characters may be escaped by \ ++ */ ++X509_NAME *parse_name(const char *cp, long chtype, int canmulti) ++{ ++ int nextismulti = 0; ++ char *work; ++ X509_NAME *n; ++ ++ if (*cp++ != '/') ++ return NULL; ++ ++ n = X509_NAME_new(); ++ if (n == NULL) ++ return NULL; ++ work = OPENSSL_strdup(cp); ++ if (work == NULL) ++ goto err; ++ ++ while (*cp) { ++ char *bp = work; ++ char *typestr = bp; ++ unsigned char *valstr; ++ int nid; ++ int ismulti = nextismulti; ++ nextismulti = 0; ++ ++ /* Collect the type */ ++ while (*cp && *cp != '=') ++ *bp++ = *cp++; ++ if (*cp == '\0') { ++ BIO_printf(bio_err, ++ "%s: Hit end of string before finding the equals.\n", ++ opt_getprog()); ++ goto err; ++ } ++ *bp++ = '\0'; ++ ++cp; ++ ++ /* Collect the value. */ ++ valstr = (unsigned char *)bp; ++ for (; *cp && *cp != '/'; *bp++ = *cp++) { ++ if (canmulti && *cp == '+') { ++ nextismulti = 1; ++ break; ++ } ++ if (*cp == '\\' && *++cp == '\0') { ++ BIO_printf(bio_err, ++ "%s: escape character at end of string\n", ++ opt_getprog()); ++ goto err; ++ } ++ } ++ *bp++ = '\0'; ++ ++ /* If not at EOS (must be + or /), move forward. */ ++ if (*cp) ++ ++cp; ++ ++ /* Parse */ ++ nid = OBJ_txt2nid(typestr); ++ if (nid == NID_undef) { ++ BIO_printf(bio_err, "%s: Skipping unknown attribute \"%s\"\n", ++ opt_getprog(), typestr); ++ continue; ++ } ++ if (!X509_NAME_add_entry_by_NID(n, nid, chtype, ++ valstr, strlen((char *)valstr), ++ -1, ismulti ? -1 : 0)) ++ goto err; ++ } ++ ++ OPENSSL_free(work); ++ return n; ++ ++ err: ++ X509_NAME_free(n); ++ OPENSSL_free(work); ++ return NULL; ++} ++ ++/* ++ * Read whole contents of a BIO into an allocated memory buffer and return ++ * it. ++ */ ++ ++int bio_to_mem(unsigned char **out, int maxlen, BIO *in) ++{ ++ BIO *mem; ++ int len, ret; ++ unsigned char tbuf[1024]; ++ ++ mem = BIO_new(BIO_s_mem()); ++ if (mem == NULL) ++ return -1; ++ for (;;) { ++ if ((maxlen != -1) && maxlen < 1024) ++ len = maxlen; ++ else ++ len = 1024; ++ len = BIO_read(in, tbuf, len); ++ if (len < 0) { ++ BIO_free(mem); ++ return -1; ++ } ++ if (len == 0) ++ break; ++ if (BIO_write(mem, tbuf, len) != len) { ++ BIO_free(mem); ++ return -1; ++ } ++ maxlen -= len; ++ ++ if (maxlen == 0) ++ break; ++ } ++ ret = BIO_get_mem_data(mem, (char **)out); ++ BIO_set_flags(mem, BIO_FLAGS_MEM_RDONLY); ++ BIO_free(mem); ++ return ret; ++} ++ ++int pkey_ctrl_string(EVP_PKEY_CTX *ctx, const char *value) ++{ ++ int rv; ++ char *stmp, *vtmp = NULL; ++ stmp = OPENSSL_strdup(value); ++ if (!stmp) ++ return -1; ++ vtmp = strchr(stmp, ':'); ++ if (vtmp) { ++ *vtmp = 0; ++ vtmp++; ++ } ++ rv = EVP_PKEY_CTX_ctrl_str(ctx, stmp, vtmp); ++ OPENSSL_free(stmp); ++ return rv; ++} ++ ++static void nodes_print(const char *name, STACK_OF(X509_POLICY_NODE) *nodes) ++{ ++ X509_POLICY_NODE *node; ++ int i; ++ ++ BIO_printf(bio_err, "%s Policies:", name); ++ if (nodes) { ++ BIO_puts(bio_err, "\n"); ++ for (i = 0; i < sk_X509_POLICY_NODE_num(nodes); i++) { ++ node = sk_X509_POLICY_NODE_value(nodes, i); ++ X509_POLICY_NODE_print(bio_err, node, 2); ++ } ++ } else ++ BIO_puts(bio_err, " \n"); ++} ++ ++void policies_print(X509_STORE_CTX *ctx) ++{ ++ X509_POLICY_TREE *tree; ++ int explicit_policy; ++ tree = X509_STORE_CTX_get0_policy_tree(ctx); ++ explicit_policy = X509_STORE_CTX_get_explicit_policy(ctx); ++ ++ BIO_printf(bio_err, "Require explicit Policy: %s\n", ++ explicit_policy ? "True" : "False"); ++ ++ nodes_print("Authority", X509_policy_tree_get0_policies(tree)); ++ nodes_print("User", X509_policy_tree_get0_user_policies(tree)); ++} ++ ++/*- ++ * next_protos_parse parses a comma separated list of strings into a string ++ * in a format suitable for passing to SSL_CTX_set_next_protos_advertised. ++ * outlen: (output) set to the length of the resulting buffer on success. ++ * err: (maybe NULL) on failure, an error message line is written to this BIO. ++ * in: a NUL terminated string like "abc,def,ghi" ++ * ++ * returns: a malloc'd buffer or NULL on failure. ++ */ ++unsigned char *next_protos_parse(size_t *outlen, const char *in) ++{ ++ size_t len; ++ unsigned char *out; ++ size_t i, start = 0; ++ ++ len = strlen(in); ++ if (len >= 65535) ++ return NULL; ++ ++ out = app_malloc(strlen(in) + 1, "NPN buffer"); ++ for (i = 0; i <= len; ++i) { ++ if (i == len || in[i] == ',') { ++ if (i - start > 255) { ++ OPENSSL_free(out); ++ return NULL; ++ } ++ out[start] = i - start; ++ start = i + 1; ++ } else ++ out[i + 1] = in[i]; ++ } ++ ++ *outlen = len + 1; ++ return out; ++} ++ ++void print_cert_checks(BIO *bio, X509 *x, ++ const char *checkhost, ++ const char *checkemail, const char *checkip) ++{ ++ if (x == NULL) ++ return; ++ if (checkhost) { ++ BIO_printf(bio, "Hostname %s does%s match certificate\n", ++ checkhost, ++ X509_check_host(x, checkhost, 0, 0, NULL) == 1 ++ ? "" : " NOT"); ++ } ++ ++ if (checkemail) { ++ BIO_printf(bio, "Email %s does%s match certificate\n", ++ checkemail, X509_check_email(x, checkemail, 0, 0) ++ ? "" : " NOT"); ++ } ++ ++ if (checkip) { ++ BIO_printf(bio, "IP %s does%s match certificate\n", ++ checkip, X509_check_ip_asc(x, checkip, 0) ? "" : " NOT"); ++ } ++} ++ ++/* Get first http URL from a DIST_POINT structure */ ++ ++static const char *get_dp_url(DIST_POINT *dp) ++{ ++ GENERAL_NAMES *gens; ++ GENERAL_NAME *gen; ++ int i, gtype; ++ ASN1_STRING *uri; ++ if (!dp->distpoint || dp->distpoint->type != 0) ++ return NULL; ++ gens = dp->distpoint->name.fullname; ++ for (i = 0; i < sk_GENERAL_NAME_num(gens); i++) { ++ gen = sk_GENERAL_NAME_value(gens, i); ++ uri = GENERAL_NAME_get0_value(gen, >ype); ++ if (gtype == GEN_URI && ASN1_STRING_length(uri) > 6) { ++ const char *uptr = (const char *)ASN1_STRING_get0_data(uri); ++ if (strncmp(uptr, "http://", 7) == 0) ++ return uptr; ++ } ++ } ++ return NULL; ++} ++ ++/* ++ * Look through a CRLDP structure and attempt to find an http URL to ++ * downloads a CRL from. ++ */ ++ ++static X509_CRL *load_crl_crldp(STACK_OF(DIST_POINT) *crldp) ++{ ++ int i; ++ const char *urlptr = NULL; ++ for (i = 0; i < sk_DIST_POINT_num(crldp); i++) { ++ DIST_POINT *dp = sk_DIST_POINT_value(crldp, i); ++ urlptr = get_dp_url(dp); ++ if (urlptr) ++ return load_crl(urlptr, FORMAT_HTTP); ++ } ++ return NULL; ++} ++ ++/* ++ * Example of downloading CRLs from CRLDP: not usable for real world as it ++ * always downloads, doesn't support non-blocking I/O and doesn't cache ++ * anything. ++ */ ++ ++static STACK_OF(X509_CRL) *crls_http_cb(X509_STORE_CTX *ctx, X509_NAME *nm) ++{ ++ X509 *x; ++ STACK_OF(X509_CRL) *crls = NULL; ++ X509_CRL *crl; ++ STACK_OF(DIST_POINT) *crldp; ++ ++ crls = sk_X509_CRL_new_null(); ++ if (!crls) ++ return NULL; ++ x = X509_STORE_CTX_get_current_cert(ctx); ++ crldp = X509_get_ext_d2i(x, NID_crl_distribution_points, NULL, NULL); ++ crl = load_crl_crldp(crldp); ++ sk_DIST_POINT_pop_free(crldp, DIST_POINT_free); ++ if (!crl) { ++ sk_X509_CRL_free(crls); ++ return NULL; ++ } ++ sk_X509_CRL_push(crls, crl); ++ /* Try to download delta CRL */ ++ crldp = X509_get_ext_d2i(x, NID_freshest_crl, NULL, NULL); ++ crl = load_crl_crldp(crldp); ++ sk_DIST_POINT_pop_free(crldp, DIST_POINT_free); ++ if (crl) ++ sk_X509_CRL_push(crls, crl); ++ return crls; ++} ++ ++void store_setup_crl_download(X509_STORE *st) ++{ ++ X509_STORE_set_lookup_crls_cb(st, crls_http_cb); ++} ++ ++/* ++ * Platform-specific sections ++ */ ++#if defined(_WIN32) ++# ifdef fileno ++# undef fileno ++# define fileno(a) (int)_fileno(a) ++# endif ++ ++# include ++# include ++ ++static int WIN32_rename(const char *from, const char *to) ++{ ++ TCHAR *tfrom = NULL, *tto; ++ DWORD err; ++ int ret = 0; ++ ++ if (sizeof(TCHAR) == 1) { ++ tfrom = (TCHAR *)from; ++ tto = (TCHAR *)to; ++ } else { /* UNICODE path */ ++ ++ size_t i, flen = strlen(from) + 1, tlen = strlen(to) + 1; ++ tfrom = malloc(sizeof(*tfrom) * (flen + tlen)); ++ if (tfrom == NULL) ++ goto err; ++ tto = tfrom + flen; ++# if !defined(_WIN32_WCE) || _WIN32_WCE>=101 ++ if (!MultiByteToWideChar(CP_ACP, 0, from, flen, (WCHAR *)tfrom, flen)) ++# endif ++ for (i = 0; i < flen; i++) ++ tfrom[i] = (TCHAR)from[i]; ++# if !defined(_WIN32_WCE) || _WIN32_WCE>=101 ++ if (!MultiByteToWideChar(CP_ACP, 0, to, tlen, (WCHAR *)tto, tlen)) ++# endif ++ for (i = 0; i < tlen; i++) ++ tto[i] = (TCHAR)to[i]; ++ } ++ ++ if (MoveFile(tfrom, tto)) ++ goto ok; ++ err = GetLastError(); ++ if (err == ERROR_ALREADY_EXISTS || err == ERROR_FILE_EXISTS) { ++ if (DeleteFile(tto) && MoveFile(tfrom, tto)) ++ goto ok; ++ err = GetLastError(); ++ } ++ if (err == ERROR_FILE_NOT_FOUND || err == ERROR_PATH_NOT_FOUND) ++ errno = ENOENT; ++ else if (err == ERROR_ACCESS_DENIED) ++ errno = EACCES; ++ else ++ errno = EINVAL; /* we could map more codes... */ ++ err: ++ ret = -1; ++ ok: ++ if (tfrom != NULL && tfrom != (TCHAR *)from) ++ free(tfrom); ++ return ret; ++} ++#endif ++ ++/* app_tminterval section */ ++#if defined(_WIN32) ++double app_tminterval(int stop, int usertime) ++{ ++ FILETIME now; ++ double ret = 0; ++ static ULARGE_INTEGER tmstart; ++ static int warning = 1; ++# ifdef _WIN32_WINNT ++ static HANDLE proc = NULL; ++ ++ if (proc == NULL) { ++ if (check_winnt()) ++ proc = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, ++ GetCurrentProcessId()); ++ if (proc == NULL) ++ proc = (HANDLE) - 1; ++ } ++ ++ if (usertime && proc != (HANDLE) - 1) { ++ FILETIME junk; ++ GetProcessTimes(proc, &junk, &junk, &junk, &now); ++ } else ++# endif ++ { ++ SYSTEMTIME systime; ++ ++ if (usertime && warning) { ++ BIO_printf(bio_err, "To get meaningful results, run " ++ "this program on idle system.\n"); ++ warning = 0; ++ } ++ GetSystemTime(&systime); ++ SystemTimeToFileTime(&systime, &now); ++ } ++ ++ if (stop == TM_START) { ++ tmstart.u.LowPart = now.dwLowDateTime; ++ tmstart.u.HighPart = now.dwHighDateTime; ++ } else { ++ ULARGE_INTEGER tmstop; ++ ++ tmstop.u.LowPart = now.dwLowDateTime; ++ tmstop.u.HighPart = now.dwHighDateTime; ++ ++ ret = (__int64)(tmstop.QuadPart - tmstart.QuadPart) * 1e-7; ++ } ++ ++ return (ret); ++} ++#elif defined(OPENSSL_SYSTEM_VXWORKS) ++# include ++ ++double app_tminterval(int stop, int usertime) ++{ ++ double ret = 0; ++# ifdef CLOCK_REALTIME ++ static struct timespec tmstart; ++ struct timespec now; ++# else ++ static unsigned long tmstart; ++ unsigned long now; ++# endif ++ static int warning = 1; ++ ++ if (usertime && warning) { ++ BIO_printf(bio_err, "To get meaningful results, run " ++ "this program on idle system.\n"); ++ warning = 0; ++ } ++# ifdef CLOCK_REALTIME ++ clock_gettime(CLOCK_REALTIME, &now); ++ if (stop == TM_START) ++ tmstart = now; ++ else ++ ret = ((now.tv_sec + now.tv_nsec * 1e-9) ++ - (tmstart.tv_sec + tmstart.tv_nsec * 1e-9)); ++# else ++ now = tickGet(); ++ if (stop == TM_START) ++ tmstart = now; ++ else ++ ret = (now - tmstart) / (double)sysClkRateGet(); ++# endif ++ return (ret); ++} ++ ++#elif defined(OPENSSL_SYSTEM_VMS) ++# include ++# include ++ ++double app_tminterval(int stop, int usertime) ++{ ++ static clock_t tmstart; ++ double ret = 0; ++ clock_t now; ++# ifdef __TMS ++ struct tms rus; ++ ++ now = times(&rus); ++ if (usertime) ++ now = rus.tms_utime; ++# else ++ if (usertime) ++ now = clock(); /* sum of user and kernel times */ ++ else { ++ struct timeval tv; ++ gettimeofday(&tv, NULL); ++ now = (clock_t)((unsigned long long)tv.tv_sec * CLK_TCK + ++ (unsigned long long)tv.tv_usec * (1000000 / CLK_TCK) ++ ); ++ } ++# endif ++ if (stop == TM_START) ++ tmstart = now; ++ else ++ ret = (now - tmstart) / (double)(CLK_TCK); ++ ++ return (ret); ++} ++ ++#elif defined(_SC_CLK_TCK) /* by means of unistd.h */ ++# include ++ ++double app_tminterval(int stop, int usertime) ++{ ++ double ret = 0; ++ struct tms rus; ++ clock_t now = times(&rus); ++ static clock_t tmstart; ++ ++ if (usertime) ++ now = rus.tms_utime; ++ ++ if (stop == TM_START) ++ tmstart = now; ++ else { ++ long int tck = sysconf(_SC_CLK_TCK); ++ ret = (now - tmstart) / (double)tck; ++ } ++ ++ return (ret); ++} ++ ++#else ++# include ++# include ++ ++double app_tminterval(int stop, int usertime) ++{ ++ double ret = 0; ++ struct rusage rus; ++ struct timeval now; ++ static struct timeval tmstart; ++ ++ if (usertime) ++ getrusage(RUSAGE_SELF, &rus), now = rus.ru_utime; ++ else ++ gettimeofday(&now, NULL); ++ ++ if (stop == TM_START) ++ tmstart = now; ++ else ++ ret = ((now.tv_sec + now.tv_usec * 1e-6) ++ - (tmstart.tv_sec + tmstart.tv_usec * 1e-6)); ++ ++ return ret; ++} ++#endif ++ ++int app_access(const char* name, int flag) ++{ ++#ifdef _WIN32 ++ return _access(name, flag); ++#else ++ return access(name, flag); ++#endif ++} ++ ++/* app_isdir section */ ++#ifdef _WIN32 ++int app_isdir(const char *name) ++{ ++ HANDLE hList; ++ WIN32_FIND_DATA FileData; ++# if defined(UNICODE) || defined(_UNICODE) ++ size_t i, len_0 = strlen(name) + 1; ++ ++ if (len_0 > OSSL_NELEM(FileData.cFileName)) ++ return -1; ++ ++# if !defined(_WIN32_WCE) || _WIN32_WCE>=101 ++ if (!MultiByteToWideChar ++ (CP_ACP, 0, name, len_0, FileData.cFileName, len_0)) ++# endif ++ for (i = 0; i < len_0; i++) ++ FileData.cFileName[i] = (WCHAR)name[i]; ++ ++ hList = FindFirstFile(FileData.cFileName, &FileData); ++# else ++ hList = FindFirstFile(name, &FileData); ++# endif ++ if (hList == INVALID_HANDLE_VALUE) ++ return -1; ++ FindClose(hList); ++ return ((FileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0); ++} ++#else ++# include ++# ifndef S_ISDIR ++# if defined(_S_IFMT) && defined(_S_IFDIR) ++# define S_ISDIR(a) (((a) & _S_IFMT) == _S_IFDIR) ++# else ++# define S_ISDIR(a) (((a) & S_IFMT) == S_IFDIR) ++# endif ++# endif ++ ++int app_isdir(const char *name) ++{ ++# if defined(S_ISDIR) ++ struct stat st; ++ ++ if (stat(name, &st) == 0) ++ return S_ISDIR(st.st_mode); ++ else ++ return -1; ++# else ++ return -1; ++# endif ++} ++#endif ++ ++/* raw_read|write section */ ++#if defined(__VMS) ++# include "vms_term_sock.h" ++static int stdin_sock = -1; ++ ++static void close_stdin_sock(void) ++{ ++ TerminalSocket (TERM_SOCK_DELETE, &stdin_sock); ++} ++ ++int fileno_stdin(void) ++{ ++ if (stdin_sock == -1) { ++ TerminalSocket(TERM_SOCK_CREATE, &stdin_sock); ++ atexit(close_stdin_sock); ++ } ++ ++ return stdin_sock; ++} ++#else ++int fileno_stdin(void) ++{ ++ return fileno(stdin); ++} ++#endif ++ ++int fileno_stdout(void) ++{ ++ return fileno(stdout); ++} ++ ++#if defined(_WIN32) && defined(STD_INPUT_HANDLE) ++int raw_read_stdin(void *buf, int siz) ++{ ++ DWORD n; ++ if (ReadFile(GetStdHandle(STD_INPUT_HANDLE), buf, siz, &n, NULL)) ++ return (n); ++ else ++ return (-1); ++} ++#elif defined(__VMS) ++#include ++ ++int raw_read_stdin(void *buf, int siz) ++{ ++ return recv(fileno_stdin(), buf, siz, 0); ++} ++#else ++int raw_read_stdin(void *buf, int siz) ++{ ++ return read(fileno_stdin(), buf, siz); ++} ++#endif ++ ++#if defined(_WIN32) && defined(STD_OUTPUT_HANDLE) ++int raw_write_stdout(const void *buf, int siz) ++{ ++ DWORD n; ++ if (WriteFile(GetStdHandle(STD_OUTPUT_HANDLE), buf, siz, &n, NULL)) ++ return (n); ++ else ++ return (-1); ++} ++#else ++int raw_write_stdout(const void *buf, int siz) ++{ ++ return write(fileno_stdout(), buf, siz); ++} ++#endif ++ ++/* ++ * Centralized handling if input and output files with format specification ++ * The format is meant to show what the input and output is supposed to be, ++ * and is therefore a show of intent more than anything else. However, it ++ * does impact behavior on some platform, such as differentiating between ++ * text and binary input/output on non-Unix platforms ++ */ ++static int istext(int format) ++{ ++ return (format & B_FORMAT_TEXT) == B_FORMAT_TEXT; ++} ++ ++BIO *dup_bio_in(int format) ++{ ++ return BIO_new_fp(stdin, ++ BIO_NOCLOSE | (istext(format) ? BIO_FP_TEXT : 0)); ++} ++ ++BIO *dup_bio_out(int format) ++{ ++ BIO *b = BIO_new_fp(stdout, ++ BIO_NOCLOSE | (istext(format) ? BIO_FP_TEXT : 0)); ++#ifdef OPENSSL_SYS_VMS ++ if (istext(format)) ++ b = BIO_push(BIO_new(BIO_f_linebuffer()), b); ++#endif ++ return b; ++} ++ ++BIO *dup_bio_err(int format) ++{ ++ BIO *b = BIO_new_fp(stderr, ++ BIO_NOCLOSE | (istext(format) ? BIO_FP_TEXT : 0)); ++#ifdef OPENSSL_SYS_VMS ++ if (istext(format)) ++ b = BIO_push(BIO_new(BIO_f_linebuffer()), b); ++#endif ++ return b; ++} ++ ++void unbuffer(FILE *fp) ++{ ++/* ++ * On VMS, setbuf() will only take 32-bit pointers, and a compilation ++ * with /POINTER_SIZE=64 will give off a MAYLOSEDATA2 warning here. ++ * However, we trust that the C RTL will never give us a FILE pointer ++ * above the first 4 GB of memory, so we simply turn off the warning ++ * temporarily. ++ */ ++#if defined(OPENSSL_SYS_VMS) && defined(__DECC) ++# pragma environment save ++# pragma message disable maylosedata2 ++#endif ++ setbuf(fp, NULL); ++#if defined(OPENSSL_SYS_VMS) && defined(__DECC) ++# pragma environment restore ++#endif ++} ++ ++static const char *modestr(char mode, int format) ++{ ++ OPENSSL_assert(mode == 'a' || mode == 'r' || mode == 'w'); ++ ++ switch (mode) { ++ case 'a': ++ return istext(format) ? "a" : "ab"; ++ case 'r': ++ return istext(format) ? "r" : "rb"; ++ case 'w': ++ return istext(format) ? "w" : "wb"; ++ } ++ /* The assert above should make sure we never reach this point */ ++ return NULL; ++} ++ ++static const char *modeverb(char mode) ++{ ++ switch (mode) { ++ case 'a': ++ return "appending"; ++ case 'r': ++ return "reading"; ++ case 'w': ++ return "writing"; ++ } ++ return "(doing something)"; ++} ++ ++/* ++ * Open a file for writing, owner-read-only. ++ */ ++BIO *bio_open_owner(const char *filename, int format, int private) ++{ ++ FILE *fp = NULL; ++ BIO *b = NULL; ++ int fd = -1, bflags, mode, textmode; ++ ++ if (!private || filename == NULL || strcmp(filename, "-") == 0) ++ return bio_open_default(filename, 'w', format); ++ ++ mode = O_WRONLY; ++#ifdef O_CREAT ++ mode |= O_CREAT; ++#endif ++#ifdef O_TRUNC ++ mode |= O_TRUNC; ++#endif ++ textmode = istext(format); ++ if (!textmode) { ++#ifdef O_BINARY ++ mode |= O_BINARY; ++#elif defined(_O_BINARY) ++ mode |= _O_BINARY; ++#endif ++ } ++ ++#ifdef OPENSSL_SYS_VMS ++ /* VMS doesn't have O_BINARY, it just doesn't make sense. But, ++ * it still needs to know that we're going binary, or fdopen() ++ * will fail with "invalid argument"... so we tell VMS what the ++ * context is. ++ */ ++ if (!textmode) ++ fd = open(filename, mode, 0600, "ctx=bin"); ++ else ++#endif ++ fd = open(filename, mode, 0600); ++ if (fd < 0) ++ goto err; ++ fp = fdopen(fd, modestr('w', format)); ++ if (fp == NULL) ++ goto err; ++ bflags = BIO_CLOSE; ++ if (textmode) ++ bflags |= BIO_FP_TEXT; ++ b = BIO_new_fp(fp, bflags); ++ if (b) ++ return b; ++ ++ err: ++ BIO_printf(bio_err, "%s: Can't open \"%s\" for writing, %s\n", ++ opt_getprog(), filename, strerror(errno)); ++ ERR_print_errors(bio_err); ++ /* If we have fp, then fdopen took over fd, so don't close both. */ ++ if (fp) ++ fclose(fp); ++ else if (fd >= 0) ++ close(fd); ++ return NULL; ++} ++ ++static BIO *bio_open_default_(const char *filename, char mode, int format, ++ int quiet) ++{ ++ BIO *ret; ++ ++ if (filename == NULL || strcmp(filename, "-") == 0) { ++ ret = mode == 'r' ? dup_bio_in(format) : dup_bio_out(format); ++ if (quiet) { ++ ERR_clear_error(); ++ return ret; ++ } ++ if (ret != NULL) ++ return ret; ++ BIO_printf(bio_err, ++ "Can't open %s, %s\n", ++ mode == 'r' ? "stdin" : "stdout", strerror(errno)); ++ } else { ++ ret = BIO_new_file(filename, modestr(mode, format)); ++ if (quiet) { ++ ERR_clear_error(); ++ return ret; ++ } ++ if (ret != NULL) ++ return ret; ++ BIO_printf(bio_err, ++ "Can't open %s for %s, %s\n", ++ filename, modeverb(mode), strerror(errno)); ++ } ++ ERR_print_errors(bio_err); ++ return NULL; ++} ++ ++BIO *bio_open_default(const char *filename, char mode, int format) ++{ ++ return bio_open_default_(filename, mode, format, 0); ++} ++ ++BIO *bio_open_default_quiet(const char *filename, char mode, int format) ++{ ++ return bio_open_default_(filename, mode, format, 1); ++} ++ ++void wait_for_async(SSL *s) ++{ ++ /* On Windows select only works for sockets, so we simply don't wait */ ++#ifndef OPENSSL_SYS_WINDOWS ++ int width = 0; ++ fd_set asyncfds; ++ OSSL_ASYNC_FD *fds; ++ size_t numfds; ++ ++ if (!SSL_get_all_async_fds(s, NULL, &numfds)) ++ return; ++ if (numfds == 0) ++ return; ++ fds = app_malloc(sizeof(OSSL_ASYNC_FD) * numfds, "allocate async fds"); ++ if (!SSL_get_all_async_fds(s, fds, &numfds)) { ++ OPENSSL_free(fds); ++ } ++ ++ FD_ZERO(&asyncfds); ++ while (numfds > 0) { ++ if (width <= (int)*fds) ++ width = (int)*fds + 1; ++ openssl_fdset((int)*fds, &asyncfds); ++ numfds--; ++ fds++; ++ } ++ select(width, (void *)&asyncfds, NULL, NULL, NULL); ++#endif ++} ++ ++/* if OPENSSL_SYS_WINDOWS is defined then so is OPENSSL_SYS_MSDOS */ ++#if defined(OPENSSL_SYS_MSDOS) ++int has_stdin_waiting(void) ++{ ++# if defined(OPENSSL_SYS_WINDOWS) ++ HANDLE inhand = GetStdHandle(STD_INPUT_HANDLE); ++ DWORD events = 0; ++ INPUT_RECORD inputrec; ++ DWORD insize = 1; ++ BOOL peeked; ++ ++ if (inhand == INVALID_HANDLE_VALUE) { ++ return 0; ++ } ++ ++ peeked = PeekConsoleInput(inhand, &inputrec, insize, &events); ++ if (!peeked) { ++ /* Probably redirected input? _kbhit() does not work in this case */ ++ if (!feof(stdin)) { ++ return 1; ++ } ++ return 0; ++ } ++# endif ++ return _kbhit(); ++} ++#endif ++ ++/* Corrupt a signature by modifying final byte */ ++void corrupt_signature(const ASN1_STRING *signature) ++{ ++ unsigned char *s = signature->data; ++ s[signature->length - 1] ^= 0x1; ++} ++ ++int set_cert_times(X509 *x, const char *startdate, const char *enddate, ++ int days) ++{ ++ if (startdate == NULL || strcmp(startdate, "today") == 0) { ++ if (X509_gmtime_adj(X509_getm_notBefore(x), 0) == NULL) ++ return 0; ++ } else { ++ if (!ASN1_TIME_set_string(X509_getm_notBefore(x), startdate)) ++ return 0; ++ } ++ if (enddate == NULL) { ++ if (X509_time_adj_ex(X509_getm_notAfter(x), days, 0, NULL) ++ == NULL) ++ return 0; ++ } else if (!ASN1_TIME_set_string(X509_getm_notAfter(x), enddate)) { ++ return 0; ++ } ++ return 1; ++} +diff --git a/CryptoPkg/Library/OpensslLib/openssl/apps/apps.h b/CryptoPkg/Library/OpensslLib/openssl/apps/apps.h +new file mode 100644 +index 0000000..926a6d6 +--- /dev/null ++++ b/CryptoPkg/Library/OpensslLib/openssl/apps/apps.h +@@ -0,0 +1,569 @@ ++/* ++ * Copyright 1995-2016 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 ++ * in the file LICENSE in the source distribution or at ++ * https://www.openssl.org/source/license.html ++ */ ++ ++#ifndef HEADER_APPS_H ++# define HEADER_APPS_H ++ ++# include "e_os.h" ++# if defined(__unix) || defined(__unix__) ++# include /* struct timeval for DTLS */ ++# endif ++# include ++ ++# include ++# include ++# include ++# include ++# include ++# include ++# include ++# include ++# include ++# include ++ ++# if defined(OPENSSL_SYS_WIN32) || defined(OPENSSL_SYS_WINCE) ++# define openssl_fdset(a,b) FD_SET((unsigned int)a, b) ++# else ++# define openssl_fdset(a,b) FD_SET(a, b) ++# endif ++ ++/* ++ * quick macro when you need to pass an unsigned char instead of a char. ++ * this is true for some implementations of the is*() functions, for ++ * example. ++ */ ++#define _UC(c) ((unsigned char)(c)) ++ ++int app_RAND_load_file(const char *file, int dont_warn); ++int app_RAND_write_file(const char *file); ++/* ++ * When `file' is NULL, use defaults. `bio_e' is for error messages. ++ */ ++void app_RAND_allow_write_file(void); ++long app_RAND_load_files(char *file); /* `file' is a list of files to read, ++ * separated by LIST_SEPARATOR_CHAR ++ * (see e_os.h). The string is ++ * destroyed! */ ++ ++extern char *default_config_file; ++extern BIO *bio_in; ++extern BIO *bio_out; ++extern BIO *bio_err; ++BIO *dup_bio_in(int format); ++BIO *dup_bio_out(int format); ++BIO *dup_bio_err(int format); ++BIO *bio_open_owner(const char *filename, int format, int private); ++BIO *bio_open_default(const char *filename, char mode, int format); ++BIO *bio_open_default_quiet(const char *filename, char mode, int format); ++CONF *app_load_config(const char *filename); ++CONF *app_load_config_quiet(const char *filename); ++int app_load_modules(const CONF *config); ++void unbuffer(FILE *fp); ++void wait_for_async(SSL *s); ++# if defined(OPENSSL_SYS_MSDOS) ++int has_stdin_waiting(void); ++# endif ++ ++void corrupt_signature(const ASN1_STRING *signature); ++int set_cert_times(X509 *x, const char *startdate, const char *enddate, ++ int days); ++ ++/* ++ * Common verification options. ++ */ ++# define OPT_V_ENUM \ ++ OPT_V__FIRST=2000, \ ++ OPT_V_POLICY, OPT_V_PURPOSE, OPT_V_VERIFY_NAME, OPT_V_VERIFY_DEPTH, \ ++ OPT_V_ATTIME, OPT_V_VERIFY_HOSTNAME, OPT_V_VERIFY_EMAIL, \ ++ OPT_V_VERIFY_IP, OPT_V_IGNORE_CRITICAL, OPT_V_ISSUER_CHECKS, \ ++ OPT_V_CRL_CHECK, OPT_V_CRL_CHECK_ALL, OPT_V_POLICY_CHECK, \ ++ OPT_V_EXPLICIT_POLICY, OPT_V_INHIBIT_ANY, OPT_V_INHIBIT_MAP, \ ++ OPT_V_X509_STRICT, OPT_V_EXTENDED_CRL, OPT_V_USE_DELTAS, \ ++ OPT_V_POLICY_PRINT, OPT_V_CHECK_SS_SIG, OPT_V_TRUSTED_FIRST, \ ++ OPT_V_SUITEB_128_ONLY, OPT_V_SUITEB_128, OPT_V_SUITEB_192, \ ++ OPT_V_PARTIAL_CHAIN, OPT_V_NO_ALT_CHAINS, OPT_V_NO_CHECK_TIME, \ ++ OPT_V_VERIFY_AUTH_LEVEL, OPT_V_ALLOW_PROXY_CERTS, \ ++ OPT_V__LAST ++ ++# define OPT_V_OPTIONS \ ++ { "policy", OPT_V_POLICY, 's', "adds policy to the acceptable policy set"}, \ ++ { "purpose", OPT_V_PURPOSE, 's', \ ++ "certificate chain purpose"}, \ ++ { "verify_name", OPT_V_VERIFY_NAME, 's', "verification policy name"}, \ ++ { "verify_depth", OPT_V_VERIFY_DEPTH, 'n', \ ++ "chain depth limit" }, \ ++ { "auth_level", OPT_V_VERIFY_AUTH_LEVEL, 'n', \ ++ "chain authentication security level" }, \ ++ { "attime", OPT_V_ATTIME, 'M', "verification epoch time" }, \ ++ { "verify_hostname", OPT_V_VERIFY_HOSTNAME, 's', \ ++ "expected peer hostname" }, \ ++ { "verify_email", OPT_V_VERIFY_EMAIL, 's', \ ++ "expected peer email" }, \ ++ { "verify_ip", OPT_V_VERIFY_IP, 's', \ ++ "expected peer IP address" }, \ ++ { "ignore_critical", OPT_V_IGNORE_CRITICAL, '-', \ ++ "permit unhandled critical extensions"}, \ ++ { "issuer_checks", OPT_V_ISSUER_CHECKS, '-', "(deprecated)"}, \ ++ { "crl_check", OPT_V_CRL_CHECK, '-', "check leaf certificate revocation" }, \ ++ { "crl_check_all", OPT_V_CRL_CHECK_ALL, '-', "check full chain revocation" }, \ ++ { "policy_check", OPT_V_POLICY_CHECK, '-', "perform rfc5280 policy checks"}, \ ++ { "explicit_policy", OPT_V_EXPLICIT_POLICY, '-', \ ++ "set policy variable require-explicit-policy"}, \ ++ { "inhibit_any", OPT_V_INHIBIT_ANY, '-', \ ++ "set policy variable inhibit-any-policy"}, \ ++ { "inhibit_map", OPT_V_INHIBIT_MAP, '-', \ ++ "set policy variable inhibit-policy-mapping"}, \ ++ { "x509_strict", OPT_V_X509_STRICT, '-', \ ++ "disable certificate compatibility work-arounds"}, \ ++ { "extended_crl", OPT_V_EXTENDED_CRL, '-', \ ++ "enable extended CRL features"}, \ ++ { "use_deltas", OPT_V_USE_DELTAS, '-', \ ++ "use delta CRLs"}, \ ++ { "policy_print", OPT_V_POLICY_PRINT, '-', \ ++ "print policy processing diagnostics"}, \ ++ { "check_ss_sig", OPT_V_CHECK_SS_SIG, '-', \ ++ "check root CA self-signatures"}, \ ++ { "trusted_first", OPT_V_TRUSTED_FIRST, '-', \ ++ "search trust store first (default)" }, \ ++ { "suiteB_128_only", OPT_V_SUITEB_128_ONLY, '-', "Suite B 128-bit-only mode"}, \ ++ { "suiteB_128", OPT_V_SUITEB_128, '-', \ ++ "Suite B 128-bit mode allowing 192-bit algorithms"}, \ ++ { "suiteB_192", OPT_V_SUITEB_192, '-', "Suite B 192-bit-only mode" }, \ ++ { "partial_chain", OPT_V_PARTIAL_CHAIN, '-', \ ++ "accept chains anchored by intermediate trust-store CAs"}, \ ++ { "no_alt_chains", OPT_V_NO_ALT_CHAINS, '-', "(deprecated)" }, \ ++ { "no_check_time", OPT_V_NO_CHECK_TIME, '-', "ignore certificate validity time" }, \ ++ { "allow_proxy_certs", OPT_V_ALLOW_PROXY_CERTS, '-', "allow the use of proxy certificates" } ++ ++# define OPT_V_CASES \ ++ OPT_V__FIRST: case OPT_V__LAST: break; \ ++ case OPT_V_POLICY: \ ++ case OPT_V_PURPOSE: \ ++ case OPT_V_VERIFY_NAME: \ ++ case OPT_V_VERIFY_DEPTH: \ ++ case OPT_V_VERIFY_AUTH_LEVEL: \ ++ case OPT_V_ATTIME: \ ++ case OPT_V_VERIFY_HOSTNAME: \ ++ case OPT_V_VERIFY_EMAIL: \ ++ case OPT_V_VERIFY_IP: \ ++ case OPT_V_IGNORE_CRITICAL: \ ++ case OPT_V_ISSUER_CHECKS: \ ++ case OPT_V_CRL_CHECK: \ ++ case OPT_V_CRL_CHECK_ALL: \ ++ case OPT_V_POLICY_CHECK: \ ++ case OPT_V_EXPLICIT_POLICY: \ ++ case OPT_V_INHIBIT_ANY: \ ++ case OPT_V_INHIBIT_MAP: \ ++ case OPT_V_X509_STRICT: \ ++ case OPT_V_EXTENDED_CRL: \ ++ case OPT_V_USE_DELTAS: \ ++ case OPT_V_POLICY_PRINT: \ ++ case OPT_V_CHECK_SS_SIG: \ ++ case OPT_V_TRUSTED_FIRST: \ ++ case OPT_V_SUITEB_128_ONLY: \ ++ case OPT_V_SUITEB_128: \ ++ case OPT_V_SUITEB_192: \ ++ case OPT_V_PARTIAL_CHAIN: \ ++ case OPT_V_NO_ALT_CHAINS: \ ++ case OPT_V_NO_CHECK_TIME: \ ++ case OPT_V_ALLOW_PROXY_CERTS ++ ++/* ++ * Common "extended"? options. ++ */ ++# define OPT_X_ENUM \ ++ OPT_X__FIRST=1000, \ ++ OPT_X_KEY, OPT_X_CERT, OPT_X_CHAIN, OPT_X_CHAIN_BUILD, \ ++ OPT_X_CERTFORM, OPT_X_KEYFORM, \ ++ OPT_X__LAST ++ ++# define OPT_X_OPTIONS \ ++ { "xkey", OPT_X_KEY, '<', "key for Extended certificates"}, \ ++ { "xcert", OPT_X_CERT, '<', "cert for Extended certificates"}, \ ++ { "xchain", OPT_X_CHAIN, '<', "chain for Extended certificates"}, \ ++ { "xchain_build", OPT_X_CHAIN_BUILD, '-', \ ++ "build certificate chain for the extended certificates"}, \ ++ { "xcertform", OPT_X_CERTFORM, 'F', \ ++ "format of Extended certificate (PEM or DER) PEM default " }, \ ++ { "xkeyform", OPT_X_KEYFORM, 'F', \ ++ "format of Extended certificate's key (PEM or DER) PEM default"} ++ ++# define OPT_X_CASES \ ++ OPT_X__FIRST: case OPT_X__LAST: break; \ ++ case OPT_X_KEY: \ ++ case OPT_X_CERT: \ ++ case OPT_X_CHAIN: \ ++ case OPT_X_CHAIN_BUILD: \ ++ case OPT_X_CERTFORM: \ ++ case OPT_X_KEYFORM ++ ++/* ++ * Common SSL options. ++ * Any changes here must be coordinated with ../ssl/ssl_conf.c ++ */ ++# define OPT_S_ENUM \ ++ OPT_S__FIRST=3000, \ ++ OPT_S_NOSSL3, OPT_S_NOTLS1, OPT_S_NOTLS1_1, OPT_S_NOTLS1_2, \ ++ OPT_S_BUGS, OPT_S_NO_COMP, OPT_S_NOTICKET, \ ++ OPT_S_SERVERPREF, OPT_S_LEGACYRENEG, OPT_S_LEGACYCONN, \ ++ OPT_S_ONRESUMP, OPT_S_NOLEGACYCONN, OPT_S_STRICT, OPT_S_SIGALGS, \ ++ OPT_S_CLIENTSIGALGS, OPT_S_CURVES, OPT_S_NAMEDCURVE, OPT_S_CIPHER, \ ++ OPT_S_DHPARAM, OPT_S_DEBUGBROKE, OPT_S_COMP, \ ++ OPT_S__LAST ++ ++# define OPT_S_OPTIONS \ ++ {"no_ssl3", OPT_S_NOSSL3, '-',"Just disable SSLv3" }, \ ++ {"no_tls1", OPT_S_NOTLS1, '-', "Just disable TLSv1"}, \ ++ {"no_tls1_1", OPT_S_NOTLS1_1, '-', "Just disable TLSv1.1" }, \ ++ {"no_tls1_2", OPT_S_NOTLS1_2, '-', "Just disable TLSv1.2"}, \ ++ {"bugs", OPT_S_BUGS, '-', "Turn on SSL bug compatibility"}, \ ++ {"no_comp", OPT_S_NO_COMP, '-', "Disable SSL/TLS compression (default)" }, \ ++ {"comp", OPT_S_COMP, '-', "Use SSL/TLS-level compression" }, \ ++ {"no_ticket", OPT_S_NOTICKET, '-', \ ++ "Disable use of TLS session tickets"}, \ ++ {"serverpref", OPT_S_SERVERPREF, '-', "Use server's cipher preferences"}, \ ++ {"legacy_renegotiation", OPT_S_LEGACYRENEG, '-', \ ++ "Enable use of legacy renegotiation (dangerous)"}, \ ++ {"legacy_server_connect", OPT_S_LEGACYCONN, '-', \ ++ "Allow initial connection to servers that don't support RI"}, \ ++ {"no_resumption_on_reneg", OPT_S_ONRESUMP, '-', \ ++ "Disallow session resumption on renegotiation"}, \ ++ {"no_legacy_server_connect", OPT_S_NOLEGACYCONN, '-', \ ++ "Disallow initial connection to servers that don't support RI"}, \ ++ {"strict", OPT_S_STRICT, '-', \ ++ "Enforce strict certificate checks as per TLS standard"}, \ ++ {"sigalgs", OPT_S_SIGALGS, 's', \ ++ "Signature algorithms to support (colon-separated list)" }, \ ++ {"client_sigalgs", OPT_S_CLIENTSIGALGS, 's', \ ++ "Signature algorithms to support for client certificate" \ ++ " authentication (colon-separated list)" }, \ ++ {"curves", OPT_S_CURVES, 's', \ ++ "Elliptic curves to advertise (colon-separated list)" }, \ ++ {"named_curve", OPT_S_NAMEDCURVE, 's', \ ++ "Elliptic curve used for ECDHE (server-side only)" }, \ ++ {"cipher", OPT_S_CIPHER, 's', "Specify cipher list to be used"}, \ ++ {"dhparam", OPT_S_DHPARAM, '<', \ ++ "DH parameter file to use, in cert file if not specified"}, \ ++ {"debug_broken_protocol", OPT_S_DEBUGBROKE, '-', \ ++ "Perform all sorts of protocol violations for testing purposes"} ++ ++# define OPT_S_CASES \ ++ OPT_S__FIRST: case OPT_S__LAST: break; \ ++ case OPT_S_NOSSL3: \ ++ case OPT_S_NOTLS1: \ ++ case OPT_S_NOTLS1_1: \ ++ case OPT_S_NOTLS1_2: \ ++ case OPT_S_BUGS: \ ++ case OPT_S_NO_COMP: \ ++ case OPT_S_COMP: \ ++ case OPT_S_NOTICKET: \ ++ case OPT_S_SERVERPREF: \ ++ case OPT_S_LEGACYRENEG: \ ++ case OPT_S_LEGACYCONN: \ ++ case OPT_S_ONRESUMP: \ ++ case OPT_S_NOLEGACYCONN: \ ++ case OPT_S_STRICT: \ ++ case OPT_S_SIGALGS: \ ++ case OPT_S_CLIENTSIGALGS: \ ++ case OPT_S_CURVES: \ ++ case OPT_S_NAMEDCURVE: \ ++ case OPT_S_CIPHER: \ ++ case OPT_S_DHPARAM: \ ++ case OPT_S_DEBUGBROKE ++ ++#define IS_NO_PROT_FLAG(o) \ ++ (o == OPT_S_NOSSL3 || o == OPT_S_NOTLS1 || o == OPT_S_NOTLS1_1 \ ++ || o == OPT_S_NOTLS1_2) ++ ++/* ++ * Option parsing. ++ */ ++extern const char OPT_HELP_STR[]; ++extern const char OPT_MORE_STR[]; ++typedef struct options_st { ++ const char *name; ++ int retval; ++ /* ++ * value type: - no value (also the value zero), n number, p positive ++ * number, u unsigned, l long, s string, < input file, > output file, ++ * f any format, F der/pem format , E der/pem/engine format identifier. ++ * l, n and u include zero; p does not. ++ */ ++ int valtype; ++ const char *helpstr; ++} OPTIONS; ++ ++/* ++ * A string/int pairing; widely use for option value lookup, hence the ++ * name OPT_PAIR. But that name is misleading in s_cb.c, so we also use ++ * the "generic" name STRINT_PAIR. ++ */ ++typedef struct string_int_pair_st { ++ const char *name; ++ int retval; ++} OPT_PAIR, STRINT_PAIR; ++ ++/* Flags to pass into opt_format; see FORMAT_xxx, below. */ ++# define OPT_FMT_PEMDER (1L << 1) ++# define OPT_FMT_PKCS12 (1L << 2) ++# define OPT_FMT_SMIME (1L << 3) ++# define OPT_FMT_ENGINE (1L << 4) ++# define OPT_FMT_MSBLOB (1L << 5) ++# define OPT_FMT_NETSCAPE (1L << 6) ++# define OPT_FMT_NSS (1L << 7) ++# define OPT_FMT_TEXT (1L << 8) ++# define OPT_FMT_HTTP (1L << 9) ++# define OPT_FMT_PVK (1L << 10) ++# define OPT_FMT_PDE (OPT_FMT_PEMDER | OPT_FMT_ENGINE) ++# define OPT_FMT_PDS (OPT_FMT_PEMDER | OPT_FMT_SMIME) ++# define OPT_FMT_ANY ( \ ++ OPT_FMT_PEMDER | OPT_FMT_PKCS12 | OPT_FMT_SMIME | \ ++ OPT_FMT_ENGINE | OPT_FMT_MSBLOB | OPT_FMT_NETSCAPE | \ ++ OPT_FMT_NSS | OPT_FMT_TEXT | OPT_FMT_HTTP | OPT_FMT_PVK) ++ ++char *opt_progname(const char *argv0); ++char *opt_getprog(void); ++char *opt_init(int ac, char **av, const OPTIONS * o); ++int opt_next(void); ++int opt_format(const char *s, unsigned long flags, int *result); ++int opt_int(const char *arg, int *result); ++int opt_ulong(const char *arg, unsigned long *result); ++int opt_long(const char *arg, long *result); ++#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L && \ ++ defined(INTMAX_MAX) && defined(UINTMAX_MAX) ++int opt_imax(const char *arg, intmax_t *result); ++int opt_umax(const char *arg, uintmax_t *result); ++#else ++# define opt_imax opt_long ++# define opt_umax opt_ulong ++# define intmax_t long ++# define uintmax_t unsigned long ++#endif ++int opt_pair(const char *arg, const OPT_PAIR * pairs, int *result); ++int opt_cipher(const char *name, const EVP_CIPHER **cipherp); ++int opt_md(const char *name, const EVP_MD **mdp); ++char *opt_arg(void); ++char *opt_flag(void); ++char *opt_unknown(void); ++char *opt_reset(void); ++char **opt_rest(void); ++int opt_num_rest(void); ++int opt_verify(int i, X509_VERIFY_PARAM *vpm); ++void opt_help(const OPTIONS * list); ++int opt_format_error(const char *s, unsigned long flags); ++ ++typedef struct args_st { ++ int size; ++ int argc; ++ char **argv; ++} ARGS; ++ ++/* ++ * VMS C only for now, implemented in vms_decc_init.c ++ * If other C compilers forget to terminate argv with NULL, this function ++ * can be re-used. ++ */ ++char **copy_argv(int *argc, char *argv[]); ++/* ++ * Win32-specific argv initialization that splits OS-supplied UNICODE ++ * command line string to array of UTF8-encoded strings. ++ */ ++void win32_utf8argv(int *argc, char **argv[]); ++ ++ ++# define PW_MIN_LENGTH 4 ++typedef struct pw_cb_data { ++ const void *password; ++ const char *prompt_info; ++} PW_CB_DATA; ++ ++int password_callback(char *buf, int bufsiz, int verify, PW_CB_DATA *cb_data); ++ ++int setup_ui_method(void); ++void destroy_ui_method(void); ++ ++int chopup_args(ARGS *arg, char *buf); ++# ifdef HEADER_X509_H ++int dump_cert_text(BIO *out, X509 *x); ++void print_name(BIO *out, const char *title, X509_NAME *nm, ++ unsigned long lflags); ++# endif ++void print_bignum_var(BIO *, const BIGNUM *, const char*, ++ int, unsigned char *); ++void print_array(BIO *, const char *, int, const unsigned char *); ++int set_cert_ex(unsigned long *flags, const char *arg); ++int set_name_ex(unsigned long *flags, const char *arg); ++int set_ext_copy(int *copy_type, const char *arg); ++int copy_extensions(X509 *x, X509_REQ *req, int copy_type); ++int app_passwd(const char *arg1, const char *arg2, char **pass1, char **pass2); ++int add_oid_section(CONF *conf); ++X509 *load_cert(const char *file, int format, const char *cert_descrip); ++X509_CRL *load_crl(const char *infile, int format); ++EVP_PKEY *load_key(const char *file, int format, int maybe_stdin, ++ const char *pass, ENGINE *e, const char *key_descrip); ++EVP_PKEY *load_pubkey(const char *file, int format, int maybe_stdin, ++ const char *pass, ENGINE *e, const char *key_descrip); ++int load_certs(const char *file, STACK_OF(X509) **certs, int format, ++ const char *pass, const char *cert_descrip); ++int load_crls(const char *file, STACK_OF(X509_CRL) **crls, int format, ++ const char *pass, const char *cert_descrip); ++X509_STORE *setup_verify(const char *CAfile, const char *CApath, ++ int noCAfile, int noCApath); ++__owur int ctx_set_verify_locations(SSL_CTX *ctx, const char *CAfile, ++ const char *CApath, int noCAfile, ++ int noCApath); ++ ++#ifndef OPENSSL_NO_CT ++ ++/* ++ * Sets the file to load the Certificate Transparency log list from. ++ * If path is NULL, loads from the default file path. ++ * Returns 1 on success, 0 otherwise. ++ */ ++__owur int ctx_set_ctlog_list_file(SSL_CTX *ctx, const char *path); ++ ++#endif ++ ++ENGINE *setup_engine(const char *engine, int debug); ++void release_engine(ENGINE *e); ++ ++# ifndef OPENSSL_NO_OCSP ++OCSP_RESPONSE *process_responder(OCSP_REQUEST *req, ++ const char *host, const char *path, ++ const char *port, int use_ssl, ++ STACK_OF(CONF_VALUE) *headers, ++ int req_timeout); ++# endif ++ ++/* Functions defined in ca.c and also used in ocsp.c */ ++int unpack_revinfo(ASN1_TIME **prevtm, int *preason, ASN1_OBJECT **phold, ++ ASN1_GENERALIZEDTIME **pinvtm, const char *str); ++ ++# define DB_type 0 ++# define DB_exp_date 1 ++# define DB_rev_date 2 ++# define DB_serial 3 /* index - unique */ ++# define DB_file 4 ++# define DB_name 5 /* index - unique when active and not ++ * disabled */ ++# define DB_NUMBER 6 ++ ++# define DB_TYPE_REV 'R' ++# define DB_TYPE_EXP 'E' ++# define DB_TYPE_VAL 'V' ++ ++typedef struct db_attr_st { ++ int unique_subject; ++} DB_ATTR; ++typedef struct ca_db_st { ++ DB_ATTR attributes; ++ TXT_DB *db; ++} CA_DB; ++ ++void* app_malloc(int sz, const char *what); ++BIGNUM *load_serial(const char *serialfile, int create, ASN1_INTEGER **retai); ++int save_serial(const char *serialfile, const char *suffix, const BIGNUM *serial, ++ ASN1_INTEGER **retai); ++int rotate_serial(const char *serialfile, const char *new_suffix, ++ const char *old_suffix); ++int rand_serial(BIGNUM *b, ASN1_INTEGER *ai); ++CA_DB *load_index(const char *dbfile, DB_ATTR *dbattr); ++int index_index(CA_DB *db); ++int save_index(const char *dbfile, const char *suffix, CA_DB *db); ++int rotate_index(const char *dbfile, const char *new_suffix, ++ const char *old_suffix); ++void free_index(CA_DB *db); ++# define index_name_cmp_noconst(a, b) \ ++ index_name_cmp((const OPENSSL_CSTRING *)CHECKED_PTR_OF(OPENSSL_STRING, a), \ ++ (const OPENSSL_CSTRING *)CHECKED_PTR_OF(OPENSSL_STRING, b)) ++int index_name_cmp(const OPENSSL_CSTRING *a, const OPENSSL_CSTRING *b); ++int parse_yesno(const char *str, int def); ++ ++X509_NAME *parse_name(const char *str, long chtype, int multirdn); ++int args_verify(char ***pargs, int *pargc, ++ int *badarg, X509_VERIFY_PARAM **pm); ++void policies_print(X509_STORE_CTX *ctx); ++int bio_to_mem(unsigned char **out, int maxlen, BIO *in); ++int pkey_ctrl_string(EVP_PKEY_CTX *ctx, const char *value); ++int init_gen_str(EVP_PKEY_CTX **pctx, ++ const char *algname, ENGINE *e, int do_param); ++int do_X509_sign(X509 *x, EVP_PKEY *pkey, const EVP_MD *md, ++ STACK_OF(OPENSSL_STRING) *sigopts); ++int do_X509_REQ_sign(X509_REQ *x, EVP_PKEY *pkey, const EVP_MD *md, ++ STACK_OF(OPENSSL_STRING) *sigopts); ++int do_X509_CRL_sign(X509_CRL *x, EVP_PKEY *pkey, const EVP_MD *md, ++ STACK_OF(OPENSSL_STRING) *sigopts); ++# ifndef OPENSSL_NO_PSK ++extern char *psk_key; ++# endif ++ ++unsigned char *next_protos_parse(size_t *outlen, const char *in); ++ ++void print_cert_checks(BIO *bio, X509 *x, ++ const char *checkhost, ++ const char *checkemail, const char *checkip); ++ ++void store_setup_crl_download(X509_STORE *st); ++ ++/* See OPT_FMT_xxx, above. */ ++/* On some platforms, it's important to distinguish between text and binary ++ * files. On some, there might even be specific file formats for different ++ * contents. The FORMAT_xxx macros are meant to express an intent with the ++ * file being read or created. ++ */ ++# define B_FORMAT_TEXT 0x8000 ++# define FORMAT_UNDEF 0 ++# define FORMAT_TEXT (1 | B_FORMAT_TEXT) /* Generic text */ ++# define FORMAT_BINARY 2 /* Generic binary */ ++# define FORMAT_BASE64 (3 | B_FORMAT_TEXT) /* Base64 */ ++# define FORMAT_ASN1 4 /* ASN.1/DER */ ++# define FORMAT_PEM (5 | B_FORMAT_TEXT) ++# define FORMAT_PKCS12 6 ++# define FORMAT_SMIME (7 | B_FORMAT_TEXT) ++# define FORMAT_ENGINE 8 /* Not really a file format */ ++# define FORMAT_PEMRSA (9 | B_FORMAT_TEXT) /* PEM RSAPubicKey format */ ++# define FORMAT_ASN1RSA 10 /* DER RSAPubicKey format */ ++# define FORMAT_MSBLOB 11 /* MS Key blob format */ ++# define FORMAT_PVK 12 /* MS PVK file format */ ++# define FORMAT_HTTP 13 /* Download using HTTP */ ++# define FORMAT_NSS 14 /* NSS keylog format */ ++ ++# define EXT_COPY_NONE 0 ++# define EXT_COPY_ADD 1 ++# define EXT_COPY_ALL 2 ++ ++# define NETSCAPE_CERT_HDR "certificate" ++ ++# define APP_PASS_LEN 1024 ++ ++# define SERIAL_RAND_BITS 64 ++ ++int app_isdir(const char *); ++int app_access(const char *, int flag); ++int fileno_stdin(void); ++int fileno_stdout(void); ++int raw_read_stdin(void *, int); ++int raw_write_stdout(const void *, int); ++ ++# define TM_START 0 ++# define TM_STOP 1 ++double app_tminterval(int stop, int usertime); ++ ++typedef struct verify_options_st { ++ int depth; ++ int quiet; ++ int error; ++ int return_error; ++} VERIFY_CB_ARGS; ++ ++extern VERIFY_CB_ARGS verify_args; ++ ++# include "progs.h" ++ ++#endif +diff --git a/CryptoPkg/Library/OpensslLib/openssl/apps/asn1pars.c b/CryptoPkg/Library/OpensslLib/openssl/apps/asn1pars.c +new file mode 100644 +index 0000000..1ac261c +--- /dev/null ++++ b/CryptoPkg/Library/OpensslLib/openssl/apps/asn1pars.c +@@ -0,0 +1,330 @@ ++/* ++ * Copyright 1995-2016 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 ++ * in the file LICENSE in the source distribution or at ++ * https://www.openssl.org/source/license.html ++ */ ++ ++/* ++ * A nice addition from Dr Stephen Henson to add the ++ * -strparse option which parses nested binary structures ++ */ ++ ++#include ++#include ++#include ++#include "apps.h" ++#include ++#include ++#include ++#include ++ ++typedef enum OPTION_choice { ++ OPT_ERR = -1, OPT_EOF = 0, OPT_HELP, ++ OPT_INFORM, OPT_IN, OPT_OUT, OPT_INDENT, OPT_NOOUT, ++ OPT_OID, OPT_OFFSET, OPT_LENGTH, OPT_DUMP, OPT_DLIMIT, ++ OPT_STRPARSE, OPT_GENSTR, OPT_GENCONF, OPT_STRICTPEM ++} OPTION_CHOICE; ++ ++OPTIONS asn1parse_options[] = { ++ {"help", OPT_HELP, '-', "Display this summary"}, ++ {"inform", OPT_INFORM, 'F', "input format - one of DER PEM"}, ++ {"in", OPT_IN, '<', "input file"}, ++ {"out", OPT_OUT, '>', "output file (output format is always DER)"}, ++ {"i", OPT_INDENT, 0, "indents the output"}, ++ {"noout", OPT_NOOUT, 0, "do not produce any output"}, ++ {"offset", OPT_OFFSET, 'p', "offset into file"}, ++ {"length", OPT_LENGTH, 'p', "length of section in file"}, ++ {"oid", OPT_OID, '<', "file of extra oid definitions"}, ++ {"dump", OPT_DUMP, 0, "unknown data in hex form"}, ++ {"dlimit", OPT_DLIMIT, 'p', ++ "dump the first arg bytes of unknown data in hex form"}, ++ {"strparse", OPT_STRPARSE, 's', ++ "offset; a series of these can be used to 'dig'"}, ++ {OPT_MORE_STR, 0, 0, "into multiple ASN1 blob wrappings"}, ++ {"genstr", OPT_GENSTR, 's', "string to generate ASN1 structure from"}, ++ {"genconf", OPT_GENCONF, 's', "file to generate ASN1 structure from"}, ++ {OPT_MORE_STR, 0, 0, "(-inform will be ignored)"}, ++ {"strictpem", OPT_STRICTPEM, 0, ++ "do not attempt base64 decode outside PEM markers"}, ++ {NULL} ++}; ++ ++static int do_generate(char *genstr, const char *genconf, BUF_MEM *buf); ++ ++int asn1parse_main(int argc, char **argv) ++{ ++ ASN1_TYPE *at = NULL; ++ BIO *in = NULL, *b64 = NULL, *derout = NULL; ++ BUF_MEM *buf = NULL; ++ STACK_OF(OPENSSL_STRING) *osk = NULL; ++ char *genstr = NULL, *genconf = NULL; ++ char *infile = NULL, *oidfile = NULL, *derfile = NULL; ++ unsigned char *str = NULL; ++ char *name = NULL, *header = NULL, *prog; ++ const unsigned char *ctmpbuf; ++ int indent = 0, noout = 0, dump = 0, strictpem = 0, informat = FORMAT_PEM; ++ int offset = 0, ret = 1, i, j; ++ long num, tmplen; ++ unsigned char *tmpbuf; ++ unsigned int length = 0; ++ OPTION_CHOICE o; ++ ++ prog = opt_init(argc, argv, asn1parse_options); ++ ++ if ((osk = sk_OPENSSL_STRING_new_null()) == NULL) { ++ BIO_printf(bio_err, "%s: Memory allocation failure\n", prog); ++ goto end; ++ } ++ ++ while ((o = opt_next()) != OPT_EOF) { ++ switch (o) { ++ case OPT_EOF: ++ case OPT_ERR: ++ opthelp: ++ BIO_printf(bio_err, "%s: Use -help for summary.\n", prog); ++ goto end; ++ case OPT_HELP: ++ opt_help(asn1parse_options); ++ ret = 0; ++ goto end; ++ case OPT_INFORM: ++ if (!opt_format(opt_arg(), OPT_FMT_PEMDER, &informat)) ++ goto opthelp; ++ break; ++ case OPT_IN: ++ infile = opt_arg(); ++ break; ++ case OPT_OUT: ++ derfile = opt_arg(); ++ break; ++ case OPT_INDENT: ++ indent = 1; ++ break; ++ case OPT_NOOUT: ++ noout = 1; ++ break; ++ case OPT_OID: ++ oidfile = opt_arg(); ++ break; ++ case OPT_OFFSET: ++ offset = strtol(opt_arg(), NULL, 0); ++ break; ++ case OPT_LENGTH: ++ length = atoi(opt_arg()); ++ break; ++ case OPT_DUMP: ++ dump = -1; ++ break; ++ case OPT_DLIMIT: ++ dump = atoi(opt_arg()); ++ break; ++ case OPT_STRPARSE: ++ sk_OPENSSL_STRING_push(osk, opt_arg()); ++ break; ++ case OPT_GENSTR: ++ genstr = opt_arg(); ++ break; ++ case OPT_GENCONF: ++ genconf = opt_arg(); ++ break; ++ case OPT_STRICTPEM: ++ strictpem = 1; ++ informat = FORMAT_PEM; ++ break; ++ } ++ } ++ argc = opt_num_rest(); ++ if (argc != 0) ++ goto opthelp; ++ ++ if (oidfile != NULL) { ++ in = bio_open_default(oidfile, 'r', FORMAT_TEXT); ++ if (in == NULL) ++ goto end; ++ OBJ_create_objects(in); ++ BIO_free(in); ++ } ++ ++ if ((in = bio_open_default(infile, 'r', informat)) == NULL) ++ goto end; ++ ++ if (derfile && (derout = bio_open_default(derfile, 'w', FORMAT_ASN1)) == NULL) ++ goto end; ++ ++ if (strictpem) { ++ if (PEM_read_bio(in, &name, &header, &str, &num) != ++ 1) { ++ BIO_printf(bio_err, "Error reading PEM file\n"); ++ ERR_print_errors(bio_err); ++ goto end; ++ } ++ } else { ++ ++ if ((buf = BUF_MEM_new()) == NULL) ++ goto end; ++ if (!BUF_MEM_grow(buf, BUFSIZ * 8)) ++ goto end; /* Pre-allocate :-) */ ++ ++ if (genstr || genconf) { ++ num = do_generate(genstr, genconf, buf); ++ if (num < 0) { ++ ERR_print_errors(bio_err); ++ goto end; ++ } ++ } ++ ++ else { ++ ++ if (informat == FORMAT_PEM) { ++ BIO *tmp; ++ ++ if ((b64 = BIO_new(BIO_f_base64())) == NULL) ++ goto end; ++ BIO_push(b64, in); ++ tmp = in; ++ in = b64; ++ b64 = tmp; ++ } ++ ++ num = 0; ++ for (;;) { ++ if (!BUF_MEM_grow(buf, (int)num + BUFSIZ)) ++ goto end; ++ i = BIO_read(in, &(buf->data[num]), BUFSIZ); ++ if (i <= 0) ++ break; ++ num += i; ++ } ++ } ++ str = (unsigned char *)buf->data; ++ ++ } ++ ++ /* If any structs to parse go through in sequence */ ++ ++ if (sk_OPENSSL_STRING_num(osk)) { ++ tmpbuf = str; ++ tmplen = num; ++ for (i = 0; i < sk_OPENSSL_STRING_num(osk); i++) { ++ ASN1_TYPE *atmp; ++ int typ; ++ j = atoi(sk_OPENSSL_STRING_value(osk, i)); ++ if (j == 0) { ++ BIO_printf(bio_err, "'%s' is an invalid number\n", ++ sk_OPENSSL_STRING_value(osk, i)); ++ continue; ++ } ++ tmpbuf += j; ++ tmplen -= j; ++ atmp = at; ++ ctmpbuf = tmpbuf; ++ at = d2i_ASN1_TYPE(NULL, &ctmpbuf, tmplen); ++ ASN1_TYPE_free(atmp); ++ if (!at) { ++ BIO_printf(bio_err, "Error parsing structure\n"); ++ ERR_print_errors(bio_err); ++ goto end; ++ } ++ typ = ASN1_TYPE_get(at); ++ if ((typ == V_ASN1_OBJECT) ++ || (typ == V_ASN1_BOOLEAN) ++ || (typ == V_ASN1_NULL)) { ++ BIO_printf(bio_err, "Can't parse %s type\n", ASN1_tag2str(typ)); ++ ERR_print_errors(bio_err); ++ goto end; ++ } ++ /* hmm... this is a little evil but it works */ ++ tmpbuf = at->value.asn1_string->data; ++ tmplen = at->value.asn1_string->length; ++ } ++ str = tmpbuf; ++ num = tmplen; ++ } ++ ++ if (offset >= num) { ++ BIO_printf(bio_err, "Error: offset too large\n"); ++ goto end; ++ } ++ ++ num -= offset; ++ ++ if ((length == 0) || ((long)length > num)) ++ length = (unsigned int)num; ++ if (derout) { ++ if (BIO_write(derout, str + offset, length) != (int)length) { ++ BIO_printf(bio_err, "Error writing output\n"); ++ ERR_print_errors(bio_err); ++ goto end; ++ } ++ } ++ if (!noout && ++ !ASN1_parse_dump(bio_out, &(str[offset]), length, ++ indent, dump)) { ++ ERR_print_errors(bio_err); ++ goto end; ++ } ++ ret = 0; ++ end: ++ BIO_free(derout); ++ BIO_free(in); ++ BIO_free(b64); ++ if (ret != 0) ++ ERR_print_errors(bio_err); ++ BUF_MEM_free(buf); ++ OPENSSL_free(name); ++ OPENSSL_free(header); ++ if (strictpem) ++ OPENSSL_free(str); ++ ASN1_TYPE_free(at); ++ sk_OPENSSL_STRING_free(osk); ++ return (ret); ++} ++ ++static int do_generate(char *genstr, const char *genconf, BUF_MEM *buf) ++{ ++ CONF *cnf = NULL; ++ int len; ++ unsigned char *p; ++ ASN1_TYPE *atyp = NULL; ++ ++ if (genconf) { ++ if ((cnf = app_load_config(genconf)) == NULL) ++ goto err; ++ if (!genstr) ++ genstr = NCONF_get_string(cnf, "default", "asn1"); ++ if (!genstr) { ++ BIO_printf(bio_err, "Can't find 'asn1' in '%s'\n", genconf); ++ goto err; ++ } ++ } ++ ++ atyp = ASN1_generate_nconf(genstr, cnf); ++ NCONF_free(cnf); ++ cnf = NULL; ++ ++ if (!atyp) ++ return -1; ++ ++ len = i2d_ASN1_TYPE(atyp, NULL); ++ ++ if (len <= 0) ++ goto err; ++ ++ if (!BUF_MEM_grow(buf, len)) ++ goto err; ++ ++ p = (unsigned char *)buf->data; ++ ++ i2d_ASN1_TYPE(atyp, &p); ++ ++ ASN1_TYPE_free(atyp); ++ return len; ++ ++ err: ++ NCONF_free(cnf); ++ ASN1_TYPE_free(atyp); ++ return -1; ++} +diff --git a/CryptoPkg/Library/OpensslLib/openssl/apps/build.info b/CryptoPkg/Library/OpensslLib/openssl/apps/build.info +new file mode 100644 +index 0000000..ae64861 +--- /dev/null ++++ b/CryptoPkg/Library/OpensslLib/openssl/apps/build.info +@@ -0,0 +1,22 @@ ++{- our $tsget_name = $config{target} =~ /^(VC|vms)-/ ? "tsget.pl" : "tsget"; ++ "" -} ++IF[{- !$disabled{apps} -}] ++ PROGRAMS=openssl ++ SOURCE[openssl]=\ ++ openssl.c \ ++ asn1pars.c ca.c ciphers.c cms.c crl.c crl2p7.c dgst.c dhparam.c \ ++ dsa.c dsaparam.c ec.c ecparam.c enc.c engine.c errstr.c gendsa.c \ ++ genpkey.c genrsa.c nseq.c ocsp.c passwd.c pkcs12.c pkcs7.c pkcs8.c \ ++ pkey.c pkeyparam.c pkeyutl.c prime.c rand.c req.c rsa.c rsautl.c \ ++ s_client.c s_server.c s_time.c sess_id.c smime.c speed.c spkac.c \ ++ srp.c ts.c verify.c version.c x509.c rehash.c \ ++ apps.c opt.c s_cb.c s_socket.c \ ++ app_rand.c \ ++ {- $target{apps_aux_src} -} ++ INCLUDE[openssl]=.. ../include ++ DEPEND[openssl]=../libssl ++ ++ SCRIPTS=CA.pl {- $tsget_name -} ++ SOURCE[CA.pl]=CA.pl.in ++ SOURCE[{- $tsget_name -}]=tsget.in ++ENDIF +diff --git a/CryptoPkg/Library/OpensslLib/openssl/apps/ca-cert.srl b/CryptoPkg/Library/OpensslLib/openssl/apps/ca-cert.srl +new file mode 100644 +index 0000000..2c7456e +--- /dev/null ++++ b/CryptoPkg/Library/OpensslLib/openssl/apps/ca-cert.srl +@@ -0,0 +1 @@ ++07 +diff --git a/CryptoPkg/Library/OpensslLib/openssl/apps/ca-key.pem b/CryptoPkg/Library/OpensslLib/openssl/apps/ca-key.pem +new file mode 100644 +index 0000000..4e74249 +--- /dev/null ++++ b/CryptoPkg/Library/OpensslLib/openssl/apps/ca-key.pem +@@ -0,0 +1,16 @@ ++-----BEGIN PRIVATE KEY----- ++MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBAL4tQNyKy4U2zX6l ++IZvORB1edmwMwIgSB4cgoFECrG5pixzYxKauZkAwKG9/+L4DB8qXRjfXWcvafcOU ++DlYpRROykJ7wGkiqmqbZyrxY8DWjk5ZZQXiSuhYOAJB+Fyfb11JZV6+CvBQX/1g+ ++vhJr39Gmp6oAesoYrj90ecozClmnAgMBAAECgYA3j6sSg+5f9hnldUMzbPjTh8Sb ++XsJlPrc6UFrmMBzGiUleXSpe9Dbla+x0XvQCN4pwMvAN4nnWp/f0Su5BV/9Y93nb ++im5ijGNrfN9i6QrnqGCr+MMute+4E8HR2pCScX0mBLDDf40SmDvMzCaxtd21keyr ++9DqHgInQZNEi6NKlkQJBAPCbUTFg6iQ6VTCQ8CsEf5q2xHhuTK23fJ999lvWVxN7 ++QsvWb9RP9Ng34HVtvB7Pl6P7FyHLQYiDJhhvYR0L0+kCQQDKV/09Kt6Wjf5Omp1I ++wd3A+tFnipdqnPw+qNHGjevv0hYiEIWQOYbx00zXgaX+WN/pzV9eeNN2XAxlNJ++ ++dxcPAkBrzeuPKFFAcjKBVC+H1rgl5gYZv7Hzk+buv02G0H6rZ+sB0c7BXiHiTwbv ++Fn/XfkP/YR14Ms3mEH0dLaphjU8hAkEAh3Ar/rRiN04mCcEuRFQXtaNtZSv8PA2G ++Pf7MI2Y9pdHupLCAZlBLRjTUO2/5hu1AO4QPMPIZQSFN3rRBtMCL+wJAMp/m2hvI ++TmtbMp/IrKGfma09e3yFiCmoNn7cHLJ7jLvXcacV2XNzpr9YHfBxiZo0g9FqZKvv ++PZoQ5B2XJ7bhTQ== ++-----END PRIVATE KEY----- +diff --git a/CryptoPkg/Library/OpensslLib/openssl/apps/ca-req.pem b/CryptoPkg/Library/OpensslLib/openssl/apps/ca-req.pem +new file mode 100644 +index 0000000..84c6dbb +--- /dev/null ++++ b/CryptoPkg/Library/OpensslLib/openssl/apps/ca-req.pem +@@ -0,0 +1,11 @@ ++-----BEGIN CERTIFICATE REQUEST----- ++MIIBmzCCAQQCAQAwWzELMAkGA1UEBhMCQVUxEzARBgNVBAgMClF1ZWVuc2xhbmQx ++GjAYBgNVBAoMEUNyeXB0U29mdCBQdHkgTHRkMRswGQYDVQQDDBJUZXN0IENBICgx ++MDI0IGJpdCkwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAL4tQNyKy4U2zX6l ++IZvORB1edmwMwIgSB4cgoFECrG5pixzYxKauZkAwKG9/+L4DB8qXRjfXWcvafcOU ++DlYpRROykJ7wGkiqmqbZyrxY8DWjk5ZZQXiSuhYOAJB+Fyfb11JZV6+CvBQX/1g+ ++vhJr39Gmp6oAesoYrj90ecozClmnAgMBAAGgADANBgkqhkiG9w0BAQsFAAOBgQCo ++2jE7J1SNV7kyRm9m8CoPw8xYsuVcVFxPheBymYp8BlO0/rSdYygRjobpYnLVRUPZ ++pV792wzT1Rp4sXfZWO10lkFY4yi0pH2cdK2RX7qedibV1Xu9vt/yYANFBKVpA4dy ++PRyTQwi3In1N8hdfddpYR8f5MIUYRe5poFMIJcf8JA== ++-----END CERTIFICATE REQUEST----- +diff --git a/CryptoPkg/Library/OpensslLib/openssl/apps/ca.c b/CryptoPkg/Library/OpensslLib/openssl/apps/ca.c +new file mode 100644 +index 0000000..1fb7b08 +--- /dev/null ++++ b/CryptoPkg/Library/OpensslLib/openssl/apps/ca.c +@@ -0,0 +1,2565 @@ ++/* ++ * Copyright 1995-2016 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 ++ * in the file LICENSE in the source distribution or at ++ * https://www.openssl.org/source/license.html ++ */ ++ ++/* The PPKI stuff has been donated by Jeff Barber */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#ifndef W_OK ++# ifdef OPENSSL_SYS_VMS ++# if defined(__DECC) ++# include ++# else ++# include ++# endif ++# elif !defined(OPENSSL_SYS_VXWORKS) && !defined(OPENSSL_SYS_WINDOWS) ++# include ++# endif ++#endif ++ ++#include "apps.h" ++ ++#ifndef W_OK ++# define F_OK 0 ++# define X_OK 1 ++# define W_OK 2 ++# define R_OK 4 ++#endif ++ ++#undef BSIZE ++#define BSIZE 256 ++ ++#define BASE_SECTION "ca" ++ ++#define ENV_DEFAULT_CA "default_ca" ++ ++#define STRING_MASK "string_mask" ++#define UTF8_IN "utf8" ++ ++#define ENV_NEW_CERTS_DIR "new_certs_dir" ++#define ENV_CERTIFICATE "certificate" ++#define ENV_SERIAL "serial" ++#define ENV_CRLNUMBER "crlnumber" ++#define ENV_PRIVATE_KEY "private_key" ++#define ENV_DEFAULT_DAYS "default_days" ++#define ENV_DEFAULT_STARTDATE "default_startdate" ++#define ENV_DEFAULT_ENDDATE "default_enddate" ++#define ENV_DEFAULT_CRL_DAYS "default_crl_days" ++#define ENV_DEFAULT_CRL_HOURS "default_crl_hours" ++#define ENV_DEFAULT_MD "default_md" ++#define ENV_DEFAULT_EMAIL_DN "email_in_dn" ++#define ENV_PRESERVE "preserve" ++#define ENV_POLICY "policy" ++#define ENV_EXTENSIONS "x509_extensions" ++#define ENV_CRLEXT "crl_extensions" ++#define ENV_MSIE_HACK "msie_hack" ++#define ENV_NAMEOPT "name_opt" ++#define ENV_CERTOPT "cert_opt" ++#define ENV_EXTCOPY "copy_extensions" ++#define ENV_UNIQUE_SUBJECT "unique_subject" ++ ++#define ENV_DATABASE "database" ++ ++/* Additional revocation information types */ ++ ++#define REV_NONE 0 /* No additional information */ ++#define REV_CRL_REASON 1 /* Value is CRL reason code */ ++#define REV_HOLD 2 /* Value is hold instruction */ ++#define REV_KEY_COMPROMISE 3 /* Value is cert key compromise time */ ++#define REV_CA_COMPROMISE 4 /* Value is CA key compromise time */ ++ ++static char *lookup_conf(const CONF *conf, const char *group, const char *tag); ++ ++static int certify(X509 **xret, const char *infile, EVP_PKEY *pkey, X509 *x509, ++ const EVP_MD *dgst, STACK_OF(OPENSSL_STRING) *sigopts, ++ STACK_OF(CONF_VALUE) *policy, CA_DB *db, ++ BIGNUM *serial, const char *subj, unsigned long chtype, ++ int multirdn, int email_dn, const char *startdate, ++ const char *enddate, ++ long days, int batch, const char *ext_sect, CONF *conf, ++ int verbose, unsigned long certopt, unsigned long nameopt, ++ int default_op, int ext_copy, int selfsign); ++static int certify_cert(X509 **xret, const char *infile, EVP_PKEY *pkey, X509 *x509, ++ const EVP_MD *dgst, STACK_OF(OPENSSL_STRING) *sigopts, ++ STACK_OF(CONF_VALUE) *policy, CA_DB *db, ++ BIGNUM *serial, const char *subj, unsigned long chtype, ++ int multirdn, int email_dn, const char *startdate, ++ const char *enddate, long days, int batch, const char *ext_sect, ++ CONF *conf, int verbose, unsigned long certopt, ++ unsigned long nameopt, int default_op, int ext_copy); ++static int certify_spkac(X509 **xret, const char *infile, EVP_PKEY *pkey, ++ X509 *x509, const EVP_MD *dgst, ++ STACK_OF(OPENSSL_STRING) *sigopts, ++ STACK_OF(CONF_VALUE) *policy, CA_DB *db, ++ BIGNUM *serial, const char *subj, unsigned long chtype, ++ int multirdn, int email_dn, const char *startdate, ++ const char *enddate, long days, const char *ext_sect, CONF *conf, ++ int verbose, unsigned long certopt, ++ unsigned long nameopt, int default_op, int ext_copy); ++static void write_new_certificate(BIO *bp, X509 *x, int output_der, int notext); ++static int do_body(X509 **xret, EVP_PKEY *pkey, X509 *x509, ++ const EVP_MD *dgst, STACK_OF(OPENSSL_STRING) *sigopts, ++ STACK_OF(CONF_VALUE) *policy, CA_DB *db, BIGNUM *serial, ++ const char *subj, unsigned long chtype, int multirdn, ++ int email_dn, const char *startdate, const char *enddate, long days, ++ int batch, int verbose, X509_REQ *req, const char *ext_sect, ++ CONF *conf, unsigned long certopt, unsigned long nameopt, ++ int default_op, int ext_copy, int selfsign); ++static int do_revoke(X509 *x509, CA_DB *db, int ext, char *extval); ++static int get_certificate_status(const char *ser_status, CA_DB *db); ++static int do_updatedb(CA_DB *db); ++static int check_time_format(const char *str); ++char *make_revocation_str(int rev_type, char *rev_arg); ++int make_revoked(X509_REVOKED *rev, const char *str); ++static int old_entry_print(const ASN1_OBJECT *obj, const ASN1_STRING *str); ++ ++static CONF *extconf = NULL; ++static int preserve = 0; ++static int msie_hack = 0; ++ ++typedef enum OPTION_choice { ++ OPT_ERR = -1, OPT_EOF = 0, OPT_HELP, ++ OPT_ENGINE, OPT_VERBOSE, OPT_CONFIG, OPT_NAME, OPT_SUBJ, OPT_UTF8, ++ OPT_CREATE_SERIAL, OPT_MULTIVALUE_RDN, OPT_STARTDATE, OPT_ENDDATE, ++ OPT_DAYS, OPT_MD, OPT_POLICY, OPT_KEYFILE, OPT_KEYFORM, OPT_PASSIN, ++ OPT_KEY, OPT_CERT, OPT_SELFSIGN, OPT_IN, OPT_OUT, OPT_OUTDIR, ++ OPT_SIGOPT, OPT_NOTEXT, OPT_BATCH, OPT_PRESERVEDN, OPT_NOEMAILDN, ++ OPT_GENCRL, OPT_MSIE_HACK, OPT_CRLDAYS, OPT_CRLHOURS, OPT_CRLSEC, ++ OPT_INFILES, OPT_SS_CERT, OPT_SPKAC, OPT_REVOKE, OPT_VALID, ++ OPT_EXTENSIONS, OPT_EXTFILE, OPT_STATUS, OPT_UPDATEDB, OPT_CRLEXTS, ++ OPT_CRL_REASON, OPT_CRL_HOLD, OPT_CRL_COMPROMISE, ++ OPT_CRL_CA_COMPROMISE ++} OPTION_CHOICE; ++ ++OPTIONS ca_options[] = { ++ {"help", OPT_HELP, '-', "Display this summary"}, ++ {"verbose", OPT_VERBOSE, '-', "Verbose output during processing"}, ++ {"config", OPT_CONFIG, 's', "A config file"}, ++ {"name", OPT_NAME, 's', "The particular CA definition to use"}, ++ {"subj", OPT_SUBJ, 's', "Use arg instead of request's subject"}, ++ {"utf8", OPT_UTF8, '-', "Input characters are UTF8 (default ASCII)"}, ++ {"create_serial", OPT_CREATE_SERIAL, '-', ++ "If reading serial fails, create a new random serial"}, ++ {"multivalue-rdn", OPT_MULTIVALUE_RDN, '-', ++ "Enable support for multivalued RDNs"}, ++ {"startdate", OPT_STARTDATE, 's', "Cert notBefore, YYMMDDHHMMSSZ"}, ++ {"enddate", OPT_ENDDATE, 's', ++ "YYMMDDHHMMSSZ cert notAfter (overrides -days)"}, ++ {"days", OPT_DAYS, 'p', "Number of days to certify the cert for"}, ++ {"md", OPT_MD, 's', "md to use; one of md2, md5, sha or sha1"}, ++ {"policy", OPT_POLICY, 's', "The CA 'policy' to support"}, ++ {"keyfile", OPT_KEYFILE, 's', "Private key"}, ++ {"keyform", OPT_KEYFORM, 'f', "Private key file format (PEM or ENGINE)"}, ++ {"passin", OPT_PASSIN, 's', "Input file pass phrase source"}, ++ {"key", OPT_KEY, 's', "Key to decode the private key if it is encrypted"}, ++ {"cert", OPT_CERT, '<', "The CA cert"}, ++ {"selfsign", OPT_SELFSIGN, '-', ++ "Sign a cert with the key associated with it"}, ++ {"in", OPT_IN, '<', "The input PEM encoded cert request(s)"}, ++ {"out", OPT_OUT, '>', "Where to put the output file(s)"}, ++ {"outdir", OPT_OUTDIR, '/', "Where to put output cert"}, ++ {"sigopt", OPT_SIGOPT, 's', "Signature parameter in n:v form"}, ++ {"notext", OPT_NOTEXT, '-', "Do not print the generated certificate"}, ++ {"batch", OPT_BATCH, '-', "Don't ask questions"}, ++ {"preserveDN", OPT_PRESERVEDN, '-', "Don't re-order the DN"}, ++ {"noemailDN", OPT_NOEMAILDN, '-', "Don't add the EMAIL field to the DN"}, ++ {"gencrl", OPT_GENCRL, '-', "Generate a new CRL"}, ++ {"msie_hack", OPT_MSIE_HACK, '-', ++ "msie modifications to handle all those universal strings"}, ++ {"crldays", OPT_CRLDAYS, 'p', "Days until the next CRL is due"}, ++ {"crlhours", OPT_CRLHOURS, 'p', "Hours until the next CRL is due"}, ++ {"crlsec", OPT_CRLSEC, 'p', "Seconds until the next CRL is due"}, ++ {"infiles", OPT_INFILES, '-', "The last argument, requests to process"}, ++ {"ss_cert", OPT_SS_CERT, '<', "File contains a self signed cert to sign"}, ++ {"spkac", OPT_SPKAC, '<', ++ "File contains DN and signed public key and challenge"}, ++ {"revoke", OPT_REVOKE, '<', "Revoke a cert (given in file)"}, ++ {"valid", OPT_VALID, 's', ++ "Add a Valid(not-revoked) DB entry about a cert (given in file)"}, ++ {"extensions", OPT_EXTENSIONS, 's', ++ "Extension section (override value in config file)"}, ++ {"extfile", OPT_EXTFILE, '<', ++ "Configuration file with X509v3 extensions to add"}, ++ {"status", OPT_STATUS, 's', "Shows cert status given the serial number"}, ++ {"updatedb", OPT_UPDATEDB, '-', "Updates db for expired cert"}, ++ {"crlexts", OPT_CRLEXTS, 's', ++ "CRL extension section (override value in config file)"}, ++ {"crl_reason", OPT_CRL_REASON, 's', "revocation reason"}, ++ {"crl_hold", OPT_CRL_HOLD, 's', ++ "the hold instruction, an OID. Sets revocation reason to certificateHold"}, ++ {"crl_compromise", OPT_CRL_COMPROMISE, 's', ++ "sets compromise time to val and the revocation reason to keyCompromise"}, ++ {"crl_CA_compromise", OPT_CRL_CA_COMPROMISE, 's', ++ "sets compromise time to val and the revocation reason to CACompromise"}, ++#ifndef OPENSSL_NO_ENGINE ++ {"engine", OPT_ENGINE, 's', "Use engine, possibly a hardware device"}, ++#endif ++ {NULL} ++}; ++ ++int ca_main(int argc, char **argv) ++{ ++ CONF *conf = NULL; ++ ENGINE *e = NULL; ++ BIGNUM *crlnumber = NULL, *serial = NULL; ++ EVP_PKEY *pkey = NULL; ++ BIO *in = NULL, *out = NULL, *Sout = NULL; ++ ASN1_INTEGER *tmpser; ++ ASN1_TIME *tmptm; ++ CA_DB *db = NULL; ++ DB_ATTR db_attr; ++ STACK_OF(CONF_VALUE) *attribs = NULL; ++ STACK_OF(OPENSSL_STRING) *sigopts = NULL; ++ STACK_OF(X509) *cert_sk = NULL; ++ X509_CRL *crl = NULL; ++ const EVP_MD *dgst = NULL; ++ char *configfile = default_config_file, *section = NULL; ++ char *md = NULL, *policy = NULL, *keyfile = NULL; ++ char *certfile = NULL, *crl_ext = NULL, *crlnumberfile = NULL, *key = NULL; ++ const char *infile = NULL, *spkac_file = NULL, *ss_cert_file = NULL; ++ const char *extensions = NULL, *extfile = NULL, *passinarg = NULL; ++ char *outdir = NULL, *outfile = NULL, *rev_arg = NULL, *ser_status = NULL; ++ const char *serialfile = NULL, *subj = NULL; ++ char *prog, *startdate = NULL, *enddate = NULL; ++ char *dbfile = NULL, *f, *randfile = NULL; ++ char buf[3][BSIZE]; ++ char *const *pp; ++ const char *p; ++ int create_ser = 0, free_key = 0, total = 0, total_done = 0; ++ int batch = 0, default_op = 1, doupdatedb = 0, ext_copy = EXT_COPY_NONE; ++ int keyformat = FORMAT_PEM, multirdn = 0, notext = 0, output_der = 0; ++ int ret = 1, email_dn = 1, req = 0, verbose = 0, gencrl = 0, dorevoke = 0; ++ int i, j, rev_type = REV_NONE, selfsign = 0; ++ long crldays = 0, crlhours = 0, crlsec = 0, days = 0; ++ unsigned long chtype = MBSTRING_ASC, nameopt = 0, certopt = 0; ++ X509 *x509 = NULL, *x509p = NULL, *x = NULL; ++ X509_REVOKED *r = NULL; ++ OPTION_CHOICE o; ++ ++ prog = opt_init(argc, argv, ca_options); ++ while ((o = opt_next()) != OPT_EOF) { ++ switch (o) { ++ case OPT_EOF: ++ case OPT_ERR: ++opthelp: ++ BIO_printf(bio_err, "%s: Use -help for summary.\n", prog); ++ goto end; ++ case OPT_HELP: ++ opt_help(ca_options); ++ ret = 0; ++ goto end; ++ case OPT_IN: ++ req = 1; ++ infile = opt_arg(); ++ break; ++ case OPT_OUT: ++ outfile = opt_arg(); ++ break; ++ case OPT_VERBOSE: ++ verbose = 1; ++ break; ++ case OPT_CONFIG: ++ configfile = opt_arg(); ++ break; ++ case OPT_NAME: ++ section = opt_arg(); ++ break; ++ case OPT_SUBJ: ++ subj = opt_arg(); ++ /* preserve=1; */ ++ break; ++ case OPT_UTF8: ++ chtype = MBSTRING_UTF8; ++ break; ++ case OPT_CREATE_SERIAL: ++ create_ser = 1; ++ break; ++ case OPT_MULTIVALUE_RDN: ++ multirdn = 1; ++ break; ++ case OPT_STARTDATE: ++ startdate = opt_arg(); ++ break; ++ case OPT_ENDDATE: ++ enddate = opt_arg(); ++ break; ++ case OPT_DAYS: ++ days = atoi(opt_arg()); ++ break; ++ case OPT_MD: ++ md = opt_arg(); ++ break; ++ case OPT_POLICY: ++ policy = opt_arg(); ++ break; ++ case OPT_KEYFILE: ++ keyfile = opt_arg(); ++ break; ++ case OPT_KEYFORM: ++ if (!opt_format(opt_arg(), OPT_FMT_ANY, &keyformat)) ++ goto opthelp; ++ break; ++ case OPT_PASSIN: ++ passinarg = opt_arg(); ++ break; ++ case OPT_KEY: ++ key = opt_arg(); ++ break; ++ case OPT_CERT: ++ certfile = opt_arg(); ++ break; ++ case OPT_SELFSIGN: ++ selfsign = 1; ++ break; ++ case OPT_OUTDIR: ++ outdir = opt_arg(); ++ break; ++ case OPT_SIGOPT: ++ if (sigopts == NULL) ++ sigopts = sk_OPENSSL_STRING_new_null(); ++ if (sigopts == NULL ++ || !sk_OPENSSL_STRING_push(sigopts, opt_arg())) ++ goto end; ++ break; ++ case OPT_NOTEXT: ++ notext = 1; ++ break; ++ case OPT_BATCH: ++ batch = 1; ++ break; ++ case OPT_PRESERVEDN: ++ preserve = 1; ++ break; ++ case OPT_NOEMAILDN: ++ email_dn = 0; ++ break; ++ case OPT_GENCRL: ++ gencrl = 1; ++ break; ++ case OPT_MSIE_HACK: ++ msie_hack = 1; ++ break; ++ case OPT_CRLDAYS: ++ crldays = atol(opt_arg()); ++ break; ++ case OPT_CRLHOURS: ++ crlhours = atol(opt_arg()); ++ break; ++ case OPT_CRLSEC: ++ crlsec = atol(opt_arg()); ++ break; ++ case OPT_INFILES: ++ req = 1; ++ goto end_of_options; ++ case OPT_SS_CERT: ++ ss_cert_file = opt_arg(); ++ req = 1; ++ break; ++ case OPT_SPKAC: ++ spkac_file = opt_arg(); ++ req = 1; ++ break; ++ case OPT_REVOKE: ++ infile = opt_arg(); ++ dorevoke = 1; ++ break; ++ case OPT_VALID: ++ infile = opt_arg(); ++ dorevoke = 2; ++ break; ++ case OPT_EXTENSIONS: ++ extensions = opt_arg(); ++ break; ++ case OPT_EXTFILE: ++ extfile = opt_arg(); ++ break; ++ case OPT_STATUS: ++ ser_status = opt_arg(); ++ break; ++ case OPT_UPDATEDB: ++ doupdatedb = 1; ++ break; ++ case OPT_CRLEXTS: ++ crl_ext = opt_arg(); ++ break; ++ case OPT_CRL_REASON: ++ rev_arg = opt_arg(); ++ rev_type = REV_CRL_REASON; ++ break; ++ case OPT_CRL_HOLD: ++ rev_arg = opt_arg(); ++ rev_type = REV_HOLD; ++ break; ++ case OPT_CRL_COMPROMISE: ++ rev_arg = opt_arg(); ++ rev_type = REV_KEY_COMPROMISE; ++ break; ++ case OPT_CRL_CA_COMPROMISE: ++ rev_arg = opt_arg(); ++ rev_type = REV_CA_COMPROMISE; ++ break; ++ case OPT_ENGINE: ++ e = setup_engine(opt_arg(), 0); ++ break; ++ } ++ } ++end_of_options: ++ argc = opt_num_rest(); ++ argv = opt_rest(); ++ ++ BIO_printf(bio_err, "Using configuration from %s\n", configfile); ++ ++ if ((conf = app_load_config(configfile)) == NULL) ++ goto end; ++ if (configfile != default_config_file && !app_load_modules(conf)) ++ goto end; ++ ++ /* Lets get the config section we are using */ ++ if (section == NULL ++ && (section = lookup_conf(conf, BASE_SECTION, ENV_DEFAULT_CA)) == NULL) ++ goto end; ++ ++ if (conf != NULL) { ++ p = NCONF_get_string(conf, NULL, "oid_file"); ++ if (p == NULL) ++ ERR_clear_error(); ++ if (p != NULL) { ++ BIO *oid_bio; ++ ++ oid_bio = BIO_new_file(p, "r"); ++ if (oid_bio == NULL) { ++ /*- ++ BIO_printf(bio_err,"problems opening %s for extra oid's\n",p); ++ ERR_print_errors(bio_err); ++ */ ++ ERR_clear_error(); ++ } else { ++ OBJ_create_objects(oid_bio); ++ BIO_free(oid_bio); ++ } ++ } ++ if (!add_oid_section(conf)) { ++ ERR_print_errors(bio_err); ++ goto end; ++ } ++ } ++ ++ randfile = NCONF_get_string(conf, BASE_SECTION, "RANDFILE"); ++ if (randfile == NULL) ++ ERR_clear_error(); ++ app_RAND_load_file(randfile, 0); ++ ++ f = NCONF_get_string(conf, section, STRING_MASK); ++ if (!f) ++ ERR_clear_error(); ++ ++ if (f && !ASN1_STRING_set_default_mask_asc(f)) { ++ BIO_printf(bio_err, "Invalid global string mask setting %s\n", f); ++ goto end; ++ } ++ ++ if (chtype != MBSTRING_UTF8) { ++ f = NCONF_get_string(conf, section, UTF8_IN); ++ if (!f) ++ ERR_clear_error(); ++ else if (strcmp(f, "yes") == 0) ++ chtype = MBSTRING_UTF8; ++ } ++ ++ db_attr.unique_subject = 1; ++ p = NCONF_get_string(conf, section, ENV_UNIQUE_SUBJECT); ++ if (p) { ++ db_attr.unique_subject = parse_yesno(p, 1); ++ } else ++ ERR_clear_error(); ++ ++ /*****************************************************************/ ++ /* report status of cert with serial number given on command line */ ++ if (ser_status) { ++ dbfile = lookup_conf(conf, section, ENV_DATABASE); ++ if (dbfile == NULL) ++ goto end; ++ ++ db = load_index(dbfile, &db_attr); ++ if (db == NULL) ++ goto end; ++ ++ if (!index_index(db)) ++ goto end; ++ ++ if (get_certificate_status(ser_status, db) != 1) ++ BIO_printf(bio_err, "Error verifying serial %s!\n", ser_status); ++ goto end; ++ } ++ ++ /*****************************************************************/ ++ /* we definitely need a private key, so let's get it */ ++ ++ if (keyfile == NULL ++ && (keyfile = lookup_conf(conf, section, ENV_PRIVATE_KEY)) == NULL) ++ goto end; ++ ++ if (!key) { ++ free_key = 1; ++ if (!app_passwd(passinarg, NULL, &key, NULL)) { ++ BIO_printf(bio_err, "Error getting password\n"); ++ goto end; ++ } ++ } ++ pkey = load_key(keyfile, keyformat, 0, key, e, "CA private key"); ++ if (key) ++ OPENSSL_cleanse(key, strlen(key)); ++ if (pkey == NULL) { ++ /* load_key() has already printed an appropriate message */ ++ goto end; ++ } ++ ++ /*****************************************************************/ ++ /* we need a certificate */ ++ if (!selfsign || spkac_file || ss_cert_file || gencrl) { ++ if (certfile == NULL ++ && (certfile = lookup_conf(conf, section, ENV_CERTIFICATE)) == NULL) ++ goto end; ++ ++ x509 = load_cert(certfile, FORMAT_PEM, "CA certificate"); ++ if (x509 == NULL) ++ goto end; ++ ++ if (!X509_check_private_key(x509, pkey)) { ++ BIO_printf(bio_err, ++ "CA certificate and CA private key do not match\n"); ++ goto end; ++ } ++ } ++ if (!selfsign) ++ x509p = x509; ++ ++ f = NCONF_get_string(conf, BASE_SECTION, ENV_PRESERVE); ++ if (f == NULL) ++ ERR_clear_error(); ++ if ((f != NULL) && ((*f == 'y') || (*f == 'Y'))) ++ preserve = 1; ++ f = NCONF_get_string(conf, BASE_SECTION, ENV_MSIE_HACK); ++ if (f == NULL) ++ ERR_clear_error(); ++ if ((f != NULL) && ((*f == 'y') || (*f == 'Y'))) ++ msie_hack = 1; ++ ++ f = NCONF_get_string(conf, section, ENV_NAMEOPT); ++ ++ if (f) { ++ if (!set_name_ex(&nameopt, f)) { ++ BIO_printf(bio_err, "Invalid name options: \"%s\"\n", f); ++ goto end; ++ } ++ default_op = 0; ++ } else { ++ nameopt = XN_FLAG_ONELINE; ++ ERR_clear_error(); ++ } ++ ++ f = NCONF_get_string(conf, section, ENV_CERTOPT); ++ ++ if (f) { ++ if (!set_cert_ex(&certopt, f)) { ++ BIO_printf(bio_err, "Invalid certificate options: \"%s\"\n", f); ++ goto end; ++ } ++ default_op = 0; ++ } else ++ ERR_clear_error(); ++ ++ f = NCONF_get_string(conf, section, ENV_EXTCOPY); ++ ++ if (f) { ++ if (!set_ext_copy(&ext_copy, f)) { ++ BIO_printf(bio_err, "Invalid extension copy option: \"%s\"\n", f); ++ goto end; ++ } ++ } else ++ ERR_clear_error(); ++ ++ /*****************************************************************/ ++ /* lookup where to write new certificates */ ++ if ((outdir == NULL) && (req)) { ++ ++ outdir = NCONF_get_string(conf, section, ENV_NEW_CERTS_DIR); ++ if (outdir == NULL) { ++ BIO_printf(bio_err, ++ "there needs to be defined a directory for new certificate to be placed in\n"); ++ goto end; ++ } ++#ifndef OPENSSL_SYS_VMS ++ /* ++ * outdir is a directory spec, but access() for VMS demands a ++ * filename. We could use the DEC C routine to convert the ++ * directory syntax to Unixly, and give that to app_isdir, ++ * but for now the fopen will catch the error if it's not a ++ * directory ++ */ ++ if (app_isdir(outdir) <= 0) { ++ BIO_printf(bio_err, "%s: %s is not a directory\n", prog, outdir); ++ perror(outdir); ++ goto end; ++ } ++#endif ++ } ++ ++ /*****************************************************************/ ++ /* we need to load the database file */ ++ dbfile = lookup_conf(conf, section, ENV_DATABASE); ++ if (dbfile == NULL) ++ goto end; ++ ++ db = load_index(dbfile, &db_attr); ++ if (db == NULL) ++ goto end; ++ ++ /* Lets check some fields */ ++ for (i = 0; i < sk_OPENSSL_PSTRING_num(db->db->data); i++) { ++ pp = sk_OPENSSL_PSTRING_value(db->db->data, i); ++ if ((pp[DB_type][0] != DB_TYPE_REV) && (pp[DB_rev_date][0] != '\0')) { ++ BIO_printf(bio_err, ++ "entry %d: not revoked yet, but has a revocation date\n", ++ i + 1); ++ goto end; ++ } ++ if ((pp[DB_type][0] == DB_TYPE_REV) && ++ !make_revoked(NULL, pp[DB_rev_date])) { ++ BIO_printf(bio_err, " in entry %d\n", i + 1); ++ goto end; ++ } ++ if (!check_time_format((char *)pp[DB_exp_date])) { ++ BIO_printf(bio_err, "entry %d: invalid expiry date\n", i + 1); ++ goto end; ++ } ++ p = pp[DB_serial]; ++ j = strlen(p); ++ if (*p == '-') { ++ p++; ++ j--; ++ } ++ if ((j & 1) || (j < 2)) { ++ BIO_printf(bio_err, "entry %d: bad serial number length (%d)\n", ++ i + 1, j); ++ goto end; ++ } ++ for ( ; *p; p++) { ++ if (!isxdigit(_UC(*p))) { ++ BIO_printf(bio_err, ++ "entry %d: bad char 0%o '%c' in serial number\n", ++ i + 1, *p, *p); ++ goto end; ++ } ++ } ++ } ++ if (verbose) { ++ TXT_DB_write(bio_out, db->db); ++ BIO_printf(bio_err, "%d entries loaded from the database\n", ++ sk_OPENSSL_PSTRING_num(db->db->data)); ++ BIO_printf(bio_err, "generating index\n"); ++ } ++ ++ if (!index_index(db)) ++ goto end; ++ ++ /*****************************************************************/ ++ /* Update the db file for expired certificates */ ++ if (doupdatedb) { ++ if (verbose) ++ BIO_printf(bio_err, "Updating %s ...\n", dbfile); ++ ++ i = do_updatedb(db); ++ if (i == -1) { ++ BIO_printf(bio_err, "Malloc failure\n"); ++ goto end; ++ } else if (i == 0) { ++ if (verbose) ++ BIO_printf(bio_err, "No entries found to mark expired\n"); ++ } else { ++ if (!save_index(dbfile, "new", db)) ++ goto end; ++ ++ if (!rotate_index(dbfile, "new", "old")) ++ goto end; ++ ++ if (verbose) ++ BIO_printf(bio_err, ++ "Done. %d entries marked as expired\n", i); ++ } ++ } ++ ++ /*****************************************************************/ ++ /* Read extensions config file */ ++ if (extfile) { ++ if ((extconf = app_load_config(extfile)) == NULL) { ++ ret = 1; ++ goto end; ++ } ++ ++ if (verbose) ++ BIO_printf(bio_err, "Successfully loaded extensions file %s\n", ++ extfile); ++ ++ /* We can have sections in the ext file */ ++ if (extensions == NULL) { ++ extensions = NCONF_get_string(extconf, "default", "extensions"); ++ if (extensions == NULL) ++ extensions = "default"; ++ } ++ } ++ ++ /*****************************************************************/ ++ if (req || gencrl) { ++ /* FIXME: Is it really always text? */ ++ Sout = bio_open_default(outfile, 'w', FORMAT_TEXT); ++ if (Sout == NULL) ++ goto end; ++ } ++ ++ if (md == NULL ++ && (md = lookup_conf(conf, section, ENV_DEFAULT_MD)) == NULL) ++ goto end; ++ ++ if (strcmp(md, "default") == 0) { ++ int def_nid; ++ if (EVP_PKEY_get_default_digest_nid(pkey, &def_nid) <= 0) { ++ BIO_puts(bio_err, "no default digest\n"); ++ goto end; ++ } ++ md = (char *)OBJ_nid2sn(def_nid); ++ } ++ ++ if (!opt_md(md, &dgst)) { ++ goto end; ++ } ++ ++ if (req) { ++ if (email_dn == 1) { ++ char *tmp_email_dn = NULL; ++ ++ tmp_email_dn = NCONF_get_string(conf, section, ENV_DEFAULT_EMAIL_DN); ++ if (tmp_email_dn != NULL && strcmp(tmp_email_dn, "no") == 0) ++ email_dn = 0; ++ } ++ if (verbose) ++ BIO_printf(bio_err, "message digest is %s\n", ++ OBJ_nid2ln(EVP_MD_type(dgst))); ++ if (policy == NULL ++ && (policy = lookup_conf(conf, section, ENV_POLICY)) == NULL) ++ goto end; ++ ++ if (verbose) ++ BIO_printf(bio_err, "policy is %s\n", policy); ++ ++ serialfile = lookup_conf(conf, section, ENV_SERIAL); ++ if (serialfile == NULL) ++ goto end; ++ ++ if (!extconf) { ++ /* ++ * no '-extfile' option, so we look for extensions in the main ++ * configuration file ++ */ ++ if (!extensions) { ++ extensions = NCONF_get_string(conf, section, ENV_EXTENSIONS); ++ if (!extensions) ++ ERR_clear_error(); ++ } ++ if (extensions) { ++ /* Check syntax of file */ ++ X509V3_CTX ctx; ++ X509V3_set_ctx_test(&ctx); ++ X509V3_set_nconf(&ctx, conf); ++ if (!X509V3_EXT_add_nconf(conf, &ctx, extensions, NULL)) { ++ BIO_printf(bio_err, ++ "Error Loading extension section %s\n", ++ extensions); ++ ret = 1; ++ goto end; ++ } ++ } ++ } ++ ++ if (startdate == NULL) { ++ startdate = NCONF_get_string(conf, section, ++ ENV_DEFAULT_STARTDATE); ++ if (startdate == NULL) ++ ERR_clear_error(); ++ } ++ if (startdate && !ASN1_TIME_set_string(NULL, startdate)) { ++ BIO_printf(bio_err, ++ "start date is invalid, it should be YYMMDDHHMMSSZ or YYYYMMDDHHMMSSZ\n"); ++ goto end; ++ } ++ if (startdate == NULL) ++ startdate = "today"; ++ ++ if (enddate == NULL) { ++ enddate = NCONF_get_string(conf, section, ENV_DEFAULT_ENDDATE); ++ if (enddate == NULL) ++ ERR_clear_error(); ++ } ++ if (enddate && !ASN1_TIME_set_string(NULL, enddate)) { ++ BIO_printf(bio_err, ++ "end date is invalid, it should be YYMMDDHHMMSSZ or YYYYMMDDHHMMSSZ\n"); ++ goto end; ++ } ++ ++ if (days == 0) { ++ if (!NCONF_get_number(conf, section, ENV_DEFAULT_DAYS, &days)) ++ days = 0; ++ } ++ if (!enddate && (days == 0)) { ++ BIO_printf(bio_err, ++ "cannot lookup how many days to certify for\n"); ++ goto end; ++ } ++ ++ if ((serial = load_serial(serialfile, create_ser, NULL)) == NULL) { ++ BIO_printf(bio_err, "error while loading serial number\n"); ++ goto end; ++ } ++ if (verbose) { ++ if (BN_is_zero(serial)) ++ BIO_printf(bio_err, "next serial number is 00\n"); ++ else { ++ if ((f = BN_bn2hex(serial)) == NULL) ++ goto end; ++ BIO_printf(bio_err, "next serial number is %s\n", f); ++ OPENSSL_free(f); ++ } ++ } ++ ++ if ((attribs = NCONF_get_section(conf, policy)) == NULL) { ++ BIO_printf(bio_err, "unable to find 'section' for %s\n", policy); ++ goto end; ++ } ++ ++ if ((cert_sk = sk_X509_new_null()) == NULL) { ++ BIO_printf(bio_err, "Memory allocation failure\n"); ++ goto end; ++ } ++ if (spkac_file != NULL) { ++ total++; ++ j = certify_spkac(&x, spkac_file, pkey, x509, dgst, sigopts, ++ attribs, db, serial, subj, chtype, multirdn, ++ email_dn, startdate, enddate, days, extensions, ++ conf, verbose, certopt, nameopt, default_op, ++ ext_copy); ++ if (j < 0) ++ goto end; ++ if (j > 0) { ++ total_done++; ++ BIO_printf(bio_err, "\n"); ++ if (!BN_add_word(serial, 1)) ++ goto end; ++ if (!sk_X509_push(cert_sk, x)) { ++ BIO_printf(bio_err, "Memory allocation failure\n"); ++ goto end; ++ } ++ if (outfile) { ++ output_der = 1; ++ batch = 1; ++ } ++ } ++ } ++ if (ss_cert_file != NULL) { ++ total++; ++ j = certify_cert(&x, ss_cert_file, pkey, x509, dgst, sigopts, ++ attribs, ++ db, serial, subj, chtype, multirdn, email_dn, ++ startdate, enddate, days, batch, extensions, ++ conf, verbose, certopt, nameopt, default_op, ++ ext_copy); ++ if (j < 0) ++ goto end; ++ if (j > 0) { ++ total_done++; ++ BIO_printf(bio_err, "\n"); ++ if (!BN_add_word(serial, 1)) ++ goto end; ++ if (!sk_X509_push(cert_sk, x)) { ++ BIO_printf(bio_err, "Memory allocation failure\n"); ++ goto end; ++ } ++ } ++ } ++ if (infile != NULL) { ++ total++; ++ j = certify(&x, infile, pkey, x509p, dgst, sigopts, attribs, db, ++ serial, subj, chtype, multirdn, email_dn, startdate, ++ enddate, days, batch, extensions, conf, verbose, ++ certopt, nameopt, default_op, ext_copy, selfsign); ++ if (j < 0) ++ goto end; ++ if (j > 0) { ++ total_done++; ++ BIO_printf(bio_err, "\n"); ++ if (!BN_add_word(serial, 1)) ++ goto end; ++ if (!sk_X509_push(cert_sk, x)) { ++ BIO_printf(bio_err, "Memory allocation failure\n"); ++ goto end; ++ } ++ } ++ } ++ for (i = 0; i < argc; i++) { ++ total++; ++ j = certify(&x, argv[i], pkey, x509p, dgst, sigopts, attribs, db, ++ serial, subj, chtype, multirdn, email_dn, startdate, ++ enddate, days, batch, extensions, conf, verbose, ++ certopt, nameopt, default_op, ext_copy, selfsign); ++ if (j < 0) ++ goto end; ++ if (j > 0) { ++ total_done++; ++ BIO_printf(bio_err, "\n"); ++ if (!BN_add_word(serial, 1)) ++ goto end; ++ if (!sk_X509_push(cert_sk, x)) { ++ BIO_printf(bio_err, "Memory allocation failure\n"); ++ goto end; ++ } ++ } ++ } ++ /* ++ * we have a stack of newly certified certificates and a data base ++ * and serial number that need updating ++ */ ++ ++ if (sk_X509_num(cert_sk) > 0) { ++ if (!batch) { ++ BIO_printf(bio_err, ++ "\n%d out of %d certificate requests certified, commit? [y/n]", ++ total_done, total); ++ (void)BIO_flush(bio_err); ++ buf[0][0] = '\0'; ++ if (!fgets(buf[0], 10, stdin)) { ++ BIO_printf(bio_err, ++ "CERTIFICATION CANCELED: I/O error\n"); ++ ret = 0; ++ goto end; ++ } ++ if ((buf[0][0] != 'y') && (buf[0][0] != 'Y')) { ++ BIO_printf(bio_err, "CERTIFICATION CANCELED\n"); ++ ret = 0; ++ goto end; ++ } ++ } ++ ++ BIO_printf(bio_err, "Write out database with %d new entries\n", ++ sk_X509_num(cert_sk)); ++ ++ if (!save_serial(serialfile, "new", serial, NULL)) ++ goto end; ++ ++ if (!save_index(dbfile, "new", db)) ++ goto end; ++ } ++ ++ if (verbose) ++ BIO_printf(bio_err, "writing new certificates\n"); ++ for (i = 0; i < sk_X509_num(cert_sk); i++) { ++ BIO *Cout = NULL; ++ X509 *xi = sk_X509_value(cert_sk, i); ++ ASN1_INTEGER *serialNumber = X509_get_serialNumber(xi); ++ int k; ++ char *n; ++ ++ j = ASN1_STRING_length(serialNumber); ++ p = (const char *)ASN1_STRING_get0_data(serialNumber); ++ ++ if (strlen(outdir) >= (size_t)(j ? BSIZE - j * 2 - 6 : BSIZE - 8)) { ++ BIO_printf(bio_err, "certificate file name too long\n"); ++ goto end; ++ } ++ ++ strcpy(buf[2], outdir); ++ ++#ifndef OPENSSL_SYS_VMS ++ OPENSSL_strlcat(buf[2], "/", sizeof(buf[2])); ++#endif ++ ++ n = (char *)&(buf[2][strlen(buf[2])]); ++ if (j > 0) { ++ for (k = 0; k < j; k++) { ++ if (n >= &(buf[2][sizeof(buf[2])])) ++ break; ++ BIO_snprintf(n, ++ &buf[2][0] + sizeof(buf[2]) - n, ++ "%02X", (unsigned char)*(p++)); ++ n += 2; ++ } ++ } else { ++ *(n++) = '0'; ++ *(n++) = '0'; ++ } ++ *(n++) = '.'; ++ *(n++) = 'p'; ++ *(n++) = 'e'; ++ *(n++) = 'm'; ++ *n = '\0'; ++ if (verbose) ++ BIO_printf(bio_err, "writing %s\n", buf[2]); ++ ++ Cout = BIO_new_file(buf[2], "w"); ++ if (Cout == NULL) { ++ perror(buf[2]); ++ goto end; ++ } ++ write_new_certificate(Cout, xi, 0, notext); ++ write_new_certificate(Sout, xi, output_der, notext); ++ BIO_free_all(Cout); ++ } ++ ++ if (sk_X509_num(cert_sk)) { ++ /* Rename the database and the serial file */ ++ if (!rotate_serial(serialfile, "new", "old")) ++ goto end; ++ ++ if (!rotate_index(dbfile, "new", "old")) ++ goto end; ++ ++ BIO_printf(bio_err, "Data Base Updated\n"); ++ } ++ } ++ ++ /*****************************************************************/ ++ if (gencrl) { ++ int crl_v2 = 0; ++ if (!crl_ext) { ++ crl_ext = NCONF_get_string(conf, section, ENV_CRLEXT); ++ if (!crl_ext) ++ ERR_clear_error(); ++ } ++ if (crl_ext) { ++ /* Check syntax of file */ ++ X509V3_CTX ctx; ++ X509V3_set_ctx_test(&ctx); ++ X509V3_set_nconf(&ctx, conf); ++ if (!X509V3_EXT_add_nconf(conf, &ctx, crl_ext, NULL)) { ++ BIO_printf(bio_err, ++ "Error Loading CRL extension section %s\n", ++ crl_ext); ++ ret = 1; ++ goto end; ++ } ++ } ++ ++ if ((crlnumberfile = NCONF_get_string(conf, section, ENV_CRLNUMBER)) ++ != NULL) ++ if ((crlnumber = load_serial(crlnumberfile, 0, NULL)) == NULL) { ++ BIO_printf(bio_err, "error while loading CRL number\n"); ++ goto end; ++ } ++ ++ if (!crldays && !crlhours && !crlsec) { ++ if (!NCONF_get_number(conf, section, ++ ENV_DEFAULT_CRL_DAYS, &crldays)) ++ crldays = 0; ++ if (!NCONF_get_number(conf, section, ++ ENV_DEFAULT_CRL_HOURS, &crlhours)) ++ crlhours = 0; ++ ERR_clear_error(); ++ } ++ if ((crldays == 0) && (crlhours == 0) && (crlsec == 0)) { ++ BIO_printf(bio_err, ++ "cannot lookup how long until the next CRL is issued\n"); ++ goto end; ++ } ++ ++ if (verbose) ++ BIO_printf(bio_err, "making CRL\n"); ++ if ((crl = X509_CRL_new()) == NULL) ++ goto end; ++ if (!X509_CRL_set_issuer_name(crl, X509_get_subject_name(x509))) ++ goto end; ++ ++ tmptm = ASN1_TIME_new(); ++ if (tmptm == NULL) ++ goto end; ++ X509_gmtime_adj(tmptm, 0); ++ X509_CRL_set1_lastUpdate(crl, tmptm); ++ if (!X509_time_adj_ex(tmptm, crldays, crlhours * 60 * 60 + crlsec, ++ NULL)) { ++ BIO_puts(bio_err, "error setting CRL nextUpdate\n"); ++ goto end; ++ } ++ X509_CRL_set1_nextUpdate(crl, tmptm); ++ ++ ASN1_TIME_free(tmptm); ++ ++ for (i = 0; i < sk_OPENSSL_PSTRING_num(db->db->data); i++) { ++ pp = sk_OPENSSL_PSTRING_value(db->db->data, i); ++ if (pp[DB_type][0] == DB_TYPE_REV) { ++ if ((r = X509_REVOKED_new()) == NULL) ++ goto end; ++ j = make_revoked(r, pp[DB_rev_date]); ++ if (!j) ++ goto end; ++ if (j == 2) ++ crl_v2 = 1; ++ if (!BN_hex2bn(&serial, pp[DB_serial])) ++ goto end; ++ tmpser = BN_to_ASN1_INTEGER(serial, NULL); ++ BN_free(serial); ++ serial = NULL; ++ if (!tmpser) ++ goto end; ++ X509_REVOKED_set_serialNumber(r, tmpser); ++ ASN1_INTEGER_free(tmpser); ++ X509_CRL_add0_revoked(crl, r); ++ } ++ } ++ ++ /* ++ * sort the data so it will be written in serial number order ++ */ ++ X509_CRL_sort(crl); ++ ++ /* we now have a CRL */ ++ if (verbose) ++ BIO_printf(bio_err, "signing CRL\n"); ++ ++ /* Add any extensions asked for */ ++ ++ if (crl_ext || crlnumberfile != NULL) { ++ X509V3_CTX crlctx; ++ X509V3_set_ctx(&crlctx, x509, NULL, NULL, crl, 0); ++ X509V3_set_nconf(&crlctx, conf); ++ ++ if (crl_ext) ++ if (!X509V3_EXT_CRL_add_nconf(conf, &crlctx, crl_ext, crl)) ++ goto end; ++ if (crlnumberfile != NULL) { ++ tmpser = BN_to_ASN1_INTEGER(crlnumber, NULL); ++ if (!tmpser) ++ goto end; ++ X509_CRL_add1_ext_i2d(crl, NID_crl_number, tmpser, 0, 0); ++ ASN1_INTEGER_free(tmpser); ++ crl_v2 = 1; ++ if (!BN_add_word(crlnumber, 1)) ++ goto end; ++ } ++ } ++ if (crl_ext || crl_v2) { ++ if (!X509_CRL_set_version(crl, 1)) ++ goto end; /* version 2 CRL */ ++ } ++ ++ /* we have a CRL number that need updating */ ++ if (crlnumberfile != NULL) ++ if (!save_serial(crlnumberfile, "new", crlnumber, NULL)) ++ goto end; ++ ++ BN_free(crlnumber); ++ crlnumber = NULL; ++ ++ if (!do_X509_CRL_sign(crl, pkey, dgst, sigopts)) ++ goto end; ++ ++ PEM_write_bio_X509_CRL(Sout, crl); ++ ++ if (crlnumberfile != NULL) /* Rename the crlnumber file */ ++ if (!rotate_serial(crlnumberfile, "new", "old")) ++ goto end; ++ ++ } ++ /*****************************************************************/ ++ if (dorevoke) { ++ if (infile == NULL) { ++ BIO_printf(bio_err, "no input files\n"); ++ goto end; ++ } else { ++ X509 *revcert; ++ revcert = load_cert(infile, FORMAT_PEM, infile); ++ if (revcert == NULL) ++ goto end; ++ if (dorevoke == 2) ++ rev_type = -1; ++ j = do_revoke(revcert, db, rev_type, rev_arg); ++ if (j <= 0) ++ goto end; ++ X509_free(revcert); ++ ++ if (!save_index(dbfile, "new", db)) ++ goto end; ++ ++ if (!rotate_index(dbfile, "new", "old")) ++ goto end; ++ ++ BIO_printf(bio_err, "Data Base Updated\n"); ++ } ++ } ++ /*****************************************************************/ ++ ret = 0; ++ end: ++ BIO_free_all(Sout); ++ BIO_free_all(out); ++ BIO_free_all(in); ++ sk_X509_pop_free(cert_sk, X509_free); ++ ++ if (ret) ++ ERR_print_errors(bio_err); ++ app_RAND_write_file(randfile); ++ if (free_key) ++ OPENSSL_free(key); ++ BN_free(serial); ++ BN_free(crlnumber); ++ free_index(db); ++ sk_OPENSSL_STRING_free(sigopts); ++ EVP_PKEY_free(pkey); ++ X509_free(x509); ++ X509_CRL_free(crl); ++ NCONF_free(conf); ++ NCONF_free(extconf); ++ release_engine(e); ++ return (ret); ++} ++ ++static char *lookup_conf(const CONF *conf, const char *section, const char *tag) ++{ ++ char *entry = NCONF_get_string(conf, section, tag); ++ if (entry == NULL) ++ BIO_printf(bio_err, "variable lookup failed for %s::%s\n", section, tag); ++ return entry; ++} ++ ++static int certify(X509 **xret, const char *infile, EVP_PKEY *pkey, X509 *x509, ++ const EVP_MD *dgst, STACK_OF(OPENSSL_STRING) *sigopts, ++ STACK_OF(CONF_VALUE) *policy, CA_DB *db, ++ BIGNUM *serial, const char *subj, unsigned long chtype, ++ int multirdn, int email_dn, const char *startdate, ++ const char *enddate, ++ long days, int batch, const char *ext_sect, CONF *lconf, ++ int verbose, unsigned long certopt, unsigned long nameopt, ++ int default_op, int ext_copy, int selfsign) ++{ ++ X509_REQ *req = NULL; ++ BIO *in = NULL; ++ EVP_PKEY *pktmp = NULL; ++ int ok = -1, i; ++ ++ in = BIO_new_file(infile, "r"); ++ if (in == NULL) { ++ ERR_print_errors(bio_err); ++ goto end; ++ } ++ if ((req = PEM_read_bio_X509_REQ(in, NULL, NULL, NULL)) == NULL) { ++ BIO_printf(bio_err, "Error reading certificate request in %s\n", ++ infile); ++ goto end; ++ } ++ if (verbose) ++ X509_REQ_print(bio_err, req); ++ ++ BIO_printf(bio_err, "Check that the request matches the signature\n"); ++ ++ if (selfsign && !X509_REQ_check_private_key(req, pkey)) { ++ BIO_printf(bio_err, ++ "Certificate request and CA private key do not match\n"); ++ ok = 0; ++ goto end; ++ } ++ if ((pktmp = X509_REQ_get0_pubkey(req)) == NULL) { ++ BIO_printf(bio_err, "error unpacking public key\n"); ++ goto end; ++ } ++ i = X509_REQ_verify(req, pktmp); ++ pktmp = NULL; ++ if (i < 0) { ++ ok = 0; ++ BIO_printf(bio_err, "Signature verification problems....\n"); ++ ERR_print_errors(bio_err); ++ goto end; ++ } ++ if (i == 0) { ++ ok = 0; ++ BIO_printf(bio_err, ++ "Signature did not match the certificate request\n"); ++ ERR_print_errors(bio_err); ++ goto end; ++ } else ++ BIO_printf(bio_err, "Signature ok\n"); ++ ++ ok = do_body(xret, pkey, x509, dgst, sigopts, policy, db, serial, subj, ++ chtype, multirdn, email_dn, startdate, enddate, days, batch, ++ verbose, req, ext_sect, lconf, certopt, nameopt, default_op, ++ ext_copy, selfsign); ++ ++ end: ++ X509_REQ_free(req); ++ BIO_free(in); ++ return (ok); ++} ++ ++static int certify_cert(X509 **xret, const char *infile, EVP_PKEY *pkey, X509 *x509, ++ const EVP_MD *dgst, STACK_OF(OPENSSL_STRING) *sigopts, ++ STACK_OF(CONF_VALUE) *policy, CA_DB *db, ++ BIGNUM *serial, const char *subj, unsigned long chtype, ++ int multirdn, int email_dn, const char *startdate, ++ const char *enddate, long days, int batch, const char *ext_sect, ++ CONF *lconf, int verbose, unsigned long certopt, ++ unsigned long nameopt, int default_op, int ext_copy) ++{ ++ X509 *req = NULL; ++ X509_REQ *rreq = NULL; ++ EVP_PKEY *pktmp = NULL; ++ int ok = -1, i; ++ ++ if ((req = load_cert(infile, FORMAT_PEM, infile)) == NULL) ++ goto end; ++ if (verbose) ++ X509_print(bio_err, req); ++ ++ BIO_printf(bio_err, "Check that the request matches the signature\n"); ++ ++ if ((pktmp = X509_get0_pubkey(req)) == NULL) { ++ BIO_printf(bio_err, "error unpacking public key\n"); ++ goto end; ++ } ++ i = X509_verify(req, pktmp); ++ if (i < 0) { ++ ok = 0; ++ BIO_printf(bio_err, "Signature verification problems....\n"); ++ goto end; ++ } ++ if (i == 0) { ++ ok = 0; ++ BIO_printf(bio_err, "Signature did not match the certificate\n"); ++ goto end; ++ } else ++ BIO_printf(bio_err, "Signature ok\n"); ++ ++ if ((rreq = X509_to_X509_REQ(req, NULL, NULL)) == NULL) ++ goto end; ++ ++ ok = do_body(xret, pkey, x509, dgst, sigopts, policy, db, serial, subj, ++ chtype, multirdn, email_dn, startdate, enddate, days, batch, ++ verbose, rreq, ext_sect, lconf, certopt, nameopt, default_op, ++ ext_copy, 0); ++ ++ end: ++ X509_REQ_free(rreq); ++ X509_free(req); ++ return (ok); ++} ++ ++static int do_body(X509 **xret, EVP_PKEY *pkey, X509 *x509, ++ const EVP_MD *dgst, STACK_OF(OPENSSL_STRING) *sigopts, ++ STACK_OF(CONF_VALUE) *policy, CA_DB *db, BIGNUM *serial, ++ const char *subj, unsigned long chtype, int multirdn, ++ int email_dn, const char *startdate, const char *enddate, long days, ++ int batch, int verbose, X509_REQ *req, const char *ext_sect, ++ CONF *lconf, unsigned long certopt, unsigned long nameopt, ++ int default_op, int ext_copy, int selfsign) ++{ ++ X509_NAME *name = NULL, *CAname = NULL, *subject = NULL, *dn_subject = ++ NULL; ++ const ASN1_TIME *tm; ++ ASN1_STRING *str, *str2; ++ ASN1_OBJECT *obj; ++ X509 *ret = NULL; ++ X509_NAME_ENTRY *ne; ++ X509_NAME_ENTRY *tne, *push; ++ EVP_PKEY *pktmp; ++ int ok = -1, i, j, last, nid; ++ const char *p; ++ CONF_VALUE *cv; ++ OPENSSL_STRING row[DB_NUMBER]; ++ OPENSSL_STRING *irow = NULL; ++ OPENSSL_STRING *rrow = NULL; ++ char buf[25]; ++ ++ for (i = 0; i < DB_NUMBER; i++) ++ row[i] = NULL; ++ ++ if (subj) { ++ X509_NAME *n = parse_name(subj, chtype, multirdn); ++ ++ if (!n) { ++ ERR_print_errors(bio_err); ++ goto end; ++ } ++ X509_REQ_set_subject_name(req, n); ++ X509_NAME_free(n); ++ } ++ ++ if (default_op) ++ BIO_printf(bio_err, ++ "The Subject's Distinguished Name is as follows\n"); ++ ++ name = X509_REQ_get_subject_name(req); ++ for (i = 0; i < X509_NAME_entry_count(name); i++) { ++ ne = X509_NAME_get_entry(name, i); ++ str = X509_NAME_ENTRY_get_data(ne); ++ obj = X509_NAME_ENTRY_get_object(ne); ++ ++ if (msie_hack) { ++ /* assume all type should be strings */ ++ nid = OBJ_obj2nid(X509_NAME_ENTRY_get_object(ne)); ++ ++ if (str->type == V_ASN1_UNIVERSALSTRING) ++ ASN1_UNIVERSALSTRING_to_string(str); ++ ++ if ((str->type == V_ASN1_IA5STRING) && ++ (nid != NID_pkcs9_emailAddress)) ++ str->type = V_ASN1_T61STRING; ++ ++ if ((nid == NID_pkcs9_emailAddress) && ++ (str->type == V_ASN1_PRINTABLESTRING)) ++ str->type = V_ASN1_IA5STRING; ++ } ++ ++ /* If no EMAIL is wanted in the subject */ ++ if ((OBJ_obj2nid(obj) == NID_pkcs9_emailAddress) && (!email_dn)) ++ continue; ++ ++ /* check some things */ ++ if ((OBJ_obj2nid(obj) == NID_pkcs9_emailAddress) && ++ (str->type != V_ASN1_IA5STRING)) { ++ BIO_printf(bio_err, ++ "\nemailAddress type needs to be of type IA5STRING\n"); ++ goto end; ++ } ++ if ((str->type != V_ASN1_BMPSTRING) ++ && (str->type != V_ASN1_UTF8STRING)) { ++ j = ASN1_PRINTABLE_type(str->data, str->length); ++ if (((j == V_ASN1_T61STRING) && ++ (str->type != V_ASN1_T61STRING)) || ++ ((j == V_ASN1_IA5STRING) && ++ (str->type == V_ASN1_PRINTABLESTRING))) { ++ BIO_printf(bio_err, ++ "\nThe string contains characters that are illegal for the ASN.1 type\n"); ++ goto end; ++ } ++ } ++ ++ if (default_op) ++ old_entry_print(obj, str); ++ } ++ ++ /* Ok, now we check the 'policy' stuff. */ ++ if ((subject = X509_NAME_new()) == NULL) { ++ BIO_printf(bio_err, "Memory allocation failure\n"); ++ goto end; ++ } ++ ++ /* take a copy of the issuer name before we mess with it. */ ++ if (selfsign) ++ CAname = X509_NAME_dup(name); ++ else ++ CAname = X509_NAME_dup(X509_get_subject_name(x509)); ++ if (CAname == NULL) ++ goto end; ++ str = str2 = NULL; ++ ++ for (i = 0; i < sk_CONF_VALUE_num(policy); i++) { ++ cv = sk_CONF_VALUE_value(policy, i); /* get the object id */ ++ if ((j = OBJ_txt2nid(cv->name)) == NID_undef) { ++ BIO_printf(bio_err, ++ "%s:unknown object type in 'policy' configuration\n", ++ cv->name); ++ goto end; ++ } ++ obj = OBJ_nid2obj(j); ++ ++ last = -1; ++ for (;;) { ++ /* lookup the object in the supplied name list */ ++ j = X509_NAME_get_index_by_OBJ(name, obj, last); ++ if (j < 0) { ++ if (last != -1) ++ break; ++ tne = NULL; ++ } else { ++ tne = X509_NAME_get_entry(name, j); ++ } ++ last = j; ++ ++ /* depending on the 'policy', decide what to do. */ ++ push = NULL; ++ if (strcmp(cv->value, "optional") == 0) { ++ if (tne != NULL) ++ push = tne; ++ } else if (strcmp(cv->value, "supplied") == 0) { ++ if (tne == NULL) { ++ BIO_printf(bio_err, ++ "The %s field needed to be supplied and was missing\n", ++ cv->name); ++ goto end; ++ } else ++ push = tne; ++ } else if (strcmp(cv->value, "match") == 0) { ++ int last2; ++ ++ if (tne == NULL) { ++ BIO_printf(bio_err, ++ "The mandatory %s field was missing\n", ++ cv->name); ++ goto end; ++ } ++ ++ last2 = -1; ++ ++ again2: ++ j = X509_NAME_get_index_by_OBJ(CAname, obj, last2); ++ if ((j < 0) && (last2 == -1)) { ++ BIO_printf(bio_err, ++ "The %s field does not exist in the CA certificate,\n" ++ "the 'policy' is misconfigured\n", ++ cv->name); ++ goto end; ++ } ++ if (j >= 0) { ++ push = X509_NAME_get_entry(CAname, j); ++ str = X509_NAME_ENTRY_get_data(tne); ++ str2 = X509_NAME_ENTRY_get_data(push); ++ last2 = j; ++ if (ASN1_STRING_cmp(str, str2) != 0) ++ goto again2; ++ } ++ if (j < 0) { ++ BIO_printf(bio_err, ++ "The %s field is different between\n" ++ "CA certificate (%s) and the request (%s)\n", ++ cv->name, ++ ((str2 == NULL) ? "NULL" : (char *)str2->data), ++ ((str == NULL) ? "NULL" : (char *)str->data)); ++ goto end; ++ } ++ } else { ++ BIO_printf(bio_err, ++ "%s:invalid type in 'policy' configuration\n", ++ cv->value); ++ goto end; ++ } ++ ++ if (push != NULL) { ++ if (!X509_NAME_add_entry(subject, push, -1, 0)) { ++ X509_NAME_ENTRY_free(push); ++ BIO_printf(bio_err, "Memory allocation failure\n"); ++ goto end; ++ } ++ } ++ if (j < 0) ++ break; ++ } ++ } ++ ++ if (preserve) { ++ X509_NAME_free(subject); ++ /* subject=X509_NAME_dup(X509_REQ_get_subject_name(req)); */ ++ subject = X509_NAME_dup(name); ++ if (subject == NULL) ++ goto end; ++ } ++ ++ if (verbose) ++ BIO_printf(bio_err, ++ "The subject name appears to be ok, checking data base for clashes\n"); ++ ++ /* Build the correct Subject if no e-mail is wanted in the subject */ ++ /* ++ * and add it later on because of the method extensions are added ++ * (altName) ++ */ ++ ++ if (email_dn) ++ dn_subject = subject; ++ else { ++ X509_NAME_ENTRY *tmpne; ++ /* ++ * Its best to dup the subject DN and then delete any email addresses ++ * because this retains its structure. ++ */ ++ if ((dn_subject = X509_NAME_dup(subject)) == NULL) { ++ BIO_printf(bio_err, "Memory allocation failure\n"); ++ goto end; ++ } ++ while ((i = X509_NAME_get_index_by_NID(dn_subject, ++ NID_pkcs9_emailAddress, ++ -1)) >= 0) { ++ tmpne = X509_NAME_get_entry(dn_subject, i); ++ X509_NAME_delete_entry(dn_subject, i); ++ X509_NAME_ENTRY_free(tmpne); ++ } ++ } ++ ++ if (BN_is_zero(serial)) ++ row[DB_serial] = OPENSSL_strdup("00"); ++ else ++ row[DB_serial] = BN_bn2hex(serial); ++ if (row[DB_serial] == NULL) { ++ BIO_printf(bio_err, "Memory allocation failure\n"); ++ goto end; ++ } ++ ++ if (db->attributes.unique_subject) { ++ OPENSSL_STRING *crow = row; ++ ++ rrow = TXT_DB_get_by_index(db->db, DB_name, crow); ++ if (rrow != NULL) { ++ BIO_printf(bio_err, ++ "ERROR:There is already a certificate for %s\n", ++ row[DB_name]); ++ } ++ } ++ if (rrow == NULL) { ++ rrow = TXT_DB_get_by_index(db->db, DB_serial, row); ++ if (rrow != NULL) { ++ BIO_printf(bio_err, ++ "ERROR:Serial number %s has already been issued,\n", ++ row[DB_serial]); ++ BIO_printf(bio_err, ++ " check the database/serial_file for corruption\n"); ++ } ++ } ++ ++ if (rrow != NULL) { ++ BIO_printf(bio_err, "The matching entry has the following details\n"); ++ if (rrow[DB_type][0] == 'E') ++ p = "Expired"; ++ else if (rrow[DB_type][0] == 'R') ++ p = "Revoked"; ++ else if (rrow[DB_type][0] == 'V') ++ p = "Valid"; ++ else ++ p = "\ninvalid type, Data base error\n"; ++ BIO_printf(bio_err, "Type :%s\n", p);; ++ if (rrow[DB_type][0] == 'R') { ++ p = rrow[DB_exp_date]; ++ if (p == NULL) ++ p = "undef"; ++ BIO_printf(bio_err, "Was revoked on:%s\n", p); ++ } ++ p = rrow[DB_exp_date]; ++ if (p == NULL) ++ p = "undef"; ++ BIO_printf(bio_err, "Expires on :%s\n", p); ++ p = rrow[DB_serial]; ++ if (p == NULL) ++ p = "undef"; ++ BIO_printf(bio_err, "Serial Number :%s\n", p); ++ p = rrow[DB_file]; ++ if (p == NULL) ++ p = "undef"; ++ BIO_printf(bio_err, "File name :%s\n", p); ++ p = rrow[DB_name]; ++ if (p == NULL) ++ p = "undef"; ++ BIO_printf(bio_err, "Subject Name :%s\n", p); ++ ok = -1; /* This is now a 'bad' error. */ ++ goto end; ++ } ++ ++ /* We are now totally happy, lets make and sign the certificate */ ++ if (verbose) ++ BIO_printf(bio_err, ++ "Everything appears to be ok, creating and signing the certificate\n"); ++ ++ if ((ret = X509_new()) == NULL) ++ goto end; ++ ++#ifdef X509_V3 ++ /* Make it an X509 v3 certificate. */ ++ if (!X509_set_version(ret, 2)) ++ goto end; ++#endif ++ ++ if (BN_to_ASN1_INTEGER(serial, X509_get_serialNumber(ret)) == NULL) ++ goto end; ++ if (selfsign) { ++ if (!X509_set_issuer_name(ret, subject)) ++ goto end; ++ } else { ++ if (!X509_set_issuer_name(ret, X509_get_subject_name(x509))) ++ goto end; ++ } ++ ++ if (!set_cert_times(ret, startdate, enddate, days)) ++ goto end; ++ ++ if (enddate != NULL) { ++ int tdays; ++ ASN1_TIME_diff(&tdays, NULL, NULL, X509_get0_notAfter(ret)); ++ days = tdays; ++ } ++ ++ if (!X509_set_subject_name(ret, subject)) ++ goto end; ++ ++ pktmp = X509_REQ_get0_pubkey(req); ++ i = X509_set_pubkey(ret, pktmp); ++ if (!i) ++ goto end; ++ ++ /* Lets add the extensions, if there are any */ ++ if (ext_sect) { ++ X509V3_CTX ctx; ++ X509_set_version(ret, 2); ++ ++ /* Initialize the context structure */ ++ if (selfsign) ++ X509V3_set_ctx(&ctx, ret, ret, req, NULL, 0); ++ else ++ X509V3_set_ctx(&ctx, x509, ret, req, NULL, 0); ++ ++ if (extconf) { ++ if (verbose) ++ BIO_printf(bio_err, "Extra configuration file found\n"); ++ ++ /* Use the extconf configuration db LHASH */ ++ X509V3_set_nconf(&ctx, extconf); ++ ++ /* Test the structure (needed?) */ ++ /* X509V3_set_ctx_test(&ctx); */ ++ ++ /* Adds exts contained in the configuration file */ ++ if (!X509V3_EXT_add_nconf(extconf, &ctx, ext_sect, ret)) { ++ BIO_printf(bio_err, ++ "ERROR: adding extensions in section %s\n", ++ ext_sect); ++ ERR_print_errors(bio_err); ++ goto end; ++ } ++ if (verbose) ++ BIO_printf(bio_err, ++ "Successfully added extensions from file.\n"); ++ } else if (ext_sect) { ++ /* We found extensions to be set from config file */ ++ X509V3_set_nconf(&ctx, lconf); ++ ++ if (!X509V3_EXT_add_nconf(lconf, &ctx, ext_sect, ret)) { ++ BIO_printf(bio_err, ++ "ERROR: adding extensions in section %s\n", ++ ext_sect); ++ ERR_print_errors(bio_err); ++ goto end; ++ } ++ ++ if (verbose) ++ BIO_printf(bio_err, ++ "Successfully added extensions from config\n"); ++ } ++ } ++ ++ /* Copy extensions from request (if any) */ ++ ++ if (!copy_extensions(ret, req, ext_copy)) { ++ BIO_printf(bio_err, "ERROR: adding extensions from request\n"); ++ ERR_print_errors(bio_err); ++ goto end; ++ } ++ ++ /* Set the right value for the noemailDN option */ ++ if (email_dn == 0) { ++ if (!X509_set_subject_name(ret, dn_subject)) ++ goto end; ++ } ++ ++ if (!default_op) { ++ BIO_printf(bio_err, "Certificate Details:\n"); ++ /* ++ * Never print signature details because signature not present ++ */ ++ certopt |= X509_FLAG_NO_SIGDUMP | X509_FLAG_NO_SIGNAME; ++ X509_print_ex(bio_err, ret, nameopt, certopt); ++ } ++ ++ BIO_printf(bio_err, "Certificate is to be certified until "); ++ ASN1_TIME_print(bio_err, X509_get0_notAfter(ret)); ++ if (days) ++ BIO_printf(bio_err, " (%ld days)", days); ++ BIO_printf(bio_err, "\n"); ++ ++ if (!batch) { ++ ++ BIO_printf(bio_err, "Sign the certificate? [y/n]:"); ++ (void)BIO_flush(bio_err); ++ buf[0] = '\0'; ++ if (!fgets(buf, sizeof(buf) - 1, stdin)) { ++ BIO_printf(bio_err, ++ "CERTIFICATE WILL NOT BE CERTIFIED: I/O error\n"); ++ ok = 0; ++ goto end; ++ } ++ if (!((buf[0] == 'y') || (buf[0] == 'Y'))) { ++ BIO_printf(bio_err, "CERTIFICATE WILL NOT BE CERTIFIED\n"); ++ ok = 0; ++ goto end; ++ } ++ } ++ ++ pktmp = X509_get0_pubkey(ret); ++ if (EVP_PKEY_missing_parameters(pktmp) && ++ !EVP_PKEY_missing_parameters(pkey)) ++ EVP_PKEY_copy_parameters(pktmp, pkey); ++ ++ if (!do_X509_sign(ret, pkey, dgst, sigopts)) ++ goto end; ++ ++ /* We now just add it to the database */ ++ row[DB_type] = OPENSSL_strdup("V"); ++ tm = X509_get0_notAfter(ret); ++ row[DB_exp_date] = app_malloc(tm->length + 1, "row expdate"); ++ memcpy(row[DB_exp_date], tm->data, tm->length); ++ row[DB_exp_date][tm->length] = '\0'; ++ row[DB_rev_date] = NULL; ++ row[DB_file] = OPENSSL_strdup("unknown"); ++ row[DB_name] = X509_NAME_oneline(X509_get_subject_name(ret), NULL, 0); ++ ++ if ((row[DB_type] == NULL) || (row[DB_exp_date] == NULL) || ++ (row[DB_file] == NULL) || (row[DB_name] == NULL)) { ++ BIO_printf(bio_err, "Memory allocation failure\n"); ++ goto end; ++ } ++ ++ irow = app_malloc(sizeof(*irow) * (DB_NUMBER + 1), "row space"); ++ for (i = 0; i < DB_NUMBER; i++) { ++ irow[i] = row[i]; ++ row[i] = NULL; ++ } ++ irow[DB_NUMBER] = NULL; ++ ++ if (!TXT_DB_insert(db->db, irow)) { ++ BIO_printf(bio_err, "failed to update database\n"); ++ BIO_printf(bio_err, "TXT_DB error number %ld\n", db->db->error); ++ goto end; ++ } ++ ok = 1; ++ end: ++ for (i = 0; i < DB_NUMBER; i++) ++ OPENSSL_free(row[i]); ++ ++ X509_NAME_free(CAname); ++ X509_NAME_free(subject); ++ if (dn_subject != subject) ++ X509_NAME_free(dn_subject); ++ if (ok <= 0) ++ X509_free(ret); ++ else ++ *xret = ret; ++ return (ok); ++} ++ ++static void write_new_certificate(BIO *bp, X509 *x, int output_der, ++ int notext) ++{ ++ ++ if (output_der) { ++ (void)i2d_X509_bio(bp, x); ++ return; ++ } ++ if (!notext) ++ X509_print(bp, x); ++ PEM_write_bio_X509(bp, x); ++} ++ ++static int certify_spkac(X509 **xret, const char *infile, EVP_PKEY *pkey, ++ X509 *x509, const EVP_MD *dgst, ++ STACK_OF(OPENSSL_STRING) *sigopts, ++ STACK_OF(CONF_VALUE) *policy, CA_DB *db, ++ BIGNUM *serial, const char *subj, unsigned long chtype, ++ int multirdn, int email_dn, const char *startdate, ++ const char *enddate, long days, const char *ext_sect, ++ CONF *lconf, int verbose, unsigned long certopt, ++ unsigned long nameopt, int default_op, int ext_copy) ++{ ++ STACK_OF(CONF_VALUE) *sk = NULL; ++ LHASH_OF(CONF_VALUE) *parms = NULL; ++ X509_REQ *req = NULL; ++ CONF_VALUE *cv = NULL; ++ NETSCAPE_SPKI *spki = NULL; ++ char *type, *buf; ++ EVP_PKEY *pktmp = NULL; ++ X509_NAME *n = NULL; ++ X509_NAME_ENTRY *ne = NULL; ++ int ok = -1, i, j; ++ long errline; ++ int nid; ++ ++ /* ++ * Load input file into a hash table. (This is just an easy ++ * way to read and parse the file, then put it into a convenient ++ * STACK format). ++ */ ++ parms = CONF_load(NULL, infile, &errline); ++ if (parms == NULL) { ++ BIO_printf(bio_err, "error on line %ld of %s\n", errline, infile); ++ ERR_print_errors(bio_err); ++ goto end; ++ } ++ ++ sk = CONF_get_section(parms, "default"); ++ if (sk_CONF_VALUE_num(sk) == 0) { ++ BIO_printf(bio_err, "no name/value pairs found in %s\n", infile); ++ goto end; ++ } ++ ++ /* ++ * Now create a dummy X509 request structure. We don't actually ++ * have an X509 request, but we have many of the components ++ * (a public key, various DN components). The idea is that we ++ * put these components into the right X509 request structure ++ * and we can use the same code as if you had a real X509 request. ++ */ ++ req = X509_REQ_new(); ++ if (req == NULL) { ++ ERR_print_errors(bio_err); ++ goto end; ++ } ++ ++ /* ++ * Build up the subject name set. ++ */ ++ n = X509_REQ_get_subject_name(req); ++ ++ for (i = 0;; i++) { ++ if (sk_CONF_VALUE_num(sk) <= i) ++ break; ++ ++ cv = sk_CONF_VALUE_value(sk, i); ++ type = cv->name; ++ /* ++ * Skip past any leading X. X: X, etc to allow for multiple instances ++ */ ++ for (buf = cv->name; *buf; buf++) ++ if ((*buf == ':') || (*buf == ',') || (*buf == '.')) { ++ buf++; ++ if (*buf) ++ type = buf; ++ break; ++ } ++ ++ buf = cv->value; ++ if ((nid = OBJ_txt2nid(type)) == NID_undef) { ++ if (strcmp(type, "SPKAC") == 0) { ++ spki = NETSCAPE_SPKI_b64_decode(cv->value, -1); ++ if (spki == NULL) { ++ BIO_printf(bio_err, ++ "unable to load Netscape SPKAC structure\n"); ++ ERR_print_errors(bio_err); ++ goto end; ++ } ++ } ++ continue; ++ } ++ ++ if (!X509_NAME_add_entry_by_NID(n, nid, chtype, ++ (unsigned char *)buf, -1, -1, 0)) ++ goto end; ++ } ++ if (spki == NULL) { ++ BIO_printf(bio_err, "Netscape SPKAC structure not found in %s\n", ++ infile); ++ goto end; ++ } ++ ++ /* ++ * Now extract the key from the SPKI structure. ++ */ ++ ++ BIO_printf(bio_err, ++ "Check that the SPKAC request matches the signature\n"); ++ ++ if ((pktmp = NETSCAPE_SPKI_get_pubkey(spki)) == NULL) { ++ BIO_printf(bio_err, "error unpacking SPKAC public key\n"); ++ goto end; ++ } ++ ++ j = NETSCAPE_SPKI_verify(spki, pktmp); ++ if (j <= 0) { ++ EVP_PKEY_free(pktmp); ++ BIO_printf(bio_err, ++ "signature verification failed on SPKAC public key\n"); ++ goto end; ++ } ++ BIO_printf(bio_err, "Signature ok\n"); ++ ++ X509_REQ_set_pubkey(req, pktmp); ++ EVP_PKEY_free(pktmp); ++ ok = do_body(xret, pkey, x509, dgst, sigopts, policy, db, serial, subj, ++ chtype, multirdn, email_dn, startdate, enddate, days, 1, ++ verbose, req, ext_sect, lconf, certopt, nameopt, default_op, ++ ext_copy, 0); ++ end: ++ X509_REQ_free(req); ++ CONF_free(parms); ++ NETSCAPE_SPKI_free(spki); ++ X509_NAME_ENTRY_free(ne); ++ ++ return (ok); ++} ++ ++static int check_time_format(const char *str) ++{ ++ return ASN1_TIME_set_string(NULL, str); ++} ++ ++static int do_revoke(X509 *x509, CA_DB *db, int type, char *value) ++{ ++ const ASN1_TIME *tm = NULL; ++ char *row[DB_NUMBER], **rrow, **irow; ++ char *rev_str = NULL; ++ BIGNUM *bn = NULL; ++ int ok = -1, i; ++ ++ for (i = 0; i < DB_NUMBER; i++) ++ row[i] = NULL; ++ row[DB_name] = X509_NAME_oneline(X509_get_subject_name(x509), NULL, 0); ++ bn = ASN1_INTEGER_to_BN(X509_get_serialNumber(x509), NULL); ++ if (!bn) ++ goto end; ++ if (BN_is_zero(bn)) ++ row[DB_serial] = OPENSSL_strdup("00"); ++ else ++ row[DB_serial] = BN_bn2hex(bn); ++ BN_free(bn); ++ if ((row[DB_name] == NULL) || (row[DB_serial] == NULL)) { ++ BIO_printf(bio_err, "Memory allocation failure\n"); ++ goto end; ++ } ++ /* ++ * We have to lookup by serial number because name lookup skips revoked ++ * certs ++ */ ++ rrow = TXT_DB_get_by_index(db->db, DB_serial, row); ++ if (rrow == NULL) { ++ BIO_printf(bio_err, ++ "Adding Entry with serial number %s to DB for %s\n", ++ row[DB_serial], row[DB_name]); ++ ++ /* We now just add it to the database */ ++ row[DB_type] = OPENSSL_strdup("V"); ++ tm = X509_get0_notAfter(x509); ++ row[DB_exp_date] = app_malloc(tm->length + 1, "row exp_data"); ++ memcpy(row[DB_exp_date], tm->data, tm->length); ++ row[DB_exp_date][tm->length] = '\0'; ++ row[DB_rev_date] = NULL; ++ row[DB_file] = OPENSSL_strdup("unknown"); ++ ++ irow = app_malloc(sizeof(*irow) * (DB_NUMBER + 1), "row ptr"); ++ for (i = 0; i < DB_NUMBER; i++) { ++ irow[i] = row[i]; ++ row[i] = NULL; ++ } ++ irow[DB_NUMBER] = NULL; ++ ++ if (!TXT_DB_insert(db->db, irow)) { ++ BIO_printf(bio_err, "failed to update database\n"); ++ BIO_printf(bio_err, "TXT_DB error number %ld\n", db->db->error); ++ goto end; ++ } ++ ++ /* Revoke Certificate */ ++ if (type == -1) ++ ok = 1; ++ else ++ ok = do_revoke(x509, db, type, value); ++ ++ goto end; ++ ++ } else if (index_name_cmp_noconst(row, rrow)) { ++ BIO_printf(bio_err, "ERROR:name does not match %s\n", row[DB_name]); ++ goto end; ++ } else if (type == -1) { ++ BIO_printf(bio_err, "ERROR:Already present, serial number %s\n", ++ row[DB_serial]); ++ goto end; ++ } else if (rrow[DB_type][0] == 'R') { ++ BIO_printf(bio_err, "ERROR:Already revoked, serial number %s\n", ++ row[DB_serial]); ++ goto end; ++ } else { ++ BIO_printf(bio_err, "Revoking Certificate %s.\n", rrow[DB_serial]); ++ rev_str = make_revocation_str(type, value); ++ if (!rev_str) { ++ BIO_printf(bio_err, "Error in revocation arguments\n"); ++ goto end; ++ } ++ rrow[DB_type][0] = 'R'; ++ rrow[DB_type][1] = '\0'; ++ rrow[DB_rev_date] = rev_str; ++ } ++ ok = 1; ++ end: ++ for (i = 0; i < DB_NUMBER; i++) { ++ OPENSSL_free(row[i]); ++ } ++ return (ok); ++} ++ ++static int get_certificate_status(const char *serial, CA_DB *db) ++{ ++ char *row[DB_NUMBER], **rrow; ++ int ok = -1, i; ++ size_t serial_len = strlen(serial); ++ ++ /* Free Resources */ ++ for (i = 0; i < DB_NUMBER; i++) ++ row[i] = NULL; ++ ++ /* Malloc needed char spaces */ ++ row[DB_serial] = app_malloc(serial_len + 2, "row serial#"); ++ ++ if (serial_len % 2) { ++ /* ++ * Set the first char to 0 ++ */ ; ++ row[DB_serial][0] = '0'; ++ ++ /* Copy String from serial to row[DB_serial] */ ++ memcpy(row[DB_serial] + 1, serial, serial_len); ++ row[DB_serial][serial_len + 1] = '\0'; ++ } else { ++ /* Copy String from serial to row[DB_serial] */ ++ memcpy(row[DB_serial], serial, serial_len); ++ row[DB_serial][serial_len] = '\0'; ++ } ++ ++ /* Make it Upper Case */ ++ for (i = 0; row[DB_serial][i] != '\0'; i++) ++ row[DB_serial][i] = toupper((unsigned char)row[DB_serial][i]); ++ ++ ok = 1; ++ ++ /* Search for the certificate */ ++ rrow = TXT_DB_get_by_index(db->db, DB_serial, row); ++ if (rrow == NULL) { ++ BIO_printf(bio_err, "Serial %s not present in db.\n", row[DB_serial]); ++ ok = -1; ++ goto end; ++ } else if (rrow[DB_type][0] == 'V') { ++ BIO_printf(bio_err, "%s=Valid (%c)\n", ++ row[DB_serial], rrow[DB_type][0]); ++ goto end; ++ } else if (rrow[DB_type][0] == 'R') { ++ BIO_printf(bio_err, "%s=Revoked (%c)\n", ++ row[DB_serial], rrow[DB_type][0]); ++ goto end; ++ } else if (rrow[DB_type][0] == 'E') { ++ BIO_printf(bio_err, "%s=Expired (%c)\n", ++ row[DB_serial], rrow[DB_type][0]); ++ goto end; ++ } else if (rrow[DB_type][0] == 'S') { ++ BIO_printf(bio_err, "%s=Suspended (%c)\n", ++ row[DB_serial], rrow[DB_type][0]); ++ goto end; ++ } else { ++ BIO_printf(bio_err, "%s=Unknown (%c).\n", ++ row[DB_serial], rrow[DB_type][0]); ++ ok = -1; ++ } ++ end: ++ for (i = 0; i < DB_NUMBER; i++) { ++ OPENSSL_free(row[i]); ++ } ++ return (ok); ++} ++ ++static int do_updatedb(CA_DB *db) ++{ ++ ASN1_UTCTIME *a_tm = NULL; ++ int i, cnt = 0; ++ int db_y2k, a_y2k; /* flags = 1 if y >= 2000 */ ++ char **rrow, *a_tm_s; ++ ++ a_tm = ASN1_UTCTIME_new(); ++ if (a_tm == NULL) ++ return -1; ++ ++ /* get actual time and make a string */ ++ a_tm = X509_gmtime_adj(a_tm, 0); ++ a_tm_s = app_malloc(a_tm->length + 1, "time string"); ++ ++ memcpy(a_tm_s, a_tm->data, a_tm->length); ++ a_tm_s[a_tm->length] = '\0'; ++ ++ if (strncmp(a_tm_s, "49", 2) <= 0) ++ a_y2k = 1; ++ else ++ a_y2k = 0; ++ ++ for (i = 0; i < sk_OPENSSL_PSTRING_num(db->db->data); i++) { ++ rrow = sk_OPENSSL_PSTRING_value(db->db->data, i); ++ ++ if (rrow[DB_type][0] == 'V') { ++ /* ignore entries that are not valid */ ++ if (strncmp(rrow[DB_exp_date], "49", 2) <= 0) ++ db_y2k = 1; ++ else ++ db_y2k = 0; ++ ++ if (db_y2k == a_y2k) { ++ /* all on the same y2k side */ ++ if (strcmp(rrow[DB_exp_date], a_tm_s) <= 0) { ++ rrow[DB_type][0] = 'E'; ++ rrow[DB_type][1] = '\0'; ++ cnt++; ++ ++ BIO_printf(bio_err, "%s=Expired\n", rrow[DB_serial]); ++ } ++ } else if (db_y2k < a_y2k) { ++ rrow[DB_type][0] = 'E'; ++ rrow[DB_type][1] = '\0'; ++ cnt++; ++ ++ BIO_printf(bio_err, "%s=Expired\n", rrow[DB_serial]); ++ } ++ ++ } ++ } ++ ++ ASN1_UTCTIME_free(a_tm); ++ OPENSSL_free(a_tm_s); ++ return (cnt); ++} ++ ++static const char *crl_reasons[] = { ++ /* CRL reason strings */ ++ "unspecified", ++ "keyCompromise", ++ "CACompromise", ++ "affiliationChanged", ++ "superseded", ++ "cessationOfOperation", ++ "certificateHold", ++ "removeFromCRL", ++ /* Additional pseudo reasons */ ++ "holdInstruction", ++ "keyTime", ++ "CAkeyTime" ++}; ++ ++#define NUM_REASONS OSSL_NELEM(crl_reasons) ++ ++/* ++ * Given revocation information convert to a DB string. The format of the ++ * string is: revtime[,reason,extra]. Where 'revtime' is the revocation time ++ * (the current time). 'reason' is the optional CRL reason and 'extra' is any ++ * additional argument ++ */ ++ ++char *make_revocation_str(int rev_type, char *rev_arg) ++{ ++ char *str; ++ const char *other = NULL; ++ const char *reason = NULL; ++ ASN1_OBJECT *otmp; ++ ASN1_UTCTIME *revtm = NULL; ++ int i; ++ switch (rev_type) { ++ case REV_NONE: ++ break; ++ ++ case REV_CRL_REASON: ++ for (i = 0; i < 8; i++) { ++ if (strcasecmp(rev_arg, crl_reasons[i]) == 0) { ++ reason = crl_reasons[i]; ++ break; ++ } ++ } ++ if (reason == NULL) { ++ BIO_printf(bio_err, "Unknown CRL reason %s\n", rev_arg); ++ return NULL; ++ } ++ break; ++ ++ case REV_HOLD: ++ /* Argument is an OID */ ++ ++ otmp = OBJ_txt2obj(rev_arg, 0); ++ ASN1_OBJECT_free(otmp); ++ ++ if (otmp == NULL) { ++ BIO_printf(bio_err, "Invalid object identifier %s\n", rev_arg); ++ return NULL; ++ } ++ ++ reason = "holdInstruction"; ++ other = rev_arg; ++ break; ++ ++ case REV_KEY_COMPROMISE: ++ case REV_CA_COMPROMISE: ++ ++ /* Argument is the key compromise time */ ++ if (!ASN1_GENERALIZEDTIME_set_string(NULL, rev_arg)) { ++ BIO_printf(bio_err, ++ "Invalid time format %s. Need YYYYMMDDHHMMSSZ\n", ++ rev_arg); ++ return NULL; ++ } ++ other = rev_arg; ++ if (rev_type == REV_KEY_COMPROMISE) ++ reason = "keyTime"; ++ else ++ reason = "CAkeyTime"; ++ ++ break; ++ ++ } ++ ++ revtm = X509_gmtime_adj(NULL, 0); ++ ++ if (!revtm) ++ return NULL; ++ ++ i = revtm->length + 1; ++ ++ if (reason) ++ i += strlen(reason) + 1; ++ if (other) ++ i += strlen(other) + 1; ++ ++ str = app_malloc(i, "revocation reason"); ++ OPENSSL_strlcpy(str, (char *)revtm->data, i); ++ if (reason) { ++ OPENSSL_strlcat(str, ",", i); ++ OPENSSL_strlcat(str, reason, i); ++ } ++ if (other) { ++ OPENSSL_strlcat(str, ",", i); ++ OPENSSL_strlcat(str, other, i); ++ } ++ ASN1_UTCTIME_free(revtm); ++ return str; ++} ++ ++/*- ++ * Convert revocation field to X509_REVOKED entry ++ * return code: ++ * 0 error ++ * 1 OK ++ * 2 OK and some extensions added (i.e. V2 CRL) ++ */ ++ ++int make_revoked(X509_REVOKED *rev, const char *str) ++{ ++ char *tmp = NULL; ++ int reason_code = -1; ++ int i, ret = 0; ++ ASN1_OBJECT *hold = NULL; ++ ASN1_GENERALIZEDTIME *comp_time = NULL; ++ ASN1_ENUMERATED *rtmp = NULL; ++ ++ ASN1_TIME *revDate = NULL; ++ ++ i = unpack_revinfo(&revDate, &reason_code, &hold, &comp_time, str); ++ ++ if (i == 0) ++ goto end; ++ ++ if (rev && !X509_REVOKED_set_revocationDate(rev, revDate)) ++ goto end; ++ ++ if (rev && (reason_code != OCSP_REVOKED_STATUS_NOSTATUS)) { ++ rtmp = ASN1_ENUMERATED_new(); ++ if (rtmp == NULL || !ASN1_ENUMERATED_set(rtmp, reason_code)) ++ goto end; ++ if (!X509_REVOKED_add1_ext_i2d(rev, NID_crl_reason, rtmp, 0, 0)) ++ goto end; ++ } ++ ++ if (rev && comp_time) { ++ if (!X509_REVOKED_add1_ext_i2d ++ (rev, NID_invalidity_date, comp_time, 0, 0)) ++ goto end; ++ } ++ if (rev && hold) { ++ if (!X509_REVOKED_add1_ext_i2d ++ (rev, NID_hold_instruction_code, hold, 0, 0)) ++ goto end; ++ } ++ ++ if (reason_code != OCSP_REVOKED_STATUS_NOSTATUS) ++ ret = 2; ++ else ++ ret = 1; ++ ++ end: ++ ++ OPENSSL_free(tmp); ++ ASN1_OBJECT_free(hold); ++ ASN1_GENERALIZEDTIME_free(comp_time); ++ ASN1_ENUMERATED_free(rtmp); ++ ASN1_TIME_free(revDate); ++ ++ return ret; ++} ++ ++static int old_entry_print(const ASN1_OBJECT *obj, const ASN1_STRING *str) ++{ ++ char buf[25], *pbuf; ++ const char *p; ++ int j; ++ ++ j = i2a_ASN1_OBJECT(bio_err, obj); ++ pbuf = buf; ++ for (j = 22 - j; j > 0; j--) ++ *(pbuf++) = ' '; ++ *(pbuf++) = ':'; ++ *(pbuf++) = '\0'; ++ BIO_puts(bio_err, buf); ++ ++ if (str->type == V_ASN1_PRINTABLESTRING) ++ BIO_printf(bio_err, "PRINTABLE:'"); ++ else if (str->type == V_ASN1_T61STRING) ++ BIO_printf(bio_err, "T61STRING:'"); ++ else if (str->type == V_ASN1_IA5STRING) ++ BIO_printf(bio_err, "IA5STRING:'"); ++ else if (str->type == V_ASN1_UNIVERSALSTRING) ++ BIO_printf(bio_err, "UNIVERSALSTRING:'"); ++ else ++ BIO_printf(bio_err, "ASN.1 %2d:'", str->type); ++ ++ p = (const char *)str->data; ++ for (j = str->length; j > 0; j--) { ++ if ((*p >= ' ') && (*p <= '~')) ++ BIO_printf(bio_err, "%c", *p); ++ else if (*p & 0x80) ++ BIO_printf(bio_err, "\\0x%02X", *p); ++ else if ((unsigned char)*p == 0xf7) ++ BIO_printf(bio_err, "^?"); ++ else ++ BIO_printf(bio_err, "^%c", *p + '@'); ++ p++; ++ } ++ BIO_printf(bio_err, "'\n"); ++ return 1; ++} ++ ++int unpack_revinfo(ASN1_TIME **prevtm, int *preason, ASN1_OBJECT **phold, ++ ASN1_GENERALIZEDTIME **pinvtm, const char *str) ++{ ++ char *tmp; ++ char *rtime_str, *reason_str = NULL, *arg_str = NULL, *p; ++ int reason_code = -1; ++ int ret = 0; ++ unsigned int i; ++ ASN1_OBJECT *hold = NULL; ++ ASN1_GENERALIZEDTIME *comp_time = NULL; ++ ++ tmp = OPENSSL_strdup(str); ++ if (!tmp) { ++ BIO_printf(bio_err, "memory allocation failure\n"); ++ goto end; ++ } ++ ++ p = strchr(tmp, ','); ++ ++ rtime_str = tmp; ++ ++ if (p) { ++ *p = '\0'; ++ p++; ++ reason_str = p; ++ p = strchr(p, ','); ++ if (p) { ++ *p = '\0'; ++ arg_str = p + 1; ++ } ++ } ++ ++ if (prevtm) { ++ *prevtm = ASN1_UTCTIME_new(); ++ if (*prevtm == NULL) { ++ BIO_printf(bio_err, "memory allocation failure\n"); ++ goto end; ++ } ++ if (!ASN1_UTCTIME_set_string(*prevtm, rtime_str)) { ++ BIO_printf(bio_err, "invalid revocation date %s\n", rtime_str); ++ goto end; ++ } ++ } ++ if (reason_str) { ++ for (i = 0; i < NUM_REASONS; i++) { ++ if (strcasecmp(reason_str, crl_reasons[i]) == 0) { ++ reason_code = i; ++ break; ++ } ++ } ++ if (reason_code == OCSP_REVOKED_STATUS_NOSTATUS) { ++ BIO_printf(bio_err, "invalid reason code %s\n", reason_str); ++ goto end; ++ } ++ ++ if (reason_code == 7) ++ reason_code = OCSP_REVOKED_STATUS_REMOVEFROMCRL; ++ else if (reason_code == 8) { /* Hold instruction */ ++ if (!arg_str) { ++ BIO_printf(bio_err, "missing hold instruction\n"); ++ goto end; ++ } ++ reason_code = OCSP_REVOKED_STATUS_CERTIFICATEHOLD; ++ hold = OBJ_txt2obj(arg_str, 0); ++ ++ if (!hold) { ++ BIO_printf(bio_err, "invalid object identifier %s\n", ++ arg_str); ++ goto end; ++ } ++ if (phold) ++ *phold = hold; ++ else ++ ASN1_OBJECT_free(hold); ++ } else if ((reason_code == 9) || (reason_code == 10)) { ++ if (!arg_str) { ++ BIO_printf(bio_err, "missing compromised time\n"); ++ goto end; ++ } ++ comp_time = ASN1_GENERALIZEDTIME_new(); ++ if (comp_time == NULL) { ++ BIO_printf(bio_err, "memory allocation failure\n"); ++ goto end; ++ } ++ if (!ASN1_GENERALIZEDTIME_set_string(comp_time, arg_str)) { ++ BIO_printf(bio_err, "invalid compromised time %s\n", arg_str); ++ goto end; ++ } ++ if (reason_code == 9) ++ reason_code = OCSP_REVOKED_STATUS_KEYCOMPROMISE; ++ else ++ reason_code = OCSP_REVOKED_STATUS_CACOMPROMISE; ++ } ++ } ++ ++ if (preason) ++ *preason = reason_code; ++ if (pinvtm) { ++ *pinvtm = comp_time; ++ comp_time = NULL; ++ } ++ ++ ret = 1; ++ ++ end: ++ ++ OPENSSL_free(tmp); ++ ASN1_GENERALIZEDTIME_free(comp_time); ++ ++ return ret; ++} +diff --git a/CryptoPkg/Library/OpensslLib/openssl/apps/cert.pem b/CryptoPkg/Library/OpensslLib/openssl/apps/cert.pem +new file mode 100644 +index 0000000..de4a77a +--- /dev/null ++++ b/CryptoPkg/Library/OpensslLib/openssl/apps/cert.pem +@@ -0,0 +1,11 @@ ++-----BEGIN CERTIFICATE----- ++MIIBoDCCAUoCAQAwDQYJKoZIhvcNAQEEBQAwYzELMAkGA1UEBhMCQVUxEzARBgNV ++BAgTClF1ZWVuc2xhbmQxGjAYBgNVBAoTEUNyeXB0U29mdCBQdHkgTHRkMSMwIQYD ++VQQDExpTZXJ2ZXIgdGVzdCBjZXJ0ICg1MTIgYml0KTAeFw05NzA5MDkwMzQxMjZa ++Fw05NzEwMDkwMzQxMjZaMF4xCzAJBgNVBAYTAkFVMRMwEQYDVQQIEwpTb21lLVN0 ++YXRlMSEwHwYDVQQKExhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQxFzAVBgNVBAMT ++DkVyaWMgdGhlIFlvdW5nMFEwCQYFKw4DAgwFAANEAAJBALVEqPODnpI4rShlY8S7 ++tB713JNvabvn6Gned7zylwLLiXQAo/PAT6mfdWPTyCX9RlId/Aroh1ou893BA32Q ++sggwDQYJKoZIhvcNAQEEBQADQQCU5SSgapJSdRXJoX+CpCvFy+JVh9HpSjCpSNKO ++19raHv98hKAUJuP9HyM+SUsffO6mAIgitUaqW8/wDMePhEC3 ++-----END CERTIFICATE----- +diff --git a/CryptoPkg/Library/OpensslLib/openssl/apps/ciphers.c b/CryptoPkg/Library/OpensslLib/openssl/apps/ciphers.c +new file mode 100644 +index 0000000..c0f43ea +--- /dev/null ++++ b/CryptoPkg/Library/OpensslLib/openssl/apps/ciphers.c +@@ -0,0 +1,242 @@ ++/* ++ * Copyright 1995-2016 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 ++ * in the file LICENSE in the source distribution or at ++ * https://www.openssl.org/source/license.html ++ */ ++ ++#include ++#include ++#include ++#include "apps.h" ++#include ++#include ++ ++typedef enum OPTION_choice { ++ OPT_ERR = -1, OPT_EOF = 0, OPT_HELP, ++ OPT_STDNAME, ++ OPT_SSL3, ++ OPT_TLS1, ++ OPT_TLS1_1, ++ OPT_TLS1_2, ++ OPT_PSK, ++ OPT_SRP, ++ OPT_V, OPT_UPPER_V, OPT_S ++} OPTION_CHOICE; ++ ++OPTIONS ciphers_options[] = { ++ {"help", OPT_HELP, '-', "Display this summary"}, ++ {"v", OPT_V, '-', "Verbose listing of the SSL/TLS ciphers"}, ++ {"V", OPT_UPPER_V, '-', "Even more verbose"}, ++ {"s", OPT_S, '-', "Only supported ciphers"}, ++#ifndef OPENSSL_NO_SSL3 ++ {"ssl3", OPT_SSL3, '-', "SSL3 mode"}, ++#endif ++#ifndef OPENSSL_NO_TLS1 ++ {"tls1", OPT_TLS1, '-', "TLS1 mode"}, ++#endif ++#ifndef OPENSSL_NO_TLS1_1 ++ {"tls1_1", OPT_TLS1_1, '-', "TLS1.1 mode"}, ++#endif ++#ifndef OPENSSL_NO_TLS1_2 ++ {"tls1_2", OPT_TLS1_2, '-', "TLS1.2 mode"}, ++#endif ++#ifndef OPENSSL_NO_SSL_TRACE ++ {"stdname", OPT_STDNAME, '-', "Show standard cipher names"}, ++#endif ++#ifndef OPENSSL_NO_PSK ++ {"psk", OPT_PSK, '-', "include ciphersuites requiring PSK"}, ++#endif ++#ifndef OPENSSL_NO_SRP ++ {"srp", OPT_SRP, '-', "include ciphersuites requiring SRP"}, ++#endif ++ {NULL} ++}; ++ ++#ifndef OPENSSL_NO_PSK ++static unsigned int dummy_psk(SSL *ssl, const char *hint, char *identity, ++ unsigned int max_identity_len, ++ unsigned char *psk, ++ unsigned int max_psk_len) ++{ ++ return 0; ++} ++#endif ++#ifndef OPENSSL_NO_SRP ++static char *dummy_srp(SSL *ssl, void *arg) ++{ ++ return ""; ++} ++#endif ++ ++int ciphers_main(int argc, char **argv) ++{ ++ SSL_CTX *ctx = NULL; ++ SSL *ssl = NULL; ++ STACK_OF(SSL_CIPHER) *sk = NULL; ++ const SSL_METHOD *meth = TLS_server_method(); ++ int ret = 1, i, verbose = 0, Verbose = 0, use_supported = 0; ++#ifndef OPENSSL_NO_SSL_TRACE ++ int stdname = 0; ++#endif ++#ifndef OPENSSL_NO_PSK ++ int psk = 0; ++#endif ++#ifndef OPENSSL_NO_SRP ++ int srp = 0; ++#endif ++ const char *p; ++ char *ciphers = NULL, *prog; ++ char buf[512]; ++ OPTION_CHOICE o; ++ int min_version = 0, max_version = 0; ++ ++ prog = opt_init(argc, argv, ciphers_options); ++ while ((o = opt_next()) != OPT_EOF) { ++ switch (o) { ++ case OPT_EOF: ++ case OPT_ERR: ++ opthelp: ++ BIO_printf(bio_err, "%s: Use -help for summary.\n", prog); ++ goto end; ++ case OPT_HELP: ++ opt_help(ciphers_options); ++ ret = 0; ++ goto end; ++ case OPT_V: ++ verbose = 1; ++ break; ++ case OPT_UPPER_V: ++ verbose = Verbose = 1; ++ break; ++ case OPT_S: ++ use_supported = 1; ++ break; ++ case OPT_STDNAME: ++#ifndef OPENSSL_NO_SSL_TRACE ++ stdname = verbose = 1; ++#endif ++ break; ++ case OPT_SSL3: ++ min_version = SSL3_VERSION; ++ max_version = SSL3_VERSION; ++ break; ++ case OPT_TLS1: ++ min_version = TLS1_VERSION; ++ max_version = TLS1_VERSION; ++ break; ++ case OPT_TLS1_1: ++ min_version = TLS1_1_VERSION; ++ max_version = TLS1_1_VERSION; ++ break; ++ case OPT_TLS1_2: ++ min_version = TLS1_2_VERSION; ++ max_version = TLS1_2_VERSION; ++ break; ++ case OPT_PSK: ++#ifndef OPENSSL_NO_PSK ++ psk = 1; ++#endif ++ break; ++ case OPT_SRP: ++#ifndef OPENSSL_NO_SRP ++ srp = 1; ++#endif ++ break; ++ } ++ } ++ argv = opt_rest(); ++ argc = opt_num_rest(); ++ ++ if (argc == 1) ++ ciphers = *argv; ++ else if (argc != 0) ++ goto opthelp; ++ ++ ctx = SSL_CTX_new(meth); ++ if (ctx == NULL) ++ goto err; ++ if (SSL_CTX_set_min_proto_version(ctx, min_version) == 0) ++ goto err; ++ if (SSL_CTX_set_max_proto_version(ctx, max_version) == 0) ++ goto err; ++ ++#ifndef OPENSSL_NO_PSK ++ if (psk) ++ SSL_CTX_set_psk_client_callback(ctx, dummy_psk); ++#endif ++#ifndef OPENSSL_NO_SRP ++ if (srp) ++ SSL_CTX_set_srp_client_pwd_callback(ctx, dummy_srp); ++#endif ++ if (ciphers != NULL) { ++ if (!SSL_CTX_set_cipher_list(ctx, ciphers)) { ++ BIO_printf(bio_err, "Error in cipher list\n"); ++ goto err; ++ } ++ } ++ ssl = SSL_new(ctx); ++ if (ssl == NULL) ++ goto err; ++ ++ if (use_supported) ++ sk = SSL_get1_supported_ciphers(ssl); ++ else ++ sk = SSL_get_ciphers(ssl); ++ ++ if (!verbose) { ++ for (i = 0; i < sk_SSL_CIPHER_num(sk); i++) { ++ const SSL_CIPHER *c = sk_SSL_CIPHER_value(sk, i); ++ p = SSL_CIPHER_get_name(c); ++ if (p == NULL) ++ break; ++ if (i != 0) ++ BIO_printf(bio_out, ":"); ++ BIO_printf(bio_out, "%s", p); ++ } ++ BIO_printf(bio_out, "\n"); ++ } else { ++ ++ for (i = 0; i < sk_SSL_CIPHER_num(sk); i++) { ++ const SSL_CIPHER *c; ++ ++ c = sk_SSL_CIPHER_value(sk, i); ++ ++ if (Verbose) { ++ unsigned long id = SSL_CIPHER_get_id(c); ++ int id0 = (int)(id >> 24); ++ int id1 = (int)((id >> 16) & 0xffL); ++ int id2 = (int)((id >> 8) & 0xffL); ++ int id3 = (int)(id & 0xffL); ++ ++ if ((id & 0xff000000L) == 0x03000000L) ++ BIO_printf(bio_out, " 0x%02X,0x%02X - ", id2, id3); /* SSL3 ++ * cipher */ ++ else ++ BIO_printf(bio_out, "0x%02X,0x%02X,0x%02X,0x%02X - ", id0, id1, id2, id3); /* whatever */ ++ } ++#ifndef OPENSSL_NO_SSL_TRACE ++ if (stdname) { ++ const char *nm = SSL_CIPHER_standard_name(c); ++ if (nm == NULL) ++ nm = "UNKNOWN"; ++ BIO_printf(bio_out, "%s - ", nm); ++ } ++#endif ++ BIO_puts(bio_out, SSL_CIPHER_description(c, buf, sizeof buf)); ++ } ++ } ++ ++ ret = 0; ++ goto end; ++ err: ++ ERR_print_errors(bio_err); ++ end: ++ if (use_supported) ++ sk_SSL_CIPHER_free(sk); ++ SSL_CTX_free(ctx); ++ SSL_free(ssl); ++ return (ret); ++} +diff --git a/CryptoPkg/Library/OpensslLib/openssl/apps/client.pem b/CryptoPkg/Library/OpensslLib/openssl/apps/client.pem +new file mode 100644 +index 0000000..e7a47a7 +--- /dev/null ++++ b/CryptoPkg/Library/OpensslLib/openssl/apps/client.pem +@@ -0,0 +1,52 @@ ++subject= C = UK, O = OpenSSL Group, OU = FOR TESTING PURPOSES ONLY, CN = Test Client Cert ++issuer= C = UK, O = OpenSSL Group, OU = FOR TESTING PURPOSES ONLY, CN = OpenSSL Test Intermediate CA ++-----BEGIN CERTIFICATE----- ++MIID5zCCAs+gAwIBAgIJALnu1NlVpZ6yMA0GCSqGSIb3DQEBBQUAMHAxCzAJBgNV ++BAYTAlVLMRYwFAYDVQQKDA1PcGVuU1NMIEdyb3VwMSIwIAYDVQQLDBlGT1IgVEVT ++VElORyBQVVJQT1NFUyBPTkxZMSUwIwYDVQQDDBxPcGVuU1NMIFRlc3QgSW50ZXJt ++ZWRpYXRlIENBMB4XDTExMTIwODE0MDE0OFoXDTIxMTAxNjE0MDE0OFowZDELMAkG ++A1UEBhMCVUsxFjAUBgNVBAoMDU9wZW5TU0wgR3JvdXAxIjAgBgNVBAsMGUZPUiBU ++RVNUSU5HIFBVUlBPU0VTIE9OTFkxGTAXBgNVBAMMEFRlc3QgQ2xpZW50IENlcnQw ++ggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC0ranbHRLcLVqN+0BzcZpY +++yOLqxzDWT1LD9eW1stC4NzXX9/DCtSIVyN7YIHdGLrIPr64IDdXXaMRzgZ2rOKs ++lmHCAiFpO/ja99gGCJRxH0xwQatqAULfJVHeUhs7OEGOZc2nWifjqKvGfNTilP7D ++nwi69ipQFq9oS19FmhwVHk2wg7KZGHI1qDyG04UrfCZMRitvS9+UVhPpIPjuiBi2 ++x3/FZIpL5gXJvvFK6xHY63oq2asyzBATntBgnP4qJFWWcvRx24wF1PnZabxuVoL2 ++bPnQ/KvONDrw3IdqkKhYNTul7jEcu3OlcZIMw+7DiaKJLAzKb/bBF5gm/pwW6As9 ++AgMBAAGjgY8wgYwwDAYDVR0TAQH/BAIwADAOBgNVHQ8BAf8EBAMCBeAwLAYJYIZI ++AYb4QgENBB8WHU9wZW5TU0wgR2VuZXJhdGVkIENlcnRpZmljYXRlMB0GA1UdDgQW ++BBSZHKyLoTh7Mb409Zn/mK1ceSDAjDAfBgNVHSMEGDAWgBQ2w2yI55X+sL3szj49 ++hqshgYfa2jANBgkqhkiG9w0BAQUFAAOCAQEAD0mL7PtPYgCEuDyOQSbLpeND5hVS ++curxQdGnrJ6Acrhodb7E9ccATokeb0PLx6HBLQUicxhTZIQ9FbO43YkQcOU6C3BB ++IlwskqmtN6+VmrQzNolHCDzvxNZs9lYL2VbGPGqVRyjZeHpoAlf9cQr8PgDb4d4b ++vUx2KAhHQvV2nkmYvKyXcgnRuHggumF87mkxidriGAEFwH4qfOqetUg64WyxP7P2 ++QLipm04SyQa7ONtIApfVXgHcE42Py4/f4arzCzMjKe3VyhGkS7nsT55X/fWgTaRm ++CQPkO+H94P958WTvQDt77bQ+D3IvYaVvfil8n6HJMOJfFT0LJuSUbpSXJg== ++-----END CERTIFICATE----- ++-----BEGIN RSA PRIVATE KEY----- ++MIIEpQIBAAKCAQEAtK2p2x0S3C1ajftAc3GaWPsji6scw1k9Sw/XltbLQuDc11/f ++wwrUiFcje2CB3Ri6yD6+uCA3V12jEc4GdqzirJZhwgIhaTv42vfYBgiUcR9McEGr ++agFC3yVR3lIbOzhBjmXNp1on46irxnzU4pT+w58IuvYqUBavaEtfRZocFR5NsIOy ++mRhyNag8htOFK3wmTEYrb0vflFYT6SD47ogYtsd/xWSKS+YFyb7xSusR2Ot6Ktmr ++MswQE57QYJz+KiRVlnL0cduMBdT52Wm8blaC9mz50PyrzjQ68NyHapCoWDU7pe4x ++HLtzpXGSDMPuw4miiSwMym/2wReYJv6cFugLPQIDAQABAoIBAAZOyc9MhIwLSU4L ++p4RgQvM4UVVe8/Id+3XTZ8NsXExJbWxXfIhiqGjaIfL8u4vsgRjcl+v1s/jo2/iT ++KMab4o4D8gXD7UavQVDjtjb/ta79WL3SjRl2Uc9YjjMkyq6WmDNQeo2NKDdafCTB ++1uzSJtLNipB8Z53ELPuHJhxX9QMHrMnuha49riQgXZ7buP9iQrHJFhImBjSzbxJx ++L+TI6rkyLSf9Wi0Pd3L27Ob3QWNfNRYNSeTE+08eSRChkur5W0RuXAcuAICdQlCl ++LBvWO/LmmvbzCqiDcgy/TliSb6CGGwgiNG7LJZmlkYNj8laGwalNlYZs3UrVv6NO ++Br2loAECgYEA2kvCvPGj0Dg/6g7WhXDvAkEbcaL1tSeCxBbNH+6HS2UWMWvyTtCn ++/bbD519QIdkvayy1QjEf32GV/UjUVmlULMLBcDy0DGjtL3+XpIhLKWDNxN1v1/ai ++1oz23ZJCOgnk6K4qtFtlRS1XtynjA+rBetvYvLP9SKeFrnpzCgaA2r0CgYEA0+KX ++1ACXDTNH5ySX3kMjSS9xdINf+OOw4CvPHFwbtc9aqk2HePlEsBTz5I/W3rKwXva3 ++NqZ/bRqVVeZB/hHKFywgdUQk2Uc5z/S7Lw70/w1HubNTXGU06Ngb6zOFAo/o/TwZ ++zTP1BMIKSOB6PAZPS3l+aLO4FRIRotfFhgRHOoECgYEAmiZbqt8cJaJDB/5YYDzC ++mp3tSk6gIb936Q6M5VqkMYp9pIKsxhk0N8aDCnTU+kIK6SzWBpr3/d9Ecmqmfyq7 ++5SvWO3KyVf0WWK9KH0abhOm2BKm2HBQvI0DB5u8sUx2/hsvOnjPYDISbZ11t0MtK ++u35Zy89yMYcSsIYJjG/ROCUCgYEAgI2P9G5PNxEP5OtMwOsW84Y3Xat/hPAQFlI+ ++HES+AzbFGWJkeT8zL2nm95tVkFP1sggZ7Kxjz3w7cpx7GX0NkbWSE9O+T51pNASV ++tN1sQ3p5M+/a+cnlqgfEGJVvc7iAcXQPa3LEi5h2yPR49QYXAgG6cifn3dDSpmwn ++SUI7PQECgYEApGCIIpSRPLAEHTGmP87RBL1smurhwmy2s/pghkvUkWehtxg0sGHh ++kuaqDWcskogv+QC0sVdytiLSz8G0DwcEcsHK1Fkyb8A+ayiw6jWJDo2m9+IF4Fww ++1Te6jFPYDESnbhq7+TLGgHGhtwcu5cnb4vSuYXGXKupZGzoLOBbv1Zw= ++-----END RSA PRIVATE KEY----- +diff --git a/CryptoPkg/Library/OpensslLib/openssl/apps/cms.c b/CryptoPkg/Library/OpensslLib/openssl/apps/cms.c +new file mode 100644 +index 0000000..579b227 +--- /dev/null ++++ b/CryptoPkg/Library/OpensslLib/openssl/apps/cms.c +@@ -0,0 +1,1294 @@ ++/* ++ * Copyright 2008-2016 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 ++ * in the file LICENSE in the source distribution or at ++ * https://www.openssl.org/source/license.html ++ */ ++ ++/* CMS utility function */ ++ ++#include ++#include ++#include "apps.h" ++ ++#ifndef OPENSSL_NO_CMS ++ ++# include ++# include ++# include ++# include ++# include ++# include ++ ++static int save_certs(char *signerfile, STACK_OF(X509) *signers); ++static int cms_cb(int ok, X509_STORE_CTX *ctx); ++static void receipt_request_print(CMS_ContentInfo *cms); ++static CMS_ReceiptRequest *make_receipt_request(STACK_OF(OPENSSL_STRING) ++ *rr_to, int rr_allorfirst, STACK_OF(OPENSSL_STRING) ++ *rr_from); ++static int cms_set_pkey_param(EVP_PKEY_CTX *pctx, ++ STACK_OF(OPENSSL_STRING) *param); ++ ++# define SMIME_OP 0x10 ++# define SMIME_IP 0x20 ++# define SMIME_SIGNERS 0x40 ++# define SMIME_ENCRYPT (1 | SMIME_OP) ++# define SMIME_DECRYPT (2 | SMIME_IP) ++# define SMIME_SIGN (3 | SMIME_OP | SMIME_SIGNERS) ++# define SMIME_VERIFY (4 | SMIME_IP) ++# define SMIME_CMSOUT (5 | SMIME_IP | SMIME_OP) ++# define SMIME_RESIGN (6 | SMIME_IP | SMIME_OP | SMIME_SIGNERS) ++# define SMIME_DATAOUT (7 | SMIME_IP) ++# define SMIME_DATA_CREATE (8 | SMIME_OP) ++# define SMIME_DIGEST_VERIFY (9 | SMIME_IP) ++# define SMIME_DIGEST_CREATE (10 | SMIME_OP) ++# define SMIME_UNCOMPRESS (11 | SMIME_IP) ++# define SMIME_COMPRESS (12 | SMIME_OP) ++# define SMIME_ENCRYPTED_DECRYPT (13 | SMIME_IP) ++# define SMIME_ENCRYPTED_ENCRYPT (14 | SMIME_OP) ++# define SMIME_SIGN_RECEIPT (15 | SMIME_IP | SMIME_OP) ++# define SMIME_VERIFY_RECEIPT (16 | SMIME_IP) ++ ++static int verify_err = 0; ++ ++typedef struct cms_key_param_st cms_key_param; ++ ++struct cms_key_param_st { ++ int idx; ++ STACK_OF(OPENSSL_STRING) *param; ++ cms_key_param *next; ++}; ++ ++typedef enum OPTION_choice { ++ OPT_ERR = -1, OPT_EOF = 0, OPT_HELP, ++ OPT_INFORM, OPT_OUTFORM, OPT_IN, OPT_OUT, OPT_ENCRYPT, ++ OPT_DECRYPT, OPT_SIGN, OPT_SIGN_RECEIPT, OPT_RESIGN, ++ OPT_VERIFY, OPT_VERIFY_RETCODE, OPT_VERIFY_RECEIPT, ++ OPT_CMSOUT, OPT_DATA_OUT, OPT_DATA_CREATE, OPT_DIGEST_VERIFY, ++ OPT_DIGEST_CREATE, OPT_COMPRESS, OPT_UNCOMPRESS, ++ OPT_ED_DECRYPT, OPT_ED_ENCRYPT, OPT_DEBUG_DECRYPT, OPT_TEXT, ++ OPT_ASCIICRLF, OPT_NOINTERN, OPT_NOVERIFY, OPT_NOCERTS, ++ OPT_NOATTR, OPT_NODETACH, OPT_NOSMIMECAP, OPT_BINARY, OPT_KEYID, ++ 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_SECRETKEY, OPT_SECRETKEYID, OPT_PWRI_PASSWORD, OPT_ECONTENT_TYPE, ++ OPT_RAND, 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_V_ENUM, ++ OPT_CIPHER ++} OPTION_CHOICE; ++ ++OPTIONS cms_options[] = { ++ {OPT_HELP_STR, 1, '-', "Usage: %s [options] cert.pem...\n"}, ++ {OPT_HELP_STR, 1, '-', ++ " cert.pem... recipient certs for encryption\n"}, ++ {OPT_HELP_STR, 1, '-', "Valid options are:\n"}, ++ {"help", OPT_HELP, '-', "Display this summary"}, ++ {"inform", OPT_INFORM, 'c', "Input format SMIME (default), PEM or DER"}, ++ {"outform", OPT_OUTFORM, 'c', ++ "Output format SMIME (default), PEM or DER"}, ++ {"in", OPT_IN, '<', "Input file"}, ++ {"out", OPT_OUT, '>', "Output file"}, ++ {"encrypt", OPT_ENCRYPT, '-', "Encrypt message"}, ++ {"decrypt", OPT_DECRYPT, '-', "Decrypt encrypted message"}, ++ {"sign", OPT_SIGN, '-', "Sign message"}, ++ {"sign_receipt", OPT_SIGN_RECEIPT, '-', "Generate a signed receipt for the message"}, ++ {"resign", OPT_RESIGN, '-', "Resign a signed message"}, ++ {"verify", OPT_VERIFY, '-', "Verify signed message"}, ++ {"verify_retcode", OPT_VERIFY_RETCODE, '-'}, ++ {"verify_receipt", OPT_VERIFY_RECEIPT, '<'}, ++ {"cmsout", OPT_CMSOUT, '-', "Output CMS structure"}, ++ {"data_out", OPT_DATA_OUT, '-'}, ++ {"data_create", OPT_DATA_CREATE, '-'}, ++ {"digest_verify", OPT_DIGEST_VERIFY, '-'}, ++ {"digest_create", OPT_DIGEST_CREATE, '-'}, ++ {"compress", OPT_COMPRESS, '-'}, ++ {"uncompress", OPT_UNCOMPRESS, '-'}, ++ {"EncryptedData_decrypt", OPT_ED_DECRYPT, '-'}, ++ {"EncryptedData_encrypt", OPT_ED_ENCRYPT, '-'}, ++ {"debug_decrypt", OPT_DEBUG_DECRYPT, '-'}, ++ {"text", OPT_TEXT, '-', "Include or delete text MIME headers"}, ++ {"asciicrlf", OPT_ASCIICRLF, '-'}, ++ {"nointern", OPT_NOINTERN, '-', ++ "Don't search certificates in message for signer"}, ++ {"noverify", OPT_NOVERIFY, '-', "Don't verify signers certificate"}, ++ {"nocerts", OPT_NOCERTS, '-', ++ "Don't include signers certificate when signing"}, ++ {"noattr", OPT_NOATTR, '-', "Don't include any signed attributes"}, ++ {"nodetach", OPT_NODETACH, '-', "Use opaque signing"}, ++ {"nosmimecap", OPT_NOSMIMECAP, '-', "Omit the SMIMECapabilities attribute"}, ++ {"binary", OPT_BINARY, '-', "Don't translate message to text"}, ++ {"keyid", OPT_KEYID, '-', "Use subject key identifier"}, ++ {"nosigs", OPT_NOSIGS, '-', "Don't verify message signature"}, ++ {"no_content_verify", OPT_NO_CONTENT_VERIFY, '-'}, ++ {"no_attr_verify", OPT_NO_ATTR_VERIFY, '-'}, ++ {"stream", OPT_INDEF, '-', "Enable CMS streaming"}, ++ {"indef", OPT_INDEF, '-', "Same as -stream"}, ++ {"noindef", OPT_NOINDEF, '-', "Disable CMS streaming"}, ++ {"crlfeol", OPT_CRLFEOL, '-', "Use CRLF as EOL termination instead of CR only" }, ++ {"noout", OPT_NOOUT, '-', "For the -cmsout operation do not output the parsed CMS structure"}, ++ {"receipt_request_print", OPT_RR_PRINT, '-', "Print CMS Receipt Request" }, ++ {"receipt_request_all", OPT_RR_ALL, '-'}, ++ {"receipt_request_first", OPT_RR_FIRST, '-'}, ++ {"rctform", OPT_RCTFORM, 'F', "Receipt file format"}, ++ {"certfile", OPT_CERTFILE, '<', "Other certificates file"}, ++ {"CAfile", OPT_CAFILE, '<', "Trusted certificates file"}, ++ {"CApath", OPT_CAPATH, '/', "trusted certificates directory"}, ++ {"no-CAfile", OPT_NOCAFILE, '-', ++ "Do not load the default certificates file"}, ++ {"no-CApath", OPT_NOCAPATH, '-', ++ "Do not load certificates from the default certificates directory"}, ++ {"content", OPT_CONTENT, '<', ++ "Supply or override content for detached signature"}, ++ {"print", OPT_PRINT, '-', ++ "For the -cmsout operation print out all fields of the CMS structure"}, ++ {"secretkey", OPT_SECRETKEY, 's'}, ++ {"secretkeyid", OPT_SECRETKEYID, 's'}, ++ {"pwri_password", OPT_PWRI_PASSWORD, 's'}, ++ {"econtent_type", OPT_ECONTENT_TYPE, 's'}, ++ {"rand", OPT_RAND, 's', ++ "Load the file(s) into the random number generator"}, ++ {"passin", OPT_PASSIN, 's', "Input file pass phrase source"}, ++ {"to", OPT_TO, 's', "To address"}, ++ {"from", OPT_FROM, 's', "From address"}, ++ {"subject", OPT_SUBJECT, 's', "Subject"}, ++ {"signer", OPT_SIGNER, 's', "Signer 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"}, ++ {"inkey", OPT_INKEY, 's', ++ "Input private key (if not signer or recipient)"}, ++ {"keyform", OPT_KEYFORM, 'f', "Input private key format (PEM or ENGINE)"}, ++ {"keyopt", OPT_KEYOPT, 's', "Set public key parameters as n:v pairs"}, ++ {"receipt_request_from", OPT_RR_FROM, 's'}, ++ {"receipt_request_to", OPT_RR_TO, 's'}, ++ {"", OPT_CIPHER, '-', "Any supported cipher"}, ++ OPT_V_OPTIONS, ++ {"aes128-wrap", OPT_AES128_WRAP, '-', "Use AES128 to wrap key"}, ++ {"aes192-wrap", OPT_AES192_WRAP, '-', "Use AES192 to wrap key"}, ++ {"aes256-wrap", OPT_AES256_WRAP, '-', "Use AES256 to wrap key"}, ++# ifndef OPENSSL_NO_DES ++ {"des3-wrap", OPT_3DES_WRAP, '-', "Use 3DES-EDE to wrap key"}, ++# endif ++# ifndef OPENSSL_NO_ENGINE ++ {"engine", OPT_ENGINE, 's', "Use engine e, possibly a hardware device"}, ++# endif ++ {NULL} ++}; ++ ++int cms_main(int argc, char **argv) ++{ ++ ASN1_OBJECT *econtent_type = NULL; ++ BIO *in = NULL, *out = NULL, *indata = NULL, *rctin = NULL; ++ CMS_ContentInfo *cms = NULL, *rcms = NULL; ++ CMS_ReceiptRequest *rr = NULL; ++ ENGINE *e = NULL; ++ EVP_PKEY *key = NULL; ++ const EVP_CIPHER *cipher = NULL, *wrap_cipher = NULL; ++ const EVP_MD *sign_md = NULL; ++ 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_STORE *store = NULL; ++ X509_VERIFY_PARAM *vpm = NULL; ++ char *certfile = NULL, *keyfile = NULL, *contfile = NULL; ++ const char *CAfile = NULL, *CApath = NULL; ++ char *certsoutfile = NULL; ++ int noCAfile = 0, noCApath = 0; ++ char *infile = NULL, *outfile = NULL, *rctfile = NULL, *inrand = NULL; ++ char *passinarg = NULL, *passin = NULL, *signerfile = 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; ++ int informat = FORMAT_SMIME, outformat = FORMAT_SMIME; ++ int need_rand = 0, operation = 0, ret = 1, rr_print = 0, rr_allorfirst = ++ -1; ++ int verify_retcode = 0, rctformat = FORMAT_SMIME, keyform = FORMAT_PEM; ++ size_t secret_keylen = 0, secret_keyidlen = 0; ++ unsigned char *pwri_pass = NULL, *pwri_tmp = NULL; ++ unsigned char *secret_key = NULL, *secret_keyid = NULL; ++ long ltmp; ++ const char *mime_eol = "\n"; ++ OPTION_CHOICE o; ++ ++ if ((vpm = X509_VERIFY_PARAM_new()) == NULL) ++ return 1; ++ ++ prog = opt_init(argc, argv, cms_options); ++ while ((o = opt_next()) != OPT_EOF) { ++ switch (o) { ++ case OPT_EOF: ++ case OPT_ERR: ++ opthelp: ++ BIO_printf(bio_err, "%s: Use -help for summary.\n", prog); ++ goto end; ++ case OPT_HELP: ++ opt_help(cms_options); ++ ret = 0; ++ goto end; ++ case OPT_INFORM: ++ if (!opt_format(opt_arg(), OPT_FMT_PDS, &informat)) ++ goto opthelp; ++ break; ++ case OPT_OUTFORM: ++ if (!opt_format(opt_arg(), OPT_FMT_PDS, &outformat)) ++ goto opthelp; ++ break; ++ case OPT_OUT: ++ outfile = opt_arg(); ++ break; ++ case OPT_ENCRYPT: ++ operation = SMIME_ENCRYPT; ++ break; ++ case OPT_DECRYPT: ++ operation = SMIME_DECRYPT; ++ break; ++ case OPT_SIGN: ++ operation = SMIME_SIGN; ++ break; ++ case OPT_SIGN_RECEIPT: ++ operation = SMIME_SIGN_RECEIPT; ++ break; ++ case OPT_RESIGN: ++ operation = SMIME_RESIGN; ++ break; ++ case OPT_VERIFY: ++ operation = SMIME_VERIFY; ++ break; ++ case OPT_VERIFY_RETCODE: ++ verify_retcode = 1; ++ break; ++ case OPT_VERIFY_RECEIPT: ++ operation = SMIME_VERIFY_RECEIPT; ++ rctfile = opt_arg(); ++ break; ++ case OPT_CMSOUT: ++ operation = SMIME_CMSOUT; ++ break; ++ case OPT_DATA_OUT: ++ operation = SMIME_DATAOUT; ++ break; ++ case OPT_DATA_CREATE: ++ operation = SMIME_DATA_CREATE; ++ break; ++ case OPT_DIGEST_VERIFY: ++ operation = SMIME_DIGEST_VERIFY; ++ break; ++ case OPT_DIGEST_CREATE: ++ operation = SMIME_DIGEST_CREATE; ++ break; ++ case OPT_COMPRESS: ++ operation = SMIME_COMPRESS; ++ break; ++ case OPT_UNCOMPRESS: ++ operation = SMIME_UNCOMPRESS; ++ break; ++ case OPT_ED_DECRYPT: ++ operation = SMIME_ENCRYPTED_DECRYPT; ++ break; ++ case OPT_ED_ENCRYPT: ++ operation = SMIME_ENCRYPTED_ENCRYPT; ++ break; ++ case OPT_DEBUG_DECRYPT: ++ flags |= CMS_DEBUG_DECRYPT; ++ break; ++ case OPT_TEXT: ++ flags |= CMS_TEXT; ++ break; ++ case OPT_ASCIICRLF: ++ flags |= CMS_ASCIICRLF; ++ break; ++ case OPT_NOINTERN: ++ flags |= CMS_NOINTERN; ++ break; ++ case OPT_NOVERIFY: ++ flags |= CMS_NO_SIGNER_CERT_VERIFY; ++ break; ++ case OPT_NOCERTS: ++ flags |= CMS_NOCERTS; ++ break; ++ case OPT_NOATTR: ++ flags |= CMS_NOATTR; ++ break; ++ case OPT_NODETACH: ++ flags &= ~CMS_DETACHED; ++ break; ++ case OPT_NOSMIMECAP: ++ flags |= CMS_NOSMIMECAP; ++ break; ++ case OPT_BINARY: ++ flags |= CMS_BINARY; ++ break; ++ case OPT_KEYID: ++ flags |= CMS_USE_KEYID; ++ break; ++ case OPT_NOSIGS: ++ flags |= CMS_NOSIGS; ++ break; ++ case OPT_NO_CONTENT_VERIFY: ++ flags |= CMS_NO_CONTENT_VERIFY; ++ break; ++ case OPT_NO_ATTR_VERIFY: ++ flags |= CMS_NO_ATTR_VERIFY; ++ break; ++ case OPT_INDEF: ++ flags |= CMS_STREAM; ++ break; ++ case OPT_NOINDEF: ++ flags &= ~CMS_STREAM; ++ break; ++ case OPT_CRLFEOL: ++ mime_eol = "\r\n"; ++ flags |= CMS_CRLFEOL; ++ break; ++ case OPT_NOOUT: ++ noout = 1; ++ break; ++ case OPT_RR_PRINT: ++ rr_print = 1; ++ break; ++ case OPT_RR_ALL: ++ rr_allorfirst = 0; ++ break; ++ case OPT_RR_FIRST: ++ rr_allorfirst = 1; ++ break; ++ case OPT_RCTFORM: ++ if (rctformat == FORMAT_SMIME) ++ rcms = SMIME_read_CMS(rctin, NULL); ++ else if (rctformat == FORMAT_PEM) ++ rcms = PEM_read_bio_CMS(rctin, NULL, NULL, NULL); ++ else if (rctformat == FORMAT_ASN1) ++ if (!opt_format(opt_arg(), ++ OPT_FMT_PEMDER | OPT_FMT_SMIME, &rctformat)) ++ goto opthelp; ++ break; ++ case OPT_CERTFILE: ++ certfile = opt_arg(); ++ break; ++ case OPT_CAFILE: ++ CAfile = opt_arg(); ++ break; ++ case OPT_CAPATH: ++ CApath = opt_arg(); ++ break; ++ case OPT_NOCAFILE: ++ noCAfile = 1; ++ break; ++ case OPT_NOCAPATH: ++ noCApath = 1; ++ break; ++ case OPT_IN: ++ infile = opt_arg(); ++ break; ++ case OPT_CONTENT: ++ contfile = opt_arg(); ++ break; ++ case OPT_RR_FROM: ++ if (rr_from == NULL ++ && (rr_from = sk_OPENSSL_STRING_new_null()) == NULL) ++ goto end; ++ sk_OPENSSL_STRING_push(rr_from, opt_arg()); ++ break; ++ case OPT_RR_TO: ++ if (rr_to == NULL ++ && (rr_to = sk_OPENSSL_STRING_new_null()) == NULL) ++ goto end; ++ sk_OPENSSL_STRING_push(rr_to, opt_arg()); ++ break; ++ case OPT_PRINT: ++ noout = print = 1; ++ break; ++ case OPT_SECRETKEY: ++ if (secret_key != NULL) { ++ BIO_printf(bio_err, "Invalid key (supplied twice) %s\n", ++ opt_arg()); ++ goto opthelp; ++ } ++ secret_key = OPENSSL_hexstr2buf(opt_arg(), <mp); ++ if (secret_key == NULL) { ++ BIO_printf(bio_err, "Invalid key %s\n", opt_arg()); ++ goto end; ++ } ++ secret_keylen = (size_t)ltmp; ++ break; ++ case OPT_SECRETKEYID: ++ if (secret_keyid != NULL) { ++ BIO_printf(bio_err, "Invalid id (supplied twice) %s\n", ++ opt_arg()); ++ goto opthelp; ++ } ++ secret_keyid = OPENSSL_hexstr2buf(opt_arg(), <mp); ++ if (secret_keyid == NULL) { ++ BIO_printf(bio_err, "Invalid id %s\n", opt_arg()); ++ goto opthelp; ++ } ++ secret_keyidlen = (size_t)ltmp; ++ break; ++ case OPT_PWRI_PASSWORD: ++ pwri_pass = (unsigned char *)opt_arg(); ++ break; ++ case OPT_ECONTENT_TYPE: ++ if (econtent_type != NULL) { ++ BIO_printf(bio_err, "Invalid OID (supplied twice) %s\n", ++ opt_arg()); ++ goto opthelp; ++ } ++ econtent_type = OBJ_txt2obj(opt_arg(), 0); ++ if (econtent_type == NULL) { ++ BIO_printf(bio_err, "Invalid OID %s\n", opt_arg()); ++ goto opthelp; ++ } ++ break; ++ case OPT_RAND: ++ inrand = opt_arg(); ++ need_rand = 1; ++ break; ++ case OPT_ENGINE: ++ e = setup_engine(opt_arg(), 0); ++ break; ++ case OPT_PASSIN: ++ passinarg = opt_arg(); ++ break; ++ case OPT_TO: ++ to = opt_arg(); ++ break; ++ case OPT_FROM: ++ from = opt_arg(); ++ break; ++ case OPT_SUBJECT: ++ subject = opt_arg(); ++ break; ++ case OPT_CERTSOUT: ++ certsoutfile = opt_arg(); ++ break; ++ case OPT_MD: ++ if (!opt_md(opt_arg(), &sign_md)) ++ goto end; ++ break; ++ case OPT_SIGNER: ++ /* If previous -signer argument add signer to list */ ++ if (signerfile) { ++ if (sksigners == NULL ++ && (sksigners = sk_OPENSSL_STRING_new_null()) == NULL) ++ goto end; ++ sk_OPENSSL_STRING_push(sksigners, signerfile); ++ if (keyfile == NULL) ++ keyfile = signerfile; ++ if (skkeys == NULL ++ && (skkeys = sk_OPENSSL_STRING_new_null()) == NULL) ++ goto end; ++ sk_OPENSSL_STRING_push(skkeys, keyfile); ++ keyfile = NULL; ++ } ++ signerfile = opt_arg(); ++ break; ++ case OPT_INKEY: ++ /* If previous -inkey argument add signer to list */ ++ if (keyfile) { ++ if (signerfile == NULL) { ++ BIO_puts(bio_err, "Illegal -inkey without -signer\n"); ++ goto end; ++ } ++ if (sksigners == NULL ++ && (sksigners = sk_OPENSSL_STRING_new_null()) == NULL) ++ goto end; ++ sk_OPENSSL_STRING_push(sksigners, signerfile); ++ signerfile = NULL; ++ if (skkeys == NULL ++ && (skkeys = sk_OPENSSL_STRING_new_null()) == NULL) ++ goto end; ++ sk_OPENSSL_STRING_push(skkeys, keyfile); ++ } ++ keyfile = opt_arg(); ++ break; ++ case OPT_KEYFORM: ++ if (!opt_format(opt_arg(), OPT_FMT_ANY, &keyform)) ++ goto opthelp; ++ break; ++ case OPT_RECIP: ++ if (operation == SMIME_ENCRYPT) { ++ if (encerts == NULL && (encerts = sk_X509_new_null()) == NULL) ++ goto end; ++ cert = load_cert(opt_arg(), FORMAT_PEM, ++ "recipient certificate file"); ++ if (cert == NULL) ++ goto end; ++ sk_X509_push(encerts, cert); ++ cert = NULL; ++ } else ++ recipfile = opt_arg(); ++ break; ++ case OPT_CIPHER: ++ if (!opt_cipher(opt_unknown(), &cipher)) ++ goto end; ++ break; ++ case OPT_KEYOPT: ++ keyidx = -1; ++ if (operation == SMIME_ENCRYPT) { ++ if (encerts) ++ keyidx += sk_X509_num(encerts); ++ } else { ++ if (keyfile || signerfile) ++ keyidx++; ++ if (skkeys) ++ keyidx += sk_OPENSSL_STRING_num(skkeys); ++ } ++ if (keyidx < 0) { ++ BIO_printf(bio_err, "No key specified\n"); ++ goto opthelp; ++ } ++ if (key_param == NULL || key_param->idx != keyidx) { ++ cms_key_param *nparam; ++ nparam = app_malloc(sizeof(*nparam), "key param buffer"); ++ nparam->idx = keyidx; ++ if ((nparam->param = sk_OPENSSL_STRING_new_null()) == NULL) ++ goto end; ++ nparam->next = NULL; ++ if (key_first == NULL) ++ key_first = nparam; ++ else ++ key_param->next = nparam; ++ key_param = nparam; ++ } ++ sk_OPENSSL_STRING_push(key_param->param, opt_arg()); ++ break; ++ case OPT_V_CASES: ++ if (!opt_verify(o, vpm)) ++ goto end; ++ vpmtouched++; ++ break; ++ case OPT_3DES_WRAP: ++# ifndef OPENSSL_NO_DES ++ wrap_cipher = EVP_des_ede3_wrap(); ++# endif ++ break; ++ case OPT_AES128_WRAP: ++ wrap_cipher = EVP_aes_128_wrap(); ++ break; ++ case OPT_AES192_WRAP: ++ wrap_cipher = EVP_aes_192_wrap(); ++ break; ++ case OPT_AES256_WRAP: ++ wrap_cipher = EVP_aes_256_wrap(); ++ break; ++ } ++ } ++ argc = opt_num_rest(); ++ argv = opt_rest(); ++ ++ if (((rr_allorfirst != -1) || rr_from) && !rr_to) { ++ BIO_puts(bio_err, "No Signed Receipts Recipients\n"); ++ goto opthelp; ++ } ++ ++ if (!(operation & SMIME_SIGNERS) && (rr_to || rr_from)) { ++ BIO_puts(bio_err, "Signed receipts only allowed with -sign\n"); ++ goto opthelp; ++ } ++ if (!(operation & SMIME_SIGNERS) && (skkeys || sksigners)) { ++ BIO_puts(bio_err, "Multiple signers or keys not allowed\n"); ++ goto opthelp; ++ } ++ ++ if (operation & SMIME_SIGNERS) { ++ if (keyfile && !signerfile) { ++ BIO_puts(bio_err, "Illegal -inkey without -signer\n"); ++ goto opthelp; ++ } ++ /* Check to see if any final signer needs to be appended */ ++ if (signerfile) { ++ if (!sksigners ++ && (sksigners = sk_OPENSSL_STRING_new_null()) == NULL) ++ goto end; ++ sk_OPENSSL_STRING_push(sksigners, signerfile); ++ if (!skkeys && (skkeys = sk_OPENSSL_STRING_new_null()) == NULL) ++ goto end; ++ if (!keyfile) ++ keyfile = signerfile; ++ sk_OPENSSL_STRING_push(skkeys, keyfile); ++ } ++ if (!sksigners) { ++ BIO_printf(bio_err, "No signer certificate specified\n"); ++ goto opthelp; ++ } ++ signerfile = NULL; ++ keyfile = NULL; ++ need_rand = 1; ++ } ++ ++ else if (operation == SMIME_DECRYPT) { ++ if (!recipfile && !keyfile && !secret_key && !pwri_pass) { ++ BIO_printf(bio_err, ++ "No recipient certificate or key specified\n"); ++ goto opthelp; ++ } ++ } else if (operation == SMIME_ENCRYPT) { ++ if (*argv == NULL && !secret_key && !pwri_pass && !encerts) { ++ BIO_printf(bio_err, "No recipient(s) certificate(s) specified\n"); ++ goto opthelp; ++ } ++ need_rand = 1; ++ } else if (!operation) ++ goto opthelp; ++ ++ if (!app_passwd(passinarg, NULL, &passin, NULL)) { ++ BIO_printf(bio_err, "Error getting password\n"); ++ goto end; ++ } ++ ++ if (need_rand) { ++ app_RAND_load_file(NULL, (inrand != NULL)); ++ if (inrand != NULL) ++ BIO_printf(bio_err, "%ld semi-random bytes loaded\n", ++ app_RAND_load_files(inrand)); ++ } ++ ++ ret = 2; ++ ++ if (!(operation & SMIME_SIGNERS)) ++ flags &= ~CMS_DETACHED; ++ ++ if (!(operation & SMIME_OP)) { ++ if (flags & CMS_BINARY) ++ outformat = FORMAT_BINARY; ++ } ++ ++ if (!(operation & SMIME_IP)) { ++ if (flags & CMS_BINARY) ++ informat = FORMAT_BINARY; ++ } ++ ++ if (operation == SMIME_ENCRYPT) { ++ if (!cipher) { ++# ifndef OPENSSL_NO_DES ++ cipher = EVP_des_ede3_cbc(); ++# else ++ BIO_printf(bio_err, "No cipher selected\n"); ++ goto end; ++# endif ++ } ++ ++ if (secret_key && !secret_keyid) { ++ BIO_printf(bio_err, "No secret key id\n"); ++ goto end; ++ } ++ ++ if (*argv && !encerts) ++ if ((encerts = sk_X509_new_null()) == NULL) ++ goto end; ++ while (*argv) { ++ if ((cert = load_cert(*argv, FORMAT_PEM, ++ "recipient certificate file")) == NULL) ++ goto end; ++ sk_X509_push(encerts, cert); ++ cert = NULL; ++ argv++; ++ } ++ } ++ ++ if (certfile) { ++ if (!load_certs(certfile, &other, FORMAT_PEM, NULL, ++ "certificate file")) { ++ ERR_print_errors(bio_err); ++ goto end; ++ } ++ } ++ ++ if (recipfile && (operation == SMIME_DECRYPT)) { ++ if ((recip = load_cert(recipfile, FORMAT_PEM, ++ "recipient 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) { ++ ERR_print_errors(bio_err); ++ goto end; ++ } ++ } ++ ++ if (operation == SMIME_DECRYPT) { ++ if (!keyfile) ++ keyfile = recipfile; ++ } else if ((operation == SMIME_SIGN) || (operation == SMIME_SIGN_RECEIPT)) { ++ if (!keyfile) ++ keyfile = signerfile; ++ } else ++ keyfile = NULL; ++ ++ if (keyfile) { ++ key = load_key(keyfile, keyform, 0, passin, e, "signing key file"); ++ if (!key) ++ goto end; ++ } ++ ++ in = bio_open_default(infile, 'r', informat); ++ if (in == NULL) ++ goto end; ++ ++ if (operation & SMIME_IP) { ++ if (informat == FORMAT_SMIME) ++ cms = SMIME_read_CMS(in, &indata); ++ else if (informat == FORMAT_PEM) ++ cms = PEM_read_bio_CMS(in, NULL, NULL, NULL); ++ else if (informat == FORMAT_ASN1) ++ cms = d2i_CMS_bio(in, NULL); ++ else { ++ BIO_printf(bio_err, "Bad input format for CMS file\n"); ++ goto end; ++ } ++ ++ if (!cms) { ++ BIO_printf(bio_err, "Error reading S/MIME message\n"); ++ goto end; ++ } ++ if (contfile) { ++ BIO_free(indata); ++ if ((indata = BIO_new_file(contfile, "rb")) == NULL) { ++ BIO_printf(bio_err, "Can't read content file %s\n", contfile); ++ goto end; ++ } ++ } ++ if (certsoutfile) { ++ STACK_OF(X509) *allcerts; ++ allcerts = CMS_get1_certs(cms); ++ if (!save_certs(certsoutfile, allcerts)) { ++ BIO_printf(bio_err, ++ "Error writing certs to %s\n", certsoutfile); ++ ret = 5; ++ goto end; ++ } ++ sk_X509_pop_free(allcerts, X509_free); ++ } ++ } ++ ++ if (rctfile) { ++ char *rctmode = (rctformat == FORMAT_ASN1) ? "rb" : "r"; ++ if ((rctin = BIO_new_file(rctfile, rctmode)) == NULL) { ++ BIO_printf(bio_err, "Can't open receipt file %s\n", rctfile); ++ goto end; ++ } ++ ++ if (rctformat == FORMAT_SMIME) ++ rcms = SMIME_read_CMS(rctin, NULL); ++ else if (rctformat == FORMAT_PEM) ++ rcms = PEM_read_bio_CMS(rctin, NULL, NULL, NULL); ++ else if (rctformat == FORMAT_ASN1) ++ rcms = d2i_CMS_bio(rctin, NULL); ++ else { ++ BIO_printf(bio_err, "Bad input format for receipt\n"); ++ goto end; ++ } ++ ++ if (!rcms) { ++ BIO_printf(bio_err, "Error reading receipt\n"); ++ goto end; ++ } ++ } ++ ++ out = bio_open_default(outfile, 'w', outformat); ++ if (out == NULL) ++ goto end; ++ ++ if ((operation == SMIME_VERIFY) || (operation == SMIME_VERIFY_RECEIPT)) { ++ if ((store = setup_verify(CAfile, CApath, noCAfile, noCApath)) == NULL) ++ goto end; ++ X509_STORE_set_verify_cb(store, cms_cb); ++ if (vpmtouched) ++ X509_STORE_set1_param(store, vpm); ++ } ++ ++ ret = 3; ++ ++ if (operation == SMIME_DATA_CREATE) { ++ cms = CMS_data_create(in, flags); ++ } else if (operation == SMIME_DIGEST_CREATE) { ++ cms = CMS_digest_create(in, sign_md, flags); ++ } else if (operation == SMIME_COMPRESS) { ++ cms = CMS_compress(in, -1, flags); ++ } else if (operation == SMIME_ENCRYPT) { ++ int i; ++ flags |= CMS_PARTIAL; ++ cms = CMS_encrypt(NULL, in, cipher, flags); ++ if (!cms) ++ goto end; ++ for (i = 0; i < sk_X509_num(encerts); i++) { ++ CMS_RecipientInfo *ri; ++ cms_key_param *kparam; ++ int tflags = flags; ++ X509 *x = sk_X509_value(encerts, i); ++ 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); ++ if (!ri) ++ goto end; ++ if (kparam) { ++ EVP_PKEY_CTX *pctx; ++ pctx = CMS_RecipientInfo_get0_pkey_ctx(ri); ++ if (!cms_set_pkey_param(pctx, kparam->param)) ++ goto end; ++ } ++ if (CMS_RecipientInfo_type(ri) == CMS_RECIPINFO_AGREE ++ && wrap_cipher) { ++ EVP_CIPHER_CTX *wctx; ++ wctx = CMS_RecipientInfo_kari_get0_ctx(ri); ++ EVP_EncryptInit_ex(wctx, wrap_cipher, NULL, NULL, NULL); ++ } ++ } ++ ++ if (secret_key) { ++ if (!CMS_add0_recipient_key(cms, NID_undef, ++ secret_key, secret_keylen, ++ secret_keyid, secret_keyidlen, ++ NULL, NULL, NULL)) ++ goto end; ++ /* NULL these because call absorbs them */ ++ secret_key = NULL; ++ secret_keyid = NULL; ++ } ++ if (pwri_pass) { ++ pwri_tmp = (unsigned char *)OPENSSL_strdup((char *)pwri_pass); ++ if (!pwri_tmp) ++ goto end; ++ if (!CMS_add0_recipient_password(cms, ++ -1, NID_undef, NID_undef, ++ pwri_tmp, -1, NULL)) ++ goto end; ++ pwri_tmp = NULL; ++ } ++ if (!(flags & CMS_STREAM)) { ++ if (!CMS_final(cms, in, NULL, flags)) ++ goto end; ++ } ++ } else if (operation == SMIME_ENCRYPTED_ENCRYPT) { ++ cms = CMS_EncryptedData_encrypt(in, cipher, ++ secret_key, secret_keylen, flags); ++ ++ } else if (operation == SMIME_SIGN_RECEIPT) { ++ CMS_ContentInfo *srcms = NULL; ++ STACK_OF(CMS_SignerInfo) *sis; ++ CMS_SignerInfo *si; ++ sis = CMS_get0_SignerInfos(cms); ++ if (!sis) ++ goto end; ++ si = sk_CMS_SignerInfo_value(sis, 0); ++ srcms = CMS_sign_receipt(si, signer, key, other, flags); ++ if (!srcms) ++ goto end; ++ CMS_ContentInfo_free(cms); ++ cms = srcms; ++ } else if (operation & SMIME_SIGNERS) { ++ int i; ++ /* ++ * If detached data content we enable streaming if S/MIME output ++ * format. ++ */ ++ if (operation == SMIME_SIGN) { ++ ++ if (flags & CMS_DETACHED) { ++ if (outformat == FORMAT_SMIME) ++ flags |= CMS_STREAM; ++ } ++ flags |= CMS_PARTIAL; ++ cms = CMS_sign(NULL, NULL, other, in, flags); ++ if (!cms) ++ goto end; ++ if (econtent_type) ++ CMS_set1_eContentType(cms, econtent_type); ++ ++ if (rr_to) { ++ rr = make_receipt_request(rr_to, rr_allorfirst, rr_from); ++ if (!rr) { ++ BIO_puts(bio_err, ++ "Signed Receipt Request Creation Error\n"); ++ goto end; ++ } ++ } ++ } else ++ flags |= CMS_REUSE_DIGEST; ++ for (i = 0; i < sk_OPENSSL_STRING_num(sksigners); i++) { ++ CMS_SignerInfo *si; ++ cms_key_param *kparam; ++ int tflags = flags; ++ signerfile = sk_OPENSSL_STRING_value(sksigners, i); ++ keyfile = sk_OPENSSL_STRING_value(skkeys, i); ++ ++ signer = load_cert(signerfile, FORMAT_PEM, "signer certificate"); ++ if (!signer) ++ goto end; ++ key = load_key(keyfile, keyform, 0, passin, e, "signing key file"); ++ if (!key) ++ goto end; ++ for (kparam = key_first; kparam; kparam = kparam->next) { ++ if (kparam->idx == i) { ++ tflags |= CMS_KEY_PARAM; ++ break; ++ } ++ } ++ si = CMS_add1_signer(cms, signer, key, sign_md, tflags); ++ if (!si) ++ goto end; ++ if (kparam) { ++ EVP_PKEY_CTX *pctx; ++ pctx = CMS_SignerInfo_get0_pkey_ctx(si); ++ if (!cms_set_pkey_param(pctx, kparam->param)) ++ goto end; ++ } ++ if (rr && !CMS_add1_ReceiptRequest(si, rr)) ++ goto end; ++ X509_free(signer); ++ signer = NULL; ++ EVP_PKEY_free(key); ++ key = NULL; ++ } ++ /* If not streaming or resigning finalize structure */ ++ if ((operation == SMIME_SIGN) && !(flags & CMS_STREAM)) { ++ if (!CMS_final(cms, in, NULL, flags)) ++ goto end; ++ } ++ } ++ ++ if (!cms) { ++ BIO_printf(bio_err, "Error creating CMS structure\n"); ++ goto end; ++ } ++ ++ ret = 4; ++ if (operation == SMIME_DECRYPT) { ++ if (flags & CMS_DEBUG_DECRYPT) ++ CMS_decrypt(cms, NULL, NULL, NULL, NULL, flags); ++ ++ if (secret_key) { ++ if (!CMS_decrypt_set1_key(cms, ++ secret_key, secret_keylen, ++ secret_keyid, secret_keyidlen)) { ++ BIO_puts(bio_err, "Error decrypting CMS using secret key\n"); ++ goto end; ++ } ++ } ++ ++ if (key) { ++ if (!CMS_decrypt_set1_pkey(cms, key, recip)) { ++ BIO_puts(bio_err, "Error decrypting CMS using private key\n"); ++ goto end; ++ } ++ } ++ ++ if (pwri_pass) { ++ if (!CMS_decrypt_set1_password(cms, pwri_pass, -1)) { ++ BIO_puts(bio_err, "Error decrypting CMS using password\n"); ++ goto end; ++ } ++ } ++ ++ if (!CMS_decrypt(cms, NULL, NULL, indata, out, flags)) { ++ BIO_printf(bio_err, "Error decrypting CMS structure\n"); ++ goto end; ++ } ++ } else if (operation == SMIME_DATAOUT) { ++ if (!CMS_data(cms, out, flags)) ++ goto end; ++ } else if (operation == SMIME_UNCOMPRESS) { ++ if (!CMS_uncompress(cms, indata, out, flags)) ++ goto end; ++ } else if (operation == SMIME_DIGEST_VERIFY) { ++ if (CMS_digest_verify(cms, indata, out, flags) > 0) ++ BIO_printf(bio_err, "Verification successful\n"); ++ else { ++ BIO_printf(bio_err, "Verification failure\n"); ++ goto end; ++ } ++ } else if (operation == SMIME_ENCRYPTED_DECRYPT) { ++ if (!CMS_EncryptedData_decrypt(cms, secret_key, secret_keylen, ++ indata, out, flags)) ++ goto end; ++ } else if (operation == SMIME_VERIFY) { ++ if (CMS_verify(cms, other, store, indata, out, flags) > 0) ++ BIO_printf(bio_err, "Verification successful\n"); ++ else { ++ BIO_printf(bio_err, "Verification failure\n"); ++ if (verify_retcode) ++ ret = verify_err + 32; ++ goto end; ++ } ++ if (signerfile) { ++ STACK_OF(X509) *signers; ++ signers = CMS_get0_signers(cms); ++ if (!save_certs(signerfile, signers)) { ++ BIO_printf(bio_err, ++ "Error writing signers to %s\n", signerfile); ++ ret = 5; ++ goto end; ++ } ++ sk_X509_free(signers); ++ } ++ if (rr_print) ++ receipt_request_print(cms); ++ ++ } else if (operation == SMIME_VERIFY_RECEIPT) { ++ if (CMS_verify_receipt(rcms, cms, other, store, flags) > 0) ++ BIO_printf(bio_err, "Verification successful\n"); ++ else { ++ BIO_printf(bio_err, "Verification failure\n"); ++ goto end; ++ } ++ } else { ++ if (noout) { ++ if (print) ++ CMS_ContentInfo_print_ctx(out, cms, 0, NULL); ++ } else if (outformat == FORMAT_SMIME) { ++ if (to) ++ BIO_printf(out, "To: %s%s", to, mime_eol); ++ if (from) ++ BIO_printf(out, "From: %s%s", from, mime_eol); ++ if (subject) ++ BIO_printf(out, "Subject: %s%s", subject, mime_eol); ++ if (operation == SMIME_RESIGN) ++ ret = SMIME_write_CMS(out, cms, indata, flags); ++ else ++ ret = SMIME_write_CMS(out, cms, in, flags); ++ } else if (outformat == FORMAT_PEM) ++ ret = PEM_write_bio_CMS_stream(out, cms, in, flags); ++ else if (outformat == FORMAT_ASN1) ++ ret = i2d_CMS_bio_stream(out, cms, in, flags); ++ else { ++ BIO_printf(bio_err, "Bad output format for CMS file\n"); ++ goto end; ++ } ++ if (ret <= 0) { ++ ret = 6; ++ goto end; ++ } ++ } ++ ret = 0; ++ end: ++ if (ret) ++ ERR_print_errors(bio_err); ++ if (need_rand) ++ app_RAND_write_file(NULL); ++ sk_X509_pop_free(encerts, X509_free); ++ sk_X509_pop_free(other, X509_free); ++ X509_VERIFY_PARAM_free(vpm); ++ sk_OPENSSL_STRING_free(sksigners); ++ sk_OPENSSL_STRING_free(skkeys); ++ OPENSSL_free(secret_key); ++ OPENSSL_free(secret_keyid); ++ OPENSSL_free(pwri_tmp); ++ ASN1_OBJECT_free(econtent_type); ++ CMS_ReceiptRequest_free(rr); ++ sk_OPENSSL_STRING_free(rr_to); ++ sk_OPENSSL_STRING_free(rr_from); ++ for (key_param = key_first; key_param;) { ++ cms_key_param *tparam; ++ sk_OPENSSL_STRING_free(key_param->param); ++ tparam = key_param->next; ++ OPENSSL_free(key_param); ++ key_param = tparam; ++ } ++ X509_STORE_free(store); ++ X509_free(cert); ++ X509_free(recip); ++ X509_free(signer); ++ EVP_PKEY_free(key); ++ CMS_ContentInfo_free(cms); ++ CMS_ContentInfo_free(rcms); ++ release_engine(e); ++ BIO_free(rctin); ++ BIO_free(in); ++ BIO_free(indata); ++ BIO_free_all(out); ++ OPENSSL_free(passin); ++ return (ret); ++} ++ ++static int save_certs(char *signerfile, STACK_OF(X509) *signers) ++{ ++ int i; ++ BIO *tmp; ++ if (!signerfile) ++ return 1; ++ tmp = BIO_new_file(signerfile, "w"); ++ if (!tmp) ++ return 0; ++ for (i = 0; i < sk_X509_num(signers); i++) ++ PEM_write_bio_X509(tmp, sk_X509_value(signers, i)); ++ BIO_free(tmp); ++ return 1; ++} ++ ++/* Minimal callback just to output policy info (if any) */ ++ ++static int cms_cb(int ok, X509_STORE_CTX *ctx) ++{ ++ int error; ++ ++ error = X509_STORE_CTX_get_error(ctx); ++ ++ verify_err = error; ++ ++ if ((error != X509_V_ERR_NO_EXPLICIT_POLICY) ++ && ((error != X509_V_OK) || (ok != 2))) ++ return ok; ++ ++ policies_print(ctx); ++ ++ return ok; ++ ++} ++ ++static void gnames_stack_print(STACK_OF(GENERAL_NAMES) *gns) ++{ ++ STACK_OF(GENERAL_NAME) *gens; ++ GENERAL_NAME *gen; ++ int i, j; ++ ++ for (i = 0; i < sk_GENERAL_NAMES_num(gns); i++) { ++ gens = sk_GENERAL_NAMES_value(gns, i); ++ for (j = 0; j < sk_GENERAL_NAME_num(gens); j++) { ++ gen = sk_GENERAL_NAME_value(gens, j); ++ BIO_puts(bio_err, " "); ++ GENERAL_NAME_print(bio_err, gen); ++ BIO_puts(bio_err, "\n"); ++ } ++ } ++ return; ++} ++ ++static void receipt_request_print(CMS_ContentInfo *cms) ++{ ++ STACK_OF(CMS_SignerInfo) *sis; ++ CMS_SignerInfo *si; ++ CMS_ReceiptRequest *rr; ++ int allorfirst; ++ STACK_OF(GENERAL_NAMES) *rto, *rlist; ++ ASN1_STRING *scid; ++ int i, rv; ++ sis = CMS_get0_SignerInfos(cms); ++ for (i = 0; i < sk_CMS_SignerInfo_num(sis); i++) { ++ si = sk_CMS_SignerInfo_value(sis, i); ++ rv = CMS_get1_ReceiptRequest(si, &rr); ++ BIO_printf(bio_err, "Signer %d:\n", i + 1); ++ if (rv == 0) ++ BIO_puts(bio_err, " No Receipt Request\n"); ++ else if (rv < 0) { ++ BIO_puts(bio_err, " Receipt Request Parse Error\n"); ++ ERR_print_errors(bio_err); ++ } else { ++ const char *id; ++ int idlen; ++ CMS_ReceiptRequest_get0_values(rr, &scid, &allorfirst, ++ &rlist, &rto); ++ BIO_puts(bio_err, " Signed Content ID:\n"); ++ idlen = ASN1_STRING_length(scid); ++ id = (const char *)ASN1_STRING_get0_data(scid); ++ BIO_dump_indent(bio_err, id, idlen, 4); ++ BIO_puts(bio_err, " Receipts From"); ++ if (rlist) { ++ BIO_puts(bio_err, " List:\n"); ++ gnames_stack_print(rlist); ++ } else if (allorfirst == 1) ++ BIO_puts(bio_err, ": First Tier\n"); ++ else if (allorfirst == 0) ++ BIO_puts(bio_err, ": All\n"); ++ else ++ BIO_printf(bio_err, " Unknown (%d)\n", allorfirst); ++ BIO_puts(bio_err, " Receipts To:\n"); ++ gnames_stack_print(rto); ++ } ++ CMS_ReceiptRequest_free(rr); ++ } ++} ++ ++static STACK_OF(GENERAL_NAMES) *make_names_stack(STACK_OF(OPENSSL_STRING) *ns) ++{ ++ int i; ++ STACK_OF(GENERAL_NAMES) *ret; ++ GENERAL_NAMES *gens = NULL; ++ GENERAL_NAME *gen = NULL; ++ ret = sk_GENERAL_NAMES_new_null(); ++ if (!ret) ++ goto err; ++ for (i = 0; i < sk_OPENSSL_STRING_num(ns); i++) { ++ char *str = sk_OPENSSL_STRING_value(ns, i); ++ gen = a2i_GENERAL_NAME(NULL, NULL, NULL, GEN_EMAIL, str, 0); ++ if (!gen) ++ goto err; ++ gens = GENERAL_NAMES_new(); ++ if (gens == NULL) ++ goto err; ++ if (!sk_GENERAL_NAME_push(gens, gen)) ++ goto err; ++ gen = NULL; ++ if (!sk_GENERAL_NAMES_push(ret, gens)) ++ goto err; ++ gens = NULL; ++ } ++ ++ return ret; ++ ++ err: ++ sk_GENERAL_NAMES_pop_free(ret, GENERAL_NAMES_free); ++ GENERAL_NAMES_free(gens); ++ GENERAL_NAME_free(gen); ++ return NULL; ++} ++ ++static CMS_ReceiptRequest *make_receipt_request(STACK_OF(OPENSSL_STRING) ++ *rr_to, int rr_allorfirst, STACK_OF(OPENSSL_STRING) ++ *rr_from) ++{ ++ STACK_OF(GENERAL_NAMES) *rct_to = NULL, *rct_from = NULL; ++ CMS_ReceiptRequest *rr; ++ rct_to = make_names_stack(rr_to); ++ if (!rct_to) ++ goto err; ++ if (rr_from) { ++ rct_from = make_names_stack(rr_from); ++ if (!rct_from) ++ goto err; ++ } else ++ rct_from = NULL; ++ rr = CMS_ReceiptRequest_create0(NULL, -1, rr_allorfirst, rct_from, ++ rct_to); ++ return rr; ++ err: ++ sk_GENERAL_NAMES_pop_free(rct_to, GENERAL_NAMES_free); ++ return NULL; ++} ++ ++static int cms_set_pkey_param(EVP_PKEY_CTX *pctx, ++ STACK_OF(OPENSSL_STRING) *param) ++{ ++ char *keyopt; ++ int i; ++ if (sk_OPENSSL_STRING_num(param) <= 0) ++ return 1; ++ for (i = 0; i < sk_OPENSSL_STRING_num(param); i++) { ++ keyopt = sk_OPENSSL_STRING_value(param, i); ++ if (pkey_ctrl_string(pctx, keyopt) <= 0) { ++ BIO_printf(bio_err, "parameter error \"%s\"\n", keyopt); ++ ERR_print_errors(bio_err); ++ return 0; ++ } ++ } ++ return 1; ++} ++ ++#endif +diff --git a/CryptoPkg/Library/OpensslLib/openssl/apps/crl.c b/CryptoPkg/Library/OpensslLib/openssl/apps/crl.c +new file mode 100644 +index 0000000..06b6e5b +--- /dev/null ++++ b/CryptoPkg/Library/OpensslLib/openssl/apps/crl.c +@@ -0,0 +1,347 @@ ++/* ++ * Copyright 1995-2016 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 ++ * in the file LICENSE in the source distribution or at ++ * https://www.openssl.org/source/license.html ++ */ ++ ++#include ++#include ++#include ++#include "apps.h" ++#include ++#include ++#include ++#include ++#include ++ ++typedef enum OPTION_choice { ++ OPT_ERR = -1, OPT_EOF = 0, OPT_HELP, ++ OPT_INFORM, OPT_IN, OPT_OUTFORM, OPT_OUT, OPT_KEYFORM, OPT_KEY, ++ OPT_ISSUER, OPT_LASTUPDATE, OPT_NEXTUPDATE, OPT_FINGERPRINT, ++ OPT_CRLNUMBER, OPT_BADSIG, OPT_GENDELTA, OPT_CAPATH, OPT_CAFILE, ++ OPT_NOCAPATH, OPT_NOCAFILE, OPT_VERIFY, OPT_TEXT, OPT_HASH, OPT_HASH_OLD, ++ OPT_NOOUT, OPT_NAMEOPT, OPT_MD ++} OPTION_CHOICE; ++ ++OPTIONS crl_options[] = { ++ {"help", OPT_HELP, '-', "Display this summary"}, ++ {"inform", OPT_INFORM, 'F', "Input format; default PEM"}, ++ {"in", OPT_IN, '<', "Input file - default stdin"}, ++ {"outform", OPT_OUTFORM, 'F', "Output format - default PEM"}, ++ {"out", OPT_OUT, '>', "output file - default stdout"}, ++ {"keyform", OPT_KEYFORM, 'F', "Private key file format (PEM or ENGINE)"}, ++ {"key", OPT_KEY, '<', "CRL signing Private key to use"}, ++ {"issuer", OPT_ISSUER, '-', "Print issuer DN"}, ++ {"lastupdate", OPT_LASTUPDATE, '-', "Set lastUpdate field"}, ++ {"nextupdate", OPT_NEXTUPDATE, '-', "Set nextUpdate field"}, ++ {"noout", OPT_NOOUT, '-', "No CRL output"}, ++ {"fingerprint", OPT_FINGERPRINT, '-', "Print the crl fingerprint"}, ++ {"crlnumber", OPT_CRLNUMBER, '-', "Print CRL number"}, ++ {"badsig", OPT_BADSIG, '-', "Corrupt last byte of loaded CRL signature (for test)" }, ++ {"gendelta", OPT_GENDELTA, '<', "Other CRL to compare/diff to the Input one"}, ++ {"CApath", OPT_CAPATH, '/', "Verify CRL using certificates in dir"}, ++ {"CAfile", OPT_CAFILE, '<', "Verify CRL using certificates in file name"}, ++ {"no-CAfile", OPT_NOCAFILE, '-', ++ "Do not load the default certificates file"}, ++ {"no-CApath", OPT_NOCAPATH, '-', ++ "Do not load certificates from the default certificates directory"}, ++ {"verify", OPT_VERIFY, '-', "Verify CRL signature"}, ++ {"text", OPT_TEXT, '-', "Print out a text format version"}, ++ {"hash", OPT_HASH, '-', "Print hash value"}, ++ {"nameopt", OPT_NAMEOPT, 's', "Various certificate name options"}, ++ {"", OPT_MD, '-', "Any supported digest"}, ++#ifndef OPENSSL_NO_MD5 ++ {"hash_old", OPT_HASH_OLD, '-', "Print old-style (MD5) hash value"}, ++#endif ++ {NULL} ++}; ++ ++int crl_main(int argc, char **argv) ++{ ++ X509_CRL *x = NULL; ++ BIO *out = NULL; ++ X509_STORE *store = NULL; ++ X509_STORE_CTX *ctx = NULL; ++ X509_LOOKUP *lookup = NULL; ++ X509_OBJECT *xobj = NULL; ++ EVP_PKEY *pkey; ++ const EVP_MD *digest = EVP_sha1(); ++ unsigned long nmflag = 0; ++ char nmflag_set = 0; ++ char *infile = NULL, *outfile = NULL, *crldiff = NULL, *keyfile = NULL; ++ const char *CAfile = NULL, *CApath = NULL, *prog; ++ OPTION_CHOICE o; ++ int hash = 0, issuer = 0, lastupdate = 0, nextupdate = 0, noout = 0; ++ int informat = FORMAT_PEM, outformat = FORMAT_PEM, keyformat = FORMAT_PEM; ++ int ret = 1, num = 0, badsig = 0, fingerprint = 0, crlnumber = 0; ++ int text = 0, do_ver = 0, noCAfile = 0, noCApath = 0; ++ int i; ++#ifndef OPENSSL_NO_MD5 ++ int hash_old = 0; ++#endif ++ ++ prog = opt_init(argc, argv, crl_options); ++ while ((o = opt_next()) != OPT_EOF) { ++ switch (o) { ++ case OPT_EOF: ++ case OPT_ERR: ++ opthelp: ++ BIO_printf(bio_err, "%s: Use -help for summary.\n", prog); ++ goto end; ++ case OPT_HELP: ++ opt_help(crl_options); ++ ret = 0; ++ goto end; ++ case OPT_INFORM: ++ if (!opt_format(opt_arg(), OPT_FMT_PEMDER, &informat)) ++ goto opthelp; ++ break; ++ case OPT_IN: ++ infile = opt_arg(); ++ break; ++ case OPT_OUTFORM: ++ if (!opt_format(opt_arg(), OPT_FMT_PEMDER, &outformat)) ++ goto opthelp; ++ break; ++ case OPT_OUT: ++ outfile = opt_arg(); ++ break; ++ case OPT_KEYFORM: ++ if (!opt_format(opt_arg(), OPT_FMT_PEMDER, &keyformat)) ++ goto opthelp; ++ break; ++ case OPT_KEY: ++ keyfile = opt_arg(); ++ break; ++ case OPT_GENDELTA: ++ crldiff = opt_arg(); ++ break; ++ case OPT_CAPATH: ++ CApath = opt_arg(); ++ do_ver = 1; ++ break; ++ case OPT_CAFILE: ++ CAfile = opt_arg(); ++ do_ver = 1; ++ break; ++ case OPT_NOCAPATH: ++ noCApath = 1; ++ break; ++ case OPT_NOCAFILE: ++ noCAfile = 1; ++ break; ++ case OPT_HASH_OLD: ++#ifndef OPENSSL_NO_MD5 ++ hash_old = ++num; ++#endif ++ break; ++ case OPT_VERIFY: ++ do_ver = 1; ++ break; ++ case OPT_TEXT: ++ text = 1; ++ break; ++ case OPT_HASH: ++ hash = ++num; ++ break; ++ case OPT_ISSUER: ++ issuer = ++num; ++ break; ++ case OPT_LASTUPDATE: ++ lastupdate = ++num; ++ break; ++ case OPT_NEXTUPDATE: ++ nextupdate = ++num; ++ break; ++ case OPT_NOOUT: ++ noout = ++num; ++ break; ++ case OPT_FINGERPRINT: ++ fingerprint = ++num; ++ break; ++ case OPT_CRLNUMBER: ++ crlnumber = ++num; ++ break; ++ case OPT_BADSIG: ++ badsig = 1; ++ break; ++ case OPT_NAMEOPT: ++ nmflag_set = 1; ++ if (!set_name_ex(&nmflag, opt_arg())) ++ goto opthelp; ++ break; ++ case OPT_MD: ++ if (!opt_md(opt_unknown(), &digest)) ++ goto opthelp; ++ } ++ } ++ argc = opt_num_rest(); ++ if (argc != 0) ++ goto opthelp; ++ ++ if (!nmflag_set) ++ nmflag = XN_FLAG_ONELINE; ++ ++ x = load_crl(infile, informat); ++ if (x == NULL) ++ goto end; ++ ++ if (do_ver) { ++ if ((store = setup_verify(CAfile, CApath, noCAfile, noCApath)) == NULL) ++ goto end; ++ lookup = X509_STORE_add_lookup(store, X509_LOOKUP_file()); ++ if (lookup == NULL) ++ goto end; ++ ctx = X509_STORE_CTX_new(); ++ if (ctx == NULL || !X509_STORE_CTX_init(ctx, store, NULL, NULL)) { ++ BIO_printf(bio_err, "Error initialising X509 store\n"); ++ goto end; ++ } ++ ++ xobj = X509_STORE_CTX_get_obj_by_subject(ctx, X509_LU_X509, ++ X509_CRL_get_issuer(x)); ++ if (xobj == NULL) { ++ BIO_printf(bio_err, "Error getting CRL issuer certificate\n"); ++ goto end; ++ } ++ pkey = X509_get_pubkey(X509_OBJECT_get0_X509(xobj)); ++ X509_OBJECT_free(xobj); ++ if (!pkey) { ++ BIO_printf(bio_err, "Error getting CRL issuer public key\n"); ++ goto end; ++ } ++ i = X509_CRL_verify(x, pkey); ++ EVP_PKEY_free(pkey); ++ if (i < 0) ++ goto end; ++ if (i == 0) ++ BIO_printf(bio_err, "verify failure\n"); ++ else ++ BIO_printf(bio_err, "verify OK\n"); ++ } ++ ++ if (crldiff) { ++ X509_CRL *newcrl, *delta; ++ if (!keyfile) { ++ BIO_puts(bio_err, "Missing CRL signing key\n"); ++ goto end; ++ } ++ newcrl = load_crl(crldiff, informat); ++ if (!newcrl) ++ goto end; ++ pkey = load_key(keyfile, keyformat, 0, NULL, NULL, "CRL signing key"); ++ if (!pkey) { ++ X509_CRL_free(newcrl); ++ goto end; ++ } ++ delta = X509_CRL_diff(x, newcrl, pkey, digest, 0); ++ X509_CRL_free(newcrl); ++ EVP_PKEY_free(pkey); ++ if (delta) { ++ X509_CRL_free(x); ++ x = delta; ++ } else { ++ BIO_puts(bio_err, "Error creating delta CRL\n"); ++ goto end; ++ } ++ } ++ ++ if (badsig) { ++ const ASN1_BIT_STRING *sig; ++ ++ X509_CRL_get0_signature(x, &sig, NULL); ++ corrupt_signature(sig); ++ } ++ ++ if (num) { ++ for (i = 1; i <= num; i++) { ++ if (issuer == i) { ++ print_name(bio_out, "issuer=", X509_CRL_get_issuer(x), ++ nmflag); ++ } ++ if (crlnumber == i) { ++ ASN1_INTEGER *crlnum; ++ crlnum = X509_CRL_get_ext_d2i(x, NID_crl_number, NULL, NULL); ++ BIO_printf(bio_out, "crlNumber="); ++ if (crlnum) { ++ i2a_ASN1_INTEGER(bio_out, crlnum); ++ ASN1_INTEGER_free(crlnum); ++ } else ++ BIO_puts(bio_out, ""); ++ BIO_printf(bio_out, "\n"); ++ } ++ if (hash == i) { ++ BIO_printf(bio_out, "%08lx\n", ++ X509_NAME_hash(X509_CRL_get_issuer(x))); ++ } ++#ifndef OPENSSL_NO_MD5 ++ if (hash_old == i) { ++ BIO_printf(bio_out, "%08lx\n", ++ X509_NAME_hash_old(X509_CRL_get_issuer(x))); ++ } ++#endif ++ if (lastupdate == i) { ++ BIO_printf(bio_out, "lastUpdate="); ++ ASN1_TIME_print(bio_out, X509_CRL_get0_lastUpdate(x)); ++ BIO_printf(bio_out, "\n"); ++ } ++ if (nextupdate == i) { ++ BIO_printf(bio_out, "nextUpdate="); ++ if (X509_CRL_get0_nextUpdate(x)) ++ ASN1_TIME_print(bio_out, X509_CRL_get0_nextUpdate(x)); ++ else ++ BIO_printf(bio_out, "NONE"); ++ BIO_printf(bio_out, "\n"); ++ } ++ if (fingerprint == i) { ++ int j; ++ unsigned int n; ++ unsigned char md[EVP_MAX_MD_SIZE]; ++ ++ if (!X509_CRL_digest(x, digest, md, &n)) { ++ BIO_printf(bio_err, "out of memory\n"); ++ goto end; ++ } ++ BIO_printf(bio_out, "%s Fingerprint=", ++ OBJ_nid2sn(EVP_MD_type(digest))); ++ for (j = 0; j < (int)n; j++) { ++ BIO_printf(bio_out, "%02X%c", md[j], (j + 1 == (int)n) ++ ? '\n' : ':'); ++ } ++ } ++ } ++ } ++ out = bio_open_default(outfile, 'w', outformat); ++ if (out == NULL) ++ goto end; ++ ++ if (text) ++ X509_CRL_print(out, x); ++ ++ if (noout) { ++ ret = 0; ++ goto end; ++ } ++ ++ if (outformat == FORMAT_ASN1) ++ i = (int)i2d_X509_CRL_bio(out, x); ++ else ++ i = PEM_write_bio_X509_CRL(out, x); ++ if (!i) { ++ BIO_printf(bio_err, "unable to write CRL\n"); ++ goto end; ++ } ++ ret = 0; ++ ++ end: ++ if (ret != 0) ++ ERR_print_errors(bio_err); ++ BIO_free_all(out); ++ X509_CRL_free(x); ++ X509_STORE_CTX_free(ctx); ++ X509_STORE_free(store); ++ return (ret); ++} +diff --git a/CryptoPkg/Library/OpensslLib/openssl/apps/crl2p7.c b/CryptoPkg/Library/OpensslLib/openssl/apps/crl2p7.c +new file mode 100644 +index 0000000..9c5f79f +--- /dev/null ++++ b/CryptoPkg/Library/OpensslLib/openssl/apps/crl2p7.c +@@ -0,0 +1,216 @@ ++/* ++ * Copyright 1995-2016 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 ++ * in the file LICENSE in the source distribution or at ++ * https://www.openssl.org/source/license.html ++ */ ++ ++#include ++#include ++#include ++#include "apps.h" ++#include ++#include ++#include ++#include ++#include ++#include ++ ++static int add_certs_from_file(STACK_OF(X509) *stack, char *certfile); ++ ++typedef enum OPTION_choice { ++ OPT_ERR = -1, OPT_EOF = 0, OPT_HELP, ++ OPT_INFORM, OPT_OUTFORM, OPT_IN, OPT_OUT, OPT_NOCRL, OPT_CERTFILE ++} OPTION_CHOICE; ++ ++OPTIONS crl2pkcs7_options[] = { ++ {"help", OPT_HELP, '-', "Display this summary"}, ++ {"inform", OPT_INFORM, 'F', "Input format - DER or PEM"}, ++ {"outform", OPT_OUTFORM, 'F', "Output format - DER or PEM"}, ++ {"in", OPT_IN, '<', "Input file"}, ++ {"out", OPT_OUT, '>', "Output file"}, ++ {"nocrl", OPT_NOCRL, '-', "No crl to load, just certs from '-certfile'"}, ++ {"certfile", OPT_CERTFILE, '<', ++ "File of chain of certs to a trusted CA; can be repeated"}, ++ {NULL} ++}; ++ ++int crl2pkcs7_main(int argc, char **argv) ++{ ++ BIO *in = NULL, *out = NULL; ++ PKCS7 *p7 = NULL; ++ PKCS7_SIGNED *p7s = NULL; ++ STACK_OF(OPENSSL_STRING) *certflst = NULL; ++ STACK_OF(X509) *cert_stack = NULL; ++ STACK_OF(X509_CRL) *crl_stack = NULL; ++ X509_CRL *crl = NULL; ++ char *infile = NULL, *outfile = NULL, *prog, *certfile; ++ int i = 0, informat = FORMAT_PEM, outformat = FORMAT_PEM, ret = 1, nocrl = ++ 0; ++ OPTION_CHOICE o; ++ ++ prog = opt_init(argc, argv, crl2pkcs7_options); ++ while ((o = opt_next()) != OPT_EOF) { ++ switch (o) { ++ case OPT_EOF: ++ case OPT_ERR: ++ opthelp: ++ BIO_printf(bio_err, "%s: Use -help for summary.\n", prog); ++ goto end; ++ case OPT_HELP: ++ opt_help(crl2pkcs7_options); ++ ret = 0; ++ goto end; ++ case OPT_INFORM: ++ if (!opt_format(opt_arg(), OPT_FMT_PEMDER, &informat)) ++ goto opthelp; ++ break; ++ case OPT_OUTFORM: ++ if (!opt_format(opt_arg(), OPT_FMT_PEMDER, &outformat)) ++ goto opthelp; ++ break; ++ case OPT_IN: ++ infile = opt_arg(); ++ break; ++ case OPT_OUT: ++ outfile = opt_arg(); ++ break; ++ case OPT_NOCRL: ++ nocrl = 1; ++ break; ++ case OPT_CERTFILE: ++ if ((certflst == NULL) ++ && (certflst = sk_OPENSSL_STRING_new_null()) == NULL) ++ goto end; ++ if (!sk_OPENSSL_STRING_push(certflst, opt_arg())) ++ goto end; ++ break; ++ } ++ } ++ argc = opt_num_rest(); ++ if (argc != 0) ++ goto opthelp; ++ ++ if (!nocrl) { ++ in = bio_open_default(infile, 'r', informat); ++ if (in == NULL) ++ goto end; ++ ++ if (informat == FORMAT_ASN1) ++ crl = d2i_X509_CRL_bio(in, NULL); ++ else if (informat == FORMAT_PEM) ++ crl = PEM_read_bio_X509_CRL(in, NULL, NULL, NULL); ++ if (crl == NULL) { ++ BIO_printf(bio_err, "unable to load CRL\n"); ++ ERR_print_errors(bio_err); ++ goto end; ++ } ++ } ++ ++ if ((p7 = PKCS7_new()) == NULL) ++ goto end; ++ if ((p7s = PKCS7_SIGNED_new()) == NULL) ++ goto end; ++ p7->type = OBJ_nid2obj(NID_pkcs7_signed); ++ p7->d.sign = p7s; ++ p7s->contents->type = OBJ_nid2obj(NID_pkcs7_data); ++ ++ if (!ASN1_INTEGER_set(p7s->version, 1)) ++ goto end; ++ if ((crl_stack = sk_X509_CRL_new_null()) == NULL) ++ goto end; ++ p7s->crl = crl_stack; ++ if (crl != NULL) { ++ sk_X509_CRL_push(crl_stack, crl); ++ crl = NULL; /* now part of p7 for OPENSSL_freeing */ ++ } ++ ++ if ((cert_stack = sk_X509_new_null()) == NULL) ++ goto end; ++ p7s->cert = cert_stack; ++ ++ if (certflst) ++ for (i = 0; i < sk_OPENSSL_STRING_num(certflst); i++) { ++ certfile = sk_OPENSSL_STRING_value(certflst, i); ++ if (add_certs_from_file(cert_stack, certfile) < 0) { ++ BIO_printf(bio_err, "error loading certificates\n"); ++ ERR_print_errors(bio_err); ++ goto end; ++ } ++ } ++ ++ out = bio_open_default(outfile, 'w', outformat); ++ if (out == NULL) ++ goto end; ++ ++ if (outformat == FORMAT_ASN1) ++ i = i2d_PKCS7_bio(out, p7); ++ else if (outformat == FORMAT_PEM) ++ i = PEM_write_bio_PKCS7(out, p7); ++ if (!i) { ++ BIO_printf(bio_err, "unable to write pkcs7 object\n"); ++ ERR_print_errors(bio_err); ++ goto end; ++ } ++ ret = 0; ++ end: ++ sk_OPENSSL_STRING_free(certflst); ++ BIO_free(in); ++ BIO_free_all(out); ++ PKCS7_free(p7); ++ X509_CRL_free(crl); ++ ++ return (ret); ++} ++ ++/*- ++ *---------------------------------------------------------------------- ++ * int add_certs_from_file ++ * ++ * Read a list of certificates to be checked from a file. ++ * ++ * Results: ++ * number of certs added if successful, -1 if not. ++ *---------------------------------------------------------------------- ++ */ ++static int add_certs_from_file(STACK_OF(X509) *stack, char *certfile) ++{ ++ BIO *in = NULL; ++ int count = 0; ++ int ret = -1; ++ STACK_OF(X509_INFO) *sk = NULL; ++ X509_INFO *xi; ++ ++ in = BIO_new_file(certfile, "r"); ++ if (in == NULL) { ++ BIO_printf(bio_err, "error opening the file, %s\n", certfile); ++ goto end; ++ } ++ ++ /* This loads from a file, a stack of x509/crl/pkey sets */ ++ sk = PEM_X509_INFO_read_bio(in, NULL, NULL, NULL); ++ if (sk == NULL) { ++ BIO_printf(bio_err, "error reading the file, %s\n", certfile); ++ goto end; ++ } ++ ++ /* scan over it and pull out the CRL's */ ++ while (sk_X509_INFO_num(sk)) { ++ xi = sk_X509_INFO_shift(sk); ++ if (xi->x509 != NULL) { ++ sk_X509_push(stack, xi->x509); ++ xi->x509 = NULL; ++ count++; ++ } ++ X509_INFO_free(xi); ++ } ++ ++ ret = count; ++ end: ++ /* never need to OPENSSL_free x */ ++ BIO_free(in); ++ sk_X509_INFO_free(sk); ++ return (ret); ++} +diff --git a/CryptoPkg/Library/OpensslLib/openssl/apps/ct_log_list.cnf b/CryptoPkg/Library/OpensslLib/openssl/apps/ct_log_list.cnf +new file mode 100644 +index 0000000..2434874 +--- /dev/null ++++ b/CryptoPkg/Library/OpensslLib/openssl/apps/ct_log_list.cnf +@@ -0,0 +1,34 @@ ++enabled_logs=pilot,aviator,rocketeer,digicert,certly,izempe,symantec,venafi ++ ++[pilot] ++description = Google Pilot Log ++key = MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEfahLEimAoz2t01p3uMziiLOl/fHTDM0YDOhBRuiBARsV4UvxG2LdNgoIGLrtCzWE0J5APC2em4JlvR8EEEFMoA== ++ ++[aviator] ++description = Google Aviator log ++key = MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE1/TMabLkDpCjiupacAlP7xNi0I1JYP8bQFAHDG1xhtolSY1l4QgNRzRrvSe8liE+NPWHdjGxfx3JhTsN9x8/6Q== ++ ++[rocketeer] ++description = Google Rocketeer log ++key = MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEIFsYyDzBi7MxCAC/oJBXK7dHjG+1aLCOkHjpoHPqTyghLpzA9BYbqvnV16mAw04vUjyYASVGJCUoI3ctBcJAeg== ++ ++[digicert] ++description = DigiCert Log Server ++key = MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEAkbFvhu7gkAW6MHSrBlpE1n4+HCFRkC5OLAjgqhkTH+/uzSfSl8ois8ZxAD2NgaTZe1M9akhYlrYkes4JECs6A== ++ ++[certly] ++description = Certly.IO log ++key = MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAECyPLhWKYYUgEc+tUXfPQB4wtGS2MNvXrjwFCCnyYJifBtd2Sk7Cu+Js9DNhMTh35FftHaHu6ZrclnNBKwmbbSA== ++ ++[izempe] ++description = Izempe log ++key = MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEJ2Q5DC3cUBj4IQCiDu0s6j51up+TZAkAEcQRF6tczw90rLWXkJMAW7jr9yc92bIKgV8vDXU4lDeZHvYHduDuvg== ++ ++[symantec] ++description = Symantec log ++key = MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEluqsHEYMG1XcDfy1lCdGV0JwOmkY4r87xNuroPS2bMBTP01CEDPwWJePa75y9CrsHEKqAy8afig1dpkIPSEUhg== ++ ++[venafi] ++description = Venafi log ++key = MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAolpIHxdSlTXLo1s6H1OCdpSj/4DyHDc8wLG9wVmLqy1lk9fz4ATVmm+/1iN2Nk8jmctUKK2MFUtlWXZBSpym97M7frGlSaQXUWyA3CqQUEuIJOmlEjKTBEiQAvpfDjCHjlV2Be4qTM6jamkJbiWtgnYPhJL6ONaGTiSPm7Byy57iaz/hbckldSOIoRhYBiMzeNoA0DiRZ9KmfSeXZ1rB8y8X5urSW+iBzf2SaOfzBvDpcoTuAaWx2DPazoOl28fP1hZ+kHUYvxbcMjttjauCFx+JII0dmuZNIwjfeG/GBb9frpSX219k1O4Wi6OEbHEr8at/XQ0y7gTikOxBn/s5wQIDAQAB ++ +diff --git a/CryptoPkg/Library/OpensslLib/openssl/apps/demoCA/cacert.pem b/CryptoPkg/Library/OpensslLib/openssl/apps/demoCA/cacert.pem +new file mode 100644 +index 0000000..affbce3 +--- /dev/null ++++ b/CryptoPkg/Library/OpensslLib/openssl/apps/demoCA/cacert.pem +@@ -0,0 +1,14 @@ ++subject=/C=AU/SOP=QLD/O=Mincom Pty. Ltd./OU=CS/CN=SSLeay demo server ++issuer= /C=AU/SOP=QLD/O=Mincom Pty. Ltd./OU=CS/CN=CA ++-----BEGIN X509 CERTIFICATE----- ++ ++MIIBgjCCASwCAQQwDQYJKoZIhvcNAQEEBQAwODELMAkGA1UEBhMCQVUxDDAKBgNV ++BAgTA1FMRDEbMBkGA1UEAxMSU1NMZWF5L3JzYSB0ZXN0IENBMB4XDTk1MTAwOTIz ++MzIwNVoXDTk4MDcwNTIzMzIwNVowYDELMAkGA1UEBhMCQVUxDDAKBgNVBAgTA1FM ++RDEZMBcGA1UEChMQTWluY29tIFB0eS4gTHRkLjELMAkGA1UECxMCQ1MxGzAZBgNV ++BAMTElNTTGVheSBkZW1vIHNlcnZlcjBcMA0GCSqGSIb3DQEBAQUAA0sAMEgCQQC3 ++LCXcScWua0PFLkHBLm2VejqpA1F4RQ8q0VjRiPafjx/Z/aWH3ipdMVvuJGa/wFXb ++/nDFLDlfWp+oCPwhBtVPAgMBAAEwDQYJKoZIhvcNAQEEBQADQQArNFsihWIjBzb0 ++DCsU0BvL2bvSwJrPEqFlkDq3F4M6EGutL9axEcANWgbbEdAvNJD1dmEmoWny27Pn ++IMs6ZOZB ++-----END X509 CERTIFICATE----- +diff --git a/CryptoPkg/Library/OpensslLib/openssl/apps/demoCA/index.txt b/CryptoPkg/Library/OpensslLib/openssl/apps/demoCA/index.txt +new file mode 100644 +index 0000000..2cdd252 +--- /dev/null ++++ b/CryptoPkg/Library/OpensslLib/openssl/apps/demoCA/index.txt +@@ -0,0 +1,39 @@ ++R 980705233205Z 951009233205Z 01 certs/00000001 /CN=Eric Young ++E 951009233205Z 02 certs/00000002 /CN=Duncan Young ++R 980705233205Z 951201010000Z 03 certs/00000003 /CN=Tim Hudson ++V 980705233205Z 04 certs/00000004 /CN=Eric Young4 ++V 980705233205Z 05 certs/00000004 /CN=Eric Young5 ++V 980705233205Z 06 certs/00000004 /CN=Eric Young6 ++V 980705233205Z 07 certs/00000004 /CN=Eric Young7 ++V 980705233205Z 08 certs/00000004 /CN=Eric Young8 ++V 980705233205Z 09 certs/00000004 /CN=Eric Young9 ++V 980705233205Z 0A certs/00000004 /CN=Eric YoungA ++V 980705233205Z 0B certs/00000004 /CN=Eric YoungB ++V 980705233205Z 0C certs/00000004 /CN=Eric YoungC ++V 980705233205Z 0D certs/00000004 /CN=Eric YoungD ++V 980705233205Z 0E certs/00000004 /CN=Eric YoungE ++V 980705233205Z 0F certs/00000004 /CN=Eric YoungF ++V 980705233205Z 10 certs/00000004 /CN=Eric Young10 ++V 980705233205Z 11 certs/00000004 /CN=Eric Young11 ++V 980705233205Z 12 certs/00000004 /CN=Eric Young12 ++V 980705233205Z 13 certs/00000004 /CN=Eric Young13 ++V 980705233205Z 14 certs/00000004 /CN=Eric Young14 ++V 980705233205Z 15 certs/00000004 /CN=Eric Young15 ++V 980705233205Z 16 certs/00000004 /CN=Eric Young16 ++V 980705233205Z 17 certs/00000004 /CN=Eric Young17 ++V 961206150305Z 010C unknown /C=AU/SP=QLD/O=Mincom Pty. Ltd./OU=MTR/CN=Eric Young/Email=eay@mincom.oz.au ++V 961206153245Z 010D unknown /C=AU/SP=Queensland/O=Mincom Pty Ltd/OU=MTR/CN=Eric Young/Email=eay@mincom.oz.au ++V 970322074816Z 010E unknown /CN=Eric Young/Email=eay@mincom.oz.au ++V 970322075152Z 010F unknown /CN=Eric Young ++V 970322075906Z 0110 unknown /CN=Eric Youngg ++V 970324092238Z 0111 unknown /C=AU/SP=Queensland/CN=Eric Young ++V 970324221931Z 0112 unknown /CN=Fred ++V 970324224934Z 0113 unknown /C=AU/CN=eay ++V 971001005237Z 0114 unknown /C=AU/SP=QLD/O=Mincom Pty Ltd/OU=MTR/CN=x509v3 test ++V 971001010331Z 0115 unknown /C=AU/SP=Queensland/O=Mincom Pty Ltd/OU=MTR/CN=test again - x509v3 ++V 971001013945Z 0117 unknown /C=AU/SP=Queensland/O=Mincom Pty Ltd/OU=MTR/CN=x509v3 test ++V 971014225415Z 0118 unknown /C=AU/SP=Queensland/CN=test ++V 971015004448Z 0119 unknown /C=AU/SP=Queensland/O=Mincom Pty Ltd/OU=MTR/CN=test2 ++V 971016035001Z 011A unknown /C=AU/SP=Queensland/O=Mincom Pty Ltd/OU=MTR/CN=test64 ++V 971016080129Z 011B unknown /C=FR/O=ALCATEL/OU=Alcatel Mobile Phones/CN=bourque/Email=bourque@art.alcatel.fr ++V 971016224000Z 011D unknown /L=Bedford/O=Cranfield University/OU=Computer Centre/CN=Peter R Lister/Email=P.Lister@cranfield.ac.uk +diff --git a/CryptoPkg/Library/OpensslLib/openssl/apps/demoCA/private/cakey.pem b/CryptoPkg/Library/OpensslLib/openssl/apps/demoCA/private/cakey.pem +new file mode 100644 +index 0000000..48fb18c +--- /dev/null ++++ b/CryptoPkg/Library/OpensslLib/openssl/apps/demoCA/private/cakey.pem +@@ -0,0 +1,24 @@ ++issuer= /C=AU/SOP=QLD/O=Mincom Pty. Ltd./OU=CS/CN=CA ++subject=/C=AU/SOP=QLD/O=Mincom Pty. Ltd./OU=CS/CN=SSLeay demo server ++-----BEGIN X509 CERTIFICATE----- ++ ++MIIBgjCCASwCAQQwDQYJKoZIhvcNAQEEBQAwODELMAkGA1UEBhMCQVUxDDAKBgNV ++BAgTA1FMRDEbMBkGA1UEAxMSU1NMZWF5L3JzYSB0ZXN0IENBMB4XDTk1MTAwOTIz ++MzIwNVoXDTk4MDcwNTIzMzIwNVowYDELMAkGA1UEBhMCQVUxDDAKBgNVBAgTA1FM ++RDEZMBcGA1UEChMQTWluY29tIFB0eS4gTHRkLjELMAkGA1UECxMCQ1MxGzAZBgNV ++BAMTElNTTGVheSBkZW1vIHNlcnZlcjBcMA0GCSqGSIb3DQEBAQUAA0sAMEgCQQC3 ++LCXcScWua0PFLkHBLm2VejqpA1F4RQ8q0VjRiPafjx/Z/aWH3ipdMVvuJGa/wFXb ++/nDFLDlfWp+oCPwhBtVPAgMBAAEwDQYJKoZIhvcNAQEEBQADQQArNFsihWIjBzb0 ++DCsU0BvL2bvSwJrPEqFlkDq3F4M6EGutL9axEcANWgbbEdAvNJD1dmEmoWny27Pn ++IMs6ZOZB ++-----END X509 CERTIFICATE----- ++-----BEGIN RSA PRIVATE KEY----- ++ ++MIIBPAIBAAJBALcsJdxJxa5rQ8UuQcEubZV6OqkDUXhFDyrRWNGI9p+PH9n9pYfe ++Kl0xW+4kZr/AVdv+cMUsOV9an6gI/CEG1U8CAwEAAQJAXJMBZ34ZXHd1vtgL/3hZ ++hexKbVTx/djZO4imXO/dxPGRzG2ylYZpHmG32/T1kaHpZlCHoEPgHoSzmxYXfxjG ++sQIhAPmZ/bQOjmRUHM/VM2X5zrjjM6z18R1P6l3ObFwt9FGdAiEAu943Yh9SqMRw ++tL0xHGxKmM/YJueUw1gB6sLkETN71NsCIQCeT3RhoqXfrpXDoEcEU+gwzjI1bpxq ++agiNTOLfqGoA5QIhAIQFYjgzONxex7FLrsKBm16N2SFl5pXsN9SpRqqL2n63AiEA ++g9VNIQ3xwpw7og3IbONifeku+J9qGMGQJMKwSTwrFtI= ++-----END RSA PRIVATE KEY----- +diff --git a/CryptoPkg/Library/OpensslLib/openssl/apps/demoCA/serial b/CryptoPkg/Library/OpensslLib/openssl/apps/demoCA/serial +new file mode 100644 +index 0000000..69fa0ff +--- /dev/null ++++ b/CryptoPkg/Library/OpensslLib/openssl/apps/demoCA/serial +@@ -0,0 +1 @@ ++011E +diff --git a/CryptoPkg/Library/OpensslLib/openssl/apps/demoSRP/srp_verifier.txt b/CryptoPkg/Library/OpensslLib/openssl/apps/demoSRP/srp_verifier.txt +new file mode 100644 +index 0000000..ccae629 +--- /dev/null ++++ b/CryptoPkg/Library/OpensslLib/openssl/apps/demoSRP/srp_verifier.txt +@@ -0,0 +1,6 @@ ++# This is a file that will be filled by the openssl srp routine. ++# You can initialize the file with additional groups, these are ++# records starting with a I followed by the g and N values and the id. ++# The exact values ... you have to dig this out from the source of srp.c ++# or srp_vfy.c ++# The last value of an I is used as the default group for new users. +diff --git a/CryptoPkg/Library/OpensslLib/openssl/apps/demoSRP/srp_verifier.txt.attr b/CryptoPkg/Library/OpensslLib/openssl/apps/demoSRP/srp_verifier.txt.attr +new file mode 100644 +index 0000000..8f7e63a +--- /dev/null ++++ b/CryptoPkg/Library/OpensslLib/openssl/apps/demoSRP/srp_verifier.txt.attr +@@ -0,0 +1 @@ ++unique_subject = yes +diff --git a/CryptoPkg/Library/OpensslLib/openssl/apps/dgst.c b/CryptoPkg/Library/OpensslLib/openssl/apps/dgst.c +new file mode 100644 +index 0000000..08182e2 +--- /dev/null ++++ b/CryptoPkg/Library/OpensslLib/openssl/apps/dgst.c +@@ -0,0 +1,480 @@ ++/* ++ * Copyright 1995-2016 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 ++ * in the file LICENSE in the source distribution or at ++ * https://www.openssl.org/source/license.html ++ */ ++ ++#include ++#include ++#include ++#include "apps.h" ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#undef BUFSIZE ++#define BUFSIZE 1024*8 ++ ++int do_fp(BIO *out, unsigned char *buf, BIO *bp, int sep, int binout, ++ EVP_PKEY *key, unsigned char *sigin, int siglen, ++ const char *sig_name, const char *md_name, ++ const char *file); ++ ++typedef enum OPTION_choice { ++ OPT_ERR = -1, OPT_EOF = 0, OPT_HELP, ++ OPT_C, OPT_R, OPT_RAND, OPT_OUT, OPT_SIGN, OPT_PASSIN, OPT_VERIFY, ++ OPT_PRVERIFY, OPT_SIGNATURE, OPT_KEYFORM, OPT_ENGINE, OPT_ENGINE_IMPL, ++ OPT_HEX, OPT_BINARY, OPT_DEBUG, OPT_FIPS_FINGERPRINT, ++ OPT_HMAC, OPT_MAC, OPT_SIGOPT, OPT_MACOPT, ++ OPT_DIGEST ++} OPTION_CHOICE; ++ ++OPTIONS dgst_options[] = { ++ {OPT_HELP_STR, 1, '-', "Usage: %s [options] [file...]\n"}, ++ {OPT_HELP_STR, 1, '-', ++ " file... files to digest (default is stdin)\n"}, ++ {"help", OPT_HELP, '-', "Display this summary"}, ++ {"c", OPT_C, '-', "Print the digest with separating colons"}, ++ {"r", OPT_R, '-', "Print the digest in coreutils format"}, ++ {"rand", OPT_RAND, 's', ++ "Use file(s) containing random data to seed RNG or an EGD sock"}, ++ {"out", OPT_OUT, '>', "Output to filename rather than stdout"}, ++ {"passin", OPT_PASSIN, 's', "Input file pass phrase source"}, ++ {"sign", OPT_SIGN, 's', "Sign digest using private key"}, ++ {"verify", OPT_VERIFY, 's', ++ "Verify a signature using public key"}, ++ {"prverify", OPT_PRVERIFY, 's', ++ "Verify a signature using private key"}, ++ {"signature", OPT_SIGNATURE, '<', "File with signature to verify"}, ++ {"keyform", OPT_KEYFORM, 'f', "Key file format (PEM or ENGINE)"}, ++ {"hex", OPT_HEX, '-', "Print as hex dump"}, ++ {"binary", OPT_BINARY, '-', "Print in binary form"}, ++ {"d", OPT_DEBUG, '-', "Print debug info"}, ++ {"debug", OPT_DEBUG, '-', "Print debug info"}, ++ {"fips-fingerprint", OPT_FIPS_FINGERPRINT, '-', ++ "Compute HMAC with the key used in OpenSSL-FIPS fingerprint"}, ++ {"hmac", OPT_HMAC, 's', "Create hashed MAC with key"}, ++ {"mac", OPT_MAC, 's', "Create MAC (not necessarily HMAC)"}, ++ {"sigopt", OPT_SIGOPT, 's', "Signature parameter in n:v form"}, ++ {"macopt", OPT_MACOPT, 's', "MAC algorithm parameters in n:v form or key"}, ++ {"", OPT_DIGEST, '-', "Any supported digest"}, ++#ifndef OPENSSL_NO_ENGINE ++ {"engine", OPT_ENGINE, 's', "Use engine e, possibly a hardware device"}, ++ {"engine_impl", OPT_ENGINE_IMPL, '-', ++ "Also use engine given by -engine for digest operations"}, ++#endif ++ {NULL} ++}; ++ ++int dgst_main(int argc, char **argv) ++{ ++ BIO *in = NULL, *inp, *bmd = NULL, *out = NULL; ++ ENGINE *e = NULL, *impl = NULL; ++ EVP_PKEY *sigkey = NULL; ++ STACK_OF(OPENSSL_STRING) *sigopts = NULL, *macopts = NULL; ++ char *hmac_key = NULL; ++ char *mac_name = NULL; ++ char *passinarg = NULL, *passin = NULL; ++ const EVP_MD *md = NULL, *m; ++ const char *outfile = NULL, *keyfile = NULL, *prog = NULL; ++ const char *sigfile = NULL, *randfile = NULL; ++ OPTION_CHOICE o; ++ int separator = 0, debug = 0, keyform = FORMAT_PEM, siglen = 0; ++ int i, ret = 1, out_bin = -1, want_pub = 0, do_verify = 0; ++ unsigned char *buf = NULL, *sigbuf = NULL; ++ int engine_impl = 0; ++ ++ prog = opt_progname(argv[0]); ++ buf = app_malloc(BUFSIZE, "I/O buffer"); ++ md = EVP_get_digestbyname(prog); ++ ++ prog = opt_init(argc, argv, dgst_options); ++ while ((o = opt_next()) != OPT_EOF) { ++ switch (o) { ++ case OPT_EOF: ++ case OPT_ERR: ++ opthelp: ++ BIO_printf(bio_err, "%s: Use -help for summary.\n", prog); ++ goto end; ++ case OPT_HELP: ++ opt_help(dgst_options); ++ ret = 0; ++ goto end; ++ case OPT_C: ++ separator = 1; ++ break; ++ case OPT_R: ++ separator = 2; ++ break; ++ case OPT_RAND: ++ randfile = opt_arg(); ++ break; ++ case OPT_OUT: ++ outfile = opt_arg(); ++ break; ++ case OPT_SIGN: ++ keyfile = opt_arg(); ++ break; ++ case OPT_PASSIN: ++ passinarg = opt_arg(); ++ break; ++ case OPT_VERIFY: ++ keyfile = opt_arg(); ++ want_pub = do_verify = 1; ++ break; ++ case OPT_PRVERIFY: ++ keyfile = opt_arg(); ++ do_verify = 1; ++ break; ++ case OPT_SIGNATURE: ++ sigfile = opt_arg(); ++ break; ++ case OPT_KEYFORM: ++ if (!opt_format(opt_arg(), OPT_FMT_ANY, &keyform)) ++ goto opthelp; ++ break; ++ case OPT_ENGINE: ++ e = setup_engine(opt_arg(), 0); ++ break; ++ case OPT_ENGINE_IMPL: ++ engine_impl = 1; ++ break; ++ case OPT_HEX: ++ out_bin = 0; ++ break; ++ case OPT_BINARY: ++ out_bin = 1; ++ break; ++ case OPT_DEBUG: ++ debug = 1; ++ break; ++ case OPT_FIPS_FINGERPRINT: ++ hmac_key = "etaonrishdlcupfm"; ++ break; ++ case OPT_HMAC: ++ hmac_key = opt_arg(); ++ break; ++ case OPT_MAC: ++ mac_name = opt_arg(); ++ break; ++ case OPT_SIGOPT: ++ if (!sigopts) ++ sigopts = sk_OPENSSL_STRING_new_null(); ++ if (!sigopts || !sk_OPENSSL_STRING_push(sigopts, opt_arg())) ++ goto opthelp; ++ break; ++ case OPT_MACOPT: ++ if (!macopts) ++ macopts = sk_OPENSSL_STRING_new_null(); ++ if (!macopts || !sk_OPENSSL_STRING_push(macopts, opt_arg())) ++ goto opthelp; ++ break; ++ case OPT_DIGEST: ++ if (!opt_md(opt_unknown(), &m)) ++ goto opthelp; ++ md = m; ++ break; ++ } ++ } ++ argc = opt_num_rest(); ++ argv = opt_rest(); ++ if (keyfile != NULL && argc > 1) { ++ BIO_printf(bio_err, "%s: Can only sign or verify one file.\n", prog); ++ goto end; ++ } ++ ++ if (do_verify && !sigfile) { ++ BIO_printf(bio_err, ++ "No signature to verify: use the -signature option\n"); ++ goto end; ++ } ++ if (engine_impl) ++ impl = e; ++ ++ in = BIO_new(BIO_s_file()); ++ bmd = BIO_new(BIO_f_md()); ++ if ((in == NULL) || (bmd == NULL)) { ++ ERR_print_errors(bio_err); ++ goto end; ++ } ++ ++ if (debug) { ++ BIO_set_callback(in, BIO_debug_callback); ++ /* needed for windows 3.1 */ ++ BIO_set_callback_arg(in, (char *)bio_err); ++ } ++ ++ if (!app_passwd(passinarg, NULL, &passin, NULL)) { ++ BIO_printf(bio_err, "Error getting password\n"); ++ goto end; ++ } ++ ++ if (out_bin == -1) { ++ if (keyfile) ++ out_bin = 1; ++ else ++ out_bin = 0; ++ } ++ ++ if (randfile) ++ app_RAND_load_file(randfile, 0); ++ ++ out = bio_open_default(outfile, 'w', out_bin ? FORMAT_BINARY : FORMAT_TEXT); ++ if (out == NULL) ++ goto end; ++ ++ if ((! !mac_name + ! !keyfile + ! !hmac_key) > 1) { ++ BIO_printf(bio_err, "MAC and Signing key cannot both be specified\n"); ++ goto end; ++ } ++ ++ if (keyfile) { ++ if (want_pub) ++ sigkey = load_pubkey(keyfile, keyform, 0, NULL, e, "key file"); ++ else ++ sigkey = load_key(keyfile, keyform, 0, passin, e, "key file"); ++ if (!sigkey) { ++ /* ++ * load_[pub]key() has already printed an appropriate message ++ */ ++ goto end; ++ } ++ } ++ ++ if (mac_name) { ++ EVP_PKEY_CTX *mac_ctx = NULL; ++ int r = 0; ++ if (!init_gen_str(&mac_ctx, mac_name, impl, 0)) ++ goto mac_end; ++ if (macopts) { ++ char *macopt; ++ for (i = 0; i < sk_OPENSSL_STRING_num(macopts); i++) { ++ macopt = sk_OPENSSL_STRING_value(macopts, i); ++ if (pkey_ctrl_string(mac_ctx, macopt) <= 0) { ++ BIO_printf(bio_err, ++ "MAC parameter error \"%s\"\n", macopt); ++ ERR_print_errors(bio_err); ++ goto mac_end; ++ } ++ } ++ } ++ if (EVP_PKEY_keygen(mac_ctx, &sigkey) <= 0) { ++ BIO_puts(bio_err, "Error generating key\n"); ++ ERR_print_errors(bio_err); ++ goto mac_end; ++ } ++ r = 1; ++ mac_end: ++ EVP_PKEY_CTX_free(mac_ctx); ++ if (r == 0) ++ goto end; ++ } ++ ++ if (hmac_key) { ++ sigkey = EVP_PKEY_new_mac_key(EVP_PKEY_HMAC, impl, ++ (unsigned char *)hmac_key, -1); ++ if (!sigkey) ++ goto end; ++ } ++ ++ if (sigkey) { ++ EVP_MD_CTX *mctx = NULL; ++ EVP_PKEY_CTX *pctx = NULL; ++ int r; ++ if (!BIO_get_md_ctx(bmd, &mctx)) { ++ BIO_printf(bio_err, "Error getting context\n"); ++ ERR_print_errors(bio_err); ++ goto end; ++ } ++ if (do_verify) ++ r = EVP_DigestVerifyInit(mctx, &pctx, md, impl, sigkey); ++ else ++ r = EVP_DigestSignInit(mctx, &pctx, md, impl, sigkey); ++ if (!r) { ++ BIO_printf(bio_err, "Error setting context\n"); ++ ERR_print_errors(bio_err); ++ goto end; ++ } ++ if (sigopts) { ++ char *sigopt; ++ for (i = 0; i < sk_OPENSSL_STRING_num(sigopts); i++) { ++ sigopt = sk_OPENSSL_STRING_value(sigopts, i); ++ if (pkey_ctrl_string(pctx, sigopt) <= 0) { ++ BIO_printf(bio_err, "parameter error \"%s\"\n", sigopt); ++ ERR_print_errors(bio_err); ++ goto end; ++ } ++ } ++ } ++ } ++ /* we use md as a filter, reading from 'in' */ ++ else { ++ EVP_MD_CTX *mctx = NULL; ++ if (!BIO_get_md_ctx(bmd, &mctx)) { ++ BIO_printf(bio_err, "Error getting context\n"); ++ ERR_print_errors(bio_err); ++ goto end; ++ } ++ if (md == NULL) ++ md = EVP_sha256(); ++ if (!EVP_DigestInit_ex(mctx, md, impl)) { ++ BIO_printf(bio_err, "Error setting digest\n"); ++ ERR_print_errors(bio_err); ++ goto end; ++ } ++ } ++ ++ if (sigfile && sigkey) { ++ BIO *sigbio = BIO_new_file(sigfile, "rb"); ++ if (!sigbio) { ++ BIO_printf(bio_err, "Error opening signature file %s\n", sigfile); ++ ERR_print_errors(bio_err); ++ goto end; ++ } ++ siglen = EVP_PKEY_size(sigkey); ++ sigbuf = app_malloc(siglen, "signature buffer"); ++ siglen = BIO_read(sigbio, sigbuf, siglen); ++ BIO_free(sigbio); ++ if (siglen <= 0) { ++ BIO_printf(bio_err, "Error reading signature file %s\n", sigfile); ++ ERR_print_errors(bio_err); ++ goto end; ++ } ++ } ++ inp = BIO_push(bmd, in); ++ ++ if (md == NULL) { ++ EVP_MD_CTX *tctx; ++ BIO_get_md_ctx(bmd, &tctx); ++ md = EVP_MD_CTX_md(tctx); ++ } ++ ++ if (argc == 0) { ++ BIO_set_fp(in, stdin, BIO_NOCLOSE); ++ ret = do_fp(out, buf, inp, separator, out_bin, sigkey, sigbuf, ++ siglen, NULL, NULL, "stdin"); ++ } else { ++ const char *md_name = NULL, *sig_name = NULL; ++ if (!out_bin) { ++ if (sigkey) { ++ const EVP_PKEY_ASN1_METHOD *ameth; ++ ameth = EVP_PKEY_get0_asn1(sigkey); ++ if (ameth) ++ EVP_PKEY_asn1_get0_info(NULL, NULL, ++ NULL, NULL, &sig_name, ameth); ++ } ++ if (md) ++ md_name = EVP_MD_name(md); ++ } ++ ret = 0; ++ for (i = 0; i < argc; i++) { ++ int r; ++ if (BIO_read_filename(in, argv[i]) <= 0) { ++ perror(argv[i]); ++ ret++; ++ continue; ++ } else ++ r = do_fp(out, buf, inp, separator, out_bin, sigkey, sigbuf, ++ siglen, sig_name, md_name, argv[i]); ++ if (r) ++ ret = r; ++ (void)BIO_reset(bmd); ++ } ++ } ++ end: ++ OPENSSL_clear_free(buf, BUFSIZE); ++ BIO_free(in); ++ OPENSSL_free(passin); ++ BIO_free_all(out); ++ EVP_PKEY_free(sigkey); ++ sk_OPENSSL_STRING_free(sigopts); ++ sk_OPENSSL_STRING_free(macopts); ++ OPENSSL_free(sigbuf); ++ BIO_free(bmd); ++ release_engine(e); ++ return (ret); ++} ++ ++int do_fp(BIO *out, unsigned char *buf, BIO *bp, int sep, int binout, ++ EVP_PKEY *key, unsigned char *sigin, int siglen, ++ const char *sig_name, const char *md_name, ++ const char *file) ++{ ++ size_t len; ++ int i; ++ ++ for (;;) { ++ i = BIO_read(bp, (char *)buf, BUFSIZE); ++ if (i < 0) { ++ BIO_printf(bio_err, "Read Error in %s\n", file); ++ ERR_print_errors(bio_err); ++ return 1; ++ } ++ if (i == 0) ++ break; ++ } ++ if (sigin) { ++ EVP_MD_CTX *ctx; ++ BIO_get_md_ctx(bp, &ctx); ++ i = EVP_DigestVerifyFinal(ctx, sigin, (unsigned int)siglen); ++ if (i > 0) ++ BIO_printf(out, "Verified OK\n"); ++ else if (i == 0) { ++ BIO_printf(out, "Verification Failure\n"); ++ return 1; ++ } else { ++ BIO_printf(bio_err, "Error Verifying Data\n"); ++ ERR_print_errors(bio_err); ++ return 1; ++ } ++ return 0; ++ } ++ if (key) { ++ EVP_MD_CTX *ctx; ++ BIO_get_md_ctx(bp, &ctx); ++ len = BUFSIZE; ++ if (!EVP_DigestSignFinal(ctx, buf, &len)) { ++ BIO_printf(bio_err, "Error Signing Data\n"); ++ ERR_print_errors(bio_err); ++ return 1; ++ } ++ } else { ++ len = BIO_gets(bp, (char *)buf, BUFSIZE); ++ if ((int)len < 0) { ++ ERR_print_errors(bio_err); ++ return 1; ++ } ++ } ++ ++ if (binout) ++ BIO_write(out, buf, len); ++ else if (sep == 2) { ++ for (i = 0; i < (int)len; i++) ++ BIO_printf(out, "%02x", buf[i]); ++ BIO_printf(out, " *%s\n", file); ++ } else { ++ if (sig_name) { ++ BIO_puts(out, sig_name); ++ if (md_name) ++ BIO_printf(out, "-%s", md_name); ++ BIO_printf(out, "(%s)= ", file); ++ } else if (md_name) ++ BIO_printf(out, "%s(%s)= ", md_name, file); ++ else ++ BIO_printf(out, "(%s)= ", file); ++ for (i = 0; i < (int)len; i++) { ++ if (sep && (i != 0)) ++ BIO_printf(out, ":"); ++ BIO_printf(out, "%02x", buf[i]); ++ } ++ BIO_printf(out, "\n"); ++ } ++ return 0; ++} +diff --git a/CryptoPkg/Library/OpensslLib/openssl/apps/dh1024.pem b/CryptoPkg/Library/OpensslLib/openssl/apps/dh1024.pem +new file mode 100644 +index 0000000..f1a5e18 +--- /dev/null ++++ b/CryptoPkg/Library/OpensslLib/openssl/apps/dh1024.pem +@@ -0,0 +1,10 @@ ++-----BEGIN DH PARAMETERS----- ++MIGHAoGBAP//////////yQ/aoiFowjTExmKLgNwc0SkCTgiKZ8x0Agu+pjsTmyJR ++Sgh5jjQE3e+VGbPNOkMbMCsKbfJfFDdP4TVtbVHCReSFtXZiXn7G9ExC6aY37WsL ++/1y29Aa37e44a/taiZ+lrp8kEXxLH+ZJKGZR7OZTgf//////////AgEC ++-----END DH PARAMETERS----- ++ ++These are the 1024-bit DH parameters from "Internet Key Exchange ++Protocol Version 2 (IKEv2)": https://tools.ietf.org/html/rfc5996 ++ ++See https://tools.ietf.org/html/rfc2412 for how they were generated. +diff --git a/CryptoPkg/Library/OpensslLib/openssl/apps/dh2048.pem b/CryptoPkg/Library/OpensslLib/openssl/apps/dh2048.pem +new file mode 100644 +index 0000000..e899f2e +--- /dev/null ++++ b/CryptoPkg/Library/OpensslLib/openssl/apps/dh2048.pem +@@ -0,0 +1,14 @@ ++-----BEGIN DH PARAMETERS----- ++MIIBCAKCAQEA///////////JD9qiIWjCNMTGYouA3BzRKQJOCIpnzHQCC76mOxOb ++IlFKCHmONATd75UZs806QxswKwpt8l8UN0/hNW1tUcJF5IW1dmJefsb0TELppjft ++awv/XLb0Brft7jhr+1qJn6WunyQRfEsf5kkoZlHs5Fs9wgB8uKFjvwWY2kg2HFXT ++mmkWP6j9JM9fg2VdI9yjrZYcYvNWIIVSu57VKQdwlpZtZww1Tkq8mATxdGwIyhgh ++fDKQXkYuNs474553LBgOhgObJ4Oi7Aeij7XFXfBvTFLJ3ivL9pVYFxg5lUl86pVq ++5RXSJhiY+gUQFXKOWoqsqmj//////////wIBAg== ++-----END DH PARAMETERS----- ++ ++These are the 2048-bit DH parameters from "More Modular Exponential ++(MODP) Diffie-Hellman groups for Internet Key Exchange (IKE)": ++https://tools.ietf.org/html/rfc3526 ++ ++See https://tools.ietf.org/html/rfc2412 for how they were generated. +diff --git a/CryptoPkg/Library/OpensslLib/openssl/apps/dh4096.pem b/CryptoPkg/Library/OpensslLib/openssl/apps/dh4096.pem +new file mode 100644 +index 0000000..adada2b +--- /dev/null ++++ b/CryptoPkg/Library/OpensslLib/openssl/apps/dh4096.pem +@@ -0,0 +1,19 @@ ++-----BEGIN DH PARAMETERS----- ++MIICCAKCAgEA///////////JD9qiIWjCNMTGYouA3BzRKQJOCIpnzHQCC76mOxOb ++IlFKCHmONATd75UZs806QxswKwpt8l8UN0/hNW1tUcJF5IW1dmJefsb0TELppjft ++awv/XLb0Brft7jhr+1qJn6WunyQRfEsf5kkoZlHs5Fs9wgB8uKFjvwWY2kg2HFXT ++mmkWP6j9JM9fg2VdI9yjrZYcYvNWIIVSu57VKQdwlpZtZww1Tkq8mATxdGwIyhgh ++fDKQXkYuNs474553LBgOhgObJ4Oi7Aeij7XFXfBvTFLJ3ivL9pVYFxg5lUl86pVq ++5RXSJhiY+gUQFXKOWoqqxC2tMxcNBFB6M6hVIavfHLpk7PuFBFjb7wqK6nFXXQYM ++fbOXD4Wm4eTHq/WujNsJM9cejJTgSiVhnc7j0iYa0u5r8S/6BtmKCGTYdgJzPshq ++ZFIfKxgXeyAMu+EXV3phXWx3CYjAutlG4gjiT6B05asxQ9tb/OD9EI5LgtEgqSEI ++ARpyPBKnh+bXiHGaEL26WyaZwycYavTiPBqUaDS2FQvaJYPpyirUTOjbu8LbBN6O +++S6O/BQfvsqmKHxZR05rwF2ZspZPoJDDoiM7oYZRW+ftH2EpcM7i16+4G912IXBI ++HNAGkSfVsFqpk7TqmI2P3cGG/7fckKbAj030Nck0BjGZ//////////8CAQI= ++-----END DH PARAMETERS----- ++ ++These are the 4096-bit DH parameters from "More Modular Exponential ++(MODP) Diffie-Hellman groups for Internet Key Exchange (IKE)": ++https://tools.ietf.org/html/rfc3526 ++ ++See https://tools.ietf.org/html/rfc2412 for how they were generated. +diff --git a/CryptoPkg/Library/OpensslLib/openssl/apps/dhparam.c b/CryptoPkg/Library/OpensslLib/openssl/apps/dhparam.c +new file mode 100644 +index 0000000..2223e1a +--- /dev/null ++++ b/CryptoPkg/Library/OpensslLib/openssl/apps/dhparam.c +@@ -0,0 +1,380 @@ ++/* ++ * Copyright 1995-2016 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 ++ * in the file LICENSE in the source distribution or at ++ * https://www.openssl.org/source/license.html ++ */ ++ ++#include ++#ifdef OPENSSL_NO_DH ++NON_EMPTY_TRANSLATION_UNIT ++#else ++ ++# include ++# include ++# include ++# include ++# include "apps.h" ++# include ++# include ++# include ++# include ++# include ++# include ++ ++# ifndef OPENSSL_NO_DSA ++# include ++# endif ++ ++# define DEFBITS 2048 ++ ++static int dh_cb(int p, int n, BN_GENCB *cb); ++ ++typedef enum OPTION_choice { ++ OPT_ERR = -1, OPT_EOF = 0, OPT_HELP, ++ OPT_INFORM, OPT_OUTFORM, OPT_IN, OPT_OUT, ++ OPT_ENGINE, OPT_CHECK, OPT_TEXT, OPT_NOOUT, ++ OPT_RAND, OPT_DSAPARAM, OPT_C, OPT_2, OPT_5 ++} OPTION_CHOICE; ++ ++OPTIONS dhparam_options[] = { ++ {OPT_HELP_STR, 1, '-', "Usage: %s [flags] [numbits]\n"}, ++ {OPT_HELP_STR, 1, '-', "Valid options are:\n"}, ++ {"help", OPT_HELP, '-', "Display this summary"}, ++ {"in", OPT_IN, '<', "Input file"}, ++ {"inform", OPT_INFORM, 'F', "Input format, DER or PEM"}, ++ {"outform", OPT_OUTFORM, 'F', "Output format, DER or PEM"}, ++ {"out", OPT_OUT, '>', "Output file"}, ++ {"check", OPT_CHECK, '-', "Check the DH parameters"}, ++ {"text", OPT_TEXT, '-', "Print a text form of the DH parameters"}, ++ {"noout", OPT_NOOUT, '-', "Don't output any DH parameters"}, ++ {"rand", OPT_RAND, 's', ++ "Load the file(s) into the random number generator"}, ++ {"C", OPT_C, '-', "Print C code"}, ++ {"2", OPT_2, '-', "Generate parameters using 2 as the generator value"}, ++ {"5", OPT_5, '-', "Generate parameters using 5 as the generator value"}, ++# ifndef OPENSSL_NO_DSA ++ {"dsaparam", OPT_DSAPARAM, '-', ++ "Read or generate DSA parameters, convert to DH"}, ++# endif ++# ifndef OPENSSL_NO_ENGINE ++ {"engine", OPT_ENGINE, 's', "Use engine e, possibly a hardware device"}, ++# endif ++ {NULL} ++}; ++ ++int dhparam_main(int argc, char **argv) ++{ ++ BIO *in = NULL, *out = NULL; ++ DH *dh = NULL; ++ char *infile = NULL, *outfile = NULL, *prog, *inrand = NULL; ++ ENGINE *e = NULL; ++#ifndef OPENSSL_NO_DSA ++ int dsaparam = 0; ++#endif ++ int i, text = 0, C = 0, ret = 1, num = 0, g = 0; ++ int informat = FORMAT_PEM, outformat = FORMAT_PEM, check = 0, noout = 0; ++ OPTION_CHOICE o; ++ ++ prog = opt_init(argc, argv, dhparam_options); ++ while ((o = opt_next()) != OPT_EOF) { ++ switch (o) { ++ case OPT_EOF: ++ case OPT_ERR: ++ opthelp: ++ BIO_printf(bio_err, "%s: Use -help for summary.\n", prog); ++ goto end; ++ case OPT_HELP: ++ opt_help(dhparam_options); ++ ret = 0; ++ goto end; ++ case OPT_INFORM: ++ if (!opt_format(opt_arg(), OPT_FMT_PEMDER, &informat)) ++ goto opthelp; ++ break; ++ case OPT_OUTFORM: ++ if (!opt_format(opt_arg(), OPT_FMT_PEMDER, &outformat)) ++ goto opthelp; ++ break; ++ case OPT_IN: ++ infile = opt_arg(); ++ break; ++ case OPT_OUT: ++ outfile = opt_arg(); ++ break; ++ case OPT_ENGINE: ++ e = setup_engine(opt_arg(), 0); ++ break; ++ case OPT_CHECK: ++ check = 1; ++ break; ++ case OPT_TEXT: ++ text = 1; ++ break; ++ case OPT_DSAPARAM: ++#ifndef OPENSSL_NO_DSA ++ dsaparam = 1; ++#endif ++ break; ++ case OPT_C: ++ C = 1; ++ break; ++ case OPT_2: ++ g = 2; ++ break; ++ case OPT_5: ++ g = 5; ++ break; ++ case OPT_NOOUT: ++ noout = 1; ++ break; ++ case OPT_RAND: ++ inrand = opt_arg(); ++ break; ++ } ++ } ++ argc = opt_num_rest(); ++ argv = opt_rest(); ++ ++ if (argv[0] && (!opt_int(argv[0], &num) || num <= 0)) ++ goto end; ++ ++ if (g && !num) ++ num = DEFBITS; ++ ++# ifndef OPENSSL_NO_DSA ++ if (dsaparam && g) { ++ BIO_printf(bio_err, ++ "generator may not be chosen for DSA parameters\n"); ++ goto end; ++ } ++# endif ++ /* DH parameters */ ++ if (num && !g) ++ g = 2; ++ ++ if (num) { ++ ++ BN_GENCB *cb; ++ cb = BN_GENCB_new(); ++ if (cb == NULL) { ++ ERR_print_errors(bio_err); ++ goto end; ++ } ++ ++ BN_GENCB_set(cb, dh_cb, bio_err); ++ if (!app_RAND_load_file(NULL, 1) && inrand == NULL) { ++ BIO_printf(bio_err, ++ "warning, not much extra random data, consider using the -rand option\n"); ++ } ++ if (inrand != NULL) ++ BIO_printf(bio_err, "%ld semi-random bytes loaded\n", ++ app_RAND_load_files(inrand)); ++ ++# ifndef OPENSSL_NO_DSA ++ if (dsaparam) { ++ DSA *dsa = DSA_new(); ++ ++ BIO_printf(bio_err, ++ "Generating DSA parameters, %d bit long prime\n", num); ++ if (dsa == NULL ++ || !DSA_generate_parameters_ex(dsa, num, NULL, 0, NULL, NULL, ++ cb)) { ++ DSA_free(dsa); ++ BN_GENCB_free(cb); ++ ERR_print_errors(bio_err); ++ goto end; ++ } ++ ++ dh = DSA_dup_DH(dsa); ++ DSA_free(dsa); ++ if (dh == NULL) { ++ BN_GENCB_free(cb); ++ ERR_print_errors(bio_err); ++ goto end; ++ } ++ } else ++# endif ++ { ++ dh = DH_new(); ++ BIO_printf(bio_err, ++ "Generating DH parameters, %d bit long safe prime, generator %d\n", ++ num, g); ++ BIO_printf(bio_err, "This is going to take a long time\n"); ++ if (dh == NULL || !DH_generate_parameters_ex(dh, num, g, cb)) { ++ BN_GENCB_free(cb); ++ ERR_print_errors(bio_err); ++ goto end; ++ } ++ } ++ ++ BN_GENCB_free(cb); ++ app_RAND_write_file(NULL); ++ } else { ++ ++ in = bio_open_default(infile, 'r', informat); ++ if (in == NULL) ++ goto end; ++ ++# ifndef OPENSSL_NO_DSA ++ if (dsaparam) { ++ DSA *dsa; ++ ++ if (informat == FORMAT_ASN1) ++ dsa = d2i_DSAparams_bio(in, NULL); ++ else /* informat == FORMAT_PEM */ ++ dsa = PEM_read_bio_DSAparams(in, NULL, NULL, NULL); ++ ++ if (dsa == NULL) { ++ BIO_printf(bio_err, "unable to load DSA parameters\n"); ++ ERR_print_errors(bio_err); ++ goto end; ++ } ++ ++ dh = DSA_dup_DH(dsa); ++ DSA_free(dsa); ++ if (dh == NULL) { ++ ERR_print_errors(bio_err); ++ goto end; ++ } ++ } else ++# endif ++ { ++ if (informat == FORMAT_ASN1) ++ dh = d2i_DHparams_bio(in, NULL); ++ else /* informat == FORMAT_PEM */ ++ dh = PEM_read_bio_DHparams(in, NULL, NULL, NULL); ++ ++ if (dh == NULL) { ++ BIO_printf(bio_err, "unable to load DH parameters\n"); ++ ERR_print_errors(bio_err); ++ goto end; ++ } ++ } ++ ++ /* dh != NULL */ ++ } ++ ++ out = bio_open_default(outfile, 'w', outformat); ++ if (out == NULL) ++ goto end; ++ ++ if (text) { ++ DHparams_print(out, dh); ++ } ++ ++ if (check) { ++ if (!DH_check(dh, &i)) { ++ ERR_print_errors(bio_err); ++ goto end; ++ } ++ if (i & DH_CHECK_P_NOT_PRIME) ++ BIO_printf(bio_err, "WARNING: p value is not prime\n"); ++ if (i & DH_CHECK_P_NOT_SAFE_PRIME) ++ BIO_printf(bio_err, "WARNING: p value is not a safe prime\n"); ++ if (i & DH_CHECK_Q_NOT_PRIME) ++ BIO_printf(bio_err, "WARNING: q value is not a prime\n"); ++ if (i & DH_CHECK_INVALID_Q_VALUE) ++ BIO_printf(bio_err, "WARNING: q value is invalid\n"); ++ if (i & DH_CHECK_INVALID_J_VALUE) ++ BIO_printf(bio_err, "WARNING: j value is invalid\n"); ++ if (i & DH_UNABLE_TO_CHECK_GENERATOR) ++ BIO_printf(bio_err, ++ "WARNING: unable to check the generator value\n"); ++ if (i & DH_NOT_SUITABLE_GENERATOR) ++ BIO_printf(bio_err, "WARNING: the g value is not a generator\n"); ++ if (i == 0) ++ BIO_printf(bio_err, "DH parameters appear to be ok.\n"); ++ if (num != 0 && i != 0) { ++ /* ++ * We have generated parameters but DH_check() indicates they are ++ * invalid! This should never happen! ++ */ ++ BIO_printf(bio_err, "ERROR: Invalid parameters generated\n"); ++ goto end; ++ } ++ } ++ if (C) { ++ unsigned char *data; ++ int len, bits; ++ const BIGNUM *pbn, *gbn; ++ ++ len = DH_size(dh); ++ bits = DH_bits(dh); ++ DH_get0_pqg(dh, &pbn, NULL, &gbn); ++ data = app_malloc(len, "print a BN"); ++ BIO_printf(out, "#ifndef HEADER_DH_H\n" ++ "# include \n" ++ "#endif\n" ++ "\n"); ++ BIO_printf(out, "DH *get_dh%d()\n{\n", bits); ++ print_bignum_var(out, pbn, "dhp", bits, data); ++ print_bignum_var(out, gbn, "dhg", bits, data); ++ BIO_printf(out, " DH *dh = DH_new();\n" ++ " BIGNUM *dhp_bn, *dhg_bn;\n" ++ "\n" ++ " if (dh == NULL)\n" ++ " return NULL;\n"); ++ BIO_printf(out, " dhp_bn = BN_bin2bn(dhp_%d, sizeof (dhp_%d), NULL);\n", ++ bits, bits); ++ BIO_printf(out, " dhg_bn = BN_bin2bn(dhg_%d, sizeof (dhg_%d), NULL);\n", ++ bits, bits); ++ BIO_printf(out, " if (dhp_bn == NULL || dhg_bn == NULL\n" ++ " || !DH_set0_pqg(dh, dhp_bn, NULL, dhg_bn)) {\n" ++ " DH_free(dh);\n" ++ " BN_free(dhp_bn);\n" ++ " BN_free(dhg_bn);\n" ++ " return NULL;\n" ++ " }\n"); ++ if (DH_get_length(dh) > 0) ++ BIO_printf(out, ++ " if (!DH_set_length(dh, %ld)) {\n" ++ " DH_free(dh);\n" ++ " }\n", DH_get_length(dh)); ++ BIO_printf(out, " return dh;\n}\n"); ++ OPENSSL_free(data); ++ } ++ ++ if (!noout) { ++ const BIGNUM *q; ++ DH_get0_pqg(dh, NULL, &q, NULL); ++ if (outformat == FORMAT_ASN1) ++ i = i2d_DHparams_bio(out, dh); ++ else if (q != NULL) ++ i = PEM_write_bio_DHxparams(out, dh); ++ else ++ i = PEM_write_bio_DHparams(out, dh); ++ if (!i) { ++ BIO_printf(bio_err, "unable to write DH parameters\n"); ++ ERR_print_errors(bio_err); ++ goto end; ++ } ++ } ++ ret = 0; ++ end: ++ BIO_free(in); ++ BIO_free_all(out); ++ DH_free(dh); ++ release_engine(e); ++ return (ret); ++} ++ ++static int dh_cb(int p, int n, BN_GENCB *cb) ++{ ++ char c = '*'; ++ ++ if (p == 0) ++ c = '.'; ++ if (p == 1) ++ c = '+'; ++ if (p == 2) ++ c = '*'; ++ if (p == 3) ++ c = '\n'; ++ BIO_write(BN_GENCB_get_arg(cb), &c, 1); ++ (void)BIO_flush(BN_GENCB_get_arg(cb)); ++ return 1; ++} ++#endif +diff --git a/CryptoPkg/Library/OpensslLib/openssl/apps/dsa-ca.pem b/CryptoPkg/Library/OpensslLib/openssl/apps/dsa-ca.pem +new file mode 100644 +index 0000000..3ce8dc6 +--- /dev/null ++++ b/CryptoPkg/Library/OpensslLib/openssl/apps/dsa-ca.pem +@@ -0,0 +1,47 @@ ++-----BEGIN DSA PRIVATE KEY----- ++MIIBugIBAAKBgQCnP26Fv0FqKX3wn0cZMJCaCR3aajMexT2GlrMV4FMuj+BZgnOQ ++PnUxmUd6UvuF5NmmezibaIqEm4fGHrV+hktTW1nPcWUZiG7OZq5riDb77Cjcwtel ++u+UsOSZL2ppwGJU3lRBWI/YV7boEXt45T/23Qx+1pGVvzYAR5HCVW1DNSQIVAPcH ++Me36bAYD1YWKHKycZedQZmVvAoGATd9MA6aRivUZb1BGJZnlaG8w42nh5bNdmLso ++hkj83pkEP1+IDJxzJA0gXbkqmj8YlifkYofBe3RiU/xhJ6h6kQmdtvFNnFQPWAbu ++SXQHzlV+I84W9srcWmEBfslxtU323DQph2j2XiCTs9v15AlsQReVkusBtXOlan7Y ++Mu0OArgCgYAapll6iqz9XrZFlk2GCVcB+KihxWnH7IuHvSLw9YUrJahcBHmbpvt4 ++94lF4gC5w3WPM+vXJofbusk4GoQEEsQNMDaah4m49uUqAylOVFJJJXuirVJ+o+0T ++tOFDITEAl+YZZariXOD7tdOSOl9RLMPC6+daHKS9e68u3enxhqnDGQIUB78dhW77 ++J6zsFbSEHaQGUmfSeoM= ++-----END DSA PRIVATE KEY----- ++-----BEGIN CERTIFICATE REQUEST----- ++MIICVjCCAhMCAQAwUjELMAkGA1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUx ++ITAfBgNVBAoMGEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDELMAkGA1UEAwwCQ0Ew ++ggG2MIIBKwYHKoZIzjgEATCCAR4CgYEApz9uhb9Bail98J9HGTCQmgkd2mozHsU9 ++hpazFeBTLo/gWYJzkD51MZlHelL7heTZpns4m2iKhJuHxh61foZLU1tZz3FlGYhu ++zmaua4g2++wo3MLXpbvlLDkmS9qacBiVN5UQViP2Fe26BF7eOU/9t0MftaRlb82A ++EeRwlVtQzUkCFQD3BzHt+mwGA9WFihysnGXnUGZlbwKBgE3fTAOmkYr1GW9QRiWZ ++5WhvMONp4eWzXZi7KIZI/N6ZBD9fiAyccyQNIF25Kpo/GJYn5GKHwXt0YlP8YSeo ++epEJnbbxTZxUD1gG7kl0B85VfiPOFvbK3FphAX7JcbVN9tw0KYdo9l4gk7Pb9eQJ ++bEEXlZLrAbVzpWp+2DLtDgK4A4GEAAKBgBqmWXqKrP1etkWWTYYJVwH4qKHFacfs ++i4e9IvD1hSslqFwEeZum+3j3iUXiALnDdY8z69cmh9u6yTgahAQSxA0wNpqHibj2 ++5SoDKU5UUkkle6KtUn6j7RO04UMhMQCX5hllquJc4Pu105I6X1Esw8Lr51ocpL17 ++ry7d6fGGqcMZoAAwCwYJYIZIAWUDBAMCAzAAMC0CFCp7rUwGJNtxK6Aqo6k6US+S ++KP8sAhUAyfSi8Zs3QAvkJoFG0IMRaq8M03I= ++-----END CERTIFICATE REQUEST----- ++-----BEGIN CERTIFICATE----- ++MIIDMDCCAuygAwIBAgIBAjALBglghkgBZQMEAwIwUzELMAkGA1UEBhMCQVUxEzAR ++BgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoMGEludGVybmV0IFdpZGdpdHMgUHR5 ++IEx0ZDEMMAoGA1UEAwwDUENBMCAXDTE2MDExMzIxNDE0OVoYDzMwMTUwNTE2MjE0 ++MTQ5WjBSMQswCQYDVQQGEwJBVTETMBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UE ++CgwYSW50ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMQswCQYDVQQDDAJDQTCCAbYwggEr ++BgcqhkjOOAQBMIIBHgKBgQCnP26Fv0FqKX3wn0cZMJCaCR3aajMexT2GlrMV4FMu ++j+BZgnOQPnUxmUd6UvuF5NmmezibaIqEm4fGHrV+hktTW1nPcWUZiG7OZq5riDb7 ++7Cjcwtelu+UsOSZL2ppwGJU3lRBWI/YV7boEXt45T/23Qx+1pGVvzYAR5HCVW1DN ++SQIVAPcHMe36bAYD1YWKHKycZedQZmVvAoGATd9MA6aRivUZb1BGJZnlaG8w42nh ++5bNdmLsohkj83pkEP1+IDJxzJA0gXbkqmj8YlifkYofBe3RiU/xhJ6h6kQmdtvFN ++nFQPWAbuSXQHzlV+I84W9srcWmEBfslxtU323DQph2j2XiCTs9v15AlsQReVkusB ++tXOlan7YMu0OArgDgYQAAoGAGqZZeoqs/V62RZZNhglXAfioocVpx+yLh70i8PWF ++KyWoXAR5m6b7ePeJReIAucN1jzPr1yaH27rJOBqEBBLEDTA2moeJuPblKgMpTlRS ++SSV7oq1SfqPtE7ThQyExAJfmGWWq4lzg+7XTkjpfUSzDwuvnWhykvXuvLt3p8Yap ++wxmjUDBOMB0GA1UdDgQWBBTMZcORcBEVlqO/CD4pf4V6N1NM1zAfBgNVHSMEGDAW ++gBTGjwJ33uvjSa20RNrMKWoGptOLdDAMBgNVHRMEBTADAQH/MAsGCWCGSAFlAwQD ++AgMxADAuAhUA4V6MrHufG8R79E+AtVO02olPxK8CFQDkZyo/TWpavsUBRDJbCeD9 ++jgjIkA== ++-----END CERTIFICATE----- +diff --git a/CryptoPkg/Library/OpensslLib/openssl/apps/dsa-pca.pem b/CryptoPkg/Library/OpensslLib/openssl/apps/dsa-pca.pem +new file mode 100644 +index 0000000..a51a06e +--- /dev/null ++++ b/CryptoPkg/Library/OpensslLib/openssl/apps/dsa-pca.pem +@@ -0,0 +1,47 @@ ++-----BEGIN DSA PRIVATE KEY----- ++MIIBvAIBAAKBgQCnP26Fv0FqKX3wn0cZMJCaCR3aajMexT2GlrMV4FMuj+BZgnOQ ++PnUxmUd6UvuF5NmmezibaIqEm4fGHrV+hktTW1nPcWUZiG7OZq5riDb77Cjcwtel ++u+UsOSZL2ppwGJU3lRBWI/YV7boEXt45T/23Qx+1pGVvzYAR5HCVW1DNSQIVAPcH ++Me36bAYD1YWKHKycZedQZmVvAoGATd9MA6aRivUZb1BGJZnlaG8w42nh5bNdmLso ++hkj83pkEP1+IDJxzJA0gXbkqmj8YlifkYofBe3RiU/xhJ6h6kQmdtvFNnFQPWAbu ++SXQHzlV+I84W9srcWmEBfslxtU323DQph2j2XiCTs9v15AlsQReVkusBtXOlan7Y ++Mu0OArgCgYEApu25HkB1b4gKMIV7aLGNSIknMzYgrB7o1kQxeDf34dDVRM9OZ8tk ++umz6tl+iUcNe5EoxdsYV1IXSddjOi08LOLsZq7AQlNnKvbtlmMDULpqkZJD0bO7A ++29nisJfKy1URqABLw5DgfcPh1ZLXtmDfUgJvmjgTmvTPT2j9TPjq7RUCFQDNvrBz ++6TicfImU7UFRn9h00j0lJQ== ++-----END DSA PRIVATE KEY----- ++-----BEGIN CERTIFICATE REQUEST----- ++MIICWDCCAhUCAQAwUzELMAkGA1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUx ++ITAfBgNVBAoMGEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDEMMAoGA1UEAwwDUENB ++MIIBtzCCASsGByqGSM44BAEwggEeAoGBAKc/boW/QWopffCfRxkwkJoJHdpqMx7F ++PYaWsxXgUy6P4FmCc5A+dTGZR3pS+4Xk2aZ7OJtoioSbh8YetX6GS1NbWc9xZRmI ++bs5mrmuINvvsKNzC16W75Sw5JkvamnAYlTeVEFYj9hXtugRe3jlP/bdDH7WkZW/N ++gBHkcJVbUM1JAhUA9wcx7fpsBgPVhYocrJxl51BmZW8CgYBN30wDppGK9RlvUEYl ++meVobzDjaeHls12YuyiGSPzemQQ/X4gMnHMkDSBduSqaPxiWJ+Rih8F7dGJT/GEn ++qHqRCZ228U2cVA9YBu5JdAfOVX4jzhb2ytxaYQF+yXG1TfbcNCmHaPZeIJOz2/Xk ++CWxBF5WS6wG1c6Vqftgy7Q4CuAOBhQACgYEApu25HkB1b4gKMIV7aLGNSIknMzYg ++rB7o1kQxeDf34dDVRM9OZ8tkumz6tl+iUcNe5EoxdsYV1IXSddjOi08LOLsZq7AQ ++lNnKvbtlmMDULpqkZJD0bO7A29nisJfKy1URqABLw5DgfcPh1ZLXtmDfUgJvmjgT ++mvTPT2j9TPjq7RWgADALBglghkgBZQMEAwIDMAAwLQIVAPA6/jxCT1D2HgzE4iZR ++AEup/C7YAhRPLTQvQnAiS5FRrA+8SwBLvDAsaw== ++-----END CERTIFICATE REQUEST----- ++-----BEGIN CERTIFICATE----- ++MIIDMDCCAu6gAwIBAgIBATALBglghkgBZQMEAwIwUzELMAkGA1UEBhMCQVUxEzAR ++BgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoMGEludGVybmV0IFdpZGdpdHMgUHR5 ++IEx0ZDEMMAoGA1UEAwwDUENBMCAXDTE2MDExMzIxNDE0OVoYDzMwMTUwNTE2MjE0 ++MTQ5WjBTMQswCQYDVQQGEwJBVTETMBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UE ++CgwYSW50ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMQwwCgYDVQQDDANQQ0EwggG3MIIB ++KwYHKoZIzjgEATCCAR4CgYEApz9uhb9Bail98J9HGTCQmgkd2mozHsU9hpazFeBT ++Lo/gWYJzkD51MZlHelL7heTZpns4m2iKhJuHxh61foZLU1tZz3FlGYhuzmaua4g2 ++++wo3MLXpbvlLDkmS9qacBiVN5UQViP2Fe26BF7eOU/9t0MftaRlb82AEeRwlVtQ ++zUkCFQD3BzHt+mwGA9WFihysnGXnUGZlbwKBgE3fTAOmkYr1GW9QRiWZ5WhvMONp ++4eWzXZi7KIZI/N6ZBD9fiAyccyQNIF25Kpo/GJYn5GKHwXt0YlP8YSeoepEJnbbx ++TZxUD1gG7kl0B85VfiPOFvbK3FphAX7JcbVN9tw0KYdo9l4gk7Pb9eQJbEEXlZLr ++AbVzpWp+2DLtDgK4A4GFAAKBgQCm7bkeQHVviAowhXtosY1IiSczNiCsHujWRDF4 ++N/fh0NVEz05ny2S6bPq2X6JRw17kSjF2xhXUhdJ12M6LTws4uxmrsBCU2cq9u2WY ++wNQumqRkkPRs7sDb2eKwl8rLVRGoAEvDkOB9w+HVkte2YN9SAm+aOBOa9M9PaP1M +++OrtFaNQME4wHQYDVR0OBBYEFMaPAnfe6+NJrbRE2swpagam04t0MB8GA1UdIwQY ++MBaAFMaPAnfe6+NJrbRE2swpagam04t0MAwGA1UdEwQFMAMBAf8wCwYJYIZIAWUD ++BAMCAy8AMCwCFFhdz4fzQo9BBF20U1CHldYTi/D7AhQydDnDMj21y+U1UhDZJrvh ++lnt88g== ++-----END CERTIFICATE----- +diff --git a/CryptoPkg/Library/OpensslLib/openssl/apps/dsa.c b/CryptoPkg/Library/OpensslLib/openssl/apps/dsa.c +new file mode 100644 +index 0000000..9c93549 +--- /dev/null ++++ b/CryptoPkg/Library/OpensslLib/openssl/apps/dsa.c +@@ -0,0 +1,262 @@ ++/* ++ * Copyright 1995-2016 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 ++ * in the file LICENSE in the source distribution or at ++ * https://www.openssl.org/source/license.html ++ */ ++ ++#include ++#ifdef OPENSSL_NO_DSA ++NON_EMPTY_TRANSLATION_UNIT ++#else ++ ++# include ++# include ++# include ++# include ++# include "apps.h" ++# include ++# include ++# include ++# include ++# include ++# include ++# include ++ ++typedef enum OPTION_choice { ++ OPT_ERR = -1, OPT_EOF = 0, OPT_HELP, ++ OPT_INFORM, OPT_OUTFORM, OPT_IN, OPT_OUT, OPT_ENGINE, ++ /* Do not change the order here; see case statements below */ ++ OPT_PVK_NONE, OPT_PVK_WEAK, OPT_PVK_STRONG, ++ OPT_NOOUT, OPT_TEXT, OPT_MODULUS, OPT_PUBIN, ++ OPT_PUBOUT, OPT_CIPHER, OPT_PASSIN, OPT_PASSOUT ++} OPTION_CHOICE; ++ ++OPTIONS dsa_options[] = { ++ {"help", OPT_HELP, '-', "Display this summary"}, ++ {"inform", OPT_INFORM, 'f', "Input format, DER PEM PVK"}, ++ {"outform", OPT_OUTFORM, 'f', "Output format, DER PEM PVK"}, ++ {"in", OPT_IN, 's', "Input key"}, ++ {"out", OPT_OUT, '>', "Output file"}, ++ {"noout", OPT_NOOUT, '-', "Don't print key out"}, ++ {"text", OPT_TEXT, '-', "Print the key in text"}, ++ {"modulus", OPT_MODULUS, '-', "Print the DSA public value"}, ++ {"pubin", OPT_PUBIN, '-', "Expect a public key in input file"}, ++ {"pubout", OPT_PUBOUT, '-', "Output public key, not private"}, ++ {"passin", OPT_PASSIN, 's', "Input file pass phrase source"}, ++ {"passout", OPT_PASSOUT, 's', "Output file pass phrase source"}, ++ {"", OPT_CIPHER, '-', "Any supported cipher"}, ++# ifndef OPENSSL_NO_RC4 ++ {"pvk-strong", OPT_PVK_STRONG, '-', "Enable 'Strong' PVK encoding level (default)"}, ++ {"pvk-weak", OPT_PVK_WEAK, '-', "Enable 'Weak' PVK encoding level"}, ++ {"pvk-none", OPT_PVK_NONE, '-', "Don't enforce PVK encoding"}, ++# endif ++# ifndef OPENSSL_NO_ENGINE ++ {"engine", OPT_ENGINE, 's', "Use engine e, possibly a hardware device"}, ++# endif ++ {NULL} ++}; ++ ++int dsa_main(int argc, char **argv) ++{ ++ BIO *out = NULL; ++ DSA *dsa = NULL; ++ ENGINE *e = NULL; ++ const EVP_CIPHER *enc = NULL; ++ char *infile = NULL, *outfile = NULL, *prog; ++ char *passin = NULL, *passout = NULL, *passinarg = NULL, *passoutarg = NULL; ++ OPTION_CHOICE o; ++ int informat = FORMAT_PEM, outformat = FORMAT_PEM, text = 0, noout = 0; ++ int i, modulus = 0, pubin = 0, pubout = 0, ret = 1; ++# ifndef OPENSSL_NO_RC4 ++ int pvk_encr = 2; ++# endif ++ int private = 0; ++ ++ prog = opt_init(argc, argv, dsa_options); ++ while ((o = opt_next()) != OPT_EOF) { ++ switch (o) { ++ case OPT_EOF: ++ case OPT_ERR: ++ opthelp: ++ ret = 0; ++ BIO_printf(bio_err, "%s: Use -help for summary.\n", prog); ++ goto end; ++ case OPT_HELP: ++ opt_help(dsa_options); ++ ret = 0; ++ goto end; ++ case OPT_INFORM: ++ if (!opt_format(opt_arg(), OPT_FMT_ANY, &informat)) ++ goto opthelp; ++ break; ++ case OPT_IN: ++ infile = opt_arg(); ++ break; ++ case OPT_OUTFORM: ++ if (!opt_format(opt_arg(), OPT_FMT_ANY, &outformat)) ++ goto opthelp; ++ break; ++ case OPT_OUT: ++ outfile = opt_arg(); ++ break; ++ case OPT_ENGINE: ++ e = setup_engine(opt_arg(), 0); ++ break; ++ case OPT_PASSIN: ++ passinarg = opt_arg(); ++ break; ++ case OPT_PASSOUT: ++ passoutarg = opt_arg(); ++ break; ++ case OPT_PVK_STRONG: /* pvk_encr:= 2 */ ++ case OPT_PVK_WEAK: /* pvk_encr:= 1 */ ++ case OPT_PVK_NONE: /* pvk_encr:= 0 */ ++#ifndef OPENSSL_NO_RC4 ++ pvk_encr = (o - OPT_PVK_NONE); ++#endif ++ break; ++ case OPT_NOOUT: ++ noout = 1; ++ break; ++ case OPT_TEXT: ++ text = 1; ++ break; ++ case OPT_MODULUS: ++ modulus = 1; ++ break; ++ case OPT_PUBIN: ++ pubin = 1; ++ break; ++ case OPT_PUBOUT: ++ pubout = 1; ++ break; ++ case OPT_CIPHER: ++ if (!opt_cipher(opt_unknown(), &enc)) ++ goto end; ++ break; ++ } ++ } ++ argc = opt_num_rest(); ++ if (argc != 0) ++ goto opthelp; ++ ++ private = pubin || pubout ? 0 : 1; ++ if (text && !pubin) ++ private = 1; ++ ++ if (!app_passwd(passinarg, passoutarg, &passin, &passout)) { ++ BIO_printf(bio_err, "Error getting passwords\n"); ++ goto end; ++ } ++ ++ BIO_printf(bio_err, "read DSA key\n"); ++ { ++ EVP_PKEY *pkey; ++ ++ if (pubin) ++ pkey = load_pubkey(infile, informat, 1, passin, e, "Public Key"); ++ else ++ pkey = load_key(infile, informat, 1, passin, e, "Private Key"); ++ ++ if (pkey) { ++ dsa = EVP_PKEY_get1_DSA(pkey); ++ EVP_PKEY_free(pkey); ++ } ++ } ++ if (dsa == NULL) { ++ BIO_printf(bio_err, "unable to load Key\n"); ++ ERR_print_errors(bio_err); ++ goto end; ++ } ++ ++ out = bio_open_owner(outfile, outformat, private); ++ if (out == NULL) ++ goto end; ++ ++ if (text) { ++ assert(pubin || private); ++ if (!DSA_print(out, dsa, 0)) { ++ perror(outfile); ++ ERR_print_errors(bio_err); ++ goto end; ++ } ++ } ++ ++ if (modulus) { ++ const BIGNUM *pub_key = NULL; ++ DSA_get0_key(dsa, &pub_key, NULL); ++ BIO_printf(out, "Public Key="); ++ BN_print(out, pub_key); ++ BIO_printf(out, "\n"); ++ } ++ ++ if (noout) { ++ ret = 0; ++ goto end; ++ } ++ BIO_printf(bio_err, "writing DSA key\n"); ++ if (outformat == FORMAT_ASN1) { ++ if (pubin || pubout) ++ i = i2d_DSA_PUBKEY_bio(out, dsa); ++ else { ++ assert(private); ++ i = i2d_DSAPrivateKey_bio(out, dsa); ++ } ++ } else if (outformat == FORMAT_PEM) { ++ if (pubin || pubout) ++ i = PEM_write_bio_DSA_PUBKEY(out, dsa); ++ else { ++ assert(private); ++ i = PEM_write_bio_DSAPrivateKey(out, dsa, enc, ++ NULL, 0, NULL, passout); ++ } ++# ifndef OPENSSL_NO_RSA ++ } else if (outformat == FORMAT_MSBLOB || outformat == FORMAT_PVK) { ++ EVP_PKEY *pk; ++ pk = EVP_PKEY_new(); ++ EVP_PKEY_set1_DSA(pk, dsa); ++ if (outformat == FORMAT_PVK) { ++ if (pubin) { ++ BIO_printf(bio_err, "PVK form impossible with public key input\n"); ++ EVP_PKEY_free(pk); ++ goto end; ++ } ++ assert(private); ++# ifdef OPENSSL_NO_RC4 ++ BIO_printf(bio_err, "PVK format not supported\n"); ++ EVP_PKEY_free(pk); ++ goto end; ++# else ++ i = i2b_PVK_bio(out, pk, pvk_encr, 0, passout); ++# endif ++ } ++ else if (pubin || pubout) ++ i = i2b_PublicKey_bio(out, pk); ++ else { ++ assert(private); ++ i = i2b_PrivateKey_bio(out, pk); ++ } ++ EVP_PKEY_free(pk); ++# endif ++ } else { ++ BIO_printf(bio_err, "bad output format specified for outfile\n"); ++ goto end; ++ } ++ if (i <= 0) { ++ BIO_printf(bio_err, "unable to write private key\n"); ++ ERR_print_errors(bio_err); ++ goto end; ++ } ++ ret = 0; ++ end: ++ BIO_free_all(out); ++ DSA_free(dsa); ++ release_engine(e); ++ OPENSSL_free(passin); ++ OPENSSL_free(passout); ++ return (ret); ++} ++#endif +diff --git a/CryptoPkg/Library/OpensslLib/openssl/apps/dsa1024.pem b/CryptoPkg/Library/OpensslLib/openssl/apps/dsa1024.pem +new file mode 100644 +index 0000000..082dec3 +--- /dev/null ++++ b/CryptoPkg/Library/OpensslLib/openssl/apps/dsa1024.pem +@@ -0,0 +1,9 @@ ++-----BEGIN DSA PARAMETERS----- ++MIIBHgKBgQCnP26Fv0FqKX3wn0cZMJCaCR3aajMexT2GlrMV4FMuj+BZgnOQPnUx ++mUd6UvuF5NmmezibaIqEm4fGHrV+hktTW1nPcWUZiG7OZq5riDb77Cjcwtelu+Us ++OSZL2ppwGJU3lRBWI/YV7boEXt45T/23Qx+1pGVvzYAR5HCVW1DNSQIVAPcHMe36 ++bAYD1YWKHKycZedQZmVvAoGATd9MA6aRivUZb1BGJZnlaG8w42nh5bNdmLsohkj8 ++3pkEP1+IDJxzJA0gXbkqmj8YlifkYofBe3RiU/xhJ6h6kQmdtvFNnFQPWAbuSXQH ++zlV+I84W9srcWmEBfslxtU323DQph2j2XiCTs9v15AlsQReVkusBtXOlan7YMu0O ++Arg= ++-----END DSA PARAMETERS----- +diff --git a/CryptoPkg/Library/OpensslLib/openssl/apps/dsa512.pem b/CryptoPkg/Library/OpensslLib/openssl/apps/dsa512.pem +new file mode 100644 +index 0000000..5f86d1a +--- /dev/null ++++ b/CryptoPkg/Library/OpensslLib/openssl/apps/dsa512.pem +@@ -0,0 +1,6 @@ ++-----BEGIN DSA PARAMETERS----- ++MIGdAkEAnRtpjibb8isRcBmG9hnI+BnyGFOURgbQYlAzSwI8UjADizv5X9EkBk97 ++TLqqQJv9luQ3M7stWtdaEUBmonZ9MQIVAPtT71C0QJIxVoZTeuiLIppJ+3GPAkEA ++gz6I5cWJc847bAFJv7PHnwrqRJHlMKrZvltftxDXibeOdPvPKR7rqCxUUbgQ3qDO ++L8wka5B33qJoplISogOdIA== ++-----END DSA PARAMETERS----- +diff --git a/CryptoPkg/Library/OpensslLib/openssl/apps/dsap.pem b/CryptoPkg/Library/OpensslLib/openssl/apps/dsap.pem +new file mode 100644 +index 0000000..d4dfdb3 +--- /dev/null ++++ b/CryptoPkg/Library/OpensslLib/openssl/apps/dsap.pem +@@ -0,0 +1,6 @@ ++-----BEGIN DSA PARAMETERS----- ++MIGcAkEA+ZiKEvZmc9MtnaFZh4NiZ3oZS4J1PHvPrm9MXj5ntVheDPkdmBDTncya ++GAJcMjwsyB/GvLDGd6yGCw/8eF+09wIVAK3VagOxGd/Q4Af5NbxR5FB7CXEjAkA2 ++t/q7HgVLi0KeKvcDG8BRl3wuy7bCvpjgtWiJc/tpvcuzeuAayH89UofjAGueKjXD ++ADiRffvSdhrNw5dkqdql ++-----END DSA PARAMETERS----- +diff --git a/CryptoPkg/Library/OpensslLib/openssl/apps/dsaparam.c b/CryptoPkg/Library/OpensslLib/openssl/apps/dsaparam.c +new file mode 100644 +index 0000000..9258803 +--- /dev/null ++++ b/CryptoPkg/Library/OpensslLib/openssl/apps/dsaparam.c +@@ -0,0 +1,313 @@ ++/* ++ * Copyright 1995-2016 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 ++ * in the file LICENSE in the source distribution or at ++ * https://www.openssl.org/source/license.html ++ */ ++ ++#include ++#ifdef OPENSSL_NO_DSA ++NON_EMPTY_TRANSLATION_UNIT ++#else ++ ++# include ++# include ++# include ++# include ++# include "apps.h" ++# include ++# include ++# include ++# include ++# include ++# include ++ ++# ifdef GENCB_TEST ++ ++static int stop_keygen_flag = 0; ++ ++static void timebomb_sigalarm(int foo) ++{ ++ stop_keygen_flag = 1; ++} ++ ++# endif ++ ++static int dsa_cb(int p, int n, BN_GENCB *cb); ++ ++typedef enum OPTION_choice { ++ OPT_ERR = -1, OPT_EOF = 0, OPT_HELP, ++ OPT_INFORM, OPT_OUTFORM, OPT_IN, OPT_OUT, OPT_TEXT, OPT_C, ++ OPT_NOOUT, OPT_GENKEY, OPT_RAND, OPT_ENGINE, ++ OPT_TIMEBOMB ++} OPTION_CHOICE; ++ ++OPTIONS dsaparam_options[] = { ++ {"help", OPT_HELP, '-', "Display this summary"}, ++ {"inform", OPT_INFORM, 'F', "Input format - DER or PEM"}, ++ {"in", OPT_IN, '<', "Input file"}, ++ {"outform", OPT_OUTFORM, 'F', "Output format - DER or PEM"}, ++ {"out", OPT_OUT, '>', "Output file"}, ++ {"text", OPT_TEXT, '-', "Print as text"}, ++ {"C", OPT_C, '-', "Output C code"}, ++ {"noout", OPT_NOOUT, '-', "No output"}, ++ {"genkey", OPT_GENKEY, '-', "Generate a DSA key"}, ++ {"rand", OPT_RAND, 's', "Files to use for random number input"}, ++# ifdef GENCB_TEST ++ {"timebomb", OPT_TIMEBOMB, 'p', "Interrupt keygen after 'pnum' seconds"}, ++# endif ++# ifndef OPENSSL_NO_ENGINE ++ {"engine", OPT_ENGINE, 's', "Use engine e, possibly a hardware device"}, ++# endif ++ {NULL} ++}; ++ ++int dsaparam_main(int argc, char **argv) ++{ ++ ENGINE *e = NULL; ++ DSA *dsa = NULL; ++ BIO *in = NULL, *out = NULL; ++ BN_GENCB *cb = NULL; ++ int numbits = -1, num = 0, genkey = 0, need_rand = 0; ++ int informat = FORMAT_PEM, outformat = FORMAT_PEM, noout = 0, C = 0; ++ int ret = 1, i, text = 0, private = 0; ++# ifdef GENCB_TEST ++ int timebomb = 0; ++# endif ++ char *infile = NULL, *outfile = NULL, *prog, *inrand = NULL; ++ OPTION_CHOICE o; ++ ++ prog = opt_init(argc, argv, dsaparam_options); ++ while ((o = opt_next()) != OPT_EOF) { ++ switch (o) { ++ case OPT_EOF: ++ case OPT_ERR: ++ opthelp: ++ BIO_printf(bio_err, "%s: Use -help for summary.\n", prog); ++ goto end; ++ case OPT_HELP: ++ opt_help(dsaparam_options); ++ ret = 0; ++ goto end; ++ case OPT_INFORM: ++ if (!opt_format(opt_arg(), OPT_FMT_PEMDER, &informat)) ++ goto opthelp; ++ break; ++ case OPT_IN: ++ infile = opt_arg(); ++ break; ++ case OPT_OUTFORM: ++ if (!opt_format(opt_arg(), OPT_FMT_PEMDER, &outformat)) ++ goto opthelp; ++ break; ++ case OPT_OUT: ++ outfile = opt_arg(); ++ break; ++ case OPT_ENGINE: ++ e = setup_engine(opt_arg(), 0); ++ break; ++ case OPT_TIMEBOMB: ++# ifdef GENCB_TEST ++ timebomb = atoi(opt_arg()); ++ break; ++# endif ++ case OPT_TEXT: ++ text = 1; ++ break; ++ case OPT_C: ++ C = 1; ++ break; ++ case OPT_GENKEY: ++ genkey = need_rand = 1; ++ break; ++ case OPT_RAND: ++ inrand = opt_arg(); ++ need_rand = 1; ++ break; ++ case OPT_NOOUT: ++ noout = 1; ++ break; ++ } ++ } ++ argc = opt_num_rest(); ++ argv = opt_rest(); ++ ++ if (argc == 1) { ++ if (!opt_int(argv[0], &num) || num < 0) ++ goto end; ++ /* generate a key */ ++ numbits = num; ++ need_rand = 1; ++ } ++ private = genkey ? 1 : 0; ++ ++ in = bio_open_default(infile, 'r', informat); ++ if (in == NULL) ++ goto end; ++ out = bio_open_owner(outfile, outformat, private); ++ if (out == NULL) ++ goto end; ++ ++ if (need_rand) { ++ app_RAND_load_file(NULL, (inrand != NULL)); ++ if (inrand != NULL) ++ BIO_printf(bio_err, "%ld semi-random bytes loaded\n", ++ app_RAND_load_files(inrand)); ++ } ++ ++ if (numbits > 0) { ++ cb = BN_GENCB_new(); ++ if (cb == NULL) { ++ BIO_printf(bio_err, "Error allocating BN_GENCB object\n"); ++ goto end; ++ } ++ BN_GENCB_set(cb, dsa_cb, bio_err); ++ assert(need_rand); ++ dsa = DSA_new(); ++ if (dsa == NULL) { ++ BIO_printf(bio_err, "Error allocating DSA object\n"); ++ goto end; ++ } ++ BIO_printf(bio_err, "Generating DSA parameters, %d bit long prime\n", ++ num); ++ BIO_printf(bio_err, "This could take some time\n"); ++# ifdef GENCB_TEST ++ if (timebomb > 0) { ++ struct sigaction act; ++ act.sa_handler = timebomb_sigalarm; ++ act.sa_flags = 0; ++ BIO_printf(bio_err, ++ "(though I'll stop it if not done within %d secs)\n", ++ timebomb); ++ if (sigaction(SIGALRM, &act, NULL) != 0) { ++ BIO_printf(bio_err, "Error, couldn't set SIGALRM handler\n"); ++ goto end; ++ } ++ alarm(timebomb); ++ } ++# endif ++ if (!DSA_generate_parameters_ex(dsa, num, NULL, 0, NULL, NULL, cb)) { ++# ifdef GENCB_TEST ++ if (stop_keygen_flag) { ++ BIO_printf(bio_err, "DSA key generation time-stopped\n"); ++ /* This is an asked-for behaviour! */ ++ ret = 0; ++ goto end; ++ } ++# endif ++ ERR_print_errors(bio_err); ++ BIO_printf(bio_err, "Error, DSA key generation failed\n"); ++ goto end; ++ } ++ } else if (informat == FORMAT_ASN1) ++ dsa = d2i_DSAparams_bio(in, NULL); ++ else ++ dsa = PEM_read_bio_DSAparams(in, NULL, NULL, NULL); ++ if (dsa == NULL) { ++ BIO_printf(bio_err, "unable to load DSA parameters\n"); ++ ERR_print_errors(bio_err); ++ goto end; ++ } ++ ++ if (text) { ++ DSAparams_print(out, dsa); ++ } ++ ++ if (C) { ++ const BIGNUM *p = NULL, *q = NULL, *g = NULL; ++ unsigned char *data; ++ int len, bits_p; ++ ++ DSA_get0_pqg(dsa, &p, &q, &g); ++ len = BN_num_bytes(p); ++ bits_p = BN_num_bits(p); ++ ++ data = app_malloc(len + 20, "BN space"); ++ ++ BIO_printf(bio_out, "DSA *get_dsa%d()\n{\n", bits_p); ++ print_bignum_var(bio_out, p, "dsap", len, data); ++ print_bignum_var(bio_out, q, "dsaq", len, data); ++ print_bignum_var(bio_out, g, "dsag", len, data); ++ BIO_printf(bio_out, " DSA *dsa = DSA_new();\n" ++ "\n"); ++ BIO_printf(bio_out, " if (dsa == NULL)\n" ++ " return NULL;\n"); ++ BIO_printf(bio_out, " dsa->p = BN_bin2bn(dsap_%d, sizeof (dsap_%d), NULL);\n", ++ bits_p, bits_p); ++ BIO_printf(bio_out, " dsa->q = BN_bin2bn(dsaq_%d, sizeof (dsaq_%d), NULL);\n", ++ bits_p, bits_p); ++ BIO_printf(bio_out, " dsa->g = BN_bin2bn(dsag_%d, sizeof (dsag_%d), NULL);\n", ++ bits_p, bits_p); ++ BIO_printf(bio_out, " if (!dsa->p || !dsa->q || !dsa->g) {\n" ++ " DSA_free(dsa);\n" ++ " return NULL;\n" ++ " }\n" ++ " return(dsa);\n}\n"); ++ OPENSSL_free(data); ++ } ++ ++ if (!noout) { ++ if (outformat == FORMAT_ASN1) ++ i = i2d_DSAparams_bio(out, dsa); ++ else ++ i = PEM_write_bio_DSAparams(out, dsa); ++ if (!i) { ++ BIO_printf(bio_err, "unable to write DSA parameters\n"); ++ ERR_print_errors(bio_err); ++ goto end; ++ } ++ } ++ if (genkey) { ++ DSA *dsakey; ++ ++ assert(need_rand); ++ if ((dsakey = DSAparams_dup(dsa)) == NULL) ++ goto end; ++ if (!DSA_generate_key(dsakey)) { ++ ERR_print_errors(bio_err); ++ DSA_free(dsakey); ++ goto end; ++ } ++ assert(private); ++ if (outformat == FORMAT_ASN1) ++ i = i2d_DSAPrivateKey_bio(out, dsakey); ++ else ++ i = PEM_write_bio_DSAPrivateKey(out, dsakey, NULL, NULL, 0, NULL, ++ NULL); ++ DSA_free(dsakey); ++ } ++ if (need_rand) ++ app_RAND_write_file(NULL); ++ ret = 0; ++ end: ++ BN_GENCB_free(cb); ++ BIO_free(in); ++ BIO_free_all(out); ++ DSA_free(dsa); ++ release_engine(e); ++ return (ret); ++} ++ ++static int dsa_cb(int p, int n, BN_GENCB *cb) ++{ ++ char c = '*'; ++ ++ if (p == 0) ++ c = '.'; ++ if (p == 1) ++ c = '+'; ++ if (p == 2) ++ c = '*'; ++ if (p == 3) ++ c = '\n'; ++ BIO_write(BN_GENCB_get_arg(cb), &c, 1); ++ (void)BIO_flush(BN_GENCB_get_arg(cb)); ++# ifdef GENCB_TEST ++ if (stop_keygen_flag) ++ return 0; ++# endif ++ return 1; ++} ++#endif +diff --git a/CryptoPkg/Library/OpensslLib/openssl/apps/ec.c b/CryptoPkg/Library/OpensslLib/openssl/apps/ec.c +new file mode 100644 +index 0000000..2516c03 +--- /dev/null ++++ b/CryptoPkg/Library/OpensslLib/openssl/apps/ec.c +@@ -0,0 +1,281 @@ ++/* ++ * Copyright 2002-2016 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 ++ * in the file LICENSE in the source distribution or at ++ * https://www.openssl.org/source/license.html ++ */ ++ ++#include ++#ifdef OPENSSL_NO_EC ++NON_EMPTY_TRANSLATION_UNIT ++#else ++ ++# include ++# include ++# include ++# include "apps.h" ++# include ++# include ++# include ++# include ++ ++static OPT_PAIR conv_forms[] = { ++ {"compressed", POINT_CONVERSION_COMPRESSED}, ++ {"uncompressed", POINT_CONVERSION_UNCOMPRESSED}, ++ {"hybrid", POINT_CONVERSION_HYBRID}, ++ {NULL} ++}; ++ ++static OPT_PAIR param_enc[] = { ++ {"named_curve", OPENSSL_EC_NAMED_CURVE}, ++ {"explicit", 0}, ++ {NULL} ++}; ++ ++typedef enum OPTION_choice { ++ OPT_ERR = -1, OPT_EOF = 0, OPT_HELP, ++ OPT_INFORM, OPT_OUTFORM, OPT_ENGINE, OPT_IN, OPT_OUT, ++ OPT_NOOUT, OPT_TEXT, OPT_PARAM_OUT, OPT_PUBIN, OPT_PUBOUT, ++ OPT_PASSIN, OPT_PASSOUT, OPT_PARAM_ENC, OPT_CONV_FORM, OPT_CIPHER, ++ OPT_NO_PUBLIC, OPT_CHECK ++} OPTION_CHOICE; ++ ++OPTIONS ec_options[] = { ++ {"help", OPT_HELP, '-', "Display this summary"}, ++ {"in", OPT_IN, 's', "Input file"}, ++ {"inform", OPT_INFORM, 'f', "Input format - DER or PEM"}, ++ {"out", OPT_OUT, '>', "Output file"}, ++ {"outform", OPT_OUTFORM, 'F', "Output format - DER or PEM"}, ++ {"noout", OPT_NOOUT, '-', "Don't print key out"}, ++ {"text", OPT_TEXT, '-', "Print the key"}, ++ {"param_out", OPT_PARAM_OUT, '-', "Print the elliptic curve parameters"}, ++ {"pubin", OPT_PUBIN, '-', "Expect a public key in input file"}, ++ {"pubout", OPT_PUBOUT, '-', "Output public key, not private"}, ++ {"no_public", OPT_NO_PUBLIC, '-', "exclude public key from private key"}, ++ {"check", OPT_CHECK, '-', "check key consistency"}, ++ {"passin", OPT_PASSIN, 's', "Input file pass phrase source"}, ++ {"passout", OPT_PASSOUT, 's', "Output file pass phrase source"}, ++ {"param_enc", OPT_PARAM_ENC, 's', ++ "Specifies the way the ec parameters are encoded"}, ++ {"conv_form", OPT_CONV_FORM, 's', "Specifies the point conversion form "}, ++ {"", OPT_CIPHER, '-', "Any supported cipher"}, ++# ifndef OPENSSL_NO_ENGINE ++ {"engine", OPT_ENGINE, 's', "Use engine, possibly a hardware device"}, ++# endif ++ {NULL} ++}; ++ ++int ec_main(int argc, char **argv) ++{ ++ BIO *in = NULL, *out = NULL; ++ ENGINE *e = NULL; ++ EC_KEY *eckey = NULL; ++ const EC_GROUP *group; ++ const EVP_CIPHER *enc = NULL; ++ point_conversion_form_t form = POINT_CONVERSION_UNCOMPRESSED; ++ char *infile = NULL, *outfile = NULL, *prog; ++ char *passin = NULL, *passout = NULL, *passinarg = NULL, *passoutarg = NULL; ++ OPTION_CHOICE o; ++ int asn1_flag = OPENSSL_EC_NAMED_CURVE, new_form = 0, new_asn1_flag = 0; ++ int informat = FORMAT_PEM, outformat = FORMAT_PEM, text = 0, noout = 0; ++ int pubin = 0, pubout = 0, param_out = 0, i, ret = 1, private = 0; ++ int no_public = 0, check = 0; ++ ++ prog = opt_init(argc, argv, ec_options); ++ while ((o = opt_next()) != OPT_EOF) { ++ switch (o) { ++ case OPT_EOF: ++ case OPT_ERR: ++ opthelp: ++ BIO_printf(bio_err, "%s: Use -help for summary.\n", prog); ++ goto end; ++ case OPT_HELP: ++ opt_help(ec_options); ++ ret = 0; ++ goto end; ++ case OPT_INFORM: ++ if (!opt_format(opt_arg(), OPT_FMT_ANY, &informat)) ++ goto opthelp; ++ break; ++ case OPT_IN: ++ infile = opt_arg(); ++ break; ++ case OPT_OUTFORM: ++ if (!opt_format(opt_arg(), OPT_FMT_PEMDER, &outformat)) ++ goto opthelp; ++ break; ++ case OPT_OUT: ++ outfile = opt_arg(); ++ break; ++ case OPT_NOOUT: ++ noout = 1; ++ break; ++ case OPT_TEXT: ++ text = 1; ++ break; ++ case OPT_PARAM_OUT: ++ param_out = 1; ++ break; ++ case OPT_PUBIN: ++ pubin = 1; ++ break; ++ case OPT_PUBOUT: ++ pubout = 1; ++ break; ++ case OPT_PASSIN: ++ passinarg = opt_arg(); ++ break; ++ case OPT_PASSOUT: ++ passoutarg = opt_arg(); ++ break; ++ case OPT_ENGINE: ++ e = setup_engine(opt_arg(), 0); ++ break; ++ case OPT_CIPHER: ++ if (!opt_cipher(opt_unknown(), &enc)) ++ goto opthelp; ++ break; ++ case OPT_CONV_FORM: ++ if (!opt_pair(opt_arg(), conv_forms, &i)) ++ goto opthelp; ++ new_form = 1; ++ form = i; ++ break; ++ case OPT_PARAM_ENC: ++ if (!opt_pair(opt_arg(), param_enc, &i)) ++ goto opthelp; ++ new_asn1_flag = 1; ++ asn1_flag = i; ++ break; ++ case OPT_NO_PUBLIC: ++ no_public = 1; ++ break; ++ case OPT_CHECK: ++ check = 1; ++ break; ++ } ++ } ++ argc = opt_num_rest(); ++ if (argc != 0) ++ goto opthelp; ++ ++ private = param_out || pubin || pubout ? 0 : 1; ++ if (text && !pubin) ++ private = 1; ++ ++ if (!app_passwd(passinarg, passoutarg, &passin, &passout)) { ++ BIO_printf(bio_err, "Error getting passwords\n"); ++ goto end; ++ } ++ ++ if (informat != FORMAT_ENGINE) { ++ in = bio_open_default(infile, 'r', informat); ++ if (in == NULL) ++ goto end; ++ } ++ ++ BIO_printf(bio_err, "read EC key\n"); ++ if (informat == FORMAT_ASN1) { ++ if (pubin) ++ eckey = d2i_EC_PUBKEY_bio(in, NULL); ++ else ++ eckey = d2i_ECPrivateKey_bio(in, NULL); ++ } else if (informat == FORMAT_ENGINE) { ++ EVP_PKEY *pkey; ++ if (pubin) ++ pkey = load_pubkey(infile, informat , 1, passin, e, "Public Key"); ++ else ++ pkey = load_key(infile, informat, 1, passin, e, "Private Key"); ++ if (pkey != NULL) { ++ eckey = EVP_PKEY_get1_EC_KEY(pkey); ++ EVP_PKEY_free(pkey); ++ } ++ } else { ++ if (pubin) ++ eckey = PEM_read_bio_EC_PUBKEY(in, NULL, NULL, NULL); ++ else ++ eckey = PEM_read_bio_ECPrivateKey(in, NULL, NULL, passin); ++ } ++ if (eckey == NULL) { ++ BIO_printf(bio_err, "unable to load Key\n"); ++ ERR_print_errors(bio_err); ++ goto end; ++ } ++ ++ out = bio_open_owner(outfile, outformat, private); ++ if (out == NULL) ++ goto end; ++ ++ group = EC_KEY_get0_group(eckey); ++ ++ if (new_form) ++ EC_KEY_set_conv_form(eckey, form); ++ ++ if (new_asn1_flag) ++ EC_KEY_set_asn1_flag(eckey, asn1_flag); ++ ++ if (no_public) ++ EC_KEY_set_enc_flags(eckey, EC_PKEY_NO_PUBKEY); ++ ++ if (text) { ++ assert(pubin || private); ++ if (!EC_KEY_print(out, eckey, 0)) { ++ perror(outfile); ++ ERR_print_errors(bio_err); ++ goto end; ++ } ++ } ++ ++ if (check) { ++ if (EC_KEY_check_key(eckey) == 1) { ++ BIO_printf(bio_err, "EC Key valid.\n"); ++ } else { ++ BIO_printf(bio_err, "EC Key Invalid!\n"); ++ ERR_print_errors(bio_err); ++ } ++ } ++ ++ if (noout) { ++ ret = 0; ++ goto end; ++ } ++ ++ BIO_printf(bio_err, "writing EC key\n"); ++ if (outformat == FORMAT_ASN1) { ++ if (param_out) ++ i = i2d_ECPKParameters_bio(out, group); ++ else if (pubin || pubout) ++ i = i2d_EC_PUBKEY_bio(out, eckey); ++ else { ++ assert(private); ++ i = i2d_ECPrivateKey_bio(out, eckey); ++ } ++ } else { ++ if (param_out) ++ i = PEM_write_bio_ECPKParameters(out, group); ++ else if (pubin || pubout) ++ i = PEM_write_bio_EC_PUBKEY(out, eckey); ++ else { ++ assert(private); ++ i = PEM_write_bio_ECPrivateKey(out, eckey, enc, ++ NULL, 0, NULL, passout); ++ } ++ } ++ ++ if (!i) { ++ BIO_printf(bio_err, "unable to write private key\n"); ++ ERR_print_errors(bio_err); ++ } else ++ ret = 0; ++ end: ++ BIO_free(in); ++ BIO_free_all(out); ++ EC_KEY_free(eckey); ++ release_engine(e); ++ OPENSSL_free(passin); ++ OPENSSL_free(passout); ++ return (ret); ++} ++#endif +diff --git a/CryptoPkg/Library/OpensslLib/openssl/apps/ecparam.c b/CryptoPkg/Library/OpensslLib/openssl/apps/ecparam.c +new file mode 100644 +index 0000000..891a0ca +--- /dev/null ++++ b/CryptoPkg/Library/OpensslLib/openssl/apps/ecparam.c +@@ -0,0 +1,465 @@ ++/* ++ * Copyright 2002-2016 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 ++ * in the file LICENSE in the source distribution or at ++ * https://www.openssl.org/source/license.html ++ */ ++ ++/* ==================================================================== ++ * Copyright 2002 Sun Microsystems, Inc. ALL RIGHTS RESERVED. ++ * ++ * Portions of the attached software ("Contribution") are developed by ++ * SUN MICROSYSTEMS, INC., and are contributed to the OpenSSL project. ++ * ++ * The Contribution is licensed pursuant to the OpenSSL open source ++ * license provided above. ++ * ++ * The elliptic curve binary polynomial software is originally written by ++ * Sheueling Chang Shantz and Douglas Stebila of Sun Microsystems Laboratories. ++ * ++ */ ++ ++#include ++#ifdef OPENSSL_NO_EC ++NON_EMPTY_TRANSLATION_UNIT ++#else ++ ++# include ++# include ++# include ++# include ++# include "apps.h" ++# include ++# include ++# include ++# include ++# include ++# include ++ ++typedef enum OPTION_choice { ++ OPT_ERR = -1, OPT_EOF = 0, OPT_HELP, ++ OPT_INFORM, OPT_OUTFORM, OPT_IN, OPT_OUT, OPT_TEXT, OPT_C, ++ OPT_CHECK, OPT_LIST_CURVES, OPT_NO_SEED, OPT_NOOUT, OPT_NAME, ++ OPT_CONV_FORM, OPT_PARAM_ENC, OPT_GENKEY, OPT_RAND, OPT_ENGINE ++} OPTION_CHOICE; ++ ++OPTIONS ecparam_options[] = { ++ {"help", OPT_HELP, '-', "Display this summary"}, ++ {"inform", OPT_INFORM, 'F', "Input format - default PEM (DER or PEM)"}, ++ {"outform", OPT_OUTFORM, 'F', "Output format - default PEM"}, ++ {"in", OPT_IN, '<', "Input file - default stdin"}, ++ {"out", OPT_OUT, '>', "Output file - default stdout"}, ++ {"text", OPT_TEXT, '-', "Print the ec parameters in text form"}, ++ {"C", OPT_C, '-', "Print a 'C' function creating the parameters"}, ++ {"check", OPT_CHECK, '-', "Validate the ec parameters"}, ++ {"list_curves", OPT_LIST_CURVES, '-', ++ "Prints a list of all curve 'short names'"}, ++ {"no_seed", OPT_NO_SEED, '-', ++ "If 'explicit' parameters are chosen do not use the seed"}, ++ {"noout", OPT_NOOUT, '-', "Do not print the ec parameter"}, ++ {"name", OPT_NAME, 's', ++ "Use the ec parameters with specified 'short name'"}, ++ {"conv_form", OPT_CONV_FORM, 's', "Specifies the point conversion form "}, ++ {"param_enc", OPT_PARAM_ENC, 's', ++ "Specifies the way the ec parameters are encoded"}, ++ {"genkey", OPT_GENKEY, '-', "Generate ec key"}, ++ {"rand", OPT_RAND, 's', "Files to use for random number input"}, ++# ifndef OPENSSL_NO_ENGINE ++ {"engine", OPT_ENGINE, 's', "Use engine, possibly a hardware device"}, ++# endif ++ {NULL} ++}; ++ ++static OPT_PAIR forms[] = { ++ {"compressed", POINT_CONVERSION_COMPRESSED}, ++ {"uncompressed", POINT_CONVERSION_UNCOMPRESSED}, ++ {"hybrid", POINT_CONVERSION_HYBRID}, ++ {NULL} ++}; ++ ++static OPT_PAIR encodings[] = { ++ {"named_curve", OPENSSL_EC_NAMED_CURVE}, ++ {"explicit", 0}, ++ {NULL} ++}; ++ ++int ecparam_main(int argc, char **argv) ++{ ++ ENGINE *e = NULL; ++ BIGNUM *ec_gen = NULL, *ec_order = NULL, *ec_cofactor = NULL; ++ BIGNUM *ec_p = NULL, *ec_a = NULL, *ec_b = NULL; ++ BIO *in = NULL, *out = NULL; ++ EC_GROUP *group = NULL; ++ point_conversion_form_t form = POINT_CONVERSION_UNCOMPRESSED; ++ char *curve_name = NULL, *inrand = NULL; ++ char *infile = NULL, *outfile = NULL, *prog; ++ unsigned char *buffer = NULL; ++ OPTION_CHOICE o; ++ int asn1_flag = OPENSSL_EC_NAMED_CURVE, new_asn1_flag = 0; ++ int informat = FORMAT_PEM, outformat = FORMAT_PEM, noout = 0, C = 0; ++ int ret = 1, private = 0; ++ int list_curves = 0, no_seed = 0, check = 0, new_form = 0; ++ int text = 0, i, need_rand = 0, genkey = 0; ++ ++ prog = opt_init(argc, argv, ecparam_options); ++ while ((o = opt_next()) != OPT_EOF) { ++ switch (o) { ++ case OPT_EOF: ++ case OPT_ERR: ++ opthelp: ++ BIO_printf(bio_err, "%s: Use -help for summary.\n", prog); ++ goto end; ++ case OPT_HELP: ++ opt_help(ecparam_options); ++ ret = 0; ++ goto end; ++ case OPT_INFORM: ++ if (!opt_format(opt_arg(), OPT_FMT_PEMDER, &informat)) ++ goto opthelp; ++ break; ++ case OPT_IN: ++ infile = opt_arg(); ++ break; ++ case OPT_OUTFORM: ++ if (!opt_format(opt_arg(), OPT_FMT_PEMDER, &outformat)) ++ goto opthelp; ++ break; ++ case OPT_OUT: ++ outfile = opt_arg(); ++ break; ++ case OPT_TEXT: ++ text = 1; ++ break; ++ case OPT_C: ++ C = 1; ++ break; ++ case OPT_CHECK: ++ check = 1; ++ break; ++ case OPT_LIST_CURVES: ++ list_curves = 1; ++ break; ++ case OPT_NO_SEED: ++ no_seed = 1; ++ break; ++ case OPT_NOOUT: ++ noout = 1; ++ break; ++ case OPT_NAME: ++ curve_name = opt_arg(); ++ break; ++ case OPT_CONV_FORM: ++ if (!opt_pair(opt_arg(), forms, &new_form)) ++ goto opthelp; ++ form = new_form; ++ new_form = 1; ++ break; ++ case OPT_PARAM_ENC: ++ if (!opt_pair(opt_arg(), encodings, &asn1_flag)) ++ goto opthelp; ++ new_asn1_flag = 1; ++ break; ++ case OPT_GENKEY: ++ genkey = need_rand = 1; ++ break; ++ case OPT_RAND: ++ inrand = opt_arg(); ++ need_rand = 1; ++ break; ++ case OPT_ENGINE: ++ e = setup_engine(opt_arg(), 0); ++ break; ++ } ++ } ++ argc = opt_num_rest(); ++ if (argc != 0) ++ goto opthelp; ++ ++ private = genkey ? 1 : 0; ++ ++ in = bio_open_default(infile, 'r', informat); ++ if (in == NULL) ++ goto end; ++ out = bio_open_owner(outfile, outformat, private); ++ if (out == NULL) ++ goto end; ++ ++ if (list_curves) { ++ EC_builtin_curve *curves = NULL; ++ size_t crv_len = EC_get_builtin_curves(NULL, 0); ++ size_t n; ++ ++ curves = app_malloc((int)sizeof(*curves) * crv_len, "list curves"); ++ if (!EC_get_builtin_curves(curves, crv_len)) { ++ OPENSSL_free(curves); ++ goto end; ++ } ++ ++ for (n = 0; n < crv_len; n++) { ++ const char *comment; ++ const char *sname; ++ comment = curves[n].comment; ++ sname = OBJ_nid2sn(curves[n].nid); ++ if (comment == NULL) ++ comment = "CURVE DESCRIPTION NOT AVAILABLE"; ++ if (sname == NULL) ++ sname = ""; ++ ++ BIO_printf(out, " %-10s: ", sname); ++ BIO_printf(out, "%s\n", comment); ++ } ++ ++ OPENSSL_free(curves); ++ ret = 0; ++ goto end; ++ } ++ ++ if (curve_name != NULL) { ++ int nid; ++ ++ /* ++ * workaround for the SECG curve names secp192r1 and secp256r1 (which ++ * are the same as the curves prime192v1 and prime256v1 defined in ++ * X9.62) ++ */ ++ if (strcmp(curve_name, "secp192r1") == 0) { ++ BIO_printf(bio_err, "using curve name prime192v1 " ++ "instead of secp192r1\n"); ++ nid = NID_X9_62_prime192v1; ++ } else if (strcmp(curve_name, "secp256r1") == 0) { ++ BIO_printf(bio_err, "using curve name prime256v1 " ++ "instead of secp256r1\n"); ++ nid = NID_X9_62_prime256v1; ++ } else ++ nid = OBJ_sn2nid(curve_name); ++ ++ if (nid == 0) ++ nid = EC_curve_nist2nid(curve_name); ++ ++ if (nid == 0) { ++ BIO_printf(bio_err, "unknown curve name (%s)\n", curve_name); ++ goto end; ++ } ++ ++ group = EC_GROUP_new_by_curve_name(nid); ++ if (group == NULL) { ++ BIO_printf(bio_err, "unable to create curve (%s)\n", curve_name); ++ goto end; ++ } ++ EC_GROUP_set_asn1_flag(group, asn1_flag); ++ EC_GROUP_set_point_conversion_form(group, form); ++ } else if (informat == FORMAT_ASN1) ++ group = d2i_ECPKParameters_bio(in, NULL); ++ else ++ group = PEM_read_bio_ECPKParameters(in, NULL, NULL, NULL); ++ if (group == NULL) { ++ BIO_printf(bio_err, "unable to load elliptic curve parameters\n"); ++ ERR_print_errors(bio_err); ++ goto end; ++ } ++ ++ if (new_form) ++ EC_GROUP_set_point_conversion_form(group, form); ++ ++ if (new_asn1_flag) ++ EC_GROUP_set_asn1_flag(group, asn1_flag); ++ ++ if (no_seed) { ++ EC_GROUP_set_seed(group, NULL, 0); ++ } ++ ++ if (text) { ++ if (!ECPKParameters_print(out, group, 0)) ++ goto end; ++ } ++ ++ if (check) { ++ BIO_printf(bio_err, "checking elliptic curve parameters: "); ++ if (!EC_GROUP_check(group, NULL)) { ++ BIO_printf(bio_err, "failed\n"); ++ ERR_print_errors(bio_err); ++ goto end; ++ } ++ BIO_printf(bio_err, "ok\n"); ++ ++ } ++ ++ if (C) { ++ size_t buf_len = 0, tmp_len = 0; ++ const EC_POINT *point; ++ int is_prime, len = 0; ++ const EC_METHOD *meth = EC_GROUP_method_of(group); ++ ++ if ((ec_p = BN_new()) == NULL ++ || (ec_a = BN_new()) == NULL ++ || (ec_b = BN_new()) == NULL ++ || (ec_gen = BN_new()) == NULL ++ || (ec_order = BN_new()) == NULL ++ || (ec_cofactor = BN_new()) == NULL) { ++ perror("Can't allocate BN"); ++ goto end; ++ } ++ ++ is_prime = (EC_METHOD_get_field_type(meth) == NID_X9_62_prime_field); ++ if (!is_prime) { ++ BIO_printf(bio_err, "Can only handle X9.62 prime fields\n"); ++ goto end; ++ } ++ ++ if (!EC_GROUP_get_curve_GFp(group, ec_p, ec_a, ec_b, NULL)) ++ goto end; ++ ++ if ((point = EC_GROUP_get0_generator(group)) == NULL) ++ goto end; ++ if (!EC_POINT_point2bn(group, point, ++ EC_GROUP_get_point_conversion_form(group), ++ ec_gen, NULL)) ++ goto end; ++ if (!EC_GROUP_get_order(group, ec_order, NULL)) ++ goto end; ++ if (!EC_GROUP_get_cofactor(group, ec_cofactor, NULL)) ++ goto end; ++ ++ if (!ec_p || !ec_a || !ec_b || !ec_gen || !ec_order || !ec_cofactor) ++ goto end; ++ ++ len = BN_num_bits(ec_order); ++ ++ if ((tmp_len = (size_t)BN_num_bytes(ec_p)) > buf_len) ++ buf_len = tmp_len; ++ if ((tmp_len = (size_t)BN_num_bytes(ec_a)) > buf_len) ++ buf_len = tmp_len; ++ if ((tmp_len = (size_t)BN_num_bytes(ec_b)) > buf_len) ++ buf_len = tmp_len; ++ if ((tmp_len = (size_t)BN_num_bytes(ec_gen)) > buf_len) ++ buf_len = tmp_len; ++ if ((tmp_len = (size_t)BN_num_bytes(ec_order)) > buf_len) ++ buf_len = tmp_len; ++ if ((tmp_len = (size_t)BN_num_bytes(ec_cofactor)) > buf_len) ++ buf_len = tmp_len; ++ ++ buffer = app_malloc(buf_len, "BN buffer"); ++ ++ BIO_printf(out, "EC_GROUP *get_ec_group_%d(void)\n{\n", len); ++ print_bignum_var(out, ec_p, "ec_p", len, buffer); ++ print_bignum_var(out, ec_a, "ec_a", len, buffer); ++ print_bignum_var(out, ec_b, "ec_b", len, buffer); ++ print_bignum_var(out, ec_gen, "ec_gen", len, buffer); ++ print_bignum_var(out, ec_order, "ec_order", len, buffer); ++ print_bignum_var(out, ec_cofactor, "ec_cofactor", len, buffer); ++ BIO_printf(out, " int ok = 0;\n" ++ " EC_GROUP *group = NULL;\n" ++ " EC_POINT *point = NULL;\n" ++ " BIGNUM *tmp_1 = NULL;\n" ++ " BIGNUM *tmp_2 = NULL;\n" ++ " BIGNUM *tmp_3 = NULL;\n" ++ "\n"); ++ ++ BIO_printf(out, " if ((tmp_1 = BN_bin2bn(ec_p_%d, sizeof (ec_p_%d), NULL)) == NULL)\n" ++ " goto err;\n", len, len); ++ BIO_printf(out, " if ((tmp_2 = BN_bin2bn(ec_a_%d, sizeof (ec_a_%d), NULL)) == NULL)\n" ++ " goto err;\n", len, len); ++ BIO_printf(out, " if ((tmp_3 = BN_bin2bn(ec_b_%d, sizeof (ec_b_%d), NULL)) == NULL)\n" ++ " goto err;\n", len, len); ++ BIO_printf(out, " if ((group = EC_GROUP_new_curve_GFp(tmp_1, tmp_2, tmp_3, NULL)) == NULL)\n" ++ " goto err;\n" ++ "\n"); ++ BIO_printf(out, " /* build generator */\n"); ++ BIO_printf(out, " if ((tmp_1 = BN_bin2bn(ec_gen_%d, sizeof (ec_gen_%d), tmp_1)) == NULL)\n" ++ " goto err;\n", len, len); ++ BIO_printf(out, " point = EC_POINT_bn2point(group, tmp_1, NULL, NULL);\n"); ++ BIO_printf(out, " if (point == NULL)\n" ++ " goto err;\n"); ++ BIO_printf(out, " if ((tmp_2 = BN_bin2bn(ec_order_%d, sizeof (ec_order_%d), tmp_2)) == NULL)\n" ++ " goto err;\n", len, len); ++ BIO_printf(out, " if ((tmp_3 = BN_bin2bn(ec_cofactor_%d, sizeof (ec_cofactor_%d), tmp_3)) == NULL)\n" ++ " goto err;\n", len, len); ++ BIO_printf(out, " if (!EC_GROUP_set_generator(group, point, tmp_2, tmp_3))\n" ++ " goto err;\n" ++ "ok = 1;" ++ "\n"); ++ BIO_printf(out, "err:\n" ++ " BN_free(tmp_1);\n" ++ " BN_free(tmp_2);\n" ++ " BN_free(tmp_3);\n" ++ " EC_POINT_free(point);\n" ++ " if (!ok) {\n" ++ " EC_GROUP_free(group);\n" ++ " return NULL;\n" ++ " }\n" ++ " return (group);\n" ++ "}\n"); ++ } ++ ++ if (!noout) { ++ if (outformat == FORMAT_ASN1) ++ i = i2d_ECPKParameters_bio(out, group); ++ else ++ i = PEM_write_bio_ECPKParameters(out, group); ++ if (!i) { ++ BIO_printf(bio_err, "unable to write elliptic " ++ "curve parameters\n"); ++ ERR_print_errors(bio_err); ++ goto end; ++ } ++ } ++ ++ if (need_rand) { ++ app_RAND_load_file(NULL, (inrand != NULL)); ++ if (inrand != NULL) ++ BIO_printf(bio_err, "%ld semi-random bytes loaded\n", ++ app_RAND_load_files(inrand)); ++ } ++ ++ if (genkey) { ++ EC_KEY *eckey = EC_KEY_new(); ++ ++ if (eckey == NULL) ++ goto end; ++ ++ assert(need_rand); ++ ++ if (EC_KEY_set_group(eckey, group) == 0) { ++ BIO_printf(bio_err, "unable to set group when generating key\n"); ++ EC_KEY_free(eckey); ++ ERR_print_errors(bio_err); ++ goto end; ++ } ++ ++ if (!EC_KEY_generate_key(eckey)) { ++ BIO_printf(bio_err, "unable to generate key\n"); ++ EC_KEY_free(eckey); ++ ERR_print_errors(bio_err); ++ goto end; ++ } ++ assert(private); ++ if (outformat == FORMAT_ASN1) ++ i = i2d_ECPrivateKey_bio(out, eckey); ++ else ++ i = PEM_write_bio_ECPrivateKey(out, eckey, NULL, ++ NULL, 0, NULL, NULL); ++ EC_KEY_free(eckey); ++ } ++ ++ if (need_rand) ++ app_RAND_write_file(NULL); ++ ++ ret = 0; ++ end: ++ BN_free(ec_p); ++ BN_free(ec_a); ++ BN_free(ec_b); ++ BN_free(ec_gen); ++ BN_free(ec_order); ++ BN_free(ec_cofactor); ++ OPENSSL_free(buffer); ++ EC_GROUP_free(group); ++ release_engine(e); ++ BIO_free(in); ++ BIO_free_all(out); ++ return (ret); ++} ++ ++#endif +diff --git a/CryptoPkg/Library/OpensslLib/openssl/apps/enc.c b/CryptoPkg/Library/OpensslLib/openssl/apps/enc.c +new file mode 100644 +index 0000000..c66ad93 +--- /dev/null ++++ b/CryptoPkg/Library/OpensslLib/openssl/apps/enc.c +@@ -0,0 +1,604 @@ ++/* ++ * Copyright 1995-2016 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 ++ * in the file LICENSE in the source distribution or at ++ * https://www.openssl.org/source/license.html ++ */ ++ ++#include ++#include ++#include ++#include ++#include "apps.h" ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#ifndef OPENSSL_NO_COMP ++# include ++#endif ++#include ++ ++#undef SIZE ++#undef BSIZE ++#define SIZE (512) ++#define BSIZE (8*1024) ++ ++static int set_hex(char *in, unsigned char *out, int size); ++static void show_ciphers(const OBJ_NAME *name, void *bio_); ++ ++typedef enum OPTION_choice { ++ OPT_ERR = -1, OPT_EOF = 0, OPT_HELP, ++ OPT_LIST, ++ OPT_E, OPT_IN, OPT_OUT, OPT_PASS, OPT_ENGINE, OPT_D, OPT_P, OPT_V, ++ OPT_NOPAD, OPT_SALT, OPT_NOSALT, OPT_DEBUG, OPT_UPPER_P, OPT_UPPER_A, ++ OPT_A, OPT_Z, OPT_BUFSIZE, OPT_K, OPT_KFILE, OPT_UPPER_K, OPT_NONE, ++ OPT_UPPER_S, OPT_IV, OPT_MD, OPT_CIPHER ++} OPTION_CHOICE; ++ ++OPTIONS enc_options[] = { ++ {"help", OPT_HELP, '-', "Display this summary"}, ++ {"ciphers", OPT_LIST, '-', "List ciphers"}, ++ {"in", OPT_IN, '<', "Input file"}, ++ {"out", OPT_OUT, '>', "Output file"}, ++ {"pass", OPT_PASS, 's', "Passphrase source"}, ++ {"e", OPT_E, '-', "Encrypt"}, ++ {"d", OPT_D, '-', "Decrypt"}, ++ {"p", OPT_P, '-', "Print the iv/key"}, ++ {"P", OPT_UPPER_P, '-', "Print the iv/key and exit"}, ++ {"v", OPT_V, '-', "Verbose output"}, ++ {"nopad", OPT_NOPAD, '-', "Disable standard block padding"}, ++ {"salt", OPT_SALT, '-', "Use salt in the KDF (default)"}, ++ {"nosalt", OPT_NOSALT, '-', "Do not use salt in the KDF"}, ++ {"debug", OPT_DEBUG, '-', "Print debug info"}, ++ {"a", OPT_A, '-', "Base64 encode/decode, depending on encryption flag"}, ++ {"base64", OPT_A, '-', "Same as option -a"}, ++ {"A", OPT_UPPER_A, '-', ++ "Used with -[base64|a] to specify base64 buffer as a single line"}, ++ {"bufsize", OPT_BUFSIZE, 's', "Buffer size"}, ++ {"k", OPT_K, 's', "Passphrase"}, ++ {"kfile", OPT_KFILE, '<', "Read passphrase from file"}, ++ {"K", OPT_UPPER_K, 's', "Raw key, in hex"}, ++ {"S", OPT_UPPER_S, 's', "Salt, in hex"}, ++ {"iv", OPT_IV, 's', "IV in hex"}, ++ {"md", OPT_MD, 's', "Use specified digest to create a key from the passphrase"}, ++ {"none", OPT_NONE, '-', "Don't encrypt"}, ++ {"", OPT_CIPHER, '-', "Any supported cipher"}, ++#ifdef ZLIB ++ {"z", OPT_Z, '-', "Use zlib as the 'encryption'"}, ++#endif ++#ifndef OPENSSL_NO_ENGINE ++ {"engine", OPT_ENGINE, 's', "Use engine, possibly a hardware device"}, ++#endif ++ {NULL} ++}; ++ ++int enc_main(int argc, char **argv) ++{ ++ static char buf[128]; ++ static const char magic[] = "Salted__"; ++ ENGINE *e = NULL; ++ BIO *in = NULL, *out = NULL, *b64 = NULL, *benc = NULL, *rbio = ++ NULL, *wbio = NULL; ++ EVP_CIPHER_CTX *ctx = NULL; ++ const EVP_CIPHER *cipher = NULL, *c; ++ const EVP_MD *dgst = NULL; ++ char *hkey = NULL, *hiv = NULL, *hsalt = NULL, *p; ++ char *infile = NULL, *outfile = NULL, *prog; ++ char *str = NULL, *passarg = NULL, *pass = NULL, *strbuf = NULL; ++ char mbuf[sizeof magic - 1]; ++ OPTION_CHOICE o; ++ int bsize = BSIZE, verbose = 0, debug = 0, olb64 = 0, nosalt = 0; ++ int enc = 1, printkey = 0, i, k; ++ int base64 = 0, informat = FORMAT_BINARY, outformat = FORMAT_BINARY; ++ int ret = 1, inl, nopad = 0; ++ unsigned char key[EVP_MAX_KEY_LENGTH], iv[EVP_MAX_IV_LENGTH]; ++ unsigned char *buff = NULL, salt[PKCS5_SALT_LEN]; ++ long n; ++#ifdef ZLIB ++ int do_zlib = 0; ++ BIO *bzl = NULL; ++#endif ++ ++ /* first check the program name */ ++ prog = opt_progname(argv[0]); ++ if (strcmp(prog, "base64") == 0) ++ base64 = 1; ++#ifdef ZLIB ++ else if (strcmp(prog, "zlib") == 0) ++ do_zlib = 1; ++#endif ++ else { ++ cipher = EVP_get_cipherbyname(prog); ++ if (cipher == NULL && strcmp(prog, "enc") != 0) { ++ BIO_printf(bio_err, "%s is not a known cipher\n", prog); ++ goto end; ++ } ++ } ++ ++ prog = opt_init(argc, argv, enc_options); ++ while ((o = opt_next()) != OPT_EOF) { ++ switch (o) { ++ case OPT_EOF: ++ case OPT_ERR: ++ opthelp: ++ BIO_printf(bio_err, "%s: Use -help for summary.\n", prog); ++ goto end; ++ case OPT_HELP: ++ opt_help(enc_options); ++ ret = 0; ++ goto end; ++ case OPT_LIST: ++ BIO_printf(bio_err, "Supported ciphers:\n"); ++ OBJ_NAME_do_all_sorted(OBJ_NAME_TYPE_CIPHER_METH, ++ show_ciphers, bio_err); ++ BIO_printf(bio_err, "\n"); ++ goto end; ++ case OPT_E: ++ enc = 1; ++ break; ++ case OPT_IN: ++ infile = opt_arg(); ++ break; ++ case OPT_OUT: ++ outfile = opt_arg(); ++ break; ++ case OPT_PASS: ++ passarg = opt_arg(); ++ break; ++ case OPT_ENGINE: ++ e = setup_engine(opt_arg(), 0); ++ break; ++ case OPT_D: ++ enc = 0; ++ break; ++ case OPT_P: ++ printkey = 1; ++ break; ++ case OPT_V: ++ verbose = 1; ++ break; ++ case OPT_NOPAD: ++ nopad = 1; ++ break; ++ case OPT_SALT: ++ nosalt = 0; ++ break; ++ case OPT_NOSALT: ++ nosalt = 1; ++ break; ++ case OPT_DEBUG: ++ debug = 1; ++ break; ++ case OPT_UPPER_P: ++ printkey = 2; ++ break; ++ case OPT_UPPER_A: ++ olb64 = 1; ++ break; ++ case OPT_A: ++ base64 = 1; ++ break; ++ case OPT_Z: ++#ifdef ZLIB ++ do_zlib = 1; ++#endif ++ break; ++ case OPT_BUFSIZE: ++ p = opt_arg(); ++ i = (int)strlen(p) - 1; ++ k = i >= 1 && p[i] == 'k'; ++ if (k) ++ p[i] = '\0'; ++ if (!opt_long(opt_arg(), &n) ++ || n < 0 || (k && n >= LONG_MAX / 1024)) ++ goto opthelp; ++ if (k) ++ n *= 1024; ++ bsize = (int)n; ++ break; ++ case OPT_K: ++ str = opt_arg(); ++ break; ++ case OPT_KFILE: ++ in = bio_open_default(opt_arg(), 'r', FORMAT_TEXT); ++ if (in == NULL) ++ goto opthelp; ++ i = BIO_gets(in, buf, sizeof buf); ++ BIO_free(in); ++ in = NULL; ++ if (i <= 0) { ++ BIO_printf(bio_err, ++ "%s Can't read key from %s\n", prog, opt_arg()); ++ goto opthelp; ++ } ++ while (--i > 0 && (buf[i] == '\r' || buf[i] == '\n')) ++ buf[i] = '\0'; ++ if (i <= 0) { ++ BIO_printf(bio_err, "%s: zero length password\n", prog); ++ goto opthelp; ++ } ++ str = buf; ++ break; ++ case OPT_UPPER_K: ++ hkey = opt_arg(); ++ break; ++ case OPT_UPPER_S: ++ hsalt = opt_arg(); ++ break; ++ case OPT_IV: ++ hiv = opt_arg(); ++ break; ++ case OPT_MD: ++ if (!opt_md(opt_arg(), &dgst)) ++ goto opthelp; ++ break; ++ case OPT_CIPHER: ++ if (!opt_cipher(opt_unknown(), &c)) ++ goto opthelp; ++ cipher = c; ++ break; ++ case OPT_NONE: ++ cipher = NULL; ++ break; ++ } ++ } ++ ++ if (cipher && EVP_CIPHER_flags(cipher) & EVP_CIPH_FLAG_AEAD_CIPHER) { ++ BIO_printf(bio_err, "%s: AEAD ciphers not supported\n", prog); ++ goto end; ++ } ++ ++ if (cipher && (EVP_CIPHER_mode(cipher) == EVP_CIPH_XTS_MODE)) { ++ BIO_printf(bio_err, "%s XTS ciphers not supported\n", prog); ++ goto end; ++ } ++ ++ if (dgst == NULL) ++ dgst = EVP_sha256(); ++ ++ /* It must be large enough for a base64 encoded line */ ++ if (base64 && bsize < 80) ++ bsize = 80; ++ if (verbose) ++ BIO_printf(bio_err, "bufsize=%d\n", bsize); ++ ++#ifdef ZLIB ++ if (!do_zlib) ++#endif ++ if (base64) { ++ if (enc) ++ outformat = FORMAT_BASE64; ++ else ++ informat = FORMAT_BASE64; ++ } ++ ++ strbuf = app_malloc(SIZE, "strbuf"); ++ buff = app_malloc(EVP_ENCODE_LENGTH(bsize), "evp buffer"); ++ ++ if (infile == NULL) { ++ unbuffer(stdin); ++ in = dup_bio_in(informat); ++ } else ++ in = bio_open_default(infile, 'r', informat); ++ if (in == NULL) ++ goto end; ++ ++ if (!str && passarg) { ++ if (!app_passwd(passarg, NULL, &pass, NULL)) { ++ BIO_printf(bio_err, "Error getting password\n"); ++ goto end; ++ } ++ str = pass; ++ } ++ ++ if ((str == NULL) && (cipher != NULL) && (hkey == NULL)) { ++ if (1) { ++#ifndef OPENSSL_NO_UI ++ for (;;) { ++ char prompt[200]; ++ ++ BIO_snprintf(prompt, sizeof prompt, "enter %s %s password:", ++ OBJ_nid2ln(EVP_CIPHER_nid(cipher)), ++ (enc) ? "encryption" : "decryption"); ++ strbuf[0] = '\0'; ++ i = EVP_read_pw_string((char *)strbuf, SIZE, prompt, enc); ++ if (i == 0) { ++ if (strbuf[0] == '\0') { ++ ret = 1; ++ goto end; ++ } ++ str = strbuf; ++ break; ++ } ++ if (i < 0) { ++ BIO_printf(bio_err, "bad password read\n"); ++ goto end; ++ } ++ } ++ } else { ++#endif ++ BIO_printf(bio_err, "password required\n"); ++ goto end; ++ } ++ } ++ ++ out = bio_open_default(outfile, 'w', outformat); ++ if (out == NULL) ++ goto end; ++ ++ if (debug) { ++ BIO_set_callback(in, BIO_debug_callback); ++ BIO_set_callback(out, BIO_debug_callback); ++ BIO_set_callback_arg(in, (char *)bio_err); ++ BIO_set_callback_arg(out, (char *)bio_err); ++ } ++ ++ rbio = in; ++ wbio = out; ++ ++#ifdef ZLIB ++ if (do_zlib) { ++ if ((bzl = BIO_new(BIO_f_zlib())) == NULL) ++ goto end; ++ if (debug) { ++ BIO_set_callback(bzl, BIO_debug_callback); ++ BIO_set_callback_arg(bzl, (char *)bio_err); ++ } ++ if (enc) ++ wbio = BIO_push(bzl, wbio); ++ else ++ rbio = BIO_push(bzl, rbio); ++ } ++#endif ++ ++ if (base64) { ++ if ((b64 = BIO_new(BIO_f_base64())) == NULL) ++ goto end; ++ if (debug) { ++ BIO_set_callback(b64, BIO_debug_callback); ++ BIO_set_callback_arg(b64, (char *)bio_err); ++ } ++ if (olb64) ++ BIO_set_flags(b64, BIO_FLAGS_BASE64_NO_NL); ++ if (enc) ++ wbio = BIO_push(b64, wbio); ++ else ++ rbio = BIO_push(b64, rbio); ++ } ++ ++ if (cipher != NULL) { ++ /* ++ * Note that str is NULL if a key was passed on the command line, so ++ * we get no salt in that case. Is this a bug? ++ */ ++ if (str != NULL) { ++ /* ++ * Salt handling: if encrypting generate a salt and write to ++ * output BIO. If decrypting read salt from input BIO. ++ */ ++ unsigned char *sptr; ++ size_t str_len = strlen(str); ++ ++ if (nosalt) ++ sptr = NULL; ++ else { ++ if (enc) { ++ if (hsalt) { ++ if (!set_hex(hsalt, salt, sizeof salt)) { ++ BIO_printf(bio_err, "invalid hex salt value\n"); ++ goto end; ++ } ++ } else if (RAND_bytes(salt, sizeof salt) <= 0) ++ goto end; ++ /* ++ * If -P option then don't bother writing ++ */ ++ if ((printkey != 2) ++ && (BIO_write(wbio, magic, ++ sizeof magic - 1) != sizeof magic - 1 ++ || BIO_write(wbio, ++ (char *)salt, ++ sizeof salt) != sizeof salt)) { ++ BIO_printf(bio_err, "error writing output file\n"); ++ goto end; ++ } ++ } else if (BIO_read(rbio, mbuf, sizeof mbuf) != sizeof mbuf ++ || BIO_read(rbio, ++ (unsigned char *)salt, ++ sizeof salt) != sizeof salt) { ++ BIO_printf(bio_err, "error reading input file\n"); ++ goto end; ++ } else if (memcmp(mbuf, magic, sizeof magic - 1)) { ++ BIO_printf(bio_err, "bad magic number\n"); ++ goto end; ++ } ++ ++ sptr = salt; ++ } ++ ++ if (!EVP_BytesToKey(cipher, dgst, sptr, ++ (unsigned char *)str, ++ str_len, 1, key, iv)) { ++ BIO_printf(bio_err, "EVP_BytesToKey failed\n"); ++ goto end; ++ } ++ /* ++ * zero the complete buffer or the string passed from the command ++ * line bug picked up by Larry J. Hughes Jr. ++ */ ++ if (str == strbuf) ++ OPENSSL_cleanse(str, SIZE); ++ else ++ OPENSSL_cleanse(str, str_len); ++ } ++ if (hiv != NULL) { ++ int siz = EVP_CIPHER_iv_length(cipher); ++ if (siz == 0) { ++ BIO_printf(bio_err, "warning: iv not use by this cipher\n"); ++ } else if (!set_hex(hiv, iv, sizeof iv)) { ++ BIO_printf(bio_err, "invalid hex iv value\n"); ++ goto end; ++ } ++ } ++ if ((hiv == NULL) && (str == NULL) ++ && EVP_CIPHER_iv_length(cipher) != 0) { ++ /* ++ * No IV was explicitly set and no IV was generated during ++ * EVP_BytesToKey. Hence the IV is undefined, making correct ++ * decryption impossible. ++ */ ++ BIO_printf(bio_err, "iv undefined\n"); ++ goto end; ++ } ++ if ((hkey != NULL) && !set_hex(hkey, key, EVP_CIPHER_key_length(cipher))) { ++ BIO_printf(bio_err, "invalid hex key value\n"); ++ goto end; ++ } ++ ++ if ((benc = BIO_new(BIO_f_cipher())) == NULL) ++ goto end; ++ ++ /* ++ * Since we may be changing parameters work on the encryption context ++ * rather than calling BIO_set_cipher(). ++ */ ++ ++ BIO_get_cipher_ctx(benc, &ctx); ++ ++ if (!EVP_CipherInit_ex(ctx, cipher, NULL, NULL, NULL, enc)) { ++ BIO_printf(bio_err, "Error setting cipher %s\n", ++ EVP_CIPHER_name(cipher)); ++ ERR_print_errors(bio_err); ++ goto end; ++ } ++ ++ if (nopad) ++ EVP_CIPHER_CTX_set_padding(ctx, 0); ++ ++ if (!EVP_CipherInit_ex(ctx, NULL, NULL, key, iv, enc)) { ++ BIO_printf(bio_err, "Error setting cipher %s\n", ++ EVP_CIPHER_name(cipher)); ++ ERR_print_errors(bio_err); ++ goto end; ++ } ++ ++ if (debug) { ++ BIO_set_callback(benc, BIO_debug_callback); ++ BIO_set_callback_arg(benc, (char *)bio_err); ++ } ++ ++ if (printkey) { ++ if (!nosalt) { ++ printf("salt="); ++ for (i = 0; i < (int)sizeof(salt); i++) ++ printf("%02X", salt[i]); ++ printf("\n"); ++ } ++ if (EVP_CIPHER_key_length(cipher) > 0) { ++ printf("key="); ++ for (i = 0; i < EVP_CIPHER_key_length(cipher); i++) ++ printf("%02X", key[i]); ++ printf("\n"); ++ } ++ if (EVP_CIPHER_iv_length(cipher) > 0) { ++ printf("iv ="); ++ for (i = 0; i < EVP_CIPHER_iv_length(cipher); i++) ++ printf("%02X", iv[i]); ++ printf("\n"); ++ } ++ if (printkey == 2) { ++ ret = 0; ++ goto end; ++ } ++ } ++ } ++ ++ /* Only encrypt/decrypt as we write the file */ ++ if (benc != NULL) ++ wbio = BIO_push(benc, wbio); ++ ++ for (;;) { ++ inl = BIO_read(rbio, (char *)buff, bsize); ++ if (inl <= 0) ++ break; ++ if (BIO_write(wbio, (char *)buff, inl) != inl) { ++ BIO_printf(bio_err, "error writing output file\n"); ++ goto end; ++ } ++ } ++ if (!BIO_flush(wbio)) { ++ BIO_printf(bio_err, "bad decrypt\n"); ++ goto end; ++ } ++ ++ ret = 0; ++ if (verbose) { ++ BIO_printf(bio_err, "bytes read :%8"PRIu64"\n", BIO_number_read(in)); ++ BIO_printf(bio_err, "bytes written:%8"PRIu64"\n", BIO_number_written(out)); ++ } ++ end: ++ ERR_print_errors(bio_err); ++ OPENSSL_free(strbuf); ++ OPENSSL_free(buff); ++ BIO_free(in); ++ BIO_free_all(out); ++ BIO_free(benc); ++ BIO_free(b64); ++#ifdef ZLIB ++ BIO_free(bzl); ++#endif ++ release_engine(e); ++ OPENSSL_free(pass); ++ return (ret); ++} ++ ++static void show_ciphers(const OBJ_NAME *name, void *bio_) ++{ ++ BIO *bio = bio_; ++ static int n; ++ ++ if (!islower((unsigned char)*name->name)) ++ return; ++ ++ BIO_printf(bio, "-%-25s", name->name); ++ if (++n == 3) { ++ BIO_printf(bio, "\n"); ++ n = 0; ++ } else ++ BIO_printf(bio, " "); ++} ++ ++static int set_hex(char *in, unsigned char *out, int size) ++{ ++ int i, n; ++ unsigned char j; ++ ++ n = strlen(in); ++ if (n > (size * 2)) { ++ BIO_printf(bio_err, "hex string is too long\n"); ++ return (0); ++ } ++ memset(out, 0, size); ++ for (i = 0; i < n; i++) { ++ j = (unsigned char)*in; ++ *(in++) = '\0'; ++ if (j == 0) ++ break; ++ if (!isxdigit(j)) { ++ BIO_printf(bio_err, "non-hex digit\n"); ++ return (0); ++ } ++ j = (unsigned char)OPENSSL_hexchar2int(j); ++ if (i & 1) ++ out[i / 2] |= j; ++ else ++ out[i / 2] = (j << 4); ++ } ++ return (1); ++} +diff --git a/CryptoPkg/Library/OpensslLib/openssl/apps/engine.c b/CryptoPkg/Library/OpensslLib/openssl/apps/engine.c +new file mode 100644 +index 0000000..ffd3137 +--- /dev/null ++++ b/CryptoPkg/Library/OpensslLib/openssl/apps/engine.c +@@ -0,0 +1,445 @@ ++/* ++ * Copyright 2000-2016 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 ++ * in the file LICENSE in the source distribution or at ++ * https://www.openssl.org/source/license.html ++ */ ++ ++#include ++#ifdef OPENSSL_NO_ENGINE ++NON_EMPTY_TRANSLATION_UNIT ++#else ++ ++# include "apps.h" ++# include ++# include ++# include ++# include ++# include ++# include ++ ++typedef enum OPTION_choice { ++ OPT_ERR = -1, OPT_EOF = 0, OPT_HELP, ++ OPT_C, OPT_T, OPT_TT, OPT_PRE, OPT_POST, ++ OPT_V = 100, OPT_VV, OPT_VVV, OPT_VVVV ++} OPTION_CHOICE; ++ ++OPTIONS engine_options[] = { ++ {OPT_HELP_STR, 1, '-', "Usage: %s [options] engine...\n"}, ++ {OPT_HELP_STR, 1, '-', ++ " engine... Engines to load\n"}, ++ {"help", OPT_HELP, '-', "Display this summary"}, ++ {"v", OPT_V, '-', "List 'control commands' For each specified engine"}, ++ {"vv", OPT_VV, '-', "Also display each command's description"}, ++ {"vvv", OPT_VVV, '-', "Also add the input flags for each command"}, ++ {"vvvv", OPT_VVVV, '-', "Also show internal input flags"}, ++ {"c", OPT_C, '-', "List the capabilities of specified engine"}, ++ {"t", OPT_T, '-', "Check that specified engine is available"}, ++ {"tt", OPT_TT, '-', "Display error trace for unavailable engines"}, ++ {"pre", OPT_PRE, 's', "Run command against the ENGINE before loading it"}, ++ {"post", OPT_POST, 's', "Run command against the ENGINE after loading it"}, ++ {OPT_MORE_STR, OPT_EOF, 1, ++ "Commands are like \"SO_PATH:/lib/libdriver.so\""}, ++ {NULL} ++}; ++ ++static int append_buf(char **buf, int *size, const char *s) ++{ ++ if (*buf == NULL) { ++ *size = 256; ++ *buf = app_malloc(*size, "engine buffer"); ++ **buf = '\0'; ++ } ++ ++ if (strlen(*buf) + strlen(s) >= (unsigned int)*size) { ++ char *tmp; ++ *size += 256; ++ tmp = OPENSSL_realloc(*buf, *size); ++ if (tmp == NULL) { ++ OPENSSL_free(*buf); ++ *buf = NULL; ++ return 0; ++ } ++ *buf = tmp; ++ } ++ ++ if (**buf != '\0') ++ OPENSSL_strlcat(*buf, ", ", *size); ++ OPENSSL_strlcat(*buf, s, *size); ++ ++ return 1; ++} ++ ++static int util_flags(BIO *out, unsigned int flags, const char *indent) ++{ ++ int started = 0, err = 0; ++ /* Indent before displaying input flags */ ++ BIO_printf(out, "%s%s(input flags): ", indent, indent); ++ if (flags == 0) { ++ BIO_printf(out, "\n"); ++ return 1; ++ } ++ /* ++ * If the object is internal, mark it in a way that shows instead of ++ * having it part of all the other flags, even if it really is. ++ */ ++ if (flags & ENGINE_CMD_FLAG_INTERNAL) { ++ BIO_printf(out, "[Internal] "); ++ } ++ ++ if (flags & ENGINE_CMD_FLAG_NUMERIC) { ++ BIO_printf(out, "NUMERIC"); ++ started = 1; ++ } ++ /* ++ * Now we check that no combinations of the mutually exclusive NUMERIC, ++ * STRING, and NO_INPUT flags have been used. Future flags that can be ++ * OR'd together with these would need to added after these to preserve ++ * the testing logic. ++ */ ++ if (flags & ENGINE_CMD_FLAG_STRING) { ++ if (started) { ++ BIO_printf(out, "|"); ++ err = 1; ++ } ++ BIO_printf(out, "STRING"); ++ started = 1; ++ } ++ if (flags & ENGINE_CMD_FLAG_NO_INPUT) { ++ if (started) { ++ BIO_printf(out, "|"); ++ err = 1; ++ } ++ BIO_printf(out, "NO_INPUT"); ++ started = 1; ++ } ++ /* Check for unknown flags */ ++ flags = flags & ~ENGINE_CMD_FLAG_NUMERIC & ++ ~ENGINE_CMD_FLAG_STRING & ++ ~ENGINE_CMD_FLAG_NO_INPUT & ~ENGINE_CMD_FLAG_INTERNAL; ++ if (flags) { ++ if (started) ++ BIO_printf(out, "|"); ++ BIO_printf(out, "<0x%04X>", flags); ++ } ++ if (err) ++ BIO_printf(out, " "); ++ BIO_printf(out, "\n"); ++ return 1; ++} ++ ++static int util_verbose(ENGINE *e, int verbose, BIO *out, const char *indent) ++{ ++ static const int line_wrap = 78; ++ int num; ++ int ret = 0; ++ char *name = NULL; ++ char *desc = NULL; ++ int flags; ++ int xpos = 0; ++ STACK_OF(OPENSSL_STRING) *cmds = NULL; ++ if (!ENGINE_ctrl(e, ENGINE_CTRL_HAS_CTRL_FUNCTION, 0, NULL, NULL) || ++ ((num = ENGINE_ctrl(e, ENGINE_CTRL_GET_FIRST_CMD_TYPE, ++ 0, NULL, NULL)) <= 0)) { ++ return 1; ++ } ++ ++ cmds = sk_OPENSSL_STRING_new_null(); ++ if (!cmds) ++ goto err; ++ ++ do { ++ int len; ++ /* Get the command input flags */ ++ if ((flags = ENGINE_ctrl(e, ENGINE_CTRL_GET_CMD_FLAGS, num, ++ NULL, NULL)) < 0) ++ goto err; ++ if (!(flags & ENGINE_CMD_FLAG_INTERNAL) || verbose >= 4) { ++ /* Get the command name */ ++ if ((len = ENGINE_ctrl(e, ENGINE_CTRL_GET_NAME_LEN_FROM_CMD, num, ++ NULL, NULL)) <= 0) ++ goto err; ++ name = app_malloc(len + 1, "name buffer"); ++ if (ENGINE_ctrl(e, ENGINE_CTRL_GET_NAME_FROM_CMD, num, name, ++ NULL) <= 0) ++ goto err; ++ /* Get the command description */ ++ if ((len = ENGINE_ctrl(e, ENGINE_CTRL_GET_DESC_LEN_FROM_CMD, num, ++ NULL, NULL)) < 0) ++ goto err; ++ if (len > 0) { ++ desc = app_malloc(len + 1, "description buffer"); ++ if (ENGINE_ctrl(e, ENGINE_CTRL_GET_DESC_FROM_CMD, num, desc, ++ NULL) <= 0) ++ goto err; ++ } ++ /* Now decide on the output */ ++ if (xpos == 0) ++ /* Do an indent */ ++ xpos = BIO_puts(out, indent); ++ else ++ /* Otherwise prepend a ", " */ ++ xpos += BIO_printf(out, ", "); ++ if (verbose == 1) { ++ /* ++ * We're just listing names, comma-delimited ++ */ ++ if ((xpos > (int)strlen(indent)) && ++ (xpos + (int)strlen(name) > line_wrap)) { ++ BIO_printf(out, "\n"); ++ xpos = BIO_puts(out, indent); ++ } ++ xpos += BIO_printf(out, "%s", name); ++ } else { ++ /* We're listing names plus descriptions */ ++ BIO_printf(out, "%s: %s\n", name, ++ (desc == NULL) ? "" : desc); ++ /* ... and sometimes input flags */ ++ if ((verbose >= 3) && !util_flags(out, flags, indent)) ++ goto err; ++ xpos = 0; ++ } ++ } ++ OPENSSL_free(name); ++ name = NULL; ++ OPENSSL_free(desc); ++ desc = NULL; ++ /* Move to the next command */ ++ num = ENGINE_ctrl(e, ENGINE_CTRL_GET_NEXT_CMD_TYPE, num, NULL, NULL); ++ } while (num > 0); ++ if (xpos > 0) ++ BIO_printf(out, "\n"); ++ ret = 1; ++ err: ++ sk_OPENSSL_STRING_free(cmds); ++ OPENSSL_free(name); ++ OPENSSL_free(desc); ++ return ret; ++} ++ ++static void util_do_cmds(ENGINE *e, STACK_OF(OPENSSL_STRING) *cmds, ++ BIO *out, const char *indent) ++{ ++ int loop, res, num = sk_OPENSSL_STRING_num(cmds); ++ ++ if (num < 0) { ++ BIO_printf(out, "[Error]: internal stack error\n"); ++ return; ++ } ++ for (loop = 0; loop < num; loop++) { ++ char buf[256]; ++ const char *cmd, *arg; ++ cmd = sk_OPENSSL_STRING_value(cmds, loop); ++ res = 1; /* assume success */ ++ /* Check if this command has no ":arg" */ ++ if ((arg = strstr(cmd, ":")) == NULL) { ++ if (!ENGINE_ctrl_cmd_string(e, cmd, NULL, 0)) ++ res = 0; ++ } else { ++ if ((int)(arg - cmd) > 254) { ++ BIO_printf(out, "[Error]: command name too long\n"); ++ return; ++ } ++ memcpy(buf, cmd, (int)(arg - cmd)); ++ buf[arg - cmd] = '\0'; ++ arg++; /* Move past the ":" */ ++ /* Call the command with the argument */ ++ if (!ENGINE_ctrl_cmd_string(e, buf, arg, 0)) ++ res = 0; ++ } ++ if (res) ++ BIO_printf(out, "[Success]: %s\n", cmd); ++ else { ++ BIO_printf(out, "[Failure]: %s\n", cmd); ++ ERR_print_errors(out); ++ } ++ } ++} ++ ++int engine_main(int argc, char **argv) ++{ ++ int ret = 1, i; ++ int verbose = 0, list_cap = 0, test_avail = 0, test_avail_noise = 0; ++ ENGINE *e; ++ STACK_OF(OPENSSL_CSTRING) *engines = sk_OPENSSL_CSTRING_new_null(); ++ STACK_OF(OPENSSL_STRING) *pre_cmds = sk_OPENSSL_STRING_new_null(); ++ STACK_OF(OPENSSL_STRING) *post_cmds = sk_OPENSSL_STRING_new_null(); ++ BIO *out; ++ const char *indent = " "; ++ OPTION_CHOICE o; ++ char *prog; ++ char *argv1; ++ ++ out = dup_bio_out(FORMAT_TEXT); ++ if (engines == NULL || pre_cmds == NULL || post_cmds == NULL) ++ goto end; ++ ++ /* Remember the original command name, parse/skip any leading engine ++ * names, and then setup to parse the rest of the line as flags. */ ++ prog = argv[0]; ++ while ((argv1 = argv[1]) != NULL && *argv1 != '-') { ++ sk_OPENSSL_CSTRING_push(engines, argv1); ++ argc--; ++ argv++; ++ } ++ argv[0] = prog; ++ opt_init(argc, argv, engine_options); ++ ++ while ((o = opt_next()) != OPT_EOF) { ++ switch (o) { ++ case OPT_EOF: ++ case OPT_ERR: ++ BIO_printf(bio_err, "%s: Use -help for summary.\n", prog); ++ goto end; ++ case OPT_HELP: ++ opt_help(engine_options); ++ ret = 0; ++ goto end; ++ case OPT_VVVV: ++ case OPT_VVV: ++ case OPT_VV: ++ case OPT_V: ++ /* Convert to an integer from one to four. */ ++ i = (int)(o - OPT_V) + 1; ++ if (verbose < i) ++ verbose = i; ++ break; ++ case OPT_C: ++ list_cap = 1; ++ break; ++ case OPT_TT: ++ test_avail_noise++; ++ case OPT_T: ++ test_avail++; ++ break; ++ case OPT_PRE: ++ sk_OPENSSL_STRING_push(pre_cmds, opt_arg()); ++ break; ++ case OPT_POST: ++ sk_OPENSSL_STRING_push(post_cmds, opt_arg()); ++ break; ++ } ++ } ++ ++ /* Allow any trailing parameters as engine names. */ ++ argc = opt_num_rest(); ++ argv = opt_rest(); ++ for ( ; *argv; argv++) { ++ if (**argv == '-') { ++ BIO_printf(bio_err, "%s: Cannot mix flags and engine names.\n", ++ prog); ++ BIO_printf(bio_err, "%s: Use -help for summary.\n", prog); ++ goto end; ++ } ++ sk_OPENSSL_CSTRING_push(engines, *argv); ++ } ++ ++ if (sk_OPENSSL_CSTRING_num(engines) == 0) { ++ for (e = ENGINE_get_first(); e != NULL; e = ENGINE_get_next(e)) { ++ sk_OPENSSL_CSTRING_push(engines, ENGINE_get_id(e)); ++ } ++ } ++ ++ ret = 0; ++ for (i = 0; i < sk_OPENSSL_CSTRING_num(engines); i++) { ++ const char *id = sk_OPENSSL_CSTRING_value(engines, i); ++ if ((e = ENGINE_by_id(id)) != NULL) { ++ const char *name = ENGINE_get_name(e); ++ /* ++ * Do "id" first, then "name". Easier to auto-parse. ++ */ ++ BIO_printf(out, "(%s) %s\n", id, name); ++ util_do_cmds(e, pre_cmds, out, indent); ++ if (strcmp(ENGINE_get_id(e), id) != 0) { ++ BIO_printf(out, "Loaded: (%s) %s\n", ++ ENGINE_get_id(e), ENGINE_get_name(e)); ++ } ++ if (list_cap) { ++ int cap_size = 256; ++ char *cap_buf = NULL; ++ int k, n; ++ const int *nids; ++ ENGINE_CIPHERS_PTR fn_c; ++ ENGINE_DIGESTS_PTR fn_d; ++ ENGINE_PKEY_METHS_PTR fn_pk; ++ ++ if (ENGINE_get_RSA(e) != NULL ++ && !append_buf(&cap_buf, &cap_size, "RSA")) ++ goto end; ++ if (ENGINE_get_DSA(e) != NULL ++ && !append_buf(&cap_buf, &cap_size, "DSA")) ++ goto end; ++ if (ENGINE_get_DH(e) != NULL ++ && !append_buf(&cap_buf, &cap_size, "DH")) ++ goto end; ++ if (ENGINE_get_RAND(e) != NULL ++ && !append_buf(&cap_buf, &cap_size, "RAND")) ++ goto end; ++ ++ fn_c = ENGINE_get_ciphers(e); ++ if (!fn_c) ++ goto skip_ciphers; ++ n = fn_c(e, NULL, &nids, 0); ++ for (k = 0; k < n; ++k) ++ if (!append_buf(&cap_buf, &cap_size, OBJ_nid2sn(nids[k]))) ++ goto end; ++ ++ skip_ciphers: ++ fn_d = ENGINE_get_digests(e); ++ if (!fn_d) ++ goto skip_digests; ++ n = fn_d(e, NULL, &nids, 0); ++ for (k = 0; k < n; ++k) ++ if (!append_buf(&cap_buf, &cap_size, OBJ_nid2sn(nids[k]))) ++ goto end; ++ ++ skip_digests: ++ fn_pk = ENGINE_get_pkey_meths(e); ++ if (!fn_pk) ++ goto skip_pmeths; ++ n = fn_pk(e, NULL, &nids, 0); ++ for (k = 0; k < n; ++k) ++ if (!append_buf(&cap_buf, &cap_size, OBJ_nid2sn(nids[k]))) ++ goto end; ++ skip_pmeths: ++ if (cap_buf && (*cap_buf != '\0')) ++ BIO_printf(out, " [%s]\n", cap_buf); ++ ++ OPENSSL_free(cap_buf); ++ } ++ if (test_avail) { ++ BIO_printf(out, "%s", indent); ++ if (ENGINE_init(e)) { ++ BIO_printf(out, "[ available ]\n"); ++ util_do_cmds(e, post_cmds, out, indent); ++ ENGINE_finish(e); ++ } else { ++ BIO_printf(out, "[ unavailable ]\n"); ++ if (test_avail_noise) ++ ERR_print_errors_fp(stdout); ++ ERR_clear_error(); ++ } ++ } ++ if ((verbose > 0) && !util_verbose(e, verbose, out, indent)) ++ goto end; ++ ENGINE_free(e); ++ } else { ++ ERR_print_errors(bio_err); ++ /* because exit codes above 127 have special meaning on Unix */ ++ if (++ret > 127) ++ ret = 127; ++ } ++ } ++ ++ end: ++ ++ ERR_print_errors(bio_err); ++ sk_OPENSSL_CSTRING_free(engines); ++ sk_OPENSSL_STRING_free(pre_cmds); ++ sk_OPENSSL_STRING_free(post_cmds); ++ BIO_free_all(out); ++ return (ret); ++} ++#endif +diff --git a/CryptoPkg/Library/OpensslLib/openssl/apps/errstr.c b/CryptoPkg/Library/OpensslLib/openssl/apps/errstr.c +new file mode 100644 +index 0000000..5fda799 +--- /dev/null ++++ b/CryptoPkg/Library/OpensslLib/openssl/apps/errstr.c +@@ -0,0 +1,67 @@ ++/* ++ * Copyright 1995-2016 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 ++ * in the file LICENSE in the source distribution or at ++ * https://www.openssl.org/source/license.html ++ */ ++ ++#include ++#include ++#include ++#include "apps.h" ++#include ++#include ++#include ++#include ++ ++typedef enum OPTION_choice { ++ OPT_ERR = -1, OPT_EOF = 0, OPT_HELP ++} OPTION_CHOICE; ++ ++OPTIONS errstr_options[] = { ++ {OPT_HELP_STR, 1, '-', "Usage: %s [options] errnum...\n"}, ++ {OPT_HELP_STR, 1, '-', " errnum Error number\n"}, ++ {"help", OPT_HELP, '-', "Display this summary"}, ++ {NULL} ++}; ++ ++int errstr_main(int argc, char **argv) ++{ ++ OPTION_CHOICE o; ++ char buf[256], *prog; ++ int ret = 1; ++ unsigned long l; ++ ++ prog = opt_init(argc, argv, errstr_options); ++ while ((o = opt_next()) != OPT_EOF) { ++ switch (o) { ++ case OPT_EOF: ++ case OPT_ERR: ++ BIO_printf(bio_err, "%s: Use -help for summary.\n", prog); ++ goto end; ++ case OPT_HELP: ++ opt_help(errstr_options); ++ ret = 0; ++ goto end; ++ } ++ } ++ ++ ret = 0; ++ for (argv = opt_rest(); *argv; argv++) { ++ if (sscanf(*argv, "%lx", &l) == 0) ++ ret++; ++ else { ++ /* We're not really an SSL application so this won't auto-init, but ++ * we're still interested in SSL error strings ++ */ ++ OPENSSL_init_ssl(OPENSSL_INIT_LOAD_SSL_STRINGS ++ | OPENSSL_INIT_LOAD_CRYPTO_STRINGS, NULL); ++ ERR_error_string_n(l, buf, sizeof buf); ++ BIO_printf(bio_out, "%s\n", buf); ++ } ++ } ++ end: ++ return (ret); ++} +diff --git a/CryptoPkg/Library/OpensslLib/openssl/apps/gendsa.c b/CryptoPkg/Library/OpensslLib/openssl/apps/gendsa.c +new file mode 100644 +index 0000000..bdef022 +--- /dev/null ++++ b/CryptoPkg/Library/OpensslLib/openssl/apps/gendsa.c +@@ -0,0 +1,147 @@ ++/* ++ * Copyright 1995-2016 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 ++ * in the file LICENSE in the source distribution or at ++ * https://www.openssl.org/source/license.html ++ */ ++ ++#include ++#ifdef OPENSSL_NO_DSA ++NON_EMPTY_TRANSLATION_UNIT ++#else ++ ++# include ++# include ++# include ++# include ++# include "apps.h" ++# include ++# include ++# include ++# include ++# include ++# include ++ ++typedef enum OPTION_choice { ++ OPT_ERR = -1, OPT_EOF = 0, OPT_HELP, ++ OPT_OUT, OPT_PASSOUT, OPT_ENGINE, OPT_RAND, OPT_CIPHER ++} OPTION_CHOICE; ++ ++OPTIONS gendsa_options[] = { ++ {OPT_HELP_STR, 1, '-', "Usage: %s [args] dsaparam-file\n"}, ++ {OPT_HELP_STR, 1, '-', "Valid options are:\n"}, ++ {"help", OPT_HELP, '-', "Display this summary"}, ++ {"out", OPT_OUT, '>', "Output the key to the specified file"}, ++ {"passout", OPT_PASSOUT, 's', "Output file pass phrase source"}, ++ {"rand", OPT_RAND, 's', ++ "Load the file(s) into the random number generator"}, ++ {"", OPT_CIPHER, '-', "Encrypt the output with any supported cipher"}, ++# ifndef OPENSSL_NO_ENGINE ++ {"engine", OPT_ENGINE, 's', "Use engine, possibly a hardware device"}, ++# endif ++ {NULL} ++}; ++ ++int gendsa_main(int argc, char **argv) ++{ ++ ENGINE *e = NULL; ++ BIO *out = NULL, *in = NULL; ++ DSA *dsa = NULL; ++ const EVP_CIPHER *enc = NULL; ++ char *inrand = NULL, *dsaparams = NULL; ++ char *outfile = NULL, *passoutarg = NULL, *passout = NULL, *prog; ++ OPTION_CHOICE o; ++ int ret = 1, private = 0; ++ const BIGNUM *p = NULL; ++ ++ prog = opt_init(argc, argv, gendsa_options); ++ while ((o = opt_next()) != OPT_EOF) { ++ switch (o) { ++ case OPT_EOF: ++ case OPT_ERR: ++ opthelp: ++ BIO_printf(bio_err, "%s: Use -help for summary.\n", prog); ++ goto end; ++ case OPT_HELP: ++ ret = 0; ++ opt_help(gendsa_options); ++ goto end; ++ case OPT_OUT: ++ outfile = opt_arg(); ++ break; ++ case OPT_PASSOUT: ++ passoutarg = opt_arg(); ++ break; ++ case OPT_ENGINE: ++ e = setup_engine(opt_arg(), 0); ++ break; ++ case OPT_RAND: ++ inrand = opt_arg(); ++ break; ++ case OPT_CIPHER: ++ if (!opt_cipher(opt_unknown(), &enc)) ++ goto end; ++ break; ++ } ++ } ++ argc = opt_num_rest(); ++ argv = opt_rest(); ++ private = 1; ++ ++ if (argc != 1) ++ goto opthelp; ++ dsaparams = *argv; ++ ++ if (!app_passwd(NULL, passoutarg, NULL, &passout)) { ++ BIO_printf(bio_err, "Error getting password\n"); ++ goto end; ++ } ++ ++ in = bio_open_default(dsaparams, 'r', FORMAT_PEM); ++ if (in == NULL) ++ goto end2; ++ ++ if ((dsa = PEM_read_bio_DSAparams(in, NULL, NULL, NULL)) == NULL) { ++ BIO_printf(bio_err, "unable to load DSA parameter file\n"); ++ goto end; ++ } ++ BIO_free(in); ++ in = NULL; ++ ++ out = bio_open_owner(outfile, FORMAT_PEM, private); ++ if (out == NULL) ++ goto end2; ++ ++ if (!app_RAND_load_file(NULL, 1) && inrand == NULL) { ++ BIO_printf(bio_err, ++ "warning, not much extra random data, consider using the -rand option\n"); ++ } ++ if (inrand != NULL) ++ BIO_printf(bio_err, "%ld semi-random bytes loaded\n", ++ app_RAND_load_files(inrand)); ++ ++ DSA_get0_pqg(dsa, &p, NULL, NULL); ++ BIO_printf(bio_err, "Generating DSA key, %d bits\n", BN_num_bits(p)); ++ if (!DSA_generate_key(dsa)) ++ goto end; ++ ++ app_RAND_write_file(NULL); ++ ++ assert(private); ++ if (!PEM_write_bio_DSAPrivateKey(out, dsa, enc, NULL, 0, NULL, passout)) ++ goto end; ++ ret = 0; ++ end: ++ if (ret != 0) ++ ERR_print_errors(bio_err); ++ end2: ++ BIO_free(in); ++ BIO_free_all(out); ++ DSA_free(dsa); ++ release_engine(e); ++ OPENSSL_free(passout); ++ return (ret); ++} ++#endif +diff --git a/CryptoPkg/Library/OpensslLib/openssl/apps/genpkey.c b/CryptoPkg/Library/OpensslLib/openssl/apps/genpkey.c +new file mode 100644 +index 0000000..9e37977 +--- /dev/null ++++ b/CryptoPkg/Library/OpensslLib/openssl/apps/genpkey.c +@@ -0,0 +1,314 @@ ++/* ++ * Copyright 2006-2016 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 ++ * in the file LICENSE in the source distribution or at ++ * https://www.openssl.org/source/license.html ++ */ ++ ++#include ++#include ++#include "apps.h" ++#include ++#include ++#include ++#ifndef OPENSSL_NO_ENGINE ++# include ++#endif ++ ++static int init_keygen_file(EVP_PKEY_CTX **pctx, const char *file, ENGINE *e); ++static int genpkey_cb(EVP_PKEY_CTX *ctx); ++ ++typedef enum OPTION_choice { ++ OPT_ERR = -1, OPT_EOF = 0, OPT_HELP, ++ OPT_ENGINE, OPT_OUTFORM, OPT_OUT, OPT_PASS, OPT_PARAMFILE, ++ OPT_ALGORITHM, OPT_PKEYOPT, OPT_GENPARAM, OPT_TEXT, OPT_CIPHER ++} OPTION_CHOICE; ++ ++OPTIONS genpkey_options[] = { ++ {"help", OPT_HELP, '-', "Display this summary"}, ++ {"out", OPT_OUT, '>', "Output file"}, ++ {"outform", OPT_OUTFORM, 'F', "output format (DER or PEM)"}, ++ {"pass", OPT_PASS, 's', "Output file pass phrase source"}, ++ {"paramfile", OPT_PARAMFILE, '<', "Parameters file"}, ++ {"algorithm", OPT_ALGORITHM, 's', "The public key algorithm"}, ++ {"pkeyopt", OPT_PKEYOPT, 's', ++ "Set the public key algorithm option as opt:value"}, ++ {"genparam", OPT_GENPARAM, '-', "Generate parameters, not key"}, ++ {"text", OPT_TEXT, '-', "Print the in text"}, ++ {"", OPT_CIPHER, '-', "Cipher to use to encrypt the key"}, ++#ifndef OPENSSL_NO_ENGINE ++ {"engine", OPT_ENGINE, 's', "Use engine, possibly a hardware device"}, ++#endif ++ /* This is deliberately last. */ ++ {OPT_HELP_STR, 1, 1, ++ "Order of options may be important! See the documentation.\n"}, ++ {NULL} ++}; ++ ++int genpkey_main(int argc, char **argv) ++{ ++ BIO *in = NULL, *out = NULL; ++ ENGINE *e = NULL; ++ EVP_PKEY *pkey = NULL; ++ EVP_PKEY_CTX *ctx = NULL; ++ char *outfile = NULL, *passarg = NULL, *pass = NULL, *prog; ++ const EVP_CIPHER *cipher = NULL; ++ OPTION_CHOICE o; ++ int outformat = FORMAT_PEM, text = 0, ret = 1, rv, do_param = 0; ++ int private = 0; ++ ++ prog = opt_init(argc, argv, genpkey_options); ++ while ((o = opt_next()) != OPT_EOF) { ++ switch (o) { ++ case OPT_EOF: ++ case OPT_ERR: ++ opthelp: ++ BIO_printf(bio_err, "%s: Use -help for summary.\n", prog); ++ goto end; ++ case OPT_HELP: ++ ret = 0; ++ opt_help(genpkey_options); ++ goto end; ++ case OPT_OUTFORM: ++ if (!opt_format(opt_arg(), OPT_FMT_PEMDER, &outformat)) ++ goto opthelp; ++ break; ++ case OPT_OUT: ++ outfile = opt_arg(); ++ break; ++ case OPT_PASS: ++ passarg = opt_arg(); ++ break; ++ case OPT_ENGINE: ++ e = setup_engine(opt_arg(), 0); ++ break; ++ case OPT_PARAMFILE: ++ if (do_param == 1) ++ goto opthelp; ++ if (!init_keygen_file(&ctx, opt_arg(), e)) ++ goto end; ++ break; ++ case OPT_ALGORITHM: ++ if (!init_gen_str(&ctx, opt_arg(), e, do_param)) ++ goto end; ++ break; ++ case OPT_PKEYOPT: ++ if (ctx == NULL) { ++ BIO_printf(bio_err, "%s: No keytype specified.\n", prog); ++ goto opthelp; ++ } ++ if (pkey_ctrl_string(ctx, opt_arg()) <= 0) { ++ BIO_printf(bio_err, ++ "%s: Error setting %s parameter:\n", ++ prog, opt_arg()); ++ ERR_print_errors(bio_err); ++ goto end; ++ } ++ break; ++ case OPT_GENPARAM: ++ if (ctx != NULL) ++ goto opthelp; ++ do_param = 1; ++ break; ++ case OPT_TEXT: ++ text = 1; ++ break; ++ case OPT_CIPHER: ++ if (!opt_cipher(opt_unknown(), &cipher) ++ || do_param == 1) ++ goto opthelp; ++ } ++ } ++ argc = opt_num_rest(); ++ if (argc != 0) ++ goto opthelp; ++ ++ private = do_param ? 0 : 1; ++ ++ if (ctx == NULL) ++ goto opthelp; ++ ++ if (!app_passwd(passarg, NULL, &pass, NULL)) { ++ BIO_puts(bio_err, "Error getting password\n"); ++ goto end; ++ } ++ ++ out = bio_open_owner(outfile, outformat, private); ++ if (out == NULL) ++ goto end; ++ ++ EVP_PKEY_CTX_set_cb(ctx, genpkey_cb); ++ EVP_PKEY_CTX_set_app_data(ctx, bio_err); ++ ++ if (do_param) { ++ if (EVP_PKEY_paramgen(ctx, &pkey) <= 0) { ++ BIO_puts(bio_err, "Error generating parameters\n"); ++ ERR_print_errors(bio_err); ++ goto end; ++ } ++ } else { ++ if (EVP_PKEY_keygen(ctx, &pkey) <= 0) { ++ BIO_puts(bio_err, "Error generating key\n"); ++ ERR_print_errors(bio_err); ++ goto end; ++ } ++ } ++ ++ if (do_param) ++ rv = PEM_write_bio_Parameters(out, pkey); ++ else if (outformat == FORMAT_PEM) { ++ assert(private); ++ rv = PEM_write_bio_PrivateKey(out, pkey, cipher, NULL, 0, NULL, pass); ++ } else if (outformat == FORMAT_ASN1) { ++ assert(private); ++ rv = i2d_PrivateKey_bio(out, pkey); ++ } else { ++ BIO_printf(bio_err, "Bad format specified for key\n"); ++ goto end; ++ } ++ ++ if (rv <= 0) { ++ BIO_puts(bio_err, "Error writing key\n"); ++ ERR_print_errors(bio_err); ++ } ++ ++ if (text) { ++ if (do_param) ++ rv = EVP_PKEY_print_params(out, pkey, 0, NULL); ++ else ++ rv = EVP_PKEY_print_private(out, pkey, 0, NULL); ++ ++ if (rv <= 0) { ++ BIO_puts(bio_err, "Error printing key\n"); ++ ERR_print_errors(bio_err); ++ } ++ } ++ ++ ret = 0; ++ ++ end: ++ EVP_PKEY_free(pkey); ++ EVP_PKEY_CTX_free(ctx); ++ BIO_free_all(out); ++ BIO_free(in); ++ release_engine(e); ++ OPENSSL_free(pass); ++ return ret; ++} ++ ++static int init_keygen_file(EVP_PKEY_CTX **pctx, const char *file, ENGINE *e) ++{ ++ BIO *pbio; ++ EVP_PKEY *pkey = NULL; ++ EVP_PKEY_CTX *ctx = NULL; ++ if (*pctx) { ++ BIO_puts(bio_err, "Parameters already set!\n"); ++ return 0; ++ } ++ ++ pbio = BIO_new_file(file, "r"); ++ if (!pbio) { ++ BIO_printf(bio_err, "Can't open parameter file %s\n", file); ++ return 0; ++ } ++ ++ pkey = PEM_read_bio_Parameters(pbio, NULL); ++ BIO_free(pbio); ++ ++ if (!pkey) { ++ BIO_printf(bio_err, "Error reading parameter file %s\n", file); ++ return 0; ++ } ++ ++ ctx = EVP_PKEY_CTX_new(pkey, e); ++ if (ctx == NULL) ++ goto err; ++ if (EVP_PKEY_keygen_init(ctx) <= 0) ++ goto err; ++ EVP_PKEY_free(pkey); ++ *pctx = ctx; ++ return 1; ++ ++ err: ++ BIO_puts(bio_err, "Error initializing context\n"); ++ ERR_print_errors(bio_err); ++ EVP_PKEY_CTX_free(ctx); ++ EVP_PKEY_free(pkey); ++ return 0; ++ ++} ++ ++int init_gen_str(EVP_PKEY_CTX **pctx, ++ const char *algname, ENGINE *e, int do_param) ++{ ++ EVP_PKEY_CTX *ctx = NULL; ++ const EVP_PKEY_ASN1_METHOD *ameth; ++ ENGINE *tmpeng = NULL; ++ int pkey_id; ++ ++ if (*pctx) { ++ BIO_puts(bio_err, "Algorithm already set!\n"); ++ return 0; ++ } ++ ++ ameth = EVP_PKEY_asn1_find_str(&tmpeng, algname, -1); ++ ++#ifndef OPENSSL_NO_ENGINE ++ if (!ameth && e) ++ ameth = ENGINE_get_pkey_asn1_meth_str(e, algname, -1); ++#endif ++ ++ if (!ameth) { ++ BIO_printf(bio_err, "Algorithm %s not found\n", algname); ++ return 0; ++ } ++ ++ ERR_clear_error(); ++ ++ EVP_PKEY_asn1_get0_info(&pkey_id, NULL, NULL, NULL, NULL, ameth); ++#ifndef OPENSSL_NO_ENGINE ++ ENGINE_finish(tmpeng); ++#endif ++ ctx = EVP_PKEY_CTX_new_id(pkey_id, e); ++ ++ if (!ctx) ++ goto err; ++ if (do_param) { ++ if (EVP_PKEY_paramgen_init(ctx) <= 0) ++ goto err; ++ } else { ++ if (EVP_PKEY_keygen_init(ctx) <= 0) ++ goto err; ++ } ++ ++ *pctx = ctx; ++ return 1; ++ ++ err: ++ BIO_printf(bio_err, "Error initializing %s context\n", algname); ++ ERR_print_errors(bio_err); ++ EVP_PKEY_CTX_free(ctx); ++ return 0; ++ ++} ++ ++static int genpkey_cb(EVP_PKEY_CTX *ctx) ++{ ++ char c = '*'; ++ BIO *b = EVP_PKEY_CTX_get_app_data(ctx); ++ int p; ++ p = EVP_PKEY_CTX_get_keygen_info(ctx, 0); ++ if (p == 0) ++ c = '.'; ++ if (p == 1) ++ c = '+'; ++ if (p == 2) ++ c = '*'; ++ if (p == 3) ++ c = '\n'; ++ BIO_write(b, &c, 1); ++ (void)BIO_flush(b); ++ return 1; ++} +diff --git a/CryptoPkg/Library/OpensslLib/openssl/apps/genrsa.c b/CryptoPkg/Library/OpensslLib/openssl/apps/genrsa.c +new file mode 100644 +index 0000000..1ac66a9 +--- /dev/null ++++ b/CryptoPkg/Library/OpensslLib/openssl/apps/genrsa.c +@@ -0,0 +1,192 @@ ++/* ++ * Copyright 1995-2016 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 ++ * in the file LICENSE in the source distribution or at ++ * https://www.openssl.org/source/license.html ++ */ ++ ++#include ++#ifdef OPENSSL_NO_RSA ++NON_EMPTY_TRANSLATION_UNIT ++#else ++ ++# include ++# include ++# include ++# include ++# include "apps.h" ++# include ++# include ++# include ++# include ++# include ++# include ++# include ++# include ++ ++# define DEFBITS 2048 ++ ++static int genrsa_cb(int p, int n, BN_GENCB *cb); ++ ++typedef enum OPTION_choice { ++ OPT_ERR = -1, OPT_EOF = 0, OPT_HELP, ++ OPT_3, OPT_F4, OPT_ENGINE, ++ OPT_OUT, OPT_RAND, OPT_PASSOUT, OPT_CIPHER ++} OPTION_CHOICE; ++ ++OPTIONS genrsa_options[] = { ++ {"help", OPT_HELP, '-', "Display this summary"}, ++ {"3", OPT_3, '-', "Use 3 for the E value"}, ++ {"F4", OPT_F4, '-', "Use F4 (0x10001) for the E value"}, ++ {"f4", OPT_F4, '-', "Use F4 (0x10001) for the E value"}, ++ {"out", OPT_OUT, 's', "Output the key to specified file"}, ++ {"rand", OPT_RAND, 's', ++ "Load the file(s) into the random number generator"}, ++ {"passout", OPT_PASSOUT, 's', "Output file pass phrase source"}, ++ {"", OPT_CIPHER, '-', "Encrypt the output with any supported cipher"}, ++# ifndef OPENSSL_NO_ENGINE ++ {"engine", OPT_ENGINE, 's', "Use engine, possibly a hardware device"}, ++# endif ++ {NULL} ++}; ++ ++int genrsa_main(int argc, char **argv) ++{ ++ BN_GENCB *cb = BN_GENCB_new(); ++ PW_CB_DATA cb_data; ++ ENGINE *eng = NULL; ++ BIGNUM *bn = BN_new(); ++ BIO *out = NULL; ++ const BIGNUM *e; ++ RSA *rsa = NULL; ++ const EVP_CIPHER *enc = NULL; ++ int ret = 1, num = DEFBITS, private = 0; ++ unsigned long f4 = RSA_F4; ++ char *outfile = NULL, *passoutarg = NULL, *passout = NULL; ++ char *inrand = NULL, *prog, *hexe, *dece; ++ OPTION_CHOICE o; ++ ++ if (bn == NULL || cb == NULL) ++ goto end; ++ ++ BN_GENCB_set(cb, genrsa_cb, bio_err); ++ ++ prog = opt_init(argc, argv, genrsa_options); ++ while ((o = opt_next()) != OPT_EOF) { ++ switch (o) { ++ case OPT_EOF: ++ case OPT_ERR: ++ BIO_printf(bio_err, "%s: Use -help for summary.\n", prog); ++ goto end; ++ case OPT_HELP: ++ ret = 0; ++ opt_help(genrsa_options); ++ goto end; ++ case OPT_3: ++ f4 = 3; ++ break; ++ case OPT_F4: ++ f4 = RSA_F4; ++ break; ++ case OPT_OUT: ++ outfile = opt_arg(); ++ break; ++ case OPT_ENGINE: ++ eng = setup_engine(opt_arg(), 0); ++ break; ++ case OPT_RAND: ++ inrand = opt_arg(); ++ break; ++ case OPT_PASSOUT: ++ passoutarg = opt_arg(); ++ break; ++ case OPT_CIPHER: ++ if (!opt_cipher(opt_unknown(), &enc)) ++ goto end; ++ break; ++ } ++ } ++ argc = opt_num_rest(); ++ argv = opt_rest(); ++ private = 1; ++ ++ if (argv[0] && (!opt_int(argv[0], &num) || num <= 0)) ++ goto end; ++ ++ if (!app_passwd(NULL, passoutarg, NULL, &passout)) { ++ BIO_printf(bio_err, "Error getting password\n"); ++ goto end; ++ } ++ ++ out = bio_open_owner(outfile, FORMAT_PEM, private); ++ if (out == NULL) ++ goto end; ++ ++ if (!app_RAND_load_file(NULL, 1) && inrand == NULL ++ && !RAND_status()) { ++ BIO_printf(bio_err, ++ "warning, not much extra random data, consider using the -rand option\n"); ++ } ++ if (inrand != NULL) ++ BIO_printf(bio_err, "%ld semi-random bytes loaded\n", ++ app_RAND_load_files(inrand)); ++ ++ BIO_printf(bio_err, "Generating RSA private key, %d bit long modulus\n", ++ num); ++ rsa = eng ? RSA_new_method(eng) : RSA_new(); ++ if (rsa == NULL) ++ goto end; ++ ++ if (!BN_set_word(bn, f4) || !RSA_generate_key_ex(rsa, num, bn, cb)) ++ goto end; ++ ++ app_RAND_write_file(NULL); ++ ++ RSA_get0_key(rsa, NULL, &e, NULL); ++ hexe = BN_bn2hex(e); ++ dece = BN_bn2dec(e); ++ if (hexe && dece) { ++ BIO_printf(bio_err, "e is %s (0x%s)\n", dece, hexe); ++ } ++ OPENSSL_free(hexe); ++ OPENSSL_free(dece); ++ cb_data.password = passout; ++ cb_data.prompt_info = outfile; ++ assert(private); ++ if (!PEM_write_bio_RSAPrivateKey(out, rsa, enc, NULL, 0, ++ (pem_password_cb *)password_callback, ++ &cb_data)) ++ goto end; ++ ++ ret = 0; ++ end: ++ BN_free(bn); ++ BN_GENCB_free(cb); ++ RSA_free(rsa); ++ BIO_free_all(out); ++ release_engine(eng); ++ OPENSSL_free(passout); ++ if (ret != 0) ++ ERR_print_errors(bio_err); ++ return (ret); ++} ++ ++static int genrsa_cb(int p, int n, BN_GENCB *cb) ++{ ++ char c = '*'; ++ ++ if (p == 0) ++ c = '.'; ++ if (p == 1) ++ c = '+'; ++ if (p == 2) ++ c = '*'; ++ if (p == 3) ++ c = '\n'; ++ BIO_write(BN_GENCB_get_arg(cb), &c, 1); ++ (void)BIO_flush(BN_GENCB_get_arg(cb)); ++ return 1; ++} ++#endif +diff --git a/CryptoPkg/Library/OpensslLib/openssl/apps/nseq.c b/CryptoPkg/Library/OpensslLib/openssl/apps/nseq.c +new file mode 100644 +index 0000000..018d5eb +--- /dev/null ++++ b/CryptoPkg/Library/OpensslLib/openssl/apps/nseq.c +@@ -0,0 +1,113 @@ ++/* ++ * Copyright 1999-2016 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 ++ * in the file LICENSE in the source distribution or at ++ * https://www.openssl.org/source/license.html ++ */ ++ ++#include ++#include ++#include "apps.h" ++#include ++#include ++ ++typedef enum OPTION_choice { ++ OPT_ERR = -1, OPT_EOF = 0, OPT_HELP, ++ OPT_TOSEQ, OPT_IN, OPT_OUT ++} OPTION_CHOICE; ++ ++OPTIONS nseq_options[] = { ++ {"help", OPT_HELP, '-', "Display this summary"}, ++ {"toseq", OPT_TOSEQ, '-', "Output NS Sequence file"}, ++ {"in", OPT_IN, '<', "Input file"}, ++ {"out", OPT_OUT, '>', "Output file"}, ++ {NULL} ++}; ++ ++int nseq_main(int argc, char **argv) ++{ ++ BIO *in = NULL, *out = NULL; ++ X509 *x509 = NULL; ++ NETSCAPE_CERT_SEQUENCE *seq = NULL; ++ OPTION_CHOICE o; ++ int toseq = 0, ret = 1, i; ++ char *infile = NULL, *outfile = NULL, *prog; ++ ++ prog = opt_init(argc, argv, nseq_options); ++ while ((o = opt_next()) != OPT_EOF) { ++ switch (o) { ++ case OPT_EOF: ++ case OPT_ERR: ++ opthelp: ++ BIO_printf(bio_err, "%s: Use -help for summary.\n", prog); ++ goto end; ++ case OPT_HELP: ++ ret = 0; ++ opt_help(nseq_options); ++ goto end; ++ case OPT_TOSEQ: ++ toseq = 1; ++ break; ++ case OPT_IN: ++ infile = opt_arg(); ++ break; ++ case OPT_OUT: ++ outfile = opt_arg(); ++ break; ++ } ++ } ++ argc = opt_num_rest(); ++ if (argc != 0) ++ goto opthelp; ++ ++ in = bio_open_default(infile, 'r', FORMAT_PEM); ++ if (in == NULL) ++ goto end; ++ out = bio_open_default(outfile, 'w', FORMAT_PEM); ++ if (out == NULL) ++ goto end; ++ ++ if (toseq) { ++ seq = NETSCAPE_CERT_SEQUENCE_new(); ++ if (seq == NULL) ++ goto end; ++ seq->certs = sk_X509_new_null(); ++ if (seq->certs == NULL) ++ goto end; ++ while ((x509 = PEM_read_bio_X509(in, NULL, NULL, NULL))) ++ sk_X509_push(seq->certs, x509); ++ ++ if (!sk_X509_num(seq->certs)) { ++ BIO_printf(bio_err, "%s: Error reading certs file %s\n", ++ prog, infile); ++ ERR_print_errors(bio_err); ++ goto end; ++ } ++ PEM_write_bio_NETSCAPE_CERT_SEQUENCE(out, seq); ++ ret = 0; ++ goto end; ++ } ++ ++ seq = PEM_read_bio_NETSCAPE_CERT_SEQUENCE(in, NULL, NULL, NULL); ++ if (seq == NULL) { ++ BIO_printf(bio_err, "%s: Error reading sequence file %s\n", ++ prog, infile); ++ ERR_print_errors(bio_err); ++ goto end; ++ } ++ ++ for (i = 0; i < sk_X509_num(seq->certs); i++) { ++ x509 = sk_X509_value(seq->certs, i); ++ dump_cert_text(out, x509); ++ PEM_write_bio_X509(out, x509); ++ } ++ ret = 0; ++ end: ++ BIO_free(in); ++ BIO_free_all(out); ++ NETSCAPE_CERT_SEQUENCE_free(seq); ++ ++ return (ret); ++} +diff --git a/CryptoPkg/Library/OpensslLib/openssl/apps/ocsp.c b/CryptoPkg/Library/OpensslLib/openssl/apps/ocsp.c +new file mode 100644 +index 0000000..41ea970 +--- /dev/null ++++ b/CryptoPkg/Library/OpensslLib/openssl/apps/ocsp.c +@@ -0,0 +1,1290 @@ ++/* ++ * Copyright 2001-2016 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 ++ * in the file LICENSE in the source distribution or at ++ * https://www.openssl.org/source/license.html ++ */ ++ ++#include ++ ++#ifdef OPENSSL_NO_OCSP ++NON_EMPTY_TRANSLATION_UNIT ++#else ++# ifdef OPENSSL_SYS_VMS ++# define _XOPEN_SOURCE_EXTENDED/* So fd_set and friends get properly defined ++ * on OpenVMS */ ++# endif ++ ++# define USE_SOCKETS ++ ++# include ++# include ++# include ++# include ++# include ++ ++/* Needs to be included before the openssl headers */ ++# include "apps.h" ++# include ++# include ++# include ++# include ++# include ++# include ++# include ++ ++# if defined(NETWARE_CLIB) ++# ifdef NETWARE_BSDSOCK ++# include ++# include ++# else ++# include ++# endif ++# elif defined(NETWARE_LIBC) ++# ifdef NETWARE_BSDSOCK ++# include ++# else ++# include ++# endif ++# endif ++ ++/* Maximum leeway in validity period: default 5 minutes */ ++# define MAX_VALIDITY_PERIOD (5 * 60) ++ ++static int add_ocsp_cert(OCSP_REQUEST **req, X509 *cert, ++ const EVP_MD *cert_id_md, X509 *issuer, ++ STACK_OF(OCSP_CERTID) *ids); ++static int add_ocsp_serial(OCSP_REQUEST **req, char *serial, ++ const EVP_MD *cert_id_md, X509 *issuer, ++ STACK_OF(OCSP_CERTID) *ids); ++static void print_ocsp_summary(BIO *out, OCSP_BASICRESP *bs, OCSP_REQUEST *req, ++ STACK_OF(OPENSSL_STRING) *names, ++ STACK_OF(OCSP_CERTID) *ids, long nsec, ++ long maxage); ++static void make_ocsp_response(OCSP_RESPONSE **resp, OCSP_REQUEST *req, ++ CA_DB *db, X509 *ca, X509 *rcert, ++ EVP_PKEY *rkey, const EVP_MD *md, ++ STACK_OF(X509) *rother, unsigned long flags, ++ int nmin, int ndays, int badsig); ++ ++static char **lookup_serial(CA_DB *db, ASN1_INTEGER *ser); ++static BIO *init_responder(const char *port); ++static int do_responder(OCSP_REQUEST **preq, BIO **pcbio, BIO *acbio); ++static int send_ocsp_response(BIO *cbio, OCSP_RESPONSE *resp); ++ ++# ifndef OPENSSL_NO_SOCK ++static OCSP_RESPONSE *query_responder(BIO *cbio, const char *host, ++ const char *path, ++ const STACK_OF(CONF_VALUE) *headers, ++ OCSP_REQUEST *req, int req_timeout); ++# endif ++ ++typedef enum OPTION_choice { ++ OPT_ERR = -1, OPT_EOF = 0, OPT_HELP, ++ OPT_OUTFILE, OPT_TIMEOUT, OPT_URL, OPT_HOST, OPT_PORT, ++ OPT_IGNORE_ERR, OPT_NOVERIFY, OPT_NONCE, OPT_NO_NONCE, ++ OPT_RESP_NO_CERTS, OPT_RESP_KEY_ID, OPT_NO_CERTS, ++ OPT_NO_SIGNATURE_VERIFY, OPT_NO_CERT_VERIFY, OPT_NO_CHAIN, ++ OPT_NO_CERT_CHECKS, OPT_NO_EXPLICIT, OPT_TRUST_OTHER, ++ OPT_NO_INTERN, OPT_BADSIG, OPT_TEXT, OPT_REQ_TEXT, OPT_RESP_TEXT, ++ OPT_REQIN, OPT_RESPIN, OPT_SIGNER, OPT_VAFILE, OPT_SIGN_OTHER, ++ OPT_VERIFY_OTHER, OPT_CAFILE, OPT_CAPATH, OPT_NOCAFILE, OPT_NOCAPATH, ++ OPT_VALIDITY_PERIOD, OPT_STATUS_AGE, OPT_SIGNKEY, OPT_REQOUT, ++ OPT_RESPOUT, OPT_PATH, OPT_ISSUER, OPT_CERT, OPT_SERIAL, ++ OPT_INDEX, OPT_CA, OPT_NMIN, OPT_REQUEST, OPT_NDAYS, OPT_RSIGNER, ++ OPT_RKEY, OPT_ROTHER, OPT_RMD, OPT_HEADER, ++ OPT_V_ENUM, ++ OPT_MD ++} OPTION_CHOICE; ++ ++OPTIONS ocsp_options[] = { ++ {"help", OPT_HELP, '-', "Display this summary"}, ++ {"out", OPT_OUTFILE, '>', "Output filename"}, ++ {"timeout", OPT_TIMEOUT, 'p', ++ "Connection timeout (in seconds) to the OCSP responder"}, ++ {"url", OPT_URL, 's', "Responder URL"}, ++ {"host", OPT_HOST, 's', "TCP/IP hostname:port to connect to"}, ++ {"port", OPT_PORT, 'p', "Port to run responder on"}, ++ {"ignore_err", OPT_IGNORE_ERR, '-', ++ "Ignore Error response from OCSP responder, and retry "}, ++ {"noverify", OPT_NOVERIFY, '-', "Don't verify response at all"}, ++ {"nonce", OPT_NONCE, '-', "Add OCSP nonce to request"}, ++ {"no_nonce", OPT_NO_NONCE, '-', "Don't add OCSP nonce to request"}, ++ {"resp_no_certs", OPT_RESP_NO_CERTS, '-', ++ "Don't include any certificates in response"}, ++ {"resp_key_id", OPT_RESP_KEY_ID, '-', ++ "Identify response by signing certificate key ID"}, ++ {"no_certs", OPT_NO_CERTS, '-', ++ "Don't include any certificates in signed request"}, ++ {"no_signature_verify", OPT_NO_SIGNATURE_VERIFY, '-', ++ "Don't check signature on response"}, ++ {"no_cert_verify", OPT_NO_CERT_VERIFY, '-', ++ "Don't check signing certificate"}, ++ {"no_chain", OPT_NO_CHAIN, '-', "Don't chain verify response"}, ++ {"no_cert_checks", OPT_NO_CERT_CHECKS, '-', ++ "Don't do additional checks on signing certificate"}, ++ {"no_explicit", OPT_NO_EXPLICIT, '-', ++ "Do not explicitly check the chain, just verify the root"}, ++ {"trust_other", OPT_TRUST_OTHER, '-', ++ "Don't verify additional certificates"}, ++ {"no_intern", OPT_NO_INTERN, '-', ++ "Don't search certificates contained in response for signer"}, ++ {"badsig", OPT_BADSIG, '-', ++ "Corrupt last byte of loaded OSCP response signature (for test)"}, ++ {"text", OPT_TEXT, '-', "Print text form of request and response"}, ++ {"req_text", OPT_REQ_TEXT, '-', "Print text form of request"}, ++ {"resp_text", OPT_RESP_TEXT, '-', "Print text form of response"}, ++ {"reqin", OPT_REQIN, 's', "File with the DER-encoded request"}, ++ {"respin", OPT_RESPIN, 's', "File with the DER-encoded response"}, ++ {"signer", OPT_SIGNER, '<', "Certificate to sign OCSP request with"}, ++ {"VAfile", OPT_VAFILE, '<', "Validator certificates file"}, ++ {"sign_other", OPT_SIGN_OTHER, '<', ++ "Additional certificates to include in signed request"}, ++ {"verify_other", OPT_VERIFY_OTHER, '<', ++ "Additional certificates to search for signer"}, ++ {"CAfile", OPT_CAFILE, '<', "Trusted certificates file"}, ++ {"CApath", OPT_CAPATH, '<', "Trusted certificates directory"}, ++ {"no-CAfile", OPT_NOCAFILE, '-', ++ "Do not load the default certificates file"}, ++ {"no-CApath", OPT_NOCAPATH, '-', ++ "Do not load certificates from the default certificates directory"}, ++ {"validity_period", OPT_VALIDITY_PERIOD, 'u', ++ "Maximum validity discrepancy in seconds"}, ++ {"status_age", OPT_STATUS_AGE, 'p', "Maximum status age in seconds"}, ++ {"signkey", OPT_SIGNKEY, 's', "Private key to sign OCSP request with"}, ++ {"reqout", OPT_REQOUT, 's', "Output file for the DER-encoded request"}, ++ {"respout", OPT_RESPOUT, 's', "Output file for the DER-encoded response"}, ++ {"path", OPT_PATH, 's', "Path to use in OCSP request"}, ++ {"issuer", OPT_ISSUER, '<', "Issuer certificate"}, ++ {"cert", OPT_CERT, '<', "Certificate to check"}, ++ {"serial", OPT_SERIAL, 's', "Serial number to check"}, ++ {"index", OPT_INDEX, '<', "Certificate status index file"}, ++ {"CA", OPT_CA, '<', "CA certificate"}, ++ {"nmin", OPT_NMIN, 'p', "Number of minutes before next update"}, ++ {"nrequest", OPT_REQUEST, 'p', ++ "Number of requests to accept (default unlimited)"}, ++ {"ndays", OPT_NDAYS, 'p', "Number of days before next update"}, ++ {"rsigner", OPT_RSIGNER, '<', ++ "Responder certificate to sign responses with"}, ++ {"rkey", OPT_RKEY, '<', "Responder key to sign responses with"}, ++ {"rother", OPT_ROTHER, '<', "Other certificates to include in response"}, ++ {"rmd", OPT_RMD, 's', "Digest Algorithm to use in signature of OCSP response"}, ++ {"header", OPT_HEADER, 's', "key=value header to add"}, ++ {"", OPT_MD, '-', "Any supported digest algorithm (sha1,sha256, ... )"}, ++ OPT_V_OPTIONS, ++ {NULL} ++}; ++ ++int ocsp_main(int argc, char **argv) ++{ ++ BIO *acbio = NULL, *cbio = NULL, *derbio = NULL, *out = NULL; ++ const EVP_MD *cert_id_md = NULL, *rsign_md = NULL; ++ int trailing_md = 0; ++ CA_DB *rdb = NULL; ++ EVP_PKEY *key = NULL, *rkey = NULL; ++ OCSP_BASICRESP *bs = NULL; ++ OCSP_REQUEST *req = NULL; ++ OCSP_RESPONSE *resp = NULL; ++ STACK_OF(CONF_VALUE) *headers = NULL; ++ STACK_OF(OCSP_CERTID) *ids = NULL; ++ STACK_OF(OPENSSL_STRING) *reqnames = NULL; ++ STACK_OF(X509) *sign_other = NULL, *verify_other = NULL, *rother = NULL; ++ STACK_OF(X509) *issuers = NULL; ++ X509 *issuer = NULL, *cert = NULL, *rca_cert = NULL; ++ X509 *signer = NULL, *rsigner = NULL; ++ X509_STORE *store = NULL; ++ X509_VERIFY_PARAM *vpm = NULL; ++ const char *CAfile = NULL, *CApath = NULL; ++ char *header, *value; ++ char *host = NULL, *port = NULL, *path = "/", *outfile = NULL; ++ char *rca_filename = NULL, *reqin = NULL, *respin = NULL; ++ char *reqout = NULL, *respout = NULL, *ridx_filename = NULL; ++ char *rsignfile = NULL, *rkeyfile = NULL; ++ char *sign_certfile = NULL, *verify_certfile = NULL, *rcertfile = NULL; ++ char *signfile = NULL, *keyfile = NULL; ++ char *thost = NULL, *tport = NULL, *tpath = NULL; ++ int noCAfile = 0, noCApath = 0; ++ int accept_count = -1, add_nonce = 1, noverify = 0, use_ssl = -1; ++ int vpmtouched = 0, badsig = 0, i, ignore_err = 0, nmin = 0, ndays = -1; ++ int req_text = 0, resp_text = 0, ret = 1; ++#ifndef OPENSSL_NO_SOCK ++ int req_timeout = -1; ++#endif ++ long nsec = MAX_VALIDITY_PERIOD, maxage = -1; ++ unsigned long sign_flags = 0, verify_flags = 0, rflags = 0; ++ OPTION_CHOICE o; ++ char *prog; ++ ++ reqnames = sk_OPENSSL_STRING_new_null(); ++ if (!reqnames) ++ goto end; ++ ids = sk_OCSP_CERTID_new_null(); ++ if (!ids) ++ goto end; ++ if ((vpm = X509_VERIFY_PARAM_new()) == NULL) ++ return 1; ++ ++ prog = opt_init(argc, argv, ocsp_options); ++ while ((o = opt_next()) != OPT_EOF) { ++ switch (o) { ++ case OPT_EOF: ++ case OPT_ERR: ++ opthelp: ++ BIO_printf(bio_err, "%s: Use -help for summary.\n", prog); ++ goto end; ++ case OPT_HELP: ++ ret = 0; ++ opt_help(ocsp_options); ++ goto end; ++ case OPT_OUTFILE: ++ outfile = opt_arg(); ++ break; ++ case OPT_TIMEOUT: ++#ifndef OPENSSL_NO_SOCK ++ req_timeout = atoi(opt_arg()); ++#endif ++ break; ++ case OPT_URL: ++ OPENSSL_free(thost); ++ OPENSSL_free(tport); ++ OPENSSL_free(tpath); ++ thost = tport = tpath = NULL; ++ if (!OCSP_parse_url(opt_arg(), &host, &port, &path, &use_ssl)) { ++ BIO_printf(bio_err, "%s Error parsing URL\n", prog); ++ goto end; ++ } ++ thost = host; ++ tport = port; ++ tpath = path; ++ break; ++ case OPT_HOST: ++ host = opt_arg(); ++ break; ++ case OPT_PORT: ++ port = opt_arg(); ++ break; ++ case OPT_IGNORE_ERR: ++ ignore_err = 1; ++ break; ++ case OPT_NOVERIFY: ++ noverify = 1; ++ break; ++ case OPT_NONCE: ++ add_nonce = 2; ++ break; ++ case OPT_NO_NONCE: ++ add_nonce = 0; ++ break; ++ case OPT_RESP_NO_CERTS: ++ rflags |= OCSP_NOCERTS; ++ break; ++ case OPT_RESP_KEY_ID: ++ rflags |= OCSP_RESPID_KEY; ++ break; ++ case OPT_NO_CERTS: ++ sign_flags |= OCSP_NOCERTS; ++ break; ++ case OPT_NO_SIGNATURE_VERIFY: ++ verify_flags |= OCSP_NOSIGS; ++ break; ++ case OPT_NO_CERT_VERIFY: ++ verify_flags |= OCSP_NOVERIFY; ++ break; ++ case OPT_NO_CHAIN: ++ verify_flags |= OCSP_NOCHAIN; ++ break; ++ case OPT_NO_CERT_CHECKS: ++ verify_flags |= OCSP_NOCHECKS; ++ break; ++ case OPT_NO_EXPLICIT: ++ verify_flags |= OCSP_NOEXPLICIT; ++ break; ++ case OPT_TRUST_OTHER: ++ verify_flags |= OCSP_TRUSTOTHER; ++ break; ++ case OPT_NO_INTERN: ++ verify_flags |= OCSP_NOINTERN; ++ break; ++ case OPT_BADSIG: ++ badsig = 1; ++ break; ++ case OPT_TEXT: ++ req_text = resp_text = 1; ++ break; ++ case OPT_REQ_TEXT: ++ req_text = 1; ++ break; ++ case OPT_RESP_TEXT: ++ resp_text = 1; ++ break; ++ case OPT_REQIN: ++ reqin = opt_arg(); ++ break; ++ case OPT_RESPIN: ++ respin = opt_arg(); ++ break; ++ case OPT_SIGNER: ++ signfile = opt_arg(); ++ break; ++ case OPT_VAFILE: ++ verify_certfile = opt_arg(); ++ verify_flags |= OCSP_TRUSTOTHER; ++ break; ++ case OPT_SIGN_OTHER: ++ sign_certfile = opt_arg(); ++ break; ++ case OPT_VERIFY_OTHER: ++ verify_certfile = opt_arg(); ++ break; ++ case OPT_CAFILE: ++ CAfile = opt_arg(); ++ break; ++ case OPT_CAPATH: ++ CApath = opt_arg(); ++ break; ++ case OPT_NOCAFILE: ++ noCAfile = 1; ++ break; ++ case OPT_NOCAPATH: ++ noCApath = 1; ++ break; ++ case OPT_V_CASES: ++ if (!opt_verify(o, vpm)) ++ goto end; ++ vpmtouched++; ++ break; ++ case OPT_VALIDITY_PERIOD: ++ opt_long(opt_arg(), &nsec); ++ break; ++ case OPT_STATUS_AGE: ++ opt_long(opt_arg(), &maxage); ++ break; ++ case OPT_SIGNKEY: ++ keyfile = opt_arg(); ++ break; ++ case OPT_REQOUT: ++ reqout = opt_arg(); ++ break; ++ case OPT_RESPOUT: ++ respout = opt_arg(); ++ break; ++ case OPT_PATH: ++ path = opt_arg(); ++ break; ++ case OPT_ISSUER: ++ issuer = load_cert(opt_arg(), FORMAT_PEM, "issuer certificate"); ++ if (issuer == NULL) ++ goto end; ++ if (issuers == NULL) { ++ if ((issuers = sk_X509_new_null()) == NULL) ++ goto end; ++ } ++ sk_X509_push(issuers, issuer); ++ break; ++ case OPT_CERT: ++ X509_free(cert); ++ cert = load_cert(opt_arg(), FORMAT_PEM, "certificate"); ++ if (cert == NULL) ++ goto end; ++ if (cert_id_md == NULL) ++ cert_id_md = EVP_sha1(); ++ if (!add_ocsp_cert(&req, cert, cert_id_md, issuer, ids)) ++ goto end; ++ if (!sk_OPENSSL_STRING_push(reqnames, opt_arg())) ++ goto end; ++ trailing_md = 0; ++ break; ++ case OPT_SERIAL: ++ if (cert_id_md == NULL) ++ cert_id_md = EVP_sha1(); ++ if (!add_ocsp_serial(&req, opt_arg(), cert_id_md, issuer, ids)) ++ goto end; ++ if (!sk_OPENSSL_STRING_push(reqnames, opt_arg())) ++ goto end; ++ trailing_md = 0; ++ break; ++ case OPT_INDEX: ++ ridx_filename = opt_arg(); ++ break; ++ case OPT_CA: ++ rca_filename = opt_arg(); ++ break; ++ case OPT_NMIN: ++ opt_int(opt_arg(), &nmin); ++ if (ndays == -1) ++ ndays = 0; ++ break; ++ case OPT_REQUEST: ++ opt_int(opt_arg(), &accept_count); ++ break; ++ case OPT_NDAYS: ++ ndays = atoi(opt_arg()); ++ break; ++ case OPT_RSIGNER: ++ rsignfile = opt_arg(); ++ break; ++ case OPT_RKEY: ++ rkeyfile = opt_arg(); ++ break; ++ case OPT_ROTHER: ++ rcertfile = opt_arg(); ++ break; ++ case OPT_RMD: /* Response MessageDigest */ ++ if (!opt_md(opt_arg(), &rsign_md)) ++ goto end; ++ break; ++ case OPT_HEADER: ++ header = opt_arg(); ++ value = strchr(header, '='); ++ if (value == NULL) { ++ BIO_printf(bio_err, "Missing = in header key=value\n"); ++ goto opthelp; ++ } ++ *value++ = '\0'; ++ if (!X509V3_add_value(header, value, &headers)) ++ goto end; ++ break; ++ case OPT_MD: ++ if (trailing_md) { ++ BIO_printf(bio_err, ++ "%s: Digest must be before -cert or -serial\n", ++ prog); ++ goto opthelp; ++ } ++ if (!opt_md(opt_unknown(), &cert_id_md)) ++ goto opthelp; ++ trailing_md = 1; ++ break; ++ } ++ } ++ ++ if (trailing_md) { ++ BIO_printf(bio_err, "%s: Digest must be before -cert or -serial\n", ++ prog); ++ goto opthelp; ++ } ++ argc = opt_num_rest(); ++ if (argc != 0) ++ goto opthelp; ++ ++ /* Have we anything to do? */ ++ if (!req && !reqin && !respin && !(port && ridx_filename)) ++ goto opthelp; ++ ++ out = bio_open_default(outfile, 'w', FORMAT_TEXT); ++ if (out == NULL) ++ goto end; ++ ++ if (!req && (add_nonce != 2)) ++ add_nonce = 0; ++ ++ if (!req && reqin) { ++ derbio = bio_open_default(reqin, 'r', FORMAT_ASN1); ++ if (derbio == NULL) ++ goto end; ++ req = d2i_OCSP_REQUEST_bio(derbio, NULL); ++ BIO_free(derbio); ++ if (!req) { ++ BIO_printf(bio_err, "Error reading OCSP request\n"); ++ goto end; ++ } ++ } ++ ++ if (!req && port) { ++ acbio = init_responder(port); ++ if (!acbio) ++ goto end; ++ } ++ ++ if (rsignfile) { ++ if (!rkeyfile) ++ rkeyfile = rsignfile; ++ rsigner = load_cert(rsignfile, FORMAT_PEM, "responder certificate"); ++ if (!rsigner) { ++ BIO_printf(bio_err, "Error loading responder certificate\n"); ++ goto end; ++ } ++ rca_cert = load_cert(rca_filename, FORMAT_PEM, "CA certificate"); ++ if (rcertfile) { ++ if (!load_certs(rcertfile, &rother, FORMAT_PEM, NULL, ++ "responder other certificates")) ++ goto end; ++ } ++ rkey = load_key(rkeyfile, FORMAT_PEM, 0, NULL, NULL, ++ "responder private key"); ++ if (!rkey) ++ goto end; ++ } ++ if (acbio) ++ BIO_printf(bio_err, "Waiting for OCSP client connections...\n"); ++ ++ redo_accept: ++ ++ if (acbio) { ++ if (!do_responder(&req, &cbio, acbio)) ++ goto end; ++ if (!req) { ++ resp = ++ OCSP_response_create(OCSP_RESPONSE_STATUS_MALFORMEDREQUEST, ++ NULL); ++ send_ocsp_response(cbio, resp); ++ goto done_resp; ++ } ++ } ++ ++ if (!req && (signfile || reqout || host || add_nonce || ridx_filename)) { ++ BIO_printf(bio_err, "Need an OCSP request for this operation!\n"); ++ goto end; ++ } ++ ++ if (req && add_nonce) ++ OCSP_request_add1_nonce(req, NULL, -1); ++ ++ if (signfile) { ++ if (!keyfile) ++ keyfile = signfile; ++ signer = load_cert(signfile, FORMAT_PEM, "signer certificate"); ++ if (!signer) { ++ BIO_printf(bio_err, "Error loading signer certificate\n"); ++ goto end; ++ } ++ if (sign_certfile) { ++ if (!load_certs(sign_certfile, &sign_other, FORMAT_PEM, NULL, ++ "signer certificates")) ++ goto end; ++ } ++ key = load_key(keyfile, FORMAT_PEM, 0, NULL, NULL, ++ "signer private key"); ++ if (!key) ++ goto end; ++ ++ if (!OCSP_request_sign ++ (req, signer, key, NULL, sign_other, sign_flags)) { ++ BIO_printf(bio_err, "Error signing OCSP request\n"); ++ goto end; ++ } ++ } ++ ++ if (req_text && req) ++ OCSP_REQUEST_print(out, req, 0); ++ ++ if (reqout) { ++ derbio = bio_open_default(reqout, 'w', FORMAT_ASN1); ++ if (derbio == NULL) ++ goto end; ++ i2d_OCSP_REQUEST_bio(derbio, req); ++ BIO_free(derbio); ++ } ++ ++ if (ridx_filename && (!rkey || !rsigner || !rca_cert)) { ++ BIO_printf(bio_err, ++ "Need a responder certificate, key and CA for this operation!\n"); ++ goto end; ++ } ++ ++ if (ridx_filename && !rdb) { ++ rdb = load_index(ridx_filename, NULL); ++ if (!rdb) ++ goto end; ++ if (!index_index(rdb)) ++ goto end; ++ } ++ ++ if (rdb) { ++ make_ocsp_response(&resp, req, rdb, rca_cert, rsigner, rkey, ++ rsign_md, rother, rflags, nmin, ndays, badsig); ++ if (cbio) ++ send_ocsp_response(cbio, resp); ++ } else if (host) { ++# ifndef OPENSSL_NO_SOCK ++ resp = process_responder(req, host, path, ++ port, use_ssl, headers, req_timeout); ++ if (!resp) ++ goto end; ++# else ++ BIO_printf(bio_err, ++ "Error creating connect BIO - sockets not supported.\n"); ++ goto end; ++# endif ++ } else if (respin) { ++ derbio = bio_open_default(respin, 'r', FORMAT_ASN1); ++ if (derbio == NULL) ++ goto end; ++ resp = d2i_OCSP_RESPONSE_bio(derbio, NULL); ++ BIO_free(derbio); ++ if (!resp) { ++ BIO_printf(bio_err, "Error reading OCSP response\n"); ++ goto end; ++ } ++ } else { ++ ret = 0; ++ goto end; ++ } ++ ++ done_resp: ++ ++ if (respout) { ++ derbio = bio_open_default(respout, 'w', FORMAT_ASN1); ++ if (derbio == NULL) ++ goto end; ++ i2d_OCSP_RESPONSE_bio(derbio, resp); ++ BIO_free(derbio); ++ } ++ ++ i = OCSP_response_status(resp); ++ if (i != OCSP_RESPONSE_STATUS_SUCCESSFUL) { ++ BIO_printf(out, "Responder Error: %s (%d)\n", ++ OCSP_response_status_str(i), i); ++ if (ignore_err) ++ goto redo_accept; ++ ret = 0; ++ goto end; ++ } ++ ++ if (resp_text) ++ OCSP_RESPONSE_print(out, resp, 0); ++ ++ /* If running as responder don't verify our own response */ ++ if (cbio) { ++ /* If not unlimited, see if we took all we should. */ ++ if (accept_count != -1 && --accept_count <= 0) { ++ ret = 0; ++ goto end; ++ } ++ BIO_free_all(cbio); ++ cbio = NULL; ++ OCSP_REQUEST_free(req); ++ req = NULL; ++ OCSP_RESPONSE_free(resp); ++ resp = NULL; ++ goto redo_accept; ++ } ++ if (ridx_filename) { ++ ret = 0; ++ goto end; ++ } ++ ++ if (!store) { ++ store = setup_verify(CAfile, CApath, noCAfile, noCApath); ++ if (!store) ++ goto end; ++ } ++ if (vpmtouched) ++ X509_STORE_set1_param(store, vpm); ++ if (verify_certfile) { ++ if (!load_certs(verify_certfile, &verify_other, FORMAT_PEM, NULL, ++ "validator certificate")) ++ goto end; ++ } ++ ++ bs = OCSP_response_get1_basic(resp); ++ if (!bs) { ++ BIO_printf(bio_err, "Error parsing response\n"); ++ goto end; ++ } ++ ++ ret = 0; ++ ++ if (!noverify) { ++ if (req && ((i = OCSP_check_nonce(req, bs)) <= 0)) { ++ if (i == -1) ++ BIO_printf(bio_err, "WARNING: no nonce in response\n"); ++ else { ++ BIO_printf(bio_err, "Nonce Verify error\n"); ++ ret = 1; ++ goto end; ++ } ++ } ++ ++ i = OCSP_basic_verify(bs, verify_other, store, verify_flags); ++ if (i <= 0 && issuers) { ++ i = OCSP_basic_verify(bs, issuers, store, OCSP_TRUSTOTHER); ++ if (i > 0) ++ ERR_clear_error(); ++ } ++ if (i <= 0) { ++ BIO_printf(bio_err, "Response Verify Failure\n"); ++ ERR_print_errors(bio_err); ++ ret = 1; ++ } else ++ BIO_printf(bio_err, "Response verify OK\n"); ++ ++ } ++ ++ print_ocsp_summary(out, bs, req, reqnames, ids, nsec, maxage); ++ ++ end: ++ ERR_print_errors(bio_err); ++ X509_free(signer); ++ X509_STORE_free(store); ++ X509_VERIFY_PARAM_free(vpm); ++ EVP_PKEY_free(key); ++ EVP_PKEY_free(rkey); ++ X509_free(cert); ++ sk_X509_pop_free(issuers, X509_free); ++ X509_free(rsigner); ++ X509_free(rca_cert); ++ free_index(rdb); ++ BIO_free_all(cbio); ++ BIO_free_all(acbio); ++ BIO_free(out); ++ OCSP_REQUEST_free(req); ++ OCSP_RESPONSE_free(resp); ++ OCSP_BASICRESP_free(bs); ++ sk_OPENSSL_STRING_free(reqnames); ++ sk_OCSP_CERTID_free(ids); ++ sk_X509_pop_free(sign_other, X509_free); ++ sk_X509_pop_free(verify_other, X509_free); ++ sk_CONF_VALUE_pop_free(headers, X509V3_conf_free); ++ OPENSSL_free(thost); ++ OPENSSL_free(tport); ++ OPENSSL_free(tpath); ++ ++ return (ret); ++} ++ ++static int add_ocsp_cert(OCSP_REQUEST **req, X509 *cert, ++ const EVP_MD *cert_id_md, X509 *issuer, ++ STACK_OF(OCSP_CERTID) *ids) ++{ ++ OCSP_CERTID *id; ++ if (!issuer) { ++ BIO_printf(bio_err, "No issuer certificate specified\n"); ++ return 0; ++ } ++ if (*req == NULL) ++ *req = OCSP_REQUEST_new(); ++ if (*req == NULL) ++ goto err; ++ id = OCSP_cert_to_id(cert_id_md, cert, issuer); ++ if (!id || !sk_OCSP_CERTID_push(ids, id)) ++ goto err; ++ if (!OCSP_request_add0_id(*req, id)) ++ goto err; ++ return 1; ++ ++ err: ++ BIO_printf(bio_err, "Error Creating OCSP request\n"); ++ return 0; ++} ++ ++static int add_ocsp_serial(OCSP_REQUEST **req, char *serial, ++ const EVP_MD *cert_id_md, X509 *issuer, ++ STACK_OF(OCSP_CERTID) *ids) ++{ ++ OCSP_CERTID *id; ++ X509_NAME *iname; ++ ASN1_BIT_STRING *ikey; ++ ASN1_INTEGER *sno; ++ if (!issuer) { ++ BIO_printf(bio_err, "No issuer certificate specified\n"); ++ return 0; ++ } ++ if (*req == NULL) ++ *req = OCSP_REQUEST_new(); ++ if (*req == NULL) ++ goto err; ++ iname = X509_get_subject_name(issuer); ++ ikey = X509_get0_pubkey_bitstr(issuer); ++ sno = s2i_ASN1_INTEGER(NULL, serial); ++ if (!sno) { ++ BIO_printf(bio_err, "Error converting serial number %s\n", serial); ++ return 0; ++ } ++ id = OCSP_cert_id_new(cert_id_md, iname, ikey, sno); ++ ASN1_INTEGER_free(sno); ++ if (id == NULL || !sk_OCSP_CERTID_push(ids, id)) ++ goto err; ++ if (!OCSP_request_add0_id(*req, id)) ++ goto err; ++ return 1; ++ ++ err: ++ BIO_printf(bio_err, "Error Creating OCSP request\n"); ++ return 0; ++} ++ ++static void print_ocsp_summary(BIO *out, OCSP_BASICRESP *bs, OCSP_REQUEST *req, ++ STACK_OF(OPENSSL_STRING) *names, ++ STACK_OF(OCSP_CERTID) *ids, long nsec, ++ long maxage) ++{ ++ OCSP_CERTID *id; ++ const char *name; ++ int i, status, reason; ++ ASN1_GENERALIZEDTIME *rev, *thisupd, *nextupd; ++ ++ if (!bs || !req || !sk_OPENSSL_STRING_num(names) ++ || !sk_OCSP_CERTID_num(ids)) ++ return; ++ ++ for (i = 0; i < sk_OCSP_CERTID_num(ids); i++) { ++ id = sk_OCSP_CERTID_value(ids, i); ++ name = sk_OPENSSL_STRING_value(names, i); ++ BIO_printf(out, "%s: ", name); ++ ++ if (!OCSP_resp_find_status(bs, id, &status, &reason, ++ &rev, &thisupd, &nextupd)) { ++ BIO_puts(out, "ERROR: No Status found.\n"); ++ continue; ++ } ++ ++ /* ++ * Check validity: if invalid write to output BIO so we know which ++ * response this refers to. ++ */ ++ if (!OCSP_check_validity(thisupd, nextupd, nsec, maxage)) { ++ BIO_puts(out, "WARNING: Status times invalid.\n"); ++ ERR_print_errors(out); ++ } ++ BIO_printf(out, "%s\n", OCSP_cert_status_str(status)); ++ ++ BIO_puts(out, "\tThis Update: "); ++ ASN1_GENERALIZEDTIME_print(out, thisupd); ++ BIO_puts(out, "\n"); ++ ++ if (nextupd) { ++ BIO_puts(out, "\tNext Update: "); ++ ASN1_GENERALIZEDTIME_print(out, nextupd); ++ BIO_puts(out, "\n"); ++ } ++ ++ if (status != V_OCSP_CERTSTATUS_REVOKED) ++ continue; ++ ++ if (reason != -1) ++ BIO_printf(out, "\tReason: %s\n", OCSP_crl_reason_str(reason)); ++ ++ BIO_puts(out, "\tRevocation Time: "); ++ ASN1_GENERALIZEDTIME_print(out, rev); ++ BIO_puts(out, "\n"); ++ } ++} ++ ++static void make_ocsp_response(OCSP_RESPONSE **resp, OCSP_REQUEST *req, ++ CA_DB *db, X509 *ca, X509 *rcert, ++ EVP_PKEY *rkey, const EVP_MD *rmd, ++ STACK_OF(X509) *rother, unsigned long flags, ++ int nmin, int ndays, int badsig) ++{ ++ ASN1_TIME *thisupd = NULL, *nextupd = NULL; ++ OCSP_CERTID *cid, *ca_id = NULL; ++ OCSP_BASICRESP *bs = NULL; ++ int i, id_count; ++ ++ id_count = OCSP_request_onereq_count(req); ++ ++ if (id_count <= 0) { ++ *resp = ++ OCSP_response_create(OCSP_RESPONSE_STATUS_MALFORMEDREQUEST, NULL); ++ goto end; ++ } ++ ++ bs = OCSP_BASICRESP_new(); ++ thisupd = X509_gmtime_adj(NULL, 0); ++ if (ndays != -1) ++ nextupd = X509_time_adj_ex(NULL, ndays, nmin * 60, NULL); ++ ++ /* Examine each certificate id in the request */ ++ for (i = 0; i < id_count; i++) { ++ OCSP_ONEREQ *one; ++ ASN1_INTEGER *serial; ++ char **inf; ++ ASN1_OBJECT *cert_id_md_oid; ++ const EVP_MD *cert_id_md; ++ one = OCSP_request_onereq_get0(req, i); ++ cid = OCSP_onereq_get0_id(one); ++ ++ OCSP_id_get0_info(NULL, &cert_id_md_oid, NULL, NULL, cid); ++ ++ cert_id_md = EVP_get_digestbyobj(cert_id_md_oid); ++ if (!cert_id_md) { ++ *resp = OCSP_response_create(OCSP_RESPONSE_STATUS_INTERNALERROR, ++ NULL); ++ goto end; ++ } ++ OCSP_CERTID_free(ca_id); ++ ca_id = OCSP_cert_to_id(cert_id_md, NULL, ca); ++ ++ /* Is this request about our CA? */ ++ if (OCSP_id_issuer_cmp(ca_id, cid)) { ++ OCSP_basic_add1_status(bs, cid, ++ V_OCSP_CERTSTATUS_UNKNOWN, ++ 0, NULL, thisupd, nextupd); ++ continue; ++ } ++ OCSP_id_get0_info(NULL, NULL, NULL, &serial, cid); ++ inf = lookup_serial(db, serial); ++ if (!inf) ++ OCSP_basic_add1_status(bs, cid, ++ V_OCSP_CERTSTATUS_UNKNOWN, ++ 0, NULL, thisupd, nextupd); ++ else if (inf[DB_type][0] == DB_TYPE_VAL) ++ OCSP_basic_add1_status(bs, cid, ++ V_OCSP_CERTSTATUS_GOOD, ++ 0, NULL, thisupd, nextupd); ++ else if (inf[DB_type][0] == DB_TYPE_REV) { ++ ASN1_OBJECT *inst = NULL; ++ ASN1_TIME *revtm = NULL; ++ ASN1_GENERALIZEDTIME *invtm = NULL; ++ OCSP_SINGLERESP *single; ++ int reason = -1; ++ unpack_revinfo(&revtm, &reason, &inst, &invtm, inf[DB_rev_date]); ++ single = OCSP_basic_add1_status(bs, cid, ++ V_OCSP_CERTSTATUS_REVOKED, ++ reason, revtm, thisupd, nextupd); ++ if (invtm) ++ OCSP_SINGLERESP_add1_ext_i2d(single, NID_invalidity_date, ++ invtm, 0, 0); ++ else if (inst) ++ OCSP_SINGLERESP_add1_ext_i2d(single, ++ NID_hold_instruction_code, inst, ++ 0, 0); ++ ASN1_OBJECT_free(inst); ++ ASN1_TIME_free(revtm); ++ ASN1_GENERALIZEDTIME_free(invtm); ++ } ++ } ++ ++ OCSP_copy_nonce(bs, req); ++ ++ OCSP_basic_sign(bs, rcert, rkey, rmd, rother, flags); ++ ++ if (badsig) { ++ const ASN1_OCTET_STRING *sig = OCSP_resp_get0_signature(bs); ++ corrupt_signature(sig); ++ } ++ ++ *resp = OCSP_response_create(OCSP_RESPONSE_STATUS_SUCCESSFUL, bs); ++ ++ end: ++ ASN1_TIME_free(thisupd); ++ ASN1_TIME_free(nextupd); ++ OCSP_CERTID_free(ca_id); ++ OCSP_BASICRESP_free(bs); ++} ++ ++static char **lookup_serial(CA_DB *db, ASN1_INTEGER *ser) ++{ ++ int i; ++ BIGNUM *bn = NULL; ++ char *itmp, *row[DB_NUMBER], **rrow; ++ for (i = 0; i < DB_NUMBER; i++) ++ row[i] = NULL; ++ bn = ASN1_INTEGER_to_BN(ser, NULL); ++ OPENSSL_assert(bn); /* FIXME: should report an error at this ++ * point and abort */ ++ if (BN_is_zero(bn)) ++ itmp = OPENSSL_strdup("00"); ++ else ++ itmp = BN_bn2hex(bn); ++ row[DB_serial] = itmp; ++ BN_free(bn); ++ rrow = TXT_DB_get_by_index(db->db, DB_serial, row); ++ OPENSSL_free(itmp); ++ return rrow; ++} ++ ++/* Quick and dirty OCSP server: read in and parse input request */ ++ ++static BIO *init_responder(const char *port) ++{ ++# ifdef OPENSSL_NO_SOCK ++ BIO_printf(bio_err, ++ "Error setting up accept BIO - sockets not supported.\n"); ++ return NULL; ++# else ++ BIO *acbio = NULL, *bufbio = NULL; ++ ++ bufbio = BIO_new(BIO_f_buffer()); ++ if (bufbio == NULL) ++ goto err; ++ acbio = BIO_new(BIO_s_accept()); ++ if (acbio == NULL ++ || BIO_set_bind_mode(acbio, BIO_BIND_REUSEADDR) < 0 ++ || BIO_set_accept_port(acbio, port) < 0) { ++ BIO_printf(bio_err, "Error setting up accept BIO\n"); ++ ERR_print_errors(bio_err); ++ goto err; ++ } ++ ++ BIO_set_accept_bios(acbio, bufbio); ++ bufbio = NULL; ++ if (BIO_do_accept(acbio) <= 0) { ++ BIO_printf(bio_err, "Error starting accept\n"); ++ ERR_print_errors(bio_err); ++ goto err; ++ } ++ ++ return acbio; ++ ++ err: ++ BIO_free_all(acbio); ++ BIO_free(bufbio); ++ return NULL; ++# endif ++} ++ ++# ifndef OPENSSL_NO_SOCK ++/* ++ * Decode %xx URL-decoding in-place. Ignores mal-formed sequences. ++ */ ++static int urldecode(char *p) ++{ ++ unsigned char *out = (unsigned char *)p; ++ unsigned char *save = out; ++ ++ for (; *p; p++) { ++ if (*p != '%') ++ *out++ = *p; ++ else if (isxdigit(_UC(p[1])) && isxdigit(_UC(p[2]))) { ++ /* Don't check, can't fail because of ixdigit() call. */ ++ *out++ = (OPENSSL_hexchar2int(p[1]) << 4) ++ | OPENSSL_hexchar2int(p[2]); ++ p += 2; ++ } ++ else ++ return -1; ++ } ++ *out = '\0'; ++ return (int)(out - save); ++} ++# endif ++ ++static int do_responder(OCSP_REQUEST **preq, BIO **pcbio, BIO *acbio) ++{ ++# ifdef OPENSSL_NO_SOCK ++ return 0; ++# else ++ int len; ++ OCSP_REQUEST *req = NULL; ++ char inbuf[2048], reqbuf[2048]; ++ char *p, *q; ++ BIO *cbio = NULL, *getbio = NULL, *b64 = NULL; ++ ++ if (BIO_do_accept(acbio) <= 0) { ++ BIO_printf(bio_err, "Error accepting connection\n"); ++ ERR_print_errors(bio_err); ++ return 0; ++ } ++ ++ cbio = BIO_pop(acbio); ++ *pcbio = cbio; ++ ++ /* Read the request line. */ ++ len = BIO_gets(cbio, reqbuf, sizeof reqbuf); ++ if (len <= 0) ++ return 1; ++ if (strncmp(reqbuf, "GET ", 4) == 0) { ++ /* Expecting GET {sp} /URL {sp} HTTP/1.x */ ++ for (p = reqbuf + 4; *p == ' '; ++p) ++ continue; ++ if (*p != '/') { ++ BIO_printf(bio_err, "Invalid request -- bad URL\n"); ++ return 1; ++ } ++ p++; ++ ++ /* Splice off the HTTP version identifier. */ ++ for (q = p; *q; q++) ++ if (*q == ' ') ++ break; ++ if (strncmp(q, " HTTP/1.", 8) != 0) { ++ BIO_printf(bio_err, "Invalid request -- bad HTTP vesion\n"); ++ return 1; ++ } ++ *q = '\0'; ++ len = urldecode(p); ++ if (len <= 0) { ++ BIO_printf(bio_err, "Invalid request -- bad URL encoding\n"); ++ return 1; ++ } ++ if ((getbio = BIO_new_mem_buf(p, len)) == NULL ++ || (b64 = BIO_new(BIO_f_base64())) == NULL) { ++ BIO_printf(bio_err, "Could not allocate memory\n"); ++ ERR_print_errors(bio_err); ++ return 1; ++ } ++ BIO_set_flags(b64, BIO_FLAGS_BASE64_NO_NL); ++ getbio = BIO_push(b64, getbio); ++ } else if (strncmp(reqbuf, "POST ", 5) != 0) { ++ BIO_printf(bio_err, "Invalid request -- bad HTTP verb\n"); ++ return 1; ++ } ++ ++ /* Read and skip past the headers. */ ++ for (;;) { ++ len = BIO_gets(cbio, inbuf, sizeof inbuf); ++ if (len <= 0) ++ return 1; ++ if ((inbuf[0] == '\r') || (inbuf[0] == '\n')) ++ break; ++ } ++ ++ /* Try to read OCSP request */ ++ if (getbio) { ++ req = d2i_OCSP_REQUEST_bio(getbio, NULL); ++ BIO_free_all(getbio); ++ } else ++ req = d2i_OCSP_REQUEST_bio(cbio, NULL); ++ ++ if (!req) { ++ BIO_printf(bio_err, "Error parsing OCSP request\n"); ++ ERR_print_errors(bio_err); ++ } ++ ++ *preq = req; ++ ++ return 1; ++# endif ++} ++ ++static int send_ocsp_response(BIO *cbio, OCSP_RESPONSE *resp) ++{ ++ char http_resp[] = ++ "HTTP/1.0 200 OK\r\nContent-type: application/ocsp-response\r\n" ++ "Content-Length: %d\r\n\r\n"; ++ if (!cbio) ++ return 0; ++ BIO_printf(cbio, http_resp, i2d_OCSP_RESPONSE(resp, NULL)); ++ i2d_OCSP_RESPONSE_bio(cbio, resp); ++ (void)BIO_flush(cbio); ++ return 1; ++} ++ ++# ifndef OPENSSL_NO_SOCK ++static OCSP_RESPONSE *query_responder(BIO *cbio, const char *host, ++ const char *path, ++ const STACK_OF(CONF_VALUE) *headers, ++ OCSP_REQUEST *req, int req_timeout) ++{ ++ int fd; ++ int rv; ++ int i; ++ int add_host = 1; ++ OCSP_REQ_CTX *ctx = NULL; ++ OCSP_RESPONSE *rsp = NULL; ++ fd_set confds; ++ struct timeval tv; ++ ++ if (req_timeout != -1) ++ BIO_set_nbio(cbio, 1); ++ ++ rv = BIO_do_connect(cbio); ++ ++ if ((rv <= 0) && ((req_timeout == -1) || !BIO_should_retry(cbio))) { ++ BIO_puts(bio_err, "Error connecting BIO\n"); ++ return NULL; ++ } ++ ++ if (BIO_get_fd(cbio, &fd) < 0) { ++ BIO_puts(bio_err, "Can't get connection fd\n"); ++ goto err; ++ } ++ ++ if (req_timeout != -1 && rv <= 0) { ++ FD_ZERO(&confds); ++ openssl_fdset(fd, &confds); ++ tv.tv_usec = 0; ++ tv.tv_sec = req_timeout; ++ rv = select(fd + 1, NULL, (void *)&confds, NULL, &tv); ++ if (rv == 0) { ++ BIO_puts(bio_err, "Timeout on connect\n"); ++ return NULL; ++ } ++ } ++ ++ ctx = OCSP_sendreq_new(cbio, path, NULL, -1); ++ if (ctx == NULL) ++ return NULL; ++ ++ for (i = 0; i < sk_CONF_VALUE_num(headers); i++) { ++ CONF_VALUE *hdr = sk_CONF_VALUE_value(headers, i); ++ if (add_host == 1 && strcasecmp("host", hdr->name) == 0) ++ add_host = 0; ++ if (!OCSP_REQ_CTX_add1_header(ctx, hdr->name, hdr->value)) ++ goto err; ++ } ++ ++ if (add_host == 1 && OCSP_REQ_CTX_add1_header(ctx, "Host", host) == 0) ++ goto err; ++ ++ if (!OCSP_REQ_CTX_set1_req(ctx, req)) ++ goto err; ++ ++ for (;;) { ++ rv = OCSP_sendreq_nbio(&rsp, ctx); ++ if (rv != -1) ++ break; ++ if (req_timeout == -1) ++ continue; ++ FD_ZERO(&confds); ++ openssl_fdset(fd, &confds); ++ tv.tv_usec = 0; ++ tv.tv_sec = req_timeout; ++ if (BIO_should_read(cbio)) ++ rv = select(fd + 1, (void *)&confds, NULL, NULL, &tv); ++ else if (BIO_should_write(cbio)) ++ rv = select(fd + 1, NULL, (void *)&confds, NULL, &tv); ++ else { ++ BIO_puts(bio_err, "Unexpected retry condition\n"); ++ goto err; ++ } ++ if (rv == 0) { ++ BIO_puts(bio_err, "Timeout on request\n"); ++ break; ++ } ++ if (rv == -1) { ++ BIO_puts(bio_err, "Select error\n"); ++ break; ++ } ++ ++ } ++ err: ++ OCSP_REQ_CTX_free(ctx); ++ ++ return rsp; ++} ++ ++OCSP_RESPONSE *process_responder(OCSP_REQUEST *req, ++ const char *host, const char *path, ++ const char *port, int use_ssl, ++ STACK_OF(CONF_VALUE) *headers, ++ int req_timeout) ++{ ++ BIO *cbio = NULL; ++ SSL_CTX *ctx = NULL; ++ OCSP_RESPONSE *resp = NULL; ++ ++ cbio = BIO_new_connect(host); ++ if (!cbio) { ++ BIO_printf(bio_err, "Error creating connect BIO\n"); ++ goto end; ++ } ++ if (port) ++ BIO_set_conn_port(cbio, port); ++ if (use_ssl == 1) { ++ BIO *sbio; ++ ctx = SSL_CTX_new(TLS_client_method()); ++ if (ctx == NULL) { ++ BIO_printf(bio_err, "Error creating SSL context.\n"); ++ goto end; ++ } ++ SSL_CTX_set_mode(ctx, SSL_MODE_AUTO_RETRY); ++ sbio = BIO_new_ssl(ctx, 1); ++ cbio = BIO_push(sbio, cbio); ++ } ++ ++ resp = query_responder(cbio, host, path, headers, req, req_timeout); ++ if (!resp) ++ BIO_printf(bio_err, "Error querying OCSP responder\n"); ++ end: ++ BIO_free_all(cbio); ++ SSL_CTX_free(ctx); ++ return resp; ++} ++# endif ++ ++#endif +diff --git a/CryptoPkg/Library/OpensslLib/openssl/apps/openssl-vms.cnf b/CryptoPkg/Library/OpensslLib/openssl/apps/openssl-vms.cnf +new file mode 100644 +index 0000000..0092a65 +--- /dev/null ++++ b/CryptoPkg/Library/OpensslLib/openssl/apps/openssl-vms.cnf +@@ -0,0 +1,346 @@ ++# ++# OpenSSL example configuration file. ++# This is mostly being used for generation of certificate requests. ++# ++ ++# This definition stops the following lines choking if HOME isn't ++# defined. ++HOME = . ++RANDFILE = $ENV::HOME/.rnd ++ ++# Extra OBJECT IDENTIFIER info: ++#oid_file = $ENV::HOME/.oid ++oid_section = new_oids ++ ++# To use this configuration file with the "-extfile" option of the ++# "openssl x509" utility, name here the section containing the ++# X.509v3 extensions to use: ++# extensions = ++# (Alternatively, use a configuration file that has only ++# X.509v3 extensions in its main [= default] section.) ++ ++[ new_oids ] ++ ++# We can add new OIDs in here for use by 'ca', 'req' and 'ts'. ++# Add a simple OID like this: ++# testoid1=1.2.3.4 ++# Or use config file substitution like this: ++# testoid2=${testoid1}.5.6 ++ ++# Policies used by the TSA examples. ++tsa_policy1 = 1.2.3.4.1 ++tsa_policy2 = 1.2.3.4.5.6 ++tsa_policy3 = 1.2.3.4.5.7 ++ ++#################################################################### ++[ ca ] ++default_ca = CA_default # The default ca section ++ ++#################################################################### ++[ CA_default ] ++ ++dir = sys\$disk:[.demoCA # Where everything is kept ++certs = $dir.certs] # Where the issued certs are kept ++crl_dir = $dir.crl] # Where the issued crl are kept ++database = $dir]index.txt # database index file. ++#unique_subject = no # Set to 'no' to allow creation of ++ # several certs with same subject. ++new_certs_dir = $dir.newcerts] # default place for new certs. ++ ++certificate = $dir]cacert.pem # The CA certificate ++serial = $dir]serial. # The current serial number ++crlnumber = $dir]crlnumber. # the current crl number ++ # must be commented out to leave a V1 CRL ++crl = $dir]crl.pem # The current CRL ++private_key = $dir.private]cakey.pem# The private key ++RANDFILE = $dir.private].rand # private random number file ++ ++x509_extensions = usr_cert # The extensions to add to the cert ++ ++# Comment out the following two lines for the "traditional" ++# (and highly broken) format. ++name_opt = ca_default # Subject Name options ++cert_opt = ca_default # Certificate field options ++ ++# Extension copying option: use with caution. ++# copy_extensions = copy ++ ++# Extensions to add to a CRL. Note: Netscape communicator chokes on V2 CRLs ++# so this is commented out by default to leave a V1 CRL. ++# crlnumber must also be commented out to leave a V1 CRL. ++# crl_extensions = crl_ext ++ ++default_days = 365 # how long to certify for ++default_crl_days= 30 # how long before next CRL ++default_md = default # use public key default MD ++preserve = no # keep passed DN ordering ++ ++# A few difference way of specifying how similar the request should look ++# For type CA, the listed attributes must be the same, and the optional ++# and supplied fields are just that :-) ++policy = policy_match ++ ++# For the CA policy ++[ policy_match ] ++countryName = match ++stateOrProvinceName = match ++organizationName = match ++organizationalUnitName = optional ++commonName = supplied ++emailAddress = optional ++ ++# For the 'anything' policy ++# At this point in time, you must list all acceptable 'object' ++# types. ++[ policy_anything ] ++countryName = optional ++stateOrProvinceName = optional ++localityName = optional ++organizationName = optional ++organizationalUnitName = optional ++commonName = supplied ++emailAddress = optional ++ ++#################################################################### ++[ req ] ++default_bits = 2048 ++default_keyfile = privkey.pem ++distinguished_name = req_distinguished_name ++attributes = req_attributes ++x509_extensions = v3_ca # The extensions to add to the self signed cert ++ ++# Passwords for private keys if not present they will be prompted for ++# input_password = secret ++# output_password = secret ++ ++# This sets a mask for permitted string types. There are several options. ++# default: PrintableString, T61String, BMPString. ++# pkix : PrintableString, BMPString (PKIX recommendation before 2004) ++# utf8only: only UTF8Strings (PKIX recommendation after 2004). ++# nombstr : PrintableString, T61String (no BMPStrings or UTF8Strings). ++# MASK:XXXX a literal mask value. ++# WARNING: ancient versions of Netscape crash on BMPStrings or UTF8Strings. ++string_mask = utf8only ++ ++# req_extensions = v3_req # The extensions to add to a certificate request ++ ++[ req_distinguished_name ] ++countryName = Country Name (2 letter code) ++countryName_default = AU ++countryName_min = 2 ++countryName_max = 2 ++ ++stateOrProvinceName = State or Province Name (full name) ++stateOrProvinceName_default = Some-State ++ ++localityName = Locality Name (eg, city) ++ ++0.organizationName = Organization Name (eg, company) ++0.organizationName_default = Internet Widgits Pty Ltd ++ ++# we can do this but it is not needed normally :-) ++#1.organizationName = Second Organization Name (eg, company) ++#1.organizationName_default = World Wide Web Pty Ltd ++ ++organizationalUnitName = Organizational Unit Name (eg, section) ++#organizationalUnitName_default = ++ ++commonName = Common Name (e.g. server FQDN or YOUR name) ++commonName_max = 64 ++ ++emailAddress = Email Address ++emailAddress_max = 64 ++ ++# SET-ex3 = SET extension number 3 ++ ++[ req_attributes ] ++challengePassword = A challenge password ++challengePassword_min = 4 ++challengePassword_max = 20 ++ ++unstructuredName = An optional company name ++ ++[ usr_cert ] ++ ++# These extensions are added when 'ca' signs a request. ++ ++# This goes against PKIX guidelines but some CAs do it and some software ++# requires this to avoid interpreting an end user certificate as a CA. ++ ++basicConstraints=CA:FALSE ++ ++# Here are some examples of the usage of nsCertType. If it is omitted ++# the certificate can be used for anything *except* object signing. ++ ++# This is OK for an SSL server. ++# nsCertType = server ++ ++# For an object signing certificate this would be used. ++# nsCertType = objsign ++ ++# For normal client use this is typical ++# nsCertType = client, email ++ ++# and for everything including object signing: ++# nsCertType = client, email, objsign ++ ++# This is typical in keyUsage for a client certificate. ++# keyUsage = nonRepudiation, digitalSignature, keyEncipherment ++ ++# This will be displayed in Netscape's comment listbox. ++nsComment = "OpenSSL Generated Certificate" ++ ++# PKIX recommendations harmless if included in all certificates. ++subjectKeyIdentifier=hash ++authorityKeyIdentifier=keyid,issuer ++ ++# This stuff is for subjectAltName and issuerAltname. ++# Import the email address. ++# subjectAltName=email:copy ++# An alternative to produce certificates that aren't ++# deprecated according to PKIX. ++# subjectAltName=email:move ++ ++# Copy subject details ++# issuerAltName=issuer:copy ++ ++#nsCaRevocationUrl = http://www.domain.dom/ca-crl.pem ++#nsBaseUrl ++#nsRevocationUrl ++#nsRenewalUrl ++#nsCaPolicyUrl ++#nsSslServerName ++ ++# This is required for TSA certificates. ++# extendedKeyUsage = critical,timeStamping ++ ++[ v3_req ] ++ ++# Extensions to add to a certificate request ++ ++basicConstraints = CA:FALSE ++keyUsage = nonRepudiation, digitalSignature, keyEncipherment ++ ++[ v3_ca ] ++ ++ ++# Extensions for a typical CA ++ ++ ++# PKIX recommendation. ++ ++subjectKeyIdentifier=hash ++ ++authorityKeyIdentifier=keyid:always,issuer ++ ++basicConstraints = critical,CA:true ++ ++# Key usage: this is typical for a CA certificate. However since it will ++# prevent it being used as an test self-signed certificate it is best ++# left out by default. ++# keyUsage = cRLSign, keyCertSign ++ ++# Some might want this also ++# nsCertType = sslCA, emailCA ++ ++# Include email address in subject alt name: another PKIX recommendation ++# subjectAltName=email:copy ++# Copy issuer details ++# issuerAltName=issuer:copy ++ ++# DER hex encoding of an extension: beware experts only! ++# obj=DER:02:03 ++# Where 'obj' is a standard or added object ++# You can even override a supported extension: ++# basicConstraints= critical, DER:30:03:01:01:FF ++ ++[ crl_ext ] ++ ++# CRL extensions. ++# Only issuerAltName and authorityKeyIdentifier make any sense in a CRL. ++ ++# issuerAltName=issuer:copy ++authorityKeyIdentifier=keyid:always ++ ++[ proxy_cert_ext ] ++# These extensions should be added when creating a proxy certificate ++ ++# This goes against PKIX guidelines but some CAs do it and some software ++# requires this to avoid interpreting an end user certificate as a CA. ++ ++basicConstraints=CA:FALSE ++ ++# Here are some examples of the usage of nsCertType. If it is omitted ++# the certificate can be used for anything *except* object signing. ++ ++# This is OK for an SSL server. ++# nsCertType = server ++ ++# For an object signing certificate this would be used. ++# nsCertType = objsign ++ ++# For normal client use this is typical ++# nsCertType = client, email ++ ++# and for everything including object signing: ++# nsCertType = client, email, objsign ++ ++# This is typical in keyUsage for a client certificate. ++# keyUsage = nonRepudiation, digitalSignature, keyEncipherment ++ ++# This will be displayed in Netscape's comment listbox. ++nsComment = "OpenSSL Generated Certificate" ++ ++# PKIX recommendations harmless if included in all certificates. ++subjectKeyIdentifier=hash ++authorityKeyIdentifier=keyid,issuer ++ ++# This stuff is for subjectAltName and issuerAltname. ++# Import the email address. ++# subjectAltName=email:copy ++# An alternative to produce certificates that aren't ++# deprecated according to PKIX. ++# subjectAltName=email:move ++ ++# Copy subject details ++# issuerAltName=issuer:copy ++ ++#nsCaRevocationUrl = http://www.domain.dom/ca-crl.pem ++#nsBaseUrl ++#nsRevocationUrl ++#nsRenewalUrl ++#nsCaPolicyUrl ++#nsSslServerName ++ ++# This really needs to be in place for it to be a proxy certificate. ++proxyCertInfo=critical,language:id-ppl-anyLanguage,pathlen:3,policy:foo ++ ++#################################################################### ++[ tsa ] ++ ++default_tsa = tsa_config1 # the default TSA section ++ ++[ tsa_config1 ] ++ ++# These are used by the TSA reply generation only. ++dir = sys\$disk:[.demoCA # TSA root directory ++serial = $dir]tsaserial. # The current serial number (mandatory) ++crypto_device = builtin # OpenSSL engine to use for signing ++signer_cert = $dir/tsacert.pem # The TSA signing certificate ++ # (optional) ++certs = $dir.cacert.pem] # Certificate chain to include in reply ++ # (optional) ++signer_key = $dir/private/tsakey.pem # The TSA private key (optional) ++signer_digest = sha256 # Signing digest to use. (Optional) ++default_policy = tsa_policy1 # Policy if request did not specify it ++ # (optional) ++other_policies = tsa_policy2, tsa_policy3 # acceptable policies (optional) ++digests = sha1, sha256, sha384, sha512 # Acceptable message digests (mandatory) ++accuracy = secs:1, millisecs:500, microsecs:100 # (optional) ++clock_precision_digits = 0 # number of digits after dot. (optional) ++ordering = yes # Is ordering defined for timestamps? ++ # (optional, default: no) ++tsa_name = yes # Must the TSA name be included in the reply? ++ # (optional, default: no) ++ess_cert_id_chain = no # Must the ESS cert id chain be included? ++ # (optional, default: no) +diff --git a/CryptoPkg/Library/OpensslLib/openssl/apps/openssl.c b/CryptoPkg/Library/OpensslLib/openssl/apps/openssl.c +new file mode 100644 +index 0000000..e69e7d9 +--- /dev/null ++++ b/CryptoPkg/Library/OpensslLib/openssl/apps/openssl.c +@@ -0,0 +1,695 @@ ++/* ++ * Copyright 1995-2016 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 ++ * in the file LICENSE in the source distribution or at ++ * https://www.openssl.org/source/license.html ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#ifndef OPENSSL_NO_ENGINE ++# include ++#endif ++#include ++#ifdef OPENSSL_FIPS ++# include ++#endif ++#define USE_SOCKETS /* needed for the _O_BINARY defs in the MS world */ ++#include "s_apps.h" ++/* Needed to get the other O_xxx flags. */ ++#ifdef OPENSSL_SYS_VMS ++# include ++#endif ++#define INCLUDE_FUNCTION_TABLE ++#include "apps.h" ++ ++ ++#ifdef OPENSSL_NO_CAMELLIA ++# define FORMAT "%-15s" ++# define COLUMNS 5 ++#else ++# define FORMAT "%-18s" ++# define COLUMNS 4 ++#endif ++ ++/* Special sentinel to exit the program. */ ++#define EXIT_THE_PROGRAM (-1) ++ ++/* ++ * The LHASH callbacks ("hash" & "cmp") have been replaced by functions with ++ * the base prototypes (we cast each variable inside the function to the ++ * required type of "FUNCTION*"). This removes the necessity for ++ * macro-generated wrapper functions. ++ */ ++static LHASH_OF(FUNCTION) *prog_init(void); ++static int do_cmd(LHASH_OF(FUNCTION) *prog, int argc, char *argv[]); ++static void list_pkey(void); ++static void list_type(FUNC_TYPE ft); ++static void list_disabled(void); ++char *default_config_file = NULL; ++ ++BIO *bio_in = NULL; ++BIO *bio_out = NULL; ++BIO *bio_err = NULL; ++ ++static int apps_startup() ++{ ++#ifdef SIGPIPE ++ signal(SIGPIPE, SIG_IGN); ++#endif ++ ++ /* Set non-default library initialisation settings */ ++ if (!OPENSSL_init_crypto(OPENSSL_INIT_ENGINE_ALL_BUILTIN ++ | OPENSSL_INIT_LOAD_CONFIG, NULL)) ++ return 0; ++ ++#ifndef OPENSSL_NO_UI ++ setup_ui_method(); ++#endif ++ ++ return 1; ++} ++ ++static void apps_shutdown() ++{ ++#ifndef OPENSSL_NO_UI ++ destroy_ui_method(); ++#endif ++} ++ ++static char *make_config_name() ++{ ++ const char *t; ++ size_t len; ++ char *p; ++ ++ if ((t = getenv("OPENSSL_CONF")) != NULL) ++ return OPENSSL_strdup(t); ++ ++ t = X509_get_default_cert_area(); ++ len = strlen(t) + 1 + strlen(OPENSSL_CONF) + 1; ++ p = app_malloc(len, "config filename buffer"); ++ strcpy(p, t); ++#ifndef OPENSSL_SYS_VMS ++ strcat(p, "/"); ++#endif ++ strcat(p, OPENSSL_CONF); ++ ++ return p; ++} ++ ++int main(int argc, char *argv[]) ++{ ++ FUNCTION f, *fp; ++ LHASH_OF(FUNCTION) *prog = NULL; ++ char **copied_argv = NULL; ++ char *p, *pname; ++ char buf[1024]; ++ const char *prompt; ++ ARGS arg; ++ int first, n, i, ret = 0; ++ ++ arg.argv = NULL; ++ arg.size = 0; ++ ++ /* Set up some of the environment. */ ++ default_config_file = make_config_name(); ++ bio_in = dup_bio_in(FORMAT_TEXT); ++ bio_out = dup_bio_out(FORMAT_TEXT); ++ bio_err = dup_bio_err(FORMAT_TEXT); ++ ++#if defined(OPENSSL_SYS_VMS) && defined(__DECC) ++ copied_argv = argv = copy_argv(&argc, argv); ++#elif defined(_WIN32) ++ /* ++ * Replace argv[] with UTF-8 encoded strings. ++ */ ++ win32_utf8argv(&argc, &argv); ++#endif ++ ++ p = getenv("OPENSSL_DEBUG_MEMORY"); ++ if (p != NULL && strcmp(p, "on") == 0) ++ CRYPTO_set_mem_debug(1); ++ CRYPTO_mem_ctrl(CRYPTO_MEM_CHECK_ON); ++ ++ if (getenv("OPENSSL_FIPS")) { ++#ifdef OPENSSL_FIPS ++ if (!FIPS_mode_set(1)) { ++ ERR_print_errors(bio_err); ++ return 1; ++ } ++#else ++ BIO_printf(bio_err, "FIPS mode not supported.\n"); ++ return 1; ++#endif ++ } ++ ++ if (!apps_startup()) ++ goto end; ++ ++ prog = prog_init(); ++ pname = opt_progname(argv[0]); ++ ++ /* first check the program name */ ++ f.name = pname; ++ fp = lh_FUNCTION_retrieve(prog, &f); ++ if (fp != NULL) { ++ argv[0] = pname; ++ ret = fp->func(argc, argv); ++ goto end; ++ } ++ ++ /* If there is stuff on the command line, run with that. */ ++ if (argc != 1) { ++ argc--; ++ argv++; ++ ret = do_cmd(prog, argc, argv); ++ if (ret < 0) ++ ret = 0; ++ goto end; ++ } ++ ++ /* ok, lets enter interactive mode */ ++ for (;;) { ++ ret = 0; ++ /* Read a line, continue reading if line ends with \ */ ++ for (p = buf, n = sizeof buf, i = 0, first = 1; n > 0; first = 0) { ++ prompt = first ? "OpenSSL> " : "> "; ++ p[0] = '\0'; ++#ifndef READLINE ++ fputs(prompt, stdout); ++ fflush(stdout); ++ if (!fgets(p, n, stdin)) ++ goto end; ++ if (p[0] == '\0') ++ goto end; ++ i = strlen(p); ++ if (i <= 1) ++ break; ++ if (p[i - 2] != '\\') ++ break; ++ i -= 2; ++ p += i; ++ n -= i; ++#else ++ { ++ extern char *readline(const char *); ++ extern void add_history(const char *cp); ++ char *text; ++ ++ text = readline(prompt); ++ if (text == NULL) ++ goto end; ++ i = strlen(text); ++ if (i == 0 || i > n) ++ break; ++ if (text[i - 1] != '\\') { ++ p += strlen(strcpy(p, text)); ++ free(text); ++ add_history(buf); ++ break; ++ } ++ ++ text[i - 1] = '\0'; ++ p += strlen(strcpy(p, text)); ++ free(text); ++ n -= i; ++ } ++#endif ++ } ++ ++ if (!chopup_args(&arg, buf)) { ++ BIO_printf(bio_err, "Can't parse (no memory?)\n"); ++ break; ++ } ++ ++ ret = do_cmd(prog, arg.argc, arg.argv); ++ if (ret == EXIT_THE_PROGRAM) { ++ ret = 0; ++ goto end; ++ } ++ if (ret != 0) ++ BIO_printf(bio_err, "error in %s\n", arg.argv[0]); ++ (void)BIO_flush(bio_out); ++ (void)BIO_flush(bio_err); ++ } ++ ret = 1; ++ end: ++ OPENSSL_free(copied_argv); ++ OPENSSL_free(default_config_file); ++ lh_FUNCTION_free(prog); ++ OPENSSL_free(arg.argv); ++ ++ BIO_free(bio_in); ++ BIO_free_all(bio_out); ++ apps_shutdown(); ++#ifndef OPENSSL_NO_CRYPTO_MDEBUG ++ if (CRYPTO_mem_leaks(bio_err) <= 0) ++ ret = 1; ++#endif ++ BIO_free(bio_err); ++ EXIT(ret); ++} ++ ++OPTIONS exit_options[] = { ++ {NULL} ++}; ++ ++static void list_cipher_fn(const EVP_CIPHER *c, ++ const char *from, const char *to, void *arg) ++{ ++ if (c) ++ BIO_printf(arg, "%s\n", EVP_CIPHER_name(c)); ++ else { ++ if (!from) ++ from = ""; ++ if (!to) ++ to = ""; ++ BIO_printf(arg, "%s => %s\n", from, to); ++ } ++} ++ ++static void list_md_fn(const EVP_MD *m, ++ const char *from, const char *to, void *arg) ++{ ++ if (m) ++ BIO_printf(arg, "%s\n", EVP_MD_name(m)); ++ else { ++ if (!from) ++ from = ""; ++ if (!to) ++ to = ""; ++ BIO_printf((BIO *)arg, "%s => %s\n", from, to); ++ } ++} ++ ++/* Unified enum for help and list commands. */ ++typedef enum HELPLIST_CHOICE { ++ OPT_ERR = -1, OPT_EOF = 0, OPT_HELP, ++ OPT_COMMANDS, OPT_DIGEST_COMMANDS, ++ OPT_DIGEST_ALGORITHMS, OPT_CIPHER_COMMANDS, OPT_CIPHER_ALGORITHMS, ++ OPT_PK_ALGORITHMS, OPT_DISABLED ++} HELPLIST_CHOICE; ++ ++OPTIONS list_options[] = { ++ {"help", OPT_HELP, '-', "Display this summary"}, ++ {"commands", OPT_COMMANDS, '-', "List of standard commands"}, ++ {"digest-commands", OPT_DIGEST_COMMANDS, '-', ++ "List of message digest commands"}, ++ {"digest-algorithms", OPT_DIGEST_ALGORITHMS, '-', ++ "List of message digest algorithms"}, ++ {"cipher-commands", OPT_CIPHER_COMMANDS, '-', "List of cipher commands"}, ++ {"cipher-algorithms", OPT_CIPHER_ALGORITHMS, '-', ++ "List of cipher algorithms"}, ++ {"public-key-algorithms", OPT_PK_ALGORITHMS, '-', ++ "List of public key algorithms"}, ++ {"disabled", OPT_DISABLED, '-', ++ "List of disabled features"}, ++ {NULL} ++}; ++ ++int list_main(int argc, char **argv) ++{ ++ char *prog; ++ HELPLIST_CHOICE o; ++ int done = 0; ++ ++ prog = opt_init(argc, argv, list_options); ++ while ((o = opt_next()) != OPT_EOF) { ++ switch (o) { ++ case OPT_EOF: /* Never hit, but suppresses warning */ ++ case OPT_ERR: ++ BIO_printf(bio_err, "%s: Use -help for summary.\n", prog); ++ return 1; ++ case OPT_HELP: ++ opt_help(list_options); ++ break; ++ case OPT_COMMANDS: ++ list_type(FT_general); ++ break; ++ case OPT_DIGEST_COMMANDS: ++ list_type(FT_md); ++ break; ++ case OPT_DIGEST_ALGORITHMS: ++ EVP_MD_do_all_sorted(list_md_fn, bio_out); ++ break; ++ case OPT_CIPHER_COMMANDS: ++ list_type(FT_cipher); ++ break; ++ case OPT_CIPHER_ALGORITHMS: ++ EVP_CIPHER_do_all_sorted(list_cipher_fn, bio_out); ++ break; ++ case OPT_PK_ALGORITHMS: ++ list_pkey(); ++ break; ++ case OPT_DISABLED: ++ list_disabled(); ++ break; ++ } ++ done = 1; ++ } ++ ++ if (!done) { ++ BIO_printf(bio_err, "%s: Use -help for summary.\n", prog); ++ return 1; ++ } ++ ++ return 0; ++} ++ ++OPTIONS help_options[] = { ++ {"help", OPT_HELP, '-', "Display this summary"}, ++ {NULL} ++}; ++ ++int help_main(int argc, char **argv) ++{ ++ FUNCTION *fp; ++ int i, nl; ++ FUNC_TYPE tp; ++ char *prog; ++ HELPLIST_CHOICE o; ++ ++ prog = opt_init(argc, argv, help_options); ++ while ((o = opt_next()) != OPT_EOF) { ++ switch (o) { ++ default: ++ BIO_printf(bio_err, "%s: Use -help for summary.\n", prog); ++ return 1; ++ case OPT_HELP: ++ opt_help(help_options); ++ return 0; ++ } ++ } ++ ++ if (opt_num_rest() != 0) { ++ BIO_printf(bio_err, "Usage: %s\n", prog); ++ return 1; ++ } ++ ++ BIO_printf(bio_err, "\nStandard commands"); ++ i = 0; ++ tp = FT_none; ++ for (fp = functions; fp->name != NULL; fp++) { ++ nl = 0; ++ if (((i++) % COLUMNS) == 0) { ++ BIO_printf(bio_err, "\n"); ++ nl = 1; ++ } ++ if (fp->type != tp) { ++ tp = fp->type; ++ if (!nl) ++ BIO_printf(bio_err, "\n"); ++ if (tp == FT_md) { ++ i = 1; ++ BIO_printf(bio_err, ++ "\nMessage Digest commands (see the `dgst' command for more details)\n"); ++ } else if (tp == FT_cipher) { ++ i = 1; ++ BIO_printf(bio_err, ++ "\nCipher commands (see the `enc' command for more details)\n"); ++ } ++ } ++ BIO_printf(bio_err, FORMAT, fp->name); ++ } ++ BIO_printf(bio_err, "\n\n"); ++ return 0; ++} ++ ++int exit_main(int argc, char **argv) ++{ ++ return EXIT_THE_PROGRAM; ++} ++ ++static void list_type(FUNC_TYPE ft) ++{ ++ FUNCTION *fp; ++ int i = 0; ++ ++ for (fp = functions; fp->name != NULL; fp++) ++ if (fp->type == ft) { ++ if ((i++ % COLUMNS) == 0) ++ BIO_printf(bio_out, "\n"); ++ BIO_printf(bio_out, FORMAT, fp->name); ++ } ++ BIO_printf(bio_out, "\n"); ++} ++ ++static int do_cmd(LHASH_OF(FUNCTION) *prog, int argc, char *argv[]) ++{ ++ FUNCTION f, *fp; ++ ++ if (argc <= 0 || argv[0] == NULL) ++ return (0); ++ f.name = argv[0]; ++ fp = lh_FUNCTION_retrieve(prog, &f); ++ if (fp == NULL) { ++ if (EVP_get_digestbyname(argv[0])) { ++ f.type = FT_md; ++ f.func = dgst_main; ++ fp = &f; ++ } else if (EVP_get_cipherbyname(argv[0])) { ++ f.type = FT_cipher; ++ f.func = enc_main; ++ fp = &f; ++ } ++ } ++ if (fp != NULL) { ++ return (fp->func(argc, argv)); ++ } ++ if ((strncmp(argv[0], "no-", 3)) == 0) { ++ /* ++ * User is asking if foo is unsupported, by trying to "run" the ++ * no-foo command. Strange. ++ */ ++ f.name = argv[0] + 3; ++ if (lh_FUNCTION_retrieve(prog, &f) == NULL) { ++ BIO_printf(bio_out, "%s\n", argv[0]); ++ return (0); ++ } ++ BIO_printf(bio_out, "%s\n", argv[0] + 3); ++ return 1; ++ } ++ if (strcmp(argv[0], "quit") == 0 || strcmp(argv[0], "q") == 0 || ++ strcmp(argv[0], "exit") == 0 || strcmp(argv[0], "bye") == 0) ++ /* Special value to mean "exit the program. */ ++ return EXIT_THE_PROGRAM; ++ ++ BIO_printf(bio_err, "Invalid command '%s'; type \"help\" for a list.\n", ++ argv[0]); ++ return (1); ++} ++ ++static void list_pkey(void) ++{ ++ int i; ++ ++ for (i = 0; i < EVP_PKEY_asn1_get_count(); i++) { ++ const EVP_PKEY_ASN1_METHOD *ameth; ++ int pkey_id, pkey_base_id, pkey_flags; ++ const char *pinfo, *pem_str; ++ ameth = EVP_PKEY_asn1_get0(i); ++ EVP_PKEY_asn1_get0_info(&pkey_id, &pkey_base_id, &pkey_flags, ++ &pinfo, &pem_str, ameth); ++ if (pkey_flags & ASN1_PKEY_ALIAS) { ++ BIO_printf(bio_out, "Name: %s\n", OBJ_nid2ln(pkey_id)); ++ BIO_printf(bio_out, "\tAlias for: %s\n", ++ OBJ_nid2ln(pkey_base_id)); ++ } else { ++ BIO_printf(bio_out, "Name: %s\n", pinfo); ++ BIO_printf(bio_out, "\tType: %s Algorithm\n", ++ pkey_flags & ASN1_PKEY_DYNAMIC ? ++ "External" : "Builtin"); ++ BIO_printf(bio_out, "\tOID: %s\n", OBJ_nid2ln(pkey_id)); ++ if (pem_str == NULL) ++ pem_str = "(none)"; ++ BIO_printf(bio_out, "\tPEM string: %s\n", pem_str); ++ } ++ ++ } ++} ++ ++static int function_cmp(const FUNCTION * a, const FUNCTION * b) ++{ ++ return strncmp(a->name, b->name, 8); ++} ++ ++static unsigned long function_hash(const FUNCTION * a) ++{ ++ return OPENSSL_LH_strhash(a->name); ++} ++ ++static int SortFnByName(const void *_f1, const void *_f2) ++{ ++ const FUNCTION *f1 = _f1; ++ const FUNCTION *f2 = _f2; ++ ++ if (f1->type != f2->type) ++ return f1->type - f2->type; ++ return strcmp(f1->name, f2->name); ++} ++ ++static void list_disabled(void) ++{ ++ BIO_puts(bio_out, "Disabled algorithms:\n"); ++#ifdef OPENSSL_NO_BF ++ BIO_puts(bio_out, "BF\n"); ++#endif ++#ifdef OPENSSL_NO_BLAKE2 ++ BIO_puts(bio_out, "BLAKE2\n"); ++#endif ++#ifdef OPENSSL_NO_CAMELLIA ++ BIO_puts(bio_out, "CAMELLIA\n"); ++#endif ++#ifdef OPENSSL_NO_CAST ++ BIO_puts(bio_out, "CAST\n"); ++#endif ++#ifdef OPENSSL_NO_CMAC ++ BIO_puts(bio_out, "CMAC\n"); ++#endif ++#ifdef OPENSSL_NO_CMS ++ BIO_puts(bio_out, "CMS\n"); ++#endif ++#ifdef OPENSSL_NO_COMP ++ BIO_puts(bio_out, "COMP\n"); ++#endif ++#ifdef OPENSSL_NO_DES ++ BIO_puts(bio_out, "DES\n"); ++#endif ++#ifdef OPENSSL_NO_DGRAM ++ BIO_puts(bio_out, "DGRAM\n"); ++#endif ++#ifdef OPENSSL_NO_DH ++ BIO_puts(bio_out, "DH\n"); ++#endif ++#ifdef OPENSSL_NO_DSA ++ BIO_puts(bio_out, "DSA\n"); ++#endif ++#if defined(OPENSSL_NO_DTLS) ++ BIO_puts(bio_out, "DTLS\n"); ++#endif ++#if defined(OPENSSL_NO_DTLS1) ++ BIO_puts(bio_out, "DTLS1\n"); ++#endif ++#if defined(OPENSSL_NO_DTLS1_2) ++ BIO_puts(bio_out, "DTLS1_2\n"); ++#endif ++#ifdef OPENSSL_NO_EC ++ BIO_puts(bio_out, "EC\n"); ++#endif ++#ifdef OPENSSL_NO_EC2M ++ BIO_puts(bio_out, "EC2M\n"); ++#endif ++#ifdef OPENSSL_NO_ENGINE ++ BIO_puts(bio_out, "ENGINE\n"); ++#endif ++#ifdef OPENSSL_NO_GOST ++ BIO_puts(bio_out, "GOST\n"); ++#endif ++#ifdef OPENSSL_NO_HEARTBEATS ++ BIO_puts(bio_out, "HEARTBEATS\n"); ++#endif ++#ifdef OPENSSL_NO_IDEA ++ BIO_puts(bio_out, "IDEA\n"); ++#endif ++#ifdef OPENSSL_NO_MD2 ++ BIO_puts(bio_out, "MD2\n"); ++#endif ++#ifdef OPENSSL_NO_MD4 ++ BIO_puts(bio_out, "MD4\n"); ++#endif ++#ifdef OPENSSL_NO_MD5 ++ BIO_puts(bio_out, "MD5\n"); ++#endif ++#ifdef OPENSSL_NO_MDC2 ++ BIO_puts(bio_out, "MDC2\n"); ++#endif ++#ifdef OPENSSL_NO_OCB ++ BIO_puts(bio_out, "OCB\n"); ++#endif ++#ifdef OPENSSL_NO_OCSP ++ BIO_puts(bio_out, "OCSP\n"); ++#endif ++#ifdef OPENSSL_NO_PSK ++ BIO_puts(bio_out, "PSK\n"); ++#endif ++#ifdef OPENSSL_NO_RC2 ++ BIO_puts(bio_out, "RC2\n"); ++#endif ++#ifdef OPENSSL_NO_RC4 ++ BIO_puts(bio_out, "RC4\n"); ++#endif ++#ifdef OPENSSL_NO_RC5 ++ BIO_puts(bio_out, "RC5\n"); ++#endif ++#ifdef OPENSSL_NO_RMD160 ++ BIO_puts(bio_out, "RMD160\n"); ++#endif ++#ifdef OPENSSL_NO_RSA ++ BIO_puts(bio_out, "RSA\n"); ++#endif ++#ifdef OPENSSL_NO_SCRYPT ++ BIO_puts(bio_out, "SCRYPT\n"); ++#endif ++#ifdef OPENSSL_NO_SCTP ++ BIO_puts(bio_out, "SCTP\n"); ++#endif ++#ifdef OPENSSL_NO_SEED ++ BIO_puts(bio_out, "SEED\n"); ++#endif ++#ifdef OPENSSL_NO_SOCK ++ BIO_puts(bio_out, "SOCK\n"); ++#endif ++#ifdef OPENSSL_NO_SRP ++ BIO_puts(bio_out, "SRP\n"); ++#endif ++#ifdef OPENSSL_NO_SRTP ++ BIO_puts(bio_out, "SRTP\n"); ++#endif ++#ifdef OPENSSL_NO_SSL3 ++ BIO_puts(bio_out, "SSL3\n"); ++#endif ++#ifdef OPENSSL_NO_TLS1 ++ BIO_puts(bio_out, "TLS1\n"); ++#endif ++#ifdef OPENSSL_NO_TLS1_1 ++ BIO_puts(bio_out, "TLS1_1\n"); ++#endif ++#ifdef OPENSSL_NO_TLS1_2 ++ BIO_puts(bio_out, "TLS1_2\n"); ++#endif ++#ifdef OPENSSL_NO_WHIRLPOOL ++ BIO_puts(bio_out, "WHIRLPOOL\n"); ++#endif ++#ifndef ZLIB ++ BIO_puts(bio_out, "ZLIB\n"); ++#endif ++} ++ ++static LHASH_OF(FUNCTION) *prog_init(void) ++{ ++ LHASH_OF(FUNCTION) *ret; ++ FUNCTION *f; ++ size_t i; ++ ++ /* Sort alphabetically within category. For nicer help displays. */ ++ for (i = 0, f = functions; f->name != NULL; ++f, ++i) ; ++ qsort(functions, i, sizeof(*functions), SortFnByName); ++ ++ if ((ret = lh_FUNCTION_new(function_hash, function_cmp)) == NULL) ++ return (NULL); ++ ++ for (f = functions; f->name != NULL; f++) ++ (void)lh_FUNCTION_insert(ret, f); ++ return (ret); ++} +diff --git a/CryptoPkg/Library/OpensslLib/openssl/apps/openssl.cnf b/CryptoPkg/Library/OpensslLib/openssl/apps/openssl.cnf +new file mode 100644 +index 0000000..b3e7444 +--- /dev/null ++++ b/CryptoPkg/Library/OpensslLib/openssl/apps/openssl.cnf +@@ -0,0 +1,346 @@ ++# ++# OpenSSL example configuration file. ++# This is mostly being used for generation of certificate requests. ++# ++ ++# This definition stops the following lines choking if HOME isn't ++# defined. ++HOME = . ++RANDFILE = $ENV::HOME/.rnd ++ ++# Extra OBJECT IDENTIFIER info: ++#oid_file = $ENV::HOME/.oid ++oid_section = new_oids ++ ++# To use this configuration file with the "-extfile" option of the ++# "openssl x509" utility, name here the section containing the ++# X.509v3 extensions to use: ++# extensions = ++# (Alternatively, use a configuration file that has only ++# X.509v3 extensions in its main [= default] section.) ++ ++[ new_oids ] ++ ++# We can add new OIDs in here for use by 'ca', 'req' and 'ts'. ++# Add a simple OID like this: ++# testoid1=1.2.3.4 ++# Or use config file substitution like this: ++# testoid2=${testoid1}.5.6 ++ ++# Policies used by the TSA examples. ++tsa_policy1 = 1.2.3.4.1 ++tsa_policy2 = 1.2.3.4.5.6 ++tsa_policy3 = 1.2.3.4.5.7 ++ ++#################################################################### ++[ ca ] ++default_ca = CA_default # The default ca section ++ ++#################################################################### ++[ CA_default ] ++ ++dir = ./demoCA # Where everything is kept ++certs = $dir/certs # Where the issued certs are kept ++crl_dir = $dir/crl # Where the issued crl are kept ++database = $dir/index.txt # database index file. ++#unique_subject = no # Set to 'no' to allow creation of ++ # several certs with same subject. ++new_certs_dir = $dir/newcerts # default place for new certs. ++ ++certificate = $dir/cacert.pem # The CA certificate ++serial = $dir/serial # The current serial number ++crlnumber = $dir/crlnumber # the current crl number ++ # must be commented out to leave a V1 CRL ++crl = $dir/crl.pem # The current CRL ++private_key = $dir/private/cakey.pem# The private key ++RANDFILE = $dir/private/.rand # private random number file ++ ++x509_extensions = usr_cert # The extensions to add to the cert ++ ++# Comment out the following two lines for the "traditional" ++# (and highly broken) format. ++name_opt = ca_default # Subject Name options ++cert_opt = ca_default # Certificate field options ++ ++# Extension copying option: use with caution. ++# copy_extensions = copy ++ ++# Extensions to add to a CRL. Note: Netscape communicator chokes on V2 CRLs ++# so this is commented out by default to leave a V1 CRL. ++# crlnumber must also be commented out to leave a V1 CRL. ++# crl_extensions = crl_ext ++ ++default_days = 365 # how long to certify for ++default_crl_days= 30 # how long before next CRL ++default_md = default # use public key default MD ++preserve = no # keep passed DN ordering ++ ++# A few difference way of specifying how similar the request should look ++# For type CA, the listed attributes must be the same, and the optional ++# and supplied fields are just that :-) ++policy = policy_match ++ ++# For the CA policy ++[ policy_match ] ++countryName = match ++stateOrProvinceName = match ++organizationName = match ++organizationalUnitName = optional ++commonName = supplied ++emailAddress = optional ++ ++# For the 'anything' policy ++# At this point in time, you must list all acceptable 'object' ++# types. ++[ policy_anything ] ++countryName = optional ++stateOrProvinceName = optional ++localityName = optional ++organizationName = optional ++organizationalUnitName = optional ++commonName = supplied ++emailAddress = optional ++ ++#################################################################### ++[ req ] ++default_bits = 2048 ++default_keyfile = privkey.pem ++distinguished_name = req_distinguished_name ++attributes = req_attributes ++x509_extensions = v3_ca # The extensions to add to the self signed cert ++ ++# Passwords for private keys if not present they will be prompted for ++# input_password = secret ++# output_password = secret ++ ++# This sets a mask for permitted string types. There are several options. ++# default: PrintableString, T61String, BMPString. ++# pkix : PrintableString, BMPString (PKIX recommendation before 2004) ++# utf8only: only UTF8Strings (PKIX recommendation after 2004). ++# nombstr : PrintableString, T61String (no BMPStrings or UTF8Strings). ++# MASK:XXXX a literal mask value. ++# WARNING: ancient versions of Netscape crash on BMPStrings or UTF8Strings. ++string_mask = utf8only ++ ++# req_extensions = v3_req # The extensions to add to a certificate request ++ ++[ req_distinguished_name ] ++countryName = Country Name (2 letter code) ++countryName_default = AU ++countryName_min = 2 ++countryName_max = 2 ++ ++stateOrProvinceName = State or Province Name (full name) ++stateOrProvinceName_default = Some-State ++ ++localityName = Locality Name (eg, city) ++ ++0.organizationName = Organization Name (eg, company) ++0.organizationName_default = Internet Widgits Pty Ltd ++ ++# we can do this but it is not needed normally :-) ++#1.organizationName = Second Organization Name (eg, company) ++#1.organizationName_default = World Wide Web Pty Ltd ++ ++organizationalUnitName = Organizational Unit Name (eg, section) ++#organizationalUnitName_default = ++ ++commonName = Common Name (e.g. server FQDN or YOUR name) ++commonName_max = 64 ++ ++emailAddress = Email Address ++emailAddress_max = 64 ++ ++# SET-ex3 = SET extension number 3 ++ ++[ req_attributes ] ++challengePassword = A challenge password ++challengePassword_min = 4 ++challengePassword_max = 20 ++ ++unstructuredName = An optional company name ++ ++[ usr_cert ] ++ ++# These extensions are added when 'ca' signs a request. ++ ++# This goes against PKIX guidelines but some CAs do it and some software ++# requires this to avoid interpreting an end user certificate as a CA. ++ ++basicConstraints=CA:FALSE ++ ++# Here are some examples of the usage of nsCertType. If it is omitted ++# the certificate can be used for anything *except* object signing. ++ ++# This is OK for an SSL server. ++# nsCertType = server ++ ++# For an object signing certificate this would be used. ++# nsCertType = objsign ++ ++# For normal client use this is typical ++# nsCertType = client, email ++ ++# and for everything including object signing: ++# nsCertType = client, email, objsign ++ ++# This is typical in keyUsage for a client certificate. ++# keyUsage = nonRepudiation, digitalSignature, keyEncipherment ++ ++# This will be displayed in Netscape's comment listbox. ++nsComment = "OpenSSL Generated Certificate" ++ ++# PKIX recommendations harmless if included in all certificates. ++subjectKeyIdentifier=hash ++authorityKeyIdentifier=keyid,issuer ++ ++# This stuff is for subjectAltName and issuerAltname. ++# Import the email address. ++# subjectAltName=email:copy ++# An alternative to produce certificates that aren't ++# deprecated according to PKIX. ++# subjectAltName=email:move ++ ++# Copy subject details ++# issuerAltName=issuer:copy ++ ++#nsCaRevocationUrl = http://www.domain.dom/ca-crl.pem ++#nsBaseUrl ++#nsRevocationUrl ++#nsRenewalUrl ++#nsCaPolicyUrl ++#nsSslServerName ++ ++# This is required for TSA certificates. ++# extendedKeyUsage = critical,timeStamping ++ ++[ v3_req ] ++ ++# Extensions to add to a certificate request ++ ++basicConstraints = CA:FALSE ++keyUsage = nonRepudiation, digitalSignature, keyEncipherment ++ ++[ v3_ca ] ++ ++ ++# Extensions for a typical CA ++ ++ ++# PKIX recommendation. ++ ++subjectKeyIdentifier=hash ++ ++authorityKeyIdentifier=keyid:always,issuer ++ ++basicConstraints = critical,CA:true ++ ++# Key usage: this is typical for a CA certificate. However since it will ++# prevent it being used as an test self-signed certificate it is best ++# left out by default. ++# keyUsage = cRLSign, keyCertSign ++ ++# Some might want this also ++# nsCertType = sslCA, emailCA ++ ++# Include email address in subject alt name: another PKIX recommendation ++# subjectAltName=email:copy ++# Copy issuer details ++# issuerAltName=issuer:copy ++ ++# DER hex encoding of an extension: beware experts only! ++# obj=DER:02:03 ++# Where 'obj' is a standard or added object ++# You can even override a supported extension: ++# basicConstraints= critical, DER:30:03:01:01:FF ++ ++[ crl_ext ] ++ ++# CRL extensions. ++# Only issuerAltName and authorityKeyIdentifier make any sense in a CRL. ++ ++# issuerAltName=issuer:copy ++authorityKeyIdentifier=keyid:always ++ ++[ proxy_cert_ext ] ++# These extensions should be added when creating a proxy certificate ++ ++# This goes against PKIX guidelines but some CAs do it and some software ++# requires this to avoid interpreting an end user certificate as a CA. ++ ++basicConstraints=CA:FALSE ++ ++# Here are some examples of the usage of nsCertType. If it is omitted ++# the certificate can be used for anything *except* object signing. ++ ++# This is OK for an SSL server. ++# nsCertType = server ++ ++# For an object signing certificate this would be used. ++# nsCertType = objsign ++ ++# For normal client use this is typical ++# nsCertType = client, email ++ ++# and for everything including object signing: ++# nsCertType = client, email, objsign ++ ++# This is typical in keyUsage for a client certificate. ++# keyUsage = nonRepudiation, digitalSignature, keyEncipherment ++ ++# This will be displayed in Netscape's comment listbox. ++nsComment = "OpenSSL Generated Certificate" ++ ++# PKIX recommendations harmless if included in all certificates. ++subjectKeyIdentifier=hash ++authorityKeyIdentifier=keyid,issuer ++ ++# This stuff is for subjectAltName and issuerAltname. ++# Import the email address. ++# subjectAltName=email:copy ++# An alternative to produce certificates that aren't ++# deprecated according to PKIX. ++# subjectAltName=email:move ++ ++# Copy subject details ++# issuerAltName=issuer:copy ++ ++#nsCaRevocationUrl = http://www.domain.dom/ca-crl.pem ++#nsBaseUrl ++#nsRevocationUrl ++#nsRenewalUrl ++#nsCaPolicyUrl ++#nsSslServerName ++ ++# This really needs to be in place for it to be a proxy certificate. ++proxyCertInfo=critical,language:id-ppl-anyLanguage,pathlen:3,policy:foo ++ ++#################################################################### ++[ tsa ] ++ ++default_tsa = tsa_config1 # the default TSA section ++ ++[ tsa_config1 ] ++ ++# These are used by the TSA reply generation only. ++dir = ./demoCA # TSA root directory ++serial = $dir/tsaserial # The current serial number (mandatory) ++crypto_device = builtin # OpenSSL engine to use for signing ++signer_cert = $dir/tsacert.pem # The TSA signing certificate ++ # (optional) ++certs = $dir/cacert.pem # Certificate chain to include in reply ++ # (optional) ++signer_key = $dir/private/tsakey.pem # The TSA private key (optional) ++signer_digest = sha256 # Signing digest to use. (Optional) ++default_policy = tsa_policy1 # Policy if request did not specify it ++ # (optional) ++other_policies = tsa_policy2, tsa_policy3 # acceptable policies (optional) ++digests = sha1, sha256, sha384, sha512 # Acceptable message digests (mandatory) ++accuracy = secs:1, millisecs:500, microsecs:100 # (optional) ++clock_precision_digits = 0 # number of digits after dot. (optional) ++ordering = yes # Is ordering defined for timestamps? ++ # (optional, default: no) ++tsa_name = yes # Must the TSA name be included in the reply? ++ # (optional, default: no) ++ess_cert_id_chain = no # Must the ESS cert id chain be included? ++ # (optional, default: no) +diff --git a/CryptoPkg/Library/OpensslLib/openssl/apps/opt.c b/CryptoPkg/Library/OpensslLib/openssl/apps/opt.c +new file mode 100644 +index 0000000..f72ac64 +--- /dev/null ++++ b/CryptoPkg/Library/OpensslLib/openssl/apps/opt.c +@@ -0,0 +1,977 @@ ++/* ++ * Copyright 2015-2016 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 ++ * in the file LICENSE in the source distribution or at ++ * https://www.openssl.org/source/license.html ++ */ ++ ++/* #define COMPILE_STANDALONE_TEST_DRIVER */ ++#include "apps.h" ++#include ++#if !defined(OPENSSL_SYS_MSDOS) ++# include OPENSSL_UNISTD ++#endif ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#define MAX_OPT_HELP_WIDTH 30 ++const char OPT_HELP_STR[] = "--"; ++const char OPT_MORE_STR[] = "---"; ++ ++/* Our state */ ++static char **argv; ++static int argc; ++static int opt_index; ++static char *arg; ++static char *flag; ++static char *dunno; ++static const OPTIONS *unknown; ++static const OPTIONS *opts; ++static char prog[40]; ++ ++/* ++ * Return the simple name of the program; removing various platform gunk. ++ */ ++#if defined(OPENSSL_SYS_WIN32) ++char *opt_progname(const char *argv0) ++{ ++ size_t i, n; ++ const char *p; ++ char *q; ++ ++ /* find the last '/', '\' or ':' */ ++ for (p = argv0 + strlen(argv0); --p > argv0;) ++ if (*p == '/' || *p == '\\' || *p == ':') { ++ p++; ++ break; ++ } ++ ++ /* Strip off trailing nonsense. */ ++ n = strlen(p); ++ if (n > 4 && ++ (strcmp(&p[n - 4], ".exe") == 0 || strcmp(&p[n - 4], ".EXE") == 0)) ++ n -= 4; ++ ++ /* Copy over the name, in lowercase. */ ++ if (n > sizeof prog - 1) ++ n = sizeof prog - 1; ++ for (q = prog, i = 0; i < n; i++, p++) ++ *q++ = isupper(*p) ? tolower(*p) : *p; ++ *q = '\0'; ++ return prog; ++} ++ ++#elif defined(OPENSSL_SYS_VMS) ++ ++char *opt_progname(const char *argv0) ++{ ++ const char *p, *q; ++ ++ /* Find last special character sys:[foo.bar]openssl */ ++ for (p = argv0 + strlen(argv0); --p > argv0;) ++ if (*p == ':' || *p == ']' || *p == '>') { ++ p++; ++ break; ++ } ++ ++ q = strrchr(p, '.'); ++ strncpy(prog, p, sizeof prog - 1); ++ prog[sizeof prog - 1] = '\0'; ++ if (q != NULL && q - p < sizeof prog) ++ prog[q - p] = '\0'; ++ return prog; ++} ++ ++#else ++ ++char *opt_progname(const char *argv0) ++{ ++ const char *p; ++ ++ /* Could use strchr, but this is like the ones above. */ ++ for (p = argv0 + strlen(argv0); --p > argv0;) ++ if (*p == '/') { ++ p++; ++ break; ++ } ++ strncpy(prog, p, sizeof prog - 1); ++ prog[sizeof prog - 1] = '\0'; ++ return prog; ++} ++#endif ++ ++char *opt_getprog(void) ++{ ++ return prog; ++} ++ ++/* Set up the arg parsing. */ ++char *opt_init(int ac, char **av, const OPTIONS *o) ++{ ++ /* Store state. */ ++ argc = ac; ++ argv = av; ++ opt_index = 1; ++ opts = o; ++ opt_progname(av[0]); ++ unknown = NULL; ++ ++ for (; o->name; ++o) { ++#ifndef NDEBUG ++ const OPTIONS *next; ++ int duplicated, i; ++#endif ++ ++ if (o->name == OPT_HELP_STR || o->name == OPT_MORE_STR) ++ continue; ++#ifndef NDEBUG ++ i = o->valtype; ++ ++ /* Make sure options are legit. */ ++ assert(o->name[0] != '-'); ++ assert(o->retval > 0); ++ switch (i) { ++ case 0: case '-': case '/': case '<': case '>': case 'E': case 'F': ++ case 'M': case 'U': case 'f': case 'l': case 'n': case 'p': case 's': ++ case 'u': case 'c': ++ break; ++ default: ++ assert(0); ++ } ++ ++ /* Make sure there are no duplicates. */ ++ for (next = o + 1; next->name; ++next) { ++ /* ++ * Some compilers inline strcmp and the assert string is too long. ++ */ ++ duplicated = strcmp(o->name, next->name) == 0; ++ assert(!duplicated); ++ } ++#endif ++ if (o->name[0] == '\0') { ++ assert(unknown == NULL); ++ unknown = o; ++ assert(unknown->valtype == 0 || unknown->valtype == '-'); ++ } ++ } ++ return prog; ++} ++ ++static OPT_PAIR formats[] = { ++ {"PEM/DER", OPT_FMT_PEMDER}, ++ {"pkcs12", OPT_FMT_PKCS12}, ++ {"smime", OPT_FMT_SMIME}, ++ {"engine", OPT_FMT_ENGINE}, ++ {"msblob", OPT_FMT_MSBLOB}, ++ {"netscape", OPT_FMT_NETSCAPE}, ++ {"nss", OPT_FMT_NSS}, ++ {"text", OPT_FMT_TEXT}, ++ {"http", OPT_FMT_HTTP}, ++ {"pvk", OPT_FMT_PVK}, ++ {NULL} ++}; ++ ++/* Print an error message about a failed format parse. */ ++int opt_format_error(const char *s, unsigned long flags) ++{ ++ OPT_PAIR *ap; ++ ++ if (flags == OPT_FMT_PEMDER) ++ BIO_printf(bio_err, "%s: Bad format \"%s\"; must be pem or der\n", ++ prog, s); ++ else { ++ BIO_printf(bio_err, "%s: Bad format \"%s\"; must be one of:\n", ++ prog, s); ++ for (ap = formats; ap->name; ap++) ++ if (flags & ap->retval) ++ BIO_printf(bio_err, " %s\n", ap->name); ++ } ++ return 0; ++} ++ ++/* Parse a format string, put it into *result; return 0 on failure, else 1. */ ++int opt_format(const char *s, unsigned long flags, int *result) ++{ ++ switch (*s) { ++ default: ++ return 0; ++ case 'D': ++ case 'd': ++ if ((flags & OPT_FMT_PEMDER) == 0) ++ return opt_format_error(s, flags); ++ *result = FORMAT_ASN1; ++ break; ++ case 'T': ++ case 't': ++ if ((flags & OPT_FMT_TEXT) == 0) ++ return opt_format_error(s, flags); ++ *result = FORMAT_TEXT; ++ break; ++ case 'N': ++ case 'n': ++ if ((flags & OPT_FMT_NSS) == 0) ++ return opt_format_error(s, flags); ++ if (strcmp(s, "NSS") != 0 && strcmp(s, "nss") != 0) ++ return opt_format_error(s, flags); ++ *result = FORMAT_NSS; ++ break; ++ case 'S': ++ case 's': ++ if ((flags & OPT_FMT_SMIME) == 0) ++ return opt_format_error(s, flags); ++ *result = FORMAT_SMIME; ++ break; ++ case 'M': ++ case 'm': ++ if ((flags & OPT_FMT_MSBLOB) == 0) ++ return opt_format_error(s, flags); ++ *result = FORMAT_MSBLOB; ++ break; ++ case 'E': ++ case 'e': ++ if ((flags & OPT_FMT_ENGINE) == 0) ++ return opt_format_error(s, flags); ++ *result = FORMAT_ENGINE; ++ break; ++ case 'H': ++ case 'h': ++ if ((flags & OPT_FMT_HTTP) == 0) ++ return opt_format_error(s, flags); ++ *result = FORMAT_HTTP; ++ break; ++ case '1': ++ if ((flags & OPT_FMT_PKCS12) == 0) ++ return opt_format_error(s, flags); ++ *result = FORMAT_PKCS12; ++ break; ++ case 'P': ++ case 'p': ++ if (s[1] == '\0' || strcmp(s, "PEM") == 0 || strcmp(s, "pem") == 0) { ++ if ((flags & OPT_FMT_PEMDER) == 0) ++ return opt_format_error(s, flags); ++ *result = FORMAT_PEM; ++ } else if (strcmp(s, "PVK") == 0 || strcmp(s, "pvk") == 0) { ++ if ((flags & OPT_FMT_PVK) == 0) ++ return opt_format_error(s, flags); ++ *result = FORMAT_PVK; ++ } else if (strcmp(s, "P12") == 0 || strcmp(s, "p12") == 0 ++ || strcmp(s, "PKCS12") == 0 || strcmp(s, "pkcs12") == 0) { ++ if ((flags & OPT_FMT_PKCS12) == 0) ++ return opt_format_error(s, flags); ++ *result = FORMAT_PKCS12; ++ } else ++ return 0; ++ break; ++ } ++ return 1; ++} ++ ++/* Parse a cipher name, put it in *EVP_CIPHER; return 0 on failure, else 1. */ ++int opt_cipher(const char *name, const EVP_CIPHER **cipherp) ++{ ++ *cipherp = EVP_get_cipherbyname(name); ++ if (*cipherp) ++ return 1; ++ BIO_printf(bio_err, "%s: Unknown cipher %s\n", prog, name); ++ return 0; ++} ++ ++/* ++ * Parse message digest name, put it in *EVP_MD; return 0 on failure, else 1. ++ */ ++int opt_md(const char *name, const EVP_MD **mdp) ++{ ++ *mdp = EVP_get_digestbyname(name); ++ if (*mdp) ++ return 1; ++ BIO_printf(bio_err, "%s: Unknown digest %s\n", prog, name); ++ return 0; ++} ++ ++/* Look through a list of name/value pairs. */ ++int opt_pair(const char *name, const OPT_PAIR* pairs, int *result) ++{ ++ const OPT_PAIR *pp; ++ ++ for (pp = pairs; pp->name; pp++) ++ if (strcmp(pp->name, name) == 0) { ++ *result = pp->retval; ++ return 1; ++ } ++ BIO_printf(bio_err, "%s: Value must be one of:\n", prog); ++ for (pp = pairs; pp->name; pp++) ++ BIO_printf(bio_err, "\t%s\n", pp->name); ++ return 0; ++} ++ ++/* Parse an int, put it into *result; return 0 on failure, else 1. */ ++int opt_int(const char *value, int *result) ++{ ++ long l; ++ ++ if (!opt_long(value, &l)) ++ return 0; ++ *result = (int)l; ++ if (*result != l) { ++ BIO_printf(bio_err, "%s: Value \"%s\" outside integer range\n", ++ prog, value); ++ return 0; ++ } ++ return 1; ++} ++ ++/* Parse a long, put it into *result; return 0 on failure, else 1. */ ++int opt_long(const char *value, long *result) ++{ ++ int oerrno = errno; ++ long l; ++ char *endp; ++ ++ errno = 0; ++ l = strtol(value, &endp, 0); ++ if (*endp ++ || endp == value ++ || ((l == LONG_MAX || l == LONG_MIN) && errno == ERANGE) ++ || (l == 0 && errno != 0)) { ++ BIO_printf(bio_err, "%s: Can't parse \"%s\" as a number\n", ++ prog, value); ++ errno = oerrno; ++ return 0; ++ } ++ *result = l; ++ errno = oerrno; ++ return 1; ++} ++ ++#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L && \ ++ defined(INTMAX_MAX) && defined(UINTMAX_MAX) ++ ++/* Parse an intmax_t, put it into *result; return 0 on failure, else 1. */ ++int opt_imax(const char *value, intmax_t *result) ++{ ++ int oerrno = errno; ++ intmax_t m; ++ char *endp; ++ ++ errno = 0; ++ m = strtoimax(value, &endp, 0); ++ if (*endp ++ || endp == value ++ || ((m == INTMAX_MAX || m == INTMAX_MIN) && errno == ERANGE) ++ || (m == 0 && errno != 0)) { ++ BIO_printf(bio_err, "%s: Can't parse \"%s\" as a number\n", ++ prog, value); ++ errno = oerrno; ++ return 0; ++ } ++ *result = m; ++ errno = oerrno; ++ return 1; ++} ++ ++/* Parse a uintmax_t, put it into *result; return 0 on failure, else 1. */ ++int opt_umax(const char *value, uintmax_t *result) ++{ ++ int oerrno = errno; ++ uintmax_t m; ++ char *endp; ++ ++ errno = 0; ++ m = strtoumax(value, &endp, 0); ++ if (*endp ++ || endp == value ++ || (m == UINTMAX_MAX && errno == ERANGE) ++ || (m == 0 && errno != 0)) { ++ BIO_printf(bio_err, "%s: Can't parse \"%s\" as a number\n", ++ prog, value); ++ errno = oerrno; ++ return 0; ++ } ++ *result = m; ++ errno = oerrno; ++ return 1; ++} ++#endif ++ ++/* ++ * Parse an unsigned long, put it into *result; return 0 on failure, else 1. ++ */ ++int opt_ulong(const char *value, unsigned long *result) ++{ ++ int oerrno = errno; ++ char *endptr; ++ unsigned long l; ++ ++ errno = 0; ++ l = strtoul(value, &endptr, 0); ++ if (*endptr ++ || endptr == value ++ || ((l == ULONG_MAX) && errno == ERANGE) ++ || (l == 0 && errno != 0)) { ++ BIO_printf(bio_err, "%s: Can't parse \"%s\" as an unsigned number\n", ++ prog, value); ++ errno = oerrno; ++ return 0; ++ } ++ *result = l; ++ errno = oerrno; ++ return 1; ++} ++ ++/* ++ * We pass opt as an int but cast it to "enum range" so that all the ++ * items in the OPT_V_ENUM enumeration are caught; this makes -Wswitch ++ * in gcc do the right thing. ++ */ ++enum range { OPT_V_ENUM }; ++ ++int opt_verify(int opt, X509_VERIFY_PARAM *vpm) ++{ ++ int i; ++ ossl_intmax_t t = 0; ++ ASN1_OBJECT *otmp; ++ X509_PURPOSE *xptmp; ++ const X509_VERIFY_PARAM *vtmp; ++ ++ assert(vpm != NULL); ++ assert(opt > OPT_V__FIRST); ++ assert(opt < OPT_V__LAST); ++ ++ switch ((enum range)opt) { ++ case OPT_V__FIRST: ++ case OPT_V__LAST: ++ return 0; ++ case OPT_V_POLICY: ++ otmp = OBJ_txt2obj(opt_arg(), 0); ++ if (otmp == NULL) { ++ BIO_printf(bio_err, "%s: Invalid Policy %s\n", prog, opt_arg()); ++ return 0; ++ } ++ X509_VERIFY_PARAM_add0_policy(vpm, otmp); ++ break; ++ case OPT_V_PURPOSE: ++ /* purpose name -> purpose index */ ++ i = X509_PURPOSE_get_by_sname(opt_arg()); ++ if (i < 0) { ++ BIO_printf(bio_err, "%s: Invalid purpose %s\n", prog, opt_arg()); ++ return 0; ++ } ++ ++ /* purpose index -> purpose object */ ++ xptmp = X509_PURPOSE_get0(i); ++ ++ /* purpose object -> purpose value */ ++ i = X509_PURPOSE_get_id(xptmp); ++ ++ if (!X509_VERIFY_PARAM_set_purpose(vpm, i)) { ++ BIO_printf(bio_err, ++ "%s: Internal error setting purpose %s\n", ++ prog, opt_arg()); ++ return 0; ++ } ++ break; ++ case OPT_V_VERIFY_NAME: ++ vtmp = X509_VERIFY_PARAM_lookup(opt_arg()); ++ if (vtmp == NULL) { ++ BIO_printf(bio_err, "%s: Invalid verify name %s\n", ++ prog, opt_arg()); ++ return 0; ++ } ++ X509_VERIFY_PARAM_set1(vpm, vtmp); ++ break; ++ case OPT_V_VERIFY_DEPTH: ++ i = atoi(opt_arg()); ++ if (i >= 0) ++ X509_VERIFY_PARAM_set_depth(vpm, i); ++ break; ++ case OPT_V_VERIFY_AUTH_LEVEL: ++ i = atoi(opt_arg()); ++ if (i >= 0) ++ X509_VERIFY_PARAM_set_auth_level(vpm, i); ++ break; ++ case OPT_V_ATTIME: ++ if (!opt_imax(opt_arg(), &t)) ++ return 0; ++ if (t != (time_t)t) { ++ BIO_printf(bio_err, "%s: epoch time out of range %s\n", ++ prog, opt_arg()); ++ return 0; ++ } ++ X509_VERIFY_PARAM_set_time(vpm, (time_t)t); ++ break; ++ case OPT_V_VERIFY_HOSTNAME: ++ if (!X509_VERIFY_PARAM_set1_host(vpm, opt_arg(), 0)) ++ return 0; ++ break; ++ case OPT_V_VERIFY_EMAIL: ++ if (!X509_VERIFY_PARAM_set1_email(vpm, opt_arg(), 0)) ++ return 0; ++ break; ++ case OPT_V_VERIFY_IP: ++ if (!X509_VERIFY_PARAM_set1_ip_asc(vpm, opt_arg())) ++ return 0; ++ break; ++ case OPT_V_IGNORE_CRITICAL: ++ X509_VERIFY_PARAM_set_flags(vpm, X509_V_FLAG_IGNORE_CRITICAL); ++ break; ++ case OPT_V_ISSUER_CHECKS: ++ /* NOP, deprecated */ ++ break; ++ case OPT_V_CRL_CHECK: ++ X509_VERIFY_PARAM_set_flags(vpm, X509_V_FLAG_CRL_CHECK); ++ break; ++ case OPT_V_CRL_CHECK_ALL: ++ X509_VERIFY_PARAM_set_flags(vpm, ++ X509_V_FLAG_CRL_CHECK | ++ X509_V_FLAG_CRL_CHECK_ALL); ++ break; ++ case OPT_V_POLICY_CHECK: ++ X509_VERIFY_PARAM_set_flags(vpm, X509_V_FLAG_POLICY_CHECK); ++ break; ++ case OPT_V_EXPLICIT_POLICY: ++ X509_VERIFY_PARAM_set_flags(vpm, X509_V_FLAG_EXPLICIT_POLICY); ++ break; ++ case OPT_V_INHIBIT_ANY: ++ X509_VERIFY_PARAM_set_flags(vpm, X509_V_FLAG_INHIBIT_ANY); ++ break; ++ case OPT_V_INHIBIT_MAP: ++ X509_VERIFY_PARAM_set_flags(vpm, X509_V_FLAG_INHIBIT_MAP); ++ break; ++ case OPT_V_X509_STRICT: ++ X509_VERIFY_PARAM_set_flags(vpm, X509_V_FLAG_X509_STRICT); ++ break; ++ case OPT_V_EXTENDED_CRL: ++ X509_VERIFY_PARAM_set_flags(vpm, X509_V_FLAG_EXTENDED_CRL_SUPPORT); ++ break; ++ case OPT_V_USE_DELTAS: ++ X509_VERIFY_PARAM_set_flags(vpm, X509_V_FLAG_USE_DELTAS); ++ break; ++ case OPT_V_POLICY_PRINT: ++ X509_VERIFY_PARAM_set_flags(vpm, X509_V_FLAG_NOTIFY_POLICY); ++ break; ++ case OPT_V_CHECK_SS_SIG: ++ X509_VERIFY_PARAM_set_flags(vpm, X509_V_FLAG_CHECK_SS_SIGNATURE); ++ break; ++ case OPT_V_TRUSTED_FIRST: ++ X509_VERIFY_PARAM_set_flags(vpm, X509_V_FLAG_TRUSTED_FIRST); ++ break; ++ case OPT_V_SUITEB_128_ONLY: ++ X509_VERIFY_PARAM_set_flags(vpm, X509_V_FLAG_SUITEB_128_LOS_ONLY); ++ break; ++ case OPT_V_SUITEB_128: ++ X509_VERIFY_PARAM_set_flags(vpm, X509_V_FLAG_SUITEB_128_LOS); ++ break; ++ case OPT_V_SUITEB_192: ++ X509_VERIFY_PARAM_set_flags(vpm, X509_V_FLAG_SUITEB_192_LOS); ++ break; ++ case OPT_V_PARTIAL_CHAIN: ++ X509_VERIFY_PARAM_set_flags(vpm, X509_V_FLAG_PARTIAL_CHAIN); ++ break; ++ case OPT_V_NO_ALT_CHAINS: ++ X509_VERIFY_PARAM_set_flags(vpm, X509_V_FLAG_NO_ALT_CHAINS); ++ break; ++ case OPT_V_NO_CHECK_TIME: ++ X509_VERIFY_PARAM_set_flags(vpm, X509_V_FLAG_NO_CHECK_TIME); ++ break; ++ case OPT_V_ALLOW_PROXY_CERTS: ++ X509_VERIFY_PARAM_set_flags(vpm, X509_V_FLAG_ALLOW_PROXY_CERTS); ++ break; ++ } ++ return 1; ++ ++} ++ ++/* ++ * Parse the next flag (and value if specified), return 0 if done, -1 on ++ * error, otherwise the flag's retval. ++ */ ++int opt_next(void) ++{ ++ char *p; ++ const OPTIONS *o; ++ int ival; ++ long lval; ++ unsigned long ulval; ++ ossl_intmax_t imval; ++ ossl_uintmax_t umval; ++ ++ /* Look at current arg; at end of the list? */ ++ arg = NULL; ++ p = argv[opt_index]; ++ if (p == NULL) ++ return 0; ++ ++ /* If word doesn't start with a -, we're done. */ ++ if (*p != '-') ++ return 0; ++ ++ /* Hit "--" ? We're done. */ ++ opt_index++; ++ if (strcmp(p, "--") == 0) ++ return 0; ++ ++ /* Allow -nnn and --nnn */ ++ if (*++p == '-') ++ p++; ++ flag = p - 1; ++ ++ /* If we have --flag=foo, snip it off */ ++ if ((arg = strchr(p, '=')) != NULL) ++ *arg++ = '\0'; ++ for (o = opts; o->name; ++o) { ++ /* If not this option, move on to the next one. */ ++ if (strcmp(p, o->name) != 0) ++ continue; ++ ++ /* If it doesn't take a value, make sure none was given. */ ++ if (o->valtype == 0 || o->valtype == '-') { ++ if (arg) { ++ BIO_printf(bio_err, ++ "%s: Option -%s does not take a value\n", prog, p); ++ return -1; ++ } ++ return o->retval; ++ } ++ ++ /* Want a value; get the next param if =foo not used. */ ++ if (arg == NULL) { ++ if (argv[opt_index] == NULL) { ++ BIO_printf(bio_err, ++ "%s: Option -%s needs a value\n", prog, o->name); ++ return -1; ++ } ++ arg = argv[opt_index++]; ++ } ++ ++ /* Syntax-check value. */ ++ switch (o->valtype) { ++ default: ++ case 's': ++ /* Just a string. */ ++ break; ++ case '/': ++ if (app_isdir(arg) >= 0) ++ break; ++ BIO_printf(bio_err, "%s: Not a directory: %s\n", prog, arg); ++ return -1; ++ case '<': ++ /* Input file. */ ++ if (strcmp(arg, "-") == 0 || app_access(arg, R_OK) >= 0) ++ break; ++ BIO_printf(bio_err, ++ "%s: Cannot open input file %s, %s\n", ++ prog, arg, strerror(errno)); ++ return -1; ++ case '>': ++ /* Output file. */ ++ if (strcmp(arg, "-") == 0 || app_access(arg, W_OK) >= 0 || errno == ENOENT) ++ break; ++ BIO_printf(bio_err, ++ "%s: Cannot open output file %s, %s\n", ++ prog, arg, strerror(errno)); ++ return -1; ++ case 'p': ++ case 'n': ++ if (!opt_int(arg, &ival) ++ || (o->valtype == 'p' && ival <= 0)) { ++ BIO_printf(bio_err, ++ "%s: Non-positive number \"%s\" for -%s\n", ++ prog, arg, o->name); ++ return -1; ++ } ++ break; ++ case 'M': ++ if (!opt_imax(arg, &imval)) { ++ BIO_printf(bio_err, ++ "%s: Invalid number \"%s\" for -%s\n", ++ prog, arg, o->name); ++ return -1; ++ } ++ break; ++ case 'U': ++ if (!opt_umax(arg, &umval)) { ++ BIO_printf(bio_err, ++ "%s: Invalid number \"%s\" for -%s\n", ++ prog, arg, o->name); ++ return -1; ++ } ++ break; ++ case 'l': ++ if (!opt_long(arg, &lval)) { ++ BIO_printf(bio_err, ++ "%s: Invalid number \"%s\" for -%s\n", ++ prog, arg, o->name); ++ return -1; ++ } ++ break; ++ case 'u': ++ if (!opt_ulong(arg, &ulval)) { ++ BIO_printf(bio_err, ++ "%s: Invalid number \"%s\" for -%s\n", ++ prog, arg, o->name); ++ return -1; ++ } ++ break; ++ case 'c': ++ case 'E': ++ case 'F': ++ case 'f': ++ if (opt_format(arg, ++ o->valtype == 'c' ? OPT_FMT_PDS : ++ o->valtype == 'E' ? OPT_FMT_PDE : ++ o->valtype == 'F' ? OPT_FMT_PEMDER ++ : OPT_FMT_ANY, &ival)) ++ break; ++ BIO_printf(bio_err, ++ "%s: Invalid format \"%s\" for -%s\n", ++ prog, arg, o->name); ++ return -1; ++ } ++ ++ /* Return the flag value. */ ++ return o->retval; ++ } ++ if (unknown != NULL) { ++ dunno = p; ++ return unknown->retval; ++ } ++ BIO_printf(bio_err, "%s: Option unknown option -%s\n", prog, p); ++ return -1; ++} ++ ++/* Return the most recent flag parameter. */ ++char *opt_arg(void) ++{ ++ return arg; ++} ++ ++/* Return the most recent flag. */ ++char *opt_flag(void) ++{ ++ return flag; ++} ++ ++/* Return the unknown option. */ ++char *opt_unknown(void) ++{ ++ return dunno; ++} ++ ++/* Return the rest of the arguments after parsing flags. */ ++char **opt_rest(void) ++{ ++ return &argv[opt_index]; ++} ++ ++/* How many items in remaining args? */ ++int opt_num_rest(void) ++{ ++ int i = 0; ++ char **pp; ++ ++ for (pp = opt_rest(); *pp; pp++, i++) ++ continue; ++ return i; ++} ++ ++/* Return a string describing the parameter type. */ ++static const char *valtype2param(const OPTIONS *o) ++{ ++ switch (o->valtype) { ++ case 0: ++ case '-': ++ return ""; ++ case 's': ++ return "val"; ++ case '/': ++ return "dir"; ++ case '<': ++ return "infile"; ++ case '>': ++ return "outfile"; ++ case 'p': ++ return "+int"; ++ case 'n': ++ return "int"; ++ case 'l': ++ return "long"; ++ case 'u': ++ return "ulong"; ++ case 'E': ++ return "PEM|DER|ENGINE"; ++ case 'F': ++ return "PEM|DER"; ++ case 'f': ++ return "format"; ++ case 'M': ++ return "intmax"; ++ case 'U': ++ return "uintmax"; ++ } ++ return "parm"; ++} ++ ++void opt_help(const OPTIONS *list) ++{ ++ const OPTIONS *o; ++ int i; ++ int standard_prolog; ++ int width = 5; ++ char start[80 + 1]; ++ char *p; ++ const char *help; ++ ++ /* Starts with its own help message? */ ++ standard_prolog = list[0].name != OPT_HELP_STR; ++ ++ /* Find the widest help. */ ++ for (o = list; o->name; o++) { ++ if (o->name == OPT_MORE_STR) ++ continue; ++ i = 2 + (int)strlen(o->name); ++ if (o->valtype != '-') ++ i += 1 + strlen(valtype2param(o)); ++ if (i < MAX_OPT_HELP_WIDTH && i > width) ++ width = i; ++ assert(i < (int)sizeof start); ++ } ++ ++ if (standard_prolog) ++ BIO_printf(bio_err, "Usage: %s [options]\nValid options are:\n", ++ prog); ++ ++ /* Now let's print. */ ++ for (o = list; o->name; o++) { ++ help = o->helpstr ? o->helpstr : "(No additional info)"; ++ if (o->name == OPT_HELP_STR) { ++ BIO_printf(bio_err, help, prog); ++ continue; ++ } ++ ++ /* Pad out prefix */ ++ memset(start, ' ', sizeof(start) - 1); ++ start[sizeof start - 1] = '\0'; ++ ++ if (o->name == OPT_MORE_STR) { ++ /* Continuation of previous line; pad and print. */ ++ start[width] = '\0'; ++ BIO_printf(bio_err, "%s %s\n", start, help); ++ continue; ++ } ++ ++ /* Build up the "-flag [param]" part. */ ++ p = start; ++ *p++ = ' '; ++ *p++ = '-'; ++ if (o->name[0]) ++ p += strlen(strcpy(p, o->name)); ++ else ++ *p++ = '*'; ++ if (o->valtype != '-') { ++ *p++ = ' '; ++ p += strlen(strcpy(p, valtype2param(o))); ++ } ++ *p = ' '; ++ if ((int)(p - start) >= MAX_OPT_HELP_WIDTH) { ++ *p = '\0'; ++ BIO_printf(bio_err, "%s\n", start); ++ memset(start, ' ', sizeof(start)); ++ } ++ start[width] = '\0'; ++ BIO_printf(bio_err, "%s %s\n", start, help); ++ } ++} ++ ++#ifdef COMPILE_STANDALONE_TEST_DRIVER ++# include ++ ++typedef enum OPTION_choice { ++ OPT_ERR = -1, OPT_EOF = 0, OPT_HELP, ++ OPT_IN, OPT_INFORM, OPT_OUT, OPT_COUNT, OPT_U, OPT_FLAG, ++ OPT_STR, OPT_NOTUSED ++} OPTION_CHOICE; ++ ++static OPTIONS options[] = { ++ {OPT_HELP_STR, 1, '-', "Usage: %s flags\n"}, ++ {OPT_HELP_STR, 1, '-', "Valid options are:\n"}, ++ {"help", OPT_HELP, '-', "Display this summary"}, ++ {"in", OPT_IN, '<', "input file"}, ++ {OPT_MORE_STR, 1, '-', "more detail about input"}, ++ {"inform", OPT_INFORM, 'f', "input file format; defaults to pem"}, ++ {"out", OPT_OUT, '>', "output file"}, ++ {"count", OPT_COUNT, 'p', "a counter greater than zero"}, ++ {"u", OPT_U, 'u', "an unsigned number"}, ++ {"flag", OPT_FLAG, 0, "just some flag"}, ++ {"str", OPT_STR, 's', "the magic word"}, ++ {"areallyverylongoption", OPT_HELP, '-', "long way for help"}, ++ {NULL} ++}; ++ ++BIO *bio_err; ++ ++int app_isdir(const char *name) ++{ ++ struct stat sb; ++ ++ return name != NULL && stat(name, &sb) >= 0 && S_ISDIR(sb.st_mode); ++} ++ ++int main(int ac, char **av) ++{ ++ OPTION_CHOICE o; ++ char **rest; ++ char *prog; ++ ++ bio_err = BIO_new_fp(stderr, BIO_NOCLOSE | BIO_FP_TEXT); ++ ++ prog = opt_init(ac, av, options); ++ while ((o = opt_next()) != OPT_EOF) { ++ switch (c) { ++ case OPT_NOTUSED: ++ case OPT_EOF: ++ case OPT_ERR: ++ printf("%s: Usage error; try -help.\n", prog); ++ return 1; ++ case OPT_HELP: ++ opt_help(options); ++ return 0; ++ case OPT_IN: ++ printf("in %s\n", opt_arg()); ++ break; ++ case OPT_INFORM: ++ printf("inform %s\n", opt_arg()); ++ break; ++ case OPT_OUT: ++ printf("out %s\n", opt_arg()); ++ break; ++ case OPT_COUNT: ++ printf("count %s\n", opt_arg()); ++ break; ++ case OPT_U: ++ printf("u %s\n", opt_arg()); ++ break; ++ case OPT_FLAG: ++ printf("flag\n"); ++ break; ++ case OPT_STR: ++ printf("str %s\n", opt_arg()); ++ break; ++ } ++ } ++ argc = opt_num_rest(); ++ argv = opt_rest(); ++ ++ printf("args = %d\n", argc); ++ if (argc) ++ while (*argv) ++ printf(" %s\n", *argv++); ++ return 0; ++} ++#endif +diff --git a/CryptoPkg/Library/OpensslLib/openssl/apps/passwd.c b/CryptoPkg/Library/OpensslLib/openssl/apps/passwd.c +new file mode 100644 +index 0000000..a45245c +--- /dev/null ++++ b/CryptoPkg/Library/OpensslLib/openssl/apps/passwd.c +@@ -0,0 +1,512 @@ ++/* ++ * Copyright 2000-2016 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 ++ * in the file LICENSE in the source distribution or at ++ * https://www.openssl.org/source/license.html ++ */ ++ ++#if defined OPENSSL_NO_MD5 || defined CHARSET_EBCDIC ++# define NO_MD5CRYPT_1 ++#endif ++ ++#if !defined(OPENSSL_NO_DES) || !defined(NO_MD5CRYPT_1) ++ ++# include ++ ++# include "apps.h" ++ ++# include ++# include ++# include ++# include ++# ifndef OPENSSL_NO_DES ++# include ++# endif ++# ifndef NO_MD5CRYPT_1 ++# include ++# endif ++ ++static unsigned const char cov_2char[64] = { ++ /* from crypto/des/fcrypt.c */ ++ 0x2E, 0x2F, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, ++ 0x36, 0x37, 0x38, 0x39, 0x41, 0x42, 0x43, 0x44, ++ 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x4B, 0x4C, ++ 0x4D, 0x4E, 0x4F, 0x50, 0x51, 0x52, 0x53, 0x54, ++ 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x61, 0x62, ++ 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6A, ++ 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 0x70, 0x71, 0x72, ++ 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A ++}; ++ ++static int do_passwd(int passed_salt, char **salt_p, char **salt_malloc_p, ++ char *passwd, BIO *out, int quiet, int table, ++ int reverse, size_t pw_maxlen, int usecrypt, int use1, ++ int useapr1); ++ ++typedef enum OPTION_choice { ++ OPT_ERR = -1, OPT_EOF = 0, OPT_HELP, ++ OPT_IN, ++ OPT_NOVERIFY, OPT_QUIET, OPT_TABLE, OPT_REVERSE, OPT_APR1, ++ OPT_1, OPT_CRYPT, OPT_SALT, OPT_STDIN ++} OPTION_CHOICE; ++ ++OPTIONS passwd_options[] = { ++ {"help", OPT_HELP, '-', "Display this summary"}, ++ {"in", OPT_IN, '<', "Pead passwords from file"}, ++ {"noverify", OPT_NOVERIFY, '-', ++ "Never verify when reading password from terminal"}, ++ {"quiet", OPT_QUIET, '-', "No warnings"}, ++ {"table", OPT_TABLE, '-', "Format output as table"}, ++ {"reverse", OPT_REVERSE, '-', "Switch table columns"}, ++ {"salt", OPT_SALT, 's', "Use provided salt"}, ++ {"stdin", OPT_STDIN, '-', "Read passwords from stdin"}, ++# ifndef NO_MD5CRYPT_1 ++ {"apr1", OPT_APR1, '-', "MD5-based password algorithm, Apache variant"}, ++ {"1", OPT_1, '-', "MD5-based password algorithm"}, ++# endif ++# ifndef OPENSSL_NO_DES ++ {"crypt", OPT_CRYPT, '-', "Standard Unix password algorithm (default)"}, ++# endif ++ {NULL} ++}; ++ ++int passwd_main(int argc, char **argv) ++{ ++ BIO *in = NULL; ++ char *infile = NULL, *salt = NULL, *passwd = NULL, **passwds = NULL; ++ char *salt_malloc = NULL, *passwd_malloc = NULL, *prog; ++ OPTION_CHOICE o; ++ int in_stdin = 0, pw_source_defined = 0; ++#ifndef OPENSSL_NO_UI ++ int in_noverify = 0; ++#endif ++ int passed_salt = 0, quiet = 0, table = 0, reverse = 0; ++ int ret = 1, usecrypt = 0, use1 = 0, useapr1 = 0; ++ size_t passwd_malloc_size = 0, pw_maxlen = 256; ++ ++ prog = opt_init(argc, argv, passwd_options); ++ while ((o = opt_next()) != OPT_EOF) { ++ switch (o) { ++ case OPT_EOF: ++ case OPT_ERR: ++ opthelp: ++ BIO_printf(bio_err, "%s: Use -help for summary.\n", prog); ++ goto end; ++ case OPT_HELP: ++ opt_help(passwd_options); ++ ret = 0; ++ goto end; ++ case OPT_IN: ++ if (pw_source_defined) ++ goto opthelp; ++ infile = opt_arg(); ++ pw_source_defined = 1; ++ break; ++ case OPT_NOVERIFY: ++#ifndef OPENSSL_NO_UI ++ in_noverify = 1; ++#endif ++ break; ++ case OPT_QUIET: ++ quiet = 1; ++ break; ++ case OPT_TABLE: ++ table = 1; ++ break; ++ case OPT_REVERSE: ++ reverse = 1; ++ break; ++ case OPT_1: ++ use1 = 1; ++ break; ++ case OPT_APR1: ++ useapr1 = 1; ++ break; ++ case OPT_CRYPT: ++ usecrypt = 1; ++ break; ++ case OPT_SALT: ++ passed_salt = 1; ++ salt = opt_arg(); ++ break; ++ case OPT_STDIN: ++ if (pw_source_defined) ++ goto opthelp; ++ in_stdin = 1; ++ pw_source_defined = 1; ++ break; ++ } ++ } ++ argc = opt_num_rest(); ++ argv = opt_rest(); ++ ++ if (*argv) { ++ if (pw_source_defined) ++ goto opthelp; ++ pw_source_defined = 1; ++ passwds = argv; ++ } ++ ++ if (!usecrypt && !use1 && !useapr1) { ++ /* use default */ ++ usecrypt = 1; ++ } ++ if (usecrypt + use1 + useapr1 > 1) { ++ /* conflict */ ++ goto opthelp; ++ } ++ ++# ifdef OPENSSL_NO_DES ++ if (usecrypt) ++ goto opthelp; ++# endif ++# ifdef NO_MD5CRYPT_1 ++ if (use1 || useapr1) ++ goto opthelp; ++# endif ++ ++ if (infile != NULL && in_stdin) { ++ BIO_printf(bio_err, "%s: Can't combine -in and -stdin\n", prog); ++ goto end; ++ } ++ ++ if (infile != NULL || in_stdin) { ++ /* ++ * If in_stdin is true, we know that infile is NULL, and that ++ * bio_open_default() will give us back an alias for stdin. ++ */ ++ in = bio_open_default(infile, 'r', FORMAT_TEXT); ++ if (in == NULL) ++ goto end; ++ } ++ ++ if (usecrypt) ++ pw_maxlen = 8; ++ else if (use1 || useapr1) ++ pw_maxlen = 256; /* arbitrary limit, should be enough for most ++ * passwords */ ++ ++ if (passwds == NULL) { ++ /* no passwords on the command line */ ++ ++ passwd_malloc_size = pw_maxlen + 2; ++ /* longer than necessary so that we can warn about truncation */ ++ passwd = passwd_malloc = ++ app_malloc(passwd_malloc_size, "password buffer"); ++ } ++ ++ if ((in == NULL) && (passwds == NULL)) { ++ if (1) { ++#ifndef OPENSSL_NO_UI ++ /* build a null-terminated list */ ++ static char *passwds_static[2] = { NULL, NULL }; ++ ++ passwds = passwds_static; ++ if (in == NULL) ++ if (EVP_read_pw_string ++ (passwd_malloc, passwd_malloc_size, "Password: ", ++ !(passed_salt || in_noverify)) != 0) ++ goto end; ++ passwds[0] = passwd_malloc; ++ } else { ++#endif ++ BIO_printf(bio_err, "password required\n"); ++ goto end; ++ } ++ } ++ ++ ++ if (in == NULL) { ++ assert(passwds != NULL); ++ assert(*passwds != NULL); ++ ++ do { /* loop over list of passwords */ ++ passwd = *passwds++; ++ if (!do_passwd(passed_salt, &salt, &salt_malloc, passwd, bio_out, ++ quiet, table, reverse, pw_maxlen, usecrypt, use1, ++ useapr1)) ++ goto end; ++ } ++ while (*passwds != NULL); ++ } else ++ /* in != NULL */ ++ { ++ int done; ++ ++ assert(passwd != NULL); ++ do { ++ int r = BIO_gets(in, passwd, pw_maxlen + 1); ++ if (r > 0) { ++ char *c = (strchr(passwd, '\n')); ++ if (c != NULL) ++ *c = 0; /* truncate at newline */ ++ else { ++ /* ignore rest of line */ ++ char trash[BUFSIZ]; ++ do ++ r = BIO_gets(in, trash, sizeof trash); ++ while ((r > 0) && (!strchr(trash, '\n'))); ++ } ++ ++ if (!do_passwd ++ (passed_salt, &salt, &salt_malloc, passwd, bio_out, quiet, ++ table, reverse, pw_maxlen, usecrypt, use1, useapr1)) ++ goto end; ++ } ++ done = (r <= 0); ++ } ++ while (!done); ++ } ++ ret = 0; ++ ++ end: ++ ERR_print_errors(bio_err); ++ OPENSSL_free(salt_malloc); ++ OPENSSL_free(passwd_malloc); ++ BIO_free(in); ++ return (ret); ++} ++ ++# ifndef NO_MD5CRYPT_1 ++/* ++ * MD5-based password algorithm (should probably be available as a library ++ * function; then the static buffer would not be acceptable). For magic ++ * string "1", this should be compatible to the MD5-based BSD password ++ * algorithm. For 'magic' string "apr1", this is compatible to the MD5-based ++ * Apache password algorithm. (Apparently, the Apache password algorithm is ++ * identical except that the 'magic' string was changed -- the laziest ++ * application of the NIH principle I've ever encountered.) ++ */ ++static char *md5crypt(const char *passwd, const char *magic, const char *salt) ++{ ++ /* "$apr1$..salt..$.......md5hash..........\0" */ ++ static char out_buf[6 + 9 + 24 + 2]; ++ unsigned char buf[MD5_DIGEST_LENGTH]; ++ char *salt_out; ++ int n; ++ unsigned int i; ++ EVP_MD_CTX *md = NULL, *md2 = NULL; ++ size_t passwd_len, salt_len, magic_len; ++ ++ passwd_len = strlen(passwd); ++ out_buf[0] = '$'; ++ out_buf[1] = 0; ++ magic_len = strlen(magic); ++ ++ if (magic_len > 4) /* assert it's "1" or "apr1" */ ++ return NULL; ++ ++ OPENSSL_strlcat(out_buf, magic, sizeof out_buf); ++ OPENSSL_strlcat(out_buf, "$", sizeof out_buf); ++ OPENSSL_strlcat(out_buf, salt, sizeof out_buf); ++ ++ if (strlen(out_buf) > 6 + 8) /* assert "$apr1$..salt.." */ ++ return NULL; ++ ++ salt_out = out_buf + 2 + magic_len; ++ salt_len = strlen(salt_out); ++ ++ if (salt_len > 8) ++ return NULL; ++ ++ md = EVP_MD_CTX_new(); ++ if (md == NULL ++ || !EVP_DigestInit_ex(md, EVP_md5(), NULL) ++ || !EVP_DigestUpdate(md, passwd, passwd_len) ++ || !EVP_DigestUpdate(md, "$", 1) ++ || !EVP_DigestUpdate(md, magic, magic_len) ++ || !EVP_DigestUpdate(md, "$", 1) ++ || !EVP_DigestUpdate(md, salt_out, salt_len)) ++ goto err; ++ ++ md2 = EVP_MD_CTX_new(); ++ if (md2 == NULL ++ || !EVP_DigestInit_ex(md2, EVP_md5(), NULL) ++ || !EVP_DigestUpdate(md2, passwd, passwd_len) ++ || !EVP_DigestUpdate(md2, salt_out, salt_len) ++ || !EVP_DigestUpdate(md2, passwd, passwd_len) ++ || !EVP_DigestFinal_ex(md2, buf, NULL)) ++ goto err; ++ ++ for (i = passwd_len; i > sizeof buf; i -= sizeof buf) { ++ if (!EVP_DigestUpdate(md, buf, sizeof buf)) ++ goto err; ++ } ++ if (!EVP_DigestUpdate(md, buf, i)) ++ goto err; ++ ++ n = passwd_len; ++ while (n) { ++ if (!EVP_DigestUpdate(md, (n & 1) ? "\0" : passwd, 1)) ++ goto err; ++ n >>= 1; ++ } ++ if (!EVP_DigestFinal_ex(md, buf, NULL)) ++ return NULL; ++ ++ for (i = 0; i < 1000; i++) { ++ if (!EVP_DigestInit_ex(md2, EVP_md5(), NULL)) ++ goto err; ++ if (!EVP_DigestUpdate(md2, ++ (i & 1) ? (unsigned const char *)passwd : buf, ++ (i & 1) ? passwd_len : sizeof buf)) ++ goto err; ++ if (i % 3) { ++ if (!EVP_DigestUpdate(md2, salt_out, salt_len)) ++ goto err; ++ } ++ if (i % 7) { ++ if (!EVP_DigestUpdate(md2, passwd, passwd_len)) ++ goto err; ++ } ++ if (!EVP_DigestUpdate(md2, ++ (i & 1) ? buf : (unsigned const char *)passwd, ++ (i & 1) ? sizeof buf : passwd_len)) ++ goto err; ++ if (!EVP_DigestFinal_ex(md2, buf, NULL)) ++ goto err; ++ } ++ EVP_MD_CTX_free(md2); ++ EVP_MD_CTX_free(md); ++ md2 = NULL; ++ md = NULL; ++ ++ { ++ /* transform buf into output string */ ++ unsigned char buf_perm[sizeof buf]; ++ int dest, source; ++ char *output; ++ ++ /* silly output permutation */ ++ for (dest = 0, source = 0; dest < 14; ++ dest++, source = (source + 6) % 17) ++ buf_perm[dest] = buf[source]; ++ buf_perm[14] = buf[5]; ++ buf_perm[15] = buf[11]; ++# ifndef PEDANTIC /* Unfortunately, this generates a "no ++ * effect" warning */ ++ assert(16 == sizeof buf_perm); ++# endif ++ ++ output = salt_out + salt_len; ++ assert(output == out_buf + strlen(out_buf)); ++ ++ *output++ = '$'; ++ ++ for (i = 0; i < 15; i += 3) { ++ *output++ = cov_2char[buf_perm[i + 2] & 0x3f]; ++ *output++ = cov_2char[((buf_perm[i + 1] & 0xf) << 2) | ++ (buf_perm[i + 2] >> 6)]; ++ *output++ = cov_2char[((buf_perm[i] & 3) << 4) | ++ (buf_perm[i + 1] >> 4)]; ++ *output++ = cov_2char[buf_perm[i] >> 2]; ++ } ++ assert(i == 15); ++ *output++ = cov_2char[buf_perm[i] & 0x3f]; ++ *output++ = cov_2char[buf_perm[i] >> 6]; ++ *output = 0; ++ assert(strlen(out_buf) < sizeof(out_buf)); ++ } ++ ++ return out_buf; ++ ++ err: ++ EVP_MD_CTX_free(md2); ++ EVP_MD_CTX_free(md); ++ return NULL; ++} ++# endif ++ ++static int do_passwd(int passed_salt, char **salt_p, char **salt_malloc_p, ++ char *passwd, BIO *out, int quiet, int table, ++ int reverse, size_t pw_maxlen, int usecrypt, int use1, ++ int useapr1) ++{ ++ char *hash = NULL; ++ ++ assert(salt_p != NULL); ++ assert(salt_malloc_p != NULL); ++ ++ /* first make sure we have a salt */ ++ if (!passed_salt) { ++# ifndef OPENSSL_NO_DES ++ if (usecrypt) { ++ if (*salt_malloc_p == NULL) { ++ *salt_p = *salt_malloc_p = app_malloc(3, "salt buffer"); ++ } ++ if (RAND_bytes((unsigned char *)*salt_p, 2) <= 0) ++ goto end; ++ (*salt_p)[0] = cov_2char[(*salt_p)[0] & 0x3f]; /* 6 bits */ ++ (*salt_p)[1] = cov_2char[(*salt_p)[1] & 0x3f]; /* 6 bits */ ++ (*salt_p)[2] = 0; ++# ifdef CHARSET_EBCDIC ++ ascii2ebcdic(*salt_p, *salt_p, 2); /* des_crypt will convert back ++ * to ASCII */ ++# endif ++ } ++# endif /* !OPENSSL_NO_DES */ ++ ++# ifndef NO_MD5CRYPT_1 ++ if (use1 || useapr1) { ++ int i; ++ ++ if (*salt_malloc_p == NULL) { ++ *salt_p = *salt_malloc_p = app_malloc(9, "salt buffer"); ++ } ++ if (RAND_bytes((unsigned char *)*salt_p, 8) <= 0) ++ goto end; ++ ++ for (i = 0; i < 8; i++) ++ (*salt_p)[i] = cov_2char[(*salt_p)[i] & 0x3f]; /* 6 bits */ ++ (*salt_p)[8] = 0; ++ } ++# endif /* !NO_MD5CRYPT_1 */ ++ } ++ ++ assert(*salt_p != NULL); ++ ++ /* truncate password if necessary */ ++ if ((strlen(passwd) > pw_maxlen)) { ++ if (!quiet) ++ /* ++ * XXX: really we should know how to print a size_t, not cast it ++ */ ++ BIO_printf(bio_err, ++ "Warning: truncating password to %u characters\n", ++ (unsigned)pw_maxlen); ++ passwd[pw_maxlen] = 0; ++ } ++ assert(strlen(passwd) <= pw_maxlen); ++ ++ /* now compute password hash */ ++# ifndef OPENSSL_NO_DES ++ if (usecrypt) ++ hash = DES_crypt(passwd, *salt_p); ++# endif ++# ifndef NO_MD5CRYPT_1 ++ if (use1 || useapr1) ++ hash = md5crypt(passwd, (use1 ? "1" : "apr1"), *salt_p); ++# endif ++ assert(hash != NULL); ++ ++ if (table && !reverse) ++ BIO_printf(out, "%s\t%s\n", passwd, hash); ++ else if (table && reverse) ++ BIO_printf(out, "%s\t%s\n", hash, passwd); ++ else ++ BIO_printf(out, "%s\n", hash); ++ return 1; ++ ++ end: ++ return 0; ++} ++#else ++ ++int passwd_main(int argc, char **argv) ++{ ++ BIO_printf(bio_err, "Program not available.\n"); ++ return (1); ++} ++#endif +diff --git a/CryptoPkg/Library/OpensslLib/openssl/apps/pca-cert.srl b/CryptoPkg/Library/OpensslLib/openssl/apps/pca-cert.srl +new file mode 100644 +index 0000000..2c7456e +--- /dev/null ++++ b/CryptoPkg/Library/OpensslLib/openssl/apps/pca-cert.srl +@@ -0,0 +1 @@ ++07 +diff --git a/CryptoPkg/Library/OpensslLib/openssl/apps/pca-key.pem b/CryptoPkg/Library/OpensslLib/openssl/apps/pca-key.pem +new file mode 100644 +index 0000000..c6ad0e9 +--- /dev/null ++++ b/CryptoPkg/Library/OpensslLib/openssl/apps/pca-key.pem +@@ -0,0 +1,16 @@ ++-----BEGIN PRIVATE KEY----- ++MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBALYYjjtpLs/lfkPF ++xAFZ4V3He5mZFbsEakK9bA2fQaryreRwyfhbXbDJHyBV+c4xI5fbmmVd2t/us4k4 ++rMhGsBtL89SqCEHhPJpLFywiQVmJTAjANYrWkZK5uR/++YmZyzuLfPHLButuK6cF ++GKXw3NNToxjYooMf0mad2rPX3cKTAgMBAAECgYBvrJ+Nz/Pli9jjt2V9bqHH4Y7r ++o/avuwVv6Ltbn0+mhy4d6w3yQhYzVSTBr/iDe59YglUt1WFl8/4nKZrNOIzHJlav ++Sw4hd3fYBHxbT+DgZMQ9ikjHECWRdDffrnlTLsSJAcxnpMJBPe3dKCRDMUrqWUvB ++IIKaxyqmXJms5Y/wAQJBAPFL9NMKJcWBftMKXCasxsV0ZGjgqHGZODYjtGFN9jJO ++6AbZrxfCcapTWG4RCC2o/EDEMN8aArEhfdrYY3lhXGsCQQDBMRzFevkD7SYXTw5G ++NA/gJOAsFMYbt7tebcCRsHT7t3ymVfO2QwK7ZF0f/SYvi7cMAPraHvO7s3kFdGTB ++kDx5AkAHBICASsFCdzurA5gef9PgFjx9WFtNwnkCChPK6KuKVwUkfdw7wqnvnDDs ++Mo6cVVfQwmPxeR4u7JxuavCprQ01AkEAp5ZGAh1J9Jj9CQ1AMbAp8WOrvzGKJTM9 ++641Dll4/LLif/d7j2kDJFuvaSMyeGnKVqGkVMq/U+QeYPR4Z5TuM6QJAWK05qFed ++wYgTZyVN0MY53ZOMAIWwjz0cr24TvDfmsZqIvguGL616GKQZKdKDZQyQHg+dCzqJ ++HgIoacuFDKz5CA== ++-----END PRIVATE KEY----- +diff --git a/CryptoPkg/Library/OpensslLib/openssl/apps/pca-req.pem b/CryptoPkg/Library/OpensslLib/openssl/apps/pca-req.pem +new file mode 100644 +index 0000000..5a8c5cb +--- /dev/null ++++ b/CryptoPkg/Library/OpensslLib/openssl/apps/pca-req.pem +@@ -0,0 +1,11 @@ ++-----BEGIN CERTIFICATE REQUEST----- ++MIIBnDCCAQUCAQAwXDELMAkGA1UEBhMCQVUxEzARBgNVBAgMClF1ZWVuc2xhbmQx ++GjAYBgNVBAoMEUNyeXB0U29mdCBQdHkgTHRkMRwwGgYDVQQDDBNUZXN0IFBDQSAo ++MTAyNCBiaXQpMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC2GI47aS7P5X5D ++xcQBWeFdx3uZmRW7BGpCvWwNn0Gq8q3kcMn4W12wyR8gVfnOMSOX25plXdrf7rOJ ++OKzIRrAbS/PUqghB4TyaSxcsIkFZiUwIwDWK1pGSubkf/vmJmcs7i3zxywbrbiun ++BRil8NzTU6MY2KKDH9Jmndqz193CkwIDAQABoAAwDQYJKoZIhvcNAQELBQADgYEA ++eJdCB0nHnFK0hek4biAxX0GuJXkknuUy46NKEhv3GBwt4gtO29bfkbQTGOsBBKNs ++KptlnkItscOXY+0lSva9K3XlwD9do7k2IZFtXJVayZVw1GcKybIY0l7B6kcSxG7T ++f3CsO+ifdrsJKtyoZNs96lBMrtXyGybt3mgQNdZauQU= ++-----END CERTIFICATE REQUEST----- +diff --git a/CryptoPkg/Library/OpensslLib/openssl/apps/pkcs12.c b/CryptoPkg/Library/OpensslLib/openssl/apps/pkcs12.c +new file mode 100644 +index 0000000..0e69c9c +--- /dev/null ++++ b/CryptoPkg/Library/OpensslLib/openssl/apps/pkcs12.c +@@ -0,0 +1,935 @@ ++/* ++ * Copyright 1999-2016 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 ++ * in the file LICENSE in the source distribution or at ++ * https://www.openssl.org/source/license.html ++ */ ++ ++#include ++#if defined(OPENSSL_NO_DES) ++NON_EMPTY_TRANSLATION_UNIT ++#else ++ ++# include ++# include ++# include ++# include "apps.h" ++# include ++# include ++# include ++# include ++ ++# define NOKEYS 0x1 ++# define NOCERTS 0x2 ++# define INFO 0x4 ++# define CLCERTS 0x8 ++# define CACERTS 0x10 ++ ++static int get_cert_chain(X509 *cert, X509_STORE *store, ++ STACK_OF(X509) **chain); ++int dump_certs_keys_p12(BIO *out, const PKCS12 *p12, ++ const char *pass, int passlen, int options, ++ char *pempass, const EVP_CIPHER *enc); ++int dump_certs_pkeys_bags(BIO *out, const STACK_OF(PKCS12_SAFEBAG) *bags, ++ const char *pass, int passlen, int options, ++ char *pempass, const EVP_CIPHER *enc); ++int dump_certs_pkeys_bag(BIO *out, const PKCS12_SAFEBAG *bags, ++ const char *pass, int passlen, ++ int options, char *pempass, const EVP_CIPHER *enc); ++int print_attribs(BIO *out, const STACK_OF(X509_ATTRIBUTE) *attrlst, ++ const char *name); ++void hex_prin(BIO *out, unsigned char *buf, int len); ++static int alg_print(const X509_ALGOR *alg); ++int cert_load(BIO *in, STACK_OF(X509) *sk); ++static int set_pbe(int *ppbe, const char *str); ++ ++typedef enum OPTION_choice { ++ OPT_ERR = -1, OPT_EOF = 0, OPT_HELP, ++ OPT_CIPHER, OPT_NOKEYS, OPT_KEYEX, OPT_KEYSIG, OPT_NOCERTS, OPT_CLCERTS, ++ OPT_CACERTS, OPT_NOOUT, OPT_INFO, OPT_CHAIN, OPT_TWOPASS, OPT_NOMACVER, ++ OPT_DESCERT, OPT_EXPORT, OPT_NOITER, OPT_MACITER, OPT_NOMACITER, ++ OPT_NOMAC, OPT_LMK, OPT_NODES, OPT_MACALG, OPT_CERTPBE, OPT_KEYPBE, ++ OPT_RAND, OPT_INKEY, OPT_CERTFILE, OPT_NAME, OPT_CSP, OPT_CANAME, ++ OPT_IN, OPT_OUT, OPT_PASSIN, OPT_PASSOUT, OPT_PASSWORD, OPT_CAPATH, ++ OPT_CAFILE, OPT_NOCAPATH, OPT_NOCAFILE, OPT_ENGINE ++} OPTION_CHOICE; ++ ++OPTIONS pkcs12_options[] = { ++ {"help", OPT_HELP, '-', "Display this summary"}, ++ {"nokeys", OPT_NOKEYS, '-', "Don't output private keys"}, ++ {"keyex", OPT_KEYEX, '-', "Set MS key exchange type"}, ++ {"keysig", OPT_KEYSIG, '-', "Set MS key signature type"}, ++ {"nocerts", OPT_NOCERTS, '-', "Don't output certificates"}, ++ {"clcerts", OPT_CLCERTS, '-', "Only output client certificates"}, ++ {"cacerts", OPT_CACERTS, '-', "Only output CA certificates"}, ++ {"noout", OPT_NOOUT, '-', "Don't output anything, just verify"}, ++ {"info", OPT_INFO, '-', "Print info about PKCS#12 structure"}, ++ {"chain", OPT_CHAIN, '-', "Add certificate chain"}, ++ {"twopass", OPT_TWOPASS, '-', "Separate MAC, encryption passwords"}, ++ {"nomacver", OPT_NOMACVER, '-', "Don't verify MAC"}, ++# ifndef OPENSSL_NO_RC2 ++ {"descert", OPT_DESCERT, '-', ++ "Encrypt output with 3DES (default RC2-40)"}, ++ {"certpbe", OPT_CERTPBE, 's', ++ "Certificate PBE algorithm (default RC2-40)"}, ++# else ++ {"descert", OPT_DESCERT, '-', "Encrypt output with 3DES (the default)"}, ++ {"certpbe", OPT_CERTPBE, 's', "Certificate PBE algorithm (default 3DES)"}, ++# endif ++ {"export", OPT_EXPORT, '-', "Output PKCS12 file"}, ++ {"noiter", OPT_NOITER, '-', "Don't use encryption iteration"}, ++ {"maciter", OPT_MACITER, '-', "Use MAC iteration"}, ++ {"nomaciter", OPT_NOMACITER, '-', "Don't use MAC iteration"}, ++ {"nomac", OPT_NOMAC, '-', "Don't generate MAC"}, ++ {"LMK", OPT_LMK, '-', ++ "Add local machine keyset attribute to private key"}, ++ {"nodes", OPT_NODES, '-', "Don't encrypt private keys"}, ++ {"macalg", OPT_MACALG, 's', ++ "Digest algorithm used in MAC (default SHA1)"}, ++ {"keypbe", OPT_KEYPBE, 's', "Private key PBE algorithm (default 3DES)"}, ++ {"rand", OPT_RAND, 's', ++ "Load the file(s) into the random number generator"}, ++ {"inkey", OPT_INKEY, '<', "Private key if not infile"}, ++ {"certfile", OPT_CERTFILE, '<', "Load certs from file"}, ++ {"name", OPT_NAME, 's', "Use name as friendly name"}, ++ {"CSP", OPT_CSP, 's', "Microsoft CSP name"}, ++ {"caname", OPT_CANAME, 's', ++ "Use name as CA friendly name (can be repeated)"}, ++ {"in", OPT_IN, '<', "Input filename"}, ++ {"out", OPT_OUT, '>', "Output filename"}, ++ {"passin", OPT_PASSIN, 's', "Input file pass phrase source"}, ++ {"passout", OPT_PASSOUT, 's', "Output file pass phrase source"}, ++ {"password", OPT_PASSWORD, 's', "Set import/export password source"}, ++ {"CApath", OPT_CAPATH, '/', "PEM-format directory of CA's"}, ++ {"CAfile", OPT_CAFILE, '<', "PEM-format file of CA's"}, ++ {"no-CAfile", OPT_NOCAFILE, '-', ++ "Do not load the default certificates file"}, ++ {"no-CApath", OPT_NOCAPATH, '-', ++ "Do not load certificates from the default certificates directory"}, ++ {"", OPT_CIPHER, '-', "Any supported cipher"}, ++# ifndef OPENSSL_NO_ENGINE ++ {"engine", OPT_ENGINE, 's', "Use engine, possibly a hardware device"}, ++# endif ++ {NULL} ++}; ++ ++int pkcs12_main(int argc, char **argv) ++{ ++ char *infile = NULL, *outfile = NULL, *keyname = NULL, *certfile = NULL; ++ char *name = NULL, *csp_name = NULL; ++ char pass[2048] = "", macpass[2048] = ""; ++ int export_cert = 0, options = 0, chain = 0, twopass = 0, keytype = 0; ++ int iter = PKCS12_DEFAULT_ITER, maciter = PKCS12_DEFAULT_ITER; ++# ifndef OPENSSL_NO_RC2 ++ int cert_pbe = NID_pbe_WithSHA1And40BitRC2_CBC; ++# else ++ int cert_pbe = NID_pbe_WithSHA1And3_Key_TripleDES_CBC; ++# endif ++ int key_pbe = NID_pbe_WithSHA1And3_Key_TripleDES_CBC; ++ int ret = 1, macver = 1, add_lmk = 0, private = 0; ++ int noprompt = 0; ++ char *passinarg = NULL, *passoutarg = NULL, *passarg = NULL; ++ char *passin = NULL, *passout = NULL, *inrand = NULL, *macalg = NULL; ++ char *cpass = NULL, *mpass = NULL, *badpass = NULL; ++ const char *CApath = NULL, *CAfile = NULL, *prog; ++ int noCApath = 0, noCAfile = 0; ++ ENGINE *e = NULL; ++ BIO *in = NULL, *out = NULL; ++ PKCS12 *p12 = NULL; ++ STACK_OF(OPENSSL_STRING) *canames = NULL; ++ const EVP_CIPHER *enc = EVP_des_ede3_cbc(); ++ OPTION_CHOICE o; ++ ++ prog = opt_init(argc, argv, pkcs12_options); ++ while ((o = opt_next()) != OPT_EOF) { ++ switch (o) { ++ case OPT_EOF: ++ case OPT_ERR: ++ opthelp: ++ BIO_printf(bio_err, "%s: Use -help for summary.\n", prog); ++ goto end; ++ case OPT_HELP: ++ opt_help(pkcs12_options); ++ ret = 0; ++ goto end; ++ case OPT_NOKEYS: ++ options |= NOKEYS; ++ break; ++ case OPT_KEYEX: ++ keytype = KEY_EX; ++ break; ++ case OPT_KEYSIG: ++ keytype = KEY_SIG; ++ break; ++ case OPT_NOCERTS: ++ options |= NOCERTS; ++ break; ++ case OPT_CLCERTS: ++ options |= CLCERTS; ++ break; ++ case OPT_CACERTS: ++ options |= CACERTS; ++ break; ++ case OPT_NOOUT: ++ options |= (NOKEYS | NOCERTS); ++ break; ++ case OPT_INFO: ++ options |= INFO; ++ break; ++ case OPT_CHAIN: ++ chain = 1; ++ break; ++ case OPT_TWOPASS: ++ twopass = 1; ++ break; ++ case OPT_NOMACVER: ++ macver = 0; ++ break; ++ case OPT_DESCERT: ++ cert_pbe = NID_pbe_WithSHA1And3_Key_TripleDES_CBC; ++ break; ++ case OPT_EXPORT: ++ export_cert = 1; ++ break; ++ case OPT_CIPHER: ++ if (!opt_cipher(opt_unknown(), &enc)) ++ goto opthelp; ++ break; ++ case OPT_NOITER: ++ iter = 1; ++ break; ++ case OPT_MACITER: ++ maciter = PKCS12_DEFAULT_ITER; ++ break; ++ case OPT_NOMACITER: ++ maciter = 1; ++ break; ++ case OPT_NOMAC: ++ maciter = -1; ++ break; ++ case OPT_MACALG: ++ macalg = opt_arg(); ++ break; ++ case OPT_NODES: ++ enc = NULL; ++ break; ++ case OPT_CERTPBE: ++ if (!set_pbe(&cert_pbe, opt_arg())) ++ goto opthelp; ++ break; ++ case OPT_KEYPBE: ++ if (!set_pbe(&key_pbe, opt_arg())) ++ goto opthelp; ++ break; ++ case OPT_RAND: ++ inrand = opt_arg(); ++ break; ++ case OPT_INKEY: ++ keyname = opt_arg(); ++ break; ++ case OPT_CERTFILE: ++ certfile = opt_arg(); ++ break; ++ case OPT_NAME: ++ name = opt_arg(); ++ break; ++ case OPT_LMK: ++ add_lmk = 1; ++ break; ++ case OPT_CSP: ++ csp_name = opt_arg(); ++ break; ++ case OPT_CANAME: ++ if (canames == NULL ++ && (canames = sk_OPENSSL_STRING_new_null()) == NULL) ++ goto end; ++ sk_OPENSSL_STRING_push(canames, opt_arg()); ++ break; ++ case OPT_IN: ++ infile = opt_arg(); ++ break; ++ case OPT_OUT: ++ outfile = opt_arg(); ++ break; ++ case OPT_PASSIN: ++ passinarg = opt_arg(); ++ break; ++ case OPT_PASSOUT: ++ passoutarg = opt_arg(); ++ break; ++ case OPT_PASSWORD: ++ passarg = opt_arg(); ++ break; ++ case OPT_CAPATH: ++ CApath = opt_arg(); ++ break; ++ case OPT_CAFILE: ++ CAfile = opt_arg(); ++ break; ++ case OPT_NOCAPATH: ++ noCApath = 1; ++ break; ++ case OPT_NOCAFILE: ++ noCAfile = 1; ++ break; ++ case OPT_ENGINE: ++ e = setup_engine(opt_arg(), 0); ++ break; ++ } ++ } ++ argc = opt_num_rest(); ++ if (argc != 0) ++ goto opthelp; ++ ++ private = 1; ++ ++ if (passarg) { ++ if (export_cert) ++ passoutarg = passarg; ++ else ++ passinarg = passarg; ++ } ++ ++ if (!app_passwd(passinarg, passoutarg, &passin, &passout)) { ++ BIO_printf(bio_err, "Error getting passwords\n"); ++ goto end; ++ } ++ ++ if (!cpass) { ++ if (export_cert) ++ cpass = passout; ++ else ++ cpass = passin; ++ } ++ ++ if (cpass) { ++ mpass = cpass; ++ noprompt = 1; ++ } else { ++ cpass = pass; ++ mpass = macpass; ++ } ++ ++ if (export_cert || inrand) { ++ app_RAND_load_file(NULL, (inrand != NULL)); ++ if (inrand != NULL) ++ BIO_printf(bio_err, "%ld semi-random bytes loaded\n", ++ app_RAND_load_files(inrand)); ++ } ++ ++ if (twopass) { ++ if (1) { ++#ifndef OPENSSL_NO_UI ++ if (EVP_read_pw_string ++ (macpass, sizeof macpass, "Enter MAC Password:", export_cert)) { ++ BIO_printf(bio_err, "Can't read Password\n"); ++ goto end; ++ } ++ } else { ++#endif ++ BIO_printf(bio_err, "Unsupported option -twopass\n"); ++ goto end; ++ } ++ } ++ ++ if (export_cert) { ++ EVP_PKEY *key = NULL; ++ X509 *ucert = NULL, *x = NULL; ++ STACK_OF(X509) *certs = NULL; ++ const EVP_MD *macmd = NULL; ++ unsigned char *catmp = NULL; ++ int i; ++ ++ if ((options & (NOCERTS | NOKEYS)) == (NOCERTS | NOKEYS)) { ++ BIO_printf(bio_err, "Nothing to do!\n"); ++ goto export_end; ++ } ++ ++ if (options & NOCERTS) ++ chain = 0; ++ ++ if (!(options & NOKEYS)) { ++ key = load_key(keyname ? keyname : infile, ++ FORMAT_PEM, 1, passin, e, "private key"); ++ if (!key) ++ goto export_end; ++ } ++ ++ /* Load in all certs in input file */ ++ if (!(options & NOCERTS)) { ++ if (!load_certs(infile, &certs, FORMAT_PEM, NULL, ++ "certificates")) ++ goto export_end; ++ ++ if (key) { ++ /* Look for matching private key */ ++ for (i = 0; i < sk_X509_num(certs); i++) { ++ x = sk_X509_value(certs, i); ++ if (X509_check_private_key(x, key)) { ++ ucert = x; ++ /* Zero keyid and alias */ ++ X509_keyid_set1(ucert, NULL, 0); ++ X509_alias_set1(ucert, NULL, 0); ++ /* Remove from list */ ++ (void)sk_X509_delete(certs, i); ++ break; ++ } ++ } ++ if (!ucert) { ++ BIO_printf(bio_err, ++ "No certificate matches private key\n"); ++ goto export_end; ++ } ++ } ++ ++ } ++ ++ /* Add any more certificates asked for */ ++ if (certfile) { ++ if (!load_certs(certfile, &certs, FORMAT_PEM, NULL, ++ "certificates from certfile")) ++ goto export_end; ++ } ++ ++ /* If chaining get chain from user cert */ ++ if (chain) { ++ int vret; ++ STACK_OF(X509) *chain2; ++ X509_STORE *store; ++ if ((store = setup_verify(CAfile, CApath, noCAfile, noCApath)) ++ == NULL) ++ goto export_end; ++ ++ vret = get_cert_chain(ucert, store, &chain2); ++ X509_STORE_free(store); ++ ++ if (vret == X509_V_OK) { ++ /* Exclude verified certificate */ ++ for (i = 1; i < sk_X509_num(chain2); i++) ++ sk_X509_push(certs, sk_X509_value(chain2, i)); ++ /* Free first certificate */ ++ X509_free(sk_X509_value(chain2, 0)); ++ sk_X509_free(chain2); ++ } else { ++ if (vret != X509_V_ERR_UNSPECIFIED) ++ BIO_printf(bio_err, "Error %s getting chain.\n", ++ X509_verify_cert_error_string(vret)); ++ else ++ ERR_print_errors(bio_err); ++ goto export_end; ++ } ++ } ++ ++ /* Add any CA names */ ++ ++ for (i = 0; i < sk_OPENSSL_STRING_num(canames); i++) { ++ catmp = (unsigned char *)sk_OPENSSL_STRING_value(canames, i); ++ X509_alias_set1(sk_X509_value(certs, i), catmp, -1); ++ } ++ ++ if (csp_name && key) ++ EVP_PKEY_add1_attr_by_NID(key, NID_ms_csp_name, ++ MBSTRING_ASC, (unsigned char *)csp_name, ++ -1); ++ ++ if (add_lmk && key) ++ EVP_PKEY_add1_attr_by_NID(key, NID_LocalKeySet, 0, NULL, -1); ++ ++ if (!noprompt) { ++ if (1) { ++#ifndef OPENSSL_NO_UI ++ if (EVP_read_pw_string(pass, sizeof pass, "Enter Export Password:", ++ 1)) { ++ BIO_printf(bio_err, "Can't read Password\n"); ++ goto export_end; ++ } ++ } else { ++#endif ++ BIO_printf(bio_err, "Password required\n"); ++ goto export_end; ++ } ++ } ++ ++ if (!twopass) ++ OPENSSL_strlcpy(macpass, pass, sizeof macpass); ++ ++ p12 = PKCS12_create(cpass, name, key, ucert, certs, ++ key_pbe, cert_pbe, iter, -1, keytype); ++ ++ if (!p12) { ++ ERR_print_errors(bio_err); ++ goto export_end; ++ } ++ ++ if (macalg) { ++ if (!opt_md(macalg, &macmd)) ++ goto opthelp; ++ } ++ ++ if (maciter != -1) ++ PKCS12_set_mac(p12, mpass, -1, NULL, 0, maciter, macmd); ++ ++ assert(private); ++ ++ out = bio_open_owner(outfile, FORMAT_PKCS12, private); ++ if (out == NULL) ++ goto end; ++ ++ i2d_PKCS12_bio(out, p12); ++ ++ ret = 0; ++ ++ export_end: ++ ++ EVP_PKEY_free(key); ++ sk_X509_pop_free(certs, X509_free); ++ X509_free(ucert); ++ ++ goto end; ++ ++ } ++ ++ in = bio_open_default(infile, 'r', FORMAT_PKCS12); ++ if (in == NULL) ++ goto end; ++ out = bio_open_owner(outfile, FORMAT_PEM, private); ++ if (out == NULL) ++ goto end; ++ ++ if ((p12 = d2i_PKCS12_bio(in, NULL)) == NULL) { ++ ERR_print_errors(bio_err); ++ goto end; ++ } ++ ++ if (!noprompt) { ++ if (1) { ++#ifndef OPENSSL_NO_UI ++ if (EVP_read_pw_string(pass, sizeof pass, "Enter Import Password:", ++ 0)) { ++ BIO_printf(bio_err, "Can't read Password\n"); ++ goto end; ++ } ++ } else { ++#endif ++ BIO_printf(bio_err, "Password required\n"); ++ goto end; ++ } ++ } ++ ++ if (!twopass) ++ OPENSSL_strlcpy(macpass, pass, sizeof macpass); ++ ++ if ((options & INFO) && PKCS12_mac_present(p12)) { ++ const ASN1_INTEGER *tmaciter; ++ const X509_ALGOR *macalgid; ++ const ASN1_OBJECT *macobj; ++ PKCS12_get0_mac(NULL, &macalgid, NULL, &tmaciter, p12); ++ X509_ALGOR_get0(&macobj, NULL, NULL, macalgid); ++ BIO_puts(bio_err, "MAC:"); ++ i2a_ASN1_OBJECT(bio_err, macobj); ++ BIO_printf(bio_err, " Iteration %ld\n", ++ tmaciter != NULL ? ASN1_INTEGER_get(tmaciter) : 1L); ++ } ++ if (macver) { ++ /* If we enter empty password try no password first */ ++ if (!mpass[0] && PKCS12_verify_mac(p12, NULL, 0)) { ++ /* If mac and crypto pass the same set it to NULL too */ ++ if (!twopass) ++ cpass = NULL; ++ } else if (!PKCS12_verify_mac(p12, mpass, -1)) { ++ /* ++ * May be UTF8 from previous version of OpenSSL: ++ * convert to a UTF8 form which will translate ++ * to the same Unicode password. ++ */ ++ unsigned char *utmp; ++ int utmplen; ++ utmp = OPENSSL_asc2uni(mpass, -1, NULL, &utmplen); ++ if (utmp == NULL) ++ goto end; ++ badpass = OPENSSL_uni2utf8(utmp, utmplen); ++ OPENSSL_free(utmp); ++ if (!PKCS12_verify_mac(p12, badpass, -1)) { ++ BIO_printf(bio_err, "Mac verify error: invalid password?\n"); ++ ERR_print_errors(bio_err); ++ goto end; ++ } else { ++ BIO_printf(bio_err, "Warning: using broken algorithm\n"); ++ if (!twopass) ++ cpass = badpass; ++ } ++ } ++ } ++ ++ assert(private); ++ if (!dump_certs_keys_p12(out, p12, cpass, -1, options, passout, enc)) { ++ BIO_printf(bio_err, "Error outputting keys and certificates\n"); ++ ERR_print_errors(bio_err); ++ goto end; ++ } ++ ret = 0; ++ end: ++ PKCS12_free(p12); ++ if (export_cert || inrand) ++ app_RAND_write_file(NULL); ++ release_engine(e); ++ BIO_free(in); ++ BIO_free_all(out); ++ sk_OPENSSL_STRING_free(canames); ++ OPENSSL_free(badpass); ++ OPENSSL_free(passin); ++ OPENSSL_free(passout); ++ return (ret); ++} ++ ++int dump_certs_keys_p12(BIO *out, const PKCS12 *p12, const char *pass, ++ int passlen, int options, char *pempass, ++ const EVP_CIPHER *enc) ++{ ++ STACK_OF(PKCS7) *asafes = NULL; ++ STACK_OF(PKCS12_SAFEBAG) *bags; ++ int i, bagnid; ++ int ret = 0; ++ PKCS7 *p7; ++ ++ if ((asafes = PKCS12_unpack_authsafes(p12)) == NULL) ++ return 0; ++ for (i = 0; i < sk_PKCS7_num(asafes); i++) { ++ p7 = sk_PKCS7_value(asafes, i); ++ bagnid = OBJ_obj2nid(p7->type); ++ if (bagnid == NID_pkcs7_data) { ++ bags = PKCS12_unpack_p7data(p7); ++ if (options & INFO) ++ BIO_printf(bio_err, "PKCS7 Data\n"); ++ } else if (bagnid == NID_pkcs7_encrypted) { ++ if (options & INFO) { ++ BIO_printf(bio_err, "PKCS7 Encrypted data: "); ++ alg_print(p7->d.encrypted->enc_data->algorithm); ++ } ++ bags = PKCS12_unpack_p7encdata(p7, pass, passlen); ++ } else ++ continue; ++ if (!bags) ++ goto err; ++ if (!dump_certs_pkeys_bags(out, bags, pass, passlen, ++ options, pempass, enc)) { ++ sk_PKCS12_SAFEBAG_pop_free(bags, PKCS12_SAFEBAG_free); ++ goto err; ++ } ++ sk_PKCS12_SAFEBAG_pop_free(bags, PKCS12_SAFEBAG_free); ++ bags = NULL; ++ } ++ ret = 1; ++ ++ err: ++ sk_PKCS7_pop_free(asafes, PKCS7_free); ++ return ret; ++} ++ ++int dump_certs_pkeys_bags(BIO *out, const STACK_OF(PKCS12_SAFEBAG) *bags, ++ const char *pass, int passlen, int options, ++ char *pempass, const EVP_CIPHER *enc) ++{ ++ int i; ++ for (i = 0; i < sk_PKCS12_SAFEBAG_num(bags); i++) { ++ if (!dump_certs_pkeys_bag(out, ++ sk_PKCS12_SAFEBAG_value(bags, i), ++ pass, passlen, options, pempass, enc)) ++ return 0; ++ } ++ return 1; ++} ++ ++int dump_certs_pkeys_bag(BIO *out, const PKCS12_SAFEBAG *bag, ++ const char *pass, int passlen, int options, ++ char *pempass, const EVP_CIPHER *enc) ++{ ++ EVP_PKEY *pkey; ++ PKCS8_PRIV_KEY_INFO *p8; ++ const PKCS8_PRIV_KEY_INFO *p8c; ++ X509 *x509; ++ const STACK_OF(X509_ATTRIBUTE) *attrs; ++ int ret = 0; ++ ++ attrs = PKCS12_SAFEBAG_get0_attrs(bag); ++ ++ switch (PKCS12_SAFEBAG_get_nid(bag)) { ++ case NID_keyBag: ++ if (options & INFO) ++ BIO_printf(bio_err, "Key bag\n"); ++ if (options & NOKEYS) ++ return 1; ++ print_attribs(out, attrs, "Bag Attributes"); ++ p8c = PKCS12_SAFEBAG_get0_p8inf(bag); ++ if ((pkey = EVP_PKCS82PKEY(p8c)) == NULL) ++ return 0; ++ print_attribs(out, PKCS8_pkey_get0_attrs(p8c), "Key Attributes"); ++ ret = PEM_write_bio_PrivateKey(out, pkey, enc, NULL, 0, NULL, pempass); ++ EVP_PKEY_free(pkey); ++ break; ++ ++ case NID_pkcs8ShroudedKeyBag: ++ if (options & INFO) { ++ const X509_SIG *tp8; ++ const X509_ALGOR *tp8alg; ++ ++ BIO_printf(bio_err, "Shrouded Keybag: "); ++ tp8 = PKCS12_SAFEBAG_get0_pkcs8(bag); ++ X509_SIG_get0(tp8, &tp8alg, NULL); ++ alg_print(tp8alg); ++ } ++ if (options & NOKEYS) ++ return 1; ++ print_attribs(out, attrs, "Bag Attributes"); ++ if ((p8 = PKCS12_decrypt_skey(bag, pass, passlen)) == NULL) ++ return 0; ++ if ((pkey = EVP_PKCS82PKEY(p8)) == NULL) { ++ PKCS8_PRIV_KEY_INFO_free(p8); ++ return 0; ++ } ++ print_attribs(out, PKCS8_pkey_get0_attrs(p8), "Key Attributes"); ++ PKCS8_PRIV_KEY_INFO_free(p8); ++ ret = PEM_write_bio_PrivateKey(out, pkey, enc, NULL, 0, NULL, pempass); ++ EVP_PKEY_free(pkey); ++ break; ++ ++ case NID_certBag: ++ if (options & INFO) ++ BIO_printf(bio_err, "Certificate bag\n"); ++ if (options & NOCERTS) ++ return 1; ++ if (PKCS12_SAFEBAG_get0_attr(bag, NID_localKeyID)) { ++ if (options & CACERTS) ++ return 1; ++ } else if (options & CLCERTS) ++ return 1; ++ print_attribs(out, attrs, "Bag Attributes"); ++ if (PKCS12_SAFEBAG_get_bag_nid(bag) != NID_x509Certificate) ++ return 1; ++ if ((x509 = PKCS12_SAFEBAG_get1_cert(bag)) == NULL) ++ return 0; ++ dump_cert_text(out, x509); ++ ret = PEM_write_bio_X509(out, x509); ++ X509_free(x509); ++ break; ++ ++ case NID_safeContentsBag: ++ if (options & INFO) ++ BIO_printf(bio_err, "Safe Contents bag\n"); ++ print_attribs(out, attrs, "Bag Attributes"); ++ return dump_certs_pkeys_bags(out, PKCS12_SAFEBAG_get0_safes(bag), ++ pass, passlen, options, pempass, enc); ++ ++ default: ++ BIO_printf(bio_err, "Warning unsupported bag type: "); ++ i2a_ASN1_OBJECT(bio_err, PKCS12_SAFEBAG_get0_type(bag)); ++ BIO_printf(bio_err, "\n"); ++ return 1; ++ } ++ return ret; ++} ++ ++/* Given a single certificate return a verified chain or NULL if error */ ++ ++static int get_cert_chain(X509 *cert, X509_STORE *store, ++ STACK_OF(X509) **chain) ++{ ++ X509_STORE_CTX *store_ctx = NULL; ++ STACK_OF(X509) *chn = NULL; ++ int i = 0; ++ ++ store_ctx = X509_STORE_CTX_new(); ++ if (store_ctx == NULL) { ++ i = X509_V_ERR_UNSPECIFIED; ++ goto end; ++ } ++ if (!X509_STORE_CTX_init(store_ctx, store, cert, NULL)) { ++ i = X509_V_ERR_UNSPECIFIED; ++ goto end; ++ } ++ ++ ++ if (X509_verify_cert(store_ctx) > 0) ++ chn = X509_STORE_CTX_get1_chain(store_ctx); ++ else if ((i = X509_STORE_CTX_get_error(store_ctx)) == 0) ++ i = X509_V_ERR_UNSPECIFIED; ++ ++end: ++ X509_STORE_CTX_free(store_ctx); ++ *chain = chn; ++ return i; ++} ++ ++static int alg_print(const X509_ALGOR *alg) ++{ ++ int pbenid, aparamtype; ++ const ASN1_OBJECT *aoid; ++ const void *aparam; ++ PBEPARAM *pbe = NULL; ++ ++ X509_ALGOR_get0(&aoid, &aparamtype, &aparam, alg); ++ ++ pbenid = OBJ_obj2nid(aoid); ++ ++ BIO_printf(bio_err, "%s", OBJ_nid2ln(pbenid)); ++ ++ /* ++ * If PBE algorithm is PBES2 decode algorithm parameters ++ * for additional details. ++ */ ++ if (pbenid == NID_pbes2) { ++ PBE2PARAM *pbe2 = NULL; ++ int encnid; ++ if (aparamtype == V_ASN1_SEQUENCE) ++ pbe2 = ASN1_item_unpack(aparam, ASN1_ITEM_rptr(PBE2PARAM)); ++ if (pbe2 == NULL) { ++ BIO_puts(bio_err, ""); ++ goto done; ++ } ++ X509_ALGOR_get0(&aoid, &aparamtype, &aparam, pbe2->keyfunc); ++ pbenid = OBJ_obj2nid(aoid); ++ X509_ALGOR_get0(&aoid, NULL, NULL, pbe2->encryption); ++ encnid = OBJ_obj2nid(aoid); ++ BIO_printf(bio_err, ", %s, %s", OBJ_nid2ln(pbenid), ++ OBJ_nid2sn(encnid)); ++ /* If KDF is PBKDF2 decode parameters */ ++ if (pbenid == NID_id_pbkdf2) { ++ PBKDF2PARAM *kdf = NULL; ++ int prfnid; ++ if (aparamtype == V_ASN1_SEQUENCE) ++ kdf = ASN1_item_unpack(aparam, ASN1_ITEM_rptr(PBKDF2PARAM)); ++ if (kdf == NULL) { ++ BIO_puts(bio_err, ""); ++ goto done; ++ } ++ ++ if (kdf->prf == NULL) { ++ prfnid = NID_hmacWithSHA1; ++ } else { ++ X509_ALGOR_get0(&aoid, NULL, NULL, kdf->prf); ++ prfnid = OBJ_obj2nid(aoid); ++ } ++ BIO_printf(bio_err, ", Iteration %ld, PRF %s", ++ ASN1_INTEGER_get(kdf->iter), OBJ_nid2sn(prfnid)); ++ PBKDF2PARAM_free(kdf); ++ } ++ PBE2PARAM_free(pbe2); ++ } else { ++ if (aparamtype == V_ASN1_SEQUENCE) ++ pbe = ASN1_item_unpack(aparam, ASN1_ITEM_rptr(PBEPARAM)); ++ if (pbe == NULL) { ++ BIO_puts(bio_err, ""); ++ goto done; ++ } ++ BIO_printf(bio_err, ", Iteration %ld", ASN1_INTEGER_get(pbe->iter)); ++ PBEPARAM_free(pbe); ++ } ++ done: ++ BIO_puts(bio_err, "\n"); ++ return 1; ++} ++ ++/* Load all certificates from a given file */ ++ ++int cert_load(BIO *in, STACK_OF(X509) *sk) ++{ ++ int ret; ++ X509 *cert; ++ ret = 0; ++ while ((cert = PEM_read_bio_X509(in, NULL, NULL, NULL))) { ++ ret = 1; ++ sk_X509_push(sk, cert); ++ } ++ if (ret) ++ ERR_clear_error(); ++ return ret; ++} ++ ++/* Generalised attribute print: handle PKCS#8 and bag attributes */ ++ ++int print_attribs(BIO *out, const STACK_OF(X509_ATTRIBUTE) *attrlst, ++ const char *name) ++{ ++ X509_ATTRIBUTE *attr; ++ ASN1_TYPE *av; ++ char *value; ++ int i, attr_nid; ++ if (!attrlst) { ++ BIO_printf(out, "%s: \n", name); ++ return 1; ++ } ++ if (!sk_X509_ATTRIBUTE_num(attrlst)) { ++ BIO_printf(out, "%s: \n", name); ++ return 1; ++ } ++ BIO_printf(out, "%s\n", name); ++ for (i = 0; i < sk_X509_ATTRIBUTE_num(attrlst); i++) { ++ ASN1_OBJECT *attr_obj; ++ attr = sk_X509_ATTRIBUTE_value(attrlst, i); ++ attr_obj = X509_ATTRIBUTE_get0_object(attr); ++ attr_nid = OBJ_obj2nid(attr_obj); ++ BIO_printf(out, " "); ++ if (attr_nid == NID_undef) { ++ i2a_ASN1_OBJECT(out, attr_obj); ++ BIO_printf(out, ": "); ++ } else ++ BIO_printf(out, "%s: ", OBJ_nid2ln(attr_nid)); ++ ++ if (X509_ATTRIBUTE_count(attr)) { ++ av = X509_ATTRIBUTE_get0_type(attr, 0); ++ switch (av->type) { ++ case V_ASN1_BMPSTRING: ++ value = OPENSSL_uni2asc(av->value.bmpstring->data, ++ av->value.bmpstring->length); ++ BIO_printf(out, "%s\n", value); ++ OPENSSL_free(value); ++ break; ++ ++ case V_ASN1_OCTET_STRING: ++ hex_prin(out, av->value.octet_string->data, ++ av->value.octet_string->length); ++ BIO_printf(out, "\n"); ++ break; ++ ++ case V_ASN1_BIT_STRING: ++ hex_prin(out, av->value.bit_string->data, ++ av->value.bit_string->length); ++ BIO_printf(out, "\n"); ++ break; ++ ++ default: ++ BIO_printf(out, "\n", av->type); ++ break; ++ } ++ } else ++ BIO_printf(out, "\n"); ++ } ++ return 1; ++} ++ ++void hex_prin(BIO *out, unsigned char *buf, int len) ++{ ++ int i; ++ for (i = 0; i < len; i++) ++ BIO_printf(out, "%02X ", buf[i]); ++} ++ ++static int set_pbe(int *ppbe, const char *str) ++{ ++ if (!str) ++ return 0; ++ if (strcmp(str, "NONE") == 0) { ++ *ppbe = -1; ++ return 1; ++ } ++ *ppbe = OBJ_txt2nid(str); ++ if (*ppbe == NID_undef) { ++ BIO_printf(bio_err, "Unknown PBE algorithm %s\n", str); ++ return 0; ++ } ++ return 1; ++} ++ ++#endif +diff --git a/CryptoPkg/Library/OpensslLib/openssl/apps/pkcs7.c b/CryptoPkg/Library/OpensslLib/openssl/apps/pkcs7.c +new file mode 100644 +index 0000000..209e30d +--- /dev/null ++++ b/CryptoPkg/Library/OpensslLib/openssl/apps/pkcs7.c +@@ -0,0 +1,197 @@ ++/* ++ * Copyright 1995-2016 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 ++ * in the file LICENSE in the source distribution or at ++ * https://www.openssl.org/source/license.html ++ */ ++ ++#include ++#include ++#include ++#include ++#include "apps.h" ++#include ++#include ++#include ++#include ++#include ++#include ++ ++typedef enum OPTION_choice { ++ OPT_ERR = -1, OPT_EOF = 0, OPT_HELP, ++ OPT_INFORM, OPT_OUTFORM, OPT_IN, OPT_OUT, OPT_NOOUT, ++ OPT_TEXT, OPT_PRINT, OPT_PRINT_CERTS, OPT_ENGINE ++} OPTION_CHOICE; ++ ++OPTIONS pkcs7_options[] = { ++ {"help", OPT_HELP, '-', "Display this summary"}, ++ {"inform", OPT_INFORM, 'F', "Input format - DER or PEM"}, ++ {"in", OPT_IN, '<', "Input file"}, ++ {"outform", OPT_OUTFORM, 'F', "Output format - DER or PEM"}, ++ {"out", OPT_OUT, '>', "Output file"}, ++ {"noout", OPT_NOOUT, '-', "Don't output encoded data"}, ++ {"text", OPT_TEXT, '-', "Print full details of certificates"}, ++ {"print", OPT_PRINT, '-', "Print out all fields of the PKCS7 structure"}, ++ {"print_certs", OPT_PRINT_CERTS, '-', ++ "Print_certs print any certs or crl in the input"}, ++#ifndef OPENSSL_NO_ENGINE ++ {"engine", OPT_ENGINE, 's', "Use engine, possibly a hardware device"}, ++#endif ++ {NULL} ++}; ++ ++int pkcs7_main(int argc, char **argv) ++{ ++ ENGINE *e = NULL; ++ PKCS7 *p7 = NULL; ++ BIO *in = NULL, *out = NULL; ++ int informat = FORMAT_PEM, outformat = FORMAT_PEM; ++ char *infile = NULL, *outfile = NULL, *prog; ++ int i, print_certs = 0, text = 0, noout = 0, p7_print = 0, ret = 1; ++ OPTION_CHOICE o; ++ ++ prog = opt_init(argc, argv, pkcs7_options); ++ while ((o = opt_next()) != OPT_EOF) { ++ switch (o) { ++ case OPT_EOF: ++ case OPT_ERR: ++ opthelp: ++ BIO_printf(bio_err, "%s: Use -help for summary.\n", prog); ++ goto end; ++ case OPT_HELP: ++ opt_help(pkcs7_options); ++ ret = 0; ++ goto end; ++ case OPT_INFORM: ++ if (!opt_format(opt_arg(), OPT_FMT_PEMDER, &informat)) ++ goto opthelp; ++ break; ++ case OPT_OUTFORM: ++ if (!opt_format(opt_arg(), OPT_FMT_PEMDER, &outformat)) ++ goto opthelp; ++ break; ++ case OPT_IN: ++ infile = opt_arg(); ++ break; ++ case OPT_OUT: ++ outfile = opt_arg(); ++ break; ++ case OPT_NOOUT: ++ noout = 1; ++ break; ++ case OPT_TEXT: ++ text = 1; ++ break; ++ case OPT_PRINT: ++ p7_print = 1; ++ break; ++ case OPT_PRINT_CERTS: ++ print_certs = 1; ++ break; ++ case OPT_ENGINE: ++ e = setup_engine(opt_arg(), 0); ++ break; ++ } ++ } ++ argc = opt_num_rest(); ++ if (argc != 0) ++ goto opthelp; ++ ++ in = bio_open_default(infile, 'r', informat); ++ if (in == NULL) ++ goto end; ++ ++ if (informat == FORMAT_ASN1) ++ p7 = d2i_PKCS7_bio(in, NULL); ++ else ++ p7 = PEM_read_bio_PKCS7(in, NULL, NULL, NULL); ++ if (p7 == NULL) { ++ BIO_printf(bio_err, "unable to load PKCS7 object\n"); ++ ERR_print_errors(bio_err); ++ goto end; ++ } ++ ++ out = bio_open_default(outfile, 'w', outformat); ++ if (out == NULL) ++ goto end; ++ ++ if (p7_print) ++ PKCS7_print_ctx(out, p7, 0, NULL); ++ ++ if (print_certs) { ++ STACK_OF(X509) *certs = NULL; ++ STACK_OF(X509_CRL) *crls = NULL; ++ ++ i = OBJ_obj2nid(p7->type); ++ switch (i) { ++ case NID_pkcs7_signed: ++ if (p7->d.sign != NULL) { ++ certs = p7->d.sign->cert; ++ crls = p7->d.sign->crl; ++ } ++ break; ++ case NID_pkcs7_signedAndEnveloped: ++ if (p7->d.signed_and_enveloped != NULL) { ++ certs = p7->d.signed_and_enveloped->cert; ++ crls = p7->d.signed_and_enveloped->crl; ++ } ++ break; ++ default: ++ break; ++ } ++ ++ if (certs != NULL) { ++ X509 *x; ++ ++ for (i = 0; i < sk_X509_num(certs); i++) { ++ x = sk_X509_value(certs, i); ++ if (text) ++ X509_print(out, x); ++ else ++ dump_cert_text(out, x); ++ ++ if (!noout) ++ PEM_write_bio_X509(out, x); ++ BIO_puts(out, "\n"); ++ } ++ } ++ if (crls != NULL) { ++ X509_CRL *crl; ++ ++ for (i = 0; i < sk_X509_CRL_num(crls); i++) { ++ crl = sk_X509_CRL_value(crls, i); ++ ++ X509_CRL_print(out, crl); ++ ++ if (!noout) ++ PEM_write_bio_X509_CRL(out, crl); ++ BIO_puts(out, "\n"); ++ } ++ } ++ ++ ret = 0; ++ goto end; ++ } ++ ++ if (!noout) { ++ if (outformat == FORMAT_ASN1) ++ i = i2d_PKCS7_bio(out, p7); ++ else ++ i = PEM_write_bio_PKCS7(out, p7); ++ ++ if (!i) { ++ BIO_printf(bio_err, "unable to write pkcs7 object\n"); ++ ERR_print_errors(bio_err); ++ goto end; ++ } ++ } ++ ret = 0; ++ end: ++ PKCS7_free(p7); ++ release_engine(e); ++ BIO_free(in); ++ BIO_free_all(out); ++ return (ret); ++} +diff --git a/CryptoPkg/Library/OpensslLib/openssl/apps/pkcs8.c b/CryptoPkg/Library/OpensslLib/openssl/apps/pkcs8.c +new file mode 100644 +index 0000000..93ffdd5 +--- /dev/null ++++ b/CryptoPkg/Library/OpensslLib/openssl/apps/pkcs8.c +@@ -0,0 +1,353 @@ ++/* ++ * Copyright 1999-2016 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 ++ * in the file LICENSE in the source distribution or at ++ * https://www.openssl.org/source/license.html ++ */ ++ ++#include ++#include ++#include ++#include "apps.h" ++#include ++#include ++#include ++#include ++ ++typedef enum OPTION_choice { ++ OPT_ERR = -1, OPT_EOF = 0, OPT_HELP, ++ OPT_INFORM, OPT_OUTFORM, OPT_ENGINE, OPT_IN, OPT_OUT, ++ OPT_TOPK8, OPT_NOITER, OPT_NOCRYPT, ++#ifndef OPENSSL_NO_SCRYPT ++ OPT_SCRYPT, OPT_SCRYPT_N, OPT_SCRYPT_R, OPT_SCRYPT_P, ++#endif ++ OPT_V2, OPT_V1, OPT_V2PRF, OPT_ITER, OPT_PASSIN, OPT_PASSOUT, ++ OPT_TRADITIONAL ++} OPTION_CHOICE; ++ ++OPTIONS pkcs8_options[] = { ++ {"help", OPT_HELP, '-', "Display this summary"}, ++ {"inform", OPT_INFORM, 'F', "Input format (DER or PEM)"}, ++ {"outform", OPT_OUTFORM, 'F', "Output format (DER or PEM)"}, ++ {"in", OPT_IN, '<', "Input file"}, ++ {"out", OPT_OUT, '>', "Output file"}, ++ {"topk8", OPT_TOPK8, '-', "Output PKCS8 file"}, ++ {"noiter", OPT_NOITER, '-', "Use 1 as iteration count"}, ++ {"nocrypt", OPT_NOCRYPT, '-', "Use or expect unencrypted private key"}, ++ {"v2", OPT_V2, 's', "Use PKCS#5 v2.0 and cipher"}, ++ {"v1", OPT_V1, 's', "Use PKCS#5 v1.5 and cipher"}, ++ {"v2prf", OPT_V2PRF, 's', "Set the PRF algorithm to use with PKCS#5 v2.0"}, ++ {"iter", OPT_ITER, 'p', "Specify the iteration count"}, ++ {"passin", OPT_PASSIN, 's', "Input file pass phrase source"}, ++ {"passout", OPT_PASSOUT, 's', "Output file pass phrase source"}, ++ {"traditional", OPT_TRADITIONAL, '-', "use traditional format private key"}, ++#ifndef OPENSSL_NO_ENGINE ++ {"engine", OPT_ENGINE, 's', "Use engine, possibly a hardware device"}, ++#endif ++#ifndef OPENSSL_NO_SCRYPT ++ {"scrypt", OPT_SCRYPT, '-', "Use scrypt algorithm"}, ++ {"scrypt_N", OPT_SCRYPT_N, 's', "Set scrypt N parameter"}, ++ {"scrypt_r", OPT_SCRYPT_R, 's', "Set scrypt r parameter"}, ++ {"scrypt_p", OPT_SCRYPT_P, 's', "Set scrypt p parameter"}, ++#endif ++ {NULL} ++}; ++ ++int pkcs8_main(int argc, char **argv) ++{ ++ BIO *in = NULL, *out = NULL; ++ ENGINE *e = NULL; ++ EVP_PKEY *pkey = NULL; ++ PKCS8_PRIV_KEY_INFO *p8inf = NULL; ++ X509_SIG *p8 = NULL; ++ const EVP_CIPHER *cipher = NULL; ++ char *infile = NULL, *outfile = NULL; ++ char *passinarg = NULL, *passoutarg = NULL, *prog; ++#ifndef OPENSSL_NO_UI ++ char pass[50]; ++#endif ++ char *passin = NULL, *passout = NULL, *p8pass = NULL; ++ OPTION_CHOICE o; ++ int nocrypt = 0, ret = 1, iter = PKCS12_DEFAULT_ITER; ++ int informat = FORMAT_PEM, outformat = FORMAT_PEM, topk8 = 0, pbe_nid = -1; ++ int private = 0, traditional = 0; ++#ifndef OPENSSL_NO_SCRYPT ++ long scrypt_N = 0, scrypt_r = 0, scrypt_p = 0; ++#endif ++ ++ prog = opt_init(argc, argv, pkcs8_options); ++ while ((o = opt_next()) != OPT_EOF) { ++ switch (o) { ++ case OPT_EOF: ++ case OPT_ERR: ++ opthelp: ++ BIO_printf(bio_err, "%s: Use -help for summary.\n", prog); ++ goto end; ++ case OPT_HELP: ++ opt_help(pkcs8_options); ++ ret = 0; ++ goto end; ++ case OPT_INFORM: ++ if (!opt_format(opt_arg(), OPT_FMT_PEMDER, &informat)) ++ goto opthelp; ++ break; ++ case OPT_IN: ++ infile = opt_arg(); ++ break; ++ case OPT_OUTFORM: ++ if (!opt_format(opt_arg(), OPT_FMT_PEMDER, &outformat)) ++ goto opthelp; ++ break; ++ case OPT_OUT: ++ outfile = opt_arg(); ++ break; ++ case OPT_TOPK8: ++ topk8 = 1; ++ break; ++ case OPT_NOITER: ++ iter = 1; ++ break; ++ case OPT_NOCRYPT: ++ nocrypt = 1; ++ break; ++ case OPT_TRADITIONAL: ++ traditional = 1; ++ break; ++ case OPT_V2: ++ if (!opt_cipher(opt_arg(), &cipher)) ++ goto opthelp; ++ break; ++ case OPT_V1: ++ pbe_nid = OBJ_txt2nid(opt_arg()); ++ if (pbe_nid == NID_undef) { ++ BIO_printf(bio_err, ++ "%s: Unknown PBE algorithm %s\n", prog, opt_arg()); ++ goto opthelp; ++ } ++ break; ++ case OPT_V2PRF: ++ pbe_nid = OBJ_txt2nid(opt_arg()); ++ if (!EVP_PBE_find(EVP_PBE_TYPE_PRF, pbe_nid, NULL, NULL, 0)) { ++ BIO_printf(bio_err, ++ "%s: Unknown PRF algorithm %s\n", prog, opt_arg()); ++ goto opthelp; ++ } ++ if (cipher == NULL) ++ cipher = EVP_aes_256_cbc(); ++ break; ++ case OPT_ITER: ++ if (!opt_int(opt_arg(), &iter)) ++ goto opthelp; ++ break; ++ case OPT_PASSIN: ++ passinarg = opt_arg(); ++ break; ++ case OPT_PASSOUT: ++ passoutarg = opt_arg(); ++ break; ++ case OPT_ENGINE: ++ e = setup_engine(opt_arg(), 0); ++ break; ++#ifndef OPENSSL_NO_SCRYPT ++ case OPT_SCRYPT: ++ scrypt_N = 16384; ++ scrypt_r = 8; ++ scrypt_p = 1; ++ if (cipher == NULL) ++ cipher = EVP_aes_256_cbc(); ++ break; ++ case OPT_SCRYPT_N: ++ if (!opt_long(opt_arg(), &scrypt_N) || scrypt_N <= 0) ++ goto opthelp; ++ break; ++ case OPT_SCRYPT_R: ++ if (!opt_long(opt_arg(), &scrypt_r) || scrypt_r <= 0) ++ goto opthelp; ++ break; ++ case OPT_SCRYPT_P: ++ if (!opt_long(opt_arg(), &scrypt_p) || scrypt_p <= 0) ++ goto opthelp; ++ break; ++#endif ++ } ++ } ++ argc = opt_num_rest(); ++ if (argc != 0) ++ goto opthelp; ++ ++ private = 1; ++ ++ if (!app_passwd(passinarg, passoutarg, &passin, &passout)) { ++ BIO_printf(bio_err, "Error getting passwords\n"); ++ goto end; ++ } ++ ++ if ((pbe_nid == -1) && cipher == NULL) ++ cipher = EVP_aes_256_cbc(); ++ ++ in = bio_open_default(infile, 'r', informat); ++ if (in == NULL) ++ goto end; ++ out = bio_open_owner(outfile, outformat, private); ++ if (out == NULL) ++ goto end; ++ ++ if (topk8) { ++ pkey = load_key(infile, informat, 1, passin, e, "key"); ++ if (!pkey) ++ goto end; ++ if ((p8inf = EVP_PKEY2PKCS8(pkey)) == NULL) { ++ BIO_printf(bio_err, "Error converting key\n"); ++ ERR_print_errors(bio_err); ++ goto end; ++ } ++ if (nocrypt) { ++ assert(private); ++ if (outformat == FORMAT_PEM) ++ PEM_write_bio_PKCS8_PRIV_KEY_INFO(out, p8inf); ++ else if (outformat == FORMAT_ASN1) ++ i2d_PKCS8_PRIV_KEY_INFO_bio(out, p8inf); ++ else { ++ BIO_printf(bio_err, "Bad format specified for key\n"); ++ goto end; ++ } ++ } else { ++ X509_ALGOR *pbe; ++ if (cipher) { ++#ifndef OPENSSL_NO_SCRYPT ++ if (scrypt_N && scrypt_r && scrypt_p) ++ pbe = PKCS5_pbe2_set_scrypt(cipher, NULL, 0, NULL, ++ scrypt_N, scrypt_r, scrypt_p); ++ else ++#endif ++ pbe = PKCS5_pbe2_set_iv(cipher, iter, NULL, 0, NULL, ++ pbe_nid); ++ } else { ++ pbe = PKCS5_pbe_set(pbe_nid, iter, NULL, 0); ++ } ++ if (pbe == NULL) { ++ BIO_printf(bio_err, "Error setting PBE algorithm\n"); ++ ERR_print_errors(bio_err); ++ goto end; ++ } ++ if (passout) ++ p8pass = passout; ++ else if (1) { ++#ifndef OPENSSL_NO_UI ++ p8pass = pass; ++ if (EVP_read_pw_string ++ (pass, sizeof pass, "Enter Encryption Password:", 1)) { ++ X509_ALGOR_free(pbe); ++ goto end; ++ } ++ } else { ++#endif ++ BIO_printf(bio_err, "Password required\n"); ++ goto end; ++ } ++ app_RAND_load_file(NULL, 0); ++ p8 = PKCS8_set0_pbe(p8pass, strlen(p8pass), p8inf, pbe); ++ if (p8 == NULL) { ++ X509_ALGOR_free(pbe); ++ BIO_printf(bio_err, "Error encrypting key\n"); ++ ERR_print_errors(bio_err); ++ goto end; ++ } ++ app_RAND_write_file(NULL); ++ assert(private); ++ if (outformat == FORMAT_PEM) ++ PEM_write_bio_PKCS8(out, p8); ++ else if (outformat == FORMAT_ASN1) ++ i2d_PKCS8_bio(out, p8); ++ else { ++ BIO_printf(bio_err, "Bad format specified for key\n"); ++ goto end; ++ } ++ } ++ ++ ret = 0; ++ goto end; ++ } ++ ++ if (nocrypt) { ++ if (informat == FORMAT_PEM) ++ p8inf = PEM_read_bio_PKCS8_PRIV_KEY_INFO(in, NULL, NULL, NULL); ++ else if (informat == FORMAT_ASN1) ++ p8inf = d2i_PKCS8_PRIV_KEY_INFO_bio(in, NULL); ++ else { ++ BIO_printf(bio_err, "Bad format specified for key\n"); ++ goto end; ++ } ++ } else { ++ if (informat == FORMAT_PEM) ++ p8 = PEM_read_bio_PKCS8(in, NULL, NULL, NULL); ++ else if (informat == FORMAT_ASN1) ++ p8 = d2i_PKCS8_bio(in, NULL); ++ else { ++ BIO_printf(bio_err, "Bad format specified for key\n"); ++ goto end; ++ } ++ ++ if (!p8) { ++ BIO_printf(bio_err, "Error reading key\n"); ++ ERR_print_errors(bio_err); ++ goto end; ++ } ++ if (passin) ++ p8pass = passin; ++ else if (1) { ++#ifndef OPENSSL_NO_UI ++ p8pass = pass; ++ if (EVP_read_pw_string(pass, sizeof pass, "Enter Password:", 0)) { ++ BIO_printf(bio_err, "Can't read Password\n"); ++ goto end; ++ } ++ } else { ++#endif ++ BIO_printf(bio_err, "Password required\n"); ++ goto end; ++ } ++ p8inf = PKCS8_decrypt(p8, p8pass, strlen(p8pass)); ++ } ++ ++ if (!p8inf) { ++ BIO_printf(bio_err, "Error decrypting key\n"); ++ ERR_print_errors(bio_err); ++ goto end; ++ } ++ ++ if ((pkey = EVP_PKCS82PKEY(p8inf)) == NULL) { ++ BIO_printf(bio_err, "Error converting key\n"); ++ ERR_print_errors(bio_err); ++ goto end; ++ } ++ ++ assert(private); ++ if (outformat == FORMAT_PEM) { ++ if (traditional) ++ PEM_write_bio_PrivateKey_traditional(out, pkey, NULL, NULL, 0, ++ NULL, passout); ++ else ++ PEM_write_bio_PrivateKey(out, pkey, NULL, NULL, 0, NULL, passout); ++ } else if (outformat == FORMAT_ASN1) { ++ i2d_PrivateKey_bio(out, pkey); ++ } else { ++ BIO_printf(bio_err, "Bad format specified for key\n"); ++ goto end; ++ } ++ ret = 0; ++ ++ end: ++ X509_SIG_free(p8); ++ PKCS8_PRIV_KEY_INFO_free(p8inf); ++ EVP_PKEY_free(pkey); ++ release_engine(e); ++ BIO_free_all(out); ++ BIO_free(in); ++ OPENSSL_free(passin); ++ OPENSSL_free(passout); ++ ++ return ret; ++} +diff --git a/CryptoPkg/Library/OpensslLib/openssl/apps/pkey.c b/CryptoPkg/Library/OpensslLib/openssl/apps/pkey.c +new file mode 100644 +index 0000000..ad1a3b1 +--- /dev/null ++++ b/CryptoPkg/Library/OpensslLib/openssl/apps/pkey.c +@@ -0,0 +1,190 @@ ++/* ++ * Copyright 2006-2016 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 ++ * in the file LICENSE in the source distribution or at ++ * https://www.openssl.org/source/license.html ++ */ ++ ++#include ++#include ++#include "apps.h" ++#include ++#include ++#include ++ ++typedef enum OPTION_choice { ++ OPT_ERR = -1, OPT_EOF = 0, OPT_HELP, ++ OPT_INFORM, OPT_OUTFORM, OPT_PASSIN, OPT_PASSOUT, OPT_ENGINE, ++ OPT_IN, OPT_OUT, OPT_PUBIN, OPT_PUBOUT, OPT_TEXT_PUB, ++ OPT_TEXT, OPT_NOOUT, OPT_MD, OPT_TRADITIONAL ++} OPTION_CHOICE; ++ ++OPTIONS pkey_options[] = { ++ {"help", OPT_HELP, '-', "Display this summary"}, ++ {"inform", OPT_INFORM, 'f', "Input format (DER or PEM)"}, ++ {"outform", OPT_OUTFORM, 'F', "Output format (DER or PEM)"}, ++ {"passin", OPT_PASSIN, 's', "Input file pass phrase source"}, ++ {"passout", OPT_PASSOUT, 's', "Output file pass phrase source"}, ++ {"in", OPT_IN, 's', "Input key"}, ++ {"out", OPT_OUT, '>', "Output file"}, ++ {"pubin", OPT_PUBIN, '-', ++ "Read public key from input (default is private key)"}, ++ {"pubout", OPT_PUBOUT, '-', "Output public key, not private"}, ++ {"text_pub", OPT_TEXT_PUB, '-', "Only output public key components"}, ++ {"text", OPT_TEXT, '-', "Output in plaintext as well"}, ++ {"noout", OPT_NOOUT, '-', "Don't output the key"}, ++ {"", OPT_MD, '-', "Any supported cipher"}, ++ {"traditional", OPT_TRADITIONAL, '-', ++ "Use traditional format for private keys"}, ++#ifndef OPENSSL_NO_ENGINE ++ {"engine", OPT_ENGINE, 's', "Use engine, possibly a hardware device"}, ++#endif ++ {NULL} ++}; ++ ++int pkey_main(int argc, char **argv) ++{ ++ BIO *in = NULL, *out = NULL; ++ ENGINE *e = NULL; ++ EVP_PKEY *pkey = NULL; ++ const EVP_CIPHER *cipher = NULL; ++ char *infile = NULL, *outfile = NULL, *passin = NULL, *passout = NULL; ++ char *passinarg = NULL, *passoutarg = NULL, *prog; ++ OPTION_CHOICE o; ++ int informat = FORMAT_PEM, outformat = FORMAT_PEM; ++ int pubin = 0, pubout = 0, pubtext = 0, text = 0, noout = 0, ret = 1; ++ int private = 0, traditional = 0; ++ ++ prog = opt_init(argc, argv, pkey_options); ++ while ((o = opt_next()) != OPT_EOF) { ++ switch (o) { ++ case OPT_EOF: ++ case OPT_ERR: ++ opthelp: ++ BIO_printf(bio_err, "%s: Use -help for summary.\n", prog); ++ goto end; ++ case OPT_HELP: ++ opt_help(pkey_options); ++ ret = 0; ++ goto end; ++ case OPT_INFORM: ++ if (!opt_format(opt_arg(), OPT_FMT_ANY, &informat)) ++ goto opthelp; ++ break; ++ case OPT_OUTFORM: ++ if (!opt_format(opt_arg(), OPT_FMT_PEMDER, &outformat)) ++ goto opthelp; ++ break; ++ case OPT_PASSIN: ++ passinarg = opt_arg(); ++ break; ++ case OPT_PASSOUT: ++ passoutarg = opt_arg(); ++ break; ++ case OPT_ENGINE: ++ e = setup_engine(opt_arg(), 0); ++ break; ++ case OPT_IN: ++ infile = opt_arg(); ++ break; ++ case OPT_OUT: ++ outfile = opt_arg(); ++ break; ++ case OPT_PUBIN: ++ pubin = pubout = pubtext = 1; ++ break; ++ case OPT_PUBOUT: ++ pubout = 1; ++ break; ++ case OPT_TEXT_PUB: ++ pubtext = text = 1; ++ break; ++ case OPT_TEXT: ++ text = 1; ++ break; ++ case OPT_NOOUT: ++ noout = 1; ++ break; ++ case OPT_TRADITIONAL: ++ traditional = 1; ++ break; ++ case OPT_MD: ++ if (!opt_cipher(opt_unknown(), &cipher)) ++ goto opthelp; ++ } ++ } ++ argc = opt_num_rest(); ++ if (argc != 0) ++ goto opthelp; ++ ++ private = !noout && !pubout ? 1 : 0; ++ if (text && !pubtext) ++ private = 1; ++ ++ if (!app_passwd(passinarg, passoutarg, &passin, &passout)) { ++ BIO_printf(bio_err, "Error getting passwords\n"); ++ goto end; ++ } ++ ++ out = bio_open_owner(outfile, outformat, private); ++ if (out == NULL) ++ goto end; ++ ++ if (pubin) ++ pkey = load_pubkey(infile, informat, 1, passin, e, "Public Key"); ++ else ++ pkey = load_key(infile, informat, 1, passin, e, "key"); ++ if (!pkey) ++ goto end; ++ ++ if (!noout) { ++ if (outformat == FORMAT_PEM) { ++ if (pubout) ++ PEM_write_bio_PUBKEY(out, pkey); ++ else { ++ assert(private); ++ if (traditional) ++ PEM_write_bio_PrivateKey_traditional(out, pkey, cipher, ++ NULL, 0, NULL, ++ passout); ++ else ++ PEM_write_bio_PrivateKey(out, pkey, cipher, ++ NULL, 0, NULL, passout); ++ } ++ } else if (outformat == FORMAT_ASN1) { ++ if (pubout) ++ i2d_PUBKEY_bio(out, pkey); ++ else { ++ assert(private); ++ i2d_PrivateKey_bio(out, pkey); ++ } ++ } else { ++ BIO_printf(bio_err, "Bad format specified for key\n"); ++ goto end; ++ } ++ ++ } ++ ++ if (text) { ++ if (pubtext) ++ EVP_PKEY_print_public(out, pkey, 0, NULL); ++ else { ++ assert(private); ++ EVP_PKEY_print_private(out, pkey, 0, NULL); ++ } ++ } ++ ++ ret = 0; ++ ++ end: ++ EVP_PKEY_free(pkey); ++ release_engine(e); ++ BIO_free_all(out); ++ BIO_free(in); ++ OPENSSL_free(passin); ++ OPENSSL_free(passout); ++ ++ return ret; ++} +diff --git a/CryptoPkg/Library/OpensslLib/openssl/apps/pkeyparam.c b/CryptoPkg/Library/OpensslLib/openssl/apps/pkeyparam.c +new file mode 100644 +index 0000000..0a1b2d1 +--- /dev/null ++++ b/CryptoPkg/Library/OpensslLib/openssl/apps/pkeyparam.c +@@ -0,0 +1,104 @@ ++/* ++ * Copyright 2006-2016 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 ++ * in the file LICENSE in the source distribution or at ++ * https://www.openssl.org/source/license.html ++ */ ++ ++#include ++#include ++#include "apps.h" ++#include ++#include ++#include ++ ++typedef enum OPTION_choice { ++ OPT_ERR = -1, OPT_EOF = 0, OPT_HELP, ++ OPT_IN, OPT_OUT, OPT_TEXT, OPT_NOOUT, OPT_ENGINE ++} OPTION_CHOICE; ++ ++OPTIONS pkeyparam_options[] = { ++ {"help", OPT_HELP, '-', "Display this summary"}, ++ {"in", OPT_IN, '<', "Input file"}, ++ {"out", OPT_OUT, '>', "Output file"}, ++ {"text", OPT_TEXT, '-', "Print parameters as text"}, ++ {"noout", OPT_NOOUT, '-', "Don't output encoded parameters"}, ++#ifndef OPENSSL_NO_ENGINE ++ {"engine", OPT_ENGINE, 's', "Use engine, possibly a hardware device"}, ++#endif ++ {NULL} ++}; ++ ++int pkeyparam_main(int argc, char **argv) ++{ ++ ENGINE *e = NULL; ++ BIO *in = NULL, *out = NULL; ++ EVP_PKEY *pkey = NULL; ++ int text = 0, noout = 0, ret = 1; ++ OPTION_CHOICE o; ++ char *infile = NULL, *outfile = NULL, *prog; ++ ++ prog = opt_init(argc, argv, pkeyparam_options); ++ while ((o = opt_next()) != OPT_EOF) { ++ switch (o) { ++ case OPT_EOF: ++ case OPT_ERR: ++ opthelp: ++ BIO_printf(bio_err, "%s: Use -help for summary.\n", prog); ++ goto end; ++ case OPT_HELP: ++ opt_help(pkeyparam_options); ++ ret = 0; ++ goto end; ++ case OPT_IN: ++ infile = opt_arg(); ++ break; ++ case OPT_OUT: ++ outfile = opt_arg(); ++ break; ++ case OPT_ENGINE: ++ e = setup_engine(opt_arg(), 0); ++ break; ++ case OPT_TEXT: ++ text = 1; ++ break; ++ case OPT_NOOUT: ++ noout = 1; ++ break; ++ } ++ } ++ argc = opt_num_rest(); ++ if (argc != 0) ++ goto opthelp; ++ ++ in = bio_open_default(infile, 'r', FORMAT_PEM); ++ if (in == NULL) ++ goto end; ++ out = bio_open_default(outfile, 'w', FORMAT_PEM); ++ if (out == NULL) ++ goto end; ++ pkey = PEM_read_bio_Parameters(in, NULL); ++ if (!pkey) { ++ BIO_printf(bio_err, "Error reading parameters\n"); ++ ERR_print_errors(bio_err); ++ goto end; ++ } ++ ++ if (!noout) ++ PEM_write_bio_Parameters(out, pkey); ++ ++ if (text) ++ EVP_PKEY_print_params(out, pkey, 0, NULL); ++ ++ ret = 0; ++ ++ end: ++ EVP_PKEY_free(pkey); ++ release_engine(e); ++ BIO_free_all(out); ++ BIO_free(in); ++ ++ return ret; ++} +diff --git a/CryptoPkg/Library/OpensslLib/openssl/apps/pkeyutl.c b/CryptoPkg/Library/OpensslLib/openssl/apps/pkeyutl.c +new file mode 100644 +index 0000000..962a389 +--- /dev/null ++++ b/CryptoPkg/Library/OpensslLib/openssl/apps/pkeyutl.c +@@ -0,0 +1,489 @@ ++/* ++ * Copyright 2006-2016 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 ++ * in the file LICENSE in the source distribution or at ++ * https://www.openssl.org/source/license.html ++ */ ++ ++#include "apps.h" ++#include ++#include ++#include ++#include ++ ++#define KEY_NONE 0 ++#define KEY_PRIVKEY 1 ++#define KEY_PUBKEY 2 ++#define KEY_CERT 3 ++ ++static EVP_PKEY_CTX *init_ctx(const char *kdfalg, int *pkeysize, ++ const char *keyfile, int keyform, int key_type, ++ char *passinarg, int pkey_op, ENGINE *e, ++ const int impl); ++ ++static int setup_peer(EVP_PKEY_CTX *ctx, int peerform, const char *file, ++ ENGINE *e); ++ ++static int do_keyop(EVP_PKEY_CTX *ctx, int pkey_op, ++ unsigned char *out, size_t *poutlen, ++ const unsigned char *in, size_t inlen); ++ ++typedef enum OPTION_choice { ++ OPT_ERR = -1, OPT_EOF = 0, OPT_HELP, ++ OPT_ENGINE, OPT_ENGINE_IMPL, OPT_IN, OPT_OUT, ++ OPT_PUBIN, OPT_CERTIN, OPT_ASN1PARSE, OPT_HEXDUMP, OPT_SIGN, ++ OPT_VERIFY, OPT_VERIFYRECOVER, OPT_REV, OPT_ENCRYPT, OPT_DECRYPT, ++ OPT_DERIVE, OPT_SIGFILE, OPT_INKEY, OPT_PEERKEY, OPT_PASSIN, ++ OPT_PEERFORM, OPT_KEYFORM, OPT_PKEYOPT, OPT_KDF, OPT_KDFLEN ++} OPTION_CHOICE; ++ ++OPTIONS pkeyutl_options[] = { ++ {"help", OPT_HELP, '-', "Display this summary"}, ++ {"in", OPT_IN, '<', "Input file - default stdin"}, ++ {"out", OPT_OUT, '>', "Output file - default stdout"}, ++ {"pubin", OPT_PUBIN, '-', "Input is a public key"}, ++ {"certin", OPT_CERTIN, '-', "Input is a cert with a public key"}, ++ {"asn1parse", OPT_ASN1PARSE, '-', "asn1parse the output data"}, ++ {"hexdump", OPT_HEXDUMP, '-', "Hex dump output"}, ++ {"sign", OPT_SIGN, '-', "Sign input data with private key"}, ++ {"verify", OPT_VERIFY, '-', "Verify with public key"}, ++ {"verifyrecover", OPT_VERIFYRECOVER, '-', ++ "Verify with public key, recover original data"}, ++ {"rev", OPT_REV, '-', "Reverse the order of the input buffer"}, ++ {"encrypt", OPT_ENCRYPT, '-', "Encrypt input data with public key"}, ++ {"decrypt", OPT_DECRYPT, '-', "Decrypt input data with private key"}, ++ {"derive", OPT_DERIVE, '-', "Derive shared secret"}, ++ {"kdf", OPT_KDF, 's', "Use KDF algorithm"}, ++ {"kdflen", OPT_KDFLEN, 'p', "KDF algorithm output length"}, ++ {"sigfile", OPT_SIGFILE, '<', "Signature file (verify operation only)"}, ++ {"inkey", OPT_INKEY, 's', "Input private key file"}, ++ {"peerkey", OPT_PEERKEY, 's', "Peer key file used in key derivation"}, ++ {"passin", OPT_PASSIN, 's', "Input file pass phrase source"}, ++ {"peerform", OPT_PEERFORM, 'E', "Peer key format - default PEM"}, ++ {"keyform", OPT_KEYFORM, 'E', "Private key format - default PEM"}, ++ {"pkeyopt", OPT_PKEYOPT, 's', "Public key options as opt:value"}, ++#ifndef OPENSSL_NO_ENGINE ++ {"engine", OPT_ENGINE, 's', "Use engine, possibly a hardware device"}, ++ {"engine_impl", OPT_ENGINE_IMPL, '-', ++ "Also use engine given by -engine for crypto operations"}, ++#endif ++ {NULL} ++}; ++ ++int pkeyutl_main(int argc, char **argv) ++{ ++ BIO *in = NULL, *out = NULL; ++ ENGINE *e = NULL; ++ EVP_PKEY_CTX *ctx = NULL; ++ char *infile = NULL, *outfile = NULL, *sigfile = NULL, *passinarg = NULL; ++ char hexdump = 0, asn1parse = 0, rev = 0, *prog; ++ unsigned char *buf_in = NULL, *buf_out = NULL, *sig = NULL; ++ OPTION_CHOICE o; ++ int buf_inlen = 0, siglen = -1, keyform = FORMAT_PEM, peerform = ++ FORMAT_PEM; ++ int keysize = -1, pkey_op = EVP_PKEY_OP_SIGN, key_type = KEY_PRIVKEY; ++ int engine_impl = 0; ++ int ret = 1, rv = -1; ++ size_t buf_outlen; ++ const char *inkey = NULL; ++ const char *peerkey = NULL; ++ const char *kdfalg = NULL; ++ int kdflen = 0; ++ STACK_OF(OPENSSL_STRING) *pkeyopts = NULL; ++ ++ prog = opt_init(argc, argv, pkeyutl_options); ++ while ((o = opt_next()) != OPT_EOF) { ++ switch (o) { ++ case OPT_EOF: ++ case OPT_ERR: ++ opthelp: ++ BIO_printf(bio_err, "%s: Use -help for summary.\n", prog); ++ goto end; ++ case OPT_HELP: ++ opt_help(pkeyutl_options); ++ ret = 0; ++ goto end; ++ case OPT_IN: ++ infile = opt_arg(); ++ break; ++ case OPT_OUT: ++ outfile = opt_arg(); ++ break; ++ case OPT_SIGFILE: ++ sigfile = opt_arg(); ++ break; ++ case OPT_ENGINE_IMPL: ++ engine_impl = 1; ++ break; ++ case OPT_INKEY: ++ inkey = opt_arg(); ++ break; ++ case OPT_PEERKEY: ++ peerkey = opt_arg(); ++ break; ++ case OPT_PASSIN: ++ passinarg = opt_arg(); ++ break; ++ case OPT_PEERFORM: ++ if (!opt_format(opt_arg(), OPT_FMT_PDE, &peerform)) ++ goto opthelp; ++ break; ++ case OPT_KEYFORM: ++ if (!opt_format(opt_arg(), OPT_FMT_PDE, &keyform)) ++ goto opthelp; ++ break; ++ case OPT_ENGINE: ++ e = setup_engine(opt_arg(), 0); ++ break; ++ case OPT_PUBIN: ++ key_type = KEY_PUBKEY; ++ break; ++ case OPT_CERTIN: ++ key_type = KEY_CERT; ++ break; ++ case OPT_ASN1PARSE: ++ asn1parse = 1; ++ break; ++ case OPT_HEXDUMP: ++ hexdump = 1; ++ break; ++ case OPT_SIGN: ++ pkey_op = EVP_PKEY_OP_SIGN; ++ break; ++ case OPT_VERIFY: ++ pkey_op = EVP_PKEY_OP_VERIFY; ++ break; ++ case OPT_VERIFYRECOVER: ++ pkey_op = EVP_PKEY_OP_VERIFYRECOVER; ++ break; ++ case OPT_ENCRYPT: ++ pkey_op = EVP_PKEY_OP_ENCRYPT; ++ break; ++ case OPT_DECRYPT: ++ pkey_op = EVP_PKEY_OP_DECRYPT; ++ break; ++ case OPT_DERIVE: ++ pkey_op = EVP_PKEY_OP_DERIVE; ++ break; ++ case OPT_KDF: ++ pkey_op = EVP_PKEY_OP_DERIVE; ++ key_type = KEY_NONE; ++ kdfalg = opt_arg(); ++ break; ++ case OPT_KDFLEN: ++ kdflen = atoi(opt_arg()); ++ break; ++ case OPT_REV: ++ rev = 1; ++ break; ++ case OPT_PKEYOPT: ++ if ((pkeyopts == NULL && ++ (pkeyopts = sk_OPENSSL_STRING_new_null()) == NULL) || ++ sk_OPENSSL_STRING_push(pkeyopts, opt_arg()) == 0) { ++ BIO_puts(bio_err, "out of memory\n"); ++ goto end; ++ } ++ break; ++ } ++ } ++ argc = opt_num_rest(); ++ if (argc != 0) ++ goto opthelp; ++ ++ if (kdfalg != NULL) { ++ if (kdflen == 0) ++ goto opthelp; ++ } else if ((inkey == NULL) ++ || (peerkey != NULL && pkey_op != EVP_PKEY_OP_DERIVE)) { ++ goto opthelp; ++ } ++ ctx = init_ctx(kdfalg, &keysize, inkey, keyform, key_type, ++ passinarg, pkey_op, e, engine_impl); ++ if (ctx == NULL) { ++ BIO_printf(bio_err, "%s: Error initializing context\n", prog); ++ ERR_print_errors(bio_err); ++ goto end; ++ } ++ if (peerkey != NULL && !setup_peer(ctx, peerform, peerkey, e)) { ++ BIO_printf(bio_err, "%s: Error setting up peer key\n", prog); ++ ERR_print_errors(bio_err); ++ goto end; ++ } ++ if (pkeyopts != NULL) { ++ int num = sk_OPENSSL_STRING_num(pkeyopts); ++ int i; ++ ++ for (i = 0; i < num; ++i) { ++ const char *opt = sk_OPENSSL_STRING_value(pkeyopts, i); ++ ++ if (pkey_ctrl_string(ctx, opt) <= 0) { ++ BIO_printf(bio_err, "%s: Can't set parameter:\n", prog); ++ ERR_print_errors(bio_err); ++ goto end; ++ } ++ } ++ } ++ ++ if (sigfile && (pkey_op != EVP_PKEY_OP_VERIFY)) { ++ BIO_printf(bio_err, ++ "%s: Signature file specified for non verify\n", prog); ++ goto end; ++ } ++ ++ if (!sigfile && (pkey_op == EVP_PKEY_OP_VERIFY)) { ++ BIO_printf(bio_err, ++ "%s: No signature file specified for verify\n", prog); ++ goto end; ++ } ++ ++/* FIXME: seed PRNG only if needed */ ++ app_RAND_load_file(NULL, 0); ++ ++ if (pkey_op != EVP_PKEY_OP_DERIVE) { ++ in = bio_open_default(infile, 'r', FORMAT_BINARY); ++ if (in == NULL) ++ goto end; ++ } ++ out = bio_open_default(outfile, 'w', FORMAT_BINARY); ++ if (out == NULL) ++ goto end; ++ ++ if (sigfile) { ++ BIO *sigbio = BIO_new_file(sigfile, "rb"); ++ if (!sigbio) { ++ BIO_printf(bio_err, "Can't open signature file %s\n", sigfile); ++ goto end; ++ } ++ siglen = bio_to_mem(&sig, keysize * 10, sigbio); ++ BIO_free(sigbio); ++ if (siglen < 0) { ++ BIO_printf(bio_err, "Error reading signature data\n"); ++ goto end; ++ } ++ } ++ ++ if (in) { ++ /* Read the input data */ ++ buf_inlen = bio_to_mem(&buf_in, keysize * 10, in); ++ if (buf_inlen < 0) { ++ BIO_printf(bio_err, "Error reading input Data\n"); ++ exit(1); ++ } ++ if (rev) { ++ size_t i; ++ unsigned char ctmp; ++ size_t l = (size_t)buf_inlen; ++ for (i = 0; i < l / 2; i++) { ++ ctmp = buf_in[i]; ++ buf_in[i] = buf_in[l - 1 - i]; ++ buf_in[l - 1 - i] = ctmp; ++ } ++ } ++ } ++ ++ if (pkey_op == EVP_PKEY_OP_VERIFY) { ++ rv = EVP_PKEY_verify(ctx, sig, (size_t)siglen, ++ buf_in, (size_t)buf_inlen); ++ if (rv == 1) { ++ BIO_puts(out, "Signature Verified Successfully\n"); ++ ret = 0; ++ } else ++ BIO_puts(out, "Signature Verification Failure\n"); ++ goto end; ++ } ++ if (kdflen != 0) { ++ buf_outlen = kdflen; ++ rv = 1; ++ } else { ++ rv = do_keyop(ctx, pkey_op, NULL, (size_t *)&buf_outlen, ++ buf_in, (size_t)buf_inlen); ++ } ++ if (rv > 0 && buf_outlen != 0) { ++ buf_out = app_malloc(buf_outlen, "buffer output"); ++ rv = do_keyop(ctx, pkey_op, ++ buf_out, (size_t *)&buf_outlen, ++ buf_in, (size_t)buf_inlen); ++ } ++ if (rv <= 0) { ++ BIO_puts(bio_err, "Public Key operation error\n"); ++ ERR_print_errors(bio_err); ++ goto end; ++ } ++ ret = 0; ++ ++ if (asn1parse) { ++ if (!ASN1_parse_dump(out, buf_out, buf_outlen, 1, -1)) ++ ERR_print_errors(bio_err); ++ } else if (hexdump) ++ BIO_dump(out, (char *)buf_out, buf_outlen); ++ else ++ BIO_write(out, buf_out, buf_outlen); ++ ++ end: ++ EVP_PKEY_CTX_free(ctx); ++ release_engine(e); ++ BIO_free(in); ++ BIO_free_all(out); ++ OPENSSL_free(buf_in); ++ OPENSSL_free(buf_out); ++ OPENSSL_free(sig); ++ sk_OPENSSL_STRING_free(pkeyopts); ++ return ret; ++} ++ ++static EVP_PKEY_CTX *init_ctx(const char *kdfalg, int *pkeysize, ++ const char *keyfile, int keyform, int key_type, ++ char *passinarg, int pkey_op, ENGINE *e, ++ const int engine_impl) ++{ ++ EVP_PKEY *pkey = NULL; ++ EVP_PKEY_CTX *ctx = NULL; ++ ENGINE *impl = NULL; ++ char *passin = NULL; ++ int rv = -1; ++ X509 *x; ++ if (((pkey_op == EVP_PKEY_OP_SIGN) || (pkey_op == EVP_PKEY_OP_DECRYPT) ++ || (pkey_op == EVP_PKEY_OP_DERIVE)) ++ && (key_type != KEY_PRIVKEY && kdfalg == NULL)) { ++ BIO_printf(bio_err, "A private key is needed for this operation\n"); ++ goto end; ++ } ++ if (!app_passwd(passinarg, NULL, &passin, NULL)) { ++ BIO_printf(bio_err, "Error getting password\n"); ++ goto end; ++ } ++ switch (key_type) { ++ case KEY_PRIVKEY: ++ pkey = load_key(keyfile, keyform, 0, passin, e, "Private Key"); ++ break; ++ ++ case KEY_PUBKEY: ++ pkey = load_pubkey(keyfile, keyform, 0, NULL, e, "Public Key"); ++ break; ++ ++ case KEY_CERT: ++ x = load_cert(keyfile, keyform, "Certificate"); ++ if (x) { ++ pkey = X509_get_pubkey(x); ++ X509_free(x); ++ } ++ break; ++ ++ case KEY_NONE: ++ break; ++ ++ } ++ ++#ifndef OPENSSL_NO_ENGINE ++ if (engine_impl) ++ impl = e; ++#endif ++ ++ if (kdfalg) { ++ int kdfnid = OBJ_sn2nid(kdfalg); ++ if (kdfnid == NID_undef) ++ goto end; ++ ctx = EVP_PKEY_CTX_new_id(kdfnid, impl); ++ } else { ++ if (pkey == NULL) ++ goto end; ++ *pkeysize = EVP_PKEY_size(pkey); ++ ctx = EVP_PKEY_CTX_new(pkey, impl); ++ EVP_PKEY_free(pkey); ++ } ++ ++ if (ctx == NULL) ++ goto end; ++ ++ switch (pkey_op) { ++ case EVP_PKEY_OP_SIGN: ++ rv = EVP_PKEY_sign_init(ctx); ++ break; ++ ++ case EVP_PKEY_OP_VERIFY: ++ rv = EVP_PKEY_verify_init(ctx); ++ break; ++ ++ case EVP_PKEY_OP_VERIFYRECOVER: ++ rv = EVP_PKEY_verify_recover_init(ctx); ++ break; ++ ++ case EVP_PKEY_OP_ENCRYPT: ++ rv = EVP_PKEY_encrypt_init(ctx); ++ break; ++ ++ case EVP_PKEY_OP_DECRYPT: ++ rv = EVP_PKEY_decrypt_init(ctx); ++ break; ++ ++ case EVP_PKEY_OP_DERIVE: ++ rv = EVP_PKEY_derive_init(ctx); ++ break; ++ } ++ ++ if (rv <= 0) { ++ EVP_PKEY_CTX_free(ctx); ++ ctx = NULL; ++ } ++ ++ end: ++ OPENSSL_free(passin); ++ return ctx; ++ ++} ++ ++static int setup_peer(EVP_PKEY_CTX *ctx, int peerform, const char *file, ++ ENGINE* e) ++{ ++ EVP_PKEY *peer = NULL; ++ ENGINE* engine = NULL; ++ int ret; ++ ++ if (peerform == FORMAT_ENGINE) ++ engine = e; ++ peer = load_pubkey(file, peerform, 0, NULL, engine, "Peer Key"); ++ if (!peer) { ++ BIO_printf(bio_err, "Error reading peer key %s\n", file); ++ ERR_print_errors(bio_err); ++ return 0; ++ } ++ ++ ret = EVP_PKEY_derive_set_peer(ctx, peer); ++ ++ EVP_PKEY_free(peer); ++ if (ret <= 0) ++ ERR_print_errors(bio_err); ++ return ret; ++} ++ ++static int do_keyop(EVP_PKEY_CTX *ctx, int pkey_op, ++ unsigned char *out, size_t *poutlen, ++ const unsigned char *in, size_t inlen) ++{ ++ int rv = 0; ++ switch (pkey_op) { ++ case EVP_PKEY_OP_VERIFYRECOVER: ++ rv = EVP_PKEY_verify_recover(ctx, out, poutlen, in, inlen); ++ break; ++ ++ case EVP_PKEY_OP_SIGN: ++ rv = EVP_PKEY_sign(ctx, out, poutlen, in, inlen); ++ break; ++ ++ case EVP_PKEY_OP_ENCRYPT: ++ rv = EVP_PKEY_encrypt(ctx, out, poutlen, in, inlen); ++ break; ++ ++ case EVP_PKEY_OP_DECRYPT: ++ rv = EVP_PKEY_decrypt(ctx, out, poutlen, in, inlen); ++ break; ++ ++ case EVP_PKEY_OP_DERIVE: ++ rv = EVP_PKEY_derive(ctx, out, poutlen); ++ break; ++ ++ } ++ return rv; ++} +diff --git a/CryptoPkg/Library/OpensslLib/openssl/apps/prime.c b/CryptoPkg/Library/OpensslLib/openssl/apps/prime.c +new file mode 100644 +index 0000000..b0f5969 +--- /dev/null ++++ b/CryptoPkg/Library/OpensslLib/openssl/apps/prime.c +@@ -0,0 +1,126 @@ ++/* ++ * Copyright 2004-2016 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 ++ * in the file LICENSE in the source distribution or at ++ * https://www.openssl.org/source/license.html ++ */ ++ ++#include ++ ++#include "apps.h" ++#include ++ ++typedef enum OPTION_choice { ++ OPT_ERR = -1, OPT_EOF = 0, OPT_HELP, ++ OPT_HEX, OPT_GENERATE, OPT_BITS, OPT_SAFE, OPT_CHECKS ++} OPTION_CHOICE; ++ ++OPTIONS prime_options[] = { ++ {OPT_HELP_STR, 1, '-', "Usage: %s [options] [number...]\n"}, ++ {OPT_HELP_STR, 1, '-', ++ " number Number to check for primality\n"}, ++ {"help", OPT_HELP, '-', "Display this summary"}, ++ {"hex", OPT_HEX, '-', "Hex output"}, ++ {"generate", OPT_GENERATE, '-', "Generate a prime"}, ++ {"bits", OPT_BITS, 'p', "Size of number in bits"}, ++ {"safe", OPT_SAFE, '-', ++ "When used with -generate, generate a safe prime"}, ++ {"checks", OPT_CHECKS, 'p', "Number of checks"}, ++ {NULL} ++}; ++ ++int prime_main(int argc, char **argv) ++{ ++ BIGNUM *bn = NULL; ++ int hex = 0, checks = 20, generate = 0, bits = 0, safe = 0, ret = 1; ++ char *prog; ++ OPTION_CHOICE o; ++ ++ prog = opt_init(argc, argv, prime_options); ++ while ((o = opt_next()) != OPT_EOF) { ++ switch (o) { ++ case OPT_EOF: ++ case OPT_ERR: ++ BIO_printf(bio_err, "%s: Use -help for summary.\n", prog); ++ goto end; ++ case OPT_HELP: ++ opt_help(prime_options); ++ ret = 0; ++ goto end; ++ case OPT_HEX: ++ hex = 1; ++ break; ++ case OPT_GENERATE: ++ generate = 1; ++ break; ++ case OPT_BITS: ++ bits = atoi(opt_arg()); ++ break; ++ case OPT_SAFE: ++ safe = 1; ++ break; ++ case OPT_CHECKS: ++ checks = atoi(opt_arg()); ++ break; ++ } ++ } ++ argc = opt_num_rest(); ++ argv = opt_rest(); ++ ++ if (argc == 0 && !generate) { ++ BIO_printf(bio_err, "%s: No prime specified\n", prog); ++ goto end; ++ } ++ ++ if (generate) { ++ char *s; ++ ++ if (!bits) { ++ BIO_printf(bio_err, "Specify the number of bits.\n"); ++ goto end; ++ } ++ bn = BN_new(); ++ if (bn == NULL) { ++ BIO_printf(bio_err, "Out of memory.\n"); ++ goto end; ++ } ++ if (!BN_generate_prime_ex(bn, bits, safe, NULL, NULL, NULL)) { ++ BIO_printf(bio_err, "Failed to generate prime.\n"); ++ goto end; ++ } ++ s = hex ? BN_bn2hex(bn) : BN_bn2dec(bn); ++ if (s == NULL) { ++ BIO_printf(bio_err, "Out of memory.\n"); ++ goto end; ++ } ++ BIO_printf(bio_out, "%s\n", s); ++ OPENSSL_free(s); ++ } else { ++ for ( ; *argv; argv++) { ++ int r; ++ ++ if (hex) ++ r = BN_hex2bn(&bn, argv[0]); ++ else ++ r = BN_dec2bn(&bn, argv[0]); ++ ++ if(!r) { ++ BIO_printf(bio_err, "Failed to process value (%s)\n", argv[0]); ++ goto end; ++ } ++ ++ BN_print(bio_out, bn); ++ BIO_printf(bio_out, " (%s) %s prime\n", ++ argv[0], ++ BN_is_prime_ex(bn, checks, NULL, NULL) ++ ? "is" : "is not"); ++ } ++ } ++ ++ ret = 0; ++ end: ++ BN_free(bn); ++ return ret; ++} +diff --git a/CryptoPkg/Library/OpensslLib/openssl/apps/privkey.pem b/CryptoPkg/Library/OpensslLib/openssl/apps/privkey.pem +new file mode 100644 +index 0000000..02f3498 +--- /dev/null ++++ b/CryptoPkg/Library/OpensslLib/openssl/apps/privkey.pem +@@ -0,0 +1,16 @@ ++-----BEGIN PRIVATE KEY----- ++MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBAMo7DFNMqywUA1O/ ++qvWqCOm6rGrUAcR+dKsSXw6y2qiKO7APDDyotc0b4Mxwqjga98npex2RBIwUoCGJ ++iEmMXo/a8RbXVUZ+ZwcAX7PC+XeXVC5qoajaBBkd2MvYmib/2PqnNrgvhHsUL5dO ++xhC7cRqxLM/g45k3Yyw+nGa+WkTdAgMBAAECgYBMBT5w4dVG0I8foGFnz+9hzWab ++Ee9IKjE5TcKmB93ilXQyjrWO5+zPmbc7ou6aAKk9IaPCTY1kCyzW7pho7Xdt+RFq ++TgVXGZZfqtixO7f2/5oqZAkd00eOn9ZrhBpVMu4yXbbDvhDyFe4/oy0HGDjRUhxa ++Lf6ZlBuTherxm4eFkQJBAPBQwRs9UtqaMAQlagA9pV5UsQjV1WT4IxDURMPfXgCd ++ETNkB6pP0SmxQm5xhv9N2HY1UtoWpug9s0OU5IJB15sCQQDXbfbjiujNbuOxCFNw ++68JZaCFVdNovyOWORkpenQLNEjVkmTCS9OayK09ADEYtsdpUGKeF+2EYBNkFr5px ++CajnAkBMYI4PNz1HBuwt1SpMa0tMoMQnV7bbwVV7usskKbC5pzHZUHhzM6z5gEHp ++0iEisT4Ty7zKXZqsgzefSgoaMAzzAkEAoCIaUhtwXzwdPfvNYnOs3J6doJMimECB +++lbfcyLM8TimvadtRt+KGEg/OYGmLNM2UiqdY+duzdbUpvhYGcwvYwJAQvaoi9z2 ++CkiwSs/PFrLaNlfLJmXRsUBzmiWYoh6+IQJJorEXz7ewI72ee9RBO4s746cgUFwH ++Ri+qO+HhZFUBqQ== ++-----END PRIVATE KEY----- +diff --git a/CryptoPkg/Library/OpensslLib/openssl/apps/progs.h b/CryptoPkg/Library/OpensslLib/openssl/apps/progs.h +new file mode 100644 +index 0000000..72d93ba +--- /dev/null ++++ b/CryptoPkg/Library/OpensslLib/openssl/apps/progs.h +@@ -0,0 +1,415 @@ ++/* ++ * WARNING: do not edit! ++ * Generated by apps/progs.pl ++ * ++ * Copyright 1995-2016 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 ++ * in the file LICENSE in the source distribution or at ++ * https://www.openssl.org/source/license.html ++ */ ++ ++typedef enum FUNC_TYPE { ++ FT_none, FT_general, FT_md, FT_cipher, FT_pkey, ++ FT_md_alg, FT_cipher_alg ++} FUNC_TYPE; ++ ++typedef struct function_st { ++ FUNC_TYPE type; ++ const char *name; ++ int (*func)(int argc, char *argv[]); ++ const OPTIONS *help; ++} FUNCTION; ++ ++DEFINE_LHASH_OF(FUNCTION); ++ ++extern int asn1parse_main(int argc, char *argv[]); ++extern int ca_main(int argc, char *argv[]); ++extern int ciphers_main(int argc, char *argv[]); ++extern int cms_main(int argc, char *argv[]); ++extern int crl_main(int argc, char *argv[]); ++extern int crl2pkcs7_main(int argc, char *argv[]); ++extern int dgst_main(int argc, char *argv[]); ++extern int dhparam_main(int argc, char *argv[]); ++extern int dsa_main(int argc, char *argv[]); ++extern int dsaparam_main(int argc, char *argv[]); ++extern int ec_main(int argc, char *argv[]); ++extern int ecparam_main(int argc, char *argv[]); ++extern int enc_main(int argc, char *argv[]); ++extern int engine_main(int argc, char *argv[]); ++extern int errstr_main(int argc, char *argv[]); ++extern int exit_main(int argc, char *argv[]); ++extern int gendsa_main(int argc, char *argv[]); ++extern int genpkey_main(int argc, char *argv[]); ++extern int genrsa_main(int argc, char *argv[]); ++extern int help_main(int argc, char *argv[]); ++extern int list_main(int argc, char *argv[]); ++extern int nseq_main(int argc, char *argv[]); ++extern int ocsp_main(int argc, char *argv[]); ++extern int passwd_main(int argc, char *argv[]); ++extern int pkcs12_main(int argc, char *argv[]); ++extern int pkcs7_main(int argc, char *argv[]); ++extern int pkcs8_main(int argc, char *argv[]); ++extern int pkey_main(int argc, char *argv[]); ++extern int pkeyparam_main(int argc, char *argv[]); ++extern int pkeyutl_main(int argc, char *argv[]); ++extern int prime_main(int argc, char *argv[]); ++extern int rand_main(int argc, char *argv[]); ++extern int rehash_main(int argc, char *argv[]); ++extern int req_main(int argc, char *argv[]); ++extern int rsa_main(int argc, char *argv[]); ++extern int rsautl_main(int argc, char *argv[]); ++extern int s_client_main(int argc, char *argv[]); ++extern int s_server_main(int argc, char *argv[]); ++extern int s_time_main(int argc, char *argv[]); ++extern int sess_id_main(int argc, char *argv[]); ++extern int smime_main(int argc, char *argv[]); ++extern int speed_main(int argc, char *argv[]); ++extern int spkac_main(int argc, char *argv[]); ++extern int srp_main(int argc, char *argv[]); ++extern int ts_main(int argc, char *argv[]); ++extern int verify_main(int argc, char *argv[]); ++extern int version_main(int argc, char *argv[]); ++extern int x509_main(int argc, char *argv[]); ++ ++extern OPTIONS asn1parse_options[]; ++extern OPTIONS ca_options[]; ++extern OPTIONS ciphers_options[]; ++extern OPTIONS cms_options[]; ++extern OPTIONS crl_options[]; ++extern OPTIONS crl2pkcs7_options[]; ++extern OPTIONS dgst_options[]; ++extern OPTIONS dhparam_options[]; ++extern OPTIONS dsa_options[]; ++extern OPTIONS dsaparam_options[]; ++extern OPTIONS ec_options[]; ++extern OPTIONS ecparam_options[]; ++extern OPTIONS enc_options[]; ++extern OPTIONS engine_options[]; ++extern OPTIONS errstr_options[]; ++extern OPTIONS exit_options[]; ++extern OPTIONS gendsa_options[]; ++extern OPTIONS genpkey_options[]; ++extern OPTIONS genrsa_options[]; ++extern OPTIONS help_options[]; ++extern OPTIONS list_options[]; ++extern OPTIONS nseq_options[]; ++extern OPTIONS ocsp_options[]; ++extern OPTIONS passwd_options[]; ++extern OPTIONS pkcs12_options[]; ++extern OPTIONS pkcs7_options[]; ++extern OPTIONS pkcs8_options[]; ++extern OPTIONS pkey_options[]; ++extern OPTIONS pkeyparam_options[]; ++extern OPTIONS pkeyutl_options[]; ++extern OPTIONS prime_options[]; ++extern OPTIONS rand_options[]; ++extern OPTIONS rehash_options[]; ++extern OPTIONS req_options[]; ++extern OPTIONS rsa_options[]; ++extern OPTIONS rsautl_options[]; ++extern OPTIONS s_client_options[]; ++extern OPTIONS s_server_options[]; ++extern OPTIONS s_time_options[]; ++extern OPTIONS sess_id_options[]; ++extern OPTIONS smime_options[]; ++extern OPTIONS speed_options[]; ++extern OPTIONS spkac_options[]; ++extern OPTIONS srp_options[]; ++extern OPTIONS ts_options[]; ++extern OPTIONS verify_options[]; ++extern OPTIONS version_options[]; ++extern OPTIONS x509_options[]; ++ ++#ifdef INCLUDE_FUNCTION_TABLE ++static FUNCTION functions[] = { ++ { FT_general, "asn1parse", asn1parse_main, asn1parse_options }, ++ { FT_general, "ca", ca_main, ca_options }, ++#ifndef OPENSSL_NO_SOCK ++ { FT_general, "ciphers", ciphers_main, ciphers_options }, ++#endif ++#ifndef OPENSSL_NO_CMS ++ { FT_general, "cms", cms_main, cms_options }, ++#endif ++ { FT_general, "crl", crl_main, crl_options }, ++ { FT_general, "crl2pkcs7", crl2pkcs7_main, crl2pkcs7_options }, ++ { FT_general, "dgst", dgst_main, dgst_options }, ++#ifndef OPENSSL_NO_DH ++ { FT_general, "dhparam", dhparam_main, dhparam_options }, ++#endif ++#ifndef OPENSSL_NO_DSA ++ { FT_general, "dsa", dsa_main, dsa_options }, ++#endif ++#ifndef OPENSSL_NO_DSA ++ { FT_general, "dsaparam", dsaparam_main, dsaparam_options }, ++#endif ++#ifndef OPENSSL_NO_EC ++ { FT_general, "ec", ec_main, ec_options }, ++#endif ++#ifndef OPENSSL_NO_EC ++ { FT_general, "ecparam", ecparam_main, ecparam_options }, ++#endif ++ { FT_general, "enc", enc_main, enc_options }, ++#ifndef OPENSSL_NO_ENGINE ++ { FT_general, "engine", engine_main, engine_options }, ++#endif ++ { FT_general, "errstr", errstr_main, errstr_options }, ++ { FT_general, "exit", exit_main, exit_options }, ++#ifndef OPENSSL_NO_DSA ++ { FT_general, "gendsa", gendsa_main, gendsa_options }, ++#endif ++ { FT_general, "genpkey", genpkey_main, genpkey_options }, ++#ifndef OPENSSL_NO_RSA ++ { FT_general, "genrsa", genrsa_main, genrsa_options }, ++#endif ++ { FT_general, "help", help_main, help_options }, ++ { FT_general, "list", list_main, list_options }, ++ { FT_general, "nseq", nseq_main, nseq_options }, ++#ifndef OPENSSL_NO_OCSP ++ { FT_general, "ocsp", ocsp_main, ocsp_options }, ++#endif ++ { FT_general, "passwd", passwd_main, passwd_options }, ++#ifndef OPENSSL_NO_DES ++ { FT_general, "pkcs12", pkcs12_main, pkcs12_options }, ++#endif ++ { FT_general, "pkcs7", pkcs7_main, pkcs7_options }, ++ { FT_general, "pkcs8", pkcs8_main, pkcs8_options }, ++ { FT_general, "pkey", pkey_main, pkey_options }, ++ { FT_general, "pkeyparam", pkeyparam_main, pkeyparam_options }, ++ { FT_general, "pkeyutl", pkeyutl_main, pkeyutl_options }, ++ { FT_general, "prime", prime_main, prime_options }, ++ { FT_general, "rand", rand_main, rand_options }, ++ { FT_general, "rehash", rehash_main, rehash_options }, ++ { FT_general, "req", req_main, req_options }, ++ { FT_general, "rsa", rsa_main, rsa_options }, ++#ifndef OPENSSL_NO_RSA ++ { FT_general, "rsautl", rsautl_main, rsautl_options }, ++#endif ++#ifndef OPENSSL_NO_SOCK ++ { FT_general, "s_client", s_client_main, s_client_options }, ++#endif ++#ifndef OPENSSL_NO_SOCK ++ { FT_general, "s_server", s_server_main, s_server_options }, ++#endif ++#ifndef OPENSSL_NO_SOCK ++ { FT_general, "s_time", s_time_main, s_time_options }, ++#endif ++ { FT_general, "sess_id", sess_id_main, sess_id_options }, ++ { FT_general, "smime", smime_main, smime_options }, ++ { FT_general, "speed", speed_main, speed_options }, ++ { FT_general, "spkac", spkac_main, spkac_options }, ++#ifndef OPENSSL_NO_TS ++ { FT_general, "ts", ts_main, ts_options }, ++#endif ++ { FT_general, "verify", verify_main, verify_options }, ++ { FT_general, "version", version_main, version_options }, ++ { FT_general, "x509", x509_main, x509_options }, ++#ifndef OPENSSL_NO_MD2 ++ { FT_md, "md2", dgst_main}, ++#endif ++#ifndef OPENSSL_NO_MD4 ++ { FT_md, "md4", dgst_main}, ++#endif ++ { FT_md, "md5", dgst_main}, ++#ifndef OPENSSL_NO_GOST ++ { FT_md, "gost", dgst_main}, ++#endif ++ { FT_md, "sha1", dgst_main}, ++ { FT_md, "sha224", dgst_main}, ++ { FT_md, "sha256", dgst_main}, ++ { FT_md, "sha384", dgst_main}, ++ { FT_md, "sha512", dgst_main}, ++#ifndef OPENSSL_NO_MDC2 ++ { FT_md, "mdc2", dgst_main}, ++#endif ++#ifndef OPENSSL_NO_RMD160 ++ { FT_md, "rmd160", dgst_main}, ++#endif ++#ifndef OPENSSL_NO_BLAKE2 ++ { FT_md, "blake2b512", dgst_main}, ++#endif ++#ifndef OPENSSL_NO_BLAKE2 ++ { FT_md, "blake2s256", dgst_main}, ++#endif ++ { FT_cipher, "aes-128-cbc", enc_main, enc_options }, ++ { FT_cipher, "aes-128-ecb", enc_main, enc_options }, ++ { FT_cipher, "aes-192-cbc", enc_main, enc_options }, ++ { FT_cipher, "aes-192-ecb", enc_main, enc_options }, ++ { FT_cipher, "aes-256-cbc", enc_main, enc_options }, ++ { FT_cipher, "aes-256-ecb", enc_main, enc_options }, ++#ifndef OPENSSL_NO_CAMELLIA ++ { FT_cipher, "camellia-128-cbc", enc_main, enc_options }, ++#endif ++#ifndef OPENSSL_NO_CAMELLIA ++ { FT_cipher, "camellia-128-ecb", enc_main, enc_options }, ++#endif ++#ifndef OPENSSL_NO_CAMELLIA ++ { FT_cipher, "camellia-192-cbc", enc_main, enc_options }, ++#endif ++#ifndef OPENSSL_NO_CAMELLIA ++ { FT_cipher, "camellia-192-ecb", enc_main, enc_options }, ++#endif ++#ifndef OPENSSL_NO_CAMELLIA ++ { FT_cipher, "camellia-256-cbc", enc_main, enc_options }, ++#endif ++#ifndef OPENSSL_NO_CAMELLIA ++ { FT_cipher, "camellia-256-ecb", enc_main, enc_options }, ++#endif ++ { FT_cipher, "base64", enc_main, enc_options }, ++#ifdef ZLIB ++ { FT_cipher, "zlib", enc_main, enc_options }, ++#endif ++#ifndef OPENSSL_NO_DES ++ { FT_cipher, "des", enc_main, enc_options }, ++#endif ++#ifndef OPENSSL_NO_DES ++ { FT_cipher, "des3", enc_main, enc_options }, ++#endif ++#ifndef OPENSSL_NO_DES ++ { FT_cipher, "desx", enc_main, enc_options }, ++#endif ++#ifndef OPENSSL_NO_IDEA ++ { FT_cipher, "idea", enc_main, enc_options }, ++#endif ++#ifndef OPENSSL_NO_SEED ++ { FT_cipher, "seed", enc_main, enc_options }, ++#endif ++#ifndef OPENSSL_NO_RC4 ++ { FT_cipher, "rc4", enc_main, enc_options }, ++#endif ++#ifndef OPENSSL_NO_RC4 ++ { FT_cipher, "rc4-40", enc_main, enc_options }, ++#endif ++#ifndef OPENSSL_NO_RC2 ++ { FT_cipher, "rc2", enc_main, enc_options }, ++#endif ++#ifndef OPENSSL_NO_BF ++ { FT_cipher, "bf", enc_main, enc_options }, ++#endif ++#ifndef OPENSSL_NO_CAST ++ { FT_cipher, "cast", enc_main, enc_options }, ++#endif ++#ifndef OPENSSL_NO_RC5 ++ { FT_cipher, "rc5", enc_main, enc_options }, ++#endif ++#ifndef OPENSSL_NO_DES ++ { FT_cipher, "des-ecb", enc_main, enc_options }, ++#endif ++#ifndef OPENSSL_NO_DES ++ { FT_cipher, "des-ede", enc_main, enc_options }, ++#endif ++#ifndef OPENSSL_NO_DES ++ { FT_cipher, "des-ede3", enc_main, enc_options }, ++#endif ++#ifndef OPENSSL_NO_DES ++ { FT_cipher, "des-cbc", enc_main, enc_options }, ++#endif ++#ifndef OPENSSL_NO_DES ++ { FT_cipher, "des-ede-cbc", enc_main, enc_options }, ++#endif ++#ifndef OPENSSL_NO_DES ++ { FT_cipher, "des-ede3-cbc", enc_main, enc_options }, ++#endif ++#ifndef OPENSSL_NO_DES ++ { FT_cipher, "des-cfb", enc_main, enc_options }, ++#endif ++#ifndef OPENSSL_NO_DES ++ { FT_cipher, "des-ede-cfb", enc_main, enc_options }, ++#endif ++#ifndef OPENSSL_NO_DES ++ { FT_cipher, "des-ede3-cfb", enc_main, enc_options }, ++#endif ++#ifndef OPENSSL_NO_DES ++ { FT_cipher, "des-ofb", enc_main, enc_options }, ++#endif ++#ifndef OPENSSL_NO_DES ++ { FT_cipher, "des-ede-ofb", enc_main, enc_options }, ++#endif ++#ifndef OPENSSL_NO_DES ++ { FT_cipher, "des-ede3-ofb", enc_main, enc_options }, ++#endif ++#ifndef OPENSSL_NO_IDEA ++ { FT_cipher, "idea-cbc", enc_main, enc_options }, ++#endif ++#ifndef OPENSSL_NO_IDEA ++ { FT_cipher, "idea-ecb", enc_main, enc_options }, ++#endif ++#ifndef OPENSSL_NO_IDEA ++ { FT_cipher, "idea-cfb", enc_main, enc_options }, ++#endif ++#ifndef OPENSSL_NO_IDEA ++ { FT_cipher, "idea-ofb", enc_main, enc_options }, ++#endif ++#ifndef OPENSSL_NO_SEED ++ { FT_cipher, "seed-cbc", enc_main, enc_options }, ++#endif ++#ifndef OPENSSL_NO_SEED ++ { FT_cipher, "seed-ecb", enc_main, enc_options }, ++#endif ++#ifndef OPENSSL_NO_SEED ++ { FT_cipher, "seed-cfb", enc_main, enc_options }, ++#endif ++#ifndef OPENSSL_NO_SEED ++ { FT_cipher, "seed-ofb", enc_main, enc_options }, ++#endif ++#ifndef OPENSSL_NO_RC2 ++ { FT_cipher, "rc2-cbc", enc_main, enc_options }, ++#endif ++#ifndef OPENSSL_NO_RC2 ++ { FT_cipher, "rc2-ecb", enc_main, enc_options }, ++#endif ++#ifndef OPENSSL_NO_RC2 ++ { FT_cipher, "rc2-cfb", enc_main, enc_options }, ++#endif ++#ifndef OPENSSL_NO_RC2 ++ { FT_cipher, "rc2-ofb", enc_main, enc_options }, ++#endif ++#ifndef OPENSSL_NO_RC2 ++ { FT_cipher, "rc2-64-cbc", enc_main, enc_options }, ++#endif ++#ifndef OPENSSL_NO_RC2 ++ { FT_cipher, "rc2-40-cbc", enc_main, enc_options }, ++#endif ++#ifndef OPENSSL_NO_BF ++ { FT_cipher, "bf-cbc", enc_main, enc_options }, ++#endif ++#ifndef OPENSSL_NO_BF ++ { FT_cipher, "bf-ecb", enc_main, enc_options }, ++#endif ++#ifndef OPENSSL_NO_BF ++ { FT_cipher, "bf-cfb", enc_main, enc_options }, ++#endif ++#ifndef OPENSSL_NO_BF ++ { FT_cipher, "bf-ofb", enc_main, enc_options }, ++#endif ++#ifndef OPENSSL_NO_CAST ++ { FT_cipher, "cast5-cbc", enc_main, enc_options }, ++#endif ++#ifndef OPENSSL_NO_CAST ++ { FT_cipher, "cast5-ecb", enc_main, enc_options }, ++#endif ++#ifndef OPENSSL_NO_CAST ++ { FT_cipher, "cast5-cfb", enc_main, enc_options }, ++#endif ++#ifndef OPENSSL_NO_CAST ++ { FT_cipher, "cast5-ofb", enc_main, enc_options }, ++#endif ++#ifndef OPENSSL_NO_CAST ++ { FT_cipher, "cast-cbc", enc_main, enc_options }, ++#endif ++#ifndef OPENSSL_NO_RC5 ++ { FT_cipher, "rc5-cbc", enc_main, enc_options }, ++#endif ++#ifndef OPENSSL_NO_RC5 ++ { FT_cipher, "rc5-ecb", enc_main, enc_options }, ++#endif ++#ifndef OPENSSL_NO_RC5 ++ { FT_cipher, "rc5-cfb", enc_main, enc_options }, ++#endif ++#ifndef OPENSSL_NO_RC5 ++ { FT_cipher, "rc5-ofb", enc_main, enc_options }, ++#endif ++ { 0, NULL, NULL} ++}; ++#endif +diff --git a/CryptoPkg/Library/OpensslLib/openssl/apps/progs.pl b/CryptoPkg/Library/OpensslLib/openssl/apps/progs.pl +new file mode 100644 +index 0000000..21baf17 +--- /dev/null ++++ b/CryptoPkg/Library/OpensslLib/openssl/apps/progs.pl +@@ -0,0 +1,155 @@ ++#! /usr/bin/env perl ++# Copyright 1995-2016 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 ++# in the file LICENSE in the source distribution or at ++# https://www.openssl.org/source/license.html ++ ++# Generate progs.h file by looking for command mains in list of C files ++# passed on the command line. ++ ++use strict; ++use warnings; ++use configdata qw/@disablables/; ++ ++my %commands = (); ++my $cmdre = qr/^\s*int\s+([a-z_][a-z0-9_]*)_main\(\s*int\s+argc\s*,/; ++ ++foreach my $filename (@ARGV) { ++ open F, $filename or die "Coudn't open $_: $!\n"; ++ foreach (grep /$cmdre/, ) { ++ my @foo = /$cmdre/; ++ $commands{$1} = 1; ++ } ++ close F; ++} ++ ++@ARGV = sort keys %commands; ++ ++print <<'EOF'; ++/* ++ * WARNING: do not edit! ++ * Generated by apps/progs.pl ++ * ++ * Copyright 1995-2016 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 ++ * in the file LICENSE in the source distribution or at ++ * https://www.openssl.org/source/license.html ++ */ ++ ++typedef enum FUNC_TYPE { ++ FT_none, FT_general, FT_md, FT_cipher, FT_pkey, ++ FT_md_alg, FT_cipher_alg ++} FUNC_TYPE; ++ ++typedef struct function_st { ++ FUNC_TYPE type; ++ const char *name; ++ int (*func)(int argc, char *argv[]); ++ const OPTIONS *help; ++} FUNCTION; ++ ++DEFINE_LHASH_OF(FUNCTION); ++ ++EOF ++ ++foreach (@ARGV) { ++ printf "extern int %s_main(int argc, char *argv[]);\n", $_; ++} ++ ++print "\n"; ++ ++foreach (@ARGV) { ++ printf "extern OPTIONS %s_options[];\n", $_; ++} ++ ++print "\n#ifdef INCLUDE_FUNCTION_TABLE\n"; ++print "static FUNCTION functions[] = {\n"; ++my %cmd_disabler = ( ++ ciphers => "sock", ++ genrsa => "rsa", ++ rsautl => "rsa", ++ gendsa => "dsa", ++ dsaparam => "dsa", ++ gendh => "dh", ++ dhparam => "dh", ++ ecparam => "ec", ++ pkcs12 => "des", ++ ); ++foreach my $cmd (@ARGV) { ++ my $str=" { FT_general, \"$cmd\", ${cmd}_main, ${cmd}_options },\n"; ++ if ($cmd =~ /^s_/) { ++ print "#ifndef OPENSSL_NO_SOCK\n${str}#endif\n"; ++ } elsif (grep { $cmd eq $_ } @disablables) { ++ print "#ifndef OPENSSL_NO_".uc($cmd)."\n${str}#endif\n"; ++ } elsif (my $disabler = $cmd_disabler{$cmd}) { ++ print "#ifndef OPENSSL_NO_".uc($disabler)."\n${str}#endif\n"; ++ } else { ++ print $str; ++ } ++} ++ ++my %md_disabler = ( ++ blake2b512 => "blake2", ++ blake2s256 => "blake2", ++ ); ++foreach my $cmd ( ++ "md2", "md4", "md5", ++ "gost", ++ "sha1", "sha224", "sha256", "sha384", "sha512", ++ "mdc2", "rmd160", "blake2b512", "blake2s256" ++) { ++ my $str = " { FT_md, \"".$cmd."\", dgst_main},\n"; ++ if (grep { $cmd eq $_ } @disablables) { ++ print "#ifndef OPENSSL_NO_".uc($cmd)."\n${str}#endif\n"; ++ } elsif (my $disabler = $md_disabler{$cmd}) { ++ print "#ifndef OPENSSL_NO_".uc($disabler)."\n${str}#endif\n"; ++ } else { ++ print $str; ++ } ++} ++ ++my %cipher_disabler = ( ++ des3 => "des", ++ desx => "des", ++ cast5 => "cast", ++ ); ++foreach my $cmd ( ++ "aes-128-cbc", "aes-128-ecb", ++ "aes-192-cbc", "aes-192-ecb", ++ "aes-256-cbc", "aes-256-ecb", ++ "camellia-128-cbc", "camellia-128-ecb", ++ "camellia-192-cbc", "camellia-192-ecb", ++ "camellia-256-cbc", "camellia-256-ecb", ++ "base64", "zlib", ++ "des", "des3", "desx", "idea", "seed", "rc4", "rc4-40", ++ "rc2", "bf", "cast", "rc5", ++ "des-ecb", "des-ede", "des-ede3", ++ "des-cbc", "des-ede-cbc","des-ede3-cbc", ++ "des-cfb", "des-ede-cfb","des-ede3-cfb", ++ "des-ofb", "des-ede-ofb","des-ede3-ofb", ++ "idea-cbc","idea-ecb", "idea-cfb", "idea-ofb", ++ "seed-cbc","seed-ecb", "seed-cfb", "seed-ofb", ++ "rc2-cbc", "rc2-ecb", "rc2-cfb","rc2-ofb", "rc2-64-cbc", "rc2-40-cbc", ++ "bf-cbc", "bf-ecb", "bf-cfb", "bf-ofb", ++ "cast5-cbc","cast5-ecb", "cast5-cfb","cast5-ofb", ++ "cast-cbc", "rc5-cbc", "rc5-ecb", "rc5-cfb", "rc5-ofb" ++) { ++ my $str=" { FT_cipher, \"$cmd\", enc_main, enc_options },\n"; ++ (my $algo= $cmd) =~ s/-.*//g; ++ if ($cmd eq "zlib") { ++ print "#ifdef ZLIB\n${str}#endif\n"; ++ } elsif (grep { $algo eq $_ } @disablables) { ++ print "#ifndef OPENSSL_NO_".uc($algo)."\n${str}#endif\n"; ++ } elsif (my $disabler = $cipher_disabler{$algo}) { ++ print "#ifndef OPENSSL_NO_".uc($disabler)."\n${str}#endif\n"; ++ } else { ++ print $str; ++ } ++} ++ ++print " { 0, NULL, NULL}\n};\n"; ++print "#endif\n"; +diff --git a/CryptoPkg/Library/OpensslLib/openssl/apps/rand.c b/CryptoPkg/Library/OpensslLib/openssl/apps/rand.c +new file mode 100644 +index 0000000..e726180 +--- /dev/null ++++ b/CryptoPkg/Library/OpensslLib/openssl/apps/rand.c +@@ -0,0 +1,132 @@ ++/* ++ * Copyright 1998-2016 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 ++ * in the file LICENSE in the source distribution or at ++ * https://www.openssl.org/source/license.html ++ */ ++ ++#include "apps.h" ++ ++#include ++#include ++#include ++ ++#include ++#include ++#include ++ ++typedef enum OPTION_choice { ++ OPT_ERR = -1, OPT_EOF = 0, OPT_HELP, ++ OPT_OUT, OPT_ENGINE, OPT_RAND, OPT_BASE64, OPT_HEX ++} OPTION_CHOICE; ++ ++OPTIONS rand_options[] = { ++ {OPT_HELP_STR, 1, '-', "Usage: %s [flags] num\n"}, ++ {OPT_HELP_STR, 1, '-', "Valid options are:\n"}, ++ {"help", OPT_HELP, '-', "Display this summary"}, ++ {"out", OPT_OUT, '>', "Output file"}, ++ {"rand", OPT_RAND, 's', ++ "Load the file(s) into the random number generator"}, ++ {"base64", OPT_BASE64, '-', "Base64 encode output"}, ++ {"hex", OPT_HEX, '-', "Hex encode output"}, ++#ifndef OPENSSL_NO_ENGINE ++ {"engine", OPT_ENGINE, 's', "Use engine, possibly a hardware device"}, ++#endif ++ {NULL} ++}; ++ ++int rand_main(int argc, char **argv) ++{ ++ ENGINE *e = NULL; ++ BIO *out = NULL; ++ char *inrand = NULL, *outfile = NULL, *prog; ++ OPTION_CHOICE o; ++ int format = FORMAT_BINARY, i, num = -1, r, ret = 1; ++ ++ prog = opt_init(argc, argv, rand_options); ++ while ((o = opt_next()) != OPT_EOF) { ++ switch (o) { ++ case OPT_EOF: ++ case OPT_ERR: ++ opthelp: ++ BIO_printf(bio_err, "%s: Use -help for summary.\n", prog); ++ goto end; ++ case OPT_HELP: ++ opt_help(rand_options); ++ ret = 0; ++ goto end; ++ case OPT_OUT: ++ outfile = opt_arg(); ++ break; ++ case OPT_ENGINE: ++ e = setup_engine(opt_arg(), 0); ++ break; ++ case OPT_RAND: ++ inrand = opt_arg(); ++ break; ++ case OPT_BASE64: ++ format = FORMAT_BASE64; ++ break; ++ case OPT_HEX: ++ format = FORMAT_TEXT; ++ break; ++ } ++ } ++ argc = opt_num_rest(); ++ argv = opt_rest(); ++ ++ if (argc != 1 || !opt_int(argv[0], &num) || num < 0) ++ goto opthelp; ++ ++ app_RAND_load_file(NULL, (inrand != NULL)); ++ if (inrand != NULL) ++ BIO_printf(bio_err, "%ld semi-random bytes loaded\n", ++ app_RAND_load_files(inrand)); ++ ++ out = bio_open_default(outfile, 'w', format); ++ if (out == NULL) ++ goto end; ++ ++ if (format == FORMAT_BASE64) { ++ BIO *b64 = BIO_new(BIO_f_base64()); ++ if (b64 == NULL) ++ goto end; ++ out = BIO_push(b64, out); ++ } ++ ++ while (num > 0) { ++ unsigned char buf[4096]; ++ int chunk; ++ ++ chunk = num; ++ if (chunk > (int)sizeof(buf)) ++ chunk = sizeof buf; ++ r = RAND_bytes(buf, chunk); ++ if (r <= 0) ++ goto end; ++ if (format != FORMAT_TEXT) { ++ if (BIO_write(out, buf, chunk) != chunk) ++ goto end; ++ } else { ++ for (i = 0; i < chunk; i++) ++ if (BIO_printf(out, "%02x", buf[i]) != 2) ++ goto end; ++ } ++ num -= chunk; ++ } ++ if (format == FORMAT_TEXT) ++ BIO_puts(out, "\n"); ++ if (BIO_flush(out) <= 0 || !app_RAND_write_file(NULL)) ++ goto end; ++ ++ ret = 0; ++ ++ end: ++ if (ret != 0) ++ ERR_print_errors(bio_err); ++ release_engine(e); ++ BIO_free_all(out); ++ return (ret); ++} +diff --git a/CryptoPkg/Library/OpensslLib/openssl/apps/rehash.c b/CryptoPkg/Library/OpensslLib/openssl/apps/rehash.c +new file mode 100644 +index 0000000..4e10ded +--- /dev/null ++++ b/CryptoPkg/Library/OpensslLib/openssl/apps/rehash.c +@@ -0,0 +1,480 @@ ++/* ++ * Copyright 2015-2016 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 ++ * in the file LICENSE in the source distribution or at ++ * https://www.openssl.org/source/license.html ++ */ ++ ++/* ++ * C implementation based on the original Perl and shell versions ++ * ++ * Copyright (c) 2013-2014 Timo Teräs ++ */ ++ ++#include "apps.h" ++ ++#if defined(OPENSSL_SYS_UNIX) || defined(__APPLE__) || \ ++ (defined(__VMS) && defined(__DECC) && __CTRL_VER >= 80300000) ++# include ++# include ++# include ++# include ++# include ++# include ++# include ++ ++# include "internal/o_dir.h" ++# include ++# include ++# include ++ ++ ++# ifndef PATH_MAX ++# define PATH_MAX 4096 ++# endif ++# ifndef NAME_MAX ++# define NAME_MAX 255 ++# endif ++# define MAX_COLLISIONS 256 ++ ++typedef struct hentry_st { ++ struct hentry_st *next; ++ char *filename; ++ unsigned short old_id; ++ unsigned char need_symlink; ++ unsigned char digest[EVP_MAX_MD_SIZE]; ++} HENTRY; ++ ++typedef struct bucket_st { ++ struct bucket_st *next; ++ HENTRY *first_entry, *last_entry; ++ unsigned int hash; ++ unsigned short type; ++ unsigned short num_needed; ++} BUCKET; ++ ++enum Type { ++ /* Keep in sync with |suffixes|, below. */ ++ TYPE_CERT=0, TYPE_CRL=1 ++}; ++ ++enum Hash { ++ HASH_OLD, HASH_NEW, HASH_BOTH ++}; ++ ++ ++static int evpmdsize; ++static const EVP_MD *evpmd; ++static int remove_links = 1; ++static int verbose = 0; ++static BUCKET *hash_table[257]; ++ ++static const char *suffixes[] = { "", "r" }; ++static const char *extensions[] = { "pem", "crt", "cer", "crl" }; ++ ++ ++static void bit_set(unsigned char *set, unsigned int bit) ++{ ++ set[bit >> 3] |= 1 << (bit & 0x7); ++} ++ ++static int bit_isset(unsigned char *set, unsigned int bit) ++{ ++ return set[bit >> 3] & (1 << (bit & 0x7)); ++} ++ ++ ++/* ++ * Process an entry; return number of errors. ++ */ ++static int add_entry(enum Type type, unsigned int hash, const char *filename, ++ const unsigned char *digest, int need_symlink, ++ unsigned short old_id) ++{ ++ static BUCKET nilbucket; ++ static HENTRY nilhentry; ++ BUCKET *bp; ++ HENTRY *ep, *found = NULL; ++ unsigned int ndx = (type + hash) % OSSL_NELEM(hash_table); ++ ++ for (bp = hash_table[ndx]; bp; bp = bp->next) ++ if (bp->type == type && bp->hash == hash) ++ break; ++ if (bp == NULL) { ++ bp = app_malloc(sizeof(*bp), "hash bucket"); ++ *bp = nilbucket; ++ bp->next = hash_table[ndx]; ++ bp->type = type; ++ bp->hash = hash; ++ hash_table[ndx] = bp; ++ } ++ ++ for (ep = bp->first_entry; ep; ep = ep->next) { ++ if (digest && memcmp(digest, ep->digest, evpmdsize) == 0) { ++ BIO_printf(bio_err, ++ "%s: skipping duplicate %s in %s\n", opt_getprog(), ++ type == TYPE_CERT ? "certificate" : "CRL", filename); ++ return 1; ++ } ++ if (strcmp(filename, ep->filename) == 0) { ++ found = ep; ++ if (digest == NULL) ++ break; ++ } ++ } ++ ep = found; ++ if (ep == NULL) { ++ if (bp->num_needed >= MAX_COLLISIONS) { ++ BIO_printf(bio_err, ++ "%s: hash table overflow for %s\n", ++ opt_getprog(), filename); ++ return 1; ++ } ++ ep = app_malloc(sizeof(*ep), "collision bucket"); ++ *ep = nilhentry; ++ ep->old_id = ~0; ++ ep->filename = OPENSSL_strdup(filename); ++ if (bp->last_entry) ++ bp->last_entry->next = ep; ++ if (bp->first_entry == NULL) ++ bp->first_entry = ep; ++ bp->last_entry = ep; ++ } ++ ++ if (old_id < ep->old_id) ++ ep->old_id = old_id; ++ if (need_symlink && !ep->need_symlink) { ++ ep->need_symlink = 1; ++ bp->num_needed++; ++ memcpy(ep->digest, digest, evpmdsize); ++ } ++ return 0; ++} ++ ++/* ++ * Check if a symlink goes to the right spot; return 0 if okay. ++ * This can be -1 if bad filename, or an error count. ++ */ ++static int handle_symlink(const char *filename, const char *fullpath) ++{ ++ unsigned int hash = 0; ++ int i, type, id; ++ unsigned char ch; ++ char linktarget[PATH_MAX], *endptr; ++ ossl_ssize_t n; ++ ++ for (i = 0; i < 8; i++) { ++ ch = filename[i]; ++ if (!isxdigit(ch)) ++ return -1; ++ hash <<= 4; ++ hash += OPENSSL_hexchar2int(ch); ++ } ++ if (filename[i++] != '.') ++ return -1; ++ for (type = OSSL_NELEM(suffixes) - 1; type > 0; type--) { ++ const char *suffix = suffixes[type]; ++ if (strncasecmp(suffix, &filename[i], strlen(suffix)) == 0) ++ break; ++ } ++ i += strlen(suffixes[type]); ++ ++ id = strtoul(&filename[i], &endptr, 10); ++ if (*endptr != '\0') ++ return -1; ++ ++ n = readlink(fullpath, linktarget, sizeof(linktarget)); ++ if (n < 0 || n >= (int)sizeof(linktarget)) ++ return -1; ++ linktarget[n] = 0; ++ ++ return add_entry(type, hash, linktarget, NULL, 0, id); ++} ++ ++/* ++ * process a file, return number of errors. ++ */ ++static int do_file(const char *filename, const char *fullpath, enum Hash h) ++{ ++ STACK_OF (X509_INFO) *inf = NULL; ++ X509_INFO *x; ++ X509_NAME *name = NULL; ++ BIO *b; ++ const char *ext; ++ unsigned char digest[EVP_MAX_MD_SIZE]; ++ int type, errs = 0; ++ size_t i; ++ ++ /* Does it end with a recognized extension? */ ++ if ((ext = strrchr(filename, '.')) == NULL) ++ goto end; ++ for (i = 0; i < OSSL_NELEM(extensions); i++) { ++ if (strcasecmp(extensions[i], ext + 1) == 0) ++ break; ++ } ++ if (i >= OSSL_NELEM(extensions)) ++ goto end; ++ ++ /* Does it have X.509 data in it? */ ++ if ((b = BIO_new_file(fullpath, "r")) == NULL) { ++ BIO_printf(bio_err, "%s: skipping %s, cannot open file\n", ++ opt_getprog(), filename); ++ errs++; ++ goto end; ++ } ++ inf = PEM_X509_INFO_read_bio(b, NULL, NULL, NULL); ++ BIO_free(b); ++ if (inf == NULL) ++ goto end; ++ ++ if (sk_X509_INFO_num(inf) != 1) { ++ BIO_printf(bio_err, ++ "%s: skipping %s," ++ "it does not contain exactly one certificate or CRL\n", ++ opt_getprog(), filename); ++ /* This is not an error. */ ++ goto end; ++ } ++ x = sk_X509_INFO_value(inf, 0); ++ if (x->x509) { ++ type = TYPE_CERT; ++ name = X509_get_subject_name(x->x509); ++ X509_digest(x->x509, evpmd, digest, NULL); ++ } else if (x->crl) { ++ type = TYPE_CRL; ++ name = X509_CRL_get_issuer(x->crl); ++ X509_CRL_digest(x->crl, evpmd, digest, NULL); ++ } else { ++ ++errs; ++ goto end; ++ } ++ if (name) { ++ if ((h == HASH_NEW) || (h == HASH_BOTH)) ++ errs += add_entry(type, X509_NAME_hash(name), filename, digest, 1, ~0); ++ if ((h == HASH_OLD) || (h == HASH_BOTH)) ++ errs += add_entry(type, X509_NAME_hash_old(name), filename, digest, 1, ~0); ++ } ++ ++end: ++ sk_X509_INFO_pop_free(inf, X509_INFO_free); ++ return errs; ++} ++ ++static void str_free(char *s) ++{ ++ OPENSSL_free(s); ++} ++ ++/* ++ * Process a directory; return number of errors found. ++ */ ++static int do_dir(const char *dirname, enum Hash h) ++{ ++ BUCKET *bp, *nextbp; ++ HENTRY *ep, *nextep; ++ OPENSSL_DIR_CTX *d = NULL; ++ struct stat st; ++ unsigned char idmask[MAX_COLLISIONS / 8]; ++ int n, numfiles, nextid, buflen, errs = 0; ++ size_t i; ++ const char *pathsep; ++ const char *filename; ++ char *buf, *copy; ++ STACK_OF(OPENSSL_STRING) *files = NULL; ++ ++ if (app_access(dirname, W_OK) < 0) { ++ BIO_printf(bio_err, "Skipping %s, can't write\n", dirname); ++ return 1; ++ } ++ buflen = strlen(dirname); ++ pathsep = (buflen && dirname[buflen - 1] == '/') ? "" : "/"; ++ buflen += NAME_MAX + 1 + 1; ++ buf = app_malloc(buflen, "filename buffer"); ++ ++ if (verbose) ++ BIO_printf(bio_out, "Doing %s\n", dirname); ++ ++ if ((files = sk_OPENSSL_STRING_new_null()) == NULL) { ++ BIO_printf(bio_err, "Skipping %s, out of memory\n", dirname); ++ exit(1); ++ } ++ while ((filename = OPENSSL_DIR_read(&d, dirname)) != NULL) { ++ if ((copy = strdup(filename)) == NULL ++ || sk_OPENSSL_STRING_push(files, copy) == 0) { ++ BIO_puts(bio_err, "out of memory\n"); ++ exit(1); ++ } ++ } ++ OPENSSL_DIR_end(&d); ++ sk_OPENSSL_STRING_sort(files); ++ ++ numfiles = sk_OPENSSL_STRING_num(files); ++ for (n = 0; n < numfiles; ++n) { ++ filename = sk_OPENSSL_STRING_value(files, n); ++ if (snprintf(buf, buflen, "%s%s%s", ++ dirname, pathsep, filename) >= buflen) ++ continue; ++ if (lstat(buf, &st) < 0) ++ continue; ++ if (S_ISLNK(st.st_mode) && handle_symlink(filename, buf) == 0) ++ continue; ++ errs += do_file(filename, buf, h); ++ } ++ sk_OPENSSL_STRING_pop_free(files, str_free); ++ ++ for (i = 0; i < OSSL_NELEM(hash_table); i++) { ++ for (bp = hash_table[i]; bp; bp = nextbp) { ++ nextbp = bp->next; ++ nextid = 0; ++ memset(idmask, 0, (bp->num_needed + 7) / 8); ++ for (ep = bp->first_entry; ep; ep = ep->next) ++ if (ep->old_id < bp->num_needed) ++ bit_set(idmask, ep->old_id); ++ ++ for (ep = bp->first_entry; ep; ep = nextep) { ++ nextep = ep->next; ++ if (ep->old_id < bp->num_needed) { ++ /* Link exists, and is used as-is */ ++ snprintf(buf, buflen, "%08x.%s%d", bp->hash, ++ suffixes[bp->type], ep->old_id); ++ if (verbose) ++ BIO_printf(bio_out, "link %s -> %s\n", ++ ep->filename, buf); ++ } else if (ep->need_symlink) { ++ /* New link needed (it may replace something) */ ++ while (bit_isset(idmask, nextid)) ++ nextid++; ++ ++ snprintf(buf, buflen, "%s%s%n%08x.%s%d", ++ dirname, pathsep, &n, bp->hash, ++ suffixes[bp->type], nextid); ++ if (verbose) ++ BIO_printf(bio_out, "link %s -> %s\n", ++ ep->filename, &buf[n]); ++ if (unlink(buf) < 0 && errno != ENOENT) { ++ BIO_printf(bio_err, ++ "%s: Can't unlink %s, %s\n", ++ opt_getprog(), buf, strerror(errno)); ++ errs++; ++ } ++ if (symlink(ep->filename, buf) < 0) { ++ BIO_printf(bio_err, ++ "%s: Can't symlink %s, %s\n", ++ opt_getprog(), ep->filename, ++ strerror(errno)); ++ errs++; ++ } ++ bit_set(idmask, nextid); ++ } else if (remove_links) { ++ /* Link to be deleted */ ++ snprintf(buf, buflen, "%s%s%n%08x.%s%d", ++ dirname, pathsep, &n, bp->hash, ++ suffixes[bp->type], ep->old_id); ++ if (verbose) ++ BIO_printf(bio_out, "unlink %s\n", ++ &buf[n]); ++ if (unlink(buf) < 0 && errno != ENOENT) { ++ BIO_printf(bio_err, ++ "%s: Can't unlink %s, %s\n", ++ opt_getprog(), buf, strerror(errno)); ++ errs++; ++ } ++ } ++ OPENSSL_free(ep->filename); ++ OPENSSL_free(ep); ++ } ++ OPENSSL_free(bp); ++ } ++ hash_table[i] = NULL; ++ } ++ ++ OPENSSL_free(buf); ++ return errs; ++} ++ ++typedef enum OPTION_choice { ++ OPT_ERR = -1, OPT_EOF = 0, OPT_HELP, ++ OPT_COMPAT, OPT_OLD, OPT_N, OPT_VERBOSE ++} OPTION_CHOICE; ++ ++OPTIONS rehash_options[] = { ++ {OPT_HELP_STR, 1, '-', "Usage: %s [options] [cert-directory...]\n"}, ++ {OPT_HELP_STR, 1, '-', "Valid options are:\n"}, ++ {"help", OPT_HELP, '-', "Display this summary"}, ++ {"h", OPT_HELP, '-', "Display this summary"}, ++ {"compat", OPT_COMPAT, '-', "Create both new- and old-style hash links"}, ++ {"old", OPT_OLD, '-', "Use old-style hash to generate links"}, ++ {"n", OPT_N, '-', "Do not remove existing links"}, ++ {"v", OPT_VERBOSE, '-', "Verbose output"}, ++ {NULL} ++}; ++ ++ ++int rehash_main(int argc, char **argv) ++{ ++ const char *env, *prog; ++ char *e, *m; ++ int errs = 0; ++ OPTION_CHOICE o; ++ enum Hash h = HASH_NEW; ++ ++ prog = opt_init(argc, argv, rehash_options); ++ while ((o = opt_next()) != OPT_EOF) { ++ switch (o) { ++ case OPT_EOF: ++ case OPT_ERR: ++ BIO_printf(bio_err, "%s: Use -help for summary.\n", prog); ++ goto end; ++ case OPT_HELP: ++ opt_help(rehash_options); ++ goto end; ++ case OPT_COMPAT: ++ h = HASH_BOTH; ++ break; ++ case OPT_OLD: ++ h = HASH_OLD; ++ break; ++ case OPT_N: ++ remove_links = 0; ++ break; ++ case OPT_VERBOSE: ++ verbose = 1; ++ break; ++ } ++ } ++ argc = opt_num_rest(); ++ argv = opt_rest(); ++ ++ evpmd = EVP_sha1(); ++ evpmdsize = EVP_MD_size(evpmd); ++ ++ if (*argv) { ++ while (*argv) ++ errs += do_dir(*argv++, h); ++ } else if ((env = getenv("SSL_CERT_DIR")) != NULL) { ++ m = OPENSSL_strdup(env); ++ for (e = strtok(m, ":"); e != NULL; e = strtok(NULL, ":")) ++ errs += do_dir(e, h); ++ OPENSSL_free(m); ++ } else { ++ errs += do_dir("/etc/ssl/certs", h); ++ } ++ ++ end: ++ return errs; ++} ++ ++#else ++OPTIONS rehash_options[] = { ++ {NULL} ++}; ++ ++int rehash_main(int argc, char **argv) ++{ ++ BIO_printf(bio_err, "Not available; use c_rehash script\n"); ++ return (1); ++} ++ ++#endif /* defined(OPENSSL_SYS_UNIX) || defined(__APPLE__) */ +diff --git a/CryptoPkg/Library/OpensslLib/openssl/apps/req.c b/CryptoPkg/Library/OpensslLib/openssl/apps/req.c +new file mode 100644 +index 0000000..e8951ae +--- /dev/null ++++ b/CryptoPkg/Library/OpensslLib/openssl/apps/req.c +@@ -0,0 +1,1508 @@ ++/* ++ * Copyright 1995-2016 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 ++ * in the file LICENSE in the source distribution or at ++ * https://www.openssl.org/source/license.html ++ */ ++ ++#include ++#include ++#include ++#include ++#include "apps.h" ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#ifndef OPENSSL_NO_RSA ++# include ++#endif ++#ifndef OPENSSL_NO_DSA ++# include ++#endif ++ ++#define SECTION "req" ++ ++#define BITS "default_bits" ++#define KEYFILE "default_keyfile" ++#define PROMPT "prompt" ++#define DISTINGUISHED_NAME "distinguished_name" ++#define ATTRIBUTES "attributes" ++#define V3_EXTENSIONS "x509_extensions" ++#define REQ_EXTENSIONS "req_extensions" ++#define STRING_MASK "string_mask" ++#define UTF8_IN "utf8" ++ ++#define DEFAULT_KEY_LENGTH 2048 ++#define MIN_KEY_LENGTH 512 ++ ++static int make_REQ(X509_REQ *req, EVP_PKEY *pkey, char *dn, int mutlirdn, ++ int attribs, unsigned long chtype); ++static int build_subject(X509_REQ *req, const char *subj, unsigned long chtype, ++ int multirdn); ++static int prompt_info(X509_REQ *req, ++ STACK_OF(CONF_VALUE) *dn_sk, const char *dn_sect, ++ STACK_OF(CONF_VALUE) *attr_sk, const char *attr_sect, ++ int attribs, unsigned long chtype); ++static int auto_info(X509_REQ *req, STACK_OF(CONF_VALUE) *sk, ++ STACK_OF(CONF_VALUE) *attr, int attribs, ++ unsigned long chtype); ++static int add_attribute_object(X509_REQ *req, char *text, const char *def, ++ char *value, int nid, int n_min, int n_max, ++ unsigned long chtype); ++static int add_DN_object(X509_NAME *n, char *text, const char *def, ++ char *value, int nid, int n_min, int n_max, ++ unsigned long chtype, int mval); ++static int genpkey_cb(EVP_PKEY_CTX *ctx); ++static int req_check_len(int len, int n_min, int n_max); ++static int check_end(const char *str, const char *end); ++static EVP_PKEY_CTX *set_keygen_ctx(const char *gstr, ++ int *pkey_type, long *pkeylen, ++ char **palgnam, ENGINE *keygen_engine); ++static CONF *req_conf = NULL; ++static int batch = 0; ++ ++typedef enum OPTION_choice { ++ OPT_ERR = -1, OPT_EOF = 0, OPT_HELP, ++ OPT_INFORM, OPT_OUTFORM, OPT_ENGINE, OPT_KEYGEN_ENGINE, OPT_KEY, ++ OPT_PUBKEY, OPT_NEW, OPT_CONFIG, OPT_KEYFORM, OPT_IN, OPT_OUT, ++ OPT_KEYOUT, OPT_PASSIN, OPT_PASSOUT, OPT_RAND, OPT_NEWKEY, ++ OPT_PKEYOPT, OPT_SIGOPT, OPT_BATCH, OPT_NEWHDR, OPT_MODULUS, ++ OPT_VERIFY, OPT_NODES, OPT_NOOUT, OPT_VERBOSE, OPT_UTF8, ++ OPT_NAMEOPT, OPT_REQOPT, OPT_SUBJ, OPT_SUBJECT, OPT_TEXT, OPT_X509, ++ OPT_MULTIVALUE_RDN, OPT_DAYS, OPT_SET_SERIAL, OPT_EXTENSIONS, ++ OPT_REQEXTS, OPT_MD ++} OPTION_CHOICE; ++ ++OPTIONS req_options[] = { ++ {"help", OPT_HELP, '-', "Display this summary"}, ++ {"inform", OPT_INFORM, 'F', "Input format - DER or PEM"}, ++ {"outform", OPT_OUTFORM, 'F', "Output format - DER or PEM"}, ++ {"in", OPT_IN, '<', "Input file"}, ++ {"out", OPT_OUT, '>', "Output file"}, ++ {"key", OPT_KEY, 's', "Private key to use"}, ++ {"keyform", OPT_KEYFORM, 'f', "Key file format"}, ++ {"pubkey", OPT_PUBKEY, '-', "Output public key"}, ++ {"new", OPT_NEW, '-', "New request"}, ++ {"config", OPT_CONFIG, '<', "Request template file"}, ++ {"keyout", OPT_KEYOUT, '>', "File to send the key to"}, ++ {"passin", OPT_PASSIN, 's', "Private key password source"}, ++ {"passout", OPT_PASSOUT, 's', "Output file pass phrase source"}, ++ {"rand", OPT_RAND, 's', ++ "Load the file(s) into the random number generator"}, ++ {"newkey", OPT_NEWKEY, 's', "Specify as type:bits"}, ++ {"pkeyopt", OPT_PKEYOPT, 's', "Public key options as opt:value"}, ++ {"sigopt", OPT_SIGOPT, 's', "Signature parameter in n:v form"}, ++ {"batch", OPT_BATCH, '-', ++ "Do not ask anything during request generation"}, ++ {"newhdr", OPT_NEWHDR, '-', "Output \"NEW\" in the header lines"}, ++ {"modulus", OPT_MODULUS, '-', "RSA modulus"}, ++ {"verify", OPT_VERIFY, '-', "Verify signature on REQ"}, ++ {"nodes", OPT_NODES, '-', "Don't encrypt the output key"}, ++ {"noout", OPT_NOOUT, '-', "Do not output REQ"}, ++ {"verbose", OPT_VERBOSE, '-', "Verbose output"}, ++ {"utf8", OPT_UTF8, '-', "Input characters are UTF8 (default ASCII)"}, ++ {"nameopt", OPT_NAMEOPT, 's', "Various certificate name options"}, ++ {"reqopt", OPT_REQOPT, 's', "Various request text options"}, ++ {"text", OPT_TEXT, '-', "Text form of request"}, ++ {"x509", OPT_X509, '-', ++ "Output a x509 structure instead of a cert request"}, ++ {OPT_MORE_STR, 1, 1, "(Required by some CA's)"}, ++ {"subj", OPT_SUBJ, 's', "Set or modify request subject"}, ++ {"subject", OPT_SUBJECT, '-', "Output the request's subject"}, ++ {"multivalue-rdn", OPT_MULTIVALUE_RDN, '-', ++ "Enable support for multivalued RDNs"}, ++ {"days", OPT_DAYS, 'p', "Number of days cert is valid for"}, ++ {"set_serial", OPT_SET_SERIAL, 's', "Serial number to use"}, ++ {"extensions", OPT_EXTENSIONS, 's', ++ "Cert extension section (override value in config file)"}, ++ {"reqexts", OPT_REQEXTS, 's', ++ "Request extension section (override value in config file)"}, ++ {"", OPT_MD, '-', "Any supported digest"}, ++#ifndef OPENSSL_NO_ENGINE ++ {"engine", OPT_ENGINE, 's', "Use engine, possibly a hardware device"}, ++ {"keygen_engine", OPT_KEYGEN_ENGINE, 's', ++ "Specify engine to be used for key generation operations"}, ++#endif ++ {NULL} ++}; ++ ++int req_main(int argc, char **argv) ++{ ++ ASN1_INTEGER *serial = NULL; ++ BIO *in = NULL, *out = NULL; ++ ENGINE *e = NULL, *gen_eng = NULL; ++ EVP_PKEY *pkey = NULL; ++ EVP_PKEY_CTX *genctx = NULL; ++ STACK_OF(OPENSSL_STRING) *pkeyopts = NULL, *sigopts = NULL; ++ X509 *x509ss = NULL; ++ X509_REQ *req = NULL; ++ const EVP_CIPHER *cipher = NULL; ++ const EVP_MD *md_alg = NULL, *digest = NULL; ++ char *extensions = NULL, *infile = NULL; ++ char *outfile = NULL, *keyfile = NULL, *inrand = NULL; ++ char *keyalgstr = NULL, *p, *prog, *passargin = NULL, *passargout = NULL; ++ char *passin = NULL, *passout = NULL; ++ char *nofree_passin = NULL, *nofree_passout = NULL; ++ char *req_exts = NULL, *subj = NULL; ++ char *template = default_config_file, *keyout = NULL; ++ const char *keyalg = NULL; ++ OPTION_CHOICE o; ++ int ret = 1, x509 = 0, days = 30, i = 0, newreq = 0, verbose = 0; ++ int pkey_type = -1, private = 0; ++ int informat = FORMAT_PEM, outformat = FORMAT_PEM, keyform = FORMAT_PEM; ++ int modulus = 0, multirdn = 0, verify = 0, noout = 0, text = 0; ++ int nodes = 0, newhdr = 0, subject = 0, pubkey = 0; ++ long newkey = -1; ++ unsigned long chtype = MBSTRING_ASC, nmflag = 0, reqflag = 0; ++ char nmflag_set = 0; ++ ++#ifndef OPENSSL_NO_DES ++ cipher = EVP_des_ede3_cbc(); ++#endif ++ ++ prog = opt_init(argc, argv, req_options); ++ while ((o = opt_next()) != OPT_EOF) { ++ switch (o) { ++ case OPT_EOF: ++ case OPT_ERR: ++ opthelp: ++ BIO_printf(bio_err, "%s: Use -help for summary.\n", prog); ++ goto end; ++ case OPT_HELP: ++ opt_help(req_options); ++ ret = 0; ++ goto end; ++ case OPT_INFORM: ++ if (!opt_format(opt_arg(), OPT_FMT_PEMDER, &informat)) ++ goto opthelp; ++ break; ++ case OPT_OUTFORM: ++ if (!opt_format(opt_arg(), OPT_FMT_PEMDER, &outformat)) ++ goto opthelp; ++ break; ++ case OPT_ENGINE: ++ e = setup_engine(opt_arg(), 0); ++ break; ++ case OPT_KEYGEN_ENGINE: ++#ifndef OPENSSL_NO_ENGINE ++ gen_eng = ENGINE_by_id(opt_arg()); ++ if (gen_eng == NULL) { ++ BIO_printf(bio_err, "Can't find keygen engine %s\n", *argv); ++ goto opthelp; ++ } ++#endif ++ break; ++ case OPT_KEY: ++ keyfile = opt_arg(); ++ break; ++ case OPT_PUBKEY: ++ pubkey = 1; ++ break; ++ case OPT_NEW: ++ newreq = 1; ++ break; ++ case OPT_CONFIG: ++ template = opt_arg(); ++ break; ++ case OPT_KEYFORM: ++ if (!opt_format(opt_arg(), OPT_FMT_ANY, &keyform)) ++ goto opthelp; ++ break; ++ case OPT_IN: ++ infile = opt_arg(); ++ break; ++ case OPT_OUT: ++ outfile = opt_arg(); ++ break; ++ case OPT_KEYOUT: ++ keyout = opt_arg(); ++ break; ++ case OPT_PASSIN: ++ passargin = opt_arg(); ++ break; ++ case OPT_PASSOUT: ++ passargout = opt_arg(); ++ break; ++ case OPT_RAND: ++ inrand = opt_arg(); ++ break; ++ case OPT_NEWKEY: ++ keyalg = opt_arg(); ++ newreq = 1; ++ break; ++ case OPT_PKEYOPT: ++ if (!pkeyopts) ++ pkeyopts = sk_OPENSSL_STRING_new_null(); ++ if (!pkeyopts || !sk_OPENSSL_STRING_push(pkeyopts, opt_arg())) ++ goto opthelp; ++ break; ++ case OPT_SIGOPT: ++ if (!sigopts) ++ sigopts = sk_OPENSSL_STRING_new_null(); ++ if (!sigopts || !sk_OPENSSL_STRING_push(sigopts, opt_arg())) ++ goto opthelp; ++ break; ++ case OPT_BATCH: ++ batch = 1; ++ break; ++ case OPT_NEWHDR: ++ newhdr = 1; ++ break; ++ case OPT_MODULUS: ++ modulus = 1; ++ break; ++ case OPT_VERIFY: ++ verify = 1; ++ break; ++ case OPT_NODES: ++ nodes = 1; ++ break; ++ case OPT_NOOUT: ++ noout = 1; ++ break; ++ case OPT_VERBOSE: ++ verbose = 1; ++ break; ++ case OPT_UTF8: ++ chtype = MBSTRING_UTF8; ++ break; ++ case OPT_NAMEOPT: ++ nmflag_set = 1; ++ if (!set_name_ex(&nmflag, opt_arg())) ++ goto opthelp; ++ break; ++ case OPT_REQOPT: ++ if (!set_cert_ex(&reqflag, opt_arg())) ++ goto opthelp; ++ break; ++ case OPT_TEXT: ++ text = 1; ++ break; ++ case OPT_X509: ++ x509 = 1; ++ newreq = 1; ++ break; ++ case OPT_DAYS: ++ days = atoi(opt_arg()); ++ break; ++ case OPT_SET_SERIAL: ++ if (serial != NULL) { ++ BIO_printf(bio_err, "Serial number supplied twice\n"); ++ goto opthelp; ++ } ++ serial = s2i_ASN1_INTEGER(NULL, opt_arg()); ++ if (serial == NULL) ++ goto opthelp; ++ break; ++ case OPT_SUBJECT: ++ subject = 1; ++ break; ++ case OPT_SUBJ: ++ subj = opt_arg(); ++ break; ++ case OPT_MULTIVALUE_RDN: ++ multirdn = 1; ++ break; ++ case OPT_EXTENSIONS: ++ extensions = opt_arg(); ++ break; ++ case OPT_REQEXTS: ++ req_exts = opt_arg(); ++ break; ++ case OPT_MD: ++ if (!opt_md(opt_unknown(), &md_alg)) ++ goto opthelp; ++ digest = md_alg; ++ break; ++ } ++ } ++ argc = opt_num_rest(); ++ if (argc != 0) ++ goto opthelp; ++ ++ if (!nmflag_set) ++ nmflag = XN_FLAG_ONELINE; ++ ++ /* TODO: simplify this as pkey is still always NULL here */ ++ private = newreq && (pkey == NULL) ? 1 : 0; ++ ++ if (!app_passwd(passargin, passargout, &passin, &passout)) { ++ BIO_printf(bio_err, "Error getting passwords\n"); ++ goto end; ++ } ++ ++ if (verbose) ++ BIO_printf(bio_err, "Using configuration from %s\n", template); ++ req_conf = app_load_config(template); ++ if (template != default_config_file && !app_load_modules(req_conf)) ++ goto end; ++ ++ if (req_conf != NULL) { ++ p = NCONF_get_string(req_conf, NULL, "oid_file"); ++ if (p == NULL) ++ ERR_clear_error(); ++ if (p != NULL) { ++ BIO *oid_bio; ++ ++ oid_bio = BIO_new_file(p, "r"); ++ if (oid_bio == NULL) { ++ /*- ++ BIO_printf(bio_err,"problems opening %s for extra oid's\n",p); ++ ERR_print_errors(bio_err); ++ */ ++ } else { ++ OBJ_create_objects(oid_bio); ++ BIO_free(oid_bio); ++ } ++ } ++ } ++ if (!add_oid_section(req_conf)) ++ goto end; ++ ++ if (md_alg == NULL) { ++ p = NCONF_get_string(req_conf, SECTION, "default_md"); ++ if (p == NULL) ++ ERR_clear_error(); ++ else { ++ if (!opt_md(p, &md_alg)) ++ goto opthelp; ++ digest = md_alg; ++ } ++ } ++ ++ if (!extensions) { ++ extensions = NCONF_get_string(req_conf, SECTION, V3_EXTENSIONS); ++ if (!extensions) ++ ERR_clear_error(); ++ } ++ if (extensions) { ++ /* Check syntax of file */ ++ X509V3_CTX ctx; ++ X509V3_set_ctx_test(&ctx); ++ X509V3_set_nconf(&ctx, req_conf); ++ if (!X509V3_EXT_add_nconf(req_conf, &ctx, extensions, NULL)) { ++ BIO_printf(bio_err, ++ "Error Loading extension section %s\n", extensions); ++ goto end; ++ } ++ } ++ ++ if (passin == NULL) { ++ passin = nofree_passin = ++ NCONF_get_string(req_conf, SECTION, "input_password"); ++ if (passin == NULL) ++ ERR_clear_error(); ++ } ++ ++ if (passout == NULL) { ++ passout = nofree_passout = ++ NCONF_get_string(req_conf, SECTION, "output_password"); ++ if (passout == NULL) ++ ERR_clear_error(); ++ } ++ ++ p = NCONF_get_string(req_conf, SECTION, STRING_MASK); ++ if (!p) ++ ERR_clear_error(); ++ ++ if (p && !ASN1_STRING_set_default_mask_asc(p)) { ++ BIO_printf(bio_err, "Invalid global string mask setting %s\n", p); ++ goto end; ++ } ++ ++ if (chtype != MBSTRING_UTF8) { ++ p = NCONF_get_string(req_conf, SECTION, UTF8_IN); ++ if (!p) ++ ERR_clear_error(); ++ else if (strcmp(p, "yes") == 0) ++ chtype = MBSTRING_UTF8; ++ } ++ ++ if (!req_exts) { ++ req_exts = NCONF_get_string(req_conf, SECTION, REQ_EXTENSIONS); ++ if (!req_exts) ++ ERR_clear_error(); ++ } ++ if (req_exts) { ++ /* Check syntax of file */ ++ X509V3_CTX ctx; ++ X509V3_set_ctx_test(&ctx); ++ X509V3_set_nconf(&ctx, req_conf); ++ if (!X509V3_EXT_add_nconf(req_conf, &ctx, req_exts, NULL)) { ++ BIO_printf(bio_err, ++ "Error Loading request extension section %s\n", ++ req_exts); ++ goto end; ++ } ++ } ++ ++ if (keyfile != NULL) { ++ pkey = load_key(keyfile, keyform, 0, passin, e, "Private Key"); ++ if (!pkey) { ++ /* load_key() has already printed an appropriate message */ ++ goto end; ++ } else { ++ char *randfile = NCONF_get_string(req_conf, SECTION, "RANDFILE"); ++ if (randfile == NULL) ++ ERR_clear_error(); ++ app_RAND_load_file(randfile, 0); ++ } ++ } ++ ++ if (newreq && (pkey == NULL)) { ++ char *randfile = NCONF_get_string(req_conf, SECTION, "RANDFILE"); ++ if (randfile == NULL) ++ ERR_clear_error(); ++ app_RAND_load_file(randfile, 0); ++ if (inrand) ++ app_RAND_load_files(inrand); ++ ++ if (!NCONF_get_number(req_conf, SECTION, BITS, &newkey)) { ++ newkey = DEFAULT_KEY_LENGTH; ++ } ++ ++ if (keyalg) { ++ genctx = set_keygen_ctx(keyalg, &pkey_type, &newkey, ++ &keyalgstr, gen_eng); ++ if (!genctx) ++ goto end; ++ } ++ ++ if (newkey < MIN_KEY_LENGTH ++ && (pkey_type == EVP_PKEY_RSA || pkey_type == EVP_PKEY_DSA)) { ++ BIO_printf(bio_err, "private key length is too short,\n"); ++ BIO_printf(bio_err, "it needs to be at least %d bits, not %ld\n", ++ MIN_KEY_LENGTH, newkey); ++ goto end; ++ } ++ ++ if (!genctx) { ++ genctx = set_keygen_ctx(NULL, &pkey_type, &newkey, ++ &keyalgstr, gen_eng); ++ if (!genctx) ++ goto end; ++ } ++ ++ if (pkeyopts) { ++ char *genopt; ++ for (i = 0; i < sk_OPENSSL_STRING_num(pkeyopts); i++) { ++ genopt = sk_OPENSSL_STRING_value(pkeyopts, i); ++ if (pkey_ctrl_string(genctx, genopt) <= 0) { ++ BIO_printf(bio_err, "parameter error \"%s\"\n", genopt); ++ ERR_print_errors(bio_err); ++ goto end; ++ } ++ } ++ } ++ ++ if (pkey_type == EVP_PKEY_EC) { ++ BIO_printf(bio_err, "Generating an EC private key\n"); ++ } else { ++ BIO_printf(bio_err, "Generating a %ld bit %s private key\n", ++ newkey, keyalgstr); ++ } ++ ++ EVP_PKEY_CTX_set_cb(genctx, genpkey_cb); ++ EVP_PKEY_CTX_set_app_data(genctx, bio_err); ++ ++ if (EVP_PKEY_keygen(genctx, &pkey) <= 0) { ++ BIO_puts(bio_err, "Error Generating Key\n"); ++ goto end; ++ } ++ ++ EVP_PKEY_CTX_free(genctx); ++ genctx = NULL; ++ ++ app_RAND_write_file(randfile); ++ ++ if (keyout == NULL) { ++ keyout = NCONF_get_string(req_conf, SECTION, KEYFILE); ++ if (keyout == NULL) ++ ERR_clear_error(); ++ } ++ ++ if (keyout == NULL) ++ BIO_printf(bio_err, "writing new private key to stdout\n"); ++ else ++ BIO_printf(bio_err, "writing new private key to '%s'\n", keyout); ++ out = bio_open_owner(keyout, outformat, private); ++ if (out == NULL) ++ goto end; ++ ++ p = NCONF_get_string(req_conf, SECTION, "encrypt_rsa_key"); ++ if (p == NULL) { ++ ERR_clear_error(); ++ p = NCONF_get_string(req_conf, SECTION, "encrypt_key"); ++ if (p == NULL) ++ ERR_clear_error(); ++ } ++ if ((p != NULL) && (strcmp(p, "no") == 0)) ++ cipher = NULL; ++ if (nodes) ++ cipher = NULL; ++ ++ i = 0; ++ loop: ++ assert(private); ++ if (!PEM_write_bio_PrivateKey(out, pkey, cipher, ++ NULL, 0, NULL, passout)) { ++ if ((ERR_GET_REASON(ERR_peek_error()) == ++ PEM_R_PROBLEMS_GETTING_PASSWORD) && (i < 3)) { ++ ERR_clear_error(); ++ i++; ++ goto loop; ++ } ++ goto end; ++ } ++ BIO_free(out); ++ out = NULL; ++ BIO_printf(bio_err, "-----\n"); ++ } ++ ++ if (!newreq) { ++ in = bio_open_default(infile, 'r', informat); ++ if (in == NULL) ++ goto end; ++ ++ if (informat == FORMAT_ASN1) ++ req = d2i_X509_REQ_bio(in, NULL); ++ else ++ req = PEM_read_bio_X509_REQ(in, NULL, NULL, NULL); ++ if (req == NULL) { ++ BIO_printf(bio_err, "unable to load X509 request\n"); ++ goto end; ++ } ++ } ++ ++ if (newreq) { ++ if (pkey == NULL) { ++ BIO_printf(bio_err, "you need to specify a private key\n"); ++ goto end; ++ } ++ ++ if (req == NULL) { ++ req = X509_REQ_new(); ++ if (req == NULL) { ++ goto end; ++ } ++ ++ i = make_REQ(req, pkey, subj, multirdn, !x509, chtype); ++ subj = NULL; /* done processing '-subj' option */ ++ if (!i) { ++ BIO_printf(bio_err, "problems making Certificate Request\n"); ++ goto end; ++ } ++ } ++ if (x509) { ++ EVP_PKEY *tmppkey; ++ X509V3_CTX ext_ctx; ++ if ((x509ss = X509_new()) == NULL) ++ goto end; ++ ++ /* Set version to V3 */ ++ if (extensions && !X509_set_version(x509ss, 2)) ++ goto end; ++ if (serial) { ++ if (!X509_set_serialNumber(x509ss, serial)) ++ goto end; ++ } else { ++ if (!rand_serial(NULL, X509_get_serialNumber(x509ss))) ++ goto end; ++ } ++ ++ if (!X509_set_issuer_name(x509ss, X509_REQ_get_subject_name(req))) ++ goto end; ++ if (!set_cert_times(x509ss, NULL, NULL, days)) ++ goto end; ++ if (!X509_set_subject_name ++ (x509ss, X509_REQ_get_subject_name(req))) ++ goto end; ++ tmppkey = X509_REQ_get0_pubkey(req); ++ if (!tmppkey || !X509_set_pubkey(x509ss, tmppkey)) ++ goto end; ++ ++ /* Set up V3 context struct */ ++ ++ X509V3_set_ctx(&ext_ctx, x509ss, x509ss, NULL, NULL, 0); ++ X509V3_set_nconf(&ext_ctx, req_conf); ++ ++ /* Add extensions */ ++ if (extensions && !X509V3_EXT_add_nconf(req_conf, ++ &ext_ctx, extensions, ++ x509ss)) { ++ BIO_printf(bio_err, "Error Loading extension section %s\n", ++ extensions); ++ goto end; ++ } ++ ++ i = do_X509_sign(x509ss, pkey, digest, sigopts); ++ if (!i) { ++ ERR_print_errors(bio_err); ++ goto end; ++ } ++ } else { ++ X509V3_CTX ext_ctx; ++ ++ /* Set up V3 context struct */ ++ ++ X509V3_set_ctx(&ext_ctx, NULL, NULL, req, NULL, 0); ++ X509V3_set_nconf(&ext_ctx, req_conf); ++ ++ /* Add extensions */ ++ if (req_exts && !X509V3_EXT_REQ_add_nconf(req_conf, ++ &ext_ctx, req_exts, ++ req)) { ++ BIO_printf(bio_err, "Error Loading extension section %s\n", ++ req_exts); ++ goto end; ++ } ++ i = do_X509_REQ_sign(req, pkey, digest, sigopts); ++ if (!i) { ++ ERR_print_errors(bio_err); ++ goto end; ++ } ++ } ++ } ++ ++ if (subj && x509) { ++ BIO_printf(bio_err, "Cannot modify certificate subject\n"); ++ goto end; ++ } ++ ++ if (subj && !x509) { ++ if (verbose) { ++ BIO_printf(bio_err, "Modifying Request's Subject\n"); ++ print_name(bio_err, "old subject=", ++ X509_REQ_get_subject_name(req), nmflag); ++ } ++ ++ if (build_subject(req, subj, chtype, multirdn) == 0) { ++ BIO_printf(bio_err, "ERROR: cannot modify subject\n"); ++ ret = 1; ++ goto end; ++ } ++ ++ if (verbose) { ++ print_name(bio_err, "new subject=", ++ X509_REQ_get_subject_name(req), nmflag); ++ } ++ } ++ ++ if (verify && !x509) { ++ EVP_PKEY *tpubkey = pkey; ++ ++ if (tpubkey == NULL) { ++ tpubkey = X509_REQ_get0_pubkey(req); ++ if (tpubkey == NULL) ++ goto end; ++ } ++ ++ i = X509_REQ_verify(req, tpubkey); ++ ++ if (i < 0) { ++ goto end; ++ } else if (i == 0) { ++ BIO_printf(bio_err, "verify failure\n"); ++ ERR_print_errors(bio_err); ++ } else /* if (i > 0) */ ++ BIO_printf(bio_err, "verify OK\n"); ++ } ++ ++ if (noout && !text && !modulus && !subject && !pubkey) { ++ ret = 0; ++ goto end; ++ } ++ ++ out = bio_open_default(outfile, ++ keyout != NULL && outfile != NULL && ++ strcmp(keyout, outfile) == 0 ? 'a' : 'w', ++ outformat); ++ if (out == NULL) ++ goto end; ++ ++ if (pubkey) { ++ EVP_PKEY *tpubkey = X509_REQ_get0_pubkey(req); ++ ++ if (tpubkey == NULL) { ++ BIO_printf(bio_err, "Error getting public key\n"); ++ ERR_print_errors(bio_err); ++ goto end; ++ } ++ PEM_write_bio_PUBKEY(out, tpubkey); ++ } ++ ++ if (text) { ++ if (x509) ++ X509_print_ex(out, x509ss, nmflag, reqflag); ++ else ++ X509_REQ_print_ex(out, req, nmflag, reqflag); ++ } ++ ++ if (subject) { ++ if (x509) ++ print_name(out, "subject=", X509_get_subject_name(x509ss), ++ nmflag); ++ else ++ print_name(out, "subject=", X509_REQ_get_subject_name(req), ++ nmflag); ++ } ++ ++ if (modulus) { ++ EVP_PKEY *tpubkey; ++ ++ if (x509) ++ tpubkey = X509_get0_pubkey(x509ss); ++ else ++ tpubkey = X509_REQ_get0_pubkey(req); ++ if (tpubkey == NULL) { ++ fprintf(stdout, "Modulus=unavailable\n"); ++ goto end; ++ } ++ fprintf(stdout, "Modulus="); ++#ifndef OPENSSL_NO_RSA ++ if (EVP_PKEY_base_id(tpubkey) == EVP_PKEY_RSA) { ++ const BIGNUM *n; ++ RSA_get0_key(EVP_PKEY_get0_RSA(tpubkey), &n, NULL, NULL); ++ BN_print(out, n); ++ } else ++#endif ++ fprintf(stdout, "Wrong Algorithm type"); ++ fprintf(stdout, "\n"); ++ } ++ ++ if (!noout && !x509) { ++ if (outformat == FORMAT_ASN1) ++ i = i2d_X509_REQ_bio(out, req); ++ else if (newhdr) ++ i = PEM_write_bio_X509_REQ_NEW(out, req); ++ else ++ i = PEM_write_bio_X509_REQ(out, req); ++ if (!i) { ++ BIO_printf(bio_err, "unable to write X509 request\n"); ++ goto end; ++ } ++ } ++ if (!noout && x509 && (x509ss != NULL)) { ++ if (outformat == FORMAT_ASN1) ++ i = i2d_X509_bio(out, x509ss); ++ else ++ i = PEM_write_bio_X509(out, x509ss); ++ if (!i) { ++ BIO_printf(bio_err, "unable to write X509 certificate\n"); ++ goto end; ++ } ++ } ++ ret = 0; ++ end: ++ if (ret) { ++ ERR_print_errors(bio_err); ++ } ++ NCONF_free(req_conf); ++ BIO_free(in); ++ BIO_free_all(out); ++ EVP_PKEY_free(pkey); ++ EVP_PKEY_CTX_free(genctx); ++ sk_OPENSSL_STRING_free(pkeyopts); ++ sk_OPENSSL_STRING_free(sigopts); ++#ifndef OPENSSL_NO_ENGINE ++ ENGINE_free(gen_eng); ++#endif ++ OPENSSL_free(keyalgstr); ++ X509_REQ_free(req); ++ X509_free(x509ss); ++ ASN1_INTEGER_free(serial); ++ release_engine(e); ++ if (passin != nofree_passin) ++ OPENSSL_free(passin); ++ if (passout != nofree_passout) ++ OPENSSL_free(passout); ++ return (ret); ++} ++ ++static int make_REQ(X509_REQ *req, EVP_PKEY *pkey, char *subj, int multirdn, ++ int attribs, unsigned long chtype) ++{ ++ int ret = 0, i; ++ char no_prompt = 0; ++ STACK_OF(CONF_VALUE) *dn_sk, *attr_sk = NULL; ++ char *tmp, *dn_sect, *attr_sect; ++ ++ tmp = NCONF_get_string(req_conf, SECTION, PROMPT); ++ if (tmp == NULL) ++ ERR_clear_error(); ++ if ((tmp != NULL) && strcmp(tmp, "no") == 0) ++ no_prompt = 1; ++ ++ dn_sect = NCONF_get_string(req_conf, SECTION, DISTINGUISHED_NAME); ++ if (dn_sect == NULL) { ++ BIO_printf(bio_err, "unable to find '%s' in config\n", ++ DISTINGUISHED_NAME); ++ goto err; ++ } ++ dn_sk = NCONF_get_section(req_conf, dn_sect); ++ if (dn_sk == NULL) { ++ BIO_printf(bio_err, "unable to get '%s' section\n", dn_sect); ++ goto err; ++ } ++ ++ attr_sect = NCONF_get_string(req_conf, SECTION, ATTRIBUTES); ++ if (attr_sect == NULL) { ++ ERR_clear_error(); ++ attr_sk = NULL; ++ } else { ++ attr_sk = NCONF_get_section(req_conf, attr_sect); ++ if (attr_sk == NULL) { ++ BIO_printf(bio_err, "unable to get '%s' section\n", attr_sect); ++ goto err; ++ } ++ } ++ ++ /* setup version number */ ++ if (!X509_REQ_set_version(req, 0L)) ++ goto err; /* version 1 */ ++ ++ if (subj) ++ i = build_subject(req, subj, chtype, multirdn); ++ else if (no_prompt) ++ i = auto_info(req, dn_sk, attr_sk, attribs, chtype); ++ else ++ i = prompt_info(req, dn_sk, dn_sect, attr_sk, attr_sect, attribs, ++ chtype); ++ if (!i) ++ goto err; ++ ++ if (!X509_REQ_set_pubkey(req, pkey)) ++ goto err; ++ ++ ret = 1; ++ err: ++ return (ret); ++} ++ ++/* ++ * subject is expected to be in the format /type0=value0/type1=value1/type2=... ++ * where characters may be escaped by \ ++ */ ++static int build_subject(X509_REQ *req, const char *subject, unsigned long chtype, ++ int multirdn) ++{ ++ X509_NAME *n; ++ ++ if ((n = parse_name(subject, chtype, multirdn)) == NULL) ++ return 0; ++ ++ if (!X509_REQ_set_subject_name(req, n)) { ++ X509_NAME_free(n); ++ return 0; ++ } ++ X509_NAME_free(n); ++ return 1; ++} ++ ++static int prompt_info(X509_REQ *req, ++ STACK_OF(CONF_VALUE) *dn_sk, const char *dn_sect, ++ STACK_OF(CONF_VALUE) *attr_sk, const char *attr_sect, ++ int attribs, unsigned long chtype) ++{ ++ int i; ++ char *p, *q; ++ char buf[100]; ++ int nid, mval; ++ long n_min, n_max; ++ char *type, *value; ++ const char *def; ++ CONF_VALUE *v; ++ X509_NAME *subj; ++ subj = X509_REQ_get_subject_name(req); ++ ++ if (!batch) { ++ BIO_printf(bio_err, ++ "You are about to be asked to enter information that will be incorporated\n"); ++ BIO_printf(bio_err, "into your certificate request.\n"); ++ BIO_printf(bio_err, ++ "What you are about to enter is what is called a Distinguished Name or a DN.\n"); ++ BIO_printf(bio_err, ++ "There are quite a few fields but you can leave some blank\n"); ++ BIO_printf(bio_err, ++ "For some fields there will be a default value,\n"); ++ BIO_printf(bio_err, ++ "If you enter '.', the field will be left blank.\n"); ++ BIO_printf(bio_err, "-----\n"); ++ } ++ ++ if (sk_CONF_VALUE_num(dn_sk)) { ++ i = -1; ++ start:for (;;) { ++ i++; ++ if (sk_CONF_VALUE_num(dn_sk) <= i) ++ break; ++ ++ v = sk_CONF_VALUE_value(dn_sk, i); ++ p = q = NULL; ++ type = v->name; ++ if (!check_end(type, "_min") || !check_end(type, "_max") || ++ !check_end(type, "_default") || !check_end(type, "_value")) ++ continue; ++ /* ++ * Skip past any leading X. X: X, etc to allow for multiple ++ * instances ++ */ ++ for (p = v->name; *p; p++) ++ if ((*p == ':') || (*p == ',') || (*p == '.')) { ++ p++; ++ if (*p) ++ type = p; ++ break; ++ } ++ if (*type == '+') { ++ mval = -1; ++ type++; ++ } else ++ mval = 0; ++ /* If OBJ not recognised ignore it */ ++ if ((nid = OBJ_txt2nid(type)) == NID_undef) ++ goto start; ++ if (BIO_snprintf(buf, sizeof buf, "%s_default", v->name) ++ >= (int)sizeof(buf)) { ++ BIO_printf(bio_err, "Name '%s' too long\n", v->name); ++ return 0; ++ } ++ ++ if ((def = NCONF_get_string(req_conf, dn_sect, buf)) == NULL) { ++ ERR_clear_error(); ++ def = ""; ++ } ++ ++ BIO_snprintf(buf, sizeof buf, "%s_value", v->name); ++ if ((value = NCONF_get_string(req_conf, dn_sect, buf)) == NULL) { ++ ERR_clear_error(); ++ value = NULL; ++ } ++ ++ BIO_snprintf(buf, sizeof buf, "%s_min", v->name); ++ if (!NCONF_get_number(req_conf, dn_sect, buf, &n_min)) { ++ ERR_clear_error(); ++ n_min = -1; ++ } ++ ++ BIO_snprintf(buf, sizeof buf, "%s_max", v->name); ++ if (!NCONF_get_number(req_conf, dn_sect, buf, &n_max)) { ++ ERR_clear_error(); ++ n_max = -1; ++ } ++ ++ if (!add_DN_object(subj, v->value, def, value, nid, ++ n_min, n_max, chtype, mval)) ++ return 0; ++ } ++ if (X509_NAME_entry_count(subj) == 0) { ++ BIO_printf(bio_err, ++ "error, no objects specified in config file\n"); ++ return 0; ++ } ++ ++ if (attribs) { ++ if ((attr_sk != NULL) && (sk_CONF_VALUE_num(attr_sk) > 0) ++ && (!batch)) { ++ BIO_printf(bio_err, ++ "\nPlease enter the following 'extra' attributes\n"); ++ BIO_printf(bio_err, ++ "to be sent with your certificate request\n"); ++ } ++ ++ i = -1; ++ start2: for (;;) { ++ i++; ++ if ((attr_sk == NULL) || (sk_CONF_VALUE_num(attr_sk) <= i)) ++ break; ++ ++ v = sk_CONF_VALUE_value(attr_sk, i); ++ type = v->name; ++ if ((nid = OBJ_txt2nid(type)) == NID_undef) ++ goto start2; ++ ++ if (BIO_snprintf(buf, sizeof buf, "%s_default", type) ++ >= (int)sizeof(buf)) { ++ BIO_printf(bio_err, "Name '%s' too long\n", v->name); ++ return 0; ++ } ++ ++ if ((def = NCONF_get_string(req_conf, attr_sect, buf)) ++ == NULL) { ++ ERR_clear_error(); ++ def = ""; ++ } ++ ++ BIO_snprintf(buf, sizeof buf, "%s_value", type); ++ if ((value = NCONF_get_string(req_conf, attr_sect, buf)) ++ == NULL) { ++ ERR_clear_error(); ++ value = NULL; ++ } ++ ++ BIO_snprintf(buf, sizeof buf, "%s_min", type); ++ if (!NCONF_get_number(req_conf, attr_sect, buf, &n_min)) { ++ ERR_clear_error(); ++ n_min = -1; ++ } ++ ++ BIO_snprintf(buf, sizeof buf, "%s_max", type); ++ if (!NCONF_get_number(req_conf, attr_sect, buf, &n_max)) { ++ ERR_clear_error(); ++ n_max = -1; ++ } ++ ++ if (!add_attribute_object(req, ++ v->value, def, value, nid, n_min, ++ n_max, chtype)) ++ return 0; ++ } ++ } ++ } else { ++ BIO_printf(bio_err, "No template, please set one up.\n"); ++ return 0; ++ } ++ ++ return 1; ++ ++} ++ ++static int auto_info(X509_REQ *req, STACK_OF(CONF_VALUE) *dn_sk, ++ STACK_OF(CONF_VALUE) *attr_sk, int attribs, ++ unsigned long chtype) ++{ ++ int i, spec_char, plus_char; ++ char *p, *q; ++ char *type; ++ CONF_VALUE *v; ++ X509_NAME *subj; ++ ++ subj = X509_REQ_get_subject_name(req); ++ ++ for (i = 0; i < sk_CONF_VALUE_num(dn_sk); i++) { ++ int mval; ++ v = sk_CONF_VALUE_value(dn_sk, i); ++ p = q = NULL; ++ type = v->name; ++ /* ++ * Skip past any leading X. X: X, etc to allow for multiple instances ++ */ ++ for (p = v->name; *p; p++) { ++#ifndef CHARSET_EBCDIC ++ spec_char = ((*p == ':') || (*p == ',') || (*p == '.')); ++#else ++ spec_char = ((*p == os_toascii[':']) || (*p == os_toascii[',']) ++ || (*p == os_toascii['.'])); ++#endif ++ if (spec_char) { ++ p++; ++ if (*p) ++ type = p; ++ break; ++ } ++ } ++#ifndef CHARSET_EBCDIC ++ plus_char = (*type == '+'); ++#else ++ plus_char = (*type == os_toascii['+']); ++#endif ++ if (plus_char) { ++ type++; ++ mval = -1; ++ } else ++ mval = 0; ++ if (!X509_NAME_add_entry_by_txt(subj, type, chtype, ++ (unsigned char *)v->value, -1, -1, ++ mval)) ++ return 0; ++ ++ } ++ ++ if (!X509_NAME_entry_count(subj)) { ++ BIO_printf(bio_err, "error, no objects specified in config file\n"); ++ return 0; ++ } ++ if (attribs) { ++ for (i = 0; i < sk_CONF_VALUE_num(attr_sk); i++) { ++ v = sk_CONF_VALUE_value(attr_sk, i); ++ if (!X509_REQ_add1_attr_by_txt(req, v->name, chtype, ++ (unsigned char *)v->value, -1)) ++ return 0; ++ } ++ } ++ return 1; ++} ++ ++static int add_DN_object(X509_NAME *n, char *text, const char *def, ++ char *value, int nid, int n_min, int n_max, ++ unsigned long chtype, int mval) ++{ ++ int i, ret = 0; ++ char buf[1024]; ++ start: ++ if (!batch) ++ BIO_printf(bio_err, "%s [%s]:", text, def); ++ (void)BIO_flush(bio_err); ++ if (value != NULL) { ++ OPENSSL_strlcpy(buf, value, sizeof buf); ++ OPENSSL_strlcat(buf, "\n", sizeof buf); ++ BIO_printf(bio_err, "%s\n", value); ++ } else { ++ buf[0] = '\0'; ++ if (!batch) { ++ if (!fgets(buf, sizeof buf, stdin)) ++ return 0; ++ } else { ++ buf[0] = '\n'; ++ buf[1] = '\0'; ++ } ++ } ++ ++ if (buf[0] == '\0') ++ return (0); ++ else if (buf[0] == '\n') { ++ if ((def == NULL) || (def[0] == '\0')) ++ return (1); ++ OPENSSL_strlcpy(buf, def, sizeof buf); ++ OPENSSL_strlcat(buf, "\n", sizeof buf); ++ } else if ((buf[0] == '.') && (buf[1] == '\n')) ++ return (1); ++ ++ i = strlen(buf); ++ if (buf[i - 1] != '\n') { ++ BIO_printf(bio_err, "weird input :-(\n"); ++ return (0); ++ } ++ buf[--i] = '\0'; ++#ifdef CHARSET_EBCDIC ++ ebcdic2ascii(buf, buf, i); ++#endif ++ if (!req_check_len(i, n_min, n_max)) { ++ if (batch || value) ++ return 0; ++ goto start; ++ } ++ ++ if (!X509_NAME_add_entry_by_NID(n, nid, chtype, ++ (unsigned char *)buf, -1, -1, mval)) ++ goto err; ++ ret = 1; ++ err: ++ return (ret); ++} ++ ++static int add_attribute_object(X509_REQ *req, char *text, const char *def, ++ char *value, int nid, int n_min, ++ int n_max, unsigned long chtype) ++{ ++ int i; ++ static char buf[1024]; ++ ++ start: ++ if (!batch) ++ BIO_printf(bio_err, "%s [%s]:", text, def); ++ (void)BIO_flush(bio_err); ++ if (value != NULL) { ++ OPENSSL_strlcpy(buf, value, sizeof buf); ++ OPENSSL_strlcat(buf, "\n", sizeof buf); ++ BIO_printf(bio_err, "%s\n", value); ++ } else { ++ buf[0] = '\0'; ++ if (!batch) { ++ if (!fgets(buf, sizeof buf, stdin)) ++ return 0; ++ } else { ++ buf[0] = '\n'; ++ buf[1] = '\0'; ++ } ++ } ++ ++ if (buf[0] == '\0') ++ return (0); ++ else if (buf[0] == '\n') { ++ if ((def == NULL) || (def[0] == '\0')) ++ return (1); ++ OPENSSL_strlcpy(buf, def, sizeof buf); ++ OPENSSL_strlcat(buf, "\n", sizeof buf); ++ } else if ((buf[0] == '.') && (buf[1] == '\n')) ++ return (1); ++ ++ i = strlen(buf); ++ if (buf[i - 1] != '\n') { ++ BIO_printf(bio_err, "weird input :-(\n"); ++ return (0); ++ } ++ buf[--i] = '\0'; ++#ifdef CHARSET_EBCDIC ++ ebcdic2ascii(buf, buf, i); ++#endif ++ if (!req_check_len(i, n_min, n_max)) { ++ if (batch || value) ++ return 0; ++ goto start; ++ } ++ ++ if (!X509_REQ_add1_attr_by_NID(req, nid, chtype, ++ (unsigned char *)buf, -1)) { ++ BIO_printf(bio_err, "Error adding attribute\n"); ++ ERR_print_errors(bio_err); ++ goto err; ++ } ++ ++ return (1); ++ err: ++ return (0); ++} ++ ++static int req_check_len(int len, int n_min, int n_max) ++{ ++ if ((n_min > 0) && (len < n_min)) { ++ BIO_printf(bio_err, ++ "string is too short, it needs to be at least %d bytes long\n", ++ n_min); ++ return (0); ++ } ++ if ((n_max >= 0) && (len > n_max)) { ++ BIO_printf(bio_err, ++ "string is too long, it needs to be less than %d bytes long\n", ++ n_max); ++ return (0); ++ } ++ return (1); ++} ++ ++/* Check if the end of a string matches 'end' */ ++static int check_end(const char *str, const char *end) ++{ ++ int elen, slen; ++ const char *tmp; ++ elen = strlen(end); ++ slen = strlen(str); ++ if (elen > slen) ++ return 1; ++ tmp = str + slen - elen; ++ return strcmp(tmp, end); ++} ++ ++static EVP_PKEY_CTX *set_keygen_ctx(const char *gstr, ++ int *pkey_type, long *pkeylen, ++ char **palgnam, ENGINE *keygen_engine) ++{ ++ EVP_PKEY_CTX *gctx = NULL; ++ EVP_PKEY *param = NULL; ++ long keylen = -1; ++ BIO *pbio = NULL; ++ const char *paramfile = NULL; ++ ++ if (gstr == NULL) { ++ *pkey_type = EVP_PKEY_RSA; ++ keylen = *pkeylen; ++ } else if (gstr[0] >= '0' && gstr[0] <= '9') { ++ *pkey_type = EVP_PKEY_RSA; ++ keylen = atol(gstr); ++ *pkeylen = keylen; ++ } else if (strncmp(gstr, "param:", 6) == 0) ++ paramfile = gstr + 6; ++ else { ++ const char *p = strchr(gstr, ':'); ++ int len; ++ ENGINE *tmpeng; ++ const EVP_PKEY_ASN1_METHOD *ameth; ++ ++ if (p) ++ len = p - gstr; ++ else ++ len = strlen(gstr); ++ /* ++ * The lookup of a the string will cover all engines so keep a note ++ * of the implementation. ++ */ ++ ++ ameth = EVP_PKEY_asn1_find_str(&tmpeng, gstr, len); ++ ++ if (!ameth) { ++ BIO_printf(bio_err, "Unknown algorithm %.*s\n", len, gstr); ++ return NULL; ++ } ++ ++ EVP_PKEY_asn1_get0_info(NULL, pkey_type, NULL, NULL, NULL, ameth); ++#ifndef OPENSSL_NO_ENGINE ++ ENGINE_finish(tmpeng); ++#endif ++ if (*pkey_type == EVP_PKEY_RSA) { ++ if (p) { ++ keylen = atol(p + 1); ++ *pkeylen = keylen; ++ } else ++ keylen = *pkeylen; ++ } else if (p) ++ paramfile = p + 1; ++ } ++ ++ if (paramfile) { ++ pbio = BIO_new_file(paramfile, "r"); ++ if (!pbio) { ++ BIO_printf(bio_err, "Can't open parameter file %s\n", paramfile); ++ return NULL; ++ } ++ param = PEM_read_bio_Parameters(pbio, NULL); ++ ++ if (!param) { ++ X509 *x; ++ (void)BIO_reset(pbio); ++ x = PEM_read_bio_X509(pbio, NULL, NULL, NULL); ++ if (x) { ++ param = X509_get_pubkey(x); ++ X509_free(x); ++ } ++ } ++ ++ BIO_free(pbio); ++ ++ if (!param) { ++ BIO_printf(bio_err, "Error reading parameter file %s\n", paramfile); ++ return NULL; ++ } ++ if (*pkey_type == -1) ++ *pkey_type = EVP_PKEY_id(param); ++ else if (*pkey_type != EVP_PKEY_base_id(param)) { ++ BIO_printf(bio_err, "Key Type does not match parameters\n"); ++ EVP_PKEY_free(param); ++ return NULL; ++ } ++ } ++ ++ if (palgnam) { ++ const EVP_PKEY_ASN1_METHOD *ameth; ++ ENGINE *tmpeng; ++ const char *anam; ++ ameth = EVP_PKEY_asn1_find(&tmpeng, *pkey_type); ++ if (!ameth) { ++ BIO_puts(bio_err, "Internal error: can't find key algorithm\n"); ++ return NULL; ++ } ++ EVP_PKEY_asn1_get0_info(NULL, NULL, NULL, NULL, &anam, ameth); ++ *palgnam = OPENSSL_strdup(anam); ++#ifndef OPENSSL_NO_ENGINE ++ ENGINE_finish(tmpeng); ++#endif ++ } ++ ++ if (param) { ++ gctx = EVP_PKEY_CTX_new(param, keygen_engine); ++ *pkeylen = EVP_PKEY_bits(param); ++ EVP_PKEY_free(param); ++ } else ++ gctx = EVP_PKEY_CTX_new_id(*pkey_type, keygen_engine); ++ ++ if (gctx == NULL) { ++ BIO_puts(bio_err, "Error allocating keygen context\n"); ++ ERR_print_errors(bio_err); ++ return NULL; ++ } ++ ++ if (EVP_PKEY_keygen_init(gctx) <= 0) { ++ BIO_puts(bio_err, "Error initializing keygen context\n"); ++ ERR_print_errors(bio_err); ++ EVP_PKEY_CTX_free(gctx); ++ return NULL; ++ } ++#ifndef OPENSSL_NO_RSA ++ if ((*pkey_type == EVP_PKEY_RSA) && (keylen != -1)) { ++ if (EVP_PKEY_CTX_set_rsa_keygen_bits(gctx, keylen) <= 0) { ++ BIO_puts(bio_err, "Error setting RSA keysize\n"); ++ ERR_print_errors(bio_err); ++ EVP_PKEY_CTX_free(gctx); ++ return NULL; ++ } ++ } ++#endif ++ ++ return gctx; ++} ++ ++static int genpkey_cb(EVP_PKEY_CTX *ctx) ++{ ++ char c = '*'; ++ BIO *b = EVP_PKEY_CTX_get_app_data(ctx); ++ int p; ++ p = EVP_PKEY_CTX_get_keygen_info(ctx, 0); ++ if (p == 0) ++ c = '.'; ++ if (p == 1) ++ c = '+'; ++ if (p == 2) ++ c = '*'; ++ if (p == 3) ++ c = '\n'; ++ BIO_write(b, &c, 1); ++ (void)BIO_flush(b); ++ return 1; ++} ++ ++static int do_sign_init(EVP_MD_CTX *ctx, EVP_PKEY *pkey, ++ const EVP_MD *md, STACK_OF(OPENSSL_STRING) *sigopts) ++{ ++ EVP_PKEY_CTX *pkctx = NULL; ++ int i; ++ ++ if (ctx == NULL) ++ return 0; ++ if (!EVP_DigestSignInit(ctx, &pkctx, md, NULL, pkey)) ++ return 0; ++ for (i = 0; i < sk_OPENSSL_STRING_num(sigopts); i++) { ++ char *sigopt = sk_OPENSSL_STRING_value(sigopts, i); ++ if (pkey_ctrl_string(pkctx, sigopt) <= 0) { ++ BIO_printf(bio_err, "parameter error \"%s\"\n", sigopt); ++ ERR_print_errors(bio_err); ++ return 0; ++ } ++ } ++ return 1; ++} ++ ++int do_X509_sign(X509 *x, EVP_PKEY *pkey, const EVP_MD *md, ++ STACK_OF(OPENSSL_STRING) *sigopts) ++{ ++ int rv; ++ EVP_MD_CTX *mctx = EVP_MD_CTX_new(); ++ ++ rv = do_sign_init(mctx, pkey, md, sigopts); ++ if (rv > 0) ++ rv = X509_sign_ctx(x, mctx); ++ EVP_MD_CTX_free(mctx); ++ return rv > 0 ? 1 : 0; ++} ++ ++int do_X509_REQ_sign(X509_REQ *x, EVP_PKEY *pkey, const EVP_MD *md, ++ STACK_OF(OPENSSL_STRING) *sigopts) ++{ ++ int rv; ++ EVP_MD_CTX *mctx = EVP_MD_CTX_new(); ++ rv = do_sign_init(mctx, pkey, md, sigopts); ++ if (rv > 0) ++ rv = X509_REQ_sign_ctx(x, mctx); ++ EVP_MD_CTX_free(mctx); ++ return rv > 0 ? 1 : 0; ++} ++ ++int do_X509_CRL_sign(X509_CRL *x, EVP_PKEY *pkey, const EVP_MD *md, ++ STACK_OF(OPENSSL_STRING) *sigopts) ++{ ++ int rv; ++ EVP_MD_CTX *mctx = EVP_MD_CTX_new(); ++ rv = do_sign_init(mctx, pkey, md, sigopts); ++ if (rv > 0) ++ rv = X509_CRL_sign_ctx(x, mctx); ++ EVP_MD_CTX_free(mctx); ++ return rv > 0 ? 1 : 0; ++} +diff --git a/CryptoPkg/Library/OpensslLib/openssl/apps/req.pem b/CryptoPkg/Library/OpensslLib/openssl/apps/req.pem +new file mode 100644 +index 0000000..5537df6 +--- /dev/null ++++ b/CryptoPkg/Library/OpensslLib/openssl/apps/req.pem +@@ -0,0 +1,11 @@ ++-----BEGIN CERTIFICATE REQUEST----- ++MIIBlzCCAVcCAQAwXjELMAkGA1UEBhMCQVUxEzARBgNVBAgTClNvbWUtU3RhdGUx ++ITAfBgNVBAoTGEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDEXMBUGA1UEAxMORXJp ++YyB0aGUgWW91bmcwge8wgaYGBSsOAwIMMIGcAkEA+ZiKEvZmc9MtnaFZh4NiZ3oZ ++S4J1PHvPrm9MXj5ntVheDPkdmBDTncyaGAJcMjwsyB/GvLDGd6yGCw/8eF+09wIV ++AK3VagOxGd/Q4Af5NbxR5FB7CXEjAkA2t/q7HgVLi0KeKvcDG8BRl3wuy7bCvpjg ++tWiJc/tpvcuzeuAayH89UofjAGueKjXDADiRffvSdhrNw5dkqdqlA0QAAkEAtUSo ++84OekjitKGVjxLu0HvXck29pu+foad53vPKXAsuJdACj88BPqZ91Y9PIJf1GUh38 ++CuiHWi7z3cEDfZCyCKAAMAkGBSsOAwIbBQADLwAwLAIUTg8amKVBE9oqC5B75dDQ ++Chy3LdQCFHKodGEj3LjuTzdm/RTe2KZL9Uzf ++-----END CERTIFICATE REQUEST----- +diff --git a/CryptoPkg/Library/OpensslLib/openssl/apps/rsa.c b/CryptoPkg/Library/OpensslLib/openssl/apps/rsa.c +new file mode 100644 +index 0000000..35ab727 +--- /dev/null ++++ b/CryptoPkg/Library/OpensslLib/openssl/apps/rsa.c +@@ -0,0 +1,310 @@ ++/* ++ * Copyright 1995-2016 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 ++ * in the file LICENSE in the source distribution or at ++ * https://www.openssl.org/source/license.html ++ */ ++ ++#include ++#ifdef OPENSSL_NO_RSA ++NON_EMPTY_TRANSLATION_UNIT ++#else ++ ++# include ++# include ++# include ++# include ++# include "apps.h" ++# include ++# include ++# include ++# include ++# include ++# include ++# include ++ ++typedef enum OPTION_choice { ++ OPT_ERR = -1, OPT_EOF = 0, OPT_HELP, ++ OPT_INFORM, OPT_OUTFORM, OPT_ENGINE, OPT_IN, OPT_OUT, ++ OPT_PUBIN, OPT_PUBOUT, OPT_PASSOUT, OPT_PASSIN, ++ OPT_RSAPUBKEY_IN, OPT_RSAPUBKEY_OUT, ++ /* Do not change the order here; see case statements below */ ++ OPT_PVK_NONE, OPT_PVK_WEAK, OPT_PVK_STRONG, ++ OPT_NOOUT, OPT_TEXT, OPT_MODULUS, OPT_CHECK, OPT_CIPHER ++} OPTION_CHOICE; ++ ++OPTIONS rsa_options[] = { ++ {"help", OPT_HELP, '-', "Display this summary"}, ++ {"inform", OPT_INFORM, 'f', "Input format, one of DER NET PEM"}, ++ {"outform", OPT_OUTFORM, 'f', "Output format, one of DER NET PEM PVK"}, ++ {"in", OPT_IN, 's', "Input file"}, ++ {"out", OPT_OUT, '>', "Output file"}, ++ {"pubin", OPT_PUBIN, '-', "Expect a public key in input file"}, ++ {"pubout", OPT_PUBOUT, '-', "Output a public key"}, ++ {"passout", OPT_PASSOUT, 's', "Output file pass phrase source"}, ++ {"passin", OPT_PASSIN, 's', "Input file pass phrase source"}, ++ {"RSAPublicKey_in", OPT_RSAPUBKEY_IN, '-', "Input is an RSAPublicKey"}, ++ {"RSAPublicKey_out", OPT_RSAPUBKEY_OUT, '-', "Output is an RSAPublicKey"}, ++ {"noout", OPT_NOOUT, '-', "Don't print key out"}, ++ {"text", OPT_TEXT, '-', "Print the key in text"}, ++ {"modulus", OPT_MODULUS, '-', "Print the RSA key modulus"}, ++ {"check", OPT_CHECK, '-', "Verify key consistency"}, ++ {"", OPT_CIPHER, '-', "Any supported cipher"}, ++# if !defined(OPENSSL_NO_DSA) && !defined(OPENSSL_NO_RC4) ++ {"pvk-strong", OPT_PVK_STRONG, '-', "Enable 'Strong' PVK encoding level (default)"}, ++ {"pvk-weak", OPT_PVK_WEAK, '-', "Enable 'Weak' PVK encoding level"}, ++ {"pvk-none", OPT_PVK_NONE, '-', "Don't enforce PVK encoding"}, ++# endif ++# ifndef OPENSSL_NO_ENGINE ++ {"engine", OPT_ENGINE, 's', "Use engine, possibly a hardware device"}, ++# endif ++ {NULL} ++}; ++ ++int rsa_main(int argc, char **argv) ++{ ++ ENGINE *e = NULL; ++ BIO *out = NULL; ++ RSA *rsa = NULL; ++ const EVP_CIPHER *enc = NULL; ++ char *infile = NULL, *outfile = NULL, *prog; ++ char *passin = NULL, *passout = NULL, *passinarg = NULL, *passoutarg = NULL; ++ int i, private = 0; ++ int informat = FORMAT_PEM, outformat = FORMAT_PEM, text = 0, check = 0; ++ int noout = 0, modulus = 0, pubin = 0, pubout = 0, ret = 1; ++# if !defined(OPENSSL_NO_DSA) && !defined(OPENSSL_NO_RC4) ++ int pvk_encr = 2; ++# endif ++ OPTION_CHOICE o; ++ ++ prog = opt_init(argc, argv, rsa_options); ++ while ((o = opt_next()) != OPT_EOF) { ++ switch (o) { ++ case OPT_EOF: ++ case OPT_ERR: ++ opthelp: ++ BIO_printf(bio_err, "%s: Use -help for summary.\n", prog); ++ goto end; ++ case OPT_HELP: ++ opt_help(rsa_options); ++ ret = 0; ++ goto end; ++ case OPT_INFORM: ++ if (!opt_format(opt_arg(), OPT_FMT_ANY, &informat)) ++ goto opthelp; ++ break; ++ case OPT_IN: ++ infile = opt_arg(); ++ break; ++ case OPT_OUTFORM: ++ if (!opt_format(opt_arg(), OPT_FMT_ANY, &outformat)) ++ goto opthelp; ++ break; ++ case OPT_OUT: ++ outfile = opt_arg(); ++ break; ++ case OPT_PASSIN: ++ passinarg = opt_arg(); ++ break; ++ case OPT_PASSOUT: ++ passoutarg = opt_arg(); ++ break; ++ case OPT_ENGINE: ++ e = setup_engine(opt_arg(), 0); ++ break; ++ case OPT_PUBIN: ++ pubin = 1; ++ break; ++ case OPT_PUBOUT: ++ pubout = 1; ++ break; ++ case OPT_RSAPUBKEY_IN: ++ pubin = 2; ++ break; ++ case OPT_RSAPUBKEY_OUT: ++ pubout = 2; ++ break; ++ case OPT_PVK_STRONG: /* pvk_encr:= 2 */ ++ case OPT_PVK_WEAK: /* pvk_encr:= 1 */ ++ case OPT_PVK_NONE: /* pvk_encr:= 0 */ ++# if !defined(OPENSSL_NO_DSA) && !defined(OPENSSL_NO_RC4) ++ pvk_encr = (o - OPT_PVK_NONE); ++# endif ++ break; ++ case OPT_NOOUT: ++ noout = 1; ++ break; ++ case OPT_TEXT: ++ text = 1; ++ break; ++ case OPT_MODULUS: ++ modulus = 1; ++ break; ++ case OPT_CHECK: ++ check = 1; ++ break; ++ case OPT_CIPHER: ++ if (!opt_cipher(opt_unknown(), &enc)) ++ goto opthelp; ++ break; ++ } ++ } ++ argc = opt_num_rest(); ++ if (argc != 0) ++ goto opthelp; ++ ++ private = (text && !pubin) || (!pubout && !noout) ? 1 : 0; ++ ++ if (!app_passwd(passinarg, passoutarg, &passin, &passout)) { ++ BIO_printf(bio_err, "Error getting passwords\n"); ++ goto end; ++ } ++ if (check && pubin) { ++ BIO_printf(bio_err, "Only private keys can be checked\n"); ++ goto end; ++ } ++ ++ { ++ EVP_PKEY *pkey; ++ ++ if (pubin) { ++ int tmpformat = -1; ++ if (pubin == 2) { ++ if (informat == FORMAT_PEM) ++ tmpformat = FORMAT_PEMRSA; ++ else if (informat == FORMAT_ASN1) ++ tmpformat = FORMAT_ASN1RSA; ++ } else ++ tmpformat = informat; ++ ++ pkey = load_pubkey(infile, tmpformat, 1, passin, e, "Public Key"); ++ } else ++ pkey = load_key(infile, informat, 1, passin, e, "Private Key"); ++ ++ if (pkey != NULL) ++ rsa = EVP_PKEY_get1_RSA(pkey); ++ EVP_PKEY_free(pkey); ++ } ++ ++ if (rsa == NULL) { ++ ERR_print_errors(bio_err); ++ goto end; ++ } ++ ++ out = bio_open_owner(outfile, outformat, private); ++ if (out == NULL) ++ goto end; ++ ++ if (text) { ++ assert(pubin || private); ++ if (!RSA_print(out, rsa, 0)) { ++ perror(outfile); ++ ERR_print_errors(bio_err); ++ goto end; ++ } ++ } ++ ++ if (modulus) { ++ const BIGNUM *n; ++ RSA_get0_key(rsa, &n, NULL, NULL); ++ BIO_printf(out, "Modulus="); ++ BN_print(out, n); ++ BIO_printf(out, "\n"); ++ } ++ ++ if (check) { ++ int r = RSA_check_key(rsa); ++ ++ if (r == 1) ++ BIO_printf(out, "RSA key ok\n"); ++ else if (r == 0) { ++ unsigned long err; ++ ++ while ((err = ERR_peek_error()) != 0 && ++ ERR_GET_LIB(err) == ERR_LIB_RSA && ++ ERR_GET_FUNC(err) == RSA_F_RSA_CHECK_KEY && ++ ERR_GET_REASON(err) != ERR_R_MALLOC_FAILURE) { ++ BIO_printf(out, "RSA key error: %s\n", ++ ERR_reason_error_string(err)); ++ ERR_get_error(); /* remove e from error stack */ ++ } ++ } else if (r == -1) { ++ ERR_print_errors(bio_err); ++ goto end; ++ } ++ } ++ ++ if (noout) { ++ ret = 0; ++ goto end; ++ } ++ BIO_printf(bio_err, "writing RSA key\n"); ++ if (outformat == FORMAT_ASN1) { ++ if (pubout || pubin) { ++ if (pubout == 2) ++ i = i2d_RSAPublicKey_bio(out, rsa); ++ else ++ i = i2d_RSA_PUBKEY_bio(out, rsa); ++ } else { ++ assert(private); ++ i = i2d_RSAPrivateKey_bio(out, rsa); ++ } ++ } ++ else if (outformat == FORMAT_PEM) { ++ if (pubout || pubin) { ++ if (pubout == 2) ++ i = PEM_write_bio_RSAPublicKey(out, rsa); ++ else ++ i = PEM_write_bio_RSA_PUBKEY(out, rsa); ++ } else { ++ assert(private); ++ i = PEM_write_bio_RSAPrivateKey(out, rsa, ++ enc, NULL, 0, NULL, passout); ++ } ++# ifndef OPENSSL_NO_DSA ++ } else if (outformat == FORMAT_MSBLOB || outformat == FORMAT_PVK) { ++ EVP_PKEY *pk; ++ pk = EVP_PKEY_new(); ++ EVP_PKEY_set1_RSA(pk, rsa); ++ if (outformat == FORMAT_PVK) { ++ if (pubin) { ++ BIO_printf(bio_err, "PVK form impossible with public key input\n"); ++ EVP_PKEY_free(pk); ++ goto end; ++ } ++ assert(private); ++# ifdef OPENSSL_NO_RC4 ++ BIO_printf(bio_err, "PVK format not supported\n"); ++ EVP_PKEY_free(pk); ++ goto end; ++# else ++ i = i2b_PVK_bio(out, pk, pvk_encr, 0, passout); ++# endif ++ } else if (pubin || pubout) { ++ i = i2b_PublicKey_bio(out, pk); ++ } else { ++ assert(private); ++ i = i2b_PrivateKey_bio(out, pk); ++ } ++ EVP_PKEY_free(pk); ++# endif ++ } else { ++ BIO_printf(bio_err, "bad output format specified for outfile\n"); ++ goto end; ++ } ++ if (i <= 0) { ++ BIO_printf(bio_err, "unable to write key\n"); ++ ERR_print_errors(bio_err); ++ } else ++ ret = 0; ++ end: ++ release_engine(e); ++ BIO_free_all(out); ++ RSA_free(rsa); ++ OPENSSL_free(passin); ++ OPENSSL_free(passout); ++ return (ret); ++} ++#endif +diff --git a/CryptoPkg/Library/OpensslLib/openssl/apps/rsa8192.pem b/CryptoPkg/Library/OpensslLib/openssl/apps/rsa8192.pem +new file mode 100644 +index 0000000..946a6e5 +--- /dev/null ++++ b/CryptoPkg/Library/OpensslLib/openssl/apps/rsa8192.pem +@@ -0,0 +1,101 @@ ++-----BEGIN RSA PRIVATE KEY----- ++ ++MIISKAIBAAKCBAEAiQ2f1X6Bte1DKD0OoCBKEikzPW+5w3oXk3WwnE97Wxzy6wJZ ++ebbZC3CZKKBnJeBMrysPf+lK+9+fP6Vm8bp1wvbcSIA59BDrX6irFSuM/bdnkbuF ++MFlDjt+uVrxwoyqfPi2IPot1HQg3l5mdyBqcTWvbOnU2L9HZxJfPUCjfzdTMPrMY ++55/A20XL7tlV2opEfwhy3uVlveQBM0DnZ3MUQfrk+lRRNWv7yE4ScbOfER9fjvOm ++yJc3ZbOa3e+AMGGU9OqJ/fyOl0SGYyP2k23omy/idBV4uOs8QWdnAvq8UOzDdua3 ++tuf5Tn17XBurPJ8juwyPBNispkwwn8BjxAZVPhwUIcxFBg339IxJ9cW0WdVy4nNA ++LWo/8Ahlf+kZNnFNGCPFytU9gGMLMhab9w/rLrwa9qNe4L8Fmu1JxONn1WfhMOKE ++aFmycf2olJsYLgUIGYZrjnYu0p/7P3yhTOv8JIhmK+SzmA/I0xiQoF84rpaQzH2d ++PvxICOA9oQSowou0gLuBSZWm6LiXirg1DZCziU46v33ErQlWM1dSyNaUSzihcV59 ++mVD0nmzboXH75lGiyiZlp8cLbozzoCwvk9rYqpUGSBzbAy0ECCpabGpzO2Ug+oDi ++71e5z4WMpeoR4IS8MaOG/GsJnwaXhiB/gNYfK+8pRADVk5StEAZDE2alSuCbDs0z ++d9zYr4/em5T9VZsLetxRE7pm/Es9yELuViz8/Tm0/8MVdmNYc/xZU1t6qYYFdyQ2 ++wlGDTiNPsjR8yXCkmBjKwqnuleu1X6LaZu3VPhEkXGcyFAquQUkSiMv0Yu74qAe0 ++bQ2v+jjZzP6AM9LUo89cW4Kd8SGD96BdNlAVPNMXoBcIOsZBwsOtETBd4KAyvkXE ++Ob17u+PLl4UPnSxm9ypKZunUNFRPxtKUyjySYnvlGL+kTjAXrIrZwKJqIn0uhnfa ++Ck3o7bU6yVMK22ODxy2/Vi3E0P6k5JLwnrF0VIOBqGhts66qo6mWDP8l6MZHARFd ++pU+nofssVmr8tLKmMmjYGMM5GmKIXRNBs0ksTwFnKRs9AmpE5owC8tTSVdTAkGuS ++os7QwLvyvNzq7BGJiVr0Iy3Dhsl1vzR35acNOrCsDl3DcCQONKJ2sVXV4pD3dBah ++mG3sR/jHgjasffJJ35uiGoAua9dbT7HG/+D0z1SHYaVqH8zO4VZSOnGJh/P9rtxx ++cckFDbiag/JMWig2lbnCjebTtp/BcUsK3TNaDOb7vb0LvbAeRJadd1EFu6PSlH3K ++LykSUPm4UedvUU3cWjqkSY5lITFJkVaIYOv/EljYtK7p7kFZFTaEwMAWxgsXU3pQ ++tTzVmq1gZ4vXPwcUq0zK50Frq0F7SQc21ZsunwIDAQABAoIEADuQAkDEpBausJsS ++PgL1RXuzECPJJJCBxTE+2qx0FoY4hJICCWTORHGmU8nGPE3Ht0wBiNDsULw6KXl9 ++psmzYW6D3qRbpdQebky6fu/KZ5H0XTyGpJGomaXELH5hkwo2gdKB805LSXB+m7p0 ++9o96kSdMkpBLVGtf5iZ8W4rY2LsZmlI9f7taQHSLVt/M8HTz1mTnBRU92QO3zZW6 ++xVa+OrWaFl18u3ZeIaSh2X40tBK68cqstXVD0r2OWuXNKobcQeJW8/XABzBShZ0c ++ihL0lzyqiN4uXrLu+Nbr22b+FU2OODy6dGk3U6/69NvI4piMCPlHsfhHOnFjd1ZW ++RIVywyUlCtLNdcn11CchuRro+0J3c2Ba+i9Cl9r3qzT11xFEGF8/XLyUBBCB+uGf ++1dR/xJQhCA7cXWWLXyI/semxcvTaGpImP6kiIl1MAjHjXZTSdvyw4JmfXyYGhSjI ++P0mw3Xn7FXxJ/os9gOfNKz2nZHjr0q4sgWRYO+4vllkeL0GteZrg4oVaVpmZb7LH ++77afhodLylhijlEtV5skfkPujbBLQk6E5Ez3U/huEt2NLg6guADmwxMxfBRliZO4 ++4Ex/td4cuggpEj3FGJV74qRvdvj/MF/uF7IxC/3WapPIsFBFH4zrJsUYt6u3L68I ++/KC/bfioDeUR/8ANw1DNh+UsnPV3GJIwDkIJKdppi2uXPahJyJQQ8Inps53nn8Gg ++GifS+HnOXNgMoKOJnZ9IDGjXpfjIs8dJNrGfDHF0mH30N2WARq2v/a3cNUC+f8Bq ++HSKQ9YrZopktMunsut8u7ZYbTmjIqJpXCaM0CCrSlzSMTDHFSj2tzLk6+qnxeGxB ++ZwIdShbdeK+0ETG91lE1e9RPQs/uXQP9+uCHJV0YpqQcA6pkCLYJfYpoSMu/Bafy ++AgfVZz6l5tyEnV0wCcbopsQShc1k9xtTbYNF1h9AQHknj6zeDW4iZMvmVeh3RovT ++52OA2R8oLyauF+QaG6x2wUjEx13SJlaBarJZ4seZIOJ+a8+oNzKsbgokXc2cyC9p ++5FAZz1OsOb68o93qD1Xvl7bY97fq2q55L7G1XHPPLtZE5lGiLGDtnAuwY8UPrdpr ++7Mv2yIxB7xVGurXyHb5PvusR88XED6HMPfLBG/55ENHTal7G5mRix+IWSBAIkxA5 ++KZ0j8r5Ng4+wELZhqFQai39799bIAyiV6CEz4kyDXlo0kSSexp8o4iz5sPq5vp6h ++cCb7rdRw7uRnbXrHmXahxoB+ibXaurgV/6B2yurrU/UFoxEp2sHp8LXZGfF6ztY1 ++dMhSQAACK2vGy5yNagbkTHLgVaHicG5zavJBqzCE+lbPlCqhOUQPdOIwvjHNjdS/ ++DL3WV/ECggIBAMbW65wPk/i43nSyeZeYwcHtR1SUJqDXavYfBPC0VRhKz+7DVMFw ++Nwnocn6gITABc445W1yl7U3uww+LGuDlSlFnd8WuiXpVYud9/jeNu6Mu4wvNsnWr ++f4f4ua8CcS03GmqmcbROD2Z6by1AblCZ2UL1kv9cUX1FLVjPP1ESAGKoePt3BmZQ ++J1uJfK8HilNT8dcUlj/5CBi2uHxttDhoG0sxXE/SVsG9OD/Pjme0mj7gdzc6Ztd+ ++TALuvpNQR4pRzfo5XWDZBcEYntcEE3PxYJB1+vnZ8509ew5/yLHTbLjFxIcx71zY ++fhH0gM36Sz7mz37r0+E/QkRkc5bVIDC4LDnWmjpAde6QUx0d218ShNx6sJo4kt5c ++Dd7tEVx8nuX8AIZYgwsOb382anLyFRkkmEdK3gRvwQ6SWR36Ez5L7/mHWODpLAX5 ++mVBKSG4/ccFbc633/g0xHw0Nwajir/klckdakuYPlwF0yAxJSKDLhmNctDhRmxjC ++YP+fISkl5oTvFRzJH6HEyNu8M3ybRvmpPIjM5J5JpnB2IYbohYBR+T6/97C1DKrd ++mzL5PjlrWm0c1/d7LlDoP65fOShDMmj2zCiBAHHOM0Alokx+v5LmMd8NJumZIwGJ ++Rt5OpeMOhowz6j1AjYxYgV7PmJL6Ovpfb775od/aLaUbbwHz2uWIvfF7AoICAQCw ++c7NaO7oJVLJClhYw6OCvjT6oqtgNVWaennnDiJgzY9lv5HEgV0MAG0eYuB3hvj+w ++Y1P9DJxP1D+R+cshYrAFg8yU/3kaYVNI0Bl3ygX0eW1b/0HZTdocs+8kM/9PZQDR ++WrKQoU5lHvqRt99dXlD4NWGI2YQtzdZ8iet9QLqnjwRZabgE96mF01qKisMnFcsh ++KjT7ieheU4J15TZj/mdZRNK126d7e3q/rNj73e5EJ9tkYLcolSr4gpknUMJULSEi ++JH1/Qx7C/mTAMRsN5SkOthnGq0djCNWfPv/3JV0H67Uf5krFlnwLebrgfTYoPPdo ++yO7iBUNJzv6Qh22malLp4P8gzACkD7DGlSTnoB5cLwcjmDGg+i9WrUBbOiVTeQfZ ++kOj1o+Tz35ndpq/DDUVlqliB9krcxva+QHeJPH53EGI+YVg1nD+s/vUDZ3mQMGX9 ++DQou2L8uU6RnWNv/BihGcL8QvS4Ty6QyPOUPpD3zc70JQAEcQk9BxQNaELgJX0IN ++22cYn22tYvElew9G41OpDqzBRcfbdJmKXQ2HcroShutYJQRGUpAXHk24fy6JVkIU ++ojF5U6cwextMja1ZIIZgh9eugIRUeIE7319nQNDzuXWjRCcoBLA25P7wnpHWDRpz ++D9ovXCIvdja74lL5psqobV6L5+fbLPkSgXoImKR0LQKCAgAIC9Jk8kxumCyIVGCP ++PeM5Uby9M3GMuKrfYsn0Y5e97+kSJF1dpojTodBgR2KQar6eVrvXt+8uZCcIjfx8 ++dUrYmHNEUJfHl4T1ESgkX1vkcpVFeQFruZDjk7EP3+1sgvpSroGTZkVBRFsTXbQZ ++FuCv0Pgt1TKG+zGmklxhj3TsiRy8MEjWAxBUp++ftZJnZNI4feDGnfEx7tLwVhAg ++6DWSiWDO6hgQpvOLwX5lu+0x9itc1MQsnDO/OqIDnBAJDN5k7cVVkfKlqbVjxgpz ++eqUJs3yAd81f44kDQTCB4ahYocgeIGsrOqd/WoGL1EEPPo/O9wQP7VtlIRt8UwuG ++bS18+a4sBUfAa56xYu/pnPo7YcubsgZfcSIujzFQqMpVTClJRnOnEuJ4J1+PXzRz ++XAO9fs4VJ+CMEmgAyonUz4Xadxulnknlw//sO9VKgM69oFHCDHL/XamAAbqAdwvf ++7R/+uy+Ol7romC0wMhb6SsIZazrvvH2mNtduAKZ638nAP1x/WbQp+6iVG7yJok7w ++82Q7tO7baOePTXh12Rrt4mNPor0HLYxhra4GFgfqkumJ2Mz0esuZAozxJXFOq8ly ++beo9CVtXP5zbT6qNpeNismX6PLICaev8t+1iOZSE56WSLtefuuj/cOVrTMNDz1Rr ++pUkEVV2zjUSjlcScM538A9iL2QKCAgBLbBk0r6T0ihRsK9UucMxhnYEz/Vq+UEu9 ++70Vi1AciqEJv9nh4d3Q3HnH7EHANZxG4Jqzm1DYYVUQa9GfkTFeq88xFv/GW2hUM ++YY8RSfRDrIeXNEOETCe37x2AHw25dRXlZtw+wARPau91y9+Y/FCl18NqCHfcUEin ++ERjsf/eI2bPlODAlR2tZvZ7M60VBdqpN8cmV3zvI3e88z43xLfQlDyr1+v7a5Evy ++lEJnXlSTI2o+vKxtl103vjMSwA1gh63K90gBVsJWXQDZueOzi8mB9UqNRfcMmOEe ++4YHttTXPxeu0x+4cCRfam9zKShsVFgI28vRQ/ijl6qmbQ5gV8wqf18GV1j1L4z0P ++lP6iVynDA4MMrug/w9DqPsHsfK0pwekeETfSj4y0xVXyjWZBfHG2ZBrS6mDTf+RG ++LC4sJgR0hjdILLnUqIX7PzuhieBHRrjBcopwvcryVWRHnI7kslAS0+yHjiWc5oW3 ++x5mtlum4HzelNYuD9cAE/95P6CeSMfp9CyIE/KSX4VvsRm6gQVkoQRKMxnQIFQ3w ++O5gl1l88vhjoo2HxYScgCp70BsDwiUNTqIR3NM+ZBHYFweVf3Gwz5LzHZT2rEZtD ++6VXRP75Q/2wOLnqCO4bK4BUs6sqxcQZmOldruPkPynrY0oPfHHExjxZDvQu4/r80 ++Ls3n0L8yvQKCAgEAnYWS6EikwaQNpJEfiUnOlglgFz4EE1eVkrDbBY4J3oPU+doz ++DrqmsvgpSZIAfd2MUbkN4pOMsMTjbeIYWDnZDa1RoctKs3FhwFPHwAjQpznab4mn ++Bp81FMHM40qyb0NaNuFRwghdXvoQvBBX1p8oEnFzDRvTiuS/vTPTA8KDY8IeRp8R ++oGzKHpfziNwq/URpqj7pwi9odNjGZvR2IwYw9jCLPIqaEbMoSOdI0mg4MoYyqP4q ++nm7d4wqSDwrYxiXZ6f3nYpkhEY1lb0Wbksp1ig8sKSF4nDZRGK1RSfE+6gjBp94H ++X/Wog6Zb6NC9ZpusTiDLvuIUXcyUJvmHiWjSNqiTv8jurlwEsgSwhziEQfqLrtdV ++QI3PRMolBkD1iCk+HFE53r05LMf1bp3r4MS+naaQrLbIrl1kgDNGwVdgS+SCM7Bg ++TwEgE67iOb2iIoUpon/NyP4LesMzvdpsu2JFlfz13PmmQ34mFI7tWvOb3NA5DP3c ++46C6SaWI0TD9B11nJbHGTYN3Si9n0EBgoDJEXUKeh3km9O47dgvkSug4WzhYsvrE ++rMlMLtKfp2w8HlMZpsUlToNCx6CI+tJrohzcs3BAVAbjFAXRKWGijB1rxwyDdHPv ++I+/wJTNaRNPQ1M0SwtEL/zJd21y3KSPn4eL+GP3efhlDSjtlDvZqkdAUsU8= ++-----END RSA PRIVATE KEY----- ++ +diff --git a/CryptoPkg/Library/OpensslLib/openssl/apps/rsautl.c b/CryptoPkg/Library/OpensslLib/openssl/apps/rsautl.c +new file mode 100644 +index 0000000..d527bf4 +--- /dev/null ++++ b/CryptoPkg/Library/OpensslLib/openssl/apps/rsautl.c +@@ -0,0 +1,278 @@ ++/* ++ * Copyright 2000-2016 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 ++ * in the file LICENSE in the source distribution or at ++ * https://www.openssl.org/source/license.html ++ */ ++ ++#include ++#ifdef OPENSSL_NO_RSA ++NON_EMPTY_TRANSLATION_UNIT ++#else ++ ++# include "apps.h" ++# include ++# include ++# include ++# include ++ ++# define RSA_SIGN 1 ++# define RSA_VERIFY 2 ++# define RSA_ENCRYPT 3 ++# define RSA_DECRYPT 4 ++ ++# define KEY_PRIVKEY 1 ++# define KEY_PUBKEY 2 ++# define KEY_CERT 3 ++ ++typedef enum OPTION_choice { ++ OPT_ERR = -1, OPT_EOF = 0, OPT_HELP, ++ OPT_ENGINE, OPT_IN, OPT_OUT, OPT_ASN1PARSE, OPT_HEXDUMP, ++ OPT_RAW, OPT_OAEP, OPT_SSL, OPT_PKCS, OPT_X931, ++ OPT_SIGN, OPT_VERIFY, OPT_REV, OPT_ENCRYPT, OPT_DECRYPT, ++ OPT_PUBIN, OPT_CERTIN, OPT_INKEY, OPT_PASSIN, OPT_KEYFORM ++} OPTION_CHOICE; ++ ++OPTIONS rsautl_options[] = { ++ {"help", OPT_HELP, '-', "Display this summary"}, ++ {"in", OPT_IN, '<', "Input file"}, ++ {"out", OPT_OUT, '>', "Output file"}, ++ {"inkey", OPT_INKEY, 's', "Input key"}, ++ {"keyform", OPT_KEYFORM, 'E', "Private key format - default PEM"}, ++ {"pubin", OPT_PUBIN, '-', "Input is an RSA public"}, ++ {"certin", OPT_CERTIN, '-', "Input is a cert carrying an RSA public key"}, ++ {"ssl", OPT_SSL, '-', "Use SSL v2 padding"}, ++ {"raw", OPT_RAW, '-', "Use no padding"}, ++ {"pkcs", OPT_PKCS, '-', "Use PKCS#1 v1.5 padding (default)"}, ++ {"oaep", OPT_OAEP, '-', "Use PKCS#1 OAEP"}, ++ {"sign", OPT_SIGN, '-', "Sign with private key"}, ++ {"verify", OPT_VERIFY, '-', "Verify with public key"}, ++ {"asn1parse", OPT_ASN1PARSE, '-', ++ "Run output through asn1parse; useful with -verify"}, ++ {"hexdump", OPT_HEXDUMP, '-', "Hex dump output"}, ++ {"x931", OPT_X931, '-', "Use ANSI X9.31 padding"}, ++ {"rev", OPT_REV, '-', "Reverse the order of the input buffer"}, ++ {"encrypt", OPT_ENCRYPT, '-', "Encrypt with public key"}, ++ {"decrypt", OPT_DECRYPT, '-', "Decrypt with private key"}, ++ {"passin", OPT_PASSIN, 's', "Input file pass phrase source"}, ++# ifndef OPENSSL_NO_ENGINE ++ {"engine", OPT_ENGINE, 's', "Use engine, possibly a hardware device"}, ++# endif ++ {NULL} ++}; ++ ++int rsautl_main(int argc, char **argv) ++{ ++ BIO *in = NULL, *out = NULL; ++ ENGINE *e = NULL; ++ EVP_PKEY *pkey = NULL; ++ RSA *rsa = NULL; ++ X509 *x; ++ char *infile = NULL, *outfile = NULL, *keyfile = NULL; ++ char *passinarg = NULL, *passin = NULL, *prog; ++ char rsa_mode = RSA_VERIFY, key_type = KEY_PRIVKEY; ++ unsigned char *rsa_in = NULL, *rsa_out = NULL, pad = RSA_PKCS1_PADDING; ++ int rsa_inlen, keyformat = FORMAT_PEM, keysize, ret = 1; ++ int rsa_outlen = 0, hexdump = 0, asn1parse = 0, need_priv = 0, rev = 0; ++ OPTION_CHOICE o; ++ ++ prog = opt_init(argc, argv, rsautl_options); ++ while ((o = opt_next()) != OPT_EOF) { ++ switch (o) { ++ case OPT_EOF: ++ case OPT_ERR: ++ opthelp: ++ BIO_printf(bio_err, "%s: Use -help for summary.\n", prog); ++ goto end; ++ case OPT_HELP: ++ opt_help(rsautl_options); ++ ret = 0; ++ goto end; ++ case OPT_KEYFORM: ++ if (!opt_format(opt_arg(), OPT_FMT_PDE, &keyformat)) ++ goto opthelp; ++ break; ++ case OPT_IN: ++ infile = opt_arg(); ++ break; ++ case OPT_OUT: ++ outfile = opt_arg(); ++ break; ++ case OPT_ENGINE: ++ e = setup_engine(opt_arg(), 0); ++ break; ++ case OPT_ASN1PARSE: ++ asn1parse = 1; ++ break; ++ case OPT_HEXDUMP: ++ hexdump = 1; ++ break; ++ case OPT_RAW: ++ pad = RSA_NO_PADDING; ++ break; ++ case OPT_OAEP: ++ pad = RSA_PKCS1_OAEP_PADDING; ++ break; ++ case OPT_SSL: ++ pad = RSA_SSLV23_PADDING; ++ break; ++ case OPT_PKCS: ++ pad = RSA_PKCS1_PADDING; ++ break; ++ case OPT_X931: ++ pad = RSA_X931_PADDING; ++ break; ++ case OPT_SIGN: ++ rsa_mode = RSA_SIGN; ++ need_priv = 1; ++ break; ++ case OPT_VERIFY: ++ rsa_mode = RSA_VERIFY; ++ break; ++ case OPT_REV: ++ rev = 1; ++ break; ++ case OPT_ENCRYPT: ++ rsa_mode = RSA_ENCRYPT; ++ break; ++ case OPT_DECRYPT: ++ rsa_mode = RSA_DECRYPT; ++ need_priv = 1; ++ break; ++ case OPT_PUBIN: ++ key_type = KEY_PUBKEY; ++ break; ++ case OPT_CERTIN: ++ key_type = KEY_CERT; ++ break; ++ case OPT_INKEY: ++ keyfile = opt_arg(); ++ break; ++ case OPT_PASSIN: ++ passinarg = opt_arg(); ++ break; ++ } ++ } ++ argc = opt_num_rest(); ++ if (argc != 0) ++ goto opthelp; ++ ++ if (need_priv && (key_type != KEY_PRIVKEY)) { ++ BIO_printf(bio_err, "A private key is needed for this operation\n"); ++ goto end; ++ } ++ ++ if (!app_passwd(passinarg, NULL, &passin, NULL)) { ++ BIO_printf(bio_err, "Error getting password\n"); ++ goto end; ++ } ++ ++/* FIXME: seed PRNG only if needed */ ++ app_RAND_load_file(NULL, 0); ++ ++ switch (key_type) { ++ case KEY_PRIVKEY: ++ pkey = load_key(keyfile, keyformat, 0, passin, e, "Private Key"); ++ break; ++ ++ case KEY_PUBKEY: ++ pkey = load_pubkey(keyfile, keyformat, 0, NULL, e, "Public Key"); ++ break; ++ ++ case KEY_CERT: ++ x = load_cert(keyfile, keyformat, "Certificate"); ++ if (x) { ++ pkey = X509_get_pubkey(x); ++ X509_free(x); ++ } ++ break; ++ } ++ ++ if (!pkey) { ++ return 1; ++ } ++ ++ rsa = EVP_PKEY_get1_RSA(pkey); ++ EVP_PKEY_free(pkey); ++ ++ if (!rsa) { ++ BIO_printf(bio_err, "Error getting RSA key\n"); ++ ERR_print_errors(bio_err); ++ goto end; ++ } ++ ++ in = bio_open_default(infile, 'r', FORMAT_BINARY); ++ if (in == NULL) ++ goto end; ++ out = bio_open_default(outfile, 'w', FORMAT_BINARY); ++ if (out == NULL) ++ goto end; ++ ++ keysize = RSA_size(rsa); ++ ++ rsa_in = app_malloc(keysize * 2, "hold rsa key"); ++ rsa_out = app_malloc(keysize, "output rsa key"); ++ ++ /* Read the input data */ ++ rsa_inlen = BIO_read(in, rsa_in, keysize * 2); ++ if (rsa_inlen < 0) { ++ BIO_printf(bio_err, "Error reading input Data\n"); ++ goto end; ++ } ++ if (rev) { ++ int i; ++ unsigned char ctmp; ++ for (i = 0; i < rsa_inlen / 2; i++) { ++ ctmp = rsa_in[i]; ++ rsa_in[i] = rsa_in[rsa_inlen - 1 - i]; ++ rsa_in[rsa_inlen - 1 - i] = ctmp; ++ } ++ } ++ switch (rsa_mode) { ++ ++ case RSA_VERIFY: ++ rsa_outlen = RSA_public_decrypt(rsa_inlen, rsa_in, rsa_out, rsa, pad); ++ break; ++ ++ case RSA_SIGN: ++ rsa_outlen = ++ RSA_private_encrypt(rsa_inlen, rsa_in, rsa_out, rsa, pad); ++ break; ++ ++ case RSA_ENCRYPT: ++ rsa_outlen = RSA_public_encrypt(rsa_inlen, rsa_in, rsa_out, rsa, pad); ++ break; ++ ++ case RSA_DECRYPT: ++ rsa_outlen = ++ RSA_private_decrypt(rsa_inlen, rsa_in, rsa_out, rsa, pad); ++ break; ++ } ++ ++ if (rsa_outlen < 0) { ++ BIO_printf(bio_err, "RSA operation error\n"); ++ ERR_print_errors(bio_err); ++ goto end; ++ } ++ ret = 0; ++ if (asn1parse) { ++ if (!ASN1_parse_dump(out, rsa_out, rsa_outlen, 1, -1)) { ++ ERR_print_errors(bio_err); ++ } ++ } else if (hexdump) ++ BIO_dump(out, (char *)rsa_out, rsa_outlen); ++ else ++ BIO_write(out, rsa_out, rsa_outlen); ++ end: ++ RSA_free(rsa); ++ release_engine(e); ++ BIO_free(in); ++ BIO_free_all(out); ++ OPENSSL_free(rsa_in); ++ OPENSSL_free(rsa_out); ++ OPENSSL_free(passin); ++ return ret; ++} ++#endif +diff --git a/CryptoPkg/Library/OpensslLib/openssl/apps/s1024key.pem b/CryptoPkg/Library/OpensslLib/openssl/apps/s1024key.pem +new file mode 100644 +index 0000000..19e0403 +--- /dev/null ++++ b/CryptoPkg/Library/OpensslLib/openssl/apps/s1024key.pem +@@ -0,0 +1,15 @@ ++-----BEGIN RSA PRIVATE KEY----- ++MIICXgIBAAKBgQCzEfU8E+ZGTGtHXV5XhvM2Lg32fXUIjydXb34BGVPX6oN7+aNV ++S9eWayvW/+9/vUb0aCqilJrpFesgItV2T8VhhjOE++XUz46uNpcMU7wHMEAXUufP ++pztpFm8ZEk2tFKvadkSSoN8lb11juvZVkSkPlB65pFhSe4QKSp6J4HrkYwIDAQAB ++AoGBAKy8jvb0Lzby8q11yNLf7+78wCVdYi7ugMHcYA1JVFK8+zb1WfSm44FLQo/0 ++dSChAjgz36TTexeLODPYxleJndjVcOMVzsLJjSM8dLpXsTS4FCeMbhw2s2u+xqKY ++bbPWfk+HOTyJjfnkcC5Nbg44eOmruq0gSmBeUXVM5UntlTnxAkEA7TGCA3h7kx5E ++Bl4zl2pc3gPAGt+dyfk5Po9mGJUUXhF5p2zueGmYWW74TmOWB1kzt4QRdYMzFePq ++zfDNXEa1CwJBAMFErdY0xp0UJ13WwBbUTk8rujqQdHtjw0klhpbuKkjxu2hN0wwM ++6p0D9qxF7JHaghqVRI0fAW/EE0OzdHMR9QkCQQDNR26dMFXKsoPu+vItljj/UEGf ++QG7gERiQ4yxaFBPHgdpGo0kT31eh9x9hQGDkxTe0GNG/YSgCRvm8+C3TMcKXAkBD ++dhGn36wkUFCddMSAM4NSJ1VN8/Z0y5HzCmI8dM3VwGtGMUQlxKxwOl30LEQzdS5M ++0SWojNYXiT2gOBfBwtbhAkEAhafl5QEOIgUz+XazS/IlZ8goNKdDVfYgK3mHHjvv ++nY5G+AuGebdNkXJr4KSWxDcN+C2i47zuj4QXA16MAOandA== ++-----END RSA PRIVATE KEY----- +diff --git a/CryptoPkg/Library/OpensslLib/openssl/apps/s1024req.pem b/CryptoPkg/Library/OpensslLib/openssl/apps/s1024req.pem +new file mode 100644 +index 0000000..bb75e7e +--- /dev/null ++++ b/CryptoPkg/Library/OpensslLib/openssl/apps/s1024req.pem +@@ -0,0 +1,11 @@ ++-----BEGIN CERTIFICATE REQUEST----- ++MIIBojCCAQsCAQAwZDELMAkGA1UEBhMCQVUxEzARBgNVBAgTClF1ZWVuc2xhbmQx ++GjAYBgNVBAoTEUNyeXB0U29mdCBQdHkgTHRkMSQwIgYDVQQDExtTZXJ2ZXIgdGVz ++dCBjZXJ0ICgxMDI0IGJpdCkwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBALMR ++9TwT5kZMa0ddXleG8zYuDfZ9dQiPJ1dvfgEZU9fqg3v5o1VL15ZrK9b/73+9RvRo ++KqKUmukV6yAi1XZPxWGGM4T75dTPjq42lwxTvAcwQBdS58+nO2kWbxkSTa0Uq9p2 ++RJKg3yVvXWO69lWRKQ+UHrmkWFJ7hApKnongeuRjAgMBAAEwDQYJKoZIhvcNAQEE ++BQADgYEAStHlk4pBbwiNeQ2/PKTPPXzITYC8Gn0XMbrU94e/6JIKiO7aArq9Espq ++nrBSvC14dHcNl6NNvnkEKdQ7hAkcACfBbnOXA/oQvMBd4GD78cH3k0jVDoVUEjil ++frLfWlckW6WzpTktt0ZPDdAjJCmKVh0ABHimi7Bo9FC3wIGIe5M= ++-----END CERTIFICATE REQUEST----- +diff --git a/CryptoPkg/Library/OpensslLib/openssl/apps/s512-key.pem b/CryptoPkg/Library/OpensslLib/openssl/apps/s512-key.pem +new file mode 100644 +index 0000000..0e3ff2d +--- /dev/null ++++ b/CryptoPkg/Library/OpensslLib/openssl/apps/s512-key.pem +@@ -0,0 +1,9 @@ ++-----BEGIN RSA PRIVATE KEY----- ++MIIBPAIBAAJBAJ+zw4Qnlf8SMVIPFe9GEcStgOY2Ww/dgNdhjeD8ckUJNP5VZkVD ++TGiXav6ooKXfX3j/7tdkuD8Ey2//Kv7+ue0CAwEAAQJAN6W31vDEP2DjdqhzCDDu ++OA4NACqoiFqyblo7yc2tM4h4xMbC3Yx5UKMN9ZkCtX0gzrz6DyF47bdKcWBzNWCj ++gQIhANEoojVt7hq+SQ6MCN6FTAysGgQf56Q3TYoJMoWvdiXVAiEAw3e3rc+VJpOz ++rHuDo6bgpjUAAXM+v3fcpsfZSNO6V7kCIQCtbVjanpUwvZkMI9by02oUk9taki3b ++PzPfAfNPYAbCJQIhAJXNQDWyqwn/lGmR11cqY2y9nZ1+5w3yHGatLrcDnQHxAiEA ++vnlEGo8K85u+KwIOimM48ZG8oTk7iFdkqLJR1utT3aU= ++-----END RSA PRIVATE KEY----- +diff --git a/CryptoPkg/Library/OpensslLib/openssl/apps/s512-req.pem b/CryptoPkg/Library/OpensslLib/openssl/apps/s512-req.pem +new file mode 100644 +index 0000000..ea314be +--- /dev/null ++++ b/CryptoPkg/Library/OpensslLib/openssl/apps/s512-req.pem +@@ -0,0 +1,8 @@ ++-----BEGIN CERTIFICATE REQUEST----- ++MIIBGzCBxgIBADBjMQswCQYDVQQGEwJBVTETMBEGA1UECBMKUXVlZW5zbGFuZDEa ++MBgGA1UEChMRQ3J5cHRTb2Z0IFB0eSBMdGQxIzAhBgNVBAMTGlNlcnZlciB0ZXN0 ++IGNlcnQgKDUxMiBiaXQpMFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAJ+zw4Qnlf8S ++MVIPFe9GEcStgOY2Ww/dgNdhjeD8ckUJNP5VZkVDTGiXav6ooKXfX3j/7tdkuD8E ++y2//Kv7+ue0CAwEAATANBgkqhkiG9w0BAQQFAANBAAB+uQi+qwn6qRSHB8EUTvsm ++5TNTHzYDeN39nyIbZNX2s0se3Srn2Bxft5YCwD3moFZ9QoyDHxE0h6qLX5yjD+8= ++-----END CERTIFICATE REQUEST----- +diff --git a/CryptoPkg/Library/OpensslLib/openssl/apps/s_apps.h b/CryptoPkg/Library/OpensslLib/openssl/apps/s_apps.h +new file mode 100644 +index 0000000..c47932b +--- /dev/null ++++ b/CryptoPkg/Library/OpensslLib/openssl/apps/s_apps.h +@@ -0,0 +1,102 @@ ++/* ++ * Copyright 1995-2016 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 ++ * in the file LICENSE in the source distribution or at ++ * https://www.openssl.org/source/license.html ++ */ ++ ++#include ++ ++#if defined(OPENSSL_SYS_WINDOWS) || defined(OPENSSL_SYS_MSDOS) ++# include ++#endif ++ ++#if defined(OPENSSL_SYS_MSDOS) && !defined(_WIN32) ++# define _kbhit kbhit ++#endif ++ ++#if defined(OPENSSL_SYS_VMS) && !defined(FD_SET) ++/* ++ * VAX C does not defined fd_set and friends, but it's actually quite simple ++ */ ++/* These definitions are borrowed from SOCKETSHR. /Richard Levitte */ ++# define MAX_NOFILE 32 ++# define NBBY 8 /* number of bits in a byte */ ++ ++# ifndef FD_SETSIZE ++# define FD_SETSIZE MAX_NOFILE ++# endif /* FD_SETSIZE */ ++ ++/* How many things we'll allow select to use. 0 if unlimited */ ++# define MAXSELFD MAX_NOFILE ++typedef int fd_mask; /* int here! VMS prototypes int, not long */ ++# define NFDBITS (sizeof(fd_mask) * NBBY)/* bits per mask (power of 2!) */ ++# define NFDSHIFT 5 /* Shift based on above */ ++ ++typedef fd_mask fd_set; ++# define FD_SET(n, p) (*(p) |= (1 << ((n) % NFDBITS))) ++# define FD_CLR(n, p) (*(p) &= ~(1 << ((n) % NFDBITS))) ++# define FD_ISSET(n, p) (*(p) & (1 << ((n) % NFDBITS))) ++# define FD_ZERO(p) memset((p), 0, sizeof(*(p))) ++#endif ++ ++#define PORT "4433" ++#define PROTOCOL "tcp" ++ ++typedef int (*do_server_cb)(int s, int stype, unsigned char *context); ++int do_server(int *accept_sock, const char *host, const char *port, ++ int family, int type, ++ do_server_cb cb, ++ unsigned char *context, int naccept); ++#ifdef HEADER_X509_H ++int verify_callback(int ok, X509_STORE_CTX *ctx); ++#endif ++#ifdef HEADER_SSL_H ++int set_cert_stuff(SSL_CTX *ctx, char *cert_file, char *key_file); ++int set_cert_key_stuff(SSL_CTX *ctx, X509 *cert, EVP_PKEY *key, ++ STACK_OF(X509) *chain, int build_chain); ++int ssl_print_sigalgs(BIO *out, SSL *s); ++int ssl_print_point_formats(BIO *out, SSL *s); ++int ssl_print_curves(BIO *out, SSL *s, int noshared); ++#endif ++int ssl_print_tmp_key(BIO *out, SSL *s); ++int init_client(int *sock, const char *host, const char *port, ++ int family, int type); ++int should_retry(int i); ++ ++long bio_dump_callback(BIO *bio, int cmd, const char *argp, ++ int argi, long argl, long ret); ++ ++#ifdef HEADER_SSL_H ++void apps_ssl_info_callback(const SSL *s, int where, int ret); ++void msg_cb(int write_p, int version, int content_type, const void *buf, ++ size_t len, SSL *ssl, void *arg); ++void tlsext_cb(SSL *s, int client_server, int type, const unsigned char *data, ++ int len, void *arg); ++#endif ++ ++int generate_cookie_callback(SSL *ssl, unsigned char *cookie, ++ unsigned int *cookie_len); ++int verify_cookie_callback(SSL *ssl, const unsigned char *cookie, ++ unsigned int cookie_len); ++ ++typedef struct ssl_excert_st SSL_EXCERT; ++ ++void ssl_ctx_set_excert(SSL_CTX *ctx, SSL_EXCERT *exc); ++void ssl_excert_free(SSL_EXCERT *exc); ++int args_excert(int option, SSL_EXCERT **pexc); ++int load_excert(SSL_EXCERT **pexc); ++void print_verify_detail(SSL *s, BIO *bio); ++void print_ssl_summary(SSL *s); ++#ifdef HEADER_SSL_H ++int config_ctx(SSL_CONF_CTX *cctx, STACK_OF(OPENSSL_STRING) *str, SSL_CTX *ctx); ++int ssl_ctx_add_crls(SSL_CTX *ctx, STACK_OF(X509_CRL) *crls, ++ int crl_download); ++int ssl_load_stores(SSL_CTX *ctx, const char *vfyCApath, ++ const char *vfyCAfile, const char *chCApath, ++ const char *chCAfile, STACK_OF(X509_CRL) *crls, ++ int crl_download); ++void ssl_ctx_security_debug(SSL_CTX *ctx, int verbose); ++#endif +diff --git a/CryptoPkg/Library/OpensslLib/openssl/apps/s_cb.c b/CryptoPkg/Library/OpensslLib/openssl/apps/s_cb.c +new file mode 100644 +index 0000000..e0acd51 +--- /dev/null ++++ b/CryptoPkg/Library/OpensslLib/openssl/apps/s_cb.c +@@ -0,0 +1,1335 @@ ++/* ++ * Copyright 1995-2016 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 ++ * in the file LICENSE in the source distribution or at ++ * https://www.openssl.org/source/license.html ++ */ ++ ++/* callback functions used by s_client, s_server, and s_time */ ++#include ++#include ++#include /* for memcpy() and strcmp() */ ++#define USE_SOCKETS ++#include "apps.h" ++#undef USE_SOCKETS ++#include ++#include ++#include ++#include ++#include ++#ifndef OPENSSL_NO_DH ++# include ++#endif ++#include "s_apps.h" ++ ++#define COOKIE_SECRET_LENGTH 16 ++ ++VERIFY_CB_ARGS verify_args = { 0, 0, X509_V_OK, 0 }; ++ ++#ifndef OPENSSL_NO_SOCK ++static unsigned char cookie_secret[COOKIE_SECRET_LENGTH]; ++static int cookie_initialized = 0; ++#endif ++ ++static const char *lookup(int val, const STRINT_PAIR* list, const char* def) ++{ ++ for ( ; list->name; ++list) ++ if (list->retval == val) ++ return list->name; ++ return def; ++} ++ ++int verify_callback(int ok, X509_STORE_CTX *ctx) ++{ ++ X509 *err_cert; ++ int err, depth; ++ ++ err_cert = X509_STORE_CTX_get_current_cert(ctx); ++ err = X509_STORE_CTX_get_error(ctx); ++ depth = X509_STORE_CTX_get_error_depth(ctx); ++ ++ if (!verify_args.quiet || !ok) { ++ BIO_printf(bio_err, "depth=%d ", depth); ++ if (err_cert) { ++ X509_NAME_print_ex(bio_err, ++ X509_get_subject_name(err_cert), ++ 0, XN_FLAG_ONELINE); ++ BIO_puts(bio_err, "\n"); ++ } else ++ BIO_puts(bio_err, "\n"); ++ } ++ if (!ok) { ++ BIO_printf(bio_err, "verify error:num=%d:%s\n", err, ++ X509_verify_cert_error_string(err)); ++ if (verify_args.depth >= depth) { ++ if (!verify_args.return_error) ++ ok = 1; ++ verify_args.error = err; ++ } else { ++ ok = 0; ++ verify_args.error = X509_V_ERR_CERT_CHAIN_TOO_LONG; ++ } ++ } ++ switch (err) { ++ case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT: ++ BIO_puts(bio_err, "issuer= "); ++ X509_NAME_print_ex(bio_err, X509_get_issuer_name(err_cert), ++ 0, XN_FLAG_ONELINE); ++ BIO_puts(bio_err, "\n"); ++ break; ++ case X509_V_ERR_CERT_NOT_YET_VALID: ++ case X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD: ++ BIO_printf(bio_err, "notBefore="); ++ ASN1_TIME_print(bio_err, X509_get0_notBefore(err_cert)); ++ BIO_printf(bio_err, "\n"); ++ break; ++ case X509_V_ERR_CERT_HAS_EXPIRED: ++ case X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD: ++ BIO_printf(bio_err, "notAfter="); ++ ASN1_TIME_print(bio_err, X509_get0_notAfter(err_cert)); ++ BIO_printf(bio_err, "\n"); ++ break; ++ case X509_V_ERR_NO_EXPLICIT_POLICY: ++ if (!verify_args.quiet) ++ policies_print(ctx); ++ break; ++ } ++ if (err == X509_V_OK && ok == 2 && !verify_args.quiet) ++ policies_print(ctx); ++ if (ok && !verify_args.quiet) ++ BIO_printf(bio_err, "verify return:%d\n", ok); ++ return (ok); ++} ++ ++int set_cert_stuff(SSL_CTX *ctx, char *cert_file, char *key_file) ++{ ++ if (cert_file != NULL) { ++ if (SSL_CTX_use_certificate_file(ctx, cert_file, ++ SSL_FILETYPE_PEM) <= 0) { ++ BIO_printf(bio_err, "unable to get certificate from '%s'\n", ++ cert_file); ++ ERR_print_errors(bio_err); ++ return (0); ++ } ++ if (key_file == NULL) ++ key_file = cert_file; ++ if (SSL_CTX_use_PrivateKey_file(ctx, key_file, SSL_FILETYPE_PEM) <= 0) { ++ BIO_printf(bio_err, "unable to get private key from '%s'\n", ++ key_file); ++ ERR_print_errors(bio_err); ++ return (0); ++ } ++ ++ /* ++ * If we are using DSA, we can copy the parameters from the private ++ * key ++ */ ++ ++ /* ++ * Now we know that a key and cert have been set against the SSL ++ * context ++ */ ++ if (!SSL_CTX_check_private_key(ctx)) { ++ BIO_printf(bio_err, ++ "Private key does not match the certificate public key\n"); ++ return (0); ++ } ++ } ++ return (1); ++} ++ ++int set_cert_key_stuff(SSL_CTX *ctx, X509 *cert, EVP_PKEY *key, ++ STACK_OF(X509) *chain, int build_chain) ++{ ++ int chflags = chain ? SSL_BUILD_CHAIN_FLAG_CHECK : 0; ++ if (cert == NULL) ++ return 1; ++ if (SSL_CTX_use_certificate(ctx, cert) <= 0) { ++ BIO_printf(bio_err, "error setting certificate\n"); ++ ERR_print_errors(bio_err); ++ return 0; ++ } ++ ++ if (SSL_CTX_use_PrivateKey(ctx, key) <= 0) { ++ BIO_printf(bio_err, "error setting private key\n"); ++ ERR_print_errors(bio_err); ++ return 0; ++ } ++ ++ /* ++ * Now we know that a key and cert have been set against the SSL context ++ */ ++ if (!SSL_CTX_check_private_key(ctx)) { ++ BIO_printf(bio_err, ++ "Private key does not match the certificate public key\n"); ++ return 0; ++ } ++ if (chain && !SSL_CTX_set1_chain(ctx, chain)) { ++ BIO_printf(bio_err, "error setting certificate chain\n"); ++ ERR_print_errors(bio_err); ++ return 0; ++ } ++ if (build_chain && !SSL_CTX_build_cert_chain(ctx, chflags)) { ++ BIO_printf(bio_err, "error building certificate chain\n"); ++ ERR_print_errors(bio_err); ++ return 0; ++ } ++ return 1; ++} ++ ++static STRINT_PAIR cert_type_list[] = { ++ {"RSA sign", TLS_CT_RSA_SIGN}, ++ {"DSA sign", TLS_CT_DSS_SIGN}, ++ {"RSA fixed DH", TLS_CT_RSA_FIXED_DH}, ++ {"DSS fixed DH", TLS_CT_DSS_FIXED_DH}, ++ {"ECDSA sign", TLS_CT_ECDSA_SIGN}, ++ {"RSA fixed ECDH", TLS_CT_RSA_FIXED_ECDH}, ++ {"ECDSA fixed ECDH", TLS_CT_ECDSA_FIXED_ECDH}, ++ {"GOST01 Sign", TLS_CT_GOST01_SIGN}, ++ {NULL} ++}; ++ ++static void ssl_print_client_cert_types(BIO *bio, SSL *s) ++{ ++ const unsigned char *p; ++ int i; ++ int cert_type_num = SSL_get0_certificate_types(s, &p); ++ if (!cert_type_num) ++ return; ++ BIO_puts(bio, "Client Certificate Types: "); ++ for (i = 0; i < cert_type_num; i++) { ++ unsigned char cert_type = p[i]; ++ const char *cname = lookup((int)cert_type, cert_type_list, NULL); ++ ++ if (i) ++ BIO_puts(bio, ", "); ++ if (cname) ++ BIO_puts(bio, cname); ++ else ++ BIO_printf(bio, "UNKNOWN (%d),", cert_type); ++ } ++ BIO_puts(bio, "\n"); ++} ++ ++static int do_print_sigalgs(BIO *out, SSL *s, int shared) ++{ ++ int i, nsig, client; ++ client = SSL_is_server(s) ? 0 : 1; ++ if (shared) ++ nsig = SSL_get_shared_sigalgs(s, -1, NULL, NULL, NULL, NULL, NULL); ++ else ++ nsig = SSL_get_sigalgs(s, -1, NULL, NULL, NULL, NULL, NULL); ++ if (nsig == 0) ++ return 1; ++ ++ if (shared) ++ BIO_puts(out, "Shared "); ++ ++ if (client) ++ BIO_puts(out, "Requested "); ++ BIO_puts(out, "Signature Algorithms: "); ++ for (i = 0; i < nsig; i++) { ++ int hash_nid, sign_nid; ++ unsigned char rhash, rsign; ++ const char *sstr = NULL; ++ if (shared) ++ SSL_get_shared_sigalgs(s, i, &sign_nid, &hash_nid, NULL, ++ &rsign, &rhash); ++ else ++ SSL_get_sigalgs(s, i, &sign_nid, &hash_nid, NULL, &rsign, &rhash); ++ if (i) ++ BIO_puts(out, ":"); ++ if (sign_nid == EVP_PKEY_RSA) ++ sstr = "RSA"; ++ else if (sign_nid == EVP_PKEY_DSA) ++ sstr = "DSA"; ++ else if (sign_nid == EVP_PKEY_EC) ++ sstr = "ECDSA"; ++ if (sstr) ++ BIO_printf(out, "%s+", sstr); ++ else ++ BIO_printf(out, "0x%02X+", (int)rsign); ++ if (hash_nid != NID_undef) ++ BIO_printf(out, "%s", OBJ_nid2sn(hash_nid)); ++ else ++ BIO_printf(out, "0x%02X", (int)rhash); ++ } ++ BIO_puts(out, "\n"); ++ return 1; ++} ++ ++int ssl_print_sigalgs(BIO *out, SSL *s) ++{ ++ int mdnid; ++ if (!SSL_is_server(s)) ++ ssl_print_client_cert_types(out, s); ++ do_print_sigalgs(out, s, 0); ++ do_print_sigalgs(out, s, 1); ++ if (SSL_get_peer_signature_nid(s, &mdnid)) ++ BIO_printf(out, "Peer signing digest: %s\n", OBJ_nid2sn(mdnid)); ++ return 1; ++} ++ ++#ifndef OPENSSL_NO_EC ++int ssl_print_point_formats(BIO *out, SSL *s) ++{ ++ int i, nformats; ++ const char *pformats; ++ nformats = SSL_get0_ec_point_formats(s, &pformats); ++ if (nformats <= 0) ++ return 1; ++ BIO_puts(out, "Supported Elliptic Curve Point Formats: "); ++ for (i = 0; i < nformats; i++, pformats++) { ++ if (i) ++ BIO_puts(out, ":"); ++ switch (*pformats) { ++ case TLSEXT_ECPOINTFORMAT_uncompressed: ++ BIO_puts(out, "uncompressed"); ++ break; ++ ++ case TLSEXT_ECPOINTFORMAT_ansiX962_compressed_prime: ++ BIO_puts(out, "ansiX962_compressed_prime"); ++ break; ++ ++ case TLSEXT_ECPOINTFORMAT_ansiX962_compressed_char2: ++ BIO_puts(out, "ansiX962_compressed_char2"); ++ break; ++ ++ default: ++ BIO_printf(out, "unknown(%d)", (int)*pformats); ++ break; ++ ++ } ++ } ++ BIO_puts(out, "\n"); ++ return 1; ++} ++ ++int ssl_print_curves(BIO *out, SSL *s, int noshared) ++{ ++ int i, ncurves, *curves, nid; ++ const char *cname; ++ ++ ncurves = SSL_get1_curves(s, NULL); ++ if (ncurves <= 0) ++ return 1; ++ curves = app_malloc(ncurves * sizeof(int), "curves to print"); ++ SSL_get1_curves(s, curves); ++ ++ BIO_puts(out, "Supported Elliptic Curves: "); ++ for (i = 0; i < ncurves; i++) { ++ if (i) ++ BIO_puts(out, ":"); ++ nid = curves[i]; ++ /* If unrecognised print out hex version */ ++ if (nid & TLSEXT_nid_unknown) ++ BIO_printf(out, "0x%04X", nid & 0xFFFF); ++ else { ++ /* Use NIST name for curve if it exists */ ++ cname = EC_curve_nid2nist(nid); ++ if (!cname) ++ cname = OBJ_nid2sn(nid); ++ BIO_printf(out, "%s", cname); ++ } ++ } ++ OPENSSL_free(curves); ++ if (noshared) { ++ BIO_puts(out, "\n"); ++ return 1; ++ } ++ BIO_puts(out, "\nShared Elliptic curves: "); ++ ncurves = SSL_get_shared_curve(s, -1); ++ for (i = 0; i < ncurves; i++) { ++ if (i) ++ BIO_puts(out, ":"); ++ nid = SSL_get_shared_curve(s, i); ++ cname = EC_curve_nid2nist(nid); ++ if (!cname) ++ cname = OBJ_nid2sn(nid); ++ BIO_printf(out, "%s", cname); ++ } ++ if (ncurves == 0) ++ BIO_puts(out, "NONE"); ++ BIO_puts(out, "\n"); ++ return 1; ++} ++#endif ++int ssl_print_tmp_key(BIO *out, SSL *s) ++{ ++ EVP_PKEY *key; ++ if (!SSL_get_server_tmp_key(s, &key)) ++ return 1; ++ BIO_puts(out, "Server Temp Key: "); ++ switch (EVP_PKEY_id(key)) { ++ case EVP_PKEY_RSA: ++ BIO_printf(out, "RSA, %d bits\n", EVP_PKEY_bits(key)); ++ break; ++ ++ case EVP_PKEY_DH: ++ BIO_printf(out, "DH, %d bits\n", EVP_PKEY_bits(key)); ++ break; ++#ifndef OPENSSL_NO_EC ++ case EVP_PKEY_EC: ++ { ++ EC_KEY *ec = EVP_PKEY_get1_EC_KEY(key); ++ int nid; ++ const char *cname; ++ nid = EC_GROUP_get_curve_name(EC_KEY_get0_group(ec)); ++ EC_KEY_free(ec); ++ cname = EC_curve_nid2nist(nid); ++ if (!cname) ++ cname = OBJ_nid2sn(nid); ++ BIO_printf(out, "ECDH, %s, %d bits\n", cname, EVP_PKEY_bits(key)); ++ } ++ break; ++#endif ++ default: ++ BIO_printf(out, "%s, %d bits\n", OBJ_nid2sn(EVP_PKEY_id(key)), ++ EVP_PKEY_bits(key)); ++ } ++ EVP_PKEY_free(key); ++ return 1; ++} ++ ++long bio_dump_callback(BIO *bio, int cmd, const char *argp, ++ int argi, long argl, long ret) ++{ ++ BIO *out; ++ ++ out = (BIO *)BIO_get_callback_arg(bio); ++ if (out == NULL) ++ return (ret); ++ ++ if (cmd == (BIO_CB_READ | BIO_CB_RETURN)) { ++ BIO_printf(out, "read from %p [%p] (%lu bytes => %ld (0x%lX))\n", ++ (void *)bio, (void *)argp, (unsigned long)argi, ret, ret); ++ BIO_dump(out, argp, (int)ret); ++ return (ret); ++ } else if (cmd == (BIO_CB_WRITE | BIO_CB_RETURN)) { ++ BIO_printf(out, "write to %p [%p] (%lu bytes => %ld (0x%lX))\n", ++ (void *)bio, (void *)argp, (unsigned long)argi, ret, ret); ++ BIO_dump(out, argp, (int)ret); ++ } ++ return (ret); ++} ++ ++void apps_ssl_info_callback(const SSL *s, int where, int ret) ++{ ++ const char *str; ++ int w; ++ ++ w = where & ~SSL_ST_MASK; ++ ++ if (w & SSL_ST_CONNECT) ++ str = "SSL_connect"; ++ else if (w & SSL_ST_ACCEPT) ++ str = "SSL_accept"; ++ else ++ str = "undefined"; ++ ++ if (where & SSL_CB_LOOP) { ++ BIO_printf(bio_err, "%s:%s\n", str, SSL_state_string_long(s)); ++ } else if (where & SSL_CB_ALERT) { ++ str = (where & SSL_CB_READ) ? "read" : "write"; ++ BIO_printf(bio_err, "SSL3 alert %s:%s:%s\n", ++ str, ++ SSL_alert_type_string_long(ret), ++ SSL_alert_desc_string_long(ret)); ++ } else if (where & SSL_CB_EXIT) { ++ if (ret == 0) ++ BIO_printf(bio_err, "%s:failed in %s\n", ++ str, SSL_state_string_long(s)); ++ else if (ret < 0) { ++ BIO_printf(bio_err, "%s:error in %s\n", ++ str, SSL_state_string_long(s)); ++ } ++ } ++} ++ ++static STRINT_PAIR ssl_versions[] = { ++ {"SSL 3.0", SSL3_VERSION}, ++ {"TLS 1.0", TLS1_VERSION}, ++ {"TLS 1.1", TLS1_1_VERSION}, ++ {"TLS 1.2", TLS1_2_VERSION}, ++ {"DTLS 1.0", DTLS1_VERSION}, ++ {"DTLS 1.0 (bad)", DTLS1_BAD_VER}, ++ {NULL} ++}; ++static STRINT_PAIR alert_types[] = { ++ {" close_notify", 0}, ++ {" unexpected_message", 10}, ++ {" bad_record_mac", 20}, ++ {" decryption_failed", 21}, ++ {" record_overflow", 22}, ++ {" decompression_failure", 30}, ++ {" handshake_failure", 40}, ++ {" bad_certificate", 42}, ++ {" unsupported_certificate", 43}, ++ {" certificate_revoked", 44}, ++ {" certificate_expired", 45}, ++ {" certificate_unknown", 46}, ++ {" illegal_parameter", 47}, ++ {" unknown_ca", 48}, ++ {" access_denied", 49}, ++ {" decode_error", 50}, ++ {" decrypt_error", 51}, ++ {" export_restriction", 60}, ++ {" protocol_version", 70}, ++ {" insufficient_security", 71}, ++ {" internal_error", 80}, ++ {" user_canceled", 90}, ++ {" no_renegotiation", 100}, ++ {" unsupported_extension", 110}, ++ {" certificate_unobtainable", 111}, ++ {" unrecognized_name", 112}, ++ {" bad_certificate_status_response", 113}, ++ {" bad_certificate_hash_value", 114}, ++ {" unknown_psk_identity", 115}, ++ {NULL} ++}; ++ ++static STRINT_PAIR handshakes[] = { ++ {", HelloRequest", 0}, ++ {", ClientHello", 1}, ++ {", ServerHello", 2}, ++ {", HelloVerifyRequest", 3}, ++ {", NewSessionTicket", 4}, ++ {", Certificate", 11}, ++ {", ServerKeyExchange", 12}, ++ {", CertificateRequest", 13}, ++ {", ServerHelloDone", 14}, ++ {", CertificateVerify", 15}, ++ {", ClientKeyExchange", 16}, ++ {", Finished", 20}, ++ {", CertificateUrl", 21}, ++ {", CertificateStatus", 22}, ++ {", SupplementalData", 23}, ++ {NULL} ++}; ++ ++void msg_cb(int write_p, int version, int content_type, const void *buf, ++ size_t len, SSL *ssl, void *arg) ++{ ++ BIO *bio = arg; ++ const char *str_write_p = write_p ? ">>>" : "<<<"; ++ const char *str_version = lookup(version, ssl_versions, "???"); ++ const char *str_content_type = "", *str_details1 = "", *str_details2 = ""; ++ const unsigned char* bp = buf; ++ ++ if (version == SSL3_VERSION || ++ version == TLS1_VERSION || ++ version == TLS1_1_VERSION || ++ version == TLS1_2_VERSION || ++ version == DTLS1_VERSION || version == DTLS1_BAD_VER) { ++ switch (content_type) { ++ case 20: ++ str_content_type = "ChangeCipherSpec"; ++ break; ++ case 21: ++ str_content_type = "Alert"; ++ str_details1 = ", ???"; ++ if (len == 2) { ++ switch (bp[0]) { ++ case 1: ++ str_details1 = ", warning"; ++ break; ++ case 2: ++ str_details1 = ", fatal"; ++ break; ++ } ++ str_details2 = lookup((int)bp[1], alert_types, " ???"); ++ } ++ break; ++ case 22: ++ str_content_type = "Handshake"; ++ str_details1 = "???"; ++ if (len > 0) ++ str_details1 = lookup((int)bp[0], handshakes, "???"); ++ break; ++ case 23: ++ str_content_type = "ApplicationData"; ++ break; ++#ifndef OPENSSL_NO_HEARTBEATS ++ case 24: ++ str_details1 = ", Heartbeat"; ++ ++ if (len > 0) { ++ switch (bp[0]) { ++ case 1: ++ str_details1 = ", HeartbeatRequest"; ++ break; ++ case 2: ++ str_details1 = ", HeartbeatResponse"; ++ break; ++ } ++ } ++ break; ++#endif ++ } ++ } ++ ++ BIO_printf(bio, "%s %s%s [length %04lx]%s%s\n", str_write_p, str_version, ++ str_content_type, (unsigned long)len, str_details1, ++ str_details2); ++ ++ if (len > 0) { ++ size_t num, i; ++ ++ BIO_printf(bio, " "); ++ num = len; ++ for (i = 0; i < num; i++) { ++ if (i % 16 == 0 && i > 0) ++ BIO_printf(bio, "\n "); ++ BIO_printf(bio, " %02x", ((const unsigned char *)buf)[i]); ++ } ++ if (i < len) ++ BIO_printf(bio, " ..."); ++ BIO_printf(bio, "\n"); ++ } ++ (void)BIO_flush(bio); ++} ++ ++static STRINT_PAIR tlsext_types[] = { ++ {"server name", TLSEXT_TYPE_server_name}, ++ {"max fragment length", TLSEXT_TYPE_max_fragment_length}, ++ {"client certificate URL", TLSEXT_TYPE_client_certificate_url}, ++ {"trusted CA keys", TLSEXT_TYPE_trusted_ca_keys}, ++ {"truncated HMAC", TLSEXT_TYPE_truncated_hmac}, ++ {"status request", TLSEXT_TYPE_status_request}, ++ {"user mapping", TLSEXT_TYPE_user_mapping}, ++ {"client authz", TLSEXT_TYPE_client_authz}, ++ {"server authz", TLSEXT_TYPE_server_authz}, ++ {"cert type", TLSEXT_TYPE_cert_type}, ++ {"elliptic curves", TLSEXT_TYPE_elliptic_curves}, ++ {"EC point formats", TLSEXT_TYPE_ec_point_formats}, ++ {"SRP", TLSEXT_TYPE_srp}, ++ {"signature algorithms", TLSEXT_TYPE_signature_algorithms}, ++ {"use SRTP", TLSEXT_TYPE_use_srtp}, ++ {"heartbeat", TLSEXT_TYPE_heartbeat}, ++ {"session ticket", TLSEXT_TYPE_session_ticket}, ++ {"renegotiation info", TLSEXT_TYPE_renegotiate}, ++ {"signed certificate timestamps", TLSEXT_TYPE_signed_certificate_timestamp}, ++ {"TLS padding", TLSEXT_TYPE_padding}, ++#ifdef TLSEXT_TYPE_next_proto_neg ++ {"next protocol", TLSEXT_TYPE_next_proto_neg}, ++#endif ++#ifdef TLSEXT_TYPE_encrypt_then_mac ++ {"encrypt-then-mac", TLSEXT_TYPE_encrypt_then_mac}, ++#endif ++#ifdef TLSEXT_TYPE_application_layer_protocol_negotiation ++ {"application layer protocol negotiation", ++ TLSEXT_TYPE_application_layer_protocol_negotiation}, ++#endif ++#ifdef TLSEXT_TYPE_extended_master_secret ++ {"extended master secret", TLSEXT_TYPE_extended_master_secret}, ++#endif ++ {NULL} ++}; ++ ++void tlsext_cb(SSL *s, int client_server, int type, ++ const unsigned char *data, int len, void *arg) ++{ ++ BIO *bio = arg; ++ const char *extname = lookup(type, tlsext_types, "unknown"); ++ ++ BIO_printf(bio, "TLS %s extension \"%s\" (id=%d), len=%d\n", ++ client_server ? "server" : "client", extname, type, len); ++ BIO_dump(bio, (const char *)data, len); ++ (void)BIO_flush(bio); ++} ++ ++#ifndef OPENSSL_NO_SOCK ++int generate_cookie_callback(SSL *ssl, unsigned char *cookie, ++ unsigned int *cookie_len) ++{ ++ unsigned char *buffer; ++ size_t length; ++ unsigned short port; ++ BIO_ADDR *peer = NULL; ++ ++ /* Initialize a random secret */ ++ if (!cookie_initialized) { ++ if (RAND_bytes(cookie_secret, COOKIE_SECRET_LENGTH) <= 0) { ++ BIO_printf(bio_err, "error setting random cookie secret\n"); ++ return 0; ++ } ++ cookie_initialized = 1; ++ } ++ ++ peer = BIO_ADDR_new(); ++ if (peer == NULL) { ++ BIO_printf(bio_err, "memory full\n"); ++ return 0; ++ } ++ ++ /* Read peer information */ ++ (void)BIO_dgram_get_peer(SSL_get_rbio(ssl), peer); ++ ++ /* Create buffer with peer's address and port */ ++ BIO_ADDR_rawaddress(peer, NULL, &length); ++ OPENSSL_assert(length != 0); ++ port = BIO_ADDR_rawport(peer); ++ length += sizeof(port); ++ buffer = app_malloc(length, "cookie generate buffer"); ++ ++ memcpy(buffer, &port, sizeof(port)); ++ BIO_ADDR_rawaddress(peer, buffer + sizeof(port), NULL); ++ ++ /* Calculate HMAC of buffer using the secret */ ++ HMAC(EVP_sha1(), cookie_secret, COOKIE_SECRET_LENGTH, ++ buffer, length, cookie, cookie_len); ++ ++ OPENSSL_free(buffer); ++ BIO_ADDR_free(peer); ++ ++ return 1; ++} ++ ++int verify_cookie_callback(SSL *ssl, const unsigned char *cookie, ++ unsigned int cookie_len) ++{ ++ unsigned char result[EVP_MAX_MD_SIZE]; ++ unsigned int resultlength; ++ ++ /* Note: we check cookie_initialized because if it's not, ++ * it cannot be valid */ ++ if (cookie_initialized ++ && generate_cookie_callback(ssl, result, &resultlength) ++ && cookie_len == resultlength ++ && memcmp(result, cookie, resultlength) == 0) ++ return 1; ++ ++ return 0; ++} ++#endif ++ ++/* ++ * Example of extended certificate handling. Where the standard support of ++ * one certificate per algorithm is not sufficient an application can decide ++ * which certificate(s) to use at runtime based on whatever criteria it deems ++ * appropriate. ++ */ ++ ++/* Linked list of certificates, keys and chains */ ++struct ssl_excert_st { ++ int certform; ++ const char *certfile; ++ int keyform; ++ const char *keyfile; ++ const char *chainfile; ++ X509 *cert; ++ EVP_PKEY *key; ++ STACK_OF(X509) *chain; ++ int build_chain; ++ struct ssl_excert_st *next, *prev; ++}; ++ ++static STRINT_PAIR chain_flags[] = { ++ {"Overall Validity", CERT_PKEY_VALID}, ++ {"Sign with EE key", CERT_PKEY_SIGN}, ++ {"EE signature", CERT_PKEY_EE_SIGNATURE}, ++ {"CA signature", CERT_PKEY_CA_SIGNATURE}, ++ {"EE key parameters", CERT_PKEY_EE_PARAM}, ++ {"CA key parameters", CERT_PKEY_CA_PARAM}, ++ {"Explicitly sign with EE key", CERT_PKEY_EXPLICIT_SIGN}, ++ {"Issuer Name", CERT_PKEY_ISSUER_NAME}, ++ {"Certificate Type", CERT_PKEY_CERT_TYPE}, ++ {NULL} ++}; ++ ++static void print_chain_flags(SSL *s, int flags) ++{ ++ STRINT_PAIR *pp; ++ ++ for (pp = chain_flags; pp->name; ++pp) ++ BIO_printf(bio_err, "\t%s: %s\n", ++ pp->name, ++ (flags & pp->retval) ? "OK" : "NOT OK"); ++ BIO_printf(bio_err, "\tSuite B: "); ++ if (SSL_set_cert_flags(s, 0) & SSL_CERT_FLAG_SUITEB_128_LOS) ++ BIO_puts(bio_err, flags & CERT_PKEY_SUITEB ? "OK\n" : "NOT OK\n"); ++ else ++ BIO_printf(bio_err, "not tested\n"); ++} ++ ++/* ++ * Very basic selection callback: just use any certificate chain reported as ++ * valid. More sophisticated could prioritise according to local policy. ++ */ ++static int set_cert_cb(SSL *ssl, void *arg) ++{ ++ int i, rv; ++ SSL_EXCERT *exc = arg; ++#ifdef CERT_CB_TEST_RETRY ++ static int retry_cnt; ++ if (retry_cnt < 5) { ++ retry_cnt++; ++ BIO_printf(bio_err, ++ "Certificate callback retry test: count %d\n", ++ retry_cnt); ++ return -1; ++ } ++#endif ++ SSL_certs_clear(ssl); ++ ++ if (!exc) ++ return 1; ++ ++ /* ++ * Go to end of list and traverse backwards since we prepend newer ++ * entries this retains the original order. ++ */ ++ while (exc->next) ++ exc = exc->next; ++ ++ i = 0; ++ ++ while (exc) { ++ i++; ++ rv = SSL_check_chain(ssl, exc->cert, exc->key, exc->chain); ++ BIO_printf(bio_err, "Checking cert chain %d:\nSubject: ", i); ++ X509_NAME_print_ex(bio_err, X509_get_subject_name(exc->cert), 0, ++ XN_FLAG_ONELINE); ++ BIO_puts(bio_err, "\n"); ++ print_chain_flags(ssl, rv); ++ if (rv & CERT_PKEY_VALID) { ++ if (!SSL_use_certificate(ssl, exc->cert) ++ || !SSL_use_PrivateKey(ssl, exc->key)) { ++ return 0; ++ } ++ /* ++ * NB: we wouldn't normally do this as it is not efficient ++ * building chains on each connection better to cache the chain ++ * in advance. ++ */ ++ if (exc->build_chain) { ++ if (!SSL_build_cert_chain(ssl, 0)) ++ return 0; ++ } else if (exc->chain) ++ SSL_set1_chain(ssl, exc->chain); ++ } ++ exc = exc->prev; ++ } ++ return 1; ++} ++ ++void ssl_ctx_set_excert(SSL_CTX *ctx, SSL_EXCERT *exc) ++{ ++ SSL_CTX_set_cert_cb(ctx, set_cert_cb, exc); ++} ++ ++static int ssl_excert_prepend(SSL_EXCERT **pexc) ++{ ++ SSL_EXCERT *exc = app_malloc(sizeof(*exc), "prepend cert"); ++ ++ memset(exc, 0, sizeof(*exc)); ++ ++ exc->next = *pexc; ++ *pexc = exc; ++ ++ if (exc->next) { ++ exc->certform = exc->next->certform; ++ exc->keyform = exc->next->keyform; ++ exc->next->prev = exc; ++ } else { ++ exc->certform = FORMAT_PEM; ++ exc->keyform = FORMAT_PEM; ++ } ++ return 1; ++ ++} ++ ++void ssl_excert_free(SSL_EXCERT *exc) ++{ ++ SSL_EXCERT *curr; ++ ++ if (!exc) ++ return; ++ while (exc) { ++ X509_free(exc->cert); ++ EVP_PKEY_free(exc->key); ++ sk_X509_pop_free(exc->chain, X509_free); ++ curr = exc; ++ exc = exc->next; ++ OPENSSL_free(curr); ++ } ++} ++ ++int load_excert(SSL_EXCERT **pexc) ++{ ++ SSL_EXCERT *exc = *pexc; ++ if (!exc) ++ return 1; ++ /* If nothing in list, free and set to NULL */ ++ if (!exc->certfile && !exc->next) { ++ ssl_excert_free(exc); ++ *pexc = NULL; ++ return 1; ++ } ++ for (; exc; exc = exc->next) { ++ if (!exc->certfile) { ++ BIO_printf(bio_err, "Missing filename\n"); ++ return 0; ++ } ++ exc->cert = load_cert(exc->certfile, exc->certform, ++ "Server Certificate"); ++ if (!exc->cert) ++ return 0; ++ if (exc->keyfile) { ++ exc->key = load_key(exc->keyfile, exc->keyform, ++ 0, NULL, NULL, "Server Key"); ++ } else { ++ exc->key = load_key(exc->certfile, exc->certform, ++ 0, NULL, NULL, "Server Key"); ++ } ++ if (!exc->key) ++ return 0; ++ if (exc->chainfile) { ++ if (!load_certs(exc->chainfile, &exc->chain, FORMAT_PEM, NULL, ++ "Server Chain")) ++ return 0; ++ } ++ } ++ return 1; ++} ++ ++enum range { OPT_X_ENUM }; ++ ++int args_excert(int opt, SSL_EXCERT **pexc) ++{ ++ SSL_EXCERT *exc = *pexc; ++ ++ assert(opt > OPT_X__FIRST); ++ assert(opt < OPT_X__LAST); ++ ++ if (exc == NULL) { ++ if (!ssl_excert_prepend(&exc)) { ++ BIO_printf(bio_err, " %s: Error initialising xcert\n", ++ opt_getprog()); ++ goto err; ++ } ++ *pexc = exc; ++ } ++ ++ switch ((enum range)opt) { ++ case OPT_X__FIRST: ++ case OPT_X__LAST: ++ return 0; ++ case OPT_X_CERT: ++ if (exc->certfile && !ssl_excert_prepend(&exc)) { ++ BIO_printf(bio_err, "%s: Error adding xcert\n", opt_getprog()); ++ goto err; ++ } ++ *pexc = exc; ++ exc->certfile = opt_arg(); ++ break; ++ case OPT_X_KEY: ++ if (exc->keyfile) { ++ BIO_printf(bio_err, "%s: Key already specified\n", opt_getprog()); ++ goto err; ++ } ++ exc->keyfile = opt_arg(); ++ break; ++ case OPT_X_CHAIN: ++ if (exc->chainfile) { ++ BIO_printf(bio_err, "%s: Chain already specified\n", ++ opt_getprog()); ++ goto err; ++ } ++ exc->chainfile = opt_arg(); ++ break; ++ case OPT_X_CHAIN_BUILD: ++ exc->build_chain = 1; ++ break; ++ case OPT_X_CERTFORM: ++ if (!opt_format(opt_arg(), OPT_FMT_PEMDER, &exc->certform)) ++ return 0; ++ break; ++ case OPT_X_KEYFORM: ++ if (!opt_format(opt_arg(), OPT_FMT_PEMDER, &exc->keyform)) ++ return 0; ++ break; ++ } ++ return 1; ++ ++ err: ++ ERR_print_errors(bio_err); ++ ssl_excert_free(exc); ++ *pexc = NULL; ++ return 0; ++} ++ ++static void print_raw_cipherlist(SSL *s) ++{ ++ const unsigned char *rlist; ++ static const unsigned char scsv_id[] = { 0, 0xFF }; ++ size_t i, rlistlen, num; ++ if (!SSL_is_server(s)) ++ return; ++ num = SSL_get0_raw_cipherlist(s, NULL); ++ OPENSSL_assert(num == 2); ++ rlistlen = SSL_get0_raw_cipherlist(s, &rlist); ++ BIO_puts(bio_err, "Client cipher list: "); ++ for (i = 0; i < rlistlen; i += num, rlist += num) { ++ const SSL_CIPHER *c = SSL_CIPHER_find(s, rlist); ++ if (i) ++ BIO_puts(bio_err, ":"); ++ if (c) ++ BIO_puts(bio_err, SSL_CIPHER_get_name(c)); ++ else if (!memcmp(rlist, scsv_id, num)) ++ BIO_puts(bio_err, "SCSV"); ++ else { ++ size_t j; ++ BIO_puts(bio_err, "0x"); ++ for (j = 0; j < num; j++) ++ BIO_printf(bio_err, "%02X", rlist[j]); ++ } ++ } ++ BIO_puts(bio_err, "\n"); ++} ++ ++/* ++ * Hex encoder for TLSA RRdata, not ':' delimited. ++ */ ++static char *hexencode(const unsigned char *data, size_t len) ++{ ++ static const char *hex = "0123456789abcdef"; ++ char *out; ++ char *cp; ++ size_t outlen = 2 * len + 1; ++ int ilen = (int) outlen; ++ ++ if (outlen < len || ilen < 0 || outlen != (size_t)ilen) { ++ BIO_printf(bio_err, "%s: %" PRIu64 "-byte buffer too large to hexencode\n", ++ opt_getprog(), (uint64_t)len); ++ exit(1); ++ } ++ cp = out = app_malloc(ilen, "TLSA hex data buffer"); ++ ++ while (len-- > 0) { ++ *cp++ = hex[(*data >> 4) & 0x0f]; ++ *cp++ = hex[*data++ & 0x0f]; ++ } ++ *cp = '\0'; ++ return out; ++} ++ ++void print_verify_detail(SSL *s, BIO *bio) ++{ ++ int mdpth; ++ EVP_PKEY *mspki; ++ long verify_err = SSL_get_verify_result(s); ++ ++ if (verify_err == X509_V_OK) { ++ const char *peername = SSL_get0_peername(s); ++ ++ BIO_printf(bio, "Verification: OK\n"); ++ if (peername != NULL) ++ BIO_printf(bio, "Verified peername: %s\n", peername); ++ } else { ++ const char *reason = X509_verify_cert_error_string(verify_err); ++ ++ BIO_printf(bio, "Verification error: %s\n", reason); ++ } ++ ++ if ((mdpth = SSL_get0_dane_authority(s, NULL, &mspki)) >= 0) { ++ uint8_t usage, selector, mtype; ++ const unsigned char *data = NULL; ++ size_t dlen = 0; ++ char *hexdata; ++ ++ mdpth = SSL_get0_dane_tlsa(s, &usage, &selector, &mtype, &data, &dlen); ++ ++ /* ++ * The TLSA data field can be quite long when it is a certificate, ++ * public key or even a SHA2-512 digest. Because the initial octets of ++ * ASN.1 certificates and public keys contain mostly boilerplate OIDs ++ * and lengths, we show the last 12 bytes of the data instead, as these ++ * are more likely to distinguish distinct TLSA records. ++ */ ++#define TLSA_TAIL_SIZE 12 ++ if (dlen > TLSA_TAIL_SIZE) ++ hexdata = hexencode(data + dlen - TLSA_TAIL_SIZE, TLSA_TAIL_SIZE); ++ else ++ hexdata = hexencode(data, dlen); ++ BIO_printf(bio, "DANE TLSA %d %d %d %s%s %s at depth %d\n", ++ usage, selector, mtype, ++ (dlen > TLSA_TAIL_SIZE) ? "..." : "", hexdata, ++ (mspki != NULL) ? "signed the certificate" : ++ mdpth ? "matched TA certificate" : "matched EE certificate", ++ mdpth); ++ OPENSSL_free(hexdata); ++ } ++} ++ ++void print_ssl_summary(SSL *s) ++{ ++ const SSL_CIPHER *c; ++ X509 *peer; ++ /* const char *pnam = SSL_is_server(s) ? "client" : "server"; */ ++ ++ BIO_printf(bio_err, "Protocol version: %s\n", SSL_get_version(s)); ++ print_raw_cipherlist(s); ++ c = SSL_get_current_cipher(s); ++ BIO_printf(bio_err, "Ciphersuite: %s\n", SSL_CIPHER_get_name(c)); ++ do_print_sigalgs(bio_err, s, 0); ++ peer = SSL_get_peer_certificate(s); ++ if (peer) { ++ int nid; ++ ++ BIO_puts(bio_err, "Peer certificate: "); ++ X509_NAME_print_ex(bio_err, X509_get_subject_name(peer), ++ 0, XN_FLAG_ONELINE); ++ BIO_puts(bio_err, "\n"); ++ if (SSL_get_peer_signature_nid(s, &nid)) ++ BIO_printf(bio_err, "Hash used: %s\n", OBJ_nid2sn(nid)); ++ print_verify_detail(s, bio_err); ++ } else ++ BIO_puts(bio_err, "No peer certificate\n"); ++ X509_free(peer); ++#ifndef OPENSSL_NO_EC ++ ssl_print_point_formats(bio_err, s); ++ if (SSL_is_server(s)) ++ ssl_print_curves(bio_err, s, 1); ++ else ++ ssl_print_tmp_key(bio_err, s); ++#else ++ if (!SSL_is_server(s)) ++ ssl_print_tmp_key(bio_err, s); ++#endif ++} ++ ++int config_ctx(SSL_CONF_CTX *cctx, STACK_OF(OPENSSL_STRING) *str, ++ SSL_CTX *ctx) ++{ ++ int i; ++ ++ SSL_CONF_CTX_set_ssl_ctx(cctx, ctx); ++ for (i = 0; i < sk_OPENSSL_STRING_num(str); i += 2) { ++ const char *flag = sk_OPENSSL_STRING_value(str, i); ++ const char *arg = sk_OPENSSL_STRING_value(str, i + 1); ++ if (SSL_CONF_cmd(cctx, flag, arg) <= 0) { ++ if (arg) ++ BIO_printf(bio_err, "Error with command: \"%s %s\"\n", ++ flag, arg); ++ else ++ BIO_printf(bio_err, "Error with command: \"%s\"\n", flag); ++ ERR_print_errors(bio_err); ++ return 0; ++ } ++ } ++ if (!SSL_CONF_CTX_finish(cctx)) { ++ BIO_puts(bio_err, "Error finishing context\n"); ++ ERR_print_errors(bio_err); ++ return 0; ++ } ++ return 1; ++} ++ ++static int add_crls_store(X509_STORE *st, STACK_OF(X509_CRL) *crls) ++{ ++ X509_CRL *crl; ++ int i; ++ for (i = 0; i < sk_X509_CRL_num(crls); i++) { ++ crl = sk_X509_CRL_value(crls, i); ++ X509_STORE_add_crl(st, crl); ++ } ++ return 1; ++} ++ ++int ssl_ctx_add_crls(SSL_CTX *ctx, STACK_OF(X509_CRL) *crls, int crl_download) ++{ ++ X509_STORE *st; ++ st = SSL_CTX_get_cert_store(ctx); ++ add_crls_store(st, crls); ++ if (crl_download) ++ store_setup_crl_download(st); ++ return 1; ++} ++ ++int ssl_load_stores(SSL_CTX *ctx, ++ const char *vfyCApath, const char *vfyCAfile, ++ const char *chCApath, const char *chCAfile, ++ STACK_OF(X509_CRL) *crls, int crl_download) ++{ ++ X509_STORE *vfy = NULL, *ch = NULL; ++ int rv = 0; ++ if (vfyCApath != NULL || vfyCAfile != NULL) { ++ vfy = X509_STORE_new(); ++ if (vfy == NULL) ++ goto err; ++ if (!X509_STORE_load_locations(vfy, vfyCAfile, vfyCApath)) ++ goto err; ++ add_crls_store(vfy, crls); ++ SSL_CTX_set1_verify_cert_store(ctx, vfy); ++ if (crl_download) ++ store_setup_crl_download(vfy); ++ } ++ if (chCApath != NULL || chCAfile != NULL) { ++ ch = X509_STORE_new(); ++ if (ch == NULL) ++ goto err; ++ if (!X509_STORE_load_locations(ch, chCAfile, chCApath)) ++ goto err; ++ SSL_CTX_set1_chain_cert_store(ctx, ch); ++ } ++ rv = 1; ++ err: ++ X509_STORE_free(vfy); ++ X509_STORE_free(ch); ++ return rv; ++} ++ ++/* Verbose print out of security callback */ ++ ++typedef struct { ++ BIO *out; ++ int verbose; ++ int (*old_cb) (const SSL *s, const SSL_CTX *ctx, int op, int bits, int nid, ++ void *other, void *ex); ++} security_debug_ex; ++ ++static STRINT_PAIR callback_types[] = { ++ {"Supported Ciphersuite", SSL_SECOP_CIPHER_SUPPORTED}, ++ {"Shared Ciphersuite", SSL_SECOP_CIPHER_SHARED}, ++ {"Check Ciphersuite", SSL_SECOP_CIPHER_CHECK}, ++#ifndef OPENSSL_NO_DH ++ {"Temp DH key bits", SSL_SECOP_TMP_DH}, ++#endif ++ {"Supported Curve", SSL_SECOP_CURVE_SUPPORTED}, ++ {"Shared Curve", SSL_SECOP_CURVE_SHARED}, ++ {"Check Curve", SSL_SECOP_CURVE_CHECK}, ++ {"Supported Signature Algorithm digest", SSL_SECOP_SIGALG_SUPPORTED}, ++ {"Shared Signature Algorithm digest", SSL_SECOP_SIGALG_SHARED}, ++ {"Check Signature Algorithm digest", SSL_SECOP_SIGALG_CHECK}, ++ {"Signature Algorithm mask", SSL_SECOP_SIGALG_MASK}, ++ {"Certificate chain EE key", SSL_SECOP_EE_KEY}, ++ {"Certificate chain CA key", SSL_SECOP_CA_KEY}, ++ {"Peer Chain EE key", SSL_SECOP_PEER_EE_KEY}, ++ {"Peer Chain CA key", SSL_SECOP_PEER_CA_KEY}, ++ {"Certificate chain CA digest", SSL_SECOP_CA_MD}, ++ {"Peer chain CA digest", SSL_SECOP_PEER_CA_MD}, ++ {"SSL compression", SSL_SECOP_COMPRESSION}, ++ {"Session ticket", SSL_SECOP_TICKET}, ++ {NULL} ++}; ++ ++static int security_callback_debug(const SSL *s, const SSL_CTX *ctx, ++ int op, int bits, int nid, ++ void *other, void *ex) ++{ ++ security_debug_ex *sdb = ex; ++ int rv, show_bits = 1, cert_md = 0; ++ const char *nm; ++ rv = sdb->old_cb(s, ctx, op, bits, nid, other, ex); ++ if (rv == 1 && sdb->verbose < 2) ++ return 1; ++ BIO_puts(sdb->out, "Security callback: "); ++ ++ nm = lookup(op, callback_types, NULL); ++ switch (op) { ++ case SSL_SECOP_TICKET: ++ case SSL_SECOP_COMPRESSION: ++ show_bits = 0; ++ nm = NULL; ++ break; ++ case SSL_SECOP_VERSION: ++ BIO_printf(sdb->out, "Version=%s", lookup(nid, ssl_versions, "???")); ++ show_bits = 0; ++ nm = NULL; ++ break; ++ case SSL_SECOP_CA_MD: ++ case SSL_SECOP_PEER_CA_MD: ++ cert_md = 1; ++ break; ++ } ++ if (nm) ++ BIO_printf(sdb->out, "%s=", nm); ++ ++ switch (op & SSL_SECOP_OTHER_TYPE) { ++ ++ case SSL_SECOP_OTHER_CIPHER: ++ BIO_puts(sdb->out, SSL_CIPHER_get_name(other)); ++ break; ++ ++#ifndef OPENSSL_NO_EC ++ case SSL_SECOP_OTHER_CURVE: ++ { ++ const char *cname; ++ cname = EC_curve_nid2nist(nid); ++ if (cname == NULL) ++ cname = OBJ_nid2sn(nid); ++ BIO_puts(sdb->out, cname); ++ } ++ break; ++#endif ++#ifndef OPENSSL_NO_DH ++ case SSL_SECOP_OTHER_DH: ++ { ++ DH *dh = other; ++ BIO_printf(sdb->out, "%d", DH_bits(dh)); ++ break; ++ } ++#endif ++ case SSL_SECOP_OTHER_CERT: ++ { ++ if (cert_md) { ++ int sig_nid = X509_get_signature_nid(other); ++ BIO_puts(sdb->out, OBJ_nid2sn(sig_nid)); ++ } else { ++ EVP_PKEY *pkey = X509_get0_pubkey(other); ++ const char *algname = ""; ++ EVP_PKEY_asn1_get0_info(NULL, NULL, NULL, NULL, ++ &algname, EVP_PKEY_get0_asn1(pkey)); ++ BIO_printf(sdb->out, "%s, bits=%d", ++ algname, EVP_PKEY_bits(pkey)); ++ } ++ break; ++ } ++ case SSL_SECOP_OTHER_SIGALG: ++ { ++ const unsigned char *salg = other; ++ const char *sname = NULL; ++ switch (salg[1]) { ++ case TLSEXT_signature_anonymous: ++ sname = "anonymous"; ++ break; ++ case TLSEXT_signature_rsa: ++ sname = "RSA"; ++ break; ++ case TLSEXT_signature_dsa: ++ sname = "DSA"; ++ break; ++ case TLSEXT_signature_ecdsa: ++ sname = "ECDSA"; ++ break; ++ } ++ ++ BIO_puts(sdb->out, OBJ_nid2sn(nid)); ++ if (sname) ++ BIO_printf(sdb->out, ", algorithm=%s", sname); ++ else ++ BIO_printf(sdb->out, ", algid=%d", salg[1]); ++ break; ++ } ++ ++ } ++ ++ if (show_bits) ++ BIO_printf(sdb->out, ", security bits=%d", bits); ++ BIO_printf(sdb->out, ": %s\n", rv ? "yes" : "no"); ++ return rv; ++} ++ ++void ssl_ctx_security_debug(SSL_CTX *ctx, int verbose) ++{ ++ static security_debug_ex sdb; ++ ++ sdb.out = bio_err; ++ sdb.verbose = verbose; ++ sdb.old_cb = SSL_CTX_get_security_callback(ctx); ++ SSL_CTX_set_security_callback(ctx, security_callback_debug); ++ SSL_CTX_set0_security_ex_data(ctx, &sdb); ++} +diff --git a/CryptoPkg/Library/OpensslLib/openssl/apps/s_client.c b/CryptoPkg/Library/OpensslLib/openssl/apps/s_client.c +new file mode 100644 +index 0000000..458b9e0 +--- /dev/null ++++ b/CryptoPkg/Library/OpensslLib/openssl/apps/s_client.c +@@ -0,0 +1,2747 @@ ++/* ++ * Copyright 1995-2016 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 ++ * in the file LICENSE in the source distribution or at ++ * https://www.openssl.org/source/license.html ++ */ ++ ++/* ==================================================================== ++ * Copyright 2005 Nokia. All rights reserved. ++ * ++ * The portions of the attached software ("Contribution") is developed by ++ * Nokia Corporation and is licensed pursuant to the OpenSSL open source ++ * license. ++ * ++ * The Contribution, originally written by Mika Kousa and Pasi Eronen of ++ * Nokia Corporation, consists of the "PSK" (Pre-Shared Key) ciphersuites ++ * support (see RFC 4279) to OpenSSL. ++ * ++ * No patent licenses or other rights except those expressly stated in ++ * the OpenSSL open source license shall be deemed granted or received ++ * expressly, by implication, estoppel, or otherwise. ++ * ++ * No assurances are provided by Nokia that the Contribution does not ++ * infringe the patent or other intellectual property rights of any third ++ * party or that the license provides you with all the necessary rights ++ * to make use of the Contribution. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND. IN ++ * ADDITION TO THE DISCLAIMERS INCLUDED IN THE LICENSE, NOKIA ++ * SPECIFICALLY DISCLAIMS ANY LIABILITY FOR CLAIMS BROUGHT BY YOU OR ANY ++ * OTHER ENTITY BASED ON INFRINGEMENT OF INTELLECTUAL PROPERTY RIGHTS OR ++ * OTHERWISE. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#ifndef OPENSSL_NO_SOCK ++ ++/* ++ * With IPv6, it looks like Digital has mixed up the proper order of ++ * recursive header file inclusion, resulting in the compiler complaining ++ * that u_int isn't defined, but only if _POSIX_C_SOURCE is defined, which is ++ * needed to have fileno() declared correctly... So let's define u_int ++ */ ++#if defined(OPENSSL_SYS_VMS_DECC) && !defined(__U_INT) ++# define __U_INT ++typedef unsigned int u_int; ++#endif ++ ++#define USE_SOCKETS ++#include "apps.h" ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#ifndef OPENSSL_NO_SRP ++# include ++#endif ++#ifndef OPENSSL_NO_CT ++# include ++#endif ++#include "s_apps.h" ++#include "timeouts.h" ++ ++#if defined(__has_feature) ++# if __has_feature(memory_sanitizer) ++# include ++# endif ++#endif ++ ++#undef BUFSIZZ ++#define BUFSIZZ 1024*8 ++#define S_CLIENT_IRC_READ_TIMEOUT 8 ++ ++static char *prog; ++static int c_debug = 0; ++static int c_showcerts = 0; ++static char *keymatexportlabel = NULL; ++static int keymatexportlen = 20; ++static BIO *bio_c_out = NULL; ++static int c_quiet = 0; ++ ++static void print_stuff(BIO *berr, SSL *con, int full); ++#ifndef OPENSSL_NO_OCSP ++static int ocsp_resp_cb(SSL *s, void *arg); ++#endif ++ ++static int saved_errno; ++ ++static void save_errno(void) ++{ ++ saved_errno = errno; ++ errno = 0; ++} ++ ++static int restore_errno(void) ++{ ++ int ret = errno; ++ errno = saved_errno; ++ return ret; ++} ++ ++static void do_ssl_shutdown(SSL *ssl) ++{ ++ int ret; ++ ++ do { ++ /* We only do unidirectional shutdown */ ++ ret = SSL_shutdown(ssl); ++ if (ret < 0) { ++ switch (SSL_get_error(ssl, ret)) { ++ case SSL_ERROR_WANT_READ: ++ case SSL_ERROR_WANT_WRITE: ++ case SSL_ERROR_WANT_ASYNC: ++ case SSL_ERROR_WANT_ASYNC_JOB: ++ /* We just do busy waiting. Nothing clever */ ++ continue; ++ } ++ ret = 0; ++ } ++ } while (ret < 0); ++} ++ ++#ifndef OPENSSL_NO_PSK ++/* Default PSK identity and key */ ++static char *psk_identity = "Client_identity"; ++/* ++ * char *psk_key=NULL; by default PSK is not used ++ */ ++ ++static unsigned int psk_client_cb(SSL *ssl, const char *hint, char *identity, ++ unsigned int max_identity_len, ++ unsigned char *psk, ++ unsigned int max_psk_len) ++{ ++ int ret; ++ long key_len; ++ unsigned char *key; ++ ++ if (c_debug) ++ BIO_printf(bio_c_out, "psk_client_cb\n"); ++ if (!hint) { ++ /* no ServerKeyExchange message */ ++ if (c_debug) ++ BIO_printf(bio_c_out, ++ "NULL received PSK identity hint, continuing anyway\n"); ++ } else if (c_debug) ++ BIO_printf(bio_c_out, "Received PSK identity hint '%s'\n", hint); ++ ++ /* ++ * lookup PSK identity and PSK key based on the given identity hint here ++ */ ++ ret = BIO_snprintf(identity, max_identity_len, "%s", psk_identity); ++ if (ret < 0 || (unsigned int)ret > max_identity_len) ++ goto out_err; ++ if (c_debug) ++ BIO_printf(bio_c_out, "created identity '%s' len=%d\n", identity, ++ ret); ++ ++ /* convert the PSK key to binary */ ++ key = OPENSSL_hexstr2buf(psk_key, &key_len); ++ if (key == NULL) { ++ BIO_printf(bio_err, "Could not convert PSK key '%s' to buffer\n", ++ psk_key); ++ return 0; ++ } ++ if (key_len > max_psk_len) { ++ BIO_printf(bio_err, ++ "psk buffer of callback is too small (%d) for key (%ld)\n", ++ max_psk_len, key_len); ++ OPENSSL_free(key); ++ return 0; ++ } ++ ++ memcpy(psk, key, key_len); ++ OPENSSL_free(key); ++ ++ if (c_debug) ++ BIO_printf(bio_c_out, "created PSK len=%ld\n", key_len); ++ ++ return key_len; ++ out_err: ++ if (c_debug) ++ BIO_printf(bio_err, "Error in PSK client callback\n"); ++ return 0; ++} ++#endif ++ ++/* This is a context that we pass to callbacks */ ++typedef struct tlsextctx_st { ++ BIO *biodebug; ++ int ack; ++} tlsextctx; ++ ++static int ssl_servername_cb(SSL *s, int *ad, void *arg) ++{ ++ tlsextctx *p = (tlsextctx *) arg; ++ const char *hn = SSL_get_servername(s, TLSEXT_NAMETYPE_host_name); ++ if (SSL_get_servername_type(s) != -1) ++ p->ack = !SSL_session_reused(s) && hn != NULL; ++ else ++ BIO_printf(bio_err, "Can't use SSL_get_servername\n"); ++ ++ return SSL_TLSEXT_ERR_OK; ++} ++ ++#ifndef OPENSSL_NO_SRP ++ ++/* This is a context that we pass to all callbacks */ ++typedef struct srp_arg_st { ++ char *srppassin; ++ char *srplogin; ++ int msg; /* copy from c_msg */ ++ int debug; /* copy from c_debug */ ++ int amp; /* allow more groups */ ++ int strength; /* minimal size for N */ ++} SRP_ARG; ++ ++# define SRP_NUMBER_ITERATIONS_FOR_PRIME 64 ++ ++static int srp_Verify_N_and_g(const BIGNUM *N, const BIGNUM *g) ++{ ++ BN_CTX *bn_ctx = BN_CTX_new(); ++ BIGNUM *p = BN_new(); ++ BIGNUM *r = BN_new(); ++ int ret = ++ g != NULL && N != NULL && bn_ctx != NULL && BN_is_odd(N) && ++ BN_is_prime_ex(N, SRP_NUMBER_ITERATIONS_FOR_PRIME, bn_ctx, NULL) == 1 && ++ p != NULL && BN_rshift1(p, N) && ++ /* p = (N-1)/2 */ ++ BN_is_prime_ex(p, SRP_NUMBER_ITERATIONS_FOR_PRIME, bn_ctx, NULL) == 1 && ++ r != NULL && ++ /* verify g^((N-1)/2) == -1 (mod N) */ ++ BN_mod_exp(r, g, p, N, bn_ctx) && ++ BN_add_word(r, 1) && BN_cmp(r, N) == 0; ++ ++ BN_free(r); ++ BN_free(p); ++ BN_CTX_free(bn_ctx); ++ return ret; ++} ++ ++/*- ++ * This callback is used here for two purposes: ++ * - extended debugging ++ * - making some primality tests for unknown groups ++ * The callback is only called for a non default group. ++ * ++ * An application does not need the call back at all if ++ * only the standard groups are used. In real life situations, ++ * client and server already share well known groups, ++ * thus there is no need to verify them. ++ * Furthermore, in case that a server actually proposes a group that ++ * is not one of those defined in RFC 5054, it is more appropriate ++ * to add the group to a static list and then compare since ++ * primality tests are rather cpu consuming. ++ */ ++ ++static int ssl_srp_verify_param_cb(SSL *s, void *arg) ++{ ++ SRP_ARG *srp_arg = (SRP_ARG *)arg; ++ BIGNUM *N = NULL, *g = NULL; ++ ++ if (((N = SSL_get_srp_N(s)) == NULL) || ((g = SSL_get_srp_g(s)) == NULL)) ++ return 0; ++ if (srp_arg->debug || srp_arg->msg || srp_arg->amp == 1) { ++ BIO_printf(bio_err, "SRP parameters:\n"); ++ BIO_printf(bio_err, "\tN="); ++ BN_print(bio_err, N); ++ BIO_printf(bio_err, "\n\tg="); ++ BN_print(bio_err, g); ++ BIO_printf(bio_err, "\n"); ++ } ++ ++ if (SRP_check_known_gN_param(g, N)) ++ return 1; ++ ++ if (srp_arg->amp == 1) { ++ if (srp_arg->debug) ++ BIO_printf(bio_err, ++ "SRP param N and g are not known params, going to check deeper.\n"); ++ ++ /* ++ * The srp_moregroups is a real debugging feature. Implementors ++ * should rather add the value to the known ones. The minimal size ++ * has already been tested. ++ */ ++ if (BN_num_bits(g) <= BN_BITS && srp_Verify_N_and_g(N, g)) ++ return 1; ++ } ++ BIO_printf(bio_err, "SRP param N and g rejected.\n"); ++ return 0; ++} ++ ++# define PWD_STRLEN 1024 ++ ++static char *ssl_give_srp_client_pwd_cb(SSL *s, void *arg) ++{ ++ SRP_ARG *srp_arg = (SRP_ARG *)arg; ++ char *pass = app_malloc(PWD_STRLEN + 1, "SRP password buffer"); ++ PW_CB_DATA cb_tmp; ++ int l; ++ ++ cb_tmp.password = (char *)srp_arg->srppassin; ++ cb_tmp.prompt_info = "SRP user"; ++ if ((l = password_callback(pass, PWD_STRLEN, 0, &cb_tmp)) < 0) { ++ BIO_printf(bio_err, "Can't read Password\n"); ++ OPENSSL_free(pass); ++ return NULL; ++ } ++ *(pass + l) = '\0'; ++ ++ return pass; ++} ++ ++#endif ++ ++static char *srtp_profiles = NULL; ++ ++#ifndef OPENSSL_NO_NEXTPROTONEG ++/* This the context that we pass to next_proto_cb */ ++typedef struct tlsextnextprotoctx_st { ++ unsigned char *data; ++ size_t len; ++ int status; ++} tlsextnextprotoctx; ++ ++static tlsextnextprotoctx next_proto; ++ ++static int next_proto_cb(SSL *s, unsigned char **out, unsigned char *outlen, ++ const unsigned char *in, unsigned int inlen, ++ void *arg) ++{ ++ tlsextnextprotoctx *ctx = arg; ++ ++ if (!c_quiet) { ++ /* We can assume that |in| is syntactically valid. */ ++ unsigned i; ++ BIO_printf(bio_c_out, "Protocols advertised by server: "); ++ for (i = 0; i < inlen;) { ++ if (i) ++ BIO_write(bio_c_out, ", ", 2); ++ BIO_write(bio_c_out, &in[i + 1], in[i]); ++ i += in[i] + 1; ++ } ++ BIO_write(bio_c_out, "\n", 1); ++ } ++ ++ ctx->status = ++ SSL_select_next_proto(out, outlen, in, inlen, ctx->data, ctx->len); ++ return SSL_TLSEXT_ERR_OK; ++} ++#endif /* ndef OPENSSL_NO_NEXTPROTONEG */ ++ ++static int serverinfo_cli_parse_cb(SSL *s, unsigned int ext_type, ++ const unsigned char *in, size_t inlen, ++ int *al, void *arg) ++{ ++ char pem_name[100]; ++ unsigned char ext_buf[4 + 65536]; ++ ++ /* Reconstruct the type/len fields prior to extension data */ ++ ext_buf[0] = ext_type >> 8; ++ ext_buf[1] = ext_type & 0xFF; ++ ext_buf[2] = inlen >> 8; ++ ext_buf[3] = inlen & 0xFF; ++ memcpy(ext_buf + 4, in, inlen); ++ ++ BIO_snprintf(pem_name, sizeof(pem_name), "SERVERINFO FOR EXTENSION %d", ++ ext_type); ++ PEM_write_bio(bio_c_out, pem_name, "", ext_buf, 4 + inlen); ++ return 1; ++} ++ ++/* ++ * Hex decoder that tolerates optional whitespace. Returns number of bytes ++ * produced, advances inptr to end of input string. ++ */ ++static ossl_ssize_t hexdecode(const char **inptr, void *result) ++{ ++ unsigned char **out = (unsigned char **)result; ++ const char *in = *inptr; ++ unsigned char *ret = app_malloc(strlen(in) / 2, "hexdecode"); ++ unsigned char *cp = ret; ++ uint8_t byte; ++ int nibble = 0; ++ ++ if (ret == NULL) ++ return -1; ++ ++ for (byte = 0; *in; ++in) { ++ int x; ++ ++ if (isspace(_UC(*in))) ++ continue; ++ x = OPENSSL_hexchar2int(*in); ++ if (x < 0) { ++ OPENSSL_free(ret); ++ return 0; ++ } ++ byte |= (char)x; ++ if ((nibble ^= 1) == 0) { ++ *cp++ = byte; ++ byte = 0; ++ } else { ++ byte <<= 4; ++ } ++ } ++ if (nibble != 0) { ++ OPENSSL_free(ret); ++ return 0; ++ } ++ *inptr = in; ++ ++ return cp - (*out = ret); ++} ++ ++/* ++ * Decode unsigned 0..255, returns 1 on success, <= 0 on failure. Advances ++ * inptr to next field skipping leading whitespace. ++ */ ++static ossl_ssize_t checked_uint8(const char **inptr, void *out) ++{ ++ uint8_t *result = (uint8_t *)out; ++ const char *in = *inptr; ++ char *endp; ++ long v; ++ int e; ++ ++ save_errno(); ++ v = strtol(in, &endp, 10); ++ e = restore_errno(); ++ ++ if (((v == LONG_MIN || v == LONG_MAX) && e == ERANGE) || ++ endp == in || !isspace(_UC(*endp)) || ++ v != (*result = (uint8_t) v)) { ++ return -1; ++ } ++ for (in = endp; isspace(_UC(*in)); ++in) ++ continue; ++ ++ *inptr = in; ++ return 1; ++} ++ ++struct tlsa_field { ++ void *var; ++ const char *name; ++ ossl_ssize_t (*parser)(const char **, void *); ++}; ++ ++static int tlsa_import_rr(SSL *con, const char *rrdata) ++{ ++ /* Not necessary to re-init these values; the "parsers" do that. */ ++ static uint8_t usage; ++ static uint8_t selector; ++ static uint8_t mtype; ++ static unsigned char *data; ++ static struct tlsa_field tlsa_fields[] = { ++ { &usage, "usage", checked_uint8 }, ++ { &selector, "selector", checked_uint8 }, ++ { &mtype, "mtype", checked_uint8 }, ++ { &data, "data", hexdecode }, ++ { NULL, } ++ }; ++ struct tlsa_field *f; ++ int ret; ++ const char *cp = rrdata; ++ ossl_ssize_t len = 0; ++ ++ for (f = tlsa_fields; f->var; ++f) { ++ /* Returns number of bytes produced, advances cp to next field */ ++ if ((len = f->parser(&cp, f->var)) <= 0) { ++ BIO_printf(bio_err, "%s: warning: bad TLSA %s field in: %s\n", ++ prog, f->name, rrdata); ++ return 0; ++ } ++ } ++ /* The data field is last, so len is its length */ ++ ret = SSL_dane_tlsa_add(con, usage, selector, mtype, data, len); ++ OPENSSL_free(data); ++ ++ if (ret == 0) { ++ ERR_print_errors(bio_err); ++ BIO_printf(bio_err, "%s: warning: unusable TLSA rrdata: %s\n", ++ prog, rrdata); ++ return 0; ++ } ++ if (ret < 0) { ++ ERR_print_errors(bio_err); ++ BIO_printf(bio_err, "%s: warning: error loading TLSA rrdata: %s\n", ++ prog, rrdata); ++ return 0; ++ } ++ return ret; ++} ++ ++static int tlsa_import_rrset(SSL *con, STACK_OF(OPENSSL_STRING) *rrset) ++{ ++ int num = sk_OPENSSL_STRING_num(rrset); ++ int count = 0; ++ int i; ++ ++ for (i = 0; i < num; ++i) { ++ char *rrdata = sk_OPENSSL_STRING_value(rrset, i); ++ if (tlsa_import_rr(con, rrdata) > 0) ++ ++count; ++ } ++ return count > 0; ++} ++ ++typedef enum OPTION_choice { ++ OPT_ERR = -1, OPT_EOF = 0, OPT_HELP, ++ OPT_4, OPT_6, OPT_HOST, OPT_PORT, OPT_CONNECT, OPT_UNIX, ++ OPT_XMPPHOST, OPT_VERIFY, ++ OPT_CERT, OPT_CRL, OPT_CRL_DOWNLOAD, OPT_SESS_OUT, OPT_SESS_IN, ++ OPT_CERTFORM, OPT_CRLFORM, OPT_VERIFY_RET_ERROR, OPT_VERIFY_QUIET, ++ OPT_BRIEF, OPT_PREXIT, OPT_CRLF, OPT_QUIET, OPT_NBIO, ++ OPT_SSL_CLIENT_ENGINE, OPT_RAND, OPT_IGN_EOF, OPT_NO_IGN_EOF, ++ OPT_DEBUG, OPT_TLSEXTDEBUG, OPT_STATUS, OPT_WDEBUG, ++ OPT_MSG, OPT_MSGFILE, OPT_ENGINE, OPT_TRACE, OPT_SECURITY_DEBUG, ++ OPT_SECURITY_DEBUG_VERBOSE, OPT_SHOWCERTS, OPT_NBIO_TEST, OPT_STATE, ++#ifndef OPENSSL_NO_PSK ++ OPT_PSK_IDENTITY, OPT_PSK, ++#endif ++#ifndef OPENSSL_NO_SRP ++ OPT_SRPUSER, OPT_SRPPASS, OPT_SRP_STRENGTH, OPT_SRP_LATEUSER, ++ OPT_SRP_MOREGROUPS, ++#endif ++ OPT_SSL3, OPT_SSL_CONFIG, ++ OPT_TLS1_2, OPT_TLS1_1, OPT_TLS1, OPT_DTLS, OPT_DTLS1, ++ OPT_DTLS1_2, OPT_TIMEOUT, OPT_MTU, OPT_KEYFORM, OPT_PASS, ++ OPT_CERT_CHAIN, OPT_CAPATH, OPT_NOCAPATH, OPT_CHAINCAPATH, ++ OPT_VERIFYCAPATH, ++ OPT_KEY, OPT_RECONNECT, OPT_BUILD_CHAIN, OPT_CAFILE, OPT_NOCAFILE, ++ OPT_CHAINCAFILE, OPT_VERIFYCAFILE, OPT_NEXTPROTONEG, OPT_ALPN, ++ OPT_SERVERINFO, OPT_STARTTLS, OPT_SERVERNAME, ++ OPT_USE_SRTP, OPT_KEYMATEXPORT, OPT_KEYMATEXPORTLEN, OPT_SMTPHOST, ++ OPT_ASYNC, OPT_SPLIT_SEND_FRAG, OPT_MAX_PIPELINES, OPT_READ_BUF, ++ OPT_V_ENUM, ++ OPT_X_ENUM, ++ OPT_S_ENUM, ++ OPT_FALLBACKSCSV, OPT_NOCMDS, OPT_PROXY, OPT_DANE_TLSA_DOMAIN, ++#ifndef OPENSSL_NO_CT ++ OPT_CT, OPT_NOCT, OPT_CTLOG_FILE, ++#endif ++ OPT_DANE_TLSA_RRDATA, OPT_DANE_EE_NO_NAME ++} OPTION_CHOICE; ++ ++OPTIONS s_client_options[] = { ++ {"help", OPT_HELP, '-', "Display this summary"}, ++ {"host", OPT_HOST, 's', "Use -connect instead"}, ++ {"port", OPT_PORT, 'p', "Use -connect instead"}, ++ {"connect", OPT_CONNECT, 's', ++ "TCP/IP where to connect (default is :" PORT ")"}, ++ {"proxy", OPT_PROXY, 's', ++ "Connect to via specified proxy to the real server"}, ++#ifdef AF_UNIX ++ {"unix", OPT_UNIX, 's', "Connect over the specified Unix-domain socket"}, ++#endif ++ {"4", OPT_4, '-', "Use IPv4 only"}, ++#ifdef AF_INET6 ++ {"6", OPT_6, '-', "Use IPv6 only"}, ++#endif ++ {"verify", OPT_VERIFY, 'p', "Turn on peer certificate verification"}, ++ {"cert", OPT_CERT, '<', "Certificate file to use, PEM format assumed"}, ++ {"certform", OPT_CERTFORM, 'F', ++ "Certificate format (PEM or DER) PEM default"}, ++ {"key", OPT_KEY, 's', "Private key file to use, if not in -cert file"}, ++ {"keyform", OPT_KEYFORM, 'E', "Key format (PEM, DER or engine) PEM default"}, ++ {"pass", OPT_PASS, 's', "Private key file pass phrase source"}, ++ {"CApath", OPT_CAPATH, '/', "PEM format directory of CA's"}, ++ {"CAfile", OPT_CAFILE, '<', "PEM format file of CA's"}, ++ {"no-CAfile", OPT_NOCAFILE, '-', ++ "Do not load the default certificates file"}, ++ {"no-CApath", OPT_NOCAPATH, '-', ++ "Do not load certificates from the default certificates directory"}, ++ {"dane_tlsa_domain", OPT_DANE_TLSA_DOMAIN, 's', "DANE TLSA base domain"}, ++ {"dane_tlsa_rrdata", OPT_DANE_TLSA_RRDATA, 's', ++ "DANE TLSA rrdata presentation form"}, ++ {"dane_ee_no_namechecks", OPT_DANE_EE_NO_NAME, '-', ++ "Disable name checks when matching DANE-EE(3) TLSA records"}, ++ {"reconnect", OPT_RECONNECT, '-', ++ "Drop and re-make the connection with the same Session-ID"}, ++ {"showcerts", OPT_SHOWCERTS, '-', "Show all certificates in the chain"}, ++ {"debug", OPT_DEBUG, '-', "Extra output"}, ++ {"msg", OPT_MSG, '-', "Show protocol messages"}, ++ {"msgfile", OPT_MSGFILE, '>', ++ "File to send output of -msg or -trace, instead of stdout"}, ++ {"nbio_test", OPT_NBIO_TEST, '-', "More ssl protocol testing"}, ++ {"state", OPT_STATE, '-', "Print the ssl states"}, ++ {"crlf", OPT_CRLF, '-', "Convert LF from terminal into CRLF"}, ++ {"quiet", OPT_QUIET, '-', "No s_client output"}, ++ {"ign_eof", OPT_IGN_EOF, '-', "Ignore input eof (default when -quiet)"}, ++ {"no_ign_eof", OPT_NO_IGN_EOF, '-', "Don't ignore input eof"}, ++ {"starttls", OPT_STARTTLS, 's', ++ "Use the appropriate STARTTLS command before starting TLS"}, ++ {"xmpphost", OPT_XMPPHOST, 's', ++ "Host to use with \"-starttls xmpp[-server]\""}, ++ {"rand", OPT_RAND, 's', ++ "Load the file(s) into the random number generator"}, ++ {"sess_out", OPT_SESS_OUT, '>', "File to write SSL session to"}, ++ {"sess_in", OPT_SESS_IN, '<', "File to read SSL session from"}, ++ {"use_srtp", OPT_USE_SRTP, 's', ++ "Offer SRTP key management with a colon-separated profile list"}, ++ {"keymatexport", OPT_KEYMATEXPORT, 's', ++ "Export keying material using label"}, ++ {"keymatexportlen", OPT_KEYMATEXPORTLEN, 'p', ++ "Export len bytes of keying material (default 20)"}, ++ {"fallback_scsv", OPT_FALLBACKSCSV, '-', "Send the fallback SCSV"}, ++ {"name", OPT_SMTPHOST, 's', "Hostname to use for \"-starttls smtp\""}, ++ {"CRL", OPT_CRL, '<', "CRL file to use"}, ++ {"crl_download", OPT_CRL_DOWNLOAD, '-', "Download CRL from distribution points"}, ++ {"CRLform", OPT_CRLFORM, 'F', "CRL format (PEM or DER) PEM is default"}, ++ {"verify_return_error", OPT_VERIFY_RET_ERROR, '-', ++ "Close connection on verification error"}, ++ {"verify_quiet", OPT_VERIFY_QUIET, '-', "Restrict verify output to errors"}, ++ {"brief", OPT_BRIEF, '-', ++ "Restrict output to brief summary of connection parameters"}, ++ {"prexit", OPT_PREXIT, '-', ++ "Print session information when the program exits"}, ++ {"security_debug", OPT_SECURITY_DEBUG, '-', ++ "Enable security debug messages"}, ++ {"security_debug_verbose", OPT_SECURITY_DEBUG_VERBOSE, '-', ++ "Output more security debug output"}, ++ {"cert_chain", OPT_CERT_CHAIN, '<', ++ "Certificate chain file (in PEM format)"}, ++ {"chainCApath", OPT_CHAINCAPATH, '/', ++ "Use dir as certificate store path to build CA certificate chain"}, ++ {"verifyCApath", OPT_VERIFYCAPATH, '/', ++ "Use dir as certificate store path to verify CA certificate"}, ++ {"build_chain", OPT_BUILD_CHAIN, '-', "Build certificate chain"}, ++ {"chainCAfile", OPT_CHAINCAFILE, '<', ++ "CA file for certificate chain (PEM format)"}, ++ {"verifyCAfile", OPT_VERIFYCAFILE, '<', ++ "CA file for certificate verification (PEM format)"}, ++ {"nocommands", OPT_NOCMDS, '-', "Do not use interactive command letters"}, ++ {"servername", OPT_SERVERNAME, 's', ++ "Set TLS extension servername in ClientHello"}, ++ {"tlsextdebug", OPT_TLSEXTDEBUG, '-', ++ "Hex dump of all TLS extensions received"}, ++#ifndef OPENSSL_NO_OCSP ++ {"status", OPT_STATUS, '-', "Request certificate status from server"}, ++#endif ++ {"serverinfo", OPT_SERVERINFO, 's', ++ "types Send empty ClientHello extensions (comma-separated numbers)"}, ++ {"alpn", OPT_ALPN, 's', ++ "Enable ALPN extension, considering named protocols supported (comma-separated list)"}, ++ {"async", OPT_ASYNC, '-', "Support asynchronous operation"}, ++ {"ssl_config", OPT_SSL_CONFIG, 's', "Use specified configuration file"}, ++ {"split_send_frag", OPT_SPLIT_SEND_FRAG, 'n', ++ "Size used to split data for encrypt pipelines"}, ++ {"max_pipelines", OPT_MAX_PIPELINES, 'n', ++ "Maximum number of encrypt/decrypt pipelines to be used"}, ++ {"read_buf", OPT_READ_BUF, 'n', ++ "Default read buffer size to be used for connections"}, ++ OPT_S_OPTIONS, ++ OPT_V_OPTIONS, ++ OPT_X_OPTIONS, ++#ifndef OPENSSL_NO_SSL3 ++ {"ssl3", OPT_SSL3, '-', "Just use SSLv3"}, ++#endif ++#ifndef OPENSSL_NO_TLS1 ++ {"tls1", OPT_TLS1, '-', "Just use TLSv1"}, ++#endif ++#ifndef OPENSSL_NO_TLS1_1 ++ {"tls1_1", OPT_TLS1_1, '-', "Just use TLSv1.1"}, ++#endif ++#ifndef OPENSSL_NO_TLS1_2 ++ {"tls1_2", OPT_TLS1_2, '-', "Just use TLSv1.2"}, ++#endif ++#ifndef OPENSSL_NO_DTLS ++ {"dtls", OPT_DTLS, '-', "Use any version of DTLS"}, ++ {"timeout", OPT_TIMEOUT, '-', ++ "Enable send/receive timeout on DTLS connections"}, ++ {"mtu", OPT_MTU, 'p', "Set the link layer MTU"}, ++#endif ++#ifndef OPENSSL_NO_DTLS1 ++ {"dtls1", OPT_DTLS1, '-', "Just use DTLSv1"}, ++#endif ++#ifndef OPENSSL_NO_DTLS1_2 ++ {"dtls1_2", OPT_DTLS1_2, '-', "Just use DTLSv1.2"}, ++#endif ++#ifndef OPENSSL_NO_SSL_TRACE ++ {"trace", OPT_TRACE, '-', "Show trace output of protocol messages"}, ++#endif ++#ifdef WATT32 ++ {"wdebug", OPT_WDEBUG, '-', "WATT-32 tcp debugging"}, ++#endif ++ {"nbio", OPT_NBIO, '-', "Use non-blocking IO"}, ++#ifndef OPENSSL_NO_PSK ++ {"psk_identity", OPT_PSK_IDENTITY, 's', "PSK identity"}, ++ {"psk", OPT_PSK, 's', "PSK in hex (without 0x)"}, ++#endif ++#ifndef OPENSSL_NO_SRP ++ {"srpuser", OPT_SRPUSER, 's', "SRP authentication for 'user'"}, ++ {"srppass", OPT_SRPPASS, 's', "Password for 'user'"}, ++ {"srp_lateuser", OPT_SRP_LATEUSER, '-', ++ "SRP username into second ClientHello message"}, ++ {"srp_moregroups", OPT_SRP_MOREGROUPS, '-', ++ "Tolerate other than the known g N values."}, ++ {"srp_strength", OPT_SRP_STRENGTH, 'p', "Minimal length in bits for N"}, ++#endif ++#ifndef OPENSSL_NO_NEXTPROTONEG ++ {"nextprotoneg", OPT_NEXTPROTONEG, 's', ++ "Enable NPN extension, considering named protocols supported (comma-separated list)"}, ++#endif ++#ifndef OPENSSL_NO_ENGINE ++ {"engine", OPT_ENGINE, 's', "Use engine, possibly a hardware device"}, ++ {"ssl_client_engine", OPT_SSL_CLIENT_ENGINE, 's', ++ "Specify engine to be used for client certificate operations"}, ++#endif ++#ifndef OPENSSL_NO_CT ++ {"ct", OPT_CT, '-', "Request and parse SCTs (also enables OCSP stapling)"}, ++ {"noct", OPT_NOCT, '-', "Do not request or parse SCTs (default)"}, ++ {"ctlogfile", OPT_CTLOG_FILE, '<', "CT log list CONF file"}, ++#endif ++ {NULL, OPT_EOF, 0x00, NULL} ++}; ++ ++typedef enum PROTOCOL_choice { ++ PROTO_OFF, ++ PROTO_SMTP, ++ PROTO_POP3, ++ PROTO_IMAP, ++ PROTO_FTP, ++ PROTO_TELNET, ++ PROTO_XMPP, ++ PROTO_XMPP_SERVER, ++ PROTO_CONNECT, ++ PROTO_IRC ++} PROTOCOL_CHOICE; ++ ++static const OPT_PAIR services[] = { ++ {"smtp", PROTO_SMTP}, ++ {"pop3", PROTO_POP3}, ++ {"imap", PROTO_IMAP}, ++ {"ftp", PROTO_FTP}, ++ {"xmpp", PROTO_XMPP}, ++ {"xmpp-server", PROTO_XMPP_SERVER}, ++ {"telnet", PROTO_TELNET}, ++ {"irc", PROTO_IRC}, ++ {NULL, 0} ++}; ++ ++#define IS_INET_FLAG(o) \ ++ (o == OPT_4 || o == OPT_6 || o == OPT_HOST || o == OPT_PORT || o == OPT_CONNECT) ++#define IS_UNIX_FLAG(o) (o == OPT_UNIX) ++ ++#define IS_PROT_FLAG(o) \ ++ (o == OPT_SSL3 || o == OPT_TLS1 || o == OPT_TLS1_1 || o == OPT_TLS1_2 \ ++ || o == OPT_DTLS || o == OPT_DTLS1 || o == OPT_DTLS1_2) ++ ++/* Free |*dest| and optionally set it to a copy of |source|. */ ++static void freeandcopy(char **dest, const char *source) ++{ ++ OPENSSL_free(*dest); ++ *dest = NULL; ++ if (source != NULL) ++ *dest = OPENSSL_strdup(source); ++} ++ ++int s_client_main(int argc, char **argv) ++{ ++ BIO *sbio; ++ EVP_PKEY *key = NULL; ++ SSL *con = NULL; ++ SSL_CTX *ctx = NULL; ++ STACK_OF(X509) *chain = NULL; ++ X509 *cert = NULL; ++ X509_VERIFY_PARAM *vpm = NULL; ++ SSL_EXCERT *exc = NULL; ++ SSL_CONF_CTX *cctx = NULL; ++ STACK_OF(OPENSSL_STRING) *ssl_args = NULL; ++ char *dane_tlsa_domain = NULL; ++ STACK_OF(OPENSSL_STRING) *dane_tlsa_rrset = NULL; ++ int dane_ee_no_name = 0; ++ STACK_OF(X509_CRL) *crls = NULL; ++ const SSL_METHOD *meth = TLS_client_method(); ++ const char *CApath = NULL, *CAfile = NULL; ++ char *cbuf = NULL, *sbuf = NULL; ++ char *mbuf = NULL, *proxystr = NULL, *connectstr = NULL; ++ char *cert_file = NULL, *key_file = NULL, *chain_file = NULL; ++ char *chCApath = NULL, *chCAfile = NULL, *host = NULL; ++ char *port = OPENSSL_strdup(PORT); ++ char *inrand = NULL; ++ char *passarg = NULL, *pass = NULL, *vfyCApath = NULL, *vfyCAfile = NULL; ++ char *sess_in = NULL, *sess_out = NULL, *crl_file = NULL, *p; ++ char *xmpphost = NULL; ++ const char *ehlo = "mail.example.com"; ++ struct timeval timeout, *timeoutp; ++ fd_set readfds, writefds; ++ int noCApath = 0, noCAfile = 0; ++ int build_chain = 0, cbuf_len, cbuf_off, cert_format = FORMAT_PEM; ++ int key_format = FORMAT_PEM, crlf = 0, full_log = 1, mbuf_len = 0; ++ int prexit = 0; ++ int sdebug = 0; ++ int reconnect = 0, verify = SSL_VERIFY_NONE, vpmtouched = 0; ++ int ret = 1, in_init = 1, i, nbio_test = 0, s = -1, k, width, state = 0; ++ int sbuf_len, sbuf_off, cmdletters = 1; ++ int socket_family = AF_UNSPEC, socket_type = SOCK_STREAM; ++ int starttls_proto = PROTO_OFF, crl_format = FORMAT_PEM, crl_download = 0; ++ int write_tty, read_tty, write_ssl, read_ssl, tty_on, ssl_pending; ++#if !defined(OPENSSL_SYS_WINDOWS) && !defined(OPENSSL_SYS_MSDOS) ++ int at_eof = 0; ++#endif ++ int read_buf_len = 0; ++ int fallback_scsv = 0; ++ long randamt = 0; ++ OPTION_CHOICE o; ++#ifndef OPENSSL_NO_DTLS ++ int enable_timeouts = 0; ++ long socket_mtu = 0; ++#endif ++#ifndef OPENSSL_NO_ENGINE ++ ENGINE *ssl_client_engine = NULL; ++#endif ++ ENGINE *e = NULL; ++#if defined(OPENSSL_SYS_WINDOWS) || defined(OPENSSL_SYS_MSDOS) ++ struct timeval tv; ++#endif ++ char *servername = NULL; ++ const char *alpn_in = NULL; ++ tlsextctx tlsextcbp = { NULL, 0 }; ++ const char *ssl_config = NULL; ++#define MAX_SI_TYPES 100 ++ unsigned short serverinfo_types[MAX_SI_TYPES]; ++ int serverinfo_count = 0, start = 0, len; ++#ifndef OPENSSL_NO_NEXTPROTONEG ++ const char *next_proto_neg_in = NULL; ++#endif ++#ifndef OPENSSL_NO_SRP ++ char *srppass = NULL; ++ int srp_lateuser = 0; ++ SRP_ARG srp_arg = { NULL, NULL, 0, 0, 0, 1024 }; ++#endif ++#ifndef OPENSSL_NO_CT ++ char *ctlog_file = NULL; ++ int ct_validation = 0; ++#endif ++ int min_version = 0, max_version = 0, prot_opt = 0, no_prot_opt = 0; ++ int async = 0; ++ unsigned int split_send_fragment = 0; ++ unsigned int max_pipelines = 0; ++ enum { use_inet, use_unix, use_unknown } connect_type = use_unknown; ++ int count4or6 = 0; ++ int c_nbio = 0, c_msg = 0, c_ign_eof = 0, c_brief = 0; ++ int c_tlsextdebug = 0; ++#ifndef OPENSSL_NO_OCSP ++ int c_status_req = 0; ++#endif ++ BIO *bio_c_msg = NULL; ++ ++ FD_ZERO(&readfds); ++ FD_ZERO(&writefds); ++/* Known false-positive of MemorySanitizer. */ ++#if defined(__has_feature) ++# if __has_feature(memory_sanitizer) ++ __msan_unpoison(&readfds, sizeof(readfds)); ++ __msan_unpoison(&writefds, sizeof(writefds)); ++# endif ++#endif ++ ++ prog = opt_progname(argv[0]); ++ c_quiet = 0; ++ c_debug = 0; ++ c_showcerts = 0; ++ c_nbio = 0; ++ vpm = X509_VERIFY_PARAM_new(); ++ cctx = SSL_CONF_CTX_new(); ++ ++ if (vpm == NULL || cctx == NULL) { ++ BIO_printf(bio_err, "%s: out of memory\n", prog); ++ goto end; ++ } ++ ++ cbuf = app_malloc(BUFSIZZ, "cbuf"); ++ sbuf = app_malloc(BUFSIZZ, "sbuf"); ++ mbuf = app_malloc(BUFSIZZ, "mbuf"); ++ ++ SSL_CONF_CTX_set_flags(cctx, SSL_CONF_FLAG_CLIENT | SSL_CONF_FLAG_CMDLINE); ++ ++ prog = opt_init(argc, argv, s_client_options); ++ while ((o = opt_next()) != OPT_EOF) { ++ /* Check for intermixing flags. */ ++ if (connect_type == use_unix && IS_INET_FLAG(o)) { ++ BIO_printf(bio_err, ++ "%s: Intermixed protocol flags (unix and internet domains)\n", ++ prog); ++ goto end; ++ } ++ if (connect_type == use_inet && IS_UNIX_FLAG(o)) { ++ BIO_printf(bio_err, ++ "%s: Intermixed protocol flags (internet and unix domains)\n", ++ prog); ++ goto end; ++ } ++ ++ if (IS_PROT_FLAG(o) && ++prot_opt > 1) { ++ BIO_printf(bio_err, "Cannot supply multiple protocol flags\n"); ++ goto end; ++ } ++ if (IS_NO_PROT_FLAG(o)) ++ no_prot_opt++; ++ if (prot_opt == 1 && no_prot_opt) { ++ BIO_printf(bio_err, ++ "Cannot supply both a protocol flag and '-no_'\n"); ++ goto end; ++ } ++ ++ switch (o) { ++ case OPT_EOF: ++ case OPT_ERR: ++ opthelp: ++ BIO_printf(bio_err, "%s: Use -help for summary.\n", prog); ++ goto end; ++ case OPT_HELP: ++ opt_help(s_client_options); ++ ret = 0; ++ goto end; ++ case OPT_4: ++ connect_type = use_inet; ++ socket_family = AF_INET; ++ count4or6++; ++ break; ++#ifdef AF_INET6 ++ case OPT_6: ++ connect_type = use_inet; ++ socket_family = AF_INET6; ++ count4or6++; ++ break; ++#endif ++ case OPT_HOST: ++ connect_type = use_inet; ++ freeandcopy(&host, opt_arg()); ++ break; ++ case OPT_PORT: ++ connect_type = use_inet; ++ freeandcopy(&port, opt_arg()); ++ break; ++ case OPT_CONNECT: ++ connect_type = use_inet; ++ freeandcopy(&connectstr, opt_arg()); ++ break; ++ case OPT_PROXY: ++ proxystr = opt_arg(); ++ starttls_proto = PROTO_CONNECT; ++ break; ++#ifdef AF_UNIX ++ case OPT_UNIX: ++ connect_type = use_unix; ++ socket_family = AF_UNIX; ++ freeandcopy(&host, opt_arg()); ++ break; ++#endif ++ case OPT_XMPPHOST: ++ xmpphost = opt_arg(); ++ break; ++ case OPT_SMTPHOST: ++ ehlo = opt_arg(); ++ break; ++ case OPT_VERIFY: ++ verify = SSL_VERIFY_PEER; ++ verify_args.depth = atoi(opt_arg()); ++ if (!c_quiet) ++ BIO_printf(bio_err, "verify depth is %d\n", verify_args.depth); ++ break; ++ case OPT_CERT: ++ cert_file = opt_arg(); ++ break; ++ case OPT_CRL: ++ crl_file = opt_arg(); ++ break; ++ case OPT_CRL_DOWNLOAD: ++ crl_download = 1; ++ break; ++ case OPT_SESS_OUT: ++ sess_out = opt_arg(); ++ break; ++ case OPT_SESS_IN: ++ sess_in = opt_arg(); ++ break; ++ case OPT_CERTFORM: ++ if (!opt_format(opt_arg(), OPT_FMT_PEMDER, &cert_format)) ++ goto opthelp; ++ break; ++ case OPT_CRLFORM: ++ if (!opt_format(opt_arg(), OPT_FMT_PEMDER, &crl_format)) ++ goto opthelp; ++ break; ++ case OPT_VERIFY_RET_ERROR: ++ verify_args.return_error = 1; ++ break; ++ case OPT_VERIFY_QUIET: ++ verify_args.quiet = 1; ++ break; ++ case OPT_BRIEF: ++ c_brief = verify_args.quiet = c_quiet = 1; ++ break; ++ case OPT_S_CASES: ++ if (ssl_args == NULL) ++ ssl_args = sk_OPENSSL_STRING_new_null(); ++ if (ssl_args == NULL ++ || !sk_OPENSSL_STRING_push(ssl_args, opt_flag()) ++ || !sk_OPENSSL_STRING_push(ssl_args, opt_arg())) { ++ BIO_printf(bio_err, "%s: Memory allocation failure\n", prog); ++ goto end; ++ } ++ break; ++ case OPT_V_CASES: ++ if (!opt_verify(o, vpm)) ++ goto end; ++ vpmtouched++; ++ break; ++ case OPT_X_CASES: ++ if (!args_excert(o, &exc)) ++ goto end; ++ break; ++ case OPT_PREXIT: ++ prexit = 1; ++ break; ++ case OPT_CRLF: ++ crlf = 1; ++ break; ++ case OPT_QUIET: ++ c_quiet = c_ign_eof = 1; ++ break; ++ case OPT_NBIO: ++ c_nbio = 1; ++ break; ++ case OPT_NOCMDS: ++ cmdletters = 0; ++ break; ++ case OPT_ENGINE: ++ e = setup_engine(opt_arg(), 1); ++ break; ++ case OPT_SSL_CLIENT_ENGINE: ++#ifndef OPENSSL_NO_ENGINE ++ ssl_client_engine = ENGINE_by_id(opt_arg()); ++ if (ssl_client_engine == NULL) { ++ BIO_printf(bio_err, "Error getting client auth engine\n"); ++ goto opthelp; ++ } ++#endif ++ break; ++ case OPT_RAND: ++ inrand = opt_arg(); ++ break; ++ case OPT_IGN_EOF: ++ c_ign_eof = 1; ++ break; ++ case OPT_NO_IGN_EOF: ++ c_ign_eof = 0; ++ break; ++ case OPT_DEBUG: ++ c_debug = 1; ++ break; ++ case OPT_TLSEXTDEBUG: ++ c_tlsextdebug = 1; ++ break; ++ case OPT_STATUS: ++#ifndef OPENSSL_NO_OCSP ++ c_status_req = 1; ++#endif ++ break; ++ case OPT_WDEBUG: ++#ifdef WATT32 ++ dbug_init(); ++#endif ++ break; ++ case OPT_MSG: ++ c_msg = 1; ++ break; ++ case OPT_MSGFILE: ++ bio_c_msg = BIO_new_file(opt_arg(), "w"); ++ break; ++ case OPT_TRACE: ++#ifndef OPENSSL_NO_SSL_TRACE ++ c_msg = 2; ++#endif ++ break; ++ case OPT_SECURITY_DEBUG: ++ sdebug = 1; ++ break; ++ case OPT_SECURITY_DEBUG_VERBOSE: ++ sdebug = 2; ++ break; ++ case OPT_SHOWCERTS: ++ c_showcerts = 1; ++ break; ++ case OPT_NBIO_TEST: ++ nbio_test = 1; ++ break; ++ case OPT_STATE: ++ state = 1; ++ break; ++#ifndef OPENSSL_NO_PSK ++ case OPT_PSK_IDENTITY: ++ psk_identity = opt_arg(); ++ break; ++ case OPT_PSK: ++ for (p = psk_key = opt_arg(); *p; p++) { ++ if (isxdigit(_UC(*p))) ++ continue; ++ BIO_printf(bio_err, "Not a hex number '%s'\n", psk_key); ++ goto end; ++ } ++ break; ++#endif ++#ifndef OPENSSL_NO_SRP ++ case OPT_SRPUSER: ++ srp_arg.srplogin = opt_arg(); ++ if (min_version < TLS1_VERSION) ++ min_version = TLS1_VERSION; ++ break; ++ case OPT_SRPPASS: ++ srppass = opt_arg(); ++ if (min_version < TLS1_VERSION) ++ min_version = TLS1_VERSION; ++ break; ++ case OPT_SRP_STRENGTH: ++ srp_arg.strength = atoi(opt_arg()); ++ BIO_printf(bio_err, "SRP minimal length for N is %d\n", ++ srp_arg.strength); ++ if (min_version < TLS1_VERSION) ++ min_version = TLS1_VERSION; ++ break; ++ case OPT_SRP_LATEUSER: ++ srp_lateuser = 1; ++ if (min_version < TLS1_VERSION) ++ min_version = TLS1_VERSION; ++ break; ++ case OPT_SRP_MOREGROUPS: ++ srp_arg.amp = 1; ++ if (min_version < TLS1_VERSION) ++ min_version = TLS1_VERSION; ++ break; ++#endif ++ case OPT_SSL_CONFIG: ++ ssl_config = opt_arg(); ++ break; ++ case OPT_SSL3: ++ min_version = SSL3_VERSION; ++ max_version = SSL3_VERSION; ++ break; ++ case OPT_TLS1_2: ++ min_version = TLS1_2_VERSION; ++ max_version = TLS1_2_VERSION; ++ break; ++ case OPT_TLS1_1: ++ min_version = TLS1_1_VERSION; ++ max_version = TLS1_1_VERSION; ++ break; ++ case OPT_TLS1: ++ min_version = TLS1_VERSION; ++ max_version = TLS1_VERSION; ++ break; ++ case OPT_DTLS: ++#ifndef OPENSSL_NO_DTLS ++ meth = DTLS_client_method(); ++ socket_type = SOCK_DGRAM; ++#endif ++ break; ++ case OPT_DTLS1: ++#ifndef OPENSSL_NO_DTLS1 ++ meth = DTLS_client_method(); ++ min_version = DTLS1_VERSION; ++ max_version = DTLS1_VERSION; ++ socket_type = SOCK_DGRAM; ++#endif ++ break; ++ case OPT_DTLS1_2: ++#ifndef OPENSSL_NO_DTLS1_2 ++ meth = DTLS_client_method(); ++ min_version = DTLS1_2_VERSION; ++ max_version = DTLS1_2_VERSION; ++ socket_type = SOCK_DGRAM; ++#endif ++ break; ++ case OPT_TIMEOUT: ++#ifndef OPENSSL_NO_DTLS ++ enable_timeouts = 1; ++#endif ++ break; ++ case OPT_MTU: ++#ifndef OPENSSL_NO_DTLS ++ socket_mtu = atol(opt_arg()); ++#endif ++ break; ++ case OPT_FALLBACKSCSV: ++ fallback_scsv = 1; ++ break; ++ case OPT_KEYFORM: ++ if (!opt_format(opt_arg(), OPT_FMT_PDE, &key_format)) ++ goto opthelp; ++ break; ++ case OPT_PASS: ++ passarg = opt_arg(); ++ break; ++ case OPT_CERT_CHAIN: ++ chain_file = opt_arg(); ++ break; ++ case OPT_KEY: ++ key_file = opt_arg(); ++ break; ++ case OPT_RECONNECT: ++ reconnect = 5; ++ break; ++ case OPT_CAPATH: ++ CApath = opt_arg(); ++ break; ++ case OPT_NOCAPATH: ++ noCApath = 1; ++ break; ++ case OPT_CHAINCAPATH: ++ chCApath = opt_arg(); ++ break; ++ case OPT_VERIFYCAPATH: ++ vfyCApath = opt_arg(); ++ break; ++ case OPT_BUILD_CHAIN: ++ build_chain = 1; ++ break; ++ case OPT_CAFILE: ++ CAfile = opt_arg(); ++ break; ++ case OPT_NOCAFILE: ++ noCAfile = 1; ++ break; ++#ifndef OPENSSL_NO_CT ++ case OPT_NOCT: ++ ct_validation = 0; ++ break; ++ case OPT_CT: ++ ct_validation = 1; ++ break; ++ case OPT_CTLOG_FILE: ++ ctlog_file = opt_arg(); ++ break; ++#endif ++ case OPT_CHAINCAFILE: ++ chCAfile = opt_arg(); ++ break; ++ case OPT_VERIFYCAFILE: ++ vfyCAfile = opt_arg(); ++ break; ++ case OPT_DANE_TLSA_DOMAIN: ++ dane_tlsa_domain = opt_arg(); ++ break; ++ case OPT_DANE_TLSA_RRDATA: ++ if (dane_tlsa_rrset == NULL) ++ dane_tlsa_rrset = sk_OPENSSL_STRING_new_null(); ++ if (dane_tlsa_rrset == NULL || ++ !sk_OPENSSL_STRING_push(dane_tlsa_rrset, opt_arg())) { ++ BIO_printf(bio_err, "%s: Memory allocation failure\n", prog); ++ goto end; ++ } ++ break; ++ case OPT_DANE_EE_NO_NAME: ++ dane_ee_no_name = 1; ++ break; ++ case OPT_NEXTPROTONEG: ++#ifndef OPENSSL_NO_NEXTPROTONEG ++ next_proto_neg_in = opt_arg(); ++#endif ++ break; ++ case OPT_ALPN: ++ alpn_in = opt_arg(); ++ break; ++ case OPT_SERVERINFO: ++ p = opt_arg(); ++ len = strlen(p); ++ for (start = 0, i = 0; i <= len; ++i) { ++ if (i == len || p[i] == ',') { ++ serverinfo_types[serverinfo_count] = atoi(p + start); ++ if (++serverinfo_count == MAX_SI_TYPES) ++ break; ++ start = i + 1; ++ } ++ } ++ break; ++ case OPT_STARTTLS: ++ if (!opt_pair(opt_arg(), services, &starttls_proto)) ++ goto end; ++ break; ++ case OPT_SERVERNAME: ++ servername = opt_arg(); ++ break; ++ case OPT_USE_SRTP: ++ srtp_profiles = opt_arg(); ++ break; ++ case OPT_KEYMATEXPORT: ++ keymatexportlabel = opt_arg(); ++ break; ++ case OPT_KEYMATEXPORTLEN: ++ keymatexportlen = atoi(opt_arg()); ++ break; ++ case OPT_ASYNC: ++ async = 1; ++ break; ++ case OPT_SPLIT_SEND_FRAG: ++ split_send_fragment = atoi(opt_arg()); ++ if (split_send_fragment == 0) { ++ /* ++ * Not allowed - set to a deliberately bad value so we get an ++ * error message below ++ */ ++ split_send_fragment = SSL3_RT_MAX_PLAIN_LENGTH + 1; ++ } ++ break; ++ case OPT_MAX_PIPELINES: ++ max_pipelines = atoi(opt_arg()); ++ break; ++ case OPT_READ_BUF: ++ read_buf_len = atoi(opt_arg()); ++ break; ++ } ++ } ++ if (count4or6 >= 2) { ++ BIO_printf(bio_err, "%s: Can't use both -4 and -6\n", prog); ++ goto opthelp; ++ } ++ argc = opt_num_rest(); ++ if (argc != 0) ++ goto opthelp; ++ ++ if (proxystr) { ++ int res; ++ char *tmp_host = host, *tmp_port = port; ++ if (connectstr == NULL) { ++ BIO_printf(bio_err, "%s: -proxy requires use of -connect\n", prog); ++ goto opthelp; ++ } ++ res = BIO_parse_hostserv(proxystr, &host, &port, BIO_PARSE_PRIO_HOST); ++ if (tmp_host != host) ++ OPENSSL_free(tmp_host); ++ if (tmp_port != port) ++ OPENSSL_free(tmp_port); ++ if (!res) { ++ BIO_printf(bio_err, ++ "%s: -proxy argument malformed or ambiguous\n", prog); ++ goto end; ++ } ++ } else { ++ int res = 1; ++ char *tmp_host = host, *tmp_port = port; ++ if (connectstr != NULL) ++ res = BIO_parse_hostserv(connectstr, &host, &port, ++ BIO_PARSE_PRIO_HOST); ++ if (tmp_host != host) ++ OPENSSL_free(tmp_host); ++ if (tmp_port != port) ++ OPENSSL_free(tmp_port); ++ if (!res) { ++ BIO_printf(bio_err, ++ "%s: -connect argument malformed or ambiguous\n", ++ prog); ++ goto end; ++ } ++ } ++ ++ if (socket_family == AF_UNIX && socket_type != SOCK_STREAM) { ++ BIO_printf(bio_err, ++ "Can't use unix sockets and datagrams together\n"); ++ goto end; ++ } ++ ++ if (split_send_fragment > SSL3_RT_MAX_PLAIN_LENGTH) { ++ BIO_printf(bio_err, "Bad split send fragment size\n"); ++ goto end; ++ } ++ ++ if (max_pipelines > SSL_MAX_PIPELINES) { ++ BIO_printf(bio_err, "Bad max pipelines value\n"); ++ goto end; ++ } ++ ++#if !defined(OPENSSL_NO_NEXTPROTONEG) ++ next_proto.status = -1; ++ if (next_proto_neg_in) { ++ next_proto.data = ++ next_protos_parse(&next_proto.len, next_proto_neg_in); ++ if (next_proto.data == NULL) { ++ BIO_printf(bio_err, "Error parsing -nextprotoneg argument\n"); ++ goto end; ++ } ++ } else ++ next_proto.data = NULL; ++#endif ++ ++ if (!app_passwd(passarg, NULL, &pass, NULL)) { ++ BIO_printf(bio_err, "Error getting password\n"); ++ goto end; ++ } ++ ++ if (key_file == NULL) ++ key_file = cert_file; ++ ++ if (key_file) { ++ key = load_key(key_file, key_format, 0, pass, e, ++ "client certificate private key file"); ++ if (key == NULL) { ++ ERR_print_errors(bio_err); ++ goto end; ++ } ++ } ++ ++ if (cert_file) { ++ cert = load_cert(cert_file, cert_format, "client certificate file"); ++ if (cert == NULL) { ++ ERR_print_errors(bio_err); ++ goto end; ++ } ++ } ++ ++ if (chain_file) { ++ if (!load_certs(chain_file, &chain, FORMAT_PEM, NULL, ++ "client certificate chain")) ++ goto end; ++ } ++ ++ if (crl_file) { ++ X509_CRL *crl; ++ crl = load_crl(crl_file, crl_format); ++ if (crl == NULL) { ++ BIO_puts(bio_err, "Error loading CRL\n"); ++ ERR_print_errors(bio_err); ++ goto end; ++ } ++ crls = sk_X509_CRL_new_null(); ++ if (crls == NULL || !sk_X509_CRL_push(crls, crl)) { ++ BIO_puts(bio_err, "Error adding CRL\n"); ++ ERR_print_errors(bio_err); ++ X509_CRL_free(crl); ++ goto end; ++ } ++ } ++ ++ if (!load_excert(&exc)) ++ goto end; ++ ++ if (!app_RAND_load_file(NULL, 1) && inrand == NULL ++ && !RAND_status()) { ++ BIO_printf(bio_err, ++ "warning, not much extra random data, consider using the -rand option\n"); ++ } ++ if (inrand != NULL) { ++ randamt = app_RAND_load_files(inrand); ++ BIO_printf(bio_err, "%ld semi-random bytes loaded\n", randamt); ++ } ++ ++ if (bio_c_out == NULL) { ++ if (c_quiet && !c_debug) { ++ bio_c_out = BIO_new(BIO_s_null()); ++ if (c_msg && !bio_c_msg) ++ bio_c_msg = dup_bio_out(FORMAT_TEXT); ++ } else if (bio_c_out == NULL) ++ bio_c_out = dup_bio_out(FORMAT_TEXT); ++ } ++#ifndef OPENSSL_NO_SRP ++ if (!app_passwd(srppass, NULL, &srp_arg.srppassin, NULL)) { ++ BIO_printf(bio_err, "Error getting password\n"); ++ goto end; ++ } ++#endif ++ ++ ctx = SSL_CTX_new(meth); ++ if (ctx == NULL) { ++ ERR_print_errors(bio_err); ++ goto end; ++ } ++ ++ if (sdebug) ++ ssl_ctx_security_debug(ctx, sdebug); ++ ++ if (ssl_config) { ++ if (SSL_CTX_config(ctx, ssl_config) == 0) { ++ BIO_printf(bio_err, "Error using configuration \"%s\"\n", ++ ssl_config); ++ ERR_print_errors(bio_err); ++ goto end; ++ } ++ } ++ ++ if (SSL_CTX_set_min_proto_version(ctx, min_version) == 0) ++ goto end; ++ if (SSL_CTX_set_max_proto_version(ctx, max_version) == 0) ++ goto end; ++ ++ if (vpmtouched && !SSL_CTX_set1_param(ctx, vpm)) { ++ BIO_printf(bio_err, "Error setting verify params\n"); ++ ERR_print_errors(bio_err); ++ goto end; ++ } ++ ++ if (async) { ++ SSL_CTX_set_mode(ctx, SSL_MODE_ASYNC); ++ } ++ if (split_send_fragment > 0) { ++ SSL_CTX_set_split_send_fragment(ctx, split_send_fragment); ++ } ++ if (max_pipelines > 0) { ++ SSL_CTX_set_max_pipelines(ctx, max_pipelines); ++ } ++ ++ if (read_buf_len > 0) { ++ SSL_CTX_set_default_read_buffer_len(ctx, read_buf_len); ++ } ++ ++ if (!config_ctx(cctx, ssl_args, ctx)) ++ goto end; ++ ++ if (!ssl_load_stores(ctx, vfyCApath, vfyCAfile, chCApath, chCAfile, ++ crls, crl_download)) { ++ BIO_printf(bio_err, "Error loading store locations\n"); ++ ERR_print_errors(bio_err); ++ goto end; ++ } ++#ifndef OPENSSL_NO_ENGINE ++ if (ssl_client_engine) { ++ if (!SSL_CTX_set_client_cert_engine(ctx, ssl_client_engine)) { ++ BIO_puts(bio_err, "Error setting client auth engine\n"); ++ ERR_print_errors(bio_err); ++ ENGINE_free(ssl_client_engine); ++ goto end; ++ } ++ ENGINE_free(ssl_client_engine); ++ } ++#endif ++ ++#ifndef OPENSSL_NO_PSK ++ if (psk_key != NULL) { ++ if (c_debug) ++ BIO_printf(bio_c_out, "PSK key given, setting client callback\n"); ++ SSL_CTX_set_psk_client_callback(ctx, psk_client_cb); ++ } ++#endif ++#ifndef OPENSSL_NO_SRTP ++ if (srtp_profiles != NULL) { ++ /* Returns 0 on success! */ ++ if (SSL_CTX_set_tlsext_use_srtp(ctx, srtp_profiles) != 0) { ++ BIO_printf(bio_err, "Error setting SRTP profile\n"); ++ ERR_print_errors(bio_err); ++ goto end; ++ } ++ } ++#endif ++ ++ if (exc) ++ ssl_ctx_set_excert(ctx, exc); ++ ++#if !defined(OPENSSL_NO_NEXTPROTONEG) ++ if (next_proto.data) ++ SSL_CTX_set_next_proto_select_cb(ctx, next_proto_cb, &next_proto); ++#endif ++ if (alpn_in) { ++ size_t alpn_len; ++ unsigned char *alpn = next_protos_parse(&alpn_len, alpn_in); ++ ++ if (alpn == NULL) { ++ BIO_printf(bio_err, "Error parsing -alpn argument\n"); ++ goto end; ++ } ++ /* Returns 0 on success! */ ++ if (SSL_CTX_set_alpn_protos(ctx, alpn, alpn_len) != 0) { ++ BIO_printf(bio_err, "Error setting ALPN\n"); ++ goto end; ++ } ++ OPENSSL_free(alpn); ++ } ++ ++ for (i = 0; i < serverinfo_count; i++) { ++ if (!SSL_CTX_add_client_custom_ext(ctx, ++ serverinfo_types[i], ++ NULL, NULL, NULL, ++ serverinfo_cli_parse_cb, NULL)) { ++ BIO_printf(bio_err, ++ "Warning: Unable to add custom extension %u, skipping\n", ++ serverinfo_types[i]); ++ } ++ } ++ ++ if (state) ++ SSL_CTX_set_info_callback(ctx, apps_ssl_info_callback); ++ ++#ifndef OPENSSL_NO_CT ++ /* Enable SCT processing, without early connection termination */ ++ if (ct_validation && ++ !SSL_CTX_enable_ct(ctx, SSL_CT_VALIDATION_PERMISSIVE)) { ++ ERR_print_errors(bio_err); ++ goto end; ++ } ++ ++ if (!ctx_set_ctlog_list_file(ctx, ctlog_file)) { ++ if (ct_validation) { ++ ERR_print_errors(bio_err); ++ goto end; ++ } ++ ++ /* ++ * If CT validation is not enabled, the log list isn't needed so don't ++ * show errors or abort. We try to load it regardless because then we ++ * can show the names of the logs any SCTs came from (SCTs may be seen ++ * even with validation disabled). ++ */ ++ ERR_clear_error(); ++ } ++#endif ++ ++ SSL_CTX_set_verify(ctx, verify, verify_callback); ++ ++ if (!ctx_set_verify_locations(ctx, CAfile, CApath, noCAfile, noCApath)) { ++ ERR_print_errors(bio_err); ++ goto end; ++ } ++ ++ ssl_ctx_add_crls(ctx, crls, crl_download); ++ ++ if (!set_cert_key_stuff(ctx, cert, key, chain, build_chain)) ++ goto end; ++ ++ if (servername != NULL) { ++ tlsextcbp.biodebug = bio_err; ++ SSL_CTX_set_tlsext_servername_callback(ctx, ssl_servername_cb); ++ SSL_CTX_set_tlsext_servername_arg(ctx, &tlsextcbp); ++ } ++# ifndef OPENSSL_NO_SRP ++ if (srp_arg.srplogin) { ++ if (!srp_lateuser && !SSL_CTX_set_srp_username(ctx, srp_arg.srplogin)) { ++ BIO_printf(bio_err, "Unable to set SRP username\n"); ++ goto end; ++ } ++ srp_arg.msg = c_msg; ++ srp_arg.debug = c_debug; ++ SSL_CTX_set_srp_cb_arg(ctx, &srp_arg); ++ SSL_CTX_set_srp_client_pwd_callback(ctx, ssl_give_srp_client_pwd_cb); ++ SSL_CTX_set_srp_strength(ctx, srp_arg.strength); ++ if (c_msg || c_debug || srp_arg.amp == 0) ++ SSL_CTX_set_srp_verify_param_callback(ctx, ++ ssl_srp_verify_param_cb); ++ } ++# endif ++ ++ if (dane_tlsa_domain != NULL) { ++ if (SSL_CTX_dane_enable(ctx) <= 0) { ++ BIO_printf(bio_err, ++ "%s: Error enabling DANE TLSA authentication.\n", ++ prog); ++ ERR_print_errors(bio_err); ++ goto end; ++ } ++ } ++ ++ con = SSL_new(ctx); ++ if (sess_in) { ++ SSL_SESSION *sess; ++ BIO *stmp = BIO_new_file(sess_in, "r"); ++ if (!stmp) { ++ BIO_printf(bio_err, "Can't open session file %s\n", sess_in); ++ ERR_print_errors(bio_err); ++ goto end; ++ } ++ sess = PEM_read_bio_SSL_SESSION(stmp, NULL, 0, NULL); ++ BIO_free(stmp); ++ if (!sess) { ++ BIO_printf(bio_err, "Can't open session file %s\n", sess_in); ++ ERR_print_errors(bio_err); ++ goto end; ++ } ++ if (!SSL_set_session(con, sess)) { ++ BIO_printf(bio_err, "Can't set session\n"); ++ ERR_print_errors(bio_err); ++ goto end; ++ } ++ SSL_SESSION_free(sess); ++ } ++ ++ if (fallback_scsv) ++ SSL_set_mode(con, SSL_MODE_SEND_FALLBACK_SCSV); ++ ++ if (servername != NULL) { ++ if (!SSL_set_tlsext_host_name(con, servername)) { ++ BIO_printf(bio_err, "Unable to set TLS servername extension.\n"); ++ ERR_print_errors(bio_err); ++ goto end; ++ } ++ } ++ ++ if (dane_tlsa_domain != NULL) { ++ if (SSL_dane_enable(con, dane_tlsa_domain) <= 0) { ++ BIO_printf(bio_err, "%s: Error enabling DANE TLSA " ++ "authentication.\n", prog); ++ ERR_print_errors(bio_err); ++ goto end; ++ } ++ if (dane_tlsa_rrset == NULL) { ++ BIO_printf(bio_err, "%s: DANE TLSA authentication requires at " ++ "least one -dane_tlsa_rrdata option.\n", prog); ++ goto end; ++ } ++ if (tlsa_import_rrset(con, dane_tlsa_rrset) <= 0) { ++ BIO_printf(bio_err, "%s: Failed to import any TLSA " ++ "records.\n", prog); ++ goto end; ++ } ++ if (dane_ee_no_name) ++ SSL_dane_set_flags(con, DANE_FLAG_NO_DANE_EE_NAMECHECKS); ++ } else if (dane_tlsa_rrset != NULL) { ++ BIO_printf(bio_err, "%s: DANE TLSA authentication requires the " ++ "-dane_tlsa_domain option.\n", prog); ++ goto end; ++ } ++ ++ re_start: ++ if (init_client(&s, host, port, socket_family, socket_type) == 0) { ++ BIO_printf(bio_err, "connect:errno=%d\n", get_last_socket_error()); ++ BIO_closesocket(s); ++ goto end; ++ } ++ BIO_printf(bio_c_out, "CONNECTED(%08X)\n", s); ++ ++ if (c_nbio) { ++ if (!BIO_socket_nbio(s, 1)) { ++ ERR_print_errors(bio_err); ++ goto end; ++ } ++ BIO_printf(bio_c_out, "Turned on non blocking io\n"); ++ } ++#ifndef OPENSSL_NO_DTLS ++ if (socket_type == SOCK_DGRAM) { ++ union BIO_sock_info_u peer_info; ++ ++ sbio = BIO_new_dgram(s, BIO_NOCLOSE); ++ if ((peer_info.addr = BIO_ADDR_new()) == NULL) { ++ BIO_printf(bio_err, "memory allocation failure\n"); ++ BIO_closesocket(s); ++ goto end; ++ } ++ if (!BIO_sock_info(s, BIO_SOCK_INFO_ADDRESS, &peer_info)) { ++ BIO_printf(bio_err, "getsockname:errno=%d\n", ++ get_last_socket_error()); ++ BIO_ADDR_free(peer_info.addr); ++ BIO_closesocket(s); ++ goto end; ++ } ++ ++ (void)BIO_ctrl_set_connected(sbio, peer_info.addr); ++ BIO_ADDR_free(peer_info.addr); ++ peer_info.addr = NULL; ++ ++ if (enable_timeouts) { ++ timeout.tv_sec = 0; ++ timeout.tv_usec = DGRAM_RCV_TIMEOUT; ++ BIO_ctrl(sbio, BIO_CTRL_DGRAM_SET_RECV_TIMEOUT, 0, &timeout); ++ ++ timeout.tv_sec = 0; ++ timeout.tv_usec = DGRAM_SND_TIMEOUT; ++ BIO_ctrl(sbio, BIO_CTRL_DGRAM_SET_SEND_TIMEOUT, 0, &timeout); ++ } ++ ++ if (socket_mtu) { ++ if (socket_mtu < DTLS_get_link_min_mtu(con)) { ++ BIO_printf(bio_err, "MTU too small. Must be at least %ld\n", ++ DTLS_get_link_min_mtu(con)); ++ BIO_free(sbio); ++ goto shut; ++ } ++ SSL_set_options(con, SSL_OP_NO_QUERY_MTU); ++ if (!DTLS_set_link_mtu(con, socket_mtu)) { ++ BIO_printf(bio_err, "Failed to set MTU\n"); ++ BIO_free(sbio); ++ goto shut; ++ } ++ } else ++ /* want to do MTU discovery */ ++ BIO_ctrl(sbio, BIO_CTRL_DGRAM_MTU_DISCOVER, 0, NULL); ++ } else ++#endif /* OPENSSL_NO_DTLS */ ++ sbio = BIO_new_socket(s, BIO_NOCLOSE); ++ ++ if (nbio_test) { ++ BIO *test; ++ ++ test = BIO_new(BIO_f_nbio_test()); ++ sbio = BIO_push(test, sbio); ++ } ++ ++ if (c_debug) { ++ BIO_set_callback(sbio, bio_dump_callback); ++ BIO_set_callback_arg(sbio, (char *)bio_c_out); ++ } ++ if (c_msg) { ++#ifndef OPENSSL_NO_SSL_TRACE ++ if (c_msg == 2) ++ SSL_set_msg_callback(con, SSL_trace); ++ else ++#endif ++ SSL_set_msg_callback(con, msg_cb); ++ SSL_set_msg_callback_arg(con, bio_c_msg ? bio_c_msg : bio_c_out); ++ } ++ ++ if (c_tlsextdebug) { ++ SSL_set_tlsext_debug_callback(con, tlsext_cb); ++ SSL_set_tlsext_debug_arg(con, bio_c_out); ++ } ++#ifndef OPENSSL_NO_OCSP ++ if (c_status_req) { ++ SSL_set_tlsext_status_type(con, TLSEXT_STATUSTYPE_ocsp); ++ SSL_CTX_set_tlsext_status_cb(ctx, ocsp_resp_cb); ++ SSL_CTX_set_tlsext_status_arg(ctx, bio_c_out); ++ } ++#endif ++ ++ SSL_set_bio(con, sbio, sbio); ++ SSL_set_connect_state(con); ++ ++ /* ok, lets connect */ ++ if (fileno_stdin() > SSL_get_fd(con)) ++ width = fileno_stdin() + 1; ++ else ++ width = SSL_get_fd(con) + 1; ++ ++ read_tty = 1; ++ write_tty = 0; ++ tty_on = 0; ++ read_ssl = 1; ++ write_ssl = 1; ++ ++ cbuf_len = 0; ++ cbuf_off = 0; ++ sbuf_len = 0; ++ sbuf_off = 0; ++ ++ switch ((PROTOCOL_CHOICE) starttls_proto) { ++ case PROTO_OFF: ++ break; ++ case PROTO_SMTP: ++ { ++ /* ++ * This is an ugly hack that does a lot of assumptions. We do ++ * have to handle multi-line responses which may come in a single ++ * packet or not. We therefore have to use BIO_gets() which does ++ * need a buffering BIO. So during the initial chitchat we do ++ * push a buffering BIO into the chain that is removed again ++ * later on to not disturb the rest of the s_client operation. ++ */ ++ int foundit = 0; ++ BIO *fbio = BIO_new(BIO_f_buffer()); ++ BIO_push(fbio, sbio); ++ /* wait for multi-line response to end from SMTP */ ++ do { ++ mbuf_len = BIO_gets(fbio, mbuf, BUFSIZZ); ++ } ++ while (mbuf_len > 3 && mbuf[3] == '-'); ++ BIO_printf(fbio, "EHLO %s\r\n", ehlo); ++ (void)BIO_flush(fbio); ++ /* wait for multi-line response to end EHLO SMTP response */ ++ do { ++ mbuf_len = BIO_gets(fbio, mbuf, BUFSIZZ); ++ if (strstr(mbuf, "STARTTLS")) ++ foundit = 1; ++ } ++ while (mbuf_len > 3 && mbuf[3] == '-'); ++ (void)BIO_flush(fbio); ++ BIO_pop(fbio); ++ BIO_free(fbio); ++ if (!foundit) ++ BIO_printf(bio_err, ++ "didn't find starttls in server response," ++ " trying anyway...\n"); ++ BIO_printf(sbio, "STARTTLS\r\n"); ++ BIO_read(sbio, sbuf, BUFSIZZ); ++ } ++ break; ++ case PROTO_POP3: ++ { ++ BIO_read(sbio, mbuf, BUFSIZZ); ++ BIO_printf(sbio, "STLS\r\n"); ++ mbuf_len = BIO_read(sbio, sbuf, BUFSIZZ); ++ if (mbuf_len < 0) { ++ BIO_printf(bio_err, "BIO_read failed\n"); ++ goto end; ++ } ++ } ++ break; ++ case PROTO_IMAP: ++ { ++ int foundit = 0; ++ BIO *fbio = BIO_new(BIO_f_buffer()); ++ BIO_push(fbio, sbio); ++ BIO_gets(fbio, mbuf, BUFSIZZ); ++ /* STARTTLS command requires CAPABILITY... */ ++ BIO_printf(fbio, ". CAPABILITY\r\n"); ++ (void)BIO_flush(fbio); ++ /* wait for multi-line CAPABILITY response */ ++ do { ++ mbuf_len = BIO_gets(fbio, mbuf, BUFSIZZ); ++ if (strstr(mbuf, "STARTTLS")) ++ foundit = 1; ++ } ++ while (mbuf_len > 3 && mbuf[0] != '.'); ++ (void)BIO_flush(fbio); ++ BIO_pop(fbio); ++ BIO_free(fbio); ++ if (!foundit) ++ BIO_printf(bio_err, ++ "didn't find STARTTLS in server response," ++ " trying anyway...\n"); ++ BIO_printf(sbio, ". STARTTLS\r\n"); ++ BIO_read(sbio, sbuf, BUFSIZZ); ++ } ++ break; ++ case PROTO_FTP: ++ { ++ BIO *fbio = BIO_new(BIO_f_buffer()); ++ BIO_push(fbio, sbio); ++ /* wait for multi-line response to end from FTP */ ++ do { ++ mbuf_len = BIO_gets(fbio, mbuf, BUFSIZZ); ++ } ++ while (mbuf_len > 3 && mbuf[3] == '-'); ++ (void)BIO_flush(fbio); ++ BIO_pop(fbio); ++ BIO_free(fbio); ++ BIO_printf(sbio, "AUTH TLS\r\n"); ++ BIO_read(sbio, sbuf, BUFSIZZ); ++ } ++ break; ++ case PROTO_XMPP: ++ case PROTO_XMPP_SERVER: ++ { ++ int seen = 0; ++ BIO_printf(sbio, "", ++ starttls_proto == PROTO_XMPP ? "client" : "server", ++ xmpphost ? xmpphost : host); ++ seen = BIO_read(sbio, mbuf, BUFSIZZ); ++ mbuf[seen] = 0; ++ while (!strstr ++ (mbuf, ""); ++ seen = BIO_read(sbio, sbuf, BUFSIZZ); ++ sbuf[seen] = 0; ++ if (!strstr(sbuf, " 2); ++ } ++ (void)BIO_flush(fbio); ++ BIO_pop(fbio); ++ BIO_free(fbio); ++ if (foundit != success) { ++ goto shut; ++ } ++ } ++ break; ++ case PROTO_IRC: ++ { ++ int numeric; ++ BIO *fbio = BIO_new(BIO_f_buffer()); ++ ++ BIO_push(fbio, sbio); ++ BIO_printf(fbio, "STARTTLS\r\n"); ++ (void)BIO_flush(fbio); ++ width = SSL_get_fd(con) + 1; ++ ++ do { ++ numeric = 0; ++ ++ FD_ZERO(&readfds); ++ openssl_fdset(SSL_get_fd(con), &readfds); ++ timeout.tv_sec = S_CLIENT_IRC_READ_TIMEOUT; ++ timeout.tv_usec = 0; ++ /* ++ * If the IRCd doesn't respond within ++ * S_CLIENT_IRC_READ_TIMEOUT seconds, assume ++ * it doesn't support STARTTLS. Many IRCds ++ * will not give _any_ sort of response to a ++ * STARTTLS command when it's not supported. ++ */ ++ if (!BIO_get_buffer_num_lines(fbio) ++ && !BIO_pending(fbio) ++ && !BIO_pending(sbio) ++ && select(width, (void *)&readfds, NULL, NULL, ++ &timeout) < 1) { ++ BIO_printf(bio_err, ++ "Timeout waiting for response (%d seconds).\n", ++ S_CLIENT_IRC_READ_TIMEOUT); ++ break; ++ } ++ ++ mbuf_len = BIO_gets(fbio, mbuf, BUFSIZZ); ++ if (mbuf_len < 1 || sscanf(mbuf, "%*s %d", &numeric) != 1) ++ break; ++ /* :example.net 451 STARTTLS :You have not registered */ ++ /* :example.net 421 STARTTLS :Unknown command */ ++ if ((numeric == 451 || numeric == 421) ++ && strstr(mbuf, "STARTTLS") != NULL) { ++ BIO_printf(bio_err, "STARTTLS not supported: %s", mbuf); ++ break; ++ } ++ if (numeric == 691) { ++ BIO_printf(bio_err, "STARTTLS negotiation failed: "); ++ ERR_print_errors(bio_err); ++ break; ++ } ++ } while (numeric != 670); ++ ++ (void)BIO_flush(fbio); ++ BIO_pop(fbio); ++ BIO_free(fbio); ++ if (numeric != 670) { ++ BIO_printf(bio_err, "Server does not support STARTTLS.\n"); ++ ret = 1; ++ goto shut; ++ } ++ } ++ } ++ ++ for (;;) { ++ FD_ZERO(&readfds); ++ FD_ZERO(&writefds); ++ ++ if ((SSL_version(con) == DTLS1_VERSION) && ++ DTLSv1_get_timeout(con, &timeout)) ++ timeoutp = &timeout; ++ else ++ timeoutp = NULL; ++ ++ if (SSL_in_init(con) && !SSL_total_renegotiations(con)) { ++ in_init = 1; ++ tty_on = 0; ++ } else { ++ tty_on = 1; ++ if (in_init) { ++ in_init = 0; ++ ++ if (servername != NULL && !SSL_session_reused(con)) { ++ BIO_printf(bio_c_out, ++ "Server did %sacknowledge servername extension.\n", ++ tlsextcbp.ack ? "" : "not "); ++ } ++ ++ if (sess_out) { ++ BIO *stmp = BIO_new_file(sess_out, "w"); ++ if (stmp) { ++ PEM_write_bio_SSL_SESSION(stmp, SSL_get_session(con)); ++ BIO_free(stmp); ++ } else ++ BIO_printf(bio_err, "Error writing session file %s\n", ++ sess_out); ++ } ++ if (c_brief) { ++ BIO_puts(bio_err, "CONNECTION ESTABLISHED\n"); ++ print_ssl_summary(con); ++ } ++ ++ print_stuff(bio_c_out, con, full_log); ++ if (full_log > 0) ++ full_log--; ++ ++ if (starttls_proto) { ++ BIO_write(bio_err, mbuf, mbuf_len); ++ /* We don't need to know any more */ ++ if (!reconnect) ++ starttls_proto = PROTO_OFF; ++ } ++ ++ if (reconnect) { ++ reconnect--; ++ BIO_printf(bio_c_out, ++ "drop connection and then reconnect\n"); ++ do_ssl_shutdown(con); ++ SSL_set_connect_state(con); ++ BIO_closesocket(SSL_get_fd(con)); ++ goto re_start; ++ } ++ } ++ } ++ ++ ssl_pending = read_ssl && SSL_has_pending(con); ++ ++ if (!ssl_pending) { ++#if !defined(OPENSSL_SYS_WINDOWS) && !defined(OPENSSL_SYS_MSDOS) ++ if (tty_on) { ++ /* ++ * Note that select() returns when read _would not block_, ++ * and EOF satisfies that. To avoid a CPU-hogging loop, ++ * set the flag so we exit. ++ */ ++ if (read_tty && !at_eof) ++ openssl_fdset(fileno_stdin(), &readfds); ++#if !defined(OPENSSL_SYS_VMS) ++ if (write_tty) ++ openssl_fdset(fileno_stdout(), &writefds); ++#endif ++ } ++ if (read_ssl) ++ openssl_fdset(SSL_get_fd(con), &readfds); ++ if (write_ssl) ++ openssl_fdset(SSL_get_fd(con), &writefds); ++#else ++ if (!tty_on || !write_tty) { ++ if (read_ssl) ++ openssl_fdset(SSL_get_fd(con), &readfds); ++ if (write_ssl) ++ openssl_fdset(SSL_get_fd(con), &writefds); ++ } ++#endif ++ ++ /* ++ * Note: under VMS with SOCKETSHR the second parameter is ++ * currently of type (int *) whereas under other systems it is ++ * (void *) if you don't have a cast it will choke the compiler: ++ * if you do have a cast then you can either go for (int *) or ++ * (void *). ++ */ ++#if defined(OPENSSL_SYS_WINDOWS) || defined(OPENSSL_SYS_MSDOS) ++ /* ++ * Under Windows/DOS we make the assumption that we can always ++ * write to the tty: therefore if we need to write to the tty we ++ * just fall through. Otherwise we timeout the select every ++ * second and see if there are any keypresses. Note: this is a ++ * hack, in a proper Windows application we wouldn't do this. ++ */ ++ i = 0; ++ if (!write_tty) { ++ if (read_tty) { ++ tv.tv_sec = 1; ++ tv.tv_usec = 0; ++ i = select(width, (void *)&readfds, (void *)&writefds, ++ NULL, &tv); ++ if (!i && (!has_stdin_waiting() || !read_tty)) ++ continue; ++ } else ++ i = select(width, (void *)&readfds, (void *)&writefds, ++ NULL, timeoutp); ++ } ++#else ++ i = select(width, (void *)&readfds, (void *)&writefds, ++ NULL, timeoutp); ++#endif ++ if (i < 0) { ++ BIO_printf(bio_err, "bad select %d\n", ++ get_last_socket_error()); ++ goto shut; ++ /* goto end; */ ++ } ++ } ++ ++ if ((SSL_version(con) == DTLS1_VERSION) ++ && DTLSv1_handle_timeout(con) > 0) { ++ BIO_printf(bio_err, "TIMEOUT occurred\n"); ++ } ++ ++ if (!ssl_pending && FD_ISSET(SSL_get_fd(con), &writefds)) { ++ k = SSL_write(con, &(cbuf[cbuf_off]), (unsigned int)cbuf_len); ++ switch (SSL_get_error(con, k)) { ++ case SSL_ERROR_NONE: ++ cbuf_off += k; ++ cbuf_len -= k; ++ if (k <= 0) ++ goto end; ++ /* we have done a write(con,NULL,0); */ ++ if (cbuf_len <= 0) { ++ read_tty = 1; ++ write_ssl = 0; ++ } else { /* if (cbuf_len > 0) */ ++ ++ read_tty = 0; ++ write_ssl = 1; ++ } ++ break; ++ case SSL_ERROR_WANT_WRITE: ++ BIO_printf(bio_c_out, "write W BLOCK\n"); ++ write_ssl = 1; ++ read_tty = 0; ++ break; ++ case SSL_ERROR_WANT_ASYNC: ++ BIO_printf(bio_c_out, "write A BLOCK\n"); ++ wait_for_async(con); ++ write_ssl = 1; ++ read_tty = 0; ++ break; ++ case SSL_ERROR_WANT_READ: ++ BIO_printf(bio_c_out, "write R BLOCK\n"); ++ write_tty = 0; ++ read_ssl = 1; ++ write_ssl = 0; ++ break; ++ case SSL_ERROR_WANT_X509_LOOKUP: ++ BIO_printf(bio_c_out, "write X BLOCK\n"); ++ break; ++ case SSL_ERROR_ZERO_RETURN: ++ if (cbuf_len != 0) { ++ BIO_printf(bio_c_out, "shutdown\n"); ++ ret = 0; ++ goto shut; ++ } else { ++ read_tty = 1; ++ write_ssl = 0; ++ break; ++ } ++ ++ case SSL_ERROR_SYSCALL: ++ if ((k != 0) || (cbuf_len != 0)) { ++ BIO_printf(bio_err, "write:errno=%d\n", ++ get_last_socket_error()); ++ goto shut; ++ } else { ++ read_tty = 1; ++ write_ssl = 0; ++ } ++ break; ++ case SSL_ERROR_WANT_ASYNC_JOB: ++ /* This shouldn't ever happen in s_client - treat as an error */ ++ case SSL_ERROR_SSL: ++ ERR_print_errors(bio_err); ++ goto shut; ++ } ++ } ++#if defined(OPENSSL_SYS_WINDOWS) || defined(OPENSSL_SYS_MSDOS) || defined(OPENSSL_SYS_VMS) ++ /* Assume Windows/DOS/BeOS can always write */ ++ else if (!ssl_pending && write_tty) ++#else ++ else if (!ssl_pending && FD_ISSET(fileno_stdout(), &writefds)) ++#endif ++ { ++#ifdef CHARSET_EBCDIC ++ ascii2ebcdic(&(sbuf[sbuf_off]), &(sbuf[sbuf_off]), sbuf_len); ++#endif ++ i = raw_write_stdout(&(sbuf[sbuf_off]), sbuf_len); ++ ++ if (i <= 0) { ++ BIO_printf(bio_c_out, "DONE\n"); ++ ret = 0; ++ goto shut; ++ /* goto end; */ ++ } ++ ++ sbuf_len -= i;; ++ sbuf_off += i; ++ if (sbuf_len <= 0) { ++ read_ssl = 1; ++ write_tty = 0; ++ } ++ } else if (ssl_pending || FD_ISSET(SSL_get_fd(con), &readfds)) { ++#ifdef RENEG ++ { ++ static int iiii; ++ if (++iiii == 52) { ++ SSL_renegotiate(con); ++ iiii = 0; ++ } ++ } ++#endif ++ k = SSL_read(con, sbuf, 1024 /* BUFSIZZ */ ); ++ ++ switch (SSL_get_error(con, k)) { ++ case SSL_ERROR_NONE: ++ if (k <= 0) ++ goto end; ++ sbuf_off = 0; ++ sbuf_len = k; ++ ++ read_ssl = 0; ++ write_tty = 1; ++ break; ++ case SSL_ERROR_WANT_ASYNC: ++ BIO_printf(bio_c_out, "read A BLOCK\n"); ++ wait_for_async(con); ++ write_tty = 0; ++ read_ssl = 1; ++ if ((read_tty == 0) && (write_ssl == 0)) ++ write_ssl = 1; ++ break; ++ case SSL_ERROR_WANT_WRITE: ++ BIO_printf(bio_c_out, "read W BLOCK\n"); ++ write_ssl = 1; ++ read_tty = 0; ++ break; ++ case SSL_ERROR_WANT_READ: ++ BIO_printf(bio_c_out, "read R BLOCK\n"); ++ write_tty = 0; ++ read_ssl = 1; ++ if ((read_tty == 0) && (write_ssl == 0)) ++ write_ssl = 1; ++ break; ++ case SSL_ERROR_WANT_X509_LOOKUP: ++ BIO_printf(bio_c_out, "read X BLOCK\n"); ++ break; ++ case SSL_ERROR_SYSCALL: ++ ret = get_last_socket_error(); ++ if (c_brief) ++ BIO_puts(bio_err, "CONNECTION CLOSED BY SERVER\n"); ++ else ++ BIO_printf(bio_err, "read:errno=%d\n", ret); ++ goto shut; ++ case SSL_ERROR_ZERO_RETURN: ++ BIO_printf(bio_c_out, "closed\n"); ++ ret = 0; ++ goto shut; ++ case SSL_ERROR_WANT_ASYNC_JOB: ++ /* This shouldn't ever happen in s_client. Treat as an error */ ++ case SSL_ERROR_SSL: ++ ERR_print_errors(bio_err); ++ goto shut; ++ /* break; */ ++ } ++ } ++/* OPENSSL_SYS_MSDOS includes OPENSSL_SYS_WINDOWS */ ++#if defined(OPENSSL_SYS_MSDOS) ++ else if (has_stdin_waiting()) ++#else ++ else if (FD_ISSET(fileno_stdin(), &readfds)) ++#endif ++ { ++ if (crlf) { ++ int j, lf_num; ++ ++ i = raw_read_stdin(cbuf, BUFSIZZ / 2); ++ lf_num = 0; ++ /* both loops are skipped when i <= 0 */ ++ for (j = 0; j < i; j++) ++ if (cbuf[j] == '\n') ++ lf_num++; ++ for (j = i - 1; j >= 0; j--) { ++ cbuf[j + lf_num] = cbuf[j]; ++ if (cbuf[j] == '\n') { ++ lf_num--; ++ i++; ++ cbuf[j + lf_num] = '\r'; ++ } ++ } ++ assert(lf_num == 0); ++ } else ++ i = raw_read_stdin(cbuf, BUFSIZZ); ++#if !defined(OPENSSL_SYS_WINDOWS) && !defined(OPENSSL_SYS_MSDOS) ++ if (i == 0) ++ at_eof = 1; ++#endif ++ ++ if ((!c_ign_eof) && ((i <= 0) || (cbuf[0] == 'Q' && cmdletters))) { ++ BIO_printf(bio_err, "DONE\n"); ++ ret = 0; ++ goto shut; ++ } ++ ++ if ((!c_ign_eof) && (cbuf[0] == 'R' && cmdletters)) { ++ BIO_printf(bio_err, "RENEGOTIATING\n"); ++ SSL_renegotiate(con); ++ cbuf_len = 0; ++ } ++#ifndef OPENSSL_NO_HEARTBEATS ++ else if ((!c_ign_eof) && (cbuf[0] == 'B' && cmdletters)) { ++ BIO_printf(bio_err, "HEARTBEATING\n"); ++ SSL_heartbeat(con); ++ cbuf_len = 0; ++ } ++#endif ++ else { ++ cbuf_len = i; ++ cbuf_off = 0; ++#ifdef CHARSET_EBCDIC ++ ebcdic2ascii(cbuf, cbuf, i); ++#endif ++ } ++ ++ write_ssl = 1; ++ read_tty = 0; ++ } ++ } ++ ++ ret = 0; ++ shut: ++ if (in_init) ++ print_stuff(bio_c_out, con, full_log); ++ do_ssl_shutdown(con); ++#if defined(OPENSSL_SYS_WINDOWS) ++ /* ++ * Give the socket time to send its last data before we close it. ++ * No amount of setting SO_LINGER etc on the socket seems to persuade ++ * Windows to send the data before closing the socket...but sleeping ++ * for a short time seems to do it (units in ms) ++ * TODO: Find a better way to do this ++ */ ++ Sleep(50); ++#endif ++ BIO_closesocket(SSL_get_fd(con)); ++ end: ++ if (con != NULL) { ++ if (prexit != 0) ++ print_stuff(bio_c_out, con, 1); ++ SSL_free(con); ++ } ++#if !defined(OPENSSL_NO_NEXTPROTONEG) ++ OPENSSL_free(next_proto.data); ++#endif ++ SSL_CTX_free(ctx); ++ X509_free(cert); ++ sk_X509_CRL_pop_free(crls, X509_CRL_free); ++ EVP_PKEY_free(key); ++ sk_X509_pop_free(chain, X509_free); ++ OPENSSL_free(pass); ++#ifndef OPENSSL_NO_SRP ++ OPENSSL_free(srp_arg.srppassin); ++#endif ++ OPENSSL_free(connectstr); ++ OPENSSL_free(host); ++ OPENSSL_free(port); ++ X509_VERIFY_PARAM_free(vpm); ++ ssl_excert_free(exc); ++ sk_OPENSSL_STRING_free(ssl_args); ++ sk_OPENSSL_STRING_free(dane_tlsa_rrset); ++ SSL_CONF_CTX_free(cctx); ++ OPENSSL_clear_free(cbuf, BUFSIZZ); ++ OPENSSL_clear_free(sbuf, BUFSIZZ); ++ OPENSSL_clear_free(mbuf, BUFSIZZ); ++ release_engine(e); ++ BIO_free(bio_c_out); ++ bio_c_out = NULL; ++ BIO_free(bio_c_msg); ++ bio_c_msg = NULL; ++ return (ret); ++} ++ ++static void print_stuff(BIO *bio, SSL *s, int full) ++{ ++ X509 *peer = NULL; ++ char buf[BUFSIZ]; ++ STACK_OF(X509) *sk; ++ STACK_OF(X509_NAME) *sk2; ++ const SSL_CIPHER *c; ++ X509_NAME *xn; ++ int i; ++#ifndef OPENSSL_NO_COMP ++ const COMP_METHOD *comp, *expansion; ++#endif ++ unsigned char *exportedkeymat; ++#ifndef OPENSSL_NO_CT ++ const SSL_CTX *ctx = SSL_get_SSL_CTX(s); ++#endif ++ ++ if (full) { ++ int got_a_chain = 0; ++ ++ sk = SSL_get_peer_cert_chain(s); ++ if (sk != NULL) { ++ got_a_chain = 1; ++ ++ BIO_printf(bio, "---\nCertificate chain\n"); ++ for (i = 0; i < sk_X509_num(sk); i++) { ++ X509_NAME_oneline(X509_get_subject_name(sk_X509_value(sk, i)), ++ buf, sizeof buf); ++ BIO_printf(bio, "%2d s:%s\n", i, buf); ++ X509_NAME_oneline(X509_get_issuer_name(sk_X509_value(sk, i)), ++ buf, sizeof buf); ++ BIO_printf(bio, " i:%s\n", buf); ++ if (c_showcerts) ++ PEM_write_bio_X509(bio, sk_X509_value(sk, i)); ++ } ++ } ++ ++ BIO_printf(bio, "---\n"); ++ peer = SSL_get_peer_certificate(s); ++ if (peer != NULL) { ++ BIO_printf(bio, "Server certificate\n"); ++ ++ /* Redundant if we showed the whole chain */ ++ if (!(c_showcerts && got_a_chain)) ++ PEM_write_bio_X509(bio, peer); ++ X509_NAME_oneline(X509_get_subject_name(peer), buf, sizeof buf); ++ BIO_printf(bio, "subject=%s\n", buf); ++ X509_NAME_oneline(X509_get_issuer_name(peer), buf, sizeof buf); ++ BIO_printf(bio, "issuer=%s\n", buf); ++ } else ++ BIO_printf(bio, "no peer certificate available\n"); ++ ++ sk2 = SSL_get_client_CA_list(s); ++ if ((sk2 != NULL) && (sk_X509_NAME_num(sk2) > 0)) { ++ BIO_printf(bio, "---\nAcceptable client certificate CA names\n"); ++ for (i = 0; i < sk_X509_NAME_num(sk2); i++) { ++ xn = sk_X509_NAME_value(sk2, i); ++ X509_NAME_oneline(xn, buf, sizeof(buf)); ++ BIO_write(bio, buf, strlen(buf)); ++ BIO_write(bio, "\n", 1); ++ } ++ } else { ++ BIO_printf(bio, "---\nNo client certificate CA names sent\n"); ++ } ++ ++ ssl_print_sigalgs(bio, s); ++ ssl_print_tmp_key(bio, s); ++ ++#ifndef OPENSSL_NO_CT ++ /* ++ * When the SSL session is anonymous, or resumed via an abbreviated ++ * handshake, no SCTs are provided as part of the handshake. While in ++ * a resumed session SCTs may be present in the session's certificate, ++ * no callbacks are invoked to revalidate these, and in any case that ++ * set of SCTs may be incomplete. Thus it makes little sense to ++ * attempt to display SCTs from a resumed session's certificate, and of ++ * course none are associated with an anonymous peer. ++ */ ++ if (peer != NULL && !SSL_session_reused(s) && SSL_ct_is_enabled(s)) { ++ const STACK_OF(SCT) *scts = SSL_get0_peer_scts(s); ++ int sct_count = scts != NULL ? sk_SCT_num(scts) : 0; ++ ++ BIO_printf(bio, "---\nSCTs present (%i)\n", sct_count); ++ if (sct_count > 0) { ++ const CTLOG_STORE *log_store = SSL_CTX_get0_ctlog_store(ctx); ++ ++ BIO_printf(bio, "---\n"); ++ for (i = 0; i < sct_count; ++i) { ++ SCT *sct = sk_SCT_value(scts, i); ++ ++ BIO_printf(bio, "SCT validation status: %s\n", ++ SCT_validation_status_string(sct)); ++ SCT_print(sct, bio, 0, log_store); ++ if (i < sct_count - 1) ++ BIO_printf(bio, "\n---\n"); ++ } ++ BIO_printf(bio, "\n"); ++ } ++ } ++#endif ++ ++ BIO_printf(bio, ++ "---\nSSL handshake has read %" PRIu64 ++ " bytes and written %" PRIu64 " bytes\n", ++ BIO_number_read(SSL_get_rbio(s)), ++ BIO_number_written(SSL_get_wbio(s))); ++ } ++ print_verify_detail(s, bio); ++ BIO_printf(bio, (SSL_session_reused(s) ? "---\nReused, " : "---\nNew, ")); ++ c = SSL_get_current_cipher(s); ++ BIO_printf(bio, "%s, Cipher is %s\n", ++ SSL_CIPHER_get_version(c), SSL_CIPHER_get_name(c)); ++ if (peer != NULL) { ++ EVP_PKEY *pktmp; ++ ++ pktmp = X509_get0_pubkey(peer); ++ BIO_printf(bio, "Server public key is %d bit\n", ++ EVP_PKEY_bits(pktmp)); ++ } ++ BIO_printf(bio, "Secure Renegotiation IS%s supported\n", ++ SSL_get_secure_renegotiation_support(s) ? "" : " NOT"); ++#ifndef OPENSSL_NO_COMP ++ comp = SSL_get_current_compression(s); ++ expansion = SSL_get_current_expansion(s); ++ BIO_printf(bio, "Compression: %s\n", ++ comp ? SSL_COMP_get_name(comp) : "NONE"); ++ BIO_printf(bio, "Expansion: %s\n", ++ expansion ? SSL_COMP_get_name(expansion) : "NONE"); ++#endif ++ ++#ifdef SSL_DEBUG ++ { ++ /* Print out local port of connection: useful for debugging */ ++ int sock; ++ union BIO_sock_info_u info; ++ ++ sock = SSL_get_fd(s); ++ if ((info.addr = BIO_ADDR_new()) != NULL ++ && BIO_sock_info(sock, BIO_SOCK_INFO_ADDRESS, &info)) { ++ BIO_printf(bio_c_out, "LOCAL PORT is %u\n", ++ ntohs(BIO_ADDR_rawport(info.addr))); ++ } ++ BIO_ADDR_free(info.addr); ++ } ++#endif ++ ++#if !defined(OPENSSL_NO_NEXTPROTONEG) ++ if (next_proto.status != -1) { ++ const unsigned char *proto; ++ unsigned int proto_len; ++ SSL_get0_next_proto_negotiated(s, &proto, &proto_len); ++ BIO_printf(bio, "Next protocol: (%d) ", next_proto.status); ++ BIO_write(bio, proto, proto_len); ++ BIO_write(bio, "\n", 1); ++ } ++#endif ++ { ++ const unsigned char *proto; ++ unsigned int proto_len; ++ SSL_get0_alpn_selected(s, &proto, &proto_len); ++ if (proto_len > 0) { ++ BIO_printf(bio, "ALPN protocol: "); ++ BIO_write(bio, proto, proto_len); ++ BIO_write(bio, "\n", 1); ++ } else ++ BIO_printf(bio, "No ALPN negotiated\n"); ++ } ++ ++#ifndef OPENSSL_NO_SRTP ++ { ++ SRTP_PROTECTION_PROFILE *srtp_profile = ++ SSL_get_selected_srtp_profile(s); ++ ++ if (srtp_profile) ++ BIO_printf(bio, "SRTP Extension negotiated, profile=%s\n", ++ srtp_profile->name); ++ } ++#endif ++ ++ SSL_SESSION_print(bio, SSL_get_session(s)); ++ if (SSL_get_session(s) != NULL && keymatexportlabel != NULL) { ++ BIO_printf(bio, "Keying material exporter:\n"); ++ BIO_printf(bio, " Label: '%s'\n", keymatexportlabel); ++ BIO_printf(bio, " Length: %i bytes\n", keymatexportlen); ++ exportedkeymat = app_malloc(keymatexportlen, "export key"); ++ if (!SSL_export_keying_material(s, exportedkeymat, ++ keymatexportlen, ++ keymatexportlabel, ++ strlen(keymatexportlabel), ++ NULL, 0, 0)) { ++ BIO_printf(bio, " Error\n"); ++ } else { ++ BIO_printf(bio, " Keying material: "); ++ for (i = 0; i < keymatexportlen; i++) ++ BIO_printf(bio, "%02X", exportedkeymat[i]); ++ BIO_printf(bio, "\n"); ++ } ++ OPENSSL_free(exportedkeymat); ++ } ++ BIO_printf(bio, "---\n"); ++ X509_free(peer); ++ /* flush, or debugging output gets mixed with http response */ ++ (void)BIO_flush(bio); ++} ++ ++# ifndef OPENSSL_NO_OCSP ++static int ocsp_resp_cb(SSL *s, void *arg) ++{ ++ const unsigned char *p; ++ int len; ++ OCSP_RESPONSE *rsp; ++ len = SSL_get_tlsext_status_ocsp_resp(s, &p); ++ BIO_puts(arg, "OCSP response: "); ++ if (!p) { ++ BIO_puts(arg, "no response sent\n"); ++ return 1; ++ } ++ rsp = d2i_OCSP_RESPONSE(NULL, &p, len); ++ if (!rsp) { ++ BIO_puts(arg, "response parse error\n"); ++ BIO_dump_indent(arg, (char *)p, len, 4); ++ return 0; ++ } ++ BIO_puts(arg, "\n======================================\n"); ++ OCSP_RESPONSE_print(arg, rsp, 0); ++ BIO_puts(arg, "======================================\n"); ++ OCSP_RESPONSE_free(rsp); ++ return 1; ++} ++# endif ++ ++#endif /* OPENSSL_NO_SOCK */ +diff --git a/CryptoPkg/Library/OpensslLib/openssl/apps/s_server.c b/CryptoPkg/Library/OpensslLib/openssl/apps/s_server.c +new file mode 100644 +index 0000000..66405e6 +--- /dev/null ++++ b/CryptoPkg/Library/OpensslLib/openssl/apps/s_server.c +@@ -0,0 +1,3301 @@ ++/* ++ * Copyright 1995-2016 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 ++ * in the file LICENSE in the source distribution or at ++ * https://www.openssl.org/source/license.html ++ */ ++ ++/* ==================================================================== ++ * Copyright 2002 Sun Microsystems, Inc. ALL RIGHTS RESERVED. ++ * ECC cipher suite support in OpenSSL originally developed by ++ * SUN MICROSYSTEMS, INC., and contributed to the OpenSSL project. ++ */ ++/* ==================================================================== ++ * Copyright 2005 Nokia. All rights reserved. ++ * ++ * The portions of the attached software ("Contribution") is developed by ++ * Nokia Corporation and is licensed pursuant to the OpenSSL open source ++ * license. ++ * ++ * The Contribution, originally written by Mika Kousa and Pasi Eronen of ++ * Nokia Corporation, consists of the "PSK" (Pre-Shared Key) ciphersuites ++ * support (see RFC 4279) to OpenSSL. ++ * ++ * No patent licenses or other rights except those expressly stated in ++ * the OpenSSL open source license shall be deemed granted or received ++ * expressly, by implication, estoppel, or otherwise. ++ * ++ * No assurances are provided by Nokia that the Contribution does not ++ * infringe the patent or other intellectual property rights of any third ++ * party or that the license provides you with all the necessary rights ++ * to make use of the Contribution. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND. IN ++ * ADDITION TO THE DISCLAIMERS INCLUDED IN THE LICENSE, NOKIA ++ * SPECIFICALLY DISCLAIMS ANY LIABILITY FOR CLAIMS BROUGHT BY YOU OR ANY ++ * OTHER ENTITY BASED ON INFRINGEMENT OF INTELLECTUAL PROPERTY RIGHTS OR ++ * OTHERWISE. ++ */ ++ ++#include ++#include ++#include ++#include ++#if defined(_WIN32) ++/* Included before async.h to avoid some warnings */ ++# include ++#endif ++ ++#include ++#include ++#include ++ ++#ifndef OPENSSL_NO_SOCK ++ ++/* ++ * With IPv6, it looks like Digital has mixed up the proper order of ++ * recursive header file inclusion, resulting in the compiler complaining ++ * that u_int isn't defined, but only if _POSIX_C_SOURCE is defined, which is ++ * needed to have fileno() declared correctly... So let's define u_int ++ */ ++#if defined(OPENSSL_SYS_VMS_DECC) && !defined(__U_INT) ++# define __U_INT ++typedef unsigned int u_int; ++#endif ++ ++#include ++#include ++#define USE_SOCKETS ++#include "apps.h" ++#include ++#include ++#include ++#include ++#include ++#include ++#ifndef OPENSSL_NO_DH ++# include ++#endif ++#ifndef OPENSSL_NO_RSA ++# include ++#endif ++#ifndef OPENSSL_NO_SRP ++# include ++#endif ++#include "s_apps.h" ++#include "timeouts.h" ++#ifdef CHARSET_EBCDIC ++#include ++#endif ++ ++static int not_resumable_sess_cb(SSL *s, int is_forward_secure); ++static int sv_body(int s, int stype, unsigned char *context); ++static int www_body(int s, int stype, unsigned char *context); ++static int rev_body(int s, int stype, unsigned char *context); ++static void close_accept_socket(void); ++static int init_ssl_connection(SSL *s); ++static void print_stats(BIO *bp, SSL_CTX *ctx); ++static int generate_session_id(const SSL *ssl, unsigned char *id, ++ unsigned int *id_len); ++static void init_session_cache_ctx(SSL_CTX *sctx); ++static void free_sessions(void); ++#ifndef OPENSSL_NO_DH ++static DH *load_dh_param(const char *dhfile); ++#endif ++ ++/* static int load_CA(SSL_CTX *ctx, char *file);*/ ++ ++static const int bufsize = 16 * 1024; ++static int accept_socket = -1; ++ ++#define TEST_CERT "server.pem" ++#define TEST_CERT2 "server2.pem" ++ ++static int s_nbio = 0; ++static int s_nbio_test = 0; ++static int s_crlf = 0; ++static SSL_CTX *ctx = NULL; ++static SSL_CTX *ctx2 = NULL; ++static int www = 0; ++ ++static BIO *bio_s_out = NULL; ++static BIO *bio_s_msg = NULL; ++static int s_debug = 0; ++static int s_tlsextdebug = 0; ++static int s_msg = 0; ++static int s_quiet = 0; ++static int s_ign_eof = 0; ++static int s_brief = 0; ++ ++static char *keymatexportlabel = NULL; ++static int keymatexportlen = 20; ++ ++static int async = 0; ++ ++static const char *session_id_prefix = NULL; ++ ++#ifndef OPENSSL_NO_DTLS ++static int enable_timeouts = 0; ++static long socket_mtu; ++ ++#endif ++static int dtlslisten = 0; ++ ++#ifndef OPENSSL_NO_PSK ++static char *psk_identity = "Client_identity"; ++char *psk_key = NULL; /* by default PSK is not used */ ++ ++static unsigned int psk_server_cb(SSL *ssl, const char *identity, ++ unsigned char *psk, ++ unsigned int max_psk_len) ++{ ++ long key_len = 0; ++ unsigned char *key; ++ ++ if (s_debug) ++ BIO_printf(bio_s_out, "psk_server_cb\n"); ++ if (!identity) { ++ BIO_printf(bio_err, "Error: client did not send PSK identity\n"); ++ goto out_err; ++ } ++ if (s_debug) ++ BIO_printf(bio_s_out, "identity_len=%d identity=%s\n", ++ (int)strlen(identity), identity); ++ ++ /* here we could lookup the given identity e.g. from a database */ ++ if (strcmp(identity, psk_identity) != 0) { ++ BIO_printf(bio_s_out, "PSK error: client identity not found" ++ " (got '%s' expected '%s')\n", identity, psk_identity); ++ goto out_err; ++ } ++ if (s_debug) ++ BIO_printf(bio_s_out, "PSK client identity found\n"); ++ ++ /* convert the PSK key to binary */ ++ key = OPENSSL_hexstr2buf(psk_key, &key_len); ++ if (key == NULL) { ++ BIO_printf(bio_err, "Could not convert PSK key '%s' to buffer\n", ++ psk_key); ++ return 0; ++ } ++ if (key_len > (int)max_psk_len) { ++ BIO_printf(bio_err, ++ "psk buffer of callback is too small (%d) for key (%ld)\n", ++ max_psk_len, key_len); ++ OPENSSL_free(key); ++ return 0; ++ } ++ ++ memcpy(psk, key, key_len); ++ OPENSSL_free(key); ++ ++ if (s_debug) ++ BIO_printf(bio_s_out, "fetched PSK len=%ld\n", key_len); ++ return key_len; ++ out_err: ++ if (s_debug) ++ BIO_printf(bio_err, "Error in PSK server callback\n"); ++ (void)BIO_flush(bio_err); ++ (void)BIO_flush(bio_s_out); ++ return 0; ++} ++#endif ++ ++#ifndef OPENSSL_NO_SRP ++/* This is a context that we pass to callbacks */ ++typedef struct srpsrvparm_st { ++ char *login; ++ SRP_VBASE *vb; ++ SRP_user_pwd *user; ++} srpsrvparm; ++ ++/* ++ * This callback pretends to require some asynchronous logic in order to ++ * obtain a verifier. When the callback is called for a new connection we ++ * return with a negative value. This will provoke the accept etc to return ++ * with an LOOKUP_X509. The main logic of the reinvokes the suspended call ++ * (which would normally occur after a worker has finished) and we set the ++ * user parameters. ++ */ ++static int ssl_srp_server_param_cb(SSL *s, int *ad, void *arg) ++{ ++ srpsrvparm *p = (srpsrvparm *) arg; ++ int ret = SSL3_AL_FATAL; ++ ++ if (p->login == NULL && p->user == NULL) { ++ p->login = SSL_get_srp_username(s); ++ BIO_printf(bio_err, "SRP username = \"%s\"\n", p->login); ++ return (-1); ++ } ++ ++ if (p->user == NULL) { ++ BIO_printf(bio_err, "User %s doesn't exist\n", p->login); ++ goto err; ++ } ++ ++ if (SSL_set_srp_server_param ++ (s, p->user->N, p->user->g, p->user->s, p->user->v, ++ p->user->info) < 0) { ++ *ad = SSL_AD_INTERNAL_ERROR; ++ goto err; ++ } ++ BIO_printf(bio_err, ++ "SRP parameters set: username = \"%s\" info=\"%s\" \n", ++ p->login, p->user->info); ++ ret = SSL_ERROR_NONE; ++ ++ err: ++ SRP_user_pwd_free(p->user); ++ p->user = NULL; ++ p->login = NULL; ++ return ret; ++} ++ ++#endif ++ ++static int local_argc = 0; ++static char **local_argv; ++ ++#ifdef CHARSET_EBCDIC ++static int ebcdic_new(BIO *bi); ++static int ebcdic_free(BIO *a); ++static int ebcdic_read(BIO *b, char *out, int outl); ++static int ebcdic_write(BIO *b, const char *in, int inl); ++static long ebcdic_ctrl(BIO *b, int cmd, long num, void *ptr); ++static int ebcdic_gets(BIO *bp, char *buf, int size); ++static int ebcdic_puts(BIO *bp, const char *str); ++ ++# define BIO_TYPE_EBCDIC_FILTER (18|0x0200) ++static BIO_METHOD *methods_ebcdic = NULL; ++ ++/* This struct is "unwarranted chumminess with the compiler." */ ++typedef struct { ++ size_t alloced; ++ char buff[1]; ++} EBCDIC_OUTBUFF; ++ ++static const BIO_METHOD *BIO_f_ebcdic_filter() ++{ ++ if (methods_ebcdic == NULL) { ++ methods_ebcdic = BIO_meth_new(BIO_TYPE_EBCDIC_FILTER, ++ "EBCDIC/ASCII filter"); ++ if (methods_ebcdic == NULL ++ || !BIO_meth_set_write(methods_ebcdic, ebcdic_write) ++ || !BIO_meth_set_read(methods_ebcdic, ebcdic_read) ++ || !BIO_meth_set_puts(methods_ebcdic, ebcdic_puts) ++ || !BIO_meth_set_gets(methods_ebcdic, ebcdic_gets) ++ || !BIO_meth_set_ctrl(methods_ebcdic, ebcdic_ctrl) ++ || !BIO_meth_set_create(methods_ebcdic, ebcdic_new) ++ || !BIO_meth_set_destroy(methods_ebcdic, ebcdic_free)) ++ return NULL; ++ } ++ return methods_ebcdic; ++} ++ ++static int ebcdic_new(BIO *bi) ++{ ++ EBCDIC_OUTBUFF *wbuf; ++ ++ wbuf = app_malloc(sizeof(*wbuf) + 1024, "ebcdic wbuf"); ++ wbuf->alloced = 1024; ++ wbuf->buff[0] = '\0'; ++ ++ BIO_set_data(bi, wbuf); ++ BIO_set_init(bi, 1); ++ return 1; ++} ++ ++static int ebcdic_free(BIO *a) ++{ ++ EBCDIC_OUTBUFF *wbuf; ++ ++ if (a == NULL) ++ return 0; ++ wbuf = BIO_get_data(a); ++ OPENSSL_free(wbuf); ++ BIO_set_data(a, NULL); ++ BIO_set_init(a, 0); ++ ++ return 1; ++} ++ ++static int ebcdic_read(BIO *b, char *out, int outl) ++{ ++ int ret = 0; ++ BIO *next = BIO_next(b); ++ ++ if (out == NULL || outl == 0) ++ return (0); ++ if (next == NULL) ++ return (0); ++ ++ ret = BIO_read(next, out, outl); ++ if (ret > 0) ++ ascii2ebcdic(out, out, ret); ++ return ret; ++} ++ ++static int ebcdic_write(BIO *b, const char *in, int inl) ++{ ++ EBCDIC_OUTBUFF *wbuf; ++ BIO *next = BIO_next(b); ++ int ret = 0; ++ int num; ++ ++ if ((in == NULL) || (inl <= 0)) ++ return (0); ++ if (next == NULL) ++ return 0; ++ ++ wbuf = (EBCDIC_OUTBUFF *) BIO_get_data(b); ++ ++ if (inl > (num = wbuf->alloced)) { ++ num = num + num; /* double the size */ ++ if (num < inl) ++ num = inl; ++ OPENSSL_free(wbuf); ++ wbuf = app_malloc(sizeof(*wbuf) + num, "grow ebcdic wbuf"); ++ ++ wbuf->alloced = num; ++ wbuf->buff[0] = '\0'; ++ ++ BIO_set_data(b, wbuf); ++ } ++ ++ ebcdic2ascii(wbuf->buff, in, inl); ++ ++ ret = BIO_write(next, wbuf->buff, inl); ++ ++ return (ret); ++} ++ ++static long ebcdic_ctrl(BIO *b, int cmd, long num, void *ptr) ++{ ++ long ret; ++ BIO *next = BIO_next(b); ++ ++ if (next == NULL) ++ return (0); ++ switch (cmd) { ++ case BIO_CTRL_DUP: ++ ret = 0L; ++ break; ++ default: ++ ret = BIO_ctrl(next, cmd, num, ptr); ++ break; ++ } ++ return (ret); ++} ++ ++static int ebcdic_gets(BIO *bp, char *buf, int size) ++{ ++ int i, ret = 0; ++ BIO *next = BIO_next(bp); ++ ++ if (next == NULL) ++ return 0; ++/* return(BIO_gets(bp->next_bio,buf,size));*/ ++ for (i = 0; i < size - 1; ++i) { ++ ret = ebcdic_read(bp, &buf[i], 1); ++ if (ret <= 0) ++ break; ++ else if (buf[i] == '\n') { ++ ++i; ++ break; ++ } ++ } ++ if (i < size) ++ buf[i] = '\0'; ++ return (ret < 0 && i == 0) ? ret : i; ++} ++ ++static int ebcdic_puts(BIO *bp, const char *str) ++{ ++ if (BIO_next(bp) == NULL) ++ return 0; ++ return ebcdic_write(bp, str, strlen(str)); ++} ++#endif ++ ++/* This is a context that we pass to callbacks */ ++typedef struct tlsextctx_st { ++ char *servername; ++ BIO *biodebug; ++ int extension_error; ++} tlsextctx; ++ ++static int ssl_servername_cb(SSL *s, int *ad, void *arg) ++{ ++ tlsextctx *p = (tlsextctx *) arg; ++ const char *servername = SSL_get_servername(s, TLSEXT_NAMETYPE_host_name); ++ if (servername && p->biodebug) ++ BIO_printf(p->biodebug, "Hostname in TLS extension: \"%s\"\n", ++ servername); ++ ++ if (!p->servername) ++ return SSL_TLSEXT_ERR_NOACK; ++ ++ if (servername) { ++ if (strcasecmp(servername, p->servername)) ++ return p->extension_error; ++ if (ctx2) { ++ BIO_printf(p->biodebug, "Switching server context.\n"); ++ SSL_set_SSL_CTX(s, ctx2); ++ } ++ } ++ return SSL_TLSEXT_ERR_OK; ++} ++ ++/* Structure passed to cert status callback */ ++ ++typedef struct tlsextstatusctx_st { ++ /* Default responder to use */ ++ char *host, *path, *port; ++ int use_ssl; ++ int timeout; ++ int verbose; ++} tlsextstatusctx; ++ ++static tlsextstatusctx tlscstatp = { NULL, NULL, NULL, 0, -1, 0 }; ++ ++#ifndef OPENSSL_NO_OCSP ++/* ++ * Certificate Status callback. This is called when a client includes a ++ * certificate status request extension. This is a simplified version. It ++ * examines certificates each time and makes one OCSP responder query for ++ * each request. A full version would store details such as the OCSP ++ * certificate IDs and minimise the number of OCSP responses by caching them ++ * until they were considered "expired". ++ */ ++ ++static int cert_status_cb(SSL *s, void *arg) ++{ ++ tlsextstatusctx *srctx = arg; ++ char *host = NULL, *port = NULL, *path = NULL; ++ int use_ssl; ++ unsigned char *rspder = NULL; ++ int rspderlen; ++ STACK_OF(OPENSSL_STRING) *aia = NULL; ++ X509 *x = NULL; ++ X509_STORE_CTX *inctx = NULL; ++ X509_OBJECT *obj; ++ OCSP_REQUEST *req = NULL; ++ OCSP_RESPONSE *resp = NULL; ++ OCSP_CERTID *id = NULL; ++ STACK_OF(X509_EXTENSION) *exts; ++ int ret = SSL_TLSEXT_ERR_NOACK; ++ int i; ++ ++ if (srctx->verbose) ++ BIO_puts(bio_err, "cert_status: callback called\n"); ++ /* Build up OCSP query from server certificate */ ++ x = SSL_get_certificate(s); ++ aia = X509_get1_ocsp(x); ++ if (aia) { ++ if (!OCSP_parse_url(sk_OPENSSL_STRING_value(aia, 0), ++ &host, &port, &path, &use_ssl)) { ++ BIO_puts(bio_err, "cert_status: can't parse AIA URL\n"); ++ goto err; ++ } ++ if (srctx->verbose) ++ BIO_printf(bio_err, "cert_status: AIA URL: %s\n", ++ sk_OPENSSL_STRING_value(aia, 0)); ++ } else { ++ if (!srctx->host) { ++ BIO_puts(bio_err, ++ "cert_status: no AIA and no default responder URL\n"); ++ goto done; ++ } ++ host = srctx->host; ++ path = srctx->path; ++ port = srctx->port; ++ use_ssl = srctx->use_ssl; ++ } ++ ++ inctx = X509_STORE_CTX_new(); ++ if (inctx == NULL) ++ goto err; ++ if (!X509_STORE_CTX_init(inctx, ++ SSL_CTX_get_cert_store(SSL_get_SSL_CTX(s)), ++ NULL, NULL)) ++ goto err; ++ obj = X509_STORE_CTX_get_obj_by_subject(inctx, X509_LU_X509, ++ X509_get_issuer_name(x)); ++ if (obj == NULL) { ++ BIO_puts(bio_err, "cert_status: Can't retrieve issuer certificate.\n"); ++ goto done; ++ } ++ id = OCSP_cert_to_id(NULL, x, X509_OBJECT_get0_X509(obj)); ++ X509_OBJECT_free(obj); ++ if (!id) ++ goto err; ++ req = OCSP_REQUEST_new(); ++ if (req == NULL) ++ goto err; ++ if (!OCSP_request_add0_id(req, id)) ++ goto err; ++ id = NULL; ++ /* Add any extensions to the request */ ++ SSL_get_tlsext_status_exts(s, &exts); ++ for (i = 0; i < sk_X509_EXTENSION_num(exts); i++) { ++ X509_EXTENSION *ext = sk_X509_EXTENSION_value(exts, i); ++ if (!OCSP_REQUEST_add_ext(req, ext, -1)) ++ goto err; ++ } ++ resp = process_responder(req, host, path, port, use_ssl, NULL, ++ srctx->timeout); ++ if (!resp) { ++ BIO_puts(bio_err, "cert_status: error querying responder\n"); ++ goto done; ++ } ++ rspderlen = i2d_OCSP_RESPONSE(resp, &rspder); ++ if (rspderlen <= 0) ++ goto err; ++ SSL_set_tlsext_status_ocsp_resp(s, rspder, rspderlen); ++ if (srctx->verbose) { ++ BIO_puts(bio_err, "cert_status: ocsp response sent:\n"); ++ OCSP_RESPONSE_print(bio_err, resp, 2); ++ } ++ ret = SSL_TLSEXT_ERR_OK; ++ goto done; ++ ++ err: ++ ret = SSL_TLSEXT_ERR_ALERT_FATAL; ++ done: ++ if (ret != SSL_TLSEXT_ERR_OK) ++ ERR_print_errors(bio_err); ++ if (aia) { ++ OPENSSL_free(host); ++ OPENSSL_free(path); ++ OPENSSL_free(port); ++ X509_email_free(aia); ++ } ++ OCSP_CERTID_free(id); ++ OCSP_REQUEST_free(req); ++ OCSP_RESPONSE_free(resp); ++ X509_STORE_CTX_free(inctx); ++ return ret; ++} ++#endif ++ ++#ifndef OPENSSL_NO_NEXTPROTONEG ++/* This is the context that we pass to next_proto_cb */ ++typedef struct tlsextnextprotoctx_st { ++ unsigned char *data; ++ unsigned int len; ++} tlsextnextprotoctx; ++ ++static int next_proto_cb(SSL *s, const unsigned char **data, ++ unsigned int *len, void *arg) ++{ ++ tlsextnextprotoctx *next_proto = arg; ++ ++ *data = next_proto->data; ++ *len = next_proto->len; ++ ++ return SSL_TLSEXT_ERR_OK; ++} ++#endif /* ndef OPENSSL_NO_NEXTPROTONEG */ ++ ++/* This the context that we pass to alpn_cb */ ++typedef struct tlsextalpnctx_st { ++ unsigned char *data; ++ size_t len; ++} tlsextalpnctx; ++ ++static int alpn_cb(SSL *s, const unsigned char **out, unsigned char *outlen, ++ const unsigned char *in, unsigned int inlen, void *arg) ++{ ++ tlsextalpnctx *alpn_ctx = arg; ++ ++ if (!s_quiet) { ++ /* We can assume that |in| is syntactically valid. */ ++ unsigned int i; ++ BIO_printf(bio_s_out, "ALPN protocols advertised by the client: "); ++ for (i = 0; i < inlen;) { ++ if (i) ++ BIO_write(bio_s_out, ", ", 2); ++ BIO_write(bio_s_out, &in[i + 1], in[i]); ++ i += in[i] + 1; ++ } ++ BIO_write(bio_s_out, "\n", 1); ++ } ++ ++ if (SSL_select_next_proto ++ ((unsigned char **)out, outlen, alpn_ctx->data, alpn_ctx->len, in, ++ inlen) != OPENSSL_NPN_NEGOTIATED) { ++ return SSL_TLSEXT_ERR_NOACK; ++ } ++ ++ if (!s_quiet) { ++ BIO_printf(bio_s_out, "ALPN protocols selected: "); ++ BIO_write(bio_s_out, *out, *outlen); ++ BIO_write(bio_s_out, "\n", 1); ++ } ++ ++ return SSL_TLSEXT_ERR_OK; ++} ++ ++static int not_resumable_sess_cb(SSL *s, int is_forward_secure) ++{ ++ /* disable resumption for sessions with forward secure ciphers */ ++ return is_forward_secure; ++} ++ ++#ifndef OPENSSL_NO_SRP ++static srpsrvparm srp_callback_parm; ++#endif ++#ifndef OPENSSL_NO_SRTP ++static char *srtp_profiles = NULL; ++#endif ++ ++typedef enum OPTION_choice { ++ OPT_ERR = -1, OPT_EOF = 0, OPT_HELP, OPT_ENGINE, ++ OPT_4, OPT_6, OPT_ACCEPT, OPT_PORT, OPT_UNIX, OPT_UNLINK, OPT_NACCEPT, ++ OPT_VERIFY, OPT_UPPER_V_VERIFY, OPT_CONTEXT, OPT_CERT, OPT_CRL, ++ OPT_CRL_DOWNLOAD, OPT_SERVERINFO, OPT_CERTFORM, OPT_KEY, OPT_KEYFORM, ++ OPT_PASS, OPT_CERT_CHAIN, OPT_DHPARAM, OPT_DCERTFORM, OPT_DCERT, ++ OPT_DKEYFORM, OPT_DPASS, OPT_DKEY, OPT_DCERT_CHAIN, OPT_NOCERT, ++ OPT_CAPATH, OPT_NOCAPATH, OPT_CHAINCAPATH, OPT_VERIFYCAPATH, OPT_NO_CACHE, ++ OPT_EXT_CACHE, OPT_CRLFORM, OPT_VERIFY_RET_ERROR, OPT_VERIFY_QUIET, ++ OPT_BUILD_CHAIN, OPT_CAFILE, OPT_NOCAFILE, OPT_CHAINCAFILE, ++ OPT_VERIFYCAFILE, OPT_NBIO, OPT_NBIO_TEST, OPT_IGN_EOF, OPT_NO_IGN_EOF, ++ OPT_DEBUG, OPT_TLSEXTDEBUG, OPT_STATUS, OPT_STATUS_VERBOSE, ++ OPT_STATUS_TIMEOUT, OPT_STATUS_URL, OPT_MSG, OPT_MSGFILE, OPT_TRACE, ++ OPT_SECURITY_DEBUG, OPT_SECURITY_DEBUG_VERBOSE, OPT_STATE, OPT_CRLF, ++ OPT_QUIET, OPT_BRIEF, OPT_NO_DHE, ++ OPT_NO_RESUME_EPHEMERAL, OPT_PSK_HINT, OPT_PSK, OPT_SRPVFILE, ++ OPT_SRPUSERSEED, OPT_REV, OPT_WWW, OPT_UPPER_WWW, OPT_HTTP, OPT_ASYNC, ++ OPT_SSL_CONFIG, OPT_SPLIT_SEND_FRAG, OPT_MAX_PIPELINES, OPT_READ_BUF, ++ OPT_SSL3, OPT_TLS1_2, OPT_TLS1_1, OPT_TLS1, OPT_DTLS, OPT_DTLS1, ++ OPT_DTLS1_2, OPT_TIMEOUT, OPT_MTU, OPT_LISTEN, ++ OPT_ID_PREFIX, OPT_RAND, OPT_SERVERNAME, OPT_SERVERNAME_FATAL, ++ OPT_CERT2, OPT_KEY2, OPT_NEXTPROTONEG, OPT_ALPN, ++ OPT_SRTP_PROFILES, OPT_KEYMATEXPORT, OPT_KEYMATEXPORTLEN, ++ OPT_S_ENUM, ++ OPT_V_ENUM, ++ OPT_X_ENUM ++} OPTION_CHOICE; ++ ++OPTIONS s_server_options[] = { ++ {"help", OPT_HELP, '-', "Display this summary"}, ++ {"port", OPT_PORT, 'p', ++ "TCP/IP port to listen on for connections (default is " PORT ")"}, ++ {"accept", OPT_ACCEPT, 's', ++ "TCP/IP optional host and port to listen on for connections (default is *:" PORT ")"}, ++#ifdef AF_UNIX ++ {"unix", OPT_UNIX, 's', "Unix domain socket to accept on"}, ++#endif ++ {"4", OPT_4, '-', "Use IPv4 only"}, ++ {"6", OPT_6, '-', "Use IPv6 only"}, ++#ifdef AF_UNIX ++ {"unlink", OPT_UNLINK, '-', "For -unix, unlink existing socket first"}, ++#endif ++ {"context", OPT_CONTEXT, 's', "Set session ID context"}, ++ {"verify", OPT_VERIFY, 'n', "Turn on peer certificate verification"}, ++ {"Verify", OPT_UPPER_V_VERIFY, 'n', ++ "Turn on peer certificate verification, must have a cert"}, ++ {"cert", OPT_CERT, '<', "Certificate file to use; default is " TEST_CERT}, ++ {"naccept", OPT_NACCEPT, 'p', "Terminate after #num connections"}, ++ {"serverinfo", OPT_SERVERINFO, 's', ++ "PEM serverinfo file for certificate"}, ++ {"certform", OPT_CERTFORM, 'F', ++ "Certificate format (PEM or DER) PEM default"}, ++ {"key", OPT_KEY, '<', ++ "Private Key if not in -cert; default is " TEST_CERT}, ++ {"keyform", OPT_KEYFORM, 'f', ++ "Key format (PEM, DER or ENGINE) PEM default"}, ++ {"pass", OPT_PASS, 's', "Private key file pass phrase source"}, ++ {"dcert", OPT_DCERT, '<', ++ "Second certificate file to use (usually for DSA)"}, ++ {"dcertform", OPT_DCERTFORM, 'F', ++ "Second certificate format (PEM or DER) PEM default"}, ++ {"dkey", OPT_DKEY, '<', ++ "Second private key file to use (usually for DSA)"}, ++ {"dkeyform", OPT_DKEYFORM, 'F', ++ "Second key format (PEM, DER or ENGINE) PEM default"}, ++ {"dpass", OPT_DPASS, 's', "Second private key file pass phrase source"}, ++ {"nbio_test", OPT_NBIO_TEST, '-', "Test with the non-blocking test bio"}, ++ {"crlf", OPT_CRLF, '-', "Convert LF from terminal into CRLF"}, ++ {"debug", OPT_DEBUG, '-', "Print more output"}, ++ {"msg", OPT_MSG, '-', "Show protocol messages"}, ++ {"msgfile", OPT_MSGFILE, '>', ++ "File to send output of -msg or -trace, instead of stdout"}, ++ {"state", OPT_STATE, '-', "Print the SSL states"}, ++ {"CAfile", OPT_CAFILE, '<', "PEM format file of CA's"}, ++ {"CApath", OPT_CAPATH, '/', "PEM format directory of CA's"}, ++ {"no-CAfile", OPT_NOCAFILE, '-', ++ "Do not load the default certificates file"}, ++ {"no-CApath", OPT_NOCAPATH, '-', ++ "Do not load certificates from the default certificates directory"}, ++ {"nocert", OPT_NOCERT, '-', "Don't use any certificates (Anon-DH)"}, ++ {"quiet", OPT_QUIET, '-', "No server output"}, ++ {"no_resume_ephemeral", OPT_NO_RESUME_EPHEMERAL, '-', ++ "Disable caching and tickets if ephemeral (EC)DH is used"}, ++ {"www", OPT_WWW, '-', "Respond to a 'GET /' with a status page"}, ++ {"WWW", OPT_UPPER_WWW, '-', "Respond to a 'GET with the file ./path"}, ++ {"servername", OPT_SERVERNAME, 's', ++ "Servername for HostName TLS extension"}, ++ {"servername_fatal", OPT_SERVERNAME_FATAL, '-', ++ "mismatch send fatal alert (default warning alert)"}, ++ {"cert2", OPT_CERT2, '<', ++ "Certificate file to use for servername; default is" TEST_CERT2}, ++ {"key2", OPT_KEY2, '<', ++ "-Private Key file to use for servername if not in -cert2"}, ++ {"tlsextdebug", OPT_TLSEXTDEBUG, '-', ++ "Hex dump of all TLS extensions received"}, ++ {"HTTP", OPT_HTTP, '-', "Like -WWW but ./path includes HTTP headers"}, ++ {"id_prefix", OPT_ID_PREFIX, 's', ++ "Generate SSL/TLS session IDs prefixed by arg"}, ++ {"rand", OPT_RAND, 's', ++ "Load the file(s) into the random number generator"}, ++ {"keymatexport", OPT_KEYMATEXPORT, 's', ++ "Export keying material using label"}, ++ {"keymatexportlen", OPT_KEYMATEXPORTLEN, 'p', ++ "Export len bytes of keying material (default 20)"}, ++ {"CRL", OPT_CRL, '<', "CRL file to use"}, ++ {"crl_download", OPT_CRL_DOWNLOAD, '-', ++ "Download CRL from distribution points"}, ++ {"cert_chain", OPT_CERT_CHAIN, '<', ++ "certificate chain file in PEM format"}, ++ {"dcert_chain", OPT_DCERT_CHAIN, '<', ++ "second certificate chain file in PEM format"}, ++ {"chainCApath", OPT_CHAINCAPATH, '/', ++ "use dir as certificate store path to build CA certificate chain"}, ++ {"verifyCApath", OPT_VERIFYCAPATH, '/', ++ "use dir as certificate store path to verify CA certificate"}, ++ {"no_cache", OPT_NO_CACHE, '-', "Disable session cache"}, ++ {"ext_cache", OPT_EXT_CACHE, '-', ++ "Disable internal cache, setup and use external cache"}, ++ {"CRLform", OPT_CRLFORM, 'F', "CRL format (PEM or DER) PEM is default"}, ++ {"verify_return_error", OPT_VERIFY_RET_ERROR, '-', ++ "Close connection on verification error"}, ++ {"verify_quiet", OPT_VERIFY_QUIET, '-', ++ "No verify output except verify errors"}, ++ {"build_chain", OPT_BUILD_CHAIN, '-', "Build certificate chain"}, ++ {"chainCAfile", OPT_CHAINCAFILE, '<', ++ "CA file for certificate chain (PEM format)"}, ++ {"verifyCAfile", OPT_VERIFYCAFILE, '<', ++ "CA file for certificate verification (PEM format)"}, ++ {"ign_eof", OPT_IGN_EOF, '-', "ignore input eof (default when -quiet)"}, ++ {"no_ign_eof", OPT_NO_IGN_EOF, '-', "Do not ignore input eof"}, ++#ifndef OPENSSL_NO_OCSP ++ {"status", OPT_STATUS, '-', "Request certificate status from server"}, ++ {"status_verbose", OPT_STATUS_VERBOSE, '-', ++ "Print more output in certificate status callback"}, ++ {"status_timeout", OPT_STATUS_TIMEOUT, 'n', ++ "Status request responder timeout"}, ++ {"status_url", OPT_STATUS_URL, 's', "Status request fallback URL"}, ++#endif ++#ifndef OPENSSL_NO_SSL_TRACE ++ {"trace", OPT_TRACE, '-', "trace protocol messages"}, ++#endif ++ {"security_debug", OPT_SECURITY_DEBUG, '-', ++ "Print output from SSL/TLS security framework"}, ++ {"security_debug_verbose", OPT_SECURITY_DEBUG_VERBOSE, '-', ++ "Print more output from SSL/TLS security framework"}, ++ {"brief", OPT_BRIEF, '-', ++ "Restrict output to brief summary of connection parameters"}, ++ {"rev", OPT_REV, '-', ++ "act as a simple test server which just sends back with the received text reversed"}, ++ {"async", OPT_ASYNC, '-', "Operate in asynchronous mode"}, ++ {"ssl_config", OPT_SSL_CONFIG, 's', ++ "Configure SSL_CTX using the configuration 'val'"}, ++ {"split_send_frag", OPT_SPLIT_SEND_FRAG, 'n', ++ "Size used to split data for encrypt pipelines"}, ++ {"max_pipelines", OPT_MAX_PIPELINES, 'n', ++ "Maximum number of encrypt/decrypt pipelines to be used"}, ++ {"read_buf", OPT_READ_BUF, 'n', ++ "Default read buffer size to be used for connections"}, ++ OPT_S_OPTIONS, ++ OPT_V_OPTIONS, ++ OPT_X_OPTIONS, ++ {"nbio", OPT_NBIO, '-', "Use non-blocking IO"}, ++#ifndef OPENSSL_NO_PSK ++ {"psk_hint", OPT_PSK_HINT, 's', "PSK identity hint to use"}, ++ {"psk", OPT_PSK, 's', "PSK in hex (without 0x)"}, ++#endif ++#ifndef OPENSSL_NO_SRP ++ {"srpvfile", OPT_SRPVFILE, '<', "The verifier file for SRP"}, ++ {"srpuserseed", OPT_SRPUSERSEED, 's', ++ "A seed string for a default user salt"}, ++#endif ++#ifndef OPENSSL_NO_SSL3 ++ {"ssl3", OPT_SSL3, '-', "Just talk SSLv3"}, ++#endif ++#ifndef OPENSSL_NO_TLS1 ++ {"tls1", OPT_TLS1, '-', "Just talk TLSv1"}, ++#endif ++#ifndef OPENSSL_NO_TLS1_1 ++ {"tls1_1", OPT_TLS1_1, '-', "Just talk TLSv1.1"}, ++#endif ++#ifndef OPENSSL_NO_TLS1_2 ++ {"tls1_2", OPT_TLS1_2, '-', "just talk TLSv1.2"}, ++#endif ++#ifndef OPENSSL_NO_DTLS ++ {"dtls", OPT_DTLS, '-', "Use any DTLS version"}, ++ {"timeout", OPT_TIMEOUT, '-', "Enable timeouts"}, ++ {"mtu", OPT_MTU, 'p', "Set link layer MTU"}, ++ {"listen", OPT_LISTEN, '-', ++ "Listen for a DTLS ClientHello with a cookie and then connect"}, ++#endif ++#ifndef OPENSSL_NO_DTLS1 ++ {"dtls1", OPT_DTLS1, '-', "Just talk DTLSv1"}, ++#endif ++#ifndef OPENSSL_NO_DTLS1_2 ++ {"dtls1_2", OPT_DTLS1_2, '-', "Just talk DTLSv1.2"}, ++#endif ++#ifndef OPENSSL_NO_DH ++ {"no_dhe", OPT_NO_DHE, '-', "Disable ephemeral DH"}, ++#endif ++#ifndef OPENSSL_NO_NEXTPROTONEG ++ {"nextprotoneg", OPT_NEXTPROTONEG, 's', ++ "Set the advertised protocols for the NPN extension (comma-separated list)"}, ++#endif ++#ifndef OPENSSL_NO_SRTP ++ {"use_srtp", OPT_SRTP_PROFILES, 's', ++ "Offer SRTP key management with a colon-separated profile list"}, ++#endif ++ {"alpn", OPT_ALPN, 's', ++ "Set the advertised protocols for the ALPN extension (comma-separated list)"}, ++#ifndef OPENSSL_NO_ENGINE ++ {"engine", OPT_ENGINE, 's', "Use engine, possibly a hardware device"}, ++#endif ++ {NULL, OPT_EOF, 0, NULL} ++}; ++ ++#define IS_PROT_FLAG(o) \ ++ (o == OPT_SSL3 || o == OPT_TLS1 || o == OPT_TLS1_1 || o == OPT_TLS1_2 \ ++ || o == OPT_DTLS || o == OPT_DTLS1 || o == OPT_DTLS1_2) ++ ++int s_server_main(int argc, char *argv[]) ++{ ++ ENGINE *engine = NULL; ++ EVP_PKEY *s_key = NULL, *s_dkey = NULL; ++ SSL_CONF_CTX *cctx = NULL; ++ const SSL_METHOD *meth = TLS_server_method(); ++ SSL_EXCERT *exc = NULL; ++ STACK_OF(OPENSSL_STRING) *ssl_args = NULL; ++ STACK_OF(X509) *s_chain = NULL, *s_dchain = NULL; ++ STACK_OF(X509_CRL) *crls = NULL; ++ X509 *s_cert = NULL, *s_dcert = NULL; ++ X509_VERIFY_PARAM *vpm = NULL; ++ const char *CApath = NULL, *CAfile = NULL, *chCApath = NULL, *chCAfile = NULL; ++ char *dpassarg = NULL, *dpass = NULL, *inrand = NULL; ++ char *passarg = NULL, *pass = NULL, *vfyCApath = NULL, *vfyCAfile = NULL; ++ char *crl_file = NULL, *prog; ++#ifdef AF_UNIX ++ int unlink_unix_path = 0; ++#endif ++ do_server_cb server_cb; ++ int vpmtouched = 0, build_chain = 0, no_cache = 0, ext_cache = 0; ++#ifndef OPENSSL_NO_DH ++ char *dhfile = NULL; ++ int no_dhe = 0; ++#endif ++ int nocert = 0, ret = 1; ++ int noCApath = 0, noCAfile = 0; ++ int s_cert_format = FORMAT_PEM, s_key_format = FORMAT_PEM; ++ int s_dcert_format = FORMAT_PEM, s_dkey_format = FORMAT_PEM; ++ int rev = 0, naccept = -1, sdebug = 0; ++ int socket_family = AF_UNSPEC, socket_type = SOCK_STREAM; ++ int state = 0, crl_format = FORMAT_PEM, crl_download = 0; ++ char *host = NULL; ++ char *port = BUF_strdup(PORT); ++ unsigned char *context = NULL; ++ OPTION_CHOICE o; ++ EVP_PKEY *s_key2 = NULL; ++ X509 *s_cert2 = NULL; ++ tlsextctx tlsextcbp = { NULL, NULL, SSL_TLSEXT_ERR_ALERT_WARNING }; ++ const char *ssl_config = NULL; ++ int read_buf_len = 0; ++#ifndef OPENSSL_NO_NEXTPROTONEG ++ const char *next_proto_neg_in = NULL; ++ tlsextnextprotoctx next_proto = { NULL, 0 }; ++#endif ++ const char *alpn_in = NULL; ++ tlsextalpnctx alpn_ctx = { NULL, 0 }; ++#ifndef OPENSSL_NO_PSK ++ /* by default do not send a PSK identity hint */ ++ static char *psk_identity_hint = NULL; ++ char *p; ++#endif ++#ifndef OPENSSL_NO_SRP ++ char *srpuserseed = NULL; ++ char *srp_verifier_file = NULL; ++#endif ++ int min_version = 0, max_version = 0, prot_opt = 0, no_prot_opt = 0; ++ int s_server_verify = SSL_VERIFY_NONE; ++ int s_server_session_id_context = 1; /* anything will do */ ++ const char *s_cert_file = TEST_CERT, *s_key_file = NULL, *s_chain_file = NULL; ++ const char *s_cert_file2 = TEST_CERT2, *s_key_file2 = NULL; ++ char *s_dcert_file = NULL, *s_dkey_file = NULL, *s_dchain_file = NULL; ++#ifndef OPENSSL_NO_OCSP ++ int s_tlsextstatus = 0; ++#endif ++ int no_resume_ephemeral = 0; ++ unsigned int split_send_fragment = 0, max_pipelines = 0; ++ const char *s_serverinfo_file = NULL; ++ ++ /* Init of few remaining global variables */ ++ local_argc = argc; ++ local_argv = argv; ++ ++ ctx = ctx2 = NULL; ++ s_nbio = s_nbio_test = 0; ++ www = 0; ++ bio_s_out = NULL; ++ s_debug = 0; ++ s_msg = 0; ++ s_quiet = 0; ++ s_brief = 0; ++ async = 0; ++ ++ cctx = SSL_CONF_CTX_new(); ++ vpm = X509_VERIFY_PARAM_new(); ++ if (cctx == NULL || vpm == NULL) ++ goto end; ++ SSL_CONF_CTX_set_flags(cctx, ++ SSL_CONF_FLAG_SERVER | SSL_CONF_FLAG_CMDLINE); ++ ++ prog = opt_init(argc, argv, s_server_options); ++ while ((o = opt_next()) != OPT_EOF) { ++ if (IS_PROT_FLAG(o) && ++prot_opt > 1) { ++ BIO_printf(bio_err, "Cannot supply multiple protocol flags\n"); ++ goto end; ++ } ++ if (IS_NO_PROT_FLAG(o)) ++ no_prot_opt++; ++ if (prot_opt == 1 && no_prot_opt) { ++ BIO_printf(bio_err, ++ "Cannot supply both a protocol flag and '-no_'\n"); ++ goto end; ++ } ++ switch (o) { ++ case OPT_EOF: ++ case OPT_ERR: ++ opthelp: ++ BIO_printf(bio_err, "%s: Use -help for summary.\n", prog); ++ goto end; ++ case OPT_HELP: ++ opt_help(s_server_options); ++ ret = 0; ++ goto end; ++ ++ case OPT_4: ++#ifdef AF_UNIX ++ if (socket_family == AF_UNIX) { ++ OPENSSL_free(host); host = NULL; ++ OPENSSL_free(port); port = NULL; ++ } ++#endif ++ socket_family = AF_INET; ++ break; ++ case OPT_6: ++ if (1) { ++#ifdef AF_INET6 ++#ifdef AF_UNIX ++ if (socket_family == AF_UNIX) { ++ OPENSSL_free(host); host = NULL; ++ OPENSSL_free(port); port = NULL; ++ } ++#endif ++ socket_family = AF_INET6; ++ } else { ++#endif ++ BIO_printf(bio_err, "%s: IPv6 domain sockets unsupported\n", prog); ++ goto end; ++ } ++ break; ++ case OPT_PORT: ++#ifdef AF_UNIX ++ if (socket_family == AF_UNIX) { ++ socket_family = AF_UNSPEC; ++ } ++#endif ++ OPENSSL_free(port); port = NULL; ++ OPENSSL_free(host); host = NULL; ++ if (BIO_parse_hostserv(opt_arg(), NULL, &port, BIO_PARSE_PRIO_SERV) < 1) { ++ BIO_printf(bio_err, ++ "%s: -port argument malformed or ambiguous\n", ++ port); ++ goto end; ++ } ++ break; ++ case OPT_ACCEPT: ++#ifdef AF_UNIX ++ if (socket_family == AF_UNIX) { ++ socket_family = AF_UNSPEC; ++ } ++#endif ++ OPENSSL_free(port); port = NULL; ++ OPENSSL_free(host); host = NULL; ++ if (BIO_parse_hostserv(opt_arg(), &host, &port, BIO_PARSE_PRIO_SERV) < 1) { ++ BIO_printf(bio_err, ++ "%s: -accept argument malformed or ambiguous\n", ++ port); ++ goto end; ++ } ++ break; ++#ifdef AF_UNIX ++ case OPT_UNIX: ++ socket_family = AF_UNIX; ++ OPENSSL_free(host); host = BUF_strdup(opt_arg()); ++ OPENSSL_free(port); port = NULL; ++ break; ++ case OPT_UNLINK: ++ unlink_unix_path = 1; ++ break; ++#endif ++ case OPT_NACCEPT: ++ naccept = atol(opt_arg()); ++ break; ++ case OPT_VERIFY: ++ s_server_verify = SSL_VERIFY_PEER | SSL_VERIFY_CLIENT_ONCE; ++ verify_args.depth = atoi(opt_arg()); ++ if (!s_quiet) ++ BIO_printf(bio_err, "verify depth is %d\n", verify_args.depth); ++ break; ++ case OPT_UPPER_V_VERIFY: ++ s_server_verify = ++ SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT | ++ SSL_VERIFY_CLIENT_ONCE; ++ verify_args.depth = atoi(opt_arg()); ++ if (!s_quiet) ++ BIO_printf(bio_err, ++ "verify depth is %d, must return a certificate\n", ++ verify_args.depth); ++ break; ++ case OPT_CONTEXT: ++ context = (unsigned char *)opt_arg(); ++ break; ++ case OPT_CERT: ++ s_cert_file = opt_arg(); ++ break; ++ case OPT_CRL: ++ crl_file = opt_arg(); ++ break; ++ case OPT_CRL_DOWNLOAD: ++ crl_download = 1; ++ break; ++ case OPT_SERVERINFO: ++ s_serverinfo_file = opt_arg(); ++ break; ++ case OPT_CERTFORM: ++ if (!opt_format(opt_arg(), OPT_FMT_PEMDER, &s_cert_format)) ++ goto opthelp; ++ break; ++ case OPT_KEY: ++ s_key_file = opt_arg(); ++ break; ++ case OPT_KEYFORM: ++ if (!opt_format(opt_arg(), OPT_FMT_ANY, &s_key_format)) ++ goto opthelp; ++ break; ++ case OPT_PASS: ++ passarg = opt_arg(); ++ break; ++ case OPT_CERT_CHAIN: ++ s_chain_file = opt_arg(); ++ break; ++ case OPT_DHPARAM: ++#ifndef OPENSSL_NO_DH ++ dhfile = opt_arg(); ++#endif ++ break; ++ case OPT_DCERTFORM: ++ if (!opt_format(opt_arg(), OPT_FMT_PEMDER, &s_dcert_format)) ++ goto opthelp; ++ break; ++ case OPT_DCERT: ++ s_dcert_file = opt_arg(); ++ break; ++ case OPT_DKEYFORM: ++ if (!opt_format(opt_arg(), OPT_FMT_PEMDER, &s_dkey_format)) ++ goto opthelp; ++ break; ++ case OPT_DPASS: ++ dpassarg = opt_arg(); ++ break; ++ case OPT_DKEY: ++ s_dkey_file = opt_arg(); ++ break; ++ case OPT_DCERT_CHAIN: ++ s_dchain_file = opt_arg(); ++ break; ++ case OPT_NOCERT: ++ nocert = 1; ++ break; ++ case OPT_CAPATH: ++ CApath = opt_arg(); ++ break; ++ case OPT_NOCAPATH: ++ noCApath = 1; ++ break; ++ case OPT_CHAINCAPATH: ++ chCApath = opt_arg(); ++ break; ++ case OPT_VERIFYCAPATH: ++ vfyCApath = opt_arg(); ++ break; ++ case OPT_NO_CACHE: ++ no_cache = 1; ++ break; ++ case OPT_EXT_CACHE: ++ ext_cache = 1; ++ break; ++ case OPT_CRLFORM: ++ if (!opt_format(opt_arg(), OPT_FMT_PEMDER, &crl_format)) ++ goto opthelp; ++ break; ++ case OPT_S_CASES: ++ if (ssl_args == NULL) ++ ssl_args = sk_OPENSSL_STRING_new_null(); ++ if (ssl_args == NULL ++ || !sk_OPENSSL_STRING_push(ssl_args, opt_flag()) ++ || !sk_OPENSSL_STRING_push(ssl_args, opt_arg())) { ++ BIO_printf(bio_err, "%s: Memory allocation failure\n", prog); ++ goto end; ++ } ++ break; ++ case OPT_V_CASES: ++ if (!opt_verify(o, vpm)) ++ goto end; ++ vpmtouched++; ++ break; ++ case OPT_X_CASES: ++ if (!args_excert(o, &exc)) ++ goto end; ++ break; ++ case OPT_VERIFY_RET_ERROR: ++ verify_args.return_error = 1; ++ break; ++ case OPT_VERIFY_QUIET: ++ verify_args.quiet = 1; ++ break; ++ case OPT_BUILD_CHAIN: ++ build_chain = 1; ++ break; ++ case OPT_CAFILE: ++ CAfile = opt_arg(); ++ break; ++ case OPT_NOCAFILE: ++ noCAfile = 1; ++ break; ++ case OPT_CHAINCAFILE: ++ chCAfile = opt_arg(); ++ break; ++ case OPT_VERIFYCAFILE: ++ vfyCAfile = opt_arg(); ++ break; ++ case OPT_NBIO: ++ s_nbio = 1; ++ break; ++ case OPT_NBIO_TEST: ++ s_nbio = s_nbio_test = 1; ++ break; ++ case OPT_IGN_EOF: ++ s_ign_eof = 1; ++ break; ++ case OPT_NO_IGN_EOF: ++ s_ign_eof = 0; ++ break; ++ case OPT_DEBUG: ++ s_debug = 1; ++ break; ++ case OPT_TLSEXTDEBUG: ++ s_tlsextdebug = 1; ++ break; ++ case OPT_STATUS: ++#ifndef OPENSSL_NO_OCSP ++ s_tlsextstatus = 1; ++#endif ++ break; ++ case OPT_STATUS_VERBOSE: ++#ifndef OPENSSL_NO_OCSP ++ s_tlsextstatus = tlscstatp.verbose = 1; ++#endif ++ break; ++ case OPT_STATUS_TIMEOUT: ++#ifndef OPENSSL_NO_OCSP ++ s_tlsextstatus = 1; ++ tlscstatp.timeout = atoi(opt_arg()); ++#endif ++ break; ++ case OPT_STATUS_URL: ++#ifndef OPENSSL_NO_OCSP ++ s_tlsextstatus = 1; ++ if (!OCSP_parse_url(opt_arg(), ++ &tlscstatp.host, ++ &tlscstatp.port, ++ &tlscstatp.path, &tlscstatp.use_ssl)) { ++ BIO_printf(bio_err, "Error parsing URL\n"); ++ goto end; ++ } ++#endif ++ break; ++ case OPT_MSG: ++ s_msg = 1; ++ break; ++ case OPT_MSGFILE: ++ bio_s_msg = BIO_new_file(opt_arg(), "w"); ++ break; ++ case OPT_TRACE: ++#ifndef OPENSSL_NO_SSL_TRACE ++ s_msg = 2; ++#endif ++ break; ++ case OPT_SECURITY_DEBUG: ++ sdebug = 1; ++ break; ++ case OPT_SECURITY_DEBUG_VERBOSE: ++ sdebug = 2; ++ break; ++ case OPT_STATE: ++ state = 1; ++ break; ++ case OPT_CRLF: ++ s_crlf = 1; ++ break; ++ case OPT_QUIET: ++ s_quiet = 1; ++ break; ++ case OPT_BRIEF: ++ s_quiet = s_brief = verify_args.quiet = 1; ++ break; ++ case OPT_NO_DHE: ++#ifndef OPENSSL_NO_DH ++ no_dhe = 1; ++#endif ++ break; ++ case OPT_NO_RESUME_EPHEMERAL: ++ no_resume_ephemeral = 1; ++ break; ++ case OPT_PSK_HINT: ++#ifndef OPENSSL_NO_PSK ++ psk_identity_hint = opt_arg(); ++#endif ++ break; ++ case OPT_PSK: ++#ifndef OPENSSL_NO_PSK ++ for (p = psk_key = opt_arg(); *p; p++) { ++ if (isxdigit(_UC(*p))) ++ continue; ++ BIO_printf(bio_err, "Not a hex number '%s'\n", *argv); ++ goto end; ++ } ++#endif ++ break; ++ case OPT_SRPVFILE: ++#ifndef OPENSSL_NO_SRP ++ srp_verifier_file = opt_arg(); ++ if (min_version < TLS1_VERSION) ++ min_version = TLS1_VERSION; ++#endif ++ break; ++ case OPT_SRPUSERSEED: ++#ifndef OPENSSL_NO_SRP ++ srpuserseed = opt_arg(); ++ if (min_version < TLS1_VERSION) ++ min_version = TLS1_VERSION; ++#endif ++ break; ++ case OPT_REV: ++ rev = 1; ++ break; ++ case OPT_WWW: ++ www = 1; ++ break; ++ case OPT_UPPER_WWW: ++ www = 2; ++ break; ++ case OPT_HTTP: ++ www = 3; ++ break; ++ case OPT_SSL_CONFIG: ++ ssl_config = opt_arg(); ++ break; ++ case OPT_SSL3: ++ min_version = SSL3_VERSION; ++ max_version = SSL3_VERSION; ++ break; ++ case OPT_TLS1_2: ++ min_version = TLS1_2_VERSION; ++ max_version = TLS1_2_VERSION; ++ break; ++ case OPT_TLS1_1: ++ min_version = TLS1_1_VERSION; ++ max_version = TLS1_1_VERSION; ++ break; ++ case OPT_TLS1: ++ min_version = TLS1_VERSION; ++ max_version = TLS1_VERSION; ++ break; ++ case OPT_DTLS: ++#ifndef OPENSSL_NO_DTLS ++ meth = DTLS_server_method(); ++ socket_type = SOCK_DGRAM; ++#endif ++ break; ++ case OPT_DTLS1: ++#ifndef OPENSSL_NO_DTLS ++ meth = DTLS_server_method(); ++ min_version = DTLS1_VERSION; ++ max_version = DTLS1_VERSION; ++ socket_type = SOCK_DGRAM; ++#endif ++ break; ++ case OPT_DTLS1_2: ++#ifndef OPENSSL_NO_DTLS ++ meth = DTLS_server_method(); ++ min_version = DTLS1_2_VERSION; ++ max_version = DTLS1_2_VERSION; ++ socket_type = SOCK_DGRAM; ++#endif ++ break; ++ case OPT_TIMEOUT: ++#ifndef OPENSSL_NO_DTLS ++ enable_timeouts = 1; ++#endif ++ break; ++ case OPT_MTU: ++#ifndef OPENSSL_NO_DTLS ++ socket_mtu = atol(opt_arg()); ++#endif ++ break; ++ case OPT_LISTEN: ++#ifndef OPENSSL_NO_DTLS ++ dtlslisten = 1; ++#endif ++ break; ++ case OPT_ID_PREFIX: ++ session_id_prefix = opt_arg(); ++ break; ++ case OPT_ENGINE: ++ engine = setup_engine(opt_arg(), 1); ++ break; ++ case OPT_RAND: ++ inrand = opt_arg(); ++ break; ++ case OPT_SERVERNAME: ++ tlsextcbp.servername = opt_arg(); ++ break; ++ case OPT_SERVERNAME_FATAL: ++ tlsextcbp.extension_error = SSL_TLSEXT_ERR_ALERT_FATAL; ++ break; ++ case OPT_CERT2: ++ s_cert_file2 = opt_arg(); ++ break; ++ case OPT_KEY2: ++ s_key_file2 = opt_arg(); ++ break; ++ case OPT_NEXTPROTONEG: ++# ifndef OPENSSL_NO_NEXTPROTONEG ++ next_proto_neg_in = opt_arg(); ++#endif ++ break; ++ case OPT_ALPN: ++ alpn_in = opt_arg(); ++ break; ++ case OPT_SRTP_PROFILES: ++#ifndef OPENSSL_NO_SRTP ++ srtp_profiles = opt_arg(); ++#endif ++ break; ++ case OPT_KEYMATEXPORT: ++ keymatexportlabel = opt_arg(); ++ break; ++ case OPT_KEYMATEXPORTLEN: ++ keymatexportlen = atoi(opt_arg()); ++ break; ++ case OPT_ASYNC: ++ async = 1; ++ break; ++ case OPT_SPLIT_SEND_FRAG: ++ split_send_fragment = atoi(opt_arg()); ++ if (split_send_fragment == 0) { ++ /* ++ * Not allowed - set to a deliberately bad value so we get an ++ * error message below ++ */ ++ split_send_fragment = SSL3_RT_MAX_PLAIN_LENGTH + 1; ++ } ++ break; ++ case OPT_MAX_PIPELINES: ++ max_pipelines = atoi(opt_arg()); ++ break; ++ case OPT_READ_BUF: ++ read_buf_len = atoi(opt_arg()); ++ break; ++ ++ } ++ } ++ argc = opt_num_rest(); ++ argv = opt_rest(); ++ ++#ifndef OPENSSL_NO_DTLS ++ if (www && socket_type == SOCK_DGRAM) { ++ BIO_printf(bio_err, "Can't use -HTTP, -www or -WWW with DTLS\n"); ++ goto end; ++ } ++ ++ if (dtlslisten && socket_type != SOCK_DGRAM) { ++ BIO_printf(bio_err, "Can only use -listen with DTLS\n"); ++ goto end; ++ } ++#endif ++ ++#ifdef AF_UNIX ++ if (socket_family == AF_UNIX && socket_type != SOCK_STREAM) { ++ BIO_printf(bio_err, ++ "Can't use unix sockets and datagrams together\n"); ++ goto end; ++ } ++#endif ++ ++ if (split_send_fragment > SSL3_RT_MAX_PLAIN_LENGTH) { ++ BIO_printf(bio_err, "Bad split send fragment size\n"); ++ goto end; ++ } ++ ++ if (max_pipelines > SSL_MAX_PIPELINES) { ++ BIO_printf(bio_err, "Bad max pipelines value\n"); ++ goto end; ++ } ++ ++ if (!app_passwd(passarg, dpassarg, &pass, &dpass)) { ++ BIO_printf(bio_err, "Error getting password\n"); ++ goto end; ++ } ++ ++ if (s_key_file == NULL) ++ s_key_file = s_cert_file; ++ ++ if (s_key_file2 == NULL) ++ s_key_file2 = s_cert_file2; ++ ++ if (!load_excert(&exc)) ++ goto end; ++ ++ if (nocert == 0) { ++ s_key = load_key(s_key_file, s_key_format, 0, pass, engine, ++ "server certificate private key file"); ++ if (!s_key) { ++ ERR_print_errors(bio_err); ++ goto end; ++ } ++ ++ s_cert = load_cert(s_cert_file, s_cert_format, ++ "server certificate file"); ++ ++ if (!s_cert) { ++ ERR_print_errors(bio_err); ++ goto end; ++ } ++ if (s_chain_file) { ++ if (!load_certs(s_chain_file, &s_chain, FORMAT_PEM, NULL, ++ "server certificate chain")) ++ goto end; ++ } ++ ++ if (tlsextcbp.servername) { ++ s_key2 = load_key(s_key_file2, s_key_format, 0, pass, engine, ++ "second server certificate private key file"); ++ if (!s_key2) { ++ ERR_print_errors(bio_err); ++ goto end; ++ } ++ ++ s_cert2 = load_cert(s_cert_file2, s_cert_format, ++ "second server certificate file"); ++ ++ if (!s_cert2) { ++ ERR_print_errors(bio_err); ++ goto end; ++ } ++ } ++ } ++#if !defined(OPENSSL_NO_NEXTPROTONEG) ++ if (next_proto_neg_in) { ++ size_t len; ++ next_proto.data = next_protos_parse(&len, next_proto_neg_in); ++ if (next_proto.data == NULL) ++ goto end; ++ next_proto.len = len; ++ } else { ++ next_proto.data = NULL; ++ } ++#endif ++ alpn_ctx.data = NULL; ++ if (alpn_in) { ++ size_t len; ++ alpn_ctx.data = next_protos_parse(&len, alpn_in); ++ if (alpn_ctx.data == NULL) ++ goto end; ++ alpn_ctx.len = len; ++ } ++ ++ if (crl_file) { ++ X509_CRL *crl; ++ crl = load_crl(crl_file, crl_format); ++ if (!crl) { ++ BIO_puts(bio_err, "Error loading CRL\n"); ++ ERR_print_errors(bio_err); ++ goto end; ++ } ++ crls = sk_X509_CRL_new_null(); ++ if (!crls || !sk_X509_CRL_push(crls, crl)) { ++ BIO_puts(bio_err, "Error adding CRL\n"); ++ ERR_print_errors(bio_err); ++ X509_CRL_free(crl); ++ goto end; ++ } ++ } ++ ++ if (s_dcert_file) { ++ ++ if (s_dkey_file == NULL) ++ s_dkey_file = s_dcert_file; ++ ++ s_dkey = load_key(s_dkey_file, s_dkey_format, ++ 0, dpass, engine, "second certificate private key file"); ++ if (!s_dkey) { ++ ERR_print_errors(bio_err); ++ goto end; ++ } ++ ++ s_dcert = load_cert(s_dcert_file, s_dcert_format, ++ "second server certificate file"); ++ ++ if (!s_dcert) { ++ ERR_print_errors(bio_err); ++ goto end; ++ } ++ if (s_dchain_file) { ++ if (!load_certs(s_dchain_file, &s_dchain, FORMAT_PEM, NULL, ++ "second server certificate chain")) ++ goto end; ++ } ++ ++ } ++ ++ if (!app_RAND_load_file(NULL, 1) && inrand == NULL ++ && !RAND_status()) { ++ BIO_printf(bio_err, ++ "warning, not much extra random data, consider using the -rand option\n"); ++ } ++ if (inrand != NULL) ++ BIO_printf(bio_err, "%ld semi-random bytes loaded\n", ++ app_RAND_load_files(inrand)); ++ ++ if (bio_s_out == NULL) { ++ if (s_quiet && !s_debug) { ++ bio_s_out = BIO_new(BIO_s_null()); ++ if (s_msg && !bio_s_msg) ++ bio_s_msg = dup_bio_out(FORMAT_TEXT); ++ } else { ++ if (bio_s_out == NULL) ++ bio_s_out = dup_bio_out(FORMAT_TEXT); ++ } ++ } ++#if !defined(OPENSSL_NO_RSA) || !defined(OPENSSL_NO_DSA) || !defined(OPENSSL_NO_EC) ++ if (nocert) ++#endif ++ { ++ s_cert_file = NULL; ++ s_key_file = NULL; ++ s_dcert_file = NULL; ++ s_dkey_file = NULL; ++ s_cert_file2 = NULL; ++ s_key_file2 = NULL; ++ } ++ ++ ctx = SSL_CTX_new(meth); ++ if (ctx == NULL) { ++ ERR_print_errors(bio_err); ++ goto end; ++ } ++ if (sdebug) ++ ssl_ctx_security_debug(ctx, sdebug); ++ if (ssl_config) { ++ if (SSL_CTX_config(ctx, ssl_config) == 0) { ++ BIO_printf(bio_err, "Error using configuration \"%s\"\n", ++ ssl_config); ++ ERR_print_errors(bio_err); ++ goto end; ++ } ++ } ++ if (SSL_CTX_set_min_proto_version(ctx, min_version) == 0) ++ goto end; ++ if (SSL_CTX_set_max_proto_version(ctx, max_version) == 0) ++ goto end; ++ ++ if (session_id_prefix) { ++ if (strlen(session_id_prefix) >= 32) ++ BIO_printf(bio_err, ++ "warning: id_prefix is too long, only one new session will be possible\n"); ++ if (!SSL_CTX_set_generate_session_id(ctx, generate_session_id)) { ++ BIO_printf(bio_err, "error setting 'id_prefix'\n"); ++ ERR_print_errors(bio_err); ++ goto end; ++ } ++ BIO_printf(bio_err, "id_prefix '%s' set.\n", session_id_prefix); ++ } ++ SSL_CTX_set_quiet_shutdown(ctx, 1); ++ if (exc) ++ ssl_ctx_set_excert(ctx, exc); ++ ++ if (state) ++ SSL_CTX_set_info_callback(ctx, apps_ssl_info_callback); ++ if (no_cache) ++ SSL_CTX_set_session_cache_mode(ctx, SSL_SESS_CACHE_OFF); ++ else if (ext_cache) ++ init_session_cache_ctx(ctx); ++ else ++ SSL_CTX_sess_set_cache_size(ctx, 128); ++ ++ if (async) { ++ SSL_CTX_set_mode(ctx, SSL_MODE_ASYNC); ++ } ++ if (split_send_fragment > 0) { ++ SSL_CTX_set_split_send_fragment(ctx, split_send_fragment); ++ } ++ if (max_pipelines > 0) { ++ SSL_CTX_set_max_pipelines(ctx, max_pipelines); ++ } ++ ++ if (read_buf_len > 0) { ++ SSL_CTX_set_default_read_buffer_len(ctx, read_buf_len); ++ } ++#ifndef OPENSSL_NO_SRTP ++ if (srtp_profiles != NULL) { ++ /* Returns 0 on success! */ ++ if (SSL_CTX_set_tlsext_use_srtp(ctx, srtp_profiles) != 0) { ++ BIO_printf(bio_err, "Error setting SRTP profile\n"); ++ ERR_print_errors(bio_err); ++ goto end; ++ } ++ } ++#endif ++ ++ if (!ctx_set_verify_locations(ctx, CAfile, CApath, noCAfile, noCApath)) { ++ ERR_print_errors(bio_err); ++ goto end; ++ } ++ if (vpmtouched && !SSL_CTX_set1_param(ctx, vpm)) { ++ BIO_printf(bio_err, "Error setting verify params\n"); ++ ERR_print_errors(bio_err); ++ goto end; ++ } ++ ++ ssl_ctx_add_crls(ctx, crls, 0); ++ if (!config_ctx(cctx, ssl_args, ctx)) ++ goto end; ++ ++ if (!ssl_load_stores(ctx, vfyCApath, vfyCAfile, chCApath, chCAfile, ++ crls, crl_download)) { ++ BIO_printf(bio_err, "Error loading store locations\n"); ++ ERR_print_errors(bio_err); ++ goto end; ++ } ++ ++ if (s_cert2) { ++ ctx2 = SSL_CTX_new(meth); ++ if (ctx2 == NULL) { ++ ERR_print_errors(bio_err); ++ goto end; ++ } ++ } ++ ++ if (ctx2) { ++ BIO_printf(bio_s_out, "Setting secondary ctx parameters\n"); ++ ++ if (sdebug) ++ ssl_ctx_security_debug(ctx, sdebug); ++ ++ if (session_id_prefix) { ++ if (strlen(session_id_prefix) >= 32) ++ BIO_printf(bio_err, ++ "warning: id_prefix is too long, only one new session will be possible\n"); ++ if (!SSL_CTX_set_generate_session_id(ctx2, generate_session_id)) { ++ BIO_printf(bio_err, "error setting 'id_prefix'\n"); ++ ERR_print_errors(bio_err); ++ goto end; ++ } ++ BIO_printf(bio_err, "id_prefix '%s' set.\n", session_id_prefix); ++ } ++ SSL_CTX_set_quiet_shutdown(ctx2, 1); ++ if (exc) ++ ssl_ctx_set_excert(ctx2, exc); ++ ++ if (state) ++ SSL_CTX_set_info_callback(ctx2, apps_ssl_info_callback); ++ ++ if (no_cache) ++ SSL_CTX_set_session_cache_mode(ctx2, SSL_SESS_CACHE_OFF); ++ else if (ext_cache) ++ init_session_cache_ctx(ctx2); ++ else ++ SSL_CTX_sess_set_cache_size(ctx2, 128); ++ ++ if (async) ++ SSL_CTX_set_mode(ctx2, SSL_MODE_ASYNC); ++ ++ if (!ctx_set_verify_locations(ctx2, CAfile, CApath, noCAfile, ++ noCApath)) { ++ ERR_print_errors(bio_err); ++ goto end; ++ } ++ if (vpmtouched && !SSL_CTX_set1_param(ctx2, vpm)) { ++ BIO_printf(bio_err, "Error setting verify params\n"); ++ ERR_print_errors(bio_err); ++ goto end; ++ } ++ ++ ssl_ctx_add_crls(ctx2, crls, 0); ++ if (!config_ctx(cctx, ssl_args, ctx2)) ++ goto end; ++ } ++#ifndef OPENSSL_NO_NEXTPROTONEG ++ if (next_proto.data) ++ SSL_CTX_set_next_protos_advertised_cb(ctx, next_proto_cb, ++ &next_proto); ++#endif ++ if (alpn_ctx.data) ++ SSL_CTX_set_alpn_select_cb(ctx, alpn_cb, &alpn_ctx); ++ ++#ifndef OPENSSL_NO_DH ++ if (!no_dhe) { ++ DH *dh = NULL; ++ ++ if (dhfile) ++ dh = load_dh_param(dhfile); ++ else if (s_cert_file) ++ dh = load_dh_param(s_cert_file); ++ ++ if (dh != NULL) { ++ BIO_printf(bio_s_out, "Setting temp DH parameters\n"); ++ } else { ++ BIO_printf(bio_s_out, "Using default temp DH parameters\n"); ++ } ++ (void)BIO_flush(bio_s_out); ++ ++ if (dh == NULL) ++ SSL_CTX_set_dh_auto(ctx, 1); ++ else if (!SSL_CTX_set_tmp_dh(ctx, dh)) { ++ BIO_puts(bio_err, "Error setting temp DH parameters\n"); ++ ERR_print_errors(bio_err); ++ DH_free(dh); ++ goto end; ++ } ++ ++ if (ctx2) { ++ if (!dhfile) { ++ DH *dh2 = load_dh_param(s_cert_file2); ++ if (dh2 != NULL) { ++ BIO_printf(bio_s_out, "Setting temp DH parameters\n"); ++ (void)BIO_flush(bio_s_out); ++ ++ DH_free(dh); ++ dh = dh2; ++ } ++ } ++ if (dh == NULL) ++ SSL_CTX_set_dh_auto(ctx2, 1); ++ else if (!SSL_CTX_set_tmp_dh(ctx2, dh)) { ++ BIO_puts(bio_err, "Error setting temp DH parameters\n"); ++ ERR_print_errors(bio_err); ++ DH_free(dh); ++ goto end; ++ } ++ } ++ DH_free(dh); ++ } ++#endif ++ ++ if (!set_cert_key_stuff(ctx, s_cert, s_key, s_chain, build_chain)) ++ goto end; ++ ++ if (s_serverinfo_file != NULL ++ && !SSL_CTX_use_serverinfo_file(ctx, s_serverinfo_file)) { ++ ERR_print_errors(bio_err); ++ goto end; ++ } ++ ++ if (ctx2 && !set_cert_key_stuff(ctx2, s_cert2, s_key2, NULL, build_chain)) ++ goto end; ++ ++ if (s_dcert != NULL) { ++ if (!set_cert_key_stuff(ctx, s_dcert, s_dkey, s_dchain, build_chain)) ++ goto end; ++ } ++ ++ if (no_resume_ephemeral) { ++ SSL_CTX_set_not_resumable_session_callback(ctx, ++ not_resumable_sess_cb); ++ ++ if (ctx2) ++ SSL_CTX_set_not_resumable_session_callback(ctx2, ++ not_resumable_sess_cb); ++ } ++#ifndef OPENSSL_NO_PSK ++ if (psk_key != NULL) { ++ if (s_debug) ++ BIO_printf(bio_s_out, "PSK key given, setting server callback\n"); ++ SSL_CTX_set_psk_server_callback(ctx, psk_server_cb); ++ } ++ ++ if (!SSL_CTX_use_psk_identity_hint(ctx, psk_identity_hint)) { ++ BIO_printf(bio_err, "error setting PSK identity hint to context\n"); ++ ERR_print_errors(bio_err); ++ goto end; ++ } ++#endif ++ ++ SSL_CTX_set_verify(ctx, s_server_verify, verify_callback); ++ if (!SSL_CTX_set_session_id_context(ctx, ++ (void *)&s_server_session_id_context, ++ sizeof s_server_session_id_context)) { ++ BIO_printf(bio_err, "error setting session id context\n"); ++ ERR_print_errors(bio_err); ++ goto end; ++ } ++ ++ /* Set DTLS cookie generation and verification callbacks */ ++ SSL_CTX_set_cookie_generate_cb(ctx, generate_cookie_callback); ++ SSL_CTX_set_cookie_verify_cb(ctx, verify_cookie_callback); ++ ++ if (ctx2) { ++ SSL_CTX_set_verify(ctx2, s_server_verify, verify_callback); ++ if (!SSL_CTX_set_session_id_context(ctx2, ++ (void *)&s_server_session_id_context, ++ sizeof s_server_session_id_context)) { ++ BIO_printf(bio_err, "error setting session id context\n"); ++ ERR_print_errors(bio_err); ++ goto end; ++ } ++ tlsextcbp.biodebug = bio_s_out; ++ SSL_CTX_set_tlsext_servername_callback(ctx2, ssl_servername_cb); ++ SSL_CTX_set_tlsext_servername_arg(ctx2, &tlsextcbp); ++ SSL_CTX_set_tlsext_servername_callback(ctx, ssl_servername_cb); ++ SSL_CTX_set_tlsext_servername_arg(ctx, &tlsextcbp); ++ } ++ ++#ifndef OPENSSL_NO_SRP ++ if (srp_verifier_file != NULL) { ++ srp_callback_parm.vb = SRP_VBASE_new(srpuserseed); ++ srp_callback_parm.user = NULL; ++ srp_callback_parm.login = NULL; ++ if ((ret = ++ SRP_VBASE_init(srp_callback_parm.vb, ++ srp_verifier_file)) != SRP_NO_ERROR) { ++ BIO_printf(bio_err, ++ "Cannot initialize SRP verifier file \"%s\":ret=%d\n", ++ srp_verifier_file, ret); ++ goto end; ++ } ++ SSL_CTX_set_verify(ctx, SSL_VERIFY_NONE, verify_callback); ++ SSL_CTX_set_srp_cb_arg(ctx, &srp_callback_parm); ++ SSL_CTX_set_srp_username_callback(ctx, ssl_srp_server_param_cb); ++ } else ++#endif ++ if (CAfile != NULL) { ++ SSL_CTX_set_client_CA_list(ctx, SSL_load_client_CA_file(CAfile)); ++ ++ if (ctx2) ++ SSL_CTX_set_client_CA_list(ctx2, SSL_load_client_CA_file(CAfile)); ++ } ++#ifndef OPENSSL_NO_OCSP ++ if (s_tlsextstatus) { ++ SSL_CTX_set_tlsext_status_cb(ctx, cert_status_cb); ++ SSL_CTX_set_tlsext_status_arg(ctx, &tlscstatp); ++ if (ctx2) { ++ SSL_CTX_set_tlsext_status_cb(ctx2, cert_status_cb); ++ SSL_CTX_set_tlsext_status_arg(ctx2, &tlscstatp); ++ } ++ } ++#endif ++ ++ BIO_printf(bio_s_out, "ACCEPT\n"); ++ (void)BIO_flush(bio_s_out); ++ if (rev) ++ server_cb = rev_body; ++ else if (www) ++ server_cb = www_body; ++ else ++ server_cb = sv_body; ++#ifdef AF_UNIX ++ if (socket_family == AF_UNIX ++ && unlink_unix_path) ++ unlink(host); ++#endif ++ do_server(&accept_socket, host, port, socket_family, socket_type, ++ server_cb, context, naccept); ++ print_stats(bio_s_out, ctx); ++ ret = 0; ++ end: ++ SSL_CTX_free(ctx); ++ X509_free(s_cert); ++ sk_X509_CRL_pop_free(crls, X509_CRL_free); ++ X509_free(s_dcert); ++ EVP_PKEY_free(s_key); ++ EVP_PKEY_free(s_dkey); ++ sk_X509_pop_free(s_chain, X509_free); ++ sk_X509_pop_free(s_dchain, X509_free); ++ OPENSSL_free(pass); ++ OPENSSL_free(dpass); ++ OPENSSL_free(host); ++ OPENSSL_free(port); ++ X509_VERIFY_PARAM_free(vpm); ++ free_sessions(); ++ OPENSSL_free(tlscstatp.host); ++ OPENSSL_free(tlscstatp.port); ++ OPENSSL_free(tlscstatp.path); ++ SSL_CTX_free(ctx2); ++ X509_free(s_cert2); ++ EVP_PKEY_free(s_key2); ++#ifndef OPENSSL_NO_NEXTPROTONEG ++ OPENSSL_free(next_proto.data); ++#endif ++ OPENSSL_free(alpn_ctx.data); ++ ssl_excert_free(exc); ++ sk_OPENSSL_STRING_free(ssl_args); ++ SSL_CONF_CTX_free(cctx); ++ release_engine(engine); ++ BIO_free(bio_s_out); ++ bio_s_out = NULL; ++ BIO_free(bio_s_msg); ++ bio_s_msg = NULL; ++#ifdef CHARSET_EBCDIC ++ BIO_meth_free(methods_ebcdic); ++#endif ++ return (ret); ++} ++ ++static void print_stats(BIO *bio, SSL_CTX *ssl_ctx) ++{ ++ BIO_printf(bio, "%4ld items in the session cache\n", ++ SSL_CTX_sess_number(ssl_ctx)); ++ BIO_printf(bio, "%4ld client connects (SSL_connect())\n", ++ SSL_CTX_sess_connect(ssl_ctx)); ++ BIO_printf(bio, "%4ld client renegotiates (SSL_connect())\n", ++ SSL_CTX_sess_connect_renegotiate(ssl_ctx)); ++ BIO_printf(bio, "%4ld client connects that finished\n", ++ SSL_CTX_sess_connect_good(ssl_ctx)); ++ BIO_printf(bio, "%4ld server accepts (SSL_accept())\n", ++ SSL_CTX_sess_accept(ssl_ctx)); ++ BIO_printf(bio, "%4ld server renegotiates (SSL_accept())\n", ++ SSL_CTX_sess_accept_renegotiate(ssl_ctx)); ++ BIO_printf(bio, "%4ld server accepts that finished\n", ++ SSL_CTX_sess_accept_good(ssl_ctx)); ++ BIO_printf(bio, "%4ld session cache hits\n", SSL_CTX_sess_hits(ssl_ctx)); ++ BIO_printf(bio, "%4ld session cache misses\n", ++ SSL_CTX_sess_misses(ssl_ctx)); ++ BIO_printf(bio, "%4ld session cache timeouts\n", ++ SSL_CTX_sess_timeouts(ssl_ctx)); ++ BIO_printf(bio, "%4ld callback cache hits\n", ++ SSL_CTX_sess_cb_hits(ssl_ctx)); ++ BIO_printf(bio, "%4ld cache full overflows (%ld allowed)\n", ++ SSL_CTX_sess_cache_full(ssl_ctx), ++ SSL_CTX_sess_get_cache_size(ssl_ctx)); ++} ++ ++static int sv_body(int s, int stype, unsigned char *context) ++{ ++ char *buf = NULL; ++ fd_set readfds; ++ int ret = 1, width; ++ int k, i; ++ unsigned long l; ++ SSL *con = NULL; ++ BIO *sbio; ++ struct timeval timeout; ++#if defined(OPENSSL_SYS_WINDOWS) || defined(OPENSSL_SYS_MSDOS) ++ struct timeval tv; ++#else ++ struct timeval *timeoutp; ++#endif ++ ++ buf = app_malloc(bufsize, "server buffer"); ++ if (s_nbio) { ++ if (!BIO_socket_nbio(s, 1)) ++ ERR_print_errors(bio_err); ++ else if (!s_quiet) ++ BIO_printf(bio_err, "Turned on non blocking io\n"); ++ } ++ ++ if (con == NULL) { ++ con = SSL_new(ctx); ++ ++ if (s_tlsextdebug) { ++ SSL_set_tlsext_debug_callback(con, tlsext_cb); ++ SSL_set_tlsext_debug_arg(con, bio_s_out); ++ } ++ ++ if (context ++ && !SSL_set_session_id_context(con, ++ context, strlen((char *)context))) { ++ BIO_printf(bio_err, "Error setting session id context\n"); ++ ret = -1; ++ goto err; ++ } ++ } ++ if (!SSL_clear(con)) { ++ BIO_printf(bio_err, "Error clearing SSL connection\n"); ++ ret = -1; ++ goto err; ++ } ++#ifndef OPENSSL_NO_DTLS ++ if (stype == SOCK_DGRAM) { ++ ++ sbio = BIO_new_dgram(s, BIO_NOCLOSE); ++ ++ if (enable_timeouts) { ++ timeout.tv_sec = 0; ++ timeout.tv_usec = DGRAM_RCV_TIMEOUT; ++ BIO_ctrl(sbio, BIO_CTRL_DGRAM_SET_RECV_TIMEOUT, 0, &timeout); ++ ++ timeout.tv_sec = 0; ++ timeout.tv_usec = DGRAM_SND_TIMEOUT; ++ BIO_ctrl(sbio, BIO_CTRL_DGRAM_SET_SEND_TIMEOUT, 0, &timeout); ++ } ++ ++ if (socket_mtu) { ++ if (socket_mtu < DTLS_get_link_min_mtu(con)) { ++ BIO_printf(bio_err, "MTU too small. Must be at least %ld\n", ++ DTLS_get_link_min_mtu(con)); ++ ret = -1; ++ BIO_free(sbio); ++ goto err; ++ } ++ SSL_set_options(con, SSL_OP_NO_QUERY_MTU); ++ if (!DTLS_set_link_mtu(con, socket_mtu)) { ++ BIO_printf(bio_err, "Failed to set MTU\n"); ++ ret = -1; ++ BIO_free(sbio); ++ goto err; ++ } ++ } else ++ /* want to do MTU discovery */ ++ BIO_ctrl(sbio, BIO_CTRL_DGRAM_MTU_DISCOVER, 0, NULL); ++ ++ /* turn on cookie exchange */ ++ SSL_set_options(con, SSL_OP_COOKIE_EXCHANGE); ++ } else ++#endif ++ sbio = BIO_new_socket(s, BIO_NOCLOSE); ++ ++ if (s_nbio_test) { ++ BIO *test; ++ ++ test = BIO_new(BIO_f_nbio_test()); ++ sbio = BIO_push(test, sbio); ++ } ++ ++ SSL_set_bio(con, sbio, sbio); ++ SSL_set_accept_state(con); ++ /* SSL_set_fd(con,s); */ ++ ++ if (s_debug) { ++ BIO_set_callback(SSL_get_rbio(con), bio_dump_callback); ++ BIO_set_callback_arg(SSL_get_rbio(con), (char *)bio_s_out); ++ } ++ if (s_msg) { ++#ifndef OPENSSL_NO_SSL_TRACE ++ if (s_msg == 2) ++ SSL_set_msg_callback(con, SSL_trace); ++ else ++#endif ++ SSL_set_msg_callback(con, msg_cb); ++ SSL_set_msg_callback_arg(con, bio_s_msg ? bio_s_msg : bio_s_out); ++ } ++ ++ if (s_tlsextdebug) { ++ SSL_set_tlsext_debug_callback(con, tlsext_cb); ++ SSL_set_tlsext_debug_arg(con, bio_s_out); ++ } ++ ++ if (fileno_stdin() > s) ++ width = fileno_stdin() + 1; ++ else ++ width = s + 1; ++ for (;;) { ++ int read_from_terminal; ++ int read_from_sslcon; ++ ++ read_from_terminal = 0; ++ read_from_sslcon = SSL_has_pending(con) ++ || (async && SSL_waiting_for_async(con)); ++ ++ if (!read_from_sslcon) { ++ FD_ZERO(&readfds); ++#if !defined(OPENSSL_SYS_WINDOWS) && !defined(OPENSSL_SYS_MSDOS) ++ openssl_fdset(fileno_stdin(), &readfds); ++#endif ++ openssl_fdset(s, &readfds); ++ /* ++ * Note: under VMS with SOCKETSHR the second parameter is ++ * currently of type (int *) whereas under other systems it is ++ * (void *) if you don't have a cast it will choke the compiler: ++ * if you do have a cast then you can either go for (int *) or ++ * (void *). ++ */ ++#if defined(OPENSSL_SYS_WINDOWS) || defined(OPENSSL_SYS_MSDOS) ++ /* ++ * Under DOS (non-djgpp) and Windows we can't select on stdin: ++ * only on sockets. As a workaround we timeout the select every ++ * second and check for any keypress. In a proper Windows ++ * application we wouldn't do this because it is inefficient. ++ */ ++ tv.tv_sec = 1; ++ tv.tv_usec = 0; ++ i = select(width, (void *)&readfds, NULL, NULL, &tv); ++ if (has_stdin_waiting()) ++ read_from_terminal = 1; ++ if ((i < 0) || (!i && !read_from_terminal)) ++ continue; ++#else ++ if ((SSL_version(con) == DTLS1_VERSION) && ++ DTLSv1_get_timeout(con, &timeout)) ++ timeoutp = &timeout; ++ else ++ timeoutp = NULL; ++ ++ i = select(width, (void *)&readfds, NULL, NULL, timeoutp); ++ ++ if ((SSL_version(con) == DTLS1_VERSION) ++ && DTLSv1_handle_timeout(con) > 0) { ++ BIO_printf(bio_err, "TIMEOUT occurred\n"); ++ } ++ ++ if (i <= 0) ++ continue; ++ if (FD_ISSET(fileno_stdin(), &readfds)) ++ read_from_terminal = 1; ++#endif ++ if (FD_ISSET(s, &readfds)) ++ read_from_sslcon = 1; ++ } ++ if (read_from_terminal) { ++ if (s_crlf) { ++ int j, lf_num; ++ ++ i = raw_read_stdin(buf, bufsize / 2); ++ lf_num = 0; ++ /* both loops are skipped when i <= 0 */ ++ for (j = 0; j < i; j++) ++ if (buf[j] == '\n') ++ lf_num++; ++ for (j = i - 1; j >= 0; j--) { ++ buf[j + lf_num] = buf[j]; ++ if (buf[j] == '\n') { ++ lf_num--; ++ i++; ++ buf[j + lf_num] = '\r'; ++ } ++ } ++ assert(lf_num == 0); ++ } else ++ i = raw_read_stdin(buf, bufsize); ++ ++ if (!s_quiet && !s_brief) { ++ if ((i <= 0) || (buf[0] == 'Q')) { ++ BIO_printf(bio_s_out, "DONE\n"); ++ (void)BIO_flush(bio_s_out); ++ BIO_closesocket(s); ++ close_accept_socket(); ++ ret = -11; ++ goto err; ++ } ++ if ((i <= 0) || (buf[0] == 'q')) { ++ BIO_printf(bio_s_out, "DONE\n"); ++ (void)BIO_flush(bio_s_out); ++ if (SSL_version(con) != DTLS1_VERSION) ++ BIO_closesocket(s); ++ /* ++ * close_accept_socket(); ret= -11; ++ */ ++ goto err; ++ } ++#ifndef OPENSSL_NO_HEARTBEATS ++ if ((buf[0] == 'B') && ((buf[1] == '\n') || (buf[1] == '\r'))) { ++ BIO_printf(bio_err, "HEARTBEATING\n"); ++ SSL_heartbeat(con); ++ i = 0; ++ continue; ++ } ++#endif ++ if ((buf[0] == 'r') && ((buf[1] == '\n') || (buf[1] == '\r'))) { ++ SSL_renegotiate(con); ++ i = SSL_do_handshake(con); ++ printf("SSL_do_handshake -> %d\n", i); ++ i = 0; /* 13; */ ++ continue; ++ /* ++ * strcpy(buf,"server side RE-NEGOTIATE\n"); ++ */ ++ } ++ if ((buf[0] == 'R') && ((buf[1] == '\n') || (buf[1] == '\r'))) { ++ SSL_set_verify(con, ++ SSL_VERIFY_PEER | SSL_VERIFY_CLIENT_ONCE, ++ NULL); ++ SSL_renegotiate(con); ++ i = SSL_do_handshake(con); ++ printf("SSL_do_handshake -> %d\n", i); ++ i = 0; /* 13; */ ++ continue; ++ /* ++ * strcpy(buf,"server side RE-NEGOTIATE asking for client ++ * cert\n"); ++ */ ++ } ++ if (buf[0] == 'P') { ++ static const char *str = "Lets print some clear text\n"; ++ BIO_write(SSL_get_wbio(con), str, strlen(str)); ++ } ++ if (buf[0] == 'S') { ++ print_stats(bio_s_out, SSL_get_SSL_CTX(con)); ++ } ++ } ++#ifdef CHARSET_EBCDIC ++ ebcdic2ascii(buf, buf, i); ++#endif ++ l = k = 0; ++ for (;;) { ++ /* should do a select for the write */ ++#ifdef RENEG ++ static count = 0; ++ if (++count == 100) { ++ count = 0; ++ SSL_renegotiate(con); ++ } ++#endif ++ k = SSL_write(con, &(buf[l]), (unsigned int)i); ++#ifndef OPENSSL_NO_SRP ++ while (SSL_get_error(con, k) == SSL_ERROR_WANT_X509_LOOKUP) { ++ BIO_printf(bio_s_out, "LOOKUP renego during write\n"); ++ SRP_user_pwd_free(srp_callback_parm.user); ++ srp_callback_parm.user = ++ SRP_VBASE_get1_by_user(srp_callback_parm.vb, ++ srp_callback_parm.login); ++ if (srp_callback_parm.user) ++ BIO_printf(bio_s_out, "LOOKUP done %s\n", ++ srp_callback_parm.user->info); ++ else ++ BIO_printf(bio_s_out, "LOOKUP not successful\n"); ++ k = SSL_write(con, &(buf[l]), (unsigned int)i); ++ } ++#endif ++ switch (SSL_get_error(con, k)) { ++ case SSL_ERROR_NONE: ++ break; ++ case SSL_ERROR_WANT_ASYNC: ++ BIO_printf(bio_s_out, "Write BLOCK (Async)\n"); ++ (void)BIO_flush(bio_s_out); ++ wait_for_async(con); ++ break; ++ case SSL_ERROR_WANT_WRITE: ++ case SSL_ERROR_WANT_READ: ++ case SSL_ERROR_WANT_X509_LOOKUP: ++ BIO_printf(bio_s_out, "Write BLOCK\n"); ++ (void)BIO_flush(bio_s_out); ++ break; ++ case SSL_ERROR_WANT_ASYNC_JOB: ++ /* ++ * This shouldn't ever happen in s_server. Treat as an error ++ */ ++ case SSL_ERROR_SYSCALL: ++ case SSL_ERROR_SSL: ++ BIO_printf(bio_s_out, "ERROR\n"); ++ (void)BIO_flush(bio_s_out); ++ ERR_print_errors(bio_err); ++ ret = 1; ++ goto err; ++ /* break; */ ++ case SSL_ERROR_ZERO_RETURN: ++ BIO_printf(bio_s_out, "DONE\n"); ++ (void)BIO_flush(bio_s_out); ++ ret = 1; ++ goto err; ++ } ++ if (k > 0) { ++ l += k; ++ i -= k; ++ } ++ if (i <= 0) ++ break; ++ } ++ } ++ if (read_from_sslcon) { ++ /* ++ * init_ssl_connection handles all async events itself so if we're ++ * waiting for async then we shouldn't go back into ++ * init_ssl_connection ++ */ ++ if ((!async || !SSL_waiting_for_async(con)) ++ && !SSL_is_init_finished(con)) { ++ i = init_ssl_connection(con); ++ ++ if (i < 0) { ++ ret = 0; ++ goto err; ++ } else if (i == 0) { ++ ret = 1; ++ goto err; ++ } ++ } else { ++ again: ++ i = SSL_read(con, (char *)buf, bufsize); ++#ifndef OPENSSL_NO_SRP ++ while (SSL_get_error(con, i) == SSL_ERROR_WANT_X509_LOOKUP) { ++ BIO_printf(bio_s_out, "LOOKUP renego during read\n"); ++ SRP_user_pwd_free(srp_callback_parm.user); ++ srp_callback_parm.user = ++ SRP_VBASE_get1_by_user(srp_callback_parm.vb, ++ srp_callback_parm.login); ++ if (srp_callback_parm.user) ++ BIO_printf(bio_s_out, "LOOKUP done %s\n", ++ srp_callback_parm.user->info); ++ else ++ BIO_printf(bio_s_out, "LOOKUP not successful\n"); ++ i = SSL_read(con, (char *)buf, bufsize); ++ } ++#endif ++ switch (SSL_get_error(con, i)) { ++ case SSL_ERROR_NONE: ++#ifdef CHARSET_EBCDIC ++ ascii2ebcdic(buf, buf, i); ++#endif ++ raw_write_stdout(buf, (unsigned int)i); ++ (void)BIO_flush(bio_s_out); ++ if (SSL_has_pending(con)) ++ goto again; ++ break; ++ case SSL_ERROR_WANT_ASYNC: ++ BIO_printf(bio_s_out, "Read BLOCK (Async)\n"); ++ (void)BIO_flush(bio_s_out); ++ wait_for_async(con); ++ break; ++ case SSL_ERROR_WANT_WRITE: ++ case SSL_ERROR_WANT_READ: ++ BIO_printf(bio_s_out, "Read BLOCK\n"); ++ (void)BIO_flush(bio_s_out); ++ break; ++ case SSL_ERROR_WANT_ASYNC_JOB: ++ /* ++ * This shouldn't ever happen in s_server. Treat as an error ++ */ ++ case SSL_ERROR_SYSCALL: ++ case SSL_ERROR_SSL: ++ BIO_printf(bio_s_out, "ERROR\n"); ++ (void)BIO_flush(bio_s_out); ++ ERR_print_errors(bio_err); ++ ret = 1; ++ goto err; ++ case SSL_ERROR_ZERO_RETURN: ++ BIO_printf(bio_s_out, "DONE\n"); ++ (void)BIO_flush(bio_s_out); ++ ret = 1; ++ goto err; ++ } ++ } ++ } ++ } ++ err: ++ if (con != NULL) { ++ BIO_printf(bio_s_out, "shutting down SSL\n"); ++ SSL_set_shutdown(con, SSL_SENT_SHUTDOWN | SSL_RECEIVED_SHUTDOWN); ++ SSL_free(con); ++ } ++ BIO_printf(bio_s_out, "CONNECTION CLOSED\n"); ++ OPENSSL_clear_free(buf, bufsize); ++ if (ret >= 0) ++ BIO_printf(bio_s_out, "ACCEPT\n"); ++ (void)BIO_flush(bio_s_out); ++ return (ret); ++} ++ ++static void close_accept_socket(void) ++{ ++ BIO_printf(bio_err, "shutdown accept socket\n"); ++ if (accept_socket >= 0) { ++ BIO_closesocket(accept_socket); ++ } ++} ++ ++static int init_ssl_connection(SSL *con) ++{ ++ int i; ++ const char *str; ++ X509 *peer; ++ long verify_err; ++ char buf[BUFSIZ]; ++#if !defined(OPENSSL_NO_NEXTPROTONEG) ++ const unsigned char *next_proto_neg; ++ unsigned next_proto_neg_len; ++#endif ++ unsigned char *exportedkeymat; ++ int retry = 0; ++ ++#ifndef OPENSSL_NO_DTLS ++ if (dtlslisten) { ++ BIO_ADDR *client = NULL; ++ ++ if ((client = BIO_ADDR_new()) == NULL) { ++ BIO_printf(bio_err, "ERROR - memory\n"); ++ return 0; ++ } ++ i = DTLSv1_listen(con, client); ++ if (i > 0) { ++ BIO *wbio; ++ int fd = -1; ++ ++ wbio = SSL_get_wbio(con); ++ if (wbio) { ++ BIO_get_fd(wbio, &fd); ++ } ++ ++ if (!wbio || BIO_connect(fd, client, 0) == 0) { ++ BIO_printf(bio_err, "ERROR - unable to connect\n"); ++ BIO_ADDR_free(client); ++ return 0; ++ } ++ BIO_ADDR_free(client); ++ dtlslisten = 0; ++ i = SSL_accept(con); ++ } else { ++ BIO_ADDR_free(client); ++ } ++ } else ++#endif ++ ++ do { ++ i = SSL_accept(con); ++ ++ if (i <= 0) ++ retry = BIO_sock_should_retry(i); ++#ifdef CERT_CB_TEST_RETRY ++ { ++ while (i <= 0 ++ && SSL_get_error(con, i) == SSL_ERROR_WANT_X509_LOOKUP ++ && SSL_get_state(con) == TLS_ST_SR_CLNT_HELLO) { ++ BIO_printf(bio_err, ++ "LOOKUP from certificate callback during accept\n"); ++ i = SSL_accept(con); ++ if (i <= 0) ++ retry = BIO_sock_should_retry(i); ++ } ++ } ++#endif ++ ++#ifndef OPENSSL_NO_SRP ++ while (i <= 0 ++ && SSL_get_error(con, i) == SSL_ERROR_WANT_X509_LOOKUP) { ++ BIO_printf(bio_s_out, "LOOKUP during accept %s\n", ++ srp_callback_parm.login); ++ SRP_user_pwd_free(srp_callback_parm.user); ++ srp_callback_parm.user = ++ SRP_VBASE_get1_by_user(srp_callback_parm.vb, ++ srp_callback_parm.login); ++ if (srp_callback_parm.user) ++ BIO_printf(bio_s_out, "LOOKUP done %s\n", ++ srp_callback_parm.user->info); ++ else ++ BIO_printf(bio_s_out, "LOOKUP not successful\n"); ++ i = SSL_accept(con); ++ if (i <= 0) ++ retry = BIO_sock_should_retry(i); ++ } ++#endif ++ } while (i < 0 && SSL_waiting_for_async(con)); ++ ++ if (i <= 0) { ++ if ((dtlslisten && i == 0) ++ || (!dtlslisten && retry)) { ++ BIO_printf(bio_s_out, "DELAY\n"); ++ return (1); ++ } ++ ++ BIO_printf(bio_err, "ERROR\n"); ++ ++ verify_err = SSL_get_verify_result(con); ++ if (verify_err != X509_V_OK) { ++ BIO_printf(bio_err, "verify error:%s\n", ++ X509_verify_cert_error_string(verify_err)); ++ } ++ /* Always print any error messages */ ++ ERR_print_errors(bio_err); ++ return (0); ++ } ++ ++ if (s_brief) ++ print_ssl_summary(con); ++ ++ PEM_write_bio_SSL_SESSION(bio_s_out, SSL_get_session(con)); ++ ++ peer = SSL_get_peer_certificate(con); ++ if (peer != NULL) { ++ BIO_printf(bio_s_out, "Client certificate\n"); ++ PEM_write_bio_X509(bio_s_out, peer); ++ X509_NAME_oneline(X509_get_subject_name(peer), buf, sizeof buf); ++ BIO_printf(bio_s_out, "subject=%s\n", buf); ++ X509_NAME_oneline(X509_get_issuer_name(peer), buf, sizeof buf); ++ BIO_printf(bio_s_out, "issuer=%s\n", buf); ++ X509_free(peer); ++ peer = NULL; ++ } ++ ++ if (SSL_get_shared_ciphers(con, buf, sizeof buf) != NULL) ++ BIO_printf(bio_s_out, "Shared ciphers:%s\n", buf); ++ str = SSL_CIPHER_get_name(SSL_get_current_cipher(con)); ++ ssl_print_sigalgs(bio_s_out, con); ++#ifndef OPENSSL_NO_EC ++ ssl_print_point_formats(bio_s_out, con); ++ ssl_print_curves(bio_s_out, con, 0); ++#endif ++ BIO_printf(bio_s_out, "CIPHER is %s\n", (str != NULL) ? str : "(NONE)"); ++ ++#if !defined(OPENSSL_NO_NEXTPROTONEG) ++ SSL_get0_next_proto_negotiated(con, &next_proto_neg, &next_proto_neg_len); ++ if (next_proto_neg) { ++ BIO_printf(bio_s_out, "NEXTPROTO is "); ++ BIO_write(bio_s_out, next_proto_neg, next_proto_neg_len); ++ BIO_printf(bio_s_out, "\n"); ++ } ++#endif ++#ifndef OPENSSL_NO_SRTP ++ { ++ SRTP_PROTECTION_PROFILE *srtp_profile ++ = SSL_get_selected_srtp_profile(con); ++ ++ if (srtp_profile) ++ BIO_printf(bio_s_out, "SRTP Extension negotiated, profile=%s\n", ++ srtp_profile->name); ++ } ++#endif ++ if (SSL_session_reused(con)) ++ BIO_printf(bio_s_out, "Reused session-id\n"); ++ BIO_printf(bio_s_out, "Secure Renegotiation IS%s supported\n", ++ SSL_get_secure_renegotiation_support(con) ? "" : " NOT"); ++ if (keymatexportlabel != NULL) { ++ BIO_printf(bio_s_out, "Keying material exporter:\n"); ++ BIO_printf(bio_s_out, " Label: '%s'\n", keymatexportlabel); ++ BIO_printf(bio_s_out, " Length: %i bytes\n", keymatexportlen); ++ exportedkeymat = app_malloc(keymatexportlen, "export key"); ++ if (!SSL_export_keying_material(con, exportedkeymat, ++ keymatexportlen, ++ keymatexportlabel, ++ strlen(keymatexportlabel), ++ NULL, 0, 0)) { ++ BIO_printf(bio_s_out, " Error\n"); ++ } else { ++ BIO_printf(bio_s_out, " Keying material: "); ++ for (i = 0; i < keymatexportlen; i++) ++ BIO_printf(bio_s_out, "%02X", exportedkeymat[i]); ++ BIO_printf(bio_s_out, "\n"); ++ } ++ OPENSSL_free(exportedkeymat); ++ } ++ ++ (void)BIO_flush(bio_s_out); ++ return (1); ++} ++ ++#ifndef OPENSSL_NO_DH ++static DH *load_dh_param(const char *dhfile) ++{ ++ DH *ret = NULL; ++ BIO *bio; ++ ++ if ((bio = BIO_new_file(dhfile, "r")) == NULL) ++ goto err; ++ ret = PEM_read_bio_DHparams(bio, NULL, NULL, NULL); ++ err: ++ BIO_free(bio); ++ return (ret); ++} ++#endif ++ ++static int www_body(int s, int stype, unsigned char *context) ++{ ++ char *buf = NULL; ++ int ret = 1; ++ int i, j, k, dot; ++ SSL *con; ++ const SSL_CIPHER *c; ++ BIO *io, *ssl_bio, *sbio; ++#ifdef RENEG ++ int total_bytes = 0; ++#endif ++ int width; ++ fd_set readfds; ++ ++ /* Set width for a select call if needed */ ++ width = s + 1; ++ ++ buf = app_malloc(bufsize, "server www buffer"); ++ io = BIO_new(BIO_f_buffer()); ++ ssl_bio = BIO_new(BIO_f_ssl()); ++ if ((io == NULL) || (ssl_bio == NULL)) ++ goto err; ++ ++ if (s_nbio) { ++ if (!BIO_socket_nbio(s, 1)) ++ ERR_print_errors(bio_err); ++ else if (!s_quiet) ++ BIO_printf(bio_err, "Turned on non blocking io\n"); ++ } ++ ++ /* lets make the output buffer a reasonable size */ ++ if (!BIO_set_write_buffer_size(io, bufsize)) ++ goto err; ++ ++ if ((con = SSL_new(ctx)) == NULL) ++ goto err; ++ ++ if (s_tlsextdebug) { ++ SSL_set_tlsext_debug_callback(con, tlsext_cb); ++ SSL_set_tlsext_debug_arg(con, bio_s_out); ++ } ++ ++ if (context ++ && !SSL_set_session_id_context(con, context, ++ strlen((char *)context))) ++ goto err; ++ ++ sbio = BIO_new_socket(s, BIO_NOCLOSE); ++ if (s_nbio_test) { ++ BIO *test; ++ ++ test = BIO_new(BIO_f_nbio_test()); ++ sbio = BIO_push(test, sbio); ++ } ++ SSL_set_bio(con, sbio, sbio); ++ SSL_set_accept_state(con); ++ ++ /* SSL_set_fd(con,s); */ ++ BIO_set_ssl(ssl_bio, con, BIO_CLOSE); ++ BIO_push(io, ssl_bio); ++#ifdef CHARSET_EBCDIC ++ io = BIO_push(BIO_new(BIO_f_ebcdic_filter()), io); ++#endif ++ ++ if (s_debug) { ++ BIO_set_callback(SSL_get_rbio(con), bio_dump_callback); ++ BIO_set_callback_arg(SSL_get_rbio(con), (char *)bio_s_out); ++ } ++ if (s_msg) { ++#ifndef OPENSSL_NO_SSL_TRACE ++ if (s_msg == 2) ++ SSL_set_msg_callback(con, SSL_trace); ++ else ++#endif ++ SSL_set_msg_callback(con, msg_cb); ++ SSL_set_msg_callback_arg(con, bio_s_msg ? bio_s_msg : bio_s_out); ++ } ++ ++ for (;;) { ++ i = BIO_gets(io, buf, bufsize - 1); ++ if (i < 0) { /* error */ ++ if (!BIO_should_retry(io) && !SSL_waiting_for_async(con)) { ++ if (!s_quiet) ++ ERR_print_errors(bio_err); ++ goto err; ++ } else { ++ BIO_printf(bio_s_out, "read R BLOCK\n"); ++#ifndef OPENSSL_NO_SRP ++ if (BIO_should_io_special(io) ++ && BIO_get_retry_reason(io) == BIO_RR_SSL_X509_LOOKUP) { ++ BIO_printf(bio_s_out, "LOOKUP renego during read\n"); ++ SRP_user_pwd_free(srp_callback_parm.user); ++ srp_callback_parm.user = ++ SRP_VBASE_get1_by_user(srp_callback_parm.vb, ++ srp_callback_parm.login); ++ if (srp_callback_parm.user) ++ BIO_printf(bio_s_out, "LOOKUP done %s\n", ++ srp_callback_parm.user->info); ++ else ++ BIO_printf(bio_s_out, "LOOKUP not successful\n"); ++ continue; ++ } ++#endif ++#if !defined(OPENSSL_SYS_MSDOS) ++ sleep(1); ++#endif ++ continue; ++ } ++ } else if (i == 0) { /* end of input */ ++ ret = 1; ++ goto end; ++ } ++ ++ /* else we have data */ ++ if (((www == 1) && (strncmp("GET ", buf, 4) == 0)) || ++ ((www == 2) && (strncmp("GET /stats ", buf, 11) == 0))) { ++ char *p; ++ X509 *peer = NULL; ++ STACK_OF(SSL_CIPHER) *sk; ++ static const char *space = " "; ++ ++ if (www == 1 && strncmp("GET /reneg", buf, 10) == 0) { ++ if (strncmp("GET /renegcert", buf, 14) == 0) ++ SSL_set_verify(con, ++ SSL_VERIFY_PEER | SSL_VERIFY_CLIENT_ONCE, ++ NULL); ++ i = SSL_renegotiate(con); ++ BIO_printf(bio_s_out, "SSL_renegotiate -> %d\n", i); ++ /* Send the HelloRequest */ ++ i = SSL_do_handshake(con); ++ if (i <= 0) { ++ BIO_printf(bio_s_out, "SSL_do_handshake() Retval %d\n", ++ SSL_get_error(con, i)); ++ ERR_print_errors(bio_err); ++ goto err; ++ } ++ /* Wait for a ClientHello to come back */ ++ FD_ZERO(&readfds); ++ openssl_fdset(s, &readfds); ++ i = select(width, (void *)&readfds, NULL, NULL, NULL); ++ if (i <= 0 || !FD_ISSET(s, &readfds)) { ++ BIO_printf(bio_s_out, ++ "Error waiting for client response\n"); ++ ERR_print_errors(bio_err); ++ goto err; ++ } ++ /* ++ * We're not actually expecting any data here and we ignore ++ * any that is sent. This is just to force the handshake that ++ * we're expecting to come from the client. If they haven't ++ * sent one there's not much we can do. ++ */ ++ BIO_gets(io, buf, bufsize - 1); ++ } ++ ++ BIO_puts(io, ++ "HTTP/1.0 200 ok\r\nContent-type: text/html\r\n\r\n"); ++ BIO_puts(io, "\n"); ++ BIO_puts(io, "
\n");
++            /* BIO_puts(io, OpenSSL_version(OPENSSL_VERSION)); */
++            BIO_puts(io, "\n");
++            for (i = 0; i < local_argc; i++) {
++                const char *myp;
++                for (myp = local_argv[i]; *myp; myp++)
++                    switch (*myp) {
++                    case '<':
++                        BIO_puts(io, "<");
++                        break;
++                    case '>':
++                        BIO_puts(io, ">");
++                        break;
++                    case '&':
++                        BIO_puts(io, "&");
++                        break;
++                    default:
++                        BIO_write(io, myp, 1);
++                        break;
++                    }
++                BIO_write(io, " ", 1);
++            }
++            BIO_puts(io, "\n");
++
++            BIO_printf(io,
++                       "Secure Renegotiation IS%s supported\n",
++                       SSL_get_secure_renegotiation_support(con) ?
++                       "" : " NOT");
++
++            /*
++             * The following is evil and should not really be done
++             */
++            BIO_printf(io, "Ciphers supported in s_server binary\n");
++            sk = SSL_get_ciphers(con);
++            j = sk_SSL_CIPHER_num(sk);
++            for (i = 0; i < j; i++) {
++                c = sk_SSL_CIPHER_value(sk, i);
++                BIO_printf(io, "%-11s:%-25s ",
++                           SSL_CIPHER_get_version(c), SSL_CIPHER_get_name(c));
++                if ((((i + 1) % 2) == 0) && (i + 1 != j))
++                    BIO_puts(io, "\n");
++            }
++            BIO_puts(io, "\n");
++            p = SSL_get_shared_ciphers(con, buf, bufsize);
++            if (p != NULL) {
++                BIO_printf(io,
++                           "---\nCiphers common between both SSL end points:\n");
++                j = i = 0;
++                while (*p) {
++                    if (*p == ':') {
++                        BIO_write(io, space, 26 - j);
++                        i++;
++                        j = 0;
++                        BIO_write(io, ((i % 3) ? " " : "\n"), 1);
++                    } else {
++                        BIO_write(io, p, 1);
++                        j++;
++                    }
++                    p++;
++                }
++                BIO_puts(io, "\n");
++            }
++            ssl_print_sigalgs(io, con);
++#ifndef OPENSSL_NO_EC
++            ssl_print_curves(io, con, 0);
++#endif
++            BIO_printf(io, (SSL_session_reused(con)
++                            ? "---\nReused, " : "---\nNew, "));
++            c = SSL_get_current_cipher(con);
++            BIO_printf(io, "%s, Cipher is %s\n",
++                       SSL_CIPHER_get_version(c), SSL_CIPHER_get_name(c));
++            SSL_SESSION_print(io, SSL_get_session(con));
++            BIO_printf(io, "---\n");
++            print_stats(io, SSL_get_SSL_CTX(con));
++            BIO_printf(io, "---\n");
++            peer = SSL_get_peer_certificate(con);
++            if (peer != NULL) {
++                BIO_printf(io, "Client certificate\n");
++                X509_print(io, peer);
++                PEM_write_bio_X509(io, peer);
++                X509_free(peer);
++                peer = NULL;
++            } else
++                BIO_puts(io, "no client certificate available\n");
++            BIO_puts(io, "\r\n\r\n");
++            break;
++        } else if ((www == 2 || www == 3)
++                   && (strncmp("GET /", buf, 5) == 0)) {
++            BIO *file;
++            char *p, *e;
++            static const char *text =
++                "HTTP/1.0 200 ok\r\nContent-type: text/plain\r\n\r\n";
++
++            /* skip the '/' */
++            p = &(buf[5]);
++
++            dot = 1;
++            for (e = p; *e != '\0'; e++) {
++                if (e[0] == ' ')
++                    break;
++
++                switch (dot) {
++                case 1:
++                    dot = (e[0] == '.') ? 2 : 0;
++                    break;
++                case 2:
++                    dot = (e[0] == '.') ? 3 : 0;
++                    break;
++                case 3:
++                    dot = (e[0] == '/') ? -1 : 0;
++                    break;
++                }
++                if (dot == 0)
++                    dot = (e[0] == '/') ? 1 : 0;
++            }
++            dot = (dot == 3) || (dot == -1); /* filename contains ".."
++                                              * component */
++
++            if (*e == '\0') {
++                BIO_puts(io, text);
++                BIO_printf(io, "'%s' is an invalid file name\r\n", p);
++                break;
++            }
++            *e = '\0';
++
++            if (dot) {
++                BIO_puts(io, text);
++                BIO_printf(io, "'%s' contains '..' reference\r\n", p);
++                break;
++            }
++
++            if (*p == '/') {
++                BIO_puts(io, text);
++                BIO_printf(io, "'%s' is an invalid path\r\n", p);
++                break;
++            }
++
++            /* if a directory, do the index thang */
++            if (app_isdir(p) > 0) {
++                BIO_puts(io, text);
++                BIO_printf(io, "'%s' is a directory\r\n", p);
++                break;
++            }
++
++            if ((file = BIO_new_file(p, "r")) == NULL) {
++                BIO_puts(io, text);
++                BIO_printf(io, "Error opening '%s'\r\n", p);
++                ERR_print_errors(io);
++                break;
++            }
++
++            if (!s_quiet)
++                BIO_printf(bio_err, "FILE:%s\n", p);
++
++            if (www == 2) {
++                i = strlen(p);
++                if (((i > 5) && (strcmp(&(p[i - 5]), ".html") == 0)) ||
++                    ((i > 4) && (strcmp(&(p[i - 4]), ".php") == 0)) ||
++                    ((i > 4) && (strcmp(&(p[i - 4]), ".htm") == 0)))
++                    BIO_puts(io,
++                             "HTTP/1.0 200 ok\r\nContent-type: text/html\r\n\r\n");
++                else
++                    BIO_puts(io,
++                             "HTTP/1.0 200 ok\r\nContent-type: text/plain\r\n\r\n");
++            }
++            /* send the file */
++            for (;;) {
++                i = BIO_read(file, buf, bufsize);
++                if (i <= 0)
++                    break;
++
++#ifdef RENEG
++                total_bytes += i;
++                BIO_printf(bio_err, "%d\n", i);
++                if (total_bytes > 3 * 1024) {
++                    total_bytes = 0;
++                    BIO_printf(bio_err, "RENEGOTIATE\n");
++                    SSL_renegotiate(con);
++                }
++#endif
++
++                for (j = 0; j < i;) {
++#ifdef RENEG
++                    static count = 0;
++                    if (++count == 13) {
++                        SSL_renegotiate(con);
++                    }
++#endif
++                    k = BIO_write(io, &(buf[j]), i - j);
++                    if (k <= 0) {
++                        if (!BIO_should_retry(io)
++                            && !SSL_waiting_for_async(con))
++                            goto write_error;
++                        else {
++                            BIO_printf(bio_s_out, "rwrite W BLOCK\n");
++                        }
++                    } else {
++                        j += k;
++                    }
++                }
++            }
++ write_error:
++            BIO_free(file);
++            break;
++        }
++    }
++
++    for (;;) {
++        i = (int)BIO_flush(io);
++        if (i <= 0) {
++            if (!BIO_should_retry(io))
++                break;
++        } else
++            break;
++    }
++ end:
++    /* make sure we re-use sessions */
++    SSL_set_shutdown(con, SSL_SENT_SHUTDOWN | SSL_RECEIVED_SHUTDOWN);
++
++ err:
++    if (ret >= 0)
++        BIO_printf(bio_s_out, "ACCEPT\n");
++    OPENSSL_free(buf);
++    BIO_free_all(io);
++    return (ret);
++}
++
++static int rev_body(int s, int stype, unsigned char *context)
++{
++    char *buf = NULL;
++    int i;
++    int ret = 1;
++    SSL *con;
++    BIO *io, *ssl_bio, *sbio;
++
++    buf = app_malloc(bufsize, "server rev buffer");
++    io = BIO_new(BIO_f_buffer());
++    ssl_bio = BIO_new(BIO_f_ssl());
++    if ((io == NULL) || (ssl_bio == NULL))
++        goto err;
++
++    /* lets make the output buffer a reasonable size */
++    if (!BIO_set_write_buffer_size(io, bufsize))
++        goto err;
++
++    if ((con = SSL_new(ctx)) == NULL)
++        goto err;
++
++    if (s_tlsextdebug) {
++        SSL_set_tlsext_debug_callback(con, tlsext_cb);
++        SSL_set_tlsext_debug_arg(con, bio_s_out);
++    }
++    if (context
++        && !SSL_set_session_id_context(con, context,
++                                       strlen((char *)context))) {
++        ERR_print_errors(bio_err);
++        goto err;
++    }
++
++    sbio = BIO_new_socket(s, BIO_NOCLOSE);
++    SSL_set_bio(con, sbio, sbio);
++    SSL_set_accept_state(con);
++
++    BIO_set_ssl(ssl_bio, con, BIO_CLOSE);
++    BIO_push(io, ssl_bio);
++#ifdef CHARSET_EBCDIC
++    io = BIO_push(BIO_new(BIO_f_ebcdic_filter()), io);
++#endif
++
++    if (s_debug) {
++        BIO_set_callback(SSL_get_rbio(con), bio_dump_callback);
++        BIO_set_callback_arg(SSL_get_rbio(con), (char *)bio_s_out);
++    }
++    if (s_msg) {
++#ifndef OPENSSL_NO_SSL_TRACE
++        if (s_msg == 2)
++            SSL_set_msg_callback(con, SSL_trace);
++        else
++#endif
++            SSL_set_msg_callback(con, msg_cb);
++        SSL_set_msg_callback_arg(con, bio_s_msg ? bio_s_msg : bio_s_out);
++    }
++
++    for (;;) {
++        i = BIO_do_handshake(io);
++        if (i > 0)
++            break;
++        if (!BIO_should_retry(io)) {
++            BIO_puts(bio_err, "CONNECTION FAILURE\n");
++            ERR_print_errors(bio_err);
++            goto end;
++        }
++#ifndef OPENSSL_NO_SRP
++        if (BIO_should_io_special(io)
++            && BIO_get_retry_reason(io) == BIO_RR_SSL_X509_LOOKUP) {
++            BIO_printf(bio_s_out, "LOOKUP renego during accept\n");
++            SRP_user_pwd_free(srp_callback_parm.user);
++            srp_callback_parm.user =
++                SRP_VBASE_get1_by_user(srp_callback_parm.vb,
++                                       srp_callback_parm.login);
++            if (srp_callback_parm.user)
++                BIO_printf(bio_s_out, "LOOKUP done %s\n",
++                           srp_callback_parm.user->info);
++            else
++                BIO_printf(bio_s_out, "LOOKUP not successful\n");
++            continue;
++        }
++#endif
++    }
++    BIO_printf(bio_err, "CONNECTION ESTABLISHED\n");
++    print_ssl_summary(con);
++
++    for (;;) {
++        i = BIO_gets(io, buf, bufsize - 1);
++        if (i < 0) {            /* error */
++            if (!BIO_should_retry(io)) {
++                if (!s_quiet)
++                    ERR_print_errors(bio_err);
++                goto err;
++            } else {
++                BIO_printf(bio_s_out, "read R BLOCK\n");
++#ifndef OPENSSL_NO_SRP
++                if (BIO_should_io_special(io)
++                    && BIO_get_retry_reason(io) == BIO_RR_SSL_X509_LOOKUP) {
++                    BIO_printf(bio_s_out, "LOOKUP renego during read\n");
++                    SRP_user_pwd_free(srp_callback_parm.user);
++                    srp_callback_parm.user =
++                        SRP_VBASE_get1_by_user(srp_callback_parm.vb,
++                                               srp_callback_parm.login);
++                    if (srp_callback_parm.user)
++                        BIO_printf(bio_s_out, "LOOKUP done %s\n",
++                                   srp_callback_parm.user->info);
++                    else
++                        BIO_printf(bio_s_out, "LOOKUP not successful\n");
++                    continue;
++                }
++#endif
++#if !defined(OPENSSL_SYS_MSDOS)
++                sleep(1);
++#endif
++                continue;
++            }
++        } else if (i == 0) {    /* end of input */
++            ret = 1;
++            BIO_printf(bio_err, "CONNECTION CLOSED\n");
++            goto end;
++        } else {
++            char *p = buf + i - 1;
++            while (i && (*p == '\n' || *p == '\r')) {
++                p--;
++                i--;
++            }
++            if (!s_ign_eof && (i == 5) && (strncmp(buf, "CLOSE", 5) == 0)) {
++                ret = 1;
++                BIO_printf(bio_err, "CONNECTION CLOSED\n");
++                goto end;
++            }
++            BUF_reverse((unsigned char *)buf, NULL, i);
++            buf[i] = '\n';
++            BIO_write(io, buf, i + 1);
++            for (;;) {
++                i = BIO_flush(io);
++                if (i > 0)
++                    break;
++                if (!BIO_should_retry(io))
++                    goto end;
++            }
++        }
++    }
++ end:
++    /* make sure we re-use sessions */
++    SSL_set_shutdown(con, SSL_SENT_SHUTDOWN | SSL_RECEIVED_SHUTDOWN);
++
++ err:
++
++    OPENSSL_free(buf);
++    BIO_free_all(io);
++    return (ret);
++}
++
++#define MAX_SESSION_ID_ATTEMPTS 10
++static int generate_session_id(const SSL *ssl, unsigned char *id,
++                               unsigned int *id_len)
++{
++    unsigned int count = 0;
++    do {
++        if (RAND_bytes(id, *id_len) <= 0)
++            return 0;
++        /*
++         * Prefix the session_id with the required prefix. NB: If our prefix
++         * is too long, clip it - but there will be worse effects anyway, eg.
++         * the server could only possibly create 1 session ID (ie. the
++         * prefix!) so all future session negotiations will fail due to
++         * conflicts.
++         */
++        memcpy(id, session_id_prefix,
++               (strlen(session_id_prefix) < *id_len) ?
++               strlen(session_id_prefix) : *id_len);
++    }
++    while (SSL_has_matching_session_id(ssl, id, *id_len) &&
++           (++count < MAX_SESSION_ID_ATTEMPTS));
++    if (count >= MAX_SESSION_ID_ATTEMPTS)
++        return 0;
++    return 1;
++}
++
++/*
++ * By default s_server uses an in-memory cache which caches SSL_SESSION
++ * structures without any serialisation. This hides some bugs which only
++ * become apparent in deployed servers. By implementing a basic external
++ * session cache some issues can be debugged using s_server.
++ */
++
++typedef struct simple_ssl_session_st {
++    unsigned char *id;
++    unsigned int idlen;
++    unsigned char *der;
++    int derlen;
++    struct simple_ssl_session_st *next;
++} simple_ssl_session;
++
++static simple_ssl_session *first = NULL;
++
++static int add_session(SSL *ssl, SSL_SESSION *session)
++{
++    simple_ssl_session *sess = app_malloc(sizeof(*sess), "get session");
++    unsigned char *p;
++
++    SSL_SESSION_get_id(session, &sess->idlen);
++    sess->derlen = i2d_SSL_SESSION(session, NULL);
++    if (sess->derlen < 0) {
++        BIO_printf(bio_err, "Error encoding session\n");
++        OPENSSL_free(sess);
++        return 0;
++    }
++
++    sess->id = OPENSSL_memdup(SSL_SESSION_get_id(session, NULL), sess->idlen);
++    sess->der = app_malloc(sess->derlen, "get session buffer");
++    if (!sess->id) {
++        BIO_printf(bio_err, "Out of memory adding to external cache\n");
++        OPENSSL_free(sess->id);
++        OPENSSL_free(sess->der);
++        OPENSSL_free(sess);
++        return 0;
++    }
++    p = sess->der;
++
++    /* Assume it still works. */
++    if (i2d_SSL_SESSION(session, &p) != sess->derlen) {
++        BIO_printf(bio_err, "Unexpected session encoding length\n");
++        OPENSSL_free(sess->id);
++        OPENSSL_free(sess->der);
++        OPENSSL_free(sess);
++        return 0;
++    }
++
++    sess->next = first;
++    first = sess;
++    BIO_printf(bio_err, "New session added to external cache\n");
++    return 0;
++}
++
++static SSL_SESSION *get_session(SSL *ssl, const unsigned char *id, int idlen,
++                                int *do_copy)
++{
++    simple_ssl_session *sess;
++    *do_copy = 0;
++    for (sess = first; sess; sess = sess->next) {
++        if (idlen == (int)sess->idlen && !memcmp(sess->id, id, idlen)) {
++            const unsigned char *p = sess->der;
++            BIO_printf(bio_err, "Lookup session: cache hit\n");
++            return d2i_SSL_SESSION(NULL, &p, sess->derlen);
++        }
++    }
++    BIO_printf(bio_err, "Lookup session: cache miss\n");
++    return NULL;
++}
++
++static void del_session(SSL_CTX *sctx, SSL_SESSION *session)
++{
++    simple_ssl_session *sess, *prev = NULL;
++    const unsigned char *id;
++    unsigned int idlen;
++    id = SSL_SESSION_get_id(session, &idlen);
++    for (sess = first; sess; sess = sess->next) {
++        if (idlen == sess->idlen && !memcmp(sess->id, id, idlen)) {
++            if (prev)
++                prev->next = sess->next;
++            else
++                first = sess->next;
++            OPENSSL_free(sess->id);
++            OPENSSL_free(sess->der);
++            OPENSSL_free(sess);
++            return;
++        }
++        prev = sess;
++    }
++}
++
++static void init_session_cache_ctx(SSL_CTX *sctx)
++{
++    SSL_CTX_set_session_cache_mode(sctx,
++                                   SSL_SESS_CACHE_NO_INTERNAL |
++                                   SSL_SESS_CACHE_SERVER);
++    SSL_CTX_sess_set_new_cb(sctx, add_session);
++    SSL_CTX_sess_set_get_cb(sctx, get_session);
++    SSL_CTX_sess_set_remove_cb(sctx, del_session);
++}
++
++static void free_sessions(void)
++{
++    simple_ssl_session *sess, *tsess;
++    for (sess = first; sess;) {
++        OPENSSL_free(sess->id);
++        OPENSSL_free(sess->der);
++        tsess = sess;
++        sess = sess->next;
++        OPENSSL_free(tsess);
++    }
++    first = NULL;
++}
++
++#endif                          /* OPENSSL_NO_SOCK */
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/apps/s_socket.c b/CryptoPkg/Library/OpensslLib/openssl/apps/s_socket.c
+new file mode 100644
+index 0000000..d16f5ad
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/apps/s_socket.c
+@@ -0,0 +1,201 @@
++/*
++ * Copyright 1995-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++/* socket-related functions used by s_client and s_server */
++#include 
++#include 
++#include 
++#include 
++#include 
++#include 
++
++/*
++ * With IPv6, it looks like Digital has mixed up the proper order of
++ * recursive header file inclusion, resulting in the compiler complaining
++ * that u_int isn't defined, but only if _POSIX_C_SOURCE is defined, which is
++ * needed to have fileno() declared correctly...  So let's define u_int
++ */
++#if defined(OPENSSL_SYS_VMS_DECC) && !defined(__U_INT)
++# define __U_INT
++typedef unsigned int u_int;
++#endif
++
++#ifndef OPENSSL_NO_SOCK
++
++# define USE_SOCKETS
++# include "apps.h"
++# undef USE_SOCKETS
++# include "s_apps.h"
++
++# include 
++# include 
++
++/*
++ * init_client - helper routine to set up socket communication
++ * @sock: pointer to storage of resulting socket.
++ * @host: the host name or path (for AF_UNIX) to connect to.
++ * @port: the port to connect to (ignored for AF_UNIX).
++ * @family: desired socket family, may be AF_INET, AF_INET6, AF_UNIX or
++ *  AF_UNSPEC
++ * @type: socket type, must be SOCK_STREAM or SOCK_DGRAM
++ *
++ * This will create a socket and use it to connect to a host:port, or if
++ * family == AF_UNIX, to the path found in host.
++ *
++ * If the host has more than one address, it will try them one by one until
++ * a successful connection is established.  The resulting socket will be
++ * found in *sock on success, it will be given INVALID_SOCKET otherwise.
++ *
++ * Returns 1 on success, 0 on failure.
++ */
++int init_client(int *sock, const char *host, const char *port,
++                int family, int type)
++{
++    BIO_ADDRINFO *res = NULL;
++    const BIO_ADDRINFO *ai = NULL;
++    int ret;
++
++    if (!BIO_sock_init())
++        return 0;
++
++    ret = BIO_lookup(host, port, BIO_LOOKUP_CLIENT, family, type, &res);
++    if (ret == 0) {
++        ERR_print_errors(bio_err);
++        return 0;
++    }
++
++    ret = 0;
++    for (ai = res; ai != NULL; ai = BIO_ADDRINFO_next(ai)) {
++        /* Admittedly, these checks are quite paranoid, we should not get
++         * anything in the BIO_ADDRINFO chain that we haven't
++         * asked for. */
++        OPENSSL_assert((family == AF_UNSPEC || family == BIO_ADDRINFO_family(res))
++                       && (type == 0 || type == BIO_ADDRINFO_socktype(res)));
++
++        *sock = BIO_socket(BIO_ADDRINFO_family(ai), BIO_ADDRINFO_socktype(ai),
++                           BIO_ADDRINFO_protocol(res), 0);
++        if (*sock == INVALID_SOCKET) {
++            /* Maybe the kernel doesn't support the socket family, even if
++             * BIO_lookup() added it in the returned result...
++             */
++            continue;
++        }
++        if (!BIO_connect(*sock, BIO_ADDRINFO_address(ai), 0)) {
++            BIO_closesocket(*sock);
++            *sock = INVALID_SOCKET;
++            continue;
++        }
++
++        /* Success, don't try any more addresses */
++        break;
++    }
++
++    if (*sock == INVALID_SOCKET) {
++        ERR_print_errors(bio_err);
++    } else {
++        /* Remove any stale errors from previous connection attempts */
++        ERR_clear_error();
++        ret = 1;
++    }
++    BIO_ADDRINFO_free(res);
++    return ret;
++}
++
++/*
++ * do_server - helper routine to perform a server operation
++ * @accept_sock: pointer to storage of resulting socket.
++ * @host: the host name or path (for AF_UNIX) to connect to.
++ * @port: the port to connect to (ignored for AF_UNIX).
++ * @family: desired socket family, may be AF_INET, AF_INET6, AF_UNIX or
++ *  AF_UNSPEC
++ * @type: socket type, must be SOCK_STREAM or SOCK_DGRAM
++ * @cb: pointer to a function that receives the accepted socket and
++ *  should perform the communication with the connecting client.
++ * @context: pointer to memory that's passed verbatim to the cb function.
++ * @naccept: number of times an incoming connect should be accepted.  If -1,
++ *  unlimited number.
++ *
++ * This will create a socket and use it to listen to a host:port, or if
++ * family == AF_UNIX, to the path found in host, then start accepting
++ * incoming connections and run cb on the resulting socket.
++ *
++ * 0 on failure, something other on success.
++ */
++int do_server(int *accept_sock, const char *host, const char *port,
++              int family, int type, do_server_cb cb,
++              unsigned char *context, int naccept)
++{
++    int asock = 0;
++    int sock;
++    int i;
++    BIO_ADDRINFO *res = NULL;
++    int ret = 0;
++
++    if (!BIO_sock_init())
++        return 0;
++
++    if (!BIO_lookup(host, port, BIO_LOOKUP_SERVER, family, type, &res)) {
++        ERR_print_errors(bio_err);
++        return 0;
++    }
++
++    /* Admittedly, these checks are quite paranoid, we should not get
++     * anything in the BIO_ADDRINFO chain that we haven't asked for */
++    OPENSSL_assert((family == AF_UNSPEC || family == BIO_ADDRINFO_family(res))
++                   && (type == 0 || type == BIO_ADDRINFO_socktype(res)));
++
++    asock = BIO_socket(BIO_ADDRINFO_family(res), BIO_ADDRINFO_socktype(res),
++                       BIO_ADDRINFO_protocol(res), 0);
++    if (asock == INVALID_SOCKET
++        || !BIO_listen(asock, BIO_ADDRINFO_address(res), BIO_SOCK_REUSEADDR)) {
++        BIO_ADDRINFO_free(res);
++        ERR_print_errors(bio_err);
++        if (asock != INVALID_SOCKET)
++            BIO_closesocket(asock);
++        goto end;
++    }
++
++    BIO_ADDRINFO_free(res);
++    res = NULL;
++
++    if (accept_sock != NULL)
++        *accept_sock = asock;
++    for (;;) {
++        if (type == SOCK_STREAM) {
++            do {
++                sock = BIO_accept_ex(asock, NULL, 0);
++            } while (sock < 0 && BIO_sock_should_retry(ret));
++            if (sock < 0) {
++                ERR_print_errors(bio_err);
++                BIO_closesocket(asock);
++                break;
++            }
++            i = (*cb)(sock, type, context);
++            BIO_closesocket(sock);
++        } else {
++            i = (*cb)(asock, type, context);
++        }
++
++        if (naccept != -1)
++            naccept--;
++        if (i < 0 || naccept == 0) {
++            BIO_closesocket(asock);
++            ret = i;
++            break;
++        }
++    }
++ end:
++# ifdef AF_UNIX
++    if (family == AF_UNIX)
++        unlink(host);
++# endif
++    return ret;
++}
++
++#endif  /* OPENSSL_NO_SOCK */
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/apps/s_time.c b/CryptoPkg/Library/OpensslLib/openssl/apps/s_time.c
+new file mode 100644
+index 0000000..263502c
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/apps/s_time.c
+@@ -0,0 +1,422 @@
++/*
++ * Copyright 1995-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#define NO_SHUTDOWN
++
++#include 
++#include 
++#include 
++
++#include 
++
++#ifndef OPENSSL_NO_SOCK
++
++#define USE_SOCKETS
++#include "apps.h"
++#include 
++#include 
++#include 
++#include "s_apps.h"
++#include 
++#if !defined(OPENSSL_SYS_MSDOS)
++# include OPENSSL_UNISTD
++#endif
++
++#undef ioctl
++#define ioctl ioctlsocket
++
++#define SSL_CONNECT_NAME        "localhost:4433"
++
++/* no default cert. */
++/*
++ * #define TEST_CERT "client.pem"
++ */
++
++#undef min
++#undef max
++#define min(a,b) (((a) < (b)) ? (a) : (b))
++#define max(a,b) (((a) > (b)) ? (a) : (b))
++
++#undef SECONDS
++#define SECONDS 30
++#define SECONDSSTR "30"
++
++static SSL *doConnection(SSL *scon, const char *host, SSL_CTX *ctx);
++
++static const char fmt_http_get_cmd[] = "GET %s HTTP/1.0\r\n\r\n";
++
++typedef enum OPTION_choice {
++    OPT_ERR = -1, OPT_EOF = 0, OPT_HELP,
++    OPT_CONNECT, OPT_CIPHER, OPT_CERT, OPT_KEY, OPT_CAPATH,
++    OPT_CAFILE, OPT_NOCAPATH, OPT_NOCAFILE, OPT_NEW, OPT_REUSE, OPT_BUGS,
++    OPT_VERIFY, OPT_TIME, OPT_SSL3,
++    OPT_WWW
++} OPTION_CHOICE;
++
++OPTIONS s_time_options[] = {
++    {"help", OPT_HELP, '-', "Display this summary"},
++    {"connect", OPT_CONNECT, 's',
++     "Where to connect as post:port (default is " SSL_CONNECT_NAME ")"},
++    {"cipher", OPT_CIPHER, 's', "Cipher to use, see 'openssl ciphers'"},
++    {"cert", OPT_CERT, '<', "Cert file to use, PEM format assumed"},
++    {"key", OPT_KEY, '<', "File with key, PEM; default is -cert file"},
++    {"CApath", OPT_CAPATH, '/', "PEM format directory of CA's"},
++    {"cafile", OPT_CAFILE, '<', "PEM format file of CA's"},
++    {"no-CAfile", OPT_NOCAFILE, '-',
++     "Do not load the default certificates file"},
++    {"no-CApath", OPT_NOCAPATH, '-',
++     "Do not load certificates from the default certificates directory"},
++    {"new", OPT_NEW, '-', "Just time new connections"},
++    {"reuse", OPT_REUSE, '-', "Just time connection reuse"},
++    {"bugs", OPT_BUGS, '-', "Turn on SSL bug compatibility"},
++    {"verify", OPT_VERIFY, 'p',
++     "Turn on peer certificate verification, set depth"},
++    {"time", OPT_TIME, 'p', "Seconds to collect data, default " SECONDSSTR},
++    {"www", OPT_WWW, 's', "Fetch specified page from the site"},
++#ifndef OPENSSL_NO_SSL3
++    {"ssl3", OPT_SSL3, '-', "Just use SSLv3"},
++#endif
++    {NULL}
++};
++
++#define START   0
++#define STOP    1
++
++static double tm_Time_F(int s)
++{
++    return app_tminterval(s, 1);
++}
++
++int s_time_main(int argc, char **argv)
++{
++    char buf[1024 * 8];
++    SSL *scon = NULL;
++    SSL_CTX *ctx = NULL;
++    const SSL_METHOD *meth = NULL;
++    char *CApath = NULL, *CAfile = NULL, *cipher = NULL, *www_path = NULL;
++    char *host = SSL_CONNECT_NAME, *certfile = NULL, *keyfile = NULL, *prog;
++    double totalTime = 0.0;
++    int noCApath = 0, noCAfile = 0;
++    int maxtime = SECONDS, nConn = 0, perform = 3, ret = 1, i, st_bugs = 0;
++    long bytes_read = 0, finishtime = 0;
++    OPTION_CHOICE o;
++    int max_version = 0, ver, buf_len;
++    size_t buf_size;
++
++    meth = TLS_client_method();
++
++    prog = opt_init(argc, argv, s_time_options);
++    while ((o = opt_next()) != OPT_EOF) {
++        switch (o) {
++        case OPT_EOF:
++        case OPT_ERR:
++ opthelp:
++            BIO_printf(bio_err, "%s: Use -help for summary.\n", prog);
++            goto end;
++        case OPT_HELP:
++            opt_help(s_time_options);
++            ret = 0;
++            goto end;
++        case OPT_CONNECT:
++            host = opt_arg();
++            break;
++        case OPT_REUSE:
++            perform = 2;
++            break;
++        case OPT_NEW:
++            perform = 1;
++            break;
++        case OPT_VERIFY:
++            if (!opt_int(opt_arg(), &verify_args.depth))
++                goto opthelp;
++            BIO_printf(bio_err, "%s: verify depth is %d\n",
++                       prog, verify_args.depth);
++            break;
++        case OPT_CERT:
++            certfile = opt_arg();
++            break;
++        case OPT_KEY:
++            keyfile = opt_arg();
++            break;
++        case OPT_CAPATH:
++            CApath = opt_arg();
++            break;
++        case OPT_CAFILE:
++            CAfile = opt_arg();
++            break;
++        case OPT_NOCAPATH:
++            noCApath = 1;
++            break;
++        case OPT_NOCAFILE:
++            noCAfile = 1;
++            break;
++        case OPT_CIPHER:
++            cipher = opt_arg();
++            break;
++        case OPT_BUGS:
++            st_bugs = 1;
++            break;
++        case OPT_TIME:
++            if (!opt_int(opt_arg(), &maxtime))
++                goto opthelp;
++            break;
++        case OPT_WWW:
++            www_path = opt_arg();
++            buf_size = strlen(www_path) + sizeof(fmt_http_get_cmd) - 2;  /* 2 is for %s */
++            if (buf_size > sizeof(buf)) {
++                BIO_printf(bio_err, "%s: -www option is too long\n", prog);
++                goto end;
++            }
++            break;
++        case OPT_SSL3:
++            max_version = SSL3_VERSION;
++            break;
++        }
++    }
++    argc = opt_num_rest();
++    if (argc != 0)
++        goto opthelp;
++
++    if (cipher == NULL)
++        cipher = getenv("SSL_CIPHER");
++    if (cipher == NULL) {
++        BIO_printf(bio_err, "No CIPHER specified\n");
++        goto end;
++    }
++
++    if ((ctx = SSL_CTX_new(meth)) == NULL)
++        goto end;
++
++    SSL_CTX_set_quiet_shutdown(ctx, 1);
++    if (SSL_CTX_set_max_proto_version(ctx, max_version) == 0)
++        goto end;
++
++    if (st_bugs)
++        SSL_CTX_set_options(ctx, SSL_OP_ALL);
++    if (!SSL_CTX_set_cipher_list(ctx, cipher))
++        goto end;
++    if (!set_cert_stuff(ctx, certfile, keyfile))
++        goto end;
++
++    if (!ctx_set_verify_locations(ctx, CAfile, CApath, noCAfile, noCApath)) {
++        ERR_print_errors(bio_err);
++        goto end;
++    }
++    if (!(perform & 1))
++        goto next;
++    printf("Collecting connection statistics for %d seconds\n", maxtime);
++
++    /* Loop and time how long it takes to make connections */
++
++    bytes_read = 0;
++    finishtime = (long)time(NULL) + maxtime;
++    tm_Time_F(START);
++    for (;;) {
++        if (finishtime < (long)time(NULL))
++            break;
++
++        if ((scon = doConnection(NULL, host, ctx)) == NULL)
++            goto end;
++
++        if (www_path != NULL) {
++            buf_len = BIO_snprintf(buf, sizeof buf,
++                                   fmt_http_get_cmd, www_path);
++            if (SSL_write(scon, buf, buf_len) <= 0)
++                goto end;
++            while ((i = SSL_read(scon, buf, sizeof(buf))) > 0)
++                bytes_read += i;
++        }
++#ifdef NO_SHUTDOWN
++        SSL_set_shutdown(scon, SSL_SENT_SHUTDOWN | SSL_RECEIVED_SHUTDOWN);
++#else
++        SSL_shutdown(scon);
++#endif
++        BIO_closesocket(SSL_get_fd(scon));
++
++        nConn += 1;
++        if (SSL_session_reused(scon))
++            ver = 'r';
++        else {
++            ver = SSL_version(scon);
++            if (ver == TLS1_VERSION)
++                ver = 't';
++            else if (ver == SSL3_VERSION)
++                ver = '3';
++            else
++                ver = '*';
++        }
++        fputc(ver, stdout);
++        fflush(stdout);
++
++        SSL_free(scon);
++        scon = NULL;
++    }
++    totalTime += tm_Time_F(STOP); /* Add the time for this iteration */
++
++    i = (int)((long)time(NULL) - finishtime + maxtime);
++    printf
++        ("\n\n%d connections in %.2fs; %.2f connections/user sec, bytes read %ld\n",
++         nConn, totalTime, ((double)nConn / totalTime), bytes_read);
++    printf
++        ("%d connections in %ld real seconds, %ld bytes read per connection\n",
++         nConn, (long)time(NULL) - finishtime + maxtime, bytes_read / nConn);
++
++    /*
++     * Now loop and time connections using the same session id over and over
++     */
++
++ next:
++    if (!(perform & 2))
++        goto end;
++    printf("\n\nNow timing with session id reuse.\n");
++
++    /* Get an SSL object so we can reuse the session id */
++    if ((scon = doConnection(NULL, host, ctx)) == NULL) {
++        BIO_printf(bio_err, "Unable to get connection\n");
++        goto end;
++    }
++
++    if (www_path != NULL) {
++        buf_len = BIO_snprintf(buf, sizeof buf,
++                               fmt_http_get_cmd, www_path);
++        if (SSL_write(scon, buf, buf_len) <= 0)
++            goto end;
++        while (SSL_read(scon, buf, sizeof(buf)) > 0)
++            continue;
++    }
++#ifdef NO_SHUTDOWN
++    SSL_set_shutdown(scon, SSL_SENT_SHUTDOWN | SSL_RECEIVED_SHUTDOWN);
++#else
++    SSL_shutdown(scon);
++#endif
++    BIO_closesocket(SSL_get_fd(scon));
++
++    nConn = 0;
++    totalTime = 0.0;
++
++    finishtime = (long)time(NULL) + maxtime;
++
++    printf("starting\n");
++    bytes_read = 0;
++    tm_Time_F(START);
++
++    for (;;) {
++        if (finishtime < (long)time(NULL))
++            break;
++
++        if ((doConnection(scon, host, ctx)) == NULL)
++            goto end;
++
++        if (www_path) {
++            BIO_snprintf(buf, sizeof buf, "GET %s HTTP/1.0\r\n\r\n",
++                         www_path);
++            if (SSL_write(scon, buf, strlen(buf)) <= 0)
++                goto end;
++            while ((i = SSL_read(scon, buf, sizeof(buf))) > 0)
++                bytes_read += i;
++        }
++#ifdef NO_SHUTDOWN
++        SSL_set_shutdown(scon, SSL_SENT_SHUTDOWN | SSL_RECEIVED_SHUTDOWN);
++#else
++        SSL_shutdown(scon);
++#endif
++        BIO_closesocket(SSL_get_fd(scon));
++
++        nConn += 1;
++        if (SSL_session_reused(scon))
++            ver = 'r';
++        else {
++            ver = SSL_version(scon);
++            if (ver == TLS1_VERSION)
++                ver = 't';
++            else if (ver == SSL3_VERSION)
++                ver = '3';
++            else
++                ver = '*';
++        }
++        fputc(ver, stdout);
++        fflush(stdout);
++    }
++    totalTime += tm_Time_F(STOP); /* Add the time for this iteration */
++
++    printf
++        ("\n\n%d connections in %.2fs; %.2f connections/user sec, bytes read %ld\n",
++         nConn, totalTime, ((double)nConn / totalTime), bytes_read);
++    printf
++        ("%d connections in %ld real seconds, %ld bytes read per connection\n",
++         nConn, (long)time(NULL) - finishtime + maxtime, bytes_read / nConn);
++
++    ret = 0;
++
++ end:
++    SSL_free(scon);
++    SSL_CTX_free(ctx);
++    return (ret);
++}
++
++/*-
++ * doConnection - make a connection
++ */
++static SSL *doConnection(SSL *scon, const char *host, SSL_CTX *ctx)
++{
++    BIO *conn;
++    SSL *serverCon;
++    int width, i;
++    fd_set readfds;
++
++    if ((conn = BIO_new(BIO_s_connect())) == NULL)
++        return (NULL);
++
++    BIO_set_conn_hostname(conn, host);
++
++    if (scon == NULL)
++        serverCon = SSL_new(ctx);
++    else {
++        serverCon = scon;
++        SSL_set_connect_state(serverCon);
++    }
++
++    SSL_set_bio(serverCon, conn, conn);
++
++    /* ok, lets connect */
++    for (;;) {
++        i = SSL_connect(serverCon);
++        if (BIO_sock_should_retry(i)) {
++            BIO_printf(bio_err, "DELAY\n");
++
++            i = SSL_get_fd(serverCon);
++            width = i + 1;
++            FD_ZERO(&readfds);
++            openssl_fdset(i, &readfds);
++            /*
++             * Note: under VMS with SOCKETSHR the 2nd parameter is currently
++             * of type (int *) whereas under other systems it is (void *) if
++             * you don't have a cast it will choke the compiler: if you do
++             * have a cast then you can either go for (int *) or (void *).
++             */
++            select(width, (void *)&readfds, NULL, NULL, NULL);
++            continue;
++        }
++        break;
++    }
++    if (i <= 0) {
++        BIO_printf(bio_err, "ERROR\n");
++        if (verify_args.error != X509_V_OK)
++            BIO_printf(bio_err, "verify error:%s\n",
++                       X509_verify_cert_error_string(verify_args.error));
++        else
++            ERR_print_errors(bio_err);
++        if (scon == NULL)
++            SSL_free(serverCon);
++        return NULL;
++    }
++
++    return serverCon;
++}
++#endif /* OPENSSL_NO_SOCK */
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/apps/server.pem b/CryptoPkg/Library/OpensslLib/openssl/apps/server.pem
+new file mode 100644
+index 0000000..d0fc265
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/apps/server.pem
+@@ -0,0 +1,52 @@
++subject= C = UK, O = OpenSSL Group, OU = FOR TESTING PURPOSES ONLY, CN = Test Server Cert
++issuer= C = UK, O = OpenSSL Group, OU = FOR TESTING PURPOSES ONLY, CN = OpenSSL Test Intermediate CA
++-----BEGIN CERTIFICATE-----
++MIID5zCCAs+gAwIBAgIJALnu1NlVpZ6zMA0GCSqGSIb3DQEBBQUAMHAxCzAJBgNV
++BAYTAlVLMRYwFAYDVQQKDA1PcGVuU1NMIEdyb3VwMSIwIAYDVQQLDBlGT1IgVEVT
++VElORyBQVVJQT1NFUyBPTkxZMSUwIwYDVQQDDBxPcGVuU1NMIFRlc3QgSW50ZXJt
++ZWRpYXRlIENBMB4XDTExMTIwODE0MDE0OFoXDTIxMTAxNjE0MDE0OFowZDELMAkG
++A1UEBhMCVUsxFjAUBgNVBAoMDU9wZW5TU0wgR3JvdXAxIjAgBgNVBAsMGUZPUiBU
++RVNUSU5HIFBVUlBPU0VTIE9OTFkxGTAXBgNVBAMMEFRlc3QgU2VydmVyIENlcnQw
++ggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDzhPOSNtyyRspmeuUpxfNJ
++KCLTuf7g3uQ4zu4iHOmRO5TQci+HhVlLZrHF9XqFXcIP0y4pWDbMSGuiorUmzmfi
++R7bfSdI/+qIQt8KXRH6HNG1t8ou0VSvWId5TS5Dq/er5ODUr9OaaDva7EquHIcMv
++vPQGuI+OEAcnleVCy9HVEIySrO4P3CNIicnGkwwiAud05yUAq/gPXBC1hTtmlPD7
++TVcGVSEiJdvzqqlgv02qedGrkki6GY4S7GjZxrrf7Foc2EP+51LJzwLQx3/JfrCU
++41NEWAsu/Sl0tQabXESN+zJ1pDqoZ3uHMgpQjeGiE0olr+YcsSW/tJmiU9OiAr8R
++AgMBAAGjgY8wgYwwDAYDVR0TAQH/BAIwADAOBgNVHQ8BAf8EBAMCBeAwLAYJYIZI
++AYb4QgENBB8WHU9wZW5TU0wgR2VuZXJhdGVkIENlcnRpZmljYXRlMB0GA1UdDgQW
++BBSCvM8AABPR9zklmifnr9LvIBturDAfBgNVHSMEGDAWgBQ2w2yI55X+sL3szj49
++hqshgYfa2jANBgkqhkiG9w0BAQUFAAOCAQEAqb1NV0B0/pbpK9Z4/bNjzPQLTRLK
++WnSNm/Jh5v0GEUOE/Beg7GNjNrmeNmqxAlpqWz9qoeoFZax+QBpIZYjROU3TS3fp
++yLsrnlr0CDQ5R7kCCDGa8dkXxemmpZZLbUCpW2Uoy8sAA4JjN9OtsZY7dvUXFgJ7
++vVNTRnI01ghknbtD+2SxSQd3CWF6QhcRMAzZJ1z1cbbwGDDzfvGFPzJ+Sq+zEPds
++xoVLLSetCiBc+40ZcDS5dV98h9XD7JMTQfxzA7mNGv73JoZJA6nFgj+ADSlJsY/t
++JBv+z1iQRueoh9Qeee+ZbRifPouCB8FDx+AltvHTANdAq0t/K3o+pplMVA==
++-----END CERTIFICATE-----
++-----BEGIN RSA PRIVATE KEY-----
++MIIEpAIBAAKCAQEA84TzkjbcskbKZnrlKcXzSSgi07n+4N7kOM7uIhzpkTuU0HIv
++h4VZS2axxfV6hV3CD9MuKVg2zEhroqK1Js5n4ke230nSP/qiELfCl0R+hzRtbfKL
++tFUr1iHeU0uQ6v3q+Tg1K/Tmmg72uxKrhyHDL7z0BriPjhAHJ5XlQsvR1RCMkqzu
++D9wjSInJxpMMIgLndOclAKv4D1wQtYU7ZpTw+01XBlUhIiXb86qpYL9NqnnRq5JI
++uhmOEuxo2ca63+xaHNhD/udSyc8C0Md/yX6wlONTRFgLLv0pdLUGm1xEjfsydaQ6
++qGd7hzIKUI3hohNKJa/mHLElv7SZolPTogK/EQIDAQABAoIBAADq9FwNtuE5IRQn
++zGtO4q7Y5uCzZ8GDNYr9RKp+P2cbuWDbvVAecYq2NV9QoIiWJOAYZKklOvekIju3
++r0UZLA0PRiIrTg6NrESx3JrjWDK8QNlUO7CPTZ39/K+FrmMkV9lem9yxjJjyC34D
++AQB+YRTx+l14HppjdxNwHjAVQpIx/uO2F5xAMuk32+3K+pq9CZUtrofe1q4Agj9R
++5s8mSy9pbRo9kW9wl5xdEotz1LivFOEiqPUJTUq5J5PeMKao3vdK726XI4Z455Nm
++W2/MA0YV0ug2FYinHcZdvKM6dimH8GLfa3X8xKRfzjGjTiMSwsdjgMa4awY3tEHH
++674jhAECgYEA/zqMrc0zsbNk83sjgaYIug5kzEpN4ic020rSZsmQxSCerJTgNhmg
++utKSCt0Re09Jt3LqG48msahX8ycqDsHNvlEGPQSbMu9IYeO3Wr3fAm75GEtFWePY
++BhM73I7gkRt4s8bUiUepMG/wY45c5tRF23xi8foReHFFe9MDzh8fJFECgYEA9EFX
++4qAik1pOJGNei9BMwmx0I0gfVEIgu0tzeVqT45vcxbxr7RkTEaDoAG6PlbWP6D9a
++WQNLp4gsgRM90ZXOJ4up5DsAWDluvaF4/omabMA+MJJ5kGZ0gCj5rbZbKqUws7x8
++bp+6iBfUPJUbcqNqFmi/08Yt7vrDnMnyMw2A/sECgYEAiiuRMxnuzVm34hQcsbhH
++6ymVqf7j0PW2qK0F4H1ocT9qhzWFd+RB3kHWrCjnqODQoI6GbGr/4JepHUpre1ex
++4UEN5oSS3G0ru0rC3U4C59dZ5KwDHFm7ffZ1pr52ljfQDUsrjjIMRtuiwNK2OoRa
++WSsqiaL+SDzSB+nBmpnAizECgYBdt/y6rerWUx4MhDwwtTnel7JwHyo2MDFS6/5g
++n8qC2Lj6/fMDRE22w+CA2esp7EJNQJGv+b27iFpbJEDh+/Lf5YzIT4MwVskQ5bYB
++JFcmRxUVmf4e09D7o705U/DjCgMH09iCsbLmqQ38ONIRSHZaJtMDtNTHD1yi+jF+
++OT43gQKBgQC/2OHZoko6iRlNOAQ/tMVFNq7fL81GivoQ9F1U0Qr+DH3ZfaH8eIkX
++xT0ToMPJUzWAn8pZv0snA0um6SIgvkCuxO84OkANCVbttzXImIsL7pFzfcwV/ERK
++UM6j0ZuSMFOCr/lGPAoOQU0fskidGEHi1/kW+suSr28TqsyYZpwBDQ==
++-----END RSA PRIVATE KEY-----
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/apps/server.srl b/CryptoPkg/Library/OpensslLib/openssl/apps/server.srl
+new file mode 100644
+index 0000000..8a0f05e
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/apps/server.srl
+@@ -0,0 +1 @@
++01
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/apps/server2.pem b/CryptoPkg/Library/OpensslLib/openssl/apps/server2.pem
+new file mode 100644
+index 0000000..a3927cf
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/apps/server2.pem
+@@ -0,0 +1,52 @@
++subject= C = UK, O = OpenSSL Group, OU = FOR TESTING PURPOSES ONLY, CN = Test Server Cert #2
++issuer= C = UK, O = OpenSSL Group, OU = FOR TESTING PURPOSES ONLY, CN = OpenSSL Test Intermediate CA
++-----BEGIN CERTIFICATE-----
++MIID6jCCAtKgAwIBAgIJALnu1NlVpZ60MA0GCSqGSIb3DQEBBQUAMHAxCzAJBgNV
++BAYTAlVLMRYwFAYDVQQKDA1PcGVuU1NMIEdyb3VwMSIwIAYDVQQLDBlGT1IgVEVT
++VElORyBQVVJQT1NFUyBPTkxZMSUwIwYDVQQDDBxPcGVuU1NMIFRlc3QgSW50ZXJt
++ZWRpYXRlIENBMB4XDTExMTIwODE0MDE0OFoXDTIxMTAxNjE0MDE0OFowZzELMAkG
++A1UEBhMCVUsxFjAUBgNVBAoMDU9wZW5TU0wgR3JvdXAxIjAgBgNVBAsMGUZPUiBU
++RVNUSU5HIFBVUlBPU0VTIE9OTFkxHDAaBgNVBAMME1Rlc3QgU2VydmVyIENlcnQg
++IzIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDrdi7j9yctG+L4EjBy
++gjPmEqZzOJEQba26MoQGzglU7e5Xf59Rb/hgVQuKAoiZe7/R8rK4zJ4W7iXdXw0L
++qBpyG8B5aGKeI32w+A9TcBApoXXL2CrYQEQjZwUIpLlYBIi2NkJj3nVkq5dgl1gO
++ALiQ+W8jg3kzg5Ec9rimp9r93N8wsSL3awsafurmYCvOf7leHaMP1WJ/zDRGUNHG
++/WtDjXc8ZUG1+6EXU9Jc2Fs+2Omf7fcN0l00AK/wPg8OaNS0rKyGq9JdIT9FRGV1
++bXe/rx58FaE5CItdwCSYhJvF/O95LWQoxJXye5bCFLmvDTEyVq9FMSCptfsmbXjE
++ZGsXAgMBAAGjgY8wgYwwDAYDVR0TAQH/BAIwADAOBgNVHQ8BAf8EBAMCBeAwLAYJ
++YIZIAYb4QgENBB8WHU9wZW5TU0wgR2VuZXJhdGVkIENlcnRpZmljYXRlMB0GA1Ud
++DgQWBBR52UaWWTKzZGDH/X4mWNcuqeQVazAfBgNVHSMEGDAWgBQ2w2yI55X+sL3s
++zj49hqshgYfa2jANBgkqhkiG9w0BAQUFAAOCAQEANBW+XYLlHBqVY/31ie+3gRlS
++LPfy4SIqn0t3RJjagT29MXprblBO2cbMO8VGjkQdKGpmMXjxbht2arOOUXRHX4n/
++XTyn/QHEf0bcwIITMReO3DZUPAEw8hSjn9xEOM0IRVOCP+mH5fi74QzzQaZVCyYg
++5VtLKdww/+sc0nCbKl2KWgDluriH0nfVx95qgW3mg9dhXRr0zmf1w2zkBHYpARYL
++Dew6Z8EE4tS3HJu8/qM6meWzNtrfonQ3eiiMxjZBxzV46jchBwa2z9XYhP6AmpPb
++oeTSzcQNbWsxaGYzWo46oLDUZmJOwSBawbS31bZNMCoPIY6ukoesCzFSsUKZww==
++-----END CERTIFICATE-----
++-----BEGIN RSA PRIVATE KEY-----
++MIIEowIBAAKCAQEA63Yu4/cnLRvi+BIwcoIz5hKmcziREG2tujKEBs4JVO3uV3+f
++UW/4YFULigKImXu/0fKyuMyeFu4l3V8NC6gachvAeWhiniN9sPgPU3AQKaF1y9gq
++2EBEI2cFCKS5WASItjZCY951ZKuXYJdYDgC4kPlvI4N5M4ORHPa4pqfa/dzfMLEi
++92sLGn7q5mArzn+5Xh2jD9Vif8w0RlDRxv1rQ413PGVBtfuhF1PSXNhbPtjpn+33
++DdJdNACv8D4PDmjUtKyshqvSXSE/RURldW13v68efBWhOQiLXcAkmISbxfzveS1k
++KMSV8nuWwhS5rw0xMlavRTEgqbX7Jm14xGRrFwIDAQABAoIBAHLsTPihIfLnYIE5
++x4GsQQ5zXeBw5ITDM37ktwHnQDC+rIzyUl1aLD1AZRBoKinXd4lOTqLZ4/NHKx4A
++DYr58mZtWyUmqLOMmQVuHXTZBlp7XtYuXMMNovQwjQlp9LicBeoBU6gQ5PVMtubD
++F4xGF89Sn0cTHW3iMkqTtQ5KcR1j57OcJO0FEb1vPvk2MXI5ZyAatUYE7YacbEzd
++rg02uIwx3FqNSkuSI79uz4hMdV5TPtuhxx9nTwj9aLUhXFeZ0mn2PVgVzEnnMoJb
+++znlsZDgzDlJqdaD744YGWh8Z3OEssB35KfzFcdOeO6yH8lmv2Zfznk7pNPT7LTb
++Lae9VgkCgYEA92p1qnAB3NtJtNcaW53i0S5WJgS1hxWKvUDx3lTB9s8X9fHpqL1a
++E94fDfWzp/hax6FefUKIvBOukPLQ6bYjTMiFoOHzVirghAIuIUoMI5VtLhwD1hKs
++Lr7l/dptMgKb1nZHyXoKHRBthsy3K4+udsPi8TzMvYElgEqyQIe/Rk0CgYEA86GL
++8HC6zLszzKERDPBxrboRmoFvVUCTQDhsfj1M8aR3nQ8V5LkdIJc7Wqm/Ggfk9QRf
++rJ8M2WUMlU5CNnCn/KCrKzCNZIReze3fV+HnKdbcXGLvgbHPrhnz8yYehUFG+RGq
++bVyDWRU94T38izy2s5qMYrMJWZEYyXncSPbfcPMCgYAtaXfxcZ+V5xYPQFARMtiX
++5nZfggvDoJuXgx0h3tK/N2HBfcaSdzbaYLG4gTmZggc/jwnl2dl5E++9oSPhUdIG
++3ONSFUbxsOsGr9PBvnKd8WZZyUCXAVRjPBzAzF+whzQNWCZy/5htnz9LN7YDI9s0
++5113Q96cheDZPFydZY0hHQKBgQDVbEhNukM5xCiNcu+f2SaMnLp9EjQ4h5g3IvaP
++5B16daw/Dw8LzcohWboqIxeAsze0GD/D1ZUJAEd0qBjC3g+a9BjefervCjKOzXng
++38mEUm+6EwVjJSQcjSmycEs+Sr/kwr/8i5WYvU32+jk4tFgMoC+o6tQe/Uesf68k
++z/dPVwKBgGbF7Vv1/3SmhlOy+zYyvJ0CrWtKxH9QP6tLIEgEpd8x7YTSuCH94yok
++kToMXYA3sWNPt22GbRDZ+rcp4c7HkDx6I6vpdP9aQEwJTp0EPy0sgWr2XwYmreIQ
++NFmkk8Itn9EY2R9VBaP7GLv5kvwxDdLAnmwGmzVtbmaVdxCaBwUk
++-----END RSA PRIVATE KEY-----
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/apps/sess_id.c b/CryptoPkg/Library/OpensslLib/openssl/apps/sess_id.c
+new file mode 100644
+index 0000000..2b63e69
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/apps/sess_id.c
+@@ -0,0 +1,190 @@
++/*
++ * Copyright 1995-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include 
++#include 
++#include "apps.h"
++#include 
++#include 
++#include 
++#include 
++#include 
++
++typedef enum OPTION_choice {
++    OPT_ERR = -1, OPT_EOF = 0, OPT_HELP,
++    OPT_INFORM, OPT_OUTFORM, OPT_IN, OPT_OUT,
++    OPT_TEXT, OPT_CERT, OPT_NOOUT, OPT_CONTEXT
++} OPTION_CHOICE;
++
++OPTIONS sess_id_options[] = {
++    {"help", OPT_HELP, '-', "Display this summary"},
++    {"inform", OPT_INFORM, 'F', "Input format - default PEM (DER or PEM)"},
++    {"outform", OPT_OUTFORM, 'f',
++     "Output format - default PEM (PEM, DER or NSS)"},
++    {"in", OPT_IN, 's', "Input file - default stdin"},
++    {"out", OPT_OUT, 's', "Output file - default stdout"},
++    {"text", OPT_TEXT, '-', "Print ssl session id details"},
++    {"cert", OPT_CERT, '-', "Output certificate "},
++    {"noout", OPT_NOOUT, '-', "Don't output the encoded session info"},
++    {"context", OPT_CONTEXT, 's', "Set the session ID context"},
++    {NULL}
++};
++
++static SSL_SESSION *load_sess_id(char *file, int format);
++
++int sess_id_main(int argc, char **argv)
++{
++    SSL_SESSION *x = NULL;
++    X509 *peer = NULL;
++    BIO *out = NULL;
++    char *infile = NULL, *outfile = NULL, *context = NULL, *prog;
++    int informat = FORMAT_PEM, outformat = FORMAT_PEM;
++    int cert = 0, noout = 0, text = 0, ret = 1, i, num = 0;
++    OPTION_CHOICE o;
++
++    prog = opt_init(argc, argv, sess_id_options);
++    while ((o = opt_next()) != OPT_EOF) {
++        switch (o) {
++        case OPT_EOF:
++        case OPT_ERR:
++ opthelp:
++            BIO_printf(bio_err, "%s: Use -help for summary.\n", prog);
++            goto end;
++        case OPT_HELP:
++            opt_help(sess_id_options);
++            ret = 0;
++            goto end;
++        case OPT_INFORM:
++            if (!opt_format(opt_arg(), OPT_FMT_PEMDER, &informat))
++                goto opthelp;
++            break;
++        case OPT_OUTFORM:
++            if (!opt_format(opt_arg(), OPT_FMT_PEMDER | OPT_FMT_NSS,
++                            &outformat))
++                goto opthelp;
++            break;
++        case OPT_IN:
++            infile = opt_arg();
++            break;
++        case OPT_OUT:
++            outfile = opt_arg();
++            break;
++        case OPT_TEXT:
++            text = ++num;
++            break;
++        case OPT_CERT:
++            cert = ++num;
++            break;
++        case OPT_NOOUT:
++            noout = ++num;
++            break;
++        case OPT_CONTEXT:
++            context = opt_arg();
++            break;
++        }
++    }
++    argc = opt_num_rest();
++    if (argc != 0)
++        goto opthelp;
++
++    x = load_sess_id(infile, informat);
++    if (x == NULL) {
++        goto end;
++    }
++    peer = SSL_SESSION_get0_peer(x);
++
++    if (context) {
++        size_t ctx_len = strlen(context);
++        if (ctx_len > SSL_MAX_SID_CTX_LENGTH) {
++            BIO_printf(bio_err, "Context too long\n");
++            goto end;
++        }
++        if (!SSL_SESSION_set1_id_context(x, (unsigned char *)context,
++                    ctx_len)) {
++            BIO_printf(bio_err, "Error setting id context\n");
++            goto end;
++        }
++    }
++
++    if (!noout || text) {
++        out = bio_open_default(outfile, 'w', outformat);
++        if (out == NULL)
++            goto end;
++    }
++
++    if (text) {
++        SSL_SESSION_print(out, x);
++
++        if (cert) {
++            if (peer == NULL)
++                BIO_puts(out, "No certificate present\n");
++            else
++                X509_print(out, peer);
++        }
++    }
++
++    if (!noout && !cert) {
++        if (outformat == FORMAT_ASN1)
++            i = i2d_SSL_SESSION_bio(out, x);
++        else if (outformat == FORMAT_PEM)
++            i = PEM_write_bio_SSL_SESSION(out, x);
++        else if (outformat == FORMAT_NSS)
++            i = SSL_SESSION_print_keylog(out, x);
++        else {
++            BIO_printf(bio_err, "bad output format specified for outfile\n");
++            goto end;
++        }
++        if (!i) {
++            BIO_printf(bio_err, "unable to write SSL_SESSION\n");
++            goto end;
++        }
++    } else if (!noout && (peer != NULL)) { /* just print the certificate */
++        if (outformat == FORMAT_ASN1)
++            i = (int)i2d_X509_bio(out, peer);
++        else if (outformat == FORMAT_PEM)
++            i = PEM_write_bio_X509(out, peer);
++        else {
++            BIO_printf(bio_err, "bad output format specified for outfile\n");
++            goto end;
++        }
++        if (!i) {
++            BIO_printf(bio_err, "unable to write X509\n");
++            goto end;
++        }
++    }
++    ret = 0;
++ end:
++    BIO_free_all(out);
++    SSL_SESSION_free(x);
++    return (ret);
++}
++
++static SSL_SESSION *load_sess_id(char *infile, int format)
++{
++    SSL_SESSION *x = NULL;
++    BIO *in = NULL;
++
++    in = bio_open_default(infile, 'r', format);
++    if (in == NULL)
++        goto end;
++    if (format == FORMAT_ASN1)
++        x = d2i_SSL_SESSION_bio(in, NULL);
++    else
++        x = PEM_read_bio_SSL_SESSION(in, NULL, NULL, NULL);
++    if (x == NULL) {
++        BIO_printf(bio_err, "unable to load SSL_SESSION\n");
++        ERR_print_errors(bio_err);
++        goto end;
++    }
++
++ end:
++    BIO_free(in);
++    return (x);
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/apps/smime.c b/CryptoPkg/Library/OpensslLib/openssl/apps/smime.c
+new file mode 100644
+index 0000000..caa9252
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/apps/smime.c
+@@ -0,0 +1,656 @@
++/*
++ * Copyright 1999-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++/* S/MIME utility function */
++
++#include 
++#include 
++#include "apps.h"
++#include 
++#include 
++#include 
++#include 
++#include 
++
++static int save_certs(char *signerfile, STACK_OF(X509) *signers);
++static int smime_cb(int ok, X509_STORE_CTX *ctx);
++
++#define SMIME_OP        0x10
++#define SMIME_IP        0x20
++#define SMIME_SIGNERS   0x40
++#define SMIME_ENCRYPT   (1 | SMIME_OP)
++#define SMIME_DECRYPT   (2 | SMIME_IP)
++#define SMIME_SIGN      (3 | SMIME_OP | SMIME_SIGNERS)
++#define SMIME_VERIFY    (4 | SMIME_IP)
++#define SMIME_PK7OUT    (5 | SMIME_IP | SMIME_OP)
++#define SMIME_RESIGN    (6 | SMIME_IP | SMIME_OP | SMIME_SIGNERS)
++
++typedef enum OPTION_choice {
++    OPT_ERR = -1, OPT_EOF = 0, OPT_HELP,
++    OPT_ENCRYPT, OPT_DECRYPT, OPT_SIGN, OPT_RESIGN, OPT_VERIFY,
++    OPT_PK7OUT, OPT_TEXT, OPT_NOINTERN, OPT_NOVERIFY, OPT_NOCHAIN,
++    OPT_NOCERTS, OPT_NOATTR, OPT_NODETACH, OPT_NOSMIMECAP,
++    OPT_BINARY, OPT_NOSIGS, OPT_STREAM, OPT_INDEF, OPT_NOINDEF,
++    OPT_CRLFEOL, OPT_RAND, OPT_ENGINE, OPT_PASSIN,
++    OPT_TO, OPT_FROM, OPT_SUBJECT, OPT_SIGNER, OPT_RECIP, OPT_MD,
++    OPT_CIPHER, OPT_INKEY, OPT_KEYFORM, OPT_CERTFILE, OPT_CAFILE,
++    OPT_V_ENUM,
++    OPT_CAPATH, OPT_NOCAFILE, OPT_NOCAPATH, OPT_IN, OPT_INFORM, OPT_OUT,
++    OPT_OUTFORM, OPT_CONTENT
++} OPTION_CHOICE;
++
++OPTIONS smime_options[] = {
++    {OPT_HELP_STR, 1, '-', "Usage: %s [options] cert.pem...\n"},
++    {OPT_HELP_STR, 1, '-',
++        "  cert.pem... recipient certs for encryption\n"},
++    {OPT_HELP_STR, 1, '-', "Valid options are:\n"},
++    {"help", OPT_HELP, '-', "Display this summary"},
++    {"encrypt", OPT_ENCRYPT, '-', "Encrypt message"},
++    {"decrypt", OPT_DECRYPT, '-', "Decrypt encrypted message"},
++    {"sign", OPT_SIGN, '-', "Sign message"},
++    {"verify", OPT_VERIFY, '-', "Verify signed message"},
++    {"pk7out", OPT_PK7OUT, '-', "Output PKCS#7 structure"},
++    {"nointern", OPT_NOINTERN, '-',
++     "Don't search certificates in message for signer"},
++    {"nosigs", OPT_NOSIGS, '-', "Don't verify message signature"},
++    {"noverify", OPT_NOVERIFY, '-', "Don't verify signers certificate"},
++    {"nocerts", OPT_NOCERTS, '-',
++     "Don't include signers certificate when signing"},
++    {"nodetach", OPT_NODETACH, '-', "Use opaque signing"},
++    {"noattr", OPT_NOATTR, '-', "Don't include any signed attributes"},
++    {"binary", OPT_BINARY, '-', "Don't translate message to text"},
++    {"certfile", OPT_CERTFILE, '<', "Other certificates file"},
++    {"signer", OPT_SIGNER, 's', "Signer certificate file"},
++    {"recip", OPT_RECIP, '<', "Recipient certificate file for decryption"},
++    {"in", OPT_IN, '<', "Input file"},
++    {"inform", OPT_INFORM, 'c', "Input format SMIME (default), PEM or DER"},
++    {"inkey", OPT_INKEY, '<',
++     "Input private key (if not signer or recipient)"},
++    {"keyform", OPT_KEYFORM, 'f', "Input private key format (PEM or ENGINE)"},
++    {"out", OPT_OUT, '>', "Output file"},
++    {"outform", OPT_OUTFORM, 'c',
++     "Output format SMIME (default), PEM or DER"},
++    {"content", OPT_CONTENT, '<',
++     "Supply or override content for detached signature"},
++    {"to", OPT_TO, 's', "To address"},
++    {"from", OPT_FROM, 's', "From address"},
++    {"subject", OPT_SUBJECT, 's', "Subject"},
++    {"text", OPT_TEXT, '-', "Include or delete text MIME headers"},
++    {"CApath", OPT_CAPATH, '/', "Trusted certificates directory"},
++    {"CAfile", OPT_CAFILE, '<', "Trusted certificates file"},
++    {"no-CAfile", OPT_NOCAFILE, '-',
++     "Do not load the default certificates file"},
++    {"no-CApath", OPT_NOCAPATH, '-',
++     "Do not load certificates from the default certificates directory"},
++    {"resign", OPT_RESIGN, '-', "Resign a signed message"},
++    {"nochain", OPT_NOCHAIN, '-', 
++     "set PKCS7_NOCHAIN so certificates contained in the message are not used as untrusted CAs" },
++    {"nosmimecap", OPT_NOSMIMECAP, '-', "Omit the SMIMECapabilities attribute"},
++    {"stream", OPT_STREAM, '-', "Enable CMS streaming" },
++    {"indef", OPT_INDEF, '-', "Same as -stream" },
++    {"noindef", OPT_NOINDEF, '-', "Disable CMS streaming"},
++    {"crlfeol", OPT_CRLFEOL, '-', "Use CRLF as EOL termination instead of CR only"},
++    {"rand", OPT_RAND, 's',
++     "Load the file(s) into the random number generator"},
++    {"passin", OPT_PASSIN, 's', "Input file pass phrase source"},
++    {"md", OPT_MD, 's', "Digest algorithm to use when signing or resigning"},
++    {"", OPT_CIPHER, '-', "Any supported cipher"},
++    OPT_V_OPTIONS,
++#ifndef OPENSSL_NO_ENGINE
++    {"engine", OPT_ENGINE, 's', "Use engine, possibly a hardware device"},
++#endif
++    {NULL}
++};
++
++int smime_main(int argc, char **argv)
++{
++    BIO *in = NULL, *out = NULL, *indata = NULL;
++    EVP_PKEY *key = NULL;
++    PKCS7 *p7 = NULL;
++    STACK_OF(OPENSSL_STRING) *sksigners = NULL, *skkeys = NULL;
++    STACK_OF(X509) *encerts = NULL, *other = NULL;
++    X509 *cert = NULL, *recip = NULL, *signer = NULL;
++    X509_STORE *store = NULL;
++    X509_VERIFY_PARAM *vpm = NULL;
++    const EVP_CIPHER *cipher = NULL;
++    const EVP_MD *sign_md = NULL;
++    const char *CAfile = NULL, *CApath = NULL, *prog = NULL;
++    char *certfile = NULL, *keyfile = NULL, *contfile = NULL, *inrand = NULL;
++    char *infile = NULL, *outfile = NULL, *signerfile = NULL, *recipfile =
++        NULL;
++    char *passinarg = NULL, *passin = NULL, *to = NULL, *from =
++        NULL, *subject = NULL;
++    OPTION_CHOICE o;
++    int noCApath = 0, noCAfile = 0;
++    int flags = PKCS7_DETACHED, operation = 0, ret = 0, need_rand = 0, indef =
++        0;
++    int informat = FORMAT_SMIME, outformat = FORMAT_SMIME, keyform =
++        FORMAT_PEM;
++    int vpmtouched = 0, rv = 0;
++    ENGINE *e = NULL;
++    const char *mime_eol = "\n";
++
++    if ((vpm = X509_VERIFY_PARAM_new()) == NULL)
++        return 1;
++
++    prog = opt_init(argc, argv, smime_options);
++    while ((o = opt_next()) != OPT_EOF) {
++        switch (o) {
++        case OPT_EOF:
++        case OPT_ERR:
++ opthelp:
++            BIO_printf(bio_err, "%s: Use -help for summary.\n", prog);
++            goto end;
++        case OPT_HELP:
++            opt_help(smime_options);
++            ret = 0;
++            goto end;
++        case OPT_INFORM:
++            if (!opt_format(opt_arg(), OPT_FMT_PDS, &informat))
++                goto opthelp;
++            break;
++        case OPT_IN:
++            infile = opt_arg();
++            break;
++        case OPT_OUTFORM:
++            if (!opt_format(opt_arg(), OPT_FMT_PDS, &outformat))
++                goto opthelp;
++            break;
++        case OPT_OUT:
++            outfile = opt_arg();
++            break;
++        case OPT_ENCRYPT:
++            operation = SMIME_ENCRYPT;
++            break;
++        case OPT_DECRYPT:
++            operation = SMIME_DECRYPT;
++            break;
++        case OPT_SIGN:
++            operation = SMIME_SIGN;
++            break;
++        case OPT_RESIGN:
++            operation = SMIME_RESIGN;
++            break;
++        case OPT_VERIFY:
++            operation = SMIME_VERIFY;
++            break;
++        case OPT_PK7OUT:
++            operation = SMIME_PK7OUT;
++            break;
++        case OPT_TEXT:
++            flags |= PKCS7_TEXT;
++            break;
++        case OPT_NOINTERN:
++            flags |= PKCS7_NOINTERN;
++            break;
++        case OPT_NOVERIFY:
++            flags |= PKCS7_NOVERIFY;
++            break;
++        case OPT_NOCHAIN:
++            flags |= PKCS7_NOCHAIN;
++            break;
++        case OPT_NOCERTS:
++            flags |= PKCS7_NOCERTS;
++            break;
++        case OPT_NOATTR:
++            flags |= PKCS7_NOATTR;
++            break;
++        case OPT_NODETACH:
++            flags &= ~PKCS7_DETACHED;
++            break;
++        case OPT_NOSMIMECAP:
++            flags |= PKCS7_NOSMIMECAP;
++            break;
++        case OPT_BINARY:
++            flags |= PKCS7_BINARY;
++            break;
++        case OPT_NOSIGS:
++            flags |= PKCS7_NOSIGS;
++            break;
++        case OPT_STREAM:
++        case OPT_INDEF:
++            indef = 1;
++            break;
++        case OPT_NOINDEF:
++            indef = 0;
++            break;
++        case OPT_CRLFEOL:
++            flags |= PKCS7_CRLFEOL;
++            mime_eol = "\r\n";
++            break;
++        case OPT_RAND:
++            inrand = opt_arg();
++            need_rand = 1;
++            break;
++        case OPT_ENGINE:
++            e = setup_engine(opt_arg(), 0);
++            break;
++        case OPT_PASSIN:
++            passinarg = opt_arg();
++            break;
++        case OPT_TO:
++            to = opt_arg();
++            break;
++        case OPT_FROM:
++            from = opt_arg();
++            break;
++        case OPT_SUBJECT:
++            subject = opt_arg();
++            break;
++        case OPT_SIGNER:
++            /* If previous -signer argument add signer to list */
++            if (signerfile) {
++                if (sksigners == NULL
++                    && (sksigners = sk_OPENSSL_STRING_new_null()) == NULL)
++                    goto end;
++                sk_OPENSSL_STRING_push(sksigners, signerfile);
++                if (keyfile == NULL)
++                    keyfile = signerfile;
++                if (skkeys == NULL
++                    && (skkeys = sk_OPENSSL_STRING_new_null()) == NULL)
++                    goto end;
++                sk_OPENSSL_STRING_push(skkeys, keyfile);
++                keyfile = NULL;
++            }
++            signerfile = opt_arg();
++            break;
++        case OPT_RECIP:
++            recipfile = opt_arg();
++            break;
++        case OPT_MD:
++            if (!opt_md(opt_arg(), &sign_md))
++                goto opthelp;
++            break;
++        case OPT_CIPHER:
++            if (!opt_cipher(opt_unknown(), &cipher))
++                goto opthelp;
++            break;
++        case OPT_INKEY:
++            /* If previous -inkey argument add signer to list */
++            if (keyfile) {
++                if (signerfile == NULL) {
++                    BIO_printf(bio_err,
++                               "%s: Must have -signer before -inkey\n", prog);
++                    goto opthelp;
++                }
++                if (sksigners == NULL
++                    && (sksigners = sk_OPENSSL_STRING_new_null()) == NULL)
++                    goto end;
++                sk_OPENSSL_STRING_push(sksigners, signerfile);
++                signerfile = NULL;
++                if (skkeys == NULL
++                    && (skkeys = sk_OPENSSL_STRING_new_null()) == NULL)
++                    goto end;
++                sk_OPENSSL_STRING_push(skkeys, keyfile);
++            }
++            keyfile = opt_arg();
++            break;
++        case OPT_KEYFORM:
++            if (!opt_format(opt_arg(), OPT_FMT_ANY, &keyform))
++                goto opthelp;
++            break;
++        case OPT_CERTFILE:
++            certfile = opt_arg();
++            break;
++        case OPT_CAFILE:
++            CAfile = opt_arg();
++            break;
++        case OPT_CAPATH:
++            CApath = opt_arg();
++            break;
++        case OPT_NOCAFILE:
++            noCAfile = 1;
++            break;
++        case OPT_NOCAPATH:
++            noCApath = 1;
++            break;
++        case OPT_CONTENT:
++            contfile = opt_arg();
++            break;
++        case OPT_V_CASES:
++            if (!opt_verify(o, vpm))
++                goto opthelp;
++            vpmtouched++;
++            break;
++        }
++    }
++    argc = opt_num_rest();
++    argv = opt_rest();
++
++    if (!(operation & SMIME_SIGNERS) && (skkeys || sksigners)) {
++        BIO_puts(bio_err, "Multiple signers or keys not allowed\n");
++        goto opthelp;
++    }
++
++    if (operation & SMIME_SIGNERS) {
++        /* Check to see if any final signer needs to be appended */
++        if (keyfile && !signerfile) {
++            BIO_puts(bio_err, "Illegal -inkey without -signer\n");
++            goto opthelp;
++        }
++        if (signerfile) {
++            if (!sksigners
++                && (sksigners = sk_OPENSSL_STRING_new_null()) == NULL)
++                goto end;
++            sk_OPENSSL_STRING_push(sksigners, signerfile);
++            if (!skkeys && (skkeys = sk_OPENSSL_STRING_new_null()) == NULL)
++                goto end;
++            if (!keyfile)
++                keyfile = signerfile;
++            sk_OPENSSL_STRING_push(skkeys, keyfile);
++        }
++        if (!sksigners) {
++            BIO_printf(bio_err, "No signer certificate specified\n");
++            goto opthelp;
++        }
++        signerfile = NULL;
++        keyfile = NULL;
++        need_rand = 1;
++    } else if (operation == SMIME_DECRYPT) {
++        if (!recipfile && !keyfile) {
++            BIO_printf(bio_err,
++                       "No recipient certificate or key specified\n");
++            goto opthelp;
++        }
++    } else if (operation == SMIME_ENCRYPT) {
++        if (argc == 0) {
++            BIO_printf(bio_err, "No recipient(s) certificate(s) specified\n");
++            goto opthelp;
++        }
++        need_rand = 1;
++    } else if (!operation)
++        goto opthelp;
++
++    if (!app_passwd(passinarg, NULL, &passin, NULL)) {
++        BIO_printf(bio_err, "Error getting password\n");
++        goto end;
++    }
++
++    if (need_rand) {
++        app_RAND_load_file(NULL, (inrand != NULL));
++        if (inrand != NULL)
++            BIO_printf(bio_err, "%ld semi-random bytes loaded\n",
++                       app_RAND_load_files(inrand));
++    }
++
++    ret = 2;
++
++    if (!(operation & SMIME_SIGNERS))
++        flags &= ~PKCS7_DETACHED;
++
++    if (!(operation & SMIME_OP)) {
++        if (flags & PKCS7_BINARY)
++            outformat = FORMAT_BINARY;
++    }
++
++    if (!(operation & SMIME_IP)) {
++        if (flags & PKCS7_BINARY)
++            informat = FORMAT_BINARY;
++    }
++
++    if (operation == SMIME_ENCRYPT) {
++        if (!cipher) {
++#ifndef OPENSSL_NO_DES
++            cipher = EVP_des_ede3_cbc();
++#else
++            BIO_printf(bio_err, "No cipher selected\n");
++            goto end;
++#endif
++        }
++        encerts = sk_X509_new_null();
++        if (!encerts)
++            goto end;
++        while (*argv) {
++            cert = load_cert(*argv, FORMAT_PEM,
++                             "recipient certificate file");
++            if (cert == NULL)
++                goto end;
++            sk_X509_push(encerts, cert);
++            cert = NULL;
++            argv++;
++        }
++    }
++
++    if (certfile) {
++        if (!load_certs(certfile, &other, FORMAT_PEM, NULL,
++                        "certificate file")) {
++            ERR_print_errors(bio_err);
++            goto end;
++        }
++    }
++
++    if (recipfile && (operation == SMIME_DECRYPT)) {
++        if ((recip = load_cert(recipfile, FORMAT_PEM,
++                               "recipient certificate file")) == NULL) {
++            ERR_print_errors(bio_err);
++            goto end;
++        }
++    }
++
++    if (operation == SMIME_DECRYPT) {
++        if (!keyfile)
++            keyfile = recipfile;
++    } else if (operation == SMIME_SIGN) {
++        if (!keyfile)
++            keyfile = signerfile;
++    } else
++        keyfile = NULL;
++
++    if (keyfile) {
++        key = load_key(keyfile, keyform, 0, passin, e, "signing key file");
++        if (!key)
++            goto end;
++    }
++
++    in = bio_open_default(infile, 'r', informat);
++    if (in == NULL)
++        goto end;
++
++    if (operation & SMIME_IP) {
++        if (informat == FORMAT_SMIME)
++            p7 = SMIME_read_PKCS7(in, &indata);
++        else if (informat == FORMAT_PEM)
++            p7 = PEM_read_bio_PKCS7(in, NULL, NULL, NULL);
++        else if (informat == FORMAT_ASN1)
++            p7 = d2i_PKCS7_bio(in, NULL);
++        else {
++            BIO_printf(bio_err, "Bad input format for PKCS#7 file\n");
++            goto end;
++        }
++
++        if (!p7) {
++            BIO_printf(bio_err, "Error reading S/MIME message\n");
++            goto end;
++        }
++        if (contfile) {
++            BIO_free(indata);
++            if ((indata = BIO_new_file(contfile, "rb")) == NULL) {
++                BIO_printf(bio_err, "Can't read content file %s\n", contfile);
++                goto end;
++            }
++        }
++    }
++
++    out = bio_open_default(outfile, 'w', outformat);
++    if (out == NULL)
++        goto end;
++
++    if (operation == SMIME_VERIFY) {
++        if ((store = setup_verify(CAfile, CApath, noCAfile, noCApath)) == NULL)
++            goto end;
++        X509_STORE_set_verify_cb(store, smime_cb);
++        if (vpmtouched)
++            X509_STORE_set1_param(store, vpm);
++    }
++
++    ret = 3;
++
++    if (operation == SMIME_ENCRYPT) {
++        if (indef)
++            flags |= PKCS7_STREAM;
++        p7 = PKCS7_encrypt(encerts, in, cipher, flags);
++    } else if (operation & SMIME_SIGNERS) {
++        int i;
++        /*
++         * If detached data content we only enable streaming if S/MIME output
++         * format.
++         */
++        if (operation == SMIME_SIGN) {
++            if (flags & PKCS7_DETACHED) {
++                if (outformat == FORMAT_SMIME)
++                    flags |= PKCS7_STREAM;
++            } else if (indef)
++                flags |= PKCS7_STREAM;
++            flags |= PKCS7_PARTIAL;
++            p7 = PKCS7_sign(NULL, NULL, other, in, flags);
++            if (!p7)
++                goto end;
++            if (flags & PKCS7_NOCERTS) {
++                for (i = 0; i < sk_X509_num(other); i++) {
++                    X509 *x = sk_X509_value(other, i);
++                    PKCS7_add_certificate(p7, x);
++                }
++            }
++        } else
++            flags |= PKCS7_REUSE_DIGEST;
++        for (i = 0; i < sk_OPENSSL_STRING_num(sksigners); i++) {
++            signerfile = sk_OPENSSL_STRING_value(sksigners, i);
++            keyfile = sk_OPENSSL_STRING_value(skkeys, i);
++            signer = load_cert(signerfile, FORMAT_PEM,
++                               "signer certificate");
++            if (!signer)
++                goto end;
++            key = load_key(keyfile, keyform, 0, passin, e, "signing key file");
++            if (!key)
++                goto end;
++            if (!PKCS7_sign_add_signer(p7, signer, key, sign_md, flags))
++                goto end;
++            X509_free(signer);
++            signer = NULL;
++            EVP_PKEY_free(key);
++            key = NULL;
++        }
++        /* If not streaming or resigning finalize structure */
++        if ((operation == SMIME_SIGN) && !(flags & PKCS7_STREAM)) {
++            if (!PKCS7_final(p7, in, flags))
++                goto end;
++        }
++    }
++
++    if (!p7) {
++        BIO_printf(bio_err, "Error creating PKCS#7 structure\n");
++        goto end;
++    }
++
++    ret = 4;
++    if (operation == SMIME_DECRYPT) {
++        if (!PKCS7_decrypt(p7, key, recip, out, flags)) {
++            BIO_printf(bio_err, "Error decrypting PKCS#7 structure\n");
++            goto end;
++        }
++    } else if (operation == SMIME_VERIFY) {
++        STACK_OF(X509) *signers;
++        if (PKCS7_verify(p7, other, store, indata, out, flags))
++            BIO_printf(bio_err, "Verification successful\n");
++        else {
++            BIO_printf(bio_err, "Verification failure\n");
++            goto end;
++        }
++        signers = PKCS7_get0_signers(p7, other, flags);
++        if (!save_certs(signerfile, signers)) {
++            BIO_printf(bio_err, "Error writing signers to %s\n", signerfile);
++            ret = 5;
++            goto end;
++        }
++        sk_X509_free(signers);
++    } else if (operation == SMIME_PK7OUT)
++        PEM_write_bio_PKCS7(out, p7);
++    else {
++        if (to)
++            BIO_printf(out, "To: %s%s", to, mime_eol);
++        if (from)
++            BIO_printf(out, "From: %s%s", from, mime_eol);
++        if (subject)
++            BIO_printf(out, "Subject: %s%s", subject, mime_eol);
++        if (outformat == FORMAT_SMIME) {
++            if (operation == SMIME_RESIGN)
++                rv = SMIME_write_PKCS7(out, p7, indata, flags);
++            else
++                rv = SMIME_write_PKCS7(out, p7, in, flags);
++        } else if (outformat == FORMAT_PEM)
++            rv = PEM_write_bio_PKCS7_stream(out, p7, in, flags);
++        else if (outformat == FORMAT_ASN1)
++            rv = i2d_PKCS7_bio_stream(out, p7, in, flags);
++        else {
++            BIO_printf(bio_err, "Bad output format for PKCS#7 file\n");
++            goto end;
++        }
++        if (rv == 0) {
++            BIO_printf(bio_err, "Error writing output\n");
++            ret = 3;
++            goto end;
++        }
++    }
++    ret = 0;
++ end:
++    if (need_rand)
++        app_RAND_write_file(NULL);
++    if (ret)
++        ERR_print_errors(bio_err);
++    sk_X509_pop_free(encerts, X509_free);
++    sk_X509_pop_free(other, X509_free);
++    X509_VERIFY_PARAM_free(vpm);
++    sk_OPENSSL_STRING_free(sksigners);
++    sk_OPENSSL_STRING_free(skkeys);
++    X509_STORE_free(store);
++    X509_free(cert);
++    X509_free(recip);
++    X509_free(signer);
++    EVP_PKEY_free(key);
++    PKCS7_free(p7);
++    release_engine(e);
++    BIO_free(in);
++    BIO_free(indata);
++    BIO_free_all(out);
++    OPENSSL_free(passin);
++    return (ret);
++}
++
++static int save_certs(char *signerfile, STACK_OF(X509) *signers)
++{
++    int i;
++    BIO *tmp;
++    if (!signerfile)
++        return 1;
++    tmp = BIO_new_file(signerfile, "w");
++    if (!tmp)
++        return 0;
++    for (i = 0; i < sk_X509_num(signers); i++)
++        PEM_write_bio_X509(tmp, sk_X509_value(signers, i));
++    BIO_free(tmp);
++    return 1;
++}
++
++/* Minimal callback just to output policy info (if any) */
++
++static int smime_cb(int ok, X509_STORE_CTX *ctx)
++{
++    int error;
++
++    error = X509_STORE_CTX_get_error(ctx);
++
++    if ((error != X509_V_ERR_NO_EXPLICIT_POLICY)
++        && ((error != X509_V_OK) || (ok != 2)))
++        return ok;
++
++    policies_print(ctx);
++
++    return ok;
++
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/apps/speed.c b/CryptoPkg/Library/OpensslLib/openssl/apps/speed.c
+new file mode 100644
+index 0000000..df22422
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/apps/speed.c
+@@ -0,0 +1,3144 @@
++/*
++ * Copyright 1995-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++/* ====================================================================
++ * Copyright 2002 Sun Microsystems, Inc. ALL RIGHTS RESERVED.
++ *
++ * Portions of the attached software ("Contribution") are developed by
++ * SUN MICROSYSTEMS, INC., and are contributed to the OpenSSL project.
++ *
++ * The Contribution is licensed pursuant to the OpenSSL open source
++ * license provided above.
++ *
++ * The ECDH and ECDSA speed test software is originally written by
++ * Sumit Gupta of Sun Microsystems Laboratories.
++ *
++ */
++
++#undef SECONDS
++#define SECONDS                 3
++#define PRIME_SECONDS   10
++#define RSA_SECONDS             10
++#define DSA_SECONDS             10
++#define ECDSA_SECONDS   10
++#define ECDH_SECONDS    10
++
++#include 
++#include 
++#include 
++#include 
++#include "apps.h"
++#include 
++#include 
++#include 
++#include 
++#include 
++#include 
++#if !defined(OPENSSL_SYS_MSDOS)
++# include OPENSSL_UNISTD
++#endif
++
++#if defined(_WIN32)
++# include 
++#endif
++
++#include 
++#ifndef OPENSSL_NO_DES
++# include 
++#endif
++#include 
++#ifndef OPENSSL_NO_CAMELLIA
++# include 
++#endif
++#ifndef OPENSSL_NO_MD2
++# include 
++#endif
++#ifndef OPENSSL_NO_MDC2
++# include 
++#endif
++#ifndef OPENSSL_NO_MD4
++# include 
++#endif
++#ifndef OPENSSL_NO_MD5
++# include 
++#endif
++#include 
++#include 
++#ifndef OPENSSL_NO_RMD160
++# include 
++#endif
++#ifndef OPENSSL_NO_WHIRLPOOL
++# include 
++#endif
++#ifndef OPENSSL_NO_RC4
++# include 
++#endif
++#ifndef OPENSSL_NO_RC5
++# include 
++#endif
++#ifndef OPENSSL_NO_RC2
++# include 
++#endif
++#ifndef OPENSSL_NO_IDEA
++# include 
++#endif
++#ifndef OPENSSL_NO_SEED
++# include 
++#endif
++#ifndef OPENSSL_NO_BF
++# include 
++#endif
++#ifndef OPENSSL_NO_CAST
++# include 
++#endif
++#ifndef OPENSSL_NO_RSA
++# include 
++# include "./testrsa.h"
++#endif
++#include 
++#ifndef OPENSSL_NO_DSA
++# include 
++# include "./testdsa.h"
++#endif
++#ifndef OPENSSL_NO_EC
++# include 
++#endif
++#include 
++
++#ifndef HAVE_FORK
++# if defined(OPENSSL_SYS_VMS) || defined(OPENSSL_SYS_WINDOWS)
++#  define HAVE_FORK 0
++# else
++#  define HAVE_FORK 1
++# endif
++#endif
++
++#if HAVE_FORK
++# undef NO_FORK
++#else
++# define NO_FORK
++#endif
++
++#undef BUFSIZE
++#define BUFSIZE (1024*16+1)
++#define MAX_MISALIGNMENT 63
++
++#define ALGOR_NUM       30
++#define SIZE_NUM        6
++#define PRIME_NUM       3
++#define RSA_NUM         7
++#define DSA_NUM         3
++
++#define EC_NUM          17
++#define MAX_ECDH_SIZE   256
++#define MISALIGN        64
++
++static volatile int run = 0;
++
++static int mr = 0;
++static int usertime = 1;
++
++typedef void *(*kdf_fn) (
++        const void *in, size_t inlen, void *out, size_t *xoutlen);
++
++typedef struct loopargs_st {
++    ASYNC_JOB *inprogress_job;
++    ASYNC_WAIT_CTX *wait_ctx;
++    unsigned char *buf;
++    unsigned char *buf2;
++    unsigned char *buf_malloc;
++    unsigned char *buf2_malloc;
++    unsigned int siglen;
++#ifndef OPENSSL_NO_RSA
++    RSA *rsa_key[RSA_NUM];
++#endif
++#ifndef OPENSSL_NO_DSA
++    DSA *dsa_key[DSA_NUM];
++#endif
++#ifndef OPENSSL_NO_EC
++    EC_KEY *ecdsa[EC_NUM];
++    EC_KEY *ecdh_a[EC_NUM];
++    EC_KEY *ecdh_b[EC_NUM];
++    unsigned char *secret_a;
++    unsigned char *secret_b;
++    size_t      outlen;
++    kdf_fn      kdf;
++#endif
++    EVP_CIPHER_CTX *ctx;
++    HMAC_CTX *hctx;
++    GCM128_CONTEXT *gcm_ctx;
++} loopargs_t;
++
++#ifndef OPENSSL_NO_MD2
++static int EVP_Digest_MD2_loop(void *args);
++#endif
++
++#ifndef OPENSSL_NO_MDC2
++static int EVP_Digest_MDC2_loop(void *args);
++#endif
++#ifndef OPENSSL_NO_MD4
++static int EVP_Digest_MD4_loop(void *args);
++#endif
++#ifndef OPENSSL_NO_MD5
++static int MD5_loop(void *args);
++static int HMAC_loop(void *args);
++#endif
++static int SHA1_loop(void *args);
++static int SHA256_loop(void *args);
++static int SHA512_loop(void *args);
++#ifndef OPENSSL_NO_WHIRLPOOL
++static int WHIRLPOOL_loop(void *args);
++#endif
++#ifndef OPENSSL_NO_RMD160
++static int EVP_Digest_RMD160_loop(void *args);
++#endif
++#ifndef OPENSSL_NO_RC4
++static int RC4_loop(void *args);
++#endif
++#ifndef OPENSSL_NO_DES
++static int DES_ncbc_encrypt_loop(void *args);
++static int DES_ede3_cbc_encrypt_loop(void *args);
++#endif
++static int AES_cbc_128_encrypt_loop(void *args);
++static int AES_cbc_192_encrypt_loop(void *args);
++static int AES_ige_128_encrypt_loop(void *args);
++static int AES_cbc_256_encrypt_loop(void *args);
++static int AES_ige_192_encrypt_loop(void *args);
++static int AES_ige_256_encrypt_loop(void *args);
++static int CRYPTO_gcm128_aad_loop(void *args);
++static int EVP_Update_loop(void *args);
++static int EVP_Digest_loop(void *args);
++#ifndef OPENSSL_NO_RSA
++static int RSA_sign_loop(void *args);
++static int RSA_verify_loop(void *args);
++#endif
++#ifndef OPENSSL_NO_DSA
++static int DSA_sign_loop(void *args);
++static int DSA_verify_loop(void *args);
++#endif
++#ifndef OPENSSL_NO_EC
++static int ECDSA_sign_loop(void *args);
++static int ECDSA_verify_loop(void *args);
++static int ECDH_compute_key_loop(void *args);
++#endif
++static int run_benchmark(int async_jobs, int (*loop_function)(void *), loopargs_t *loopargs);
++
++static double Time_F(int s);
++static void print_message(const char *s, long num, int length);
++static void pkey_print_message(const char *str, const char *str2,
++                               long num, int bits, int sec);
++static void print_result(int alg, int run_no, int count, double time_used);
++#ifndef NO_FORK
++static int do_multi(int multi);
++#endif
++
++static const char *names[ALGOR_NUM] = {
++    "md2", "mdc2", "md4", "md5", "hmac(md5)", "sha1", "rmd160", "rc4",
++    "des cbc", "des ede3", "idea cbc", "seed cbc",
++    "rc2 cbc", "rc5-32/12 cbc", "blowfish cbc", "cast cbc",
++    "aes-128 cbc", "aes-192 cbc", "aes-256 cbc",
++    "camellia-128 cbc", "camellia-192 cbc", "camellia-256 cbc",
++    "evp", "sha256", "sha512", "whirlpool",
++    "aes-128 ige", "aes-192 ige", "aes-256 ige", "ghash"
++};
++
++static double results[ALGOR_NUM][SIZE_NUM];
++
++static const int lengths[SIZE_NUM] = {
++    16, 64, 256, 1024, 8 * 1024, 16 * 1024
++};
++
++#ifndef OPENSSL_NO_RSA
++static double rsa_results[RSA_NUM][2];
++#endif
++#ifndef OPENSSL_NO_DSA
++static double dsa_results[DSA_NUM][2];
++#endif
++#ifndef OPENSSL_NO_EC
++static double ecdsa_results[EC_NUM][2];
++static double ecdh_results[EC_NUM][1];
++#endif
++
++#if !defined(OPENSSL_NO_DSA) || !defined(OPENSSL_NO_EC)
++static const char rnd_seed[] =
++    "string to make the random number generator think it has entropy";
++#endif
++
++#ifdef SIGALRM
++# if defined(__STDC__) || defined(sgi) || defined(_AIX)
++#  define SIGRETTYPE void
++# else
++#  define SIGRETTYPE int
++# endif
++
++static SIGRETTYPE sig_done(int sig);
++static SIGRETTYPE sig_done(int sig)
++{
++    signal(SIGALRM, sig_done);
++    run = 0;
++}
++#endif
++
++#define START   0
++#define STOP    1
++
++#if defined(_WIN32)
++
++# if !defined(SIGALRM)
++#  define SIGALRM
++# endif
++static unsigned int lapse, schlock;
++static void alarm_win32(unsigned int secs)
++{
++    lapse = secs * 1000;
++}
++
++# define alarm alarm_win32
++
++static DWORD WINAPI sleepy(VOID * arg)
++{
++    schlock = 1;
++    Sleep(lapse);
++    run = 0;
++    return 0;
++}
++
++static double Time_F(int s)
++{
++    double ret;
++    static HANDLE thr;
++
++    if (s == START) {
++        schlock = 0;
++        thr = CreateThread(NULL, 4096, sleepy, NULL, 0, NULL);
++        if (thr == NULL) {
++            DWORD err = GetLastError();
++            BIO_printf(bio_err, "unable to CreateThread (%lu)", err);
++            ExitProcess(err);
++        }
++        while (!schlock)
++            Sleep(0);           /* scheduler spinlock */
++        ret = app_tminterval(s, usertime);
++    } else {
++        ret = app_tminterval(s, usertime);
++        if (run)
++            TerminateThread(thr, 0);
++        CloseHandle(thr);
++    }
++
++    return ret;
++}
++#else
++
++static double Time_F(int s)
++{
++    double ret = app_tminterval(s, usertime);
++    if (s == STOP)
++        alarm(0);
++    return ret;
++}
++#endif
++
++static void multiblock_speed(const EVP_CIPHER *evp_cipher);
++
++static int found(const char *name, const OPT_PAIR *pairs, int *result)
++{
++    for (; pairs->name; pairs++)
++        if (strcmp(name, pairs->name) == 0) {
++            *result = pairs->retval;
++            return 1;
++        }
++    return 0;
++}
++
++typedef enum OPTION_choice {
++    OPT_ERR = -1, OPT_EOF = 0, OPT_HELP,
++    OPT_ELAPSED, OPT_EVP, OPT_DECRYPT, OPT_ENGINE, OPT_MULTI,
++    OPT_MR, OPT_MB, OPT_MISALIGN, OPT_ASYNCJOBS
++} OPTION_CHOICE;
++
++OPTIONS speed_options[] = {
++    {OPT_HELP_STR, 1, '-', "Usage: %s [options] ciphers...\n"},
++    {OPT_HELP_STR, 1, '-', "Valid options are:\n"},
++    {"help", OPT_HELP, '-', "Display this summary"},
++    {"evp", OPT_EVP, 's', "Use specified EVP cipher"},
++    {"decrypt", OPT_DECRYPT, '-',
++     "Time decryption instead of encryption (only EVP)"},
++    {"mr", OPT_MR, '-', "Produce machine readable output"},
++    {"mb", OPT_MB, '-',
++     "Enable (tls1.1) multi-block mode on evp_cipher requested with -evp"},
++    {"misalign", OPT_MISALIGN, 'n', "Amount to mis-align buffers"},
++    {"elapsed", OPT_ELAPSED, '-',
++     "Measure time in real time instead of CPU user time"},
++#ifndef NO_FORK
++    {"multi", OPT_MULTI, 'p', "Run benchmarks in parallel"},
++#endif
++#ifndef OPENSSL_NO_ASYNC
++    {"async_jobs", OPT_ASYNCJOBS, 'p',
++     "Enable async mode and start pnum jobs"},
++#endif
++#ifndef OPENSSL_NO_ENGINE
++    {"engine", OPT_ENGINE, 's', "Use engine, possibly a hardware device"},
++#endif
++    {NULL},
++};
++
++#define D_MD2           0
++#define D_MDC2          1
++#define D_MD4           2
++#define D_MD5           3
++#define D_HMAC          4
++#define D_SHA1          5
++#define D_RMD160        6
++#define D_RC4           7
++#define D_CBC_DES       8
++#define D_EDE3_DES      9
++#define D_CBC_IDEA      10
++#define D_CBC_SEED      11
++#define D_CBC_RC2       12
++#define D_CBC_RC5       13
++#define D_CBC_BF        14
++#define D_CBC_CAST      15
++#define D_CBC_128_AES   16
++#define D_CBC_192_AES   17
++#define D_CBC_256_AES   18
++#define D_CBC_128_CML   19
++#define D_CBC_192_CML   20
++#define D_CBC_256_CML   21
++#define D_EVP           22
++#define D_SHA256        23
++#define D_SHA512        24
++#define D_WHIRLPOOL     25
++#define D_IGE_128_AES   26
++#define D_IGE_192_AES   27
++#define D_IGE_256_AES   28
++#define D_GHASH         29
++static OPT_PAIR doit_choices[] = {
++#ifndef OPENSSL_NO_MD2
++    {"md2", D_MD2},
++#endif
++#ifndef OPENSSL_NO_MDC2
++    {"mdc2", D_MDC2},
++#endif
++#ifndef OPENSSL_NO_MD4
++    {"md4", D_MD4},
++#endif
++#ifndef OPENSSL_NO_MD5
++    {"md5", D_MD5},
++    {"hmac", D_HMAC},
++#endif
++    {"sha1", D_SHA1},
++    {"sha256", D_SHA256},
++    {"sha512", D_SHA512},
++#ifndef OPENSSL_NO_WHIRLPOOL
++    {"whirlpool", D_WHIRLPOOL},
++#endif
++#ifndef OPENSSL_NO_RMD160
++    {"ripemd", D_RMD160},
++    {"rmd160", D_RMD160},
++    {"ripemd160", D_RMD160},
++#endif
++#ifndef OPENSSL_NO_RC4
++    {"rc4", D_RC4},
++#endif
++#ifndef OPENSSL_NO_DES
++    {"des-cbc", D_CBC_DES},
++    {"des-ede3", D_EDE3_DES},
++#endif
++    {"aes-128-cbc", D_CBC_128_AES},
++    {"aes-192-cbc", D_CBC_192_AES},
++    {"aes-256-cbc", D_CBC_256_AES},
++    {"aes-128-ige", D_IGE_128_AES},
++    {"aes-192-ige", D_IGE_192_AES},
++    {"aes-256-ige", D_IGE_256_AES},
++#ifndef OPENSSL_NO_RC2
++    {"rc2-cbc", D_CBC_RC2},
++    {"rc2", D_CBC_RC2},
++#endif
++#ifndef OPENSSL_NO_RC5
++    {"rc5-cbc", D_CBC_RC5},
++    {"rc5", D_CBC_RC5},
++#endif
++#ifndef OPENSSL_NO_IDEA
++    {"idea-cbc", D_CBC_IDEA},
++    {"idea", D_CBC_IDEA},
++#endif
++#ifndef OPENSSL_NO_SEED
++    {"seed-cbc", D_CBC_SEED},
++    {"seed", D_CBC_SEED},
++#endif
++#ifndef OPENSSL_NO_BF
++    {"bf-cbc", D_CBC_BF},
++    {"blowfish", D_CBC_BF},
++    {"bf", D_CBC_BF},
++#endif
++#ifndef OPENSSL_NO_CAST
++    {"cast-cbc", D_CBC_CAST},
++    {"cast", D_CBC_CAST},
++    {"cast5", D_CBC_CAST},
++#endif
++    {"ghash", D_GHASH},
++    {NULL}
++};
++
++#ifndef OPENSSL_NO_DSA
++# define R_DSA_512       0
++# define R_DSA_1024      1
++# define R_DSA_2048      2
++static OPT_PAIR dsa_choices[] = {
++    {"dsa512", R_DSA_512},
++    {"dsa1024", R_DSA_1024},
++    {"dsa2048", R_DSA_2048},
++    {NULL},
++};
++#endif
++
++#define R_RSA_512       0
++#define R_RSA_1024      1
++#define R_RSA_2048      2
++#define R_RSA_3072      3
++#define R_RSA_4096      4
++#define R_RSA_7680      5
++#define R_RSA_15360     6
++static OPT_PAIR rsa_choices[] = {
++    {"rsa512", R_RSA_512},
++    {"rsa1024", R_RSA_1024},
++    {"rsa2048", R_RSA_2048},
++    {"rsa3072", R_RSA_3072},
++    {"rsa4096", R_RSA_4096},
++    {"rsa7680", R_RSA_7680},
++    {"rsa15360", R_RSA_15360},
++    {NULL}
++};
++
++#define R_EC_P160    0
++#define R_EC_P192    1
++#define R_EC_P224    2
++#define R_EC_P256    3
++#define R_EC_P384    4
++#define R_EC_P521    5
++#define R_EC_K163    6
++#define R_EC_K233    7
++#define R_EC_K283    8
++#define R_EC_K409    9
++#define R_EC_K571    10
++#define R_EC_B163    11
++#define R_EC_B233    12
++#define R_EC_B283    13
++#define R_EC_B409    14
++#define R_EC_B571    15
++#define R_EC_X25519  16
++#ifndef OPENSSL_NO_EC
++static OPT_PAIR ecdsa_choices[] = {
++    {"ecdsap160", R_EC_P160},
++    {"ecdsap192", R_EC_P192},
++    {"ecdsap224", R_EC_P224},
++    {"ecdsap256", R_EC_P256},
++    {"ecdsap384", R_EC_P384},
++    {"ecdsap521", R_EC_P521},
++    {"ecdsak163", R_EC_K163},
++    {"ecdsak233", R_EC_K233},
++    {"ecdsak283", R_EC_K283},
++    {"ecdsak409", R_EC_K409},
++    {"ecdsak571", R_EC_K571},
++    {"ecdsab163", R_EC_B163},
++    {"ecdsab233", R_EC_B233},
++    {"ecdsab283", R_EC_B283},
++    {"ecdsab409", R_EC_B409},
++    {"ecdsab571", R_EC_B571},
++    {NULL}
++};
++
++static OPT_PAIR ecdh_choices[] = {
++    {"ecdhp160", R_EC_P160},
++    {"ecdhp192", R_EC_P192},
++    {"ecdhp224", R_EC_P224},
++    {"ecdhp256", R_EC_P256},
++    {"ecdhp384", R_EC_P384},
++    {"ecdhp521", R_EC_P521},
++    {"ecdhk163", R_EC_K163},
++    {"ecdhk233", R_EC_K233},
++    {"ecdhk283", R_EC_K283},
++    {"ecdhk409", R_EC_K409},
++    {"ecdhk571", R_EC_K571},
++    {"ecdhb163", R_EC_B163},
++    {"ecdhb233", R_EC_B233},
++    {"ecdhb283", R_EC_B283},
++    {"ecdhb409", R_EC_B409},
++    {"ecdhb571", R_EC_B571},
++    {"ecdhx25519", R_EC_X25519},
++    {NULL}
++};
++#endif
++
++#ifndef SIGALRM
++# define COND(d) (count < (d))
++# define COUNT(d) (d)
++#else
++# define COND(unused_cond) (run && count<0x7fffffff)
++# define COUNT(d) (count)
++#endif                         /* SIGALRM */
++
++static int testnum;
++
++/* Nb of iterations to do per algorithm and key-size */
++static long c[ALGOR_NUM][SIZE_NUM];
++
++#ifndef OPENSSL_NO_MD2
++static int EVP_Digest_MD2_loop(void *args)
++{
++    loopargs_t *tempargs = *(loopargs_t **)args;
++    unsigned char *buf = tempargs->buf;
++    unsigned char md2[MD2_DIGEST_LENGTH];
++    int count;
++
++    for (count = 0; COND(c[D_MD2][testnum]); count++) {
++        if (!EVP_Digest(buf, (size_t)lengths[testnum], md2, NULL, EVP_md2(),
++                NULL))
++            return -1;
++    }
++    return count;
++}
++#endif
++
++#ifndef OPENSSL_NO_MDC2
++static int EVP_Digest_MDC2_loop(void *args)
++{
++    loopargs_t *tempargs = *(loopargs_t **)args;
++    unsigned char *buf = tempargs->buf;
++    unsigned char mdc2[MDC2_DIGEST_LENGTH];
++    int count;
++
++    for (count = 0; COND(c[D_MDC2][testnum]); count++) {
++        if (!EVP_Digest(buf, (size_t)lengths[testnum], mdc2, NULL, EVP_mdc2(),
++                NULL))
++            return -1;
++    }
++    return count;
++}
++#endif
++
++#ifndef OPENSSL_NO_MD4
++static int EVP_Digest_MD4_loop(void *args)
++{
++    loopargs_t *tempargs = *(loopargs_t **)args;
++    unsigned char *buf = tempargs->buf;
++    unsigned char md4[MD4_DIGEST_LENGTH];
++    int count;
++
++    for (count = 0; COND(c[D_MD4][testnum]); count++) {
++        if (!EVP_Digest(buf, (size_t)lengths[testnum], md4, NULL, EVP_md4(),
++                NULL))
++            return -1;
++    }
++    return count;
++}
++#endif
++
++#ifndef OPENSSL_NO_MD5
++static int MD5_loop(void *args)
++{
++    loopargs_t *tempargs = *(loopargs_t **)args;
++    unsigned char *buf = tempargs->buf;
++    unsigned char md5[MD5_DIGEST_LENGTH];
++    int count;
++    for (count = 0; COND(c[D_MD5][testnum]); count++)
++        MD5(buf, lengths[testnum], md5);
++    return count;
++}
++
++static int HMAC_loop(void *args)
++{
++    loopargs_t *tempargs = *(loopargs_t **)args;
++    unsigned char *buf = tempargs->buf;
++    HMAC_CTX *hctx = tempargs->hctx;
++    unsigned char hmac[MD5_DIGEST_LENGTH];
++    int count;
++
++    for (count = 0; COND(c[D_HMAC][testnum]); count++) {
++        HMAC_Init_ex(hctx, NULL, 0, NULL, NULL);
++        HMAC_Update(hctx, buf, lengths[testnum]);
++        HMAC_Final(hctx, hmac, NULL);
++    }
++    return count;
++}
++#endif
++
++static int SHA1_loop(void *args)
++{
++    loopargs_t *tempargs = *(loopargs_t **)args;
++    unsigned char *buf = tempargs->buf;
++    unsigned char sha[SHA_DIGEST_LENGTH];
++    int count;
++    for (count = 0; COND(c[D_SHA1][testnum]); count++)
++        SHA1(buf, lengths[testnum], sha);
++    return count;
++}
++
++static int SHA256_loop(void *args)
++{
++    loopargs_t *tempargs = *(loopargs_t **)args;
++    unsigned char *buf = tempargs->buf;
++    unsigned char sha256[SHA256_DIGEST_LENGTH];
++    int count;
++    for (count = 0; COND(c[D_SHA256][testnum]); count++)
++        SHA256(buf, lengths[testnum], sha256);
++    return count;
++}
++
++static int SHA512_loop(void *args)
++{
++    loopargs_t *tempargs = *(loopargs_t **)args;
++    unsigned char *buf = tempargs->buf;
++    unsigned char sha512[SHA512_DIGEST_LENGTH];
++    int count;
++    for (count = 0; COND(c[D_SHA512][testnum]); count++)
++        SHA512(buf, lengths[testnum], sha512);
++    return count;
++}
++
++#ifndef OPENSSL_NO_WHIRLPOOL
++static int WHIRLPOOL_loop(void *args)
++{
++    loopargs_t *tempargs = *(loopargs_t **)args;
++    unsigned char *buf = tempargs->buf;
++    unsigned char whirlpool[WHIRLPOOL_DIGEST_LENGTH];
++    int count;
++    for (count = 0; COND(c[D_WHIRLPOOL][testnum]); count++)
++        WHIRLPOOL(buf, lengths[testnum], whirlpool);
++    return count;
++}
++#endif
++
++#ifndef OPENSSL_NO_RMD160
++static int EVP_Digest_RMD160_loop(void *args)
++{
++    loopargs_t *tempargs = *(loopargs_t **)args;
++    unsigned char *buf = tempargs->buf;
++    unsigned char rmd160[RIPEMD160_DIGEST_LENGTH];
++    int count;
++    for (count = 0; COND(c[D_RMD160][testnum]); count++) {
++        if (!EVP_Digest(buf, (size_t)lengths[testnum], &(rmd160[0]),
++                NULL, EVP_ripemd160(), NULL))
++            return -1;
++    }
++    return count;
++}
++#endif
++
++#ifndef OPENSSL_NO_RC4
++static RC4_KEY rc4_ks;
++static int RC4_loop(void *args)
++{
++    loopargs_t *tempargs = *(loopargs_t **)args;
++    unsigned char *buf = tempargs->buf;
++    int count;
++    for (count = 0; COND(c[D_RC4][testnum]); count++)
++        RC4(&rc4_ks, (size_t)lengths[testnum], buf, buf);
++    return count;
++}
++#endif
++
++#ifndef OPENSSL_NO_DES
++static unsigned char DES_iv[8];
++static DES_key_schedule sch;
++static DES_key_schedule sch2;
++static DES_key_schedule sch3;
++static int DES_ncbc_encrypt_loop(void *args)
++{
++    loopargs_t *tempargs = *(loopargs_t **)args;
++    unsigned char *buf = tempargs->buf;
++    int count;
++    for (count = 0; COND(c[D_CBC_DES][testnum]); count++)
++        DES_ncbc_encrypt(buf, buf, lengths[testnum], &sch,
++                &DES_iv, DES_ENCRYPT);
++    return count;
++}
++
++static int DES_ede3_cbc_encrypt_loop(void *args)
++{
++    loopargs_t *tempargs = *(loopargs_t **)args;
++    unsigned char *buf = tempargs->buf;
++    int count;
++    for (count = 0; COND(c[D_EDE3_DES][testnum]); count++)
++        DES_ede3_cbc_encrypt(buf, buf, lengths[testnum],
++                &sch, &sch2, &sch3,
++                &DES_iv, DES_ENCRYPT);
++    return count;
++}
++#endif
++
++#define MAX_BLOCK_SIZE 128
++
++static unsigned char iv[2 * MAX_BLOCK_SIZE / 8];
++static AES_KEY aes_ks1, aes_ks2, aes_ks3;
++static int AES_cbc_128_encrypt_loop(void *args)
++{
++    loopargs_t *tempargs = *(loopargs_t **)args;
++    unsigned char *buf = tempargs->buf;
++    int count;
++    for (count = 0; COND(c[D_CBC_128_AES][testnum]); count++)
++        AES_cbc_encrypt(buf, buf,
++                (size_t)lengths[testnum], &aes_ks1,
++                iv, AES_ENCRYPT);
++    return count;
++}
++
++static int AES_cbc_192_encrypt_loop(void *args)
++{
++    loopargs_t *tempargs = *(loopargs_t **)args;
++    unsigned char *buf = tempargs->buf;
++    int count;
++    for (count = 0; COND(c[D_CBC_192_AES][testnum]); count++)
++        AES_cbc_encrypt(buf, buf,
++                (size_t)lengths[testnum], &aes_ks2,
++                iv, AES_ENCRYPT);
++    return count;
++}
++
++static int AES_cbc_256_encrypt_loop(void *args)
++{
++    loopargs_t *tempargs = *(loopargs_t **)args;
++    unsigned char *buf = tempargs->buf;
++    int count;
++    for (count = 0; COND(c[D_CBC_256_AES][testnum]); count++)
++        AES_cbc_encrypt(buf, buf,
++                (size_t)lengths[testnum], &aes_ks3,
++                iv, AES_ENCRYPT);
++    return count;
++}
++
++static int AES_ige_128_encrypt_loop(void *args)
++{
++    loopargs_t *tempargs = *(loopargs_t **)args;
++    unsigned char *buf = tempargs->buf;
++    unsigned char *buf2 = tempargs->buf2;
++    int count;
++    for (count = 0; COND(c[D_IGE_128_AES][testnum]); count++)
++        AES_ige_encrypt(buf, buf2,
++                (size_t)lengths[testnum], &aes_ks1,
++                iv, AES_ENCRYPT);
++    return count;
++}
++
++static int AES_ige_192_encrypt_loop(void *args)
++{
++    loopargs_t *tempargs = *(loopargs_t **)args;
++    unsigned char *buf = tempargs->buf;
++    unsigned char *buf2 = tempargs->buf2;
++    int count;
++    for (count = 0; COND(c[D_IGE_192_AES][testnum]); count++)
++        AES_ige_encrypt(buf, buf2,
++                (size_t)lengths[testnum], &aes_ks2,
++                iv, AES_ENCRYPT);
++    return count;
++}
++
++static int AES_ige_256_encrypt_loop(void *args)
++{
++    loopargs_t *tempargs = *(loopargs_t **)args;
++    unsigned char *buf = tempargs->buf;
++    unsigned char *buf2 = tempargs->buf2;
++    int count;
++    for (count = 0; COND(c[D_IGE_256_AES][testnum]); count++)
++        AES_ige_encrypt(buf, buf2,
++                (size_t)lengths[testnum], &aes_ks3,
++                iv, AES_ENCRYPT);
++    return count;
++}
++
++static int CRYPTO_gcm128_aad_loop(void *args)
++{
++    loopargs_t *tempargs = *(loopargs_t **)args;
++    unsigned char *buf = tempargs->buf;
++    GCM128_CONTEXT *gcm_ctx = tempargs->gcm_ctx;
++    int count;
++    for (count = 0; COND(c[D_GHASH][testnum]); count++)
++        CRYPTO_gcm128_aad(gcm_ctx, buf, lengths[testnum]);
++    return count;
++}
++
++static long save_count = 0;
++static int decrypt = 0;
++static int EVP_Update_loop(void *args)
++{
++    loopargs_t *tempargs = *(loopargs_t **)args;
++    unsigned char *buf = tempargs->buf;
++    EVP_CIPHER_CTX *ctx = tempargs->ctx;
++    int outl, count;
++#ifndef SIGALRM
++    int nb_iter = save_count * 4 * lengths[0] / lengths[testnum];
++#endif
++    if (decrypt)
++        for (count = 0; COND(nb_iter); count++)
++            EVP_DecryptUpdate(ctx, buf, &outl, buf, lengths[testnum]);
++    else
++        for (count = 0; COND(nb_iter); count++)
++            EVP_EncryptUpdate(ctx, buf, &outl, buf, lengths[testnum]);
++    if (decrypt)
++        EVP_DecryptFinal_ex(ctx, buf, &outl);
++    else
++        EVP_EncryptFinal_ex(ctx, buf, &outl);
++    return count;
++}
++
++static const EVP_MD *evp_md = NULL;
++static int EVP_Digest_loop(void *args)
++{
++    loopargs_t *tempargs = *(loopargs_t **)args;
++    unsigned char *buf = tempargs->buf;
++    unsigned char md[EVP_MAX_MD_SIZE];
++    int count;
++#ifndef SIGALRM
++    int nb_iter = save_count * 4 * lengths[0] / lengths[testnum];
++#endif
++
++    for (count = 0; COND(nb_iter); count++) {
++        if (!EVP_Digest(buf, lengths[testnum], md, NULL, evp_md, NULL))
++            return -1;
++    }
++    return count;
++}
++
++#ifndef OPENSSL_NO_RSA
++static long rsa_c[RSA_NUM][2];  /* # RSA iteration test */
++
++static int RSA_sign_loop(void *args)
++{
++    loopargs_t *tempargs = *(loopargs_t **)args;
++    unsigned char *buf = tempargs->buf;
++    unsigned char *buf2 = tempargs->buf2;
++    unsigned int *rsa_num = &tempargs->siglen;
++    RSA **rsa_key = tempargs->rsa_key;
++    int ret, count;
++    for (count = 0; COND(rsa_c[testnum][0]); count++) {
++        ret = RSA_sign(NID_md5_sha1, buf, 36, buf2, rsa_num, rsa_key[testnum]);
++        if (ret == 0) {
++            BIO_printf(bio_err, "RSA sign failure\n");
++            ERR_print_errors(bio_err);
++            count = -1;
++            break;
++        }
++    }
++    return count;
++}
++
++static int RSA_verify_loop(void *args)
++{
++    loopargs_t *tempargs = *(loopargs_t **)args;
++    unsigned char *buf = tempargs->buf;
++    unsigned char *buf2 = tempargs->buf2;
++    unsigned int rsa_num = tempargs->siglen;
++    RSA **rsa_key = tempargs->rsa_key;
++    int ret, count;
++    for (count = 0; COND(rsa_c[testnum][1]); count++) {
++        ret = RSA_verify(NID_md5_sha1, buf, 36, buf2, rsa_num, rsa_key[testnum]);
++        if (ret <= 0) {
++            BIO_printf(bio_err, "RSA verify failure\n");
++            ERR_print_errors(bio_err);
++            count = -1;
++            break;
++        }
++    }
++    return count;
++}
++#endif
++
++#ifndef OPENSSL_NO_DSA
++static long dsa_c[DSA_NUM][2];
++static int DSA_sign_loop(void *args)
++{
++    loopargs_t *tempargs = *(loopargs_t **)args;
++    unsigned char *buf = tempargs->buf;
++    unsigned char *buf2 = tempargs->buf2;
++    DSA **dsa_key = tempargs->dsa_key;
++    unsigned int *siglen = &tempargs->siglen;
++    int ret, count;
++    for (count = 0; COND(dsa_c[testnum][0]); count++) {
++        ret = DSA_sign(0, buf, 20, buf2, siglen, dsa_key[testnum]);
++        if (ret == 0) {
++            BIO_printf(bio_err, "DSA sign failure\n");
++            ERR_print_errors(bio_err);
++            count = -1;
++            break;
++        }
++    }
++    return count;
++}
++
++static int DSA_verify_loop(void *args)
++{
++    loopargs_t *tempargs = *(loopargs_t **)args;
++    unsigned char *buf = tempargs->buf;
++    unsigned char *buf2 = tempargs->buf2;
++    DSA **dsa_key = tempargs->dsa_key;
++    unsigned int siglen = tempargs->siglen;
++    int ret, count;
++    for (count = 0; COND(dsa_c[testnum][1]); count++) {
++        ret = DSA_verify(0, buf, 20, buf2, siglen, dsa_key[testnum]);
++        if (ret <= 0) {
++            BIO_printf(bio_err, "DSA verify failure\n");
++            ERR_print_errors(bio_err);
++            count = -1;
++            break;
++        }
++    }
++    return count;
++}
++#endif
++
++#ifndef OPENSSL_NO_EC
++static long ecdsa_c[EC_NUM][2];
++static int ECDSA_sign_loop(void *args)
++{
++    loopargs_t *tempargs = *(loopargs_t **)args;
++    unsigned char *buf = tempargs->buf;
++    EC_KEY **ecdsa = tempargs->ecdsa;
++    unsigned char *ecdsasig = tempargs->buf2;
++    unsigned int *ecdsasiglen = &tempargs->siglen;
++    int ret, count;
++    for (count = 0; COND(ecdsa_c[testnum][0]); count++) {
++        ret = ECDSA_sign(0, buf, 20,
++                ecdsasig, ecdsasiglen, ecdsa[testnum]);
++        if (ret == 0) {
++            BIO_printf(bio_err, "ECDSA sign failure\n");
++            ERR_print_errors(bio_err);
++            count = -1;
++            break;
++        }
++    }
++    return count;
++}
++
++static int ECDSA_verify_loop(void *args)
++{
++    loopargs_t *tempargs = *(loopargs_t **)args;
++    unsigned char *buf = tempargs->buf;
++    EC_KEY **ecdsa = tempargs->ecdsa;
++    unsigned char *ecdsasig = tempargs->buf2;
++    unsigned int ecdsasiglen = tempargs->siglen;
++    int ret, count;
++    for (count = 0; COND(ecdsa_c[testnum][1]); count++) {
++        ret = ECDSA_verify(0, buf, 20, ecdsasig, ecdsasiglen,
++                ecdsa[testnum]);
++        if (ret != 1) {
++            BIO_printf(bio_err, "ECDSA verify failure\n");
++            ERR_print_errors(bio_err);
++            count = -1;
++            break;
++        }
++    }
++    return count;
++}
++
++/* ******************************************************************** */
++static long ecdh_c[EC_NUM][1];
++
++static int ECDH_compute_key_loop(void *args)
++{
++    loopargs_t *tempargs = *(loopargs_t **)args;
++    EC_KEY **ecdh_a = tempargs->ecdh_a;
++    EC_KEY **ecdh_b = tempargs->ecdh_b;
++    unsigned char *secret_a = tempargs->secret_a;
++    int count;
++    size_t outlen = tempargs->outlen;
++    kdf_fn kdf = tempargs->kdf;
++
++    for (count = 0; COND(ecdh_c[testnum][0]); count++) {
++        ECDH_compute_key(secret_a, outlen,
++                EC_KEY_get0_public_key(ecdh_b[testnum]),
++                ecdh_a[testnum], kdf);
++    }
++    return count;
++}
++
++static const size_t KDF1_SHA1_len = 20;
++static void *KDF1_SHA1(const void *in, size_t inlen, void *out,
++                       size_t *outlen)
++{
++    if (*outlen < SHA_DIGEST_LENGTH)
++        return NULL;
++    *outlen = SHA_DIGEST_LENGTH;
++    return SHA1(in, inlen, out);
++}
++#endif                          /* OPENSSL_NO_EC */
++
++static int run_benchmark(int async_jobs,
++                         int (*loop_function)(void *), loopargs_t *loopargs)
++{
++    int job_op_count = 0;
++    int total_op_count = 0;
++    int num_inprogress = 0;
++    int error = 0, i = 0, ret = 0;
++    OSSL_ASYNC_FD job_fd = 0;
++    size_t num_job_fds = 0;
++
++    run = 1;
++
++    if (async_jobs == 0) {
++        return loop_function((void *)&loopargs);
++    }
++
++    for (i = 0; i < async_jobs && !error; i++) {
++        loopargs_t *looparg_item = loopargs + i;
++
++        /* Copy pointer content (looparg_t item address) into async context */
++        ret = ASYNC_start_job(&loopargs[i].inprogress_job, loopargs[i].wait_ctx,
++                              &job_op_count, loop_function,
++                              (void *)&looparg_item, sizeof(looparg_item));
++        switch (ret) {
++        case ASYNC_PAUSE:
++            ++num_inprogress;
++            break;
++        case ASYNC_FINISH:
++            if (job_op_count == -1) {
++                error = 1;
++            } else {
++                total_op_count += job_op_count;
++            }
++            break;
++        case ASYNC_NO_JOBS:
++        case ASYNC_ERR:
++            BIO_printf(bio_err, "Failure in the job\n");
++            ERR_print_errors(bio_err);
++            error = 1;
++            break;
++        }
++    }
++
++    while (num_inprogress > 0) {
++#if defined(OPENSSL_SYS_WINDOWS)
++        DWORD avail = 0;
++#elif defined(OPENSSL_SYS_UNIX)
++        int select_result = 0;
++        OSSL_ASYNC_FD max_fd = 0;
++        fd_set waitfdset;
++
++        FD_ZERO(&waitfdset);
++
++        for (i = 0; i < async_jobs && num_inprogress > 0; i++) {
++            if (loopargs[i].inprogress_job == NULL)
++                continue;
++
++            if (!ASYNC_WAIT_CTX_get_all_fds(loopargs[i].wait_ctx, NULL, &num_job_fds)
++                    || num_job_fds > 1) {
++                BIO_printf(bio_err, "Too many fds in ASYNC_WAIT_CTX\n");
++                ERR_print_errors(bio_err);
++                error = 1;
++                break;
++            }
++            ASYNC_WAIT_CTX_get_all_fds(loopargs[i].wait_ctx, &job_fd, &num_job_fds);
++            FD_SET(job_fd, &waitfdset);
++            if (job_fd > max_fd)
++                max_fd = job_fd;
++        }
++
++        if (max_fd >= (OSSL_ASYNC_FD)FD_SETSIZE) {
++            BIO_printf(bio_err,
++                    "Error: max_fd (%d) must be smaller than FD_SETSIZE (%d). "
++                    "Decrease the value of async_jobs\n",
++                    max_fd, FD_SETSIZE);
++            ERR_print_errors(bio_err);
++            error = 1;
++            break;
++        }
++
++        select_result = select(max_fd + 1, &waitfdset, NULL, NULL, NULL);
++        if (select_result == -1 && errno == EINTR)
++            continue;
++
++        if (select_result == -1) {
++            BIO_printf(bio_err, "Failure in the select\n");
++            ERR_print_errors(bio_err);
++            error = 1;
++            break;
++        }
++
++        if (select_result == 0)
++            continue;
++#endif
++
++        for (i = 0; i < async_jobs; i++) {
++            if (loopargs[i].inprogress_job == NULL)
++                continue;
++
++            if (!ASYNC_WAIT_CTX_get_all_fds(loopargs[i].wait_ctx, NULL, &num_job_fds)
++                    || num_job_fds > 1) {
++                BIO_printf(bio_err, "Too many fds in ASYNC_WAIT_CTX\n");
++                ERR_print_errors(bio_err);
++                error = 1;
++                break;
++            }
++            ASYNC_WAIT_CTX_get_all_fds(loopargs[i].wait_ctx, &job_fd, &num_job_fds);
++
++#if defined(OPENSSL_SYS_UNIX)
++            if (num_job_fds == 1 && !FD_ISSET(job_fd, &waitfdset))
++                continue;
++#elif defined(OPENSSL_SYS_WINDOWS)
++            if (num_job_fds == 1
++                && !PeekNamedPipe(job_fd, NULL, 0, NULL, &avail, NULL)
++                && avail > 0)
++                continue;
++#endif
++
++            ret = ASYNC_start_job(&loopargs[i].inprogress_job, 
++                    loopargs[i].wait_ctx, &job_op_count, loop_function, 
++                    (void *)(loopargs + i), sizeof(loopargs_t));
++            switch (ret) {
++            case ASYNC_PAUSE:
++                break;
++            case ASYNC_FINISH:
++                if (job_op_count == -1) {
++                    error = 1;
++                } else {
++                    total_op_count += job_op_count;
++                }
++                --num_inprogress;
++                loopargs[i].inprogress_job = NULL;
++                break;
++            case ASYNC_NO_JOBS:
++            case ASYNC_ERR:
++                --num_inprogress;
++                loopargs[i].inprogress_job = NULL;
++                BIO_printf(bio_err, "Failure in the job\n");
++                ERR_print_errors(bio_err);
++                error = 1;
++                break;
++            }
++        }
++    }
++
++    return error ? -1 : total_op_count;
++}
++
++int speed_main(int argc, char **argv)
++{
++    ENGINE *e = NULL;
++    loopargs_t *loopargs = NULL;
++    int async_init = 0;
++    int loopargs_len = 0;
++    char *prog;
++    const char *engine_id = NULL;
++    const EVP_CIPHER *evp_cipher = NULL;
++    double d = 0.0;
++    OPTION_CHOICE o;
++    int multiblock = 0, pr_header = 0;
++    int doit[ALGOR_NUM] = { 0 };
++    int ret = 1, i, k, misalign = 0;
++    long count = 0;
++#ifndef NO_FORK
++    int multi = 0;
++#endif
++    int async_jobs = 0;
++#if !defined(OPENSSL_NO_RSA) || !defined(OPENSSL_NO_DSA) \
++    || !defined(OPENSSL_NO_EC)
++    long rsa_count = 1;
++#endif
++
++    /* What follows are the buffers and key material. */
++#ifndef OPENSSL_NO_RC5
++    RC5_32_KEY rc5_ks;
++#endif
++#ifndef OPENSSL_NO_RC2
++    RC2_KEY rc2_ks;
++#endif
++#ifndef OPENSSL_NO_IDEA
++    IDEA_KEY_SCHEDULE idea_ks;
++#endif
++#ifndef OPENSSL_NO_SEED
++    SEED_KEY_SCHEDULE seed_ks;
++#endif
++#ifndef OPENSSL_NO_BF
++    BF_KEY bf_ks;
++#endif
++#ifndef OPENSSL_NO_CAST
++    CAST_KEY cast_ks;
++#endif
++    static const unsigned char key16[16] = {
++        0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0,
++        0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12
++    };
++    static const unsigned char key24[24] = {
++        0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0,
++        0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12,
++        0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34
++    };
++    static const unsigned char key32[32] = {
++        0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0,
++        0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12,
++        0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34,
++        0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34, 0x56
++    };
++#ifndef OPENSSL_NO_CAMELLIA
++    static const unsigned char ckey24[24] = {
++        0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0,
++        0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12,
++        0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34
++    };
++    static const unsigned char ckey32[32] = {
++        0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0,
++        0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12,
++        0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34,
++        0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34, 0x56
++    };
++    CAMELLIA_KEY camellia_ks1, camellia_ks2, camellia_ks3;
++#endif
++#ifndef OPENSSL_NO_DES
++    static DES_cblock key = {
++        0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0
++    };
++    static DES_cblock key2 = {
++        0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12
++    };
++    static DES_cblock key3 = {
++        0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34
++    };
++#endif
++#ifndef OPENSSL_NO_RSA
++    static const unsigned int rsa_bits[RSA_NUM] = {
++        512, 1024, 2048, 3072, 4096, 7680, 15360
++    };
++    static const unsigned char *rsa_data[RSA_NUM] = {
++        test512, test1024, test2048, test3072, test4096, test7680, test15360
++    };
++    static const int rsa_data_length[RSA_NUM] = {
++        sizeof(test512), sizeof(test1024),
++        sizeof(test2048), sizeof(test3072),
++        sizeof(test4096), sizeof(test7680),
++        sizeof(test15360)
++    };
++    int rsa_doit[RSA_NUM] = { 0 };
++#endif
++#ifndef OPENSSL_NO_DSA
++    static const unsigned int dsa_bits[DSA_NUM] = { 512, 1024, 2048 };
++    int dsa_doit[DSA_NUM] = { 0 };
++#endif
++#ifndef OPENSSL_NO_EC
++    /*
++     * We only test over the following curves as they are representative, To
++     * add tests over more curves, simply add the curve NID and curve name to
++     * the following arrays and increase the EC_NUM value accordingly.
++     */
++    static const unsigned int test_curves[EC_NUM] = {
++        /* Prime Curves */
++        NID_secp160r1, NID_X9_62_prime192v1, NID_secp224r1,
++        NID_X9_62_prime256v1, NID_secp384r1, NID_secp521r1,
++        /* Binary Curves */
++        NID_sect163k1, NID_sect233k1, NID_sect283k1,
++        NID_sect409k1, NID_sect571k1, NID_sect163r2,
++        NID_sect233r1, NID_sect283r1, NID_sect409r1,
++        NID_sect571r1,
++        /* Other */
++        NID_X25519
++    };
++    static const char *test_curves_names[EC_NUM] = {
++        /* Prime Curves */
++        "secp160r1", "nistp192", "nistp224",
++        "nistp256", "nistp384", "nistp521",
++        /* Binary Curves */
++        "nistk163", "nistk233", "nistk283",
++        "nistk409", "nistk571", "nistb163",
++        "nistb233", "nistb283", "nistb409",
++        "nistb571",
++        /* Other */
++        "X25519"
++    };
++    static const int test_curves_bits[EC_NUM] = {
++        160, 192, 224,
++        256, 384, 521,
++        163, 233, 283,
++        409, 571, 163,
++        233, 283, 409,
++        571, 253 /* X25519 */
++    };
++
++    int ecdsa_doit[EC_NUM] = { 0 };
++    int ecdh_doit[EC_NUM] = { 0 };
++#endif                          /* ndef OPENSSL_NO_EC */
++
++    prog = opt_init(argc, argv, speed_options);
++    while ((o = opt_next()) != OPT_EOF) {
++        switch (o) {
++        case OPT_EOF:
++        case OPT_ERR:
++ opterr:
++            BIO_printf(bio_err, "%s: Use -help for summary.\n", prog);
++            goto end;
++        case OPT_HELP:
++            opt_help(speed_options);
++            ret = 0;
++            goto end;
++        case OPT_ELAPSED:
++            usertime = 0;
++            break;
++        case OPT_EVP:
++            evp_cipher = EVP_get_cipherbyname(opt_arg());
++            if (evp_cipher == NULL)
++                evp_md = EVP_get_digestbyname(opt_arg());
++            if (evp_cipher == NULL && evp_md == NULL) {
++                BIO_printf(bio_err,
++                           "%s: %s is an unknown cipher or digest\n",
++                           prog, opt_arg());
++                goto end;
++            }
++            doit[D_EVP] = 1;
++            break;
++        case OPT_DECRYPT:
++            decrypt = 1;
++            break;
++        case OPT_ENGINE:
++            /*
++             * In a forked execution, an engine might need to be
++             * initialised by each child process, not by the parent.
++             * So store the name here and run setup_engine() later on.
++             */
++            engine_id = opt_arg();
++            break;
++        case OPT_MULTI:
++#ifndef NO_FORK
++            multi = atoi(opt_arg());
++#endif
++            break;
++        case OPT_ASYNCJOBS:
++#ifndef OPENSSL_NO_ASYNC
++            async_jobs = atoi(opt_arg());
++            if (!ASYNC_is_capable()) {
++                BIO_printf(bio_err,
++                           "%s: async_jobs specified but async not supported\n",
++                           prog);
++                goto opterr;
++            }
++#endif
++            break;
++        case OPT_MISALIGN:
++            if (!opt_int(opt_arg(), &misalign))
++                goto end;
++            if (misalign > MISALIGN) {
++                BIO_printf(bio_err,
++                           "%s: Maximum offset is %d\n", prog, MISALIGN);
++                goto opterr;
++            }
++            break;
++        case OPT_MR:
++            mr = 1;
++            break;
++        case OPT_MB:
++            multiblock = 1;
++#ifdef OPENSSL_NO_MULTIBLOCK
++            BIO_printf(bio_err,
++                       "%s: -mb specified but multi-block support is disabled\n",
++                       prog);
++            goto end;
++#endif
++            break;
++        }
++    }
++    argc = opt_num_rest();
++    argv = opt_rest();
++
++    /* Remaining arguments are algorithms. */
++    for ( ; *argv; argv++) {
++        if (found(*argv, doit_choices, &i)) {
++            doit[i] = 1;
++            continue;
++        }
++#ifndef OPENSSL_NO_DES
++        if (strcmp(*argv, "des") == 0) {
++            doit[D_CBC_DES] = doit[D_EDE3_DES] = 1;
++            continue;
++        }
++#endif
++        if (strcmp(*argv, "sha") == 0) {
++            doit[D_SHA1] = doit[D_SHA256] = doit[D_SHA512] = 1;
++            continue;
++        }
++#ifndef OPENSSL_NO_RSA
++# ifndef RSA_NULL
++        if (strcmp(*argv, "openssl") == 0) {
++            RSA_set_default_method(RSA_PKCS1_OpenSSL());
++            continue;
++        }
++# endif
++        if (strcmp(*argv, "rsa") == 0) {
++            rsa_doit[R_RSA_512] = rsa_doit[R_RSA_1024] =
++                rsa_doit[R_RSA_2048] = rsa_doit[R_RSA_3072] =
++                rsa_doit[R_RSA_4096] = rsa_doit[R_RSA_7680] =
++                rsa_doit[R_RSA_15360] = 1;
++            continue;
++        }
++        if (found(*argv, rsa_choices, &i)) {
++            rsa_doit[i] = 1;
++            continue;
++        }
++#endif
++#ifndef OPENSSL_NO_DSA
++        if (strcmp(*argv, "dsa") == 0) {
++            dsa_doit[R_DSA_512] = dsa_doit[R_DSA_1024] =
++                dsa_doit[R_DSA_2048] = 1;
++            continue;
++        }
++        if (found(*argv, dsa_choices, &i)) {
++            dsa_doit[i] = 2;
++            continue;
++        }
++#endif
++        if (strcmp(*argv, "aes") == 0) {
++            doit[D_CBC_128_AES] = doit[D_CBC_192_AES] =
++                doit[D_CBC_256_AES] = 1;
++            continue;
++        }
++#ifndef OPENSSL_NO_CAMELLIA
++        if (strcmp(*argv, "camellia") == 0) {
++            doit[D_CBC_128_CML] = doit[D_CBC_192_CML] =
++                doit[D_CBC_256_CML] = 1;
++            continue;
++        }
++#endif
++#ifndef OPENSSL_NO_EC
++        if (strcmp(*argv, "ecdsa") == 0) {
++            for (i = 0; i < EC_NUM; i++)
++                ecdsa_doit[i] = 1;
++            continue;
++        }
++        if (found(*argv, ecdsa_choices, &i)) {
++            ecdsa_doit[i] = 2;
++            continue;
++        }
++        if (strcmp(*argv, "ecdh") == 0) {
++            for (i = 0; i < EC_NUM; i++)
++                ecdh_doit[i] = 1;
++            continue;
++        }
++        if (found(*argv, ecdh_choices, &i)) {
++            ecdh_doit[i] = 2;
++            continue;
++        }
++#endif
++        BIO_printf(bio_err, "%s: Unknown algorithm %s\n", prog, *argv);
++        goto end;
++    }
++
++    /* Initialize the job pool if async mode is enabled */
++    if (async_jobs > 0) {
++        async_init = ASYNC_init_thread(async_jobs, async_jobs);
++        if (!async_init) {
++            BIO_printf(bio_err, "Error creating the ASYNC job pool\n");
++            goto end;
++        }
++    }
++
++    loopargs_len = (async_jobs == 0 ? 1 : async_jobs);
++    loopargs = app_malloc(loopargs_len * sizeof(loopargs_t), "array of loopargs");
++    memset(loopargs, 0, loopargs_len * sizeof(loopargs_t));
++
++    for (i = 0; i < loopargs_len; i++) {
++        if (async_jobs > 0) {
++            loopargs[i].wait_ctx = ASYNC_WAIT_CTX_new();
++            if (loopargs[i].wait_ctx == NULL) {
++                BIO_printf(bio_err, "Error creating the ASYNC_WAIT_CTX\n");
++                goto end;
++            }
++        }
++
++        loopargs[i].buf_malloc = app_malloc((int)BUFSIZE + MAX_MISALIGNMENT + 1, "input buffer");
++        loopargs[i].buf2_malloc = app_malloc((int)BUFSIZE + MAX_MISALIGNMENT + 1, "input buffer");
++        /* Align the start of buffers on a 64 byte boundary */
++        loopargs[i].buf = loopargs[i].buf_malloc + misalign;
++        loopargs[i].buf2 = loopargs[i].buf2_malloc + misalign;
++#ifndef OPENSSL_NO_EC
++        loopargs[i].secret_a = app_malloc(MAX_ECDH_SIZE, "ECDH secret a");
++        loopargs[i].secret_b = app_malloc(MAX_ECDH_SIZE, "ECDH secret b");
++#endif
++    }
++
++#ifndef NO_FORK
++    if (multi && do_multi(multi))
++        goto show_res;
++#endif
++
++    /* Initialize the engine after the fork */
++    e = setup_engine(engine_id, 0);
++
++    /* No parameters; turn on everything. */
++    if ((argc == 0) && !doit[D_EVP]) {
++        for (i = 0; i < ALGOR_NUM; i++)
++            if (i != D_EVP)
++                doit[i] = 1;
++#ifndef OPENSSL_NO_RSA
++        for (i = 0; i < RSA_NUM; i++)
++            rsa_doit[i] = 1;
++#endif
++#ifndef OPENSSL_NO_DSA
++        for (i = 0; i < DSA_NUM; i++)
++            dsa_doit[i] = 1;
++#endif
++#ifndef OPENSSL_NO_EC
++        for (i = 0; i < EC_NUM; i++)
++            ecdsa_doit[i] = 1;
++        for (i = 0; i < EC_NUM; i++)
++            ecdh_doit[i] = 1;
++#endif
++    }
++    for (i = 0; i < ALGOR_NUM; i++)
++        if (doit[i])
++            pr_header++;
++
++    if (usertime == 0 && !mr)
++        BIO_printf(bio_err,
++                   "You have chosen to measure elapsed time "
++                   "instead of user CPU time.\n");
++
++#ifndef OPENSSL_NO_RSA
++    for (i = 0; i < loopargs_len; i++) {
++        for (k = 0; k < RSA_NUM; k++) {
++            const unsigned char *p;
++
++            p = rsa_data[k];
++            loopargs[i].rsa_key[k] = d2i_RSAPrivateKey(NULL, &p, rsa_data_length[k]);
++            if (loopargs[i].rsa_key[k] == NULL) {
++                BIO_printf(bio_err, "internal error loading RSA key number %d\n",
++                        k);
++                goto end;
++            }
++        }
++    }
++#endif
++#ifndef OPENSSL_NO_DSA
++    for (i = 0; i < loopargs_len; i++) {
++        loopargs[i].dsa_key[0] = get_dsa512();
++        loopargs[i].dsa_key[1] = get_dsa1024();
++        loopargs[i].dsa_key[2] = get_dsa2048();
++    }
++#endif
++#ifndef OPENSSL_NO_DES
++    DES_set_key_unchecked(&key, &sch);
++    DES_set_key_unchecked(&key2, &sch2);
++    DES_set_key_unchecked(&key3, &sch3);
++#endif
++    AES_set_encrypt_key(key16, 128, &aes_ks1);
++    AES_set_encrypt_key(key24, 192, &aes_ks2);
++    AES_set_encrypt_key(key32, 256, &aes_ks3);
++#ifndef OPENSSL_NO_CAMELLIA
++    Camellia_set_key(key16, 128, &camellia_ks1);
++    Camellia_set_key(ckey24, 192, &camellia_ks2);
++    Camellia_set_key(ckey32, 256, &camellia_ks3);
++#endif
++#ifndef OPENSSL_NO_IDEA
++    IDEA_set_encrypt_key(key16, &idea_ks);
++#endif
++#ifndef OPENSSL_NO_SEED
++    SEED_set_key(key16, &seed_ks);
++#endif
++#ifndef OPENSSL_NO_RC4
++    RC4_set_key(&rc4_ks, 16, key16);
++#endif
++#ifndef OPENSSL_NO_RC2
++    RC2_set_key(&rc2_ks, 16, key16, 128);
++#endif
++#ifndef OPENSSL_NO_RC5
++    RC5_32_set_key(&rc5_ks, 16, key16, 12);
++#endif
++#ifndef OPENSSL_NO_BF
++    BF_set_key(&bf_ks, 16, key16);
++#endif
++#ifndef OPENSSL_NO_CAST
++    CAST_set_key(&cast_ks, 16, key16);
++#endif
++#ifndef SIGALRM
++# ifndef OPENSSL_NO_DES
++    BIO_printf(bio_err, "First we calculate the approximate speed ...\n");
++    count = 10;
++    do {
++        long it;
++        count *= 2;
++        Time_F(START);
++        for (it = count; it; it--)
++            DES_ecb_encrypt((DES_cblock *)loopargs[0].buf,
++                            (DES_cblock *)loopargs[0].buf, &sch, DES_ENCRYPT);
++        d = Time_F(STOP);
++    } while (d < 3);
++    save_count = count;
++    c[D_MD2][0] = count / 10;
++    c[D_MDC2][0] = count / 10;
++    c[D_MD4][0] = count;
++    c[D_MD5][0] = count;
++    c[D_HMAC][0] = count;
++    c[D_SHA1][0] = count;
++    c[D_RMD160][0] = count;
++    c[D_RC4][0] = count * 5;
++    c[D_CBC_DES][0] = count;
++    c[D_EDE3_DES][0] = count / 3;
++    c[D_CBC_IDEA][0] = count;
++    c[D_CBC_SEED][0] = count;
++    c[D_CBC_RC2][0] = count;
++    c[D_CBC_RC5][0] = count;
++    c[D_CBC_BF][0] = count;
++    c[D_CBC_CAST][0] = count;
++    c[D_CBC_128_AES][0] = count;
++    c[D_CBC_192_AES][0] = count;
++    c[D_CBC_256_AES][0] = count;
++    c[D_CBC_128_CML][0] = count;
++    c[D_CBC_192_CML][0] = count;
++    c[D_CBC_256_CML][0] = count;
++    c[D_SHA256][0] = count;
++    c[D_SHA512][0] = count;
++    c[D_WHIRLPOOL][0] = count;
++    c[D_IGE_128_AES][0] = count;
++    c[D_IGE_192_AES][0] = count;
++    c[D_IGE_256_AES][0] = count;
++    c[D_GHASH][0] = count;
++
++    for (i = 1; i < SIZE_NUM; i++) {
++        long l0, l1;
++
++        l0 = (long)lengths[0];
++        l1 = (long)lengths[i];
++
++        c[D_MD2][i] = c[D_MD2][0] * 4 * l0 / l1;
++        c[D_MDC2][i] = c[D_MDC2][0] * 4 * l0 / l1;
++        c[D_MD4][i] = c[D_MD4][0] * 4 * l0 / l1;
++        c[D_MD5][i] = c[D_MD5][0] * 4 * l0 / l1;
++        c[D_HMAC][i] = c[D_HMAC][0] * 4 * l0 / l1;
++        c[D_SHA1][i] = c[D_SHA1][0] * 4 * l0 / l1;
++        c[D_RMD160][i] = c[D_RMD160][0] * 4 * l0 / l1;
++        c[D_SHA256][i] = c[D_SHA256][0] * 4 * l0 / l1;
++        c[D_SHA512][i] = c[D_SHA512][0] * 4 * l0 / l1;
++        c[D_WHIRLPOOL][i] = c[D_WHIRLPOOL][0] * 4 * l0 / l1;
++        c[D_GHASH][i] = c[D_GHASH][0] * 4 * l0 / l1;
++
++        l0 = (long)lengths[i - 1];
++
++        c[D_RC4][i] = c[D_RC4][i - 1] * l0 / l1;
++        c[D_CBC_DES][i] = c[D_CBC_DES][i - 1] * l0 / l1;
++        c[D_EDE3_DES][i] = c[D_EDE3_DES][i - 1] * l0 / l1;
++        c[D_CBC_IDEA][i] = c[D_CBC_IDEA][i - 1] * l0 / l1;
++        c[D_CBC_SEED][i] = c[D_CBC_SEED][i - 1] * l0 / l1;
++        c[D_CBC_RC2][i] = c[D_CBC_RC2][i - 1] * l0 / l1;
++        c[D_CBC_RC5][i] = c[D_CBC_RC5][i - 1] * l0 / l1;
++        c[D_CBC_BF][i] = c[D_CBC_BF][i - 1] * l0 / l1;
++        c[D_CBC_CAST][i] = c[D_CBC_CAST][i - 1] * l0 / l1;
++        c[D_CBC_128_AES][i] = c[D_CBC_128_AES][i - 1] * l0 / l1;
++        c[D_CBC_192_AES][i] = c[D_CBC_192_AES][i - 1] * l0 / l1;
++        c[D_CBC_256_AES][i] = c[D_CBC_256_AES][i - 1] * l0 / l1;
++        c[D_CBC_128_CML][i] = c[D_CBC_128_CML][i - 1] * l0 / l1;
++        c[D_CBC_192_CML][i] = c[D_CBC_192_CML][i - 1] * l0 / l1;
++        c[D_CBC_256_CML][i] = c[D_CBC_256_CML][i - 1] * l0 / l1;
++        c[D_IGE_128_AES][i] = c[D_IGE_128_AES][i - 1] * l0 / l1;
++        c[D_IGE_192_AES][i] = c[D_IGE_192_AES][i - 1] * l0 / l1;
++        c[D_IGE_256_AES][i] = c[D_IGE_256_AES][i - 1] * l0 / l1;
++    }
++
++#  ifndef OPENSSL_NO_RSA
++    rsa_c[R_RSA_512][0] = count / 2000;
++    rsa_c[R_RSA_512][1] = count / 400;
++    for (i = 1; i < RSA_NUM; i++) {
++        rsa_c[i][0] = rsa_c[i - 1][0] / 8;
++        rsa_c[i][1] = rsa_c[i - 1][1] / 4;
++        if (rsa_doit[i] <= 1 && rsa_c[i][0] == 0)
++            rsa_doit[i] = 0;
++        else {
++            if (rsa_c[i][0] == 0) {
++                rsa_c[i][0] = 1;            /* Set minimum iteration Nb to 1. */
++                rsa_c[i][1] = 20;
++            }
++        }
++    }
++#  endif
++
++#  ifndef OPENSSL_NO_DSA
++    dsa_c[R_DSA_512][0] = count / 1000;
++    dsa_c[R_DSA_512][1] = count / 1000 / 2;
++    for (i = 1; i < DSA_NUM; i++) {
++        dsa_c[i][0] = dsa_c[i - 1][0] / 4;
++        dsa_c[i][1] = dsa_c[i - 1][1] / 4;
++        if (dsa_doit[i] <= 1 && dsa_c[i][0] == 0)
++            dsa_doit[i] = 0;
++        else {
++            if (dsa_c[i][0] == 0) {
++                dsa_c[i][0] = 1;            /* Set minimum iteration Nb to 1. */
++                dsa_c[i][1] = 1;
++            }
++        }
++    }
++#  endif
++
++#  ifndef OPENSSL_NO_EC
++    ecdsa_c[R_EC_P160][0] = count / 1000;
++    ecdsa_c[R_EC_P160][1] = count / 1000 / 2;
++    for (i = R_EC_P192; i <= R_EC_P521; i++) {
++        ecdsa_c[i][0] = ecdsa_c[i - 1][0] / 2;
++        ecdsa_c[i][1] = ecdsa_c[i - 1][1] / 2;
++        if (ecdsa_doit[i] <= 1 && ecdsa_c[i][0] == 0)
++            ecdsa_doit[i] = 0;
++        else {
++            if (ecdsa_c[i][0] == 0) {
++                ecdsa_c[i][0] = 1;
++                ecdsa_c[i][1] = 1;
++            }
++        }
++    }
++    ecdsa_c[R_EC_K163][0] = count / 1000;
++    ecdsa_c[R_EC_K163][1] = count / 1000 / 2;
++    for (i = R_EC_K233; i <= R_EC_K571; i++) {
++        ecdsa_c[i][0] = ecdsa_c[i - 1][0] / 2;
++        ecdsa_c[i][1] = ecdsa_c[i - 1][1] / 2;
++        if (ecdsa_doit[i] <= 1 && ecdsa_c[i][0] == 0)
++            ecdsa_doit[i] = 0;
++        else {
++            if (ecdsa_c[i][0] == 0) {
++                ecdsa_c[i][0] = 1;
++                ecdsa_c[i][1] = 1;
++            }
++        }
++    }
++    ecdsa_c[R_EC_B163][0] = count / 1000;
++    ecdsa_c[R_EC_B163][1] = count / 1000 / 2;
++    for (i = R_EC_B233; i <= R_EC_B571; i++) {
++        ecdsa_c[i][0] = ecdsa_c[i - 1][0] / 2;
++        ecdsa_c[i][1] = ecdsa_c[i - 1][1] / 2;
++        if (ecdsa_doit[i] <= 1 && ecdsa_c[i][0] == 0)
++            ecdsa_doit[i] = 0;
++        else {
++            if (ecdsa_c[i][0] == 0) {
++                ecdsa_c[i][0] = 1;
++                ecdsa_c[i][1] = 1;
++            }
++        }
++    }
++
++    ecdh_c[R_EC_P160][0] = count / 1000;
++    for (i = R_EC_P192; i <= R_EC_P521; i++) {
++        ecdh_c[i][0] = ecdh_c[i - 1][0] / 2;
++        if (ecdh_doit[i] <= 1 && ecdh_c[i][0] == 0)
++            ecdh_doit[i] = 0;
++        else {
++            if (ecdh_c[i][0] == 0) {
++                ecdh_c[i][0] = 1;
++            }
++        }
++    }
++    ecdh_c[R_EC_K163][0] = count / 1000;
++    for (i = R_EC_K233; i <= R_EC_K571; i++) {
++        ecdh_c[i][0] = ecdh_c[i - 1][0] / 2;
++        if (ecdh_doit[i] <= 1 && ecdh_c[i][0] == 0)
++            ecdh_doit[i] = 0;
++        else {
++            if (ecdh_c[i][0] == 0) {
++                ecdh_c[i][0] = 1;
++            }
++        }
++    }
++    ecdh_c[R_EC_B163][0] = count / 1000;
++    for (i = R_EC_B233; i <= R_EC_B571; i++) {
++        ecdh_c[i][0] = ecdh_c[i - 1][0] / 2;
++        if (ecdh_doit[i] <= 1 && ecdh_c[i][0] == 0)
++            ecdh_doit[i] = 0;
++        else {
++            if (ecdh_c[i][0] == 0) {
++                ecdh_c[i][0] = 1;
++            }
++        }
++    }
++#  endif
++
++# else
++/* not worth fixing */
++#  error "You cannot disable DES on systems without SIGALRM."
++# endif                        /* OPENSSL_NO_DES */
++#else
++# ifndef _WIN32
++    signal(SIGALRM, sig_done);
++# endif
++#endif                         /* SIGALRM */
++
++#ifndef OPENSSL_NO_MD2
++    if (doit[D_MD2]) {
++        for (testnum = 0; testnum < SIZE_NUM; testnum++) {
++            print_message(names[D_MD2], c[D_MD2][testnum], lengths[testnum]);
++            Time_F(START);
++            count = run_benchmark(async_jobs, EVP_Digest_MD2_loop, loopargs);
++            d = Time_F(STOP);
++            print_result(D_MD2, testnum, count, d);
++        }
++    }
++#endif
++#ifndef OPENSSL_NO_MDC2
++    if (doit[D_MDC2]) {
++        for (testnum = 0; testnum < SIZE_NUM; testnum++) {
++            print_message(names[D_MDC2], c[D_MDC2][testnum], lengths[testnum]);
++            Time_F(START);
++            count = run_benchmark(async_jobs, EVP_Digest_MDC2_loop, loopargs);
++            d = Time_F(STOP);
++            print_result(D_MDC2, testnum, count, d);
++        }
++    }
++#endif
++
++#ifndef OPENSSL_NO_MD4
++    if (doit[D_MD4]) {
++        for (testnum = 0; testnum < SIZE_NUM; testnum++) {
++            print_message(names[D_MD4], c[D_MD4][testnum], lengths[testnum]);
++            Time_F(START);
++            count = run_benchmark(async_jobs, EVP_Digest_MD4_loop, loopargs);
++            d = Time_F(STOP);
++            print_result(D_MD4, testnum, count, d);
++        }
++    }
++#endif
++
++#ifndef OPENSSL_NO_MD5
++    if (doit[D_MD5]) {
++        for (testnum = 0; testnum < SIZE_NUM; testnum++) {
++            print_message(names[D_MD5], c[D_MD5][testnum], lengths[testnum]);
++            Time_F(START);
++            count = run_benchmark(async_jobs, MD5_loop, loopargs);
++            d = Time_F(STOP);
++            print_result(D_MD5, testnum, count, d);
++        }
++    }
++
++    if (doit[D_HMAC]) {
++        static const char hmac_key[] = "This is a key...";
++        int len = strlen(hmac_key);
++
++        for (i = 0; i < loopargs_len; i++) {
++            loopargs[i].hctx = HMAC_CTX_new();
++            if (loopargs[i].hctx == NULL) {
++                BIO_printf(bio_err, "HMAC malloc failure, exiting...");
++                exit(1);
++            }
++
++            HMAC_Init_ex(loopargs[i].hctx, hmac_key, len, EVP_md5(), NULL);
++        }
++        for (testnum = 0; testnum < SIZE_NUM; testnum++) {
++            print_message(names[D_HMAC], c[D_HMAC][testnum], lengths[testnum]);
++            Time_F(START);
++            count = run_benchmark(async_jobs, HMAC_loop, loopargs);
++            d = Time_F(STOP);
++            print_result(D_HMAC, testnum, count, d);
++        }
++        for (i = 0; i < loopargs_len; i++) {
++            HMAC_CTX_free(loopargs[i].hctx);
++        }
++    }
++#endif
++    if (doit[D_SHA1]) {
++        for (testnum = 0; testnum < SIZE_NUM; testnum++) {
++            print_message(names[D_SHA1], c[D_SHA1][testnum], lengths[testnum]);
++            Time_F(START);
++            count = run_benchmark(async_jobs, SHA1_loop, loopargs);
++            d = Time_F(STOP);
++            print_result(D_SHA1, testnum, count, d);
++        }
++    }
++    if (doit[D_SHA256]) {
++        for (testnum = 0; testnum < SIZE_NUM; testnum++) {
++            print_message(names[D_SHA256], c[D_SHA256][testnum], lengths[testnum]);
++            Time_F(START);
++            count = run_benchmark(async_jobs, SHA256_loop, loopargs);
++            d = Time_F(STOP);
++            print_result(D_SHA256, testnum, count, d);
++        }
++    }
++    if (doit[D_SHA512]) {
++        for (testnum = 0; testnum < SIZE_NUM; testnum++) {
++            print_message(names[D_SHA512], c[D_SHA512][testnum], lengths[testnum]);
++            Time_F(START);
++            count = run_benchmark(async_jobs, SHA512_loop, loopargs);
++            d = Time_F(STOP);
++            print_result(D_SHA512, testnum, count, d);
++        }
++    }
++
++#ifndef OPENSSL_NO_WHIRLPOOL
++    if (doit[D_WHIRLPOOL]) {
++        for (testnum = 0; testnum < SIZE_NUM; testnum++) {
++            print_message(names[D_WHIRLPOOL], c[D_WHIRLPOOL][testnum], lengths[testnum]);
++            Time_F(START);
++            count = run_benchmark(async_jobs, WHIRLPOOL_loop, loopargs);
++            d = Time_F(STOP);
++            print_result(D_WHIRLPOOL, testnum, count, d);
++        }
++    }
++#endif
++
++#ifndef OPENSSL_NO_RMD160
++    if (doit[D_RMD160]) {
++        for (testnum = 0; testnum < SIZE_NUM; testnum++) {
++            print_message(names[D_RMD160], c[D_RMD160][testnum], lengths[testnum]);
++            Time_F(START);
++            count = run_benchmark(async_jobs, EVP_Digest_RMD160_loop, loopargs);
++            d = Time_F(STOP);
++            print_result(D_RMD160, testnum, count, d);
++        }
++    }
++#endif
++#ifndef OPENSSL_NO_RC4
++    if (doit[D_RC4]) {
++        for (testnum = 0; testnum < SIZE_NUM; testnum++) {
++            print_message(names[D_RC4], c[D_RC4][testnum], lengths[testnum]);
++            Time_F(START);
++            count = run_benchmark(async_jobs, RC4_loop, loopargs);
++            d = Time_F(STOP);
++            print_result(D_RC4, testnum, count, d);
++        }
++    }
++#endif
++#ifndef OPENSSL_NO_DES
++    if (doit[D_CBC_DES]) {
++        for (testnum = 0; testnum < SIZE_NUM; testnum++) {
++            print_message(names[D_CBC_DES], c[D_CBC_DES][testnum], lengths[testnum]);
++            Time_F(START);
++            count = run_benchmark(async_jobs, DES_ncbc_encrypt_loop, loopargs);
++            d = Time_F(STOP);
++            print_result(D_CBC_DES, testnum, count, d);
++        }
++    }
++
++    if (doit[D_EDE3_DES]) {
++        for (testnum = 0; testnum < SIZE_NUM; testnum++) {
++            print_message(names[D_EDE3_DES], c[D_EDE3_DES][testnum], lengths[testnum]);
++            Time_F(START);
++            count = run_benchmark(async_jobs, DES_ede3_cbc_encrypt_loop, loopargs);
++            d = Time_F(STOP);
++            print_result(D_EDE3_DES, testnum, count, d);
++        }
++    }
++#endif
++
++    if (doit[D_CBC_128_AES]) {
++        for (testnum = 0; testnum < SIZE_NUM; testnum++) {
++            print_message(names[D_CBC_128_AES], c[D_CBC_128_AES][testnum],
++                          lengths[testnum]);
++            Time_F(START);
++            count = run_benchmark(async_jobs, AES_cbc_128_encrypt_loop, loopargs);
++            d = Time_F(STOP);
++            print_result(D_CBC_128_AES, testnum, count, d);
++        }
++    }
++    if (doit[D_CBC_192_AES]) {
++        for (testnum = 0; testnum < SIZE_NUM; testnum++) {
++            print_message(names[D_CBC_192_AES], c[D_CBC_192_AES][testnum],
++                          lengths[testnum]);
++            Time_F(START);
++            count = run_benchmark(async_jobs, AES_cbc_192_encrypt_loop, loopargs);
++            d = Time_F(STOP);
++            print_result(D_CBC_192_AES, testnum, count, d);
++        }
++    }
++    if (doit[D_CBC_256_AES]) {
++        for (testnum = 0; testnum < SIZE_NUM; testnum++) {
++            print_message(names[D_CBC_256_AES], c[D_CBC_256_AES][testnum],
++                          lengths[testnum]);
++            Time_F(START);
++            count = run_benchmark(async_jobs, AES_cbc_256_encrypt_loop, loopargs);
++            d = Time_F(STOP);
++            print_result(D_CBC_256_AES, testnum, count, d);
++        }
++    }
++
++    if (doit[D_IGE_128_AES]) {
++        for (testnum = 0; testnum < SIZE_NUM; testnum++) {
++            print_message(names[D_IGE_128_AES], c[D_IGE_128_AES][testnum],
++                          lengths[testnum]);
++            Time_F(START);
++            count = run_benchmark(async_jobs, AES_ige_128_encrypt_loop, loopargs);
++            d = Time_F(STOP);
++            print_result(D_IGE_128_AES, testnum, count, d);
++        }
++    }
++    if (doit[D_IGE_192_AES]) {
++        for (testnum = 0; testnum < SIZE_NUM; testnum++) {
++            print_message(names[D_IGE_192_AES], c[D_IGE_192_AES][testnum],
++                          lengths[testnum]);
++            Time_F(START);
++            count = run_benchmark(async_jobs, AES_ige_192_encrypt_loop, loopargs);
++            d = Time_F(STOP);
++            print_result(D_IGE_192_AES, testnum, count, d);
++        }
++    }
++    if (doit[D_IGE_256_AES]) {
++        for (testnum = 0; testnum < SIZE_NUM; testnum++) {
++            print_message(names[D_IGE_256_AES], c[D_IGE_256_AES][testnum],
++                          lengths[testnum]);
++            Time_F(START);
++            count = run_benchmark(async_jobs, AES_ige_256_encrypt_loop, loopargs);
++            d = Time_F(STOP);
++            print_result(D_IGE_256_AES, testnum, count, d);
++        }
++    }
++    if (doit[D_GHASH]) {
++        for (i = 0; i < loopargs_len; i++) {
++            loopargs[i].gcm_ctx = CRYPTO_gcm128_new(&aes_ks1, (block128_f) AES_encrypt);
++            CRYPTO_gcm128_setiv(loopargs[i].gcm_ctx, (unsigned char *)"0123456789ab", 12);
++        }
++
++        for (testnum = 0; testnum < SIZE_NUM; testnum++) {
++            print_message(names[D_GHASH], c[D_GHASH][testnum], lengths[testnum]);
++            Time_F(START);
++            count = run_benchmark(async_jobs, CRYPTO_gcm128_aad_loop, loopargs);
++            d = Time_F(STOP);
++            print_result(D_GHASH, testnum, count, d);
++        }
++        for (i = 0; i < loopargs_len; i++)
++            CRYPTO_gcm128_release(loopargs[i].gcm_ctx);
++    }
++
++#ifndef OPENSSL_NO_CAMELLIA
++    if (doit[D_CBC_128_CML]) {
++        if (async_jobs > 0) {
++            BIO_printf(bio_err, "Async mode is not supported with %s\n",
++                       names[D_CBC_128_CML]);
++            doit[D_CBC_128_CML] = 0;
++        }
++        for (testnum = 0; testnum < SIZE_NUM && async_init == 0; testnum++) {
++            print_message(names[D_CBC_128_CML], c[D_CBC_128_CML][testnum],
++                          lengths[testnum]);
++            Time_F(START);
++            for (count = 0, run = 1; COND(c[D_CBC_128_CML][testnum]); count++)
++                Camellia_cbc_encrypt(loopargs[0].buf, loopargs[0].buf,
++                                     (size_t)lengths[testnum], &camellia_ks1,
++                                     iv, CAMELLIA_ENCRYPT);
++            d = Time_F(STOP);
++            print_result(D_CBC_128_CML, testnum, count, d);
++        }
++    }
++    if (doit[D_CBC_192_CML]) {
++        if (async_jobs > 0) {
++            BIO_printf(bio_err, "Async mode is not supported with %s\n",
++                       names[D_CBC_192_CML]);
++            doit[D_CBC_192_CML] = 0;
++        }
++        for (testnum = 0; testnum < SIZE_NUM && async_init == 0; testnum++) {
++            print_message(names[D_CBC_192_CML], c[D_CBC_192_CML][testnum],
++                          lengths[testnum]);
++            if (async_jobs > 0) {
++                BIO_printf(bio_err, "Async mode is not supported, exiting...");
++                exit(1);
++            }
++            Time_F(START);
++            for (count = 0, run = 1; COND(c[D_CBC_192_CML][testnum]); count++)
++                Camellia_cbc_encrypt(loopargs[0].buf, loopargs[0].buf,
++                                     (size_t)lengths[testnum], &camellia_ks2,
++                                     iv, CAMELLIA_ENCRYPT);
++            d = Time_F(STOP);
++            print_result(D_CBC_192_CML, testnum, count, d);
++        }
++    }
++    if (doit[D_CBC_256_CML]) {
++        if (async_jobs > 0) {
++            BIO_printf(bio_err, "Async mode is not supported with %s\n",
++                       names[D_CBC_256_CML]);
++            doit[D_CBC_256_CML] = 0;
++        }
++        for (testnum = 0; testnum < SIZE_NUM && async_init == 0; testnum++) {
++            print_message(names[D_CBC_256_CML], c[D_CBC_256_CML][testnum],
++                          lengths[testnum]);
++            Time_F(START);
++            for (count = 0, run = 1; COND(c[D_CBC_256_CML][testnum]); count++)
++                Camellia_cbc_encrypt(loopargs[0].buf, loopargs[0].buf,
++                                     (size_t)lengths[testnum], &camellia_ks3,
++                                     iv, CAMELLIA_ENCRYPT);
++            d = Time_F(STOP);
++            print_result(D_CBC_256_CML, testnum, count, d);
++        }
++    }
++#endif
++#ifndef OPENSSL_NO_IDEA
++    if (doit[D_CBC_IDEA]) {
++        if (async_jobs > 0) {
++            BIO_printf(bio_err, "Async mode is not supported with %s\n",
++                       names[D_CBC_IDEA]);
++            doit[D_CBC_IDEA] = 0;
++        }
++        for (testnum = 0; testnum < SIZE_NUM && async_init == 0; testnum++) {
++            print_message(names[D_CBC_IDEA], c[D_CBC_IDEA][testnum], lengths[testnum]);
++            Time_F(START);
++            for (count = 0, run = 1; COND(c[D_CBC_IDEA][testnum]); count++)
++                IDEA_cbc_encrypt(loopargs[0].buf, loopargs[0].buf,
++                                 (size_t)lengths[testnum], &idea_ks,
++                                 iv, IDEA_ENCRYPT);
++            d = Time_F(STOP);
++            print_result(D_CBC_IDEA, testnum, count, d);
++        }
++    }
++#endif
++#ifndef OPENSSL_NO_SEED
++    if (doit[D_CBC_SEED]) {
++        if (async_jobs > 0) {
++            BIO_printf(bio_err, "Async mode is not supported with %s\n",
++                       names[D_CBC_SEED]);
++            doit[D_CBC_SEED] = 0;
++        }
++        for (testnum = 0; testnum < SIZE_NUM && async_init == 0; testnum++) {
++            print_message(names[D_CBC_SEED], c[D_CBC_SEED][testnum], lengths[testnum]);
++            Time_F(START);
++            for (count = 0, run = 1; COND(c[D_CBC_SEED][testnum]); count++)
++                SEED_cbc_encrypt(loopargs[0].buf, loopargs[0].buf,
++                                 (size_t)lengths[testnum], &seed_ks, iv, 1);
++            d = Time_F(STOP);
++            print_result(D_CBC_SEED, testnum, count, d);
++        }
++    }
++#endif
++#ifndef OPENSSL_NO_RC2
++    if (doit[D_CBC_RC2]) {
++        if (async_jobs > 0) {
++            BIO_printf(bio_err, "Async mode is not supported with %s\n",
++                       names[D_CBC_RC2]);
++            doit[D_CBC_RC2] = 0;
++        }
++        for (testnum = 0; testnum < SIZE_NUM && async_init == 0; testnum++) {
++            print_message(names[D_CBC_RC2], c[D_CBC_RC2][testnum], lengths[testnum]);
++            if (async_jobs > 0) {
++                BIO_printf(bio_err, "Async mode is not supported, exiting...");
++                exit(1);
++            }
++            Time_F(START);
++            for (count = 0, run = 1; COND(c[D_CBC_RC2][testnum]); count++)
++                RC2_cbc_encrypt(loopargs[0].buf, loopargs[0].buf,
++                                (size_t)lengths[testnum], &rc2_ks,
++                                iv, RC2_ENCRYPT);
++            d = Time_F(STOP);
++            print_result(D_CBC_RC2, testnum, count, d);
++        }
++    }
++#endif
++#ifndef OPENSSL_NO_RC5
++    if (doit[D_CBC_RC5]) {
++        if (async_jobs > 0) {
++            BIO_printf(bio_err, "Async mode is not supported with %s\n",
++                       names[D_CBC_RC5]);
++            doit[D_CBC_RC5] = 0;
++        }
++        for (testnum = 0; testnum < SIZE_NUM && async_init == 0; testnum++) {
++            print_message(names[D_CBC_RC5], c[D_CBC_RC5][testnum], lengths[testnum]);
++            if (async_jobs > 0) {
++                BIO_printf(bio_err, "Async mode is not supported, exiting...");
++                exit(1);
++            }
++            Time_F(START);
++            for (count = 0, run = 1; COND(c[D_CBC_RC5][testnum]); count++)
++                RC5_32_cbc_encrypt(loopargs[0].buf, loopargs[0].buf,
++                                   (size_t)lengths[testnum], &rc5_ks,
++                                   iv, RC5_ENCRYPT);
++            d = Time_F(STOP);
++            print_result(D_CBC_RC5, testnum, count, d);
++        }
++    }
++#endif
++#ifndef OPENSSL_NO_BF
++    if (doit[D_CBC_BF]) {
++        if (async_jobs > 0) {
++            BIO_printf(bio_err, "Async mode is not supported with %s\n",
++                       names[D_CBC_BF]);
++            doit[D_CBC_BF] = 0;
++        }
++        for (testnum = 0; testnum < SIZE_NUM && async_init == 0; testnum++) {
++            print_message(names[D_CBC_BF], c[D_CBC_BF][testnum], lengths[testnum]);
++            Time_F(START);
++            for (count = 0, run = 1; COND(c[D_CBC_BF][testnum]); count++)
++                BF_cbc_encrypt(loopargs[0].buf, loopargs[0].buf,
++                               (size_t)lengths[testnum], &bf_ks,
++                               iv, BF_ENCRYPT);
++            d = Time_F(STOP);
++            print_result(D_CBC_BF, testnum, count, d);
++        }
++    }
++#endif
++#ifndef OPENSSL_NO_CAST
++    if (doit[D_CBC_CAST]) {
++        if (async_jobs > 0) {
++            BIO_printf(bio_err, "Async mode is not supported with %s\n",
++                       names[D_CBC_CAST]);
++            doit[D_CBC_CAST] = 0;
++        }
++        for (testnum = 0; testnum < SIZE_NUM && async_init == 0; testnum++) {
++            print_message(names[D_CBC_CAST], c[D_CBC_CAST][testnum], lengths[testnum]);
++            Time_F(START);
++            for (count = 0, run = 1; COND(c[D_CBC_CAST][testnum]); count++)
++                CAST_cbc_encrypt(loopargs[0].buf, loopargs[0].buf,
++                                 (size_t)lengths[testnum], &cast_ks,
++                                 iv, CAST_ENCRYPT);
++            d = Time_F(STOP);
++            print_result(D_CBC_CAST, testnum, count, d);
++        }
++    }
++#endif
++
++    if (doit[D_EVP]) {
++        if (multiblock && evp_cipher) {
++            if (!
++                (EVP_CIPHER_flags(evp_cipher) &
++                 EVP_CIPH_FLAG_TLS1_1_MULTIBLOCK)) {
++                BIO_printf(bio_err, "%s is not multi-block capable\n",
++                           OBJ_nid2ln(EVP_CIPHER_nid(evp_cipher)));
++                goto end;
++            }
++            if (async_jobs > 0) {
++                BIO_printf(bio_err, "Async mode is not supported, exiting...");
++                exit(1);
++            }
++            multiblock_speed(evp_cipher);
++            ret = 0;
++            goto end;
++        }
++        for (testnum = 0; testnum < SIZE_NUM; testnum++) {
++            if (evp_cipher) {
++
++                names[D_EVP] = OBJ_nid2ln(EVP_CIPHER_nid(evp_cipher));
++                /*
++                 * -O3 -fschedule-insns messes up an optimization here!
++                 * names[D_EVP] somehow becomes NULL
++                 */
++                print_message(names[D_EVP], save_count, lengths[testnum]);
++
++                for (k = 0; k < loopargs_len; k++) {
++                    loopargs[k].ctx = EVP_CIPHER_CTX_new();
++                    if (decrypt)
++                        EVP_DecryptInit_ex(loopargs[k].ctx, evp_cipher, NULL, key16, iv);
++                    else
++                        EVP_EncryptInit_ex(loopargs[k].ctx, evp_cipher, NULL, key16, iv);
++                    EVP_CIPHER_CTX_set_padding(loopargs[k].ctx, 0);
++                }
++
++                Time_F(START);
++                count = run_benchmark(async_jobs, EVP_Update_loop, loopargs);
++                d = Time_F(STOP);
++                for (k = 0; k < loopargs_len; k++) {
++                    EVP_CIPHER_CTX_free(loopargs[k].ctx);
++                }
++            }
++            if (evp_md) {
++                names[D_EVP] = OBJ_nid2ln(EVP_MD_type(evp_md));
++                print_message(names[D_EVP], save_count, lengths[testnum]);
++                Time_F(START);
++                count = run_benchmark(async_jobs, EVP_Digest_loop, loopargs);
++                d = Time_F(STOP);
++            }
++            print_result(D_EVP, testnum, count, d);
++        }
++    }
++
++    for (i = 0; i < loopargs_len; i++)
++        RAND_bytes(loopargs[i].buf, 36);
++
++#ifndef OPENSSL_NO_RSA
++    for (testnum = 0; testnum < RSA_NUM; testnum++) {
++        int st = 0;
++        if (!rsa_doit[testnum])
++            continue;
++        for (i = 0; i < loopargs_len; i++) {
++            st = RSA_sign(NID_md5_sha1, loopargs[i].buf, 36, loopargs[i].buf2,
++                          &loopargs[i].siglen, loopargs[i].rsa_key[testnum]);
++            if (st == 0)
++                break;
++        }
++        if (st == 0) {
++            BIO_printf(bio_err,
++                       "RSA sign failure.  No RSA sign will be done.\n");
++            ERR_print_errors(bio_err);
++            rsa_count = 1;
++        } else {
++            pkey_print_message("private", "rsa",
++                               rsa_c[testnum][0], rsa_bits[testnum], RSA_SECONDS);
++            /* RSA_blinding_on(rsa_key[testnum],NULL); */
++            Time_F(START);
++            count = run_benchmark(async_jobs, RSA_sign_loop, loopargs);
++            d = Time_F(STOP);
++            BIO_printf(bio_err,
++                       mr ? "+R1:%ld:%d:%.2f\n"
++                       : "%ld %d bit private RSA's in %.2fs\n",
++                       count, rsa_bits[testnum], d);
++            rsa_results[testnum][0] = d / (double)count;
++            rsa_count = count;
++        }
++
++        for (i = 0; i < loopargs_len; i++) {
++            st = RSA_verify(NID_md5_sha1, loopargs[i].buf, 36, loopargs[i].buf2,
++                            loopargs[i].siglen, loopargs[i].rsa_key[testnum]);
++            if (st <= 0)
++                break;
++        }
++        if (st <= 0) {
++            BIO_printf(bio_err,
++                       "RSA verify failure.  No RSA verify will be done.\n");
++            ERR_print_errors(bio_err);
++            rsa_doit[testnum] = 0;
++        } else {
++            pkey_print_message("public", "rsa",
++                               rsa_c[testnum][1], rsa_bits[testnum], RSA_SECONDS);
++            Time_F(START);
++            count = run_benchmark(async_jobs, RSA_verify_loop, loopargs);
++            d = Time_F(STOP);
++            BIO_printf(bio_err,
++                       mr ? "+R2:%ld:%d:%.2f\n"
++                       : "%ld %d bit public RSA's in %.2fs\n",
++                       count, rsa_bits[testnum], d);
++            rsa_results[testnum][1] = d / (double)count;
++        }
++
++        if (rsa_count <= 1) {
++            /* if longer than 10s, don't do any more */
++            for (testnum++; testnum < RSA_NUM; testnum++)
++                rsa_doit[testnum] = 0;
++        }
++    }
++#endif                          /* OPENSSL_NO_RSA */
++
++    for (i = 0; i < loopargs_len; i++)
++        RAND_bytes(loopargs[i].buf, 36);
++
++#ifndef OPENSSL_NO_DSA
++    if (RAND_status() != 1) {
++        RAND_seed(rnd_seed, sizeof rnd_seed);
++    }
++    for (testnum = 0; testnum < DSA_NUM; testnum++) {
++        int st = 0;
++        if (!dsa_doit[testnum])
++            continue;
++
++        /* DSA_generate_key(dsa_key[testnum]); */
++        /* DSA_sign_setup(dsa_key[testnum],NULL); */
++        for (i = 0; i < loopargs_len; i++) {
++            st = DSA_sign(0, loopargs[i].buf, 20, loopargs[i].buf2,
++                          &loopargs[i].siglen, loopargs[i].dsa_key[testnum]);
++            if (st == 0)
++                break;
++        }
++        if (st == 0) {
++            BIO_printf(bio_err,
++                       "DSA sign failure.  No DSA sign will be done.\n");
++            ERR_print_errors(bio_err);
++            rsa_count = 1;
++        } else {
++            pkey_print_message("sign", "dsa",
++                               dsa_c[testnum][0], dsa_bits[testnum], DSA_SECONDS);
++            Time_F(START);
++            count = run_benchmark(async_jobs, DSA_sign_loop, loopargs);
++            d = Time_F(STOP);
++            BIO_printf(bio_err,
++                       mr ? "+R3:%ld:%d:%.2f\n"
++                       : "%ld %d bit DSA signs in %.2fs\n",
++                       count, dsa_bits[testnum], d);
++            dsa_results[testnum][0] = d / (double)count;
++            rsa_count = count;
++        }
++
++        for (i = 0; i < loopargs_len; i++) {
++            st = DSA_verify(0, loopargs[i].buf, 20, loopargs[i].buf2,
++                            loopargs[i].siglen, loopargs[i].dsa_key[testnum]);
++            if (st <= 0)
++                break;
++        }
++        if (st <= 0) {
++            BIO_printf(bio_err,
++                       "DSA verify failure.  No DSA verify will be done.\n");
++            ERR_print_errors(bio_err);
++            dsa_doit[testnum] = 0;
++        } else {
++            pkey_print_message("verify", "dsa",
++                               dsa_c[testnum][1], dsa_bits[testnum], DSA_SECONDS);
++            Time_F(START);
++            count = run_benchmark(async_jobs, DSA_verify_loop, loopargs);
++            d = Time_F(STOP);
++            BIO_printf(bio_err,
++                       mr ? "+R4:%ld:%d:%.2f\n"
++                       : "%ld %d bit DSA verify in %.2fs\n",
++                       count, dsa_bits[testnum], d);
++            dsa_results[testnum][1] = d / (double)count;
++        }
++
++        if (rsa_count <= 1) {
++            /* if longer than 10s, don't do any more */
++            for (testnum++; testnum < DSA_NUM; testnum++)
++                dsa_doit[testnum] = 0;
++        }
++    }
++#endif                          /* OPENSSL_NO_DSA */
++
++#ifndef OPENSSL_NO_EC
++    if (RAND_status() != 1) {
++        RAND_seed(rnd_seed, sizeof rnd_seed);
++    }
++    for (testnum = 0; testnum < EC_NUM; testnum++) {
++        int st = 1;
++
++        if (!ecdsa_doit[testnum])
++            continue;           /* Ignore Curve */
++        for (i = 0; i < loopargs_len; i++) {
++            loopargs[i].ecdsa[testnum] = EC_KEY_new_by_curve_name(test_curves[testnum]);
++            if (loopargs[i].ecdsa[testnum] == NULL) {
++                st = 0;
++                break;
++            }
++        }
++        if (st == 0) {
++            BIO_printf(bio_err, "ECDSA failure.\n");
++            ERR_print_errors(bio_err);
++            rsa_count = 1;
++        } else {
++            for (i = 0; i < loopargs_len; i++) {
++                EC_KEY_precompute_mult(loopargs[i].ecdsa[testnum], NULL);
++                /* Perform ECDSA signature test */
++                EC_KEY_generate_key(loopargs[i].ecdsa[testnum]);
++                st = ECDSA_sign(0, loopargs[i].buf, 20, loopargs[i].buf2,
++                                &loopargs[i].siglen, loopargs[i].ecdsa[testnum]);
++                if (st == 0)
++                    break;
++            }
++            if (st == 0) {
++                BIO_printf(bio_err,
++                           "ECDSA sign failure.  No ECDSA sign will be done.\n");
++                ERR_print_errors(bio_err);
++                rsa_count = 1;
++            } else {
++                pkey_print_message("sign", "ecdsa",
++                                   ecdsa_c[testnum][0],
++                                   test_curves_bits[testnum], ECDSA_SECONDS);
++                Time_F(START);
++                count = run_benchmark(async_jobs, ECDSA_sign_loop, loopargs);
++                d = Time_F(STOP);
++
++                BIO_printf(bio_err,
++                           mr ? "+R5:%ld:%d:%.2f\n" :
++                           "%ld %d bit ECDSA signs in %.2fs \n",
++                           count, test_curves_bits[testnum], d);
++                ecdsa_results[testnum][0] = d / (double)count;
++                rsa_count = count;
++            }
++
++            /* Perform ECDSA verification test */
++            for (i = 0; i < loopargs_len; i++) {
++                st = ECDSA_verify(0, loopargs[i].buf, 20, loopargs[i].buf2,
++                                  loopargs[i].siglen, loopargs[i].ecdsa[testnum]);
++                if (st != 1)
++                    break;
++            }
++            if (st != 1) {
++                BIO_printf(bio_err,
++                           "ECDSA verify failure.  No ECDSA verify will be done.\n");
++                ERR_print_errors(bio_err);
++                ecdsa_doit[testnum] = 0;
++            } else {
++                pkey_print_message("verify", "ecdsa",
++                                   ecdsa_c[testnum][1],
++                                   test_curves_bits[testnum], ECDSA_SECONDS);
++                Time_F(START);
++                count = run_benchmark(async_jobs, ECDSA_verify_loop, loopargs);
++                d = Time_F(STOP);
++                BIO_printf(bio_err,
++                           mr ? "+R6:%ld:%d:%.2f\n"
++                           : "%ld %d bit ECDSA verify in %.2fs\n",
++                           count, test_curves_bits[testnum], d);
++                ecdsa_results[testnum][1] = d / (double)count;
++            }
++
++            if (rsa_count <= 1) {
++                /* if longer than 10s, don't do any more */
++                for (testnum++; testnum < EC_NUM; testnum++)
++                    ecdsa_doit[testnum] = 0;
++            }
++        }
++    }
++
++    if (RAND_status() != 1) {
++        RAND_seed(rnd_seed, sizeof rnd_seed);
++    }
++    for (testnum = 0; testnum < EC_NUM; testnum++) {
++        int ecdh_checks = 1;
++
++        if (!ecdh_doit[testnum])
++            continue;
++        for (i = 0; i < loopargs_len; i++) {
++            loopargs[i].ecdh_a[testnum] = EC_KEY_new_by_curve_name(test_curves[testnum]);
++            loopargs[i].ecdh_b[testnum] = EC_KEY_new_by_curve_name(test_curves[testnum]);
++            if (loopargs[i].ecdh_a[testnum] == NULL ||
++                loopargs[i].ecdh_b[testnum] == NULL) {
++                ecdh_checks = 0;
++                break;
++            }
++        }
++        if (ecdh_checks == 0) {
++            BIO_printf(bio_err, "ECDH failure.\n");
++            ERR_print_errors(bio_err);
++            rsa_count = 1;
++        } else {
++            for (i = 0; i < loopargs_len; i++) {
++                /* generate two ECDH key pairs */
++                if (!EC_KEY_generate_key(loopargs[i].ecdh_a[testnum]) ||
++                        !EC_KEY_generate_key(loopargs[i].ecdh_b[testnum])) {
++                    BIO_printf(bio_err, "ECDH key generation failure.\n");
++                    ERR_print_errors(bio_err);
++                    ecdh_checks = 0;
++                    rsa_count = 1;
++                } else {
++                    int secret_size_a, secret_size_b;
++                    /*
++                     * If field size is not more than 24 octets, then use SHA-1
++                     * hash of result; otherwise, use result (see section 4.8 of
++                     * draft-ietf-tls-ecc-03.txt).
++                     */
++                    int field_size = EC_GROUP_get_degree(
++                            EC_KEY_get0_group(loopargs[i].ecdh_a[testnum]));
++
++                    if (field_size <= 24 * 8) {                 /* 192 bits */
++                        loopargs[i].outlen = KDF1_SHA1_len;
++                        loopargs[i].kdf = KDF1_SHA1;
++                    } else {
++                        loopargs[i].outlen = (field_size + 7) / 8;
++                        loopargs[i].kdf = NULL;
++                    }
++                    secret_size_a =
++                        ECDH_compute_key(loopargs[i].secret_a, loopargs[i].outlen,
++                                EC_KEY_get0_public_key(loopargs[i].ecdh_b[testnum]),
++                                loopargs[i].ecdh_a[testnum], loopargs[i].kdf);
++                    secret_size_b =
++                        ECDH_compute_key(loopargs[i].secret_b, loopargs[i].outlen,
++                                EC_KEY_get0_public_key(loopargs[i].ecdh_a[testnum]),
++                                loopargs[i].ecdh_b[testnum], loopargs[i].kdf);
++                    if (secret_size_a != secret_size_b)
++                        ecdh_checks = 0;
++                    else
++                        ecdh_checks = 1;
++
++                    for (k = 0; k < secret_size_a && ecdh_checks == 1; k++) {
++                        if (loopargs[i].secret_a[k] != loopargs[i].secret_b[k])
++                            ecdh_checks = 0;
++                    }
++
++                    if (ecdh_checks == 0) {
++                        BIO_printf(bio_err, "ECDH computations don't match.\n");
++                        ERR_print_errors(bio_err);
++                        rsa_count = 1;
++                        break;
++                    }
++                }
++            }
++            if (ecdh_checks != 0) {
++                pkey_print_message("", "ecdh",
++                        ecdh_c[testnum][0],
++                        test_curves_bits[testnum], ECDH_SECONDS);
++                Time_F(START);
++                count = run_benchmark(async_jobs, ECDH_compute_key_loop, loopargs);
++                d = Time_F(STOP);
++                BIO_printf(bio_err,
++                        mr ? "+R7:%ld:%d:%.2f\n" :
++                        "%ld %d-bit ECDH ops in %.2fs\n", count,
++                        test_curves_bits[testnum], d);
++                ecdh_results[testnum][0] = d / (double)count;
++                rsa_count = count;
++            }
++        }
++
++        if (rsa_count <= 1) {
++            /* if longer than 10s, don't do any more */
++            for (testnum++; testnum < EC_NUM; testnum++)
++                ecdh_doit[testnum] = 0;
++        }
++    }
++#endif                          /* OPENSSL_NO_EC */
++#ifndef NO_FORK
++ show_res:
++#endif
++    if (!mr) {
++        printf("%s\n", OpenSSL_version(OPENSSL_VERSION));
++        printf("%s\n", OpenSSL_version(OPENSSL_BUILT_ON));
++        printf("options:");
++        printf("%s ", BN_options());
++#ifndef OPENSSL_NO_MD2
++        printf("%s ", MD2_options());
++#endif
++#ifndef OPENSSL_NO_RC4
++        printf("%s ", RC4_options());
++#endif
++#ifndef OPENSSL_NO_DES
++        printf("%s ", DES_options());
++#endif
++        printf("%s ", AES_options());
++#ifndef OPENSSL_NO_IDEA
++        printf("%s ", IDEA_options());
++#endif
++#ifndef OPENSSL_NO_BF
++        printf("%s ", BF_options());
++#endif
++        printf("\n%s\n", OpenSSL_version(OPENSSL_CFLAGS));
++    }
++
++    if (pr_header) {
++        if (mr)
++            printf("+H");
++        else {
++            printf
++                ("The 'numbers' are in 1000s of bytes per second processed.\n");
++            printf("type        ");
++        }
++        for (testnum = 0; testnum < SIZE_NUM; testnum++)
++            printf(mr ? ":%d" : "%7d bytes", lengths[testnum]);
++        printf("\n");
++    }
++
++    for (k = 0; k < ALGOR_NUM; k++) {
++        if (!doit[k])
++            continue;
++        if (mr)
++            printf("+F:%d:%s", k, names[k]);
++        else
++            printf("%-13s", names[k]);
++        for (testnum = 0; testnum < SIZE_NUM; testnum++) {
++            if (results[k][testnum] > 10000 && !mr)
++                printf(" %11.2fk", results[k][testnum] / 1e3);
++            else
++                printf(mr ? ":%.2f" : " %11.2f ", results[k][testnum]);
++        }
++        printf("\n");
++    }
++#ifndef OPENSSL_NO_RSA
++    testnum = 1;
++    for (k = 0; k < RSA_NUM; k++) {
++        if (!rsa_doit[k])
++            continue;
++        if (testnum && !mr) {
++            printf("%18ssign    verify    sign/s verify/s\n", " ");
++            testnum = 0;
++        }
++        if (mr)
++            printf("+F2:%u:%u:%f:%f\n",
++                   k, rsa_bits[k], rsa_results[k][0], rsa_results[k][1]);
++        else
++            printf("rsa %4u bits %8.6fs %8.6fs %8.1f %8.1f\n",
++                   rsa_bits[k], rsa_results[k][0], rsa_results[k][1],
++                   1.0 / rsa_results[k][0], 1.0 / rsa_results[k][1]);
++    }
++#endif
++#ifndef OPENSSL_NO_DSA
++    testnum = 1;
++    for (k = 0; k < DSA_NUM; k++) {
++        if (!dsa_doit[k])
++            continue;
++        if (testnum && !mr) {
++            printf("%18ssign    verify    sign/s verify/s\n", " ");
++            testnum = 0;
++        }
++        if (mr)
++            printf("+F3:%u:%u:%f:%f\n",
++                   k, dsa_bits[k], dsa_results[k][0], dsa_results[k][1]);
++        else
++            printf("dsa %4u bits %8.6fs %8.6fs %8.1f %8.1f\n",
++                   dsa_bits[k], dsa_results[k][0], dsa_results[k][1],
++                   1.0 / dsa_results[k][0], 1.0 / dsa_results[k][1]);
++    }
++#endif
++#ifndef OPENSSL_NO_EC
++    testnum = 1;
++    for (k = 0; k < EC_NUM; k++) {
++        if (!ecdsa_doit[k])
++            continue;
++        if (testnum && !mr) {
++            printf("%30ssign    verify    sign/s verify/s\n", " ");
++            testnum = 0;
++        }
++
++        if (mr)
++            printf("+F4:%u:%u:%f:%f\n",
++                   k, test_curves_bits[k],
++                   ecdsa_results[k][0], ecdsa_results[k][1]);
++        else
++            printf("%4u bit ecdsa (%s) %8.4fs %8.4fs %8.1f %8.1f\n",
++                   test_curves_bits[k],
++                   test_curves_names[k],
++                   ecdsa_results[k][0], ecdsa_results[k][1],
++                   1.0 / ecdsa_results[k][0], 1.0 / ecdsa_results[k][1]);
++    }
++
++    testnum = 1;
++    for (k = 0; k < EC_NUM; k++) {
++        if (!ecdh_doit[k])
++            continue;
++        if (testnum && !mr) {
++            printf("%30sop      op/s\n", " ");
++            testnum = 0;
++        }
++        if (mr)
++            printf("+F5:%u:%u:%f:%f\n",
++                   k, test_curves_bits[k],
++                   ecdh_results[k][0], 1.0 / ecdh_results[k][0]);
++
++        else
++            printf("%4u bit ecdh (%s) %8.4fs %8.1f\n",
++                   test_curves_bits[k],
++                   test_curves_names[k],
++                   ecdh_results[k][0], 1.0 / ecdh_results[k][0]);
++    }
++#endif
++
++    ret = 0;
++
++ end:
++    ERR_print_errors(bio_err);
++    for (i = 0; i < loopargs_len; i++) {
++        OPENSSL_free(loopargs[i].buf_malloc);
++        OPENSSL_free(loopargs[i].buf2_malloc);
++
++#ifndef OPENSSL_NO_RSA
++        for (k = 0; k < RSA_NUM; k++)
++            RSA_free(loopargs[i].rsa_key[k]);
++#endif
++#ifndef OPENSSL_NO_DSA
++        for (k = 0; k < DSA_NUM; k++)
++            DSA_free(loopargs[i].dsa_key[k]);
++#endif
++#ifndef OPENSSL_NO_EC
++        for (k = 0; k < EC_NUM; k++) {
++            EC_KEY_free(loopargs[i].ecdsa[k]);
++            EC_KEY_free(loopargs[i].ecdh_a[k]);
++            EC_KEY_free(loopargs[i].ecdh_b[k]);
++        }
++        OPENSSL_free(loopargs[i].secret_a);
++        OPENSSL_free(loopargs[i].secret_b);
++#endif
++    }
++
++    if (async_jobs > 0) {
++        for (i = 0; i < loopargs_len; i++)
++            ASYNC_WAIT_CTX_free(loopargs[i].wait_ctx);
++    }
++
++    if (async_init) {
++        ASYNC_cleanup_thread();
++    }
++    OPENSSL_free(loopargs);
++    release_engine(e);
++    return (ret);
++}
++
++static void print_message(const char *s, long num, int length)
++{
++#ifdef SIGALRM
++    BIO_printf(bio_err,
++               mr ? "+DT:%s:%d:%d\n"
++               : "Doing %s for %ds on %d size blocks: ", s, SECONDS, length);
++    (void)BIO_flush(bio_err);
++    alarm(SECONDS);
++#else
++    BIO_printf(bio_err,
++               mr ? "+DN:%s:%ld:%d\n"
++               : "Doing %s %ld times on %d size blocks: ", s, num, length);
++    (void)BIO_flush(bio_err);
++#endif
++}
++
++static void pkey_print_message(const char *str, const char *str2, long num,
++                               int bits, int tm)
++{
++#ifdef SIGALRM
++    BIO_printf(bio_err,
++               mr ? "+DTP:%d:%s:%s:%d\n"
++               : "Doing %d bit %s %s's for %ds: ", bits, str, str2, tm);
++    (void)BIO_flush(bio_err);
++    alarm(tm);
++#else
++    BIO_printf(bio_err,
++               mr ? "+DNP:%ld:%d:%s:%s\n"
++               : "Doing %ld %d bit %s %s's: ", num, bits, str, str2);
++    (void)BIO_flush(bio_err);
++#endif
++}
++
++static void print_result(int alg, int run_no, int count, double time_used)
++{
++    if (count == -1) {
++        BIO_puts(bio_err, "EVP error!\n");
++        exit(1);
++    }
++    BIO_printf(bio_err,
++               mr ? "+R:%d:%s:%f\n"
++               : "%d %s's in %.2fs\n", count, names[alg], time_used);
++    results[alg][run_no] = ((double)count) / time_used * lengths[run_no];
++}
++
++#ifndef NO_FORK
++static char *sstrsep(char **string, const char *delim)
++{
++    char isdelim[256];
++    char *token = *string;
++
++    if (**string == 0)
++        return NULL;
++
++    memset(isdelim, 0, sizeof isdelim);
++    isdelim[0] = 1;
++
++    while (*delim) {
++        isdelim[(unsigned char)(*delim)] = 1;
++        delim++;
++    }
++
++    while (!isdelim[(unsigned char)(**string)]) {
++        (*string)++;
++    }
++
++    if (**string) {
++        **string = 0;
++        (*string)++;
++    }
++
++    return token;
++}
++
++static int do_multi(int multi)
++{
++    int n;
++    int fd[2];
++    int *fds;
++    static char sep[] = ":";
++
++    fds = malloc(sizeof(*fds) * multi);
++    for (n = 0; n < multi; ++n) {
++        if (pipe(fd) == -1) {
++            BIO_printf(bio_err, "pipe failure\n");
++            exit(1);
++        }
++        fflush(stdout);
++        (void)BIO_flush(bio_err);
++        if (fork()) {
++            close(fd[1]);
++            fds[n] = fd[0];
++        } else {
++            close(fd[0]);
++            close(1);
++            if (dup(fd[1]) == -1) {
++                BIO_printf(bio_err, "dup failed\n");
++                exit(1);
++            }
++            close(fd[1]);
++            mr = 1;
++            usertime = 0;
++            free(fds);
++            return 0;
++        }
++        printf("Forked child %d\n", n);
++    }
++
++    /* for now, assume the pipe is long enough to take all the output */
++    for (n = 0; n < multi; ++n) {
++        FILE *f;
++        char buf[1024];
++        char *p;
++
++        f = fdopen(fds[n], "r");
++        while (fgets(buf, sizeof buf, f)) {
++            p = strchr(buf, '\n');
++            if (p)
++                *p = '\0';
++            if (buf[0] != '+') {
++                BIO_printf(bio_err, "Don't understand line '%s' from child %d\n",
++                        buf, n);
++                continue;
++            }
++            printf("Got: %s from %d\n", buf, n);
++            if (strncmp(buf, "+F:", 3) == 0) {
++                int alg;
++                int j;
++
++                p = buf + 3;
++                alg = atoi(sstrsep(&p, sep));
++                sstrsep(&p, sep);
++                for (j = 0; j < SIZE_NUM; ++j)
++                    results[alg][j] += atof(sstrsep(&p, sep));
++            } else if (strncmp(buf, "+F2:", 4) == 0) {
++                int k;
++                double d;
++
++                p = buf + 4;
++                k = atoi(sstrsep(&p, sep));
++                sstrsep(&p, sep);
++
++                d = atof(sstrsep(&p, sep));
++                if (n)
++                    rsa_results[k][0] = 1 / (1 / rsa_results[k][0] + 1 / d);
++                else
++                    rsa_results[k][0] = d;
++
++                d = atof(sstrsep(&p, sep));
++                if (n)
++                    rsa_results[k][1] = 1 / (1 / rsa_results[k][1] + 1 / d);
++                else
++                    rsa_results[k][1] = d;
++            }
++# ifndef OPENSSL_NO_DSA
++            else if (strncmp(buf, "+F3:", 4) == 0) {
++                int k;
++                double d;
++
++                p = buf + 4;
++                k = atoi(sstrsep(&p, sep));
++                sstrsep(&p, sep);
++
++                d = atof(sstrsep(&p, sep));
++                if (n)
++                    dsa_results[k][0] = 1 / (1 / dsa_results[k][0] + 1 / d);
++                else
++                    dsa_results[k][0] = d;
++
++                d = atof(sstrsep(&p, sep));
++                if (n)
++                    dsa_results[k][1] = 1 / (1 / dsa_results[k][1] + 1 / d);
++                else
++                    dsa_results[k][1] = d;
++            }
++# endif
++# ifndef OPENSSL_NO_EC
++            else if (strncmp(buf, "+F4:", 4) == 0) {
++                int k;
++                double d;
++
++                p = buf + 4;
++                k = atoi(sstrsep(&p, sep));
++                sstrsep(&p, sep);
++
++                d = atof(sstrsep(&p, sep));
++                if (n)
++                    ecdsa_results[k][0] =
++                        1 / (1 / ecdsa_results[k][0] + 1 / d);
++                else
++                    ecdsa_results[k][0] = d;
++
++                d = atof(sstrsep(&p, sep));
++                if (n)
++                    ecdsa_results[k][1] =
++                        1 / (1 / ecdsa_results[k][1] + 1 / d);
++                else
++                    ecdsa_results[k][1] = d;
++            } else if (strncmp(buf, "+F5:", 4) == 0) {
++                int k;
++                double d;
++
++                p = buf + 4;
++                k = atoi(sstrsep(&p, sep));
++                sstrsep(&p, sep);
++
++                d = atof(sstrsep(&p, sep));
++                if (n)
++                    ecdh_results[k][0] = 1 / (1 / ecdh_results[k][0] + 1 / d);
++                else
++                    ecdh_results[k][0] = d;
++
++            }
++# endif
++
++            else if (strncmp(buf, "+H:", 3) == 0) {
++                ;
++            } else
++                BIO_printf(bio_err, "Unknown type '%s' from child %d\n", buf, n);
++        }
++
++        fclose(f);
++    }
++    free(fds);
++    return 1;
++}
++#endif
++
++static void multiblock_speed(const EVP_CIPHER *evp_cipher)
++{
++    static int mblengths[] =
++        { 8 * 1024, 2 * 8 * 1024, 4 * 8 * 1024, 8 * 8 * 1024, 8 * 16 * 1024 };
++    int j, count, num = OSSL_NELEM(mblengths);
++    const char *alg_name;
++    unsigned char *inp, *out, no_key[32], no_iv[16];
++    EVP_CIPHER_CTX *ctx;
++    double d = 0.0;
++
++    inp = app_malloc(mblengths[num - 1], "multiblock input buffer");
++    out = app_malloc(mblengths[num - 1] + 1024, "multiblock output buffer");
++    ctx = EVP_CIPHER_CTX_new();
++    EVP_EncryptInit_ex(ctx, evp_cipher, NULL, no_key, no_iv);
++    EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_SET_MAC_KEY, sizeof(no_key),
++                        no_key);
++    alg_name = OBJ_nid2ln(EVP_CIPHER_nid(evp_cipher));
++
++    for (j = 0; j < num; j++) {
++        print_message(alg_name, 0, mblengths[j]);
++        Time_F(START);
++        for (count = 0, run = 1; run && count < 0x7fffffff; count++) {
++            unsigned char aad[EVP_AEAD_TLS1_AAD_LEN];
++            EVP_CTRL_TLS1_1_MULTIBLOCK_PARAM mb_param;
++            size_t len = mblengths[j];
++            int packlen;
++
++            memset(aad, 0, 8);  /* avoid uninitialized values */
++            aad[8] = 23;        /* SSL3_RT_APPLICATION_DATA */
++            aad[9] = 3;         /* version */
++            aad[10] = 2;
++            aad[11] = 0;        /* length */
++            aad[12] = 0;
++            mb_param.out = NULL;
++            mb_param.inp = aad;
++            mb_param.len = len;
++            mb_param.interleave = 8;
++
++            packlen = EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_TLS1_1_MULTIBLOCK_AAD,
++                                          sizeof(mb_param), &mb_param);
++
++            if (packlen > 0) {
++                mb_param.out = out;
++                mb_param.inp = inp;
++                mb_param.len = len;
++                EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_TLS1_1_MULTIBLOCK_ENCRYPT,
++                                    sizeof(mb_param), &mb_param);
++            } else {
++                int pad;
++
++                RAND_bytes(out, 16);
++                len += 16;
++                aad[11] = len >> 8;
++                aad[12] = len;
++                pad = EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_TLS1_AAD,
++                                          EVP_AEAD_TLS1_AAD_LEN, aad);
++                EVP_Cipher(ctx, out, inp, len + pad);
++            }
++        }
++        d = Time_F(STOP);
++        BIO_printf(bio_err, mr ? "+R:%d:%s:%f\n"
++                   : "%d %s's in %.2fs\n", count, "evp", d);
++        results[D_EVP][j] = ((double)count) / d * mblengths[j];
++    }
++
++    if (mr) {
++        fprintf(stdout, "+H");
++        for (j = 0; j < num; j++)
++            fprintf(stdout, ":%d", mblengths[j]);
++        fprintf(stdout, "\n");
++        fprintf(stdout, "+F:%d:%s", D_EVP, alg_name);
++        for (j = 0; j < num; j++)
++            fprintf(stdout, ":%.2f", results[D_EVP][j]);
++        fprintf(stdout, "\n");
++    } else {
++        fprintf(stdout,
++                "The 'numbers' are in 1000s of bytes per second processed.\n");
++        fprintf(stdout, "type                    ");
++        for (j = 0; j < num; j++)
++            fprintf(stdout, "%7d bytes", mblengths[j]);
++        fprintf(stdout, "\n");
++        fprintf(stdout, "%-24s", alg_name);
++
++        for (j = 0; j < num; j++) {
++            if (results[D_EVP][j] > 10000)
++                fprintf(stdout, " %11.2fk", results[D_EVP][j] / 1e3);
++            else
++                fprintf(stdout, " %11.2f ", results[D_EVP][j]);
++        }
++        fprintf(stdout, "\n");
++    }
++
++    OPENSSL_free(inp);
++    OPENSSL_free(out);
++    EVP_CIPHER_CTX_free(ctx);
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/apps/spkac.c b/CryptoPkg/Library/OpensslLib/openssl/apps/spkac.c
+new file mode 100644
+index 0000000..90a5bea
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/apps/spkac.c
+@@ -0,0 +1,193 @@
++/*
++ * Copyright 1999-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include 
++#include 
++#include 
++#include "apps.h"
++#include 
++#include 
++#include 
++#include 
++#include 
++#include 
++#include 
++
++typedef enum OPTION_choice {
++    OPT_ERR = -1, OPT_EOF = 0, OPT_HELP,
++    OPT_NOOUT, OPT_PUBKEY, OPT_VERIFY, OPT_IN, OPT_OUT,
++    OPT_ENGINE, OPT_KEY, OPT_CHALLENGE, OPT_PASSIN, OPT_SPKAC,
++    OPT_SPKSECT
++} OPTION_CHOICE;
++
++OPTIONS spkac_options[] = {
++    {"help", OPT_HELP, '-', "Display this summary"},
++    {"in", OPT_IN, '<', "Input file"},
++    {"out", OPT_OUT, '>', "Output file"},
++    {"key", OPT_KEY, '<', "Create SPKAC using private key"},
++    {"passin", OPT_PASSIN, 's', "Input file pass phrase source"},
++    {"challenge", OPT_CHALLENGE, 's', "Challenge string"},
++    {"spkac", OPT_SPKAC, 's', "Alternative SPKAC name"},
++    {"noout", OPT_NOOUT, '-', "Don't print SPKAC"},
++    {"pubkey", OPT_PUBKEY, '-', "Output public key"},
++    {"verify", OPT_VERIFY, '-', "Verify SPKAC signature"},
++    {"spksect", OPT_SPKSECT, 's',
++     "Specify the name of an SPKAC-dedicated section of configuration"},
++#ifndef OPENSSL_NO_ENGINE
++    {"engine", OPT_ENGINE, 's', "Use engine, possibly a hardware device"},
++#endif
++    {NULL}
++};
++
++int spkac_main(int argc, char **argv)
++{
++    BIO *out = NULL;
++    CONF *conf = NULL;
++    ENGINE *e = NULL;
++    EVP_PKEY *pkey = NULL;
++    NETSCAPE_SPKI *spki = NULL;
++    char *challenge = NULL, *keyfile = NULL;
++    char *infile = NULL, *outfile = NULL, *passinarg = NULL, *passin = NULL;
++    char *spkstr = NULL, *prog;
++    const char *spkac = "SPKAC", *spksect = "default";
++    int i, ret = 1, verify = 0, noout = 0, pubkey = 0;
++    OPTION_CHOICE o;
++
++    prog = opt_init(argc, argv, spkac_options);
++    while ((o = opt_next()) != OPT_EOF) {
++        switch (o) {
++        case OPT_EOF:
++        case OPT_ERR:
++ opthelp:
++            BIO_printf(bio_err, "%s: Use -help for summary.\n", prog);
++            goto end;
++        case OPT_HELP:
++            opt_help(spkac_options);
++            ret = 0;
++            goto end;
++        case OPT_IN:
++            infile = opt_arg();
++            break;
++        case OPT_OUT:
++            outfile = opt_arg();
++            break;
++        case OPT_NOOUT:
++            noout = 1;
++            break;
++        case OPT_PUBKEY:
++            pubkey = 1;
++            break;
++        case OPT_VERIFY:
++            verify = 1;
++            break;
++        case OPT_PASSIN:
++            passinarg = opt_arg();
++            break;
++        case OPT_KEY:
++            keyfile = opt_arg();
++            break;
++        case OPT_CHALLENGE:
++            challenge = opt_arg();
++            break;
++        case OPT_SPKAC:
++            spkac = opt_arg();
++            break;
++        case OPT_SPKSECT:
++            spksect = opt_arg();
++            break;
++        case OPT_ENGINE:
++            e = setup_engine(opt_arg(), 0);
++            break;
++        }
++    }
++    argc = opt_num_rest();
++    if (argc != 0)
++        goto opthelp;
++
++    if (!app_passwd(passinarg, NULL, &passin, NULL)) {
++        BIO_printf(bio_err, "Error getting password\n");
++        goto end;
++    }
++
++    if (keyfile) {
++        pkey = load_key(strcmp(keyfile, "-") ? keyfile : NULL,
++                        FORMAT_PEM, 1, passin, e, "private key");
++        if (!pkey) {
++            goto end;
++        }
++        spki = NETSCAPE_SPKI_new();
++        if (challenge)
++            ASN1_STRING_set(spki->spkac->challenge,
++                            challenge, (int)strlen(challenge));
++        NETSCAPE_SPKI_set_pubkey(spki, pkey);
++        NETSCAPE_SPKI_sign(spki, pkey, EVP_md5());
++        spkstr = NETSCAPE_SPKI_b64_encode(spki);
++
++        out = bio_open_default(outfile, 'w', FORMAT_TEXT);
++        if (out == NULL) {
++            OPENSSL_free(spkstr);
++            goto end;
++        }
++        BIO_printf(out, "SPKAC=%s\n", spkstr);
++        OPENSSL_free(spkstr);
++        ret = 0;
++        goto end;
++    }
++
++    if ((conf = app_load_config(infile)) == NULL)
++        goto end;
++
++    spkstr = NCONF_get_string(conf, spksect, spkac);
++
++    if (spkstr == NULL) {
++        BIO_printf(bio_err, "Can't find SPKAC called \"%s\"\n", spkac);
++        ERR_print_errors(bio_err);
++        goto end;
++    }
++
++    spki = NETSCAPE_SPKI_b64_decode(spkstr, -1);
++
++    if (!spki) {
++        BIO_printf(bio_err, "Error loading SPKAC\n");
++        ERR_print_errors(bio_err);
++        goto end;
++    }
++
++    out = bio_open_default(outfile, 'w', FORMAT_TEXT);
++    if (out == NULL)
++        goto end;
++
++    if (!noout)
++        NETSCAPE_SPKI_print(out, spki);
++    pkey = NETSCAPE_SPKI_get_pubkey(spki);
++    if (verify) {
++        i = NETSCAPE_SPKI_verify(spki, pkey);
++        if (i > 0)
++            BIO_printf(bio_err, "Signature OK\n");
++        else {
++            BIO_printf(bio_err, "Signature Failure\n");
++            ERR_print_errors(bio_err);
++            goto end;
++        }
++    }
++    if (pubkey)
++        PEM_write_bio_PUBKEY(out, pkey);
++
++    ret = 0;
++
++ end:
++    NCONF_free(conf);
++    NETSCAPE_SPKI_free(spki);
++    BIO_free_all(out);
++    EVP_PKEY_free(pkey);
++    release_engine(e);
++    OPENSSL_free(passin);
++    return (ret);
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/apps/srp.c b/CryptoPkg/Library/OpensslLib/openssl/apps/srp.c
+new file mode 100644
+index 0000000..add0100
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/apps/srp.c
+@@ -0,0 +1,609 @@
++/*
++ * Copyright 2004-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#ifdef OPENSSL_NO_SRP
++NON_EMPTY_TRANSLATION_UNIT
++#else
++
++# include 
++# include 
++# include 
++# include 
++# include 
++# include 
++# include 
++# include 
++# include 
++# include "apps.h"
++
++# define BASE_SECTION    "srp"
++# define CONFIG_FILE "openssl.cnf"
++
++# define ENV_RANDFILE            "RANDFILE"
++
++# define ENV_DATABASE            "srpvfile"
++# define ENV_DEFAULT_SRP         "default_srp"
++
++static int get_index(CA_DB *db, char *id, char type)
++{
++    char **pp;
++    int i;
++    if (id == NULL)
++        return -1;
++    if (type == DB_SRP_INDEX)
++        for (i = 0; i < sk_OPENSSL_PSTRING_num(db->db->data); i++) {
++            pp = sk_OPENSSL_PSTRING_value(db->db->data, i);
++            if (pp[DB_srptype][0] == DB_SRP_INDEX
++                && strcmp(id, pp[DB_srpid]) == 0)
++                return i;
++    } else
++        for (i = 0; i < sk_OPENSSL_PSTRING_num(db->db->data); i++) {
++            pp = sk_OPENSSL_PSTRING_value(db->db->data, i);
++
++            if (pp[DB_srptype][0] != DB_SRP_INDEX
++                && strcmp(id, pp[DB_srpid]) == 0)
++                return i;
++        }
++
++    return -1;
++}
++
++static void print_entry(CA_DB *db, int indx, int verbose, char *s)
++{
++    if (indx >= 0 && verbose) {
++        int j;
++        char **pp = sk_OPENSSL_PSTRING_value(db->db->data, indx);
++        BIO_printf(bio_err, "%s \"%s\"\n", s, pp[DB_srpid]);
++        for (j = 0; j < DB_NUMBER; j++) {
++            BIO_printf(bio_err, "  %d = \"%s\"\n", j, pp[j]);
++        }
++    }
++}
++
++static void print_index(CA_DB *db, int indexindex, int verbose)
++{
++    print_entry(db, indexindex, verbose, "g N entry");
++}
++
++static void print_user(CA_DB *db, int userindex, int verbose)
++{
++    if (verbose > 0) {
++        char **pp = sk_OPENSSL_PSTRING_value(db->db->data, userindex);
++
++        if (pp[DB_srptype][0] != 'I') {
++            print_entry(db, userindex, verbose, "User entry");
++            print_entry(db, get_index(db, pp[DB_srpgN], 'I'), verbose,
++                        "g N entry");
++        }
++
++    }
++}
++
++static int update_index(CA_DB *db, char **row)
++{
++    char **irow;
++    int i;
++
++    irow = app_malloc(sizeof(*irow) * (DB_NUMBER + 1), "row pointers");
++    for (i = 0; i < DB_NUMBER; i++) {
++        irow[i] = row[i];
++        row[i] = NULL;
++    }
++    irow[DB_NUMBER] = NULL;
++
++    if (!TXT_DB_insert(db->db, irow)) {
++        BIO_printf(bio_err, "failed to update srpvfile\n");
++        BIO_printf(bio_err, "TXT_DB error number %ld\n", db->db->error);
++        OPENSSL_free(irow);
++        return 0;
++    }
++    return 1;
++}
++
++static char *lookup_conf(const CONF *conf, const char *section, const char *tag)
++{
++    char *entry = NCONF_get_string(conf, section, tag);
++    if (entry == NULL)
++        BIO_printf(bio_err, "variable lookup failed for %s::%s\n", section, tag);
++    return entry;
++}
++
++static char *srp_verify_user(const char *user, const char *srp_verifier,
++                             char *srp_usersalt, const char *g, const char *N,
++                             const char *passin, int verbose)
++{
++    char password[1024];
++    PW_CB_DATA cb_tmp;
++    char *verifier = NULL;
++    char *gNid = NULL;
++
++    cb_tmp.prompt_info = user;
++    cb_tmp.password = passin;
++
++    if (password_callback(password, sizeof(password), 0, &cb_tmp) > 0) {
++        if (verbose)
++            BIO_printf(bio_err,
++                       "Validating\n   user=\"%s\"\n srp_verifier=\"%s\"\n srp_usersalt=\"%s\"\n g=\"%s\"\n N=\"%s\"\n",
++                       user, srp_verifier, srp_usersalt, g, N);
++        BIO_printf(bio_err, "Pass %s\n", password);
++
++        OPENSSL_assert(srp_usersalt != NULL);
++        if (!
++            (gNid =
++             SRP_create_verifier(user, password, &srp_usersalt, &verifier, N,
++                                 g))) {
++            BIO_printf(bio_err, "Internal error validating SRP verifier\n");
++        } else {
++            if (strcmp(verifier, srp_verifier))
++                gNid = NULL;
++            OPENSSL_free(verifier);
++        }
++    }
++    return gNid;
++}
++
++static char *srp_create_user(char *user, char **srp_verifier,
++                             char **srp_usersalt, char *g, char *N,
++                             char *passout, int verbose)
++{
++    char password[1024];
++    PW_CB_DATA cb_tmp;
++    char *gNid = NULL;
++    char *salt = NULL;
++    cb_tmp.prompt_info = user;
++    cb_tmp.password = passout;
++
++    if (password_callback(password, sizeof(password), 1, &cb_tmp) > 0) {
++        if (verbose)
++            BIO_printf(bio_err, "Creating\n user=\"%s\"\n g=\"%s\"\n N=\"%s\"\n",
++                       user, g, N);
++        if (!
++            (gNid =
++             SRP_create_verifier(user, password, &salt, srp_verifier, N,
++                                 g))) {
++            BIO_printf(bio_err, "Internal error creating SRP verifier\n");
++        } else
++            *srp_usersalt = salt;
++        if (verbose > 1)
++            BIO_printf(bio_err, "gNid=%s salt =\"%s\"\n verifier =\"%s\"\n", gNid,
++                       salt, *srp_verifier);
++
++    }
++    return gNid;
++}
++
++typedef enum OPTION_choice {
++    OPT_ERR = -1, OPT_EOF = 0, OPT_HELP,
++    OPT_VERBOSE, OPT_CONFIG, OPT_NAME, OPT_SRPVFILE, OPT_ADD,
++    OPT_DELETE, OPT_MODIFY, OPT_LIST, OPT_GN, OPT_USERINFO,
++    OPT_PASSIN, OPT_PASSOUT, OPT_ENGINE
++} OPTION_CHOICE;
++
++OPTIONS srp_options[] = {
++    {"help", OPT_HELP, '-', "Display this summary"},
++    {"verbose", OPT_VERBOSE, '-', "Talk a lot while doing things"},
++    {"config", OPT_CONFIG, '<', "A config file"},
++    {"name", OPT_NAME, 's', "The particular srp definition to use"},
++    {"srpvfile", OPT_SRPVFILE, '<', "The srp verifier file name"},
++    {"add", OPT_ADD, '-', "Add a user and srp verifier"},
++    {"modify", OPT_MODIFY, '-',
++     "Modify the srp verifier of an existing user"},
++    {"delete", OPT_DELETE, '-', "Delete user from verifier file"},
++    {"list", OPT_LIST, '-', "List users"},
++    {"gn", OPT_GN, 's', "Set g and N values to be used for new verifier"},
++    {"userinfo", OPT_USERINFO, 's', "Additional info to be set for user"},
++    {"passin", OPT_PASSIN, 's', "Input file pass phrase source"},
++    {"passout", OPT_PASSOUT, 's', "Output file pass phrase source"},
++# ifndef OPENSSL_NO_ENGINE
++    {"engine", OPT_ENGINE, 's', "Use engine, possibly a hardware device"},
++# endif
++    {NULL}
++};
++
++int srp_main(int argc, char **argv)
++{
++    ENGINE *e = NULL;
++    CA_DB *db = NULL;
++    CONF *conf = NULL;
++    int gNindex = -1, maxgN = -1, ret = 1, errors = 0, verbose = 0, i;
++    int doupdatedb = 0, mode = OPT_ERR;
++    char *user = NULL, *passinarg = NULL, *passoutarg = NULL;
++    char *passin = NULL, *passout = NULL, *gN = NULL, *userinfo = NULL;
++    char *randfile = NULL, *section = NULL;
++    char **gNrow = NULL, *configfile = NULL;
++    char *srpvfile = NULL, **pp, *prog;
++    OPTION_CHOICE o;
++
++    prog = opt_init(argc, argv, srp_options);
++    while ((o = opt_next()) != OPT_EOF) {
++        switch (o) {
++        case OPT_EOF:
++        case OPT_ERR:
++ opthelp:
++            BIO_printf(bio_err, "%s: Use -help for summary.\n", prog);
++            goto end;
++        case OPT_HELP:
++            opt_help(srp_options);
++            ret = 0;
++            goto end;
++        case OPT_VERBOSE:
++            verbose++;
++            break;
++        case OPT_CONFIG:
++            configfile = opt_arg();
++            break;
++        case OPT_NAME:
++            section = opt_arg();
++            break;
++        case OPT_SRPVFILE:
++            srpvfile = opt_arg();
++            break;
++        case OPT_ADD:
++        case OPT_DELETE:
++        case OPT_MODIFY:
++        case OPT_LIST:
++            if (mode != OPT_ERR) {
++                BIO_printf(bio_err,
++                           "%s: Only one of -add/delete-modify/-list\n",
++                           prog);
++                goto opthelp;
++            }
++            mode = o;
++            break;
++        case OPT_GN:
++            gN = opt_arg();
++            break;
++        case OPT_USERINFO:
++            userinfo = opt_arg();
++            break;
++        case OPT_PASSIN:
++            passinarg = opt_arg();
++            break;
++        case OPT_PASSOUT:
++            passoutarg = opt_arg();
++            break;
++        case OPT_ENGINE:
++            e = setup_engine(opt_arg(), 0);
++            break;
++        }
++    }
++    argc = opt_num_rest();
++    argv = opt_rest();
++
++    if (srpvfile && configfile) {
++        BIO_printf(bio_err,
++                   "-srpvfile and -configfile cannot be specified together.\n");
++        goto end;
++    }
++    if (mode == OPT_ERR) {
++        BIO_printf(bio_err,
++                   "Exactly one of the options -add, -delete, -modify -list must be specified.\n");
++        goto opthelp;
++    }
++    if ((mode == OPT_DELETE || mode == OPT_MODIFY || mode == OPT_ADD)
++        && argc < 1) {
++        BIO_printf(bio_err,
++                   "Need at least one user for options -add, -delete, -modify. \n");
++        goto opthelp;
++    }
++    if ((passin || passout) && argc != 1) {
++        BIO_printf(bio_err,
++                   "-passin, -passout arguments only valid with one user.\n");
++        goto opthelp;
++    }
++
++    if (!app_passwd(passinarg, passoutarg, &passin, &passout)) {
++        BIO_printf(bio_err, "Error getting passwords\n");
++        goto end;
++    }
++
++    if (!srpvfile) {
++        if (!configfile)
++            configfile = default_config_file;
++
++        if (verbose)
++            BIO_printf(bio_err, "Using configuration from %s\n",
++                       configfile);
++        conf = app_load_config(configfile);
++        if (conf == NULL)
++            goto end;
++        if (configfile != default_config_file && !app_load_modules(conf))
++            goto end;
++
++        /* Lets get the config section we are using */
++        if (section == NULL) {
++            if (verbose)
++                BIO_printf(bio_err,
++                           "trying to read " ENV_DEFAULT_SRP
++                           " in " BASE_SECTION "\n");
++
++            section = lookup_conf(conf, BASE_SECTION, ENV_DEFAULT_SRP);
++            if (section == NULL)
++                goto end;
++        }
++
++        if (randfile == NULL)
++            randfile = NCONF_get_string(conf, BASE_SECTION, "RANDFILE");
++
++        if (verbose)
++            BIO_printf(bio_err,
++                       "trying to read " ENV_DATABASE " in section \"%s\"\n",
++                       section);
++
++        srpvfile = lookup_conf(conf, section, ENV_DATABASE);
++        if (srpvfile == NULL)
++            goto end;
++    }
++    if (randfile == NULL)
++        ERR_clear_error();
++    else
++        app_RAND_load_file(randfile, 0);
++
++    if (verbose)
++        BIO_printf(bio_err, "Trying to read SRP verifier file \"%s\"\n",
++                   srpvfile);
++
++    db = load_index(srpvfile, NULL);
++    if (db == NULL)
++        goto end;
++
++    /* Lets check some fields */
++    for (i = 0; i < sk_OPENSSL_PSTRING_num(db->db->data); i++) {
++        pp = sk_OPENSSL_PSTRING_value(db->db->data, i);
++
++        if (pp[DB_srptype][0] == DB_SRP_INDEX) {
++            maxgN = i;
++            if ((gNindex < 0) && (gN != NULL) && strcmp(gN, pp[DB_srpid]) == 0)
++                gNindex = i;
++
++            print_index(db, i, verbose > 1);
++        }
++    }
++
++    if (verbose)
++        BIO_printf(bio_err, "Database initialised\n");
++
++    if (gNindex >= 0) {
++        gNrow = sk_OPENSSL_PSTRING_value(db->db->data, gNindex);
++        print_entry(db, gNindex, verbose > 1, "Default g and N");
++    } else if (maxgN > 0 && !SRP_get_default_gN(gN)) {
++        BIO_printf(bio_err, "No g and N value for index \"%s\"\n", gN);
++        goto end;
++    } else {
++        if (verbose)
++            BIO_printf(bio_err, "Database has no g N information.\n");
++        gNrow = NULL;
++    }
++
++    if (verbose > 1)
++        BIO_printf(bio_err, "Starting user processing\n");
++
++    if (argc > 0)
++        user = *(argv++);
++
++    while (mode == OPT_LIST || user) {
++        int userindex = -1;
++
++        if (user != NULL && verbose > 1)
++            BIO_printf(bio_err, "Processing user \"%s\"\n", user);
++        if ((userindex = get_index(db, user, 'U')) >= 0) {
++            print_user(db, userindex, (verbose > 0) || mode == OPT_LIST);
++        }
++
++        if (mode == OPT_LIST) {
++            if (user == NULL) {
++                BIO_printf(bio_err, "List all users\n");
++
++                for (i = 0; i < sk_OPENSSL_PSTRING_num(db->db->data); i++) {
++                    print_user(db, i, 1);
++                }
++            } else if (userindex < 0) {
++                BIO_printf(bio_err,
++                           "user \"%s\" does not exist, ignored. t\n", user);
++                errors++;
++            }
++        } else if (mode == OPT_ADD) {
++            if (userindex >= 0) {
++                /* reactivation of a new user */
++                char **row =
++                    sk_OPENSSL_PSTRING_value(db->db->data, userindex);
++                BIO_printf(bio_err, "user \"%s\" reactivated.\n", user);
++                row[DB_srptype][0] = 'V';
++
++                doupdatedb = 1;
++            } else {
++                char *row[DB_NUMBER];
++                char *gNid;
++                row[DB_srpverifier] = NULL;
++                row[DB_srpsalt] = NULL;
++                row[DB_srpinfo] = NULL;
++                if (!
++                    (gNid =
++                     srp_create_user(user, &(row[DB_srpverifier]),
++                                     &(row[DB_srpsalt]),
++                                     gNrow ? gNrow[DB_srpsalt] : gN,
++                                     gNrow ? gNrow[DB_srpverifier] : NULL,
++                                     passout, verbose))) {
++                    BIO_printf(bio_err,
++                               "Cannot create srp verifier for user \"%s\", operation abandoned .\n",
++                               user);
++                    errors++;
++                    goto end;
++                }
++                row[DB_srpid] = OPENSSL_strdup(user);
++                row[DB_srptype] = OPENSSL_strdup("v");
++                row[DB_srpgN] = OPENSSL_strdup(gNid);
++
++                if ((row[DB_srpid] == NULL)
++                    || (row[DB_srpgN] == NULL)
++                    || (row[DB_srptype] == NULL)
++                    || (row[DB_srpverifier] == NULL)
++                    || (row[DB_srpsalt] == NULL)
++                    || (userinfo
++                        && ((row[DB_srpinfo] = OPENSSL_strdup(userinfo)) == NULL))
++                    || !update_index(db, row)) {
++                    OPENSSL_free(row[DB_srpid]);
++                    OPENSSL_free(row[DB_srpgN]);
++                    OPENSSL_free(row[DB_srpinfo]);
++                    OPENSSL_free(row[DB_srptype]);
++                    OPENSSL_free(row[DB_srpverifier]);
++                    OPENSSL_free(row[DB_srpsalt]);
++                    goto end;
++                }
++                doupdatedb = 1;
++            }
++        } else if (mode == OPT_MODIFY) {
++            if (userindex < 0) {
++                BIO_printf(bio_err,
++                           "user \"%s\" does not exist, operation ignored.\n",
++                           user);
++                errors++;
++            } else {
++
++                char **row =
++                    sk_OPENSSL_PSTRING_value(db->db->data, userindex);
++                char type = row[DB_srptype][0];
++                if (type == 'v') {
++                    BIO_printf(bio_err,
++                               "user \"%s\" already updated, operation ignored.\n",
++                               user);
++                    errors++;
++                } else {
++                    char *gNid;
++
++                    if (row[DB_srptype][0] == 'V') {
++                        int user_gN;
++                        char **irow = NULL;
++                        if (verbose)
++                            BIO_printf(bio_err,
++                                       "Verifying password for user \"%s\"\n",
++                                       user);
++                        if ((user_gN =
++                             get_index(db, row[DB_srpgN], DB_SRP_INDEX)) >= 0)
++                            irow =
++                                sk_OPENSSL_PSTRING_value(db->db->data,
++                                                         userindex);
++
++                        if (!srp_verify_user
++                            (user, row[DB_srpverifier], row[DB_srpsalt],
++                             irow ? irow[DB_srpsalt] : row[DB_srpgN],
++                             irow ? irow[DB_srpverifier] : NULL, passin,
++                             verbose)) {
++                            BIO_printf(bio_err,
++                                       "Invalid password for user \"%s\", operation abandoned.\n",
++                                       user);
++                            errors++;
++                            goto end;
++                        }
++                    }
++                    if (verbose)
++                        BIO_printf(bio_err, "Password for user \"%s\" ok.\n",
++                                   user);
++
++                    if (!
++                        (gNid =
++                         srp_create_user(user, &(row[DB_srpverifier]),
++                                         &(row[DB_srpsalt]),
++                                         gNrow ? gNrow[DB_srpsalt] : NULL,
++                                         gNrow ? gNrow[DB_srpverifier] : NULL,
++                                         passout, verbose))) {
++                        BIO_printf(bio_err,
++                                   "Cannot create srp verifier for user \"%s\", operation abandoned.\n",
++                                   user);
++                        errors++;
++                        goto end;
++                    }
++
++                    row[DB_srptype][0] = 'v';
++                    row[DB_srpgN] = OPENSSL_strdup(gNid);
++
++                    if (row[DB_srpid] == NULL
++                        || row[DB_srpgN] == NULL
++                        || row[DB_srptype] == NULL
++                        || row[DB_srpverifier] == NULL
++                        || row[DB_srpsalt] == NULL
++                        || (userinfo
++                            && ((row[DB_srpinfo] = OPENSSL_strdup(userinfo))
++                                == NULL)))
++                        goto end;
++
++                    doupdatedb = 1;
++                }
++            }
++        } else if (mode == OPT_DELETE) {
++            if (userindex < 0) {
++                BIO_printf(bio_err,
++                           "user \"%s\" does not exist, operation ignored. t\n",
++                           user);
++                errors++;
++            } else {
++                char **xpp = sk_OPENSSL_PSTRING_value(db->db->data, userindex);
++
++                BIO_printf(bio_err, "user \"%s\" revoked. t\n", user);
++                xpp[DB_srptype][0] = 'R';
++                doupdatedb = 1;
++            }
++        }
++        if (--argc > 0)
++            user = *(argv++);
++        else {
++            user = NULL;
++        }
++    }
++
++    if (verbose)
++        BIO_printf(bio_err, "User procession done.\n");
++
++    if (doupdatedb) {
++        /* Lets check some fields */
++        for (i = 0; i < sk_OPENSSL_PSTRING_num(db->db->data); i++) {
++            pp = sk_OPENSSL_PSTRING_value(db->db->data, i);
++
++            if (pp[DB_srptype][0] == 'v') {
++                pp[DB_srptype][0] = 'V';
++                print_user(db, i, verbose);
++            }
++        }
++
++        if (verbose)
++            BIO_printf(bio_err, "Trying to update srpvfile.\n");
++        if (!save_index(srpvfile, "new", db))
++            goto end;
++
++        if (verbose)
++            BIO_printf(bio_err, "Temporary srpvfile created.\n");
++        if (!rotate_index(srpvfile, "new", "old"))
++            goto end;
++
++        if (verbose)
++            BIO_printf(bio_err, "srpvfile updated.\n");
++    }
++
++    ret = (errors != 0);
++ end:
++    if (errors != 0)
++        if (verbose)
++            BIO_printf(bio_err, "User errors %d.\n", errors);
++
++    if (verbose)
++        BIO_printf(bio_err, "SRP terminating with code %d.\n", ret);
++
++    OPENSSL_free(passin);
++    OPENSSL_free(passout);
++    if (ret)
++        ERR_print_errors(bio_err);
++    if (randfile)
++        app_RAND_write_file(randfile);
++    NCONF_free(conf);
++    free_index(db);
++    release_engine(e);
++    return (ret);
++}
++#endif
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/apps/testCA.pem b/CryptoPkg/Library/OpensslLib/openssl/apps/testCA.pem
+new file mode 100644
+index 0000000..dcb710a
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/apps/testCA.pem
+@@ -0,0 +1,8 @@
++-----BEGIN CERTIFICATE REQUEST-----
++MIIBBzCBsgIBADBNMQswCQYDVQQGEwJBVTETMBEGA1UECBMKUXVlZW5zbGFuZDEX
++MBUGA1UEChMOTWluY29tIFB0eSBMdGQxEDAOBgNVBAMTB1RFU1QgQ0EwXDANBgkq
++hkiG9w0BAQEFAANLADBIAkEAzW9brgA8efT2ODB+NrsflJZj3KKqKsm4OrXTRqfL
++VETj1ws/zCXl42XJAxdWQMCP0liKfc9Ut4xi1qCVI7N07wIDAQABoAAwDQYJKoZI
++hvcNAQEEBQADQQBjZZ42Det9Uw0AFwJy4ufUEy5Cv74pxBp5SZnljgHY+Az0Hs2S
++uNkIegr2ITX5azKi9nOkg9ZmsmGG13FIjiC/
++-----END CERTIFICATE REQUEST-----
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/apps/testdsa.h b/CryptoPkg/Library/OpensslLib/openssl/apps/testdsa.h
+new file mode 100644
+index 0000000..1e4502a
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/apps/testdsa.h
+@@ -0,0 +1,290 @@
++/*
++ * Copyright 1998-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++/* used by speed.c */
++DSA *get_dsa512(void);
++DSA *get_dsa1024(void);
++DSA *get_dsa2048(void);
++
++static unsigned char dsa512_priv[] = {
++    0x65, 0xe5, 0xc7, 0x38, 0x60, 0x24, 0xb5, 0x89, 0xd4, 0x9c, 0xeb, 0x4c,
++    0x9c, 0x1d, 0x7a, 0x22, 0xbd, 0xd1, 0xc2, 0xd2,
++};
++
++static unsigned char dsa512_pub[] = {
++    0x00, 0x95, 0xa7, 0x0d, 0xec, 0x93, 0x68, 0xba, 0x5f, 0xf7, 0x5f, 0x07,
++    0xf2, 0x3b, 0xad, 0x6b, 0x01, 0xdc, 0xbe, 0xec, 0xde, 0x04, 0x7a, 0x3a,
++    0x27, 0xb3, 0xec, 0x49, 0xfd, 0x08, 0x43, 0x3d, 0x7e, 0xa8, 0x2c, 0x5e,
++    0x7b, 0xbb, 0xfc, 0xf4, 0x6e, 0xeb, 0x6c, 0xb0, 0x6e, 0xf8, 0x02, 0x12,
++    0x8c, 0x38, 0x5d, 0x83, 0x56, 0x7d, 0xee, 0x53, 0x05, 0x3e, 0x24, 0x84,
++    0xbe, 0xba, 0x0a, 0x6b, 0xc8,
++};
++
++static unsigned char dsa512_p[] = {
++    0x9D, 0x1B, 0x69, 0x8E, 0x26, 0xDB, 0xF2, 0x2B, 0x11, 0x70, 0x19, 0x86,
++    0xF6, 0x19, 0xC8, 0xF8, 0x19, 0xF2, 0x18, 0x53, 0x94, 0x46, 0x06, 0xD0,
++    0x62, 0x50, 0x33, 0x4B, 0x02, 0x3C, 0x52, 0x30, 0x03, 0x8B, 0x3B, 0xF9,
++    0x5F, 0xD1, 0x24, 0x06, 0x4F, 0x7B, 0x4C, 0xBA, 0xAA, 0x40, 0x9B, 0xFD,
++    0x96, 0xE4, 0x37, 0x33, 0xBB, 0x2D, 0x5A, 0xD7, 0x5A, 0x11, 0x40, 0x66,
++    0xA2, 0x76, 0x7D, 0x31,
++};
++
++static unsigned char dsa512_q[] = {
++    0xFB, 0x53, 0xEF, 0x50, 0xB4, 0x40, 0x92, 0x31, 0x56, 0x86, 0x53, 0x7A,
++    0xE8, 0x8B, 0x22, 0x9A, 0x49, 0xFB, 0x71, 0x8F,
++};
++
++static unsigned char dsa512_g[] = {
++    0x83, 0x3E, 0x88, 0xE5, 0xC5, 0x89, 0x73, 0xCE, 0x3B, 0x6C, 0x01, 0x49,
++    0xBF, 0xB3, 0xC7, 0x9F, 0x0A, 0xEA, 0x44, 0x91, 0xE5, 0x30, 0xAA, 0xD9,
++    0xBE, 0x5B, 0x5F, 0xB7, 0x10, 0xD7, 0x89, 0xB7, 0x8E, 0x74, 0xFB, 0xCF,
++    0x29, 0x1E, 0xEB, 0xA8, 0x2C, 0x54, 0x51, 0xB8, 0x10, 0xDE, 0xA0, 0xCE,
++    0x2F, 0xCC, 0x24, 0x6B, 0x90, 0x77, 0xDE, 0xA2, 0x68, 0xA6, 0x52, 0x12,
++    0xA2, 0x03, 0x9D, 0x20,
++};
++
++DSA *get_dsa512()
++{
++    DSA *dsa;
++    BIGNUM *priv_key, *pub_key, *p, *q, *g;
++
++    if ((dsa = DSA_new()) == NULL)
++        return (NULL);
++    priv_key = BN_bin2bn(dsa512_priv, sizeof(dsa512_priv), NULL);
++    pub_key = BN_bin2bn(dsa512_pub, sizeof(dsa512_pub), NULL);
++    p = BN_bin2bn(dsa512_p, sizeof(dsa512_p), NULL);
++    q = BN_bin2bn(dsa512_q, sizeof(dsa512_q), NULL);
++    g = BN_bin2bn(dsa512_g, sizeof(dsa512_g), NULL);
++    if ((priv_key == NULL) || (pub_key == NULL) || (p == NULL) || (q == NULL)
++            || (g == NULL)) {
++        goto err;
++    }
++    if (!DSA_set0_pqg(dsa, p, q, g))
++        goto err;
++    p = q = g = NULL;
++
++    if (!DSA_set0_key(dsa, pub_key, priv_key))
++        goto err;
++
++    return dsa;
++ err:
++    DSA_free(dsa);
++    BN_free(priv_key);
++    BN_free(pub_key);
++    BN_free(p);
++    BN_free(q);
++    BN_free(g);
++    return NULL;
++}
++
++static unsigned char dsa1024_priv[] = {
++    0x7d, 0x21, 0xda, 0xbb, 0x62, 0x15, 0x47, 0x36, 0x07, 0x67, 0x12, 0xe8,
++    0x8c, 0xaa, 0x1c, 0xcd, 0x38, 0x12, 0x61, 0x18,
++};
++
++static unsigned char dsa1024_pub[] = {
++    0x3c, 0x4e, 0x9c, 0x2a, 0x7f, 0x16, 0xc1, 0x25, 0xeb, 0xac, 0x78, 0x63,
++    0x90, 0x14, 0x8c, 0x8b, 0xf4, 0x68, 0x43, 0x3c, 0x2d, 0xee, 0x65, 0x50,
++    0x7d, 0x9c, 0x8f, 0x8c, 0x8a, 0x51, 0xd6, 0x11, 0x2b, 0x99, 0xaf, 0x1e,
++    0x90, 0x97, 0xb5, 0xd3, 0xa6, 0x20, 0x25, 0xd6, 0xfe, 0x43, 0x02, 0xd5,
++    0x91, 0x7d, 0xa7, 0x8c, 0xdb, 0xc9, 0x85, 0xa3, 0x36, 0x48, 0xf7, 0x68,
++    0xaa, 0x60, 0xb1, 0xf7, 0x05, 0x68, 0x3a, 0xa3, 0x3f, 0xd3, 0x19, 0x82,
++    0xd8, 0x82, 0x7a, 0x77, 0xfb, 0xef, 0xf4, 0x15, 0x0a, 0xeb, 0x06, 0x04,
++    0x7f, 0x53, 0x07, 0x0c, 0xbc, 0xcb, 0x2d, 0x83, 0xdb, 0x3e, 0xd1, 0x28,
++    0xa5, 0xa1, 0x31, 0xe0, 0x67, 0xfa, 0x50, 0xde, 0x9b, 0x07, 0x83, 0x7e,
++    0x2c, 0x0b, 0xc3, 0x13, 0x50, 0x61, 0xe5, 0xad, 0xbd, 0x36, 0xb8, 0x97,
++    0x4e, 0x40, 0x7d, 0xe8, 0x83, 0x0d, 0xbc, 0x4b
++};
++
++static unsigned char dsa1024_p[] = {
++    0xA7, 0x3F, 0x6E, 0x85, 0xBF, 0x41, 0x6A, 0x29, 0x7D, 0xF0, 0x9F, 0x47,
++    0x19, 0x30, 0x90, 0x9A, 0x09, 0x1D, 0xDA, 0x6A, 0x33, 0x1E, 0xC5, 0x3D,
++    0x86, 0x96, 0xB3, 0x15, 0xE0, 0x53, 0x2E, 0x8F, 0xE0, 0x59, 0x82, 0x73,
++    0x90, 0x3E, 0x75, 0x31, 0x99, 0x47, 0x7A, 0x52, 0xFB, 0x85, 0xE4, 0xD9,
++    0xA6, 0x7B, 0x38, 0x9B, 0x68, 0x8A, 0x84, 0x9B, 0x87, 0xC6, 0x1E, 0xB5,
++    0x7E, 0x86, 0x4B, 0x53, 0x5B, 0x59, 0xCF, 0x71, 0x65, 0x19, 0x88, 0x6E,
++    0xCE, 0x66, 0xAE, 0x6B, 0x88, 0x36, 0xFB, 0xEC, 0x28, 0xDC, 0xC2, 0xD7,
++    0xA5, 0xBB, 0xE5, 0x2C, 0x39, 0x26, 0x4B, 0xDA, 0x9A, 0x70, 0x18, 0x95,
++    0x37, 0x95, 0x10, 0x56, 0x23, 0xF6, 0x15, 0xED, 0xBA, 0x04, 0x5E, 0xDE,
++    0x39, 0x4F, 0xFD, 0xB7, 0x43, 0x1F, 0xB5, 0xA4, 0x65, 0x6F, 0xCD, 0x80,
++    0x11, 0xE4, 0x70, 0x95, 0x5B, 0x50, 0xCD, 0x49,
++};
++
++static unsigned char dsa1024_q[] = {
++    0xF7, 0x07, 0x31, 0xED, 0xFA, 0x6C, 0x06, 0x03, 0xD5, 0x85, 0x8A, 0x1C,
++    0xAC, 0x9C, 0x65, 0xE7, 0x50, 0x66, 0x65, 0x6F,
++};
++
++static unsigned char dsa1024_g[] = {
++    0x4D, 0xDF, 0x4C, 0x03, 0xA6, 0x91, 0x8A, 0xF5, 0x19, 0x6F, 0x50, 0x46,
++    0x25, 0x99, 0xE5, 0x68, 0x6F, 0x30, 0xE3, 0x69, 0xE1, 0xE5, 0xB3, 0x5D,
++    0x98, 0xBB, 0x28, 0x86, 0x48, 0xFC, 0xDE, 0x99, 0x04, 0x3F, 0x5F, 0x88,
++    0x0C, 0x9C, 0x73, 0x24, 0x0D, 0x20, 0x5D, 0xB9, 0x2A, 0x9A, 0x3F, 0x18,
++    0x96, 0x27, 0xE4, 0x62, 0x87, 0xC1, 0x7B, 0x74, 0x62, 0x53, 0xFC, 0x61,
++    0x27, 0xA8, 0x7A, 0x91, 0x09, 0x9D, 0xB6, 0xF1, 0x4D, 0x9C, 0x54, 0x0F,
++    0x58, 0x06, 0xEE, 0x49, 0x74, 0x07, 0xCE, 0x55, 0x7E, 0x23, 0xCE, 0x16,
++    0xF6, 0xCA, 0xDC, 0x5A, 0x61, 0x01, 0x7E, 0xC9, 0x71, 0xB5, 0x4D, 0xF6,
++    0xDC, 0x34, 0x29, 0x87, 0x68, 0xF6, 0x5E, 0x20, 0x93, 0xB3, 0xDB, 0xF5,
++    0xE4, 0x09, 0x6C, 0x41, 0x17, 0x95, 0x92, 0xEB, 0x01, 0xB5, 0x73, 0xA5,
++    0x6A, 0x7E, 0xD8, 0x32, 0xED, 0x0E, 0x02, 0xB8,
++};
++
++DSA *get_dsa1024()
++{
++    DSA *dsa;
++    BIGNUM *priv_key, *pub_key, *p, *q, *g;
++
++    if ((dsa = DSA_new()) == NULL)
++        return (NULL);
++    priv_key = BN_bin2bn(dsa1024_priv, sizeof(dsa1024_priv), NULL);
++    pub_key = BN_bin2bn(dsa1024_pub, sizeof(dsa1024_pub), NULL);
++    p = BN_bin2bn(dsa1024_p, sizeof(dsa1024_p), NULL);
++    q = BN_bin2bn(dsa1024_q, sizeof(dsa1024_q), NULL);
++    g = BN_bin2bn(dsa1024_g, sizeof(dsa1024_g), NULL);
++    if ((priv_key == NULL) || (pub_key == NULL) || (p == NULL) || (q == NULL)
++            || (g == NULL)) {
++        goto err;
++    }
++    if (!DSA_set0_pqg(dsa, p, q, g))
++        goto err;
++    p = q = g = NULL;
++
++    if (!DSA_set0_key(dsa, pub_key, priv_key))
++        goto err;
++
++    return dsa;
++ err:
++    DSA_free(dsa);
++    BN_free(priv_key);
++    BN_free(pub_key);
++    BN_free(p);
++    BN_free(q);
++    BN_free(g);
++    return NULL;
++}
++
++static unsigned char dsa2048_priv[] = {
++    0x32, 0x67, 0x92, 0xf6, 0xc4, 0xe2, 0xe2, 0xe8, 0xa0, 0x8b, 0x6b, 0x45,
++    0x0c, 0x8a, 0x76, 0xb0, 0xee, 0xcf, 0x91, 0xa7,
++};
++
++static unsigned char dsa2048_pub[] = {
++    0x17, 0x8f, 0xa8, 0x11, 0x84, 0x92, 0xec, 0x83, 0x47, 0xc7, 0x6a, 0xb0,
++    0x92, 0xaf, 0x5a, 0x20, 0x37, 0xa3, 0x64, 0x79, 0xd2, 0xd0, 0x3d, 0xcd,
++    0xe0, 0x61, 0x88, 0x88, 0x21, 0xcc, 0x74, 0x5d, 0xce, 0x4c, 0x51, 0x47,
++    0xf0, 0xc5, 0x5c, 0x4c, 0x82, 0x7a, 0xaf, 0x72, 0xad, 0xb9, 0xe0, 0x53,
++    0xf2, 0x78, 0xb7, 0xf0, 0xb5, 0x48, 0x7f, 0x8a, 0x3a, 0x18, 0xd1, 0x9f,
++    0x8b, 0x7d, 0xa5, 0x47, 0xb7, 0x95, 0xab, 0x98, 0xf8, 0x7b, 0x74, 0x50,
++    0x56, 0x8e, 0x57, 0xf0, 0xee, 0xf5, 0xb7, 0xba, 0xab, 0x85, 0x86, 0xf9,
++    0x2b, 0xef, 0x41, 0x56, 0xa0, 0xa4, 0x9f, 0xb7, 0x38, 0x00, 0x46, 0x0a,
++    0xa6, 0xf1, 0xfc, 0x1f, 0xd8, 0x4e, 0x85, 0x44, 0x92, 0x43, 0x21, 0x5d,
++    0x6e, 0xcc, 0xc2, 0xcb, 0x26, 0x31, 0x0d, 0x21, 0xc4, 0xbd, 0x8d, 0x24,
++    0xbc, 0xd9, 0x18, 0x19, 0xd7, 0xdc, 0xf1, 0xe7, 0x93, 0x50, 0x48, 0x03,
++    0x2c, 0xae, 0x2e, 0xe7, 0x49, 0x88, 0x5f, 0x93, 0x57, 0x27, 0x99, 0x36,
++    0xb4, 0x20, 0xab, 0xfc, 0xa7, 0x2b, 0xf2, 0xd9, 0x98, 0xd7, 0xd4, 0x34,
++    0x9d, 0x96, 0x50, 0x58, 0x9a, 0xea, 0x54, 0xf3, 0xee, 0xf5, 0x63, 0x14,
++    0xee, 0x85, 0x83, 0x74, 0x76, 0xe1, 0x52, 0x95, 0xc3, 0xf7, 0xeb, 0x04,
++    0x04, 0x7b, 0xa7, 0x28, 0x1b, 0xcc, 0xea, 0x4a, 0x4e, 0x84, 0xda, 0xd8,
++    0x9c, 0x79, 0xd8, 0x9b, 0x66, 0x89, 0x2f, 0xcf, 0xac, 0xd7, 0x79, 0xf9,
++    0xa9, 0xd8, 0x45, 0x13, 0x78, 0xb9, 0x00, 0x14, 0xc9, 0x7e, 0x22, 0x51,
++    0x86, 0x67, 0xb0, 0x9f, 0x26, 0x11, 0x23, 0xc8, 0x38, 0xd7, 0x70, 0x1d,
++    0x15, 0x8e, 0x4d, 0x4f, 0x95, 0x97, 0x40, 0xa1, 0xc2, 0x7e, 0x01, 0x18,
++    0x72, 0xf4, 0x10, 0xe6, 0x8d, 0x52, 0x16, 0x7f, 0xf2, 0xc9, 0xf8, 0x33,
++    0x8b, 0x33, 0xb7, 0xce,
++};
++
++static unsigned char dsa2048_p[] = {
++    0xA0, 0x25, 0xFA, 0xAD, 0xF4, 0x8E, 0xB9, 0xE5, 0x99, 0xF3, 0x5D, 0x6F,
++    0x4F, 0x83, 0x34, 0xE2, 0x7E, 0xCF, 0x6F, 0xBF, 0x30, 0xAF, 0x6F, 0x81,
++    0xEB, 0xF8, 0xC4, 0x13, 0xD9, 0xA0, 0x5D, 0x8B, 0x5C, 0x8E, 0xDC, 0xC2,
++    0x1D, 0x0B, 0x41, 0x32, 0xB0, 0x1F, 0xFE, 0xEF, 0x0C, 0xC2, 0xA2, 0x7E,
++    0x68, 0x5C, 0x28, 0x21, 0xE9, 0xF5, 0xB1, 0x58, 0x12, 0x63, 0x4C, 0x19,
++    0x4E, 0xFF, 0x02, 0x4B, 0x92, 0xED, 0xD2, 0x07, 0x11, 0x4D, 0x8C, 0x58,
++    0x16, 0x5C, 0x55, 0x8E, 0xAD, 0xA3, 0x67, 0x7D, 0xB9, 0x86, 0x6E, 0x0B,
++    0xE6, 0x54, 0x6F, 0x40, 0xAE, 0x0E, 0x67, 0x4C, 0xF9, 0x12, 0x5B, 0x3C,
++    0x08, 0x7A, 0xF7, 0xFC, 0x67, 0x86, 0x69, 0xE7, 0x0A, 0x94, 0x40, 0xBF,
++    0x8B, 0x76, 0xFE, 0x26, 0xD1, 0xF2, 0xA1, 0x1A, 0x84, 0xA1, 0x43, 0x56,
++    0x28, 0xBC, 0x9A, 0x5F, 0xD7, 0x3B, 0x69, 0x89, 0x8A, 0x36, 0x2C, 0x51,
++    0xDF, 0x12, 0x77, 0x2F, 0x57, 0x7B, 0xA0, 0xAA, 0xDD, 0x7F, 0xA1, 0x62,
++    0x3B, 0x40, 0x7B, 0x68, 0x1A, 0x8F, 0x0D, 0x38, 0xBB, 0x21, 0x5D, 0x18,
++    0xFC, 0x0F, 0x46, 0xF7, 0xA3, 0xB0, 0x1D, 0x23, 0xC3, 0xD2, 0xC7, 0x72,
++    0x51, 0x18, 0xDF, 0x46, 0x95, 0x79, 0xD9, 0xBD, 0xB5, 0x19, 0x02, 0x2C,
++    0x87, 0xDC, 0xE7, 0x57, 0x82, 0x7E, 0xF1, 0x8B, 0x06, 0x3D, 0x00, 0xA5,
++    0x7B, 0x6B, 0x26, 0x27, 0x91, 0x0F, 0x6A, 0x77, 0xE4, 0xD5, 0x04, 0xE4,
++    0x12, 0x2C, 0x42, 0xFF, 0xD2, 0x88, 0xBB, 0xD3, 0x92, 0xA0, 0xF9, 0xC8,
++    0x51, 0x64, 0x14, 0x5C, 0xD8, 0xF9, 0x6C, 0x47, 0x82, 0xB4, 0x1C, 0x7F,
++    0x09, 0xB8, 0xF0, 0x25, 0x83, 0x1D, 0x3F, 0x3F, 0x05, 0xB3, 0x21, 0x0A,
++    0x5D, 0xA7, 0xD8, 0x54, 0xC3, 0x65, 0x7D, 0xC3, 0xB0, 0x1D, 0xBF, 0xAE,
++    0xF8, 0x68, 0xCF, 0x9B,
++};
++
++static unsigned char dsa2048_q[] = {
++    0x97, 0xE7, 0x33, 0x4D, 0xD3, 0x94, 0x3E, 0x0B, 0xDB, 0x62, 0x74, 0xC6,
++    0xA1, 0x08, 0xDD, 0x19, 0xA3, 0x75, 0x17, 0x1B,
++};
++
++static unsigned char dsa2048_g[] = {
++    0x2C, 0x78, 0x16, 0x59, 0x34, 0x63, 0xF4, 0xF3, 0x92, 0xFC, 0xB5, 0xA5,
++    0x4F, 0x13, 0xDE, 0x2F, 0x1C, 0xA4, 0x3C, 0xAE, 0xAD, 0x38, 0x3F, 0x7E,
++    0x90, 0xBF, 0x96, 0xA6, 0xAE, 0x25, 0x90, 0x72, 0xF5, 0x8E, 0x80, 0x0C,
++    0x39, 0x1C, 0xD9, 0xEC, 0xBA, 0x90, 0x5B, 0x3A, 0xE8, 0x58, 0x6C, 0x9E,
++    0x30, 0x42, 0x37, 0x02, 0x31, 0x82, 0xBC, 0x6A, 0xDF, 0x6A, 0x09, 0x29,
++    0xE3, 0xC0, 0x46, 0xD1, 0xCB, 0x85, 0xEC, 0x0C, 0x30, 0x5E, 0xEA, 0xC8,
++    0x39, 0x8E, 0x22, 0x9F, 0x22, 0x10, 0xD2, 0x34, 0x61, 0x68, 0x37, 0x3D,
++    0x2E, 0x4A, 0x5B, 0x9A, 0xF5, 0xC1, 0x48, 0xC6, 0xF6, 0xDC, 0x63, 0x1A,
++    0xD3, 0x96, 0x64, 0xBA, 0x34, 0xC9, 0xD1, 0xA0, 0xD1, 0xAE, 0x6C, 0x2F,
++    0x48, 0x17, 0x93, 0x14, 0x43, 0xED, 0xF0, 0x21, 0x30, 0x19, 0xC3, 0x1B,
++    0x5F, 0xDE, 0xA3, 0xF0, 0x70, 0x78, 0x18, 0xE1, 0xA8, 0xE4, 0xEE, 0x2E,
++    0x00, 0xA5, 0xE4, 0xB3, 0x17, 0xC8, 0x0C, 0x7D, 0x6E, 0x42, 0xDC, 0xB7,
++    0x46, 0x00, 0x36, 0x4D, 0xD4, 0x46, 0xAA, 0x3D, 0x3C, 0x46, 0x89, 0x40,
++    0xBF, 0x1D, 0x84, 0x77, 0x0A, 0x75, 0xF3, 0x87, 0x1D, 0x08, 0x4C, 0xA6,
++    0xD1, 0xA9, 0x1C, 0x1E, 0x12, 0x1E, 0xE1, 0xC7, 0x30, 0x28, 0x76, 0xA5,
++    0x7F, 0x6C, 0x85, 0x96, 0x2B, 0x6F, 0xDB, 0x80, 0x66, 0x26, 0xAE, 0xF5,
++    0x93, 0xC7, 0x8E, 0xAE, 0x9A, 0xED, 0xE4, 0xCA, 0x04, 0xEA, 0x3B, 0x72,
++    0xEF, 0xDC, 0x87, 0xED, 0x0D, 0xA5, 0x4C, 0x4A, 0xDD, 0x71, 0x22, 0x64,
++    0x59, 0x69, 0x4E, 0x8E, 0xBF, 0x43, 0xDC, 0xAB, 0x8E, 0x66, 0xBB, 0x01,
++    0xB6, 0xF4, 0xE7, 0xFD, 0xD2, 0xAD, 0x9F, 0x36, 0xC1, 0xA0, 0x29, 0x99,
++    0xD1, 0x96, 0x70, 0x59, 0x06, 0x78, 0x35, 0xBD, 0x65, 0x55, 0x52, 0x9E,
++    0xF8, 0xB2, 0xE5, 0x38,
++};
++
++DSA *get_dsa2048()
++{
++    DSA *dsa;
++    BIGNUM *priv_key, *pub_key, *p, *q, *g;
++
++    if ((dsa = DSA_new()) == NULL)
++        return (NULL);
++    priv_key = BN_bin2bn(dsa2048_priv, sizeof(dsa2048_priv), NULL);
++    pub_key = BN_bin2bn(dsa2048_pub, sizeof(dsa2048_pub), NULL);
++    p = BN_bin2bn(dsa2048_p, sizeof(dsa2048_p), NULL);
++    q = BN_bin2bn(dsa2048_q, sizeof(dsa2048_q), NULL);
++    g = BN_bin2bn(dsa2048_g, sizeof(dsa2048_g), NULL);
++    if ((priv_key == NULL) || (pub_key == NULL) || (p == NULL) || (q == NULL)
++            || (g == NULL)) {
++        goto err;
++    }
++    if (!DSA_set0_pqg(dsa, p, q, g))
++        goto err;
++    p = q = g = NULL;
++
++    if (!DSA_set0_key(dsa, pub_key, priv_key))
++        goto err;
++
++    return dsa;
++ err:
++    DSA_free(dsa);
++    BN_free(priv_key);
++    BN_free(pub_key);
++    BN_free(p);
++    BN_free(q);
++    BN_free(g);
++    return NULL;
++}
++
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/apps/testrsa.h b/CryptoPkg/Library/OpensslLib/openssl/apps/testrsa.h
+new file mode 100644
+index 0000000..1350ce5
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/apps/testrsa.h
+@@ -0,0 +1,1960 @@
++/*
++ * Copyright 1995-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++static unsigned char test512[] = {
++    0x30, 0x82, 0x01, 0x3a, 0x02, 0x01, 0x00, 0x02, 0x41, 0x00,
++    0xd6, 0x33, 0xb9, 0xc8, 0xfb, 0x4f, 0x3c, 0x7d, 0xc0, 0x01,
++    0x86, 0xd0, 0xe7, 0xa0, 0x55, 0xf2, 0x95, 0x93, 0xcc, 0x4f,
++    0xb7, 0x5b, 0x67, 0x5b, 0x94, 0x68, 0xc9, 0x34, 0x15, 0xde,
++    0xa5, 0x2e, 0x1c, 0x33, 0xc2, 0x6e, 0xfc, 0x34, 0x5e, 0x71,
++    0x13, 0xb7, 0xd6, 0xee, 0xd8, 0xa5, 0x65, 0x05, 0x72, 0x87,
++    0xa8, 0xb0, 0x77, 0xfe, 0x57, 0xf5, 0xfc, 0x5f, 0x55, 0x83,
++    0x87, 0xdd, 0x57, 0x49, 0x02, 0x03, 0x01, 0x00, 0x01, 0x02,
++    0x41, 0x00, 0xa7, 0xf7, 0x91, 0xc5, 0x0f, 0x84, 0x57, 0xdc,
++    0x07, 0xf7, 0x6a, 0x7f, 0x60, 0x52, 0xb3, 0x72, 0xf1, 0x66,
++    0x1f, 0x7d, 0x97, 0x3b, 0x9e, 0xb6, 0x0a, 0x8f, 0x8c, 0xcf,
++    0x42, 0x23, 0x00, 0x04, 0xd4, 0x28, 0x0e, 0x1c, 0x90, 0xc4,
++    0x11, 0x25, 0x25, 0xa5, 0x93, 0xa5, 0x2f, 0x70, 0x02, 0xdf,
++    0x81, 0x9c, 0x49, 0x03, 0xa0, 0xf8, 0x6d, 0x54, 0x2e, 0x26,
++    0xde, 0xaa, 0x85, 0x59, 0xa8, 0x31, 0x02, 0x21, 0x00, 0xeb,
++    0x47, 0xd7, 0x3b, 0xf6, 0xc3, 0xdd, 0x5a, 0x46, 0xc5, 0xb9,
++    0x2b, 0x9a, 0xa0, 0x09, 0x8f, 0xa6, 0xfb, 0xf3, 0x78, 0x7a,
++    0x33, 0x70, 0x9d, 0x0f, 0x42, 0x6b, 0x13, 0x68, 0x24, 0xd3,
++    0x15, 0x02, 0x21, 0x00, 0xe9, 0x10, 0xb0, 0xb3, 0x0d, 0xe2,
++    0x82, 0x68, 0x77, 0x8a, 0x6e, 0x7c, 0xda, 0xbc, 0x3e, 0x53,
++    0x83, 0xfb, 0xd6, 0x22, 0xe7, 0xb5, 0xae, 0x6e, 0x80, 0xda,
++    0x00, 0x55, 0x97, 0xc1, 0xd0, 0x65, 0x02, 0x20, 0x4c, 0xf8,
++    0x73, 0xb1, 0x6a, 0x49, 0x29, 0x61, 0x1f, 0x46, 0x10, 0x0d,
++    0xf3, 0xc7, 0xe7, 0x58, 0xd7, 0x88, 0x15, 0x5e, 0x94, 0x9b,
++    0xbf, 0x7b, 0xa2, 0x42, 0x58, 0x45, 0x41, 0x0c, 0xcb, 0x01,
++    0x02, 0x20, 0x12, 0x11, 0xba, 0x31, 0x57, 0x9d, 0x3d, 0x11,
++    0x0e, 0x5b, 0x8c, 0x2f, 0x5f, 0xe2, 0x02, 0x4f, 0x05, 0x47,
++    0x8c, 0x15, 0x8e, 0xb3, 0x56, 0x3f, 0xb8, 0xfb, 0xad, 0xd4,
++    0xf4, 0xfc, 0x10, 0xc5, 0x02, 0x20, 0x18, 0xa1, 0x29, 0x99,
++    0x5b, 0xd9, 0xc8, 0xd4, 0xfc, 0x49, 0x7a, 0x2a, 0x21, 0x2c,
++    0x49, 0xe4, 0x4f, 0xeb, 0xef, 0x51, 0xf1, 0xab, 0x6d, 0xfb,
++    0x4b, 0x14, 0xe9, 0x4b, 0x52, 0xb5, 0x82, 0x2c,
++};
++
++static unsigned char test1024[] = {
++    0x30, 0x82, 0x02, 0x5c, 0x02, 0x01, 0x00, 0x02, 0x81, 0x81,
++    0x00, 0xdc, 0x98, 0x43, 0xe8, 0x3d, 0x43, 0x5b, 0xe4, 0x05,
++    0xcd, 0xd0, 0xa9, 0x3e, 0xcb, 0x83, 0x75, 0xf6, 0xb5, 0xa5,
++    0x9f, 0x6b, 0xe9, 0x34, 0x41, 0x29, 0x18, 0xfa, 0x6a, 0x55,
++    0x4d, 0x70, 0xfc, 0xec, 0xae, 0x87, 0x38, 0x0a, 0x20, 0xa9,
++    0xc0, 0x45, 0x77, 0x6e, 0x57, 0x60, 0x57, 0xf4, 0xed, 0x96,
++    0x22, 0xcb, 0x8f, 0xe1, 0x33, 0x3a, 0x17, 0x1f, 0xed, 0x37,
++    0xa5, 0x6f, 0xeb, 0xa6, 0xbc, 0x12, 0x80, 0x1d, 0x53, 0xbd,
++    0x70, 0xeb, 0x21, 0x76, 0x3e, 0xc9, 0x2f, 0x1a, 0x45, 0x24,
++    0x82, 0xff, 0xcd, 0x59, 0x32, 0x06, 0x2e, 0x12, 0x3b, 0x23,
++    0x78, 0xed, 0x12, 0x3d, 0xe0, 0x8d, 0xf9, 0x67, 0x4f, 0x37,
++    0x4e, 0x47, 0x02, 0x4c, 0x2d, 0xc0, 0x4f, 0x1f, 0xb3, 0x94,
++    0xe1, 0x41, 0x2e, 0x2d, 0x90, 0x10, 0xfc, 0x82, 0x91, 0x8b,
++    0x0f, 0x22, 0xd4, 0xf2, 0xfc, 0x2c, 0xab, 0x53, 0x55, 0x02,
++    0x03, 0x01, 0x00, 0x01, 0x02, 0x81, 0x80, 0x2b, 0xcc, 0x3f,
++    0x8f, 0x58, 0xba, 0x8b, 0x00, 0x16, 0xf6, 0xea, 0x3a, 0xf0,
++    0x30, 0xd0, 0x05, 0x17, 0xda, 0xb0, 0xeb, 0x9a, 0x2d, 0x4f,
++    0x26, 0xb0, 0xd6, 0x38, 0xc1, 0xeb, 0xf5, 0xd8, 0x3d, 0x1f,
++    0x70, 0xf7, 0x7f, 0xf4, 0xe2, 0xcf, 0x51, 0x51, 0x79, 0x88,
++    0xfa, 0xe8, 0x32, 0x0e, 0x7b, 0x2d, 0x97, 0xf2, 0xfa, 0xba,
++    0x27, 0xc5, 0x9c, 0xd9, 0xc5, 0xeb, 0x8a, 0x79, 0x52, 0x3c,
++    0x64, 0x34, 0x7d, 0xc2, 0xcf, 0x28, 0xc7, 0x4e, 0xd5, 0x43,
++    0x0b, 0xd1, 0xa6, 0xca, 0x6d, 0x03, 0x2d, 0x72, 0x23, 0xbc,
++    0x6d, 0x05, 0xfa, 0x16, 0x09, 0x2f, 0x2e, 0x5c, 0xb6, 0xee,
++    0x74, 0xdd, 0xd2, 0x48, 0x8e, 0x36, 0x0c, 0x06, 0x3d, 0x4d,
++    0xe5, 0x10, 0x82, 0xeb, 0x6a, 0xf3, 0x4b, 0x9f, 0xd6, 0xed,
++    0x11, 0xb1, 0x6e, 0xec, 0xf4, 0xfe, 0x8e, 0x75, 0x94, 0x20,
++    0x2f, 0xcb, 0xac, 0x46, 0xf1, 0x02, 0x41, 0x00, 0xf9, 0x8c,
++    0xa3, 0x85, 0xb1, 0xdd, 0x29, 0xaf, 0x65, 0xc1, 0x33, 0xf3,
++    0x95, 0xc5, 0x52, 0x68, 0x0b, 0xd4, 0xf1, 0xe5, 0x0e, 0x02,
++    0x9f, 0x4f, 0xfa, 0x77, 0xdc, 0x46, 0x9e, 0xc7, 0xa6, 0xe4,
++    0x16, 0x29, 0xda, 0xb0, 0x07, 0xcf, 0x5b, 0xa9, 0x12, 0x8a,
++    0xdd, 0x63, 0x0a, 0xde, 0x2e, 0x8c, 0x66, 0x8b, 0x8c, 0xdc,
++    0x19, 0xa3, 0x7e, 0xf4, 0x3b, 0xd0, 0x1a, 0x8c, 0xa4, 0xc2,
++    0xe1, 0xd3, 0x02, 0x41, 0x00, 0xe2, 0x4c, 0x05, 0xf2, 0x04,
++    0x86, 0x4e, 0x61, 0x43, 0xdb, 0xb0, 0xb9, 0x96, 0x86, 0x52,
++    0x2c, 0xca, 0x8d, 0x7b, 0xab, 0x0b, 0x13, 0x0d, 0x7e, 0x38,
++    0x5b, 0xe2, 0x2e, 0x7b, 0x0e, 0xe7, 0x19, 0x99, 0x38, 0xe7,
++    0xf2, 0x21, 0xbd, 0x85, 0x85, 0xe3, 0xfd, 0x28, 0x77, 0x20,
++    0x31, 0x71, 0x2c, 0xd0, 0xff, 0xfb, 0x2e, 0xaf, 0x85, 0xb4,
++    0x86, 0xca, 0xf3, 0xbb, 0xca, 0xaa, 0x0f, 0x95, 0x37, 0x02,
++    0x40, 0x0e, 0x41, 0x9a, 0x95, 0xe8, 0xb3, 0x59, 0xce, 0x4b,
++    0x61, 0xde, 0x35, 0xec, 0x38, 0x79, 0x9c, 0xb8, 0x10, 0x52,
++    0x41, 0x63, 0xab, 0x82, 0xae, 0x6f, 0x00, 0xa9, 0xf4, 0xde,
++    0xdd, 0x49, 0x0b, 0x7e, 0xb8, 0xa5, 0x65, 0xa9, 0x0c, 0x8f,
++    0x8f, 0xf9, 0x1f, 0x35, 0xc6, 0x92, 0xb8, 0x5e, 0xb0, 0x66,
++    0xab, 0x52, 0x40, 0xc0, 0xb6, 0x36, 0x6a, 0x7d, 0x80, 0x46,
++    0x04, 0x02, 0xe5, 0x9f, 0x41, 0x02, 0x41, 0x00, 0xc0, 0xad,
++    0xcc, 0x4e, 0x21, 0xee, 0x1d, 0x24, 0x91, 0xfb, 0xa7, 0x80,
++    0x8d, 0x9a, 0xb6, 0xb3, 0x2e, 0x8f, 0xc2, 0xe1, 0x82, 0xdf,
++    0x69, 0x18, 0xb4, 0x71, 0xff, 0xa6, 0x65, 0xde, 0xed, 0x84,
++    0x8d, 0x42, 0xb7, 0xb3, 0x21, 0x69, 0x56, 0x1c, 0x07, 0x60,
++    0x51, 0x29, 0x04, 0xff, 0x34, 0x06, 0xdd, 0xb9, 0x67, 0x2c,
++    0x7c, 0x04, 0x93, 0x0e, 0x46, 0x15, 0xbb, 0x2a, 0xb7, 0x1b,
++    0xe7, 0x87, 0x02, 0x40, 0x78, 0xda, 0x5d, 0x07, 0x51, 0x0c,
++    0x16, 0x7a, 0x9f, 0x29, 0x20, 0x84, 0x0d, 0x42, 0xfa, 0xd7,
++    0x00, 0xd8, 0x77, 0x7e, 0xb0, 0xb0, 0x6b, 0xd6, 0x5b, 0x53,
++    0xb8, 0x9b, 0x7a, 0xcd, 0xc7, 0x2b, 0xb8, 0x6a, 0x63, 0xa9,
++    0xfb, 0x6f, 0xa4, 0x72, 0xbf, 0x4c, 0x5d, 0x00, 0x14, 0xba,
++    0xfa, 0x59, 0x88, 0xed, 0xe4, 0xe0, 0x8c, 0xa2, 0xec, 0x14,
++    0x7e, 0x2d, 0xe2, 0xf0, 0x46, 0x49, 0x95, 0x45,
++};
++
++static unsigned char test2048[] = {
++    0x30, 0x82, 0x04, 0xa3, 0x02, 0x01, 0x00, 0x02, 0x82, 0x01,
++    0x01, 0x00, 0xc0, 0xc0, 0xce, 0x3e, 0x3c, 0x53, 0x67, 0x3f,
++    0x4f, 0xc5, 0x2f, 0xa4, 0xc2, 0x5a, 0x2f, 0x58, 0xfd, 0x27,
++    0x52, 0x6a, 0xe8, 0xcf, 0x4a, 0x73, 0x47, 0x8d, 0x25, 0x0f,
++    0x5f, 0x03, 0x26, 0x78, 0xef, 0xf0, 0x22, 0x12, 0xd3, 0xde,
++    0x47, 0xb2, 0x1c, 0x0b, 0x38, 0x63, 0x1a, 0x6c, 0x85, 0x7a,
++    0x80, 0xc6, 0x8f, 0xa0, 0x41, 0xaf, 0x62, 0xc4, 0x67, 0x32,
++    0x88, 0xf8, 0xa6, 0x9c, 0xf5, 0x23, 0x1d, 0xe4, 0xac, 0x3f,
++    0x29, 0xf9, 0xec, 0xe1, 0x8b, 0x26, 0x03, 0x2c, 0xb2, 0xab,
++    0xf3, 0x7d, 0xb5, 0xca, 0x49, 0xc0, 0x8f, 0x1c, 0xdf, 0x33,
++    0x3a, 0x60, 0xda, 0x3c, 0xb0, 0x16, 0xf8, 0xa9, 0x12, 0x8f,
++    0x64, 0xac, 0x23, 0x0c, 0x69, 0x64, 0x97, 0x5d, 0x99, 0xd4,
++    0x09, 0x83, 0x9b, 0x61, 0xd3, 0xac, 0xf0, 0xde, 0xdd, 0x5e,
++    0x9f, 0x44, 0x94, 0xdb, 0x3a, 0x4d, 0x97, 0xe8, 0x52, 0x29,
++    0xf7, 0xdb, 0x94, 0x07, 0x45, 0x90, 0x78, 0x1e, 0x31, 0x0b,
++    0x80, 0xf7, 0x57, 0xad, 0x1c, 0x79, 0xc5, 0xcb, 0x32, 0xb0,
++    0xce, 0xcd, 0x74, 0xb3, 0xe2, 0x94, 0xc5, 0x78, 0x2f, 0x34,
++    0x1a, 0x45, 0xf7, 0x8c, 0x52, 0xa5, 0xbc, 0x8d, 0xec, 0xd1,
++    0x2f, 0x31, 0x3b, 0xf0, 0x49, 0x59, 0x5e, 0x88, 0x9d, 0x15,
++    0x92, 0x35, 0x32, 0xc1, 0xe7, 0x61, 0xec, 0x50, 0x48, 0x7c,
++    0xba, 0x05, 0xf9, 0xf8, 0xf8, 0xa7, 0x8c, 0x83, 0xe8, 0x66,
++    0x5b, 0xeb, 0xfe, 0xd8, 0x4f, 0xdd, 0x6d, 0x36, 0xc0, 0xb2,
++    0x90, 0x0f, 0xb8, 0x52, 0xf9, 0x04, 0x9b, 0x40, 0x2c, 0x27,
++    0xd6, 0x36, 0x8e, 0xc2, 0x1b, 0x44, 0xf3, 0x92, 0xd5, 0x15,
++    0x9e, 0x9a, 0xbc, 0xf3, 0x7d, 0x03, 0xd7, 0x02, 0x14, 0x20,
++    0xe9, 0x10, 0x92, 0xfd, 0xf9, 0xfc, 0x8f, 0xe5, 0x18, 0xe1,
++    0x95, 0xcc, 0x9e, 0x60, 0xa6, 0xfa, 0x38, 0x4d, 0x02, 0x03,
++    0x01, 0x00, 0x01, 0x02, 0x82, 0x01, 0x00, 0x00, 0xc3, 0xc3,
++    0x0d, 0xb4, 0x27, 0x90, 0x8d, 0x4b, 0xbf, 0xb8, 0x84, 0xaa,
++    0xd0, 0xb8, 0xc7, 0x5d, 0x99, 0xbe, 0x55, 0xf6, 0x3e, 0x7c,
++    0x49, 0x20, 0xcb, 0x8a, 0x8e, 0x19, 0x0e, 0x66, 0x24, 0xac,
++    0xaf, 0x03, 0x33, 0x97, 0xeb, 0x95, 0xd5, 0x3b, 0x0f, 0x40,
++    0x56, 0x04, 0x50, 0xd1, 0xe6, 0xbe, 0x84, 0x0b, 0x25, 0xd3,
++    0x9c, 0xe2, 0x83, 0x6c, 0xf5, 0x62, 0x5d, 0xba, 0x2b, 0x7d,
++    0x3d, 0x7a, 0x6c, 0xe1, 0xd2, 0x0e, 0x54, 0x93, 0x80, 0x01,
++    0x91, 0x51, 0x09, 0xe8, 0x5b, 0x8e, 0x47, 0xbd, 0x64, 0xe4,
++    0x0e, 0x03, 0x83, 0x55, 0xcf, 0x5a, 0x37, 0xf0, 0x25, 0xb5,
++    0x7d, 0x21, 0xd7, 0x69, 0xdf, 0x6f, 0xc2, 0xcf, 0x10, 0xc9,
++    0x8a, 0x40, 0x9f, 0x7a, 0x70, 0xc0, 0xe8, 0xe8, 0xc0, 0xe6,
++    0x9a, 0x15, 0x0a, 0x8d, 0x4e, 0x46, 0xcb, 0x7a, 0xdb, 0xb3,
++    0xcb, 0x83, 0x02, 0xc4, 0xf0, 0xab, 0xeb, 0x02, 0x01, 0x0e,
++    0x23, 0xfc, 0x1d, 0xc4, 0xbd, 0xd4, 0xaa, 0x5d, 0x31, 0x46,
++    0x99, 0xce, 0x9e, 0xf8, 0x04, 0x75, 0x10, 0x67, 0xc4, 0x53,
++    0x47, 0x44, 0xfa, 0xc2, 0x25, 0x73, 0x7e, 0xd0, 0x8e, 0x59,
++    0xd1, 0xb2, 0x5a, 0xf4, 0xc7, 0x18, 0x92, 0x2f, 0x39, 0xab,
++    0xcd, 0xa3, 0xb5, 0xc2, 0xb9, 0xc7, 0xb9, 0x1b, 0x9f, 0x48,
++    0xfa, 0x13, 0xc6, 0x98, 0x4d, 0xca, 0x84, 0x9c, 0x06, 0xca,
++    0xe7, 0x89, 0x01, 0x04, 0xc4, 0x6c, 0xfd, 0x29, 0x59, 0x35,
++    0xe7, 0xf3, 0xdd, 0xce, 0x64, 0x59, 0xbf, 0x21, 0x13, 0xa9,
++    0x9f, 0x0e, 0xc5, 0xff, 0xbd, 0x33, 0x00, 0xec, 0xac, 0x6b,
++    0x11, 0xef, 0x51, 0x5e, 0xad, 0x07, 0x15, 0xde, 0xb8, 0x5f,
++    0xc6, 0xb9, 0xa3, 0x22, 0x65, 0x46, 0x83, 0x14, 0xdf, 0xd0,
++    0xf1, 0x44, 0x8a, 0xe1, 0x9c, 0x23, 0x33, 0xb4, 0x97, 0x33,
++    0xe6, 0x6b, 0x81, 0x02, 0x81, 0x81, 0x00, 0xec, 0x12, 0xa7,
++    0x59, 0x74, 0x6a, 0xde, 0x3e, 0xad, 0xd8, 0x36, 0x80, 0x50,
++    0xa2, 0xd5, 0x21, 0x81, 0x07, 0xf1, 0xd0, 0x91, 0xf2, 0x6c,
++    0x12, 0x2f, 0x9d, 0x1a, 0x26, 0xf8, 0x30, 0x65, 0xdf, 0xe8,
++    0xc0, 0x9b, 0x6a, 0x30, 0x98, 0x82, 0x87, 0xec, 0xa2, 0x56,
++    0x87, 0x62, 0x6f, 0xe7, 0x9f, 0xf6, 0x56, 0xe6, 0x71, 0x8f,
++    0x49, 0x86, 0x93, 0x5a, 0x4d, 0x34, 0x58, 0xfe, 0xd9, 0x04,
++    0x13, 0xaf, 0x79, 0xb7, 0xad, 0x11, 0xd1, 0x30, 0x9a, 0x14,
++    0x06, 0xa0, 0xfa, 0xb7, 0x55, 0xdc, 0x6c, 0x5a, 0x4c, 0x2c,
++    0x59, 0x56, 0xf6, 0xe8, 0x9d, 0xaf, 0x0a, 0x78, 0x99, 0x06,
++    0x06, 0x9e, 0xe7, 0x9c, 0x51, 0x55, 0x43, 0xfc, 0x3b, 0x6c,
++    0x0b, 0xbf, 0x2d, 0x41, 0xa7, 0xaf, 0xb7, 0xe0, 0xe8, 0x28,
++    0x18, 0xb4, 0x13, 0xd1, 0xe6, 0x97, 0xd0, 0x9f, 0x6a, 0x80,
++    0xca, 0xdd, 0x1a, 0x7e, 0x15, 0x02, 0x81, 0x81, 0x00, 0xd1,
++    0x06, 0x0c, 0x1f, 0xe3, 0xd0, 0xab, 0xd6, 0xca, 0x7c, 0xbc,
++    0x7d, 0x13, 0x35, 0xce, 0x27, 0xcd, 0xd8, 0x49, 0x51, 0x63,
++    0x64, 0x0f, 0xca, 0x06, 0x12, 0xfc, 0x07, 0x3e, 0xaf, 0x61,
++    0x6d, 0xe2, 0x53, 0x39, 0x27, 0xae, 0xc3, 0x11, 0x9e, 0x94,
++    0x01, 0x4f, 0xe3, 0xf3, 0x67, 0xf9, 0x77, 0xf9, 0xe7, 0x95,
++    0x3a, 0x6f, 0xe2, 0x20, 0x73, 0x3e, 0xa4, 0x7a, 0x28, 0xd4,
++    0x61, 0x97, 0xf6, 0x17, 0xa0, 0x23, 0x10, 0x2b, 0xce, 0x84,
++    0x57, 0x7e, 0x25, 0x1f, 0xf4, 0xa8, 0x54, 0xd2, 0x65, 0x94,
++    0xcc, 0x95, 0x0a, 0xab, 0x30, 0xc1, 0x59, 0x1f, 0x61, 0x8e,
++    0xb9, 0x6b, 0xd7, 0x4e, 0xb9, 0x83, 0x43, 0x79, 0x85, 0x11,
++    0xbc, 0x0f, 0xae, 0x25, 0x20, 0x05, 0xbc, 0xd2, 0x48, 0xa1,
++    0x68, 0x09, 0x84, 0xf6, 0x12, 0x9a, 0x66, 0xb9, 0x2b, 0xbb,
++    0x76, 0x03, 0x17, 0x46, 0x4e, 0x97, 0x59, 0x02, 0x81, 0x80,
++    0x09, 0x4c, 0xfa, 0xd6, 0xe5, 0x65, 0x48, 0x78, 0x43, 0xb5,
++    0x1f, 0x00, 0x93, 0x2c, 0xb7, 0x24, 0xe8, 0xc6, 0x7d, 0x5a,
++    0x70, 0x45, 0x92, 0xc8, 0x6c, 0xa3, 0xcd, 0xe1, 0xf7, 0x29,
++    0x40, 0xfa, 0x3f, 0x5b, 0x47, 0x44, 0x39, 0xc1, 0xe8, 0x72,
++    0x9e, 0x7a, 0x0e, 0xda, 0xaa, 0xa0, 0x2a, 0x09, 0xfd, 0x54,
++    0x93, 0x23, 0xaa, 0x37, 0x85, 0x5b, 0xcc, 0xd4, 0xf9, 0xd8,
++    0xff, 0xc1, 0x61, 0x0d, 0xbd, 0x7e, 0x18, 0x24, 0x73, 0x6d,
++    0x40, 0x72, 0xf1, 0x93, 0x09, 0x48, 0x97, 0x6c, 0x84, 0x90,
++    0xa8, 0x46, 0x14, 0x01, 0x39, 0x11, 0xe5, 0x3c, 0x41, 0x27,
++    0x32, 0x75, 0x24, 0xed, 0xa1, 0xd9, 0x12, 0x29, 0x8a, 0x28,
++    0x71, 0x89, 0x8d, 0xca, 0x30, 0xb0, 0x01, 0xc4, 0x2f, 0x82,
++    0x19, 0x14, 0x4c, 0x70, 0x1c, 0xb8, 0x23, 0x2e, 0xe8, 0x90,
++    0x49, 0x97, 0x92, 0x97, 0x6b, 0x7a, 0x9d, 0xb9, 0x02, 0x81,
++    0x80, 0x0f, 0x0e, 0xa1, 0x76, 0xf6, 0xa1, 0x44, 0x8f, 0xaf,
++    0x7c, 0x76, 0xd3, 0x87, 0xbb, 0xbb, 0x83, 0x10, 0x88, 0x01,
++    0x18, 0x14, 0xd1, 0xd3, 0x75, 0x59, 0x24, 0xaa, 0xf5, 0x16,
++    0xa5, 0xe9, 0x9d, 0xd1, 0xcc, 0xee, 0xf4, 0x15, 0xd9, 0xc5,
++    0x7e, 0x27, 0xe9, 0x44, 0x49, 0x06, 0x72, 0xb9, 0xfc, 0xd3,
++    0x8a, 0xc4, 0x2c, 0x36, 0x7d, 0x12, 0x9b, 0x5a, 0xaa, 0xdc,
++    0x85, 0xee, 0x6e, 0xad, 0x54, 0xb3, 0xf4, 0xfc, 0x31, 0xa1,
++    0x06, 0x3a, 0x70, 0x57, 0x0c, 0xf3, 0x95, 0x5b, 0x3e, 0xe8,
++    0xfd, 0x1a, 0x4f, 0xf6, 0x78, 0x93, 0x46, 0x6a, 0xd7, 0x31,
++    0xb4, 0x84, 0x64, 0x85, 0x09, 0x38, 0x89, 0x92, 0x94, 0x1c,
++    0xbf, 0xe2, 0x3c, 0x2a, 0xe0, 0xff, 0x99, 0xa3, 0xf0, 0x2b,
++    0x31, 0xc2, 0x36, 0xcd, 0x60, 0xbf, 0x9d, 0x2d, 0x74, 0x32,
++    0xe8, 0x9c, 0x93, 0x6e, 0xbb, 0x91, 0x7b, 0xfd, 0xd9, 0x02,
++    0x81, 0x81, 0x00, 0xa2, 0x71, 0x25, 0x38, 0xeb, 0x2a, 0xe9,
++    0x37, 0xcd, 0xfe, 0x44, 0xce, 0x90, 0x3f, 0x52, 0x87, 0x84,
++    0x52, 0x1b, 0xae, 0x8d, 0x22, 0x94, 0xce, 0x38, 0xe6, 0x04,
++    0x88, 0x76, 0x85, 0x9a, 0xd3, 0x14, 0x09, 0xe5, 0x69, 0x9a,
++    0xff, 0x58, 0x92, 0x02, 0x6a, 0x7d, 0x7c, 0x1e, 0x2c, 0xfd,
++    0xa8, 0xca, 0x32, 0x14, 0x4f, 0x0d, 0x84, 0x0d, 0x37, 0x43,
++    0xbf, 0xe4, 0x5d, 0x12, 0xc8, 0x24, 0x91, 0x27, 0x8d, 0x46,
++    0xd9, 0x54, 0x53, 0xe7, 0x62, 0x71, 0xa8, 0x2b, 0x71, 0x41,
++    0x8d, 0x75, 0xf8, 0x3a, 0xa0, 0x61, 0x29, 0x46, 0xa6, 0xe5,
++    0x82, 0xfa, 0x3a, 0xd9, 0x08, 0xfa, 0xfc, 0x63, 0xfd, 0x6b,
++    0x30, 0xbc, 0xf4, 0x4e, 0x9e, 0x8c, 0x25, 0x0c, 0xb6, 0x55,
++    0xe7, 0x3c, 0xd4, 0x4e, 0x0b, 0xfd, 0x8b, 0xc3, 0x0e, 0x1d,
++    0x9c, 0x44, 0x57, 0x8f, 0x1f, 0x86, 0xf7, 0xd5, 0x1b, 0xe4,
++    0x95,
++};
++
++static unsigned char test3072[] = {
++    0x30, 0x82, 0x06, 0xe3, 0x02, 0x01, 0x00, 0x02, 0x82, 0x01,
++    0x81, 0x00, 0xbc, 0x3b, 0x23, 0xc0, 0x33, 0xa7, 0x8b, 0xaa,
++    0xca, 0xa3, 0x8c, 0x94, 0xf2, 0x4c, 0x52, 0x08, 0x85, 0x80,
++    0xfc, 0x36, 0x15, 0xfa, 0x03, 0x06, 0xb6, 0xd6, 0x3f, 0x60,
++    0x8a, 0x89, 0x0d, 0xba, 0x1a, 0x51, 0x0b, 0x12, 0xea, 0x71,
++    0x77, 0xf6, 0x3a, 0x30, 0x21, 0x3d, 0x24, 0xf8, 0x2e, 0xd0,
++    0x17, 0x3a, 0x85, 0x94, 0x25, 0x42, 0x89, 0xff, 0x6a, 0x68,
++    0xdf, 0x1f, 0x86, 0xae, 0xa5, 0xbb, 0x9a, 0x79, 0xf6, 0x69,
++    0x94, 0xfe, 0xde, 0xfe, 0xce, 0x1b, 0x2e, 0xae, 0x1d, 0x91,
++    0xcb, 0xb9, 0xf1, 0x2d, 0xd8, 0x00, 0x82, 0x51, 0x8e, 0xf9,
++    0xfd, 0xac, 0xf1, 0x0e, 0x7f, 0xb7, 0x95, 0x85, 0x35, 0xf9,
++    0xcb, 0xbe, 0x5f, 0xd3, 0x58, 0xe3, 0xa1, 0x54, 0x9e, 0x30,
++    0xb1, 0x8d, 0x01, 0x97, 0x82, 0x06, 0x8e, 0x77, 0xfb, 0xce,
++    0x50, 0x2f, 0xbf, 0xf1, 0xff, 0x57, 0x0a, 0x42, 0x03, 0xfd,
++    0x0e, 0xba, 0x1e, 0xca, 0x85, 0xc1, 0x9b, 0xa5, 0x9d, 0x09,
++    0x0e, 0xe9, 0xbb, 0xc5, 0x73, 0x47, 0x0d, 0x39, 0x3c, 0x64,
++    0x06, 0x9a, 0x79, 0x3f, 0x50, 0x87, 0x9c, 0x18, 0x2d, 0x62,
++    0x01, 0xfc, 0xed, 0xc1, 0x58, 0x28, 0x21, 0x94, 0x1e, 0xf9,
++    0x2d, 0x96, 0x4f, 0xd0, 0xbc, 0xf1, 0xe0, 0x8a, 0xfa, 0x4d,
++    0xb6, 0x78, 0x4a, 0xde, 0x17, 0x59, 0xb0, 0x22, 0xa0, 0x9a,
++    0xd3, 0x70, 0xb6, 0xc2, 0xbe, 0xbc, 0x96, 0xca, 0x41, 0x5f,
++    0x58, 0x4e, 0xce, 0xef, 0x64, 0x45, 0xdd, 0x3f, 0x81, 0x92,
++    0xcc, 0x40, 0x79, 0xfc, 0x19, 0xe2, 0xbc, 0x77, 0x2f, 0x43,
++    0xfb, 0x8e, 0xad, 0x82, 0x4a, 0x0b, 0xb1, 0xbc, 0x09, 0x8a,
++    0x80, 0xc3, 0x0f, 0xef, 0xd2, 0x06, 0xd3, 0x4b, 0x0c, 0x7f,
++    0xae, 0x60, 0x3f, 0x2e, 0x52, 0xb4, 0xe4, 0xc2, 0x5c, 0xa6,
++    0x71, 0xc0, 0x13, 0x9c, 0xca, 0xa6, 0x0d, 0x13, 0xd7, 0xb7,
++    0x14, 0x94, 0x3f, 0x0d, 0x8b, 0x06, 0x70, 0x2f, 0x15, 0x82,
++    0x8d, 0x47, 0x45, 0xa6, 0x00, 0x8a, 0x14, 0x91, 0xde, 0x2f,
++    0x50, 0x17, 0xe3, 0x1d, 0x34, 0x29, 0x8c, 0xe4, 0x57, 0x74,
++    0x2a, 0x3a, 0x82, 0x65, 0x26, 0xf7, 0x8d, 0xcc, 0x1b, 0x8f,
++    0xaf, 0xe5, 0x85, 0xe5, 0xbe, 0x85, 0xd6, 0xb7, 0x04, 0xe8,
++    0xf5, 0xd4, 0x74, 0xe2, 0x54, 0x14, 0xdd, 0x58, 0xcf, 0x1f,
++    0x11, 0x8a, 0x9f, 0x82, 0xa2, 0x01, 0xf9, 0xc2, 0xdf, 0x7b,
++    0x84, 0xb1, 0xd8, 0x5b, 0x70, 0xbb, 0x24, 0xe7, 0xd0, 0x2a,
++    0x75, 0x3d, 0x55, 0xac, 0x45, 0xe9, 0xab, 0xc6, 0x84, 0x8a,
++    0xe7, 0x6d, 0x26, 0x12, 0x89, 0xb5, 0x67, 0xe8, 0x46, 0x9d,
++    0x46, 0x1a, 0xfa, 0x2d, 0xc0, 0x5b, 0x60, 0x46, 0x8b, 0xb7,
++    0x32, 0x03, 0xff, 0x75, 0xee, 0x9f, 0x3c, 0xdd, 0xb6, 0x35,
++    0x4e, 0x82, 0xbd, 0x99, 0x73, 0x51, 0x02, 0x03, 0x01, 0x00,
++    0x01, 0x02, 0x82, 0x01, 0x80, 0x42, 0xee, 0xa4, 0x9f, 0xcb,
++    0xbe, 0x60, 0x23, 0xb3, 0x3a, 0xc4, 0xda, 0x91, 0xee, 0x21,
++    0x9d, 0x76, 0x1b, 0x8f, 0x93, 0x8b, 0xed, 0x02, 0xf6, 0x78,
++    0x3d, 0x66, 0xfb, 0xe5, 0x47, 0x26, 0xe2, 0x6e, 0x49, 0x33,
++    0x2e, 0xde, 0xbe, 0xca, 0x71, 0x7b, 0xef, 0x71, 0x62, 0x54,
++    0xab, 0x0b, 0xba, 0x63, 0x08, 0x24, 0x47, 0xb1, 0x98, 0x1f,
++    0x89, 0xfb, 0x44, 0x9f, 0x52, 0x8e, 0x89, 0xbb, 0xd5, 0x21,
++    0xf1, 0x0c, 0x76, 0x2e, 0xcd, 0x12, 0x6e, 0x78, 0xcb, 0xa1,
++    0xa5, 0xb8, 0x4e, 0x07, 0xab, 0x6e, 0xdf, 0x66, 0x57, 0x87,
++    0xff, 0x88, 0x5f, 0xcc, 0x9c, 0x9a, 0x7b, 0x15, 0x5f, 0x2a,
++    0x83, 0xdb, 0xd5, 0x9f, 0x65, 0x6a, 0x9d, 0xb4, 0x95, 0xfc,
++    0xe0, 0x22, 0x00, 0x1e, 0xa2, 0x8d, 0x56, 0x5a, 0x9e, 0x0a,
++    0x3b, 0x10, 0x07, 0x24, 0xec, 0x55, 0xcc, 0xaf, 0x87, 0x3b,
++    0xd6, 0x8d, 0xa4, 0x86, 0x80, 0x18, 0x42, 0xdb, 0x9d, 0x24,
++    0xc3, 0x97, 0x3b, 0x89, 0x5a, 0x03, 0xb3, 0x0a, 0x72, 0xd1,
++    0x78, 0xf0, 0xc8, 0x80, 0xb0, 0x9d, 0x3c, 0xae, 0x5e, 0x0a,
++    0x5b, 0x6e, 0x87, 0xd3, 0x3d, 0x25, 0x2e, 0x03, 0x33, 0x01,
++    0xfd, 0xb1, 0xa5, 0xd9, 0x58, 0x01, 0xb9, 0xaf, 0xf6, 0x32,
++    0x6a, 0x38, 0xe7, 0x39, 0x63, 0x3c, 0xfc, 0x0c, 0x41, 0x90,
++    0x28, 0x40, 0x03, 0xcd, 0xfb, 0xde, 0x80, 0x74, 0x21, 0xaa,
++    0xae, 0x58, 0xe9, 0x97, 0x18, 0x85, 0x58, 0x3d, 0x2b, 0xd6,
++    0x61, 0xf6, 0xe8, 0xbc, 0x6d, 0x2a, 0xf3, 0xb8, 0xea, 0x8c,
++    0x64, 0x44, 0xc6, 0xd3, 0x9f, 0x00, 0x7b, 0xb2, 0x52, 0x18,
++    0x11, 0x04, 0x96, 0xb7, 0x05, 0xbb, 0xc2, 0x38, 0x5b, 0xa7,
++    0x0a, 0x84, 0xb6, 0x4f, 0x02, 0x63, 0xa4, 0x57, 0x00, 0xe3,
++    0xde, 0xe4, 0xf2, 0xb3, 0x55, 0xd9, 0x00, 0xa9, 0xd2, 0x5c,
++    0x69, 0x9f, 0xe5, 0x80, 0x4f, 0x23, 0x7c, 0xd9, 0xa7, 0x77,
++    0x4a, 0xbb, 0x09, 0x6d, 0x45, 0x02, 0xcf, 0x32, 0x90, 0xfd,
++    0x10, 0xb6, 0xb3, 0x93, 0xd9, 0x3b, 0x1d, 0x57, 0x66, 0xb5,
++    0xb3, 0xb1, 0x6e, 0x53, 0x5f, 0x04, 0x60, 0x29, 0xcd, 0xe8,
++    0xb8, 0xab, 0x62, 0x82, 0x33, 0x40, 0xc7, 0xf8, 0x64, 0x60,
++    0x0e, 0xab, 0x06, 0x3e, 0xa0, 0xa3, 0x62, 0x11, 0x3f, 0x67,
++    0x5d, 0x24, 0x9e, 0x60, 0x29, 0xdc, 0x4c, 0xd5, 0x13, 0xee,
++    0x3d, 0xb7, 0x84, 0x93, 0x27, 0xb5, 0x6a, 0xf9, 0xf0, 0xdd,
++    0x50, 0xac, 0x46, 0x3c, 0xe6, 0xd5, 0xec, 0xf7, 0xb7, 0x9f,
++    0x23, 0x39, 0x9c, 0x88, 0x8c, 0x5a, 0x62, 0x3f, 0x8d, 0x4a,
++    0xd7, 0xeb, 0x5e, 0x1e, 0x49, 0xf8, 0xa9, 0x53, 0x11, 0x75,
++    0xd0, 0x43, 0x1e, 0xc7, 0x29, 0x22, 0x80, 0x1f, 0xc5, 0x83,
++    0x8d, 0x20, 0x04, 0x87, 0x7f, 0x57, 0x8c, 0xf5, 0xa1, 0x02,
++    0x81, 0xc1, 0x00, 0xf7, 0xaa, 0xf5, 0xa5, 0x00, 0xdb, 0xd6,
++    0x11, 0xfc, 0x07, 0x6d, 0x22, 0x24, 0x2b, 0x4b, 0xc5, 0x67,
++    0x0f, 0x37, 0xa5, 0xdb, 0x8f, 0x38, 0xe2, 0x05, 0x43, 0x9a,
++    0x44, 0x05, 0x3f, 0xa9, 0xac, 0x4c, 0x98, 0x3c, 0x72, 0x38,
++    0xc3, 0x89, 0x33, 0x58, 0x73, 0x51, 0xcc, 0x5d, 0x2f, 0x8f,
++    0x6d, 0x3f, 0xa1, 0x22, 0x9e, 0xfb, 0x9a, 0xb4, 0xb8, 0x79,
++    0x95, 0xaf, 0x83, 0xcf, 0x5a, 0xb7, 0x14, 0x14, 0x0c, 0x51,
++    0x8a, 0x11, 0xe6, 0xd6, 0x21, 0x1e, 0x17, 0x13, 0xd3, 0x69,
++    0x7a, 0x3a, 0xd5, 0xaf, 0x3f, 0xb8, 0x25, 0x01, 0xcb, 0x2b,
++    0xe6, 0xfc, 0x03, 0xd8, 0xd4, 0xf7, 0x20, 0xe0, 0x21, 0xef,
++    0x1a, 0xca, 0x61, 0xeb, 0x8e, 0x96, 0x45, 0x8e, 0x5c, 0xe6,
++    0x81, 0x0b, 0x2d, 0x05, 0x32, 0xf9, 0x41, 0x62, 0xb4, 0x33,
++    0x98, 0x10, 0x3a, 0xcd, 0xf0, 0x7a, 0x8b, 0x1a, 0x48, 0xd7,
++    0x3b, 0x01, 0xf5, 0x18, 0x65, 0x8f, 0x3c, 0xc2, 0x31, 0x3b,
++    0xd3, 0xa7, 0x17, 0x5f, 0x7c, 0x0c, 0xe7, 0x25, 0x18, 0x5a,
++    0x08, 0xe1, 0x09, 0x89, 0x13, 0xa7, 0xc5, 0x12, 0xab, 0x88,
++    0x30, 0xcd, 0x06, 0xf9, 0xba, 0x6f, 0xca, 0x9c, 0x8a, 0xda,
++    0x3e, 0x53, 0x90, 0xd7, 0x16, 0x2e, 0xfc, 0xbc, 0xad, 0xd6,
++    0x3d, 0xc0, 0x66, 0x4c, 0x02, 0x3d, 0x31, 0xfd, 0x6c, 0xdb,
++    0x1c, 0xdf, 0x96, 0x33, 0x23, 0x02, 0x81, 0xc1, 0x00, 0xc2,
++    0x90, 0x47, 0xc4, 0xfb, 0x59, 0xf0, 0xc5, 0x14, 0x75, 0x29,
++    0xfa, 0x77, 0xa1, 0x8d, 0xd4, 0x90, 0xa1, 0x0d, 0x3f, 0x16,
++    0x88, 0xe3, 0x4c, 0x8f, 0x8f, 0x18, 0x8c, 0x9c, 0x8a, 0xd5,
++    0xa7, 0x41, 0x99, 0xf3, 0x80, 0x8e, 0xb1, 0xb8, 0x63, 0xd8,
++    0x3f, 0x95, 0xd0, 0xd0, 0x2b, 0xf5, 0xe6, 0x93, 0xe8, 0xfe,
++    0xd0, 0x73, 0xd5, 0xbd, 0xb4, 0xee, 0x51, 0x19, 0x6a, 0x10,
++    0xca, 0xc8, 0xba, 0xa4, 0x4d, 0x84, 0x54, 0x38, 0x17, 0xb5,
++    0xd0, 0xa8, 0x75, 0x22, 0xc5, 0x1b, 0x61, 0xa6, 0x51, 0x88,
++    0x63, 0xf0, 0x4f, 0xd1, 0x88, 0xd9, 0x16, 0x49, 0x30, 0xe1,
++    0xa8, 0x47, 0xc9, 0x30, 0x1d, 0x5c, 0x75, 0xd8, 0x89, 0xb6,
++    0x1d, 0x45, 0xd8, 0x0f, 0x94, 0x89, 0xb3, 0xe4, 0x51, 0xfa,
++    0x21, 0xff, 0x6f, 0xb6, 0x30, 0x6f, 0x33, 0x24, 0xbc, 0x09,
++    0x98, 0xe9, 0x20, 0x02, 0x0b, 0xde, 0xff, 0xc5, 0x06, 0xb6,
++    0x28, 0xa3, 0xa1, 0x07, 0xe8, 0xe1, 0xd2, 0xc2, 0xf1, 0xd1,
++    0x23, 0x6b, 0x4c, 0x3a, 0xae, 0x85, 0xec, 0xf9, 0xff, 0xa7,
++    0x9b, 0x25, 0xb8, 0x95, 0x1d, 0xa8, 0x14, 0x81, 0x4f, 0x79,
++    0x4f, 0xd6, 0x39, 0x5d, 0xe6, 0x5f, 0xd2, 0x34, 0x54, 0x8b,
++    0x1e, 0x40, 0x4c, 0x15, 0x5a, 0x45, 0xce, 0x0c, 0xb0, 0xdf,
++    0xa1, 0x17, 0xb8, 0xb0, 0x6a, 0x82, 0xa5, 0x97, 0x92, 0x70,
++    0xfb, 0x02, 0x81, 0xc0, 0x77, 0x46, 0x44, 0x2b, 0x04, 0xf0,
++    0xda, 0x75, 0xaa, 0xd4, 0xc0, 0xc0, 0x32, 0x7f, 0x0f, 0x6c,
++    0xb0, 0x27, 0x69, 0xfb, 0x5c, 0x73, 0xeb, 0x47, 0x1e, 0x95,
++    0xe2, 0x13, 0x64, 0x1b, 0xb6, 0xd1, 0x1d, 0xca, 0x2b, 0x42,
++    0x2f, 0x08, 0x2c, 0x69, 0x27, 0xed, 0xd1, 0xb5, 0x04, 0x23,
++    0xc5, 0x85, 0x2d, 0xa1, 0xa2, 0x94, 0xc2, 0x43, 0x4d, 0x49,
++    0x92, 0x74, 0x7e, 0x24, 0x92, 0x95, 0xf3, 0x99, 0x9d, 0xd6,
++    0x18, 0xe6, 0xcf, 0x9c, 0x45, 0xff, 0x89, 0x08, 0x40, 0x2a,
++    0x0e, 0xa0, 0x28, 0xf9, 0x83, 0xfe, 0xc1, 0xe6, 0x40, 0xa8,
++    0xe2, 0x29, 0xc9, 0xb0, 0xe8, 0x9a, 0x17, 0xb2, 0x23, 0x7e,
++    0xf4, 0x32, 0x08, 0xc9, 0x83, 0xb2, 0x15, 0xb8, 0xc5, 0xc9,
++    0x03, 0xd1, 0x9d, 0xda, 0x3e, 0xa8, 0xbf, 0xd5, 0xb7, 0x7d,
++    0x65, 0x63, 0x94, 0x5d, 0x5d, 0x94, 0xb4, 0xcf, 0x8d, 0x07,
++    0x0b, 0x70, 0x85, 0x8e, 0xce, 0x03, 0x0b, 0x2a, 0x8d, 0xb3,
++    0x3c, 0x46, 0xc0, 0x2f, 0xc7, 0x72, 0x6c, 0x9c, 0x5d, 0x07,
++    0x0f, 0x45, 0x3b, 0x6b, 0x66, 0x32, 0xab, 0x17, 0x83, 0xd8,
++    0x4c, 0x2c, 0x84, 0x71, 0x19, 0x8f, 0xaa, 0x0a, 0xff, 0xbc,
++    0xf7, 0x42, 0x10, 0xe8, 0xae, 0x4d, 0x26, 0xaf, 0xdd, 0x06,
++    0x33, 0x29, 0x66, 0x21, 0x5d, 0xf5, 0xae, 0x17, 0x07, 0x1f,
++    0x87, 0x9e, 0xae, 0x27, 0x1d, 0xd5, 0x02, 0x81, 0xc0, 0x56,
++    0x17, 0x4f, 0x9a, 0x8a, 0xf9, 0xde, 0x3e, 0xe6, 0x71, 0x7d,
++    0x94, 0xb5, 0xb0, 0xc7, 0xb8, 0x62, 0x12, 0xd1, 0x70, 0xb4,
++    0x00, 0xf8, 0x4a, 0xdd, 0x4f, 0x1d, 0x36, 0xc2, 0xe1, 0xef,
++    0xee, 0x25, 0x6a, 0x00, 0xc4, 0x46, 0xdf, 0xbe, 0xce, 0x77,
++    0x56, 0x93, 0x6d, 0x25, 0x5f, 0xfe, 0x5b, 0xfb, 0xe0, 0xe2,
++    0x37, 0xcc, 0xb9, 0xac, 0x4a, 0xce, 0x15, 0x16, 0xa0, 0xc7,
++    0x33, 0x63, 0xa4, 0xaa, 0xa5, 0x1e, 0x43, 0xc1, 0xda, 0x43,
++    0xfa, 0x43, 0x40, 0x29, 0x95, 0x7c, 0x2b, 0x36, 0x53, 0xe7,
++    0x7d, 0x09, 0x4d, 0xd8, 0x52, 0xac, 0x74, 0x5f, 0x08, 0x81,
++    0x21, 0x5c, 0x3a, 0x5a, 0xce, 0xf3, 0x25, 0xb6, 0x1e, 0x21,
++    0x76, 0x4c, 0x7c, 0x71, 0x50, 0x71, 0xaa, 0x27, 0x02, 0x5b,
++    0x23, 0x06, 0x0b, 0x21, 0x5b, 0xc7, 0x28, 0xa3, 0x3d, 0x8d,
++    0x25, 0x9b, 0x2a, 0x2d, 0x9d, 0xa1, 0x1c, 0x1d, 0xcb, 0x7d,
++    0x78, 0xf8, 0x06, 0x7e, 0x20, 0x7f, 0x24, 0x2a, 0x5c, 0xa4,
++    0x04, 0xff, 0x2a, 0x68, 0xe0, 0xe6, 0xa3, 0xd8, 0x6f, 0x56,
++    0x73, 0xa1, 0x3a, 0x4e, 0xc9, 0x23, 0xa1, 0x87, 0x22, 0x6a,
++    0x74, 0x78, 0x3f, 0x44, 0x1c, 0x77, 0x13, 0xe5, 0x51, 0xef,
++    0x89, 0x00, 0x3c, 0x6a, 0x4a, 0x5a, 0x8e, 0xf5, 0x30, 0xa2,
++    0x93, 0x7e, 0x92, 0x9b, 0x85, 0x55, 0xaf, 0xfe, 0x24, 0xaf,
++    0x57, 0x02, 0x81, 0xc1, 0x00, 0xa4, 0xc2, 0x6a, 0x59, 0x45,
++    0xea, 0x71, 0x7d, 0x4c, 0xaf, 0xaf, 0xd6, 0x55, 0x97, 0x73,
++    0xc5, 0xa1, 0x3c, 0xf6, 0x59, 0x23, 0xb6, 0x1f, 0x5e, 0x9c,
++    0x96, 0x0f, 0x97, 0x66, 0x82, 0x91, 0x48, 0x36, 0x70, 0x02,
++    0x67, 0xde, 0x34, 0xa6, 0x95, 0x7b, 0x51, 0x43, 0x66, 0xa4,
++    0x16, 0x45, 0x59, 0x12, 0xdb, 0x35, 0x19, 0x4b, 0xbf, 0x1d,
++    0xab, 0xf3, 0x3f, 0xb4, 0xb4, 0x6f, 0x66, 0xb0, 0x67, 0xc6,
++    0x77, 0x2c, 0x46, 0xa8, 0x03, 0x64, 0x9a, 0x13, 0x9d, 0x40,
++    0x22, 0x56, 0x76, 0x1a, 0x7c, 0x1e, 0xe2, 0xda, 0x7f, 0x09,
++    0xcf, 0x10, 0xe3, 0xf2, 0xf4, 0x2a, 0x3b, 0x46, 0xc7, 0x61,
++    0x9b, 0xef, 0x4a, 0x18, 0x60, 0x8c, 0x32, 0x71, 0xb9, 0xdd,
++    0xac, 0xa0, 0xc6, 0x8d, 0x3f, 0xab, 0xc3, 0x21, 0x2c, 0xeb,
++    0x91, 0x8f, 0xc7, 0x43, 0x0d, 0x0c, 0x67, 0x9e, 0xab, 0xe6,
++    0x8d, 0xb6, 0x2d, 0x41, 0xca, 0x43, 0xd8, 0xcb, 0x30, 0xfb,
++    0x3b, 0x40, 0x0d, 0x10, 0x9b, 0xb1, 0x55, 0x93, 0x73, 0x8b,
++    0x60, 0xef, 0xc0, 0xee, 0xc0, 0xa6, 0x7a, 0x79, 0x90, 0xfd,
++    0x4c, 0x25, 0xd4, 0x4f, 0x67, 0xbe, 0xf7, 0x86, 0x3c, 0x5d,
++    0x2b, 0x7d, 0x97, 0x3d, 0xa2, 0x91, 0xa5, 0x06, 0x69, 0xf6,
++    0x7a, 0xb8, 0x77, 0xe6, 0x70, 0xa9, 0xd8, 0x86, 0x4b, 0xa6,
++    0xcf, 0x67, 0x1d, 0x33, 0xcf, 0xfe, 0x3e
++};
++
++static unsigned char test4096[] = {
++    0x30, 0x82, 0x09, 0x29, 0x02, 0x01, 0x00, 0x02, 0x82, 0x02,
++    0x01, 0x00, 0xc0, 0x71, 0xac, 0x1a, 0x13, 0x88, 0x82, 0x43,
++    0x3b, 0x51, 0x57, 0x71, 0x8d, 0xb6, 0x2b, 0x82, 0x65, 0x21,
++    0x53, 0x5f, 0x28, 0x29, 0x4f, 0x8d, 0x7c, 0x8a, 0xb9, 0x44,
++    0xb3, 0x28, 0x41, 0x4f, 0xd3, 0xfa, 0x6a, 0xf8, 0xb9, 0x28,
++    0x50, 0x39, 0x67, 0x53, 0x2c, 0x3c, 0xd7, 0xcb, 0x96, 0x41,
++    0x40, 0x32, 0xbb, 0xeb, 0x70, 0xae, 0x1f, 0xb0, 0x65, 0xf7,
++    0x3a, 0xd9, 0x22, 0xfd, 0x10, 0xae, 0xbd, 0x02, 0xe2, 0xdd,
++    0xf3, 0xc2, 0x79, 0x3c, 0xc6, 0xfc, 0x75, 0xbb, 0xaf, 0x4e,
++    0x3a, 0x36, 0xc2, 0x4f, 0xea, 0x25, 0xdf, 0x13, 0x16, 0x4b,
++    0x20, 0xfe, 0x4b, 0x69, 0x16, 0xc4, 0x7f, 0x1a, 0x43, 0xa6,
++    0x17, 0x1b, 0xb9, 0x0a, 0xf3, 0x09, 0x86, 0x28, 0x89, 0xcf,
++    0x2c, 0xd0, 0xd4, 0x81, 0xaf, 0xc6, 0x6d, 0xe6, 0x21, 0x8d,
++    0xee, 0xef, 0xea, 0xdc, 0xb7, 0xc6, 0x3b, 0x63, 0x9f, 0x0e,
++    0xad, 0x89, 0x78, 0x23, 0x18, 0xbf, 0x70, 0x7e, 0x84, 0xe0,
++    0x37, 0xec, 0xdb, 0x8e, 0x9c, 0x3e, 0x6a, 0x19, 0xcc, 0x99,
++    0x72, 0xe6, 0xb5, 0x7d, 0x6d, 0xfa, 0xe5, 0xd3, 0xe4, 0x90,
++    0xb5, 0xb2, 0xb2, 0x12, 0x70, 0x4e, 0xca, 0xf8, 0x10, 0xf8,
++    0xa3, 0x14, 0xc2, 0x48, 0x19, 0xeb, 0x60, 0x99, 0xbb, 0x2a,
++    0x1f, 0xb1, 0x7a, 0xb1, 0x3d, 0x24, 0xfb, 0xa0, 0x29, 0xda,
++    0xbd, 0x1b, 0xd7, 0xa4, 0xbf, 0xef, 0x60, 0x2d, 0x22, 0xca,
++    0x65, 0x98, 0xf1, 0xc4, 0xe1, 0xc9, 0x02, 0x6b, 0x16, 0x28,
++    0x2f, 0xa1, 0xaa, 0x79, 0x00, 0xda, 0xdc, 0x7c, 0x43, 0xf7,
++    0x42, 0x3c, 0xa0, 0xef, 0x68, 0xf7, 0xdf, 0xb9, 0x69, 0xfb,
++    0x8e, 0x01, 0xed, 0x01, 0x42, 0xb5, 0x4e, 0x57, 0xa6, 0x26,
++    0xb8, 0xd0, 0x7b, 0x56, 0x6d, 0x03, 0xc6, 0x40, 0x8c, 0x8c,
++    0x2a, 0x55, 0xd7, 0x9c, 0x35, 0x00, 0x94, 0x93, 0xec, 0x03,
++    0xeb, 0x22, 0xef, 0x77, 0xbb, 0x79, 0x13, 0x3f, 0x15, 0xa1,
++    0x8f, 0xca, 0xdf, 0xfd, 0xd3, 0xb8, 0xe1, 0xd4, 0xcc, 0x09,
++    0x3f, 0x3c, 0x2c, 0xdb, 0xd1, 0x49, 0x7f, 0x38, 0x07, 0x83,
++    0x6d, 0xeb, 0x08, 0x66, 0xe9, 0x06, 0x44, 0x12, 0xac, 0x95,
++    0x22, 0x90, 0x23, 0x67, 0xd4, 0x08, 0xcc, 0xf4, 0xb7, 0xdc,
++    0xcc, 0x87, 0xd4, 0xac, 0x69, 0x35, 0x4c, 0xb5, 0x39, 0x36,
++    0xcd, 0xa4, 0xd2, 0x95, 0xca, 0x0d, 0xc5, 0xda, 0xc2, 0xc5,
++    0x22, 0x32, 0x28, 0x08, 0xe3, 0xd2, 0x8b, 0x38, 0x30, 0xdc,
++    0x8c, 0x75, 0x4f, 0x6a, 0xec, 0x7a, 0xac, 0x16, 0x3e, 0xa8,
++    0xd4, 0x6a, 0x45, 0xe1, 0xa8, 0x4f, 0x2e, 0x80, 0x34, 0xaa,
++    0x54, 0x1b, 0x02, 0x95, 0x7d, 0x8a, 0x6d, 0xcc, 0x79, 0xca,
++    0xf2, 0xa4, 0x2e, 0x8d, 0xfb, 0xfe, 0x15, 0x51, 0x10, 0x0e,
++    0x4d, 0x88, 0xb1, 0xc7, 0xf4, 0x79, 0xdb, 0xf0, 0xb4, 0x56,
++    0x44, 0x37, 0xca, 0x5a, 0xc1, 0x8c, 0x48, 0xac, 0xae, 0x48,
++    0x80, 0x83, 0x01, 0x3f, 0xde, 0xd9, 0xd3, 0x2c, 0x51, 0x46,
++    0xb1, 0x41, 0xb6, 0xc6, 0x91, 0x72, 0xf9, 0x83, 0x55, 0x1b,
++    0x8c, 0xba, 0xf3, 0x73, 0xe5, 0x2c, 0x74, 0x50, 0x3a, 0xbe,
++    0xc5, 0x2f, 0xa7, 0xb2, 0x6d, 0x8c, 0x9e, 0x13, 0x77, 0xa3,
++    0x13, 0xcd, 0x6d, 0x8c, 0x45, 0xe1, 0xfc, 0x0b, 0xb7, 0x69,
++    0xe9, 0x27, 0xbc, 0x65, 0xc3, 0xfa, 0x9b, 0xd0, 0xef, 0xfe,
++    0xe8, 0x1f, 0xb3, 0x5e, 0x34, 0xf4, 0x8c, 0xea, 0xfc, 0xd3,
++    0x81, 0xbf, 0x3d, 0x30, 0xb2, 0xb4, 0x01, 0xe8, 0x43, 0x0f,
++    0xba, 0x02, 0x23, 0x42, 0x76, 0x82, 0x31, 0x73, 0x91, 0xed,
++    0x07, 0x46, 0x61, 0x0d, 0x39, 0x83, 0x40, 0xce, 0x7a, 0xd4,
++    0xdb, 0x80, 0x2c, 0x1f, 0x0d, 0xd1, 0x34, 0xd4, 0x92, 0xe3,
++    0xd4, 0xf1, 0xc2, 0x01, 0x02, 0x03, 0x01, 0x00, 0x01, 0x02,
++    0x82, 0x02, 0x01, 0x00, 0x97, 0x6c, 0xda, 0x6e, 0xea, 0x4f,
++    0xcf, 0xaf, 0xf7, 0x4c, 0xd9, 0xf1, 0x90, 0x00, 0x77, 0xdb,
++    0xf2, 0x97, 0x76, 0x72, 0xb9, 0xb7, 0x47, 0xd1, 0x9c, 0xdd,
++    0xcb, 0x4a, 0x33, 0x6e, 0xc9, 0x75, 0x76, 0xe6, 0xe4, 0xa5,
++    0x31, 0x8c, 0x77, 0x13, 0xb4, 0x29, 0xcd, 0xf5, 0x52, 0x17,
++    0xef, 0xf3, 0x08, 0x00, 0xe3, 0xbd, 0x2e, 0xbc, 0xd4, 0x52,
++    0x88, 0xe9, 0x30, 0x75, 0x0b, 0x02, 0xf5, 0xcd, 0x89, 0x0c,
++    0x6c, 0x57, 0x19, 0x27, 0x3d, 0x1e, 0x85, 0xb4, 0xc1, 0x2f,
++    0x1d, 0x92, 0x00, 0x5c, 0x76, 0x29, 0x4b, 0xa4, 0xe1, 0x12,
++    0xb3, 0xc8, 0x09, 0xfe, 0x0e, 0x78, 0x72, 0x61, 0xcb, 0x61,
++    0x6f, 0x39, 0x91, 0x95, 0x4e, 0xd5, 0x3e, 0xc7, 0x8f, 0xb8,
++    0xf6, 0x36, 0xfe, 0x9c, 0x93, 0x9a, 0x38, 0x25, 0x7a, 0xf4,
++    0x4a, 0x12, 0xd4, 0xa0, 0x13, 0xbd, 0xf9, 0x1d, 0x12, 0x3e,
++    0x21, 0x39, 0xfb, 0x72, 0xe0, 0x05, 0x3d, 0xc3, 0xe5, 0x50,
++    0xa8, 0x5d, 0x85, 0xa3, 0xea, 0x5f, 0x1c, 0xb2, 0x3f, 0xea,
++    0x6d, 0x03, 0x91, 0x55, 0xd8, 0x19, 0x0a, 0x21, 0x12, 0x16,
++    0xd9, 0x12, 0xc4, 0xe6, 0x07, 0x18, 0x5b, 0x26, 0xa4, 0xae,
++    0xed, 0x2b, 0xb7, 0xa6, 0xed, 0xf8, 0xad, 0xec, 0x77, 0xe6,
++    0x7f, 0x4f, 0x76, 0x00, 0xc0, 0xfa, 0x15, 0x92, 0xb4, 0x2c,
++    0x22, 0xc2, 0xeb, 0x6a, 0xad, 0x14, 0x05, 0xb2, 0xe5, 0x8a,
++    0x9e, 0x85, 0x83, 0xcc, 0x04, 0xf1, 0x56, 0x78, 0x44, 0x5e,
++    0xde, 0xe0, 0x60, 0x1a, 0x65, 0x79, 0x31, 0x23, 0x05, 0xbb,
++    0x01, 0xff, 0xdd, 0x2e, 0xb7, 0xb3, 0xaa, 0x74, 0xe0, 0xa5,
++    0x94, 0xaf, 0x4b, 0xde, 0x58, 0x0f, 0x55, 0xde, 0x33, 0xf6,
++    0xe3, 0xd6, 0x34, 0x36, 0x57, 0xd6, 0x79, 0x91, 0x2e, 0xbe,
++    0x3b, 0xd9, 0x4e, 0xb6, 0x9d, 0x21, 0x5c, 0xd3, 0x48, 0x14,
++    0x7f, 0x4a, 0xc4, 0x60, 0xa9, 0x29, 0xf8, 0x53, 0x7f, 0x88,
++    0x11, 0x2d, 0xb5, 0xc5, 0x2d, 0x6f, 0xee, 0x85, 0x0b, 0xf7,
++    0x8d, 0x9a, 0xbe, 0xb0, 0x42, 0xf2, 0x2e, 0x71, 0xaf, 0x19,
++    0x31, 0x6d, 0xec, 0xcd, 0x6f, 0x2b, 0x23, 0xdf, 0xb4, 0x40,
++    0xaf, 0x2c, 0x0a, 0xc3, 0x1b, 0x7d, 0x7d, 0x03, 0x1d, 0x4b,
++    0xf3, 0xb5, 0xe0, 0x85, 0xd8, 0xdf, 0x91, 0x6b, 0x0a, 0x69,
++    0xf7, 0xf2, 0x69, 0x66, 0x5b, 0xf1, 0xcf, 0x46, 0x7d, 0xe9,
++    0x70, 0xfa, 0x6d, 0x7e, 0x75, 0x4e, 0xa9, 0x77, 0xe6, 0x8c,
++    0x02, 0xf7, 0x14, 0x4d, 0xa5, 0x41, 0x8f, 0x3f, 0xc1, 0x62,
++    0x1e, 0x71, 0x5e, 0x38, 0xb4, 0xd6, 0xe6, 0xe1, 0x4b, 0xc2,
++    0x2c, 0x30, 0x83, 0x81, 0x6f, 0x49, 0x2e, 0x96, 0xe6, 0xc9,
++    0x9a, 0xf7, 0x5d, 0x09, 0xa0, 0x55, 0x02, 0xa5, 0x3a, 0x25,
++    0x23, 0xd0, 0x92, 0xc3, 0xa3, 0xe3, 0x0e, 0x12, 0x2f, 0x4d,
++    0xef, 0xf3, 0x55, 0x5a, 0xbe, 0xe6, 0x19, 0x86, 0x31, 0xab,
++    0x75, 0x9a, 0xd3, 0xf0, 0x2c, 0xc5, 0x41, 0x92, 0xd9, 0x1f,
++    0x5f, 0x11, 0x8c, 0x75, 0x1c, 0x63, 0xd0, 0x02, 0x80, 0x2c,
++    0x68, 0xcb, 0x93, 0xfb, 0x51, 0x73, 0x49, 0xb4, 0x60, 0xda,
++    0xe2, 0x26, 0xaf, 0xa9, 0x46, 0x12, 0xb8, 0xec, 0x50, 0xdd,
++    0x12, 0x06, 0x5f, 0xce, 0x59, 0xe6, 0xf6, 0x1c, 0xe0, 0x54,
++    0x10, 0xad, 0xf6, 0xcd, 0x98, 0xcc, 0x0f, 0xfb, 0xcb, 0x41,
++    0x14, 0x9d, 0xed, 0xe4, 0xb4, 0x74, 0x5f, 0x09, 0x60, 0xc7,
++    0x12, 0xf6, 0x7b, 0x3c, 0x8f, 0xa7, 0x20, 0xbc, 0xe4, 0xb1,
++    0xef, 0xeb, 0xa4, 0x93, 0xc5, 0x06, 0xca, 0x9a, 0x27, 0x9d,
++    0x87, 0xf3, 0xde, 0xca, 0xe5, 0xe7, 0xf6, 0x1c, 0x01, 0x65,
++    0x5b, 0xfb, 0x19, 0x79, 0x6e, 0x08, 0x26, 0xc5, 0xc8, 0x28,
++    0x0e, 0xb6, 0x3b, 0x07, 0x08, 0xc1, 0x02, 0x82, 0x01, 0x01,
++    0x00, 0xe8, 0x1c, 0x73, 0xa6, 0xb8, 0xe0, 0x0e, 0x6d, 0x8d,
++    0x1b, 0xb9, 0x53, 0xed, 0x58, 0x94, 0xe6, 0x1d, 0x60, 0x14,
++    0x5c, 0x76, 0x43, 0xc4, 0x58, 0x19, 0xc4, 0x24, 0xe8, 0xbc,
++    0x1b, 0x3b, 0x0b, 0x13, 0x24, 0x45, 0x54, 0x0e, 0xcc, 0x37,
++    0xf0, 0xe0, 0x63, 0x7d, 0xc3, 0xf7, 0xfb, 0x81, 0x74, 0x81,
++    0xc4, 0x0f, 0x1a, 0x21, 0x48, 0xaf, 0xce, 0xc1, 0xc4, 0x94,
++    0x18, 0x06, 0x44, 0x8d, 0xd3, 0xd2, 0x22, 0x2d, 0x2d, 0x3e,
++    0x5a, 0x31, 0xdc, 0x95, 0x8e, 0xf4, 0x41, 0xfc, 0x58, 0xc9,
++    0x40, 0x92, 0x17, 0x5f, 0xe3, 0xda, 0xac, 0x9e, 0x3f, 0x1c,
++    0x2a, 0x6b, 0x58, 0x5f, 0x48, 0x78, 0x20, 0xb1, 0xaf, 0x24,
++    0x9b, 0x3c, 0x20, 0x8b, 0x93, 0x25, 0x9e, 0xe6, 0x6b, 0xbc,
++    0x13, 0x42, 0x14, 0x6c, 0x36, 0x31, 0xff, 0x7a, 0xd1, 0xc1,
++    0x1a, 0x26, 0x14, 0x7f, 0xa9, 0x76, 0xa7, 0x0c, 0xf8, 0xcc,
++    0xed, 0x07, 0x6a, 0xd2, 0xdf, 0x62, 0xee, 0x0a, 0x7c, 0x84,
++    0xcb, 0x49, 0x90, 0xb2, 0x03, 0x0d, 0xa2, 0x82, 0x06, 0x77,
++    0xf1, 0xcd, 0x67, 0xf2, 0x47, 0x21, 0x02, 0x3f, 0x43, 0x21,
++    0xf0, 0x46, 0x30, 0x62, 0x51, 0x72, 0xb1, 0xe7, 0x48, 0xc6,
++    0x67, 0x12, 0xcd, 0x9e, 0xd6, 0x15, 0xe5, 0x21, 0xed, 0xfa,
++    0x8f, 0x30, 0xa6, 0x41, 0xfe, 0xb6, 0xfa, 0x8f, 0x34, 0x14,
++    0x19, 0xe8, 0x11, 0xf7, 0xa5, 0x77, 0x3e, 0xb7, 0xf9, 0x39,
++    0x07, 0x8c, 0x67, 0x2a, 0xab, 0x7b, 0x08, 0xf8, 0xb0, 0x06,
++    0xa8, 0xea, 0x2f, 0x8f, 0xfa, 0xcc, 0xcc, 0x40, 0xce, 0xf3,
++    0x70, 0x4f, 0x3f, 0x7f, 0xe2, 0x0c, 0xea, 0x76, 0x4a, 0x35,
++    0x4e, 0x47, 0xad, 0x2b, 0xa7, 0x97, 0x5d, 0x74, 0x43, 0x97,
++    0x90, 0xd2, 0xfb, 0xd9, 0xf9, 0x96, 0x01, 0x33, 0x05, 0xed,
++    0x7b, 0x03, 0x05, 0xad, 0xf8, 0x49, 0x03, 0x02, 0x82, 0x01,
++    0x01, 0x00, 0xd4, 0x40, 0x17, 0x66, 0x10, 0x92, 0x95, 0xc8,
++    0xec, 0x62, 0xa9, 0x7a, 0xcb, 0x93, 0x8e, 0xe6, 0x53, 0xd4,
++    0x80, 0x48, 0x27, 0x4b, 0x41, 0xce, 0x61, 0xdf, 0xbf, 0x94,
++    0xa4, 0x3d, 0x71, 0x03, 0x0b, 0xed, 0x25, 0x71, 0x98, 0xa4,
++    0xd6, 0xd5, 0x4a, 0x57, 0xf5, 0x6c, 0x1b, 0xda, 0x21, 0x7d,
++    0x35, 0x45, 0xb3, 0xf3, 0x6a, 0xd9, 0xd3, 0x43, 0xe8, 0x5c,
++    0x54, 0x1c, 0x83, 0x1b, 0xb4, 0x5f, 0xf2, 0x97, 0x24, 0x2e,
++    0xdc, 0x40, 0xde, 0x92, 0x23, 0x59, 0x8e, 0xbc, 0xd2, 0xa1,
++    0xf2, 0xe0, 0x4c, 0xdd, 0x0b, 0xd1, 0xe7, 0xae, 0x65, 0xbc,
++    0xb5, 0xf5, 0x5b, 0x98, 0xe9, 0xd7, 0xc2, 0xb7, 0x0e, 0x55,
++    0x71, 0x0e, 0x3c, 0x0a, 0x24, 0x6b, 0xa6, 0xe6, 0x14, 0x61,
++    0x11, 0xfd, 0x33, 0x42, 0x99, 0x2b, 0x84, 0x77, 0x74, 0x92,
++    0x91, 0xf5, 0x79, 0x79, 0xcf, 0xad, 0x8e, 0x04, 0xef, 0x80,
++    0x1e, 0x57, 0xf4, 0x14, 0xf5, 0x35, 0x09, 0x74, 0xb2, 0x13,
++    0x71, 0x58, 0x6b, 0xea, 0x32, 0x5d, 0xf3, 0xd3, 0x76, 0x48,
++    0x39, 0x10, 0x23, 0x84, 0x9d, 0xbe, 0x92, 0x77, 0x4a, 0xed,
++    0x70, 0x3e, 0x1a, 0xa2, 0x6c, 0xb3, 0x81, 0x00, 0xc3, 0xc9,
++    0xe4, 0x52, 0xc8, 0x24, 0x88, 0x0c, 0x41, 0xad, 0x87, 0x5a,
++    0xea, 0xa3, 0x7a, 0x85, 0x1c, 0x5e, 0x31, 0x7f, 0xc3, 0x35,
++    0xc6, 0xfa, 0x10, 0xc8, 0x75, 0x10, 0xc4, 0x96, 0x99, 0xe7,
++    0xfe, 0x01, 0xb4, 0x74, 0xdb, 0xb4, 0x11, 0xc3, 0xc8, 0x8c,
++    0xf6, 0xf7, 0x3b, 0x66, 0x50, 0xfc, 0xdb, 0xeb, 0xca, 0x47,
++    0x85, 0x89, 0xe1, 0x65, 0xd9, 0x62, 0x34, 0x3c, 0x70, 0xd8,
++    0x2e, 0xb4, 0x2f, 0x65, 0x3c, 0x4a, 0xa6, 0x2a, 0xe7, 0xc7,
++    0xd8, 0x41, 0x8f, 0x8a, 0x43, 0xbf, 0x42, 0xf2, 0x4d, 0xbc,
++    0xfc, 0x9e, 0x27, 0x95, 0xfb, 0x75, 0xff, 0xab, 0x02, 0x82,
++    0x01, 0x00, 0x41, 0x2f, 0x44, 0x57, 0x6d, 0x12, 0x17, 0x5b,
++    0x32, 0xc6, 0xb7, 0x6c, 0x57, 0x7a, 0x8a, 0x0e, 0x79, 0xef,
++    0x72, 0xa8, 0x68, 0xda, 0x2d, 0x38, 0xe4, 0xbb, 0x8d, 0xf6,
++    0x02, 0x65, 0xcf, 0x56, 0x13, 0xe1, 0x1a, 0xcb, 0x39, 0x80,
++    0xa6, 0xb1, 0x32, 0x03, 0x1e, 0xdd, 0xbb, 0x35, 0xd9, 0xac,
++    0x43, 0x89, 0x31, 0x08, 0x90, 0x92, 0x5e, 0x35, 0x3d, 0x7b,
++    0x9c, 0x6f, 0x86, 0xcb, 0x17, 0xdd, 0x85, 0xe4, 0xed, 0x35,
++    0x08, 0x8e, 0xc1, 0xf4, 0x05, 0xd8, 0x68, 0xc6, 0x63, 0x3c,
++    0xf7, 0xff, 0xf7, 0x47, 0x33, 0x39, 0xc5, 0x3e, 0xb7, 0x0e,
++    0x58, 0x35, 0x9d, 0x81, 0xea, 0xf8, 0x6a, 0x2c, 0x1c, 0x5a,
++    0x68, 0x78, 0x64, 0x11, 0x6b, 0xc1, 0x3e, 0x4e, 0x7a, 0xbd,
++    0x84, 0xcb, 0x0f, 0xc2, 0xb6, 0x85, 0x1d, 0xd3, 0x76, 0xc5,
++    0x93, 0x6a, 0x69, 0x89, 0x56, 0x34, 0xdc, 0x4a, 0x9b, 0xbc,
++    0xff, 0xa8, 0x0d, 0x6e, 0x35, 0x9c, 0x60, 0xa7, 0x23, 0x30,
++    0xc7, 0x06, 0x64, 0x39, 0x8b, 0x94, 0x89, 0xee, 0xba, 0x7f,
++    0x60, 0x8d, 0xfa, 0xb6, 0x97, 0x76, 0xdc, 0x51, 0x4a, 0x3c,
++    0xeb, 0x3a, 0x14, 0x2c, 0x20, 0x60, 0x69, 0x4a, 0x86, 0xfe,
++    0x8c, 0x21, 0x84, 0x49, 0x54, 0xb3, 0x20, 0xe1, 0x01, 0x7f,
++    0x58, 0xdf, 0x7f, 0xb5, 0x21, 0x51, 0x8c, 0x47, 0x9f, 0x91,
++    0xeb, 0x97, 0x3e, 0xf2, 0x54, 0xcf, 0x16, 0x46, 0xf9, 0xd9,
++    0xb6, 0xe7, 0x64, 0xc9, 0xd0, 0x54, 0xea, 0x2f, 0xa1, 0xcf,
++    0xa5, 0x7f, 0x28, 0x8d, 0x84, 0xec, 0xd5, 0x39, 0x03, 0x76,
++    0x5b, 0x2d, 0x8e, 0x43, 0xf2, 0x01, 0x24, 0xc9, 0x6f, 0xc0,
++    0xf5, 0x69, 0x6f, 0x7d, 0xb5, 0x85, 0xd2, 0x5f, 0x7f, 0x78,
++    0x40, 0x07, 0x7f, 0x09, 0x15, 0xb5, 0x1f, 0x28, 0x65, 0x10,
++    0xe4, 0x19, 0xa8, 0xc6, 0x9e, 0x8d, 0xdc, 0xcb, 0x02, 0x82,
++    0x01, 0x00, 0x13, 0x01, 0xee, 0x56, 0x80, 0x93, 0x70, 0x00,
++    0x7f, 0x52, 0xd2, 0x94, 0xa1, 0x98, 0x84, 0x4a, 0x92, 0x25,
++    0x4c, 0x9b, 0xa9, 0x91, 0x2e, 0xc2, 0x79, 0xb7, 0x5c, 0xe3,
++    0xc5, 0xd5, 0x8e, 0xc2, 0x54, 0x16, 0x17, 0xad, 0x55, 0x9b,
++    0x25, 0x76, 0x12, 0x63, 0x50, 0x22, 0x2f, 0x58, 0x58, 0x79,
++    0x6b, 0x04, 0xe3, 0xf9, 0x9f, 0x8f, 0x04, 0x41, 0x67, 0x94,
++    0xa5, 0x1f, 0xac, 0x8a, 0x15, 0x9c, 0x26, 0x10, 0x6c, 0xf8,
++    0x19, 0x57, 0x61, 0xd7, 0x3a, 0x7d, 0x31, 0xb0, 0x2d, 0x38,
++    0xbd, 0x94, 0x62, 0xad, 0xc4, 0xfa, 0x36, 0x42, 0x42, 0xf0,
++    0x24, 0x67, 0x65, 0x9d, 0x8b, 0x0b, 0x7c, 0x6f, 0x82, 0x44,
++    0x1a, 0x8c, 0xc8, 0xc9, 0xab, 0xbb, 0x4c, 0x45, 0xfc, 0x7b,
++    0x38, 0xee, 0x30, 0xe1, 0xfc, 0xef, 0x8d, 0xbc, 0x58, 0xdf,
++    0x2b, 0x5d, 0x0d, 0x54, 0xe0, 0x49, 0x4d, 0x97, 0x99, 0x8f,
++    0x22, 0xa8, 0x83, 0xbe, 0x40, 0xbb, 0x50, 0x2e, 0x78, 0x28,
++    0x0f, 0x95, 0x78, 0x8c, 0x8f, 0x98, 0x24, 0x56, 0xc2, 0x97,
++    0xf3, 0x2c, 0x43, 0xd2, 0x03, 0x82, 0x66, 0x81, 0x72, 0x5f,
++    0x53, 0x16, 0xec, 0xb1, 0xb1, 0x04, 0x5e, 0x40, 0x20, 0x48,
++    0x7b, 0x3f, 0x02, 0x97, 0x6a, 0xeb, 0x96, 0x12, 0x21, 0x35,
++    0xfe, 0x1f, 0x47, 0xc0, 0x95, 0xea, 0xc5, 0x8a, 0x08, 0x84,
++    0x4f, 0x5e, 0x63, 0x94, 0x60, 0x0f, 0x71, 0x5b, 0x7f, 0x4a,
++    0xec, 0x4f, 0x60, 0xc6, 0xba, 0x4a, 0x24, 0xf1, 0x20, 0x8b,
++    0xa7, 0x2e, 0x3a, 0xce, 0x8d, 0xe0, 0x27, 0x1d, 0xb5, 0x8e,
++    0xb4, 0x21, 0xc5, 0xe2, 0xa6, 0x16, 0x0a, 0x51, 0x83, 0x55,
++    0x88, 0xd1, 0x30, 0x11, 0x63, 0xd5, 0xd7, 0x8d, 0xae, 0x16,
++    0x12, 0x82, 0xc4, 0x85, 0x00, 0x4e, 0x27, 0x83, 0xa5, 0x7c,
++    0x90, 0x2e, 0xe5, 0xa2, 0xa3, 0xd3, 0x4c, 0x63, 0x02, 0x82,
++    0x01, 0x01, 0x00, 0x86, 0x08, 0x98, 0x98, 0xa5, 0x00, 0x05,
++    0x39, 0x77, 0xd9, 0x66, 0xb3, 0xcf, 0xca, 0xa0, 0x71, 0xb3,
++    0x50, 0xce, 0x3d, 0xb1, 0x93, 0x95, 0x35, 0xc4, 0xd4, 0x2e,
++    0x90, 0xdf, 0x0f, 0xfc, 0x60, 0xc1, 0x94, 0x68, 0x61, 0x43,
++    0xca, 0x9a, 0x23, 0x4a, 0x1e, 0x45, 0x72, 0x99, 0xb5, 0x1e,
++    0x61, 0x8d, 0x77, 0x0f, 0xa0, 0xbb, 0xd7, 0x77, 0xb4, 0x2a,
++    0x15, 0x11, 0x88, 0x2d, 0xb3, 0x56, 0x61, 0x5e, 0x6a, 0xed,
++    0xa4, 0x46, 0x4a, 0x3f, 0x50, 0x11, 0xd6, 0xba, 0xb6, 0xd7,
++    0x95, 0x65, 0x53, 0xc3, 0xa1, 0x8f, 0xe0, 0xa3, 0xf5, 0x1c,
++    0xfd, 0xaf, 0x6e, 0x43, 0xd7, 0x17, 0xa7, 0xd3, 0x81, 0x1b,
++    0xa4, 0xdf, 0xe0, 0x97, 0x8a, 0x46, 0x03, 0xd3, 0x46, 0x0e,
++    0x83, 0x48, 0x4e, 0xd2, 0x02, 0xcb, 0xc0, 0xad, 0x79, 0x95,
++    0x8c, 0x96, 0xba, 0x40, 0x34, 0x11, 0x71, 0x5e, 0xe9, 0x11,
++    0xf9, 0xc5, 0x4a, 0x5e, 0x91, 0x9d, 0xf5, 0x92, 0x4f, 0xeb,
++    0xc6, 0x70, 0x02, 0x2d, 0x3d, 0x04, 0xaa, 0xe9, 0x3a, 0x8e,
++    0xd5, 0xa8, 0xad, 0xf7, 0xce, 0x0d, 0x16, 0xb2, 0xec, 0x0a,
++    0x9c, 0xf5, 0x94, 0x39, 0xb9, 0x8a, 0xfc, 0x1e, 0xf9, 0xcc,
++    0xf2, 0x5f, 0x21, 0x31, 0x74, 0x72, 0x6b, 0x64, 0xae, 0x35,
++    0x61, 0x8d, 0x0d, 0xcb, 0xe7, 0xda, 0x39, 0xca, 0xf3, 0x21,
++    0x66, 0x0b, 0x95, 0xd7, 0x0a, 0x7c, 0xca, 0xa1, 0xa9, 0x5a,
++    0xe8, 0xac, 0xe0, 0x71, 0x54, 0xaf, 0x28, 0xcf, 0xd5, 0x70,
++    0x89, 0xe0, 0xf3, 0x9e, 0x43, 0x6c, 0x8d, 0x7b, 0x99, 0x01,
++    0x68, 0x4d, 0xa1, 0x45, 0x46, 0x0c, 0x43, 0xbc, 0xcc, 0x2c,
++    0xdd, 0xc5, 0x46, 0xc8, 0x4e, 0x0e, 0xbe, 0xed, 0xb9, 0x26,
++    0xab, 0x2e, 0xdb, 0xeb, 0x8f, 0xff, 0xdb, 0xb0, 0xc6, 0x55,
++    0xaf, 0xf8, 0x2a, 0x91, 0x9d, 0x50, 0x44, 0x21, 0x17,
++};
++
++static unsigned char test7680[] = {
++    0x30, 0x82, 0x11, 0x09, 0x02, 0x01, 0x00, 0x02, 0x82, 0x03,
++    0xc1, 0x00, 0xe3, 0x27, 0x46, 0x99, 0xb5, 0x17, 0xab, 0xfa,
++    0x65, 0x05, 0x7a, 0x06, 0x81, 0x14, 0xce, 0x43, 0x21, 0x49,
++    0x0f, 0x08, 0xf1, 0x70, 0xb4, 0xc1, 0x10, 0xd1, 0x87, 0xf8,
++    0x29, 0x91, 0x36, 0x66, 0x2d, 0xbe, 0x7b, 0x1d, 0xa2, 0x0b,
++    0x20, 0x38, 0xd9, 0x8e, 0x78, 0x27, 0xcf, 0xb5, 0x45, 0x58,
++    0x3d, 0xf4, 0xda, 0xf0, 0xdc, 0x21, 0x17, 0x52, 0xcd, 0x68,
++    0xe2, 0x81, 0xac, 0x88, 0x61, 0x10, 0xbc, 0xb0, 0x7f, 0xe4,
++    0xf3, 0x78, 0xb7, 0x28, 0x6c, 0x5f, 0x5c, 0xc2, 0x8d, 0x3d,
++    0xb0, 0x87, 0x41, 0x15, 0x2e, 0x09, 0x5f, 0xea, 0x06, 0x7f,
++    0xe9, 0x35, 0x18, 0x90, 0x50, 0xad, 0xf6, 0xb9, 0xfd, 0x33,
++    0x02, 0x1a, 0x99, 0x9e, 0xa5, 0x7d, 0x2c, 0x3b, 0x24, 0xe7,
++    0x31, 0x35, 0x73, 0x9a, 0xb0, 0xfe, 0x03, 0xfc, 0xc6, 0x98,
++    0x78, 0xd9, 0x66, 0x95, 0xa5, 0x12, 0xbc, 0x1e, 0x82, 0xbc,
++    0xf1, 0xc5, 0x31, 0xcd, 0xa6, 0xb1, 0x0c, 0x02, 0xbf, 0x7f,
++    0xb7, 0xaf, 0x5f, 0xd6, 0xed, 0xf7, 0xc1, 0x59, 0x86, 0x3a,
++    0x35, 0x95, 0x54, 0x21, 0x8d, 0x6a, 0xb3, 0xd1, 0x2b, 0x71,
++    0xf5, 0xf1, 0x66, 0x00, 0xb1, 0x88, 0xee, 0x3b, 0xa4, 0x41,
++    0x52, 0x1a, 0xf5, 0x0e, 0x32, 0xb6, 0xbf, 0x52, 0xab, 0x51,
++    0x55, 0x91, 0x32, 0x4f, 0xaf, 0x91, 0xac, 0xf7, 0xff, 0x8e,
++    0x3b, 0x2b, 0x61, 0xe9, 0x6d, 0x1d, 0x68, 0x80, 0x90, 0x79,
++    0x34, 0x96, 0xca, 0x49, 0x43, 0x7c, 0x89, 0x4e, 0x5e, 0x31,
++    0xb5, 0xce, 0x01, 0x9b, 0x09, 0xaf, 0x92, 0x06, 0x24, 0xe7,
++    0x22, 0x35, 0xcc, 0xa2, 0x0b, 0xfb, 0x5b, 0x87, 0x65, 0x71,
++    0xff, 0x64, 0x3e, 0xf9, 0xe8, 0x33, 0xa0, 0xc3, 0x4e, 0xb2,
++    0x41, 0x98, 0x54, 0xeb, 0x13, 0x99, 0xfb, 0x32, 0x78, 0x7e,
++    0xda, 0x4f, 0xd3, 0x46, 0x6a, 0xb5, 0x78, 0x81, 0x3f, 0x04,
++    0x13, 0x5f, 0x67, 0xaf, 0x88, 0xa5, 0x9e, 0x0d, 0xc5, 0xf3,
++    0xe7, 0x4c, 0x51, 0xf5, 0x51, 0x4a, 0xa4, 0x58, 0x64, 0xd9,
++    0xa2, 0x32, 0x54, 0x36, 0xce, 0x38, 0xd8, 0xc2, 0x0e, 0x0d,
++    0x60, 0x8e, 0x32, 0x7f, 0x90, 0x8a, 0xbc, 0x88, 0xbe, 0x6a,
++    0xc0, 0x47, 0x0f, 0x02, 0x41, 0xff, 0x3b, 0x7e, 0xc5, 0xa6,
++    0x33, 0x1d, 0x19, 0xd1, 0xd5, 0x67, 0x6c, 0xbf, 0x16, 0xb0,
++    0x7e, 0x80, 0x10, 0xbf, 0x7f, 0xdd, 0xd0, 0xf4, 0xc3, 0x94,
++    0x2c, 0x9a, 0x2c, 0xda, 0x69, 0x4e, 0xd6, 0x7b, 0x40, 0x4d,
++    0x2a, 0x27, 0xcb, 0x5a, 0xe5, 0x2d, 0x3f, 0x7d, 0x51, 0x9d,
++    0x9f, 0x70, 0xde, 0x50, 0xb1, 0xd3, 0xd2, 0x38, 0x4d, 0x1c,
++    0xca, 0xc2, 0x1e, 0x80, 0xd0, 0x36, 0x82, 0x04, 0xe6, 0x17,
++    0x79, 0x9f, 0x2e, 0xc9, 0xed, 0x2b, 0xd5, 0x1b, 0xfa, 0x7d,
++    0x1a, 0x80, 0xb5, 0x0e, 0x2f, 0x05, 0xbe, 0x4a, 0x1b, 0xfe,
++    0x0a, 0xad, 0x01, 0xde, 0x91, 0xc8, 0xf9, 0x81, 0xbe, 0xc7,
++    0xaf, 0xe7, 0x87, 0xed, 0x9d, 0xb8, 0x6c, 0xad, 0x65, 0xed,
++    0x5e, 0xd3, 0x67, 0x8c, 0x62, 0x3a, 0xe7, 0xfd, 0x67, 0xe0,
++    0xbb, 0x57, 0xaf, 0x56, 0xeb, 0x4a, 0x58, 0x6e, 0xad, 0xf2,
++    0xbe, 0xc3, 0x70, 0x29, 0xf8, 0xeb, 0x68, 0x45, 0xa0, 0xbd,
++    0xcd, 0xa5, 0xb4, 0xd9, 0x01, 0xb7, 0x44, 0xeb, 0x97, 0xf3,
++    0x0c, 0x56, 0xe4, 0x26, 0xd0, 0xa5, 0xb1, 0xa3, 0x49, 0x6e,
++    0x88, 0xf2, 0x22, 0xe2, 0x7b, 0x58, 0x3a, 0xd9, 0x52, 0xa4,
++    0xb1, 0x4c, 0x5c, 0x7c, 0xf0, 0x88, 0x7b, 0x9f, 0x06, 0xe9,
++    0x32, 0x4e, 0xf2, 0x64, 0x83, 0x8b, 0xa2, 0xea, 0x1d, 0x25,
++    0xf1, 0x8d, 0x16, 0x8b, 0xe0, 0xab, 0xd2, 0xe9, 0xe4, 0x6b,
++    0x7d, 0x76, 0x98, 0x22, 0x53, 0x31, 0x6b, 0xcc, 0xf1, 0xe5,
++    0x1d, 0xd7, 0xa5, 0xb0, 0xea, 0x6b, 0x38, 0x14, 0x0c, 0x06,
++    0x10, 0x27, 0xd8, 0x33, 0xf3, 0x9a, 0xae, 0x94, 0xdd, 0x0b,
++    0xb4, 0x6d, 0xe5, 0x91, 0xdd, 0xf1, 0x0f, 0x27, 0xa4, 0x94,
++    0x55, 0xf0, 0xde, 0x07, 0x29, 0xe6, 0x3f, 0x26, 0x19, 0xa1,
++    0xdd, 0xd1, 0x06, 0x99, 0xda, 0x54, 0x23, 0x3c, 0xf5, 0x5c,
++    0x2e, 0x96, 0xa9, 0x21, 0x23, 0x25, 0x2e, 0x6f, 0xf1, 0xf9,
++    0x11, 0x54, 0xe5, 0x7b, 0xb9, 0x1f, 0x11, 0xe2, 0x9e, 0x6b,
++    0x61, 0x8b, 0xa3, 0x8b, 0xc1, 0x20, 0x9b, 0xfb, 0x51, 0xef,
++    0xbb, 0xb9, 0xf6, 0xaf, 0x66, 0xb3, 0x2c, 0x25, 0xef, 0x76,
++    0xcb, 0xbf, 0x7a, 0x93, 0x2f, 0xe1, 0x17, 0x56, 0xc1, 0x00,
++    0x33, 0xb5, 0xd9, 0x91, 0x05, 0x31, 0xcc, 0x72, 0xcd, 0x4a,
++    0x93, 0x9a, 0xe3, 0x21, 0x42, 0x9e, 0xb8, 0x4e, 0x6c, 0x27,
++    0x93, 0xf0, 0x7f, 0x22, 0xdb, 0xe5, 0xb3, 0xa3, 0xf7, 0xe7,
++    0x80, 0xbb, 0x91, 0xca, 0xf7, 0xe8, 0x52, 0xb8, 0x11, 0x64,
++    0x66, 0x25, 0x94, 0xf8, 0x6f, 0x0b, 0x3b, 0xb7, 0xff, 0x80,
++    0x9e, 0x36, 0xe9, 0x88, 0x2e, 0xab, 0x05, 0xbf, 0x99, 0x9f,
++    0x2b, 0x4f, 0xc6, 0xb1, 0x13, 0x5b, 0x06, 0xff, 0x0a, 0x7b,
++    0xbc, 0x7f, 0x07, 0xa0, 0x35, 0xc2, 0x2d, 0x44, 0x3e, 0xad,
++    0x44, 0xcb, 0x47, 0x18, 0x26, 0x71, 0x7b, 0x17, 0xc9, 0x6d,
++    0xb5, 0x4b, 0xcf, 0xdf, 0x14, 0x2c, 0x6c, 0xdf, 0x21, 0xce,
++    0x93, 0x49, 0x34, 0x69, 0x49, 0xfd, 0x3e, 0x71, 0x5b, 0xfa,
++    0x07, 0xc5, 0x7e, 0x5e, 0x54, 0x1a, 0x3c, 0xa6, 0x29, 0xb5,
++    0xbf, 0x0d, 0xf1, 0xc6, 0xa4, 0x61, 0xd6, 0x17, 0x1d, 0xf0,
++    0xa2, 0x78, 0x8f, 0xbc, 0x7e, 0x0c, 0xb4, 0xf0, 0x1e, 0x05,
++    0xea, 0xb5, 0xad, 0x68, 0x95, 0x0b, 0x27, 0xb4, 0x29, 0x7c,
++    0x70, 0x2a, 0x9a, 0x0a, 0x39, 0xd4, 0x76, 0xb7, 0x72, 0x30,
++    0x5e, 0xae, 0x9c, 0x4a, 0x55, 0xc7, 0x46, 0xd7, 0x5f, 0xbe,
++    0x10, 0x61, 0x25, 0x18, 0x7a, 0x9f, 0xd3, 0x05, 0x3d, 0x6f,
++    0x9a, 0x1e, 0xec, 0x2b, 0x03, 0xe0, 0x49, 0x6a, 0x9c, 0xd6,
++    0xdb, 0xc2, 0xa1, 0xe1, 0x0a, 0xbb, 0x31, 0x42, 0xc8, 0x43,
++    0x4e, 0x7c, 0xa9, 0x7c, 0x60, 0xea, 0xbe, 0xf1, 0x8b, 0xe8,
++    0xb2, 0x90, 0x83, 0x14, 0x21, 0xe4, 0xb3, 0x0d, 0x7c, 0x63,
++    0x3c, 0x98, 0x55, 0xc6, 0x44, 0xa6, 0xa8, 0x1e, 0x42, 0xb7,
++    0x89, 0xa8, 0xbd, 0xb8, 0x34, 0x3d, 0x09, 0x80, 0x99, 0x73,
++    0x9f, 0xaf, 0x17, 0x56, 0xf2, 0x73, 0x3e, 0x1e, 0x6e, 0xe9,
++    0x18, 0xa0, 0x5b, 0x69, 0xce, 0xfd, 0x3d, 0x77, 0x81, 0x95,
++    0x3b, 0xf1, 0xde, 0x26, 0xe9, 0x27, 0xef, 0x92, 0x2a, 0x97,
++    0xdc, 0x95, 0xa5, 0xa3, 0xb0, 0xfb, 0x96, 0x89, 0x4f, 0xe6,
++    0xc1, 0x42, 0x0b, 0xfd, 0xb4, 0x6d, 0x0a, 0x9f, 0x9b, 0x31,
++    0xd8, 0x21, 0x38, 0x8a, 0xee, 0xb6, 0x5c, 0x12, 0xa8, 0xb4,
++    0x07, 0x79, 0x41, 0xa7, 0x7f, 0x13, 0x74, 0xad, 0x0b, 0xee,
++    0x28, 0x52, 0xac, 0x2f, 0x4d, 0x30, 0x1c, 0xc5, 0xa6, 0xa5,
++    0x61, 0x42, 0xbd, 0xe1, 0x4f, 0xd3, 0xec, 0x66, 0xf2, 0x63,
++    0xf4, 0x93, 0xdb, 0x35, 0x2d, 0x3b, 0x71, 0x25, 0x09, 0xde,
++    0xda, 0x46, 0xda, 0xe2, 0xa7, 0xa3, 0xdf, 0xcd, 0xbf, 0x58,
++    0x05, 0x25, 0x02, 0x03, 0x01, 0x00, 0x01, 0x02, 0x82, 0x03,
++    0xc0, 0x5f, 0xd5, 0x15, 0x1b, 0x09, 0xe4, 0xa7, 0xc0, 0xa6,
++    0xd8, 0x0d, 0xa8, 0x2a, 0xd3, 0x1d, 0x46, 0x03, 0x07, 0xf0,
++    0x98, 0xe4, 0x4b, 0x99, 0x66, 0x8e, 0x72, 0xe7, 0xbb, 0x51,
++    0xc6, 0x1a, 0xbe, 0x36, 0xf4, 0x52, 0xba, 0xa8, 0xbf, 0xaa,
++    0xe3, 0x71, 0x1d, 0x83, 0x21, 0xc0, 0xa6, 0x88, 0x4f, 0xf7,
++    0x2b, 0x93, 0x26, 0xe4, 0xa7, 0xed, 0x50, 0x18, 0xaa, 0xf4,
++    0x4c, 0xa2, 0xfe, 0x92, 0x7c, 0xde, 0x2e, 0x54, 0x76, 0xc2,
++    0x25, 0x1e, 0x98, 0xa6, 0x48, 0x01, 0x39, 0x6f, 0x1f, 0x24,
++    0x97, 0x9b, 0x64, 0x95, 0x1c, 0x8d, 0x63, 0x8d, 0x44, 0x6f,
++    0x9d, 0xdf, 0xf4, 0x1a, 0xa5, 0x9a, 0x1e, 0xd3, 0x6c, 0xae,
++    0xa9, 0x8c, 0x3f, 0xfb, 0x2f, 0x78, 0xf6, 0xa6, 0xd6, 0x06,
++    0xd3, 0xb7, 0x26, 0xff, 0x1e, 0xdb, 0x8d, 0xcc, 0x37, 0x4d,
++    0x5c, 0xe2, 0xc3, 0xa5, 0x75, 0xe6, 0xf9, 0xb4, 0x4c, 0x84,
++    0x6f, 0x9e, 0x58, 0x55, 0xc8, 0x01, 0xfa, 0x32, 0xd2, 0x6e,
++    0x2b, 0x45, 0xf2, 0xc6, 0x48, 0xad, 0x40, 0xd8, 0xb9, 0x3c,
++    0x1b, 0xf8, 0xf7, 0x82, 0xd3, 0x0e, 0x73, 0xe3, 0xb1, 0x5b,
++    0x82, 0x71, 0x77, 0x3f, 0x6f, 0x36, 0x9a, 0xe0, 0xec, 0x51,
++    0xf8, 0x5f, 0x84, 0x92, 0xee, 0xb8, 0x7e, 0xe7, 0x1a, 0x14,
++    0x50, 0x82, 0x7a, 0x4d, 0xe6, 0xd6, 0xa3, 0x76, 0x24, 0x8a,
++    0x5f, 0xfe, 0x19, 0xdd, 0xd7, 0xf7, 0x5b, 0xae, 0x18, 0x04,
++    0x90, 0xcd, 0x5c, 0xe5, 0x64, 0xe8, 0x04, 0xb1, 0x06, 0xa5,
++    0xdd, 0xf8, 0x9d, 0x71, 0x13, 0xaa, 0x36, 0x7f, 0x61, 0x27,
++    0xf4, 0xac, 0x95, 0x7d, 0x1a, 0x99, 0x7d, 0xe0, 0xd5, 0x9c,
++    0x5a, 0xad, 0x9a, 0xff, 0x54, 0xb0, 0xb1, 0x55, 0x45, 0x2d,
++    0x19, 0x58, 0x52, 0x28, 0xdd, 0xe0, 0xb5, 0x65, 0x52, 0x97,
++    0x45, 0xf0, 0x2b, 0x98, 0x1f, 0x61, 0x6c, 0x9d, 0xaa, 0x59,
++    0x85, 0xf9, 0x97, 0x7b, 0xbd, 0xeb, 0x95, 0x81, 0xfb, 0x29,
++    0x8c, 0xf0, 0x52, 0xdf, 0xed, 0xee, 0xb2, 0x00, 0x32, 0x35,
++    0x14, 0xa8, 0xa4, 0xca, 0x91, 0xff, 0x18, 0xb7, 0x96, 0xfb,
++    0x32, 0x62, 0xa9, 0xa0, 0xd0, 0x77, 0x43, 0xf5, 0x99, 0xd1,
++    0xee, 0xe8, 0xad, 0x1a, 0x2c, 0xd4, 0xeb, 0xe1, 0xf5, 0x01,
++    0x41, 0x78, 0xc0, 0x27, 0x19, 0x50, 0x2e, 0xba, 0x22, 0xd1,
++    0xeb, 0xb3, 0xa5, 0x27, 0x0b, 0xec, 0xf9, 0x26, 0x7e, 0x1f,
++    0xe7, 0x17, 0x9f, 0x39, 0xa8, 0x72, 0x22, 0x63, 0x79, 0x6a,
++    0x9c, 0x89, 0x55, 0x9a, 0xb4, 0x61, 0x41, 0xbc, 0xaa, 0x14,
++    0x37, 0x29, 0x03, 0xc0, 0x52, 0x4e, 0x31, 0x44, 0x8f, 0x2e,
++    0x17, 0x81, 0x88, 0xf4, 0xce, 0xda, 0x41, 0xb8, 0xd5, 0x14,
++    0x91, 0x8c, 0xca, 0xd2, 0x0d, 0x99, 0x06, 0x09, 0xc2, 0xb7,
++    0xe8, 0xae, 0xfa, 0x01, 0xea, 0x99, 0x62, 0x68, 0xb6, 0xdf,
++    0xc8, 0x27, 0xae, 0xbf, 0xb0, 0x9b, 0x5b, 0x1a, 0xa2, 0xe2,
++    0x5a, 0x7a, 0xe5, 0x4b, 0x92, 0x1f, 0xff, 0x73, 0xae, 0x16,
++    0x40, 0x78, 0x42, 0x28, 0xbb, 0x13, 0x5e, 0xbc, 0x71, 0x7a,
++    0x78, 0x3e, 0xd8, 0x1b, 0xc2, 0x2c, 0xd6, 0xdc, 0xfa, 0x39,
++    0x72, 0xf8, 0xa2, 0x2c, 0x8b, 0x1c, 0x5d, 0xab, 0xb8, 0x07,
++    0xc7, 0xae, 0x29, 0x93, 0x68, 0xbf, 0x61, 0xe9, 0xa4, 0x37,
++    0x83, 0x7d, 0x13, 0xc7, 0x18, 0xf0, 0x7d, 0xa4, 0x20, 0x47,
++    0x14, 0x68, 0x95, 0x46, 0x56, 0x6d, 0xd5, 0x7b, 0xe1, 0x51,
++    0x8f, 0x96, 0xc1, 0x7b, 0x35, 0x09, 0x7a, 0x89, 0x0e, 0xdf,
++    0x12, 0xd5, 0xe1, 0x9c, 0x2a, 0x94, 0x95, 0x43, 0x93, 0x48,
++    0xa6, 0x23, 0xe6, 0xd8, 0xf2, 0xb8, 0x0e, 0xba, 0x6d, 0x61,
++    0x03, 0xaf, 0x40, 0x63, 0x2b, 0x2f, 0xee, 0x61, 0x4c, 0xc4,
++    0x70, 0x3d, 0x78, 0xc1, 0x4f, 0x8e, 0x0b, 0x9b, 0x06, 0x35,
++    0x6d, 0x6d, 0x83, 0x37, 0xbb, 0x39, 0x7d, 0x7f, 0x33, 0x93,
++    0xc4, 0xeb, 0x8e, 0xfc, 0xda, 0xf0, 0x54, 0xfe, 0x1d, 0xc4,
++    0xd3, 0x83, 0x99, 0xdf, 0x65, 0xee, 0x00, 0x7d, 0x86, 0x27,
++    0xd4, 0x3a, 0x6b, 0xe6, 0x82, 0x8e, 0x58, 0x2d, 0x03, 0x38,
++    0xef, 0x6c, 0x82, 0x87, 0x18, 0x3b, 0x47, 0xe7, 0xbc, 0xe1,
++    0x58, 0x70, 0x4d, 0x46, 0x96, 0x34, 0x60, 0x96, 0x15, 0x09,
++    0x3c, 0x84, 0x40, 0xaf, 0x80, 0x32, 0x75, 0xc7, 0x23, 0x6c,
++    0xfb, 0x1d, 0x57, 0x73, 0x19, 0x09, 0xe8, 0x1a, 0x4c, 0x02,
++    0x5c, 0x7e, 0x4e, 0xbe, 0x75, 0xf8, 0x73, 0xff, 0x2d, 0x54,
++    0x19, 0x55, 0xf5, 0xf4, 0x1b, 0xc9, 0xbc, 0xc2, 0x19, 0xcb,
++    0xb7, 0x4e, 0x6a, 0x0d, 0xff, 0xca, 0x7d, 0xd0, 0x88, 0x91,
++    0x8b, 0x9b, 0x21, 0xa4, 0xa2, 0x43, 0x0d, 0xbc, 0x9e, 0x73,
++    0x7d, 0x54, 0x7d, 0x95, 0xcc, 0x63, 0x5e, 0xc1, 0xb8, 0xe6,
++    0x27, 0xff, 0x20, 0x07, 0xe8, 0x6e, 0x7e, 0xf2, 0x0f, 0x5a,
++    0x09, 0xef, 0xe5, 0x4d, 0x80, 0x39, 0x95, 0xd5, 0xf4, 0xee,
++    0x3b, 0xca, 0x7c, 0x73, 0xf8, 0x39, 0x5a, 0xc1, 0x1d, 0x7d,
++    0x94, 0x72, 0x32, 0xad, 0x58, 0xe2, 0xfc, 0x71, 0x6e, 0x66,
++    0xaa, 0xa1, 0x59, 0xd6, 0xac, 0xab, 0xbe, 0x8c, 0x53, 0x99,
++    0xcd, 0xe8, 0x2d, 0xb5, 0xb3, 0x46, 0x58, 0x2e, 0x16, 0xd7,
++    0x4d, 0x8b, 0x7d, 0x4a, 0xb1, 0x4c, 0x85, 0x91, 0x1b, 0x57,
++    0x54, 0xf8, 0x14, 0x59, 0xdb, 0xc4, 0x2c, 0x9c, 0x08, 0x6d,
++    0x3d, 0xd7, 0xf6, 0xa6, 0xe6, 0xb3, 0x2a, 0xe7, 0x29, 0x1c,
++    0xab, 0xb4, 0xed, 0x13, 0x19, 0xf8, 0xb6, 0x60, 0x92, 0x44,
++    0x53, 0xd4, 0xa9, 0x7e, 0xba, 0x21, 0xa2, 0xdc, 0x6e, 0xa5,
++    0x5e, 0x53, 0x59, 0x3c, 0x52, 0x61, 0x7b, 0x5f, 0x19, 0xad,
++    0xc8, 0x6d, 0x68, 0x8d, 0x7a, 0xc9, 0xd6, 0xef, 0xeb, 0x67,
++    0x4f, 0xca, 0xe7, 0xf6, 0x29, 0x36, 0x97, 0xfb, 0x3e, 0x37,
++    0x95, 0x85, 0x71, 0x70, 0xf6, 0x63, 0x86, 0x2a, 0x29, 0xd7,
++    0x9a, 0x96, 0x76, 0xa7, 0x47, 0x98, 0x4e, 0x06, 0x31, 0xaf,
++    0xf3, 0x4f, 0x2a, 0x65, 0x90, 0x6a, 0x4b, 0x8e, 0x43, 0x79,
++    0xe2, 0xdd, 0xce, 0x08, 0x1c, 0x01, 0xec, 0x38, 0x41, 0xdd,
++    0x19, 0xd8, 0xf3, 0x36, 0x03, 0x35, 0x03, 0xaf, 0x1c, 0x45,
++    0x3c, 0xac, 0x13, 0xaa, 0x36, 0x16, 0x48, 0x77, 0xb3, 0xbe,
++    0xa3, 0xb3, 0x9d, 0x7f, 0x20, 0xca, 0x74, 0x65, 0xac, 0x93,
++    0xa7, 0x54, 0xad, 0xc8, 0x68, 0x0e, 0xf8, 0x44, 0x1f, 0xad,
++    0x2c, 0xb7, 0x9a, 0x9a, 0x07, 0xe5, 0xcd, 0x87, 0xe0, 0x14,
++    0xb5, 0xaf, 0xd3, 0xd7, 0xcf, 0x13, 0x9f, 0x3b, 0xbd, 0xfe,
++    0x29, 0x0b, 0x72, 0xf5, 0x4c, 0x54, 0x94, 0xc7, 0x66, 0xec,
++    0xa8, 0x41, 0x96, 0x3d, 0x17, 0xed, 0x19, 0xc0, 0x82, 0x3e,
++    0x5f, 0x9a, 0x91, 0xfe, 0xd1, 0x2f, 0xb8, 0x94, 0xaa, 0x58,
++    0x68, 0x95, 0x31, 0x87, 0x57, 0x9a, 0x75, 0x94, 0x4d, 0x38,
++    0x7d, 0x56, 0x82, 0x81, 0x9c, 0xb9, 0x34, 0x2b, 0xe7, 0x40,
++    0xd9, 0x3c, 0x77, 0x5b, 0x95, 0x51, 0x06, 0x11, 0x41, 0xe3,
++    0x8b, 0xb7, 0x32, 0xeb, 0xe1, 0x05, 0x1b, 0x10, 0xa8, 0x0e,
++    0xa1, 0x02, 0x82, 0x01, 0xe1, 0x00, 0xfa, 0x38, 0x34, 0xfe,
++    0x55, 0x87, 0x71, 0x62, 0x47, 0x00, 0x33, 0x64, 0x67, 0x70,
++    0x79, 0x76, 0xdf, 0xfe, 0xc3, 0x28, 0x38, 0xdf, 0x90, 0xd4,
++    0xc0, 0xee, 0x98, 0xbf, 0x9d, 0x9b, 0x85, 0xd8, 0x61, 0x65,
++    0xa5, 0x70, 0xf5, 0xd2, 0x2c, 0xbf, 0x2f, 0xb5, 0x55, 0x79,
++    0x92, 0x13, 0xba, 0x4d, 0x3c, 0x39, 0xbf, 0xd5, 0x31, 0x13,
++    0x7a, 0x31, 0xf4, 0x8b, 0xce, 0xf8, 0xd0, 0xd3, 0x9b, 0xe2,
++    0xee, 0x31, 0xdb, 0xba, 0xcc, 0x1a, 0xba, 0x1c, 0x8d, 0xee,
++    0xea, 0xcb, 0xd3, 0x5a, 0xad, 0x87, 0xd6, 0xf9, 0x15, 0x2f,
++    0x6e, 0x00, 0x06, 0x74, 0x25, 0x8d, 0xff, 0xc8, 0xa6, 0x11,
++    0x1c, 0xe8, 0x16, 0x1a, 0xde, 0x53, 0x05, 0xb9, 0x53, 0x55,
++    0x28, 0x83, 0x3d, 0xbe, 0x61, 0x0c, 0xc4, 0x98, 0x7d, 0xf6,
++    0xec, 0x36, 0xc3, 0xe5, 0xe7, 0x1d, 0x14, 0x64, 0xcb, 0x0d,
++    0x62, 0x5d, 0x7a, 0xcd, 0x88, 0xfc, 0x66, 0x4e, 0xf9, 0x36,
++    0x47, 0x95, 0x18, 0x3a, 0x48, 0x2a, 0xff, 0x62, 0x8f, 0x6c,
++    0xe2, 0xc2, 0xe9, 0xd3, 0x6a, 0x45, 0x5c, 0xf5, 0x89, 0x53,
++    0x5c, 0xbe, 0xcf, 0xad, 0x87, 0x22, 0x9c, 0x31, 0x48, 0xdb,
++    0xd8, 0xe4, 0xe5, 0x38, 0xae, 0xc2, 0xb0, 0xd2, 0xba, 0xb7,
++    0x30, 0x53, 0x2d, 0xb1, 0x35, 0xf1, 0x58, 0x0f, 0x8a, 0x06,
++    0x51, 0x76, 0xb9, 0x2c, 0x32, 0xe0, 0xd1, 0xaa, 0x82, 0x34,
++    0x69, 0x71, 0x1c, 0x5f, 0x35, 0xa8, 0x9d, 0x11, 0xac, 0x13,
++    0xdb, 0x7b, 0xf6, 0x93, 0xe3, 0xb9, 0xbd, 0xd9, 0xb2, 0x86,
++    0xff, 0x61, 0x88, 0x2b, 0x72, 0x5c, 0x84, 0xe1, 0x0c, 0x72,
++    0xab, 0x44, 0xff, 0x23, 0x13, 0xaf, 0xd1, 0x5a, 0xd3, 0xea,
++    0x73, 0xfe, 0xd5, 0xa4, 0x7d, 0x9e, 0x4e, 0xac, 0x03, 0x93,
++    0x72, 0x14, 0x2d, 0x96, 0x6f, 0xee, 0xb4, 0xcd, 0x4e, 0xab,
++    0xea, 0x71, 0x93, 0x81, 0xe0, 0x3d, 0xcd, 0x61, 0x96, 0x25,
++    0x76, 0xbd, 0xc4, 0xb5, 0xdd, 0x7c, 0xf1, 0xb9, 0xe1, 0x2c,
++    0x58, 0x1b, 0xa4, 0x46, 0x4b, 0x12, 0x57, 0x58, 0xaa, 0x3a,
++    0xae, 0x89, 0xa3, 0xb3, 0xcf, 0x1f, 0x8d, 0x67, 0xdf, 0x6d,
++    0x7e, 0x8e, 0xfa, 0xc5, 0x09, 0x73, 0x46, 0x56, 0x55, 0x90,
++    0xeb, 0x77, 0x4e, 0x16, 0x4f, 0x68, 0x7b, 0x1f, 0x61, 0x23,
++    0xec, 0xa9, 0x71, 0x30, 0x33, 0x25, 0xc7, 0x4e, 0x26, 0x2e,
++    0x4e, 0x2b, 0xc2, 0x64, 0x5f, 0xf5, 0x8f, 0x7a, 0x4b, 0x1c,
++    0x06, 0xb3, 0x91, 0xf6, 0x9b, 0x51, 0xb7, 0xb0, 0x64, 0x72,
++    0x04, 0xe5, 0xfa, 0x14, 0x2f, 0xed, 0x61, 0x29, 0x03, 0x73,
++    0x19, 0x15, 0x6e, 0x2c, 0x8b, 0x0e, 0xec, 0x4d, 0xf1, 0xe3,
++    0x6f, 0x58, 0x7c, 0xc9, 0x48, 0x67, 0x3f, 0x51, 0xb5, 0xb7,
++    0x26, 0x46, 0xa7, 0x25, 0x79, 0x55, 0xfe, 0x3a, 0x44, 0xb4,
++    0x44, 0xfc, 0xb8, 0x14, 0x34, 0x47, 0xd7, 0xa3, 0x0e, 0x76,
++    0xe7, 0x83, 0x9a, 0x02, 0xc3, 0xcf, 0x2b, 0xd9, 0x83, 0x93,
++    0xd5, 0xee, 0x99, 0x74, 0x45, 0x62, 0x23, 0xa6, 0x02, 0xc9,
++    0xc0, 0x10, 0x70, 0x0a, 0x99, 0x29, 0x0c, 0x79, 0x04, 0x4c,
++    0x77, 0x21, 0x96, 0xf0, 0xa5, 0x17, 0x22, 0xbe, 0xab, 0x9b,
++    0xd7, 0x42, 0xd3, 0xe9, 0xc0, 0x42, 0x44, 0x7d, 0x9d, 0xc9,
++    0x3d, 0xf9, 0x36, 0x97, 0x1b, 0x75, 0x52, 0x8f, 0xe9, 0xb9,
++    0x8c, 0xa7, 0x64, 0x19, 0x5b, 0x5d, 0x60, 0xb4, 0x42, 0x95,
++    0xc9, 0xdb, 0x82, 0x03, 0xc6, 0xb0, 0x28, 0x72, 0x64, 0x03,
++    0x41, 0x4d, 0x8f, 0xc6, 0xd0, 0xcd, 0x02, 0x82, 0x01, 0xe1,
++    0x00, 0xe8, 0x66, 0xa7, 0xf9, 0x0f, 0x5a, 0x21, 0xfc, 0x88,
++    0x4e, 0x91, 0xd5, 0x4a, 0xf0, 0xf4, 0x32, 0xe5, 0x0d, 0xf3,
++    0x06, 0x95, 0xd0, 0x4e, 0x47, 0x0c, 0x04, 0x66, 0x77, 0xfd,
++    0xb8, 0x93, 0x0d, 0xff, 0x8f, 0x97, 0xa0, 0x4a, 0x36, 0x37,
++    0xa6, 0x5e, 0x95, 0x79, 0xc8, 0xb2, 0x21, 0x98, 0x81, 0xf1,
++    0xb8, 0xf4, 0x52, 0xaf, 0x3c, 0x8c, 0x86, 0x85, 0x55, 0x56,
++    0xfc, 0x90, 0xe3, 0x32, 0x50, 0x7c, 0x54, 0x07, 0x9e, 0xed,
++    0xfc, 0xd4, 0xb9, 0x5c, 0x98, 0x22, 0xfb, 0x72, 0xd7, 0x83,
++    0xf0, 0xd1, 0x61, 0x10, 0xbd, 0x68, 0x5d, 0x72, 0xc1, 0xce,
++    0x92, 0x43, 0x77, 0x9f, 0xb8, 0x8d, 0x8e, 0xf2, 0xe3, 0x62,
++    0x4a, 0x93, 0x03, 0xd3, 0xd9, 0x01, 0xa8, 0x99, 0x6f, 0xa3,
++    0x4c, 0x6d, 0x7a, 0xf2, 0x9e, 0x8e, 0x6b, 0xbc, 0xe4, 0x9d,
++    0x8e, 0xe7, 0x25, 0x86, 0xa4, 0xa9, 0xc2, 0xef, 0xdf, 0xbb,
++    0x6e, 0x3d, 0x4b, 0x57, 0x95, 0x81, 0x6f, 0x68, 0x3f, 0x19,
++    0xa8, 0xff, 0x5a, 0x08, 0x7a, 0xe4, 0x4c, 0x4e, 0xb4, 0xea,
++    0xf4, 0xc8, 0x2f, 0xef, 0x8c, 0x5e, 0xcd, 0x62, 0x1c, 0x8c,
++    0x93, 0x60, 0x5d, 0xa3, 0x11, 0x64, 0x0b, 0xeb, 0x6d, 0x21,
++    0xbc, 0x3a, 0x5b, 0x5c, 0x0c, 0xa7, 0x8a, 0xc6, 0xa8, 0xe1,
++    0x48, 0x81, 0x01, 0xb5, 0x65, 0xab, 0x2e, 0xbe, 0x38, 0x94,
++    0xf7, 0xa6, 0x33, 0xc1, 0x6e, 0x0b, 0x88, 0x38, 0xe7, 0x1b,
++    0x04, 0x9a, 0x10, 0x2d, 0x1d, 0x3f, 0x5f, 0x5f, 0xc8, 0xef,
++    0xcd, 0xc5, 0x16, 0xdc, 0x84, 0xc0, 0x66, 0xe0, 0xa3, 0xfc,
++    0xfa, 0x96, 0xc7, 0xb7, 0xec, 0x4f, 0x40, 0x0a, 0xc5, 0xbe,
++    0x6d, 0x39, 0x4a, 0x7e, 0x91, 0x4f, 0xe1, 0x03, 0xd2, 0x39,
++    0xbc, 0x87, 0x69, 0xa1, 0xf0, 0x6d, 0x11, 0xf5, 0xb4, 0x9d,
++    0xae, 0x76, 0x6b, 0xc6, 0xbf, 0xe4, 0x47, 0xbc, 0x4d, 0x13,
++    0x88, 0xa8, 0x83, 0xf5, 0xae, 0x1d, 0xfb, 0x4d, 0x4c, 0x44,
++    0x03, 0xd8, 0xa4, 0x2e, 0x4d, 0xf8, 0x5f, 0x45, 0x94, 0x58,
++    0xd7, 0xd9, 0x4b, 0x47, 0xd8, 0xfc, 0x35, 0x05, 0xed, 0xb4,
++    0xb6, 0xc2, 0x36, 0x2e, 0xba, 0xd2, 0x7a, 0xba, 0x69, 0x34,
++    0xbf, 0xf1, 0xa1, 0x5e, 0x17, 0x71, 0x89, 0xd3, 0x54, 0x57,
++    0x05, 0x2b, 0x82, 0xe3, 0x0a, 0x64, 0x5c, 0x3b, 0x8c, 0x6b,
++    0xc7, 0x10, 0x8a, 0xb5, 0xd3, 0xd7, 0x90, 0xeb, 0xdb, 0x1d,
++    0xa0, 0xbf, 0x6b, 0xea, 0xcd, 0x31, 0x7a, 0x8d, 0x64, 0xcc,
++    0x58, 0xc0, 0x07, 0xa4, 0x6e, 0x14, 0x0b, 0xf3, 0xea, 0x3e,
++    0x87, 0x9f, 0x7c, 0xb8, 0x1c, 0x22, 0x26, 0x8a, 0x7d, 0x90,
++    0xdd, 0x57, 0x28, 0x38, 0xcc, 0x0e, 0x71, 0x92, 0x89, 0xee,
++    0x79, 0x88, 0xbc, 0x05, 0x21, 0xda, 0x42, 0x92, 0x52, 0x66,
++    0xac, 0x4a, 0xe5, 0xf5, 0x6e, 0x47, 0xd5, 0xba, 0x37, 0xd3,
++    0x7c, 0x89, 0xd4, 0xd8, 0x6f, 0xde, 0x63, 0x44, 0xb5, 0x88,
++    0xdd, 0xb1, 0x30, 0xb4, 0x6d, 0xcd, 0xbf, 0xc8, 0x34, 0x27,
++    0x59, 0x7d, 0x79, 0xdc, 0x96, 0x5b, 0x8e, 0xc0, 0x87, 0xc0,
++    0x4e, 0x40, 0x07, 0x13, 0x91, 0x6b, 0x3a, 0x12, 0x03, 0x64,
++    0x70, 0xaf, 0x80, 0x24, 0x1c, 0x5c, 0xfb, 0xf5, 0xc0, 0x74,
++    0x5e, 0xaf, 0x06, 0x18, 0x04, 0x67, 0x4a, 0xbd, 0xac, 0xd7,
++    0xca, 0xbe, 0x4e, 0xa1, 0x19, 0x48, 0x7d, 0xa6, 0x59, 0xf6,
++    0x1a, 0x62, 0x50, 0x53, 0x46, 0xa4, 0x5b, 0x9c, 0x5a, 0xfd,
++    0x89, 0x9d, 0xd4, 0xde, 0xf4, 0xa7, 0x3d, 0x88, 0x73, 0xa5,
++    0xb9, 0x02, 0x82, 0x01, 0xe1, 0x00, 0xe7, 0x70, 0x59, 0xc3,
++    0xed, 0xc4, 0x6b, 0xa1, 0xa5, 0x5e, 0x90, 0x2a, 0x8c, 0x6a,
++    0xc2, 0x4e, 0xab, 0xfc, 0xee, 0xf2, 0x23, 0x38, 0xd6, 0xb3,
++    0x93, 0x08, 0x9e, 0x0c, 0x8e, 0x71, 0x2d, 0xa9, 0xe8, 0xdc,
++    0xa5, 0xdc, 0x07, 0xe3, 0xb1, 0x33, 0xdd, 0xa2, 0xf2, 0x3e,
++    0x92, 0x58, 0xe0, 0xf7, 0x53, 0x7f, 0x6e, 0xea, 0x78, 0x8c,
++    0x35, 0x78, 0x43, 0x63, 0x95, 0xbb, 0x1b, 0x1c, 0xbf, 0x91,
++    0x75, 0x14, 0x74, 0xd3, 0x20, 0xba, 0x8f, 0xee, 0x9d, 0x71,
++    0xa1, 0x87, 0x8a, 0x24, 0xd3, 0x61, 0x53, 0xfb, 0xec, 0x16,
++    0x84, 0xbe, 0x4d, 0x39, 0xdd, 0x0a, 0xac, 0xce, 0x20, 0x9c,
++    0xaf, 0x8a, 0x13, 0xf8, 0x22, 0x2f, 0xd4, 0x99, 0x88, 0x74,
++    0xba, 0x16, 0x3a, 0x63, 0xff, 0x4c, 0x5a, 0x03, 0x5a, 0x6f,
++    0xac, 0x29, 0x33, 0xa5, 0x50, 0xd1, 0xda, 0xed, 0x27, 0xcb,
++    0x67, 0x72, 0x63, 0x85, 0xfc, 0xf0, 0xc8, 0x88, 0xbf, 0x85,
++    0xef, 0x4b, 0xfe, 0xae, 0xd9, 0xd5, 0xbb, 0x86, 0xa4, 0x76,
++    0xe8, 0x7f, 0xb4, 0xdb, 0xb1, 0xee, 0x1a, 0x7f, 0x99, 0xd7,
++    0x9b, 0x6f, 0x7a, 0x94, 0x5c, 0xec, 0x2c, 0x60, 0x81, 0xad,
++    0xa7, 0xbe, 0x80, 0x2e, 0x9f, 0xa6, 0xc0, 0xfb, 0x09, 0x6d,
++    0x2b, 0xab, 0xa4, 0x15, 0xc7, 0x79, 0x46, 0x24, 0x89, 0x5c,
++    0x32, 0xb9, 0x87, 0xa9, 0x54, 0x1e, 0x12, 0x90, 0x8e, 0x02,
++    0x80, 0x8c, 0xf8, 0xdb, 0x2f, 0xbc, 0x98, 0x1b, 0xa2, 0x78,
++    0x73, 0x89, 0x03, 0x97, 0xe3, 0x09, 0x08, 0x8b, 0x75, 0xcf,
++    0xdc, 0x23, 0x90, 0x59, 0xef, 0x5b, 0x98, 0x24, 0xb8, 0xe8,
++    0xcf, 0x75, 0xf0, 0x2f, 0xb7, 0xa3, 0xe6, 0x17, 0x06, 0xf0,
++    0x52, 0xfe, 0x21, 0x0a, 0x16, 0x8e, 0xf8, 0xe1, 0xae, 0x25,
++    0x11, 0x5d, 0x8c, 0x95, 0x1b, 0x4f, 0x45, 0xb8, 0xa8, 0xcd,
++    0xe6, 0xf9, 0xca, 0xa0, 0x54, 0x93, 0x95, 0x86, 0x6f, 0xe4,
++    0x93, 0x22, 0x0f, 0xf2, 0xcf, 0xbd, 0x23, 0xb0, 0xf4, 0x8f,
++    0x99, 0xa7, 0x67, 0x99, 0x05, 0x13, 0x1f, 0xeb, 0x88, 0xf8,
++    0xe2, 0x3b, 0xb9, 0x49, 0x35, 0x89, 0x4f, 0xb8, 0x06, 0x37,
++    0x36, 0xda, 0x75, 0x25, 0x0f, 0x0a, 0xaa, 0xc2, 0x6c, 0x3e,
++    0xb1, 0x2d, 0x16, 0xf3, 0x17, 0xdb, 0xe2, 0x16, 0x32, 0x39,
++    0x92, 0x4b, 0x5f, 0xc0, 0x5f, 0x6e, 0xd0, 0x1c, 0x7e, 0xc0,
++    0x51, 0xd9, 0xb3, 0xe2, 0x37, 0xc7, 0xe0, 0x40, 0x13, 0x7d,
++    0x06, 0xcd, 0xcd, 0x72, 0xb6, 0x53, 0x2d, 0x7e, 0x60, 0x49,
++    0xfe, 0x31, 0xe1, 0xd0, 0x0e, 0x4c, 0x98, 0x93, 0xe0, 0xf6,
++    0xf2, 0xfa, 0x99, 0x7f, 0x65, 0xd8, 0x15, 0xc6, 0x3a, 0xb8,
++    0x4d, 0x63, 0x21, 0x78, 0xe4, 0x19, 0x6b, 0xbd, 0xde, 0x40,
++    0x5b, 0x8c, 0xfa, 0x49, 0x75, 0x23, 0x8f, 0x14, 0xc2, 0x3b,
++    0xa3, 0x9b, 0xc5, 0x80, 0x1a, 0xa3, 0x60, 0xd7, 0x17, 0x27,
++    0xf0, 0x18, 0x0f, 0xba, 0x02, 0xf7, 0x7a, 0xed, 0xa4, 0x00,
++    0x77, 0xde, 0x4b, 0xdd, 0xf9, 0xd7, 0x3e, 0x75, 0xed, 0x1a,
++    0x43, 0x26, 0x71, 0x1b, 0xbc, 0x72, 0xf5, 0x70, 0x72, 0x03,
++    0x70, 0x25, 0x87, 0x81, 0x6a, 0x92, 0x2d, 0xb7, 0x02, 0xf0,
++    0x10, 0x79, 0x65, 0x9d, 0x4e, 0x11, 0x7d, 0x5c, 0x5b, 0x37,
++    0xaa, 0xb4, 0xfa, 0x43, 0x66, 0x48, 0x6c, 0x67, 0x64, 0x9e,
++    0x15, 0x75, 0x36, 0xe7, 0x25, 0x55, 0x07, 0x7f, 0x74, 0x1f,
++    0x2c, 0x28, 0x76, 0xe7, 0x9b, 0x3d, 0x91, 0x0b, 0xcd, 0x6a,
++    0x1d, 0x5a, 0xea, 0x63, 0xd0, 0xf9, 0x02, 0x82, 0x01, 0xe0,
++    0x3e, 0x31, 0xf2, 0xf4, 0x29, 0x92, 0xa2, 0x93, 0xd5, 0xda,
++    0xc9, 0x16, 0x7e, 0xf6, 0xdb, 0x33, 0x9f, 0xaf, 0x4b, 0x01,
++    0xd1, 0x28, 0x2d, 0x3a, 0xc0, 0x51, 0x91, 0x26, 0xbd, 0xa5,
++    0x1e, 0xdd, 0xd9, 0x2e, 0x11, 0x93, 0x19, 0x29, 0x47, 0x5d,
++    0x63, 0xe4, 0xb6, 0xf1, 0xea, 0x12, 0x29, 0xa1, 0x65, 0x12,
++    0x6d, 0x78, 0x8f, 0x63, 0x31, 0xec, 0x72, 0x54, 0x73, 0x72,
++    0x26, 0x48, 0x57, 0x57, 0xc8, 0xde, 0x28, 0x27, 0xf5, 0x62,
++    0xfb, 0x7f, 0x1b, 0xf3, 0xaf, 0x31, 0x01, 0xfc, 0x01, 0x58,
++    0x7a, 0x80, 0x72, 0x9d, 0x6e, 0x07, 0xcc, 0x45, 0x67, 0xc6,
++    0x26, 0xfe, 0x25, 0xa5, 0x9b, 0x64, 0xcd, 0x45, 0xe3, 0x31,
++    0x38, 0x05, 0x07, 0x36, 0x05, 0x46, 0x9c, 0xc1, 0x8e, 0xbf,
++    0x4e, 0x71, 0x5f, 0xea, 0xe5, 0x0c, 0x9a, 0x41, 0xc8, 0x94,
++    0xcc, 0xf1, 0x73, 0x06, 0x30, 0x54, 0x76, 0x23, 0xb7, 0x22,
++    0x7a, 0x8e, 0xe6, 0x42, 0xa1, 0xa0, 0x32, 0x12, 0xe9, 0x08,
++    0x1c, 0x46, 0x79, 0x0c, 0x82, 0x7a, 0x95, 0x79, 0xbf, 0x83,
++    0x80, 0xeb, 0xab, 0x3d, 0x32, 0xc5, 0xde, 0x62, 0xeb, 0x90,
++    0x29, 0x73, 0x05, 0xc8, 0x0a, 0xb1, 0x51, 0xf1, 0x23, 0xdd,
++    0x1e, 0xf5, 0x02, 0x3e, 0x74, 0xbc, 0x24, 0x0c, 0x60, 0x36,
++    0x2a, 0x28, 0x4d, 0xe6, 0x86, 0x98, 0x7c, 0xd9, 0xe1, 0xac,
++    0x21, 0x33, 0xaa, 0xa9, 0x8b, 0xb6, 0x8a, 0x1b, 0xf7, 0x54,
++    0x14, 0xf3, 0x0d, 0x4f, 0xcd, 0x7c, 0xf5, 0xc2, 0x6d, 0xc2,
++    0xf0, 0xe2, 0xfc, 0x63, 0x1e, 0xa6, 0xa9, 0xa9, 0xd9, 0x73,
++    0x2a, 0xd5, 0x0a, 0x38, 0xd8, 0xc0, 0xb7, 0xe1, 0x51, 0xe4,
++    0x23, 0x37, 0xf7, 0x85, 0x66, 0x0e, 0x3f, 0x1a, 0x8c, 0xcf,
++    0x12, 0xa2, 0x47, 0x6f, 0x73, 0x91, 0x21, 0xe3, 0x93, 0x6b,
++    0x74, 0x4f, 0xc5, 0xa1, 0xe7, 0x32, 0xf7, 0x86, 0xdd, 0x1a,
++    0x6e, 0x96, 0xda, 0x32, 0x1d, 0xdd, 0xfa, 0x42, 0xd5, 0xd4,
++    0xfd, 0xae, 0x7a, 0xa1, 0xed, 0x3d, 0x79, 0xfe, 0x88, 0x84,
++    0x43, 0xa7, 0xec, 0xf3, 0x7a, 0x13, 0xaa, 0xa1, 0x82, 0x02,
++    0x83, 0x19, 0x43, 0x0a, 0x46, 0x78, 0x07, 0xd9, 0x4d, 0xff,
++    0xac, 0x67, 0xd6, 0x29, 0x89, 0xfe, 0x2b, 0xab, 0x5f, 0x9a,
++    0x87, 0x99, 0x80, 0xaf, 0x70, 0x4a, 0x6a, 0xb9, 0x5a, 0xc2,
++    0xac, 0x7f, 0xa2, 0xc7, 0xad, 0xe2, 0x1f, 0xec, 0xc5, 0x12,
++    0x17, 0x08, 0x87, 0x8f, 0x20, 0x95, 0xbe, 0xaf, 0x62, 0x2c,
++    0xc2, 0x3f, 0x89, 0x56, 0xd8, 0x50, 0x96, 0x97, 0x72, 0xe2,
++    0x92, 0xe1, 0x2a, 0xd8, 0x84, 0x9f, 0x31, 0xe3, 0x06, 0xd8,
++    0xe5, 0x91, 0x63, 0x19, 0xe1, 0x27, 0xad, 0xe2, 0xf2, 0x0a,
++    0x5e, 0x78, 0x8b, 0x1b, 0x13, 0x31, 0x4b, 0xbd, 0x77, 0xb2,
++    0xd6, 0x5c, 0x92, 0x81, 0x50, 0x02, 0x37, 0xd2, 0xe6, 0xeb,
++    0x66, 0x6b, 0xaa, 0xfc, 0xcd, 0x54, 0x5d, 0xb8, 0x03, 0x87,
++    0xe8, 0xfa, 0xb2, 0xde, 0xcb, 0xf8, 0x6e, 0x58, 0xde, 0xcb,
++    0x09, 0x54, 0x8a, 0x9f, 0x46, 0xa3, 0x7e, 0x8d, 0x15, 0xff,
++    0x1b, 0x0d, 0x89, 0xc4, 0x1a, 0x21, 0x31, 0x5e, 0xed, 0x0b,
++    0x67, 0x3c, 0x70, 0xed, 0x92, 0x48, 0xef, 0xec, 0xf0, 0x77,
++    0xc2, 0x79, 0x6c, 0x06, 0x09, 0xaa, 0xab, 0xf6, 0x4c, 0xcd,
++    0xfa, 0x7e, 0x4a, 0x88, 0xdc, 0xa8, 0x9b, 0xd3, 0x69, 0x94,
++    0x88, 0x09, 0x1d, 0x30, 0x43, 0x9e, 0x2c, 0xcb, 0x01, 0x1d,
++    0x4a, 0x3b, 0x04, 0xec, 0x0e, 0xb1, 0xde, 0x09, 0xad, 0x29,
++    0x02, 0x82, 0x01, 0xe1, 0x00, 0x9f, 0x02, 0x13, 0x7a, 0xd0,
++    0xa9, 0x8a, 0x7a, 0xa0, 0x05, 0xbb, 0x44, 0x6f, 0xaf, 0xf7,
++    0xe3, 0xd4, 0x35, 0xef, 0x73, 0x39, 0xd5, 0xe0, 0xa2, 0x0f,
++    0x1a, 0x25, 0xa8, 0xf7, 0xc2, 0xa5, 0xec, 0x57, 0xf8, 0x0d,
++    0x2a, 0xb6, 0x64, 0x03, 0x8c, 0x22, 0x0f, 0xe7, 0x98, 0xa1,
++    0x12, 0xfe, 0x24, 0xef, 0x61, 0x28, 0x9f, 0xa7, 0x22, 0x6b,
++    0x6d, 0xab, 0x8d, 0x7d, 0x2a, 0x8b, 0xae, 0x8b, 0xfd, 0xcb,
++    0xd5, 0x0b, 0x79, 0x1b, 0x89, 0xcb, 0x5b, 0x7a, 0x8c, 0xdc,
++    0xe8, 0x8d, 0xdd, 0x35, 0x9f, 0x06, 0x69, 0x64, 0x12, 0xeb,
++    0x46, 0x79, 0xdf, 0x82, 0x2c, 0x89, 0x75, 0x9e, 0x7a, 0xec,
++    0xad, 0xe5, 0x88, 0x31, 0xfa, 0x86, 0x93, 0xca, 0xf1, 0x2d,
++    0x9b, 0x62, 0x5a, 0xe9, 0x43, 0x09, 0xf3, 0x8c, 0xe5, 0xc7,
++    0xc0, 0xce, 0x86, 0xe7, 0xdb, 0xc7, 0x4d, 0x27, 0xd5, 0xee,
++    0x76, 0xce, 0x35, 0x30, 0x47, 0xef, 0x00, 0x1b, 0x69, 0x9a,
++    0x3f, 0xa5, 0x2a, 0xc9, 0x07, 0xab, 0x99, 0xba, 0x2a, 0xe7,
++    0xfb, 0xa9, 0x4e, 0xb9, 0xae, 0x2c, 0x50, 0xfc, 0x35, 0x49,
++    0xe6, 0x97, 0x78, 0x3c, 0xb1, 0x59, 0xd7, 0x1d, 0x4e, 0x4e,
++    0xea, 0xde, 0xa0, 0xd0, 0xc4, 0x1d, 0xb1, 0xd3, 0x53, 0x1e,
++    0xf9, 0xbf, 0xb3, 0x6a, 0x17, 0xb4, 0xda, 0xcc, 0x27, 0x19,
++    0xc6, 0x35, 0xe8, 0x28, 0xd3, 0xe3, 0x76, 0x3a, 0xdc, 0xd0,
++    0x75, 0xc8, 0xb4, 0x6c, 0xbe, 0x84, 0x2a, 0x45, 0xd1, 0x43,
++    0x22, 0x54, 0xd7, 0xc5, 0xd0, 0xd7, 0x73, 0x35, 0x6b, 0xa8,
++    0xfa, 0xad, 0x60, 0xc0, 0x64, 0xc1, 0x58, 0x89, 0x09, 0x81,
++    0x0a, 0x0b, 0xea, 0x33, 0x91, 0xb0, 0xef, 0x53, 0x50, 0x41,
++    0xae, 0xd9, 0xee, 0xbe, 0x9e, 0xf0, 0x0b, 0xa0, 0x7c, 0xbf,
++    0x3f, 0xc9, 0x4b, 0xe0, 0x48, 0xd8, 0x10, 0xd5, 0x2e, 0xce,
++    0xf0, 0x7c, 0xd8, 0x05, 0xde, 0x09, 0x7e, 0x8c, 0x63, 0x4c,
++    0xdb, 0x8b, 0x91, 0xcd, 0x7f, 0xb6, 0x6b, 0xad, 0xce, 0xb1,
++    0x17, 0x6c, 0xf7, 0x08, 0x0d, 0x7c, 0xda, 0x4f, 0x0a, 0x07,
++    0xd0, 0xae, 0x72, 0x3c, 0x67, 0x4a, 0x44, 0x54, 0x47, 0xce,
++    0xe1, 0x17, 0x07, 0x12, 0xde, 0x52, 0xef, 0xef, 0x4c, 0x2b,
++    0x42, 0x7d, 0x09, 0x80, 0x36, 0x34, 0xdc, 0x45, 0x6f, 0xb0,
++    0x2d, 0xab, 0xa0, 0x0c, 0x58, 0xae, 0x35, 0xd3, 0x9b, 0x37,
++    0xc1, 0x1d, 0xeb, 0xfe, 0xc3, 0x04, 0xc9, 0x1d, 0xe7, 0x3d,
++    0x16, 0x64, 0xed, 0xf5, 0xe8, 0xdf, 0x99, 0xa4, 0xfb, 0xad,
++    0x79, 0x88, 0xd5, 0x8c, 0x62, 0x33, 0x9e, 0x35, 0xa6, 0x7f,
++    0x9d, 0xb6, 0x1a, 0x40, 0x6d, 0xc3, 0x89, 0x5d, 0x7b, 0xe2,
++    0xc8, 0xd3, 0x16, 0x13, 0x07, 0x9a, 0x38, 0x22, 0x33, 0x03,
++    0xac, 0x70, 0x3e, 0xce, 0x32, 0x56, 0x0b, 0x58, 0x56, 0xb8,
++    0xe9, 0xd8, 0x42, 0x35, 0x6c, 0xb9, 0x02, 0xb3, 0x64, 0xeb,
++    0xaa, 0x09, 0x3f, 0xac, 0x66, 0x08, 0xb4, 0x5f, 0x3e, 0xb4,
++    0xec, 0x39, 0xb1, 0x99, 0xe4, 0x5d, 0x1d, 0x32, 0x14, 0xc1,
++    0x48, 0x8f, 0x6c, 0x65, 0x87, 0x34, 0x50, 0xa4, 0xf4, 0x9b,
++    0x5b, 0x2e, 0xb5, 0x79, 0x0d, 0x11, 0x62, 0xa4, 0x35, 0x9c,
++    0x6f, 0x92, 0xd0, 0x68, 0x07, 0xdd, 0x69, 0x85, 0x48, 0xe3,
++    0x5d, 0x10, 0x34, 0xaf, 0xea, 0x41, 0x72, 0x5a, 0x71, 0x00,
++    0xf8, 0xe6, 0x47, 0x7f, 0xa0, 0x6f, 0x91, 0x96, 0x40, 0x00,
++    0x40, 0x70, 0xfb, 0x63, 0xcf, 0xc9, 0x36, 0x04, 0x1c, 0x3b,
++    0x11, 0x08, 0x29, 0x81, 0x9f
++};
++
++static unsigned char test15360[] = {
++    0x30, 0x82, 0x21, 0xe8, 0x02, 0x01, 0x00, 0x02, 0x82, 0x07,
++    0x81, 0x00, 0xad, 0x3f, 0xaa, 0xdc, 0x8c, 0x85, 0xcb, 0x60,
++    0xd2, 0xf5, 0x30, 0xa1, 0x0f, 0x26, 0xec, 0xdf, 0xfc, 0x91,
++    0x39, 0xbd, 0x3e, 0x8f, 0x99, 0x64, 0x1e, 0x51, 0xd2, 0x27,
++    0x5e, 0x76, 0xcd, 0x86, 0x33, 0x07, 0xf9, 0xbd, 0x3b, 0x06,
++    0xc3, 0x3c, 0x85, 0xcb, 0x7e, 0x91, 0x14, 0xb0, 0x0b, 0x77,
++    0x22, 0x30, 0x71, 0xb8, 0xbb, 0x74, 0x30, 0x33, 0x35, 0x56,
++    0x34, 0x47, 0x10, 0x8f, 0x88, 0xe2, 0x6f, 0xdc, 0x3b, 0xe9,
++    0x58, 0x9d, 0x0c, 0xdc, 0x8f, 0x70, 0x41, 0x7a, 0x12, 0xd2,
++    0x9a, 0x35, 0xbe, 0x0a, 0x57, 0x13, 0x0c, 0xe9, 0xbf, 0x77,
++    0x54, 0x00, 0x74, 0xb7, 0x1a, 0x3e, 0xa7, 0xe9, 0xb6, 0xe7,
++    0x4f, 0x1e, 0xa4, 0xc0, 0x7c, 0x4c, 0x66, 0xc5, 0xce, 0xad,
++    0x96, 0x1b, 0xe2, 0x1a, 0xf1, 0x3d, 0x8b, 0x50, 0xcf, 0xe2,
++    0x15, 0x21, 0x6d, 0x83, 0x95, 0x00, 0xee, 0x97, 0xc4, 0xae,
++    0xc9, 0x38, 0x62, 0x6c, 0xb2, 0xe7, 0x7f, 0x15, 0x0a, 0xab,
++    0x86, 0xb9, 0xd9, 0x8a, 0xf8, 0xeb, 0x88, 0x5d, 0xdc, 0x0c,
++    0x1e, 0xc5, 0xe6, 0xa1, 0x7b, 0xbf, 0xf1, 0x02, 0xe3, 0xad,
++    0xf8, 0xed, 0x17, 0x9f, 0x83, 0x11, 0x31, 0x3b, 0xad, 0xb4,
++    0xf9, 0x8d, 0x1d, 0x56, 0x9b, 0xac, 0x68, 0x55, 0x0a, 0x74,
++    0x20, 0xee, 0x57, 0xe7, 0x1c, 0x6d, 0x05, 0xa1, 0x4e, 0xa5,
++    0x11, 0x99, 0xb4, 0x86, 0xdb, 0x58, 0xe7, 0xf6, 0xb6, 0x4f,
++    0x92, 0x58, 0x57, 0x9b, 0x74, 0x04, 0xe5, 0xd1, 0x1d, 0x7c,
++    0x4b, 0xb8, 0x1f, 0x5d, 0x0e, 0x93, 0xee, 0x44, 0x18, 0xb6,
++    0x58, 0x0e, 0xa1, 0x0b, 0x8e, 0x2e, 0x99, 0x4c, 0x72, 0x91,
++    0xfa, 0xfa, 0xe2, 0x22, 0x05, 0x5d, 0x2b, 0x2d, 0xd8, 0x60,
++    0xd5, 0x1b, 0x08, 0x56, 0x2b, 0xb5, 0x21, 0xdb, 0x1a, 0xe6,
++    0xa8, 0x39, 0xa2, 0xf4, 0x58, 0xcb, 0xd2, 0xf9, 0xce, 0xc0,
++    0x1e, 0x1b, 0xf9, 0xa7, 0x37, 0xca, 0xa3, 0x77, 0x6e, 0xb1,
++    0xaf, 0x33, 0xb5, 0x6d, 0x5f, 0x33, 0x2e, 0x1a, 0x34, 0xdb,
++    0x42, 0xbe, 0x5f, 0xf9, 0x09, 0xb7, 0x9f, 0xd4, 0x09, 0xfb,
++    0x87, 0x13, 0x3c, 0xe2, 0x27, 0xb8, 0xf3, 0x1d, 0x7e, 0x92,
++    0xdd, 0x87, 0x86, 0x55, 0x69, 0x9b, 0x55, 0xcd, 0xef, 0x7a,
++    0x71, 0x5d, 0x81, 0x3a, 0xd9, 0xf7, 0x7f, 0xde, 0xe0, 0x92,
++    0xd9, 0x78, 0x0f, 0x1d, 0x43, 0xb1, 0x1e, 0x29, 0xc1, 0x49,
++    0xb6, 0x5e, 0x85, 0x83, 0xd9, 0x04, 0xfd, 0x79, 0xd8, 0x47,
++    0x03, 0x2e, 0x85, 0x19, 0xfd, 0x63, 0xe7, 0xa4, 0x8b, 0xc0,
++    0x94, 0x0e, 0xb7, 0x54, 0x97, 0xd6, 0x44, 0x5d, 0x63, 0x12,
++    0xff, 0xdd, 0xde, 0x2c, 0x00, 0x0e, 0xc9, 0xca, 0x7e, 0xa2,
++    0x65, 0x25, 0xb0, 0x1d, 0xa9, 0x20, 0x4f, 0xdd, 0xea, 0x3a,
++    0xb5, 0xe8, 0x0f, 0xf3, 0xb2, 0xb7, 0x00, 0x4a, 0xe8, 0xa4,
++    0x83, 0x49, 0xbd, 0x78, 0xdf, 0xac, 0x2c, 0x37, 0x81, 0xb3,
++    0xf3, 0xb7, 0x13, 0x93, 0x3e, 0xb2, 0x79, 0x55, 0xf2, 0xd8,
++    0x9c, 0xf7, 0xf2, 0xf1, 0xd5, 0x6c, 0x9c, 0xff, 0xec, 0xf4,
++    0xea, 0x08, 0x3c, 0x65, 0x35, 0xb7, 0x09, 0x03, 0x6d, 0x99,
++    0x1d, 0x5b, 0x73, 0x06, 0x61, 0xb4, 0xf0, 0xc5, 0xdb, 0x3e,
++    0xe0, 0x1d, 0xa8, 0x5b, 0x7a, 0x5b, 0x5b, 0x9c, 0x11, 0x75,
++    0x83, 0x1d, 0xf4, 0x73, 0x27, 0xf3, 0x79, 0xf2, 0x82, 0xd6,
++    0x28, 0x45, 0x58, 0x23, 0x6c, 0x29, 0xd3, 0x50, 0x51, 0x1b,
++    0x38, 0xef, 0x89, 0x90, 0x84, 0xa2, 0x4c, 0x35, 0x7b, 0x30,
++    0x5e, 0xbd, 0x1a, 0xd5, 0xdf, 0xcd, 0xcd, 0x74, 0x3f, 0x2e,
++    0x01, 0xea, 0x33, 0x07, 0x74, 0xfb, 0x86, 0x75, 0x20, 0x0e,
++    0x4f, 0xbf, 0x65, 0xd4, 0x15, 0x19, 0x6f, 0x8d, 0x37, 0xcd,
++    0xb6, 0x6f, 0x50, 0x9d, 0x5e, 0x04, 0x81, 0x7d, 0xec, 0xd6,
++    0xbb, 0x40, 0x1b, 0xe0, 0xf5, 0xd5, 0x86, 0x26, 0xc5, 0x41,
++    0x84, 0x0e, 0x3e, 0x73, 0xb7, 0xa4, 0xbe, 0x2a, 0xfe, 0xd7,
++    0xe4, 0x4d, 0x5c, 0x2d, 0x6a, 0x04, 0xe6, 0xdd, 0x28, 0xa0,
++    0x75, 0x4c, 0xe0, 0x23, 0x2c, 0xad, 0xec, 0xaa, 0x72, 0xfd,
++    0x03, 0xc0, 0x65, 0xfa, 0xc4, 0x3c, 0x25, 0x10, 0xae, 0x3f,
++    0x09, 0x96, 0x4e, 0xff, 0xfe, 0xc7, 0xe4, 0x9e, 0xec, 0xb5,
++    0x6e, 0xec, 0xf3, 0x7a, 0x83, 0x7a, 0x8b, 0xbb, 0x91, 0x8d,
++    0xab, 0x3c, 0x4d, 0x7f, 0x34, 0x77, 0xbe, 0x0c, 0x87, 0xf2,
++    0xc3, 0xd6, 0xcb, 0xcc, 0xfa, 0x1e, 0xaf, 0x21, 0x24, 0xe9,
++    0xaa, 0x89, 0x61, 0x0c, 0x7a, 0x1c, 0x7d, 0x00, 0x87, 0x69,
++    0x30, 0xa0, 0xb4, 0x3b, 0x96, 0x1c, 0x00, 0x14, 0x07, 0xb8,
++    0x3f, 0x59, 0x62, 0x3a, 0x3f, 0xfb, 0x68, 0xb8, 0x81, 0x7d,
++    0x4a, 0x9d, 0x1c, 0xa2, 0x07, 0xa3, 0xb1, 0x42, 0x7b, 0xfa,
++    0x9b, 0xbc, 0x94, 0x30, 0x7e, 0xea, 0xe7, 0x40, 0x7e, 0xd4,
++    0x0f, 0x33, 0x3b, 0x57, 0xda, 0x8b, 0x6d, 0x64, 0xd5, 0xe4,
++    0x91, 0x83, 0xf0, 0x3d, 0xae, 0x8b, 0x91, 0xf0, 0xcd, 0xb1,
++    0xa0, 0xe0, 0x0d, 0xe1, 0xbb, 0x22, 0x78, 0x1f, 0x3a, 0xe5,
++    0x53, 0x28, 0xf0, 0x35, 0xae, 0x71, 0xe6, 0xfd, 0x63, 0xb2,
++    0x9c, 0x3f, 0xdd, 0x95, 0x7b, 0xc4, 0xe9, 0x2f, 0xd9, 0x93,
++    0x3a, 0x10, 0x42, 0x1c, 0x90, 0xab, 0xfb, 0xd3, 0x02, 0xe9,
++    0x59, 0xbc, 0x53, 0x7e, 0xf3, 0xe1, 0x52, 0x15, 0xa6, 0x58,
++    0x9e, 0xc1, 0xa6, 0x0e, 0x2e, 0x35, 0x07, 0x3a, 0xc3, 0x1f,
++    0xaa, 0x58, 0xe7, 0xc6, 0x33, 0x6a, 0x39, 0x4b, 0x21, 0x15,
++    0x3d, 0x92, 0x4e, 0x5e, 0xf9, 0x01, 0xd6, 0x0f, 0x28, 0x61,
++    0x15, 0xdf, 0xed, 0x6f, 0x75, 0xc4, 0x8f, 0xcb, 0x16, 0x55,
++    0x09, 0xc7, 0x24, 0xb2, 0x0c, 0x49, 0x25, 0x8d, 0x5e, 0xf1,
++    0x0e, 0xe0, 0xe2, 0xc4, 0xcc, 0x1f, 0x4e, 0x60, 0x5c, 0x5e,
++    0xc6, 0x7f, 0x68, 0x7f, 0xdb, 0x1a, 0x01, 0x67, 0x07, 0xb1,
++    0x56, 0x93, 0xf2, 0x26, 0x81, 0xc0, 0x33, 0xb8, 0x48, 0xf9,
++    0x2c, 0x5c, 0x18, 0x29, 0xed, 0xe0, 0x6c, 0xa0, 0xac, 0xd2,
++    0x90, 0x4b, 0x52, 0x87, 0xbb, 0xb5, 0x05, 0xd8, 0x56, 0xc5,
++    0xb8, 0x8f, 0x3f, 0x49, 0x52, 0x9a, 0xa2, 0xd0, 0x40, 0x80,
++    0x5b, 0x16, 0x15, 0xbc, 0x74, 0x8e, 0x00, 0x10, 0xaf, 0xfb,
++    0x6d, 0xba, 0xcb, 0xbc, 0xe6, 0x13, 0x75, 0xce, 0x27, 0xae,
++    0x85, 0x57, 0x6c, 0xc0, 0x8a, 0x84, 0x6f, 0x34, 0x16, 0xd4,
++    0x35, 0xd2, 0xcc, 0x55, 0x00, 0xc1, 0xd8, 0x28, 0x2c, 0x9c,
++    0x84, 0x78, 0xbf, 0xf0, 0x3b, 0x0d, 0x9f, 0x81, 0xd4, 0xef,
++    0x99, 0x77, 0x53, 0xd2, 0x8e, 0x43, 0x52, 0xf0, 0x32, 0x7e,
++    0xba, 0xbf, 0xb6, 0x0e, 0x9d, 0x9b, 0x00, 0xd0, 0x50, 0x55,
++    0x67, 0x5a, 0x2c, 0x8b, 0x9b, 0x29, 0xfb, 0x41, 0x74, 0x4c,
++    0xb7, 0xd8, 0x98, 0xa2, 0xfb, 0x73, 0x07, 0x96, 0xef, 0xcd,
++    0x47, 0x13, 0x1d, 0xe2, 0xb1, 0xac, 0xf3, 0xcf, 0x47, 0x98,
++    0x7b, 0x6f, 0xf6, 0x32, 0x44, 0x41, 0x78, 0x09, 0x8e, 0x64,
++    0x0c, 0xbf, 0xe2, 0x0f, 0x8c, 0x44, 0x2f, 0x4e, 0x55, 0xe0,
++    0xc6, 0xfd, 0x05, 0x74, 0x18, 0x1a, 0xb9, 0xfa, 0xcb, 0xd3,
++    0xfa, 0x69, 0x50, 0x63, 0xce, 0x2b, 0xef, 0x92, 0x0f, 0x11,
++    0xd4, 0x9b, 0x53, 0x6c, 0xed, 0xc5, 0x0b, 0x7c, 0xbd, 0xa1,
++    0x5d, 0xdf, 0xab, 0xcf, 0xaa, 0x83, 0x5e, 0xa8, 0xc5, 0xfe,
++    0x91, 0x2b, 0x23, 0x1f, 0x39, 0x3d, 0x71, 0x74, 0xbf, 0xa2,
++    0xf1, 0xda, 0x2f, 0x29, 0x02, 0x9b, 0xea, 0x48, 0x2c, 0xaf,
++    0xe7, 0xa9, 0xf5, 0x68, 0xab, 0x8f, 0x18, 0xb9, 0x7b, 0x28,
++    0xf0, 0x92, 0xfb, 0x07, 0xd7, 0xbd, 0x43, 0xcd, 0x7f, 0xfc,
++    0xb9, 0x5f, 0x24, 0xf8, 0x48, 0x2e, 0xbe, 0x42, 0x87, 0x80,
++    0x38, 0x78, 0x9e, 0x8c, 0x52, 0x6d, 0xfa, 0x2e, 0x46, 0x35,
++    0x7a, 0x59, 0x88, 0xb9, 0x3e, 0xcb, 0x79, 0xb4, 0x8a, 0x9e,
++    0xd5, 0xd0, 0x30, 0x8c, 0xb2, 0x0c, 0x9d, 0x8d, 0x2d, 0x64,
++    0x0b, 0xf6, 0xeb, 0xf1, 0xde, 0xea, 0x74, 0xfc, 0xbc, 0x01,
++    0x18, 0x48, 0x4e, 0x35, 0x02, 0x83, 0x01, 0xb2, 0x50, 0xa0,
++    0x44, 0x19, 0x30, 0x00, 0x12, 0x4a, 0xa0, 0x6d, 0x6b, 0x8b,
++    0xf1, 0xce, 0xda, 0x2e, 0x16, 0x35, 0x52, 0x26, 0xf9, 0xbe,
++    0xb1, 0x37, 0xfc, 0x0a, 0x8b, 0x6f, 0x06, 0x11, 0x7b, 0xf7,
++    0xa8, 0x40, 0xbd, 0x8d, 0x94, 0xa4, 0xa2, 0xe0, 0xb6, 0xdf,
++    0x62, 0xc0, 0x6f, 0xb3, 0x5d, 0x84, 0xb9, 0xaa, 0x2f, 0xc1,
++    0x3b, 0xcb, 0x20, 0xc6, 0x68, 0x69, 0x15, 0x74, 0xbc, 0xdb,
++    0x43, 0x9c, 0x4a, 0xfc, 0x72, 0xc1, 0xf5, 0x87, 0x80, 0xe8,
++    0x6c, 0xd5, 0xc1, 0x2e, 0x34, 0x5e, 0x96, 0x76, 0x08, 0x3e,
++    0x45, 0xe4, 0xa0, 0x4a, 0x7a, 0xc1, 0x67, 0x38, 0xf2, 0x31,
++    0x1f, 0x7b, 0x0f, 0x54, 0xbd, 0x0d, 0x1f, 0x9e, 0x8e, 0x99,
++    0x8b, 0x58, 0xd9, 0x94, 0x87, 0xaa, 0x8b, 0x82, 0x5d, 0x5e,
++    0xe8, 0x50, 0xf4, 0xf2, 0xc7, 0xe9, 0x85, 0x6b, 0xd2, 0xef,
++    0x13, 0xc1, 0xed, 0x57, 0x2a, 0xc5, 0xd6, 0x5d, 0xa4, 0x3b,
++    0x29, 0xba, 0xab, 0x1b, 0xaa, 0x21, 0x41, 0xe9, 0xdc, 0x47,
++    0x88, 0xef, 0x0c, 0xfc, 0xb2, 0xdc, 0xf7, 0xdb, 0x55, 0x4d,
++    0x70, 0xc7, 0xe2, 0x8a, 0x8a, 0xe1, 0xde, 0xcf, 0xe5, 0xca,
++    0x23, 0x36, 0x29, 0xe5, 0xfc, 0x54, 0x66, 0xda, 0xe9, 0xab,
++    0x58, 0x20, 0xb2, 0x8e, 0xb2, 0x7d, 0x5d, 0xb8, 0xc7, 0x6c,
++    0x48, 0x53, 0x2b, 0x47, 0xe0, 0x12, 0x00, 0x0e, 0xfe, 0xa5,
++    0x93, 0x34, 0xf9, 0x3e, 0xa6, 0x3f, 0x56, 0xaa, 0x43, 0x65,
++    0xbb, 0x5a, 0x70, 0x3e, 0x62, 0xac, 0x3f, 0x5b, 0x90, 0x02,
++    0x50, 0x5d, 0x05, 0xa8, 0xd5, 0x67, 0x1a, 0x62, 0xec, 0xd4,
++    0xde, 0x29, 0x04, 0xac, 0x6d, 0x15, 0x5d, 0xa0, 0xec, 0xf2,
++    0x57, 0x13, 0x0e, 0x17, 0x96, 0x0c, 0x32, 0x6a, 0xc5, 0xe0,
++    0xa8, 0xff, 0x85, 0xa4, 0xa3, 0xe3, 0x0e, 0x35, 0x5d, 0xd1,
++    0x28, 0x84, 0xaa, 0xc4, 0x84, 0xcd, 0x25, 0x63, 0x85, 0x82,
++    0x3e, 0x12, 0x30, 0x17, 0x57, 0x45, 0xb8, 0xb4, 0x34, 0x01,
++    0x3a, 0xa2, 0x77, 0x61, 0xc8, 0x3d, 0x1f, 0xc5, 0x0e, 0x4a,
++    0xbb, 0xf6, 0xa0, 0x5d, 0x79, 0x4b, 0xc8, 0xf3, 0x9c, 0x87,
++    0x05, 0x2f, 0xea, 0x25, 0x28, 0x91, 0x69, 0x77, 0x7c, 0xba,
++    0xea, 0x4a, 0x75, 0x2e, 0x2b, 0x17, 0x83, 0x50, 0x32, 0x43,
++    0x4f, 0xcd, 0xf1, 0x77, 0xb1, 0x22, 0x0a, 0x8b, 0x69, 0x58,
++    0x09, 0x35, 0x07, 0x6d, 0x61, 0x4a, 0x8d, 0x18, 0x65, 0x6e,
++    0x9b, 0x62, 0x07, 0xd0, 0x6a, 0x92, 0x39, 0x05, 0x80, 0x14,
++    0xfa, 0x1c, 0x93, 0x84, 0x0c, 0xb5, 0x8c, 0x41, 0x91, 0x4e,
++    0x48, 0xf0, 0xf2, 0xba, 0x1d, 0x73, 0x2f, 0x1e, 0xa1, 0x55,
++    0xc3, 0x02, 0x8c, 0xb1, 0xf2, 0x37, 0xa6, 0x9a, 0x6b, 0xcd,
++    0x45, 0x2e, 0x08, 0x90, 0x26, 0x63, 0x91, 0xff, 0x22, 0x5e,
++    0xcd, 0xae, 0x9b, 0x19, 0x1e, 0x10, 0x62, 0x4e, 0x1f, 0x2d,
++    0x81, 0x69, 0x4f, 0x41, 0xe5, 0x94, 0xff, 0x7e, 0xcc, 0x15,
++    0x36, 0x1e, 0x29, 0x59, 0x37, 0xe7, 0x64, 0x40, 0x17, 0x1a,
++    0x32, 0xba, 0x01, 0x26, 0x30, 0x80, 0x60, 0x07, 0x86, 0x6e,
++    0xd4, 0xb3, 0xe2, 0x44, 0x16, 0x33, 0xf2, 0x4c, 0x84, 0x0e,
++    0xb1, 0x4a, 0xc7, 0x92, 0xa6, 0xa3, 0x42, 0x36, 0x05, 0x3e,
++    0x74, 0xa8, 0xb1, 0xc5, 0x63, 0x59, 0x0d, 0x1e, 0x36, 0x45,
++    0x2b, 0x36, 0x5e, 0xca, 0xab, 0x97, 0x49, 0xd3, 0xab, 0xae,
++    0x63, 0x0a, 0xd1, 0x03, 0x57, 0x88, 0xa4, 0xa4, 0x3c, 0xda,
++    0x15, 0x49, 0x1a, 0x5d, 0xe6, 0x5e, 0xb9, 0x82, 0x23, 0xc0,
++    0x83, 0x96, 0xfe, 0x38, 0x0b, 0x80, 0x0e, 0xde, 0x22, 0xeb,
++    0x5d, 0xe4, 0x56, 0x32, 0xbe, 0xe0, 0xc0, 0x6e, 0x69, 0x63,
++    0x27, 0x4e, 0x00, 0x58, 0x80, 0x70, 0xd9, 0xcc, 0x4e, 0xae,
++    0x6c, 0x5e, 0x6a, 0x43, 0x81, 0xfd, 0x45, 0xb2, 0xa4, 0x6c,
++    0xf0, 0x9c, 0x66, 0x5c, 0x7d, 0x5c, 0x78, 0x55, 0x33, 0x4b,
++    0x3c, 0x3b, 0x1d, 0x18, 0x58, 0x79, 0x6a, 0x02, 0xec, 0xce,
++    0x53, 0x69, 0xc0, 0x17, 0xed, 0x57, 0xaf, 0x71, 0x5b, 0x42,
++    0x1b, 0x49, 0xd8, 0xe8, 0x96, 0x80, 0xb6, 0x48, 0x1b, 0x7c,
++    0xf8, 0x74, 0x1c, 0xb1, 0xc4, 0x10, 0xb7, 0xf4, 0x97, 0x7e,
++    0x6b, 0x8f, 0x54, 0xba, 0x37, 0xb9, 0x35, 0x9e, 0x7b, 0x17,
++    0x16, 0x9b, 0x89, 0x39, 0xae, 0x4f, 0x2e, 0x18, 0x65, 0xb4,
++    0x76, 0x20, 0x9a, 0x58, 0xe2, 0x57, 0x6e, 0x1c, 0x3f, 0x8e,
++    0x9a, 0xbb, 0xd8, 0xfc, 0x4c, 0xd6, 0x2d, 0xc1, 0xa6, 0x46,
++    0xac, 0x13, 0x1e, 0xa7, 0xf7, 0x1d, 0x28, 0x3a, 0xf4, 0xd6,
++    0x48, 0xfb, 0xe5, 0xb3, 0x84, 0x94, 0x47, 0x92, 0xae, 0x9a,
++    0x58, 0xc5, 0xac, 0x23, 0x1b, 0xb5, 0xcd, 0x96, 0xd2, 0x5e,
++    0xb2, 0x41, 0xfc, 0x9a, 0xae, 0x19, 0xf1, 0x7b, 0x4b, 0x53,
++    0x1b, 0xfa, 0xa5, 0x0c, 0x49, 0x6d, 0xff, 0xf4, 0x51, 0x88,
++    0x19, 0x04, 0xd9, 0x85, 0x8e, 0xe2, 0x3a, 0x62, 0x31, 0x5c,
++    0x6e, 0xe8, 0x4d, 0x04, 0x1d, 0xd8, 0xc2, 0x7b, 0x51, 0xe7,
++    0x59, 0xbc, 0x85, 0x5c, 0xc4, 0xcc, 0xad, 0xcb, 0x93, 0x69,
++    0x18, 0xe4, 0x71, 0x9e, 0x63, 0x33, 0x99, 0xb6, 0x3b, 0x23,
++    0x11, 0x17, 0x7a, 0x3d, 0x6f, 0xb9, 0x6b, 0xf1, 0xf2, 0xa7,
++    0x03, 0xfd, 0xf0, 0xcd, 0x5b, 0xb5, 0xda, 0x9a, 0xd9, 0x95,
++    0x02, 0x76, 0xd8, 0x38, 0xd3, 0xbd, 0xa0, 0x4a, 0x9a, 0xab,
++    0x70, 0xde, 0xc6, 0xf9, 0xa5, 0x19, 0x9c, 0xc4, 0xf9, 0x07,
++    0x4d, 0xea, 0x15, 0xc2, 0x91, 0x4d, 0x54, 0xa9, 0x2c, 0xca,
++    0xdf, 0xaa, 0xd1, 0xc4, 0xc0, 0x18, 0x77, 0x28, 0x2a, 0x2c,
++    0xc3, 0x7c, 0x26, 0xbd, 0xd8, 0x0d, 0x51, 0xa1, 0x4d, 0xad,
++    0x76, 0x76, 0xaa, 0xa9, 0x45, 0x82, 0x4f, 0x76, 0xfb, 0x1a,
++    0xd3, 0x71, 0x3c, 0x55, 0xa2, 0x5c, 0xe0, 0xd6, 0xda, 0x35,
++    0xbe, 0x25, 0x23, 0x26, 0x51, 0xc6, 0xb4, 0xf3, 0x3e, 0x2c,
++    0x54, 0x09, 0xc7, 0x6f, 0xa5, 0x08, 0x81, 0xba, 0x75, 0xda,
++    0xcb, 0x4d, 0x05, 0xdd, 0xca, 0x93, 0x48, 0x30, 0xe8, 0x4a,
++    0x1f, 0xfd, 0x02, 0x03, 0x01, 0x00, 0x01, 0x02, 0x82, 0x07,
++    0x80, 0x25, 0x2f, 0xbc, 0x49, 0xf8, 0xb3, 0xa3, 0x32, 0xd6,
++    0x35, 0x20, 0xca, 0x01, 0x49, 0x96, 0xa0, 0x81, 0x42, 0xde,
++    0xc4, 0xdb, 0x0f, 0xd1, 0x99, 0xe6, 0xd4, 0x23, 0x2a, 0xa6,
++    0x21, 0x13, 0xfe, 0x51, 0x27, 0xce, 0x18, 0x2a, 0xfa, 0x49,
++    0x9f, 0xcd, 0x0c, 0x1f, 0xcf, 0x9e, 0x44, 0x27, 0x41, 0xdc,
++    0x09, 0xcf, 0xef, 0x19, 0xf5, 0x57, 0x7f, 0x36, 0x5c, 0x99,
++    0x7e, 0x03, 0x74, 0xfb, 0xa9, 0xb6, 0xde, 0xeb, 0xd1, 0x2b,
++    0x5f, 0x12, 0x6a, 0xa9, 0x33, 0x2c, 0x2a, 0xba, 0xad, 0x8f,
++    0xc2, 0x27, 0x57, 0x6a, 0xd7, 0x40, 0xf7, 0x4f, 0x4c, 0x9a,
++    0xb0, 0x3a, 0x5d, 0x2e, 0xf9, 0xf1, 0xea, 0xbd, 0x82, 0xaa,
++    0xbd, 0xe6, 0x19, 0x16, 0xd5, 0x03, 0x5e, 0x43, 0xfd, 0x88,
++    0x71, 0xd5, 0xb7, 0x78, 0xbe, 0x80, 0x0f, 0xc9, 0x7f, 0x3a,
++    0x8f, 0xe1, 0x44, 0xd4, 0x0f, 0xce, 0x26, 0xaf, 0x65, 0xe0,
++    0xf5, 0x04, 0x53, 0x56, 0x97, 0x4f, 0xf4, 0xc1, 0x44, 0x8d,
++    0xf7, 0x88, 0x55, 0x47, 0x16, 0xaf, 0x3f, 0x8e, 0x42, 0xdf,
++    0xbc, 0x14, 0xc3, 0xe6, 0x9f, 0x0d, 0x69, 0x54, 0x5b, 0x7c,
++    0x49, 0xcf, 0xbf, 0x42, 0x4f, 0xc7, 0x64, 0x8a, 0xe5, 0x84,
++    0x87, 0x20, 0x9b, 0xfd, 0x70, 0x25, 0x38, 0xd3, 0xb4, 0x97,
++    0x78, 0xf1, 0x4f, 0x3f, 0x0f, 0xbb, 0x9c, 0xa3, 0x17, 0xd5,
++    0x4e, 0x4b, 0xac, 0x82, 0x9a, 0x73, 0xb7, 0xc5, 0xec, 0x10,
++    0x7a, 0x7b, 0xdb, 0x77, 0x2c, 0xb1, 0xf3, 0x8f, 0xc3, 0xa5,
++    0x31, 0x11, 0x32, 0x55, 0x35, 0xb5, 0x77, 0xd2, 0x62, 0x19,
++    0x46, 0x92, 0x94, 0xbb, 0x61, 0x0f, 0x30, 0x94, 0x8a, 0xf6,
++    0xf7, 0x30, 0xe0, 0xa2, 0x8c, 0x1b, 0xff, 0x8c, 0x29, 0x44,
++    0xb4, 0xb7, 0xb6, 0x5f, 0x4d, 0x52, 0xc6, 0x07, 0xe1, 0x28,
++    0x8c, 0xae, 0x88, 0x8a, 0x22, 0xbd, 0xd7, 0x36, 0xe4, 0x8f,
++    0xd1, 0xeb, 0x65, 0x54, 0x19, 0x5f, 0xba, 0xfb, 0xfc, 0x91,
++    0xa1, 0xa4, 0xb8, 0xa4, 0x2d, 0x85, 0x20, 0xc4, 0xe5, 0xa7,
++    0x4e, 0xdb, 0xa4, 0xc5, 0xcc, 0x2f, 0x37, 0x41, 0x29, 0x47,
++    0x15, 0xff, 0x04, 0x80, 0x08, 0x37, 0xce, 0xc5, 0xe3, 0x5a,
++    0x3f, 0x83, 0xbb, 0x03, 0x9e, 0xfe, 0xec, 0xe4, 0x11, 0x41,
++    0x12, 0x13, 0xf2, 0x00, 0xe5, 0x1a, 0x02, 0x49, 0xeb, 0xdb,
++    0x57, 0xe4, 0xce, 0xa0, 0x3f, 0xfd, 0x3c, 0x73, 0x2b, 0x92,
++    0x44, 0x79, 0x9e, 0x12, 0x4f, 0xfa, 0xe4, 0x53, 0x62, 0xf2,
++    0xb0, 0xe2, 0x8a, 0xf0, 0x93, 0xa8, 0x1d, 0xee, 0x8d, 0x58,
++    0x7a, 0x4c, 0x29, 0x91, 0x29, 0xc1, 0xa4, 0xd5, 0xe6, 0x37,
++    0x1b, 0x75, 0x5b, 0xb6, 0x6b, 0x76, 0x2e, 0xcb, 0xbd, 0xa9,
++    0xbe, 0x4c, 0x2e, 0x21, 0xa6, 0x38, 0xde, 0x66, 0x2f, 0x51,
++    0xea, 0x4c, 0xba, 0x3f, 0x4a, 0xfe, 0x7a, 0x15, 0xb3, 0x72,
++    0x26, 0xba, 0xcf, 0x9e, 0x1b, 0x03, 0xa6, 0xaa, 0x65, 0x68,
++    0xd3, 0x8c, 0x15, 0x17, 0xe9, 0x11, 0x18, 0x3c, 0xb6, 0xf8,
++    0x02, 0x54, 0x98, 0x49, 0xfa, 0x35, 0x3c, 0xcd, 0xac, 0xc8,
++    0x2b, 0x1a, 0x63, 0x93, 0x03, 0x05, 0xa1, 0x41, 0xbe, 0x12,
++    0xca, 0x15, 0x47, 0x72, 0x63, 0x77, 0x26, 0xd0, 0xe7, 0x8f,
++    0x0d, 0x6e, 0x9c, 0xac, 0x07, 0xbe, 0x03, 0x22, 0xd0, 0x39,
++    0x63, 0x8d, 0x9b, 0xc6, 0x20, 0x81, 0xb5, 0x67, 0x15, 0xf6,
++    0xb0, 0xe3, 0xb9, 0x3e, 0xb7, 0x3f, 0x8f, 0x46, 0xc9, 0x74,
++    0x10, 0x1e, 0x53, 0xf1, 0xd4, 0x30, 0x4d, 0x6e, 0x72, 0xb4,
++    0x73, 0x1c, 0xb6, 0x79, 0x82, 0x60, 0x2e, 0x2a, 0x7d, 0x82,
++    0x95, 0xb5, 0x7c, 0x4d, 0x44, 0xcb, 0xd8, 0x8a, 0x17, 0xe8,
++    0x50, 0x29, 0xd8, 0x3a, 0xeb, 0x29, 0xc1, 0x83, 0x0f, 0xd9,
++    0xaf, 0xcc, 0xfa, 0xea, 0x3a, 0x47, 0x5d, 0x33, 0x1f, 0xe8,
++    0x33, 0x5b, 0x88, 0x8e, 0xdb, 0xd5, 0x1e, 0xaf, 0x4a, 0x5f,
++    0xc0, 0xfa, 0xf0, 0xb5, 0xa3, 0x5b, 0xda, 0x38, 0xb7, 0x38,
++    0x5e, 0xce, 0x81, 0x44, 0xf7, 0x66, 0x62, 0x64, 0x1d, 0x04,
++    0xf0, 0x8a, 0x4f, 0xa2, 0x80, 0x76, 0x83, 0x23, 0x89, 0x61,
++    0x6b, 0xc3, 0xb7, 0xee, 0xb5, 0x06, 0x33, 0xad, 0x63, 0x04,
++    0x78, 0xc9, 0xde, 0x32, 0xde, 0xcf, 0x18, 0xb9, 0xb0, 0x3b,
++    0xee, 0x0a, 0x58, 0xea, 0xad, 0xbc, 0x1e, 0x77, 0xa0, 0x93,
++    0xf7, 0xae, 0x9e, 0xb6, 0x31, 0x59, 0x8e, 0xb1, 0x03, 0x8f,
++    0xbb, 0xa4, 0x25, 0x0c, 0x2e, 0xd7, 0xe2, 0x62, 0x5c, 0xf1,
++    0x68, 0xe9, 0x76, 0xd7, 0x23, 0x14, 0x45, 0xaf, 0xcb, 0x09,
++    0x50, 0x05, 0x3f, 0xa0, 0xf9, 0xc3, 0x9e, 0x89, 0x05, 0xa8,
++    0x3b, 0x54, 0x55, 0x32, 0x74, 0x91, 0x46, 0xc1, 0x2c, 0x96,
++    0x7e, 0x60, 0xad, 0xfa, 0xbb, 0xcd, 0x09, 0x7b, 0x39, 0x10,
++    0x82, 0x8a, 0xc0, 0x5a, 0x0d, 0xab, 0xb3, 0x71, 0x45, 0xad,
++    0x39, 0x8e, 0xec, 0x4d, 0x91, 0x8d, 0xda, 0x8d, 0xfa, 0xb0,
++    0xad, 0x44, 0x3c, 0xc9, 0x21, 0x56, 0x22, 0xfc, 0xd3, 0xba,
++    0xb7, 0x3c, 0xe3, 0x8d, 0xda, 0x59, 0x34, 0x42, 0xdd, 0x04,
++    0x5b, 0x8e, 0x2b, 0xc7, 0x94, 0xd5, 0x42, 0xe0, 0x4a, 0x6f,
++    0x35, 0x5a, 0x27, 0x82, 0xd8, 0x82, 0x40, 0xee, 0x0f, 0xa6,
++    0xef, 0xe4, 0x70, 0xe3, 0x30, 0xb7, 0x2d, 0xd4, 0xbb, 0x27,
++    0xb2, 0xbf, 0xad, 0x49, 0x45, 0xbc, 0xeb, 0xbe, 0xb7, 0xd8,
++    0xe3, 0xb1, 0xf3, 0xeb, 0x41, 0x20, 0x9b, 0x21, 0x54, 0xc3,
++    0xa8, 0xaf, 0x9f, 0x20, 0x5c, 0x15, 0x8e, 0x25, 0xbc, 0xbc,
++    0x69, 0x91, 0xfe, 0xda, 0xad, 0xe5, 0x37, 0x7d, 0xb0, 0x51,
++    0x14, 0xae, 0x8f, 0x35, 0x15, 0x0a, 0xd4, 0x49, 0xa7, 0xd9,
++    0x20, 0x70, 0xa4, 0xf2, 0xf4, 0x24, 0x66, 0x52, 0xd1, 0xa5,
++    0x22, 0xea, 0x29, 0xd9, 0xb2, 0x82, 0x8d, 0x36, 0x66, 0x75,
++    0x6e, 0xd5, 0x8c, 0x54, 0x08, 0x21, 0xf2, 0xee, 0x78, 0xc7,
++    0x1f, 0x9c, 0x63, 0x5d, 0x88, 0x56, 0xd1, 0xa0, 0x80, 0x33,
++    0x60, 0x55, 0x23, 0x72, 0xd6, 0xb0, 0x1a, 0x50, 0xde, 0x25,
++    0x70, 0xb5, 0x77, 0x42, 0xf8, 0x19, 0x18, 0x15, 0x8f, 0xfd,
++    0x0c, 0x6a, 0x46, 0x1f, 0xbf, 0xe7, 0x60, 0x91, 0xe7, 0xbb,
++    0x25, 0x63, 0x66, 0xff, 0x11, 0x97, 0xbb, 0xfd, 0x3a, 0x17,
++    0x94, 0x77, 0xb4, 0xc5, 0x21, 0xba, 0x30, 0x94, 0xdd, 0xe5,
++    0xeb, 0x1d, 0x01, 0xba, 0xf9, 0xb0, 0x30, 0xdb, 0x11, 0x93,
++    0xb7, 0xfa, 0x79, 0xe8, 0x5e, 0xb3, 0x39, 0xf4, 0x51, 0x68,
++    0x31, 0xce, 0xe9, 0x0e, 0x93, 0xde, 0xff, 0xec, 0x27, 0xbd,
++    0xa6, 0x1a, 0x4c, 0xe0, 0x92, 0x5c, 0xd4, 0x07, 0xd2, 0xa1,
++    0xdd, 0x12, 0x83, 0xd2, 0x9a, 0x79, 0xb3, 0x3c, 0xfb, 0x07,
++    0xe3, 0x18, 0x1a, 0xa3, 0x24, 0x80, 0xb4, 0xcc, 0xf4, 0xc6,
++    0xa5, 0x6c, 0x25, 0xd7, 0x99, 0x1a, 0x30, 0xf0, 0xa9, 0xfc,
++    0x2e, 0x83, 0x44, 0xac, 0x64, 0x76, 0x34, 0xb0, 0xa6, 0x6f,
++    0x20, 0x5a, 0x14, 0xf2, 0x07, 0xa7, 0x6f, 0x4d, 0xab, 0xf5,
++    0xfc, 0x9d, 0xd6, 0x3e, 0x82, 0x48, 0x31, 0x25, 0x47, 0xc9,
++    0x0e, 0x1d, 0xdb, 0x98, 0x91, 0x56, 0xf5, 0xfe, 0x66, 0x8d,
++    0x48, 0xf0, 0x4c, 0x6c, 0x2c, 0x96, 0x54, 0x43, 0xec, 0x76,
++    0xf2, 0xe1, 0x76, 0x68, 0xc8, 0xe1, 0xde, 0x0d, 0x8e, 0x6f,
++    0xfc, 0x15, 0xd5, 0x93, 0x92, 0xfe, 0xca, 0x9b, 0x30, 0x61,
++    0x03, 0x0b, 0xca, 0x99, 0x2f, 0xd3, 0x15, 0xe9, 0x66, 0x81,
++    0xbd, 0x56, 0x17, 0x14, 0x4a, 0x2e, 0xf1, 0x34, 0x84, 0x55,
++    0x9d, 0xc0, 0x2b, 0xa7, 0x4a, 0xee, 0xf1, 0x7c, 0x67, 0xc7,
++    0xf3, 0x08, 0x1e, 0x6d, 0x6b, 0x5b, 0xcc, 0x81, 0x91, 0x5c,
++    0x94, 0x1a, 0x80, 0xda, 0x3a, 0xce, 0x36, 0x05, 0xb0, 0x7a,
++    0xe8, 0xd0, 0xb4, 0x57, 0x9c, 0xf9, 0xea, 0xf3, 0x26, 0x1d,
++    0xcb, 0xf8, 0xdd, 0x65, 0xaf, 0xf7, 0xcd, 0xf7, 0xa1, 0x3d,
++    0xfc, 0x9a, 0x3b, 0x08, 0xb9, 0xfa, 0x3c, 0x16, 0x49, 0x4a,
++    0xf1, 0xba, 0x4d, 0x31, 0xdd, 0x5e, 0x4f, 0x3d, 0x66, 0x22,
++    0x1b, 0x08, 0x91, 0x7d, 0xc6, 0xaf, 0x15, 0x07, 0x3c, 0xa1,
++    0xf7, 0x07, 0xfd, 0x3e, 0x90, 0xbb, 0x6f, 0x7a, 0xe9, 0xe1,
++    0x2f, 0xb9, 0xee, 0x91, 0x8e, 0x18, 0xcc, 0x8d, 0x1d, 0x22,
++    0xa0, 0xa0, 0x28, 0x25, 0xfc, 0xd4, 0x94, 0xd3, 0xaa, 0xcf,
++    0xce, 0xd0, 0x85, 0x82, 0x6f, 0x20, 0x9f, 0x55, 0x0e, 0xe5,
++    0x72, 0x0d, 0x17, 0x3e, 0x34, 0xc7, 0x2c, 0x0a, 0x14, 0x45,
++    0x27, 0xe2, 0xc7, 0x2f, 0x86, 0xa1, 0x55, 0x3e, 0x78, 0x03,
++    0xe9, 0x78, 0x2e, 0xd3, 0x99, 0xee, 0xa0, 0x14, 0xf8, 0xe3,
++    0x6c, 0xeb, 0x3f, 0x9a, 0xf3, 0x15, 0xce, 0xd5, 0x76, 0xf6,
++    0x3a, 0x86, 0x30, 0x76, 0xf9, 0x88, 0x30, 0xf5, 0x4a, 0x50,
++    0x58, 0x80, 0xe9, 0xd9, 0xd4, 0xb9, 0x34, 0x42, 0xa6, 0x4e,
++    0x9c, 0x1a, 0x07, 0x16, 0x9e, 0xee, 0xe4, 0x88, 0x04, 0x8e,
++    0xa8, 0xe7, 0xcd, 0xe8, 0x47, 0x1e, 0x54, 0x45, 0xd2, 0x65,
++    0xd8, 0xee, 0x4b, 0xbd, 0xd0, 0x85, 0xaa, 0xfb, 0x06, 0x53,
++    0x91, 0x7e, 0xe0, 0x59, 0x20, 0x57, 0x6a, 0xee, 0xd8, 0x9f,
++    0x77, 0x7f, 0xd7, 0x40, 0x63, 0xbb, 0x21, 0x75, 0x76, 0x11,
++    0x27, 0xcf, 0x05, 0xbb, 0x41, 0x30, 0x98, 0xbf, 0xdc, 0x5f,
++    0xc6, 0xa4, 0x1e, 0x30, 0xa1, 0x53, 0xd4, 0x36, 0x7f, 0x2e,
++    0x86, 0xd7, 0xd9, 0x95, 0x29, 0xd5, 0x46, 0x18, 0x60, 0x27,
++    0xe4, 0x6f, 0xcb, 0xf4, 0xe2, 0xfe, 0xff, 0x3e, 0xff, 0x15,
++    0xc6, 0xf2, 0x31, 0xf9, 0x2a, 0xc8, 0x05, 0x4e, 0x7c, 0x2e,
++    0x92, 0xc8, 0x41, 0x4f, 0x9e, 0x23, 0x21, 0x4d, 0x74, 0xf8,
++    0xc3, 0x44, 0x39, 0xc2, 0x69, 0x4b, 0x2e, 0x76, 0x5e, 0x44,
++    0x12, 0x65, 0x31, 0x98, 0xbe, 0x0a, 0x10, 0x11, 0x12, 0x2c,
++    0x67, 0x3d, 0x85, 0x2e, 0xd3, 0x97, 0x54, 0x1e, 0xb6, 0xad,
++    0xd9, 0x45, 0x11, 0x53, 0x04, 0x7c, 0x3f, 0xf4, 0xc9, 0xac,
++    0x82, 0x1b, 0x84, 0xf4, 0x20, 0x6b, 0xf1, 0xf5, 0x72, 0x04,
++    0x24, 0xc1, 0xd3, 0x42, 0x43, 0x52, 0x9d, 0x2d, 0xd3, 0x89,
++    0x8e, 0xd8, 0x28, 0xb9, 0xa2, 0xb4, 0xed, 0xbc, 0x76, 0x87,
++    0x55, 0x67, 0x39, 0xd9, 0xb7, 0x20, 0x6a, 0xec, 0xec, 0xb8,
++    0x14, 0x51, 0x91, 0xb9, 0x96, 0x0f, 0x7a, 0x3a, 0x12, 0xde,
++    0x14, 0x3b, 0x83, 0xcf, 0x41, 0x5b, 0x5d, 0xff, 0x33, 0x68,
++    0xdb, 0x53, 0x64, 0x93, 0xb1, 0xc3, 0x8a, 0x46, 0xa8, 0x44,
++    0x9c, 0x14, 0x12, 0x6c, 0x92, 0x6f, 0xae, 0xc3, 0x45, 0xb2,
++    0xa1, 0x67, 0x81, 0x3c, 0x22, 0x47, 0xfd, 0xa4, 0x7a, 0x79,
++    0xa8, 0x0a, 0xfb, 0x7a, 0x91, 0x6e, 0xe9, 0x53, 0xec, 0x98,
++    0x82, 0x57, 0xad, 0x05, 0x38, 0x55, 0xc1, 0xce, 0x3a, 0x04,
++    0x4d, 0x12, 0x72, 0x37, 0x4a, 0x36, 0x54, 0x3f, 0x67, 0x8a,
++    0xee, 0xd9, 0xf3, 0x80, 0xd5, 0xd7, 0xb8, 0xfc, 0x6e, 0x4f,
++    0x60, 0x2b, 0x5a, 0xa4, 0xc5, 0x05, 0xdb, 0xe5, 0x09, 0xe3,
++    0xeb, 0xa2, 0x51, 0x33, 0x30, 0x96, 0x46, 0x01, 0x26, 0x8f,
++    0x38, 0xc9, 0x97, 0x32, 0x2d, 0xb4, 0x59, 0x15, 0x15, 0x38,
++    0x66, 0x66, 0xfe, 0xcb, 0xee, 0xc1, 0xf6, 0x4e, 0xb7, 0xdf,
++    0x7b, 0x63, 0xe6, 0x3f, 0xe0, 0x1c, 0x97, 0xed, 0x86, 0xf3,
++    0xd2, 0xad, 0x42, 0x29, 0x20, 0x28, 0xa6, 0x59, 0x58, 0x7d,
++    0x8f, 0x5c, 0x43, 0x07, 0xd1, 0x7e, 0x83, 0xba, 0x9c, 0x1b,
++    0xfe, 0x17, 0x9e, 0xc8, 0x09, 0x63, 0x9a, 0x2d, 0x61, 0x33,
++    0x51, 0x46, 0x01, 0xa8, 0xe9, 0x43, 0x1e, 0x4e, 0xfe, 0x61,
++    0x1a, 0x28, 0x11, 0x65, 0x70, 0x43, 0x9f, 0xfc, 0x21, 0x1d,
++    0x76, 0x7b, 0x40, 0x08, 0x18, 0xd3, 0xe8, 0xc2, 0xe3, 0x8c,
++    0xe7, 0x27, 0xc2, 0xec, 0xb0, 0x08, 0x3e, 0x6b, 0x8f, 0x77,
++    0x6d, 0x9e, 0xa6, 0xab, 0xce, 0x9a, 0xf8, 0x8f, 0x77, 0xb3,
++    0xf4, 0xe8, 0x8b, 0xe7, 0xd9, 0xa1, 0x95, 0x40, 0x6b, 0xca,
++    0x21, 0x98, 0xff, 0xdc, 0xdc, 0x96, 0xc3, 0x08, 0x81, 0x72,
++    0x9a, 0xdd, 0xe2, 0xcf, 0x95, 0x99, 0xa6, 0xa3, 0x5e, 0x9e,
++    0x25, 0x60, 0xa3, 0xc3, 0x39, 0xf7, 0x54, 0x6c, 0xf2, 0x75,
++    0xa9, 0x38, 0x12, 0x38, 0x4d, 0x42, 0xe8, 0xec, 0x13, 0x25,
++    0xa0, 0xf8, 0x04, 0xb8, 0xf6, 0x66, 0x0b, 0x56, 0xe1, 0xfb,
++    0x26, 0x03, 0xe6, 0xa5, 0xf1, 0x4d, 0x7f, 0xa5, 0x9d, 0x58,
++    0x71, 0xd8, 0xc7, 0x6a, 0xbe, 0xdc, 0x90, 0x89, 0xb1, 0x36,
++    0xb4, 0xb6, 0xb4, 0xbb, 0xaf, 0x6e, 0x43, 0x10, 0xa6, 0xea,
++    0xee, 0x12, 0xcb, 0x08, 0x2c, 0x4e, 0x66, 0xf0, 0x1f, 0xf4,
++    0xbf, 0xd3, 0xeb, 0x63, 0x48, 0xd0, 0xbe, 0x8a, 0xed, 0x24,
++    0xdb, 0x0f, 0x23, 0x1d, 0x2e, 0x30, 0x97, 0x0f, 0xd8, 0xc6,
++    0x3b, 0x04, 0x2f, 0x33, 0x78, 0x20, 0x6e, 0xb1, 0x33, 0x03,
++    0x27, 0xac, 0x0a, 0x37, 0x15, 0x31, 0xef, 0x4d, 0x43, 0xcc,
++    0xa0, 0x49, 0x80, 0xe3, 0x8c, 0xc0, 0xf3, 0xf7, 0x2d, 0x37,
++    0x1d, 0xd3, 0x90, 0x5f, 0xad, 0x31, 0xb5, 0x95, 0x17, 0x69,
++    0x4b, 0xec, 0x84, 0x9d, 0x2b, 0x8d, 0xdd, 0x9b, 0x58, 0x04,
++    0xba, 0x28, 0x0e, 0x28, 0xc1, 0x54, 0x6c, 0xb0, 0x25, 0x0c,
++    0x4f, 0x98, 0x47, 0xf7, 0x93, 0xc2, 0xae, 0x2f, 0x6d, 0x29,
++    0x9c, 0x3d, 0xe3, 0xb5, 0xe3, 0x28, 0x43, 0x14, 0xe6, 0x92,
++    0x4c, 0x79, 0x90, 0x59, 0x75, 0x77, 0x56, 0x43, 0xda, 0xac,
++    0xa9, 0x42, 0xd7, 0xca, 0x95, 0x73, 0x26, 0x54, 0x1f, 0x3a,
++    0x8a, 0x37, 0x64, 0xd7, 0xcf, 0xe1, 0x31, 0xf7, 0x40, 0x59,
++    0xfd, 0xff, 0xea, 0x72, 0xfd, 0xc4, 0xde, 0xe3, 0x4d, 0x8a,
++    0xf5, 0x80, 0xc0, 0x61, 0x21, 0xbd, 0xbd, 0x8e, 0x42, 0xd5,
++    0x4c, 0xe4, 0xf4, 0x78, 0x31, 0xca, 0xf1, 0xec, 0x7c, 0x7b,
++    0x85, 0x6a, 0x05, 0x54, 0xbe, 0x38, 0x54, 0x2f, 0x1f, 0xda,
++    0x9f, 0x98, 0xe2, 0x79, 0xd7, 0x42, 0xca, 0xba, 0x85, 0x21,
++    0xe2, 0xcb, 0x2b, 0xae, 0x4a, 0x4e, 0x35, 0xfb, 0xcf, 0x3d,
++    0xc5, 0xae, 0x27, 0x30, 0xa9, 0x45, 0xe6, 0x3b, 0x43, 0x3e,
++    0x35, 0xe3, 0xf2, 0x0d, 0x53, 0x32, 0x2b, 0xf6, 0xe6, 0xc7,
++    0xd5, 0x02, 0x82, 0x03, 0xc1, 0x00, 0xd4, 0x04, 0x9b, 0xef,
++    0x5d, 0x58, 0xb0, 0xa3, 0xaa, 0xd2, 0xab, 0x53, 0x65, 0x99,
++    0x03, 0x49, 0x48, 0x4d, 0xf5, 0xdf, 0x5d, 0x16, 0x14, 0x11,
++    0x60, 0x45, 0x1b, 0xff, 0x4a, 0x60, 0x2b, 0x37, 0x63, 0xf6,
++    0xa7, 0x8a, 0xa8, 0xff, 0x08, 0x97, 0x08, 0xfc, 0xbb, 0xb3,
++    0x20, 0xa3, 0xcd, 0xd9, 0x58, 0xdb, 0x16, 0x1b, 0x88, 0x02,
++    0x1e, 0x0f, 0x43, 0x9b, 0x16, 0x7e, 0xbe, 0xb1, 0x9c, 0x13,
++    0x10, 0xdc, 0xa1, 0x56, 0xff, 0xa3, 0xff, 0x5e, 0x69, 0x30,
++    0xee, 0x7e, 0x76, 0x5f, 0x84, 0x94, 0xeb, 0x8f, 0x58, 0xf8,
++    0xcf, 0xbb, 0x99, 0x6e, 0xf0, 0xd8, 0x32, 0xf6, 0xce, 0x48,
++    0x6f, 0x7c, 0xc8, 0x8f, 0xd3, 0x86, 0x22, 0x49, 0x9f, 0xde,
++    0x11, 0x05, 0xa4, 0xdc, 0x92, 0xfb, 0x0f, 0xfa, 0x09, 0x4d,
++    0x17, 0x1a, 0xe2, 0x76, 0x67, 0x40, 0xa9, 0x5b, 0x1b, 0x54,
++    0x66, 0x48, 0xf7, 0xc3, 0x59, 0xd4, 0xcf, 0x55, 0xd0, 0x7f,
++    0x3b, 0xb0, 0xa2, 0xd8, 0xec, 0xb7, 0x88, 0xe7, 0xb0, 0x30,
++    0x72, 0x42, 0x65, 0xe2, 0x91, 0xa7, 0x9b, 0xf6, 0x07, 0x45,
++    0x52, 0x51, 0xaa, 0xbe, 0x32, 0x35, 0xe4, 0x88, 0x23, 0xe7,
++    0xcb, 0x3c, 0x1c, 0xfb, 0x0b, 0x96, 0xd5, 0xb3, 0x92, 0x86,
++    0x79, 0x5b, 0x47, 0x93, 0xd6, 0xbd, 0xc7, 0x21, 0x17, 0xd0,
++    0xc9, 0xc7, 0x69, 0x84, 0x80, 0x98, 0xaf, 0x2c, 0x63, 0xd1,
++    0xef, 0x6e, 0xca, 0x84, 0x30, 0x32, 0x83, 0x2d, 0x49, 0xbb,
++    0x1f, 0x2a, 0xfe, 0x40, 0x7c, 0x03, 0xd4, 0x45, 0xdc, 0xfe,
++    0x94, 0xf9, 0xe4, 0x36, 0x47, 0xfa, 0x7e, 0x2e, 0x93, 0x03,
++    0xf8, 0x15, 0xf9, 0xce, 0xc3, 0x5b, 0x76, 0x10, 0xec, 0x89,
++    0x8c, 0xce, 0x25, 0xa5, 0x77, 0x9a, 0xc5, 0x1e, 0xdd, 0x07,
++    0x1b, 0x5b, 0xac, 0x6f, 0xdb, 0x94, 0x85, 0xdf, 0x02, 0x22,
++    0xd1, 0xa9, 0x01, 0x8e, 0x63, 0xa1, 0xee, 0x94, 0x9c, 0xdb,
++    0xb4, 0x1a, 0x43, 0xe1, 0x1f, 0x4e, 0x2f, 0x68, 0x50, 0x0c,
++    0x2f, 0x5b, 0xc5, 0x1b, 0xe1, 0x8d, 0x4b, 0xe0, 0x63, 0x8d,
++    0x7a, 0x30, 0xbe, 0xb7, 0x2e, 0x02, 0xc6, 0x02, 0xac, 0xa8,
++    0xb8, 0x65, 0xc6, 0x28, 0xee, 0xe4, 0xec, 0x99, 0xa1, 0x9a,
++    0xfd, 0x1f, 0xb5, 0x85, 0x7a, 0x94, 0x16, 0xe2, 0xe7, 0x74,
++    0x06, 0x54, 0x1b, 0xd0, 0xaf, 0x58, 0x4e, 0x50, 0x7e, 0xd6,
++    0xe4, 0x31, 0xd2, 0x0c, 0xd7, 0x9d, 0xe2, 0x00, 0x30, 0xbe,
++    0x26, 0x30, 0x48, 0x99, 0x98, 0x58, 0x54, 0x5a, 0xc4, 0x0a,
++    0x6c, 0xa1, 0x06, 0xe9, 0x38, 0xe6, 0x79, 0x39, 0x00, 0x9e,
++    0xb6, 0xe3, 0xf7, 0x01, 0xcf, 0x2f, 0x82, 0x5e, 0xc3, 0x21,
++    0x1b, 0x79, 0x93, 0xb5, 0xe4, 0x39, 0x9d, 0x32, 0x9d, 0x72,
++    0xa4, 0xa8, 0xc9, 0x90, 0xce, 0xaf, 0xc0, 0x00, 0xad, 0x20,
++    0x87, 0x26, 0xc7, 0xd3, 0x5f, 0x2e, 0xf0, 0x5e, 0xf8, 0x8b,
++    0x85, 0xa3, 0xc6, 0x66, 0xd8, 0x2f, 0x86, 0xfe, 0x7d, 0x8d,
++    0x22, 0xa5, 0x6d, 0x68, 0x3e, 0x87, 0x6e, 0xf7, 0xf1, 0xf0,
++    0x07, 0xc4, 0xe3, 0xf1, 0x84, 0xc4, 0x93, 0x42, 0x06, 0x20,
++    0x80, 0x64, 0xb3, 0x52, 0x5c, 0xa5, 0xcf, 0xee, 0xfe, 0xa4,
++    0x09, 0x41, 0xbe, 0xaa, 0x78, 0x52, 0x76, 0x3f, 0xf7, 0xe8,
++    0xa1, 0x6b, 0x0a, 0xbc, 0x22, 0xbe, 0xdf, 0x72, 0x7b, 0xea,
++    0x90, 0x43, 0xee, 0xc2, 0x0b, 0x26, 0xdc, 0x02, 0x26, 0xa7,
++    0x50, 0x04, 0x7a, 0x06, 0x91, 0xae, 0x93, 0xd5, 0xd2, 0xc9,
++    0xa1, 0xe1, 0xfc, 0xb9, 0x8c, 0x94, 0xca, 0xa8, 0x1c, 0x2c,
++    0x57, 0x97, 0x3e, 0x50, 0xed, 0x93, 0x45, 0x7a, 0x2c, 0x59,
++    0x7b, 0x34, 0x8f, 0xcd, 0xd6, 0x17, 0x93, 0xd8, 0xde, 0xe8,
++    0xb0, 0x9e, 0x27, 0x15, 0xc5, 0xbb, 0xa5, 0xbb, 0xc2, 0x30,
++    0x9b, 0xc7, 0x27, 0x02, 0x18, 0xd8, 0xdb, 0xa4, 0x84, 0x37,
++    0x64, 0xf7, 0xf7, 0xf1, 0xc8, 0x86, 0x4c, 0x64, 0x97, 0x08,
++    0xe9, 0x4e, 0x0e, 0xb6, 0x92, 0xe9, 0x4c, 0x7b, 0x7f, 0xe1,
++    0xcc, 0xa0, 0x71, 0xa7, 0x34, 0x48, 0x46, 0xbb, 0x37, 0xce,
++    0xb0, 0x4d, 0x39, 0xa8, 0x0e, 0xab, 0xf6, 0x2f, 0x7c, 0x88,
++    0xae, 0xcf, 0x90, 0xc6, 0x01, 0xd3, 0x5b, 0x37, 0xe9, 0xb1,
++    0x28, 0x42, 0x14, 0xbf, 0x59, 0x35, 0x04, 0xab, 0x46, 0x6e,
++    0xa8, 0x29, 0xe2, 0x7a, 0x77, 0x0e, 0x07, 0x67, 0xe4, 0x2b,
++    0x03, 0xd2, 0x02, 0x36, 0x16, 0xd7, 0x81, 0x5d, 0x38, 0x9c,
++    0x68, 0x9c, 0xf5, 0x9e, 0x49, 0x7d, 0x99, 0xfd, 0xcd, 0x1d,
++    0xd2, 0xdf, 0x3c, 0x36, 0x19, 0x85, 0xaa, 0xb1, 0x30, 0x7a,
++    0x21, 0xb1, 0x83, 0x16, 0xcf, 0xd1, 0x75, 0xa5, 0x9d, 0xd7,
++    0xc1, 0x60, 0xa8, 0xdb, 0x1e, 0xb9, 0x3e, 0x9c, 0x12, 0x42,
++    0xe8, 0x47, 0x49, 0x18, 0x9f, 0x5c, 0x12, 0xd1, 0x69, 0xd5,
++    0x7d, 0xa8, 0x3c, 0xda, 0x35, 0x8a, 0x6c, 0x63, 0xb8, 0x62,
++    0x8a, 0x61, 0xfa, 0xf2, 0x61, 0x11, 0x1e, 0xb6, 0xf3, 0x5c,
++    0x62, 0x9d, 0xa7, 0x62, 0x0c, 0x87, 0x93, 0xe2, 0x23, 0x6c,
++    0x3d, 0xa9, 0x2c, 0x4b, 0xd5, 0x7f, 0xfe, 0x72, 0x27, 0x36,
++    0x06, 0xcb, 0x65, 0x38, 0xef, 0x13, 0x57, 0x6a, 0xc9, 0xc6,
++    0x4f, 0x51, 0xd0, 0x90, 0x06, 0xa0, 0x23, 0x65, 0x95, 0xce,
++    0x16, 0x8f, 0x8d, 0xb2, 0xf9, 0x7f, 0x3c, 0x2c, 0x30, 0x5a,
++    0x38, 0xf1, 0x62, 0x79, 0x4b, 0xe5, 0xd7, 0x0a, 0x3f, 0x83,
++    0x5f, 0x46, 0x26, 0x97, 0xb7, 0x08, 0x8c, 0x5b, 0xb8, 0x02,
++    0x28, 0xf2, 0x4d, 0xdf, 0x93, 0x97, 0xc5, 0x94, 0x4b, 0x0e,
++    0x42, 0xc3, 0x35, 0x91, 0x6b, 0x69, 0x61, 0x76, 0x7f, 0x94,
++    0xcf, 0x0b, 0x81, 0x33, 0xff, 0xf3, 0x0c, 0xc7, 0x01, 0x94,
++    0x94, 0xa9, 0xed, 0xcd, 0x4b, 0xc8, 0xcb, 0x91, 0xf9, 0x7a,
++    0x47, 0xcd, 0x79, 0x3c, 0xa6, 0xde, 0x52, 0xd2, 0x47, 0x5c,
++    0x10, 0x62, 0xbb, 0xe5, 0x32, 0xde, 0x83, 0xcf, 0xa8, 0x52,
++    0xb3, 0xe7, 0xf9, 0xec, 0x17, 0x34, 0xbf, 0x33, 0x5d, 0xb2,
++    0x4e, 0x56, 0xf7, 0x29, 0xd9, 0x5c, 0x1b, 0x83, 0x01, 0xbb,
++    0xb9, 0x2b, 0x95, 0x52, 0x08, 0xab, 0xa4, 0x51, 0x03, 0xa1,
++    0xfb, 0x6a, 0x50, 0xcd, 0xa8, 0x9d, 0x95, 0x6f, 0x7e, 0xb1,
++    0x80, 0x1e, 0x9d, 0x81, 0x01, 0x26, 0x41, 0x78, 0x36, 0x3c,
++    0x8a, 0x44, 0xf4, 0x98, 0x88, 0x1c, 0x5d, 0x06, 0xd3, 0xd2,
++    0xb2, 0x58, 0x7d, 0xa1, 0x45, 0x1b, 0xbf, 0x8c, 0xf6, 0x6a,
++    0xfa, 0xfd, 0x08, 0x29, 0x3e, 0x91, 0x57, 0xf1, 0x3d, 0x20,
++    0xed, 0x49, 0x6e, 0x9c, 0x46, 0xd5, 0x08, 0x8d, 0x9b, 0xf8,
++    0xef, 0xa3, 0x3a, 0x98, 0xcb, 0xb4, 0xcb, 0x5b, 0x30, 0x25,
++    0x20, 0xcc, 0x04, 0xa1, 0xeb, 0xeb, 0xee, 0x1b, 0x36, 0x85,
++    0xc1, 0x93, 0x16, 0x5a, 0x31, 0xdf, 0xd6, 0x0e, 0x73, 0x9e,
++    0x63, 0x6e, 0x96, 0x90, 0x54, 0xd2, 0xc2, 0x53, 0x69, 0x93,
++    0xd5, 0x54, 0xca, 0xd8, 0x84, 0xf7, 0x8f, 0x9a, 0xd1, 0x80,
++    0x0d, 0x57, 0xa8, 0x26, 0xbe, 0x45, 0x64, 0xd5, 0x2b, 0xbb,
++    0x45, 0xb5, 0x08, 0xb9, 0x37, 0x57, 0x02, 0x82, 0x03, 0xc1,
++    0x00, 0xd1, 0x30, 0x2e, 0xb7, 0x9b, 0xe7, 0x5d, 0x13, 0x74,
++    0x1f, 0x52, 0xf2, 0x02, 0x18, 0xe9, 0x07, 0x87, 0x9e, 0xed,
++    0xde, 0x83, 0x92, 0xcf, 0x73, 0x61, 0x21, 0xc4, 0x62, 0x30,
++    0x6c, 0xa2, 0x36, 0xbd, 0xe2, 0xc5, 0x19, 0xf6, 0xdf, 0x51,
++    0x7b, 0xca, 0xd4, 0xe4, 0x51, 0x83, 0x49, 0x27, 0xdd, 0xbd,
++    0xb0, 0x10, 0x79, 0x39, 0xdd, 0x0e, 0x3d, 0x65, 0xad, 0x6d,
++    0xa3, 0x95, 0x52, 0x85, 0xdb, 0x18, 0x94, 0x60, 0xaa, 0xc0,
++    0xc8, 0x8b, 0xdb, 0xfe, 0xf9, 0xf0, 0x86, 0xf9, 0x33, 0x8a,
++    0xd7, 0xbe, 0x8d, 0x43, 0x83, 0x4d, 0xe4, 0x17, 0x2b, 0x46,
++    0x54, 0x44, 0x1b, 0xbe, 0x52, 0x64, 0x47, 0x02, 0x6c, 0x4a,
++    0x64, 0xb4, 0x3f, 0x21, 0x2f, 0xbb, 0xe3, 0x72, 0x7c, 0x26,
++    0x14, 0xdf, 0x80, 0x50, 0xd4, 0x94, 0xe9, 0xc6, 0x7d, 0x71,
++    0xd8, 0xaf, 0xfb, 0x74, 0x36, 0x33, 0xbe, 0x58, 0x63, 0xad,
++    0xcb, 0xdf, 0xc0, 0x73, 0x9e, 0x19, 0xb0, 0x65, 0xe1, 0xd1,
++    0x10, 0x44, 0xf1, 0xf0, 0x08, 0xa3, 0x09, 0x25, 0xeb, 0xd5,
++    0xcb, 0xdd, 0x98, 0xdd, 0xbc, 0x09, 0x2c, 0xef, 0xc1, 0x8d,
++    0x43, 0x15, 0x41, 0xc2, 0xa1, 0x84, 0x37, 0x70, 0x5a, 0xd5,
++    0xf5, 0xb2, 0x6a, 0x1f, 0xbb, 0xcc, 0x30, 0xb9, 0xd9, 0xc7,
++    0x36, 0x21, 0xf3, 0x69, 0x3e, 0x91, 0x38, 0x4d, 0xa5, 0xc4,
++    0xf7, 0x84, 0x90, 0x34, 0x0e, 0x47, 0x7e, 0x26, 0xf2, 0x98,
++    0x25, 0x26, 0xda, 0xf0, 0x4e, 0x55, 0xea, 0x4d, 0x9b, 0x8a,
++    0x4a, 0xe1, 0x1f, 0xa0, 0x07, 0x90, 0x9e, 0x59, 0x64, 0xae,
++    0xd9, 0xd6, 0x7e, 0x72, 0xa1, 0xc4, 0xea, 0x7d, 0xbd, 0x1f,
++    0x7d, 0x2b, 0xd9, 0x2c, 0xdc, 0x8b, 0xc0, 0xda, 0x52, 0x0c,
++    0xd1, 0xd0, 0x56, 0xb7, 0x93, 0xc7, 0x26, 0x79, 0x71, 0xd0,
++    0x0d, 0xae, 0xaa, 0xa7, 0xe4, 0xc1, 0x59, 0x27, 0x68, 0x97,
++    0x9a, 0xff, 0x3d, 0x36, 0x07, 0x55, 0x77, 0x07, 0x97, 0x69,
++    0xf3, 0x99, 0x91, 0x3f, 0x63, 0xfd, 0x70, 0x8c, 0xa1, 0xeb,
++    0xc5, 0x21, 0xa3, 0xfe, 0x99, 0x96, 0x11, 0x37, 0xb9, 0xe6,
++    0x93, 0xf8, 0xd0, 0xb1, 0xa3, 0x57, 0x7a, 0xa8, 0x63, 0xdd,
++    0x09, 0x56, 0xb0, 0x3b, 0xa6, 0x59, 0xc7, 0x89, 0x54, 0x16,
++    0xe9, 0x2d, 0x78, 0x7d, 0xaf, 0x4e, 0x0a, 0x5b, 0x62, 0x3b,
++    0x0b, 0xcb, 0x24, 0x89, 0x4e, 0x1c, 0x3d, 0xe1, 0xbd, 0x5a,
++    0x3e, 0xc5, 0xfd, 0x15, 0x3d, 0x08, 0x38, 0x33, 0x5e, 0x37,
++    0x4c, 0xe3, 0xe3, 0xe9, 0xc4, 0x1d, 0x2b, 0xd4, 0x58, 0x25,
++    0x58, 0x23, 0x8e, 0xc6, 0x83, 0x9a, 0xf3, 0x9a, 0x78, 0xe9,
++    0xa7, 0xca, 0xd7, 0xdd, 0x89, 0x20, 0x6e, 0x02, 0xea, 0x6b,
++    0x37, 0x74, 0xda, 0xa0, 0xc2, 0x5a, 0x2b, 0x80, 0x1c, 0x28,
++    0x91, 0x0d, 0x50, 0x64, 0xf0, 0x12, 0xe7, 0xc4, 0x7e, 0xdd,
++    0x28, 0x3b, 0x26, 0x9a, 0xf4, 0x39, 0x56, 0xa4, 0x72, 0x4d,
++    0xcb, 0x67, 0x3c, 0x68, 0xb2, 0x6f, 0xf0, 0xd0, 0x15, 0x90,
++    0xc8, 0x08, 0xbb, 0x0b, 0x08, 0x6b, 0x8a, 0xde, 0x41, 0x57,
++    0xbc, 0x63, 0x0e, 0x00, 0x8d, 0xf8, 0xdd, 0x93, 0xce, 0x58,
++    0x7b, 0xa8, 0xb9, 0x64, 0x26, 0x06, 0xe7, 0x71, 0x23, 0x0f,
++    0x41, 0xf1, 0xb7, 0xae, 0x59, 0x2e, 0xd0, 0x73, 0xc5, 0xd9,
++    0xdc, 0x0e, 0x1c, 0x02, 0x58, 0x69, 0xb3, 0x15, 0x6d, 0x96,
++    0x2b, 0xdb, 0x7b, 0x3b, 0x6c, 0x38, 0x32, 0x6b, 0xd8, 0x08,
++    0xb2, 0xbd, 0xa7, 0x49, 0x43, 0xeb, 0x90, 0x42, 0x70, 0xc5,
++    0xba, 0xcd, 0x4a, 0x44, 0x8f, 0x83, 0x0d, 0x17, 0x51, 0x5a,
++    0x95, 0xa2, 0x57, 0x9a, 0x16, 0x19, 0x91, 0xbb, 0x90, 0x5c,
++    0x2a, 0x16, 0xe8, 0x26, 0x10, 0x3c, 0xb7, 0x10, 0x5c, 0xf8,
++    0xc5, 0x15, 0x2b, 0x70, 0x75, 0x69, 0xba, 0x7b, 0x3d, 0x0b,
++    0x57, 0xac, 0x39, 0x12, 0x2e, 0xd6, 0xd9, 0x13, 0x74, 0x8e,
++    0xa8, 0x0b, 0x17, 0xe1, 0x03, 0x7a, 0xba, 0x1d, 0x07, 0x91,
++    0x8c, 0x2a, 0x3a, 0x8d, 0xe0, 0x2a, 0x94, 0xd4, 0x16, 0x35,
++    0x64, 0x8b, 0x92, 0x2c, 0x2f, 0xa4, 0x18, 0xfe, 0x3f, 0x02,
++    0x19, 0x8c, 0xb9, 0xeb, 0xaf, 0x01, 0x06, 0xa8, 0x37, 0x7f,
++    0xe2, 0x44, 0x10, 0xce, 0xeb, 0x8d, 0xd0, 0x73, 0xc4, 0x1e,
++    0x3d, 0x2c, 0xaf, 0x77, 0xb2, 0xef, 0xe5, 0x95, 0x8b, 0xdf,
++    0x02, 0xfc, 0x93, 0xb8, 0xa9, 0x27, 0x88, 0x1d, 0x1d, 0x82,
++    0x9f, 0xb6, 0xe4, 0x12, 0x05, 0x79, 0xb6, 0x1c, 0x41, 0x0d,
++    0xc1, 0x53, 0x49, 0x8f, 0x3d, 0xc9, 0xad, 0x84, 0xcb, 0x0b,
++    0x88, 0x7e, 0xfe, 0x73, 0x59, 0x21, 0x64, 0xc5, 0x50, 0x53,
++    0xdc, 0x98, 0xc6, 0x43, 0xb8, 0xf5, 0xc3, 0xa1, 0xf5, 0xb2,
++    0xd8, 0x86, 0xe9, 0xae, 0x98, 0xf9, 0x3b, 0x99, 0xc0, 0xe7,
++    0xd7, 0x4a, 0xed, 0xac, 0x89, 0x84, 0xb0, 0x8e, 0xd3, 0xab,
++    0xec, 0x03, 0x02, 0x12, 0x4b, 0x44, 0x17, 0x4d, 0x98, 0x26,
++    0x1e, 0x51, 0xc5, 0xbb, 0xcd, 0xdc, 0x50, 0xab, 0x83, 0x37,
++    0x49, 0x90, 0x1e, 0x34, 0xad, 0x81, 0x22, 0x6c, 0xe4, 0xdd,
++    0x19, 0x01, 0x09, 0x25, 0x2d, 0x9e, 0x52, 0x90, 0x72, 0xa1,
++    0x68, 0x3d, 0x0c, 0x49, 0x99, 0x19, 0x75, 0x5a, 0xca, 0x08,
++    0x69, 0xa1, 0xd2, 0x88, 0x8c, 0xea, 0xcf, 0x9c, 0xbc, 0x23,
++    0xad, 0x3f, 0xb9, 0xfc, 0xb9, 0x30, 0x0d, 0xd6, 0xd9, 0x65,
++    0x0c, 0x7e, 0x99, 0x68, 0x35, 0x26, 0x07, 0xd1, 0x55, 0xbf,
++    0x8e, 0xde, 0xe7, 0xe7, 0x01, 0xcb, 0xca, 0x0a, 0x39, 0x2e,
++    0xcc, 0x19, 0xec, 0x77, 0xf3, 0xab, 0xb2, 0xe6, 0x0e, 0x54,
++    0x06, 0x01, 0x50, 0x77, 0xd3, 0x61, 0x36, 0x05, 0x90, 0xe4,
++    0xd8, 0xc4, 0x1d, 0xf5, 0xc7, 0xfa, 0x65, 0xf0, 0x46, 0x6a,
++    0x5f, 0xa7, 0xc3, 0x8c, 0x6f, 0x04, 0x7f, 0xcf, 0x97, 0xb9,
++    0x68, 0x92, 0x31, 0x09, 0x02, 0x9f, 0x22, 0xc9, 0xf8, 0xe6,
++    0x7e, 0xa8, 0x95, 0x5b, 0x6b, 0xfe, 0x9c, 0x4e, 0x63, 0x2d,
++    0x8c, 0x1a, 0x4c, 0x8b, 0x14, 0x79, 0x08, 0xd5, 0x96, 0x76,
++    0xd1, 0xb4, 0x2f, 0xae, 0x5d, 0x91, 0x88, 0x7c, 0xdd, 0xd2,
++    0x06, 0x86, 0xcf, 0x0a, 0x83, 0x6f, 0xda, 0xca, 0x71, 0x7c,
++    0xe7, 0xe5, 0x34, 0xa8, 0x9a, 0x53, 0x8d, 0xa5, 0xaa, 0x5d,
++    0xb5, 0x17, 0x81, 0x34, 0x6f, 0xbe, 0xbb, 0xb6, 0x58, 0x22,
++    0x90, 0x80, 0xf6, 0x9c, 0x1c, 0xb0, 0x79, 0x8f, 0x92, 0x5b,
++    0x7d, 0x1c, 0x71, 0x5f, 0xb4, 0x87, 0x36, 0xbe, 0x81, 0x8d,
++    0x4a, 0xfc, 0x28, 0x72, 0x81, 0xaf, 0x5f, 0xbd, 0x5f, 0x99,
++    0xe3, 0xc9, 0x37, 0xb0, 0x6e, 0xad, 0x70, 0x96, 0xfa, 0xe3,
++    0x99, 0xf7, 0x08, 0x14, 0x21, 0x21, 0xb7, 0x1a, 0xaa, 0xe8,
++    0x07, 0xb6, 0xfd, 0xa3, 0x7a, 0x2d, 0x93, 0x64, 0x8f, 0x89,
++    0x2c, 0x71, 0x49, 0x71, 0xb8, 0x45, 0xca, 0xe0, 0x7c, 0x00,
++    0x8d, 0xbd, 0xb8, 0x1c, 0x3a, 0x94, 0xa2, 0xa7, 0x6d, 0x0a,
++    0x2e, 0x84, 0xaf, 0xbd, 0xab, 0x05, 0x95, 0x64, 0x8b, 0x05,
++    0xc8, 0xc9, 0x4e, 0xea, 0xb5, 0x96, 0x4a, 0x47, 0xdd, 0xf2,
++    0xcb, 0x02, 0x82, 0x03, 0xc0, 0x59, 0xb3, 0xd9, 0x85, 0xdc,
++    0xa8, 0xb9, 0x93, 0x85, 0xa2, 0xbc, 0x79, 0xfc, 0x72, 0x50,
++    0xc1, 0xa0, 0xa5, 0xdb, 0x71, 0x35, 0xa1, 0x31, 0xbc, 0x68,
++    0x4e, 0xd5, 0x19, 0x9e, 0x0e, 0x32, 0x3a, 0xad, 0x40, 0x9e,
++    0x82, 0x3c, 0x1e, 0x2b, 0x34, 0x3b, 0xc9, 0x32, 0x61, 0x07,
++    0x5e, 0x46, 0xa9, 0xbe, 0xbe, 0x73, 0x0c, 0x12, 0xef, 0x52,
++    0x68, 0x82, 0xe2, 0x0b, 0x12, 0x74, 0xfc, 0x10, 0x5c, 0xc0,
++    0xb5, 0x98, 0x4d, 0x86, 0xbb, 0x8c, 0x40, 0x15, 0xa1, 0x6e,
++    0x46, 0x73, 0x2e, 0xd6, 0x99, 0x6b, 0x50, 0xab, 0x04, 0x1a,
++    0x5f, 0xf4, 0xfa, 0xcb, 0x4b, 0xad, 0xc4, 0x5e, 0x62, 0xa7,
++    0x48, 0xd4, 0x52, 0x85, 0xdc, 0x2a, 0x85, 0x9b, 0xee, 0x08,
++    0xa5, 0xaa, 0xaa, 0xe8, 0x44, 0xf0, 0xed, 0x89, 0x21, 0xe4,
++    0xb4, 0xab, 0x3c, 0x0d, 0x53, 0x7e, 0x53, 0xdd, 0xac, 0x47,
++    0xda, 0x77, 0x79, 0x5f, 0x78, 0x7a, 0x80, 0x84, 0x46, 0x50,
++    0xaa, 0xdb, 0x3b, 0x8c, 0x6b, 0xda, 0xb0, 0xac, 0x0a, 0xd3,
++    0x4c, 0xe4, 0x6e, 0x87, 0xd1, 0xb2, 0x5a, 0xd5, 0x98, 0xae,
++    0xcb, 0x7e, 0xc2, 0x19, 0xdc, 0x53, 0x64, 0x86, 0x4c, 0x7b,
++    0xe0, 0x63, 0x22, 0x94, 0x34, 0xad, 0x15, 0xdc, 0xd8, 0xa8,
++    0x5f, 0xc6, 0x58, 0xf6, 0x72, 0x34, 0xdd, 0xfb, 0x85, 0x8a,
++    0xd9, 0xa3, 0xfb, 0x3b, 0xad, 0x5d, 0xf0, 0x1a, 0x0b, 0xa8,
++    0x91, 0xe7, 0x7d, 0x26, 0x27, 0x38, 0xf8, 0xe0, 0x49, 0x1b,
++    0x56, 0xc5, 0x5b, 0xe3, 0x1c, 0x7b, 0xa3, 0x53, 0x6d, 0x22,
++    0xfa, 0xd7, 0x63, 0x5f, 0xf0, 0xcb, 0x92, 0x49, 0x01, 0x54,
++    0xe5, 0x77, 0x5b, 0xd3, 0xab, 0xce, 0xb8, 0x3a, 0x5b, 0xb8,
++    0x07, 0x40, 0x46, 0x51, 0xe4, 0x59, 0xa2, 0x45, 0x41, 0xcc,
++    0x81, 0x6c, 0xe3, 0xa6, 0xb3, 0xa0, 0x30, 0x4a, 0x67, 0x10,
++    0xed, 0xc0, 0x8a, 0xcd, 0xfc, 0xa5, 0x44, 0x9b, 0x59, 0x19,
++    0x4a, 0x43, 0x8d, 0xec, 0x00, 0xd8, 0x6d, 0xf9, 0xf0, 0x2d,
++    0xd9, 0x55, 0xfc, 0x05, 0xe2, 0x12, 0x48, 0x4d, 0xd6, 0x7d,
++    0xec, 0x41, 0xc4, 0x9e, 0xe2, 0xed, 0x84, 0x14, 0x29, 0x0e,
++    0x5b, 0x81, 0x0b, 0xb0, 0x87, 0x8a, 0xd3, 0x35, 0x5c, 0xad,
++    0xdb, 0xcc, 0xa1, 0x3c, 0xcb, 0x8b, 0x23, 0x55, 0x69, 0xf1,
++    0x83, 0x84, 0x81, 0x36, 0xae, 0xd5, 0xf3, 0x98, 0xb6, 0xb2,
++    0xb5, 0xa1, 0x79, 0x6d, 0x80, 0x8f, 0x2e, 0x25, 0x71, 0x4e,
++    0x16, 0xff, 0xa0, 0x7c, 0xa4, 0x62, 0x8c, 0x44, 0x85, 0x64,
++    0x90, 0x7c, 0xac, 0x10, 0x36, 0xf2, 0xf2, 0xfb, 0x20, 0x2b,
++    0xa1, 0x27, 0xd0, 0xcc, 0x27, 0xfd, 0xb0, 0xba, 0x3e, 0x37,
++    0xb1, 0xa8, 0x9d, 0x3c, 0x82, 0x63, 0xd0, 0x16, 0x6d, 0x7a,
++    0xdd, 0x2e, 0xea, 0xe5, 0x87, 0xd6, 0x64, 0x72, 0xdb, 0x60,
++    0x53, 0x38, 0x18, 0x66, 0x1d, 0x25, 0xf6, 0x08, 0x92, 0x7f,
++    0x68, 0x5b, 0x79, 0x07, 0xde, 0x93, 0xee, 0xf8, 0x8f, 0xce,
++    0x28, 0xcf, 0xb1, 0x5b, 0x43, 0x51, 0xdf, 0xf5, 0xac, 0xe8,
++    0x9c, 0x95, 0x14, 0x8a, 0x67, 0xe1, 0x25, 0xfe, 0x11, 0xa2,
++    0x40, 0xf8, 0xdd, 0xcf, 0xf5, 0x17, 0x94, 0xb6, 0x88, 0x10,
++    0xa2, 0x90, 0x58, 0xef, 0xaf, 0x73, 0xf8, 0x7c, 0x9b, 0x20,
++    0x30, 0x79, 0xca, 0x3f, 0xa9, 0x22, 0x40, 0xfd, 0xcc, 0xb0,
++    0x5d, 0x0d, 0x97, 0x6b, 0xc0, 0x75, 0x35, 0x33, 0xc5, 0x76,
++    0x45, 0x6e, 0x9b, 0x78, 0xe7, 0xb4, 0x04, 0xb3, 0xba, 0x3b,
++    0x93, 0xb1, 0xa9, 0x8f, 0xa1, 0x24, 0x5d, 0x1c, 0x0e, 0x66,
++    0xc0, 0xc6, 0xcc, 0xd6, 0xb7, 0x88, 0x9d, 0xb8, 0x45, 0xe3,
++    0xaa, 0xc9, 0x6c, 0xfd, 0x37, 0xdc, 0x85, 0xd5, 0x49, 0xfd,
++    0xef, 0xeb, 0xf9, 0x7a, 0x3f, 0x7a, 0x4f, 0x86, 0x49, 0xaa,
++    0x9f, 0x08, 0x12, 0x0b, 0x11, 0x35, 0x5c, 0xd5, 0xd3, 0xda,
++    0x14, 0x50, 0x03, 0x2c, 0x24, 0x26, 0x0e, 0x29, 0x18, 0xcc,
++    0x1d, 0x0a, 0x7c, 0x94, 0x8b, 0xc0, 0xa0, 0x3f, 0xea, 0xf8,
++    0xf8, 0xa9, 0x1d, 0x65, 0x31, 0x6f, 0x3b, 0xa6, 0xd0, 0xfc,
++    0x26, 0xb0, 0x4e, 0x3a, 0x66, 0xe7, 0x32, 0x10, 0x2e, 0x84,
++    0x47, 0xad, 0xa9, 0x18, 0xfc, 0xa3, 0x8b, 0x74, 0x84, 0x4f,
++    0xd4, 0x25, 0x93, 0x0f, 0xdb, 0x2e, 0xae, 0x88, 0x8e, 0x28,
++    0xf8, 0x0f, 0xaa, 0x60, 0xd4, 0xbe, 0xad, 0x66, 0x0c, 0x0d,
++    0x01, 0xbd, 0x8d, 0xc4, 0xfc, 0x48, 0xef, 0x78, 0x14, 0x34,
++    0xee, 0xb3, 0xbc, 0xd4, 0xbb, 0x1f, 0x7c, 0x12, 0x5c, 0x9b,
++    0xeb, 0x77, 0x3e, 0x2c, 0x6e, 0x31, 0x59, 0xe6, 0x78, 0xc5,
++    0xe8, 0xa4, 0xdd, 0xf1, 0xef, 0x5d, 0x27, 0x45, 0x31, 0x13,
++    0xd0, 0x21, 0xa1, 0x13, 0xce, 0xac, 0x7e, 0xbb, 0xfb, 0x32,
++    0xeb, 0x76, 0x31, 0xc4, 0xba, 0xdf, 0xfb, 0x5a, 0x1b, 0xc9,
++    0x9e, 0x74, 0xa0, 0x9e, 0x26, 0x82, 0xd5, 0x6e, 0x1d, 0xc3,
++    0x0e, 0xd1, 0x6d, 0xdb, 0x43, 0xb3, 0x0b, 0x14, 0xcb, 0xf1,
++    0xad, 0x62, 0x34, 0x49, 0xb8, 0xd3, 0x08, 0xca, 0x93, 0xf1,
++    0x42, 0xb2, 0x4b, 0x23, 0x79, 0x93, 0xde, 0x18, 0x58, 0xf3,
++    0x66, 0xfa, 0xdc, 0xab, 0xca, 0x33, 0x22, 0x2b, 0x5c, 0x8c,
++    0x12, 0xc1, 0x7b, 0x2e, 0x52, 0x72, 0xa7, 0x78, 0x4a, 0x49,
++    0xa1, 0x53, 0x02, 0x76, 0x2d, 0x2e, 0xf8, 0x43, 0x3c, 0xe8,
++    0xfa, 0xb7, 0xff, 0x39, 0xed, 0x74, 0x9e, 0x11, 0x61, 0x33,
++    0xde, 0x2a, 0x55, 0xe6, 0x4a, 0xe7, 0x97, 0xa6, 0xb2, 0xc3,
++    0x40, 0x41, 0x52, 0x66, 0xcf, 0xbf, 0xf8, 0x8e, 0x08, 0xea,
++    0x96, 0x4d, 0x03, 0xc9, 0xbe, 0x3c, 0x4e, 0x36, 0x8c, 0x6f,
++    0x4d, 0x1e, 0xcd, 0x31, 0x6d, 0x53, 0xea, 0x9e, 0xf0, 0x8e,
++    0x35, 0x97, 0x37, 0x54, 0xe9, 0x0f, 0xb8, 0x23, 0x25, 0x69,
++    0x5b, 0xb5, 0xff, 0xc3, 0x5a, 0x2d, 0x10, 0x6a, 0xc0, 0xb8,
++    0xee, 0x0d, 0x31, 0x5b, 0xe4, 0x69, 0x40, 0x62, 0xa7, 0x1b,
++    0x16, 0xfa, 0xd6, 0xb8, 0xba, 0xc8, 0x6a, 0xa3, 0x29, 0xdd,
++    0x9b, 0x4d, 0xd7, 0x96, 0xef, 0x31, 0x74, 0xac, 0x37, 0x10,
++    0x91, 0x30, 0x0c, 0x15, 0x3f, 0x09, 0xb6, 0x7d, 0x22, 0xfb,
++    0x8c, 0x6f, 0xc3, 0x93, 0xa3, 0x98, 0xa6, 0x23, 0xa4, 0x55,
++    0xe0, 0x9e, 0x23, 0x06, 0xa9, 0x78, 0xe9, 0xb3, 0x88, 0xc9,
++    0xb7, 0x83, 0x05, 0x46, 0x11, 0x3a, 0x0a, 0xb9, 0x74, 0x5b,
++    0xa0, 0xb5, 0x06, 0x96, 0x86, 0xb6, 0xf4, 0x9d, 0x0d, 0x86,
++    0x43, 0xa8, 0x40, 0x4b, 0x08, 0x93, 0x7c, 0xad, 0xb0, 0x50,
++    0xb4, 0xd0, 0xe7, 0xad, 0xd0, 0x54, 0x5e, 0x15, 0xaf, 0xad,
++    0x34, 0x12, 0x86, 0xb3, 0x29, 0x3b, 0x20, 0xc9, 0xad, 0xeb,
++    0xc2, 0x65, 0xf3, 0x5c, 0x2d, 0xe5, 0xff, 0xfd, 0x81, 0x79,
++    0xf5, 0x11, 0x6f, 0xf7, 0xca, 0x0c, 0x76, 0xf0, 0xd4, 0x02,
++    0x9d, 0xb7, 0x76, 0x39, 0x6d, 0x32, 0x6a, 0xb8, 0x30, 0xa4,
++    0x01, 0xcc, 0x10, 0xef, 0xb1, 0x0e, 0x41, 0x22, 0x82, 0x5b,
++    0x22, 0xcb, 0x32, 0x19, 0x2e, 0xa3, 0x0a, 0xce, 0x05, 0xdd,
++    0xe8, 0x4a, 0x58, 0x92, 0xe1, 0x02, 0x82, 0x03, 0xc0, 0x22,
++    0x0f, 0x95, 0x5b, 0xc2, 0x1f, 0xde, 0xf0, 0xde, 0xf4, 0x86,
++    0xbd, 0xef, 0x07, 0x7d, 0x52, 0x03, 0x8c, 0x26, 0x31, 0x17,
++    0xfd, 0x5c, 0x97, 0xed, 0xd5, 0xe0, 0xb3, 0x18, 0x2d, 0x68,
++    0x10, 0x3f, 0xc4, 0xdf, 0xd1, 0x05, 0x78, 0x81, 0x3d, 0x05,
++    0xde, 0xba, 0x3a, 0x67, 0x85, 0x0e, 0xdf, 0xb5, 0x16, 0x28,
++    0xe8, 0x84, 0x3a, 0x71, 0x2a, 0x20, 0x17, 0x28, 0x05, 0xfd,
++    0xb7, 0x4d, 0x22, 0x4a, 0x93, 0x46, 0x56, 0x27, 0x43, 0xc0,
++    0x3a, 0x16, 0xff, 0x3d, 0x61, 0xcc, 0xcb, 0xce, 0xac, 0xa8,
++    0x53, 0x3a, 0x0d, 0xf4, 0x2d, 0xd2, 0x73, 0xf2, 0x64, 0xa0,
++    0x1e, 0x60, 0x53, 0xec, 0x0d, 0xff, 0xe0, 0x00, 0x10, 0xfb,
++    0xa4, 0x57, 0xd3, 0xfc, 0xe4, 0xe0, 0xec, 0x44, 0x0b, 0x1c,
++    0x05, 0x39, 0xa4, 0x13, 0x87, 0x29, 0x11, 0x9d, 0xea, 0xe9,
++    0x64, 0xa9, 0x1c, 0x76, 0x3a, 0x65, 0x0b, 0xfd, 0xed, 0x77,
++    0x46, 0x4f, 0xcd, 0x0b, 0x63, 0xc4, 0x83, 0x0b, 0x56, 0x79,
++    0xd3, 0x67, 0x01, 0x11, 0x02, 0xd9, 0x50, 0xd8, 0x23, 0xf4,
++    0xb6, 0x02, 0x4c, 0xae, 0xb5, 0xc9, 0x68, 0x1b, 0x87, 0x33,
++    0xbb, 0xdc, 0x64, 0x0e, 0x32, 0x34, 0xb2, 0x25, 0xaa, 0x76,
++    0xdd, 0x7e, 0xc3, 0x46, 0x51, 0x1c, 0xc1, 0xd0, 0x05, 0x09,
++    0x6c, 0x27, 0xd3, 0xcf, 0x33, 0x7a, 0xb9, 0x26, 0x24, 0x23,
++    0x4a, 0x93, 0x9f, 0x4b, 0x96, 0xc7, 0xe2, 0xb2, 0x51, 0x42,
++    0x4d, 0x5d, 0xd9, 0x73, 0x75, 0xce, 0x23, 0x28, 0x56, 0x5e,
++    0xe7, 0x96, 0x58, 0x04, 0xfd, 0x33, 0x93, 0x08, 0x41, 0x62,
++    0x02, 0x7e, 0xc9, 0xc6, 0x55, 0x64, 0x19, 0xda, 0x39, 0xb8,
++    0x5d, 0x09, 0x47, 0xf3, 0xdd, 0x77, 0xee, 0xea, 0x35, 0x73,
++    0x95, 0xdb, 0x18, 0x4d, 0xd1, 0xfe, 0xee, 0x40, 0x31, 0x2a,
++    0x22, 0x91, 0x69, 0xd6, 0xed, 0x9c, 0x54, 0x14, 0x73, 0x61,
++    0x61, 0xe7, 0x1d, 0x34, 0x96, 0x47, 0xff, 0x28, 0x7a, 0x48,
++    0xa3, 0xf4, 0xcd, 0x64, 0x23, 0xe2, 0x52, 0x2f, 0x20, 0x8f,
++    0x04, 0xb3, 0xdc, 0xf0, 0x29, 0x67, 0x88, 0x76, 0x79, 0xdb,
++    0x86, 0xa7, 0x95, 0xf0, 0x15, 0x81, 0xbb, 0x98, 0xee, 0xff,
++    0x55, 0x7c, 0xb0, 0xee, 0x67, 0x65, 0xfd, 0xf2, 0x29, 0x0f,
++    0x85, 0x51, 0xf9, 0xac, 0x5c, 0x55, 0x5a, 0xde, 0x40, 0x62,
++    0x58, 0x55, 0x9f, 0x09, 0x4c, 0x2e, 0x28, 0x75, 0xbc, 0x48,
++    0xe2, 0x97, 0x85, 0xb3, 0x83, 0xeb, 0x21, 0x49, 0x21, 0xd4,
++    0xed, 0x74, 0x4f, 0xc1, 0x6c, 0x34, 0x8c, 0x11, 0xb0, 0x93,
++    0x41, 0x99, 0x23, 0x2e, 0xa4, 0xc1, 0x9f, 0x34, 0x74, 0x64,
++    0xbb, 0xd7, 0x4f, 0x8f, 0x9f, 0x3a, 0x0c, 0x4f, 0x5e, 0xdd,
++    0x41, 0x07, 0xf1, 0xfd, 0x5a, 0x9d, 0xe6, 0x77, 0xd8, 0x7e,
++    0x71, 0x7b, 0xad, 0xf7, 0x76, 0x13, 0x71, 0x90, 0xb3, 0x0f,
++    0x46, 0x8e, 0xee, 0x7b, 0x33, 0x97, 0x5d, 0x21, 0x3b, 0xa0,
++    0x58, 0x9e, 0xb7, 0x87, 0x30, 0x8f, 0xc1, 0x23, 0x2c, 0xde,
++    0xf7, 0x0d, 0xa9, 0xd6, 0x50, 0xeb, 0x35, 0x7a, 0x82, 0xab,
++    0x22, 0x49, 0x86, 0xd4, 0x61, 0xc7, 0xc2, 0x4e, 0x77, 0xfc,
++    0x16, 0x0b, 0xaf, 0x81, 0x6a, 0x47, 0xea, 0xac, 0x7e, 0x51,
++    0x4c, 0x56, 0x30, 0x21, 0x46, 0x41, 0xc3, 0x92, 0x60, 0x99,
++    0x4f, 0x88, 0x36, 0x3b, 0x27, 0xb4, 0xb2, 0x7e, 0x44, 0x2f,
++    0xdd, 0x95, 0xe4, 0x5e, 0x16, 0x1f, 0xa7, 0x32, 0x6b, 0x60,
++    0x24, 0x0f, 0xf2, 0xe6, 0x35, 0x3c, 0x0c, 0x3e, 0xb5, 0xd6,
++    0xdd, 0x63, 0xe2, 0x76, 0x35, 0x38, 0x79, 0xbf, 0xa5, 0x23,
++    0xa4, 0xdd, 0xeb, 0x01, 0x48, 0xd0, 0x60, 0x86, 0x11, 0x38,
++    0x5f, 0x9e, 0x6b, 0x00, 0x67, 0xd2, 0x5b, 0x41, 0x0a, 0x5e,
++    0x13, 0x0f, 0xa1, 0x9e, 0x90, 0x85, 0xa6, 0x7f, 0xe5, 0x4b,
++    0x9e, 0x93, 0x4e, 0x5b, 0x1f, 0x47, 0x62, 0xb0, 0x23, 0xbe,
++    0x82, 0xa9, 0xd9, 0xb6, 0x2e, 0xfd, 0xb1, 0x10, 0xca, 0xe0,
++    0xc9, 0x5d, 0xf6, 0x85, 0x18, 0x6c, 0x9c, 0x1d, 0x1f, 0x7c,
++    0xf6, 0x55, 0x09, 0x80, 0xcf, 0xac, 0xfe, 0x37, 0x6a, 0x4f,
++    0x96, 0xaa, 0x40, 0x79, 0x8b, 0x4a, 0xf2, 0x96, 0x79, 0x12,
++    0x1a, 0x26, 0x87, 0x06, 0x35, 0x4d, 0xd4, 0x3e, 0x14, 0x39,
++    0xe5, 0x6c, 0x39, 0x0f, 0x84, 0xb3, 0x5f, 0xed, 0xf4, 0xff,
++    0x89, 0x52, 0x05, 0x00, 0xf1, 0xd1, 0xc3, 0xcf, 0x54, 0x10,
++    0x24, 0x7c, 0xa6, 0xb5, 0x95, 0xa8, 0x6e, 0x13, 0x3e, 0x4a,
++    0x40, 0x6c, 0xf9, 0x63, 0x90, 0x44, 0x52, 0x07, 0x53, 0xb7,
++    0x51, 0xd9, 0x18, 0x47, 0x2e, 0xb0, 0x4e, 0x0f, 0x09, 0x99,
++    0x3a, 0x97, 0x26, 0x53, 0xa6, 0x02, 0x06, 0x0e, 0x93, 0xe1,
++    0x0b, 0xc5, 0xa9, 0x14, 0xd3, 0xd6, 0x8a, 0x29, 0x75, 0xcd,
++    0xb6, 0x7b, 0x64, 0x7c, 0xdd, 0x7e, 0xb4, 0x0a, 0x87, 0x48,
++    0x4a, 0x1b, 0x0e, 0x74, 0x4c, 0xd3, 0x0e, 0x96, 0x0e, 0x53,
++    0xc4, 0x3d, 0x7b, 0x1c, 0x87, 0x6a, 0x15, 0xd8, 0x77, 0xba,
++    0xe6, 0xa0, 0x2f, 0x2c, 0x1a, 0x9d, 0xde, 0x79, 0xfd, 0xab,
++    0x44, 0x80, 0xf0, 0x37, 0x9a, 0x3b, 0xf8, 0xde, 0x3d, 0x29,
++    0xcb, 0x89, 0x64, 0x4b, 0x57, 0xe7, 0x6b, 0x84, 0x09, 0x27,
++    0x17, 0x2f, 0xb2, 0xba, 0x3d, 0x09, 0xc9, 0x3c, 0x89, 0xe6,
++    0x19, 0x73, 0x83, 0xf7, 0xc6, 0x19, 0x18, 0x96, 0xb2, 0x7d,
++    0x1e, 0x9f, 0x70, 0x1f, 0xfc, 0x1f, 0xe2, 0xb5, 0x69, 0x1e,
++    0xf4, 0x65, 0x91, 0xce, 0x4b, 0xdc, 0x74, 0x49, 0x21, 0x64,
++    0x8b, 0x33, 0x50, 0xd2, 0xc1, 0x33, 0x62, 0x5b, 0xde, 0x0a,
++    0x72, 0xbe, 0xc0, 0x05, 0x51, 0x15, 0x80, 0xed, 0x32, 0x3a,
++    0x64, 0xa2, 0x73, 0x68, 0x5b, 0x16, 0xcf, 0x70, 0x5c, 0x98,
++    0xe5, 0x67, 0x45, 0x60, 0x57, 0x2b, 0x47, 0x0a, 0x22, 0x73,
++    0xc3, 0x56, 0x33, 0x3e, 0x14, 0x1d, 0x0c, 0xd1, 0x03, 0x08,
++    0x92, 0x21, 0x2b, 0xa9, 0x6e, 0x6b, 0xf9, 0x0c, 0x1e, 0x86,
++    0xdd, 0xb5, 0xbb, 0xa4, 0xa5, 0x82, 0x99, 0x98, 0x49, 0x36,
++    0xec, 0x98, 0x98, 0x95, 0xac, 0xc2, 0xa0, 0x1f, 0xa5, 0x7e,
++    0x67, 0xd1, 0xcf, 0x6a, 0xf4, 0x16, 0x08, 0x7a, 0x8d, 0x0b,
++    0xae, 0x12, 0x51, 0xe6, 0x8e, 0xe6, 0xcd, 0xa1, 0xaa, 0x6d,
++    0xe4, 0x54, 0xd4, 0x69, 0x1b, 0x09, 0x6a, 0xba, 0x5e, 0x0b,
++    0x11, 0x9c, 0x83, 0xb3, 0x5c, 0x67, 0xbb, 0x2d, 0xf8, 0x66,
++    0x1c, 0x33, 0xb8, 0x22, 0x58, 0x10, 0x96, 0xe9, 0x99, 0xaf,
++    0x0b, 0x2a, 0xf1, 0xe0, 0xcb, 0x56, 0xfb, 0x6d, 0x04, 0x40,
++    0xec, 0x37, 0x67, 0x1e, 0x08, 0x7a, 0x1c, 0xe9, 0xd8, 0x54,
++    0xf7, 0xd4, 0xc7, 0x3c, 0x45, 0x23, 0x2b, 0x76, 0xd2, 0x62,
++    0xc2, 0x53, 0xce, 0xfe, 0x02, 0xc4, 0xd9, 0xf6, 0x3c, 0xed,
++    0x49, 0x47, 0x21, 0xf9, 0x03, 0x3a, 0xa0, 0x16, 0x3a, 0xfe,
++    0x0c, 0x2f, 0x54, 0x7e, 0x85, 0x29, 0x7b, 0xc0, 0xaf, 0xa8,
++    0x5d, 0x31, 0x25, 0xda, 0xa7, 0xe3, 0x92, 0x1b, 0x64, 0x01,
++    0x1b, 0x3f, 0x6e, 0x47, 0xc5, 0x5a, 0x84, 0x52, 0x17, 0x02,
++    0x82, 0x03, 0xc1, 0x00, 0x81, 0x99, 0x2e, 0x72, 0x41, 0x6e,
++    0x86, 0xeb, 0x6f, 0x42, 0xd1, 0x38, 0x6e, 0xaa, 0x1a, 0xd5,
++    0x0a, 0xad, 0x51, 0xb1, 0xce, 0xd6, 0x35, 0xbe, 0x34, 0xd8,
++    0xc1, 0xe4, 0x5f, 0xdf, 0x2e, 0xe4, 0x90, 0xf2, 0x61, 0x21,
++    0x46, 0xc6, 0xfe, 0xab, 0x0f, 0x6c, 0x97, 0x78, 0xcd, 0x55,
++    0x86, 0x83, 0x61, 0x99, 0x49, 0x14, 0x86, 0xc6, 0x86, 0xf1,
++    0x41, 0x66, 0xc9, 0x39, 0x52, 0x99, 0x49, 0x07, 0xd6, 0x9d,
++    0xb7, 0x40, 0x34, 0x5f, 0xe7, 0x3a, 0xfa, 0x95, 0xeb, 0xa1,
++    0x03, 0xb7, 0x52, 0x71, 0x93, 0x30, 0x0b, 0x51, 0x58, 0x82,
++    0x07, 0x2f, 0x44, 0xa9, 0x4f, 0x9b, 0x1b, 0xf3, 0xd6, 0x21,
++    0x3d, 0x68, 0xef, 0x3f, 0xaf, 0xc2, 0x6f, 0xa0, 0xd5, 0x2b,
++    0xb8, 0x73, 0x84, 0x67, 0x36, 0x8b, 0xa4, 0x25, 0xe0, 0x86,
++    0xd9, 0x14, 0x5c, 0x6c, 0xd8, 0x61, 0xe1, 0x0a, 0x6c, 0xaf,
++    0xbb, 0x9c, 0xf6, 0x74, 0xca, 0x5a, 0x04, 0xac, 0x85, 0xc1,
++    0x1b, 0x4d, 0xf2, 0x07, 0xb6, 0x1e, 0x97, 0x7b, 0x75, 0xdf,
++    0x9b, 0x8a, 0x31, 0xc6, 0x90, 0xd5, 0x8d, 0x39, 0xc2, 0x54,
++    0xf4, 0xe2, 0x83, 0x57, 0x12, 0x19, 0xf5, 0xb2, 0xd2, 0x53,
++    0x81, 0x6d, 0xf0, 0x09, 0xc9, 0x80, 0x8b, 0x07, 0x7c, 0x59,
++    0xcd, 0x78, 0x00, 0xd6, 0x44, 0x7f, 0xe4, 0xdb, 0x77, 0x02,
++    0x00, 0x25, 0x79, 0x91, 0xc9, 0xde, 0xd0, 0xed, 0x3f, 0xfc,
++    0x37, 0x36, 0xea, 0xf0, 0x56, 0x50, 0xe7, 0x38, 0xca, 0xe1,
++    0x67, 0x12, 0x96, 0x55, 0x3e, 0xff, 0x97, 0xe5, 0xa7, 0x03,
++    0x5b, 0x72, 0x80, 0xd6, 0xa5, 0x23, 0x39, 0x78, 0x07, 0xc8,
++    0x83, 0x19, 0x74, 0xfb, 0x79, 0xc2, 0x9e, 0xbd, 0xf9, 0xaf,
++    0x09, 0x0f, 0xbd, 0x3d, 0x34, 0xe8, 0x44, 0x89, 0xb1, 0xf1,
++    0x2b, 0xa5, 0xff, 0x22, 0xc9, 0x47, 0xe2, 0x31, 0xb5, 0x6b,
++    0x8a, 0x65, 0x5f, 0x81, 0x5f, 0x89, 0xb0, 0x03, 0x5d, 0x53,
++    0x0e, 0xdd, 0xfb, 0xe5, 0x70, 0xaa, 0xd2, 0x37, 0x4d, 0xa1,
++    0x7c, 0xf2, 0xe4, 0x7f, 0xf1, 0x4a, 0xaf, 0x12, 0xd1, 0x83,
++    0xdc, 0xb2, 0x9e, 0xc1, 0x95, 0x3d, 0x04, 0x9f, 0xa3, 0xad,
++    0xcc, 0x78, 0x14, 0x9a, 0xf9, 0x58, 0x39, 0x08, 0x15, 0xda,
++    0x1b, 0x94, 0x50, 0x2d, 0x44, 0xc0, 0x23, 0x1c, 0x36, 0x5f,
++    0x16, 0x08, 0xa3, 0xdf, 0x9e, 0x4f, 0xbb, 0x07, 0xcd, 0xe3,
++    0x8c, 0xbf, 0xf1, 0xc3, 0x3e, 0x98, 0xf8, 0x49, 0x79, 0x58,
++    0xc9, 0x0f, 0x47, 0xc0, 0xab, 0x2f, 0x21, 0x63, 0xf6, 0xe6,
++    0xfe, 0x8a, 0xea, 0xbc, 0x32, 0x63, 0xca, 0x75, 0xf8, 0xa4,
++    0x1b, 0x6c, 0xfe, 0x9a, 0x6e, 0x68, 0x1f, 0x48, 0x59, 0xfb,
++    0x34, 0x43, 0x10, 0xd5, 0x0d, 0x80, 0x54, 0xcb, 0x67, 0x21,
++    0xc7, 0x13, 0x85, 0x38, 0x0c, 0xf9, 0x40, 0x2e, 0x2e, 0x4a,
++    0x05, 0x9e, 0x51, 0xae, 0xdd, 0xba, 0x23, 0x83, 0x66, 0x2a,
++    0xbf, 0x7f, 0xca, 0x9c, 0x6c, 0x2d, 0x6b, 0x7d, 0x68, 0x52,
++    0x81, 0x56, 0x2f, 0xea, 0xf9, 0xe7, 0xf1, 0x55, 0x16, 0xfc,
++    0x29, 0xe2, 0xa5, 0x1e, 0x0a, 0x06, 0xe0, 0x85, 0x4e, 0xa6,
++    0x5d, 0x20, 0x9d, 0x2b, 0xa2, 0xad, 0xaa, 0xd6, 0x9b, 0xd2,
++    0x98, 0x29, 0x45, 0x5c, 0x55, 0xc0, 0x91, 0xa2, 0x65, 0xcd,
++    0xac, 0xc6, 0x1a, 0x53, 0xa1, 0x46, 0x13, 0xf9, 0xfe, 0x1a,
++    0xf6, 0xdf, 0xa5, 0x1a, 0x58, 0x7c, 0x81, 0x2e, 0x46, 0x46,
++    0xf7, 0x2f, 0xd6, 0xaa, 0x21, 0xb0, 0x0e, 0x7e, 0xac, 0xb8,
++    0xc6, 0x76, 0x62, 0x82, 0x3b, 0x0a, 0x36, 0xbe, 0x97, 0x16,
++    0xd5, 0x79, 0x55, 0x15, 0x64, 0x2a, 0xbe, 0x19, 0x4e, 0x93,
++    0x3b, 0x44, 0x7c, 0xe2, 0xfc, 0x18, 0x4e, 0x83, 0x37, 0xfb,
++    0x26, 0x78, 0x6d, 0x24, 0x6b, 0x48, 0x21, 0x67, 0xde, 0xf5,
++    0x00, 0x22, 0x9a, 0xec, 0x40, 0x16, 0x96, 0x8a, 0x3f, 0xd5,
++    0xa6, 0x5e, 0x03, 0x84, 0xbb, 0x15, 0x4d, 0x55, 0x71, 0x00,
++    0x90, 0xc2, 0x96, 0x25, 0x01, 0xab, 0xe6, 0x47, 0x44, 0x6f,
++    0xf9, 0x53, 0x80, 0x2b, 0xa8, 0x83, 0xc8, 0x14, 0x77, 0x13,
++    0x00, 0x66, 0xee, 0x7e, 0x7a, 0xa0, 0x28, 0x65, 0xf3, 0x31,
++    0xb6, 0xac, 0xd7, 0x87, 0x84, 0x29, 0xed, 0x5b, 0xcd, 0x74,
++    0xc0, 0x89, 0x51, 0x11, 0x9a, 0xd5, 0x7b, 0xe0, 0x9c, 0xd0,
++    0x8d, 0x72, 0xe3, 0x77, 0xda, 0x0a, 0xc2, 0xdc, 0x6f, 0xad,
++    0x49, 0x03, 0xfa, 0xe6, 0x7e, 0xa6, 0x24, 0x32, 0xe6, 0x8f,
++    0xd9, 0x70, 0xfa, 0x59, 0x70, 0xa9, 0xa3, 0x08, 0x7d, 0x89,
++    0xc4, 0x96, 0x61, 0xc2, 0xf5, 0xe5, 0xb5, 0x3b, 0x0d, 0xec,
++    0xb8, 0x9c, 0xee, 0x09, 0x77, 0x27, 0xbd, 0x35, 0x66, 0x90,
++    0x9e, 0x46, 0xf7, 0xbd, 0xa6, 0xc5, 0x31, 0xd4, 0x6a, 0x52,
++    0x17, 0x5d, 0x0a, 0x0e, 0x2c, 0x34, 0x7a, 0x6a, 0x21, 0xac,
++    0x42, 0xf0, 0x31, 0xde, 0x48, 0xe0, 0x27, 0xd0, 0x79, 0xc9,
++    0x06, 0x94, 0x7b, 0x51, 0x4b, 0x5b, 0x02, 0x6a, 0x19, 0xba,
++    0x71, 0x45, 0x9c, 0xdf, 0xe6, 0x30, 0x9e, 0xaa, 0xad, 0xa1,
++    0x87, 0xf6, 0x37, 0xde, 0xa2, 0x97, 0x68, 0x20, 0x2d, 0x5a,
++    0xdc, 0xdd, 0x91, 0x63, 0x5f, 0x79, 0xda, 0x99, 0x20, 0x3a,
++    0x4b, 0xe5, 0x43, 0x0e, 0x12, 0x70, 0x57, 0x91, 0xfa, 0xee,
++    0xc4, 0xb6, 0xb6, 0xb1, 0xf1, 0x06, 0xbd, 0xcf, 0x8d, 0x2a,
++    0x05, 0xc0, 0x07, 0x23, 0x84, 0x85, 0xef, 0x9c, 0xbb, 0x6f,
++    0x5f, 0x4a, 0x9a, 0x27, 0x9f, 0x9f, 0x32, 0x97, 0xe8, 0x24,
++    0xb9, 0x64, 0x2c, 0x39, 0xff, 0x2f, 0x4b, 0xc4, 0x7e, 0x65,
++    0xfe, 0xbb, 0x5c, 0xa0, 0xb2, 0x6e, 0xc4, 0xb6, 0x93, 0x2b,
++    0x51, 0x9e, 0x2e, 0x1f, 0xd8, 0xcf, 0x60, 0xe0, 0x75, 0x15,
++    0xf9, 0xa0, 0x67, 0x99, 0x88, 0x2b, 0x76, 0xce, 0x41, 0x42,
++    0x10, 0x29, 0x89, 0xbf, 0xca, 0xb7, 0x61, 0x08, 0x94, 0xee,
++    0xa0, 0xb3, 0x3a, 0x09, 0xc5, 0x6f, 0x04, 0xf9, 0x1b, 0xb5,
++    0x64, 0x99, 0x08, 0xe4, 0xcc, 0xce, 0xdf, 0x71, 0x65, 0x8a,
++    0x6d, 0x62, 0xde, 0x76, 0x1d, 0x6d, 0x6b, 0x78, 0x22, 0x32,
++    0x63, 0xdd, 0x53, 0x7d, 0xec, 0xed, 0x9d, 0x82, 0xa9, 0x2c,
++    0x5c, 0x8a, 0x17, 0xdd, 0x85, 0xf9, 0xd2, 0xac, 0x6e, 0x98,
++    0x60, 0x2e, 0x08, 0xd4, 0x06, 0x76, 0xf4, 0x97, 0xca, 0xb1,
++    0x72, 0x50, 0x5b, 0x83, 0xea, 0xbb, 0x39, 0x0f, 0x18, 0xb3,
++    0xb8, 0x03, 0xee, 0x7c, 0x84, 0xa9, 0x69, 0xcd, 0x1d, 0xbd,
++    0xe2, 0xb7, 0xce, 0xe2, 0x6f, 0x03, 0x49, 0x52, 0x67, 0xa0,
++    0x1b, 0x23, 0x43, 0x92, 0x2c, 0x7c, 0x3b, 0x65, 0xe8, 0x61,
++    0x99, 0xde, 0xb5, 0xf1, 0x63, 0x73, 0x92, 0x6c, 0x70, 0x8b,
++    0x83, 0x10, 0xb4, 0x06, 0x2c, 0x99, 0x12, 0x73, 0xec, 0x87,
++    0x92, 0x09, 0x67, 0x96, 0xd6, 0x9c, 0x9f, 0x35, 0x48, 0x48,
++    0x3b, 0x44, 0x00, 0x73, 0x1c, 0x59, 0xeb, 0x81, 0x7b, 0xd1,
++    0xda, 0x76, 0xcf, 0xc2, 0x4d, 0xf1, 0xa2, 0x5b, 0x2f, 0x5f,
++    0x91, 0x29, 0x6e, 0x08, 0x37, 0xd6, 0xaa, 0xd2, 0xf8, 0x4f,
++    0x5e, 0x00, 0x16, 0x52
++};
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/apps/timeouts.h b/CryptoPkg/Library/OpensslLib/openssl/apps/timeouts.h
+new file mode 100644
+index 0000000..e023b0a
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/apps/timeouts.h
+@@ -0,0 +1,17 @@
++/*
++ * Copyright 1999-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#ifndef INCLUDED_TIMEOUTS_H
++# define INCLUDED_TIMEOUTS_H
++
++/* numbers in us */
++# define DGRAM_RCV_TIMEOUT         250000
++# define DGRAM_SND_TIMEOUT         250000
++
++#endif                          /* ! INCLUDED_TIMEOUTS_H */
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/apps/ts.c b/CryptoPkg/Library/OpensslLib/openssl/apps/ts.c
+new file mode 100644
+index 0000000..14c533b
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/apps/ts.c
+@@ -0,0 +1,995 @@
++/*
++ * Copyright 2006-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#ifdef OPENSSL_NO_TS
++NON_EMPTY_TRANSLATION_UNIT
++#else
++# include 
++# include 
++# include 
++# include "apps.h"
++# include 
++# include 
++# include 
++# include 
++# include 
++# include 
++
++/* Request nonce length, in bits (must be a multiple of 8). */
++# define NONCE_LENGTH            64
++
++/* Name of config entry that defines the OID file. */
++# define ENV_OID_FILE            "oid_file"
++
++/* Is |EXACTLY_ONE| of three pointers set? */
++# define EXACTLY_ONE(a, b, c) \
++        (( a && !b && !c) || \
++         ( b && !a && !c) || \
++         ( c && !a && !b))
++
++static ASN1_OBJECT *txt2obj(const char *oid);
++static CONF *load_config_file(const char *configfile);
++
++/* Query related functions. */
++static int query_command(const char *data, const char *digest,
++                         const EVP_MD *md, const char *policy, int no_nonce,
++                         int cert, const char *in, const char *out, int text);
++static TS_REQ *create_query(BIO *data_bio, const char *digest, const EVP_MD *md,
++                            const char *policy, int no_nonce, int cert);
++static int create_digest(BIO *input, const char *digest,
++                         const EVP_MD *md, unsigned char **md_value);
++static ASN1_INTEGER *create_nonce(int bits);
++
++/* Reply related functions. */
++static int reply_command(CONF *conf, const char *section, const char *engine,
++                         const char *queryfile, const char *passin, const char *inkey,
++                         const EVP_MD *md, const char *signer, const char *chain,
++                         const char *policy, const char *in, int token_in,
++                         const char *out, int token_out, int text);
++static TS_RESP *read_PKCS7(BIO *in_bio);
++static TS_RESP *create_response(CONF *conf, const char *section, const char *engine,
++                                const char *queryfile, const char *passin,
++                                const char *inkey, const EVP_MD *md, const char *signer,
++                                const char *chain, const char *policy);
++static ASN1_INTEGER *serial_cb(TS_RESP_CTX *ctx, void *data);
++static ASN1_INTEGER *next_serial(const char *serialfile);
++static int save_ts_serial(const char *serialfile, ASN1_INTEGER *serial);
++
++/* Verify related functions. */
++static int verify_command(const char *data, const char *digest, const char *queryfile,
++                          const char *in, int token_in,
++                          const char *CApath, const char *CAfile, const char *untrusted,
++                          X509_VERIFY_PARAM *vpm);
++static TS_VERIFY_CTX *create_verify_ctx(const char *data, const char *digest,
++                                        const char *queryfile,
++                                        const char *CApath, const char *CAfile,
++                                        const char *untrusted,
++                                        X509_VERIFY_PARAM *vpm);
++static X509_STORE *create_cert_store(const char *CApath, const char *CAfile,
++                                     X509_VERIFY_PARAM *vpm);
++static int verify_cb(int ok, X509_STORE_CTX *ctx);
++
++typedef enum OPTION_choice {
++    OPT_ERR = -1, OPT_EOF = 0, OPT_HELP,
++    OPT_ENGINE, OPT_CONFIG, OPT_SECTION, OPT_QUERY, OPT_DATA,
++    OPT_DIGEST, OPT_RAND, OPT_TSPOLICY, OPT_NO_NONCE, OPT_CERT,
++    OPT_IN, OPT_TOKEN_IN, OPT_OUT, OPT_TOKEN_OUT, OPT_TEXT,
++    OPT_REPLY, OPT_QUERYFILE, OPT_PASSIN, OPT_INKEY, OPT_SIGNER,
++    OPT_CHAIN, OPT_VERIFY, OPT_CAPATH, OPT_CAFILE, OPT_UNTRUSTED,
++    OPT_MD, OPT_V_ENUM
++} OPTION_CHOICE;
++
++OPTIONS ts_options[] = {
++    {"help", OPT_HELP, '-', "Display this summary"},
++    {"config", OPT_CONFIG, '<', "Configuration file"},
++    {"section", OPT_SECTION, 's', "Section to use within config file"},
++    {"query", OPT_QUERY, '-', "Generate a TS query"},
++    {"data", OPT_DATA, '<', "File to hash"},
++    {"digest", OPT_DIGEST, 's', "Digest (as a hex string)"},
++    {"rand", OPT_RAND, 's',
++     "Load the file(s) into the random number generator"},
++    {"tspolicy", OPT_TSPOLICY, 's', "Policy OID to use"},
++    {"no_nonce", OPT_NO_NONCE, '-', "Do not include a nonce"},
++    {"cert", OPT_CERT, '-', "Put cert request into query"},
++    {"in", OPT_IN, '<', "Input file"},
++    {"token_in", OPT_TOKEN_IN, '-', "Input is a PKCS#7 file"},
++    {"out", OPT_OUT, '>', "Output file"},
++    {"token_out", OPT_TOKEN_OUT, '-', "Output is a PKCS#7 file"},
++    {"text", OPT_TEXT, '-', "Output text (not DER)"},
++    {"reply", OPT_REPLY, '-', "Generate a TS reply"},
++    {"queryfile", OPT_QUERYFILE, '<', "File containing a TS query"},
++    {"passin", OPT_PASSIN, 's', "Input file pass phrase source"},
++    {"inkey", OPT_INKEY, '<', "File with private key for reply"},
++    {"signer", OPT_SIGNER, 's', "Signer certificate file"},
++    {"chain", OPT_CHAIN, '<', "File with signer CA chain"},
++    {"verify", OPT_VERIFY, '-', "Verify a TS response"},
++    {"CApath", OPT_CAPATH, '/', "Path to trusted CA files"},
++    {"CAfile", OPT_CAFILE, '<', "File with trusted CA certs"},
++    {"untrusted", OPT_UNTRUSTED, '<', "File with untrusted certs"},
++    {"", OPT_MD, '-', "Any supported digest"},
++# ifndef OPENSSL_NO_ENGINE
++    {"engine", OPT_ENGINE, 's', "Use engine, possibly a hardware device"},
++# endif
++    {OPT_HELP_STR, 1, '-', "\nOptions specific to 'ts -verify': \n"},
++    OPT_V_OPTIONS,
++    {OPT_HELP_STR, 1, '-', "\n"},
++    {NULL}
++};
++
++/*
++ * This command is so complex, special help is needed.
++ */
++static char* opt_helplist[] = {
++    "Typical uses:",
++    "ts -query [-rand file...] [-config file] [-data file]",
++    "          [-digest hexstring] [-tspolicy oid] [-no_nonce] [-cert]",
++    "          [-in file] [-out file] [-text]",
++    "  or",
++    "ts -reply [-config file] [-section tsa_section]",
++    "          [-queryfile file] [-passin password]",
++    "          [-signer tsa_cert.pem] [-inkey private_key.pem]",
++    "          [-chain certs_file.pem] [-tspolicy oid]",
++    "          [-in file] [-token_in] [-out file] [-token_out]",
++# ifndef OPENSSL_NO_ENGINE
++    "          [-text] [-engine id]",
++# else
++    "          [-text]",
++# endif
++    "  or",
++    "ts -verify -CApath dir -CAfile file.pem -untrusted file.pem",
++    "           [-data file] [-digest hexstring]",
++    "           [-queryfile file] -in file [-token_in]",
++    "           [[options specific to 'ts -verify']]",
++    NULL,
++};
++
++int ts_main(int argc, char **argv)
++{
++    CONF *conf = NULL;
++    const char *CAfile = NULL, *untrusted = NULL, *prog;
++    const char *configfile = default_config_file, *engine = NULL;
++    const char *section = NULL;
++    char **helpp;
++    char *password = NULL;
++    char *data = NULL, *digest = NULL, *rnd = NULL, *policy = NULL;
++    char *in = NULL, *out = NULL, *queryfile = NULL, *passin = NULL;
++    char *inkey = NULL, *signer = NULL, *chain = NULL, *CApath = NULL;
++    const EVP_MD *md = NULL;
++    OPTION_CHOICE o, mode = OPT_ERR;
++    int ret = 1, no_nonce = 0, cert = 0, text = 0;
++    int vpmtouched = 0;
++    X509_VERIFY_PARAM *vpm = NULL;
++    /* Input is ContentInfo instead of TimeStampResp. */
++    int token_in = 0;
++    /* Output is ContentInfo instead of TimeStampResp. */
++    int token_out = 0;
++
++    if ((vpm = X509_VERIFY_PARAM_new()) == NULL)
++        goto end;
++
++    prog = opt_init(argc, argv, ts_options);
++    while ((o = opt_next()) != OPT_EOF) {
++        switch (o) {
++        case OPT_EOF:
++        case OPT_ERR:
++ opthelp:
++            BIO_printf(bio_err, "%s: Use -help for summary.\n", prog);
++            goto end;
++        case OPT_HELP:
++            opt_help(ts_options);
++            for (helpp = opt_helplist; *helpp; ++helpp)
++                BIO_printf(bio_err, "%s\n", *helpp);
++            ret = 0;
++            goto end;
++        case OPT_CONFIG:
++            configfile = opt_arg();
++            break;
++        case OPT_SECTION:
++            section = opt_arg();
++            break;
++        case OPT_QUERY:
++        case OPT_REPLY:
++        case OPT_VERIFY:
++            if (mode != OPT_ERR)
++                goto opthelp;
++            mode = o;
++            break;
++        case OPT_DATA:
++            data = opt_arg();
++            break;
++        case OPT_DIGEST:
++            digest = opt_arg();
++            break;
++        case OPT_RAND:
++            rnd = opt_arg();
++            break;
++        case OPT_TSPOLICY:
++            policy = opt_arg();
++            break;
++        case OPT_NO_NONCE:
++            no_nonce = 1;
++            break;
++        case OPT_CERT:
++            cert = 1;
++            break;
++        case OPT_IN:
++            in = opt_arg();
++            break;
++        case OPT_TOKEN_IN:
++            token_in = 1;
++            break;
++        case OPT_OUT:
++            out = opt_arg();
++            break;
++        case OPT_TOKEN_OUT:
++            token_out = 1;
++            break;
++        case OPT_TEXT:
++            text = 1;
++            break;
++        case OPT_QUERYFILE:
++            queryfile = opt_arg();
++            break;
++        case OPT_PASSIN:
++            passin = opt_arg();
++            break;
++        case OPT_INKEY:
++            inkey = opt_arg();
++            break;
++        case OPT_SIGNER:
++            signer = opt_arg();
++            break;
++        case OPT_CHAIN:
++            chain = opt_arg();
++            break;
++        case OPT_CAPATH:
++            CApath = opt_arg();
++            break;
++        case OPT_CAFILE:
++            CAfile = opt_arg();
++            break;
++        case OPT_UNTRUSTED:
++            untrusted = opt_arg();
++            break;
++        case OPT_ENGINE:
++            engine = opt_arg();
++            break;
++        case OPT_MD:
++            if (!opt_md(opt_unknown(), &md))
++                goto opthelp;
++            break;
++        case OPT_V_CASES:
++            if (!opt_verify(o, vpm))
++                goto end;
++            vpmtouched++;
++            break;
++        }
++    }
++    if (mode == OPT_ERR || opt_num_rest() != 0)
++        goto opthelp;
++
++    /* Seed the random number generator if it is going to be used. */
++    if (mode == OPT_QUERY && !no_nonce) {
++        if (!app_RAND_load_file(NULL, 1) && rnd == NULL)
++            BIO_printf(bio_err, "warning, not much extra random "
++                       "data, consider using the -rand option\n");
++        if (rnd != NULL)
++            BIO_printf(bio_err, "%ld semi-random bytes loaded\n",
++                       app_RAND_load_files(rnd));
++    }
++
++    if (mode == OPT_REPLY && passin &&
++        !app_passwd(passin, NULL, &password, NULL)) {
++        BIO_printf(bio_err, "Error getting password.\n");
++        goto end;
++    }
++
++    conf = load_config_file(configfile);
++    if (configfile != default_config_file && !app_load_modules(conf))
++        goto end;
++
++    /* Check parameter consistency and execute the appropriate function. */
++    switch (mode) {
++    default:
++    case OPT_ERR:
++        goto opthelp;
++    case OPT_QUERY:
++        if (vpmtouched)
++            goto opthelp;
++        if ((data != NULL) && (digest != NULL))
++            goto opthelp;
++        ret = !query_command(data, digest, md, policy, no_nonce, cert,
++                             in, out, text);
++        break;
++    case OPT_REPLY:
++        if (vpmtouched)
++            goto opthelp;
++        if ((in != NULL) && (queryfile != NULL))
++            goto opthelp;
++        if (in == NULL) {
++            if ((conf == NULL) || (token_in != 0))
++                goto opthelp;
++        }
++        ret = !reply_command(conf, section, engine, queryfile,
++                             password, inkey, md, signer, chain, policy,
++                             in, token_in, out, token_out, text);
++        break;
++    case OPT_VERIFY:
++        if ((in == NULL) || !EXACTLY_ONE(queryfile, data, digest))
++            goto opthelp;
++        ret = !verify_command(data, digest, queryfile, in, token_in,
++                              CApath, CAfile, untrusted,
++                              vpmtouched ? vpm : NULL);
++    }
++
++ end:
++    X509_VERIFY_PARAM_free(vpm);
++    app_RAND_write_file(NULL);
++    NCONF_free(conf);
++    OPENSSL_free(password);
++    return (ret);
++}
++
++/*
++ * Configuration file-related function definitions.
++ */
++
++static ASN1_OBJECT *txt2obj(const char *oid)
++{
++    ASN1_OBJECT *oid_obj = NULL;
++
++    if ((oid_obj = OBJ_txt2obj(oid, 0)) == NULL)
++        BIO_printf(bio_err, "cannot convert %s to OID\n", oid);
++
++    return oid_obj;
++}
++
++static CONF *load_config_file(const char *configfile)
++{
++    CONF *conf = app_load_config(configfile);
++
++    if (conf != NULL) {
++        const char *p;
++
++        BIO_printf(bio_err, "Using configuration from %s\n", configfile);
++        p = NCONF_get_string(conf, NULL, ENV_OID_FILE);
++        if (p != NULL) {
++            BIO *oid_bio = BIO_new_file(p, "r");
++            if (!oid_bio)
++                ERR_print_errors(bio_err);
++            else {
++                OBJ_create_objects(oid_bio);
++                BIO_free_all(oid_bio);
++            }
++        } else
++            ERR_clear_error();
++        if (!add_oid_section(conf))
++            ERR_print_errors(bio_err);
++    }
++    return conf;
++}
++
++/*
++ * Query-related method definitions.
++ */
++static int query_command(const char *data, const char *digest, const EVP_MD *md,
++                         const char *policy, int no_nonce,
++                         int cert, const char *in, const char *out, int text)
++{
++    int ret = 0;
++    TS_REQ *query = NULL;
++    BIO *in_bio = NULL;
++    BIO *data_bio = NULL;
++    BIO *out_bio = NULL;
++
++    /* Build query object. */
++    if (in != NULL) {
++        if ((in_bio = bio_open_default(in, 'r', FORMAT_ASN1)) == NULL)
++            goto end;
++        query = d2i_TS_REQ_bio(in_bio, NULL);
++    } else {
++        if (digest == NULL
++            && (data_bio = bio_open_default(data, 'r', FORMAT_ASN1)) == NULL)
++            goto end;
++        query = create_query(data_bio, digest, md, policy, no_nonce, cert);
++    }
++    if (query == NULL)
++        goto end;
++
++    if (text) {
++        if ((out_bio = bio_open_default(out, 'w', FORMAT_TEXT)) == NULL)
++            goto end;
++        if (!TS_REQ_print_bio(out_bio, query))
++            goto end;
++    } else {
++        if ((out_bio = bio_open_default(out, 'w', FORMAT_ASN1)) == NULL)
++            goto end;
++        if (!i2d_TS_REQ_bio(out_bio, query))
++            goto end;
++    }
++
++    ret = 1;
++
++ end:
++    ERR_print_errors(bio_err);
++    BIO_free_all(in_bio);
++    BIO_free_all(data_bio);
++    BIO_free_all(out_bio);
++    TS_REQ_free(query);
++    return ret;
++}
++
++static TS_REQ *create_query(BIO *data_bio, const char *digest, const EVP_MD *md,
++                            const char *policy, int no_nonce, int cert)
++{
++    int ret = 0;
++    TS_REQ *ts_req = NULL;
++    int len;
++    TS_MSG_IMPRINT *msg_imprint = NULL;
++    X509_ALGOR *algo = NULL;
++    unsigned char *data = NULL;
++    ASN1_OBJECT *policy_obj = NULL;
++    ASN1_INTEGER *nonce_asn1 = NULL;
++
++    if (md == NULL && (md = EVP_get_digestbyname("sha1")) == NULL)
++        goto err;
++    if ((ts_req = TS_REQ_new()) == NULL)
++        goto err;
++    if (!TS_REQ_set_version(ts_req, 1))
++        goto err;
++    if ((msg_imprint = TS_MSG_IMPRINT_new()) == NULL)
++        goto err;
++    if ((algo = X509_ALGOR_new()) == NULL)
++        goto err;
++    if ((algo->algorithm = OBJ_nid2obj(EVP_MD_type(md))) == NULL)
++        goto err;
++    if ((algo->parameter = ASN1_TYPE_new()) == NULL)
++        goto err;
++    algo->parameter->type = V_ASN1_NULL;
++    if (!TS_MSG_IMPRINT_set_algo(msg_imprint, algo))
++        goto err;
++    if ((len = create_digest(data_bio, digest, md, &data)) == 0)
++        goto err;
++    if (!TS_MSG_IMPRINT_set_msg(msg_imprint, data, len))
++        goto err;
++    if (!TS_REQ_set_msg_imprint(ts_req, msg_imprint))
++        goto err;
++    if (policy && (policy_obj = txt2obj(policy)) == NULL)
++        goto err;
++    if (policy_obj && !TS_REQ_set_policy_id(ts_req, policy_obj))
++        goto err;
++
++    /* Setting nonce if requested. */
++    if (!no_nonce && (nonce_asn1 = create_nonce(NONCE_LENGTH)) == NULL)
++        goto err;
++    if (nonce_asn1 && !TS_REQ_set_nonce(ts_req, nonce_asn1))
++        goto err;
++    if (!TS_REQ_set_cert_req(ts_req, cert))
++        goto err;
++
++    ret = 1;
++ err:
++    if (!ret) {
++        TS_REQ_free(ts_req);
++        ts_req = NULL;
++        BIO_printf(bio_err, "could not create query\n");
++        ERR_print_errors(bio_err);
++    }
++    TS_MSG_IMPRINT_free(msg_imprint);
++    X509_ALGOR_free(algo);
++    OPENSSL_free(data);
++    ASN1_OBJECT_free(policy_obj);
++    ASN1_INTEGER_free(nonce_asn1);
++    return ts_req;
++}
++
++static int create_digest(BIO *input, const char *digest, const EVP_MD *md,
++                         unsigned char **md_value)
++{
++    int md_value_len;
++    int rv = 0;
++    EVP_MD_CTX *md_ctx = NULL;
++
++    md_value_len = EVP_MD_size(md);
++    if (md_value_len < 0)
++        return 0;
++
++    if (input) {
++        unsigned char buffer[4096];
++        int length;
++
++        md_ctx = EVP_MD_CTX_new();
++        if (md_ctx == NULL)
++            return 0;
++        *md_value = app_malloc(md_value_len, "digest buffer");
++        if (!EVP_DigestInit(md_ctx, md))
++            goto err;
++        while ((length = BIO_read(input, buffer, sizeof(buffer))) > 0) {
++            if (!EVP_DigestUpdate(md_ctx, buffer, length))
++                goto err;
++        }
++        if (!EVP_DigestFinal(md_ctx, *md_value, NULL))
++            goto err;
++        md_value_len = EVP_MD_size(md);
++    } else {
++        long digest_len;
++        *md_value = OPENSSL_hexstr2buf(digest, &digest_len);
++        if (!*md_value || md_value_len != digest_len) {
++            OPENSSL_free(*md_value);
++            *md_value = NULL;
++            BIO_printf(bio_err, "bad digest, %d bytes "
++                       "must be specified\n", md_value_len);
++            return 0;
++        }
++    }
++    rv = md_value_len;
++ err:
++    EVP_MD_CTX_free(md_ctx);
++    return rv;
++}
++
++static ASN1_INTEGER *create_nonce(int bits)
++{
++    unsigned char buf[20];
++    ASN1_INTEGER *nonce = NULL;
++    int len = (bits - 1) / 8 + 1;
++    int i;
++
++    if (len > (int)sizeof(buf))
++        goto err;
++    if (RAND_bytes(buf, len) <= 0)
++        goto err;
++
++    /* Find the first non-zero byte and creating ASN1_INTEGER object. */
++    for (i = 0; i < len && !buf[i]; ++i)
++        continue;
++    if ((nonce = ASN1_INTEGER_new()) == NULL)
++        goto err;
++    OPENSSL_free(nonce->data);
++    nonce->length = len - i;
++    nonce->data = app_malloc(nonce->length + 1, "nonce buffer");
++    memcpy(nonce->data, buf + i, nonce->length);
++    return nonce;
++
++ err:
++    BIO_printf(bio_err, "could not create nonce\n");
++    ASN1_INTEGER_free(nonce);
++    return NULL;
++}
++
++/*
++ * Reply-related method definitions.
++ */
++
++static int reply_command(CONF *conf, const char *section, const char *engine,
++                         const char *queryfile, const char *passin, const char *inkey,
++                         const EVP_MD *md, const char *signer, const char *chain,
++                         const char *policy, const char *in, int token_in,
++                         const char *out, int token_out, int text)
++{
++    int ret = 0;
++    TS_RESP *response = NULL;
++    BIO *in_bio = NULL;
++    BIO *query_bio = NULL;
++    BIO *inkey_bio = NULL;
++    BIO *signer_bio = NULL;
++    BIO *out_bio = NULL;
++
++    if (in != NULL) {
++        if ((in_bio = BIO_new_file(in, "rb")) == NULL)
++            goto end;
++        if (token_in) {
++            response = read_PKCS7(in_bio);
++        } else {
++            response = d2i_TS_RESP_bio(in_bio, NULL);
++        }
++    } else {
++        response = create_response(conf, section, engine, queryfile,
++                                   passin, inkey, md, signer, chain, policy);
++        if (response)
++            BIO_printf(bio_err, "Response has been generated.\n");
++        else
++            BIO_printf(bio_err, "Response is not generated.\n");
++    }
++    if (response == NULL)
++        goto end;
++
++    /* Write response. */
++    if (text) {
++        if ((out_bio = bio_open_default(out, 'w', FORMAT_TEXT)) == NULL)
++        goto end;
++        if (token_out) {
++            TS_TST_INFO *tst_info = TS_RESP_get_tst_info(response);
++            if (!TS_TST_INFO_print_bio(out_bio, tst_info))
++                goto end;
++        } else {
++            if (!TS_RESP_print_bio(out_bio, response))
++                goto end;
++        }
++    } else {
++        if ((out_bio = bio_open_default(out, 'w', FORMAT_ASN1)) == NULL)
++            goto end;
++        if (token_out) {
++            PKCS7 *token = TS_RESP_get_token(response);
++            if (!i2d_PKCS7_bio(out_bio, token))
++                goto end;
++        } else {
++            if (!i2d_TS_RESP_bio(out_bio, response))
++                goto end;
++        }
++    }
++
++    ret = 1;
++
++ end:
++    ERR_print_errors(bio_err);
++    BIO_free_all(in_bio);
++    BIO_free_all(query_bio);
++    BIO_free_all(inkey_bio);
++    BIO_free_all(signer_bio);
++    BIO_free_all(out_bio);
++    TS_RESP_free(response);
++    return ret;
++}
++
++/* Reads a PKCS7 token and adds default 'granted' status info to it. */
++static TS_RESP *read_PKCS7(BIO *in_bio)
++{
++    int ret = 0;
++    PKCS7 *token = NULL;
++    TS_TST_INFO *tst_info = NULL;
++    TS_RESP *resp = NULL;
++    TS_STATUS_INFO *si = NULL;
++
++    if ((token = d2i_PKCS7_bio(in_bio, NULL)) == NULL)
++        goto end;
++    if ((tst_info = PKCS7_to_TS_TST_INFO(token)) == NULL)
++        goto end;
++    if ((resp = TS_RESP_new()) == NULL)
++        goto end;
++    if ((si = TS_STATUS_INFO_new()) == NULL)
++        goto end;
++    if (!TS_STATUS_INFO_set_status(si, TS_STATUS_GRANTED))
++        goto end;
++    if (!TS_RESP_set_status_info(resp, si))
++        goto end;
++    TS_RESP_set_tst_info(resp, token, tst_info);
++    token = NULL;               /* Ownership is lost. */
++    tst_info = NULL;            /* Ownership is lost. */
++    ret = 1;
++
++ end:
++    PKCS7_free(token);
++    TS_TST_INFO_free(tst_info);
++    if (!ret) {
++        TS_RESP_free(resp);
++        resp = NULL;
++    }
++    TS_STATUS_INFO_free(si);
++    return resp;
++}
++
++static TS_RESP *create_response(CONF *conf, const char *section, const char *engine,
++                                const char *queryfile, const char *passin,
++                                const char *inkey, const EVP_MD *md, const char *signer,
++                                const char *chain, const char *policy)
++{
++    int ret = 0;
++    TS_RESP *response = NULL;
++    BIO *query_bio = NULL;
++    TS_RESP_CTX *resp_ctx = NULL;
++
++    if ((query_bio = BIO_new_file(queryfile, "rb")) == NULL)
++        goto end;
++    if ((section = TS_CONF_get_tsa_section(conf, section)) == NULL)
++        goto end;
++    if ((resp_ctx = TS_RESP_CTX_new()) == NULL)
++        goto end;
++    if (!TS_CONF_set_serial(conf, section, serial_cb, resp_ctx))
++        goto end;
++# ifndef OPENSSL_NO_ENGINE
++    if (!TS_CONF_set_crypto_device(conf, section, engine))
++        goto end;
++# endif
++    if (!TS_CONF_set_signer_cert(conf, section, signer, resp_ctx))
++        goto end;
++    if (!TS_CONF_set_certs(conf, section, chain, resp_ctx))
++        goto end;
++    if (!TS_CONF_set_signer_key(conf, section, inkey, passin, resp_ctx))
++        goto end;
++
++    if (md) {
++        if (!TS_RESP_CTX_set_signer_digest(resp_ctx, md))
++            goto end;
++    } else if (!TS_CONF_set_signer_digest(conf, section, NULL, resp_ctx)) {
++            goto end;
++    }
++
++    if (!TS_CONF_set_def_policy(conf, section, policy, resp_ctx))
++        goto end;
++    if (!TS_CONF_set_policies(conf, section, resp_ctx))
++        goto end;
++    if (!TS_CONF_set_digests(conf, section, resp_ctx))
++        goto end;
++    if (!TS_CONF_set_accuracy(conf, section, resp_ctx))
++        goto end;
++    if (!TS_CONF_set_clock_precision_digits(conf, section, resp_ctx))
++        goto end;
++    if (!TS_CONF_set_ordering(conf, section, resp_ctx))
++        goto end;
++    if (!TS_CONF_set_tsa_name(conf, section, resp_ctx))
++        goto end;
++    if (!TS_CONF_set_ess_cert_id_chain(conf, section, resp_ctx))
++        goto end;
++    if ((response = TS_RESP_create_response(resp_ctx, query_bio)) == NULL)
++        goto end;
++    ret = 1;
++
++ end:
++    if (!ret) {
++        TS_RESP_free(response);
++        response = NULL;
++    }
++    TS_RESP_CTX_free(resp_ctx);
++    BIO_free_all(query_bio);
++    return response;
++}
++
++static ASN1_INTEGER *serial_cb(TS_RESP_CTX *ctx, void *data)
++{
++    const char *serial_file = (const char *)data;
++    ASN1_INTEGER *serial = next_serial(serial_file);
++
++    if (!serial) {
++        TS_RESP_CTX_set_status_info(ctx, TS_STATUS_REJECTION,
++                                    "Error during serial number "
++                                    "generation.");
++        TS_RESP_CTX_add_failure_info(ctx, TS_INFO_ADD_INFO_NOT_AVAILABLE);
++    } else
++        save_ts_serial(serial_file, serial);
++
++    return serial;
++}
++
++static ASN1_INTEGER *next_serial(const char *serialfile)
++{
++    int ret = 0;
++    BIO *in = NULL;
++    ASN1_INTEGER *serial = NULL;
++    BIGNUM *bn = NULL;
++
++    if ((serial = ASN1_INTEGER_new()) == NULL)
++        goto err;
++
++    if ((in = BIO_new_file(serialfile, "r")) == NULL) {
++        ERR_clear_error();
++        BIO_printf(bio_err, "Warning: could not open file %s for "
++                   "reading, using serial number: 1\n", serialfile);
++        if (!ASN1_INTEGER_set(serial, 1))
++            goto err;
++    } else {
++        char buf[1024];
++        if (!a2i_ASN1_INTEGER(in, serial, buf, sizeof(buf))) {
++            BIO_printf(bio_err, "unable to load number from %s\n",
++                       serialfile);
++            goto err;
++        }
++        if ((bn = ASN1_INTEGER_to_BN(serial, NULL)) == NULL)
++            goto err;
++        ASN1_INTEGER_free(serial);
++        serial = NULL;
++        if (!BN_add_word(bn, 1))
++            goto err;
++        if ((serial = BN_to_ASN1_INTEGER(bn, NULL)) == NULL)
++            goto err;
++    }
++    ret = 1;
++
++ err:
++    if (!ret) {
++        ASN1_INTEGER_free(serial);
++        serial = NULL;
++    }
++    BIO_free_all(in);
++    BN_free(bn);
++    return serial;
++}
++
++static int save_ts_serial(const char *serialfile, ASN1_INTEGER *serial)
++{
++    int ret = 0;
++    BIO *out = NULL;
++
++    if ((out = BIO_new_file(serialfile, "w")) == NULL)
++        goto err;
++    if (i2a_ASN1_INTEGER(out, serial) <= 0)
++        goto err;
++    if (BIO_puts(out, "\n") <= 0)
++        goto err;
++    ret = 1;
++ err:
++    if (!ret)
++        BIO_printf(bio_err, "could not save serial number to %s\n",
++                   serialfile);
++    BIO_free_all(out);
++    return ret;
++}
++
++
++/*
++ * Verify-related method definitions.
++ */
++
++static int verify_command(const char *data, const char *digest, const char *queryfile,
++                          const char *in, int token_in,
++                          const char *CApath, const char *CAfile, const char *untrusted,
++                          X509_VERIFY_PARAM *vpm)
++{
++    BIO *in_bio = NULL;
++    PKCS7 *token = NULL;
++    TS_RESP *response = NULL;
++    TS_VERIFY_CTX *verify_ctx = NULL;
++    int ret = 0;
++
++    if ((in_bio = BIO_new_file(in, "rb")) == NULL)
++        goto end;
++    if (token_in) {
++        if ((token = d2i_PKCS7_bio(in_bio, NULL)) == NULL)
++            goto end;
++    } else {
++        if ((response = d2i_TS_RESP_bio(in_bio, NULL)) == NULL)
++            goto end;
++    }
++
++    if ((verify_ctx = create_verify_ctx(data, digest, queryfile,
++                                        CApath, CAfile, untrusted,
++                                        vpm)) == NULL)
++        goto end;
++
++    ret = token_in
++        ? TS_RESP_verify_token(verify_ctx, token)
++        : TS_RESP_verify_response(verify_ctx, response);
++
++ end:
++    printf("Verification: ");
++    if (ret)
++        printf("OK\n");
++    else {
++        printf("FAILED\n");
++        ERR_print_errors(bio_err);
++    }
++
++    BIO_free_all(in_bio);
++    PKCS7_free(token);
++    TS_RESP_free(response);
++    TS_VERIFY_CTX_free(verify_ctx);
++    return ret;
++}
++
++static TS_VERIFY_CTX *create_verify_ctx(const char *data, const char *digest,
++                                        const char *queryfile,
++                                        const char *CApath, const char *CAfile,
++                                        const char *untrusted,
++                                        X509_VERIFY_PARAM *vpm)
++{
++    TS_VERIFY_CTX *ctx = NULL;
++    BIO *input = NULL;
++    TS_REQ *request = NULL;
++    int ret = 0;
++    int f = 0;
++
++    if (data != NULL || digest != NULL) {
++        if ((ctx = TS_VERIFY_CTX_new()) == NULL)
++            goto err;
++        f = TS_VFY_VERSION | TS_VFY_SIGNER;
++        if (data != NULL) {
++            BIO *out = NULL;
++
++            f |= TS_VFY_DATA;
++            if ((out = BIO_new_file(data, "rb")) == NULL)
++                goto err;
++            if (TS_VERIFY_CTX_set_data(ctx, out) == NULL) {
++                BIO_free_all(out);
++                goto err;
++            }
++        } else if (digest != NULL) {
++            long imprint_len;
++            unsigned char *hexstr = OPENSSL_hexstr2buf(digest, &imprint_len);
++            f |= TS_VFY_IMPRINT;
++            if (TS_VERIFY_CTX_set_imprint(ctx, hexstr, imprint_len) == NULL) {
++                BIO_printf(bio_err, "invalid digest string\n");
++                goto err;
++            }
++        }
++
++    } else if (queryfile != NULL) {
++        if ((input = BIO_new_file(queryfile, "rb")) == NULL)
++            goto err;
++        if ((request = d2i_TS_REQ_bio(input, NULL)) == NULL)
++            goto err;
++        if ((ctx = TS_REQ_to_TS_VERIFY_CTX(request, NULL)) == NULL)
++            goto err;
++    } else
++        return NULL;
++
++    /* Add the signature verification flag and arguments. */
++    TS_VERIFY_CTX_add_flags(ctx, f | TS_VFY_SIGNATURE);
++
++    /* Initialising the X509_STORE object. */
++    if (TS_VERIFY_CTX_set_store(ctx, create_cert_store(CApath, CAfile, vpm))
++            == NULL)
++        goto err;
++
++    /* Loading untrusted certificates. */
++    if (untrusted
++        && TS_VERIFY_CTS_set_certs(ctx, TS_CONF_load_certs(untrusted)) == NULL)
++        goto err;
++    ret = 1;
++
++ err:
++    if (!ret) {
++        TS_VERIFY_CTX_free(ctx);
++        ctx = NULL;
++    }
++    BIO_free_all(input);
++    TS_REQ_free(request);
++    return ctx;
++}
++
++static X509_STORE *create_cert_store(const char *CApath, const char *CAfile,
++                                     X509_VERIFY_PARAM *vpm)
++{
++    X509_STORE *cert_ctx = NULL;
++    X509_LOOKUP *lookup = NULL;
++    int i;
++
++    cert_ctx = X509_STORE_new();
++    X509_STORE_set_verify_cb(cert_ctx, verify_cb);
++    if (CApath != NULL) {
++        lookup = X509_STORE_add_lookup(cert_ctx, X509_LOOKUP_hash_dir());
++        if (lookup == NULL) {
++            BIO_printf(bio_err, "memory allocation failure\n");
++            goto err;
++        }
++        i = X509_LOOKUP_add_dir(lookup, CApath, X509_FILETYPE_PEM);
++        if (!i) {
++            BIO_printf(bio_err, "Error loading directory %s\n", CApath);
++            goto err;
++        }
++    }
++
++    if (CAfile != NULL) {
++        lookup = X509_STORE_add_lookup(cert_ctx, X509_LOOKUP_file());
++        if (lookup == NULL) {
++            BIO_printf(bio_err, "memory allocation failure\n");
++            goto err;
++        }
++        i = X509_LOOKUP_load_file(lookup, CAfile, X509_FILETYPE_PEM);
++        if (!i) {
++            BIO_printf(bio_err, "Error loading file %s\n", CAfile);
++            goto err;
++        }
++    }
++
++    if (vpm != NULL)
++        X509_STORE_set1_param(cert_ctx, vpm);
++
++    return cert_ctx;
++
++ err:
++    X509_STORE_free(cert_ctx);
++    return NULL;
++}
++
++static int verify_cb(int ok, X509_STORE_CTX *ctx)
++{
++    return ok;
++}
++#endif  /* ndef OPENSSL_NO_TS */
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/apps/tsget.in b/CryptoPkg/Library/OpensslLib/openssl/apps/tsget.in
+new file mode 100644
+index 0000000..89d1bc7
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/apps/tsget.in
+@@ -0,0 +1,201 @@
++#!{- $config{hashbangperl} -}
++# Copyright (c) 2002 The OpenTSA Project. All rights reserved.
++# Copyright 2002-2016 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
++# in the file LICENSE in the source distribution or at
++# https://www.openssl.org/source/license.html
++
++use strict;
++use IO::Handle;
++use Getopt::Std;
++use File::Basename;
++use WWW::Curl::Easy;
++
++use vars qw(%options);
++
++# Callback for reading the body.
++sub read_body {
++    my ($maxlength, $state) = @_;
++    my $return_data = "";
++    my $data_len = length ${$state->{data}};
++    if ($state->{bytes} < $data_len) {
++	$data_len = $data_len - $state->{bytes};
++	$data_len = $maxlength if $data_len > $maxlength;
++	$return_data = substr ${$state->{data}}, $state->{bytes}, $data_len;
++	$state->{bytes} += $data_len;
++    }
++    return $return_data;
++}
++
++# Callback for writing the body into a variable.
++sub write_body {
++    my ($data, $pointer) = @_;
++    ${$pointer} .= $data;
++    return length($data);
++}
++
++# Initialise a new Curl object.
++sub create_curl {
++    my $url = shift;
++
++    # Create Curl object.
++    my $curl = WWW::Curl::Easy::new();
++
++    # Error-handling related options.
++    $curl->setopt(CURLOPT_VERBOSE, 1) if $options{d};
++    $curl->setopt(CURLOPT_FAILONERROR, 1);
++    $curl->setopt(CURLOPT_USERAGENT,
++        "OpenTSA tsget.pl/openssl-{- $config{version} -}");
++
++    # Options for POST method.
++    $curl->setopt(CURLOPT_UPLOAD, 1);
++    $curl->setopt(CURLOPT_CUSTOMREQUEST, "POST");
++    $curl->setopt(CURLOPT_HTTPHEADER,
++		["Content-Type: application/timestamp-query",
++		"Accept: application/timestamp-reply,application/timestamp-response"]);
++    $curl->setopt(CURLOPT_READFUNCTION, \&read_body);
++    $curl->setopt(CURLOPT_HEADERFUNCTION, sub { return length($_[0]); });
++
++    # Options for getting the result.
++    $curl->setopt(CURLOPT_WRITEFUNCTION, \&write_body);
++
++    # SSL related options.
++    $curl->setopt(CURLOPT_SSLKEYTYPE, "PEM");
++    $curl->setopt(CURLOPT_SSL_VERIFYPEER, 1);	# Verify server's certificate.
++    $curl->setopt(CURLOPT_SSL_VERIFYHOST, 2);	# Check server's CN.
++    $curl->setopt(CURLOPT_SSLKEY, $options{k}) if defined($options{k});
++    $curl->setopt(CURLOPT_SSLKEYPASSWD, $options{p}) if defined($options{p});
++    $curl->setopt(CURLOPT_SSLCERT, $options{c}) if defined($options{c});
++    $curl->setopt(CURLOPT_CAINFO, $options{C}) if defined($options{C});
++    $curl->setopt(CURLOPT_CAPATH, $options{P}) if defined($options{P});
++    $curl->setopt(CURLOPT_RANDOM_FILE, $options{r}) if defined($options{r});
++    $curl->setopt(CURLOPT_EGDSOCKET, $options{g}) if defined($options{g});
++
++    # Setting destination.
++    $curl->setopt(CURLOPT_URL, $url);
++
++    return $curl;
++}
++
++# Send a request and returns the body back.
++sub get_timestamp {
++    my $curl = shift;
++    my $body = shift;
++    my $ts_body;
++    local $::error_buf;
++
++    # Error-handling related options.
++    $curl->setopt(CURLOPT_ERRORBUFFER, "::error_buf");
++
++    # Options for POST method.
++    $curl->setopt(CURLOPT_INFILE, {data => $body, bytes => 0});
++    $curl->setopt(CURLOPT_INFILESIZE, length(${$body}));
++
++    # Options for getting the result.
++    $curl->setopt(CURLOPT_FILE, \$ts_body);
++
++    # Send the request...
++    my $error_code = $curl->perform();
++    my $error_string;
++    if ($error_code != 0) {
++        my $http_code = $curl->getinfo(CURLINFO_HTTP_CODE);
++	$error_string = "could not get timestamp";
++	$error_string .= ", http code: $http_code" unless $http_code == 0;
++	$error_string .= ", curl code: $error_code";
++	$error_string .= " ($::error_buf)" if defined($::error_buf);
++    } else {
++        my $ct = $curl->getinfo(CURLINFO_CONTENT_TYPE);
++	if (lc($ct) ne "application/timestamp-reply"
++	    && lc($ct) ne "application/timestamp-response") {
++	    $error_string = "unexpected content type returned: $ct";
++        }
++    }
++    return ($ts_body, $error_string);
++
++}
++
++# Print usage information and exists.
++sub usage {
++
++    print STDERR "usage: $0 -h  [-e ] [-o ] ";
++    print STDERR "[-v] [-d] [-k ] [-p ] ";
++    print STDERR "[-c ] [-C ] [-P ] ";
++    print STDERR "[-r ] [-g ] []...\n";
++    exit 1;
++}
++
++# ----------------------------------------------------------------------
++#   Main program
++# ----------------------------------------------------------------------
++
++# Getting command-line options (default comes from TSGET environment variable).
++my $getopt_arg =  "h:e:o:vdk:p:c:C:P:r:g:";
++if (exists $ENV{TSGET}) {
++    my @old_argv = @ARGV;
++    @ARGV = split /\s+/, $ENV{TSGET};
++    getopts($getopt_arg, \%options) or usage;
++    @ARGV = @old_argv;
++}
++getopts($getopt_arg, \%options) or usage;
++
++# Checking argument consistency.
++if (!exists($options{h}) || (@ARGV == 0 && !exists($options{o}))
++    || (@ARGV > 1 && exists($options{o}))) {
++    print STDERR "Inconsistent command line options.\n";
++    usage;
++}
++# Setting defaults.
++@ARGV = ("-") unless @ARGV != 0;
++$options{e} = ".tsr" unless defined($options{e});
++
++# Processing requests.
++my $curl = create_curl $options{h};
++undef $/;   # For reading whole files.
++REQUEST: foreach (@ARGV) {
++    my $input = $_;
++    my ($base, $path) = fileparse($input, '\.[^.]*');
++    my $output_base = $base . $options{e};
++    my $output = defined($options{o}) ? $options{o} : $path . $output_base;
++
++    STDERR->printflush("$input: ") if $options{v};
++    # Read request.
++    my $body;
++    if ($input eq "-") {
++	# Read the request from STDIN;
++	$body = ;
++    } else {
++	# Read the request from file.
++        open INPUT, "<" . $input
++	    or warn("$input: could not open input file: $!\n"), next REQUEST;
++        $body = ;
++        close INPUT
++	    or warn("$input: could not close input file: $!\n"), next REQUEST;
++    }
++
++    # Send request.
++    STDERR->printflush("sending request") if $options{v};
++
++    my ($ts_body, $error) = get_timestamp $curl, \$body;
++    if (defined($error)) {
++	die "$input: fatal error: $error\n";
++    }
++    STDERR->printflush(", reply received") if $options{v};
++
++    # Write response.
++    if ($output eq "-") {
++	# Write to STDOUT.
++        print $ts_body;
++    } else {
++	# Write to file.
++        open OUTPUT, ">", $output
++	    or warn("$output: could not open output file: $!\n"), next REQUEST;
++        print OUTPUT $ts_body;
++        close OUTPUT
++	    or warn("$output: could not close output file: $!\n"), next REQUEST;
++    }
++    STDERR->printflush(", $output written.\n") if $options{v};
++}
++$curl->cleanup();
++WWW::Curl::Easy::global_cleanup();
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/apps/verify.c b/CryptoPkg/Library/OpensslLib/openssl/apps/verify.c
+new file mode 100644
+index 0000000..3c45663
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/apps/verify.c
+@@ -0,0 +1,311 @@
++/*
++ * Copyright 1995-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include 
++#include 
++#include "apps.h"
++#include 
++#include 
++#include 
++#include 
++#include 
++
++static int cb(int ok, X509_STORE_CTX *ctx);
++static int check(X509_STORE *ctx, const char *file,
++                 STACK_OF(X509) *uchain, STACK_OF(X509) *tchain,
++                 STACK_OF(X509_CRL) *crls, int show_chain);
++static int v_verbose = 0, vflags = 0;
++
++typedef enum OPTION_choice {
++    OPT_ERR = -1, OPT_EOF = 0, OPT_HELP,
++    OPT_ENGINE, OPT_CAPATH, OPT_CAFILE, OPT_NOCAPATH, OPT_NOCAFILE,
++    OPT_UNTRUSTED, OPT_TRUSTED, OPT_CRLFILE, OPT_CRL_DOWNLOAD, OPT_SHOW_CHAIN,
++    OPT_V_ENUM,
++    OPT_VERBOSE
++} OPTION_CHOICE;
++
++OPTIONS verify_options[] = {
++    {OPT_HELP_STR, 1, '-', "Usage: %s [options] cert.pem...\n"},
++    {OPT_HELP_STR, 1, '-', "Valid options are:\n"},
++    {"help", OPT_HELP, '-', "Display this summary"},
++    {"verbose", OPT_VERBOSE, '-',
++        "Print extra information about the operations being performed."},
++    {"CApath", OPT_CAPATH, '/', "A directory of trusted certificates"},
++    {"CAfile", OPT_CAFILE, '<', "A file of trusted certificates"},
++    {"no-CAfile", OPT_NOCAFILE, '-',
++     "Do not load the default certificates file"},
++    {"no-CApath", OPT_NOCAPATH, '-',
++     "Do not load certificates from the default certificates directory"},
++    {"untrusted", OPT_UNTRUSTED, '<', "A file of untrusted certificates"},
++    {"trusted", OPT_TRUSTED, '<', "A file of trusted certificates"},
++    {"CRLfile", OPT_CRLFILE, '<',
++        "File containing one or more CRL's (in PEM format) to load"},
++    {"crl_download", OPT_CRL_DOWNLOAD, '-',
++        "Attempt to download CRL information for this certificate"},
++    {"show_chain", OPT_SHOW_CHAIN, '-',
++        "Display information about the certificate chain"},
++    OPT_V_OPTIONS,
++#ifndef OPENSSL_NO_ENGINE
++    {"engine", OPT_ENGINE, 's', "Use engine, possibly a hardware device"},
++#endif
++    {NULL}
++};
++
++int verify_main(int argc, char **argv)
++{
++    ENGINE *e = NULL;
++    STACK_OF(X509) *untrusted = NULL, *trusted = NULL;
++    STACK_OF(X509_CRL) *crls = NULL;
++    X509_STORE *store = NULL;
++    X509_VERIFY_PARAM *vpm = NULL;
++    const char *prog, *CApath = NULL, *CAfile = NULL;
++    int noCApath = 0, noCAfile = 0;
++    int vpmtouched = 0, crl_download = 0, show_chain = 0, i = 0, ret = 1;
++    OPTION_CHOICE o;
++
++    if ((vpm = X509_VERIFY_PARAM_new()) == NULL)
++        goto end;
++
++    prog = opt_init(argc, argv, verify_options);
++    while ((o = opt_next()) != OPT_EOF) {
++        switch (o) {
++        case OPT_EOF:
++        case OPT_ERR:
++            BIO_printf(bio_err, "%s: Use -help for summary.\n", prog);
++            goto end;
++        case OPT_HELP:
++            opt_help(verify_options);
++            BIO_printf(bio_err, "Recognized usages:\n");
++            for (i = 0; i < X509_PURPOSE_get_count(); i++) {
++                X509_PURPOSE *ptmp;
++                ptmp = X509_PURPOSE_get0(i);
++                BIO_printf(bio_err, "\t%-10s\t%s\n",
++                        X509_PURPOSE_get0_sname(ptmp),
++                        X509_PURPOSE_get0_name(ptmp));
++            }
++
++            BIO_printf(bio_err, "Recognized verify names:\n");
++            for (i = 0; i < X509_VERIFY_PARAM_get_count(); i++) {
++                const X509_VERIFY_PARAM *vptmp;
++                vptmp = X509_VERIFY_PARAM_get0(i);
++                BIO_printf(bio_err, "\t%-10s\n",
++                        X509_VERIFY_PARAM_get0_name(vptmp));
++            }
++            ret = 0;
++            goto end;
++        case OPT_V_CASES:
++            if (!opt_verify(o, vpm))
++                goto end;
++            vpmtouched++;
++            break;
++        case OPT_CAPATH:
++            CApath = opt_arg();
++            break;
++        case OPT_CAFILE:
++            CAfile = opt_arg();
++            break;
++        case OPT_NOCAPATH:
++            noCApath = 1;
++            break;
++        case OPT_NOCAFILE:
++            noCAfile = 1;
++            break;
++        case OPT_UNTRUSTED:
++            /* Zero or more times */
++            if (!load_certs(opt_arg(), &untrusted, FORMAT_PEM, NULL,
++                            "untrusted certificates"))
++                goto end;
++            break;
++        case OPT_TRUSTED:
++            /* Zero or more times */
++            noCAfile = 1;
++            noCApath = 1;
++            if (!load_certs(opt_arg(), &trusted, FORMAT_PEM, NULL,
++                            "trusted certificates"))
++                goto end;
++            break;
++        case OPT_CRLFILE:
++            /* Zero or more times */
++            if (!load_crls(opt_arg(), &crls, FORMAT_PEM, NULL,
++                           "other CRLs"))
++                goto end;
++            break;
++        case OPT_CRL_DOWNLOAD:
++            crl_download = 1;
++            break;
++        case OPT_ENGINE:
++            if ((e = setup_engine(opt_arg(), 0)) == NULL) {
++                /* Failure message already displayed */
++                goto end;
++            }
++            break;
++        case OPT_SHOW_CHAIN:
++            show_chain = 1;
++            break;
++        case OPT_VERBOSE:
++            v_verbose = 1;
++            break;
++        }
++    }
++    argc = opt_num_rest();
++    argv = opt_rest();
++    if (trusted != NULL && (CAfile || CApath)) {
++        BIO_printf(bio_err,
++                   "%s: Cannot use -trusted with -CAfile or -CApath\n",
++                   prog);
++        goto end;
++    }
++
++    if ((store = setup_verify(CAfile, CApath, noCAfile, noCApath)) == NULL)
++        goto end;
++    X509_STORE_set_verify_cb(store, cb);
++
++    if (vpmtouched)
++        X509_STORE_set1_param(store, vpm);
++
++    ERR_clear_error();
++
++    if (crl_download)
++        store_setup_crl_download(store);
++
++    ret = 0;
++    if (argc < 1) {
++        if (check(store, NULL, untrusted, trusted, crls, show_chain) != 1)
++            ret = -1;
++    } else {
++        for (i = 0; i < argc; i++)
++            if (check(store, argv[i], untrusted, trusted, crls,
++                      show_chain) != 1)
++                ret = -1;
++    }
++
++ end:
++    X509_VERIFY_PARAM_free(vpm);
++    X509_STORE_free(store);
++    sk_X509_pop_free(untrusted, X509_free);
++    sk_X509_pop_free(trusted, X509_free);
++    sk_X509_CRL_pop_free(crls, X509_CRL_free);
++    release_engine(e);
++    return (ret < 0 ? 2 : ret);
++}
++
++static int check(X509_STORE *ctx, const char *file,
++                 STACK_OF(X509) *uchain, STACK_OF(X509) *tchain,
++                 STACK_OF(X509_CRL) *crls, int show_chain)
++{
++    X509 *x = NULL;
++    int i = 0, ret = 0;
++    X509_STORE_CTX *csc;
++    STACK_OF(X509) *chain = NULL;
++    int num_untrusted;
++
++    x = load_cert(file, FORMAT_PEM, "certificate file");
++    if (x == NULL)
++        goto end;
++
++    csc = X509_STORE_CTX_new();
++    if (csc == NULL) {
++        printf("error %s: X.509 store context allocation failed\n",
++               (file == NULL) ? "stdin" : file);
++        goto end;
++    }
++
++    X509_STORE_set_flags(ctx, vflags);
++    if (!X509_STORE_CTX_init(csc, ctx, x, uchain)) {
++        printf("error %s: X.509 store context initialization failed\n",
++               (file == NULL) ? "stdin" : file);
++        goto end;
++    }
++    if (tchain)
++        X509_STORE_CTX_set0_trusted_stack(csc, tchain);
++    if (crls)
++        X509_STORE_CTX_set0_crls(csc, crls);
++    i = X509_verify_cert(csc);
++    if (i > 0 && X509_STORE_CTX_get_error(csc) == X509_V_OK) {
++        printf("%s: OK\n", (file == NULL) ? "stdin" : file);
++        ret = 1;
++        if (show_chain) {
++            int j;
++
++            chain = X509_STORE_CTX_get1_chain(csc);
++            num_untrusted = X509_STORE_CTX_get_num_untrusted(csc);
++            printf("Chain:\n");
++            for (j = 0; j < sk_X509_num(chain); j++) {
++                X509 *cert = sk_X509_value(chain, j);
++                printf("depth=%d: ", j);
++                X509_NAME_print_ex_fp(stdout,
++                                      X509_get_subject_name(cert),
++                                      0, XN_FLAG_ONELINE);
++                if (j < num_untrusted)
++                    printf(" (untrusted)");
++                printf("\n");
++            }
++            sk_X509_pop_free(chain, X509_free);
++        }
++    } else {
++        printf("error %s: verification failed\n", (file == NULL) ? "stdin" : file);
++    }
++    X509_STORE_CTX_free(csc);
++
++ end:
++    if (i <= 0)
++        ERR_print_errors(bio_err);
++    X509_free(x);
++
++    return ret;
++}
++
++static int cb(int ok, X509_STORE_CTX *ctx)
++{
++    int cert_error = X509_STORE_CTX_get_error(ctx);
++    X509 *current_cert = X509_STORE_CTX_get_current_cert(ctx);
++
++    if (!ok) {
++        if (current_cert) {
++            X509_NAME_print_ex(bio_err,
++                            X509_get_subject_name(current_cert),
++                            0, XN_FLAG_ONELINE);
++            BIO_printf(bio_err, "\n");
++        }
++        BIO_printf(bio_err, "%serror %d at %d depth lookup: %s\n",
++               X509_STORE_CTX_get0_parent_ctx(ctx) ? "[CRL path] " : "",
++               cert_error,
++               X509_STORE_CTX_get_error_depth(ctx),
++               X509_verify_cert_error_string(cert_error));
++        switch (cert_error) {
++        case X509_V_ERR_NO_EXPLICIT_POLICY:
++            policies_print(ctx);
++        case X509_V_ERR_CERT_HAS_EXPIRED:
++
++            /*
++             * since we are just checking the certificates, it is ok if they
++             * are self signed. But we should still warn the user.
++             */
++        case X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT:
++            /* Continue after extension errors too */
++        case X509_V_ERR_INVALID_CA:
++        case X509_V_ERR_INVALID_NON_CA:
++        case X509_V_ERR_PATH_LENGTH_EXCEEDED:
++        case X509_V_ERR_INVALID_PURPOSE:
++        case X509_V_ERR_CRL_HAS_EXPIRED:
++        case X509_V_ERR_CRL_NOT_YET_VALID:
++        case X509_V_ERR_UNHANDLED_CRITICAL_EXTENSION:
++            ok = 1;
++        }
++
++        return ok;
++
++    }
++    if (cert_error == X509_V_OK && ok == 2)
++        policies_print(ctx);
++    if (!v_verbose)
++        ERR_clear_error();
++    return (ok);
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/apps/version.c b/CryptoPkg/Library/OpensslLib/openssl/apps/version.c
+new file mode 100644
+index 0000000..e3c8299
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/apps/version.c
+@@ -0,0 +1,140 @@
++/*
++ * Copyright 1995-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include 
++#include 
++#include "apps.h"
++#include 
++#include 
++#include 
++#ifndef OPENSSL_NO_MD2
++# include 
++#endif
++#ifndef OPENSSL_NO_RC4
++# include 
++#endif
++#ifndef OPENSSL_NO_DES
++# include 
++#endif
++#ifndef OPENSSL_NO_IDEA
++# include 
++#endif
++#ifndef OPENSSL_NO_BF
++# include 
++#endif
++
++typedef enum OPTION_choice {
++    OPT_ERR = -1, OPT_EOF = 0, OPT_HELP,
++    OPT_B, OPT_D, OPT_E, OPT_F, OPT_O, OPT_P, OPT_V, OPT_A
++} OPTION_CHOICE;
++
++OPTIONS version_options[] = {
++    {"help", OPT_HELP, '-', "Display this summary"},
++    {"a", OPT_A, '-', "Show all data"},
++    {"b", OPT_B, '-', "Show build date"},
++    {"d", OPT_D, '-', "Show configuration directory"},
++    {"e", OPT_E, '-', "Show engines directory"},
++    {"f", OPT_F, '-', "Show compiler flags used"},
++    {"o", OPT_O, '-', "Show some internal datatype options"},
++    {"p", OPT_P, '-', "Show target build platform"},
++    {"v", OPT_V, '-', "Show library version"},
++    {NULL}
++};
++
++int version_main(int argc, char **argv)
++{
++    int ret = 1, dirty = 0;
++    int cflags = 0, version = 0, date = 0, options = 0, platform = 0, dir = 0;
++    int engdir = 0;
++    char *prog;
++    OPTION_CHOICE o;
++
++    prog = opt_init(argc, argv, version_options);
++    while ((o = opt_next()) != OPT_EOF) {
++        switch (o) {
++        case OPT_EOF:
++        case OPT_ERR:
++            BIO_printf(bio_err, "%s: Use -help for summary.\n", prog);
++            goto end;
++        case OPT_HELP:
++            opt_help(version_options);
++            ret = 0;
++            goto end;
++        case OPT_B:
++            dirty = date = 1;
++            break;
++        case OPT_D:
++            dirty = dir = 1;
++            break;
++        case OPT_E:
++            dirty = engdir = 1;
++            break;
++        case OPT_F:
++            dirty = cflags = 1;
++            break;
++        case OPT_O:
++            dirty = options = 1;
++            break;
++        case OPT_P:
++            dirty = platform = 1;
++            break;
++        case OPT_V:
++            dirty = version = 1;
++            break;
++        case OPT_A:
++            cflags = version = date = platform = dir = engdir = 1;
++            break;
++        }
++    }
++    if (!dirty)
++        version = 1;
++
++    if (version) {
++        if (OpenSSL_version_num() == OPENSSL_VERSION_NUMBER) {
++            printf("%s\n", OpenSSL_version(OPENSSL_VERSION));
++        } else {
++            printf("%s (Library: %s)\n",
++                   OPENSSL_VERSION_TEXT, OpenSSL_version(OPENSSL_VERSION));
++        }
++    }
++    if (date)
++        printf("%s\n", OpenSSL_version(OPENSSL_BUILT_ON));
++    if (platform)
++        printf("%s\n", OpenSSL_version(OPENSSL_PLATFORM));
++    if (options) {
++        printf("options:  ");
++        printf("%s ", BN_options());
++#ifndef OPENSSL_NO_MD2
++        printf("%s ", MD2_options());
++#endif
++#ifndef OPENSSL_NO_RC4
++        printf("%s ", RC4_options());
++#endif
++#ifndef OPENSSL_NO_DES
++        printf("%s ", DES_options());
++#endif
++#ifndef OPENSSL_NO_IDEA
++        printf("%s ", IDEA_options());
++#endif
++#ifndef OPENSSL_NO_BF
++        printf("%s ", BF_options());
++#endif
++        printf("\n");
++    }
++    if (cflags)
++        printf("%s\n", OpenSSL_version(OPENSSL_CFLAGS));
++    if (dir)
++        printf("%s\n", OpenSSL_version(OPENSSL_DIR));
++    if (engdir)
++        printf("%s\n", OpenSSL_version(OPENSSL_ENGINES_DIR));
++    ret = 0;
++ end:
++    return (ret);
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/apps/vms_decc_init.c b/CryptoPkg/Library/OpensslLib/openssl/apps/vms_decc_init.c
+new file mode 100644
+index 0000000..f83f716
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/apps/vms_decc_init.c
+@@ -0,0 +1,214 @@
++/*
++ * Copyright 2010-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#if defined( __VMS) && !defined( OPENSSL_NO_DECC_INIT) && \
++ defined( __DECC) && !defined( __VAX) && (__CRTL_VER >= 70301000)
++# define USE_DECC_INIT 1
++#endif
++
++#ifdef USE_DECC_INIT
++
++/*
++ * ----------------------------------------------------------------------
++ * decc_init() On non-VAX systems, uses LIB$INITIALIZE to set a collection
++ * of C RTL features without using the DECC$* logical name method.
++ * ----------------------------------------------------------------------
++ */
++
++# include 
++# include 
++# include 
++
++# include "apps.h"
++
++/* Global storage. */
++
++/* Flag to sense if decc_init() was called. */
++
++int decc_init_done = -1;
++
++/* Structure to hold a DECC$* feature name and its desired value. */
++
++typedef struct {
++    char *name;
++    int value;
++} decc_feat_t;
++
++/*
++ * Array of DECC$* feature names and their desired values. Note:
++ * DECC$ARGV_PARSE_STYLE is the urgent one.
++ */
++
++decc_feat_t decc_feat_array[] = {
++    /* Preserve command-line case with SET PROCESS/PARSE_STYLE=EXTENDED */
++    {"DECC$ARGV_PARSE_STYLE", 1},
++
++    /* Preserve case for file names on ODS5 disks. */
++    {"DECC$EFS_CASE_PRESERVE", 1},
++
++    /*
++     * Enable multiple dots (and most characters) in ODS5 file names, while
++     * preserving VMS-ness of ";version".
++     */
++    {"DECC$EFS_CHARSET", 1},
++
++    /* List terminator. */
++    {(char *)NULL, 0}
++};
++
++
++char **copy_argv(int *argc, char *argv[])
++{
++    /*-
++     * The note below is for historical purpose.  On VMS now we always
++     * copy argv "safely."
++     *
++     * 2011-03-22 SMS.
++     * If we have 32-bit pointers everywhere, then we're safe, and
++     * we bypass this mess, as on non-VMS systems.
++     * Problem 1: Compaq/HP C before V7.3 always used 32-bit
++     * pointers for argv[].
++     * Fix 1: For a 32-bit argv[], when we're using 64-bit pointers
++     * everywhere else, we always allocate and use a 64-bit
++     * duplicate of argv[].
++     * Problem 2: Compaq/HP C V7.3 (Alpha, IA64) before ECO1 failed
++     * to NULL-terminate a 64-bit argv[].  (As this was written, the
++     * compiler ECO was available only on IA64.)
++     * Fix 2: Unless advised not to (VMS_TRUST_ARGV), we test a
++     * 64-bit argv[argc] for NULL, and, if necessary, use a
++     * (properly) NULL-terminated (64-bit) duplicate of argv[].
++     * The same code is used in either case to duplicate argv[].
++     * Some of these decisions could be handled in preprocessing,
++     * but the code tends to get even uglier, and the penalty for
++     * deciding at compile- or run-time is tiny.
++     */
++
++    int i, count = *argc;
++    char **newargv = app_malloc(sizeof(*newargv) * (count + 1), "argv copy");
++
++    for (i = 0; i < count; i++)
++        newargv[i] = argv[i];
++    newargv[i] = NULL;
++    *argc = i;
++    return newargv;
++}
++
++/* LIB$INITIALIZE initialization function. */
++
++static void decc_init(void)
++{
++    char *openssl_debug_decc_init;
++    int verbose = 0;
++    int feat_index;
++    int feat_value;
++    int feat_value_max;
++    int feat_value_min;
++    int i;
++    int sts;
++
++    /* Get debug option. */
++    openssl_debug_decc_init = getenv("OPENSSL_DEBUG_DECC_INIT");
++    if (openssl_debug_decc_init != NULL) {
++        verbose = strtol(openssl_debug_decc_init, NULL, 10);
++        if (verbose <= 0) {
++            verbose = 1;
++        }
++    }
++
++    /* Set the global flag to indicate that LIB$INITIALIZE worked. */
++    decc_init_done = 1;
++
++    /* Loop through all items in the decc_feat_array[]. */
++
++    for (i = 0; decc_feat_array[i].name != NULL; i++) {
++        /* Get the feature index. */
++        feat_index = decc$feature_get_index(decc_feat_array[i].name);
++        if (feat_index >= 0) {
++            /* Valid item.  Collect its properties. */
++            feat_value = decc$feature_get_value(feat_index, 1);
++            feat_value_min = decc$feature_get_value(feat_index, 2);
++            feat_value_max = decc$feature_get_value(feat_index, 3);
++
++            /* Check the validity of our desired value. */
++            if ((decc_feat_array[i].value >= feat_value_min) &&
++                (decc_feat_array[i].value <= feat_value_max)) {
++                /* Valid value.  Set it if necessary. */
++                if (feat_value != decc_feat_array[i].value) {
++                    sts = decc$feature_set_value(feat_index,
++                                                 1, decc_feat_array[i].value);
++
++                    if (verbose > 1) {
++                        fprintf(stderr, " %s = %d, sts = %d.\n",
++                                decc_feat_array[i].name,
++                                decc_feat_array[i].value, sts);
++                    }
++                }
++            } else {
++                /* Invalid DECC feature value. */
++                fprintf(stderr,
++                        " INVALID DECC$FEATURE VALUE, %d: %d <= %s <= %d.\n",
++                        feat_value,
++                        feat_value_min, decc_feat_array[i].name,
++                        feat_value_max);
++            }
++        } else {
++            /* Invalid DECC feature name. */
++            fprintf(stderr,
++                    " UNKNOWN DECC$FEATURE: %s.\n", decc_feat_array[i].name);
++        }
++    }
++
++    if (verbose > 0) {
++        fprintf(stderr, " DECC_INIT complete.\n");
++    }
++}
++
++/* Get "decc_init()" into a valid, loaded LIB$INITIALIZE PSECT. */
++
++# pragma nostandard
++
++/*
++ * Establish the LIB$INITIALIZE PSECTs, with proper alignment and other
++ * attributes.  Note that "nopic" is significant only on VAX.
++ */
++# pragma extern_model save
++
++# if __INITIAL_POINTER_SIZE == 64
++#  define PSECT_ALIGN 3
++# else
++#  define PSECT_ALIGN 2
++# endif
++
++# pragma extern_model strict_refdef "LIB$INITIALIZ" PSECT_ALIGN, nopic, nowrt
++const int spare[8] = { 0 };
++
++# pragma extern_model strict_refdef "LIB$INITIALIZE" PSECT_ALIGN, nopic, nowrt
++void (*const x_decc_init) () = decc_init;
++
++# pragma extern_model restore
++
++/* Fake reference to ensure loading the LIB$INITIALIZE PSECT. */
++
++# pragma extern_model save
++
++int LIB$INITIALIZE(void);
++
++# pragma extern_model strict_refdef
++int dmy_lib$initialize = (int)LIB$INITIALIZE;
++
++# pragma extern_model restore
++
++# pragma standard
++
++#else                           /* def USE_DECC_INIT */
++
++/* Dummy code to avoid a %CC-W-EMPTYFILE complaint. */
++int decc_init_dummy(void);
++
++#endif                          /* def USE_DECC_INIT */
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/apps/vms_term_sock.c b/CryptoPkg/Library/OpensslLib/openssl/apps/vms_term_sock.c
+new file mode 100644
+index 0000000..a7d87ff
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/apps/vms_term_sock.c
+@@ -0,0 +1,590 @@
++/*
++ * Copyright 2016 VMS Software, Inc. 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#ifdef __VMS
++# define OPENSSL_SYS_VMS
++# pragma message disable DOLLARID
++
++
++# include 
++
++# if !defined(_POSIX_C_SOURCE) && defined(OPENSSL_SYS_VMS)
++/*
++ * On VMS, you need to define this to get the declaration of fileno().  The
++ * value 2 is to make sure no function defined in POSIX-2 is left undefined.
++ */
++#  define _POSIX_C_SOURCE 2
++# endif
++
++# include 
++
++# undef _POSIX_C_SOURCE
++
++# include 
++# include 
++# include 
++# include 
++# include 
++# include 
++# include 
++# include 
++# include 
++# ifdef __alpha
++#  include 
++# else
++typedef struct _iosb {           /* Copied from IOSBDEF.H for Alpha  */
++#  pragma __nomember_alignment
++    __union  {
++        __struct  {
++            unsigned short int iosb$w_status; /* Final I/O status           */
++            __union  {
++                __struct  {             /* 16-bit byte count variant        */
++                    unsigned short int iosb$w_bcnt; /* 16-bit byte count    */
++                    __union  {
++                        unsigned int iosb$l_dev_depend; /* 32-bit device dependent info */
++                        unsigned int iosb$l_pid; /* 32-bit pid              */
++                    } iosb$r_l;
++                } iosb$r_bcnt_16;
++                __struct  {             /* 32-bit byte count variant        */
++                    unsigned int iosb$l_bcnt; /* 32-bit byte count (unaligned) */
++                    unsigned short int iosb$w_dev_depend_high; /* 16-bit device dependent info */
++                } iosb$r_bcnt_32;
++            } iosb$r_devdepend;
++        } iosb$r_io_64;
++        __struct  {
++            __union  {
++                unsigned int iosb$l_getxxi_status; /* Final GETxxI status   */
++                unsigned int iosb$l_reg_status; /* Final $Registry status   */
++            } iosb$r_l_status;
++            unsigned int iosb$l_reserved; /* Reserved field                 */
++        } iosb$r_get_64;
++    } iosb$r_io_get;
++} IOSB;
++
++#  if !defined(__VAXC)
++#   define iosb$w_status iosb$r_io_get.iosb$r_io_64.iosb$w_status
++#   define iosb$w_bcnt iosb$r_io_get.iosb$r_io_64.iosb$r_devdepend.iosb$r_bcnt_16.iosb$w_bcnt
++#   define iosb$r_l        iosb$r_io_get.iosb$r_io_64.iosb$r_devdepend.iosb$r_bcnt_16.iosb$r_l
++#   define iosb$l_dev_depend iosb$r_l.iosb$l_dev_depend
++#   define iosb$l_pid iosb$r_l.iosb$l_pid
++#   define iosb$l_bcnt iosb$r_io_get.iosb$r_io_64.iosb$r_devdepend.iosb$r_bcnt_32.iosb$l_bcnt
++#   define iosb$w_dev_depend_high iosb$r_io_get.iosb$r_io_64.iosb$r_devdepend.iosb$r_bcnt_32.iosb$w_dev_depend_high
++#   define iosb$l_getxxi_status iosb$r_io_get.iosb$r_get_64.iosb$r_l_status.iosb$l_getxxi_status
++#   define iosb$l_reg_status iosb$r_io_get.iosb$r_get_64.iosb$r_l_status.iosb$l_reg_status
++#  endif          /* #if !defined(__VAXC) */
++
++# endif  /* End of IOSBDEF */
++
++# include 
++# include 
++# include 
++# include 
++# include 
++# include 
++
++# include "vms_term_sock.h"
++
++# ifdef __alpha
++static struct _iosb TerminalDeviceIosb;
++# else
++IOSB TerminalDeviceIosb;
++# endif
++
++static char TerminalDeviceBuff[255 + 2];
++static int TerminalSocketPair[2] = {0, 0};
++static unsigned short TerminalDeviceChan = 0;
++
++static int CreateSocketPair (int, int, int, int *);
++static void SocketPairTimeoutAst (int);
++static int TerminalDeviceAst (int);
++static void LogMessage (char *, ...);
++
++/*
++** Socket Pair Timeout Value (must be 0-59 seconds)
++*/
++# define SOCKET_PAIR_TIMEOUT_VALUE 20
++
++/*
++** Socket Pair Timeout Block which is passed to timeout AST
++*/
++typedef struct _SocketPairTimeoutBlock {
++    unsigned short SockChan1;
++    unsigned short SockChan2;
++} SPTB;
++
++# ifdef TERM_SOCK_TEST
++
++/*----------------------------------------------------------------------------*/
++/*                                                                            */
++/*----------------------------------------------------------------------------*/
++int main (int argc, char *argv[], char *envp[])
++{
++    char TermBuff[80];
++    int TermSock,
++        status,
++        len;
++
++    LogMessage ("Enter 'q' or 'Q' to quit ...");
++    while (strcasecmp (TermBuff, "Q")) {
++        /*
++        ** Create the terminal socket
++        */
++        status = TerminalSocket (TERM_SOCK_CREATE, &TermSock);
++        if (status != TERM_SOCK_SUCCESS)
++            exit (1);
++
++        /*
++        ** Process the terminal input
++        */
++        LogMessage ("Waiting on terminal I/O ...\n");
++        len = recv (TermSock, TermBuff, sizeof (TermBuff), 0) ;
++        TermBuff[len] = '\0';
++        LogMessage ("Received terminal I/O [%s]", TermBuff);
++
++        /*
++        ** Delete the terminal socket
++        */
++        status = TerminalSocket (TERM_SOCK_DELETE, &TermSock);
++        if (status != TERM_SOCK_SUCCESS)
++            exit (1);
++    }
++
++    return 1;
++
++}
++# endif
++
++/*----------------------------------------------------------------------------*/
++/*                                                                            */
++/*----------------------------------------------------------------------------*/
++int TerminalSocket (int FunctionCode, int *ReturnSocket)
++{
++    int status;
++    $DESCRIPTOR (TerminalDeviceDesc, "SYS$COMMAND");
++
++    /*
++    ** Process the requested function code
++    */
++    switch (FunctionCode) {
++    case TERM_SOCK_CREATE:
++        /*
++        ** Create a socket pair
++        */
++        status = CreateSocketPair (AF_INET, SOCK_STREAM, 0, TerminalSocketPair);
++        if (status == -1) {
++            LogMessage ("TerminalSocket: CreateSocketPair () - %08X", status);
++            if (TerminalSocketPair[0])
++                close (TerminalSocketPair[0]);
++            if (TerminalSocketPair[1])
++                close (TerminalSocketPair[1]);
++            return (TERM_SOCK_FAILURE);
++        }
++
++        /*
++        ** Assign a channel to the terminal device
++        */
++        status = sys$assign (&TerminalDeviceDesc,
++                             &TerminalDeviceChan,
++                             0, 0, 0);
++        if (! (status & 1)) {
++            LogMessage ("TerminalSocket: SYS$ASSIGN () - %08X", status);
++            close (TerminalSocketPair[0]);
++            close (TerminalSocketPair[1]);
++            return (TERM_SOCK_FAILURE);
++        }
++
++        /*
++        ** Queue an async IO to the terminal device
++        */
++        status = sys$qio (EFN$C_ENF,
++                          TerminalDeviceChan,
++                          IO$_READVBLK,
++                          &TerminalDeviceIosb,
++                          TerminalDeviceAst,
++                          0,
++                          TerminalDeviceBuff,
++                          sizeof (TerminalDeviceBuff) - 2,
++                          0, 0, 0, 0);
++        if (! (status & 1)) {
++            LogMessage ("TerminalSocket: SYS$QIO () - %08X", status);
++            close (TerminalSocketPair[0]);
++            close (TerminalSocketPair[1]);
++            return (TERM_SOCK_FAILURE);
++        }
++
++        /*
++        ** Return the input side of the socket pair
++        */
++        *ReturnSocket = TerminalSocketPair[1];
++        break;
++
++    case TERM_SOCK_DELETE:
++        /*
++        ** Cancel any pending IO on the terminal channel
++        */
++        status = sys$cancel (TerminalDeviceChan);
++        if (! (status & 1)) {
++            LogMessage ("TerminalSocket: SYS$CANCEL () - %08X", status);
++            close (TerminalSocketPair[0]);
++            close (TerminalSocketPair[1]);
++            return (TERM_SOCK_FAILURE);
++        }
++
++        /*
++	** Deassign the terminal channel
++	*/
++        status = sys$dassgn (TerminalDeviceChan);
++        if (! (status & 1)) {
++            LogMessage ("TerminalSocket: SYS$DASSGN () - %08X", status);
++            close (TerminalSocketPair[0]);
++            close (TerminalSocketPair[1]);
++            return (TERM_SOCK_FAILURE);
++        }
++
++        /*
++        ** Close the terminal socket pair
++        */
++        close (TerminalSocketPair[0]);
++        close (TerminalSocketPair[1]);
++
++        /*
++	** Return the initialized socket
++	*/
++        *ReturnSocket = 0;
++        break;
++
++    default:
++        /*
++	** Invalid function code
++	*/
++        LogMessage ("TerminalSocket: Invalid Function Code - %d", FunctionCode);
++        return (TERM_SOCK_FAILURE);
++        break;
++    }
++
++    /*
++    ** Return success
++    */
++    return (TERM_SOCK_SUCCESS);
++
++}
++
++/*----------------------------------------------------------------------------*/
++/*                                                                            */
++/*----------------------------------------------------------------------------*/
++static int CreateSocketPair (int SocketFamily,
++                             int SocketType,
++                             int SocketProtocol,
++                             int *SocketPair)
++{
++    struct dsc$descriptor AscTimeDesc = {0, DSC$K_DTYPE_T, DSC$K_CLASS_S, NULL};
++    static const char* LocalHostAddr = {"127.0.0.1"};
++    unsigned short TcpAcceptChan = 0,
++        TcpDeviceChan = 0;
++    unsigned long BinTimeBuff[2];
++    struct sockaddr_in sin;
++    char AscTimeBuff[32];
++    short LocalHostPort;
++    int status;
++    unsigned int slen;
++
++# ifdef __alpha
++    struct _iosb iosb;
++# else
++    IOSB iosb;
++# endif
++
++    int SockDesc1 = 0,
++        SockDesc2 = 0;
++    SPTB sptb;
++    $DESCRIPTOR (TcpDeviceDesc, "TCPIP$DEVICE");
++
++    /*
++    ** Create a socket
++    */
++    SockDesc1 = socket (SocketFamily, SocketType, 0);
++    if (SockDesc1 < 0) {
++        LogMessage ("CreateSocketPair: socket () - %d", errno);
++        return (-1);
++    }
++
++    /*
++    ** Initialize the socket information
++    */
++    slen = sizeof (sin);
++    memset ((char *) &sin, 0, slen);
++    sin.sin_family = SocketFamily;
++    sin.sin_addr.s_addr = inet_addr (LocalHostAddr);
++    sin.sin_port = 0;
++
++    /*
++    ** Bind the socket to the local IP
++    */
++    status = bind (SockDesc1, (struct sockaddr *) &sin, slen);
++    if (status < 0) {
++        LogMessage ("CreateSocketPair: bind () - %d", errno);
++        close (SockDesc1);
++        return (-1);
++    }
++
++    /*
++    ** Get the socket name so we can save the port number
++    */
++    status = getsockname (SockDesc1, (struct sockaddr *) &sin, &slen);
++    if (status < 0) {
++        LogMessage ("CreateSocketPair: getsockname () - %d", errno);
++        close (SockDesc1);
++        return (-1);
++    } else
++        LocalHostPort = sin.sin_port;
++
++    /*
++    ** Setup a listen for the socket
++    */
++    listen (SockDesc1, 5);
++
++    /*
++    ** Get the binary (64-bit) time of the specified timeout value
++    */
++    sprintf (AscTimeBuff, "0 0:0:%02d.00", SOCKET_PAIR_TIMEOUT_VALUE);
++    AscTimeDesc.dsc$w_length = strlen (AscTimeBuff);
++    AscTimeDesc.dsc$a_pointer = AscTimeBuff;
++    status = sys$bintim (&AscTimeDesc, BinTimeBuff);
++    if (! (status & 1)) {
++        LogMessage ("CreateSocketPair: SYS$BINTIM () - %08X", status);
++        close (SockDesc1);
++        return (-1);
++    }
++
++    /*
++    ** Assign another channel to the TCP/IP device for the accept.
++    ** This is the channel that ends up being connected to.
++    */
++    status = sys$assign (&TcpDeviceDesc, &TcpDeviceChan, 0, 0, 0);
++    if (! (status & 1)) {
++        LogMessage ("CreateSocketPair: SYS$ASSIGN () - %08X", status);
++        close (SockDesc1);
++        return (-1);
++    }
++
++    /*
++    ** Get the channel of the first socket for the accept
++    */
++    TcpAcceptChan = decc$get_sdc (SockDesc1);
++
++    /*
++    ** Perform the accept using $QIO so we can do this asynchronously
++    */
++    status = sys$qio (EFN$C_ENF,
++                      TcpAcceptChan,
++                      IO$_ACCESS | IO$M_ACCEPT,
++                      &iosb,
++                      0, 0, 0, 0, 0,
++                      &TcpDeviceChan,
++                      0, 0);
++    if (! (status & 1)) {
++        LogMessage ("CreateSocketPair: SYS$QIO () - %08X", status);
++        close (SockDesc1);
++        sys$dassgn (TcpDeviceChan);
++        return (-1);
++    }
++
++    /*
++    ** Create the second socket to do the connect
++    */
++    SockDesc2 = socket (SocketFamily, SocketType, 0);
++    if (SockDesc2 < 0) {
++        LogMessage ("CreateSocketPair: socket () - %d", errno);
++        sys$cancel (TcpAcceptChan);
++        close (SockDesc1);
++        sys$dassgn (TcpDeviceChan);
++        return (-1) ;
++    }
++
++    /*
++    ** Setup the Socket Pair Timeout Block
++    */
++    sptb.SockChan1 = TcpAcceptChan;
++    sptb.SockChan2 = decc$get_sdc (SockDesc2);
++
++    /*
++    ** Before we block on the connect, set a timer that can cancel I/O on our
++    ** two sockets if it never connects.
++    */
++    status = sys$setimr (EFN$C_ENF,
++                         BinTimeBuff,
++                         SocketPairTimeoutAst,
++                         &sptb,
++                         0);
++    if (! (status & 1)) {
++        LogMessage ("CreateSocketPair: SYS$SETIMR () - %08X", status);
++        sys$cancel (TcpAcceptChan);
++        close (SockDesc1);
++        close (SockDesc2);
++        sys$dassgn (TcpDeviceChan);
++        return (-1);
++    }
++
++    /*
++    ** Now issue the connect
++    */
++    memset ((char *) &sin, 0, sizeof (sin)) ;
++    sin.sin_family = SocketFamily;
++    sin.sin_addr.s_addr = inet_addr (LocalHostAddr) ;
++    sin.sin_port = LocalHostPort ;
++
++    status = connect (SockDesc2, (struct sockaddr *) &sin, sizeof (sin));
++    if (status < 0 ) {
++        LogMessage ("CreateSocketPair: connect () - %d", errno);
++        sys$cantim (&sptb, 0);
++        sys$cancel (TcpAcceptChan);
++        close (SockDesc1);
++        close (SockDesc2);
++        sys$dassgn (TcpDeviceChan);
++        return (-1);
++    }
++
++    /*
++    ** Wait for the asynch $QIO to finish.  Note that if the I/O was aborted
++    ** (SS$_ABORT), then we probably canceled it from the AST routine - so log
++    ** a timeout.
++    */
++    status = sys$synch (EFN$C_ENF, &iosb);
++    if (! (iosb.iosb$w_status & 1)) {
++        if (iosb.iosb$w_status == SS$_ABORT)
++            LogMessage ("CreateSocketPair: SYS$QIO(iosb) timeout");
++        else {
++            LogMessage ("CreateSocketPair: SYS$QIO(iosb) - %d",
++                        iosb.iosb$w_status);
++            sys$cantim (&sptb, 0);
++        }
++        close (SockDesc1);
++        close (SockDesc2);
++        sys$dassgn (TcpDeviceChan);
++        return (-1);
++    }
++
++    /*
++    ** Here we're successfully connected, so cancel the timer, convert the
++    ** I/O channel to a socket fd, close the listener socket and return the
++    ** connected pair.
++    */
++    sys$cantim (&sptb, 0);
++
++    close (SockDesc1) ;
++    SocketPair[0] = SockDesc2 ;
++    SocketPair[1] = socket_fd (TcpDeviceChan);
++
++    return (0) ;
++
++}
++
++/*----------------------------------------------------------------------------*/
++/*                                                                            */
++/*----------------------------------------------------------------------------*/
++static void SocketPairTimeoutAst (int astparm)
++{
++    SPTB *sptb = (SPTB *) astparm;
++
++    sys$cancel (sptb->SockChan2); /* Cancel the connect() */
++    sys$cancel (sptb->SockChan1); /* Cancel the accept() */
++
++    return;
++
++}
++
++/*----------------------------------------------------------------------------*/
++/*                                                                            */
++/*----------------------------------------------------------------------------*/
++static int TerminalDeviceAst (int astparm)
++{
++    int status;
++
++    /*
++    ** Terminate the terminal buffer
++    */
++    TerminalDeviceBuff[TerminalDeviceIosb.iosb$w_bcnt] = '\0';
++    strcat (TerminalDeviceBuff, "\n");
++
++    /*
++    ** Send the data read from the terminal device throught the socket pair
++    */
++    send (TerminalSocketPair[0], TerminalDeviceBuff,
++          TerminalDeviceIosb.iosb$w_bcnt + 1, 0);
++
++    /*
++    ** Queue another async IO to the terminal device
++    */
++    status = sys$qio (EFN$C_ENF,
++                      TerminalDeviceChan,
++                      IO$_READVBLK,
++                      &TerminalDeviceIosb,
++                      TerminalDeviceAst,
++                      0,
++                      TerminalDeviceBuff,
++                      sizeof (TerminalDeviceBuff) - 1,
++                      0, 0, 0, 0);
++
++    /*
++    ** Return status
++    */
++    return status;
++
++}
++
++/*----------------------------------------------------------------------------*/
++/*                                                                            */
++/*----------------------------------------------------------------------------*/
++static void LogMessage (char *msg, ...)
++{
++    char *Month[] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun",
++                     "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
++    static unsigned int pid = 0;
++    va_list args;
++    time_t CurTime;
++    struct tm *LocTime;
++    char MsgBuff[256];
++
++    /*
++    ** Get the process pid
++    */
++    if (pid == 0)
++        pid = getpid ();
++
++    /*
++    ** Convert the current time into local time
++    */
++    CurTime = time (NULL);
++    LocTime = localtime (&CurTime);
++
++    /*
++    ** Format the message buffer
++    */
++    sprintf (MsgBuff, "%02d-%s-%04d %02d:%02d:%02d [%08X] %s\n",
++             LocTime->tm_mday, Month[LocTime->tm_mon],
++             (LocTime->tm_year + 1900), LocTime->tm_hour, LocTime->tm_min,
++             LocTime->tm_sec, pid, msg);
++
++    /*
++    ** Get any variable arguments and add them to the print of the message
++    ** buffer
++    */
++    va_start (args, msg);
++    vfprintf (stderr, MsgBuff, args);
++    va_end (args);
++
++    /*
++    ** Flush standard error output
++    */
++    fsync (fileno (stderr));
++
++    return;
++
++}
++#endif
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/apps/vms_term_sock.h b/CryptoPkg/Library/OpensslLib/openssl/apps/vms_term_sock.h
+new file mode 100644
+index 0000000..662fa0a
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/apps/vms_term_sock.h
+@@ -0,0 +1,30 @@
++/*
++ * Copyright 2016 VMS Software, Inc. 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#ifndef TERM_SOCK_H
++# define TERM_SOCK_H
++
++/*
++** Terminal Socket Function Codes
++*/
++# define TERM_SOCK_CREATE       1
++# define TERM_SOCK_DELETE       2
++
++/*
++** Terminal Socket Status Codes
++*/
++# define TERM_SOCK_FAILURE      0
++# define TERM_SOCK_SUCCESS      1
++
++/*
++** Terminal Socket Prototype
++*/
++int TerminalSocket (int FunctionCode, int *ReturnSocket);
++
++#endif
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/apps/win32_init.c b/CryptoPkg/Library/OpensslLib/openssl/apps/win32_init.c
+new file mode 100644
+index 0000000..ebe92bc
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/apps/win32_init.c
+@@ -0,0 +1,307 @@
++/*
++ * Copyright 2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include 
++#include 
++#include 
++
++#if defined(CP_UTF8)
++
++static UINT saved_cp;
++static int newargc;
++static char **newargv;
++
++static void cleanup(void)
++{
++    int i;
++
++    SetConsoleOutputCP(saved_cp);
++
++    for (i = 0; i < newargc; i++)
++        free(newargv[i]);
++
++    free(newargv);
++}
++
++/*
++ * Incrementally [re]allocate newargv and keep it NULL-terminated.
++ */
++static int validate_argv(int argc)
++{
++    static int size = 0;
++
++    if (argc >= size) {
++        char **ptr;
++
++        while (argc >= size)
++            size += 64;
++
++        ptr = realloc(newargv, size * sizeof(newargv[0]));
++        if (ptr == NULL)
++            return 0;
++
++        (newargv = ptr)[argc] = NULL;
++    } else {
++        newargv[argc] = NULL;
++    }
++
++    return 1;
++}
++
++static int process_glob(WCHAR *wstr, int wlen)
++{
++    int i, slash, udlen;
++    WCHAR saved_char;
++    WIN32_FIND_DATAW data;
++    HANDLE h;
++
++    /*
++     * Note that we support wildcard characters only in filename part
++     * of the path, and not in directories. Windows users are used to
++     * this, that's why recursive glob processing is not implemented.
++     */
++    /*
++     * Start by looking for last slash or backslash, ...
++     */
++    for (slash = 0, i = 0; i < wlen; i++)
++        if (wstr[i] == L'/' || wstr[i] == L'\\')
++            slash = i + 1;
++    /*
++     * ... then look for asterisk or question mark in the file name.
++     */
++    for (i = slash; i < wlen; i++)
++        if (wstr[i] == L'*' || wstr[i] == L'?')
++            break;
++
++    if (i == wlen)
++        return 0;   /* definitely not a glob */
++
++    saved_char = wstr[wlen];
++    wstr[wlen] = L'\0';
++    h = FindFirstFileW(wstr, &data);
++    wstr[wlen] = saved_char;
++    if (h == INVALID_HANDLE_VALUE)
++        return 0;   /* not a valid glob, just pass... */
++
++    if (slash)
++        udlen = WideCharToMultiByte(CP_UTF8, 0, wstr, slash,
++                                    NULL, 0, NULL, NULL);
++    else
++        udlen = 0;
++
++    do {
++        int uflen;
++        char *arg;
++
++        /*
++         * skip over . and ..
++         */
++        if (data.cFileName[0] == L'.') {
++            if ((data.cFileName[1] == L'\0') ||
++                (data.cFileName[1] == L'.' && data.cFileName[2] == L'\0'))
++                continue;
++        }
++
++        if (!validate_argv(newargc + 1))
++            break;
++
++        /*
++         * -1 below means "scan for trailing '\0' *and* count it",
++         * so that |uflen| covers even trailing '\0'.
++         */
++        uflen = WideCharToMultiByte(CP_UTF8, 0, data.cFileName, -1,
++                                    NULL, 0, NULL, NULL);
++
++        arg = malloc(udlen + uflen);
++        if (arg == NULL)
++            break;
++
++        if (udlen)
++            WideCharToMultiByte(CP_UTF8, 0, wstr, slash,
++                                arg, udlen, NULL, NULL);
++
++        WideCharToMultiByte(CP_UTF8, 0, data.cFileName, -1,
++                            arg + udlen, uflen, NULL, NULL);
++
++        newargv[newargc++] = arg;
++    } while (FindNextFileW(h, &data));
++
++    CloseHandle(h);
++
++    return 1;
++}
++
++void win32_utf8argv(int *argc, char **argv[])
++{
++    const WCHAR *wcmdline;
++    WCHAR *warg, *wend, *p;
++    int wlen, ulen, valid = 1;
++    char *arg;
++
++    if (GetEnvironmentVariableW(L"OPENSSL_WIN32_UTF8", NULL, 0) == 0)
++        return;
++
++    newargc = 0;
++    newargv = NULL;
++    if (!validate_argv(newargc))
++        return;
++
++    wcmdline = GetCommandLineW();
++    if (wcmdline == NULL) return;
++
++    /*
++     * make a copy of the command line, since we might have to modify it...
++     */
++    wlen = wcslen(wcmdline);
++    p = _alloca((wlen + 1) * sizeof(WCHAR));
++    wcscpy(p, wcmdline);
++
++    while (*p != L'\0') {
++        int in_quote = 0;
++
++        if (*p == L' ' || *p == L'\t') {
++            p++; /* skip over white spaces */
++            continue;
++        }
++
++        /*
++         * Note: because we may need to fiddle with the number of backslashes,
++         * the argument string is copied into itself.  This is safe because
++         * the number of characters will never expand.
++         */
++        warg = wend = p;
++        while (*p != L'\0'
++               && (in_quote || (*p != L' ' && *p != L'\t'))) {
++            switch (*p) {
++            case L'\\':
++                /*
++                 * Microsoft documentation on how backslashes are treated
++                 * is:
++                 *
++                 * + Backslashes are interpreted literally, unless they
++                 *   immediately precede a double quotation mark.
++                 * + If an even number of backslashes is followed by a double
++                 *   quotation mark, one backslash is placed in the argv array
++                 *   for every pair of backslashes, and the double quotation
++                 *   mark is interpreted as a string delimiter.
++                 * + If an odd number of backslashes is followed by a double
++                 *   quotation mark, one backslash is placed in the argv array
++                 *   for every pair of backslashes, and the double quotation
++                 *   mark is "escaped" by the remaining backslash, causing a
++                 *   literal double quotation mark (") to be placed in argv.
++                 *
++                 * Ref: https://msdn.microsoft.com/en-us/library/17w5ykft.aspx
++                 *
++                 * Though referred page doesn't mention it, multiple qouble
++                 * quotes are also special. Pair of double quotes in quoted
++                 * string is counted as single double quote.
++                 */
++                {
++                    const WCHAR *q = p;
++                    int i;
++
++                    while (*p == L'\\')
++                        p++;
++
++                    if (*p == L'"') {
++                        int i;
++
++                        for (i = (p - q) / 2; i > 0; i--)
++                            *wend++ = L'\\';
++
++                        /*
++                         * if odd amount of backslashes before the quote,
++                         * said quote is part of the argument, not a delimiter
++                         */
++                        if ((p - q) % 2 == 1)
++                            *wend++ = *p++;
++                    } else {
++                        for (i = p - q; i > 0; i--)
++                            *wend++ = L'\\';
++                    }
++                }
++                break;
++            case L'"':
++                /*
++                 * Without the preceding backslash (or when preceded with an
++                 * even number of backslashes), the double quote is a simple
++                 * string delimiter and just slightly change the parsing state
++                 */
++                if (in_quote && p[1] == L'"')
++                    *wend++ = *p++;
++                else
++                    in_quote = !in_quote;
++                p++;
++                break;
++            default:
++                /*
++                 * Any other non-delimiter character is just taken verbatim
++                 */
++                *wend++ = *p++;
++            }
++        }
++
++        wlen = wend - warg;
++
++        if (wlen == 0 || !process_glob(warg, wlen)) {
++            if (!validate_argv(newargc + 1)) {
++                valid = 0;
++                break;
++            }
++
++            ulen = 0;
++            if (wlen > 0) {
++                ulen = WideCharToMultiByte(CP_UTF8, 0, warg, wlen,
++                                           NULL, 0, NULL, NULL);
++                if (ulen <= 0)
++                    continue;
++            }
++
++            arg = malloc(ulen + 1);
++            if (arg == NULL) {
++                valid = 0;
++                break;
++            }
++
++            if (wlen > 0)
++                WideCharToMultiByte(CP_UTF8, 0, warg, wlen,
++                                    arg, ulen, NULL, NULL);
++            arg[ulen] = '\0';
++
++            newargv[newargc++] = arg;
++        }
++    }
++
++    if (valid) {
++        saved_cp = GetConsoleOutputCP();
++        SetConsoleOutputCP(CP_UTF8);
++
++        *argc = newargc;
++        *argv = newargv;
++
++        atexit(cleanup);
++    } else if (newargv != NULL) {
++        int i;
++
++        for (i = 0; i < newargc; i++)
++            free(newargv[i]);
++
++        free(newargv);
++
++        newargc = 0;
++        newargv = NULL;
++    }
++
++    return;
++}
++#else
++void win32_utf8argv(int &argc, char **argv[])
++{   return;   }
++#endif
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/apps/x509.c b/CryptoPkg/Library/OpensslLib/openssl/apps/x509.c
+new file mode 100644
+index 0000000..577c35d
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/apps/x509.c
+@@ -0,0 +1,1101 @@
++/*
++ * Copyright 1995-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include 
++#include 
++#include "apps.h"
++#include 
++#include 
++#include 
++#include 
++#include 
++#include 
++#include 
++#include 
++#include 
++#ifndef OPENSSL_NO_RSA
++# include 
++#endif
++#ifndef OPENSSL_NO_DSA
++# include 
++#endif
++
++#undef POSTFIX
++#define POSTFIX ".srl"
++#define DEF_DAYS        30
++
++static int callb(int ok, X509_STORE_CTX *ctx);
++static int sign(X509 *x, EVP_PKEY *pkey, int days, int clrext,
++                const EVP_MD *digest, CONF *conf, const char *section);
++static int x509_certify(X509_STORE *ctx, const char *CAfile, const EVP_MD *digest,
++                        X509 *x, X509 *xca, EVP_PKEY *pkey,
++                        STACK_OF(OPENSSL_STRING) *sigopts, const char *serialfile,
++                        int create, int days, int clrext, CONF *conf,
++                        const char *section, ASN1_INTEGER *sno, int reqfile);
++static int purpose_print(BIO *bio, X509 *cert, X509_PURPOSE *pt);
++
++typedef enum OPTION_choice {
++    OPT_ERR = -1, OPT_EOF = 0, OPT_HELP,
++    OPT_INFORM, OPT_OUTFORM, OPT_KEYFORM, OPT_REQ, OPT_CAFORM,
++    OPT_CAKEYFORM, OPT_SIGOPT, OPT_DAYS, OPT_PASSIN, OPT_EXTFILE,
++    OPT_EXTENSIONS, OPT_IN, OPT_OUT, OPT_SIGNKEY, OPT_CA,
++    OPT_CAKEY, OPT_CASERIAL, OPT_SET_SERIAL, OPT_FORCE_PUBKEY,
++    OPT_ADDTRUST, OPT_ADDREJECT, OPT_SETALIAS, OPT_CERTOPT, OPT_NAMEOPT,
++    OPT_C, OPT_EMAIL, OPT_OCSP_URI, OPT_SERIAL, OPT_NEXT_SERIAL,
++    OPT_MODULUS, OPT_PUBKEY, OPT_X509TOREQ, OPT_TEXT, OPT_HASH,
++    OPT_ISSUER_HASH, OPT_SUBJECT, OPT_ISSUER, OPT_FINGERPRINT, OPT_DATES,
++    OPT_PURPOSE, OPT_STARTDATE, OPT_ENDDATE, OPT_CHECKEND, OPT_CHECKHOST,
++    OPT_CHECKEMAIL, OPT_CHECKIP, OPT_NOOUT, OPT_TRUSTOUT, OPT_CLRTRUST,
++    OPT_CLRREJECT, OPT_ALIAS, OPT_CACREATESERIAL, OPT_CLREXT, OPT_OCSPID,
++    OPT_SUBJECT_HASH_OLD,
++    OPT_ISSUER_HASH_OLD,
++    OPT_BADSIG, OPT_MD, OPT_ENGINE, OPT_NOCERT
++} OPTION_CHOICE;
++
++OPTIONS x509_options[] = {
++    {"help", OPT_HELP, '-', "Display this summary"},
++    {"inform", OPT_INFORM, 'f',
++     "Input format - default PEM (one of DER, NET or PEM)"},
++    {"in", OPT_IN, '<', "Input file - default stdin"},
++    {"outform", OPT_OUTFORM, 'f',
++     "Output format - default PEM (one of DER, NET or PEM)"},
++    {"out", OPT_OUT, '>', "Output file - default stdout"},
++    {"keyform", OPT_KEYFORM, 'F', "Private key format - default PEM"},
++    {"passin", OPT_PASSIN, 's', "Private key password/pass-phrase source"},
++    {"serial", OPT_SERIAL, '-', "Print serial number value"},
++    {"subject_hash", OPT_HASH, '-', "Print subject hash value"},
++    {"issuer_hash", OPT_ISSUER_HASH, '-', "Print issuer hash value"},
++    {"hash", OPT_HASH, '-', "Synonym for -subject_hash"},
++    {"subject", OPT_SUBJECT, '-', "Print subject DN"},
++    {"issuer", OPT_ISSUER, '-', "Print issuer DN"},
++    {"email", OPT_EMAIL, '-', "Print email address(es)"},
++    {"startdate", OPT_STARTDATE, '-', "Set notBefore field"},
++    {"enddate", OPT_ENDDATE, '-', "Set notAfter field"},
++    {"purpose", OPT_PURPOSE, '-', "Print out certificate purposes"},
++    {"dates", OPT_DATES, '-', "Both Before and After dates"},
++    {"modulus", OPT_MODULUS, '-', "Print the RSA key modulus"},
++    {"pubkey", OPT_PUBKEY, '-', "Output the public key"},
++    {"fingerprint", OPT_FINGERPRINT, '-',
++     "Print the certificate fingerprint"},
++    {"alias", OPT_ALIAS, '-', "Output certificate alias"},
++    {"noout", OPT_NOOUT, '-', "No output, just status"},
++    {"nocert", OPT_NOCERT, '-', "No certificate output"},
++    {"ocspid", OPT_OCSPID, '-',
++     "Print OCSP hash values for the subject name and public key"},
++    {"ocsp_uri", OPT_OCSP_URI, '-', "Print OCSP Responder URL(s)"},
++    {"trustout", OPT_TRUSTOUT, '-', "Output a trusted certificate"},
++    {"clrtrust", OPT_CLRTRUST, '-', "Clear all trusted purposes"},
++    {"clrext", OPT_CLREXT, '-', "Clear all certificate extensions"},
++    {"addtrust", OPT_ADDTRUST, 's', "Trust certificate for a given purpose"},
++    {"addreject", OPT_ADDREJECT, 's',
++     "Reject certificate for a given purpose"},
++    {"setalias", OPT_SETALIAS, 's', "Set certificate alias"},
++    {"days", OPT_DAYS, 'n',
++     "How long till expiry of a signed certificate - def 30 days"},
++    {"checkend", OPT_CHECKEND, 'M',
++     "Check whether the cert expires in the next arg seconds"},
++    {OPT_MORE_STR, 1, 1, "Exit 1 if so, 0 if not"},
++    {"signkey", OPT_SIGNKEY, '<', "Self sign cert with arg"},
++    {"x509toreq", OPT_X509TOREQ, '-',
++     "Output a certification request object"},
++    {"req", OPT_REQ, '-', "Input is a certificate request, sign and output"},
++    {"CA", OPT_CA, '<', "Set the CA certificate, must be PEM format"},
++    {"CAkey", OPT_CAKEY, 's',
++     "The CA key, must be PEM format; if not in CAfile"},
++    {"CAcreateserial", OPT_CACREATESERIAL, '-',
++     "Create serial number file if it does not exist"},
++    {"CAserial", OPT_CASERIAL, 's', "Serial file"},
++    {"set_serial", OPT_SET_SERIAL, 's', "Serial number to use"},
++    {"text", OPT_TEXT, '-', "Print the certificate in text form"},
++    {"C", OPT_C, '-', "Print out C code forms"},
++    {"extfile", OPT_EXTFILE, '<', "File with X509V3 extensions to add"},
++    {"extensions", OPT_EXTENSIONS, 's', "Section from config file to use"},
++    {"nameopt", OPT_NAMEOPT, 's', "Various certificate name options"},
++    {"certopt", OPT_CERTOPT, 's', "Various certificate text options"},
++    {"checkhost", OPT_CHECKHOST, 's', "Check certificate matches host"},
++    {"checkemail", OPT_CHECKEMAIL, 's', "Check certificate matches email"},
++    {"checkip", OPT_CHECKIP, 's', "Check certificate matches ipaddr"},
++    {"CAform", OPT_CAFORM, 'F', "CA format - default PEM"},
++    {"CAkeyform", OPT_CAKEYFORM, 'F', "CA key format - default PEM"},
++    {"sigopt", OPT_SIGOPT, 's', "Signature parameter in n:v form"},
++    {"force_pubkey", OPT_FORCE_PUBKEY, '<', "Force the Key to put inside certificate"},
++    {"next_serial", OPT_NEXT_SERIAL, '-', "Increment current certificate serial number"},
++    {"clrreject", OPT_CLRREJECT, '-',
++     "Clears all the prohibited or rejected uses of the certificate"},
++    {"badsig", OPT_BADSIG, '-', "Corrupt last byte of certificate signature (for test)"},
++    {"", OPT_MD, '-', "Any supported digest"},
++#ifndef OPENSSL_NO_MD5
++    {"subject_hash_old", OPT_SUBJECT_HASH_OLD, '-',
++     "Print old-style (MD5) issuer hash value"},
++    {"issuer_hash_old", OPT_ISSUER_HASH_OLD, '-',
++     "Print old-style (MD5) subject hash value"},
++#endif
++#ifndef OPENSSL_NO_ENGINE
++    {"engine", OPT_ENGINE, 's', "Use engine, possibly a hardware device"},
++#endif
++    {NULL}
++};
++
++int x509_main(int argc, char **argv)
++{
++    ASN1_INTEGER *sno = NULL;
++    ASN1_OBJECT *objtmp = NULL;
++    BIO *out = NULL;
++    CONF *extconf = NULL;
++    EVP_PKEY *Upkey = NULL, *CApkey = NULL, *fkey = NULL;
++    STACK_OF(ASN1_OBJECT) *trust = NULL, *reject = NULL;
++    STACK_OF(OPENSSL_STRING) *sigopts = NULL;
++    X509 *x = NULL, *xca = NULL;
++    X509_REQ *req = NULL, *rq = NULL;
++    X509_STORE *ctx = NULL;
++    const EVP_MD *digest = NULL;
++    char *CAkeyfile = NULL, *CAserial = NULL, *fkeyfile = NULL, *alias = NULL;
++    char *checkhost = NULL, *checkemail = NULL, *checkip = NULL;
++    char *extsect = NULL, *extfile = NULL, *passin = NULL, *passinarg = NULL;
++    char *infile = NULL, *outfile = NULL, *keyfile = NULL, *CAfile = NULL;
++    char buf[256], *prog;
++    int x509req = 0, days = DEF_DAYS, modulus = 0, pubkey = 0, pprint = 0;
++    int C = 0, CAformat = FORMAT_PEM, CAkeyformat = FORMAT_PEM;
++    int fingerprint = 0, reqfile = 0, need_rand = 0, checkend = 0;
++    int informat = FORMAT_PEM, outformat = FORMAT_PEM, keyformat = FORMAT_PEM;
++    int next_serial = 0, subject_hash = 0, issuer_hash = 0, ocspid = 0;
++    int noout = 0, sign_flag = 0, CA_flag = 0, CA_createserial = 0, email = 0;
++    int ocsp_uri = 0, trustout = 0, clrtrust = 0, clrreject = 0, aliasout = 0;
++    int ret = 1, i, num = 0, badsig = 0, clrext = 0, nocert = 0;
++    int text = 0, serial = 0, subject = 0, issuer = 0, startdate = 0;
++    int enddate = 0;
++    time_t checkoffset = 0;
++    unsigned long nmflag = 0, certflag = 0;
++    char nmflag_set = 0;
++    OPTION_CHOICE o;
++    ENGINE *e = NULL;
++#ifndef OPENSSL_NO_MD5
++    int subject_hash_old = 0, issuer_hash_old = 0;
++#endif
++
++    ctx = X509_STORE_new();
++    if (ctx == NULL)
++        goto end;
++    X509_STORE_set_verify_cb(ctx, callb);
++
++    prog = opt_init(argc, argv, x509_options);
++    while ((o = opt_next()) != OPT_EOF) {
++        switch (o) {
++        case OPT_EOF:
++        case OPT_ERR:
++ opthelp:
++            BIO_printf(bio_err, "%s: Use -help for summary.\n", prog);
++            goto end;
++        case OPT_HELP:
++            opt_help(x509_options);
++            ret = 0;
++            goto end;
++        case OPT_INFORM:
++            if (!opt_format(opt_arg(), OPT_FMT_ANY, &informat))
++                goto opthelp;
++            break;
++        case OPT_IN:
++            infile = opt_arg();
++            break;
++        case OPT_OUTFORM:
++            if (!opt_format(opt_arg(), OPT_FMT_ANY, &outformat))
++                goto opthelp;
++            break;
++        case OPT_KEYFORM:
++            if (!opt_format(opt_arg(), OPT_FMT_PEMDER, &keyformat))
++                goto opthelp;
++            break;
++        case OPT_CAFORM:
++            if (!opt_format(opt_arg(), OPT_FMT_PEMDER, &CAformat))
++                goto opthelp;
++            break;
++        case OPT_CAKEYFORM:
++            if (!opt_format(opt_arg(), OPT_FMT_ANY, &CAkeyformat))
++                goto opthelp;
++            break;
++        case OPT_OUT:
++            outfile = opt_arg();
++            break;
++        case OPT_REQ:
++            reqfile = need_rand = 1;
++            break;
++
++        case OPT_SIGOPT:
++            if (!sigopts)
++                sigopts = sk_OPENSSL_STRING_new_null();
++            if (!sigopts || !sk_OPENSSL_STRING_push(sigopts, opt_arg()))
++                goto opthelp;
++            break;
++        case OPT_DAYS:
++            days = atoi(opt_arg());
++            break;
++        case OPT_PASSIN:
++            passinarg = opt_arg();
++            break;
++        case OPT_EXTFILE:
++            extfile = opt_arg();
++            break;
++        case OPT_EXTENSIONS:
++            extsect = opt_arg();
++            break;
++        case OPT_SIGNKEY:
++            keyfile = opt_arg();
++            sign_flag = ++num;
++            need_rand = 1;
++            break;
++        case OPT_CA:
++            CAfile = opt_arg();
++            CA_flag = ++num;
++            need_rand = 1;
++            break;
++        case OPT_CAKEY:
++            CAkeyfile = opt_arg();
++            break;
++        case OPT_CASERIAL:
++            CAserial = opt_arg();
++            break;
++        case OPT_SET_SERIAL:
++            if (sno != NULL) {
++                BIO_printf(bio_err, "Serial number supplied twice\n");
++                goto opthelp;
++            }
++            if ((sno = s2i_ASN1_INTEGER(NULL, opt_arg())) == NULL)
++                goto opthelp;
++            break;
++        case OPT_FORCE_PUBKEY:
++            fkeyfile = opt_arg();
++            break;
++        case OPT_ADDTRUST:
++            if ((objtmp = OBJ_txt2obj(opt_arg(), 0)) == NULL) {
++                BIO_printf(bio_err,
++                           "%s: Invalid trust object value %s\n",
++                           prog, opt_arg());
++                goto opthelp;
++            }
++            if (trust == NULL && (trust = sk_ASN1_OBJECT_new_null()) == NULL)
++                goto end;
++            sk_ASN1_OBJECT_push(trust, objtmp);
++            objtmp = NULL;
++            trustout = 1;
++            break;
++        case OPT_ADDREJECT:
++            if ((objtmp = OBJ_txt2obj(opt_arg(), 0)) == NULL) {
++                BIO_printf(bio_err,
++                           "%s: Invalid reject object value %s\n",
++                           prog, opt_arg());
++                goto opthelp;
++            }
++            if (reject == NULL
++                && (reject = sk_ASN1_OBJECT_new_null()) == NULL)
++                goto end;
++            sk_ASN1_OBJECT_push(reject, objtmp);
++            objtmp = NULL;
++            trustout = 1;
++            break;
++        case OPT_SETALIAS:
++            alias = opt_arg();
++            trustout = 1;
++            break;
++        case OPT_CERTOPT:
++            if (!set_cert_ex(&certflag, opt_arg()))
++                goto opthelp;
++            break;
++        case OPT_NAMEOPT:
++            nmflag_set = 1;
++            if (!set_name_ex(&nmflag, opt_arg()))
++                goto opthelp;
++            break;
++        case OPT_ENGINE:
++            e = setup_engine(opt_arg(), 0);
++            break;
++        case OPT_C:
++            C = ++num;
++            break;
++        case OPT_EMAIL:
++            email = ++num;
++            break;
++        case OPT_OCSP_URI:
++            ocsp_uri = ++num;
++            break;
++        case OPT_SERIAL:
++            serial = ++num;
++            break;
++        case OPT_NEXT_SERIAL:
++            next_serial = ++num;
++            break;
++        case OPT_MODULUS:
++            modulus = ++num;
++            break;
++        case OPT_PUBKEY:
++            pubkey = ++num;
++            break;
++        case OPT_X509TOREQ:
++            x509req = ++num;
++            break;
++        case OPT_TEXT:
++            text = ++num;
++            break;
++        case OPT_SUBJECT:
++            subject = ++num;
++            break;
++        case OPT_ISSUER:
++            issuer = ++num;
++            break;
++        case OPT_FINGERPRINT:
++            fingerprint = ++num;
++            break;
++        case OPT_HASH:
++            subject_hash = ++num;
++            break;
++        case OPT_ISSUER_HASH:
++            issuer_hash = ++num;
++            break;
++        case OPT_PURPOSE:
++            pprint = ++num;
++            break;
++        case OPT_STARTDATE:
++            startdate = ++num;
++            break;
++        case OPT_ENDDATE:
++            enddate = ++num;
++            break;
++        case OPT_NOOUT:
++            noout = ++num;
++            break;
++        case OPT_NOCERT:
++            nocert = 1;
++            break;
++        case OPT_TRUSTOUT:
++            trustout = 1;
++            break;
++        case OPT_CLRTRUST:
++            clrtrust = ++num;
++            break;
++        case OPT_CLRREJECT:
++            clrreject = ++num;
++            break;
++        case OPT_ALIAS:
++            aliasout = ++num;
++            break;
++        case OPT_CACREATESERIAL:
++            CA_createserial = ++num;
++            break;
++        case OPT_CLREXT:
++            clrext = 1;
++            break;
++        case OPT_OCSPID:
++            ocspid = ++num;
++            break;
++        case OPT_BADSIG:
++            badsig = 1;
++            break;
++#ifndef OPENSSL_NO_MD5
++        case OPT_SUBJECT_HASH_OLD:
++            subject_hash_old = ++num;
++            break;
++        case OPT_ISSUER_HASH_OLD:
++            issuer_hash_old = ++num;
++            break;
++#else
++        case OPT_SUBJECT_HASH_OLD:
++        case OPT_ISSUER_HASH_OLD:
++            break;
++#endif
++        case OPT_DATES:
++            startdate = ++num;
++            enddate = ++num;
++            break;
++        case OPT_CHECKEND:
++            checkend = 1;
++            {
++                intmax_t temp = 0;
++                if (!opt_imax(opt_arg(), &temp))
++                    goto opthelp;
++                checkoffset = (time_t)temp;
++                if ((intmax_t)checkoffset != temp) {
++                    BIO_printf(bio_err, "%s: checkend time out of range %s\n",
++                               prog, opt_arg());
++                    goto opthelp;
++                }
++            }
++            break;
++        case OPT_CHECKHOST:
++            checkhost = opt_arg();
++            break;
++        case OPT_CHECKEMAIL:
++            checkemail = opt_arg();
++            break;
++        case OPT_CHECKIP:
++            checkip = opt_arg();
++            break;
++        case OPT_MD:
++            if (!opt_md(opt_unknown(), &digest))
++                goto opthelp;
++        }
++    }
++    argc = opt_num_rest();
++    argv = opt_rest();
++    if (argc != 0) {
++        BIO_printf(bio_err, "%s: Unknown parameter %s\n", prog, argv[0]);
++        goto opthelp;
++    }
++
++    if (!nmflag_set)
++        nmflag = XN_FLAG_ONELINE;
++
++    out = bio_open_default(outfile, 'w', outformat);
++    if (out == NULL)
++        goto end;
++
++    if (need_rand)
++        app_RAND_load_file(NULL, 0);
++
++    if (!app_passwd(passinarg, NULL, &passin, NULL)) {
++        BIO_printf(bio_err, "Error getting password\n");
++        goto end;
++    }
++
++    if (!X509_STORE_set_default_paths(ctx)) {
++        ERR_print_errors(bio_err);
++        goto end;
++    }
++
++    if (fkeyfile) {
++        fkey = load_pubkey(fkeyfile, keyformat, 0, NULL, e, "Forced key");
++        if (fkey == NULL)
++            goto end;
++    }
++
++    if ((CAkeyfile == NULL) && (CA_flag) && (CAformat == FORMAT_PEM)) {
++        CAkeyfile = CAfile;
++    } else if ((CA_flag) && (CAkeyfile == NULL)) {
++        BIO_printf(bio_err,
++                   "need to specify a CAkey if using the CA command\n");
++        goto end;
++    }
++
++    if (extfile) {
++        X509V3_CTX ctx2;
++        if ((extconf = app_load_config(extfile)) == NULL)
++            goto end;
++        if (!extsect) {
++            extsect = NCONF_get_string(extconf, "default", "extensions");
++            if (!extsect) {
++                ERR_clear_error();
++                extsect = "default";
++            }
++        }
++        X509V3_set_ctx_test(&ctx2);
++        X509V3_set_nconf(&ctx2, extconf);
++        if (!X509V3_EXT_add_nconf(extconf, &ctx2, extsect, NULL)) {
++            BIO_printf(bio_err,
++                       "Error Loading extension section %s\n", extsect);
++            ERR_print_errors(bio_err);
++            goto end;
++        }
++    }
++
++    if (reqfile) {
++        EVP_PKEY *pkey;
++        BIO *in;
++
++        if (!sign_flag && !CA_flag) {
++            BIO_printf(bio_err, "We need a private key to sign with\n");
++            goto end;
++        }
++        in = bio_open_default(infile, 'r', informat);
++        if (in == NULL)
++            goto end;
++        req = PEM_read_bio_X509_REQ(in, NULL, NULL, NULL);
++        BIO_free(in);
++
++        if (req == NULL) {
++            ERR_print_errors(bio_err);
++            goto end;
++        }
++
++        if ((pkey = X509_REQ_get0_pubkey(req)) == NULL) {
++            BIO_printf(bio_err, "error unpacking public key\n");
++            goto end;
++        }
++        i = X509_REQ_verify(req, pkey);
++        if (i < 0) {
++            BIO_printf(bio_err, "Signature verification error\n");
++            ERR_print_errors(bio_err);
++            goto end;
++        }
++        if (i == 0) {
++            BIO_printf(bio_err,
++                       "Signature did not match the certificate request\n");
++            goto end;
++        } else
++            BIO_printf(bio_err, "Signature ok\n");
++
++        print_name(bio_err, "subject=", X509_REQ_get_subject_name(req),
++                   nmflag);
++
++        if ((x = X509_new()) == NULL)
++            goto end;
++
++        if (sno == NULL) {
++            sno = ASN1_INTEGER_new();
++            if (sno == NULL || !rand_serial(NULL, sno))
++                goto end;
++            if (!X509_set_serialNumber(x, sno))
++                goto end;
++            ASN1_INTEGER_free(sno);
++            sno = NULL;
++        } else if (!X509_set_serialNumber(x, sno))
++            goto end;
++
++        if (!X509_set_issuer_name(x, X509_REQ_get_subject_name(req)))
++            goto end;
++        if (!X509_set_subject_name(x, X509_REQ_get_subject_name(req)))
++            goto end;
++        if (!set_cert_times(x, NULL, NULL, days))
++            goto end;
++
++        if (fkey)
++            X509_set_pubkey(x, fkey);
++        else {
++            pkey = X509_REQ_get0_pubkey(req);
++            X509_set_pubkey(x, pkey);
++        }
++    } else
++        x = load_cert(infile, informat, "Certificate");
++
++    if (x == NULL)
++        goto end;
++    if (CA_flag) {
++        xca = load_cert(CAfile, CAformat, "CA Certificate");
++        if (xca == NULL)
++            goto end;
++    }
++
++    if (!noout || text || next_serial) {
++        OBJ_create("2.99999.3", "SET.ex3", "SET x509v3 extension 3");
++
++    }
++
++    if (alias)
++        X509_alias_set1(x, (unsigned char *)alias, -1);
++
++    if (clrtrust)
++        X509_trust_clear(x);
++    if (clrreject)
++        X509_reject_clear(x);
++
++    if (trust) {
++        for (i = 0; i < sk_ASN1_OBJECT_num(trust); i++) {
++            objtmp = sk_ASN1_OBJECT_value(trust, i);
++            X509_add1_trust_object(x, objtmp);
++        }
++        objtmp = NULL;
++    }
++
++    if (reject) {
++        for (i = 0; i < sk_ASN1_OBJECT_num(reject); i++) {
++            objtmp = sk_ASN1_OBJECT_value(reject, i);
++            X509_add1_reject_object(x, objtmp);
++        }
++        objtmp = NULL;
++    }
++
++    if (badsig) {
++        const ASN1_BIT_STRING *signature;
++
++        X509_get0_signature(&signature, NULL, x);
++        corrupt_signature(signature);
++    }
++
++    if (num) {
++        for (i = 1; i <= num; i++) {
++            if (issuer == i) {
++                print_name(out, "issuer=", X509_get_issuer_name(x), nmflag);
++            } else if (subject == i) {
++                print_name(out, "subject=",
++                           X509_get_subject_name(x), nmflag);
++            } else if (serial == i) {
++                BIO_printf(out, "serial=");
++                i2a_ASN1_INTEGER(out, X509_get_serialNumber(x));
++                BIO_printf(out, "\n");
++            } else if (next_serial == i) {
++                ASN1_INTEGER *ser = X509_get_serialNumber(x);
++                BIGNUM *bnser = ASN1_INTEGER_to_BN(ser, NULL);
++
++                if (!bnser)
++                    goto end;
++                if (!BN_add_word(bnser, 1))
++                    goto end;
++                ser = BN_to_ASN1_INTEGER(bnser, NULL);
++                if (!ser)
++                    goto end;
++                BN_free(bnser);
++                i2a_ASN1_INTEGER(out, ser);
++                ASN1_INTEGER_free(ser);
++                BIO_puts(out, "\n");
++            } else if ((email == i) || (ocsp_uri == i)) {
++                int j;
++                STACK_OF(OPENSSL_STRING) *emlst;
++                if (email == i)
++                    emlst = X509_get1_email(x);
++                else
++                    emlst = X509_get1_ocsp(x);
++                for (j = 0; j < sk_OPENSSL_STRING_num(emlst); j++)
++                    BIO_printf(out, "%s\n",
++                               sk_OPENSSL_STRING_value(emlst, j));
++                X509_email_free(emlst);
++            } else if (aliasout == i) {
++                unsigned char *alstr;
++                alstr = X509_alias_get0(x, NULL);
++                if (alstr)
++                    BIO_printf(out, "%s\n", alstr);
++                else
++                    BIO_puts(out, "\n");
++            } else if (subject_hash == i) {
++                BIO_printf(out, "%08lx\n", X509_subject_name_hash(x));
++            }
++#ifndef OPENSSL_NO_MD5
++            else if (subject_hash_old == i) {
++                BIO_printf(out, "%08lx\n", X509_subject_name_hash_old(x));
++            }
++#endif
++            else if (issuer_hash == i) {
++                BIO_printf(out, "%08lx\n", X509_issuer_name_hash(x));
++            }
++#ifndef OPENSSL_NO_MD5
++            else if (issuer_hash_old == i) {
++                BIO_printf(out, "%08lx\n", X509_issuer_name_hash_old(x));
++            }
++#endif
++            else if (pprint == i) {
++                X509_PURPOSE *ptmp;
++                int j;
++                BIO_printf(out, "Certificate purposes:\n");
++                for (j = 0; j < X509_PURPOSE_get_count(); j++) {
++                    ptmp = X509_PURPOSE_get0(j);
++                    purpose_print(out, x, ptmp);
++                }
++            } else if (modulus == i) {
++                EVP_PKEY *pkey;
++
++                pkey = X509_get0_pubkey(x);
++                if (pkey == NULL) {
++                    BIO_printf(bio_err, "Modulus=unavailable\n");
++                    ERR_print_errors(bio_err);
++                    goto end;
++                }
++                BIO_printf(out, "Modulus=");
++#ifndef OPENSSL_NO_RSA
++                if (EVP_PKEY_id(pkey) == EVP_PKEY_RSA) {
++                    const BIGNUM *n;
++                    RSA_get0_key(EVP_PKEY_get0_RSA(pkey), &n, NULL, NULL);
++                    BN_print(out, n);
++                } else
++#endif
++#ifndef OPENSSL_NO_DSA
++                if (EVP_PKEY_id(pkey) == EVP_PKEY_DSA) {
++                    const BIGNUM *dsapub = NULL;
++                    DSA_get0_key(EVP_PKEY_get0_DSA(pkey), &dsapub, NULL);
++                    BN_print(out, dsapub);
++                } else
++#endif
++                {
++                    BIO_printf(out, "Wrong Algorithm type");
++                }
++                BIO_printf(out, "\n");
++            } else if (pubkey == i) {
++                EVP_PKEY *pkey;
++
++                pkey = X509_get0_pubkey(x);
++                if (pkey == NULL) {
++                    BIO_printf(bio_err, "Error getting public key\n");
++                    ERR_print_errors(bio_err);
++                    goto end;
++                }
++                PEM_write_bio_PUBKEY(out, pkey);
++            } else if (C == i) {
++                unsigned char *d;
++                char *m;
++                int len;
++
++                X509_NAME_oneline(X509_get_subject_name(x), buf, sizeof buf);
++                BIO_printf(out, "/*\n"
++                                " * Subject: %s\n", buf);
++
++                X509_NAME_oneline(X509_get_issuer_name(x), buf, sizeof buf);
++                BIO_printf(out, " * Issuer:  %s\n"
++                                " */\n", buf);
++
++                len = i2d_X509(x, NULL);
++                m = app_malloc(len, "x509 name buffer");
++                d = (unsigned char *)m;
++                len = i2d_X509_NAME(X509_get_subject_name(x), &d);
++                print_array(out, "the_subject_name", len, (unsigned char *)m);
++                d = (unsigned char *)m;
++                len = i2d_X509_PUBKEY(X509_get_X509_PUBKEY(x), &d);
++                print_array(out, "the_public_key", len, (unsigned char *)m);
++                d = (unsigned char *)m;
++                len = i2d_X509(x, &d);
++                print_array(out, "the_certificate", len, (unsigned char *)m);
++                OPENSSL_free(m);
++            } else if (text == i) {
++                X509_print_ex(out, x, nmflag, certflag);
++            } else if (startdate == i) {
++                BIO_puts(out, "notBefore=");
++                ASN1_TIME_print(out, X509_get0_notBefore(x));
++                BIO_puts(out, "\n");
++            } else if (enddate == i) {
++                BIO_puts(out, "notAfter=");
++                ASN1_TIME_print(out, X509_get0_notAfter(x));
++                BIO_puts(out, "\n");
++            } else if (fingerprint == i) {
++                int j;
++                unsigned int n;
++                unsigned char md[EVP_MAX_MD_SIZE];
++                const EVP_MD *fdig = digest;
++
++                if (!fdig)
++                    fdig = EVP_sha1();
++
++                if (!X509_digest(x, fdig, md, &n)) {
++                    BIO_printf(bio_err, "out of memory\n");
++                    goto end;
++                }
++                BIO_printf(out, "%s Fingerprint=",
++                           OBJ_nid2sn(EVP_MD_type(fdig)));
++                for (j = 0; j < (int)n; j++) {
++                    BIO_printf(out, "%02X%c", md[j], (j + 1 == (int)n)
++                               ? '\n' : ':');
++                }
++            }
++
++            /* should be in the library */
++            else if ((sign_flag == i) && (x509req == 0)) {
++                BIO_printf(bio_err, "Getting Private key\n");
++                if (Upkey == NULL) {
++                    Upkey = load_key(keyfile, keyformat, 0,
++                                     passin, e, "Private key");
++                    if (Upkey == NULL)
++                        goto end;
++                }
++
++                assert(need_rand);
++                if (!sign(x, Upkey, days, clrext, digest, extconf, extsect))
++                    goto end;
++            } else if (CA_flag == i) {
++                BIO_printf(bio_err, "Getting CA Private Key\n");
++                if (CAkeyfile != NULL) {
++                    CApkey = load_key(CAkeyfile, CAkeyformat,
++                                      0, passin, e, "CA Private Key");
++                    if (CApkey == NULL)
++                        goto end;
++                }
++
++                assert(need_rand);
++                if (!x509_certify(ctx, CAfile, digest, x, xca,
++                                  CApkey, sigopts,
++                                  CAserial, CA_createserial, days, clrext,
++                                  extconf, extsect, sno, reqfile))
++                    goto end;
++            } else if (x509req == i) {
++                EVP_PKEY *pk;
++
++                BIO_printf(bio_err, "Getting request Private Key\n");
++                if (keyfile == NULL) {
++                    BIO_printf(bio_err, "no request key file specified\n");
++                    goto end;
++                } else {
++                    pk = load_key(keyfile, keyformat, 0,
++                                  passin, e, "request key");
++                    if (pk == NULL)
++                        goto end;
++                }
++
++                BIO_printf(bio_err, "Generating certificate request\n");
++
++                rq = X509_to_X509_REQ(x, pk, digest);
++                EVP_PKEY_free(pk);
++                if (rq == NULL) {
++                    ERR_print_errors(bio_err);
++                    goto end;
++                }
++                if (!noout) {
++                    X509_REQ_print(out, rq);
++                    PEM_write_bio_X509_REQ(out, rq);
++                }
++                noout = 1;
++            } else if (ocspid == i) {
++                X509_ocspid_print(out, x);
++            }
++        }
++    }
++
++    if (checkend) {
++        time_t tcheck = time(NULL) + checkoffset;
++
++        if (X509_cmp_time(X509_get0_notAfter(x), &tcheck) < 0) {
++            BIO_printf(out, "Certificate will expire\n");
++            ret = 1;
++        } else {
++            BIO_printf(out, "Certificate will not expire\n");
++            ret = 0;
++        }
++        goto end;
++    }
++
++    print_cert_checks(out, x, checkhost, checkemail, checkip);
++
++    if (noout || nocert) {
++        ret = 0;
++        goto end;
++    }
++
++    if (outformat == FORMAT_ASN1)
++        i = i2d_X509_bio(out, x);
++    else if (outformat == FORMAT_PEM) {
++        if (trustout)
++            i = PEM_write_bio_X509_AUX(out, x);
++        else
++            i = PEM_write_bio_X509(out, x);
++    } else {
++        BIO_printf(bio_err, "bad output format specified for outfile\n");
++        goto end;
++    }
++    if (!i) {
++        BIO_printf(bio_err, "unable to write certificate\n");
++        ERR_print_errors(bio_err);
++        goto end;
++    }
++    ret = 0;
++ end:
++    if (need_rand)
++        app_RAND_write_file(NULL);
++    NCONF_free(extconf);
++    BIO_free_all(out);
++    X509_STORE_free(ctx);
++    X509_REQ_free(req);
++    X509_free(x);
++    X509_free(xca);
++    EVP_PKEY_free(Upkey);
++    EVP_PKEY_free(CApkey);
++    EVP_PKEY_free(fkey);
++    sk_OPENSSL_STRING_free(sigopts);
++    X509_REQ_free(rq);
++    ASN1_INTEGER_free(sno);
++    sk_ASN1_OBJECT_pop_free(trust, ASN1_OBJECT_free);
++    sk_ASN1_OBJECT_pop_free(reject, ASN1_OBJECT_free);
++    ASN1_OBJECT_free(objtmp);
++    release_engine(e);
++    OPENSSL_free(passin);
++    return (ret);
++}
++
++static ASN1_INTEGER *x509_load_serial(const char *CAfile, const char *serialfile,
++                                      int create)
++{
++    char *buf = NULL, *p;
++    ASN1_INTEGER *bs = NULL;
++    BIGNUM *serial = NULL;
++    size_t len;
++
++    len = ((serialfile == NULL)
++           ? (strlen(CAfile) + strlen(POSTFIX) + 1)
++           : (strlen(serialfile))) + 1;
++    buf = app_malloc(len, "serial# buffer");
++    if (serialfile == NULL) {
++        OPENSSL_strlcpy(buf, CAfile, len);
++        for (p = buf; *p; p++)
++            if (*p == '.') {
++                *p = '\0';
++                break;
++            }
++        OPENSSL_strlcat(buf, POSTFIX, len);
++    } else
++        OPENSSL_strlcpy(buf, serialfile, len);
++
++    serial = load_serial(buf, create, NULL);
++    if (serial == NULL)
++        goto end;
++
++    if (!BN_add_word(serial, 1)) {
++        BIO_printf(bio_err, "add_word failure\n");
++        goto end;
++    }
++
++    if (!save_serial(buf, NULL, serial, &bs))
++        goto end;
++
++ end:
++    OPENSSL_free(buf);
++    BN_free(serial);
++    return bs;
++}
++
++static int x509_certify(X509_STORE *ctx, const char *CAfile, const EVP_MD *digest,
++                        X509 *x, X509 *xca, EVP_PKEY *pkey,
++                        STACK_OF(OPENSSL_STRING) *sigopts,
++                        const char *serialfile, int create,
++                        int days, int clrext, CONF *conf, const char *section,
++                        ASN1_INTEGER *sno, int reqfile)
++{
++    int ret = 0;
++    ASN1_INTEGER *bs = NULL;
++    X509_STORE_CTX *xsc = NULL;
++    EVP_PKEY *upkey;
++
++    upkey = X509_get0_pubkey(xca);
++    if (upkey == NULL) {
++        BIO_printf(bio_err, "Error obtaining CA X509 public key\n");
++        goto end;
++    }
++    EVP_PKEY_copy_parameters(upkey, pkey);
++
++    xsc = X509_STORE_CTX_new();
++    if (xsc == NULL || !X509_STORE_CTX_init(xsc, ctx, x, NULL)) {
++        BIO_printf(bio_err, "Error initialising X509 store\n");
++        goto end;
++    }
++    if (sno)
++        bs = sno;
++    else if ((bs = x509_load_serial(CAfile, serialfile, create)) == NULL)
++        goto end;
++
++    /*
++     * NOTE: this certificate can/should be self signed, unless it was a
++     * certificate request in which case it is not.
++     */
++    X509_STORE_CTX_set_cert(xsc, x);
++    X509_STORE_CTX_set_flags(xsc, X509_V_FLAG_CHECK_SS_SIGNATURE);
++    if (!reqfile && X509_verify_cert(xsc) <= 0)
++        goto end;
++
++    if (!X509_check_private_key(xca, pkey)) {
++        BIO_printf(bio_err,
++                   "CA certificate and CA private key do not match\n");
++        goto end;
++    }
++
++    if (!X509_set_issuer_name(x, X509_get_subject_name(xca)))
++        goto end;
++    if (!X509_set_serialNumber(x, bs))
++        goto end;
++
++    if (!set_cert_times(x, NULL, NULL, days))
++        goto end;
++
++    if (clrext) {
++        while (X509_get_ext_count(x) > 0)
++            X509_delete_ext(x, 0);
++    }
++
++    if (conf) {
++        X509V3_CTX ctx2;
++        X509_set_version(x, 2); /* version 3 certificate */
++        X509V3_set_ctx(&ctx2, xca, x, NULL, NULL, 0);
++        X509V3_set_nconf(&ctx2, conf);
++        if (!X509V3_EXT_add_nconf(conf, &ctx2, section, x))
++            goto end;
++    }
++
++    if (!do_X509_sign(x, pkey, digest, sigopts))
++        goto end;
++    ret = 1;
++ end:
++    X509_STORE_CTX_free(xsc);
++    if (!ret)
++        ERR_print_errors(bio_err);
++    if (!sno)
++        ASN1_INTEGER_free(bs);
++    return ret;
++}
++
++static int callb(int ok, X509_STORE_CTX *ctx)
++{
++    int err;
++    X509 *err_cert;
++
++    /*
++     * it is ok to use a self signed certificate This case will catch both
++     * the initial ok == 0 and the final ok == 1 calls to this function
++     */
++    err = X509_STORE_CTX_get_error(ctx);
++    if (err == X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT)
++        return 1;
++
++    /*
++     * BAD we should have gotten an error.  Normally if everything worked
++     * X509_STORE_CTX_get_error(ctx) will still be set to
++     * DEPTH_ZERO_SELF_....
++     */
++    if (ok) {
++        BIO_printf(bio_err,
++                   "error with certificate to be certified - should be self signed\n");
++        return 0;
++    } else {
++        err_cert = X509_STORE_CTX_get_current_cert(ctx);
++        print_name(bio_err, NULL, X509_get_subject_name(err_cert), 0);
++        BIO_printf(bio_err,
++                   "error with certificate - error %d at depth %d\n%s\n", err,
++                   X509_STORE_CTX_get_error_depth(ctx),
++                   X509_verify_cert_error_string(err));
++        return 1;
++    }
++}
++
++/* self sign */
++static int sign(X509 *x, EVP_PKEY *pkey, int days, int clrext,
++                const EVP_MD *digest, CONF *conf, const char *section)
++{
++
++    if (!X509_set_issuer_name(x, X509_get_subject_name(x)))
++        goto err;
++    if (!set_cert_times(x, NULL, NULL, days))
++        goto err;
++    if (!X509_set_pubkey(x, pkey))
++        goto err;
++    if (clrext) {
++        while (X509_get_ext_count(x) > 0)
++            X509_delete_ext(x, 0);
++    }
++    if (conf) {
++        X509V3_CTX ctx;
++        X509_set_version(x, 2); /* version 3 certificate */
++        X509V3_set_ctx(&ctx, x, x, NULL, NULL, 0);
++        X509V3_set_nconf(&ctx, conf);
++        if (!X509V3_EXT_add_nconf(conf, &ctx, section, x))
++            goto err;
++    }
++    if (!X509_sign(x, pkey, digest))
++        goto err;
++    return 1;
++ err:
++    ERR_print_errors(bio_err);
++    return 0;
++}
++
++static int purpose_print(BIO *bio, X509 *cert, X509_PURPOSE *pt)
++{
++    int id, i, idret;
++    const char *pname;
++    id = X509_PURPOSE_get_id(pt);
++    pname = X509_PURPOSE_get0_name(pt);
++    for (i = 0; i < 2; i++) {
++        idret = X509_check_purpose(cert, id, i);
++        BIO_printf(bio, "%s%s : ", pname, i ? " CA" : "");
++        if (idret == 1)
++            BIO_printf(bio, "Yes\n");
++        else if (idret == 0)
++            BIO_printf(bio, "No\n");
++        else
++            BIO_printf(bio, "Yes (WARNING code=%d)\n", idret);
++    }
++    return 1;
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/appveyor.yml b/CryptoPkg/Library/OpensslLib/openssl/appveyor.yml
+new file mode 100644
+index 0000000..9074a8c
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/appveyor.yml
+@@ -0,0 +1,53 @@
++platform:
++    - x86
++    - x64
++
++environment:
++    matrix:
++        - VSVER: 14
++
++configuration:
++    - plain
++    - shared
++
++before_build:
++    - ps: >-
++        If ($env:Platform -Match "x86") {
++            $env:VCVARS_PLATFORM="x86"
++            $env:TARGET="VC-WIN32"
++        } Else {
++            $env:VCVARS_PLATFORM="amd64"
++            $env:TARGET="VC-WIN64A"
++        }
++    - ps: >-
++        If ($env:Configuration -Match "shared") {
++            $env:SHARED=""
++        } Else {
++            $env:SHARED="no-shared"
++        }
++    - ps: $env:VSCOMNTOOLS=(Get-Content ("env:VS" + "$env:VSVER" + "0COMNTOOLS"))
++    - call "%VSCOMNTOOLS%\..\..\VC\vcvarsall.bat" %VCVARS_PLATFORM%
++    - mkdir _build
++    - cd _build
++    - perl ..\Configure %TARGET% no-asm %SHARED%
++    - cd ..
++
++build_script:
++    - cd _build
++    - nmake
++    - cd ..
++
++test_script:
++    - cd _build
++    - nmake test
++    - mkdir ..\_install
++    - nmake install install_docs DESTDIR=..\_install
++    - cd ..
++
++notifications:
++    - provider: Email
++      to:
++          - openssl-commits@openssl.org
++      on_build_success: false
++      on_build_failure: true
++      on_build_status_changed: true
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/build.info b/CryptoPkg/Library/OpensslLib/openssl/build.info
+new file mode 100644
+index 0000000..fa136dc
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/build.info
+@@ -0,0 +1,41 @@
++LIBS=libcrypto libssl
++ORDINALS[libcrypto]=crypto
++ORDINALS[libssl]=ssl
++INCLUDE[libcrypto]=. crypto/include include
++INCLUDE[libssl]=. include
++DEPEND[libssl]=libcrypto
++
++# Empty DEPEND "indices" means the dependencies are expected to be built
++# unconditionally before anything else.
++DEPEND[]=include/openssl/opensslconf.h crypto/include/internal/bn_conf.h \
++         crypto/include/internal/dso_conf.h
++DEPEND[include/openssl/opensslconf.h]=configdata.pm
++GENERATE[include/openssl/opensslconf.h]=include/openssl/opensslconf.h.in
++DEPEND[crypto/include/internal/bn_conf.h]=configdata.pm
++GENERATE[crypto/include/internal/bn_conf.h]=crypto/include/internal/bn_conf.h.in
++DEPEND[crypto/include/internal/dso_conf.h]=configdata.pm
++GENERATE[crypto/include/internal/dso_conf.h]=crypto/include/internal/dso_conf.h.in
++
++
++IF[{- $config{target} =~ /^Cygwin/ -}]
++ SHARED_NAME[libcrypto]=cygcrypto-{- $config{shlib_major}.".".$config{shlib_minor} -}
++ SHARED_NAME[libssl]=cygssl-{- $config{shlib_major}.".".$config{shlib_minor} -}
++ELSIF[{- $config{target} =~ /^mingw/ -}]
++ SHARED_NAME[libcrypto]=libcrypto-{- $config{shlib_major}."_".$config{shlib_minor} -}{- $config{target} eq "mingw64" ? "-x64" : "" -}
++ SHARED_NAME[libssl]=libssl-{- $config{shlib_major}."_".$config{shlib_minor} -}{- $config{target} eq "mingw64" ? "-x64" : "" -}
++ELSIF[{- $config{target} =~ /^VC-/ -}]
++ SHARED_NAME[libcrypto]=libcrypto-{- $config{shlib_major}."_".$config{shlib_minor} -}{- $target{multilib} -}
++ SHARED_NAME[libssl]=libssl-{- $config{shlib_major}."_".$config{shlib_minor} -}{- $target{multilib} -}
++ENDIF
++
++# VMS has a cultural standard where all libraries are prefixed.
++# For OpenSSL, the choice is 'ossl$' (this prefix was claimed in a
++# conversation with VSI, Tuesday January 26 2016)
++# Also, it seems it's usual to have the pointer size the libraries
++# were built for as part of the name.
++IF[{- $config{target} =~ /^vms/ -}]
++ RENAME[libcrypto]=ossl$libcrypto{- $target{pointer_size} -}
++ RENAME[libssl]=ossl$libssl{- $target{pointer_size} -}
++ SHARED_NAME[libcrypto]=ossl$libcrypto{- sprintf "%02d%02d", $config{shlib_major}, $config{shlib_minor} -}_shr{- $target{pointer_size} -}
++ SHARED_NAME[libssl]=ossl$libssl{- sprintf "%02d%02d", $config{shlib_major}, $config{shlib_minor} -}_shr{- $target{pointer_size} -}
++ENDIF
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/config b/CryptoPkg/Library/OpensslLib/openssl/config
+new file mode 100755
+index 0000000..1341fd6
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/config
+@@ -0,0 +1,924 @@
++#!/bin/sh
++# Copyright 1998-2016 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
++# in the file LICENSE in the source distribution or at
++# https://www.openssl.org/source/license.html
++
++# OpenSSL config: determine the operating system and run ./Configure
++# Derived from minarch and GuessOS from Apache.
++#
++# Do "config -h" for usage information.
++SUFFIX=""
++DRYRUN="false"
++VERBOSE="false"
++EXE=""
++THERE=`dirname $0`
++
++# pick up any command line args to config
++for i
++do
++case "$i" in 
++-d*) options=$options" --debug";;
++-t*) DRYRUN="true" VERBOSE="true";;
++-v*) VERBOSE="true";;
++-h*) DRYRUN="true"; cat </dev/null` || MACHINE="unknown"
++[ "$RELEASE" ] || RELEASE=`(uname -r) 2>/dev/null` || RELEASE="unknown"
++[ "$SYSTEM" ] || SYSTEM=`(uname -s) 2>/dev/null`  || SYSTEM="unknown"
++[ "$BUILD" ] || VERSION=`(uname -v) 2>/dev/null` || VERSION="unknown"
++
++
++# Now test for ISC and SCO, since it is has a braindamaged uname.
++#
++# We need to work around FreeBSD 1.1.5.1 
++(
++XREL=`uname -X 2>/dev/null | grep "^Release" | awk '{print $3}'`
++if [ "x$XREL" != "x" ]; then
++    if [ -f /etc/kconfig ]; then
++	case "$XREL" in
++	    4.0|4.1)
++		    echo "${MACHINE}-whatever-isc4"; exit 0
++		;;
++	esac
++    else
++	case "$XREL" in
++	    3.2v4.2)
++		echo "whatever-whatever-sco3"; exit 0
++		;;
++	    3.2v5.0*)
++		echo "whatever-whatever-sco5"; exit 0
++		;;
++	    4.2MP)
++		case "x${VERSION}" in
++		    x2.0*) echo "whatever-whatever-unixware20"; exit 0 ;;
++		    x2.1*) echo "whatever-whatever-unixware21"; exit 0 ;;
++		    x2*)   echo "whatever-whatever-unixware2";  exit 0 ;;
++		esac
++		;;
++	    4.2)
++		echo "whatever-whatever-unixware1"; exit 0
++		;;
++	    5*)
++		case "x${VERSION}" in
++		    # We hardcode i586 in place of ${MACHINE} for the
++		    # following reason. The catch is that even though Pentium
++		    # is minimum requirement for platforms in question,
++		    # ${MACHINE} gets always assigned to i386. Now, problem
++		    # with i386 is that it makes ./config pass 386 to
++		    # ./Configure, which in turn makes make generate
++		    # inefficient SHA-1 (for this moment) code.
++		    x[678]*)  echo "i586-sco-unixware7"; exit 0 ;;
++		esac
++		;;
++	esac
++    fi
++fi
++# Now we simply scan though... In most cases, the SYSTEM info is enough
++#
++case "${SYSTEM}:${RELEASE}:${VERSION}:${MACHINE}" in
++    A/UX:*)
++	echo "m68k-apple-aux3"; exit 0
++	;;
++
++    AIX:[3-9]:4:*)
++	echo "${MACHINE}-ibm-aix"; exit 0
++	;;
++
++    AIX:*:[5-9]:*)
++	echo "${MACHINE}-ibm-aix"; exit 0
++	;;
++
++    AIX:*)
++	echo "${MACHINE}-ibm-aix3"; exit 0
++	;;
++
++    HI-UX:*)
++	echo "${MACHINE}-hi-hiux"; exit 0
++	;;
++
++    HP-UX:*)
++	HPUXVER=`echo ${RELEASE}|sed -e 's/[^.]*.[0B]*//'`
++	case "$HPUXVER" in
++	    1[0-9].*)	# HPUX 10 and 11 targets are unified
++		echo "${MACHINE}-hp-hpux1x"; exit 0
++		;;
++	    *)
++		echo "${MACHINE}-hp-hpux"; exit 0
++		;;
++	esac
++	;;
++
++    IRIX:6.*)
++	echo "mips3-sgi-irix"; exit 0
++	;;
++
++    IRIX64:*)
++	echo "mips4-sgi-irix64"; exit 0
++	;;
++
++    Linux:[2-9].*)
++	echo "${MACHINE}-whatever-linux2"; exit 0
++	;;
++
++    Linux:1.*)
++	echo "${MACHINE}-whatever-linux1"; exit 0
++	;;
++
++    GNU*)
++	echo "hurd-x86"; exit 0;
++	;;
++
++    LynxOS:*)
++	echo "${MACHINE}-lynx-lynxos"; exit 0
++	;;
++
++    BSD/OS:4.*)  # BSD/OS always says 386
++	echo "i486-whatever-bsdi4"; exit 0
++	;;
++
++    BSD/386:*:*:*486*|BSD/OS:*:*:*:*486*)
++        case `/sbin/sysctl -n hw.model` in
++	    Pentium*)
++                echo "i586-whatever-bsdi"; exit 0
++                ;;
++            *)
++                echo "i386-whatever-bsdi"; exit 0
++                ;;
++            esac;
++	;;
++
++    BSD/386:*|BSD/OS:*)
++	echo "${MACHINE}-whatever-bsdi"; exit 0
++	;;
++
++    FreeBSD:*:*:*386*)
++        VERS=`echo ${RELEASE} | sed -e 's/[-(].*//'`
++        MACH=`sysctl -n hw.model`
++        ARCH='whatever'
++        case ${MACH} in
++           *386*       ) MACH="i386"     ;;
++           *486*       ) MACH="i486"     ;;
++           Pentium\ II*) MACH="i686"     ;;
++           Pentium*    ) MACH="i586"     ;;
++           *           ) MACH="$MACHINE" ;;
++        esac
++        case ${MACH} in
++           i[0-9]86 ) ARCH="pc" ;;
++        esac
++        echo "${MACH}-${ARCH}-freebsd${VERS}"; exit 0
++        ;;
++
++    FreeBSD:*)
++	echo "${MACHINE}-whatever-freebsd"; exit 0
++	;;
++
++    Haiku:*)
++	echo "${MACHINE}-whatever-haiku"; exit 0
++	;;
++
++    NetBSD:*:*:*386*)
++        echo "`(/usr/sbin/sysctl -n hw.model || /sbin/sysctl -n hw.model) | sed 's,.*\(.\)86-class.*,i\186,'`-whatever-netbsd"; exit 0
++	;;
++
++    NetBSD:*)
++	echo "${MACHINE}-whatever-netbsd"; exit 0
++	;;
++
++    OpenBSD:*)
++	echo "${MACHINE}-whatever-openbsd"; exit 0
++	;;
++
++    OpenUNIX:*)
++	echo "${MACHINE}-unknown-OpenUNIX${VERSION}"; exit 0
++	;;
++
++    OSF1:*:*:*alpha*)
++	OSFMAJOR=`echo ${RELEASE}| sed -e 's/^V\([0-9]*\)\..*$/\1/'`
++	case "$OSFMAJOR" in
++	    4|5)
++		echo "${MACHINE}-dec-tru64"; exit 0
++		;;
++	    1|2|3)
++		echo "${MACHINE}-dec-osf"; exit 0
++		;;
++	    *)
++		echo "${MACHINE}-dec-osf"; exit 0
++		;;
++	esac
++	;;
++
++    QNX:*)
++	case "$RELEASE" in
++	    4*)
++		echo "${MACHINE}-whatever-qnx4"
++		;;
++	    6*)
++		echo "${MACHINE}-whatever-qnx6"
++		;;
++	    *)
++		echo "${MACHINE}-whatever-qnx"
++		;;
++	esac
++	exit 0
++	;;
++
++    Paragon*:*:*:*)
++	echo "i860-intel-osf1"; exit 0
++	;;
++
++    Rhapsody:*)
++	echo "ppc-apple-rhapsody"; exit 0
++	;;
++
++    Darwin:*)
++	case "$MACHINE" in
++	    Power*)
++		echo "ppc-apple-darwin${VERSION}"
++		;;
++	    x86_64)
++		echo "x86_64-apple-darwin${VERSION}"
++		;;
++	    *)
++		echo "i686-apple-darwin${VERSION}"
++		;;
++	esac
++	exit 0
++	;;
++
++    SunOS:5.*)
++	echo "${MACHINE}-whatever-solaris2"; exit 0
++	;;
++
++    SunOS:*)
++	echo "${MACHINE}-sun-sunos4"; exit 0
++	;;
++
++    UNIX_System_V:4.*:*)
++	echo "${MACHINE}-whatever-sysv4"; exit 0
++	;;
++
++    VOS:*:*:i786)
++     echo "i386-stratus-vos"; exit 0
++     ;;
++
++    VOS:*:*:*)
++     echo "hppa1.1-stratus-vos"; exit 0
++     ;;
++
++    *:4*:R4*:m88k)
++	echo "${MACHINE}-whatever-sysv4"; exit 0
++	;;
++
++    DYNIX/ptx:4*:*)
++	echo "${MACHINE}-whatever-sysv4"; exit 0
++	;;
++
++    *:4.0:3.0:3[34]?? | *:4.0:3.0:3[34]??,*)
++	echo "i486-ncr-sysv4"; exit 0
++	;;
++
++    ULTRIX:*)
++	echo "${MACHINE}-unknown-ultrix"; exit 0
++	;;
++
++    POSIX-BC*)
++	echo "${MACHINE}-siemens-sysv4"; exit 0   # Here, $MACHINE == "BS2000"
++	;;
++
++    machten:*)
++       echo "${MACHINE}-tenon-${SYSTEM}"; exit 0;
++       ;;
++
++    library:*)
++	echo "${MACHINE}-ncr-sysv4"; exit 0
++	;;
++
++    ConvexOS:*:11.0:*)
++	echo "${MACHINE}-v11-${SYSTEM}"; exit 0;
++	;;
++
++    MINGW*)
++	echo "${MACHINE}-whatever-mingw"; exit 0;
++	;;
++    CYGWIN*)
++	echo "${MACHINE}-pc-cygwin"; exit 0
++	;;
++
++    vxworks*)
++       echo "${MACHINE}-whatever-vxworks"; exit 0;
++       ;;
++esac
++
++#
++# Ugg. These are all we can determine by what we know about
++# the output of uname. Be more creative:
++#
++
++# Do the Apollo stuff first. Here, we just simply assume
++# that the existence of the /usr/apollo directory is proof
++# enough
++if [ -d /usr/apollo ]; then
++    echo "whatever-apollo-whatever"
++    exit 0
++fi
++
++# Now NeXT
++ISNEXT=`hostinfo 2>/dev/null`
++case "$ISNEXT" in
++    *'NeXT Mach 3.3'*)
++	echo "whatever-next-nextstep3.3"; exit 0
++	;;
++    *NeXT*)
++	echo "whatever-next-nextstep"; exit 0
++	;;
++esac
++
++# At this point we gone through all the one's
++# we know of: Punt
++
++echo "${MACHINE}-whatever-${SYSTEM}" 
++exit 0
++) 2>/dev/null | (
++
++# ---------------------------------------------------------------------------
++# this is where the translation occurs into SSLeay terms
++# ---------------------------------------------------------------------------
++
++# Only set CC if not supplied already
++if [ -z "$CROSS_COMPILE$CC" ]; then
++  GCCVER=`sh -c "gcc -dumpversion" 2>/dev/null`
++  if [ "$GCCVER" != "" ]; then
++    # then strip off whatever prefix egcs prepends the number with...
++    # Hopefully, this will work for any future prefixes as well.
++    GCCVER=`echo $GCCVER | LC_ALL=C sed 's/^[a-zA-Z]*\-//'`
++    # Since gcc 3.1 gcc --version behaviour has changed.  gcc -dumpversion
++    # does give us what we want though, so we use that.  We just just the
++    # major and minor version numbers.
++    # peak single digit before and after first dot, e.g. 2.95.1 gives 29
++    GCCVER=`echo $GCCVER | sed 's/\([0-9]\)\.\([0-9]\).*/\1\2/'`
++    CC=gcc
++  else
++    CC=cc
++  fi
++fi
++GCCVER=${GCCVER:-0}
++if [ "$SYSTEM" = "HP-UX" ];then
++  # By default gcc is a ILP32 compiler (with long long == 64).
++  GCC_BITS="32"
++  if [ $GCCVER -ge 30 ]; then
++    # PA64 support only came in with gcc 3.0.x.
++    # We check if the preprocessor symbol __LP64__ is defined...
++    if echo "__LP64__" | gcc -v -E -x c - 2>/dev/null | grep "^__LP64__" 2>&1 > /dev/null; then
++      : # __LP64__ has slipped through, it therefore is not defined
++    else
++      GCC_BITS="64"
++    fi
++  fi
++fi
++if [ "$SYSTEM" = "SunOS" ]; then
++  if [ $GCCVER -ge 30 ]; then
++    # 64-bit ABI isn't officially supported in gcc 3.0, but it appears
++    # to be working, at the very least 'make test' passes...
++    if gcc -v -E -x c /dev/null 2>&1 | grep __arch64__ > /dev/null; then
++      GCC_ARCH="-m64"
++    else
++      GCC_ARCH="-m32"
++    fi
++  fi
++  # check for WorkShop C, expected output is "cc: blah-blah C x.x"
++  CCVER=`(cc -V 2>&1) 2>/dev/null | \
++  	egrep -e '^cc: .* C [0-9]\.[0-9]' | \
++	sed 's/.* C \([0-9]\)\.\([0-9]\).*/\1\2/'`
++  CCVER=${CCVER:-0}
++  if [ $MACHINE != i86pc -a $CCVER -gt 40 ]; then
++    CC=cc	# overrides gcc!!!
++    if [ $CCVER -eq 50 ]; then
++      echo "WARNING! Detected WorkShop C 5.0. Do make sure you have"
++      echo "         patch #107357-01 or later applied."
++      sleep 5
++    fi
++  fi
++fi
++
++if [ "${SYSTEM}" = "AIX" ]; then	# favor vendor cc over gcc
++    (cc) 2>&1 | grep -iv "not found" > /dev/null && CC=cc
++fi
++
++CCVER=${CCVER:-0}
++
++# read the output of the embedded GuessOS 
++read GUESSOS
++
++echo Operating system: $GUESSOS
++
++# now map the output into SSLeay terms ... really should hack into the
++# script above so we end up with values in vars but that would take
++# more time that I want to waste at the moment
++case "$GUESSOS" in
++  uClinux*64*)
++    OUT=uClinux-dist64
++	;;
++  uClinux*)
++    OUT=uClinux-dist
++	;;
++  mips3-sgi-irix)
++	#CPU=`(hinv -t cpu) 2>/dev/null | head -1 | sed 's/^CPU:[^R]*R\([0-9]*\).*/\1/'`
++	#CPU=${CPU:-0}
++	#if [ $CPU -ge 5000 ]; then
++	#	options="$options -mips4"
++	#else
++	#	options="$options -mips3"
++	#fi
++	OUT="irix-mips3-$CC"
++	;;
++  mips4-sgi-irix64)
++	echo "WARNING! If you wish to build 64-bit library, then you have to"
++	echo "         invoke '$THERE/Configure irix64-mips4-$CC' *manually*."
++	if [ "$DRYRUN" = "false" -a -t 1 ]; then
++	  echo "         You have about 5 seconds to press Ctrl-C to abort."
++	  (trap "stty `stty -g`; exit 0" 2 0; stty -icanon min 0 time 50; read waste) <&1
++	fi
++        #CPU=`(hinv -t cpu) 2>/dev/null | head -1 | sed 's/^CPU:[^R]*R\([0-9]*\).*/\1/'`
++        #CPU=${CPU:-0}
++        #if [ $CPU -ge 5000 ]; then
++        #        options="$options -mips4"
++        #else
++        #        options="$options -mips3"
++        #fi
++	OUT="irix-mips3-$CC"
++	;;
++  ppc-apple-rhapsody) OUT="rhapsody-ppc-cc" ;;
++  ppc-apple-darwin*)
++	ISA64=`(sysctl -n hw.optional.64bitops) 2>/dev/null`
++	if [ "$ISA64" = "1" -a -z "$KERNEL_BITS" ]; then
++	    echo "WARNING! If you wish to build 64-bit library, then you have to"
++	    echo "         invoke '$THERE/Configure darwin64-ppc-cc' *manually*."
++	    if [ "$DRYRUN" = "false" -a -t 1 ]; then
++	      echo "         You have about 5 seconds to press Ctrl-C to abort."
++	      (trap "stty `stty -g`; exit 0" 2 0; stty -icanon min 0 time 50; read waste) <&1
++	    fi
++	fi
++	if [ "$ISA64" = "1" -a "$KERNEL_BITS" = "64" ]; then
++	    OUT="darwin64-ppc-cc"
++	else
++	    OUT="darwin-ppc-cc"
++	fi ;;
++  i?86-apple-darwin*)
++	ISA64=`(sysctl -n hw.optional.x86_64) 2>/dev/null`
++	if [ "$ISA64" = "1" -a -z "$KERNEL_BITS" ]; then
++	    echo "WARNING! If you wish to build 64-bit library, then you have to"
++	    echo "         invoke 'KERNEL_BITS=64 $THERE/config $options'."
++	    if [ "$DRYRUN" = "false" -a -t 1 ]; then
++	      echo "         You have about 5 seconds to press Ctrl-C to abort."
++	      # The stty technique used elsewhere doesn't work on
++	      # MacOS. At least, right now on this Mac.
++	      sleep 5
++	    fi
++	fi
++	if [ "$ISA64" = "1" -a "$KERNEL_BITS" = "64" ]; then
++	    OUT="darwin64-x86_64-cc"
++	else
++	    OUT="darwin-i386-cc"
++	fi ;;
++  x86_64-apple-darwin*)
++	if [ -z "$KERNEL_BITS" ]; then
++	    echo "WARNING! If you wish to build 32-bit library, then you have to"
++	    echo "         invoke 'KERNEL_BITS=32 $THERE/config $options'."
++	    if [ "$DRYRUN" = "false" -a -t 1 ]; then
++	      echo "         You have about 5 seconds to press Ctrl-C to abort."
++	      # The stty technique used elsewhere doesn't work on
++	      # MacOS. At least, right now on this Mac.
++	      sleep 5
++	    fi
++	fi
++	if [ "$KERNEL_BITS" = "32" ]; then
++	    OUT="darwin-i386-cc"
++	else
++	    OUT="darwin64-x86_64-cc"
++	fi ;;
++  armv6+7-*-iphoneos)
++	options="$options -arch%20armv6 -arch%20armv7"
++	OUT="iphoneos-cross" ;;
++  *-*-iphoneos)
++	options="$options -arch%20${MACHINE}"
++	OUT="iphoneos-cross" ;;
++  arm64-*-iphoneos|*-*-ios64)
++	OUT="ios64-cross" ;;
++  alpha-*-linux2)
++        ISA=`awk '/cpu model/{print$4;exit(0);}' /proc/cpuinfo`
++	case ${ISA:-generic} in
++	*[678])	OUT="linux-alpha+bwx-$CC" ;;
++	*)	OUT="linux-alpha-$CC" ;;
++	esac
++	if [ "$CC" = "gcc" ]; then
++	    case ${ISA:-generic} in
++	    EV5|EV45)		options="$options -mcpu=ev5";;
++	    EV56|PCA56)		options="$options -mcpu=ev56";;
++	    *)			options="$options -mcpu=ev6";;
++	    esac
++	fi
++	;;
++  ppc64-*-linux2)
++	if [ -z "$KERNEL_BITS" ]; then
++	    echo "WARNING! If you wish to build 64-bit library, then you have to"
++	    echo "         invoke '$THERE/Configure linux-ppc64' *manually*."
++	    if [ "$DRYRUN" = "false" -a -t 1 ]; then
++		echo "         You have about 5 seconds to press Ctrl-C to abort."
++		(trap "stty `stty -g`; exit 0" 2 0; stty -icanon min 0 time 50; read waste) <&1
++	    fi
++	fi
++	if [ "$KERNEL_BITS" = "64" ]; then
++	    OUT="linux-ppc64"
++	else
++	    OUT="linux-ppc"
++	    (echo "__LP64__" | gcc -E -x c - 2>/dev/null | grep "^__LP64__" 2>&1 > /dev/null) || options="$options -m32"
++	fi
++	;;
++  ppc64le-*-linux2) OUT="linux-ppc64le" ;;
++  ppc-*-linux2) OUT="linux-ppc" ;;
++  mips64*-*-linux2)
++	echo "WARNING! If you wish to build 64-bit library, then you have to"
++	echo "         invoke '$THERE/Configure linux64-mips64' *manually*."
++	if [ "$DRYRUN" = "false" -a -t 1 ]; then
++	    echo "         You have about 5 seconds to press Ctrl-C to abort."
++	    (trap "stty `stty -g`; exit 0" 2 0; stty -icanon min 0 time 50; read waste) <&1
++	fi
++	OUT="linux-mips64"
++	;;
++  mips*-*-linux2) OUT="linux-mips32" ;;
++  ppc60x-*-vxworks*) OUT="vxworks-ppc60x" ;;
++  ppcgen-*-vxworks*) OUT="vxworks-ppcgen" ;;
++  pentium-*-vxworks*) OUT="vxworks-pentium" ;;
++  simlinux-*-vxworks*) OUT="vxworks-simlinux" ;;
++  mips-*-vxworks*) OUT="vxworks-mips";;
++  ia64-*-linux?) OUT="linux-ia64" ;;
++  sparc64-*-linux2)
++	echo "WARNING! If you *know* that your GNU C supports 64-bit/V9 ABI"
++	echo "         and wish to build 64-bit library, then you have to"
++	echo "         invoke '$THERE/Configure linux64-sparcv9' *manually*."
++	if [ "$DRYRUN" = "false" -a -t 1 ]; then
++	  echo "          You have about 5 seconds to press Ctrl-C to abort."
++	  (trap "stty `stty -g`; exit 0" 2 0; stty -icanon min 0 time 50; read waste) <&1
++	fi
++	OUT="linux-sparcv9" ;;
++  sparc-*-linux2)
++	KARCH=`awk '/^type/{print$3;exit(0);}' /proc/cpuinfo`
++	case ${KARCH:-sun4} in
++	sun4u*)	OUT="linux-sparcv9" ;;
++	sun4m)	OUT="linux-sparcv8" ;;
++	sun4d)	OUT="linux-sparcv8" ;;
++	*)	OUT="linux-generic32"; options="$options -DB_ENDIAN" ;;
++	esac ;;
++  parisc*-*-linux2)
++	# 64-bit builds under parisc64 linux are not supported and
++	# compiler is expected to generate 32-bit objects...
++	CPUARCH=`awk '/cpu family/{print substr($5,1,3); exit(0);}' /proc/cpuinfo`
++	CPUSCHEDULE=`awk '/^cpu.[ 	]*: PA/{print substr($3,3); exit(0);}' /proc/cpuinfo`
++
++	# ??TODO ??  Model transformations
++	# 0. CPU Architecture for the 1.1 processor has letter suffixes. We strip that off
++	#    assuming no further arch. identification will ever be used by GCC.
++	# 1. I'm most concerned about whether is a 7300LC is closer to a 7100 versus a 7100LC.
++	# 2. The variant 64-bit processors cause concern should GCC support explicit schedulers
++	#    for these chips in the future.
++	#         PA7300LC -> 7100LC (1.1)
++	#         PA8200   -> 8000   (2.0)
++	#         PA8500   -> 8000   (2.0)
++	#         PA8600   -> 8000   (2.0)
++
++	CPUSCHEDULE=`echo $CPUSCHEDULE|sed -e 's/7300LC/7100LC/' -e 's/8.00/8000/'`
++	# Finish Model transformations
++
++	options="$options -DB_ENDIAN -mschedule=$CPUSCHEDULE -march=$CPUARCH"
++	OUT="linux-generic32" ;;
++  armv[1-3]*-*-linux2) OUT="linux-generic32" ;;
++  armv[7-9]*-*-linux2) OUT="linux-armv4"; options="$options -march=armv7-a" ;;
++  arm*-*-linux2) OUT="linux-armv4" ;;
++  aarch64-*-linux2) OUT="linux-aarch64" ;;
++  sh*b-*-linux2) OUT="linux-generic32"; options="$options -DB_ENDIAN" ;;
++  sh*-*-linux2)  OUT="linux-generic32"; options="$options -DL_ENDIAN" ;;
++  m68k*-*-linux2) OUT="linux-generic32"; options="$options -DB_ENDIAN" ;;
++  s390-*-linux2) OUT="linux-generic32"; options="$options -DB_ENDIAN" ;;
++  s390x-*-linux2)
++	# To be uncommented when glibc bug is fixed, see Configure...
++	#if egrep -e '^features.* highgprs' /proc/cpuinfo >/dev/null ; then
++	#  echo "WARNING! If you wish to build \"highgprs\" 32-bit library, then you"
++	#  echo "         have to invoke './Configure linux32-s390x' *manually*."
++	#  if [ "$DRYRUN" = "false" -a -t -1 ]; then
++	#    echo "         You have about 5 seconds to press Ctrl-C to abort."
++	#    (trap "stty `stty -g`; exit 0" 2 0; stty -icanon min 0 time 50; read waste) <&1
++	#  fi
++	#fi
++	OUT="linux64-s390x"
++	;;
++  x86_64-*-linux?)
++	if $CC -dM -E -x c /dev/null 2>&1 | grep -q ILP32 > /dev/null; then
++	    OUT="linux-x32"
++	else
++	    OUT="linux-x86_64"
++	fi ;;
++  *86-*-linux2)
++        # On machines where the compiler understands -m32, prefer a
++        # config target that uses it
++        if $CC -m32 -E -x c /dev/null > /dev/null 2>&1; then
++            OUT="linux-x86"
++        else
++            OUT="linux-elf"
++        fi ;;
++  *86-*-linux1) OUT="linux-aout" ;;
++  *-*-linux?) OUT="linux-generic32" ;;
++  sun4[uv]*-*-solaris2)
++	OUT="solaris-sparcv9-$CC"
++	ISA64=`(isainfo) 2>/dev/null | grep sparcv9`
++	if [ "$ISA64" != "" -a "$KERNEL_BITS" = "" ]; then
++	    if [ "$CC" = "cc" -a $CCVER -ge 50 ]; then
++		echo "WARNING! If you wish to build 64-bit library, then you have to"
++		echo "         invoke '$THERE/Configure solaris64-sparcv9-cc' *manually*."
++		if [ "$DRYRUN" = "false" -a -t 1 ]; then
++		  echo "         You have about 5 seconds to press Ctrl-C to abort."
++		  (trap "stty `stty -g`; exit 0" 2 0; stty -icanon min 0 time 50; read waste) <&1
++		fi
++	    elif [ "$CC" = "gcc" -a "$GCC_ARCH" = "-m64" ]; then
++		# $GCC_ARCH denotes default ABI chosen by compiler driver
++		# (first one found on the $PATH). I assume that user
++		# expects certain consistency with the rest of his builds
++		# and therefore switch over to 64-bit. 
++		OUT="solaris64-sparcv9-gcc"
++		echo "WARNING! If you wish to build 32-bit library, then you have to"
++		echo "         invoke '$THERE/Configure solaris-sparcv9-gcc' *manually*."
++		if [ "$DRYRUN" = "false" -a -t 1 ]; then
++		  echo "         You have about 5 seconds to press Ctrl-C to abort."
++		  (trap "stty `stty -g`; exit 0" 2 0; stty -icanon min 0 time 50; read waste) <&1
++		fi
++	    elif [ "$GCC_ARCH" = "-m32" ]; then
++		echo "NOTICE! If you *know* that your GNU C supports 64-bit/V9 ABI"
++		echo "        and wish to build 64-bit library, then you have to"
++		echo "        invoke '$THERE/Configure solaris64-sparcv9-gcc' *manually*."
++		if [ "$DRYRUN" = "false" -a -t 1 ]; then
++		  echo "         You have about 5 seconds to press Ctrl-C to abort."
++		  (trap "stty `stty -g`; exit 0" 2 0; stty -icanon min 0 time 50; read waste) <&1
++		fi
++	    fi
++	fi
++	if [ "$ISA64" != "" -a "$KERNEL_BITS" = "64" ]; then
++	    OUT="solaris64-sparcv9-$CC"
++	fi
++	;;
++  sun4m-*-solaris2)	OUT="solaris-sparcv8-$CC" ;;
++  sun4d-*-solaris2)	OUT="solaris-sparcv8-$CC" ;;
++  sun4*-*-solaris2)	OUT="solaris-sparcv7-$CC" ;;
++  *86*-*-solaris2)
++	ISA64=`(isainfo) 2>/dev/null | grep amd64`
++	if [ "$ISA64" != "" -a ${KERNEL_BITS:-64} -eq 64 ]; then
++	    OUT="solaris64-x86_64-$CC"
++	else
++	    OUT="solaris-x86-$CC"
++	    if [ `uname -r | sed -e 's/5\.//'` -lt 10 ]; then
++		options="$options no-sse2"
++	    fi
++	fi
++	;;
++  *-*-sunos4)		OUT="sunos-$CC" ;;
++
++  *86*-*-bsdi4)		OUT="BSD-x86-elf"; options="$options no-sse2 -ldl" ;;
++  alpha*-*-*bsd*)	OUT="BSD-generic64"; options="$options -DL_ENDIAN" ;;
++  powerpc64-*-*bsd*)	OUT="BSD-generic64"; options="$options -DB_ENDIAN" ;;
++  sparc64-*-*bsd*)	OUT="BSD-sparc64" ;;
++  ia64-*-*bsd*)		OUT="BSD-ia64" ;;
++  amd64-*-*bsd*)	OUT="BSD-x86_64" ;;
++  *86*-*-*bsd*)		# mimic ld behaviour when it's looking for libc...
++			if [ -L /usr/lib/libc.so ]; then	# [Free|Net]BSD
++			    libc=/usr/lib/libc.so
++			else					# OpenBSD
++			    # ld searches for highest libc.so.* and so do we
++			    libc=`(ls /usr/lib/libc.so.* /lib/libc.so.* | tail -1) 2>/dev/null`
++			fi
++			case "`(file -L $libc) 2>/dev/null`" in
++			*ELF*)	OUT="BSD-x86-elf" ;;
++			*)	OUT="BSD-x86"; options="$options no-sse2" ;;
++			esac ;;
++  *-*-*bsd*)		OUT="BSD-generic32" ;;
++
++  x86_64-*-haiku)	OUT="haiku-x86_64" ;;
++  *-*-haiku)		OUT="haiku-x86" ;;
++
++  *-*-osf)		OUT="osf1-alpha-cc" ;;
++  *-*-tru64)		OUT="tru64-alpha-cc" ;;
++  *-*-[Uu]nix[Ww]are7)
++	if [ "$CC" = "gcc" ]; then
++	  OUT="unixware-7-gcc" ; options="$options no-sse2"
++	else    
++	  OUT="unixware-7" ; options="$options no-sse2 -D__i386__"
++	fi
++	;;
++  *-*-[Uu]nix[Ww]are20*) OUT="unixware-2.0"; options="$options no-sse2 no-sha512" ;;
++  *-*-[Uu]nix[Ww]are21*) OUT="unixware-2.1"; options="$options no-sse2 no-sha512" ;;
++  *-*-vos)
++	options="$options no-threads no-shared no-asm no-dso"
++	EXE=".pm"
++	OUT="vos-$CC" ;;
++  BS2000-siemens-sysv4) OUT="BS2000-OSD" ;;
++  *-hpux1*)
++	if [ $CC = "gcc" -a $GCC_BITS = "64" ]; then
++	    OUT="hpux64-parisc2-gcc"
++	fi
++	[ "$KERNEL_BITS" ] || KERNEL_BITS=`(getconf KERNEL_BITS) 2>/dev/null`
++	KERNEL_BITS=${KERNEL_BITS:-32}
++	CPU_VERSION=`(getconf CPU_VERSION) 2>/dev/null`
++	CPU_VERSION=${CPU_VERSION:-0}
++	# See  for further info on CPU_VERSION.
++	if   [ $CPU_VERSION -ge 768 ]; then	# IA-64 CPU
++	     if [ $KERNEL_BITS -eq 64 -a "$CC" = "cc" ]; then
++	        OUT="hpux64-ia64-cc"
++             else
++	        OUT="hpux-ia64-cc"
++             fi
++	elif [ $CPU_VERSION -ge 532 ]; then	# PA-RISC 2.x CPU
++	     OUT=${OUT:-"hpux-parisc2-${CC}"}
++	     if [ $KERNEL_BITS -eq 64 -a "$CC" = "cc" ]; then
++		echo "WARNING! If you wish to build 64-bit library then you have to"
++		echo "         invoke '$THERE/Configure hpux64-parisc2-cc' *manually*."
++		if [ "$DRYRUN" = "false" -a -t 1 ]; then
++		  echo "         You have about 5 seconds to press Ctrl-C to abort."
++		  (trap "stty `stty -g`; exit 0" 2 0; stty -icanon min 0 time 50; read waste) <&1
++		fi
++	     fi
++	     # PA-RISC 2.0 is no longer supported as separate 32-bit
++	     # target. This is compensated for by run-time detection
++	     # in most critical assembly modules and taking advantage
++	     # of 2.0 architecture in PA-RISC 1.1 build.
++	     OUT="hpux-parisc1_1-${CC}"
++	elif [ $CPU_VERSION -ge 528 ]; then	# PA-RISC 1.1+ CPU
++	     OUT="hpux-parisc1_1-${CC}"
++	elif [ $CPU_VERSION -ge 523 ]; then	# PA-RISC 1.0 CPU
++	     OUT="hpux-parisc-${CC}"
++	else					# Motorola(?) CPU
++	     OUT="hpux-$CC"
++	fi
++	options="$options -D_REENTRANT" ;;
++  *-hpux)	OUT="hpux-parisc-$CC" ;;
++  *-aix)
++	[ "$KERNEL_BITS" ] || KERNEL_BITS=`(getconf KERNEL_BITMODE) 2>/dev/null`
++	KERNEL_BITS=${KERNEL_BITS:-32}
++	OBJECT_MODE=${OBJECT_MODE:-32}
++	if [ "$CC" = "gcc" ]; then
++	    OUT="aix-gcc"
++          if [ $OBJECT_MODE -eq 64 ]; then
++            echo 'Your $OBJECT_MODE was found to be set to 64'
++            OUT="aix64-gcc"
++          fi
++	elif [ $OBJECT_MODE -eq 64 ]; then
++	    echo 'Your $OBJECT_MODE was found to be set to 64' 
++	    OUT="aix64-cc"
++	else
++	    OUT="aix-cc"
++	    if [ $KERNEL_BITS -eq 64 ]; then
++		echo "WARNING! If you wish to build 64-bit kit, then you have to"
++		echo "         invoke '$THERE/Configure aix64-cc' *manually*."
++		if [ "$DRYRUN" = "false" -a -t 1 ]; then
++		    echo "         You have ~5 seconds to press Ctrl-C to abort."
++		    (trap "stty `stty -g`; exit 0" 2 0; stty -icanon min 0 time 50; read waste) <&1
++		fi
++	    fi
++	fi
++	if (lsattr -E -O -l `lsdev -c processor|awk '{print$1;exit}'` | grep -i powerpc) >/dev/null 2>&1; then
++	    :	# this applies even to Power3 and later, as they return PowerPC_POWER[345]
++	else
++	    options="$options no-asm"
++	fi
++	;;
++  # these are all covered by the catchall below
++  i[3456]86-*-cygwin) OUT="Cygwin-x86" ;;
++  *-*-cygwin) OUT="Cygwin-${MACHINE}" ;;
++  x86pc-*-qnx6) OUT="QNX6-i386" ;;
++  *-*-qnx6) OUT="QNX6" ;;
++  x86-*-android|i?86-*-android) OUT="android-x86" ;;
++  armv[7-9]*-*-android)
++      OUT="android-armeabi"; options="$options -march=armv7-a" ;;
++  arm*-*-android) OUT="android-armeabi" ;;
++  *) OUT=`echo $GUESSOS | awk -F- '{print $3}'`;;
++esac
++
++# NB: This atalla support has been superseded by the ENGINE support
++# That contains its own header and definitions anyway. Support can
++# be enabled or disabled on any supported platform without external
++# headers, eg. by adding the "hw-atalla" switch to ./config or
++# perl Configure
++#
++# See whether we can compile Atalla support
++#if [ -f /usr/include/atasi.h ]
++#then
++#  options="$options -DATALLA"
++#fi
++
++if [ -n "$CONFIG_OPTIONS" ]; then
++  options="$options $CONFIG_OPTIONS"
++fi
++
++if expr "$options" : '.*no\-asm' > /dev/null; then :; else
++  sh -c "$CROSS_COMPILE${CC:-gcc} -Wa,--help -c -o /tmp/null.$$.o -x assembler /dev/null && rm /tmp/null.$$.o" 2>&1 | \
++  grep \\--noexecstack >/dev/null && \
++  options="$options -Wa,--noexecstack"
++fi
++
++# gcc < 2.8 does not support -march=ultrasparc
++if [ "$OUT" = solaris-sparcv9-gcc -a $GCCVER -lt 28 ]
++then
++  echo "WARNING! Falling down to 'solaris-sparcv8-gcc'."
++  echo "         Upgrade to gcc-2.8 or later."
++  sleep 5
++  OUT=solaris-sparcv8-gcc
++fi
++if [ "$OUT" = "linux-sparcv9" -a $GCCVER -lt 28 ]
++then
++  echo "WARNING! Falling down to 'linux-sparcv8'."
++  echo "         Upgrade to gcc-2.8 or later."
++  sleep 5
++  OUT=linux-sparcv8
++fi
++
++case "$GUESSOS" in
++  i386-*) options="$options 386" ;;
++esac
++
++for i in aes bf camellia cast des dh dsa ec hmac idea md2 md5 mdc2 rc2 rc4 rc5 ripemd rsa seed sha
++do
++  if [ ! -d $THERE/crypto/$i ]
++  then
++    options="$options no-$i"
++  fi
++done
++
++if [ -z "$OUT" ]; then
++  OUT="$CC"
++fi
++
++if [ ".$PERL" = . ] ; then
++	for i in . `echo $PATH | sed 's/:/ /g'`; do
++		if [ -f "$i/perl5$EXE" ] ; then
++			PERL="$i/perl5$EXE"
++			break;
++		fi;
++	done
++fi
++
++if [ ".$PERL" = . ] ; then
++	for i in . `echo $PATH | sed 's/:/ /g'`; do
++		if [ -f "$i/perl$EXE" ] ; then
++			if "$i/perl$EXE" -e 'exit($]<5.0)'; then
++				PERL="$i/perl$EXE"
++				break;
++			fi;
++		fi;
++	done
++fi
++
++if [ ".$PERL" = . ] ; then
++	echo "You need Perl 5."
++	exit 1
++fi
++
++# run Configure to check to see if we need to specify the 
++# compiler for the platform ... in which case we add it on
++# the end ... otherwise we leave it off
++
++$PERL $THERE/Configure LIST | grep "$OUT-$CC" > /dev/null
++if [ $? = "0" ]; then
++  OUT="$OUT-$CC"
++fi
++
++OUT="$OUT"
++
++$PERL $THERE/Configure LIST | grep "$OUT" > /dev/null
++if [ $? = "0" ]; then
++  echo Configuring for $OUT
++
++  if [ "$VERBOSE" = "true" ]; then
++    echo $PERL $THERE/Configure $OUT $options
++  fi  
++  if [ "$DRYRUN" = "false" ]; then
++    $PERL $THERE/Configure $OUT $options
++  fi
++else
++  echo "This system ($OUT) is not supported. See file INSTALL for details."
++fi
++)
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/config.com b/CryptoPkg/Library/OpensslLib/openssl/config.com
+new file mode 100644
+index 0000000..5b54995
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/config.com
+@@ -0,0 +1,93 @@
++$	! OpenSSL config: determine the architecture and run Configure
++$	! Copyright 2016 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 in the file LICENSE in the source distribution or at
++$	! https://www.openssl.org/source/license.html
++$	!
++$	! Very simple for the moment, it will take the following arguments:
++$	!
++$	! -32 or 32	sets /POINTER_SIZE=32
++$	! -64 or 64	sets /POINTER_SIZE=64
++$	! -d		sets debugging
++$	! -h		prints a usage and exits
++$	! -t		test mode, doesn't run Configure
++$
++$	arch = f$edit( f$getsyi( "arch_name"), "lowercase")
++$	pointer_size = ""
++$	dryrun = 0
++$	verbose = 0
++$	here = F$PARSE("A.;",F$ENVIRONMENT("PROCEDURE"),,,"SYNTAX_ONLY") - "A.;"
++$
++$	collected_args = ""
++$	P_index = 0
++$	LOOP1:
++$	    P_index = P_index + 1
++$	    IF P_index .GT. 8 THEN GOTO ENDLOOP1
++$	    P = F$EDIT(P1,"TRIM,LOWERCASE")
++$	    IF P .EQS. "-h"
++$           THEN
++$               dryrun = 1
++$               P = ""
++$               TYPE SYS$INPUT
++$               DECK
++Usage: @config [options]
++
++  -32 or 32	Build with 32-bit pointer size.
++  -64 or 64	Build with 64-bit pointer size.
++  -d		Build with debugging.
++  -t            Test mode, do not run the Configure perl script.
++  -v            Verbose mode, show the exact Configure call that is being made.
++  -h		This help.
++
++Any other text will be passed to the Configure perl script.
++See INSTALL for instructions.
++
++$               EOD
++$           ENDIF
++$	    IF P .EQS. "-t"
++$	    THEN
++$		dryrun = 1
++$		verbose = 1
++$		P = ""
++$	    ENDIF
++$	    IF P .EQS. "-v"
++$	    THEN
++$		verbose = 1
++$		P = ""
++$	    ENDIF
++$	    IF P .EQS. "-32" .OR. P .EQS. "32"
++$	    THEN
++$		pointer_size = "-P32"
++$		P = ""
++$	    ENDIF
++$	    IF P .EQS. "-64" .OR. P .EQS. "64"
++$	    THEN
++$		pointer_size = "-P64"
++$		P = ""
++$	    ENDIF
++$	    IF P .EQS. "-d"
++$	    THEN
++$               collected_args = collected_args + " --debug"
++$		P = ""
++$	    ENDIF
++$	    IF P .NES. "" THEN -
++	       collected_args = collected_args + " " + P1
++$	    P1 = P2
++$	    P2 = P3
++$	    P3 = P4
++$	    P4 = P5
++$	    P5 = P6
++$	    P6 = P7
++$	    P7 = P8
++$	    P8 = ""
++$	    GOTO LOOP1
++$	ENDLOOP1:
++$
++$	target = "vms-''arch'''pointer_size'"
++$       IF verbose THEN -
++           WRITE SYS$OUTPUT "PERL ''here'Configure ""''target'""''collected_args'"
++$       IF .not. dryrun THEN -
++           PERL 'here'Configure "''target'" 'debug' 'collected_args'
++$       EXIT $STATUS
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/LPdir_nyi.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/LPdir_nyi.c
+new file mode 100644
+index 0000000..049044c
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/LPdir_nyi.c
+@@ -0,0 +1,53 @@
++/*
++ * Copyright 2004-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++/*
++ * Copyright (c) 2004, Richard Levitte 
++ * 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.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
++ * ANY EXPRESS 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 REGENTS OR 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.
++ */
++
++#ifndef LPDIR_H
++# include "LPdir.h"
++#endif
++
++struct LP_dir_context_st {
++    void *dummy;
++};
++const char *LP_find_file(LP_DIR_CTX **ctx, const char *directory)
++{
++    errno = EINVAL;
++    return 0;
++}
++
++int LP_find_file_end(LP_DIR_CTX **ctx)
++{
++    errno = EINVAL;
++    return 0;
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/LPdir_unix.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/LPdir_unix.c
+new file mode 100644
+index 0000000..1bb2940
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/LPdir_unix.c
+@@ -0,0 +1,131 @@
++/*
++ * Copyright 2004-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++/*
++ * Copyright (c) 2004, Richard Levitte 
++ * 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.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
++ * ``AS IS'' AND ANY EXPRESS 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 COPYRIGHT
++ * OWNER OR 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.
++ */
++
++#include 
++#include 
++#include 
++#include 
++#include 
++#include 
++#include 
++#ifndef LPDIR_H
++# include "LPdir.h"
++#endif
++
++/*
++ * The POSIXly macro for the maximum number of characters in a file path is
++ * NAME_MAX.  However, some operating systems use PATH_MAX instead.
++ * Therefore, it seems natural to first check for PATH_MAX and use that, and
++ * if it doesn't exist, use NAME_MAX.
++ */
++#if defined(PATH_MAX)
++# define LP_ENTRY_SIZE PATH_MAX
++#elif defined(NAME_MAX)
++# define LP_ENTRY_SIZE NAME_MAX
++#endif
++
++/*
++ * Of course, there's the possibility that neither PATH_MAX nor NAME_MAX
++ * exist.  It's also possible that NAME_MAX exists but is define to a very
++ * small value (HP-UX offers 14), so we need to check if we got a result, and
++ * if it meets a minimum standard, and create or change it if not.
++ */
++#if !defined(LP_ENTRY_SIZE) || LP_ENTRY_SIZE<255
++# undef LP_ENTRY_SIZE
++# define LP_ENTRY_SIZE 255
++#endif
++
++struct LP_dir_context_st {
++    DIR *dir;
++    char entry_name[LP_ENTRY_SIZE + 1];
++};
++
++const char *LP_find_file(LP_DIR_CTX **ctx, const char *directory)
++{
++    struct dirent *direntry = NULL;
++
++    if (ctx == NULL || directory == NULL) {
++        errno = EINVAL;
++        return 0;
++    }
++
++    errno = 0;
++    if (*ctx == NULL) {
++        *ctx = malloc(sizeof(**ctx));
++        if (*ctx == NULL) {
++            errno = ENOMEM;
++            return 0;
++        }
++        memset(*ctx, 0, sizeof(**ctx));
++
++        (*ctx)->dir = opendir(directory);
++        if ((*ctx)->dir == NULL) {
++            int save_errno = errno; /* Probably not needed, but I'm paranoid */
++            free(*ctx);
++            *ctx = NULL;
++            errno = save_errno;
++            return 0;
++        }
++    }
++
++    direntry = readdir((*ctx)->dir);
++    if (direntry == NULL) {
++        return 0;
++    }
++
++    strncpy((*ctx)->entry_name, direntry->d_name,
++            sizeof((*ctx)->entry_name) - 1);
++    (*ctx)->entry_name[sizeof((*ctx)->entry_name) - 1] = '\0';
++    return (*ctx)->entry_name;
++}
++
++int LP_find_file_end(LP_DIR_CTX **ctx)
++{
++    if (ctx != NULL && *ctx != NULL) {
++        int ret = closedir((*ctx)->dir);
++
++        free(*ctx);
++        switch (ret) {
++        case 0:
++            return 1;
++        case -1:
++            return 0;
++        default:
++            break;
++        }
++    }
++    errno = EINVAL;
++    return 0;
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/LPdir_vms.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/LPdir_vms.c
+new file mode 100644
+index 0000000..1a5b60f
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/LPdir_vms.c
+@@ -0,0 +1,204 @@
++/*
++ * Copyright 2004-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++/*
++ * Copyright (c) 2004, Richard Levitte 
++ * 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.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
++ * ``AS IS'' AND ANY EXPRESS 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 COPYRIGHT
++ * OWNER OR 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.
++ */
++
++#include 
++#include 
++#include 
++#include 
++#include 
++#include 
++#include 
++#include 
++#include 
++#include 
++#include 
++#include 
++#ifndef LPDIR_H
++# include "LPdir.h"
++#endif
++#include "vms_rms.h"
++
++/* Some compiler options hide EVMSERR. */
++#ifndef EVMSERR
++# define EVMSERR        65535   /* error for non-translatable VMS errors */
++#endif
++
++struct LP_dir_context_st {
++    unsigned long VMS_context;
++    char filespec[NAMX_MAXRSS + 1];
++    char result[NAMX_MAXRSS + 1];
++    struct dsc$descriptor_d filespec_dsc;
++    struct dsc$descriptor_d result_dsc;
++};
++
++const char *LP_find_file(LP_DIR_CTX **ctx, const char *directory)
++{
++    int status;
++    char *p, *r;
++    size_t l;
++    unsigned long flags = 0;
++
++/* Arrange 32-bit pointer to (copied) string storage, if needed. */
++#if __INITIAL_POINTER_SIZE == 64
++# pragma pointer_size save
++# pragma pointer_size 32
++    char *ctx_filespec_32p;
++# pragma pointer_size restore
++    char ctx_filespec_32[NAMX_MAXRSS + 1];
++#endif                          /* __INITIAL_POINTER_SIZE == 64 */
++
++#ifdef NAML$C_MAXRSS
++    flags |= LIB$M_FIL_LONG_NAMES;
++#endif
++
++    if (ctx == NULL || directory == NULL) {
++        errno = EINVAL;
++        return 0;
++    }
++
++    errno = 0;
++    if (*ctx == NULL) {
++        size_t filespeclen = strlen(directory);
++        char *filespec = NULL;
++
++        if (filespeclen == 0) {
++            errno = ENOENT;
++            return 0;
++        }
++
++        /* MUST be a VMS directory specification!  Let's estimate if it is. */
++        if (directory[filespeclen - 1] != ']'
++            && directory[filespeclen - 1] != '>'
++            && directory[filespeclen - 1] != ':') {
++            errno = EINVAL;
++            return 0;
++        }
++
++        filespeclen += 4;       /* "*.*;" */
++
++        if (filespeclen > NAMX_MAXRSS) {
++            errno = ENAMETOOLONG;
++            return 0;
++        }
++
++        *ctx = malloc(sizeof(**ctx));
++        if (*ctx == NULL) {
++            errno = ENOMEM;
++            return 0;
++        }
++        memset(*ctx, 0, sizeof(**ctx));
++
++        strcpy((*ctx)->filespec, directory);
++        strcat((*ctx)->filespec, "*.*;");
++
++/* Arrange 32-bit pointer to (copied) string storage, if needed. */
++#if __INITIAL_POINTER_SIZE == 64
++# define CTX_FILESPEC ctx_filespec_32p
++        /* Copy the file name to storage with a 32-bit pointer. */
++        ctx_filespec_32p = ctx_filespec_32;
++        strcpy(ctx_filespec_32p, (*ctx)->filespec);
++#else                           /* __INITIAL_POINTER_SIZE == 64 */
++# define CTX_FILESPEC (*ctx)->filespec
++#endif                          /* __INITIAL_POINTER_SIZE == 64 [else] */
++
++        (*ctx)->filespec_dsc.dsc$w_length = filespeclen;
++        (*ctx)->filespec_dsc.dsc$b_dtype = DSC$K_DTYPE_T;
++        (*ctx)->filespec_dsc.dsc$b_class = DSC$K_CLASS_S;
++        (*ctx)->filespec_dsc.dsc$a_pointer = CTX_FILESPEC;
++    }
++
++    (*ctx)->result_dsc.dsc$w_length = 0;
++    (*ctx)->result_dsc.dsc$b_dtype = DSC$K_DTYPE_T;
++    (*ctx)->result_dsc.dsc$b_class = DSC$K_CLASS_D;
++    (*ctx)->result_dsc.dsc$a_pointer = 0;
++
++    status = lib$find_file(&(*ctx)->filespec_dsc, &(*ctx)->result_dsc,
++                           &(*ctx)->VMS_context, 0, 0, 0, &flags);
++
++    if (status == RMS$_NMF) {
++        errno = 0;
++        vaxc$errno = status;
++        return NULL;
++    }
++
++    if (!$VMS_STATUS_SUCCESS(status)) {
++        errno = EVMSERR;
++        vaxc$errno = status;
++        return NULL;
++    }
++
++    /*
++     * Quick, cheap and dirty way to discard any device and directory, since
++     * we only want file names
++     */
++    l = (*ctx)->result_dsc.dsc$w_length;
++    p = (*ctx)->result_dsc.dsc$a_pointer;
++    r = p;
++    for (; *p; p++) {
++        if (*p == '^' && p[1] != '\0') { /* Take care of ODS-5 escapes */
++            p++;
++        } else if (*p == ':' || *p == '>' || *p == ']') {
++            l -= p + 1 - r;
++            r = p + 1;
++        } else if (*p == ';') {
++            l = p - r;
++            break;
++        }
++    }
++
++    strncpy((*ctx)->result, r, l);
++    (*ctx)->result[l] = '\0';
++    str$free1_dx(&(*ctx)->result_dsc);
++
++    return (*ctx)->result;
++}
++
++int LP_find_file_end(LP_DIR_CTX **ctx)
++{
++    if (ctx != NULL && *ctx != NULL) {
++        int status = lib$find_file_end(&(*ctx)->VMS_context);
++
++        free(*ctx);
++
++        if (!$VMS_STATUS_SUCCESS(status)) {
++            errno = EVMSERR;
++            vaxc$errno = status;
++            return 0;
++        }
++        return 1;
++    }
++    errno = EINVAL;
++    return 0;
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/LPdir_win.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/LPdir_win.c
+new file mode 100644
+index 0000000..8f674d3
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/LPdir_win.c
+@@ -0,0 +1,211 @@
++/*
++ * Copyright 2004-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++/*
++ * Copyright (c) 2004, Richard Levitte 
++ * 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.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
++ * ``AS IS'' AND ANY EXPRESS 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 COPYRIGHT
++ * OWNER OR 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.
++ */
++
++#include 
++#include 
++#include "internal/numbers.h"
++#ifndef LPDIR_H
++# include "LPdir.h"
++#endif
++
++/*
++ * We're most likely overcautious here, but let's reserve for broken WinCE
++ * headers and explicitly opt for UNICODE call. Keep in mind that our WinCE
++ * builds are compiled with -DUNICODE [as well as -D_UNICODE].
++ */
++#if defined(LP_SYS_WINCE) && !defined(FindFirstFile)
++# define FindFirstFile FindFirstFileW
++#endif
++#if defined(LP_SYS_WINCE) && !defined(FindNextFile)
++# define FindNextFile FindNextFileW
++#endif
++
++#ifndef NAME_MAX
++# define NAME_MAX 255
++#endif
++
++#ifdef CP_UTF8
++# define CP_DEFAULT CP_UTF8
++#else
++# define CP_DEFAULT CP_ACP
++#endif
++
++struct LP_dir_context_st {
++    WIN32_FIND_DATA ctx;
++    HANDLE handle;
++    char entry_name[NAME_MAX + 1];
++};
++
++const char *LP_find_file(LP_DIR_CTX **ctx, const char *directory)
++{
++    if (ctx == NULL || directory == NULL) {
++        errno = EINVAL;
++        return 0;
++    }
++
++    errno = 0;
++    if (*ctx == NULL) {
++        size_t dirlen = strlen(directory);
++
++        if (dirlen == 0 || dirlen > INT_MAX - 3) {
++            errno = ENOENT;
++            return 0;
++        }
++
++        *ctx = malloc(sizeof(**ctx));
++        if (*ctx == NULL) {
++            errno = ENOMEM;
++            return 0;
++        }
++        memset(*ctx, 0, sizeof(**ctx));
++
++        if (sizeof(TCHAR) != sizeof(char)) {
++            TCHAR *wdir = NULL;
++            /* len_0 denotes string length *with* trailing 0 */
++            size_t index = 0, len_0 = dirlen + 1;
++#ifdef LP_MULTIBYTE_AVAILABLE
++            int sz = 0;
++            UINT cp;
++
++            do {
++# ifdef CP_UTF8
++                if ((sz = MultiByteToWideChar((cp = CP_UTF8), 0,
++                                              directory, len_0,
++                                              NULL, 0)) > 0 ||
++                    GetLastError() != ERROR_NO_UNICODE_TRANSLATION)
++                    break;
++# endif
++                sz = MultiByteToWideChar((cp = CP_ACP), 0,
++                                         directory, len_0,
++                                         NULL, 0);
++            } while (0);
++
++            if (sz > 0) {
++                /*
++                 * allocate two additional characters in case we need to
++                 * concatenate asterisk, |sz| covers trailing '\0'!
++                 */
++                wdir = _alloca((sz + 2) * sizeof(TCHAR));
++                if (!MultiByteToWideChar(cp, 0, directory, len_0,
++                                         (WCHAR *)wdir, sz)) {
++                    free(*ctx);
++                    *ctx = NULL;
++                    errno = EINVAL;
++                    return 0;
++                }
++            } else
++#endif
++            {
++                sz = len_0;
++                /*
++                 * allocate two additional characters in case we need to
++                 * concatenate asterisk, |sz| covers trailing '\0'!
++                 */
++                wdir = _alloca((sz + 2) * sizeof(TCHAR));
++                for (index = 0; index < len_0; index++)
++                    wdir[index] = (TCHAR)directory[index];
++            }
++
++            sz--; /* wdir[sz] is trailing '\0' now */
++            if (wdir[sz - 1] != TEXT('*')) {
++                if (wdir[sz - 1] != TEXT('/') && wdir[sz - 1] != TEXT('\\'))
++                    _tcscpy(wdir + sz, TEXT("/*"));
++                else
++                    _tcscpy(wdir + sz, TEXT("*"));
++            }
++
++            (*ctx)->handle = FindFirstFile(wdir, &(*ctx)->ctx);
++        } else {
++            if (directory[dirlen - 1] != '*') {
++                char *buf = _alloca(dirlen + 3);
++
++                strcpy(buf, directory);
++                if (buf[dirlen - 1] != '/' && buf[dirlen - 1] != '\\')
++                    strcpy(buf + dirlen, "/*");
++                else
++                    strcpy(buf + dirlen, "*");
++
++                directory = buf;
++            }
++
++            (*ctx)->handle = FindFirstFile((TCHAR *)directory, &(*ctx)->ctx);
++        }
++
++        if ((*ctx)->handle == INVALID_HANDLE_VALUE) {
++            free(*ctx);
++            *ctx = NULL;
++            errno = EINVAL;
++            return 0;
++        }
++    } else {
++        if (FindNextFile((*ctx)->handle, &(*ctx)->ctx) == FALSE) {
++            return 0;
++        }
++    }
++    if (sizeof(TCHAR) != sizeof(char)) {
++        TCHAR *wdir = (*ctx)->ctx.cFileName;
++        size_t index, len_0 = 0;
++
++        while (wdir[len_0] && len_0 < (sizeof((*ctx)->entry_name) - 1))
++            len_0++;
++        len_0++;
++
++#ifdef LP_MULTIBYTE_AVAILABLE
++        if (!WideCharToMultiByte(CP_DEFAULT, 0, (WCHAR *)wdir, len_0,
++                                 (*ctx)->entry_name,
++                                 sizeof((*ctx)->entry_name), NULL, 0))
++#endif
++            for (index = 0; index < len_0; index++)
++                (*ctx)->entry_name[index] = (char)wdir[index];
++    } else
++        strncpy((*ctx)->entry_name, (const char *)(*ctx)->ctx.cFileName,
++                sizeof((*ctx)->entry_name) - 1);
++
++    (*ctx)->entry_name[sizeof((*ctx)->entry_name) - 1] = '\0';
++
++    return (*ctx)->entry_name;
++}
++
++int LP_find_file_end(LP_DIR_CTX **ctx)
++{
++    if (ctx != NULL && *ctx != NULL) {
++        FindClose((*ctx)->handle);
++        free(*ctx);
++        *ctx = NULL;
++        return 1;
++    }
++    errno = EINVAL;
++    return 0;
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/LPdir_win32.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/LPdir_win32.c
+new file mode 100644
+index 0000000..59ed485
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/LPdir_win32.c
+@@ -0,0 +1,38 @@
++/*
++ * Copyright 2004-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++/*
++ * Copyright (c) 2004, Richard Levitte 
++ * 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.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
++ * ``AS IS'' AND ANY EXPRESS 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 COPYRIGHT
++ * OWNER OR 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.
++ */
++
++#define LP_SYS_WIN32
++#define LP_MULTIBYTE_AVAILABLE
++#include "LPdir_win.c"
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/LPdir_wince.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/LPdir_wince.c
+new file mode 100644
+index 0000000..dbc1052
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/LPdir_wince.c
+@@ -0,0 +1,41 @@
++/*
++ * Copyright 2004-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++/*
++ * Copyright (c) 2004, Richard Levitte 
++ * 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.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
++ * ``AS IS'' AND ANY EXPRESS 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 COPYRIGHT
++ * OWNER OR 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.
++ */
++
++#define LP_SYS_WINCE
++/*
++ * We might want to define LP_MULTIBYTE_AVAILABLE here.  It's currently under
++ * investigation what the exact conditions would be
++ */
++#include "LPdir_win.c"
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/aes/aes_cbc.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/aes/aes_cbc.c
+new file mode 100644
+index 0000000..342841f
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/aes/aes_cbc.c
+@@ -0,0 +1,24 @@
++/*
++ * Copyright 2002-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include 
++
++void AES_cbc_encrypt(const unsigned char *in, unsigned char *out,
++                     size_t len, const AES_KEY *key,
++                     unsigned char *ivec, const int enc)
++{
++
++    if (enc)
++        CRYPTO_cbc128_encrypt(in, out, len, key, ivec,
++                              (block128_f) AES_encrypt);
++    else
++        CRYPTO_cbc128_decrypt(in, out, len, key, ivec,
++                              (block128_f) AES_decrypt);
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/aes/aes_cfb.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/aes/aes_cfb.c
+new file mode 100644
+index 0000000..f010e3c
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/aes/aes_cfb.c
+@@ -0,0 +1,43 @@
++/*
++ * Copyright 2002-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include 
++
++/*
++ * The input and output encrypted as though 128bit cfb mode is being used.
++ * The extra state information to record how much of the 128bit block we have
++ * used is contained in *num;
++ */
++
++void AES_cfb128_encrypt(const unsigned char *in, unsigned char *out,
++                        size_t length, const AES_KEY *key,
++                        unsigned char *ivec, int *num, const int enc)
++{
++
++    CRYPTO_cfb128_encrypt(in, out, length, key, ivec, num, enc,
++                          (block128_f) AES_encrypt);
++}
++
++/* N.B. This expects the input to be packed, MS bit first */
++void AES_cfb1_encrypt(const unsigned char *in, unsigned char *out,
++                      size_t length, const AES_KEY *key,
++                      unsigned char *ivec, int *num, const int enc)
++{
++    CRYPTO_cfb128_1_encrypt(in, out, length, key, ivec, num, enc,
++                            (block128_f) AES_encrypt);
++}
++
++void AES_cfb8_encrypt(const unsigned char *in, unsigned char *out,
++                      size_t length, const AES_KEY *key,
++                      unsigned char *ivec, int *num, const int enc)
++{
++    CRYPTO_cfb128_8_encrypt(in, out, length, key, ivec, num, enc,
++                            (block128_f) AES_encrypt);
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/aes/aes_core.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/aes/aes_core.c
+new file mode 100644
+index 0000000..bd5c779
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/aes/aes_core.c
+@@ -0,0 +1,1367 @@
++/*
++ * Copyright 2002-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++/**
++ * rijndael-alg-fst.c
++ *
++ * @version 3.0 (December 2000)
++ *
++ * Optimised ANSI C code for the Rijndael cipher (now AES)
++ *
++ * @author Vincent Rijmen 
++ * @author Antoon Bosselaers 
++ * @author Paulo Barreto 
++ *
++ * This code is hereby placed in the public domain.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ''AS IS'' AND ANY EXPRESS
++ * 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 AUTHORS OR 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.
++ */
++
++/* Note: rewritten a little bit to provide error control and an OpenSSL-
++   compatible API */
++
++#include 
++
++#include 
++#include 
++#include 
++#include "aes_locl.h"
++
++#ifndef AES_ASM
++/*-
++Te0[x] = S [x].[02, 01, 01, 03];
++Te1[x] = S [x].[03, 02, 01, 01];
++Te2[x] = S [x].[01, 03, 02, 01];
++Te3[x] = S [x].[01, 01, 03, 02];
++
++Td0[x] = Si[x].[0e, 09, 0d, 0b];
++Td1[x] = Si[x].[0b, 0e, 09, 0d];
++Td2[x] = Si[x].[0d, 0b, 0e, 09];
++Td3[x] = Si[x].[09, 0d, 0b, 0e];
++Td4[x] = Si[x].[01];
++*/
++
++static const u32 Te0[256] = {
++    0xc66363a5U, 0xf87c7c84U, 0xee777799U, 0xf67b7b8dU,
++    0xfff2f20dU, 0xd66b6bbdU, 0xde6f6fb1U, 0x91c5c554U,
++    0x60303050U, 0x02010103U, 0xce6767a9U, 0x562b2b7dU,
++    0xe7fefe19U, 0xb5d7d762U, 0x4dababe6U, 0xec76769aU,
++    0x8fcaca45U, 0x1f82829dU, 0x89c9c940U, 0xfa7d7d87U,
++    0xeffafa15U, 0xb25959ebU, 0x8e4747c9U, 0xfbf0f00bU,
++    0x41adadecU, 0xb3d4d467U, 0x5fa2a2fdU, 0x45afafeaU,
++    0x239c9cbfU, 0x53a4a4f7U, 0xe4727296U, 0x9bc0c05bU,
++    0x75b7b7c2U, 0xe1fdfd1cU, 0x3d9393aeU, 0x4c26266aU,
++    0x6c36365aU, 0x7e3f3f41U, 0xf5f7f702U, 0x83cccc4fU,
++    0x6834345cU, 0x51a5a5f4U, 0xd1e5e534U, 0xf9f1f108U,
++    0xe2717193U, 0xabd8d873U, 0x62313153U, 0x2a15153fU,
++    0x0804040cU, 0x95c7c752U, 0x46232365U, 0x9dc3c35eU,
++    0x30181828U, 0x379696a1U, 0x0a05050fU, 0x2f9a9ab5U,
++    0x0e070709U, 0x24121236U, 0x1b80809bU, 0xdfe2e23dU,
++    0xcdebeb26U, 0x4e272769U, 0x7fb2b2cdU, 0xea75759fU,
++    0x1209091bU, 0x1d83839eU, 0x582c2c74U, 0x341a1a2eU,
++    0x361b1b2dU, 0xdc6e6eb2U, 0xb45a5aeeU, 0x5ba0a0fbU,
++    0xa45252f6U, 0x763b3b4dU, 0xb7d6d661U, 0x7db3b3ceU,
++    0x5229297bU, 0xdde3e33eU, 0x5e2f2f71U, 0x13848497U,
++    0xa65353f5U, 0xb9d1d168U, 0x00000000U, 0xc1eded2cU,
++    0x40202060U, 0xe3fcfc1fU, 0x79b1b1c8U, 0xb65b5bedU,
++    0xd46a6abeU, 0x8dcbcb46U, 0x67bebed9U, 0x7239394bU,
++    0x944a4adeU, 0x984c4cd4U, 0xb05858e8U, 0x85cfcf4aU,
++    0xbbd0d06bU, 0xc5efef2aU, 0x4faaaae5U, 0xedfbfb16U,
++    0x864343c5U, 0x9a4d4dd7U, 0x66333355U, 0x11858594U,
++    0x8a4545cfU, 0xe9f9f910U, 0x04020206U, 0xfe7f7f81U,
++    0xa05050f0U, 0x783c3c44U, 0x259f9fbaU, 0x4ba8a8e3U,
++    0xa25151f3U, 0x5da3a3feU, 0x804040c0U, 0x058f8f8aU,
++    0x3f9292adU, 0x219d9dbcU, 0x70383848U, 0xf1f5f504U,
++    0x63bcbcdfU, 0x77b6b6c1U, 0xafdada75U, 0x42212163U,
++    0x20101030U, 0xe5ffff1aU, 0xfdf3f30eU, 0xbfd2d26dU,
++    0x81cdcd4cU, 0x180c0c14U, 0x26131335U, 0xc3ecec2fU,
++    0xbe5f5fe1U, 0x359797a2U, 0x884444ccU, 0x2e171739U,
++    0x93c4c457U, 0x55a7a7f2U, 0xfc7e7e82U, 0x7a3d3d47U,
++    0xc86464acU, 0xba5d5de7U, 0x3219192bU, 0xe6737395U,
++    0xc06060a0U, 0x19818198U, 0x9e4f4fd1U, 0xa3dcdc7fU,
++    0x44222266U, 0x542a2a7eU, 0x3b9090abU, 0x0b888883U,
++    0x8c4646caU, 0xc7eeee29U, 0x6bb8b8d3U, 0x2814143cU,
++    0xa7dede79U, 0xbc5e5ee2U, 0x160b0b1dU, 0xaddbdb76U,
++    0xdbe0e03bU, 0x64323256U, 0x743a3a4eU, 0x140a0a1eU,
++    0x924949dbU, 0x0c06060aU, 0x4824246cU, 0xb85c5ce4U,
++    0x9fc2c25dU, 0xbdd3d36eU, 0x43acacefU, 0xc46262a6U,
++    0x399191a8U, 0x319595a4U, 0xd3e4e437U, 0xf279798bU,
++    0xd5e7e732U, 0x8bc8c843U, 0x6e373759U, 0xda6d6db7U,
++    0x018d8d8cU, 0xb1d5d564U, 0x9c4e4ed2U, 0x49a9a9e0U,
++    0xd86c6cb4U, 0xac5656faU, 0xf3f4f407U, 0xcfeaea25U,
++    0xca6565afU, 0xf47a7a8eU, 0x47aeaee9U, 0x10080818U,
++    0x6fbabad5U, 0xf0787888U, 0x4a25256fU, 0x5c2e2e72U,
++    0x381c1c24U, 0x57a6a6f1U, 0x73b4b4c7U, 0x97c6c651U,
++    0xcbe8e823U, 0xa1dddd7cU, 0xe874749cU, 0x3e1f1f21U,
++    0x964b4bddU, 0x61bdbddcU, 0x0d8b8b86U, 0x0f8a8a85U,
++    0xe0707090U, 0x7c3e3e42U, 0x71b5b5c4U, 0xcc6666aaU,
++    0x904848d8U, 0x06030305U, 0xf7f6f601U, 0x1c0e0e12U,
++    0xc26161a3U, 0x6a35355fU, 0xae5757f9U, 0x69b9b9d0U,
++    0x17868691U, 0x99c1c158U, 0x3a1d1d27U, 0x279e9eb9U,
++    0xd9e1e138U, 0xebf8f813U, 0x2b9898b3U, 0x22111133U,
++    0xd26969bbU, 0xa9d9d970U, 0x078e8e89U, 0x339494a7U,
++    0x2d9b9bb6U, 0x3c1e1e22U, 0x15878792U, 0xc9e9e920U,
++    0x87cece49U, 0xaa5555ffU, 0x50282878U, 0xa5dfdf7aU,
++    0x038c8c8fU, 0x59a1a1f8U, 0x09898980U, 0x1a0d0d17U,
++    0x65bfbfdaU, 0xd7e6e631U, 0x844242c6U, 0xd06868b8U,
++    0x824141c3U, 0x299999b0U, 0x5a2d2d77U, 0x1e0f0f11U,
++    0x7bb0b0cbU, 0xa85454fcU, 0x6dbbbbd6U, 0x2c16163aU,
++};
++static const u32 Te1[256] = {
++    0xa5c66363U, 0x84f87c7cU, 0x99ee7777U, 0x8df67b7bU,
++    0x0dfff2f2U, 0xbdd66b6bU, 0xb1de6f6fU, 0x5491c5c5U,
++    0x50603030U, 0x03020101U, 0xa9ce6767U, 0x7d562b2bU,
++    0x19e7fefeU, 0x62b5d7d7U, 0xe64dababU, 0x9aec7676U,
++    0x458fcacaU, 0x9d1f8282U, 0x4089c9c9U, 0x87fa7d7dU,
++    0x15effafaU, 0xebb25959U, 0xc98e4747U, 0x0bfbf0f0U,
++    0xec41adadU, 0x67b3d4d4U, 0xfd5fa2a2U, 0xea45afafU,
++    0xbf239c9cU, 0xf753a4a4U, 0x96e47272U, 0x5b9bc0c0U,
++    0xc275b7b7U, 0x1ce1fdfdU, 0xae3d9393U, 0x6a4c2626U,
++    0x5a6c3636U, 0x417e3f3fU, 0x02f5f7f7U, 0x4f83ccccU,
++    0x5c683434U, 0xf451a5a5U, 0x34d1e5e5U, 0x08f9f1f1U,
++    0x93e27171U, 0x73abd8d8U, 0x53623131U, 0x3f2a1515U,
++    0x0c080404U, 0x5295c7c7U, 0x65462323U, 0x5e9dc3c3U,
++    0x28301818U, 0xa1379696U, 0x0f0a0505U, 0xb52f9a9aU,
++    0x090e0707U, 0x36241212U, 0x9b1b8080U, 0x3ddfe2e2U,
++    0x26cdebebU, 0x694e2727U, 0xcd7fb2b2U, 0x9fea7575U,
++    0x1b120909U, 0x9e1d8383U, 0x74582c2cU, 0x2e341a1aU,
++    0x2d361b1bU, 0xb2dc6e6eU, 0xeeb45a5aU, 0xfb5ba0a0U,
++    0xf6a45252U, 0x4d763b3bU, 0x61b7d6d6U, 0xce7db3b3U,
++    0x7b522929U, 0x3edde3e3U, 0x715e2f2fU, 0x97138484U,
++    0xf5a65353U, 0x68b9d1d1U, 0x00000000U, 0x2cc1ededU,
++    0x60402020U, 0x1fe3fcfcU, 0xc879b1b1U, 0xedb65b5bU,
++    0xbed46a6aU, 0x468dcbcbU, 0xd967bebeU, 0x4b723939U,
++    0xde944a4aU, 0xd4984c4cU, 0xe8b05858U, 0x4a85cfcfU,
++    0x6bbbd0d0U, 0x2ac5efefU, 0xe54faaaaU, 0x16edfbfbU,
++    0xc5864343U, 0xd79a4d4dU, 0x55663333U, 0x94118585U,
++    0xcf8a4545U, 0x10e9f9f9U, 0x06040202U, 0x81fe7f7fU,
++    0xf0a05050U, 0x44783c3cU, 0xba259f9fU, 0xe34ba8a8U,
++    0xf3a25151U, 0xfe5da3a3U, 0xc0804040U, 0x8a058f8fU,
++    0xad3f9292U, 0xbc219d9dU, 0x48703838U, 0x04f1f5f5U,
++    0xdf63bcbcU, 0xc177b6b6U, 0x75afdadaU, 0x63422121U,
++    0x30201010U, 0x1ae5ffffU, 0x0efdf3f3U, 0x6dbfd2d2U,
++    0x4c81cdcdU, 0x14180c0cU, 0x35261313U, 0x2fc3ececU,
++    0xe1be5f5fU, 0xa2359797U, 0xcc884444U, 0x392e1717U,
++    0x5793c4c4U, 0xf255a7a7U, 0x82fc7e7eU, 0x477a3d3dU,
++    0xacc86464U, 0xe7ba5d5dU, 0x2b321919U, 0x95e67373U,
++    0xa0c06060U, 0x98198181U, 0xd19e4f4fU, 0x7fa3dcdcU,
++    0x66442222U, 0x7e542a2aU, 0xab3b9090U, 0x830b8888U,
++    0xca8c4646U, 0x29c7eeeeU, 0xd36bb8b8U, 0x3c281414U,
++    0x79a7dedeU, 0xe2bc5e5eU, 0x1d160b0bU, 0x76addbdbU,
++    0x3bdbe0e0U, 0x56643232U, 0x4e743a3aU, 0x1e140a0aU,
++    0xdb924949U, 0x0a0c0606U, 0x6c482424U, 0xe4b85c5cU,
++    0x5d9fc2c2U, 0x6ebdd3d3U, 0xef43acacU, 0xa6c46262U,
++    0xa8399191U, 0xa4319595U, 0x37d3e4e4U, 0x8bf27979U,
++    0x32d5e7e7U, 0x438bc8c8U, 0x596e3737U, 0xb7da6d6dU,
++    0x8c018d8dU, 0x64b1d5d5U, 0xd29c4e4eU, 0xe049a9a9U,
++    0xb4d86c6cU, 0xfaac5656U, 0x07f3f4f4U, 0x25cfeaeaU,
++    0xafca6565U, 0x8ef47a7aU, 0xe947aeaeU, 0x18100808U,
++    0xd56fbabaU, 0x88f07878U, 0x6f4a2525U, 0x725c2e2eU,
++    0x24381c1cU, 0xf157a6a6U, 0xc773b4b4U, 0x5197c6c6U,
++    0x23cbe8e8U, 0x7ca1ddddU, 0x9ce87474U, 0x213e1f1fU,
++    0xdd964b4bU, 0xdc61bdbdU, 0x860d8b8bU, 0x850f8a8aU,
++    0x90e07070U, 0x427c3e3eU, 0xc471b5b5U, 0xaacc6666U,
++    0xd8904848U, 0x05060303U, 0x01f7f6f6U, 0x121c0e0eU,
++    0xa3c26161U, 0x5f6a3535U, 0xf9ae5757U, 0xd069b9b9U,
++    0x91178686U, 0x5899c1c1U, 0x273a1d1dU, 0xb9279e9eU,
++    0x38d9e1e1U, 0x13ebf8f8U, 0xb32b9898U, 0x33221111U,
++    0xbbd26969U, 0x70a9d9d9U, 0x89078e8eU, 0xa7339494U,
++    0xb62d9b9bU, 0x223c1e1eU, 0x92158787U, 0x20c9e9e9U,
++    0x4987ceceU, 0xffaa5555U, 0x78502828U, 0x7aa5dfdfU,
++    0x8f038c8cU, 0xf859a1a1U, 0x80098989U, 0x171a0d0dU,
++    0xda65bfbfU, 0x31d7e6e6U, 0xc6844242U, 0xb8d06868U,
++    0xc3824141U, 0xb0299999U, 0x775a2d2dU, 0x111e0f0fU,
++    0xcb7bb0b0U, 0xfca85454U, 0xd66dbbbbU, 0x3a2c1616U,
++};
++static const u32 Te2[256] = {
++    0x63a5c663U, 0x7c84f87cU, 0x7799ee77U, 0x7b8df67bU,
++    0xf20dfff2U, 0x6bbdd66bU, 0x6fb1de6fU, 0xc55491c5U,
++    0x30506030U, 0x01030201U, 0x67a9ce67U, 0x2b7d562bU,
++    0xfe19e7feU, 0xd762b5d7U, 0xabe64dabU, 0x769aec76U,
++    0xca458fcaU, 0x829d1f82U, 0xc94089c9U, 0x7d87fa7dU,
++    0xfa15effaU, 0x59ebb259U, 0x47c98e47U, 0xf00bfbf0U,
++    0xadec41adU, 0xd467b3d4U, 0xa2fd5fa2U, 0xafea45afU,
++    0x9cbf239cU, 0xa4f753a4U, 0x7296e472U, 0xc05b9bc0U,
++    0xb7c275b7U, 0xfd1ce1fdU, 0x93ae3d93U, 0x266a4c26U,
++    0x365a6c36U, 0x3f417e3fU, 0xf702f5f7U, 0xcc4f83ccU,
++    0x345c6834U, 0xa5f451a5U, 0xe534d1e5U, 0xf108f9f1U,
++    0x7193e271U, 0xd873abd8U, 0x31536231U, 0x153f2a15U,
++    0x040c0804U, 0xc75295c7U, 0x23654623U, 0xc35e9dc3U,
++    0x18283018U, 0x96a13796U, 0x050f0a05U, 0x9ab52f9aU,
++    0x07090e07U, 0x12362412U, 0x809b1b80U, 0xe23ddfe2U,
++    0xeb26cdebU, 0x27694e27U, 0xb2cd7fb2U, 0x759fea75U,
++    0x091b1209U, 0x839e1d83U, 0x2c74582cU, 0x1a2e341aU,
++    0x1b2d361bU, 0x6eb2dc6eU, 0x5aeeb45aU, 0xa0fb5ba0U,
++    0x52f6a452U, 0x3b4d763bU, 0xd661b7d6U, 0xb3ce7db3U,
++    0x297b5229U, 0xe33edde3U, 0x2f715e2fU, 0x84971384U,
++    0x53f5a653U, 0xd168b9d1U, 0x00000000U, 0xed2cc1edU,
++    0x20604020U, 0xfc1fe3fcU, 0xb1c879b1U, 0x5bedb65bU,
++    0x6abed46aU, 0xcb468dcbU, 0xbed967beU, 0x394b7239U,
++    0x4ade944aU, 0x4cd4984cU, 0x58e8b058U, 0xcf4a85cfU,
++    0xd06bbbd0U, 0xef2ac5efU, 0xaae54faaU, 0xfb16edfbU,
++    0x43c58643U, 0x4dd79a4dU, 0x33556633U, 0x85941185U,
++    0x45cf8a45U, 0xf910e9f9U, 0x02060402U, 0x7f81fe7fU,
++    0x50f0a050U, 0x3c44783cU, 0x9fba259fU, 0xa8e34ba8U,
++    0x51f3a251U, 0xa3fe5da3U, 0x40c08040U, 0x8f8a058fU,
++    0x92ad3f92U, 0x9dbc219dU, 0x38487038U, 0xf504f1f5U,
++    0xbcdf63bcU, 0xb6c177b6U, 0xda75afdaU, 0x21634221U,
++    0x10302010U, 0xff1ae5ffU, 0xf30efdf3U, 0xd26dbfd2U,
++    0xcd4c81cdU, 0x0c14180cU, 0x13352613U, 0xec2fc3ecU,
++    0x5fe1be5fU, 0x97a23597U, 0x44cc8844U, 0x17392e17U,
++    0xc45793c4U, 0xa7f255a7U, 0x7e82fc7eU, 0x3d477a3dU,
++    0x64acc864U, 0x5de7ba5dU, 0x192b3219U, 0x7395e673U,
++    0x60a0c060U, 0x81981981U, 0x4fd19e4fU, 0xdc7fa3dcU,
++    0x22664422U, 0x2a7e542aU, 0x90ab3b90U, 0x88830b88U,
++    0x46ca8c46U, 0xee29c7eeU, 0xb8d36bb8U, 0x143c2814U,
++    0xde79a7deU, 0x5ee2bc5eU, 0x0b1d160bU, 0xdb76addbU,
++    0xe03bdbe0U, 0x32566432U, 0x3a4e743aU, 0x0a1e140aU,
++    0x49db9249U, 0x060a0c06U, 0x246c4824U, 0x5ce4b85cU,
++    0xc25d9fc2U, 0xd36ebdd3U, 0xacef43acU, 0x62a6c462U,
++    0x91a83991U, 0x95a43195U, 0xe437d3e4U, 0x798bf279U,
++    0xe732d5e7U, 0xc8438bc8U, 0x37596e37U, 0x6db7da6dU,
++    0x8d8c018dU, 0xd564b1d5U, 0x4ed29c4eU, 0xa9e049a9U,
++    0x6cb4d86cU, 0x56faac56U, 0xf407f3f4U, 0xea25cfeaU,
++    0x65afca65U, 0x7a8ef47aU, 0xaee947aeU, 0x08181008U,
++    0xbad56fbaU, 0x7888f078U, 0x256f4a25U, 0x2e725c2eU,
++    0x1c24381cU, 0xa6f157a6U, 0xb4c773b4U, 0xc65197c6U,
++    0xe823cbe8U, 0xdd7ca1ddU, 0x749ce874U, 0x1f213e1fU,
++    0x4bdd964bU, 0xbddc61bdU, 0x8b860d8bU, 0x8a850f8aU,
++    0x7090e070U, 0x3e427c3eU, 0xb5c471b5U, 0x66aacc66U,
++    0x48d89048U, 0x03050603U, 0xf601f7f6U, 0x0e121c0eU,
++    0x61a3c261U, 0x355f6a35U, 0x57f9ae57U, 0xb9d069b9U,
++    0x86911786U, 0xc15899c1U, 0x1d273a1dU, 0x9eb9279eU,
++    0xe138d9e1U, 0xf813ebf8U, 0x98b32b98U, 0x11332211U,
++    0x69bbd269U, 0xd970a9d9U, 0x8e89078eU, 0x94a73394U,
++    0x9bb62d9bU, 0x1e223c1eU, 0x87921587U, 0xe920c9e9U,
++    0xce4987ceU, 0x55ffaa55U, 0x28785028U, 0xdf7aa5dfU,
++    0x8c8f038cU, 0xa1f859a1U, 0x89800989U, 0x0d171a0dU,
++    0xbfda65bfU, 0xe631d7e6U, 0x42c68442U, 0x68b8d068U,
++    0x41c38241U, 0x99b02999U, 0x2d775a2dU, 0x0f111e0fU,
++    0xb0cb7bb0U, 0x54fca854U, 0xbbd66dbbU, 0x163a2c16U,
++};
++static const u32 Te3[256] = {
++    0x6363a5c6U, 0x7c7c84f8U, 0x777799eeU, 0x7b7b8df6U,
++    0xf2f20dffU, 0x6b6bbdd6U, 0x6f6fb1deU, 0xc5c55491U,
++    0x30305060U, 0x01010302U, 0x6767a9ceU, 0x2b2b7d56U,
++    0xfefe19e7U, 0xd7d762b5U, 0xababe64dU, 0x76769aecU,
++    0xcaca458fU, 0x82829d1fU, 0xc9c94089U, 0x7d7d87faU,
++    0xfafa15efU, 0x5959ebb2U, 0x4747c98eU, 0xf0f00bfbU,
++    0xadadec41U, 0xd4d467b3U, 0xa2a2fd5fU, 0xafafea45U,
++    0x9c9cbf23U, 0xa4a4f753U, 0x727296e4U, 0xc0c05b9bU,
++    0xb7b7c275U, 0xfdfd1ce1U, 0x9393ae3dU, 0x26266a4cU,
++    0x36365a6cU, 0x3f3f417eU, 0xf7f702f5U, 0xcccc4f83U,
++    0x34345c68U, 0xa5a5f451U, 0xe5e534d1U, 0xf1f108f9U,
++    0x717193e2U, 0xd8d873abU, 0x31315362U, 0x15153f2aU,
++    0x04040c08U, 0xc7c75295U, 0x23236546U, 0xc3c35e9dU,
++    0x18182830U, 0x9696a137U, 0x05050f0aU, 0x9a9ab52fU,
++    0x0707090eU, 0x12123624U, 0x80809b1bU, 0xe2e23ddfU,
++    0xebeb26cdU, 0x2727694eU, 0xb2b2cd7fU, 0x75759feaU,
++    0x09091b12U, 0x83839e1dU, 0x2c2c7458U, 0x1a1a2e34U,
++    0x1b1b2d36U, 0x6e6eb2dcU, 0x5a5aeeb4U, 0xa0a0fb5bU,
++    0x5252f6a4U, 0x3b3b4d76U, 0xd6d661b7U, 0xb3b3ce7dU,
++    0x29297b52U, 0xe3e33eddU, 0x2f2f715eU, 0x84849713U,
++    0x5353f5a6U, 0xd1d168b9U, 0x00000000U, 0xeded2cc1U,
++    0x20206040U, 0xfcfc1fe3U, 0xb1b1c879U, 0x5b5bedb6U,
++    0x6a6abed4U, 0xcbcb468dU, 0xbebed967U, 0x39394b72U,
++    0x4a4ade94U, 0x4c4cd498U, 0x5858e8b0U, 0xcfcf4a85U,
++    0xd0d06bbbU, 0xefef2ac5U, 0xaaaae54fU, 0xfbfb16edU,
++    0x4343c586U, 0x4d4dd79aU, 0x33335566U, 0x85859411U,
++    0x4545cf8aU, 0xf9f910e9U, 0x02020604U, 0x7f7f81feU,
++    0x5050f0a0U, 0x3c3c4478U, 0x9f9fba25U, 0xa8a8e34bU,
++    0x5151f3a2U, 0xa3a3fe5dU, 0x4040c080U, 0x8f8f8a05U,
++    0x9292ad3fU, 0x9d9dbc21U, 0x38384870U, 0xf5f504f1U,
++    0xbcbcdf63U, 0xb6b6c177U, 0xdada75afU, 0x21216342U,
++    0x10103020U, 0xffff1ae5U, 0xf3f30efdU, 0xd2d26dbfU,
++    0xcdcd4c81U, 0x0c0c1418U, 0x13133526U, 0xecec2fc3U,
++    0x5f5fe1beU, 0x9797a235U, 0x4444cc88U, 0x1717392eU,
++    0xc4c45793U, 0xa7a7f255U, 0x7e7e82fcU, 0x3d3d477aU,
++    0x6464acc8U, 0x5d5de7baU, 0x19192b32U, 0x737395e6U,
++    0x6060a0c0U, 0x81819819U, 0x4f4fd19eU, 0xdcdc7fa3U,
++    0x22226644U, 0x2a2a7e54U, 0x9090ab3bU, 0x8888830bU,
++    0x4646ca8cU, 0xeeee29c7U, 0xb8b8d36bU, 0x14143c28U,
++    0xdede79a7U, 0x5e5ee2bcU, 0x0b0b1d16U, 0xdbdb76adU,
++    0xe0e03bdbU, 0x32325664U, 0x3a3a4e74U, 0x0a0a1e14U,
++    0x4949db92U, 0x06060a0cU, 0x24246c48U, 0x5c5ce4b8U,
++    0xc2c25d9fU, 0xd3d36ebdU, 0xacacef43U, 0x6262a6c4U,
++    0x9191a839U, 0x9595a431U, 0xe4e437d3U, 0x79798bf2U,
++    0xe7e732d5U, 0xc8c8438bU, 0x3737596eU, 0x6d6db7daU,
++    0x8d8d8c01U, 0xd5d564b1U, 0x4e4ed29cU, 0xa9a9e049U,
++    0x6c6cb4d8U, 0x5656faacU, 0xf4f407f3U, 0xeaea25cfU,
++    0x6565afcaU, 0x7a7a8ef4U, 0xaeaee947U, 0x08081810U,
++    0xbabad56fU, 0x787888f0U, 0x25256f4aU, 0x2e2e725cU,
++    0x1c1c2438U, 0xa6a6f157U, 0xb4b4c773U, 0xc6c65197U,
++    0xe8e823cbU, 0xdddd7ca1U, 0x74749ce8U, 0x1f1f213eU,
++    0x4b4bdd96U, 0xbdbddc61U, 0x8b8b860dU, 0x8a8a850fU,
++    0x707090e0U, 0x3e3e427cU, 0xb5b5c471U, 0x6666aaccU,
++    0x4848d890U, 0x03030506U, 0xf6f601f7U, 0x0e0e121cU,
++    0x6161a3c2U, 0x35355f6aU, 0x5757f9aeU, 0xb9b9d069U,
++    0x86869117U, 0xc1c15899U, 0x1d1d273aU, 0x9e9eb927U,
++    0xe1e138d9U, 0xf8f813ebU, 0x9898b32bU, 0x11113322U,
++    0x6969bbd2U, 0xd9d970a9U, 0x8e8e8907U, 0x9494a733U,
++    0x9b9bb62dU, 0x1e1e223cU, 0x87879215U, 0xe9e920c9U,
++    0xcece4987U, 0x5555ffaaU, 0x28287850U, 0xdfdf7aa5U,
++    0x8c8c8f03U, 0xa1a1f859U, 0x89898009U, 0x0d0d171aU,
++    0xbfbfda65U, 0xe6e631d7U, 0x4242c684U, 0x6868b8d0U,
++    0x4141c382U, 0x9999b029U, 0x2d2d775aU, 0x0f0f111eU,
++    0xb0b0cb7bU, 0x5454fca8U, 0xbbbbd66dU, 0x16163a2cU,
++};
++
++static const u32 Td0[256] = {
++    0x51f4a750U, 0x7e416553U, 0x1a17a4c3U, 0x3a275e96U,
++    0x3bab6bcbU, 0x1f9d45f1U, 0xacfa58abU, 0x4be30393U,
++    0x2030fa55U, 0xad766df6U, 0x88cc7691U, 0xf5024c25U,
++    0x4fe5d7fcU, 0xc52acbd7U, 0x26354480U, 0xb562a38fU,
++    0xdeb15a49U, 0x25ba1b67U, 0x45ea0e98U, 0x5dfec0e1U,
++    0xc32f7502U, 0x814cf012U, 0x8d4697a3U, 0x6bd3f9c6U,
++    0x038f5fe7U, 0x15929c95U, 0xbf6d7aebU, 0x955259daU,
++    0xd4be832dU, 0x587421d3U, 0x49e06929U, 0x8ec9c844U,
++    0x75c2896aU, 0xf48e7978U, 0x99583e6bU, 0x27b971ddU,
++    0xbee14fb6U, 0xf088ad17U, 0xc920ac66U, 0x7dce3ab4U,
++    0x63df4a18U, 0xe51a3182U, 0x97513360U, 0x62537f45U,
++    0xb16477e0U, 0xbb6bae84U, 0xfe81a01cU, 0xf9082b94U,
++    0x70486858U, 0x8f45fd19U, 0x94de6c87U, 0x527bf8b7U,
++    0xab73d323U, 0x724b02e2U, 0xe31f8f57U, 0x6655ab2aU,
++    0xb2eb2807U, 0x2fb5c203U, 0x86c57b9aU, 0xd33708a5U,
++    0x302887f2U, 0x23bfa5b2U, 0x02036abaU, 0xed16825cU,
++    0x8acf1c2bU, 0xa779b492U, 0xf307f2f0U, 0x4e69e2a1U,
++    0x65daf4cdU, 0x0605bed5U, 0xd134621fU, 0xc4a6fe8aU,
++    0x342e539dU, 0xa2f355a0U, 0x058ae132U, 0xa4f6eb75U,
++    0x0b83ec39U, 0x4060efaaU, 0x5e719f06U, 0xbd6e1051U,
++    0x3e218af9U, 0x96dd063dU, 0xdd3e05aeU, 0x4de6bd46U,
++    0x91548db5U, 0x71c45d05U, 0x0406d46fU, 0x605015ffU,
++    0x1998fb24U, 0xd6bde997U, 0x894043ccU, 0x67d99e77U,
++    0xb0e842bdU, 0x07898b88U, 0xe7195b38U, 0x79c8eedbU,
++    0xa17c0a47U, 0x7c420fe9U, 0xf8841ec9U, 0x00000000U,
++    0x09808683U, 0x322bed48U, 0x1e1170acU, 0x6c5a724eU,
++    0xfd0efffbU, 0x0f853856U, 0x3daed51eU, 0x362d3927U,
++    0x0a0fd964U, 0x685ca621U, 0x9b5b54d1U, 0x24362e3aU,
++    0x0c0a67b1U, 0x9357e70fU, 0xb4ee96d2U, 0x1b9b919eU,
++    0x80c0c54fU, 0x61dc20a2U, 0x5a774b69U, 0x1c121a16U,
++    0xe293ba0aU, 0xc0a02ae5U, 0x3c22e043U, 0x121b171dU,
++    0x0e090d0bU, 0xf28bc7adU, 0x2db6a8b9U, 0x141ea9c8U,
++    0x57f11985U, 0xaf75074cU, 0xee99ddbbU, 0xa37f60fdU,
++    0xf701269fU, 0x5c72f5bcU, 0x44663bc5U, 0x5bfb7e34U,
++    0x8b432976U, 0xcb23c6dcU, 0xb6edfc68U, 0xb8e4f163U,
++    0xd731dccaU, 0x42638510U, 0x13972240U, 0x84c61120U,
++    0x854a247dU, 0xd2bb3df8U, 0xaef93211U, 0xc729a16dU,
++    0x1d9e2f4bU, 0xdcb230f3U, 0x0d8652ecU, 0x77c1e3d0U,
++    0x2bb3166cU, 0xa970b999U, 0x119448faU, 0x47e96422U,
++    0xa8fc8cc4U, 0xa0f03f1aU, 0x567d2cd8U, 0x223390efU,
++    0x87494ec7U, 0xd938d1c1U, 0x8ccaa2feU, 0x98d40b36U,
++    0xa6f581cfU, 0xa57ade28U, 0xdab78e26U, 0x3fadbfa4U,
++    0x2c3a9de4U, 0x5078920dU, 0x6a5fcc9bU, 0x547e4662U,
++    0xf68d13c2U, 0x90d8b8e8U, 0x2e39f75eU, 0x82c3aff5U,
++    0x9f5d80beU, 0x69d0937cU, 0x6fd52da9U, 0xcf2512b3U,
++    0xc8ac993bU, 0x10187da7U, 0xe89c636eU, 0xdb3bbb7bU,
++    0xcd267809U, 0x6e5918f4U, 0xec9ab701U, 0x834f9aa8U,
++    0xe6956e65U, 0xaaffe67eU, 0x21bccf08U, 0xef15e8e6U,
++    0xbae79bd9U, 0x4a6f36ceU, 0xea9f09d4U, 0x29b07cd6U,
++    0x31a4b2afU, 0x2a3f2331U, 0xc6a59430U, 0x35a266c0U,
++    0x744ebc37U, 0xfc82caa6U, 0xe090d0b0U, 0x33a7d815U,
++    0xf104984aU, 0x41ecdaf7U, 0x7fcd500eU, 0x1791f62fU,
++    0x764dd68dU, 0x43efb04dU, 0xccaa4d54U, 0xe49604dfU,
++    0x9ed1b5e3U, 0x4c6a881bU, 0xc12c1fb8U, 0x4665517fU,
++    0x9d5eea04U, 0x018c355dU, 0xfa877473U, 0xfb0b412eU,
++    0xb3671d5aU, 0x92dbd252U, 0xe9105633U, 0x6dd64713U,
++    0x9ad7618cU, 0x37a10c7aU, 0x59f8148eU, 0xeb133c89U,
++    0xcea927eeU, 0xb761c935U, 0xe11ce5edU, 0x7a47b13cU,
++    0x9cd2df59U, 0x55f2733fU, 0x1814ce79U, 0x73c737bfU,
++    0x53f7cdeaU, 0x5ffdaa5bU, 0xdf3d6f14U, 0x7844db86U,
++    0xcaaff381U, 0xb968c43eU, 0x3824342cU, 0xc2a3405fU,
++    0x161dc372U, 0xbce2250cU, 0x283c498bU, 0xff0d9541U,
++    0x39a80171U, 0x080cb3deU, 0xd8b4e49cU, 0x6456c190U,
++    0x7bcb8461U, 0xd532b670U, 0x486c5c74U, 0xd0b85742U,
++};
++static const u32 Td1[256] = {
++    0x5051f4a7U, 0x537e4165U, 0xc31a17a4U, 0x963a275eU,
++    0xcb3bab6bU, 0xf11f9d45U, 0xabacfa58U, 0x934be303U,
++    0x552030faU, 0xf6ad766dU, 0x9188cc76U, 0x25f5024cU,
++    0xfc4fe5d7U, 0xd7c52acbU, 0x80263544U, 0x8fb562a3U,
++    0x49deb15aU, 0x6725ba1bU, 0x9845ea0eU, 0xe15dfec0U,
++    0x02c32f75U, 0x12814cf0U, 0xa38d4697U, 0xc66bd3f9U,
++    0xe7038f5fU, 0x9515929cU, 0xebbf6d7aU, 0xda955259U,
++    0x2dd4be83U, 0xd3587421U, 0x2949e069U, 0x448ec9c8U,
++    0x6a75c289U, 0x78f48e79U, 0x6b99583eU, 0xdd27b971U,
++    0xb6bee14fU, 0x17f088adU, 0x66c920acU, 0xb47dce3aU,
++    0x1863df4aU, 0x82e51a31U, 0x60975133U, 0x4562537fU,
++    0xe0b16477U, 0x84bb6baeU, 0x1cfe81a0U, 0x94f9082bU,
++    0x58704868U, 0x198f45fdU, 0x8794de6cU, 0xb7527bf8U,
++    0x23ab73d3U, 0xe2724b02U, 0x57e31f8fU, 0x2a6655abU,
++    0x07b2eb28U, 0x032fb5c2U, 0x9a86c57bU, 0xa5d33708U,
++    0xf2302887U, 0xb223bfa5U, 0xba02036aU, 0x5ced1682U,
++    0x2b8acf1cU, 0x92a779b4U, 0xf0f307f2U, 0xa14e69e2U,
++    0xcd65daf4U, 0xd50605beU, 0x1fd13462U, 0x8ac4a6feU,
++    0x9d342e53U, 0xa0a2f355U, 0x32058ae1U, 0x75a4f6ebU,
++    0x390b83ecU, 0xaa4060efU, 0x065e719fU, 0x51bd6e10U,
++    0xf93e218aU, 0x3d96dd06U, 0xaedd3e05U, 0x464de6bdU,
++    0xb591548dU, 0x0571c45dU, 0x6f0406d4U, 0xff605015U,
++    0x241998fbU, 0x97d6bde9U, 0xcc894043U, 0x7767d99eU,
++    0xbdb0e842U, 0x8807898bU, 0x38e7195bU, 0xdb79c8eeU,
++    0x47a17c0aU, 0xe97c420fU, 0xc9f8841eU, 0x00000000U,
++    0x83098086U, 0x48322bedU, 0xac1e1170U, 0x4e6c5a72U,
++    0xfbfd0effU, 0x560f8538U, 0x1e3daed5U, 0x27362d39U,
++    0x640a0fd9U, 0x21685ca6U, 0xd19b5b54U, 0x3a24362eU,
++    0xb10c0a67U, 0x0f9357e7U, 0xd2b4ee96U, 0x9e1b9b91U,
++    0x4f80c0c5U, 0xa261dc20U, 0x695a774bU, 0x161c121aU,
++    0x0ae293baU, 0xe5c0a02aU, 0x433c22e0U, 0x1d121b17U,
++    0x0b0e090dU, 0xadf28bc7U, 0xb92db6a8U, 0xc8141ea9U,
++    0x8557f119U, 0x4caf7507U, 0xbbee99ddU, 0xfda37f60U,
++    0x9ff70126U, 0xbc5c72f5U, 0xc544663bU, 0x345bfb7eU,
++    0x768b4329U, 0xdccb23c6U, 0x68b6edfcU, 0x63b8e4f1U,
++    0xcad731dcU, 0x10426385U, 0x40139722U, 0x2084c611U,
++    0x7d854a24U, 0xf8d2bb3dU, 0x11aef932U, 0x6dc729a1U,
++    0x4b1d9e2fU, 0xf3dcb230U, 0xec0d8652U, 0xd077c1e3U,
++    0x6c2bb316U, 0x99a970b9U, 0xfa119448U, 0x2247e964U,
++    0xc4a8fc8cU, 0x1aa0f03fU, 0xd8567d2cU, 0xef223390U,
++    0xc787494eU, 0xc1d938d1U, 0xfe8ccaa2U, 0x3698d40bU,
++    0xcfa6f581U, 0x28a57adeU, 0x26dab78eU, 0xa43fadbfU,
++    0xe42c3a9dU, 0x0d507892U, 0x9b6a5fccU, 0x62547e46U,
++    0xc2f68d13U, 0xe890d8b8U, 0x5e2e39f7U, 0xf582c3afU,
++    0xbe9f5d80U, 0x7c69d093U, 0xa96fd52dU, 0xb3cf2512U,
++    0x3bc8ac99U, 0xa710187dU, 0x6ee89c63U, 0x7bdb3bbbU,
++    0x09cd2678U, 0xf46e5918U, 0x01ec9ab7U, 0xa8834f9aU,
++    0x65e6956eU, 0x7eaaffe6U, 0x0821bccfU, 0xe6ef15e8U,
++    0xd9bae79bU, 0xce4a6f36U, 0xd4ea9f09U, 0xd629b07cU,
++    0xaf31a4b2U, 0x312a3f23U, 0x30c6a594U, 0xc035a266U,
++    0x37744ebcU, 0xa6fc82caU, 0xb0e090d0U, 0x1533a7d8U,
++    0x4af10498U, 0xf741ecdaU, 0x0e7fcd50U, 0x2f1791f6U,
++    0x8d764dd6U, 0x4d43efb0U, 0x54ccaa4dU, 0xdfe49604U,
++    0xe39ed1b5U, 0x1b4c6a88U, 0xb8c12c1fU, 0x7f466551U,
++    0x049d5eeaU, 0x5d018c35U, 0x73fa8774U, 0x2efb0b41U,
++    0x5ab3671dU, 0x5292dbd2U, 0x33e91056U, 0x136dd647U,
++    0x8c9ad761U, 0x7a37a10cU, 0x8e59f814U, 0x89eb133cU,
++    0xeecea927U, 0x35b761c9U, 0xede11ce5U, 0x3c7a47b1U,
++    0x599cd2dfU, 0x3f55f273U, 0x791814ceU, 0xbf73c737U,
++    0xea53f7cdU, 0x5b5ffdaaU, 0x14df3d6fU, 0x867844dbU,
++    0x81caaff3U, 0x3eb968c4U, 0x2c382434U, 0x5fc2a340U,
++    0x72161dc3U, 0x0cbce225U, 0x8b283c49U, 0x41ff0d95U,
++    0x7139a801U, 0xde080cb3U, 0x9cd8b4e4U, 0x906456c1U,
++    0x617bcb84U, 0x70d532b6U, 0x74486c5cU, 0x42d0b857U,
++};
++static const u32 Td2[256] = {
++    0xa75051f4U, 0x65537e41U, 0xa4c31a17U, 0x5e963a27U,
++    0x6bcb3babU, 0x45f11f9dU, 0x58abacfaU, 0x03934be3U,
++    0xfa552030U, 0x6df6ad76U, 0x769188ccU, 0x4c25f502U,
++    0xd7fc4fe5U, 0xcbd7c52aU, 0x44802635U, 0xa38fb562U,
++    0x5a49deb1U, 0x1b6725baU, 0x0e9845eaU, 0xc0e15dfeU,
++    0x7502c32fU, 0xf012814cU, 0x97a38d46U, 0xf9c66bd3U,
++    0x5fe7038fU, 0x9c951592U, 0x7aebbf6dU, 0x59da9552U,
++    0x832dd4beU, 0x21d35874U, 0x692949e0U, 0xc8448ec9U,
++    0x896a75c2U, 0x7978f48eU, 0x3e6b9958U, 0x71dd27b9U,
++    0x4fb6bee1U, 0xad17f088U, 0xac66c920U, 0x3ab47dceU,
++    0x4a1863dfU, 0x3182e51aU, 0x33609751U, 0x7f456253U,
++    0x77e0b164U, 0xae84bb6bU, 0xa01cfe81U, 0x2b94f908U,
++    0x68587048U, 0xfd198f45U, 0x6c8794deU, 0xf8b7527bU,
++    0xd323ab73U, 0x02e2724bU, 0x8f57e31fU, 0xab2a6655U,
++    0x2807b2ebU, 0xc2032fb5U, 0x7b9a86c5U, 0x08a5d337U,
++    0x87f23028U, 0xa5b223bfU, 0x6aba0203U, 0x825ced16U,
++    0x1c2b8acfU, 0xb492a779U, 0xf2f0f307U, 0xe2a14e69U,
++    0xf4cd65daU, 0xbed50605U, 0x621fd134U, 0xfe8ac4a6U,
++    0x539d342eU, 0x55a0a2f3U, 0xe132058aU, 0xeb75a4f6U,
++    0xec390b83U, 0xefaa4060U, 0x9f065e71U, 0x1051bd6eU,
++    0x8af93e21U, 0x063d96ddU, 0x05aedd3eU, 0xbd464de6U,
++    0x8db59154U, 0x5d0571c4U, 0xd46f0406U, 0x15ff6050U,
++    0xfb241998U, 0xe997d6bdU, 0x43cc8940U, 0x9e7767d9U,
++    0x42bdb0e8U, 0x8b880789U, 0x5b38e719U, 0xeedb79c8U,
++    0x0a47a17cU, 0x0fe97c42U, 0x1ec9f884U, 0x00000000U,
++    0x86830980U, 0xed48322bU, 0x70ac1e11U, 0x724e6c5aU,
++    0xfffbfd0eU, 0x38560f85U, 0xd51e3daeU, 0x3927362dU,
++    0xd9640a0fU, 0xa621685cU, 0x54d19b5bU, 0x2e3a2436U,
++    0x67b10c0aU, 0xe70f9357U, 0x96d2b4eeU, 0x919e1b9bU,
++    0xc54f80c0U, 0x20a261dcU, 0x4b695a77U, 0x1a161c12U,
++    0xba0ae293U, 0x2ae5c0a0U, 0xe0433c22U, 0x171d121bU,
++    0x0d0b0e09U, 0xc7adf28bU, 0xa8b92db6U, 0xa9c8141eU,
++    0x198557f1U, 0x074caf75U, 0xddbbee99U, 0x60fda37fU,
++    0x269ff701U, 0xf5bc5c72U, 0x3bc54466U, 0x7e345bfbU,
++    0x29768b43U, 0xc6dccb23U, 0xfc68b6edU, 0xf163b8e4U,
++    0xdccad731U, 0x85104263U, 0x22401397U, 0x112084c6U,
++    0x247d854aU, 0x3df8d2bbU, 0x3211aef9U, 0xa16dc729U,
++    0x2f4b1d9eU, 0x30f3dcb2U, 0x52ec0d86U, 0xe3d077c1U,
++    0x166c2bb3U, 0xb999a970U, 0x48fa1194U, 0x642247e9U,
++    0x8cc4a8fcU, 0x3f1aa0f0U, 0x2cd8567dU, 0x90ef2233U,
++    0x4ec78749U, 0xd1c1d938U, 0xa2fe8ccaU, 0x0b3698d4U,
++    0x81cfa6f5U, 0xde28a57aU, 0x8e26dab7U, 0xbfa43fadU,
++    0x9de42c3aU, 0x920d5078U, 0xcc9b6a5fU, 0x4662547eU,
++    0x13c2f68dU, 0xb8e890d8U, 0xf75e2e39U, 0xaff582c3U,
++    0x80be9f5dU, 0x937c69d0U, 0x2da96fd5U, 0x12b3cf25U,
++    0x993bc8acU, 0x7da71018U, 0x636ee89cU, 0xbb7bdb3bU,
++    0x7809cd26U, 0x18f46e59U, 0xb701ec9aU, 0x9aa8834fU,
++    0x6e65e695U, 0xe67eaaffU, 0xcf0821bcU, 0xe8e6ef15U,
++    0x9bd9bae7U, 0x36ce4a6fU, 0x09d4ea9fU, 0x7cd629b0U,
++    0xb2af31a4U, 0x23312a3fU, 0x9430c6a5U, 0x66c035a2U,
++    0xbc37744eU, 0xcaa6fc82U, 0xd0b0e090U, 0xd81533a7U,
++    0x984af104U, 0xdaf741ecU, 0x500e7fcdU, 0xf62f1791U,
++    0xd68d764dU, 0xb04d43efU, 0x4d54ccaaU, 0x04dfe496U,
++    0xb5e39ed1U, 0x881b4c6aU, 0x1fb8c12cU, 0x517f4665U,
++    0xea049d5eU, 0x355d018cU, 0x7473fa87U, 0x412efb0bU,
++    0x1d5ab367U, 0xd25292dbU, 0x5633e910U, 0x47136dd6U,
++    0x618c9ad7U, 0x0c7a37a1U, 0x148e59f8U, 0x3c89eb13U,
++    0x27eecea9U, 0xc935b761U, 0xe5ede11cU, 0xb13c7a47U,
++    0xdf599cd2U, 0x733f55f2U, 0xce791814U, 0x37bf73c7U,
++    0xcdea53f7U, 0xaa5b5ffdU, 0x6f14df3dU, 0xdb867844U,
++    0xf381caafU, 0xc43eb968U, 0x342c3824U, 0x405fc2a3U,
++    0xc372161dU, 0x250cbce2U, 0x498b283cU, 0x9541ff0dU,
++    0x017139a8U, 0xb3de080cU, 0xe49cd8b4U, 0xc1906456U,
++    0x84617bcbU, 0xb670d532U, 0x5c74486cU, 0x5742d0b8U,
++};
++static const u32 Td3[256] = {
++    0xf4a75051U, 0x4165537eU, 0x17a4c31aU, 0x275e963aU,
++    0xab6bcb3bU, 0x9d45f11fU, 0xfa58abacU, 0xe303934bU,
++    0x30fa5520U, 0x766df6adU, 0xcc769188U, 0x024c25f5U,
++    0xe5d7fc4fU, 0x2acbd7c5U, 0x35448026U, 0x62a38fb5U,
++    0xb15a49deU, 0xba1b6725U, 0xea0e9845U, 0xfec0e15dU,
++    0x2f7502c3U, 0x4cf01281U, 0x4697a38dU, 0xd3f9c66bU,
++    0x8f5fe703U, 0x929c9515U, 0x6d7aebbfU, 0x5259da95U,
++    0xbe832dd4U, 0x7421d358U, 0xe0692949U, 0xc9c8448eU,
++    0xc2896a75U, 0x8e7978f4U, 0x583e6b99U, 0xb971dd27U,
++    0xe14fb6beU, 0x88ad17f0U, 0x20ac66c9U, 0xce3ab47dU,
++    0xdf4a1863U, 0x1a3182e5U, 0x51336097U, 0x537f4562U,
++    0x6477e0b1U, 0x6bae84bbU, 0x81a01cfeU, 0x082b94f9U,
++    0x48685870U, 0x45fd198fU, 0xde6c8794U, 0x7bf8b752U,
++    0x73d323abU, 0x4b02e272U, 0x1f8f57e3U, 0x55ab2a66U,
++    0xeb2807b2U, 0xb5c2032fU, 0xc57b9a86U, 0x3708a5d3U,
++    0x2887f230U, 0xbfa5b223U, 0x036aba02U, 0x16825cedU,
++    0xcf1c2b8aU, 0x79b492a7U, 0x07f2f0f3U, 0x69e2a14eU,
++    0xdaf4cd65U, 0x05bed506U, 0x34621fd1U, 0xa6fe8ac4U,
++    0x2e539d34U, 0xf355a0a2U, 0x8ae13205U, 0xf6eb75a4U,
++    0x83ec390bU, 0x60efaa40U, 0x719f065eU, 0x6e1051bdU,
++    0x218af93eU, 0xdd063d96U, 0x3e05aeddU, 0xe6bd464dU,
++    0x548db591U, 0xc45d0571U, 0x06d46f04U, 0x5015ff60U,
++    0x98fb2419U, 0xbde997d6U, 0x4043cc89U, 0xd99e7767U,
++    0xe842bdb0U, 0x898b8807U, 0x195b38e7U, 0xc8eedb79U,
++    0x7c0a47a1U, 0x420fe97cU, 0x841ec9f8U, 0x00000000U,
++    0x80868309U, 0x2bed4832U, 0x1170ac1eU, 0x5a724e6cU,
++    0x0efffbfdU, 0x8538560fU, 0xaed51e3dU, 0x2d392736U,
++    0x0fd9640aU, 0x5ca62168U, 0x5b54d19bU, 0x362e3a24U,
++    0x0a67b10cU, 0x57e70f93U, 0xee96d2b4U, 0x9b919e1bU,
++    0xc0c54f80U, 0xdc20a261U, 0x774b695aU, 0x121a161cU,
++    0x93ba0ae2U, 0xa02ae5c0U, 0x22e0433cU, 0x1b171d12U,
++    0x090d0b0eU, 0x8bc7adf2U, 0xb6a8b92dU, 0x1ea9c814U,
++    0xf1198557U, 0x75074cafU, 0x99ddbbeeU, 0x7f60fda3U,
++    0x01269ff7U, 0x72f5bc5cU, 0x663bc544U, 0xfb7e345bU,
++    0x4329768bU, 0x23c6dccbU, 0xedfc68b6U, 0xe4f163b8U,
++    0x31dccad7U, 0x63851042U, 0x97224013U, 0xc6112084U,
++    0x4a247d85U, 0xbb3df8d2U, 0xf93211aeU, 0x29a16dc7U,
++    0x9e2f4b1dU, 0xb230f3dcU, 0x8652ec0dU, 0xc1e3d077U,
++    0xb3166c2bU, 0x70b999a9U, 0x9448fa11U, 0xe9642247U,
++    0xfc8cc4a8U, 0xf03f1aa0U, 0x7d2cd856U, 0x3390ef22U,
++    0x494ec787U, 0x38d1c1d9U, 0xcaa2fe8cU, 0xd40b3698U,
++    0xf581cfa6U, 0x7ade28a5U, 0xb78e26daU, 0xadbfa43fU,
++    0x3a9de42cU, 0x78920d50U, 0x5fcc9b6aU, 0x7e466254U,
++    0x8d13c2f6U, 0xd8b8e890U, 0x39f75e2eU, 0xc3aff582U,
++    0x5d80be9fU, 0xd0937c69U, 0xd52da96fU, 0x2512b3cfU,
++    0xac993bc8U, 0x187da710U, 0x9c636ee8U, 0x3bbb7bdbU,
++    0x267809cdU, 0x5918f46eU, 0x9ab701ecU, 0x4f9aa883U,
++    0x956e65e6U, 0xffe67eaaU, 0xbccf0821U, 0x15e8e6efU,
++    0xe79bd9baU, 0x6f36ce4aU, 0x9f09d4eaU, 0xb07cd629U,
++    0xa4b2af31U, 0x3f23312aU, 0xa59430c6U, 0xa266c035U,
++    0x4ebc3774U, 0x82caa6fcU, 0x90d0b0e0U, 0xa7d81533U,
++    0x04984af1U, 0xecdaf741U, 0xcd500e7fU, 0x91f62f17U,
++    0x4dd68d76U, 0xefb04d43U, 0xaa4d54ccU, 0x9604dfe4U,
++    0xd1b5e39eU, 0x6a881b4cU, 0x2c1fb8c1U, 0x65517f46U,
++    0x5eea049dU, 0x8c355d01U, 0x877473faU, 0x0b412efbU,
++    0x671d5ab3U, 0xdbd25292U, 0x105633e9U, 0xd647136dU,
++    0xd7618c9aU, 0xa10c7a37U, 0xf8148e59U, 0x133c89ebU,
++    0xa927eeceU, 0x61c935b7U, 0x1ce5ede1U, 0x47b13c7aU,
++    0xd2df599cU, 0xf2733f55U, 0x14ce7918U, 0xc737bf73U,
++    0xf7cdea53U, 0xfdaa5b5fU, 0x3d6f14dfU, 0x44db8678U,
++    0xaff381caU, 0x68c43eb9U, 0x24342c38U, 0xa3405fc2U,
++    0x1dc37216U, 0xe2250cbcU, 0x3c498b28U, 0x0d9541ffU,
++    0xa8017139U, 0x0cb3de08U, 0xb4e49cd8U, 0x56c19064U,
++    0xcb84617bU, 0x32b670d5U, 0x6c5c7448U, 0xb85742d0U,
++};
++static const u8 Td4[256] = {
++    0x52U, 0x09U, 0x6aU, 0xd5U, 0x30U, 0x36U, 0xa5U, 0x38U,
++    0xbfU, 0x40U, 0xa3U, 0x9eU, 0x81U, 0xf3U, 0xd7U, 0xfbU,
++    0x7cU, 0xe3U, 0x39U, 0x82U, 0x9bU, 0x2fU, 0xffU, 0x87U,
++    0x34U, 0x8eU, 0x43U, 0x44U, 0xc4U, 0xdeU, 0xe9U, 0xcbU,
++    0x54U, 0x7bU, 0x94U, 0x32U, 0xa6U, 0xc2U, 0x23U, 0x3dU,
++    0xeeU, 0x4cU, 0x95U, 0x0bU, 0x42U, 0xfaU, 0xc3U, 0x4eU,
++    0x08U, 0x2eU, 0xa1U, 0x66U, 0x28U, 0xd9U, 0x24U, 0xb2U,
++    0x76U, 0x5bU, 0xa2U, 0x49U, 0x6dU, 0x8bU, 0xd1U, 0x25U,
++    0x72U, 0xf8U, 0xf6U, 0x64U, 0x86U, 0x68U, 0x98U, 0x16U,
++    0xd4U, 0xa4U, 0x5cU, 0xccU, 0x5dU, 0x65U, 0xb6U, 0x92U,
++    0x6cU, 0x70U, 0x48U, 0x50U, 0xfdU, 0xedU, 0xb9U, 0xdaU,
++    0x5eU, 0x15U, 0x46U, 0x57U, 0xa7U, 0x8dU, 0x9dU, 0x84U,
++    0x90U, 0xd8U, 0xabU, 0x00U, 0x8cU, 0xbcU, 0xd3U, 0x0aU,
++    0xf7U, 0xe4U, 0x58U, 0x05U, 0xb8U, 0xb3U, 0x45U, 0x06U,
++    0xd0U, 0x2cU, 0x1eU, 0x8fU, 0xcaU, 0x3fU, 0x0fU, 0x02U,
++    0xc1U, 0xafU, 0xbdU, 0x03U, 0x01U, 0x13U, 0x8aU, 0x6bU,
++    0x3aU, 0x91U, 0x11U, 0x41U, 0x4fU, 0x67U, 0xdcU, 0xeaU,
++    0x97U, 0xf2U, 0xcfU, 0xceU, 0xf0U, 0xb4U, 0xe6U, 0x73U,
++    0x96U, 0xacU, 0x74U, 0x22U, 0xe7U, 0xadU, 0x35U, 0x85U,
++    0xe2U, 0xf9U, 0x37U, 0xe8U, 0x1cU, 0x75U, 0xdfU, 0x6eU,
++    0x47U, 0xf1U, 0x1aU, 0x71U, 0x1dU, 0x29U, 0xc5U, 0x89U,
++    0x6fU, 0xb7U, 0x62U, 0x0eU, 0xaaU, 0x18U, 0xbeU, 0x1bU,
++    0xfcU, 0x56U, 0x3eU, 0x4bU, 0xc6U, 0xd2U, 0x79U, 0x20U,
++    0x9aU, 0xdbU, 0xc0U, 0xfeU, 0x78U, 0xcdU, 0x5aU, 0xf4U,
++    0x1fU, 0xddU, 0xa8U, 0x33U, 0x88U, 0x07U, 0xc7U, 0x31U,
++    0xb1U, 0x12U, 0x10U, 0x59U, 0x27U, 0x80U, 0xecU, 0x5fU,
++    0x60U, 0x51U, 0x7fU, 0xa9U, 0x19U, 0xb5U, 0x4aU, 0x0dU,
++    0x2dU, 0xe5U, 0x7aU, 0x9fU, 0x93U, 0xc9U, 0x9cU, 0xefU,
++    0xa0U, 0xe0U, 0x3bU, 0x4dU, 0xaeU, 0x2aU, 0xf5U, 0xb0U,
++    0xc8U, 0xebU, 0xbbU, 0x3cU, 0x83U, 0x53U, 0x99U, 0x61U,
++    0x17U, 0x2bU, 0x04U, 0x7eU, 0xbaU, 0x77U, 0xd6U, 0x26U,
++    0xe1U, 0x69U, 0x14U, 0x63U, 0x55U, 0x21U, 0x0cU, 0x7dU,
++};
++static const u32 rcon[] = {
++    0x01000000, 0x02000000, 0x04000000, 0x08000000,
++    0x10000000, 0x20000000, 0x40000000, 0x80000000,
++    0x1B000000, 0x36000000, /* for 128-bit blocks, Rijndael never uses more than 10 rcon values */
++};
++
++/**
++ * Expand the cipher key into the encryption key schedule.
++ */
++int AES_set_encrypt_key(const unsigned char *userKey, const int bits,
++                        AES_KEY *key)
++{
++
++    u32 *rk;
++    int i = 0;
++    u32 temp;
++
++    if (!userKey || !key)
++        return -1;
++    if (bits != 128 && bits != 192 && bits != 256)
++        return -2;
++
++    rk = key->rd_key;
++
++    if (bits == 128)
++        key->rounds = 10;
++    else if (bits == 192)
++        key->rounds = 12;
++    else
++        key->rounds = 14;
++
++    rk[0] = GETU32(userKey     );
++    rk[1] = GETU32(userKey +  4);
++    rk[2] = GETU32(userKey +  8);
++    rk[3] = GETU32(userKey + 12);
++    if (bits == 128) {
++        while (1) {
++            temp  = rk[3];
++            rk[4] = rk[0] ^
++                (Te2[(temp >> 16) & 0xff] & 0xff000000) ^
++                (Te3[(temp >>  8) & 0xff] & 0x00ff0000) ^
++                (Te0[(temp      ) & 0xff] & 0x0000ff00) ^
++                (Te1[(temp >> 24)       ] & 0x000000ff) ^
++                rcon[i];
++            rk[5] = rk[1] ^ rk[4];
++            rk[6] = rk[2] ^ rk[5];
++            rk[7] = rk[3] ^ rk[6];
++            if (++i == 10) {
++                return 0;
++            }
++            rk += 4;
++        }
++    }
++    rk[4] = GETU32(userKey + 16);
++    rk[5] = GETU32(userKey + 20);
++    if (bits == 192) {
++        while (1) {
++            temp = rk[ 5];
++            rk[ 6] = rk[ 0] ^
++                (Te2[(temp >> 16) & 0xff] & 0xff000000) ^
++                (Te3[(temp >>  8) & 0xff] & 0x00ff0000) ^
++                (Te0[(temp      ) & 0xff] & 0x0000ff00) ^
++                (Te1[(temp >> 24)       ] & 0x000000ff) ^
++                rcon[i];
++            rk[ 7] = rk[ 1] ^ rk[ 6];
++            rk[ 8] = rk[ 2] ^ rk[ 7];
++            rk[ 9] = rk[ 3] ^ rk[ 8];
++            if (++i == 8) {
++                return 0;
++            }
++            rk[10] = rk[ 4] ^ rk[ 9];
++            rk[11] = rk[ 5] ^ rk[10];
++            rk += 6;
++        }
++    }
++    rk[6] = GETU32(userKey + 24);
++    rk[7] = GETU32(userKey + 28);
++    if (bits == 256) {
++        while (1) {
++            temp = rk[ 7];
++            rk[ 8] = rk[ 0] ^
++                (Te2[(temp >> 16) & 0xff] & 0xff000000) ^
++                (Te3[(temp >>  8) & 0xff] & 0x00ff0000) ^
++                (Te0[(temp      ) & 0xff] & 0x0000ff00) ^
++                (Te1[(temp >> 24)       ] & 0x000000ff) ^
++                rcon[i];
++            rk[ 9] = rk[ 1] ^ rk[ 8];
++            rk[10] = rk[ 2] ^ rk[ 9];
++            rk[11] = rk[ 3] ^ rk[10];
++            if (++i == 7) {
++                return 0;
++            }
++            temp = rk[11];
++            rk[12] = rk[ 4] ^
++                (Te2[(temp >> 24)       ] & 0xff000000) ^
++                (Te3[(temp >> 16) & 0xff] & 0x00ff0000) ^
++                (Te0[(temp >>  8) & 0xff] & 0x0000ff00) ^
++                (Te1[(temp      ) & 0xff] & 0x000000ff);
++            rk[13] = rk[ 5] ^ rk[12];
++            rk[14] = rk[ 6] ^ rk[13];
++            rk[15] = rk[ 7] ^ rk[14];
++
++            rk += 8;
++            }
++    }
++    return 0;
++}
++
++/**
++ * Expand the cipher key into the decryption key schedule.
++ */
++int AES_set_decrypt_key(const unsigned char *userKey, const int bits,
++                        AES_KEY *key)
++{
++
++    u32 *rk;
++    int i, j, status;
++    u32 temp;
++
++    /* first, start with an encryption schedule */
++    status = AES_set_encrypt_key(userKey, bits, key);
++    if (status < 0)
++        return status;
++
++    rk = key->rd_key;
++
++    /* invert the order of the round keys: */
++    for (i = 0, j = 4*(key->rounds); i < j; i += 4, j -= 4) {
++        temp = rk[i    ]; rk[i    ] = rk[j    ]; rk[j    ] = temp;
++        temp = rk[i + 1]; rk[i + 1] = rk[j + 1]; rk[j + 1] = temp;
++        temp = rk[i + 2]; rk[i + 2] = rk[j + 2]; rk[j + 2] = temp;
++        temp = rk[i + 3]; rk[i + 3] = rk[j + 3]; rk[j + 3] = temp;
++    }
++    /* apply the inverse MixColumn transform to all round keys but the first and the last: */
++    for (i = 1; i < (key->rounds); i++) {
++        rk += 4;
++        rk[0] =
++            Td0[Te1[(rk[0] >> 24)       ] & 0xff] ^
++            Td1[Te1[(rk[0] >> 16) & 0xff] & 0xff] ^
++            Td2[Te1[(rk[0] >>  8) & 0xff] & 0xff] ^
++            Td3[Te1[(rk[0]      ) & 0xff] & 0xff];
++        rk[1] =
++            Td0[Te1[(rk[1] >> 24)       ] & 0xff] ^
++            Td1[Te1[(rk[1] >> 16) & 0xff] & 0xff] ^
++            Td2[Te1[(rk[1] >>  8) & 0xff] & 0xff] ^
++            Td3[Te1[(rk[1]      ) & 0xff] & 0xff];
++        rk[2] =
++            Td0[Te1[(rk[2] >> 24)       ] & 0xff] ^
++            Td1[Te1[(rk[2] >> 16) & 0xff] & 0xff] ^
++            Td2[Te1[(rk[2] >>  8) & 0xff] & 0xff] ^
++            Td3[Te1[(rk[2]      ) & 0xff] & 0xff];
++        rk[3] =
++            Td0[Te1[(rk[3] >> 24)       ] & 0xff] ^
++            Td1[Te1[(rk[3] >> 16) & 0xff] & 0xff] ^
++            Td2[Te1[(rk[3] >>  8) & 0xff] & 0xff] ^
++            Td3[Te1[(rk[3]      ) & 0xff] & 0xff];
++    }
++    return 0;
++}
++
++/*
++ * Encrypt a single block
++ * in and out can overlap
++ */
++void AES_encrypt(const unsigned char *in, unsigned char *out,
++                 const AES_KEY *key) {
++
++    const u32 *rk;
++    u32 s0, s1, s2, s3, t0, t1, t2, t3;
++#ifndef FULL_UNROLL
++    int r;
++#endif /* ?FULL_UNROLL */
++
++    assert(in && out && key);
++    rk = key->rd_key;
++
++    /*
++     * map byte array block to cipher state
++     * and add initial round key:
++     */
++    s0 = GETU32(in     ) ^ rk[0];
++    s1 = GETU32(in +  4) ^ rk[1];
++    s2 = GETU32(in +  8) ^ rk[2];
++    s3 = GETU32(in + 12) ^ rk[3];
++#ifdef FULL_UNROLL
++    /* round 1: */
++    t0 = Te0[s0 >> 24] ^ Te1[(s1 >> 16) & 0xff] ^ Te2[(s2 >>  8) & 0xff] ^ Te3[s3 & 0xff] ^ rk[ 4];
++    t1 = Te0[s1 >> 24] ^ Te1[(s2 >> 16) & 0xff] ^ Te2[(s3 >>  8) & 0xff] ^ Te3[s0 & 0xff] ^ rk[ 5];
++    t2 = Te0[s2 >> 24] ^ Te1[(s3 >> 16) & 0xff] ^ Te2[(s0 >>  8) & 0xff] ^ Te3[s1 & 0xff] ^ rk[ 6];
++    t3 = Te0[s3 >> 24] ^ Te1[(s0 >> 16) & 0xff] ^ Te2[(s1 >>  8) & 0xff] ^ Te3[s2 & 0xff] ^ rk[ 7];
++    /* round 2: */
++    s0 = Te0[t0 >> 24] ^ Te1[(t1 >> 16) & 0xff] ^ Te2[(t2 >>  8) & 0xff] ^ Te3[t3 & 0xff] ^ rk[ 8];
++    s1 = Te0[t1 >> 24] ^ Te1[(t2 >> 16) & 0xff] ^ Te2[(t3 >>  8) & 0xff] ^ Te3[t0 & 0xff] ^ rk[ 9];
++    s2 = Te0[t2 >> 24] ^ Te1[(t3 >> 16) & 0xff] ^ Te2[(t0 >>  8) & 0xff] ^ Te3[t1 & 0xff] ^ rk[10];
++    s3 = Te0[t3 >> 24] ^ Te1[(t0 >> 16) & 0xff] ^ Te2[(t1 >>  8) & 0xff] ^ Te3[t2 & 0xff] ^ rk[11];
++    /* round 3: */
++    t0 = Te0[s0 >> 24] ^ Te1[(s1 >> 16) & 0xff] ^ Te2[(s2 >>  8) & 0xff] ^ Te3[s3 & 0xff] ^ rk[12];
++    t1 = Te0[s1 >> 24] ^ Te1[(s2 >> 16) & 0xff] ^ Te2[(s3 >>  8) & 0xff] ^ Te3[s0 & 0xff] ^ rk[13];
++    t2 = Te0[s2 >> 24] ^ Te1[(s3 >> 16) & 0xff] ^ Te2[(s0 >>  8) & 0xff] ^ Te3[s1 & 0xff] ^ rk[14];
++    t3 = Te0[s3 >> 24] ^ Te1[(s0 >> 16) & 0xff] ^ Te2[(s1 >>  8) & 0xff] ^ Te3[s2 & 0xff] ^ rk[15];
++    /* round 4: */
++    s0 = Te0[t0 >> 24] ^ Te1[(t1 >> 16) & 0xff] ^ Te2[(t2 >>  8) & 0xff] ^ Te3[t3 & 0xff] ^ rk[16];
++    s1 = Te0[t1 >> 24] ^ Te1[(t2 >> 16) & 0xff] ^ Te2[(t3 >>  8) & 0xff] ^ Te3[t0 & 0xff] ^ rk[17];
++    s2 = Te0[t2 >> 24] ^ Te1[(t3 >> 16) & 0xff] ^ Te2[(t0 >>  8) & 0xff] ^ Te3[t1 & 0xff] ^ rk[18];
++    s3 = Te0[t3 >> 24] ^ Te1[(t0 >> 16) & 0xff] ^ Te2[(t1 >>  8) & 0xff] ^ Te3[t2 & 0xff] ^ rk[19];
++    /* round 5: */
++    t0 = Te0[s0 >> 24] ^ Te1[(s1 >> 16) & 0xff] ^ Te2[(s2 >>  8) & 0xff] ^ Te3[s3 & 0xff] ^ rk[20];
++    t1 = Te0[s1 >> 24] ^ Te1[(s2 >> 16) & 0xff] ^ Te2[(s3 >>  8) & 0xff] ^ Te3[s0 & 0xff] ^ rk[21];
++    t2 = Te0[s2 >> 24] ^ Te1[(s3 >> 16) & 0xff] ^ Te2[(s0 >>  8) & 0xff] ^ Te3[s1 & 0xff] ^ rk[22];
++    t3 = Te0[s3 >> 24] ^ Te1[(s0 >> 16) & 0xff] ^ Te2[(s1 >>  8) & 0xff] ^ Te3[s2 & 0xff] ^ rk[23];
++    /* round 6: */
++    s0 = Te0[t0 >> 24] ^ Te1[(t1 >> 16) & 0xff] ^ Te2[(t2 >>  8) & 0xff] ^ Te3[t3 & 0xff] ^ rk[24];
++    s1 = Te0[t1 >> 24] ^ Te1[(t2 >> 16) & 0xff] ^ Te2[(t3 >>  8) & 0xff] ^ Te3[t0 & 0xff] ^ rk[25];
++    s2 = Te0[t2 >> 24] ^ Te1[(t3 >> 16) & 0xff] ^ Te2[(t0 >>  8) & 0xff] ^ Te3[t1 & 0xff] ^ rk[26];
++    s3 = Te0[t3 >> 24] ^ Te1[(t0 >> 16) & 0xff] ^ Te2[(t1 >>  8) & 0xff] ^ Te3[t2 & 0xff] ^ rk[27];
++    /* round 7: */
++    t0 = Te0[s0 >> 24] ^ Te1[(s1 >> 16) & 0xff] ^ Te2[(s2 >>  8) & 0xff] ^ Te3[s3 & 0xff] ^ rk[28];
++    t1 = Te0[s1 >> 24] ^ Te1[(s2 >> 16) & 0xff] ^ Te2[(s3 >>  8) & 0xff] ^ Te3[s0 & 0xff] ^ rk[29];
++    t2 = Te0[s2 >> 24] ^ Te1[(s3 >> 16) & 0xff] ^ Te2[(s0 >>  8) & 0xff] ^ Te3[s1 & 0xff] ^ rk[30];
++    t3 = Te0[s3 >> 24] ^ Te1[(s0 >> 16) & 0xff] ^ Te2[(s1 >>  8) & 0xff] ^ Te3[s2 & 0xff] ^ rk[31];
++    /* round 8: */
++    s0 = Te0[t0 >> 24] ^ Te1[(t1 >> 16) & 0xff] ^ Te2[(t2 >>  8) & 0xff] ^ Te3[t3 & 0xff] ^ rk[32];
++    s1 = Te0[t1 >> 24] ^ Te1[(t2 >> 16) & 0xff] ^ Te2[(t3 >>  8) & 0xff] ^ Te3[t0 & 0xff] ^ rk[33];
++    s2 = Te0[t2 >> 24] ^ Te1[(t3 >> 16) & 0xff] ^ Te2[(t0 >>  8) & 0xff] ^ Te3[t1 & 0xff] ^ rk[34];
++    s3 = Te0[t3 >> 24] ^ Te1[(t0 >> 16) & 0xff] ^ Te2[(t1 >>  8) & 0xff] ^ Te3[t2 & 0xff] ^ rk[35];
++    /* round 9: */
++    t0 = Te0[s0 >> 24] ^ Te1[(s1 >> 16) & 0xff] ^ Te2[(s2 >>  8) & 0xff] ^ Te3[s3 & 0xff] ^ rk[36];
++    t1 = Te0[s1 >> 24] ^ Te1[(s2 >> 16) & 0xff] ^ Te2[(s3 >>  8) & 0xff] ^ Te3[s0 & 0xff] ^ rk[37];
++    t2 = Te0[s2 >> 24] ^ Te1[(s3 >> 16) & 0xff] ^ Te2[(s0 >>  8) & 0xff] ^ Te3[s1 & 0xff] ^ rk[38];
++    t3 = Te0[s3 >> 24] ^ Te1[(s0 >> 16) & 0xff] ^ Te2[(s1 >>  8) & 0xff] ^ Te3[s2 & 0xff] ^ rk[39];
++    if (key->rounds > 10) {
++        /* round 10: */
++        s0 = Te0[t0 >> 24] ^ Te1[(t1 >> 16) & 0xff] ^ Te2[(t2 >>  8) & 0xff] ^ Te3[t3 & 0xff] ^ rk[40];
++        s1 = Te0[t1 >> 24] ^ Te1[(t2 >> 16) & 0xff] ^ Te2[(t3 >>  8) & 0xff] ^ Te3[t0 & 0xff] ^ rk[41];
++        s2 = Te0[t2 >> 24] ^ Te1[(t3 >> 16) & 0xff] ^ Te2[(t0 >>  8) & 0xff] ^ Te3[t1 & 0xff] ^ rk[42];
++        s3 = Te0[t3 >> 24] ^ Te1[(t0 >> 16) & 0xff] ^ Te2[(t1 >>  8) & 0xff] ^ Te3[t2 & 0xff] ^ rk[43];
++        /* round 11: */
++        t0 = Te0[s0 >> 24] ^ Te1[(s1 >> 16) & 0xff] ^ Te2[(s2 >>  8) & 0xff] ^ Te3[s3 & 0xff] ^ rk[44];
++        t1 = Te0[s1 >> 24] ^ Te1[(s2 >> 16) & 0xff] ^ Te2[(s3 >>  8) & 0xff] ^ Te3[s0 & 0xff] ^ rk[45];
++        t2 = Te0[s2 >> 24] ^ Te1[(s3 >> 16) & 0xff] ^ Te2[(s0 >>  8) & 0xff] ^ Te3[s1 & 0xff] ^ rk[46];
++        t3 = Te0[s3 >> 24] ^ Te1[(s0 >> 16) & 0xff] ^ Te2[(s1 >>  8) & 0xff] ^ Te3[s2 & 0xff] ^ rk[47];
++        if (key->rounds > 12) {
++            /* round 12: */
++            s0 = Te0[t0 >> 24] ^ Te1[(t1 >> 16) & 0xff] ^ Te2[(t2 >>  8) & 0xff] ^ Te3[t3 & 0xff] ^ rk[48];
++            s1 = Te0[t1 >> 24] ^ Te1[(t2 >> 16) & 0xff] ^ Te2[(t3 >>  8) & 0xff] ^ Te3[t0 & 0xff] ^ rk[49];
++            s2 = Te0[t2 >> 24] ^ Te1[(t3 >> 16) & 0xff] ^ Te2[(t0 >>  8) & 0xff] ^ Te3[t1 & 0xff] ^ rk[50];
++            s3 = Te0[t3 >> 24] ^ Te1[(t0 >> 16) & 0xff] ^ Te2[(t1 >>  8) & 0xff] ^ Te3[t2 & 0xff] ^ rk[51];
++            /* round 13: */
++            t0 = Te0[s0 >> 24] ^ Te1[(s1 >> 16) & 0xff] ^ Te2[(s2 >>  8) & 0xff] ^ Te3[s3 & 0xff] ^ rk[52];
++            t1 = Te0[s1 >> 24] ^ Te1[(s2 >> 16) & 0xff] ^ Te2[(s3 >>  8) & 0xff] ^ Te3[s0 & 0xff] ^ rk[53];
++            t2 = Te0[s2 >> 24] ^ Te1[(s3 >> 16) & 0xff] ^ Te2[(s0 >>  8) & 0xff] ^ Te3[s1 & 0xff] ^ rk[54];
++            t3 = Te0[s3 >> 24] ^ Te1[(s0 >> 16) & 0xff] ^ Te2[(s1 >>  8) & 0xff] ^ Te3[s2 & 0xff] ^ rk[55];
++        }
++    }
++    rk += key->rounds << 2;
++#else  /* !FULL_UNROLL */
++    /*
++     * Nr - 1 full rounds:
++     */
++    r = key->rounds >> 1;
++    for (;;) {
++        t0 =
++            Te0[(s0 >> 24)       ] ^
++            Te1[(s1 >> 16) & 0xff] ^
++            Te2[(s2 >>  8) & 0xff] ^
++            Te3[(s3      ) & 0xff] ^
++            rk[4];
++        t1 =
++            Te0[(s1 >> 24)       ] ^
++            Te1[(s2 >> 16) & 0xff] ^
++            Te2[(s3 >>  8) & 0xff] ^
++            Te3[(s0      ) & 0xff] ^
++            rk[5];
++        t2 =
++            Te0[(s2 >> 24)       ] ^
++            Te1[(s3 >> 16) & 0xff] ^
++            Te2[(s0 >>  8) & 0xff] ^
++            Te3[(s1      ) & 0xff] ^
++            rk[6];
++        t3 =
++            Te0[(s3 >> 24)       ] ^
++            Te1[(s0 >> 16) & 0xff] ^
++            Te2[(s1 >>  8) & 0xff] ^
++            Te3[(s2      ) & 0xff] ^
++            rk[7];
++
++        rk += 8;
++        if (--r == 0) {
++            break;
++        }
++
++        s0 =
++            Te0[(t0 >> 24)       ] ^
++            Te1[(t1 >> 16) & 0xff] ^
++            Te2[(t2 >>  8) & 0xff] ^
++            Te3[(t3      ) & 0xff] ^
++            rk[0];
++        s1 =
++            Te0[(t1 >> 24)       ] ^
++            Te1[(t2 >> 16) & 0xff] ^
++            Te2[(t3 >>  8) & 0xff] ^
++            Te3[(t0      ) & 0xff] ^
++            rk[1];
++        s2 =
++            Te0[(t2 >> 24)       ] ^
++            Te1[(t3 >> 16) & 0xff] ^
++            Te2[(t0 >>  8) & 0xff] ^
++            Te3[(t1      ) & 0xff] ^
++            rk[2];
++        s3 =
++            Te0[(t3 >> 24)       ] ^
++            Te1[(t0 >> 16) & 0xff] ^
++            Te2[(t1 >>  8) & 0xff] ^
++            Te3[(t2      ) & 0xff] ^
++            rk[3];
++    }
++#endif /* ?FULL_UNROLL */
++    /*
++     * apply last round and
++     * map cipher state to byte array block:
++     */
++    s0 =
++        (Te2[(t0 >> 24)       ] & 0xff000000) ^
++        (Te3[(t1 >> 16) & 0xff] & 0x00ff0000) ^
++        (Te0[(t2 >>  8) & 0xff] & 0x0000ff00) ^
++        (Te1[(t3      ) & 0xff] & 0x000000ff) ^
++        rk[0];
++    PUTU32(out     , s0);
++    s1 =
++        (Te2[(t1 >> 24)       ] & 0xff000000) ^
++        (Te3[(t2 >> 16) & 0xff] & 0x00ff0000) ^
++        (Te0[(t3 >>  8) & 0xff] & 0x0000ff00) ^
++        (Te1[(t0      ) & 0xff] & 0x000000ff) ^
++        rk[1];
++    PUTU32(out +  4, s1);
++    s2 =
++        (Te2[(t2 >> 24)       ] & 0xff000000) ^
++        (Te3[(t3 >> 16) & 0xff] & 0x00ff0000) ^
++        (Te0[(t0 >>  8) & 0xff] & 0x0000ff00) ^
++        (Te1[(t1      ) & 0xff] & 0x000000ff) ^
++        rk[2];
++    PUTU32(out +  8, s2);
++    s3 =
++        (Te2[(t3 >> 24)       ] & 0xff000000) ^
++        (Te3[(t0 >> 16) & 0xff] & 0x00ff0000) ^
++        (Te0[(t1 >>  8) & 0xff] & 0x0000ff00) ^
++        (Te1[(t2      ) & 0xff] & 0x000000ff) ^
++        rk[3];
++    PUTU32(out + 12, s3);
++}
++
++/*
++ * Decrypt a single block
++ * in and out can overlap
++ */
++void AES_decrypt(const unsigned char *in, unsigned char *out,
++                 const AES_KEY *key)
++{
++
++    const u32 *rk;
++    u32 s0, s1, s2, s3, t0, t1, t2, t3;
++#ifndef FULL_UNROLL
++    int r;
++#endif /* ?FULL_UNROLL */
++
++    assert(in && out && key);
++    rk = key->rd_key;
++
++    /*
++     * map byte array block to cipher state
++     * and add initial round key:
++     */
++    s0 = GETU32(in     ) ^ rk[0];
++    s1 = GETU32(in +  4) ^ rk[1];
++    s2 = GETU32(in +  8) ^ rk[2];
++    s3 = GETU32(in + 12) ^ rk[3];
++#ifdef FULL_UNROLL
++    /* round 1: */
++    t0 = Td0[s0 >> 24] ^ Td1[(s3 >> 16) & 0xff] ^ Td2[(s2 >>  8) & 0xff] ^ Td3[s1 & 0xff] ^ rk[ 4];
++    t1 = Td0[s1 >> 24] ^ Td1[(s0 >> 16) & 0xff] ^ Td2[(s3 >>  8) & 0xff] ^ Td3[s2 & 0xff] ^ rk[ 5];
++    t2 = Td0[s2 >> 24] ^ Td1[(s1 >> 16) & 0xff] ^ Td2[(s0 >>  8) & 0xff] ^ Td3[s3 & 0xff] ^ rk[ 6];
++    t3 = Td0[s3 >> 24] ^ Td1[(s2 >> 16) & 0xff] ^ Td2[(s1 >>  8) & 0xff] ^ Td3[s0 & 0xff] ^ rk[ 7];
++    /* round 2: */
++    s0 = Td0[t0 >> 24] ^ Td1[(t3 >> 16) & 0xff] ^ Td2[(t2 >>  8) & 0xff] ^ Td3[t1 & 0xff] ^ rk[ 8];
++    s1 = Td0[t1 >> 24] ^ Td1[(t0 >> 16) & 0xff] ^ Td2[(t3 >>  8) & 0xff] ^ Td3[t2 & 0xff] ^ rk[ 9];
++    s2 = Td0[t2 >> 24] ^ Td1[(t1 >> 16) & 0xff] ^ Td2[(t0 >>  8) & 0xff] ^ Td3[t3 & 0xff] ^ rk[10];
++    s3 = Td0[t3 >> 24] ^ Td1[(t2 >> 16) & 0xff] ^ Td2[(t1 >>  8) & 0xff] ^ Td3[t0 & 0xff] ^ rk[11];
++    /* round 3: */
++    t0 = Td0[s0 >> 24] ^ Td1[(s3 >> 16) & 0xff] ^ Td2[(s2 >>  8) & 0xff] ^ Td3[s1 & 0xff] ^ rk[12];
++    t1 = Td0[s1 >> 24] ^ Td1[(s0 >> 16) & 0xff] ^ Td2[(s3 >>  8) & 0xff] ^ Td3[s2 & 0xff] ^ rk[13];
++    t2 = Td0[s2 >> 24] ^ Td1[(s1 >> 16) & 0xff] ^ Td2[(s0 >>  8) & 0xff] ^ Td3[s3 & 0xff] ^ rk[14];
++    t3 = Td0[s3 >> 24] ^ Td1[(s2 >> 16) & 0xff] ^ Td2[(s1 >>  8) & 0xff] ^ Td3[s0 & 0xff] ^ rk[15];
++    /* round 4: */
++    s0 = Td0[t0 >> 24] ^ Td1[(t3 >> 16) & 0xff] ^ Td2[(t2 >>  8) & 0xff] ^ Td3[t1 & 0xff] ^ rk[16];
++    s1 = Td0[t1 >> 24] ^ Td1[(t0 >> 16) & 0xff] ^ Td2[(t3 >>  8) & 0xff] ^ Td3[t2 & 0xff] ^ rk[17];
++    s2 = Td0[t2 >> 24] ^ Td1[(t1 >> 16) & 0xff] ^ Td2[(t0 >>  8) & 0xff] ^ Td3[t3 & 0xff] ^ rk[18];
++    s3 = Td0[t3 >> 24] ^ Td1[(t2 >> 16) & 0xff] ^ Td2[(t1 >>  8) & 0xff] ^ Td3[t0 & 0xff] ^ rk[19];
++    /* round 5: */
++    t0 = Td0[s0 >> 24] ^ Td1[(s3 >> 16) & 0xff] ^ Td2[(s2 >>  8) & 0xff] ^ Td3[s1 & 0xff] ^ rk[20];
++    t1 = Td0[s1 >> 24] ^ Td1[(s0 >> 16) & 0xff] ^ Td2[(s3 >>  8) & 0xff] ^ Td3[s2 & 0xff] ^ rk[21];
++    t2 = Td0[s2 >> 24] ^ Td1[(s1 >> 16) & 0xff] ^ Td2[(s0 >>  8) & 0xff] ^ Td3[s3 & 0xff] ^ rk[22];
++    t3 = Td0[s3 >> 24] ^ Td1[(s2 >> 16) & 0xff] ^ Td2[(s1 >>  8) & 0xff] ^ Td3[s0 & 0xff] ^ rk[23];
++    /* round 6: */
++    s0 = Td0[t0 >> 24] ^ Td1[(t3 >> 16) & 0xff] ^ Td2[(t2 >>  8) & 0xff] ^ Td3[t1 & 0xff] ^ rk[24];
++    s1 = Td0[t1 >> 24] ^ Td1[(t0 >> 16) & 0xff] ^ Td2[(t3 >>  8) & 0xff] ^ Td3[t2 & 0xff] ^ rk[25];
++    s2 = Td0[t2 >> 24] ^ Td1[(t1 >> 16) & 0xff] ^ Td2[(t0 >>  8) & 0xff] ^ Td3[t3 & 0xff] ^ rk[26];
++    s3 = Td0[t3 >> 24] ^ Td1[(t2 >> 16) & 0xff] ^ Td2[(t1 >>  8) & 0xff] ^ Td3[t0 & 0xff] ^ rk[27];
++    /* round 7: */
++    t0 = Td0[s0 >> 24] ^ Td1[(s3 >> 16) & 0xff] ^ Td2[(s2 >>  8) & 0xff] ^ Td3[s1 & 0xff] ^ rk[28];
++    t1 = Td0[s1 >> 24] ^ Td1[(s0 >> 16) & 0xff] ^ Td2[(s3 >>  8) & 0xff] ^ Td3[s2 & 0xff] ^ rk[29];
++    t2 = Td0[s2 >> 24] ^ Td1[(s1 >> 16) & 0xff] ^ Td2[(s0 >>  8) & 0xff] ^ Td3[s3 & 0xff] ^ rk[30];
++    t3 = Td0[s3 >> 24] ^ Td1[(s2 >> 16) & 0xff] ^ Td2[(s1 >>  8) & 0xff] ^ Td3[s0 & 0xff] ^ rk[31];
++    /* round 8: */
++    s0 = Td0[t0 >> 24] ^ Td1[(t3 >> 16) & 0xff] ^ Td2[(t2 >>  8) & 0xff] ^ Td3[t1 & 0xff] ^ rk[32];
++    s1 = Td0[t1 >> 24] ^ Td1[(t0 >> 16) & 0xff] ^ Td2[(t3 >>  8) & 0xff] ^ Td3[t2 & 0xff] ^ rk[33];
++    s2 = Td0[t2 >> 24] ^ Td1[(t1 >> 16) & 0xff] ^ Td2[(t0 >>  8) & 0xff] ^ Td3[t3 & 0xff] ^ rk[34];
++    s3 = Td0[t3 >> 24] ^ Td1[(t2 >> 16) & 0xff] ^ Td2[(t1 >>  8) & 0xff] ^ Td3[t0 & 0xff] ^ rk[35];
++    /* round 9: */
++    t0 = Td0[s0 >> 24] ^ Td1[(s3 >> 16) & 0xff] ^ Td2[(s2 >>  8) & 0xff] ^ Td3[s1 & 0xff] ^ rk[36];
++    t1 = Td0[s1 >> 24] ^ Td1[(s0 >> 16) & 0xff] ^ Td2[(s3 >>  8) & 0xff] ^ Td3[s2 & 0xff] ^ rk[37];
++    t2 = Td0[s2 >> 24] ^ Td1[(s1 >> 16) & 0xff] ^ Td2[(s0 >>  8) & 0xff] ^ Td3[s3 & 0xff] ^ rk[38];
++    t3 = Td0[s3 >> 24] ^ Td1[(s2 >> 16) & 0xff] ^ Td2[(s1 >>  8) & 0xff] ^ Td3[s0 & 0xff] ^ rk[39];
++    if (key->rounds > 10) {
++        /* round 10: */
++        s0 = Td0[t0 >> 24] ^ Td1[(t3 >> 16) & 0xff] ^ Td2[(t2 >>  8) & 0xff] ^ Td3[t1 & 0xff] ^ rk[40];
++        s1 = Td0[t1 >> 24] ^ Td1[(t0 >> 16) & 0xff] ^ Td2[(t3 >>  8) & 0xff] ^ Td3[t2 & 0xff] ^ rk[41];
++        s2 = Td0[t2 >> 24] ^ Td1[(t1 >> 16) & 0xff] ^ Td2[(t0 >>  8) & 0xff] ^ Td3[t3 & 0xff] ^ rk[42];
++        s3 = Td0[t3 >> 24] ^ Td1[(t2 >> 16) & 0xff] ^ Td2[(t1 >>  8) & 0xff] ^ Td3[t0 & 0xff] ^ rk[43];
++        /* round 11: */
++        t0 = Td0[s0 >> 24] ^ Td1[(s3 >> 16) & 0xff] ^ Td2[(s2 >>  8) & 0xff] ^ Td3[s1 & 0xff] ^ rk[44];
++        t1 = Td0[s1 >> 24] ^ Td1[(s0 >> 16) & 0xff] ^ Td2[(s3 >>  8) & 0xff] ^ Td3[s2 & 0xff] ^ rk[45];
++        t2 = Td0[s2 >> 24] ^ Td1[(s1 >> 16) & 0xff] ^ Td2[(s0 >>  8) & 0xff] ^ Td3[s3 & 0xff] ^ rk[46];
++        t3 = Td0[s3 >> 24] ^ Td1[(s2 >> 16) & 0xff] ^ Td2[(s1 >>  8) & 0xff] ^ Td3[s0 & 0xff] ^ rk[47];
++        if (key->rounds > 12) {
++            /* round 12: */
++            s0 = Td0[t0 >> 24] ^ Td1[(t3 >> 16) & 0xff] ^ Td2[(t2 >>  8) & 0xff] ^ Td3[t1 & 0xff] ^ rk[48];
++            s1 = Td0[t1 >> 24] ^ Td1[(t0 >> 16) & 0xff] ^ Td2[(t3 >>  8) & 0xff] ^ Td3[t2 & 0xff] ^ rk[49];
++            s2 = Td0[t2 >> 24] ^ Td1[(t1 >> 16) & 0xff] ^ Td2[(t0 >>  8) & 0xff] ^ Td3[t3 & 0xff] ^ rk[50];
++            s3 = Td0[t3 >> 24] ^ Td1[(t2 >> 16) & 0xff] ^ Td2[(t1 >>  8) & 0xff] ^ Td3[t0 & 0xff] ^ rk[51];
++            /* round 13: */
++            t0 = Td0[s0 >> 24] ^ Td1[(s3 >> 16) & 0xff] ^ Td2[(s2 >>  8) & 0xff] ^ Td3[s1 & 0xff] ^ rk[52];
++            t1 = Td0[s1 >> 24] ^ Td1[(s0 >> 16) & 0xff] ^ Td2[(s3 >>  8) & 0xff] ^ Td3[s2 & 0xff] ^ rk[53];
++            t2 = Td0[s2 >> 24] ^ Td1[(s1 >> 16) & 0xff] ^ Td2[(s0 >>  8) & 0xff] ^ Td3[s3 & 0xff] ^ rk[54];
++            t3 = Td0[s3 >> 24] ^ Td1[(s2 >> 16) & 0xff] ^ Td2[(s1 >>  8) & 0xff] ^ Td3[s0 & 0xff] ^ rk[55];
++        }
++    }
++    rk += key->rounds << 2;
++#else  /* !FULL_UNROLL */
++    /*
++     * Nr - 1 full rounds:
++     */
++    r = key->rounds >> 1;
++    for (;;) {
++        t0 =
++            Td0[(s0 >> 24)       ] ^
++            Td1[(s3 >> 16) & 0xff] ^
++            Td2[(s2 >>  8) & 0xff] ^
++            Td3[(s1      ) & 0xff] ^
++            rk[4];
++        t1 =
++            Td0[(s1 >> 24)       ] ^
++            Td1[(s0 >> 16) & 0xff] ^
++            Td2[(s3 >>  8) & 0xff] ^
++            Td3[(s2      ) & 0xff] ^
++            rk[5];
++        t2 =
++            Td0[(s2 >> 24)       ] ^
++            Td1[(s1 >> 16) & 0xff] ^
++            Td2[(s0 >>  8) & 0xff] ^
++            Td3[(s3      ) & 0xff] ^
++            rk[6];
++        t3 =
++            Td0[(s3 >> 24)       ] ^
++            Td1[(s2 >> 16) & 0xff] ^
++            Td2[(s1 >>  8) & 0xff] ^
++            Td3[(s0      ) & 0xff] ^
++            rk[7];
++
++        rk += 8;
++        if (--r == 0) {
++            break;
++        }
++
++        s0 =
++            Td0[(t0 >> 24)       ] ^
++            Td1[(t3 >> 16) & 0xff] ^
++            Td2[(t2 >>  8) & 0xff] ^
++            Td3[(t1      ) & 0xff] ^
++            rk[0];
++        s1 =
++            Td0[(t1 >> 24)       ] ^
++            Td1[(t0 >> 16) & 0xff] ^
++            Td2[(t3 >>  8) & 0xff] ^
++            Td3[(t2      ) & 0xff] ^
++            rk[1];
++        s2 =
++            Td0[(t2 >> 24)       ] ^
++            Td1[(t1 >> 16) & 0xff] ^
++            Td2[(t0 >>  8) & 0xff] ^
++            Td3[(t3      ) & 0xff] ^
++            rk[2];
++        s3 =
++            Td0[(t3 >> 24)       ] ^
++            Td1[(t2 >> 16) & 0xff] ^
++            Td2[(t1 >>  8) & 0xff] ^
++            Td3[(t0      ) & 0xff] ^
++            rk[3];
++    }
++#endif /* ?FULL_UNROLL */
++    /*
++     * apply last round and
++     * map cipher state to byte array block:
++     */
++    s0 =
++        ((u32)Td4[(t0 >> 24)       ] << 24) ^
++        ((u32)Td4[(t3 >> 16) & 0xff] << 16) ^
++        ((u32)Td4[(t2 >>  8) & 0xff] <<  8) ^
++        ((u32)Td4[(t1      ) & 0xff])       ^
++        rk[0];
++    PUTU32(out     , s0);
++    s1 =
++        ((u32)Td4[(t1 >> 24)       ] << 24) ^
++        ((u32)Td4[(t0 >> 16) & 0xff] << 16) ^
++        ((u32)Td4[(t3 >>  8) & 0xff] <<  8) ^
++        ((u32)Td4[(t2      ) & 0xff])       ^
++        rk[1];
++    PUTU32(out +  4, s1);
++    s2 =
++        ((u32)Td4[(t2 >> 24)       ] << 24) ^
++        ((u32)Td4[(t1 >> 16) & 0xff] << 16) ^
++        ((u32)Td4[(t0 >>  8) & 0xff] <<  8) ^
++        ((u32)Td4[(t3      ) & 0xff])       ^
++        rk[2];
++    PUTU32(out +  8, s2);
++    s3 =
++        ((u32)Td4[(t3 >> 24)       ] << 24) ^
++        ((u32)Td4[(t2 >> 16) & 0xff] << 16) ^
++        ((u32)Td4[(t1 >>  8) & 0xff] <<  8) ^
++        ((u32)Td4[(t0      ) & 0xff])       ^
++        rk[3];
++    PUTU32(out + 12, s3);
++}
++
++#else /* AES_ASM */
++
++static const u8 Te4[256] = {
++    0x63U, 0x7cU, 0x77U, 0x7bU, 0xf2U, 0x6bU, 0x6fU, 0xc5U,
++    0x30U, 0x01U, 0x67U, 0x2bU, 0xfeU, 0xd7U, 0xabU, 0x76U,
++    0xcaU, 0x82U, 0xc9U, 0x7dU, 0xfaU, 0x59U, 0x47U, 0xf0U,
++    0xadU, 0xd4U, 0xa2U, 0xafU, 0x9cU, 0xa4U, 0x72U, 0xc0U,
++    0xb7U, 0xfdU, 0x93U, 0x26U, 0x36U, 0x3fU, 0xf7U, 0xccU,
++    0x34U, 0xa5U, 0xe5U, 0xf1U, 0x71U, 0xd8U, 0x31U, 0x15U,
++    0x04U, 0xc7U, 0x23U, 0xc3U, 0x18U, 0x96U, 0x05U, 0x9aU,
++    0x07U, 0x12U, 0x80U, 0xe2U, 0xebU, 0x27U, 0xb2U, 0x75U,
++    0x09U, 0x83U, 0x2cU, 0x1aU, 0x1bU, 0x6eU, 0x5aU, 0xa0U,
++    0x52U, 0x3bU, 0xd6U, 0xb3U, 0x29U, 0xe3U, 0x2fU, 0x84U,
++    0x53U, 0xd1U, 0x00U, 0xedU, 0x20U, 0xfcU, 0xb1U, 0x5bU,
++    0x6aU, 0xcbU, 0xbeU, 0x39U, 0x4aU, 0x4cU, 0x58U, 0xcfU,
++    0xd0U, 0xefU, 0xaaU, 0xfbU, 0x43U, 0x4dU, 0x33U, 0x85U,
++    0x45U, 0xf9U, 0x02U, 0x7fU, 0x50U, 0x3cU, 0x9fU, 0xa8U,
++    0x51U, 0xa3U, 0x40U, 0x8fU, 0x92U, 0x9dU, 0x38U, 0xf5U,
++    0xbcU, 0xb6U, 0xdaU, 0x21U, 0x10U, 0xffU, 0xf3U, 0xd2U,
++    0xcdU, 0x0cU, 0x13U, 0xecU, 0x5fU, 0x97U, 0x44U, 0x17U,
++    0xc4U, 0xa7U, 0x7eU, 0x3dU, 0x64U, 0x5dU, 0x19U, 0x73U,
++    0x60U, 0x81U, 0x4fU, 0xdcU, 0x22U, 0x2aU, 0x90U, 0x88U,
++    0x46U, 0xeeU, 0xb8U, 0x14U, 0xdeU, 0x5eU, 0x0bU, 0xdbU,
++    0xe0U, 0x32U, 0x3aU, 0x0aU, 0x49U, 0x06U, 0x24U, 0x5cU,
++    0xc2U, 0xd3U, 0xacU, 0x62U, 0x91U, 0x95U, 0xe4U, 0x79U,
++    0xe7U, 0xc8U, 0x37U, 0x6dU, 0x8dU, 0xd5U, 0x4eU, 0xa9U,
++    0x6cU, 0x56U, 0xf4U, 0xeaU, 0x65U, 0x7aU, 0xaeU, 0x08U,
++    0xbaU, 0x78U, 0x25U, 0x2eU, 0x1cU, 0xa6U, 0xb4U, 0xc6U,
++    0xe8U, 0xddU, 0x74U, 0x1fU, 0x4bU, 0xbdU, 0x8bU, 0x8aU,
++    0x70U, 0x3eU, 0xb5U, 0x66U, 0x48U, 0x03U, 0xf6U, 0x0eU,
++    0x61U, 0x35U, 0x57U, 0xb9U, 0x86U, 0xc1U, 0x1dU, 0x9eU,
++    0xe1U, 0xf8U, 0x98U, 0x11U, 0x69U, 0xd9U, 0x8eU, 0x94U,
++    0x9bU, 0x1eU, 0x87U, 0xe9U, 0xceU, 0x55U, 0x28U, 0xdfU,
++    0x8cU, 0xa1U, 0x89U, 0x0dU, 0xbfU, 0xe6U, 0x42U, 0x68U,
++    0x41U, 0x99U, 0x2dU, 0x0fU, 0xb0U, 0x54U, 0xbbU, 0x16U
++};
++static const u32 rcon[] = {
++    0x01000000, 0x02000000, 0x04000000, 0x08000000,
++    0x10000000, 0x20000000, 0x40000000, 0x80000000,
++    0x1B000000, 0x36000000, /* for 128-bit blocks, Rijndael never uses more than 10 rcon values */
++};
++
++/**
++ * Expand the cipher key into the encryption key schedule.
++ */
++int AES_set_encrypt_key(const unsigned char *userKey, const int bits,
++                        AES_KEY *key)
++{
++    u32 *rk;
++    int i = 0;
++    u32 temp;
++
++    if (!userKey || !key)
++        return -1;
++    if (bits != 128 && bits != 192 && bits != 256)
++        return -2;
++
++    rk = key->rd_key;
++
++    if (bits == 128)
++        key->rounds = 10;
++    else if (bits == 192)
++        key->rounds = 12;
++    else
++        key->rounds = 14;
++
++    rk[0] = GETU32(userKey     );
++    rk[1] = GETU32(userKey +  4);
++    rk[2] = GETU32(userKey +  8);
++    rk[3] = GETU32(userKey + 12);
++    if (bits == 128) {
++        while (1) {
++            temp  = rk[3];
++            rk[4] = rk[0] ^
++                ((u32)Te4[(temp >> 16) & 0xff] << 24) ^
++                ((u32)Te4[(temp >>  8) & 0xff] << 16) ^
++                ((u32)Te4[(temp      ) & 0xff] << 8) ^
++                ((u32)Te4[(temp >> 24)       ]) ^
++                rcon[i];
++            rk[5] = rk[1] ^ rk[4];
++            rk[6] = rk[2] ^ rk[5];
++            rk[7] = rk[3] ^ rk[6];
++            if (++i == 10) {
++                return 0;
++            }
++            rk += 4;
++        }
++    }
++    rk[4] = GETU32(userKey + 16);
++    rk[5] = GETU32(userKey + 20);
++    if (bits == 192) {
++        while (1) {
++            temp = rk[ 5];
++            rk[ 6] = rk[ 0] ^
++                ((u32)Te4[(temp >> 16) & 0xff] << 24) ^
++                ((u32)Te4[(temp >>  8) & 0xff] << 16) ^
++                ((u32)Te4[(temp      ) & 0xff] << 8) ^
++                ((u32)Te4[(temp >> 24)       ]) ^
++                rcon[i];
++            rk[ 7] = rk[ 1] ^ rk[ 6];
++            rk[ 8] = rk[ 2] ^ rk[ 7];
++            rk[ 9] = rk[ 3] ^ rk[ 8];
++            if (++i == 8) {
++                return 0;
++            }
++            rk[10] = rk[ 4] ^ rk[ 9];
++            rk[11] = rk[ 5] ^ rk[10];
++            rk += 6;
++        }
++    }
++    rk[6] = GETU32(userKey + 24);
++    rk[7] = GETU32(userKey + 28);
++    if (bits == 256) {
++        while (1) {
++            temp = rk[ 7];
++            rk[ 8] = rk[ 0] ^
++                ((u32)Te4[(temp >> 16) & 0xff] << 24) ^
++                ((u32)Te4[(temp >>  8) & 0xff] << 16) ^
++                ((u32)Te4[(temp      ) & 0xff] << 8) ^
++                ((u32)Te4[(temp >> 24)       ]) ^
++                rcon[i];
++            rk[ 9] = rk[ 1] ^ rk[ 8];
++            rk[10] = rk[ 2] ^ rk[ 9];
++            rk[11] = rk[ 3] ^ rk[10];
++            if (++i == 7) {
++                return 0;
++            }
++            temp = rk[11];
++            rk[12] = rk[ 4] ^
++                ((u32)Te4[(temp >> 24)       ] << 24) ^
++                ((u32)Te4[(temp >> 16) & 0xff] << 16) ^
++                ((u32)Te4[(temp >>  8) & 0xff] << 8) ^
++                ((u32)Te4[(temp      ) & 0xff]);
++            rk[13] = rk[ 5] ^ rk[12];
++            rk[14] = rk[ 6] ^ rk[13];
++            rk[15] = rk[ 7] ^ rk[14];
++
++            rk += 8;
++        }
++    }
++    return 0;
++}
++
++/**
++ * Expand the cipher key into the decryption key schedule.
++ */
++int AES_set_decrypt_key(const unsigned char *userKey, const int bits,
++                        AES_KEY *key)
++{
++
++    u32 *rk;
++    int i, j, status;
++    u32 temp;
++
++    /* first, start with an encryption schedule */
++    status = AES_set_encrypt_key(userKey, bits, key);
++    if (status < 0)
++        return status;
++
++    rk = key->rd_key;
++
++    /* invert the order of the round keys: */
++    for (i = 0, j = 4*(key->rounds); i < j; i += 4, j -= 4) {
++        temp = rk[i    ]; rk[i    ] = rk[j    ]; rk[j    ] = temp;
++        temp = rk[i + 1]; rk[i + 1] = rk[j + 1]; rk[j + 1] = temp;
++        temp = rk[i + 2]; rk[i + 2] = rk[j + 2]; rk[j + 2] = temp;
++        temp = rk[i + 3]; rk[i + 3] = rk[j + 3]; rk[j + 3] = temp;
++    }
++    /* apply the inverse MixColumn transform to all round keys but the first and the last: */
++    for (i = 1; i < (key->rounds); i++) {
++        rk += 4;
++        for (j = 0; j < 4; j++) {
++            u32 tp1, tp2, tp4, tp8, tp9, tpb, tpd, tpe, m;
++
++            tp1 = rk[j];
++            m = tp1 & 0x80808080;
++            tp2 = ((tp1 & 0x7f7f7f7f) << 1) ^
++                ((m - (m >> 7)) & 0x1b1b1b1b);
++            m = tp2 & 0x80808080;
++            tp4 = ((tp2 & 0x7f7f7f7f) << 1) ^
++                ((m - (m >> 7)) & 0x1b1b1b1b);
++            m = tp4 & 0x80808080;
++            tp8 = ((tp4 & 0x7f7f7f7f) << 1) ^
++                ((m - (m >> 7)) & 0x1b1b1b1b);
++            tp9 = tp8 ^ tp1;
++            tpb = tp9 ^ tp2;
++            tpd = tp9 ^ tp4;
++            tpe = tp8 ^ tp4 ^ tp2;
++#if defined(ROTATE)
++            rk[j] = tpe ^ ROTATE(tpd,16) ^
++                ROTATE(tp9,24) ^ ROTATE(tpb,8);
++#else
++            rk[j] = tpe ^ (tpd >> 16) ^ (tpd << 16) ^
++                (tp9 >> 8) ^ (tp9 << 24) ^
++                (tpb >> 24) ^ (tpb << 8);
++#endif
++        }
++    }
++    return 0;
++}
++
++#endif /* AES_ASM */
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/aes/aes_ecb.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/aes/aes_ecb.c
+new file mode 100644
+index 0000000..29bfc1a
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/aes/aes_ecb.c
+@@ -0,0 +1,26 @@
++/*
++ * Copyright 2002-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++
++#include 
++#include "aes_locl.h"
++
++void AES_ecb_encrypt(const unsigned char *in, unsigned char *out,
++                     const AES_KEY *key, const int enc)
++{
++
++    assert(in && out && key);
++    assert((AES_ENCRYPT == enc) || (AES_DECRYPT == enc));
++
++    if (AES_ENCRYPT == enc)
++        AES_encrypt(in, out, key);
++    else
++        AES_decrypt(in, out, key);
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/aes/aes_ige.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/aes/aes_ige.c
+new file mode 100644
+index 0000000..9125264
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/aes/aes_ige.c
+@@ -0,0 +1,281 @@
++/*
++ * Copyright 2006-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include "internal/cryptlib.h"
++
++#include 
++#include "aes_locl.h"
++
++#define N_WORDS (AES_BLOCK_SIZE / sizeof(unsigned long))
++typedef struct {
++    unsigned long data[N_WORDS];
++} aes_block_t;
++
++/* XXX: probably some better way to do this */
++#if defined(__i386__) || defined(__x86_64__)
++# define UNALIGNED_MEMOPS_ARE_FAST 1
++#else
++# define UNALIGNED_MEMOPS_ARE_FAST 0
++#endif
++
++#if UNALIGNED_MEMOPS_ARE_FAST
++# define load_block(d, s)        (d) = *(const aes_block_t *)(s)
++# define store_block(d, s)       *(aes_block_t *)(d) = (s)
++#else
++# define load_block(d, s)        memcpy((d).data, (s), AES_BLOCK_SIZE)
++# define store_block(d, s)       memcpy((d), (s).data, AES_BLOCK_SIZE)
++#endif
++
++/* N.B. The IV for this mode is _twice_ the block size */
++
++void AES_ige_encrypt(const unsigned char *in, unsigned char *out,
++                     size_t length, const AES_KEY *key,
++                     unsigned char *ivec, const int enc)
++{
++    size_t n;
++    size_t len = length;
++
++    OPENSSL_assert(in && out && key && ivec);
++    OPENSSL_assert((AES_ENCRYPT == enc) || (AES_DECRYPT == enc));
++    OPENSSL_assert((length % AES_BLOCK_SIZE) == 0);
++
++    len = length / AES_BLOCK_SIZE;
++
++    if (AES_ENCRYPT == enc) {
++        if (in != out &&
++            (UNALIGNED_MEMOPS_ARE_FAST
++             || ((size_t)in | (size_t)out | (size_t)ivec) % sizeof(long) ==
++             0)) {
++            aes_block_t *ivp = (aes_block_t *) ivec;
++            aes_block_t *iv2p = (aes_block_t *) (ivec + AES_BLOCK_SIZE);
++
++            while (len) {
++                aes_block_t *inp = (aes_block_t *) in;
++                aes_block_t *outp = (aes_block_t *) out;
++
++                for (n = 0; n < N_WORDS; ++n)
++                    outp->data[n] = inp->data[n] ^ ivp->data[n];
++                AES_encrypt((unsigned char *)outp->data,
++                            (unsigned char *)outp->data, key);
++                for (n = 0; n < N_WORDS; ++n)
++                    outp->data[n] ^= iv2p->data[n];
++                ivp = outp;
++                iv2p = inp;
++                --len;
++                in += AES_BLOCK_SIZE;
++                out += AES_BLOCK_SIZE;
++            }
++            memcpy(ivec, ivp->data, AES_BLOCK_SIZE);
++            memcpy(ivec + AES_BLOCK_SIZE, iv2p->data, AES_BLOCK_SIZE);
++        } else {
++            aes_block_t tmp, tmp2;
++            aes_block_t iv;
++            aes_block_t iv2;
++
++            load_block(iv, ivec);
++            load_block(iv2, ivec + AES_BLOCK_SIZE);
++
++            while (len) {
++                load_block(tmp, in);
++                for (n = 0; n < N_WORDS; ++n)
++                    tmp2.data[n] = tmp.data[n] ^ iv.data[n];
++                AES_encrypt((unsigned char *)tmp2.data,
++                            (unsigned char *)tmp2.data, key);
++                for (n = 0; n < N_WORDS; ++n)
++                    tmp2.data[n] ^= iv2.data[n];
++                store_block(out, tmp2);
++                iv = tmp2;
++                iv2 = tmp;
++                --len;
++                in += AES_BLOCK_SIZE;
++                out += AES_BLOCK_SIZE;
++            }
++            memcpy(ivec, iv.data, AES_BLOCK_SIZE);
++            memcpy(ivec + AES_BLOCK_SIZE, iv2.data, AES_BLOCK_SIZE);
++        }
++    } else {
++        if (in != out &&
++            (UNALIGNED_MEMOPS_ARE_FAST
++             || ((size_t)in | (size_t)out | (size_t)ivec) % sizeof(long) ==
++             0)) {
++            aes_block_t *ivp = (aes_block_t *) ivec;
++            aes_block_t *iv2p = (aes_block_t *) (ivec + AES_BLOCK_SIZE);
++
++            while (len) {
++                aes_block_t tmp;
++                aes_block_t *inp = (aes_block_t *) in;
++                aes_block_t *outp = (aes_block_t *) out;
++
++                for (n = 0; n < N_WORDS; ++n)
++                    tmp.data[n] = inp->data[n] ^ iv2p->data[n];
++                AES_decrypt((unsigned char *)tmp.data,
++                            (unsigned char *)outp->data, key);
++                for (n = 0; n < N_WORDS; ++n)
++                    outp->data[n] ^= ivp->data[n];
++                ivp = inp;
++                iv2p = outp;
++                --len;
++                in += AES_BLOCK_SIZE;
++                out += AES_BLOCK_SIZE;
++            }
++            memcpy(ivec, ivp->data, AES_BLOCK_SIZE);
++            memcpy(ivec + AES_BLOCK_SIZE, iv2p->data, AES_BLOCK_SIZE);
++        } else {
++            aes_block_t tmp, tmp2;
++            aes_block_t iv;
++            aes_block_t iv2;
++
++            load_block(iv, ivec);
++            load_block(iv2, ivec + AES_BLOCK_SIZE);
++
++            while (len) {
++                load_block(tmp, in);
++                tmp2 = tmp;
++                for (n = 0; n < N_WORDS; ++n)
++                    tmp.data[n] ^= iv2.data[n];
++                AES_decrypt((unsigned char *)tmp.data,
++                            (unsigned char *)tmp.data, key);
++                for (n = 0; n < N_WORDS; ++n)
++                    tmp.data[n] ^= iv.data[n];
++                store_block(out, tmp);
++                iv = tmp2;
++                iv2 = tmp;
++                --len;
++                in += AES_BLOCK_SIZE;
++                out += AES_BLOCK_SIZE;
++            }
++            memcpy(ivec, iv.data, AES_BLOCK_SIZE);
++            memcpy(ivec + AES_BLOCK_SIZE, iv2.data, AES_BLOCK_SIZE);
++        }
++    }
++}
++
++/*
++ * Note that its effectively impossible to do biIGE in anything other
++ * than a single pass, so no provision is made for chaining.
++ */
++
++/* N.B. The IV for this mode is _four times_ the block size */
++
++void AES_bi_ige_encrypt(const unsigned char *in, unsigned char *out,
++                        size_t length, const AES_KEY *key,
++                        const AES_KEY *key2, const unsigned char *ivec,
++                        const int enc)
++{
++    size_t n;
++    size_t len = length;
++    unsigned char tmp[AES_BLOCK_SIZE];
++    unsigned char tmp2[AES_BLOCK_SIZE];
++    unsigned char tmp3[AES_BLOCK_SIZE];
++    unsigned char prev[AES_BLOCK_SIZE];
++    const unsigned char *iv;
++    const unsigned char *iv2;
++
++    OPENSSL_assert(in && out && key && ivec);
++    OPENSSL_assert((AES_ENCRYPT == enc) || (AES_DECRYPT == enc));
++    OPENSSL_assert((length % AES_BLOCK_SIZE) == 0);
++
++    if (AES_ENCRYPT == enc) {
++        /*
++         * XXX: Do a separate case for when in != out (strictly should check
++         * for overlap, too)
++         */
++
++        /* First the forward pass */
++        iv = ivec;
++        iv2 = ivec + AES_BLOCK_SIZE;
++        while (len >= AES_BLOCK_SIZE) {
++            for (n = 0; n < AES_BLOCK_SIZE; ++n)
++                out[n] = in[n] ^ iv[n];
++            AES_encrypt(out, out, key);
++            for (n = 0; n < AES_BLOCK_SIZE; ++n)
++                out[n] ^= iv2[n];
++            iv = out;
++            memcpy(prev, in, AES_BLOCK_SIZE);
++            iv2 = prev;
++            len -= AES_BLOCK_SIZE;
++            in += AES_BLOCK_SIZE;
++            out += AES_BLOCK_SIZE;
++        }
++
++        /* And now backwards */
++        iv = ivec + AES_BLOCK_SIZE * 2;
++        iv2 = ivec + AES_BLOCK_SIZE * 3;
++        len = length;
++        while (len >= AES_BLOCK_SIZE) {
++            out -= AES_BLOCK_SIZE;
++            /*
++             * XXX: reduce copies by alternating between buffers
++             */
++            memcpy(tmp, out, AES_BLOCK_SIZE);
++            for (n = 0; n < AES_BLOCK_SIZE; ++n)
++                out[n] ^= iv[n];
++            /*
++             * hexdump(stdout, "out ^ iv", out, AES_BLOCK_SIZE);
++             */
++            AES_encrypt(out, out, key);
++            /*
++             * hexdump(stdout,"enc", out, AES_BLOCK_SIZE);
++             */
++            /*
++             * hexdump(stdout,"iv2", iv2, AES_BLOCK_SIZE);
++             */
++            for (n = 0; n < AES_BLOCK_SIZE; ++n)
++                out[n] ^= iv2[n];
++            /*
++             * hexdump(stdout,"out", out, AES_BLOCK_SIZE);
++             */
++            iv = out;
++            memcpy(prev, tmp, AES_BLOCK_SIZE);
++            iv2 = prev;
++            len -= AES_BLOCK_SIZE;
++        }
++    } else {
++        /* First backwards */
++        iv = ivec + AES_BLOCK_SIZE * 2;
++        iv2 = ivec + AES_BLOCK_SIZE * 3;
++        in += length;
++        out += length;
++        while (len >= AES_BLOCK_SIZE) {
++            in -= AES_BLOCK_SIZE;
++            out -= AES_BLOCK_SIZE;
++            memcpy(tmp, in, AES_BLOCK_SIZE);
++            memcpy(tmp2, in, AES_BLOCK_SIZE);
++            for (n = 0; n < AES_BLOCK_SIZE; ++n)
++                tmp[n] ^= iv2[n];
++            AES_decrypt(tmp, out, key);
++            for (n = 0; n < AES_BLOCK_SIZE; ++n)
++                out[n] ^= iv[n];
++            memcpy(tmp3, tmp2, AES_BLOCK_SIZE);
++            iv = tmp3;
++            iv2 = out;
++            len -= AES_BLOCK_SIZE;
++        }
++
++        /* And now forwards */
++        iv = ivec;
++        iv2 = ivec + AES_BLOCK_SIZE;
++        len = length;
++        while (len >= AES_BLOCK_SIZE) {
++            memcpy(tmp, out, AES_BLOCK_SIZE);
++            memcpy(tmp2, out, AES_BLOCK_SIZE);
++            for (n = 0; n < AES_BLOCK_SIZE; ++n)
++                tmp[n] ^= iv2[n];
++            AES_decrypt(tmp, out, key);
++            for (n = 0; n < AES_BLOCK_SIZE; ++n)
++                out[n] ^= iv[n];
++            memcpy(tmp3, tmp2, AES_BLOCK_SIZE);
++            iv = tmp3;
++            iv2 = out;
++            len -= AES_BLOCK_SIZE;
++            in += AES_BLOCK_SIZE;
++            out += AES_BLOCK_SIZE;
++        }
++    }
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/aes/aes_locl.h b/CryptoPkg/Library/OpensslLib/openssl/crypto/aes/aes_locl.h
+new file mode 100644
+index 0000000..adee29d
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/aes/aes_locl.h
+@@ -0,0 +1,42 @@
++/*
++ * Copyright 2002-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#ifndef HEADER_AES_LOCL_H
++# define HEADER_AES_LOCL_H
++
++# include 
++# include 
++# include 
++# include 
++
++# if defined(_MSC_VER) && (defined(_M_IX86) || defined(_M_AMD64) || defined(_M_X64))
++#  define SWAP(x) (_lrotl(x, 8) & 0x00ff00ff | _lrotr(x, 8) & 0xff00ff00)
++#  define GETU32(p) SWAP(*((u32 *)(p)))
++#  define PUTU32(ct, st) { *((u32 *)(ct)) = SWAP((st)); }
++# else
++#  define GETU32(pt) (((u32)(pt)[0] << 24) ^ ((u32)(pt)[1] << 16) ^ ((u32)(pt)[2] <<  8) ^ ((u32)(pt)[3]))
++#  define PUTU32(ct, st) { (ct)[0] = (u8)((st) >> 24); (ct)[1] = (u8)((st) >> 16); (ct)[2] = (u8)((st) >>  8); (ct)[3] = (u8)(st); }
++# endif
++
++# ifdef AES_LONG
++typedef unsigned long u32;
++# else
++typedef unsigned int u32;
++# endif
++typedef unsigned short u16;
++typedef unsigned char u8;
++
++# define MAXKC   (256/32)
++# define MAXKB   (256/8)
++# define MAXNR   14
++
++/* This controls loop-unrolling in aes_core.c */
++# undef FULL_UNROLL
++
++#endif                          /* !HEADER_AES_LOCL_H */
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/aes/aes_misc.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/aes/aes_misc.c
+new file mode 100644
+index 0000000..7403c84
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/aes/aes_misc.c
+@@ -0,0 +1,21 @@
++/*
++ * Copyright 2002-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include 
++#include "aes_locl.h"
++
++const char *AES_options(void)
++{
++#ifdef FULL_UNROLL
++    return "aes(full)";
++#else
++    return "aes(partial)";
++#endif
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/aes/aes_ofb.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/aes/aes_ofb.c
+new file mode 100644
+index 0000000..215b538
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/aes/aes_ofb.c
+@@ -0,0 +1,19 @@
++/*
++ * Copyright 2002-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include 
++
++void AES_ofb128_encrypt(const unsigned char *in, unsigned char *out,
++                        size_t length, const AES_KEY *key,
++                        unsigned char *ivec, int *num)
++{
++    CRYPTO_ofb128_encrypt(in, out, length, key, ivec, num,
++                          (block128_f) AES_encrypt);
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/aes/aes_wrap.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/aes/aes_wrap.c
+new file mode 100644
+index 0000000..cae0b21
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/aes/aes_wrap.c
+@@ -0,0 +1,27 @@
++/*
++ * Copyright 2008-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include "internal/cryptlib.h"
++#include 
++#include 
++
++int AES_wrap_key(AES_KEY *key, const unsigned char *iv,
++                 unsigned char *out,
++                 const unsigned char *in, unsigned int inlen)
++{
++    return CRYPTO_128_wrap(key, iv, out, in, inlen, (block128_f) AES_encrypt);
++}
++
++int AES_unwrap_key(AES_KEY *key, const unsigned char *iv,
++                   unsigned char *out,
++                   const unsigned char *in, unsigned int inlen)
++{
++    return CRYPTO_128_unwrap(key, iv, out, in, inlen,
++                             (block128_f) AES_decrypt);
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/aes/aes_x86core.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/aes/aes_x86core.c
+new file mode 100644
+index 0000000..95b49bb
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/aes/aes_x86core.c
+@@ -0,0 +1,1075 @@
++/*
++ * Copyright 2006-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++/**
++ * rijndael-alg-fst.c
++ *
++ * @version 3.0 (December 2000)
++ *
++ * Optimised ANSI C code for the Rijndael cipher (now AES)
++ *
++ * @author Vincent Rijmen 
++ * @author Antoon Bosselaers 
++ * @author Paulo Barreto 
++ *
++ * This code is hereby placed in the public domain.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ''AS IS'' AND ANY EXPRESS
++ * 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 AUTHORS OR 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 is experimental x86[_64] derivative. It assumes little-endian
++ * byte order and expects CPU to sustain unaligned memory references.
++ * It is used as playground for cache-time attack mitigations and
++ * serves as reference C implementation for x86[_64] assembler.
++ *
++ *                  
++ */
++
++
++#include 
++
++#include 
++#include 
++#include "aes_locl.h"
++
++/*
++ * These two parameters control which table, 256-byte or 2KB, is
++ * referenced in outer and respectively inner rounds.
++ */
++#define AES_COMPACT_IN_OUTER_ROUNDS
++#ifdef  AES_COMPACT_IN_OUTER_ROUNDS
++/* AES_COMPACT_IN_OUTER_ROUNDS costs ~30% in performance, while
++ * adding AES_COMPACT_IN_INNER_ROUNDS reduces benchmark *further*
++ * by factor of ~2. */
++# undef  AES_COMPACT_IN_INNER_ROUNDS
++#endif
++
++#if 1
++static void prefetch256(const void *table)
++{
++    volatile unsigned long *t=(void *)table,ret;
++    unsigned long sum;
++    int i;
++
++    /* 32 is common least cache-line size */
++    for (sum=0,i=0;i<256/sizeof(t[0]);i+=32/sizeof(t[0]))   sum ^= t[i];
++
++    ret = sum;
++}
++#else
++# define prefetch256(t)
++#endif
++
++#undef GETU32
++#define GETU32(p) (*((u32*)(p)))
++
++#if (defined(_WIN32) || defined(_WIN64)) && !defined(__MINGW32__)
++typedef unsigned __int64 u64;
++#define U64(C)  C##UI64
++#elif defined(__arch64__)
++typedef unsigned long u64;
++#define U64(C)  C##UL
++#else
++typedef unsigned long long u64;
++#define U64(C)  C##ULL
++#endif
++
++#undef ROTATE
++#if defined(_MSC_VER)
++# define ROTATE(a,n)    _lrotl(a,n)
++#elif defined(__ICC)
++# define ROTATE(a,n)    _rotl(a,n)
++#elif defined(__GNUC__) && __GNUC__>=2
++# if defined(__i386) || defined(__i386__) || defined(__x86_64) || defined(__x86_64__)
++#   define ROTATE(a,n)  ({ register unsigned int ret;   \
++                asm (           \
++                "roll %1,%0"        \
++                : "=r"(ret)     \
++                : "I"(n), "0"(a)    \
++                : "cc");        \
++               ret;             \
++            })
++# endif
++#endif
++/*-
++Te [x] = S [x].[02, 01, 01, 03, 02, 01, 01, 03];
++Te0[x] = S [x].[02, 01, 01, 03];
++Te1[x] = S [x].[03, 02, 01, 01];
++Te2[x] = S [x].[01, 03, 02, 01];
++Te3[x] = S [x].[01, 01, 03, 02];
++*/
++#define Te0 (u32)((u64*)((u8*)Te+0))
++#define Te1 (u32)((u64*)((u8*)Te+3))
++#define Te2 (u32)((u64*)((u8*)Te+2))
++#define Te3 (u32)((u64*)((u8*)Te+1))
++/*-
++Td [x] = Si[x].[0e, 09, 0d, 0b, 0e, 09, 0d, 0b];
++Td0[x] = Si[x].[0e, 09, 0d, 0b];
++Td1[x] = Si[x].[0b, 0e, 09, 0d];
++Td2[x] = Si[x].[0d, 0b, 0e, 09];
++Td3[x] = Si[x].[09, 0d, 0b, 0e];
++Td4[x] = Si[x].[01];
++*/
++#define Td0 (u32)((u64*)((u8*)Td+0))
++#define Td1 (u32)((u64*)((u8*)Td+3))
++#define Td2 (u32)((u64*)((u8*)Td+2))
++#define Td3 (u32)((u64*)((u8*)Td+1))
++
++static const u64 Te[256] = {
++    U64(0xa56363c6a56363c6), U64(0x847c7cf8847c7cf8),
++    U64(0x997777ee997777ee), U64(0x8d7b7bf68d7b7bf6),
++    U64(0x0df2f2ff0df2f2ff), U64(0xbd6b6bd6bd6b6bd6),
++    U64(0xb16f6fdeb16f6fde), U64(0x54c5c59154c5c591),
++    U64(0x5030306050303060), U64(0x0301010203010102),
++    U64(0xa96767cea96767ce), U64(0x7d2b2b567d2b2b56),
++    U64(0x19fefee719fefee7), U64(0x62d7d7b562d7d7b5),
++    U64(0xe6abab4de6abab4d), U64(0x9a7676ec9a7676ec),
++    U64(0x45caca8f45caca8f), U64(0x9d82821f9d82821f),
++    U64(0x40c9c98940c9c989), U64(0x877d7dfa877d7dfa),
++    U64(0x15fafaef15fafaef), U64(0xeb5959b2eb5959b2),
++    U64(0xc947478ec947478e), U64(0x0bf0f0fb0bf0f0fb),
++    U64(0xecadad41ecadad41), U64(0x67d4d4b367d4d4b3),
++    U64(0xfda2a25ffda2a25f), U64(0xeaafaf45eaafaf45),
++    U64(0xbf9c9c23bf9c9c23), U64(0xf7a4a453f7a4a453),
++    U64(0x967272e4967272e4), U64(0x5bc0c09b5bc0c09b),
++    U64(0xc2b7b775c2b7b775), U64(0x1cfdfde11cfdfde1),
++    U64(0xae93933dae93933d), U64(0x6a26264c6a26264c),
++    U64(0x5a36366c5a36366c), U64(0x413f3f7e413f3f7e),
++    U64(0x02f7f7f502f7f7f5), U64(0x4fcccc834fcccc83),
++    U64(0x5c3434685c343468), U64(0xf4a5a551f4a5a551),
++    U64(0x34e5e5d134e5e5d1), U64(0x08f1f1f908f1f1f9),
++    U64(0x937171e2937171e2), U64(0x73d8d8ab73d8d8ab),
++    U64(0x5331316253313162), U64(0x3f15152a3f15152a),
++    U64(0x0c0404080c040408), U64(0x52c7c79552c7c795),
++    U64(0x6523234665232346), U64(0x5ec3c39d5ec3c39d),
++    U64(0x2818183028181830), U64(0xa1969637a1969637),
++    U64(0x0f05050a0f05050a), U64(0xb59a9a2fb59a9a2f),
++    U64(0x0907070e0907070e), U64(0x3612122436121224),
++    U64(0x9b80801b9b80801b), U64(0x3de2e2df3de2e2df),
++    U64(0x26ebebcd26ebebcd), U64(0x6927274e6927274e),
++    U64(0xcdb2b27fcdb2b27f), U64(0x9f7575ea9f7575ea),
++    U64(0x1b0909121b090912), U64(0x9e83831d9e83831d),
++    U64(0x742c2c58742c2c58), U64(0x2e1a1a342e1a1a34),
++    U64(0x2d1b1b362d1b1b36), U64(0xb26e6edcb26e6edc),
++    U64(0xee5a5ab4ee5a5ab4), U64(0xfba0a05bfba0a05b),
++    U64(0xf65252a4f65252a4), U64(0x4d3b3b764d3b3b76),
++    U64(0x61d6d6b761d6d6b7), U64(0xceb3b37dceb3b37d),
++    U64(0x7b2929527b292952), U64(0x3ee3e3dd3ee3e3dd),
++    U64(0x712f2f5e712f2f5e), U64(0x9784841397848413),
++    U64(0xf55353a6f55353a6), U64(0x68d1d1b968d1d1b9),
++    U64(0x0000000000000000), U64(0x2cededc12cededc1),
++    U64(0x6020204060202040), U64(0x1ffcfce31ffcfce3),
++    U64(0xc8b1b179c8b1b179), U64(0xed5b5bb6ed5b5bb6),
++    U64(0xbe6a6ad4be6a6ad4), U64(0x46cbcb8d46cbcb8d),
++    U64(0xd9bebe67d9bebe67), U64(0x4b3939724b393972),
++    U64(0xde4a4a94de4a4a94), U64(0xd44c4c98d44c4c98),
++    U64(0xe85858b0e85858b0), U64(0x4acfcf854acfcf85),
++    U64(0x6bd0d0bb6bd0d0bb), U64(0x2aefefc52aefefc5),
++    U64(0xe5aaaa4fe5aaaa4f), U64(0x16fbfbed16fbfbed),
++    U64(0xc5434386c5434386), U64(0xd74d4d9ad74d4d9a),
++    U64(0x5533336655333366), U64(0x9485851194858511),
++    U64(0xcf45458acf45458a), U64(0x10f9f9e910f9f9e9),
++    U64(0x0602020406020204), U64(0x817f7ffe817f7ffe),
++    U64(0xf05050a0f05050a0), U64(0x443c3c78443c3c78),
++    U64(0xba9f9f25ba9f9f25), U64(0xe3a8a84be3a8a84b),
++    U64(0xf35151a2f35151a2), U64(0xfea3a35dfea3a35d),
++    U64(0xc0404080c0404080), U64(0x8a8f8f058a8f8f05),
++    U64(0xad92923fad92923f), U64(0xbc9d9d21bc9d9d21),
++    U64(0x4838387048383870), U64(0x04f5f5f104f5f5f1),
++    U64(0xdfbcbc63dfbcbc63), U64(0xc1b6b677c1b6b677),
++    U64(0x75dadaaf75dadaaf), U64(0x6321214263212142),
++    U64(0x3010102030101020), U64(0x1affffe51affffe5),
++    U64(0x0ef3f3fd0ef3f3fd), U64(0x6dd2d2bf6dd2d2bf),
++    U64(0x4ccdcd814ccdcd81), U64(0x140c0c18140c0c18),
++    U64(0x3513132635131326), U64(0x2fececc32fececc3),
++    U64(0xe15f5fbee15f5fbe), U64(0xa2979735a2979735),
++    U64(0xcc444488cc444488), U64(0x3917172e3917172e),
++    U64(0x57c4c49357c4c493), U64(0xf2a7a755f2a7a755),
++    U64(0x827e7efc827e7efc), U64(0x473d3d7a473d3d7a),
++    U64(0xac6464c8ac6464c8), U64(0xe75d5dbae75d5dba),
++    U64(0x2b1919322b191932), U64(0x957373e6957373e6),
++    U64(0xa06060c0a06060c0), U64(0x9881811998818119),
++    U64(0xd14f4f9ed14f4f9e), U64(0x7fdcdca37fdcdca3),
++    U64(0x6622224466222244), U64(0x7e2a2a547e2a2a54),
++    U64(0xab90903bab90903b), U64(0x8388880b8388880b),
++    U64(0xca46468cca46468c), U64(0x29eeeec729eeeec7),
++    U64(0xd3b8b86bd3b8b86b), U64(0x3c1414283c141428),
++    U64(0x79dedea779dedea7), U64(0xe25e5ebce25e5ebc),
++    U64(0x1d0b0b161d0b0b16), U64(0x76dbdbad76dbdbad),
++    U64(0x3be0e0db3be0e0db), U64(0x5632326456323264),
++    U64(0x4e3a3a744e3a3a74), U64(0x1e0a0a141e0a0a14),
++    U64(0xdb494992db494992), U64(0x0a06060c0a06060c),
++    U64(0x6c2424486c242448), U64(0xe45c5cb8e45c5cb8),
++    U64(0x5dc2c29f5dc2c29f), U64(0x6ed3d3bd6ed3d3bd),
++    U64(0xefacac43efacac43), U64(0xa66262c4a66262c4),
++    U64(0xa8919139a8919139), U64(0xa4959531a4959531),
++    U64(0x37e4e4d337e4e4d3), U64(0x8b7979f28b7979f2),
++    U64(0x32e7e7d532e7e7d5), U64(0x43c8c88b43c8c88b),
++    U64(0x5937376e5937376e), U64(0xb76d6ddab76d6dda),
++    U64(0x8c8d8d018c8d8d01), U64(0x64d5d5b164d5d5b1),
++    U64(0xd24e4e9cd24e4e9c), U64(0xe0a9a949e0a9a949),
++    U64(0xb46c6cd8b46c6cd8), U64(0xfa5656acfa5656ac),
++    U64(0x07f4f4f307f4f4f3), U64(0x25eaeacf25eaeacf),
++    U64(0xaf6565caaf6565ca), U64(0x8e7a7af48e7a7af4),
++    U64(0xe9aeae47e9aeae47), U64(0x1808081018080810),
++    U64(0xd5baba6fd5baba6f), U64(0x887878f0887878f0),
++    U64(0x6f25254a6f25254a), U64(0x722e2e5c722e2e5c),
++    U64(0x241c1c38241c1c38), U64(0xf1a6a657f1a6a657),
++    U64(0xc7b4b473c7b4b473), U64(0x51c6c69751c6c697),
++    U64(0x23e8e8cb23e8e8cb), U64(0x7cdddda17cdddda1),
++    U64(0x9c7474e89c7474e8), U64(0x211f1f3e211f1f3e),
++    U64(0xdd4b4b96dd4b4b96), U64(0xdcbdbd61dcbdbd61),
++    U64(0x868b8b0d868b8b0d), U64(0x858a8a0f858a8a0f),
++    U64(0x907070e0907070e0), U64(0x423e3e7c423e3e7c),
++    U64(0xc4b5b571c4b5b571), U64(0xaa6666ccaa6666cc),
++    U64(0xd8484890d8484890), U64(0x0503030605030306),
++    U64(0x01f6f6f701f6f6f7), U64(0x120e0e1c120e0e1c),
++    U64(0xa36161c2a36161c2), U64(0x5f35356a5f35356a),
++    U64(0xf95757aef95757ae), U64(0xd0b9b969d0b9b969),
++    U64(0x9186861791868617), U64(0x58c1c19958c1c199),
++    U64(0x271d1d3a271d1d3a), U64(0xb99e9e27b99e9e27),
++    U64(0x38e1e1d938e1e1d9), U64(0x13f8f8eb13f8f8eb),
++    U64(0xb398982bb398982b), U64(0x3311112233111122),
++    U64(0xbb6969d2bb6969d2), U64(0x70d9d9a970d9d9a9),
++    U64(0x898e8e07898e8e07), U64(0xa7949433a7949433),
++    U64(0xb69b9b2db69b9b2d), U64(0x221e1e3c221e1e3c),
++    U64(0x9287871592878715), U64(0x20e9e9c920e9e9c9),
++    U64(0x49cece8749cece87), U64(0xff5555aaff5555aa),
++    U64(0x7828285078282850), U64(0x7adfdfa57adfdfa5),
++    U64(0x8f8c8c038f8c8c03), U64(0xf8a1a159f8a1a159),
++    U64(0x8089890980898909), U64(0x170d0d1a170d0d1a),
++    U64(0xdabfbf65dabfbf65), U64(0x31e6e6d731e6e6d7),
++    U64(0xc6424284c6424284), U64(0xb86868d0b86868d0),
++    U64(0xc3414182c3414182), U64(0xb0999929b0999929),
++    U64(0x772d2d5a772d2d5a), U64(0x110f0f1e110f0f1e),
++    U64(0xcbb0b07bcbb0b07b), U64(0xfc5454a8fc5454a8),
++    U64(0xd6bbbb6dd6bbbb6d), U64(0x3a16162c3a16162c)
++};
++
++static const u8 Te4[256] = {
++    0x63U, 0x7cU, 0x77U, 0x7bU, 0xf2U, 0x6bU, 0x6fU, 0xc5U,
++    0x30U, 0x01U, 0x67U, 0x2bU, 0xfeU, 0xd7U, 0xabU, 0x76U,
++    0xcaU, 0x82U, 0xc9U, 0x7dU, 0xfaU, 0x59U, 0x47U, 0xf0U,
++    0xadU, 0xd4U, 0xa2U, 0xafU, 0x9cU, 0xa4U, 0x72U, 0xc0U,
++    0xb7U, 0xfdU, 0x93U, 0x26U, 0x36U, 0x3fU, 0xf7U, 0xccU,
++    0x34U, 0xa5U, 0xe5U, 0xf1U, 0x71U, 0xd8U, 0x31U, 0x15U,
++    0x04U, 0xc7U, 0x23U, 0xc3U, 0x18U, 0x96U, 0x05U, 0x9aU,
++    0x07U, 0x12U, 0x80U, 0xe2U, 0xebU, 0x27U, 0xb2U, 0x75U,
++    0x09U, 0x83U, 0x2cU, 0x1aU, 0x1bU, 0x6eU, 0x5aU, 0xa0U,
++    0x52U, 0x3bU, 0xd6U, 0xb3U, 0x29U, 0xe3U, 0x2fU, 0x84U,
++    0x53U, 0xd1U, 0x00U, 0xedU, 0x20U, 0xfcU, 0xb1U, 0x5bU,
++    0x6aU, 0xcbU, 0xbeU, 0x39U, 0x4aU, 0x4cU, 0x58U, 0xcfU,
++    0xd0U, 0xefU, 0xaaU, 0xfbU, 0x43U, 0x4dU, 0x33U, 0x85U,
++    0x45U, 0xf9U, 0x02U, 0x7fU, 0x50U, 0x3cU, 0x9fU, 0xa8U,
++    0x51U, 0xa3U, 0x40U, 0x8fU, 0x92U, 0x9dU, 0x38U, 0xf5U,
++    0xbcU, 0xb6U, 0xdaU, 0x21U, 0x10U, 0xffU, 0xf3U, 0xd2U,
++    0xcdU, 0x0cU, 0x13U, 0xecU, 0x5fU, 0x97U, 0x44U, 0x17U,
++    0xc4U, 0xa7U, 0x7eU, 0x3dU, 0x64U, 0x5dU, 0x19U, 0x73U,
++    0x60U, 0x81U, 0x4fU, 0xdcU, 0x22U, 0x2aU, 0x90U, 0x88U,
++    0x46U, 0xeeU, 0xb8U, 0x14U, 0xdeU, 0x5eU, 0x0bU, 0xdbU,
++    0xe0U, 0x32U, 0x3aU, 0x0aU, 0x49U, 0x06U, 0x24U, 0x5cU,
++    0xc2U, 0xd3U, 0xacU, 0x62U, 0x91U, 0x95U, 0xe4U, 0x79U,
++    0xe7U, 0xc8U, 0x37U, 0x6dU, 0x8dU, 0xd5U, 0x4eU, 0xa9U,
++    0x6cU, 0x56U, 0xf4U, 0xeaU, 0x65U, 0x7aU, 0xaeU, 0x08U,
++    0xbaU, 0x78U, 0x25U, 0x2eU, 0x1cU, 0xa6U, 0xb4U, 0xc6U,
++    0xe8U, 0xddU, 0x74U, 0x1fU, 0x4bU, 0xbdU, 0x8bU, 0x8aU,
++    0x70U, 0x3eU, 0xb5U, 0x66U, 0x48U, 0x03U, 0xf6U, 0x0eU,
++    0x61U, 0x35U, 0x57U, 0xb9U, 0x86U, 0xc1U, 0x1dU, 0x9eU,
++    0xe1U, 0xf8U, 0x98U, 0x11U, 0x69U, 0xd9U, 0x8eU, 0x94U,
++    0x9bU, 0x1eU, 0x87U, 0xe9U, 0xceU, 0x55U, 0x28U, 0xdfU,
++    0x8cU, 0xa1U, 0x89U, 0x0dU, 0xbfU, 0xe6U, 0x42U, 0x68U,
++    0x41U, 0x99U, 0x2dU, 0x0fU, 0xb0U, 0x54U, 0xbbU, 0x16U
++};
++
++static const u64 Td[256] = {
++    U64(0x50a7f45150a7f451), U64(0x5365417e5365417e),
++    U64(0xc3a4171ac3a4171a), U64(0x965e273a965e273a),
++    U64(0xcb6bab3bcb6bab3b), U64(0xf1459d1ff1459d1f),
++    U64(0xab58faacab58faac), U64(0x9303e34b9303e34b),
++    U64(0x55fa302055fa3020), U64(0xf66d76adf66d76ad),
++    U64(0x9176cc889176cc88), U64(0x254c02f5254c02f5),
++    U64(0xfcd7e54ffcd7e54f), U64(0xd7cb2ac5d7cb2ac5),
++    U64(0x8044352680443526), U64(0x8fa362b58fa362b5),
++    U64(0x495ab1de495ab1de), U64(0x671bba25671bba25),
++    U64(0x980eea45980eea45), U64(0xe1c0fe5de1c0fe5d),
++    U64(0x02752fc302752fc3), U64(0x12f04c8112f04c81),
++    U64(0xa397468da397468d), U64(0xc6f9d36bc6f9d36b),
++    U64(0xe75f8f03e75f8f03), U64(0x959c9215959c9215),
++    U64(0xeb7a6dbfeb7a6dbf), U64(0xda595295da595295),
++    U64(0x2d83bed42d83bed4), U64(0xd3217458d3217458),
++    U64(0x2969e0492969e049), U64(0x44c8c98e44c8c98e),
++    U64(0x6a89c2756a89c275), U64(0x78798ef478798ef4),
++    U64(0x6b3e58996b3e5899), U64(0xdd71b927dd71b927),
++    U64(0xb64fe1beb64fe1be), U64(0x17ad88f017ad88f0),
++    U64(0x66ac20c966ac20c9), U64(0xb43ace7db43ace7d),
++    U64(0x184adf63184adf63), U64(0x82311ae582311ae5),
++    U64(0x6033519760335197), U64(0x457f5362457f5362),
++    U64(0xe07764b1e07764b1), U64(0x84ae6bbb84ae6bbb),
++    U64(0x1ca081fe1ca081fe), U64(0x942b08f9942b08f9),
++    U64(0x5868487058684870), U64(0x19fd458f19fd458f),
++    U64(0x876cde94876cde94), U64(0xb7f87b52b7f87b52),
++    U64(0x23d373ab23d373ab), U64(0xe2024b72e2024b72),
++    U64(0x578f1fe3578f1fe3), U64(0x2aab55662aab5566),
++    U64(0x0728ebb20728ebb2), U64(0x03c2b52f03c2b52f),
++    U64(0x9a7bc5869a7bc586), U64(0xa50837d3a50837d3),
++    U64(0xf2872830f2872830), U64(0xb2a5bf23b2a5bf23),
++    U64(0xba6a0302ba6a0302), U64(0x5c8216ed5c8216ed),
++    U64(0x2b1ccf8a2b1ccf8a), U64(0x92b479a792b479a7),
++    U64(0xf0f207f3f0f207f3), U64(0xa1e2694ea1e2694e),
++    U64(0xcdf4da65cdf4da65), U64(0xd5be0506d5be0506),
++    U64(0x1f6234d11f6234d1), U64(0x8afea6c48afea6c4),
++    U64(0x9d532e349d532e34), U64(0xa055f3a2a055f3a2),
++    U64(0x32e18a0532e18a05), U64(0x75ebf6a475ebf6a4),
++    U64(0x39ec830b39ec830b), U64(0xaaef6040aaef6040),
++    U64(0x069f715e069f715e), U64(0x51106ebd51106ebd),
++    U64(0xf98a213ef98a213e), U64(0x3d06dd963d06dd96),
++    U64(0xae053eddae053edd), U64(0x46bde64d46bde64d),
++    U64(0xb58d5491b58d5491), U64(0x055dc471055dc471),
++    U64(0x6fd406046fd40604), U64(0xff155060ff155060),
++    U64(0x24fb981924fb9819), U64(0x97e9bdd697e9bdd6),
++    U64(0xcc434089cc434089), U64(0x779ed967779ed967),
++    U64(0xbd42e8b0bd42e8b0), U64(0x888b8907888b8907),
++    U64(0x385b19e7385b19e7), U64(0xdbeec879dbeec879),
++    U64(0x470a7ca1470a7ca1), U64(0xe90f427ce90f427c),
++    U64(0xc91e84f8c91e84f8), U64(0x0000000000000000),
++    U64(0x8386800983868009), U64(0x48ed2b3248ed2b32),
++    U64(0xac70111eac70111e), U64(0x4e725a6c4e725a6c),
++    U64(0xfbff0efdfbff0efd), U64(0x5638850f5638850f),
++    U64(0x1ed5ae3d1ed5ae3d), U64(0x27392d3627392d36),
++    U64(0x64d90f0a64d90f0a), U64(0x21a65c6821a65c68),
++    U64(0xd1545b9bd1545b9b), U64(0x3a2e36243a2e3624),
++    U64(0xb1670a0cb1670a0c), U64(0x0fe757930fe75793),
++    U64(0xd296eeb4d296eeb4), U64(0x9e919b1b9e919b1b),
++    U64(0x4fc5c0804fc5c080), U64(0xa220dc61a220dc61),
++    U64(0x694b775a694b775a), U64(0x161a121c161a121c),
++    U64(0x0aba93e20aba93e2), U64(0xe52aa0c0e52aa0c0),
++    U64(0x43e0223c43e0223c), U64(0x1d171b121d171b12),
++    U64(0x0b0d090e0b0d090e), U64(0xadc78bf2adc78bf2),
++    U64(0xb9a8b62db9a8b62d), U64(0xc8a91e14c8a91e14),
++    U64(0x8519f1578519f157), U64(0x4c0775af4c0775af),
++    U64(0xbbdd99eebbdd99ee), U64(0xfd607fa3fd607fa3),
++    U64(0x9f2601f79f2601f7), U64(0xbcf5725cbcf5725c),
++    U64(0xc53b6644c53b6644), U64(0x347efb5b347efb5b),
++    U64(0x7629438b7629438b), U64(0xdcc623cbdcc623cb),
++    U64(0x68fcedb668fcedb6), U64(0x63f1e4b863f1e4b8),
++    U64(0xcadc31d7cadc31d7), U64(0x1085634210856342),
++    U64(0x4022971340229713), U64(0x2011c6842011c684),
++    U64(0x7d244a857d244a85), U64(0xf83dbbd2f83dbbd2),
++    U64(0x1132f9ae1132f9ae), U64(0x6da129c76da129c7),
++    U64(0x4b2f9e1d4b2f9e1d), U64(0xf330b2dcf330b2dc),
++    U64(0xec52860dec52860d), U64(0xd0e3c177d0e3c177),
++    U64(0x6c16b32b6c16b32b), U64(0x99b970a999b970a9),
++    U64(0xfa489411fa489411), U64(0x2264e9472264e947),
++    U64(0xc48cfca8c48cfca8), U64(0x1a3ff0a01a3ff0a0),
++    U64(0xd82c7d56d82c7d56), U64(0xef903322ef903322),
++    U64(0xc74e4987c74e4987), U64(0xc1d138d9c1d138d9),
++    U64(0xfea2ca8cfea2ca8c), U64(0x360bd498360bd498),
++    U64(0xcf81f5a6cf81f5a6), U64(0x28de7aa528de7aa5),
++    U64(0x268eb7da268eb7da), U64(0xa4bfad3fa4bfad3f),
++    U64(0xe49d3a2ce49d3a2c), U64(0x0d9278500d927850),
++    U64(0x9bcc5f6a9bcc5f6a), U64(0x62467e5462467e54),
++    U64(0xc2138df6c2138df6), U64(0xe8b8d890e8b8d890),
++    U64(0x5ef7392e5ef7392e), U64(0xf5afc382f5afc382),
++    U64(0xbe805d9fbe805d9f), U64(0x7c93d0697c93d069),
++    U64(0xa92dd56fa92dd56f), U64(0xb31225cfb31225cf),
++    U64(0x3b99acc83b99acc8), U64(0xa77d1810a77d1810),
++    U64(0x6e639ce86e639ce8), U64(0x7bbb3bdb7bbb3bdb),
++    U64(0x097826cd097826cd), U64(0xf418596ef418596e),
++    U64(0x01b79aec01b79aec), U64(0xa89a4f83a89a4f83),
++    U64(0x656e95e6656e95e6), U64(0x7ee6ffaa7ee6ffaa),
++    U64(0x08cfbc2108cfbc21), U64(0xe6e815efe6e815ef),
++    U64(0xd99be7bad99be7ba), U64(0xce366f4ace366f4a),
++    U64(0xd4099fead4099fea), U64(0xd67cb029d67cb029),
++    U64(0xafb2a431afb2a431), U64(0x31233f2a31233f2a),
++    U64(0x3094a5c63094a5c6), U64(0xc066a235c066a235),
++    U64(0x37bc4e7437bc4e74), U64(0xa6ca82fca6ca82fc),
++    U64(0xb0d090e0b0d090e0), U64(0x15d8a73315d8a733),
++    U64(0x4a9804f14a9804f1), U64(0xf7daec41f7daec41),
++    U64(0x0e50cd7f0e50cd7f), U64(0x2ff691172ff69117),
++    U64(0x8dd64d768dd64d76), U64(0x4db0ef434db0ef43),
++    U64(0x544daacc544daacc), U64(0xdf0496e4df0496e4),
++    U64(0xe3b5d19ee3b5d19e), U64(0x1b886a4c1b886a4c),
++    U64(0xb81f2cc1b81f2cc1), U64(0x7f5165467f516546),
++    U64(0x04ea5e9d04ea5e9d), U64(0x5d358c015d358c01),
++    U64(0x737487fa737487fa), U64(0x2e410bfb2e410bfb),
++    U64(0x5a1d67b35a1d67b3), U64(0x52d2db9252d2db92),
++    U64(0x335610e9335610e9), U64(0x1347d66d1347d66d),
++    U64(0x8c61d79a8c61d79a), U64(0x7a0ca1377a0ca137),
++    U64(0x8e14f8598e14f859), U64(0x893c13eb893c13eb),
++    U64(0xee27a9ceee27a9ce), U64(0x35c961b735c961b7),
++    U64(0xede51ce1ede51ce1), U64(0x3cb1477a3cb1477a),
++    U64(0x59dfd29c59dfd29c), U64(0x3f73f2553f73f255),
++    U64(0x79ce141879ce1418), U64(0xbf37c773bf37c773),
++    U64(0xeacdf753eacdf753), U64(0x5baafd5f5baafd5f),
++    U64(0x146f3ddf146f3ddf), U64(0x86db447886db4478),
++    U64(0x81f3afca81f3afca), U64(0x3ec468b93ec468b9),
++    U64(0x2c3424382c342438), U64(0x5f40a3c25f40a3c2),
++    U64(0x72c31d1672c31d16), U64(0x0c25e2bc0c25e2bc),
++    U64(0x8b493c288b493c28), U64(0x41950dff41950dff),
++    U64(0x7101a8397101a839), U64(0xdeb30c08deb30c08),
++    U64(0x9ce4b4d89ce4b4d8), U64(0x90c1566490c15664),
++    U64(0x6184cb7b6184cb7b), U64(0x70b632d570b632d5),
++    U64(0x745c6c48745c6c48), U64(0x4257b8d04257b8d0)
++};
++static const u8 Td4[256] = {
++    0x52U, 0x09U, 0x6aU, 0xd5U, 0x30U, 0x36U, 0xa5U, 0x38U,
++    0xbfU, 0x40U, 0xa3U, 0x9eU, 0x81U, 0xf3U, 0xd7U, 0xfbU,
++    0x7cU, 0xe3U, 0x39U, 0x82U, 0x9bU, 0x2fU, 0xffU, 0x87U,
++    0x34U, 0x8eU, 0x43U, 0x44U, 0xc4U, 0xdeU, 0xe9U, 0xcbU,
++    0x54U, 0x7bU, 0x94U, 0x32U, 0xa6U, 0xc2U, 0x23U, 0x3dU,
++    0xeeU, 0x4cU, 0x95U, 0x0bU, 0x42U, 0xfaU, 0xc3U, 0x4eU,
++    0x08U, 0x2eU, 0xa1U, 0x66U, 0x28U, 0xd9U, 0x24U, 0xb2U,
++    0x76U, 0x5bU, 0xa2U, 0x49U, 0x6dU, 0x8bU, 0xd1U, 0x25U,
++    0x72U, 0xf8U, 0xf6U, 0x64U, 0x86U, 0x68U, 0x98U, 0x16U,
++    0xd4U, 0xa4U, 0x5cU, 0xccU, 0x5dU, 0x65U, 0xb6U, 0x92U,
++    0x6cU, 0x70U, 0x48U, 0x50U, 0xfdU, 0xedU, 0xb9U, 0xdaU,
++    0x5eU, 0x15U, 0x46U, 0x57U, 0xa7U, 0x8dU, 0x9dU, 0x84U,
++    0x90U, 0xd8U, 0xabU, 0x00U, 0x8cU, 0xbcU, 0xd3U, 0x0aU,
++    0xf7U, 0xe4U, 0x58U, 0x05U, 0xb8U, 0xb3U, 0x45U, 0x06U,
++    0xd0U, 0x2cU, 0x1eU, 0x8fU, 0xcaU, 0x3fU, 0x0fU, 0x02U,
++    0xc1U, 0xafU, 0xbdU, 0x03U, 0x01U, 0x13U, 0x8aU, 0x6bU,
++    0x3aU, 0x91U, 0x11U, 0x41U, 0x4fU, 0x67U, 0xdcU, 0xeaU,
++    0x97U, 0xf2U, 0xcfU, 0xceU, 0xf0U, 0xb4U, 0xe6U, 0x73U,
++    0x96U, 0xacU, 0x74U, 0x22U, 0xe7U, 0xadU, 0x35U, 0x85U,
++    0xe2U, 0xf9U, 0x37U, 0xe8U, 0x1cU, 0x75U, 0xdfU, 0x6eU,
++    0x47U, 0xf1U, 0x1aU, 0x71U, 0x1dU, 0x29U, 0xc5U, 0x89U,
++    0x6fU, 0xb7U, 0x62U, 0x0eU, 0xaaU, 0x18U, 0xbeU, 0x1bU,
++    0xfcU, 0x56U, 0x3eU, 0x4bU, 0xc6U, 0xd2U, 0x79U, 0x20U,
++    0x9aU, 0xdbU, 0xc0U, 0xfeU, 0x78U, 0xcdU, 0x5aU, 0xf4U,
++    0x1fU, 0xddU, 0xa8U, 0x33U, 0x88U, 0x07U, 0xc7U, 0x31U,
++    0xb1U, 0x12U, 0x10U, 0x59U, 0x27U, 0x80U, 0xecU, 0x5fU,
++    0x60U, 0x51U, 0x7fU, 0xa9U, 0x19U, 0xb5U, 0x4aU, 0x0dU,
++    0x2dU, 0xe5U, 0x7aU, 0x9fU, 0x93U, 0xc9U, 0x9cU, 0xefU,
++    0xa0U, 0xe0U, 0x3bU, 0x4dU, 0xaeU, 0x2aU, 0xf5U, 0xb0U,
++    0xc8U, 0xebU, 0xbbU, 0x3cU, 0x83U, 0x53U, 0x99U, 0x61U,
++    0x17U, 0x2bU, 0x04U, 0x7eU, 0xbaU, 0x77U, 0xd6U, 0x26U,
++    0xe1U, 0x69U, 0x14U, 0x63U, 0x55U, 0x21U, 0x0cU, 0x7dU
++};
++
++static const u32 rcon[] = {
++    0x00000001U, 0x00000002U, 0x00000004U, 0x00000008U,
++    0x00000010U, 0x00000020U, 0x00000040U, 0x00000080U,
++    0x0000001bU, 0x00000036U, /* for 128-bit blocks, Rijndael never uses more than 10 rcon values */
++};
++
++/**
++ * Expand the cipher key into the encryption key schedule.
++ */
++int AES_set_encrypt_key(const unsigned char *userKey, const int bits,
++                        AES_KEY *key)
++{
++
++    u32 *rk;
++    int i = 0;
++    u32 temp;
++
++    if (!userKey || !key)
++        return -1;
++    if (bits != 128 && bits != 192 && bits != 256)
++        return -2;
++
++    rk = key->rd_key;
++
++    if (bits==128)
++        key->rounds = 10;
++    else if (bits==192)
++        key->rounds = 12;
++    else
++        key->rounds = 14;
++
++    rk[0] = GETU32(userKey     );
++    rk[1] = GETU32(userKey +  4);
++    rk[2] = GETU32(userKey +  8);
++    rk[3] = GETU32(userKey + 12);
++    if (bits == 128) {
++        while (1) {
++            temp  = rk[3];
++            rk[4] = rk[0] ^
++                ((u32)Te4[(temp >>  8) & 0xff]      ) ^
++                ((u32)Te4[(temp >> 16) & 0xff] <<  8) ^
++                ((u32)Te4[(temp >> 24)       ] << 16) ^
++                ((u32)Te4[(temp      ) & 0xff] << 24) ^
++                rcon[i];
++            rk[5] = rk[1] ^ rk[4];
++            rk[6] = rk[2] ^ rk[5];
++            rk[7] = rk[3] ^ rk[6];
++            if (++i == 10) {
++                return 0;
++            }
++            rk += 4;
++        }
++    }
++    rk[4] = GETU32(userKey + 16);
++    rk[5] = GETU32(userKey + 20);
++    if (bits == 192) {
++        while (1) {
++            temp = rk[ 5];
++            rk[ 6] = rk[ 0] ^
++                ((u32)Te4[(temp >>  8) & 0xff]      ) ^
++                ((u32)Te4[(temp >> 16) & 0xff] <<  8) ^
++                ((u32)Te4[(temp >> 24)       ] << 16) ^
++                ((u32)Te4[(temp      ) & 0xff] << 24) ^
++                rcon[i];
++            rk[ 7] = rk[ 1] ^ rk[ 6];
++            rk[ 8] = rk[ 2] ^ rk[ 7];
++            rk[ 9] = rk[ 3] ^ rk[ 8];
++            if (++i == 8) {
++                return 0;
++            }
++            rk[10] = rk[ 4] ^ rk[ 9];
++            rk[11] = rk[ 5] ^ rk[10];
++            rk += 6;
++        }
++    }
++    rk[6] = GETU32(userKey + 24);
++    rk[7] = GETU32(userKey + 28);
++    if (bits == 256) {
++        while (1) {
++            temp = rk[ 7];
++            rk[ 8] = rk[ 0] ^
++                ((u32)Te4[(temp >>  8) & 0xff]      ) ^
++                ((u32)Te4[(temp >> 16) & 0xff] <<  8) ^
++                ((u32)Te4[(temp >> 24)       ] << 16) ^
++                ((u32)Te4[(temp      ) & 0xff] << 24) ^
++                rcon[i];
++            rk[ 9] = rk[ 1] ^ rk[ 8];
++            rk[10] = rk[ 2] ^ rk[ 9];
++            rk[11] = rk[ 3] ^ rk[10];
++            if (++i == 7) {
++                return 0;
++            }
++            temp = rk[11];
++            rk[12] = rk[ 4] ^
++                ((u32)Te4[(temp      ) & 0xff]      ) ^
++                ((u32)Te4[(temp >>  8) & 0xff] <<  8) ^
++                ((u32)Te4[(temp >> 16) & 0xff] << 16) ^
++                ((u32)Te4[(temp >> 24)       ] << 24);
++            rk[13] = rk[ 5] ^ rk[12];
++            rk[14] = rk[ 6] ^ rk[13];
++            rk[15] = rk[ 7] ^ rk[14];
++
++            rk += 8;
++            }
++    }
++    return 0;
++}
++
++/**
++ * Expand the cipher key into the decryption key schedule.
++ */
++int AES_set_decrypt_key(const unsigned char *userKey, const int bits,
++                        AES_KEY *key)
++{
++
++    u32 *rk;
++    int i, j, status;
++    u32 temp;
++
++    /* first, start with an encryption schedule */
++    status = AES_set_encrypt_key(userKey, bits, key);
++    if (status < 0)
++        return status;
++
++    rk = key->rd_key;
++
++    /* invert the order of the round keys: */
++    for (i = 0, j = 4*(key->rounds); i < j; i += 4, j -= 4) {
++        temp = rk[i    ]; rk[i    ] = rk[j    ]; rk[j    ] = temp;
++        temp = rk[i + 1]; rk[i + 1] = rk[j + 1]; rk[j + 1] = temp;
++        temp = rk[i + 2]; rk[i + 2] = rk[j + 2]; rk[j + 2] = temp;
++        temp = rk[i + 3]; rk[i + 3] = rk[j + 3]; rk[j + 3] = temp;
++    }
++    /* apply the inverse MixColumn transform to all round keys but the first and the last: */
++    for (i = 1; i < (key->rounds); i++) {
++        rk += 4;
++#if 1
++        for (j = 0; j < 4; j++) {
++            u32 tp1, tp2, tp4, tp8, tp9, tpb, tpd, tpe, m;
++
++            tp1 = rk[j];
++            m = tp1 & 0x80808080;
++            tp2 = ((tp1 & 0x7f7f7f7f) << 1) ^
++                ((m - (m >> 7)) & 0x1b1b1b1b);
++            m = tp2 & 0x80808080;
++            tp4 = ((tp2 & 0x7f7f7f7f) << 1) ^
++                ((m - (m >> 7)) & 0x1b1b1b1b);
++            m = tp4 & 0x80808080;
++            tp8 = ((tp4 & 0x7f7f7f7f) << 1) ^
++                ((m - (m >> 7)) & 0x1b1b1b1b);
++            tp9 = tp8 ^ tp1;
++            tpb = tp9 ^ tp2;
++            tpd = tp9 ^ tp4;
++            tpe = tp8 ^ tp4 ^ tp2;
++#if defined(ROTATE)
++            rk[j] = tpe ^ ROTATE(tpd,16) ^
++                ROTATE(tp9,8) ^ ROTATE(tpb,24);
++#else
++            rk[j] = tpe ^ (tpd >> 16) ^ (tpd << 16) ^
++                (tp9 >> 24) ^ (tp9 << 8) ^
++                (tpb >> 8) ^ (tpb << 24);
++#endif
++        }
++#else
++        rk[0] =
++            Td0[Te2[(rk[0]      ) & 0xff] & 0xff] ^
++            Td1[Te2[(rk[0] >>  8) & 0xff] & 0xff] ^
++            Td2[Te2[(rk[0] >> 16) & 0xff] & 0xff] ^
++            Td3[Te2[(rk[0] >> 24)       ] & 0xff];
++        rk[1] =
++            Td0[Te2[(rk[1]      ) & 0xff] & 0xff] ^
++            Td1[Te2[(rk[1] >>  8) & 0xff] & 0xff] ^
++            Td2[Te2[(rk[1] >> 16) & 0xff] & 0xff] ^
++            Td3[Te2[(rk[1] >> 24)       ] & 0xff];
++        rk[2] =
++            Td0[Te2[(rk[2]      ) & 0xff] & 0xff] ^
++            Td1[Te2[(rk[2] >>  8) & 0xff] & 0xff] ^
++            Td2[Te2[(rk[2] >> 16) & 0xff] & 0xff] ^
++            Td3[Te2[(rk[2] >> 24)       ] & 0xff];
++        rk[3] =
++            Td0[Te2[(rk[3]      ) & 0xff] & 0xff] ^
++            Td1[Te2[(rk[3] >>  8) & 0xff] & 0xff] ^
++            Td2[Te2[(rk[3] >> 16) & 0xff] & 0xff] ^
++            Td3[Te2[(rk[3] >> 24)       ] & 0xff];
++#endif
++    }
++    return 0;
++}
++
++/*
++ * Encrypt a single block
++ * in and out can overlap
++ */
++void AES_encrypt(const unsigned char *in, unsigned char *out,
++                 const AES_KEY *key)
++{
++
++    const u32 *rk;
++    u32 s0, s1, s2, s3, t[4];
++    int r;
++
++    assert(in && out && key);
++    rk = key->rd_key;
++
++    /*
++     * map byte array block to cipher state
++     * and add initial round key:
++     */
++    s0 = GETU32(in     ) ^ rk[0];
++    s1 = GETU32(in +  4) ^ rk[1];
++    s2 = GETU32(in +  8) ^ rk[2];
++    s3 = GETU32(in + 12) ^ rk[3];
++
++#if defined(AES_COMPACT_IN_OUTER_ROUNDS)
++    prefetch256(Te4);
++
++    t[0] = (u32)Te4[(s0      ) & 0xff]       ^
++           (u32)Te4[(s1 >>  8) & 0xff] <<  8 ^
++           (u32)Te4[(s2 >> 16) & 0xff] << 16 ^
++           (u32)Te4[(s3 >> 24)       ] << 24;
++    t[1] = (u32)Te4[(s1      ) & 0xff]       ^
++           (u32)Te4[(s2 >>  8) & 0xff] <<  8 ^
++           (u32)Te4[(s3 >> 16) & 0xff] << 16 ^
++           (u32)Te4[(s0 >> 24)       ] << 24;
++    t[2] = (u32)Te4[(s2      ) & 0xff]       ^
++           (u32)Te4[(s3 >>  8) & 0xff] <<  8 ^
++           (u32)Te4[(s0 >> 16) & 0xff] << 16 ^
++           (u32)Te4[(s1 >> 24)       ] << 24;
++    t[3] = (u32)Te4[(s3      ) & 0xff]       ^
++           (u32)Te4[(s0 >>  8) & 0xff] <<  8 ^
++           (u32)Te4[(s1 >> 16) & 0xff] << 16 ^
++           (u32)Te4[(s2 >> 24)       ] << 24;
++
++    /* now do the linear transform using words */
++    {   int i;
++        u32 r0, r1, r2;
++
++        for (i = 0; i < 4; i++) {
++            r0 = t[i];
++            r1 = r0 & 0x80808080;
++            r2 = ((r0 & 0x7f7f7f7f) << 1) ^
++                ((r1 - (r1 >> 7)) & 0x1b1b1b1b);
++#if defined(ROTATE)
++            t[i] = r2 ^ ROTATE(r2,24) ^ ROTATE(r0,24) ^
++                ROTATE(r0,16) ^ ROTATE(r0,8);
++#else
++            t[i] = r2 ^ ((r2 ^ r0) << 24) ^ ((r2 ^ r0) >> 8) ^
++                (r0 << 16) ^ (r0 >> 16) ^
++                (r0 << 8) ^ (r0 >> 24);
++#endif
++            t[i] ^= rk[4+i];
++        }
++    }
++#else
++    t[0] =  Te0[(s0      ) & 0xff] ^
++        Te1[(s1 >>  8) & 0xff] ^
++        Te2[(s2 >> 16) & 0xff] ^
++        Te3[(s3 >> 24)       ] ^
++        rk[4];
++    t[1] =  Te0[(s1      ) & 0xff] ^
++        Te1[(s2 >>  8) & 0xff] ^
++        Te2[(s3 >> 16) & 0xff] ^
++        Te3[(s0 >> 24)       ] ^
++        rk[5];
++    t[2] =  Te0[(s2      ) & 0xff] ^
++        Te1[(s3 >>  8) & 0xff] ^
++        Te2[(s0 >> 16) & 0xff] ^
++        Te3[(s1 >> 24)       ] ^
++        rk[6];
++    t[3] =  Te0[(s3      ) & 0xff] ^
++        Te1[(s0 >>  8) & 0xff] ^
++        Te2[(s1 >> 16) & 0xff] ^
++        Te3[(s2 >> 24)       ] ^
++        rk[7];
++#endif
++    s0 = t[0]; s1 = t[1]; s2 = t[2]; s3 = t[3];
++
++    /*
++     * Nr - 2 full rounds:
++     */
++    for (rk+=8,r=key->rounds-2; r>0; rk+=4,r--) {
++#if defined(AES_COMPACT_IN_INNER_ROUNDS)
++        t[0] = (u32)Te4[(s0      ) & 0xff]       ^
++               (u32)Te4[(s1 >>  8) & 0xff] <<  8 ^
++               (u32)Te4[(s2 >> 16) & 0xff] << 16 ^
++               (u32)Te4[(s3 >> 24)       ] << 24;
++        t[1] = (u32)Te4[(s1      ) & 0xff]       ^
++               (u32)Te4[(s2 >>  8) & 0xff] <<  8 ^
++               (u32)Te4[(s3 >> 16) & 0xff] << 16 ^
++               (u32)Te4[(s0 >> 24)       ] << 24;
++        t[2] = (u32)Te4[(s2      ) & 0xff]       ^
++               (u32)Te4[(s3 >>  8) & 0xff] <<  8 ^
++               (u32)Te4[(s0 >> 16) & 0xff] << 16 ^
++               (u32)Te4[(s1 >> 24)       ] << 24;
++        t[3] = (u32)Te4[(s3      ) & 0xff]       ^
++               (u32)Te4[(s0 >>  8) & 0xff] <<  8 ^
++               (u32)Te4[(s1 >> 16) & 0xff] << 16 ^
++               (u32)Te4[(s2 >> 24)       ] << 24;
++
++        /* now do the linear transform using words */
++        {
++            int i;
++            u32 r0, r1, r2;
++
++            for (i = 0; i < 4; i++) {
++                r0 = t[i];
++                r1 = r0 & 0x80808080;
++                r2 = ((r0 & 0x7f7f7f7f) << 1) ^
++                    ((r1 - (r1 >> 7)) & 0x1b1b1b1b);
++#if defined(ROTATE)
++                t[i] = r2 ^ ROTATE(r2,24) ^ ROTATE(r0,24) ^
++                    ROTATE(r0,16) ^ ROTATE(r0,8);
++#else
++                t[i] = r2 ^ ((r2 ^ r0) << 24) ^ ((r2 ^ r0) >> 8) ^
++                    (r0 << 16) ^ (r0 >> 16) ^
++                    (r0 << 8) ^ (r0 >> 24);
++#endif
++                t[i] ^= rk[i];
++            }
++        }
++#else
++        t[0] =  Te0[(s0      ) & 0xff] ^
++            Te1[(s1 >>  8) & 0xff] ^
++            Te2[(s2 >> 16) & 0xff] ^
++            Te3[(s3 >> 24)       ] ^
++            rk[0];
++        t[1] =  Te0[(s1      ) & 0xff] ^
++            Te1[(s2 >>  8) & 0xff] ^
++            Te2[(s3 >> 16) & 0xff] ^
++            Te3[(s0 >> 24)       ] ^
++            rk[1];
++        t[2] =  Te0[(s2      ) & 0xff] ^
++            Te1[(s3 >>  8) & 0xff] ^
++            Te2[(s0 >> 16) & 0xff] ^
++            Te3[(s1 >> 24)       ] ^
++            rk[2];
++        t[3] =  Te0[(s3      ) & 0xff] ^
++            Te1[(s0 >>  8) & 0xff] ^
++            Te2[(s1 >> 16) & 0xff] ^
++            Te3[(s2 >> 24)       ] ^
++            rk[3];
++#endif
++        s0 = t[0]; s1 = t[1]; s2 = t[2]; s3 = t[3];
++    }
++    /*
++     * apply last round and
++     * map cipher state to byte array block:
++     */
++#if defined(AES_COMPACT_IN_OUTER_ROUNDS)
++    prefetch256(Te4);
++
++    *(u32*)(out+0) =
++           (u32)Te4[(s0      ) & 0xff]       ^
++           (u32)Te4[(s1 >>  8) & 0xff] <<  8 ^
++           (u32)Te4[(s2 >> 16) & 0xff] << 16 ^
++           (u32)Te4[(s3 >> 24)       ] << 24 ^
++        rk[0];
++    *(u32*)(out+4) =
++           (u32)Te4[(s1      ) & 0xff]       ^
++           (u32)Te4[(s2 >>  8) & 0xff] <<  8 ^
++           (u32)Te4[(s3 >> 16) & 0xff] << 16 ^
++           (u32)Te4[(s0 >> 24)       ] << 24 ^
++        rk[1];
++    *(u32*)(out+8) =
++           (u32)Te4[(s2      ) & 0xff]       ^
++           (u32)Te4[(s3 >>  8) & 0xff] <<  8 ^
++           (u32)Te4[(s0 >> 16) & 0xff] << 16 ^
++           (u32)Te4[(s1 >> 24)       ] << 24 ^
++        rk[2];
++    *(u32*)(out+12) =
++           (u32)Te4[(s3      ) & 0xff]       ^
++           (u32)Te4[(s0 >>  8) & 0xff] <<  8 ^
++           (u32)Te4[(s1 >> 16) & 0xff] << 16 ^
++           (u32)Te4[(s2 >> 24)       ] << 24 ^
++        rk[3];
++#else
++    *(u32*)(out+0) =
++        (Te2[(s0      ) & 0xff] & 0x000000ffU) ^
++        (Te3[(s1 >>  8) & 0xff] & 0x0000ff00U) ^
++        (Te0[(s2 >> 16) & 0xff] & 0x00ff0000U) ^
++        (Te1[(s3 >> 24)       ] & 0xff000000U) ^
++        rk[0];
++    *(u32*)(out+4) =
++        (Te2[(s1      ) & 0xff] & 0x000000ffU) ^
++        (Te3[(s2 >>  8) & 0xff] & 0x0000ff00U) ^
++        (Te0[(s3 >> 16) & 0xff] & 0x00ff0000U) ^
++        (Te1[(s0 >> 24)       ] & 0xff000000U) ^
++        rk[1];
++    *(u32*)(out+8) =
++        (Te2[(s2      ) & 0xff] & 0x000000ffU) ^
++        (Te3[(s3 >>  8) & 0xff] & 0x0000ff00U) ^
++        (Te0[(s0 >> 16) & 0xff] & 0x00ff0000U) ^
++        (Te1[(s1 >> 24)       ] & 0xff000000U) ^
++        rk[2];
++    *(u32*)(out+12) =
++        (Te2[(s3      ) & 0xff] & 0x000000ffU) ^
++        (Te3[(s0 >>  8) & 0xff] & 0x0000ff00U) ^
++        (Te0[(s1 >> 16) & 0xff] & 0x00ff0000U) ^
++        (Te1[(s2 >> 24)       ] & 0xff000000U) ^
++        rk[3];
++#endif
++}
++
++/*
++ * Decrypt a single block
++ * in and out can overlap
++ */
++void AES_decrypt(const unsigned char *in, unsigned char *out,
++                 const AES_KEY *key)
++{
++
++    const u32 *rk;
++    u32 s0, s1, s2, s3, t[4];
++    int r;
++
++    assert(in && out && key);
++    rk = key->rd_key;
++
++    /*
++     * map byte array block to cipher state
++     * and add initial round key:
++     */
++    s0 = GETU32(in     ) ^ rk[0];
++    s1 = GETU32(in +  4) ^ rk[1];
++    s2 = GETU32(in +  8) ^ rk[2];
++    s3 = GETU32(in + 12) ^ rk[3];
++
++#if defined(AES_COMPACT_IN_OUTER_ROUNDS)
++    prefetch256(Td4);
++
++    t[0] = (u32)Td4[(s0      ) & 0xff]       ^
++           (u32)Td4[(s3 >>  8) & 0xff] <<  8 ^
++           (u32)Td4[(s2 >> 16) & 0xff] << 16 ^
++           (u32)Td4[(s1 >> 24)       ] << 24;
++    t[1] = (u32)Td4[(s1      ) & 0xff]       ^
++           (u32)Td4[(s0 >>  8) & 0xff] <<  8 ^
++           (u32)Td4[(s3 >> 16) & 0xff] << 16 ^
++           (u32)Td4[(s2 >> 24)       ] << 24;
++    t[2] = (u32)Td4[(s2      ) & 0xff]       ^
++           (u32)Td4[(s1 >>  8) & 0xff] <<  8 ^
++           (u32)Td4[(s0 >> 16) & 0xff] << 16 ^
++           (u32)Td4[(s3 >> 24)       ] << 24;
++    t[3] = (u32)Td4[(s3      ) & 0xff]       ^
++           (u32)Td4[(s2 >>  8) & 0xff] <<  8 ^
++           (u32)Td4[(s1 >> 16) & 0xff] << 16 ^
++           (u32)Td4[(s0 >> 24)       ] << 24;
++
++    /* now do the linear transform using words */
++    {
++        int i;
++        u32 tp1, tp2, tp4, tp8, tp9, tpb, tpd, tpe, m;
++
++        for (i = 0; i < 4; i++) {
++            tp1 = t[i];
++            m = tp1 & 0x80808080;
++            tp2 = ((tp1 & 0x7f7f7f7f) << 1) ^
++                ((m - (m >> 7)) & 0x1b1b1b1b);
++            m = tp2 & 0x80808080;
++            tp4 = ((tp2 & 0x7f7f7f7f) << 1) ^
++                ((m - (m >> 7)) & 0x1b1b1b1b);
++            m = tp4 & 0x80808080;
++            tp8 = ((tp4 & 0x7f7f7f7f) << 1) ^
++                ((m - (m >> 7)) & 0x1b1b1b1b);
++            tp9 = tp8 ^ tp1;
++            tpb = tp9 ^ tp2;
++            tpd = tp9 ^ tp4;
++            tpe = tp8 ^ tp4 ^ tp2;
++#if defined(ROTATE)
++            t[i] = tpe ^ ROTATE(tpd,16) ^
++                ROTATE(tp9,8) ^ ROTATE(tpb,24);
++#else
++            t[i] = tpe ^ (tpd >> 16) ^ (tpd << 16) ^
++                (tp9 >> 24) ^ (tp9 << 8) ^
++                (tpb >> 8) ^ (tpb << 24);
++#endif
++            t[i] ^= rk[4+i];
++        }
++    }
++#else
++    t[0] =  Td0[(s0      ) & 0xff] ^
++        Td1[(s3 >>  8) & 0xff] ^
++        Td2[(s2 >> 16) & 0xff] ^
++        Td3[(s1 >> 24)       ] ^
++        rk[4];
++    t[1] =  Td0[(s1      ) & 0xff] ^
++        Td1[(s0 >>  8) & 0xff] ^
++        Td2[(s3 >> 16) & 0xff] ^
++        Td3[(s2 >> 24)       ] ^
++        rk[5];
++    t[2] =  Td0[(s2      ) & 0xff] ^
++        Td1[(s1 >>  8) & 0xff] ^
++        Td2[(s0 >> 16) & 0xff] ^
++        Td3[(s3 >> 24)       ] ^
++        rk[6];
++    t[3] =  Td0[(s3      ) & 0xff] ^
++        Td1[(s2 >>  8) & 0xff] ^
++        Td2[(s1 >> 16) & 0xff] ^
++        Td3[(s0 >> 24)       ] ^
++        rk[7];
++#endif
++    s0 = t[0]; s1 = t[1]; s2 = t[2]; s3 = t[3];
++
++    /*
++     * Nr - 2 full rounds:
++     */
++    for (rk+=8,r=key->rounds-2; r>0; rk+=4,r--) {
++#if defined(AES_COMPACT_IN_INNER_ROUNDS)
++        t[0] = (u32)Td4[(s0      ) & 0xff]       ^
++               (u32)Td4[(s3 >>  8) & 0xff] <<  8 ^
++               (u32)Td4[(s2 >> 16) & 0xff] << 16 ^
++               (u32)Td4[(s1 >> 24)       ] << 24;
++        t[1] = (u32)Td4[(s1      ) & 0xff]       ^
++               (u32)Td4[(s0 >>  8) & 0xff] <<  8 ^
++               (u32)Td4[(s3 >> 16) & 0xff] << 16 ^
++               (u32)Td4[(s2 >> 24)       ] << 24;
++        t[2] = (u32)Td4[(s2      ) & 0xff]       ^
++               (u32)Td4[(s1 >>  8) & 0xff] <<  8 ^
++               (u32)Td4[(s0 >> 16) & 0xff] << 16 ^
++               (u32)Td4[(s3 >> 24)       ] << 24;
++        t[3] = (u32)Td4[(s3      ) & 0xff]       ^
++               (u32)Td4[(s2 >>  8) & 0xff] <<  8 ^
++               (u32)Td4[(s1 >> 16) & 0xff] << 16 ^
++               (u32)Td4[(s0 >> 24)       ] << 24;
++
++    /* now do the linear transform using words */
++    {
++        int i;
++        u32 tp1, tp2, tp4, tp8, tp9, tpb, tpd, tpe, m;
++
++        for (i = 0; i < 4; i++) {
++            tp1 = t[i];
++            m = tp1 & 0x80808080;
++            tp2 = ((tp1 & 0x7f7f7f7f) << 1) ^
++                ((m - (m >> 7)) & 0x1b1b1b1b);
++            m = tp2 & 0x80808080;
++            tp4 = ((tp2 & 0x7f7f7f7f) << 1) ^
++                ((m - (m >> 7)) & 0x1b1b1b1b);
++            m = tp4 & 0x80808080;
++            tp8 = ((tp4 & 0x7f7f7f7f) << 1) ^
++                ((m - (m >> 7)) & 0x1b1b1b1b);
++            tp9 = tp8 ^ tp1;
++            tpb = tp9 ^ tp2;
++            tpd = tp9 ^ tp4;
++            tpe = tp8 ^ tp4 ^ tp2;
++#if defined(ROTATE)
++            t[i] = tpe ^ ROTATE(tpd,16) ^
++                ROTATE(tp9,8) ^ ROTATE(tpb,24);
++#else
++            t[i] = tpe ^ (tpd >> 16) ^ (tpd << 16) ^
++                (tp9 >> 24) ^ (tp9 << 8) ^
++                (tpb >> 8) ^ (tpb << 24);
++#endif
++            t[i] ^= rk[i];
++        }
++    }
++#else
++    t[0] =  Td0[(s0      ) & 0xff] ^
++        Td1[(s3 >>  8) & 0xff] ^
++        Td2[(s2 >> 16) & 0xff] ^
++        Td3[(s1 >> 24)       ] ^
++        rk[0];
++    t[1] =  Td0[(s1      ) & 0xff] ^
++        Td1[(s0 >>  8) & 0xff] ^
++        Td2[(s3 >> 16) & 0xff] ^
++        Td3[(s2 >> 24)       ] ^
++        rk[1];
++    t[2] =  Td0[(s2      ) & 0xff] ^
++        Td1[(s1 >>  8) & 0xff] ^
++        Td2[(s0 >> 16) & 0xff] ^
++        Td3[(s3 >> 24)       ] ^
++        rk[2];
++    t[3] =  Td0[(s3      ) & 0xff] ^
++        Td1[(s2 >>  8) & 0xff] ^
++        Td2[(s1 >> 16) & 0xff] ^
++        Td3[(s0 >> 24)       ] ^
++        rk[3];
++#endif
++    s0 = t[0]; s1 = t[1]; s2 = t[2]; s3 = t[3];
++    }
++    /*
++     * apply last round and
++     * map cipher state to byte array block:
++     */
++    prefetch256(Td4);
++
++    *(u32*)(out+0) =
++        ((u32)Td4[(s0      ) & 0xff])    ^
++        ((u32)Td4[(s3 >>  8) & 0xff] <<  8) ^
++        ((u32)Td4[(s2 >> 16) & 0xff] << 16) ^
++        ((u32)Td4[(s1 >> 24)       ] << 24) ^
++        rk[0];
++    *(u32*)(out+4) =
++        ((u32)Td4[(s1      ) & 0xff])     ^
++        ((u32)Td4[(s0 >>  8) & 0xff] <<  8) ^
++        ((u32)Td4[(s3 >> 16) & 0xff] << 16) ^
++        ((u32)Td4[(s2 >> 24)       ] << 24) ^
++        rk[1];
++    *(u32*)(out+8) =
++        ((u32)Td4[(s2      ) & 0xff])     ^
++        ((u32)Td4[(s1 >>  8) & 0xff] <<  8) ^
++        ((u32)Td4[(s0 >> 16) & 0xff] << 16) ^
++        ((u32)Td4[(s3 >> 24)       ] << 24) ^
++        rk[2];
++    *(u32*)(out+12) =
++        ((u32)Td4[(s3      ) & 0xff])     ^
++        ((u32)Td4[(s2 >>  8) & 0xff] <<  8) ^
++        ((u32)Td4[(s1 >> 16) & 0xff] << 16) ^
++        ((u32)Td4[(s0 >> 24)       ] << 24) ^
++        rk[3];
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/aes/asm/aes-586.pl b/CryptoPkg/Library/OpensslLib/openssl/crypto/aes/asm/aes-586.pl
+new file mode 100755
+index 0000000..1ba3565
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/aes/asm/aes-586.pl
+@@ -0,0 +1,3000 @@
++#! /usr/bin/env perl
++# Copyright 2004-2016 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
++# in the file LICENSE in the source distribution or at
++# https://www.openssl.org/source/license.html
++
++#
++# ====================================================================
++# Written by Andy Polyakov  for the OpenSSL
++# project. The module is, however, dual licensed under OpenSSL and
++# CRYPTOGAMS licenses depending on where you obtain it. For further
++# details see http://www.openssl.org/~appro/cryptogams/.
++# ====================================================================
++#
++# Version 4.3.
++#
++# You might fail to appreciate this module performance from the first
++# try. If compared to "vanilla" linux-ia32-icc target, i.e. considered
++# to be *the* best Intel C compiler without -KPIC, performance appears
++# to be virtually identical... But try to re-configure with shared
++# library support... Aha! Intel compiler "suddenly" lags behind by 30%
++# [on P4, more on others]:-) And if compared to position-independent
++# code generated by GNU C, this code performs *more* than *twice* as
++# fast! Yes, all this buzz about PIC means that unlike other hand-
++# coded implementations, this one was explicitly designed to be safe
++# to use even in shared library context... This also means that this
++# code isn't necessarily absolutely fastest "ever," because in order
++# to achieve position independence an extra register has to be
++# off-loaded to stack, which affects the benchmark result.
++#
++# Special note about instruction choice. Do you recall RC4_INT code
++# performing poorly on P4? It might be the time to figure out why.
++# RC4_INT code implies effective address calculations in base+offset*4
++# form. Trouble is that it seems that offset scaling turned to be
++# critical path... At least eliminating scaling resulted in 2.8x RC4
++# performance improvement [as you might recall]. As AES code is hungry
++# for scaling too, I [try to] avoid the latter by favoring off-by-2
++# shifts and masking the result with 0xFF<<2 instead of "boring" 0xFF.
++#
++# As was shown by Dean Gaudet , the above note turned
++# void. Performance improvement with off-by-2 shifts was observed on
++# intermediate implementation, which was spilling yet another register
++# to stack... Final offset*4 code below runs just a tad faster on P4,
++# but exhibits up to 10% improvement on other cores.
++#
++# Second version is "monolithic" replacement for aes_core.c, which in
++# addition to AES_[de|en]crypt implements AES_set_[de|en]cryption_key.
++# This made it possible to implement little-endian variant of the
++# algorithm without modifying the base C code. Motivating factor for
++# the undertaken effort was that it appeared that in tight IA-32
++# register window little-endian flavor could achieve slightly higher
++# Instruction Level Parallelism, and it indeed resulted in up to 15%
++# better performance on most recent µ-archs...
++#
++# Third version adds AES_cbc_encrypt implementation, which resulted in
++# up to 40% performance imrovement of CBC benchmark results. 40% was
++# observed on P4 core, where "overall" imrovement coefficient, i.e. if
++# compared to PIC generated by GCC and in CBC mode, was observed to be
++# as large as 4x:-) CBC performance is virtually identical to ECB now
++# and on some platforms even better, e.g. 17.6 "small" cycles/byte on
++# Opteron, because certain function prologues and epilogues are
++# effectively taken out of the loop...
++#
++# Version 3.2 implements compressed tables and prefetch of these tables
++# in CBC[!] mode. Former means that 3/4 of table references are now
++# misaligned, which unfortunately has negative impact on elder IA-32
++# implementations, Pentium suffered 30% penalty, PIII - 10%.
++#
++# Version 3.3 avoids L1 cache aliasing between stack frame and
++# S-boxes, and 3.4 - L1 cache aliasing even between key schedule. The
++# latter is achieved by copying the key schedule to controlled place in
++# stack. This unfortunately has rather strong impact on small block CBC
++# performance, ~2x deterioration on 16-byte block if compared to 3.3.
++#
++# Version 3.5 checks if there is L1 cache aliasing between user-supplied
++# key schedule and S-boxes and abstains from copying the former if
++# there is no. This allows end-user to consciously retain small block
++# performance by aligning key schedule in specific manner.
++#
++# Version 3.6 compresses Td4 to 256 bytes and prefetches it in ECB.
++#
++# Current ECB performance numbers for 128-bit key in CPU cycles per
++# processed byte [measure commonly used by AES benchmarkers] are:
++#
++#		small footprint		fully unrolled
++# P4		24			22
++# AMD K8	20			19
++# PIII		25			23
++# Pentium	81			78
++#
++# Version 3.7 reimplements outer rounds as "compact." Meaning that
++# first and last rounds reference compact 256 bytes S-box. This means
++# that first round consumes a lot more CPU cycles and that encrypt
++# and decrypt performance becomes asymmetric. Encrypt performance
++# drops by 10-12%, while decrypt - by 20-25%:-( 256 bytes S-box is
++# aggressively pre-fetched.
++#
++# Version 4.0 effectively rolls back to 3.6 and instead implements
++# additional set of functions, _[x86|sse]_AES_[en|de]crypt_compact,
++# which use exclusively 256 byte S-box. These functions are to be
++# called in modes not concealing plain text, such as ECB, or when
++# we're asked to process smaller amount of data [or unconditionally
++# on hyper-threading CPU]. Currently it's called unconditionally from
++# AES_[en|de]crypt, which affects all modes, but CBC. CBC routine
++# still needs to be modified to switch between slower and faster
++# mode when appropriate... But in either case benchmark landscape
++# changes dramatically and below numbers are CPU cycles per processed
++# byte for 128-bit key.
++#
++#		ECB encrypt	ECB decrypt	CBC large chunk
++# P4		52[54]		83[95]		23
++# AMD K8	46[41]		66[70]		18
++# PIII		41[50]		60[77]		24
++# Core 2	31[36]		45[64]		18.5
++# Atom		76[100]		96[138]		60
++# Pentium	115		150		77
++#
++# Version 4.1 switches to compact S-box even in key schedule setup.
++#
++# Version 4.2 prefetches compact S-box in every SSE round or in other
++# words every cache-line is *guaranteed* to be accessed within ~50
++# cycles window. Why just SSE? Because it's needed on hyper-threading
++# CPU! Which is also why it's prefetched with 64 byte stride. Best
++# part is that it has no negative effect on performance:-)  
++#
++# Version 4.3 implements switch between compact and non-compact block
++# functions in AES_cbc_encrypt depending on how much data was asked
++# to be processed in one stroke.
++#
++######################################################################
++# Timing attacks are classified in two classes: synchronous when
++# attacker consciously initiates cryptographic operation and collects
++# timing data of various character afterwards, and asynchronous when
++# malicious code is executed on same CPU simultaneously with AES,
++# instruments itself and performs statistical analysis of this data.
++#
++# As far as synchronous attacks go the root to the AES timing
++# vulnerability is twofold. Firstly, of 256 S-box elements at most 160
++# are referred to in single 128-bit block operation. Well, in C
++# implementation with 4 distinct tables it's actually as little as 40
++# references per 256 elements table, but anyway... Secondly, even
++# though S-box elements are clustered into smaller amount of cache-
++# lines, smaller than 160 and even 40, it turned out that for certain
++# plain-text pattern[s] or simply put chosen plain-text and given key
++# few cache-lines remain unaccessed during block operation. Now, if
++# attacker can figure out this access pattern, he can deduct the key
++# [or at least part of it]. The natural way to mitigate this kind of
++# attacks is to minimize the amount of cache-lines in S-box and/or
++# prefetch them to ensure that every one is accessed for more uniform
++# timing. But note that *if* plain-text was concealed in such way that
++# input to block function is distributed *uniformly*, then attack
++# wouldn't apply. Now note that some encryption modes, most notably
++# CBC, do mask the plain-text in this exact way [secure cipher output
++# is distributed uniformly]. Yes, one still might find input that
++# would reveal the information about given key, but if amount of
++# candidate inputs to be tried is larger than amount of possible key
++# combinations then attack becomes infeasible. This is why revised
++# AES_cbc_encrypt "dares" to switch to larger S-box when larger chunk
++# of data is to be processed in one stroke. The current size limit of
++# 512 bytes is chosen to provide same [diminishigly low] probability
++# for cache-line to remain untouched in large chunk operation with
++# large S-box as for single block operation with compact S-box and
++# surely needs more careful consideration...
++#
++# As for asynchronous attacks. There are two flavours: attacker code
++# being interleaved with AES on hyper-threading CPU at *instruction*
++# level, and two processes time sharing single core. As for latter.
++# Two vectors. 1. Given that attacker process has higher priority,
++# yield execution to process performing AES just before timer fires
++# off the scheduler, immediately regain control of CPU and analyze the
++# cache state. For this attack to be efficient attacker would have to
++# effectively slow down the operation by several *orders* of magnitute,
++# by ratio of time slice to duration of handful of AES rounds, which
++# unlikely to remain unnoticed. Not to mention that this also means
++# that he would spend correspondigly more time to collect enough
++# statistical data to mount the attack. It's probably appropriate to
++# say that if adeversary reckons that this attack is beneficial and
++# risks to be noticed, you probably have larger problems having him
++# mere opportunity. In other words suggested code design expects you
++# to preclude/mitigate this attack by overall system security design.
++# 2. Attacker manages to make his code interrupt driven. In order for
++# this kind of attack to be feasible, interrupt rate has to be high
++# enough, again comparable to duration of handful of AES rounds. But
++# is there interrupt source of such rate? Hardly, not even 1Gbps NIC
++# generates interrupts at such raging rate...
++#
++# And now back to the former, hyper-threading CPU or more specifically
++# Intel P4. Recall that asynchronous attack implies that malicious
++# code instruments itself. And naturally instrumentation granularity
++# has be noticeably lower than duration of codepath accessing S-box.
++# Given that all cache-lines are accessed during that time that is.
++# Current implementation accesses *all* cache-lines within ~50 cycles
++# window, which is actually *less* than RDTSC latency on Intel P4!
++
++$0 =~ m/(.*[\/\\])[^\/\\]+$/; $dir=$1;
++push(@INC,"${dir}","${dir}../../perlasm");
++require "x86asm.pl";
++
++$output = pop;
++open OUT,">$output";
++*STDOUT=*OUT;
++
++&asm_init($ARGV[0],"aes-586.pl",$x86only = $ARGV[$#ARGV] eq "386");
++&static_label("AES_Te");
++&static_label("AES_Td");
++
++$s0="eax";
++$s1="ebx";
++$s2="ecx";
++$s3="edx";
++$key="edi";
++$acc="esi";
++$tbl="ebp";
++
++# stack frame layout in _[x86|sse]_AES_* routines, frame is allocated
++# by caller
++$__ra=&DWP(0,"esp");	# return address
++$__s0=&DWP(4,"esp");	# s0 backing store
++$__s1=&DWP(8,"esp");	# s1 backing store
++$__s2=&DWP(12,"esp");	# s2 backing store
++$__s3=&DWP(16,"esp");	# s3 backing store
++$__key=&DWP(20,"esp");	# pointer to key schedule
++$__end=&DWP(24,"esp");	# pointer to end of key schedule
++$__tbl=&DWP(28,"esp");	# %ebp backing store
++
++# stack frame layout in AES_[en|crypt] routines, which differs from
++# above by 4 and overlaps by %ebp backing store
++$_tbl=&DWP(24,"esp");
++$_esp=&DWP(28,"esp");
++
++sub _data_word() { my $i; while(defined($i=shift)) { &data_word($i,$i); } }
++
++$speed_limit=512;	# chunks smaller than $speed_limit are
++			# processed with compact routine in CBC mode
++$small_footprint=1;	# $small_footprint=1 code is ~5% slower [on
++			# recent µ-archs], but ~5 times smaller!
++			# I favor compact code to minimize cache
++			# contention and in hope to "collect" 5% back
++			# in real-life applications...
++
++$vertical_spin=0;	# shift "verticaly" defaults to 0, because of
++			# its proof-of-concept status...
++# Note that there is no decvert(), as well as last encryption round is
++# performed with "horizontal" shifts. This is because this "vertical"
++# implementation [one which groups shifts on a given $s[i] to form a
++# "column," unlike "horizontal" one, which groups shifts on different
++# $s[i] to form a "row"] is work in progress. It was observed to run
++# few percents faster on Intel cores, but not AMD. On AMD K8 core it's
++# whole 12% slower:-( So we face a trade-off... Shall it be resolved
++# some day? Till then the code is considered experimental and by
++# default remains dormant...
++
++sub encvert()
++{ my ($te,@s) = @_;
++  my ($v0,$v1) = ($acc,$key);
++
++	&mov	($v0,$s[3]);				# copy s3
++	&mov	(&DWP(4,"esp"),$s[2]);			# save s2
++	&mov	($v1,$s[0]);				# copy s0
++	&mov	(&DWP(8,"esp"),$s[1]);			# save s1
++
++	&movz	($s[2],&HB($s[0]));
++	&and	($s[0],0xFF);
++	&mov	($s[0],&DWP(0,$te,$s[0],8));		# s0>>0
++	&shr	($v1,16);
++	&mov	($s[3],&DWP(3,$te,$s[2],8));		# s0>>8
++	&movz	($s[1],&HB($v1));
++	&and	($v1,0xFF);
++	&mov	($s[2],&DWP(2,$te,$v1,8));		# s0>>16
++	 &mov	($v1,$v0);
++	&mov	($s[1],&DWP(1,$te,$s[1],8));		# s0>>24
++
++	&and	($v0,0xFF);
++	&xor	($s[3],&DWP(0,$te,$v0,8));		# s3>>0
++	&movz	($v0,&HB($v1));
++	&shr	($v1,16);
++	&xor	($s[2],&DWP(3,$te,$v0,8));		# s3>>8
++	&movz	($v0,&HB($v1));
++	&and	($v1,0xFF);
++	&xor	($s[1],&DWP(2,$te,$v1,8));		# s3>>16
++	 &mov	($v1,&DWP(4,"esp"));			# restore s2
++	&xor	($s[0],&DWP(1,$te,$v0,8));		# s3>>24
++
++	&mov	($v0,$v1);
++	&and	($v1,0xFF);
++	&xor	($s[2],&DWP(0,$te,$v1,8));		# s2>>0
++	&movz	($v1,&HB($v0));
++	&shr	($v0,16);
++	&xor	($s[1],&DWP(3,$te,$v1,8));		# s2>>8
++	&movz	($v1,&HB($v0));
++	&and	($v0,0xFF);
++	&xor	($s[0],&DWP(2,$te,$v0,8));		# s2>>16
++	 &mov	($v0,&DWP(8,"esp"));			# restore s1
++	&xor	($s[3],&DWP(1,$te,$v1,8));		# s2>>24
++
++	&mov	($v1,$v0);
++	&and	($v0,0xFF);
++	&xor	($s[1],&DWP(0,$te,$v0,8));		# s1>>0
++	&movz	($v0,&HB($v1));
++	&shr	($v1,16);
++	&xor	($s[0],&DWP(3,$te,$v0,8));		# s1>>8
++	&movz	($v0,&HB($v1));
++	&and	($v1,0xFF);
++	&xor	($s[3],&DWP(2,$te,$v1,8));		# s1>>16
++	 &mov	($key,$__key);				# reincarnate v1 as key
++	&xor	($s[2],&DWP(1,$te,$v0,8));		# s1>>24
++}
++
++# Another experimental routine, which features "horizontal spin," but
++# eliminates one reference to stack. Strangely enough runs slower...
++sub enchoriz()
++{ my ($v0,$v1) = ($key,$acc);
++
++	&movz	($v0,&LB($s0));			#  3, 2, 1, 0*
++	&rotr	($s2,8);			#  8,11,10, 9
++	&mov	($v1,&DWP(0,$te,$v0,8));	#  0
++	&movz	($v0,&HB($s1));			#  7, 6, 5*, 4
++	&rotr	($s3,16);			# 13,12,15,14
++	&xor	($v1,&DWP(3,$te,$v0,8));	#  5
++	&movz	($v0,&HB($s2));			#  8,11,10*, 9
++	&rotr	($s0,16);			#  1, 0, 3, 2
++	&xor	($v1,&DWP(2,$te,$v0,8));	# 10
++	&movz	($v0,&HB($s3));			# 13,12,15*,14
++	&xor	($v1,&DWP(1,$te,$v0,8));	# 15, t[0] collected
++	&mov	($__s0,$v1);			# t[0] saved
++
++	&movz	($v0,&LB($s1));			#  7, 6, 5, 4*
++	&shr	($s1,16);			#  -, -, 7, 6
++	&mov	($v1,&DWP(0,$te,$v0,8));	#  4
++	&movz	($v0,&LB($s3));			# 13,12,15,14*
++	&xor	($v1,&DWP(2,$te,$v0,8));	# 14
++	&movz	($v0,&HB($s0));			#  1, 0, 3*, 2
++	&and	($s3,0xffff0000);		# 13,12, -, -
++	&xor	($v1,&DWP(1,$te,$v0,8));	#  3
++	&movz	($v0,&LB($s2));			#  8,11,10, 9*
++	&or	($s3,$s1);			# 13,12, 7, 6
++	&xor	($v1,&DWP(3,$te,$v0,8));	#  9, t[1] collected
++	&mov	($s1,$v1);			#  s[1]=t[1]
++
++	&movz	($v0,&LB($s0));			#  1, 0, 3, 2*
++	&shr	($s2,16);			#  -, -, 8,11
++	&mov	($v1,&DWP(2,$te,$v0,8));	#  2
++	&movz	($v0,&HB($s3));			# 13,12, 7*, 6
++	&xor	($v1,&DWP(1,$te,$v0,8));	#  7
++	&movz	($v0,&HB($s2));			#  -, -, 8*,11
++	&xor	($v1,&DWP(0,$te,$v0,8));	#  8
++	&mov	($v0,$s3);
++	&shr	($v0,24);			# 13
++	&xor	($v1,&DWP(3,$te,$v0,8));	# 13, t[2] collected
++
++	&movz	($v0,&LB($s2));			#  -, -, 8,11*
++	&shr	($s0,24);			#  1*
++	&mov	($s2,&DWP(1,$te,$v0,8));	# 11
++	&xor	($s2,&DWP(3,$te,$s0,8));	#  1
++	&mov	($s0,$__s0);			# s[0]=t[0]
++	&movz	($v0,&LB($s3));			# 13,12, 7, 6*
++	&shr	($s3,16);			#   ,  ,13,12
++	&xor	($s2,&DWP(2,$te,$v0,8));	#  6
++	&mov	($key,$__key);			# reincarnate v0 as key
++	&and	($s3,0xff);			#   ,  ,13,12*
++	&mov	($s3,&DWP(0,$te,$s3,8));	# 12
++	&xor	($s3,$s2);			# s[2]=t[3] collected
++	&mov	($s2,$v1);			# s[2]=t[2]
++}
++
++# More experimental code... SSE one... Even though this one eliminates
++# *all* references to stack, it's not faster...
++sub sse_encbody()
++{
++	&movz	($acc,&LB("eax"));		#  0
++	&mov	("ecx",&DWP(0,$tbl,$acc,8));	#  0
++	&pshufw	("mm2","mm0",0x0d);		#  7, 6, 3, 2
++	&movz	("edx",&HB("eax"));		#  1
++	&mov	("edx",&DWP(3,$tbl,"edx",8));	#  1
++	&shr	("eax",16);			#  5, 4
++
++	&movz	($acc,&LB("ebx"));		# 10
++	&xor	("ecx",&DWP(2,$tbl,$acc,8));	# 10
++	&pshufw	("mm6","mm4",0x08);		# 13,12, 9, 8
++	&movz	($acc,&HB("ebx"));		# 11
++	&xor	("edx",&DWP(1,$tbl,$acc,8));	# 11
++	&shr	("ebx",16);			# 15,14
++
++	&movz	($acc,&HB("eax"));		#  5
++	&xor	("ecx",&DWP(3,$tbl,$acc,8));	#  5
++	&movq	("mm3",QWP(16,$key));
++	&movz	($acc,&HB("ebx"));		# 15
++	&xor	("ecx",&DWP(1,$tbl,$acc,8));	# 15
++	&movd	("mm0","ecx");			# t[0] collected
++
++	&movz	($acc,&LB("eax"));		#  4
++	&mov	("ecx",&DWP(0,$tbl,$acc,8));	#  4
++	&movd	("eax","mm2");			#  7, 6, 3, 2
++	&movz	($acc,&LB("ebx"));		# 14
++	&xor	("ecx",&DWP(2,$tbl,$acc,8));	# 14
++	&movd	("ebx","mm6");			# 13,12, 9, 8
++
++	&movz	($acc,&HB("eax"));		#  3
++	&xor	("ecx",&DWP(1,$tbl,$acc,8));	#  3
++	&movz	($acc,&HB("ebx"));		#  9
++	&xor	("ecx",&DWP(3,$tbl,$acc,8));	#  9
++	&movd	("mm1","ecx");			# t[1] collected
++
++	&movz	($acc,&LB("eax"));		#  2
++	&mov	("ecx",&DWP(2,$tbl,$acc,8));	#  2
++	&shr	("eax",16);			#  7, 6
++	&punpckldq	("mm0","mm1");		# t[0,1] collected
++	&movz	($acc,&LB("ebx"));		#  8
++	&xor	("ecx",&DWP(0,$tbl,$acc,8));	#  8
++	&shr	("ebx",16);			# 13,12
++
++	&movz	($acc,&HB("eax"));		#  7
++	&xor	("ecx",&DWP(1,$tbl,$acc,8));	#  7
++	&pxor	("mm0","mm3");
++	&movz	("eax",&LB("eax"));		#  6
++	&xor	("edx",&DWP(2,$tbl,"eax",8));	#  6
++	&pshufw	("mm1","mm0",0x08);		#  5, 4, 1, 0
++	&movz	($acc,&HB("ebx"));		# 13
++	&xor	("ecx",&DWP(3,$tbl,$acc,8));	# 13
++	&xor	("ecx",&DWP(24,$key));		# t[2]
++	&movd	("mm4","ecx");			# t[2] collected
++	&movz	("ebx",&LB("ebx"));		# 12
++	&xor	("edx",&DWP(0,$tbl,"ebx",8));	# 12
++	&shr	("ecx",16);
++	&movd	("eax","mm1");			#  5, 4, 1, 0
++	&mov	("ebx",&DWP(28,$key));		# t[3]
++	&xor	("ebx","edx");
++	&movd	("mm5","ebx");			# t[3] collected
++	&and	("ebx",0xffff0000);
++	&or	("ebx","ecx");
++
++	&punpckldq	("mm4","mm5");		# t[2,3] collected
++}
++
++######################################################################
++# "Compact" block function
++######################################################################
++
++sub enccompact()
++{ my $Fn = \&mov;
++  while ($#_>5) { pop(@_); $Fn=sub{}; }
++  my ($i,$te,@s)=@_;
++  my $tmp = $key;
++  my $out = $i==3?$s[0]:$acc;
++
++	# $Fn is used in first compact round and its purpose is to
++	# void restoration of some values from stack, so that after
++	# 4xenccompact with extra argument $key value is left there...
++	if ($i==3)  {	&$Fn	($key,$__key);			}##%edx
++	else        {	&mov	($out,$s[0]);			}
++			&and	($out,0xFF);
++	if ($i==1)  {	&shr	($s[0],16);			}#%ebx[1]
++	if ($i==2)  {	&shr	($s[0],24);			}#%ecx[2]
++			&movz	($out,&BP(-128,$te,$out,1));
++
++	if ($i==3)  {	$tmp=$s[1];				}##%eax
++			&movz	($tmp,&HB($s[1]));
++			&movz	($tmp,&BP(-128,$te,$tmp,1));
++			&shl	($tmp,8);
++			&xor	($out,$tmp);
++
++	if ($i==3)  {	$tmp=$s[2]; &mov ($s[1],$__s0);		}##%ebx
++	else        {	&mov	($tmp,$s[2]);
++			&shr	($tmp,16);			}
++	if ($i==2)  {	&and	($s[1],0xFF);			}#%edx[2]
++			&and	($tmp,0xFF);
++			&movz	($tmp,&BP(-128,$te,$tmp,1));
++			&shl	($tmp,16);
++			&xor	($out,$tmp);
++
++	if ($i==3)  {	$tmp=$s[3]; &mov ($s[2],$__s1);		}##%ecx
++	elsif($i==2){	&movz	($tmp,&HB($s[3]));		}#%ebx[2]
++	else        {	&mov	($tmp,$s[3]);
++			&shr	($tmp,24);			}
++			&movz	($tmp,&BP(-128,$te,$tmp,1));
++			&shl	($tmp,24);
++			&xor	($out,$tmp);
++	if ($i<2)   {	&mov	(&DWP(4+4*$i,"esp"),$out);	}
++	if ($i==3)  {	&mov	($s[3],$acc);			}
++	&comment();
++}
++
++sub enctransform()
++{ my @s = ($s0,$s1,$s2,$s3);
++  my $i = shift;
++  my $tmp = $tbl;
++  my $r2  = $key ;
++
++	&and	($tmp,$s[$i]);
++	&lea	($r2,&DWP(0,$s[$i],$s[$i]));
++	&mov	($acc,$tmp);
++	&shr	($tmp,7);
++	&and	($r2,0xfefefefe);
++	&sub	($acc,$tmp);
++	&mov	($tmp,$s[$i]);
++	&and	($acc,0x1b1b1b1b);
++	&rotr	($tmp,16);
++	&xor	($acc,$r2);	# r2
++	&mov	($r2,$s[$i]);
++
++	&xor	($s[$i],$acc);	# r0 ^ r2
++	&rotr	($r2,16+8);
++	&xor	($acc,$tmp);
++	&rotl	($s[$i],24);
++	&xor	($acc,$r2);
++	&mov	($tmp,0x80808080)	if ($i!=1);
++	&xor	($s[$i],$acc);	# ROTATE(r2^r0,24) ^ r2
++}
++
++&function_begin_B("_x86_AES_encrypt_compact");
++	# note that caller is expected to allocate stack frame for me!
++	&mov	($__key,$key);			# save key
++
++	&xor	($s0,&DWP(0,$key));		# xor with key
++	&xor	($s1,&DWP(4,$key));
++	&xor	($s2,&DWP(8,$key));
++	&xor	($s3,&DWP(12,$key));
++
++	&mov	($acc,&DWP(240,$key));		# load key->rounds
++	&lea	($acc,&DWP(-2,$acc,$acc));
++	&lea	($acc,&DWP(0,$key,$acc,8));
++	&mov	($__end,$acc);			# end of key schedule
++
++	# prefetch Te4
++	&mov	($key,&DWP(0-128,$tbl));
++	&mov	($acc,&DWP(32-128,$tbl));
++	&mov	($key,&DWP(64-128,$tbl));
++	&mov	($acc,&DWP(96-128,$tbl));
++	&mov	($key,&DWP(128-128,$tbl));
++	&mov	($acc,&DWP(160-128,$tbl));
++	&mov	($key,&DWP(192-128,$tbl));
++	&mov	($acc,&DWP(224-128,$tbl));
++
++	&set_label("loop",16);
++
++		&enccompact(0,$tbl,$s0,$s1,$s2,$s3,1);
++		&enccompact(1,$tbl,$s1,$s2,$s3,$s0,1);
++		&enccompact(2,$tbl,$s2,$s3,$s0,$s1,1);
++		&enccompact(3,$tbl,$s3,$s0,$s1,$s2,1);
++		&mov	($tbl,0x80808080);
++		&enctransform(2);
++		&enctransform(3);
++		&enctransform(0);
++		&enctransform(1);
++		&mov 	($key,$__key);
++		&mov	($tbl,$__tbl);
++		&add	($key,16);		# advance rd_key
++		&xor	($s0,&DWP(0,$key));
++		&xor	($s1,&DWP(4,$key));
++		&xor	($s2,&DWP(8,$key));
++		&xor	($s3,&DWP(12,$key));
++
++	&cmp	($key,$__end);
++	&mov	($__key,$key);
++	&jb	(&label("loop"));
++
++	&enccompact(0,$tbl,$s0,$s1,$s2,$s3);
++	&enccompact(1,$tbl,$s1,$s2,$s3,$s0);
++	&enccompact(2,$tbl,$s2,$s3,$s0,$s1);
++	&enccompact(3,$tbl,$s3,$s0,$s1,$s2);
++
++	&xor	($s0,&DWP(16,$key));
++	&xor	($s1,&DWP(20,$key));
++	&xor	($s2,&DWP(24,$key));
++	&xor	($s3,&DWP(28,$key));
++
++	&ret	();
++&function_end_B("_x86_AES_encrypt_compact");
++
++######################################################################
++# "Compact" SSE block function.
++######################################################################
++#
++# Performance is not actually extraordinary in comparison to pure
++# x86 code. In particular encrypt performance is virtually the same.
++# Decrypt performance on the other hand is 15-20% better on newer
++# µ-archs [but we're thankful for *any* improvement here], and ~50%
++# better on PIII:-) And additionally on the pros side this code
++# eliminates redundant references to stack and thus relieves/
++# minimizes the pressure on the memory bus.
++#
++# MMX register layout                           lsb
++# +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
++# |          mm4          |          mm0          |
++# +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
++# |     s3    |     s2    |     s1    |     s0    |    
++# +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
++# |15|14|13|12|11|10| 9| 8| 7| 6| 5| 4| 3| 2| 1| 0|
++# +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
++#
++# Indexes translate as s[N/4]>>(8*(N%4)), e.g. 5 means s1>>8.
++# In this terms encryption and decryption "compact" permutation
++# matrices can be depicted as following:
++#
++# encryption              lsb	# decryption              lsb
++# +----++----+----+----+----+	# +----++----+----+----+----+
++# | t0 || 15 | 10 |  5 |  0 |	# | t0 ||  7 | 10 | 13 |  0 |
++# +----++----+----+----+----+	# +----++----+----+----+----+
++# | t1 ||  3 | 14 |  9 |  4 |	# | t1 || 11 | 14 |  1 |  4 |
++# +----++----+----+----+----+	# +----++----+----+----+----+
++# | t2 ||  7 |  2 | 13 |  8 |	# | t2 || 15 |  2 |  5 |  8 |
++# +----++----+----+----+----+	# +----++----+----+----+----+
++# | t3 || 11 |  6 |  1 | 12 |	# | t3 ||  3 |  6 |  9 | 12 |
++# +----++----+----+----+----+	# +----++----+----+----+----+
++#
++######################################################################
++# Why not xmm registers? Short answer. It was actually tested and
++# was not any faster, but *contrary*, most notably on Intel CPUs.
++# Longer answer. Main advantage of using mm registers is that movd
++# latency is lower, especially on Intel P4. While arithmetic
++# instructions are twice as many, they can be scheduled every cycle
++# and not every second one when they are operating on xmm register,
++# so that "arithmetic throughput" remains virtually the same. And
++# finally the code can be executed even on elder SSE-only CPUs:-)
++
++sub sse_enccompact()
++{
++	&pshufw	("mm1","mm0",0x08);		#  5, 4, 1, 0
++	&pshufw	("mm5","mm4",0x0d);		# 15,14,11,10
++	&movd	("eax","mm1");			#  5, 4, 1, 0
++	&movd	("ebx","mm5");			# 15,14,11,10
++	&mov	($__key,$key);
++
++	&movz	($acc,&LB("eax"));		#  0
++	&movz	("edx",&HB("eax"));		#  1
++	&pshufw	("mm2","mm0",0x0d);		#  7, 6, 3, 2
++	&movz	("ecx",&BP(-128,$tbl,$acc,1));	#  0
++	&movz	($key,&LB("ebx"));		# 10
++	&movz	("edx",&BP(-128,$tbl,"edx",1));	#  1
++	&shr	("eax",16);			#  5, 4
++	&shl	("edx",8);			#  1
++
++	&movz	($acc,&BP(-128,$tbl,$key,1));	# 10
++	&movz	($key,&HB("ebx"));		# 11
++	&shl	($acc,16);			# 10
++	&pshufw	("mm6","mm4",0x08);		# 13,12, 9, 8
++	&or	("ecx",$acc);			# 10
++	&movz	($acc,&BP(-128,$tbl,$key,1));	# 11
++	&movz	($key,&HB("eax"));		#  5
++	&shl	($acc,24);			# 11
++	&shr	("ebx",16);			# 15,14
++	&or	("edx",$acc);			# 11
++
++	&movz	($acc,&BP(-128,$tbl,$key,1));	#  5
++	&movz	($key,&HB("ebx"));		# 15
++	&shl	($acc,8);			#  5
++	&or	("ecx",$acc);			#  5
++	&movz	($acc,&BP(-128,$tbl,$key,1));	# 15
++	&movz	($key,&LB("eax"));		#  4
++	&shl	($acc,24);			# 15
++	&or	("ecx",$acc);			# 15
++
++	&movz	($acc,&BP(-128,$tbl,$key,1));	#  4
++	&movz	($key,&LB("ebx"));		# 14
++	&movd	("eax","mm2");			#  7, 6, 3, 2
++	&movd	("mm0","ecx");			# t[0] collected
++	&movz	("ecx",&BP(-128,$tbl,$key,1));	# 14
++	&movz	($key,&HB("eax"));		#  3
++	&shl	("ecx",16);			# 14
++	&movd	("ebx","mm6");			# 13,12, 9, 8
++	&or	("ecx",$acc);			# 14
++
++	&movz	($acc,&BP(-128,$tbl,$key,1));	#  3
++	&movz	($key,&HB("ebx"));		#  9
++	&shl	($acc,24);			#  3
++	&or	("ecx",$acc);			#  3
++	&movz	($acc,&BP(-128,$tbl,$key,1));	#  9
++	&movz	($key,&LB("ebx"));		#  8
++	&shl	($acc,8);			#  9
++	&shr	("ebx",16);			# 13,12
++	&or	("ecx",$acc);			#  9
++
++	&movz	($acc,&BP(-128,$tbl,$key,1));	#  8
++	&movz	($key,&LB("eax"));		#  2
++	&shr	("eax",16);			#  7, 6
++	&movd	("mm1","ecx");			# t[1] collected
++	&movz	("ecx",&BP(-128,$tbl,$key,1));	#  2
++	&movz	($key,&HB("eax"));		#  7
++	&shl	("ecx",16);			#  2
++	&and	("eax",0xff);			#  6
++	&or	("ecx",$acc);			#  2
++
++	&punpckldq	("mm0","mm1");		# t[0,1] collected
++
++	&movz	($acc,&BP(-128,$tbl,$key,1));	#  7
++	&movz	($key,&HB("ebx"));		# 13
++	&shl	($acc,24);			#  7
++	&and	("ebx",0xff);			# 12
++	&movz	("eax",&BP(-128,$tbl,"eax",1));	#  6
++	&or	("ecx",$acc);			#  7
++	&shl	("eax",16);			#  6
++	&movz	($acc,&BP(-128,$tbl,$key,1));	# 13
++	&or	("edx","eax");			#  6
++	&shl	($acc,8);			# 13
++	&movz	("ebx",&BP(-128,$tbl,"ebx",1));	# 12
++	&or	("ecx",$acc);			# 13
++	&or	("edx","ebx");			# 12
++	&mov	($key,$__key);
++	&movd	("mm4","ecx");			# t[2] collected
++	&movd	("mm5","edx");			# t[3] collected
++
++	&punpckldq	("mm4","mm5");		# t[2,3] collected
++}
++
++					if (!$x86only) {
++&function_begin_B("_sse_AES_encrypt_compact");
++	&pxor	("mm0",&QWP(0,$key));	#  7, 6, 5, 4, 3, 2, 1, 0
++	&pxor	("mm4",&QWP(8,$key));	# 15,14,13,12,11,10, 9, 8
++
++	# note that caller is expected to allocate stack frame for me!
++	&mov	($acc,&DWP(240,$key));		# load key->rounds
++	&lea	($acc,&DWP(-2,$acc,$acc));
++	&lea	($acc,&DWP(0,$key,$acc,8));
++	&mov	($__end,$acc);			# end of key schedule
++
++	&mov	($s0,0x1b1b1b1b);		# magic constant
++	&mov	(&DWP(8,"esp"),$s0);
++	&mov	(&DWP(12,"esp"),$s0);
++
++	# prefetch Te4
++	&mov	($s0,&DWP(0-128,$tbl));
++	&mov	($s1,&DWP(32-128,$tbl));
++	&mov	($s2,&DWP(64-128,$tbl));
++	&mov	($s3,&DWP(96-128,$tbl));
++	&mov	($s0,&DWP(128-128,$tbl));
++	&mov	($s1,&DWP(160-128,$tbl));
++	&mov	($s2,&DWP(192-128,$tbl));
++	&mov	($s3,&DWP(224-128,$tbl));
++
++	&set_label("loop",16);
++		&sse_enccompact();
++		&add	($key,16);
++		&cmp	($key,$__end);
++		&ja	(&label("out"));
++
++		&movq	("mm2",&QWP(8,"esp"));
++		&pxor	("mm3","mm3");		&pxor	("mm7","mm7");
++		&movq	("mm1","mm0");		&movq	("mm5","mm4");	# r0
++		&pcmpgtb("mm3","mm0");		&pcmpgtb("mm7","mm4");
++		&pand	("mm3","mm2");		&pand	("mm7","mm2");
++		&pshufw	("mm2","mm0",0xb1);	&pshufw	("mm6","mm4",0xb1);# ROTATE(r0,16)
++		&paddb	("mm0","mm0");		&paddb	("mm4","mm4");
++		&pxor	("mm0","mm3");		&pxor	("mm4","mm7");	# = r2
++		&pshufw	("mm3","mm2",0xb1);	&pshufw	("mm7","mm6",0xb1);# r0
++		&pxor	("mm1","mm0");		&pxor	("mm5","mm4");	# r0^r2
++		&pxor	("mm0","mm2");		&pxor	("mm4","mm6");	# ^= ROTATE(r0,16)
++
++		&movq	("mm2","mm3");		&movq	("mm6","mm7");
++		&pslld	("mm3",8);		&pslld	("mm7",8);
++		&psrld	("mm2",24);		&psrld	("mm6",24);
++		&pxor	("mm0","mm3");		&pxor	("mm4","mm7");	# ^= r0<<8
++		&pxor	("mm0","mm2");		&pxor	("mm4","mm6");	# ^= r0>>24
++
++		&movq	("mm3","mm1");		&movq	("mm7","mm5");
++		&movq	("mm2",&QWP(0,$key));	&movq	("mm6",&QWP(8,$key));
++		&psrld	("mm1",8);		&psrld	("mm5",8);
++		&mov	($s0,&DWP(0-128,$tbl));
++		&pslld	("mm3",24);		&pslld	("mm7",24);
++		&mov	($s1,&DWP(64-128,$tbl));
++		&pxor	("mm0","mm1");		&pxor	("mm4","mm5");	# ^= (r2^r0)<<8
++		&mov	($s2,&DWP(128-128,$tbl));
++		&pxor	("mm0","mm3");		&pxor	("mm4","mm7");	# ^= (r2^r0)>>24
++		&mov	($s3,&DWP(192-128,$tbl));
++
++		&pxor	("mm0","mm2");		&pxor	("mm4","mm6");
++	&jmp	(&label("loop"));
++
++	&set_label("out",16);
++	&pxor	("mm0",&QWP(0,$key));
++	&pxor	("mm4",&QWP(8,$key));
++
++	&ret	();
++&function_end_B("_sse_AES_encrypt_compact");
++					}
++
++######################################################################
++# Vanilla block function.
++######################################################################
++
++sub encstep()
++{ my ($i,$te,@s) = @_;
++  my $tmp = $key;
++  my $out = $i==3?$s[0]:$acc;
++
++	# lines marked with #%e?x[i] denote "reordered" instructions...
++	if ($i==3)  {	&mov	($key,$__key);			}##%edx
++	else        {	&mov	($out,$s[0]);
++			&and	($out,0xFF);			}
++	if ($i==1)  {	&shr	($s[0],16);			}#%ebx[1]
++	if ($i==2)  {	&shr	($s[0],24);			}#%ecx[2]
++			&mov	($out,&DWP(0,$te,$out,8));
++
++	if ($i==3)  {	$tmp=$s[1];				}##%eax
++			&movz	($tmp,&HB($s[1]));
++			&xor	($out,&DWP(3,$te,$tmp,8));
++
++	if ($i==3)  {	$tmp=$s[2]; &mov ($s[1],$__s0);		}##%ebx
++	else        {	&mov	($tmp,$s[2]);
++			&shr	($tmp,16);			}
++	if ($i==2)  {	&and	($s[1],0xFF);			}#%edx[2]
++			&and	($tmp,0xFF);
++			&xor	($out,&DWP(2,$te,$tmp,8));
++
++	if ($i==3)  {	$tmp=$s[3]; &mov ($s[2],$__s1);		}##%ecx
++	elsif($i==2){	&movz	($tmp,&HB($s[3]));		}#%ebx[2]
++	else        {	&mov	($tmp,$s[3]); 
++			&shr	($tmp,24)			}
++			&xor	($out,&DWP(1,$te,$tmp,8));
++	if ($i<2)   {	&mov	(&DWP(4+4*$i,"esp"),$out);	}
++	if ($i==3)  {	&mov	($s[3],$acc);			}
++			&comment();
++}
++
++sub enclast()
++{ my ($i,$te,@s)=@_;
++  my $tmp = $key;
++  my $out = $i==3?$s[0]:$acc;
++
++	if ($i==3)  {	&mov	($key,$__key);			}##%edx
++	else        {	&mov	($out,$s[0]);			}
++			&and	($out,0xFF);
++	if ($i==1)  {	&shr	($s[0],16);			}#%ebx[1]
++	if ($i==2)  {	&shr	($s[0],24);			}#%ecx[2]
++			&mov	($out,&DWP(2,$te,$out,8));
++			&and	($out,0x000000ff);
++
++	if ($i==3)  {	$tmp=$s[1];				}##%eax
++			&movz	($tmp,&HB($s[1]));
++			&mov	($tmp,&DWP(0,$te,$tmp,8));
++			&and	($tmp,0x0000ff00);
++			&xor	($out,$tmp);
++
++	if ($i==3)  {	$tmp=$s[2]; &mov ($s[1],$__s0);		}##%ebx
++	else        {	&mov	($tmp,$s[2]);
++			&shr	($tmp,16);			}
++	if ($i==2)  {	&and	($s[1],0xFF);			}#%edx[2]
++			&and	($tmp,0xFF);
++			&mov	($tmp,&DWP(0,$te,$tmp,8));
++			&and	($tmp,0x00ff0000);
++			&xor	($out,$tmp);
++
++	if ($i==3)  {	$tmp=$s[3]; &mov ($s[2],$__s1);		}##%ecx
++	elsif($i==2){	&movz	($tmp,&HB($s[3]));		}#%ebx[2]
++	else        {	&mov	($tmp,$s[3]);
++			&shr	($tmp,24);			}
++			&mov	($tmp,&DWP(2,$te,$tmp,8));
++			&and	($tmp,0xff000000);
++			&xor	($out,$tmp);
++	if ($i<2)   {	&mov	(&DWP(4+4*$i,"esp"),$out);	}
++	if ($i==3)  {	&mov	($s[3],$acc);			}
++}
++
++&function_begin_B("_x86_AES_encrypt");
++	if ($vertical_spin) {
++		# I need high parts of volatile registers to be accessible...
++		&exch	($s1="edi",$key="ebx");
++		&mov	($s2="esi",$acc="ecx");
++	}
++
++	# note that caller is expected to allocate stack frame for me!
++	&mov	($__key,$key);			# save key
++
++	&xor	($s0,&DWP(0,$key));		# xor with key
++	&xor	($s1,&DWP(4,$key));
++	&xor	($s2,&DWP(8,$key));
++	&xor	($s3,&DWP(12,$key));
++
++	&mov	($acc,&DWP(240,$key));		# load key->rounds
++
++	if ($small_footprint) {
++	    &lea	($acc,&DWP(-2,$acc,$acc));
++	    &lea	($acc,&DWP(0,$key,$acc,8));
++	    &mov	($__end,$acc);		# end of key schedule
++
++	    &set_label("loop",16);
++		if ($vertical_spin) {
++		    &encvert($tbl,$s0,$s1,$s2,$s3);
++		} else {
++		    &encstep(0,$tbl,$s0,$s1,$s2,$s3);
++		    &encstep(1,$tbl,$s1,$s2,$s3,$s0);
++		    &encstep(2,$tbl,$s2,$s3,$s0,$s1);
++		    &encstep(3,$tbl,$s3,$s0,$s1,$s2);
++		}
++		&add	($key,16);		# advance rd_key
++		&xor	($s0,&DWP(0,$key));
++		&xor	($s1,&DWP(4,$key));
++		&xor	($s2,&DWP(8,$key));
++		&xor	($s3,&DWP(12,$key));
++	    &cmp	($key,$__end);
++	    &mov	($__key,$key);
++	    &jb		(&label("loop"));
++	}
++	else {
++	    &cmp	($acc,10);
++	    &jle	(&label("10rounds"));
++	    &cmp	($acc,12);
++	    &jle	(&label("12rounds"));
++
++	&set_label("14rounds",4);
++	    for ($i=1;$i<3;$i++) {
++		if ($vertical_spin) {
++		    &encvert($tbl,$s0,$s1,$s2,$s3);
++		} else {
++		    &encstep(0,$tbl,$s0,$s1,$s2,$s3);
++		    &encstep(1,$tbl,$s1,$s2,$s3,$s0);
++		    &encstep(2,$tbl,$s2,$s3,$s0,$s1);
++		    &encstep(3,$tbl,$s3,$s0,$s1,$s2);
++		}
++		&xor	($s0,&DWP(16*$i+0,$key));
++		&xor	($s1,&DWP(16*$i+4,$key));
++		&xor	($s2,&DWP(16*$i+8,$key));
++		&xor	($s3,&DWP(16*$i+12,$key));
++	    }
++	    &add	($key,32);
++	    &mov	($__key,$key);		# advance rd_key
++	&set_label("12rounds",4);
++	    for ($i=1;$i<3;$i++) {
++		if ($vertical_spin) {
++		    &encvert($tbl,$s0,$s1,$s2,$s3);
++		} else {
++		    &encstep(0,$tbl,$s0,$s1,$s2,$s3);
++		    &encstep(1,$tbl,$s1,$s2,$s3,$s0);
++		    &encstep(2,$tbl,$s2,$s3,$s0,$s1);
++		    &encstep(3,$tbl,$s3,$s0,$s1,$s2);
++		}
++		&xor	($s0,&DWP(16*$i+0,$key));
++		&xor	($s1,&DWP(16*$i+4,$key));
++		&xor	($s2,&DWP(16*$i+8,$key));
++		&xor	($s3,&DWP(16*$i+12,$key));
++	    }
++	    &add	($key,32);
++	    &mov	($__key,$key);		# advance rd_key
++	&set_label("10rounds",4);
++	    for ($i=1;$i<10;$i++) {
++		if ($vertical_spin) {
++		    &encvert($tbl,$s0,$s1,$s2,$s3);
++		} else {
++		    &encstep(0,$tbl,$s0,$s1,$s2,$s3);
++		    &encstep(1,$tbl,$s1,$s2,$s3,$s0);
++		    &encstep(2,$tbl,$s2,$s3,$s0,$s1);
++		    &encstep(3,$tbl,$s3,$s0,$s1,$s2);
++		}
++		&xor	($s0,&DWP(16*$i+0,$key));
++		&xor	($s1,&DWP(16*$i+4,$key));
++		&xor	($s2,&DWP(16*$i+8,$key));
++		&xor	($s3,&DWP(16*$i+12,$key));
++	    }
++	}
++
++	if ($vertical_spin) {
++	    # "reincarnate" some registers for "horizontal" spin...
++	    &mov	($s1="ebx",$key="edi");
++	    &mov	($s2="ecx",$acc="esi");
++	}
++	&enclast(0,$tbl,$s0,$s1,$s2,$s3);
++	&enclast(1,$tbl,$s1,$s2,$s3,$s0);
++	&enclast(2,$tbl,$s2,$s3,$s0,$s1);
++	&enclast(3,$tbl,$s3,$s0,$s1,$s2);
++
++	&add	($key,$small_footprint?16:160);
++	&xor	($s0,&DWP(0,$key));
++	&xor	($s1,&DWP(4,$key));
++	&xor	($s2,&DWP(8,$key));
++	&xor	($s3,&DWP(12,$key));
++
++	&ret	();
++
++&set_label("AES_Te",64);	# Yes! I keep it in the code segment!
++	&_data_word(0xa56363c6, 0x847c7cf8, 0x997777ee, 0x8d7b7bf6);
++	&_data_word(0x0df2f2ff, 0xbd6b6bd6, 0xb16f6fde, 0x54c5c591);
++	&_data_word(0x50303060, 0x03010102, 0xa96767ce, 0x7d2b2b56);
++	&_data_word(0x19fefee7, 0x62d7d7b5, 0xe6abab4d, 0x9a7676ec);
++	&_data_word(0x45caca8f, 0x9d82821f, 0x40c9c989, 0x877d7dfa);
++	&_data_word(0x15fafaef, 0xeb5959b2, 0xc947478e, 0x0bf0f0fb);
++	&_data_word(0xecadad41, 0x67d4d4b3, 0xfda2a25f, 0xeaafaf45);
++	&_data_word(0xbf9c9c23, 0xf7a4a453, 0x967272e4, 0x5bc0c09b);
++	&_data_word(0xc2b7b775, 0x1cfdfde1, 0xae93933d, 0x6a26264c);
++	&_data_word(0x5a36366c, 0x413f3f7e, 0x02f7f7f5, 0x4fcccc83);
++	&_data_word(0x5c343468, 0xf4a5a551, 0x34e5e5d1, 0x08f1f1f9);
++	&_data_word(0x937171e2, 0x73d8d8ab, 0x53313162, 0x3f15152a);
++	&_data_word(0x0c040408, 0x52c7c795, 0x65232346, 0x5ec3c39d);
++	&_data_word(0x28181830, 0xa1969637, 0x0f05050a, 0xb59a9a2f);
++	&_data_word(0x0907070e, 0x36121224, 0x9b80801b, 0x3de2e2df);
++	&_data_word(0x26ebebcd, 0x6927274e, 0xcdb2b27f, 0x9f7575ea);
++	&_data_word(0x1b090912, 0x9e83831d, 0x742c2c58, 0x2e1a1a34);
++	&_data_word(0x2d1b1b36, 0xb26e6edc, 0xee5a5ab4, 0xfba0a05b);
++	&_data_word(0xf65252a4, 0x4d3b3b76, 0x61d6d6b7, 0xceb3b37d);
++	&_data_word(0x7b292952, 0x3ee3e3dd, 0x712f2f5e, 0x97848413);
++	&_data_word(0xf55353a6, 0x68d1d1b9, 0x00000000, 0x2cededc1);
++	&_data_word(0x60202040, 0x1ffcfce3, 0xc8b1b179, 0xed5b5bb6);
++	&_data_word(0xbe6a6ad4, 0x46cbcb8d, 0xd9bebe67, 0x4b393972);
++	&_data_word(0xde4a4a94, 0xd44c4c98, 0xe85858b0, 0x4acfcf85);
++	&_data_word(0x6bd0d0bb, 0x2aefefc5, 0xe5aaaa4f, 0x16fbfbed);
++	&_data_word(0xc5434386, 0xd74d4d9a, 0x55333366, 0x94858511);
++	&_data_word(0xcf45458a, 0x10f9f9e9, 0x06020204, 0x817f7ffe);
++	&_data_word(0xf05050a0, 0x443c3c78, 0xba9f9f25, 0xe3a8a84b);
++	&_data_word(0xf35151a2, 0xfea3a35d, 0xc0404080, 0x8a8f8f05);
++	&_data_word(0xad92923f, 0xbc9d9d21, 0x48383870, 0x04f5f5f1);
++	&_data_word(0xdfbcbc63, 0xc1b6b677, 0x75dadaaf, 0x63212142);
++	&_data_word(0x30101020, 0x1affffe5, 0x0ef3f3fd, 0x6dd2d2bf);
++	&_data_word(0x4ccdcd81, 0x140c0c18, 0x35131326, 0x2fececc3);
++	&_data_word(0xe15f5fbe, 0xa2979735, 0xcc444488, 0x3917172e);
++	&_data_word(0x57c4c493, 0xf2a7a755, 0x827e7efc, 0x473d3d7a);
++	&_data_word(0xac6464c8, 0xe75d5dba, 0x2b191932, 0x957373e6);
++	&_data_word(0xa06060c0, 0x98818119, 0xd14f4f9e, 0x7fdcdca3);
++	&_data_word(0x66222244, 0x7e2a2a54, 0xab90903b, 0x8388880b);
++	&_data_word(0xca46468c, 0x29eeeec7, 0xd3b8b86b, 0x3c141428);
++	&_data_word(0x79dedea7, 0xe25e5ebc, 0x1d0b0b16, 0x76dbdbad);
++	&_data_word(0x3be0e0db, 0x56323264, 0x4e3a3a74, 0x1e0a0a14);
++	&_data_word(0xdb494992, 0x0a06060c, 0x6c242448, 0xe45c5cb8);
++	&_data_word(0x5dc2c29f, 0x6ed3d3bd, 0xefacac43, 0xa66262c4);
++	&_data_word(0xa8919139, 0xa4959531, 0x37e4e4d3, 0x8b7979f2);
++	&_data_word(0x32e7e7d5, 0x43c8c88b, 0x5937376e, 0xb76d6dda);
++	&_data_word(0x8c8d8d01, 0x64d5d5b1, 0xd24e4e9c, 0xe0a9a949);
++	&_data_word(0xb46c6cd8, 0xfa5656ac, 0x07f4f4f3, 0x25eaeacf);
++	&_data_word(0xaf6565ca, 0x8e7a7af4, 0xe9aeae47, 0x18080810);
++	&_data_word(0xd5baba6f, 0x887878f0, 0x6f25254a, 0x722e2e5c);
++	&_data_word(0x241c1c38, 0xf1a6a657, 0xc7b4b473, 0x51c6c697);
++	&_data_word(0x23e8e8cb, 0x7cdddda1, 0x9c7474e8, 0x211f1f3e);
++	&_data_word(0xdd4b4b96, 0xdcbdbd61, 0x868b8b0d, 0x858a8a0f);
++	&_data_word(0x907070e0, 0x423e3e7c, 0xc4b5b571, 0xaa6666cc);
++	&_data_word(0xd8484890, 0x05030306, 0x01f6f6f7, 0x120e0e1c);
++	&_data_word(0xa36161c2, 0x5f35356a, 0xf95757ae, 0xd0b9b969);
++	&_data_word(0x91868617, 0x58c1c199, 0x271d1d3a, 0xb99e9e27);
++	&_data_word(0x38e1e1d9, 0x13f8f8eb, 0xb398982b, 0x33111122);
++	&_data_word(0xbb6969d2, 0x70d9d9a9, 0x898e8e07, 0xa7949433);
++	&_data_word(0xb69b9b2d, 0x221e1e3c, 0x92878715, 0x20e9e9c9);
++	&_data_word(0x49cece87, 0xff5555aa, 0x78282850, 0x7adfdfa5);
++	&_data_word(0x8f8c8c03, 0xf8a1a159, 0x80898909, 0x170d0d1a);
++	&_data_word(0xdabfbf65, 0x31e6e6d7, 0xc6424284, 0xb86868d0);
++	&_data_word(0xc3414182, 0xb0999929, 0x772d2d5a, 0x110f0f1e);
++	&_data_word(0xcbb0b07b, 0xfc5454a8, 0xd6bbbb6d, 0x3a16162c);
++
++#Te4	# four copies of Te4 to choose from to avoid L1 aliasing
++	&data_byte(0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5);
++	&data_byte(0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76);
++	&data_byte(0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0);
++	&data_byte(0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0);
++	&data_byte(0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc);
++	&data_byte(0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15);
++	&data_byte(0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a);
++	&data_byte(0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75);
++	&data_byte(0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0);
++	&data_byte(0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84);
++	&data_byte(0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b);
++	&data_byte(0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf);
++	&data_byte(0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85);
++	&data_byte(0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8);
++	&data_byte(0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5);
++	&data_byte(0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2);
++	&data_byte(0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17);
++	&data_byte(0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73);
++	&data_byte(0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88);
++	&data_byte(0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb);
++	&data_byte(0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c);
++	&data_byte(0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79);
++	&data_byte(0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9);
++	&data_byte(0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08);
++	&data_byte(0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6);
++	&data_byte(0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a);
++	&data_byte(0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e);
++	&data_byte(0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e);
++	&data_byte(0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94);
++	&data_byte(0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf);
++	&data_byte(0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68);
++	&data_byte(0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16);
++
++	&data_byte(0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5);
++	&data_byte(0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76);
++	&data_byte(0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0);
++	&data_byte(0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0);
++	&data_byte(0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc);
++	&data_byte(0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15);
++	&data_byte(0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a);
++	&data_byte(0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75);
++	&data_byte(0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0);
++	&data_byte(0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84);
++	&data_byte(0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b);
++	&data_byte(0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf);
++	&data_byte(0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85);
++	&data_byte(0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8);
++	&data_byte(0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5);
++	&data_byte(0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2);
++	&data_byte(0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17);
++	&data_byte(0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73);
++	&data_byte(0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88);
++	&data_byte(0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb);
++	&data_byte(0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c);
++	&data_byte(0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79);
++	&data_byte(0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9);
++	&data_byte(0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08);
++	&data_byte(0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6);
++	&data_byte(0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a);
++	&data_byte(0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e);
++	&data_byte(0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e);
++	&data_byte(0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94);
++	&data_byte(0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf);
++	&data_byte(0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68);
++	&data_byte(0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16);
++
++	&data_byte(0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5);
++	&data_byte(0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76);
++	&data_byte(0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0);
++	&data_byte(0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0);
++	&data_byte(0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc);
++	&data_byte(0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15);
++	&data_byte(0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a);
++	&data_byte(0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75);
++	&data_byte(0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0);
++	&data_byte(0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84);
++	&data_byte(0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b);
++	&data_byte(0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf);
++	&data_byte(0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85);
++	&data_byte(0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8);
++	&data_byte(0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5);
++	&data_byte(0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2);
++	&data_byte(0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17);
++	&data_byte(0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73);
++	&data_byte(0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88);
++	&data_byte(0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb);
++	&data_byte(0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c);
++	&data_byte(0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79);
++	&data_byte(0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9);
++	&data_byte(0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08);
++	&data_byte(0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6);
++	&data_byte(0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a);
++	&data_byte(0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e);
++	&data_byte(0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e);
++	&data_byte(0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94);
++	&data_byte(0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf);
++	&data_byte(0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68);
++	&data_byte(0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16);
++
++	&data_byte(0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5);
++	&data_byte(0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76);
++	&data_byte(0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0);
++	&data_byte(0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0);
++	&data_byte(0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc);
++	&data_byte(0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15);
++	&data_byte(0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a);
++	&data_byte(0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75);
++	&data_byte(0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0);
++	&data_byte(0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84);
++	&data_byte(0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b);
++	&data_byte(0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf);
++	&data_byte(0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85);
++	&data_byte(0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8);
++	&data_byte(0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5);
++	&data_byte(0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2);
++	&data_byte(0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17);
++	&data_byte(0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73);
++	&data_byte(0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88);
++	&data_byte(0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb);
++	&data_byte(0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c);
++	&data_byte(0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79);
++	&data_byte(0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9);
++	&data_byte(0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08);
++	&data_byte(0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6);
++	&data_byte(0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a);
++	&data_byte(0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e);
++	&data_byte(0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e);
++	&data_byte(0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94);
++	&data_byte(0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf);
++	&data_byte(0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68);
++	&data_byte(0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16);
++#rcon:
++	&data_word(0x00000001, 0x00000002, 0x00000004, 0x00000008);
++	&data_word(0x00000010, 0x00000020, 0x00000040, 0x00000080);
++	&data_word(0x0000001b, 0x00000036, 0x00000000, 0x00000000);
++	&data_word(0x00000000, 0x00000000, 0x00000000, 0x00000000);
++&function_end_B("_x86_AES_encrypt");
++
++# void AES_encrypt (const void *inp,void *out,const AES_KEY *key);
++&function_begin("AES_encrypt");
++	&mov	($acc,&wparam(0));		# load inp
++	&mov	($key,&wparam(2));		# load key
++
++	&mov	($s0,"esp");
++	&sub	("esp",36);
++	&and	("esp",-64);			# align to cache-line
++
++	# place stack frame just "above" the key schedule
++	&lea	($s1,&DWP(-64-63,$key));
++	&sub	($s1,"esp");
++	&neg	($s1);
++	&and	($s1,0x3C0);	# modulo 1024, but aligned to cache-line
++	&sub	("esp",$s1);
++	&add	("esp",4);	# 4 is reserved for caller's return address
++	&mov	($_esp,$s0);			# save stack pointer
++
++	&call   (&label("pic_point"));          # make it PIC!
++	&set_label("pic_point");
++	&blindpop($tbl);
++	&picmeup($s0,"OPENSSL_ia32cap_P",$tbl,&label("pic_point")) if (!$x86only);
++	&lea    ($tbl,&DWP(&label("AES_Te")."-".&label("pic_point"),$tbl));
++
++	# pick Te4 copy which can't "overlap" with stack frame or key schedule
++	&lea	($s1,&DWP(768-4,"esp"));
++	&sub	($s1,$tbl);
++	&and	($s1,0x300);
++	&lea	($tbl,&DWP(2048+128,$tbl,$s1));
++
++					if (!$x86only) {
++	&bt	(&DWP(0,$s0),25);	# check for SSE bit
++	&jnc	(&label("x86"));
++
++	&movq	("mm0",&QWP(0,$acc));
++	&movq	("mm4",&QWP(8,$acc));
++	&call	("_sse_AES_encrypt_compact");
++	&mov	("esp",$_esp);			# restore stack pointer
++	&mov	($acc,&wparam(1));		# load out
++	&movq	(&QWP(0,$acc),"mm0");		# write output data
++	&movq	(&QWP(8,$acc),"mm4");
++	&emms	();
++	&function_end_A();
++					}
++	&set_label("x86",16);
++	&mov	($_tbl,$tbl);
++	&mov	($s0,&DWP(0,$acc));		# load input data
++	&mov	($s1,&DWP(4,$acc));
++	&mov	($s2,&DWP(8,$acc));
++	&mov	($s3,&DWP(12,$acc));
++	&call	("_x86_AES_encrypt_compact");
++	&mov	("esp",$_esp);			# restore stack pointer
++	&mov	($acc,&wparam(1));		# load out
++	&mov	(&DWP(0,$acc),$s0);		# write output data
++	&mov	(&DWP(4,$acc),$s1);
++	&mov	(&DWP(8,$acc),$s2);
++	&mov	(&DWP(12,$acc),$s3);
++&function_end("AES_encrypt");
++
++#--------------------------------------------------------------------#
++
++######################################################################
++# "Compact" block function
++######################################################################
++
++sub deccompact()
++{ my $Fn = \&mov;
++  while ($#_>5) { pop(@_); $Fn=sub{}; }
++  my ($i,$td,@s)=@_;
++  my $tmp = $key;
++  my $out = $i==3?$s[0]:$acc;
++
++	# $Fn is used in first compact round and its purpose is to
++	# void restoration of some values from stack, so that after
++	# 4xdeccompact with extra argument $key, $s0 and $s1 values
++	# are left there...
++	if($i==3)   {	&$Fn	($key,$__key);			}
++	else        {	&mov	($out,$s[0]);			}
++			&and	($out,0xFF);
++			&movz	($out,&BP(-128,$td,$out,1));
++
++	if ($i==3)  {	$tmp=$s[1];				}
++			&movz	($tmp,&HB($s[1]));
++			&movz	($tmp,&BP(-128,$td,$tmp,1));
++			&shl	($tmp,8);
++			&xor	($out,$tmp);
++
++	if ($i==3)  {	$tmp=$s[2]; &mov ($s[1],$acc);		}
++	else        {	mov	($tmp,$s[2]);			}
++			&shr	($tmp,16);
++			&and	($tmp,0xFF);
++			&movz	($tmp,&BP(-128,$td,$tmp,1));
++			&shl	($tmp,16);
++			&xor	($out,$tmp);
++
++	if ($i==3)  {	$tmp=$s[3]; &$Fn ($s[2],$__s1);		}
++	else        {	&mov	($tmp,$s[3]);			}
++			&shr	($tmp,24);
++			&movz	($tmp,&BP(-128,$td,$tmp,1));
++			&shl	($tmp,24);
++			&xor	($out,$tmp);
++	if ($i<2)   {	&mov	(&DWP(4+4*$i,"esp"),$out);	}
++	if ($i==3)  {	&$Fn	($s[3],$__s0);			}
++}
++
++# must be called with 2,3,0,1 as argument sequence!!!
++sub dectransform()
++{ my @s = ($s0,$s1,$s2,$s3);
++  my $i = shift;
++  my $tmp = $key;
++  my $tp2 = @s[($i+2)%4]; $tp2 = @s[2] if ($i==1);
++  my $tp4 = @s[($i+3)%4]; $tp4 = @s[3] if ($i==1);
++  my $tp8 = $tbl;
++
++	&mov	($tmp,0x80808080);
++	&and	($tmp,$s[$i]);
++	&mov	($acc,$tmp);
++	&shr	($tmp,7);
++	&lea	($tp2,&DWP(0,$s[$i],$s[$i]));
++	&sub	($acc,$tmp);
++	&and	($tp2,0xfefefefe);
++	&and	($acc,0x1b1b1b1b);
++	&xor	($tp2,$acc);
++	&mov	($tmp,0x80808080);
++
++	&and	($tmp,$tp2);
++	&mov	($acc,$tmp);
++	&shr	($tmp,7);
++	&lea	($tp4,&DWP(0,$tp2,$tp2));
++	&sub	($acc,$tmp);
++	&and	($tp4,0xfefefefe);
++	&and	($acc,0x1b1b1b1b);
++	 &xor	($tp2,$s[$i]);	# tp2^tp1
++	&xor	($tp4,$acc);
++	&mov	($tmp,0x80808080);
++
++	&and	($tmp,$tp4);
++	&mov	($acc,$tmp);
++	&shr	($tmp,7);
++	&lea	($tp8,&DWP(0,$tp4,$tp4));
++	&sub	($acc,$tmp);
++	&and	($tp8,0xfefefefe);
++	&and	($acc,0x1b1b1b1b);
++	 &xor	($tp4,$s[$i]);	# tp4^tp1
++	 &rotl	($s[$i],8);	# = ROTATE(tp1,8)
++	&xor	($tp8,$acc);
++
++	&xor	($s[$i],$tp2);
++	&xor	($tp2,$tp8);
++	&xor	($s[$i],$tp4);
++	&xor	($tp4,$tp8);
++	&rotl	($tp2,24);
++	&xor	($s[$i],$tp8);	# ^= tp8^(tp4^tp1)^(tp2^tp1)
++	&rotl	($tp4,16);
++	&xor	($s[$i],$tp2);	# ^= ROTATE(tp8^tp2^tp1,24)
++	&rotl	($tp8,8);
++	&xor	($s[$i],$tp4);	# ^= ROTATE(tp8^tp4^tp1,16)
++	 &mov	($s[0],$__s0)			if($i==2); #prefetch $s0
++	 &mov	($s[1],$__s1)			if($i==3); #prefetch $s1
++	 &mov	($s[2],$__s2)			if($i==1);
++	&xor	($s[$i],$tp8);	# ^= ROTATE(tp8,8)
++
++	&mov	($s[3],$__s3)			if($i==1);
++	&mov	(&DWP(4+4*$i,"esp"),$s[$i])	if($i>=2);
++}
++
++&function_begin_B("_x86_AES_decrypt_compact");
++	# note that caller is expected to allocate stack frame for me!
++	&mov	($__key,$key);			# save key
++
++	&xor	($s0,&DWP(0,$key));		# xor with key
++	&xor	($s1,&DWP(4,$key));
++	&xor	($s2,&DWP(8,$key));
++	&xor	($s3,&DWP(12,$key));
++
++	&mov	($acc,&DWP(240,$key));		# load key->rounds
++
++	&lea	($acc,&DWP(-2,$acc,$acc));
++	&lea	($acc,&DWP(0,$key,$acc,8));
++	&mov	($__end,$acc);			# end of key schedule
++
++	# prefetch Td4
++	&mov	($key,&DWP(0-128,$tbl));
++	&mov	($acc,&DWP(32-128,$tbl));
++	&mov	($key,&DWP(64-128,$tbl));
++	&mov	($acc,&DWP(96-128,$tbl));
++	&mov	($key,&DWP(128-128,$tbl));
++	&mov	($acc,&DWP(160-128,$tbl));
++	&mov	($key,&DWP(192-128,$tbl));
++	&mov	($acc,&DWP(224-128,$tbl));
++
++	&set_label("loop",16);
++
++		&deccompact(0,$tbl,$s0,$s3,$s2,$s1,1);
++		&deccompact(1,$tbl,$s1,$s0,$s3,$s2,1);
++		&deccompact(2,$tbl,$s2,$s1,$s0,$s3,1);
++		&deccompact(3,$tbl,$s3,$s2,$s1,$s0,1);
++		&dectransform(2);
++		&dectransform(3);
++		&dectransform(0);
++		&dectransform(1);
++		&mov 	($key,$__key);
++		&mov	($tbl,$__tbl);
++		&add	($key,16);		# advance rd_key
++		&xor	($s0,&DWP(0,$key));
++		&xor	($s1,&DWP(4,$key));
++		&xor	($s2,&DWP(8,$key));
++		&xor	($s3,&DWP(12,$key));
++
++	&cmp	($key,$__end);
++	&mov	($__key,$key);
++	&jb	(&label("loop"));
++
++	&deccompact(0,$tbl,$s0,$s3,$s2,$s1);
++	&deccompact(1,$tbl,$s1,$s0,$s3,$s2);
++	&deccompact(2,$tbl,$s2,$s1,$s0,$s3);
++	&deccompact(3,$tbl,$s3,$s2,$s1,$s0);
++
++	&xor	($s0,&DWP(16,$key));
++	&xor	($s1,&DWP(20,$key));
++	&xor	($s2,&DWP(24,$key));
++	&xor	($s3,&DWP(28,$key));
++
++	&ret	();
++&function_end_B("_x86_AES_decrypt_compact");
++
++######################################################################
++# "Compact" SSE block function.
++######################################################################
++
++sub sse_deccompact()
++{
++	&pshufw	("mm1","mm0",0x0c);		#  7, 6, 1, 0
++	&pshufw	("mm5","mm4",0x09);		# 13,12,11,10
++	&movd	("eax","mm1");			#  7, 6, 1, 0
++	&movd	("ebx","mm5");			# 13,12,11,10
++	&mov	($__key,$key);
++
++	&movz	($acc,&LB("eax"));		#  0
++	&movz	("edx",&HB("eax"));		#  1
++	&pshufw	("mm2","mm0",0x06);		#  3, 2, 5, 4
++	&movz	("ecx",&BP(-128,$tbl,$acc,1));	#  0
++	&movz	($key,&LB("ebx"));		# 10
++	&movz	("edx",&BP(-128,$tbl,"edx",1));	#  1
++	&shr	("eax",16);			#  7, 6
++	&shl	("edx",8);			#  1
++
++	&movz	($acc,&BP(-128,$tbl,$key,1));	# 10
++	&movz	($key,&HB("ebx"));		# 11
++	&shl	($acc,16);			# 10
++	&pshufw	("mm6","mm4",0x03);		# 9, 8,15,14
++	&or	("ecx",$acc);			# 10
++	&movz	($acc,&BP(-128,$tbl,$key,1));	# 11
++	&movz	($key,&HB("eax"));		#  7
++	&shl	($acc,24);			# 11
++	&shr	("ebx",16);			# 13,12
++	&or	("edx",$acc);			# 11
++
++	&movz	($acc,&BP(-128,$tbl,$key,1));	#  7
++	&movz	($key,&HB("ebx"));		# 13
++	&shl	($acc,24);			#  7
++	&or	("ecx",$acc);			#  7
++	&movz	($acc,&BP(-128,$tbl,$key,1));	# 13
++	&movz	($key,&LB("eax"));		#  6
++	&shl	($acc,8);			# 13
++	&movd	("eax","mm2");			#  3, 2, 5, 4
++	&or	("ecx",$acc);			# 13
++
++	&movz	($acc,&BP(-128,$tbl,$key,1));	#  6
++	&movz	($key,&LB("ebx"));		# 12
++	&shl	($acc,16);			#  6
++	&movd	("ebx","mm6");			#  9, 8,15,14
++	&movd	("mm0","ecx");			# t[0] collected
++	&movz	("ecx",&BP(-128,$tbl,$key,1));	# 12
++	&movz	($key,&LB("eax"));		#  4
++	&or	("ecx",$acc);			# 12
++
++	&movz	($acc,&BP(-128,$tbl,$key,1));	#  4
++	&movz	($key,&LB("ebx"));		# 14
++	&or	("edx",$acc);			#  4
++	&movz	($acc,&BP(-128,$tbl,$key,1));	# 14
++	&movz	($key,&HB("eax"));		#  5
++	&shl	($acc,16);			# 14
++	&shr	("eax",16);			#  3, 2
++	&or	("edx",$acc);			# 14
++
++	&movz	($acc,&BP(-128,$tbl,$key,1));	#  5
++	&movz	($key,&HB("ebx"));		# 15
++	&shr	("ebx",16);			#  9, 8
++	&shl	($acc,8);			#  5
++	&movd	("mm1","edx");			# t[1] collected
++	&movz	("edx",&BP(-128,$tbl,$key,1));	# 15
++	&movz	($key,&HB("ebx"));		#  9
++	&shl	("edx",24);			# 15
++	&and	("ebx",0xff);			#  8
++	&or	("edx",$acc);			# 15
++
++	&punpckldq	("mm0","mm1");		# t[0,1] collected
++
++	&movz	($acc,&BP(-128,$tbl,$key,1));	#  9
++	&movz	($key,&LB("eax"));		#  2
++	&shl	($acc,8);			#  9
++	&movz	("eax",&HB("eax"));		#  3
++	&movz	("ebx",&BP(-128,$tbl,"ebx",1));	#  8
++	&or	("ecx",$acc);			#  9
++	&movz	($acc,&BP(-128,$tbl,$key,1));	#  2
++	&or	("edx","ebx");			#  8
++	&shl	($acc,16);			#  2
++	&movz	("eax",&BP(-128,$tbl,"eax",1));	#  3
++	&or	("edx",$acc);			#  2
++	&shl	("eax",24);			#  3
++	&or	("ecx","eax");			#  3
++	&mov	($key,$__key);
++	&movd	("mm4","edx");			# t[2] collected
++	&movd	("mm5","ecx");			# t[3] collected
++
++	&punpckldq	("mm4","mm5");		# t[2,3] collected
++}
++
++					if (!$x86only) {
++&function_begin_B("_sse_AES_decrypt_compact");
++	&pxor	("mm0",&QWP(0,$key));	#  7, 6, 5, 4, 3, 2, 1, 0
++	&pxor	("mm4",&QWP(8,$key));	# 15,14,13,12,11,10, 9, 8
++
++	# note that caller is expected to allocate stack frame for me!
++	&mov	($acc,&DWP(240,$key));		# load key->rounds
++	&lea	($acc,&DWP(-2,$acc,$acc));
++	&lea	($acc,&DWP(0,$key,$acc,8));
++	&mov	($__end,$acc);			# end of key schedule
++
++	&mov	($s0,0x1b1b1b1b);		# magic constant
++	&mov	(&DWP(8,"esp"),$s0);
++	&mov	(&DWP(12,"esp"),$s0);
++
++	# prefetch Td4
++	&mov	($s0,&DWP(0-128,$tbl));
++	&mov	($s1,&DWP(32-128,$tbl));
++	&mov	($s2,&DWP(64-128,$tbl));
++	&mov	($s3,&DWP(96-128,$tbl));
++	&mov	($s0,&DWP(128-128,$tbl));
++	&mov	($s1,&DWP(160-128,$tbl));
++	&mov	($s2,&DWP(192-128,$tbl));
++	&mov	($s3,&DWP(224-128,$tbl));
++
++	&set_label("loop",16);
++		&sse_deccompact();
++		&add	($key,16);
++		&cmp	($key,$__end);
++		&ja	(&label("out"));
++
++		# ROTATE(x^y,N) == ROTATE(x,N)^ROTATE(y,N)
++		&movq	("mm3","mm0");		&movq	("mm7","mm4");
++		&movq	("mm2","mm0",1);	&movq	("mm6","mm4",1);
++		&movq	("mm1","mm0");		&movq	("mm5","mm4");
++		&pshufw	("mm0","mm0",0xb1);	&pshufw	("mm4","mm4",0xb1);# = ROTATE(tp0,16)
++		&pslld	("mm2",8);		&pslld	("mm6",8);
++		&psrld	("mm3",8);		&psrld	("mm7",8);
++		&pxor	("mm0","mm2");		&pxor	("mm4","mm6");	# ^= tp0<<8
++		&pxor	("mm0","mm3");		&pxor	("mm4","mm7");	# ^= tp0>>8
++		&pslld	("mm2",16);		&pslld	("mm6",16);
++		&psrld	("mm3",16);		&psrld	("mm7",16);
++		&pxor	("mm0","mm2");		&pxor	("mm4","mm6");	# ^= tp0<<24
++		&pxor	("mm0","mm3");		&pxor	("mm4","mm7");	# ^= tp0>>24
++
++		&movq	("mm3",&QWP(8,"esp"));
++		&pxor	("mm2","mm2");		&pxor	("mm6","mm6");
++		&pcmpgtb("mm2","mm1");		&pcmpgtb("mm6","mm5");
++		&pand	("mm2","mm3");		&pand	("mm6","mm3");
++		&paddb	("mm1","mm1");		&paddb	("mm5","mm5");
++		&pxor	("mm1","mm2");		&pxor	("mm5","mm6");	# tp2
++		&movq	("mm3","mm1");		&movq	("mm7","mm5");
++		&movq	("mm2","mm1");		&movq	("mm6","mm5");
++		&pxor	("mm0","mm1");		&pxor	("mm4","mm5");	# ^= tp2
++		&pslld	("mm3",24);		&pslld	("mm7",24);
++		&psrld	("mm2",8);		&psrld	("mm6",8);
++		&pxor	("mm0","mm3");		&pxor	("mm4","mm7");	# ^= tp2<<24
++		&pxor	("mm0","mm2");		&pxor	("mm4","mm6");	# ^= tp2>>8
++
++		&movq	("mm2",&QWP(8,"esp"));
++		&pxor	("mm3","mm3");		&pxor	("mm7","mm7");
++		&pcmpgtb("mm3","mm1");		&pcmpgtb("mm7","mm5");
++		&pand	("mm3","mm2");		&pand	("mm7","mm2");
++		&paddb	("mm1","mm1");		&paddb	("mm5","mm5");
++		&pxor	("mm1","mm3");		&pxor	("mm5","mm7");	# tp4
++		&pshufw	("mm3","mm1",0xb1);	&pshufw	("mm7","mm5",0xb1);
++		&pxor	("mm0","mm1");		&pxor	("mm4","mm5");	# ^= tp4
++		&pxor	("mm0","mm3");		&pxor	("mm4","mm7");	# ^= ROTATE(tp4,16)	
++
++		&pxor	("mm3","mm3");		&pxor	("mm7","mm7");
++		&pcmpgtb("mm3","mm1");		&pcmpgtb("mm7","mm5");
++		&pand	("mm3","mm2");		&pand	("mm7","mm2");
++		&paddb	("mm1","mm1");		&paddb	("mm5","mm5");
++		&pxor	("mm1","mm3");		&pxor	("mm5","mm7");	# tp8
++		&pxor	("mm0","mm1");		&pxor	("mm4","mm5");	# ^= tp8
++		&movq	("mm3","mm1");		&movq	("mm7","mm5");
++		&pshufw	("mm2","mm1",0xb1);	&pshufw	("mm6","mm5",0xb1);
++		&pxor	("mm0","mm2");		&pxor	("mm4","mm6");	# ^= ROTATE(tp8,16)
++		&pslld	("mm1",8);		&pslld	("mm5",8);
++		&psrld	("mm3",8);		&psrld	("mm7",8);
++		&movq	("mm2",&QWP(0,$key));	&movq	("mm6",&QWP(8,$key));
++		&pxor	("mm0","mm1");		&pxor	("mm4","mm5");	# ^= tp8<<8
++		&pxor	("mm0","mm3");		&pxor	("mm4","mm7");	# ^= tp8>>8
++		&mov	($s0,&DWP(0-128,$tbl));
++		&pslld	("mm1",16);		&pslld	("mm5",16);
++		&mov	($s1,&DWP(64-128,$tbl));
++		&psrld	("mm3",16);		&psrld	("mm7",16);
++		&mov	($s2,&DWP(128-128,$tbl));
++		&pxor	("mm0","mm1");		&pxor	("mm4","mm5");	# ^= tp8<<24
++		&mov	($s3,&DWP(192-128,$tbl));
++		&pxor	("mm0","mm3");		&pxor	("mm4","mm7");	# ^= tp8>>24
++
++		&pxor	("mm0","mm2");		&pxor	("mm4","mm6");
++	&jmp	(&label("loop"));
++
++	&set_label("out",16);
++	&pxor	("mm0",&QWP(0,$key));
++	&pxor	("mm4",&QWP(8,$key));
++
++	&ret	();
++&function_end_B("_sse_AES_decrypt_compact");
++					}
++
++######################################################################
++# Vanilla block function.
++######################################################################
++
++sub decstep()
++{ my ($i,$td,@s) = @_;
++  my $tmp = $key;
++  my $out = $i==3?$s[0]:$acc;
++
++	# no instructions are reordered, as performance appears
++	# optimal... or rather that all attempts to reorder didn't
++	# result in better performance [which by the way is not a
++	# bit lower than ecryption].
++	if($i==3)   {	&mov	($key,$__key);			}
++	else        {	&mov	($out,$s[0]);			}
++			&and	($out,0xFF);
++			&mov	($out,&DWP(0,$td,$out,8));
++
++	if ($i==3)  {	$tmp=$s[1];				}
++			&movz	($tmp,&HB($s[1]));
++			&xor	($out,&DWP(3,$td,$tmp,8));
++
++	if ($i==3)  {	$tmp=$s[2]; &mov ($s[1],$acc);		}
++	else        {	&mov	($tmp,$s[2]);			}
++			&shr	($tmp,16);
++			&and	($tmp,0xFF);
++			&xor	($out,&DWP(2,$td,$tmp,8));
++
++	if ($i==3)  {	$tmp=$s[3]; &mov ($s[2],$__s1);		}
++	else        {	&mov	($tmp,$s[3]);			}
++			&shr	($tmp,24);
++			&xor	($out,&DWP(1,$td,$tmp,8));
++	if ($i<2)   {	&mov	(&DWP(4+4*$i,"esp"),$out);	}
++	if ($i==3)  {	&mov	($s[3],$__s0);			}
++			&comment();
++}
++
++sub declast()
++{ my ($i,$td,@s)=@_;
++  my $tmp = $key;
++  my $out = $i==3?$s[0]:$acc;
++
++	if($i==0)   {	&lea	($td,&DWP(2048+128,$td));
++			&mov	($tmp,&DWP(0-128,$td));
++			&mov	($acc,&DWP(32-128,$td));
++			&mov	($tmp,&DWP(64-128,$td));
++			&mov	($acc,&DWP(96-128,$td));
++			&mov	($tmp,&DWP(128-128,$td));
++			&mov	($acc,&DWP(160-128,$td));
++			&mov	($tmp,&DWP(192-128,$td));
++			&mov	($acc,&DWP(224-128,$td));
++			&lea	($td,&DWP(-128,$td));		}
++	if($i==3)   {	&mov	($key,$__key);			}
++	else        {	&mov	($out,$s[0]);			}
++			&and	($out,0xFF);
++			&movz	($out,&BP(0,$td,$out,1));
++
++	if ($i==3)  {	$tmp=$s[1];				}
++			&movz	($tmp,&HB($s[1]));
++			&movz	($tmp,&BP(0,$td,$tmp,1));
++			&shl	($tmp,8);
++			&xor	($out,$tmp);
++
++	if ($i==3)  {	$tmp=$s[2]; &mov ($s[1],$acc);		}
++	else        {	mov	($tmp,$s[2]);			}
++			&shr	($tmp,16);
++			&and	($tmp,0xFF);
++			&movz	($tmp,&BP(0,$td,$tmp,1));
++			&shl	($tmp,16);
++			&xor	($out,$tmp);
++
++	if ($i==3)  {	$tmp=$s[3]; &mov ($s[2],$__s1);		}
++	else        {	&mov	($tmp,$s[3]);			}
++			&shr	($tmp,24);
++			&movz	($tmp,&BP(0,$td,$tmp,1));
++			&shl	($tmp,24);
++			&xor	($out,$tmp);
++	if ($i<2)   {	&mov	(&DWP(4+4*$i,"esp"),$out);	}
++	if ($i==3)  {	&mov	($s[3],$__s0);
++			&lea	($td,&DWP(-2048,$td));		}
++}
++
++&function_begin_B("_x86_AES_decrypt");
++	# note that caller is expected to allocate stack frame for me!
++	&mov	($__key,$key);			# save key
++
++	&xor	($s0,&DWP(0,$key));		# xor with key
++	&xor	($s1,&DWP(4,$key));
++	&xor	($s2,&DWP(8,$key));
++	&xor	($s3,&DWP(12,$key));
++
++	&mov	($acc,&DWP(240,$key));		# load key->rounds
++
++	if ($small_footprint) {
++	    &lea	($acc,&DWP(-2,$acc,$acc));
++	    &lea	($acc,&DWP(0,$key,$acc,8));
++	    &mov	($__end,$acc);		# end of key schedule
++	    &set_label("loop",16);
++		&decstep(0,$tbl,$s0,$s3,$s2,$s1);
++		&decstep(1,$tbl,$s1,$s0,$s3,$s2);
++		&decstep(2,$tbl,$s2,$s1,$s0,$s3);
++		&decstep(3,$tbl,$s3,$s2,$s1,$s0);
++		&add	($key,16);		# advance rd_key
++		&xor	($s0,&DWP(0,$key));
++		&xor	($s1,&DWP(4,$key));
++		&xor	($s2,&DWP(8,$key));
++		&xor	($s3,&DWP(12,$key));
++	    &cmp	($key,$__end);
++	    &mov	($__key,$key);
++	    &jb		(&label("loop"));
++	}
++	else {
++	    &cmp	($acc,10);
++	    &jle	(&label("10rounds"));
++	    &cmp	($acc,12);
++	    &jle	(&label("12rounds"));
++
++	&set_label("14rounds",4);
++	    for ($i=1;$i<3;$i++) {
++		&decstep(0,$tbl,$s0,$s3,$s2,$s1);
++		&decstep(1,$tbl,$s1,$s0,$s3,$s2);
++		&decstep(2,$tbl,$s2,$s1,$s0,$s3);
++		&decstep(3,$tbl,$s3,$s2,$s1,$s0);
++		&xor	($s0,&DWP(16*$i+0,$key));
++		&xor	($s1,&DWP(16*$i+4,$key));
++		&xor	($s2,&DWP(16*$i+8,$key));
++		&xor	($s3,&DWP(16*$i+12,$key));
++	    }
++	    &add	($key,32);
++	    &mov	($__key,$key);		# advance rd_key
++	&set_label("12rounds",4);
++	    for ($i=1;$i<3;$i++) {
++		&decstep(0,$tbl,$s0,$s3,$s2,$s1);
++		&decstep(1,$tbl,$s1,$s0,$s3,$s2);
++		&decstep(2,$tbl,$s2,$s1,$s0,$s3);
++		&decstep(3,$tbl,$s3,$s2,$s1,$s0);
++		&xor	($s0,&DWP(16*$i+0,$key));
++		&xor	($s1,&DWP(16*$i+4,$key));
++		&xor	($s2,&DWP(16*$i+8,$key));
++		&xor	($s3,&DWP(16*$i+12,$key));
++	    }
++	    &add	($key,32);
++	    &mov	($__key,$key);		# advance rd_key
++	&set_label("10rounds",4);
++	    for ($i=1;$i<10;$i++) {
++		&decstep(0,$tbl,$s0,$s3,$s2,$s1);
++		&decstep(1,$tbl,$s1,$s0,$s3,$s2);
++		&decstep(2,$tbl,$s2,$s1,$s0,$s3);
++		&decstep(3,$tbl,$s3,$s2,$s1,$s0);
++		&xor	($s0,&DWP(16*$i+0,$key));
++		&xor	($s1,&DWP(16*$i+4,$key));
++		&xor	($s2,&DWP(16*$i+8,$key));
++		&xor	($s3,&DWP(16*$i+12,$key));
++	    }
++	}
++
++	&declast(0,$tbl,$s0,$s3,$s2,$s1);
++	&declast(1,$tbl,$s1,$s0,$s3,$s2);
++	&declast(2,$tbl,$s2,$s1,$s0,$s3);
++	&declast(3,$tbl,$s3,$s2,$s1,$s0);
++
++	&add	($key,$small_footprint?16:160);
++	&xor	($s0,&DWP(0,$key));
++	&xor	($s1,&DWP(4,$key));
++	&xor	($s2,&DWP(8,$key));
++	&xor	($s3,&DWP(12,$key));
++
++	&ret	();
++
++&set_label("AES_Td",64);	# Yes! I keep it in the code segment!
++	&_data_word(0x50a7f451, 0x5365417e, 0xc3a4171a, 0x965e273a);
++	&_data_word(0xcb6bab3b, 0xf1459d1f, 0xab58faac, 0x9303e34b);
++	&_data_word(0x55fa3020, 0xf66d76ad, 0x9176cc88, 0x254c02f5);
++	&_data_word(0xfcd7e54f, 0xd7cb2ac5, 0x80443526, 0x8fa362b5);
++	&_data_word(0x495ab1de, 0x671bba25, 0x980eea45, 0xe1c0fe5d);
++	&_data_word(0x02752fc3, 0x12f04c81, 0xa397468d, 0xc6f9d36b);
++	&_data_word(0xe75f8f03, 0x959c9215, 0xeb7a6dbf, 0xda595295);
++	&_data_word(0x2d83bed4, 0xd3217458, 0x2969e049, 0x44c8c98e);
++	&_data_word(0x6a89c275, 0x78798ef4, 0x6b3e5899, 0xdd71b927);
++	&_data_word(0xb64fe1be, 0x17ad88f0, 0x66ac20c9, 0xb43ace7d);
++	&_data_word(0x184adf63, 0x82311ae5, 0x60335197, 0x457f5362);
++	&_data_word(0xe07764b1, 0x84ae6bbb, 0x1ca081fe, 0x942b08f9);
++	&_data_word(0x58684870, 0x19fd458f, 0x876cde94, 0xb7f87b52);
++	&_data_word(0x23d373ab, 0xe2024b72, 0x578f1fe3, 0x2aab5566);
++	&_data_word(0x0728ebb2, 0x03c2b52f, 0x9a7bc586, 0xa50837d3);
++	&_data_word(0xf2872830, 0xb2a5bf23, 0xba6a0302, 0x5c8216ed);
++	&_data_word(0x2b1ccf8a, 0x92b479a7, 0xf0f207f3, 0xa1e2694e);
++	&_data_word(0xcdf4da65, 0xd5be0506, 0x1f6234d1, 0x8afea6c4);
++	&_data_word(0x9d532e34, 0xa055f3a2, 0x32e18a05, 0x75ebf6a4);
++	&_data_word(0x39ec830b, 0xaaef6040, 0x069f715e, 0x51106ebd);
++	&_data_word(0xf98a213e, 0x3d06dd96, 0xae053edd, 0x46bde64d);
++	&_data_word(0xb58d5491, 0x055dc471, 0x6fd40604, 0xff155060);
++	&_data_word(0x24fb9819, 0x97e9bdd6, 0xcc434089, 0x779ed967);
++	&_data_word(0xbd42e8b0, 0x888b8907, 0x385b19e7, 0xdbeec879);
++	&_data_word(0x470a7ca1, 0xe90f427c, 0xc91e84f8, 0x00000000);
++	&_data_word(0x83868009, 0x48ed2b32, 0xac70111e, 0x4e725a6c);
++	&_data_word(0xfbff0efd, 0x5638850f, 0x1ed5ae3d, 0x27392d36);
++	&_data_word(0x64d90f0a, 0x21a65c68, 0xd1545b9b, 0x3a2e3624);
++	&_data_word(0xb1670a0c, 0x0fe75793, 0xd296eeb4, 0x9e919b1b);
++	&_data_word(0x4fc5c080, 0xa220dc61, 0x694b775a, 0x161a121c);
++	&_data_word(0x0aba93e2, 0xe52aa0c0, 0x43e0223c, 0x1d171b12);
++	&_data_word(0x0b0d090e, 0xadc78bf2, 0xb9a8b62d, 0xc8a91e14);
++	&_data_word(0x8519f157, 0x4c0775af, 0xbbdd99ee, 0xfd607fa3);
++	&_data_word(0x9f2601f7, 0xbcf5725c, 0xc53b6644, 0x347efb5b);
++	&_data_word(0x7629438b, 0xdcc623cb, 0x68fcedb6, 0x63f1e4b8);
++	&_data_word(0xcadc31d7, 0x10856342, 0x40229713, 0x2011c684);
++	&_data_word(0x7d244a85, 0xf83dbbd2, 0x1132f9ae, 0x6da129c7);
++	&_data_word(0x4b2f9e1d, 0xf330b2dc, 0xec52860d, 0xd0e3c177);
++	&_data_word(0x6c16b32b, 0x99b970a9, 0xfa489411, 0x2264e947);
++	&_data_word(0xc48cfca8, 0x1a3ff0a0, 0xd82c7d56, 0xef903322);
++	&_data_word(0xc74e4987, 0xc1d138d9, 0xfea2ca8c, 0x360bd498);
++	&_data_word(0xcf81f5a6, 0x28de7aa5, 0x268eb7da, 0xa4bfad3f);
++	&_data_word(0xe49d3a2c, 0x0d927850, 0x9bcc5f6a, 0x62467e54);
++	&_data_word(0xc2138df6, 0xe8b8d890, 0x5ef7392e, 0xf5afc382);
++	&_data_word(0xbe805d9f, 0x7c93d069, 0xa92dd56f, 0xb31225cf);
++	&_data_word(0x3b99acc8, 0xa77d1810, 0x6e639ce8, 0x7bbb3bdb);
++	&_data_word(0x097826cd, 0xf418596e, 0x01b79aec, 0xa89a4f83);
++	&_data_word(0x656e95e6, 0x7ee6ffaa, 0x08cfbc21, 0xe6e815ef);
++	&_data_word(0xd99be7ba, 0xce366f4a, 0xd4099fea, 0xd67cb029);
++	&_data_word(0xafb2a431, 0x31233f2a, 0x3094a5c6, 0xc066a235);
++	&_data_word(0x37bc4e74, 0xa6ca82fc, 0xb0d090e0, 0x15d8a733);
++	&_data_word(0x4a9804f1, 0xf7daec41, 0x0e50cd7f, 0x2ff69117);
++	&_data_word(0x8dd64d76, 0x4db0ef43, 0x544daacc, 0xdf0496e4);
++	&_data_word(0xe3b5d19e, 0x1b886a4c, 0xb81f2cc1, 0x7f516546);
++	&_data_word(0x04ea5e9d, 0x5d358c01, 0x737487fa, 0x2e410bfb);
++	&_data_word(0x5a1d67b3, 0x52d2db92, 0x335610e9, 0x1347d66d);
++	&_data_word(0x8c61d79a, 0x7a0ca137, 0x8e14f859, 0x893c13eb);
++	&_data_word(0xee27a9ce, 0x35c961b7, 0xede51ce1, 0x3cb1477a);
++	&_data_word(0x59dfd29c, 0x3f73f255, 0x79ce1418, 0xbf37c773);
++	&_data_word(0xeacdf753, 0x5baafd5f, 0x146f3ddf, 0x86db4478);
++	&_data_word(0x81f3afca, 0x3ec468b9, 0x2c342438, 0x5f40a3c2);
++	&_data_word(0x72c31d16, 0x0c25e2bc, 0x8b493c28, 0x41950dff);
++	&_data_word(0x7101a839, 0xdeb30c08, 0x9ce4b4d8, 0x90c15664);
++	&_data_word(0x6184cb7b, 0x70b632d5, 0x745c6c48, 0x4257b8d0);
++
++#Td4:	# four copies of Td4 to choose from to avoid L1 aliasing
++	&data_byte(0x52, 0x09, 0x6a, 0xd5, 0x30, 0x36, 0xa5, 0x38);
++	&data_byte(0xbf, 0x40, 0xa3, 0x9e, 0x81, 0xf3, 0xd7, 0xfb);
++	&data_byte(0x7c, 0xe3, 0x39, 0x82, 0x9b, 0x2f, 0xff, 0x87);
++	&data_byte(0x34, 0x8e, 0x43, 0x44, 0xc4, 0xde, 0xe9, 0xcb);
++	&data_byte(0x54, 0x7b, 0x94, 0x32, 0xa6, 0xc2, 0x23, 0x3d);
++	&data_byte(0xee, 0x4c, 0x95, 0x0b, 0x42, 0xfa, 0xc3, 0x4e);
++	&data_byte(0x08, 0x2e, 0xa1, 0x66, 0x28, 0xd9, 0x24, 0xb2);
++	&data_byte(0x76, 0x5b, 0xa2, 0x49, 0x6d, 0x8b, 0xd1, 0x25);
++	&data_byte(0x72, 0xf8, 0xf6, 0x64, 0x86, 0x68, 0x98, 0x16);
++	&data_byte(0xd4, 0xa4, 0x5c, 0xcc, 0x5d, 0x65, 0xb6, 0x92);
++	&data_byte(0x6c, 0x70, 0x48, 0x50, 0xfd, 0xed, 0xb9, 0xda);
++	&data_byte(0x5e, 0x15, 0x46, 0x57, 0xa7, 0x8d, 0x9d, 0x84);
++	&data_byte(0x90, 0xd8, 0xab, 0x00, 0x8c, 0xbc, 0xd3, 0x0a);
++	&data_byte(0xf7, 0xe4, 0x58, 0x05, 0xb8, 0xb3, 0x45, 0x06);
++	&data_byte(0xd0, 0x2c, 0x1e, 0x8f, 0xca, 0x3f, 0x0f, 0x02);
++	&data_byte(0xc1, 0xaf, 0xbd, 0x03, 0x01, 0x13, 0x8a, 0x6b);
++	&data_byte(0x3a, 0x91, 0x11, 0x41, 0x4f, 0x67, 0xdc, 0xea);
++	&data_byte(0x97, 0xf2, 0xcf, 0xce, 0xf0, 0xb4, 0xe6, 0x73);
++	&data_byte(0x96, 0xac, 0x74, 0x22, 0xe7, 0xad, 0x35, 0x85);
++	&data_byte(0xe2, 0xf9, 0x37, 0xe8, 0x1c, 0x75, 0xdf, 0x6e);
++	&data_byte(0x47, 0xf1, 0x1a, 0x71, 0x1d, 0x29, 0xc5, 0x89);
++	&data_byte(0x6f, 0xb7, 0x62, 0x0e, 0xaa, 0x18, 0xbe, 0x1b);
++	&data_byte(0xfc, 0x56, 0x3e, 0x4b, 0xc6, 0xd2, 0x79, 0x20);
++	&data_byte(0x9a, 0xdb, 0xc0, 0xfe, 0x78, 0xcd, 0x5a, 0xf4);
++	&data_byte(0x1f, 0xdd, 0xa8, 0x33, 0x88, 0x07, 0xc7, 0x31);
++	&data_byte(0xb1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xec, 0x5f);
++	&data_byte(0x60, 0x51, 0x7f, 0xa9, 0x19, 0xb5, 0x4a, 0x0d);
++	&data_byte(0x2d, 0xe5, 0x7a, 0x9f, 0x93, 0xc9, 0x9c, 0xef);
++	&data_byte(0xa0, 0xe0, 0x3b, 0x4d, 0xae, 0x2a, 0xf5, 0xb0);
++	&data_byte(0xc8, 0xeb, 0xbb, 0x3c, 0x83, 0x53, 0x99, 0x61);
++	&data_byte(0x17, 0x2b, 0x04, 0x7e, 0xba, 0x77, 0xd6, 0x26);
++	&data_byte(0xe1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0c, 0x7d);
++
++	&data_byte(0x52, 0x09, 0x6a, 0xd5, 0x30, 0x36, 0xa5, 0x38);
++	&data_byte(0xbf, 0x40, 0xa3, 0x9e, 0x81, 0xf3, 0xd7, 0xfb);
++	&data_byte(0x7c, 0xe3, 0x39, 0x82, 0x9b, 0x2f, 0xff, 0x87);
++	&data_byte(0x34, 0x8e, 0x43, 0x44, 0xc4, 0xde, 0xe9, 0xcb);
++	&data_byte(0x54, 0x7b, 0x94, 0x32, 0xa6, 0xc2, 0x23, 0x3d);
++	&data_byte(0xee, 0x4c, 0x95, 0x0b, 0x42, 0xfa, 0xc3, 0x4e);
++	&data_byte(0x08, 0x2e, 0xa1, 0x66, 0x28, 0xd9, 0x24, 0xb2);
++	&data_byte(0x76, 0x5b, 0xa2, 0x49, 0x6d, 0x8b, 0xd1, 0x25);
++	&data_byte(0x72, 0xf8, 0xf6, 0x64, 0x86, 0x68, 0x98, 0x16);
++	&data_byte(0xd4, 0xa4, 0x5c, 0xcc, 0x5d, 0x65, 0xb6, 0x92);
++	&data_byte(0x6c, 0x70, 0x48, 0x50, 0xfd, 0xed, 0xb9, 0xda);
++	&data_byte(0x5e, 0x15, 0x46, 0x57, 0xa7, 0x8d, 0x9d, 0x84);
++	&data_byte(0x90, 0xd8, 0xab, 0x00, 0x8c, 0xbc, 0xd3, 0x0a);
++	&data_byte(0xf7, 0xe4, 0x58, 0x05, 0xb8, 0xb3, 0x45, 0x06);
++	&data_byte(0xd0, 0x2c, 0x1e, 0x8f, 0xca, 0x3f, 0x0f, 0x02);
++	&data_byte(0xc1, 0xaf, 0xbd, 0x03, 0x01, 0x13, 0x8a, 0x6b);
++	&data_byte(0x3a, 0x91, 0x11, 0x41, 0x4f, 0x67, 0xdc, 0xea);
++	&data_byte(0x97, 0xf2, 0xcf, 0xce, 0xf0, 0xb4, 0xe6, 0x73);
++	&data_byte(0x96, 0xac, 0x74, 0x22, 0xe7, 0xad, 0x35, 0x85);
++	&data_byte(0xe2, 0xf9, 0x37, 0xe8, 0x1c, 0x75, 0xdf, 0x6e);
++	&data_byte(0x47, 0xf1, 0x1a, 0x71, 0x1d, 0x29, 0xc5, 0x89);
++	&data_byte(0x6f, 0xb7, 0x62, 0x0e, 0xaa, 0x18, 0xbe, 0x1b);
++	&data_byte(0xfc, 0x56, 0x3e, 0x4b, 0xc6, 0xd2, 0x79, 0x20);
++	&data_byte(0x9a, 0xdb, 0xc0, 0xfe, 0x78, 0xcd, 0x5a, 0xf4);
++	&data_byte(0x1f, 0xdd, 0xa8, 0x33, 0x88, 0x07, 0xc7, 0x31);
++	&data_byte(0xb1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xec, 0x5f);
++	&data_byte(0x60, 0x51, 0x7f, 0xa9, 0x19, 0xb5, 0x4a, 0x0d);
++	&data_byte(0x2d, 0xe5, 0x7a, 0x9f, 0x93, 0xc9, 0x9c, 0xef);
++	&data_byte(0xa0, 0xe0, 0x3b, 0x4d, 0xae, 0x2a, 0xf5, 0xb0);
++	&data_byte(0xc8, 0xeb, 0xbb, 0x3c, 0x83, 0x53, 0x99, 0x61);
++	&data_byte(0x17, 0x2b, 0x04, 0x7e, 0xba, 0x77, 0xd6, 0x26);
++	&data_byte(0xe1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0c, 0x7d);
++
++	&data_byte(0x52, 0x09, 0x6a, 0xd5, 0x30, 0x36, 0xa5, 0x38);
++	&data_byte(0xbf, 0x40, 0xa3, 0x9e, 0x81, 0xf3, 0xd7, 0xfb);
++	&data_byte(0x7c, 0xe3, 0x39, 0x82, 0x9b, 0x2f, 0xff, 0x87);
++	&data_byte(0x34, 0x8e, 0x43, 0x44, 0xc4, 0xde, 0xe9, 0xcb);
++	&data_byte(0x54, 0x7b, 0x94, 0x32, 0xa6, 0xc2, 0x23, 0x3d);
++	&data_byte(0xee, 0x4c, 0x95, 0x0b, 0x42, 0xfa, 0xc3, 0x4e);
++	&data_byte(0x08, 0x2e, 0xa1, 0x66, 0x28, 0xd9, 0x24, 0xb2);
++	&data_byte(0x76, 0x5b, 0xa2, 0x49, 0x6d, 0x8b, 0xd1, 0x25);
++	&data_byte(0x72, 0xf8, 0xf6, 0x64, 0x86, 0x68, 0x98, 0x16);
++	&data_byte(0xd4, 0xa4, 0x5c, 0xcc, 0x5d, 0x65, 0xb6, 0x92);
++	&data_byte(0x6c, 0x70, 0x48, 0x50, 0xfd, 0xed, 0xb9, 0xda);
++	&data_byte(0x5e, 0x15, 0x46, 0x57, 0xa7, 0x8d, 0x9d, 0x84);
++	&data_byte(0x90, 0xd8, 0xab, 0x00, 0x8c, 0xbc, 0xd3, 0x0a);
++	&data_byte(0xf7, 0xe4, 0x58, 0x05, 0xb8, 0xb3, 0x45, 0x06);
++	&data_byte(0xd0, 0x2c, 0x1e, 0x8f, 0xca, 0x3f, 0x0f, 0x02);
++	&data_byte(0xc1, 0xaf, 0xbd, 0x03, 0x01, 0x13, 0x8a, 0x6b);
++	&data_byte(0x3a, 0x91, 0x11, 0x41, 0x4f, 0x67, 0xdc, 0xea);
++	&data_byte(0x97, 0xf2, 0xcf, 0xce, 0xf0, 0xb4, 0xe6, 0x73);
++	&data_byte(0x96, 0xac, 0x74, 0x22, 0xe7, 0xad, 0x35, 0x85);
++	&data_byte(0xe2, 0xf9, 0x37, 0xe8, 0x1c, 0x75, 0xdf, 0x6e);
++	&data_byte(0x47, 0xf1, 0x1a, 0x71, 0x1d, 0x29, 0xc5, 0x89);
++	&data_byte(0x6f, 0xb7, 0x62, 0x0e, 0xaa, 0x18, 0xbe, 0x1b);
++	&data_byte(0xfc, 0x56, 0x3e, 0x4b, 0xc6, 0xd2, 0x79, 0x20);
++	&data_byte(0x9a, 0xdb, 0xc0, 0xfe, 0x78, 0xcd, 0x5a, 0xf4);
++	&data_byte(0x1f, 0xdd, 0xa8, 0x33, 0x88, 0x07, 0xc7, 0x31);
++	&data_byte(0xb1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xec, 0x5f);
++	&data_byte(0x60, 0x51, 0x7f, 0xa9, 0x19, 0xb5, 0x4a, 0x0d);
++	&data_byte(0x2d, 0xe5, 0x7a, 0x9f, 0x93, 0xc9, 0x9c, 0xef);
++	&data_byte(0xa0, 0xe0, 0x3b, 0x4d, 0xae, 0x2a, 0xf5, 0xb0);
++	&data_byte(0xc8, 0xeb, 0xbb, 0x3c, 0x83, 0x53, 0x99, 0x61);
++	&data_byte(0x17, 0x2b, 0x04, 0x7e, 0xba, 0x77, 0xd6, 0x26);
++	&data_byte(0xe1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0c, 0x7d);
++
++	&data_byte(0x52, 0x09, 0x6a, 0xd5, 0x30, 0x36, 0xa5, 0x38);
++	&data_byte(0xbf, 0x40, 0xa3, 0x9e, 0x81, 0xf3, 0xd7, 0xfb);
++	&data_byte(0x7c, 0xe3, 0x39, 0x82, 0x9b, 0x2f, 0xff, 0x87);
++	&data_byte(0x34, 0x8e, 0x43, 0x44, 0xc4, 0xde, 0xe9, 0xcb);
++	&data_byte(0x54, 0x7b, 0x94, 0x32, 0xa6, 0xc2, 0x23, 0x3d);
++	&data_byte(0xee, 0x4c, 0x95, 0x0b, 0x42, 0xfa, 0xc3, 0x4e);
++	&data_byte(0x08, 0x2e, 0xa1, 0x66, 0x28, 0xd9, 0x24, 0xb2);
++	&data_byte(0x76, 0x5b, 0xa2, 0x49, 0x6d, 0x8b, 0xd1, 0x25);
++	&data_byte(0x72, 0xf8, 0xf6, 0x64, 0x86, 0x68, 0x98, 0x16);
++	&data_byte(0xd4, 0xa4, 0x5c, 0xcc, 0x5d, 0x65, 0xb6, 0x92);
++	&data_byte(0x6c, 0x70, 0x48, 0x50, 0xfd, 0xed, 0xb9, 0xda);
++	&data_byte(0x5e, 0x15, 0x46, 0x57, 0xa7, 0x8d, 0x9d, 0x84);
++	&data_byte(0x90, 0xd8, 0xab, 0x00, 0x8c, 0xbc, 0xd3, 0x0a);
++	&data_byte(0xf7, 0xe4, 0x58, 0x05, 0xb8, 0xb3, 0x45, 0x06);
++	&data_byte(0xd0, 0x2c, 0x1e, 0x8f, 0xca, 0x3f, 0x0f, 0x02);
++	&data_byte(0xc1, 0xaf, 0xbd, 0x03, 0x01, 0x13, 0x8a, 0x6b);
++	&data_byte(0x3a, 0x91, 0x11, 0x41, 0x4f, 0x67, 0xdc, 0xea);
++	&data_byte(0x97, 0xf2, 0xcf, 0xce, 0xf0, 0xb4, 0xe6, 0x73);
++	&data_byte(0x96, 0xac, 0x74, 0x22, 0xe7, 0xad, 0x35, 0x85);
++	&data_byte(0xe2, 0xf9, 0x37, 0xe8, 0x1c, 0x75, 0xdf, 0x6e);
++	&data_byte(0x47, 0xf1, 0x1a, 0x71, 0x1d, 0x29, 0xc5, 0x89);
++	&data_byte(0x6f, 0xb7, 0x62, 0x0e, 0xaa, 0x18, 0xbe, 0x1b);
++	&data_byte(0xfc, 0x56, 0x3e, 0x4b, 0xc6, 0xd2, 0x79, 0x20);
++	&data_byte(0x9a, 0xdb, 0xc0, 0xfe, 0x78, 0xcd, 0x5a, 0xf4);
++	&data_byte(0x1f, 0xdd, 0xa8, 0x33, 0x88, 0x07, 0xc7, 0x31);
++	&data_byte(0xb1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xec, 0x5f);
++	&data_byte(0x60, 0x51, 0x7f, 0xa9, 0x19, 0xb5, 0x4a, 0x0d);
++	&data_byte(0x2d, 0xe5, 0x7a, 0x9f, 0x93, 0xc9, 0x9c, 0xef);
++	&data_byte(0xa0, 0xe0, 0x3b, 0x4d, 0xae, 0x2a, 0xf5, 0xb0);
++	&data_byte(0xc8, 0xeb, 0xbb, 0x3c, 0x83, 0x53, 0x99, 0x61);
++	&data_byte(0x17, 0x2b, 0x04, 0x7e, 0xba, 0x77, 0xd6, 0x26);
++	&data_byte(0xe1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0c, 0x7d);
++&function_end_B("_x86_AES_decrypt");
++
++# void AES_decrypt (const void *inp,void *out,const AES_KEY *key);
++&function_begin("AES_decrypt");
++	&mov	($acc,&wparam(0));		# load inp
++	&mov	($key,&wparam(2));		# load key
++
++	&mov	($s0,"esp");
++	&sub	("esp",36);
++	&and	("esp",-64);			# align to cache-line
++
++	# place stack frame just "above" the key schedule
++	&lea	($s1,&DWP(-64-63,$key));
++	&sub	($s1,"esp");
++	&neg	($s1);
++	&and	($s1,0x3C0);	# modulo 1024, but aligned to cache-line
++	&sub	("esp",$s1);
++	&add	("esp",4);	# 4 is reserved for caller's return address
++	&mov	($_esp,$s0);	# save stack pointer
++
++	&call   (&label("pic_point"));          # make it PIC!
++	&set_label("pic_point");
++	&blindpop($tbl);
++	&picmeup($s0,"OPENSSL_ia32cap_P",$tbl,&label("pic_point")) if(!$x86only);
++	&lea    ($tbl,&DWP(&label("AES_Td")."-".&label("pic_point"),$tbl));
++
++	# pick Td4 copy which can't "overlap" with stack frame or key schedule
++	&lea	($s1,&DWP(768-4,"esp"));
++	&sub	($s1,$tbl);
++	&and	($s1,0x300);
++	&lea	($tbl,&DWP(2048+128,$tbl,$s1));
++
++					if (!$x86only) {
++	&bt	(&DWP(0,$s0),25);	# check for SSE bit
++	&jnc	(&label("x86"));
++
++	&movq	("mm0",&QWP(0,$acc));
++	&movq	("mm4",&QWP(8,$acc));
++	&call	("_sse_AES_decrypt_compact");
++	&mov	("esp",$_esp);			# restore stack pointer
++	&mov	($acc,&wparam(1));		# load out
++	&movq	(&QWP(0,$acc),"mm0");		# write output data
++	&movq	(&QWP(8,$acc),"mm4");
++	&emms	();
++	&function_end_A();
++					}
++	&set_label("x86",16);
++	&mov	($_tbl,$tbl);
++	&mov	($s0,&DWP(0,$acc));		# load input data
++	&mov	($s1,&DWP(4,$acc));
++	&mov	($s2,&DWP(8,$acc));
++	&mov	($s3,&DWP(12,$acc));
++	&call	("_x86_AES_decrypt_compact");
++	&mov	("esp",$_esp);			# restore stack pointer
++	&mov	($acc,&wparam(1));		# load out
++	&mov	(&DWP(0,$acc),$s0);		# write output data
++	&mov	(&DWP(4,$acc),$s1);
++	&mov	(&DWP(8,$acc),$s2);
++	&mov	(&DWP(12,$acc),$s3);
++&function_end("AES_decrypt");
++
++# void AES_cbc_encrypt (const void char *inp, unsigned char *out,
++#			size_t length, const AES_KEY *key,
++#			unsigned char *ivp,const int enc);
++{
++# stack frame layout
++#             -4(%esp)		# return address	 0(%esp)
++#              0(%esp)		# s0 backing store	 4(%esp)	
++#              4(%esp)		# s1 backing store	 8(%esp)
++#              8(%esp)		# s2 backing store	12(%esp)
++#             12(%esp)		# s3 backing store	16(%esp)
++#             16(%esp)		# key backup		20(%esp)
++#             20(%esp)		# end of key schedule	24(%esp)
++#             24(%esp)		# %ebp backup		28(%esp)
++#             28(%esp)		# %esp backup
++my $_inp=&DWP(32,"esp");	# copy of wparam(0)
++my $_out=&DWP(36,"esp");	# copy of wparam(1)
++my $_len=&DWP(40,"esp");	# copy of wparam(2)
++my $_key=&DWP(44,"esp");	# copy of wparam(3)
++my $_ivp=&DWP(48,"esp");	# copy of wparam(4)
++my $_tmp=&DWP(52,"esp");	# volatile variable
++#
++my $ivec=&DWP(60,"esp");	# ivec[16]
++my $aes_key=&DWP(76,"esp");	# copy of aes_key
++my $mark=&DWP(76+240,"esp");	# copy of aes_key->rounds
++
++&function_begin("AES_cbc_encrypt");
++	&mov	($s2 eq "ecx"? $s2 : "",&wparam(2));	# load len
++	&cmp	($s2,0);
++	&je	(&label("drop_out"));
++
++	&call   (&label("pic_point"));		# make it PIC!
++	&set_label("pic_point");
++	&blindpop($tbl);
++	&picmeup($s0,"OPENSSL_ia32cap_P",$tbl,&label("pic_point")) if(!$x86only);
++
++	&cmp	(&wparam(5),0);
++	&lea    ($tbl,&DWP(&label("AES_Te")."-".&label("pic_point"),$tbl));
++	&jne	(&label("picked_te"));
++	&lea	($tbl,&DWP(&label("AES_Td")."-".&label("AES_Te"),$tbl));
++	&set_label("picked_te");
++
++	# one can argue if this is required
++	&pushf	();
++	&cld	();
++
++	&cmp	($s2,$speed_limit);
++	&jb	(&label("slow_way"));
++	&test	($s2,15);
++	&jnz	(&label("slow_way"));
++					if (!$x86only) {
++	&bt	(&DWP(0,$s0),28);	# check for hyper-threading bit
++	&jc	(&label("slow_way"));
++					}
++	# pre-allocate aligned stack frame...
++	&lea	($acc,&DWP(-80-244,"esp"));
++	&and	($acc,-64);
++
++	# ... and make sure it doesn't alias with $tbl modulo 4096
++	&mov	($s0,$tbl);
++	&lea	($s1,&DWP(2048+256,$tbl));
++	&mov	($s3,$acc);
++	&and	($s0,0xfff);		# s = %ebp&0xfff
++	&and	($s1,0xfff);		# e = (%ebp+2048+256)&0xfff
++	&and	($s3,0xfff);		# p = %esp&0xfff
++
++	&cmp	($s3,$s1);		# if (p>=e) %esp =- (p-e);
++	&jb	(&label("tbl_break_out"));
++	&sub	($s3,$s1);
++	&sub	($acc,$s3);
++	&jmp	(&label("tbl_ok"));
++	&set_label("tbl_break_out",4);	# else %esp -= (p-s)&0xfff + framesz;
++	&sub	($s3,$s0);
++	&and	($s3,0xfff);
++	&add	($s3,384);
++	&sub	($acc,$s3);
++	&set_label("tbl_ok",4);
++
++	&lea	($s3,&wparam(0));	# obtain pointer to parameter block
++	&exch	("esp",$acc);		# allocate stack frame
++	&add	("esp",4);		# reserve for return address!
++	&mov	($_tbl,$tbl);		# save %ebp
++	&mov	($_esp,$acc);		# save %esp
++
++	&mov	($s0,&DWP(0,$s3));	# load inp
++	&mov	($s1,&DWP(4,$s3));	# load out
++	#&mov	($s2,&DWP(8,$s3));	# load len
++	&mov	($key,&DWP(12,$s3));	# load key
++	&mov	($acc,&DWP(16,$s3));	# load ivp
++	&mov	($s3,&DWP(20,$s3));	# load enc flag
++
++	&mov	($_inp,$s0);		# save copy of inp
++	&mov	($_out,$s1);		# save copy of out
++	&mov	($_len,$s2);		# save copy of len
++	&mov	($_key,$key);		# save copy of key
++	&mov	($_ivp,$acc);		# save copy of ivp
++
++	&mov	($mark,0);		# copy of aes_key->rounds = 0;
++	# do we copy key schedule to stack?
++	&mov	($s1 eq "ebx" ? $s1 : "",$key);
++	&mov	($s2 eq "ecx" ? $s2 : "",244/4);
++	&sub	($s1,$tbl);
++	&mov	("esi",$key);
++	&and	($s1,0xfff);
++	&lea	("edi",$aes_key);
++	&cmp	($s1,2048+256);
++	&jb	(&label("do_copy"));
++	&cmp	($s1,4096-244);
++	&jb	(&label("skip_copy"));
++	&set_label("do_copy",4);
++		&mov	($_key,"edi");
++		&data_word(0xA5F3F689);	# rep movsd
++	&set_label("skip_copy");
++
++	&mov	($key,16);
++	&set_label("prefetch_tbl",4);
++		&mov	($s0,&DWP(0,$tbl));
++		&mov	($s1,&DWP(32,$tbl));
++		&mov	($s2,&DWP(64,$tbl));
++		&mov	($acc,&DWP(96,$tbl));
++		&lea	($tbl,&DWP(128,$tbl));
++		&sub	($key,1);
++	&jnz	(&label("prefetch_tbl"));
++	&sub	($tbl,2048);
++
++	&mov	($acc,$_inp);
++	&mov	($key,$_ivp);
++
++	&cmp	($s3,0);
++	&je	(&label("fast_decrypt"));
++
++#----------------------------- ENCRYPT -----------------------------#
++	&mov	($s0,&DWP(0,$key));		# load iv
++	&mov	($s1,&DWP(4,$key));
++
++	&set_label("fast_enc_loop",16);
++		&mov	($s2,&DWP(8,$key));
++		&mov	($s3,&DWP(12,$key));
++
++		&xor	($s0,&DWP(0,$acc));	# xor input data
++		&xor	($s1,&DWP(4,$acc));
++		&xor	($s2,&DWP(8,$acc));
++		&xor	($s3,&DWP(12,$acc));
++
++		&mov	($key,$_key);		# load key
++		&call	("_x86_AES_encrypt");
++
++		&mov	($acc,$_inp);		# load inp
++		&mov	($key,$_out);		# load out
++
++		&mov	(&DWP(0,$key),$s0);	# save output data
++		&mov	(&DWP(4,$key),$s1);
++		&mov	(&DWP(8,$key),$s2);
++		&mov	(&DWP(12,$key),$s3);
++
++		&lea	($acc,&DWP(16,$acc));	# advance inp
++		&mov	($s2,$_len);		# load len
++		&mov	($_inp,$acc);		# save inp
++		&lea	($s3,&DWP(16,$key));	# advance out
++		&mov	($_out,$s3);		# save out
++		&sub	($s2,16);		# decrease len
++		&mov	($_len,$s2);		# save len
++	&jnz	(&label("fast_enc_loop"));
++	&mov	($acc,$_ivp);		# load ivp
++	&mov	($s2,&DWP(8,$key));	# restore last 2 dwords
++	&mov	($s3,&DWP(12,$key));
++	&mov	(&DWP(0,$acc),$s0);	# save ivec
++	&mov	(&DWP(4,$acc),$s1);
++	&mov	(&DWP(8,$acc),$s2);
++	&mov	(&DWP(12,$acc),$s3);
++
++	&cmp	($mark,0);		# was the key schedule copied?
++	&mov	("edi",$_key);
++	&je	(&label("skip_ezero"));
++	# zero copy of key schedule
++	&mov	("ecx",240/4);
++	&xor	("eax","eax");
++	&align	(4);
++	&data_word(0xABF3F689);		# rep stosd
++	&set_label("skip_ezero");
++	&mov	("esp",$_esp);
++	&popf	();
++    &set_label("drop_out");
++	&function_end_A();
++	&pushf	();			# kludge, never executed
++
++#----------------------------- DECRYPT -----------------------------#
++&set_label("fast_decrypt",16);
++
++	&cmp	($acc,$_out);
++	&je	(&label("fast_dec_in_place"));	# in-place processing...
++
++	&mov	($_tmp,$key);
++
++	&align	(4);
++	&set_label("fast_dec_loop",16);
++		&mov	($s0,&DWP(0,$acc));	# read input
++		&mov	($s1,&DWP(4,$acc));
++		&mov	($s2,&DWP(8,$acc));
++		&mov	($s3,&DWP(12,$acc));
++
++		&mov	($key,$_key);		# load key
++		&call	("_x86_AES_decrypt");
++
++		&mov	($key,$_tmp);		# load ivp
++		&mov	($acc,$_len);		# load len
++		&xor	($s0,&DWP(0,$key));	# xor iv
++		&xor	($s1,&DWP(4,$key));
++		&xor	($s2,&DWP(8,$key));
++		&xor	($s3,&DWP(12,$key));
++
++		&mov	($key,$_out);		# load out
++		&mov	($acc,$_inp);		# load inp
++
++		&mov	(&DWP(0,$key),$s0);	# write output
++		&mov	(&DWP(4,$key),$s1);
++		&mov	(&DWP(8,$key),$s2);
++		&mov	(&DWP(12,$key),$s3);
++
++		&mov	($s2,$_len);		# load len
++		&mov	($_tmp,$acc);		# save ivp
++		&lea	($acc,&DWP(16,$acc));	# advance inp
++		&mov	($_inp,$acc);		# save inp
++		&lea	($key,&DWP(16,$key));	# advance out
++		&mov	($_out,$key);		# save out
++		&sub	($s2,16);		# decrease len
++		&mov	($_len,$s2);		# save len
++	&jnz	(&label("fast_dec_loop"));
++	&mov	($key,$_tmp);		# load temp ivp
++	&mov	($acc,$_ivp);		# load user ivp
++	&mov	($s0,&DWP(0,$key));	# load iv
++	&mov	($s1,&DWP(4,$key));
++	&mov	($s2,&DWP(8,$key));
++	&mov	($s3,&DWP(12,$key));
++	&mov	(&DWP(0,$acc),$s0);	# copy back to user
++	&mov	(&DWP(4,$acc),$s1);
++	&mov	(&DWP(8,$acc),$s2);
++	&mov	(&DWP(12,$acc),$s3);
++	&jmp	(&label("fast_dec_out"));
++
++    &set_label("fast_dec_in_place",16);
++	&set_label("fast_dec_in_place_loop");
++		&mov	($s0,&DWP(0,$acc));	# read input
++		&mov	($s1,&DWP(4,$acc));
++		&mov	($s2,&DWP(8,$acc));
++		&mov	($s3,&DWP(12,$acc));
++
++		&lea	($key,$ivec);
++		&mov	(&DWP(0,$key),$s0);	# copy to temp
++		&mov	(&DWP(4,$key),$s1);
++		&mov	(&DWP(8,$key),$s2);
++		&mov	(&DWP(12,$key),$s3);
++
++		&mov	($key,$_key);		# load key
++		&call	("_x86_AES_decrypt");
++
++		&mov	($key,$_ivp);		# load ivp
++		&mov	($acc,$_out);		# load out
++		&xor	($s0,&DWP(0,$key));	# xor iv
++		&xor	($s1,&DWP(4,$key));
++		&xor	($s2,&DWP(8,$key));
++		&xor	($s3,&DWP(12,$key));
++
++		&mov	(&DWP(0,$acc),$s0);	# write output
++		&mov	(&DWP(4,$acc),$s1);
++		&mov	(&DWP(8,$acc),$s2);
++		&mov	(&DWP(12,$acc),$s3);
++
++		&lea	($acc,&DWP(16,$acc));	# advance out
++		&mov	($_out,$acc);		# save out
++
++		&lea	($acc,$ivec);
++		&mov	($s0,&DWP(0,$acc));	# read temp
++		&mov	($s1,&DWP(4,$acc));
++		&mov	($s2,&DWP(8,$acc));
++		&mov	($s3,&DWP(12,$acc));
++
++		&mov	(&DWP(0,$key),$s0);	# copy iv
++		&mov	(&DWP(4,$key),$s1);
++		&mov	(&DWP(8,$key),$s2);
++		&mov	(&DWP(12,$key),$s3);
++
++		&mov	($acc,$_inp);		# load inp
++		&mov	($s2,$_len);		# load len
++		&lea	($acc,&DWP(16,$acc));	# advance inp
++		&mov	($_inp,$acc);		# save inp
++		&sub	($s2,16);		# decrease len
++		&mov	($_len,$s2);		# save len
++	&jnz	(&label("fast_dec_in_place_loop"));
++
++    &set_label("fast_dec_out",4);
++	&cmp	($mark,0);		# was the key schedule copied?
++	&mov	("edi",$_key);
++	&je	(&label("skip_dzero"));
++	# zero copy of key schedule
++	&mov	("ecx",240/4);
++	&xor	("eax","eax");
++	&align	(4);
++	&data_word(0xABF3F689);		# rep stosd
++	&set_label("skip_dzero");
++	&mov	("esp",$_esp);
++	&popf	();
++	&function_end_A();
++	&pushf	();			# kludge, never executed
++
++#--------------------------- SLOW ROUTINE ---------------------------#
++&set_label("slow_way",16);
++
++	&mov	($s0,&DWP(0,$s0)) if (!$x86only);# load OPENSSL_ia32cap
++	&mov	($key,&wparam(3));	# load key
++
++	# pre-allocate aligned stack frame...
++	&lea	($acc,&DWP(-80,"esp"));
++	&and	($acc,-64);
++
++	# ... and make sure it doesn't alias with $key modulo 1024
++	&lea	($s1,&DWP(-80-63,$key));
++	&sub	($s1,$acc);
++	&neg	($s1);
++	&and	($s1,0x3C0);	# modulo 1024, but aligned to cache-line
++	&sub	($acc,$s1);
++
++	# pick S-box copy which can't overlap with stack frame or $key
++	&lea	($s1,&DWP(768,$acc));
++	&sub	($s1,$tbl);
++	&and	($s1,0x300);
++	&lea	($tbl,&DWP(2048+128,$tbl,$s1));
++
++	&lea	($s3,&wparam(0));	# pointer to parameter block
++
++	&exch	("esp",$acc);
++	&add	("esp",4);		# reserve for return address!
++	&mov	($_tbl,$tbl);		# save %ebp
++	&mov	($_esp,$acc);		# save %esp
++	&mov	($_tmp,$s0);		# save OPENSSL_ia32cap
++
++	&mov	($s0,&DWP(0,$s3));	# load inp
++	&mov	($s1,&DWP(4,$s3));	# load out
++	#&mov	($s2,&DWP(8,$s3));	# load len
++	#&mov	($key,&DWP(12,$s3));	# load key
++	&mov	($acc,&DWP(16,$s3));	# load ivp
++	&mov	($s3,&DWP(20,$s3));	# load enc flag
++
++	&mov	($_inp,$s0);		# save copy of inp
++	&mov	($_out,$s1);		# save copy of out
++	&mov	($_len,$s2);		# save copy of len
++	&mov	($_key,$key);		# save copy of key
++	&mov	($_ivp,$acc);		# save copy of ivp
++
++	&mov	($key,$acc);
++	&mov	($acc,$s0);
++
++	&cmp	($s3,0);
++	&je	(&label("slow_decrypt"));
++
++#--------------------------- SLOW ENCRYPT ---------------------------#
++	&cmp	($s2,16);
++	&mov	($s3,$s1);
++	&jb	(&label("slow_enc_tail"));
++
++					if (!$x86only) {
++	&bt	($_tmp,25);		# check for SSE bit
++	&jnc	(&label("slow_enc_x86"));
++
++	&movq	("mm0",&QWP(0,$key));	# load iv
++	&movq	("mm4",&QWP(8,$key));
++
++	&set_label("slow_enc_loop_sse",16);
++		&pxor	("mm0",&QWP(0,$acc));	# xor input data
++		&pxor	("mm4",&QWP(8,$acc));
++
++		&mov	($key,$_key);
++		&call	("_sse_AES_encrypt_compact");
++
++		&mov	($acc,$_inp);		# load inp
++		&mov	($key,$_out);		# load out
++		&mov	($s2,$_len);		# load len
++
++		&movq	(&QWP(0,$key),"mm0");	# save output data
++		&movq	(&QWP(8,$key),"mm4");
++
++		&lea	($acc,&DWP(16,$acc));	# advance inp
++		&mov	($_inp,$acc);		# save inp
++		&lea	($s3,&DWP(16,$key));	# advance out
++		&mov	($_out,$s3);		# save out
++		&sub	($s2,16);		# decrease len
++		&cmp	($s2,16);
++		&mov	($_len,$s2);		# save len
++	&jae	(&label("slow_enc_loop_sse"));
++	&test	($s2,15);
++	&jnz	(&label("slow_enc_tail"));
++	&mov	($acc,$_ivp);		# load ivp
++	&movq	(&QWP(0,$acc),"mm0");	# save ivec
++	&movq	(&QWP(8,$acc),"mm4");
++	&emms	();
++	&mov	("esp",$_esp);
++	&popf	();
++	&function_end_A();
++	&pushf	();			# kludge, never executed
++					}
++    &set_label("slow_enc_x86",16);
++	&mov	($s0,&DWP(0,$key));	# load iv
++	&mov	($s1,&DWP(4,$key));
++
++	&set_label("slow_enc_loop_x86",4);
++		&mov	($s2,&DWP(8,$key));
++		&mov	($s3,&DWP(12,$key));
++
++		&xor	($s0,&DWP(0,$acc));	# xor input data
++		&xor	($s1,&DWP(4,$acc));
++		&xor	($s2,&DWP(8,$acc));
++		&xor	($s3,&DWP(12,$acc));
++
++		&mov	($key,$_key);		# load key
++		&call	("_x86_AES_encrypt_compact");
++
++		&mov	($acc,$_inp);		# load inp
++		&mov	($key,$_out);		# load out
++
++		&mov	(&DWP(0,$key),$s0);	# save output data
++		&mov	(&DWP(4,$key),$s1);
++		&mov	(&DWP(8,$key),$s2);
++		&mov	(&DWP(12,$key),$s3);
++
++		&mov	($s2,$_len);		# load len
++		&lea	($acc,&DWP(16,$acc));	# advance inp
++		&mov	($_inp,$acc);		# save inp
++		&lea	($s3,&DWP(16,$key));	# advance out
++		&mov	($_out,$s3);		# save out
++		&sub	($s2,16);		# decrease len
++		&cmp	($s2,16);
++		&mov	($_len,$s2);		# save len
++	&jae	(&label("slow_enc_loop_x86"));
++	&test	($s2,15);
++	&jnz	(&label("slow_enc_tail"));
++	&mov	($acc,$_ivp);		# load ivp
++	&mov	($s2,&DWP(8,$key));	# restore last dwords
++	&mov	($s3,&DWP(12,$key));
++	&mov	(&DWP(0,$acc),$s0);	# save ivec
++	&mov	(&DWP(4,$acc),$s1);
++	&mov	(&DWP(8,$acc),$s2);
++	&mov	(&DWP(12,$acc),$s3);
++
++	&mov	("esp",$_esp);
++	&popf	();
++	&function_end_A();
++	&pushf	();			# kludge, never executed
++
++    &set_label("slow_enc_tail",16);
++	&emms	()	if (!$x86only);
++	&mov	($key eq "edi"? $key:"",$s3);	# load out to edi
++	&mov	($s1,16);
++	&sub	($s1,$s2);
++	&cmp	($key,$acc eq "esi"? $acc:"");	# compare with inp
++	&je	(&label("enc_in_place"));
++	&align	(4);
++	&data_word(0xA4F3F689);	# rep movsb	# copy input
++	&jmp	(&label("enc_skip_in_place"));
++    &set_label("enc_in_place");
++	&lea	($key,&DWP(0,$key,$s2));
++    &set_label("enc_skip_in_place");
++	&mov	($s2,$s1);
++	&xor	($s0,$s0);
++	&align	(4);
++	&data_word(0xAAF3F689);	# rep stosb	# zero tail
++
++	&mov	($key,$_ivp);			# restore ivp
++	&mov	($acc,$s3);			# output as input
++	&mov	($s0,&DWP(0,$key));
++	&mov	($s1,&DWP(4,$key));
++	&mov	($_len,16);			# len=16
++	&jmp	(&label("slow_enc_loop_x86"));	# one more spin...
++
++#--------------------------- SLOW DECRYPT ---------------------------#
++&set_label("slow_decrypt",16);
++					if (!$x86only) {
++	&bt	($_tmp,25);		# check for SSE bit
++	&jnc	(&label("slow_dec_loop_x86"));
++
++	&set_label("slow_dec_loop_sse",4);
++		&movq	("mm0",&QWP(0,$acc));	# read input
++		&movq	("mm4",&QWP(8,$acc));
++
++		&mov	($key,$_key);
++		&call	("_sse_AES_decrypt_compact");
++
++		&mov	($acc,$_inp);		# load inp
++		&lea	($s0,$ivec);
++		&mov	($s1,$_out);		# load out
++		&mov	($s2,$_len);		# load len
++		&mov	($key,$_ivp);		# load ivp
++
++		&movq	("mm1",&QWP(0,$acc));	# re-read input
++		&movq	("mm5",&QWP(8,$acc));
++
++		&pxor	("mm0",&QWP(0,$key));	# xor iv
++		&pxor	("mm4",&QWP(8,$key));
++
++		&movq	(&QWP(0,$key),"mm1");	# copy input to iv
++		&movq	(&QWP(8,$key),"mm5");
++
++		&sub	($s2,16);		# decrease len
++		&jc	(&label("slow_dec_partial_sse"));
++
++		&movq	(&QWP(0,$s1),"mm0");	# write output
++		&movq	(&QWP(8,$s1),"mm4");
++
++		&lea	($s1,&DWP(16,$s1));	# advance out
++		&mov	($_out,$s1);		# save out
++		&lea	($acc,&DWP(16,$acc));	# advance inp
++		&mov	($_inp,$acc);		# save inp
++		&mov	($_len,$s2);		# save len
++	&jnz	(&label("slow_dec_loop_sse"));
++	&emms	();
++	&mov	("esp",$_esp);
++	&popf	();
++	&function_end_A();
++	&pushf	();			# kludge, never executed
++
++    &set_label("slow_dec_partial_sse",16);
++	&movq	(&QWP(0,$s0),"mm0");	# save output to temp
++	&movq	(&QWP(8,$s0),"mm4");
++	&emms	();
++
++	&add	($s2 eq "ecx" ? "ecx":"",16);
++	&mov	("edi",$s1);		# out
++	&mov	("esi",$s0);		# temp
++	&align	(4);
++	&data_word(0xA4F3F689);		# rep movsb # copy partial output
++
++	&mov	("esp",$_esp);
++	&popf	();
++	&function_end_A();
++	&pushf	();			# kludge, never executed
++					}
++	&set_label("slow_dec_loop_x86",16);
++		&mov	($s0,&DWP(0,$acc));	# read input
++		&mov	($s1,&DWP(4,$acc));
++		&mov	($s2,&DWP(8,$acc));
++		&mov	($s3,&DWP(12,$acc));
++
++		&lea	($key,$ivec);
++		&mov	(&DWP(0,$key),$s0);	# copy to temp
++		&mov	(&DWP(4,$key),$s1);
++		&mov	(&DWP(8,$key),$s2);
++		&mov	(&DWP(12,$key),$s3);
++
++		&mov	($key,$_key);		# load key
++		&call	("_x86_AES_decrypt_compact");
++
++		&mov	($key,$_ivp);		# load ivp
++		&mov	($acc,$_len);		# load len
++		&xor	($s0,&DWP(0,$key));	# xor iv
++		&xor	($s1,&DWP(4,$key));
++		&xor	($s2,&DWP(8,$key));
++		&xor	($s3,&DWP(12,$key));
++
++		&sub	($acc,16);
++		&jc	(&label("slow_dec_partial_x86"));
++
++		&mov	($_len,$acc);		# save len
++		&mov	($acc,$_out);		# load out
++
++		&mov	(&DWP(0,$acc),$s0);	# write output
++		&mov	(&DWP(4,$acc),$s1);
++		&mov	(&DWP(8,$acc),$s2);
++		&mov	(&DWP(12,$acc),$s3);
++
++		&lea	($acc,&DWP(16,$acc));	# advance out
++		&mov	($_out,$acc);		# save out
++
++		&lea	($acc,$ivec);
++		&mov	($s0,&DWP(0,$acc));	# read temp
++		&mov	($s1,&DWP(4,$acc));
++		&mov	($s2,&DWP(8,$acc));
++		&mov	($s3,&DWP(12,$acc));
++
++		&mov	(&DWP(0,$key),$s0);	# copy it to iv
++		&mov	(&DWP(4,$key),$s1);
++		&mov	(&DWP(8,$key),$s2);
++		&mov	(&DWP(12,$key),$s3);
++
++		&mov	($acc,$_inp);		# load inp
++		&lea	($acc,&DWP(16,$acc));	# advance inp
++		&mov	($_inp,$acc);		# save inp
++	&jnz	(&label("slow_dec_loop_x86"));
++	&mov	("esp",$_esp);
++	&popf	();
++	&function_end_A();
++	&pushf	();			# kludge, never executed
++
++    &set_label("slow_dec_partial_x86",16);
++	&lea	($acc,$ivec);
++	&mov	(&DWP(0,$acc),$s0);	# save output to temp
++	&mov	(&DWP(4,$acc),$s1);
++	&mov	(&DWP(8,$acc),$s2);
++	&mov	(&DWP(12,$acc),$s3);
++
++	&mov	($acc,$_inp);
++	&mov	($s0,&DWP(0,$acc));	# re-read input
++	&mov	($s1,&DWP(4,$acc));
++	&mov	($s2,&DWP(8,$acc));
++	&mov	($s3,&DWP(12,$acc));
++
++	&mov	(&DWP(0,$key),$s0);	# copy it to iv
++	&mov	(&DWP(4,$key),$s1);
++	&mov	(&DWP(8,$key),$s2);
++	&mov	(&DWP(12,$key),$s3);
++
++	&mov	("ecx",$_len);
++	&mov	("edi",$_out);
++	&lea	("esi",$ivec);
++	&align	(4);
++	&data_word(0xA4F3F689);		# rep movsb # copy partial output
++
++	&mov	("esp",$_esp);
++	&popf	();
++&function_end("AES_cbc_encrypt");
++}
++
++#------------------------------------------------------------------#
++
++sub enckey()
++{
++	&movz	("esi",&LB("edx"));		# rk[i]>>0
++	&movz	("ebx",&BP(-128,$tbl,"esi",1));
++	&movz	("esi",&HB("edx"));		# rk[i]>>8
++	&shl	("ebx",24);
++	&xor	("eax","ebx");
++
++	&movz	("ebx",&BP(-128,$tbl,"esi",1));
++	&shr	("edx",16);
++	&movz	("esi",&LB("edx"));		# rk[i]>>16
++	&xor	("eax","ebx");
++
++	&movz	("ebx",&BP(-128,$tbl,"esi",1));
++	&movz	("esi",&HB("edx"));		# rk[i]>>24
++	&shl	("ebx",8);
++	&xor	("eax","ebx");
++
++	&movz	("ebx",&BP(-128,$tbl,"esi",1));
++	&shl	("ebx",16);
++	&xor	("eax","ebx");
++
++	&xor	("eax",&DWP(1024-128,$tbl,"ecx",4));	# rcon
++}
++
++&function_begin("_x86_AES_set_encrypt_key");
++	&mov	("esi",&wparam(1));		# user supplied key
++	&mov	("edi",&wparam(3));		# private key schedule
++
++	&test	("esi",-1);
++	&jz	(&label("badpointer"));
++	&test	("edi",-1);
++	&jz	(&label("badpointer"));
++
++	&call	(&label("pic_point"));
++	&set_label("pic_point");
++	&blindpop($tbl);
++	&lea	($tbl,&DWP(&label("AES_Te")."-".&label("pic_point"),$tbl));
++	&lea	($tbl,&DWP(2048+128,$tbl));
++
++	# prefetch Te4
++	&mov	("eax",&DWP(0-128,$tbl));
++	&mov	("ebx",&DWP(32-128,$tbl));
++	&mov	("ecx",&DWP(64-128,$tbl));
++	&mov	("edx",&DWP(96-128,$tbl));
++	&mov	("eax",&DWP(128-128,$tbl));
++	&mov	("ebx",&DWP(160-128,$tbl));
++	&mov	("ecx",&DWP(192-128,$tbl));
++	&mov	("edx",&DWP(224-128,$tbl));
++
++	&mov	("ecx",&wparam(2));		# number of bits in key
++	&cmp	("ecx",128);
++	&je	(&label("10rounds"));
++	&cmp	("ecx",192);
++	&je	(&label("12rounds"));
++	&cmp	("ecx",256);
++	&je	(&label("14rounds"));
++	&mov	("eax",-2);			# invalid number of bits
++	&jmp	(&label("exit"));
++
++    &set_label("10rounds");
++	&mov	("eax",&DWP(0,"esi"));		# copy first 4 dwords
++	&mov	("ebx",&DWP(4,"esi"));
++	&mov	("ecx",&DWP(8,"esi"));
++	&mov	("edx",&DWP(12,"esi"));
++	&mov	(&DWP(0,"edi"),"eax");
++	&mov	(&DWP(4,"edi"),"ebx");
++	&mov	(&DWP(8,"edi"),"ecx");
++	&mov	(&DWP(12,"edi"),"edx");
++
++	&xor	("ecx","ecx");
++	&jmp	(&label("10shortcut"));
++
++	&align	(4);
++	&set_label("10loop");
++		&mov	("eax",&DWP(0,"edi"));		# rk[0]
++		&mov	("edx",&DWP(12,"edi"));		# rk[3]
++	&set_label("10shortcut");
++		&enckey	();
++
++		&mov	(&DWP(16,"edi"),"eax");		# rk[4]
++		&xor	("eax",&DWP(4,"edi"));
++		&mov	(&DWP(20,"edi"),"eax");		# rk[5]
++		&xor	("eax",&DWP(8,"edi"));
++		&mov	(&DWP(24,"edi"),"eax");		# rk[6]
++		&xor	("eax",&DWP(12,"edi"));
++		&mov	(&DWP(28,"edi"),"eax");		# rk[7]
++		&inc	("ecx");
++		&add	("edi",16);
++		&cmp	("ecx",10);
++	&jl	(&label("10loop"));
++
++	&mov	(&DWP(80,"edi"),10);		# setup number of rounds
++	&xor	("eax","eax");
++	&jmp	(&label("exit"));
++		
++    &set_label("12rounds");
++	&mov	("eax",&DWP(0,"esi"));		# copy first 6 dwords
++	&mov	("ebx",&DWP(4,"esi"));
++	&mov	("ecx",&DWP(8,"esi"));
++	&mov	("edx",&DWP(12,"esi"));
++	&mov	(&DWP(0,"edi"),"eax");
++	&mov	(&DWP(4,"edi"),"ebx");
++	&mov	(&DWP(8,"edi"),"ecx");
++	&mov	(&DWP(12,"edi"),"edx");
++	&mov	("ecx",&DWP(16,"esi"));
++	&mov	("edx",&DWP(20,"esi"));
++	&mov	(&DWP(16,"edi"),"ecx");
++	&mov	(&DWP(20,"edi"),"edx");
++
++	&xor	("ecx","ecx");
++	&jmp	(&label("12shortcut"));
++
++	&align	(4);
++	&set_label("12loop");
++		&mov	("eax",&DWP(0,"edi"));		# rk[0]
++		&mov	("edx",&DWP(20,"edi"));		# rk[5]
++	&set_label("12shortcut");
++		&enckey	();
++
++		&mov	(&DWP(24,"edi"),"eax");		# rk[6]
++		&xor	("eax",&DWP(4,"edi"));
++		&mov	(&DWP(28,"edi"),"eax");		# rk[7]
++		&xor	("eax",&DWP(8,"edi"));
++		&mov	(&DWP(32,"edi"),"eax");		# rk[8]
++		&xor	("eax",&DWP(12,"edi"));
++		&mov	(&DWP(36,"edi"),"eax");		# rk[9]
++
++		&cmp	("ecx",7);
++		&je	(&label("12break"));
++		&inc	("ecx");
++
++		&xor	("eax",&DWP(16,"edi"));
++		&mov	(&DWP(40,"edi"),"eax");		# rk[10]
++		&xor	("eax",&DWP(20,"edi"));
++		&mov	(&DWP(44,"edi"),"eax");		# rk[11]
++
++		&add	("edi",24);
++	&jmp	(&label("12loop"));
++
++	&set_label("12break");
++	&mov	(&DWP(72,"edi"),12);		# setup number of rounds
++	&xor	("eax","eax");
++	&jmp	(&label("exit"));
++
++    &set_label("14rounds");
++	&mov	("eax",&DWP(0,"esi"));		# copy first 8 dwords
++	&mov	("ebx",&DWP(4,"esi"));
++	&mov	("ecx",&DWP(8,"esi"));
++	&mov	("edx",&DWP(12,"esi"));
++	&mov	(&DWP(0,"edi"),"eax");
++	&mov	(&DWP(4,"edi"),"ebx");
++	&mov	(&DWP(8,"edi"),"ecx");
++	&mov	(&DWP(12,"edi"),"edx");
++	&mov	("eax",&DWP(16,"esi"));
++	&mov	("ebx",&DWP(20,"esi"));
++	&mov	("ecx",&DWP(24,"esi"));
++	&mov	("edx",&DWP(28,"esi"));
++	&mov	(&DWP(16,"edi"),"eax");
++	&mov	(&DWP(20,"edi"),"ebx");
++	&mov	(&DWP(24,"edi"),"ecx");
++	&mov	(&DWP(28,"edi"),"edx");
++
++	&xor	("ecx","ecx");
++	&jmp	(&label("14shortcut"));
++
++	&align	(4);
++	&set_label("14loop");
++		&mov	("edx",&DWP(28,"edi"));		# rk[7]
++	&set_label("14shortcut");
++		&mov	("eax",&DWP(0,"edi"));		# rk[0]
++
++		&enckey	();
++
++		&mov	(&DWP(32,"edi"),"eax");		# rk[8]
++		&xor	("eax",&DWP(4,"edi"));
++		&mov	(&DWP(36,"edi"),"eax");		# rk[9]
++		&xor	("eax",&DWP(8,"edi"));
++		&mov	(&DWP(40,"edi"),"eax");		# rk[10]
++		&xor	("eax",&DWP(12,"edi"));
++		&mov	(&DWP(44,"edi"),"eax");		# rk[11]
++
++		&cmp	("ecx",6);
++		&je	(&label("14break"));
++		&inc	("ecx");
++
++		&mov	("edx","eax");
++		&mov	("eax",&DWP(16,"edi"));		# rk[4]
++		&movz	("esi",&LB("edx"));		# rk[11]>>0
++		&movz	("ebx",&BP(-128,$tbl,"esi",1));
++		&movz	("esi",&HB("edx"));		# rk[11]>>8
++		&xor	("eax","ebx");
++
++		&movz	("ebx",&BP(-128,$tbl,"esi",1));
++		&shr	("edx",16);
++		&shl	("ebx",8);
++		&movz	("esi",&LB("edx"));		# rk[11]>>16
++		&xor	("eax","ebx");
++
++		&movz	("ebx",&BP(-128,$tbl,"esi",1));
++		&movz	("esi",&HB("edx"));		# rk[11]>>24
++		&shl	("ebx",16);
++		&xor	("eax","ebx");
++
++		&movz	("ebx",&BP(-128,$tbl,"esi",1));
++		&shl	("ebx",24);
++		&xor	("eax","ebx");
++
++		&mov	(&DWP(48,"edi"),"eax");		# rk[12]
++		&xor	("eax",&DWP(20,"edi"));
++		&mov	(&DWP(52,"edi"),"eax");		# rk[13]
++		&xor	("eax",&DWP(24,"edi"));
++		&mov	(&DWP(56,"edi"),"eax");		# rk[14]
++		&xor	("eax",&DWP(28,"edi"));
++		&mov	(&DWP(60,"edi"),"eax");		# rk[15]
++
++		&add	("edi",32);
++	&jmp	(&label("14loop"));
++
++	&set_label("14break");
++	&mov	(&DWP(48,"edi"),14);		# setup number of rounds
++	&xor	("eax","eax");
++	&jmp	(&label("exit"));
++
++    &set_label("badpointer");
++	&mov	("eax",-1);
++    &set_label("exit");
++&function_end("_x86_AES_set_encrypt_key");
++
++# int AES_set_encrypt_key(const unsigned char *userKey, const int bits,
++#                        AES_KEY *key)
++&function_begin_B("AES_set_encrypt_key");
++	&call	("_x86_AES_set_encrypt_key");
++	&ret	();
++&function_end_B("AES_set_encrypt_key");
++
++sub deckey()
++{ my ($i,$key,$tp1,$tp2,$tp4,$tp8) = @_;
++  my $tmp = $tbl;
++
++	&mov	($tmp,0x80808080);
++	&and	($tmp,$tp1);
++	&lea	($tp2,&DWP(0,$tp1,$tp1));
++	&mov	($acc,$tmp);
++	&shr	($tmp,7);
++	&sub	($acc,$tmp);
++	&and	($tp2,0xfefefefe);
++	&and	($acc,0x1b1b1b1b);
++	&xor	($tp2,$acc);
++	&mov	($tmp,0x80808080);
++
++	&and	($tmp,$tp2);
++	&lea	($tp4,&DWP(0,$tp2,$tp2));
++	&mov	($acc,$tmp);
++	&shr	($tmp,7);
++	&sub	($acc,$tmp);
++	&and	($tp4,0xfefefefe);
++	&and	($acc,0x1b1b1b1b);
++	 &xor	($tp2,$tp1);	# tp2^tp1
++	&xor	($tp4,$acc);
++	&mov	($tmp,0x80808080);
++
++	&and	($tmp,$tp4);
++	&lea	($tp8,&DWP(0,$tp4,$tp4));
++	&mov	($acc,$tmp);
++	&shr	($tmp,7);
++	 &xor	($tp4,$tp1);	# tp4^tp1
++	&sub	($acc,$tmp);
++	&and	($tp8,0xfefefefe);
++	&and	($acc,0x1b1b1b1b);
++	 &rotl	($tp1,8);	# = ROTATE(tp1,8)
++	&xor	($tp8,$acc);
++
++	&mov	($tmp,&DWP(4*($i+1),$key));	# modulo-scheduled load
++
++	&xor	($tp1,$tp2);
++	&xor	($tp2,$tp8);
++	&xor	($tp1,$tp4);
++	&rotl	($tp2,24);
++	&xor	($tp4,$tp8);
++	&xor	($tp1,$tp8);	# ^= tp8^(tp4^tp1)^(tp2^tp1)
++	&rotl	($tp4,16);
++	&xor	($tp1,$tp2);	# ^= ROTATE(tp8^tp2^tp1,24)
++	&rotl	($tp8,8);
++	&xor	($tp1,$tp4);	# ^= ROTATE(tp8^tp4^tp1,16)
++	&mov	($tp2,$tmp);
++	&xor	($tp1,$tp8);	# ^= ROTATE(tp8,8)
++
++	&mov	(&DWP(4*$i,$key),$tp1);
++}
++
++# int AES_set_decrypt_key(const unsigned char *userKey, const int bits,
++#                        AES_KEY *key)
++&function_begin_B("AES_set_decrypt_key");
++	&call	("_x86_AES_set_encrypt_key");
++	&cmp	("eax",0);
++	&je	(&label("proceed"));
++	&ret	();
++
++    &set_label("proceed");
++	&push	("ebp");
++	&push	("ebx");
++	&push	("esi");
++	&push	("edi");
++
++	&mov	("esi",&wparam(2));
++	&mov	("ecx",&DWP(240,"esi"));	# pull number of rounds
++	&lea	("ecx",&DWP(0,"","ecx",4));
++	&lea	("edi",&DWP(0,"esi","ecx",4));	# pointer to last chunk
++
++	&set_label("invert",4);			# invert order of chunks
++		&mov	("eax",&DWP(0,"esi"));
++		&mov	("ebx",&DWP(4,"esi"));
++		&mov	("ecx",&DWP(0,"edi"));
++		&mov	("edx",&DWP(4,"edi"));
++		&mov	(&DWP(0,"edi"),"eax");
++		&mov	(&DWP(4,"edi"),"ebx");
++		&mov	(&DWP(0,"esi"),"ecx");
++		&mov	(&DWP(4,"esi"),"edx");
++		&mov	("eax",&DWP(8,"esi"));
++		&mov	("ebx",&DWP(12,"esi"));
++		&mov	("ecx",&DWP(8,"edi"));
++		&mov	("edx",&DWP(12,"edi"));
++		&mov	(&DWP(8,"edi"),"eax");
++		&mov	(&DWP(12,"edi"),"ebx");
++		&mov	(&DWP(8,"esi"),"ecx");
++		&mov	(&DWP(12,"esi"),"edx");
++		&add	("esi",16);
++		&sub	("edi",16);
++		&cmp	("esi","edi");
++	&jne	(&label("invert"));
++
++	&mov	($key,&wparam(2));
++	&mov	($acc,&DWP(240,$key));		# pull number of rounds
++	&lea	($acc,&DWP(-2,$acc,$acc));
++	&lea	($acc,&DWP(0,$key,$acc,8));
++	&mov	(&wparam(2),$acc);
++
++	&mov	($s0,&DWP(16,$key));		# modulo-scheduled load
++	&set_label("permute",4);		# permute the key schedule
++		&add	($key,16);
++		&deckey	(0,$key,$s0,$s1,$s2,$s3);
++		&deckey	(1,$key,$s1,$s2,$s3,$s0);
++		&deckey	(2,$key,$s2,$s3,$s0,$s1);
++		&deckey	(3,$key,$s3,$s0,$s1,$s2);
++		&cmp	($key,&wparam(2));
++	&jb	(&label("permute"));
++
++	&xor	("eax","eax");			# return success
++&function_end("AES_set_decrypt_key");
++&asciz("AES for x86, CRYPTOGAMS by ");
++
++&asm_finish();
++
++close STDOUT;
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/aes/asm/aes-armv4.pl b/CryptoPkg/Library/OpensslLib/openssl/crypto/aes/asm/aes-armv4.pl
+new file mode 100644
+index 0000000..16d79aa
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/aes/asm/aes-armv4.pl
+@@ -0,0 +1,1245 @@
++#! /usr/bin/env perl
++# Copyright 2007-2016 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
++# in the file LICENSE in the source distribution or at
++# https://www.openssl.org/source/license.html
++
++
++# ====================================================================
++# Written by Andy Polyakov  for the OpenSSL
++# project. The module is, however, dual licensed under OpenSSL and
++# CRYPTOGAMS licenses depending on where you obtain it. For further
++# details see http://www.openssl.org/~appro/cryptogams/.
++# ====================================================================
++
++# AES for ARMv4
++
++# January 2007.
++#
++# Code uses single 1K S-box and is >2 times faster than code generated
++# by gcc-3.4.1. This is thanks to unique feature of ARMv4 ISA, which
++# allows to merge logical or arithmetic operation with shift or rotate
++# in one instruction and emit combined result every cycle. The module
++# is endian-neutral. The performance is ~42 cycles/byte for 128-bit
++# key [on single-issue Xscale PXA250 core].
++
++# May 2007.
++#
++# AES_set_[en|de]crypt_key is added.
++
++# July 2010.
++#
++# Rescheduling for dual-issue pipeline resulted in 12% improvement on
++# Cortex A8 core and ~25 cycles per byte processed with 128-bit key.
++
++# February 2011.
++#
++# Profiler-assisted and platform-specific optimization resulted in 16%
++# improvement on Cortex A8 core and ~21.5 cycles per byte.
++
++$flavour = shift;
++if ($flavour=~/\w[\w\-]*\.\w+$/) { $output=$flavour; undef $flavour; }
++else { while (($output=shift) && ($output!~/\w[\w\-]*\.\w+$/)) {} }
++
++if ($flavour && $flavour ne "void") {
++    $0 =~ m/(.*[\/\\])[^\/\\]+$/; $dir=$1;
++    ( $xlate="${dir}arm-xlate.pl" and -f $xlate ) or
++    ( $xlate="${dir}../../perlasm/arm-xlate.pl" and -f $xlate) or
++    die "can't locate arm-xlate.pl";
++
++    open STDOUT,"| \"$^X\" $xlate $flavour $output";
++} else {
++    open STDOUT,">$output";
++}
++
++$s0="r0";
++$s1="r1";
++$s2="r2";
++$s3="r3";
++$t1="r4";
++$t2="r5";
++$t3="r6";
++$i1="r7";
++$i2="r8";
++$i3="r9";
++
++$tbl="r10";
++$key="r11";
++$rounds="r12";
++
++$code=<<___;
++#ifndef __KERNEL__
++# include "arm_arch.h"
++#else
++# define __ARM_ARCH__ __LINUX_ARM_ARCH__
++#endif
++
++.text
++#if defined(__thumb2__) && !defined(__APPLE__)
++.syntax	unified
++.thumb
++#else
++.code	32
++#undef __thumb2__
++#endif
++
++.type	AES_Te,%object
++.align	5
++AES_Te:
++.word	0xc66363a5, 0xf87c7c84, 0xee777799, 0xf67b7b8d
++.word	0xfff2f20d, 0xd66b6bbd, 0xde6f6fb1, 0x91c5c554
++.word	0x60303050, 0x02010103, 0xce6767a9, 0x562b2b7d
++.word	0xe7fefe19, 0xb5d7d762, 0x4dababe6, 0xec76769a
++.word	0x8fcaca45, 0x1f82829d, 0x89c9c940, 0xfa7d7d87
++.word	0xeffafa15, 0xb25959eb, 0x8e4747c9, 0xfbf0f00b
++.word	0x41adadec, 0xb3d4d467, 0x5fa2a2fd, 0x45afafea
++.word	0x239c9cbf, 0x53a4a4f7, 0xe4727296, 0x9bc0c05b
++.word	0x75b7b7c2, 0xe1fdfd1c, 0x3d9393ae, 0x4c26266a
++.word	0x6c36365a, 0x7e3f3f41, 0xf5f7f702, 0x83cccc4f
++.word	0x6834345c, 0x51a5a5f4, 0xd1e5e534, 0xf9f1f108
++.word	0xe2717193, 0xabd8d873, 0x62313153, 0x2a15153f
++.word	0x0804040c, 0x95c7c752, 0x46232365, 0x9dc3c35e
++.word	0x30181828, 0x379696a1, 0x0a05050f, 0x2f9a9ab5
++.word	0x0e070709, 0x24121236, 0x1b80809b, 0xdfe2e23d
++.word	0xcdebeb26, 0x4e272769, 0x7fb2b2cd, 0xea75759f
++.word	0x1209091b, 0x1d83839e, 0x582c2c74, 0x341a1a2e
++.word	0x361b1b2d, 0xdc6e6eb2, 0xb45a5aee, 0x5ba0a0fb
++.word	0xa45252f6, 0x763b3b4d, 0xb7d6d661, 0x7db3b3ce
++.word	0x5229297b, 0xdde3e33e, 0x5e2f2f71, 0x13848497
++.word	0xa65353f5, 0xb9d1d168, 0x00000000, 0xc1eded2c
++.word	0x40202060, 0xe3fcfc1f, 0x79b1b1c8, 0xb65b5bed
++.word	0xd46a6abe, 0x8dcbcb46, 0x67bebed9, 0x7239394b
++.word	0x944a4ade, 0x984c4cd4, 0xb05858e8, 0x85cfcf4a
++.word	0xbbd0d06b, 0xc5efef2a, 0x4faaaae5, 0xedfbfb16
++.word	0x864343c5, 0x9a4d4dd7, 0x66333355, 0x11858594
++.word	0x8a4545cf, 0xe9f9f910, 0x04020206, 0xfe7f7f81
++.word	0xa05050f0, 0x783c3c44, 0x259f9fba, 0x4ba8a8e3
++.word	0xa25151f3, 0x5da3a3fe, 0x804040c0, 0x058f8f8a
++.word	0x3f9292ad, 0x219d9dbc, 0x70383848, 0xf1f5f504
++.word	0x63bcbcdf, 0x77b6b6c1, 0xafdada75, 0x42212163
++.word	0x20101030, 0xe5ffff1a, 0xfdf3f30e, 0xbfd2d26d
++.word	0x81cdcd4c, 0x180c0c14, 0x26131335, 0xc3ecec2f
++.word	0xbe5f5fe1, 0x359797a2, 0x884444cc, 0x2e171739
++.word	0x93c4c457, 0x55a7a7f2, 0xfc7e7e82, 0x7a3d3d47
++.word	0xc86464ac, 0xba5d5de7, 0x3219192b, 0xe6737395
++.word	0xc06060a0, 0x19818198, 0x9e4f4fd1, 0xa3dcdc7f
++.word	0x44222266, 0x542a2a7e, 0x3b9090ab, 0x0b888883
++.word	0x8c4646ca, 0xc7eeee29, 0x6bb8b8d3, 0x2814143c
++.word	0xa7dede79, 0xbc5e5ee2, 0x160b0b1d, 0xaddbdb76
++.word	0xdbe0e03b, 0x64323256, 0x743a3a4e, 0x140a0a1e
++.word	0x924949db, 0x0c06060a, 0x4824246c, 0xb85c5ce4
++.word	0x9fc2c25d, 0xbdd3d36e, 0x43acacef, 0xc46262a6
++.word	0x399191a8, 0x319595a4, 0xd3e4e437, 0xf279798b
++.word	0xd5e7e732, 0x8bc8c843, 0x6e373759, 0xda6d6db7
++.word	0x018d8d8c, 0xb1d5d564, 0x9c4e4ed2, 0x49a9a9e0
++.word	0xd86c6cb4, 0xac5656fa, 0xf3f4f407, 0xcfeaea25
++.word	0xca6565af, 0xf47a7a8e, 0x47aeaee9, 0x10080818
++.word	0x6fbabad5, 0xf0787888, 0x4a25256f, 0x5c2e2e72
++.word	0x381c1c24, 0x57a6a6f1, 0x73b4b4c7, 0x97c6c651
++.word	0xcbe8e823, 0xa1dddd7c, 0xe874749c, 0x3e1f1f21
++.word	0x964b4bdd, 0x61bdbddc, 0x0d8b8b86, 0x0f8a8a85
++.word	0xe0707090, 0x7c3e3e42, 0x71b5b5c4, 0xcc6666aa
++.word	0x904848d8, 0x06030305, 0xf7f6f601, 0x1c0e0e12
++.word	0xc26161a3, 0x6a35355f, 0xae5757f9, 0x69b9b9d0
++.word	0x17868691, 0x99c1c158, 0x3a1d1d27, 0x279e9eb9
++.word	0xd9e1e138, 0xebf8f813, 0x2b9898b3, 0x22111133
++.word	0xd26969bb, 0xa9d9d970, 0x078e8e89, 0x339494a7
++.word	0x2d9b9bb6, 0x3c1e1e22, 0x15878792, 0xc9e9e920
++.word	0x87cece49, 0xaa5555ff, 0x50282878, 0xa5dfdf7a
++.word	0x038c8c8f, 0x59a1a1f8, 0x09898980, 0x1a0d0d17
++.word	0x65bfbfda, 0xd7e6e631, 0x844242c6, 0xd06868b8
++.word	0x824141c3, 0x299999b0, 0x5a2d2d77, 0x1e0f0f11
++.word	0x7bb0b0cb, 0xa85454fc, 0x6dbbbbd6, 0x2c16163a
++@ Te4[256]
++.byte	0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5
++.byte	0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76
++.byte	0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0
++.byte	0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0
++.byte	0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc
++.byte	0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15
++.byte	0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a
++.byte	0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75
++.byte	0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0
++.byte	0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84
++.byte	0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b
++.byte	0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf
++.byte	0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85
++.byte	0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8
++.byte	0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5
++.byte	0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2
++.byte	0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17
++.byte	0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73
++.byte	0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88
++.byte	0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb
++.byte	0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c
++.byte	0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79
++.byte	0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9
++.byte	0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08
++.byte	0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6
++.byte	0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a
++.byte	0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e
++.byte	0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e
++.byte	0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94
++.byte	0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf
++.byte	0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68
++.byte	0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16
++@ rcon[]
++.word	0x01000000, 0x02000000, 0x04000000, 0x08000000
++.word	0x10000000, 0x20000000, 0x40000000, 0x80000000
++.word	0x1B000000, 0x36000000, 0, 0, 0, 0, 0, 0
++.size	AES_Te,.-AES_Te
++
++@ void AES_encrypt(const unsigned char *in, unsigned char *out,
++@ 		 const AES_KEY *key) {
++.global AES_encrypt
++.type   AES_encrypt,%function
++.align	5
++AES_encrypt:
++#ifndef	__thumb2__
++	sub	r3,pc,#8		@ AES_encrypt
++#else
++	adr	r3,AES_encrypt
++#endif
++	stmdb   sp!,{r1,r4-r12,lr}
++#ifdef	__APPLE__
++	adr	$tbl,AES_Te
++#else
++	sub	$tbl,r3,#AES_encrypt-AES_Te	@ Te
++#endif
++	mov	$rounds,r0		@ inp
++	mov	$key,r2
++#if __ARM_ARCH__<7
++	ldrb	$s0,[$rounds,#3]	@ load input data in endian-neutral
++	ldrb	$t1,[$rounds,#2]	@ manner...
++	ldrb	$t2,[$rounds,#1]
++	ldrb	$t3,[$rounds,#0]
++	orr	$s0,$s0,$t1,lsl#8
++	ldrb	$s1,[$rounds,#7]
++	orr	$s0,$s0,$t2,lsl#16
++	ldrb	$t1,[$rounds,#6]
++	orr	$s0,$s0,$t3,lsl#24
++	ldrb	$t2,[$rounds,#5]
++	ldrb	$t3,[$rounds,#4]
++	orr	$s1,$s1,$t1,lsl#8
++	ldrb	$s2,[$rounds,#11]
++	orr	$s1,$s1,$t2,lsl#16
++	ldrb	$t1,[$rounds,#10]
++	orr	$s1,$s1,$t3,lsl#24
++	ldrb	$t2,[$rounds,#9]
++	ldrb	$t3,[$rounds,#8]
++	orr	$s2,$s2,$t1,lsl#8
++	ldrb	$s3,[$rounds,#15]
++	orr	$s2,$s2,$t2,lsl#16
++	ldrb	$t1,[$rounds,#14]
++	orr	$s2,$s2,$t3,lsl#24
++	ldrb	$t2,[$rounds,#13]
++	ldrb	$t3,[$rounds,#12]
++	orr	$s3,$s3,$t1,lsl#8
++	orr	$s3,$s3,$t2,lsl#16
++	orr	$s3,$s3,$t3,lsl#24
++#else
++	ldr	$s0,[$rounds,#0]
++	ldr	$s1,[$rounds,#4]
++	ldr	$s2,[$rounds,#8]
++	ldr	$s3,[$rounds,#12]
++#ifdef __ARMEL__
++	rev	$s0,$s0
++	rev	$s1,$s1
++	rev	$s2,$s2
++	rev	$s3,$s3
++#endif
++#endif
++	bl	_armv4_AES_encrypt
++
++	ldr	$rounds,[sp],#4		@ pop out
++#if __ARM_ARCH__>=7
++#ifdef __ARMEL__
++	rev	$s0,$s0
++	rev	$s1,$s1
++	rev	$s2,$s2
++	rev	$s3,$s3
++#endif
++	str	$s0,[$rounds,#0]
++	str	$s1,[$rounds,#4]
++	str	$s2,[$rounds,#8]
++	str	$s3,[$rounds,#12]
++#else
++	mov	$t1,$s0,lsr#24		@ write output in endian-neutral
++	mov	$t2,$s0,lsr#16		@ manner...
++	mov	$t3,$s0,lsr#8
++	strb	$t1,[$rounds,#0]
++	strb	$t2,[$rounds,#1]
++	mov	$t1,$s1,lsr#24
++	strb	$t3,[$rounds,#2]
++	mov	$t2,$s1,lsr#16
++	strb	$s0,[$rounds,#3]
++	mov	$t3,$s1,lsr#8
++	strb	$t1,[$rounds,#4]
++	strb	$t2,[$rounds,#5]
++	mov	$t1,$s2,lsr#24
++	strb	$t3,[$rounds,#6]
++	mov	$t2,$s2,lsr#16
++	strb	$s1,[$rounds,#7]
++	mov	$t3,$s2,lsr#8
++	strb	$t1,[$rounds,#8]
++	strb	$t2,[$rounds,#9]
++	mov	$t1,$s3,lsr#24
++	strb	$t3,[$rounds,#10]
++	mov	$t2,$s3,lsr#16
++	strb	$s2,[$rounds,#11]
++	mov	$t3,$s3,lsr#8
++	strb	$t1,[$rounds,#12]
++	strb	$t2,[$rounds,#13]
++	strb	$t3,[$rounds,#14]
++	strb	$s3,[$rounds,#15]
++#endif
++#if __ARM_ARCH__>=5
++	ldmia	sp!,{r4-r12,pc}
++#else
++	ldmia   sp!,{r4-r12,lr}
++	tst	lr,#1
++	moveq	pc,lr			@ be binary compatible with V4, yet
++	bx	lr			@ interoperable with Thumb ISA:-)
++#endif
++.size	AES_encrypt,.-AES_encrypt
++
++.type   _armv4_AES_encrypt,%function
++.align	2
++_armv4_AES_encrypt:
++	str	lr,[sp,#-4]!		@ push lr
++	ldmia	$key!,{$t1-$i1}
++	eor	$s0,$s0,$t1
++	ldr	$rounds,[$key,#240-16]
++	eor	$s1,$s1,$t2
++	eor	$s2,$s2,$t3
++	eor	$s3,$s3,$i1
++	sub	$rounds,$rounds,#1
++	mov	lr,#255
++
++	and	$i1,lr,$s0
++	and	$i2,lr,$s0,lsr#8
++	and	$i3,lr,$s0,lsr#16
++	mov	$s0,$s0,lsr#24
++.Lenc_loop:
++	ldr	$t1,[$tbl,$i1,lsl#2]	@ Te3[s0>>0]
++	and	$i1,lr,$s1,lsr#16	@ i0
++	ldr	$t2,[$tbl,$i2,lsl#2]	@ Te2[s0>>8]
++	and	$i2,lr,$s1
++	ldr	$t3,[$tbl,$i3,lsl#2]	@ Te1[s0>>16]
++	and	$i3,lr,$s1,lsr#8
++	ldr	$s0,[$tbl,$s0,lsl#2]	@ Te0[s0>>24]
++	mov	$s1,$s1,lsr#24
++
++	ldr	$i1,[$tbl,$i1,lsl#2]	@ Te1[s1>>16]
++	ldr	$i2,[$tbl,$i2,lsl#2]	@ Te3[s1>>0]
++	ldr	$i3,[$tbl,$i3,lsl#2]	@ Te2[s1>>8]
++	eor	$s0,$s0,$i1,ror#8
++	ldr	$s1,[$tbl,$s1,lsl#2]	@ Te0[s1>>24]
++	and	$i1,lr,$s2,lsr#8	@ i0
++	eor	$t2,$t2,$i2,ror#8
++	and	$i2,lr,$s2,lsr#16	@ i1
++	eor	$t3,$t3,$i3,ror#8
++	and	$i3,lr,$s2
++	ldr	$i1,[$tbl,$i1,lsl#2]	@ Te2[s2>>8]
++	eor	$s1,$s1,$t1,ror#24
++	ldr	$i2,[$tbl,$i2,lsl#2]	@ Te1[s2>>16]
++	mov	$s2,$s2,lsr#24
++
++	ldr	$i3,[$tbl,$i3,lsl#2]	@ Te3[s2>>0]
++	eor	$s0,$s0,$i1,ror#16
++	ldr	$s2,[$tbl,$s2,lsl#2]	@ Te0[s2>>24]
++	and	$i1,lr,$s3		@ i0
++	eor	$s1,$s1,$i2,ror#8
++	and	$i2,lr,$s3,lsr#8	@ i1
++	eor	$t3,$t3,$i3,ror#16
++	and	$i3,lr,$s3,lsr#16	@ i2
++	ldr	$i1,[$tbl,$i1,lsl#2]	@ Te3[s3>>0]
++	eor	$s2,$s2,$t2,ror#16
++	ldr	$i2,[$tbl,$i2,lsl#2]	@ Te2[s3>>8]
++	mov	$s3,$s3,lsr#24
++
++	ldr	$i3,[$tbl,$i3,lsl#2]	@ Te1[s3>>16]
++	eor	$s0,$s0,$i1,ror#24
++	ldr	$i1,[$key],#16
++	eor	$s1,$s1,$i2,ror#16
++	ldr	$s3,[$tbl,$s3,lsl#2]	@ Te0[s3>>24]
++	eor	$s2,$s2,$i3,ror#8
++	ldr	$t1,[$key,#-12]
++	eor	$s3,$s3,$t3,ror#8
++
++	ldr	$t2,[$key,#-8]
++	eor	$s0,$s0,$i1
++	ldr	$t3,[$key,#-4]
++	and	$i1,lr,$s0
++	eor	$s1,$s1,$t1
++	and	$i2,lr,$s0,lsr#8
++	eor	$s2,$s2,$t2
++	and	$i3,lr,$s0,lsr#16
++	eor	$s3,$s3,$t3
++	mov	$s0,$s0,lsr#24
++
++	subs	$rounds,$rounds,#1
++	bne	.Lenc_loop
++
++	add	$tbl,$tbl,#2
++
++	ldrb	$t1,[$tbl,$i1,lsl#2]	@ Te4[s0>>0]
++	and	$i1,lr,$s1,lsr#16	@ i0
++	ldrb	$t2,[$tbl,$i2,lsl#2]	@ Te4[s0>>8]
++	and	$i2,lr,$s1
++	ldrb	$t3,[$tbl,$i3,lsl#2]	@ Te4[s0>>16]
++	and	$i3,lr,$s1,lsr#8
++	ldrb	$s0,[$tbl,$s0,lsl#2]	@ Te4[s0>>24]
++	mov	$s1,$s1,lsr#24
++
++	ldrb	$i1,[$tbl,$i1,lsl#2]	@ Te4[s1>>16]
++	ldrb	$i2,[$tbl,$i2,lsl#2]	@ Te4[s1>>0]
++	ldrb	$i3,[$tbl,$i3,lsl#2]	@ Te4[s1>>8]
++	eor	$s0,$i1,$s0,lsl#8
++	ldrb	$s1,[$tbl,$s1,lsl#2]	@ Te4[s1>>24]
++	and	$i1,lr,$s2,lsr#8	@ i0
++	eor	$t2,$i2,$t2,lsl#8
++	and	$i2,lr,$s2,lsr#16	@ i1
++	eor	$t3,$i3,$t3,lsl#8
++	and	$i3,lr,$s2
++	ldrb	$i1,[$tbl,$i1,lsl#2]	@ Te4[s2>>8]
++	eor	$s1,$t1,$s1,lsl#24
++	ldrb	$i2,[$tbl,$i2,lsl#2]	@ Te4[s2>>16]
++	mov	$s2,$s2,lsr#24
++
++	ldrb	$i3,[$tbl,$i3,lsl#2]	@ Te4[s2>>0]
++	eor	$s0,$i1,$s0,lsl#8
++	ldrb	$s2,[$tbl,$s2,lsl#2]	@ Te4[s2>>24]
++	and	$i1,lr,$s3		@ i0
++	eor	$s1,$s1,$i2,lsl#16
++	and	$i2,lr,$s3,lsr#8	@ i1
++	eor	$t3,$i3,$t3,lsl#8
++	and	$i3,lr,$s3,lsr#16	@ i2
++	ldrb	$i1,[$tbl,$i1,lsl#2]	@ Te4[s3>>0]
++	eor	$s2,$t2,$s2,lsl#24
++	ldrb	$i2,[$tbl,$i2,lsl#2]	@ Te4[s3>>8]
++	mov	$s3,$s3,lsr#24
++
++	ldrb	$i3,[$tbl,$i3,lsl#2]	@ Te4[s3>>16]
++	eor	$s0,$i1,$s0,lsl#8
++	ldr	$i1,[$key,#0]
++	ldrb	$s3,[$tbl,$s3,lsl#2]	@ Te4[s3>>24]
++	eor	$s1,$s1,$i2,lsl#8
++	ldr	$t1,[$key,#4]
++	eor	$s2,$s2,$i3,lsl#16
++	ldr	$t2,[$key,#8]
++	eor	$s3,$t3,$s3,lsl#24
++	ldr	$t3,[$key,#12]
++
++	eor	$s0,$s0,$i1
++	eor	$s1,$s1,$t1
++	eor	$s2,$s2,$t2
++	eor	$s3,$s3,$t3
++
++	sub	$tbl,$tbl,#2
++	ldr	pc,[sp],#4		@ pop and return
++.size	_armv4_AES_encrypt,.-_armv4_AES_encrypt
++
++.global AES_set_encrypt_key
++.type   AES_set_encrypt_key,%function
++.align	5
++AES_set_encrypt_key:
++_armv4_AES_set_encrypt_key:
++#ifndef	__thumb2__
++	sub	r3,pc,#8		@ AES_set_encrypt_key
++#else
++	adr	r3,AES_set_encrypt_key
++#endif
++	teq	r0,#0
++#ifdef	__thumb2__
++	itt	eq			@ Thumb2 thing, sanity check in ARM
++#endif
++	moveq	r0,#-1
++	beq	.Labrt
++	teq	r2,#0
++#ifdef	__thumb2__
++	itt	eq			@ Thumb2 thing, sanity check in ARM
++#endif
++	moveq	r0,#-1
++	beq	.Labrt
++
++	teq	r1,#128
++	beq	.Lok
++	teq	r1,#192
++	beq	.Lok
++	teq	r1,#256
++#ifdef	__thumb2__
++	itt	ne			@ Thumb2 thing, sanity check in ARM
++#endif
++	movne	r0,#-1
++	bne	.Labrt
++
++.Lok:	stmdb   sp!,{r4-r12,lr}
++	mov	$rounds,r0		@ inp
++	mov	lr,r1			@ bits
++	mov	$key,r2			@ key
++
++#ifdef	__APPLE__
++	adr	$tbl,AES_Te+1024				@ Te4
++#else
++	sub	$tbl,r3,#_armv4_AES_set_encrypt_key-AES_Te-1024	@ Te4
++#endif
++
++#if __ARM_ARCH__<7
++	ldrb	$s0,[$rounds,#3]	@ load input data in endian-neutral
++	ldrb	$t1,[$rounds,#2]	@ manner...
++	ldrb	$t2,[$rounds,#1]
++	ldrb	$t3,[$rounds,#0]
++	orr	$s0,$s0,$t1,lsl#8
++	ldrb	$s1,[$rounds,#7]
++	orr	$s0,$s0,$t2,lsl#16
++	ldrb	$t1,[$rounds,#6]
++	orr	$s0,$s0,$t3,lsl#24
++	ldrb	$t2,[$rounds,#5]
++	ldrb	$t3,[$rounds,#4]
++	orr	$s1,$s1,$t1,lsl#8
++	ldrb	$s2,[$rounds,#11]
++	orr	$s1,$s1,$t2,lsl#16
++	ldrb	$t1,[$rounds,#10]
++	orr	$s1,$s1,$t3,lsl#24
++	ldrb	$t2,[$rounds,#9]
++	ldrb	$t3,[$rounds,#8]
++	orr	$s2,$s2,$t1,lsl#8
++	ldrb	$s3,[$rounds,#15]
++	orr	$s2,$s2,$t2,lsl#16
++	ldrb	$t1,[$rounds,#14]
++	orr	$s2,$s2,$t3,lsl#24
++	ldrb	$t2,[$rounds,#13]
++	ldrb	$t3,[$rounds,#12]
++	orr	$s3,$s3,$t1,lsl#8
++	str	$s0,[$key],#16
++	orr	$s3,$s3,$t2,lsl#16
++	str	$s1,[$key,#-12]
++	orr	$s3,$s3,$t3,lsl#24
++	str	$s2,[$key,#-8]
++	str	$s3,[$key,#-4]
++#else
++	ldr	$s0,[$rounds,#0]
++	ldr	$s1,[$rounds,#4]
++	ldr	$s2,[$rounds,#8]
++	ldr	$s3,[$rounds,#12]
++#ifdef __ARMEL__
++	rev	$s0,$s0
++	rev	$s1,$s1
++	rev	$s2,$s2
++	rev	$s3,$s3
++#endif
++	str	$s0,[$key],#16
++	str	$s1,[$key,#-12]
++	str	$s2,[$key,#-8]
++	str	$s3,[$key,#-4]
++#endif
++
++	teq	lr,#128
++	bne	.Lnot128
++	mov	$rounds,#10
++	str	$rounds,[$key,#240-16]
++	add	$t3,$tbl,#256			@ rcon
++	mov	lr,#255
++
++.L128_loop:
++	and	$t2,lr,$s3,lsr#24
++	and	$i1,lr,$s3,lsr#16
++	ldrb	$t2,[$tbl,$t2]
++	and	$i2,lr,$s3,lsr#8
++	ldrb	$i1,[$tbl,$i1]
++	and	$i3,lr,$s3
++	ldrb	$i2,[$tbl,$i2]
++	orr	$t2,$t2,$i1,lsl#24
++	ldrb	$i3,[$tbl,$i3]
++	orr	$t2,$t2,$i2,lsl#16
++	ldr	$t1,[$t3],#4			@ rcon[i++]
++	orr	$t2,$t2,$i3,lsl#8
++	eor	$t2,$t2,$t1
++	eor	$s0,$s0,$t2			@ rk[4]=rk[0]^...
++	eor	$s1,$s1,$s0			@ rk[5]=rk[1]^rk[4]
++	str	$s0,[$key],#16
++	eor	$s2,$s2,$s1			@ rk[6]=rk[2]^rk[5]
++	str	$s1,[$key,#-12]
++	eor	$s3,$s3,$s2			@ rk[7]=rk[3]^rk[6]
++	str	$s2,[$key,#-8]
++	subs	$rounds,$rounds,#1
++	str	$s3,[$key,#-4]
++	bne	.L128_loop
++	sub	r2,$key,#176
++	b	.Ldone
++
++.Lnot128:
++#if __ARM_ARCH__<7
++	ldrb	$i2,[$rounds,#19]
++	ldrb	$t1,[$rounds,#18]
++	ldrb	$t2,[$rounds,#17]
++	ldrb	$t3,[$rounds,#16]
++	orr	$i2,$i2,$t1,lsl#8
++	ldrb	$i3,[$rounds,#23]
++	orr	$i2,$i2,$t2,lsl#16
++	ldrb	$t1,[$rounds,#22]
++	orr	$i2,$i2,$t3,lsl#24
++	ldrb	$t2,[$rounds,#21]
++	ldrb	$t3,[$rounds,#20]
++	orr	$i3,$i3,$t1,lsl#8
++	orr	$i3,$i3,$t2,lsl#16
++	str	$i2,[$key],#8
++	orr	$i3,$i3,$t3,lsl#24
++	str	$i3,[$key,#-4]
++#else
++	ldr	$i2,[$rounds,#16]
++	ldr	$i3,[$rounds,#20]
++#ifdef __ARMEL__
++	rev	$i2,$i2
++	rev	$i3,$i3
++#endif
++	str	$i2,[$key],#8
++	str	$i3,[$key,#-4]
++#endif
++
++	teq	lr,#192
++	bne	.Lnot192
++	mov	$rounds,#12
++	str	$rounds,[$key,#240-24]
++	add	$t3,$tbl,#256			@ rcon
++	mov	lr,#255
++	mov	$rounds,#8
++
++.L192_loop:
++	and	$t2,lr,$i3,lsr#24
++	and	$i1,lr,$i3,lsr#16
++	ldrb	$t2,[$tbl,$t2]
++	and	$i2,lr,$i3,lsr#8
++	ldrb	$i1,[$tbl,$i1]
++	and	$i3,lr,$i3
++	ldrb	$i2,[$tbl,$i2]
++	orr	$t2,$t2,$i1,lsl#24
++	ldrb	$i3,[$tbl,$i3]
++	orr	$t2,$t2,$i2,lsl#16
++	ldr	$t1,[$t3],#4			@ rcon[i++]
++	orr	$t2,$t2,$i3,lsl#8
++	eor	$i3,$t2,$t1
++	eor	$s0,$s0,$i3			@ rk[6]=rk[0]^...
++	eor	$s1,$s1,$s0			@ rk[7]=rk[1]^rk[6]
++	str	$s0,[$key],#24
++	eor	$s2,$s2,$s1			@ rk[8]=rk[2]^rk[7]
++	str	$s1,[$key,#-20]
++	eor	$s3,$s3,$s2			@ rk[9]=rk[3]^rk[8]
++	str	$s2,[$key,#-16]
++	subs	$rounds,$rounds,#1
++	str	$s3,[$key,#-12]
++#ifdef	__thumb2__
++	itt	eq				@ Thumb2 thing, sanity check in ARM
++#endif
++	subeq	r2,$key,#216
++	beq	.Ldone
++
++	ldr	$i1,[$key,#-32]
++	ldr	$i2,[$key,#-28]
++	eor	$i1,$i1,$s3			@ rk[10]=rk[4]^rk[9]
++	eor	$i3,$i2,$i1			@ rk[11]=rk[5]^rk[10]
++	str	$i1,[$key,#-8]
++	str	$i3,[$key,#-4]
++	b	.L192_loop
++
++.Lnot192:
++#if __ARM_ARCH__<7
++	ldrb	$i2,[$rounds,#27]
++	ldrb	$t1,[$rounds,#26]
++	ldrb	$t2,[$rounds,#25]
++	ldrb	$t3,[$rounds,#24]
++	orr	$i2,$i2,$t1,lsl#8
++	ldrb	$i3,[$rounds,#31]
++	orr	$i2,$i2,$t2,lsl#16
++	ldrb	$t1,[$rounds,#30]
++	orr	$i2,$i2,$t3,lsl#24
++	ldrb	$t2,[$rounds,#29]
++	ldrb	$t3,[$rounds,#28]
++	orr	$i3,$i3,$t1,lsl#8
++	orr	$i3,$i3,$t2,lsl#16
++	str	$i2,[$key],#8
++	orr	$i3,$i3,$t3,lsl#24
++	str	$i3,[$key,#-4]
++#else
++	ldr	$i2,[$rounds,#24]
++	ldr	$i3,[$rounds,#28]
++#ifdef __ARMEL__
++	rev	$i2,$i2
++	rev	$i3,$i3
++#endif
++	str	$i2,[$key],#8
++	str	$i3,[$key,#-4]
++#endif
++
++	mov	$rounds,#14
++	str	$rounds,[$key,#240-32]
++	add	$t3,$tbl,#256			@ rcon
++	mov	lr,#255
++	mov	$rounds,#7
++
++.L256_loop:
++	and	$t2,lr,$i3,lsr#24
++	and	$i1,lr,$i3,lsr#16
++	ldrb	$t2,[$tbl,$t2]
++	and	$i2,lr,$i3,lsr#8
++	ldrb	$i1,[$tbl,$i1]
++	and	$i3,lr,$i3
++	ldrb	$i2,[$tbl,$i2]
++	orr	$t2,$t2,$i1,lsl#24
++	ldrb	$i3,[$tbl,$i3]
++	orr	$t2,$t2,$i2,lsl#16
++	ldr	$t1,[$t3],#4			@ rcon[i++]
++	orr	$t2,$t2,$i3,lsl#8
++	eor	$i3,$t2,$t1
++	eor	$s0,$s0,$i3			@ rk[8]=rk[0]^...
++	eor	$s1,$s1,$s0			@ rk[9]=rk[1]^rk[8]
++	str	$s0,[$key],#32
++	eor	$s2,$s2,$s1			@ rk[10]=rk[2]^rk[9]
++	str	$s1,[$key,#-28]
++	eor	$s3,$s3,$s2			@ rk[11]=rk[3]^rk[10]
++	str	$s2,[$key,#-24]
++	subs	$rounds,$rounds,#1
++	str	$s3,[$key,#-20]
++#ifdef	__thumb2__
++	itt	eq				@ Thumb2 thing, sanity check in ARM
++#endif
++	subeq	r2,$key,#256
++	beq	.Ldone
++
++	and	$t2,lr,$s3
++	and	$i1,lr,$s3,lsr#8
++	ldrb	$t2,[$tbl,$t2]
++	and	$i2,lr,$s3,lsr#16
++	ldrb	$i1,[$tbl,$i1]
++	and	$i3,lr,$s3,lsr#24
++	ldrb	$i2,[$tbl,$i2]
++	orr	$t2,$t2,$i1,lsl#8
++	ldrb	$i3,[$tbl,$i3]
++	orr	$t2,$t2,$i2,lsl#16
++	ldr	$t1,[$key,#-48]
++	orr	$t2,$t2,$i3,lsl#24
++
++	ldr	$i1,[$key,#-44]
++	ldr	$i2,[$key,#-40]
++	eor	$t1,$t1,$t2			@ rk[12]=rk[4]^...
++	ldr	$i3,[$key,#-36]
++	eor	$i1,$i1,$t1			@ rk[13]=rk[5]^rk[12]
++	str	$t1,[$key,#-16]
++	eor	$i2,$i2,$i1			@ rk[14]=rk[6]^rk[13]
++	str	$i1,[$key,#-12]
++	eor	$i3,$i3,$i2			@ rk[15]=rk[7]^rk[14]
++	str	$i2,[$key,#-8]
++	str	$i3,[$key,#-4]
++	b	.L256_loop
++
++.align	2
++.Ldone:	mov	r0,#0
++	ldmia   sp!,{r4-r12,lr}
++.Labrt:
++#if __ARM_ARCH__>=5
++	ret				@ bx lr
++#else
++	tst	lr,#1
++	moveq	pc,lr			@ be binary compatible with V4, yet
++	bx	lr			@ interoperable with Thumb ISA:-)
++#endif
++.size	AES_set_encrypt_key,.-AES_set_encrypt_key
++
++.global AES_set_decrypt_key
++.type   AES_set_decrypt_key,%function
++.align	5
++AES_set_decrypt_key:
++	str	lr,[sp,#-4]!            @ push lr
++	bl	_armv4_AES_set_encrypt_key
++	teq	r0,#0
++	ldr	lr,[sp],#4              @ pop lr
++	bne	.Labrt
++
++	mov	r0,r2			@ AES_set_encrypt_key preserves r2,
++	mov	r1,r2			@ which is AES_KEY *key
++	b	_armv4_AES_set_enc2dec_key
++.size	AES_set_decrypt_key,.-AES_set_decrypt_key
++
++@ void AES_set_enc2dec_key(const AES_KEY *inp,AES_KEY *out)
++.global	AES_set_enc2dec_key
++.type	AES_set_enc2dec_key,%function
++.align	5
++AES_set_enc2dec_key:
++_armv4_AES_set_enc2dec_key:
++	stmdb   sp!,{r4-r12,lr}
++
++	ldr	$rounds,[r0,#240]
++	mov	$i1,r0			@ input
++	add	$i2,r0,$rounds,lsl#4
++	mov	$key,r1			@ output
++	add	$tbl,r1,$rounds,lsl#4
++	str	$rounds,[r1,#240]
++
++.Linv:	ldr	$s0,[$i1],#16
++	ldr	$s1,[$i1,#-12]
++	ldr	$s2,[$i1,#-8]
++	ldr	$s3,[$i1,#-4]
++	ldr	$t1,[$i2],#-16
++	ldr	$t2,[$i2,#16+4]
++	ldr	$t3,[$i2,#16+8]
++	ldr	$i3,[$i2,#16+12]
++	str	$s0,[$tbl],#-16
++	str	$s1,[$tbl,#16+4]
++	str	$s2,[$tbl,#16+8]
++	str	$s3,[$tbl,#16+12]
++	str	$t1,[$key],#16
++	str	$t2,[$key,#-12]
++	str	$t3,[$key,#-8]
++	str	$i3,[$key,#-4]
++	teq	$i1,$i2
++	bne	.Linv
++
++	ldr	$s0,[$i1]
++	ldr	$s1,[$i1,#4]
++	ldr	$s2,[$i1,#8]
++	ldr	$s3,[$i1,#12]
++	str	$s0,[$key]
++	str	$s1,[$key,#4]
++	str	$s2,[$key,#8]
++	str	$s3,[$key,#12]
++	sub	$key,$key,$rounds,lsl#3
++___
++$mask80=$i1;
++$mask1b=$i2;
++$mask7f=$i3;
++$code.=<<___;
++	ldr	$s0,[$key,#16]!		@ prefetch tp1
++	mov	$mask80,#0x80
++	mov	$mask1b,#0x1b
++	orr	$mask80,$mask80,#0x8000
++	orr	$mask1b,$mask1b,#0x1b00
++	orr	$mask80,$mask80,$mask80,lsl#16
++	orr	$mask1b,$mask1b,$mask1b,lsl#16
++	sub	$rounds,$rounds,#1
++	mvn	$mask7f,$mask80
++	mov	$rounds,$rounds,lsl#2	@ (rounds-1)*4
++
++.Lmix:	and	$t1,$s0,$mask80
++	and	$s1,$s0,$mask7f
++	sub	$t1,$t1,$t1,lsr#7
++	and	$t1,$t1,$mask1b
++	eor	$s1,$t1,$s1,lsl#1	@ tp2
++
++	and	$t1,$s1,$mask80
++	and	$s2,$s1,$mask7f
++	sub	$t1,$t1,$t1,lsr#7
++	and	$t1,$t1,$mask1b
++	eor	$s2,$t1,$s2,lsl#1	@ tp4
++
++	and	$t1,$s2,$mask80
++	and	$s3,$s2,$mask7f
++	sub	$t1,$t1,$t1,lsr#7
++	and	$t1,$t1,$mask1b
++	eor	$s3,$t1,$s3,lsl#1	@ tp8
++
++	eor	$t1,$s1,$s2
++	eor	$t2,$s0,$s3		@ tp9
++	eor	$t1,$t1,$s3		@ tpe
++	eor	$t1,$t1,$s1,ror#24
++	eor	$t1,$t1,$t2,ror#24	@ ^= ROTATE(tpb=tp9^tp2,8)
++	eor	$t1,$t1,$s2,ror#16
++	eor	$t1,$t1,$t2,ror#16	@ ^= ROTATE(tpd=tp9^tp4,16)
++	eor	$t1,$t1,$t2,ror#8	@ ^= ROTATE(tp9,24)
++
++	ldr	$s0,[$key,#4]		@ prefetch tp1
++	str	$t1,[$key],#4
++	subs	$rounds,$rounds,#1
++	bne	.Lmix
++
++	mov	r0,#0
++#if __ARM_ARCH__>=5
++	ldmia	sp!,{r4-r12,pc}
++#else
++	ldmia   sp!,{r4-r12,lr}
++	tst	lr,#1
++	moveq	pc,lr			@ be binary compatible with V4, yet
++	bx	lr			@ interoperable with Thumb ISA:-)
++#endif
++.size	AES_set_enc2dec_key,.-AES_set_enc2dec_key
++
++.type	AES_Td,%object
++.align	5
++AES_Td:
++.word	0x51f4a750, 0x7e416553, 0x1a17a4c3, 0x3a275e96
++.word	0x3bab6bcb, 0x1f9d45f1, 0xacfa58ab, 0x4be30393
++.word	0x2030fa55, 0xad766df6, 0x88cc7691, 0xf5024c25
++.word	0x4fe5d7fc, 0xc52acbd7, 0x26354480, 0xb562a38f
++.word	0xdeb15a49, 0x25ba1b67, 0x45ea0e98, 0x5dfec0e1
++.word	0xc32f7502, 0x814cf012, 0x8d4697a3, 0x6bd3f9c6
++.word	0x038f5fe7, 0x15929c95, 0xbf6d7aeb, 0x955259da
++.word	0xd4be832d, 0x587421d3, 0x49e06929, 0x8ec9c844
++.word	0x75c2896a, 0xf48e7978, 0x99583e6b, 0x27b971dd
++.word	0xbee14fb6, 0xf088ad17, 0xc920ac66, 0x7dce3ab4
++.word	0x63df4a18, 0xe51a3182, 0x97513360, 0x62537f45
++.word	0xb16477e0, 0xbb6bae84, 0xfe81a01c, 0xf9082b94
++.word	0x70486858, 0x8f45fd19, 0x94de6c87, 0x527bf8b7
++.word	0xab73d323, 0x724b02e2, 0xe31f8f57, 0x6655ab2a
++.word	0xb2eb2807, 0x2fb5c203, 0x86c57b9a, 0xd33708a5
++.word	0x302887f2, 0x23bfa5b2, 0x02036aba, 0xed16825c
++.word	0x8acf1c2b, 0xa779b492, 0xf307f2f0, 0x4e69e2a1
++.word	0x65daf4cd, 0x0605bed5, 0xd134621f, 0xc4a6fe8a
++.word	0x342e539d, 0xa2f355a0, 0x058ae132, 0xa4f6eb75
++.word	0x0b83ec39, 0x4060efaa, 0x5e719f06, 0xbd6e1051
++.word	0x3e218af9, 0x96dd063d, 0xdd3e05ae, 0x4de6bd46
++.word	0x91548db5, 0x71c45d05, 0x0406d46f, 0x605015ff
++.word	0x1998fb24, 0xd6bde997, 0x894043cc, 0x67d99e77
++.word	0xb0e842bd, 0x07898b88, 0xe7195b38, 0x79c8eedb
++.word	0xa17c0a47, 0x7c420fe9, 0xf8841ec9, 0x00000000
++.word	0x09808683, 0x322bed48, 0x1e1170ac, 0x6c5a724e
++.word	0xfd0efffb, 0x0f853856, 0x3daed51e, 0x362d3927
++.word	0x0a0fd964, 0x685ca621, 0x9b5b54d1, 0x24362e3a
++.word	0x0c0a67b1, 0x9357e70f, 0xb4ee96d2, 0x1b9b919e
++.word	0x80c0c54f, 0x61dc20a2, 0x5a774b69, 0x1c121a16
++.word	0xe293ba0a, 0xc0a02ae5, 0x3c22e043, 0x121b171d
++.word	0x0e090d0b, 0xf28bc7ad, 0x2db6a8b9, 0x141ea9c8
++.word	0x57f11985, 0xaf75074c, 0xee99ddbb, 0xa37f60fd
++.word	0xf701269f, 0x5c72f5bc, 0x44663bc5, 0x5bfb7e34
++.word	0x8b432976, 0xcb23c6dc, 0xb6edfc68, 0xb8e4f163
++.word	0xd731dcca, 0x42638510, 0x13972240, 0x84c61120
++.word	0x854a247d, 0xd2bb3df8, 0xaef93211, 0xc729a16d
++.word	0x1d9e2f4b, 0xdcb230f3, 0x0d8652ec, 0x77c1e3d0
++.word	0x2bb3166c, 0xa970b999, 0x119448fa, 0x47e96422
++.word	0xa8fc8cc4, 0xa0f03f1a, 0x567d2cd8, 0x223390ef
++.word	0x87494ec7, 0xd938d1c1, 0x8ccaa2fe, 0x98d40b36
++.word	0xa6f581cf, 0xa57ade28, 0xdab78e26, 0x3fadbfa4
++.word	0x2c3a9de4, 0x5078920d, 0x6a5fcc9b, 0x547e4662
++.word	0xf68d13c2, 0x90d8b8e8, 0x2e39f75e, 0x82c3aff5
++.word	0x9f5d80be, 0x69d0937c, 0x6fd52da9, 0xcf2512b3
++.word	0xc8ac993b, 0x10187da7, 0xe89c636e, 0xdb3bbb7b
++.word	0xcd267809, 0x6e5918f4, 0xec9ab701, 0x834f9aa8
++.word	0xe6956e65, 0xaaffe67e, 0x21bccf08, 0xef15e8e6
++.word	0xbae79bd9, 0x4a6f36ce, 0xea9f09d4, 0x29b07cd6
++.word	0x31a4b2af, 0x2a3f2331, 0xc6a59430, 0x35a266c0
++.word	0x744ebc37, 0xfc82caa6, 0xe090d0b0, 0x33a7d815
++.word	0xf104984a, 0x41ecdaf7, 0x7fcd500e, 0x1791f62f
++.word	0x764dd68d, 0x43efb04d, 0xccaa4d54, 0xe49604df
++.word	0x9ed1b5e3, 0x4c6a881b, 0xc12c1fb8, 0x4665517f
++.word	0x9d5eea04, 0x018c355d, 0xfa877473, 0xfb0b412e
++.word	0xb3671d5a, 0x92dbd252, 0xe9105633, 0x6dd64713
++.word	0x9ad7618c, 0x37a10c7a, 0x59f8148e, 0xeb133c89
++.word	0xcea927ee, 0xb761c935, 0xe11ce5ed, 0x7a47b13c
++.word	0x9cd2df59, 0x55f2733f, 0x1814ce79, 0x73c737bf
++.word	0x53f7cdea, 0x5ffdaa5b, 0xdf3d6f14, 0x7844db86
++.word	0xcaaff381, 0xb968c43e, 0x3824342c, 0xc2a3405f
++.word	0x161dc372, 0xbce2250c, 0x283c498b, 0xff0d9541
++.word	0x39a80171, 0x080cb3de, 0xd8b4e49c, 0x6456c190
++.word	0x7bcb8461, 0xd532b670, 0x486c5c74, 0xd0b85742
++@ Td4[256]
++.byte	0x52, 0x09, 0x6a, 0xd5, 0x30, 0x36, 0xa5, 0x38
++.byte	0xbf, 0x40, 0xa3, 0x9e, 0x81, 0xf3, 0xd7, 0xfb
++.byte	0x7c, 0xe3, 0x39, 0x82, 0x9b, 0x2f, 0xff, 0x87
++.byte	0x34, 0x8e, 0x43, 0x44, 0xc4, 0xde, 0xe9, 0xcb
++.byte	0x54, 0x7b, 0x94, 0x32, 0xa6, 0xc2, 0x23, 0x3d
++.byte	0xee, 0x4c, 0x95, 0x0b, 0x42, 0xfa, 0xc3, 0x4e
++.byte	0x08, 0x2e, 0xa1, 0x66, 0x28, 0xd9, 0x24, 0xb2
++.byte	0x76, 0x5b, 0xa2, 0x49, 0x6d, 0x8b, 0xd1, 0x25
++.byte	0x72, 0xf8, 0xf6, 0x64, 0x86, 0x68, 0x98, 0x16
++.byte	0xd4, 0xa4, 0x5c, 0xcc, 0x5d, 0x65, 0xb6, 0x92
++.byte	0x6c, 0x70, 0x48, 0x50, 0xfd, 0xed, 0xb9, 0xda
++.byte	0x5e, 0x15, 0x46, 0x57, 0xa7, 0x8d, 0x9d, 0x84
++.byte	0x90, 0xd8, 0xab, 0x00, 0x8c, 0xbc, 0xd3, 0x0a
++.byte	0xf7, 0xe4, 0x58, 0x05, 0xb8, 0xb3, 0x45, 0x06
++.byte	0xd0, 0x2c, 0x1e, 0x8f, 0xca, 0x3f, 0x0f, 0x02
++.byte	0xc1, 0xaf, 0xbd, 0x03, 0x01, 0x13, 0x8a, 0x6b
++.byte	0x3a, 0x91, 0x11, 0x41, 0x4f, 0x67, 0xdc, 0xea
++.byte	0x97, 0xf2, 0xcf, 0xce, 0xf0, 0xb4, 0xe6, 0x73
++.byte	0x96, 0xac, 0x74, 0x22, 0xe7, 0xad, 0x35, 0x85
++.byte	0xe2, 0xf9, 0x37, 0xe8, 0x1c, 0x75, 0xdf, 0x6e
++.byte	0x47, 0xf1, 0x1a, 0x71, 0x1d, 0x29, 0xc5, 0x89
++.byte	0x6f, 0xb7, 0x62, 0x0e, 0xaa, 0x18, 0xbe, 0x1b
++.byte	0xfc, 0x56, 0x3e, 0x4b, 0xc6, 0xd2, 0x79, 0x20
++.byte	0x9a, 0xdb, 0xc0, 0xfe, 0x78, 0xcd, 0x5a, 0xf4
++.byte	0x1f, 0xdd, 0xa8, 0x33, 0x88, 0x07, 0xc7, 0x31
++.byte	0xb1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xec, 0x5f
++.byte	0x60, 0x51, 0x7f, 0xa9, 0x19, 0xb5, 0x4a, 0x0d
++.byte	0x2d, 0xe5, 0x7a, 0x9f, 0x93, 0xc9, 0x9c, 0xef
++.byte	0xa0, 0xe0, 0x3b, 0x4d, 0xae, 0x2a, 0xf5, 0xb0
++.byte	0xc8, 0xeb, 0xbb, 0x3c, 0x83, 0x53, 0x99, 0x61
++.byte	0x17, 0x2b, 0x04, 0x7e, 0xba, 0x77, 0xd6, 0x26
++.byte	0xe1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0c, 0x7d
++.size	AES_Td,.-AES_Td
++
++@ void AES_decrypt(const unsigned char *in, unsigned char *out,
++@ 		 const AES_KEY *key) {
++.global AES_decrypt
++.type   AES_decrypt,%function
++.align	5
++AES_decrypt:
++#ifndef	__thumb2__
++	sub	r3,pc,#8		@ AES_decrypt
++#else
++	adr	r3,AES_decrypt
++#endif
++	stmdb   sp!,{r1,r4-r12,lr}
++#ifdef	__APPLE__
++	adr	$tbl,AES_Td
++#else
++	sub	$tbl,r3,#AES_decrypt-AES_Td	@ Td
++#endif
++	mov	$rounds,r0		@ inp
++	mov	$key,r2
++#if __ARM_ARCH__<7
++	ldrb	$s0,[$rounds,#3]	@ load input data in endian-neutral
++	ldrb	$t1,[$rounds,#2]	@ manner...
++	ldrb	$t2,[$rounds,#1]
++	ldrb	$t3,[$rounds,#0]
++	orr	$s0,$s0,$t1,lsl#8
++	ldrb	$s1,[$rounds,#7]
++	orr	$s0,$s0,$t2,lsl#16
++	ldrb	$t1,[$rounds,#6]
++	orr	$s0,$s0,$t3,lsl#24
++	ldrb	$t2,[$rounds,#5]
++	ldrb	$t3,[$rounds,#4]
++	orr	$s1,$s1,$t1,lsl#8
++	ldrb	$s2,[$rounds,#11]
++	orr	$s1,$s1,$t2,lsl#16
++	ldrb	$t1,[$rounds,#10]
++	orr	$s1,$s1,$t3,lsl#24
++	ldrb	$t2,[$rounds,#9]
++	ldrb	$t3,[$rounds,#8]
++	orr	$s2,$s2,$t1,lsl#8
++	ldrb	$s3,[$rounds,#15]
++	orr	$s2,$s2,$t2,lsl#16
++	ldrb	$t1,[$rounds,#14]
++	orr	$s2,$s2,$t3,lsl#24
++	ldrb	$t2,[$rounds,#13]
++	ldrb	$t3,[$rounds,#12]
++	orr	$s3,$s3,$t1,lsl#8
++	orr	$s3,$s3,$t2,lsl#16
++	orr	$s3,$s3,$t3,lsl#24
++#else
++	ldr	$s0,[$rounds,#0]
++	ldr	$s1,[$rounds,#4]
++	ldr	$s2,[$rounds,#8]
++	ldr	$s3,[$rounds,#12]
++#ifdef __ARMEL__
++	rev	$s0,$s0
++	rev	$s1,$s1
++	rev	$s2,$s2
++	rev	$s3,$s3
++#endif
++#endif
++	bl	_armv4_AES_decrypt
++
++	ldr	$rounds,[sp],#4		@ pop out
++#if __ARM_ARCH__>=7
++#ifdef __ARMEL__
++	rev	$s0,$s0
++	rev	$s1,$s1
++	rev	$s2,$s2
++	rev	$s3,$s3
++#endif
++	str	$s0,[$rounds,#0]
++	str	$s1,[$rounds,#4]
++	str	$s2,[$rounds,#8]
++	str	$s3,[$rounds,#12]
++#else
++	mov	$t1,$s0,lsr#24		@ write output in endian-neutral
++	mov	$t2,$s0,lsr#16		@ manner...
++	mov	$t3,$s0,lsr#8
++	strb	$t1,[$rounds,#0]
++	strb	$t2,[$rounds,#1]
++	mov	$t1,$s1,lsr#24
++	strb	$t3,[$rounds,#2]
++	mov	$t2,$s1,lsr#16
++	strb	$s0,[$rounds,#3]
++	mov	$t3,$s1,lsr#8
++	strb	$t1,[$rounds,#4]
++	strb	$t2,[$rounds,#5]
++	mov	$t1,$s2,lsr#24
++	strb	$t3,[$rounds,#6]
++	mov	$t2,$s2,lsr#16
++	strb	$s1,[$rounds,#7]
++	mov	$t3,$s2,lsr#8
++	strb	$t1,[$rounds,#8]
++	strb	$t2,[$rounds,#9]
++	mov	$t1,$s3,lsr#24
++	strb	$t3,[$rounds,#10]
++	mov	$t2,$s3,lsr#16
++	strb	$s2,[$rounds,#11]
++	mov	$t3,$s3,lsr#8
++	strb	$t1,[$rounds,#12]
++	strb	$t2,[$rounds,#13]
++	strb	$t3,[$rounds,#14]
++	strb	$s3,[$rounds,#15]
++#endif
++#if __ARM_ARCH__>=5
++	ldmia	sp!,{r4-r12,pc}
++#else
++	ldmia   sp!,{r4-r12,lr}
++	tst	lr,#1
++	moveq	pc,lr			@ be binary compatible with V4, yet
++	bx	lr			@ interoperable with Thumb ISA:-)
++#endif
++.size	AES_decrypt,.-AES_decrypt
++
++.type   _armv4_AES_decrypt,%function
++.align	2
++_armv4_AES_decrypt:
++	str	lr,[sp,#-4]!		@ push lr
++	ldmia	$key!,{$t1-$i1}
++	eor	$s0,$s0,$t1
++	ldr	$rounds,[$key,#240-16]
++	eor	$s1,$s1,$t2
++	eor	$s2,$s2,$t3
++	eor	$s3,$s3,$i1
++	sub	$rounds,$rounds,#1
++	mov	lr,#255
++
++	and	$i1,lr,$s0,lsr#16
++	and	$i2,lr,$s0,lsr#8
++	and	$i3,lr,$s0
++	mov	$s0,$s0,lsr#24
++.Ldec_loop:
++	ldr	$t1,[$tbl,$i1,lsl#2]	@ Td1[s0>>16]
++	and	$i1,lr,$s1		@ i0
++	ldr	$t2,[$tbl,$i2,lsl#2]	@ Td2[s0>>8]
++	and	$i2,lr,$s1,lsr#16
++	ldr	$t3,[$tbl,$i3,lsl#2]	@ Td3[s0>>0]
++	and	$i3,lr,$s1,lsr#8
++	ldr	$s0,[$tbl,$s0,lsl#2]	@ Td0[s0>>24]
++	mov	$s1,$s1,lsr#24
++
++	ldr	$i1,[$tbl,$i1,lsl#2]	@ Td3[s1>>0]
++	ldr	$i2,[$tbl,$i2,lsl#2]	@ Td1[s1>>16]
++	ldr	$i3,[$tbl,$i3,lsl#2]	@ Td2[s1>>8]
++	eor	$s0,$s0,$i1,ror#24
++	ldr	$s1,[$tbl,$s1,lsl#2]	@ Td0[s1>>24]
++	and	$i1,lr,$s2,lsr#8	@ i0
++	eor	$t2,$i2,$t2,ror#8
++	and	$i2,lr,$s2		@ i1
++	eor	$t3,$i3,$t3,ror#8
++	and	$i3,lr,$s2,lsr#16
++	ldr	$i1,[$tbl,$i1,lsl#2]	@ Td2[s2>>8]
++	eor	$s1,$s1,$t1,ror#8
++	ldr	$i2,[$tbl,$i2,lsl#2]	@ Td3[s2>>0]
++	mov	$s2,$s2,lsr#24
++
++	ldr	$i3,[$tbl,$i3,lsl#2]	@ Td1[s2>>16]
++	eor	$s0,$s0,$i1,ror#16
++	ldr	$s2,[$tbl,$s2,lsl#2]	@ Td0[s2>>24]
++	and	$i1,lr,$s3,lsr#16	@ i0
++	eor	$s1,$s1,$i2,ror#24
++	and	$i2,lr,$s3,lsr#8	@ i1
++	eor	$t3,$i3,$t3,ror#8
++	and	$i3,lr,$s3		@ i2
++	ldr	$i1,[$tbl,$i1,lsl#2]	@ Td1[s3>>16]
++	eor	$s2,$s2,$t2,ror#8
++	ldr	$i2,[$tbl,$i2,lsl#2]	@ Td2[s3>>8]
++	mov	$s3,$s3,lsr#24
++
++	ldr	$i3,[$tbl,$i3,lsl#2]	@ Td3[s3>>0]
++	eor	$s0,$s0,$i1,ror#8
++	ldr	$i1,[$key],#16
++	eor	$s1,$s1,$i2,ror#16
++	ldr	$s3,[$tbl,$s3,lsl#2]	@ Td0[s3>>24]
++	eor	$s2,$s2,$i3,ror#24
++
++	ldr	$t1,[$key,#-12]
++	eor	$s0,$s0,$i1
++	ldr	$t2,[$key,#-8]
++	eor	$s3,$s3,$t3,ror#8
++	ldr	$t3,[$key,#-4]
++	and	$i1,lr,$s0,lsr#16
++	eor	$s1,$s1,$t1
++	and	$i2,lr,$s0,lsr#8
++	eor	$s2,$s2,$t2
++	and	$i3,lr,$s0
++	eor	$s3,$s3,$t3
++	mov	$s0,$s0,lsr#24
++
++	subs	$rounds,$rounds,#1
++	bne	.Ldec_loop
++
++	add	$tbl,$tbl,#1024
++
++	ldr	$t2,[$tbl,#0]		@ prefetch Td4
++	ldr	$t3,[$tbl,#32]
++	ldr	$t1,[$tbl,#64]
++	ldr	$t2,[$tbl,#96]
++	ldr	$t3,[$tbl,#128]
++	ldr	$t1,[$tbl,#160]
++	ldr	$t2,[$tbl,#192]
++	ldr	$t3,[$tbl,#224]
++
++	ldrb	$s0,[$tbl,$s0]		@ Td4[s0>>24]
++	ldrb	$t1,[$tbl,$i1]		@ Td4[s0>>16]
++	and	$i1,lr,$s1		@ i0
++	ldrb	$t2,[$tbl,$i2]		@ Td4[s0>>8]
++	and	$i2,lr,$s1,lsr#16
++	ldrb	$t3,[$tbl,$i3]		@ Td4[s0>>0]
++	and	$i3,lr,$s1,lsr#8
++
++	add	$s1,$tbl,$s1,lsr#24
++	ldrb	$i1,[$tbl,$i1]		@ Td4[s1>>0]
++	ldrb	$s1,[$s1]		@ Td4[s1>>24]
++	ldrb	$i2,[$tbl,$i2]		@ Td4[s1>>16]
++	eor	$s0,$i1,$s0,lsl#24
++	ldrb	$i3,[$tbl,$i3]		@ Td4[s1>>8]
++	eor	$s1,$t1,$s1,lsl#8
++	and	$i1,lr,$s2,lsr#8	@ i0
++	eor	$t2,$t2,$i2,lsl#8
++	and	$i2,lr,$s2		@ i1
++	ldrb	$i1,[$tbl,$i1]		@ Td4[s2>>8]
++	eor	$t3,$t3,$i3,lsl#8
++	ldrb	$i2,[$tbl,$i2]		@ Td4[s2>>0]
++	and	$i3,lr,$s2,lsr#16
++
++	add	$s2,$tbl,$s2,lsr#24
++	ldrb	$s2,[$s2]		@ Td4[s2>>24]
++	eor	$s0,$s0,$i1,lsl#8
++	ldrb	$i3,[$tbl,$i3]		@ Td4[s2>>16]
++	eor	$s1,$i2,$s1,lsl#16
++	and	$i1,lr,$s3,lsr#16	@ i0
++	eor	$s2,$t2,$s2,lsl#16
++	and	$i2,lr,$s3,lsr#8	@ i1
++	ldrb	$i1,[$tbl,$i1]		@ Td4[s3>>16]
++	eor	$t3,$t3,$i3,lsl#16
++	ldrb	$i2,[$tbl,$i2]		@ Td4[s3>>8]
++	and	$i3,lr,$s3		@ i2
++
++	add	$s3,$tbl,$s3,lsr#24
++	ldrb	$i3,[$tbl,$i3]		@ Td4[s3>>0]
++	ldrb	$s3,[$s3]		@ Td4[s3>>24]
++	eor	$s0,$s0,$i1,lsl#16
++	ldr	$i1,[$key,#0]
++	eor	$s1,$s1,$i2,lsl#8
++	ldr	$t1,[$key,#4]
++	eor	$s2,$i3,$s2,lsl#8
++	ldr	$t2,[$key,#8]
++	eor	$s3,$t3,$s3,lsl#24
++	ldr	$t3,[$key,#12]
++
++	eor	$s0,$s0,$i1
++	eor	$s1,$s1,$t1
++	eor	$s2,$s2,$t2
++	eor	$s3,$s3,$t3
++
++	sub	$tbl,$tbl,#1024
++	ldr	pc,[sp],#4		@ pop and return
++.size	_armv4_AES_decrypt,.-_armv4_AES_decrypt
++.asciz	"AES for ARMv4, CRYPTOGAMS by "
++.align	2
++___
++
++$code =~ s/\bbx\s+lr\b/.word\t0xe12fff1e/gm;	# make it possible to compile with -march=armv4
++$code =~ s/\bret\b/bx\tlr/gm;
++
++open SELF,$0;
++while() {
++	next if (/^#!/);
++	last if (!s/^#/@/ and !/^$/);
++	print;
++}
++close SELF;
++
++print $code;
++close STDOUT;	# enforce flush
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/aes/asm/aes-c64xplus.pl b/CryptoPkg/Library/OpensslLib/openssl/crypto/aes/asm/aes-c64xplus.pl
+new file mode 100644
+index 0000000..19d2cc1
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/aes/asm/aes-c64xplus.pl
+@@ -0,0 +1,1382 @@
++#! /usr/bin/env perl
++# Copyright 2012-2016 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
++# in the file LICENSE in the source distribution or at
++# https://www.openssl.org/source/license.html
++
++#
++# ====================================================================
++# Written by Andy Polyakov  for the OpenSSL
++# project. The module is, however, dual licensed under OpenSSL and
++# CRYPTOGAMS licenses depending on where you obtain it. For further
++# details see http://www.openssl.org/~appro/cryptogams/.
++# ====================================================================
++#
++# [Endian-neutral] AES for C64x+.
++#
++# Even though SPLOOPs are scheduled for 13 cycles, and thus expected
++# performance is ~8.5 cycles per byte processed with 128-bit key,
++# measured performance turned to be ~10 cycles per byte. Discrepancy
++# must be caused by limitations of L1D memory banking(*), see SPRU871
++# TI publication for further details. If any consolation it's still
++# ~20% faster than TI's linear assembly module anyway... Compared to
++# aes_core.c compiled with cl6x 6.0 with -mv6400+ -o2 options this
++# code is 3.75x faster and almost 3x smaller (tables included).
++#
++# (*)	This means that there might be subtle correlation between data
++#	and timing and one can wonder if it can be ... attacked:-(
++#	On the other hand this also means that *if* one chooses to
++#	implement *4* T-tables variant [instead of 1 T-table as in
++#	this implementation, or in addition to], then one ought to
++#	*interleave* them. Even though it complicates addressing,
++#	references to interleaved tables would be guaranteed not to
++#	clash. I reckon that it should be possible to break 8 cycles
++#	per byte "barrier," i.e. improve by ~20%, naturally at the
++#	cost of 8x increased pressure on L1D. 8x because you'd have
++#	to interleave both Te and Td tables...
++
++while (($output=shift) && ($output!~/\w[\w\-]*\.\w+$/)) {}
++open STDOUT,">$output";
++
++($TEA,$TEB)=("A5","B5");
++($KPA,$KPB)=("A3","B1");
++@K=("A6","B6","A7","B7");
++@s=("A8","B8","A9","B9");
++@Te0=@Td0=("A16","B16","A17","B17");
++@Te1=@Td1=("A18","B18","A19","B19");
++@Te2=@Td2=("A20","B20","A21","B21");
++@Te3=@Td3=("A22","B22","A23","B23");
++
++$code=<<___;
++	.text
++
++	.if	.ASSEMBLER_VERSION<7000000
++	.asg	0,__TI_EABI__
++	.endif
++	.if	__TI_EABI__
++	.nocmp
++	.asg	AES_encrypt,_AES_encrypt
++	.asg	AES_decrypt,_AES_decrypt
++	.asg	AES_set_encrypt_key,_AES_set_encrypt_key
++	.asg	AES_set_decrypt_key,_AES_set_decrypt_key
++	.asg	AES_ctr32_encrypt,_AES_ctr32_encrypt
++	.endif
++
++	.asg	B3,RA
++	.asg	A4,INP
++	.asg	B4,OUT
++	.asg	A6,KEY
++	.asg	A4,RET
++	.asg	B15,SP
++
++	.eval	24,EXT0
++	.eval	16,EXT1
++	.eval	8,EXT2
++	.eval	0,EXT3
++	.eval	8,TBL1
++	.eval	16,TBL2
++	.eval	24,TBL3
++
++	.if	.BIG_ENDIAN
++	.eval	24-EXT0,EXT0
++	.eval	24-EXT1,EXT1
++	.eval	24-EXT2,EXT2
++	.eval	24-EXT3,EXT3
++	.eval	32-TBL1,TBL1
++	.eval	32-TBL2,TBL2
++	.eval	32-TBL3,TBL3
++	.endif
++
++	.global	_AES_encrypt
++_AES_encrypt:
++	.asmfunc
++	MVK	1,B2
++__encrypt:
++	.if	__TI_EABI__
++   [B2]	LDNDW	*INP++,A9:A8			; load input
++||	MVKL	\$PCR_OFFSET(AES_Te,__encrypt),$TEA
++||	ADDKPC	__encrypt,B0
++   [B2]	LDNDW	*INP++,B9:B8
++||	MVKH	\$PCR_OFFSET(AES_Te,__encrypt),$TEA
++||	ADD	0,KEY,$KPA
++||	ADD	4,KEY,$KPB
++	.else
++   [B2]	LDNDW	*INP++,A9:A8			; load input
++||	MVKL	(AES_Te-__encrypt),$TEA
++||	ADDKPC	__encrypt,B0
++   [B2]	LDNDW	*INP++,B9:B8
++||	MVKH	(AES_Te-__encrypt),$TEA
++||	ADD	0,KEY,$KPA
++||	ADD	4,KEY,$KPB
++	.endif
++	LDW	*$KPA++[2],$Te0[0]		; zero round key
++||	LDW	*$KPB++[2],$Te0[1]
++||	MVK	60,A0
++||	ADD	B0,$TEA,$TEA			; AES_Te
++	LDW	*KEY[A0],B0			; rounds
++||	MVK	1024,A0				; sizeof(AES_Te)
++	LDW	*$KPA++[2],$Te0[2]
++||	LDW	*$KPB++[2],$Te0[3]
++||	MV	$TEA,$TEB
++	NOP
++	.if	.BIG_ENDIAN
++	MV	A9,$s[0]
++||	MV	A8,$s[1]
++||	MV	B9,$s[2]
++||	MV	B8,$s[3]
++	.else
++	MV	A8,$s[0]
++||	MV	A9,$s[1]
++||	MV	B8,$s[2]
++||	MV	B9,$s[3]
++	.endif
++	XOR	$Te0[0],$s[0],$s[0]
++||	XOR	$Te0[1],$s[1],$s[1]
++||	LDW	*$KPA++[2],$K[0]		; 1st round key
++||	LDW	*$KPB++[2],$K[1]
++	SUB	B0,2,B0
++
++	SPLOOPD	13
++||	MVC	B0,ILC
++||	LDW	*$KPA++[2],$K[2]
++||	LDW	*$KPB++[2],$K[3]
++;;====================================================================
++	EXTU	$s[1],EXT1,24,$Te1[1]
++||	EXTU	$s[0],EXT3,24,$Te3[0]
++	LDW	*${TEB}[$Te1[1]],$Te1[1]	; Te1[s1>>8],	t0
++||	LDW	*${TEA}[$Te3[0]],$Te3[0]	; Te3[s0>>24],	t1
++||	XOR	$s[2],$Te0[2],$s[2]		; modulo-scheduled
++||	XOR	$s[3],$Te0[3],$s[3]		; modulo-scheduled
++||	EXTU	$s[1],EXT3,24,$Te3[1]
++||	EXTU	$s[0],EXT1,24,$Te1[0]
++	LDW	*${TEB}[$Te3[1]],$Te3[1]	; Te3[s1>>24],	t2
++||	LDW	*${TEA}[$Te1[0]],$Te1[0]	; Te1[s0>>8],	t3
++||	EXTU	$s[2],EXT2,24,$Te2[2]
++||	EXTU	$s[3],EXT2,24,$Te2[3]
++	LDW	*${TEA}[$Te2[2]],$Te2[2]	; Te2[s2>>16],	t0
++||	LDW	*${TEB}[$Te2[3]],$Te2[3]	; Te2[s3>>16],	t1
++||	EXTU	$s[3],EXT3,24,$Te3[3]
++||	EXTU	$s[2],EXT1,24,$Te1[2]
++	LDW	*${TEB}[$Te3[3]],$Te3[3]	; Te3[s3>>24],	t0
++||	LDW	*${TEA}[$Te1[2]],$Te1[2]	; Te1[s2>>8],	t1
++||	EXTU	$s[0],EXT2,24,$Te2[0]
++||	EXTU	$s[1],EXT2,24,$Te2[1]
++	LDW	*${TEA}[$Te2[0]],$Te2[0]	; Te2[s0>>16],	t2
++||	LDW	*${TEB}[$Te2[1]],$Te2[1]	; Te2[s1>>16],	t3
++||	EXTU	$s[3],EXT1,24,$Te1[3]
++||	EXTU	$s[2],EXT3,24,$Te3[2]
++	LDW	*${TEB}[$Te1[3]],$Te1[3]	; Te1[s3>>8],	t2
++||	LDW	*${TEA}[$Te3[2]],$Te3[2]	; Te3[s2>>24],	t3
++||	ROTL	$Te1[1],TBL1,$Te3[0]		; t0
++||	ROTL	$Te3[0],TBL3,$Te1[1]		; t1
++||	EXTU	$s[0],EXT0,24,$Te0[0]
++||	EXTU	$s[1],EXT0,24,$Te0[1]
++	LDW	*${TEA}[$Te0[0]],$Te0[0]	; Te0[s0],	t0
++||	LDW	*${TEB}[$Te0[1]],$Te0[1]	; Te0[s1],	t1
++||	ROTL	$Te3[1],TBL3,$Te1[0]		; t2
++||	ROTL	$Te1[0],TBL1,$Te3[1]		; t3
++||	EXTU	$s[2],EXT0,24,$Te0[2]
++||	EXTU	$s[3],EXT0,24,$Te0[3]
++	LDW	*${TEA}[$Te0[2]],$Te0[2]	; Te0[s2],	t2
++||	LDW	*${TEB}[$Te0[3]],$Te0[3]	; Te0[s3],	t3
++||	ROTL	$Te2[2],TBL2,$Te2[2]		; t0
++||	ROTL	$Te2[3],TBL2,$Te2[3]		; t1
++||	XOR	$K[0],$Te3[0],$s[0]
++||	XOR	$K[1],$Te1[1],$s[1]
++	ROTL	$Te3[3],TBL3,$Te1[2]		; t0
++||	ROTL	$Te1[2],TBL1,$Te3[3]		; t1
++||	XOR	$K[2],$Te1[0],$s[2]
++||	XOR	$K[3],$Te3[1],$s[3]
++||	LDW	*$KPA++[2],$K[0]		; next round key
++||	LDW	*$KPB++[2],$K[1]
++	ROTL	$Te2[0],TBL2,$Te2[0]		; t2
++||	ROTL	$Te2[1],TBL2,$Te2[1]		; t3
++||	XOR	$s[0],$Te2[2],$s[0]
++||	XOR	$s[1],$Te2[3],$s[1]
++||	LDW	*$KPA++[2],$K[2]
++||	LDW	*$KPB++[2],$K[3]
++	ROTL	$Te1[3],TBL1,$Te3[2]		; t2
++||	ROTL	$Te3[2],TBL3,$Te1[3]		; t3
++||	XOR	$s[0],$Te1[2],$s[0]
++||	XOR	$s[1],$Te3[3],$s[1]
++	XOR	$s[2],$Te2[0],$s[2]
++||	XOR	$s[3],$Te2[1],$s[3]
++||	XOR	$s[0],$Te0[0],$s[0]
++||	XOR	$s[1],$Te0[1],$s[1]
++	SPKERNEL
++||	XOR.L	$s[2],$Te3[2],$s[2]
++||	XOR.L	$s[3],$Te1[3],$s[3]
++;;====================================================================
++	ADD.D	${TEA},A0,${TEA}		; point to Te4
++||	ADD.D	${TEB},A0,${TEB}
++||	EXTU	$s[1],EXT1,24,$Te1[1]
++||	EXTU	$s[0],EXT3,24,$Te3[0]
++	LDBU	*${TEB}[$Te1[1]],$Te1[1]	; Te1[s1>>8],	t0
++||	LDBU	*${TEA}[$Te3[0]],$Te3[0]	; Te3[s0>>24],	t1
++||	XOR	$s[2],$Te0[2],$s[2]		; modulo-scheduled
++||	XOR	$s[3],$Te0[3],$s[3]		; modulo-scheduled
++||	EXTU	$s[0],EXT0,24,$Te0[0]
++||	EXTU	$s[1],EXT0,24,$Te0[1]
++	LDBU	*${TEA}[$Te0[0]],$Te0[0]	; Te0[s0],	t0
++||	LDBU	*${TEB}[$Te0[1]],$Te0[1]	; Te0[s1],	t1
++||	EXTU	$s[3],EXT3,24,$Te3[3]
++||	EXTU	$s[2],EXT1,24,$Te1[2]
++	LDBU	*${TEB}[$Te3[3]],$Te3[3]	; Te3[s3>>24],	t0
++||	LDBU	*${TEA}[$Te1[2]],$Te1[2]	; Te1[s2>>8],	t1
++||	EXTU	$s[2],EXT2,24,$Te2[2]
++||	EXTU	$s[3],EXT2,24,$Te2[3]
++	LDBU	*${TEA}[$Te2[2]],$Te2[2]	; Te2[s2>>16],	t0
++||	LDBU	*${TEB}[$Te2[3]],$Te2[3]	; Te2[s3>>16],	t1
++||	EXTU	$s[1],EXT3,24,$Te3[1]
++||	EXTU	$s[0],EXT1,24,$Te1[0]
++	LDBU	*${TEB}[$Te3[1]],$Te3[1]	; Te3[s1>>24],	t2
++||	LDBU	*${TEA}[$Te1[0]],$Te1[0]	; Te1[s0>>8],	t3
++||	EXTU	$s[3],EXT1,24,$Te1[3]
++||	EXTU	$s[2],EXT3,24,$Te3[2]
++	LDBU	*${TEB}[$Te1[3]],$Te1[3]	; Te1[s3>>8],	t2
++||	LDBU	*${TEA}[$Te3[2]],$Te3[2]	; Te3[s2>>24],	t3
++||	EXTU	$s[2],EXT0,24,$Te0[2]
++||	EXTU	$s[3],EXT0,24,$Te0[3]
++	LDBU	*${TEA}[$Te0[2]],$Te0[2]	; Te0[s2],	t2
++||	LDBU	*${TEB}[$Te0[3]],$Te0[3]	; Te0[s3],	t3
++||	EXTU	$s[0],EXT2,24,$Te2[0]
++||	EXTU	$s[1],EXT2,24,$Te2[1]
++	LDBU	*${TEA}[$Te2[0]],$Te2[0]	; Te2[s0>>16],	t2
++||	LDBU	*${TEB}[$Te2[1]],$Te2[1]	; Te2[s1>>16],	t3
++
++	.if	.BIG_ENDIAN
++	PACK2	$Te0[0],$Te1[1],$Te0[0]
++||	PACK2	$Te0[1],$Te1[2],$Te0[1]
++	PACK2	$Te2[2],$Te3[3],$Te2[2]
++||	PACK2	$Te2[3],$Te3[0],$Te2[3]
++	PACKL4	$Te0[0],$Te2[2],$Te0[0]
++||	PACKL4	$Te0[1],$Te2[3],$Te0[1]
++	XOR	$K[0],$Te0[0],$Te0[0]		; s[0]
++||	XOR	$K[1],$Te0[1],$Te0[1]		; s[1]
++
++	PACK2	$Te0[2],$Te1[3],$Te0[2]
++||	PACK2	$Te0[3],$Te1[0],$Te0[3]
++	PACK2	$Te2[0],$Te3[1],$Te2[0]
++||	PACK2	$Te2[1],$Te3[2],$Te2[1]
++||	BNOP	RA
++	PACKL4	$Te0[2],$Te2[0],$Te0[2]
++||	PACKL4	$Te0[3],$Te2[1],$Te0[3]
++	XOR	$K[2],$Te0[2],$Te0[2]		; s[2]
++||	XOR	$K[3],$Te0[3],$Te0[3]		; s[3]
++
++	MV	$Te0[0],A9
++||	MV	$Te0[1],A8
++	MV	$Te0[2],B9
++||	MV	$Te0[3],B8
++|| [B2]	STNDW	A9:A8,*OUT++
++   [B2]	STNDW	B9:B8,*OUT++
++	.else
++	PACK2	$Te1[1],$Te0[0],$Te1[1]
++||	PACK2	$Te1[2],$Te0[1],$Te1[2]
++	PACK2	$Te3[3],$Te2[2],$Te3[3]
++||	PACK2	$Te3[0],$Te2[3],$Te3[0]
++	PACKL4	$Te3[3],$Te1[1],$Te1[1]
++||	PACKL4	$Te3[0],$Te1[2],$Te1[2]
++	XOR	$K[0],$Te1[1],$Te1[1]		; s[0]
++||	XOR	$K[1],$Te1[2],$Te1[2]		; s[1]
++
++	PACK2	$Te1[3],$Te0[2],$Te1[3]
++||	PACK2	$Te1[0],$Te0[3],$Te1[0]
++	PACK2	$Te3[1],$Te2[0],$Te3[1]
++||	PACK2	$Te3[2],$Te2[1],$Te3[2]
++||	BNOP	RA
++	PACKL4	$Te3[1],$Te1[3],$Te1[3]
++||	PACKL4	$Te3[2],$Te1[0],$Te1[0]
++	XOR	$K[2],$Te1[3],$Te1[3]		; s[2]
++||	XOR	$K[3],$Te1[0],$Te1[0]		; s[3]
++
++	MV	$Te1[1],A8
++||	MV	$Te1[2],A9
++	MV	$Te1[3],B8
++||	MV	$Te1[0],B9
++|| [B2]	STNDW	A9:A8,*OUT++
++   [B2]	STNDW	B9:B8,*OUT++
++	.endif
++	.endasmfunc
++
++	.global	_AES_decrypt
++_AES_decrypt:
++	.asmfunc
++	MVK	1,B2
++__decrypt:
++	.if	__TI_EABI__
++   [B2]	LDNDW	*INP++,A9:A8			; load input
++||	MVKL	\$PCR_OFFSET(AES_Td,__decrypt),$TEA
++||	ADDKPC	__decrypt,B0
++   [B2]	LDNDW	*INP++,B9:B8
++||	MVKH	\$PCR_OFFSET(AES_Td,__decrypt),$TEA
++||	ADD	0,KEY,$KPA
++||	ADD	4,KEY,$KPB
++	.else
++   [B2]	LDNDW	*INP++,A9:A8			; load input
++||	MVKL	(AES_Td-__decrypt),$TEA
++||	ADDKPC	__decrypt,B0
++   [B2]	LDNDW	*INP++,B9:B8
++||	MVKH	(AES_Td-__decrypt),$TEA
++||	ADD	0,KEY,$KPA
++||	ADD	4,KEY,$KPB
++	.endif
++	LDW	*$KPA++[2],$Td0[0]		; zero round key
++||	LDW	*$KPB++[2],$Td0[1]
++||	MVK	60,A0
++||	ADD	B0,$TEA,$TEA			; AES_Td
++	LDW	*KEY[A0],B0			; rounds
++||	MVK	1024,A0				; sizeof(AES_Td)
++	LDW	*$KPA++[2],$Td0[2]
++||	LDW	*$KPB++[2],$Td0[3]
++||	MV	$TEA,$TEB
++	NOP
++	.if	.BIG_ENDIAN
++	MV	A9,$s[0]
++||	MV	A8,$s[1]
++||	MV	B9,$s[2]
++||	MV	B8,$s[3]
++	.else
++	MV	A8,$s[0]
++||	MV	A9,$s[1]
++||	MV	B8,$s[2]
++||	MV	B9,$s[3]
++	.endif
++	XOR	$Td0[0],$s[0],$s[0]
++||	XOR	$Td0[1],$s[1],$s[1]
++||	LDW	*$KPA++[2],$K[0]		; 1st round key
++||	LDW	*$KPB++[2],$K[1]
++	SUB	B0,2,B0
++
++	SPLOOPD	13
++||	MVC	B0,ILC
++||	LDW	*$KPA++[2],$K[2]
++||	LDW	*$KPB++[2],$K[3]
++;;====================================================================
++	EXTU	$s[1],EXT3,24,$Td3[1]
++||	EXTU	$s[0],EXT1,24,$Td1[0]
++	LDW	*${TEB}[$Td3[1]],$Td3[1]	; Td3[s1>>24],	t0
++||	LDW	*${TEA}[$Td1[0]],$Td1[0]	; Td1[s0>>8],	t1
++||	XOR	$s[2],$Td0[2],$s[2]		; modulo-scheduled
++||	XOR	$s[3],$Td0[3],$s[3]		; modulo-scheduled
++||	EXTU	$s[1],EXT1,24,$Td1[1]
++||	EXTU	$s[0],EXT3,24,$Td3[0]
++	LDW	*${TEB}[$Td1[1]],$Td1[1]	; Td1[s1>>8],	t2
++||	LDW	*${TEA}[$Td3[0]],$Td3[0]	; Td3[s0>>24],	t3
++||	EXTU	$s[2],EXT2,24,$Td2[2]
++||	EXTU	$s[3],EXT2,24,$Td2[3]
++	LDW	*${TEA}[$Td2[2]],$Td2[2]	; Td2[s2>>16],	t0
++||	LDW	*${TEB}[$Td2[3]],$Td2[3]	; Td2[s3>>16],	t1
++||	EXTU	$s[3],EXT1,24,$Td1[3]
++||	EXTU	$s[2],EXT3,24,$Td3[2]
++	LDW	*${TEB}[$Td1[3]],$Td1[3]	; Td1[s3>>8],	t0
++||	LDW	*${TEA}[$Td3[2]],$Td3[2]	; Td3[s2>>24],	t1
++||	EXTU	$s[0],EXT2,24,$Td2[0]
++||	EXTU	$s[1],EXT2,24,$Td2[1]
++	LDW	*${TEA}[$Td2[0]],$Td2[0]	; Td2[s0>>16],	t2
++||	LDW	*${TEB}[$Td2[1]],$Td2[1]	; Td2[s1>>16],	t3
++||	EXTU	$s[3],EXT3,24,$Td3[3]
++||	EXTU	$s[2],EXT1,24,$Td1[2]
++	LDW	*${TEB}[$Td3[3]],$Td3[3]	; Td3[s3>>24],	t2
++||	LDW	*${TEA}[$Td1[2]],$Td1[2]	; Td1[s2>>8],	t3
++||	ROTL	$Td3[1],TBL3,$Td1[0]		; t0
++||	ROTL	$Td1[0],TBL1,$Td3[1]		; t1
++||	EXTU	$s[0],EXT0,24,$Td0[0]
++||	EXTU	$s[1],EXT0,24,$Td0[1]
++	LDW	*${TEA}[$Td0[0]],$Td0[0]	; Td0[s0],	t0
++||	LDW	*${TEB}[$Td0[1]],$Td0[1]	; Td0[s1],	t1
++||	ROTL	$Td1[1],TBL1,$Td3[0]		; t2
++||	ROTL	$Td3[0],TBL3,$Td1[1]		; t3
++||	EXTU	$s[2],EXT0,24,$Td0[2]
++||	EXTU	$s[3],EXT0,24,$Td0[3]
++	LDW	*${TEA}[$Td0[2]],$Td0[2]	; Td0[s2],	t2
++||	LDW	*${TEB}[$Td0[3]],$Td0[3]	; Td0[s3],	t3
++||	ROTL	$Td2[2],TBL2,$Td2[2]		; t0
++||	ROTL	$Td2[3],TBL2,$Td2[3]		; t1
++||	XOR	$K[0],$Td1[0],$s[0]
++||	XOR	$K[1],$Td3[1],$s[1]
++	ROTL	$Td1[3],TBL1,$Td3[2]		; t0
++||	ROTL	$Td3[2],TBL3,$Td1[3]		; t1
++||	XOR	$K[2],$Td3[0],$s[2]
++||	XOR	$K[3],$Td1[1],$s[3]
++||	LDW	*$KPA++[2],$K[0]		; next round key
++||	LDW	*$KPB++[2],$K[1]
++	ROTL	$Td2[0],TBL2,$Td2[0]		; t2
++||	ROTL	$Td2[1],TBL2,$Td2[1]		; t3
++||	XOR	$s[0],$Td2[2],$s[0]
++||	XOR	$s[1],$Td2[3],$s[1]
++||	LDW	*$KPA++[2],$K[2]
++||	LDW	*$KPB++[2],$K[3]
++	ROTL	$Td3[3],TBL3,$Td1[2]		; t2
++||	ROTL	$Td1[2],TBL1,$Td3[3]		; t3
++||	XOR	$s[0],$Td3[2],$s[0]
++||	XOR	$s[1],$Td1[3],$s[1]
++	XOR	$s[2],$Td2[0],$s[2]
++||	XOR	$s[3],$Td2[1],$s[3]
++||	XOR	$s[0],$Td0[0],$s[0]
++||	XOR	$s[1],$Td0[1],$s[1]
++	SPKERNEL
++||	XOR.L	$s[2],$Td1[2],$s[2]
++||	XOR.L	$s[3],$Td3[3],$s[3]
++;;====================================================================
++	ADD.D	${TEA},A0,${TEA}		; point to Td4
++||	ADD.D	${TEB},A0,${TEB}
++||	EXTU	$s[1],EXT3,24,$Td3[1]
++||	EXTU	$s[0],EXT1,24,$Td1[0]
++	LDBU	*${TEB}[$Td3[1]],$Td3[1]	; Td3[s1>>24],	t0
++||	LDBU	*${TEA}[$Td1[0]],$Td1[0]	; Td1[s0>>8],	t1
++||	XOR	$s[2],$Td0[2],$s[2]		; modulo-scheduled
++||	XOR	$s[3],$Td0[3],$s[3]		; modulo-scheduled
++||	EXTU	$s[0],EXT0,24,$Td0[0]
++||	EXTU	$s[1],EXT0,24,$Td0[1]
++	LDBU	*${TEA}[$Td0[0]],$Td0[0]	; Td0[s0],	t0
++||	LDBU	*${TEB}[$Td0[1]],$Td0[1]	; Td0[s1],	t1
++||	EXTU	$s[2],EXT2,24,$Td2[2]
++||	EXTU	$s[3],EXT2,24,$Td2[3]
++	LDBU	*${TEA}[$Td2[2]],$Td2[2]	; Td2[s2>>16],	t0
++||	LDBU	*${TEB}[$Td2[3]],$Td2[3]	; Td2[s3>>16],	t1
++||	EXTU	$s[3],EXT1,24,$Td1[3]
++||	EXTU	$s[2],EXT3,24,$Td3[2]
++	LDBU	*${TEB}[$Td1[3]],$Td1[3]	; Td1[s3>>8],	t0
++||	LDBU	*${TEA}[$Td3[2]],$Td3[2]	; Td3[s2>>24],	t1
++||	EXTU	$s[1],EXT1,24,$Td1[1]
++||	EXTU	$s[0],EXT3,24,$Td3[0]
++	LDBU	*${TEB}[$Td1[1]],$Td1[1]	; Td1[s1>>8],	t2
++||	LDBU	*${TEA}[$Td3[0]],$Td3[0]	; Td3[s0>>24],	t3
++||	EXTU	$s[0],EXT2,24,$Td2[0]
++||	EXTU	$s[1],EXT2,24,$Td2[1]
++	LDBU	*${TEA}[$Td2[0]],$Td2[0]	; Td2[s0>>16],	t2
++||	LDBU	*${TEB}[$Td2[1]],$Td2[1]	; Td2[s1>>16],	t3
++||	EXTU	$s[3],EXT3,24,$Td3[3]
++||	EXTU	$s[2],EXT1,24,$Td1[2]
++	LDBU	*${TEB}[$Td3[3]],$Td3[3]	; Td3[s3>>24],	t2
++||	LDBU	*${TEA}[$Td1[2]],$Td1[2]	; Td1[s2>>8],	t3
++||	EXTU	$s[2],EXT0,24,$Td0[2]
++||	EXTU	$s[3],EXT0,24,$Td0[3]
++	LDBU	*${TEA}[$Td0[2]],$Td0[2]	; Td0[s2],	t2
++||	LDBU	*${TEB}[$Td0[3]],$Td0[3]	; Td0[s3],	t3
++
++	.if	.BIG_ENDIAN
++	PACK2	$Td0[0],$Td1[3],$Td0[0]
++||	PACK2	$Td0[1],$Td1[0],$Td0[1]
++	PACK2	$Td2[2],$Td3[1],$Td2[2]
++||	PACK2	$Td2[3],$Td3[2],$Td2[3]
++	PACKL4	$Td0[0],$Td2[2],$Td0[0]
++||	PACKL4	$Td0[1],$Td2[3],$Td0[1]
++	XOR	$K[0],$Td0[0],$Td0[0]		; s[0]
++||	XOR	$K[1],$Td0[1],$Td0[1]		; s[1]
++
++	PACK2	$Td0[2],$Td1[1],$Td0[2]
++||	PACK2	$Td0[3],$Td1[2],$Td0[3]
++	PACK2	$Td2[0],$Td3[3],$Td2[0]
++||	PACK2	$Td2[1],$Td3[0],$Td2[1]
++||	BNOP	RA
++	PACKL4	$Td0[2],$Td2[0],$Td0[2]
++||	PACKL4	$Td0[3],$Td2[1],$Td0[3]
++	XOR	$K[2],$Td0[2],$Td0[2]		; s[2]
++||	XOR	$K[3],$Td0[3],$Td0[3]		; s[3]
++
++	MV	$Td0[0],A9
++||	MV	$Td0[1],A8
++	MV	$Td0[2],B9
++||	MV	$Td0[3],B8
++|| [B2]	STNDW	A9:A8,*OUT++
++   [B2]	STNDW	B9:B8,*OUT++
++	.else
++	PACK2	$Td1[3],$Td0[0],$Td1[3]
++||	PACK2	$Td1[0],$Td0[1],$Td1[0]
++	PACK2	$Td3[1],$Td2[2],$Td3[1]
++||	PACK2	$Td3[2],$Td2[3],$Td3[2]
++	PACKL4	$Td3[1],$Td1[3],$Td1[3]
++||	PACKL4	$Td3[2],$Td1[0],$Td1[0]
++	XOR	$K[0],$Td1[3],$Td1[3]		; s[0]
++||	XOR	$K[1],$Td1[0],$Td1[0]		; s[1]
++
++	PACK2	$Td1[1],$Td0[2],$Td1[1]
++||	PACK2	$Td1[2],$Td0[3],$Td1[2]
++	PACK2	$Td3[3],$Td2[0],$Td3[3]
++||	PACK2	$Td3[0],$Td2[1],$Td3[0]
++||	BNOP	RA
++	PACKL4	$Td3[3],$Td1[1],$Td1[1]
++||	PACKL4	$Td3[0],$Td1[2],$Td1[2]
++	XOR	$K[2],$Td1[1],$Td1[1]		; s[2]
++||	XOR	$K[3],$Td1[2],$Td1[2]		; s[3]
++
++	MV	$Td1[3],A8
++||	MV	$Td1[0],A9
++	MV	$Td1[1],B8
++||	MV	$Td1[2],B9
++|| [B2]	STNDW	A9:A8,*OUT++
++   [B2]	STNDW	B9:B8,*OUT++
++	.endif
++	.endasmfunc
++___
++{
++my @K=(@K,@s);			# extended key
++my @Te4=map("B$_",(16..19));
++
++my @Kx9=@Te0;			# used in AES_set_decrypt_key
++my @KxB=@Te1;
++my @KxD=@Te2;
++my @KxE=@Te3;
++
++$code.=<<___;
++	.asg	OUT,BITS
++
++	.global	_AES_set_encrypt_key
++_AES_set_encrypt_key:
++__set_encrypt_key:
++	.asmfunc
++	MV	INP,A0
++||	SHRU	BITS,5,BITS			; 128-192-256 -> 4-6-8
++||	MV	KEY,A1
++  [!A0]	B	RA
++||[!A0]	MVK	-1,RET
++||[!A0]	MVK	1,A1				; only one B RA
++  [!A1]	B	RA
++||[!A1]	MVK	-1,RET
++||[!A1]	MVK	0,A0
++||	MVK	0,B0
++||	MVK	0,A1
++   [A0]	LDNDW	*INP++,A9:A8
++|| [A0]	CMPEQ	4,BITS,B0
++|| [A0]	CMPLT	3,BITS,A1
++   [B0]	B	key128?
++|| [A1]	LDNDW	*INP++,B9:B8
++|| [A0]	CMPEQ	6,BITS,B0
++|| [A0]	CMPLT	5,BITS,A1
++   [B0]	B	key192?
++|| [A1]	LDNDW	*INP++,B17:B16
++|| [A0]	CMPEQ	8,BITS,B0
++|| [A0]	CMPLT	7,BITS,A1
++   [B0]	B	key256?
++|| [A1]	LDNDW	*INP++,B19:B18
++
++	.if	__TI_EABI__
++   [A0]	ADD	0,KEY,$KPA
++|| [A0]	ADD	4,KEY,$KPB
++|| [A0]	MVKL	\$PCR_OFFSET(AES_Te4,__set_encrypt_key),$TEA
++|| [A0]	ADDKPC	__set_encrypt_key,B6
++   [A0]	MVKH	\$PCR_OFFSET(AES_Te4,__set_encrypt_key),$TEA
++   [A0]	ADD	B6,$TEA,$TEA			; AES_Te4
++	.else
++   [A0]	ADD	0,KEY,$KPA
++|| [A0]	ADD	4,KEY,$KPB
++|| [A0]	MVKL	(AES_Te4-__set_encrypt_key),$TEA
++|| [A0]	ADDKPC	__set_encrypt_key,B6
++   [A0]	MVKH	(AES_Te4-__set_encrypt_key),$TEA
++   [A0]	ADD	B6,$TEA,$TEA			; AES_Te4
++	.endif
++	NOP
++	NOP
++
++	BNOP	RA,5
++||	MVK	-2,RET				; unknown bit length
++||	MVK	0,B0				; redundant
++;;====================================================================
++;;====================================================================
++key128?:
++	.if	.BIG_ENDIAN
++	MV	A9,$K[0]
++||	MV	A8,$K[1]
++||	MV	B9,$Te4[2]
++||	MV	B8,$K[3]
++	.else
++	MV	A8,$K[0]
++||	MV	A9,$K[1]
++||	MV	B8,$Te4[2]
++||	MV	B9,$K[3]
++	.endif
++
++	MVK	256,A0
++||	MVK	9,B0
++
++	SPLOOPD	14
++||	MVC	B0,ILC
++||	MV	$TEA,$TEB
++||	ADD	$TEA,A0,A30			; rcon
++;;====================================================================
++	LDW	*A30++[1],A31			; rcon[i]
++||	MV	$Te4[2],$K[2]
++||	EXTU	$K[3],EXT1,24,$Te4[0]
++	LDBU	*${TEB}[$Te4[0]],$Te4[0]
++||	MV	$K[3],A0
++||	EXTU	$K[3],EXT2,24,$Te4[1]
++	LDBU	*${TEB}[$Te4[1]],$Te4[1]
++||	EXTU	A0,EXT3,24,A0
++||	EXTU	$K[3],EXT0,24,$Te4[3]
++	.if	.BIG_ENDIAN
++	LDBU	*${TEA}[A0],$Te4[3]
++||	LDBU	*${TEB}[$Te4[3]],A0
++	.else
++	LDBU	*${TEA}[A0],A0
++||	LDBU	*${TEB}[$Te4[3]],$Te4[3]
++	.endif
++
++	STW	$K[0],*$KPA++[2]
++||	STW	$K[1],*$KPB++[2]
++	STW	$K[2],*$KPA++[2]
++||	STW	$K[3],*$KPB++[2]
++
++	XOR	A31,$K[0],$K[0]			; ^=rcon[i]
++	.if	.BIG_ENDIAN
++	PACK2	$Te4[0],$Te4[1],$Te4[1]
++	PACK2	$Te4[3],A0,$Te4[3]
++	PACKL4	$Te4[1],$Te4[3],$Te4[3]
++	.else
++	PACK2	$Te4[1],$Te4[0],$Te4[1]
++	PACK2	$Te4[3],A0,$Te4[3]
++	PACKL4	$Te4[3],$Te4[1],$Te4[3]
++	.endif
++	XOR	$Te4[3],$K[0],$Te4[0]		; K[0]
++	XOR	$Te4[0],$K[1],$K[1]		; K[1]
++	MV	$Te4[0],$K[0]
++||	XOR	$K[1],$K[2],$Te4[2]		; K[2]
++	XOR	$Te4[2],$K[3],$K[3]		; K[3]
++	SPKERNEL
++;;====================================================================
++	BNOP	RA
++	MV	$Te4[2],$K[2]
++||	STW	$K[0],*$KPA++[2]
++||	STW	$K[1],*$KPB++[2]
++	STW	$K[2],*$KPA++[2]
++||	STW	$K[3],*$KPB++[2]
++	MVK	10,B0				; rounds
++	STW	B0,*++${KPB}[15]
++	MVK	0,RET
++;;====================================================================
++;;====================================================================
++key192?:
++	.if	.BIG_ENDIAN
++	MV	A9,$K[0]
++||	MV	A8,$K[1]
++||	MV	B9,$K[2]
++||	MV	B8,$K[3]
++	MV	B17,$Te4[2]
++||	MV	B16,$K[5]
++	.else
++	MV	A8,$K[0]
++||	MV	A9,$K[1]
++||	MV	B8,$K[2]
++||	MV	B9,$K[3]
++	MV	B16,$Te4[2]
++||	MV	B17,$K[5]
++	.endif
++
++	MVK	256,A0
++||	MVK	6,B0
++	MV	$TEA,$TEB
++||	ADD	$TEA,A0,A30			; rcon
++;;====================================================================
++loop192?:
++	LDW	*A30++[1],A31			; rcon[i]
++||	MV	$Te4[2],$K[4]
++||	EXTU	$K[5],EXT1,24,$Te4[0]
++	LDBU	*${TEB}[$Te4[0]],$Te4[0]
++||	MV	$K[5],A0
++||	EXTU	$K[5],EXT2,24,$Te4[1]
++	LDBU	*${TEB}[$Te4[1]],$Te4[1]
++||	EXTU	A0,EXT3,24,A0
++||	EXTU	$K[5],EXT0,24,$Te4[3]
++	.if	.BIG_ENDIAN
++	LDBU	*${TEA}[A0],$Te4[3]
++||	LDBU	*${TEB}[$Te4[3]],A0
++	.else
++	LDBU	*${TEA}[A0],A0
++||	LDBU	*${TEB}[$Te4[3]],$Te4[3]
++	.endif
++
++	STW	$K[0],*$KPA++[2]
++||	STW	$K[1],*$KPB++[2]
++	STW	$K[2],*$KPA++[2]
++||	STW	$K[3],*$KPB++[2]
++	STW	$K[4],*$KPA++[2]
++||	STW	$K[5],*$KPB++[2]
++
++	XOR	A31,$K[0],$K[0]			; ^=rcon[i]
++	.if	.BIG_ENDIAN
++	PACK2	$Te4[0],$Te4[1],$Te4[1]
++||	PACK2	$Te4[3],A0,$Te4[3]
++	PACKL4	$Te4[1],$Te4[3],$Te4[3]
++	.else
++	PACK2	$Te4[1],$Te4[0],$Te4[1]
++||	PACK2	$Te4[3],A0,$Te4[3]
++	PACKL4	$Te4[3],$Te4[1],$Te4[3]
++	.endif
++	BDEC	loop192?,B0
++||	XOR	$Te4[3],$K[0],$Te4[0]		; K[0]
++	XOR	$Te4[0],$K[1],$K[1]		; K[1]
++	MV	$Te4[0],$K[0]
++||	XOR	$K[1],$K[2],$Te4[2]		; K[2]
++	XOR	$Te4[2],$K[3],$K[3]		; K[3]
++	MV	$Te4[2],$K[2]
++||	XOR	$K[3],$K[4],$Te4[2]		; K[4]
++	XOR	$Te4[2],$K[5],$K[5]		; K[5]
++;;====================================================================
++	BNOP	RA
++	STW	$K[0],*$KPA++[2]
++||	STW	$K[1],*$KPB++[2]
++	STW	$K[2],*$KPA++[2]
++||	STW	$K[3],*$KPB++[2]
++	MVK	12,B0				; rounds
++	STW	B0,*++${KPB}[7]
++	MVK	0,RET
++;;====================================================================
++;;====================================================================
++key256?:
++	.if	.BIG_ENDIAN
++	MV	A9,$K[0]
++||	MV	A8,$K[1]
++||	MV	B9,$K[2]
++||	MV	B8,$K[3]
++	MV	B17,$K[4]
++||	MV	B16,$K[5]
++||	MV	B19,$Te4[2]
++||	MV	B18,$K[7]
++	.else
++	MV	A8,$K[0]
++||	MV	A9,$K[1]
++||	MV	B8,$K[2]
++||	MV	B9,$K[3]
++	MV	B16,$K[4]
++||	MV	B17,$K[5]
++||	MV	B18,$Te4[2]
++||	MV	B19,$K[7]
++	.endif
++
++	MVK	256,A0
++||	MVK	6,B0
++	MV	$TEA,$TEB
++||	ADD	$TEA,A0,A30			; rcon
++;;====================================================================
++loop256?:
++	LDW	*A30++[1],A31			; rcon[i]
++||	MV	$Te4[2],$K[6]
++||	EXTU	$K[7],EXT1,24,$Te4[0]
++	LDBU	*${TEB}[$Te4[0]],$Te4[0]
++||	MV	$K[7],A0
++||	EXTU	$K[7],EXT2,24,$Te4[1]
++	LDBU	*${TEB}[$Te4[1]],$Te4[1]
++||	EXTU	A0,EXT3,24,A0
++||	EXTU	$K[7],EXT0,24,$Te4[3]
++	.if	.BIG_ENDIAN
++	LDBU	*${TEA}[A0],$Te4[3]
++||	LDBU	*${TEB}[$Te4[3]],A0
++	.else
++	LDBU	*${TEA}[A0],A0
++||	LDBU	*${TEB}[$Te4[3]],$Te4[3]
++	.endif
++
++	STW	$K[0],*$KPA++[2]
++||	STW	$K[1],*$KPB++[2]
++	STW	$K[2],*$KPA++[2]
++||	STW	$K[3],*$KPB++[2]
++	STW	$K[4],*$KPA++[2]
++||	STW	$K[5],*$KPB++[2]
++	STW	$K[6],*$KPA++[2]
++||	STW	$K[7],*$KPB++[2]
++||	XOR	A31,$K[0],$K[0]			; ^=rcon[i]
++	.if	.BIG_ENDIAN
++	PACK2	$Te4[0],$Te4[1],$Te4[1]
++||	PACK2	$Te4[3],A0,$Te4[3]
++	PACKL4	$Te4[1],$Te4[3],$Te4[3]
++||[!B0]	B	done256?
++	.else
++	PACK2	$Te4[1],$Te4[0],$Te4[1]
++||	PACK2	$Te4[3],A0,$Te4[3]
++	PACKL4	$Te4[3],$Te4[1],$Te4[3]
++||[!B0]	B	done256?
++	.endif
++	XOR	$Te4[3],$K[0],$Te4[0]		; K[0]
++	XOR	$Te4[0],$K[1],$K[1]		; K[1]
++	MV	$Te4[0],$K[0]
++||	XOR	$K[1],$K[2],$Te4[2]		; K[2]
++	XOR	$Te4[2],$K[3],$K[3]		; K[3]
++
++	MV	$Te4[2],$K[2]
++|| [B0]	EXTU	$K[3],EXT0,24,$Te4[0]
++|| [B0]	SUB	B0,1,B0
++	LDBU	*${TEB}[$Te4[0]],$Te4[0]
++||	MV	$K[3],A0
++||	EXTU	$K[3],EXT1,24,$Te4[1]
++	LDBU	*${TEB}[$Te4[1]],$Te4[1]
++||	EXTU	A0,EXT2,24,A0
++||	EXTU	$K[3],EXT3,24,$Te4[3]
++
++	.if	.BIG_ENDIAN
++	LDBU	*${TEA}[A0],$Te4[3]
++||	LDBU	*${TEB}[$Te4[3]],A0
++	NOP	3
++	PACK2	$Te4[0],$Te4[1],$Te4[1]
++	PACK2	$Te4[3],A0,$Te4[3]
++||	B	loop256?
++	PACKL4	$Te4[1],$Te4[3],$Te4[3]
++	.else
++	LDBU	*${TEA}[A0],A0
++||	LDBU	*${TEB}[$Te4[3]],$Te4[3]
++	NOP	3
++	PACK2	$Te4[1],$Te4[0],$Te4[1]
++	PACK2	$Te4[3],A0,$Te4[3]
++||	B	loop256?
++	PACKL4	$Te4[3],$Te4[1],$Te4[3]
++	.endif
++
++	XOR	$Te4[3],$K[4],$Te4[0]		; K[4]
++	XOR	$Te4[0],$K[5],$K[5]		; K[5]
++	MV	$Te4[0],$K[4]
++||	XOR	$K[5],$K[6],$Te4[2]		; K[6]
++	XOR	$Te4[2],$K[7],$K[7]		; K[7]
++;;====================================================================
++done256?:
++	BNOP	RA
++	STW	$K[0],*$KPA++[2]
++||	STW	$K[1],*$KPB++[2]
++	STW	$K[2],*$KPA++[2]
++||	STW	$K[3],*$KPB++[2]
++	MVK	14,B0				; rounds
++	STW	B0,*--${KPB}[1]
++	MVK	0,RET
++	.endasmfunc
++
++	.global	_AES_set_decrypt_key
++_AES_set_decrypt_key:
++	.asmfunc
++	B	__set_encrypt_key		; guarantee local call
++	MV	KEY,B30				; B30 is not modified
++	MV	RA, B31				; B31 is not modified
++	ADDKPC	ret?,RA,2
++ret?:						; B0 holds rounds or zero
++  [!B0]	BNOP	B31				; return if zero
++   [B0]	SHL	B0,4,A0				; offset to last round key
++   [B0]	SHRU	B0,1,B1
++   [B0]	SUB	B1,1,B1
++   [B0]	MVK	0x0000001B,B3			; AES polynomial
++   [B0]	MVKH	0x07000000,B3
++
++	SPLOOPD	9				; flip round keys
++||	MVC	B1,ILC
++||	MV	B30,$KPA
++||	ADD	B30,A0,$KPB
++||	MVK	16,A0				; sizeof(round key)
++;;====================================================================
++	LDW	*${KPA}[0],A16
++||	LDW	*${KPB}[0],B16
++	LDW	*${KPA}[1],A17
++||	LDW	*${KPB}[1],B17
++	LDW	*${KPA}[2],A18
++||	LDW	*${KPB}[2],B18
++	LDW	*${KPA}[3],A19
++||	ADD	$KPA,A0,$KPA
++||	LDW	*${KPB}[3],B19
++||	SUB	$KPB,A0,$KPB
++	NOP
++	STW	B16,*${KPA}[-4]
++||	STW	A16,*${KPB}[4]
++	STW	B17,*${KPA}[-3]
++||	STW	A17,*${KPB}[5]
++	STW	B18,*${KPA}[-2]
++||	STW	A18,*${KPB}[6]
++	STW	B19,*${KPA}[-1]
++||	STW	A19,*${KPB}[7]
++	SPKERNEL
++;;====================================================================
++	SUB	B0,1,B0				; skip last round
++||	ADD	B30,A0,$KPA			; skip first round
++||	ADD	B30,A0,$KPB
++||	MVC	GFPGFR,B30			; save GFPGFR
++	LDW	*${KPA}[0],$K[0]
++||	LDW	*${KPB}[1],$K[1]
++||	MVC	B3,GFPGFR
++	LDW	*${KPA}[2],$K[2]
++||	LDW	*${KPB}[3],$K[3]
++	MVK	0x00000909,A24
++||	MVK	0x00000B0B,B24
++	MVKH	0x09090000,A24
++||	MVKH	0x0B0B0000,B24
++	MVC	B0,ILC
++||	SUB	B0,1,B0
++
++	GMPY4	$K[0],A24,$Kx9[0]		; ·0x09
++||	GMPY4	$K[1],A24,$Kx9[1]
++||	MVK	0x00000D0D,A25
++||	MVK	0x00000E0E,B25
++	GMPY4	$K[2],A24,$Kx9[2]
++||	GMPY4	$K[3],A24,$Kx9[3]
++||	MVKH	0x0D0D0000,A25
++||	MVKH	0x0E0E0000,B25
++
++	GMPY4	$K[0],B24,$KxB[0]		; ·0x0B
++||	GMPY4	$K[1],B24,$KxB[1]
++	GMPY4	$K[2],B24,$KxB[2]
++||	GMPY4	$K[3],B24,$KxB[3]
++
++	SPLOOP	11				; InvMixColumns
++;;====================================================================
++	GMPY4	$K[0],A25,$KxD[0]		; ·0x0D
++||	GMPY4	$K[1],A25,$KxD[1]
++||	SWAP2	$Kx9[0],$Kx9[0]			; rotate by 16
++||	SWAP2	$Kx9[1],$Kx9[1]
++||	MV	$K[0],$s[0]			; this or DINT
++||	MV	$K[1],$s[1]
++|| [B0]	LDW	*${KPA}[4],$K[0]
++|| [B0]	LDW	*${KPB}[5],$K[1]
++	GMPY4	$K[2],A25,$KxD[2]
++||	GMPY4	$K[3],A25,$KxD[3]
++||	SWAP2	$Kx9[2],$Kx9[2]
++||	SWAP2	$Kx9[3],$Kx9[3]
++||	MV	$K[2],$s[2]
++||	MV	$K[3],$s[3]
++|| [B0]	LDW	*${KPA}[6],$K[2]
++|| [B0]	LDW	*${KPB}[7],$K[3]
++
++	GMPY4	$s[0],B25,$KxE[0]		; ·0x0E
++||	GMPY4	$s[1],B25,$KxE[1]
++||	XOR	$Kx9[0],$KxB[0],$KxB[0]
++||	XOR	$Kx9[1],$KxB[1],$KxB[1]
++	GMPY4	$s[2],B25,$KxE[2]
++||	GMPY4	$s[3],B25,$KxE[3]
++||	XOR	$Kx9[2],$KxB[2],$KxB[2]
++||	XOR	$Kx9[3],$KxB[3],$KxB[3]
++
++	ROTL	$KxB[0],TBL3,$KxB[0]
++||	ROTL	$KxB[1],TBL3,$KxB[1]
++||	SWAP2	$KxD[0],$KxD[0]			; rotate by 16
++||	SWAP2	$KxD[1],$KxD[1]
++	ROTL	$KxB[2],TBL3,$KxB[2]
++||	ROTL	$KxB[3],TBL3,$KxB[3]
++||	SWAP2	$KxD[2],$KxD[2]
++||	SWAP2	$KxD[3],$KxD[3]
++
++	XOR	$KxE[0],$KxD[0],$KxE[0]
++||	XOR	$KxE[1],$KxD[1],$KxE[1]
++|| [B0]	GMPY4	$K[0],A24,$Kx9[0]		; ·0x09
++|| [B0]	GMPY4	$K[1],A24,$Kx9[1]
++||	ADDAW	$KPA,4,$KPA
++	XOR	$KxE[2],$KxD[2],$KxE[2]
++||	XOR	$KxE[3],$KxD[3],$KxE[3]
++|| [B0]	GMPY4	$K[2],A24,$Kx9[2]
++|| [B0]	GMPY4	$K[3],A24,$Kx9[3]
++||	ADDAW	$KPB,4,$KPB
++
++	XOR	$KxB[0],$KxE[0],$KxE[0]
++||	XOR	$KxB[1],$KxE[1],$KxE[1]
++|| [B0]	GMPY4	$K[0],B24,$KxB[0]		; ·0x0B
++|| [B0]	GMPY4	$K[1],B24,$KxB[1]
++	XOR	$KxB[2],$KxE[2],$KxE[2]
++||	XOR	$KxB[3],$KxE[3],$KxE[3]
++|| [B0]	GMPY4	$K[2],B24,$KxB[2]
++|| [B0]	GMPY4	$K[3],B24,$KxB[3]
++||	STW	$KxE[0],*${KPA}[-4]
++||	STW	$KxE[1],*${KPB}[-3]
++	STW	$KxE[2],*${KPA}[-2]
++||	STW	$KxE[3],*${KPB}[-1]
++|| [B0]	SUB	B0,1,B0
++	SPKERNEL
++;;====================================================================
++	BNOP	B31,3
++	MVC	B30,GFPGFR			; restore GFPGFR(*)
++	MVK	0,RET
++	.endasmfunc
++___
++# (*)	Even though ABI doesn't specify GFPGFR as non-volatile, there
++#	are code samples out there that *assume* its default value.
++}
++{
++my ($inp,$out,$blocks,$key,$ivp)=("A4","B4","A6","B6","A8");
++$code.=<<___;
++	.global	_AES_ctr32_encrypt
++_AES_ctr32_encrypt:
++	.asmfunc
++	LDNDW	*${ivp}[0],A31:A30	; load counter value
++||	MV	$blocks,A2		; reassign $blocks
++||	DMV	RA,$key,B27:B26		; reassign RA and $key
++	LDNDW	*${ivp}[1],B31:B30
++||	MVK	0,B2			; don't let __encrypt load input
++||	MVK	0,A1			; and postpone writing output
++	.if	.BIG_ENDIAN
++	NOP
++	.else
++	NOP	4
++	SWAP2	B31,B31			; keep least significant 32 bits
++	SWAP4	B31,B31			; in host byte order
++	.endif
++ctr32_loop?:
++   [A2]	BNOP	__encrypt
++|| [A1]	XOR	A29,A9,A9		; input^Ek(counter)
++|| [A1]	XOR	A28,A8,A8
++|| [A2]	LDNDW	*INP++,A29:A28		; load input
++  [!A2]	BNOP	B27			; return
++|| [A1]	XOR	B29,B9,B9
++|| [A1]	XOR	B28,B8,B8
++|| [A2]	LDNDW	*INP++,B29:B28
++	.if	.BIG_ENDIAN
++   [A1]	STNDW	A9:A8,*OUT++		; save output
++|| [A2]	DMV	A31,A30,A9:A8		; pass counter value to __encrypt
++   [A1]	STNDW	B9:B8,*OUT++
++|| [A2]	DMV	B31,B30,B9:B8
++|| [A2]	ADD	B30,1,B30		; counter++
++	.else
++   [A1]	STNDW	A9:A8,*OUT++		; save output
++|| [A2]	DMV	A31,A30,A9:A8
++|| [A2]	SWAP2	B31,B0
++|| [A2]	ADD	B31,1,B31		; counter++
++   [A1]	STNDW	B9:B8,*OUT++
++|| [A2]	MV	B30,B8
++|| [A2]	SWAP4	B0,B9
++	.endif
++   [A2]	ADDKPC	ctr32_loop?,RA		; return to ctr32_loop?
++|| [A2]	MV	B26,KEY			; pass $key
++|| [A2]	SUB	A2,1,A2			; $blocks--
++||[!A1]	MVK	1,A1
++	NOP
++	NOP
++	.endasmfunc
++___
++}
++# Tables are kept in endian-neutral manner
++$code.=<<___;
++	.if	__TI_EABI__
++	.sect	".text:aes_asm.const"
++	.else
++	.sect	".const:aes_asm"
++	.endif
++	.align	128
++AES_Te:
++	.byte	0xc6,0x63,0x63,0xa5,	0xf8,0x7c,0x7c,0x84
++	.byte	0xee,0x77,0x77,0x99,	0xf6,0x7b,0x7b,0x8d
++	.byte	0xff,0xf2,0xf2,0x0d,	0xd6,0x6b,0x6b,0xbd
++	.byte	0xde,0x6f,0x6f,0xb1,	0x91,0xc5,0xc5,0x54
++	.byte	0x60,0x30,0x30,0x50,	0x02,0x01,0x01,0x03
++	.byte	0xce,0x67,0x67,0xa9,	0x56,0x2b,0x2b,0x7d
++	.byte	0xe7,0xfe,0xfe,0x19,	0xb5,0xd7,0xd7,0x62
++	.byte	0x4d,0xab,0xab,0xe6,	0xec,0x76,0x76,0x9a
++	.byte	0x8f,0xca,0xca,0x45,	0x1f,0x82,0x82,0x9d
++	.byte	0x89,0xc9,0xc9,0x40,	0xfa,0x7d,0x7d,0x87
++	.byte	0xef,0xfa,0xfa,0x15,	0xb2,0x59,0x59,0xeb
++	.byte	0x8e,0x47,0x47,0xc9,	0xfb,0xf0,0xf0,0x0b
++	.byte	0x41,0xad,0xad,0xec,	0xb3,0xd4,0xd4,0x67
++	.byte	0x5f,0xa2,0xa2,0xfd,	0x45,0xaf,0xaf,0xea
++	.byte	0x23,0x9c,0x9c,0xbf,	0x53,0xa4,0xa4,0xf7
++	.byte	0xe4,0x72,0x72,0x96,	0x9b,0xc0,0xc0,0x5b
++	.byte	0x75,0xb7,0xb7,0xc2,	0xe1,0xfd,0xfd,0x1c
++	.byte	0x3d,0x93,0x93,0xae,	0x4c,0x26,0x26,0x6a
++	.byte	0x6c,0x36,0x36,0x5a,	0x7e,0x3f,0x3f,0x41
++	.byte	0xf5,0xf7,0xf7,0x02,	0x83,0xcc,0xcc,0x4f
++	.byte	0x68,0x34,0x34,0x5c,	0x51,0xa5,0xa5,0xf4
++	.byte	0xd1,0xe5,0xe5,0x34,	0xf9,0xf1,0xf1,0x08
++	.byte	0xe2,0x71,0x71,0x93,	0xab,0xd8,0xd8,0x73
++	.byte	0x62,0x31,0x31,0x53,	0x2a,0x15,0x15,0x3f
++	.byte	0x08,0x04,0x04,0x0c,	0x95,0xc7,0xc7,0x52
++	.byte	0x46,0x23,0x23,0x65,	0x9d,0xc3,0xc3,0x5e
++	.byte	0x30,0x18,0x18,0x28,	0x37,0x96,0x96,0xa1
++	.byte	0x0a,0x05,0x05,0x0f,	0x2f,0x9a,0x9a,0xb5
++	.byte	0x0e,0x07,0x07,0x09,	0x24,0x12,0x12,0x36
++	.byte	0x1b,0x80,0x80,0x9b,	0xdf,0xe2,0xe2,0x3d
++	.byte	0xcd,0xeb,0xeb,0x26,	0x4e,0x27,0x27,0x69
++	.byte	0x7f,0xb2,0xb2,0xcd,	0xea,0x75,0x75,0x9f
++	.byte	0x12,0x09,0x09,0x1b,	0x1d,0x83,0x83,0x9e
++	.byte	0x58,0x2c,0x2c,0x74,	0x34,0x1a,0x1a,0x2e
++	.byte	0x36,0x1b,0x1b,0x2d,	0xdc,0x6e,0x6e,0xb2
++	.byte	0xb4,0x5a,0x5a,0xee,	0x5b,0xa0,0xa0,0xfb
++	.byte	0xa4,0x52,0x52,0xf6,	0x76,0x3b,0x3b,0x4d
++	.byte	0xb7,0xd6,0xd6,0x61,	0x7d,0xb3,0xb3,0xce
++	.byte	0x52,0x29,0x29,0x7b,	0xdd,0xe3,0xe3,0x3e
++	.byte	0x5e,0x2f,0x2f,0x71,	0x13,0x84,0x84,0x97
++	.byte	0xa6,0x53,0x53,0xf5,	0xb9,0xd1,0xd1,0x68
++	.byte	0x00,0x00,0x00,0x00,	0xc1,0xed,0xed,0x2c
++	.byte	0x40,0x20,0x20,0x60,	0xe3,0xfc,0xfc,0x1f
++	.byte	0x79,0xb1,0xb1,0xc8,	0xb6,0x5b,0x5b,0xed
++	.byte	0xd4,0x6a,0x6a,0xbe,	0x8d,0xcb,0xcb,0x46
++	.byte	0x67,0xbe,0xbe,0xd9,	0x72,0x39,0x39,0x4b
++	.byte	0x94,0x4a,0x4a,0xde,	0x98,0x4c,0x4c,0xd4
++	.byte	0xb0,0x58,0x58,0xe8,	0x85,0xcf,0xcf,0x4a
++	.byte	0xbb,0xd0,0xd0,0x6b,	0xc5,0xef,0xef,0x2a
++	.byte	0x4f,0xaa,0xaa,0xe5,	0xed,0xfb,0xfb,0x16
++	.byte	0x86,0x43,0x43,0xc5,	0x9a,0x4d,0x4d,0xd7
++	.byte	0x66,0x33,0x33,0x55,	0x11,0x85,0x85,0x94
++	.byte	0x8a,0x45,0x45,0xcf,	0xe9,0xf9,0xf9,0x10
++	.byte	0x04,0x02,0x02,0x06,	0xfe,0x7f,0x7f,0x81
++	.byte	0xa0,0x50,0x50,0xf0,	0x78,0x3c,0x3c,0x44
++	.byte	0x25,0x9f,0x9f,0xba,	0x4b,0xa8,0xa8,0xe3
++	.byte	0xa2,0x51,0x51,0xf3,	0x5d,0xa3,0xa3,0xfe
++	.byte	0x80,0x40,0x40,0xc0,	0x05,0x8f,0x8f,0x8a
++	.byte	0x3f,0x92,0x92,0xad,	0x21,0x9d,0x9d,0xbc
++	.byte	0x70,0x38,0x38,0x48,	0xf1,0xf5,0xf5,0x04
++	.byte	0x63,0xbc,0xbc,0xdf,	0x77,0xb6,0xb6,0xc1
++	.byte	0xaf,0xda,0xda,0x75,	0x42,0x21,0x21,0x63
++	.byte	0x20,0x10,0x10,0x30,	0xe5,0xff,0xff,0x1a
++	.byte	0xfd,0xf3,0xf3,0x0e,	0xbf,0xd2,0xd2,0x6d
++	.byte	0x81,0xcd,0xcd,0x4c,	0x18,0x0c,0x0c,0x14
++	.byte	0x26,0x13,0x13,0x35,	0xc3,0xec,0xec,0x2f
++	.byte	0xbe,0x5f,0x5f,0xe1,	0x35,0x97,0x97,0xa2
++	.byte	0x88,0x44,0x44,0xcc,	0x2e,0x17,0x17,0x39
++	.byte	0x93,0xc4,0xc4,0x57,	0x55,0xa7,0xa7,0xf2
++	.byte	0xfc,0x7e,0x7e,0x82,	0x7a,0x3d,0x3d,0x47
++	.byte	0xc8,0x64,0x64,0xac,	0xba,0x5d,0x5d,0xe7
++	.byte	0x32,0x19,0x19,0x2b,	0xe6,0x73,0x73,0x95
++	.byte	0xc0,0x60,0x60,0xa0,	0x19,0x81,0x81,0x98
++	.byte	0x9e,0x4f,0x4f,0xd1,	0xa3,0xdc,0xdc,0x7f
++	.byte	0x44,0x22,0x22,0x66,	0x54,0x2a,0x2a,0x7e
++	.byte	0x3b,0x90,0x90,0xab,	0x0b,0x88,0x88,0x83
++	.byte	0x8c,0x46,0x46,0xca,	0xc7,0xee,0xee,0x29
++	.byte	0x6b,0xb8,0xb8,0xd3,	0x28,0x14,0x14,0x3c
++	.byte	0xa7,0xde,0xde,0x79,	0xbc,0x5e,0x5e,0xe2
++	.byte	0x16,0x0b,0x0b,0x1d,	0xad,0xdb,0xdb,0x76
++	.byte	0xdb,0xe0,0xe0,0x3b,	0x64,0x32,0x32,0x56
++	.byte	0x74,0x3a,0x3a,0x4e,	0x14,0x0a,0x0a,0x1e
++	.byte	0x92,0x49,0x49,0xdb,	0x0c,0x06,0x06,0x0a
++	.byte	0x48,0x24,0x24,0x6c,	0xb8,0x5c,0x5c,0xe4
++	.byte	0x9f,0xc2,0xc2,0x5d,	0xbd,0xd3,0xd3,0x6e
++	.byte	0x43,0xac,0xac,0xef,	0xc4,0x62,0x62,0xa6
++	.byte	0x39,0x91,0x91,0xa8,	0x31,0x95,0x95,0xa4
++	.byte	0xd3,0xe4,0xe4,0x37,	0xf2,0x79,0x79,0x8b
++	.byte	0xd5,0xe7,0xe7,0x32,	0x8b,0xc8,0xc8,0x43
++	.byte	0x6e,0x37,0x37,0x59,	0xda,0x6d,0x6d,0xb7
++	.byte	0x01,0x8d,0x8d,0x8c,	0xb1,0xd5,0xd5,0x64
++	.byte	0x9c,0x4e,0x4e,0xd2,	0x49,0xa9,0xa9,0xe0
++	.byte	0xd8,0x6c,0x6c,0xb4,	0xac,0x56,0x56,0xfa
++	.byte	0xf3,0xf4,0xf4,0x07,	0xcf,0xea,0xea,0x25
++	.byte	0xca,0x65,0x65,0xaf,	0xf4,0x7a,0x7a,0x8e
++	.byte	0x47,0xae,0xae,0xe9,	0x10,0x08,0x08,0x18
++	.byte	0x6f,0xba,0xba,0xd5,	0xf0,0x78,0x78,0x88
++	.byte	0x4a,0x25,0x25,0x6f,	0x5c,0x2e,0x2e,0x72
++	.byte	0x38,0x1c,0x1c,0x24,	0x57,0xa6,0xa6,0xf1
++	.byte	0x73,0xb4,0xb4,0xc7,	0x97,0xc6,0xc6,0x51
++	.byte	0xcb,0xe8,0xe8,0x23,	0xa1,0xdd,0xdd,0x7c
++	.byte	0xe8,0x74,0x74,0x9c,	0x3e,0x1f,0x1f,0x21
++	.byte	0x96,0x4b,0x4b,0xdd,	0x61,0xbd,0xbd,0xdc
++	.byte	0x0d,0x8b,0x8b,0x86,	0x0f,0x8a,0x8a,0x85
++	.byte	0xe0,0x70,0x70,0x90,	0x7c,0x3e,0x3e,0x42
++	.byte	0x71,0xb5,0xb5,0xc4,	0xcc,0x66,0x66,0xaa
++	.byte	0x90,0x48,0x48,0xd8,	0x06,0x03,0x03,0x05
++	.byte	0xf7,0xf6,0xf6,0x01,	0x1c,0x0e,0x0e,0x12
++	.byte	0xc2,0x61,0x61,0xa3,	0x6a,0x35,0x35,0x5f
++	.byte	0xae,0x57,0x57,0xf9,	0x69,0xb9,0xb9,0xd0
++	.byte	0x17,0x86,0x86,0x91,	0x99,0xc1,0xc1,0x58
++	.byte	0x3a,0x1d,0x1d,0x27,	0x27,0x9e,0x9e,0xb9
++	.byte	0xd9,0xe1,0xe1,0x38,	0xeb,0xf8,0xf8,0x13
++	.byte	0x2b,0x98,0x98,0xb3,	0x22,0x11,0x11,0x33
++	.byte	0xd2,0x69,0x69,0xbb,	0xa9,0xd9,0xd9,0x70
++	.byte	0x07,0x8e,0x8e,0x89,	0x33,0x94,0x94,0xa7
++	.byte	0x2d,0x9b,0x9b,0xb6,	0x3c,0x1e,0x1e,0x22
++	.byte	0x15,0x87,0x87,0x92,	0xc9,0xe9,0xe9,0x20
++	.byte	0x87,0xce,0xce,0x49,	0xaa,0x55,0x55,0xff
++	.byte	0x50,0x28,0x28,0x78,	0xa5,0xdf,0xdf,0x7a
++	.byte	0x03,0x8c,0x8c,0x8f,	0x59,0xa1,0xa1,0xf8
++	.byte	0x09,0x89,0x89,0x80,	0x1a,0x0d,0x0d,0x17
++	.byte	0x65,0xbf,0xbf,0xda,	0xd7,0xe6,0xe6,0x31
++	.byte	0x84,0x42,0x42,0xc6,	0xd0,0x68,0x68,0xb8
++	.byte	0x82,0x41,0x41,0xc3,	0x29,0x99,0x99,0xb0
++	.byte	0x5a,0x2d,0x2d,0x77,	0x1e,0x0f,0x0f,0x11
++	.byte	0x7b,0xb0,0xb0,0xcb,	0xa8,0x54,0x54,0xfc
++	.byte	0x6d,0xbb,0xbb,0xd6,	0x2c,0x16,0x16,0x3a
++AES_Te4:
++	.byte	0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5
++	.byte	0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76
++	.byte	0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0
++	.byte	0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0
++	.byte	0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc
++	.byte	0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15
++	.byte	0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a
++	.byte	0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75
++	.byte	0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0
++	.byte	0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84
++	.byte	0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b
++	.byte	0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf
++	.byte	0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85
++	.byte	0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8
++	.byte	0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5
++	.byte	0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2
++	.byte	0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17
++	.byte	0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73
++	.byte	0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88
++	.byte	0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb
++	.byte	0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c
++	.byte	0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79
++	.byte	0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9
++	.byte	0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08
++	.byte	0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6
++	.byte	0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a
++	.byte	0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e
++	.byte	0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e
++	.byte	0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94
++	.byte	0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf
++	.byte	0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68
++	.byte	0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16
++rcon:
++	.byte	0x01,0x00,0x00,0x00,	0x02,0x00,0x00,0x00
++	.byte	0x04,0x00,0x00,0x00,	0x08,0x00,0x00,0x00
++	.byte	0x10,0x00,0x00,0x00,	0x20,0x00,0x00,0x00
++	.byte	0x40,0x00,0x00,0x00,	0x80,0x00,0x00,0x00
++	.byte	0x1B,0x00,0x00,0x00,	0x36,0x00,0x00,0x00
++	.align	128
++AES_Td:
++	.byte	0x51,0xf4,0xa7,0x50,	0x7e,0x41,0x65,0x53
++	.byte	0x1a,0x17,0xa4,0xc3,	0x3a,0x27,0x5e,0x96
++	.byte	0x3b,0xab,0x6b,0xcb,	0x1f,0x9d,0x45,0xf1
++	.byte	0xac,0xfa,0x58,0xab,	0x4b,0xe3,0x03,0x93
++	.byte	0x20,0x30,0xfa,0x55,	0xad,0x76,0x6d,0xf6
++	.byte	0x88,0xcc,0x76,0x91,	0xf5,0x02,0x4c,0x25
++	.byte	0x4f,0xe5,0xd7,0xfc,	0xc5,0x2a,0xcb,0xd7
++	.byte	0x26,0x35,0x44,0x80,	0xb5,0x62,0xa3,0x8f
++	.byte	0xde,0xb1,0x5a,0x49,	0x25,0xba,0x1b,0x67
++	.byte	0x45,0xea,0x0e,0x98,	0x5d,0xfe,0xc0,0xe1
++	.byte	0xc3,0x2f,0x75,0x02,	0x81,0x4c,0xf0,0x12
++	.byte	0x8d,0x46,0x97,0xa3,	0x6b,0xd3,0xf9,0xc6
++	.byte	0x03,0x8f,0x5f,0xe7,	0x15,0x92,0x9c,0x95
++	.byte	0xbf,0x6d,0x7a,0xeb,	0x95,0x52,0x59,0xda
++	.byte	0xd4,0xbe,0x83,0x2d,	0x58,0x74,0x21,0xd3
++	.byte	0x49,0xe0,0x69,0x29,	0x8e,0xc9,0xc8,0x44
++	.byte	0x75,0xc2,0x89,0x6a,	0xf4,0x8e,0x79,0x78
++	.byte	0x99,0x58,0x3e,0x6b,	0x27,0xb9,0x71,0xdd
++	.byte	0xbe,0xe1,0x4f,0xb6,	0xf0,0x88,0xad,0x17
++	.byte	0xc9,0x20,0xac,0x66,	0x7d,0xce,0x3a,0xb4
++	.byte	0x63,0xdf,0x4a,0x18,	0xe5,0x1a,0x31,0x82
++	.byte	0x97,0x51,0x33,0x60,	0x62,0x53,0x7f,0x45
++	.byte	0xb1,0x64,0x77,0xe0,	0xbb,0x6b,0xae,0x84
++	.byte	0xfe,0x81,0xa0,0x1c,	0xf9,0x08,0x2b,0x94
++	.byte	0x70,0x48,0x68,0x58,	0x8f,0x45,0xfd,0x19
++	.byte	0x94,0xde,0x6c,0x87,	0x52,0x7b,0xf8,0xb7
++	.byte	0xab,0x73,0xd3,0x23,	0x72,0x4b,0x02,0xe2
++	.byte	0xe3,0x1f,0x8f,0x57,	0x66,0x55,0xab,0x2a
++	.byte	0xb2,0xeb,0x28,0x07,	0x2f,0xb5,0xc2,0x03
++	.byte	0x86,0xc5,0x7b,0x9a,	0xd3,0x37,0x08,0xa5
++	.byte	0x30,0x28,0x87,0xf2,	0x23,0xbf,0xa5,0xb2
++	.byte	0x02,0x03,0x6a,0xba,	0xed,0x16,0x82,0x5c
++	.byte	0x8a,0xcf,0x1c,0x2b,	0xa7,0x79,0xb4,0x92
++	.byte	0xf3,0x07,0xf2,0xf0,	0x4e,0x69,0xe2,0xa1
++	.byte	0x65,0xda,0xf4,0xcd,	0x06,0x05,0xbe,0xd5
++	.byte	0xd1,0x34,0x62,0x1f,	0xc4,0xa6,0xfe,0x8a
++	.byte	0x34,0x2e,0x53,0x9d,	0xa2,0xf3,0x55,0xa0
++	.byte	0x05,0x8a,0xe1,0x32,	0xa4,0xf6,0xeb,0x75
++	.byte	0x0b,0x83,0xec,0x39,	0x40,0x60,0xef,0xaa
++	.byte	0x5e,0x71,0x9f,0x06,	0xbd,0x6e,0x10,0x51
++	.byte	0x3e,0x21,0x8a,0xf9,	0x96,0xdd,0x06,0x3d
++	.byte	0xdd,0x3e,0x05,0xae,	0x4d,0xe6,0xbd,0x46
++	.byte	0x91,0x54,0x8d,0xb5,	0x71,0xc4,0x5d,0x05
++	.byte	0x04,0x06,0xd4,0x6f,	0x60,0x50,0x15,0xff
++	.byte	0x19,0x98,0xfb,0x24,	0xd6,0xbd,0xe9,0x97
++	.byte	0x89,0x40,0x43,0xcc,	0x67,0xd9,0x9e,0x77
++	.byte	0xb0,0xe8,0x42,0xbd,	0x07,0x89,0x8b,0x88
++	.byte	0xe7,0x19,0x5b,0x38,	0x79,0xc8,0xee,0xdb
++	.byte	0xa1,0x7c,0x0a,0x47,	0x7c,0x42,0x0f,0xe9
++	.byte	0xf8,0x84,0x1e,0xc9,	0x00,0x00,0x00,0x00
++	.byte	0x09,0x80,0x86,0x83,	0x32,0x2b,0xed,0x48
++	.byte	0x1e,0x11,0x70,0xac,	0x6c,0x5a,0x72,0x4e
++	.byte	0xfd,0x0e,0xff,0xfb,	0x0f,0x85,0x38,0x56
++	.byte	0x3d,0xae,0xd5,0x1e,	0x36,0x2d,0x39,0x27
++	.byte	0x0a,0x0f,0xd9,0x64,	0x68,0x5c,0xa6,0x21
++	.byte	0x9b,0x5b,0x54,0xd1,	0x24,0x36,0x2e,0x3a
++	.byte	0x0c,0x0a,0x67,0xb1,	0x93,0x57,0xe7,0x0f
++	.byte	0xb4,0xee,0x96,0xd2,	0x1b,0x9b,0x91,0x9e
++	.byte	0x80,0xc0,0xc5,0x4f,	0x61,0xdc,0x20,0xa2
++	.byte	0x5a,0x77,0x4b,0x69,	0x1c,0x12,0x1a,0x16
++	.byte	0xe2,0x93,0xba,0x0a,	0xc0,0xa0,0x2a,0xe5
++	.byte	0x3c,0x22,0xe0,0x43,	0x12,0x1b,0x17,0x1d
++	.byte	0x0e,0x09,0x0d,0x0b,	0xf2,0x8b,0xc7,0xad
++	.byte	0x2d,0xb6,0xa8,0xb9,	0x14,0x1e,0xa9,0xc8
++	.byte	0x57,0xf1,0x19,0x85,	0xaf,0x75,0x07,0x4c
++	.byte	0xee,0x99,0xdd,0xbb,	0xa3,0x7f,0x60,0xfd
++	.byte	0xf7,0x01,0x26,0x9f,	0x5c,0x72,0xf5,0xbc
++	.byte	0x44,0x66,0x3b,0xc5,	0x5b,0xfb,0x7e,0x34
++	.byte	0x8b,0x43,0x29,0x76,	0xcb,0x23,0xc6,0xdc
++	.byte	0xb6,0xed,0xfc,0x68,	0xb8,0xe4,0xf1,0x63
++	.byte	0xd7,0x31,0xdc,0xca,	0x42,0x63,0x85,0x10
++	.byte	0x13,0x97,0x22,0x40,	0x84,0xc6,0x11,0x20
++	.byte	0x85,0x4a,0x24,0x7d,	0xd2,0xbb,0x3d,0xf8
++	.byte	0xae,0xf9,0x32,0x11,	0xc7,0x29,0xa1,0x6d
++	.byte	0x1d,0x9e,0x2f,0x4b,	0xdc,0xb2,0x30,0xf3
++	.byte	0x0d,0x86,0x52,0xec,	0x77,0xc1,0xe3,0xd0
++	.byte	0x2b,0xb3,0x16,0x6c,	0xa9,0x70,0xb9,0x99
++	.byte	0x11,0x94,0x48,0xfa,	0x47,0xe9,0x64,0x22
++	.byte	0xa8,0xfc,0x8c,0xc4,	0xa0,0xf0,0x3f,0x1a
++	.byte	0x56,0x7d,0x2c,0xd8,	0x22,0x33,0x90,0xef
++	.byte	0x87,0x49,0x4e,0xc7,	0xd9,0x38,0xd1,0xc1
++	.byte	0x8c,0xca,0xa2,0xfe,	0x98,0xd4,0x0b,0x36
++	.byte	0xa6,0xf5,0x81,0xcf,	0xa5,0x7a,0xde,0x28
++	.byte	0xda,0xb7,0x8e,0x26,	0x3f,0xad,0xbf,0xa4
++	.byte	0x2c,0x3a,0x9d,0xe4,	0x50,0x78,0x92,0x0d
++	.byte	0x6a,0x5f,0xcc,0x9b,	0x54,0x7e,0x46,0x62
++	.byte	0xf6,0x8d,0x13,0xc2,	0x90,0xd8,0xb8,0xe8
++	.byte	0x2e,0x39,0xf7,0x5e,	0x82,0xc3,0xaf,0xf5
++	.byte	0x9f,0x5d,0x80,0xbe,	0x69,0xd0,0x93,0x7c
++	.byte	0x6f,0xd5,0x2d,0xa9,	0xcf,0x25,0x12,0xb3
++	.byte	0xc8,0xac,0x99,0x3b,	0x10,0x18,0x7d,0xa7
++	.byte	0xe8,0x9c,0x63,0x6e,	0xdb,0x3b,0xbb,0x7b
++	.byte	0xcd,0x26,0x78,0x09,	0x6e,0x59,0x18,0xf4
++	.byte	0xec,0x9a,0xb7,0x01,	0x83,0x4f,0x9a,0xa8
++	.byte	0xe6,0x95,0x6e,0x65,	0xaa,0xff,0xe6,0x7e
++	.byte	0x21,0xbc,0xcf,0x08,	0xef,0x15,0xe8,0xe6
++	.byte	0xba,0xe7,0x9b,0xd9,	0x4a,0x6f,0x36,0xce
++	.byte	0xea,0x9f,0x09,0xd4,	0x29,0xb0,0x7c,0xd6
++	.byte	0x31,0xa4,0xb2,0xaf,	0x2a,0x3f,0x23,0x31
++	.byte	0xc6,0xa5,0x94,0x30,	0x35,0xa2,0x66,0xc0
++	.byte	0x74,0x4e,0xbc,0x37,	0xfc,0x82,0xca,0xa6
++	.byte	0xe0,0x90,0xd0,0xb0,	0x33,0xa7,0xd8,0x15
++	.byte	0xf1,0x04,0x98,0x4a,	0x41,0xec,0xda,0xf7
++	.byte	0x7f,0xcd,0x50,0x0e,	0x17,0x91,0xf6,0x2f
++	.byte	0x76,0x4d,0xd6,0x8d,	0x43,0xef,0xb0,0x4d
++	.byte	0xcc,0xaa,0x4d,0x54,	0xe4,0x96,0x04,0xdf
++	.byte	0x9e,0xd1,0xb5,0xe3,	0x4c,0x6a,0x88,0x1b
++	.byte	0xc1,0x2c,0x1f,0xb8,	0x46,0x65,0x51,0x7f
++	.byte	0x9d,0x5e,0xea,0x04,	0x01,0x8c,0x35,0x5d
++	.byte	0xfa,0x87,0x74,0x73,	0xfb,0x0b,0x41,0x2e
++	.byte	0xb3,0x67,0x1d,0x5a,	0x92,0xdb,0xd2,0x52
++	.byte	0xe9,0x10,0x56,0x33,	0x6d,0xd6,0x47,0x13
++	.byte	0x9a,0xd7,0x61,0x8c,	0x37,0xa1,0x0c,0x7a
++	.byte	0x59,0xf8,0x14,0x8e,	0xeb,0x13,0x3c,0x89
++	.byte	0xce,0xa9,0x27,0xee,	0xb7,0x61,0xc9,0x35
++	.byte	0xe1,0x1c,0xe5,0xed,	0x7a,0x47,0xb1,0x3c
++	.byte	0x9c,0xd2,0xdf,0x59,	0x55,0xf2,0x73,0x3f
++	.byte	0x18,0x14,0xce,0x79,	0x73,0xc7,0x37,0xbf
++	.byte	0x53,0xf7,0xcd,0xea,	0x5f,0xfd,0xaa,0x5b
++	.byte	0xdf,0x3d,0x6f,0x14,	0x78,0x44,0xdb,0x86
++	.byte	0xca,0xaf,0xf3,0x81,	0xb9,0x68,0xc4,0x3e
++	.byte	0x38,0x24,0x34,0x2c,	0xc2,0xa3,0x40,0x5f
++	.byte	0x16,0x1d,0xc3,0x72,	0xbc,0xe2,0x25,0x0c
++	.byte	0x28,0x3c,0x49,0x8b,	0xff,0x0d,0x95,0x41
++	.byte	0x39,0xa8,0x01,0x71,	0x08,0x0c,0xb3,0xde
++	.byte	0xd8,0xb4,0xe4,0x9c,	0x64,0x56,0xc1,0x90
++	.byte	0x7b,0xcb,0x84,0x61,	0xd5,0x32,0xb6,0x70
++	.byte	0x48,0x6c,0x5c,0x74,	0xd0,0xb8,0x57,0x42
++AES_Td4:
++	.byte	0x52, 0x09, 0x6a, 0xd5, 0x30, 0x36, 0xa5, 0x38
++	.byte	0xbf, 0x40, 0xa3, 0x9e, 0x81, 0xf3, 0xd7, 0xfb
++	.byte	0x7c, 0xe3, 0x39, 0x82, 0x9b, 0x2f, 0xff, 0x87
++	.byte	0x34, 0x8e, 0x43, 0x44, 0xc4, 0xde, 0xe9, 0xcb
++	.byte	0x54, 0x7b, 0x94, 0x32, 0xa6, 0xc2, 0x23, 0x3d
++	.byte	0xee, 0x4c, 0x95, 0x0b, 0x42, 0xfa, 0xc3, 0x4e
++	.byte	0x08, 0x2e, 0xa1, 0x66, 0x28, 0xd9, 0x24, 0xb2
++	.byte	0x76, 0x5b, 0xa2, 0x49, 0x6d, 0x8b, 0xd1, 0x25
++	.byte	0x72, 0xf8, 0xf6, 0x64, 0x86, 0x68, 0x98, 0x16
++	.byte	0xd4, 0xa4, 0x5c, 0xcc, 0x5d, 0x65, 0xb6, 0x92
++	.byte	0x6c, 0x70, 0x48, 0x50, 0xfd, 0xed, 0xb9, 0xda
++	.byte	0x5e, 0x15, 0x46, 0x57, 0xa7, 0x8d, 0x9d, 0x84
++	.byte	0x90, 0xd8, 0xab, 0x00, 0x8c, 0xbc, 0xd3, 0x0a
++	.byte	0xf7, 0xe4, 0x58, 0x05, 0xb8, 0xb3, 0x45, 0x06
++	.byte	0xd0, 0x2c, 0x1e, 0x8f, 0xca, 0x3f, 0x0f, 0x02
++	.byte	0xc1, 0xaf, 0xbd, 0x03, 0x01, 0x13, 0x8a, 0x6b
++	.byte	0x3a, 0x91, 0x11, 0x41, 0x4f, 0x67, 0xdc, 0xea
++	.byte	0x97, 0xf2, 0xcf, 0xce, 0xf0, 0xb4, 0xe6, 0x73
++	.byte	0x96, 0xac, 0x74, 0x22, 0xe7, 0xad, 0x35, 0x85
++	.byte	0xe2, 0xf9, 0x37, 0xe8, 0x1c, 0x75, 0xdf, 0x6e
++	.byte	0x47, 0xf1, 0x1a, 0x71, 0x1d, 0x29, 0xc5, 0x89
++	.byte	0x6f, 0xb7, 0x62, 0x0e, 0xaa, 0x18, 0xbe, 0x1b
++	.byte	0xfc, 0x56, 0x3e, 0x4b, 0xc6, 0xd2, 0x79, 0x20
++	.byte	0x9a, 0xdb, 0xc0, 0xfe, 0x78, 0xcd, 0x5a, 0xf4
++	.byte	0x1f, 0xdd, 0xa8, 0x33, 0x88, 0x07, 0xc7, 0x31
++	.byte	0xb1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xec, 0x5f
++	.byte	0x60, 0x51, 0x7f, 0xa9, 0x19, 0xb5, 0x4a, 0x0d
++	.byte	0x2d, 0xe5, 0x7a, 0x9f, 0x93, 0xc9, 0x9c, 0xef
++	.byte	0xa0, 0xe0, 0x3b, 0x4d, 0xae, 0x2a, 0xf5, 0xb0
++	.byte	0xc8, 0xeb, 0xbb, 0x3c, 0x83, 0x53, 0x99, 0x61
++	.byte	0x17, 0x2b, 0x04, 0x7e, 0xba, 0x77, 0xd6, 0x26
++	.byte	0xe1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0c, 0x7d
++	.cstring "AES for C64x+, CRYPTOGAMS by "
++	.align	4
++___
++
++print $code;
++close STDOUT;
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/aes/asm/aes-ia64.S b/CryptoPkg/Library/OpensslLib/openssl/crypto/aes/asm/aes-ia64.S
+new file mode 100644
+index 0000000..f7f1f63
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/aes/asm/aes-ia64.S
+@@ -0,0 +1,1130 @@
++// Copyright 2004-2016 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
++// in the file LICENSE in the source distribution or at
++// https://www.openssl.org/source/license.html
++//
++// ====================================================================
++// Written by Andy Polyakov  for the OpenSSL
++// project. Rights for redistribution and usage in source and binary
++// forms are granted according to the OpenSSL license.
++// ====================================================================
++//
++// What's wrong with compiler generated code? Compiler never uses
++// variable 'shr' which is pairable with 'extr'/'dep' instructions.
++// Then it uses 'zxt' which is an I-type, but can be replaced with
++// 'and' which in turn can be assigned to M-port [there're double as
++// much M-ports as there're I-ports on Itanium 2]. By sacrificing few
++// registers for small constants (255, 24 and 16) to be used with
++// 'shr' and 'and' instructions I can achieve better ILP, Instruction
++// Level Parallelism, and performance. This code outperforms GCC 3.3
++// generated code by over factor of 2 (two), GCC 3.4 - by 70% and
++// HP C - by 40%. Measured best-case scenario, i.e. aligned
++// big-endian input, ECB timing on Itanium 2 is (18 + 13*rounds)
++// ticks per block, or 9.25 CPU cycles per byte for 128 bit key.
++
++// Version 1.2 mitigates the hazard of cache-timing attacks by
++// a) compressing S-boxes from 8KB to 2KB+256B, b) scheduling
++// references to S-boxes for L2 cache latency, c) prefetching T[ed]4
++// prior last round. As result performance dropped to (26 + 15*rounds)
++// ticks per block or 11 cycles per byte processed with 128-bit key.
++// This is ~16% deterioration. For reference Itanium 2 L1 cache has
++// 64 bytes line size and L2 - 128 bytes...
++
++.ident	"aes-ia64.S, version 1.2"
++.ident	"IA-64 ISA artwork by Andy Polyakov "
++.explicit
++.text
++
++rk0=r8;     rk1=r9;
++
++pfssave=r2;
++lcsave=r10;
++prsave=r3;
++maskff=r11;
++twenty4=r14;
++sixteen=r15;
++
++te00=r16;   te11=r17;   te22=r18;   te33=r19;
++te01=r20;   te12=r21;   te23=r22;   te30=r23;
++te02=r24;   te13=r25;   te20=r26;   te31=r27;
++te03=r28;   te10=r29;   te21=r30;   te32=r31;
++
++// these are rotating...
++t0=r32;     s0=r33;
++t1=r34;     s1=r35;
++t2=r36;     s2=r37;
++t3=r38;     s3=r39;
++
++te0=r40;    te1=r41;    te2=r42;    te3=r43;
++
++#if defined(_HPUX_SOURCE) && !defined(_LP64)
++# define ADDP	addp4
++#else
++# define ADDP	add
++#endif
++
++// Offsets from Te0
++#define TE0	0
++#define TE2	2
++#if defined(_HPUX_SOURCE) || defined(B_ENDIAN)
++#define TE1	3
++#define TE3	1
++#else
++#define TE1	1
++#define TE3	3
++#endif
++
++// This implies that AES_KEY comprises 32-bit key schedule elements
++// even on LP64 platforms.
++#ifndef	KSZ
++# define KSZ	4
++# define LDKEY	ld4
++#endif
++
++.proc	_ia64_AES_encrypt#
++// Input:	rk0-rk1
++//		te0
++//		te3	as AES_KEY->rounds!!!
++//		s0-s3
++//		maskff,twenty4,sixteen
++// Output:	r16,r20,r24,r28 as s0-s3
++// Clobber:	r16-r31,rk0-rk1,r32-r43
++.align	32
++_ia64_AES_encrypt:
++	.prologue
++	.altrp	b6
++	.body
++{ .mmi;	alloc	r16=ar.pfs,12,0,0,8
++	LDKEY	t0=[rk0],2*KSZ
++	mov	pr.rot=1<<16	}
++{ .mmi;	LDKEY	t1=[rk1],2*KSZ
++	add	te1=TE1,te0
++	add	te3=-3,te3	};;
++{ .mib;	LDKEY	t2=[rk0],2*KSZ
++	mov	ar.ec=2		}
++{ .mib;	LDKEY	t3=[rk1],2*KSZ
++	add	te2=TE2,te0
++	brp.loop.imp	.Le_top,.Le_end-16	};;
++
++{ .mmi;	xor	s0=s0,t0
++	xor	s1=s1,t1
++	mov	ar.lc=te3	}
++{ .mmi;	xor	s2=s2,t2
++	xor	s3=s3,t3
++	add	te3=TE3,te0	};;
++
++.align	32
++.Le_top:
++{ .mmi;	(p0)	LDKEY	t0=[rk0],2*KSZ		// 0/0:rk[0]
++	(p0)	and	te33=s3,maskff		// 0/0:s3&0xff
++	(p0)	extr.u	te22=s2,8,8	}	// 0/0:s2>>8&0xff
++{ .mmi; (p0)	LDKEY	t1=[rk1],2*KSZ		// 0/1:rk[1]
++	(p0)	and	te30=s0,maskff		// 0/1:s0&0xff
++	(p0)	shr.u	te00=s0,twenty4	};;	// 0/0:s0>>24
++{ .mmi;	(p0)	LDKEY	t2=[rk0],2*KSZ		// 1/2:rk[2]
++	(p0)	shladd	te33=te33,3,te3		// 1/0:te0+s0>>24
++	(p0)	extr.u	te23=s3,8,8	}	// 1/1:s3>>8&0xff
++{ .mmi;	(p0)	LDKEY	t3=[rk1],2*KSZ		// 1/3:rk[3]
++	(p0)	shladd	te30=te30,3,te3		// 1/1:te3+s0
++	(p0)	shr.u	te01=s1,twenty4	};;	// 1/1:s1>>24
++{ .mmi;	(p0)	ld4	te33=[te33]		// 2/0:te3[s3&0xff]
++	(p0)	shladd	te22=te22,3,te2		// 2/0:te2+s2>>8&0xff
++	(p0)	extr.u	te20=s0,8,8	}	// 2/2:s0>>8&0xff
++{ .mmi;	(p0)	ld4	te30=[te30]		// 2/1:te3[s0]
++	(p0)	shladd	te23=te23,3,te2		// 2/1:te2+s3>>8
++	(p0)	shr.u	te02=s2,twenty4	};;	// 2/2:s2>>24
++{ .mmi;	(p0)	ld4	te22=[te22]		// 3/0:te2[s2>>8]
++	(p0)	shladd	te20=te20,3,te2		// 3/2:te2+s0>>8
++	(p0)	extr.u	te21=s1,8,8	}	// 3/3:s1>>8&0xff
++{ .mmi;	(p0)	ld4	te23=[te23]		// 3/1:te2[s3>>8]
++	(p0)	shladd	te00=te00,3,te0		// 3/0:te0+s0>>24
++	(p0)	shr.u	te03=s3,twenty4	};;	// 3/3:s3>>24
++{ .mmi;	(p0)	ld4	te20=[te20]		// 4/2:te2[s0>>8]
++	(p0)	shladd	te21=te21,3,te2		// 4/3:te3+s2
++	(p0)	extr.u	te11=s1,16,8	}	// 4/0:s1>>16&0xff
++{ .mmi;	(p0)	ld4	te00=[te00]		// 4/0:te0[s0>>24]
++	(p0)	shladd	te01=te01,3,te0		// 4/1:te0+s1>>24
++	(p0)	shr.u	te13=s3,sixteen	};;	// 4/2:s3>>16
++{ .mmi;	(p0)	ld4	te21=[te21]		// 5/3:te2[s1>>8]
++	(p0)	shladd	te11=te11,3,te1		// 5/0:te1+s1>>16
++	(p0)	extr.u	te12=s2,16,8	}	// 5/1:s2>>16&0xff
++{ .mmi;	(p0)	ld4	te01=[te01]		// 5/1:te0[s1>>24]
++	(p0)	shladd	te02=te02,3,te0		// 5/2:te0+s2>>24
++	(p0)	and	te31=s1,maskff	};;	// 5/2:s1&0xff
++{ .mmi;	(p0)	ld4	te11=[te11]		// 6/0:te1[s1>>16]
++	(p0)	shladd	te12=te12,3,te1		// 6/1:te1+s2>>16
++	(p0)	extr.u	te10=s0,16,8	}	// 6/3:s0>>16&0xff
++{ .mmi;	(p0)	ld4	te02=[te02]		// 6/2:te0[s2>>24]
++	(p0)	shladd	te03=te03,3,te0		// 6/3:te1+s0>>16
++	(p0)	and	te32=s2,maskff	};;	// 6/3:s2&0xff
++
++{ .mmi;	(p0)	ld4	te12=[te12]		// 7/1:te1[s2>>16]
++	(p0)	shladd	te31=te31,3,te3		// 7/2:te3+s1&0xff
++	(p0)	and	te13=te13,maskff}	// 7/2:s3>>16&0xff
++{ .mmi;	(p0)	ld4	te03=[te03]		// 7/3:te0[s3>>24]
++	(p0)	shladd	te32=te32,3,te3		// 7/3:te3+s2
++	(p0)	xor	t0=t0,te33	};;	// 7/0:
++{ .mmi;	(p0)	ld4	te31=[te31]		// 8/2:te3[s1]
++	(p0)	shladd	te13=te13,3,te1		// 8/2:te1+s3>>16
++	(p0)	xor	t0=t0,te22	}	// 8/0:
++{ .mmi;	(p0)	ld4	te32=[te32]		// 8/3:te3[s2]
++	(p0)	shladd	te10=te10,3,te1		// 8/3:te1+s0>>16
++	(p0)	xor	t1=t1,te30	};;	// 8/1:
++{ .mmi;	(p0)	ld4	te13=[te13]		// 9/2:te1[s3>>16]
++	(p0)	ld4	te10=[te10]		// 9/3:te1[s0>>16]
++	(p0)	xor	t0=t0,te00	};;	// 9/0:		!L2 scheduling
++{ .mmi;	(p0)	xor	t1=t1,te23		// 10[9]/1:	
++	(p0)	xor	t2=t2,te20		// 10[9]/2:
++	(p0)	xor	t3=t3,te21	};;	// 10[9]/3:
++{ .mmi;	(p0)	xor	t0=t0,te11		// 11[10]/0:done!
++	(p0)	xor	t1=t1,te01		// 11[10]/1:
++	(p0)	xor	t2=t2,te02	};;	// 11[10]/2:	!L2 scheduling
++{ .mmi;	(p0)	xor	t3=t3,te03		// 12[10]/3:
++	(p16)	cmp.eq	p0,p17=r0,r0 	};;	// 12[10]/clear (p17)
++{ .mmi;	(p0)	xor	t1=t1,te12		// 13[11]/1:done!
++	(p0)	xor	t2=t2,te31		// 13[11]/2:
++	(p0)	xor	t3=t3,te32	}	// 13[11]/3:
++{ .mmi;	(p17)	add	te0=2048,te0		// 13[11]/
++	(p17)	add	te1=2048+64-TE1,te1};;	// 13[11]/
++{ .mib;	(p0)	xor	t2=t2,te13		// 14[12]/2:done!
++	(p17)	add	te2=2048+128-TE2,te2}	// 14[12]/
++{ .mib;	(p0)	xor	t3=t3,te10		// 14[12]/3:done!
++	(p17)	add	te3=2048+192-TE3,te3	// 14[12]/
++	br.ctop.sptk	.Le_top		};;
++.Le_end:
++
++
++{ .mmi;	ld8	te12=[te0]		// prefetch Te4
++	ld8	te31=[te1]	}
++{ .mmi;	ld8	te10=[te2]
++	ld8	te32=[te3]	}
++
++{ .mmi;	LDKEY	t0=[rk0],2*KSZ		// 0/0:rk[0]
++	and	te33=s3,maskff		// 0/0:s3&0xff
++	extr.u	te22=s2,8,8	}	// 0/0:s2>>8&0xff
++{ .mmi; LDKEY	t1=[rk1],2*KSZ		// 0/1:rk[1]
++	and	te30=s0,maskff		// 0/1:s0&0xff
++	shr.u	te00=s0,twenty4	};;	// 0/0:s0>>24
++{ .mmi;	LDKEY	t2=[rk0],2*KSZ		// 1/2:rk[2]
++	add	te33=te33,te0		// 1/0:te0+s0>>24
++	extr.u	te23=s3,8,8	}	// 1/1:s3>>8&0xff
++{ .mmi;	LDKEY	t3=[rk1],2*KSZ		// 1/3:rk[3]
++	add	te30=te30,te0		// 1/1:te0+s0
++	shr.u	te01=s1,twenty4	};;	// 1/1:s1>>24
++{ .mmi;	ld1	te33=[te33]		// 2/0:te0[s3&0xff]
++	add	te22=te22,te0		// 2/0:te0+s2>>8&0xff
++	extr.u	te20=s0,8,8	}	// 2/2:s0>>8&0xff
++{ .mmi;	ld1	te30=[te30]		// 2/1:te0[s0]
++	add	te23=te23,te0		// 2/1:te0+s3>>8
++	shr.u	te02=s2,twenty4	};;	// 2/2:s2>>24
++{ .mmi;	ld1	te22=[te22]		// 3/0:te0[s2>>8]
++	add	te20=te20,te0		// 3/2:te0+s0>>8
++	extr.u	te21=s1,8,8	}	// 3/3:s1>>8&0xff
++{ .mmi;	ld1	te23=[te23]		// 3/1:te0[s3>>8]
++	add	te00=te00,te0		// 3/0:te0+s0>>24
++	shr.u	te03=s3,twenty4	};;	// 3/3:s3>>24
++{ .mmi;	ld1	te20=[te20]		// 4/2:te0[s0>>8]
++	add	te21=te21,te0		// 4/3:te0+s2
++	extr.u	te11=s1,16,8	}	// 4/0:s1>>16&0xff
++{ .mmi;	ld1	te00=[te00]		// 4/0:te0[s0>>24]
++	add	te01=te01,te0		// 4/1:te0+s1>>24
++	shr.u	te13=s3,sixteen	};;	// 4/2:s3>>16
++{ .mmi;	ld1	te21=[te21]		// 5/3:te0[s1>>8]
++	add	te11=te11,te0		// 5/0:te0+s1>>16
++	extr.u	te12=s2,16,8	}	// 5/1:s2>>16&0xff
++{ .mmi;	ld1	te01=[te01]		// 5/1:te0[s1>>24]
++	add	te02=te02,te0		// 5/2:te0+s2>>24
++	and	te31=s1,maskff	};;	// 5/2:s1&0xff
++{ .mmi;	ld1	te11=[te11]		// 6/0:te0[s1>>16]
++	add	te12=te12,te0		// 6/1:te0+s2>>16
++	extr.u	te10=s0,16,8	}	// 6/3:s0>>16&0xff
++{ .mmi;	ld1	te02=[te02]		// 6/2:te0[s2>>24]
++	add	te03=te03,te0		// 6/3:te0+s0>>16
++	and	te32=s2,maskff	};;	// 6/3:s2&0xff
++
++{ .mmi;	ld1	te12=[te12]		// 7/1:te0[s2>>16]
++	add	te31=te31,te0		// 7/2:te0+s1&0xff
++	dep	te33=te22,te33,8,8}	// 7/0:
++{ .mmi;	ld1	te03=[te03]		// 7/3:te0[s3>>24]
++	add	te32=te32,te0		// 7/3:te0+s2
++	and	te13=te13,maskff};;	// 7/2:s3>>16&0xff
++{ .mmi;	ld1	te31=[te31]		// 8/2:te0[s1]
++	add	te13=te13,te0		// 8/2:te0+s3>>16
++	dep	te30=te23,te30,8,8}	// 8/1:
++{ .mmi;	ld1	te32=[te32]		// 8/3:te0[s2]
++	add	te10=te10,te0		// 8/3:te0+s0>>16
++	shl	te00=te00,twenty4};;	// 8/0:
++{ .mii;	ld1	te13=[te13]		// 9/2:te0[s3>>16]
++	dep	te33=te11,te33,16,8	// 9/0:
++	shl	te01=te01,twenty4};;	// 9/1:
++{ .mii;	ld1	te10=[te10]		// 10/3:te0[s0>>16]
++	dep	te31=te20,te31,8,8	// 10/2:
++	shl	te02=te02,twenty4};;	// 10/2:
++{ .mii;	xor	t0=t0,te33		// 11/0:
++	dep	te32=te21,te32,8,8	// 11/3:
++	shl	te12=te12,sixteen};;	// 11/1:
++{ .mii;	xor	r16=t0,te00		// 12/0:done!
++	dep	te31=te13,te31,16,8	// 12/2:
++	shl	te03=te03,twenty4};;	// 12/3:
++{ .mmi;	xor	t1=t1,te01		// 13/1:
++	xor	t2=t2,te02		// 13/2:
++	dep	te32=te10,te32,16,8};;	// 13/3:
++{ .mmi;	xor	t1=t1,te30		// 14/1:
++	xor	r24=t2,te31		// 14/2:done!
++	xor	t3=t3,te32	};;	// 14/3:
++{ .mib;	xor	r20=t1,te12		// 15/1:done!
++	xor	r28=t3,te03		// 15/3:done!
++	br.ret.sptk	b6	};;
++.endp	_ia64_AES_encrypt#
++
++// void AES_encrypt (const void *in,void *out,const AES_KEY *key);
++.global	AES_encrypt#
++.proc	AES_encrypt#
++.align	32
++AES_encrypt:
++	.prologue
++	.save	ar.pfs,pfssave
++{ .mmi;	alloc	pfssave=ar.pfs,3,1,12,0
++	and	out0=3,in0
++	mov	r3=ip			}
++{ .mmi;	ADDP	in0=0,in0
++	mov	loc0=psr.um
++	ADDP	out11=KSZ*60,in2	};;	// &AES_KEY->rounds
++
++{ .mmi;	ld4	out11=[out11]			// AES_KEY->rounds
++	add	out8=(AES_Te#-AES_encrypt#),r3	// Te0
++	.save	pr,prsave
++	mov	prsave=pr		}
++{ .mmi;	rum	1<<3				// clear um.ac
++	.save	ar.lc,lcsave
++	mov	lcsave=ar.lc		};;
++
++	.body
++#if defined(_HPUX_SOURCE)	// HPUX is big-endian, cut 15+15 cycles...
++{ .mib; cmp.ne	p6,p0=out0,r0
++	add	out0=4,in0
++(p6)	br.dpnt.many	.Le_i_unaligned	};;
++
++{ .mmi;	ld4	out1=[in0],8		// s0
++	and	out9=3,in1
++	mov	twenty4=24		}
++{ .mmi;	ld4	out3=[out0],8		// s1
++	ADDP	rk0=0,in2
++	mov	sixteen=16		};;
++{ .mmi;	ld4	out5=[in0]		// s2
++	cmp.ne	p6,p0=out9,r0
++	mov	maskff=0xff		}
++{ .mmb;	ld4	out7=[out0]		// s3
++	ADDP	rk1=KSZ,in2
++	br.call.sptk.many	b6=_ia64_AES_encrypt	};;
++
++{ .mib;	ADDP	in0=4,in1
++	ADDP	in1=0,in1
++(p6)	br.spnt	.Le_o_unaligned		};;
++
++{ .mii;	mov	psr.um=loc0
++	mov	ar.pfs=pfssave
++	mov	ar.lc=lcsave		};;
++{ .mmi;	st4	[in1]=r16,8		// s0
++	st4	[in0]=r20,8		// s1
++	mov	pr=prsave,0x1ffff	};;
++{ .mmb;	st4	[in1]=r24		// s2
++	st4	[in0]=r28		// s3
++	br.ret.sptk.many	b0	};;
++#endif
++
++.align	32
++.Le_i_unaligned:
++{ .mmi;	add	out0=1,in0
++	add	out2=2,in0
++	add	out4=3,in0	};;
++{ .mmi;	ld1	r16=[in0],4
++	ld1	r17=[out0],4	}//;;
++{ .mmi;	ld1	r18=[out2],4
++	ld1	out1=[out4],4	};;	// s0
++{ .mmi;	ld1	r20=[in0],4
++	ld1	r21=[out0],4	}//;;
++{ .mmi;	ld1	r22=[out2],4
++	ld1	out3=[out4],4	};;	// s1
++{ .mmi;	ld1	r24=[in0],4
++	ld1	r25=[out0],4	}//;;
++{ .mmi;	ld1	r26=[out2],4
++	ld1	out5=[out4],4	};;	// s2
++{ .mmi;	ld1	r28=[in0]
++	ld1	r29=[out0]	}//;;
++{ .mmi;	ld1	r30=[out2]
++	ld1	out7=[out4]	};;	// s3
++
++{ .mii;
++	dep	out1=r16,out1,24,8	//;;
++	dep	out3=r20,out3,24,8	}//;;
++{ .mii;	ADDP	rk0=0,in2
++	dep	out5=r24,out5,24,8	//;;
++	dep	out7=r28,out7,24,8	};;
++{ .mii;	ADDP	rk1=KSZ,in2
++	dep	out1=r17,out1,16,8	//;;
++	dep	out3=r21,out3,16,8	}//;;
++{ .mii;	mov	twenty4=24
++	dep	out5=r25,out5,16,8	//;;
++	dep	out7=r29,out7,16,8	};;
++{ .mii;	mov	sixteen=16
++	dep	out1=r18,out1,8,8	//;;
++	dep	out3=r22,out3,8,8	}//;;
++{ .mii;	mov	maskff=0xff
++	dep	out5=r26,out5,8,8	//;;
++	dep	out7=r30,out7,8,8	};;
++
++{ .mib;	br.call.sptk.many	b6=_ia64_AES_encrypt	};;
++
++.Le_o_unaligned:
++{ .mii;	ADDP	out0=0,in1
++	extr.u	r17=r16,8,8			// s0
++	shr.u	r19=r16,twenty4		}//;;
++{ .mii;	ADDP	out1=1,in1
++	extr.u	r18=r16,16,8
++	shr.u	r23=r20,twenty4		}//;;	// s1
++{ .mii;	ADDP	out2=2,in1
++	extr.u	r21=r20,8,8
++	shr.u	r22=r20,sixteen		}//;;
++{ .mii;	ADDP	out3=3,in1
++	extr.u	r25=r24,8,8			// s2
++	shr.u	r27=r24,twenty4		};;
++{ .mii;	st1	[out3]=r16,4
++	extr.u	r26=r24,16,8
++	shr.u	r31=r28,twenty4		}//;;	// s3
++{ .mii;	st1	[out2]=r17,4
++	extr.u	r29=r28,8,8
++	shr.u	r30=r28,sixteen		}//;;
++
++{ .mmi;	st1	[out1]=r18,4
++	st1	[out0]=r19,4		};;
++{ .mmi;	st1	[out3]=r20,4
++	st1	[out2]=r21,4		}//;;
++{ .mmi;	st1	[out1]=r22,4
++	st1	[out0]=r23,4		};;
++{ .mmi;	st1	[out3]=r24,4
++	st1	[out2]=r25,4
++	mov	pr=prsave,0x1ffff	}//;;
++{ .mmi;	st1	[out1]=r26,4
++	st1	[out0]=r27,4
++	mov	ar.pfs=pfssave		};;
++{ .mmi;	st1	[out3]=r28
++	st1	[out2]=r29
++	mov	ar.lc=lcsave		}//;;
++{ .mmi;	st1	[out1]=r30
++	st1	[out0]=r31		}
++{ .mfb;	mov	psr.um=loc0			// restore user mask
++	br.ret.sptk.many	b0	};;
++.endp	AES_encrypt#
++
++// *AES_decrypt are autogenerated by the following script:
++#if 0
++#!/usr/bin/env perl
++print "// *AES_decrypt are autogenerated by the following script:\n#if 0\n";
++open(PROG,'<'.$0); while() { print; } close(PROG);
++print "#endif\n";
++while(<>) {
++	$process=1	if (/\.proc\s+_ia64_AES_encrypt/);
++	next		if (!$process);
++
++	#s/te00=s0/td00=s0/;	s/te00/td00/g;
++	s/te11=s1/td13=s3/;	s/te11/td13/g;
++	#s/te22=s2/td22=s2/;	s/te22/td22/g;
++	s/te33=s3/td31=s1/;	s/te33/td31/g;
++
++	#s/te01=s1/td01=s1/;	s/te01/td01/g;
++	s/te12=s2/td10=s0/;	s/te12/td10/g;
++	#s/te23=s3/td23=s3/;	s/te23/td23/g;
++	s/te30=s0/td32=s2/;	s/te30/td32/g;
++
++	#s/te02=s2/td02=s2/;	s/te02/td02/g;
++	s/te13=s3/td11=s1/;	s/te13/td11/g;
++	#s/te20=s0/td20=s0/;	s/te20/td20/g;
++	s/te31=s1/td33=s3/;	s/te31/td33/g;
++
++	#s/te03=s3/td03=s3/;	s/te03/td03/g;
++	s/te10=s0/td12=s2/;	s/te10/td12/g;
++	#s/te21=s1/td21=s1/;	s/te21/td21/g;
++	s/te32=s2/td30=s0/;	s/te32/td30/g;
++
++	s/td/te/g;
++
++	s/AES_encrypt/AES_decrypt/g;
++	s/\.Le_/.Ld_/g;
++	s/AES_Te#/AES_Td#/g;
++
++	print;
++
++	exit		if (/\.endp\s+AES_decrypt/);
++}
++#endif
++.proc	_ia64_AES_decrypt#
++// Input:	rk0-rk1
++//		te0
++//		te3	as AES_KEY->rounds!!!
++//		s0-s3
++//		maskff,twenty4,sixteen
++// Output:	r16,r20,r24,r28 as s0-s3
++// Clobber:	r16-r31,rk0-rk1,r32-r43
++.align	32
++_ia64_AES_decrypt:
++	.prologue
++	.altrp	b6
++	.body
++{ .mmi;	alloc	r16=ar.pfs,12,0,0,8
++	LDKEY	t0=[rk0],2*KSZ
++	mov	pr.rot=1<<16	}
++{ .mmi;	LDKEY	t1=[rk1],2*KSZ
++	add	te1=TE1,te0
++	add	te3=-3,te3	};;
++{ .mib;	LDKEY	t2=[rk0],2*KSZ
++	mov	ar.ec=2		}
++{ .mib;	LDKEY	t3=[rk1],2*KSZ
++	add	te2=TE2,te0
++	brp.loop.imp	.Ld_top,.Ld_end-16	};;
++
++{ .mmi;	xor	s0=s0,t0
++	xor	s1=s1,t1
++	mov	ar.lc=te3	}
++{ .mmi;	xor	s2=s2,t2
++	xor	s3=s3,t3
++	add	te3=TE3,te0	};;
++
++.align	32
++.Ld_top:
++{ .mmi;	(p0)	LDKEY	t0=[rk0],2*KSZ		// 0/0:rk[0]
++	(p0)	and	te31=s1,maskff		// 0/0:s3&0xff
++	(p0)	extr.u	te22=s2,8,8	}	// 0/0:s2>>8&0xff
++{ .mmi; (p0)	LDKEY	t1=[rk1],2*KSZ		// 0/1:rk[1]
++	(p0)	and	te32=s2,maskff		// 0/1:s0&0xff
++	(p0)	shr.u	te00=s0,twenty4	};;	// 0/0:s0>>24
++{ .mmi;	(p0)	LDKEY	t2=[rk0],2*KSZ		// 1/2:rk[2]
++	(p0)	shladd	te31=te31,3,te3		// 1/0:te0+s0>>24
++	(p0)	extr.u	te23=s3,8,8	}	// 1/1:s3>>8&0xff
++{ .mmi;	(p0)	LDKEY	t3=[rk1],2*KSZ		// 1/3:rk[3]
++	(p0)	shladd	te32=te32,3,te3		// 1/1:te3+s0
++	(p0)	shr.u	te01=s1,twenty4	};;	// 1/1:s1>>24
++{ .mmi;	(p0)	ld4	te31=[te31]		// 2/0:te3[s3&0xff]
++	(p0)	shladd	te22=te22,3,te2		// 2/0:te2+s2>>8&0xff
++	(p0)	extr.u	te20=s0,8,8	}	// 2/2:s0>>8&0xff
++{ .mmi;	(p0)	ld4	te32=[te32]		// 2/1:te3[s0]
++	(p0)	shladd	te23=te23,3,te2		// 2/1:te2+s3>>8
++	(p0)	shr.u	te02=s2,twenty4	};;	// 2/2:s2>>24
++{ .mmi;	(p0)	ld4	te22=[te22]		// 3/0:te2[s2>>8]
++	(p0)	shladd	te20=te20,3,te2		// 3/2:te2+s0>>8
++	(p0)	extr.u	te21=s1,8,8	}	// 3/3:s1>>8&0xff
++{ .mmi;	(p0)	ld4	te23=[te23]		// 3/1:te2[s3>>8]
++	(p0)	shladd	te00=te00,3,te0		// 3/0:te0+s0>>24
++	(p0)	shr.u	te03=s3,twenty4	};;	// 3/3:s3>>24
++{ .mmi;	(p0)	ld4	te20=[te20]		// 4/2:te2[s0>>8]
++	(p0)	shladd	te21=te21,3,te2		// 4/3:te3+s2
++	(p0)	extr.u	te13=s3,16,8	}	// 4/0:s1>>16&0xff
++{ .mmi;	(p0)	ld4	te00=[te00]		// 4/0:te0[s0>>24]
++	(p0)	shladd	te01=te01,3,te0		// 4/1:te0+s1>>24
++	(p0)	shr.u	te11=s1,sixteen	};;	// 4/2:s3>>16
++{ .mmi;	(p0)	ld4	te21=[te21]		// 5/3:te2[s1>>8]
++	(p0)	shladd	te13=te13,3,te1		// 5/0:te1+s1>>16
++	(p0)	extr.u	te10=s0,16,8	}	// 5/1:s2>>16&0xff
++{ .mmi;	(p0)	ld4	te01=[te01]		// 5/1:te0[s1>>24]
++	(p0)	shladd	te02=te02,3,te0		// 5/2:te0+s2>>24
++	(p0)	and	te33=s3,maskff	};;	// 5/2:s1&0xff
++{ .mmi;	(p0)	ld4	te13=[te13]		// 6/0:te1[s1>>16]
++	(p0)	shladd	te10=te10,3,te1		// 6/1:te1+s2>>16
++	(p0)	extr.u	te12=s2,16,8	}	// 6/3:s0>>16&0xff
++{ .mmi;	(p0)	ld4	te02=[te02]		// 6/2:te0[s2>>24]
++	(p0)	shladd	te03=te03,3,te0		// 6/3:te1+s0>>16
++	(p0)	and	te30=s0,maskff	};;	// 6/3:s2&0xff
++
++{ .mmi;	(p0)	ld4	te10=[te10]		// 7/1:te1[s2>>16]
++	(p0)	shladd	te33=te33,3,te3		// 7/2:te3+s1&0xff
++	(p0)	and	te11=te11,maskff}	// 7/2:s3>>16&0xff
++{ .mmi;	(p0)	ld4	te03=[te03]		// 7/3:te0[s3>>24]
++	(p0)	shladd	te30=te30,3,te3		// 7/3:te3+s2
++	(p0)	xor	t0=t0,te31	};;	// 7/0:
++{ .mmi;	(p0)	ld4	te33=[te33]		// 8/2:te3[s1]
++	(p0)	shladd	te11=te11,3,te1		// 8/2:te1+s3>>16
++	(p0)	xor	t0=t0,te22	}	// 8/0:
++{ .mmi;	(p0)	ld4	te30=[te30]		// 8/3:te3[s2]
++	(p0)	shladd	te12=te12,3,te1		// 8/3:te1+s0>>16
++	(p0)	xor	t1=t1,te32	};;	// 8/1:
++{ .mmi;	(p0)	ld4	te11=[te11]		// 9/2:te1[s3>>16]
++	(p0)	ld4	te12=[te12]		// 9/3:te1[s0>>16]
++	(p0)	xor	t0=t0,te00	};;	// 9/0:		!L2 scheduling
++{ .mmi;	(p0)	xor	t1=t1,te23		// 10[9]/1:	
++	(p0)	xor	t2=t2,te20		// 10[9]/2:
++	(p0)	xor	t3=t3,te21	};;	// 10[9]/3:
++{ .mmi;	(p0)	xor	t0=t0,te13		// 11[10]/0:done!
++	(p0)	xor	t1=t1,te01		// 11[10]/1:
++	(p0)	xor	t2=t2,te02	};;	// 11[10]/2:	!L2 scheduling
++{ .mmi;	(p0)	xor	t3=t3,te03		// 12[10]/3:
++	(p16)	cmp.eq	p0,p17=r0,r0 	};;	// 12[10]/clear (p17)
++{ .mmi;	(p0)	xor	t1=t1,te10		// 13[11]/1:done!
++	(p0)	xor	t2=t2,te33		// 13[11]/2:
++	(p0)	xor	t3=t3,te30	}	// 13[11]/3:
++{ .mmi;	(p17)	add	te0=2048,te0		// 13[11]/
++	(p17)	add	te1=2048+64-TE1,te1};;	// 13[11]/
++{ .mib;	(p0)	xor	t2=t2,te11		// 14[12]/2:done!
++	(p17)	add	te2=2048+128-TE2,te2}	// 14[12]/
++{ .mib;	(p0)	xor	t3=t3,te12		// 14[12]/3:done!
++	(p17)	add	te3=2048+192-TE3,te3	// 14[12]/
++	br.ctop.sptk	.Ld_top		};;
++.Ld_end:
++
++
++{ .mmi;	ld8	te10=[te0]		// prefetch Td4
++	ld8	te33=[te1]	}
++{ .mmi;	ld8	te12=[te2]
++	ld8	te30=[te3]	}
++
++{ .mmi;	LDKEY	t0=[rk0],2*KSZ		// 0/0:rk[0]
++	and	te31=s1,maskff		// 0/0:s3&0xff
++	extr.u	te22=s2,8,8	}	// 0/0:s2>>8&0xff
++{ .mmi; LDKEY	t1=[rk1],2*KSZ		// 0/1:rk[1]
++	and	te32=s2,maskff		// 0/1:s0&0xff
++	shr.u	te00=s0,twenty4	};;	// 0/0:s0>>24
++{ .mmi;	LDKEY	t2=[rk0],2*KSZ		// 1/2:rk[2]
++	add	te31=te31,te0		// 1/0:te0+s0>>24
++	extr.u	te23=s3,8,8	}	// 1/1:s3>>8&0xff
++{ .mmi;	LDKEY	t3=[rk1],2*KSZ		// 1/3:rk[3]
++	add	te32=te32,te0		// 1/1:te0+s0
++	shr.u	te01=s1,twenty4	};;	// 1/1:s1>>24
++{ .mmi;	ld1	te31=[te31]		// 2/0:te0[s3&0xff]
++	add	te22=te22,te0		// 2/0:te0+s2>>8&0xff
++	extr.u	te20=s0,8,8	}	// 2/2:s0>>8&0xff
++{ .mmi;	ld1	te32=[te32]		// 2/1:te0[s0]
++	add	te23=te23,te0		// 2/1:te0+s3>>8
++	shr.u	te02=s2,twenty4	};;	// 2/2:s2>>24
++{ .mmi;	ld1	te22=[te22]		// 3/0:te0[s2>>8]
++	add	te20=te20,te0		// 3/2:te0+s0>>8
++	extr.u	te21=s1,8,8	}	// 3/3:s1>>8&0xff
++{ .mmi;	ld1	te23=[te23]		// 3/1:te0[s3>>8]
++	add	te00=te00,te0		// 3/0:te0+s0>>24
++	shr.u	te03=s3,twenty4	};;	// 3/3:s3>>24
++{ .mmi;	ld1	te20=[te20]		// 4/2:te0[s0>>8]
++	add	te21=te21,te0		// 4/3:te0+s2
++	extr.u	te13=s3,16,8	}	// 4/0:s1>>16&0xff
++{ .mmi;	ld1	te00=[te00]		// 4/0:te0[s0>>24]
++	add	te01=te01,te0		// 4/1:te0+s1>>24
++	shr.u	te11=s1,sixteen	};;	// 4/2:s3>>16
++{ .mmi;	ld1	te21=[te21]		// 5/3:te0[s1>>8]
++	add	te13=te13,te0		// 5/0:te0+s1>>16
++	extr.u	te10=s0,16,8	}	// 5/1:s2>>16&0xff
++{ .mmi;	ld1	te01=[te01]		// 5/1:te0[s1>>24]
++	add	te02=te02,te0		// 5/2:te0+s2>>24
++	and	te33=s3,maskff	};;	// 5/2:s1&0xff
++{ .mmi;	ld1	te13=[te13]		// 6/0:te0[s1>>16]
++	add	te10=te10,te0		// 6/1:te0+s2>>16
++	extr.u	te12=s2,16,8	}	// 6/3:s0>>16&0xff
++{ .mmi;	ld1	te02=[te02]		// 6/2:te0[s2>>24]
++	add	te03=te03,te0		// 6/3:te0+s0>>16
++	and	te30=s0,maskff	};;	// 6/3:s2&0xff
++
++{ .mmi;	ld1	te10=[te10]		// 7/1:te0[s2>>16]
++	add	te33=te33,te0		// 7/2:te0+s1&0xff
++	dep	te31=te22,te31,8,8}	// 7/0:
++{ .mmi;	ld1	te03=[te03]		// 7/3:te0[s3>>24]
++	add	te30=te30,te0		// 7/3:te0+s2
++	and	te11=te11,maskff};;	// 7/2:s3>>16&0xff
++{ .mmi;	ld1	te33=[te33]		// 8/2:te0[s1]
++	add	te11=te11,te0		// 8/2:te0+s3>>16
++	dep	te32=te23,te32,8,8}	// 8/1:
++{ .mmi;	ld1	te30=[te30]		// 8/3:te0[s2]
++	add	te12=te12,te0		// 8/3:te0+s0>>16
++	shl	te00=te00,twenty4};;	// 8/0:
++{ .mii;	ld1	te11=[te11]		// 9/2:te0[s3>>16]
++	dep	te31=te13,te31,16,8	// 9/0:
++	shl	te01=te01,twenty4};;	// 9/1:
++{ .mii;	ld1	te12=[te12]		// 10/3:te0[s0>>16]
++	dep	te33=te20,te33,8,8	// 10/2:
++	shl	te02=te02,twenty4};;	// 10/2:
++{ .mii;	xor	t0=t0,te31		// 11/0:
++	dep	te30=te21,te30,8,8	// 11/3:
++	shl	te10=te10,sixteen};;	// 11/1:
++{ .mii;	xor	r16=t0,te00		// 12/0:done!
++	dep	te33=te11,te33,16,8	// 12/2:
++	shl	te03=te03,twenty4};;	// 12/3:
++{ .mmi;	xor	t1=t1,te01		// 13/1:
++	xor	t2=t2,te02		// 13/2:
++	dep	te30=te12,te30,16,8};;	// 13/3:
++{ .mmi;	xor	t1=t1,te32		// 14/1:
++	xor	r24=t2,te33		// 14/2:done!
++	xor	t3=t3,te30	};;	// 14/3:
++{ .mib;	xor	r20=t1,te10		// 15/1:done!
++	xor	r28=t3,te03		// 15/3:done!
++	br.ret.sptk	b6	};;
++.endp	_ia64_AES_decrypt#
++
++// void AES_decrypt (const void *in,void *out,const AES_KEY *key);
++.global	AES_decrypt#
++.proc	AES_decrypt#
++.align	32
++AES_decrypt:
++	.prologue
++	.save	ar.pfs,pfssave
++{ .mmi;	alloc	pfssave=ar.pfs,3,1,12,0
++	and	out0=3,in0
++	mov	r3=ip			}
++{ .mmi;	ADDP	in0=0,in0
++	mov	loc0=psr.um
++	ADDP	out11=KSZ*60,in2	};;	// &AES_KEY->rounds
++
++{ .mmi;	ld4	out11=[out11]			// AES_KEY->rounds
++	add	out8=(AES_Td#-AES_decrypt#),r3	// Te0
++	.save	pr,prsave
++	mov	prsave=pr		}
++{ .mmi;	rum	1<<3				// clear um.ac
++	.save	ar.lc,lcsave
++	mov	lcsave=ar.lc		};;
++
++	.body
++#if defined(_HPUX_SOURCE)	// HPUX is big-endian, cut 15+15 cycles...
++{ .mib; cmp.ne	p6,p0=out0,r0
++	add	out0=4,in0
++(p6)	br.dpnt.many	.Ld_i_unaligned	};;
++
++{ .mmi;	ld4	out1=[in0],8		// s0
++	and	out9=3,in1
++	mov	twenty4=24		}
++{ .mmi;	ld4	out3=[out0],8		// s1
++	ADDP	rk0=0,in2
++	mov	sixteen=16		};;
++{ .mmi;	ld4	out5=[in0]		// s2
++	cmp.ne	p6,p0=out9,r0
++	mov	maskff=0xff		}
++{ .mmb;	ld4	out7=[out0]		// s3
++	ADDP	rk1=KSZ,in2
++	br.call.sptk.many	b6=_ia64_AES_decrypt	};;
++
++{ .mib;	ADDP	in0=4,in1
++	ADDP	in1=0,in1
++(p6)	br.spnt	.Ld_o_unaligned		};;
++
++{ .mii;	mov	psr.um=loc0
++	mov	ar.pfs=pfssave
++	mov	ar.lc=lcsave		};;
++{ .mmi;	st4	[in1]=r16,8		// s0
++	st4	[in0]=r20,8		// s1
++	mov	pr=prsave,0x1ffff	};;
++{ .mmb;	st4	[in1]=r24		// s2
++	st4	[in0]=r28		// s3
++	br.ret.sptk.many	b0	};;
++#endif
++
++.align	32
++.Ld_i_unaligned:
++{ .mmi;	add	out0=1,in0
++	add	out2=2,in0
++	add	out4=3,in0	};;
++{ .mmi;	ld1	r16=[in0],4
++	ld1	r17=[out0],4	}//;;
++{ .mmi;	ld1	r18=[out2],4
++	ld1	out1=[out4],4	};;	// s0
++{ .mmi;	ld1	r20=[in0],4
++	ld1	r21=[out0],4	}//;;
++{ .mmi;	ld1	r22=[out2],4
++	ld1	out3=[out4],4	};;	// s1
++{ .mmi;	ld1	r24=[in0],4
++	ld1	r25=[out0],4	}//;;
++{ .mmi;	ld1	r26=[out2],4
++	ld1	out5=[out4],4	};;	// s2
++{ .mmi;	ld1	r28=[in0]
++	ld1	r29=[out0]	}//;;
++{ .mmi;	ld1	r30=[out2]
++	ld1	out7=[out4]	};;	// s3
++
++{ .mii;
++	dep	out1=r16,out1,24,8	//;;
++	dep	out3=r20,out3,24,8	}//;;
++{ .mii;	ADDP	rk0=0,in2
++	dep	out5=r24,out5,24,8	//;;
++	dep	out7=r28,out7,24,8	};;
++{ .mii;	ADDP	rk1=KSZ,in2
++	dep	out1=r17,out1,16,8	//;;
++	dep	out3=r21,out3,16,8	}//;;
++{ .mii;	mov	twenty4=24
++	dep	out5=r25,out5,16,8	//;;
++	dep	out7=r29,out7,16,8	};;
++{ .mii;	mov	sixteen=16
++	dep	out1=r18,out1,8,8	//;;
++	dep	out3=r22,out3,8,8	}//;;
++{ .mii;	mov	maskff=0xff
++	dep	out5=r26,out5,8,8	//;;
++	dep	out7=r30,out7,8,8	};;
++
++{ .mib;	br.call.sptk.many	b6=_ia64_AES_decrypt	};;
++
++.Ld_o_unaligned:
++{ .mii;	ADDP	out0=0,in1
++	extr.u	r17=r16,8,8			// s0
++	shr.u	r19=r16,twenty4		}//;;
++{ .mii;	ADDP	out1=1,in1
++	extr.u	r18=r16,16,8
++	shr.u	r23=r20,twenty4		}//;;	// s1
++{ .mii;	ADDP	out2=2,in1
++	extr.u	r21=r20,8,8
++	shr.u	r22=r20,sixteen		}//;;
++{ .mii;	ADDP	out3=3,in1
++	extr.u	r25=r24,8,8			// s2
++	shr.u	r27=r24,twenty4		};;
++{ .mii;	st1	[out3]=r16,4
++	extr.u	r26=r24,16,8
++	shr.u	r31=r28,twenty4		}//;;	// s3
++{ .mii;	st1	[out2]=r17,4
++	extr.u	r29=r28,8,8
++	shr.u	r30=r28,sixteen		}//;;
++
++{ .mmi;	st1	[out1]=r18,4
++	st1	[out0]=r19,4		};;
++{ .mmi;	st1	[out3]=r20,4
++	st1	[out2]=r21,4		}//;;
++{ .mmi;	st1	[out1]=r22,4
++	st1	[out0]=r23,4		};;
++{ .mmi;	st1	[out3]=r24,4
++	st1	[out2]=r25,4
++	mov	pr=prsave,0x1ffff	}//;;
++{ .mmi;	st1	[out1]=r26,4
++	st1	[out0]=r27,4
++	mov	ar.pfs=pfssave		};;
++{ .mmi;	st1	[out3]=r28
++	st1	[out2]=r29
++	mov	ar.lc=lcsave		}//;;
++{ .mmi;	st1	[out1]=r30
++	st1	[out0]=r31		}
++{ .mfb;	mov	psr.um=loc0			// restore user mask
++	br.ret.sptk.many	b0	};;
++.endp	AES_decrypt#
++
++// leave it in .text segment...
++.align	64
++.global	AES_Te#
++.type	AES_Te#,@object
++AES_Te:	data4	0xc66363a5,0xc66363a5, 0xf87c7c84,0xf87c7c84
++	data4	0xee777799,0xee777799, 0xf67b7b8d,0xf67b7b8d
++	data4	0xfff2f20d,0xfff2f20d, 0xd66b6bbd,0xd66b6bbd
++	data4	0xde6f6fb1,0xde6f6fb1, 0x91c5c554,0x91c5c554
++	data4	0x60303050,0x60303050, 0x02010103,0x02010103
++	data4	0xce6767a9,0xce6767a9, 0x562b2b7d,0x562b2b7d
++	data4	0xe7fefe19,0xe7fefe19, 0xb5d7d762,0xb5d7d762
++	data4	0x4dababe6,0x4dababe6, 0xec76769a,0xec76769a
++	data4	0x8fcaca45,0x8fcaca45, 0x1f82829d,0x1f82829d
++	data4	0x89c9c940,0x89c9c940, 0xfa7d7d87,0xfa7d7d87
++	data4	0xeffafa15,0xeffafa15, 0xb25959eb,0xb25959eb
++	data4	0x8e4747c9,0x8e4747c9, 0xfbf0f00b,0xfbf0f00b
++	data4	0x41adadec,0x41adadec, 0xb3d4d467,0xb3d4d467
++	data4	0x5fa2a2fd,0x5fa2a2fd, 0x45afafea,0x45afafea
++	data4	0x239c9cbf,0x239c9cbf, 0x53a4a4f7,0x53a4a4f7
++	data4	0xe4727296,0xe4727296, 0x9bc0c05b,0x9bc0c05b
++	data4	0x75b7b7c2,0x75b7b7c2, 0xe1fdfd1c,0xe1fdfd1c
++	data4	0x3d9393ae,0x3d9393ae, 0x4c26266a,0x4c26266a
++	data4	0x6c36365a,0x6c36365a, 0x7e3f3f41,0x7e3f3f41
++	data4	0xf5f7f702,0xf5f7f702, 0x83cccc4f,0x83cccc4f
++	data4	0x6834345c,0x6834345c, 0x51a5a5f4,0x51a5a5f4
++	data4	0xd1e5e534,0xd1e5e534, 0xf9f1f108,0xf9f1f108
++	data4	0xe2717193,0xe2717193, 0xabd8d873,0xabd8d873
++	data4	0x62313153,0x62313153, 0x2a15153f,0x2a15153f
++	data4	0x0804040c,0x0804040c, 0x95c7c752,0x95c7c752
++	data4	0x46232365,0x46232365, 0x9dc3c35e,0x9dc3c35e
++	data4	0x30181828,0x30181828, 0x379696a1,0x379696a1
++	data4	0x0a05050f,0x0a05050f, 0x2f9a9ab5,0x2f9a9ab5
++	data4	0x0e070709,0x0e070709, 0x24121236,0x24121236
++	data4	0x1b80809b,0x1b80809b, 0xdfe2e23d,0xdfe2e23d
++	data4	0xcdebeb26,0xcdebeb26, 0x4e272769,0x4e272769
++	data4	0x7fb2b2cd,0x7fb2b2cd, 0xea75759f,0xea75759f
++	data4	0x1209091b,0x1209091b, 0x1d83839e,0x1d83839e
++	data4	0x582c2c74,0x582c2c74, 0x341a1a2e,0x341a1a2e
++	data4	0x361b1b2d,0x361b1b2d, 0xdc6e6eb2,0xdc6e6eb2
++	data4	0xb45a5aee,0xb45a5aee, 0x5ba0a0fb,0x5ba0a0fb
++	data4	0xa45252f6,0xa45252f6, 0x763b3b4d,0x763b3b4d
++	data4	0xb7d6d661,0xb7d6d661, 0x7db3b3ce,0x7db3b3ce
++	data4	0x5229297b,0x5229297b, 0xdde3e33e,0xdde3e33e
++	data4	0x5e2f2f71,0x5e2f2f71, 0x13848497,0x13848497
++	data4	0xa65353f5,0xa65353f5, 0xb9d1d168,0xb9d1d168
++	data4	0x00000000,0x00000000, 0xc1eded2c,0xc1eded2c
++	data4	0x40202060,0x40202060, 0xe3fcfc1f,0xe3fcfc1f
++	data4	0x79b1b1c8,0x79b1b1c8, 0xb65b5bed,0xb65b5bed
++	data4	0xd46a6abe,0xd46a6abe, 0x8dcbcb46,0x8dcbcb46
++	data4	0x67bebed9,0x67bebed9, 0x7239394b,0x7239394b
++	data4	0x944a4ade,0x944a4ade, 0x984c4cd4,0x984c4cd4
++	data4	0xb05858e8,0xb05858e8, 0x85cfcf4a,0x85cfcf4a
++	data4	0xbbd0d06b,0xbbd0d06b, 0xc5efef2a,0xc5efef2a
++	data4	0x4faaaae5,0x4faaaae5, 0xedfbfb16,0xedfbfb16
++	data4	0x864343c5,0x864343c5, 0x9a4d4dd7,0x9a4d4dd7
++	data4	0x66333355,0x66333355, 0x11858594,0x11858594
++	data4	0x8a4545cf,0x8a4545cf, 0xe9f9f910,0xe9f9f910
++	data4	0x04020206,0x04020206, 0xfe7f7f81,0xfe7f7f81
++	data4	0xa05050f0,0xa05050f0, 0x783c3c44,0x783c3c44
++	data4	0x259f9fba,0x259f9fba, 0x4ba8a8e3,0x4ba8a8e3
++	data4	0xa25151f3,0xa25151f3, 0x5da3a3fe,0x5da3a3fe
++	data4	0x804040c0,0x804040c0, 0x058f8f8a,0x058f8f8a
++	data4	0x3f9292ad,0x3f9292ad, 0x219d9dbc,0x219d9dbc
++	data4	0x70383848,0x70383848, 0xf1f5f504,0xf1f5f504
++	data4	0x63bcbcdf,0x63bcbcdf, 0x77b6b6c1,0x77b6b6c1
++	data4	0xafdada75,0xafdada75, 0x42212163,0x42212163
++	data4	0x20101030,0x20101030, 0xe5ffff1a,0xe5ffff1a
++	data4	0xfdf3f30e,0xfdf3f30e, 0xbfd2d26d,0xbfd2d26d
++	data4	0x81cdcd4c,0x81cdcd4c, 0x180c0c14,0x180c0c14
++	data4	0x26131335,0x26131335, 0xc3ecec2f,0xc3ecec2f
++	data4	0xbe5f5fe1,0xbe5f5fe1, 0x359797a2,0x359797a2
++	data4	0x884444cc,0x884444cc, 0x2e171739,0x2e171739
++	data4	0x93c4c457,0x93c4c457, 0x55a7a7f2,0x55a7a7f2
++	data4	0xfc7e7e82,0xfc7e7e82, 0x7a3d3d47,0x7a3d3d47
++	data4	0xc86464ac,0xc86464ac, 0xba5d5de7,0xba5d5de7
++	data4	0x3219192b,0x3219192b, 0xe6737395,0xe6737395
++	data4	0xc06060a0,0xc06060a0, 0x19818198,0x19818198
++	data4	0x9e4f4fd1,0x9e4f4fd1, 0xa3dcdc7f,0xa3dcdc7f
++	data4	0x44222266,0x44222266, 0x542a2a7e,0x542a2a7e
++	data4	0x3b9090ab,0x3b9090ab, 0x0b888883,0x0b888883
++	data4	0x8c4646ca,0x8c4646ca, 0xc7eeee29,0xc7eeee29
++	data4	0x6bb8b8d3,0x6bb8b8d3, 0x2814143c,0x2814143c
++	data4	0xa7dede79,0xa7dede79, 0xbc5e5ee2,0xbc5e5ee2
++	data4	0x160b0b1d,0x160b0b1d, 0xaddbdb76,0xaddbdb76
++	data4	0xdbe0e03b,0xdbe0e03b, 0x64323256,0x64323256
++	data4	0x743a3a4e,0x743a3a4e, 0x140a0a1e,0x140a0a1e
++	data4	0x924949db,0x924949db, 0x0c06060a,0x0c06060a
++	data4	0x4824246c,0x4824246c, 0xb85c5ce4,0xb85c5ce4
++	data4	0x9fc2c25d,0x9fc2c25d, 0xbdd3d36e,0xbdd3d36e
++	data4	0x43acacef,0x43acacef, 0xc46262a6,0xc46262a6
++	data4	0x399191a8,0x399191a8, 0x319595a4,0x319595a4
++	data4	0xd3e4e437,0xd3e4e437, 0xf279798b,0xf279798b
++	data4	0xd5e7e732,0xd5e7e732, 0x8bc8c843,0x8bc8c843
++	data4	0x6e373759,0x6e373759, 0xda6d6db7,0xda6d6db7
++	data4	0x018d8d8c,0x018d8d8c, 0xb1d5d564,0xb1d5d564
++	data4	0x9c4e4ed2,0x9c4e4ed2, 0x49a9a9e0,0x49a9a9e0
++	data4	0xd86c6cb4,0xd86c6cb4, 0xac5656fa,0xac5656fa
++	data4	0xf3f4f407,0xf3f4f407, 0xcfeaea25,0xcfeaea25
++	data4	0xca6565af,0xca6565af, 0xf47a7a8e,0xf47a7a8e
++	data4	0x47aeaee9,0x47aeaee9, 0x10080818,0x10080818
++	data4	0x6fbabad5,0x6fbabad5, 0xf0787888,0xf0787888
++	data4	0x4a25256f,0x4a25256f, 0x5c2e2e72,0x5c2e2e72
++	data4	0x381c1c24,0x381c1c24, 0x57a6a6f1,0x57a6a6f1
++	data4	0x73b4b4c7,0x73b4b4c7, 0x97c6c651,0x97c6c651
++	data4	0xcbe8e823,0xcbe8e823, 0xa1dddd7c,0xa1dddd7c
++	data4	0xe874749c,0xe874749c, 0x3e1f1f21,0x3e1f1f21
++	data4	0x964b4bdd,0x964b4bdd, 0x61bdbddc,0x61bdbddc
++	data4	0x0d8b8b86,0x0d8b8b86, 0x0f8a8a85,0x0f8a8a85
++	data4	0xe0707090,0xe0707090, 0x7c3e3e42,0x7c3e3e42
++	data4	0x71b5b5c4,0x71b5b5c4, 0xcc6666aa,0xcc6666aa
++	data4	0x904848d8,0x904848d8, 0x06030305,0x06030305
++	data4	0xf7f6f601,0xf7f6f601, 0x1c0e0e12,0x1c0e0e12
++	data4	0xc26161a3,0xc26161a3, 0x6a35355f,0x6a35355f
++	data4	0xae5757f9,0xae5757f9, 0x69b9b9d0,0x69b9b9d0
++	data4	0x17868691,0x17868691, 0x99c1c158,0x99c1c158
++	data4	0x3a1d1d27,0x3a1d1d27, 0x279e9eb9,0x279e9eb9
++	data4	0xd9e1e138,0xd9e1e138, 0xebf8f813,0xebf8f813
++	data4	0x2b9898b3,0x2b9898b3, 0x22111133,0x22111133
++	data4	0xd26969bb,0xd26969bb, 0xa9d9d970,0xa9d9d970
++	data4	0x078e8e89,0x078e8e89, 0x339494a7,0x339494a7
++	data4	0x2d9b9bb6,0x2d9b9bb6, 0x3c1e1e22,0x3c1e1e22
++	data4	0x15878792,0x15878792, 0xc9e9e920,0xc9e9e920
++	data4	0x87cece49,0x87cece49, 0xaa5555ff,0xaa5555ff
++	data4	0x50282878,0x50282878, 0xa5dfdf7a,0xa5dfdf7a
++	data4	0x038c8c8f,0x038c8c8f, 0x59a1a1f8,0x59a1a1f8
++	data4	0x09898980,0x09898980, 0x1a0d0d17,0x1a0d0d17
++	data4	0x65bfbfda,0x65bfbfda, 0xd7e6e631,0xd7e6e631
++	data4	0x844242c6,0x844242c6, 0xd06868b8,0xd06868b8
++	data4	0x824141c3,0x824141c3, 0x299999b0,0x299999b0
++	data4	0x5a2d2d77,0x5a2d2d77, 0x1e0f0f11,0x1e0f0f11
++	data4	0x7bb0b0cb,0x7bb0b0cb, 0xa85454fc,0xa85454fc
++	data4	0x6dbbbbd6,0x6dbbbbd6, 0x2c16163a,0x2c16163a
++// Te4:
++	data1	0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5
++	data1	0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76
++	data1	0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0
++	data1	0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0
++	data1	0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc
++	data1	0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15
++	data1	0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a
++	data1	0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75
++	data1	0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0
++	data1	0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84
++	data1	0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b
++	data1	0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf
++	data1	0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85
++	data1	0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8
++	data1	0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5
++	data1	0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2
++	data1	0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17
++	data1	0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73
++	data1	0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88
++	data1	0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb
++	data1	0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c
++	data1	0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79
++	data1	0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9
++	data1	0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08
++	data1	0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6
++	data1	0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a
++	data1	0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e
++	data1	0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e
++	data1	0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94
++	data1	0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf
++	data1	0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68
++	data1	0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16
++.size	AES_Te#,2048+256	// HP-UX assembler fails to ".-AES_Te#"
++
++.align	64
++.global	AES_Td#
++.type	AES_Td#,@object
++AES_Td:	data4	0x51f4a750,0x51f4a750, 0x7e416553,0x7e416553
++	data4	0x1a17a4c3,0x1a17a4c3, 0x3a275e96,0x3a275e96
++	data4	0x3bab6bcb,0x3bab6bcb, 0x1f9d45f1,0x1f9d45f1
++	data4	0xacfa58ab,0xacfa58ab, 0x4be30393,0x4be30393
++	data4	0x2030fa55,0x2030fa55, 0xad766df6,0xad766df6
++	data4	0x88cc7691,0x88cc7691, 0xf5024c25,0xf5024c25
++	data4	0x4fe5d7fc,0x4fe5d7fc, 0xc52acbd7,0xc52acbd7
++	data4	0x26354480,0x26354480, 0xb562a38f,0xb562a38f
++	data4	0xdeb15a49,0xdeb15a49, 0x25ba1b67,0x25ba1b67
++	data4	0x45ea0e98,0x45ea0e98, 0x5dfec0e1,0x5dfec0e1
++	data4	0xc32f7502,0xc32f7502, 0x814cf012,0x814cf012
++	data4	0x8d4697a3,0x8d4697a3, 0x6bd3f9c6,0x6bd3f9c6
++	data4	0x038f5fe7,0x038f5fe7, 0x15929c95,0x15929c95
++	data4	0xbf6d7aeb,0xbf6d7aeb, 0x955259da,0x955259da
++	data4	0xd4be832d,0xd4be832d, 0x587421d3,0x587421d3
++	data4	0x49e06929,0x49e06929, 0x8ec9c844,0x8ec9c844
++	data4	0x75c2896a,0x75c2896a, 0xf48e7978,0xf48e7978
++	data4	0x99583e6b,0x99583e6b, 0x27b971dd,0x27b971dd
++	data4	0xbee14fb6,0xbee14fb6, 0xf088ad17,0xf088ad17
++	data4	0xc920ac66,0xc920ac66, 0x7dce3ab4,0x7dce3ab4
++	data4	0x63df4a18,0x63df4a18, 0xe51a3182,0xe51a3182
++	data4	0x97513360,0x97513360, 0x62537f45,0x62537f45
++	data4	0xb16477e0,0xb16477e0, 0xbb6bae84,0xbb6bae84
++	data4	0xfe81a01c,0xfe81a01c, 0xf9082b94,0xf9082b94
++	data4	0x70486858,0x70486858, 0x8f45fd19,0x8f45fd19
++	data4	0x94de6c87,0x94de6c87, 0x527bf8b7,0x527bf8b7
++	data4	0xab73d323,0xab73d323, 0x724b02e2,0x724b02e2
++	data4	0xe31f8f57,0xe31f8f57, 0x6655ab2a,0x6655ab2a
++	data4	0xb2eb2807,0xb2eb2807, 0x2fb5c203,0x2fb5c203
++	data4	0x86c57b9a,0x86c57b9a, 0xd33708a5,0xd33708a5
++	data4	0x302887f2,0x302887f2, 0x23bfa5b2,0x23bfa5b2
++	data4	0x02036aba,0x02036aba, 0xed16825c,0xed16825c
++	data4	0x8acf1c2b,0x8acf1c2b, 0xa779b492,0xa779b492
++	data4	0xf307f2f0,0xf307f2f0, 0x4e69e2a1,0x4e69e2a1
++	data4	0x65daf4cd,0x65daf4cd, 0x0605bed5,0x0605bed5
++	data4	0xd134621f,0xd134621f, 0xc4a6fe8a,0xc4a6fe8a
++	data4	0x342e539d,0x342e539d, 0xa2f355a0,0xa2f355a0
++	data4	0x058ae132,0x058ae132, 0xa4f6eb75,0xa4f6eb75
++	data4	0x0b83ec39,0x0b83ec39, 0x4060efaa,0x4060efaa
++	data4	0x5e719f06,0x5e719f06, 0xbd6e1051,0xbd6e1051
++	data4	0x3e218af9,0x3e218af9, 0x96dd063d,0x96dd063d
++	data4	0xdd3e05ae,0xdd3e05ae, 0x4de6bd46,0x4de6bd46
++	data4	0x91548db5,0x91548db5, 0x71c45d05,0x71c45d05
++	data4	0x0406d46f,0x0406d46f, 0x605015ff,0x605015ff
++	data4	0x1998fb24,0x1998fb24, 0xd6bde997,0xd6bde997
++	data4	0x894043cc,0x894043cc, 0x67d99e77,0x67d99e77
++	data4	0xb0e842bd,0xb0e842bd, 0x07898b88,0x07898b88
++	data4	0xe7195b38,0xe7195b38, 0x79c8eedb,0x79c8eedb
++	data4	0xa17c0a47,0xa17c0a47, 0x7c420fe9,0x7c420fe9
++	data4	0xf8841ec9,0xf8841ec9, 0x00000000,0x00000000
++	data4	0x09808683,0x09808683, 0x322bed48,0x322bed48
++	data4	0x1e1170ac,0x1e1170ac, 0x6c5a724e,0x6c5a724e
++	data4	0xfd0efffb,0xfd0efffb, 0x0f853856,0x0f853856
++	data4	0x3daed51e,0x3daed51e, 0x362d3927,0x362d3927
++	data4	0x0a0fd964,0x0a0fd964, 0x685ca621,0x685ca621
++	data4	0x9b5b54d1,0x9b5b54d1, 0x24362e3a,0x24362e3a
++	data4	0x0c0a67b1,0x0c0a67b1, 0x9357e70f,0x9357e70f
++	data4	0xb4ee96d2,0xb4ee96d2, 0x1b9b919e,0x1b9b919e
++	data4	0x80c0c54f,0x80c0c54f, 0x61dc20a2,0x61dc20a2
++	data4	0x5a774b69,0x5a774b69, 0x1c121a16,0x1c121a16
++	data4	0xe293ba0a,0xe293ba0a, 0xc0a02ae5,0xc0a02ae5
++	data4	0x3c22e043,0x3c22e043, 0x121b171d,0x121b171d
++	data4	0x0e090d0b,0x0e090d0b, 0xf28bc7ad,0xf28bc7ad
++	data4	0x2db6a8b9,0x2db6a8b9, 0x141ea9c8,0x141ea9c8
++	data4	0x57f11985,0x57f11985, 0xaf75074c,0xaf75074c
++	data4	0xee99ddbb,0xee99ddbb, 0xa37f60fd,0xa37f60fd
++	data4	0xf701269f,0xf701269f, 0x5c72f5bc,0x5c72f5bc
++	data4	0x44663bc5,0x44663bc5, 0x5bfb7e34,0x5bfb7e34
++	data4	0x8b432976,0x8b432976, 0xcb23c6dc,0xcb23c6dc
++	data4	0xb6edfc68,0xb6edfc68, 0xb8e4f163,0xb8e4f163
++	data4	0xd731dcca,0xd731dcca, 0x42638510,0x42638510
++	data4	0x13972240,0x13972240, 0x84c61120,0x84c61120
++	data4	0x854a247d,0x854a247d, 0xd2bb3df8,0xd2bb3df8
++	data4	0xaef93211,0xaef93211, 0xc729a16d,0xc729a16d
++	data4	0x1d9e2f4b,0x1d9e2f4b, 0xdcb230f3,0xdcb230f3
++	data4	0x0d8652ec,0x0d8652ec, 0x77c1e3d0,0x77c1e3d0
++	data4	0x2bb3166c,0x2bb3166c, 0xa970b999,0xa970b999
++	data4	0x119448fa,0x119448fa, 0x47e96422,0x47e96422
++	data4	0xa8fc8cc4,0xa8fc8cc4, 0xa0f03f1a,0xa0f03f1a
++	data4	0x567d2cd8,0x567d2cd8, 0x223390ef,0x223390ef
++	data4	0x87494ec7,0x87494ec7, 0xd938d1c1,0xd938d1c1
++	data4	0x8ccaa2fe,0x8ccaa2fe, 0x98d40b36,0x98d40b36
++	data4	0xa6f581cf,0xa6f581cf, 0xa57ade28,0xa57ade28
++	data4	0xdab78e26,0xdab78e26, 0x3fadbfa4,0x3fadbfa4
++	data4	0x2c3a9de4,0x2c3a9de4, 0x5078920d,0x5078920d
++	data4	0x6a5fcc9b,0x6a5fcc9b, 0x547e4662,0x547e4662
++	data4	0xf68d13c2,0xf68d13c2, 0x90d8b8e8,0x90d8b8e8
++	data4	0x2e39f75e,0x2e39f75e, 0x82c3aff5,0x82c3aff5
++	data4	0x9f5d80be,0x9f5d80be, 0x69d0937c,0x69d0937c
++	data4	0x6fd52da9,0x6fd52da9, 0xcf2512b3,0xcf2512b3
++	data4	0xc8ac993b,0xc8ac993b, 0x10187da7,0x10187da7
++	data4	0xe89c636e,0xe89c636e, 0xdb3bbb7b,0xdb3bbb7b
++	data4	0xcd267809,0xcd267809, 0x6e5918f4,0x6e5918f4
++	data4	0xec9ab701,0xec9ab701, 0x834f9aa8,0x834f9aa8
++	data4	0xe6956e65,0xe6956e65, 0xaaffe67e,0xaaffe67e
++	data4	0x21bccf08,0x21bccf08, 0xef15e8e6,0xef15e8e6
++	data4	0xbae79bd9,0xbae79bd9, 0x4a6f36ce,0x4a6f36ce
++	data4	0xea9f09d4,0xea9f09d4, 0x29b07cd6,0x29b07cd6
++	data4	0x31a4b2af,0x31a4b2af, 0x2a3f2331,0x2a3f2331
++	data4	0xc6a59430,0xc6a59430, 0x35a266c0,0x35a266c0
++	data4	0x744ebc37,0x744ebc37, 0xfc82caa6,0xfc82caa6
++	data4	0xe090d0b0,0xe090d0b0, 0x33a7d815,0x33a7d815
++	data4	0xf104984a,0xf104984a, 0x41ecdaf7,0x41ecdaf7
++	data4	0x7fcd500e,0x7fcd500e, 0x1791f62f,0x1791f62f
++	data4	0x764dd68d,0x764dd68d, 0x43efb04d,0x43efb04d
++	data4	0xccaa4d54,0xccaa4d54, 0xe49604df,0xe49604df
++	data4	0x9ed1b5e3,0x9ed1b5e3, 0x4c6a881b,0x4c6a881b
++	data4	0xc12c1fb8,0xc12c1fb8, 0x4665517f,0x4665517f
++	data4	0x9d5eea04,0x9d5eea04, 0x018c355d,0x018c355d
++	data4	0xfa877473,0xfa877473, 0xfb0b412e,0xfb0b412e
++	data4	0xb3671d5a,0xb3671d5a, 0x92dbd252,0x92dbd252
++	data4	0xe9105633,0xe9105633, 0x6dd64713,0x6dd64713
++	data4	0x9ad7618c,0x9ad7618c, 0x37a10c7a,0x37a10c7a
++	data4	0x59f8148e,0x59f8148e, 0xeb133c89,0xeb133c89
++	data4	0xcea927ee,0xcea927ee, 0xb761c935,0xb761c935
++	data4	0xe11ce5ed,0xe11ce5ed, 0x7a47b13c,0x7a47b13c
++	data4	0x9cd2df59,0x9cd2df59, 0x55f2733f,0x55f2733f
++	data4	0x1814ce79,0x1814ce79, 0x73c737bf,0x73c737bf
++	data4	0x53f7cdea,0x53f7cdea, 0x5ffdaa5b,0x5ffdaa5b
++	data4	0xdf3d6f14,0xdf3d6f14, 0x7844db86,0x7844db86
++	data4	0xcaaff381,0xcaaff381, 0xb968c43e,0xb968c43e
++	data4	0x3824342c,0x3824342c, 0xc2a3405f,0xc2a3405f
++	data4	0x161dc372,0x161dc372, 0xbce2250c,0xbce2250c
++	data4	0x283c498b,0x283c498b, 0xff0d9541,0xff0d9541
++	data4	0x39a80171,0x39a80171, 0x080cb3de,0x080cb3de
++	data4	0xd8b4e49c,0xd8b4e49c, 0x6456c190,0x6456c190
++	data4	0x7bcb8461,0x7bcb8461, 0xd532b670,0xd532b670
++	data4	0x486c5c74,0x486c5c74, 0xd0b85742,0xd0b85742
++// Td4:
++	data1	0x52, 0x09, 0x6a, 0xd5, 0x30, 0x36, 0xa5, 0x38
++	data1	0xbf, 0x40, 0xa3, 0x9e, 0x81, 0xf3, 0xd7, 0xfb
++	data1	0x7c, 0xe3, 0x39, 0x82, 0x9b, 0x2f, 0xff, 0x87
++	data1	0x34, 0x8e, 0x43, 0x44, 0xc4, 0xde, 0xe9, 0xcb
++	data1	0x54, 0x7b, 0x94, 0x32, 0xa6, 0xc2, 0x23, 0x3d
++	data1	0xee, 0x4c, 0x95, 0x0b, 0x42, 0xfa, 0xc3, 0x4e
++	data1	0x08, 0x2e, 0xa1, 0x66, 0x28, 0xd9, 0x24, 0xb2
++	data1	0x76, 0x5b, 0xa2, 0x49, 0x6d, 0x8b, 0xd1, 0x25
++	data1	0x72, 0xf8, 0xf6, 0x64, 0x86, 0x68, 0x98, 0x16
++	data1	0xd4, 0xa4, 0x5c, 0xcc, 0x5d, 0x65, 0xb6, 0x92
++	data1	0x6c, 0x70, 0x48, 0x50, 0xfd, 0xed, 0xb9, 0xda
++	data1	0x5e, 0x15, 0x46, 0x57, 0xa7, 0x8d, 0x9d, 0x84
++	data1	0x90, 0xd8, 0xab, 0x00, 0x8c, 0xbc, 0xd3, 0x0a
++	data1	0xf7, 0xe4, 0x58, 0x05, 0xb8, 0xb3, 0x45, 0x06
++	data1	0xd0, 0x2c, 0x1e, 0x8f, 0xca, 0x3f, 0x0f, 0x02
++	data1	0xc1, 0xaf, 0xbd, 0x03, 0x01, 0x13, 0x8a, 0x6b
++	data1	0x3a, 0x91, 0x11, 0x41, 0x4f, 0x67, 0xdc, 0xea
++	data1	0x97, 0xf2, 0xcf, 0xce, 0xf0, 0xb4, 0xe6, 0x73
++	data1	0x96, 0xac, 0x74, 0x22, 0xe7, 0xad, 0x35, 0x85
++	data1	0xe2, 0xf9, 0x37, 0xe8, 0x1c, 0x75, 0xdf, 0x6e
++	data1	0x47, 0xf1, 0x1a, 0x71, 0x1d, 0x29, 0xc5, 0x89
++	data1	0x6f, 0xb7, 0x62, 0x0e, 0xaa, 0x18, 0xbe, 0x1b
++	data1	0xfc, 0x56, 0x3e, 0x4b, 0xc6, 0xd2, 0x79, 0x20
++	data1	0x9a, 0xdb, 0xc0, 0xfe, 0x78, 0xcd, 0x5a, 0xf4
++	data1	0x1f, 0xdd, 0xa8, 0x33, 0x88, 0x07, 0xc7, 0x31
++	data1	0xb1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xec, 0x5f
++	data1	0x60, 0x51, 0x7f, 0xa9, 0x19, 0xb5, 0x4a, 0x0d
++	data1	0x2d, 0xe5, 0x7a, 0x9f, 0x93, 0xc9, 0x9c, 0xef
++	data1	0xa0, 0xe0, 0x3b, 0x4d, 0xae, 0x2a, 0xf5, 0xb0
++	data1	0xc8, 0xeb, 0xbb, 0x3c, 0x83, 0x53, 0x99, 0x61
++	data1	0x17, 0x2b, 0x04, 0x7e, 0xba, 0x77, 0xd6, 0x26
++	data1	0xe1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0c, 0x7d
++.size	AES_Td#,2048+256	// HP-UX assembler fails to ".-AES_Td#"
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/aes/asm/aes-mips.pl b/CryptoPkg/Library/OpensslLib/openssl/crypto/aes/asm/aes-mips.pl
+new file mode 100644
+index 0000000..439578d
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/aes/asm/aes-mips.pl
+@@ -0,0 +1,2131 @@
++#! /usr/bin/env perl
++# Copyright 2010-2016 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
++# in the file LICENSE in the source distribution or at
++# https://www.openssl.org/source/license.html
++
++
++# ====================================================================
++# Written by Andy Polyakov  for the OpenSSL
++# project. The module is, however, dual licensed under OpenSSL and
++# CRYPTOGAMS licenses depending on where you obtain it. For further
++# details see http://www.openssl.org/~appro/cryptogams/.
++# ====================================================================
++
++# AES for MIPS
++
++# October 2010
++#
++# Code uses 1K[+256B] S-box and on single-issue core [such as R5000]
++# spends ~68 cycles per byte processed with 128-bit key. This is ~16%
++# faster than gcc-generated code, which is not very impressive. But
++# recall that compressed S-box requires extra processing, namely
++# additional rotations. Rotations are implemented with lwl/lwr pairs,
++# which is normally used for loading unaligned data. Another cool
++# thing about this module is its endian neutrality, which means that
++# it processes data without ever changing byte order...
++
++# September 2012
++#
++# Add MIPS32R2 (~10% less instructions) and SmartMIPS ASE (further
++# ~25% less instructions) code. Note that there is no run-time switch,
++# instead, code path is chosen upon pre-process time, pass -mips32r2
++# or/and -msmartmips.
++
++######################################################################
++# There is a number of MIPS ABI in use, O32 and N32/64 are most
++# widely used. Then there is a new contender: NUBI. It appears that if
++# one picks the latter, it's possible to arrange code in ABI neutral
++# manner. Therefore let's stick to NUBI register layout:
++#
++($zero,$at,$t0,$t1,$t2)=map("\$$_",(0..2,24,25));
++($a0,$a1,$a2,$a3,$a4,$a5,$a6,$a7)=map("\$$_",(4..11));
++($s0,$s1,$s2,$s3,$s4,$s5,$s6,$s7,$s8,$s9,$s10,$s11)=map("\$$_",(12..23));
++($gp,$tp,$sp,$fp,$ra)=map("\$$_",(3,28..31));
++#
++# The return value is placed in $a0. Following coding rules facilitate
++# interoperability:
++#
++# - never ever touch $tp, "thread pointer", former $gp;
++# - copy return value to $t0, former $v0 [or to $a0 if you're adapting
++#   old code];
++# - on O32 populate $a4-$a7 with 'lw $aN,4*N($sp)' if necessary;
++#
++# For reference here is register layout for N32/64 MIPS ABIs:
++#
++# ($zero,$at,$v0,$v1)=map("\$$_",(0..3));
++# ($a0,$a1,$a2,$a3,$a4,$a5,$a6,$a7)=map("\$$_",(4..11));
++# ($t0,$t1,$t2,$t3,$t8,$t9)=map("\$$_",(12..15,24,25));
++# ($s0,$s1,$s2,$s3,$s4,$s5,$s6,$s7)=map("\$$_",(16..23));
++# ($gp,$sp,$fp,$ra)=map("\$$_",(28..31));
++#
++$flavour = shift || "o32"; # supported flavours are o32,n32,64,nubi32,nubi64
++
++if ($flavour =~ /64|n32/i) {
++	$PTR_LA="dla";
++	$PTR_ADD="dadd";	# incidentally works even on n32
++	$PTR_SUB="dsub";	# incidentally works even on n32
++	$PTR_INS="dins";
++	$REG_S="sd";
++	$REG_L="ld";
++	$PTR_SLL="dsll";	# incidentally works even on n32
++	$SZREG=8;
++} else {
++	$PTR_LA="la";
++	$PTR_ADD="add";
++	$PTR_SUB="sub";
++	$PTR_INS="ins";
++	$REG_S="sw";
++	$REG_L="lw";
++	$PTR_SLL="sll";
++	$SZREG=4;
++}
++$pf = ($flavour =~ /nubi/i) ? $t0 : $t2;
++#
++# 
++#
++######################################################################
++
++$big_endian=(`echo MIPSEL | $ENV{CC} -E -`=~/MIPSEL/)?1:0 if ($ENV{CC});
++
++for (@ARGV) {	$output=$_ if (/\w[\w\-]*\.\w+$/);	}
++open STDOUT,">$output";
++
++if (!defined($big_endian))
++{    $big_endian=(unpack('L',pack('N',1))==1);   }
++
++while (($output=shift) && ($output!~/\w[\w\-]*\.\w+$/)) {}
++open STDOUT,">$output";
++
++my ($MSB,$LSB)=(0,3);	# automatically converted to little-endian
++
++$code.=<<___;
++.text
++#ifdef OPENSSL_FIPSCANISTER
++# include 
++#endif
++
++#if defined(__mips_smartmips) && !defined(_MIPS_ARCH_MIPS32R2)
++#define _MIPS_ARCH_MIPS32R2
++#endif
++
++#if !defined(__mips_eabi) && (!defined(__vxworks) || defined(__pic__))
++.option	pic2
++#endif
++.set	noat
++___
++
++{{{
++my $FRAMESIZE=16*$SZREG;
++my $SAVED_REGS_MASK = ($flavour =~ /nubi/i) ? "0xc0fff008" : "0xc0ff0000";
++
++my ($inp,$out,$key,$Tbl,$s0,$s1,$s2,$s3)=($a0,$a1,$a2,$a3,$a4,$a5,$a6,$a7);
++my ($i0,$i1,$i2,$i3)=($at,$t0,$t1,$t2);
++my ($t0,$t1,$t2,$t3,$t4,$t5,$t6,$t7,$t8,$t9,$t10,$t11) = map("\$$_",(12..23));
++my ($key0,$cnt)=($gp,$fp);
++
++# instuction ordering is "stolen" from output from MIPSpro assembler
++# invoked with -mips3 -O3 arguments...
++$code.=<<___;
++.align	5
++.ent	_mips_AES_encrypt
++_mips_AES_encrypt:
++	.frame	$sp,0,$ra
++	.set	reorder
++	lw	$t0,0($key)
++	lw	$t1,4($key)
++	lw	$t2,8($key)
++	lw	$t3,12($key)
++	lw	$cnt,240($key)
++	$PTR_ADD $key0,$key,16
++
++	xor	$s0,$t0
++	xor	$s1,$t1
++	xor	$s2,$t2
++	xor	$s3,$t3
++
++	sub	$cnt,1
++#if defined(__mips_smartmips)
++	ext	$i0,$s1,16,8
++.Loop_enc:
++	ext	$i1,$s2,16,8
++	ext	$i2,$s3,16,8
++	ext	$i3,$s0,16,8
++	lwxs	$t0,$i0($Tbl)		# Te1[s1>>16]
++	ext	$i0,$s2,8,8
++	lwxs	$t1,$i1($Tbl)		# Te1[s2>>16]
++	ext	$i1,$s3,8,8
++	lwxs	$t2,$i2($Tbl)		# Te1[s3>>16]
++	ext	$i2,$s0,8,8
++	lwxs	$t3,$i3($Tbl)		# Te1[s0>>16]
++	ext	$i3,$s1,8,8
++
++	lwxs	$t4,$i0($Tbl)		# Te2[s2>>8]
++	ext	$i0,$s3,0,8
++	lwxs	$t5,$i1($Tbl)		# Te2[s3>>8]
++	ext	$i1,$s0,0,8
++	lwxs	$t6,$i2($Tbl)		# Te2[s0>>8]
++	ext	$i2,$s1,0,8
++	lwxs	$t7,$i3($Tbl)		# Te2[s1>>8]
++	ext	$i3,$s2,0,8
++
++	lwxs	$t8,$i0($Tbl)		# Te3[s3]
++	ext	$i0,$s0,24,8
++	lwxs	$t9,$i1($Tbl)		# Te3[s0]
++	ext	$i1,$s1,24,8
++	lwxs	$t10,$i2($Tbl)		# Te3[s1]
++	ext	$i2,$s2,24,8
++	lwxs	$t11,$i3($Tbl)		# Te3[s2]
++	ext	$i3,$s3,24,8
++
++	rotr	$t0,$t0,8
++	rotr	$t1,$t1,8
++	rotr	$t2,$t2,8
++	rotr	$t3,$t3,8
++
++	rotr	$t4,$t4,16
++	rotr	$t5,$t5,16
++	rotr	$t6,$t6,16
++	rotr	$t7,$t7,16
++
++	xor	$t0,$t4
++	lwxs	$t4,$i0($Tbl)		# Te0[s0>>24]
++	xor	$t1,$t5
++	lwxs	$t5,$i1($Tbl)		# Te0[s1>>24]
++	xor	$t2,$t6
++	lwxs	$t6,$i2($Tbl)		# Te0[s2>>24]
++	xor	$t3,$t7
++	lwxs	$t7,$i3($Tbl)		# Te0[s3>>24]
++
++	rotr	$t8,$t8,24
++	lw	$s0,0($key0)
++	rotr	$t9,$t9,24
++	lw	$s1,4($key0)
++	rotr	$t10,$t10,24
++	lw	$s2,8($key0)
++	rotr	$t11,$t11,24
++	lw	$s3,12($key0)
++
++	xor	$t0,$t8
++	xor	$t1,$t9
++	xor	$t2,$t10
++	xor	$t3,$t11
++
++	xor	$t0,$t4
++	xor	$t1,$t5
++	xor	$t2,$t6
++	xor	$t3,$t7
++
++	sub	$cnt,1
++	$PTR_ADD $key0,16
++	xor	$s0,$t0
++	xor	$s1,$t1
++	xor	$s2,$t2
++	xor	$s3,$t3
++	.set	noreorder
++	bnez	$cnt,.Loop_enc
++	ext	$i0,$s1,16,8
++
++	_xtr	$i0,$s1,16-2
++#else
++	_xtr	$i0,$s1,16-2
++.Loop_enc:
++	_xtr	$i1,$s2,16-2
++	_xtr	$i2,$s3,16-2
++	_xtr	$i3,$s0,16-2
++	and	$i0,0x3fc
++	and	$i1,0x3fc
++	and	$i2,0x3fc
++	and	$i3,0x3fc
++	$PTR_ADD $i0,$Tbl
++	$PTR_ADD $i1,$Tbl
++	$PTR_ADD $i2,$Tbl
++	$PTR_ADD $i3,$Tbl
++#if defined(_MIPS_ARCH_MIPS32R2) || defined(_MIPS_ARCH_MIPS64R2)
++	lw	$t0,0($i0)		# Te1[s1>>16]
++	_xtr	$i0,$s2,8-2
++	lw	$t1,0($i1)		# Te1[s2>>16]
++	_xtr	$i1,$s3,8-2
++	lw	$t2,0($i2)		# Te1[s3>>16]
++	_xtr	$i2,$s0,8-2
++	lw	$t3,0($i3)		# Te1[s0>>16]
++	_xtr	$i3,$s1,8-2
++#else
++	lwl	$t0,3($i0)		# Te1[s1>>16]
++	lwl	$t1,3($i1)		# Te1[s2>>16]
++	lwl	$t2,3($i2)		# Te1[s3>>16]
++	lwl	$t3,3($i3)		# Te1[s0>>16]
++	lwr	$t0,2($i0)		# Te1[s1>>16]
++	_xtr	$i0,$s2,8-2
++	lwr	$t1,2($i1)		# Te1[s2>>16]
++	_xtr	$i1,$s3,8-2
++	lwr	$t2,2($i2)		# Te1[s3>>16]
++	_xtr	$i2,$s0,8-2
++	lwr	$t3,2($i3)		# Te1[s0>>16]
++	_xtr	$i3,$s1,8-2
++#endif
++	and	$i0,0x3fc
++	and	$i1,0x3fc
++	and	$i2,0x3fc
++	and	$i3,0x3fc
++	$PTR_ADD $i0,$Tbl
++	$PTR_ADD $i1,$Tbl
++	$PTR_ADD $i2,$Tbl
++	$PTR_ADD $i3,$Tbl
++#if defined(_MIPS_ARCH_MIPS32R2) || defined(_MIPS_ARCH_MIPS64R2)
++	rotr	$t0,$t0,8
++	rotr	$t1,$t1,8
++	rotr	$t2,$t2,8
++	rotr	$t3,$t3,8
++# if defined(_MIPSEL)
++	lw	$t4,0($i0)		# Te2[s2>>8]
++	_xtr	$i0,$s3,0-2
++	lw	$t5,0($i1)		# Te2[s3>>8]
++	_xtr	$i1,$s0,0-2
++	lw	$t6,0($i2)		# Te2[s0>>8]
++	_xtr	$i2,$s1,0-2
++	lw	$t7,0($i3)		# Te2[s1>>8]
++	_xtr	$i3,$s2,0-2
++
++	and	$i0,0x3fc
++	and	$i1,0x3fc
++	and	$i2,0x3fc
++	and	$i3,0x3fc
++	$PTR_ADD $i0,$Tbl
++	$PTR_ADD $i1,$Tbl
++	$PTR_ADD $i2,$Tbl
++	$PTR_ADD $i3,$Tbl
++	lw	$t8,0($i0)		# Te3[s3]
++	$PTR_INS $i0,$s0,2,8
++	lw	$t9,0($i1)		# Te3[s0]
++	$PTR_INS $i1,$s1,2,8
++	lw	$t10,0($i2)		# Te3[s1]
++	$PTR_INS $i2,$s2,2,8
++	lw	$t11,0($i3)		# Te3[s2]
++	$PTR_INS $i3,$s3,2,8
++# else
++	lw	$t4,0($i0)		# Te2[s2>>8]
++	$PTR_INS $i0,$s3,2,8
++	lw	$t5,0($i1)		# Te2[s3>>8]
++	$PTR_INS $i1,$s0,2,8
++	lw	$t6,0($i2)		# Te2[s0>>8]
++	$PTR_INS $i2,$s1,2,8
++	lw	$t7,0($i3)		# Te2[s1>>8]
++	$PTR_INS $i3,$s2,2,8
++
++	lw	$t8,0($i0)		# Te3[s3]
++	_xtr	$i0,$s0,24-2
++	lw	$t9,0($i1)		# Te3[s0]
++	_xtr	$i1,$s1,24-2
++	lw	$t10,0($i2)		# Te3[s1]
++	_xtr	$i2,$s2,24-2
++	lw	$t11,0($i3)		# Te3[s2]
++	_xtr	$i3,$s3,24-2
++
++	and	$i0,0x3fc
++	and	$i1,0x3fc
++	and	$i2,0x3fc
++	and	$i3,0x3fc
++	$PTR_ADD $i0,$Tbl
++	$PTR_ADD $i1,$Tbl
++	$PTR_ADD $i2,$Tbl
++	$PTR_ADD $i3,$Tbl
++# endif
++	rotr	$t4,$t4,16
++	rotr	$t5,$t5,16
++	rotr	$t6,$t6,16
++	rotr	$t7,$t7,16
++
++	rotr	$t8,$t8,24
++	rotr	$t9,$t9,24
++	rotr	$t10,$t10,24
++	rotr	$t11,$t11,24
++#else
++	lwl	$t4,2($i0)		# Te2[s2>>8]
++	lwl	$t5,2($i1)		# Te2[s3>>8]
++	lwl	$t6,2($i2)		# Te2[s0>>8]
++	lwl	$t7,2($i3)		# Te2[s1>>8]
++	lwr	$t4,1($i0)		# Te2[s2>>8]
++	_xtr	$i0,$s3,0-2
++	lwr	$t5,1($i1)		# Te2[s3>>8]
++	_xtr	$i1,$s0,0-2
++	lwr	$t6,1($i2)		# Te2[s0>>8]
++	_xtr	$i2,$s1,0-2
++	lwr	$t7,1($i3)		# Te2[s1>>8]
++	_xtr	$i3,$s2,0-2
++
++	and	$i0,0x3fc
++	and	$i1,0x3fc
++	and	$i2,0x3fc
++	and	$i3,0x3fc
++	$PTR_ADD $i0,$Tbl
++	$PTR_ADD $i1,$Tbl
++	$PTR_ADD $i2,$Tbl
++	$PTR_ADD $i3,$Tbl
++	lwl	$t8,1($i0)		# Te3[s3]
++	lwl	$t9,1($i1)		# Te3[s0]
++	lwl	$t10,1($i2)		# Te3[s1]
++	lwl	$t11,1($i3)		# Te3[s2]
++	lwr	$t8,0($i0)		# Te3[s3]
++	_xtr	$i0,$s0,24-2
++	lwr	$t9,0($i1)		# Te3[s0]
++	_xtr	$i1,$s1,24-2
++	lwr	$t10,0($i2)		# Te3[s1]
++	_xtr	$i2,$s2,24-2
++	lwr	$t11,0($i3)		# Te3[s2]
++	_xtr	$i3,$s3,24-2
++
++	and	$i0,0x3fc
++	and	$i1,0x3fc
++	and	$i2,0x3fc
++	and	$i3,0x3fc
++	$PTR_ADD $i0,$Tbl
++	$PTR_ADD $i1,$Tbl
++	$PTR_ADD $i2,$Tbl
++	$PTR_ADD $i3,$Tbl
++#endif
++	xor	$t0,$t4
++	lw	$t4,0($i0)		# Te0[s0>>24]
++	xor	$t1,$t5
++	lw	$t5,0($i1)		# Te0[s1>>24]
++	xor	$t2,$t6
++	lw	$t6,0($i2)		# Te0[s2>>24]
++	xor	$t3,$t7
++	lw	$t7,0($i3)		# Te0[s3>>24]
++
++	xor	$t0,$t8
++	lw	$s0,0($key0)
++	xor	$t1,$t9
++	lw	$s1,4($key0)
++	xor	$t2,$t10
++	lw	$s2,8($key0)
++	xor	$t3,$t11
++	lw	$s3,12($key0)
++
++	xor	$t0,$t4
++	xor	$t1,$t5
++	xor	$t2,$t6
++	xor	$t3,$t7
++
++	sub	$cnt,1
++	$PTR_ADD $key0,16
++	xor	$s0,$t0
++	xor	$s1,$t1
++	xor	$s2,$t2
++	xor	$s3,$t3
++	.set	noreorder
++	bnez	$cnt,.Loop_enc
++	_xtr	$i0,$s1,16-2
++#endif
++
++	.set	reorder
++	_xtr	$i1,$s2,16-2
++	_xtr	$i2,$s3,16-2
++	_xtr	$i3,$s0,16-2
++	and	$i0,0x3fc
++	and	$i1,0x3fc
++	and	$i2,0x3fc
++	and	$i3,0x3fc
++	$PTR_ADD $i0,$Tbl
++	$PTR_ADD $i1,$Tbl
++	$PTR_ADD $i2,$Tbl
++	$PTR_ADD $i3,$Tbl
++	lbu	$t0,2($i0)		# Te4[s1>>16]
++	_xtr	$i0,$s2,8-2
++	lbu	$t1,2($i1)		# Te4[s2>>16]
++	_xtr	$i1,$s3,8-2
++	lbu	$t2,2($i2)		# Te4[s3>>16]
++	_xtr	$i2,$s0,8-2
++	lbu	$t3,2($i3)		# Te4[s0>>16]
++	_xtr	$i3,$s1,8-2
++
++	and	$i0,0x3fc
++	and	$i1,0x3fc
++	and	$i2,0x3fc
++	and	$i3,0x3fc
++	$PTR_ADD $i0,$Tbl
++	$PTR_ADD $i1,$Tbl
++	$PTR_ADD $i2,$Tbl
++	$PTR_ADD $i3,$Tbl
++#if defined(_MIPS_ARCH_MIPS32R2) || defined(_MIPS_ARCH_MIPS64R2)
++# if defined(_MIPSEL)
++	lbu	$t4,2($i0)		# Te4[s2>>8]
++	$PTR_INS $i0,$s0,2,8
++	lbu	$t5,2($i1)		# Te4[s3>>8]
++	$PTR_INS $i1,$s1,2,8
++	lbu	$t6,2($i2)		# Te4[s0>>8]
++	$PTR_INS $i2,$s2,2,8
++	lbu	$t7,2($i3)		# Te4[s1>>8]
++	$PTR_INS $i3,$s3,2,8
++
++	lbu	$t8,2($i0)		# Te4[s0>>24]
++	_xtr	$i0,$s3,0-2
++	lbu	$t9,2($i1)		# Te4[s1>>24]
++	_xtr	$i1,$s0,0-2
++	lbu	$t10,2($i2)		# Te4[s2>>24]
++	_xtr	$i2,$s1,0-2
++	lbu	$t11,2($i3)		# Te4[s3>>24]
++	_xtr	$i3,$s2,0-2
++
++	and	$i0,0x3fc
++	and	$i1,0x3fc
++	and	$i2,0x3fc
++	and	$i3,0x3fc
++	$PTR_ADD $i0,$Tbl
++	$PTR_ADD $i1,$Tbl
++	$PTR_ADD $i2,$Tbl
++	$PTR_ADD $i3,$Tbl
++# else
++	lbu	$t4,2($i0)		# Te4[s2>>8]
++	_xtr	$i0,$s0,24-2
++	lbu	$t5,2($i1)		# Te4[s3>>8]
++	_xtr	$i1,$s1,24-2
++	lbu	$t6,2($i2)		# Te4[s0>>8]
++	_xtr	$i2,$s2,24-2
++	lbu	$t7,2($i3)		# Te4[s1>>8]
++	_xtr	$i3,$s3,24-2
++
++	and	$i0,0x3fc
++	and	$i1,0x3fc
++	and	$i2,0x3fc
++	and	$i3,0x3fc
++	$PTR_ADD $i0,$Tbl
++	$PTR_ADD $i1,$Tbl
++	$PTR_ADD $i2,$Tbl
++	$PTR_ADD $i3,$Tbl
++	lbu	$t8,2($i0)		# Te4[s0>>24]
++	$PTR_INS $i0,$s3,2,8
++	lbu	$t9,2($i1)		# Te4[s1>>24]
++	$PTR_INS $i1,$s0,2,8
++	lbu	$t10,2($i2)		# Te4[s2>>24]
++	$PTR_INS $i2,$s1,2,8
++	lbu	$t11,2($i3)		# Te4[s3>>24]
++	$PTR_INS $i3,$s2,2,8
++# endif
++	_ins	$t0,16
++	_ins	$t1,16
++	_ins	$t2,16
++	_ins	$t3,16
++
++	_ins2	$t0,$t4,8
++	lbu	$t4,2($i0)		# Te4[s3]
++	_ins2	$t1,$t5,8
++	lbu	$t5,2($i1)		# Te4[s0]
++	_ins2	$t2,$t6,8
++	lbu	$t6,2($i2)		# Te4[s1]
++	_ins2	$t3,$t7,8
++	lbu	$t7,2($i3)		# Te4[s2]
++
++	_ins2	$t0,$t8,24
++	lw	$s0,0($key0)
++	_ins2	$t1,$t9,24
++	lw	$s1,4($key0)
++	_ins2	$t2,$t10,24
++	lw	$s2,8($key0)
++	_ins2	$t3,$t11,24
++	lw	$s3,12($key0)
++
++	_ins2	$t0,$t4,0
++	_ins2	$t1,$t5,0
++	_ins2	$t2,$t6,0
++	_ins2	$t3,$t7,0
++#else
++	lbu	$t4,2($i0)		# Te4[s2>>8]
++	_xtr	$i0,$s0,24-2
++	lbu	$t5,2($i1)		# Te4[s3>>8]
++	_xtr	$i1,$s1,24-2
++	lbu	$t6,2($i2)		# Te4[s0>>8]
++	_xtr	$i2,$s2,24-2
++	lbu	$t7,2($i3)		# Te4[s1>>8]
++	_xtr	$i3,$s3,24-2
++
++	and	$i0,0x3fc
++	and	$i1,0x3fc
++	and	$i2,0x3fc
++	and	$i3,0x3fc
++	$PTR_ADD $i0,$Tbl
++	$PTR_ADD $i1,$Tbl
++	$PTR_ADD $i2,$Tbl
++	$PTR_ADD $i3,$Tbl
++	lbu	$t8,2($i0)		# Te4[s0>>24]
++	_xtr	$i0,$s3,0-2
++	lbu	$t9,2($i1)		# Te4[s1>>24]
++	_xtr	$i1,$s0,0-2
++	lbu	$t10,2($i2)		# Te4[s2>>24]
++	_xtr	$i2,$s1,0-2
++	lbu	$t11,2($i3)		# Te4[s3>>24]
++	_xtr	$i3,$s2,0-2
++
++	and	$i0,0x3fc
++	and	$i1,0x3fc
++	and	$i2,0x3fc
++	and	$i3,0x3fc
++	$PTR_ADD $i0,$Tbl
++	$PTR_ADD $i1,$Tbl
++	$PTR_ADD $i2,$Tbl
++	$PTR_ADD $i3,$Tbl
++
++	_ins	$t0,16
++	_ins	$t1,16
++	_ins	$t2,16
++	_ins	$t3,16
++
++	_ins	$t4,8
++	_ins	$t5,8
++	_ins	$t6,8
++	_ins	$t7,8
++
++	xor	$t0,$t4
++	lbu	$t4,2($i0)		# Te4[s3]
++	xor	$t1,$t5
++	lbu	$t5,2($i1)		# Te4[s0]
++	xor	$t2,$t6
++	lbu	$t6,2($i2)		# Te4[s1]
++	xor	$t3,$t7
++	lbu	$t7,2($i3)		# Te4[s2]
++
++	_ins	$t8,24
++	lw	$s0,0($key0)
++	_ins	$t9,24
++	lw	$s1,4($key0)
++	_ins	$t10,24
++	lw	$s2,8($key0)
++	_ins	$t11,24
++	lw	$s3,12($key0)
++
++	xor	$t0,$t8
++	xor	$t1,$t9
++	xor	$t2,$t10
++	xor	$t3,$t11
++
++	_ins	$t4,0
++	_ins	$t5,0
++	_ins	$t6,0
++	_ins	$t7,0
++
++	xor	$t0,$t4
++	xor	$t1,$t5
++	xor	$t2,$t6
++	xor	$t3,$t7
++#endif
++	xor	$s0,$t0
++	xor	$s1,$t1
++	xor	$s2,$t2
++	xor	$s3,$t3
++
++	jr	$ra
++.end	_mips_AES_encrypt
++
++.align	5
++.globl	AES_encrypt
++.ent	AES_encrypt
++AES_encrypt:
++	.frame	$sp,$FRAMESIZE,$ra
++	.mask	$SAVED_REGS_MASK,-$SZREG
++	.set	noreorder
++___
++$code.=<<___ if ($flavour =~ /o32/i);	# o32 PIC-ification
++	.cpload	$pf
++___
++$code.=<<___;
++	$PTR_SUB $sp,$FRAMESIZE
++	$REG_S	$ra,$FRAMESIZE-1*$SZREG($sp)
++	$REG_S	$fp,$FRAMESIZE-2*$SZREG($sp)
++	$REG_S	$s11,$FRAMESIZE-3*$SZREG($sp)
++	$REG_S	$s10,$FRAMESIZE-4*$SZREG($sp)
++	$REG_S	$s9,$FRAMESIZE-5*$SZREG($sp)
++	$REG_S	$s8,$FRAMESIZE-6*$SZREG($sp)
++	$REG_S	$s7,$FRAMESIZE-7*$SZREG($sp)
++	$REG_S	$s6,$FRAMESIZE-8*$SZREG($sp)
++	$REG_S	$s5,$FRAMESIZE-9*$SZREG($sp)
++	$REG_S	$s4,$FRAMESIZE-10*$SZREG($sp)
++___
++$code.=<<___ if ($flavour =~ /nubi/i);	# optimize non-nubi prologue
++	$REG_S	\$15,$FRAMESIZE-11*$SZREG($sp)
++	$REG_S	\$14,$FRAMESIZE-12*$SZREG($sp)
++	$REG_S	\$13,$FRAMESIZE-13*$SZREG($sp)
++	$REG_S	\$12,$FRAMESIZE-14*$SZREG($sp)
++	$REG_S	$gp,$FRAMESIZE-15*$SZREG($sp)
++___
++$code.=<<___ if ($flavour !~ /o32/i);	# non-o32 PIC-ification
++	.cplocal	$Tbl
++	.cpsetup	$pf,$zero,AES_encrypt
++___
++$code.=<<___;
++	.set	reorder
++	$PTR_LA	$Tbl,AES_Te		# PIC-ified 'load address'
++
++	lwl	$s0,0+$MSB($inp)
++	lwl	$s1,4+$MSB($inp)
++	lwl	$s2,8+$MSB($inp)
++	lwl	$s3,12+$MSB($inp)
++	lwr	$s0,0+$LSB($inp)
++	lwr	$s1,4+$LSB($inp)
++	lwr	$s2,8+$LSB($inp)
++	lwr	$s3,12+$LSB($inp)
++
++	bal	_mips_AES_encrypt
++
++	swr	$s0,0+$LSB($out)
++	swr	$s1,4+$LSB($out)
++	swr	$s2,8+$LSB($out)
++	swr	$s3,12+$LSB($out)
++	swl	$s0,0+$MSB($out)
++	swl	$s1,4+$MSB($out)
++	swl	$s2,8+$MSB($out)
++	swl	$s3,12+$MSB($out)
++
++	.set	noreorder
++	$REG_L	$ra,$FRAMESIZE-1*$SZREG($sp)
++	$REG_L	$fp,$FRAMESIZE-2*$SZREG($sp)
++	$REG_L	$s11,$FRAMESIZE-3*$SZREG($sp)
++	$REG_L	$s10,$FRAMESIZE-4*$SZREG($sp)
++	$REG_L	$s9,$FRAMESIZE-5*$SZREG($sp)
++	$REG_L	$s8,$FRAMESIZE-6*$SZREG($sp)
++	$REG_L	$s7,$FRAMESIZE-7*$SZREG($sp)
++	$REG_L	$s6,$FRAMESIZE-8*$SZREG($sp)
++	$REG_L	$s5,$FRAMESIZE-9*$SZREG($sp)
++	$REG_L	$s4,$FRAMESIZE-10*$SZREG($sp)
++___
++$code.=<<___ if ($flavour =~ /nubi/i);
++	$REG_L	\$15,$FRAMESIZE-11*$SZREG($sp)
++	$REG_L	\$14,$FRAMESIZE-12*$SZREG($sp)
++	$REG_L	\$13,$FRAMESIZE-13*$SZREG($sp)
++	$REG_L	\$12,$FRAMESIZE-14*$SZREG($sp)
++	$REG_L	$gp,$FRAMESIZE-15*$SZREG($sp)
++___
++$code.=<<___;
++	jr	$ra
++	$PTR_ADD $sp,$FRAMESIZE
++.end	AES_encrypt
++___
++
++$code.=<<___;
++.align	5
++.ent	_mips_AES_decrypt
++_mips_AES_decrypt:
++	.frame	$sp,0,$ra
++	.set	reorder
++	lw	$t0,0($key)
++	lw	$t1,4($key)
++	lw	$t2,8($key)
++	lw	$t3,12($key)
++	lw	$cnt,240($key)
++	$PTR_ADD $key0,$key,16
++
++	xor	$s0,$t0
++	xor	$s1,$t1
++	xor	$s2,$t2
++	xor	$s3,$t3
++
++	sub	$cnt,1
++#if defined(__mips_smartmips)
++	ext	$i0,$s3,16,8
++.Loop_dec:
++	ext	$i1,$s0,16,8
++	ext	$i2,$s1,16,8
++	ext	$i3,$s2,16,8
++	lwxs	$t0,$i0($Tbl)		# Td1[s3>>16]
++	ext	$i0,$s2,8,8
++	lwxs	$t1,$i1($Tbl)		# Td1[s0>>16]
++	ext	$i1,$s3,8,8
++	lwxs	$t2,$i2($Tbl)		# Td1[s1>>16]
++	ext	$i2,$s0,8,8
++	lwxs	$t3,$i3($Tbl)		# Td1[s2>>16]
++	ext	$i3,$s1,8,8
++
++	lwxs	$t4,$i0($Tbl)		# Td2[s2>>8]
++	ext	$i0,$s1,0,8
++	lwxs	$t5,$i1($Tbl)		# Td2[s3>>8]
++	ext	$i1,$s2,0,8
++	lwxs	$t6,$i2($Tbl)		# Td2[s0>>8]
++	ext	$i2,$s3,0,8
++	lwxs	$t7,$i3($Tbl)		# Td2[s1>>8]
++	ext	$i3,$s0,0,8
++
++	lwxs	$t8,$i0($Tbl)		# Td3[s1]
++	ext	$i0,$s0,24,8
++	lwxs	$t9,$i1($Tbl)		# Td3[s2]
++	ext	$i1,$s1,24,8
++	lwxs	$t10,$i2($Tbl)		# Td3[s3]
++	ext	$i2,$s2,24,8
++	lwxs	$t11,$i3($Tbl)		# Td3[s0]
++	ext	$i3,$s3,24,8
++
++	rotr	$t0,$t0,8
++	rotr	$t1,$t1,8
++	rotr	$t2,$t2,8
++	rotr	$t3,$t3,8
++
++	rotr	$t4,$t4,16
++	rotr	$t5,$t5,16
++	rotr	$t6,$t6,16
++	rotr	$t7,$t7,16
++
++	xor	$t0,$t4
++	lwxs	$t4,$i0($Tbl)		# Td0[s0>>24]
++	xor	$t1,$t5
++	lwxs	$t5,$i1($Tbl)		# Td0[s1>>24]
++	xor	$t2,$t6
++	lwxs	$t6,$i2($Tbl)		# Td0[s2>>24]
++	xor	$t3,$t7
++	lwxs	$t7,$i3($Tbl)		# Td0[s3>>24]
++
++	rotr	$t8,$t8,24
++	lw	$s0,0($key0)
++	rotr	$t9,$t9,24
++	lw	$s1,4($key0)
++	rotr	$t10,$t10,24
++	lw	$s2,8($key0)
++	rotr	$t11,$t11,24
++	lw	$s3,12($key0)
++
++	xor	$t0,$t8
++	xor	$t1,$t9
++	xor	$t2,$t10
++	xor	$t3,$t11
++
++	xor	$t0,$t4
++	xor	$t1,$t5
++	xor	$t2,$t6
++	xor	$t3,$t7
++
++	sub	$cnt,1
++	$PTR_ADD $key0,16
++	xor	$s0,$t0
++	xor	$s1,$t1
++	xor	$s2,$t2
++	xor	$s3,$t3
++	.set	noreorder
++	bnez	$cnt,.Loop_dec
++	ext	$i0,$s3,16,8
++
++	_xtr	$i0,$s3,16-2
++#else
++	_xtr	$i0,$s3,16-2
++.Loop_dec:
++	_xtr	$i1,$s0,16-2
++	_xtr	$i2,$s1,16-2
++	_xtr	$i3,$s2,16-2
++	and	$i0,0x3fc
++	and	$i1,0x3fc
++	and	$i2,0x3fc
++	and	$i3,0x3fc
++	$PTR_ADD $i0,$Tbl
++	$PTR_ADD $i1,$Tbl
++	$PTR_ADD $i2,$Tbl
++	$PTR_ADD $i3,$Tbl
++#if defined(_MIPS_ARCH_MIPS32R2) || defined(_MIPS_ARCH_MIPS64R2)
++	lw	$t0,0($i0)		# Td1[s3>>16]
++	_xtr	$i0,$s2,8-2
++	lw	$t1,0($i1)		# Td1[s0>>16]
++	_xtr	$i1,$s3,8-2
++	lw	$t2,0($i2)		# Td1[s1>>16]
++	_xtr	$i2,$s0,8-2
++	lw	$t3,0($i3)		# Td1[s2>>16]
++	_xtr	$i3,$s1,8-2
++#else
++	lwl	$t0,3($i0)		# Td1[s3>>16]
++	lwl	$t1,3($i1)		# Td1[s0>>16]
++	lwl	$t2,3($i2)		# Td1[s1>>16]
++	lwl	$t3,3($i3)		# Td1[s2>>16]
++	lwr	$t0,2($i0)		# Td1[s3>>16]
++	_xtr	$i0,$s2,8-2
++	lwr	$t1,2($i1)		# Td1[s0>>16]
++	_xtr	$i1,$s3,8-2
++	lwr	$t2,2($i2)		# Td1[s1>>16]
++	_xtr	$i2,$s0,8-2
++	lwr	$t3,2($i3)		# Td1[s2>>16]
++	_xtr	$i3,$s1,8-2
++#endif
++
++	and	$i0,0x3fc
++	and	$i1,0x3fc
++	and	$i2,0x3fc
++	and	$i3,0x3fc
++	$PTR_ADD $i0,$Tbl
++	$PTR_ADD $i1,$Tbl
++	$PTR_ADD $i2,$Tbl
++	$PTR_ADD $i3,$Tbl
++#if defined(_MIPS_ARCH_MIPS32R2) || defined(_MIPS_ARCH_MIPS64R2)
++	rotr	$t0,$t0,8
++	rotr	$t1,$t1,8
++	rotr	$t2,$t2,8
++	rotr	$t3,$t3,8
++# if defined(_MIPSEL)
++	lw	$t4,0($i0)		# Td2[s2>>8]
++	_xtr	$i0,$s1,0-2
++	lw	$t5,0($i1)		# Td2[s3>>8]
++	_xtr	$i1,$s2,0-2
++	lw	$t6,0($i2)		# Td2[s0>>8]
++	_xtr	$i2,$s3,0-2
++	lw	$t7,0($i3)		# Td2[s1>>8]
++	_xtr	$i3,$s0,0-2
++
++	and	$i0,0x3fc
++	and	$i1,0x3fc
++	and	$i2,0x3fc
++	and	$i3,0x3fc
++	$PTR_ADD $i0,$Tbl
++	$PTR_ADD $i1,$Tbl
++	$PTR_ADD $i2,$Tbl
++	$PTR_ADD $i3,$Tbl
++	lw	$t8,0($i0)		# Td3[s1]
++	$PTR_INS $i0,$s0,2,8
++	lw	$t9,0($i1)		# Td3[s2]
++	$PTR_INS $i1,$s1,2,8
++	lw	$t10,0($i2)		# Td3[s3]
++	$PTR_INS $i2,$s2,2,8
++	lw	$t11,0($i3)		# Td3[s0]
++	$PTR_INS $i3,$s3,2,8
++#else
++	lw	$t4,0($i0)		# Td2[s2>>8]
++	$PTR_INS $i0,$s1,2,8
++	lw	$t5,0($i1)		# Td2[s3>>8]
++	$PTR_INS $i1,$s2,2,8
++	lw	$t6,0($i2)		# Td2[s0>>8]
++	$PTR_INS $i2,$s3,2,8
++	lw	$t7,0($i3)		# Td2[s1>>8]
++	$PTR_INS $i3,$s0,2,8
++
++	lw	$t8,0($i0)		# Td3[s1]
++	_xtr	$i0,$s0,24-2
++	lw	$t9,0($i1)		# Td3[s2]
++	_xtr	$i1,$s1,24-2
++	lw	$t10,0($i2)		# Td3[s3]
++	_xtr	$i2,$s2,24-2
++	lw	$t11,0($i3)		# Td3[s0]
++	_xtr	$i3,$s3,24-2
++
++	and	$i0,0x3fc
++	and	$i1,0x3fc
++	and	$i2,0x3fc
++	and	$i3,0x3fc
++	$PTR_ADD $i0,$Tbl
++	$PTR_ADD $i1,$Tbl
++	$PTR_ADD $i2,$Tbl
++	$PTR_ADD $i3,$Tbl
++#endif
++	rotr	$t4,$t4,16
++	rotr	$t5,$t5,16
++	rotr	$t6,$t6,16
++	rotr	$t7,$t7,16
++
++	rotr	$t8,$t8,24
++	rotr	$t9,$t9,24
++	rotr	$t10,$t10,24
++	rotr	$t11,$t11,24
++#else
++	lwl	$t4,2($i0)		# Td2[s2>>8]
++	lwl	$t5,2($i1)		# Td2[s3>>8]
++	lwl	$t6,2($i2)		# Td2[s0>>8]
++	lwl	$t7,2($i3)		# Td2[s1>>8]
++	lwr	$t4,1($i0)		# Td2[s2>>8]
++	_xtr	$i0,$s1,0-2
++	lwr	$t5,1($i1)		# Td2[s3>>8]
++	_xtr	$i1,$s2,0-2
++	lwr	$t6,1($i2)		# Td2[s0>>8]
++	_xtr	$i2,$s3,0-2
++	lwr	$t7,1($i3)		# Td2[s1>>8]
++	_xtr	$i3,$s0,0-2
++
++	and	$i0,0x3fc
++	and	$i1,0x3fc
++	and	$i2,0x3fc
++	and	$i3,0x3fc
++	$PTR_ADD $i0,$Tbl
++	$PTR_ADD $i1,$Tbl
++	$PTR_ADD $i2,$Tbl
++	$PTR_ADD $i3,$Tbl
++	lwl	$t8,1($i0)		# Td3[s1]
++	lwl	$t9,1($i1)		# Td3[s2]
++	lwl	$t10,1($i2)		# Td3[s3]
++	lwl	$t11,1($i3)		# Td3[s0]
++	lwr	$t8,0($i0)		# Td3[s1]
++	_xtr	$i0,$s0,24-2
++	lwr	$t9,0($i1)		# Td3[s2]
++	_xtr	$i1,$s1,24-2
++	lwr	$t10,0($i2)		# Td3[s3]
++	_xtr	$i2,$s2,24-2
++	lwr	$t11,0($i3)		# Td3[s0]
++	_xtr	$i3,$s3,24-2
++
++	and	$i0,0x3fc
++	and	$i1,0x3fc
++	and	$i2,0x3fc
++	and	$i3,0x3fc
++	$PTR_ADD $i0,$Tbl
++	$PTR_ADD $i1,$Tbl
++	$PTR_ADD $i2,$Tbl
++	$PTR_ADD $i3,$Tbl
++#endif
++
++	xor	$t0,$t4
++	lw	$t4,0($i0)		# Td0[s0>>24]
++	xor	$t1,$t5
++	lw	$t5,0($i1)		# Td0[s1>>24]
++	xor	$t2,$t6
++	lw	$t6,0($i2)		# Td0[s2>>24]
++	xor	$t3,$t7
++	lw	$t7,0($i3)		# Td0[s3>>24]
++
++	xor	$t0,$t8
++	lw	$s0,0($key0)
++	xor	$t1,$t9
++	lw	$s1,4($key0)
++	xor	$t2,$t10
++	lw	$s2,8($key0)
++	xor	$t3,$t11
++	lw	$s3,12($key0)
++
++	xor	$t0,$t4
++	xor	$t1,$t5
++	xor	$t2,$t6
++	xor	$t3,$t7
++
++	sub	$cnt,1
++	$PTR_ADD $key0,16
++	xor	$s0,$t0
++	xor	$s1,$t1
++	xor	$s2,$t2
++	xor	$s3,$t3
++	.set	noreorder
++	bnez	$cnt,.Loop_dec
++	_xtr	$i0,$s3,16-2
++#endif
++
++	.set	reorder
++	lw	$t4,1024($Tbl)		# prefetch Td4
++	_xtr	$i0,$s3,16
++	lw	$t5,1024+32($Tbl)
++	_xtr	$i1,$s0,16
++	lw	$t6,1024+64($Tbl)
++	_xtr	$i2,$s1,16
++	lw	$t7,1024+96($Tbl)
++	_xtr	$i3,$s2,16
++	lw	$t8,1024+128($Tbl)
++	and	$i0,0xff
++	lw	$t9,1024+160($Tbl)
++	and	$i1,0xff
++	lw	$t10,1024+192($Tbl)
++	and	$i2,0xff
++	lw	$t11,1024+224($Tbl)
++	and	$i3,0xff
++
++	$PTR_ADD $i0,$Tbl
++	$PTR_ADD $i1,$Tbl
++	$PTR_ADD $i2,$Tbl
++	$PTR_ADD $i3,$Tbl
++	lbu	$t0,1024($i0)		# Td4[s3>>16]
++	_xtr	$i0,$s2,8
++	lbu	$t1,1024($i1)		# Td4[s0>>16]
++	_xtr	$i1,$s3,8
++	lbu	$t2,1024($i2)		# Td4[s1>>16]
++	_xtr	$i2,$s0,8
++	lbu	$t3,1024($i3)		# Td4[s2>>16]
++	_xtr	$i3,$s1,8
++
++	and	$i0,0xff
++	and	$i1,0xff
++	and	$i2,0xff
++	and	$i3,0xff
++	$PTR_ADD $i0,$Tbl
++	$PTR_ADD $i1,$Tbl
++	$PTR_ADD $i2,$Tbl
++	$PTR_ADD $i3,$Tbl
++#if defined(_MIPS_ARCH_MIPS32R2) || defined(_MIPS_ARCH_MIPS64R2)
++# if defined(_MIPSEL)
++	lbu	$t4,1024($i0)		# Td4[s2>>8]
++	$PTR_INS $i0,$s0,0,8
++	lbu	$t5,1024($i1)		# Td4[s3>>8]
++	$PTR_INS $i1,$s1,0,8
++	lbu	$t6,1024($i2)		# Td4[s0>>8]
++	$PTR_INS $i2,$s2,0,8
++	lbu	$t7,1024($i3)		# Td4[s1>>8]
++	$PTR_INS $i3,$s3,0,8
++
++	lbu	$t8,1024($i0)		# Td4[s0>>24]
++	_xtr	$i0,$s1,0
++	lbu	$t9,1024($i1)		# Td4[s1>>24]
++	_xtr	$i1,$s2,0
++	lbu	$t10,1024($i2)		# Td4[s2>>24]
++	_xtr	$i2,$s3,0
++	lbu	$t11,1024($i3)		# Td4[s3>>24]
++	_xtr	$i3,$s0,0
++
++	$PTR_ADD $i0,$Tbl
++	$PTR_ADD $i1,$Tbl
++	$PTR_ADD $i2,$Tbl
++	$PTR_ADD $i3,$Tbl
++# else
++	lbu	$t4,1024($i0)		# Td4[s2>>8]
++	_xtr	$i0,$s0,24
++	lbu	$t5,1024($i1)		# Td4[s3>>8]
++	_xtr	$i1,$s1,24
++	lbu	$t6,1024($i2)		# Td4[s0>>8]
++	_xtr	$i2,$s2,24
++	lbu	$t7,1024($i3)		# Td4[s1>>8]
++	_xtr	$i3,$s3,24
++
++	$PTR_ADD $i0,$Tbl
++	$PTR_ADD $i1,$Tbl
++	$PTR_ADD $i2,$Tbl
++	$PTR_ADD $i3,$Tbl
++	lbu	$t8,1024($i0)		# Td4[s0>>24]
++	$PTR_INS $i0,$s1,0,8
++	lbu	$t9,1024($i1)		# Td4[s1>>24]
++	$PTR_INS $i1,$s2,0,8
++	lbu	$t10,1024($i2)		# Td4[s2>>24]
++	$PTR_INS $i2,$s3,0,8
++	lbu	$t11,1024($i3)		# Td4[s3>>24]
++	$PTR_INS $i3,$s0,0,8
++# endif
++	_ins	$t0,16
++	_ins	$t1,16
++	_ins	$t2,16
++	_ins	$t3,16
++
++	_ins2	$t0,$t4,8
++	lbu	$t4,1024($i0)		# Td4[s1]
++	_ins2	$t1,$t5,8
++	lbu	$t5,1024($i1)		# Td4[s2]
++	_ins2	$t2,$t6,8
++	lbu	$t6,1024($i2)		# Td4[s3]
++	_ins2	$t3,$t7,8
++	lbu	$t7,1024($i3)		# Td4[s0]
++
++	_ins2	$t0,$t8,24
++	lw	$s0,0($key0)
++	_ins2	$t1,$t9,24
++	lw	$s1,4($key0)
++	_ins2	$t2,$t10,24
++	lw	$s2,8($key0)
++	_ins2	$t3,$t11,24
++	lw	$s3,12($key0)
++
++	_ins2	$t0,$t4,0
++	_ins2	$t1,$t5,0
++	_ins2	$t2,$t6,0
++	_ins2	$t3,$t7,0
++#else
++	lbu	$t4,1024($i0)		# Td4[s2>>8]
++	_xtr	$i0,$s0,24
++	lbu	$t5,1024($i1)		# Td4[s3>>8]
++	_xtr	$i1,$s1,24
++	lbu	$t6,1024($i2)		# Td4[s0>>8]
++	_xtr	$i2,$s2,24
++	lbu	$t7,1024($i3)		# Td4[s1>>8]
++	_xtr	$i3,$s3,24
++
++	$PTR_ADD $i0,$Tbl
++	$PTR_ADD $i1,$Tbl
++	$PTR_ADD $i2,$Tbl
++	$PTR_ADD $i3,$Tbl
++	lbu	$t8,1024($i0)		# Td4[s0>>24]
++	_xtr	$i0,$s1,0
++	lbu	$t9,1024($i1)		# Td4[s1>>24]
++	_xtr	$i1,$s2,0
++	lbu	$t10,1024($i2)		# Td4[s2>>24]
++	_xtr	$i2,$s3,0
++	lbu	$t11,1024($i3)		# Td4[s3>>24]
++	_xtr	$i3,$s0,0
++
++	$PTR_ADD $i0,$Tbl
++	$PTR_ADD $i1,$Tbl
++	$PTR_ADD $i2,$Tbl
++	$PTR_ADD $i3,$Tbl
++
++	_ins	$t0,16
++	_ins	$t1,16
++	_ins	$t2,16
++	_ins	$t3,16
++
++	_ins	$t4,8
++	_ins	$t5,8
++	_ins	$t6,8
++	_ins	$t7,8
++
++	xor	$t0,$t4
++	lbu	$t4,1024($i0)		# Td4[s1]
++	xor	$t1,$t5
++	lbu	$t5,1024($i1)		# Td4[s2]
++	xor	$t2,$t6
++	lbu	$t6,1024($i2)		# Td4[s3]
++	xor	$t3,$t7
++	lbu	$t7,1024($i3)		# Td4[s0]
++
++	_ins	$t8,24
++	lw	$s0,0($key0)
++	_ins	$t9,24
++	lw	$s1,4($key0)
++	_ins	$t10,24
++	lw	$s2,8($key0)
++	_ins	$t11,24
++	lw	$s3,12($key0)
++
++	xor	$t0,$t8
++	xor	$t1,$t9
++	xor	$t2,$t10
++	xor	$t3,$t11
++
++	_ins	$t4,0
++	_ins	$t5,0
++	_ins	$t6,0
++	_ins	$t7,0
++
++	xor	$t0,$t4
++	xor	$t1,$t5
++	xor	$t2,$t6
++	xor	$t3,$t7
++#endif
++
++	xor	$s0,$t0
++	xor	$s1,$t1
++	xor	$s2,$t2
++	xor	$s3,$t3
++
++	jr	$ra
++.end	_mips_AES_decrypt
++
++.align	5
++.globl	AES_decrypt
++.ent	AES_decrypt
++AES_decrypt:
++	.frame	$sp,$FRAMESIZE,$ra
++	.mask	$SAVED_REGS_MASK,-$SZREG
++	.set	noreorder
++___
++$code.=<<___ if ($flavour =~ /o32/i);	# o32 PIC-ification
++	.cpload	$pf
++___
++$code.=<<___;
++	$PTR_SUB $sp,$FRAMESIZE
++	$REG_S	$ra,$FRAMESIZE-1*$SZREG($sp)
++	$REG_S	$fp,$FRAMESIZE-2*$SZREG($sp)
++	$REG_S	$s11,$FRAMESIZE-3*$SZREG($sp)
++	$REG_S	$s10,$FRAMESIZE-4*$SZREG($sp)
++	$REG_S	$s9,$FRAMESIZE-5*$SZREG($sp)
++	$REG_S	$s8,$FRAMESIZE-6*$SZREG($sp)
++	$REG_S	$s7,$FRAMESIZE-7*$SZREG($sp)
++	$REG_S	$s6,$FRAMESIZE-8*$SZREG($sp)
++	$REG_S	$s5,$FRAMESIZE-9*$SZREG($sp)
++	$REG_S	$s4,$FRAMESIZE-10*$SZREG($sp)
++___
++$code.=<<___ if ($flavour =~ /nubi/i);	# optimize non-nubi prologue
++	$REG_S	\$15,$FRAMESIZE-11*$SZREG($sp)
++	$REG_S	\$14,$FRAMESIZE-12*$SZREG($sp)
++	$REG_S	\$13,$FRAMESIZE-13*$SZREG($sp)
++	$REG_S	\$12,$FRAMESIZE-14*$SZREG($sp)
++	$REG_S	$gp,$FRAMESIZE-15*$SZREG($sp)
++___
++$code.=<<___ if ($flavour !~ /o32/i);	# non-o32 PIC-ification
++	.cplocal	$Tbl
++	.cpsetup	$pf,$zero,AES_decrypt
++___
++$code.=<<___;
++	.set	reorder
++	$PTR_LA	$Tbl,AES_Td		# PIC-ified 'load address'
++
++	lwl	$s0,0+$MSB($inp)
++	lwl	$s1,4+$MSB($inp)
++	lwl	$s2,8+$MSB($inp)
++	lwl	$s3,12+$MSB($inp)
++	lwr	$s0,0+$LSB($inp)
++	lwr	$s1,4+$LSB($inp)
++	lwr	$s2,8+$LSB($inp)
++	lwr	$s3,12+$LSB($inp)
++
++	bal	_mips_AES_decrypt
++
++	swr	$s0,0+$LSB($out)
++	swr	$s1,4+$LSB($out)
++	swr	$s2,8+$LSB($out)
++	swr	$s3,12+$LSB($out)
++	swl	$s0,0+$MSB($out)
++	swl	$s1,4+$MSB($out)
++	swl	$s2,8+$MSB($out)
++	swl	$s3,12+$MSB($out)
++
++	.set	noreorder
++	$REG_L	$ra,$FRAMESIZE-1*$SZREG($sp)
++	$REG_L	$fp,$FRAMESIZE-2*$SZREG($sp)
++	$REG_L	$s11,$FRAMESIZE-3*$SZREG($sp)
++	$REG_L	$s10,$FRAMESIZE-4*$SZREG($sp)
++	$REG_L	$s9,$FRAMESIZE-5*$SZREG($sp)
++	$REG_L	$s8,$FRAMESIZE-6*$SZREG($sp)
++	$REG_L	$s7,$FRAMESIZE-7*$SZREG($sp)
++	$REG_L	$s6,$FRAMESIZE-8*$SZREG($sp)
++	$REG_L	$s5,$FRAMESIZE-9*$SZREG($sp)
++	$REG_L	$s4,$FRAMESIZE-10*$SZREG($sp)
++___
++$code.=<<___ if ($flavour =~ /nubi/i);
++	$REG_L	\$15,$FRAMESIZE-11*$SZREG($sp)
++	$REG_L	\$14,$FRAMESIZE-12*$SZREG($sp)
++	$REG_L	\$13,$FRAMESIZE-13*$SZREG($sp)
++	$REG_L	\$12,$FRAMESIZE-14*$SZREG($sp)
++	$REG_L	$gp,$FRAMESIZE-15*$SZREG($sp)
++___
++$code.=<<___;
++	jr	$ra
++	$PTR_ADD $sp,$FRAMESIZE
++.end	AES_decrypt
++___
++}}}
++
++{{{
++my $FRAMESIZE=8*$SZREG;
++my $SAVED_REGS_MASK = ($flavour =~ /nubi/i) ? "0xc000f008" : "0xc0000000";
++
++my ($inp,$bits,$key,$Tbl)=($a0,$a1,$a2,$a3);
++my ($rk0,$rk1,$rk2,$rk3,$rk4,$rk5,$rk6,$rk7)=($a4,$a5,$a6,$a7,$s0,$s1,$s2,$s3);
++my ($i0,$i1,$i2,$i3)=($at,$t0,$t1,$t2);
++my ($rcon,$cnt)=($gp,$fp);
++
++$code.=<<___;
++.align	5
++.ent	_mips_AES_set_encrypt_key
++_mips_AES_set_encrypt_key:
++	.frame	$sp,0,$ra
++	.set	noreorder
++	beqz	$inp,.Lekey_done
++	li	$t0,-1
++	beqz	$key,.Lekey_done
++	$PTR_ADD $rcon,$Tbl,256
++
++	.set	reorder
++	lwl	$rk0,0+$MSB($inp)	# load 128 bits
++	lwl	$rk1,4+$MSB($inp)
++	lwl	$rk2,8+$MSB($inp)
++	lwl	$rk3,12+$MSB($inp)
++	li	$at,128
++	lwr	$rk0,0+$LSB($inp)
++	lwr	$rk1,4+$LSB($inp)
++	lwr	$rk2,8+$LSB($inp)
++	lwr	$rk3,12+$LSB($inp)
++	.set	noreorder
++	beq	$bits,$at,.L128bits
++	li	$cnt,10
++
++	.set	reorder
++	lwl	$rk4,16+$MSB($inp)	# load 192 bits
++	lwl	$rk5,20+$MSB($inp)
++	li	$at,192
++	lwr	$rk4,16+$LSB($inp)
++	lwr	$rk5,20+$LSB($inp)
++	.set	noreorder
++	beq	$bits,$at,.L192bits
++	li	$cnt,8
++
++	.set	reorder
++	lwl	$rk6,24+$MSB($inp)	# load 256 bits
++	lwl	$rk7,28+$MSB($inp)
++	li	$at,256
++	lwr	$rk6,24+$LSB($inp)
++	lwr	$rk7,28+$LSB($inp)
++	.set	noreorder
++	beq	$bits,$at,.L256bits
++	li	$cnt,7
++
++	b	.Lekey_done
++	li	$t0,-2
++
++.align	4
++.L128bits:
++	.set	reorder
++	srl	$i0,$rk3,16
++	srl	$i1,$rk3,8
++	and	$i0,0xff
++	and	$i1,0xff
++	and	$i2,$rk3,0xff
++	srl	$i3,$rk3,24
++	$PTR_ADD $i0,$Tbl
++	$PTR_ADD $i1,$Tbl
++	$PTR_ADD $i2,$Tbl
++	$PTR_ADD $i3,$Tbl
++	lbu	$i0,0($i0)
++	lbu	$i1,0($i1)
++	lbu	$i2,0($i2)
++	lbu	$i3,0($i3)
++
++	sw	$rk0,0($key)
++	sw	$rk1,4($key)
++	sw	$rk2,8($key)
++	sw	$rk3,12($key)
++	sub	$cnt,1
++	$PTR_ADD $key,16
++
++	_bias	$i0,24
++	_bias	$i1,16
++	_bias	$i2,8
++	_bias	$i3,0
++
++	xor	$rk0,$i0
++	lw	$i0,0($rcon)
++	xor	$rk0,$i1
++	xor	$rk0,$i2
++	xor	$rk0,$i3
++	xor	$rk0,$i0
++
++	xor	$rk1,$rk0
++	xor	$rk2,$rk1
++	xor	$rk3,$rk2
++
++	.set	noreorder
++	bnez	$cnt,.L128bits
++	$PTR_ADD $rcon,4
++
++	sw	$rk0,0($key)
++	sw	$rk1,4($key)
++	sw	$rk2,8($key)
++	li	$cnt,10
++	sw	$rk3,12($key)
++	li	$t0,0
++	sw	$cnt,80($key)
++	b	.Lekey_done
++	$PTR_SUB $key,10*16
++
++.align	4
++.L192bits:
++	.set	reorder
++	srl	$i0,$rk5,16
++	srl	$i1,$rk5,8
++	and	$i0,0xff
++	and	$i1,0xff
++	and	$i2,$rk5,0xff
++	srl	$i3,$rk5,24
++	$PTR_ADD $i0,$Tbl
++	$PTR_ADD $i1,$Tbl
++	$PTR_ADD $i2,$Tbl
++	$PTR_ADD $i3,$Tbl
++	lbu	$i0,0($i0)
++	lbu	$i1,0($i1)
++	lbu	$i2,0($i2)
++	lbu	$i3,0($i3)
++
++	sw	$rk0,0($key)
++	sw	$rk1,4($key)
++	sw	$rk2,8($key)
++	sw	$rk3,12($key)
++	sw	$rk4,16($key)
++	sw	$rk5,20($key)
++	sub	$cnt,1
++	$PTR_ADD $key,24
++
++	_bias	$i0,24
++	_bias	$i1,16
++	_bias	$i2,8
++	_bias	$i3,0
++
++	xor	$rk0,$i0
++	lw	$i0,0($rcon)
++	xor	$rk0,$i1
++	xor	$rk0,$i2
++	xor	$rk0,$i3
++	xor	$rk0,$i0
++
++	xor	$rk1,$rk0
++	xor	$rk2,$rk1
++	xor	$rk3,$rk2
++	xor	$rk4,$rk3
++	xor	$rk5,$rk4
++
++	.set	noreorder
++	bnez	$cnt,.L192bits
++	$PTR_ADD $rcon,4
++
++	sw	$rk0,0($key)
++	sw	$rk1,4($key)
++	sw	$rk2,8($key)
++	li	$cnt,12
++	sw	$rk3,12($key)
++	li	$t0,0
++	sw	$cnt,48($key)
++	b	.Lekey_done
++	$PTR_SUB $key,12*16
++
++.align	4
++.L256bits:
++	.set	reorder
++	srl	$i0,$rk7,16
++	srl	$i1,$rk7,8
++	and	$i0,0xff
++	and	$i1,0xff
++	and	$i2,$rk7,0xff
++	srl	$i3,$rk7,24
++	$PTR_ADD $i0,$Tbl
++	$PTR_ADD $i1,$Tbl
++	$PTR_ADD $i2,$Tbl
++	$PTR_ADD $i3,$Tbl
++	lbu	$i0,0($i0)
++	lbu	$i1,0($i1)
++	lbu	$i2,0($i2)
++	lbu	$i3,0($i3)
++
++	sw	$rk0,0($key)
++	sw	$rk1,4($key)
++	sw	$rk2,8($key)
++	sw	$rk3,12($key)
++	sw	$rk4,16($key)
++	sw	$rk5,20($key)
++	sw	$rk6,24($key)
++	sw	$rk7,28($key)
++	sub	$cnt,1
++
++	_bias	$i0,24
++	_bias	$i1,16
++	_bias	$i2,8
++	_bias	$i3,0
++
++	xor	$rk0,$i0
++	lw	$i0,0($rcon)
++	xor	$rk0,$i1
++	xor	$rk0,$i2
++	xor	$rk0,$i3
++	xor	$rk0,$i0
++
++	xor	$rk1,$rk0
++	xor	$rk2,$rk1
++	xor	$rk3,$rk2
++	beqz	$cnt,.L256bits_done
++
++	srl	$i0,$rk3,24
++	srl	$i1,$rk3,16
++	srl	$i2,$rk3,8
++	and	$i3,$rk3,0xff
++	and	$i1,0xff
++	and	$i2,0xff
++	$PTR_ADD $i0,$Tbl
++	$PTR_ADD $i1,$Tbl
++	$PTR_ADD $i2,$Tbl
++	$PTR_ADD $i3,$Tbl
++	lbu	$i0,0($i0)
++	lbu	$i1,0($i1)
++	lbu	$i2,0($i2)
++	lbu	$i3,0($i3)
++	sll	$i0,24
++	sll	$i1,16
++	sll	$i2,8
++
++	xor	$rk4,$i0
++	xor	$rk4,$i1
++	xor	$rk4,$i2
++	xor	$rk4,$i3
++
++	xor	$rk5,$rk4
++	xor	$rk6,$rk5
++	xor	$rk7,$rk6
++
++	$PTR_ADD $key,32
++	.set	noreorder
++	b	.L256bits
++	$PTR_ADD $rcon,4
++
++.L256bits_done:
++	sw	$rk0,32($key)
++	sw	$rk1,36($key)
++	sw	$rk2,40($key)
++	li	$cnt,14
++	sw	$rk3,44($key)
++	li	$t0,0
++	sw	$cnt,48($key)
++	$PTR_SUB $key,12*16
++
++.Lekey_done:
++	jr	$ra
++	nop
++.end	_mips_AES_set_encrypt_key
++
++.globl	AES_set_encrypt_key
++.ent	AES_set_encrypt_key
++AES_set_encrypt_key:
++	.frame	$sp,$FRAMESIZE,$ra
++	.mask	$SAVED_REGS_MASK,-$SZREG
++	.set	noreorder
++___
++$code.=<<___ if ($flavour =~ /o32/i);	# o32 PIC-ification
++	.cpload	$pf
++___
++$code.=<<___;
++	$PTR_SUB $sp,$FRAMESIZE
++	$REG_S	$ra,$FRAMESIZE-1*$SZREG($sp)
++	$REG_S	$fp,$FRAMESIZE-2*$SZREG($sp)
++___
++$code.=<<___ if ($flavour =~ /nubi/i);	# optimize non-nubi prologue
++	$REG_S	$s3,$FRAMESIZE-3*$SZREG($sp)
++	$REG_S	$s2,$FRAMESIZE-4*$SZREG($sp)
++	$REG_S	$s1,$FRAMESIZE-5*$SZREG($sp)
++	$REG_S	$s0,$FRAMESIZE-6*$SZREG($sp)
++	$REG_S	$gp,$FRAMESIZE-7*$SZREG($sp)
++___
++$code.=<<___ if ($flavour !~ /o32/i);	# non-o32 PIC-ification
++	.cplocal	$Tbl
++	.cpsetup	$pf,$zero,AES_set_encrypt_key
++___
++$code.=<<___;
++	.set	reorder
++	$PTR_LA	$Tbl,AES_Te4		# PIC-ified 'load address'
++
++	bal	_mips_AES_set_encrypt_key
++
++	.set	noreorder
++	move	$a0,$t0
++	$REG_L	$ra,$FRAMESIZE-1*$SZREG($sp)
++	$REG_L	$fp,$FRAMESIZE-2*$SZREG($sp)
++___
++$code.=<<___ if ($flavour =~ /nubi/i);
++	$REG_L	$s3,$FRAMESIZE-11*$SZREG($sp)
++	$REG_L	$s2,$FRAMESIZE-12*$SZREG($sp)
++	$REG_L	$s1,$FRAMESIZE-13*$SZREG($sp)
++	$REG_L	$s0,$FRAMESIZE-14*$SZREG($sp)
++	$REG_L	$gp,$FRAMESIZE-15*$SZREG($sp)
++___
++$code.=<<___;
++	jr	$ra
++	$PTR_ADD $sp,$FRAMESIZE
++.end	AES_set_encrypt_key
++___
++
++my ($head,$tail)=($inp,$bits);
++my ($tp1,$tp2,$tp4,$tp8,$tp9,$tpb,$tpd,$tpe)=($a4,$a5,$a6,$a7,$s0,$s1,$s2,$s3);
++my ($m,$x80808080,$x7f7f7f7f,$x1b1b1b1b)=($at,$t0,$t1,$t2);
++$code.=<<___;
++.align	5
++.globl	AES_set_decrypt_key
++.ent	AES_set_decrypt_key
++AES_set_decrypt_key:
++	.frame	$sp,$FRAMESIZE,$ra
++	.mask	$SAVED_REGS_MASK,-$SZREG
++	.set	noreorder
++___
++$code.=<<___ if ($flavour =~ /o32/i);	# o32 PIC-ification
++	.cpload	$pf
++___
++$code.=<<___;
++	$PTR_SUB $sp,$FRAMESIZE
++	$REG_S	$ra,$FRAMESIZE-1*$SZREG($sp)
++	$REG_S	$fp,$FRAMESIZE-2*$SZREG($sp)
++___
++$code.=<<___ if ($flavour =~ /nubi/i);	# optimize non-nubi prologue
++	$REG_S	$s3,$FRAMESIZE-3*$SZREG($sp)
++	$REG_S	$s2,$FRAMESIZE-4*$SZREG($sp)
++	$REG_S	$s1,$FRAMESIZE-5*$SZREG($sp)
++	$REG_S	$s0,$FRAMESIZE-6*$SZREG($sp)
++	$REG_S	$gp,$FRAMESIZE-7*$SZREG($sp)
++___
++$code.=<<___ if ($flavour !~ /o32/i);	# non-o32 PIC-ification
++	.cplocal	$Tbl
++	.cpsetup	$pf,$zero,AES_set_decrypt_key
++___
++$code.=<<___;
++	.set	reorder
++	$PTR_LA	$Tbl,AES_Te4		# PIC-ified 'load address'
++
++	bal	_mips_AES_set_encrypt_key
++
++	bltz	$t0,.Ldkey_done
++
++	sll	$at,$cnt,4
++	$PTR_ADD $head,$key,0
++	$PTR_ADD $tail,$key,$at
++.align	4
++.Lswap:
++	lw	$rk0,0($head)
++	lw	$rk1,4($head)
++	lw	$rk2,8($head)
++	lw	$rk3,12($head)
++	lw	$rk4,0($tail)
++	lw	$rk5,4($tail)
++	lw	$rk6,8($tail)
++	lw	$rk7,12($tail)
++	sw	$rk0,0($tail)
++	sw	$rk1,4($tail)
++	sw	$rk2,8($tail)
++	sw	$rk3,12($tail)
++	$PTR_ADD $head,16
++	$PTR_SUB $tail,16
++	sw	$rk4,-16($head)
++	sw	$rk5,-12($head)
++	sw	$rk6,-8($head)
++	sw	$rk7,-4($head)
++	bne	$head,$tail,.Lswap
++
++	lw	$tp1,16($key)		# modulo-scheduled
++	lui	$x80808080,0x8080
++	sub	$cnt,1
++	or	$x80808080,0x8080
++	sll	$cnt,2
++	$PTR_ADD $key,16
++	lui	$x1b1b1b1b,0x1b1b
++	nor	$x7f7f7f7f,$zero,$x80808080
++	or	$x1b1b1b1b,0x1b1b
++.align	4
++.Lmix:
++	and	$m,$tp1,$x80808080
++	and	$tp2,$tp1,$x7f7f7f7f
++	srl	$tp4,$m,7
++	addu	$tp2,$tp2		# tp2<<1
++	subu	$m,$tp4
++	and	$m,$x1b1b1b1b
++	xor	$tp2,$m
++
++	and	$m,$tp2,$x80808080
++	and	$tp4,$tp2,$x7f7f7f7f
++	srl	$tp8,$m,7
++	addu	$tp4,$tp4		# tp4<<1
++	subu	$m,$tp8
++	and	$m,$x1b1b1b1b
++	xor	$tp4,$m
++
++	and	$m,$tp4,$x80808080
++	and	$tp8,$tp4,$x7f7f7f7f
++	srl	$tp9,$m,7
++	addu	$tp8,$tp8		# tp8<<1
++	subu	$m,$tp9
++	and	$m,$x1b1b1b1b
++	xor	$tp8,$m
++
++	xor	$tp9,$tp8,$tp1
++	xor	$tpe,$tp8,$tp4
++	xor	$tpb,$tp9,$tp2
++	xor	$tpd,$tp9,$tp4
++
++#if defined(_MIPS_ARCH_MIPS32R2) || defined(_MIPS_ARCH_MIPS64R2)
++	rotr	$tp1,$tpd,16
++	 xor	$tpe,$tp2
++	rotr	$tp2,$tp9,8
++	xor	$tpe,$tp1
++	rotr	$tp4,$tpb,24
++	xor	$tpe,$tp2
++	lw	$tp1,4($key)		# modulo-scheduled
++	xor	$tpe,$tp4
++#else
++	_ror	$tp1,$tpd,16
++	 xor	$tpe,$tp2
++	_ror	$tp2,$tpd,-16
++	xor	$tpe,$tp1
++	_ror	$tp1,$tp9,8
++	xor	$tpe,$tp2
++	_ror	$tp2,$tp9,-24
++	xor	$tpe,$tp1
++	_ror	$tp1,$tpb,24
++	xor	$tpe,$tp2
++	_ror	$tp2,$tpb,-8
++	xor	$tpe,$tp1
++	lw	$tp1,4($key)		# modulo-scheduled
++	xor	$tpe,$tp2
++#endif
++	sub	$cnt,1
++	sw	$tpe,0($key)
++	$PTR_ADD $key,4
++	bnez	$cnt,.Lmix
++
++	li	$t0,0
++.Ldkey_done:
++	.set	noreorder
++	move	$a0,$t0
++	$REG_L	$ra,$FRAMESIZE-1*$SZREG($sp)
++	$REG_L	$fp,$FRAMESIZE-2*$SZREG($sp)
++___
++$code.=<<___ if ($flavour =~ /nubi/i);
++	$REG_L	$s3,$FRAMESIZE-11*$SZREG($sp)
++	$REG_L	$s2,$FRAMESIZE-12*$SZREG($sp)
++	$REG_L	$s1,$FRAMESIZE-13*$SZREG($sp)
++	$REG_L	$s0,$FRAMESIZE-14*$SZREG($sp)
++	$REG_L	$gp,$FRAMESIZE-15*$SZREG($sp)
++___
++$code.=<<___;
++	jr	$ra
++	$PTR_ADD $sp,$FRAMESIZE
++.end	AES_set_decrypt_key
++___
++}}}
++
++######################################################################
++# Tables are kept in endian-neutral manner
++$code.=<<___;
++.rdata
++.align	10
++AES_Te:
++.byte	0xc6,0x63,0x63,0xa5,	0xf8,0x7c,0x7c,0x84	# Te0
++.byte	0xee,0x77,0x77,0x99,	0xf6,0x7b,0x7b,0x8d
++.byte	0xff,0xf2,0xf2,0x0d,	0xd6,0x6b,0x6b,0xbd
++.byte	0xde,0x6f,0x6f,0xb1,	0x91,0xc5,0xc5,0x54
++.byte	0x60,0x30,0x30,0x50,	0x02,0x01,0x01,0x03
++.byte	0xce,0x67,0x67,0xa9,	0x56,0x2b,0x2b,0x7d
++.byte	0xe7,0xfe,0xfe,0x19,	0xb5,0xd7,0xd7,0x62
++.byte	0x4d,0xab,0xab,0xe6,	0xec,0x76,0x76,0x9a
++.byte	0x8f,0xca,0xca,0x45,	0x1f,0x82,0x82,0x9d
++.byte	0x89,0xc9,0xc9,0x40,	0xfa,0x7d,0x7d,0x87
++.byte	0xef,0xfa,0xfa,0x15,	0xb2,0x59,0x59,0xeb
++.byte	0x8e,0x47,0x47,0xc9,	0xfb,0xf0,0xf0,0x0b
++.byte	0x41,0xad,0xad,0xec,	0xb3,0xd4,0xd4,0x67
++.byte	0x5f,0xa2,0xa2,0xfd,	0x45,0xaf,0xaf,0xea
++.byte	0x23,0x9c,0x9c,0xbf,	0x53,0xa4,0xa4,0xf7
++.byte	0xe4,0x72,0x72,0x96,	0x9b,0xc0,0xc0,0x5b
++.byte	0x75,0xb7,0xb7,0xc2,	0xe1,0xfd,0xfd,0x1c
++.byte	0x3d,0x93,0x93,0xae,	0x4c,0x26,0x26,0x6a
++.byte	0x6c,0x36,0x36,0x5a,	0x7e,0x3f,0x3f,0x41
++.byte	0xf5,0xf7,0xf7,0x02,	0x83,0xcc,0xcc,0x4f
++.byte	0x68,0x34,0x34,0x5c,	0x51,0xa5,0xa5,0xf4
++.byte	0xd1,0xe5,0xe5,0x34,	0xf9,0xf1,0xf1,0x08
++.byte	0xe2,0x71,0x71,0x93,	0xab,0xd8,0xd8,0x73
++.byte	0x62,0x31,0x31,0x53,	0x2a,0x15,0x15,0x3f
++.byte	0x08,0x04,0x04,0x0c,	0x95,0xc7,0xc7,0x52
++.byte	0x46,0x23,0x23,0x65,	0x9d,0xc3,0xc3,0x5e
++.byte	0x30,0x18,0x18,0x28,	0x37,0x96,0x96,0xa1
++.byte	0x0a,0x05,0x05,0x0f,	0x2f,0x9a,0x9a,0xb5
++.byte	0x0e,0x07,0x07,0x09,	0x24,0x12,0x12,0x36
++.byte	0x1b,0x80,0x80,0x9b,	0xdf,0xe2,0xe2,0x3d
++.byte	0xcd,0xeb,0xeb,0x26,	0x4e,0x27,0x27,0x69
++.byte	0x7f,0xb2,0xb2,0xcd,	0xea,0x75,0x75,0x9f
++.byte	0x12,0x09,0x09,0x1b,	0x1d,0x83,0x83,0x9e
++.byte	0x58,0x2c,0x2c,0x74,	0x34,0x1a,0x1a,0x2e
++.byte	0x36,0x1b,0x1b,0x2d,	0xdc,0x6e,0x6e,0xb2
++.byte	0xb4,0x5a,0x5a,0xee,	0x5b,0xa0,0xa0,0xfb
++.byte	0xa4,0x52,0x52,0xf6,	0x76,0x3b,0x3b,0x4d
++.byte	0xb7,0xd6,0xd6,0x61,	0x7d,0xb3,0xb3,0xce
++.byte	0x52,0x29,0x29,0x7b,	0xdd,0xe3,0xe3,0x3e
++.byte	0x5e,0x2f,0x2f,0x71,	0x13,0x84,0x84,0x97
++.byte	0xa6,0x53,0x53,0xf5,	0xb9,0xd1,0xd1,0x68
++.byte	0x00,0x00,0x00,0x00,	0xc1,0xed,0xed,0x2c
++.byte	0x40,0x20,0x20,0x60,	0xe3,0xfc,0xfc,0x1f
++.byte	0x79,0xb1,0xb1,0xc8,	0xb6,0x5b,0x5b,0xed
++.byte	0xd4,0x6a,0x6a,0xbe,	0x8d,0xcb,0xcb,0x46
++.byte	0x67,0xbe,0xbe,0xd9,	0x72,0x39,0x39,0x4b
++.byte	0x94,0x4a,0x4a,0xde,	0x98,0x4c,0x4c,0xd4
++.byte	0xb0,0x58,0x58,0xe8,	0x85,0xcf,0xcf,0x4a
++.byte	0xbb,0xd0,0xd0,0x6b,	0xc5,0xef,0xef,0x2a
++.byte	0x4f,0xaa,0xaa,0xe5,	0xed,0xfb,0xfb,0x16
++.byte	0x86,0x43,0x43,0xc5,	0x9a,0x4d,0x4d,0xd7
++.byte	0x66,0x33,0x33,0x55,	0x11,0x85,0x85,0x94
++.byte	0x8a,0x45,0x45,0xcf,	0xe9,0xf9,0xf9,0x10
++.byte	0x04,0x02,0x02,0x06,	0xfe,0x7f,0x7f,0x81
++.byte	0xa0,0x50,0x50,0xf0,	0x78,0x3c,0x3c,0x44
++.byte	0x25,0x9f,0x9f,0xba,	0x4b,0xa8,0xa8,0xe3
++.byte	0xa2,0x51,0x51,0xf3,	0x5d,0xa3,0xa3,0xfe
++.byte	0x80,0x40,0x40,0xc0,	0x05,0x8f,0x8f,0x8a
++.byte	0x3f,0x92,0x92,0xad,	0x21,0x9d,0x9d,0xbc
++.byte	0x70,0x38,0x38,0x48,	0xf1,0xf5,0xf5,0x04
++.byte	0x63,0xbc,0xbc,0xdf,	0x77,0xb6,0xb6,0xc1
++.byte	0xaf,0xda,0xda,0x75,	0x42,0x21,0x21,0x63
++.byte	0x20,0x10,0x10,0x30,	0xe5,0xff,0xff,0x1a
++.byte	0xfd,0xf3,0xf3,0x0e,	0xbf,0xd2,0xd2,0x6d
++.byte	0x81,0xcd,0xcd,0x4c,	0x18,0x0c,0x0c,0x14
++.byte	0x26,0x13,0x13,0x35,	0xc3,0xec,0xec,0x2f
++.byte	0xbe,0x5f,0x5f,0xe1,	0x35,0x97,0x97,0xa2
++.byte	0x88,0x44,0x44,0xcc,	0x2e,0x17,0x17,0x39
++.byte	0x93,0xc4,0xc4,0x57,	0x55,0xa7,0xa7,0xf2
++.byte	0xfc,0x7e,0x7e,0x82,	0x7a,0x3d,0x3d,0x47
++.byte	0xc8,0x64,0x64,0xac,	0xba,0x5d,0x5d,0xe7
++.byte	0x32,0x19,0x19,0x2b,	0xe6,0x73,0x73,0x95
++.byte	0xc0,0x60,0x60,0xa0,	0x19,0x81,0x81,0x98
++.byte	0x9e,0x4f,0x4f,0xd1,	0xa3,0xdc,0xdc,0x7f
++.byte	0x44,0x22,0x22,0x66,	0x54,0x2a,0x2a,0x7e
++.byte	0x3b,0x90,0x90,0xab,	0x0b,0x88,0x88,0x83
++.byte	0x8c,0x46,0x46,0xca,	0xc7,0xee,0xee,0x29
++.byte	0x6b,0xb8,0xb8,0xd3,	0x28,0x14,0x14,0x3c
++.byte	0xa7,0xde,0xde,0x79,	0xbc,0x5e,0x5e,0xe2
++.byte	0x16,0x0b,0x0b,0x1d,	0xad,0xdb,0xdb,0x76
++.byte	0xdb,0xe0,0xe0,0x3b,	0x64,0x32,0x32,0x56
++.byte	0x74,0x3a,0x3a,0x4e,	0x14,0x0a,0x0a,0x1e
++.byte	0x92,0x49,0x49,0xdb,	0x0c,0x06,0x06,0x0a
++.byte	0x48,0x24,0x24,0x6c,	0xb8,0x5c,0x5c,0xe4
++.byte	0x9f,0xc2,0xc2,0x5d,	0xbd,0xd3,0xd3,0x6e
++.byte	0x43,0xac,0xac,0xef,	0xc4,0x62,0x62,0xa6
++.byte	0x39,0x91,0x91,0xa8,	0x31,0x95,0x95,0xa4
++.byte	0xd3,0xe4,0xe4,0x37,	0xf2,0x79,0x79,0x8b
++.byte	0xd5,0xe7,0xe7,0x32,	0x8b,0xc8,0xc8,0x43
++.byte	0x6e,0x37,0x37,0x59,	0xda,0x6d,0x6d,0xb7
++.byte	0x01,0x8d,0x8d,0x8c,	0xb1,0xd5,0xd5,0x64
++.byte	0x9c,0x4e,0x4e,0xd2,	0x49,0xa9,0xa9,0xe0
++.byte	0xd8,0x6c,0x6c,0xb4,	0xac,0x56,0x56,0xfa
++.byte	0xf3,0xf4,0xf4,0x07,	0xcf,0xea,0xea,0x25
++.byte	0xca,0x65,0x65,0xaf,	0xf4,0x7a,0x7a,0x8e
++.byte	0x47,0xae,0xae,0xe9,	0x10,0x08,0x08,0x18
++.byte	0x6f,0xba,0xba,0xd5,	0xf0,0x78,0x78,0x88
++.byte	0x4a,0x25,0x25,0x6f,	0x5c,0x2e,0x2e,0x72
++.byte	0x38,0x1c,0x1c,0x24,	0x57,0xa6,0xa6,0xf1
++.byte	0x73,0xb4,0xb4,0xc7,	0x97,0xc6,0xc6,0x51
++.byte	0xcb,0xe8,0xe8,0x23,	0xa1,0xdd,0xdd,0x7c
++.byte	0xe8,0x74,0x74,0x9c,	0x3e,0x1f,0x1f,0x21
++.byte	0x96,0x4b,0x4b,0xdd,	0x61,0xbd,0xbd,0xdc
++.byte	0x0d,0x8b,0x8b,0x86,	0x0f,0x8a,0x8a,0x85
++.byte	0xe0,0x70,0x70,0x90,	0x7c,0x3e,0x3e,0x42
++.byte	0x71,0xb5,0xb5,0xc4,	0xcc,0x66,0x66,0xaa
++.byte	0x90,0x48,0x48,0xd8,	0x06,0x03,0x03,0x05
++.byte	0xf7,0xf6,0xf6,0x01,	0x1c,0x0e,0x0e,0x12
++.byte	0xc2,0x61,0x61,0xa3,	0x6a,0x35,0x35,0x5f
++.byte	0xae,0x57,0x57,0xf9,	0x69,0xb9,0xb9,0xd0
++.byte	0x17,0x86,0x86,0x91,	0x99,0xc1,0xc1,0x58
++.byte	0x3a,0x1d,0x1d,0x27,	0x27,0x9e,0x9e,0xb9
++.byte	0xd9,0xe1,0xe1,0x38,	0xeb,0xf8,0xf8,0x13
++.byte	0x2b,0x98,0x98,0xb3,	0x22,0x11,0x11,0x33
++.byte	0xd2,0x69,0x69,0xbb,	0xa9,0xd9,0xd9,0x70
++.byte	0x07,0x8e,0x8e,0x89,	0x33,0x94,0x94,0xa7
++.byte	0x2d,0x9b,0x9b,0xb6,	0x3c,0x1e,0x1e,0x22
++.byte	0x15,0x87,0x87,0x92,	0xc9,0xe9,0xe9,0x20
++.byte	0x87,0xce,0xce,0x49,	0xaa,0x55,0x55,0xff
++.byte	0x50,0x28,0x28,0x78,	0xa5,0xdf,0xdf,0x7a
++.byte	0x03,0x8c,0x8c,0x8f,	0x59,0xa1,0xa1,0xf8
++.byte	0x09,0x89,0x89,0x80,	0x1a,0x0d,0x0d,0x17
++.byte	0x65,0xbf,0xbf,0xda,	0xd7,0xe6,0xe6,0x31
++.byte	0x84,0x42,0x42,0xc6,	0xd0,0x68,0x68,0xb8
++.byte	0x82,0x41,0x41,0xc3,	0x29,0x99,0x99,0xb0
++.byte	0x5a,0x2d,0x2d,0x77,	0x1e,0x0f,0x0f,0x11
++.byte	0x7b,0xb0,0xb0,0xcb,	0xa8,0x54,0x54,0xfc
++.byte	0x6d,0xbb,0xbb,0xd6,	0x2c,0x16,0x16,0x3a
++
++AES_Td:
++.byte	0x51,0xf4,0xa7,0x50,	0x7e,0x41,0x65,0x53	# Td0
++.byte	0x1a,0x17,0xa4,0xc3,	0x3a,0x27,0x5e,0x96
++.byte	0x3b,0xab,0x6b,0xcb,	0x1f,0x9d,0x45,0xf1
++.byte	0xac,0xfa,0x58,0xab,	0x4b,0xe3,0x03,0x93
++.byte	0x20,0x30,0xfa,0x55,	0xad,0x76,0x6d,0xf6
++.byte	0x88,0xcc,0x76,0x91,	0xf5,0x02,0x4c,0x25
++.byte	0x4f,0xe5,0xd7,0xfc,	0xc5,0x2a,0xcb,0xd7
++.byte	0x26,0x35,0x44,0x80,	0xb5,0x62,0xa3,0x8f
++.byte	0xde,0xb1,0x5a,0x49,	0x25,0xba,0x1b,0x67
++.byte	0x45,0xea,0x0e,0x98,	0x5d,0xfe,0xc0,0xe1
++.byte	0xc3,0x2f,0x75,0x02,	0x81,0x4c,0xf0,0x12
++.byte	0x8d,0x46,0x97,0xa3,	0x6b,0xd3,0xf9,0xc6
++.byte	0x03,0x8f,0x5f,0xe7,	0x15,0x92,0x9c,0x95
++.byte	0xbf,0x6d,0x7a,0xeb,	0x95,0x52,0x59,0xda
++.byte	0xd4,0xbe,0x83,0x2d,	0x58,0x74,0x21,0xd3
++.byte	0x49,0xe0,0x69,0x29,	0x8e,0xc9,0xc8,0x44
++.byte	0x75,0xc2,0x89,0x6a,	0xf4,0x8e,0x79,0x78
++.byte	0x99,0x58,0x3e,0x6b,	0x27,0xb9,0x71,0xdd
++.byte	0xbe,0xe1,0x4f,0xb6,	0xf0,0x88,0xad,0x17
++.byte	0xc9,0x20,0xac,0x66,	0x7d,0xce,0x3a,0xb4
++.byte	0x63,0xdf,0x4a,0x18,	0xe5,0x1a,0x31,0x82
++.byte	0x97,0x51,0x33,0x60,	0x62,0x53,0x7f,0x45
++.byte	0xb1,0x64,0x77,0xe0,	0xbb,0x6b,0xae,0x84
++.byte	0xfe,0x81,0xa0,0x1c,	0xf9,0x08,0x2b,0x94
++.byte	0x70,0x48,0x68,0x58,	0x8f,0x45,0xfd,0x19
++.byte	0x94,0xde,0x6c,0x87,	0x52,0x7b,0xf8,0xb7
++.byte	0xab,0x73,0xd3,0x23,	0x72,0x4b,0x02,0xe2
++.byte	0xe3,0x1f,0x8f,0x57,	0x66,0x55,0xab,0x2a
++.byte	0xb2,0xeb,0x28,0x07,	0x2f,0xb5,0xc2,0x03
++.byte	0x86,0xc5,0x7b,0x9a,	0xd3,0x37,0x08,0xa5
++.byte	0x30,0x28,0x87,0xf2,	0x23,0xbf,0xa5,0xb2
++.byte	0x02,0x03,0x6a,0xba,	0xed,0x16,0x82,0x5c
++.byte	0x8a,0xcf,0x1c,0x2b,	0xa7,0x79,0xb4,0x92
++.byte	0xf3,0x07,0xf2,0xf0,	0x4e,0x69,0xe2,0xa1
++.byte	0x65,0xda,0xf4,0xcd,	0x06,0x05,0xbe,0xd5
++.byte	0xd1,0x34,0x62,0x1f,	0xc4,0xa6,0xfe,0x8a
++.byte	0x34,0x2e,0x53,0x9d,	0xa2,0xf3,0x55,0xa0
++.byte	0x05,0x8a,0xe1,0x32,	0xa4,0xf6,0xeb,0x75
++.byte	0x0b,0x83,0xec,0x39,	0x40,0x60,0xef,0xaa
++.byte	0x5e,0x71,0x9f,0x06,	0xbd,0x6e,0x10,0x51
++.byte	0x3e,0x21,0x8a,0xf9,	0x96,0xdd,0x06,0x3d
++.byte	0xdd,0x3e,0x05,0xae,	0x4d,0xe6,0xbd,0x46
++.byte	0x91,0x54,0x8d,0xb5,	0x71,0xc4,0x5d,0x05
++.byte	0x04,0x06,0xd4,0x6f,	0x60,0x50,0x15,0xff
++.byte	0x19,0x98,0xfb,0x24,	0xd6,0xbd,0xe9,0x97
++.byte	0x89,0x40,0x43,0xcc,	0x67,0xd9,0x9e,0x77
++.byte	0xb0,0xe8,0x42,0xbd,	0x07,0x89,0x8b,0x88
++.byte	0xe7,0x19,0x5b,0x38,	0x79,0xc8,0xee,0xdb
++.byte	0xa1,0x7c,0x0a,0x47,	0x7c,0x42,0x0f,0xe9
++.byte	0xf8,0x84,0x1e,0xc9,	0x00,0x00,0x00,0x00
++.byte	0x09,0x80,0x86,0x83,	0x32,0x2b,0xed,0x48
++.byte	0x1e,0x11,0x70,0xac,	0x6c,0x5a,0x72,0x4e
++.byte	0xfd,0x0e,0xff,0xfb,	0x0f,0x85,0x38,0x56
++.byte	0x3d,0xae,0xd5,0x1e,	0x36,0x2d,0x39,0x27
++.byte	0x0a,0x0f,0xd9,0x64,	0x68,0x5c,0xa6,0x21
++.byte	0x9b,0x5b,0x54,0xd1,	0x24,0x36,0x2e,0x3a
++.byte	0x0c,0x0a,0x67,0xb1,	0x93,0x57,0xe7,0x0f
++.byte	0xb4,0xee,0x96,0xd2,	0x1b,0x9b,0x91,0x9e
++.byte	0x80,0xc0,0xc5,0x4f,	0x61,0xdc,0x20,0xa2
++.byte	0x5a,0x77,0x4b,0x69,	0x1c,0x12,0x1a,0x16
++.byte	0xe2,0x93,0xba,0x0a,	0xc0,0xa0,0x2a,0xe5
++.byte	0x3c,0x22,0xe0,0x43,	0x12,0x1b,0x17,0x1d
++.byte	0x0e,0x09,0x0d,0x0b,	0xf2,0x8b,0xc7,0xad
++.byte	0x2d,0xb6,0xa8,0xb9,	0x14,0x1e,0xa9,0xc8
++.byte	0x57,0xf1,0x19,0x85,	0xaf,0x75,0x07,0x4c
++.byte	0xee,0x99,0xdd,0xbb,	0xa3,0x7f,0x60,0xfd
++.byte	0xf7,0x01,0x26,0x9f,	0x5c,0x72,0xf5,0xbc
++.byte	0x44,0x66,0x3b,0xc5,	0x5b,0xfb,0x7e,0x34
++.byte	0x8b,0x43,0x29,0x76,	0xcb,0x23,0xc6,0xdc
++.byte	0xb6,0xed,0xfc,0x68,	0xb8,0xe4,0xf1,0x63
++.byte	0xd7,0x31,0xdc,0xca,	0x42,0x63,0x85,0x10
++.byte	0x13,0x97,0x22,0x40,	0x84,0xc6,0x11,0x20
++.byte	0x85,0x4a,0x24,0x7d,	0xd2,0xbb,0x3d,0xf8
++.byte	0xae,0xf9,0x32,0x11,	0xc7,0x29,0xa1,0x6d
++.byte	0x1d,0x9e,0x2f,0x4b,	0xdc,0xb2,0x30,0xf3
++.byte	0x0d,0x86,0x52,0xec,	0x77,0xc1,0xe3,0xd0
++.byte	0x2b,0xb3,0x16,0x6c,	0xa9,0x70,0xb9,0x99
++.byte	0x11,0x94,0x48,0xfa,	0x47,0xe9,0x64,0x22
++.byte	0xa8,0xfc,0x8c,0xc4,	0xa0,0xf0,0x3f,0x1a
++.byte	0x56,0x7d,0x2c,0xd8,	0x22,0x33,0x90,0xef
++.byte	0x87,0x49,0x4e,0xc7,	0xd9,0x38,0xd1,0xc1
++.byte	0x8c,0xca,0xa2,0xfe,	0x98,0xd4,0x0b,0x36
++.byte	0xa6,0xf5,0x81,0xcf,	0xa5,0x7a,0xde,0x28
++.byte	0xda,0xb7,0x8e,0x26,	0x3f,0xad,0xbf,0xa4
++.byte	0x2c,0x3a,0x9d,0xe4,	0x50,0x78,0x92,0x0d
++.byte	0x6a,0x5f,0xcc,0x9b,	0x54,0x7e,0x46,0x62
++.byte	0xf6,0x8d,0x13,0xc2,	0x90,0xd8,0xb8,0xe8
++.byte	0x2e,0x39,0xf7,0x5e,	0x82,0xc3,0xaf,0xf5
++.byte	0x9f,0x5d,0x80,0xbe,	0x69,0xd0,0x93,0x7c
++.byte	0x6f,0xd5,0x2d,0xa9,	0xcf,0x25,0x12,0xb3
++.byte	0xc8,0xac,0x99,0x3b,	0x10,0x18,0x7d,0xa7
++.byte	0xe8,0x9c,0x63,0x6e,	0xdb,0x3b,0xbb,0x7b
++.byte	0xcd,0x26,0x78,0x09,	0x6e,0x59,0x18,0xf4
++.byte	0xec,0x9a,0xb7,0x01,	0x83,0x4f,0x9a,0xa8
++.byte	0xe6,0x95,0x6e,0x65,	0xaa,0xff,0xe6,0x7e
++.byte	0x21,0xbc,0xcf,0x08,	0xef,0x15,0xe8,0xe6
++.byte	0xba,0xe7,0x9b,0xd9,	0x4a,0x6f,0x36,0xce
++.byte	0xea,0x9f,0x09,0xd4,	0x29,0xb0,0x7c,0xd6
++.byte	0x31,0xa4,0xb2,0xaf,	0x2a,0x3f,0x23,0x31
++.byte	0xc6,0xa5,0x94,0x30,	0x35,0xa2,0x66,0xc0
++.byte	0x74,0x4e,0xbc,0x37,	0xfc,0x82,0xca,0xa6
++.byte	0xe0,0x90,0xd0,0xb0,	0x33,0xa7,0xd8,0x15
++.byte	0xf1,0x04,0x98,0x4a,	0x41,0xec,0xda,0xf7
++.byte	0x7f,0xcd,0x50,0x0e,	0x17,0x91,0xf6,0x2f
++.byte	0x76,0x4d,0xd6,0x8d,	0x43,0xef,0xb0,0x4d
++.byte	0xcc,0xaa,0x4d,0x54,	0xe4,0x96,0x04,0xdf
++.byte	0x9e,0xd1,0xb5,0xe3,	0x4c,0x6a,0x88,0x1b
++.byte	0xc1,0x2c,0x1f,0xb8,	0x46,0x65,0x51,0x7f
++.byte	0x9d,0x5e,0xea,0x04,	0x01,0x8c,0x35,0x5d
++.byte	0xfa,0x87,0x74,0x73,	0xfb,0x0b,0x41,0x2e
++.byte	0xb3,0x67,0x1d,0x5a,	0x92,0xdb,0xd2,0x52
++.byte	0xe9,0x10,0x56,0x33,	0x6d,0xd6,0x47,0x13
++.byte	0x9a,0xd7,0x61,0x8c,	0x37,0xa1,0x0c,0x7a
++.byte	0x59,0xf8,0x14,0x8e,	0xeb,0x13,0x3c,0x89
++.byte	0xce,0xa9,0x27,0xee,	0xb7,0x61,0xc9,0x35
++.byte	0xe1,0x1c,0xe5,0xed,	0x7a,0x47,0xb1,0x3c
++.byte	0x9c,0xd2,0xdf,0x59,	0x55,0xf2,0x73,0x3f
++.byte	0x18,0x14,0xce,0x79,	0x73,0xc7,0x37,0xbf
++.byte	0x53,0xf7,0xcd,0xea,	0x5f,0xfd,0xaa,0x5b
++.byte	0xdf,0x3d,0x6f,0x14,	0x78,0x44,0xdb,0x86
++.byte	0xca,0xaf,0xf3,0x81,	0xb9,0x68,0xc4,0x3e
++.byte	0x38,0x24,0x34,0x2c,	0xc2,0xa3,0x40,0x5f
++.byte	0x16,0x1d,0xc3,0x72,	0xbc,0xe2,0x25,0x0c
++.byte	0x28,0x3c,0x49,0x8b,	0xff,0x0d,0x95,0x41
++.byte	0x39,0xa8,0x01,0x71,	0x08,0x0c,0xb3,0xde
++.byte	0xd8,0xb4,0xe4,0x9c,	0x64,0x56,0xc1,0x90
++.byte	0x7b,0xcb,0x84,0x61,	0xd5,0x32,0xb6,0x70
++.byte	0x48,0x6c,0x5c,0x74,	0xd0,0xb8,0x57,0x42
++
++.byte	0x52, 0x09, 0x6a, 0xd5, 0x30, 0x36, 0xa5, 0x38	# Td4
++.byte	0xbf, 0x40, 0xa3, 0x9e, 0x81, 0xf3, 0xd7, 0xfb
++.byte	0x7c, 0xe3, 0x39, 0x82, 0x9b, 0x2f, 0xff, 0x87
++.byte	0x34, 0x8e, 0x43, 0x44, 0xc4, 0xde, 0xe9, 0xcb
++.byte	0x54, 0x7b, 0x94, 0x32, 0xa6, 0xc2, 0x23, 0x3d
++.byte	0xee, 0x4c, 0x95, 0x0b, 0x42, 0xfa, 0xc3, 0x4e
++.byte	0x08, 0x2e, 0xa1, 0x66, 0x28, 0xd9, 0x24, 0xb2
++.byte	0x76, 0x5b, 0xa2, 0x49, 0x6d, 0x8b, 0xd1, 0x25
++.byte	0x72, 0xf8, 0xf6, 0x64, 0x86, 0x68, 0x98, 0x16
++.byte	0xd4, 0xa4, 0x5c, 0xcc, 0x5d, 0x65, 0xb6, 0x92
++.byte	0x6c, 0x70, 0x48, 0x50, 0xfd, 0xed, 0xb9, 0xda
++.byte	0x5e, 0x15, 0x46, 0x57, 0xa7, 0x8d, 0x9d, 0x84
++.byte	0x90, 0xd8, 0xab, 0x00, 0x8c, 0xbc, 0xd3, 0x0a
++.byte	0xf7, 0xe4, 0x58, 0x05, 0xb8, 0xb3, 0x45, 0x06
++.byte	0xd0, 0x2c, 0x1e, 0x8f, 0xca, 0x3f, 0x0f, 0x02
++.byte	0xc1, 0xaf, 0xbd, 0x03, 0x01, 0x13, 0x8a, 0x6b
++.byte	0x3a, 0x91, 0x11, 0x41, 0x4f, 0x67, 0xdc, 0xea
++.byte	0x97, 0xf2, 0xcf, 0xce, 0xf0, 0xb4, 0xe6, 0x73
++.byte	0x96, 0xac, 0x74, 0x22, 0xe7, 0xad, 0x35, 0x85
++.byte	0xe2, 0xf9, 0x37, 0xe8, 0x1c, 0x75, 0xdf, 0x6e
++.byte	0x47, 0xf1, 0x1a, 0x71, 0x1d, 0x29, 0xc5, 0x89
++.byte	0x6f, 0xb7, 0x62, 0x0e, 0xaa, 0x18, 0xbe, 0x1b
++.byte	0xfc, 0x56, 0x3e, 0x4b, 0xc6, 0xd2, 0x79, 0x20
++.byte	0x9a, 0xdb, 0xc0, 0xfe, 0x78, 0xcd, 0x5a, 0xf4
++.byte	0x1f, 0xdd, 0xa8, 0x33, 0x88, 0x07, 0xc7, 0x31
++.byte	0xb1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xec, 0x5f
++.byte	0x60, 0x51, 0x7f, 0xa9, 0x19, 0xb5, 0x4a, 0x0d
++.byte	0x2d, 0xe5, 0x7a, 0x9f, 0x93, 0xc9, 0x9c, 0xef
++.byte	0xa0, 0xe0, 0x3b, 0x4d, 0xae, 0x2a, 0xf5, 0xb0
++.byte	0xc8, 0xeb, 0xbb, 0x3c, 0x83, 0x53, 0x99, 0x61
++.byte	0x17, 0x2b, 0x04, 0x7e, 0xba, 0x77, 0xd6, 0x26
++.byte	0xe1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0c, 0x7d
++
++AES_Te4:
++.byte	0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5	# Te4
++.byte	0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76
++.byte	0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0
++.byte	0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0
++.byte	0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc
++.byte	0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15
++.byte	0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a
++.byte	0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75
++.byte	0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0
++.byte	0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84
++.byte	0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b
++.byte	0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf
++.byte	0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85
++.byte	0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8
++.byte	0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5
++.byte	0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2
++.byte	0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17
++.byte	0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73
++.byte	0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88
++.byte	0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb
++.byte	0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c
++.byte	0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79
++.byte	0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9
++.byte	0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08
++.byte	0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6
++.byte	0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a
++.byte	0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e
++.byte	0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e
++.byte	0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94
++.byte	0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf
++.byte	0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68
++.byte	0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16
++
++.byte	0x01,0x00,0x00,0x00,	0x02,0x00,0x00,0x00	# rcon
++.byte	0x04,0x00,0x00,0x00,	0x08,0x00,0x00,0x00
++.byte	0x10,0x00,0x00,0x00,	0x20,0x00,0x00,0x00
++.byte	0x40,0x00,0x00,0x00,	0x80,0x00,0x00,0x00
++.byte	0x1B,0x00,0x00,0x00,	0x36,0x00,0x00,0x00
++___
++
++foreach (split("\n",$code)) {
++	s/\`([^\`]*)\`/eval $1/ge;
++
++	# made-up _instructions, _xtr, _ins, _ror and _bias, cope
++	# with byte order dependencies...
++	if (/^\s+_/) {
++	    s/(_[a-z]+\s+)(\$[0-9]+),([^,]+)(#.*)*$/$1$2,$2,$3/;
++
++	    s/_xtr\s+(\$[0-9]+),(\$[0-9]+),([0-9]+(\-2)*)/
++		sprintf("srl\t$1,$2,%d",$big_endian ?	eval($3)
++					:		eval("24-$3"))/e or
++	    s/_ins\s+(\$[0-9]+),(\$[0-9]+),([0-9]+)/
++		sprintf("sll\t$1,$2,%d",$big_endian ?	eval($3)
++					:		eval("24-$3"))/e or
++	    s/_ins2\s+(\$[0-9]+),(\$[0-9]+),([0-9]+)/
++		sprintf("ins\t$1,$2,%d,8",$big_endian ?	eval($3)
++					:		eval("24-$3"))/e or
++	    s/_ror\s+(\$[0-9]+),(\$[0-9]+),(\-?[0-9]+)/
++		sprintf("srl\t$1,$2,%d",$big_endian ?	eval($3)
++					:		eval("$3*-1"))/e or
++	    s/_bias\s+(\$[0-9]+),(\$[0-9]+),([0-9]+)/
++		sprintf("sll\t$1,$2,%d",$big_endian ?	eval($3)
++					:		eval("($3-16)&31"))/e;
++
++	    s/srl\s+(\$[0-9]+),(\$[0-9]+),\-([0-9]+)/
++		sprintf("sll\t$1,$2,$3")/e				or
++	    s/srl\s+(\$[0-9]+),(\$[0-9]+),0/
++		sprintf("and\t$1,$2,0xff")/e				or
++	    s/(sll\s+\$[0-9]+,\$[0-9]+,0)/#$1/;
++	}
++
++	# convert lwl/lwr and swr/swl to little-endian order
++	if (!$big_endian && /^\s+[sl]w[lr]\s+/) {
++	    s/([sl]wl.*)([0-9]+)\((\$[0-9]+)\)/
++		sprintf("$1%d($3)",eval("$2-$2%4+($2%4-1)&3"))/e	or
++	    s/([sl]wr.*)([0-9]+)\((\$[0-9]+)\)/
++		sprintf("$1%d($3)",eval("$2-$2%4+($2%4+1)&3"))/e;
++	}
++
++	if (!$big_endian) {
++	    s/(rotr\s+\$[0-9]+,\$[0-9]+),([0-9]+)/sprintf("$1,%d",32-$2)/e;
++	    s/(ext\s+\$[0-9]+,\$[0-9]+),([0-9]+),8/sprintf("$1,%d,8",24-$2)/e;
++	}
++
++	print $_,"\n";
++}
++
++close STDOUT;
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/aes/asm/aes-parisc.pl b/CryptoPkg/Library/OpensslLib/openssl/crypto/aes/asm/aes-parisc.pl
+new file mode 100644
+index 0000000..2c785bc
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/aes/asm/aes-parisc.pl
+@@ -0,0 +1,1029 @@
++#! /usr/bin/env perl
++# Copyright 2009-2016 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
++# in the file LICENSE in the source distribution or at
++# https://www.openssl.org/source/license.html
++
++
++# ====================================================================
++# Written by Andy Polyakov  for the OpenSSL
++# project. The module is, however, dual licensed under OpenSSL and
++# CRYPTOGAMS licenses depending on where you obtain it. For further
++# details see http://www.openssl.org/~appro/cryptogams/.
++# ====================================================================
++
++# AES for PA-RISC.
++#
++# June 2009.
++#
++# The module is mechanical transliteration of aes-sparcv9.pl, but with
++# a twist: S-boxes are compressed even further down to 1K+256B. On
++# PA-7100LC performance is ~40% better than gcc 3.2 generated code and
++# is about 33 cycles per byte processed with 128-bit key. Newer CPUs
++# perform at 16 cycles per byte. It's not faster than code generated
++# by vendor compiler, but recall that it has compressed S-boxes, which
++# requires extra processing.
++#
++# Special thanks to polarhome.com for providing HP-UX account.
++
++$flavour = shift;
++$output = shift;
++open STDOUT,">$output";
++
++if ($flavour =~ /64/) {
++	$LEVEL		="2.0W";
++	$SIZE_T		=8;
++	$FRAME_MARKER	=80;
++	$SAVED_RP	=16;
++	$PUSH		="std";
++	$PUSHMA		="std,ma";
++	$POP		="ldd";
++	$POPMB		="ldd,mb";
++} else {
++	$LEVEL		="1.0";
++	$SIZE_T		=4;
++	$FRAME_MARKER	=48;
++	$SAVED_RP	=20;
++	$PUSH		="stw";
++	$PUSHMA		="stwm";
++	$POP		="ldw";
++	$POPMB		="ldwm";
++}
++
++$FRAME=16*$SIZE_T+$FRAME_MARKER;# 16 saved regs + frame marker
++				#                 [+ argument transfer]
++$inp="%r26";	# arg0
++$out="%r25";	# arg1
++$key="%r24";	# arg2
++
++($s0,$s1,$s2,$s3) = ("%r1","%r2","%r3","%r4");
++($t0,$t1,$t2,$t3) = ("%r5","%r6","%r7","%r8");
++
++($acc0, $acc1, $acc2, $acc3, $acc4, $acc5, $acc6, $acc7,
++ $acc8, $acc9,$acc10,$acc11,$acc12,$acc13,$acc14,$acc15) =
++("%r9","%r10","%r11","%r12","%r13","%r14","%r15","%r16",
++"%r17","%r18","%r19","%r20","%r21","%r22","%r23","%r26");
++
++$tbl="%r28";
++$rounds="%r29";
++
++$code=<<___;
++	.LEVEL	$LEVEL
++	.SPACE	\$TEXT\$
++	.SUBSPA	\$CODE\$,QUAD=0,ALIGN=8,ACCESS=0x2C,CODE_ONLY
++
++	.EXPORT	AES_encrypt,ENTRY,ARGW0=GR,ARGW1=GR,ARGW2=GR
++	.ALIGN	64
++AES_encrypt
++	.PROC
++	.CALLINFO	FRAME=`$FRAME-16*$SIZE_T`,NO_CALLS,SAVE_RP,ENTRY_GR=18
++	.ENTRY
++	$PUSH	%r2,-$SAVED_RP(%sp)	; standard prologue
++	$PUSHMA	%r3,$FRAME(%sp)
++	$PUSH	%r4,`-$FRAME+1*$SIZE_T`(%sp)
++	$PUSH	%r5,`-$FRAME+2*$SIZE_T`(%sp)
++	$PUSH	%r6,`-$FRAME+3*$SIZE_T`(%sp)
++	$PUSH	%r7,`-$FRAME+4*$SIZE_T`(%sp)
++	$PUSH	%r8,`-$FRAME+5*$SIZE_T`(%sp)
++	$PUSH	%r9,`-$FRAME+6*$SIZE_T`(%sp)
++	$PUSH	%r10,`-$FRAME+7*$SIZE_T`(%sp)
++	$PUSH	%r11,`-$FRAME+8*$SIZE_T`(%sp)
++	$PUSH	%r12,`-$FRAME+9*$SIZE_T`(%sp)
++	$PUSH	%r13,`-$FRAME+10*$SIZE_T`(%sp)
++	$PUSH	%r14,`-$FRAME+11*$SIZE_T`(%sp)
++	$PUSH	%r15,`-$FRAME+12*$SIZE_T`(%sp)
++	$PUSH	%r16,`-$FRAME+13*$SIZE_T`(%sp)
++	$PUSH	%r17,`-$FRAME+14*$SIZE_T`(%sp)
++	$PUSH	%r18,`-$FRAME+15*$SIZE_T`(%sp)
++
++	blr	%r0,$tbl
++	ldi	3,$t0
++L\$enc_pic
++	andcm	$tbl,$t0,$tbl
++	ldo	L\$AES_Te-L\$enc_pic($tbl),$tbl
++
++	and	$inp,$t0,$t0
++	sub	$inp,$t0,$inp
++	ldw	0($inp),$s0
++	ldw	4($inp),$s1
++	ldw	8($inp),$s2
++	comib,=	0,$t0,L\$enc_inp_aligned
++	ldw	12($inp),$s3
++
++	sh3addl	$t0,%r0,$t0
++	subi	32,$t0,$t0
++	mtctl	$t0,%cr11
++	ldw	16($inp),$t1
++	vshd	$s0,$s1,$s0
++	vshd	$s1,$s2,$s1
++	vshd	$s2,$s3,$s2
++	vshd	$s3,$t1,$s3
++
++L\$enc_inp_aligned
++	bl	_parisc_AES_encrypt,%r31
++	nop
++
++	extru,<> $out,31,2,%r0
++	b	L\$enc_out_aligned
++	nop
++
++	_srm	$s0,24,$acc0
++	_srm	$s0,16,$acc1
++	stb	$acc0,0($out)
++	_srm	$s0,8,$acc2
++	stb	$acc1,1($out)
++	_srm	$s1,24,$acc4
++	stb	$acc2,2($out)
++	_srm	$s1,16,$acc5
++	stb	$s0,3($out)
++	_srm	$s1,8,$acc6
++	stb	$acc4,4($out)
++	_srm	$s2,24,$acc0
++	stb	$acc5,5($out)
++	_srm	$s2,16,$acc1
++	stb	$acc6,6($out)
++	_srm	$s2,8,$acc2
++	stb	$s1,7($out)
++	_srm	$s3,24,$acc4
++	stb	$acc0,8($out)
++	_srm	$s3,16,$acc5
++	stb	$acc1,9($out)
++	_srm	$s3,8,$acc6
++	stb	$acc2,10($out)
++	stb	$s2,11($out)
++	stb	$acc4,12($out)
++	stb	$acc5,13($out)
++	stb	$acc6,14($out)
++	b	L\$enc_done
++	stb	$s3,15($out)
++
++L\$enc_out_aligned
++	stw	$s0,0($out)
++	stw	$s1,4($out)
++	stw	$s2,8($out)
++	stw	$s3,12($out)
++
++L\$enc_done
++	$POP	`-$FRAME-$SAVED_RP`(%sp),%r2	; standard epilogue
++	$POP	`-$FRAME+1*$SIZE_T`(%sp),%r4
++	$POP	`-$FRAME+2*$SIZE_T`(%sp),%r5
++	$POP	`-$FRAME+3*$SIZE_T`(%sp),%r6
++	$POP	`-$FRAME+4*$SIZE_T`(%sp),%r7
++	$POP	`-$FRAME+5*$SIZE_T`(%sp),%r8
++	$POP	`-$FRAME+6*$SIZE_T`(%sp),%r9
++	$POP	`-$FRAME+7*$SIZE_T`(%sp),%r10
++	$POP	`-$FRAME+8*$SIZE_T`(%sp),%r11
++	$POP	`-$FRAME+9*$SIZE_T`(%sp),%r12
++	$POP	`-$FRAME+10*$SIZE_T`(%sp),%r13
++	$POP	`-$FRAME+11*$SIZE_T`(%sp),%r14
++	$POP	`-$FRAME+12*$SIZE_T`(%sp),%r15
++	$POP	`-$FRAME+13*$SIZE_T`(%sp),%r16
++	$POP	`-$FRAME+14*$SIZE_T`(%sp),%r17
++	$POP	`-$FRAME+15*$SIZE_T`(%sp),%r18
++	bv	(%r2)
++	.EXIT
++	$POPMB	-$FRAME(%sp),%r3
++	.PROCEND
++
++	.ALIGN	16
++_parisc_AES_encrypt
++	.PROC
++	.CALLINFO	MILLICODE
++	.ENTRY
++	ldw	240($key),$rounds
++	ldw	0($key),$t0
++	ldw	4($key),$t1
++	ldw	8($key),$t2
++	_srm	$rounds,1,$rounds
++	xor	$t0,$s0,$s0
++	ldw	12($key),$t3
++	_srm	$s0,24,$acc0
++	xor	$t1,$s1,$s1
++	ldw	16($key),$t0
++	_srm	$s1,16,$acc1
++	xor	$t2,$s2,$s2
++	ldw	20($key),$t1
++	xor	$t3,$s3,$s3
++	ldw	24($key),$t2
++	ldw	28($key),$t3
++L\$enc_loop
++	_srm	$s2,8,$acc2
++	ldwx,s	$acc0($tbl),$acc0
++	_srm	$s3,0,$acc3
++	ldwx,s	$acc1($tbl),$acc1
++	_srm	$s1,24,$acc4
++	ldwx,s	$acc2($tbl),$acc2
++	_srm	$s2,16,$acc5
++	ldwx,s	$acc3($tbl),$acc3
++	_srm	$s3,8,$acc6
++	ldwx,s	$acc4($tbl),$acc4
++	_srm	$s0,0,$acc7
++	ldwx,s	$acc5($tbl),$acc5
++	_srm	$s2,24,$acc8
++	ldwx,s	$acc6($tbl),$acc6
++	_srm	$s3,16,$acc9
++	ldwx,s	$acc7($tbl),$acc7
++	_srm	$s0,8,$acc10
++	ldwx,s	$acc8($tbl),$acc8
++	_srm	$s1,0,$acc11
++	ldwx,s	$acc9($tbl),$acc9
++	_srm	$s3,24,$acc12
++	ldwx,s	$acc10($tbl),$acc10
++	_srm	$s0,16,$acc13
++	ldwx,s	$acc11($tbl),$acc11
++	_srm	$s1,8,$acc14
++	ldwx,s	$acc12($tbl),$acc12
++	_srm	$s2,0,$acc15
++	ldwx,s	$acc13($tbl),$acc13
++	ldwx,s	$acc14($tbl),$acc14
++	ldwx,s	$acc15($tbl),$acc15
++	addib,= -1,$rounds,L\$enc_last
++	ldo	32($key),$key
++
++		_ror	$acc1,8,$acc1
++		xor	$acc0,$t0,$t0
++	ldw	0($key),$s0
++		_ror	$acc2,16,$acc2
++		xor	$acc1,$t0,$t0
++	ldw	4($key),$s1
++		_ror	$acc3,24,$acc3
++		xor	$acc2,$t0,$t0
++	ldw	8($key),$s2
++		_ror	$acc5,8,$acc5
++		xor	$acc3,$t0,$t0
++	ldw	12($key),$s3
++		_ror	$acc6,16,$acc6
++		xor	$acc4,$t1,$t1
++		_ror	$acc7,24,$acc7
++		xor	$acc5,$t1,$t1
++		_ror	$acc9,8,$acc9
++		xor	$acc6,$t1,$t1
++		_ror	$acc10,16,$acc10
++		xor	$acc7,$t1,$t1
++		_ror	$acc11,24,$acc11
++		xor	$acc8,$t2,$t2
++		_ror	$acc13,8,$acc13
++		xor	$acc9,$t2,$t2
++		_ror	$acc14,16,$acc14
++		xor	$acc10,$t2,$t2
++		_ror	$acc15,24,$acc15
++		xor	$acc11,$t2,$t2
++		xor	$acc12,$acc14,$acc14
++		xor	$acc13,$t3,$t3
++	_srm	$t0,24,$acc0
++		xor	$acc14,$t3,$t3
++	_srm	$t1,16,$acc1
++		xor	$acc15,$t3,$t3
++
++	_srm	$t2,8,$acc2
++	ldwx,s	$acc0($tbl),$acc0
++	_srm	$t3,0,$acc3
++	ldwx,s	$acc1($tbl),$acc1
++	_srm	$t1,24,$acc4
++	ldwx,s	$acc2($tbl),$acc2
++	_srm	$t2,16,$acc5
++	ldwx,s	$acc3($tbl),$acc3
++	_srm	$t3,8,$acc6
++	ldwx,s	$acc4($tbl),$acc4
++	_srm	$t0,0,$acc7
++	ldwx,s	$acc5($tbl),$acc5
++	_srm	$t2,24,$acc8
++	ldwx,s	$acc6($tbl),$acc6
++	_srm	$t3,16,$acc9
++	ldwx,s	$acc7($tbl),$acc7
++	_srm	$t0,8,$acc10
++	ldwx,s	$acc8($tbl),$acc8
++	_srm	$t1,0,$acc11
++	ldwx,s	$acc9($tbl),$acc9
++	_srm	$t3,24,$acc12
++	ldwx,s	$acc10($tbl),$acc10
++	_srm	$t0,16,$acc13
++	ldwx,s	$acc11($tbl),$acc11
++	_srm	$t1,8,$acc14
++	ldwx,s	$acc12($tbl),$acc12
++	_srm	$t2,0,$acc15
++	ldwx,s	$acc13($tbl),$acc13
++		_ror	$acc1,8,$acc1
++	ldwx,s	$acc14($tbl),$acc14
++
++		_ror	$acc2,16,$acc2
++		xor	$acc0,$s0,$s0
++	ldwx,s	$acc15($tbl),$acc15
++		_ror	$acc3,24,$acc3
++		xor	$acc1,$s0,$s0
++	ldw	16($key),$t0
++		_ror	$acc5,8,$acc5
++		xor	$acc2,$s0,$s0
++	ldw	20($key),$t1
++		_ror	$acc6,16,$acc6
++		xor	$acc3,$s0,$s0
++	ldw	24($key),$t2
++		_ror	$acc7,24,$acc7
++		xor	$acc4,$s1,$s1
++	ldw	28($key),$t3
++		_ror	$acc9,8,$acc9
++		xor	$acc5,$s1,$s1
++	ldw	1024+0($tbl),%r0		; prefetch te4
++		_ror	$acc10,16,$acc10
++		xor	$acc6,$s1,$s1
++	ldw	1024+32($tbl),%r0		; prefetch te4
++		_ror	$acc11,24,$acc11
++		xor	$acc7,$s1,$s1
++	ldw	1024+64($tbl),%r0		; prefetch te4
++		_ror	$acc13,8,$acc13
++		xor	$acc8,$s2,$s2
++	ldw	1024+96($tbl),%r0		; prefetch te4
++		_ror	$acc14,16,$acc14
++		xor	$acc9,$s2,$s2
++	ldw	1024+128($tbl),%r0		; prefetch te4
++		_ror	$acc15,24,$acc15
++		xor	$acc10,$s2,$s2
++	ldw	1024+160($tbl),%r0		; prefetch te4
++	_srm	$s0,24,$acc0
++		xor	$acc11,$s2,$s2
++	ldw	1024+192($tbl),%r0		; prefetch te4
++		xor	$acc12,$acc14,$acc14
++		xor	$acc13,$s3,$s3
++	ldw	1024+224($tbl),%r0		; prefetch te4
++	_srm	$s1,16,$acc1
++		xor	$acc14,$s3,$s3
++	b	L\$enc_loop
++		xor	$acc15,$s3,$s3
++
++	.ALIGN	16
++L\$enc_last
++	ldo	1024($tbl),$rounds
++		_ror	$acc1,8,$acc1
++		xor	$acc0,$t0,$t0
++	ldw	0($key),$s0
++		_ror	$acc2,16,$acc2
++		xor	$acc1,$t0,$t0
++	ldw	4($key),$s1
++		_ror	$acc3,24,$acc3
++		xor	$acc2,$t0,$t0
++	ldw	8($key),$s2
++		_ror	$acc5,8,$acc5
++		xor	$acc3,$t0,$t0
++	ldw	12($key),$s3
++		_ror	$acc6,16,$acc6
++		xor	$acc4,$t1,$t1
++		_ror	$acc7,24,$acc7
++		xor	$acc5,$t1,$t1
++		_ror	$acc9,8,$acc9
++		xor	$acc6,$t1,$t1
++		_ror	$acc10,16,$acc10
++		xor	$acc7,$t1,$t1
++		_ror	$acc11,24,$acc11
++		xor	$acc8,$t2,$t2
++		_ror	$acc13,8,$acc13
++		xor	$acc9,$t2,$t2
++		_ror	$acc14,16,$acc14
++		xor	$acc10,$t2,$t2
++		_ror	$acc15,24,$acc15
++		xor	$acc11,$t2,$t2
++		xor	$acc12,$acc14,$acc14
++		xor	$acc13,$t3,$t3
++	_srm	$t0,24,$acc0
++		xor	$acc14,$t3,$t3
++	_srm	$t1,16,$acc1
++		xor	$acc15,$t3,$t3
++
++	_srm	$t2,8,$acc2
++	ldbx	$acc0($rounds),$acc0
++	_srm	$t1,24,$acc4
++	ldbx	$acc1($rounds),$acc1
++	_srm	$t2,16,$acc5
++	_srm	$t3,0,$acc3
++	ldbx	$acc2($rounds),$acc2
++	ldbx	$acc3($rounds),$acc3
++	_srm	$t3,8,$acc6
++	ldbx	$acc4($rounds),$acc4
++	_srm	$t2,24,$acc8
++	ldbx	$acc5($rounds),$acc5
++	_srm	$t3,16,$acc9
++	_srm	$t0,0,$acc7
++	ldbx	$acc6($rounds),$acc6
++	ldbx	$acc7($rounds),$acc7
++	_srm	$t0,8,$acc10
++	ldbx	$acc8($rounds),$acc8
++	_srm	$t3,24,$acc12
++	ldbx	$acc9($rounds),$acc9
++	_srm	$t0,16,$acc13
++	_srm	$t1,0,$acc11
++	ldbx	$acc10($rounds),$acc10
++	_srm	$t1,8,$acc14
++	ldbx	$acc11($rounds),$acc11
++	ldbx	$acc12($rounds),$acc12
++	ldbx	$acc13($rounds),$acc13
++	_srm	$t2,0,$acc15
++	ldbx	$acc14($rounds),$acc14
++
++		dep	$acc0,7,8,$acc3
++	ldbx	$acc15($rounds),$acc15
++		dep	$acc4,7,8,$acc7
++		dep	$acc1,15,8,$acc3
++		dep	$acc5,15,8,$acc7
++		dep	$acc2,23,8,$acc3
++		dep	$acc6,23,8,$acc7
++		xor	$acc3,$s0,$s0
++		xor	$acc7,$s1,$s1
++		dep	$acc8,7,8,$acc11
++		dep	$acc12,7,8,$acc15
++		dep	$acc9,15,8,$acc11
++		dep	$acc13,15,8,$acc15
++		dep	$acc10,23,8,$acc11
++		dep	$acc14,23,8,$acc15
++		xor	$acc11,$s2,$s2
++
++	bv	(%r31)
++	.EXIT
++		xor	$acc15,$s3,$s3
++	.PROCEND
++
++	.ALIGN	64
++L\$AES_Te
++	.WORD	0xc66363a5, 0xf87c7c84, 0xee777799, 0xf67b7b8d
++	.WORD	0xfff2f20d, 0xd66b6bbd, 0xde6f6fb1, 0x91c5c554
++	.WORD	0x60303050, 0x02010103, 0xce6767a9, 0x562b2b7d
++	.WORD	0xe7fefe19, 0xb5d7d762, 0x4dababe6, 0xec76769a
++	.WORD	0x8fcaca45, 0x1f82829d, 0x89c9c940, 0xfa7d7d87
++	.WORD	0xeffafa15, 0xb25959eb, 0x8e4747c9, 0xfbf0f00b
++	.WORD	0x41adadec, 0xb3d4d467, 0x5fa2a2fd, 0x45afafea
++	.WORD	0x239c9cbf, 0x53a4a4f7, 0xe4727296, 0x9bc0c05b
++	.WORD	0x75b7b7c2, 0xe1fdfd1c, 0x3d9393ae, 0x4c26266a
++	.WORD	0x6c36365a, 0x7e3f3f41, 0xf5f7f702, 0x83cccc4f
++	.WORD	0x6834345c, 0x51a5a5f4, 0xd1e5e534, 0xf9f1f108
++	.WORD	0xe2717193, 0xabd8d873, 0x62313153, 0x2a15153f
++	.WORD	0x0804040c, 0x95c7c752, 0x46232365, 0x9dc3c35e
++	.WORD	0x30181828, 0x379696a1, 0x0a05050f, 0x2f9a9ab5
++	.WORD	0x0e070709, 0x24121236, 0x1b80809b, 0xdfe2e23d
++	.WORD	0xcdebeb26, 0x4e272769, 0x7fb2b2cd, 0xea75759f
++	.WORD	0x1209091b, 0x1d83839e, 0x582c2c74, 0x341a1a2e
++	.WORD	0x361b1b2d, 0xdc6e6eb2, 0xb45a5aee, 0x5ba0a0fb
++	.WORD	0xa45252f6, 0x763b3b4d, 0xb7d6d661, 0x7db3b3ce
++	.WORD	0x5229297b, 0xdde3e33e, 0x5e2f2f71, 0x13848497
++	.WORD	0xa65353f5, 0xb9d1d168, 0x00000000, 0xc1eded2c
++	.WORD	0x40202060, 0xe3fcfc1f, 0x79b1b1c8, 0xb65b5bed
++	.WORD	0xd46a6abe, 0x8dcbcb46, 0x67bebed9, 0x7239394b
++	.WORD	0x944a4ade, 0x984c4cd4, 0xb05858e8, 0x85cfcf4a
++	.WORD	0xbbd0d06b, 0xc5efef2a, 0x4faaaae5, 0xedfbfb16
++	.WORD	0x864343c5, 0x9a4d4dd7, 0x66333355, 0x11858594
++	.WORD	0x8a4545cf, 0xe9f9f910, 0x04020206, 0xfe7f7f81
++	.WORD	0xa05050f0, 0x783c3c44, 0x259f9fba, 0x4ba8a8e3
++	.WORD	0xa25151f3, 0x5da3a3fe, 0x804040c0, 0x058f8f8a
++	.WORD	0x3f9292ad, 0x219d9dbc, 0x70383848, 0xf1f5f504
++	.WORD	0x63bcbcdf, 0x77b6b6c1, 0xafdada75, 0x42212163
++	.WORD	0x20101030, 0xe5ffff1a, 0xfdf3f30e, 0xbfd2d26d
++	.WORD	0x81cdcd4c, 0x180c0c14, 0x26131335, 0xc3ecec2f
++	.WORD	0xbe5f5fe1, 0x359797a2, 0x884444cc, 0x2e171739
++	.WORD	0x93c4c457, 0x55a7a7f2, 0xfc7e7e82, 0x7a3d3d47
++	.WORD	0xc86464ac, 0xba5d5de7, 0x3219192b, 0xe6737395
++	.WORD	0xc06060a0, 0x19818198, 0x9e4f4fd1, 0xa3dcdc7f
++	.WORD	0x44222266, 0x542a2a7e, 0x3b9090ab, 0x0b888883
++	.WORD	0x8c4646ca, 0xc7eeee29, 0x6bb8b8d3, 0x2814143c
++	.WORD	0xa7dede79, 0xbc5e5ee2, 0x160b0b1d, 0xaddbdb76
++	.WORD	0xdbe0e03b, 0x64323256, 0x743a3a4e, 0x140a0a1e
++	.WORD	0x924949db, 0x0c06060a, 0x4824246c, 0xb85c5ce4
++	.WORD	0x9fc2c25d, 0xbdd3d36e, 0x43acacef, 0xc46262a6
++	.WORD	0x399191a8, 0x319595a4, 0xd3e4e437, 0xf279798b
++	.WORD	0xd5e7e732, 0x8bc8c843, 0x6e373759, 0xda6d6db7
++	.WORD	0x018d8d8c, 0xb1d5d564, 0x9c4e4ed2, 0x49a9a9e0
++	.WORD	0xd86c6cb4, 0xac5656fa, 0xf3f4f407, 0xcfeaea25
++	.WORD	0xca6565af, 0xf47a7a8e, 0x47aeaee9, 0x10080818
++	.WORD	0x6fbabad5, 0xf0787888, 0x4a25256f, 0x5c2e2e72
++	.WORD	0x381c1c24, 0x57a6a6f1, 0x73b4b4c7, 0x97c6c651
++	.WORD	0xcbe8e823, 0xa1dddd7c, 0xe874749c, 0x3e1f1f21
++	.WORD	0x964b4bdd, 0x61bdbddc, 0x0d8b8b86, 0x0f8a8a85
++	.WORD	0xe0707090, 0x7c3e3e42, 0x71b5b5c4, 0xcc6666aa
++	.WORD	0x904848d8, 0x06030305, 0xf7f6f601, 0x1c0e0e12
++	.WORD	0xc26161a3, 0x6a35355f, 0xae5757f9, 0x69b9b9d0
++	.WORD	0x17868691, 0x99c1c158, 0x3a1d1d27, 0x279e9eb9
++	.WORD	0xd9e1e138, 0xebf8f813, 0x2b9898b3, 0x22111133
++	.WORD	0xd26969bb, 0xa9d9d970, 0x078e8e89, 0x339494a7
++	.WORD	0x2d9b9bb6, 0x3c1e1e22, 0x15878792, 0xc9e9e920
++	.WORD	0x87cece49, 0xaa5555ff, 0x50282878, 0xa5dfdf7a
++	.WORD	0x038c8c8f, 0x59a1a1f8, 0x09898980, 0x1a0d0d17
++	.WORD	0x65bfbfda, 0xd7e6e631, 0x844242c6, 0xd06868b8
++	.WORD	0x824141c3, 0x299999b0, 0x5a2d2d77, 0x1e0f0f11
++	.WORD	0x7bb0b0cb, 0xa85454fc, 0x6dbbbbd6, 0x2c16163a
++	.BYTE	0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5
++	.BYTE	0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76
++	.BYTE	0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0
++	.BYTE	0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0
++	.BYTE	0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc
++	.BYTE	0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15
++	.BYTE	0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a
++	.BYTE	0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75
++	.BYTE	0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0
++	.BYTE	0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84
++	.BYTE	0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b
++	.BYTE	0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf
++	.BYTE	0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85
++	.BYTE	0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8
++	.BYTE	0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5
++	.BYTE	0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2
++	.BYTE	0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17
++	.BYTE	0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73
++	.BYTE	0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88
++	.BYTE	0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb
++	.BYTE	0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c
++	.BYTE	0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79
++	.BYTE	0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9
++	.BYTE	0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08
++	.BYTE	0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6
++	.BYTE	0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a
++	.BYTE	0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e
++	.BYTE	0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e
++	.BYTE	0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94
++	.BYTE	0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf
++	.BYTE	0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68
++	.BYTE	0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16
++___
++
++$code.=<<___;
++	.EXPORT	AES_decrypt,ENTRY,ARGW0=GR,ARGW1=GR,ARGW2=GR
++	.ALIGN	16
++AES_decrypt
++	.PROC
++	.CALLINFO	FRAME=`$FRAME-16*$SIZE_T`,NO_CALLS,SAVE_RP,ENTRY_GR=18
++	.ENTRY
++	$PUSH	%r2,-$SAVED_RP(%sp)	; standard prologue
++	$PUSHMA	%r3,$FRAME(%sp)
++	$PUSH	%r4,`-$FRAME+1*$SIZE_T`(%sp)
++	$PUSH	%r5,`-$FRAME+2*$SIZE_T`(%sp)
++	$PUSH	%r6,`-$FRAME+3*$SIZE_T`(%sp)
++	$PUSH	%r7,`-$FRAME+4*$SIZE_T`(%sp)
++	$PUSH	%r8,`-$FRAME+5*$SIZE_T`(%sp)
++	$PUSH	%r9,`-$FRAME+6*$SIZE_T`(%sp)
++	$PUSH	%r10,`-$FRAME+7*$SIZE_T`(%sp)
++	$PUSH	%r11,`-$FRAME+8*$SIZE_T`(%sp)
++	$PUSH	%r12,`-$FRAME+9*$SIZE_T`(%sp)
++	$PUSH	%r13,`-$FRAME+10*$SIZE_T`(%sp)
++	$PUSH	%r14,`-$FRAME+11*$SIZE_T`(%sp)
++	$PUSH	%r15,`-$FRAME+12*$SIZE_T`(%sp)
++	$PUSH	%r16,`-$FRAME+13*$SIZE_T`(%sp)
++	$PUSH	%r17,`-$FRAME+14*$SIZE_T`(%sp)
++	$PUSH	%r18,`-$FRAME+15*$SIZE_T`(%sp)
++
++	blr	%r0,$tbl
++	ldi	3,$t0
++L\$dec_pic
++	andcm	$tbl,$t0,$tbl
++	ldo	L\$AES_Td-L\$dec_pic($tbl),$tbl
++
++	and	$inp,$t0,$t0
++	sub	$inp,$t0,$inp
++	ldw	0($inp),$s0
++	ldw	4($inp),$s1
++	ldw	8($inp),$s2
++	comib,=	0,$t0,L\$dec_inp_aligned
++	ldw	12($inp),$s3
++
++	sh3addl	$t0,%r0,$t0
++	subi	32,$t0,$t0
++	mtctl	$t0,%cr11
++	ldw	16($inp),$t1
++	vshd	$s0,$s1,$s0
++	vshd	$s1,$s2,$s1
++	vshd	$s2,$s3,$s2
++	vshd	$s3,$t1,$s3
++
++L\$dec_inp_aligned
++	bl	_parisc_AES_decrypt,%r31
++	nop
++
++	extru,<> $out,31,2,%r0
++	b	L\$dec_out_aligned
++	nop
++
++	_srm	$s0,24,$acc0
++	_srm	$s0,16,$acc1
++	stb	$acc0,0($out)
++	_srm	$s0,8,$acc2
++	stb	$acc1,1($out)
++	_srm	$s1,24,$acc4
++	stb	$acc2,2($out)
++	_srm	$s1,16,$acc5
++	stb	$s0,3($out)
++	_srm	$s1,8,$acc6
++	stb	$acc4,4($out)
++	_srm	$s2,24,$acc0
++	stb	$acc5,5($out)
++	_srm	$s2,16,$acc1
++	stb	$acc6,6($out)
++	_srm	$s2,8,$acc2
++	stb	$s1,7($out)
++	_srm	$s3,24,$acc4
++	stb	$acc0,8($out)
++	_srm	$s3,16,$acc5
++	stb	$acc1,9($out)
++	_srm	$s3,8,$acc6
++	stb	$acc2,10($out)
++	stb	$s2,11($out)
++	stb	$acc4,12($out)
++	stb	$acc5,13($out)
++	stb	$acc6,14($out)
++	b	L\$dec_done
++	stb	$s3,15($out)
++
++L\$dec_out_aligned
++	stw	$s0,0($out)
++	stw	$s1,4($out)
++	stw	$s2,8($out)
++	stw	$s3,12($out)
++
++L\$dec_done
++	$POP	`-$FRAME-$SAVED_RP`(%sp),%r2	; standard epilogue
++	$POP	`-$FRAME+1*$SIZE_T`(%sp),%r4
++	$POP	`-$FRAME+2*$SIZE_T`(%sp),%r5
++	$POP	`-$FRAME+3*$SIZE_T`(%sp),%r6
++	$POP	`-$FRAME+4*$SIZE_T`(%sp),%r7
++	$POP	`-$FRAME+5*$SIZE_T`(%sp),%r8
++	$POP	`-$FRAME+6*$SIZE_T`(%sp),%r9
++	$POP	`-$FRAME+7*$SIZE_T`(%sp),%r10
++	$POP	`-$FRAME+8*$SIZE_T`(%sp),%r11
++	$POP	`-$FRAME+9*$SIZE_T`(%sp),%r12
++	$POP	`-$FRAME+10*$SIZE_T`(%sp),%r13
++	$POP	`-$FRAME+11*$SIZE_T`(%sp),%r14
++	$POP	`-$FRAME+12*$SIZE_T`(%sp),%r15
++	$POP	`-$FRAME+13*$SIZE_T`(%sp),%r16
++	$POP	`-$FRAME+14*$SIZE_T`(%sp),%r17
++	$POP	`-$FRAME+15*$SIZE_T`(%sp),%r18
++	bv	(%r2)
++	.EXIT
++	$POPMB	-$FRAME(%sp),%r3
++	.PROCEND
++
++	.ALIGN	16
++_parisc_AES_decrypt
++	.PROC
++	.CALLINFO	MILLICODE
++	.ENTRY
++	ldw	240($key),$rounds
++	ldw	0($key),$t0
++	ldw	4($key),$t1
++	ldw	8($key),$t2
++	ldw	12($key),$t3
++	_srm	$rounds,1,$rounds
++	xor	$t0,$s0,$s0
++	ldw	16($key),$t0
++	xor	$t1,$s1,$s1
++	ldw	20($key),$t1
++	_srm	$s0,24,$acc0
++	xor	$t2,$s2,$s2
++	ldw	24($key),$t2
++	xor	$t3,$s3,$s3
++	ldw	28($key),$t3
++	_srm	$s3,16,$acc1
++L\$dec_loop
++	_srm	$s2,8,$acc2
++	ldwx,s	$acc0($tbl),$acc0
++	_srm	$s1,0,$acc3
++	ldwx,s	$acc1($tbl),$acc1
++	_srm	$s1,24,$acc4
++	ldwx,s	$acc2($tbl),$acc2
++	_srm	$s0,16,$acc5
++	ldwx,s	$acc3($tbl),$acc3
++	_srm	$s3,8,$acc6
++	ldwx,s	$acc4($tbl),$acc4
++	_srm	$s2,0,$acc7
++	ldwx,s	$acc5($tbl),$acc5
++	_srm	$s2,24,$acc8
++	ldwx,s	$acc6($tbl),$acc6
++	_srm	$s1,16,$acc9
++	ldwx,s	$acc7($tbl),$acc7
++	_srm	$s0,8,$acc10
++	ldwx,s	$acc8($tbl),$acc8
++	_srm	$s3,0,$acc11
++	ldwx,s	$acc9($tbl),$acc9
++	_srm	$s3,24,$acc12
++	ldwx,s	$acc10($tbl),$acc10
++	_srm	$s2,16,$acc13
++	ldwx,s	$acc11($tbl),$acc11
++	_srm	$s1,8,$acc14
++	ldwx,s	$acc12($tbl),$acc12
++	_srm	$s0,0,$acc15
++	ldwx,s	$acc13($tbl),$acc13
++	ldwx,s	$acc14($tbl),$acc14
++	ldwx,s	$acc15($tbl),$acc15
++	addib,= -1,$rounds,L\$dec_last
++	ldo	32($key),$key
++
++		_ror	$acc1,8,$acc1
++		xor	$acc0,$t0,$t0
++	ldw	0($key),$s0
++		_ror	$acc2,16,$acc2
++		xor	$acc1,$t0,$t0
++	ldw	4($key),$s1
++		_ror	$acc3,24,$acc3
++		xor	$acc2,$t0,$t0
++	ldw	8($key),$s2
++		_ror	$acc5,8,$acc5
++		xor	$acc3,$t0,$t0
++	ldw	12($key),$s3
++		_ror	$acc6,16,$acc6
++		xor	$acc4,$t1,$t1
++		_ror	$acc7,24,$acc7
++		xor	$acc5,$t1,$t1
++		_ror	$acc9,8,$acc9
++		xor	$acc6,$t1,$t1
++		_ror	$acc10,16,$acc10
++		xor	$acc7,$t1,$t1
++		_ror	$acc11,24,$acc11
++		xor	$acc8,$t2,$t2
++		_ror	$acc13,8,$acc13
++		xor	$acc9,$t2,$t2
++		_ror	$acc14,16,$acc14
++		xor	$acc10,$t2,$t2
++		_ror	$acc15,24,$acc15
++		xor	$acc11,$t2,$t2
++		xor	$acc12,$acc14,$acc14
++		xor	$acc13,$t3,$t3
++	_srm	$t0,24,$acc0
++		xor	$acc14,$t3,$t3
++		xor	$acc15,$t3,$t3
++	_srm	$t3,16,$acc1
++
++	_srm	$t2,8,$acc2
++	ldwx,s	$acc0($tbl),$acc0
++	_srm	$t1,0,$acc3
++	ldwx,s	$acc1($tbl),$acc1
++	_srm	$t1,24,$acc4
++	ldwx,s	$acc2($tbl),$acc2
++	_srm	$t0,16,$acc5
++	ldwx,s	$acc3($tbl),$acc3
++	_srm	$t3,8,$acc6
++	ldwx,s	$acc4($tbl),$acc4
++	_srm	$t2,0,$acc7
++	ldwx,s	$acc5($tbl),$acc5
++	_srm	$t2,24,$acc8
++	ldwx,s	$acc6($tbl),$acc6
++	_srm	$t1,16,$acc9
++	ldwx,s	$acc7($tbl),$acc7
++	_srm	$t0,8,$acc10
++	ldwx,s	$acc8($tbl),$acc8
++	_srm	$t3,0,$acc11
++	ldwx,s	$acc9($tbl),$acc9
++	_srm	$t3,24,$acc12
++	ldwx,s	$acc10($tbl),$acc10
++	_srm	$t2,16,$acc13
++	ldwx,s	$acc11($tbl),$acc11
++	_srm	$t1,8,$acc14
++	ldwx,s	$acc12($tbl),$acc12
++	_srm	$t0,0,$acc15
++	ldwx,s	$acc13($tbl),$acc13
++		_ror	$acc1,8,$acc1
++	ldwx,s	$acc14($tbl),$acc14
++
++		_ror	$acc2,16,$acc2
++		xor	$acc0,$s0,$s0
++	ldwx,s	$acc15($tbl),$acc15
++		_ror	$acc3,24,$acc3
++		xor	$acc1,$s0,$s0
++	ldw	16($key),$t0
++		_ror	$acc5,8,$acc5
++		xor	$acc2,$s0,$s0
++	ldw	20($key),$t1
++		_ror	$acc6,16,$acc6
++		xor	$acc3,$s0,$s0
++	ldw	24($key),$t2
++		_ror	$acc7,24,$acc7
++		xor	$acc4,$s1,$s1
++	ldw	28($key),$t3
++		_ror	$acc9,8,$acc9
++		xor	$acc5,$s1,$s1
++	ldw	1024+0($tbl),%r0		; prefetch td4
++		_ror	$acc10,16,$acc10
++		xor	$acc6,$s1,$s1
++	ldw	1024+32($tbl),%r0		; prefetch td4
++		_ror	$acc11,24,$acc11
++		xor	$acc7,$s1,$s1
++	ldw	1024+64($tbl),%r0		; prefetch td4
++		_ror	$acc13,8,$acc13
++		xor	$acc8,$s2,$s2
++	ldw	1024+96($tbl),%r0		; prefetch td4
++		_ror	$acc14,16,$acc14
++		xor	$acc9,$s2,$s2
++	ldw	1024+128($tbl),%r0		; prefetch td4
++		_ror	$acc15,24,$acc15
++		xor	$acc10,$s2,$s2
++	ldw	1024+160($tbl),%r0		; prefetch td4
++	_srm	$s0,24,$acc0
++		xor	$acc11,$s2,$s2
++	ldw	1024+192($tbl),%r0		; prefetch td4
++		xor	$acc12,$acc14,$acc14
++		xor	$acc13,$s3,$s3
++	ldw	1024+224($tbl),%r0		; prefetch td4
++		xor	$acc14,$s3,$s3
++		xor	$acc15,$s3,$s3
++	b	L\$dec_loop
++	_srm	$s3,16,$acc1
++
++	.ALIGN	16
++L\$dec_last
++	ldo	1024($tbl),$rounds
++		_ror	$acc1,8,$acc1
++		xor	$acc0,$t0,$t0
++	ldw	0($key),$s0
++		_ror	$acc2,16,$acc2
++		xor	$acc1,$t0,$t0
++	ldw	4($key),$s1
++		_ror	$acc3,24,$acc3
++		xor	$acc2,$t0,$t0
++	ldw	8($key),$s2
++		_ror	$acc5,8,$acc5
++		xor	$acc3,$t0,$t0
++	ldw	12($key),$s3
++		_ror	$acc6,16,$acc6
++		xor	$acc4,$t1,$t1
++		_ror	$acc7,24,$acc7
++		xor	$acc5,$t1,$t1
++		_ror	$acc9,8,$acc9
++		xor	$acc6,$t1,$t1
++		_ror	$acc10,16,$acc10
++		xor	$acc7,$t1,$t1
++		_ror	$acc11,24,$acc11
++		xor	$acc8,$t2,$t2
++		_ror	$acc13,8,$acc13
++		xor	$acc9,$t2,$t2
++		_ror	$acc14,16,$acc14
++		xor	$acc10,$t2,$t2
++		_ror	$acc15,24,$acc15
++		xor	$acc11,$t2,$t2
++		xor	$acc12,$acc14,$acc14
++		xor	$acc13,$t3,$t3
++	_srm	$t0,24,$acc0
++		xor	$acc14,$t3,$t3
++		xor	$acc15,$t3,$t3
++	_srm	$t3,16,$acc1
++
++	_srm	$t2,8,$acc2
++	ldbx	$acc0($rounds),$acc0
++	_srm	$t1,24,$acc4
++	ldbx	$acc1($rounds),$acc1
++	_srm	$t0,16,$acc5
++	_srm	$t1,0,$acc3
++	ldbx	$acc2($rounds),$acc2
++	ldbx	$acc3($rounds),$acc3
++	_srm	$t3,8,$acc6
++	ldbx	$acc4($rounds),$acc4
++	_srm	$t2,24,$acc8
++	ldbx	$acc5($rounds),$acc5
++	_srm	$t1,16,$acc9
++	_srm	$t2,0,$acc7
++	ldbx	$acc6($rounds),$acc6
++	ldbx	$acc7($rounds),$acc7
++	_srm	$t0,8,$acc10
++	ldbx	$acc8($rounds),$acc8
++	_srm	$t3,24,$acc12
++	ldbx	$acc9($rounds),$acc9
++	_srm	$t2,16,$acc13
++	_srm	$t3,0,$acc11
++	ldbx	$acc10($rounds),$acc10
++	_srm	$t1,8,$acc14
++	ldbx	$acc11($rounds),$acc11
++	ldbx	$acc12($rounds),$acc12
++	ldbx	$acc13($rounds),$acc13
++	_srm	$t0,0,$acc15
++	ldbx	$acc14($rounds),$acc14
++
++		dep	$acc0,7,8,$acc3
++	ldbx	$acc15($rounds),$acc15
++		dep	$acc4,7,8,$acc7
++		dep	$acc1,15,8,$acc3
++		dep	$acc5,15,8,$acc7
++		dep	$acc2,23,8,$acc3
++		dep	$acc6,23,8,$acc7
++		xor	$acc3,$s0,$s0
++		xor	$acc7,$s1,$s1
++		dep	$acc8,7,8,$acc11
++		dep	$acc12,7,8,$acc15
++		dep	$acc9,15,8,$acc11
++		dep	$acc13,15,8,$acc15
++		dep	$acc10,23,8,$acc11
++		dep	$acc14,23,8,$acc15
++		xor	$acc11,$s2,$s2
++
++	bv	(%r31)
++	.EXIT
++		xor	$acc15,$s3,$s3
++	.PROCEND
++
++	.ALIGN	64
++L\$AES_Td
++	.WORD	0x51f4a750, 0x7e416553, 0x1a17a4c3, 0x3a275e96
++	.WORD	0x3bab6bcb, 0x1f9d45f1, 0xacfa58ab, 0x4be30393
++	.WORD	0x2030fa55, 0xad766df6, 0x88cc7691, 0xf5024c25
++	.WORD	0x4fe5d7fc, 0xc52acbd7, 0x26354480, 0xb562a38f
++	.WORD	0xdeb15a49, 0x25ba1b67, 0x45ea0e98, 0x5dfec0e1
++	.WORD	0xc32f7502, 0x814cf012, 0x8d4697a3, 0x6bd3f9c6
++	.WORD	0x038f5fe7, 0x15929c95, 0xbf6d7aeb, 0x955259da
++	.WORD	0xd4be832d, 0x587421d3, 0x49e06929, 0x8ec9c844
++	.WORD	0x75c2896a, 0xf48e7978, 0x99583e6b, 0x27b971dd
++	.WORD	0xbee14fb6, 0xf088ad17, 0xc920ac66, 0x7dce3ab4
++	.WORD	0x63df4a18, 0xe51a3182, 0x97513360, 0x62537f45
++	.WORD	0xb16477e0, 0xbb6bae84, 0xfe81a01c, 0xf9082b94
++	.WORD	0x70486858, 0x8f45fd19, 0x94de6c87, 0x527bf8b7
++	.WORD	0xab73d323, 0x724b02e2, 0xe31f8f57, 0x6655ab2a
++	.WORD	0xb2eb2807, 0x2fb5c203, 0x86c57b9a, 0xd33708a5
++	.WORD	0x302887f2, 0x23bfa5b2, 0x02036aba, 0xed16825c
++	.WORD	0x8acf1c2b, 0xa779b492, 0xf307f2f0, 0x4e69e2a1
++	.WORD	0x65daf4cd, 0x0605bed5, 0xd134621f, 0xc4a6fe8a
++	.WORD	0x342e539d, 0xa2f355a0, 0x058ae132, 0xa4f6eb75
++	.WORD	0x0b83ec39, 0x4060efaa, 0x5e719f06, 0xbd6e1051
++	.WORD	0x3e218af9, 0x96dd063d, 0xdd3e05ae, 0x4de6bd46
++	.WORD	0x91548db5, 0x71c45d05, 0x0406d46f, 0x605015ff
++	.WORD	0x1998fb24, 0xd6bde997, 0x894043cc, 0x67d99e77
++	.WORD	0xb0e842bd, 0x07898b88, 0xe7195b38, 0x79c8eedb
++	.WORD	0xa17c0a47, 0x7c420fe9, 0xf8841ec9, 0x00000000
++	.WORD	0x09808683, 0x322bed48, 0x1e1170ac, 0x6c5a724e
++	.WORD	0xfd0efffb, 0x0f853856, 0x3daed51e, 0x362d3927
++	.WORD	0x0a0fd964, 0x685ca621, 0x9b5b54d1, 0x24362e3a
++	.WORD	0x0c0a67b1, 0x9357e70f, 0xb4ee96d2, 0x1b9b919e
++	.WORD	0x80c0c54f, 0x61dc20a2, 0x5a774b69, 0x1c121a16
++	.WORD	0xe293ba0a, 0xc0a02ae5, 0x3c22e043, 0x121b171d
++	.WORD	0x0e090d0b, 0xf28bc7ad, 0x2db6a8b9, 0x141ea9c8
++	.WORD	0x57f11985, 0xaf75074c, 0xee99ddbb, 0xa37f60fd
++	.WORD	0xf701269f, 0x5c72f5bc, 0x44663bc5, 0x5bfb7e34
++	.WORD	0x8b432976, 0xcb23c6dc, 0xb6edfc68, 0xb8e4f163
++	.WORD	0xd731dcca, 0x42638510, 0x13972240, 0x84c61120
++	.WORD	0x854a247d, 0xd2bb3df8, 0xaef93211, 0xc729a16d
++	.WORD	0x1d9e2f4b, 0xdcb230f3, 0x0d8652ec, 0x77c1e3d0
++	.WORD	0x2bb3166c, 0xa970b999, 0x119448fa, 0x47e96422
++	.WORD	0xa8fc8cc4, 0xa0f03f1a, 0x567d2cd8, 0x223390ef
++	.WORD	0x87494ec7, 0xd938d1c1, 0x8ccaa2fe, 0x98d40b36
++	.WORD	0xa6f581cf, 0xa57ade28, 0xdab78e26, 0x3fadbfa4
++	.WORD	0x2c3a9de4, 0x5078920d, 0x6a5fcc9b, 0x547e4662
++	.WORD	0xf68d13c2, 0x90d8b8e8, 0x2e39f75e, 0x82c3aff5
++	.WORD	0x9f5d80be, 0x69d0937c, 0x6fd52da9, 0xcf2512b3
++	.WORD	0xc8ac993b, 0x10187da7, 0xe89c636e, 0xdb3bbb7b
++	.WORD	0xcd267809, 0x6e5918f4, 0xec9ab701, 0x834f9aa8
++	.WORD	0xe6956e65, 0xaaffe67e, 0x21bccf08, 0xef15e8e6
++	.WORD	0xbae79bd9, 0x4a6f36ce, 0xea9f09d4, 0x29b07cd6
++	.WORD	0x31a4b2af, 0x2a3f2331, 0xc6a59430, 0x35a266c0
++	.WORD	0x744ebc37, 0xfc82caa6, 0xe090d0b0, 0x33a7d815
++	.WORD	0xf104984a, 0x41ecdaf7, 0x7fcd500e, 0x1791f62f
++	.WORD	0x764dd68d, 0x43efb04d, 0xccaa4d54, 0xe49604df
++	.WORD	0x9ed1b5e3, 0x4c6a881b, 0xc12c1fb8, 0x4665517f
++	.WORD	0x9d5eea04, 0x018c355d, 0xfa877473, 0xfb0b412e
++	.WORD	0xb3671d5a, 0x92dbd252, 0xe9105633, 0x6dd64713
++	.WORD	0x9ad7618c, 0x37a10c7a, 0x59f8148e, 0xeb133c89
++	.WORD	0xcea927ee, 0xb761c935, 0xe11ce5ed, 0x7a47b13c
++	.WORD	0x9cd2df59, 0x55f2733f, 0x1814ce79, 0x73c737bf
++	.WORD	0x53f7cdea, 0x5ffdaa5b, 0xdf3d6f14, 0x7844db86
++	.WORD	0xcaaff381, 0xb968c43e, 0x3824342c, 0xc2a3405f
++	.WORD	0x161dc372, 0xbce2250c, 0x283c498b, 0xff0d9541
++	.WORD	0x39a80171, 0x080cb3de, 0xd8b4e49c, 0x6456c190
++	.WORD	0x7bcb8461, 0xd532b670, 0x486c5c74, 0xd0b85742
++	.BYTE	0x52, 0x09, 0x6a, 0xd5, 0x30, 0x36, 0xa5, 0x38
++	.BYTE	0xbf, 0x40, 0xa3, 0x9e, 0x81, 0xf3, 0xd7, 0xfb
++	.BYTE	0x7c, 0xe3, 0x39, 0x82, 0x9b, 0x2f, 0xff, 0x87
++	.BYTE	0x34, 0x8e, 0x43, 0x44, 0xc4, 0xde, 0xe9, 0xcb
++	.BYTE	0x54, 0x7b, 0x94, 0x32, 0xa6, 0xc2, 0x23, 0x3d
++	.BYTE	0xee, 0x4c, 0x95, 0x0b, 0x42, 0xfa, 0xc3, 0x4e
++	.BYTE	0x08, 0x2e, 0xa1, 0x66, 0x28, 0xd9, 0x24, 0xb2
++	.BYTE	0x76, 0x5b, 0xa2, 0x49, 0x6d, 0x8b, 0xd1, 0x25
++	.BYTE	0x72, 0xf8, 0xf6, 0x64, 0x86, 0x68, 0x98, 0x16
++	.BYTE	0xd4, 0xa4, 0x5c, 0xcc, 0x5d, 0x65, 0xb6, 0x92
++	.BYTE	0x6c, 0x70, 0x48, 0x50, 0xfd, 0xed, 0xb9, 0xda
++	.BYTE	0x5e, 0x15, 0x46, 0x57, 0xa7, 0x8d, 0x9d, 0x84
++	.BYTE	0x90, 0xd8, 0xab, 0x00, 0x8c, 0xbc, 0xd3, 0x0a
++	.BYTE	0xf7, 0xe4, 0x58, 0x05, 0xb8, 0xb3, 0x45, 0x06
++	.BYTE	0xd0, 0x2c, 0x1e, 0x8f, 0xca, 0x3f, 0x0f, 0x02
++	.BYTE	0xc1, 0xaf, 0xbd, 0x03, 0x01, 0x13, 0x8a, 0x6b
++	.BYTE	0x3a, 0x91, 0x11, 0x41, 0x4f, 0x67, 0xdc, 0xea
++	.BYTE	0x97, 0xf2, 0xcf, 0xce, 0xf0, 0xb4, 0xe6, 0x73
++	.BYTE	0x96, 0xac, 0x74, 0x22, 0xe7, 0xad, 0x35, 0x85
++	.BYTE	0xe2, 0xf9, 0x37, 0xe8, 0x1c, 0x75, 0xdf, 0x6e
++	.BYTE	0x47, 0xf1, 0x1a, 0x71, 0x1d, 0x29, 0xc5, 0x89
++	.BYTE	0x6f, 0xb7, 0x62, 0x0e, 0xaa, 0x18, 0xbe, 0x1b
++	.BYTE	0xfc, 0x56, 0x3e, 0x4b, 0xc6, 0xd2, 0x79, 0x20
++	.BYTE	0x9a, 0xdb, 0xc0, 0xfe, 0x78, 0xcd, 0x5a, 0xf4
++	.BYTE	0x1f, 0xdd, 0xa8, 0x33, 0x88, 0x07, 0xc7, 0x31
++	.BYTE	0xb1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xec, 0x5f
++	.BYTE	0x60, 0x51, 0x7f, 0xa9, 0x19, 0xb5, 0x4a, 0x0d
++	.BYTE	0x2d, 0xe5, 0x7a, 0x9f, 0x93, 0xc9, 0x9c, 0xef
++	.BYTE	0xa0, 0xe0, 0x3b, 0x4d, 0xae, 0x2a, 0xf5, 0xb0
++	.BYTE	0xc8, 0xeb, 0xbb, 0x3c, 0x83, 0x53, 0x99, 0x61
++	.BYTE	0x17, 0x2b, 0x04, 0x7e, 0xba, 0x77, 0xd6, 0x26
++	.BYTE	0xe1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0c, 0x7d
++	.STRINGZ "AES for PA-RISC, CRYPTOGAMS by "
++___
++
++foreach (split("\n",$code)) {
++	s/\`([^\`]*)\`/eval $1/ge;
++
++	# translate made up instructons: _ror, _srm
++	s/_ror(\s+)(%r[0-9]+),/shd$1$2,$2,/				or
++
++	s/_srm(\s+%r[0-9]+),([0-9]+),/
++		$SIZE_T==4 ? sprintf("extru%s,%d,8,",$1,31-$2)
++		:            sprintf("extrd,u%s,%d,8,",$1,63-$2)/e;
++
++	s/,\*/,/			if ($SIZE_T==4);
++	s/\bbv\b(.*\(%r2\))/bve$1/	if ($SIZE_T==8);
++	print $_,"\n";
++}
++close STDOUT;
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/aes/asm/aes-ppc.pl b/CryptoPkg/Library/OpensslLib/openssl/crypto/aes/asm/aes-ppc.pl
+new file mode 100644
+index 0000000..1558d8e
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/aes/asm/aes-ppc.pl
+@@ -0,0 +1,1459 @@
++#! /usr/bin/env perl
++# Copyright 2007-2016 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
++# in the file LICENSE in the source distribution or at
++# https://www.openssl.org/source/license.html
++
++
++# ====================================================================
++# Written by Andy Polyakov  for the OpenSSL
++# project. The module is, however, dual licensed under OpenSSL and
++# CRYPTOGAMS licenses depending on where you obtain it. For further
++# details see http://www.openssl.org/~appro/cryptogams/.
++# ====================================================================
++
++# Needs more work: key setup, CBC routine...
++#
++# ppc_AES_[en|de]crypt perform at 18 cycles per byte processed with
++# 128-bit key, which is ~40% better than 64-bit code generated by gcc
++# 4.0. But these are not the ones currently used! Their "compact"
++# counterparts are, for security reason. ppc_AES_encrypt_compact runs
++# at 1/2 of ppc_AES_encrypt speed, while ppc_AES_decrypt_compact -
++# at 1/3 of ppc_AES_decrypt.
++
++# February 2010
++#
++# Rescheduling instructions to favour Power6 pipeline gave 10%
++# performance improvement on the platform in question (and marginal
++# improvement even on others). It should be noted that Power6 fails
++# to process byte in 18 cycles, only in 23, because it fails to issue
++# 4 load instructions in two cycles, only in 3. As result non-compact
++# block subroutines are 25% slower than one would expect. Compact
++# functions scale better, because they have pure computational part,
++# which scales perfectly with clock frequency. To be specific
++# ppc_AES_encrypt_compact operates at 42 cycles per byte, while
++# ppc_AES_decrypt_compact - at 55 (in 64-bit build).
++
++$flavour = shift;
++
++if ($flavour =~ /64/) {
++	$SIZE_T	=8;
++	$LRSAVE	=2*$SIZE_T;
++	$STU	="stdu";
++	$POP	="ld";
++	$PUSH	="std";
++} elsif ($flavour =~ /32/) {
++	$SIZE_T	=4;
++	$LRSAVE	=$SIZE_T;
++	$STU	="stwu";
++	$POP	="lwz";
++	$PUSH	="stw";
++} else { die "nonsense $flavour"; }
++
++$LITTLE_ENDIAN = ($flavour=~/le$/) ? $SIZE_T : 0;
++
++$0 =~ m/(.*[\/\\])[^\/\\]+$/; $dir=$1;
++( $xlate="${dir}ppc-xlate.pl" and -f $xlate ) or
++( $xlate="${dir}../../perlasm/ppc-xlate.pl" and -f $xlate) or
++die "can't locate ppc-xlate.pl";
++
++open STDOUT,"| $^X $xlate $flavour ".shift || die "can't call $xlate: $!";
++
++$FRAME=32*$SIZE_T;
++
++sub _data_word()
++{ my $i;
++    while(defined($i=shift)) { $code.=sprintf"\t.long\t0x%08x,0x%08x\n",$i,$i; }
++}
++
++$sp="r1";
++$toc="r2";
++$inp="r3";
++$out="r4";
++$key="r5";
++
++$Tbl0="r3";
++$Tbl1="r6";
++$Tbl2="r7";
++$Tbl3=$out;	# stay away from "r2"; $out is offloaded to stack
++
++$s0="r8";
++$s1="r9";
++$s2="r10";
++$s3="r11";
++
++$t0="r12";
++$t1="r0";	# stay away from "r13";
++$t2="r14";
++$t3="r15";
++
++$acc00="r16";
++$acc01="r17";
++$acc02="r18";
++$acc03="r19";
++
++$acc04="r20";
++$acc05="r21";
++$acc06="r22";
++$acc07="r23";
++
++$acc08="r24";
++$acc09="r25";
++$acc10="r26";
++$acc11="r27";
++
++$acc12="r28";
++$acc13="r29";
++$acc14="r30";
++$acc15="r31";
++
++$mask80=$Tbl2;
++$mask1b=$Tbl3;
++
++$code.=<<___;
++.machine	"any"
++.text
++
++.align	7
++LAES_Te:
++	mflr	r0
++	bcl	20,31,\$+4
++	mflr	$Tbl0	;    vvvvv "distance" between . and 1st data entry
++	addi	$Tbl0,$Tbl0,`128-8`
++	mtlr	r0
++	blr
++	.long	0
++	.byte	0,12,0x14,0,0,0,0,0
++	.space	`64-9*4`
++LAES_Td:
++	mflr	r0
++	bcl	20,31,\$+4
++	mflr	$Tbl0	;    vvvvvvvv "distance" between . and 1st data entry
++	addi	$Tbl0,$Tbl0,`128-64-8+2048+256`
++	mtlr	r0
++	blr
++	.long	0
++	.byte	0,12,0x14,0,0,0,0,0
++	.space	`128-64-9*4`
++___
++&_data_word(
++	0xc66363a5, 0xf87c7c84, 0xee777799, 0xf67b7b8d,
++	0xfff2f20d, 0xd66b6bbd, 0xde6f6fb1, 0x91c5c554,
++	0x60303050, 0x02010103, 0xce6767a9, 0x562b2b7d,
++	0xe7fefe19, 0xb5d7d762, 0x4dababe6, 0xec76769a,
++	0x8fcaca45, 0x1f82829d, 0x89c9c940, 0xfa7d7d87,
++	0xeffafa15, 0xb25959eb, 0x8e4747c9, 0xfbf0f00b,
++	0x41adadec, 0xb3d4d467, 0x5fa2a2fd, 0x45afafea,
++	0x239c9cbf, 0x53a4a4f7, 0xe4727296, 0x9bc0c05b,
++	0x75b7b7c2, 0xe1fdfd1c, 0x3d9393ae, 0x4c26266a,
++	0x6c36365a, 0x7e3f3f41, 0xf5f7f702, 0x83cccc4f,
++	0x6834345c, 0x51a5a5f4, 0xd1e5e534, 0xf9f1f108,
++	0xe2717193, 0xabd8d873, 0x62313153, 0x2a15153f,
++	0x0804040c, 0x95c7c752, 0x46232365, 0x9dc3c35e,
++	0x30181828, 0x379696a1, 0x0a05050f, 0x2f9a9ab5,
++	0x0e070709, 0x24121236, 0x1b80809b, 0xdfe2e23d,
++	0xcdebeb26, 0x4e272769, 0x7fb2b2cd, 0xea75759f,
++	0x1209091b, 0x1d83839e, 0x582c2c74, 0x341a1a2e,
++	0x361b1b2d, 0xdc6e6eb2, 0xb45a5aee, 0x5ba0a0fb,
++	0xa45252f6, 0x763b3b4d, 0xb7d6d661, 0x7db3b3ce,
++	0x5229297b, 0xdde3e33e, 0x5e2f2f71, 0x13848497,
++	0xa65353f5, 0xb9d1d168, 0x00000000, 0xc1eded2c,
++	0x40202060, 0xe3fcfc1f, 0x79b1b1c8, 0xb65b5bed,
++	0xd46a6abe, 0x8dcbcb46, 0x67bebed9, 0x7239394b,
++	0x944a4ade, 0x984c4cd4, 0xb05858e8, 0x85cfcf4a,
++	0xbbd0d06b, 0xc5efef2a, 0x4faaaae5, 0xedfbfb16,
++	0x864343c5, 0x9a4d4dd7, 0x66333355, 0x11858594,
++	0x8a4545cf, 0xe9f9f910, 0x04020206, 0xfe7f7f81,
++	0xa05050f0, 0x783c3c44, 0x259f9fba, 0x4ba8a8e3,
++	0xa25151f3, 0x5da3a3fe, 0x804040c0, 0x058f8f8a,
++	0x3f9292ad, 0x219d9dbc, 0x70383848, 0xf1f5f504,
++	0x63bcbcdf, 0x77b6b6c1, 0xafdada75, 0x42212163,
++	0x20101030, 0xe5ffff1a, 0xfdf3f30e, 0xbfd2d26d,
++	0x81cdcd4c, 0x180c0c14, 0x26131335, 0xc3ecec2f,
++	0xbe5f5fe1, 0x359797a2, 0x884444cc, 0x2e171739,
++	0x93c4c457, 0x55a7a7f2, 0xfc7e7e82, 0x7a3d3d47,
++	0xc86464ac, 0xba5d5de7, 0x3219192b, 0xe6737395,
++	0xc06060a0, 0x19818198, 0x9e4f4fd1, 0xa3dcdc7f,
++	0x44222266, 0x542a2a7e, 0x3b9090ab, 0x0b888883,
++	0x8c4646ca, 0xc7eeee29, 0x6bb8b8d3, 0x2814143c,
++	0xa7dede79, 0xbc5e5ee2, 0x160b0b1d, 0xaddbdb76,
++	0xdbe0e03b, 0x64323256, 0x743a3a4e, 0x140a0a1e,
++	0x924949db, 0x0c06060a, 0x4824246c, 0xb85c5ce4,
++	0x9fc2c25d, 0xbdd3d36e, 0x43acacef, 0xc46262a6,
++	0x399191a8, 0x319595a4, 0xd3e4e437, 0xf279798b,
++	0xd5e7e732, 0x8bc8c843, 0x6e373759, 0xda6d6db7,
++	0x018d8d8c, 0xb1d5d564, 0x9c4e4ed2, 0x49a9a9e0,
++	0xd86c6cb4, 0xac5656fa, 0xf3f4f407, 0xcfeaea25,
++	0xca6565af, 0xf47a7a8e, 0x47aeaee9, 0x10080818,
++	0x6fbabad5, 0xf0787888, 0x4a25256f, 0x5c2e2e72,
++	0x381c1c24, 0x57a6a6f1, 0x73b4b4c7, 0x97c6c651,
++	0xcbe8e823, 0xa1dddd7c, 0xe874749c, 0x3e1f1f21,
++	0x964b4bdd, 0x61bdbddc, 0x0d8b8b86, 0x0f8a8a85,
++	0xe0707090, 0x7c3e3e42, 0x71b5b5c4, 0xcc6666aa,
++	0x904848d8, 0x06030305, 0xf7f6f601, 0x1c0e0e12,
++	0xc26161a3, 0x6a35355f, 0xae5757f9, 0x69b9b9d0,
++	0x17868691, 0x99c1c158, 0x3a1d1d27, 0x279e9eb9,
++	0xd9e1e138, 0xebf8f813, 0x2b9898b3, 0x22111133,
++	0xd26969bb, 0xa9d9d970, 0x078e8e89, 0x339494a7,
++	0x2d9b9bb6, 0x3c1e1e22, 0x15878792, 0xc9e9e920,
++	0x87cece49, 0xaa5555ff, 0x50282878, 0xa5dfdf7a,
++	0x038c8c8f, 0x59a1a1f8, 0x09898980, 0x1a0d0d17,
++	0x65bfbfda, 0xd7e6e631, 0x844242c6, 0xd06868b8,
++	0x824141c3, 0x299999b0, 0x5a2d2d77, 0x1e0f0f11,
++	0x7bb0b0cb, 0xa85454fc, 0x6dbbbbd6, 0x2c16163a);
++$code.=<<___;
++.byte	0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5
++.byte	0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76
++.byte	0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0
++.byte	0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0
++.byte	0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc
++.byte	0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15
++.byte	0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a
++.byte	0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75
++.byte	0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0
++.byte	0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84
++.byte	0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b
++.byte	0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf
++.byte	0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85
++.byte	0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8
++.byte	0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5
++.byte	0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2
++.byte	0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17
++.byte	0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73
++.byte	0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88
++.byte	0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb
++.byte	0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c
++.byte	0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79
++.byte	0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9
++.byte	0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08
++.byte	0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6
++.byte	0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a
++.byte	0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e
++.byte	0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e
++.byte	0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94
++.byte	0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf
++.byte	0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68
++.byte	0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16
++___
++&_data_word(
++	0x51f4a750, 0x7e416553, 0x1a17a4c3, 0x3a275e96,
++	0x3bab6bcb, 0x1f9d45f1, 0xacfa58ab, 0x4be30393,
++	0x2030fa55, 0xad766df6, 0x88cc7691, 0xf5024c25,
++	0x4fe5d7fc, 0xc52acbd7, 0x26354480, 0xb562a38f,
++	0xdeb15a49, 0x25ba1b67, 0x45ea0e98, 0x5dfec0e1,
++	0xc32f7502, 0x814cf012, 0x8d4697a3, 0x6bd3f9c6,
++	0x038f5fe7, 0x15929c95, 0xbf6d7aeb, 0x955259da,
++	0xd4be832d, 0x587421d3, 0x49e06929, 0x8ec9c844,
++	0x75c2896a, 0xf48e7978, 0x99583e6b, 0x27b971dd,
++	0xbee14fb6, 0xf088ad17, 0xc920ac66, 0x7dce3ab4,
++	0x63df4a18, 0xe51a3182, 0x97513360, 0x62537f45,
++	0xb16477e0, 0xbb6bae84, 0xfe81a01c, 0xf9082b94,
++	0x70486858, 0x8f45fd19, 0x94de6c87, 0x527bf8b7,
++	0xab73d323, 0x724b02e2, 0xe31f8f57, 0x6655ab2a,
++	0xb2eb2807, 0x2fb5c203, 0x86c57b9a, 0xd33708a5,
++	0x302887f2, 0x23bfa5b2, 0x02036aba, 0xed16825c,
++	0x8acf1c2b, 0xa779b492, 0xf307f2f0, 0x4e69e2a1,
++	0x65daf4cd, 0x0605bed5, 0xd134621f, 0xc4a6fe8a,
++	0x342e539d, 0xa2f355a0, 0x058ae132, 0xa4f6eb75,
++	0x0b83ec39, 0x4060efaa, 0x5e719f06, 0xbd6e1051,
++	0x3e218af9, 0x96dd063d, 0xdd3e05ae, 0x4de6bd46,
++	0x91548db5, 0x71c45d05, 0x0406d46f, 0x605015ff,
++	0x1998fb24, 0xd6bde997, 0x894043cc, 0x67d99e77,
++	0xb0e842bd, 0x07898b88, 0xe7195b38, 0x79c8eedb,
++	0xa17c0a47, 0x7c420fe9, 0xf8841ec9, 0x00000000,
++	0x09808683, 0x322bed48, 0x1e1170ac, 0x6c5a724e,
++	0xfd0efffb, 0x0f853856, 0x3daed51e, 0x362d3927,
++	0x0a0fd964, 0x685ca621, 0x9b5b54d1, 0x24362e3a,
++	0x0c0a67b1, 0x9357e70f, 0xb4ee96d2, 0x1b9b919e,
++	0x80c0c54f, 0x61dc20a2, 0x5a774b69, 0x1c121a16,
++	0xe293ba0a, 0xc0a02ae5, 0x3c22e043, 0x121b171d,
++	0x0e090d0b, 0xf28bc7ad, 0x2db6a8b9, 0x141ea9c8,
++	0x57f11985, 0xaf75074c, 0xee99ddbb, 0xa37f60fd,
++	0xf701269f, 0x5c72f5bc, 0x44663bc5, 0x5bfb7e34,
++	0x8b432976, 0xcb23c6dc, 0xb6edfc68, 0xb8e4f163,
++	0xd731dcca, 0x42638510, 0x13972240, 0x84c61120,
++	0x854a247d, 0xd2bb3df8, 0xaef93211, 0xc729a16d,
++	0x1d9e2f4b, 0xdcb230f3, 0x0d8652ec, 0x77c1e3d0,
++	0x2bb3166c, 0xa970b999, 0x119448fa, 0x47e96422,
++	0xa8fc8cc4, 0xa0f03f1a, 0x567d2cd8, 0x223390ef,
++	0x87494ec7, 0xd938d1c1, 0x8ccaa2fe, 0x98d40b36,
++	0xa6f581cf, 0xa57ade28, 0xdab78e26, 0x3fadbfa4,
++	0x2c3a9de4, 0x5078920d, 0x6a5fcc9b, 0x547e4662,
++	0xf68d13c2, 0x90d8b8e8, 0x2e39f75e, 0x82c3aff5,
++	0x9f5d80be, 0x69d0937c, 0x6fd52da9, 0xcf2512b3,
++	0xc8ac993b, 0x10187da7, 0xe89c636e, 0xdb3bbb7b,
++	0xcd267809, 0x6e5918f4, 0xec9ab701, 0x834f9aa8,
++	0xe6956e65, 0xaaffe67e, 0x21bccf08, 0xef15e8e6,
++	0xbae79bd9, 0x4a6f36ce, 0xea9f09d4, 0x29b07cd6,
++	0x31a4b2af, 0x2a3f2331, 0xc6a59430, 0x35a266c0,
++	0x744ebc37, 0xfc82caa6, 0xe090d0b0, 0x33a7d815,
++	0xf104984a, 0x41ecdaf7, 0x7fcd500e, 0x1791f62f,
++	0x764dd68d, 0x43efb04d, 0xccaa4d54, 0xe49604df,
++	0x9ed1b5e3, 0x4c6a881b, 0xc12c1fb8, 0x4665517f,
++	0x9d5eea04, 0x018c355d, 0xfa877473, 0xfb0b412e,
++	0xb3671d5a, 0x92dbd252, 0xe9105633, 0x6dd64713,
++	0x9ad7618c, 0x37a10c7a, 0x59f8148e, 0xeb133c89,
++	0xcea927ee, 0xb761c935, 0xe11ce5ed, 0x7a47b13c,
++	0x9cd2df59, 0x55f2733f, 0x1814ce79, 0x73c737bf,
++	0x53f7cdea, 0x5ffdaa5b, 0xdf3d6f14, 0x7844db86,
++	0xcaaff381, 0xb968c43e, 0x3824342c, 0xc2a3405f,
++	0x161dc372, 0xbce2250c, 0x283c498b, 0xff0d9541,
++	0x39a80171, 0x080cb3de, 0xd8b4e49c, 0x6456c190,
++	0x7bcb8461, 0xd532b670, 0x486c5c74, 0xd0b85742);
++$code.=<<___;
++.byte	0x52, 0x09, 0x6a, 0xd5, 0x30, 0x36, 0xa5, 0x38
++.byte	0xbf, 0x40, 0xa3, 0x9e, 0x81, 0xf3, 0xd7, 0xfb
++.byte	0x7c, 0xe3, 0x39, 0x82, 0x9b, 0x2f, 0xff, 0x87
++.byte	0x34, 0x8e, 0x43, 0x44, 0xc4, 0xde, 0xe9, 0xcb
++.byte	0x54, 0x7b, 0x94, 0x32, 0xa6, 0xc2, 0x23, 0x3d
++.byte	0xee, 0x4c, 0x95, 0x0b, 0x42, 0xfa, 0xc3, 0x4e
++.byte	0x08, 0x2e, 0xa1, 0x66, 0x28, 0xd9, 0x24, 0xb2
++.byte	0x76, 0x5b, 0xa2, 0x49, 0x6d, 0x8b, 0xd1, 0x25
++.byte	0x72, 0xf8, 0xf6, 0x64, 0x86, 0x68, 0x98, 0x16
++.byte	0xd4, 0xa4, 0x5c, 0xcc, 0x5d, 0x65, 0xb6, 0x92
++.byte	0x6c, 0x70, 0x48, 0x50, 0xfd, 0xed, 0xb9, 0xda
++.byte	0x5e, 0x15, 0x46, 0x57, 0xa7, 0x8d, 0x9d, 0x84
++.byte	0x90, 0xd8, 0xab, 0x00, 0x8c, 0xbc, 0xd3, 0x0a
++.byte	0xf7, 0xe4, 0x58, 0x05, 0xb8, 0xb3, 0x45, 0x06
++.byte	0xd0, 0x2c, 0x1e, 0x8f, 0xca, 0x3f, 0x0f, 0x02
++.byte	0xc1, 0xaf, 0xbd, 0x03, 0x01, 0x13, 0x8a, 0x6b
++.byte	0x3a, 0x91, 0x11, 0x41, 0x4f, 0x67, 0xdc, 0xea
++.byte	0x97, 0xf2, 0xcf, 0xce, 0xf0, 0xb4, 0xe6, 0x73
++.byte	0x96, 0xac, 0x74, 0x22, 0xe7, 0xad, 0x35, 0x85
++.byte	0xe2, 0xf9, 0x37, 0xe8, 0x1c, 0x75, 0xdf, 0x6e
++.byte	0x47, 0xf1, 0x1a, 0x71, 0x1d, 0x29, 0xc5, 0x89
++.byte	0x6f, 0xb7, 0x62, 0x0e, 0xaa, 0x18, 0xbe, 0x1b
++.byte	0xfc, 0x56, 0x3e, 0x4b, 0xc6, 0xd2, 0x79, 0x20
++.byte	0x9a, 0xdb, 0xc0, 0xfe, 0x78, 0xcd, 0x5a, 0xf4
++.byte	0x1f, 0xdd, 0xa8, 0x33, 0x88, 0x07, 0xc7, 0x31
++.byte	0xb1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xec, 0x5f
++.byte	0x60, 0x51, 0x7f, 0xa9, 0x19, 0xb5, 0x4a, 0x0d
++.byte	0x2d, 0xe5, 0x7a, 0x9f, 0x93, 0xc9, 0x9c, 0xef
++.byte	0xa0, 0xe0, 0x3b, 0x4d, 0xae, 0x2a, 0xf5, 0xb0
++.byte	0xc8, 0xeb, 0xbb, 0x3c, 0x83, 0x53, 0x99, 0x61
++.byte	0x17, 0x2b, 0x04, 0x7e, 0xba, 0x77, 0xd6, 0x26
++.byte	0xe1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0c, 0x7d
++
++
++.globl	.AES_encrypt
++.align	7
++.AES_encrypt:
++	$STU	$sp,-$FRAME($sp)
++	mflr	r0
++
++	$PUSH	$out,`$FRAME-$SIZE_T*19`($sp)
++	$PUSH	r14,`$FRAME-$SIZE_T*18`($sp)
++	$PUSH	r15,`$FRAME-$SIZE_T*17`($sp)
++	$PUSH	r16,`$FRAME-$SIZE_T*16`($sp)
++	$PUSH	r17,`$FRAME-$SIZE_T*15`($sp)
++	$PUSH	r18,`$FRAME-$SIZE_T*14`($sp)
++	$PUSH	r19,`$FRAME-$SIZE_T*13`($sp)
++	$PUSH	r20,`$FRAME-$SIZE_T*12`($sp)
++	$PUSH	r21,`$FRAME-$SIZE_T*11`($sp)
++	$PUSH	r22,`$FRAME-$SIZE_T*10`($sp)
++	$PUSH	r23,`$FRAME-$SIZE_T*9`($sp)
++	$PUSH	r24,`$FRAME-$SIZE_T*8`($sp)
++	$PUSH	r25,`$FRAME-$SIZE_T*7`($sp)
++	$PUSH	r26,`$FRAME-$SIZE_T*6`($sp)
++	$PUSH	r27,`$FRAME-$SIZE_T*5`($sp)
++	$PUSH	r28,`$FRAME-$SIZE_T*4`($sp)
++	$PUSH	r29,`$FRAME-$SIZE_T*3`($sp)
++	$PUSH	r30,`$FRAME-$SIZE_T*2`($sp)
++	$PUSH	r31,`$FRAME-$SIZE_T*1`($sp)
++	$PUSH	r0,`$FRAME+$LRSAVE`($sp)
++
++	andi.	$t0,$inp,3
++	andi.	$t1,$out,3
++	or.	$t0,$t0,$t1
++	bne	Lenc_unaligned
++
++Lenc_unaligned_ok:
++___
++$code.=<<___ if (!$LITTLE_ENDIAN);
++	lwz	$s0,0($inp)
++	lwz	$s1,4($inp)
++	lwz	$s2,8($inp)
++	lwz	$s3,12($inp)
++___
++$code.=<<___ if ($LITTLE_ENDIAN);
++	lwz	$t0,0($inp)
++	lwz	$t1,4($inp)
++	lwz	$t2,8($inp)
++	lwz	$t3,12($inp)
++	rotlwi	$s0,$t0,8
++	rotlwi	$s1,$t1,8
++	rotlwi	$s2,$t2,8
++	rotlwi	$s3,$t3,8
++	rlwimi	$s0,$t0,24,0,7
++	rlwimi	$s1,$t1,24,0,7
++	rlwimi	$s2,$t2,24,0,7
++	rlwimi	$s3,$t3,24,0,7
++	rlwimi	$s0,$t0,24,16,23
++	rlwimi	$s1,$t1,24,16,23
++	rlwimi	$s2,$t2,24,16,23
++	rlwimi	$s3,$t3,24,16,23
++___
++$code.=<<___;
++	bl	LAES_Te
++	bl	Lppc_AES_encrypt_compact
++	$POP	$out,`$FRAME-$SIZE_T*19`($sp)
++___
++$code.=<<___ if ($LITTLE_ENDIAN);
++	rotlwi	$t0,$s0,8
++	rotlwi	$t1,$s1,8
++	rotlwi	$t2,$s2,8
++	rotlwi	$t3,$s3,8
++	rlwimi	$t0,$s0,24,0,7
++	rlwimi	$t1,$s1,24,0,7
++	rlwimi	$t2,$s2,24,0,7
++	rlwimi	$t3,$s3,24,0,7
++	rlwimi	$t0,$s0,24,16,23
++	rlwimi	$t1,$s1,24,16,23
++	rlwimi	$t2,$s2,24,16,23
++	rlwimi	$t3,$s3,24,16,23
++	stw	$t0,0($out)
++	stw	$t1,4($out)
++	stw	$t2,8($out)
++	stw	$t3,12($out)
++___
++$code.=<<___ if (!$LITTLE_ENDIAN);
++	stw	$s0,0($out)
++	stw	$s1,4($out)
++	stw	$s2,8($out)
++	stw	$s3,12($out)
++___
++$code.=<<___;
++	b	Lenc_done
++
++Lenc_unaligned:
++	subfic	$t0,$inp,4096
++	subfic	$t1,$out,4096
++	andi.	$t0,$t0,4096-16
++	beq	Lenc_xpage
++	andi.	$t1,$t1,4096-16
++	bne	Lenc_unaligned_ok
++
++Lenc_xpage:
++	lbz	$acc00,0($inp)
++	lbz	$acc01,1($inp)
++	lbz	$acc02,2($inp)
++	lbz	$s0,3($inp)
++	lbz	$acc04,4($inp)
++	lbz	$acc05,5($inp)
++	lbz	$acc06,6($inp)
++	lbz	$s1,7($inp)
++	lbz	$acc08,8($inp)
++	lbz	$acc09,9($inp)
++	lbz	$acc10,10($inp)
++	insrwi	$s0,$acc00,8,0
++	lbz	$s2,11($inp)
++	insrwi	$s1,$acc04,8,0
++	lbz	$acc12,12($inp)
++	insrwi	$s0,$acc01,8,8
++	lbz	$acc13,13($inp)
++	insrwi	$s1,$acc05,8,8
++	lbz	$acc14,14($inp)
++	insrwi	$s0,$acc02,8,16
++	lbz	$s3,15($inp)
++	insrwi	$s1,$acc06,8,16
++	insrwi	$s2,$acc08,8,0
++	insrwi	$s3,$acc12,8,0
++	insrwi	$s2,$acc09,8,8
++	insrwi	$s3,$acc13,8,8
++	insrwi	$s2,$acc10,8,16
++	insrwi	$s3,$acc14,8,16
++
++	bl	LAES_Te
++	bl	Lppc_AES_encrypt_compact
++	$POP	$out,`$FRAME-$SIZE_T*19`($sp)
++
++	extrwi	$acc00,$s0,8,0
++	extrwi	$acc01,$s0,8,8
++	stb	$acc00,0($out)
++	extrwi	$acc02,$s0,8,16
++	stb	$acc01,1($out)
++	stb	$acc02,2($out)
++	extrwi	$acc04,$s1,8,0
++	stb	$s0,3($out)
++	extrwi	$acc05,$s1,8,8
++	stb	$acc04,4($out)
++	extrwi	$acc06,$s1,8,16
++	stb	$acc05,5($out)
++	stb	$acc06,6($out)
++	extrwi	$acc08,$s2,8,0
++	stb	$s1,7($out)
++	extrwi	$acc09,$s2,8,8
++	stb	$acc08,8($out)
++	extrwi	$acc10,$s2,8,16
++	stb	$acc09,9($out)
++	stb	$acc10,10($out)
++	extrwi	$acc12,$s3,8,0
++	stb	$s2,11($out)
++	extrwi	$acc13,$s3,8,8
++	stb	$acc12,12($out)
++	extrwi	$acc14,$s3,8,16
++	stb	$acc13,13($out)
++	stb	$acc14,14($out)
++	stb	$s3,15($out)
++
++Lenc_done:
++	$POP	r0,`$FRAME+$LRSAVE`($sp)
++	$POP	r14,`$FRAME-$SIZE_T*18`($sp)
++	$POP	r15,`$FRAME-$SIZE_T*17`($sp)
++	$POP	r16,`$FRAME-$SIZE_T*16`($sp)
++	$POP	r17,`$FRAME-$SIZE_T*15`($sp)
++	$POP	r18,`$FRAME-$SIZE_T*14`($sp)
++	$POP	r19,`$FRAME-$SIZE_T*13`($sp)
++	$POP	r20,`$FRAME-$SIZE_T*12`($sp)
++	$POP	r21,`$FRAME-$SIZE_T*11`($sp)
++	$POP	r22,`$FRAME-$SIZE_T*10`($sp)
++	$POP	r23,`$FRAME-$SIZE_T*9`($sp)
++	$POP	r24,`$FRAME-$SIZE_T*8`($sp)
++	$POP	r25,`$FRAME-$SIZE_T*7`($sp)
++	$POP	r26,`$FRAME-$SIZE_T*6`($sp)
++	$POP	r27,`$FRAME-$SIZE_T*5`($sp)
++	$POP	r28,`$FRAME-$SIZE_T*4`($sp)
++	$POP	r29,`$FRAME-$SIZE_T*3`($sp)
++	$POP	r30,`$FRAME-$SIZE_T*2`($sp)
++	$POP	r31,`$FRAME-$SIZE_T*1`($sp)
++	mtlr	r0
++	addi	$sp,$sp,$FRAME
++	blr
++	.long	0
++	.byte	0,12,4,1,0x80,18,3,0
++	.long	0
++
++.align	5
++Lppc_AES_encrypt:
++	lwz	$acc00,240($key)
++	addi	$Tbl1,$Tbl0,3
++	lwz	$t0,0($key)
++	addi	$Tbl2,$Tbl0,2
++	lwz	$t1,4($key)
++	addi	$Tbl3,$Tbl0,1
++	lwz	$t2,8($key)
++	addi	$acc00,$acc00,-1
++	lwz	$t3,12($key)
++	addi	$key,$key,16
++	xor	$s0,$s0,$t0
++	xor	$s1,$s1,$t1
++	xor	$s2,$s2,$t2
++	xor	$s3,$s3,$t3
++	mtctr	$acc00
++.align	4
++Lenc_loop:
++	rlwinm	$acc00,$s0,`32-24+3`,21,28
++	rlwinm	$acc01,$s1,`32-24+3`,21,28
++	rlwinm	$acc02,$s2,`32-24+3`,21,28
++	rlwinm	$acc03,$s3,`32-24+3`,21,28
++	lwz	$t0,0($key)
++	rlwinm	$acc04,$s1,`32-16+3`,21,28
++	lwz	$t1,4($key)
++	rlwinm	$acc05,$s2,`32-16+3`,21,28
++	lwz	$t2,8($key)
++	rlwinm	$acc06,$s3,`32-16+3`,21,28
++	lwz	$t3,12($key)
++	rlwinm	$acc07,$s0,`32-16+3`,21,28
++	lwzx	$acc00,$Tbl0,$acc00
++	rlwinm	$acc08,$s2,`32-8+3`,21,28
++	lwzx	$acc01,$Tbl0,$acc01
++	rlwinm	$acc09,$s3,`32-8+3`,21,28
++	lwzx	$acc02,$Tbl0,$acc02
++	rlwinm	$acc10,$s0,`32-8+3`,21,28
++	lwzx	$acc03,$Tbl0,$acc03
++	rlwinm	$acc11,$s1,`32-8+3`,21,28
++	lwzx	$acc04,$Tbl1,$acc04
++	rlwinm	$acc12,$s3,`0+3`,21,28
++	lwzx	$acc05,$Tbl1,$acc05
++	rlwinm	$acc13,$s0,`0+3`,21,28
++	lwzx	$acc06,$Tbl1,$acc06
++	rlwinm	$acc14,$s1,`0+3`,21,28
++	lwzx	$acc07,$Tbl1,$acc07
++	rlwinm	$acc15,$s2,`0+3`,21,28
++	lwzx	$acc08,$Tbl2,$acc08
++	xor	$t0,$t0,$acc00
++	lwzx	$acc09,$Tbl2,$acc09
++	xor	$t1,$t1,$acc01
++	lwzx	$acc10,$Tbl2,$acc10
++	xor	$t2,$t2,$acc02
++	lwzx	$acc11,$Tbl2,$acc11
++	xor	$t3,$t3,$acc03
++	lwzx	$acc12,$Tbl3,$acc12
++	xor	$t0,$t0,$acc04
++	lwzx	$acc13,$Tbl3,$acc13
++	xor	$t1,$t1,$acc05
++	lwzx	$acc14,$Tbl3,$acc14
++	xor	$t2,$t2,$acc06
++	lwzx	$acc15,$Tbl3,$acc15
++	xor	$t3,$t3,$acc07
++	xor	$t0,$t0,$acc08
++	xor	$t1,$t1,$acc09
++	xor	$t2,$t2,$acc10
++	xor	$t3,$t3,$acc11
++	xor	$s0,$t0,$acc12
++	xor	$s1,$t1,$acc13
++	xor	$s2,$t2,$acc14
++	xor	$s3,$t3,$acc15
++	addi	$key,$key,16
++	bdnz	Lenc_loop
++
++	addi	$Tbl2,$Tbl0,2048
++	nop
++	lwz	$t0,0($key)
++	rlwinm	$acc00,$s0,`32-24`,24,31
++	lwz	$t1,4($key)
++	rlwinm	$acc01,$s1,`32-24`,24,31
++	lwz	$t2,8($key)
++	rlwinm	$acc02,$s2,`32-24`,24,31
++	lwz	$t3,12($key)
++	rlwinm	$acc03,$s3,`32-24`,24,31
++	lwz	$acc08,`2048+0`($Tbl0)	! prefetch Te4
++	rlwinm	$acc04,$s1,`32-16`,24,31
++	lwz	$acc09,`2048+32`($Tbl0)
++	rlwinm	$acc05,$s2,`32-16`,24,31
++	lwz	$acc10,`2048+64`($Tbl0)
++	rlwinm	$acc06,$s3,`32-16`,24,31
++	lwz	$acc11,`2048+96`($Tbl0)
++	rlwinm	$acc07,$s0,`32-16`,24,31
++	lwz	$acc12,`2048+128`($Tbl0)
++	rlwinm	$acc08,$s2,`32-8`,24,31
++	lwz	$acc13,`2048+160`($Tbl0)
++	rlwinm	$acc09,$s3,`32-8`,24,31
++	lwz	$acc14,`2048+192`($Tbl0)
++	rlwinm	$acc10,$s0,`32-8`,24,31
++	lwz	$acc15,`2048+224`($Tbl0)
++	rlwinm	$acc11,$s1,`32-8`,24,31
++	lbzx	$acc00,$Tbl2,$acc00
++	rlwinm	$acc12,$s3,`0`,24,31
++	lbzx	$acc01,$Tbl2,$acc01
++	rlwinm	$acc13,$s0,`0`,24,31
++	lbzx	$acc02,$Tbl2,$acc02
++	rlwinm	$acc14,$s1,`0`,24,31
++	lbzx	$acc03,$Tbl2,$acc03
++	rlwinm	$acc15,$s2,`0`,24,31
++	lbzx	$acc04,$Tbl2,$acc04
++	rlwinm	$s0,$acc00,24,0,7
++	lbzx	$acc05,$Tbl2,$acc05
++	rlwinm	$s1,$acc01,24,0,7
++	lbzx	$acc06,$Tbl2,$acc06
++	rlwinm	$s2,$acc02,24,0,7
++	lbzx	$acc07,$Tbl2,$acc07
++	rlwinm	$s3,$acc03,24,0,7
++	lbzx	$acc08,$Tbl2,$acc08
++	rlwimi	$s0,$acc04,16,8,15
++	lbzx	$acc09,$Tbl2,$acc09
++	rlwimi	$s1,$acc05,16,8,15
++	lbzx	$acc10,$Tbl2,$acc10
++	rlwimi	$s2,$acc06,16,8,15
++	lbzx	$acc11,$Tbl2,$acc11
++	rlwimi	$s3,$acc07,16,8,15
++	lbzx	$acc12,$Tbl2,$acc12
++	rlwimi	$s0,$acc08,8,16,23
++	lbzx	$acc13,$Tbl2,$acc13
++	rlwimi	$s1,$acc09,8,16,23
++	lbzx	$acc14,$Tbl2,$acc14
++	rlwimi	$s2,$acc10,8,16,23
++	lbzx	$acc15,$Tbl2,$acc15
++	rlwimi	$s3,$acc11,8,16,23
++	or	$s0,$s0,$acc12
++	or	$s1,$s1,$acc13
++	or	$s2,$s2,$acc14
++	or	$s3,$s3,$acc15
++	xor	$s0,$s0,$t0
++	xor	$s1,$s1,$t1
++	xor	$s2,$s2,$t2
++	xor	$s3,$s3,$t3
++	blr
++	.long	0
++	.byte	0,12,0x14,0,0,0,0,0
++
++.align	4
++Lppc_AES_encrypt_compact:
++	lwz	$acc00,240($key)
++	addi	$Tbl1,$Tbl0,2048
++	lwz	$t0,0($key)
++	lis	$mask80,0x8080
++	lwz	$t1,4($key)
++	lis	$mask1b,0x1b1b
++	lwz	$t2,8($key)
++	ori	$mask80,$mask80,0x8080
++	lwz	$t3,12($key)
++	ori	$mask1b,$mask1b,0x1b1b
++	addi	$key,$key,16
++	mtctr	$acc00
++.align	4
++Lenc_compact_loop:
++	xor	$s0,$s0,$t0
++	xor	$s1,$s1,$t1
++	rlwinm	$acc00,$s0,`32-24`,24,31
++	xor	$s2,$s2,$t2
++	rlwinm	$acc01,$s1,`32-24`,24,31
++	xor	$s3,$s3,$t3
++	rlwinm	$acc02,$s2,`32-24`,24,31
++	rlwinm	$acc03,$s3,`32-24`,24,31
++	rlwinm	$acc04,$s1,`32-16`,24,31
++	rlwinm	$acc05,$s2,`32-16`,24,31
++	rlwinm	$acc06,$s3,`32-16`,24,31
++	rlwinm	$acc07,$s0,`32-16`,24,31
++	lbzx	$acc00,$Tbl1,$acc00
++	rlwinm	$acc08,$s2,`32-8`,24,31
++	lbzx	$acc01,$Tbl1,$acc01
++	rlwinm	$acc09,$s3,`32-8`,24,31
++	lbzx	$acc02,$Tbl1,$acc02
++	rlwinm	$acc10,$s0,`32-8`,24,31
++	lbzx	$acc03,$Tbl1,$acc03
++	rlwinm	$acc11,$s1,`32-8`,24,31
++	lbzx	$acc04,$Tbl1,$acc04
++	rlwinm	$acc12,$s3,`0`,24,31
++	lbzx	$acc05,$Tbl1,$acc05
++	rlwinm	$acc13,$s0,`0`,24,31
++	lbzx	$acc06,$Tbl1,$acc06
++	rlwinm	$acc14,$s1,`0`,24,31
++	lbzx	$acc07,$Tbl1,$acc07
++	rlwinm	$acc15,$s2,`0`,24,31
++	lbzx	$acc08,$Tbl1,$acc08
++	rlwinm	$s0,$acc00,24,0,7
++	lbzx	$acc09,$Tbl1,$acc09
++	rlwinm	$s1,$acc01,24,0,7
++	lbzx	$acc10,$Tbl1,$acc10
++	rlwinm	$s2,$acc02,24,0,7
++	lbzx	$acc11,$Tbl1,$acc11
++	rlwinm	$s3,$acc03,24,0,7
++	lbzx	$acc12,$Tbl1,$acc12
++	rlwimi	$s0,$acc04,16,8,15
++	lbzx	$acc13,$Tbl1,$acc13
++	rlwimi	$s1,$acc05,16,8,15
++	lbzx	$acc14,$Tbl1,$acc14
++	rlwimi	$s2,$acc06,16,8,15
++	lbzx	$acc15,$Tbl1,$acc15
++	rlwimi	$s3,$acc07,16,8,15
++	rlwimi	$s0,$acc08,8,16,23
++	rlwimi	$s1,$acc09,8,16,23
++	rlwimi	$s2,$acc10,8,16,23
++	rlwimi	$s3,$acc11,8,16,23
++	lwz	$t0,0($key)
++	or	$s0,$s0,$acc12
++	lwz	$t1,4($key)
++	or	$s1,$s1,$acc13
++	lwz	$t2,8($key)
++	or	$s2,$s2,$acc14
++	lwz	$t3,12($key)
++	or	$s3,$s3,$acc15
++
++	addi	$key,$key,16
++	bdz	Lenc_compact_done
++
++	and	$acc00,$s0,$mask80	# r1=r0&0x80808080
++	and	$acc01,$s1,$mask80
++	and	$acc02,$s2,$mask80
++	and	$acc03,$s3,$mask80
++	srwi	$acc04,$acc00,7		# r1>>7
++	andc	$acc08,$s0,$mask80	# r0&0x7f7f7f7f
++	srwi	$acc05,$acc01,7
++	andc	$acc09,$s1,$mask80
++	srwi	$acc06,$acc02,7
++	andc	$acc10,$s2,$mask80
++	srwi	$acc07,$acc03,7
++	andc	$acc11,$s3,$mask80
++	sub	$acc00,$acc00,$acc04	# r1-(r1>>7)
++	sub	$acc01,$acc01,$acc05
++	sub	$acc02,$acc02,$acc06
++	sub	$acc03,$acc03,$acc07
++	add	$acc08,$acc08,$acc08	# (r0&0x7f7f7f7f)<<1
++	add	$acc09,$acc09,$acc09
++	add	$acc10,$acc10,$acc10
++	add	$acc11,$acc11,$acc11
++	and	$acc00,$acc00,$mask1b	# (r1-(r1>>7))&0x1b1b1b1b
++	and	$acc01,$acc01,$mask1b
++	and	$acc02,$acc02,$mask1b
++	and	$acc03,$acc03,$mask1b
++	xor	$acc00,$acc00,$acc08	# r2
++	xor	$acc01,$acc01,$acc09
++	 rotlwi	$acc12,$s0,16		# ROTATE(r0,16)
++	xor	$acc02,$acc02,$acc10
++	 rotlwi	$acc13,$s1,16
++	xor	$acc03,$acc03,$acc11
++	 rotlwi	$acc14,$s2,16
++
++	xor	$s0,$s0,$acc00		# r0^r2
++	rotlwi	$acc15,$s3,16
++	xor	$s1,$s1,$acc01
++	rotrwi	$s0,$s0,24		# ROTATE(r2^r0,24)
++	xor	$s2,$s2,$acc02
++	rotrwi	$s1,$s1,24
++	xor	$s3,$s3,$acc03
++	rotrwi	$s2,$s2,24
++	xor	$s0,$s0,$acc00		# ROTATE(r2^r0,24)^r2
++	rotrwi	$s3,$s3,24
++	xor	$s1,$s1,$acc01
++	xor	$s2,$s2,$acc02
++	xor	$s3,$s3,$acc03
++	rotlwi	$acc08,$acc12,8		# ROTATE(r0,24)
++	xor	$s0,$s0,$acc12		#
++	rotlwi	$acc09,$acc13,8
++	xor	$s1,$s1,$acc13
++	rotlwi	$acc10,$acc14,8
++	xor	$s2,$s2,$acc14
++	rotlwi	$acc11,$acc15,8
++	xor	$s3,$s3,$acc15
++	xor	$s0,$s0,$acc08		#
++	xor	$s1,$s1,$acc09
++	xor	$s2,$s2,$acc10
++	xor	$s3,$s3,$acc11
++
++	b	Lenc_compact_loop
++.align	4
++Lenc_compact_done:
++	xor	$s0,$s0,$t0
++	xor	$s1,$s1,$t1
++	xor	$s2,$s2,$t2
++	xor	$s3,$s3,$t3
++	blr
++	.long	0
++	.byte	0,12,0x14,0,0,0,0,0
++.size	.AES_encrypt,.-.AES_encrypt
++
++.globl	.AES_decrypt
++.align	7
++.AES_decrypt:
++	$STU	$sp,-$FRAME($sp)
++	mflr	r0
++
++	$PUSH	$out,`$FRAME-$SIZE_T*19`($sp)
++	$PUSH	r14,`$FRAME-$SIZE_T*18`($sp)
++	$PUSH	r15,`$FRAME-$SIZE_T*17`($sp)
++	$PUSH	r16,`$FRAME-$SIZE_T*16`($sp)
++	$PUSH	r17,`$FRAME-$SIZE_T*15`($sp)
++	$PUSH	r18,`$FRAME-$SIZE_T*14`($sp)
++	$PUSH	r19,`$FRAME-$SIZE_T*13`($sp)
++	$PUSH	r20,`$FRAME-$SIZE_T*12`($sp)
++	$PUSH	r21,`$FRAME-$SIZE_T*11`($sp)
++	$PUSH	r22,`$FRAME-$SIZE_T*10`($sp)
++	$PUSH	r23,`$FRAME-$SIZE_T*9`($sp)
++	$PUSH	r24,`$FRAME-$SIZE_T*8`($sp)
++	$PUSH	r25,`$FRAME-$SIZE_T*7`($sp)
++	$PUSH	r26,`$FRAME-$SIZE_T*6`($sp)
++	$PUSH	r27,`$FRAME-$SIZE_T*5`($sp)
++	$PUSH	r28,`$FRAME-$SIZE_T*4`($sp)
++	$PUSH	r29,`$FRAME-$SIZE_T*3`($sp)
++	$PUSH	r30,`$FRAME-$SIZE_T*2`($sp)
++	$PUSH	r31,`$FRAME-$SIZE_T*1`($sp)
++	$PUSH	r0,`$FRAME+$LRSAVE`($sp)
++
++	andi.	$t0,$inp,3
++	andi.	$t1,$out,3
++	or.	$t0,$t0,$t1
++	bne	Ldec_unaligned
++
++Ldec_unaligned_ok:
++___
++$code.=<<___ if (!$LITTLE_ENDIAN);
++	lwz	$s0,0($inp)
++	lwz	$s1,4($inp)
++	lwz	$s2,8($inp)
++	lwz	$s3,12($inp)
++___
++$code.=<<___ if ($LITTLE_ENDIAN);
++	lwz	$t0,0($inp)
++	lwz	$t1,4($inp)
++	lwz	$t2,8($inp)
++	lwz	$t3,12($inp)
++	rotlwi	$s0,$t0,8
++	rotlwi	$s1,$t1,8
++	rotlwi	$s2,$t2,8
++	rotlwi	$s3,$t3,8
++	rlwimi	$s0,$t0,24,0,7
++	rlwimi	$s1,$t1,24,0,7
++	rlwimi	$s2,$t2,24,0,7
++	rlwimi	$s3,$t3,24,0,7
++	rlwimi	$s0,$t0,24,16,23
++	rlwimi	$s1,$t1,24,16,23
++	rlwimi	$s2,$t2,24,16,23
++	rlwimi	$s3,$t3,24,16,23
++___
++$code.=<<___;
++	bl	LAES_Td
++	bl	Lppc_AES_decrypt_compact
++	$POP	$out,`$FRAME-$SIZE_T*19`($sp)
++___
++$code.=<<___ if ($LITTLE_ENDIAN);
++	rotlwi	$t0,$s0,8
++	rotlwi	$t1,$s1,8
++	rotlwi	$t2,$s2,8
++	rotlwi	$t3,$s3,8
++	rlwimi	$t0,$s0,24,0,7
++	rlwimi	$t1,$s1,24,0,7
++	rlwimi	$t2,$s2,24,0,7
++	rlwimi	$t3,$s3,24,0,7
++	rlwimi	$t0,$s0,24,16,23
++	rlwimi	$t1,$s1,24,16,23
++	rlwimi	$t2,$s2,24,16,23
++	rlwimi	$t3,$s3,24,16,23
++	stw	$t0,0($out)
++	stw	$t1,4($out)
++	stw	$t2,8($out)
++	stw	$t3,12($out)
++___
++$code.=<<___ if (!$LITTLE_ENDIAN);
++	stw	$s0,0($out)
++	stw	$s1,4($out)
++	stw	$s2,8($out)
++	stw	$s3,12($out)
++___
++$code.=<<___;
++	b	Ldec_done
++
++Ldec_unaligned:
++	subfic	$t0,$inp,4096
++	subfic	$t1,$out,4096
++	andi.	$t0,$t0,4096-16
++	beq	Ldec_xpage
++	andi.	$t1,$t1,4096-16
++	bne	Ldec_unaligned_ok
++
++Ldec_xpage:
++	lbz	$acc00,0($inp)
++	lbz	$acc01,1($inp)
++	lbz	$acc02,2($inp)
++	lbz	$s0,3($inp)
++	lbz	$acc04,4($inp)
++	lbz	$acc05,5($inp)
++	lbz	$acc06,6($inp)
++	lbz	$s1,7($inp)
++	lbz	$acc08,8($inp)
++	lbz	$acc09,9($inp)
++	lbz	$acc10,10($inp)
++	insrwi	$s0,$acc00,8,0
++	lbz	$s2,11($inp)
++	insrwi	$s1,$acc04,8,0
++	lbz	$acc12,12($inp)
++	insrwi	$s0,$acc01,8,8
++	lbz	$acc13,13($inp)
++	insrwi	$s1,$acc05,8,8
++	lbz	$acc14,14($inp)
++	insrwi	$s0,$acc02,8,16
++	lbz	$s3,15($inp)
++	insrwi	$s1,$acc06,8,16
++	insrwi	$s2,$acc08,8,0
++	insrwi	$s3,$acc12,8,0
++	insrwi	$s2,$acc09,8,8
++	insrwi	$s3,$acc13,8,8
++	insrwi	$s2,$acc10,8,16
++	insrwi	$s3,$acc14,8,16
++
++	bl	LAES_Td
++	bl	Lppc_AES_decrypt_compact
++	$POP	$out,`$FRAME-$SIZE_T*19`($sp)
++
++	extrwi	$acc00,$s0,8,0
++	extrwi	$acc01,$s0,8,8
++	stb	$acc00,0($out)
++	extrwi	$acc02,$s0,8,16
++	stb	$acc01,1($out)
++	stb	$acc02,2($out)
++	extrwi	$acc04,$s1,8,0
++	stb	$s0,3($out)
++	extrwi	$acc05,$s1,8,8
++	stb	$acc04,4($out)
++	extrwi	$acc06,$s1,8,16
++	stb	$acc05,5($out)
++	stb	$acc06,6($out)
++	extrwi	$acc08,$s2,8,0
++	stb	$s1,7($out)
++	extrwi	$acc09,$s2,8,8
++	stb	$acc08,8($out)
++	extrwi	$acc10,$s2,8,16
++	stb	$acc09,9($out)
++	stb	$acc10,10($out)
++	extrwi	$acc12,$s3,8,0
++	stb	$s2,11($out)
++	extrwi	$acc13,$s3,8,8
++	stb	$acc12,12($out)
++	extrwi	$acc14,$s3,8,16
++	stb	$acc13,13($out)
++	stb	$acc14,14($out)
++	stb	$s3,15($out)
++
++Ldec_done:
++	$POP	r0,`$FRAME+$LRSAVE`($sp)
++	$POP	r14,`$FRAME-$SIZE_T*18`($sp)
++	$POP	r15,`$FRAME-$SIZE_T*17`($sp)
++	$POP	r16,`$FRAME-$SIZE_T*16`($sp)
++	$POP	r17,`$FRAME-$SIZE_T*15`($sp)
++	$POP	r18,`$FRAME-$SIZE_T*14`($sp)
++	$POP	r19,`$FRAME-$SIZE_T*13`($sp)
++	$POP	r20,`$FRAME-$SIZE_T*12`($sp)
++	$POP	r21,`$FRAME-$SIZE_T*11`($sp)
++	$POP	r22,`$FRAME-$SIZE_T*10`($sp)
++	$POP	r23,`$FRAME-$SIZE_T*9`($sp)
++	$POP	r24,`$FRAME-$SIZE_T*8`($sp)
++	$POP	r25,`$FRAME-$SIZE_T*7`($sp)
++	$POP	r26,`$FRAME-$SIZE_T*6`($sp)
++	$POP	r27,`$FRAME-$SIZE_T*5`($sp)
++	$POP	r28,`$FRAME-$SIZE_T*4`($sp)
++	$POP	r29,`$FRAME-$SIZE_T*3`($sp)
++	$POP	r30,`$FRAME-$SIZE_T*2`($sp)
++	$POP	r31,`$FRAME-$SIZE_T*1`($sp)
++	mtlr	r0
++	addi	$sp,$sp,$FRAME
++	blr
++	.long	0
++	.byte	0,12,4,1,0x80,18,3,0
++	.long	0
++
++.align	5
++Lppc_AES_decrypt:
++	lwz	$acc00,240($key)
++	addi	$Tbl1,$Tbl0,3
++	lwz	$t0,0($key)
++	addi	$Tbl2,$Tbl0,2
++	lwz	$t1,4($key)
++	addi	$Tbl3,$Tbl0,1
++	lwz	$t2,8($key)
++	addi	$acc00,$acc00,-1
++	lwz	$t3,12($key)
++	addi	$key,$key,16
++	xor	$s0,$s0,$t0
++	xor	$s1,$s1,$t1
++	xor	$s2,$s2,$t2
++	xor	$s3,$s3,$t3
++	mtctr	$acc00
++.align	4
++Ldec_loop:
++	rlwinm	$acc00,$s0,`32-24+3`,21,28
++	rlwinm	$acc01,$s1,`32-24+3`,21,28
++	rlwinm	$acc02,$s2,`32-24+3`,21,28
++	rlwinm	$acc03,$s3,`32-24+3`,21,28
++	lwz	$t0,0($key)
++	rlwinm	$acc04,$s3,`32-16+3`,21,28
++	lwz	$t1,4($key)
++	rlwinm	$acc05,$s0,`32-16+3`,21,28
++	lwz	$t2,8($key)
++	rlwinm	$acc06,$s1,`32-16+3`,21,28
++	lwz	$t3,12($key)
++	rlwinm	$acc07,$s2,`32-16+3`,21,28
++	lwzx	$acc00,$Tbl0,$acc00
++	rlwinm	$acc08,$s2,`32-8+3`,21,28
++	lwzx	$acc01,$Tbl0,$acc01
++	rlwinm	$acc09,$s3,`32-8+3`,21,28
++	lwzx	$acc02,$Tbl0,$acc02
++	rlwinm	$acc10,$s0,`32-8+3`,21,28
++	lwzx	$acc03,$Tbl0,$acc03
++	rlwinm	$acc11,$s1,`32-8+3`,21,28
++	lwzx	$acc04,$Tbl1,$acc04
++	rlwinm	$acc12,$s1,`0+3`,21,28
++	lwzx	$acc05,$Tbl1,$acc05
++	rlwinm	$acc13,$s2,`0+3`,21,28
++	lwzx	$acc06,$Tbl1,$acc06
++	rlwinm	$acc14,$s3,`0+3`,21,28
++	lwzx	$acc07,$Tbl1,$acc07
++	rlwinm	$acc15,$s0,`0+3`,21,28
++	lwzx	$acc08,$Tbl2,$acc08
++	xor	$t0,$t0,$acc00
++	lwzx	$acc09,$Tbl2,$acc09
++	xor	$t1,$t1,$acc01
++	lwzx	$acc10,$Tbl2,$acc10
++	xor	$t2,$t2,$acc02
++	lwzx	$acc11,$Tbl2,$acc11
++	xor	$t3,$t3,$acc03
++	lwzx	$acc12,$Tbl3,$acc12
++	xor	$t0,$t0,$acc04
++	lwzx	$acc13,$Tbl3,$acc13
++	xor	$t1,$t1,$acc05
++	lwzx	$acc14,$Tbl3,$acc14
++	xor	$t2,$t2,$acc06
++	lwzx	$acc15,$Tbl3,$acc15
++	xor	$t3,$t3,$acc07
++	xor	$t0,$t0,$acc08
++	xor	$t1,$t1,$acc09
++	xor	$t2,$t2,$acc10
++	xor	$t3,$t3,$acc11
++	xor	$s0,$t0,$acc12
++	xor	$s1,$t1,$acc13
++	xor	$s2,$t2,$acc14
++	xor	$s3,$t3,$acc15
++	addi	$key,$key,16
++	bdnz	Ldec_loop
++
++	addi	$Tbl2,$Tbl0,2048
++	nop
++	lwz	$t0,0($key)
++	rlwinm	$acc00,$s0,`32-24`,24,31
++	lwz	$t1,4($key)
++	rlwinm	$acc01,$s1,`32-24`,24,31
++	lwz	$t2,8($key)
++	rlwinm	$acc02,$s2,`32-24`,24,31
++	lwz	$t3,12($key)
++	rlwinm	$acc03,$s3,`32-24`,24,31
++	lwz	$acc08,`2048+0`($Tbl0)	! prefetch Td4
++	rlwinm	$acc04,$s3,`32-16`,24,31
++	lwz	$acc09,`2048+32`($Tbl0)
++	rlwinm	$acc05,$s0,`32-16`,24,31
++	lwz	$acc10,`2048+64`($Tbl0)
++	lbzx	$acc00,$Tbl2,$acc00
++	lwz	$acc11,`2048+96`($Tbl0)
++	lbzx	$acc01,$Tbl2,$acc01
++	lwz	$acc12,`2048+128`($Tbl0)
++	rlwinm	$acc06,$s1,`32-16`,24,31
++	lwz	$acc13,`2048+160`($Tbl0)
++	rlwinm	$acc07,$s2,`32-16`,24,31
++	lwz	$acc14,`2048+192`($Tbl0)
++	rlwinm	$acc08,$s2,`32-8`,24,31
++	lwz	$acc15,`2048+224`($Tbl0)
++	rlwinm	$acc09,$s3,`32-8`,24,31
++	lbzx	$acc02,$Tbl2,$acc02
++	rlwinm	$acc10,$s0,`32-8`,24,31
++	lbzx	$acc03,$Tbl2,$acc03
++	rlwinm	$acc11,$s1,`32-8`,24,31
++	lbzx	$acc04,$Tbl2,$acc04
++	rlwinm	$acc12,$s1,`0`,24,31
++	lbzx	$acc05,$Tbl2,$acc05
++	rlwinm	$acc13,$s2,`0`,24,31
++	lbzx	$acc06,$Tbl2,$acc06
++	rlwinm	$acc14,$s3,`0`,24,31
++	lbzx	$acc07,$Tbl2,$acc07
++	rlwinm	$acc15,$s0,`0`,24,31
++	lbzx	$acc08,$Tbl2,$acc08
++	rlwinm	$s0,$acc00,24,0,7
++	lbzx	$acc09,$Tbl2,$acc09
++	rlwinm	$s1,$acc01,24,0,7
++	lbzx	$acc10,$Tbl2,$acc10
++	rlwinm	$s2,$acc02,24,0,7
++	lbzx	$acc11,$Tbl2,$acc11
++	rlwinm	$s3,$acc03,24,0,7
++	lbzx	$acc12,$Tbl2,$acc12
++	rlwimi	$s0,$acc04,16,8,15
++	lbzx	$acc13,$Tbl2,$acc13
++	rlwimi	$s1,$acc05,16,8,15
++	lbzx	$acc14,$Tbl2,$acc14
++	rlwimi	$s2,$acc06,16,8,15
++	lbzx	$acc15,$Tbl2,$acc15
++	rlwimi	$s3,$acc07,16,8,15
++	rlwimi	$s0,$acc08,8,16,23
++	rlwimi	$s1,$acc09,8,16,23
++	rlwimi	$s2,$acc10,8,16,23
++	rlwimi	$s3,$acc11,8,16,23
++	or	$s0,$s0,$acc12
++	or	$s1,$s1,$acc13
++	or	$s2,$s2,$acc14
++	or	$s3,$s3,$acc15
++	xor	$s0,$s0,$t0
++	xor	$s1,$s1,$t1
++	xor	$s2,$s2,$t2
++	xor	$s3,$s3,$t3
++	blr
++	.long	0
++	.byte	0,12,0x14,0,0,0,0,0
++
++.align	4
++Lppc_AES_decrypt_compact:
++	lwz	$acc00,240($key)
++	addi	$Tbl1,$Tbl0,2048
++	lwz	$t0,0($key)
++	lis	$mask80,0x8080
++	lwz	$t1,4($key)
++	lis	$mask1b,0x1b1b
++	lwz	$t2,8($key)
++	ori	$mask80,$mask80,0x8080
++	lwz	$t3,12($key)
++	ori	$mask1b,$mask1b,0x1b1b
++	addi	$key,$key,16
++___
++$code.=<<___ if ($SIZE_T==8);
++	insrdi	$mask80,$mask80,32,0
++	insrdi	$mask1b,$mask1b,32,0
++___
++$code.=<<___;
++	mtctr	$acc00
++.align	4
++Ldec_compact_loop:
++	xor	$s0,$s0,$t0
++	xor	$s1,$s1,$t1
++	rlwinm	$acc00,$s0,`32-24`,24,31
++	xor	$s2,$s2,$t2
++	rlwinm	$acc01,$s1,`32-24`,24,31
++	xor	$s3,$s3,$t3
++	rlwinm	$acc02,$s2,`32-24`,24,31
++	rlwinm	$acc03,$s3,`32-24`,24,31
++	rlwinm	$acc04,$s3,`32-16`,24,31
++	rlwinm	$acc05,$s0,`32-16`,24,31
++	rlwinm	$acc06,$s1,`32-16`,24,31
++	rlwinm	$acc07,$s2,`32-16`,24,31
++	lbzx	$acc00,$Tbl1,$acc00
++	rlwinm	$acc08,$s2,`32-8`,24,31
++	lbzx	$acc01,$Tbl1,$acc01
++	rlwinm	$acc09,$s3,`32-8`,24,31
++	lbzx	$acc02,$Tbl1,$acc02
++	rlwinm	$acc10,$s0,`32-8`,24,31
++	lbzx	$acc03,$Tbl1,$acc03
++	rlwinm	$acc11,$s1,`32-8`,24,31
++	lbzx	$acc04,$Tbl1,$acc04
++	rlwinm	$acc12,$s1,`0`,24,31
++	lbzx	$acc05,$Tbl1,$acc05
++	rlwinm	$acc13,$s2,`0`,24,31
++	lbzx	$acc06,$Tbl1,$acc06
++	rlwinm	$acc14,$s3,`0`,24,31
++	lbzx	$acc07,$Tbl1,$acc07
++	rlwinm	$acc15,$s0,`0`,24,31
++	lbzx	$acc08,$Tbl1,$acc08
++	rlwinm	$s0,$acc00,24,0,7
++	lbzx	$acc09,$Tbl1,$acc09
++	rlwinm	$s1,$acc01,24,0,7
++	lbzx	$acc10,$Tbl1,$acc10
++	rlwinm	$s2,$acc02,24,0,7
++	lbzx	$acc11,$Tbl1,$acc11
++	rlwinm	$s3,$acc03,24,0,7
++	lbzx	$acc12,$Tbl1,$acc12
++	rlwimi	$s0,$acc04,16,8,15
++	lbzx	$acc13,$Tbl1,$acc13
++	rlwimi	$s1,$acc05,16,8,15
++	lbzx	$acc14,$Tbl1,$acc14
++	rlwimi	$s2,$acc06,16,8,15
++	lbzx	$acc15,$Tbl1,$acc15
++	rlwimi	$s3,$acc07,16,8,15
++	rlwimi	$s0,$acc08,8,16,23
++	rlwimi	$s1,$acc09,8,16,23
++	rlwimi	$s2,$acc10,8,16,23
++	rlwimi	$s3,$acc11,8,16,23
++	lwz	$t0,0($key)
++	or	$s0,$s0,$acc12
++	lwz	$t1,4($key)
++	or	$s1,$s1,$acc13
++	lwz	$t2,8($key)
++	or	$s2,$s2,$acc14
++	lwz	$t3,12($key)
++	or	$s3,$s3,$acc15
++
++	addi	$key,$key,16
++	bdz	Ldec_compact_done
++___
++$code.=<<___ if ($SIZE_T==8);
++	# vectorized permutation improves decrypt performance by 10%
++	insrdi	$s0,$s1,32,0
++	insrdi	$s2,$s3,32,0
++
++	and	$acc00,$s0,$mask80	# r1=r0&0x80808080
++	and	$acc02,$s2,$mask80
++	srdi	$acc04,$acc00,7		# r1>>7
++	srdi	$acc06,$acc02,7
++	andc	$acc08,$s0,$mask80	# r0&0x7f7f7f7f
++	andc	$acc10,$s2,$mask80
++	sub	$acc00,$acc00,$acc04	# r1-(r1>>7)
++	sub	$acc02,$acc02,$acc06
++	add	$acc08,$acc08,$acc08	# (r0&0x7f7f7f7f)<<1
++	add	$acc10,$acc10,$acc10
++	and	$acc00,$acc00,$mask1b	# (r1-(r1>>7))&0x1b1b1b1b
++	and	$acc02,$acc02,$mask1b
++	xor	$acc00,$acc00,$acc08	# r2
++	xor	$acc02,$acc02,$acc10
++
++	and	$acc04,$acc00,$mask80	# r1=r2&0x80808080
++	and	$acc06,$acc02,$mask80
++	srdi	$acc08,$acc04,7		# r1>>7
++	srdi	$acc10,$acc06,7
++	andc	$acc12,$acc00,$mask80	# r2&0x7f7f7f7f
++	andc	$acc14,$acc02,$mask80
++	sub	$acc04,$acc04,$acc08	# r1-(r1>>7)
++	sub	$acc06,$acc06,$acc10
++	add	$acc12,$acc12,$acc12	# (r2&0x7f7f7f7f)<<1
++	add	$acc14,$acc14,$acc14
++	and	$acc04,$acc04,$mask1b	# (r1-(r1>>7))&0x1b1b1b1b
++	and	$acc06,$acc06,$mask1b
++	xor	$acc04,$acc04,$acc12	# r4
++	xor	$acc06,$acc06,$acc14
++
++	and	$acc08,$acc04,$mask80	# r1=r4&0x80808080
++	and	$acc10,$acc06,$mask80
++	srdi	$acc12,$acc08,7		# r1>>7
++	srdi	$acc14,$acc10,7
++	sub	$acc08,$acc08,$acc12	# r1-(r1>>7)
++	sub	$acc10,$acc10,$acc14
++	andc	$acc12,$acc04,$mask80	# r4&0x7f7f7f7f
++	andc	$acc14,$acc06,$mask80
++	add	$acc12,$acc12,$acc12	# (r4&0x7f7f7f7f)<<1
++	add	$acc14,$acc14,$acc14
++	and	$acc08,$acc08,$mask1b	# (r1-(r1>>7))&0x1b1b1b1b
++	and	$acc10,$acc10,$mask1b
++	xor	$acc08,$acc08,$acc12	# r8
++	xor	$acc10,$acc10,$acc14
++
++	xor	$acc00,$acc00,$s0	# r2^r0
++	xor	$acc02,$acc02,$s2
++	xor	$acc04,$acc04,$s0	# r4^r0
++	xor	$acc06,$acc06,$s2
++
++	extrdi	$acc01,$acc00,32,0
++	extrdi	$acc03,$acc02,32,0
++	extrdi	$acc05,$acc04,32,0
++	extrdi	$acc07,$acc06,32,0
++	extrdi	$acc09,$acc08,32,0
++	extrdi	$acc11,$acc10,32,0
++___
++$code.=<<___ if ($SIZE_T==4);
++	and	$acc00,$s0,$mask80	# r1=r0&0x80808080
++	and	$acc01,$s1,$mask80
++	and	$acc02,$s2,$mask80
++	and	$acc03,$s3,$mask80
++	srwi	$acc04,$acc00,7		# r1>>7
++	andc	$acc08,$s0,$mask80	# r0&0x7f7f7f7f
++	srwi	$acc05,$acc01,7
++	andc	$acc09,$s1,$mask80
++	srwi	$acc06,$acc02,7
++	andc	$acc10,$s2,$mask80
++	srwi	$acc07,$acc03,7
++	andc	$acc11,$s3,$mask80
++	sub	$acc00,$acc00,$acc04	# r1-(r1>>7)
++	sub	$acc01,$acc01,$acc05
++	sub	$acc02,$acc02,$acc06
++	sub	$acc03,$acc03,$acc07
++	add	$acc08,$acc08,$acc08	# (r0&0x7f7f7f7f)<<1
++	add	$acc09,$acc09,$acc09
++	add	$acc10,$acc10,$acc10
++	add	$acc11,$acc11,$acc11
++	and	$acc00,$acc00,$mask1b	# (r1-(r1>>7))&0x1b1b1b1b
++	and	$acc01,$acc01,$mask1b
++	and	$acc02,$acc02,$mask1b
++	and	$acc03,$acc03,$mask1b
++	xor	$acc00,$acc00,$acc08	# r2
++	xor	$acc01,$acc01,$acc09
++	xor	$acc02,$acc02,$acc10
++	xor	$acc03,$acc03,$acc11
++
++	and	$acc04,$acc00,$mask80	# r1=r2&0x80808080
++	and	$acc05,$acc01,$mask80
++	and	$acc06,$acc02,$mask80
++	and	$acc07,$acc03,$mask80
++	srwi	$acc08,$acc04,7		# r1>>7
++	andc	$acc12,$acc00,$mask80	# r2&0x7f7f7f7f
++	srwi	$acc09,$acc05,7
++	andc	$acc13,$acc01,$mask80
++	srwi	$acc10,$acc06,7
++	andc	$acc14,$acc02,$mask80
++	srwi	$acc11,$acc07,7
++	andc	$acc15,$acc03,$mask80
++	sub	$acc04,$acc04,$acc08	# r1-(r1>>7)
++	sub	$acc05,$acc05,$acc09
++	sub	$acc06,$acc06,$acc10
++	sub	$acc07,$acc07,$acc11
++	add	$acc12,$acc12,$acc12	# (r2&0x7f7f7f7f)<<1
++	add	$acc13,$acc13,$acc13
++	add	$acc14,$acc14,$acc14
++	add	$acc15,$acc15,$acc15
++	and	$acc04,$acc04,$mask1b	# (r1-(r1>>7))&0x1b1b1b1b
++	and	$acc05,$acc05,$mask1b
++	and	$acc06,$acc06,$mask1b
++	and	$acc07,$acc07,$mask1b
++	xor	$acc04,$acc04,$acc12	# r4
++	xor	$acc05,$acc05,$acc13
++	xor	$acc06,$acc06,$acc14
++	xor	$acc07,$acc07,$acc15
++
++	and	$acc08,$acc04,$mask80	# r1=r4&0x80808080
++	and	$acc09,$acc05,$mask80
++	srwi	$acc12,$acc08,7		# r1>>7
++	and	$acc10,$acc06,$mask80
++	srwi	$acc13,$acc09,7
++	and	$acc11,$acc07,$mask80
++	srwi	$acc14,$acc10,7
++	sub	$acc08,$acc08,$acc12	# r1-(r1>>7)
++	srwi	$acc15,$acc11,7
++	sub	$acc09,$acc09,$acc13
++	sub	$acc10,$acc10,$acc14
++	sub	$acc11,$acc11,$acc15
++	andc	$acc12,$acc04,$mask80	# r4&0x7f7f7f7f
++	andc	$acc13,$acc05,$mask80
++	andc	$acc14,$acc06,$mask80
++	andc	$acc15,$acc07,$mask80
++	add	$acc12,$acc12,$acc12	# (r4&0x7f7f7f7f)<<1
++	add	$acc13,$acc13,$acc13
++	add	$acc14,$acc14,$acc14
++	add	$acc15,$acc15,$acc15
++	and	$acc08,$acc08,$mask1b	# (r1-(r1>>7))&0x1b1b1b1b
++	and	$acc09,$acc09,$mask1b
++	and	$acc10,$acc10,$mask1b
++	and	$acc11,$acc11,$mask1b
++	xor	$acc08,$acc08,$acc12	# r8
++	xor	$acc09,$acc09,$acc13
++	xor	$acc10,$acc10,$acc14
++	xor	$acc11,$acc11,$acc15
++
++	xor	$acc00,$acc00,$s0	# r2^r0
++	xor	$acc01,$acc01,$s1
++	xor	$acc02,$acc02,$s2
++	xor	$acc03,$acc03,$s3
++	xor	$acc04,$acc04,$s0	# r4^r0
++	xor	$acc05,$acc05,$s1
++	xor	$acc06,$acc06,$s2
++	xor	$acc07,$acc07,$s3
++___
++$code.=<<___;
++	rotrwi	$s0,$s0,8		# = ROTATE(r0,8)
++	rotrwi	$s1,$s1,8
++	xor	$s0,$s0,$acc00		# ^= r2^r0
++	rotrwi	$s2,$s2,8
++	xor	$s1,$s1,$acc01
++	rotrwi	$s3,$s3,8
++	xor	$s2,$s2,$acc02
++	xor	$s3,$s3,$acc03
++	xor	$acc00,$acc00,$acc08
++	xor	$acc01,$acc01,$acc09
++	xor	$acc02,$acc02,$acc10
++	xor	$acc03,$acc03,$acc11
++	xor	$s0,$s0,$acc04		# ^= r4^r0
++	rotrwi	$acc00,$acc00,24
++	xor	$s1,$s1,$acc05
++	rotrwi	$acc01,$acc01,24
++	xor	$s2,$s2,$acc06
++	rotrwi	$acc02,$acc02,24
++	xor	$s3,$s3,$acc07
++	rotrwi	$acc03,$acc03,24
++	xor	$acc04,$acc04,$acc08
++	xor	$acc05,$acc05,$acc09
++	xor	$acc06,$acc06,$acc10
++	xor	$acc07,$acc07,$acc11
++	xor	$s0,$s0,$acc08		# ^= r8 [^((r4^r0)^(r2^r0)=r4^r2)]
++	rotrwi	$acc04,$acc04,16
++	xor	$s1,$s1,$acc09
++	rotrwi	$acc05,$acc05,16
++	xor	$s2,$s2,$acc10
++	rotrwi	$acc06,$acc06,16
++	xor	$s3,$s3,$acc11
++	rotrwi	$acc07,$acc07,16
++	xor	$s0,$s0,$acc00		# ^= ROTATE(r8^r2^r0,24)
++	rotrwi	$acc08,$acc08,8
++	xor	$s1,$s1,$acc01
++	rotrwi	$acc09,$acc09,8
++	xor	$s2,$s2,$acc02
++	rotrwi	$acc10,$acc10,8
++	xor	$s3,$s3,$acc03
++	rotrwi	$acc11,$acc11,8
++	xor	$s0,$s0,$acc04		# ^= ROTATE(r8^r4^r0,16)
++	xor	$s1,$s1,$acc05
++	xor	$s2,$s2,$acc06
++	xor	$s3,$s3,$acc07
++	xor	$s0,$s0,$acc08		# ^= ROTATE(r8,8)	
++	xor	$s1,$s1,$acc09	
++	xor	$s2,$s2,$acc10	
++	xor	$s3,$s3,$acc11	
++
++	b	Ldec_compact_loop
++.align	4
++Ldec_compact_done:
++	xor	$s0,$s0,$t0
++	xor	$s1,$s1,$t1
++	xor	$s2,$s2,$t2
++	xor	$s3,$s3,$t3
++	blr
++	.long	0
++	.byte	0,12,0x14,0,0,0,0,0
++.size	.AES_decrypt,.-.AES_decrypt
++
++.asciz	"AES for PPC, CRYPTOGAMS by "
++.align	7
++___
++
++$code =~ s/\`([^\`]*)\`/eval $1/gem;
++print $code;
++close STDOUT;
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/aes/asm/aes-s390x.pl b/CryptoPkg/Library/OpensslLib/openssl/crypto/aes/asm/aes-s390x.pl
+new file mode 100644
+index 0000000..a93d601
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/aes/asm/aes-s390x.pl
+@@ -0,0 +1,2235 @@
++#! /usr/bin/env perl
++# Copyright 2007-2016 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
++# in the file LICENSE in the source distribution or at
++# https://www.openssl.org/source/license.html
++
++
++# ====================================================================
++# Written by Andy Polyakov  for the OpenSSL
++# project. The module is, however, dual licensed under OpenSSL and
++# CRYPTOGAMS licenses depending on where you obtain it. For further
++# details see http://www.openssl.org/~appro/cryptogams/.
++# ====================================================================
++
++# AES for s390x.
++
++# April 2007.
++#
++# Software performance improvement over gcc-generated code is ~70% and
++# in absolute terms is ~73 cycles per byte processed with 128-bit key.
++# You're likely to exclaim "why so slow?" Keep in mind that z-CPUs are
++# *strictly* in-order execution and issued instruction [in this case
++# load value from memory is critical] has to complete before execution
++# flow proceeds. S-boxes are compressed to 2KB[+256B].
++#
++# As for hardware acceleration support. It's basically a "teaser," as
++# it can and should be improved in several ways. Most notably support
++# for CBC is not utilized, nor multiple blocks are ever processed.
++# Then software key schedule can be postponed till hardware support
++# detection... Performance improvement over assembler is reportedly
++# ~2.5x, but can reach >8x [naturally on larger chunks] if proper
++# support is implemented.
++
++# May 2007.
++#
++# Implement AES_set_[en|de]crypt_key. Key schedule setup is avoided
++# for 128-bit keys, if hardware support is detected.
++
++# Januray 2009.
++#
++# Add support for hardware AES192/256 and reschedule instructions to
++# minimize/avoid Address Generation Interlock hazard and to favour
++# dual-issue z10 pipeline. This gave ~25% improvement on z10 and
++# almost 50% on z9. The gain is smaller on z10, because being dual-
++# issue z10 makes it improssible to eliminate the interlock condition:
++# critial path is not long enough. Yet it spends ~24 cycles per byte
++# processed with 128-bit key.
++#
++# Unlike previous version hardware support detection takes place only
++# at the moment of key schedule setup, which is denoted in key->rounds.
++# This is done, because deferred key setup can't be made MT-safe, not
++# for keys longer than 128 bits.
++#
++# Add AES_cbc_encrypt, which gives incredible performance improvement,
++# it was measured to be ~6.6x. It's less than previously mentioned 8x,
++# because software implementation was optimized.
++
++# May 2010.
++#
++# Add AES_ctr32_encrypt. If hardware-assisted, it provides up to 4.3x
++# performance improvement over "generic" counter mode routine relying
++# on single-block, also hardware-assisted, AES_encrypt. "Up to" refers
++# to the fact that exact throughput value depends on current stack
++# frame alignment within 4KB page. In worst case you get ~75% of the
++# maximum, but *on average* it would be as much as ~98%. Meaning that
++# worst case is unlike, it's like hitting ravine on plateau.
++
++# November 2010.
++#
++# Adapt for -m31 build. If kernel supports what's called "highgprs"
++# feature on Linux [see /proc/cpuinfo], it's possible to use 64-bit
++# instructions and achieve "64-bit" performance even in 31-bit legacy
++# application context. The feature is not specific to any particular
++# processor, as long as it's "z-CPU". Latter implies that the code
++# remains z/Architecture specific. On z990 it was measured to perform
++# 2x better than code generated by gcc 4.3.
++
++# December 2010.
++#
++# Add support for z196 "cipher message with counter" instruction.
++# Note however that it's disengaged, because it was measured to
++# perform ~12% worse than vanilla km-based code...
++
++# February 2011.
++#
++# Add AES_xts_[en|de]crypt. This includes support for z196 km-xts-aes
++# instructions, which deliver ~70% improvement at 8KB block size over
++# vanilla km-based code, 37% - at most like 512-bytes block size.
++
++$flavour = shift;
++
++if ($flavour =~ /3[12]/) {
++	$SIZE_T=4;
++	$g="";
++} else {
++	$SIZE_T=8;
++	$g="g";
++}
++
++while (($output=shift) && ($output!~/\w[\w\-]*\.\w+$/)) {}
++open STDOUT,">$output";
++
++$softonly=0;	# allow hardware support
++
++$t0="%r0";	$mask="%r0";
++$t1="%r1";
++$t2="%r2";	$inp="%r2";
++$t3="%r3";	$out="%r3";	$bits="%r3";
++$key="%r4";
++$i1="%r5";
++$i2="%r6";
++$i3="%r7";
++$s0="%r8";
++$s1="%r9";
++$s2="%r10";
++$s3="%r11";
++$tbl="%r12";
++$rounds="%r13";
++$ra="%r14";
++$sp="%r15";
++
++$stdframe=16*$SIZE_T+4*8;
++
++sub _data_word()
++{ my $i;
++    while(defined($i=shift)) { $code.=sprintf".long\t0x%08x,0x%08x\n",$i,$i; }
++}
++
++$code=<<___;
++.text
++
++.type	AES_Te,\@object
++.align	256
++AES_Te:
++___
++&_data_word(
++	0xc66363a5, 0xf87c7c84, 0xee777799, 0xf67b7b8d,
++	0xfff2f20d, 0xd66b6bbd, 0xde6f6fb1, 0x91c5c554,
++	0x60303050, 0x02010103, 0xce6767a9, 0x562b2b7d,
++	0xe7fefe19, 0xb5d7d762, 0x4dababe6, 0xec76769a,
++	0x8fcaca45, 0x1f82829d, 0x89c9c940, 0xfa7d7d87,
++	0xeffafa15, 0xb25959eb, 0x8e4747c9, 0xfbf0f00b,
++	0x41adadec, 0xb3d4d467, 0x5fa2a2fd, 0x45afafea,
++	0x239c9cbf, 0x53a4a4f7, 0xe4727296, 0x9bc0c05b,
++	0x75b7b7c2, 0xe1fdfd1c, 0x3d9393ae, 0x4c26266a,
++	0x6c36365a, 0x7e3f3f41, 0xf5f7f702, 0x83cccc4f,
++	0x6834345c, 0x51a5a5f4, 0xd1e5e534, 0xf9f1f108,
++	0xe2717193, 0xabd8d873, 0x62313153, 0x2a15153f,
++	0x0804040c, 0x95c7c752, 0x46232365, 0x9dc3c35e,
++	0x30181828, 0x379696a1, 0x0a05050f, 0x2f9a9ab5,
++	0x0e070709, 0x24121236, 0x1b80809b, 0xdfe2e23d,
++	0xcdebeb26, 0x4e272769, 0x7fb2b2cd, 0xea75759f,
++	0x1209091b, 0x1d83839e, 0x582c2c74, 0x341a1a2e,
++	0x361b1b2d, 0xdc6e6eb2, 0xb45a5aee, 0x5ba0a0fb,
++	0xa45252f6, 0x763b3b4d, 0xb7d6d661, 0x7db3b3ce,
++	0x5229297b, 0xdde3e33e, 0x5e2f2f71, 0x13848497,
++	0xa65353f5, 0xb9d1d168, 0x00000000, 0xc1eded2c,
++	0x40202060, 0xe3fcfc1f, 0x79b1b1c8, 0xb65b5bed,
++	0xd46a6abe, 0x8dcbcb46, 0x67bebed9, 0x7239394b,
++	0x944a4ade, 0x984c4cd4, 0xb05858e8, 0x85cfcf4a,
++	0xbbd0d06b, 0xc5efef2a, 0x4faaaae5, 0xedfbfb16,
++	0x864343c5, 0x9a4d4dd7, 0x66333355, 0x11858594,
++	0x8a4545cf, 0xe9f9f910, 0x04020206, 0xfe7f7f81,
++	0xa05050f0, 0x783c3c44, 0x259f9fba, 0x4ba8a8e3,
++	0xa25151f3, 0x5da3a3fe, 0x804040c0, 0x058f8f8a,
++	0x3f9292ad, 0x219d9dbc, 0x70383848, 0xf1f5f504,
++	0x63bcbcdf, 0x77b6b6c1, 0xafdada75, 0x42212163,
++	0x20101030, 0xe5ffff1a, 0xfdf3f30e, 0xbfd2d26d,
++	0x81cdcd4c, 0x180c0c14, 0x26131335, 0xc3ecec2f,
++	0xbe5f5fe1, 0x359797a2, 0x884444cc, 0x2e171739,
++	0x93c4c457, 0x55a7a7f2, 0xfc7e7e82, 0x7a3d3d47,
++	0xc86464ac, 0xba5d5de7, 0x3219192b, 0xe6737395,
++	0xc06060a0, 0x19818198, 0x9e4f4fd1, 0xa3dcdc7f,
++	0x44222266, 0x542a2a7e, 0x3b9090ab, 0x0b888883,
++	0x8c4646ca, 0xc7eeee29, 0x6bb8b8d3, 0x2814143c,
++	0xa7dede79, 0xbc5e5ee2, 0x160b0b1d, 0xaddbdb76,
++	0xdbe0e03b, 0x64323256, 0x743a3a4e, 0x140a0a1e,
++	0x924949db, 0x0c06060a, 0x4824246c, 0xb85c5ce4,
++	0x9fc2c25d, 0xbdd3d36e, 0x43acacef, 0xc46262a6,
++	0x399191a8, 0x319595a4, 0xd3e4e437, 0xf279798b,
++	0xd5e7e732, 0x8bc8c843, 0x6e373759, 0xda6d6db7,
++	0x018d8d8c, 0xb1d5d564, 0x9c4e4ed2, 0x49a9a9e0,
++	0xd86c6cb4, 0xac5656fa, 0xf3f4f407, 0xcfeaea25,
++	0xca6565af, 0xf47a7a8e, 0x47aeaee9, 0x10080818,
++	0x6fbabad5, 0xf0787888, 0x4a25256f, 0x5c2e2e72,
++	0x381c1c24, 0x57a6a6f1, 0x73b4b4c7, 0x97c6c651,
++	0xcbe8e823, 0xa1dddd7c, 0xe874749c, 0x3e1f1f21,
++	0x964b4bdd, 0x61bdbddc, 0x0d8b8b86, 0x0f8a8a85,
++	0xe0707090, 0x7c3e3e42, 0x71b5b5c4, 0xcc6666aa,
++	0x904848d8, 0x06030305, 0xf7f6f601, 0x1c0e0e12,
++	0xc26161a3, 0x6a35355f, 0xae5757f9, 0x69b9b9d0,
++	0x17868691, 0x99c1c158, 0x3a1d1d27, 0x279e9eb9,
++	0xd9e1e138, 0xebf8f813, 0x2b9898b3, 0x22111133,
++	0xd26969bb, 0xa9d9d970, 0x078e8e89, 0x339494a7,
++	0x2d9b9bb6, 0x3c1e1e22, 0x15878792, 0xc9e9e920,
++	0x87cece49, 0xaa5555ff, 0x50282878, 0xa5dfdf7a,
++	0x038c8c8f, 0x59a1a1f8, 0x09898980, 0x1a0d0d17,
++	0x65bfbfda, 0xd7e6e631, 0x844242c6, 0xd06868b8,
++	0x824141c3, 0x299999b0, 0x5a2d2d77, 0x1e0f0f11,
++	0x7bb0b0cb, 0xa85454fc, 0x6dbbbbd6, 0x2c16163a);
++$code.=<<___;
++# Te4[256]
++.byte	0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5
++.byte	0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76
++.byte	0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0
++.byte	0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0
++.byte	0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc
++.byte	0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15
++.byte	0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a
++.byte	0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75
++.byte	0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0
++.byte	0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84
++.byte	0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b
++.byte	0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf
++.byte	0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85
++.byte	0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8
++.byte	0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5
++.byte	0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2
++.byte	0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17
++.byte	0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73
++.byte	0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88
++.byte	0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb
++.byte	0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c
++.byte	0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79
++.byte	0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9
++.byte	0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08
++.byte	0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6
++.byte	0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a
++.byte	0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e
++.byte	0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e
++.byte	0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94
++.byte	0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf
++.byte	0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68
++.byte	0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16
++# rcon[]
++.long	0x01000000, 0x02000000, 0x04000000, 0x08000000
++.long	0x10000000, 0x20000000, 0x40000000, 0x80000000
++.long	0x1B000000, 0x36000000, 0, 0, 0, 0, 0, 0
++.align	256
++.size	AES_Te,.-AES_Te
++
++# void AES_encrypt(const unsigned char *inp, unsigned char *out,
++# 		 const AES_KEY *key) {
++.globl	AES_encrypt
++.type	AES_encrypt,\@function
++AES_encrypt:
++___
++$code.=<<___ if (!$softonly);
++	l	%r0,240($key)
++	lhi	%r1,16
++	clr	%r0,%r1
++	jl	.Lesoft
++
++	la	%r1,0($key)
++	#la	%r2,0($inp)
++	la	%r4,0($out)
++	lghi	%r3,16		# single block length
++	.long	0xb92e0042	# km %r4,%r2
++	brc	1,.-4		# can this happen?
++	br	%r14
++.align	64
++.Lesoft:
++___
++$code.=<<___;
++	stm${g}	%r3,$ra,3*$SIZE_T($sp)
++
++	llgf	$s0,0($inp)
++	llgf	$s1,4($inp)
++	llgf	$s2,8($inp)
++	llgf	$s3,12($inp)
++
++	larl	$tbl,AES_Te
++	bras	$ra,_s390x_AES_encrypt
++
++	l${g}	$out,3*$SIZE_T($sp)
++	st	$s0,0($out)
++	st	$s1,4($out)
++	st	$s2,8($out)
++	st	$s3,12($out)
++
++	lm${g}	%r6,$ra,6*$SIZE_T($sp)
++	br	$ra
++.size	AES_encrypt,.-AES_encrypt
++
++.type   _s390x_AES_encrypt,\@function
++.align	16
++_s390x_AES_encrypt:
++	st${g}	$ra,15*$SIZE_T($sp)
++	x	$s0,0($key)
++	x	$s1,4($key)
++	x	$s2,8($key)
++	x	$s3,12($key)
++	l	$rounds,240($key)
++	llill	$mask,`0xff<<3`
++	aghi	$rounds,-1
++	j	.Lenc_loop
++.align	16
++.Lenc_loop:
++	sllg	$t1,$s0,`0+3`
++	srlg	$t2,$s0,`8-3`
++	srlg	$t3,$s0,`16-3`
++	srl	$s0,`24-3`
++	nr	$s0,$mask
++	ngr	$t1,$mask
++	nr	$t2,$mask
++	nr	$t3,$mask
++
++	srlg	$i1,$s1,`16-3`	# i0
++	sllg	$i2,$s1,`0+3`
++	srlg	$i3,$s1,`8-3`
++	srl	$s1,`24-3`
++	nr	$i1,$mask
++	nr	$s1,$mask
++	ngr	$i2,$mask
++	nr	$i3,$mask
++
++	l	$s0,0($s0,$tbl)	# Te0[s0>>24]
++	l	$t1,1($t1,$tbl)	# Te3[s0>>0]
++	l	$t2,2($t2,$tbl) # Te2[s0>>8]
++	l	$t3,3($t3,$tbl)	# Te1[s0>>16]
++
++	x	$s0,3($i1,$tbl)	# Te1[s1>>16]
++	l	$s1,0($s1,$tbl)	# Te0[s1>>24]
++	x	$t2,1($i2,$tbl)	# Te3[s1>>0]
++	x	$t3,2($i3,$tbl)	# Te2[s1>>8]
++
++	srlg	$i1,$s2,`8-3`	# i0
++	srlg	$i2,$s2,`16-3`	# i1
++	nr	$i1,$mask
++	nr	$i2,$mask
++	sllg	$i3,$s2,`0+3`
++	srl	$s2,`24-3`
++	nr	$s2,$mask
++	ngr	$i3,$mask
++
++	xr	$s1,$t1
++	srlg	$ra,$s3,`8-3`	# i1
++	sllg	$t1,$s3,`0+3`	# i0
++	nr	$ra,$mask
++	la	$key,16($key)
++	ngr	$t1,$mask
++
++	x	$s0,2($i1,$tbl)	# Te2[s2>>8]
++	x	$s1,3($i2,$tbl)	# Te1[s2>>16]
++	l	$s2,0($s2,$tbl)	# Te0[s2>>24]
++	x	$t3,1($i3,$tbl)	# Te3[s2>>0]
++
++	srlg	$i3,$s3,`16-3`	# i2
++	xr	$s2,$t2
++	srl	$s3,`24-3`
++	nr	$i3,$mask
++	nr	$s3,$mask
++
++	x	$s0,0($key)
++	x	$s1,4($key)
++	x	$s2,8($key)
++	x	$t3,12($key)
++
++	x	$s0,1($t1,$tbl)	# Te3[s3>>0]
++	x	$s1,2($ra,$tbl)	# Te2[s3>>8]
++	x	$s2,3($i3,$tbl)	# Te1[s3>>16]
++	l	$s3,0($s3,$tbl)	# Te0[s3>>24]
++	xr	$s3,$t3
++
++	brct	$rounds,.Lenc_loop
++	.align	16
++
++	sllg	$t1,$s0,`0+3`
++	srlg	$t2,$s0,`8-3`
++	ngr	$t1,$mask
++	srlg	$t3,$s0,`16-3`
++	srl	$s0,`24-3`
++	nr	$s0,$mask
++	nr	$t2,$mask
++	nr	$t3,$mask
++
++	srlg	$i1,$s1,`16-3`	# i0
++	sllg	$i2,$s1,`0+3`
++	ngr	$i2,$mask
++	srlg	$i3,$s1,`8-3`
++	srl	$s1,`24-3`
++	nr	$i1,$mask
++	nr	$s1,$mask
++	nr	$i3,$mask
++
++	llgc	$s0,2($s0,$tbl)	# Te4[s0>>24]
++	llgc	$t1,2($t1,$tbl)	# Te4[s0>>0]
++	sll	$s0,24
++	llgc	$t2,2($t2,$tbl)	# Te4[s0>>8]
++	llgc	$t3,2($t3,$tbl)	# Te4[s0>>16]
++	sll	$t2,8
++	sll	$t3,16
++
++	llgc	$i1,2($i1,$tbl)	# Te4[s1>>16]
++	llgc	$s1,2($s1,$tbl)	# Te4[s1>>24]
++	llgc	$i2,2($i2,$tbl)	# Te4[s1>>0]
++	llgc	$i3,2($i3,$tbl)	# Te4[s1>>8]
++	sll	$i1,16
++	sll	$s1,24
++	sll	$i3,8
++	or	$s0,$i1
++	or	$s1,$t1
++	or	$t2,$i2
++	or	$t3,$i3
++	
++	srlg	$i1,$s2,`8-3`	# i0
++	srlg	$i2,$s2,`16-3`	# i1
++	nr	$i1,$mask
++	nr	$i2,$mask
++	sllg	$i3,$s2,`0+3`
++	srl	$s2,`24-3`
++	ngr	$i3,$mask
++	nr	$s2,$mask
++
++	sllg	$t1,$s3,`0+3`	# i0
++	srlg	$ra,$s3,`8-3`	# i1
++	ngr	$t1,$mask
++
++	llgc	$i1,2($i1,$tbl)	# Te4[s2>>8]
++	llgc	$i2,2($i2,$tbl)	# Te4[s2>>16]
++	sll	$i1,8
++	llgc	$s2,2($s2,$tbl)	# Te4[s2>>24]
++	llgc	$i3,2($i3,$tbl)	# Te4[s2>>0]
++	sll	$i2,16
++	nr	$ra,$mask
++	sll	$s2,24
++	or	$s0,$i1
++	or	$s1,$i2
++	or	$s2,$t2
++	or	$t3,$i3
++
++	srlg	$i3,$s3,`16-3`	# i2
++	srl	$s3,`24-3`
++	nr	$i3,$mask
++	nr	$s3,$mask
++
++	l	$t0,16($key)
++	l	$t2,20($key)
++
++	llgc	$i1,2($t1,$tbl)	# Te4[s3>>0]
++	llgc	$i2,2($ra,$tbl)	# Te4[s3>>8]
++	llgc	$i3,2($i3,$tbl)	# Te4[s3>>16]
++	llgc	$s3,2($s3,$tbl)	# Te4[s3>>24]
++	sll	$i2,8
++	sll	$i3,16
++	sll	$s3,24
++	or	$s0,$i1
++	or	$s1,$i2
++	or	$s2,$i3
++	or	$s3,$t3
++
++	l${g}	$ra,15*$SIZE_T($sp)
++	xr	$s0,$t0
++	xr	$s1,$t2
++	x	$s2,24($key)
++	x	$s3,28($key)
++
++	br	$ra	
++.size	_s390x_AES_encrypt,.-_s390x_AES_encrypt
++___
++
++$code.=<<___;
++.type	AES_Td,\@object
++.align	256
++AES_Td:
++___
++&_data_word(
++	0x51f4a750, 0x7e416553, 0x1a17a4c3, 0x3a275e96,
++	0x3bab6bcb, 0x1f9d45f1, 0xacfa58ab, 0x4be30393,
++	0x2030fa55, 0xad766df6, 0x88cc7691, 0xf5024c25,
++	0x4fe5d7fc, 0xc52acbd7, 0x26354480, 0xb562a38f,
++	0xdeb15a49, 0x25ba1b67, 0x45ea0e98, 0x5dfec0e1,
++	0xc32f7502, 0x814cf012, 0x8d4697a3, 0x6bd3f9c6,
++	0x038f5fe7, 0x15929c95, 0xbf6d7aeb, 0x955259da,
++	0xd4be832d, 0x587421d3, 0x49e06929, 0x8ec9c844,
++	0x75c2896a, 0xf48e7978, 0x99583e6b, 0x27b971dd,
++	0xbee14fb6, 0xf088ad17, 0xc920ac66, 0x7dce3ab4,
++	0x63df4a18, 0xe51a3182, 0x97513360, 0x62537f45,
++	0xb16477e0, 0xbb6bae84, 0xfe81a01c, 0xf9082b94,
++	0x70486858, 0x8f45fd19, 0x94de6c87, 0x527bf8b7,
++	0xab73d323, 0x724b02e2, 0xe31f8f57, 0x6655ab2a,
++	0xb2eb2807, 0x2fb5c203, 0x86c57b9a, 0xd33708a5,
++	0x302887f2, 0x23bfa5b2, 0x02036aba, 0xed16825c,
++	0x8acf1c2b, 0xa779b492, 0xf307f2f0, 0x4e69e2a1,
++	0x65daf4cd, 0x0605bed5, 0xd134621f, 0xc4a6fe8a,
++	0x342e539d, 0xa2f355a0, 0x058ae132, 0xa4f6eb75,
++	0x0b83ec39, 0x4060efaa, 0x5e719f06, 0xbd6e1051,
++	0x3e218af9, 0x96dd063d, 0xdd3e05ae, 0x4de6bd46,
++	0x91548db5, 0x71c45d05, 0x0406d46f, 0x605015ff,
++	0x1998fb24, 0xd6bde997, 0x894043cc, 0x67d99e77,
++	0xb0e842bd, 0x07898b88, 0xe7195b38, 0x79c8eedb,
++	0xa17c0a47, 0x7c420fe9, 0xf8841ec9, 0x00000000,
++	0x09808683, 0x322bed48, 0x1e1170ac, 0x6c5a724e,
++	0xfd0efffb, 0x0f853856, 0x3daed51e, 0x362d3927,
++	0x0a0fd964, 0x685ca621, 0x9b5b54d1, 0x24362e3a,
++	0x0c0a67b1, 0x9357e70f, 0xb4ee96d2, 0x1b9b919e,
++	0x80c0c54f, 0x61dc20a2, 0x5a774b69, 0x1c121a16,
++	0xe293ba0a, 0xc0a02ae5, 0x3c22e043, 0x121b171d,
++	0x0e090d0b, 0xf28bc7ad, 0x2db6a8b9, 0x141ea9c8,
++	0x57f11985, 0xaf75074c, 0xee99ddbb, 0xa37f60fd,
++	0xf701269f, 0x5c72f5bc, 0x44663bc5, 0x5bfb7e34,
++	0x8b432976, 0xcb23c6dc, 0xb6edfc68, 0xb8e4f163,
++	0xd731dcca, 0x42638510, 0x13972240, 0x84c61120,
++	0x854a247d, 0xd2bb3df8, 0xaef93211, 0xc729a16d,
++	0x1d9e2f4b, 0xdcb230f3, 0x0d8652ec, 0x77c1e3d0,
++	0x2bb3166c, 0xa970b999, 0x119448fa, 0x47e96422,
++	0xa8fc8cc4, 0xa0f03f1a, 0x567d2cd8, 0x223390ef,
++	0x87494ec7, 0xd938d1c1, 0x8ccaa2fe, 0x98d40b36,
++	0xa6f581cf, 0xa57ade28, 0xdab78e26, 0x3fadbfa4,
++	0x2c3a9de4, 0x5078920d, 0x6a5fcc9b, 0x547e4662,
++	0xf68d13c2, 0x90d8b8e8, 0x2e39f75e, 0x82c3aff5,
++	0x9f5d80be, 0x69d0937c, 0x6fd52da9, 0xcf2512b3,
++	0xc8ac993b, 0x10187da7, 0xe89c636e, 0xdb3bbb7b,
++	0xcd267809, 0x6e5918f4, 0xec9ab701, 0x834f9aa8,
++	0xe6956e65, 0xaaffe67e, 0x21bccf08, 0xef15e8e6,
++	0xbae79bd9, 0x4a6f36ce, 0xea9f09d4, 0x29b07cd6,
++	0x31a4b2af, 0x2a3f2331, 0xc6a59430, 0x35a266c0,
++	0x744ebc37, 0xfc82caa6, 0xe090d0b0, 0x33a7d815,
++	0xf104984a, 0x41ecdaf7, 0x7fcd500e, 0x1791f62f,
++	0x764dd68d, 0x43efb04d, 0xccaa4d54, 0xe49604df,
++	0x9ed1b5e3, 0x4c6a881b, 0xc12c1fb8, 0x4665517f,
++	0x9d5eea04, 0x018c355d, 0xfa877473, 0xfb0b412e,
++	0xb3671d5a, 0x92dbd252, 0xe9105633, 0x6dd64713,
++	0x9ad7618c, 0x37a10c7a, 0x59f8148e, 0xeb133c89,
++	0xcea927ee, 0xb761c935, 0xe11ce5ed, 0x7a47b13c,
++	0x9cd2df59, 0x55f2733f, 0x1814ce79, 0x73c737bf,
++	0x53f7cdea, 0x5ffdaa5b, 0xdf3d6f14, 0x7844db86,
++	0xcaaff381, 0xb968c43e, 0x3824342c, 0xc2a3405f,
++	0x161dc372, 0xbce2250c, 0x283c498b, 0xff0d9541,
++	0x39a80171, 0x080cb3de, 0xd8b4e49c, 0x6456c190,
++	0x7bcb8461, 0xd532b670, 0x486c5c74, 0xd0b85742);
++$code.=<<___;
++# Td4[256]
++.byte	0x52, 0x09, 0x6a, 0xd5, 0x30, 0x36, 0xa5, 0x38
++.byte	0xbf, 0x40, 0xa3, 0x9e, 0x81, 0xf3, 0xd7, 0xfb
++.byte	0x7c, 0xe3, 0x39, 0x82, 0x9b, 0x2f, 0xff, 0x87
++.byte	0x34, 0x8e, 0x43, 0x44, 0xc4, 0xde, 0xe9, 0xcb
++.byte	0x54, 0x7b, 0x94, 0x32, 0xa6, 0xc2, 0x23, 0x3d
++.byte	0xee, 0x4c, 0x95, 0x0b, 0x42, 0xfa, 0xc3, 0x4e
++.byte	0x08, 0x2e, 0xa1, 0x66, 0x28, 0xd9, 0x24, 0xb2
++.byte	0x76, 0x5b, 0xa2, 0x49, 0x6d, 0x8b, 0xd1, 0x25
++.byte	0x72, 0xf8, 0xf6, 0x64, 0x86, 0x68, 0x98, 0x16
++.byte	0xd4, 0xa4, 0x5c, 0xcc, 0x5d, 0x65, 0xb6, 0x92
++.byte	0x6c, 0x70, 0x48, 0x50, 0xfd, 0xed, 0xb9, 0xda
++.byte	0x5e, 0x15, 0x46, 0x57, 0xa7, 0x8d, 0x9d, 0x84
++.byte	0x90, 0xd8, 0xab, 0x00, 0x8c, 0xbc, 0xd3, 0x0a
++.byte	0xf7, 0xe4, 0x58, 0x05, 0xb8, 0xb3, 0x45, 0x06
++.byte	0xd0, 0x2c, 0x1e, 0x8f, 0xca, 0x3f, 0x0f, 0x02
++.byte	0xc1, 0xaf, 0xbd, 0x03, 0x01, 0x13, 0x8a, 0x6b
++.byte	0x3a, 0x91, 0x11, 0x41, 0x4f, 0x67, 0xdc, 0xea
++.byte	0x97, 0xf2, 0xcf, 0xce, 0xf0, 0xb4, 0xe6, 0x73
++.byte	0x96, 0xac, 0x74, 0x22, 0xe7, 0xad, 0x35, 0x85
++.byte	0xe2, 0xf9, 0x37, 0xe8, 0x1c, 0x75, 0xdf, 0x6e
++.byte	0x47, 0xf1, 0x1a, 0x71, 0x1d, 0x29, 0xc5, 0x89
++.byte	0x6f, 0xb7, 0x62, 0x0e, 0xaa, 0x18, 0xbe, 0x1b
++.byte	0xfc, 0x56, 0x3e, 0x4b, 0xc6, 0xd2, 0x79, 0x20
++.byte	0x9a, 0xdb, 0xc0, 0xfe, 0x78, 0xcd, 0x5a, 0xf4
++.byte	0x1f, 0xdd, 0xa8, 0x33, 0x88, 0x07, 0xc7, 0x31
++.byte	0xb1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xec, 0x5f
++.byte	0x60, 0x51, 0x7f, 0xa9, 0x19, 0xb5, 0x4a, 0x0d
++.byte	0x2d, 0xe5, 0x7a, 0x9f, 0x93, 0xc9, 0x9c, 0xef
++.byte	0xa0, 0xe0, 0x3b, 0x4d, 0xae, 0x2a, 0xf5, 0xb0
++.byte	0xc8, 0xeb, 0xbb, 0x3c, 0x83, 0x53, 0x99, 0x61
++.byte	0x17, 0x2b, 0x04, 0x7e, 0xba, 0x77, 0xd6, 0x26
++.byte	0xe1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0c, 0x7d
++.size	AES_Td,.-AES_Td
++
++# void AES_decrypt(const unsigned char *inp, unsigned char *out,
++# 		 const AES_KEY *key) {
++.globl	AES_decrypt
++.type	AES_decrypt,\@function
++AES_decrypt:
++___
++$code.=<<___ if (!$softonly);
++	l	%r0,240($key)
++	lhi	%r1,16
++	clr	%r0,%r1
++	jl	.Ldsoft
++
++	la	%r1,0($key)
++	#la	%r2,0($inp)
++	la	%r4,0($out)
++	lghi	%r3,16		# single block length
++	.long	0xb92e0042	# km %r4,%r2
++	brc	1,.-4		# can this happen?
++	br	%r14
++.align	64
++.Ldsoft:
++___
++$code.=<<___;
++	stm${g}	%r3,$ra,3*$SIZE_T($sp)
++
++	llgf	$s0,0($inp)
++	llgf	$s1,4($inp)
++	llgf	$s2,8($inp)
++	llgf	$s3,12($inp)
++
++	larl	$tbl,AES_Td
++	bras	$ra,_s390x_AES_decrypt
++
++	l${g}	$out,3*$SIZE_T($sp)
++	st	$s0,0($out)
++	st	$s1,4($out)
++	st	$s2,8($out)
++	st	$s3,12($out)
++
++	lm${g}	%r6,$ra,6*$SIZE_T($sp)
++	br	$ra
++.size	AES_decrypt,.-AES_decrypt
++
++.type   _s390x_AES_decrypt,\@function
++.align	16
++_s390x_AES_decrypt:
++	st${g}	$ra,15*$SIZE_T($sp)
++	x	$s0,0($key)
++	x	$s1,4($key)
++	x	$s2,8($key)
++	x	$s3,12($key)
++	l	$rounds,240($key)
++	llill	$mask,`0xff<<3`
++	aghi	$rounds,-1
++	j	.Ldec_loop
++.align	16
++.Ldec_loop:
++	srlg	$t1,$s0,`16-3`
++	srlg	$t2,$s0,`8-3`
++	sllg	$t3,$s0,`0+3`
++	srl	$s0,`24-3`
++	nr	$s0,$mask
++	nr	$t1,$mask
++	nr	$t2,$mask
++	ngr	$t3,$mask
++
++	sllg	$i1,$s1,`0+3`	# i0
++	srlg	$i2,$s1,`16-3`
++	srlg	$i3,$s1,`8-3`
++	srl	$s1,`24-3`
++	ngr	$i1,$mask
++	nr	$s1,$mask
++	nr	$i2,$mask
++	nr	$i3,$mask
++
++	l	$s0,0($s0,$tbl)	# Td0[s0>>24]
++	l	$t1,3($t1,$tbl)	# Td1[s0>>16]
++	l	$t2,2($t2,$tbl)	# Td2[s0>>8]
++	l	$t3,1($t3,$tbl)	# Td3[s0>>0]
++
++	x	$s0,1($i1,$tbl)	# Td3[s1>>0]
++	l	$s1,0($s1,$tbl)	# Td0[s1>>24]
++	x	$t2,3($i2,$tbl)	# Td1[s1>>16]
++	x	$t3,2($i3,$tbl)	# Td2[s1>>8]
++
++	srlg	$i1,$s2,`8-3`	# i0
++	sllg	$i2,$s2,`0+3`	# i1
++	srlg	$i3,$s2,`16-3`
++	srl	$s2,`24-3`
++	nr	$i1,$mask
++	ngr	$i2,$mask
++	nr	$s2,$mask
++	nr	$i3,$mask
++
++	xr	$s1,$t1
++	srlg	$ra,$s3,`8-3`	# i1
++	srlg	$t1,$s3,`16-3`	# i0
++	nr	$ra,$mask
++	la	$key,16($key)
++	nr	$t1,$mask
++
++	x	$s0,2($i1,$tbl)	# Td2[s2>>8]
++	x	$s1,1($i2,$tbl)	# Td3[s2>>0]
++	l	$s2,0($s2,$tbl)	# Td0[s2>>24]
++	x	$t3,3($i3,$tbl)	# Td1[s2>>16]
++
++	sllg	$i3,$s3,`0+3`	# i2
++	srl	$s3,`24-3`
++	ngr	$i3,$mask
++	nr	$s3,$mask
++
++	xr	$s2,$t2
++	x	$s0,0($key)
++	x	$s1,4($key)
++	x	$s2,8($key)
++	x	$t3,12($key)
++
++	x	$s0,3($t1,$tbl)	# Td1[s3>>16]
++	x	$s1,2($ra,$tbl)	# Td2[s3>>8]
++	x	$s2,1($i3,$tbl)	# Td3[s3>>0]
++	l	$s3,0($s3,$tbl)	# Td0[s3>>24]
++	xr	$s3,$t3
++
++	brct	$rounds,.Ldec_loop
++	.align	16
++
++	l	$t1,`2048+0`($tbl)	# prefetch Td4
++	l	$t2,`2048+64`($tbl)
++	l	$t3,`2048+128`($tbl)
++	l	$i1,`2048+192`($tbl)
++	llill	$mask,0xff
++
++	srlg	$i3,$s0,24	# i0
++	srlg	$t1,$s0,16
++	srlg	$t2,$s0,8
++	nr	$s0,$mask	# i3
++	nr	$t1,$mask
++
++	srlg	$i1,$s1,24
++	nr	$t2,$mask
++	srlg	$i2,$s1,16
++	srlg	$ra,$s1,8
++	nr	$s1,$mask	# i0
++	nr	$i2,$mask
++	nr	$ra,$mask
++
++	llgc	$i3,2048($i3,$tbl)	# Td4[s0>>24]
++	llgc	$t1,2048($t1,$tbl)	# Td4[s0>>16]
++	llgc	$t2,2048($t2,$tbl)	# Td4[s0>>8]
++	sll	$t1,16
++	llgc	$t3,2048($s0,$tbl)	# Td4[s0>>0]
++	sllg	$s0,$i3,24
++	sll	$t2,8
++
++	llgc	$s1,2048($s1,$tbl)	# Td4[s1>>0]
++	llgc	$i1,2048($i1,$tbl)	# Td4[s1>>24]
++	llgc	$i2,2048($i2,$tbl)	# Td4[s1>>16]
++	sll	$i1,24
++	llgc	$i3,2048($ra,$tbl)	# Td4[s1>>8]
++	sll	$i2,16
++	sll	$i3,8
++	or	$s0,$s1
++	or	$t1,$i1
++	or	$t2,$i2
++	or	$t3,$i3
++
++	srlg	$i1,$s2,8	# i0
++	srlg	$i2,$s2,24
++	srlg	$i3,$s2,16
++	nr	$s2,$mask	# i1
++	nr	$i1,$mask
++	nr	$i3,$mask
++	llgc	$i1,2048($i1,$tbl)	# Td4[s2>>8]
++	llgc	$s1,2048($s2,$tbl)	# Td4[s2>>0]
++	llgc	$i2,2048($i2,$tbl)	# Td4[s2>>24]
++	llgc	$i3,2048($i3,$tbl)	# Td4[s2>>16]
++	sll	$i1,8
++	sll	$i2,24
++	or	$s0,$i1
++	sll	$i3,16
++	or	$t2,$i2
++	or	$t3,$i3
++
++	srlg	$i1,$s3,16	# i0
++	srlg	$i2,$s3,8	# i1
++	srlg	$i3,$s3,24
++	nr	$s3,$mask	# i2
++	nr	$i1,$mask
++	nr	$i2,$mask
++
++	l${g}	$ra,15*$SIZE_T($sp)
++	or	$s1,$t1
++	l	$t0,16($key)
++	l	$t1,20($key)
++
++	llgc	$i1,2048($i1,$tbl)	# Td4[s3>>16]
++	llgc	$i2,2048($i2,$tbl)	# Td4[s3>>8]
++	sll	$i1,16
++	llgc	$s2,2048($s3,$tbl)	# Td4[s3>>0]
++	llgc	$s3,2048($i3,$tbl)	# Td4[s3>>24]
++	sll	$i2,8
++	sll	$s3,24
++	or	$s0,$i1
++	or	$s1,$i2
++	or	$s2,$t2
++	or	$s3,$t3
++
++	xr	$s0,$t0
++	xr	$s1,$t1
++	x	$s2,24($key)
++	x	$s3,28($key)
++
++	br	$ra	
++.size	_s390x_AES_decrypt,.-_s390x_AES_decrypt
++___
++
++$code.=<<___;
++# void AES_set_encrypt_key(const unsigned char *in, int bits,
++# 		 AES_KEY *key) {
++.globl	AES_set_encrypt_key
++.type	AES_set_encrypt_key,\@function
++.align	16
++AES_set_encrypt_key:
++_s390x_AES_set_encrypt_key:
++	lghi	$t0,0
++	cl${g}r	$inp,$t0
++	je	.Lminus1
++	cl${g}r	$key,$t0
++	je	.Lminus1
++
++	lghi	$t0,128
++	clr	$bits,$t0
++	je	.Lproceed
++	lghi	$t0,192
++	clr	$bits,$t0
++	je	.Lproceed
++	lghi	$t0,256
++	clr	$bits,$t0
++	je	.Lproceed
++	lghi	%r2,-2
++	br	%r14
++
++.align	16
++.Lproceed:
++___
++$code.=<<___ if (!$softonly);
++	# convert bits to km code, [128,192,256]->[18,19,20]
++	lhi	%r5,-128
++	lhi	%r0,18
++	ar	%r5,$bits
++	srl	%r5,6
++	ar	%r5,%r0
++
++	larl	%r1,OPENSSL_s390xcap_P
++	lg	%r0,0(%r1)
++	tmhl	%r0,0x4000	# check for message-security assist
++	jz	.Lekey_internal
++
++	llihh	%r0,0x8000
++	srlg	%r0,%r0,0(%r5)
++	ng	%r0,48(%r1)	# check kmc capability vector
++	jz	.Lekey_internal
++
++	lmg	%r0,%r1,0($inp)	# just copy 128 bits...
++	stmg	%r0,%r1,0($key)
++	lhi	%r0,192
++	cr	$bits,%r0
++	jl	1f
++	lg	%r1,16($inp)
++	stg	%r1,16($key)
++	je	1f
++	lg	%r1,24($inp)
++	stg	%r1,24($key)
++1:	st	$bits,236($key)	# save bits [for debugging purposes]
++	lgr	$t0,%r5
++	st	%r5,240($key)	# save km code
++	lghi	%r2,0
++	br	%r14
++___
++$code.=<<___;
++.align	16
++.Lekey_internal:
++	stm${g}	%r4,%r13,4*$SIZE_T($sp)	# all non-volatile regs and $key
++
++	larl	$tbl,AES_Te+2048
++
++	llgf	$s0,0($inp)
++	llgf	$s1,4($inp)
++	llgf	$s2,8($inp)
++	llgf	$s3,12($inp)
++	st	$s0,0($key)
++	st	$s1,4($key)
++	st	$s2,8($key)
++	st	$s3,12($key)
++	lghi	$t0,128
++	cr	$bits,$t0
++	jne	.Lnot128
++
++	llill	$mask,0xff
++	lghi	$t3,0			# i=0
++	lghi	$rounds,10
++	st	$rounds,240($key)
++
++	llgfr	$t2,$s3			# temp=rk[3]
++	srlg	$i1,$s3,8
++	srlg	$i2,$s3,16
++	srlg	$i3,$s3,24
++	nr	$t2,$mask
++	nr	$i1,$mask
++	nr	$i2,$mask
++
++.align	16
++.L128_loop:
++	la	$t2,0($t2,$tbl)
++	la	$i1,0($i1,$tbl)
++	la	$i2,0($i2,$tbl)
++	la	$i3,0($i3,$tbl)
++	icm	$t2,2,0($t2)		# Te4[rk[3]>>0]<<8
++	icm	$t2,4,0($i1)		# Te4[rk[3]>>8]<<16
++	icm	$t2,8,0($i2)		# Te4[rk[3]>>16]<<24
++	icm	$t2,1,0($i3)		# Te4[rk[3]>>24]
++	x	$t2,256($t3,$tbl)	# rcon[i]
++	xr	$s0,$t2			# rk[4]=rk[0]^...
++	xr	$s1,$s0			# rk[5]=rk[1]^rk[4]
++	xr	$s2,$s1			# rk[6]=rk[2]^rk[5]
++	xr	$s3,$s2			# rk[7]=rk[3]^rk[6]
++
++	llgfr	$t2,$s3			# temp=rk[3]
++	srlg	$i1,$s3,8
++	srlg	$i2,$s3,16
++	nr	$t2,$mask
++	nr	$i1,$mask
++	srlg	$i3,$s3,24
++	nr	$i2,$mask
++
++	st	$s0,16($key)
++	st	$s1,20($key)
++	st	$s2,24($key)
++	st	$s3,28($key)
++	la	$key,16($key)		# key+=4
++	la	$t3,4($t3)		# i++
++	brct	$rounds,.L128_loop
++	lghi	$t0,10
++	lghi	%r2,0
++	lm${g}	%r4,%r13,4*$SIZE_T($sp)
++	br	$ra
++
++.align	16
++.Lnot128:
++	llgf	$t0,16($inp)
++	llgf	$t1,20($inp)
++	st	$t0,16($key)
++	st	$t1,20($key)
++	lghi	$t0,192
++	cr	$bits,$t0
++	jne	.Lnot192
++
++	llill	$mask,0xff
++	lghi	$t3,0			# i=0
++	lghi	$rounds,12
++	st	$rounds,240($key)
++	lghi	$rounds,8
++
++	srlg	$i1,$t1,8
++	srlg	$i2,$t1,16
++	srlg	$i3,$t1,24
++	nr	$t1,$mask
++	nr	$i1,$mask
++	nr	$i2,$mask
++
++.align	16
++.L192_loop:
++	la	$t1,0($t1,$tbl)
++	la	$i1,0($i1,$tbl)
++	la	$i2,0($i2,$tbl)
++	la	$i3,0($i3,$tbl)
++	icm	$t1,2,0($t1)		# Te4[rk[5]>>0]<<8
++	icm	$t1,4,0($i1)		# Te4[rk[5]>>8]<<16
++	icm	$t1,8,0($i2)		# Te4[rk[5]>>16]<<24
++	icm	$t1,1,0($i3)		# Te4[rk[5]>>24]
++	x	$t1,256($t3,$tbl)	# rcon[i]
++	xr	$s0,$t1			# rk[6]=rk[0]^...
++	xr	$s1,$s0			# rk[7]=rk[1]^rk[6]
++	xr	$s2,$s1			# rk[8]=rk[2]^rk[7]
++	xr	$s3,$s2			# rk[9]=rk[3]^rk[8]
++
++	st	$s0,24($key)
++	st	$s1,28($key)
++	st	$s2,32($key)
++	st	$s3,36($key)
++	brct	$rounds,.L192_continue
++	lghi	$t0,12
++	lghi	%r2,0
++	lm${g}	%r4,%r13,4*$SIZE_T($sp)
++	br	$ra
++
++.align	16
++.L192_continue:
++	lgr	$t1,$s3
++	x	$t1,16($key)		# rk[10]=rk[4]^rk[9]
++	st	$t1,40($key)
++	x	$t1,20($key)		# rk[11]=rk[5]^rk[10]
++	st	$t1,44($key)
++
++	srlg	$i1,$t1,8
++	srlg	$i2,$t1,16
++	srlg	$i3,$t1,24
++	nr	$t1,$mask
++	nr	$i1,$mask
++	nr	$i2,$mask
++
++	la	$key,24($key)		# key+=6
++	la	$t3,4($t3)		# i++
++	j	.L192_loop
++
++.align	16
++.Lnot192:
++	llgf	$t0,24($inp)
++	llgf	$t1,28($inp)
++	st	$t0,24($key)
++	st	$t1,28($key)
++	llill	$mask,0xff
++	lghi	$t3,0			# i=0
++	lghi	$rounds,14
++	st	$rounds,240($key)
++	lghi	$rounds,7
++
++	srlg	$i1,$t1,8
++	srlg	$i2,$t1,16
++	srlg	$i3,$t1,24
++	nr	$t1,$mask
++	nr	$i1,$mask
++	nr	$i2,$mask
++
++.align	16
++.L256_loop:
++	la	$t1,0($t1,$tbl)
++	la	$i1,0($i1,$tbl)
++	la	$i2,0($i2,$tbl)
++	la	$i3,0($i3,$tbl)
++	icm	$t1,2,0($t1)		# Te4[rk[7]>>0]<<8
++	icm	$t1,4,0($i1)		# Te4[rk[7]>>8]<<16
++	icm	$t1,8,0($i2)		# Te4[rk[7]>>16]<<24
++	icm	$t1,1,0($i3)		# Te4[rk[7]>>24]
++	x	$t1,256($t3,$tbl)	# rcon[i]
++	xr	$s0,$t1			# rk[8]=rk[0]^...
++	xr	$s1,$s0			# rk[9]=rk[1]^rk[8]
++	xr	$s2,$s1			# rk[10]=rk[2]^rk[9]
++	xr	$s3,$s2			# rk[11]=rk[3]^rk[10]
++	st	$s0,32($key)
++	st	$s1,36($key)
++	st	$s2,40($key)
++	st	$s3,44($key)
++	brct	$rounds,.L256_continue
++	lghi	$t0,14
++	lghi	%r2,0
++	lm${g}	%r4,%r13,4*$SIZE_T($sp)
++	br	$ra
++
++.align	16
++.L256_continue:
++	lgr	$t1,$s3			# temp=rk[11]
++	srlg	$i1,$s3,8
++	srlg	$i2,$s3,16
++	srlg	$i3,$s3,24
++	nr	$t1,$mask
++	nr	$i1,$mask
++	nr	$i2,$mask
++	la	$t1,0($t1,$tbl)
++	la	$i1,0($i1,$tbl)
++	la	$i2,0($i2,$tbl)
++	la	$i3,0($i3,$tbl)
++	llgc	$t1,0($t1)		# Te4[rk[11]>>0]
++	icm	$t1,2,0($i1)		# Te4[rk[11]>>8]<<8
++	icm	$t1,4,0($i2)		# Te4[rk[11]>>16]<<16
++	icm	$t1,8,0($i3)		# Te4[rk[11]>>24]<<24
++	x	$t1,16($key)		# rk[12]=rk[4]^...
++	st	$t1,48($key)
++	x	$t1,20($key)		# rk[13]=rk[5]^rk[12]
++	st	$t1,52($key)
++	x	$t1,24($key)		# rk[14]=rk[6]^rk[13]
++	st	$t1,56($key)
++	x	$t1,28($key)		# rk[15]=rk[7]^rk[14]
++	st	$t1,60($key)
++
++	srlg	$i1,$t1,8
++	srlg	$i2,$t1,16
++	srlg	$i3,$t1,24
++	nr	$t1,$mask
++	nr	$i1,$mask
++	nr	$i2,$mask
++
++	la	$key,32($key)		# key+=8
++	la	$t3,4($t3)		# i++
++	j	.L256_loop
++
++.Lminus1:
++	lghi	%r2,-1
++	br	$ra
++.size	AES_set_encrypt_key,.-AES_set_encrypt_key
++
++# void AES_set_decrypt_key(const unsigned char *in, int bits,
++# 		 AES_KEY *key) {
++.globl	AES_set_decrypt_key
++.type	AES_set_decrypt_key,\@function
++.align	16
++AES_set_decrypt_key:
++	#st${g}	$key,4*$SIZE_T($sp)	# I rely on AES_set_encrypt_key to
++	st${g}	$ra,14*$SIZE_T($sp)	# save non-volatile registers and $key!
++	bras	$ra,_s390x_AES_set_encrypt_key
++	#l${g}	$key,4*$SIZE_T($sp)
++	l${g}	$ra,14*$SIZE_T($sp)
++	ltgr	%r2,%r2
++	bnzr	$ra
++___
++$code.=<<___ if (!$softonly);
++	#l	$t0,240($key)
++	lhi	$t1,16
++	cr	$t0,$t1
++	jl	.Lgo
++	oill	$t0,0x80	# set "decrypt" bit
++	st	$t0,240($key)
++	br	$ra
++___
++$code.=<<___;
++.align	16
++.Lgo:	lgr	$rounds,$t0	#llgf	$rounds,240($key)
++	la	$i1,0($key)
++	sllg	$i2,$rounds,4
++	la	$i2,0($i2,$key)
++	srl	$rounds,1
++	lghi	$t1,-16
++
++.align	16
++.Linv:	lmg	$s0,$s1,0($i1)
++	lmg	$s2,$s3,0($i2)
++	stmg	$s0,$s1,0($i2)
++	stmg	$s2,$s3,0($i1)
++	la	$i1,16($i1)
++	la	$i2,0($t1,$i2)
++	brct	$rounds,.Linv
++___
++$mask80=$i1;
++$mask1b=$i2;
++$maskfe=$i3;
++$code.=<<___;
++	llgf	$rounds,240($key)
++	aghi	$rounds,-1
++	sll	$rounds,2	# (rounds-1)*4
++	llilh	$mask80,0x8080
++	llilh	$mask1b,0x1b1b
++	llilh	$maskfe,0xfefe
++	oill	$mask80,0x8080
++	oill	$mask1b,0x1b1b
++	oill	$maskfe,0xfefe
++
++.align	16
++.Lmix:	l	$s0,16($key)	# tp1
++	lr	$s1,$s0
++	ngr	$s1,$mask80
++	srlg	$t1,$s1,7
++	slr	$s1,$t1
++	nr	$s1,$mask1b
++	sllg	$t1,$s0,1
++	nr	$t1,$maskfe
++	xr	$s1,$t1		# tp2
++
++	lr	$s2,$s1
++	ngr	$s2,$mask80
++	srlg	$t1,$s2,7
++	slr	$s2,$t1
++	nr	$s2,$mask1b
++	sllg	$t1,$s1,1
++	nr	$t1,$maskfe
++	xr	$s2,$t1		# tp4
++
++	lr	$s3,$s2
++	ngr	$s3,$mask80
++	srlg	$t1,$s3,7
++	slr	$s3,$t1
++	nr	$s3,$mask1b
++	sllg	$t1,$s2,1
++	nr	$t1,$maskfe
++	xr	$s3,$t1		# tp8
++
++	xr	$s1,$s0		# tp2^tp1
++	xr	$s2,$s0		# tp4^tp1
++	rll	$s0,$s0,24	# = ROTATE(tp1,8)
++	xr	$s2,$s3		# ^=tp8
++	xr	$s0,$s1		# ^=tp2^tp1
++	xr	$s1,$s3		# tp2^tp1^tp8
++	xr	$s0,$s2		# ^=tp4^tp1^tp8
++	rll	$s1,$s1,8
++	rll	$s2,$s2,16
++	xr	$s0,$s1		# ^= ROTATE(tp8^tp2^tp1,24)
++	rll	$s3,$s3,24
++	xr	$s0,$s2    	# ^= ROTATE(tp8^tp4^tp1,16)
++	xr	$s0,$s3		# ^= ROTATE(tp8,8)
++
++	st	$s0,16($key)
++	la	$key,4($key)
++	brct	$rounds,.Lmix
++
++	lm${g}	%r6,%r13,6*$SIZE_T($sp)# as was saved by AES_set_encrypt_key!
++	lghi	%r2,0
++	br	$ra
++.size	AES_set_decrypt_key,.-AES_set_decrypt_key
++___
++
++########################################################################
++# void AES_cbc_encrypt(const unsigned char *in, unsigned char *out,
++#                     size_t length, const AES_KEY *key,
++#                     unsigned char *ivec, const int enc)
++{
++my $inp="%r2";
++my $out="%r4";	# length and out are swapped
++my $len="%r3";
++my $key="%r5";
++my $ivp="%r6";
++
++$code.=<<___;
++.globl	AES_cbc_encrypt
++.type	AES_cbc_encrypt,\@function
++.align	16
++AES_cbc_encrypt:
++	xgr	%r3,%r4		# flip %r3 and %r4, out and len
++	xgr	%r4,%r3
++	xgr	%r3,%r4
++___
++$code.=<<___ if (!$softonly);
++	lhi	%r0,16
++	cl	%r0,240($key)
++	jh	.Lcbc_software
++
++	lg	%r0,0($ivp)	# copy ivec
++	lg	%r1,8($ivp)
++	stmg	%r0,%r1,16($sp)
++	lmg	%r0,%r1,0($key)	# copy key, cover 256 bit
++	stmg	%r0,%r1,32($sp)
++	lmg	%r0,%r1,16($key)
++	stmg	%r0,%r1,48($sp)
++	l	%r0,240($key)	# load kmc code
++	lghi	$key,15		# res=len%16, len-=res;
++	ngr	$key,$len
++	sl${g}r	$len,$key
++	la	%r1,16($sp)	# parameter block - ivec || key
++	jz	.Lkmc_truncated
++	.long	0xb92f0042	# kmc %r4,%r2
++	brc	1,.-4		# pay attention to "partial completion"
++	ltr	$key,$key
++	jnz	.Lkmc_truncated
++.Lkmc_done:
++	lmg	%r0,%r1,16($sp)	# copy ivec to caller
++	stg	%r0,0($ivp)
++	stg	%r1,8($ivp)
++	br	$ra
++.align	16
++.Lkmc_truncated:
++	ahi	$key,-1		# it's the way it's encoded in mvc
++	tmll	%r0,0x80
++	jnz	.Lkmc_truncated_dec
++	lghi	%r1,0
++	stg	%r1,16*$SIZE_T($sp)
++	stg	%r1,16*$SIZE_T+8($sp)
++	bras	%r1,1f
++	mvc	16*$SIZE_T(1,$sp),0($inp)
++1:	ex	$key,0(%r1)
++	la	%r1,16($sp)	# restore parameter block
++	la	$inp,16*$SIZE_T($sp)
++	lghi	$len,16
++	.long	0xb92f0042	# kmc %r4,%r2
++	j	.Lkmc_done
++.align	16
++.Lkmc_truncated_dec:
++	st${g}	$out,4*$SIZE_T($sp)
++	la	$out,16*$SIZE_T($sp)
++	lghi	$len,16
++	.long	0xb92f0042	# kmc %r4,%r2
++	l${g}	$out,4*$SIZE_T($sp)
++	bras	%r1,2f
++	mvc	0(1,$out),16*$SIZE_T($sp)
++2:	ex	$key,0(%r1)
++	j	.Lkmc_done
++.align	16
++.Lcbc_software:
++___
++$code.=<<___;
++	stm${g}	$key,$ra,5*$SIZE_T($sp)
++	lhi	%r0,0
++	cl	%r0,`$stdframe+$SIZE_T-4`($sp)
++	je	.Lcbc_decrypt
++
++	larl	$tbl,AES_Te
++
++	llgf	$s0,0($ivp)
++	llgf	$s1,4($ivp)
++	llgf	$s2,8($ivp)
++	llgf	$s3,12($ivp)
++
++	lghi	$t0,16
++	sl${g}r	$len,$t0
++	brc	4,.Lcbc_enc_tail	# if borrow
++.Lcbc_enc_loop:
++	stm${g}	$inp,$out,2*$SIZE_T($sp)
++	x	$s0,0($inp)
++	x	$s1,4($inp)
++	x	$s2,8($inp)
++	x	$s3,12($inp)
++	lgr	%r4,$key
++
++	bras	$ra,_s390x_AES_encrypt
++
++	lm${g}	$inp,$key,2*$SIZE_T($sp)
++	st	$s0,0($out)
++	st	$s1,4($out)
++	st	$s2,8($out)
++	st	$s3,12($out)
++
++	la	$inp,16($inp)
++	la	$out,16($out)
++	lghi	$t0,16
++	lt${g}r	$len,$len
++	jz	.Lcbc_enc_done
++	sl${g}r	$len,$t0
++	brc	4,.Lcbc_enc_tail	# if borrow
++	j	.Lcbc_enc_loop
++.align	16
++.Lcbc_enc_done:
++	l${g}	$ivp,6*$SIZE_T($sp)
++	st	$s0,0($ivp)
++	st	$s1,4($ivp)	
++	st	$s2,8($ivp)
++	st	$s3,12($ivp)
++
++	lm${g}	%r7,$ra,7*$SIZE_T($sp)
++	br	$ra
++
++.align	16
++.Lcbc_enc_tail:
++	aghi	$len,15
++	lghi	$t0,0
++	stg	$t0,16*$SIZE_T($sp)
++	stg	$t0,16*$SIZE_T+8($sp)
++	bras	$t1,3f
++	mvc	16*$SIZE_T(1,$sp),0($inp)
++3:	ex	$len,0($t1)
++	lghi	$len,0
++	la	$inp,16*$SIZE_T($sp)
++	j	.Lcbc_enc_loop
++
++.align	16
++.Lcbc_decrypt:
++	larl	$tbl,AES_Td
++
++	lg	$t0,0($ivp)
++	lg	$t1,8($ivp)
++	stmg	$t0,$t1,16*$SIZE_T($sp)
++
++.Lcbc_dec_loop:
++	stm${g}	$inp,$out,2*$SIZE_T($sp)
++	llgf	$s0,0($inp)
++	llgf	$s1,4($inp)
++	llgf	$s2,8($inp)
++	llgf	$s3,12($inp)
++	lgr	%r4,$key
++
++	bras	$ra,_s390x_AES_decrypt
++
++	lm${g}	$inp,$key,2*$SIZE_T($sp)
++	sllg	$s0,$s0,32
++	sllg	$s2,$s2,32
++	lr	$s0,$s1
++	lr	$s2,$s3
++
++	lg	$t0,0($inp)
++	lg	$t1,8($inp)
++	xg	$s0,16*$SIZE_T($sp)
++	xg	$s2,16*$SIZE_T+8($sp)
++	lghi	$s1,16
++	sl${g}r	$len,$s1
++	brc	4,.Lcbc_dec_tail	# if borrow
++	brc	2,.Lcbc_dec_done	# if zero
++	stg	$s0,0($out)
++	stg	$s2,8($out)
++	stmg	$t0,$t1,16*$SIZE_T($sp)
++
++	la	$inp,16($inp)
++	la	$out,16($out)
++	j	.Lcbc_dec_loop
++
++.Lcbc_dec_done:
++	stg	$s0,0($out)
++	stg	$s2,8($out)
++.Lcbc_dec_exit:
++	lm${g}	%r6,$ra,6*$SIZE_T($sp)
++	stmg	$t0,$t1,0($ivp)
++
++	br	$ra
++
++.align	16
++.Lcbc_dec_tail:
++	aghi	$len,15
++	stg	$s0,16*$SIZE_T($sp)
++	stg	$s2,16*$SIZE_T+8($sp)
++	bras	$s1,4f
++	mvc	0(1,$out),16*$SIZE_T($sp)
++4:	ex	$len,0($s1)
++	j	.Lcbc_dec_exit
++.size	AES_cbc_encrypt,.-AES_cbc_encrypt
++___
++}
++########################################################################
++# void AES_ctr32_encrypt(const unsigned char *in, unsigned char *out,
++#                     size_t blocks, const AES_KEY *key,
++#                     const unsigned char *ivec)
++{
++my $inp="%r2";
++my $out="%r4";	# blocks and out are swapped
++my $len="%r3";
++my $key="%r5";	my $iv0="%r5";
++my $ivp="%r6";
++my $fp ="%r7";
++
++$code.=<<___;
++.globl	AES_ctr32_encrypt
++.type	AES_ctr32_encrypt,\@function
++.align	16
++AES_ctr32_encrypt:
++	xgr	%r3,%r4		# flip %r3 and %r4, $out and $len
++	xgr	%r4,%r3
++	xgr	%r3,%r4
++	llgfr	$len,$len	# safe in ctr32 subroutine even in 64-bit case
++___
++$code.=<<___ if (!$softonly);
++	l	%r0,240($key)
++	lhi	%r1,16
++	clr	%r0,%r1
++	jl	.Lctr32_software
++
++	stm${g}	%r6,$s3,6*$SIZE_T($sp)
++
++	slgr	$out,$inp
++	la	%r1,0($key)	# %r1 is permanent copy of $key
++	lg	$iv0,0($ivp)	# load ivec
++	lg	$ivp,8($ivp)
++
++	# prepare and allocate stack frame at the top of 4K page
++	# with 1K reserved for eventual signal handling
++	lghi	$s0,-1024-256-16# guarantee at least 256-bytes buffer
++	lghi	$s1,-4096
++	algr	$s0,$sp
++	lgr	$fp,$sp
++	ngr	$s0,$s1		# align at page boundary
++	slgr	$fp,$s0		# total buffer size
++	lgr	$s2,$sp
++	lghi	$s1,1024+16	# sl[g]fi is extended-immediate facility
++	slgr	$fp,$s1		# deduct reservation to get usable buffer size
++	# buffer size is at lest 256 and at most 3072+256-16
++
++	la	$sp,1024($s0)	# alloca
++	srlg	$fp,$fp,4	# convert bytes to blocks, minimum 16
++	st${g}	$s2,0($sp)	# back-chain
++	st${g}	$fp,$SIZE_T($sp)
++
++	slgr	$len,$fp
++	brc	1,.Lctr32_hw_switch	# not zero, no borrow
++	algr	$fp,$len	# input is shorter than allocated buffer
++	lghi	$len,0
++	st${g}	$fp,$SIZE_T($sp)
++
++.Lctr32_hw_switch:
++___
++$code.=<<___ if (0);	######### kmctr code was measured to be ~12% slower
++	larl	$s0,OPENSSL_s390xcap_P
++	lg	$s0,8($s0)
++	tmhh	$s0,0x0004	# check for message_security-assist-4
++	jz	.Lctr32_km_loop
++
++	llgfr	$s0,%r0
++	lgr	$s1,%r1
++	larl	%r1,OPENSSL_s390xcap_P
++	llihh	%r0,0x8000	# check if kmctr supports the function code
++	srlg	%r0,%r0,0($s0)
++	ng	%r0,64(%r1)	# check kmctr capability vector
++	lgr	%r0,$s0
++	lgr	%r1,$s1
++	jz	.Lctr32_km_loop
++
++####### kmctr code
++	algr	$out,$inp	# restore $out
++	lgr	$s1,$len	# $s1 undertakes $len
++	j	.Lctr32_kmctr_loop
++.align	16
++.Lctr32_kmctr_loop:
++	la	$s2,16($sp)
++	lgr	$s3,$fp
++.Lctr32_kmctr_prepare:
++	stg	$iv0,0($s2)
++	stg	$ivp,8($s2)
++	la	$s2,16($s2)
++	ahi	$ivp,1		# 32-bit increment, preserves upper half
++	brct	$s3,.Lctr32_kmctr_prepare
++
++	#la	$inp,0($inp)	# inp
++	sllg	$len,$fp,4	# len
++	#la	$out,0($out)	# out
++	la	$s2,16($sp)	# iv
++	.long	0xb92da042	# kmctr $out,$s2,$inp
++	brc	1,.-4		# pay attention to "partial completion"
++
++	slgr	$s1,$fp
++	brc	1,.Lctr32_kmctr_loop	# not zero, no borrow
++	algr	$fp,$s1
++	lghi	$s1,0
++	brc	4+1,.Lctr32_kmctr_loop	# not zero
++
++	l${g}	$sp,0($sp)
++	lm${g}	%r6,$s3,6*$SIZE_T($sp)
++	br	$ra
++.align	16
++___
++$code.=<<___;
++.Lctr32_km_loop:
++	la	$s2,16($sp)
++	lgr	$s3,$fp
++.Lctr32_km_prepare:
++	stg	$iv0,0($s2)
++	stg	$ivp,8($s2)
++	la	$s2,16($s2)
++	ahi	$ivp,1		# 32-bit increment, preserves upper half
++	brct	$s3,.Lctr32_km_prepare
++
++	la	$s0,16($sp)	# inp
++	sllg	$s1,$fp,4	# len
++	la	$s2,16($sp)	# out
++	.long	0xb92e00a8	# km %r10,%r8
++	brc	1,.-4		# pay attention to "partial completion"
++
++	la	$s2,16($sp)
++	lgr	$s3,$fp
++	slgr	$s2,$inp
++.Lctr32_km_xor:
++	lg	$s0,0($inp)
++	lg	$s1,8($inp)
++	xg	$s0,0($s2,$inp)
++	xg	$s1,8($s2,$inp)
++	stg	$s0,0($out,$inp)
++	stg	$s1,8($out,$inp)
++	la	$inp,16($inp)
++	brct	$s3,.Lctr32_km_xor
++
++	slgr	$len,$fp
++	brc	1,.Lctr32_km_loop	# not zero, no borrow
++	algr	$fp,$len
++	lghi	$len,0
++	brc	4+1,.Lctr32_km_loop	# not zero
++
++	l${g}	$s0,0($sp)
++	l${g}	$s1,$SIZE_T($sp)
++	la	$s2,16($sp)
++.Lctr32_km_zap:
++	stg	$s0,0($s2)
++	stg	$s0,8($s2)
++	la	$s2,16($s2)
++	brct	$s1,.Lctr32_km_zap
++
++	la	$sp,0($s0)
++	lm${g}	%r6,$s3,6*$SIZE_T($sp)
++	br	$ra
++.align	16
++.Lctr32_software:
++___
++$code.=<<___;
++	stm${g}	$key,$ra,5*$SIZE_T($sp)
++	sl${g}r	$inp,$out
++	larl	$tbl,AES_Te
++	llgf	$t1,12($ivp)
++
++.Lctr32_loop:
++	stm${g}	$inp,$out,2*$SIZE_T($sp)
++	llgf	$s0,0($ivp)
++	llgf	$s1,4($ivp)
++	llgf	$s2,8($ivp)
++	lgr	$s3,$t1
++	st	$t1,16*$SIZE_T($sp)
++	lgr	%r4,$key
++
++	bras	$ra,_s390x_AES_encrypt
++
++	lm${g}	$inp,$ivp,2*$SIZE_T($sp)
++	llgf	$t1,16*$SIZE_T($sp)
++	x	$s0,0($inp,$out)
++	x	$s1,4($inp,$out)
++	x	$s2,8($inp,$out)
++	x	$s3,12($inp,$out)
++	stm	$s0,$s3,0($out)
++
++	la	$out,16($out)
++	ahi	$t1,1		# 32-bit increment
++	brct	$len,.Lctr32_loop
++
++	lm${g}	%r6,$ra,6*$SIZE_T($sp)
++	br	$ra
++.size	AES_ctr32_encrypt,.-AES_ctr32_encrypt
++___
++}
++
++########################################################################
++# void AES_xts_encrypt(const char *inp,char *out,size_t len,
++#	const AES_KEY *key1, const AES_KEY *key2,
++#	const unsigned char iv[16]);
++#
++{
++my $inp="%r2";
++my $out="%r4";	# len and out are swapped
++my $len="%r3";
++my $key1="%r5";	# $i1
++my $key2="%r6";	# $i2
++my $fp="%r7";	# $i3
++my $tweak=16*$SIZE_T+16;	# or $stdframe-16, bottom of the frame...
++
++$code.=<<___;
++.type	_s390x_xts_km,\@function
++.align	16
++_s390x_xts_km:
++___
++$code.=<<___ if(1);
++	llgfr	$s0,%r0			# put aside the function code
++	lghi	$s1,0x7f
++	nr	$s1,%r0
++	larl	%r1,OPENSSL_s390xcap_P
++	llihh	%r0,0x8000
++	srlg	%r0,%r0,32($s1)		# check for 32+function code
++	ng	%r0,32(%r1)		# check km capability vector
++	lgr	%r0,$s0			# restore the function code
++	la	%r1,0($key1)		# restore $key1
++	jz	.Lxts_km_vanilla
++
++	lmg	$i2,$i3,$tweak($sp)	# put aside the tweak value
++	algr	$out,$inp
++
++	oill	%r0,32			# switch to xts function code
++	aghi	$s1,-18			#
++	sllg	$s1,$s1,3		# (function code - 18)*8, 0 or 16
++	la	%r1,$tweak-16($sp)
++	slgr	%r1,$s1			# parameter block position
++	lmg	$s0,$s3,0($key1)	# load 256 bits of key material,
++	stmg	$s0,$s3,0(%r1)		# and copy it to parameter block.
++					# yes, it contains junk and overlaps
++					# with the tweak in 128-bit case.
++					# it's done to avoid conditional
++					# branch.
++	stmg	$i2,$i3,$tweak($sp)	# "re-seat" the tweak value
++
++	.long	0xb92e0042		# km %r4,%r2
++	brc	1,.-4			# pay attention to "partial completion"
++
++	lrvg	$s0,$tweak+0($sp)	# load the last tweak
++	lrvg	$s1,$tweak+8($sp)
++	stmg	%r0,%r3,$tweak-32($sp)	# wipe copy of the key
++
++	nill	%r0,0xffdf		# switch back to original function code
++	la	%r1,0($key1)		# restore pointer to $key1
++	slgr	$out,$inp
++
++	llgc	$len,2*$SIZE_T-1($sp)
++	nill	$len,0x0f		# $len%=16
++	br	$ra
++	
++.align	16
++.Lxts_km_vanilla:
++___
++$code.=<<___;
++	# prepare and allocate stack frame at the top of 4K page
++	# with 1K reserved for eventual signal handling
++	lghi	$s0,-1024-256-16# guarantee at least 256-bytes buffer
++	lghi	$s1,-4096
++	algr	$s0,$sp
++	lgr	$fp,$sp
++	ngr	$s0,$s1		# align at page boundary
++	slgr	$fp,$s0		# total buffer size
++	lgr	$s2,$sp
++	lghi	$s1,1024+16	# sl[g]fi is extended-immediate facility
++	slgr	$fp,$s1		# deduct reservation to get usable buffer size
++	# buffer size is at lest 256 and at most 3072+256-16
++
++	la	$sp,1024($s0)	# alloca
++	nill	$fp,0xfff0	# round to 16*n
++	st${g}	$s2,0($sp)	# back-chain
++	nill	$len,0xfff0	# redundant
++	st${g}	$fp,$SIZE_T($sp)
++
++	slgr	$len,$fp
++	brc	1,.Lxts_km_go	# not zero, no borrow
++	algr	$fp,$len	# input is shorter than allocated buffer
++	lghi	$len,0
++	st${g}	$fp,$SIZE_T($sp)
++
++.Lxts_km_go:
++	lrvg	$s0,$tweak+0($s2)	# load the tweak value in little-endian
++	lrvg	$s1,$tweak+8($s2)
++
++	la	$s2,16($sp)		# vector of ascending tweak values
++	slgr	$s2,$inp
++	srlg	$s3,$fp,4
++	j	.Lxts_km_start
++
++.Lxts_km_loop:
++	la	$s2,16($sp)
++	slgr	$s2,$inp
++	srlg	$s3,$fp,4
++.Lxts_km_prepare:
++	lghi	$i1,0x87
++	srag	$i2,$s1,63		# broadcast upper bit
++	ngr	$i1,$i2			# rem
++	algr	$s0,$s0
++	alcgr	$s1,$s1
++	xgr	$s0,$i1
++.Lxts_km_start:
++	lrvgr	$i1,$s0			# flip byte order
++	lrvgr	$i2,$s1
++	stg	$i1,0($s2,$inp)
++	stg	$i2,8($s2,$inp)
++	xg	$i1,0($inp)
++	xg	$i2,8($inp)
++	stg	$i1,0($out,$inp)
++	stg	$i2,8($out,$inp)
++	la	$inp,16($inp)
++	brct	$s3,.Lxts_km_prepare
++
++	slgr	$inp,$fp		# rewind $inp
++	la	$s2,0($out,$inp)
++	lgr	$s3,$fp
++	.long	0xb92e00aa		# km $s2,$s2
++	brc	1,.-4			# pay attention to "partial completion"
++
++	la	$s2,16($sp)
++	slgr	$s2,$inp
++	srlg	$s3,$fp,4
++.Lxts_km_xor:
++	lg	$i1,0($out,$inp)
++	lg	$i2,8($out,$inp)
++	xg	$i1,0($s2,$inp)
++	xg	$i2,8($s2,$inp)
++	stg	$i1,0($out,$inp)
++	stg	$i2,8($out,$inp)
++	la	$inp,16($inp)
++	brct	$s3,.Lxts_km_xor
++
++	slgr	$len,$fp
++	brc	1,.Lxts_km_loop		# not zero, no borrow
++	algr	$fp,$len
++	lghi	$len,0
++	brc	4+1,.Lxts_km_loop	# not zero
++
++	l${g}	$i1,0($sp)		# back-chain
++	llgf	$fp,`2*$SIZE_T-4`($sp)	# bytes used
++	la	$i2,16($sp)
++	srlg	$fp,$fp,4
++.Lxts_km_zap:
++	stg	$i1,0($i2)
++	stg	$i1,8($i2)
++	la	$i2,16($i2)
++	brct	$fp,.Lxts_km_zap
++
++	la	$sp,0($i1)
++	llgc	$len,2*$SIZE_T-1($i1)
++	nill	$len,0x0f		# $len%=16
++	bzr	$ra
++
++	# generate one more tweak...
++	lghi	$i1,0x87
++	srag	$i2,$s1,63		# broadcast upper bit
++	ngr	$i1,$i2			# rem
++	algr	$s0,$s0
++	alcgr	$s1,$s1
++	xgr	$s0,$i1
++
++	ltr	$len,$len		# clear zero flag
++	br	$ra
++.size	_s390x_xts_km,.-_s390x_xts_km
++
++.globl	AES_xts_encrypt
++.type	AES_xts_encrypt,\@function
++.align	16
++AES_xts_encrypt:
++	xgr	%r3,%r4			# flip %r3 and %r4, $out and $len
++	xgr	%r4,%r3
++	xgr	%r3,%r4
++___
++$code.=<<___ if ($SIZE_T==4);
++	llgfr	$len,$len
++___
++$code.=<<___;
++	st${g}	$len,1*$SIZE_T($sp)	# save copy of $len
++	srag	$len,$len,4		# formally wrong, because it expands
++					# sign byte, but who can afford asking
++					# to process more than 2^63-1 bytes?
++					# I use it, because it sets condition
++					# code...
++	bcr	8,$ra			# abort if zero (i.e. less than 16)
++___
++$code.=<<___ if (!$softonly);
++	llgf	%r0,240($key2)
++	lhi	%r1,16
++	clr	%r0,%r1
++	jl	.Lxts_enc_software
++
++	st${g}	$ra,5*$SIZE_T($sp)
++	stm${g}	%r6,$s3,6*$SIZE_T($sp)
++
++	sllg	$len,$len,4		# $len&=~15
++	slgr	$out,$inp
++
++	# generate the tweak value
++	l${g}	$s3,$stdframe($sp)	# pointer to iv
++	la	$s2,$tweak($sp)
++	lmg	$s0,$s1,0($s3)
++	lghi	$s3,16
++	stmg	$s0,$s1,0($s2)
++	la	%r1,0($key2)		# $key2 is not needed anymore
++	.long	0xb92e00aa		# km $s2,$s2, generate the tweak
++	brc	1,.-4			# can this happen?
++
++	l	%r0,240($key1)
++	la	%r1,0($key1)		# $key1 is not needed anymore
++	bras	$ra,_s390x_xts_km
++	jz	.Lxts_enc_km_done
++
++	aghi	$inp,-16		# take one step back
++	la	$i3,0($out,$inp)	# put aside real $out
++.Lxts_enc_km_steal:
++	llgc	$i1,16($inp)
++	llgc	$i2,0($out,$inp)
++	stc	$i1,0($out,$inp)
++	stc	$i2,16($out,$inp)
++	la	$inp,1($inp)
++	brct	$len,.Lxts_enc_km_steal
++
++	la	$s2,0($i3)
++	lghi	$s3,16
++	lrvgr	$i1,$s0			# flip byte order
++	lrvgr	$i2,$s1
++	xg	$i1,0($s2)
++	xg	$i2,8($s2)
++	stg	$i1,0($s2)
++	stg	$i2,8($s2)
++	.long	0xb92e00aa		# km $s2,$s2
++	brc	1,.-4			# can this happen?
++	lrvgr	$i1,$s0			# flip byte order
++	lrvgr	$i2,$s1
++	xg	$i1,0($i3)
++	xg	$i2,8($i3)
++	stg	$i1,0($i3)
++	stg	$i2,8($i3)
++
++.Lxts_enc_km_done:
++	stg	$sp,$tweak+0($sp)	# wipe tweak
++	stg	$sp,$tweak+8($sp)
++	l${g}	$ra,5*$SIZE_T($sp)
++	lm${g}	%r6,$s3,6*$SIZE_T($sp)
++	br	$ra
++.align	16
++.Lxts_enc_software:
++___
++$code.=<<___;
++	stm${g}	%r6,$ra,6*$SIZE_T($sp)
++
++	slgr	$out,$inp
++
++	l${g}	$s3,$stdframe($sp)	# ivp
++	llgf	$s0,0($s3)		# load iv
++	llgf	$s1,4($s3)
++	llgf	$s2,8($s3)
++	llgf	$s3,12($s3)
++	stm${g}	%r2,%r5,2*$SIZE_T($sp)
++	la	$key,0($key2)
++	larl	$tbl,AES_Te
++	bras	$ra,_s390x_AES_encrypt	# generate the tweak
++	lm${g}	%r2,%r5,2*$SIZE_T($sp)
++	stm	$s0,$s3,$tweak($sp)	# save the tweak
++	j	.Lxts_enc_enter
++
++.align	16
++.Lxts_enc_loop:
++	lrvg	$s1,$tweak+0($sp)	# load the tweak in little-endian
++	lrvg	$s3,$tweak+8($sp)
++	lghi	%r1,0x87
++	srag	%r0,$s3,63		# broadcast upper bit
++	ngr	%r1,%r0			# rem
++	algr	$s1,$s1
++	alcgr	$s3,$s3
++	xgr	$s1,%r1
++	lrvgr	$s1,$s1			# flip byte order
++	lrvgr	$s3,$s3
++	srlg	$s0,$s1,32		# smash the tweak to 4x32-bits 
++	stg	$s1,$tweak+0($sp)	# save the tweak
++	llgfr	$s1,$s1
++	srlg	$s2,$s3,32
++	stg	$s3,$tweak+8($sp)
++	llgfr	$s3,$s3
++	la	$inp,16($inp)		# $inp+=16
++.Lxts_enc_enter:
++	x	$s0,0($inp)		# ^=*($inp)
++	x	$s1,4($inp)
++	x	$s2,8($inp)
++	x	$s3,12($inp)
++	stm${g}	%r2,%r3,2*$SIZE_T($sp)	# only two registers are changing
++	la	$key,0($key1)
++	bras	$ra,_s390x_AES_encrypt
++	lm${g}	%r2,%r5,2*$SIZE_T($sp)
++	x	$s0,$tweak+0($sp)	# ^=tweak
++	x	$s1,$tweak+4($sp)
++	x	$s2,$tweak+8($sp)
++	x	$s3,$tweak+12($sp)
++	st	$s0,0($out,$inp)
++	st	$s1,4($out,$inp)
++	st	$s2,8($out,$inp)
++	st	$s3,12($out,$inp)
++	brct${g}	$len,.Lxts_enc_loop
++
++	llgc	$len,`2*$SIZE_T-1`($sp)
++	nill	$len,0x0f		# $len%16
++	jz	.Lxts_enc_done
++
++	la	$i3,0($inp,$out)	# put aside real $out
++.Lxts_enc_steal:
++	llgc	%r0,16($inp)
++	llgc	%r1,0($out,$inp)
++	stc	%r0,0($out,$inp)
++	stc	%r1,16($out,$inp)
++	la	$inp,1($inp)
++	brct	$len,.Lxts_enc_steal
++	la	$out,0($i3)		# restore real $out
++
++	# generate last tweak...
++	lrvg	$s1,$tweak+0($sp)	# load the tweak in little-endian
++	lrvg	$s3,$tweak+8($sp)
++	lghi	%r1,0x87
++	srag	%r0,$s3,63		# broadcast upper bit
++	ngr	%r1,%r0			# rem
++	algr	$s1,$s1
++	alcgr	$s3,$s3
++	xgr	$s1,%r1
++	lrvgr	$s1,$s1			# flip byte order
++	lrvgr	$s3,$s3
++	srlg	$s0,$s1,32		# smash the tweak to 4x32-bits 
++	stg	$s1,$tweak+0($sp)	# save the tweak
++	llgfr	$s1,$s1
++	srlg	$s2,$s3,32
++	stg	$s3,$tweak+8($sp)
++	llgfr	$s3,$s3
++
++	x	$s0,0($out)		# ^=*(inp)|stolen cipther-text
++	x	$s1,4($out)
++	x	$s2,8($out)
++	x	$s3,12($out)
++	st${g}	$out,4*$SIZE_T($sp)
++	la	$key,0($key1)
++	bras	$ra,_s390x_AES_encrypt
++	l${g}	$out,4*$SIZE_T($sp)
++	x	$s0,`$tweak+0`($sp)	# ^=tweak
++	x	$s1,`$tweak+4`($sp)
++	x	$s2,`$tweak+8`($sp)
++	x	$s3,`$tweak+12`($sp)
++	st	$s0,0($out)
++	st	$s1,4($out)
++	st	$s2,8($out)
++	st	$s3,12($out)
++
++.Lxts_enc_done:
++	stg	$sp,$tweak+0($sp)	# wipe tweak
++	stg	$sp,$twesk+8($sp)
++	lm${g}	%r6,$ra,6*$SIZE_T($sp)
++	br	$ra
++.size	AES_xts_encrypt,.-AES_xts_encrypt
++___
++# void AES_xts_decrypt(const char *inp,char *out,size_t len,
++#	const AES_KEY *key1, const AES_KEY *key2,
++#	const unsigned char iv[16]);
++#
++$code.=<<___;
++.globl	AES_xts_decrypt
++.type	AES_xts_decrypt,\@function
++.align	16
++AES_xts_decrypt:
++	xgr	%r3,%r4			# flip %r3 and %r4, $out and $len
++	xgr	%r4,%r3
++	xgr	%r3,%r4
++___
++$code.=<<___ if ($SIZE_T==4);
++	llgfr	$len,$len
++___
++$code.=<<___;
++	st${g}	$len,1*$SIZE_T($sp)	# save copy of $len
++	aghi	$len,-16
++	bcr	4,$ra			# abort if less than zero. formally
++					# wrong, because $len is unsigned,
++					# but who can afford asking to
++					# process more than 2^63-1 bytes?
++	tmll	$len,0x0f
++	jnz	.Lxts_dec_proceed
++	aghi	$len,16
++.Lxts_dec_proceed:
++___
++$code.=<<___ if (!$softonly);
++	llgf	%r0,240($key2)
++	lhi	%r1,16
++	clr	%r0,%r1
++	jl	.Lxts_dec_software
++
++	st${g}	$ra,5*$SIZE_T($sp)
++	stm${g}	%r6,$s3,6*$SIZE_T($sp)
++
++	nill	$len,0xfff0		# $len&=~15
++	slgr	$out,$inp
++
++	# generate the tweak value
++	l${g}	$s3,$stdframe($sp)	# pointer to iv
++	la	$s2,$tweak($sp)
++	lmg	$s0,$s1,0($s3)
++	lghi	$s3,16
++	stmg	$s0,$s1,0($s2)
++	la	%r1,0($key2)		# $key2 is not needed past this point
++	.long	0xb92e00aa		# km $s2,$s2, generate the tweak
++	brc	1,.-4			# can this happen?
++
++	l	%r0,240($key1)
++	la	%r1,0($key1)		# $key1 is not needed anymore
++
++	ltgr	$len,$len
++	jz	.Lxts_dec_km_short
++	bras	$ra,_s390x_xts_km
++	jz	.Lxts_dec_km_done
++
++	lrvgr	$s2,$s0			# make copy in reverse byte order
++	lrvgr	$s3,$s1
++	j	.Lxts_dec_km_2ndtweak
++
++.Lxts_dec_km_short:
++	llgc	$len,`2*$SIZE_T-1`($sp)
++	nill	$len,0x0f		# $len%=16
++	lrvg	$s0,$tweak+0($sp)	# load the tweak
++	lrvg	$s1,$tweak+8($sp)
++	lrvgr	$s2,$s0			# make copy in reverse byte order
++	lrvgr	$s3,$s1
++
++.Lxts_dec_km_2ndtweak:
++	lghi	$i1,0x87
++	srag	$i2,$s1,63		# broadcast upper bit
++	ngr	$i1,$i2			# rem
++	algr	$s0,$s0
++	alcgr	$s1,$s1
++	xgr	$s0,$i1
++	lrvgr	$i1,$s0			# flip byte order
++	lrvgr	$i2,$s1
++
++	xg	$i1,0($inp)
++	xg	$i2,8($inp)
++	stg	$i1,0($out,$inp)
++	stg	$i2,8($out,$inp)
++	la	$i2,0($out,$inp)
++	lghi	$i3,16
++	.long	0xb92e0066		# km $i2,$i2
++	brc	1,.-4			# can this happen?
++	lrvgr	$i1,$s0
++	lrvgr	$i2,$s1
++	xg	$i1,0($out,$inp)
++	xg	$i2,8($out,$inp)
++	stg	$i1,0($out,$inp)
++	stg	$i2,8($out,$inp)
++
++	la	$i3,0($out,$inp)	# put aside real $out
++.Lxts_dec_km_steal:
++	llgc	$i1,16($inp)
++	llgc	$i2,0($out,$inp)
++	stc	$i1,0($out,$inp)
++	stc	$i2,16($out,$inp)
++	la	$inp,1($inp)
++	brct	$len,.Lxts_dec_km_steal
++
++	lgr	$s0,$s2
++	lgr	$s1,$s3
++	xg	$s0,0($i3)
++	xg	$s1,8($i3)
++	stg	$s0,0($i3)
++	stg	$s1,8($i3)
++	la	$s0,0($i3)
++	lghi	$s1,16
++	.long	0xb92e0088		# km $s0,$s0
++	brc	1,.-4			# can this happen?
++	xg	$s2,0($i3)
++	xg	$s3,8($i3)
++	stg	$s2,0($i3)
++	stg	$s3,8($i3)
++.Lxts_dec_km_done:
++	stg	$sp,$tweak+0($sp)	# wipe tweak
++	stg	$sp,$tweak+8($sp)
++	l${g}	$ra,5*$SIZE_T($sp)
++	lm${g}	%r6,$s3,6*$SIZE_T($sp)
++	br	$ra
++.align	16
++.Lxts_dec_software:
++___
++$code.=<<___;
++	stm${g}	%r6,$ra,6*$SIZE_T($sp)
++
++	srlg	$len,$len,4
++	slgr	$out,$inp
++
++	l${g}	$s3,$stdframe($sp)	# ivp
++	llgf	$s0,0($s3)		# load iv
++	llgf	$s1,4($s3)
++	llgf	$s2,8($s3)
++	llgf	$s3,12($s3)
++	stm${g}	%r2,%r5,2*$SIZE_T($sp)
++	la	$key,0($key2)
++	larl	$tbl,AES_Te
++	bras	$ra,_s390x_AES_encrypt	# generate the tweak
++	lm${g}	%r2,%r5,2*$SIZE_T($sp)
++	larl	$tbl,AES_Td
++	lt${g}r	$len,$len
++	stm	$s0,$s3,$tweak($sp)	# save the tweak
++	jz	.Lxts_dec_short
++	j	.Lxts_dec_enter
++
++.align	16
++.Lxts_dec_loop:
++	lrvg	$s1,$tweak+0($sp)	# load the tweak in little-endian
++	lrvg	$s3,$tweak+8($sp)
++	lghi	%r1,0x87
++	srag	%r0,$s3,63		# broadcast upper bit
++	ngr	%r1,%r0			# rem
++	algr	$s1,$s1
++	alcgr	$s3,$s3
++	xgr	$s1,%r1
++	lrvgr	$s1,$s1			# flip byte order
++	lrvgr	$s3,$s3
++	srlg	$s0,$s1,32		# smash the tweak to 4x32-bits 
++	stg	$s1,$tweak+0($sp)	# save the tweak
++	llgfr	$s1,$s1
++	srlg	$s2,$s3,32
++	stg	$s3,$tweak+8($sp)
++	llgfr	$s3,$s3
++.Lxts_dec_enter:
++	x	$s0,0($inp)		# tweak^=*(inp)
++	x	$s1,4($inp)
++	x	$s2,8($inp)
++	x	$s3,12($inp)
++	stm${g}	%r2,%r3,2*$SIZE_T($sp)	# only two registers are changing
++	la	$key,0($key1)
++	bras	$ra,_s390x_AES_decrypt
++	lm${g}	%r2,%r5,2*$SIZE_T($sp)
++	x	$s0,$tweak+0($sp)	# ^=tweak
++	x	$s1,$tweak+4($sp)
++	x	$s2,$tweak+8($sp)
++	x	$s3,$tweak+12($sp)
++	st	$s0,0($out,$inp)
++	st	$s1,4($out,$inp)
++	st	$s2,8($out,$inp)
++	st	$s3,12($out,$inp)
++	la	$inp,16($inp)
++	brct${g}	$len,.Lxts_dec_loop
++
++	llgc	$len,`2*$SIZE_T-1`($sp)
++	nill	$len,0x0f		# $len%16
++	jz	.Lxts_dec_done
++
++	# generate pair of tweaks...
++	lrvg	$s1,$tweak+0($sp)	# load the tweak in little-endian
++	lrvg	$s3,$tweak+8($sp)
++	lghi	%r1,0x87
++	srag	%r0,$s3,63		# broadcast upper bit
++	ngr	%r1,%r0			# rem
++	algr	$s1,$s1
++	alcgr	$s3,$s3
++	xgr	$s1,%r1
++	lrvgr	$i2,$s1			# flip byte order
++	lrvgr	$i3,$s3
++	stmg	$i2,$i3,$tweak($sp)	# save the 1st tweak
++	j	.Lxts_dec_2ndtweak
++
++.align	16
++.Lxts_dec_short:
++	llgc	$len,`2*$SIZE_T-1`($sp)
++	nill	$len,0x0f		# $len%16
++	lrvg	$s1,$tweak+0($sp)	# load the tweak in little-endian
++	lrvg	$s3,$tweak+8($sp)
++.Lxts_dec_2ndtweak:
++	lghi	%r1,0x87
++	srag	%r0,$s3,63		# broadcast upper bit
++	ngr	%r1,%r0			# rem
++	algr	$s1,$s1
++	alcgr	$s3,$s3
++	xgr	$s1,%r1
++	lrvgr	$s1,$s1			# flip byte order
++	lrvgr	$s3,$s3
++	srlg	$s0,$s1,32		# smash the tweak to 4x32-bits
++	stg	$s1,$tweak-16+0($sp)	# save the 2nd tweak
++	llgfr	$s1,$s1
++	srlg	$s2,$s3,32
++	stg	$s3,$tweak-16+8($sp)
++	llgfr	$s3,$s3
++
++	x	$s0,0($inp)		# tweak_the_2nd^=*(inp)
++	x	$s1,4($inp)
++	x	$s2,8($inp)
++	x	$s3,12($inp)
++	stm${g}	%r2,%r3,2*$SIZE_T($sp)
++	la	$key,0($key1)
++	bras	$ra,_s390x_AES_decrypt
++	lm${g}	%r2,%r5,2*$SIZE_T($sp)
++	x	$s0,$tweak-16+0($sp)	# ^=tweak_the_2nd
++	x	$s1,$tweak-16+4($sp)
++	x	$s2,$tweak-16+8($sp)
++	x	$s3,$tweak-16+12($sp)
++	st	$s0,0($out,$inp)
++	st	$s1,4($out,$inp)
++	st	$s2,8($out,$inp)
++	st	$s3,12($out,$inp)
++
++	la	$i3,0($out,$inp)	# put aside real $out
++.Lxts_dec_steal:
++	llgc	%r0,16($inp)
++	llgc	%r1,0($out,$inp)
++	stc	%r0,0($out,$inp)
++	stc	%r1,16($out,$inp)
++	la	$inp,1($inp)
++	brct	$len,.Lxts_dec_steal
++	la	$out,0($i3)		# restore real $out
++
++	lm	$s0,$s3,$tweak($sp)	# load the 1st tweak
++	x	$s0,0($out)		# tweak^=*(inp)|stolen cipher-text
++	x	$s1,4($out)
++	x	$s2,8($out)
++	x	$s3,12($out)
++	st${g}	$out,4*$SIZE_T($sp)
++	la	$key,0($key1)
++	bras	$ra,_s390x_AES_decrypt
++	l${g}	$out,4*$SIZE_T($sp)
++	x	$s0,$tweak+0($sp)	# ^=tweak
++	x	$s1,$tweak+4($sp)
++	x	$s2,$tweak+8($sp)
++	x	$s3,$tweak+12($sp)
++	st	$s0,0($out)
++	st	$s1,4($out)
++	st	$s2,8($out)
++	st	$s3,12($out)
++	stg	$sp,$tweak-16+0($sp)	# wipe 2nd tweak
++	stg	$sp,$tweak-16+8($sp)
++.Lxts_dec_done:
++	stg	$sp,$tweak+0($sp)	# wipe tweak
++	stg	$sp,$twesk+8($sp)
++	lm${g}	%r6,$ra,6*$SIZE_T($sp)
++	br	$ra
++.size	AES_xts_decrypt,.-AES_xts_decrypt
++___
++}
++$code.=<<___;
++.string	"AES for s390x, CRYPTOGAMS by "
++.comm	OPENSSL_s390xcap_P,80,8
++___
++
++$code =~ s/\`([^\`]*)\`/eval $1/gem;
++print $code;
++close STDOUT;	# force flush
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/aes/asm/aes-sparcv9.pl b/CryptoPkg/Library/OpensslLib/openssl/crypto/aes/asm/aes-sparcv9.pl
+new file mode 100755
+index 0000000..883fae8
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/aes/asm/aes-sparcv9.pl
+@@ -0,0 +1,1192 @@
++#! /usr/bin/env perl
++# Copyright 2005-2016 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
++# in the file LICENSE in the source distribution or at
++# https://www.openssl.org/source/license.html
++
++#
++# ====================================================================
++# Written by Andy Polyakov  for the OpenSSL
++# project. Rights for redistribution and usage in source and binary
++# forms are granted according to the OpenSSL license.
++# ====================================================================
++#
++# Version 1.1
++#
++# The major reason for undertaken effort was to mitigate the hazard of
++# cache-timing attack. This is [currently and initially!] addressed in
++# two ways. 1. S-boxes are compressed from 5KB to 2KB+256B size each.
++# 2. References to them are scheduled for L2 cache latency, meaning
++# that the tables don't have to reside in L1 cache. Once again, this
++# is an initial draft and one should expect more countermeasures to
++# be implemented...
++#
++# Version 1.1 prefetches T[ed]4 in order to mitigate attack on last
++# round.
++#
++# Even though performance was not the primary goal [on the contrary,
++# extra shifts "induced" by compressed S-box and longer loop epilogue
++# "induced" by scheduling for L2 have negative effect on performance],
++# the code turned out to run in ~23 cycles per processed byte en-/
++# decrypted with 128-bit key. This is pretty good result for code
++# with mentioned qualities and UltraSPARC core. Compared to Sun C
++# generated code my encrypt procedure runs just few percents faster,
++# while decrypt one - whole 50% faster [yes, Sun C failed to generate
++# optimal decrypt procedure]. Compared to GNU C generated code both
++# procedures are more than 60% faster:-)
++
++$output = pop;
++open STDOUT,">$output";
++
++$frame="STACK_FRAME";
++$bias="STACK_BIAS";
++$locals=16;
++
++$acc0="%l0";
++$acc1="%o0";
++$acc2="%o1";
++$acc3="%o2";
++
++$acc4="%l1";
++$acc5="%o3";
++$acc6="%o4";
++$acc7="%o5";
++
++$acc8="%l2";
++$acc9="%o7";
++$acc10="%g1";
++$acc11="%g2";
++
++$acc12="%l3";
++$acc13="%g3";
++$acc14="%g4";
++$acc15="%g5";
++
++$t0="%l4";
++$t1="%l5";
++$t2="%l6";
++$t3="%l7";
++
++$s0="%i0";
++$s1="%i1";
++$s2="%i2";
++$s3="%i3";
++$tbl="%i4";
++$key="%i5";
++$rounds="%i7";	# aliases with return address, which is off-loaded to stack
++
++sub _data_word()
++{ my $i;
++    while(defined($i=shift)) { $code.=sprintf"\t.long\t0x%08x,0x%08x\n",$i,$i; }
++}
++
++$code.=<<___;
++#include "sparc_arch.h"
++
++#ifdef  __arch64__
++.register	%g2,#scratch
++.register	%g3,#scratch
++#endif
++.section	".text",#alloc,#execinstr
++
++.align	256
++AES_Te:
++___
++&_data_word(
++	0xc66363a5, 0xf87c7c84, 0xee777799, 0xf67b7b8d,
++	0xfff2f20d, 0xd66b6bbd, 0xde6f6fb1, 0x91c5c554,
++	0x60303050, 0x02010103, 0xce6767a9, 0x562b2b7d,
++	0xe7fefe19, 0xb5d7d762, 0x4dababe6, 0xec76769a,
++	0x8fcaca45, 0x1f82829d, 0x89c9c940, 0xfa7d7d87,
++	0xeffafa15, 0xb25959eb, 0x8e4747c9, 0xfbf0f00b,
++	0x41adadec, 0xb3d4d467, 0x5fa2a2fd, 0x45afafea,
++	0x239c9cbf, 0x53a4a4f7, 0xe4727296, 0x9bc0c05b,
++	0x75b7b7c2, 0xe1fdfd1c, 0x3d9393ae, 0x4c26266a,
++	0x6c36365a, 0x7e3f3f41, 0xf5f7f702, 0x83cccc4f,
++	0x6834345c, 0x51a5a5f4, 0xd1e5e534, 0xf9f1f108,
++	0xe2717193, 0xabd8d873, 0x62313153, 0x2a15153f,
++	0x0804040c, 0x95c7c752, 0x46232365, 0x9dc3c35e,
++	0x30181828, 0x379696a1, 0x0a05050f, 0x2f9a9ab5,
++	0x0e070709, 0x24121236, 0x1b80809b, 0xdfe2e23d,
++	0xcdebeb26, 0x4e272769, 0x7fb2b2cd, 0xea75759f,
++	0x1209091b, 0x1d83839e, 0x582c2c74, 0x341a1a2e,
++	0x361b1b2d, 0xdc6e6eb2, 0xb45a5aee, 0x5ba0a0fb,
++	0xa45252f6, 0x763b3b4d, 0xb7d6d661, 0x7db3b3ce,
++	0x5229297b, 0xdde3e33e, 0x5e2f2f71, 0x13848497,
++	0xa65353f5, 0xb9d1d168, 0x00000000, 0xc1eded2c,
++	0x40202060, 0xe3fcfc1f, 0x79b1b1c8, 0xb65b5bed,
++	0xd46a6abe, 0x8dcbcb46, 0x67bebed9, 0x7239394b,
++	0x944a4ade, 0x984c4cd4, 0xb05858e8, 0x85cfcf4a,
++	0xbbd0d06b, 0xc5efef2a, 0x4faaaae5, 0xedfbfb16,
++	0x864343c5, 0x9a4d4dd7, 0x66333355, 0x11858594,
++	0x8a4545cf, 0xe9f9f910, 0x04020206, 0xfe7f7f81,
++	0xa05050f0, 0x783c3c44, 0x259f9fba, 0x4ba8a8e3,
++	0xa25151f3, 0x5da3a3fe, 0x804040c0, 0x058f8f8a,
++	0x3f9292ad, 0x219d9dbc, 0x70383848, 0xf1f5f504,
++	0x63bcbcdf, 0x77b6b6c1, 0xafdada75, 0x42212163,
++	0x20101030, 0xe5ffff1a, 0xfdf3f30e, 0xbfd2d26d,
++	0x81cdcd4c, 0x180c0c14, 0x26131335, 0xc3ecec2f,
++	0xbe5f5fe1, 0x359797a2, 0x884444cc, 0x2e171739,
++	0x93c4c457, 0x55a7a7f2, 0xfc7e7e82, 0x7a3d3d47,
++	0xc86464ac, 0xba5d5de7, 0x3219192b, 0xe6737395,
++	0xc06060a0, 0x19818198, 0x9e4f4fd1, 0xa3dcdc7f,
++	0x44222266, 0x542a2a7e, 0x3b9090ab, 0x0b888883,
++	0x8c4646ca, 0xc7eeee29, 0x6bb8b8d3, 0x2814143c,
++	0xa7dede79, 0xbc5e5ee2, 0x160b0b1d, 0xaddbdb76,
++	0xdbe0e03b, 0x64323256, 0x743a3a4e, 0x140a0a1e,
++	0x924949db, 0x0c06060a, 0x4824246c, 0xb85c5ce4,
++	0x9fc2c25d, 0xbdd3d36e, 0x43acacef, 0xc46262a6,
++	0x399191a8, 0x319595a4, 0xd3e4e437, 0xf279798b,
++	0xd5e7e732, 0x8bc8c843, 0x6e373759, 0xda6d6db7,
++	0x018d8d8c, 0xb1d5d564, 0x9c4e4ed2, 0x49a9a9e0,
++	0xd86c6cb4, 0xac5656fa, 0xf3f4f407, 0xcfeaea25,
++	0xca6565af, 0xf47a7a8e, 0x47aeaee9, 0x10080818,
++	0x6fbabad5, 0xf0787888, 0x4a25256f, 0x5c2e2e72,
++	0x381c1c24, 0x57a6a6f1, 0x73b4b4c7, 0x97c6c651,
++	0xcbe8e823, 0xa1dddd7c, 0xe874749c, 0x3e1f1f21,
++	0x964b4bdd, 0x61bdbddc, 0x0d8b8b86, 0x0f8a8a85,
++	0xe0707090, 0x7c3e3e42, 0x71b5b5c4, 0xcc6666aa,
++	0x904848d8, 0x06030305, 0xf7f6f601, 0x1c0e0e12,
++	0xc26161a3, 0x6a35355f, 0xae5757f9, 0x69b9b9d0,
++	0x17868691, 0x99c1c158, 0x3a1d1d27, 0x279e9eb9,
++	0xd9e1e138, 0xebf8f813, 0x2b9898b3, 0x22111133,
++	0xd26969bb, 0xa9d9d970, 0x078e8e89, 0x339494a7,
++	0x2d9b9bb6, 0x3c1e1e22, 0x15878792, 0xc9e9e920,
++	0x87cece49, 0xaa5555ff, 0x50282878, 0xa5dfdf7a,
++	0x038c8c8f, 0x59a1a1f8, 0x09898980, 0x1a0d0d17,
++	0x65bfbfda, 0xd7e6e631, 0x844242c6, 0xd06868b8,
++	0x824141c3, 0x299999b0, 0x5a2d2d77, 0x1e0f0f11,
++	0x7bb0b0cb, 0xa85454fc, 0x6dbbbbd6, 0x2c16163a);
++$code.=<<___;
++	.byte	0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5
++	.byte	0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76
++	.byte	0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0
++	.byte	0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0
++	.byte	0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc
++	.byte	0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15
++	.byte	0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a
++	.byte	0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75
++	.byte	0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0
++	.byte	0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84
++	.byte	0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b
++	.byte	0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf
++	.byte	0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85
++	.byte	0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8
++	.byte	0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5
++	.byte	0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2
++	.byte	0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17
++	.byte	0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73
++	.byte	0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88
++	.byte	0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb
++	.byte	0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c
++	.byte	0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79
++	.byte	0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9
++	.byte	0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08
++	.byte	0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6
++	.byte	0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a
++	.byte	0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e
++	.byte	0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e
++	.byte	0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94
++	.byte	0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf
++	.byte	0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68
++	.byte	0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16
++.type	AES_Te,#object
++.size	AES_Te,(.-AES_Te)
++
++.align	64
++.skip	16
++_sparcv9_AES_encrypt:
++	save	%sp,-$frame-$locals,%sp
++	stx	%i7,[%sp+$bias+$frame+0]	! off-load return address
++	ld	[$key+240],$rounds
++	ld	[$key+0],$t0
++	ld	[$key+4],$t1			!
++	ld	[$key+8],$t2
++	srl	$rounds,1,$rounds
++	xor	$t0,$s0,$s0
++	ld	[$key+12],$t3
++	srl	$s0,21,$acc0
++	xor	$t1,$s1,$s1
++	ld	[$key+16],$t0
++	srl	$s1,13,$acc1			!
++	xor	$t2,$s2,$s2
++	ld	[$key+20],$t1
++	xor	$t3,$s3,$s3
++	ld	[$key+24],$t2
++	and	$acc0,2040,$acc0
++	ld	[$key+28],$t3
++	nop
++.Lenc_loop:
++	srl	$s2,5,$acc2			!
++	and	$acc1,2040,$acc1
++	ldx	[$tbl+$acc0],$acc0
++	sll	$s3,3,$acc3
++	and	$acc2,2040,$acc2
++	ldx	[$tbl+$acc1],$acc1
++	srl	$s1,21,$acc4
++	and	$acc3,2040,$acc3
++	ldx	[$tbl+$acc2],$acc2		!
++	srl	$s2,13,$acc5
++	and	$acc4,2040,$acc4
++	ldx	[$tbl+$acc3],$acc3
++	srl	$s3,5,$acc6
++	and	$acc5,2040,$acc5
++	ldx	[$tbl+$acc4],$acc4
++	fmovs	%f0,%f0
++	sll	$s0,3,$acc7			!
++	and	$acc6,2040,$acc6
++	ldx	[$tbl+$acc5],$acc5
++	srl	$s2,21,$acc8
++	and	$acc7,2040,$acc7
++	ldx	[$tbl+$acc6],$acc6
++	srl	$s3,13,$acc9
++	and	$acc8,2040,$acc8
++	ldx	[$tbl+$acc7],$acc7		!
++	srl	$s0,5,$acc10
++	and	$acc9,2040,$acc9
++	ldx	[$tbl+$acc8],$acc8
++	sll	$s1,3,$acc11
++	and	$acc10,2040,$acc10
++	ldx	[$tbl+$acc9],$acc9
++	fmovs	%f0,%f0
++	srl	$s3,21,$acc12			!
++	and	$acc11,2040,$acc11
++	ldx	[$tbl+$acc10],$acc10
++	srl	$s0,13,$acc13
++	and	$acc12,2040,$acc12
++	ldx	[$tbl+$acc11],$acc11
++	srl	$s1,5,$acc14
++	and	$acc13,2040,$acc13
++	ldx	[$tbl+$acc12],$acc12		!
++	sll	$s2,3,$acc15
++	and	$acc14,2040,$acc14
++	ldx	[$tbl+$acc13],$acc13
++	and	$acc15,2040,$acc15
++	add	$key,32,$key
++	ldx	[$tbl+$acc14],$acc14
++	fmovs	%f0,%f0
++	subcc	$rounds,1,$rounds		!
++	ldx	[$tbl+$acc15],$acc15
++	bz,a,pn	%icc,.Lenc_last
++	add	$tbl,2048,$rounds
++
++		srlx	$acc1,8,$acc1
++		xor	$acc0,$t0,$t0
++	ld	[$key+0],$s0
++	fmovs	%f0,%f0
++		srlx	$acc2,16,$acc2		!
++		xor	$acc1,$t0,$t0
++	ld	[$key+4],$s1
++		srlx	$acc3,24,$acc3
++		xor	$acc2,$t0,$t0
++	ld	[$key+8],$s2
++		srlx	$acc5,8,$acc5
++		xor	$acc3,$t0,$t0
++	ld	[$key+12],$s3			!
++		srlx	$acc6,16,$acc6
++		xor	$acc4,$t1,$t1
++	fmovs	%f0,%f0
++		srlx	$acc7,24,$acc7
++		xor	$acc5,$t1,$t1
++		srlx	$acc9,8,$acc9
++		xor	$acc6,$t1,$t1
++		srlx	$acc10,16,$acc10	!
++		xor	$acc7,$t1,$t1
++		srlx	$acc11,24,$acc11
++		xor	$acc8,$t2,$t2
++		srlx	$acc13,8,$acc13
++		xor	$acc9,$t2,$t2
++		srlx	$acc14,16,$acc14
++		xor	$acc10,$t2,$t2
++		srlx	$acc15,24,$acc15	!
++		xor	$acc11,$t2,$t2
++		xor	$acc12,$acc14,$acc14
++		xor	$acc13,$t3,$t3
++	srl	$t0,21,$acc0
++		xor	$acc14,$t3,$t3
++	srl	$t1,13,$acc1
++		xor	$acc15,$t3,$t3
++
++	and	$acc0,2040,$acc0		!
++	srl	$t2,5,$acc2
++	and	$acc1,2040,$acc1
++	ldx	[$tbl+$acc0],$acc0
++	sll	$t3,3,$acc3
++	and	$acc2,2040,$acc2
++	ldx	[$tbl+$acc1],$acc1
++	fmovs	%f0,%f0
++	srl	$t1,21,$acc4			!
++	and	$acc3,2040,$acc3
++	ldx	[$tbl+$acc2],$acc2
++	srl	$t2,13,$acc5
++	and	$acc4,2040,$acc4
++	ldx	[$tbl+$acc3],$acc3
++	srl	$t3,5,$acc6
++	and	$acc5,2040,$acc5
++	ldx	[$tbl+$acc4],$acc4		!
++	sll	$t0,3,$acc7
++	and	$acc6,2040,$acc6
++	ldx	[$tbl+$acc5],$acc5
++	srl	$t2,21,$acc8
++	and	$acc7,2040,$acc7
++	ldx	[$tbl+$acc6],$acc6
++	fmovs	%f0,%f0
++	srl	$t3,13,$acc9			!
++	and	$acc8,2040,$acc8
++	ldx	[$tbl+$acc7],$acc7
++	srl	$t0,5,$acc10
++	and	$acc9,2040,$acc9
++	ldx	[$tbl+$acc8],$acc8
++	sll	$t1,3,$acc11
++	and	$acc10,2040,$acc10
++	ldx	[$tbl+$acc9],$acc9		!
++	srl	$t3,21,$acc12
++	and	$acc11,2040,$acc11
++	ldx	[$tbl+$acc10],$acc10
++	srl	$t0,13,$acc13
++	and	$acc12,2040,$acc12
++	ldx	[$tbl+$acc11],$acc11
++	fmovs	%f0,%f0
++	srl	$t1,5,$acc14			!
++	and	$acc13,2040,$acc13
++	ldx	[$tbl+$acc12],$acc12
++	sll	$t2,3,$acc15
++	and	$acc14,2040,$acc14
++	ldx	[$tbl+$acc13],$acc13
++		srlx	$acc1,8,$acc1
++	and	$acc15,2040,$acc15
++	ldx	[$tbl+$acc14],$acc14		!
++
++		srlx	$acc2,16,$acc2
++		xor	$acc0,$s0,$s0
++	ldx	[$tbl+$acc15],$acc15
++		srlx	$acc3,24,$acc3
++		xor	$acc1,$s0,$s0
++	ld	[$key+16],$t0
++	fmovs	%f0,%f0
++		srlx	$acc5,8,$acc5		!
++		xor	$acc2,$s0,$s0
++	ld	[$key+20],$t1
++		srlx	$acc6,16,$acc6
++		xor	$acc3,$s0,$s0
++	ld	[$key+24],$t2
++		srlx	$acc7,24,$acc7
++		xor	$acc4,$s1,$s1
++	ld	[$key+28],$t3			!
++		srlx	$acc9,8,$acc9
++		xor	$acc5,$s1,$s1
++	ldx	[$tbl+2048+0],%g0		! prefetch te4
++		srlx	$acc10,16,$acc10
++		xor	$acc6,$s1,$s1
++	ldx	[$tbl+2048+32],%g0		! prefetch te4
++		srlx	$acc11,24,$acc11
++		xor	$acc7,$s1,$s1
++	ldx	[$tbl+2048+64],%g0		! prefetch te4
++		srlx	$acc13,8,$acc13
++		xor	$acc8,$s2,$s2
++	ldx	[$tbl+2048+96],%g0		! prefetch te4
++		srlx	$acc14,16,$acc14	!
++		xor	$acc9,$s2,$s2
++	ldx	[$tbl+2048+128],%g0		! prefetch te4
++		srlx	$acc15,24,$acc15
++		xor	$acc10,$s2,$s2
++	ldx	[$tbl+2048+160],%g0		! prefetch te4
++	srl	$s0,21,$acc0
++		xor	$acc11,$s2,$s2
++	ldx	[$tbl+2048+192],%g0		! prefetch te4
++		xor	$acc12,$acc14,$acc14
++		xor	$acc13,$s3,$s3
++	ldx	[$tbl+2048+224],%g0		! prefetch te4
++	srl	$s1,13,$acc1			!
++		xor	$acc14,$s3,$s3
++		xor	$acc15,$s3,$s3
++	ba	.Lenc_loop
++	and	$acc0,2040,$acc0
++
++.align	32
++.Lenc_last:
++		srlx	$acc1,8,$acc1		!
++		xor	$acc0,$t0,$t0
++	ld	[$key+0],$s0
++		srlx	$acc2,16,$acc2
++		xor	$acc1,$t0,$t0
++	ld	[$key+4],$s1
++		srlx	$acc3,24,$acc3
++		xor	$acc2,$t0,$t0
++	ld	[$key+8],$s2			!
++		srlx	$acc5,8,$acc5
++		xor	$acc3,$t0,$t0
++	ld	[$key+12],$s3
++		srlx	$acc6,16,$acc6
++		xor	$acc4,$t1,$t1
++		srlx	$acc7,24,$acc7
++		xor	$acc5,$t1,$t1
++		srlx	$acc9,8,$acc9		!
++		xor	$acc6,$t1,$t1
++		srlx	$acc10,16,$acc10
++		xor	$acc7,$t1,$t1
++		srlx	$acc11,24,$acc11
++		xor	$acc8,$t2,$t2
++		srlx	$acc13,8,$acc13
++		xor	$acc9,$t2,$t2
++		srlx	$acc14,16,$acc14	!
++		xor	$acc10,$t2,$t2
++		srlx	$acc15,24,$acc15
++		xor	$acc11,$t2,$t2
++		xor	$acc12,$acc14,$acc14
++		xor	$acc13,$t3,$t3
++	srl	$t0,24,$acc0
++		xor	$acc14,$t3,$t3
++	srl	$t1,16,$acc1			!
++		xor	$acc15,$t3,$t3
++
++	srl	$t2,8,$acc2
++	and	$acc1,255,$acc1
++	ldub	[$rounds+$acc0],$acc0
++	srl	$t1,24,$acc4
++	and	$acc2,255,$acc2
++	ldub	[$rounds+$acc1],$acc1
++	srl	$t2,16,$acc5			!
++	and	$t3,255,$acc3
++	ldub	[$rounds+$acc2],$acc2
++	ldub	[$rounds+$acc3],$acc3
++	srl	$t3,8,$acc6
++	and	$acc5,255,$acc5
++	ldub	[$rounds+$acc4],$acc4
++	fmovs	%f0,%f0
++	srl	$t2,24,$acc8			!
++	and	$acc6,255,$acc6
++	ldub	[$rounds+$acc5],$acc5
++	srl	$t3,16,$acc9
++	and	$t0,255,$acc7
++	ldub	[$rounds+$acc6],$acc6
++	ldub	[$rounds+$acc7],$acc7
++	fmovs	%f0,%f0
++	srl	$t0,8,$acc10			!
++	and	$acc9,255,$acc9
++	ldub	[$rounds+$acc8],$acc8
++	srl	$t3,24,$acc12
++	and	$acc10,255,$acc10
++	ldub	[$rounds+$acc9],$acc9
++	srl	$t0,16,$acc13
++	and	$t1,255,$acc11
++	ldub	[$rounds+$acc10],$acc10		!
++	srl	$t1,8,$acc14
++	and	$acc13,255,$acc13
++	ldub	[$rounds+$acc11],$acc11
++	ldub	[$rounds+$acc12],$acc12
++	and	$acc14,255,$acc14
++	ldub	[$rounds+$acc13],$acc13
++	and	$t2,255,$acc15
++	ldub	[$rounds+$acc14],$acc14		!
++
++		sll	$acc0,24,$acc0
++		xor	$acc3,$s0,$s0
++	ldub	[$rounds+$acc15],$acc15
++		sll	$acc1,16,$acc1
++		xor	$acc0,$s0,$s0
++	ldx	[%sp+$bias+$frame+0],%i7	! restore return address
++	fmovs	%f0,%f0
++		sll	$acc2,8,$acc2		!
++		xor	$acc1,$s0,$s0
++		sll	$acc4,24,$acc4
++		xor	$acc2,$s0,$s0
++		sll	$acc5,16,$acc5
++		xor	$acc7,$s1,$s1
++		sll	$acc6,8,$acc6
++		xor	$acc4,$s1,$s1
++		sll	$acc8,24,$acc8		!
++		xor	$acc5,$s1,$s1
++		sll	$acc9,16,$acc9
++		xor	$acc11,$s2,$s2
++		sll	$acc10,8,$acc10
++		xor	$acc6,$s1,$s1
++		sll	$acc12,24,$acc12
++		xor	$acc8,$s2,$s2
++		sll	$acc13,16,$acc13	!
++		xor	$acc9,$s2,$s2
++		sll	$acc14,8,$acc14
++		xor	$acc10,$s2,$s2
++		xor	$acc12,$acc14,$acc14
++		xor	$acc13,$s3,$s3
++		xor	$acc14,$s3,$s3
++		xor	$acc15,$s3,$s3
++
++	ret
++	restore
++.type	_sparcv9_AES_encrypt,#function
++.size	_sparcv9_AES_encrypt,(.-_sparcv9_AES_encrypt)
++
++.align	32
++.globl	AES_encrypt
++AES_encrypt:
++	or	%o0,%o1,%g1
++	andcc	%g1,3,%g0
++	bnz,pn	%xcc,.Lunaligned_enc
++	save	%sp,-$frame,%sp
++
++	ld	[%i0+0],%o0
++	ld	[%i0+4],%o1
++	ld	[%i0+8],%o2
++	ld	[%i0+12],%o3
++
++1:	call	.+8
++	add	%o7,AES_Te-1b,%o4
++	call	_sparcv9_AES_encrypt
++	mov	%i2,%o5
++
++	st	%o0,[%i1+0]
++	st	%o1,[%i1+4]
++	st	%o2,[%i1+8]
++	st	%o3,[%i1+12]
++
++	ret
++	restore
++
++.align	32
++.Lunaligned_enc:
++	ldub	[%i0+0],%l0
++	ldub	[%i0+1],%l1
++	ldub	[%i0+2],%l2
++
++	sll	%l0,24,%l0
++	ldub	[%i0+3],%l3
++	sll	%l1,16,%l1
++	ldub	[%i0+4],%l4
++	sll	%l2,8,%l2
++	or	%l1,%l0,%l0
++	ldub	[%i0+5],%l5
++	sll	%l4,24,%l4
++	or	%l3,%l2,%l2
++	ldub	[%i0+6],%l6
++	sll	%l5,16,%l5
++	or	%l0,%l2,%o0
++	ldub	[%i0+7],%l7
++
++	sll	%l6,8,%l6
++	or	%l5,%l4,%l4
++	ldub	[%i0+8],%l0
++	or	%l7,%l6,%l6
++	ldub	[%i0+9],%l1
++	or	%l4,%l6,%o1
++	ldub	[%i0+10],%l2
++
++	sll	%l0,24,%l0
++	ldub	[%i0+11],%l3
++	sll	%l1,16,%l1
++	ldub	[%i0+12],%l4
++	sll	%l2,8,%l2
++	or	%l1,%l0,%l0
++	ldub	[%i0+13],%l5
++	sll	%l4,24,%l4
++	or	%l3,%l2,%l2
++	ldub	[%i0+14],%l6
++	sll	%l5,16,%l5
++	or	%l0,%l2,%o2
++	ldub	[%i0+15],%l7
++
++	sll	%l6,8,%l6
++	or	%l5,%l4,%l4
++	or	%l7,%l6,%l6
++	or	%l4,%l6,%o3
++
++1:	call	.+8
++	add	%o7,AES_Te-1b,%o4
++	call	_sparcv9_AES_encrypt
++	mov	%i2,%o5
++
++	srl	%o0,24,%l0
++	srl	%o0,16,%l1
++	stb	%l0,[%i1+0]
++	srl	%o0,8,%l2
++	stb	%l1,[%i1+1]
++	stb	%l2,[%i1+2]
++	srl	%o1,24,%l4
++	stb	%o0,[%i1+3]
++
++	srl	%o1,16,%l5
++	stb	%l4,[%i1+4]
++	srl	%o1,8,%l6
++	stb	%l5,[%i1+5]
++	stb	%l6,[%i1+6]
++	srl	%o2,24,%l0
++	stb	%o1,[%i1+7]
++
++	srl	%o2,16,%l1
++	stb	%l0,[%i1+8]
++	srl	%o2,8,%l2
++	stb	%l1,[%i1+9]
++	stb	%l2,[%i1+10]
++	srl	%o3,24,%l4
++	stb	%o2,[%i1+11]
++
++	srl	%o3,16,%l5
++	stb	%l4,[%i1+12]
++	srl	%o3,8,%l6
++	stb	%l5,[%i1+13]
++	stb	%l6,[%i1+14]
++	stb	%o3,[%i1+15]
++
++	ret
++	restore
++.type	AES_encrypt,#function
++.size	AES_encrypt,(.-AES_encrypt)
++
++___
++
++$code.=<<___;
++.align	256
++AES_Td:
++___
++&_data_word(
++	0x51f4a750, 0x7e416553, 0x1a17a4c3, 0x3a275e96,
++	0x3bab6bcb, 0x1f9d45f1, 0xacfa58ab, 0x4be30393,
++	0x2030fa55, 0xad766df6, 0x88cc7691, 0xf5024c25,
++	0x4fe5d7fc, 0xc52acbd7, 0x26354480, 0xb562a38f,
++	0xdeb15a49, 0x25ba1b67, 0x45ea0e98, 0x5dfec0e1,
++	0xc32f7502, 0x814cf012, 0x8d4697a3, 0x6bd3f9c6,
++	0x038f5fe7, 0x15929c95, 0xbf6d7aeb, 0x955259da,
++	0xd4be832d, 0x587421d3, 0x49e06929, 0x8ec9c844,
++	0x75c2896a, 0xf48e7978, 0x99583e6b, 0x27b971dd,
++	0xbee14fb6, 0xf088ad17, 0xc920ac66, 0x7dce3ab4,
++	0x63df4a18, 0xe51a3182, 0x97513360, 0x62537f45,
++	0xb16477e0, 0xbb6bae84, 0xfe81a01c, 0xf9082b94,
++	0x70486858, 0x8f45fd19, 0x94de6c87, 0x527bf8b7,
++	0xab73d323, 0x724b02e2, 0xe31f8f57, 0x6655ab2a,
++	0xb2eb2807, 0x2fb5c203, 0x86c57b9a, 0xd33708a5,
++	0x302887f2, 0x23bfa5b2, 0x02036aba, 0xed16825c,
++	0x8acf1c2b, 0xa779b492, 0xf307f2f0, 0x4e69e2a1,
++	0x65daf4cd, 0x0605bed5, 0xd134621f, 0xc4a6fe8a,
++	0x342e539d, 0xa2f355a0, 0x058ae132, 0xa4f6eb75,
++	0x0b83ec39, 0x4060efaa, 0x5e719f06, 0xbd6e1051,
++	0x3e218af9, 0x96dd063d, 0xdd3e05ae, 0x4de6bd46,
++	0x91548db5, 0x71c45d05, 0x0406d46f, 0x605015ff,
++	0x1998fb24, 0xd6bde997, 0x894043cc, 0x67d99e77,
++	0xb0e842bd, 0x07898b88, 0xe7195b38, 0x79c8eedb,
++	0xa17c0a47, 0x7c420fe9, 0xf8841ec9, 0x00000000,
++	0x09808683, 0x322bed48, 0x1e1170ac, 0x6c5a724e,
++	0xfd0efffb, 0x0f853856, 0x3daed51e, 0x362d3927,
++	0x0a0fd964, 0x685ca621, 0x9b5b54d1, 0x24362e3a,
++	0x0c0a67b1, 0x9357e70f, 0xb4ee96d2, 0x1b9b919e,
++	0x80c0c54f, 0x61dc20a2, 0x5a774b69, 0x1c121a16,
++	0xe293ba0a, 0xc0a02ae5, 0x3c22e043, 0x121b171d,
++	0x0e090d0b, 0xf28bc7ad, 0x2db6a8b9, 0x141ea9c8,
++	0x57f11985, 0xaf75074c, 0xee99ddbb, 0xa37f60fd,
++	0xf701269f, 0x5c72f5bc, 0x44663bc5, 0x5bfb7e34,
++	0x8b432976, 0xcb23c6dc, 0xb6edfc68, 0xb8e4f163,
++	0xd731dcca, 0x42638510, 0x13972240, 0x84c61120,
++	0x854a247d, 0xd2bb3df8, 0xaef93211, 0xc729a16d,
++	0x1d9e2f4b, 0xdcb230f3, 0x0d8652ec, 0x77c1e3d0,
++	0x2bb3166c, 0xa970b999, 0x119448fa, 0x47e96422,
++	0xa8fc8cc4, 0xa0f03f1a, 0x567d2cd8, 0x223390ef,
++	0x87494ec7, 0xd938d1c1, 0x8ccaa2fe, 0x98d40b36,
++	0xa6f581cf, 0xa57ade28, 0xdab78e26, 0x3fadbfa4,
++	0x2c3a9de4, 0x5078920d, 0x6a5fcc9b, 0x547e4662,
++	0xf68d13c2, 0x90d8b8e8, 0x2e39f75e, 0x82c3aff5,
++	0x9f5d80be, 0x69d0937c, 0x6fd52da9, 0xcf2512b3,
++	0xc8ac993b, 0x10187da7, 0xe89c636e, 0xdb3bbb7b,
++	0xcd267809, 0x6e5918f4, 0xec9ab701, 0x834f9aa8,
++	0xe6956e65, 0xaaffe67e, 0x21bccf08, 0xef15e8e6,
++	0xbae79bd9, 0x4a6f36ce, 0xea9f09d4, 0x29b07cd6,
++	0x31a4b2af, 0x2a3f2331, 0xc6a59430, 0x35a266c0,
++	0x744ebc37, 0xfc82caa6, 0xe090d0b0, 0x33a7d815,
++	0xf104984a, 0x41ecdaf7, 0x7fcd500e, 0x1791f62f,
++	0x764dd68d, 0x43efb04d, 0xccaa4d54, 0xe49604df,
++	0x9ed1b5e3, 0x4c6a881b, 0xc12c1fb8, 0x4665517f,
++	0x9d5eea04, 0x018c355d, 0xfa877473, 0xfb0b412e,
++	0xb3671d5a, 0x92dbd252, 0xe9105633, 0x6dd64713,
++	0x9ad7618c, 0x37a10c7a, 0x59f8148e, 0xeb133c89,
++	0xcea927ee, 0xb761c935, 0xe11ce5ed, 0x7a47b13c,
++	0x9cd2df59, 0x55f2733f, 0x1814ce79, 0x73c737bf,
++	0x53f7cdea, 0x5ffdaa5b, 0xdf3d6f14, 0x7844db86,
++	0xcaaff381, 0xb968c43e, 0x3824342c, 0xc2a3405f,
++	0x161dc372, 0xbce2250c, 0x283c498b, 0xff0d9541,
++	0x39a80171, 0x080cb3de, 0xd8b4e49c, 0x6456c190,
++	0x7bcb8461, 0xd532b670, 0x486c5c74, 0xd0b85742);
++$code.=<<___;
++	.byte	0x52, 0x09, 0x6a, 0xd5, 0x30, 0x36, 0xa5, 0x38
++	.byte	0xbf, 0x40, 0xa3, 0x9e, 0x81, 0xf3, 0xd7, 0xfb
++	.byte	0x7c, 0xe3, 0x39, 0x82, 0x9b, 0x2f, 0xff, 0x87
++	.byte	0x34, 0x8e, 0x43, 0x44, 0xc4, 0xde, 0xe9, 0xcb
++	.byte	0x54, 0x7b, 0x94, 0x32, 0xa6, 0xc2, 0x23, 0x3d
++	.byte	0xee, 0x4c, 0x95, 0x0b, 0x42, 0xfa, 0xc3, 0x4e
++	.byte	0x08, 0x2e, 0xa1, 0x66, 0x28, 0xd9, 0x24, 0xb2
++	.byte	0x76, 0x5b, 0xa2, 0x49, 0x6d, 0x8b, 0xd1, 0x25
++	.byte	0x72, 0xf8, 0xf6, 0x64, 0x86, 0x68, 0x98, 0x16
++	.byte	0xd4, 0xa4, 0x5c, 0xcc, 0x5d, 0x65, 0xb6, 0x92
++	.byte	0x6c, 0x70, 0x48, 0x50, 0xfd, 0xed, 0xb9, 0xda
++	.byte	0x5e, 0x15, 0x46, 0x57, 0xa7, 0x8d, 0x9d, 0x84
++	.byte	0x90, 0xd8, 0xab, 0x00, 0x8c, 0xbc, 0xd3, 0x0a
++	.byte	0xf7, 0xe4, 0x58, 0x05, 0xb8, 0xb3, 0x45, 0x06
++	.byte	0xd0, 0x2c, 0x1e, 0x8f, 0xca, 0x3f, 0x0f, 0x02
++	.byte	0xc1, 0xaf, 0xbd, 0x03, 0x01, 0x13, 0x8a, 0x6b
++	.byte	0x3a, 0x91, 0x11, 0x41, 0x4f, 0x67, 0xdc, 0xea
++	.byte	0x97, 0xf2, 0xcf, 0xce, 0xf0, 0xb4, 0xe6, 0x73
++	.byte	0x96, 0xac, 0x74, 0x22, 0xe7, 0xad, 0x35, 0x85
++	.byte	0xe2, 0xf9, 0x37, 0xe8, 0x1c, 0x75, 0xdf, 0x6e
++	.byte	0x47, 0xf1, 0x1a, 0x71, 0x1d, 0x29, 0xc5, 0x89
++	.byte	0x6f, 0xb7, 0x62, 0x0e, 0xaa, 0x18, 0xbe, 0x1b
++	.byte	0xfc, 0x56, 0x3e, 0x4b, 0xc6, 0xd2, 0x79, 0x20
++	.byte	0x9a, 0xdb, 0xc0, 0xfe, 0x78, 0xcd, 0x5a, 0xf4
++	.byte	0x1f, 0xdd, 0xa8, 0x33, 0x88, 0x07, 0xc7, 0x31
++	.byte	0xb1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xec, 0x5f
++	.byte	0x60, 0x51, 0x7f, 0xa9, 0x19, 0xb5, 0x4a, 0x0d
++	.byte	0x2d, 0xe5, 0x7a, 0x9f, 0x93, 0xc9, 0x9c, 0xef
++	.byte	0xa0, 0xe0, 0x3b, 0x4d, 0xae, 0x2a, 0xf5, 0xb0
++	.byte	0xc8, 0xeb, 0xbb, 0x3c, 0x83, 0x53, 0x99, 0x61
++	.byte	0x17, 0x2b, 0x04, 0x7e, 0xba, 0x77, 0xd6, 0x26
++	.byte	0xe1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0c, 0x7d
++.type	AES_Td,#object
++.size	AES_Td,(.-AES_Td)
++
++.align	64
++.skip	16
++_sparcv9_AES_decrypt:
++	save	%sp,-$frame-$locals,%sp
++	stx	%i7,[%sp+$bias+$frame+0]	! off-load return address
++	ld	[$key+240],$rounds
++	ld	[$key+0],$t0
++	ld	[$key+4],$t1			!
++	ld	[$key+8],$t2
++	ld	[$key+12],$t3
++	srl	$rounds,1,$rounds
++	xor	$t0,$s0,$s0
++	ld	[$key+16],$t0
++	xor	$t1,$s1,$s1
++	ld	[$key+20],$t1
++	srl	$s0,21,$acc0			!
++	xor	$t2,$s2,$s2
++	ld	[$key+24],$t2
++	xor	$t3,$s3,$s3
++	and	$acc0,2040,$acc0
++	ld	[$key+28],$t3
++	srl	$s3,13,$acc1
++	nop
++.Ldec_loop:
++	srl	$s2,5,$acc2			!
++	and	$acc1,2040,$acc1
++	ldx	[$tbl+$acc0],$acc0
++	sll	$s1,3,$acc3
++	and	$acc2,2040,$acc2
++	ldx	[$tbl+$acc1],$acc1
++	srl	$s1,21,$acc4
++	and	$acc3,2040,$acc3
++	ldx	[$tbl+$acc2],$acc2		!
++	srl	$s0,13,$acc5
++	and	$acc4,2040,$acc4
++	ldx	[$tbl+$acc3],$acc3
++	srl	$s3,5,$acc6
++	and	$acc5,2040,$acc5
++	ldx	[$tbl+$acc4],$acc4
++	fmovs	%f0,%f0
++	sll	$s2,3,$acc7			!
++	and	$acc6,2040,$acc6
++	ldx	[$tbl+$acc5],$acc5
++	srl	$s2,21,$acc8
++	and	$acc7,2040,$acc7
++	ldx	[$tbl+$acc6],$acc6
++	srl	$s1,13,$acc9
++	and	$acc8,2040,$acc8
++	ldx	[$tbl+$acc7],$acc7		!
++	srl	$s0,5,$acc10
++	and	$acc9,2040,$acc9
++	ldx	[$tbl+$acc8],$acc8
++	sll	$s3,3,$acc11
++	and	$acc10,2040,$acc10
++	ldx	[$tbl+$acc9],$acc9
++	fmovs	%f0,%f0
++	srl	$s3,21,$acc12			!
++	and	$acc11,2040,$acc11
++	ldx	[$tbl+$acc10],$acc10
++	srl	$s2,13,$acc13
++	and	$acc12,2040,$acc12
++	ldx	[$tbl+$acc11],$acc11
++	srl	$s1,5,$acc14
++	and	$acc13,2040,$acc13
++	ldx	[$tbl+$acc12],$acc12		!
++	sll	$s0,3,$acc15
++	and	$acc14,2040,$acc14
++	ldx	[$tbl+$acc13],$acc13
++	and	$acc15,2040,$acc15
++	add	$key,32,$key
++	ldx	[$tbl+$acc14],$acc14
++	fmovs	%f0,%f0
++	subcc	$rounds,1,$rounds		!
++	ldx	[$tbl+$acc15],$acc15
++	bz,a,pn	%icc,.Ldec_last
++	add	$tbl,2048,$rounds
++
++		srlx	$acc1,8,$acc1
++		xor	$acc0,$t0,$t0
++	ld	[$key+0],$s0
++	fmovs	%f0,%f0
++		srlx	$acc2,16,$acc2		!
++		xor	$acc1,$t0,$t0
++	ld	[$key+4],$s1
++		srlx	$acc3,24,$acc3
++		xor	$acc2,$t0,$t0
++	ld	[$key+8],$s2
++		srlx	$acc5,8,$acc5
++		xor	$acc3,$t0,$t0
++	ld	[$key+12],$s3			!
++		srlx	$acc6,16,$acc6
++		xor	$acc4,$t1,$t1
++	fmovs	%f0,%f0
++		srlx	$acc7,24,$acc7
++		xor	$acc5,$t1,$t1
++		srlx	$acc9,8,$acc9
++		xor	$acc6,$t1,$t1
++		srlx	$acc10,16,$acc10	!
++		xor	$acc7,$t1,$t1
++		srlx	$acc11,24,$acc11
++		xor	$acc8,$t2,$t2
++		srlx	$acc13,8,$acc13
++		xor	$acc9,$t2,$t2
++		srlx	$acc14,16,$acc14
++		xor	$acc10,$t2,$t2
++		srlx	$acc15,24,$acc15	!
++		xor	$acc11,$t2,$t2
++		xor	$acc12,$acc14,$acc14
++		xor	$acc13,$t3,$t3
++	srl	$t0,21,$acc0
++		xor	$acc14,$t3,$t3
++		xor	$acc15,$t3,$t3
++	srl	$t3,13,$acc1
++
++	and	$acc0,2040,$acc0		!
++	srl	$t2,5,$acc2
++	and	$acc1,2040,$acc1
++	ldx	[$tbl+$acc0],$acc0
++	sll	$t1,3,$acc3
++	and	$acc2,2040,$acc2
++	ldx	[$tbl+$acc1],$acc1
++	fmovs	%f0,%f0
++	srl	$t1,21,$acc4			!
++	and	$acc3,2040,$acc3
++	ldx	[$tbl+$acc2],$acc2
++	srl	$t0,13,$acc5
++	and	$acc4,2040,$acc4
++	ldx	[$tbl+$acc3],$acc3
++	srl	$t3,5,$acc6
++	and	$acc5,2040,$acc5
++	ldx	[$tbl+$acc4],$acc4		!
++	sll	$t2,3,$acc7
++	and	$acc6,2040,$acc6
++	ldx	[$tbl+$acc5],$acc5
++	srl	$t2,21,$acc8
++	and	$acc7,2040,$acc7
++	ldx	[$tbl+$acc6],$acc6
++	fmovs	%f0,%f0
++	srl	$t1,13,$acc9			!
++	and	$acc8,2040,$acc8
++	ldx	[$tbl+$acc7],$acc7
++	srl	$t0,5,$acc10
++	and	$acc9,2040,$acc9
++	ldx	[$tbl+$acc8],$acc8
++	sll	$t3,3,$acc11
++	and	$acc10,2040,$acc10
++	ldx	[$tbl+$acc9],$acc9		!
++	srl	$t3,21,$acc12
++	and	$acc11,2040,$acc11
++	ldx	[$tbl+$acc10],$acc10
++	srl	$t2,13,$acc13
++	and	$acc12,2040,$acc12
++	ldx	[$tbl+$acc11],$acc11
++	fmovs	%f0,%f0
++	srl	$t1,5,$acc14			!
++	and	$acc13,2040,$acc13
++	ldx	[$tbl+$acc12],$acc12
++	sll	$t0,3,$acc15
++	and	$acc14,2040,$acc14
++	ldx	[$tbl+$acc13],$acc13
++		srlx	$acc1,8,$acc1
++	and	$acc15,2040,$acc15
++	ldx	[$tbl+$acc14],$acc14		!
++
++		srlx	$acc2,16,$acc2
++		xor	$acc0,$s0,$s0
++	ldx	[$tbl+$acc15],$acc15
++		srlx	$acc3,24,$acc3
++		xor	$acc1,$s0,$s0
++	ld	[$key+16],$t0
++	fmovs	%f0,%f0
++		srlx	$acc5,8,$acc5		!
++		xor	$acc2,$s0,$s0
++	ld	[$key+20],$t1
++		srlx	$acc6,16,$acc6
++		xor	$acc3,$s0,$s0
++	ld	[$key+24],$t2
++		srlx	$acc7,24,$acc7
++		xor	$acc4,$s1,$s1
++	ld	[$key+28],$t3			!
++		srlx	$acc9,8,$acc9
++		xor	$acc5,$s1,$s1
++	ldx	[$tbl+2048+0],%g0		! prefetch td4
++		srlx	$acc10,16,$acc10
++		xor	$acc6,$s1,$s1
++	ldx	[$tbl+2048+32],%g0		! prefetch td4
++		srlx	$acc11,24,$acc11
++		xor	$acc7,$s1,$s1
++	ldx	[$tbl+2048+64],%g0		! prefetch td4
++		srlx	$acc13,8,$acc13
++		xor	$acc8,$s2,$s2
++	ldx	[$tbl+2048+96],%g0		! prefetch td4
++		srlx	$acc14,16,$acc14	!
++		xor	$acc9,$s2,$s2
++	ldx	[$tbl+2048+128],%g0		! prefetch td4
++		srlx	$acc15,24,$acc15
++		xor	$acc10,$s2,$s2
++	ldx	[$tbl+2048+160],%g0		! prefetch td4
++	srl	$s0,21,$acc0
++		xor	$acc11,$s2,$s2
++	ldx	[$tbl+2048+192],%g0		! prefetch td4
++		xor	$acc12,$acc14,$acc14
++		xor	$acc13,$s3,$s3
++	ldx	[$tbl+2048+224],%g0		! prefetch td4
++	and	$acc0,2040,$acc0		!
++		xor	$acc14,$s3,$s3
++		xor	$acc15,$s3,$s3
++	ba	.Ldec_loop
++	srl	$s3,13,$acc1
++
++.align	32
++.Ldec_last:
++		srlx	$acc1,8,$acc1		!
++		xor	$acc0,$t0,$t0
++	ld	[$key+0],$s0
++		srlx	$acc2,16,$acc2
++		xor	$acc1,$t0,$t0
++	ld	[$key+4],$s1
++		srlx	$acc3,24,$acc3
++		xor	$acc2,$t0,$t0
++	ld	[$key+8],$s2			!
++		srlx	$acc5,8,$acc5
++		xor	$acc3,$t0,$t0
++	ld	[$key+12],$s3
++		srlx	$acc6,16,$acc6
++		xor	$acc4,$t1,$t1
++		srlx	$acc7,24,$acc7
++		xor	$acc5,$t1,$t1
++		srlx	$acc9,8,$acc9		!
++		xor	$acc6,$t1,$t1
++		srlx	$acc10,16,$acc10
++		xor	$acc7,$t1,$t1
++		srlx	$acc11,24,$acc11
++		xor	$acc8,$t2,$t2
++		srlx	$acc13,8,$acc13
++		xor	$acc9,$t2,$t2
++		srlx	$acc14,16,$acc14	!
++		xor	$acc10,$t2,$t2
++		srlx	$acc15,24,$acc15
++		xor	$acc11,$t2,$t2
++		xor	$acc12,$acc14,$acc14
++		xor	$acc13,$t3,$t3
++	srl	$t0,24,$acc0
++		xor	$acc14,$t3,$t3
++		xor	$acc15,$t3,$t3		!
++	srl	$t3,16,$acc1
++
++	srl	$t2,8,$acc2
++	and	$acc1,255,$acc1
++	ldub	[$rounds+$acc0],$acc0
++	srl	$t1,24,$acc4
++	and	$acc2,255,$acc2
++	ldub	[$rounds+$acc1],$acc1
++	srl	$t0,16,$acc5			!
++	and	$t1,255,$acc3
++	ldub	[$rounds+$acc2],$acc2
++	ldub	[$rounds+$acc3],$acc3
++	srl	$t3,8,$acc6
++	and	$acc5,255,$acc5
++	ldub	[$rounds+$acc4],$acc4
++	fmovs	%f0,%f0
++	srl	$t2,24,$acc8			!
++	and	$acc6,255,$acc6
++	ldub	[$rounds+$acc5],$acc5
++	srl	$t1,16,$acc9
++	and	$t2,255,$acc7
++	ldub	[$rounds+$acc6],$acc6
++	ldub	[$rounds+$acc7],$acc7
++	fmovs	%f0,%f0
++	srl	$t0,8,$acc10			!
++	and	$acc9,255,$acc9
++	ldub	[$rounds+$acc8],$acc8
++	srl	$t3,24,$acc12
++	and	$acc10,255,$acc10
++	ldub	[$rounds+$acc9],$acc9
++	srl	$t2,16,$acc13
++	and	$t3,255,$acc11
++	ldub	[$rounds+$acc10],$acc10		!
++	srl	$t1,8,$acc14
++	and	$acc13,255,$acc13
++	ldub	[$rounds+$acc11],$acc11
++	ldub	[$rounds+$acc12],$acc12
++	and	$acc14,255,$acc14
++	ldub	[$rounds+$acc13],$acc13
++	and	$t0,255,$acc15
++	ldub	[$rounds+$acc14],$acc14		!
++
++		sll	$acc0,24,$acc0
++		xor	$acc3,$s0,$s0
++	ldub	[$rounds+$acc15],$acc15
++		sll	$acc1,16,$acc1
++		xor	$acc0,$s0,$s0
++	ldx	[%sp+$bias+$frame+0],%i7	! restore return address
++	fmovs	%f0,%f0
++		sll	$acc2,8,$acc2		!
++		xor	$acc1,$s0,$s0
++		sll	$acc4,24,$acc4
++		xor	$acc2,$s0,$s0
++		sll	$acc5,16,$acc5
++		xor	$acc7,$s1,$s1
++		sll	$acc6,8,$acc6
++		xor	$acc4,$s1,$s1
++		sll	$acc8,24,$acc8		!
++		xor	$acc5,$s1,$s1
++		sll	$acc9,16,$acc9
++		xor	$acc11,$s2,$s2
++		sll	$acc10,8,$acc10
++		xor	$acc6,$s1,$s1
++		sll	$acc12,24,$acc12
++		xor	$acc8,$s2,$s2
++		sll	$acc13,16,$acc13	!
++		xor	$acc9,$s2,$s2
++		sll	$acc14,8,$acc14
++		xor	$acc10,$s2,$s2
++		xor	$acc12,$acc14,$acc14
++		xor	$acc13,$s3,$s3
++		xor	$acc14,$s3,$s3
++		xor	$acc15,$s3,$s3
++
++	ret
++	restore
++.type	_sparcv9_AES_decrypt,#function
++.size	_sparcv9_AES_decrypt,(.-_sparcv9_AES_decrypt)
++
++.align	32
++.globl	AES_decrypt
++AES_decrypt:
++	or	%o0,%o1,%g1
++	andcc	%g1,3,%g0
++	bnz,pn	%xcc,.Lunaligned_dec
++	save	%sp,-$frame,%sp
++
++	ld	[%i0+0],%o0
++	ld	[%i0+4],%o1
++	ld	[%i0+8],%o2
++	ld	[%i0+12],%o3
++
++1:	call	.+8
++	add	%o7,AES_Td-1b,%o4
++	call	_sparcv9_AES_decrypt
++	mov	%i2,%o5
++
++	st	%o0,[%i1+0]
++	st	%o1,[%i1+4]
++	st	%o2,[%i1+8]
++	st	%o3,[%i1+12]
++
++	ret
++	restore
++
++.align	32
++.Lunaligned_dec:
++	ldub	[%i0+0],%l0
++	ldub	[%i0+1],%l1
++	ldub	[%i0+2],%l2
++
++	sll	%l0,24,%l0
++	ldub	[%i0+3],%l3
++	sll	%l1,16,%l1
++	ldub	[%i0+4],%l4
++	sll	%l2,8,%l2
++	or	%l1,%l0,%l0
++	ldub	[%i0+5],%l5
++	sll	%l4,24,%l4
++	or	%l3,%l2,%l2
++	ldub	[%i0+6],%l6
++	sll	%l5,16,%l5
++	or	%l0,%l2,%o0
++	ldub	[%i0+7],%l7
++
++	sll	%l6,8,%l6
++	or	%l5,%l4,%l4
++	ldub	[%i0+8],%l0
++	or	%l7,%l6,%l6
++	ldub	[%i0+9],%l1
++	or	%l4,%l6,%o1
++	ldub	[%i0+10],%l2
++
++	sll	%l0,24,%l0
++	ldub	[%i0+11],%l3
++	sll	%l1,16,%l1
++	ldub	[%i0+12],%l4
++	sll	%l2,8,%l2
++	or	%l1,%l0,%l0
++	ldub	[%i0+13],%l5
++	sll	%l4,24,%l4
++	or	%l3,%l2,%l2
++	ldub	[%i0+14],%l6
++	sll	%l5,16,%l5
++	or	%l0,%l2,%o2
++	ldub	[%i0+15],%l7
++
++	sll	%l6,8,%l6
++	or	%l5,%l4,%l4
++	or	%l7,%l6,%l6
++	or	%l4,%l6,%o3
++
++1:	call	.+8
++	add	%o7,AES_Td-1b,%o4
++	call	_sparcv9_AES_decrypt
++	mov	%i2,%o5
++
++	srl	%o0,24,%l0
++	srl	%o0,16,%l1
++	stb	%l0,[%i1+0]
++	srl	%o0,8,%l2
++	stb	%l1,[%i1+1]
++	stb	%l2,[%i1+2]
++	srl	%o1,24,%l4
++	stb	%o0,[%i1+3]
++
++	srl	%o1,16,%l5
++	stb	%l4,[%i1+4]
++	srl	%o1,8,%l6
++	stb	%l5,[%i1+5]
++	stb	%l6,[%i1+6]
++	srl	%o2,24,%l0
++	stb	%o1,[%i1+7]
++
++	srl	%o2,16,%l1
++	stb	%l0,[%i1+8]
++	srl	%o2,8,%l2
++	stb	%l1,[%i1+9]
++	stb	%l2,[%i1+10]
++	srl	%o3,24,%l4
++	stb	%o2,[%i1+11]
++
++	srl	%o3,16,%l5
++	stb	%l4,[%i1+12]
++	srl	%o3,8,%l6
++	stb	%l5,[%i1+13]
++	stb	%l6,[%i1+14]
++	stb	%o3,[%i1+15]
++
++	ret
++	restore
++.type	AES_decrypt,#function
++.size	AES_decrypt,(.-AES_decrypt)
++___
++
++# fmovs instructions substituting for FP nops were originally added
++# to meet specific instruction alignment requirements to maximize ILP.
++# As UltraSPARC T1, a.k.a. Niagara, has shared FPU, FP nops can have
++# undesired effect, so just omit them and sacrifice some portion of
++# percent in performance...
++$code =~ s/fmovs.*$//gm;
++
++print $code;
++close STDOUT;	# ensure flush
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/aes/asm/aes-x86_64.pl b/CryptoPkg/Library/OpensslLib/openssl/crypto/aes/asm/aes-x86_64.pl
+new file mode 100755
+index 0000000..ce4ca30
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/aes/asm/aes-x86_64.pl
+@@ -0,0 +1,2820 @@
++#! /usr/bin/env perl
++# Copyright 2005-2016 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
++# in the file LICENSE in the source distribution or at
++# https://www.openssl.org/source/license.html
++
++#
++# ====================================================================
++# Written by Andy Polyakov  for the OpenSSL
++# project. The module is, however, dual licensed under OpenSSL and
++# CRYPTOGAMS licenses depending on where you obtain it. For further
++# details see http://www.openssl.org/~appro/cryptogams/.
++# ====================================================================
++#
++# Version 2.1.
++#
++# aes-*-cbc benchmarks are improved by >70% [compared to gcc 3.3.2 on
++# Opteron 240 CPU] plus all the bells-n-whistles from 32-bit version
++# [you'll notice a lot of resemblance], such as compressed S-boxes
++# in little-endian byte order, prefetch of these tables in CBC mode,
++# as well as avoiding L1 cache aliasing between stack frame and key
++# schedule and already mentioned tables, compressed Td4...
++#
++# Performance in number of cycles per processed byte for 128-bit key:
++#
++#		ECB encrypt	ECB decrypt	CBC large chunk
++# AMD64		33		43		13.0
++# EM64T		38		56		18.6(*)
++# Core 2	30		42		14.5(*)
++# Atom		65		86		32.1(*)
++#
++# (*) with hyper-threading off
++
++$flavour = shift;
++$output  = shift;
++if ($flavour =~ /\./) { $output = $flavour; undef $flavour; }
++
++$win64=0; $win64=1 if ($flavour =~ /[nm]asm|mingw64/ || $output =~ /\.asm$/);
++
++$0 =~ m/(.*[\/\\])[^\/\\]+$/; $dir=$1;
++( $xlate="${dir}x86_64-xlate.pl" and -f $xlate ) or
++( $xlate="${dir}../../perlasm/x86_64-xlate.pl" and -f $xlate) or
++die "can't locate x86_64-xlate.pl";
++
++open OUT,"| \"$^X\" \"$xlate\" $flavour \"$output\"";
++*STDOUT=*OUT;
++
++$verticalspin=1;	# unlike 32-bit version $verticalspin performs
++			# ~15% better on both AMD and Intel cores
++$speed_limit=512;	# see aes-586.pl for details
++
++$code=".text\n";
++
++$s0="%eax";
++$s1="%ebx";
++$s2="%ecx";
++$s3="%edx";
++$acc0="%esi";	$mask80="%rsi";
++$acc1="%edi";	$maskfe="%rdi";
++$acc2="%ebp";	$mask1b="%rbp";
++$inp="%r8";
++$out="%r9";
++$t0="%r10d";
++$t1="%r11d";
++$t2="%r12d";
++$rnds="%r13d";
++$sbox="%r14";
++$key="%r15";
++
++sub hi() { my $r=shift;	$r =~ s/%[er]([a-d])x/%\1h/;	$r; }
++sub lo() { my $r=shift;	$r =~ s/%[er]([a-d])x/%\1l/;
++			$r =~ s/%[er]([sd]i)/%\1l/;
++			$r =~ s/%(r[0-9]+)[d]?/%\1b/;	$r; }
++sub LO() { my $r=shift; $r =~ s/%r([a-z]+)/%e\1/;
++			$r =~ s/%r([0-9]+)/%r\1d/;	$r; }
++sub _data_word()
++{ my $i;
++    while(defined($i=shift)) { $code.=sprintf".long\t0x%08x,0x%08x\n",$i,$i; }
++}
++sub data_word()
++{ my $i;
++  my $last=pop(@_);
++    $code.=".long\t";
++    while(defined($i=shift)) { $code.=sprintf"0x%08x,",$i; }
++    $code.=sprintf"0x%08x\n",$last;
++}
++
++sub data_byte()
++{ my $i;
++  my $last=pop(@_);
++    $code.=".byte\t";
++    while(defined($i=shift)) { $code.=sprintf"0x%02x,",$i&0xff; }
++    $code.=sprintf"0x%02x\n",$last&0xff;
++}
++
++sub encvert()
++{ my $t3="%r8d";	# zaps $inp!
++
++$code.=<<___;
++	# favor 3-way issue Opteron pipeline...
++	movzb	`&lo("$s0")`,$acc0
++	movzb	`&lo("$s1")`,$acc1
++	movzb	`&lo("$s2")`,$acc2
++	mov	0($sbox,$acc0,8),$t0
++	mov	0($sbox,$acc1,8),$t1
++	mov	0($sbox,$acc2,8),$t2
++
++	movzb	`&hi("$s1")`,$acc0
++	movzb	`&hi("$s2")`,$acc1
++	movzb	`&lo("$s3")`,$acc2
++	xor	3($sbox,$acc0,8),$t0
++	xor	3($sbox,$acc1,8),$t1
++	mov	0($sbox,$acc2,8),$t3
++
++	movzb	`&hi("$s3")`,$acc0
++	shr	\$16,$s2
++	movzb	`&hi("$s0")`,$acc2
++	xor	3($sbox,$acc0,8),$t2
++	shr	\$16,$s3
++	xor	3($sbox,$acc2,8),$t3
++
++	shr	\$16,$s1
++	lea	16($key),$key
++	shr	\$16,$s0
++
++	movzb	`&lo("$s2")`,$acc0
++	movzb	`&lo("$s3")`,$acc1
++	movzb	`&lo("$s0")`,$acc2
++	xor	2($sbox,$acc0,8),$t0
++	xor	2($sbox,$acc1,8),$t1
++	xor	2($sbox,$acc2,8),$t2
++
++	movzb	`&hi("$s3")`,$acc0
++	movzb	`&hi("$s0")`,$acc1
++	movzb	`&lo("$s1")`,$acc2
++	xor	1($sbox,$acc0,8),$t0
++	xor	1($sbox,$acc1,8),$t1
++	xor	2($sbox,$acc2,8),$t3
++
++	mov	12($key),$s3
++	movzb	`&hi("$s1")`,$acc1
++	movzb	`&hi("$s2")`,$acc2
++	mov	0($key),$s0
++	xor	1($sbox,$acc1,8),$t2
++	xor	1($sbox,$acc2,8),$t3
++
++	mov	4($key),$s1
++	mov	8($key),$s2
++	xor	$t0,$s0
++	xor	$t1,$s1
++	xor	$t2,$s2
++	xor	$t3,$s3
++___
++}
++
++sub enclastvert()
++{ my $t3="%r8d";	# zaps $inp!
++
++$code.=<<___;
++	movzb	`&lo("$s0")`,$acc0
++	movzb	`&lo("$s1")`,$acc1
++	movzb	`&lo("$s2")`,$acc2
++	movzb	2($sbox,$acc0,8),$t0
++	movzb	2($sbox,$acc1,8),$t1
++	movzb	2($sbox,$acc2,8),$t2
++
++	movzb	`&lo("$s3")`,$acc0
++	movzb	`&hi("$s1")`,$acc1
++	movzb	`&hi("$s2")`,$acc2
++	movzb	2($sbox,$acc0,8),$t3
++	mov	0($sbox,$acc1,8),$acc1	#$t0
++	mov	0($sbox,$acc2,8),$acc2	#$t1
++
++	and	\$0x0000ff00,$acc1
++	and	\$0x0000ff00,$acc2
++
++	xor	$acc1,$t0
++	xor	$acc2,$t1
++	shr	\$16,$s2
++
++	movzb	`&hi("$s3")`,$acc0
++	movzb	`&hi("$s0")`,$acc1
++	shr	\$16,$s3
++	mov	0($sbox,$acc0,8),$acc0	#$t2
++	mov	0($sbox,$acc1,8),$acc1	#$t3
++
++	and	\$0x0000ff00,$acc0
++	and	\$0x0000ff00,$acc1
++	shr	\$16,$s1
++	xor	$acc0,$t2
++	xor	$acc1,$t3
++	shr	\$16,$s0
++
++	movzb	`&lo("$s2")`,$acc0
++	movzb	`&lo("$s3")`,$acc1
++	movzb	`&lo("$s0")`,$acc2
++	mov	0($sbox,$acc0,8),$acc0	#$t0
++	mov	0($sbox,$acc1,8),$acc1	#$t1
++	mov	0($sbox,$acc2,8),$acc2	#$t2
++
++	and	\$0x00ff0000,$acc0
++	and	\$0x00ff0000,$acc1
++	and	\$0x00ff0000,$acc2
++
++	xor	$acc0,$t0
++	xor	$acc1,$t1
++	xor	$acc2,$t2
++
++	movzb	`&lo("$s1")`,$acc0
++	movzb	`&hi("$s3")`,$acc1
++	movzb	`&hi("$s0")`,$acc2
++	mov	0($sbox,$acc0,8),$acc0	#$t3
++	mov	2($sbox,$acc1,8),$acc1	#$t0
++	mov	2($sbox,$acc2,8),$acc2	#$t1
++
++	and	\$0x00ff0000,$acc0
++	and	\$0xff000000,$acc1
++	and	\$0xff000000,$acc2
++
++	xor	$acc0,$t3
++	xor	$acc1,$t0
++	xor	$acc2,$t1
++
++	movzb	`&hi("$s1")`,$acc0
++	movzb	`&hi("$s2")`,$acc1
++	mov	16+12($key),$s3
++	mov	2($sbox,$acc0,8),$acc0	#$t2
++	mov	2($sbox,$acc1,8),$acc1	#$t3
++	mov	16+0($key),$s0
++
++	and	\$0xff000000,$acc0
++	and	\$0xff000000,$acc1
++
++	xor	$acc0,$t2
++	xor	$acc1,$t3
++
++	mov	16+4($key),$s1
++	mov	16+8($key),$s2
++	xor	$t0,$s0
++	xor	$t1,$s1
++	xor	$t2,$s2
++	xor	$t3,$s3
++___
++}
++
++sub encstep()
++{ my ($i,@s) = @_;
++  my $tmp0=$acc0;
++  my $tmp1=$acc1;
++  my $tmp2=$acc2;
++  my $out=($t0,$t1,$t2,$s[0])[$i];
++
++	if ($i==3) {
++		$tmp0=$s[1];
++		$tmp1=$s[2];
++		$tmp2=$s[3];
++	}
++	$code.="	movzb	".&lo($s[0]).",$out\n";
++	$code.="	mov	$s[2],$tmp1\n"		if ($i!=3);
++	$code.="	lea	16($key),$key\n"	if ($i==0);
++
++	$code.="	movzb	".&hi($s[1]).",$tmp0\n";
++	$code.="	mov	0($sbox,$out,8),$out\n";
++
++	$code.="	shr	\$16,$tmp1\n";
++	$code.="	mov	$s[3],$tmp2\n"		if ($i!=3);
++	$code.="	xor	3($sbox,$tmp0,8),$out\n";
++
++	$code.="	movzb	".&lo($tmp1).",$tmp1\n";
++	$code.="	shr	\$24,$tmp2\n";
++	$code.="	xor	4*$i($key),$out\n";
++
++	$code.="	xor	2($sbox,$tmp1,8),$out\n";
++	$code.="	xor	1($sbox,$tmp2,8),$out\n";
++
++	$code.="	mov	$t0,$s[1]\n"		if ($i==3);
++	$code.="	mov	$t1,$s[2]\n"		if ($i==3);
++	$code.="	mov	$t2,$s[3]\n"		if ($i==3);
++	$code.="\n";
++}
++
++sub enclast()
++{ my ($i,@s)=@_;
++  my $tmp0=$acc0;
++  my $tmp1=$acc1;
++  my $tmp2=$acc2;
++  my $out=($t0,$t1,$t2,$s[0])[$i];
++
++	if ($i==3) {
++		$tmp0=$s[1];
++		$tmp1=$s[2];
++		$tmp2=$s[3];
++	}
++	$code.="	movzb	".&lo($s[0]).",$out\n";
++	$code.="	mov	$s[2],$tmp1\n"		if ($i!=3);
++
++	$code.="	mov	2($sbox,$out,8),$out\n";
++	$code.="	shr	\$16,$tmp1\n";
++	$code.="	mov	$s[3],$tmp2\n"		if ($i!=3);
++
++	$code.="	and	\$0x000000ff,$out\n";
++	$code.="	movzb	".&hi($s[1]).",$tmp0\n";
++	$code.="	movzb	".&lo($tmp1).",$tmp1\n";
++	$code.="	shr	\$24,$tmp2\n";
++
++	$code.="	mov	0($sbox,$tmp0,8),$tmp0\n";
++	$code.="	mov	0($sbox,$tmp1,8),$tmp1\n";
++	$code.="	mov	2($sbox,$tmp2,8),$tmp2\n";
++
++	$code.="	and	\$0x0000ff00,$tmp0\n";
++	$code.="	and	\$0x00ff0000,$tmp1\n";
++	$code.="	and	\$0xff000000,$tmp2\n";
++
++	$code.="	xor	$tmp0,$out\n";
++	$code.="	mov	$t0,$s[1]\n"		if ($i==3);
++	$code.="	xor	$tmp1,$out\n";
++	$code.="	mov	$t1,$s[2]\n"		if ($i==3);
++	$code.="	xor	$tmp2,$out\n";
++	$code.="	mov	$t2,$s[3]\n"		if ($i==3);
++	$code.="\n";
++}
++
++$code.=<<___;
++.type	_x86_64_AES_encrypt,\@abi-omnipotent
++.align	16
++_x86_64_AES_encrypt:
++	xor	0($key),$s0			# xor with key
++	xor	4($key),$s1
++	xor	8($key),$s2
++	xor	12($key),$s3
++
++	mov	240($key),$rnds			# load key->rounds
++	sub	\$1,$rnds
++	jmp	.Lenc_loop
++.align	16
++.Lenc_loop:
++___
++	if ($verticalspin) { &encvert(); }
++	else {	&encstep(0,$s0,$s1,$s2,$s3);
++		&encstep(1,$s1,$s2,$s3,$s0);
++		&encstep(2,$s2,$s3,$s0,$s1);
++		&encstep(3,$s3,$s0,$s1,$s2);
++	}
++$code.=<<___;
++	sub	\$1,$rnds
++	jnz	.Lenc_loop
++___
++	if ($verticalspin) { &enclastvert(); }
++	else {	&enclast(0,$s0,$s1,$s2,$s3);
++		&enclast(1,$s1,$s2,$s3,$s0);
++		&enclast(2,$s2,$s3,$s0,$s1);
++		&enclast(3,$s3,$s0,$s1,$s2);
++		$code.=<<___;
++		xor	16+0($key),$s0		# xor with key
++		xor	16+4($key),$s1
++		xor	16+8($key),$s2
++		xor	16+12($key),$s3
++___
++	}
++$code.=<<___;
++	.byte	0xf3,0xc3			# rep ret
++.size	_x86_64_AES_encrypt,.-_x86_64_AES_encrypt
++___
++
++# it's possible to implement this by shifting tN by 8, filling least
++# significant byte with byte load and finally bswap-ing at the end,
++# but such partial register load kills Core 2...
++sub enccompactvert()
++{ my ($t3,$t4,$t5)=("%r8d","%r9d","%r13d");
++
++$code.=<<___;
++	movzb	`&lo("$s0")`,$t0
++	movzb	`&lo("$s1")`,$t1
++	movzb	`&lo("$s2")`,$t2
++	movzb	`&lo("$s3")`,$t3
++	movzb	`&hi("$s1")`,$acc0
++	movzb	`&hi("$s2")`,$acc1
++	shr	\$16,$s2
++	movzb	`&hi("$s3")`,$acc2
++	movzb	($sbox,$t0,1),$t0
++	movzb	($sbox,$t1,1),$t1
++	movzb	($sbox,$t2,1),$t2
++	movzb	($sbox,$t3,1),$t3
++
++	movzb	($sbox,$acc0,1),$t4	#$t0
++	movzb	`&hi("$s0")`,$acc0
++	movzb	($sbox,$acc1,1),$t5	#$t1
++	movzb	`&lo("$s2")`,$acc1
++	movzb	($sbox,$acc2,1),$acc2	#$t2
++	movzb	($sbox,$acc0,1),$acc0	#$t3
++
++	shl	\$8,$t4
++	shr	\$16,$s3
++	shl	\$8,$t5
++	xor	$t4,$t0
++	shr	\$16,$s0
++	movzb	`&lo("$s3")`,$t4
++	shr	\$16,$s1
++	xor	$t5,$t1
++	shl	\$8,$acc2
++	movzb	`&lo("$s0")`,$t5
++	movzb	($sbox,$acc1,1),$acc1	#$t0
++	xor	$acc2,$t2
++
++	shl	\$8,$acc0
++	movzb	`&lo("$s1")`,$acc2
++	shl	\$16,$acc1
++	xor	$acc0,$t3
++	movzb	($sbox,$t4,1),$t4	#$t1
++	movzb	`&hi("$s3")`,$acc0
++	movzb	($sbox,$t5,1),$t5	#$t2
++	xor	$acc1,$t0
++
++	shr	\$8,$s2
++	movzb	`&hi("$s0")`,$acc1
++	shl	\$16,$t4
++	shr	\$8,$s1
++	shl	\$16,$t5
++	xor	$t4,$t1
++	movzb	($sbox,$acc2,1),$acc2	#$t3
++	movzb	($sbox,$acc0,1),$acc0	#$t0
++	movzb	($sbox,$acc1,1),$acc1	#$t1
++	movzb	($sbox,$s2,1),$s3	#$t3
++	movzb	($sbox,$s1,1),$s2	#$t2
++
++	shl	\$16,$acc2
++	xor	$t5,$t2
++	shl	\$24,$acc0
++	xor	$acc2,$t3
++	shl	\$24,$acc1
++	xor	$acc0,$t0
++	shl	\$24,$s3
++	xor	$acc1,$t1
++	shl	\$24,$s2
++	mov	$t0,$s0
++	mov	$t1,$s1
++	xor	$t2,$s2
++	xor	$t3,$s3
++___
++}
++
++sub enctransform_ref()
++{ my $sn = shift;
++  my ($acc,$r2,$tmp)=("%r8d","%r9d","%r13d");
++
++$code.=<<___;
++	mov	$sn,$acc
++	and	\$0x80808080,$acc
++	mov	$acc,$tmp
++	shr	\$7,$tmp
++	lea	($sn,$sn),$r2
++	sub	$tmp,$acc
++	and	\$0xfefefefe,$r2
++	and	\$0x1b1b1b1b,$acc
++	mov	$sn,$tmp
++	xor	$acc,$r2
++
++	xor	$r2,$sn
++	rol	\$24,$sn
++	xor	$r2,$sn
++	ror	\$16,$tmp
++	xor	$tmp,$sn
++	ror	\$8,$tmp
++	xor	$tmp,$sn
++___
++}
++
++# unlike decrypt case it does not pay off to parallelize enctransform
++sub enctransform()
++{ my ($t3,$r20,$r21)=($acc2,"%r8d","%r9d");
++
++$code.=<<___;
++	mov	\$0x80808080,$t0
++	mov	\$0x80808080,$t1
++	and	$s0,$t0
++	and	$s1,$t1
++	mov	$t0,$acc0
++	mov	$t1,$acc1
++	shr	\$7,$t0
++	lea	($s0,$s0),$r20
++	shr	\$7,$t1
++	lea	($s1,$s1),$r21
++	sub	$t0,$acc0
++	sub	$t1,$acc1
++	and	\$0xfefefefe,$r20
++	and	\$0xfefefefe,$r21
++	and	\$0x1b1b1b1b,$acc0
++	and	\$0x1b1b1b1b,$acc1
++	mov	$s0,$t0
++	mov	$s1,$t1
++	xor	$acc0,$r20
++	xor	$acc1,$r21
++
++	xor	$r20,$s0
++	xor	$r21,$s1
++	 mov	\$0x80808080,$t2
++	rol	\$24,$s0
++	 mov	\$0x80808080,$t3
++	rol	\$24,$s1
++	 and	$s2,$t2
++	 and	$s3,$t3
++	xor	$r20,$s0
++	xor	$r21,$s1
++	 mov	$t2,$acc0
++	ror	\$16,$t0
++	 mov	$t3,$acc1
++	ror	\$16,$t1
++	 lea	($s2,$s2),$r20
++	 shr	\$7,$t2
++	xor	$t0,$s0
++	 shr	\$7,$t3
++	xor	$t1,$s1
++	ror	\$8,$t0
++	 lea	($s3,$s3),$r21
++	ror	\$8,$t1
++	 sub	$t2,$acc0
++	 sub	$t3,$acc1
++	xor	$t0,$s0
++	xor	$t1,$s1
++
++	and	\$0xfefefefe,$r20
++	and	\$0xfefefefe,$r21
++	and	\$0x1b1b1b1b,$acc0
++	and	\$0x1b1b1b1b,$acc1
++	mov	$s2,$t2
++	mov	$s3,$t3
++	xor	$acc0,$r20
++	xor	$acc1,$r21
++
++	ror	\$16,$t2
++	xor	$r20,$s2
++	ror	\$16,$t3
++	xor	$r21,$s3
++	rol	\$24,$s2
++	mov	0($sbox),$acc0			# prefetch Te4
++	rol	\$24,$s3
++	xor	$r20,$s2
++	mov	64($sbox),$acc1
++	xor	$r21,$s3
++	mov	128($sbox),$r20
++	xor	$t2,$s2
++	ror	\$8,$t2
++	xor	$t3,$s3
++	ror	\$8,$t3
++	xor	$t2,$s2
++	mov	192($sbox),$r21
++	xor	$t3,$s3
++___
++}
++
++$code.=<<___;
++.type	_x86_64_AES_encrypt_compact,\@abi-omnipotent
++.align	16
++_x86_64_AES_encrypt_compact:
++	lea	128($sbox),$inp			# size optimization
++	mov	0-128($inp),$acc1		# prefetch Te4
++	mov	32-128($inp),$acc2
++	mov	64-128($inp),$t0
++	mov	96-128($inp),$t1
++	mov	128-128($inp),$acc1
++	mov	160-128($inp),$acc2
++	mov	192-128($inp),$t0
++	mov	224-128($inp),$t1
++	jmp	.Lenc_loop_compact
++.align	16
++.Lenc_loop_compact:
++		xor	0($key),$s0		# xor with key
++		xor	4($key),$s1
++		xor	8($key),$s2
++		xor	12($key),$s3
++		lea	16($key),$key
++___
++		&enccompactvert();
++$code.=<<___;
++		cmp	16(%rsp),$key
++		je	.Lenc_compact_done
++___
++		&enctransform();
++$code.=<<___;
++	jmp	.Lenc_loop_compact
++.align	16
++.Lenc_compact_done:
++	xor	0($key),$s0
++	xor	4($key),$s1
++	xor	8($key),$s2
++	xor	12($key),$s3
++	.byte	0xf3,0xc3			# rep ret
++.size	_x86_64_AES_encrypt_compact,.-_x86_64_AES_encrypt_compact
++___
++
++# void AES_encrypt (const void *inp,void *out,const AES_KEY *key);
++$code.=<<___;
++.globl	AES_encrypt
++.type	AES_encrypt,\@function,3
++.align	16
++.globl	asm_AES_encrypt
++.hidden	asm_AES_encrypt
++asm_AES_encrypt:
++AES_encrypt:
++	push	%rbx
++	push	%rbp
++	push	%r12
++	push	%r13
++	push	%r14
++	push	%r15
++
++	# allocate frame "above" key schedule
++	mov	%rsp,%r10
++	lea	-63(%rdx),%rcx	# %rdx is key argument
++	and	\$-64,%rsp
++	sub	%rsp,%rcx
++	neg	%rcx
++	and	\$0x3c0,%rcx
++	sub	%rcx,%rsp
++	sub	\$32,%rsp
++
++	mov	%rsi,16(%rsp)	# save out
++	mov	%r10,24(%rsp)	# save real stack pointer
++.Lenc_prologue:
++
++	mov	%rdx,$key
++	mov	240($key),$rnds	# load rounds
++
++	mov	0(%rdi),$s0	# load input vector
++	mov	4(%rdi),$s1
++	mov	8(%rdi),$s2
++	mov	12(%rdi),$s3
++
++	shl	\$4,$rnds
++	lea	($key,$rnds),%rbp
++	mov	$key,(%rsp)	# key schedule
++	mov	%rbp,8(%rsp)	# end of key schedule
++
++	# pick Te4 copy which can't "overlap" with stack frame or key schedule
++	lea	.LAES_Te+2048(%rip),$sbox
++	lea	768(%rsp),%rbp
++	sub	$sbox,%rbp
++	and	\$0x300,%rbp
++	lea	($sbox,%rbp),$sbox
++
++	call	_x86_64_AES_encrypt_compact
++
++	mov	16(%rsp),$out	# restore out
++	mov	24(%rsp),%rsi	# restore saved stack pointer
++	mov	$s0,0($out)	# write output vector
++	mov	$s1,4($out)
++	mov	$s2,8($out)
++	mov	$s3,12($out)
++
++	mov	(%rsi),%r15
++	mov	8(%rsi),%r14
++	mov	16(%rsi),%r13
++	mov	24(%rsi),%r12
++	mov	32(%rsi),%rbp
++	mov	40(%rsi),%rbx
++	lea	48(%rsi),%rsp
++.Lenc_epilogue:
++	ret
++.size	AES_encrypt,.-AES_encrypt
++___
++
++#------------------------------------------------------------------#
++
++sub decvert()
++{ my $t3="%r8d";	# zaps $inp!
++
++$code.=<<___;
++	# favor 3-way issue Opteron pipeline...
++	movzb	`&lo("$s0")`,$acc0
++	movzb	`&lo("$s1")`,$acc1
++	movzb	`&lo("$s2")`,$acc2
++	mov	0($sbox,$acc0,8),$t0
++	mov	0($sbox,$acc1,8),$t1
++	mov	0($sbox,$acc2,8),$t2
++
++	movzb	`&hi("$s3")`,$acc0
++	movzb	`&hi("$s0")`,$acc1
++	movzb	`&lo("$s3")`,$acc2
++	xor	3($sbox,$acc0,8),$t0
++	xor	3($sbox,$acc1,8),$t1
++	mov	0($sbox,$acc2,8),$t3
++
++	movzb	`&hi("$s1")`,$acc0
++	shr	\$16,$s0
++	movzb	`&hi("$s2")`,$acc2
++	xor	3($sbox,$acc0,8),$t2
++	shr	\$16,$s3
++	xor	3($sbox,$acc2,8),$t3
++
++	shr	\$16,$s1
++	lea	16($key),$key
++	shr	\$16,$s2
++
++	movzb	`&lo("$s2")`,$acc0
++	movzb	`&lo("$s3")`,$acc1
++	movzb	`&lo("$s0")`,$acc2
++	xor	2($sbox,$acc0,8),$t0
++	xor	2($sbox,$acc1,8),$t1
++	xor	2($sbox,$acc2,8),$t2
++
++	movzb	`&hi("$s1")`,$acc0
++	movzb	`&hi("$s2")`,$acc1
++	movzb	`&lo("$s1")`,$acc2
++	xor	1($sbox,$acc0,8),$t0
++	xor	1($sbox,$acc1,8),$t1
++	xor	2($sbox,$acc2,8),$t3
++
++	movzb	`&hi("$s3")`,$acc0
++	mov	12($key),$s3
++	movzb	`&hi("$s0")`,$acc2
++	xor	1($sbox,$acc0,8),$t2
++	mov	0($key),$s0
++	xor	1($sbox,$acc2,8),$t3
++
++	xor	$t0,$s0
++	mov	4($key),$s1
++	mov	8($key),$s2
++	xor	$t2,$s2
++	xor	$t1,$s1
++	xor	$t3,$s3
++___
++}
++
++sub declastvert()
++{ my $t3="%r8d";	# zaps $inp!
++
++$code.=<<___;
++	lea	2048($sbox),$sbox	# size optimization
++	movzb	`&lo("$s0")`,$acc0
++	movzb	`&lo("$s1")`,$acc1
++	movzb	`&lo("$s2")`,$acc2
++	movzb	($sbox,$acc0,1),$t0
++	movzb	($sbox,$acc1,1),$t1
++	movzb	($sbox,$acc2,1),$t2
++
++	movzb	`&lo("$s3")`,$acc0
++	movzb	`&hi("$s3")`,$acc1
++	movzb	`&hi("$s0")`,$acc2
++	movzb	($sbox,$acc0,1),$t3
++	movzb	($sbox,$acc1,1),$acc1	#$t0
++	movzb	($sbox,$acc2,1),$acc2	#$t1
++
++	shl	\$8,$acc1
++	shl	\$8,$acc2
++
++	xor	$acc1,$t0
++	xor	$acc2,$t1
++	shr	\$16,$s3
++
++	movzb	`&hi("$s1")`,$acc0
++	movzb	`&hi("$s2")`,$acc1
++	shr	\$16,$s0
++	movzb	($sbox,$acc0,1),$acc0	#$t2
++	movzb	($sbox,$acc1,1),$acc1	#$t3
++
++	shl	\$8,$acc0
++	shl	\$8,$acc1
++	shr	\$16,$s1
++	xor	$acc0,$t2
++	xor	$acc1,$t3
++	shr	\$16,$s2
++
++	movzb	`&lo("$s2")`,$acc0
++	movzb	`&lo("$s3")`,$acc1
++	movzb	`&lo("$s0")`,$acc2
++	movzb	($sbox,$acc0,1),$acc0	#$t0
++	movzb	($sbox,$acc1,1),$acc1	#$t1
++	movzb	($sbox,$acc2,1),$acc2	#$t2
++
++	shl	\$16,$acc0
++	shl	\$16,$acc1
++	shl	\$16,$acc2
++
++	xor	$acc0,$t0
++	xor	$acc1,$t1
++	xor	$acc2,$t2
++
++	movzb	`&lo("$s1")`,$acc0
++	movzb	`&hi("$s1")`,$acc1
++	movzb	`&hi("$s2")`,$acc2
++	movzb	($sbox,$acc0,1),$acc0	#$t3
++	movzb	($sbox,$acc1,1),$acc1	#$t0
++	movzb	($sbox,$acc2,1),$acc2	#$t1
++
++	shl	\$16,$acc0
++	shl	\$24,$acc1
++	shl	\$24,$acc2
++
++	xor	$acc0,$t3
++	xor	$acc1,$t0
++	xor	$acc2,$t1
++
++	movzb	`&hi("$s3")`,$acc0
++	movzb	`&hi("$s0")`,$acc1
++	mov	16+12($key),$s3
++	movzb	($sbox,$acc0,1),$acc0	#$t2
++	movzb	($sbox,$acc1,1),$acc1	#$t3
++	mov	16+0($key),$s0
++
++	shl	\$24,$acc0
++	shl	\$24,$acc1
++
++	xor	$acc0,$t2
++	xor	$acc1,$t3
++
++	mov	16+4($key),$s1
++	mov	16+8($key),$s2
++	lea	-2048($sbox),$sbox
++	xor	$t0,$s0
++	xor	$t1,$s1
++	xor	$t2,$s2
++	xor	$t3,$s3
++___
++}
++
++sub decstep()
++{ my ($i,@s) = @_;
++  my $tmp0=$acc0;
++  my $tmp1=$acc1;
++  my $tmp2=$acc2;
++  my $out=($t0,$t1,$t2,$s[0])[$i];
++
++	$code.="	mov	$s[0],$out\n"		if ($i!=3);
++			$tmp1=$s[2]			if ($i==3);
++	$code.="	mov	$s[2],$tmp1\n"		if ($i!=3);
++	$code.="	and	\$0xFF,$out\n";
++
++	$code.="	mov	0($sbox,$out,8),$out\n";
++	$code.="	shr	\$16,$tmp1\n";
++			$tmp2=$s[3]			if ($i==3);
++	$code.="	mov	$s[3],$tmp2\n"		if ($i!=3);
++
++			$tmp0=$s[1]			if ($i==3);
++	$code.="	movzb	".&hi($s[1]).",$tmp0\n";
++	$code.="	and	\$0xFF,$tmp1\n";
++	$code.="	shr	\$24,$tmp2\n";
++
++	$code.="	xor	3($sbox,$tmp0,8),$out\n";
++	$code.="	xor	2($sbox,$tmp1,8),$out\n";
++	$code.="	xor	1($sbox,$tmp2,8),$out\n";
++
++	$code.="	mov	$t2,$s[1]\n"		if ($i==3);
++	$code.="	mov	$t1,$s[2]\n"		if ($i==3);
++	$code.="	mov	$t0,$s[3]\n"		if ($i==3);
++	$code.="\n";
++}
++
++sub declast()
++{ my ($i,@s)=@_;
++  my $tmp0=$acc0;
++  my $tmp1=$acc1;
++  my $tmp2=$acc2;
++  my $out=($t0,$t1,$t2,$s[0])[$i];
++
++	$code.="	mov	$s[0],$out\n"		if ($i!=3);
++			$tmp1=$s[2]			if ($i==3);
++	$code.="	mov	$s[2],$tmp1\n"		if ($i!=3);
++	$code.="	and	\$0xFF,$out\n";
++
++	$code.="	movzb	2048($sbox,$out,1),$out\n";
++	$code.="	shr	\$16,$tmp1\n";
++			$tmp2=$s[3]			if ($i==3);
++	$code.="	mov	$s[3],$tmp2\n"		if ($i!=3);
++
++			$tmp0=$s[1]			if ($i==3);
++	$code.="	movzb	".&hi($s[1]).",$tmp0\n";
++	$code.="	and	\$0xFF,$tmp1\n";
++	$code.="	shr	\$24,$tmp2\n";
++
++	$code.="	movzb	2048($sbox,$tmp0,1),$tmp0\n";
++	$code.="	movzb	2048($sbox,$tmp1,1),$tmp1\n";
++	$code.="	movzb	2048($sbox,$tmp2,1),$tmp2\n";
++
++	$code.="	shl	\$8,$tmp0\n";
++	$code.="	shl	\$16,$tmp1\n";
++	$code.="	shl	\$24,$tmp2\n";
++
++	$code.="	xor	$tmp0,$out\n";
++	$code.="	mov	$t2,$s[1]\n"		if ($i==3);
++	$code.="	xor	$tmp1,$out\n";
++	$code.="	mov	$t1,$s[2]\n"		if ($i==3);
++	$code.="	xor	$tmp2,$out\n";
++	$code.="	mov	$t0,$s[3]\n"		if ($i==3);
++	$code.="\n";
++}
++
++$code.=<<___;
++.type	_x86_64_AES_decrypt,\@abi-omnipotent
++.align	16
++_x86_64_AES_decrypt:
++	xor	0($key),$s0			# xor with key
++	xor	4($key),$s1
++	xor	8($key),$s2
++	xor	12($key),$s3
++
++	mov	240($key),$rnds			# load key->rounds
++	sub	\$1,$rnds
++	jmp	.Ldec_loop
++.align	16
++.Ldec_loop:
++___
++	if ($verticalspin) { &decvert(); }
++	else {	&decstep(0,$s0,$s3,$s2,$s1);
++		&decstep(1,$s1,$s0,$s3,$s2);
++		&decstep(2,$s2,$s1,$s0,$s3);
++		&decstep(3,$s3,$s2,$s1,$s0);
++		$code.=<<___;
++		lea	16($key),$key
++		xor	0($key),$s0			# xor with key
++		xor	4($key),$s1
++		xor	8($key),$s2
++		xor	12($key),$s3
++___
++	}
++$code.=<<___;
++	sub	\$1,$rnds
++	jnz	.Ldec_loop
++___
++	if ($verticalspin) { &declastvert(); }
++	else {	&declast(0,$s0,$s3,$s2,$s1);
++		&declast(1,$s1,$s0,$s3,$s2);
++		&declast(2,$s2,$s1,$s0,$s3);
++		&declast(3,$s3,$s2,$s1,$s0);
++		$code.=<<___;
++		xor	16+0($key),$s0			# xor with key
++		xor	16+4($key),$s1
++		xor	16+8($key),$s2
++		xor	16+12($key),$s3
++___
++	}
++$code.=<<___;
++	.byte	0xf3,0xc3			# rep ret
++.size	_x86_64_AES_decrypt,.-_x86_64_AES_decrypt
++___
++
++sub deccompactvert()
++{ my ($t3,$t4,$t5)=("%r8d","%r9d","%r13d");
++
++$code.=<<___;
++	movzb	`&lo("$s0")`,$t0
++	movzb	`&lo("$s1")`,$t1
++	movzb	`&lo("$s2")`,$t2
++	movzb	`&lo("$s3")`,$t3
++	movzb	`&hi("$s3")`,$acc0
++	movzb	`&hi("$s0")`,$acc1
++	shr	\$16,$s3
++	movzb	`&hi("$s1")`,$acc2
++	movzb	($sbox,$t0,1),$t0
++	movzb	($sbox,$t1,1),$t1
++	movzb	($sbox,$t2,1),$t2
++	movzb	($sbox,$t3,1),$t3
++
++	movzb	($sbox,$acc0,1),$t4	#$t0
++	movzb	`&hi("$s2")`,$acc0
++	movzb	($sbox,$acc1,1),$t5	#$t1
++	movzb	($sbox,$acc2,1),$acc2	#$t2
++	movzb	($sbox,$acc0,1),$acc0	#$t3
++
++	shr	\$16,$s2
++	shl	\$8,$t5
++	shl	\$8,$t4
++	movzb	`&lo("$s2")`,$acc1
++	shr	\$16,$s0
++	xor	$t4,$t0
++	shr	\$16,$s1
++	movzb	`&lo("$s3")`,$t4
++
++	shl	\$8,$acc2
++	xor	$t5,$t1
++	shl	\$8,$acc0
++	movzb	`&lo("$s0")`,$t5
++	movzb	($sbox,$acc1,1),$acc1	#$t0
++	xor	$acc2,$t2
++	movzb	`&lo("$s1")`,$acc2
++
++	shl	\$16,$acc1
++	xor	$acc0,$t3
++	movzb	($sbox,$t4,1),$t4	#$t1
++	movzb	`&hi("$s1")`,$acc0
++	movzb	($sbox,$acc2,1),$acc2	#$t3
++	xor	$acc1,$t0
++	movzb	($sbox,$t5,1),$t5	#$t2
++	movzb	`&hi("$s2")`,$acc1
++
++	shl	\$16,$acc2
++	shl	\$16,$t4
++	shl	\$16,$t5
++	xor	$acc2,$t3
++	movzb	`&hi("$s3")`,$acc2
++	xor	$t4,$t1
++	shr	\$8,$s0
++	xor	$t5,$t2
++
++	movzb	($sbox,$acc0,1),$acc0	#$t0
++	movzb	($sbox,$acc1,1),$s1	#$t1
++	movzb	($sbox,$acc2,1),$s2	#$t2
++	movzb	($sbox,$s0,1),$s3	#$t3
++
++	mov	$t0,$s0
++	shl	\$24,$acc0
++	shl	\$24,$s1
++	shl	\$24,$s2
++	xor	$acc0,$s0
++	shl	\$24,$s3
++	xor	$t1,$s1
++	xor	$t2,$s2
++	xor	$t3,$s3
++___
++}
++
++# parallelized version! input is pair of 64-bit values: %rax=s1.s0
++# and %rcx=s3.s2, output is four 32-bit values in %eax=s0, %ebx=s1,
++# %ecx=s2 and %edx=s3.
++sub dectransform()
++{ my ($tp10,$tp20,$tp40,$tp80,$acc0)=("%rax","%r8", "%r9", "%r10","%rbx");
++  my ($tp18,$tp28,$tp48,$tp88,$acc8)=("%rcx","%r11","%r12","%r13","%rdx");
++  my $prefetch = shift;
++
++$code.=<<___;
++	mov	$mask80,$tp40
++	mov	$mask80,$tp48
++	and	$tp10,$tp40
++	and	$tp18,$tp48
++	mov	$tp40,$acc0
++	mov	$tp48,$acc8
++	shr	\$7,$tp40
++	lea	($tp10,$tp10),$tp20
++	shr	\$7,$tp48
++	lea	($tp18,$tp18),$tp28
++	sub	$tp40,$acc0
++	sub	$tp48,$acc8
++	and	$maskfe,$tp20
++	and	$maskfe,$tp28
++	and	$mask1b,$acc0
++	and	$mask1b,$acc8
++	xor	$acc0,$tp20
++	xor	$acc8,$tp28
++	mov	$mask80,$tp80
++	mov	$mask80,$tp88
++
++	and	$tp20,$tp80
++	and	$tp28,$tp88
++	mov	$tp80,$acc0
++	mov	$tp88,$acc8
++	shr	\$7,$tp80
++	lea	($tp20,$tp20),$tp40
++	shr	\$7,$tp88
++	lea	($tp28,$tp28),$tp48
++	sub	$tp80,$acc0
++	sub	$tp88,$acc8
++	and	$maskfe,$tp40
++	and	$maskfe,$tp48
++	and	$mask1b,$acc0
++	and	$mask1b,$acc8
++	xor	$acc0,$tp40
++	xor	$acc8,$tp48
++	mov	$mask80,$tp80
++	mov	$mask80,$tp88
++
++	and	$tp40,$tp80
++	and	$tp48,$tp88
++	mov	$tp80,$acc0
++	mov	$tp88,$acc8
++	shr	\$7,$tp80
++	 xor	$tp10,$tp20		# tp2^=tp1
++	shr	\$7,$tp88
++	 xor	$tp18,$tp28		# tp2^=tp1
++	sub	$tp80,$acc0
++	sub	$tp88,$acc8
++	lea	($tp40,$tp40),$tp80
++	lea	($tp48,$tp48),$tp88
++	 xor	$tp10,$tp40		# tp4^=tp1
++	 xor	$tp18,$tp48		# tp4^=tp1
++	and	$maskfe,$tp80
++	and	$maskfe,$tp88
++	and	$mask1b,$acc0
++	and	$mask1b,$acc8
++	xor	$acc0,$tp80
++	xor	$acc8,$tp88
++
++	xor	$tp80,$tp10		# tp1^=tp8
++	xor	$tp88,$tp18		# tp1^=tp8
++	xor	$tp80,$tp20		# tp2^tp1^=tp8
++	xor	$tp88,$tp28		# tp2^tp1^=tp8
++	mov	$tp10,$acc0
++	mov	$tp18,$acc8
++	xor	$tp80,$tp40		# tp4^tp1^=tp8
++	shr	\$32,$acc0
++	xor	$tp88,$tp48		# tp4^tp1^=tp8
++	shr	\$32,$acc8
++	xor	$tp20,$tp80		# tp8^=tp8^tp2^tp1=tp2^tp1
++	rol	\$8,`&LO("$tp10")`	# ROTATE(tp1^tp8,8)
++	xor	$tp28,$tp88		# tp8^=tp8^tp2^tp1=tp2^tp1
++	rol	\$8,`&LO("$tp18")`	# ROTATE(tp1^tp8,8)
++	xor	$tp40,$tp80		# tp2^tp1^=tp8^tp4^tp1=tp8^tp4^tp2
++	rol	\$8,`&LO("$acc0")`	# ROTATE(tp1^tp8,8)
++	xor	$tp48,$tp88		# tp2^tp1^=tp8^tp4^tp1=tp8^tp4^tp2
++
++	rol	\$8,`&LO("$acc8")`	# ROTATE(tp1^tp8,8)
++	xor	`&LO("$tp80")`,`&LO("$tp10")`
++	shr	\$32,$tp80
++	xor	`&LO("$tp88")`,`&LO("$tp18")`
++	shr	\$32,$tp88
++	xor	`&LO("$tp80")`,`&LO("$acc0")`
++	xor	`&LO("$tp88")`,`&LO("$acc8")`
++
++	mov	$tp20,$tp80
++	rol	\$24,`&LO("$tp20")`	# ROTATE(tp2^tp1^tp8,24)
++	mov	$tp28,$tp88
++	rol	\$24,`&LO("$tp28")`	# ROTATE(tp2^tp1^tp8,24)
++	shr	\$32,$tp80
++	xor	`&LO("$tp20")`,`&LO("$tp10")`
++	shr	\$32,$tp88
++	xor	`&LO("$tp28")`,`&LO("$tp18")`
++	rol	\$24,`&LO("$tp80")`	# ROTATE(tp2^tp1^tp8,24)
++	mov	$tp40,$tp20
++	rol	\$24,`&LO("$tp88")`	# ROTATE(tp2^tp1^tp8,24)
++	mov	$tp48,$tp28
++	shr	\$32,$tp20
++	xor	`&LO("$tp80")`,`&LO("$acc0")`
++	shr	\$32,$tp28
++	xor	`&LO("$tp88")`,`&LO("$acc8")`
++
++	`"mov	0($sbox),$mask80"	if ($prefetch)`
++	rol	\$16,`&LO("$tp40")`	# ROTATE(tp4^tp1^tp8,16)
++	`"mov	64($sbox),$maskfe"	if ($prefetch)`
++	rol	\$16,`&LO("$tp48")`	# ROTATE(tp4^tp1^tp8,16)
++	`"mov	128($sbox),$mask1b"	if ($prefetch)`
++	rol	\$16,`&LO("$tp20")`	# ROTATE(tp4^tp1^tp8,16)
++	`"mov	192($sbox),$tp80"	if ($prefetch)`
++	xor	`&LO("$tp40")`,`&LO("$tp10")`
++	rol	\$16,`&LO("$tp28")`	# ROTATE(tp4^tp1^tp8,16)
++	xor	`&LO("$tp48")`,`&LO("$tp18")`
++	`"mov	256($sbox),$tp88"	if ($prefetch)`
++	xor	`&LO("$tp20")`,`&LO("$acc0")`
++	xor	`&LO("$tp28")`,`&LO("$acc8")`
++___
++}
++
++$code.=<<___;
++.type	_x86_64_AES_decrypt_compact,\@abi-omnipotent
++.align	16
++_x86_64_AES_decrypt_compact:
++	lea	128($sbox),$inp			# size optimization
++	mov	0-128($inp),$acc1		# prefetch Td4
++	mov	32-128($inp),$acc2
++	mov	64-128($inp),$t0
++	mov	96-128($inp),$t1
++	mov	128-128($inp),$acc1
++	mov	160-128($inp),$acc2
++	mov	192-128($inp),$t0
++	mov	224-128($inp),$t1
++	jmp	.Ldec_loop_compact
++
++.align	16
++.Ldec_loop_compact:
++		xor	0($key),$s0		# xor with key
++		xor	4($key),$s1
++		xor	8($key),$s2
++		xor	12($key),$s3
++		lea	16($key),$key
++___
++		&deccompactvert();
++$code.=<<___;
++		cmp	16(%rsp),$key
++		je	.Ldec_compact_done
++
++		mov	256+0($sbox),$mask80
++		shl	\$32,%rbx
++		shl	\$32,%rdx
++		mov	256+8($sbox),$maskfe
++		or	%rbx,%rax
++		or	%rdx,%rcx
++		mov	256+16($sbox),$mask1b
++___
++		&dectransform(1);
++$code.=<<___;
++	jmp	.Ldec_loop_compact
++.align	16
++.Ldec_compact_done:
++	xor	0($key),$s0
++	xor	4($key),$s1
++	xor	8($key),$s2
++	xor	12($key),$s3
++	.byte	0xf3,0xc3			# rep ret
++.size	_x86_64_AES_decrypt_compact,.-_x86_64_AES_decrypt_compact
++___
++
++# void AES_decrypt (const void *inp,void *out,const AES_KEY *key);
++$code.=<<___;
++.globl	AES_decrypt
++.type	AES_decrypt,\@function,3
++.align	16
++.globl	asm_AES_decrypt
++.hidden	asm_AES_decrypt
++asm_AES_decrypt:
++AES_decrypt:
++	push	%rbx
++	push	%rbp
++	push	%r12
++	push	%r13
++	push	%r14
++	push	%r15
++
++	# allocate frame "above" key schedule
++	mov	%rsp,%r10
++	lea	-63(%rdx),%rcx	# %rdx is key argument
++	and	\$-64,%rsp
++	sub	%rsp,%rcx
++	neg	%rcx
++	and	\$0x3c0,%rcx
++	sub	%rcx,%rsp
++	sub	\$32,%rsp
++
++	mov	%rsi,16(%rsp)	# save out
++	mov	%r10,24(%rsp)	# save real stack pointer
++.Ldec_prologue:
++
++	mov	%rdx,$key
++	mov	240($key),$rnds	# load rounds
++
++	mov	0(%rdi),$s0	# load input vector
++	mov	4(%rdi),$s1
++	mov	8(%rdi),$s2
++	mov	12(%rdi),$s3
++
++	shl	\$4,$rnds
++	lea	($key,$rnds),%rbp
++	mov	$key,(%rsp)	# key schedule
++	mov	%rbp,8(%rsp)	# end of key schedule
++
++	# pick Td4 copy which can't "overlap" with stack frame or key schedule
++	lea	.LAES_Td+2048(%rip),$sbox
++	lea	768(%rsp),%rbp
++	sub	$sbox,%rbp
++	and	\$0x300,%rbp
++	lea	($sbox,%rbp),$sbox
++	shr	\$3,%rbp	# recall "magic" constants!
++	add	%rbp,$sbox
++
++	call	_x86_64_AES_decrypt_compact
++
++	mov	16(%rsp),$out	# restore out
++	mov	24(%rsp),%rsi	# restore saved stack pointer
++	mov	$s0,0($out)	# write output vector
++	mov	$s1,4($out)
++	mov	$s2,8($out)
++	mov	$s3,12($out)
++
++	mov	(%rsi),%r15
++	mov	8(%rsi),%r14
++	mov	16(%rsi),%r13
++	mov	24(%rsi),%r12
++	mov	32(%rsi),%rbp
++	mov	40(%rsi),%rbx
++	lea	48(%rsi),%rsp
++.Ldec_epilogue:
++	ret
++.size	AES_decrypt,.-AES_decrypt
++___
++#------------------------------------------------------------------#
++
++sub enckey()
++{
++$code.=<<___;
++	movz	%dl,%esi		# rk[i]>>0
++	movzb	-128(%rbp,%rsi),%ebx
++	movz	%dh,%esi		# rk[i]>>8
++	shl	\$24,%ebx
++	xor	%ebx,%eax
++
++	movzb	-128(%rbp,%rsi),%ebx
++	shr	\$16,%edx
++	movz	%dl,%esi		# rk[i]>>16
++	xor	%ebx,%eax
++
++	movzb	-128(%rbp,%rsi),%ebx
++	movz	%dh,%esi		# rk[i]>>24
++	shl	\$8,%ebx
++	xor	%ebx,%eax
++
++	movzb	-128(%rbp,%rsi),%ebx
++	shl	\$16,%ebx
++	xor	%ebx,%eax
++
++	xor	1024-128(%rbp,%rcx,4),%eax		# rcon
++___
++}
++
++# int AES_set_encrypt_key(const unsigned char *userKey, const int bits,
++#                        AES_KEY *key)
++$code.=<<___;
++.globl	AES_set_encrypt_key
++.type	AES_set_encrypt_key,\@function,3
++.align	16
++AES_set_encrypt_key:
++	push	%rbx
++	push	%rbp
++	push	%r12			# redundant, but allows to share 
++	push	%r13			# exception handler...
++	push	%r14
++	push	%r15
++	sub	\$8,%rsp
++.Lenc_key_prologue:
++
++	call	_x86_64_AES_set_encrypt_key
++
++	mov	40(%rsp),%rbp
++	mov	48(%rsp),%rbx
++	add	\$56,%rsp
++.Lenc_key_epilogue:
++	ret
++.size	AES_set_encrypt_key,.-AES_set_encrypt_key
++
++.type	_x86_64_AES_set_encrypt_key,\@abi-omnipotent
++.align	16
++_x86_64_AES_set_encrypt_key:
++	mov	%esi,%ecx			# %ecx=bits
++	mov	%rdi,%rsi			# %rsi=userKey
++	mov	%rdx,%rdi			# %rdi=key
++
++	test	\$-1,%rsi
++	jz	.Lbadpointer
++	test	\$-1,%rdi
++	jz	.Lbadpointer
++
++	lea	.LAES_Te(%rip),%rbp
++	lea	2048+128(%rbp),%rbp
++
++	# prefetch Te4
++	mov	0-128(%rbp),%eax
++	mov	32-128(%rbp),%ebx
++	mov	64-128(%rbp),%r8d
++	mov	96-128(%rbp),%edx
++	mov	128-128(%rbp),%eax
++	mov	160-128(%rbp),%ebx
++	mov	192-128(%rbp),%r8d
++	mov	224-128(%rbp),%edx
++
++	cmp	\$128,%ecx
++	je	.L10rounds
++	cmp	\$192,%ecx
++	je	.L12rounds
++	cmp	\$256,%ecx
++	je	.L14rounds
++	mov	\$-2,%rax			# invalid number of bits
++	jmp	.Lexit
++
++.L10rounds:
++	mov	0(%rsi),%rax			# copy first 4 dwords
++	mov	8(%rsi),%rdx
++	mov	%rax,0(%rdi)
++	mov	%rdx,8(%rdi)
++
++	shr	\$32,%rdx
++	xor	%ecx,%ecx
++	jmp	.L10shortcut
++.align	4
++.L10loop:
++		mov	0(%rdi),%eax			# rk[0]
++		mov	12(%rdi),%edx			# rk[3]
++.L10shortcut:
++___
++		&enckey	();
++$code.=<<___;
++		mov	%eax,16(%rdi)			# rk[4]
++		xor	4(%rdi),%eax
++		mov	%eax,20(%rdi)			# rk[5]
++		xor	8(%rdi),%eax
++		mov	%eax,24(%rdi)			# rk[6]
++		xor	12(%rdi),%eax
++		mov	%eax,28(%rdi)			# rk[7]
++		add	\$1,%ecx
++		lea	16(%rdi),%rdi
++		cmp	\$10,%ecx
++	jl	.L10loop
++
++	movl	\$10,80(%rdi)			# setup number of rounds
++	xor	%rax,%rax
++	jmp	.Lexit
++
++.L12rounds:
++	mov	0(%rsi),%rax			# copy first 6 dwords
++	mov	8(%rsi),%rbx
++	mov	16(%rsi),%rdx
++	mov	%rax,0(%rdi)
++	mov	%rbx,8(%rdi)
++	mov	%rdx,16(%rdi)
++
++	shr	\$32,%rdx
++	xor	%ecx,%ecx
++	jmp	.L12shortcut
++.align	4
++.L12loop:
++		mov	0(%rdi),%eax			# rk[0]
++		mov	20(%rdi),%edx			# rk[5]
++.L12shortcut:
++___
++		&enckey	();
++$code.=<<___;
++		mov	%eax,24(%rdi)			# rk[6]
++		xor	4(%rdi),%eax
++		mov	%eax,28(%rdi)			# rk[7]
++		xor	8(%rdi),%eax
++		mov	%eax,32(%rdi)			# rk[8]
++		xor	12(%rdi),%eax
++		mov	%eax,36(%rdi)			# rk[9]
++
++		cmp	\$7,%ecx
++		je	.L12break
++		add	\$1,%ecx
++
++		xor	16(%rdi),%eax
++		mov	%eax,40(%rdi)			# rk[10]
++		xor	20(%rdi),%eax
++		mov	%eax,44(%rdi)			# rk[11]
++
++		lea	24(%rdi),%rdi
++	jmp	.L12loop
++.L12break:
++	movl	\$12,72(%rdi)		# setup number of rounds
++	xor	%rax,%rax
++	jmp	.Lexit
++
++.L14rounds:		
++	mov	0(%rsi),%rax			# copy first 8 dwords
++	mov	8(%rsi),%rbx
++	mov	16(%rsi),%rcx
++	mov	24(%rsi),%rdx
++	mov	%rax,0(%rdi)
++	mov	%rbx,8(%rdi)
++	mov	%rcx,16(%rdi)
++	mov	%rdx,24(%rdi)
++
++	shr	\$32,%rdx
++	xor	%ecx,%ecx
++	jmp	.L14shortcut
++.align	4
++.L14loop:
++		mov	0(%rdi),%eax			# rk[0]
++		mov	28(%rdi),%edx			# rk[4]
++.L14shortcut:
++___
++		&enckey	();
++$code.=<<___;
++		mov	%eax,32(%rdi)			# rk[8]
++		xor	4(%rdi),%eax
++		mov	%eax,36(%rdi)			# rk[9]
++		xor	8(%rdi),%eax
++		mov	%eax,40(%rdi)			# rk[10]
++		xor	12(%rdi),%eax
++		mov	%eax,44(%rdi)			# rk[11]
++
++		cmp	\$6,%ecx
++		je	.L14break
++		add	\$1,%ecx
++
++		mov	%eax,%edx
++		mov	16(%rdi),%eax			# rk[4]
++		movz	%dl,%esi			# rk[11]>>0
++		movzb	-128(%rbp,%rsi),%ebx
++		movz	%dh,%esi			# rk[11]>>8
++		xor	%ebx,%eax
++
++		movzb	-128(%rbp,%rsi),%ebx
++		shr	\$16,%edx
++		shl	\$8,%ebx
++		movz	%dl,%esi			# rk[11]>>16
++		xor	%ebx,%eax
++
++		movzb	-128(%rbp,%rsi),%ebx
++		movz	%dh,%esi			# rk[11]>>24
++		shl	\$16,%ebx
++		xor	%ebx,%eax
++
++		movzb	-128(%rbp,%rsi),%ebx
++		shl	\$24,%ebx
++		xor	%ebx,%eax
++
++		mov	%eax,48(%rdi)			# rk[12]
++		xor	20(%rdi),%eax
++		mov	%eax,52(%rdi)			# rk[13]
++		xor	24(%rdi),%eax
++		mov	%eax,56(%rdi)			# rk[14]
++		xor	28(%rdi),%eax
++		mov	%eax,60(%rdi)			# rk[15]
++
++		lea	32(%rdi),%rdi
++	jmp	.L14loop
++.L14break:
++	movl	\$14,48(%rdi)		# setup number of rounds
++	xor	%rax,%rax
++	jmp	.Lexit
++
++.Lbadpointer:
++	mov	\$-1,%rax
++.Lexit:
++	.byte	0xf3,0xc3			# rep ret
++.size	_x86_64_AES_set_encrypt_key,.-_x86_64_AES_set_encrypt_key
++___
++
++sub deckey_ref()
++{ my ($i,$ptr,$te,$td) = @_;
++  my ($tp1,$tp2,$tp4,$tp8,$acc)=("%eax","%ebx","%edi","%edx","%r8d");
++$code.=<<___;
++	mov	$i($ptr),$tp1
++	mov	$tp1,$acc
++	and	\$0x80808080,$acc
++	mov	$acc,$tp4
++	shr	\$7,$tp4
++	lea	0($tp1,$tp1),$tp2
++	sub	$tp4,$acc
++	and	\$0xfefefefe,$tp2
++	and	\$0x1b1b1b1b,$acc
++	xor	$tp2,$acc
++	mov	$acc,$tp2
++
++	and	\$0x80808080,$acc
++	mov	$acc,$tp8
++	shr	\$7,$tp8
++	lea	0($tp2,$tp2),$tp4
++	sub	$tp8,$acc
++	and	\$0xfefefefe,$tp4
++	and	\$0x1b1b1b1b,$acc
++	 xor	$tp1,$tp2		# tp2^tp1
++	xor	$tp4,$acc
++	mov	$acc,$tp4
++
++	and	\$0x80808080,$acc
++	mov	$acc,$tp8
++	shr	\$7,$tp8
++	sub	$tp8,$acc
++	lea	0($tp4,$tp4),$tp8
++	 xor	$tp1,$tp4		# tp4^tp1
++	and	\$0xfefefefe,$tp8
++	and	\$0x1b1b1b1b,$acc
++	xor	$acc,$tp8
++
++	xor	$tp8,$tp1		# tp1^tp8
++	rol	\$8,$tp1		# ROTATE(tp1^tp8,8)
++	xor	$tp8,$tp2		# tp2^tp1^tp8
++	xor	$tp8,$tp4		# tp4^tp1^tp8
++	xor	$tp2,$tp8
++	xor	$tp4,$tp8		# tp8^(tp8^tp4^tp1)^(tp8^tp2^tp1)=tp8^tp4^tp2
++
++	xor	$tp8,$tp1
++	rol	\$24,$tp2		# ROTATE(tp2^tp1^tp8,24)
++	xor	$tp2,$tp1
++	rol	\$16,$tp4		# ROTATE(tp4^tp1^tp8,16)
++	xor	$tp4,$tp1
++
++	mov	$tp1,$i($ptr)
++___
++}
++
++# int AES_set_decrypt_key(const unsigned char *userKey, const int bits,
++#                        AES_KEY *key)
++$code.=<<___;
++.globl	AES_set_decrypt_key
++.type	AES_set_decrypt_key,\@function,3
++.align	16
++AES_set_decrypt_key:
++	push	%rbx
++	push	%rbp
++	push	%r12
++	push	%r13
++	push	%r14
++	push	%r15
++	push	%rdx			# save key schedule
++.Ldec_key_prologue:
++
++	call	_x86_64_AES_set_encrypt_key
++	mov	(%rsp),%r8		# restore key schedule
++	cmp	\$0,%eax
++	jne	.Labort
++
++	mov	240(%r8),%r14d		# pull number of rounds
++	xor	%rdi,%rdi
++	lea	(%rdi,%r14d,4),%rcx
++	mov	%r8,%rsi
++	lea	(%r8,%rcx,4),%rdi	# pointer to last chunk
++.align	4
++.Linvert:
++		mov	0(%rsi),%rax
++		mov	8(%rsi),%rbx
++		mov	0(%rdi),%rcx
++		mov	8(%rdi),%rdx
++		mov	%rax,0(%rdi)
++		mov	%rbx,8(%rdi)
++		mov	%rcx,0(%rsi)
++		mov	%rdx,8(%rsi)
++		lea	16(%rsi),%rsi
++		lea	-16(%rdi),%rdi
++		cmp	%rsi,%rdi
++	jne	.Linvert
++
++	lea	.LAES_Te+2048+1024(%rip),%rax	# rcon
++
++	mov	40(%rax),$mask80
++	mov	48(%rax),$maskfe
++	mov	56(%rax),$mask1b
++
++	mov	%r8,$key
++	sub	\$1,%r14d
++.align	4
++.Lpermute:
++		lea	16($key),$key
++		mov	0($key),%rax
++		mov	8($key),%rcx
++___
++		&dectransform ();
++$code.=<<___;
++		mov	%eax,0($key)
++		mov	%ebx,4($key)
++		mov	%ecx,8($key)
++		mov	%edx,12($key)
++		sub	\$1,%r14d
++	jnz	.Lpermute
++
++	xor	%rax,%rax
++.Labort:
++	mov	8(%rsp),%r15
++	mov	16(%rsp),%r14
++	mov	24(%rsp),%r13
++	mov	32(%rsp),%r12
++	mov	40(%rsp),%rbp
++	mov	48(%rsp),%rbx
++	add	\$56,%rsp
++.Ldec_key_epilogue:
++	ret
++.size	AES_set_decrypt_key,.-AES_set_decrypt_key
++___
++
++# void AES_cbc_encrypt (const void char *inp, unsigned char *out,
++#			size_t length, const AES_KEY *key,
++#			unsigned char *ivp,const int enc);
++{
++# stack frame layout
++# -8(%rsp)		return address
++my $keyp="0(%rsp)";		# one to pass as $key
++my $keyend="8(%rsp)";		# &(keyp->rd_key[4*keyp->rounds])
++my $_rsp="16(%rsp)";		# saved %rsp
++my $_inp="24(%rsp)";		# copy of 1st parameter, inp
++my $_out="32(%rsp)";		# copy of 2nd parameter, out
++my $_len="40(%rsp)";		# copy of 3rd parameter, length
++my $_key="48(%rsp)";		# copy of 4th parameter, key
++my $_ivp="56(%rsp)";		# copy of 5th parameter, ivp
++my $ivec="64(%rsp)";		# ivec[16]
++my $aes_key="80(%rsp)";		# copy of aes_key
++my $mark="80+240(%rsp)";	# copy of aes_key->rounds
++
++$code.=<<___;
++.globl	AES_cbc_encrypt
++.type	AES_cbc_encrypt,\@function,6
++.align	16
++.extern	OPENSSL_ia32cap_P
++.globl	asm_AES_cbc_encrypt
++.hidden	asm_AES_cbc_encrypt
++asm_AES_cbc_encrypt:
++AES_cbc_encrypt:
++	cmp	\$0,%rdx	# check length
++	je	.Lcbc_epilogue
++	pushfq
++	push	%rbx
++	push	%rbp
++	push	%r12
++	push	%r13
++	push	%r14
++	push	%r15
++.Lcbc_prologue:
++
++	cld
++	mov	%r9d,%r9d	# clear upper half of enc
++
++	lea	.LAES_Te(%rip),$sbox
++	cmp	\$0,%r9
++	jne	.Lcbc_picked_te
++	lea	.LAES_Td(%rip),$sbox
++.Lcbc_picked_te:
++
++	mov	OPENSSL_ia32cap_P(%rip),%r10d
++	cmp	\$$speed_limit,%rdx
++	jb	.Lcbc_slow_prologue
++	test	\$15,%rdx
++	jnz	.Lcbc_slow_prologue
++	bt	\$28,%r10d
++	jc	.Lcbc_slow_prologue
++
++	# allocate aligned stack frame...
++	lea	-88-248(%rsp),$key
++	and	\$-64,$key
++
++	# ... and make sure it doesn't alias with AES_T[ed] modulo 4096
++	mov	$sbox,%r10
++	lea	2304($sbox),%r11
++	mov	$key,%r12
++	and	\$0xFFF,%r10	# s = $sbox&0xfff
++	and	\$0xFFF,%r11	# e = ($sbox+2048)&0xfff
++	and	\$0xFFF,%r12	# p = %rsp&0xfff
++
++	cmp	%r11,%r12	# if (p=>e) %rsp =- (p-e);
++	jb	.Lcbc_te_break_out
++	sub	%r11,%r12
++	sub	%r12,$key
++	jmp	.Lcbc_te_ok
++.Lcbc_te_break_out:		# else %rsp -= (p-s)&0xfff + framesz
++	sub	%r10,%r12
++	and	\$0xFFF,%r12
++	add	\$320,%r12
++	sub	%r12,$key
++.align	4
++.Lcbc_te_ok:
++
++	xchg	%rsp,$key
++	#add	\$8,%rsp	# reserve for return address!
++	mov	$key,$_rsp	# save %rsp
++.Lcbc_fast_body:
++	mov	%rdi,$_inp	# save copy of inp
++	mov	%rsi,$_out	# save copy of out
++	mov	%rdx,$_len	# save copy of len
++	mov	%rcx,$_key	# save copy of key
++	mov	%r8,$_ivp	# save copy of ivp
++	movl	\$0,$mark	# copy of aes_key->rounds = 0;
++	mov	%r8,%rbp	# rearrange input arguments
++	mov	%r9,%rbx
++	mov	%rsi,$out
++	mov	%rdi,$inp
++	mov	%rcx,$key
++
++	mov	240($key),%eax		# key->rounds
++	# do we copy key schedule to stack?
++	mov	$key,%r10
++	sub	$sbox,%r10
++	and	\$0xfff,%r10
++	cmp	\$2304,%r10
++	jb	.Lcbc_do_ecopy
++	cmp	\$4096-248,%r10
++	jb	.Lcbc_skip_ecopy
++.align	4
++.Lcbc_do_ecopy:
++		mov	$key,%rsi
++		lea	$aes_key,%rdi
++		lea	$aes_key,$key
++		mov	\$240/8,%ecx
++		.long	0x90A548F3	# rep movsq
++		mov	%eax,(%rdi)	# copy aes_key->rounds
++.Lcbc_skip_ecopy:
++	mov	$key,$keyp	# save key pointer
++
++	mov	\$18,%ecx
++.align	4
++.Lcbc_prefetch_te:
++		mov	0($sbox),%r10
++		mov	32($sbox),%r11
++		mov	64($sbox),%r12
++		mov	96($sbox),%r13
++		lea	128($sbox),$sbox
++		sub	\$1,%ecx
++	jnz	.Lcbc_prefetch_te
++	lea	-2304($sbox),$sbox
++
++	cmp	\$0,%rbx
++	je	.LFAST_DECRYPT
++
++#----------------------------- ENCRYPT -----------------------------#
++	mov	0(%rbp),$s0		# load iv
++	mov	4(%rbp),$s1
++	mov	8(%rbp),$s2
++	mov	12(%rbp),$s3
++
++.align	4
++.Lcbc_fast_enc_loop:
++		xor	0($inp),$s0
++		xor	4($inp),$s1
++		xor	8($inp),$s2
++		xor	12($inp),$s3
++		mov	$keyp,$key	# restore key
++		mov	$inp,$_inp	# if ($verticalspin) save inp
++
++		call	_x86_64_AES_encrypt
++
++		mov	$_inp,$inp	# if ($verticalspin) restore inp
++		mov	$_len,%r10
++		mov	$s0,0($out)
++		mov	$s1,4($out)
++		mov	$s2,8($out)
++		mov	$s3,12($out)
++
++		lea	16($inp),$inp
++		lea	16($out),$out
++		sub	\$16,%r10
++		test	\$-16,%r10
++		mov	%r10,$_len
++	jnz	.Lcbc_fast_enc_loop
++	mov	$_ivp,%rbp	# restore ivp
++	mov	$s0,0(%rbp)	# save ivec
++	mov	$s1,4(%rbp)
++	mov	$s2,8(%rbp)
++	mov	$s3,12(%rbp)
++
++	jmp	.Lcbc_fast_cleanup
++
++#----------------------------- DECRYPT -----------------------------#
++.align	16
++.LFAST_DECRYPT:
++	cmp	$inp,$out
++	je	.Lcbc_fast_dec_in_place
++
++	mov	%rbp,$ivec
++.align	4
++.Lcbc_fast_dec_loop:
++		mov	0($inp),$s0	# read input
++		mov	4($inp),$s1
++		mov	8($inp),$s2
++		mov	12($inp),$s3
++		mov	$keyp,$key	# restore key
++		mov	$inp,$_inp	# if ($verticalspin) save inp
++
++		call	_x86_64_AES_decrypt
++
++		mov	$ivec,%rbp	# load ivp
++		mov	$_inp,$inp	# if ($verticalspin) restore inp
++		mov	$_len,%r10	# load len
++		xor	0(%rbp),$s0	# xor iv
++		xor	4(%rbp),$s1
++		xor	8(%rbp),$s2
++		xor	12(%rbp),$s3
++		mov	$inp,%rbp	# current input, next iv
++
++		sub	\$16,%r10
++		mov	%r10,$_len	# update len
++		mov	%rbp,$ivec	# update ivp
++
++		mov	$s0,0($out)	# write output
++		mov	$s1,4($out)
++		mov	$s2,8($out)
++		mov	$s3,12($out)
++
++		lea	16($inp),$inp
++		lea	16($out),$out
++	jnz	.Lcbc_fast_dec_loop
++	mov	$_ivp,%r12		# load user ivp
++	mov	0(%rbp),%r10		# load iv
++	mov	8(%rbp),%r11
++	mov	%r10,0(%r12)		# copy back to user
++	mov	%r11,8(%r12)
++	jmp	.Lcbc_fast_cleanup
++
++.align	16
++.Lcbc_fast_dec_in_place:
++	mov	0(%rbp),%r10		# copy iv to stack
++	mov	8(%rbp),%r11
++	mov	%r10,0+$ivec
++	mov	%r11,8+$ivec
++.align	4
++.Lcbc_fast_dec_in_place_loop:
++		mov	0($inp),$s0	# load input
++		mov	4($inp),$s1
++		mov	8($inp),$s2
++		mov	12($inp),$s3
++		mov	$keyp,$key	# restore key
++		mov	$inp,$_inp	# if ($verticalspin) save inp
++
++		call	_x86_64_AES_decrypt
++
++		mov	$_inp,$inp	# if ($verticalspin) restore inp
++		mov	$_len,%r10
++		xor	0+$ivec,$s0
++		xor	4+$ivec,$s1
++		xor	8+$ivec,$s2
++		xor	12+$ivec,$s3
++
++		mov	0($inp),%r11	# load input
++		mov	8($inp),%r12
++		sub	\$16,%r10
++		jz	.Lcbc_fast_dec_in_place_done
++
++		mov	%r11,0+$ivec	# copy input to iv
++		mov	%r12,8+$ivec
++
++		mov	$s0,0($out)	# save output [zaps input]
++		mov	$s1,4($out)
++		mov	$s2,8($out)
++		mov	$s3,12($out)
++
++		lea	16($inp),$inp
++		lea	16($out),$out
++		mov	%r10,$_len
++	jmp	.Lcbc_fast_dec_in_place_loop
++.Lcbc_fast_dec_in_place_done:
++	mov	$_ivp,%rdi
++	mov	%r11,0(%rdi)	# copy iv back to user
++	mov	%r12,8(%rdi)
++
++	mov	$s0,0($out)	# save output [zaps input]
++	mov	$s1,4($out)
++	mov	$s2,8($out)
++	mov	$s3,12($out)
++
++.align	4
++.Lcbc_fast_cleanup:
++	cmpl	\$0,$mark	# was the key schedule copied?
++	lea	$aes_key,%rdi
++	je	.Lcbc_exit
++		mov	\$240/8,%ecx
++		xor	%rax,%rax
++		.long	0x90AB48F3	# rep stosq
++
++	jmp	.Lcbc_exit
++
++#--------------------------- SLOW ROUTINE ---------------------------#
++.align	16
++.Lcbc_slow_prologue:
++	# allocate aligned stack frame...
++	lea	-88(%rsp),%rbp
++	and	\$-64,%rbp
++	# ... just "above" key schedule
++	lea	-88-63(%rcx),%r10
++	sub	%rbp,%r10
++	neg	%r10
++	and	\$0x3c0,%r10
++	sub	%r10,%rbp
++
++	xchg	%rsp,%rbp
++	#add	\$8,%rsp	# reserve for return address!
++	mov	%rbp,$_rsp	# save %rsp
++.Lcbc_slow_body:
++	#mov	%rdi,$_inp	# save copy of inp
++	#mov	%rsi,$_out	# save copy of out
++	#mov	%rdx,$_len	# save copy of len
++	#mov	%rcx,$_key	# save copy of key
++	mov	%r8,$_ivp	# save copy of ivp
++	mov	%r8,%rbp	# rearrange input arguments
++	mov	%r9,%rbx
++	mov	%rsi,$out
++	mov	%rdi,$inp
++	mov	%rcx,$key
++	mov	%rdx,%r10
++
++	mov	240($key),%eax
++	mov	$key,$keyp	# save key pointer
++	shl	\$4,%eax
++	lea	($key,%rax),%rax
++	mov	%rax,$keyend
++
++	# pick Te4 copy which can't "overlap" with stack frame or key scdedule
++	lea	2048($sbox),$sbox
++	lea	768-8(%rsp),%rax
++	sub	$sbox,%rax
++	and	\$0x300,%rax
++	lea	($sbox,%rax),$sbox
++
++	cmp	\$0,%rbx
++	je	.LSLOW_DECRYPT
++
++#--------------------------- SLOW ENCRYPT ---------------------------#
++	test	\$-16,%r10		# check upon length
++	mov	0(%rbp),$s0		# load iv
++	mov	4(%rbp),$s1
++	mov	8(%rbp),$s2
++	mov	12(%rbp),$s3
++	jz	.Lcbc_slow_enc_tail	# short input...
++
++.align	4
++.Lcbc_slow_enc_loop:
++		xor	0($inp),$s0
++		xor	4($inp),$s1
++		xor	8($inp),$s2
++		xor	12($inp),$s3
++		mov	$keyp,$key	# restore key
++		mov	$inp,$_inp	# save inp
++		mov	$out,$_out	# save out
++		mov	%r10,$_len	# save len
++
++		call	_x86_64_AES_encrypt_compact
++
++		mov	$_inp,$inp	# restore inp
++		mov	$_out,$out	# restore out
++		mov	$_len,%r10	# restore len
++		mov	$s0,0($out)
++		mov	$s1,4($out)
++		mov	$s2,8($out)
++		mov	$s3,12($out)
++
++		lea	16($inp),$inp
++		lea	16($out),$out
++		sub	\$16,%r10
++		test	\$-16,%r10
++	jnz	.Lcbc_slow_enc_loop
++	test	\$15,%r10
++	jnz	.Lcbc_slow_enc_tail
++	mov	$_ivp,%rbp	# restore ivp
++	mov	$s0,0(%rbp)	# save ivec
++	mov	$s1,4(%rbp)
++	mov	$s2,8(%rbp)
++	mov	$s3,12(%rbp)
++
++	jmp	.Lcbc_exit
++
++.align	4
++.Lcbc_slow_enc_tail:
++	mov	%rax,%r11
++	mov	%rcx,%r12
++	mov	%r10,%rcx
++	mov	$inp,%rsi
++	mov	$out,%rdi
++	.long	0x9066A4F3		# rep movsb
++	mov	\$16,%rcx		# zero tail
++	sub	%r10,%rcx
++	xor	%rax,%rax
++	.long	0x9066AAF3		# rep stosb
++	mov	$out,$inp		# this is not a mistake!
++	mov	\$16,%r10		# len=16
++	mov	%r11,%rax
++	mov	%r12,%rcx
++	jmp	.Lcbc_slow_enc_loop	# one more spin...
++#--------------------------- SLOW DECRYPT ---------------------------#
++.align	16
++.LSLOW_DECRYPT:
++	shr	\$3,%rax
++	add	%rax,$sbox		# recall "magic" constants!
++
++	mov	0(%rbp),%r11		# copy iv to stack
++	mov	8(%rbp),%r12
++	mov	%r11,0+$ivec
++	mov	%r12,8+$ivec
++
++.align	4
++.Lcbc_slow_dec_loop:
++		mov	0($inp),$s0	# load input
++		mov	4($inp),$s1
++		mov	8($inp),$s2
++		mov	12($inp),$s3
++		mov	$keyp,$key	# restore key
++		mov	$inp,$_inp	# save inp
++		mov	$out,$_out	# save out
++		mov	%r10,$_len	# save len
++
++		call	_x86_64_AES_decrypt_compact
++
++		mov	$_inp,$inp	# restore inp
++		mov	$_out,$out	# restore out
++		mov	$_len,%r10
++		xor	0+$ivec,$s0
++		xor	4+$ivec,$s1
++		xor	8+$ivec,$s2
++		xor	12+$ivec,$s3
++
++		mov	0($inp),%r11	# load input
++		mov	8($inp),%r12
++		sub	\$16,%r10
++		jc	.Lcbc_slow_dec_partial
++		jz	.Lcbc_slow_dec_done
++
++		mov	%r11,0+$ivec	# copy input to iv
++		mov	%r12,8+$ivec
++
++		mov	$s0,0($out)	# save output [can zap input]
++		mov	$s1,4($out)
++		mov	$s2,8($out)
++		mov	$s3,12($out)
++
++		lea	16($inp),$inp
++		lea	16($out),$out
++	jmp	.Lcbc_slow_dec_loop
++.Lcbc_slow_dec_done:
++	mov	$_ivp,%rdi
++	mov	%r11,0(%rdi)		# copy iv back to user
++	mov	%r12,8(%rdi)
++
++	mov	$s0,0($out)		# save output [can zap input]
++	mov	$s1,4($out)
++	mov	$s2,8($out)
++	mov	$s3,12($out)
++
++	jmp	.Lcbc_exit
++
++.align	4
++.Lcbc_slow_dec_partial:
++	mov	$_ivp,%rdi
++	mov	%r11,0(%rdi)		# copy iv back to user
++	mov	%r12,8(%rdi)
++
++	mov	$s0,0+$ivec		# save output to stack
++	mov	$s1,4+$ivec
++	mov	$s2,8+$ivec
++	mov	$s3,12+$ivec
++
++	mov	$out,%rdi
++	lea	$ivec,%rsi
++	lea	16(%r10),%rcx
++	.long	0x9066A4F3	# rep movsb
++	jmp	.Lcbc_exit
++
++.align	16
++.Lcbc_exit:
++	mov	$_rsp,%rsi
++	mov	(%rsi),%r15
++	mov	8(%rsi),%r14
++	mov	16(%rsi),%r13
++	mov	24(%rsi),%r12
++	mov	32(%rsi),%rbp
++	mov	40(%rsi),%rbx
++	lea	48(%rsi),%rsp
++.Lcbc_popfq:
++	popfq
++.Lcbc_epilogue:
++	ret
++.size	AES_cbc_encrypt,.-AES_cbc_encrypt
++___
++}
++
++$code.=<<___;
++.align	64
++.LAES_Te:
++___
++	&_data_word(0xa56363c6, 0x847c7cf8, 0x997777ee, 0x8d7b7bf6);
++	&_data_word(0x0df2f2ff, 0xbd6b6bd6, 0xb16f6fde, 0x54c5c591);
++	&_data_word(0x50303060, 0x03010102, 0xa96767ce, 0x7d2b2b56);
++	&_data_word(0x19fefee7, 0x62d7d7b5, 0xe6abab4d, 0x9a7676ec);
++	&_data_word(0x45caca8f, 0x9d82821f, 0x40c9c989, 0x877d7dfa);
++	&_data_word(0x15fafaef, 0xeb5959b2, 0xc947478e, 0x0bf0f0fb);
++	&_data_word(0xecadad41, 0x67d4d4b3, 0xfda2a25f, 0xeaafaf45);
++	&_data_word(0xbf9c9c23, 0xf7a4a453, 0x967272e4, 0x5bc0c09b);
++	&_data_word(0xc2b7b775, 0x1cfdfde1, 0xae93933d, 0x6a26264c);
++	&_data_word(0x5a36366c, 0x413f3f7e, 0x02f7f7f5, 0x4fcccc83);
++	&_data_word(0x5c343468, 0xf4a5a551, 0x34e5e5d1, 0x08f1f1f9);
++	&_data_word(0x937171e2, 0x73d8d8ab, 0x53313162, 0x3f15152a);
++	&_data_word(0x0c040408, 0x52c7c795, 0x65232346, 0x5ec3c39d);
++	&_data_word(0x28181830, 0xa1969637, 0x0f05050a, 0xb59a9a2f);
++	&_data_word(0x0907070e, 0x36121224, 0x9b80801b, 0x3de2e2df);
++	&_data_word(0x26ebebcd, 0x6927274e, 0xcdb2b27f, 0x9f7575ea);
++	&_data_word(0x1b090912, 0x9e83831d, 0x742c2c58, 0x2e1a1a34);
++	&_data_word(0x2d1b1b36, 0xb26e6edc, 0xee5a5ab4, 0xfba0a05b);
++	&_data_word(0xf65252a4, 0x4d3b3b76, 0x61d6d6b7, 0xceb3b37d);
++	&_data_word(0x7b292952, 0x3ee3e3dd, 0x712f2f5e, 0x97848413);
++	&_data_word(0xf55353a6, 0x68d1d1b9, 0x00000000, 0x2cededc1);
++	&_data_word(0x60202040, 0x1ffcfce3, 0xc8b1b179, 0xed5b5bb6);
++	&_data_word(0xbe6a6ad4, 0x46cbcb8d, 0xd9bebe67, 0x4b393972);
++	&_data_word(0xde4a4a94, 0xd44c4c98, 0xe85858b0, 0x4acfcf85);
++	&_data_word(0x6bd0d0bb, 0x2aefefc5, 0xe5aaaa4f, 0x16fbfbed);
++	&_data_word(0xc5434386, 0xd74d4d9a, 0x55333366, 0x94858511);
++	&_data_word(0xcf45458a, 0x10f9f9e9, 0x06020204, 0x817f7ffe);
++	&_data_word(0xf05050a0, 0x443c3c78, 0xba9f9f25, 0xe3a8a84b);
++	&_data_word(0xf35151a2, 0xfea3a35d, 0xc0404080, 0x8a8f8f05);
++	&_data_word(0xad92923f, 0xbc9d9d21, 0x48383870, 0x04f5f5f1);
++	&_data_word(0xdfbcbc63, 0xc1b6b677, 0x75dadaaf, 0x63212142);
++	&_data_word(0x30101020, 0x1affffe5, 0x0ef3f3fd, 0x6dd2d2bf);
++	&_data_word(0x4ccdcd81, 0x140c0c18, 0x35131326, 0x2fececc3);
++	&_data_word(0xe15f5fbe, 0xa2979735, 0xcc444488, 0x3917172e);
++	&_data_word(0x57c4c493, 0xf2a7a755, 0x827e7efc, 0x473d3d7a);
++	&_data_word(0xac6464c8, 0xe75d5dba, 0x2b191932, 0x957373e6);
++	&_data_word(0xa06060c0, 0x98818119, 0xd14f4f9e, 0x7fdcdca3);
++	&_data_word(0x66222244, 0x7e2a2a54, 0xab90903b, 0x8388880b);
++	&_data_word(0xca46468c, 0x29eeeec7, 0xd3b8b86b, 0x3c141428);
++	&_data_word(0x79dedea7, 0xe25e5ebc, 0x1d0b0b16, 0x76dbdbad);
++	&_data_word(0x3be0e0db, 0x56323264, 0x4e3a3a74, 0x1e0a0a14);
++	&_data_word(0xdb494992, 0x0a06060c, 0x6c242448, 0xe45c5cb8);
++	&_data_word(0x5dc2c29f, 0x6ed3d3bd, 0xefacac43, 0xa66262c4);
++	&_data_word(0xa8919139, 0xa4959531, 0x37e4e4d3, 0x8b7979f2);
++	&_data_word(0x32e7e7d5, 0x43c8c88b, 0x5937376e, 0xb76d6dda);
++	&_data_word(0x8c8d8d01, 0x64d5d5b1, 0xd24e4e9c, 0xe0a9a949);
++	&_data_word(0xb46c6cd8, 0xfa5656ac, 0x07f4f4f3, 0x25eaeacf);
++	&_data_word(0xaf6565ca, 0x8e7a7af4, 0xe9aeae47, 0x18080810);
++	&_data_word(0xd5baba6f, 0x887878f0, 0x6f25254a, 0x722e2e5c);
++	&_data_word(0x241c1c38, 0xf1a6a657, 0xc7b4b473, 0x51c6c697);
++	&_data_word(0x23e8e8cb, 0x7cdddda1, 0x9c7474e8, 0x211f1f3e);
++	&_data_word(0xdd4b4b96, 0xdcbdbd61, 0x868b8b0d, 0x858a8a0f);
++	&_data_word(0x907070e0, 0x423e3e7c, 0xc4b5b571, 0xaa6666cc);
++	&_data_word(0xd8484890, 0x05030306, 0x01f6f6f7, 0x120e0e1c);
++	&_data_word(0xa36161c2, 0x5f35356a, 0xf95757ae, 0xd0b9b969);
++	&_data_word(0x91868617, 0x58c1c199, 0x271d1d3a, 0xb99e9e27);
++	&_data_word(0x38e1e1d9, 0x13f8f8eb, 0xb398982b, 0x33111122);
++	&_data_word(0xbb6969d2, 0x70d9d9a9, 0x898e8e07, 0xa7949433);
++	&_data_word(0xb69b9b2d, 0x221e1e3c, 0x92878715, 0x20e9e9c9);
++	&_data_word(0x49cece87, 0xff5555aa, 0x78282850, 0x7adfdfa5);
++	&_data_word(0x8f8c8c03, 0xf8a1a159, 0x80898909, 0x170d0d1a);
++	&_data_word(0xdabfbf65, 0x31e6e6d7, 0xc6424284, 0xb86868d0);
++	&_data_word(0xc3414182, 0xb0999929, 0x772d2d5a, 0x110f0f1e);
++	&_data_word(0xcbb0b07b, 0xfc5454a8, 0xd6bbbb6d, 0x3a16162c);
++
++#Te4	# four copies of Te4 to choose from to avoid L1 aliasing
++	&data_byte(0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5);
++	&data_byte(0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76);
++	&data_byte(0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0);
++	&data_byte(0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0);
++	&data_byte(0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc);
++	&data_byte(0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15);
++	&data_byte(0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a);
++	&data_byte(0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75);
++	&data_byte(0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0);
++	&data_byte(0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84);
++	&data_byte(0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b);
++	&data_byte(0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf);
++	&data_byte(0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85);
++	&data_byte(0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8);
++	&data_byte(0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5);
++	&data_byte(0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2);
++	&data_byte(0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17);
++	&data_byte(0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73);
++	&data_byte(0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88);
++	&data_byte(0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb);
++	&data_byte(0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c);
++	&data_byte(0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79);
++	&data_byte(0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9);
++	&data_byte(0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08);
++	&data_byte(0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6);
++	&data_byte(0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a);
++	&data_byte(0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e);
++	&data_byte(0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e);
++	&data_byte(0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94);
++	&data_byte(0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf);
++	&data_byte(0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68);
++	&data_byte(0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16);
++
++	&data_byte(0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5);
++	&data_byte(0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76);
++	&data_byte(0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0);
++	&data_byte(0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0);
++	&data_byte(0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc);
++	&data_byte(0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15);
++	&data_byte(0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a);
++	&data_byte(0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75);
++	&data_byte(0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0);
++	&data_byte(0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84);
++	&data_byte(0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b);
++	&data_byte(0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf);
++	&data_byte(0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85);
++	&data_byte(0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8);
++	&data_byte(0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5);
++	&data_byte(0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2);
++	&data_byte(0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17);
++	&data_byte(0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73);
++	&data_byte(0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88);
++	&data_byte(0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb);
++	&data_byte(0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c);
++	&data_byte(0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79);
++	&data_byte(0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9);
++	&data_byte(0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08);
++	&data_byte(0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6);
++	&data_byte(0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a);
++	&data_byte(0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e);
++	&data_byte(0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e);
++	&data_byte(0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94);
++	&data_byte(0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf);
++	&data_byte(0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68);
++	&data_byte(0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16);
++
++	&data_byte(0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5);
++	&data_byte(0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76);
++	&data_byte(0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0);
++	&data_byte(0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0);
++	&data_byte(0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc);
++	&data_byte(0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15);
++	&data_byte(0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a);
++	&data_byte(0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75);
++	&data_byte(0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0);
++	&data_byte(0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84);
++	&data_byte(0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b);
++	&data_byte(0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf);
++	&data_byte(0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85);
++	&data_byte(0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8);
++	&data_byte(0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5);
++	&data_byte(0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2);
++	&data_byte(0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17);
++	&data_byte(0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73);
++	&data_byte(0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88);
++	&data_byte(0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb);
++	&data_byte(0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c);
++	&data_byte(0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79);
++	&data_byte(0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9);
++	&data_byte(0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08);
++	&data_byte(0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6);
++	&data_byte(0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a);
++	&data_byte(0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e);
++	&data_byte(0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e);
++	&data_byte(0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94);
++	&data_byte(0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf);
++	&data_byte(0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68);
++	&data_byte(0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16);
++
++	&data_byte(0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5);
++	&data_byte(0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76);
++	&data_byte(0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0);
++	&data_byte(0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0);
++	&data_byte(0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc);
++	&data_byte(0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15);
++	&data_byte(0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a);
++	&data_byte(0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75);
++	&data_byte(0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0);
++	&data_byte(0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84);
++	&data_byte(0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b);
++	&data_byte(0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf);
++	&data_byte(0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85);
++	&data_byte(0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8);
++	&data_byte(0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5);
++	&data_byte(0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2);
++	&data_byte(0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17);
++	&data_byte(0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73);
++	&data_byte(0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88);
++	&data_byte(0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb);
++	&data_byte(0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c);
++	&data_byte(0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79);
++	&data_byte(0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9);
++	&data_byte(0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08);
++	&data_byte(0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6);
++	&data_byte(0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a);
++	&data_byte(0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e);
++	&data_byte(0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e);
++	&data_byte(0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94);
++	&data_byte(0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf);
++	&data_byte(0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68);
++	&data_byte(0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16);
++#rcon:
++$code.=<<___;
++	.long	0x00000001, 0x00000002, 0x00000004, 0x00000008
++	.long	0x00000010, 0x00000020, 0x00000040, 0x00000080
++	.long	0x0000001b, 0x00000036, 0x80808080, 0x80808080
++	.long	0xfefefefe, 0xfefefefe, 0x1b1b1b1b, 0x1b1b1b1b
++___
++$code.=<<___;
++.align	64
++.LAES_Td:
++___
++	&_data_word(0x50a7f451, 0x5365417e, 0xc3a4171a, 0x965e273a);
++	&_data_word(0xcb6bab3b, 0xf1459d1f, 0xab58faac, 0x9303e34b);
++	&_data_word(0x55fa3020, 0xf66d76ad, 0x9176cc88, 0x254c02f5);
++	&_data_word(0xfcd7e54f, 0xd7cb2ac5, 0x80443526, 0x8fa362b5);
++	&_data_word(0x495ab1de, 0x671bba25, 0x980eea45, 0xe1c0fe5d);
++	&_data_word(0x02752fc3, 0x12f04c81, 0xa397468d, 0xc6f9d36b);
++	&_data_word(0xe75f8f03, 0x959c9215, 0xeb7a6dbf, 0xda595295);
++	&_data_word(0x2d83bed4, 0xd3217458, 0x2969e049, 0x44c8c98e);
++	&_data_word(0x6a89c275, 0x78798ef4, 0x6b3e5899, 0xdd71b927);
++	&_data_word(0xb64fe1be, 0x17ad88f0, 0x66ac20c9, 0xb43ace7d);
++	&_data_word(0x184adf63, 0x82311ae5, 0x60335197, 0x457f5362);
++	&_data_word(0xe07764b1, 0x84ae6bbb, 0x1ca081fe, 0x942b08f9);
++	&_data_word(0x58684870, 0x19fd458f, 0x876cde94, 0xb7f87b52);
++	&_data_word(0x23d373ab, 0xe2024b72, 0x578f1fe3, 0x2aab5566);
++	&_data_word(0x0728ebb2, 0x03c2b52f, 0x9a7bc586, 0xa50837d3);
++	&_data_word(0xf2872830, 0xb2a5bf23, 0xba6a0302, 0x5c8216ed);
++	&_data_word(0x2b1ccf8a, 0x92b479a7, 0xf0f207f3, 0xa1e2694e);
++	&_data_word(0xcdf4da65, 0xd5be0506, 0x1f6234d1, 0x8afea6c4);
++	&_data_word(0x9d532e34, 0xa055f3a2, 0x32e18a05, 0x75ebf6a4);
++	&_data_word(0x39ec830b, 0xaaef6040, 0x069f715e, 0x51106ebd);
++	&_data_word(0xf98a213e, 0x3d06dd96, 0xae053edd, 0x46bde64d);
++	&_data_word(0xb58d5491, 0x055dc471, 0x6fd40604, 0xff155060);
++	&_data_word(0x24fb9819, 0x97e9bdd6, 0xcc434089, 0x779ed967);
++	&_data_word(0xbd42e8b0, 0x888b8907, 0x385b19e7, 0xdbeec879);
++	&_data_word(0x470a7ca1, 0xe90f427c, 0xc91e84f8, 0x00000000);
++	&_data_word(0x83868009, 0x48ed2b32, 0xac70111e, 0x4e725a6c);
++	&_data_word(0xfbff0efd, 0x5638850f, 0x1ed5ae3d, 0x27392d36);
++	&_data_word(0x64d90f0a, 0x21a65c68, 0xd1545b9b, 0x3a2e3624);
++	&_data_word(0xb1670a0c, 0x0fe75793, 0xd296eeb4, 0x9e919b1b);
++	&_data_word(0x4fc5c080, 0xa220dc61, 0x694b775a, 0x161a121c);
++	&_data_word(0x0aba93e2, 0xe52aa0c0, 0x43e0223c, 0x1d171b12);
++	&_data_word(0x0b0d090e, 0xadc78bf2, 0xb9a8b62d, 0xc8a91e14);
++	&_data_word(0x8519f157, 0x4c0775af, 0xbbdd99ee, 0xfd607fa3);
++	&_data_word(0x9f2601f7, 0xbcf5725c, 0xc53b6644, 0x347efb5b);
++	&_data_word(0x7629438b, 0xdcc623cb, 0x68fcedb6, 0x63f1e4b8);
++	&_data_word(0xcadc31d7, 0x10856342, 0x40229713, 0x2011c684);
++	&_data_word(0x7d244a85, 0xf83dbbd2, 0x1132f9ae, 0x6da129c7);
++	&_data_word(0x4b2f9e1d, 0xf330b2dc, 0xec52860d, 0xd0e3c177);
++	&_data_word(0x6c16b32b, 0x99b970a9, 0xfa489411, 0x2264e947);
++	&_data_word(0xc48cfca8, 0x1a3ff0a0, 0xd82c7d56, 0xef903322);
++	&_data_word(0xc74e4987, 0xc1d138d9, 0xfea2ca8c, 0x360bd498);
++	&_data_word(0xcf81f5a6, 0x28de7aa5, 0x268eb7da, 0xa4bfad3f);
++	&_data_word(0xe49d3a2c, 0x0d927850, 0x9bcc5f6a, 0x62467e54);
++	&_data_word(0xc2138df6, 0xe8b8d890, 0x5ef7392e, 0xf5afc382);
++	&_data_word(0xbe805d9f, 0x7c93d069, 0xa92dd56f, 0xb31225cf);
++	&_data_word(0x3b99acc8, 0xa77d1810, 0x6e639ce8, 0x7bbb3bdb);
++	&_data_word(0x097826cd, 0xf418596e, 0x01b79aec, 0xa89a4f83);
++	&_data_word(0x656e95e6, 0x7ee6ffaa, 0x08cfbc21, 0xe6e815ef);
++	&_data_word(0xd99be7ba, 0xce366f4a, 0xd4099fea, 0xd67cb029);
++	&_data_word(0xafb2a431, 0x31233f2a, 0x3094a5c6, 0xc066a235);
++	&_data_word(0x37bc4e74, 0xa6ca82fc, 0xb0d090e0, 0x15d8a733);
++	&_data_word(0x4a9804f1, 0xf7daec41, 0x0e50cd7f, 0x2ff69117);
++	&_data_word(0x8dd64d76, 0x4db0ef43, 0x544daacc, 0xdf0496e4);
++	&_data_word(0xe3b5d19e, 0x1b886a4c, 0xb81f2cc1, 0x7f516546);
++	&_data_word(0x04ea5e9d, 0x5d358c01, 0x737487fa, 0x2e410bfb);
++	&_data_word(0x5a1d67b3, 0x52d2db92, 0x335610e9, 0x1347d66d);
++	&_data_word(0x8c61d79a, 0x7a0ca137, 0x8e14f859, 0x893c13eb);
++	&_data_word(0xee27a9ce, 0x35c961b7, 0xede51ce1, 0x3cb1477a);
++	&_data_word(0x59dfd29c, 0x3f73f255, 0x79ce1418, 0xbf37c773);
++	&_data_word(0xeacdf753, 0x5baafd5f, 0x146f3ddf, 0x86db4478);
++	&_data_word(0x81f3afca, 0x3ec468b9, 0x2c342438, 0x5f40a3c2);
++	&_data_word(0x72c31d16, 0x0c25e2bc, 0x8b493c28, 0x41950dff);
++	&_data_word(0x7101a839, 0xdeb30c08, 0x9ce4b4d8, 0x90c15664);
++	&_data_word(0x6184cb7b, 0x70b632d5, 0x745c6c48, 0x4257b8d0);
++
++#Td4:	# four copies of Td4 to choose from to avoid L1 aliasing
++	&data_byte(0x52, 0x09, 0x6a, 0xd5, 0x30, 0x36, 0xa5, 0x38);
++	&data_byte(0xbf, 0x40, 0xa3, 0x9e, 0x81, 0xf3, 0xd7, 0xfb);
++	&data_byte(0x7c, 0xe3, 0x39, 0x82, 0x9b, 0x2f, 0xff, 0x87);
++	&data_byte(0x34, 0x8e, 0x43, 0x44, 0xc4, 0xde, 0xe9, 0xcb);
++	&data_byte(0x54, 0x7b, 0x94, 0x32, 0xa6, 0xc2, 0x23, 0x3d);
++	&data_byte(0xee, 0x4c, 0x95, 0x0b, 0x42, 0xfa, 0xc3, 0x4e);
++	&data_byte(0x08, 0x2e, 0xa1, 0x66, 0x28, 0xd9, 0x24, 0xb2);
++	&data_byte(0x76, 0x5b, 0xa2, 0x49, 0x6d, 0x8b, 0xd1, 0x25);
++	&data_byte(0x72, 0xf8, 0xf6, 0x64, 0x86, 0x68, 0x98, 0x16);
++	&data_byte(0xd4, 0xa4, 0x5c, 0xcc, 0x5d, 0x65, 0xb6, 0x92);
++	&data_byte(0x6c, 0x70, 0x48, 0x50, 0xfd, 0xed, 0xb9, 0xda);
++	&data_byte(0x5e, 0x15, 0x46, 0x57, 0xa7, 0x8d, 0x9d, 0x84);
++	&data_byte(0x90, 0xd8, 0xab, 0x00, 0x8c, 0xbc, 0xd3, 0x0a);
++	&data_byte(0xf7, 0xe4, 0x58, 0x05, 0xb8, 0xb3, 0x45, 0x06);
++	&data_byte(0xd0, 0x2c, 0x1e, 0x8f, 0xca, 0x3f, 0x0f, 0x02);
++	&data_byte(0xc1, 0xaf, 0xbd, 0x03, 0x01, 0x13, 0x8a, 0x6b);
++	&data_byte(0x3a, 0x91, 0x11, 0x41, 0x4f, 0x67, 0xdc, 0xea);
++	&data_byte(0x97, 0xf2, 0xcf, 0xce, 0xf0, 0xb4, 0xe6, 0x73);
++	&data_byte(0x96, 0xac, 0x74, 0x22, 0xe7, 0xad, 0x35, 0x85);
++	&data_byte(0xe2, 0xf9, 0x37, 0xe8, 0x1c, 0x75, 0xdf, 0x6e);
++	&data_byte(0x47, 0xf1, 0x1a, 0x71, 0x1d, 0x29, 0xc5, 0x89);
++	&data_byte(0x6f, 0xb7, 0x62, 0x0e, 0xaa, 0x18, 0xbe, 0x1b);
++	&data_byte(0xfc, 0x56, 0x3e, 0x4b, 0xc6, 0xd2, 0x79, 0x20);
++	&data_byte(0x9a, 0xdb, 0xc0, 0xfe, 0x78, 0xcd, 0x5a, 0xf4);
++	&data_byte(0x1f, 0xdd, 0xa8, 0x33, 0x88, 0x07, 0xc7, 0x31);
++	&data_byte(0xb1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xec, 0x5f);
++	&data_byte(0x60, 0x51, 0x7f, 0xa9, 0x19, 0xb5, 0x4a, 0x0d);
++	&data_byte(0x2d, 0xe5, 0x7a, 0x9f, 0x93, 0xc9, 0x9c, 0xef);
++	&data_byte(0xa0, 0xe0, 0x3b, 0x4d, 0xae, 0x2a, 0xf5, 0xb0);
++	&data_byte(0xc8, 0xeb, 0xbb, 0x3c, 0x83, 0x53, 0x99, 0x61);
++	&data_byte(0x17, 0x2b, 0x04, 0x7e, 0xba, 0x77, 0xd6, 0x26);
++	&data_byte(0xe1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0c, 0x7d);
++$code.=<<___;
++	.long	0x80808080, 0x80808080, 0xfefefefe, 0xfefefefe
++	.long	0x1b1b1b1b, 0x1b1b1b1b, 0, 0
++___
++	&data_byte(0x52, 0x09, 0x6a, 0xd5, 0x30, 0x36, 0xa5, 0x38);
++	&data_byte(0xbf, 0x40, 0xa3, 0x9e, 0x81, 0xf3, 0xd7, 0xfb);
++	&data_byte(0x7c, 0xe3, 0x39, 0x82, 0x9b, 0x2f, 0xff, 0x87);
++	&data_byte(0x34, 0x8e, 0x43, 0x44, 0xc4, 0xde, 0xe9, 0xcb);
++	&data_byte(0x54, 0x7b, 0x94, 0x32, 0xa6, 0xc2, 0x23, 0x3d);
++	&data_byte(0xee, 0x4c, 0x95, 0x0b, 0x42, 0xfa, 0xc3, 0x4e);
++	&data_byte(0x08, 0x2e, 0xa1, 0x66, 0x28, 0xd9, 0x24, 0xb2);
++	&data_byte(0x76, 0x5b, 0xa2, 0x49, 0x6d, 0x8b, 0xd1, 0x25);
++	&data_byte(0x72, 0xf8, 0xf6, 0x64, 0x86, 0x68, 0x98, 0x16);
++	&data_byte(0xd4, 0xa4, 0x5c, 0xcc, 0x5d, 0x65, 0xb6, 0x92);
++	&data_byte(0x6c, 0x70, 0x48, 0x50, 0xfd, 0xed, 0xb9, 0xda);
++	&data_byte(0x5e, 0x15, 0x46, 0x57, 0xa7, 0x8d, 0x9d, 0x84);
++	&data_byte(0x90, 0xd8, 0xab, 0x00, 0x8c, 0xbc, 0xd3, 0x0a);
++	&data_byte(0xf7, 0xe4, 0x58, 0x05, 0xb8, 0xb3, 0x45, 0x06);
++	&data_byte(0xd0, 0x2c, 0x1e, 0x8f, 0xca, 0x3f, 0x0f, 0x02);
++	&data_byte(0xc1, 0xaf, 0xbd, 0x03, 0x01, 0x13, 0x8a, 0x6b);
++	&data_byte(0x3a, 0x91, 0x11, 0x41, 0x4f, 0x67, 0xdc, 0xea);
++	&data_byte(0x97, 0xf2, 0xcf, 0xce, 0xf0, 0xb4, 0xe6, 0x73);
++	&data_byte(0x96, 0xac, 0x74, 0x22, 0xe7, 0xad, 0x35, 0x85);
++	&data_byte(0xe2, 0xf9, 0x37, 0xe8, 0x1c, 0x75, 0xdf, 0x6e);
++	&data_byte(0x47, 0xf1, 0x1a, 0x71, 0x1d, 0x29, 0xc5, 0x89);
++	&data_byte(0x6f, 0xb7, 0x62, 0x0e, 0xaa, 0x18, 0xbe, 0x1b);
++	&data_byte(0xfc, 0x56, 0x3e, 0x4b, 0xc6, 0xd2, 0x79, 0x20);
++	&data_byte(0x9a, 0xdb, 0xc0, 0xfe, 0x78, 0xcd, 0x5a, 0xf4);
++	&data_byte(0x1f, 0xdd, 0xa8, 0x33, 0x88, 0x07, 0xc7, 0x31);
++	&data_byte(0xb1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xec, 0x5f);
++	&data_byte(0x60, 0x51, 0x7f, 0xa9, 0x19, 0xb5, 0x4a, 0x0d);
++	&data_byte(0x2d, 0xe5, 0x7a, 0x9f, 0x93, 0xc9, 0x9c, 0xef);
++	&data_byte(0xa0, 0xe0, 0x3b, 0x4d, 0xae, 0x2a, 0xf5, 0xb0);
++	&data_byte(0xc8, 0xeb, 0xbb, 0x3c, 0x83, 0x53, 0x99, 0x61);
++	&data_byte(0x17, 0x2b, 0x04, 0x7e, 0xba, 0x77, 0xd6, 0x26);
++	&data_byte(0xe1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0c, 0x7d);
++$code.=<<___;
++	.long	0x80808080, 0x80808080, 0xfefefefe, 0xfefefefe
++	.long	0x1b1b1b1b, 0x1b1b1b1b, 0, 0
++___
++	&data_byte(0x52, 0x09, 0x6a, 0xd5, 0x30, 0x36, 0xa5, 0x38);
++	&data_byte(0xbf, 0x40, 0xa3, 0x9e, 0x81, 0xf3, 0xd7, 0xfb);
++	&data_byte(0x7c, 0xe3, 0x39, 0x82, 0x9b, 0x2f, 0xff, 0x87);
++	&data_byte(0x34, 0x8e, 0x43, 0x44, 0xc4, 0xde, 0xe9, 0xcb);
++	&data_byte(0x54, 0x7b, 0x94, 0x32, 0xa6, 0xc2, 0x23, 0x3d);
++	&data_byte(0xee, 0x4c, 0x95, 0x0b, 0x42, 0xfa, 0xc3, 0x4e);
++	&data_byte(0x08, 0x2e, 0xa1, 0x66, 0x28, 0xd9, 0x24, 0xb2);
++	&data_byte(0x76, 0x5b, 0xa2, 0x49, 0x6d, 0x8b, 0xd1, 0x25);
++	&data_byte(0x72, 0xf8, 0xf6, 0x64, 0x86, 0x68, 0x98, 0x16);
++	&data_byte(0xd4, 0xa4, 0x5c, 0xcc, 0x5d, 0x65, 0xb6, 0x92);
++	&data_byte(0x6c, 0x70, 0x48, 0x50, 0xfd, 0xed, 0xb9, 0xda);
++	&data_byte(0x5e, 0x15, 0x46, 0x57, 0xa7, 0x8d, 0x9d, 0x84);
++	&data_byte(0x90, 0xd8, 0xab, 0x00, 0x8c, 0xbc, 0xd3, 0x0a);
++	&data_byte(0xf7, 0xe4, 0x58, 0x05, 0xb8, 0xb3, 0x45, 0x06);
++	&data_byte(0xd0, 0x2c, 0x1e, 0x8f, 0xca, 0x3f, 0x0f, 0x02);
++	&data_byte(0xc1, 0xaf, 0xbd, 0x03, 0x01, 0x13, 0x8a, 0x6b);
++	&data_byte(0x3a, 0x91, 0x11, 0x41, 0x4f, 0x67, 0xdc, 0xea);
++	&data_byte(0x97, 0xf2, 0xcf, 0xce, 0xf0, 0xb4, 0xe6, 0x73);
++	&data_byte(0x96, 0xac, 0x74, 0x22, 0xe7, 0xad, 0x35, 0x85);
++	&data_byte(0xe2, 0xf9, 0x37, 0xe8, 0x1c, 0x75, 0xdf, 0x6e);
++	&data_byte(0x47, 0xf1, 0x1a, 0x71, 0x1d, 0x29, 0xc5, 0x89);
++	&data_byte(0x6f, 0xb7, 0x62, 0x0e, 0xaa, 0x18, 0xbe, 0x1b);
++	&data_byte(0xfc, 0x56, 0x3e, 0x4b, 0xc6, 0xd2, 0x79, 0x20);
++	&data_byte(0x9a, 0xdb, 0xc0, 0xfe, 0x78, 0xcd, 0x5a, 0xf4);
++	&data_byte(0x1f, 0xdd, 0xa8, 0x33, 0x88, 0x07, 0xc7, 0x31);
++	&data_byte(0xb1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xec, 0x5f);
++	&data_byte(0x60, 0x51, 0x7f, 0xa9, 0x19, 0xb5, 0x4a, 0x0d);
++	&data_byte(0x2d, 0xe5, 0x7a, 0x9f, 0x93, 0xc9, 0x9c, 0xef);
++	&data_byte(0xa0, 0xe0, 0x3b, 0x4d, 0xae, 0x2a, 0xf5, 0xb0);
++	&data_byte(0xc8, 0xeb, 0xbb, 0x3c, 0x83, 0x53, 0x99, 0x61);
++	&data_byte(0x17, 0x2b, 0x04, 0x7e, 0xba, 0x77, 0xd6, 0x26);
++	&data_byte(0xe1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0c, 0x7d);
++$code.=<<___;
++	.long	0x80808080, 0x80808080, 0xfefefefe, 0xfefefefe
++	.long	0x1b1b1b1b, 0x1b1b1b1b, 0, 0
++___
++	&data_byte(0x52, 0x09, 0x6a, 0xd5, 0x30, 0x36, 0xa5, 0x38);
++	&data_byte(0xbf, 0x40, 0xa3, 0x9e, 0x81, 0xf3, 0xd7, 0xfb);
++	&data_byte(0x7c, 0xe3, 0x39, 0x82, 0x9b, 0x2f, 0xff, 0x87);
++	&data_byte(0x34, 0x8e, 0x43, 0x44, 0xc4, 0xde, 0xe9, 0xcb);
++	&data_byte(0x54, 0x7b, 0x94, 0x32, 0xa6, 0xc2, 0x23, 0x3d);
++	&data_byte(0xee, 0x4c, 0x95, 0x0b, 0x42, 0xfa, 0xc3, 0x4e);
++	&data_byte(0x08, 0x2e, 0xa1, 0x66, 0x28, 0xd9, 0x24, 0xb2);
++	&data_byte(0x76, 0x5b, 0xa2, 0x49, 0x6d, 0x8b, 0xd1, 0x25);
++	&data_byte(0x72, 0xf8, 0xf6, 0x64, 0x86, 0x68, 0x98, 0x16);
++	&data_byte(0xd4, 0xa4, 0x5c, 0xcc, 0x5d, 0x65, 0xb6, 0x92);
++	&data_byte(0x6c, 0x70, 0x48, 0x50, 0xfd, 0xed, 0xb9, 0xda);
++	&data_byte(0x5e, 0x15, 0x46, 0x57, 0xa7, 0x8d, 0x9d, 0x84);
++	&data_byte(0x90, 0xd8, 0xab, 0x00, 0x8c, 0xbc, 0xd3, 0x0a);
++	&data_byte(0xf7, 0xe4, 0x58, 0x05, 0xb8, 0xb3, 0x45, 0x06);
++	&data_byte(0xd0, 0x2c, 0x1e, 0x8f, 0xca, 0x3f, 0x0f, 0x02);
++	&data_byte(0xc1, 0xaf, 0xbd, 0x03, 0x01, 0x13, 0x8a, 0x6b);
++	&data_byte(0x3a, 0x91, 0x11, 0x41, 0x4f, 0x67, 0xdc, 0xea);
++	&data_byte(0x97, 0xf2, 0xcf, 0xce, 0xf0, 0xb4, 0xe6, 0x73);
++	&data_byte(0x96, 0xac, 0x74, 0x22, 0xe7, 0xad, 0x35, 0x85);
++	&data_byte(0xe2, 0xf9, 0x37, 0xe8, 0x1c, 0x75, 0xdf, 0x6e);
++	&data_byte(0x47, 0xf1, 0x1a, 0x71, 0x1d, 0x29, 0xc5, 0x89);
++	&data_byte(0x6f, 0xb7, 0x62, 0x0e, 0xaa, 0x18, 0xbe, 0x1b);
++	&data_byte(0xfc, 0x56, 0x3e, 0x4b, 0xc6, 0xd2, 0x79, 0x20);
++	&data_byte(0x9a, 0xdb, 0xc0, 0xfe, 0x78, 0xcd, 0x5a, 0xf4);
++	&data_byte(0x1f, 0xdd, 0xa8, 0x33, 0x88, 0x07, 0xc7, 0x31);
++	&data_byte(0xb1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xec, 0x5f);
++	&data_byte(0x60, 0x51, 0x7f, 0xa9, 0x19, 0xb5, 0x4a, 0x0d);
++	&data_byte(0x2d, 0xe5, 0x7a, 0x9f, 0x93, 0xc9, 0x9c, 0xef);
++	&data_byte(0xa0, 0xe0, 0x3b, 0x4d, 0xae, 0x2a, 0xf5, 0xb0);
++	&data_byte(0xc8, 0xeb, 0xbb, 0x3c, 0x83, 0x53, 0x99, 0x61);
++	&data_byte(0x17, 0x2b, 0x04, 0x7e, 0xba, 0x77, 0xd6, 0x26);
++	&data_byte(0xe1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0c, 0x7d);
++$code.=<<___;
++	.long	0x80808080, 0x80808080, 0xfefefefe, 0xfefefefe
++	.long	0x1b1b1b1b, 0x1b1b1b1b, 0, 0
++.asciz  "AES for x86_64, CRYPTOGAMS by "
++.align	64
++___
++
++# EXCEPTION_DISPOSITION handler (EXCEPTION_RECORD *rec,ULONG64 frame,
++#		CONTEXT *context,DISPATCHER_CONTEXT *disp)
++if ($win64) {
++$rec="%rcx";
++$frame="%rdx";
++$context="%r8";
++$disp="%r9";
++
++$code.=<<___;
++.extern	__imp_RtlVirtualUnwind
++.type	block_se_handler,\@abi-omnipotent
++.align	16
++block_se_handler:
++	push	%rsi
++	push	%rdi
++	push	%rbx
++	push	%rbp
++	push	%r12
++	push	%r13
++	push	%r14
++	push	%r15
++	pushfq
++	sub	\$64,%rsp
++
++	mov	120($context),%rax	# pull context->Rax
++	mov	248($context),%rbx	# pull context->Rip
++
++	mov	8($disp),%rsi		# disp->ImageBase
++	mov	56($disp),%r11		# disp->HandlerData
++
++	mov	0(%r11),%r10d		# HandlerData[0]
++	lea	(%rsi,%r10),%r10	# prologue label
++	cmp	%r10,%rbx		# context->RipRsp
++
++	mov	4(%r11),%r10d		# HandlerData[1]
++	lea	(%rsi,%r10),%r10	# epilogue label
++	cmp	%r10,%rbx		# context->Rip>=epilogue label
++	jae	.Lin_block_prologue
++
++	mov	24(%rax),%rax		# pull saved real stack pointer
++	lea	48(%rax),%rax		# adjust...
++
++	mov	-8(%rax),%rbx
++	mov	-16(%rax),%rbp
++	mov	-24(%rax),%r12
++	mov	-32(%rax),%r13
++	mov	-40(%rax),%r14
++	mov	-48(%rax),%r15
++	mov	%rbx,144($context)	# restore context->Rbx
++	mov	%rbp,160($context)	# restore context->Rbp
++	mov	%r12,216($context)	# restore context->R12
++	mov	%r13,224($context)	# restore context->R13
++	mov	%r14,232($context)	# restore context->R14
++	mov	%r15,240($context)	# restore context->R15
++
++.Lin_block_prologue:
++	mov	8(%rax),%rdi
++	mov	16(%rax),%rsi
++	mov	%rax,152($context)	# restore context->Rsp
++	mov	%rsi,168($context)	# restore context->Rsi
++	mov	%rdi,176($context)	# restore context->Rdi
++
++	jmp	.Lcommon_seh_exit
++.size	block_se_handler,.-block_se_handler
++
++.type	key_se_handler,\@abi-omnipotent
++.align	16
++key_se_handler:
++	push	%rsi
++	push	%rdi
++	push	%rbx
++	push	%rbp
++	push	%r12
++	push	%r13
++	push	%r14
++	push	%r15
++	pushfq
++	sub	\$64,%rsp
++
++	mov	120($context),%rax	# pull context->Rax
++	mov	248($context),%rbx	# pull context->Rip
++
++	mov	8($disp),%rsi		# disp->ImageBase
++	mov	56($disp),%r11		# disp->HandlerData
++
++	mov	0(%r11),%r10d		# HandlerData[0]
++	lea	(%rsi,%r10),%r10	# prologue label
++	cmp	%r10,%rbx		# context->RipRsp
++
++	mov	4(%r11),%r10d		# HandlerData[1]
++	lea	(%rsi,%r10),%r10	# epilogue label
++	cmp	%r10,%rbx		# context->Rip>=epilogue label
++	jae	.Lin_key_prologue
++
++	lea	56(%rax),%rax
++
++	mov	-8(%rax),%rbx
++	mov	-16(%rax),%rbp
++	mov	-24(%rax),%r12
++	mov	-32(%rax),%r13
++	mov	-40(%rax),%r14
++	mov	-48(%rax),%r15
++	mov	%rbx,144($context)	# restore context->Rbx
++	mov	%rbp,160($context)	# restore context->Rbp
++	mov	%r12,216($context)	# restore context->R12
++	mov	%r13,224($context)	# restore context->R13
++	mov	%r14,232($context)	# restore context->R14
++	mov	%r15,240($context)	# restore context->R15
++
++.Lin_key_prologue:
++	mov	8(%rax),%rdi
++	mov	16(%rax),%rsi
++	mov	%rax,152($context)	# restore context->Rsp
++	mov	%rsi,168($context)	# restore context->Rsi
++	mov	%rdi,176($context)	# restore context->Rdi
++
++	jmp	.Lcommon_seh_exit
++.size	key_se_handler,.-key_se_handler
++
++.type	cbc_se_handler,\@abi-omnipotent
++.align	16
++cbc_se_handler:
++	push	%rsi
++	push	%rdi
++	push	%rbx
++	push	%rbp
++	push	%r12
++	push	%r13
++	push	%r14
++	push	%r15
++	pushfq
++	sub	\$64,%rsp
++
++	mov	120($context),%rax	# pull context->Rax
++	mov	248($context),%rbx	# pull context->Rip
++
++	lea	.Lcbc_prologue(%rip),%r10
++	cmp	%r10,%rbx		# context->Rip<.Lcbc_prologue
++	jb	.Lin_cbc_prologue
++
++	lea	.Lcbc_fast_body(%rip),%r10
++	cmp	%r10,%rbx		# context->Rip<.Lcbc_fast_body
++	jb	.Lin_cbc_frame_setup
++
++	lea	.Lcbc_slow_prologue(%rip),%r10
++	cmp	%r10,%rbx		# context->Rip<.Lcbc_slow_prologue
++	jb	.Lin_cbc_body
++
++	lea	.Lcbc_slow_body(%rip),%r10
++	cmp	%r10,%rbx		# context->Rip<.Lcbc_slow_body
++	jb	.Lin_cbc_frame_setup
++
++.Lin_cbc_body:
++	mov	152($context),%rax	# pull context->Rsp
++
++	lea	.Lcbc_epilogue(%rip),%r10
++	cmp	%r10,%rbx		# context->Rip>=.Lcbc_epilogue
++	jae	.Lin_cbc_prologue
++
++	lea	8(%rax),%rax
++
++	lea	.Lcbc_popfq(%rip),%r10
++	cmp	%r10,%rbx		# context->Rip>=.Lcbc_popfq
++	jae	.Lin_cbc_prologue
++
++	mov	`16-8`(%rax),%rax	# biased $_rsp
++	lea	56(%rax),%rax
++
++.Lin_cbc_frame_setup:
++	mov	-16(%rax),%rbx
++	mov	-24(%rax),%rbp
++	mov	-32(%rax),%r12
++	mov	-40(%rax),%r13
++	mov	-48(%rax),%r14
++	mov	-56(%rax),%r15
++	mov	%rbx,144($context)	# restore context->Rbx
++	mov	%rbp,160($context)	# restore context->Rbp
++	mov	%r12,216($context)	# restore context->R12
++	mov	%r13,224($context)	# restore context->R13
++	mov	%r14,232($context)	# restore context->R14
++	mov	%r15,240($context)	# restore context->R15
++
++.Lin_cbc_prologue:
++	mov	8(%rax),%rdi
++	mov	16(%rax),%rsi
++	mov	%rax,152($context)	# restore context->Rsp
++	mov	%rsi,168($context)	# restore context->Rsi
++	mov	%rdi,176($context)	# restore context->Rdi
++
++.Lcommon_seh_exit:
++
++	mov	40($disp),%rdi		# disp->ContextRecord
++	mov	$context,%rsi		# context
++	mov	\$`1232/8`,%ecx		# sizeof(CONTEXT)
++	.long	0xa548f3fc		# cld; rep movsq
++
++	mov	$disp,%rsi
++	xor	%rcx,%rcx		# arg1, UNW_FLAG_NHANDLER
++	mov	8(%rsi),%rdx		# arg2, disp->ImageBase
++	mov	0(%rsi),%r8		# arg3, disp->ControlPc
++	mov	16(%rsi),%r9		# arg4, disp->FunctionEntry
++	mov	40(%rsi),%r10		# disp->ContextRecord
++	lea	56(%rsi),%r11		# &disp->HandlerData
++	lea	24(%rsi),%r12		# &disp->EstablisherFrame
++	mov	%r10,32(%rsp)		# arg5
++	mov	%r11,40(%rsp)		# arg6
++	mov	%r12,48(%rsp)		# arg7
++	mov	%rcx,56(%rsp)		# arg8, (NULL)
++	call	*__imp_RtlVirtualUnwind(%rip)
++
++	mov	\$1,%eax		# ExceptionContinueSearch
++	add	\$64,%rsp
++	popfq
++	pop	%r15
++	pop	%r14
++	pop	%r13
++	pop	%r12
++	pop	%rbp
++	pop	%rbx
++	pop	%rdi
++	pop	%rsi
++	ret
++.size	cbc_se_handler,.-cbc_se_handler
++
++.section	.pdata
++.align	4
++	.rva	.LSEH_begin_AES_encrypt
++	.rva	.LSEH_end_AES_encrypt
++	.rva	.LSEH_info_AES_encrypt
++
++	.rva	.LSEH_begin_AES_decrypt
++	.rva	.LSEH_end_AES_decrypt
++	.rva	.LSEH_info_AES_decrypt
++
++	.rva	.LSEH_begin_AES_set_encrypt_key
++	.rva	.LSEH_end_AES_set_encrypt_key
++	.rva	.LSEH_info_AES_set_encrypt_key
++
++	.rva	.LSEH_begin_AES_set_decrypt_key
++	.rva	.LSEH_end_AES_set_decrypt_key
++	.rva	.LSEH_info_AES_set_decrypt_key
++
++	.rva	.LSEH_begin_AES_cbc_encrypt
++	.rva	.LSEH_end_AES_cbc_encrypt
++	.rva	.LSEH_info_AES_cbc_encrypt
++
++.section	.xdata
++.align	8
++.LSEH_info_AES_encrypt:
++	.byte	9,0,0,0
++	.rva	block_se_handler
++	.rva	.Lenc_prologue,.Lenc_epilogue	# HandlerData[]
++.LSEH_info_AES_decrypt:
++	.byte	9,0,0,0
++	.rva	block_se_handler
++	.rva	.Ldec_prologue,.Ldec_epilogue	# HandlerData[]
++.LSEH_info_AES_set_encrypt_key:
++	.byte	9,0,0,0
++	.rva	key_se_handler
++	.rva	.Lenc_key_prologue,.Lenc_key_epilogue	# HandlerData[]
++.LSEH_info_AES_set_decrypt_key:
++	.byte	9,0,0,0
++	.rva	key_se_handler
++	.rva	.Ldec_key_prologue,.Ldec_key_epilogue	# HandlerData[]
++.LSEH_info_AES_cbc_encrypt:
++	.byte	9,0,0,0
++	.rva	cbc_se_handler
++___
++}
++
++$code =~ s/\`([^\`]*)\`/eval($1)/gem;
++
++print $code;
++
++close STDOUT;
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/aes/asm/aesfx-sparcv9.pl b/CryptoPkg/Library/OpensslLib/openssl/crypto/aes/asm/aesfx-sparcv9.pl
+new file mode 100644
+index 0000000..04b3cf7
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/aes/asm/aesfx-sparcv9.pl
+@@ -0,0 +1,1270 @@
++#! /usr/bin/env perl
++# Copyright 2016 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
++# in the file LICENSE in the source distribution or at
++# https://www.openssl.org/source/license.html
++
++#
++# ====================================================================
++# Written by Andy Polyakov  for the OpenSSL
++# project. The module is, however, dual licensed under OpenSSL and
++# CRYPTOGAMS licenses depending on where you obtain it. For further
++# details see http://www.openssl.org/~appro/cryptogams/.
++# ====================================================================
++
++# March 2016
++#
++# Initial support for Fujitsu SPARC64 X/X+ comprises minimally
++# required key setup and single-block procedures.
++#
++# April 2016
++#
++# Add "teaser" CBC and CTR mode-specific subroutines. "Teaser" means
++# that parallelizeable nature of CBC decrypt and CTR is not utilized
++# yet. CBC encrypt on the other hand is as good as it can possibly
++# get processing one byte in 4.1 cycles with 128-bit key on SPARC64 X.
++# This is ~6x faster than pure software implementation...
++#
++# July 2016
++#
++# Switch from faligndata to fshiftorx, which allows to omit alignaddr
++# instructions and improve single-block and short-input performance
++# with misaligned data.
++
++$output = pop;
++open STDOUT,">$output";
++
++{
++my ($inp,$out,$key,$rounds,$tmp,$mask) = map("%o$_",(0..5));
++
++$code.=<<___;
++#include "sparc_arch.h"
++
++#define LOCALS (STACK_BIAS+STACK_FRAME)
++
++.text
++
++.globl	aes_fx_encrypt
++.align	32
++aes_fx_encrypt:
++	and		$inp, 7, $tmp		! is input aligned?
++	andn		$inp, 7, $inp
++	ldd		[$key +  0], %f6	! round[0]
++	ldd		[$key +  8], %f8
++	mov		%o7, %g1
++	ld		[$key + 240], $rounds
++
++1:	call		.+8
++	add		%o7, .Linp_align-1b, %o7
++
++	sll		$tmp, 3, $tmp
++	ldd		[$inp + 0], %f0		! load input
++	brz,pt		$tmp, .Lenc_inp_aligned
++	ldd		[$inp + 8], %f2
++
++	ldd		[%o7 + $tmp], %f14	! shift left params
++	ldd		[$inp + 16], %f4
++	fshiftorx	%f0, %f2, %f14, %f0
++	fshiftorx	%f2, %f4, %f14, %f2
++
++.Lenc_inp_aligned:
++	ldd		[$key + 16], %f10	! round[1]
++	ldd		[$key + 24], %f12
++
++	fxor		%f0, %f6, %f0		! ^=round[0]
++	fxor		%f2, %f8, %f2
++	ldd		[$key + 32], %f6	! round[2]
++	ldd		[$key + 40], %f8
++	add		$key, 32, $key
++	sub		$rounds, 4, $rounds
++
++.Loop_enc:
++	fmovd		%f0, %f4
++	faesencx	%f2, %f10, %f0
++	faesencx	%f4, %f12, %f2
++	ldd		[$key + 16], %f10
++	ldd		[$key + 24], %f12
++	add		$key, 32, $key
++
++	fmovd		%f0, %f4
++	faesencx	%f2, %f6, %f0
++	faesencx	%f4, %f8, %f2
++	ldd		[$key +  0], %f6
++	ldd		[$key +  8], %f8
++
++	brnz,a		$rounds, .Loop_enc
++	sub		$rounds, 2, $rounds
++
++	andcc		$out, 7, $tmp		! is output aligned?
++	andn		$out, 7, $out
++	mov		0xff, $mask
++	srl		$mask, $tmp, $mask
++	add		%o7, 64, %o7
++	sll		$tmp, 3, $tmp
++
++	fmovd		%f0, %f4
++	faesencx	%f2, %f10, %f0
++	faesencx	%f4, %f12, %f2
++	ldd		[%o7 + $tmp], %f14	! shift right params
++
++	fmovd		%f0, %f4
++	faesenclx	%f2, %f6, %f0
++	faesenclx	%f4, %f8, %f2
++
++	bnz,pn		%icc, .Lenc_out_unaligned
++	mov		%g1, %o7
++
++	std		%f0, [$out + 0]
++	retl
++	std		%f2, [$out + 8]
++
++.align	16
++.Lenc_out_unaligned:
++	add		$out, 16, $inp
++	orn		%g0, $mask, $tmp
++	fshiftorx	%f0, %f0, %f14, %f4
++	fshiftorx	%f0, %f2, %f14, %f6
++	fshiftorx	%f2, %f2, %f14, %f8
++
++	stda		%f4, [$out + $mask]0xc0	! partial store
++	std		%f6, [$out + 8]
++	stda		%f8, [$inp + $tmp]0xc0	! partial store
++	retl
++	nop
++.type	aes_fx_encrypt,#function
++.size	aes_fx_encrypt,.-aes_fx_encrypt
++
++.globl	aes_fx_decrypt
++.align	32
++aes_fx_decrypt:
++	and		$inp, 7, $tmp		! is input aligned?
++	andn		$inp, 7, $inp
++	ldd		[$key +  0], %f6	! round[0]
++	ldd		[$key +  8], %f8
++	mov		%o7, %g1
++	ld		[$key + 240], $rounds
++
++1:	call		.+8
++	add		%o7, .Linp_align-1b, %o7
++
++	sll		$tmp, 3, $tmp
++	ldd		[$inp + 0], %f0		! load input
++	brz,pt		$tmp, .Ldec_inp_aligned
++	ldd		[$inp + 8], %f2
++
++	ldd		[%o7 + $tmp], %f14	! shift left params
++	ldd		[$inp + 16], %f4
++	fshiftorx	%f0, %f2, %f14, %f0
++	fshiftorx	%f2, %f4, %f14, %f2
++
++.Ldec_inp_aligned:
++	ldd		[$key + 16], %f10	! round[1]
++	ldd		[$key + 24], %f12
++
++	fxor		%f0, %f6, %f0		! ^=round[0]
++	fxor		%f2, %f8, %f2
++	ldd		[$key + 32], %f6	! round[2]
++	ldd		[$key + 40], %f8
++	add		$key, 32, $key
++	sub		$rounds, 4, $rounds
++
++.Loop_dec:
++	fmovd		%f0, %f4
++	faesdecx	%f2, %f10, %f0
++	faesdecx	%f4, %f12, %f2
++	ldd		[$key + 16], %f10
++	ldd		[$key + 24], %f12
++	add		$key, 32, $key
++
++	fmovd		%f0, %f4
++	faesdecx	%f2, %f6, %f0
++	faesdecx	%f4, %f8, %f2
++	ldd		[$key +  0], %f6
++	ldd		[$key +  8], %f8
++
++	brnz,a		$rounds, .Loop_dec
++	sub		$rounds, 2, $rounds
++
++	andcc		$out, 7, $tmp		! is output aligned?
++	andn		$out, 7, $out
++	mov		0xff, $mask
++	srl		$mask, $tmp, $mask
++	add		%o7, 64, %o7
++	sll		$tmp, 3, $tmp
++
++	fmovd		%f0, %f4
++	faesdecx	%f2, %f10, %f0
++	faesdecx	%f4, %f12, %f2
++	ldd		[%o7 + $tmp], %f14	! shift right params
++
++	fmovd		%f0, %f4
++	faesdeclx	%f2, %f6, %f0
++	faesdeclx	%f4, %f8, %f2
++
++	bnz,pn		%icc, .Ldec_out_unaligned
++	mov		%g1, %o7
++
++	std		%f0, [$out + 0]
++	retl
++	std		%f2, [$out + 8]
++
++.align	16
++.Ldec_out_unaligned:
++	add		$out, 16, $inp
++	orn		%g0, $mask, $tmp
++	fshiftorx	%f0, %f0, %f14, %f4
++	fshiftorx	%f0, %f2, %f14, %f6
++	fshiftorx	%f2, %f2, %f14, %f8
++
++	stda		%f4, [$out + $mask]0xc0	! partial store
++	std		%f6, [$out + 8]
++	stda		%f8, [$inp + $tmp]0xc0	! partial store
++	retl
++	nop
++.type	aes_fx_decrypt,#function
++.size	aes_fx_decrypt,.-aes_fx_decrypt
++___
++}
++{
++my ($inp,$bits,$out,$tmp,$inc) = map("%o$_",(0..5));
++$code.=<<___;
++.globl	aes_fx_set_decrypt_key
++.align	32
++aes_fx_set_decrypt_key:
++	b		.Lset_encrypt_key
++	mov		-1, $inc
++	retl
++	nop
++.type	aes_fx_set_decrypt_key,#function
++.size	aes_fx_set_decrypt_key,.-aes_fx_set_decrypt_key
++
++.globl	aes_fx_set_encrypt_key
++.align	32
++aes_fx_set_encrypt_key:
++	mov		1, $inc
++	nop
++.Lset_encrypt_key:
++	and		$inp, 7, $tmp
++	andn		$inp, 7, $inp
++	sll		$tmp, 3, $tmp
++	mov		%o7, %g1
++
++1:	call		.+8
++	add		%o7, .Linp_align-1b, %o7
++
++	ldd		[%o7 + $tmp], %f10	! shift left params
++	mov		%g1, %o7
++
++	cmp		$bits, 192
++	ldd		[$inp + 0], %f0
++	bl,pt		%icc, .L128
++	ldd		[$inp + 8], %f2
++
++	be,pt		%icc, .L192
++	ldd		[$inp + 16], %f4
++	brz,pt		$tmp, .L256aligned
++	ldd		[$inp + 24], %f6
++
++	ldd		[$inp + 32], %f8
++	fshiftorx	%f0, %f2, %f10, %f0
++	fshiftorx	%f2, %f4, %f10, %f2
++	fshiftorx	%f4, %f6, %f10, %f4
++	fshiftorx	%f6, %f8, %f10, %f6
++
++.L256aligned:
++	mov		14, $bits
++	and		$inc, `14*16`, $tmp
++	st		$bits, [$out + 240]	! store rounds
++	add		$out, $tmp, $out	! start or end of key schedule
++	sllx		$inc, 4, $inc		! 16 or -16
++___
++for ($i=0; $i<6; $i++) {
++    $code.=<<___;
++	std		%f0, [$out + 0]
++	faeskeyx	%f6, `0x10+$i`, %f0
++	std		%f2, [$out + 8]
++	add		$out, $inc, $out
++	faeskeyx	%f0, 0x00, %f2
++	std		%f4, [$out + 0]
++	faeskeyx	%f2, 0x01, %f4
++	std		%f6, [$out + 8]
++	add		$out, $inc, $out
++	faeskeyx	%f4, 0x00, %f6
++___
++}
++$code.=<<___;
++	std		%f0, [$out + 0]
++	faeskeyx	%f6, `0x10+$i`, %f0
++	std		%f2, [$out + 8]
++	add		$out, $inc, $out
++	faeskeyx	%f0, 0x00, %f2
++	std		%f4,[$out + 0]
++	std		%f6,[$out + 8]
++	add		$out, $inc, $out
++	std		%f0,[$out + 0]
++	std		%f2,[$out + 8]
++	retl
++	xor		%o0, %o0, %o0		! return 0
++
++.align	16
++.L192:
++	brz,pt		$tmp, .L192aligned
++	nop
++
++	ldd		[$inp + 24], %f6
++	fshiftorx	%f0, %f2, %f10, %f0
++	fshiftorx	%f2, %f4, %f10, %f2
++	fshiftorx	%f4, %f6, %f10, %f4
++
++.L192aligned:
++	mov		12, $bits
++	and		$inc, `12*16`, $tmp
++	st		$bits, [$out + 240]	! store rounds
++	add		$out, $tmp, $out	! start or end of key schedule
++	sllx		$inc, 4, $inc		! 16 or -16
++___
++for ($i=0; $i<8; $i+=2) {
++    $code.=<<___;
++	std		%f0, [$out + 0]
++	faeskeyx	%f4, `0x10+$i`, %f0
++	std		%f2, [$out + 8]
++	add		$out, $inc, $out
++	faeskeyx	%f0, 0x00, %f2
++	std		%f4, [$out + 0]
++	faeskeyx	%f2, 0x00, %f4
++	std		%f0, [$out + 8]
++	add		$out, $inc, $out
++	faeskeyx	%f4, `0x10+$i+1`, %f0
++	std		%f2, [$out + 0]
++	faeskeyx	%f0, 0x00, %f2
++	std		%f4, [$out + 8]
++	add		$out, $inc, $out
++___
++$code.=<<___		if ($i<6);
++	faeskeyx	%f2, 0x00, %f4
++___
++}
++$code.=<<___;
++	std		%f0, [$out + 0]
++	std		%f2, [$out + 8]
++	retl
++	xor		%o0, %o0, %o0		! return 0
++
++.align	16
++.L128:
++	brz,pt		$tmp, .L128aligned
++	nop
++
++	ldd		[$inp + 16], %f4
++	fshiftorx	%f0, %f2, %f10, %f0
++	fshiftorx	%f2, %f4, %f10, %f2
++
++.L128aligned:
++	mov		10, $bits
++	and		$inc, `10*16`, $tmp
++	st		$bits, [$out + 240]	! store rounds
++	add		$out, $tmp, $out	! start or end of key schedule
++	sllx		$inc, 4, $inc		! 16 or -16
++___
++for ($i=0; $i<10; $i++) {
++    $code.=<<___;
++	std		%f0, [$out + 0]
++	faeskeyx	%f2, `0x10+$i`, %f0
++	std		%f2, [$out + 8]
++	add		$out, $inc, $out
++	faeskeyx	%f0, 0x00, %f2
++___
++}
++$code.=<<___;
++	std		%f0, [$out + 0]
++	std		%f2, [$out + 8]
++	retl
++	xor		%o0, %o0, %o0		! return 0
++.type	aes_fx_set_encrypt_key,#function
++.size	aes_fx_set_encrypt_key,.-aes_fx_set_encrypt_key
++___
++}
++{
++my ($inp,$out,$len,$key,$ivp,$dir) = map("%i$_",(0..5));
++my ($rounds,$inner,$end,$inc,$ialign,$oalign,$mask) = map("%l$_",(0..7));
++my ($iv0,$iv1,$r0hi,$r0lo,$rlhi,$rllo,$in0,$in1,$intail,$outhead,$fshift)
++   = map("%f$_",grep { !($_ & 1) } (16 .. 62));
++my ($ileft,$iright) = ($ialign,$oalign);
++
++$code.=<<___;
++.globl	aes_fx_cbc_encrypt
++.align	32
++aes_fx_cbc_encrypt:
++	save		%sp, -STACK_FRAME-16, %sp
++	srln		$len, 4, $len
++	and		$inp, 7, $ialign
++	andn		$inp, 7, $inp
++	brz,pn		$len, .Lcbc_no_data
++	sll		$ialign, 3, $ileft
++
++1:	call		.+8
++	add		%o7, .Linp_align-1b, %o7
++
++	ld		[$key + 240], $rounds
++	and		$out, 7, $oalign
++	ld		[$ivp + 0], %f0		! load ivec
++	andn		$out, 7, $out
++	ld		[$ivp + 4], %f1
++	sll		$oalign, 3, $mask
++	ld		[$ivp + 8], %f2
++	ld		[$ivp + 12], %f3
++
++	sll		$rounds, 4, $rounds
++	add		$rounds, $key, $end
++	ldd		[$key + 0], $r0hi	! round[0]
++	ldd		[$key + 8], $r0lo
++
++	add		$inp, 16, $inp
++	sub		$len,  1, $len
++	ldd		[$end + 0], $rlhi	! round[last]
++	ldd		[$end + 8], $rllo
++
++	mov		16, $inc
++	movrz		$len, 0, $inc
++	ldd		[$key + 16], %f10	! round[1]
++	ldd		[$key + 24], %f12
++
++	ldd		[%o7 + $ileft], $fshift	! shift left params
++	add		%o7, 64, %o7
++	ldd		[$inp - 16], $in0	! load input
++	ldd		[$inp -  8], $in1
++	ldda		[$inp]0x82, $intail	! non-faulting load
++	brz		$dir, .Lcbc_decrypt
++	add		$inp, $inc, $inp	! inp+=16
++
++	fxor		$r0hi, %f0, %f0		! ivec^=round[0]
++	fxor		$r0lo, %f2, %f2
++	fshiftorx	$in0, $in1, $fshift, $in0
++	fshiftorx	$in1, $intail, $fshift, $in1
++	nop
++
++.Loop_cbc_enc:
++	fxor		$in0, %f0, %f0		! inp^ivec^round[0]
++	fxor		$in1, %f2, %f2
++	ldd		[$key + 32], %f6	! round[2]
++	ldd		[$key + 40], %f8
++	add		$key, 32, $end
++	sub		$rounds, 16*6, $inner
++
++.Lcbc_enc:
++	fmovd		%f0, %f4
++	faesencx	%f2, %f10, %f0
++	faesencx	%f4, %f12, %f2
++	ldd		[$end + 16], %f10
++	ldd		[$end + 24], %f12
++	add		$end, 32, $end
++
++	fmovd		%f0, %f4
++	faesencx	%f2, %f6, %f0
++	faesencx	%f4, %f8, %f2
++	ldd		[$end + 0], %f6
++	ldd		[$end + 8], %f8
++
++	brnz,a		$inner, .Lcbc_enc
++	sub		$inner, 16*2, $inner
++
++	fmovd		%f0, %f4
++	faesencx	%f2, %f10, %f0
++	faesencx	%f4, %f12, %f2
++	ldd		[$end + 16], %f10	! round[last-1]
++	ldd		[$end + 24], %f12
++
++	movrz		$len, 0, $inc
++	fmovd		$intail, $in0
++	ldd		[$inp - 8], $in1	! load next input block
++	ldda		[$inp]0x82, $intail	! non-faulting load
++	add		$inp, $inc, $inp	! inp+=16
++
++	fmovd		%f0, %f4
++	faesencx	%f2, %f6, %f0
++	faesencx	%f4, %f8, %f2
++
++	fshiftorx	$in0, $in1, $fshift, $in0
++	fshiftorx	$in1, $intail, $fshift, $in1
++
++	fmovd		%f0, %f4
++	faesencx	%f2, %f10, %f0
++	faesencx	%f4, %f12, %f2
++	ldd		[$key + 16], %f10	! round[1]
++	ldd		[$key + 24], %f12
++
++	fxor		$r0hi, $in0, $in0	! inp^=round[0]
++	fxor		$r0lo, $in1, $in1
++
++	fmovd		%f0, %f4
++	faesenclx	%f2, $rlhi, %f0
++	faesenclx	%f4, $rllo, %f2
++
++	brnz,pn		$oalign, .Lcbc_enc_unaligned_out
++	nop
++
++	std		%f0, [$out + 0]
++	std		%f2, [$out + 8]
++	add		$out, 16, $out
++
++	brnz,a		$len, .Loop_cbc_enc
++	sub		$len, 1, $len
++
++	st		%f0, [$ivp + 0]		! output ivec
++	st		%f1, [$ivp + 4]
++	st		%f2, [$ivp + 8]
++	st		%f3, [$ivp + 12]
++
++.Lcbc_no_data:
++	ret
++	restore
++
++.align	32
++.Lcbc_enc_unaligned_out:
++	ldd		[%o7 + $mask], $fshift	! shift right params
++	mov		0xff, $mask
++	srl		$mask, $oalign, $mask
++	sub		%g0, $ileft, $iright
++
++	fshiftorx	%f0, %f0, $fshift, %f6
++	fshiftorx	%f0, %f2, $fshift, %f8
++
++	stda		%f6, [$out + $mask]0xc0	! partial store
++	orn		%g0, $mask, $mask
++	std		%f8, [$out + 8]
++	add		$out, 16, $out
++	brz		$len, .Lcbc_enc_unaligned_out_done
++	sub		$len, 1, $len
++	b		.Loop_cbc_enc_unaligned_out
++	nop
++
++.align	32
++.Loop_cbc_enc_unaligned_out:
++	fmovd		%f2, $outhead
++	fxor		$in0, %f0, %f0		! inp^ivec^round[0]
++	fxor		$in1, %f2, %f2
++	ldd		[$key + 32], %f6	! round[2]
++	ldd		[$key + 40], %f8
++
++	fmovd		%f0, %f4
++	faesencx	%f2, %f10, %f0
++	faesencx	%f4, %f12, %f2
++	ldd		[$key + 48], %f10	! round[3]
++	ldd		[$key + 56], %f12
++
++	ldx		[$inp - 16], %o0
++	ldx		[$inp -  8], %o1
++	brz		$ileft, .Lcbc_enc_aligned_inp
++	movrz		$len, 0, $inc
++
++	ldx		[$inp], %o2
++	sllx		%o0, $ileft, %o0
++	srlx		%o1, $iright, %g1
++	sllx		%o1, $ileft, %o1
++	or		%g1, %o0, %o0
++	srlx		%o2, $iright, %o2
++	or		%o2, %o1, %o1
++
++.Lcbc_enc_aligned_inp:
++	fmovd		%f0, %f4
++	faesencx	%f2, %f6, %f0
++	faesencx	%f4, %f8, %f2
++	ldd		[$key + 64], %f6	! round[4]
++	ldd		[$key + 72], %f8
++	add		$key, 64, $end
++	sub		$rounds, 16*8, $inner
++
++	stx		%o0, [%sp + LOCALS + 0]
++	stx		%o1, [%sp + LOCALS + 8]
++	add		$inp, $inc, $inp	! inp+=16
++	nop
++
++.Lcbc_enc_unaligned:
++	fmovd		%f0, %f4
++	faesencx	%f2, %f10, %f0
++	faesencx	%f4, %f12, %f2
++	ldd		[$end + 16], %f10
++	ldd		[$end + 24], %f12
++	add		$end, 32, $end
++
++	fmovd		%f0, %f4
++	faesencx	%f2, %f6, %f0
++	faesencx	%f4, %f8, %f2
++	ldd		[$end + 0], %f6
++	ldd		[$end + 8], %f8
++
++	brnz,a		$inner, .Lcbc_enc_unaligned
++	sub		$inner, 16*2, $inner
++
++	fmovd		%f0, %f4
++	faesencx	%f2, %f10, %f0
++	faesencx	%f4, %f12, %f2
++	ldd		[$end + 16], %f10	! round[last-1]
++	ldd		[$end + 24], %f12
++
++	fmovd		%f0, %f4
++	faesencx	%f2, %f6, %f0
++	faesencx	%f4, %f8, %f2
++
++	ldd		[%sp + LOCALS + 0], $in0
++	ldd		[%sp + LOCALS + 8], $in1
++
++	fmovd		%f0, %f4
++	faesencx	%f2, %f10, %f0
++	faesencx	%f4, %f12, %f2
++	ldd		[$key + 16], %f10	! round[1]
++	ldd		[$key + 24], %f12
++
++	fxor		$r0hi, $in0, $in0	! inp^=round[0]
++	fxor		$r0lo, $in1, $in1
++
++	fmovd		%f0, %f4
++	faesenclx	%f2, $rlhi, %f0
++	faesenclx	%f4, $rllo, %f2
++
++	fshiftorx	$outhead, %f0, $fshift, %f6
++	fshiftorx	%f0, %f2, $fshift, %f8
++	std		%f6, [$out + 0]
++	std		%f8, [$out + 8]
++	add		$out, 16, $out
++
++	brnz,a		$len, .Loop_cbc_enc_unaligned_out
++	sub		$len, 1, $len
++
++.Lcbc_enc_unaligned_out_done:
++	fshiftorx	%f2, %f2, $fshift, %f8
++	stda		%f8, [$out + $mask]0xc0	! partial store
++
++	st		%f0, [$ivp + 0]		! output ivec
++	st		%f1, [$ivp + 4]
++	st		%f2, [$ivp + 8]
++	st		%f3, [$ivp + 12]
++
++	ret
++	restore
++
++.align	32
++.Lcbc_decrypt:
++	fshiftorx	$in0, $in1, $fshift, $in0
++	fshiftorx	$in1, $intail, $fshift, $in1
++	fmovd		%f0, $iv0
++	fmovd		%f2, $iv1
++
++.Loop_cbc_dec:
++	fxor		$in0, $r0hi, %f0	! inp^round[0]
++	fxor		$in1, $r0lo, %f2
++	ldd		[$key + 32], %f6	! round[2]
++	ldd		[$key + 40], %f8
++	add		$key, 32, $end
++	sub		$rounds, 16*6, $inner
++
++.Lcbc_dec:
++	fmovd		%f0, %f4
++	faesdecx	%f2, %f10, %f0
++	faesdecx	%f4, %f12, %f2
++	ldd		[$end + 16], %f10
++	ldd		[$end + 24], %f12
++	add		$end, 32, $end
++
++	fmovd		%f0, %f4
++	faesdecx	%f2, %f6, %f0
++	faesdecx	%f4, %f8, %f2
++	ldd		[$end + 0], %f6
++	ldd		[$end + 8], %f8
++
++	brnz,a		$inner, .Lcbc_dec
++	sub		$inner, 16*2, $inner
++
++	fmovd		%f0, %f4
++	faesdecx	%f2, %f10, %f0
++	faesdecx	%f4, %f12, %f2
++	ldd		[$end + 16], %f10	! round[last-1]
++	ldd		[$end + 24], %f12
++
++	fmovd		%f0, %f4
++	faesdecx	%f2, %f6, %f0
++	faesdecx	%f4, %f8, %f2
++	fxor		$iv0, $rlhi, %f6	! ivec^round[last]
++	fxor		$iv1, $rllo, %f8
++	fmovd		$in0, $iv0
++	fmovd		$in1, $iv1
++
++	movrz		$len, 0, $inc
++	fmovd		$intail, $in0
++	ldd		[$inp - 8], $in1	! load next input block
++	ldda		[$inp]0x82, $intail	! non-faulting load
++	add		$inp, $inc, $inp	! inp+=16
++
++	fmovd		%f0, %f4
++	faesdecx	%f2, %f10, %f0
++	faesdecx	%f4, %f12, %f2
++	ldd		[$key + 16], %f10	! round[1]
++	ldd		[$key + 24], %f12
++
++	fshiftorx	$in0, $in1, $fshift, $in0
++	fshiftorx	$in1, $intail, $fshift, $in1
++
++	fmovd		%f0, %f4
++	faesdeclx	%f2, %f6, %f0
++	faesdeclx	%f4, %f8, %f2
++
++	brnz,pn		$oalign, .Lcbc_dec_unaligned_out
++	nop
++
++	std		%f0, [$out + 0]
++	std		%f2, [$out + 8]
++	add		$out, 16, $out
++
++	brnz,a		$len, .Loop_cbc_dec
++	sub		$len, 1, $len
++
++	st		$iv0,    [$ivp + 0]	! output ivec
++	st		$iv0#lo, [$ivp + 4]
++	st		$iv1,    [$ivp + 8]
++	st		$iv1#lo, [$ivp + 12]
++
++	ret
++	restore
++
++.align	32
++.Lcbc_dec_unaligned_out:
++	ldd		[%o7 + $mask], $fshift	! shift right params
++	mov		0xff, $mask
++	srl		$mask, $oalign, $mask
++	sub		%g0, $ileft, $iright
++
++	fshiftorx	%f0, %f0, $fshift, %f6
++	fshiftorx	%f0, %f2, $fshift, %f8
++
++	stda		%f6, [$out + $mask]0xc0	! partial store
++	orn		%g0, $mask, $mask
++	std		%f8, [$out + 8]
++	add		$out, 16, $out
++	brz		$len, .Lcbc_dec_unaligned_out_done
++	sub		$len, 1, $len
++	b		.Loop_cbc_dec_unaligned_out
++	nop
++
++.align	32
++.Loop_cbc_dec_unaligned_out:
++	fmovd		%f2, $outhead
++	fxor		$in0, $r0hi, %f0	! inp^round[0]
++	fxor		$in1, $r0lo, %f2
++	ldd		[$key + 32], %f6	! round[2]
++	ldd		[$key + 40], %f8
++
++	fmovd		%f0, %f4
++	faesdecx	%f2, %f10, %f0
++	faesdecx	%f4, %f12, %f2
++	ldd		[$key + 48], %f10	! round[3]
++	ldd		[$key + 56], %f12
++
++	ldx		[$inp - 16], %o0
++	ldx		[$inp - 8], %o1
++	brz		$ileft, .Lcbc_dec_aligned_inp
++	movrz		$len, 0, $inc
++
++	ldx		[$inp], %o2
++	sllx		%o0, $ileft, %o0
++	srlx		%o1, $iright, %g1
++	sllx		%o1, $ileft, %o1
++	or		%g1, %o0, %o0
++	srlx		%o2, $iright, %o2
++	or		%o2, %o1, %o1
++
++.Lcbc_dec_aligned_inp:
++	fmovd		%f0, %f4
++	faesdecx	%f2, %f6, %f0
++	faesdecx	%f4, %f8, %f2
++	ldd		[$key + 64], %f6	! round[4]
++	ldd		[$key + 72], %f8
++	add		$key, 64, $end
++	sub		$rounds, 16*8, $inner
++
++	stx		%o0, [%sp + LOCALS + 0]
++	stx		%o1, [%sp + LOCALS + 8]
++	add		$inp, $inc, $inp	! inp+=16
++	nop
++
++.Lcbc_dec_unaligned:
++	fmovd		%f0, %f4
++	faesdecx	%f2, %f10, %f0
++	faesdecx	%f4, %f12, %f2
++	ldd		[$end + 16], %f10
++	ldd		[$end + 24], %f12
++	add		$end, 32, $end
++
++	fmovd		%f0, %f4
++	faesdecx	%f2, %f6, %f0
++	faesdecx	%f4, %f8, %f2
++	ldd		[$end + 0], %f6
++	ldd		[$end + 8], %f8
++
++	brnz,a		$inner, .Lcbc_dec_unaligned
++	sub		$inner, 16*2, $inner
++
++	fmovd		%f0, %f4
++	faesdecx	%f2, %f10, %f0
++	faesdecx	%f4, %f12, %f2
++	ldd		[$end + 16], %f10	! round[last-1]
++	ldd		[$end + 24], %f12
++
++	fmovd		%f0, %f4
++	faesdecx	%f2, %f6, %f0
++	faesdecx	%f4, %f8, %f2
++
++	fxor		$iv0, $rlhi, %f6	! ivec^round[last]
++	fxor		$iv1, $rllo, %f8
++	fmovd		$in0, $iv0
++	fmovd		$in1, $iv1
++	ldd		[%sp + LOCALS + 0], $in0
++	ldd		[%sp + LOCALS + 8], $in1
++
++	fmovd		%f0, %f4
++	faesdecx	%f2, %f10, %f0
++	faesdecx	%f4, %f12, %f2
++	ldd		[$key + 16], %f10	! round[1]
++	ldd		[$key + 24], %f12
++
++	fmovd		%f0, %f4
++	faesdeclx	%f2, %f6, %f0
++	faesdeclx	%f4, %f8, %f2
++
++	fshiftorx	$outhead, %f0, $fshift, %f6
++	fshiftorx	%f0, %f2, $fshift, %f8
++	std		%f6, [$out + 0]
++	std		%f8, [$out + 8]
++	add		$out, 16, $out
++
++	brnz,a		$len, .Loop_cbc_dec_unaligned_out
++	sub		$len, 1, $len
++
++.Lcbc_dec_unaligned_out_done:
++	fshiftorx	%f2, %f2, $fshift, %f8
++	stda		%f8, [$out + $mask]0xc0	! partial store
++
++	st		$iv0,    [$ivp + 0]	! output ivec
++	st		$iv0#lo, [$ivp + 4]
++	st		$iv1,    [$ivp + 8]
++	st		$iv1#lo, [$ivp + 12]
++
++	ret
++	restore
++.type	aes_fx_cbc_encrypt,#function
++.size	aes_fx_cbc_encrypt,.-aes_fx_cbc_encrypt
++___
++}
++{
++my ($inp,$out,$len,$key,$ivp) = map("%i$_",(0..5));
++my ($rounds,$inner,$end,$inc,$ialign,$oalign,$mask) = map("%l$_",(0..7));
++my ($ctr0,$ctr1,$r0hi,$r0lo,$rlhi,$rllo,$in0,$in1,$intail,$outhead,$fshift)
++   = map("%f$_",grep { !($_ & 1) } (16 .. 62));
++my ($ileft,$iright) = ($ialign, $oalign);
++my $one = "%f14";
++
++$code.=<<___;
++.globl	aes_fx_ctr32_encrypt_blocks
++.align	32
++aes_fx_ctr32_encrypt_blocks:
++	save		%sp, -STACK_FRAME-16, %sp
++	srln		$len, 0, $len
++	and		$inp, 7, $ialign
++	andn		$inp, 7, $inp
++	brz,pn		$len, .Lctr32_no_data
++	sll		$ialign, 3, $ileft
++
++.Lpic:	call		.+8
++	add		%o7, .Linp_align - .Lpic, %o7
++
++	ld		[$key + 240], $rounds
++	and		$out, 7, $oalign
++	ld		[$ivp +  0], $ctr0	! load counter
++	andn		$out, 7, $out
++	ld		[$ivp +  4], $ctr0#lo
++	sll		$oalign, 3, $mask
++	ld		[$ivp +  8], $ctr1
++	ld		[$ivp + 12], $ctr1#lo
++	ldd		[%o7 + 128], $one
++
++	sll		$rounds, 4, $rounds
++	add		$rounds, $key, $end
++	ldd		[$key + 0], $r0hi	! round[0]
++	ldd		[$key + 8], $r0lo
++
++	add		$inp, 16, $inp
++	sub		$len, 1, $len
++	ldd		[$key + 16], %f10	! round[1]
++	ldd		[$key + 24], %f12
++
++	mov		16, $inc
++	movrz		$len, 0, $inc
++	ldd		[$end + 0], $rlhi	! round[last]
++	ldd		[$end + 8], $rllo
++
++	ldd		[%o7 + $ileft], $fshift	! shiftleft params
++	add		%o7, 64, %o7
++	ldd		[$inp - 16], $in0	! load input
++	ldd		[$inp -  8], $in1
++	ldda		[$inp]0x82, $intail	! non-faulting load
++	add		$inp, $inc, $inp	! inp+=16
++
++	fshiftorx	$in0, $in1, $fshift, $in0
++	fshiftorx	$in1, $intail, $fshift, $in1
++
++.Loop_ctr32:
++	fxor		$ctr0, $r0hi, %f0	! counter^round[0]
++	fxor		$ctr1, $r0lo, %f2
++	ldd		[$key + 32], %f6	! round[2]
++	ldd		[$key + 40], %f8
++	add		$key, 32, $end
++	sub		$rounds, 16*6, $inner
++
++.Lctr32_enc:
++	fmovd		%f0, %f4
++	faesencx	%f2, %f10, %f0
++	faesencx	%f4, %f12, %f2
++	ldd		[$end + 16], %f10
++	ldd		[$end + 24], %f12
++	add		$end, 32, $end
++
++	fmovd		%f0, %f4
++	faesencx	%f2, %f6, %f0
++	faesencx	%f4, %f8, %f2
++	ldd		[$end + 0], %f6
++	ldd		[$end + 8], %f8
++
++	brnz,a		$inner, .Lctr32_enc
++	sub		$inner, 16*2, $inner
++
++	fmovd		%f0, %f4
++	faesencx	%f2, %f10, %f0
++	faesencx	%f4, %f12, %f2
++	ldd		[$end + 16], %f10	! round[last-1]
++	ldd		[$end + 24], %f12
++
++	fmovd		%f0, %f4
++	faesencx	%f2, %f6, %f0
++	faesencx	%f4, %f8, %f2
++	fxor		$in0, $rlhi, %f6	! inp^round[last]
++	fxor		$in1, $rllo, %f8
++
++	movrz		$len, 0, $inc
++	fmovd		$intail, $in0
++	ldd		[$inp - 8], $in1	! load next input block
++	ldda		[$inp]0x82, $intail	! non-faulting load
++	add		$inp, $inc, $inp	! inp+=16
++
++	fmovd		%f0, %f4
++	faesencx	%f2, %f10, %f0
++	faesencx	%f4, %f12, %f2
++	ldd		[$key + 16], %f10	! round[1]
++	ldd		[$key + 24], %f12
++
++	fshiftorx	$in0, $in1, $fshift, $in0
++	fshiftorx	$in1, $intail, $fshift, $in1
++	fpadd32		$ctr1, $one, $ctr1	! increment counter
++
++	fmovd		%f0, %f4
++	faesenclx	%f2, %f6, %f0
++	faesenclx	%f4, %f8, %f2
++
++	brnz,pn		$oalign, .Lctr32_unaligned_out
++	nop
++
++	std		%f0, [$out + 0]
++	std		%f2, [$out + 8]
++	add		$out, 16, $out
++
++	brnz,a		$len, .Loop_ctr32
++	sub		$len, 1, $len
++
++.Lctr32_no_data:
++	ret
++	restore
++
++.align	32
++.Lctr32_unaligned_out:
++	ldd		[%o7 + $mask], $fshift	! shift right params
++	mov		0xff, $mask
++	srl		$mask, $oalign, $mask
++	sub		%g0, $ileft, $iright
++
++	fshiftorx	%f0, %f0, $fshift, %f6
++	fshiftorx	%f0, %f2, $fshift, %f8
++
++	stda		%f6, [$out + $mask]0xc0	! partial store
++	orn		%g0, $mask, $mask
++	std		%f8, [$out + 8]
++	add		$out, 16, $out
++	brz		$len, .Lctr32_unaligned_out_done
++	sub		$len, 1, $len
++	b		.Loop_ctr32_unaligned_out
++	nop
++
++.align	32
++.Loop_ctr32_unaligned_out:
++	fmovd		%f2, $outhead
++	fxor		$ctr0, $r0hi, %f0	! counter^round[0]
++	fxor		$ctr1, $r0lo, %f2
++	ldd		[$key + 32], %f6	! round[2]
++	ldd		[$key + 40], %f8
++
++	fmovd		%f0, %f4
++	faesencx	%f2, %f10, %f0
++	faesencx	%f4, %f12, %f2
++	ldd		[$key + 48], %f10	! round[3]
++	ldd		[$key + 56], %f12
++
++	ldx		[$inp - 16], %o0
++	ldx		[$inp -  8], %o1
++	brz		$ileft, .Lctr32_aligned_inp
++	movrz		$len, 0, $inc
++
++	ldx		[$inp], %o2
++	sllx		%o0, $ileft, %o0
++	srlx		%o1, $iright, %g1
++	sllx		%o1, $ileft, %o1
++	or		%g1, %o0, %o0
++	srlx		%o2, $iright, %o2
++	or		%o2, %o1, %o1
++
++.Lctr32_aligned_inp:
++	fmovd		%f0, %f4
++	faesencx	%f2, %f6, %f0
++	faesencx	%f4, %f8, %f2
++	ldd		[$key + 64], %f6	! round[4]
++	ldd		[$key + 72], %f8
++	add		$key, 64, $end
++	sub		$rounds, 16*8, $inner
++
++	stx		%o0, [%sp + LOCALS + 0]
++	stx		%o1, [%sp + LOCALS + 8]
++	add		$inp, $inc, $inp	! inp+=16
++	nop
++
++.Lctr32_enc_unaligned:
++	fmovd		%f0, %f4
++	faesencx	%f2, %f10, %f0
++	faesencx	%f4, %f12, %f2
++	ldd		[$end + 16], %f10
++	ldd		[$end + 24], %f12
++	add		$end, 32, $end
++
++	fmovd		%f0, %f4
++	faesencx	%f2, %f6, %f0
++	faesencx	%f4, %f8, %f2
++	ldd		[$end + 0], %f6
++	ldd		[$end + 8], %f8
++
++	brnz,a		$inner, .Lctr32_enc_unaligned
++	sub		$inner, 16*2, $inner
++
++	fmovd		%f0, %f4
++	faesencx	%f2, %f10, %f0
++	faesencx	%f4, %f12, %f2
++	ldd		[$end + 16], %f10	! round[last-1]
++	ldd		[$end + 24], %f12
++	fpadd32		$ctr1, $one, $ctr1	! increment counter
++
++	fmovd		%f0, %f4
++	faesencx	%f2, %f6, %f0
++	faesencx	%f4, %f8, %f2
++	fxor		$in0, $rlhi, %f6	! inp^round[last]
++	fxor		$in1, $rllo, %f8
++	ldd		[%sp + LOCALS + 0], $in0
++	ldd		[%sp + LOCALS + 8], $in1
++
++	fmovd		%f0, %f4
++	faesencx	%f2, %f10, %f0
++	faesencx	%f4, %f12, %f2
++	ldd		[$key + 16], %f10	! round[1]
++	ldd		[$key + 24], %f12
++
++	fmovd		%f0, %f4
++	faesenclx	%f2, %f6, %f0
++	faesenclx	%f4, %f8, %f2
++
++	fshiftorx	$outhead, %f0, $fshift, %f6
++	fshiftorx	%f0, %f2, $fshift, %f8
++	std		%f6, [$out + 0]
++	std		%f8, [$out + 8]
++	add		$out, 16, $out
++
++	brnz,a		$len, .Loop_ctr32_unaligned_out
++	sub		$len, 1, $len
++
++.Lctr32_unaligned_out_done:
++	fshiftorx	%f2, %f2, $fshift, %f8
++	stda		%f8, [$out + $mask]0xc0	! partial store
++
++	ret
++	restore
++.type	aes_fx_ctr32_encrypt_blocks,#function
++.size	aes_fx_ctr32_encrypt_blocks,.-aes_fx_ctr32_encrypt_blocks
++
++.align	32
++.Linp_align:		! fshiftorx parameters for left shift toward %rs1
++	.byte	0, 0, 64,  0,	0, 64,  0, -64
++	.byte	0, 0, 56,  8,	0, 56,  8, -56
++	.byte	0, 0, 48, 16,	0, 48, 16, -48
++	.byte	0, 0, 40, 24,	0, 40, 24, -40
++	.byte	0, 0, 32, 32,	0, 32, 32, -32
++	.byte	0, 0, 24, 40,	0, 24, 40, -24
++	.byte	0, 0, 16, 48,	0, 16, 48, -16
++	.byte	0, 0,  8, 56,	0,  8, 56, -8
++.Lout_align:		! fshiftorx parameters for right shift toward %rs2
++	.byte	0, 0,  0, 64,	0,  0, 64,   0
++	.byte	0, 0,  8, 56,	0,  8, 56,  -8
++	.byte	0, 0, 16, 48,	0, 16, 48, -16
++	.byte	0, 0, 24, 40,	0, 24, 40, -24
++	.byte	0, 0, 32, 32,	0, 32, 32, -32
++	.byte	0, 0, 40, 24,	0, 40, 24, -40
++	.byte	0, 0, 48, 16,	0, 48, 16, -48
++	.byte	0, 0, 56,  8,	0, 56,  8, -56
++.Lone:
++	.word	0, 1
++.asciz	"AES for Fujitsu SPARC64 X, CRYPTOGAMS by "
++.align	4
++___
++}
++# Purpose of these subroutines is to explicitly encode VIS instructions,
++# so that one can compile the module without having to specify VIS
++# extensions on compiler command line, e.g. -xarch=v9 vs. -xarch=v9a.
++# Idea is to reserve for option to produce "universal" binary and let
++# programmer detect if current CPU is VIS capable at run-time.
++sub unvis {
++my ($mnemonic,$rs1,$rs2,$rd)=@_;
++my ($ref,$opf);
++my %visopf = (	"faligndata"	=> 0x048,
++		"bshuffle"	=> 0x04c,
++		"fpadd32"	=> 0x052,
++		"fxor"		=> 0x06c,
++		"fsrc2"		=> 0x078	);
++
++    $ref = "$mnemonic\t$rs1,$rs2,$rd";
++
++    if ($opf=$visopf{$mnemonic}) {
++	foreach ($rs1,$rs2,$rd) {
++	    return $ref if (!/%f([0-9]{1,2})/);
++	    $_=$1;
++	    if ($1>=32) {
++		return $ref if ($1&1);
++		# re-encode for upper double register addressing
++		$_=($1|$1>>5)&31;
++	    }
++	}
++
++	return	sprintf ".word\t0x%08x !%s",
++			0x81b00000|$rd<<25|$rs1<<14|$opf<<5|$rs2,
++			$ref;
++    } else {
++	return $ref;
++    }
++}
++
++sub unvis3 {
++my ($mnemonic,$rs1,$rs2,$rd)=@_;
++my %bias = ( "g" => 0, "o" => 8, "l" => 16, "i" => 24 );
++my ($ref,$opf);
++my %visopf = (	"alignaddr"	=> 0x018,
++		"bmask"		=> 0x019,
++		"alignaddrl"	=> 0x01a	);
++
++    $ref = "$mnemonic\t$rs1,$rs2,$rd";
++
++    if ($opf=$visopf{$mnemonic}) {
++	foreach ($rs1,$rs2,$rd) {
++	    return $ref if (!/%([goli])([0-9])/);
++	    $_=$bias{$1}+$2;
++	}
++
++	return	sprintf ".word\t0x%08x !%s",
++			0x81b00000|$rd<<25|$rs1<<14|$opf<<5|$rs2,
++			$ref;
++    } else {
++	return $ref;
++    }
++}
++
++sub unfx {
++my ($mnemonic,$rs1,$rs2,$rd)=@_;
++my ($ref,$opf);
++my %aesopf = (	"faesencx"	=> 0x90,
++		"faesdecx"	=> 0x91,
++		"faesenclx"	=> 0x92,
++		"faesdeclx"	=> 0x93,
++		"faeskeyx"	=> 0x94	);
++
++    $ref = "$mnemonic\t$rs1,$rs2,$rd";
++
++    if (defined($opf=$aesopf{$mnemonic})) {
++	$rs2 = ($rs2 =~ /%f([0-6]*[02468])/) ? (($1|$1>>5)&31) : $rs2;
++	$rs2 = oct($rs2) if ($rs2 =~ /^0/);
++
++	foreach ($rs1,$rd) {
++	    return $ref if (!/%f([0-9]{1,2})/);
++	    $_=$1;
++	    if ($1>=32) {
++		return $ref if ($1&1);
++		# re-encode for upper double register addressing
++		$_=($1|$1>>5)&31;
++	    }
++	}
++
++	return	sprintf ".word\t0x%08x !%s",
++			2<<30|$rd<<25|0x36<<19|$rs1<<14|$opf<<5|$rs2,
++			$ref;
++    } else {
++	return $ref;
++    }
++}
++
++sub unfx3src {
++my ($mnemonic,$rs1,$rs2,$rs3,$rd)=@_;
++my ($ref,$opf);
++my %aesopf = (	"fshiftorx"	=> 0x0b	);
++
++    $ref = "$mnemonic\t$rs1,$rs2,$rs3,$rd";
++
++    if (defined($opf=$aesopf{$mnemonic})) {
++	foreach ($rs1,$rs2,$rs3,$rd) {
++	    return $ref if (!/%f([0-9]{1,2})/);
++	    $_=$1;
++	    if ($1>=32) {
++		return $ref if ($1&1);
++		# re-encode for upper double register addressing
++		$_=($1|$1>>5)&31;
++	    }
++	}
++
++	return	sprintf ".word\t0x%08x !%s",
++			2<<30|$rd<<25|0x37<<19|$rs1<<14|$rs3<<9|$opf<<5|$rs2,
++			$ref;
++    } else {
++	return $ref;
++    }
++}
++
++foreach (split("\n",$code)) {
++    s/\`([^\`]*)\`/eval $1/ge;
++
++    s/%f([0-9]+)#lo/sprintf "%%f%d",$1+1/ge;
++
++    s/\b(faes[^x]{3,4}x)\s+(%f[0-9]{1,2}),\s*([%fx0-9]+),\s*(%f[0-9]{1,2})/
++		&unfx($1,$2,$3,$4)
++     /ge or
++    s/\b([f][^\s]*)\s+(%f[0-9]{1,2}),\s*(%f[0-9]{1,2}),\s*(%f[0-9]{1,2}),\s*(%f[0-9]{1,2})/
++		&unfx3src($1,$2,$3,$4,$5)
++     /ge or
++    s/\b([fb][^\s]*)\s+(%f[0-9]{1,2}),\s*(%f[0-9]{1,2}),\s*(%f[0-9]{1,2})/
++		&unvis($1,$2,$3,$4)
++     /ge or
++    s/\b(alignaddr[l]*)\s+(%[goli][0-7]),\s*(%[goli][0-7]),\s*(%[goli][0-7])/
++		&unvis3($1,$2,$3,$4)
++     /ge;
++    print $_,"\n";
++}
++
++close STDOUT;
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/aes/asm/aesni-mb-x86_64.pl b/CryptoPkg/Library/OpensslLib/openssl/crypto/aes/asm/aesni-mb-x86_64.pl
+new file mode 100644
+index 0000000..aa2735e
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/aes/asm/aesni-mb-x86_64.pl
+@@ -0,0 +1,1402 @@
++#! /usr/bin/env perl
++# Copyright 2013-2016 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
++# in the file LICENSE in the source distribution or at
++# https://www.openssl.org/source/license.html
++
++
++# ====================================================================
++# Written by Andy Polyakov  for the OpenSSL
++# project. The module is, however, dual licensed under OpenSSL and
++# CRYPTOGAMS licenses depending on where you obtain it. For further
++# details see http://www.openssl.org/~appro/cryptogams/.
++# ====================================================================
++
++# Multi-buffer AES-NI procedures process several independent buffers
++# in parallel by interleaving independent instructions.
++#
++# Cycles per byte for interleave factor 4:
++#
++#			asymptotic	measured
++#			---------------------------
++# Westmere		5.00/4=1.25	5.13/4=1.28
++# Atom			15.0/4=3.75	?15.7/4=3.93
++# Sandy Bridge		5.06/4=1.27	5.18/4=1.29
++# Ivy Bridge		5.06/4=1.27	5.14/4=1.29
++# Haswell		4.44/4=1.11	4.44/4=1.11
++# Bulldozer		5.75/4=1.44	5.76/4=1.44
++#
++# Cycles per byte for interleave factor 8 (not implemented for
++# pre-AVX processors, where higher interleave factor incidentally
++# doesn't result in improvement):
++#
++#			asymptotic	measured
++#			---------------------------
++# Sandy Bridge		5.06/8=0.64	7.10/8=0.89(*)
++# Ivy Bridge		5.06/8=0.64	7.14/8=0.89(*)
++# Haswell		5.00/8=0.63	5.00/8=0.63
++# Bulldozer		5.75/8=0.72	5.77/8=0.72
++#
++# (*)	Sandy/Ivy Bridge are known to handle high interleave factors
++#	suboptimally;
++
++$flavour = shift;
++$output  = shift;
++if ($flavour =~ /\./) { $output = $flavour; undef $flavour; }
++
++$win64=0; $win64=1 if ($flavour =~ /[nm]asm|mingw64/ || $output =~ /\.asm$/);
++
++$0 =~ m/(.*[\/\\])[^\/\\]+$/; $dir=$1;
++( $xlate="${dir}x86_64-xlate.pl" and -f $xlate ) or
++( $xlate="${dir}../../perlasm/x86_64-xlate.pl" and -f $xlate) or
++die "can't locate x86_64-xlate.pl";
++
++$avx=0;
++
++if (`$ENV{CC} -Wa,-v -c -o /dev/null -x assembler /dev/null 2>&1`
++		=~ /GNU assembler version ([2-9]\.[0-9]+)/) {
++	$avx = ($1>=2.19) + ($1>=2.22);
++}
++
++if (!$avx && $win64 && ($flavour =~ /nasm/ || $ENV{ASM} =~ /nasm/) &&
++	   `nasm -v 2>&1` =~ /NASM version ([2-9]\.[0-9]+)/) {
++	$avx = ($1>=2.09) + ($1>=2.10);
++}
++
++if (!$avx && $win64 && ($flavour =~ /masm/ || $ENV{ASM} =~ /ml64/) &&
++	   `ml64 2>&1` =~ /Version ([0-9]+)\./) {
++	$avx = ($1>=10) + ($1>=11);
++}
++
++if (!$avx && `$ENV{CC} -v 2>&1` =~ /((?:^clang|LLVM) version|.*based on LLVM) ([3-9]\.[0-9]+)/) {
++	$avx = ($2>=3.0) + ($2>3.0);
++}
++
++open OUT,"| \"$^X\" \"$xlate\" $flavour \"$output\"";
++*STDOUT=*OUT;
++
++# void aesni_multi_cbc_encrypt (
++#     struct {	void *inp,*out; int blocks; double iv[2]; } inp[8];
++#     const AES_KEY *key,
++#     int num);		/* 1 or 2 */
++#
++$inp="%rdi";	# 1st arg
++$key="%rsi";	# 2nd arg
++$num="%edx";
++
++@inptr=map("%r$_",(8..11));
++@outptr=map("%r$_",(12..15));
++
++($rndkey0,$rndkey1)=("%xmm0","%xmm1");
++@out=map("%xmm$_",(2..5));
++@inp=map("%xmm$_",(6..9));
++($counters,$mask,$zero)=map("%xmm$_",(10..12));
++
++($rounds,$one,$sink,$offset)=("%eax","%ecx","%rbp","%rbx");
++
++$code.=<<___;
++.text
++
++.extern	OPENSSL_ia32cap_P
++
++.globl	aesni_multi_cbc_encrypt
++.type	aesni_multi_cbc_encrypt,\@function,3
++.align	32
++aesni_multi_cbc_encrypt:
++___
++$code.=<<___ if ($avx);
++	cmp	\$2,$num
++	jb	.Lenc_non_avx
++	mov	OPENSSL_ia32cap_P+4(%rip),%ecx
++	test	\$`1<<28`,%ecx			# AVX bit
++	jnz	_avx_cbc_enc_shortcut
++	jmp	.Lenc_non_avx
++.align	16
++.Lenc_non_avx:
++___
++$code.=<<___;
++	mov	%rsp,%rax
++	push	%rbx
++	push	%rbp
++	push	%r12
++	push	%r13
++	push	%r14
++	push	%r15
++___
++$code.=<<___ if ($win64);
++	lea	-0xa8(%rsp),%rsp
++	movaps	%xmm6,(%rsp)
++	movaps	%xmm7,0x10(%rsp)
++	movaps	%xmm8,0x20(%rsp)
++	movaps	%xmm9,0x30(%rsp)
++	movaps	%xmm10,0x40(%rsp)
++	movaps	%xmm11,0x50(%rsp)
++	movaps	%xmm12,0x60(%rsp)
++	movaps	%xmm13,-0x68(%rax)	# not used, saved to share se_handler 
++	movaps	%xmm14,-0x58(%rax)
++	movaps	%xmm15,-0x48(%rax)
++___
++$code.=<<___;
++	# stack layout
++	#
++	# +0	output sink
++	# +16	input sink [original %rsp and $num]
++	# +32	counters
++
++	sub	\$48,%rsp
++	and	\$-64,%rsp
++	mov	%rax,16(%rsp)			# original %rsp
++
++.Lenc4x_body:
++	movdqu	($key),$zero			# 0-round key
++	lea	0x78($key),$key			# size optimization
++	lea	40*2($inp),$inp
++
++.Lenc4x_loop_grande:
++	mov	$num,24(%rsp)			# original $num
++	xor	$num,$num
++___
++for($i=0;$i<4;$i++) {
++    $code.=<<___;
++	mov	`40*$i+16-40*2`($inp),$one	# borrow $one for number of blocks
++	mov	`40*$i+0-40*2`($inp),@inptr[$i]
++	cmp	$num,$one
++	mov	`40*$i+8-40*2`($inp),@outptr[$i]
++	cmovg	$one,$num			# find maximum
++	test	$one,$one
++	movdqu	`40*$i+24-40*2`($inp),@out[$i]	# load IV
++	mov	$one,`32+4*$i`(%rsp)		# initialize counters
++	cmovle	%rsp,@inptr[$i]			# cancel input
++___
++}
++$code.=<<___;
++	test	$num,$num
++	jz	.Lenc4x_done
++
++	movups	0x10-0x78($key),$rndkey1
++	 pxor	$zero,@out[0]
++	movups	0x20-0x78($key),$rndkey0
++	 pxor	$zero,@out[1]
++	mov	0xf0-0x78($key),$rounds
++	 pxor	$zero,@out[2]
++	movdqu	(@inptr[0]),@inp[0]		# load inputs
++	 pxor	$zero,@out[3]
++	movdqu	(@inptr[1]),@inp[1]
++	 pxor	@inp[0],@out[0]
++	movdqu	(@inptr[2]),@inp[2]
++	 pxor	@inp[1],@out[1]
++	movdqu	(@inptr[3]),@inp[3]
++	 pxor	@inp[2],@out[2]
++	 pxor	@inp[3],@out[3]
++	movdqa	32(%rsp),$counters		# load counters
++	xor	$offset,$offset
++	jmp	.Loop_enc4x
++
++.align	32
++.Loop_enc4x:
++	add	\$16,$offset
++	lea	16(%rsp),$sink			# sink pointer
++	mov	\$1,$one			# constant of 1
++	sub	$offset,$sink
++
++	aesenc		$rndkey1,@out[0]
++	prefetcht0	31(@inptr[0],$offset)	# prefetch input
++	prefetcht0	31(@inptr[1],$offset)
++	aesenc		$rndkey1,@out[1]
++	prefetcht0	31(@inptr[2],$offset)
++	prefetcht0	31(@inptr[2],$offset)
++	aesenc		$rndkey1,@out[2]
++	aesenc		$rndkey1,@out[3]
++	movups		0x30-0x78($key),$rndkey1
++___
++for($i=0;$i<4;$i++) {
++my $rndkey = ($i&1) ? $rndkey1 : $rndkey0;
++$code.=<<___;
++	 cmp		`32+4*$i`(%rsp),$one
++	aesenc		$rndkey,@out[0]
++	aesenc		$rndkey,@out[1]
++	aesenc		$rndkey,@out[2]
++	 cmovge		$sink,@inptr[$i]	# cancel input
++	 cmovg		$sink,@outptr[$i]	# sink output
++	aesenc		$rndkey,@out[3]
++	movups		`0x40+16*$i-0x78`($key),$rndkey
++___
++}
++$code.=<<___;
++	 movdqa		$counters,$mask
++	aesenc		$rndkey0,@out[0]
++	prefetcht0	15(@outptr[0],$offset)	# prefetch output
++	prefetcht0	15(@outptr[1],$offset)
++	aesenc		$rndkey0,@out[1]
++	prefetcht0	15(@outptr[2],$offset)
++	prefetcht0	15(@outptr[3],$offset)
++	aesenc		$rndkey0,@out[2]
++	aesenc		$rndkey0,@out[3]
++	movups		0x80-0x78($key),$rndkey0
++	 pxor		$zero,$zero
++
++	aesenc		$rndkey1,@out[0]
++	 pcmpgtd	$zero,$mask
++	 movdqu		-0x78($key),$zero	# reload 0-round key
++	aesenc		$rndkey1,@out[1]
++	 paddd		$mask,$counters		# decrement counters
++	 movdqa		$counters,32(%rsp)	# update counters
++	aesenc		$rndkey1,@out[2]
++	aesenc		$rndkey1,@out[3]
++	movups		0x90-0x78($key),$rndkey1
++
++	cmp	\$11,$rounds
++
++	aesenc		$rndkey0,@out[0]
++	aesenc		$rndkey0,@out[1]
++	aesenc		$rndkey0,@out[2]
++	aesenc		$rndkey0,@out[3]
++	movups		0xa0-0x78($key),$rndkey0
++
++	jb	.Lenc4x_tail
++
++	aesenc		$rndkey1,@out[0]
++	aesenc		$rndkey1,@out[1]
++	aesenc		$rndkey1,@out[2]
++	aesenc		$rndkey1,@out[3]
++	movups		0xb0-0x78($key),$rndkey1
++
++	aesenc		$rndkey0,@out[0]
++	aesenc		$rndkey0,@out[1]
++	aesenc		$rndkey0,@out[2]
++	aesenc		$rndkey0,@out[3]
++	movups		0xc0-0x78($key),$rndkey0
++
++	je	.Lenc4x_tail
++
++	aesenc		$rndkey1,@out[0]
++	aesenc		$rndkey1,@out[1]
++	aesenc		$rndkey1,@out[2]
++	aesenc		$rndkey1,@out[3]
++	movups		0xd0-0x78($key),$rndkey1
++
++	aesenc		$rndkey0,@out[0]
++	aesenc		$rndkey0,@out[1]
++	aesenc		$rndkey0,@out[2]
++	aesenc		$rndkey0,@out[3]
++	movups		0xe0-0x78($key),$rndkey0
++	jmp	.Lenc4x_tail
++
++.align	32
++.Lenc4x_tail:
++	aesenc		$rndkey1,@out[0]
++	aesenc		$rndkey1,@out[1]
++	aesenc		$rndkey1,@out[2]
++	aesenc		$rndkey1,@out[3]
++	 movdqu		(@inptr[0],$offset),@inp[0]
++	movdqu		0x10-0x78($key),$rndkey1
++
++	aesenclast	$rndkey0,@out[0]
++	 movdqu		(@inptr[1],$offset),@inp[1]
++	 pxor		$zero,@inp[0]
++	aesenclast	$rndkey0,@out[1]
++	 movdqu		(@inptr[2],$offset),@inp[2]
++	 pxor		$zero,@inp[1]
++	aesenclast	$rndkey0,@out[2]
++	 movdqu		(@inptr[3],$offset),@inp[3]
++	 pxor		$zero,@inp[2]
++	aesenclast	$rndkey0,@out[3]
++	movdqu		0x20-0x78($key),$rndkey0
++	 pxor		$zero,@inp[3]
++
++	movups		@out[0],-16(@outptr[0],$offset)
++	 pxor		@inp[0],@out[0]
++	movups		@out[1],-16(@outptr[1],$offset)	
++	 pxor		@inp[1],@out[1]
++	movups		@out[2],-16(@outptr[2],$offset)	
++	 pxor		@inp[2],@out[2]
++	movups		@out[3],-16(@outptr[3],$offset)
++	 pxor		@inp[3],@out[3]
++
++	dec	$num
++	jnz	.Loop_enc4x
++
++	mov	16(%rsp),%rax			# original %rsp
++	mov	24(%rsp),$num
++
++	#pxor	@inp[0],@out[0]
++	#pxor	@inp[1],@out[1]
++	#movdqu	@out[0],`40*0+24-40*2`($inp)	# output iv FIX ME!
++	#pxor	@inp[2],@out[2]
++	#movdqu	@out[1],`40*1+24-40*2`($inp)
++	#pxor	@inp[3],@out[3]
++	#movdqu	@out[2],`40*2+24-40*2`($inp)	# won't fix, let caller
++	#movdqu	@out[3],`40*3+24-40*2`($inp)	# figure this out...
++
++	lea	`40*4`($inp),$inp
++	dec	$num
++	jnz	.Lenc4x_loop_grande
++
++.Lenc4x_done:
++___
++$code.=<<___ if ($win64);
++	movaps	-0xd8(%rax),%xmm6
++	movaps	-0xc8(%rax),%xmm7
++	movaps	-0xb8(%rax),%xmm8
++	movaps	-0xa8(%rax),%xmm9
++	movaps	-0x98(%rax),%xmm10
++	movaps	-0x88(%rax),%xmm11
++	movaps	-0x78(%rax),%xmm12
++	#movaps	-0x68(%rax),%xmm13
++	#movaps	-0x58(%rax),%xmm14
++	#movaps	-0x48(%rax),%xmm15
++___
++$code.=<<___;
++	mov	-48(%rax),%r15
++	mov	-40(%rax),%r14
++	mov	-32(%rax),%r13
++	mov	-24(%rax),%r12
++	mov	-16(%rax),%rbp
++	mov	-8(%rax),%rbx
++	lea	(%rax),%rsp
++.Lenc4x_epilogue:
++	ret
++.size	aesni_multi_cbc_encrypt,.-aesni_multi_cbc_encrypt
++
++.globl	aesni_multi_cbc_decrypt
++.type	aesni_multi_cbc_decrypt,\@function,3
++.align	32
++aesni_multi_cbc_decrypt:
++___
++$code.=<<___ if ($avx);
++	cmp	\$2,$num
++	jb	.Ldec_non_avx
++	mov	OPENSSL_ia32cap_P+4(%rip),%ecx
++	test	\$`1<<28`,%ecx			# AVX bit
++	jnz	_avx_cbc_dec_shortcut
++	jmp	.Ldec_non_avx
++.align	16
++.Ldec_non_avx:
++___
++$code.=<<___;
++	mov	%rsp,%rax
++	push	%rbx
++	push	%rbp
++	push	%r12
++	push	%r13
++	push	%r14
++	push	%r15
++___
++$code.=<<___ if ($win64);
++	lea	-0xa8(%rsp),%rsp
++	movaps	%xmm6,(%rsp)
++	movaps	%xmm7,0x10(%rsp)
++	movaps	%xmm8,0x20(%rsp)
++	movaps	%xmm9,0x30(%rsp)
++	movaps	%xmm10,0x40(%rsp)
++	movaps	%xmm11,0x50(%rsp)
++	movaps	%xmm12,0x60(%rsp)
++	movaps	%xmm13,-0x68(%rax)	# not used, saved to share se_handler 
++	movaps	%xmm14,-0x58(%rax)
++	movaps	%xmm15,-0x48(%rax)
++___
++$code.=<<___;
++	# stack layout
++	#
++	# +0	output sink
++	# +16	input sink [original %rsp and $num]
++	# +32	counters
++
++	sub	\$48,%rsp
++	and	\$-64,%rsp
++	mov	%rax,16(%rsp)			# original %rsp
++
++.Ldec4x_body:
++	movdqu	($key),$zero			# 0-round key
++	lea	0x78($key),$key			# size optimization
++	lea	40*2($inp),$inp
++
++.Ldec4x_loop_grande:
++	mov	$num,24(%rsp)			# original $num
++	xor	$num,$num
++___
++for($i=0;$i<4;$i++) {
++    $code.=<<___;
++	mov	`40*$i+16-40*2`($inp),$one	# borrow $one for number of blocks
++	mov	`40*$i+0-40*2`($inp),@inptr[$i]
++	cmp	$num,$one
++	mov	`40*$i+8-40*2`($inp),@outptr[$i]
++	cmovg	$one,$num			# find maximum
++	test	$one,$one
++	movdqu	`40*$i+24-40*2`($inp),@inp[$i]	# load IV
++	mov	$one,`32+4*$i`(%rsp)		# initialize counters
++	cmovle	%rsp,@inptr[$i]			# cancel input
++___
++}
++$code.=<<___;
++	test	$num,$num
++	jz	.Ldec4x_done
++
++	movups	0x10-0x78($key),$rndkey1
++	movups	0x20-0x78($key),$rndkey0
++	mov	0xf0-0x78($key),$rounds
++	movdqu	(@inptr[0]),@out[0]		# load inputs
++	movdqu	(@inptr[1]),@out[1]
++	 pxor	$zero,@out[0]
++	movdqu	(@inptr[2]),@out[2]
++	 pxor	$zero,@out[1]
++	movdqu	(@inptr[3]),@out[3]
++	 pxor	$zero,@out[2]
++	 pxor	$zero,@out[3]
++	movdqa	32(%rsp),$counters		# load counters
++	xor	$offset,$offset
++	jmp	.Loop_dec4x
++
++.align	32
++.Loop_dec4x:
++	add	\$16,$offset
++	lea	16(%rsp),$sink			# sink pointer
++	mov	\$1,$one			# constant of 1
++	sub	$offset,$sink
++
++	aesdec		$rndkey1,@out[0]
++	prefetcht0	31(@inptr[0],$offset)	# prefetch input
++	prefetcht0	31(@inptr[1],$offset)
++	aesdec		$rndkey1,@out[1]
++	prefetcht0	31(@inptr[2],$offset)
++	prefetcht0	31(@inptr[3],$offset)
++	aesdec		$rndkey1,@out[2]
++	aesdec		$rndkey1,@out[3]
++	movups		0x30-0x78($key),$rndkey1
++___
++for($i=0;$i<4;$i++) {
++my $rndkey = ($i&1) ? $rndkey1 : $rndkey0;
++$code.=<<___;
++	 cmp		`32+4*$i`(%rsp),$one
++	aesdec		$rndkey,@out[0]
++	aesdec		$rndkey,@out[1]
++	aesdec		$rndkey,@out[2]
++	 cmovge		$sink,@inptr[$i]	# cancel input
++	 cmovg		$sink,@outptr[$i]	# sink output
++	aesdec		$rndkey,@out[3]
++	movups		`0x40+16*$i-0x78`($key),$rndkey
++___
++}
++$code.=<<___;
++	 movdqa		$counters,$mask
++	aesdec		$rndkey0,@out[0]
++	prefetcht0	15(@outptr[0],$offset)	# prefetch output
++	prefetcht0	15(@outptr[1],$offset)
++	aesdec		$rndkey0,@out[1]
++	prefetcht0	15(@outptr[2],$offset)
++	prefetcht0	15(@outptr[3],$offset)
++	aesdec		$rndkey0,@out[2]
++	aesdec		$rndkey0,@out[3]
++	movups		0x80-0x78($key),$rndkey0
++	 pxor		$zero,$zero
++
++	aesdec		$rndkey1,@out[0]
++	 pcmpgtd	$zero,$mask
++	 movdqu		-0x78($key),$zero	# reload 0-round key
++	aesdec		$rndkey1,@out[1]
++	 paddd		$mask,$counters		# decrement counters
++	 movdqa		$counters,32(%rsp)	# update counters
++	aesdec		$rndkey1,@out[2]
++	aesdec		$rndkey1,@out[3]
++	movups		0x90-0x78($key),$rndkey1
++
++	cmp	\$11,$rounds
++
++	aesdec		$rndkey0,@out[0]
++	aesdec		$rndkey0,@out[1]
++	aesdec		$rndkey0,@out[2]
++	aesdec		$rndkey0,@out[3]
++	movups		0xa0-0x78($key),$rndkey0
++
++	jb	.Ldec4x_tail
++
++	aesdec		$rndkey1,@out[0]
++	aesdec		$rndkey1,@out[1]
++	aesdec		$rndkey1,@out[2]
++	aesdec		$rndkey1,@out[3]
++	movups		0xb0-0x78($key),$rndkey1
++
++	aesdec		$rndkey0,@out[0]
++	aesdec		$rndkey0,@out[1]
++	aesdec		$rndkey0,@out[2]
++	aesdec		$rndkey0,@out[3]
++	movups		0xc0-0x78($key),$rndkey0
++
++	je	.Ldec4x_tail
++
++	aesdec		$rndkey1,@out[0]
++	aesdec		$rndkey1,@out[1]
++	aesdec		$rndkey1,@out[2]
++	aesdec		$rndkey1,@out[3]
++	movups		0xd0-0x78($key),$rndkey1
++
++	aesdec		$rndkey0,@out[0]
++	aesdec		$rndkey0,@out[1]
++	aesdec		$rndkey0,@out[2]
++	aesdec		$rndkey0,@out[3]
++	movups		0xe0-0x78($key),$rndkey0
++	jmp	.Ldec4x_tail
++
++.align	32
++.Ldec4x_tail:
++	aesdec		$rndkey1,@out[0]
++	aesdec		$rndkey1,@out[1]
++	aesdec		$rndkey1,@out[2]
++	 pxor		$rndkey0,@inp[0]
++	 pxor		$rndkey0,@inp[1]
++	aesdec		$rndkey1,@out[3]
++	movdqu		0x10-0x78($key),$rndkey1
++	 pxor		$rndkey0,@inp[2]
++	 pxor		$rndkey0,@inp[3]
++	movdqu		0x20-0x78($key),$rndkey0
++
++	aesdeclast	@inp[0],@out[0]
++	aesdeclast	@inp[1],@out[1]
++	 movdqu		-16(@inptr[0],$offset),@inp[0]	# load next IV
++	 movdqu		-16(@inptr[1],$offset),@inp[1]
++	aesdeclast	@inp[2],@out[2]
++	aesdeclast	@inp[3],@out[3]
++	 movdqu		-16(@inptr[2],$offset),@inp[2]
++	 movdqu		-16(@inptr[3],$offset),@inp[3]
++
++	movups		@out[0],-16(@outptr[0],$offset)
++	 movdqu		(@inptr[0],$offset),@out[0]
++	movups		@out[1],-16(@outptr[1],$offset)	
++	 movdqu		(@inptr[1],$offset),@out[1]
++	 pxor		$zero,@out[0]
++	movups		@out[2],-16(@outptr[2],$offset)	
++	 movdqu		(@inptr[2],$offset),@out[2]
++	 pxor		$zero,@out[1]
++	movups		@out[3],-16(@outptr[3],$offset)
++	 movdqu		(@inptr[3],$offset),@out[3]
++	 pxor		$zero,@out[2]
++	 pxor		$zero,@out[3]
++
++	dec	$num
++	jnz	.Loop_dec4x
++
++	mov	16(%rsp),%rax			# original %rsp
++	mov	24(%rsp),$num
++
++	lea	`40*4`($inp),$inp
++	dec	$num
++	jnz	.Ldec4x_loop_grande
++
++.Ldec4x_done:
++___
++$code.=<<___ if ($win64);
++	movaps	-0xd8(%rax),%xmm6
++	movaps	-0xc8(%rax),%xmm7
++	movaps	-0xb8(%rax),%xmm8
++	movaps	-0xa8(%rax),%xmm9
++	movaps	-0x98(%rax),%xmm10
++	movaps	-0x88(%rax),%xmm11
++	movaps	-0x78(%rax),%xmm12
++	#movaps	-0x68(%rax),%xmm13
++	#movaps	-0x58(%rax),%xmm14
++	#movaps	-0x48(%rax),%xmm15
++___
++$code.=<<___;
++	mov	-48(%rax),%r15
++	mov	-40(%rax),%r14
++	mov	-32(%rax),%r13
++	mov	-24(%rax),%r12
++	mov	-16(%rax),%rbp
++	mov	-8(%rax),%rbx
++	lea	(%rax),%rsp
++.Ldec4x_epilogue:
++	ret
++.size	aesni_multi_cbc_decrypt,.-aesni_multi_cbc_decrypt
++___
++
++						if ($avx) {{{
++my @ptr=map("%r$_",(8..15));
++my $offload=$sink;
++
++my @out=map("%xmm$_",(2..9));
++my @inp=map("%xmm$_",(10..13));
++my ($counters,$zero)=("%xmm14","%xmm15");
++
++$code.=<<___;
++.type	aesni_multi_cbc_encrypt_avx,\@function,3
++.align	32
++aesni_multi_cbc_encrypt_avx:
++_avx_cbc_enc_shortcut:
++	mov	%rsp,%rax
++	push	%rbx
++	push	%rbp
++	push	%r12
++	push	%r13
++	push	%r14
++	push	%r15
++___
++$code.=<<___ if ($win64);
++	lea	-0xa8(%rsp),%rsp
++	movaps	%xmm6,(%rsp)
++	movaps	%xmm7,0x10(%rsp)
++	movaps	%xmm8,0x20(%rsp)
++	movaps	%xmm9,0x30(%rsp)
++	movaps	%xmm10,0x40(%rsp)
++	movaps	%xmm11,0x50(%rsp)
++	movaps	%xmm12,-0x78(%rax)
++	movaps	%xmm13,-0x68(%rax)
++	movaps	%xmm14,-0x58(%rax)
++	movaps	%xmm15,-0x48(%rax)
++___
++$code.=<<___;
++	# stack layout
++	#
++	# +0	output sink
++	# +16	input sink [original %rsp and $num]
++	# +32	counters
++	# +64	distances between inputs and outputs
++	# +128	off-load area for @inp[0..3]
++
++	sub	\$192,%rsp
++	and	\$-128,%rsp
++	mov	%rax,16(%rsp)			# original %rsp
++
++.Lenc8x_body:
++	vzeroupper
++	vmovdqu	($key),$zero			# 0-round key
++	lea	0x78($key),$key			# size optimization
++	lea	40*4($inp),$inp
++	shr	\$1,$num
++
++.Lenc8x_loop_grande:
++	#mov	$num,24(%rsp)			# original $num
++	xor	$num,$num
++___
++for($i=0;$i<8;$i++) {
++  my $temp = $i ? $offload : $offset;
++    $code.=<<___;
++	mov	`40*$i+16-40*4`($inp),$one	# borrow $one for number of blocks
++	mov	`40*$i+0-40*4`($inp),@ptr[$i]	# input pointer
++	cmp	$num,$one
++	mov	`40*$i+8-40*4`($inp),$temp	# output pointer
++	cmovg	$one,$num			# find maximum
++	test	$one,$one
++	vmovdqu	`40*$i+24-40*4`($inp),@out[$i]	# load IV
++	mov	$one,`32+4*$i`(%rsp)		# initialize counters
++	cmovle	%rsp,@ptr[$i]			# cancel input
++	sub	@ptr[$i],$temp			# distance between input and output
++	mov	$temp,`64+8*$i`(%rsp)		# initialize distances
++___
++}
++$code.=<<___;
++	test	$num,$num
++	jz	.Lenc8x_done
++
++	vmovups	0x10-0x78($key),$rndkey1
++	vmovups	0x20-0x78($key),$rndkey0
++	mov	0xf0-0x78($key),$rounds
++
++	vpxor	(@ptr[0]),$zero,@inp[0]		# load inputs and xor with 0-round
++	 lea	128(%rsp),$offload		# offload area
++	vpxor	(@ptr[1]),$zero,@inp[1]
++	vpxor	(@ptr[2]),$zero,@inp[2]
++	vpxor	(@ptr[3]),$zero,@inp[3]
++	 vpxor	@inp[0],@out[0],@out[0]
++	vpxor	(@ptr[4]),$zero,@inp[0]
++	 vpxor	@inp[1],@out[1],@out[1]
++	vpxor	(@ptr[5]),$zero,@inp[1]
++	 vpxor	@inp[2],@out[2],@out[2]
++	vpxor	(@ptr[6]),$zero,@inp[2]
++	 vpxor	@inp[3],@out[3],@out[3]
++	vpxor	(@ptr[7]),$zero,@inp[3]
++	 vpxor	@inp[0],@out[4],@out[4]
++	mov	\$1,$one			# constant of 1
++	 vpxor	@inp[1],@out[5],@out[5]
++	 vpxor	@inp[2],@out[6],@out[6]
++	 vpxor	@inp[3],@out[7],@out[7]
++	jmp	.Loop_enc8x
++
++.align	32
++.Loop_enc8x:
++___
++for($i=0;$i<8;$i++) {
++my $rndkey=($i&1)?$rndkey0:$rndkey1;
++$code.=<<___;
++	vaesenc		$rndkey,@out[0],@out[0]
++	 cmp		32+4*$i(%rsp),$one
++___
++$code.=<<___ if ($i);
++	 mov		64+8*$i(%rsp),$offset
++___
++$code.=<<___;
++	vaesenc		$rndkey,@out[1],@out[1]
++	prefetcht0	31(@ptr[$i])			# prefetch input
++	vaesenc		$rndkey,@out[2],@out[2]
++___
++$code.=<<___ if ($i>1);
++	prefetcht0	15(@ptr[$i-2])			# prefetch output
++___
++$code.=<<___;
++	vaesenc		$rndkey,@out[3],@out[3]
++	 lea		(@ptr[$i],$offset),$offset
++	 cmovge		%rsp,@ptr[$i]			# cancel input
++	vaesenc		$rndkey,@out[4],@out[4]
++	 cmovg		%rsp,$offset			# sink output
++	vaesenc		$rndkey,@out[5],@out[5]
++	 sub		@ptr[$i],$offset
++	vaesenc		$rndkey,@out[6],@out[6]
++	 vpxor		16(@ptr[$i]),$zero,@inp[$i%4]	# load input and xor with 0-round
++	 mov		$offset,64+8*$i(%rsp)
++	vaesenc		$rndkey,@out[7],@out[7]
++	vmovups		`16*(3+$i)-0x78`($key),$rndkey
++	 lea		16(@ptr[$i],$offset),@ptr[$i]	# switch to output
++___
++$code.=<<___ if ($i<4)
++	 vmovdqu	@inp[$i%4],`16*$i`($offload)	# off-load
++___
++}
++$code.=<<___;
++	 vmovdqu	32(%rsp),$counters
++	prefetcht0	15(@ptr[$i-2])			# prefetch output
++	prefetcht0	15(@ptr[$i-1])
++	cmp	\$11,$rounds
++	jb	.Lenc8x_tail
++
++	vaesenc		$rndkey1,@out[0],@out[0]
++	vaesenc		$rndkey1,@out[1],@out[1]
++	vaesenc		$rndkey1,@out[2],@out[2]
++	vaesenc		$rndkey1,@out[3],@out[3]
++	vaesenc		$rndkey1,@out[4],@out[4]
++	vaesenc		$rndkey1,@out[5],@out[5]
++	vaesenc		$rndkey1,@out[6],@out[6]
++	vaesenc		$rndkey1,@out[7],@out[7]
++	vmovups		0xb0-0x78($key),$rndkey1
++
++	vaesenc		$rndkey0,@out[0],@out[0]
++	vaesenc		$rndkey0,@out[1],@out[1]
++	vaesenc		$rndkey0,@out[2],@out[2]
++	vaesenc		$rndkey0,@out[3],@out[3]
++	vaesenc		$rndkey0,@out[4],@out[4]
++	vaesenc		$rndkey0,@out[5],@out[5]
++	vaesenc		$rndkey0,@out[6],@out[6]
++	vaesenc		$rndkey0,@out[7],@out[7]
++	vmovups		0xc0-0x78($key),$rndkey0
++	je	.Lenc8x_tail
++
++	vaesenc		$rndkey1,@out[0],@out[0]
++	vaesenc		$rndkey1,@out[1],@out[1]
++	vaesenc		$rndkey1,@out[2],@out[2]
++	vaesenc		$rndkey1,@out[3],@out[3]
++	vaesenc		$rndkey1,@out[4],@out[4]
++	vaesenc		$rndkey1,@out[5],@out[5]
++	vaesenc		$rndkey1,@out[6],@out[6]
++	vaesenc		$rndkey1,@out[7],@out[7]
++	vmovups		0xd0-0x78($key),$rndkey1
++
++	vaesenc		$rndkey0,@out[0],@out[0]
++	vaesenc		$rndkey0,@out[1],@out[1]
++	vaesenc		$rndkey0,@out[2],@out[2]
++	vaesenc		$rndkey0,@out[3],@out[3]
++	vaesenc		$rndkey0,@out[4],@out[4]
++	vaesenc		$rndkey0,@out[5],@out[5]
++	vaesenc		$rndkey0,@out[6],@out[6]
++	vaesenc		$rndkey0,@out[7],@out[7]
++	vmovups		0xe0-0x78($key),$rndkey0
++
++.Lenc8x_tail:
++	vaesenc		$rndkey1,@out[0],@out[0]
++	 vpxor		$zero,$zero,$zero
++	vaesenc		$rndkey1,@out[1],@out[1]
++	vaesenc		$rndkey1,@out[2],@out[2]
++	 vpcmpgtd	$zero,$counters,$zero
++	vaesenc		$rndkey1,@out[3],@out[3]
++	vaesenc		$rndkey1,@out[4],@out[4]
++	 vpaddd		$counters,$zero,$zero		# decrement counters
++	 vmovdqu	48(%rsp),$counters
++	vaesenc		$rndkey1,@out[5],@out[5]
++	 mov		64(%rsp),$offset		# pre-load 1st offset
++	vaesenc		$rndkey1,@out[6],@out[6]
++	vaesenc		$rndkey1,@out[7],@out[7]
++	vmovups		0x10-0x78($key),$rndkey1
++
++	vaesenclast	$rndkey0,@out[0],@out[0]
++	 vmovdqa	$zero,32(%rsp)			# update counters
++	 vpxor		$zero,$zero,$zero
++	vaesenclast	$rndkey0,@out[1],@out[1]
++	vaesenclast	$rndkey0,@out[2],@out[2]
++	 vpcmpgtd	$zero,$counters,$zero
++	vaesenclast	$rndkey0,@out[3],@out[3]
++	vaesenclast	$rndkey0,@out[4],@out[4]
++	 vpaddd		$zero,$counters,$counters	# decrement counters
++	 vmovdqu	-0x78($key),$zero		# 0-round
++	vaesenclast	$rndkey0,@out[5],@out[5]
++	vaesenclast	$rndkey0,@out[6],@out[6]
++	 vmovdqa	$counters,48(%rsp)		# update counters
++	vaesenclast	$rndkey0,@out[7],@out[7]
++	vmovups		0x20-0x78($key),$rndkey0
++
++	vmovups		@out[0],-16(@ptr[0])		# write output
++	 sub		$offset,@ptr[0]			# switch to input
++	 vpxor		0x00($offload),@out[0],@out[0]
++	vmovups		@out[1],-16(@ptr[1])	
++	 sub		`64+1*8`(%rsp),@ptr[1]
++	 vpxor		0x10($offload),@out[1],@out[1]
++	vmovups		@out[2],-16(@ptr[2])	
++	 sub		`64+2*8`(%rsp),@ptr[2]
++	 vpxor		0x20($offload),@out[2],@out[2]
++	vmovups		@out[3],-16(@ptr[3])
++	 sub		`64+3*8`(%rsp),@ptr[3]
++	 vpxor		0x30($offload),@out[3],@out[3]
++	vmovups		@out[4],-16(@ptr[4])
++	 sub		`64+4*8`(%rsp),@ptr[4]
++	 vpxor		@inp[0],@out[4],@out[4]
++	vmovups		@out[5],-16(@ptr[5])	
++	 sub		`64+5*8`(%rsp),@ptr[5]
++	 vpxor		@inp[1],@out[5],@out[5]
++	vmovups		@out[6],-16(@ptr[6])	
++	 sub		`64+6*8`(%rsp),@ptr[6]
++	 vpxor		@inp[2],@out[6],@out[6]
++	vmovups		@out[7],-16(@ptr[7])
++	 sub		`64+7*8`(%rsp),@ptr[7]
++	 vpxor		@inp[3],@out[7],@out[7]
++
++	dec	$num
++	jnz	.Loop_enc8x
++
++	mov	16(%rsp),%rax			# original %rsp
++	#mov	24(%rsp),$num
++	#lea	`40*8`($inp),$inp
++	#dec	$num
++	#jnz	.Lenc8x_loop_grande
++
++.Lenc8x_done:
++	vzeroupper
++___
++$code.=<<___ if ($win64);
++	movaps	-0xd8(%rax),%xmm6
++	movaps	-0xc8(%rax),%xmm7
++	movaps	-0xb8(%rax),%xmm8
++	movaps	-0xa8(%rax),%xmm9
++	movaps	-0x98(%rax),%xmm10
++	movaps	-0x88(%rax),%xmm11
++	movaps	-0x78(%rax),%xmm12
++	movaps	-0x68(%rax),%xmm13
++	movaps	-0x58(%rax),%xmm14
++	movaps	-0x48(%rax),%xmm15
++___
++$code.=<<___;
++	mov	-48(%rax),%r15
++	mov	-40(%rax),%r14
++	mov	-32(%rax),%r13
++	mov	-24(%rax),%r12
++	mov	-16(%rax),%rbp
++	mov	-8(%rax),%rbx
++	lea	(%rax),%rsp
++.Lenc8x_epilogue:
++	ret
++.size	aesni_multi_cbc_encrypt_avx,.-aesni_multi_cbc_encrypt_avx
++
++.type	aesni_multi_cbc_decrypt_avx,\@function,3
++.align	32
++aesni_multi_cbc_decrypt_avx:
++_avx_cbc_dec_shortcut:
++	mov	%rsp,%rax
++	push	%rbx
++	push	%rbp
++	push	%r12
++	push	%r13
++	push	%r14
++	push	%r15
++___
++$code.=<<___ if ($win64);
++	lea	-0xa8(%rsp),%rsp
++	movaps	%xmm6,(%rsp)
++	movaps	%xmm7,0x10(%rsp)
++	movaps	%xmm8,0x20(%rsp)
++	movaps	%xmm9,0x30(%rsp)
++	movaps	%xmm10,0x40(%rsp)
++	movaps	%xmm11,0x50(%rsp)
++	movaps	%xmm12,-0x78(%rax)
++	movaps	%xmm13,-0x68(%rax)
++	movaps	%xmm14,-0x58(%rax)
++	movaps	%xmm15,-0x48(%rax)
++___
++$code.=<<___;
++	# stack layout
++	#
++	# +0	output sink
++	# +16	input sink [original %rsp and $num]
++	# +32	counters
++	# +64	distances between inputs and outputs
++	# +128	off-load area for @inp[0..3]
++	# +192	IV/input offload
++
++	sub	\$256,%rsp
++	and	\$-256,%rsp
++	sub	\$192,%rsp
++	mov	%rax,16(%rsp)			# original %rsp
++
++.Ldec8x_body:
++	vzeroupper
++	vmovdqu	($key),$zero			# 0-round key
++	lea	0x78($key),$key			# size optimization
++	lea	40*4($inp),$inp
++	shr	\$1,$num
++
++.Ldec8x_loop_grande:
++	#mov	$num,24(%rsp)			# original $num
++	xor	$num,$num
++___
++for($i=0;$i<8;$i++) {
++  my $temp = $i ? $offload : $offset;
++    $code.=<<___;
++	mov	`40*$i+16-40*4`($inp),$one	# borrow $one for number of blocks
++	mov	`40*$i+0-40*4`($inp),@ptr[$i]	# input pointer
++	cmp	$num,$one
++	mov	`40*$i+8-40*4`($inp),$temp	# output pointer
++	cmovg	$one,$num			# find maximum
++	test	$one,$one
++	vmovdqu	`40*$i+24-40*4`($inp),@out[$i]	# load IV
++	mov	$one,`32+4*$i`(%rsp)		# initialize counters
++	cmovle	%rsp,@ptr[$i]			# cancel input
++	sub	@ptr[$i],$temp			# distance between input and output
++	mov	$temp,`64+8*$i`(%rsp)		# initialize distances
++	vmovdqu	@out[$i],`192+16*$i`(%rsp)	# offload IV
++___
++}
++$code.=<<___;
++	test	$num,$num
++	jz	.Ldec8x_done
++
++	vmovups	0x10-0x78($key),$rndkey1
++	vmovups	0x20-0x78($key),$rndkey0
++	mov	0xf0-0x78($key),$rounds
++	 lea	192+128(%rsp),$offload		# offload area
++
++	vmovdqu	(@ptr[0]),@out[0]		# load inputs
++	vmovdqu	(@ptr[1]),@out[1]
++	vmovdqu	(@ptr[2]),@out[2]
++	vmovdqu	(@ptr[3]),@out[3]
++	vmovdqu	(@ptr[4]),@out[4]
++	vmovdqu	(@ptr[5]),@out[5]
++	vmovdqu	(@ptr[6]),@out[6]
++	vmovdqu	(@ptr[7]),@out[7]
++	vmovdqu	@out[0],0x00($offload)		# offload inputs
++	vpxor	$zero,@out[0],@out[0]		# xor inputs with 0-round
++	vmovdqu	@out[1],0x10($offload)
++	vpxor	$zero,@out[1],@out[1]
++	vmovdqu	@out[2],0x20($offload)
++	vpxor	$zero,@out[2],@out[2]
++	vmovdqu	@out[3],0x30($offload)
++	vpxor	$zero,@out[3],@out[3]
++	vmovdqu	@out[4],0x40($offload)
++	vpxor	$zero,@out[4],@out[4]
++	vmovdqu	@out[5],0x50($offload)
++	vpxor	$zero,@out[5],@out[5]
++	vmovdqu	@out[6],0x60($offload)
++	vpxor	$zero,@out[6],@out[6]
++	vmovdqu	@out[7],0x70($offload)
++	vpxor	$zero,@out[7],@out[7]
++	xor	\$0x80,$offload
++	mov	\$1,$one			# constant of 1
++	jmp	.Loop_dec8x
++
++.align	32
++.Loop_dec8x:
++___
++for($i=0;$i<8;$i++) {
++my $rndkey=($i&1)?$rndkey0:$rndkey1;
++$code.=<<___;
++	vaesdec		$rndkey,@out[0],@out[0]
++	 cmp		32+4*$i(%rsp),$one
++___
++$code.=<<___ if ($i);
++	 mov		64+8*$i(%rsp),$offset
++___
++$code.=<<___;
++	vaesdec		$rndkey,@out[1],@out[1]
++	prefetcht0	31(@ptr[$i])			# prefetch input
++	vaesdec		$rndkey,@out[2],@out[2]
++___
++$code.=<<___ if ($i>1);
++	prefetcht0	15(@ptr[$i-2])			# prefetch output
++___
++$code.=<<___;
++	vaesdec		$rndkey,@out[3],@out[3]
++	 lea		(@ptr[$i],$offset),$offset
++	 cmovge		%rsp,@ptr[$i]			# cancel input
++	vaesdec		$rndkey,@out[4],@out[4]
++	 cmovg		%rsp,$offset			# sink output
++	vaesdec		$rndkey,@out[5],@out[5]
++	 sub		@ptr[$i],$offset
++	vaesdec		$rndkey,@out[6],@out[6]
++	 vmovdqu	16(@ptr[$i]),@inp[$i%4]		# load input
++	 mov		$offset,64+8*$i(%rsp)
++	vaesdec		$rndkey,@out[7],@out[7]
++	vmovups		`16*(3+$i)-0x78`($key),$rndkey
++	 lea		16(@ptr[$i],$offset),@ptr[$i]	# switch to output
++___
++$code.=<<___ if ($i<4);
++	 vmovdqu	@inp[$i%4],`128+16*$i`(%rsp)	# off-load
++___
++}
++$code.=<<___;
++	 vmovdqu	32(%rsp),$counters
++	prefetcht0	15(@ptr[$i-2])			# prefetch output
++	prefetcht0	15(@ptr[$i-1])
++	cmp	\$11,$rounds
++	jb	.Ldec8x_tail
++
++	vaesdec		$rndkey1,@out[0],@out[0]
++	vaesdec		$rndkey1,@out[1],@out[1]
++	vaesdec		$rndkey1,@out[2],@out[2]
++	vaesdec		$rndkey1,@out[3],@out[3]
++	vaesdec		$rndkey1,@out[4],@out[4]
++	vaesdec		$rndkey1,@out[5],@out[5]
++	vaesdec		$rndkey1,@out[6],@out[6]
++	vaesdec		$rndkey1,@out[7],@out[7]
++	vmovups		0xb0-0x78($key),$rndkey1
++
++	vaesdec		$rndkey0,@out[0],@out[0]
++	vaesdec		$rndkey0,@out[1],@out[1]
++	vaesdec		$rndkey0,@out[2],@out[2]
++	vaesdec		$rndkey0,@out[3],@out[3]
++	vaesdec		$rndkey0,@out[4],@out[4]
++	vaesdec		$rndkey0,@out[5],@out[5]
++	vaesdec		$rndkey0,@out[6],@out[6]
++	vaesdec		$rndkey0,@out[7],@out[7]
++	vmovups		0xc0-0x78($key),$rndkey0
++	je	.Ldec8x_tail
++
++	vaesdec		$rndkey1,@out[0],@out[0]
++	vaesdec		$rndkey1,@out[1],@out[1]
++	vaesdec		$rndkey1,@out[2],@out[2]
++	vaesdec		$rndkey1,@out[3],@out[3]
++	vaesdec		$rndkey1,@out[4],@out[4]
++	vaesdec		$rndkey1,@out[5],@out[5]
++	vaesdec		$rndkey1,@out[6],@out[6]
++	vaesdec		$rndkey1,@out[7],@out[7]
++	vmovups		0xd0-0x78($key),$rndkey1
++
++	vaesdec		$rndkey0,@out[0],@out[0]
++	vaesdec		$rndkey0,@out[1],@out[1]
++	vaesdec		$rndkey0,@out[2],@out[2]
++	vaesdec		$rndkey0,@out[3],@out[3]
++	vaesdec		$rndkey0,@out[4],@out[4]
++	vaesdec		$rndkey0,@out[5],@out[5]
++	vaesdec		$rndkey0,@out[6],@out[6]
++	vaesdec		$rndkey0,@out[7],@out[7]
++	vmovups		0xe0-0x78($key),$rndkey0
++
++.Ldec8x_tail:
++	vaesdec		$rndkey1,@out[0],@out[0]
++	 vpxor		$zero,$zero,$zero
++	vaesdec		$rndkey1,@out[1],@out[1]
++	vaesdec		$rndkey1,@out[2],@out[2]
++	 vpcmpgtd	$zero,$counters,$zero
++	vaesdec		$rndkey1,@out[3],@out[3]
++	vaesdec		$rndkey1,@out[4],@out[4]
++	 vpaddd		$counters,$zero,$zero		# decrement counters
++	 vmovdqu	48(%rsp),$counters
++	vaesdec		$rndkey1,@out[5],@out[5]
++	 mov		64(%rsp),$offset		# pre-load 1st offset
++	vaesdec		$rndkey1,@out[6],@out[6]
++	vaesdec		$rndkey1,@out[7],@out[7]
++	vmovups		0x10-0x78($key),$rndkey1
++
++	vaesdeclast	$rndkey0,@out[0],@out[0]
++	 vmovdqa	$zero,32(%rsp)			# update counters
++	 vpxor		$zero,$zero,$zero
++	vaesdeclast	$rndkey0,@out[1],@out[1]
++	vpxor		0x00($offload),@out[0],@out[0]	# xor with IV
++	vaesdeclast	$rndkey0,@out[2],@out[2]
++	vpxor		0x10($offload),@out[1],@out[1]
++	 vpcmpgtd	$zero,$counters,$zero
++	vaesdeclast	$rndkey0,@out[3],@out[3]
++	vpxor		0x20($offload),@out[2],@out[2]
++	vaesdeclast	$rndkey0,@out[4],@out[4]
++	vpxor		0x30($offload),@out[3],@out[3]
++	 vpaddd		$zero,$counters,$counters	# decrement counters
++	 vmovdqu	-0x78($key),$zero		# 0-round
++	vaesdeclast	$rndkey0,@out[5],@out[5]
++	vpxor		0x40($offload),@out[4],@out[4]
++	vaesdeclast	$rndkey0,@out[6],@out[6]
++	vpxor		0x50($offload),@out[5],@out[5]
++	 vmovdqa	$counters,48(%rsp)		# update counters
++	vaesdeclast	$rndkey0,@out[7],@out[7]
++	vpxor		0x60($offload),@out[6],@out[6]
++	vmovups		0x20-0x78($key),$rndkey0
++
++	vmovups		@out[0],-16(@ptr[0])		# write output
++	 sub		$offset,@ptr[0]			# switch to input
++	 vmovdqu	128+0(%rsp),@out[0]
++	vpxor		0x70($offload),@out[7],@out[7]
++	vmovups		@out[1],-16(@ptr[1])	
++	 sub		`64+1*8`(%rsp),@ptr[1]
++	 vmovdqu	@out[0],0x00($offload)
++	 vpxor		$zero,@out[0],@out[0]
++	 vmovdqu	128+16(%rsp),@out[1]
++	vmovups		@out[2],-16(@ptr[2])	
++	 sub		`64+2*8`(%rsp),@ptr[2]
++	 vmovdqu	@out[1],0x10($offload)
++	 vpxor		$zero,@out[1],@out[1]
++	 vmovdqu	128+32(%rsp),@out[2]
++	vmovups		@out[3],-16(@ptr[3])
++	 sub		`64+3*8`(%rsp),@ptr[3]
++	 vmovdqu	@out[2],0x20($offload)
++	 vpxor		$zero,@out[2],@out[2]
++	 vmovdqu	128+48(%rsp),@out[3]
++	vmovups		@out[4],-16(@ptr[4])
++	 sub		`64+4*8`(%rsp),@ptr[4]
++	 vmovdqu	@out[3],0x30($offload)
++	 vpxor		$zero,@out[3],@out[3]
++	 vmovdqu	@inp[0],0x40($offload)
++	 vpxor		@inp[0],$zero,@out[4]
++	vmovups		@out[5],-16(@ptr[5])	
++	 sub		`64+5*8`(%rsp),@ptr[5]
++	 vmovdqu	@inp[1],0x50($offload)
++	 vpxor		@inp[1],$zero,@out[5]
++	vmovups		@out[6],-16(@ptr[6])	
++	 sub		`64+6*8`(%rsp),@ptr[6]
++	 vmovdqu	@inp[2],0x60($offload)
++	 vpxor		@inp[2],$zero,@out[6]
++	vmovups		@out[7],-16(@ptr[7])
++	 sub		`64+7*8`(%rsp),@ptr[7]
++	 vmovdqu	@inp[3],0x70($offload)
++	 vpxor		@inp[3],$zero,@out[7]
++
++	xor	\$128,$offload
++	dec	$num
++	jnz	.Loop_dec8x
++
++	mov	16(%rsp),%rax			# original %rsp
++	#mov	24(%rsp),$num
++	#lea	`40*8`($inp),$inp
++	#dec	$num
++	#jnz	.Ldec8x_loop_grande
++
++.Ldec8x_done:
++	vzeroupper
++___
++$code.=<<___ if ($win64);
++	movaps	-0xd8(%rax),%xmm6
++	movaps	-0xc8(%rax),%xmm7
++	movaps	-0xb8(%rax),%xmm8
++	movaps	-0xa8(%rax),%xmm9
++	movaps	-0x98(%rax),%xmm10
++	movaps	-0x88(%rax),%xmm11
++	movaps	-0x78(%rax),%xmm12
++	movaps	-0x68(%rax),%xmm13
++	movaps	-0x58(%rax),%xmm14
++	movaps	-0x48(%rax),%xmm15
++___
++$code.=<<___;
++	mov	-48(%rax),%r15
++	mov	-40(%rax),%r14
++	mov	-32(%rax),%r13
++	mov	-24(%rax),%r12
++	mov	-16(%rax),%rbp
++	mov	-8(%rax),%rbx
++	lea	(%rax),%rsp
++.Ldec8x_epilogue:
++	ret
++.size	aesni_multi_cbc_decrypt_avx,.-aesni_multi_cbc_decrypt_avx
++___
++						}}}
++
++if ($win64) {
++# EXCEPTION_DISPOSITION handler (EXCEPTION_RECORD *rec,ULONG64 frame,
++#		CONTEXT *context,DISPATCHER_CONTEXT *disp)
++$rec="%rcx";
++$frame="%rdx";
++$context="%r8";
++$disp="%r9";
++
++$code.=<<___;
++.extern	__imp_RtlVirtualUnwind
++.type	se_handler,\@abi-omnipotent
++.align	16
++se_handler:
++	push	%rsi
++	push	%rdi
++	push	%rbx
++	push	%rbp
++	push	%r12
++	push	%r13
++	push	%r14
++	push	%r15
++	pushfq
++	sub	\$64,%rsp
++
++	mov	120($context),%rax	# pull context->Rax
++	mov	248($context),%rbx	# pull context->Rip
++
++	mov	8($disp),%rsi		# disp->ImageBase
++	mov	56($disp),%r11		# disp->HandlerData
++
++	mov	0(%r11),%r10d		# HandlerData[0]
++	lea	(%rsi,%r10),%r10	# prologue label
++	cmp	%r10,%rbx		# context->Rip<.Lprologue
++	jb	.Lin_prologue
++
++	mov	152($context),%rax	# pull context->Rsp
++
++	mov	4(%r11),%r10d		# HandlerData[1]
++	lea	(%rsi,%r10),%r10	# epilogue label
++	cmp	%r10,%rbx		# context->Rip>=.Lepilogue
++	jae	.Lin_prologue
++
++	mov	16(%rax),%rax		# pull saved stack pointer
++
++	mov	-8(%rax),%rbx
++	mov	-16(%rax),%rbp
++	mov	-24(%rax),%r12
++	mov	-32(%rax),%r13
++	mov	-40(%rax),%r14
++	mov	-48(%rax),%r15
++	mov	%rbx,144($context)	# restore context->Rbx
++	mov	%rbp,160($context)	# restore context->Rbp
++	mov	%r12,216($context)	# restore cotnext->R12
++	mov	%r13,224($context)	# restore cotnext->R13
++	mov	%r14,232($context)	# restore cotnext->R14
++	mov	%r15,240($context)	# restore cotnext->R15
++
++	lea	-56-10*16(%rax),%rsi
++	lea	512($context),%rdi	# &context.Xmm6
++	mov	\$20,%ecx
++	.long	0xa548f3fc		# cld; rep movsq
++
++.Lin_prologue:
++	mov	8(%rax),%rdi
++	mov	16(%rax),%rsi
++	mov	%rax,152($context)	# restore context->Rsp
++	mov	%rsi,168($context)	# restore context->Rsi
++	mov	%rdi,176($context)	# restore context->Rdi
++
++	mov	40($disp),%rdi		# disp->ContextRecord
++	mov	$context,%rsi		# context
++	mov	\$154,%ecx		# sizeof(CONTEXT)
++	.long	0xa548f3fc		# cld; rep movsq
++
++	mov	$disp,%rsi
++	xor	%rcx,%rcx		# arg1, UNW_FLAG_NHANDLER
++	mov	8(%rsi),%rdx		# arg2, disp->ImageBase
++	mov	0(%rsi),%r8		# arg3, disp->ControlPc
++	mov	16(%rsi),%r9		# arg4, disp->FunctionEntry
++	mov	40(%rsi),%r10		# disp->ContextRecord
++	lea	56(%rsi),%r11		# &disp->HandlerData
++	lea	24(%rsi),%r12		# &disp->EstablisherFrame
++	mov	%r10,32(%rsp)		# arg5
++	mov	%r11,40(%rsp)		# arg6
++	mov	%r12,48(%rsp)		# arg7
++	mov	%rcx,56(%rsp)		# arg8, (NULL)
++	call	*__imp_RtlVirtualUnwind(%rip)
++
++	mov	\$1,%eax		# ExceptionContinueSearch
++	add	\$64,%rsp
++	popfq
++	pop	%r15
++	pop	%r14
++	pop	%r13
++	pop	%r12
++	pop	%rbp
++	pop	%rbx
++	pop	%rdi
++	pop	%rsi
++	ret
++.size	se_handler,.-se_handler
++
++.section	.pdata
++.align	4
++	.rva	.LSEH_begin_aesni_multi_cbc_encrypt
++	.rva	.LSEH_end_aesni_multi_cbc_encrypt
++	.rva	.LSEH_info_aesni_multi_cbc_encrypt
++	.rva	.LSEH_begin_aesni_multi_cbc_decrypt
++	.rva	.LSEH_end_aesni_multi_cbc_decrypt
++	.rva	.LSEH_info_aesni_multi_cbc_decrypt
++___
++$code.=<<___ if ($avx);
++	.rva	.LSEH_begin_aesni_multi_cbc_encrypt_avx
++	.rva	.LSEH_end_aesni_multi_cbc_encrypt_avx
++	.rva	.LSEH_info_aesni_multi_cbc_encrypt_avx
++	.rva	.LSEH_begin_aesni_multi_cbc_decrypt_avx
++	.rva	.LSEH_end_aesni_multi_cbc_decrypt_avx
++	.rva	.LSEH_info_aesni_multi_cbc_decrypt_avx
++___
++$code.=<<___;
++.section	.xdata
++.align	8
++.LSEH_info_aesni_multi_cbc_encrypt:
++	.byte	9,0,0,0
++	.rva	se_handler
++	.rva	.Lenc4x_body,.Lenc4x_epilogue		# HandlerData[]
++.LSEH_info_aesni_multi_cbc_decrypt:
++	.byte	9,0,0,0
++	.rva	se_handler
++	.rva	.Ldec4x_body,.Ldec4x_epilogue		# HandlerData[]
++___
++$code.=<<___ if ($avx);
++.LSEH_info_aesni_multi_cbc_encrypt_avx:
++	.byte	9,0,0,0
++	.rva	se_handler
++	.rva	.Lenc8x_body,.Lenc8x_epilogue		# HandlerData[]
++.LSEH_info_aesni_multi_cbc_decrypt_avx:
++	.byte	9,0,0,0
++	.rva	se_handler
++	.rva	.Ldec8x_body,.Ldec8x_epilogue		# HandlerData[]
++___
++}
++####################################################################
++
++sub rex {
++  local *opcode=shift;
++  my ($dst,$src)=@_;
++  my $rex=0;
++
++    $rex|=0x04			if($dst>=8);
++    $rex|=0x01			if($src>=8);
++    push @opcode,$rex|0x40	if($rex);
++}
++
++sub aesni {
++  my $line=shift;
++  my @opcode=(0x66);
++
++    if ($line=~/(aeskeygenassist)\s+\$([x0-9a-f]+),\s*%xmm([0-9]+),\s*%xmm([0-9]+)/) {
++	rex(\@opcode,$4,$3);
++	push @opcode,0x0f,0x3a,0xdf;
++	push @opcode,0xc0|($3&7)|(($4&7)<<3);	# ModR/M
++	my $c=$2;
++	push @opcode,$c=~/^0/?oct($c):$c;
++	return ".byte\t".join(',',@opcode);
++    }
++    elsif ($line=~/(aes[a-z]+)\s+%xmm([0-9]+),\s*%xmm([0-9]+)/) {
++	my %opcodelet = (
++		"aesimc" => 0xdb,
++		"aesenc" => 0xdc,	"aesenclast" => 0xdd,
++		"aesdec" => 0xde,	"aesdeclast" => 0xdf
++	);
++	return undef if (!defined($opcodelet{$1}));
++	rex(\@opcode,$3,$2);
++	push @opcode,0x0f,0x38,$opcodelet{$1};
++	push @opcode,0xc0|($2&7)|(($3&7)<<3);	# ModR/M
++	return ".byte\t".join(',',@opcode);
++    }
++    elsif ($line=~/(aes[a-z]+)\s+([0x1-9a-fA-F]*)\(%rsp\),\s*%xmm([0-9]+)/) {
++	my %opcodelet = (
++		"aesenc" => 0xdc,	"aesenclast" => 0xdd,
++		"aesdec" => 0xde,	"aesdeclast" => 0xdf
++	);
++	return undef if (!defined($opcodelet{$1}));
++	my $off = $2;
++	push @opcode,0x44 if ($3>=8);
++	push @opcode,0x0f,0x38,$opcodelet{$1};
++	push @opcode,0x44|(($3&7)<<3),0x24;	# ModR/M
++	push @opcode,($off=~/^0/?oct($off):$off)&0xff;
++	return ".byte\t".join(',',@opcode);
++    }
++    return $line;
++}
++
++$code =~ s/\`([^\`]*)\`/eval($1)/gem;
++$code =~ s/\b(aes.*%xmm[0-9]+).*$/aesni($1)/gem;
++
++print $code;
++close STDOUT;
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/aes/asm/aesni-sha1-x86_64.pl b/CryptoPkg/Library/OpensslLib/openssl/crypto/aes/asm/aesni-sha1-x86_64.pl
+new file mode 100644
+index 0000000..4b979a7
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/aes/asm/aesni-sha1-x86_64.pl
+@@ -0,0 +1,2066 @@
++#! /usr/bin/env perl
++# Copyright 2011-2016 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
++# in the file LICENSE in the source distribution or at
++# https://www.openssl.org/source/license.html
++
++#
++# ====================================================================
++# Written by Andy Polyakov  for the OpenSSL
++# project. The module is, however, dual licensed under OpenSSL and
++# CRYPTOGAMS licenses depending on where you obtain it. For further
++# details see http://www.openssl.org/~appro/cryptogams/.
++# ====================================================================
++#
++# June 2011
++#
++# This is AESNI-CBC+SHA1 "stitch" implementation. The idea, as spelled
++# in http://download.intel.com/design/intarch/papers/323686.pdf, is
++# that since AESNI-CBC encrypt exhibit *very* low instruction-level
++# parallelism, interleaving it with another algorithm would allow to
++# utilize processor resources better and achieve better performance.
++# SHA1 instruction sequences(*) are taken from sha1-x86_64.pl and
++# AESNI code is weaved into it. Below are performance numbers in
++# cycles per processed byte, less is better, for standalone AESNI-CBC
++# encrypt, sum of the latter and standalone SHA1, and "stitched"
++# subroutine:
++#
++#		AES-128-CBC	+SHA1		stitch      gain
++# Westmere	3.77[+5.3]	9.07		6.55	    +38%
++# Sandy Bridge	5.05[+5.0(6.1)]	10.06(11.15)	5.98(7.05)  +68%(+58%)
++# Ivy Bridge	5.05[+4.6]	9.65		5.54        +74%
++# Haswell	4.43[+3.6(4.2)]	8.00(8.58)	4.55(5.21)  +75%(+65%)
++# Skylake	2.63[+3.5(4.1)]	6.17(6.69)	4.23(4.44)  +46%(+51%)
++# Bulldozer	5.77[+6.0]	11.72		6.37        +84%
++#
++#		AES-192-CBC
++# Westmere	4.51		9.81		6.80	    +44%
++# Sandy Bridge	6.05		11.06(12.15)	6.11(7.19)  +81%(+69%)
++# Ivy Bridge	6.05		10.65		6.07        +75%
++# Haswell	5.29		8.86(9.44)	5.32(5.32)  +67%(+77%)
++# Bulldozer	6.89		12.84		6.96        +84%
++#
++#		AES-256-CBC
++# Westmere	5.25		10.55		7.21	    +46%
++# Sandy Bridge	7.05		12.06(13.15)	7.12(7.72)  +69%(+70%)
++# Ivy Bridge	7.05		11.65		7.12        +64%
++# Haswell	6.19		9.76(10.34)	6.21(6.25)  +57%(+65%)
++# Skylake	3.62		7.16(7.68)	4.56(4.76)  +57%(+61$)
++# Bulldozer	8.00		13.95		8.25        +69%
++#
++# (*)	There are two code paths: SSSE3 and AVX. See sha1-568.pl for
++#	background information. Above numbers in parentheses are SSSE3
++#	results collected on AVX-capable CPU, i.e. apply on OSes that
++#	don't support AVX.
++#
++# Needless to mention that it makes no sense to implement "stitched"
++# *decrypt* subroutine. Because *both* AESNI-CBC decrypt and SHA1
++# fully utilize parallelism, so stitching would not give any gain
++# anyway. Well, there might be some, e.g. because of better cache
++# locality... For reference, here are performance results for
++# standalone AESNI-CBC decrypt:
++#
++#		AES-128-CBC	AES-192-CBC	AES-256-CBC
++# Westmere	1.25		1.50		1.75
++# Sandy Bridge	0.74		0.91		1.09
++# Ivy Bridge	0.74		0.90		1.11
++# Haswell	0.63		0.76		0.88
++# Bulldozer	0.70		0.85		0.99
++
++# And indeed:
++#
++#		AES-256-CBC	+SHA1		stitch      gain
++# Westmere	1.75		7.20		6.68        +7.8%
++# Sandy Bridge	1.09		6.09(7.22)	5.82(6.95)  +4.6%(+3.9%)
++# Ivy Bridge	1.11		5.70		5.45        +4.6%
++# Haswell	0.88		4.45(5.00)	4.39(4.69)  +1.4%(*)(+6.6%)
++# Bulldozer	0.99		6.95		5.95        +17%(**)
++#
++# (*)	Tiny improvement coefficient on Haswell is because we compare
++#	AVX1 stitch to sum with AVX2 SHA1.
++# (**)	Execution is fully dominated by integer code sequence and
++#	SIMD still hardly shows [in single-process benchmark;-]
++
++$flavour = shift;
++$output  = shift;
++if ($flavour =~ /\./) { $output = $flavour; undef $flavour; }
++
++$win64=0; $win64=1 if ($flavour =~ /[nm]asm|mingw64/ || $output =~ /\.asm$/);
++
++$0 =~ m/(.*[\/\\])[^\/\\]+$/; $dir=$1;
++( $xlate="${dir}x86_64-xlate.pl" and -f $xlate ) or
++( $xlate="${dir}../../perlasm/x86_64-xlate.pl" and -f $xlate) or
++die "can't locate x86_64-xlate.pl";
++
++$avx=1 if (`$ENV{CC} -Wa,-v -c -o /dev/null -x assembler /dev/null 2>&1`
++		=~ /GNU assembler version ([2-9]\.[0-9]+)/ &&
++	   $1>=2.19);
++$avx=1 if (!$avx && $win64 && ($flavour =~ /nasm/ || $ENV{ASM} =~ /nasm/) &&
++	   `nasm -v 2>&1` =~ /NASM version ([2-9]\.[0-9]+)/ &&
++	   $1>=2.09);
++$avx=1 if (!$avx && $win64 && ($flavour =~ /masm/ || $ENV{ASM} =~ /ml64/) &&
++	   `ml64 2>&1` =~ /Version ([0-9]+)\./ &&
++	   $1>=10);
++$avx=1 if (!$avx && `$ENV{CC} -v 2>&1` =~ /((?:^clang|LLVM) version|.*based on LLVM) ([3-9]\.[0-9]+)/ && $2>=3.0);
++
++$shaext=1;	### set to zero if compiling for 1.0.1
++
++$stitched_decrypt=0;
++
++open OUT,"| \"$^X\" \"$xlate\" $flavour \"$output\"";
++*STDOUT=*OUT;
++
++# void aesni_cbc_sha1_enc(const void *inp,
++#			void *out,
++#			size_t length,
++#			const AES_KEY *key,
++#			unsigned char *iv,
++#			SHA_CTX *ctx,
++#			const void *in0);
++
++$code.=<<___;
++.text
++.extern	OPENSSL_ia32cap_P
++
++.globl	aesni_cbc_sha1_enc
++.type	aesni_cbc_sha1_enc,\@abi-omnipotent
++.align	32
++aesni_cbc_sha1_enc:
++	# caller should check for SSSE3 and AES-NI bits
++	mov	OPENSSL_ia32cap_P+0(%rip),%r10d
++	mov	OPENSSL_ia32cap_P+4(%rip),%r11
++___
++$code.=<<___ if ($shaext);
++	bt	\$61,%r11		# check SHA bit
++	jc	aesni_cbc_sha1_enc_shaext
++___
++$code.=<<___ if ($avx);
++	and	\$`1<<28`,%r11d		# mask AVX bit
++	and	\$`1<<30`,%r10d		# mask "Intel CPU" bit
++	or	%r11d,%r10d
++	cmp	\$`1<<28|1<<30`,%r10d
++	je	aesni_cbc_sha1_enc_avx
++___
++$code.=<<___;
++	jmp	aesni_cbc_sha1_enc_ssse3
++	ret
++.size	aesni_cbc_sha1_enc,.-aesni_cbc_sha1_enc
++___
++
++my ($in0,$out,$len,$key,$ivp,$ctx,$inp)=("%rdi","%rsi","%rdx","%rcx","%r8","%r9","%r10");
++
++my $Xi=4;
++my @X=map("%xmm$_",(4..7,0..3));
++my @Tx=map("%xmm$_",(8..10));
++my @V=($A,$B,$C,$D,$E)=("%eax","%ebx","%ecx","%edx","%ebp");	# size optimization
++my @T=("%esi","%edi");
++my $j=0; my $jj=0; my $r=0; my $sn=0; my $rx=0;
++my $K_XX_XX="%r11";
++my ($rndkey0,$iv,$in)=map("%xmm$_",(11..13));			# for enc
++my @rndkey=("%xmm14","%xmm15");					# for enc
++my ($inout0,$inout1,$inout2,$inout3)=map("%xmm$_",(12..15));	# for dec
++
++if (1) {	# reassign for Atom Silvermont
++    # The goal is to minimize amount of instructions with more than
++    # 3 prefix bytes. Or in more practical terms to keep AES-NI *and*
++    # SSSE3 instructions to upper half of the register bank.
++    @X=map("%xmm$_",(8..11,4..7));
++    @Tx=map("%xmm$_",(12,13,3));
++    ($iv,$in,$rndkey0)=map("%xmm$_",(2,14,15));
++    @rndkey=("%xmm0","%xmm1");
++}
++
++sub AUTOLOAD()		# thunk [simplified] 32-bit style perlasm
++{ my $opcode = $AUTOLOAD; $opcode =~ s/.*:://;
++  my $arg = pop;
++    $arg = "\$$arg" if ($arg*1 eq $arg);
++    $code .= "\t$opcode\t".join(',',$arg,reverse @_)."\n";
++}
++
++my $_rol=sub { &rol(@_) };
++my $_ror=sub { &ror(@_) };
++
++$code.=<<___;
++.type	aesni_cbc_sha1_enc_ssse3,\@function,6
++.align	32
++aesni_cbc_sha1_enc_ssse3:
++	mov	`($win64?56:8)`(%rsp),$inp	# load 7th argument
++	#shr	\$6,$len			# debugging artefact
++	#jz	.Lepilogue_ssse3		# debugging artefact
++	push	%rbx
++	push	%rbp
++	push	%r12
++	push	%r13
++	push	%r14
++	push	%r15
++	lea	`-104-($win64?10*16:0)`(%rsp),%rsp
++	#mov	$in0,$inp			# debugging artefact
++	#lea	64(%rsp),$ctx			# debugging artefact
++___
++$code.=<<___ if ($win64);
++	movaps	%xmm6,96+0(%rsp)
++	movaps	%xmm7,96+16(%rsp)
++	movaps	%xmm8,96+32(%rsp)
++	movaps	%xmm9,96+48(%rsp)
++	movaps	%xmm10,96+64(%rsp)
++	movaps	%xmm11,96+80(%rsp)
++	movaps	%xmm12,96+96(%rsp)
++	movaps	%xmm13,96+112(%rsp)
++	movaps	%xmm14,96+128(%rsp)
++	movaps	%xmm15,96+144(%rsp)
++.Lprologue_ssse3:
++___
++$code.=<<___;
++	mov	$in0,%r12			# reassign arguments
++	mov	$out,%r13
++	mov	$len,%r14
++	lea	112($key),%r15			# size optimization
++	movdqu	($ivp),$iv			# load IV
++	mov	$ivp,88(%rsp)			# save $ivp
++___
++($in0,$out,$len,$key)=map("%r$_",(12..15));	# reassign arguments
++my $rounds="${ivp}d";
++$code.=<<___;
++	shl	\$6,$len
++	sub	$in0,$out
++	mov	240-112($key),$rounds
++	add	$inp,$len		# end of input
++
++	lea	K_XX_XX(%rip),$K_XX_XX
++	mov	0($ctx),$A		# load context
++	mov	4($ctx),$B
++	mov	8($ctx),$C
++	mov	12($ctx),$D
++	mov	$B,@T[0]		# magic seed
++	mov	16($ctx),$E
++	mov	$C,@T[1]
++	xor	$D,@T[1]
++	and	@T[1],@T[0]
++
++	movdqa	64($K_XX_XX),@Tx[2]	# pbswap mask
++	movdqa	0($K_XX_XX),@Tx[1]	# K_00_19
++	movdqu	0($inp),@X[-4&7]	# load input to %xmm[0-3]
++	movdqu	16($inp),@X[-3&7]
++	movdqu	32($inp),@X[-2&7]
++	movdqu	48($inp),@X[-1&7]
++	pshufb	@Tx[2],@X[-4&7]		# byte swap
++	pshufb	@Tx[2],@X[-3&7]
++	pshufb	@Tx[2],@X[-2&7]
++	add	\$64,$inp
++	paddd	@Tx[1],@X[-4&7]		# add K_00_19
++	pshufb	@Tx[2],@X[-1&7]
++	paddd	@Tx[1],@X[-3&7]
++	paddd	@Tx[1],@X[-2&7]
++	movdqa	@X[-4&7],0(%rsp)	# X[]+K xfer to IALU
++	psubd	@Tx[1],@X[-4&7]		# restore X[]
++	movdqa	@X[-3&7],16(%rsp)
++	psubd	@Tx[1],@X[-3&7]
++	movdqa	@X[-2&7],32(%rsp)
++	psubd	@Tx[1],@X[-2&7]
++	movups	-112($key),$rndkey0	# $key[0]
++	movups	16-112($key),$rndkey[0]	# forward reference
++	jmp	.Loop_ssse3
++___
++
++my $aesenc=sub {
++  use integer;
++  my ($n,$k)=($r/10,$r%10);
++    if ($k==0) {
++      $code.=<<___;
++	movups		`16*$n`($in0),$in		# load input
++	xorps		$rndkey0,$in
++___
++      $code.=<<___ if ($n);
++	movups		$iv,`16*($n-1)`($out,$in0)	# write output
++___
++      $code.=<<___;
++	xorps		$in,$iv
++	movups		`32+16*$k-112`($key),$rndkey[1]
++	aesenc		$rndkey[0],$iv
++___
++    } elsif ($k==9) {
++      $sn++;
++      $code.=<<___;
++	cmp		\$11,$rounds
++	jb		.Laesenclast$sn
++	movups		`32+16*($k+0)-112`($key),$rndkey[1]
++	aesenc		$rndkey[0],$iv
++	movups		`32+16*($k+1)-112`($key),$rndkey[0]
++	aesenc		$rndkey[1],$iv
++	je		.Laesenclast$sn
++	movups		`32+16*($k+2)-112`($key),$rndkey[1]
++	aesenc		$rndkey[0],$iv
++	movups		`32+16*($k+3)-112`($key),$rndkey[0]
++	aesenc		$rndkey[1],$iv
++.Laesenclast$sn:
++	aesenclast	$rndkey[0],$iv
++	movups		16-112($key),$rndkey[1]		# forward reference
++___
++    } else {
++      $code.=<<___;
++	movups		`32+16*$k-112`($key),$rndkey[1]
++	aesenc		$rndkey[0],$iv
++___
++    }
++    $r++;	unshift(@rndkey,pop(@rndkey));
++};
++
++sub Xupdate_ssse3_16_31()		# recall that $Xi starts wtih 4
++{ use integer;
++  my $body = shift;
++  my @insns = (&$body,&$body,&$body,&$body);	# 40 instructions
++  my ($a,$b,$c,$d,$e);
++
++	 eval(shift(@insns));		# ror
++	&pshufd	(@X[0],@X[-4&7],0xee);	# was &movdqa	(@X[0],@X[-3&7]);
++	 eval(shift(@insns));
++	&movdqa	(@Tx[0],@X[-1&7]);
++	  &paddd	(@Tx[1],@X[-1&7]);
++	 eval(shift(@insns));
++	 eval(shift(@insns));
++
++	&punpcklqdq(@X[0],@X[-3&7]);	# compose "X[-14]" in "X[0]", was &palignr(@X[0],@X[-4&7],8);
++	 eval(shift(@insns));
++	 eval(shift(@insns));		# rol
++	 eval(shift(@insns));
++	&psrldq	(@Tx[0],4);		# "X[-3]", 3 dwords
++	 eval(shift(@insns));
++	 eval(shift(@insns));
++
++	&pxor	(@X[0],@X[-4&7]);	# "X[0]"^="X[-16]"
++	 eval(shift(@insns));
++	 eval(shift(@insns));		# ror
++	&pxor	(@Tx[0],@X[-2&7]);	# "X[-3]"^"X[-8]"
++	 eval(shift(@insns));
++	 eval(shift(@insns));
++	 eval(shift(@insns));
++
++	&pxor	(@X[0],@Tx[0]);		# "X[0]"^="X[-3]"^"X[-8]"
++	 eval(shift(@insns));
++	 eval(shift(@insns));		# rol
++	  &movdqa	(eval(16*(($Xi-1)&3))."(%rsp)",@Tx[1]);	# X[]+K xfer to IALU
++	 eval(shift(@insns));
++	 eval(shift(@insns));
++
++	&movdqa	(@Tx[2],@X[0]);
++	 eval(shift(@insns));
++	 eval(shift(@insns));
++	 eval(shift(@insns));		# ror
++	&movdqa	(@Tx[0],@X[0]);
++	 eval(shift(@insns));
++
++	&pslldq	(@Tx[2],12);		# "X[0]"<<96, extract one dword
++	&paddd	(@X[0],@X[0]);
++	 eval(shift(@insns));
++	 eval(shift(@insns));
++
++	&psrld	(@Tx[0],31);
++	 eval(shift(@insns));
++	 eval(shift(@insns));		# rol
++	 eval(shift(@insns));
++	&movdqa	(@Tx[1],@Tx[2]);
++	 eval(shift(@insns));
++	 eval(shift(@insns));
++
++	&psrld	(@Tx[2],30);
++	 eval(shift(@insns));
++	 eval(shift(@insns));		# ror
++	&por	(@X[0],@Tx[0]);		# "X[0]"<<<=1
++	 eval(shift(@insns));
++	 eval(shift(@insns));
++	 eval(shift(@insns));
++
++	&pslld	(@Tx[1],2);
++	&pxor	(@X[0],@Tx[2]);
++	 eval(shift(@insns));
++	  &movdqa	(@Tx[2],eval(16*(($Xi)/5))."($K_XX_XX)");	# K_XX_XX
++	 eval(shift(@insns));		# rol
++	 eval(shift(@insns));
++	 eval(shift(@insns));
++
++	&pxor	(@X[0],@Tx[1]);		# "X[0]"^=("X[0]">>96)<<<2
++	&pshufd (@Tx[1],@X[-1&7],0xee)	if ($Xi==7);	# was &movdqa	(@Tx[0],@X[-1&7]) in Xupdate_ssse3_32_79
++
++	 foreach (@insns) { eval; }	# remaining instructions [if any]
++
++  $Xi++;	push(@X,shift(@X));	# "rotate" X[]
++		push(@Tx,shift(@Tx));
++}
++
++sub Xupdate_ssse3_32_79()
++{ use integer;
++  my $body = shift;
++  my @insns = (&$body,&$body,&$body,&$body);	# 32 to 44 instructions
++  my ($a,$b,$c,$d,$e);
++
++	 eval(shift(@insns))		if ($Xi==8);
++	&pxor	(@X[0],@X[-4&7]);	# "X[0]"="X[-32]"^"X[-16]"
++	 eval(shift(@insns))		if ($Xi==8);
++	 eval(shift(@insns));		# body_20_39
++	 eval(shift(@insns));
++	 eval(shift(@insns))		if (@insns[1] =~ /_ror/);
++	 eval(shift(@insns))		if (@insns[0] =~ /_ror/);
++	&punpcklqdq(@Tx[0],@X[-1&7]);	# compose "X[-6]", was &palignr(@Tx[0],@X[-2&7],8);
++	 eval(shift(@insns));
++	 eval(shift(@insns));		# rol
++
++	&pxor	(@X[0],@X[-7&7]);	# "X[0]"^="X[-28]"
++	 eval(shift(@insns));
++	 eval(shift(@insns));
++	if ($Xi%5) {
++	  &movdqa	(@Tx[2],@Tx[1]);# "perpetuate" K_XX_XX...
++	} else {			# ... or load next one
++	  &movdqa	(@Tx[2],eval(16*($Xi/5))."($K_XX_XX)");
++	}
++	 eval(shift(@insns));		# ror
++	  &paddd	(@Tx[1],@X[-1&7]);
++	 eval(shift(@insns));
++
++	&pxor	(@X[0],@Tx[0]);		# "X[0]"^="X[-6]"
++	 eval(shift(@insns));		# body_20_39
++	 eval(shift(@insns));
++	 eval(shift(@insns));
++	 eval(shift(@insns));		# rol
++	 eval(shift(@insns))		if (@insns[0] =~ /_ror/);
++
++	&movdqa	(@Tx[0],@X[0]);
++	 eval(shift(@insns));
++	 eval(shift(@insns));
++	  &movdqa	(eval(16*(($Xi-1)&3))."(%rsp)",@Tx[1]);	# X[]+K xfer to IALU
++	 eval(shift(@insns));		# ror
++	 eval(shift(@insns));
++	 eval(shift(@insns));		# body_20_39
++
++	&pslld	(@X[0],2);
++	 eval(shift(@insns));
++	 eval(shift(@insns));
++	&psrld	(@Tx[0],30);
++	 eval(shift(@insns))		if (@insns[0] =~ /_rol/);# rol
++	 eval(shift(@insns));
++	 eval(shift(@insns));
++	 eval(shift(@insns));		# ror
++
++	&por	(@X[0],@Tx[0]);		# "X[0]"<<<=2
++	 eval(shift(@insns));
++	 eval(shift(@insns));		# body_20_39
++	 eval(shift(@insns))		if (@insns[1] =~ /_rol/);
++	 eval(shift(@insns))		if (@insns[0] =~ /_rol/);
++	  &pshufd(@Tx[1],@X[-1&7],0xee)	if ($Xi<19);	# was &movdqa	(@Tx[1],@X[0])
++	 eval(shift(@insns));
++	 eval(shift(@insns));		# rol
++	 eval(shift(@insns));
++	 eval(shift(@insns));
++	 eval(shift(@insns));		# rol
++	 eval(shift(@insns));
++
++	 foreach (@insns) { eval; }	# remaining instructions
++
++  $Xi++;	push(@X,shift(@X));	# "rotate" X[]
++		push(@Tx,shift(@Tx));
++}
++
++sub Xuplast_ssse3_80()
++{ use integer;
++  my $body = shift;
++  my @insns = (&$body,&$body,&$body,&$body);	# 32 instructions
++  my ($a,$b,$c,$d,$e);
++
++	 eval(shift(@insns));
++	 eval(shift(@insns));
++	 eval(shift(@insns));
++	 eval(shift(@insns));
++	  &paddd	(@Tx[1],@X[-1&7]);
++	 eval(shift(@insns));
++	 eval(shift(@insns));
++
++	  &movdqa	(eval(16*(($Xi-1)&3))."(%rsp)",@Tx[1]);	# X[]+K xfer IALU
++
++	 foreach (@insns) { eval; }		# remaining instructions
++
++	&cmp	($inp,$len);
++	&je	(shift);
++
++	unshift(@Tx,pop(@Tx));
++
++	&movdqa	(@Tx[2],"64($K_XX_XX)");	# pbswap mask
++	&movdqa	(@Tx[1],"0($K_XX_XX)");		# K_00_19
++	&movdqu	(@X[-4&7],"0($inp)");		# load input
++	&movdqu	(@X[-3&7],"16($inp)");
++	&movdqu	(@X[-2&7],"32($inp)");
++	&movdqu	(@X[-1&7],"48($inp)");
++	&pshufb	(@X[-4&7],@Tx[2]);		# byte swap
++	&add	($inp,64);
++
++  $Xi=0;
++}
++
++sub Xloop_ssse3()
++{ use integer;
++  my $body = shift;
++  my @insns = (&$body,&$body,&$body,&$body);	# 32 instructions
++  my ($a,$b,$c,$d,$e);
++
++	 eval(shift(@insns));
++	 eval(shift(@insns));
++	 eval(shift(@insns));
++	&pshufb	(@X[($Xi-3)&7],@Tx[2]);
++	 eval(shift(@insns));
++	 eval(shift(@insns));
++	 eval(shift(@insns));
++	 eval(shift(@insns));
++	&paddd	(@X[($Xi-4)&7],@Tx[1]);
++	 eval(shift(@insns));
++	 eval(shift(@insns));
++	 eval(shift(@insns));
++	 eval(shift(@insns));
++	&movdqa	(eval(16*$Xi)."(%rsp)",@X[($Xi-4)&7]);	# X[]+K xfer to IALU
++	 eval(shift(@insns));
++	 eval(shift(@insns));
++	 eval(shift(@insns));
++	 eval(shift(@insns));
++	&psubd	(@X[($Xi-4)&7],@Tx[1]);
++
++	foreach (@insns) { eval; }
++  $Xi++;
++}
++
++sub Xtail_ssse3()
++{ use integer;
++  my $body = shift;
++  my @insns = (&$body,&$body,&$body,&$body);	# 32 instructions
++  my ($a,$b,$c,$d,$e);
++
++	foreach (@insns) { eval; }
++}
++
++my @body_00_19 = (
++	'($a,$b,$c,$d,$e)=@V;'.
++	'&$_ror	($b,$j?7:2);',	# $b>>>2
++	'&xor	(@T[0],$d);',
++	'&mov	(@T[1],$a);',	# $b for next round
++
++	'&add	($e,eval(4*($j&15))."(%rsp)");',# X[]+K xfer
++	'&xor	($b,$c);',	# $c^$d for next round
++
++	'&$_rol	($a,5);',
++	'&add	($e,@T[0]);',
++	'&and	(@T[1],$b);',	# ($b&($c^$d)) for next round
++
++	'&xor	($b,$c);',	# restore $b
++	'&add	($e,$a);'	.'$j++; unshift(@V,pop(@V)); unshift(@T,pop(@T));'
++	);
++
++sub body_00_19 () {	# ((c^d)&b)^d
++    # on start @T[0]=(c^d)&b
++    return &body_20_39() if ($rx==19); $rx++;
++
++    use integer;
++    my ($k,$n);
++    my @r=@body_00_19;
++
++	$n = scalar(@r);
++	$k = (($jj+1)*12/20)*20*$n/12;	# 12 aesencs per these 20 rounds
++	@r[$k%$n].='&$aesenc();'	if ($jj==$k/$n);
++	$jj++;
++
++    return @r;
++}
++
++my @body_20_39 = (
++	'($a,$b,$c,$d,$e)=@V;'.
++	'&add	($e,eval(4*($j&15))."(%rsp)");',# X[]+K xfer
++	'&xor	(@T[0],$d)	if($j==19);'.
++	'&xor	(@T[0],$c)	if($j> 19);',	# ($b^$d^$c)
++	'&mov	(@T[1],$a);',	# $b for next round
++
++	'&$_rol	($a,5);',
++	'&add	($e,@T[0]);',
++	'&xor	(@T[1],$c)	if ($j< 79);',	# $b^$d for next round
++
++	'&$_ror	($b,7);',	# $b>>>2
++	'&add	($e,$a);'	.'$j++; unshift(@V,pop(@V)); unshift(@T,pop(@T));'
++	);
++
++sub body_20_39 () {	# b^d^c
++    # on entry @T[0]=b^d
++    return &body_40_59() if ($rx==39); $rx++;
++
++    use integer;
++    my ($k,$n);
++    my @r=@body_20_39;
++
++	$n = scalar(@r);
++	$k = (($jj+1)*8/20)*20*$n/8;	# 8 aesencs per these 20 rounds
++	@r[$k%$n].='&$aesenc();'	if ($jj==$k/$n && $rx!=20);
++	$jj++;
++
++    return @r;
++}
++
++my @body_40_59 = (
++	'($a,$b,$c,$d,$e)=@V;'.
++	'&add	($e,eval(4*($j&15))."(%rsp)");',# X[]+K xfer
++	'&and	(@T[0],$c)	if ($j>=40);',	# (b^c)&(c^d)
++	'&xor	($c,$d)		if ($j>=40);',	# restore $c
++
++	'&$_ror	($b,7);',	# $b>>>2
++	'&mov	(@T[1],$a);',	# $b for next round
++	'&xor	(@T[0],$c);',
++
++	'&$_rol	($a,5);',
++	'&add	($e,@T[0]);',
++	'&xor	(@T[1],$c)	if ($j==59);'.
++	'&xor	(@T[1],$b)	if ($j< 59);',	# b^c for next round
++
++	'&xor	($b,$c)		if ($j< 59);',	# c^d for next round
++	'&add	($e,$a);'	.'$j++; unshift(@V,pop(@V)); unshift(@T,pop(@T));'
++	);
++
++sub body_40_59 () {	# ((b^c)&(c^d))^c
++    # on entry @T[0]=(b^c), (c^=d)
++    $rx++;
++
++    use integer;
++    my ($k,$n);
++    my @r=@body_40_59;
++
++	$n = scalar(@r);
++	$k=(($jj+1)*12/20)*20*$n/12;	# 12 aesencs per these 20 rounds
++	@r[$k%$n].='&$aesenc();'	if ($jj==$k/$n && $rx!=40);
++	$jj++;
++
++    return @r;
++}
++$code.=<<___;
++.align	32
++.Loop_ssse3:
++___
++	&Xupdate_ssse3_16_31(\&body_00_19);
++	&Xupdate_ssse3_16_31(\&body_00_19);
++	&Xupdate_ssse3_16_31(\&body_00_19);
++	&Xupdate_ssse3_16_31(\&body_00_19);
++	&Xupdate_ssse3_32_79(\&body_00_19);
++	&Xupdate_ssse3_32_79(\&body_20_39);
++	&Xupdate_ssse3_32_79(\&body_20_39);
++	&Xupdate_ssse3_32_79(\&body_20_39);
++	&Xupdate_ssse3_32_79(\&body_20_39);
++	&Xupdate_ssse3_32_79(\&body_20_39);
++	&Xupdate_ssse3_32_79(\&body_40_59);
++	&Xupdate_ssse3_32_79(\&body_40_59);
++	&Xupdate_ssse3_32_79(\&body_40_59);
++	&Xupdate_ssse3_32_79(\&body_40_59);
++	&Xupdate_ssse3_32_79(\&body_40_59);
++	&Xupdate_ssse3_32_79(\&body_20_39);
++	&Xuplast_ssse3_80(\&body_20_39,".Ldone_ssse3");	# can jump to "done"
++
++				$saved_j=$j; @saved_V=@V;
++				$saved_r=$r; @saved_rndkey=@rndkey;
++
++	&Xloop_ssse3(\&body_20_39);
++	&Xloop_ssse3(\&body_20_39);
++	&Xloop_ssse3(\&body_20_39);
++
++$code.=<<___;
++	movups	$iv,48($out,$in0)		# write output
++	lea	64($in0),$in0
++
++	add	0($ctx),$A			# update context
++	add	4($ctx),@T[0]
++	add	8($ctx),$C
++	add	12($ctx),$D
++	mov	$A,0($ctx)
++	add	16($ctx),$E
++	mov	@T[0],4($ctx)
++	mov	@T[0],$B			# magic seed
++	mov	$C,8($ctx)
++	mov	$C,@T[1]
++	mov	$D,12($ctx)
++	xor	$D,@T[1]
++	mov	$E,16($ctx)
++	and	@T[1],@T[0]
++	jmp	.Loop_ssse3
++
++.Ldone_ssse3:
++___
++				$jj=$j=$saved_j; @V=@saved_V;
++				$r=$saved_r;     @rndkey=@saved_rndkey;
++
++	&Xtail_ssse3(\&body_20_39);
++	&Xtail_ssse3(\&body_20_39);
++	&Xtail_ssse3(\&body_20_39);
++
++$code.=<<___;
++	movups	$iv,48($out,$in0)		# write output
++	mov	88(%rsp),$ivp			# restore $ivp
++
++	add	0($ctx),$A			# update context
++	add	4($ctx),@T[0]
++	add	8($ctx),$C
++	mov	$A,0($ctx)
++	add	12($ctx),$D
++	mov	@T[0],4($ctx)
++	add	16($ctx),$E
++	mov	$C,8($ctx)
++	mov	$D,12($ctx)
++	mov	$E,16($ctx)
++	movups	$iv,($ivp)			# write IV
++___
++$code.=<<___ if ($win64);
++	movaps	96+0(%rsp),%xmm6
++	movaps	96+16(%rsp),%xmm7
++	movaps	96+32(%rsp),%xmm8
++	movaps	96+48(%rsp),%xmm9
++	movaps	96+64(%rsp),%xmm10
++	movaps	96+80(%rsp),%xmm11
++	movaps	96+96(%rsp),%xmm12
++	movaps	96+112(%rsp),%xmm13
++	movaps	96+128(%rsp),%xmm14
++	movaps	96+144(%rsp),%xmm15
++___
++$code.=<<___;
++	lea	`104+($win64?10*16:0)`(%rsp),%rsi
++	mov	0(%rsi),%r15
++	mov	8(%rsi),%r14
++	mov	16(%rsi),%r13
++	mov	24(%rsi),%r12
++	mov	32(%rsi),%rbp
++	mov	40(%rsi),%rbx
++	lea	48(%rsi),%rsp
++.Lepilogue_ssse3:
++	ret
++.size	aesni_cbc_sha1_enc_ssse3,.-aesni_cbc_sha1_enc_ssse3
++___
++
++						if ($stitched_decrypt) {{{
++# reset
++($in0,$out,$len,$key,$ivp,$ctx,$inp)=("%rdi","%rsi","%rdx","%rcx","%r8","%r9","%r10");
++$j=$jj=$r=$rx=0;
++$Xi=4;
++
++# reassign for Atom Silvermont (see above)
++($inout0,$inout1,$inout2,$inout3,$rndkey0)=map("%xmm$_",(0..4));
++@X=map("%xmm$_",(8..13,6,7));
++@Tx=map("%xmm$_",(14,15,5));
++
++my @aes256_dec = (
++	'&movdqu($inout0,"0x00($in0)");',
++	'&movdqu($inout1,"0x10($in0)");	&pxor	($inout0,$rndkey0);',
++	'&movdqu($inout2,"0x20($in0)");	&pxor	($inout1,$rndkey0);',
++	'&movdqu($inout3,"0x30($in0)");	&pxor	($inout2,$rndkey0);',
++
++	'&pxor	($inout3,$rndkey0);	&movups	($rndkey0,"16-112($key)");',
++	'&movaps("64(%rsp)",@X[2]);',	# save IV, originally @X[3]
++	undef,undef
++	);
++for ($i=0;$i<13;$i++) {
++    push (@aes256_dec,(
++	'&aesdec	($inout0,$rndkey0);',
++	'&aesdec	($inout1,$rndkey0);',
++	'&aesdec	($inout2,$rndkey0);',
++	'&aesdec	($inout3,$rndkey0);	&movups($rndkey0,"'.(16*($i+2)-112).'($key)");'
++	));
++    push (@aes256_dec,(undef,undef))	if (($i>=3 && $i<=5) || $i>=11);
++    push (@aes256_dec,(undef,undef))	if ($i==5);
++}
++push(@aes256_dec,(
++	'&aesdeclast	($inout0,$rndkey0);	&movups	(@X[0],"0x00($in0)");',
++	'&aesdeclast	($inout1,$rndkey0);	&movups	(@X[1],"0x10($in0)");',
++	'&aesdeclast	($inout2,$rndkey0);	&movups	(@X[2],"0x20($in0)");',
++	'&aesdeclast	($inout3,$rndkey0);	&movups	(@X[3],"0x30($in0)");',
++
++	'&xorps		($inout0,"64(%rsp)");	&movdqu	($rndkey0,"-112($key)");',
++	'&xorps		($inout1,@X[0]);	&movups	("0x00($out,$in0)",$inout0);',
++	'&xorps		($inout2,@X[1]);	&movups	("0x10($out,$in0)",$inout1);',
++	'&xorps		($inout3,@X[2]);	&movups	("0x20($out,$in0)",$inout2);',
++
++	'&movups	("0x30($out,$in0)",$inout3);'
++	));
++
++sub body_00_19_dec () {	# ((c^d)&b)^d
++    # on start @T[0]=(c^d)&b
++    return &body_20_39_dec() if ($rx==19);
++
++    my @r=@body_00_19;
++
++	unshift (@r,@aes256_dec[$rx])	if (@aes256_dec[$rx]);
++	$rx++;
++
++    return @r;
++}
++
++sub body_20_39_dec () {	# b^d^c
++    # on entry @T[0]=b^d
++    return &body_40_59_dec() if ($rx==39);
++  
++    my @r=@body_20_39;
++
++	unshift (@r,@aes256_dec[$rx])	if (@aes256_dec[$rx]);
++	$rx++;
++
++    return @r;
++}
++
++sub body_40_59_dec () {	# ((b^c)&(c^d))^c
++    # on entry @T[0]=(b^c), (c^=d)
++
++    my @r=@body_40_59;
++
++	unshift (@r,@aes256_dec[$rx])	if (@aes256_dec[$rx]);
++	$rx++;
++
++    return @r;
++}
++
++$code.=<<___;
++.globl	aesni256_cbc_sha1_dec
++.type	aesni256_cbc_sha1_dec,\@abi-omnipotent
++.align	32
++aesni256_cbc_sha1_dec:
++	# caller should check for SSSE3 and AES-NI bits
++	mov	OPENSSL_ia32cap_P+0(%rip),%r10d
++	mov	OPENSSL_ia32cap_P+4(%rip),%r11d
++___
++$code.=<<___ if ($avx);
++	and	\$`1<<28`,%r11d		# mask AVX bit
++	and	\$`1<<30`,%r10d		# mask "Intel CPU" bit
++	or	%r11d,%r10d
++	cmp	\$`1<<28|1<<30`,%r10d
++	je	aesni256_cbc_sha1_dec_avx
++___
++$code.=<<___;
++	jmp	aesni256_cbc_sha1_dec_ssse3
++	ret
++.size	aesni256_cbc_sha1_dec,.-aesni256_cbc_sha1_dec
++
++.type	aesni256_cbc_sha1_dec_ssse3,\@function,6
++.align	32
++aesni256_cbc_sha1_dec_ssse3:
++	mov	`($win64?56:8)`(%rsp),$inp	# load 7th argument
++	push	%rbx
++	push	%rbp
++	push	%r12
++	push	%r13
++	push	%r14
++	push	%r15
++	lea	`-104-($win64?10*16:0)`(%rsp),%rsp
++___
++$code.=<<___ if ($win64);
++	movaps	%xmm6,96+0(%rsp)
++	movaps	%xmm7,96+16(%rsp)
++	movaps	%xmm8,96+32(%rsp)
++	movaps	%xmm9,96+48(%rsp)
++	movaps	%xmm10,96+64(%rsp)
++	movaps	%xmm11,96+80(%rsp)
++	movaps	%xmm12,96+96(%rsp)
++	movaps	%xmm13,96+112(%rsp)
++	movaps	%xmm14,96+128(%rsp)
++	movaps	%xmm15,96+144(%rsp)
++.Lprologue_dec_ssse3:
++___
++$code.=<<___;
++	mov	$in0,%r12			# reassign arguments
++	mov	$out,%r13
++	mov	$len,%r14
++	lea	112($key),%r15			# size optimization
++	movdqu	($ivp),@X[3]			# load IV
++	#mov	$ivp,88(%rsp)			# save $ivp
++___
++($in0,$out,$len,$key)=map("%r$_",(12..15));	# reassign arguments
++$code.=<<___;
++	shl	\$6,$len
++	sub	$in0,$out
++	add	$inp,$len		# end of input
++
++	lea	K_XX_XX(%rip),$K_XX_XX
++	mov	0($ctx),$A		# load context
++	mov	4($ctx),$B
++	mov	8($ctx),$C
++	mov	12($ctx),$D
++	mov	$B,@T[0]		# magic seed
++	mov	16($ctx),$E
++	mov	$C,@T[1]
++	xor	$D,@T[1]
++	and	@T[1],@T[0]
++
++	movdqa	64($K_XX_XX),@Tx[2]	# pbswap mask
++	movdqa	0($K_XX_XX),@Tx[1]	# K_00_19
++	movdqu	0($inp),@X[-4&7]	# load input to %xmm[0-3]
++	movdqu	16($inp),@X[-3&7]
++	movdqu	32($inp),@X[-2&7]
++	movdqu	48($inp),@X[-1&7]
++	pshufb	@Tx[2],@X[-4&7]		# byte swap
++	add	\$64,$inp
++	pshufb	@Tx[2],@X[-3&7]
++	pshufb	@Tx[2],@X[-2&7]
++	pshufb	@Tx[2],@X[-1&7]
++	paddd	@Tx[1],@X[-4&7]		# add K_00_19
++	paddd	@Tx[1],@X[-3&7]
++	paddd	@Tx[1],@X[-2&7]
++	movdqa	@X[-4&7],0(%rsp)	# X[]+K xfer to IALU
++	psubd	@Tx[1],@X[-4&7]		# restore X[]
++	movdqa	@X[-3&7],16(%rsp)
++	psubd	@Tx[1],@X[-3&7]
++	movdqa	@X[-2&7],32(%rsp)
++	psubd	@Tx[1],@X[-2&7]
++	movdqu	-112($key),$rndkey0	# $key[0]
++	jmp	.Loop_dec_ssse3
++
++.align	32
++.Loop_dec_ssse3:
++___
++	&Xupdate_ssse3_16_31(\&body_00_19_dec);
++	&Xupdate_ssse3_16_31(\&body_00_19_dec);
++	&Xupdate_ssse3_16_31(\&body_00_19_dec);
++	&Xupdate_ssse3_16_31(\&body_00_19_dec);
++	&Xupdate_ssse3_32_79(\&body_00_19_dec);
++	&Xupdate_ssse3_32_79(\&body_20_39_dec);
++	&Xupdate_ssse3_32_79(\&body_20_39_dec);
++	&Xupdate_ssse3_32_79(\&body_20_39_dec);
++	&Xupdate_ssse3_32_79(\&body_20_39_dec);
++	&Xupdate_ssse3_32_79(\&body_20_39_dec);
++	&Xupdate_ssse3_32_79(\&body_40_59_dec);
++	&Xupdate_ssse3_32_79(\&body_40_59_dec);
++	&Xupdate_ssse3_32_79(\&body_40_59_dec);
++	&Xupdate_ssse3_32_79(\&body_40_59_dec);
++	&Xupdate_ssse3_32_79(\&body_40_59_dec);
++	&Xupdate_ssse3_32_79(\&body_20_39_dec);
++	&Xuplast_ssse3_80(\&body_20_39_dec,".Ldone_dec_ssse3");	# can jump to "done"
++
++				$saved_j=$j;   @saved_V=@V;
++				$saved_rx=$rx;
++
++	&Xloop_ssse3(\&body_20_39_dec);
++	&Xloop_ssse3(\&body_20_39_dec);
++	&Xloop_ssse3(\&body_20_39_dec);
++
++	eval(@aes256_dec[-1]);			# last store
++$code.=<<___;
++	lea	64($in0),$in0
++
++	add	0($ctx),$A			# update context
++	add	4($ctx),@T[0]
++	add	8($ctx),$C
++	add	12($ctx),$D
++	mov	$A,0($ctx)
++	add	16($ctx),$E
++	mov	@T[0],4($ctx)
++	mov	@T[0],$B			# magic seed
++	mov	$C,8($ctx)
++	mov	$C,@T[1]
++	mov	$D,12($ctx)
++	xor	$D,@T[1]
++	mov	$E,16($ctx)
++	and	@T[1],@T[0]
++	jmp	.Loop_dec_ssse3
++
++.Ldone_dec_ssse3:
++___
++				$jj=$j=$saved_j; @V=@saved_V;
++				$rx=$saved_rx;
++
++	&Xtail_ssse3(\&body_20_39_dec);
++	&Xtail_ssse3(\&body_20_39_dec);
++	&Xtail_ssse3(\&body_20_39_dec);
++
++	eval(@aes256_dec[-1]);			# last store
++$code.=<<___;
++	add	0($ctx),$A			# update context
++	add	4($ctx),@T[0]
++	add	8($ctx),$C
++	mov	$A,0($ctx)
++	add	12($ctx),$D
++	mov	@T[0],4($ctx)
++	add	16($ctx),$E
++	mov	$C,8($ctx)
++	mov	$D,12($ctx)
++	mov	$E,16($ctx)
++	movups	@X[3],($ivp)			# write IV
++___
++$code.=<<___ if ($win64);
++	movaps	96+0(%rsp),%xmm6
++	movaps	96+16(%rsp),%xmm7
++	movaps	96+32(%rsp),%xmm8
++	movaps	96+48(%rsp),%xmm9
++	movaps	96+64(%rsp),%xmm10
++	movaps	96+80(%rsp),%xmm11
++	movaps	96+96(%rsp),%xmm12
++	movaps	96+112(%rsp),%xmm13
++	movaps	96+128(%rsp),%xmm14
++	movaps	96+144(%rsp),%xmm15
++___
++$code.=<<___;
++	lea	`104+($win64?10*16:0)`(%rsp),%rsi
++	mov	0(%rsi),%r15
++	mov	8(%rsi),%r14
++	mov	16(%rsi),%r13
++	mov	24(%rsi),%r12
++	mov	32(%rsi),%rbp
++	mov	40(%rsi),%rbx
++	lea	48(%rsi),%rsp
++.Lepilogue_dec_ssse3:
++	ret
++.size	aesni256_cbc_sha1_dec_ssse3,.-aesni256_cbc_sha1_dec_ssse3
++___
++						}}}
++$j=$jj=$r=$rx=0;
++
++if ($avx) {
++my ($in0,$out,$len,$key,$ivp,$ctx,$inp)=("%rdi","%rsi","%rdx","%rcx","%r8","%r9","%r10");
++
++my $Xi=4;
++my @X=map("%xmm$_",(4..7,0..3));
++my @Tx=map("%xmm$_",(8..10));
++my @V=($A,$B,$C,$D,$E)=("%eax","%ebx","%ecx","%edx","%ebp");	# size optimization
++my @T=("%esi","%edi");
++my ($rndkey0,$iv,$in)=map("%xmm$_",(11..13));
++my @rndkey=("%xmm14","%xmm15");
++my ($inout0,$inout1,$inout2,$inout3)=map("%xmm$_",(12..15));	# for dec
++my $Kx=@Tx[2];
++
++my $_rol=sub { &shld(@_[0],@_) };
++my $_ror=sub { &shrd(@_[0],@_) };
++
++$code.=<<___;
++.type	aesni_cbc_sha1_enc_avx,\@function,6
++.align	32
++aesni_cbc_sha1_enc_avx:
++	mov	`($win64?56:8)`(%rsp),$inp	# load 7th argument
++	#shr	\$6,$len			# debugging artefact
++	#jz	.Lepilogue_avx			# debugging artefact
++	push	%rbx
++	push	%rbp
++	push	%r12
++	push	%r13
++	push	%r14
++	push	%r15
++	lea	`-104-($win64?10*16:0)`(%rsp),%rsp
++	#mov	$in0,$inp			# debugging artefact
++	#lea	64(%rsp),$ctx			# debugging artefact
++___
++$code.=<<___ if ($win64);
++	movaps	%xmm6,96+0(%rsp)
++	movaps	%xmm7,96+16(%rsp)
++	movaps	%xmm8,96+32(%rsp)
++	movaps	%xmm9,96+48(%rsp)
++	movaps	%xmm10,96+64(%rsp)
++	movaps	%xmm11,96+80(%rsp)
++	movaps	%xmm12,96+96(%rsp)
++	movaps	%xmm13,96+112(%rsp)
++	movaps	%xmm14,96+128(%rsp)
++	movaps	%xmm15,96+144(%rsp)
++.Lprologue_avx:
++___
++$code.=<<___;
++	vzeroall
++	mov	$in0,%r12			# reassign arguments
++	mov	$out,%r13
++	mov	$len,%r14
++	lea	112($key),%r15			# size optimization
++	vmovdqu	($ivp),$iv			# load IV
++	mov	$ivp,88(%rsp)			# save $ivp
++___
++($in0,$out,$len,$key)=map("%r$_",(12..15));	# reassign arguments
++my $rounds="${ivp}d";
++$code.=<<___;
++	shl	\$6,$len
++	sub	$in0,$out
++	mov	240-112($key),$rounds
++	add	$inp,$len		# end of input
++
++	lea	K_XX_XX(%rip),$K_XX_XX
++	mov	0($ctx),$A		# load context
++	mov	4($ctx),$B
++	mov	8($ctx),$C
++	mov	12($ctx),$D
++	mov	$B,@T[0]		# magic seed
++	mov	16($ctx),$E
++	mov	$C,@T[1]
++	xor	$D,@T[1]
++	and	@T[1],@T[0]
++
++	vmovdqa	64($K_XX_XX),@X[2]	# pbswap mask
++	vmovdqa	0($K_XX_XX),$Kx		# K_00_19
++	vmovdqu	0($inp),@X[-4&7]	# load input to %xmm[0-3]
++	vmovdqu	16($inp),@X[-3&7]
++	vmovdqu	32($inp),@X[-2&7]
++	vmovdqu	48($inp),@X[-1&7]
++	vpshufb	@X[2],@X[-4&7],@X[-4&7]	# byte swap
++	add	\$64,$inp
++	vpshufb	@X[2],@X[-3&7],@X[-3&7]
++	vpshufb	@X[2],@X[-2&7],@X[-2&7]
++	vpshufb	@X[2],@X[-1&7],@X[-1&7]
++	vpaddd	$Kx,@X[-4&7],@X[0]	# add K_00_19
++	vpaddd	$Kx,@X[-3&7],@X[1]
++	vpaddd	$Kx,@X[-2&7],@X[2]
++	vmovdqa	@X[0],0(%rsp)		# X[]+K xfer to IALU
++	vmovdqa	@X[1],16(%rsp)
++	vmovdqa	@X[2],32(%rsp)
++	vmovups	-112($key),$rndkey[1]	# $key[0]
++	vmovups	16-112($key),$rndkey[0]	# forward reference
++	jmp	.Loop_avx
++___
++
++my $aesenc=sub {
++  use integer;
++  my ($n,$k)=($r/10,$r%10);
++    if ($k==0) {
++      $code.=<<___;
++	vmovdqu		`16*$n`($in0),$in		# load input
++	vpxor		$rndkey[1],$in,$in
++___
++      $code.=<<___ if ($n);
++	vmovups		$iv,`16*($n-1)`($out,$in0)	# write output
++___
++      $code.=<<___;
++	vpxor		$in,$iv,$iv
++	vaesenc		$rndkey[0],$iv,$iv
++	vmovups		`32+16*$k-112`($key),$rndkey[1]
++___
++    } elsif ($k==9) {
++      $sn++;
++      $code.=<<___;
++	cmp		\$11,$rounds
++	jb		.Lvaesenclast$sn
++	vaesenc		$rndkey[0],$iv,$iv
++	vmovups		`32+16*($k+0)-112`($key),$rndkey[1]
++	vaesenc		$rndkey[1],$iv,$iv
++	vmovups		`32+16*($k+1)-112`($key),$rndkey[0]
++	je		.Lvaesenclast$sn
++	vaesenc		$rndkey[0],$iv,$iv
++	vmovups		`32+16*($k+2)-112`($key),$rndkey[1]
++	vaesenc		$rndkey[1],$iv,$iv
++	vmovups		`32+16*($k+3)-112`($key),$rndkey[0]
++.Lvaesenclast$sn:
++	vaesenclast	$rndkey[0],$iv,$iv
++	vmovups		-112($key),$rndkey[0]
++	vmovups		16-112($key),$rndkey[1]		# forward reference
++___
++    } else {
++      $code.=<<___;
++	vaesenc		$rndkey[0],$iv,$iv
++	vmovups		`32+16*$k-112`($key),$rndkey[1]
++___
++    }
++    $r++;	unshift(@rndkey,pop(@rndkey));
++};
++
++sub Xupdate_avx_16_31()		# recall that $Xi starts wtih 4
++{ use integer;
++  my $body = shift;
++  my @insns = (&$body,&$body,&$body,&$body);	# 40 instructions
++  my ($a,$b,$c,$d,$e);
++
++	 eval(shift(@insns));
++	 eval(shift(@insns));
++	&vpalignr(@X[0],@X[-3&7],@X[-4&7],8);	# compose "X[-14]" in "X[0]"
++	 eval(shift(@insns));
++	 eval(shift(@insns));
++
++	  &vpaddd	(@Tx[1],$Kx,@X[-1&7]);
++	 eval(shift(@insns));
++	 eval(shift(@insns));
++	&vpsrldq(@Tx[0],@X[-1&7],4);		# "X[-3]", 3 dwords
++	 eval(shift(@insns));
++	 eval(shift(@insns));
++	&vpxor	(@X[0],@X[0],@X[-4&7]);		# "X[0]"^="X[-16]"
++	 eval(shift(@insns));
++	 eval(shift(@insns));
++
++	&vpxor	(@Tx[0],@Tx[0],@X[-2&7]);	# "X[-3]"^"X[-8]"
++	 eval(shift(@insns));
++	 eval(shift(@insns));
++	 eval(shift(@insns));
++	 eval(shift(@insns));
++
++	&vpxor	(@X[0],@X[0],@Tx[0]);		# "X[0]"^="X[-3]"^"X[-8]"
++	 eval(shift(@insns));
++	 eval(shift(@insns));
++	  &vmovdqa	(eval(16*(($Xi-1)&3))."(%rsp)",@Tx[1]);	# X[]+K xfer to IALU
++	 eval(shift(@insns));
++	 eval(shift(@insns));
++
++	&vpsrld	(@Tx[0],@X[0],31);
++	 eval(shift(@insns));
++	 eval(shift(@insns));
++	 eval(shift(@insns));
++	 eval(shift(@insns));
++
++	&vpslldq(@Tx[1],@X[0],12);		# "X[0]"<<96, extract one dword
++	&vpaddd	(@X[0],@X[0],@X[0]);
++	 eval(shift(@insns));
++	 eval(shift(@insns));
++	 eval(shift(@insns));
++	 eval(shift(@insns));
++
++	&vpor	(@X[0],@X[0],@Tx[0]);		# "X[0]"<<<=1
++	&vpsrld	(@Tx[0],@Tx[1],30);
++	 eval(shift(@insns));
++	 eval(shift(@insns));
++	 eval(shift(@insns));
++	 eval(shift(@insns));
++
++	&vpslld	(@Tx[1],@Tx[1],2);
++	&vpxor	(@X[0],@X[0],@Tx[0]);
++	 eval(shift(@insns));
++	 eval(shift(@insns));
++	 eval(shift(@insns));
++	 eval(shift(@insns));
++
++	&vpxor	(@X[0],@X[0],@Tx[1]);		# "X[0]"^=("X[0]">>96)<<<2
++	 eval(shift(@insns));
++	 eval(shift(@insns));
++	  &vmovdqa	($Kx,eval(16*(($Xi)/5))."($K_XX_XX)")	if ($Xi%5==0);	# K_XX_XX
++	 eval(shift(@insns));
++	 eval(shift(@insns));
++
++
++	 foreach (@insns) { eval; }	# remaining instructions [if any]
++
++  $Xi++;	push(@X,shift(@X));	# "rotate" X[]
++}
++
++sub Xupdate_avx_32_79()
++{ use integer;
++  my $body = shift;
++  my @insns = (&$body,&$body,&$body,&$body);	# 32 to 48 instructions
++  my ($a,$b,$c,$d,$e);
++
++	&vpalignr(@Tx[0],@X[-1&7],@X[-2&7],8);	# compose "X[-6]"
++	&vpxor	(@X[0],@X[0],@X[-4&7]);		# "X[0]"="X[-32]"^"X[-16]"
++	 eval(shift(@insns));		# body_20_39
++	 eval(shift(@insns));
++	 eval(shift(@insns));
++	 eval(shift(@insns));		# rol
++
++	&vpxor	(@X[0],@X[0],@X[-7&7]);		# "X[0]"^="X[-28]"
++	 eval(shift(@insns));
++	 eval(shift(@insns))	if (@insns[0] !~ /&ro[rl]/);
++	  &vpaddd	(@Tx[1],$Kx,@X[-1&7]);
++	  &vmovdqa	($Kx,eval(16*($Xi/5))."($K_XX_XX)")	if ($Xi%5==0);
++	 eval(shift(@insns));		# ror
++	 eval(shift(@insns));
++
++	&vpxor	(@X[0],@X[0],@Tx[0]);		# "X[0]"^="X[-6]"
++	 eval(shift(@insns));		# body_20_39
++	 eval(shift(@insns));
++	 eval(shift(@insns));
++	 eval(shift(@insns));		# rol
++
++	&vpsrld	(@Tx[0],@X[0],30);
++	  &vmovdqa	(eval(16*(($Xi-1)&3))."(%rsp)",@Tx[1]);	# X[]+K xfer to IALU
++	 eval(shift(@insns));
++	 eval(shift(@insns));
++	 eval(shift(@insns));		# ror
++	 eval(shift(@insns));
++
++	&vpslld	(@X[0],@X[0],2);
++	 eval(shift(@insns));		# body_20_39
++	 eval(shift(@insns));
++	 eval(shift(@insns));
++	 eval(shift(@insns));		# rol
++	 eval(shift(@insns));
++	 eval(shift(@insns));
++	 eval(shift(@insns));		# ror
++	 eval(shift(@insns));
++
++	&vpor	(@X[0],@X[0],@Tx[0]);		# "X[0]"<<<=2
++	 eval(shift(@insns));		# body_20_39
++	 eval(shift(@insns));
++	 eval(shift(@insns));
++	 eval(shift(@insns));		# rol
++	 eval(shift(@insns));
++	 eval(shift(@insns));
++	 eval(shift(@insns));		# rol
++	 eval(shift(@insns));
++
++	 foreach (@insns) { eval; }	# remaining instructions
++
++  $Xi++;	push(@X,shift(@X));	# "rotate" X[]
++}
++
++sub Xuplast_avx_80()
++{ use integer;
++  my $body = shift;
++  my @insns = (&$body,&$body,&$body,&$body);	# 32 instructions
++  my ($a,$b,$c,$d,$e);
++
++	 eval(shift(@insns));
++	  &vpaddd	(@Tx[1],$Kx,@X[-1&7]);
++	 eval(shift(@insns));
++	 eval(shift(@insns));
++	 eval(shift(@insns));
++	 eval(shift(@insns));
++
++	  &vmovdqa	(eval(16*(($Xi-1)&3))."(%rsp)",@Tx[1]);	# X[]+K xfer IALU
++
++	 foreach (@insns) { eval; }		# remaining instructions
++
++	&cmp	($inp,$len);
++	&je	(shift);
++
++	&vmovdqa(@Tx[1],"64($K_XX_XX)");	# pbswap mask
++	&vmovdqa($Kx,"0($K_XX_XX)");		# K_00_19
++	&vmovdqu(@X[-4&7],"0($inp)");		# load input
++	&vmovdqu(@X[-3&7],"16($inp)");
++	&vmovdqu(@X[-2&7],"32($inp)");
++	&vmovdqu(@X[-1&7],"48($inp)");
++	&vpshufb(@X[-4&7],@X[-4&7],@Tx[1]);	# byte swap
++	&add	($inp,64);
++
++  $Xi=0;
++}
++
++sub Xloop_avx()
++{ use integer;
++  my $body = shift;
++  my @insns = (&$body,&$body,&$body,&$body);	# 32 instructions
++  my ($a,$b,$c,$d,$e);
++
++	 eval(shift(@insns));
++	 eval(shift(@insns));
++	&vpshufb(@X[($Xi-3)&7],@X[($Xi-3)&7],@Tx[1]);
++	 eval(shift(@insns));
++	 eval(shift(@insns));
++	&vpaddd	(@Tx[0],@X[($Xi-4)&7],$Kx);
++	 eval(shift(@insns));
++	 eval(shift(@insns));
++	 eval(shift(@insns));
++	 eval(shift(@insns));
++	&vmovdqa(eval(16*$Xi)."(%rsp)",@Tx[0]);	# X[]+K xfer to IALU
++	 eval(shift(@insns));
++	 eval(shift(@insns));
++
++	foreach (@insns) { eval; }
++  $Xi++;
++}
++
++sub Xtail_avx()
++{ use integer;
++  my $body = shift;
++  my @insns = (&$body,&$body,&$body,&$body);	# 32 instructions
++  my ($a,$b,$c,$d,$e);
++
++	foreach (@insns) { eval; }
++}
++
++$code.=<<___;
++.align	32
++.Loop_avx:
++___
++	&Xupdate_avx_16_31(\&body_00_19);
++	&Xupdate_avx_16_31(\&body_00_19);
++	&Xupdate_avx_16_31(\&body_00_19);
++	&Xupdate_avx_16_31(\&body_00_19);
++	&Xupdate_avx_32_79(\&body_00_19);
++	&Xupdate_avx_32_79(\&body_20_39);
++	&Xupdate_avx_32_79(\&body_20_39);
++	&Xupdate_avx_32_79(\&body_20_39);
++	&Xupdate_avx_32_79(\&body_20_39);
++	&Xupdate_avx_32_79(\&body_20_39);
++	&Xupdate_avx_32_79(\&body_40_59);
++	&Xupdate_avx_32_79(\&body_40_59);
++	&Xupdate_avx_32_79(\&body_40_59);
++	&Xupdate_avx_32_79(\&body_40_59);
++	&Xupdate_avx_32_79(\&body_40_59);
++	&Xupdate_avx_32_79(\&body_20_39);
++	&Xuplast_avx_80(\&body_20_39,".Ldone_avx");	# can jump to "done"
++
++				$saved_j=$j; @saved_V=@V;
++				$saved_r=$r; @saved_rndkey=@rndkey;
++
++	&Xloop_avx(\&body_20_39);
++	&Xloop_avx(\&body_20_39);
++	&Xloop_avx(\&body_20_39);
++
++$code.=<<___;
++	vmovups	$iv,48($out,$in0)		# write output
++	lea	64($in0),$in0
++
++	add	0($ctx),$A			# update context
++	add	4($ctx),@T[0]
++	add	8($ctx),$C
++	add	12($ctx),$D
++	mov	$A,0($ctx)
++	add	16($ctx),$E
++	mov	@T[0],4($ctx)
++	mov	@T[0],$B			# magic seed
++	mov	$C,8($ctx)
++	mov	$C,@T[1]
++	mov	$D,12($ctx)
++	xor	$D,@T[1]
++	mov	$E,16($ctx)
++	and	@T[1],@T[0]
++	jmp	.Loop_avx
++
++.Ldone_avx:
++___
++				$jj=$j=$saved_j; @V=@saved_V;
++				$r=$saved_r;     @rndkey=@saved_rndkey;
++
++	&Xtail_avx(\&body_20_39);
++	&Xtail_avx(\&body_20_39);
++	&Xtail_avx(\&body_20_39);
++
++$code.=<<___;
++	vmovups	$iv,48($out,$in0)		# write output
++	mov	88(%rsp),$ivp			# restore $ivp
++
++	add	0($ctx),$A			# update context
++	add	4($ctx),@T[0]
++	add	8($ctx),$C
++	mov	$A,0($ctx)
++	add	12($ctx),$D
++	mov	@T[0],4($ctx)
++	add	16($ctx),$E
++	mov	$C,8($ctx)
++	mov	$D,12($ctx)
++	mov	$E,16($ctx)
++	vmovups	$iv,($ivp)			# write IV
++	vzeroall
++___
++$code.=<<___ if ($win64);
++	movaps	96+0(%rsp),%xmm6
++	movaps	96+16(%rsp),%xmm7
++	movaps	96+32(%rsp),%xmm8
++	movaps	96+48(%rsp),%xmm9
++	movaps	96+64(%rsp),%xmm10
++	movaps	96+80(%rsp),%xmm11
++	movaps	96+96(%rsp),%xmm12
++	movaps	96+112(%rsp),%xmm13
++	movaps	96+128(%rsp),%xmm14
++	movaps	96+144(%rsp),%xmm15
++___
++$code.=<<___;
++	lea	`104+($win64?10*16:0)`(%rsp),%rsi
++	mov	0(%rsi),%r15
++	mov	8(%rsi),%r14
++	mov	16(%rsi),%r13
++	mov	24(%rsi),%r12
++	mov	32(%rsi),%rbp
++	mov	40(%rsi),%rbx
++	lea	48(%rsi),%rsp
++.Lepilogue_avx:
++	ret
++.size	aesni_cbc_sha1_enc_avx,.-aesni_cbc_sha1_enc_avx
++___
++
++						if ($stitched_decrypt) {{{
++# reset
++($in0,$out,$len,$key,$ivp,$ctx,$inp)=("%rdi","%rsi","%rdx","%rcx","%r8","%r9","%r10");
++
++$j=$jj=$r=$rx=0;
++$Xi=4;
++
++@aes256_dec = (
++	'&vpxor	($inout0,$rndkey0,"0x00($in0)");',
++	'&vpxor	($inout1,$rndkey0,"0x10($in0)");',
++	'&vpxor	($inout2,$rndkey0,"0x20($in0)");',
++	'&vpxor	($inout3,$rndkey0,"0x30($in0)");',
++
++	'&vmovups($rndkey0,"16-112($key)");',
++	'&vmovups("64(%rsp)",@X[2]);',		# save IV, originally @X[3]
++	undef,undef
++	);
++for ($i=0;$i<13;$i++) {
++    push (@aes256_dec,(
++	'&vaesdec	($inout0,$inout0,$rndkey0);',
++	'&vaesdec	($inout1,$inout1,$rndkey0);',
++	'&vaesdec	($inout2,$inout2,$rndkey0);',
++	'&vaesdec	($inout3,$inout3,$rndkey0);	&vmovups($rndkey0,"'.(16*($i+2)-112).'($key)");'
++	));
++    push (@aes256_dec,(undef,undef))	if (($i>=3 && $i<=5) || $i>=11);
++    push (@aes256_dec,(undef,undef))	if ($i==5);
++}
++push(@aes256_dec,(
++	'&vaesdeclast	($inout0,$inout0,$rndkey0);	&vmovups(@X[0],"0x00($in0)");',
++	'&vaesdeclast	($inout1,$inout1,$rndkey0);	&vmovups(@X[1],"0x10($in0)");',
++	'&vaesdeclast	($inout2,$inout2,$rndkey0);	&vmovups(@X[2],"0x20($in0)");',
++	'&vaesdeclast	($inout3,$inout3,$rndkey0);	&vmovups(@X[3],"0x30($in0)");',
++
++	'&vxorps	($inout0,$inout0,"64(%rsp)");	&vmovdqu($rndkey0,"-112($key)");',
++	'&vxorps	($inout1,$inout1,@X[0]);	&vmovups("0x00($out,$in0)",$inout0);',
++	'&vxorps	($inout2,$inout2,@X[1]);	&vmovups("0x10($out,$in0)",$inout1);',
++	'&vxorps	($inout3,$inout3,@X[2]);	&vmovups("0x20($out,$in0)",$inout2);',
++
++	'&vmovups	("0x30($out,$in0)",$inout3);'
++	));
++
++$code.=<<___;
++.type	aesni256_cbc_sha1_dec_avx,\@function,6
++.align	32
++aesni256_cbc_sha1_dec_avx:
++	mov	`($win64?56:8)`(%rsp),$inp	# load 7th argument
++	push	%rbx
++	push	%rbp
++	push	%r12
++	push	%r13
++	push	%r14
++	push	%r15
++	lea	`-104-($win64?10*16:0)`(%rsp),%rsp
++___
++$code.=<<___ if ($win64);
++	movaps	%xmm6,96+0(%rsp)
++	movaps	%xmm7,96+16(%rsp)
++	movaps	%xmm8,96+32(%rsp)
++	movaps	%xmm9,96+48(%rsp)
++	movaps	%xmm10,96+64(%rsp)
++	movaps	%xmm11,96+80(%rsp)
++	movaps	%xmm12,96+96(%rsp)
++	movaps	%xmm13,96+112(%rsp)
++	movaps	%xmm14,96+128(%rsp)
++	movaps	%xmm15,96+144(%rsp)
++.Lprologue_dec_avx:
++___
++$code.=<<___;
++	vzeroall
++	mov	$in0,%r12			# reassign arguments
++	mov	$out,%r13
++	mov	$len,%r14
++	lea	112($key),%r15			# size optimization
++	vmovdqu	($ivp),@X[3]			# load IV
++___
++($in0,$out,$len,$key)=map("%r$_",(12..15));	# reassign arguments
++$code.=<<___;
++	shl	\$6,$len
++	sub	$in0,$out
++	add	$inp,$len		# end of input
++
++	lea	K_XX_XX(%rip),$K_XX_XX
++	mov	0($ctx),$A		# load context
++	mov	4($ctx),$B
++	mov	8($ctx),$C
++	mov	12($ctx),$D
++	mov	$B,@T[0]		# magic seed
++	mov	16($ctx),$E
++	mov	$C,@T[1]
++	xor	$D,@T[1]
++	and	@T[1],@T[0]
++
++	vmovdqa	64($K_XX_XX),@X[2]	# pbswap mask
++	vmovdqa	0($K_XX_XX),$Kx		# K_00_19
++	vmovdqu	0($inp),@X[-4&7]	# load input to %xmm[0-3]
++	vmovdqu	16($inp),@X[-3&7]
++	vmovdqu	32($inp),@X[-2&7]
++	vmovdqu	48($inp),@X[-1&7]
++	vpshufb	@X[2],@X[-4&7],@X[-4&7]	# byte swap
++	add	\$64,$inp
++	vpshufb	@X[2],@X[-3&7],@X[-3&7]
++	vpshufb	@X[2],@X[-2&7],@X[-2&7]
++	vpshufb	@X[2],@X[-1&7],@X[-1&7]
++	vpaddd	$Kx,@X[-4&7],@X[0]	# add K_00_19
++	vpaddd	$Kx,@X[-3&7],@X[1]
++	vpaddd	$Kx,@X[-2&7],@X[2]
++	vmovdqa	@X[0],0(%rsp)		# X[]+K xfer to IALU
++	vmovdqa	@X[1],16(%rsp)
++	vmovdqa	@X[2],32(%rsp)
++	vmovups	-112($key),$rndkey0	# $key[0]
++	jmp	.Loop_dec_avx
++
++.align	32
++.Loop_dec_avx:
++___
++	&Xupdate_avx_16_31(\&body_00_19_dec);
++	&Xupdate_avx_16_31(\&body_00_19_dec);
++	&Xupdate_avx_16_31(\&body_00_19_dec);
++	&Xupdate_avx_16_31(\&body_00_19_dec);
++	&Xupdate_avx_32_79(\&body_00_19_dec);
++	&Xupdate_avx_32_79(\&body_20_39_dec);
++	&Xupdate_avx_32_79(\&body_20_39_dec);
++	&Xupdate_avx_32_79(\&body_20_39_dec);
++	&Xupdate_avx_32_79(\&body_20_39_dec);
++	&Xupdate_avx_32_79(\&body_20_39_dec);
++	&Xupdate_avx_32_79(\&body_40_59_dec);
++	&Xupdate_avx_32_79(\&body_40_59_dec);
++	&Xupdate_avx_32_79(\&body_40_59_dec);
++	&Xupdate_avx_32_79(\&body_40_59_dec);
++	&Xupdate_avx_32_79(\&body_40_59_dec);
++	&Xupdate_avx_32_79(\&body_20_39_dec);
++	&Xuplast_avx_80(\&body_20_39_dec,".Ldone_dec_avx");	# can jump to "done"
++
++				$saved_j=$j; @saved_V=@V;
++				$saved_rx=$rx;
++
++	&Xloop_avx(\&body_20_39_dec);
++	&Xloop_avx(\&body_20_39_dec);
++	&Xloop_avx(\&body_20_39_dec);
++
++	eval(@aes256_dec[-1]);			# last store
++$code.=<<___;
++	lea	64($in0),$in0
++
++	add	0($ctx),$A			# update context
++	add	4($ctx),@T[0]
++	add	8($ctx),$C
++	add	12($ctx),$D
++	mov	$A,0($ctx)
++	add	16($ctx),$E
++	mov	@T[0],4($ctx)
++	mov	@T[0],$B			# magic seed
++	mov	$C,8($ctx)
++	mov	$C,@T[1]
++	mov	$D,12($ctx)
++	xor	$D,@T[1]
++	mov	$E,16($ctx)
++	and	@T[1],@T[0]
++	jmp	.Loop_dec_avx
++
++.Ldone_dec_avx:
++___
++				$jj=$j=$saved_j; @V=@saved_V;
++				$rx=$saved_rx;
++
++	&Xtail_avx(\&body_20_39_dec);
++	&Xtail_avx(\&body_20_39_dec);
++	&Xtail_avx(\&body_20_39_dec);
++
++	eval(@aes256_dec[-1]);			# last store
++$code.=<<___;
++
++	add	0($ctx),$A			# update context
++	add	4($ctx),@T[0]
++	add	8($ctx),$C
++	mov	$A,0($ctx)
++	add	12($ctx),$D
++	mov	@T[0],4($ctx)
++	add	16($ctx),$E
++	mov	$C,8($ctx)
++	mov	$D,12($ctx)
++	mov	$E,16($ctx)
++	vmovups	@X[3],($ivp)			# write IV
++	vzeroall
++___
++$code.=<<___ if ($win64);
++	movaps	96+0(%rsp),%xmm6
++	movaps	96+16(%rsp),%xmm7
++	movaps	96+32(%rsp),%xmm8
++	movaps	96+48(%rsp),%xmm9
++	movaps	96+64(%rsp),%xmm10
++	movaps	96+80(%rsp),%xmm11
++	movaps	96+96(%rsp),%xmm12
++	movaps	96+112(%rsp),%xmm13
++	movaps	96+128(%rsp),%xmm14
++	movaps	96+144(%rsp),%xmm15
++___
++$code.=<<___;
++	lea	`104+($win64?10*16:0)`(%rsp),%rsi
++	mov	0(%rsi),%r15
++	mov	8(%rsi),%r14
++	mov	16(%rsi),%r13
++	mov	24(%rsi),%r12
++	mov	32(%rsi),%rbp
++	mov	40(%rsi),%rbx
++	lea	48(%rsi),%rsp
++.Lepilogue_dec_avx:
++	ret
++.size	aesni256_cbc_sha1_dec_avx,.-aesni256_cbc_sha1_dec_avx
++___
++						}}}
++}
++$code.=<<___;
++.align	64
++K_XX_XX:
++.long	0x5a827999,0x5a827999,0x5a827999,0x5a827999	# K_00_19
++.long	0x6ed9eba1,0x6ed9eba1,0x6ed9eba1,0x6ed9eba1	# K_20_39
++.long	0x8f1bbcdc,0x8f1bbcdc,0x8f1bbcdc,0x8f1bbcdc	# K_40_59
++.long	0xca62c1d6,0xca62c1d6,0xca62c1d6,0xca62c1d6	# K_60_79
++.long	0x00010203,0x04050607,0x08090a0b,0x0c0d0e0f	# pbswap mask
++.byte	0xf,0xe,0xd,0xc,0xb,0xa,0x9,0x8,0x7,0x6,0x5,0x4,0x3,0x2,0x1,0x0
++
++.asciz	"AESNI-CBC+SHA1 stitch for x86_64, CRYPTOGAMS by "
++.align	64
++___
++						if ($shaext) {{{
++($in0,$out,$len,$key,$ivp,$ctx,$inp)=("%rdi","%rsi","%rdx","%rcx","%r8","%r9","%r10");
++
++$rounds="%r11d";
++
++($iv,$in,$rndkey0)=map("%xmm$_",(2,14,15));
++@rndkey=("%xmm0","%xmm1");
++$r=0;
++
++my ($BSWAP,$ABCD,$E,$E_,$ABCD_SAVE,$E_SAVE)=map("%xmm$_",(7..12));
++my @MSG=map("%xmm$_",(3..6));
++
++$code.=<<___;
++.type	aesni_cbc_sha1_enc_shaext,\@function,6
++.align	32
++aesni_cbc_sha1_enc_shaext:
++	mov	`($win64?56:8)`(%rsp),$inp	# load 7th argument
++___
++$code.=<<___ if ($win64);
++	lea	`-8-10*16`(%rsp),%rsp
++	movaps	%xmm6,-8-10*16(%rax)
++	movaps	%xmm7,-8-9*16(%rax)
++	movaps	%xmm8,-8-8*16(%rax)
++	movaps	%xmm9,-8-7*16(%rax)
++	movaps	%xmm10,-8-6*16(%rax)
++	movaps	%xmm11,-8-5*16(%rax)
++	movaps	%xmm12,-8-4*16(%rax)
++	movaps	%xmm13,-8-3*16(%rax)
++	movaps	%xmm14,-8-2*16(%rax)
++	movaps	%xmm15,-8-1*16(%rax)
++.Lprologue_shaext:
++___
++$code.=<<___;
++	movdqu	($ctx),$ABCD
++	movd	16($ctx),$E
++	movdqa	K_XX_XX+0x50(%rip),$BSWAP	# byte-n-word swap
++
++	mov	240($key),$rounds
++	sub	$in0,$out
++	movups	($key),$rndkey0			# $key[0]
++	movups	16($key),$rndkey[0]		# forward reference
++	lea	112($key),$key			# size optimization
++
++	pshufd	\$0b00011011,$ABCD,$ABCD	# flip word order
++	pshufd	\$0b00011011,$E,$E		# flip word order
++	jmp	.Loop_shaext
++
++.align	16
++.Loop_shaext:
++___
++	&$aesenc();
++$code.=<<___;
++	movdqu		($inp),@MSG[0]
++	movdqa		$E,$E_SAVE		# offload $E
++	pshufb		$BSWAP,@MSG[0]
++	movdqu		0x10($inp),@MSG[1]
++	movdqa		$ABCD,$ABCD_SAVE	# offload $ABCD
++___
++	&$aesenc();
++$code.=<<___;
++	pshufb		$BSWAP,@MSG[1]
++
++	paddd		@MSG[0],$E
++	movdqu		0x20($inp),@MSG[2]
++	lea		0x40($inp),$inp
++	pxor		$E_SAVE,@MSG[0]		# black magic
++___
++	&$aesenc();
++$code.=<<___;
++	pxor		$E_SAVE,@MSG[0]		# black magic
++	movdqa		$ABCD,$E_
++	pshufb		$BSWAP,@MSG[2]
++	sha1rnds4	\$0,$E,$ABCD		# 0-3
++	sha1nexte	@MSG[1],$E_
++___
++	&$aesenc();
++$code.=<<___;
++	sha1msg1	@MSG[1],@MSG[0]
++	movdqu		-0x10($inp),@MSG[3]
++	movdqa		$ABCD,$E
++	pshufb		$BSWAP,@MSG[3]
++___
++	&$aesenc();
++$code.=<<___;
++	sha1rnds4	\$0,$E_,$ABCD		# 4-7
++	sha1nexte	@MSG[2],$E
++	pxor		@MSG[2],@MSG[0]
++	sha1msg1	@MSG[2],@MSG[1]
++___
++	&$aesenc();
++
++for($i=2;$i<20-4;$i++) {
++$code.=<<___;
++	movdqa		$ABCD,$E_
++	sha1rnds4	\$`int($i/5)`,$E,$ABCD	# 8-11
++	sha1nexte	@MSG[3],$E_
++___
++	&$aesenc();
++$code.=<<___;
++	sha1msg2	@MSG[3],@MSG[0]
++	pxor		@MSG[3],@MSG[1]
++	sha1msg1	@MSG[3],@MSG[2]
++___
++	($E,$E_)=($E_,$E);
++	push(@MSG,shift(@MSG));
++
++	&$aesenc();
++}
++$code.=<<___;
++	movdqa		$ABCD,$E_
++	sha1rnds4	\$3,$E,$ABCD		# 64-67
++	sha1nexte	@MSG[3],$E_
++	sha1msg2	@MSG[3],@MSG[0]
++	pxor		@MSG[3],@MSG[1]
++___
++	&$aesenc();
++$code.=<<___;
++	movdqa		$ABCD,$E
++	sha1rnds4	\$3,$E_,$ABCD		# 68-71
++	sha1nexte	@MSG[0],$E
++	sha1msg2	@MSG[0],@MSG[1]
++___
++	&$aesenc();
++$code.=<<___;
++	movdqa		$E_SAVE,@MSG[0]
++	movdqa		$ABCD,$E_
++	sha1rnds4	\$3,$E,$ABCD		# 72-75
++	sha1nexte	@MSG[1],$E_
++___
++	&$aesenc();
++$code.=<<___;
++	movdqa		$ABCD,$E
++	sha1rnds4	\$3,$E_,$ABCD		# 76-79
++	sha1nexte	$MSG[0],$E
++___
++	while($r<40)	{ &$aesenc(); }		# remaining aesenc's
++$code.=<<___;
++	dec		$len
++
++	paddd		$ABCD_SAVE,$ABCD
++	movups		$iv,48($out,$in0)	# write output
++	lea		64($in0),$in0
++	jnz		.Loop_shaext
++
++	pshufd	\$0b00011011,$ABCD,$ABCD
++	pshufd	\$0b00011011,$E,$E
++	movups	$iv,($ivp)			# write IV
++	movdqu	$ABCD,($ctx)
++	movd	$E,16($ctx)
++___
++$code.=<<___ if ($win64);
++	movaps	-8-10*16(%rax),%xmm6
++	movaps	-8-9*16(%rax),%xmm7
++	movaps	-8-8*16(%rax),%xmm8
++	movaps	-8-7*16(%rax),%xmm9
++	movaps	-8-6*16(%rax),%xmm10
++	movaps	-8-5*16(%rax),%xmm11
++	movaps	-8-4*16(%rax),%xmm12
++	movaps	-8-3*16(%rax),%xmm13
++	movaps	-8-2*16(%rax),%xmm14
++	movaps	-8-1*16(%rax),%xmm15
++	mov	%rax,%rsp
++.Lepilogue_shaext:
++___
++$code.=<<___;
++	ret
++.size	aesni_cbc_sha1_enc_shaext,.-aesni_cbc_sha1_enc_shaext
++___
++						}}}
++# EXCEPTION_DISPOSITION handler (EXCEPTION_RECORD *rec,ULONG64 frame,
++#		CONTEXT *context,DISPATCHER_CONTEXT *disp)
++if ($win64) {
++$rec="%rcx";
++$frame="%rdx";
++$context="%r8";
++$disp="%r9";
++
++$code.=<<___;
++.extern	__imp_RtlVirtualUnwind
++.type	ssse3_handler,\@abi-omnipotent
++.align	16
++ssse3_handler:
++	push	%rsi
++	push	%rdi
++	push	%rbx
++	push	%rbp
++	push	%r12
++	push	%r13
++	push	%r14
++	push	%r15
++	pushfq
++	sub	\$64,%rsp
++
++	mov	120($context),%rax	# pull context->Rax
++	mov	248($context),%rbx	# pull context->Rip
++
++	mov	8($disp),%rsi		# disp->ImageBase
++	mov	56($disp),%r11		# disp->HandlerData
++
++	mov	0(%r11),%r10d		# HandlerData[0]
++	lea	(%rsi,%r10),%r10	# prologue label
++	cmp	%r10,%rbx		# context->RipRsp
++
++	mov	4(%r11),%r10d		# HandlerData[1]
++	lea	(%rsi,%r10),%r10	# epilogue label
++	cmp	%r10,%rbx		# context->Rip>=epilogue label
++	jae	.Lcommon_seh_tail
++___
++$code.=<<___ if ($shaext);
++	lea	aesni_cbc_sha1_enc_shaext(%rip),%r10
++	cmp	%r10,%rbx
++	jb	.Lseh_no_shaext
++
++	lea	(%rax),%rsi
++	lea	512($context),%rdi	# &context.Xmm6
++	mov	\$20,%ecx
++	.long	0xa548f3fc		# cld; rep movsq
++	lea	168(%rax),%rax		# adjust stack pointer
++	jmp	.Lcommon_seh_tail
++.Lseh_no_shaext:
++___
++$code.=<<___;
++	lea	96(%rax),%rsi
++	lea	512($context),%rdi	# &context.Xmm6
++	mov	\$20,%ecx
++	.long	0xa548f3fc		# cld; rep movsq
++	lea	`104+10*16`(%rax),%rax	# adjust stack pointer
++
++	mov	0(%rax),%r15
++	mov	8(%rax),%r14
++	mov	16(%rax),%r13
++	mov	24(%rax),%r12
++	mov	32(%rax),%rbp
++	mov	40(%rax),%rbx
++	lea	48(%rax),%rax
++	mov	%rbx,144($context)	# restore context->Rbx
++	mov	%rbp,160($context)	# restore context->Rbp
++	mov	%r12,216($context)	# restore context->R12
++	mov	%r13,224($context)	# restore context->R13
++	mov	%r14,232($context)	# restore context->R14
++	mov	%r15,240($context)	# restore context->R15
++
++.Lcommon_seh_tail:
++	mov	8(%rax),%rdi
++	mov	16(%rax),%rsi
++	mov	%rax,152($context)	# restore context->Rsp
++	mov	%rsi,168($context)	# restore context->Rsi
++	mov	%rdi,176($context)	# restore context->Rdi
++
++	mov	40($disp),%rdi		# disp->ContextRecord
++	mov	$context,%rsi		# context
++	mov	\$154,%ecx		# sizeof(CONTEXT)
++	.long	0xa548f3fc		# cld; rep movsq
++
++	mov	$disp,%rsi
++	xor	%rcx,%rcx		# arg1, UNW_FLAG_NHANDLER
++	mov	8(%rsi),%rdx		# arg2, disp->ImageBase
++	mov	0(%rsi),%r8		# arg3, disp->ControlPc
++	mov	16(%rsi),%r9		# arg4, disp->FunctionEntry
++	mov	40(%rsi),%r10		# disp->ContextRecord
++	lea	56(%rsi),%r11		# &disp->HandlerData
++	lea	24(%rsi),%r12		# &disp->EstablisherFrame
++	mov	%r10,32(%rsp)		# arg5
++	mov	%r11,40(%rsp)		# arg6
++	mov	%r12,48(%rsp)		# arg7
++	mov	%rcx,56(%rsp)		# arg8, (NULL)
++	call	*__imp_RtlVirtualUnwind(%rip)
++
++	mov	\$1,%eax		# ExceptionContinueSearch
++	add	\$64,%rsp
++	popfq
++	pop	%r15
++	pop	%r14
++	pop	%r13
++	pop	%r12
++	pop	%rbp
++	pop	%rbx
++	pop	%rdi
++	pop	%rsi
++	ret
++.size	ssse3_handler,.-ssse3_handler
++
++.section	.pdata
++.align	4
++	.rva	.LSEH_begin_aesni_cbc_sha1_enc_ssse3
++	.rva	.LSEH_end_aesni_cbc_sha1_enc_ssse3
++	.rva	.LSEH_info_aesni_cbc_sha1_enc_ssse3
++___
++$code.=<<___ if ($avx);
++	.rva	.LSEH_begin_aesni_cbc_sha1_enc_avx
++	.rva	.LSEH_end_aesni_cbc_sha1_enc_avx
++	.rva	.LSEH_info_aesni_cbc_sha1_enc_avx
++___
++$code.=<<___ if ($shaext);
++	.rva	.LSEH_begin_aesni_cbc_sha1_enc_shaext
++	.rva	.LSEH_end_aesni_cbc_sha1_enc_shaext
++	.rva	.LSEH_info_aesni_cbc_sha1_enc_shaext
++___
++$code.=<<___;
++.section	.xdata
++.align	8
++.LSEH_info_aesni_cbc_sha1_enc_ssse3:
++	.byte	9,0,0,0
++	.rva	ssse3_handler
++	.rva	.Lprologue_ssse3,.Lepilogue_ssse3	# HandlerData[]
++___
++$code.=<<___ if ($avx);
++.LSEH_info_aesni_cbc_sha1_enc_avx:
++	.byte	9,0,0,0
++	.rva	ssse3_handler
++	.rva	.Lprologue_avx,.Lepilogue_avx		# HandlerData[]
++___
++$code.=<<___ if ($shaext);
++.LSEH_info_aesni_cbc_sha1_enc_shaext:
++	.byte	9,0,0,0
++	.rva	ssse3_handler
++	.rva	.Lprologue_shaext,.Lepilogue_shaext	# HandlerData[]
++___
++}
++
++####################################################################
++sub rex {
++  local *opcode=shift;
++  my ($dst,$src)=@_;
++  my $rex=0;
++
++    $rex|=0x04			if($dst>=8);
++    $rex|=0x01			if($src>=8);
++    unshift @opcode,$rex|0x40	if($rex);
++}
++
++sub sha1rnds4 {
++    if (@_[0] =~ /\$([x0-9a-f]+),\s*%xmm([0-9]+),\s*%xmm([0-9]+)/) {
++      my @opcode=(0x0f,0x3a,0xcc);
++	rex(\@opcode,$3,$2);
++	push @opcode,0xc0|($2&7)|(($3&7)<<3);		# ModR/M
++	my $c=$1;
++	push @opcode,$c=~/^0/?oct($c):$c;
++	return ".byte\t".join(',',@opcode);
++    } else {
++	return "sha1rnds4\t".@_[0];
++    }
++}
++
++sub sha1op38 {
++    my $instr = shift;
++    my %opcodelet = (
++		"sha1nexte" => 0xc8,
++  		"sha1msg1"  => 0xc9,
++		"sha1msg2"  => 0xca	);
++
++    if (defined($opcodelet{$instr}) && @_[0] =~ /%xmm([0-9]+),\s*%xmm([0-9]+)/) {
++      my @opcode=(0x0f,0x38);
++	rex(\@opcode,$2,$1);
++	push @opcode,$opcodelet{$instr};
++	push @opcode,0xc0|($1&7)|(($2&7)<<3);		# ModR/M
++	return ".byte\t".join(',',@opcode);
++    } else {
++	return $instr."\t".@_[0];
++    }
++}
++
++sub aesni {
++  my $line=shift;
++  my @opcode=(0x0f,0x38);
++
++    if ($line=~/(aes[a-z]+)\s+%xmm([0-9]+),\s*%xmm([0-9]+)/) {
++	my %opcodelet = (
++		"aesenc" => 0xdc,	"aesenclast" => 0xdd,
++		"aesdec" => 0xde,	"aesdeclast" => 0xdf
++	);
++	return undef if (!defined($opcodelet{$1}));
++	rex(\@opcode,$3,$2);
++	push @opcode,$opcodelet{$1},0xc0|($2&7)|(($3&7)<<3);	# ModR/M
++	unshift @opcode,0x66;
++	return ".byte\t".join(',',@opcode);
++    }
++    return $line;
++}
++
++foreach (split("\n",$code)) {
++        s/\`([^\`]*)\`/eval $1/geo;
++
++	s/\b(sha1rnds4)\s+(.*)/sha1rnds4($2)/geo		or
++	s/\b(sha1[^\s]*)\s+(.*)/sha1op38($1,$2)/geo		or
++	s/\b(aes.*%xmm[0-9]+).*$/aesni($1)/geo;
++
++	print $_,"\n";
++}
++close STDOUT;
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/aes/asm/aesni-sha256-x86_64.pl b/CryptoPkg/Library/OpensslLib/openssl/crypto/aes/asm/aesni-sha256-x86_64.pl
+new file mode 100644
+index 0000000..a5fde2e
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/aes/asm/aesni-sha256-x86_64.pl
+@@ -0,0 +1,1713 @@
++#! /usr/bin/env perl
++# Copyright 2013-2016 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
++# in the file LICENSE in the source distribution or at
++# https://www.openssl.org/source/license.html
++
++#
++# ====================================================================
++# Written by Andy Polyakov  for the OpenSSL
++# project. The module is, however, dual licensed under OpenSSL and
++# CRYPTOGAMS licenses depending on where you obtain it. For further
++# details see http://www.openssl.org/~appro/cryptogams/.
++# ====================================================================
++#
++# January 2013
++#
++# This is AESNI-CBC+SHA256 stitch implementation. The idea, as spelled
++# in http://download.intel.com/design/intarch/papers/323686.pdf, is
++# that since AESNI-CBC encrypt exhibit *very* low instruction-level
++# parallelism, interleaving it with another algorithm would allow to
++# utilize processor resources better and achieve better performance.
++# SHA256 instruction sequences(*) are taken from sha512-x86_64.pl and
++# AESNI code is weaved into it. As SHA256 dominates execution time,
++# stitch performance does not depend on AES key length. Below are
++# performance numbers in cycles per processed byte, less is better,
++# for standalone AESNI-CBC encrypt, standalone SHA256, and stitched
++# subroutine:
++#
++#		 AES-128/-192/-256+SHA256	this(**)gain
++# Sandy Bridge	    5.05/6.05/7.05+11.6		13.0	+28%/36%/43%
++# Ivy Bridge	    5.05/6.05/7.05+10.3		11.6	+32%/41%/50%
++# Haswell	    4.43/5.29/6.19+7.80		8.79	+39%/49%/59%
++# Skylake	    2.62/3.14/3.62+7.70		8.10	+27%/34%/40%
++# Bulldozer	    5.77/6.89/8.00+13.7		13.7	+42%/50%/58%
++#
++# (*)	there are XOP, AVX1 and AVX2 code paths, meaning that
++#	Westmere is omitted from loop, this is because gain was not
++#	estimated high enough to justify the effort;
++# (**)	these are EVP-free results, results obtained with 'speed
++#	-evp aes-256-cbc-hmac-sha256' will vary by percent or two;
++
++$flavour = shift;
++$output  = shift;
++if ($flavour =~ /\./) { $output = $flavour; undef $flavour; }
++
++$win64=0; $win64=1 if ($flavour =~ /[nm]asm|mingw64/ || $output =~ /\.asm$/);
++
++$0 =~ m/(.*[\/\\])[^\/\\]+$/; $dir=$1;
++( $xlate="${dir}x86_64-xlate.pl" and -f $xlate ) or
++( $xlate="${dir}../../perlasm/x86_64-xlate.pl" and -f $xlate) or
++die "can't locate x86_64-xlate.pl";
++
++if (`$ENV{CC} -Wa,-v -c -o /dev/null -x assembler /dev/null 2>&1`
++		=~ /GNU assembler version ([2-9]\.[0-9]+)/) {
++	$avx = ($1>=2.19) + ($1>=2.22);
++}
++
++if (!$avx && $win64 && ($flavour =~ /nasm/ || $ENV{ASM} =~ /nasm/) &&
++	   `nasm -v 2>&1` =~ /NASM version ([2-9]\.[0-9]+)/) {
++	$avx = ($1>=2.09) + ($1>=2.10);
++}
++
++if (!$avx && $win64 && ($flavour =~ /masm/ || $ENV{ASM} =~ /ml64/) &&
++	   `ml64 2>&1` =~ /Version ([0-9]+)\./) {
++	$avx = ($1>=10) + ($1>=12);
++}
++
++if (!$avx && `$ENV{CC} -v 2>&1` =~ /((?:^clang|LLVM) version|.*based on LLVM) ([3-9]\.[0-9]+)/) {
++	$avx = ($2>=3.0) + ($2>3.0);
++}
++
++$shaext=$avx;	### set to zero if compiling for 1.0.1
++$avx=1		if (!$shaext && $avx);
++
++open OUT,"| \"$^X\" \"$xlate\" $flavour \"$output\"";
++*STDOUT=*OUT;
++
++$func="aesni_cbc_sha256_enc";
++$TABLE="K256";
++$SZ=4;
++@ROT=($A,$B,$C,$D,$E,$F,$G,$H)=("%eax","%ebx","%ecx","%edx",
++				"%r8d","%r9d","%r10d","%r11d");
++($T1,$a0,$a1,$a2,$a3)=("%r12d","%r13d","%r14d","%r15d","%esi");
++@Sigma0=( 2,13,22);
++@Sigma1=( 6,11,25);
++@sigma0=( 7,18, 3);
++@sigma1=(17,19,10);
++$rounds=64;
++
++########################################################################
++# void aesni_cbc_sha256_enc(const void *inp,
++#			void *out,
++#			size_t length,
++#			const AES_KEY *key,
++#			unsigned char *iv,
++#			SHA256_CTX *ctx,
++#			const void *in0);
++($inp,  $out,  $len,  $key,  $ivp, $ctx, $in0) =
++("%rdi","%rsi","%rdx","%rcx","%r8","%r9","%r10");
++
++$Tbl="%rbp";
++
++$_inp="16*$SZ+0*8(%rsp)";
++$_out="16*$SZ+1*8(%rsp)";
++$_end="16*$SZ+2*8(%rsp)";
++$_key="16*$SZ+3*8(%rsp)";
++$_ivp="16*$SZ+4*8(%rsp)";
++$_ctx="16*$SZ+5*8(%rsp)";
++$_in0="16*$SZ+6*8(%rsp)";
++$_rsp="16*$SZ+7*8(%rsp)";
++$framesz=16*$SZ+8*8;
++
++$code=<<___;
++.text
++
++.extern	OPENSSL_ia32cap_P
++.globl	$func
++.type	$func,\@abi-omnipotent
++.align	16
++$func:
++___
++						if ($avx) {
++$code.=<<___;
++	lea	OPENSSL_ia32cap_P(%rip),%r11
++	mov	\$1,%eax
++	cmp	\$0,`$win64?"%rcx":"%rdi"`
++	je	.Lprobe
++	mov	0(%r11),%eax
++	mov	4(%r11),%r10
++___
++$code.=<<___ if ($shaext);
++	bt	\$61,%r10			# check for SHA
++	jc	${func}_shaext
++___
++$code.=<<___;
++	mov	%r10,%r11
++	shr	\$32,%r11
++
++	test	\$`1<<11`,%r10d			# check for XOP
++	jnz	${func}_xop
++___
++$code.=<<___ if ($avx>1);
++	and	\$`1<<8|1<<5|1<<3`,%r11d	# check for BMI2+AVX2+BMI1
++	cmp	\$`1<<8|1<<5|1<<3`,%r11d
++	je	${func}_avx2
++___
++$code.=<<___;
++	and	\$`1<<28`,%r10d			# check for AVX
++	jnz	${func}_avx
++	ud2
++___
++						}
++$code.=<<___;
++	xor	%eax,%eax
++	cmp	\$0,`$win64?"%rcx":"%rdi"`
++	je	.Lprobe
++	ud2
++.Lprobe:
++	ret
++.size	$func,.-$func
++
++.align	64
++.type	$TABLE,\@object
++$TABLE:
++	.long	0x428a2f98,0x71374491,0xb5c0fbcf,0xe9b5dba5
++	.long	0x428a2f98,0x71374491,0xb5c0fbcf,0xe9b5dba5
++	.long	0x3956c25b,0x59f111f1,0x923f82a4,0xab1c5ed5
++	.long	0x3956c25b,0x59f111f1,0x923f82a4,0xab1c5ed5
++	.long	0xd807aa98,0x12835b01,0x243185be,0x550c7dc3
++	.long	0xd807aa98,0x12835b01,0x243185be,0x550c7dc3
++	.long	0x72be5d74,0x80deb1fe,0x9bdc06a7,0xc19bf174
++	.long	0x72be5d74,0x80deb1fe,0x9bdc06a7,0xc19bf174
++	.long	0xe49b69c1,0xefbe4786,0x0fc19dc6,0x240ca1cc
++	.long	0xe49b69c1,0xefbe4786,0x0fc19dc6,0x240ca1cc
++	.long	0x2de92c6f,0x4a7484aa,0x5cb0a9dc,0x76f988da
++	.long	0x2de92c6f,0x4a7484aa,0x5cb0a9dc,0x76f988da
++	.long	0x983e5152,0xa831c66d,0xb00327c8,0xbf597fc7
++	.long	0x983e5152,0xa831c66d,0xb00327c8,0xbf597fc7
++	.long	0xc6e00bf3,0xd5a79147,0x06ca6351,0x14292967
++	.long	0xc6e00bf3,0xd5a79147,0x06ca6351,0x14292967
++	.long	0x27b70a85,0x2e1b2138,0x4d2c6dfc,0x53380d13
++	.long	0x27b70a85,0x2e1b2138,0x4d2c6dfc,0x53380d13
++	.long	0x650a7354,0x766a0abb,0x81c2c92e,0x92722c85
++	.long	0x650a7354,0x766a0abb,0x81c2c92e,0x92722c85
++	.long	0xa2bfe8a1,0xa81a664b,0xc24b8b70,0xc76c51a3
++	.long	0xa2bfe8a1,0xa81a664b,0xc24b8b70,0xc76c51a3
++	.long	0xd192e819,0xd6990624,0xf40e3585,0x106aa070
++	.long	0xd192e819,0xd6990624,0xf40e3585,0x106aa070
++	.long	0x19a4c116,0x1e376c08,0x2748774c,0x34b0bcb5
++	.long	0x19a4c116,0x1e376c08,0x2748774c,0x34b0bcb5
++	.long	0x391c0cb3,0x4ed8aa4a,0x5b9cca4f,0x682e6ff3
++	.long	0x391c0cb3,0x4ed8aa4a,0x5b9cca4f,0x682e6ff3
++	.long	0x748f82ee,0x78a5636f,0x84c87814,0x8cc70208
++	.long	0x748f82ee,0x78a5636f,0x84c87814,0x8cc70208
++	.long	0x90befffa,0xa4506ceb,0xbef9a3f7,0xc67178f2
++	.long	0x90befffa,0xa4506ceb,0xbef9a3f7,0xc67178f2
++
++	.long	0x00010203,0x04050607,0x08090a0b,0x0c0d0e0f
++	.long	0x00010203,0x04050607,0x08090a0b,0x0c0d0e0f
++	.long	0,0,0,0,   0,0,0,0,   -1,-1,-1,-1
++	.long	0,0,0,0,   0,0,0,0
++	.asciz	"AESNI-CBC+SHA256 stitch for x86_64, CRYPTOGAMS by "
++.align	64
++___
++
++######################################################################
++# SIMD code paths
++#
++{{{
++($iv,$inout,$roundkey,$temp,
++ $mask10,$mask12,$mask14,$offload)=map("%xmm$_",(8..15));
++
++$aesni_cbc_idx=0;
++@aesni_cbc_block = (
++##	&vmovdqu	($roundkey,"0x00-0x80($inp)");'
++##	&vmovdqu	($inout,($inp));
++##	&mov		($_inp,$inp);
++
++	'&vpxor		($inout,$inout,$roundkey);'.
++	' &vmovdqu	($roundkey,"0x10-0x80($inp)");',
++
++	'&vpxor		($inout,$inout,$iv);',
++
++	'&vaesenc	($inout,$inout,$roundkey);'.
++	' &vmovdqu	($roundkey,"0x20-0x80($inp)");',
++
++	'&vaesenc	($inout,$inout,$roundkey);'.
++	' &vmovdqu	($roundkey,"0x30-0x80($inp)");',
++
++	'&vaesenc	($inout,$inout,$roundkey);'.
++	' &vmovdqu	($roundkey,"0x40-0x80($inp)");',
++
++	'&vaesenc	($inout,$inout,$roundkey);'.
++	' &vmovdqu	($roundkey,"0x50-0x80($inp)");',
++
++	'&vaesenc	($inout,$inout,$roundkey);'.
++	' &vmovdqu	($roundkey,"0x60-0x80($inp)");',
++
++	'&vaesenc	($inout,$inout,$roundkey);'.
++	' &vmovdqu	($roundkey,"0x70-0x80($inp)");',
++
++	'&vaesenc	($inout,$inout,$roundkey);'.
++	' &vmovdqu	($roundkey,"0x80-0x80($inp)");',
++
++	'&vaesenc	($inout,$inout,$roundkey);'.
++	' &vmovdqu	($roundkey,"0x90-0x80($inp)");',
++
++	'&vaesenc	($inout,$inout,$roundkey);'.
++	' &vmovdqu	($roundkey,"0xa0-0x80($inp)");',
++
++	'&vaesenclast	($temp,$inout,$roundkey);'.
++	' &vaesenc	($inout,$inout,$roundkey);'.
++	' &vmovdqu	($roundkey,"0xb0-0x80($inp)");',
++
++	'&vpand		($iv,$temp,$mask10);'.
++	' &vaesenc	($inout,$inout,$roundkey);'.
++	' &vmovdqu	($roundkey,"0xc0-0x80($inp)");',
++
++	'&vaesenclast	($temp,$inout,$roundkey);'.
++	' &vaesenc	($inout,$inout,$roundkey);'.
++	' &vmovdqu	($roundkey,"0xd0-0x80($inp)");',
++
++	'&vpand		($temp,$temp,$mask12);'.
++	' &vaesenc	($inout,$inout,$roundkey);'.
++	 '&vmovdqu	($roundkey,"0xe0-0x80($inp)");',
++
++	'&vpor		($iv,$iv,$temp);'.
++	' &vaesenclast	($temp,$inout,$roundkey);'.
++	' &vmovdqu	($roundkey,"0x00-0x80($inp)");'
++
++##	&mov		($inp,$_inp);
++##	&mov		($out,$_out);
++##	&vpand		($temp,$temp,$mask14);
++##	&vpor		($iv,$iv,$temp);
++##	&vmovdqu	($iv,($out,$inp);
++##	&lea		(inp,16($inp));
++);
++
++my $a4=$T1;
++my ($a,$b,$c,$d,$e,$f,$g,$h);
++
++sub AUTOLOAD()		# thunk [simplified] 32-bit style perlasm
++{ my $opcode = $AUTOLOAD; $opcode =~ s/.*:://;
++  my $arg = pop;
++    $arg = "\$$arg" if ($arg*1 eq $arg);
++    $code .= "\t$opcode\t".join(',',$arg,reverse @_)."\n";
++}
++
++sub body_00_15 () {
++	(
++	'($a,$b,$c,$d,$e,$f,$g,$h)=@ROT;'.
++
++	'&ror	($a0,$Sigma1[2]-$Sigma1[1])',
++	'&mov	($a,$a1)',
++	'&mov	($a4,$f)',
++
++	'&xor	($a0,$e)',
++	'&ror	($a1,$Sigma0[2]-$Sigma0[1])',
++	'&xor	($a4,$g)',			# f^g
++
++	'&ror	($a0,$Sigma1[1]-$Sigma1[0])',
++	'&xor	($a1,$a)',
++	'&and	($a4,$e)',			# (f^g)&e
++
++	@aesni_cbc_block[$aesni_cbc_idx++].
++	'&xor	($a0,$e)',
++	'&add	($h,$SZ*($i&15)."(%rsp)")',	# h+=X[i]+K[i]
++	'&mov	($a2,$a)',
++
++	'&ror	($a1,$Sigma0[1]-$Sigma0[0])',
++	'&xor	($a4,$g)',			# Ch(e,f,g)=((f^g)&e)^g
++	'&xor	($a2,$b)',			# a^b, b^c in next round
++
++	'&ror	($a0,$Sigma1[0])',		# Sigma1(e)
++	'&add	($h,$a4)',			# h+=Ch(e,f,g)
++	'&and	($a3,$a2)',			# (b^c)&(a^b)
++
++	'&xor	($a1,$a)',
++	'&add	($h,$a0)',			# h+=Sigma1(e)
++	'&xor	($a3,$b)',			# Maj(a,b,c)=Ch(a^b,c,b)
++
++	'&add	($d,$h)',			# d+=h
++	'&ror	($a1,$Sigma0[0])',		# Sigma0(a)
++	'&add	($h,$a3)',			# h+=Maj(a,b,c)
++
++	'&mov	($a0,$d)',
++	'&add	($a1,$h);'.			# h+=Sigma0(a)
++	'($a2,$a3) = ($a3,$a2); unshift(@ROT,pop(@ROT)); $i++;'
++	);
++}
++
++if ($avx) {{
++######################################################################
++# XOP code path
++#
++$code.=<<___;
++.type	${func}_xop,\@function,6
++.align	64
++${func}_xop:
++.Lxop_shortcut:
++	mov	`($win64?56:8)`(%rsp),$in0	# load 7th parameter
++	push	%rbx
++	push	%rbp
++	push	%r12
++	push	%r13
++	push	%r14
++	push	%r15
++	mov	%rsp,%r11		# copy %rsp
++	sub	\$`$framesz+$win64*16*10`,%rsp
++	and	\$-64,%rsp		# align stack frame
++
++	shl	\$6,$len
++	sub	$inp,$out		# re-bias
++	sub	$inp,$in0
++	add	$inp,$len		# end of input
++
++	#mov	$inp,$_inp		# saved later
++	mov	$out,$_out
++	mov	$len,$_end
++	#mov	$key,$_key		# remains resident in $inp register
++	mov	$ivp,$_ivp
++	mov	$ctx,$_ctx
++	mov	$in0,$_in0
++	mov	%r11,$_rsp
++___
++$code.=<<___ if ($win64);
++	movaps	%xmm6,`$framesz+16*0`(%rsp)
++	movaps	%xmm7,`$framesz+16*1`(%rsp)
++	movaps	%xmm8,`$framesz+16*2`(%rsp)
++	movaps	%xmm9,`$framesz+16*3`(%rsp)
++	movaps	%xmm10,`$framesz+16*4`(%rsp)
++	movaps	%xmm11,`$framesz+16*5`(%rsp)
++	movaps	%xmm12,`$framesz+16*6`(%rsp)
++	movaps	%xmm13,`$framesz+16*7`(%rsp)
++	movaps	%xmm14,`$framesz+16*8`(%rsp)
++	movaps	%xmm15,`$framesz+16*9`(%rsp)
++___
++$code.=<<___;
++.Lprologue_xop:
++	vzeroall
++
++	mov	$inp,%r12		# borrow $a4
++	lea	0x80($key),$inp		# size optimization, reassign
++	lea	$TABLE+`$SZ*2*$rounds+32`(%rip),%r13	# borrow $a0
++	mov	0xf0-0x80($inp),%r14d	# rounds, borrow $a1
++	mov	$ctx,%r15		# borrow $a2
++	mov	$in0,%rsi		# borrow $a3
++	vmovdqu	($ivp),$iv		# load IV
++	sub	\$9,%r14
++
++	mov	$SZ*0(%r15),$A
++	mov	$SZ*1(%r15),$B
++	mov	$SZ*2(%r15),$C
++	mov	$SZ*3(%r15),$D
++	mov	$SZ*4(%r15),$E
++	mov	$SZ*5(%r15),$F
++	mov	$SZ*6(%r15),$G
++	mov	$SZ*7(%r15),$H
++
++	vmovdqa	0x00(%r13,%r14,8),$mask14
++	vmovdqa	0x10(%r13,%r14,8),$mask12
++	vmovdqa	0x20(%r13,%r14,8),$mask10
++	vmovdqu	0x00-0x80($inp),$roundkey
++	jmp	.Lloop_xop
++___
++					if ($SZ==4) {	# SHA256
++    my @X = map("%xmm$_",(0..3));
++    my ($t0,$t1,$t2,$t3) = map("%xmm$_",(4..7));
++
++$code.=<<___;
++.align	16
++.Lloop_xop:
++	vmovdqa	$TABLE+`$SZ*2*$rounds`(%rip),$t3
++	vmovdqu	0x00(%rsi,%r12),@X[0]
++	vmovdqu	0x10(%rsi,%r12),@X[1]
++	vmovdqu	0x20(%rsi,%r12),@X[2]
++	vmovdqu	0x30(%rsi,%r12),@X[3]
++	vpshufb	$t3,@X[0],@X[0]
++	lea	$TABLE(%rip),$Tbl
++	vpshufb	$t3,@X[1],@X[1]
++	vpshufb	$t3,@X[2],@X[2]
++	vpaddd	0x00($Tbl),@X[0],$t0
++	vpshufb	$t3,@X[3],@X[3]
++	vpaddd	0x20($Tbl),@X[1],$t1
++	vpaddd	0x40($Tbl),@X[2],$t2
++	vpaddd	0x60($Tbl),@X[3],$t3
++	vmovdqa	$t0,0x00(%rsp)
++	mov	$A,$a1
++	vmovdqa	$t1,0x10(%rsp)
++	mov	$B,$a3
++	vmovdqa	$t2,0x20(%rsp)
++	xor	$C,$a3			# magic
++	vmovdqa	$t3,0x30(%rsp)
++	mov	$E,$a0
++	jmp	.Lxop_00_47
++
++.align	16
++.Lxop_00_47:
++	sub	\$-16*2*$SZ,$Tbl	# size optimization
++	vmovdqu	(%r12),$inout		# $a4
++	mov	%r12,$_inp		# $a4
++___
++sub XOP_256_00_47 () {
++my $j = shift;
++my $body = shift;
++my @X = @_;
++my @insns = (&$body,&$body,&$body,&$body);	# 104 instructions
++
++	&vpalignr	($t0,@X[1],@X[0],$SZ);	# X[1..4]
++	  eval(shift(@insns));
++	  eval(shift(@insns));
++	 &vpalignr	($t3,@X[3],@X[2],$SZ);	# X[9..12]
++	  eval(shift(@insns));
++	  eval(shift(@insns));
++	&vprotd		($t1,$t0,8*$SZ-$sigma0[1]);
++	  eval(shift(@insns));
++	  eval(shift(@insns));
++	&vpsrld		($t0,$t0,$sigma0[2]);
++	  eval(shift(@insns));
++	  eval(shift(@insns));
++	 &vpaddd	(@X[0],@X[0],$t3);	# X[0..3] += X[9..12]
++	  eval(shift(@insns));
++	  eval(shift(@insns));
++	  eval(shift(@insns));
++	  eval(shift(@insns));
++	&vprotd		($t2,$t1,$sigma0[1]-$sigma0[0]);
++	  eval(shift(@insns));
++	  eval(shift(@insns));
++	&vpxor		($t0,$t0,$t1);
++	  eval(shift(@insns));
++	  eval(shift(@insns));
++	  eval(shift(@insns));
++	  eval(shift(@insns));
++	 &vprotd	($t3,@X[3],8*$SZ-$sigma1[1]);
++	  eval(shift(@insns));
++	  eval(shift(@insns));
++	&vpxor		($t0,$t0,$t2);		# sigma0(X[1..4])
++	  eval(shift(@insns));
++	  eval(shift(@insns));
++	 &vpsrld	($t2,@X[3],$sigma1[2]);
++	  eval(shift(@insns));
++	  eval(shift(@insns));
++	&vpaddd		(@X[0],@X[0],$t0);	# X[0..3] += sigma0(X[1..4])
++	  eval(shift(@insns));
++	  eval(shift(@insns));
++	 &vprotd	($t1,$t3,$sigma1[1]-$sigma1[0]);
++	  eval(shift(@insns));
++	  eval(shift(@insns));
++	 &vpxor		($t3,$t3,$t2);
++	  eval(shift(@insns));
++	  eval(shift(@insns));
++	  eval(shift(@insns));
++	  eval(shift(@insns));
++	 &vpxor		($t3,$t3,$t1);		# sigma1(X[14..15])
++	  eval(shift(@insns));
++	  eval(shift(@insns));
++	  eval(shift(@insns));
++	  eval(shift(@insns));
++	&vpsrldq	($t3,$t3,8);
++	  eval(shift(@insns));
++	  eval(shift(@insns));
++	  eval(shift(@insns));
++	  eval(shift(@insns));
++	&vpaddd		(@X[0],@X[0],$t3);	# X[0..1] += sigma1(X[14..15])
++	  eval(shift(@insns));
++	  eval(shift(@insns));
++	  eval(shift(@insns));
++	  eval(shift(@insns));
++	 &vprotd	($t3,@X[0],8*$SZ-$sigma1[1]);
++	  eval(shift(@insns));
++	  eval(shift(@insns));
++	 &vpsrld	($t2,@X[0],$sigma1[2]);
++	  eval(shift(@insns));
++	  eval(shift(@insns));
++	 &vprotd	($t1,$t3,$sigma1[1]-$sigma1[0]);
++	  eval(shift(@insns));
++	  eval(shift(@insns));
++	 &vpxor		($t3,$t3,$t2);
++	  eval(shift(@insns));
++	  eval(shift(@insns));
++	  eval(shift(@insns));
++	  eval(shift(@insns));
++	 &vpxor		($t3,$t3,$t1);		# sigma1(X[16..17])
++	  eval(shift(@insns));
++	  eval(shift(@insns));
++	  eval(shift(@insns));
++	  eval(shift(@insns));
++	&vpslldq	($t3,$t3,8);		# 22 instructions
++	  eval(shift(@insns));
++	  eval(shift(@insns));
++	  eval(shift(@insns));
++	  eval(shift(@insns));
++	&vpaddd		(@X[0],@X[0],$t3);	# X[2..3] += sigma1(X[16..17])
++	  eval(shift(@insns));
++	  eval(shift(@insns));
++	  eval(shift(@insns));
++	  eval(shift(@insns));
++	&vpaddd		($t2,@X[0],16*2*$j."($Tbl)");
++	  foreach (@insns) { eval; }		# remaining instructions
++	&vmovdqa	(16*$j."(%rsp)",$t2);
++}
++
++    $aesni_cbc_idx=0;
++    for ($i=0,$j=0; $j<4; $j++) {
++	&XOP_256_00_47($j,\&body_00_15,@X);
++	push(@X,shift(@X));			# rotate(@X)
++    }
++    	&mov		("%r12",$_inp);		# borrow $a4
++	&vpand		($temp,$temp,$mask14);
++	&mov		("%r15",$_out);		# borrow $a2
++	&vpor		($iv,$iv,$temp);
++	&vmovdqu	("(%r15,%r12)",$iv);	# write output
++	&lea		("%r12","16(%r12)");	# inp++
++
++	&cmpb	($SZ-1+16*2*$SZ."($Tbl)",0);
++	&jne	(".Lxop_00_47");
++
++	&vmovdqu	($inout,"(%r12)");
++	&mov		($_inp,"%r12");
++
++    $aesni_cbc_idx=0;
++    for ($i=0; $i<16; ) {
++	foreach(body_00_15()) { eval; }
++    }
++					}
++$code.=<<___;
++	mov	$_inp,%r12		# borrow $a4
++	mov	$_out,%r13		# borrow $a0
++	mov	$_ctx,%r15		# borrow $a2
++	mov	$_in0,%rsi		# borrow $a3
++
++	vpand	$mask14,$temp,$temp
++	mov	$a1,$A
++	vpor	$temp,$iv,$iv
++	vmovdqu	$iv,(%r13,%r12)		# write output
++	lea	16(%r12),%r12		# inp++
++
++	add	$SZ*0(%r15),$A
++	add	$SZ*1(%r15),$B
++	add	$SZ*2(%r15),$C
++	add	$SZ*3(%r15),$D
++	add	$SZ*4(%r15),$E
++	add	$SZ*5(%r15),$F
++	add	$SZ*6(%r15),$G
++	add	$SZ*7(%r15),$H
++
++	cmp	$_end,%r12
++
++	mov	$A,$SZ*0(%r15)
++	mov	$B,$SZ*1(%r15)
++	mov	$C,$SZ*2(%r15)
++	mov	$D,$SZ*3(%r15)
++	mov	$E,$SZ*4(%r15)
++	mov	$F,$SZ*5(%r15)
++	mov	$G,$SZ*6(%r15)
++	mov	$H,$SZ*7(%r15)
++
++	jb	.Lloop_xop
++
++	mov	$_ivp,$ivp
++	mov	$_rsp,%rsi
++	vmovdqu	$iv,($ivp)		# output IV
++	vzeroall
++___
++$code.=<<___ if ($win64);
++	movaps	`$framesz+16*0`(%rsp),%xmm6
++	movaps	`$framesz+16*1`(%rsp),%xmm7
++	movaps	`$framesz+16*2`(%rsp),%xmm8
++	movaps	`$framesz+16*3`(%rsp),%xmm9
++	movaps	`$framesz+16*4`(%rsp),%xmm10
++	movaps	`$framesz+16*5`(%rsp),%xmm11
++	movaps	`$framesz+16*6`(%rsp),%xmm12
++	movaps	`$framesz+16*7`(%rsp),%xmm13
++	movaps	`$framesz+16*8`(%rsp),%xmm14
++	movaps	`$framesz+16*9`(%rsp),%xmm15
++___
++$code.=<<___;
++	mov	(%rsi),%r15
++	mov	8(%rsi),%r14
++	mov	16(%rsi),%r13
++	mov	24(%rsi),%r12
++	mov	32(%rsi),%rbp
++	mov	40(%rsi),%rbx
++	lea	48(%rsi),%rsp
++.Lepilogue_xop:
++	ret
++.size	${func}_xop,.-${func}_xop
++___
++######################################################################
++# AVX+shrd code path
++#
++local *ror = sub { &shrd(@_[0],@_) };
++
++$code.=<<___;
++.type	${func}_avx,\@function,6
++.align	64
++${func}_avx:
++.Lavx_shortcut:
++	mov	`($win64?56:8)`(%rsp),$in0	# load 7th parameter
++	push	%rbx
++	push	%rbp
++	push	%r12
++	push	%r13
++	push	%r14
++	push	%r15
++	mov	%rsp,%r11		# copy %rsp
++	sub	\$`$framesz+$win64*16*10`,%rsp
++	and	\$-64,%rsp		# align stack frame
++
++	shl	\$6,$len
++	sub	$inp,$out		# re-bias
++	sub	$inp,$in0
++	add	$inp,$len		# end of input
++
++	#mov	$inp,$_inp		# saved later
++	mov	$out,$_out
++	mov	$len,$_end
++	#mov	$key,$_key		# remains resident in $inp register
++	mov	$ivp,$_ivp
++	mov	$ctx,$_ctx
++	mov	$in0,$_in0
++	mov	%r11,$_rsp
++___
++$code.=<<___ if ($win64);
++	movaps	%xmm6,`$framesz+16*0`(%rsp)
++	movaps	%xmm7,`$framesz+16*1`(%rsp)
++	movaps	%xmm8,`$framesz+16*2`(%rsp)
++	movaps	%xmm9,`$framesz+16*3`(%rsp)
++	movaps	%xmm10,`$framesz+16*4`(%rsp)
++	movaps	%xmm11,`$framesz+16*5`(%rsp)
++	movaps	%xmm12,`$framesz+16*6`(%rsp)
++	movaps	%xmm13,`$framesz+16*7`(%rsp)
++	movaps	%xmm14,`$framesz+16*8`(%rsp)
++	movaps	%xmm15,`$framesz+16*9`(%rsp)
++___
++$code.=<<___;
++.Lprologue_avx:
++	vzeroall
++
++	mov	$inp,%r12		# borrow $a4
++	lea	0x80($key),$inp		# size optimization, reassign
++	lea	$TABLE+`$SZ*2*$rounds+32`(%rip),%r13	# borrow $a0
++	mov	0xf0-0x80($inp),%r14d	# rounds, borrow $a1
++	mov	$ctx,%r15		# borrow $a2
++	mov	$in0,%rsi		# borrow $a3
++	vmovdqu	($ivp),$iv		# load IV
++	sub	\$9,%r14
++
++	mov	$SZ*0(%r15),$A
++	mov	$SZ*1(%r15),$B
++	mov	$SZ*2(%r15),$C
++	mov	$SZ*3(%r15),$D
++	mov	$SZ*4(%r15),$E
++	mov	$SZ*5(%r15),$F
++	mov	$SZ*6(%r15),$G
++	mov	$SZ*7(%r15),$H
++
++	vmovdqa	0x00(%r13,%r14,8),$mask14
++	vmovdqa	0x10(%r13,%r14,8),$mask12
++	vmovdqa	0x20(%r13,%r14,8),$mask10
++	vmovdqu	0x00-0x80($inp),$roundkey
++___
++					if ($SZ==4) {	# SHA256
++    my @X = map("%xmm$_",(0..3));
++    my ($t0,$t1,$t2,$t3) = map("%xmm$_",(4..7));
++
++$code.=<<___;
++	jmp	.Lloop_avx
++.align	16
++.Lloop_avx:
++	vmovdqa	$TABLE+`$SZ*2*$rounds`(%rip),$t3
++	vmovdqu	0x00(%rsi,%r12),@X[0]
++	vmovdqu	0x10(%rsi,%r12),@X[1]
++	vmovdqu	0x20(%rsi,%r12),@X[2]
++	vmovdqu	0x30(%rsi,%r12),@X[3]
++	vpshufb	$t3,@X[0],@X[0]
++	lea	$TABLE(%rip),$Tbl
++	vpshufb	$t3,@X[1],@X[1]
++	vpshufb	$t3,@X[2],@X[2]
++	vpaddd	0x00($Tbl),@X[0],$t0
++	vpshufb	$t3,@X[3],@X[3]
++	vpaddd	0x20($Tbl),@X[1],$t1
++	vpaddd	0x40($Tbl),@X[2],$t2
++	vpaddd	0x60($Tbl),@X[3],$t3
++	vmovdqa	$t0,0x00(%rsp)
++	mov	$A,$a1
++	vmovdqa	$t1,0x10(%rsp)
++	mov	$B,$a3
++	vmovdqa	$t2,0x20(%rsp)
++	xor	$C,$a3			# magic
++	vmovdqa	$t3,0x30(%rsp)
++	mov	$E,$a0
++	jmp	.Lavx_00_47
++
++.align	16
++.Lavx_00_47:
++	sub	\$-16*2*$SZ,$Tbl	# size optimization
++	vmovdqu	(%r12),$inout		# $a4
++	mov	%r12,$_inp		# $a4
++___
++sub Xupdate_256_AVX () {
++	(
++	'&vpalignr	($t0,@X[1],@X[0],$SZ)',	# X[1..4]
++	 '&vpalignr	($t3,@X[3],@X[2],$SZ)',	# X[9..12]
++	'&vpsrld	($t2,$t0,$sigma0[0]);',
++	 '&vpaddd	(@X[0],@X[0],$t3)',	# X[0..3] += X[9..12]
++	'&vpsrld	($t3,$t0,$sigma0[2])',
++	'&vpslld	($t1,$t0,8*$SZ-$sigma0[1]);',
++	'&vpxor		($t0,$t3,$t2)',
++	 '&vpshufd	($t3,@X[3],0b11111010)',# X[14..15]
++	'&vpsrld	($t2,$t2,$sigma0[1]-$sigma0[0]);',
++	'&vpxor		($t0,$t0,$t1)',
++	'&vpslld	($t1,$t1,$sigma0[1]-$sigma0[0]);',
++	'&vpxor		($t0,$t0,$t2)',
++	 '&vpsrld	($t2,$t3,$sigma1[2]);',
++	'&vpxor		($t0,$t0,$t1)',		# sigma0(X[1..4])
++	 '&vpsrlq	($t3,$t3,$sigma1[0]);',
++	'&vpaddd	(@X[0],@X[0],$t0)',	# X[0..3] += sigma0(X[1..4])
++	 '&vpxor	($t2,$t2,$t3);',
++	 '&vpsrlq	($t3,$t3,$sigma1[1]-$sigma1[0])',
++	 '&vpxor	($t2,$t2,$t3)',		# sigma1(X[14..15])
++	 '&vpshufd	($t2,$t2,0b10000100)',
++	 '&vpsrldq	($t2,$t2,8)',
++	'&vpaddd	(@X[0],@X[0],$t2)',	# X[0..1] += sigma1(X[14..15])
++	 '&vpshufd	($t3,@X[0],0b01010000)',# X[16..17]
++	 '&vpsrld	($t2,$t3,$sigma1[2])',
++	 '&vpsrlq	($t3,$t3,$sigma1[0])',
++	 '&vpxor	($t2,$t2,$t3);',
++	 '&vpsrlq	($t3,$t3,$sigma1[1]-$sigma1[0])',
++	 '&vpxor	($t2,$t2,$t3)',
++	 '&vpshufd	($t2,$t2,0b11101000)',
++	 '&vpslldq	($t2,$t2,8)',
++	'&vpaddd	(@X[0],@X[0],$t2)'	# X[2..3] += sigma1(X[16..17])
++	);
++}
++
++sub AVX_256_00_47 () {
++my $j = shift;
++my $body = shift;
++my @X = @_;
++my @insns = (&$body,&$body,&$body,&$body);	# 104 instructions
++
++	foreach (Xupdate_256_AVX()) {		# 29 instructions
++	    eval;
++	    eval(shift(@insns));
++	    eval(shift(@insns));
++	    eval(shift(@insns));
++	}
++	&vpaddd		($t2,@X[0],16*2*$j."($Tbl)");
++	  foreach (@insns) { eval; }		# remaining instructions
++	&vmovdqa	(16*$j."(%rsp)",$t2);
++}
++
++    $aesni_cbc_idx=0;
++    for ($i=0,$j=0; $j<4; $j++) {
++	&AVX_256_00_47($j,\&body_00_15,@X);
++	push(@X,shift(@X));			# rotate(@X)
++    }
++    	&mov		("%r12",$_inp);		# borrow $a4
++	&vpand		($temp,$temp,$mask14);
++	&mov		("%r15",$_out);		# borrow $a2
++	&vpor		($iv,$iv,$temp);
++	&vmovdqu	("(%r15,%r12)",$iv);	# write output
++	&lea		("%r12","16(%r12)");	# inp++
++
++	&cmpb	($SZ-1+16*2*$SZ."($Tbl)",0);
++	&jne	(".Lavx_00_47");
++
++	&vmovdqu	($inout,"(%r12)");
++	&mov		($_inp,"%r12");
++
++    $aesni_cbc_idx=0;
++    for ($i=0; $i<16; ) {
++	foreach(body_00_15()) { eval; }
++    }
++
++					}
++$code.=<<___;
++	mov	$_inp,%r12		# borrow $a4
++	mov	$_out,%r13		# borrow $a0
++	mov	$_ctx,%r15		# borrow $a2
++	mov	$_in0,%rsi		# borrow $a3
++
++	vpand	$mask14,$temp,$temp
++	mov	$a1,$A
++	vpor	$temp,$iv,$iv
++	vmovdqu	$iv,(%r13,%r12)		# write output
++	lea	16(%r12),%r12		# inp++
++
++	add	$SZ*0(%r15),$A
++	add	$SZ*1(%r15),$B
++	add	$SZ*2(%r15),$C
++	add	$SZ*3(%r15),$D
++	add	$SZ*4(%r15),$E
++	add	$SZ*5(%r15),$F
++	add	$SZ*6(%r15),$G
++	add	$SZ*7(%r15),$H
++
++	cmp	$_end,%r12
++
++	mov	$A,$SZ*0(%r15)
++	mov	$B,$SZ*1(%r15)
++	mov	$C,$SZ*2(%r15)
++	mov	$D,$SZ*3(%r15)
++	mov	$E,$SZ*4(%r15)
++	mov	$F,$SZ*5(%r15)
++	mov	$G,$SZ*6(%r15)
++	mov	$H,$SZ*7(%r15)
++	jb	.Lloop_avx
++
++	mov	$_ivp,$ivp
++	mov	$_rsp,%rsi
++	vmovdqu	$iv,($ivp)		# output IV
++	vzeroall
++___
++$code.=<<___ if ($win64);
++	movaps	`$framesz+16*0`(%rsp),%xmm6
++	movaps	`$framesz+16*1`(%rsp),%xmm7
++	movaps	`$framesz+16*2`(%rsp),%xmm8
++	movaps	`$framesz+16*3`(%rsp),%xmm9
++	movaps	`$framesz+16*4`(%rsp),%xmm10
++	movaps	`$framesz+16*5`(%rsp),%xmm11
++	movaps	`$framesz+16*6`(%rsp),%xmm12
++	movaps	`$framesz+16*7`(%rsp),%xmm13
++	movaps	`$framesz+16*8`(%rsp),%xmm14
++	movaps	`$framesz+16*9`(%rsp),%xmm15
++___
++$code.=<<___;
++	mov	(%rsi),%r15
++	mov	8(%rsi),%r14
++	mov	16(%rsi),%r13
++	mov	24(%rsi),%r12
++	mov	32(%rsi),%rbp
++	mov	40(%rsi),%rbx
++	lea	48(%rsi),%rsp
++.Lepilogue_avx:
++	ret
++.size	${func}_avx,.-${func}_avx
++___
++
++if ($avx>1) {{
++######################################################################
++# AVX2+BMI code path
++#
++my $a5=$SZ==4?"%esi":"%rsi";	# zap $inp 
++my $PUSH8=8*2*$SZ;
++use integer;
++
++sub bodyx_00_15 () {
++	# at start $a1 should be zero, $a3 - $b^$c and $a4 copy of $f
++	(
++	'($a,$b,$c,$d,$e,$f,$g,$h)=@ROT;'.
++
++	'&add	($h,(32*($i/(16/$SZ))+$SZ*($i%(16/$SZ)))%$PUSH8.$base)',    # h+=X[i]+K[i]
++	'&and	($a4,$e)',		# f&e
++	'&rorx	($a0,$e,$Sigma1[2])',
++	'&rorx	($a2,$e,$Sigma1[1])',
++
++	'&lea	($a,"($a,$a1)")',	# h+=Sigma0(a) from the past
++	'&lea	($h,"($h,$a4)")',
++	'&andn	($a4,$e,$g)',		# ~e&g
++	'&xor	($a0,$a2)',
++
++	'&rorx	($a1,$e,$Sigma1[0])',
++	'&lea	($h,"($h,$a4)")',	# h+=Ch(e,f,g)=(e&f)+(~e&g)
++	'&xor	($a0,$a1)',		# Sigma1(e)
++	'&mov	($a2,$a)',
++
++	'&rorx	($a4,$a,$Sigma0[2])',
++	'&lea	($h,"($h,$a0)")',	# h+=Sigma1(e)
++	'&xor	($a2,$b)',		# a^b, b^c in next round
++	'&rorx	($a1,$a,$Sigma0[1])',
++
++	'&rorx	($a0,$a,$Sigma0[0])',
++	'&lea	($d,"($d,$h)")',	# d+=h
++	'&and	($a3,$a2)',		# (b^c)&(a^b)
++	@aesni_cbc_block[$aesni_cbc_idx++].
++	'&xor	($a1,$a4)',
++
++	'&xor	($a3,$b)',		# Maj(a,b,c)=Ch(a^b,c,b)
++	'&xor	($a1,$a0)',		# Sigma0(a)
++	'&lea	($h,"($h,$a3)");'.	# h+=Maj(a,b,c)
++	'&mov	($a4,$e)',		# copy of f in future
++
++	'($a2,$a3) = ($a3,$a2); unshift(@ROT,pop(@ROT)); $i++;'
++	);
++	# and at the finish one has to $a+=$a1
++}
++
++$code.=<<___;
++.type	${func}_avx2,\@function,6
++.align	64
++${func}_avx2:
++.Lavx2_shortcut:
++	mov	`($win64?56:8)`(%rsp),$in0	# load 7th parameter
++	push	%rbx
++	push	%rbp
++	push	%r12
++	push	%r13
++	push	%r14
++	push	%r15
++	mov	%rsp,%r11		# copy %rsp
++	sub	\$`2*$SZ*$rounds+8*8+$win64*16*10`,%rsp
++	and	\$-256*$SZ,%rsp		# align stack frame
++	add	\$`2*$SZ*($rounds-8)`,%rsp
++
++	shl	\$6,$len
++	sub	$inp,$out		# re-bias
++	sub	$inp,$in0
++	add	$inp,$len		# end of input
++
++	#mov	$inp,$_inp		# saved later
++	#mov	$out,$_out		# kept in $offload
++	mov	$len,$_end
++	#mov	$key,$_key		# remains resident in $inp register
++	mov	$ivp,$_ivp
++	mov	$ctx,$_ctx
++	mov	$in0,$_in0
++	mov	%r11,$_rsp
++___
++$code.=<<___ if ($win64);
++	movaps	%xmm6,`$framesz+16*0`(%rsp)
++	movaps	%xmm7,`$framesz+16*1`(%rsp)
++	movaps	%xmm8,`$framesz+16*2`(%rsp)
++	movaps	%xmm9,`$framesz+16*3`(%rsp)
++	movaps	%xmm10,`$framesz+16*4`(%rsp)
++	movaps	%xmm11,`$framesz+16*5`(%rsp)
++	movaps	%xmm12,`$framesz+16*6`(%rsp)
++	movaps	%xmm13,`$framesz+16*7`(%rsp)
++	movaps	%xmm14,`$framesz+16*8`(%rsp)
++	movaps	%xmm15,`$framesz+16*9`(%rsp)
++___
++$code.=<<___;
++.Lprologue_avx2:
++	vzeroall
++
++	mov	$inp,%r13		# borrow $a0
++	vpinsrq	\$1,$out,$offload,$offload
++	lea	0x80($key),$inp		# size optimization, reassign
++	lea	$TABLE+`$SZ*2*$rounds+32`(%rip),%r12	# borrow $a4
++	mov	0xf0-0x80($inp),%r14d	# rounds, borrow $a1
++	mov	$ctx,%r15		# borrow $a2
++	mov	$in0,%rsi		# borrow $a3
++	vmovdqu	($ivp),$iv		# load IV
++	lea	-9(%r14),%r14
++
++	vmovdqa	0x00(%r12,%r14,8),$mask14
++	vmovdqa	0x10(%r12,%r14,8),$mask12
++	vmovdqa	0x20(%r12,%r14,8),$mask10
++
++	sub	\$-16*$SZ,%r13		# inp++, size optimization
++	mov	$SZ*0(%r15),$A
++	lea	(%rsi,%r13),%r12	# borrow $a0
++	mov	$SZ*1(%r15),$B
++	cmp	$len,%r13		# $_end
++	mov	$SZ*2(%r15),$C
++	cmove	%rsp,%r12		# next block or random data
++	mov	$SZ*3(%r15),$D
++	mov	$SZ*4(%r15),$E
++	mov	$SZ*5(%r15),$F
++	mov	$SZ*6(%r15),$G
++	mov	$SZ*7(%r15),$H
++	vmovdqu	0x00-0x80($inp),$roundkey
++___
++					if ($SZ==4) {	# SHA256
++    my @X = map("%ymm$_",(0..3));
++    my ($t0,$t1,$t2,$t3) = map("%ymm$_",(4..7));
++
++$code.=<<___;
++	jmp	.Loop_avx2
++.align	16
++.Loop_avx2:
++	vmovdqa	$TABLE+`$SZ*2*$rounds`(%rip),$t3
++	vmovdqu	-16*$SZ+0(%rsi,%r13),%xmm0
++	vmovdqu	-16*$SZ+16(%rsi,%r13),%xmm1
++	vmovdqu	-16*$SZ+32(%rsi,%r13),%xmm2
++	vmovdqu	-16*$SZ+48(%rsi,%r13),%xmm3
++
++	vinserti128	\$1,(%r12),@X[0],@X[0]
++	vinserti128	\$1,16(%r12),@X[1],@X[1]
++	 vpshufb	$t3,@X[0],@X[0]
++	vinserti128	\$1,32(%r12),@X[2],@X[2]
++	 vpshufb	$t3,@X[1],@X[1]
++	vinserti128	\$1,48(%r12),@X[3],@X[3]
++
++	lea	$TABLE(%rip),$Tbl
++	vpshufb	$t3,@X[2],@X[2]
++	lea	-16*$SZ(%r13),%r13
++	vpaddd	0x00($Tbl),@X[0],$t0
++	vpshufb	$t3,@X[3],@X[3]
++	vpaddd	0x20($Tbl),@X[1],$t1
++	vpaddd	0x40($Tbl),@X[2],$t2
++	vpaddd	0x60($Tbl),@X[3],$t3
++	vmovdqa	$t0,0x00(%rsp)
++	xor	$a1,$a1
++	vmovdqa	$t1,0x20(%rsp)
++	lea	-$PUSH8(%rsp),%rsp
++	mov	$B,$a3
++	vmovdqa	$t2,0x00(%rsp)
++	xor	$C,$a3			# magic
++	vmovdqa	$t3,0x20(%rsp)
++	mov	$F,$a4
++	sub	\$-16*2*$SZ,$Tbl	# size optimization
++	jmp	.Lavx2_00_47
++
++.align	16
++.Lavx2_00_47:
++	vmovdqu	(%r13),$inout
++	vpinsrq	\$0,%r13,$offload,$offload
++___
++
++sub AVX2_256_00_47 () {
++my $j = shift;
++my $body = shift;
++my @X = @_;
++my @insns = (&$body,&$body,&$body,&$body);	# 96 instructions
++my $base = "+2*$PUSH8(%rsp)";
++
++	&lea	("%rsp","-$PUSH8(%rsp)")	if (($j%2)==0);
++	foreach (Xupdate_256_AVX()) {		# 29 instructions
++	    eval;
++	    eval(shift(@insns));
++	    eval(shift(@insns));
++	    eval(shift(@insns));
++	}
++	&vpaddd		($t2,@X[0],16*2*$j."($Tbl)");
++	  foreach (@insns) { eval; }		# remaining instructions
++	&vmovdqa	((32*$j)%$PUSH8."(%rsp)",$t2);
++}
++    $aesni_cbc_idx=0;
++    for ($i=0,$j=0; $j<4; $j++) {
++	&AVX2_256_00_47($j,\&bodyx_00_15,@X);
++	push(@X,shift(@X));			# rotate(@X)
++    }
++	&vmovq		("%r13",$offload);	# borrow $a0
++	&vpextrq	("%r15",$offload,1);	# borrow $a2
++	&vpand		($temp,$temp,$mask14);
++	&vpor		($iv,$iv,$temp);
++	&vmovdqu	("(%r15,%r13)",$iv);	# write output
++	&lea		("%r13","16(%r13)");	# inp++
++
++	&lea	($Tbl,16*2*$SZ."($Tbl)");
++	&cmpb	(($SZ-1)."($Tbl)",0);
++	&jne	(".Lavx2_00_47");
++
++	&vmovdqu	($inout,"(%r13)");
++	&vpinsrq	($offload,$offload,"%r13",0);
++
++    $aesni_cbc_idx=0;
++    for ($i=0; $i<16; ) {
++	my $base=$i<8?"+$PUSH8(%rsp)":"(%rsp)";
++	foreach(bodyx_00_15()) { eval; }
++    }
++					}
++$code.=<<___;
++	vpextrq	\$1,$offload,%r12		# $_out, borrow $a4
++	vmovq	$offload,%r13			# $_inp, borrow $a0
++	mov	`2*$SZ*$rounds+5*8`(%rsp),%r15	# $_ctx, borrow $a2
++	add	$a1,$A
++	lea	`2*$SZ*($rounds-8)`(%rsp),$Tbl
++
++	vpand	$mask14,$temp,$temp
++	vpor	$temp,$iv,$iv
++	vmovdqu	$iv,(%r12,%r13)			# write output
++	lea	16(%r13),%r13
++
++	add	$SZ*0(%r15),$A
++	add	$SZ*1(%r15),$B
++	add	$SZ*2(%r15),$C
++	add	$SZ*3(%r15),$D
++	add	$SZ*4(%r15),$E
++	add	$SZ*5(%r15),$F
++	add	$SZ*6(%r15),$G
++	add	$SZ*7(%r15),$H
++
++	mov	$A,$SZ*0(%r15)
++	mov	$B,$SZ*1(%r15)
++	mov	$C,$SZ*2(%r15)
++	mov	$D,$SZ*3(%r15)
++	mov	$E,$SZ*4(%r15)
++	mov	$F,$SZ*5(%r15)
++	mov	$G,$SZ*6(%r15)
++	mov	$H,$SZ*7(%r15)
++
++	cmp	`$PUSH8+2*8`($Tbl),%r13		# $_end
++	je	.Ldone_avx2
++
++	xor	$a1,$a1
++	mov	$B,$a3
++	mov	$F,$a4
++	xor	$C,$a3			# magic
++	jmp	.Lower_avx2
++.align	16
++.Lower_avx2:
++	vmovdqu	(%r13),$inout
++	vpinsrq	\$0,%r13,$offload,$offload
++___
++    $aesni_cbc_idx=0;
++    for ($i=0; $i<16; ) {
++	my $base="+16($Tbl)";
++	foreach(bodyx_00_15()) { eval; }
++	&lea	($Tbl,"-$PUSH8($Tbl)")	if ($i==8);
++    }
++$code.=<<___;
++	vmovq	$offload,%r13			# borrow $a0
++	vpextrq	\$1,$offload,%r15		# borrow $a2
++	vpand	$mask14,$temp,$temp
++	vpor	$temp,$iv,$iv
++	lea	-$PUSH8($Tbl),$Tbl
++	vmovdqu	$iv,(%r15,%r13)			# write output
++	lea	16(%r13),%r13			# inp++
++	cmp	%rsp,$Tbl
++	jae	.Lower_avx2
++
++	mov	`2*$SZ*$rounds+5*8`(%rsp),%r15	# $_ctx, borrow $a2
++	lea	16*$SZ(%r13),%r13
++	mov	`2*$SZ*$rounds+6*8`(%rsp),%rsi	# $_in0, borrow $a3
++	add	$a1,$A
++	lea	`2*$SZ*($rounds-8)`(%rsp),%rsp
++
++	add	$SZ*0(%r15),$A
++	add	$SZ*1(%r15),$B
++	add	$SZ*2(%r15),$C
++	add	$SZ*3(%r15),$D
++	add	$SZ*4(%r15),$E
++	add	$SZ*5(%r15),$F
++	add	$SZ*6(%r15),$G
++	lea	(%rsi,%r13),%r12
++	add	$SZ*7(%r15),$H
++
++	cmp	$_end,%r13
++
++	mov	$A,$SZ*0(%r15)
++	cmove	%rsp,%r12		# next block or stale data
++	mov	$B,$SZ*1(%r15)
++	mov	$C,$SZ*2(%r15)
++	mov	$D,$SZ*3(%r15)
++	mov	$E,$SZ*4(%r15)
++	mov	$F,$SZ*5(%r15)
++	mov	$G,$SZ*6(%r15)
++	mov	$H,$SZ*7(%r15)
++
++	jbe	.Loop_avx2
++	lea	(%rsp),$Tbl
++
++.Ldone_avx2:
++	lea	($Tbl),%rsp
++	mov	$_ivp,$ivp
++	mov	$_rsp,%rsi
++	vmovdqu	$iv,($ivp)		# output IV
++	vzeroall
++___
++$code.=<<___ if ($win64);
++	movaps	`$framesz+16*0`(%rsp),%xmm6
++	movaps	`$framesz+16*1`(%rsp),%xmm7
++	movaps	`$framesz+16*2`(%rsp),%xmm8
++	movaps	`$framesz+16*3`(%rsp),%xmm9
++	movaps	`$framesz+16*4`(%rsp),%xmm10
++	movaps	`$framesz+16*5`(%rsp),%xmm11
++	movaps	`$framesz+16*6`(%rsp),%xmm12
++	movaps	`$framesz+16*7`(%rsp),%xmm13
++	movaps	`$framesz+16*8`(%rsp),%xmm14
++	movaps	`$framesz+16*9`(%rsp),%xmm15
++___
++$code.=<<___;
++	mov	(%rsi),%r15
++	mov	8(%rsi),%r14
++	mov	16(%rsi),%r13
++	mov	24(%rsi),%r12
++	mov	32(%rsi),%rbp
++	mov	40(%rsi),%rbx
++	lea	48(%rsi),%rsp
++.Lepilogue_avx2:
++	ret
++.size	${func}_avx2,.-${func}_avx2
++___
++}}
++}}
++{{
++my ($in0,$out,$len,$key,$ivp,$ctx,$inp)=("%rdi","%rsi","%rdx","%rcx","%r8","%r9","%r10");
++
++my ($rounds,$Tbl)=("%r11d","%rbx");
++
++my ($iv,$in,$rndkey0)=map("%xmm$_",(6,14,15));
++my @rndkey=("%xmm4","%xmm5");
++my $r=0;
++my $sn=0;
++
++my ($Wi,$ABEF,$CDGH,$TMP,$BSWAP,$ABEF_SAVE,$CDGH_SAVE)=map("%xmm$_",(0..3,7..9));
++my @MSG=map("%xmm$_",(10..13));
++
++my $aesenc=sub {
++  use integer;
++  my ($n,$k)=($r/10,$r%10);
++    if ($k==0) {
++      $code.=<<___;
++	movups		`16*$n`($in0),$in		# load input
++	xorps		$rndkey0,$in
++___
++      $code.=<<___ if ($n);
++	movups		$iv,`16*($n-1)`($out,$in0)	# write output
++___
++      $code.=<<___;
++	xorps		$in,$iv
++	movups		`32+16*$k-112`($key),$rndkey[1]
++	aesenc		$rndkey[0],$iv
++___
++    } elsif ($k==9) {
++      $sn++;
++      $code.=<<___;
++	cmp		\$11,$rounds
++	jb		.Laesenclast$sn
++	movups		`32+16*($k+0)-112`($key),$rndkey[1]
++	aesenc		$rndkey[0],$iv
++	movups		`32+16*($k+1)-112`($key),$rndkey[0]
++	aesenc		$rndkey[1],$iv
++	je		.Laesenclast$sn
++	movups		`32+16*($k+2)-112`($key),$rndkey[1]
++	aesenc		$rndkey[0],$iv
++	movups		`32+16*($k+3)-112`($key),$rndkey[0]
++	aesenc		$rndkey[1],$iv
++.Laesenclast$sn:
++	aesenclast	$rndkey[0],$iv
++	movups		16-112($key),$rndkey[1]		# forward reference
++	nop
++___
++    } else {
++      $code.=<<___;
++	movups		`32+16*$k-112`($key),$rndkey[1]
++	aesenc		$rndkey[0],$iv
++___
++    }
++    $r++;	unshift(@rndkey,pop(@rndkey));
++};
++
++if ($shaext) {
++my $Tbl="%rax";
++
++$code.=<<___;
++.type	${func}_shaext,\@function,6
++.align	32
++${func}_shaext:
++	mov	`($win64?56:8)`(%rsp),$inp	# load 7th argument
++___
++$code.=<<___ if ($win64);
++	lea	`-8-10*16`(%rsp),%rsp
++	movaps	%xmm6,-8-10*16(%rax)
++	movaps	%xmm7,-8-9*16(%rax)
++	movaps	%xmm8,-8-8*16(%rax)
++	movaps	%xmm9,-8-7*16(%rax)
++	movaps	%xmm10,-8-6*16(%rax)
++	movaps	%xmm11,-8-5*16(%rax)
++	movaps	%xmm12,-8-4*16(%rax)
++	movaps	%xmm13,-8-3*16(%rax)
++	movaps	%xmm14,-8-2*16(%rax)
++	movaps	%xmm15,-8-1*16(%rax)
++.Lprologue_shaext:
++___
++$code.=<<___;
++	lea		K256+0x80(%rip),$Tbl
++	movdqu		($ctx),$ABEF		# DCBA
++	movdqu		16($ctx),$CDGH		# HGFE
++	movdqa		0x200-0x80($Tbl),$TMP	# byte swap mask
++
++	mov		240($key),$rounds
++	sub		$in0,$out
++	movups		($key),$rndkey0		# $key[0]
++	movups		16($key),$rndkey[0]	# forward reference
++	lea		112($key),$key		# size optimization
++
++	pshufd		\$0x1b,$ABEF,$Wi	# ABCD
++	pshufd		\$0xb1,$ABEF,$ABEF	# CDAB
++	pshufd		\$0x1b,$CDGH,$CDGH	# EFGH
++	movdqa		$TMP,$BSWAP		# offload
++	palignr		\$8,$CDGH,$ABEF		# ABEF
++	punpcklqdq	$Wi,$CDGH		# CDGH
++
++	jmp	.Loop_shaext
++
++.align	16
++.Loop_shaext:
++	movdqu		($inp),@MSG[0]
++	movdqu		0x10($inp),@MSG[1]
++	movdqu		0x20($inp),@MSG[2]
++	pshufb		$TMP,@MSG[0]
++	movdqu		0x30($inp),@MSG[3]
++
++	movdqa		0*32-0x80($Tbl),$Wi
++	paddd		@MSG[0],$Wi
++	pshufb		$TMP,@MSG[1]
++	movdqa		$CDGH,$CDGH_SAVE	# offload
++	movdqa		$ABEF,$ABEF_SAVE	# offload
++___
++	&$aesenc();
++$code.=<<___;
++	sha256rnds2	$ABEF,$CDGH		# 0-3
++	pshufd		\$0x0e,$Wi,$Wi
++___
++	&$aesenc();
++$code.=<<___;
++	sha256rnds2	$CDGH,$ABEF
++
++	movdqa		1*32-0x80($Tbl),$Wi
++	paddd		@MSG[1],$Wi
++	pshufb		$TMP,@MSG[2]
++	lea		0x40($inp),$inp
++___
++	&$aesenc();
++$code.=<<___;
++	sha256rnds2	$ABEF,$CDGH		# 4-7
++	pshufd		\$0x0e,$Wi,$Wi
++___
++	&$aesenc();
++$code.=<<___;
++	sha256rnds2	$CDGH,$ABEF
++
++	movdqa		2*32-0x80($Tbl),$Wi
++	paddd		@MSG[2],$Wi
++	pshufb		$TMP,@MSG[3]
++	sha256msg1	@MSG[1],@MSG[0]
++___
++	&$aesenc();
++$code.=<<___;
++	sha256rnds2	$ABEF,$CDGH		# 8-11
++	pshufd		\$0x0e,$Wi,$Wi
++	movdqa		@MSG[3],$TMP
++	palignr		\$4,@MSG[2],$TMP
++	paddd		$TMP,@MSG[0]
++___
++	&$aesenc();
++$code.=<<___;
++	sha256rnds2	$CDGH,$ABEF
++
++	movdqa		3*32-0x80($Tbl),$Wi
++	paddd		@MSG[3],$Wi
++	sha256msg2	@MSG[3],@MSG[0]
++	sha256msg1	@MSG[2],@MSG[1]
++___
++	&$aesenc();
++$code.=<<___;
++	sha256rnds2	$ABEF,$CDGH		# 12-15
++	pshufd		\$0x0e,$Wi,$Wi
++___
++	&$aesenc();
++$code.=<<___;
++	movdqa		@MSG[0],$TMP
++	palignr		\$4,@MSG[3],$TMP
++	paddd		$TMP,@MSG[1]
++	sha256rnds2	$CDGH,$ABEF
++___
++for($i=4;$i<16-3;$i++) {
++	&$aesenc()	if (($r%10)==0);
++$code.=<<___;
++	movdqa		$i*32-0x80($Tbl),$Wi
++	paddd		@MSG[0],$Wi
++	sha256msg2	@MSG[0],@MSG[1]
++	sha256msg1	@MSG[3],@MSG[2]
++___
++	&$aesenc();
++$code.=<<___;
++	sha256rnds2	$ABEF,$CDGH		# 16-19...
++	pshufd		\$0x0e,$Wi,$Wi
++	movdqa		@MSG[1],$TMP
++	palignr		\$4,@MSG[0],$TMP
++	paddd		$TMP,@MSG[2]
++___
++	&$aesenc();
++	&$aesenc()	if ($r==19);
++$code.=<<___;
++	sha256rnds2	$CDGH,$ABEF
++___
++	push(@MSG,shift(@MSG));
++}
++$code.=<<___;
++	movdqa		13*32-0x80($Tbl),$Wi
++	paddd		@MSG[0],$Wi
++	sha256msg2	@MSG[0],@MSG[1]
++	sha256msg1	@MSG[3],@MSG[2]
++___
++	&$aesenc();
++$code.=<<___;
++	sha256rnds2	$ABEF,$CDGH		# 52-55
++	pshufd		\$0x0e,$Wi,$Wi
++	movdqa		@MSG[1],$TMP
++	palignr		\$4,@MSG[0],$TMP
++	paddd		$TMP,@MSG[2]
++___
++	&$aesenc();
++	&$aesenc();
++$code.=<<___;
++	sha256rnds2	$CDGH,$ABEF
++
++	movdqa		14*32-0x80($Tbl),$Wi
++	paddd		@MSG[1],$Wi
++	sha256msg2	@MSG[1],@MSG[2]
++	movdqa		$BSWAP,$TMP
++___
++	&$aesenc();
++$code.=<<___;
++	sha256rnds2	$ABEF,$CDGH		# 56-59
++	pshufd		\$0x0e,$Wi,$Wi
++___
++	&$aesenc();
++$code.=<<___;
++	sha256rnds2	$CDGH,$ABEF
++
++	movdqa		15*32-0x80($Tbl),$Wi
++	paddd		@MSG[2],$Wi
++___
++	&$aesenc();
++	&$aesenc();
++$code.=<<___;
++	sha256rnds2	$ABEF,$CDGH		# 60-63
++	pshufd		\$0x0e,$Wi,$Wi
++___
++	&$aesenc();
++$code.=<<___;
++	sha256rnds2	$CDGH,$ABEF
++	#pxor		$CDGH,$rndkey0		# black magic
++___
++	while ($r<40)	{ &$aesenc(); }		# remaining aesenc's
++$code.=<<___;
++	#xorps		$CDGH,$rndkey0		# black magic
++	paddd		$CDGH_SAVE,$CDGH
++	paddd		$ABEF_SAVE,$ABEF
++
++	dec		$len
++	movups		$iv,48($out,$in0)	# write output
++	lea		64($in0),$in0
++	jnz		.Loop_shaext
++
++	pshufd		\$0xb1,$CDGH,$CDGH	# DCHG
++	pshufd		\$0x1b,$ABEF,$TMP	# FEBA
++	pshufd		\$0xb1,$ABEF,$ABEF	# BAFE
++	punpckhqdq	$CDGH,$ABEF		# DCBA
++	palignr		\$8,$TMP,$CDGH		# HGFE
++
++	movups		$iv,($ivp)		# write IV
++	movdqu		$ABEF,($ctx)
++	movdqu		$CDGH,16($ctx)
++___
++$code.=<<___ if ($win64);
++	movaps	0*16(%rsp),%xmm6
++	movaps	1*16(%rsp),%xmm7
++	movaps	2*16(%rsp),%xmm8
++	movaps	3*16(%rsp),%xmm9
++	movaps	4*16(%rsp),%xmm10
++	movaps	5*16(%rsp),%xmm11
++	movaps	6*16(%rsp),%xmm12
++	movaps	7*16(%rsp),%xmm13
++	movaps	8*16(%rsp),%xmm14
++	movaps	9*16(%rsp),%xmm15
++	lea	8+10*16(%rsp),%rsp
++.Lepilogue_shaext:
++___
++$code.=<<___;
++	ret
++.size	${func}_shaext,.-${func}_shaext
++___
++}
++}}}}}
++
++# EXCEPTION_DISPOSITION handler (EXCEPTION_RECORD *rec,ULONG64 frame,
++#		CONTEXT *context,DISPATCHER_CONTEXT *disp)
++if ($win64 && $avx) {
++$rec="%rcx";
++$frame="%rdx";
++$context="%r8";
++$disp="%r9";
++
++$code.=<<___;
++.extern	__imp_RtlVirtualUnwind
++.type	se_handler,\@abi-omnipotent
++.align	16
++se_handler:
++	push	%rsi
++	push	%rdi
++	push	%rbx
++	push	%rbp
++	push	%r12
++	push	%r13
++	push	%r14
++	push	%r15
++	pushfq
++	sub	\$64,%rsp
++
++	mov	120($context),%rax	# pull context->Rax
++	mov	248($context),%rbx	# pull context->Rip
++
++	mov	8($disp),%rsi		# disp->ImageBase
++	mov	56($disp),%r11		# disp->HanderlData
++
++	mov	0(%r11),%r10d		# HandlerData[0]
++	lea	(%rsi,%r10),%r10	# prologue label
++	cmp	%r10,%rbx		# context->RipRsp
++
++	mov	4(%r11),%r10d		# HandlerData[1]
++	lea	(%rsi,%r10),%r10	# epilogue label
++	cmp	%r10,%rbx		# context->Rip>=epilogue label
++	jae	.Lin_prologue
++___
++$code.=<<___ if ($shaext);
++	lea	aesni_cbc_sha256_enc_shaext(%rip),%r10
++	cmp	%r10,%rbx
++	jb	.Lnot_in_shaext
++
++	lea	(%rax),%rsi
++	lea	512($context),%rdi	# &context.Xmm6
++	mov	\$20,%ecx
++	.long	0xa548f3fc		# cld; rep movsq
++	lea	168(%rax),%rax		# adjust stack pointer
++	jmp	.Lin_prologue
++.Lnot_in_shaext:
++___
++$code.=<<___ if ($avx>1);
++	lea	.Lavx2_shortcut(%rip),%r10
++	cmp	%r10,%rbx		# context->RipRbx
++	mov	%rbp,160($context)	# restore context->Rbp
++	mov	%r12,216($context)	# restore context->R12
++	mov	%r13,224($context)	# restore context->R13
++	mov	%r14,232($context)	# restore context->R14
++	mov	%r15,240($context)	# restore context->R15
++
++	lea	16*$SZ+8*8(%rsi),%rsi	# Xmm6- save area
++	lea	512($context),%rdi	# &context.Xmm6
++	mov	\$20,%ecx
++	.long	0xa548f3fc		# cld; rep movsq
++
++.Lin_prologue:
++	mov	8(%rax),%rdi
++	mov	16(%rax),%rsi
++	mov	%rax,152($context)	# restore context->Rsp
++	mov	%rsi,168($context)	# restore context->Rsi
++	mov	%rdi,176($context)	# restore context->Rdi
++
++	mov	40($disp),%rdi		# disp->ContextRecord
++	mov	$context,%rsi		# context
++	mov	\$154,%ecx		# sizeof(CONTEXT)
++	.long	0xa548f3fc		# cld; rep movsq
++
++	mov	$disp,%rsi
++	xor	%rcx,%rcx		# arg1, UNW_FLAG_NHANDLER
++	mov	8(%rsi),%rdx		# arg2, disp->ImageBase
++	mov	0(%rsi),%r8		# arg3, disp->ControlPc
++	mov	16(%rsi),%r9		# arg4, disp->FunctionEntry
++	mov	40(%rsi),%r10		# disp->ContextRecord
++	lea	56(%rsi),%r11		# &disp->HandlerData
++	lea	24(%rsi),%r12		# &disp->EstablisherFrame
++	mov	%r10,32(%rsp)		# arg5
++	mov	%r11,40(%rsp)		# arg6
++	mov	%r12,48(%rsp)		# arg7
++	mov	%rcx,56(%rsp)		# arg8, (NULL)
++	call	*__imp_RtlVirtualUnwind(%rip)
++
++	mov	\$1,%eax		# ExceptionContinueSearch
++	add	\$64,%rsp
++	popfq
++	pop	%r15
++	pop	%r14
++	pop	%r13
++	pop	%r12
++	pop	%rbp
++	pop	%rbx
++	pop	%rdi
++	pop	%rsi
++	ret
++.size	se_handler,.-se_handler
++
++.section	.pdata
++	.rva	.LSEH_begin_${func}_xop
++	.rva	.LSEH_end_${func}_xop
++	.rva	.LSEH_info_${func}_xop
++
++	.rva	.LSEH_begin_${func}_avx
++	.rva	.LSEH_end_${func}_avx
++	.rva	.LSEH_info_${func}_avx
++___
++$code.=<<___ if ($avx>1);
++	.rva	.LSEH_begin_${func}_avx2
++	.rva	.LSEH_end_${func}_avx2
++	.rva	.LSEH_info_${func}_avx2
++___
++$code.=<<___ if ($shaext);
++	.rva	.LSEH_begin_${func}_shaext
++	.rva	.LSEH_end_${func}_shaext
++	.rva	.LSEH_info_${func}_shaext
++___
++$code.=<<___;
++.section	.xdata
++.align	8
++.LSEH_info_${func}_xop:
++	.byte	9,0,0,0
++	.rva	se_handler
++	.rva	.Lprologue_xop,.Lepilogue_xop		# HandlerData[]
++
++.LSEH_info_${func}_avx:
++	.byte	9,0,0,0
++	.rva	se_handler
++	.rva	.Lprologue_avx,.Lepilogue_avx		# HandlerData[]
++___
++$code.=<<___ if ($avx>1);
++.LSEH_info_${func}_avx2:
++	.byte	9,0,0,0
++	.rva	se_handler
++	.rva	.Lprologue_avx2,.Lepilogue_avx2		# HandlerData[]
++___
++$code.=<<___ if ($shaext);
++.LSEH_info_${func}_shaext:
++	.byte	9,0,0,0
++	.rva	se_handler
++	.rva	.Lprologue_shaext,.Lepilogue_shaext	# HandlerData[]
++___
++}
++
++####################################################################
++sub rex {
++  local *opcode=shift;
++  my ($dst,$src)=@_;
++  my $rex=0;
++
++    $rex|=0x04			if($dst>=8);
++    $rex|=0x01			if($src>=8);
++    unshift @opcode,$rex|0x40	if($rex);
++}
++
++{
++  my %opcodelet = (
++		"sha256rnds2" => 0xcb,
++  		"sha256msg1"  => 0xcc,
++		"sha256msg2"  => 0xcd	);
++
++  sub sha256op38 {
++    my $instr = shift;
++
++    if (defined($opcodelet{$instr}) && @_[0] =~ /%xmm([0-9]+),\s*%xmm([0-9]+)/) {
++      my @opcode=(0x0f,0x38);
++	rex(\@opcode,$2,$1);
++	push @opcode,$opcodelet{$instr};
++	push @opcode,0xc0|($1&7)|(($2&7)<<3);		# ModR/M
++	return ".byte\t".join(',',@opcode);
++    } else {
++	return $instr."\t".@_[0];
++    }
++  }
++}
++
++$code =~ s/\`([^\`]*)\`/eval $1/gem;
++$code =~ s/\b(sha256[^\s]*)\s+(.*)/sha256op38($1,$2)/gem;
++print $code;
++close STDOUT;
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/aes/asm/aesni-x86.pl b/CryptoPkg/Library/OpensslLib/openssl/crypto/aes/asm/aesni-x86.pl
+new file mode 100644
+index 0000000..ed1a47c
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/aes/asm/aesni-x86.pl
+@@ -0,0 +1,3413 @@
++#! /usr/bin/env perl
++# Copyright 2009-2016 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
++# in the file LICENSE in the source distribution or at
++# https://www.openssl.org/source/license.html
++
++
++# ====================================================================
++# Written by Andy Polyakov  for the OpenSSL
++# project. The module is, however, dual licensed under OpenSSL and
++# CRYPTOGAMS licenses depending on where you obtain it. For further
++# details see http://www.openssl.org/~appro/cryptogams/.
++# ====================================================================
++#
++# This module implements support for Intel AES-NI extension. In
++# OpenSSL context it's used with Intel engine, but can also be used as
++# drop-in replacement for crypto/aes/asm/aes-586.pl [see below for
++# details].
++#
++# Performance.
++#
++# To start with see corresponding paragraph in aesni-x86_64.pl...
++# Instead of filling table similar to one found there I've chosen to
++# summarize *comparison* results for raw ECB, CTR and CBC benchmarks.
++# The simplified table below represents 32-bit performance relative
++# to 64-bit one in every given point. Ratios vary for different
++# encryption modes, therefore interval values.
++#
++#	16-byte     64-byte     256-byte    1-KB        8-KB
++#	53-67%      67-84%      91-94%      95-98%      97-99.5%
++#
++# Lower ratios for smaller block sizes are perfectly understandable,
++# because function call overhead is higher in 32-bit mode. Largest
++# 8-KB block performance is virtually same: 32-bit code is less than
++# 1% slower for ECB, CBC and CCM, and ~3% slower otherwise.
++
++# January 2011
++#
++# See aesni-x86_64.pl for details. Unlike x86_64 version this module
++# interleaves at most 6 aes[enc|dec] instructions, because there are
++# not enough registers for 8x interleave [which should be optimal for
++# Sandy Bridge]. Actually, performance results for 6x interleave
++# factor presented in aesni-x86_64.pl (except for CTR) are for this
++# module.
++
++# April 2011
++#
++# Add aesni_xts_[en|de]crypt. Westmere spends 1.50 cycles processing
++# one byte out of 8KB with 128-bit key, Sandy Bridge - 1.09.
++
++# November 2015
++#
++# Add aesni_ocb_[en|de]crypt.
++
++######################################################################
++# Current large-block performance in cycles per byte processed with
++# 128-bit key (less is better).
++#
++#		CBC en-/decrypt	CTR	XTS	ECB	OCB
++# Westmere	3.77/1.37	1.37	1.52	1.27
++# * Bridge	5.07/0.98	0.99	1.09	0.91	1.10
++# Haswell	4.44/0.80	0.97	1.03	0.72	0.76
++# Silvermont	5.77/3.56	3.67	4.03	3.46	4.03
++# Bulldozer	5.80/0.98	1.05	1.24	0.93	1.23
++
++$PREFIX="aesni";	# if $PREFIX is set to "AES", the script
++			# generates drop-in replacement for
++			# crypto/aes/asm/aes-586.pl:-)
++$inline=1;		# inline _aesni_[en|de]crypt
++
++$0 =~ m/(.*[\/\\])[^\/\\]+$/; $dir=$1;
++push(@INC,"${dir}","${dir}../../perlasm");
++require "x86asm.pl";
++
++$output = pop;
++open OUT,">$output";
++*STDOUT=*OUT;
++
++&asm_init($ARGV[0],$0);
++
++&external_label("OPENSSL_ia32cap_P");
++&static_label("key_const");
++
++if ($PREFIX eq "aesni")	{ $movekey=\&movups; }
++else			{ $movekey=\&movups; }
++
++$len="eax";
++$rounds="ecx";
++$key="edx";
++$inp="esi";
++$out="edi";
++$rounds_="ebx";	# backup copy for $rounds
++$key_="ebp";	# backup copy for $key
++
++$rndkey0="xmm0";
++$rndkey1="xmm1";
++$inout0="xmm2";
++$inout1="xmm3";
++$inout2="xmm4";
++$inout3="xmm5";	$in1="xmm5";
++$inout4="xmm6";	$in0="xmm6";
++$inout5="xmm7";	$ivec="xmm7";
++
++# AESNI extension
++sub aeskeygenassist
++{ my($dst,$src,$imm)=@_;
++    if ("$dst:$src" =~ /xmm([0-7]):xmm([0-7])/)
++    {	&data_byte(0x66,0x0f,0x3a,0xdf,0xc0|($1<<3)|$2,$imm);	}
++}
++sub aescommon
++{ my($opcodelet,$dst,$src)=@_;
++    if ("$dst:$src" =~ /xmm([0-7]):xmm([0-7])/)
++    {	&data_byte(0x66,0x0f,0x38,$opcodelet,0xc0|($1<<3)|$2);}
++}
++sub aesimc	{ aescommon(0xdb,@_); }
++sub aesenc	{ aescommon(0xdc,@_); }
++sub aesenclast	{ aescommon(0xdd,@_); }
++sub aesdec	{ aescommon(0xde,@_); }
++sub aesdeclast	{ aescommon(0xdf,@_); }
++
++# Inline version of internal aesni_[en|de]crypt1
++{ my $sn;
++sub aesni_inline_generate1
++{ my ($p,$inout,$ivec)=@_; $inout=$inout0 if (!defined($inout));
++  $sn++;
++
++    &$movekey		($rndkey0,&QWP(0,$key));
++    &$movekey		($rndkey1,&QWP(16,$key));
++    &xorps		($ivec,$rndkey0)	if (defined($ivec));
++    &lea		($key,&DWP(32,$key));
++    &xorps		($inout,$ivec)		if (defined($ivec));
++    &xorps		($inout,$rndkey0)	if (!defined($ivec));
++    &set_label("${p}1_loop_$sn");
++	eval"&aes${p}	($inout,$rndkey1)";
++	&dec		($rounds);
++	&$movekey	($rndkey1,&QWP(0,$key));
++	&lea		($key,&DWP(16,$key));
++    &jnz		(&label("${p}1_loop_$sn"));
++    eval"&aes${p}last	($inout,$rndkey1)";
++}}
++
++sub aesni_generate1	# fully unrolled loop
++{ my ($p,$inout)=@_; $inout=$inout0 if (!defined($inout));
++
++    &function_begin_B("_aesni_${p}rypt1");
++	&movups		($rndkey0,&QWP(0,$key));
++	&$movekey	($rndkey1,&QWP(0x10,$key));
++	&xorps		($inout,$rndkey0);
++	&$movekey	($rndkey0,&QWP(0x20,$key));
++	&lea		($key,&DWP(0x30,$key));
++	&cmp		($rounds,11);
++	&jb		(&label("${p}128"));
++	&lea		($key,&DWP(0x20,$key));
++	&je		(&label("${p}192"));
++	&lea		($key,&DWP(0x20,$key));
++	eval"&aes${p}	($inout,$rndkey1)";
++	&$movekey	($rndkey1,&QWP(-0x40,$key));
++	eval"&aes${p}	($inout,$rndkey0)";
++	&$movekey	($rndkey0,&QWP(-0x30,$key));
++    &set_label("${p}192");
++	eval"&aes${p}	($inout,$rndkey1)";
++	&$movekey	($rndkey1,&QWP(-0x20,$key));
++	eval"&aes${p}	($inout,$rndkey0)";
++	&$movekey	($rndkey0,&QWP(-0x10,$key));
++    &set_label("${p}128");
++	eval"&aes${p}	($inout,$rndkey1)";
++	&$movekey	($rndkey1,&QWP(0,$key));
++	eval"&aes${p}	($inout,$rndkey0)";
++	&$movekey	($rndkey0,&QWP(0x10,$key));
++	eval"&aes${p}	($inout,$rndkey1)";
++	&$movekey	($rndkey1,&QWP(0x20,$key));
++	eval"&aes${p}	($inout,$rndkey0)";
++	&$movekey	($rndkey0,&QWP(0x30,$key));
++	eval"&aes${p}	($inout,$rndkey1)";
++	&$movekey	($rndkey1,&QWP(0x40,$key));
++	eval"&aes${p}	($inout,$rndkey0)";
++	&$movekey	($rndkey0,&QWP(0x50,$key));
++	eval"&aes${p}	($inout,$rndkey1)";
++	&$movekey	($rndkey1,&QWP(0x60,$key));
++	eval"&aes${p}	($inout,$rndkey0)";
++	&$movekey	($rndkey0,&QWP(0x70,$key));
++	eval"&aes${p}	($inout,$rndkey1)";
++    eval"&aes${p}last	($inout,$rndkey0)";
++    &ret();
++    &function_end_B("_aesni_${p}rypt1");
++}
++
++# void $PREFIX_encrypt (const void *inp,void *out,const AES_KEY *key);
++&aesni_generate1("enc") if (!$inline);
++&function_begin_B("${PREFIX}_encrypt");
++	&mov	("eax",&wparam(0));
++	&mov	($key,&wparam(2));
++	&movups	($inout0,&QWP(0,"eax"));
++	&mov	($rounds,&DWP(240,$key));
++	&mov	("eax",&wparam(1));
++	if ($inline)
++	{   &aesni_inline_generate1("enc");	}
++	else
++	{   &call	("_aesni_encrypt1");	}
++	&pxor	($rndkey0,$rndkey0);		# clear register bank
++	&pxor	($rndkey1,$rndkey1);
++	&movups	(&QWP(0,"eax"),$inout0);
++	&pxor	($inout0,$inout0);
++	&ret	();
++&function_end_B("${PREFIX}_encrypt");
++
++# void $PREFIX_decrypt (const void *inp,void *out,const AES_KEY *key);
++&aesni_generate1("dec") if(!$inline);
++&function_begin_B("${PREFIX}_decrypt");
++	&mov	("eax",&wparam(0));
++	&mov	($key,&wparam(2));
++	&movups	($inout0,&QWP(0,"eax"));
++	&mov	($rounds,&DWP(240,$key));
++	&mov	("eax",&wparam(1));
++	if ($inline)
++	{   &aesni_inline_generate1("dec");	}
++	else
++	{   &call	("_aesni_decrypt1");	}
++	&pxor	($rndkey0,$rndkey0);		# clear register bank
++	&pxor	($rndkey1,$rndkey1);
++	&movups	(&QWP(0,"eax"),$inout0);
++	&pxor	($inout0,$inout0);
++	&ret	();
++&function_end_B("${PREFIX}_decrypt");
++
++# _aesni_[en|de]cryptN are private interfaces, N denotes interleave
++# factor. Why 3x subroutine were originally used in loops? Even though
++# aes[enc|dec] latency was originally 6, it could be scheduled only
++# every *2nd* cycle. Thus 3x interleave was the one providing optimal
++# utilization, i.e. when subroutine's throughput is virtually same as
++# of non-interleaved subroutine [for number of input blocks up to 3].
++# This is why it originally made no sense to implement 2x subroutine.
++# But times change and it became appropriate to spend extra 192 bytes
++# on 2x subroutine on Atom Silvermont account. For processors that
++# can schedule aes[enc|dec] every cycle optimal interleave factor
++# equals to corresponding instructions latency. 8x is optimal for
++# * Bridge, but it's unfeasible to accommodate such implementation
++# in XMM registers addreassable in 32-bit mode and therefore maximum
++# of 6x is used instead...
++
++sub aesni_generate2
++{ my $p=shift;
++
++    &function_begin_B("_aesni_${p}rypt2");
++	&$movekey	($rndkey0,&QWP(0,$key));
++	&shl		($rounds,4);
++	&$movekey	($rndkey1,&QWP(16,$key));
++	&xorps		($inout0,$rndkey0);
++	&pxor		($inout1,$rndkey0);
++	&$movekey	($rndkey0,&QWP(32,$key));
++	&lea		($key,&DWP(32,$key,$rounds));
++	&neg		($rounds);
++	&add		($rounds,16);
++
++    &set_label("${p}2_loop");
++	eval"&aes${p}	($inout0,$rndkey1)";
++	eval"&aes${p}	($inout1,$rndkey1)";
++	&$movekey	($rndkey1,&QWP(0,$key,$rounds));
++	&add		($rounds,32);
++	eval"&aes${p}	($inout0,$rndkey0)";
++	eval"&aes${p}	($inout1,$rndkey0)";
++	&$movekey	($rndkey0,&QWP(-16,$key,$rounds));
++	&jnz		(&label("${p}2_loop"));
++    eval"&aes${p}	($inout0,$rndkey1)";
++    eval"&aes${p}	($inout1,$rndkey1)";
++    eval"&aes${p}last	($inout0,$rndkey0)";
++    eval"&aes${p}last	($inout1,$rndkey0)";
++    &ret();
++    &function_end_B("_aesni_${p}rypt2");
++}
++
++sub aesni_generate3
++{ my $p=shift;
++
++    &function_begin_B("_aesni_${p}rypt3");
++	&$movekey	($rndkey0,&QWP(0,$key));
++	&shl		($rounds,4);
++	&$movekey	($rndkey1,&QWP(16,$key));
++	&xorps		($inout0,$rndkey0);
++	&pxor		($inout1,$rndkey0);
++	&pxor		($inout2,$rndkey0);
++	&$movekey	($rndkey0,&QWP(32,$key));
++	&lea		($key,&DWP(32,$key,$rounds));
++	&neg		($rounds);
++	&add		($rounds,16);
++
++    &set_label("${p}3_loop");
++	eval"&aes${p}	($inout0,$rndkey1)";
++	eval"&aes${p}	($inout1,$rndkey1)";
++	eval"&aes${p}	($inout2,$rndkey1)";
++	&$movekey	($rndkey1,&QWP(0,$key,$rounds));
++	&add		($rounds,32);
++	eval"&aes${p}	($inout0,$rndkey0)";
++	eval"&aes${p}	($inout1,$rndkey0)";
++	eval"&aes${p}	($inout2,$rndkey0)";
++	&$movekey	($rndkey0,&QWP(-16,$key,$rounds));
++	&jnz		(&label("${p}3_loop"));
++    eval"&aes${p}	($inout0,$rndkey1)";
++    eval"&aes${p}	($inout1,$rndkey1)";
++    eval"&aes${p}	($inout2,$rndkey1)";
++    eval"&aes${p}last	($inout0,$rndkey0)";
++    eval"&aes${p}last	($inout1,$rndkey0)";
++    eval"&aes${p}last	($inout2,$rndkey0)";
++    &ret();
++    &function_end_B("_aesni_${p}rypt3");
++}
++
++# 4x interleave is implemented to improve small block performance,
++# most notably [and naturally] 4 block by ~30%. One can argue that one
++# should have implemented 5x as well, but improvement  would be <20%,
++# so it's not worth it...
++sub aesni_generate4
++{ my $p=shift;
++
++    &function_begin_B("_aesni_${p}rypt4");
++	&$movekey	($rndkey0,&QWP(0,$key));
++	&$movekey	($rndkey1,&QWP(16,$key));
++	&shl		($rounds,4);
++	&xorps		($inout0,$rndkey0);
++	&pxor		($inout1,$rndkey0);
++	&pxor		($inout2,$rndkey0);
++	&pxor		($inout3,$rndkey0);
++	&$movekey	($rndkey0,&QWP(32,$key));
++	&lea		($key,&DWP(32,$key,$rounds));
++	&neg		($rounds);
++	&data_byte	(0x0f,0x1f,0x40,0x00);
++	&add		($rounds,16);
++
++    &set_label("${p}4_loop");
++	eval"&aes${p}	($inout0,$rndkey1)";
++	eval"&aes${p}	($inout1,$rndkey1)";
++	eval"&aes${p}	($inout2,$rndkey1)";
++	eval"&aes${p}	($inout3,$rndkey1)";
++	&$movekey	($rndkey1,&QWP(0,$key,$rounds));
++	&add		($rounds,32);
++	eval"&aes${p}	($inout0,$rndkey0)";
++	eval"&aes${p}	($inout1,$rndkey0)";
++	eval"&aes${p}	($inout2,$rndkey0)";
++	eval"&aes${p}	($inout3,$rndkey0)";
++	&$movekey	($rndkey0,&QWP(-16,$key,$rounds));
++    &jnz		(&label("${p}4_loop"));
++
++    eval"&aes${p}	($inout0,$rndkey1)";
++    eval"&aes${p}	($inout1,$rndkey1)";
++    eval"&aes${p}	($inout2,$rndkey1)";
++    eval"&aes${p}	($inout3,$rndkey1)";
++    eval"&aes${p}last	($inout0,$rndkey0)";
++    eval"&aes${p}last	($inout1,$rndkey0)";
++    eval"&aes${p}last	($inout2,$rndkey0)";
++    eval"&aes${p}last	($inout3,$rndkey0)";
++    &ret();
++    &function_end_B("_aesni_${p}rypt4");
++}
++
++sub aesni_generate6
++{ my $p=shift;
++
++    &function_begin_B("_aesni_${p}rypt6");
++    &static_label("_aesni_${p}rypt6_enter");
++	&$movekey	($rndkey0,&QWP(0,$key));
++	&shl		($rounds,4);
++	&$movekey	($rndkey1,&QWP(16,$key));
++	&xorps		($inout0,$rndkey0);
++	&pxor		($inout1,$rndkey0);	# pxor does better here
++	&pxor		($inout2,$rndkey0);
++	eval"&aes${p}	($inout0,$rndkey1)";
++	&pxor		($inout3,$rndkey0);
++	&pxor		($inout4,$rndkey0);
++	eval"&aes${p}	($inout1,$rndkey1)";
++	&lea		($key,&DWP(32,$key,$rounds));
++	&neg		($rounds);
++	eval"&aes${p}	($inout2,$rndkey1)";
++	&pxor		($inout5,$rndkey0);
++	&$movekey	($rndkey0,&QWP(0,$key,$rounds));
++	&add		($rounds,16);
++	&jmp		(&label("_aesni_${p}rypt6_inner"));
++
++    &set_label("${p}6_loop",16);
++	eval"&aes${p}	($inout0,$rndkey1)";
++	eval"&aes${p}	($inout1,$rndkey1)";
++	eval"&aes${p}	($inout2,$rndkey1)";
++    &set_label("_aesni_${p}rypt6_inner");
++	eval"&aes${p}	($inout3,$rndkey1)";
++	eval"&aes${p}	($inout4,$rndkey1)";
++	eval"&aes${p}	($inout5,$rndkey1)";
++    &set_label("_aesni_${p}rypt6_enter");
++	&$movekey	($rndkey1,&QWP(0,$key,$rounds));
++	&add		($rounds,32);
++	eval"&aes${p}	($inout0,$rndkey0)";
++	eval"&aes${p}	($inout1,$rndkey0)";
++	eval"&aes${p}	($inout2,$rndkey0)";
++	eval"&aes${p}	($inout3,$rndkey0)";
++	eval"&aes${p}	($inout4,$rndkey0)";
++	eval"&aes${p}	($inout5,$rndkey0)";
++	&$movekey	($rndkey0,&QWP(-16,$key,$rounds));
++    &jnz		(&label("${p}6_loop"));
++
++    eval"&aes${p}	($inout0,$rndkey1)";
++    eval"&aes${p}	($inout1,$rndkey1)";
++    eval"&aes${p}	($inout2,$rndkey1)";
++    eval"&aes${p}	($inout3,$rndkey1)";
++    eval"&aes${p}	($inout4,$rndkey1)";
++    eval"&aes${p}	($inout5,$rndkey1)";
++    eval"&aes${p}last	($inout0,$rndkey0)";
++    eval"&aes${p}last	($inout1,$rndkey0)";
++    eval"&aes${p}last	($inout2,$rndkey0)";
++    eval"&aes${p}last	($inout3,$rndkey0)";
++    eval"&aes${p}last	($inout4,$rndkey0)";
++    eval"&aes${p}last	($inout5,$rndkey0)";
++    &ret();
++    &function_end_B("_aesni_${p}rypt6");
++}
++&aesni_generate2("enc") if ($PREFIX eq "aesni");
++&aesni_generate2("dec");
++&aesni_generate3("enc") if ($PREFIX eq "aesni");
++&aesni_generate3("dec");
++&aesni_generate4("enc") if ($PREFIX eq "aesni");
++&aesni_generate4("dec");
++&aesni_generate6("enc") if ($PREFIX eq "aesni");
++&aesni_generate6("dec");
++
++if ($PREFIX eq "aesni") {
++######################################################################
++# void aesni_ecb_encrypt (const void *in, void *out,
++#                         size_t length, const AES_KEY *key,
++#                         int enc);
++&function_begin("aesni_ecb_encrypt");
++	&mov	($inp,&wparam(0));
++	&mov	($out,&wparam(1));
++	&mov	($len,&wparam(2));
++	&mov	($key,&wparam(3));
++	&mov	($rounds_,&wparam(4));
++	&and	($len,-16);
++	&jz	(&label("ecb_ret"));
++	&mov	($rounds,&DWP(240,$key));
++	&test	($rounds_,$rounds_);
++	&jz	(&label("ecb_decrypt"));
++
++	&mov	($key_,$key);		# backup $key
++	&mov	($rounds_,$rounds);	# backup $rounds
++	&cmp	($len,0x60);
++	&jb	(&label("ecb_enc_tail"));
++
++	&movdqu	($inout0,&QWP(0,$inp));
++	&movdqu	($inout1,&QWP(0x10,$inp));
++	&movdqu	($inout2,&QWP(0x20,$inp));
++	&movdqu	($inout3,&QWP(0x30,$inp));
++	&movdqu	($inout4,&QWP(0x40,$inp));
++	&movdqu	($inout5,&QWP(0x50,$inp));
++	&lea	($inp,&DWP(0x60,$inp));
++	&sub	($len,0x60);
++	&jmp	(&label("ecb_enc_loop6_enter"));
++
++&set_label("ecb_enc_loop6",16);
++	&movups	(&QWP(0,$out),$inout0);
++	&movdqu	($inout0,&QWP(0,$inp));
++	&movups	(&QWP(0x10,$out),$inout1);
++	&movdqu	($inout1,&QWP(0x10,$inp));
++	&movups	(&QWP(0x20,$out),$inout2);
++	&movdqu	($inout2,&QWP(0x20,$inp));
++	&movups	(&QWP(0x30,$out),$inout3);
++	&movdqu	($inout3,&QWP(0x30,$inp));
++	&movups	(&QWP(0x40,$out),$inout4);
++	&movdqu	($inout4,&QWP(0x40,$inp));
++	&movups	(&QWP(0x50,$out),$inout5);
++	&lea	($out,&DWP(0x60,$out));
++	&movdqu	($inout5,&QWP(0x50,$inp));
++	&lea	($inp,&DWP(0x60,$inp));
++&set_label("ecb_enc_loop6_enter");
++
++	&call	("_aesni_encrypt6");
++
++	&mov	($key,$key_);		# restore $key
++	&mov	($rounds,$rounds_);	# restore $rounds
++	&sub	($len,0x60);
++	&jnc	(&label("ecb_enc_loop6"));
++
++	&movups	(&QWP(0,$out),$inout0);
++	&movups	(&QWP(0x10,$out),$inout1);
++	&movups	(&QWP(0x20,$out),$inout2);
++	&movups	(&QWP(0x30,$out),$inout3);
++	&movups	(&QWP(0x40,$out),$inout4);
++	&movups	(&QWP(0x50,$out),$inout5);
++	&lea	($out,&DWP(0x60,$out));
++	&add	($len,0x60);
++	&jz	(&label("ecb_ret"));
++
++&set_label("ecb_enc_tail");
++	&movups	($inout0,&QWP(0,$inp));
++	&cmp	($len,0x20);
++	&jb	(&label("ecb_enc_one"));
++	&movups	($inout1,&QWP(0x10,$inp));
++	&je	(&label("ecb_enc_two"));
++	&movups	($inout2,&QWP(0x20,$inp));
++	&cmp	($len,0x40);
++	&jb	(&label("ecb_enc_three"));
++	&movups	($inout3,&QWP(0x30,$inp));
++	&je	(&label("ecb_enc_four"));
++	&movups	($inout4,&QWP(0x40,$inp));
++	&xorps	($inout5,$inout5);
++	&call	("_aesni_encrypt6");
++	&movups	(&QWP(0,$out),$inout0);
++	&movups	(&QWP(0x10,$out),$inout1);
++	&movups	(&QWP(0x20,$out),$inout2);
++	&movups	(&QWP(0x30,$out),$inout3);
++	&movups	(&QWP(0x40,$out),$inout4);
++	jmp	(&label("ecb_ret"));
++
++&set_label("ecb_enc_one",16);
++	if ($inline)
++	{   &aesni_inline_generate1("enc");	}
++	else
++	{   &call	("_aesni_encrypt1");	}
++	&movups	(&QWP(0,$out),$inout0);
++	&jmp	(&label("ecb_ret"));
++
++&set_label("ecb_enc_two",16);
++	&call	("_aesni_encrypt2");
++	&movups	(&QWP(0,$out),$inout0);
++	&movups	(&QWP(0x10,$out),$inout1);
++	&jmp	(&label("ecb_ret"));
++
++&set_label("ecb_enc_three",16);
++	&call	("_aesni_encrypt3");
++	&movups	(&QWP(0,$out),$inout0);
++	&movups	(&QWP(0x10,$out),$inout1);
++	&movups	(&QWP(0x20,$out),$inout2);
++	&jmp	(&label("ecb_ret"));
++
++&set_label("ecb_enc_four",16);
++	&call	("_aesni_encrypt4");
++	&movups	(&QWP(0,$out),$inout0);
++	&movups	(&QWP(0x10,$out),$inout1);
++	&movups	(&QWP(0x20,$out),$inout2);
++	&movups	(&QWP(0x30,$out),$inout3);
++	&jmp	(&label("ecb_ret"));
++######################################################################
++&set_label("ecb_decrypt",16);
++	&mov	($key_,$key);		# backup $key
++	&mov	($rounds_,$rounds);	# backup $rounds
++	&cmp	($len,0x60);
++	&jb	(&label("ecb_dec_tail"));
++
++	&movdqu	($inout0,&QWP(0,$inp));
++	&movdqu	($inout1,&QWP(0x10,$inp));
++	&movdqu	($inout2,&QWP(0x20,$inp));
++	&movdqu	($inout3,&QWP(0x30,$inp));
++	&movdqu	($inout4,&QWP(0x40,$inp));
++	&movdqu	($inout5,&QWP(0x50,$inp));
++	&lea	($inp,&DWP(0x60,$inp));
++	&sub	($len,0x60);
++	&jmp	(&label("ecb_dec_loop6_enter"));
++
++&set_label("ecb_dec_loop6",16);
++	&movups	(&QWP(0,$out),$inout0);
++	&movdqu	($inout0,&QWP(0,$inp));
++	&movups	(&QWP(0x10,$out),$inout1);
++	&movdqu	($inout1,&QWP(0x10,$inp));
++	&movups	(&QWP(0x20,$out),$inout2);
++	&movdqu	($inout2,&QWP(0x20,$inp));
++	&movups	(&QWP(0x30,$out),$inout3);
++	&movdqu	($inout3,&QWP(0x30,$inp));
++	&movups	(&QWP(0x40,$out),$inout4);
++	&movdqu	($inout4,&QWP(0x40,$inp));
++	&movups	(&QWP(0x50,$out),$inout5);
++	&lea	($out,&DWP(0x60,$out));
++	&movdqu	($inout5,&QWP(0x50,$inp));
++	&lea	($inp,&DWP(0x60,$inp));
++&set_label("ecb_dec_loop6_enter");
++
++	&call	("_aesni_decrypt6");
++
++	&mov	($key,$key_);		# restore $key
++	&mov	($rounds,$rounds_);	# restore $rounds
++	&sub	($len,0x60);
++	&jnc	(&label("ecb_dec_loop6"));
++
++	&movups	(&QWP(0,$out),$inout0);
++	&movups	(&QWP(0x10,$out),$inout1);
++	&movups	(&QWP(0x20,$out),$inout2);
++	&movups	(&QWP(0x30,$out),$inout3);
++	&movups	(&QWP(0x40,$out),$inout4);
++	&movups	(&QWP(0x50,$out),$inout5);
++	&lea	($out,&DWP(0x60,$out));
++	&add	($len,0x60);
++	&jz	(&label("ecb_ret"));
++
++&set_label("ecb_dec_tail");
++	&movups	($inout0,&QWP(0,$inp));
++	&cmp	($len,0x20);
++	&jb	(&label("ecb_dec_one"));
++	&movups	($inout1,&QWP(0x10,$inp));
++	&je	(&label("ecb_dec_two"));
++	&movups	($inout2,&QWP(0x20,$inp));
++	&cmp	($len,0x40);
++	&jb	(&label("ecb_dec_three"));
++	&movups	($inout3,&QWP(0x30,$inp));
++	&je	(&label("ecb_dec_four"));
++	&movups	($inout4,&QWP(0x40,$inp));
++	&xorps	($inout5,$inout5);
++	&call	("_aesni_decrypt6");
++	&movups	(&QWP(0,$out),$inout0);
++	&movups	(&QWP(0x10,$out),$inout1);
++	&movups	(&QWP(0x20,$out),$inout2);
++	&movups	(&QWP(0x30,$out),$inout3);
++	&movups	(&QWP(0x40,$out),$inout4);
++	&jmp	(&label("ecb_ret"));
++
++&set_label("ecb_dec_one",16);
++	if ($inline)
++	{   &aesni_inline_generate1("dec");	}
++	else
++	{   &call	("_aesni_decrypt1");	}
++	&movups	(&QWP(0,$out),$inout0);
++	&jmp	(&label("ecb_ret"));
++
++&set_label("ecb_dec_two",16);
++	&call	("_aesni_decrypt2");
++	&movups	(&QWP(0,$out),$inout0);
++	&movups	(&QWP(0x10,$out),$inout1);
++	&jmp	(&label("ecb_ret"));
++
++&set_label("ecb_dec_three",16);
++	&call	("_aesni_decrypt3");
++	&movups	(&QWP(0,$out),$inout0);
++	&movups	(&QWP(0x10,$out),$inout1);
++	&movups	(&QWP(0x20,$out),$inout2);
++	&jmp	(&label("ecb_ret"));
++
++&set_label("ecb_dec_four",16);
++	&call	("_aesni_decrypt4");
++	&movups	(&QWP(0,$out),$inout0);
++	&movups	(&QWP(0x10,$out),$inout1);
++	&movups	(&QWP(0x20,$out),$inout2);
++	&movups	(&QWP(0x30,$out),$inout3);
++
++&set_label("ecb_ret");
++	&pxor	("xmm0","xmm0");		# clear register bank
++	&pxor	("xmm1","xmm1");
++	&pxor	("xmm2","xmm2");
++	&pxor	("xmm3","xmm3");
++	&pxor	("xmm4","xmm4");
++	&pxor	("xmm5","xmm5");
++	&pxor	("xmm6","xmm6");
++	&pxor	("xmm7","xmm7");
++&function_end("aesni_ecb_encrypt");
++
++######################################################################
++# void aesni_ccm64_[en|de]crypt_blocks (const void *in, void *out,
++#                         size_t blocks, const AES_KEY *key,
++#                         const char *ivec,char *cmac);
++#
++# Handles only complete blocks, operates on 64-bit counter and
++# does not update *ivec! Nor does it finalize CMAC value
++# (see engine/eng_aesni.c for details)
++#
++{ my $cmac=$inout1;
++&function_begin("aesni_ccm64_encrypt_blocks");
++	&mov	($inp,&wparam(0));
++	&mov	($out,&wparam(1));
++	&mov	($len,&wparam(2));
++	&mov	($key,&wparam(3));
++	&mov	($rounds_,&wparam(4));
++	&mov	($rounds,&wparam(5));
++	&mov	($key_,"esp");
++	&sub	("esp",60);
++	&and	("esp",-16);			# align stack
++	&mov	(&DWP(48,"esp"),$key_);
++
++	&movdqu	($ivec,&QWP(0,$rounds_));	# load ivec
++	&movdqu	($cmac,&QWP(0,$rounds));	# load cmac
++	&mov	($rounds,&DWP(240,$key));
++
++	# compose byte-swap control mask for pshufb on stack
++	&mov	(&DWP(0,"esp"),0x0c0d0e0f);
++	&mov	(&DWP(4,"esp"),0x08090a0b);
++	&mov	(&DWP(8,"esp"),0x04050607);
++	&mov	(&DWP(12,"esp"),0x00010203);
++
++	# compose counter increment vector on stack
++	&mov	($rounds_,1);
++	&xor	($key_,$key_);
++	&mov	(&DWP(16,"esp"),$rounds_);
++	&mov	(&DWP(20,"esp"),$key_);
++	&mov	(&DWP(24,"esp"),$key_);
++	&mov	(&DWP(28,"esp"),$key_);
++
++	&shl	($rounds,4);
++	&mov	($rounds_,16);
++	&lea	($key_,&DWP(0,$key));
++	&movdqa	($inout3,&QWP(0,"esp"));
++	&movdqa	($inout0,$ivec);
++	&lea	($key,&DWP(32,$key,$rounds));
++	&sub	($rounds_,$rounds);
++	&pshufb	($ivec,$inout3);
++
++&set_label("ccm64_enc_outer");
++	&$movekey	($rndkey0,&QWP(0,$key_));
++	&mov		($rounds,$rounds_);
++	&movups		($in0,&QWP(0,$inp));
++
++	&xorps		($inout0,$rndkey0);
++	&$movekey	($rndkey1,&QWP(16,$key_));
++	&xorps		($rndkey0,$in0);
++	&xorps		($cmac,$rndkey0);		# cmac^=inp
++	&$movekey	($rndkey0,&QWP(32,$key_));
++
++&set_label("ccm64_enc2_loop");
++	&aesenc		($inout0,$rndkey1);
++	&aesenc		($cmac,$rndkey1);
++	&$movekey	($rndkey1,&QWP(0,$key,$rounds));
++	&add		($rounds,32);
++	&aesenc		($inout0,$rndkey0);
++	&aesenc		($cmac,$rndkey0);
++	&$movekey	($rndkey0,&QWP(-16,$key,$rounds));
++	&jnz		(&label("ccm64_enc2_loop"));
++	&aesenc		($inout0,$rndkey1);
++	&aesenc		($cmac,$rndkey1);
++	&paddq		($ivec,&QWP(16,"esp"));
++	&dec		($len);
++	&aesenclast	($inout0,$rndkey0);
++	&aesenclast	($cmac,$rndkey0);
++
++	&lea	($inp,&DWP(16,$inp));
++	&xorps	($in0,$inout0);			# inp^=E(ivec)
++	&movdqa	($inout0,$ivec);
++	&movups	(&QWP(0,$out),$in0);		# save output
++	&pshufb	($inout0,$inout3);
++	&lea	($out,&DWP(16,$out));
++	&jnz	(&label("ccm64_enc_outer"));
++
++	&mov	("esp",&DWP(48,"esp"));
++	&mov	($out,&wparam(5));
++	&movups	(&QWP(0,$out),$cmac);
++
++	&pxor	("xmm0","xmm0");		# clear register bank
++	&pxor	("xmm1","xmm1");
++	&pxor	("xmm2","xmm2");
++	&pxor	("xmm3","xmm3");
++	&pxor	("xmm4","xmm4");
++	&pxor	("xmm5","xmm5");
++	&pxor	("xmm6","xmm6");
++	&pxor	("xmm7","xmm7");
++&function_end("aesni_ccm64_encrypt_blocks");
++
++&function_begin("aesni_ccm64_decrypt_blocks");
++	&mov	($inp,&wparam(0));
++	&mov	($out,&wparam(1));
++	&mov	($len,&wparam(2));
++	&mov	($key,&wparam(3));
++	&mov	($rounds_,&wparam(4));
++	&mov	($rounds,&wparam(5));
++	&mov	($key_,"esp");
++	&sub	("esp",60);
++	&and	("esp",-16);			# align stack
++	&mov	(&DWP(48,"esp"),$key_);
++
++	&movdqu	($ivec,&QWP(0,$rounds_));	# load ivec
++	&movdqu	($cmac,&QWP(0,$rounds));	# load cmac
++	&mov	($rounds,&DWP(240,$key));
++
++	# compose byte-swap control mask for pshufb on stack
++	&mov	(&DWP(0,"esp"),0x0c0d0e0f);
++	&mov	(&DWP(4,"esp"),0x08090a0b);
++	&mov	(&DWP(8,"esp"),0x04050607);
++	&mov	(&DWP(12,"esp"),0x00010203);
++
++	# compose counter increment vector on stack
++	&mov	($rounds_,1);
++	&xor	($key_,$key_);
++	&mov	(&DWP(16,"esp"),$rounds_);
++	&mov	(&DWP(20,"esp"),$key_);
++	&mov	(&DWP(24,"esp"),$key_);
++	&mov	(&DWP(28,"esp"),$key_);
++
++	&movdqa	($inout3,&QWP(0,"esp"));	# bswap mask
++	&movdqa	($inout0,$ivec);
++
++	&mov	($key_,$key);
++	&mov	($rounds_,$rounds);
++
++	&pshufb	($ivec,$inout3);
++	if ($inline)
++	{   &aesni_inline_generate1("enc");	}
++	else
++	{   &call	("_aesni_encrypt1");	}
++	&shl	($rounds_,4);
++	&mov	($rounds,16);
++	&movups	($in0,&QWP(0,$inp));		# load inp
++	&paddq	($ivec,&QWP(16,"esp"));
++	&lea	($inp,&QWP(16,$inp));
++	&sub	($rounds,$rounds_);
++	&lea	($key,&DWP(32,$key_,$rounds_));
++	&mov	($rounds_,$rounds);
++	&jmp	(&label("ccm64_dec_outer"));
++
++&set_label("ccm64_dec_outer",16);
++	&xorps	($in0,$inout0);			# inp ^= E(ivec)
++	&movdqa	($inout0,$ivec);
++	&movups	(&QWP(0,$out),$in0);		# save output
++	&lea	($out,&DWP(16,$out));
++	&pshufb	($inout0,$inout3);
++
++	&sub	($len,1);
++	&jz	(&label("ccm64_dec_break"));
++
++	&$movekey	($rndkey0,&QWP(0,$key_));
++	&mov		($rounds,$rounds_);
++	&$movekey	($rndkey1,&QWP(16,$key_));
++	&xorps		($in0,$rndkey0);
++	&xorps		($inout0,$rndkey0);
++	&xorps		($cmac,$in0);		# cmac^=out
++	&$movekey	($rndkey0,&QWP(32,$key_));
++
++&set_label("ccm64_dec2_loop");
++	&aesenc		($inout0,$rndkey1);
++	&aesenc		($cmac,$rndkey1);
++	&$movekey	($rndkey1,&QWP(0,$key,$rounds));
++	&add		($rounds,32);
++	&aesenc		($inout0,$rndkey0);
++	&aesenc		($cmac,$rndkey0);
++	&$movekey	($rndkey0,&QWP(-16,$key,$rounds));
++	&jnz		(&label("ccm64_dec2_loop"));
++	&movups		($in0,&QWP(0,$inp));	# load inp
++	&paddq		($ivec,&QWP(16,"esp"));
++	&aesenc		($inout0,$rndkey1);
++	&aesenc		($cmac,$rndkey1);
++	&aesenclast	($inout0,$rndkey0);
++	&aesenclast	($cmac,$rndkey0);
++	&lea		($inp,&QWP(16,$inp));
++	&jmp	(&label("ccm64_dec_outer"));
++
++&set_label("ccm64_dec_break",16);
++	&mov	($rounds,&DWP(240,$key_));
++	&mov	($key,$key_);
++	if ($inline)
++	{   &aesni_inline_generate1("enc",$cmac,$in0);	}
++	else
++	{   &call	("_aesni_encrypt1",$cmac);	}
++
++	&mov	("esp",&DWP(48,"esp"));
++	&mov	($out,&wparam(5));
++	&movups	(&QWP(0,$out),$cmac);
++
++	&pxor	("xmm0","xmm0");		# clear register bank
++	&pxor	("xmm1","xmm1");
++	&pxor	("xmm2","xmm2");
++	&pxor	("xmm3","xmm3");
++	&pxor	("xmm4","xmm4");
++	&pxor	("xmm5","xmm5");
++	&pxor	("xmm6","xmm6");
++	&pxor	("xmm7","xmm7");
++&function_end("aesni_ccm64_decrypt_blocks");
++}
++
++######################################################################
++# void aesni_ctr32_encrypt_blocks (const void *in, void *out,
++#                         size_t blocks, const AES_KEY *key,
++#                         const char *ivec);
++#
++# Handles only complete blocks, operates on 32-bit counter and
++# does not update *ivec! (see crypto/modes/ctr128.c for details)
++#
++# stack layout:
++#	0	pshufb mask
++#	16	vector addend: 0,6,6,6
++# 	32	counter-less ivec
++#	48	1st triplet of counter vector
++#	64	2nd triplet of counter vector
++#	80	saved %esp
++
++&function_begin("aesni_ctr32_encrypt_blocks");
++	&mov	($inp,&wparam(0));
++	&mov	($out,&wparam(1));
++	&mov	($len,&wparam(2));
++	&mov	($key,&wparam(3));
++	&mov	($rounds_,&wparam(4));
++	&mov	($key_,"esp");
++	&sub	("esp",88);
++	&and	("esp",-16);			# align stack
++	&mov	(&DWP(80,"esp"),$key_);
++
++	&cmp	($len,1);
++	&je	(&label("ctr32_one_shortcut"));
++
++	&movdqu	($inout5,&QWP(0,$rounds_));	# load ivec
++
++	# compose byte-swap control mask for pshufb on stack
++	&mov	(&DWP(0,"esp"),0x0c0d0e0f);
++	&mov	(&DWP(4,"esp"),0x08090a0b);
++	&mov	(&DWP(8,"esp"),0x04050607);
++	&mov	(&DWP(12,"esp"),0x00010203);
++
++	# compose counter increment vector on stack
++	&mov	($rounds,6);
++	&xor	($key_,$key_);
++	&mov	(&DWP(16,"esp"),$rounds);
++	&mov	(&DWP(20,"esp"),$rounds);
++	&mov	(&DWP(24,"esp"),$rounds);
++	&mov	(&DWP(28,"esp"),$key_);
++
++	&pextrd	($rounds_,$inout5,3);		# pull 32-bit counter
++	&pinsrd	($inout5,$key_,3);		# wipe 32-bit counter
++
++	&mov	($rounds,&DWP(240,$key));	# key->rounds
++
++	# compose 2 vectors of 3x32-bit counters
++	&bswap	($rounds_);
++	&pxor	($rndkey0,$rndkey0);
++	&pxor	($rndkey1,$rndkey1);
++	&movdqa	($inout0,&QWP(0,"esp"));	# load byte-swap mask
++	&pinsrd	($rndkey0,$rounds_,0);
++	&lea	($key_,&DWP(3,$rounds_));
++	&pinsrd	($rndkey1,$key_,0);
++	&inc	($rounds_);
++	&pinsrd	($rndkey0,$rounds_,1);
++	&inc	($key_);
++	&pinsrd	($rndkey1,$key_,1);
++	&inc	($rounds_);
++	&pinsrd	($rndkey0,$rounds_,2);
++	&inc	($key_);
++	&pinsrd	($rndkey1,$key_,2);
++	&movdqa	(&QWP(48,"esp"),$rndkey0);	# save 1st triplet
++	&pshufb	($rndkey0,$inout0);		# byte swap
++	&movdqu	($inout4,&QWP(0,$key));		# key[0]
++	&movdqa	(&QWP(64,"esp"),$rndkey1);	# save 2nd triplet
++	&pshufb	($rndkey1,$inout0);		# byte swap
++
++	&pshufd	($inout0,$rndkey0,3<<6);	# place counter to upper dword
++	&pshufd	($inout1,$rndkey0,2<<6);
++	&cmp	($len,6);
++	&jb	(&label("ctr32_tail"));
++	&pxor	($inout5,$inout4);		# counter-less ivec^key[0]
++	&shl	($rounds,4);
++	&mov	($rounds_,16);
++	&movdqa	(&QWP(32,"esp"),$inout5);	# save counter-less ivec^key[0]
++	&mov	($key_,$key);			# backup $key
++	&sub	($rounds_,$rounds);		# backup twisted $rounds
++	&lea	($key,&DWP(32,$key,$rounds));
++	&sub	($len,6);
++	&jmp	(&label("ctr32_loop6"));
++
++&set_label("ctr32_loop6",16);
++	# inlining _aesni_encrypt6's prologue gives ~6% improvement...
++	&pshufd	($inout2,$rndkey0,1<<6);
++	&movdqa	($rndkey0,&QWP(32,"esp"));	# pull counter-less ivec
++	&pshufd	($inout3,$rndkey1,3<<6);
++	&pxor		($inout0,$rndkey0);	# merge counter-less ivec
++	&pshufd	($inout4,$rndkey1,2<<6);
++	&pxor		($inout1,$rndkey0);
++	&pshufd	($inout5,$rndkey1,1<<6);
++	&$movekey	($rndkey1,&QWP(16,$key_));
++	&pxor		($inout2,$rndkey0);
++	&pxor		($inout3,$rndkey0);
++	&aesenc		($inout0,$rndkey1);
++	&pxor		($inout4,$rndkey0);
++	&pxor		($inout5,$rndkey0);
++	&aesenc		($inout1,$rndkey1);
++	&$movekey	($rndkey0,&QWP(32,$key_));
++	&mov		($rounds,$rounds_);
++	&aesenc		($inout2,$rndkey1);
++	&aesenc		($inout3,$rndkey1);
++	&aesenc		($inout4,$rndkey1);
++	&aesenc		($inout5,$rndkey1);
++
++	&call		(&label("_aesni_encrypt6_enter"));
++
++	&movups	($rndkey1,&QWP(0,$inp));
++	&movups	($rndkey0,&QWP(0x10,$inp));
++	&xorps	($inout0,$rndkey1);
++	&movups	($rndkey1,&QWP(0x20,$inp));
++	&xorps	($inout1,$rndkey0);
++	&movups	(&QWP(0,$out),$inout0);
++	&movdqa	($rndkey0,&QWP(16,"esp"));	# load increment
++	&xorps	($inout2,$rndkey1);
++	&movdqa	($rndkey1,&QWP(64,"esp"));	# load 2nd triplet
++	&movups	(&QWP(0x10,$out),$inout1);
++	&movups	(&QWP(0x20,$out),$inout2);
++
++	&paddd	($rndkey1,$rndkey0);		# 2nd triplet increment
++	&paddd	($rndkey0,&QWP(48,"esp"));	# 1st triplet increment
++	&movdqa	($inout0,&QWP(0,"esp"));	# load byte swap mask
++
++	&movups	($inout1,&QWP(0x30,$inp));
++	&movups	($inout2,&QWP(0x40,$inp));
++	&xorps	($inout3,$inout1);
++	&movups	($inout1,&QWP(0x50,$inp));
++	&lea	($inp,&DWP(0x60,$inp));
++	&movdqa	(&QWP(48,"esp"),$rndkey0);	# save 1st triplet
++	&pshufb	($rndkey0,$inout0);		# byte swap
++	&xorps	($inout4,$inout2);
++	&movups	(&QWP(0x30,$out),$inout3);
++	&xorps	($inout5,$inout1);
++	&movdqa	(&QWP(64,"esp"),$rndkey1);	# save 2nd triplet
++	&pshufb	($rndkey1,$inout0);		# byte swap
++	&movups	(&QWP(0x40,$out),$inout4);
++	&pshufd	($inout0,$rndkey0,3<<6);
++	&movups	(&QWP(0x50,$out),$inout5);
++	&lea	($out,&DWP(0x60,$out));
++
++	&pshufd	($inout1,$rndkey0,2<<6);
++	&sub	($len,6);
++	&jnc	(&label("ctr32_loop6"));
++
++	&add	($len,6);
++	&jz	(&label("ctr32_ret"));
++	&movdqu	($inout5,&QWP(0,$key_));
++	&mov	($key,$key_);
++	&pxor	($inout5,&QWP(32,"esp"));	# restore count-less ivec
++	&mov	($rounds,&DWP(240,$key_));	# restore $rounds
++
++&set_label("ctr32_tail");
++	&por	($inout0,$inout5);
++	&cmp	($len,2);
++	&jb	(&label("ctr32_one"));
++
++	&pshufd	($inout2,$rndkey0,1<<6);
++	&por	($inout1,$inout5);
++	&je	(&label("ctr32_two"));
++
++	&pshufd	($inout3,$rndkey1,3<<6);
++	&por	($inout2,$inout5);
++	&cmp	($len,4);
++	&jb	(&label("ctr32_three"));
++
++	&pshufd	($inout4,$rndkey1,2<<6);
++	&por	($inout3,$inout5);
++	&je	(&label("ctr32_four"));
++
++	&por	($inout4,$inout5);
++	&call	("_aesni_encrypt6");
++	&movups	($rndkey1,&QWP(0,$inp));
++	&movups	($rndkey0,&QWP(0x10,$inp));
++	&xorps	($inout0,$rndkey1);
++	&movups	($rndkey1,&QWP(0x20,$inp));
++	&xorps	($inout1,$rndkey0);
++	&movups	($rndkey0,&QWP(0x30,$inp));
++	&xorps	($inout2,$rndkey1);
++	&movups	($rndkey1,&QWP(0x40,$inp));
++	&xorps	($inout3,$rndkey0);
++	&movups	(&QWP(0,$out),$inout0);
++	&xorps	($inout4,$rndkey1);
++	&movups	(&QWP(0x10,$out),$inout1);
++	&movups	(&QWP(0x20,$out),$inout2);
++	&movups	(&QWP(0x30,$out),$inout3);
++	&movups	(&QWP(0x40,$out),$inout4);
++	&jmp	(&label("ctr32_ret"));
++
++&set_label("ctr32_one_shortcut",16);
++	&movups	($inout0,&QWP(0,$rounds_));	# load ivec
++	&mov	($rounds,&DWP(240,$key));
++	
++&set_label("ctr32_one");
++	if ($inline)
++	{   &aesni_inline_generate1("enc");	}
++	else
++	{   &call	("_aesni_encrypt1");	}
++	&movups	($in0,&QWP(0,$inp));
++	&xorps	($in0,$inout0);
++	&movups	(&QWP(0,$out),$in0);
++	&jmp	(&label("ctr32_ret"));
++
++&set_label("ctr32_two",16);
++	&call	("_aesni_encrypt2");
++	&movups	($inout3,&QWP(0,$inp));
++	&movups	($inout4,&QWP(0x10,$inp));
++	&xorps	($inout0,$inout3);
++	&xorps	($inout1,$inout4);
++	&movups	(&QWP(0,$out),$inout0);
++	&movups	(&QWP(0x10,$out),$inout1);
++	&jmp	(&label("ctr32_ret"));
++
++&set_label("ctr32_three",16);
++	&call	("_aesni_encrypt3");
++	&movups	($inout3,&QWP(0,$inp));
++	&movups	($inout4,&QWP(0x10,$inp));
++	&xorps	($inout0,$inout3);
++	&movups	($inout5,&QWP(0x20,$inp));
++	&xorps	($inout1,$inout4);
++	&movups	(&QWP(0,$out),$inout0);
++	&xorps	($inout2,$inout5);
++	&movups	(&QWP(0x10,$out),$inout1);
++	&movups	(&QWP(0x20,$out),$inout2);
++	&jmp	(&label("ctr32_ret"));
++
++&set_label("ctr32_four",16);
++	&call	("_aesni_encrypt4");
++	&movups	($inout4,&QWP(0,$inp));
++	&movups	($inout5,&QWP(0x10,$inp));
++	&movups	($rndkey1,&QWP(0x20,$inp));
++	&xorps	($inout0,$inout4);
++	&movups	($rndkey0,&QWP(0x30,$inp));
++	&xorps	($inout1,$inout5);
++	&movups	(&QWP(0,$out),$inout0);
++	&xorps	($inout2,$rndkey1);
++	&movups	(&QWP(0x10,$out),$inout1);
++	&xorps	($inout3,$rndkey0);
++	&movups	(&QWP(0x20,$out),$inout2);
++	&movups	(&QWP(0x30,$out),$inout3);
++
++&set_label("ctr32_ret");
++	&pxor	("xmm0","xmm0");		# clear register bank
++	&pxor	("xmm1","xmm1");
++	&pxor	("xmm2","xmm2");
++	&pxor	("xmm3","xmm3");
++	&pxor	("xmm4","xmm4");
++	&movdqa	(&QWP(32,"esp"),"xmm0");	# clear stack
++	&pxor	("xmm5","xmm5");
++	&movdqa	(&QWP(48,"esp"),"xmm0");
++	&pxor	("xmm6","xmm6");
++	&movdqa	(&QWP(64,"esp"),"xmm0");
++	&pxor	("xmm7","xmm7");
++	&mov	("esp",&DWP(80,"esp"));
++&function_end("aesni_ctr32_encrypt_blocks");
++
++######################################################################
++# void aesni_xts_[en|de]crypt(const char *inp,char *out,size_t len,
++#	const AES_KEY *key1, const AES_KEY *key2
++#	const unsigned char iv[16]);
++#
++{ my ($tweak,$twtmp,$twres,$twmask)=($rndkey1,$rndkey0,$inout0,$inout1);
++
++&function_begin("aesni_xts_encrypt");
++	&mov	($key,&wparam(4));		# key2
++	&mov	($inp,&wparam(5));		# clear-text tweak
++
++	&mov	($rounds,&DWP(240,$key));	# key2->rounds
++	&movups	($inout0,&QWP(0,$inp));
++	if ($inline)
++	{   &aesni_inline_generate1("enc");	}
++	else
++	{   &call	("_aesni_encrypt1");	}
++
++	&mov	($inp,&wparam(0));
++	&mov	($out,&wparam(1));
++	&mov	($len,&wparam(2));
++	&mov	($key,&wparam(3));		# key1
++
++	&mov	($key_,"esp");
++	&sub	("esp",16*7+8);
++	&mov	($rounds,&DWP(240,$key));	# key1->rounds
++	&and	("esp",-16);			# align stack
++
++	&mov	(&DWP(16*6+0,"esp"),0x87);	# compose the magic constant
++	&mov	(&DWP(16*6+4,"esp"),0);
++	&mov	(&DWP(16*6+8,"esp"),1);
++	&mov	(&DWP(16*6+12,"esp"),0);
++	&mov	(&DWP(16*7+0,"esp"),$len);	# save original $len
++	&mov	(&DWP(16*7+4,"esp"),$key_);	# save original %esp
++
++	&movdqa	($tweak,$inout0);
++	&pxor	($twtmp,$twtmp);
++	&movdqa	($twmask,&QWP(6*16,"esp"));	# 0x0...010...87
++	&pcmpgtd($twtmp,$tweak);		# broadcast upper bits
++
++	&and	($len,-16);
++	&mov	($key_,$key);			# backup $key
++	&mov	($rounds_,$rounds);		# backup $rounds
++	&sub	($len,16*6);
++	&jc	(&label("xts_enc_short"));
++
++	&shl	($rounds,4);
++	&mov	($rounds_,16);
++	&sub	($rounds_,$rounds);
++	&lea	($key,&DWP(32,$key,$rounds));
++	&jmp	(&label("xts_enc_loop6"));
++
++&set_label("xts_enc_loop6",16);
++	for ($i=0;$i<4;$i++) {
++	    &pshufd	($twres,$twtmp,0x13);
++	    &pxor	($twtmp,$twtmp);
++	    &movdqa	(&QWP(16*$i,"esp"),$tweak);
++	    &paddq	($tweak,$tweak);	# &psllq($tweak,1);
++	    &pand	($twres,$twmask);	# isolate carry and residue
++	    &pcmpgtd	($twtmp,$tweak);	# broadcast upper bits
++	    &pxor	($tweak,$twres);
++	}
++	&pshufd	($inout5,$twtmp,0x13);
++	&movdqa	(&QWP(16*$i++,"esp"),$tweak);
++	&paddq	($tweak,$tweak);		# &psllq($tweak,1);
++	 &$movekey	($rndkey0,&QWP(0,$key_));
++	&pand	($inout5,$twmask);		# isolate carry and residue
++	 &movups	($inout0,&QWP(0,$inp));	# load input
++	&pxor	($inout5,$tweak);
++
++	# inline _aesni_encrypt6 prologue and flip xor with tweak and key[0]
++	&mov	($rounds,$rounds_);		# restore $rounds
++	&movdqu	($inout1,&QWP(16*1,$inp));
++	 &xorps		($inout0,$rndkey0);	# input^=rndkey[0]
++	&movdqu	($inout2,&QWP(16*2,$inp));
++	 &pxor		($inout1,$rndkey0);
++	&movdqu	($inout3,&QWP(16*3,$inp));
++	 &pxor		($inout2,$rndkey0);
++	&movdqu	($inout4,&QWP(16*4,$inp));
++	 &pxor		($inout3,$rndkey0);
++	&movdqu	($rndkey1,&QWP(16*5,$inp));
++	 &pxor		($inout4,$rndkey0);
++	&lea	($inp,&DWP(16*6,$inp));
++	&pxor	($inout0,&QWP(16*0,"esp"));	# input^=tweak
++	&movdqa	(&QWP(16*$i,"esp"),$inout5);	# save last tweak
++	&pxor	($inout5,$rndkey1);
++
++	 &$movekey	($rndkey1,&QWP(16,$key_));
++	&pxor	($inout1,&QWP(16*1,"esp"));
++	&pxor	($inout2,&QWP(16*2,"esp"));
++	 &aesenc	($inout0,$rndkey1);
++	&pxor	($inout3,&QWP(16*3,"esp"));
++	&pxor	($inout4,&QWP(16*4,"esp"));
++	 &aesenc	($inout1,$rndkey1);
++	&pxor		($inout5,$rndkey0);
++	 &$movekey	($rndkey0,&QWP(32,$key_));
++	 &aesenc	($inout2,$rndkey1);
++	 &aesenc	($inout3,$rndkey1);
++	 &aesenc	($inout4,$rndkey1);
++	 &aesenc	($inout5,$rndkey1);
++	&call		(&label("_aesni_encrypt6_enter"));
++
++	&movdqa	($tweak,&QWP(16*5,"esp"));	# last tweak
++       &pxor	($twtmp,$twtmp);
++	&xorps	($inout0,&QWP(16*0,"esp"));	# output^=tweak
++       &pcmpgtd	($twtmp,$tweak);		# broadcast upper bits
++	&xorps	($inout1,&QWP(16*1,"esp"));
++	&movups	(&QWP(16*0,$out),$inout0);	# write output
++	&xorps	($inout2,&QWP(16*2,"esp"));
++	&movups	(&QWP(16*1,$out),$inout1);
++	&xorps	($inout3,&QWP(16*3,"esp"));
++	&movups	(&QWP(16*2,$out),$inout2);
++	&xorps	($inout4,&QWP(16*4,"esp"));
++	&movups	(&QWP(16*3,$out),$inout3);
++	&xorps	($inout5,$tweak);
++	&movups	(&QWP(16*4,$out),$inout4);
++       &pshufd	($twres,$twtmp,0x13);
++	&movups	(&QWP(16*5,$out),$inout5);
++	&lea	($out,&DWP(16*6,$out));
++       &movdqa	($twmask,&QWP(16*6,"esp"));	# 0x0...010...87
++
++	&pxor	($twtmp,$twtmp);
++	&paddq	($tweak,$tweak);		# &psllq($tweak,1);
++	&pand	($twres,$twmask);		# isolate carry and residue
++	&pcmpgtd($twtmp,$tweak);		# broadcast upper bits
++	&pxor	($tweak,$twres);
++
++	&sub	($len,16*6);
++	&jnc	(&label("xts_enc_loop6"));
++
++	&mov	($rounds,&DWP(240,$key_));	# restore $rounds
++	&mov	($key,$key_);			# restore $key
++	&mov	($rounds_,$rounds);
++
++&set_label("xts_enc_short");
++	&add	($len,16*6);
++	&jz	(&label("xts_enc_done6x"));
++
++	&movdqa	($inout3,$tweak);		# put aside previous tweak
++	&cmp	($len,0x20);
++	&jb	(&label("xts_enc_one"));
++
++	&pshufd	($twres,$twtmp,0x13);
++	&pxor	($twtmp,$twtmp);
++	&paddq	($tweak,$tweak);		# &psllq($tweak,1);
++	&pand	($twres,$twmask);		# isolate carry and residue
++	&pcmpgtd($twtmp,$tweak);		# broadcast upper bits
++	&pxor	($tweak,$twres);
++	&je	(&label("xts_enc_two"));
++
++	&pshufd	($twres,$twtmp,0x13);
++	&pxor	($twtmp,$twtmp);
++	&movdqa	($inout4,$tweak);		# put aside previous tweak
++	&paddq	($tweak,$tweak);		# &psllq($tweak,1);
++	&pand	($twres,$twmask);		# isolate carry and residue
++	&pcmpgtd($twtmp,$tweak);		# broadcast upper bits
++	&pxor	($tweak,$twres);
++	&cmp	($len,0x40);
++	&jb	(&label("xts_enc_three"));
++
++	&pshufd	($twres,$twtmp,0x13);
++	&pxor	($twtmp,$twtmp);
++	&movdqa	($inout5,$tweak);		# put aside previous tweak
++	&paddq	($tweak,$tweak);		# &psllq($tweak,1);
++	&pand	($twres,$twmask);		# isolate carry and residue
++	&pcmpgtd($twtmp,$tweak);		# broadcast upper bits
++	&pxor	($tweak,$twres);
++	&movdqa	(&QWP(16*0,"esp"),$inout3);
++	&movdqa	(&QWP(16*1,"esp"),$inout4);
++	&je	(&label("xts_enc_four"));
++
++	&movdqa	(&QWP(16*2,"esp"),$inout5);
++	&pshufd	($inout5,$twtmp,0x13);
++	&movdqa	(&QWP(16*3,"esp"),$tweak);
++	&paddq	($tweak,$tweak);		# &psllq($inout0,1);
++	&pand	($inout5,$twmask);		# isolate carry and residue
++	&pxor	($inout5,$tweak);
++
++	&movdqu	($inout0,&QWP(16*0,$inp));	# load input
++	&movdqu	($inout1,&QWP(16*1,$inp));
++	&movdqu	($inout2,&QWP(16*2,$inp));
++	&pxor	($inout0,&QWP(16*0,"esp"));	# input^=tweak
++	&movdqu	($inout3,&QWP(16*3,$inp));
++	&pxor	($inout1,&QWP(16*1,"esp"));
++	&movdqu	($inout4,&QWP(16*4,$inp));
++	&pxor	($inout2,&QWP(16*2,"esp"));
++	&lea	($inp,&DWP(16*5,$inp));
++	&pxor	($inout3,&QWP(16*3,"esp"));
++	&movdqa	(&QWP(16*4,"esp"),$inout5);	# save last tweak
++	&pxor	($inout4,$inout5);
++
++	&call	("_aesni_encrypt6");
++
++	&movaps	($tweak,&QWP(16*4,"esp"));	# last tweak
++	&xorps	($inout0,&QWP(16*0,"esp"));	# output^=tweak
++	&xorps	($inout1,&QWP(16*1,"esp"));
++	&xorps	($inout2,&QWP(16*2,"esp"));
++	&movups	(&QWP(16*0,$out),$inout0);	# write output
++	&xorps	($inout3,&QWP(16*3,"esp"));
++	&movups	(&QWP(16*1,$out),$inout1);
++	&xorps	($inout4,$tweak);
++	&movups	(&QWP(16*2,$out),$inout2);
++	&movups	(&QWP(16*3,$out),$inout3);
++	&movups	(&QWP(16*4,$out),$inout4);
++	&lea	($out,&DWP(16*5,$out));
++	&jmp	(&label("xts_enc_done"));
++
++&set_label("xts_enc_one",16);
++	&movups	($inout0,&QWP(16*0,$inp));	# load input
++	&lea	($inp,&DWP(16*1,$inp));
++	&xorps	($inout0,$inout3);		# input^=tweak
++	if ($inline)
++	{   &aesni_inline_generate1("enc");	}
++	else
++	{   &call	("_aesni_encrypt1");	}
++	&xorps	($inout0,$inout3);		# output^=tweak
++	&movups	(&QWP(16*0,$out),$inout0);	# write output
++	&lea	($out,&DWP(16*1,$out));
++
++	&movdqa	($tweak,$inout3);		# last tweak
++	&jmp	(&label("xts_enc_done"));
++
++&set_label("xts_enc_two",16);
++	&movaps	($inout4,$tweak);		# put aside last tweak
++
++	&movups	($inout0,&QWP(16*0,$inp));	# load input
++	&movups	($inout1,&QWP(16*1,$inp));
++	&lea	($inp,&DWP(16*2,$inp));
++	&xorps	($inout0,$inout3);		# input^=tweak
++	&xorps	($inout1,$inout4);
++
++	&call	("_aesni_encrypt2");
++
++	&xorps	($inout0,$inout3);		# output^=tweak
++	&xorps	($inout1,$inout4);
++	&movups	(&QWP(16*0,$out),$inout0);	# write output
++	&movups	(&QWP(16*1,$out),$inout1);
++	&lea	($out,&DWP(16*2,$out));
++
++	&movdqa	($tweak,$inout4);		# last tweak
++	&jmp	(&label("xts_enc_done"));
++
++&set_label("xts_enc_three",16);
++	&movaps	($inout5,$tweak);		# put aside last tweak
++	&movups	($inout0,&QWP(16*0,$inp));	# load input
++	&movups	($inout1,&QWP(16*1,$inp));
++	&movups	($inout2,&QWP(16*2,$inp));
++	&lea	($inp,&DWP(16*3,$inp));
++	&xorps	($inout0,$inout3);		# input^=tweak
++	&xorps	($inout1,$inout4);
++	&xorps	($inout2,$inout5);
++
++	&call	("_aesni_encrypt3");
++
++	&xorps	($inout0,$inout3);		# output^=tweak
++	&xorps	($inout1,$inout4);
++	&xorps	($inout2,$inout5);
++	&movups	(&QWP(16*0,$out),$inout0);	# write output
++	&movups	(&QWP(16*1,$out),$inout1);
++	&movups	(&QWP(16*2,$out),$inout2);
++	&lea	($out,&DWP(16*3,$out));
++
++	&movdqa	($tweak,$inout5);		# last tweak
++	&jmp	(&label("xts_enc_done"));
++
++&set_label("xts_enc_four",16);
++	&movaps	($inout4,$tweak);		# put aside last tweak
++
++	&movups	($inout0,&QWP(16*0,$inp));	# load input
++	&movups	($inout1,&QWP(16*1,$inp));
++	&movups	($inout2,&QWP(16*2,$inp));
++	&xorps	($inout0,&QWP(16*0,"esp"));	# input^=tweak
++	&movups	($inout3,&QWP(16*3,$inp));
++	&lea	($inp,&DWP(16*4,$inp));
++	&xorps	($inout1,&QWP(16*1,"esp"));
++	&xorps	($inout2,$inout5);
++	&xorps	($inout3,$inout4);
++
++	&call	("_aesni_encrypt4");
++
++	&xorps	($inout0,&QWP(16*0,"esp"));	# output^=tweak
++	&xorps	($inout1,&QWP(16*1,"esp"));
++	&xorps	($inout2,$inout5);
++	&movups	(&QWP(16*0,$out),$inout0);	# write output
++	&xorps	($inout3,$inout4);
++	&movups	(&QWP(16*1,$out),$inout1);
++	&movups	(&QWP(16*2,$out),$inout2);
++	&movups	(&QWP(16*3,$out),$inout3);
++	&lea	($out,&DWP(16*4,$out));
++
++	&movdqa	($tweak,$inout4);		# last tweak
++	&jmp	(&label("xts_enc_done"));
++
++&set_label("xts_enc_done6x",16);		# $tweak is pre-calculated
++	&mov	($len,&DWP(16*7+0,"esp"));	# restore original $len
++	&and	($len,15);
++	&jz	(&label("xts_enc_ret"));
++	&movdqa	($inout3,$tweak);
++	&mov	(&DWP(16*7+0,"esp"),$len);	# save $len%16
++	&jmp	(&label("xts_enc_steal"));
++
++&set_label("xts_enc_done",16);
++	&mov	($len,&DWP(16*7+0,"esp"));	# restore original $len
++	&pxor	($twtmp,$twtmp);
++	&and	($len,15);
++	&jz	(&label("xts_enc_ret"));
++
++	&pcmpgtd($twtmp,$tweak);		# broadcast upper bits
++	&mov	(&DWP(16*7+0,"esp"),$len);	# save $len%16
++	&pshufd	($inout3,$twtmp,0x13);
++	&paddq	($tweak,$tweak);		# &psllq($tweak,1);
++	&pand	($inout3,&QWP(16*6,"esp"));	# isolate carry and residue
++	&pxor	($inout3,$tweak);
++
++&set_label("xts_enc_steal");
++	&movz	($rounds,&BP(0,$inp));
++	&movz	($key,&BP(-16,$out));
++	&lea	($inp,&DWP(1,$inp));
++	&mov	(&BP(-16,$out),&LB($rounds));
++	&mov	(&BP(0,$out),&LB($key));
++	&lea	($out,&DWP(1,$out));
++	&sub	($len,1);
++	&jnz	(&label("xts_enc_steal"));
++
++	&sub	($out,&DWP(16*7+0,"esp"));	# rewind $out
++	&mov	($key,$key_);			# restore $key
++	&mov	($rounds,$rounds_);		# restore $rounds
++
++	&movups	($inout0,&QWP(-16,$out));	# load input
++	&xorps	($inout0,$inout3);		# input^=tweak
++	if ($inline)
++	{   &aesni_inline_generate1("enc");	}
++	else
++	{   &call	("_aesni_encrypt1");	}
++	&xorps	($inout0,$inout3);		# output^=tweak
++	&movups	(&QWP(-16,$out),$inout0);	# write output
++
++&set_label("xts_enc_ret");
++	&pxor	("xmm0","xmm0");		# clear register bank
++	&pxor	("xmm1","xmm1");
++	&pxor	("xmm2","xmm2");
++	&movdqa	(&QWP(16*0,"esp"),"xmm0");	# clear stack
++	&pxor	("xmm3","xmm3");
++	&movdqa	(&QWP(16*1,"esp"),"xmm0");
++	&pxor	("xmm4","xmm4");
++	&movdqa	(&QWP(16*2,"esp"),"xmm0");
++	&pxor	("xmm5","xmm5");
++	&movdqa	(&QWP(16*3,"esp"),"xmm0");
++	&pxor	("xmm6","xmm6");
++	&movdqa	(&QWP(16*4,"esp"),"xmm0");
++	&pxor	("xmm7","xmm7");
++	&movdqa	(&QWP(16*5,"esp"),"xmm0");
++	&mov	("esp",&DWP(16*7+4,"esp"));	# restore %esp
++&function_end("aesni_xts_encrypt");
++
++&function_begin("aesni_xts_decrypt");
++	&mov	($key,&wparam(4));		# key2
++	&mov	($inp,&wparam(5));		# clear-text tweak
++
++	&mov	($rounds,&DWP(240,$key));	# key2->rounds
++	&movups	($inout0,&QWP(0,$inp));
++	if ($inline)
++	{   &aesni_inline_generate1("enc");	}
++	else
++	{   &call	("_aesni_encrypt1");	}
++
++	&mov	($inp,&wparam(0));
++	&mov	($out,&wparam(1));
++	&mov	($len,&wparam(2));
++	&mov	($key,&wparam(3));		# key1
++
++	&mov	($key_,"esp");
++	&sub	("esp",16*7+8);
++	&and	("esp",-16);			# align stack
++
++	&xor	($rounds_,$rounds_);		# if(len%16) len-=16;
++	&test	($len,15);
++	&setnz	(&LB($rounds_));
++	&shl	($rounds_,4);
++	&sub	($len,$rounds_);
++
++	&mov	(&DWP(16*6+0,"esp"),0x87);	# compose the magic constant
++	&mov	(&DWP(16*6+4,"esp"),0);
++	&mov	(&DWP(16*6+8,"esp"),1);
++	&mov	(&DWP(16*6+12,"esp"),0);
++	&mov	(&DWP(16*7+0,"esp"),$len);	# save original $len
++	&mov	(&DWP(16*7+4,"esp"),$key_);	# save original %esp
++
++	&mov	($rounds,&DWP(240,$key));	# key1->rounds
++	&mov	($key_,$key);			# backup $key
++	&mov	($rounds_,$rounds);		# backup $rounds
++
++	&movdqa	($tweak,$inout0);
++	&pxor	($twtmp,$twtmp);
++	&movdqa	($twmask,&QWP(6*16,"esp"));	# 0x0...010...87
++	&pcmpgtd($twtmp,$tweak);		# broadcast upper bits
++
++	&and	($len,-16);
++	&sub	($len,16*6);
++	&jc	(&label("xts_dec_short"));
++
++	&shl	($rounds,4);
++	&mov	($rounds_,16);
++	&sub	($rounds_,$rounds);
++	&lea	($key,&DWP(32,$key,$rounds));
++	&jmp	(&label("xts_dec_loop6"));
++
++&set_label("xts_dec_loop6",16);
++	for ($i=0;$i<4;$i++) {
++	    &pshufd	($twres,$twtmp,0x13);
++	    &pxor	($twtmp,$twtmp);
++	    &movdqa	(&QWP(16*$i,"esp"),$tweak);
++	    &paddq	($tweak,$tweak);	# &psllq($tweak,1);
++	    &pand	($twres,$twmask);	# isolate carry and residue
++	    &pcmpgtd	($twtmp,$tweak);	# broadcast upper bits
++	    &pxor	($tweak,$twres);
++	}
++	&pshufd	($inout5,$twtmp,0x13);
++	&movdqa	(&QWP(16*$i++,"esp"),$tweak);
++	&paddq	($tweak,$tweak);		# &psllq($tweak,1);
++	 &$movekey	($rndkey0,&QWP(0,$key_));
++	&pand	($inout5,$twmask);		# isolate carry and residue
++	 &movups	($inout0,&QWP(0,$inp));	# load input
++	&pxor	($inout5,$tweak);
++
++	# inline _aesni_encrypt6 prologue and flip xor with tweak and key[0]
++	&mov	($rounds,$rounds_);
++	&movdqu	($inout1,&QWP(16*1,$inp));
++	 &xorps		($inout0,$rndkey0);	# input^=rndkey[0]
++	&movdqu	($inout2,&QWP(16*2,$inp));
++	 &pxor		($inout1,$rndkey0);
++	&movdqu	($inout3,&QWP(16*3,$inp));
++	 &pxor		($inout2,$rndkey0);
++	&movdqu	($inout4,&QWP(16*4,$inp));
++	 &pxor		($inout3,$rndkey0);
++	&movdqu	($rndkey1,&QWP(16*5,$inp));
++	 &pxor		($inout4,$rndkey0);
++	&lea	($inp,&DWP(16*6,$inp));
++	&pxor	($inout0,&QWP(16*0,"esp"));	# input^=tweak
++	&movdqa	(&QWP(16*$i,"esp"),$inout5);	# save last tweak
++	&pxor	($inout5,$rndkey1);
++
++	 &$movekey	($rndkey1,&QWP(16,$key_));
++	&pxor	($inout1,&QWP(16*1,"esp"));
++	&pxor	($inout2,&QWP(16*2,"esp"));
++	 &aesdec	($inout0,$rndkey1);
++	&pxor	($inout3,&QWP(16*3,"esp"));
++	&pxor	($inout4,&QWP(16*4,"esp"));
++	 &aesdec	($inout1,$rndkey1);
++	&pxor		($inout5,$rndkey0);
++	 &$movekey	($rndkey0,&QWP(32,$key_));
++	 &aesdec	($inout2,$rndkey1);
++	 &aesdec	($inout3,$rndkey1);
++	 &aesdec	($inout4,$rndkey1);
++	 &aesdec	($inout5,$rndkey1);
++	&call		(&label("_aesni_decrypt6_enter"));
++
++	&movdqa	($tweak,&QWP(16*5,"esp"));	# last tweak
++       &pxor	($twtmp,$twtmp);
++	&xorps	($inout0,&QWP(16*0,"esp"));	# output^=tweak
++       &pcmpgtd	($twtmp,$tweak);		# broadcast upper bits
++	&xorps	($inout1,&QWP(16*1,"esp"));
++	&movups	(&QWP(16*0,$out),$inout0);	# write output
++	&xorps	($inout2,&QWP(16*2,"esp"));
++	&movups	(&QWP(16*1,$out),$inout1);
++	&xorps	($inout3,&QWP(16*3,"esp"));
++	&movups	(&QWP(16*2,$out),$inout2);
++	&xorps	($inout4,&QWP(16*4,"esp"));
++	&movups	(&QWP(16*3,$out),$inout3);
++	&xorps	($inout5,$tweak);
++	&movups	(&QWP(16*4,$out),$inout4);
++       &pshufd	($twres,$twtmp,0x13);
++	&movups	(&QWP(16*5,$out),$inout5);
++	&lea	($out,&DWP(16*6,$out));
++       &movdqa	($twmask,&QWP(16*6,"esp"));	# 0x0...010...87
++
++	&pxor	($twtmp,$twtmp);
++	&paddq	($tweak,$tweak);		# &psllq($tweak,1);
++	&pand	($twres,$twmask);		# isolate carry and residue
++	&pcmpgtd($twtmp,$tweak);		# broadcast upper bits
++	&pxor	($tweak,$twres);
++
++	&sub	($len,16*6);
++	&jnc	(&label("xts_dec_loop6"));
++
++	&mov	($rounds,&DWP(240,$key_));	# restore $rounds
++	&mov	($key,$key_);			# restore $key
++	&mov	($rounds_,$rounds);
++
++&set_label("xts_dec_short");
++	&add	($len,16*6);
++	&jz	(&label("xts_dec_done6x"));
++
++	&movdqa	($inout3,$tweak);		# put aside previous tweak
++	&cmp	($len,0x20);
++	&jb	(&label("xts_dec_one"));
++
++	&pshufd	($twres,$twtmp,0x13);
++	&pxor	($twtmp,$twtmp);
++	&paddq	($tweak,$tweak);		# &psllq($tweak,1);
++	&pand	($twres,$twmask);		# isolate carry and residue
++	&pcmpgtd($twtmp,$tweak);		# broadcast upper bits
++	&pxor	($tweak,$twres);
++	&je	(&label("xts_dec_two"));
++
++	&pshufd	($twres,$twtmp,0x13);
++	&pxor	($twtmp,$twtmp);
++	&movdqa	($inout4,$tweak);		# put aside previous tweak
++	&paddq	($tweak,$tweak);		# &psllq($tweak,1);
++	&pand	($twres,$twmask);		# isolate carry and residue
++	&pcmpgtd($twtmp,$tweak);		# broadcast upper bits
++	&pxor	($tweak,$twres);
++	&cmp	($len,0x40);
++	&jb	(&label("xts_dec_three"));
++
++	&pshufd	($twres,$twtmp,0x13);
++	&pxor	($twtmp,$twtmp);
++	&movdqa	($inout5,$tweak);		# put aside previous tweak
++	&paddq	($tweak,$tweak);		# &psllq($tweak,1);
++	&pand	($twres,$twmask);		# isolate carry and residue
++	&pcmpgtd($twtmp,$tweak);		# broadcast upper bits
++	&pxor	($tweak,$twres);
++	&movdqa	(&QWP(16*0,"esp"),$inout3);
++	&movdqa	(&QWP(16*1,"esp"),$inout4);
++	&je	(&label("xts_dec_four"));
++
++	&movdqa	(&QWP(16*2,"esp"),$inout5);
++	&pshufd	($inout5,$twtmp,0x13);
++	&movdqa	(&QWP(16*3,"esp"),$tweak);
++	&paddq	($tweak,$tweak);		# &psllq($inout0,1);
++	&pand	($inout5,$twmask);		# isolate carry and residue
++	&pxor	($inout5,$tweak);
++
++	&movdqu	($inout0,&QWP(16*0,$inp));	# load input
++	&movdqu	($inout1,&QWP(16*1,$inp));
++	&movdqu	($inout2,&QWP(16*2,$inp));
++	&pxor	($inout0,&QWP(16*0,"esp"));	# input^=tweak
++	&movdqu	($inout3,&QWP(16*3,$inp));
++	&pxor	($inout1,&QWP(16*1,"esp"));
++	&movdqu	($inout4,&QWP(16*4,$inp));
++	&pxor	($inout2,&QWP(16*2,"esp"));
++	&lea	($inp,&DWP(16*5,$inp));
++	&pxor	($inout3,&QWP(16*3,"esp"));
++	&movdqa	(&QWP(16*4,"esp"),$inout5);	# save last tweak
++	&pxor	($inout4,$inout5);
++
++	&call	("_aesni_decrypt6");
++
++	&movaps	($tweak,&QWP(16*4,"esp"));	# last tweak
++	&xorps	($inout0,&QWP(16*0,"esp"));	# output^=tweak
++	&xorps	($inout1,&QWP(16*1,"esp"));
++	&xorps	($inout2,&QWP(16*2,"esp"));
++	&movups	(&QWP(16*0,$out),$inout0);	# write output
++	&xorps	($inout3,&QWP(16*3,"esp"));
++	&movups	(&QWP(16*1,$out),$inout1);
++	&xorps	($inout4,$tweak);
++	&movups	(&QWP(16*2,$out),$inout2);
++	&movups	(&QWP(16*3,$out),$inout3);
++	&movups	(&QWP(16*4,$out),$inout4);
++	&lea	($out,&DWP(16*5,$out));
++	&jmp	(&label("xts_dec_done"));
++
++&set_label("xts_dec_one",16);
++	&movups	($inout0,&QWP(16*0,$inp));	# load input
++	&lea	($inp,&DWP(16*1,$inp));
++	&xorps	($inout0,$inout3);		# input^=tweak
++	if ($inline)
++	{   &aesni_inline_generate1("dec");	}
++	else
++	{   &call	("_aesni_decrypt1");	}
++	&xorps	($inout0,$inout3);		# output^=tweak
++	&movups	(&QWP(16*0,$out),$inout0);	# write output
++	&lea	($out,&DWP(16*1,$out));
++
++	&movdqa	($tweak,$inout3);		# last tweak
++	&jmp	(&label("xts_dec_done"));
++
++&set_label("xts_dec_two",16);
++	&movaps	($inout4,$tweak);		# put aside last tweak
++
++	&movups	($inout0,&QWP(16*0,$inp));	# load input
++	&movups	($inout1,&QWP(16*1,$inp));
++	&lea	($inp,&DWP(16*2,$inp));
++	&xorps	($inout0,$inout3);		# input^=tweak
++	&xorps	($inout1,$inout4);
++
++	&call	("_aesni_decrypt2");
++
++	&xorps	($inout0,$inout3);		# output^=tweak
++	&xorps	($inout1,$inout4);
++	&movups	(&QWP(16*0,$out),$inout0);	# write output
++	&movups	(&QWP(16*1,$out),$inout1);
++	&lea	($out,&DWP(16*2,$out));
++
++	&movdqa	($tweak,$inout4);		# last tweak
++	&jmp	(&label("xts_dec_done"));
++
++&set_label("xts_dec_three",16);
++	&movaps	($inout5,$tweak);		# put aside last tweak
++	&movups	($inout0,&QWP(16*0,$inp));	# load input
++	&movups	($inout1,&QWP(16*1,$inp));
++	&movups	($inout2,&QWP(16*2,$inp));
++	&lea	($inp,&DWP(16*3,$inp));
++	&xorps	($inout0,$inout3);		# input^=tweak
++	&xorps	($inout1,$inout4);
++	&xorps	($inout2,$inout5);
++
++	&call	("_aesni_decrypt3");
++
++	&xorps	($inout0,$inout3);		# output^=tweak
++	&xorps	($inout1,$inout4);
++	&xorps	($inout2,$inout5);
++	&movups	(&QWP(16*0,$out),$inout0);	# write output
++	&movups	(&QWP(16*1,$out),$inout1);
++	&movups	(&QWP(16*2,$out),$inout2);
++	&lea	($out,&DWP(16*3,$out));
++
++	&movdqa	($tweak,$inout5);		# last tweak
++	&jmp	(&label("xts_dec_done"));
++
++&set_label("xts_dec_four",16);
++	&movaps	($inout4,$tweak);		# put aside last tweak
++
++	&movups	($inout0,&QWP(16*0,$inp));	# load input
++	&movups	($inout1,&QWP(16*1,$inp));
++	&movups	($inout2,&QWP(16*2,$inp));
++	&xorps	($inout0,&QWP(16*0,"esp"));	# input^=tweak
++	&movups	($inout3,&QWP(16*3,$inp));
++	&lea	($inp,&DWP(16*4,$inp));
++	&xorps	($inout1,&QWP(16*1,"esp"));
++	&xorps	($inout2,$inout5);
++	&xorps	($inout3,$inout4);
++
++	&call	("_aesni_decrypt4");
++
++	&xorps	($inout0,&QWP(16*0,"esp"));	# output^=tweak
++	&xorps	($inout1,&QWP(16*1,"esp"));
++	&xorps	($inout2,$inout5);
++	&movups	(&QWP(16*0,$out),$inout0);	# write output
++	&xorps	($inout3,$inout4);
++	&movups	(&QWP(16*1,$out),$inout1);
++	&movups	(&QWP(16*2,$out),$inout2);
++	&movups	(&QWP(16*3,$out),$inout3);
++	&lea	($out,&DWP(16*4,$out));
++
++	&movdqa	($tweak,$inout4);		# last tweak
++	&jmp	(&label("xts_dec_done"));
++
++&set_label("xts_dec_done6x",16);		# $tweak is pre-calculated
++	&mov	($len,&DWP(16*7+0,"esp"));	# restore original $len
++	&and	($len,15);
++	&jz	(&label("xts_dec_ret"));
++	&mov	(&DWP(16*7+0,"esp"),$len);	# save $len%16
++	&jmp	(&label("xts_dec_only_one_more"));
++
++&set_label("xts_dec_done",16);
++	&mov	($len,&DWP(16*7+0,"esp"));	# restore original $len
++	&pxor	($twtmp,$twtmp);
++	&and	($len,15);
++	&jz	(&label("xts_dec_ret"));
++
++	&pcmpgtd($twtmp,$tweak);		# broadcast upper bits
++	&mov	(&DWP(16*7+0,"esp"),$len);	# save $len%16
++	&pshufd	($twres,$twtmp,0x13);
++	&pxor	($twtmp,$twtmp);
++	&movdqa	($twmask,&QWP(16*6,"esp"));
++	&paddq	($tweak,$tweak);		# &psllq($tweak,1);
++	&pand	($twres,$twmask);		# isolate carry and residue
++	&pcmpgtd($twtmp,$tweak);		# broadcast upper bits
++	&pxor	($tweak,$twres);
++
++&set_label("xts_dec_only_one_more");
++	&pshufd	($inout3,$twtmp,0x13);
++	&movdqa	($inout4,$tweak);		# put aside previous tweak
++	&paddq	($tweak,$tweak);		# &psllq($tweak,1);
++	&pand	($inout3,$twmask);		# isolate carry and residue
++	&pxor	($inout3,$tweak);
++
++	&mov	($key,$key_);			# restore $key
++	&mov	($rounds,$rounds_);		# restore $rounds
++
++	&movups	($inout0,&QWP(0,$inp));		# load input
++	&xorps	($inout0,$inout3);		# input^=tweak
++	if ($inline)
++	{   &aesni_inline_generate1("dec");	}
++	else
++	{   &call	("_aesni_decrypt1");	}
++	&xorps	($inout0,$inout3);		# output^=tweak
++	&movups	(&QWP(0,$out),$inout0);		# write output
++
++&set_label("xts_dec_steal");
++	&movz	($rounds,&BP(16,$inp));
++	&movz	($key,&BP(0,$out));
++	&lea	($inp,&DWP(1,$inp));
++	&mov	(&BP(0,$out),&LB($rounds));
++	&mov	(&BP(16,$out),&LB($key));
++	&lea	($out,&DWP(1,$out));
++	&sub	($len,1);
++	&jnz	(&label("xts_dec_steal"));
++
++	&sub	($out,&DWP(16*7+0,"esp"));	# rewind $out
++	&mov	($key,$key_);			# restore $key
++	&mov	($rounds,$rounds_);		# restore $rounds
++
++	&movups	($inout0,&QWP(0,$out));		# load input
++	&xorps	($inout0,$inout4);		# input^=tweak
++	if ($inline)
++	{   &aesni_inline_generate1("dec");	}
++	else
++	{   &call	("_aesni_decrypt1");	}
++	&xorps	($inout0,$inout4);		# output^=tweak
++	&movups	(&QWP(0,$out),$inout0);		# write output
++
++&set_label("xts_dec_ret");
++	&pxor	("xmm0","xmm0");		# clear register bank
++	&pxor	("xmm1","xmm1");
++	&pxor	("xmm2","xmm2");
++	&movdqa	(&QWP(16*0,"esp"),"xmm0");	# clear stack
++	&pxor	("xmm3","xmm3");
++	&movdqa	(&QWP(16*1,"esp"),"xmm0");
++	&pxor	("xmm4","xmm4");
++	&movdqa	(&QWP(16*2,"esp"),"xmm0");
++	&pxor	("xmm5","xmm5");
++	&movdqa	(&QWP(16*3,"esp"),"xmm0");
++	&pxor	("xmm6","xmm6");
++	&movdqa	(&QWP(16*4,"esp"),"xmm0");
++	&pxor	("xmm7","xmm7");
++	&movdqa	(&QWP(16*5,"esp"),"xmm0");
++	&mov	("esp",&DWP(16*7+4,"esp"));	# restore %esp
++&function_end("aesni_xts_decrypt");
++}
++
++######################################################################
++# void aesni_ocb_[en|de]crypt(const char *inp, char *out, size_t blocks,
++#	const AES_KEY *key, unsigned int start_block_num,
++#	unsigned char offset_i[16], const unsigned char L_[][16],
++#	unsigned char checksum[16]);
++#
++{
++# offsets within stack frame
++my $checksum = 16*6;
++my ($key_off,$rounds_off,$out_off,$end_off,$esp_off)=map(16*7+4*$_,(0..4));
++
++# reassigned registers
++my ($l_,$block,$i1,$i3,$i5) = ($rounds_,$key_,$rounds,$len,$out);
++# $l_, $blocks, $inp, $key are permanently allocated in registers;
++# remaining non-volatile ones are offloaded to stack, which even
++# stay invariant after written to stack.
++
++&function_begin("aesni_ocb_encrypt");
++	&mov	($rounds,&wparam(5));		# &offset_i
++	&mov	($rounds_,&wparam(7));		# &checksum
++
++	&mov	($inp,&wparam(0));
++	&mov	($out,&wparam(1));
++	&mov	($len,&wparam(2));
++	&mov	($key,&wparam(3));
++	&movdqu	($rndkey0,&QWP(0,$rounds));	# load offset_i
++	&mov	($block,&wparam(4));		# start_block_num
++	&movdqu	($rndkey1,&QWP(0,$rounds_));	# load checksum
++	&mov	($l_,&wparam(6));		# L_
++
++	&mov	($rounds,"esp");
++	&sub	("esp",$esp_off+4);		# alloca
++	&and	("esp",-16);			# align stack
++
++	&sub	($out,$inp);
++	&shl	($len,4);
++	&lea	($len,&DWP(-16*6,$inp,$len));	# end of input - 16*6
++	&mov	(&DWP($out_off,"esp"),$out);
++	&mov	(&DWP($end_off,"esp"),$len);
++	&mov	(&DWP($esp_off,"esp"),$rounds);
++
++	&mov	($rounds,&DWP(240,$key));
++
++	&test	($block,1);
++	&jnz	(&label("odd"));
++
++	&bsf		($i3,$block);
++	&add		($block,1);
++	&shl		($i3,4);
++	&movdqu		($inout5,&QWP(0,$l_,$i3));
++	&mov		($i3,$key);			# put aside key
++
++	&movdqu		($inout0,&QWP(16*0,$inp));	# load input
++	&lea		($inp,&DWP(16,$inp));
++
++	&pxor		($inout5,$rndkey0);		# ^ last offset_i
++	&pxor		($rndkey1,$inout0);		# checksum
++	&pxor		($inout0,$inout5);		# ^ offset_i
++
++	&movdqa		($inout4,$rndkey1);
++	if ($inline)
++	{   &aesni_inline_generate1("enc");	}
++	else
++	{   &call	("_aesni_encrypt1");	}
++
++	&xorps		($inout0,$inout5);		# ^ offset_i
++	&movdqa		($rndkey0,$inout5);		# pass last offset_i
++	&movdqa		($rndkey1,$inout4);		# pass the checksum
++
++	&movups		(&QWP(-16,$out,$inp),$inout0);	# store output
++
++	&mov		($rounds,&DWP(240,$i3));
++	&mov		($key,$i3);			# restore key
++	&mov		($len,&DWP($end_off,"esp"));
++
++&set_label("odd");
++	&shl		($rounds,4);
++	&mov		($out,16);
++	&sub		($out,$rounds);			# twisted rounds
++	&mov		(&DWP($key_off,"esp"),$key);
++	&lea		($key,&DWP(32,$key,$rounds));	# end of key schedule
++	&mov		(&DWP($rounds_off,"esp"),$out);
++
++	&cmp		($inp,$len);
++	&ja		(&label("short"));
++	&jmp		(&label("grandloop"));
++
++&set_label("grandloop",32);
++	&lea		($i1,&DWP(1,$block));
++	&lea		($i3,&DWP(3,$block));
++	&lea		($i5,&DWP(5,$block));
++	&add		($block,6);
++	&bsf		($i1,$i1);
++	&bsf		($i3,$i3);
++	&bsf		($i5,$i5);
++	&shl		($i1,4);
++	&shl		($i3,4);
++	&shl		($i5,4);
++	&movdqu		($inout0,&QWP(0,$l_));
++	&movdqu		($inout1,&QWP(0,$l_,$i1));
++	&mov		($rounds,&DWP($rounds_off,"esp"));
++	&movdqa		($inout2,$inout0);
++	&movdqu		($inout3,&QWP(0,$l_,$i3));
++	&movdqa		($inout4,$inout0);
++	&movdqu		($inout5,&QWP(0,$l_,$i5));
++
++	&pxor		($inout0,$rndkey0);		# ^ last offset_i
++	&pxor		($inout1,$inout0);
++	&movdqa		(&QWP(16*0,"esp"),$inout0);
++	&pxor		($inout2,$inout1);
++	&movdqa		(&QWP(16*1,"esp"),$inout1);
++	&pxor		($inout3,$inout2);
++	&movdqa		(&QWP(16*2,"esp"),$inout2);
++	&pxor		($inout4,$inout3);
++	&movdqa		(&QWP(16*3,"esp"),$inout3);
++	&pxor		($inout5,$inout4);
++	&movdqa		(&QWP(16*4,"esp"),$inout4);
++	&movdqa		(&QWP(16*5,"esp"),$inout5);
++
++	&$movekey	($rndkey0,&QWP(-48,$key,$rounds));
++	&movdqu		($inout0,&QWP(16*0,$inp));	# load input
++	&movdqu		($inout1,&QWP(16*1,$inp));
++	&movdqu		($inout2,&QWP(16*2,$inp));
++	&movdqu		($inout3,&QWP(16*3,$inp));
++	&movdqu		($inout4,&QWP(16*4,$inp));
++	&movdqu		($inout5,&QWP(16*5,$inp));
++	&lea		($inp,&DWP(16*6,$inp));
++
++	&pxor		($rndkey1,$inout0);		# checksum
++	&pxor		($inout0,$rndkey0);		# ^ roundkey[0]
++	&pxor		($rndkey1,$inout1);
++	&pxor		($inout1,$rndkey0);
++	&pxor		($rndkey1,$inout2);
++	&pxor		($inout2,$rndkey0);
++	&pxor		($rndkey1,$inout3);
++	&pxor		($inout3,$rndkey0);
++	&pxor		($rndkey1,$inout4);
++	&pxor		($inout4,$rndkey0);
++	&pxor		($rndkey1,$inout5);
++	&pxor		($inout5,$rndkey0);
++	&movdqa		(&QWP($checksum,"esp"),$rndkey1);
++
++	&$movekey	($rndkey1,&QWP(-32,$key,$rounds));
++	&pxor		($inout0,&QWP(16*0,"esp"));	# ^ offset_i
++	&pxor		($inout1,&QWP(16*1,"esp"));
++	&pxor		($inout2,&QWP(16*2,"esp"));
++	&pxor		($inout3,&QWP(16*3,"esp"));
++	&pxor		($inout4,&QWP(16*4,"esp"));
++	&pxor		($inout5,&QWP(16*5,"esp"));
++
++	&$movekey	($rndkey0,&QWP(-16,$key,$rounds));
++	&aesenc		($inout0,$rndkey1);
++	&aesenc		($inout1,$rndkey1);
++	&aesenc		($inout2,$rndkey1);
++	&aesenc		($inout3,$rndkey1);
++	&aesenc		($inout4,$rndkey1);
++	&aesenc		($inout5,$rndkey1);
++
++	&mov		($out,&DWP($out_off,"esp"));
++	&mov		($len,&DWP($end_off,"esp"));
++	&call		("_aesni_encrypt6_enter");
++
++	&movdqa		($rndkey0,&QWP(16*5,"esp"));	# pass last offset_i
++	&pxor		($inout0,&QWP(16*0,"esp"));	# ^ offset_i
++	&pxor		($inout1,&QWP(16*1,"esp"));
++	&pxor		($inout2,&QWP(16*2,"esp"));
++	&pxor		($inout3,&QWP(16*3,"esp"));
++	&pxor		($inout4,&QWP(16*4,"esp"));
++	&pxor		($inout5,$rndkey0);
++	&movdqa		($rndkey1,&QWP($checksum,"esp"));# pass the checksum
++
++	&movdqu		(&QWP(-16*6,$out,$inp),$inout0);# store output
++	&movdqu		(&QWP(-16*5,$out,$inp),$inout1);
++	&movdqu		(&QWP(-16*4,$out,$inp),$inout2);
++	&movdqu		(&QWP(-16*3,$out,$inp),$inout3);
++	&movdqu		(&QWP(-16*2,$out,$inp),$inout4);
++	&movdqu		(&QWP(-16*1,$out,$inp),$inout5);
++	&cmp		($inp,$len);			# done yet?
++	&jb		(&label("grandloop"));
++
++&set_label("short");
++	&add		($len,16*6);
++	&sub		($len,$inp);
++	&jz		(&label("done"));
++
++	&cmp		($len,16*2);
++	&jb		(&label("one"));
++	&je		(&label("two"));
++
++	&cmp		($len,16*4);
++	&jb		(&label("three"));
++	&je		(&label("four"));
++
++	&lea		($i1,&DWP(1,$block));
++	&lea		($i3,&DWP(3,$block));
++	&bsf		($i1,$i1);
++	&bsf		($i3,$i3);
++	&shl		($i1,4);
++	&shl		($i3,4);
++	&movdqu		($inout0,&QWP(0,$l_));
++	&movdqu		($inout1,&QWP(0,$l_,$i1));
++	&mov		($rounds,&DWP($rounds_off,"esp"));
++	&movdqa		($inout2,$inout0);
++	&movdqu		($inout3,&QWP(0,$l_,$i3));
++	&movdqa		($inout4,$inout0);
++
++	&pxor		($inout0,$rndkey0);		# ^ last offset_i
++	&pxor		($inout1,$inout0);
++	&movdqa		(&QWP(16*0,"esp"),$inout0);
++	&pxor		($inout2,$inout1);
++	&movdqa		(&QWP(16*1,"esp"),$inout1);
++	&pxor		($inout3,$inout2);
++	&movdqa		(&QWP(16*2,"esp"),$inout2);
++	&pxor		($inout4,$inout3);
++	&movdqa		(&QWP(16*3,"esp"),$inout3);
++	&pxor		($inout5,$inout4);
++	&movdqa		(&QWP(16*4,"esp"),$inout4);
++
++	&$movekey	($rndkey0,&QWP(-48,$key,$rounds));
++	&movdqu		($inout0,&QWP(16*0,$inp));	# load input
++	&movdqu		($inout1,&QWP(16*1,$inp));
++	&movdqu		($inout2,&QWP(16*2,$inp));
++	&movdqu		($inout3,&QWP(16*3,$inp));
++	&movdqu		($inout4,&QWP(16*4,$inp));
++	&pxor		($inout5,$inout5);
++
++	&pxor		($rndkey1,$inout0);		# checksum
++	&pxor		($inout0,$rndkey0);		# ^ roundkey[0]
++	&pxor		($rndkey1,$inout1);
++	&pxor		($inout1,$rndkey0);
++	&pxor		($rndkey1,$inout2);
++	&pxor		($inout2,$rndkey0);
++	&pxor		($rndkey1,$inout3);
++	&pxor		($inout3,$rndkey0);
++	&pxor		($rndkey1,$inout4);
++	&pxor		($inout4,$rndkey0);
++	&movdqa		(&QWP($checksum,"esp"),$rndkey1);
++
++	&$movekey	($rndkey1,&QWP(-32,$key,$rounds));
++	&pxor		($inout0,&QWP(16*0,"esp"));	# ^ offset_i
++	&pxor		($inout1,&QWP(16*1,"esp"));
++	&pxor		($inout2,&QWP(16*2,"esp"));
++	&pxor		($inout3,&QWP(16*3,"esp"));
++	&pxor		($inout4,&QWP(16*4,"esp"));
++
++	&$movekey	($rndkey0,&QWP(-16,$key,$rounds));
++	&aesenc		($inout0,$rndkey1);
++	&aesenc		($inout1,$rndkey1);
++	&aesenc		($inout2,$rndkey1);
++	&aesenc		($inout3,$rndkey1);
++	&aesenc		($inout4,$rndkey1);
++	&aesenc		($inout5,$rndkey1);
++
++	&mov		($out,&DWP($out_off,"esp"));
++	&call		("_aesni_encrypt6_enter");
++
++	&movdqa		($rndkey0,&QWP(16*4,"esp"));	# pass last offset_i
++	&pxor		($inout0,&QWP(16*0,"esp"));	# ^ offset_i
++	&pxor		($inout1,&QWP(16*1,"esp"));
++	&pxor		($inout2,&QWP(16*2,"esp"));
++	&pxor		($inout3,&QWP(16*3,"esp"));
++	&pxor		($inout4,$rndkey0);
++	&movdqa		($rndkey1,&QWP($checksum,"esp"));# pass the checksum
++
++	&movdqu		(&QWP(16*0,$out,$inp),$inout0);	# store output
++	&movdqu		(&QWP(16*1,$out,$inp),$inout1);
++	&movdqu		(&QWP(16*2,$out,$inp),$inout2);
++	&movdqu		(&QWP(16*3,$out,$inp),$inout3);
++	&movdqu		(&QWP(16*4,$out,$inp),$inout4);
++
++	&jmp		(&label("done"));
++
++&set_label("one",16);
++	&movdqu		($inout5,&QWP(0,$l_));
++	&mov		($key,&DWP($key_off,"esp"));	# restore key
++
++	&movdqu		($inout0,&QWP(16*0,$inp));	# load input
++	&mov		($rounds,&DWP(240,$key));
++
++	&pxor		($inout5,$rndkey0);		# ^ last offset_i
++	&pxor		($rndkey1,$inout0);		# checksum
++	&pxor		($inout0,$inout5);		# ^ offset_i
++
++	&movdqa		($inout4,$rndkey1);
++	&mov		($out,&DWP($out_off,"esp"));
++	if ($inline)
++	{   &aesni_inline_generate1("enc");	}
++	else
++	{   &call	("_aesni_encrypt1");	}
++
++	&xorps		($inout0,$inout5);		# ^ offset_i
++	&movdqa		($rndkey0,$inout5);		# pass last offset_i
++	&movdqa		($rndkey1,$inout4);		# pass the checksum
++	&movups		(&QWP(0,$out,$inp),$inout0);
++
++	&jmp		(&label("done"));
++
++&set_label("two",16);
++	&lea		($i1,&DWP(1,$block));
++	&mov		($key,&DWP($key_off,"esp"));	# restore key
++	&bsf		($i1,$i1);
++	&shl		($i1,4);
++	&movdqu		($inout4,&QWP(0,$l_));
++	&movdqu		($inout5,&QWP(0,$l_,$i1));
++
++	&movdqu		($inout0,&QWP(16*0,$inp));	# load input
++	&movdqu		($inout1,&QWP(16*1,$inp));
++	&mov		($rounds,&DWP(240,$key));
++
++	&pxor		($inout4,$rndkey0);		# ^ last offset_i
++	&pxor		($inout5,$inout4);
++
++	&pxor		($rndkey1,$inout0);		# checksum
++	&pxor		($inout0,$inout4);		# ^ offset_i
++	&pxor		($rndkey1,$inout1);
++	&pxor		($inout1,$inout5);
++
++	&movdqa		($inout3,$rndkey1)
++	&mov		($out,&DWP($out_off,"esp"));
++	&call		("_aesni_encrypt2");
++
++	&xorps		($inout0,$inout4);		# ^ offset_i
++	&xorps		($inout1,$inout5);
++	&movdqa		($rndkey0,$inout5);		# pass last offset_i
++	&movdqa		($rndkey1,$inout3);		# pass the checksum
++	&movups		(&QWP(16*0,$out,$inp),$inout0);	# store output
++	&movups		(&QWP(16*1,$out,$inp),$inout1);
++
++	&jmp		(&label("done"));
++
++&set_label("three",16);
++	&lea		($i1,&DWP(1,$block));
++	&mov		($key,&DWP($key_off,"esp"));	# restore key
++	&bsf		($i1,$i1);
++	&shl		($i1,4);
++	&movdqu		($inout3,&QWP(0,$l_));
++	&movdqu		($inout4,&QWP(0,$l_,$i1));
++	&movdqa		($inout5,$inout3);
++
++	&movdqu		($inout0,&QWP(16*0,$inp));	# load input
++	&movdqu		($inout1,&QWP(16*1,$inp));
++	&movdqu		($inout2,&QWP(16*2,$inp));
++	&mov		($rounds,&DWP(240,$key));
++
++	&pxor		($inout3,$rndkey0);		# ^ last offset_i
++	&pxor		($inout4,$inout3);
++	&pxor		($inout5,$inout4);
++
++	&pxor		($rndkey1,$inout0);		# checksum
++	&pxor		($inout0,$inout3);		# ^ offset_i
++	&pxor		($rndkey1,$inout1);
++	&pxor		($inout1,$inout4);
++	&pxor		($rndkey1,$inout2);
++	&pxor		($inout2,$inout5);
++
++	&movdqa		(&QWP($checksum,"esp"),$rndkey1);
++	&mov		($out,&DWP($out_off,"esp"));
++	&call		("_aesni_encrypt3");
++
++	&xorps		($inout0,$inout3);		# ^ offset_i
++	&xorps		($inout1,$inout4);
++	&xorps		($inout2,$inout5);
++	&movdqa		($rndkey0,$inout5);		# pass last offset_i
++	&movdqa		($rndkey1,&QWP($checksum,"esp"));# pass the checksum
++	&movups		(&QWP(16*0,$out,$inp),$inout0);	# store output
++	&movups		(&QWP(16*1,$out,$inp),$inout1);
++	&movups		(&QWP(16*2,$out,$inp),$inout2);
++
++	&jmp		(&label("done"));
++
++&set_label("four",16);
++	&lea		($i1,&DWP(1,$block));
++	&lea		($i3,&DWP(3,$block));
++	&bsf		($i1,$i1);
++	&bsf		($i3,$i3);
++	&mov		($key,&DWP($key_off,"esp"));	# restore key
++	&shl		($i1,4);
++	&shl		($i3,4);
++	&movdqu		($inout2,&QWP(0,$l_));
++	&movdqu		($inout3,&QWP(0,$l_,$i1));
++	&movdqa		($inout4,$inout2);
++	&movdqu		($inout5,&QWP(0,$l_,$i3));
++
++	&pxor		($inout2,$rndkey0);		# ^ last offset_i
++	&movdqu		($inout0,&QWP(16*0,$inp));	# load input
++	&pxor		($inout3,$inout2);
++	&movdqu		($inout1,&QWP(16*1,$inp));
++	&pxor		($inout4,$inout3);
++	&movdqa		(&QWP(16*0,"esp"),$inout2);
++	&pxor		($inout5,$inout4);
++	&movdqa		(&QWP(16*1,"esp"),$inout3);
++	&movdqu		($inout2,&QWP(16*2,$inp));
++	&movdqu		($inout3,&QWP(16*3,$inp));
++	&mov		($rounds,&DWP(240,$key));
++
++	&pxor		($rndkey1,$inout0);		# checksum
++	&pxor		($inout0,&QWP(16*0,"esp"));	# ^ offset_i
++	&pxor		($rndkey1,$inout1);
++	&pxor		($inout1,&QWP(16*1,"esp"));
++	&pxor		($rndkey1,$inout2);
++	&pxor		($inout2,$inout4);
++	&pxor		($rndkey1,$inout3);
++	&pxor		($inout3,$inout5);
++
++	&movdqa		(&QWP($checksum,"esp"),$rndkey1)
++	&mov		($out,&DWP($out_off,"esp"));
++	&call		("_aesni_encrypt4");
++
++	&xorps		($inout0,&QWP(16*0,"esp"));	# ^ offset_i
++	&xorps		($inout1,&QWP(16*1,"esp"));
++	&xorps		($inout2,$inout4);
++	&movups		(&QWP(16*0,$out,$inp),$inout0);	# store output
++	&xorps		($inout3,$inout5);
++	&movups		(&QWP(16*1,$out,$inp),$inout1);
++	&movdqa		($rndkey0,$inout5);		# pass last offset_i
++	&movups		(&QWP(16*2,$out,$inp),$inout2);
++	&movdqa		($rndkey1,&QWP($checksum,"esp"));# pass the checksum
++	&movups		(&QWP(16*3,$out,$inp),$inout3);
++
++&set_label("done");
++	&mov	($key,&DWP($esp_off,"esp"));
++	&pxor	($inout0,$inout0);		# clear register bank
++	&pxor	($inout1,$inout1);
++	&movdqa	(&QWP(16*0,"esp"),$inout0);	# clear stack
++	&pxor	($inout2,$inout2);
++	&movdqa	(&QWP(16*1,"esp"),$inout0);
++	&pxor	($inout3,$inout3);
++	&movdqa	(&QWP(16*2,"esp"),$inout0);
++	&pxor	($inout4,$inout4);
++	&movdqa	(&QWP(16*3,"esp"),$inout0);
++	&pxor	($inout5,$inout5);
++	&movdqa	(&QWP(16*4,"esp"),$inout0);
++	&movdqa	(&QWP(16*5,"esp"),$inout0);
++	&movdqa	(&QWP(16*6,"esp"),$inout0);
++
++	&lea	("esp",&DWP(0,$key));
++	&mov	($rounds,&wparam(5));		# &offset_i
++	&mov	($rounds_,&wparam(7));		# &checksum
++	&movdqu	(&QWP(0,$rounds),$rndkey0);
++	&pxor	($rndkey0,$rndkey0);
++	&movdqu	(&QWP(0,$rounds_),$rndkey1);
++	&pxor	($rndkey1,$rndkey1);
++&function_end("aesni_ocb_encrypt");
++
++&function_begin("aesni_ocb_decrypt");
++	&mov	($rounds,&wparam(5));		# &offset_i
++	&mov	($rounds_,&wparam(7));		# &checksum
++
++	&mov	($inp,&wparam(0));
++	&mov	($out,&wparam(1));
++	&mov	($len,&wparam(2));
++	&mov	($key,&wparam(3));
++	&movdqu	($rndkey0,&QWP(0,$rounds));	# load offset_i
++	&mov	($block,&wparam(4));		# start_block_num
++	&movdqu	($rndkey1,&QWP(0,$rounds_));	# load checksum
++	&mov	($l_,&wparam(6));		# L_
++
++	&mov	($rounds,"esp");
++	&sub	("esp",$esp_off+4);		# alloca
++	&and	("esp",-16);			# align stack
++
++	&sub	($out,$inp);
++	&shl	($len,4);
++	&lea	($len,&DWP(-16*6,$inp,$len));	# end of input - 16*6
++	&mov	(&DWP($out_off,"esp"),$out);
++	&mov	(&DWP($end_off,"esp"),$len);
++	&mov	(&DWP($esp_off,"esp"),$rounds);
++
++	&mov	($rounds,&DWP(240,$key));
++
++	&test	($block,1);
++	&jnz	(&label("odd"));
++
++	&bsf		($i3,$block);
++	&add		($block,1);
++	&shl		($i3,4);
++	&movdqu		($inout5,&QWP(0,$l_,$i3));
++	&mov		($i3,$key);			# put aside key
++
++	&movdqu		($inout0,&QWP(16*0,$inp));	# load input
++	&lea		($inp,&DWP(16,$inp));
++
++	&pxor		($inout5,$rndkey0);		# ^ last offset_i
++	&pxor		($inout0,$inout5);		# ^ offset_i
++
++	&movdqa		($inout4,$rndkey1);
++	if ($inline)
++	{   &aesni_inline_generate1("dec");	}
++	else
++	{   &call	("_aesni_decrypt1");	}
++
++	&xorps		($inout0,$inout5);		# ^ offset_i
++	&movaps		($rndkey1,$inout4);		# pass the checksum
++	&movdqa		($rndkey0,$inout5);		# pass last offset_i
++	&xorps		($rndkey1,$inout0);		# checksum
++	&movups		(&QWP(-16,$out,$inp),$inout0);	# store output
++
++	&mov		($rounds,&DWP(240,$i3));
++	&mov		($key,$i3);			# restore key
++	&mov		($len,&DWP($end_off,"esp"));
++
++&set_label("odd");
++	&shl		($rounds,4);
++	&mov		($out,16);
++	&sub		($out,$rounds);			# twisted rounds
++	&mov		(&DWP($key_off,"esp"),$key);
++	&lea		($key,&DWP(32,$key,$rounds));	# end of key schedule
++	&mov		(&DWP($rounds_off,"esp"),$out);
++
++	&cmp		($inp,$len);
++	&ja		(&label("short"));
++	&jmp		(&label("grandloop"));
++
++&set_label("grandloop",32);
++	&lea		($i1,&DWP(1,$block));
++	&lea		($i3,&DWP(3,$block));
++	&lea		($i5,&DWP(5,$block));
++	&add		($block,6);
++	&bsf		($i1,$i1);
++	&bsf		($i3,$i3);
++	&bsf		($i5,$i5);
++	&shl		($i1,4);
++	&shl		($i3,4);
++	&shl		($i5,4);
++	&movdqu		($inout0,&QWP(0,$l_));
++	&movdqu		($inout1,&QWP(0,$l_,$i1));
++	&mov		($rounds,&DWP($rounds_off,"esp"));
++	&movdqa		($inout2,$inout0);
++	&movdqu		($inout3,&QWP(0,$l_,$i3));
++	&movdqa		($inout4,$inout0);
++	&movdqu		($inout5,&QWP(0,$l_,$i5));
++
++	&pxor		($inout0,$rndkey0);		# ^ last offset_i
++	&pxor		($inout1,$inout0);
++	&movdqa		(&QWP(16*0,"esp"),$inout0);
++	&pxor		($inout2,$inout1);
++	&movdqa		(&QWP(16*1,"esp"),$inout1);
++	&pxor		($inout3,$inout2);
++	&movdqa		(&QWP(16*2,"esp"),$inout2);
++	&pxor		($inout4,$inout3);
++	&movdqa		(&QWP(16*3,"esp"),$inout3);
++	&pxor		($inout5,$inout4);
++	&movdqa		(&QWP(16*4,"esp"),$inout4);
++	&movdqa		(&QWP(16*5,"esp"),$inout5);
++
++	&$movekey	($rndkey0,&QWP(-48,$key,$rounds));
++	&movdqu		($inout0,&QWP(16*0,$inp));	# load input
++	&movdqu		($inout1,&QWP(16*1,$inp));
++	&movdqu		($inout2,&QWP(16*2,$inp));
++	&movdqu		($inout3,&QWP(16*3,$inp));
++	&movdqu		($inout4,&QWP(16*4,$inp));
++	&movdqu		($inout5,&QWP(16*5,$inp));
++	&lea		($inp,&DWP(16*6,$inp));
++
++	&movdqa		(&QWP($checksum,"esp"),$rndkey1);
++	&pxor		($inout0,$rndkey0);		# ^ roundkey[0]
++	&pxor		($inout1,$rndkey0);
++	&pxor		($inout2,$rndkey0);
++	&pxor		($inout3,$rndkey0);
++	&pxor		($inout4,$rndkey0);
++	&pxor		($inout5,$rndkey0);
++
++	&$movekey	($rndkey1,&QWP(-32,$key,$rounds));
++	&pxor		($inout0,&QWP(16*0,"esp"));	# ^ offset_i
++	&pxor		($inout1,&QWP(16*1,"esp"));
++	&pxor		($inout2,&QWP(16*2,"esp"));
++	&pxor		($inout3,&QWP(16*3,"esp"));
++	&pxor		($inout4,&QWP(16*4,"esp"));
++	&pxor		($inout5,&QWP(16*5,"esp"));
++
++	&$movekey	($rndkey0,&QWP(-16,$key,$rounds));
++	&aesdec		($inout0,$rndkey1);
++	&aesdec		($inout1,$rndkey1);
++	&aesdec		($inout2,$rndkey1);
++	&aesdec		($inout3,$rndkey1);
++	&aesdec		($inout4,$rndkey1);
++	&aesdec		($inout5,$rndkey1);
++
++	&mov		($out,&DWP($out_off,"esp"));
++	&mov		($len,&DWP($end_off,"esp"));
++	&call		("_aesni_decrypt6_enter");
++
++	&movdqa		($rndkey0,&QWP(16*5,"esp"));	# pass last offset_i
++	&pxor		($inout0,&QWP(16*0,"esp"));	# ^ offset_i
++	&movdqa		($rndkey1,&QWP($checksum,"esp"));
++	&pxor		($inout1,&QWP(16*1,"esp"));
++	&pxor		($inout2,&QWP(16*2,"esp"));
++	&pxor		($inout3,&QWP(16*3,"esp"));
++	&pxor		($inout4,&QWP(16*4,"esp"));
++	&pxor		($inout5,$rndkey0);
++
++	&pxor		($rndkey1,$inout0);		# checksum
++	&movdqu		(&QWP(-16*6,$out,$inp),$inout0);# store output
++	&pxor		($rndkey1,$inout1);
++	&movdqu		(&QWP(-16*5,$out,$inp),$inout1);
++	&pxor		($rndkey1,$inout2);
++	&movdqu		(&QWP(-16*4,$out,$inp),$inout2);
++	&pxor		($rndkey1,$inout3);
++	&movdqu		(&QWP(-16*3,$out,$inp),$inout3);
++	&pxor		($rndkey1,$inout4);
++	&movdqu		(&QWP(-16*2,$out,$inp),$inout4);
++	&pxor		($rndkey1,$inout5);
++	&movdqu		(&QWP(-16*1,$out,$inp),$inout5);
++	&cmp		($inp,$len);			# done yet?
++	&jb		(&label("grandloop"));
++
++&set_label("short");
++	&add		($len,16*6);
++	&sub		($len,$inp);
++	&jz		(&label("done"));
++
++	&cmp		($len,16*2);
++	&jb		(&label("one"));
++	&je		(&label("two"));
++
++	&cmp		($len,16*4);
++	&jb		(&label("three"));
++	&je		(&label("four"));
++
++	&lea		($i1,&DWP(1,$block));
++	&lea		($i3,&DWP(3,$block));
++	&bsf		($i1,$i1);
++	&bsf		($i3,$i3);
++	&shl		($i1,4);
++	&shl		($i3,4);
++	&movdqu		($inout0,&QWP(0,$l_));
++	&movdqu		($inout1,&QWP(0,$l_,$i1));
++	&mov		($rounds,&DWP($rounds_off,"esp"));
++	&movdqa		($inout2,$inout0);
++	&movdqu		($inout3,&QWP(0,$l_,$i3));
++	&movdqa		($inout4,$inout0);
++
++	&pxor		($inout0,$rndkey0);		# ^ last offset_i
++	&pxor		($inout1,$inout0);
++	&movdqa		(&QWP(16*0,"esp"),$inout0);
++	&pxor		($inout2,$inout1);
++	&movdqa		(&QWP(16*1,"esp"),$inout1);
++	&pxor		($inout3,$inout2);
++	&movdqa		(&QWP(16*2,"esp"),$inout2);
++	&pxor		($inout4,$inout3);
++	&movdqa		(&QWP(16*3,"esp"),$inout3);
++	&pxor		($inout5,$inout4);
++	&movdqa		(&QWP(16*4,"esp"),$inout4);
++
++	&$movekey	($rndkey0,&QWP(-48,$key,$rounds));
++	&movdqu		($inout0,&QWP(16*0,$inp));	# load input
++	&movdqu		($inout1,&QWP(16*1,$inp));
++	&movdqu		($inout2,&QWP(16*2,$inp));
++	&movdqu		($inout3,&QWP(16*3,$inp));
++	&movdqu		($inout4,&QWP(16*4,$inp));
++	&pxor		($inout5,$inout5);
++
++	&movdqa		(&QWP($checksum,"esp"),$rndkey1);
++	&pxor		($inout0,$rndkey0);		# ^ roundkey[0]
++	&pxor		($inout1,$rndkey0);
++	&pxor		($inout2,$rndkey0);
++	&pxor		($inout3,$rndkey0);
++	&pxor		($inout4,$rndkey0);
++
++	&$movekey	($rndkey1,&QWP(-32,$key,$rounds));
++	&pxor		($inout0,&QWP(16*0,"esp"));	# ^ offset_i
++	&pxor		($inout1,&QWP(16*1,"esp"));
++	&pxor		($inout2,&QWP(16*2,"esp"));
++	&pxor		($inout3,&QWP(16*3,"esp"));
++	&pxor		($inout4,&QWP(16*4,"esp"));
++
++	&$movekey	($rndkey0,&QWP(-16,$key,$rounds));
++	&aesdec		($inout0,$rndkey1);
++	&aesdec		($inout1,$rndkey1);
++	&aesdec		($inout2,$rndkey1);
++	&aesdec		($inout3,$rndkey1);
++	&aesdec		($inout4,$rndkey1);
++	&aesdec		($inout5,$rndkey1);
++
++	&mov		($out,&DWP($out_off,"esp"));
++	&call		("_aesni_decrypt6_enter");
++
++	&movdqa		($rndkey0,&QWP(16*4,"esp"));	# pass last offset_i
++	&pxor		($inout0,&QWP(16*0,"esp"));	# ^ offset_i
++	&movdqa		($rndkey1,&QWP($checksum,"esp"));
++	&pxor		($inout1,&QWP(16*1,"esp"));
++	&pxor		($inout2,&QWP(16*2,"esp"));
++	&pxor		($inout3,&QWP(16*3,"esp"));
++	&pxor		($inout4,$rndkey0);
++
++	&pxor		($rndkey1,$inout0);		# checksum
++	&movdqu		(&QWP(16*0,$out,$inp),$inout0);	# store output
++	&pxor		($rndkey1,$inout1);
++	&movdqu		(&QWP(16*1,$out,$inp),$inout1);
++	&pxor		($rndkey1,$inout2);
++	&movdqu		(&QWP(16*2,$out,$inp),$inout2);
++	&pxor		($rndkey1,$inout3);
++	&movdqu		(&QWP(16*3,$out,$inp),$inout3);
++	&pxor		($rndkey1,$inout4);
++	&movdqu		(&QWP(16*4,$out,$inp),$inout4);
++
++	&jmp		(&label("done"));
++
++&set_label("one",16);
++	&movdqu		($inout5,&QWP(0,$l_));
++	&mov		($key,&DWP($key_off,"esp"));	# restore key
++
++	&movdqu		($inout0,&QWP(16*0,$inp));	# load input
++	&mov		($rounds,&DWP(240,$key));
++
++	&pxor		($inout5,$rndkey0);		# ^ last offset_i
++	&pxor		($inout0,$inout5);		# ^ offset_i
++
++	&movdqa		($inout4,$rndkey1);
++	&mov		($out,&DWP($out_off,"esp"));
++	if ($inline)
++	{   &aesni_inline_generate1("dec");	}
++	else
++	{   &call	("_aesni_decrypt1");	}
++
++	&xorps		($inout0,$inout5);		# ^ offset_i
++	&movaps		($rndkey1,$inout4);		# pass the checksum
++	&movdqa		($rndkey0,$inout5);		# pass last offset_i
++	&xorps		($rndkey1,$inout0);		# checksum
++	&movups		(&QWP(0,$out,$inp),$inout0);
++
++	&jmp		(&label("done"));
++
++&set_label("two",16);
++	&lea		($i1,&DWP(1,$block));
++	&mov		($key,&DWP($key_off,"esp"));	# restore key
++	&bsf		($i1,$i1);
++	&shl		($i1,4);
++	&movdqu		($inout4,&QWP(0,$l_));
++	&movdqu		($inout5,&QWP(0,$l_,$i1));
++
++	&movdqu		($inout0,&QWP(16*0,$inp));	# load input
++	&movdqu		($inout1,&QWP(16*1,$inp));
++	&mov		($rounds,&DWP(240,$key));
++
++	&movdqa		($inout3,$rndkey1);
++	&pxor		($inout4,$rndkey0);		# ^ last offset_i
++	&pxor		($inout5,$inout4);
++
++	&pxor		($inout0,$inout4);		# ^ offset_i
++	&pxor		($inout1,$inout5);
++
++	&mov		($out,&DWP($out_off,"esp"));
++	&call		("_aesni_decrypt2");
++
++	&xorps		($inout0,$inout4);		# ^ offset_i
++	&xorps		($inout1,$inout5);
++	&movdqa		($rndkey0,$inout5);		# pass last offset_i
++	&xorps		($inout3,$inout0);		# checksum
++	&movups		(&QWP(16*0,$out,$inp),$inout0);	# store output
++	&xorps		($inout3,$inout1);
++	&movups		(&QWP(16*1,$out,$inp),$inout1);
++	&movaps		($rndkey1,$inout3);		# pass the checksum
++
++	&jmp		(&label("done"));
++
++&set_label("three",16);
++	&lea		($i1,&DWP(1,$block));
++	&mov		($key,&DWP($key_off,"esp"));	# restore key
++	&bsf		($i1,$i1);
++	&shl		($i1,4);
++	&movdqu		($inout3,&QWP(0,$l_));
++	&movdqu		($inout4,&QWP(0,$l_,$i1));
++	&movdqa		($inout5,$inout3);
++
++	&movdqu		($inout0,&QWP(16*0,$inp));	# load input
++	&movdqu		($inout1,&QWP(16*1,$inp));
++	&movdqu		($inout2,&QWP(16*2,$inp));
++	&mov		($rounds,&DWP(240,$key));
++
++	&movdqa		(&QWP($checksum,"esp"),$rndkey1);
++	&pxor		($inout3,$rndkey0);		# ^ last offset_i
++	&pxor		($inout4,$inout3);
++	&pxor		($inout5,$inout4);
++
++	&pxor		($inout0,$inout3);		# ^ offset_i
++	&pxor		($inout1,$inout4);
++	&pxor		($inout2,$inout5);
++
++	&mov		($out,&DWP($out_off,"esp"));
++	&call		("_aesni_decrypt3");
++
++	&movdqa		($rndkey1,&QWP($checksum,"esp"));# pass the checksum
++	&xorps		($inout0,$inout3);		# ^ offset_i
++	&xorps		($inout1,$inout4);
++	&xorps		($inout2,$inout5);
++	&movups		(&QWP(16*0,$out,$inp),$inout0);	# store output
++	&pxor		($rndkey1,$inout0);		# checksum
++	&movdqa		($rndkey0,$inout5);		# pass last offset_i
++	&movups		(&QWP(16*1,$out,$inp),$inout1);
++	&pxor		($rndkey1,$inout1);
++	&movups		(&QWP(16*2,$out,$inp),$inout2);
++	&pxor		($rndkey1,$inout2);
++
++	&jmp		(&label("done"));
++
++&set_label("four",16);
++	&lea		($i1,&DWP(1,$block));
++	&lea		($i3,&DWP(3,$block));
++	&bsf		($i1,$i1);
++	&bsf		($i3,$i3);
++	&mov		($key,&DWP($key_off,"esp"));	# restore key
++	&shl		($i1,4);
++	&shl		($i3,4);
++	&movdqu		($inout2,&QWP(0,$l_));
++	&movdqu		($inout3,&QWP(0,$l_,$i1));
++	&movdqa		($inout4,$inout2);
++	&movdqu		($inout5,&QWP(0,$l_,$i3));
++
++	&pxor		($inout2,$rndkey0);		# ^ last offset_i
++	&movdqu		($inout0,&QWP(16*0,$inp));	# load input
++	&pxor		($inout3,$inout2);
++	&movdqu		($inout1,&QWP(16*1,$inp));
++	&pxor		($inout4,$inout3);
++	&movdqa		(&QWP(16*0,"esp"),$inout2);
++	&pxor		($inout5,$inout4);
++	&movdqa		(&QWP(16*1,"esp"),$inout3);
++	&movdqu		($inout2,&QWP(16*2,$inp));
++	&movdqu		($inout3,&QWP(16*3,$inp));
++	&mov		($rounds,&DWP(240,$key));
++
++	&movdqa		(&QWP($checksum,"esp"),$rndkey1);
++	&pxor		($inout0,&QWP(16*0,"esp"));	# ^ offset_i
++	&pxor		($inout1,&QWP(16*1,"esp"));
++	&pxor		($inout2,$inout4);
++	&pxor		($inout3,$inout5);
++
++	&mov		($out,&DWP($out_off,"esp"));
++	&call		("_aesni_decrypt4");
++
++	&movdqa		($rndkey1,&QWP($checksum,"esp"));# pass the checksum
++	&xorps		($inout0,&QWP(16*0,"esp"));	# ^ offset_i
++	&xorps		($inout1,&QWP(16*1,"esp"));
++	&xorps		($inout2,$inout4);
++	&movups		(&QWP(16*0,$out,$inp),$inout0);	# store output
++	&pxor		($rndkey1,$inout0);		# checksum
++	&xorps		($inout3,$inout5);
++	&movups		(&QWP(16*1,$out,$inp),$inout1);
++	&pxor		($rndkey1,$inout1);
++	&movdqa		($rndkey0,$inout5);		# pass last offset_i
++	&movups		(&QWP(16*2,$out,$inp),$inout2);
++	&pxor		($rndkey1,$inout2);
++	&movups		(&QWP(16*3,$out,$inp),$inout3);
++	&pxor		($rndkey1,$inout3);
++
++&set_label("done");
++	&mov	($key,&DWP($esp_off,"esp"));
++	&pxor	($inout0,$inout0);		# clear register bank
++	&pxor	($inout1,$inout1);
++	&movdqa	(&QWP(16*0,"esp"),$inout0);	# clear stack
++	&pxor	($inout2,$inout2);
++	&movdqa	(&QWP(16*1,"esp"),$inout0);
++	&pxor	($inout3,$inout3);
++	&movdqa	(&QWP(16*2,"esp"),$inout0);
++	&pxor	($inout4,$inout4);
++	&movdqa	(&QWP(16*3,"esp"),$inout0);
++	&pxor	($inout5,$inout5);
++	&movdqa	(&QWP(16*4,"esp"),$inout0);
++	&movdqa	(&QWP(16*5,"esp"),$inout0);
++	&movdqa	(&QWP(16*6,"esp"),$inout0);
++
++	&lea	("esp",&DWP(0,$key));
++	&mov	($rounds,&wparam(5));		# &offset_i
++	&mov	($rounds_,&wparam(7));		# &checksum
++	&movdqu	(&QWP(0,$rounds),$rndkey0);
++	&pxor	($rndkey0,$rndkey0);
++	&movdqu	(&QWP(0,$rounds_),$rndkey1);
++	&pxor	($rndkey1,$rndkey1);
++&function_end("aesni_ocb_decrypt");
++}
++}
++
++######################################################################
++# void $PREFIX_cbc_encrypt (const void *inp, void *out,
++#                           size_t length, const AES_KEY *key,
++#                           unsigned char *ivp,const int enc);
++&function_begin("${PREFIX}_cbc_encrypt");
++	&mov	($inp,&wparam(0));
++	&mov	($rounds_,"esp");
++	&mov	($out,&wparam(1));
++	&sub	($rounds_,24);
++	&mov	($len,&wparam(2));
++	&and	($rounds_,-16);
++	&mov	($key,&wparam(3));
++	&mov	($key_,&wparam(4));
++	&test	($len,$len);
++	&jz	(&label("cbc_abort"));
++
++	&cmp	(&wparam(5),0);
++	&xchg	($rounds_,"esp");		# alloca
++	&movups	($ivec,&QWP(0,$key_));		# load IV
++	&mov	($rounds,&DWP(240,$key));
++	&mov	($key_,$key);			# backup $key
++	&mov	(&DWP(16,"esp"),$rounds_);	# save original %esp
++	&mov	($rounds_,$rounds);		# backup $rounds
++	&je	(&label("cbc_decrypt"));
++
++	&movaps	($inout0,$ivec);
++	&cmp	($len,16);
++	&jb	(&label("cbc_enc_tail"));
++	&sub	($len,16);
++	&jmp	(&label("cbc_enc_loop"));
++
++&set_label("cbc_enc_loop",16);
++	&movups	($ivec,&QWP(0,$inp));		# input actually
++	&lea	($inp,&DWP(16,$inp));
++	if ($inline)
++	{   &aesni_inline_generate1("enc",$inout0,$ivec);	}
++	else
++	{   &xorps($inout0,$ivec); &call("_aesni_encrypt1");	}
++	&mov	($rounds,$rounds_);	# restore $rounds
++	&mov	($key,$key_);		# restore $key
++	&movups	(&QWP(0,$out),$inout0);	# store output
++	&lea	($out,&DWP(16,$out));
++	&sub	($len,16);
++	&jnc	(&label("cbc_enc_loop"));
++	&add	($len,16);
++	&jnz	(&label("cbc_enc_tail"));
++	&movaps	($ivec,$inout0);
++	&pxor	($inout0,$inout0);
++	&jmp	(&label("cbc_ret"));
++
++&set_label("cbc_enc_tail");
++	&mov	("ecx",$len);		# zaps $rounds
++	&data_word(0xA4F3F689);		# rep movsb
++	&mov	("ecx",16);		# zero tail
++	&sub	("ecx",$len);
++	&xor	("eax","eax");		# zaps $len
++	&data_word(0xAAF3F689);		# rep stosb
++	&lea	($out,&DWP(-16,$out));	# rewind $out by 1 block
++	&mov	($rounds,$rounds_);	# restore $rounds
++	&mov	($inp,$out);		# $inp and $out are the same
++	&mov	($key,$key_);		# restore $key
++	&jmp	(&label("cbc_enc_loop"));
++######################################################################
++&set_label("cbc_decrypt",16);
++	&cmp	($len,0x50);
++	&jbe	(&label("cbc_dec_tail"));
++	&movaps	(&QWP(0,"esp"),$ivec);		# save IV
++	&sub	($len,0x50);
++	&jmp	(&label("cbc_dec_loop6_enter"));
++
++&set_label("cbc_dec_loop6",16);
++	&movaps	(&QWP(0,"esp"),$rndkey0);	# save IV
++	&movups	(&QWP(0,$out),$inout5);
++	&lea	($out,&DWP(0x10,$out));
++&set_label("cbc_dec_loop6_enter");
++	&movdqu	($inout0,&QWP(0,$inp));
++	&movdqu	($inout1,&QWP(0x10,$inp));
++	&movdqu	($inout2,&QWP(0x20,$inp));
++	&movdqu	($inout3,&QWP(0x30,$inp));
++	&movdqu	($inout4,&QWP(0x40,$inp));
++	&movdqu	($inout5,&QWP(0x50,$inp));
++
++	&call	("_aesni_decrypt6");
++
++	&movups	($rndkey1,&QWP(0,$inp));
++	&movups	($rndkey0,&QWP(0x10,$inp));
++	&xorps	($inout0,&QWP(0,"esp"));	# ^=IV
++	&xorps	($inout1,$rndkey1);
++	&movups	($rndkey1,&QWP(0x20,$inp));
++	&xorps	($inout2,$rndkey0);
++	&movups	($rndkey0,&QWP(0x30,$inp));
++	&xorps	($inout3,$rndkey1);
++	&movups	($rndkey1,&QWP(0x40,$inp));
++	&xorps	($inout4,$rndkey0);
++	&movups	($rndkey0,&QWP(0x50,$inp));	# IV
++	&xorps	($inout5,$rndkey1);
++	&movups	(&QWP(0,$out),$inout0);
++	&movups	(&QWP(0x10,$out),$inout1);
++	&lea	($inp,&DWP(0x60,$inp));
++	&movups	(&QWP(0x20,$out),$inout2);
++	&mov	($rounds,$rounds_);		# restore $rounds
++	&movups	(&QWP(0x30,$out),$inout3);
++	&mov	($key,$key_);			# restore $key
++	&movups	(&QWP(0x40,$out),$inout4);
++	&lea	($out,&DWP(0x50,$out));
++	&sub	($len,0x60);
++	&ja	(&label("cbc_dec_loop6"));
++
++	&movaps	($inout0,$inout5);
++	&movaps	($ivec,$rndkey0);
++	&add	($len,0x50);
++	&jle	(&label("cbc_dec_clear_tail_collected"));
++	&movups	(&QWP(0,$out),$inout0);
++	&lea	($out,&DWP(0x10,$out));
++&set_label("cbc_dec_tail");
++	&movups	($inout0,&QWP(0,$inp));
++	&movaps	($in0,$inout0);
++	&cmp	($len,0x10);
++	&jbe	(&label("cbc_dec_one"));
++
++	&movups	($inout1,&QWP(0x10,$inp));
++	&movaps	($in1,$inout1);
++	&cmp	($len,0x20);
++	&jbe	(&label("cbc_dec_two"));
++
++	&movups	($inout2,&QWP(0x20,$inp));
++	&cmp	($len,0x30);
++	&jbe	(&label("cbc_dec_three"));
++
++	&movups	($inout3,&QWP(0x30,$inp));
++	&cmp	($len,0x40);
++	&jbe	(&label("cbc_dec_four"));
++
++	&movups	($inout4,&QWP(0x40,$inp));
++	&movaps	(&QWP(0,"esp"),$ivec);		# save IV
++	&movups	($inout0,&QWP(0,$inp));
++	&xorps	($inout5,$inout5);
++	&call	("_aesni_decrypt6");
++	&movups	($rndkey1,&QWP(0,$inp));
++	&movups	($rndkey0,&QWP(0x10,$inp));
++	&xorps	($inout0,&QWP(0,"esp"));	# ^= IV
++	&xorps	($inout1,$rndkey1);
++	&movups	($rndkey1,&QWP(0x20,$inp));
++	&xorps	($inout2,$rndkey0);
++	&movups	($rndkey0,&QWP(0x30,$inp));
++	&xorps	($inout3,$rndkey1);
++	&movups	($ivec,&QWP(0x40,$inp));	# IV
++	&xorps	($inout4,$rndkey0);
++	&movups	(&QWP(0,$out),$inout0);
++	&movups	(&QWP(0x10,$out),$inout1);
++	&pxor	($inout1,$inout1);
++	&movups	(&QWP(0x20,$out),$inout2);
++	&pxor	($inout2,$inout2);
++	&movups	(&QWP(0x30,$out),$inout3);
++	&pxor	($inout3,$inout3);
++	&lea	($out,&DWP(0x40,$out));
++	&movaps	($inout0,$inout4);
++	&pxor	($inout4,$inout4);
++	&sub	($len,0x50);
++	&jmp	(&label("cbc_dec_tail_collected"));
++
++&set_label("cbc_dec_one",16);
++	if ($inline)
++	{   &aesni_inline_generate1("dec");	}
++	else
++	{   &call	("_aesni_decrypt1");	}
++	&xorps	($inout0,$ivec);
++	&movaps	($ivec,$in0);
++	&sub	($len,0x10);
++	&jmp	(&label("cbc_dec_tail_collected"));
++
++&set_label("cbc_dec_two",16);
++	&call	("_aesni_decrypt2");
++	&xorps	($inout0,$ivec);
++	&xorps	($inout1,$in0);
++	&movups	(&QWP(0,$out),$inout0);
++	&movaps	($inout0,$inout1);
++	&pxor	($inout1,$inout1);
++	&lea	($out,&DWP(0x10,$out));
++	&movaps	($ivec,$in1);
++	&sub	($len,0x20);
++	&jmp	(&label("cbc_dec_tail_collected"));
++
++&set_label("cbc_dec_three",16);
++	&call	("_aesni_decrypt3");
++	&xorps	($inout0,$ivec);
++	&xorps	($inout1,$in0);
++	&xorps	($inout2,$in1);
++	&movups	(&QWP(0,$out),$inout0);
++	&movaps	($inout0,$inout2);
++	&pxor	($inout2,$inout2);
++	&movups	(&QWP(0x10,$out),$inout1);
++	&pxor	($inout1,$inout1);
++	&lea	($out,&DWP(0x20,$out));
++	&movups	($ivec,&QWP(0x20,$inp));
++	&sub	($len,0x30);
++	&jmp	(&label("cbc_dec_tail_collected"));
++
++&set_label("cbc_dec_four",16);
++	&call	("_aesni_decrypt4");
++	&movups	($rndkey1,&QWP(0x10,$inp));
++	&movups	($rndkey0,&QWP(0x20,$inp));
++	&xorps	($inout0,$ivec);
++	&movups	($ivec,&QWP(0x30,$inp));
++	&xorps	($inout1,$in0);
++	&movups	(&QWP(0,$out),$inout0);
++	&xorps	($inout2,$rndkey1);
++	&movups	(&QWP(0x10,$out),$inout1);
++	&pxor	($inout1,$inout1);
++	&xorps	($inout3,$rndkey0);
++	&movups	(&QWP(0x20,$out),$inout2);
++	&pxor	($inout2,$inout2);
++	&lea	($out,&DWP(0x30,$out));
++	&movaps	($inout0,$inout3);
++	&pxor	($inout3,$inout3);
++	&sub	($len,0x40);
++	&jmp	(&label("cbc_dec_tail_collected"));
++
++&set_label("cbc_dec_clear_tail_collected",16);
++	&pxor	($inout1,$inout1);
++	&pxor	($inout2,$inout2);
++	&pxor	($inout3,$inout3);
++	&pxor	($inout4,$inout4);
++&set_label("cbc_dec_tail_collected");
++	&and	($len,15);
++	&jnz	(&label("cbc_dec_tail_partial"));
++	&movups	(&QWP(0,$out),$inout0);
++	&pxor	($rndkey0,$rndkey0);
++	&jmp	(&label("cbc_ret"));
++
++&set_label("cbc_dec_tail_partial",16);
++	&movaps	(&QWP(0,"esp"),$inout0);
++	&pxor	($rndkey0,$rndkey0);
++	&mov	("ecx",16);
++	&mov	($inp,"esp");
++	&sub	("ecx",$len);
++	&data_word(0xA4F3F689);		# rep movsb
++	&movdqa	(&QWP(0,"esp"),$inout0);
++
++&set_label("cbc_ret");
++	&mov	("esp",&DWP(16,"esp"));	# pull original %esp
++	&mov	($key_,&wparam(4));
++	&pxor	($inout0,$inout0);
++	&pxor	($rndkey1,$rndkey1);
++	&movups	(&QWP(0,$key_),$ivec);	# output IV
++	&pxor	($ivec,$ivec);
++&set_label("cbc_abort");
++&function_end("${PREFIX}_cbc_encrypt");
++
++######################################################################
++# Mechanical port from aesni-x86_64.pl.
++#
++# _aesni_set_encrypt_key is private interface,
++# input:
++#	"eax"	const unsigned char *userKey
++#	$rounds	int bits
++#	$key	AES_KEY *key
++# output:
++#	"eax"	return code
++#	$round	rounds
++
++&function_begin_B("_aesni_set_encrypt_key");
++	&push	("ebp");
++	&push	("ebx");
++	&test	("eax","eax");
++	&jz	(&label("bad_pointer"));
++	&test	($key,$key);
++	&jz	(&label("bad_pointer"));
++
++	&call	(&label("pic"));
++&set_label("pic");
++	&blindpop("ebx");
++	&lea	("ebx",&DWP(&label("key_const")."-".&label("pic"),"ebx"));
++
++	&picmeup("ebp","OPENSSL_ia32cap_P","ebx",&label("key_const"));
++	&movups	("xmm0",&QWP(0,"eax"));	# pull first 128 bits of *userKey
++	&xorps	("xmm4","xmm4");	# low dword of xmm4 is assumed 0
++	&mov	("ebp",&DWP(4,"ebp"));
++	&lea	($key,&DWP(16,$key));
++	&and	("ebp",1<<28|1<<11);	# AVX and XOP bits
++	&cmp	($rounds,256);
++	&je	(&label("14rounds"));
++	&cmp	($rounds,192);
++	&je	(&label("12rounds"));
++	&cmp	($rounds,128);
++	&jne	(&label("bad_keybits"));
++
++&set_label("10rounds",16);
++	&cmp		("ebp",1<<28);
++	&je		(&label("10rounds_alt"));
++
++	&mov		($rounds,9);
++	&$movekey	(&QWP(-16,$key),"xmm0");	# round 0
++	&aeskeygenassist("xmm1","xmm0",0x01);		# round 1
++	&call		(&label("key_128_cold"));
++	&aeskeygenassist("xmm1","xmm0",0x2);		# round 2
++	&call		(&label("key_128"));
++	&aeskeygenassist("xmm1","xmm0",0x04);		# round 3
++	&call		(&label("key_128"));
++	&aeskeygenassist("xmm1","xmm0",0x08);		# round 4
++	&call		(&label("key_128"));
++	&aeskeygenassist("xmm1","xmm0",0x10);		# round 5
++	&call		(&label("key_128"));
++	&aeskeygenassist("xmm1","xmm0",0x20);		# round 6
++	&call		(&label("key_128"));
++	&aeskeygenassist("xmm1","xmm0",0x40);		# round 7
++	&call		(&label("key_128"));
++	&aeskeygenassist("xmm1","xmm0",0x80);		# round 8
++	&call		(&label("key_128"));
++	&aeskeygenassist("xmm1","xmm0",0x1b);		# round 9
++	&call		(&label("key_128"));
++	&aeskeygenassist("xmm1","xmm0",0x36);		# round 10
++	&call		(&label("key_128"));
++	&$movekey	(&QWP(0,$key),"xmm0");
++	&mov		(&DWP(80,$key),$rounds);
++
++	&jmp	(&label("good_key"));
++
++&set_label("key_128",16);
++	&$movekey	(&QWP(0,$key),"xmm0");
++	&lea		($key,&DWP(16,$key));
++&set_label("key_128_cold");
++	&shufps		("xmm4","xmm0",0b00010000);
++	&xorps		("xmm0","xmm4");
++	&shufps		("xmm4","xmm0",0b10001100);
++	&xorps		("xmm0","xmm4");
++	&shufps		("xmm1","xmm1",0b11111111);	# critical path
++	&xorps		("xmm0","xmm1");
++	&ret();
++
++&set_label("10rounds_alt",16);
++	&movdqa		("xmm5",&QWP(0x00,"ebx"));
++	&mov		($rounds,8);
++	&movdqa		("xmm4",&QWP(0x20,"ebx"));
++	&movdqa		("xmm2","xmm0");
++	&movdqu		(&QWP(-16,$key),"xmm0");
++
++&set_label("loop_key128");
++	&pshufb		("xmm0","xmm5");
++	&aesenclast	("xmm0","xmm4");
++	&pslld		("xmm4",1);
++	&lea		($key,&DWP(16,$key));
++
++	&movdqa		("xmm3","xmm2");
++	&pslldq		("xmm2",4);
++	&pxor		("xmm3","xmm2");
++	&pslldq		("xmm2",4);
++	&pxor		("xmm3","xmm2");
++	&pslldq		("xmm2",4);
++	&pxor		("xmm2","xmm3");
++
++	&pxor		("xmm0","xmm2");
++	&movdqu		(&QWP(-16,$key),"xmm0");
++	&movdqa		("xmm2","xmm0");
++
++	&dec		($rounds);
++	&jnz		(&label("loop_key128"));
++
++	&movdqa		("xmm4",&QWP(0x30,"ebx"));
++
++	&pshufb		("xmm0","xmm5");
++	&aesenclast	("xmm0","xmm4");
++	&pslld		("xmm4",1);
++
++	&movdqa		("xmm3","xmm2");
++	&pslldq		("xmm2",4);
++	&pxor		("xmm3","xmm2");
++	&pslldq		("xmm2",4);
++	&pxor		("xmm3","xmm2");
++	&pslldq		("xmm2",4);
++	&pxor		("xmm2","xmm3");
++
++	&pxor		("xmm0","xmm2");
++	&movdqu		(&QWP(0,$key),"xmm0");
++
++	&movdqa		("xmm2","xmm0");
++	&pshufb		("xmm0","xmm5");
++	&aesenclast	("xmm0","xmm4");
++
++	&movdqa		("xmm3","xmm2");
++	&pslldq		("xmm2",4);
++	&pxor		("xmm3","xmm2");
++	&pslldq		("xmm2",4);
++	&pxor		("xmm3","xmm2");
++	&pslldq		("xmm2",4);
++	&pxor		("xmm2","xmm3");
++
++	&pxor		("xmm0","xmm2");
++	&movdqu		(&QWP(16,$key),"xmm0");
++
++	&mov		($rounds,9);
++	&mov		(&DWP(96,$key),$rounds);
++
++	&jmp	(&label("good_key"));
++
++&set_label("12rounds",16);
++	&movq		("xmm2",&QWP(16,"eax"));	# remaining 1/3 of *userKey
++	&cmp		("ebp",1<<28);
++	&je		(&label("12rounds_alt"));
++
++	&mov		($rounds,11);
++	&$movekey	(&QWP(-16,$key),"xmm0");	# round 0
++	&aeskeygenassist("xmm1","xmm2",0x01);		# round 1,2
++	&call		(&label("key_192a_cold"));
++	&aeskeygenassist("xmm1","xmm2",0x02);		# round 2,3
++	&call		(&label("key_192b"));
++	&aeskeygenassist("xmm1","xmm2",0x04);		# round 4,5
++	&call		(&label("key_192a"));
++	&aeskeygenassist("xmm1","xmm2",0x08);		# round 5,6
++	&call		(&label("key_192b"));
++	&aeskeygenassist("xmm1","xmm2",0x10);		# round 7,8
++	&call		(&label("key_192a"));
++	&aeskeygenassist("xmm1","xmm2",0x20);		# round 8,9
++	&call		(&label("key_192b"));
++	&aeskeygenassist("xmm1","xmm2",0x40);		# round 10,11
++	&call		(&label("key_192a"));
++	&aeskeygenassist("xmm1","xmm2",0x80);		# round 11,12
++	&call		(&label("key_192b"));
++	&$movekey	(&QWP(0,$key),"xmm0");
++	&mov		(&DWP(48,$key),$rounds);
++
++	&jmp	(&label("good_key"));
++
++&set_label("key_192a",16);
++	&$movekey	(&QWP(0,$key),"xmm0");
++	&lea		($key,&DWP(16,$key));
++&set_label("key_192a_cold",16);
++	&movaps		("xmm5","xmm2");
++&set_label("key_192b_warm");
++	&shufps		("xmm4","xmm0",0b00010000);
++	&movdqa		("xmm3","xmm2");
++	&xorps		("xmm0","xmm4");
++	&shufps		("xmm4","xmm0",0b10001100);
++	&pslldq		("xmm3",4);
++	&xorps		("xmm0","xmm4");
++	&pshufd		("xmm1","xmm1",0b01010101);	# critical path
++	&pxor		("xmm2","xmm3");
++	&pxor		("xmm0","xmm1");
++	&pshufd		("xmm3","xmm0",0b11111111);
++	&pxor		("xmm2","xmm3");
++	&ret();
++
++&set_label("key_192b",16);
++	&movaps		("xmm3","xmm0");
++	&shufps		("xmm5","xmm0",0b01000100);
++	&$movekey	(&QWP(0,$key),"xmm5");
++	&shufps		("xmm3","xmm2",0b01001110);
++	&$movekey	(&QWP(16,$key),"xmm3");
++	&lea		($key,&DWP(32,$key));
++	&jmp		(&label("key_192b_warm"));
++
++&set_label("12rounds_alt",16);
++	&movdqa		("xmm5",&QWP(0x10,"ebx"));
++	&movdqa		("xmm4",&QWP(0x20,"ebx"));
++	&mov		($rounds,8);
++	&movdqu		(&QWP(-16,$key),"xmm0");
++
++&set_label("loop_key192");
++	&movq		(&QWP(0,$key),"xmm2");
++	&movdqa		("xmm1","xmm2");
++	&pshufb		("xmm2","xmm5");
++	&aesenclast	("xmm2","xmm4");
++	&pslld		("xmm4",1);
++	&lea		($key,&DWP(24,$key));
++
++	&movdqa		("xmm3","xmm0");
++	&pslldq		("xmm0",4);
++	&pxor		("xmm3","xmm0");
++	&pslldq		("xmm0",4);
++	&pxor		("xmm3","xmm0");
++	&pslldq		("xmm0",4);
++	&pxor		("xmm0","xmm3");
++
++	&pshufd		("xmm3","xmm0",0xff);
++	&pxor		("xmm3","xmm1");
++	&pslldq		("xmm1",4);
++	&pxor		("xmm3","xmm1");
++
++	&pxor		("xmm0","xmm2");
++	&pxor		("xmm2","xmm3");
++	&movdqu		(&QWP(-16,$key),"xmm0");
++
++	&dec		($rounds);
++	&jnz		(&label("loop_key192"));
++
++	&mov	($rounds,11);
++	&mov	(&DWP(32,$key),$rounds);
++
++	&jmp	(&label("good_key"));
++
++&set_label("14rounds",16);
++	&movups		("xmm2",&QWP(16,"eax"));	# remaining half of *userKey
++	&lea		($key,&DWP(16,$key));
++	&cmp		("ebp",1<<28);
++	&je		(&label("14rounds_alt"));
++
++	&mov		($rounds,13);
++	&$movekey	(&QWP(-32,$key),"xmm0");	# round 0
++	&$movekey	(&QWP(-16,$key),"xmm2");	# round 1
++	&aeskeygenassist("xmm1","xmm2",0x01);		# round 2
++	&call		(&label("key_256a_cold"));
++	&aeskeygenassist("xmm1","xmm0",0x01);		# round 3
++	&call		(&label("key_256b"));
++	&aeskeygenassist("xmm1","xmm2",0x02);		# round 4
++	&call		(&label("key_256a"));
++	&aeskeygenassist("xmm1","xmm0",0x02);		# round 5
++	&call		(&label("key_256b"));
++	&aeskeygenassist("xmm1","xmm2",0x04);		# round 6
++	&call		(&label("key_256a"));
++	&aeskeygenassist("xmm1","xmm0",0x04);		# round 7
++	&call		(&label("key_256b"));
++	&aeskeygenassist("xmm1","xmm2",0x08);		# round 8
++	&call		(&label("key_256a"));
++	&aeskeygenassist("xmm1","xmm0",0x08);		# round 9
++	&call		(&label("key_256b"));
++	&aeskeygenassist("xmm1","xmm2",0x10);		# round 10
++	&call		(&label("key_256a"));
++	&aeskeygenassist("xmm1","xmm0",0x10);		# round 11
++	&call		(&label("key_256b"));
++	&aeskeygenassist("xmm1","xmm2",0x20);		# round 12
++	&call		(&label("key_256a"));
++	&aeskeygenassist("xmm1","xmm0",0x20);		# round 13
++	&call		(&label("key_256b"));
++	&aeskeygenassist("xmm1","xmm2",0x40);		# round 14
++	&call		(&label("key_256a"));
++	&$movekey	(&QWP(0,$key),"xmm0");
++	&mov		(&DWP(16,$key),$rounds);
++	&xor		("eax","eax");
++
++	&jmp	(&label("good_key"));
++
++&set_label("key_256a",16);
++	&$movekey	(&QWP(0,$key),"xmm2");
++	&lea		($key,&DWP(16,$key));
++&set_label("key_256a_cold");
++	&shufps		("xmm4","xmm0",0b00010000);
++	&xorps		("xmm0","xmm4");
++	&shufps		("xmm4","xmm0",0b10001100);
++	&xorps		("xmm0","xmm4");
++	&shufps		("xmm1","xmm1",0b11111111);	# critical path
++	&xorps		("xmm0","xmm1");
++	&ret();
++
++&set_label("key_256b",16);
++	&$movekey	(&QWP(0,$key),"xmm0");
++	&lea		($key,&DWP(16,$key));
++
++	&shufps		("xmm4","xmm2",0b00010000);
++	&xorps		("xmm2","xmm4");
++	&shufps		("xmm4","xmm2",0b10001100);
++	&xorps		("xmm2","xmm4");
++	&shufps		("xmm1","xmm1",0b10101010);	# critical path
++	&xorps		("xmm2","xmm1");
++	&ret();
++
++&set_label("14rounds_alt",16);
++	&movdqa		("xmm5",&QWP(0x00,"ebx"));
++	&movdqa		("xmm4",&QWP(0x20,"ebx"));
++	&mov		($rounds,7);
++	&movdqu		(&QWP(-32,$key),"xmm0");
++	&movdqa		("xmm1","xmm2");
++	&movdqu		(&QWP(-16,$key),"xmm2");
++
++&set_label("loop_key256");
++	&pshufb		("xmm2","xmm5");
++	&aesenclast	("xmm2","xmm4");
++
++	&movdqa		("xmm3","xmm0");
++	&pslldq		("xmm0",4);
++	&pxor		("xmm3","xmm0");
++	&pslldq		("xmm0",4);
++	&pxor		("xmm3","xmm0");
++	&pslldq		("xmm0",4);
++	&pxor		("xmm0","xmm3");
++	&pslld		("xmm4",1);
++
++	&pxor		("xmm0","xmm2");
++	&movdqu		(&QWP(0,$key),"xmm0");
++
++	&dec		($rounds);
++	&jz		(&label("done_key256"));
++
++	&pshufd		("xmm2","xmm0",0xff);
++	&pxor		("xmm3","xmm3");
++	&aesenclast	("xmm2","xmm3");
++
++	&movdqa		("xmm3","xmm1");
++	&pslldq		("xmm1",4);
++	&pxor		("xmm3","xmm1");
++	&pslldq		("xmm1",4);
++	&pxor		("xmm3","xmm1");
++	&pslldq		("xmm1",4);
++	&pxor		("xmm1","xmm3");
++
++	&pxor		("xmm2","xmm1");
++	&movdqu		(&QWP(16,$key),"xmm2");
++	&lea		($key,&DWP(32,$key));
++	&movdqa		("xmm1","xmm2");
++	&jmp		(&label("loop_key256"));
++
++&set_label("done_key256");
++	&mov		($rounds,13);
++	&mov		(&DWP(16,$key),$rounds);
++
++&set_label("good_key");
++	&pxor	("xmm0","xmm0");
++	&pxor	("xmm1","xmm1");
++	&pxor	("xmm2","xmm2");
++	&pxor	("xmm3","xmm3");
++	&pxor	("xmm4","xmm4");
++	&pxor	("xmm5","xmm5");
++	&xor	("eax","eax");
++	&pop	("ebx");
++	&pop	("ebp");
++	&ret	();
++
++&set_label("bad_pointer",4);
++	&mov	("eax",-1);
++	&pop	("ebx");
++	&pop	("ebp");
++	&ret	();
++&set_label("bad_keybits",4);
++	&pxor	("xmm0","xmm0");
++	&mov	("eax",-2);
++	&pop	("ebx");
++	&pop	("ebp");
++	&ret	();
++&function_end_B("_aesni_set_encrypt_key");
++
++# int $PREFIX_set_encrypt_key (const unsigned char *userKey, int bits,
++#                              AES_KEY *key)
++&function_begin_B("${PREFIX}_set_encrypt_key");
++	&mov	("eax",&wparam(0));
++	&mov	($rounds,&wparam(1));
++	&mov	($key,&wparam(2));
++	&call	("_aesni_set_encrypt_key");
++	&ret	();
++&function_end_B("${PREFIX}_set_encrypt_key");
++
++# int $PREFIX_set_decrypt_key (const unsigned char *userKey, int bits,
++#                              AES_KEY *key)
++&function_begin_B("${PREFIX}_set_decrypt_key");
++	&mov	("eax",&wparam(0));
++	&mov	($rounds,&wparam(1));
++	&mov	($key,&wparam(2));
++	&call	("_aesni_set_encrypt_key");
++	&mov	($key,&wparam(2));
++	&shl	($rounds,4);	# rounds-1 after _aesni_set_encrypt_key
++	&test	("eax","eax");
++	&jnz	(&label("dec_key_ret"));
++	&lea	("eax",&DWP(16,$key,$rounds));	# end of key schedule
++
++	&$movekey	("xmm0",&QWP(0,$key));	# just swap
++	&$movekey	("xmm1",&QWP(0,"eax"));
++	&$movekey	(&QWP(0,"eax"),"xmm0");
++	&$movekey	(&QWP(0,$key),"xmm1");
++	&lea		($key,&DWP(16,$key));
++	&lea		("eax",&DWP(-16,"eax"));
++
++&set_label("dec_key_inverse");
++	&$movekey	("xmm0",&QWP(0,$key));	# swap and inverse
++	&$movekey	("xmm1",&QWP(0,"eax"));
++	&aesimc		("xmm0","xmm0");
++	&aesimc		("xmm1","xmm1");
++	&lea		($key,&DWP(16,$key));
++	&lea		("eax",&DWP(-16,"eax"));
++	&$movekey	(&QWP(16,"eax"),"xmm0");
++	&$movekey	(&QWP(-16,$key),"xmm1");
++	&cmp		("eax",$key);
++	&ja		(&label("dec_key_inverse"));
++
++	&$movekey	("xmm0",&QWP(0,$key));	# inverse middle
++	&aesimc		("xmm0","xmm0");
++	&$movekey	(&QWP(0,$key),"xmm0");
++
++	&pxor		("xmm0","xmm0");
++	&pxor		("xmm1","xmm1");
++	&xor		("eax","eax");		# return success
++&set_label("dec_key_ret");
++	&ret	();
++&function_end_B("${PREFIX}_set_decrypt_key");
++
++&set_label("key_const",64);
++&data_word(0x0c0f0e0d,0x0c0f0e0d,0x0c0f0e0d,0x0c0f0e0d);
++&data_word(0x04070605,0x04070605,0x04070605,0x04070605);
++&data_word(1,1,1,1);
++&data_word(0x1b,0x1b,0x1b,0x1b);
++&asciz("AES for Intel AES-NI, CRYPTOGAMS by ");
++
++&asm_finish();
++
++close STDOUT;
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/aes/asm/aesni-x86_64.pl b/CryptoPkg/Library/OpensslLib/openssl/crypto/aes/asm/aesni-x86_64.pl
+new file mode 100644
+index 0000000..98ca179
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/aes/asm/aesni-x86_64.pl
+@@ -0,0 +1,5060 @@
++#! /usr/bin/env perl
++# Copyright 2009-2016 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
++# in the file LICENSE in the source distribution or at
++# https://www.openssl.org/source/license.html
++
++#
++# ====================================================================
++# Written by Andy Polyakov  for the OpenSSL
++# project. The module is, however, dual licensed under OpenSSL and
++# CRYPTOGAMS licenses depending on where you obtain it. For further
++# details see http://www.openssl.org/~appro/cryptogams/.
++# ====================================================================
++#
++# This module implements support for Intel AES-NI extension. In
++# OpenSSL context it's used with Intel engine, but can also be used as
++# drop-in replacement for crypto/aes/asm/aes-x86_64.pl [see below for
++# details].
++#
++# Performance.
++#
++# Given aes(enc|dec) instructions' latency asymptotic performance for
++# non-parallelizable modes such as CBC encrypt is 3.75 cycles per byte
++# processed with 128-bit key. And given their throughput asymptotic
++# performance for parallelizable modes is 1.25 cycles per byte. Being
++# asymptotic limit it's not something you commonly achieve in reality,
++# but how close does one get? Below are results collected for
++# different modes and block sized. Pairs of numbers are for en-/
++# decryption.
++#
++#	16-byte     64-byte     256-byte    1-KB        8-KB
++# ECB	4.25/4.25   1.38/1.38   1.28/1.28   1.26/1.26	1.26/1.26
++# CTR	5.42/5.42   1.92/1.92   1.44/1.44   1.28/1.28   1.26/1.26
++# CBC	4.38/4.43   4.15/1.43   4.07/1.32   4.07/1.29   4.06/1.28
++# CCM	5.66/9.42   4.42/5.41   4.16/4.40   4.09/4.15   4.06/4.07   
++# OFB	5.42/5.42   4.64/4.64   4.44/4.44   4.39/4.39   4.38/4.38
++# CFB	5.73/5.85   5.56/5.62   5.48/5.56   5.47/5.55   5.47/5.55
++#
++# ECB, CTR, CBC and CCM results are free from EVP overhead. This means
++# that otherwise used 'openssl speed -evp aes-128-??? -engine aesni
++# [-decrypt]' will exhibit 10-15% worse results for smaller blocks.
++# The results were collected with specially crafted speed.c benchmark
++# in order to compare them with results reported in "Intel Advanced
++# Encryption Standard (AES) New Instruction Set" White Paper Revision
++# 3.0 dated May 2010. All above results are consistently better. This
++# module also provides better performance for block sizes smaller than
++# 128 bytes in points *not* represented in the above table.
++#
++# Looking at the results for 8-KB buffer.
++#
++# CFB and OFB results are far from the limit, because implementation
++# uses "generic" CRYPTO_[c|o]fb128_encrypt interfaces relying on
++# single-block aesni_encrypt, which is not the most optimal way to go.
++# CBC encrypt result is unexpectedly high and there is no documented
++# explanation for it. Seemingly there is a small penalty for feeding
++# the result back to AES unit the way it's done in CBC mode. There is
++# nothing one can do and the result appears optimal. CCM result is
++# identical to CBC, because CBC-MAC is essentially CBC encrypt without
++# saving output. CCM CTR "stays invisible," because it's neatly
++# interleaved wih CBC-MAC. This provides ~30% improvement over
++# "straghtforward" CCM implementation with CTR and CBC-MAC performed
++# disjointly. Parallelizable modes practically achieve the theoretical
++# limit.
++#
++# Looking at how results vary with buffer size.
++#
++# Curves are practically saturated at 1-KB buffer size. In most cases
++# "256-byte" performance is >95%, and "64-byte" is ~90% of "8-KB" one.
++# CTR curve doesn't follow this pattern and is "slowest" changing one
++# with "256-byte" result being 87% of "8-KB." This is because overhead
++# in CTR mode is most computationally intensive. Small-block CCM
++# decrypt is slower than encrypt, because first CTR and last CBC-MAC
++# iterations can't be interleaved.
++#
++# Results for 192- and 256-bit keys.
++#
++# EVP-free results were observed to scale perfectly with number of
++# rounds for larger block sizes, i.e. 192-bit result being 10/12 times
++# lower and 256-bit one - 10/14. Well, in CBC encrypt case differences
++# are a tad smaller, because the above mentioned penalty biases all
++# results by same constant value. In similar way function call
++# overhead affects small-block performance, as well as OFB and CFB
++# results. Differences are not large, most common coefficients are
++# 10/11.7 and 10/13.4 (as opposite to 10/12.0 and 10/14.0), but one
++# observe even 10/11.2 and 10/12.4 (CTR, OFB, CFB)...
++
++# January 2011
++#
++# While Westmere processor features 6 cycles latency for aes[enc|dec]
++# instructions, which can be scheduled every second cycle, Sandy
++# Bridge spends 8 cycles per instruction, but it can schedule them
++# every cycle. This means that code targeting Westmere would perform
++# suboptimally on Sandy Bridge. Therefore this update.
++#
++# In addition, non-parallelizable CBC encrypt (as well as CCM) is
++# optimized. Relative improvement might appear modest, 8% on Westmere,
++# but in absolute terms it's 3.77 cycles per byte encrypted with
++# 128-bit key on Westmere, and 5.07 - on Sandy Bridge. These numbers
++# should be compared to asymptotic limits of 3.75 for Westmere and
++# 5.00 for Sandy Bridge. Actually, the fact that they get this close
++# to asymptotic limits is quite amazing. Indeed, the limit is
++# calculated as latency times number of rounds, 10 for 128-bit key,
++# and divided by 16, the number of bytes in block, or in other words
++# it accounts *solely* for aesenc instructions. But there are extra
++# instructions, and numbers so close to the asymptotic limits mean
++# that it's as if it takes as little as *one* additional cycle to
++# execute all of them. How is it possible? It is possible thanks to
++# out-of-order execution logic, which manages to overlap post-
++# processing of previous block, things like saving the output, with
++# actual encryption of current block, as well as pre-processing of
++# current block, things like fetching input and xor-ing it with
++# 0-round element of the key schedule, with actual encryption of
++# previous block. Keep this in mind...
++#
++# For parallelizable modes, such as ECB, CBC decrypt, CTR, higher
++# performance is achieved by interleaving instructions working on
++# independent blocks. In which case asymptotic limit for such modes
++# can be obtained by dividing above mentioned numbers by AES
++# instructions' interleave factor. Westmere can execute at most 3 
++# instructions at a time, meaning that optimal interleave factor is 3,
++# and that's where the "magic" number of 1.25 come from. "Optimal
++# interleave factor" means that increase of interleave factor does
++# not improve performance. The formula has proven to reflect reality
++# pretty well on Westmere... Sandy Bridge on the other hand can
++# execute up to 8 AES instructions at a time, so how does varying
++# interleave factor affect the performance? Here is table for ECB
++# (numbers are cycles per byte processed with 128-bit key):
++#
++# instruction interleave factor		3x	6x	8x
++# theoretical asymptotic limit		1.67	0.83	0.625
++# measured performance for 8KB block	1.05	0.86	0.84
++#
++# "as if" interleave factor		4.7x	5.8x	6.0x
++#
++# Further data for other parallelizable modes:
++#
++# CBC decrypt				1.16	0.93	0.74
++# CTR					1.14	0.91	0.74
++#
++# Well, given 3x column it's probably inappropriate to call the limit
++# asymptotic, if it can be surpassed, isn't it? What happens there?
++# Rewind to CBC paragraph for the answer. Yes, out-of-order execution
++# magic is responsible for this. Processor overlaps not only the
++# additional instructions with AES ones, but even AES instuctions
++# processing adjacent triplets of independent blocks. In the 6x case
++# additional instructions  still claim disproportionally small amount
++# of additional cycles, but in 8x case number of instructions must be
++# a tad too high for out-of-order logic to cope with, and AES unit
++# remains underutilized... As you can see 8x interleave is hardly
++# justifiable, so there no need to feel bad that 32-bit aesni-x86.pl
++# utilizies 6x interleave because of limited register bank capacity.
++#
++# Higher interleave factors do have negative impact on Westmere
++# performance. While for ECB mode it's negligible ~1.5%, other
++# parallelizables perform ~5% worse, which is outweighed by ~25%
++# improvement on Sandy Bridge. To balance regression on Westmere
++# CTR mode was implemented with 6x aesenc interleave factor.
++
++# April 2011
++#
++# Add aesni_xts_[en|de]crypt. Westmere spends 1.25 cycles processing
++# one byte out of 8KB with 128-bit key, Sandy Bridge - 0.90. Just like
++# in CTR mode AES instruction interleave factor was chosen to be 6x.
++
++# November 2015
++#
++# Add aesni_ocb_[en|de]crypt. AES instruction interleave factor was
++# chosen to be 6x.
++
++######################################################################
++# Current large-block performance in cycles per byte processed with
++# 128-bit key (less is better).
++#
++#		CBC en-/decrypt	CTR	XTS	ECB	OCB
++# Westmere	3.77/1.25	1.25	1.25	1.26
++# * Bridge	5.07/0.74	0.75	0.90	0.85	0.98
++# Haswell	4.44/0.63	0.63	0.73	0.63	0.70
++# Skylake	2.62/0.63	0.63	0.63	0.63
++# Silvermont	5.75/3.54	3.56	4.12	3.87(*)	4.11
++# Goldmont	3.82/1.26	1.26	1.29	1.29	1.50
++# Bulldozer	5.77/0.70	0.72	0.90	0.70	0.95
++#
++# (*)	Atom Silvermont ECB result is suboptimal because of penalties
++#	incurred by operations on %xmm8-15. As ECB is not considered
++#	critical, nothing was done to mitigate the problem.
++
++$PREFIX="aesni";	# if $PREFIX is set to "AES", the script
++			# generates drop-in replacement for
++			# crypto/aes/asm/aes-x86_64.pl:-)
++
++$flavour = shift;
++$output  = shift;
++if ($flavour =~ /\./) { $output = $flavour; undef $flavour; }
++
++$win64=0; $win64=1 if ($flavour =~ /[nm]asm|mingw64/ || $output =~ /\.asm$/);
++
++$0 =~ m/(.*[\/\\])[^\/\\]+$/; $dir=$1;
++( $xlate="${dir}x86_64-xlate.pl" and -f $xlate ) or
++( $xlate="${dir}../../perlasm/x86_64-xlate.pl" and -f $xlate) or
++die "can't locate x86_64-xlate.pl";
++
++open OUT,"| \"$^X\" \"$xlate\" $flavour \"$output\"";
++*STDOUT=*OUT;
++
++$movkey = $PREFIX eq "aesni" ? "movups" : "movups";
++@_4args=$win64?	("%rcx","%rdx","%r8", "%r9") :	# Win64 order
++		("%rdi","%rsi","%rdx","%rcx");	# Unix order
++
++$code=".text\n";
++$code.=".extern	OPENSSL_ia32cap_P\n";
++
++$rounds="%eax";	# input to and changed by aesni_[en|de]cryptN !!!
++# this is natural Unix argument order for public $PREFIX_[ecb|cbc]_encrypt ...
++$inp="%rdi";
++$out="%rsi";
++$len="%rdx";
++$key="%rcx";	# input to and changed by aesni_[en|de]cryptN !!!
++$ivp="%r8";	# cbc, ctr, ...
++
++$rnds_="%r10d";	# backup copy for $rounds
++$key_="%r11";	# backup copy for $key
++
++# %xmm register layout
++$rndkey0="%xmm0";	$rndkey1="%xmm1";
++$inout0="%xmm2";	$inout1="%xmm3";
++$inout2="%xmm4";	$inout3="%xmm5";
++$inout4="%xmm6";	$inout5="%xmm7";
++$inout6="%xmm8";	$inout7="%xmm9";
++
++$in2="%xmm6";		$in1="%xmm7";	# used in CBC decrypt, CTR, ...
++$in0="%xmm8";		$iv="%xmm9";
++
++# Inline version of internal aesni_[en|de]crypt1.
++#
++# Why folded loop? Because aes[enc|dec] is slow enough to accommodate
++# cycles which take care of loop variables...
++{ my $sn;
++sub aesni_generate1 {
++my ($p,$key,$rounds,$inout,$ivec)=@_;	$inout=$inout0 if (!defined($inout));
++++$sn;
++$code.=<<___;
++	$movkey	($key),$rndkey0
++	$movkey	16($key),$rndkey1
++___
++$code.=<<___ if (defined($ivec));
++	xorps	$rndkey0,$ivec
++	lea	32($key),$key
++	xorps	$ivec,$inout
++___
++$code.=<<___ if (!defined($ivec));
++	lea	32($key),$key
++	xorps	$rndkey0,$inout
++___
++$code.=<<___;
++.Loop_${p}1_$sn:
++	aes${p}	$rndkey1,$inout
++	dec	$rounds
++	$movkey	($key),$rndkey1
++	lea	16($key),$key
++	jnz	.Loop_${p}1_$sn	# loop body is 16 bytes
++	aes${p}last	$rndkey1,$inout
++___
++}}
++# void $PREFIX_[en|de]crypt (const void *inp,void *out,const AES_KEY *key);
++#
++{ my ($inp,$out,$key) = @_4args;
++
++$code.=<<___;
++.globl	${PREFIX}_encrypt
++.type	${PREFIX}_encrypt,\@abi-omnipotent
++.align	16
++${PREFIX}_encrypt:
++	movups	($inp),$inout0		# load input
++	mov	240($key),$rounds	# key->rounds
++___
++	&aesni_generate1("enc",$key,$rounds);
++$code.=<<___;
++	 pxor	$rndkey0,$rndkey0	# clear register bank
++	 pxor	$rndkey1,$rndkey1
++	movups	$inout0,($out)		# output
++	 pxor	$inout0,$inout0
++	ret
++.size	${PREFIX}_encrypt,.-${PREFIX}_encrypt
++
++.globl	${PREFIX}_decrypt
++.type	${PREFIX}_decrypt,\@abi-omnipotent
++.align	16
++${PREFIX}_decrypt:
++	movups	($inp),$inout0		# load input
++	mov	240($key),$rounds	# key->rounds
++___
++	&aesni_generate1("dec",$key,$rounds);
++$code.=<<___;
++	 pxor	$rndkey0,$rndkey0	# clear register bank
++	 pxor	$rndkey1,$rndkey1
++	movups	$inout0,($out)		# output
++	 pxor	$inout0,$inout0
++	ret
++.size	${PREFIX}_decrypt, .-${PREFIX}_decrypt
++___
++}
++
++# _aesni_[en|de]cryptN are private interfaces, N denotes interleave
++# factor. Why 3x subroutine were originally used in loops? Even though
++# aes[enc|dec] latency was originally 6, it could be scheduled only
++# every *2nd* cycle. Thus 3x interleave was the one providing optimal
++# utilization, i.e. when subroutine's throughput is virtually same as
++# of non-interleaved subroutine [for number of input blocks up to 3].
++# This is why it originally made no sense to implement 2x subroutine.
++# But times change and it became appropriate to spend extra 192 bytes
++# on 2x subroutine on Atom Silvermont account. For processors that
++# can schedule aes[enc|dec] every cycle optimal interleave factor
++# equals to corresponding instructions latency. 8x is optimal for
++# * Bridge and "super-optimal" for other Intel CPUs... 
++
++sub aesni_generate2 {
++my $dir=shift;
++# As already mentioned it takes in $key and $rounds, which are *not*
++# preserved. $inout[0-1] is cipher/clear text...
++$code.=<<___;
++.type	_aesni_${dir}rypt2,\@abi-omnipotent
++.align	16
++_aesni_${dir}rypt2:
++	$movkey	($key),$rndkey0
++	shl	\$4,$rounds
++	$movkey	16($key),$rndkey1
++	xorps	$rndkey0,$inout0
++	xorps	$rndkey0,$inout1
++	$movkey	32($key),$rndkey0
++	lea	32($key,$rounds),$key
++	neg	%rax				# $rounds
++	add	\$16,%rax
++
++.L${dir}_loop2:
++	aes${dir}	$rndkey1,$inout0
++	aes${dir}	$rndkey1,$inout1
++	$movkey		($key,%rax),$rndkey1
++	add		\$32,%rax
++	aes${dir}	$rndkey0,$inout0
++	aes${dir}	$rndkey0,$inout1
++	$movkey		-16($key,%rax),$rndkey0
++	jnz		.L${dir}_loop2
++
++	aes${dir}	$rndkey1,$inout0
++	aes${dir}	$rndkey1,$inout1
++	aes${dir}last	$rndkey0,$inout0
++	aes${dir}last	$rndkey0,$inout1
++	ret
++.size	_aesni_${dir}rypt2,.-_aesni_${dir}rypt2
++___
++}
++sub aesni_generate3 {
++my $dir=shift;
++# As already mentioned it takes in $key and $rounds, which are *not*
++# preserved. $inout[0-2] is cipher/clear text...
++$code.=<<___;
++.type	_aesni_${dir}rypt3,\@abi-omnipotent
++.align	16
++_aesni_${dir}rypt3:
++	$movkey	($key),$rndkey0
++	shl	\$4,$rounds
++	$movkey	16($key),$rndkey1
++	xorps	$rndkey0,$inout0
++	xorps	$rndkey0,$inout1
++	xorps	$rndkey0,$inout2
++	$movkey	32($key),$rndkey0
++	lea	32($key,$rounds),$key
++	neg	%rax				# $rounds
++	add	\$16,%rax
++
++.L${dir}_loop3:
++	aes${dir}	$rndkey1,$inout0
++	aes${dir}	$rndkey1,$inout1
++	aes${dir}	$rndkey1,$inout2
++	$movkey		($key,%rax),$rndkey1
++	add		\$32,%rax
++	aes${dir}	$rndkey0,$inout0
++	aes${dir}	$rndkey0,$inout1
++	aes${dir}	$rndkey0,$inout2
++	$movkey		-16($key,%rax),$rndkey0
++	jnz		.L${dir}_loop3
++
++	aes${dir}	$rndkey1,$inout0
++	aes${dir}	$rndkey1,$inout1
++	aes${dir}	$rndkey1,$inout2
++	aes${dir}last	$rndkey0,$inout0
++	aes${dir}last	$rndkey0,$inout1
++	aes${dir}last	$rndkey0,$inout2
++	ret
++.size	_aesni_${dir}rypt3,.-_aesni_${dir}rypt3
++___
++}
++# 4x interleave is implemented to improve small block performance,
++# most notably [and naturally] 4 block by ~30%. One can argue that one
++# should have implemented 5x as well, but improvement would be <20%,
++# so it's not worth it...
++sub aesni_generate4 {
++my $dir=shift;
++# As already mentioned it takes in $key and $rounds, which are *not*
++# preserved. $inout[0-3] is cipher/clear text...
++$code.=<<___;
++.type	_aesni_${dir}rypt4,\@abi-omnipotent
++.align	16
++_aesni_${dir}rypt4:
++	$movkey	($key),$rndkey0
++	shl	\$4,$rounds
++	$movkey	16($key),$rndkey1
++	xorps	$rndkey0,$inout0
++	xorps	$rndkey0,$inout1
++	xorps	$rndkey0,$inout2
++	xorps	$rndkey0,$inout3
++	$movkey	32($key),$rndkey0
++	lea	32($key,$rounds),$key
++	neg	%rax				# $rounds
++	.byte	0x0f,0x1f,0x00
++	add	\$16,%rax
++
++.L${dir}_loop4:
++	aes${dir}	$rndkey1,$inout0
++	aes${dir}	$rndkey1,$inout1
++	aes${dir}	$rndkey1,$inout2
++	aes${dir}	$rndkey1,$inout3
++	$movkey		($key,%rax),$rndkey1
++	add		\$32,%rax
++	aes${dir}	$rndkey0,$inout0
++	aes${dir}	$rndkey0,$inout1
++	aes${dir}	$rndkey0,$inout2
++	aes${dir}	$rndkey0,$inout3
++	$movkey		-16($key,%rax),$rndkey0
++	jnz		.L${dir}_loop4
++
++	aes${dir}	$rndkey1,$inout0
++	aes${dir}	$rndkey1,$inout1
++	aes${dir}	$rndkey1,$inout2
++	aes${dir}	$rndkey1,$inout3
++	aes${dir}last	$rndkey0,$inout0
++	aes${dir}last	$rndkey0,$inout1
++	aes${dir}last	$rndkey0,$inout2
++	aes${dir}last	$rndkey0,$inout3
++	ret
++.size	_aesni_${dir}rypt4,.-_aesni_${dir}rypt4
++___
++}
++sub aesni_generate6 {
++my $dir=shift;
++# As already mentioned it takes in $key and $rounds, which are *not*
++# preserved. $inout[0-5] is cipher/clear text...
++$code.=<<___;
++.type	_aesni_${dir}rypt6,\@abi-omnipotent
++.align	16
++_aesni_${dir}rypt6:
++	$movkey		($key),$rndkey0
++	shl		\$4,$rounds
++	$movkey		16($key),$rndkey1
++	xorps		$rndkey0,$inout0
++	pxor		$rndkey0,$inout1
++	pxor		$rndkey0,$inout2
++	aes${dir}	$rndkey1,$inout0
++	lea		32($key,$rounds),$key
++	neg		%rax			# $rounds
++	aes${dir}	$rndkey1,$inout1
++	pxor		$rndkey0,$inout3
++	pxor		$rndkey0,$inout4
++	aes${dir}	$rndkey1,$inout2
++	pxor		$rndkey0,$inout5
++	$movkey		($key,%rax),$rndkey0
++	add		\$16,%rax
++	jmp		.L${dir}_loop6_enter
++.align	16
++.L${dir}_loop6:
++	aes${dir}	$rndkey1,$inout0
++	aes${dir}	$rndkey1,$inout1
++	aes${dir}	$rndkey1,$inout2
++.L${dir}_loop6_enter:
++	aes${dir}	$rndkey1,$inout3
++	aes${dir}	$rndkey1,$inout4
++	aes${dir}	$rndkey1,$inout5
++	$movkey		($key,%rax),$rndkey1
++	add		\$32,%rax
++	aes${dir}	$rndkey0,$inout0
++	aes${dir}	$rndkey0,$inout1
++	aes${dir}	$rndkey0,$inout2
++	aes${dir}	$rndkey0,$inout3
++	aes${dir}	$rndkey0,$inout4
++	aes${dir}	$rndkey0,$inout5
++	$movkey		-16($key,%rax),$rndkey0
++	jnz		.L${dir}_loop6
++
++	aes${dir}	$rndkey1,$inout0
++	aes${dir}	$rndkey1,$inout1
++	aes${dir}	$rndkey1,$inout2
++	aes${dir}	$rndkey1,$inout3
++	aes${dir}	$rndkey1,$inout4
++	aes${dir}	$rndkey1,$inout5
++	aes${dir}last	$rndkey0,$inout0
++	aes${dir}last	$rndkey0,$inout1
++	aes${dir}last	$rndkey0,$inout2
++	aes${dir}last	$rndkey0,$inout3
++	aes${dir}last	$rndkey0,$inout4
++	aes${dir}last	$rndkey0,$inout5
++	ret
++.size	_aesni_${dir}rypt6,.-_aesni_${dir}rypt6
++___
++}
++sub aesni_generate8 {
++my $dir=shift;
++# As already mentioned it takes in $key and $rounds, which are *not*
++# preserved. $inout[0-7] is cipher/clear text...
++$code.=<<___;
++.type	_aesni_${dir}rypt8,\@abi-omnipotent
++.align	16
++_aesni_${dir}rypt8:
++	$movkey		($key),$rndkey0
++	shl		\$4,$rounds
++	$movkey		16($key),$rndkey1
++	xorps		$rndkey0,$inout0
++	xorps		$rndkey0,$inout1
++	pxor		$rndkey0,$inout2
++	pxor		$rndkey0,$inout3
++	pxor		$rndkey0,$inout4
++	lea		32($key,$rounds),$key
++	neg		%rax			# $rounds
++	aes${dir}	$rndkey1,$inout0
++	pxor		$rndkey0,$inout5
++	pxor		$rndkey0,$inout6
++	aes${dir}	$rndkey1,$inout1
++	pxor		$rndkey0,$inout7
++	$movkey		($key,%rax),$rndkey0
++	add		\$16,%rax
++	jmp		.L${dir}_loop8_inner
++.align	16
++.L${dir}_loop8:
++	aes${dir}	$rndkey1,$inout0
++	aes${dir}	$rndkey1,$inout1
++.L${dir}_loop8_inner:
++	aes${dir}	$rndkey1,$inout2
++	aes${dir}	$rndkey1,$inout3
++	aes${dir}	$rndkey1,$inout4
++	aes${dir}	$rndkey1,$inout5
++	aes${dir}	$rndkey1,$inout6
++	aes${dir}	$rndkey1,$inout7
++.L${dir}_loop8_enter:
++	$movkey		($key,%rax),$rndkey1
++	add		\$32,%rax
++	aes${dir}	$rndkey0,$inout0
++	aes${dir}	$rndkey0,$inout1
++	aes${dir}	$rndkey0,$inout2
++	aes${dir}	$rndkey0,$inout3
++	aes${dir}	$rndkey0,$inout4
++	aes${dir}	$rndkey0,$inout5
++	aes${dir}	$rndkey0,$inout6
++	aes${dir}	$rndkey0,$inout7
++	$movkey		-16($key,%rax),$rndkey0
++	jnz		.L${dir}_loop8
++
++	aes${dir}	$rndkey1,$inout0
++	aes${dir}	$rndkey1,$inout1
++	aes${dir}	$rndkey1,$inout2
++	aes${dir}	$rndkey1,$inout3
++	aes${dir}	$rndkey1,$inout4
++	aes${dir}	$rndkey1,$inout5
++	aes${dir}	$rndkey1,$inout6
++	aes${dir}	$rndkey1,$inout7
++	aes${dir}last	$rndkey0,$inout0
++	aes${dir}last	$rndkey0,$inout1
++	aes${dir}last	$rndkey0,$inout2
++	aes${dir}last	$rndkey0,$inout3
++	aes${dir}last	$rndkey0,$inout4
++	aes${dir}last	$rndkey0,$inout5
++	aes${dir}last	$rndkey0,$inout6
++	aes${dir}last	$rndkey0,$inout7
++	ret
++.size	_aesni_${dir}rypt8,.-_aesni_${dir}rypt8
++___
++}
++&aesni_generate2("enc") if ($PREFIX eq "aesni");
++&aesni_generate2("dec");
++&aesni_generate3("enc") if ($PREFIX eq "aesni");
++&aesni_generate3("dec");
++&aesni_generate4("enc") if ($PREFIX eq "aesni");
++&aesni_generate4("dec");
++&aesni_generate6("enc") if ($PREFIX eq "aesni");
++&aesni_generate6("dec");
++&aesni_generate8("enc") if ($PREFIX eq "aesni");
++&aesni_generate8("dec");
++
++if ($PREFIX eq "aesni") {
++########################################################################
++# void aesni_ecb_encrypt (const void *in, void *out,
++#			  size_t length, const AES_KEY *key,
++#			  int enc);
++$code.=<<___;
++.globl	aesni_ecb_encrypt
++.type	aesni_ecb_encrypt,\@function,5
++.align	16
++aesni_ecb_encrypt:
++___
++$code.=<<___ if ($win64);
++	lea	-0x58(%rsp),%rsp
++	movaps	%xmm6,(%rsp)		# offload $inout4..7
++	movaps	%xmm7,0x10(%rsp)
++	movaps	%xmm8,0x20(%rsp)
++	movaps	%xmm9,0x30(%rsp)
++.Lecb_enc_body:
++___
++$code.=<<___;
++	and	\$-16,$len		# if ($len<16)
++	jz	.Lecb_ret		# return
++
++	mov	240($key),$rounds	# key->rounds
++	$movkey	($key),$rndkey0
++	mov	$key,$key_		# backup $key
++	mov	$rounds,$rnds_		# backup $rounds
++	test	%r8d,%r8d		# 5th argument
++	jz	.Lecb_decrypt
++#--------------------------- ECB ENCRYPT ------------------------------#
++	cmp	\$0x80,$len		# if ($len<8*16)
++	jb	.Lecb_enc_tail		# short input
++
++	movdqu	($inp),$inout0		# load 8 input blocks
++	movdqu	0x10($inp),$inout1
++	movdqu	0x20($inp),$inout2
++	movdqu	0x30($inp),$inout3
++	movdqu	0x40($inp),$inout4
++	movdqu	0x50($inp),$inout5
++	movdqu	0x60($inp),$inout6
++	movdqu	0x70($inp),$inout7
++	lea	0x80($inp),$inp		# $inp+=8*16
++	sub	\$0x80,$len		# $len-=8*16 (can be zero)
++	jmp	.Lecb_enc_loop8_enter
++.align 16
++.Lecb_enc_loop8:
++	movups	$inout0,($out)		# store 8 output blocks
++	mov	$key_,$key		# restore $key
++	movdqu	($inp),$inout0		# load 8 input blocks
++	mov	$rnds_,$rounds		# restore $rounds
++	movups	$inout1,0x10($out)
++	movdqu	0x10($inp),$inout1
++	movups	$inout2,0x20($out)
++	movdqu	0x20($inp),$inout2
++	movups	$inout3,0x30($out)
++	movdqu	0x30($inp),$inout3
++	movups	$inout4,0x40($out)
++	movdqu	0x40($inp),$inout4
++	movups	$inout5,0x50($out)
++	movdqu	0x50($inp),$inout5
++	movups	$inout6,0x60($out)
++	movdqu	0x60($inp),$inout6
++	movups	$inout7,0x70($out)
++	lea	0x80($out),$out		# $out+=8*16
++	movdqu	0x70($inp),$inout7
++	lea	0x80($inp),$inp		# $inp+=8*16
++.Lecb_enc_loop8_enter:
++
++	call	_aesni_encrypt8
++
++	sub	\$0x80,$len
++	jnc	.Lecb_enc_loop8		# loop if $len-=8*16 didn't borrow
++
++	movups	$inout0,($out)		# store 8 output blocks
++	mov	$key_,$key		# restore $key
++	movups	$inout1,0x10($out)
++	mov	$rnds_,$rounds		# restore $rounds
++	movups	$inout2,0x20($out)
++	movups	$inout3,0x30($out)
++	movups	$inout4,0x40($out)
++	movups	$inout5,0x50($out)
++	movups	$inout6,0x60($out)
++	movups	$inout7,0x70($out)
++	lea	0x80($out),$out		# $out+=8*16
++	add	\$0x80,$len		# restore real remaining $len
++	jz	.Lecb_ret		# done if ($len==0)
++
++.Lecb_enc_tail:				# $len is less than 8*16
++	movups	($inp),$inout0
++	cmp	\$0x20,$len
++	jb	.Lecb_enc_one
++	movups	0x10($inp),$inout1
++	je	.Lecb_enc_two
++	movups	0x20($inp),$inout2
++	cmp	\$0x40,$len
++	jb	.Lecb_enc_three
++	movups	0x30($inp),$inout3
++	je	.Lecb_enc_four
++	movups	0x40($inp),$inout4
++	cmp	\$0x60,$len
++	jb	.Lecb_enc_five
++	movups	0x50($inp),$inout5
++	je	.Lecb_enc_six
++	movdqu	0x60($inp),$inout6
++	xorps	$inout7,$inout7
++	call	_aesni_encrypt8
++	movups	$inout0,($out)		# store 7 output blocks
++	movups	$inout1,0x10($out)
++	movups	$inout2,0x20($out)
++	movups	$inout3,0x30($out)
++	movups	$inout4,0x40($out)
++	movups	$inout5,0x50($out)
++	movups	$inout6,0x60($out)
++	jmp	.Lecb_ret
++.align	16
++.Lecb_enc_one:
++___
++	&aesni_generate1("enc",$key,$rounds);
++$code.=<<___;
++	movups	$inout0,($out)		# store one output block
++	jmp	.Lecb_ret
++.align	16
++.Lecb_enc_two:
++	call	_aesni_encrypt2
++	movups	$inout0,($out)		# store 2 output blocks
++	movups	$inout1,0x10($out)
++	jmp	.Lecb_ret
++.align	16
++.Lecb_enc_three:
++	call	_aesni_encrypt3
++	movups	$inout0,($out)		# store 3 output blocks
++	movups	$inout1,0x10($out)
++	movups	$inout2,0x20($out)
++	jmp	.Lecb_ret
++.align	16
++.Lecb_enc_four:
++	call	_aesni_encrypt4
++	movups	$inout0,($out)		# store 4 output blocks
++	movups	$inout1,0x10($out)
++	movups	$inout2,0x20($out)
++	movups	$inout3,0x30($out)
++	jmp	.Lecb_ret
++.align	16
++.Lecb_enc_five:
++	xorps	$inout5,$inout5
++	call	_aesni_encrypt6
++	movups	$inout0,($out)		# store 5 output blocks
++	movups	$inout1,0x10($out)
++	movups	$inout2,0x20($out)
++	movups	$inout3,0x30($out)
++	movups	$inout4,0x40($out)
++	jmp	.Lecb_ret
++.align	16
++.Lecb_enc_six:
++	call	_aesni_encrypt6
++	movups	$inout0,($out)		# store 6 output blocks
++	movups	$inout1,0x10($out)
++	movups	$inout2,0x20($out)
++	movups	$inout3,0x30($out)
++	movups	$inout4,0x40($out)
++	movups	$inout5,0x50($out)
++	jmp	.Lecb_ret
++#--------------------------- ECB DECRYPT ------------------------------#
++.align	16
++.Lecb_decrypt:
++	cmp	\$0x80,$len		# if ($len<8*16)
++	jb	.Lecb_dec_tail		# short input
++
++	movdqu	($inp),$inout0		# load 8 input blocks
++	movdqu	0x10($inp),$inout1
++	movdqu	0x20($inp),$inout2
++	movdqu	0x30($inp),$inout3
++	movdqu	0x40($inp),$inout4
++	movdqu	0x50($inp),$inout5
++	movdqu	0x60($inp),$inout6
++	movdqu	0x70($inp),$inout7
++	lea	0x80($inp),$inp		# $inp+=8*16
++	sub	\$0x80,$len		# $len-=8*16 (can be zero)
++	jmp	.Lecb_dec_loop8_enter
++.align 16
++.Lecb_dec_loop8:
++	movups	$inout0,($out)		# store 8 output blocks
++	mov	$key_,$key		# restore $key
++	movdqu	($inp),$inout0		# load 8 input blocks
++	mov	$rnds_,$rounds		# restore $rounds
++	movups	$inout1,0x10($out)
++	movdqu	0x10($inp),$inout1
++	movups	$inout2,0x20($out)
++	movdqu	0x20($inp),$inout2
++	movups	$inout3,0x30($out)
++	movdqu	0x30($inp),$inout3
++	movups	$inout4,0x40($out)
++	movdqu	0x40($inp),$inout4
++	movups	$inout5,0x50($out)
++	movdqu	0x50($inp),$inout5
++	movups	$inout6,0x60($out)
++	movdqu	0x60($inp),$inout6
++	movups	$inout7,0x70($out)
++	lea	0x80($out),$out		# $out+=8*16
++	movdqu	0x70($inp),$inout7
++	lea	0x80($inp),$inp		# $inp+=8*16
++.Lecb_dec_loop8_enter:
++
++	call	_aesni_decrypt8
++
++	$movkey	($key_),$rndkey0
++	sub	\$0x80,$len
++	jnc	.Lecb_dec_loop8		# loop if $len-=8*16 didn't borrow
++
++	movups	$inout0,($out)		# store 8 output blocks
++	 pxor	$inout0,$inout0		# clear register bank
++	mov	$key_,$key		# restore $key
++	movups	$inout1,0x10($out)
++	 pxor	$inout1,$inout1
++	mov	$rnds_,$rounds		# restore $rounds
++	movups	$inout2,0x20($out)
++	 pxor	$inout2,$inout2
++	movups	$inout3,0x30($out)
++	 pxor	$inout3,$inout3
++	movups	$inout4,0x40($out)
++	 pxor	$inout4,$inout4
++	movups	$inout5,0x50($out)
++	 pxor	$inout5,$inout5
++	movups	$inout6,0x60($out)
++	 pxor	$inout6,$inout6
++	movups	$inout7,0x70($out)
++	 pxor	$inout7,$inout7
++	lea	0x80($out),$out		# $out+=8*16
++	add	\$0x80,$len		# restore real remaining $len
++	jz	.Lecb_ret		# done if ($len==0)
++
++.Lecb_dec_tail:
++	movups	($inp),$inout0
++	cmp	\$0x20,$len
++	jb	.Lecb_dec_one
++	movups	0x10($inp),$inout1
++	je	.Lecb_dec_two
++	movups	0x20($inp),$inout2
++	cmp	\$0x40,$len
++	jb	.Lecb_dec_three
++	movups	0x30($inp),$inout3
++	je	.Lecb_dec_four
++	movups	0x40($inp),$inout4
++	cmp	\$0x60,$len
++	jb	.Lecb_dec_five
++	movups	0x50($inp),$inout5
++	je	.Lecb_dec_six
++	movups	0x60($inp),$inout6
++	$movkey	($key),$rndkey0
++	xorps	$inout7,$inout7
++	call	_aesni_decrypt8
++	movups	$inout0,($out)		# store 7 output blocks
++	 pxor	$inout0,$inout0		# clear register bank
++	movups	$inout1,0x10($out)
++	 pxor	$inout1,$inout1
++	movups	$inout2,0x20($out)
++	 pxor	$inout2,$inout2
++	movups	$inout3,0x30($out)
++	 pxor	$inout3,$inout3
++	movups	$inout4,0x40($out)
++	 pxor	$inout4,$inout4
++	movups	$inout5,0x50($out)
++	 pxor	$inout5,$inout5
++	movups	$inout6,0x60($out)
++	 pxor	$inout6,$inout6
++	 pxor	$inout7,$inout7
++	jmp	.Lecb_ret
++.align	16
++.Lecb_dec_one:
++___
++	&aesni_generate1("dec",$key,$rounds);
++$code.=<<___;
++	movups	$inout0,($out)		# store one output block
++	 pxor	$inout0,$inout0		# clear register bank
++	jmp	.Lecb_ret
++.align	16
++.Lecb_dec_two:
++	call	_aesni_decrypt2
++	movups	$inout0,($out)		# store 2 output blocks
++	 pxor	$inout0,$inout0		# clear register bank
++	movups	$inout1,0x10($out)
++	 pxor	$inout1,$inout1
++	jmp	.Lecb_ret
++.align	16
++.Lecb_dec_three:
++	call	_aesni_decrypt3
++	movups	$inout0,($out)		# store 3 output blocks
++	 pxor	$inout0,$inout0		# clear register bank
++	movups	$inout1,0x10($out)
++	 pxor	$inout1,$inout1
++	movups	$inout2,0x20($out)
++	 pxor	$inout2,$inout2
++	jmp	.Lecb_ret
++.align	16
++.Lecb_dec_four:
++	call	_aesni_decrypt4
++	movups	$inout0,($out)		# store 4 output blocks
++	 pxor	$inout0,$inout0		# clear register bank
++	movups	$inout1,0x10($out)
++	 pxor	$inout1,$inout1
++	movups	$inout2,0x20($out)
++	 pxor	$inout2,$inout2
++	movups	$inout3,0x30($out)
++	 pxor	$inout3,$inout3
++	jmp	.Lecb_ret
++.align	16
++.Lecb_dec_five:
++	xorps	$inout5,$inout5
++	call	_aesni_decrypt6
++	movups	$inout0,($out)		# store 5 output blocks
++	 pxor	$inout0,$inout0		# clear register bank
++	movups	$inout1,0x10($out)
++	 pxor	$inout1,$inout1
++	movups	$inout2,0x20($out)
++	 pxor	$inout2,$inout2
++	movups	$inout3,0x30($out)
++	 pxor	$inout3,$inout3
++	movups	$inout4,0x40($out)
++	 pxor	$inout4,$inout4
++	 pxor	$inout5,$inout5
++	jmp	.Lecb_ret
++.align	16
++.Lecb_dec_six:
++	call	_aesni_decrypt6
++	movups	$inout0,($out)		# store 6 output blocks
++	 pxor	$inout0,$inout0		# clear register bank
++	movups	$inout1,0x10($out)
++	 pxor	$inout1,$inout1
++	movups	$inout2,0x20($out)
++	 pxor	$inout2,$inout2
++	movups	$inout3,0x30($out)
++	 pxor	$inout3,$inout3
++	movups	$inout4,0x40($out)
++	 pxor	$inout4,$inout4
++	movups	$inout5,0x50($out)
++	 pxor	$inout5,$inout5
++
++.Lecb_ret:
++	xorps	$rndkey0,$rndkey0	# %xmm0
++	pxor	$rndkey1,$rndkey1
++___
++$code.=<<___ if ($win64);
++	movaps	(%rsp),%xmm6
++	movaps	%xmm0,(%rsp)		# clear stack
++	movaps	0x10(%rsp),%xmm7
++	movaps	%xmm0,0x10(%rsp)
++	movaps	0x20(%rsp),%xmm8
++	movaps	%xmm0,0x20(%rsp)
++	movaps	0x30(%rsp),%xmm9
++	movaps	%xmm0,0x30(%rsp)
++	lea	0x58(%rsp),%rsp
++.Lecb_enc_ret:
++___
++$code.=<<___;
++	ret
++.size	aesni_ecb_encrypt,.-aesni_ecb_encrypt
++___
++
++{
++######################################################################
++# void aesni_ccm64_[en|de]crypt_blocks (const void *in, void *out,
++#                         size_t blocks, const AES_KEY *key,
++#                         const char *ivec,char *cmac);
++#
++# Handles only complete blocks, operates on 64-bit counter and
++# does not update *ivec! Nor does it finalize CMAC value
++# (see engine/eng_aesni.c for details)
++#
++{
++my $cmac="%r9";	# 6th argument
++
++my $increment="%xmm9";
++my $iv="%xmm6";
++my $bswap_mask="%xmm7";
++
++$code.=<<___;
++.globl	aesni_ccm64_encrypt_blocks
++.type	aesni_ccm64_encrypt_blocks,\@function,6
++.align	16
++aesni_ccm64_encrypt_blocks:
++___
++$code.=<<___ if ($win64);
++	lea	-0x58(%rsp),%rsp
++	movaps	%xmm6,(%rsp)		# $iv
++	movaps	%xmm7,0x10(%rsp)	# $bswap_mask
++	movaps	%xmm8,0x20(%rsp)	# $in0
++	movaps	%xmm9,0x30(%rsp)	# $increment
++.Lccm64_enc_body:
++___
++$code.=<<___;
++	mov	240($key),$rounds		# key->rounds
++	movdqu	($ivp),$iv
++	movdqa	.Lincrement64(%rip),$increment
++	movdqa	.Lbswap_mask(%rip),$bswap_mask
++
++	shl	\$4,$rounds
++	mov	\$16,$rnds_
++	lea	0($key),$key_
++	movdqu	($cmac),$inout1
++	movdqa	$iv,$inout0
++	lea	32($key,$rounds),$key		# end of key schedule
++	pshufb	$bswap_mask,$iv
++	sub	%rax,%r10			# twisted $rounds
++	jmp	.Lccm64_enc_outer
++.align	16
++.Lccm64_enc_outer:
++	$movkey	($key_),$rndkey0
++	mov	%r10,%rax
++	movups	($inp),$in0			# load inp
++
++	xorps	$rndkey0,$inout0		# counter
++	$movkey	16($key_),$rndkey1
++	xorps	$in0,$rndkey0
++	xorps	$rndkey0,$inout1		# cmac^=inp
++	$movkey	32($key_),$rndkey0
++
++.Lccm64_enc2_loop:
++	aesenc	$rndkey1,$inout0
++	aesenc	$rndkey1,$inout1
++	$movkey	($key,%rax),$rndkey1
++	add	\$32,%rax
++	aesenc	$rndkey0,$inout0
++	aesenc	$rndkey0,$inout1
++	$movkey	-16($key,%rax),$rndkey0
++	jnz	.Lccm64_enc2_loop
++	aesenc	$rndkey1,$inout0
++	aesenc	$rndkey1,$inout1
++	paddq	$increment,$iv
++	dec	$len				# $len-- ($len is in blocks)
++	aesenclast	$rndkey0,$inout0
++	aesenclast	$rndkey0,$inout1
++
++	lea	16($inp),$inp
++	xorps	$inout0,$in0			# inp ^= E(iv)
++	movdqa	$iv,$inout0
++	movups	$in0,($out)			# save output
++	pshufb	$bswap_mask,$inout0
++	lea	16($out),$out			# $out+=16
++	jnz	.Lccm64_enc_outer		# loop if ($len!=0)
++
++	 pxor	$rndkey0,$rndkey0		# clear register bank
++	 pxor	$rndkey1,$rndkey1
++	 pxor	$inout0,$inout0
++	movups	$inout1,($cmac)			# store resulting mac
++	 pxor	$inout1,$inout1
++	 pxor	$in0,$in0
++	 pxor	$iv,$iv
++___
++$code.=<<___ if ($win64);
++	movaps	(%rsp),%xmm6
++	movaps	%xmm0,(%rsp)			# clear stack
++	movaps	0x10(%rsp),%xmm7
++	movaps	%xmm0,0x10(%rsp)
++	movaps	0x20(%rsp),%xmm8
++	movaps	%xmm0,0x20(%rsp)
++	movaps	0x30(%rsp),%xmm9
++	movaps	%xmm0,0x30(%rsp)
++	lea	0x58(%rsp),%rsp
++.Lccm64_enc_ret:
++___
++$code.=<<___;
++	ret
++.size	aesni_ccm64_encrypt_blocks,.-aesni_ccm64_encrypt_blocks
++___
++######################################################################
++$code.=<<___;
++.globl	aesni_ccm64_decrypt_blocks
++.type	aesni_ccm64_decrypt_blocks,\@function,6
++.align	16
++aesni_ccm64_decrypt_blocks:
++___
++$code.=<<___ if ($win64);
++	lea	-0x58(%rsp),%rsp
++	movaps	%xmm6,(%rsp)		# $iv
++	movaps	%xmm7,0x10(%rsp)	# $bswap_mask
++	movaps	%xmm8,0x20(%rsp)	# $in8
++	movaps	%xmm9,0x30(%rsp)	# $increment
++.Lccm64_dec_body:
++___
++$code.=<<___;
++	mov	240($key),$rounds		# key->rounds
++	movups	($ivp),$iv
++	movdqu	($cmac),$inout1
++	movdqa	.Lincrement64(%rip),$increment
++	movdqa	.Lbswap_mask(%rip),$bswap_mask
++
++	movaps	$iv,$inout0
++	mov	$rounds,$rnds_
++	mov	$key,$key_
++	pshufb	$bswap_mask,$iv
++___
++	&aesni_generate1("enc",$key,$rounds);
++$code.=<<___;
++	shl	\$4,$rnds_
++	mov	\$16,$rounds
++	movups	($inp),$in0			# load inp
++	paddq	$increment,$iv
++	lea	16($inp),$inp			# $inp+=16
++	sub	%r10,%rax			# twisted $rounds
++	lea	32($key_,$rnds_),$key		# end of key schedule
++	mov	%rax,%r10
++	jmp	.Lccm64_dec_outer
++.align	16
++.Lccm64_dec_outer:
++	xorps	$inout0,$in0			# inp ^= E(iv)
++	movdqa	$iv,$inout0
++	movups	$in0,($out)			# save output
++	lea	16($out),$out			# $out+=16
++	pshufb	$bswap_mask,$inout0
++
++	sub	\$1,$len			# $len-- ($len is in blocks)
++	jz	.Lccm64_dec_break		# if ($len==0) break
++
++	$movkey	($key_),$rndkey0
++	mov	%r10,%rax
++	$movkey	16($key_),$rndkey1
++	xorps	$rndkey0,$in0
++	xorps	$rndkey0,$inout0
++	xorps	$in0,$inout1			# cmac^=out
++	$movkey	32($key_),$rndkey0
++	jmp	.Lccm64_dec2_loop
++.align	16
++.Lccm64_dec2_loop:
++	aesenc	$rndkey1,$inout0
++	aesenc	$rndkey1,$inout1
++	$movkey	($key,%rax),$rndkey1
++	add	\$32,%rax
++	aesenc	$rndkey0,$inout0
++	aesenc	$rndkey0,$inout1
++	$movkey	-16($key,%rax),$rndkey0
++	jnz	.Lccm64_dec2_loop
++	movups	($inp),$in0			# load input
++	paddq	$increment,$iv
++	aesenc	$rndkey1,$inout0
++	aesenc	$rndkey1,$inout1
++	aesenclast	$rndkey0,$inout0
++	aesenclast	$rndkey0,$inout1
++	lea	16($inp),$inp			# $inp+=16
++	jmp	.Lccm64_dec_outer
++
++.align	16
++.Lccm64_dec_break:
++	#xorps	$in0,$inout1			# cmac^=out
++	mov	240($key_),$rounds
++___
++	&aesni_generate1("enc",$key_,$rounds,$inout1,$in0);
++$code.=<<___;
++	 pxor	$rndkey0,$rndkey0		# clear register bank
++	 pxor	$rndkey1,$rndkey1
++	 pxor	$inout0,$inout0
++	movups	$inout1,($cmac)			# store resulting mac
++	 pxor	$inout1,$inout1
++	 pxor	$in0,$in0
++	 pxor	$iv,$iv
++___
++$code.=<<___ if ($win64);
++	movaps	(%rsp),%xmm6
++	movaps	%xmm0,(%rsp)			# clear stack
++	movaps	0x10(%rsp),%xmm7
++	movaps	%xmm0,0x10(%rsp)
++	movaps	0x20(%rsp),%xmm8
++	movaps	%xmm0,0x20(%rsp)
++	movaps	0x30(%rsp),%xmm9
++	movaps	%xmm0,0x30(%rsp)
++	lea	0x58(%rsp),%rsp
++.Lccm64_dec_ret:
++___
++$code.=<<___;
++	ret
++.size	aesni_ccm64_decrypt_blocks,.-aesni_ccm64_decrypt_blocks
++___
++}
++######################################################################
++# void aesni_ctr32_encrypt_blocks (const void *in, void *out,
++#                         size_t blocks, const AES_KEY *key,
++#                         const char *ivec);
++#
++# Handles only complete blocks, operates on 32-bit counter and
++# does not update *ivec! (see crypto/modes/ctr128.c for details)
++#
++# Overhaul based on suggestions from Shay Gueron and Vlad Krasnov,
++# http://rt.openssl.org/Ticket/Display.html?id=3021&user=guest&pass=guest.
++# Keywords are full unroll and modulo-schedule counter calculations
++# with zero-round key xor.
++{
++my ($in0,$in1,$in2,$in3,$in4,$in5)=map("%xmm$_",(10..15));
++my ($key0,$ctr)=("${key_}d","${ivp}d");
++my $frame_size = 0x80 + ($win64?160:0);
++
++$code.=<<___;
++.globl	aesni_ctr32_encrypt_blocks
++.type	aesni_ctr32_encrypt_blocks,\@function,5
++.align	16
++aesni_ctr32_encrypt_blocks:
++	cmp	\$1,$len
++	jne	.Lctr32_bulk
++
++	# handle single block without allocating stack frame,
++	# useful when handling edges
++	movups	($ivp),$inout0
++	movups	($inp),$inout1
++	mov	240($key),%edx			# key->rounds
++___
++	&aesni_generate1("enc",$key,"%edx");
++$code.=<<___;
++	 pxor	$rndkey0,$rndkey0		# clear register bank
++	 pxor	$rndkey1,$rndkey1
++	xorps	$inout1,$inout0
++	 pxor	$inout1,$inout1
++	movups	$inout0,($out)
++	 xorps	$inout0,$inout0
++	jmp	.Lctr32_epilogue
++
++.align	16
++.Lctr32_bulk:
++	lea	(%rsp),%rax
++	push	%rbp
++	sub	\$$frame_size,%rsp
++	and	\$-16,%rsp	# Linux kernel stack can be incorrectly seeded
++___
++$code.=<<___ if ($win64);
++	movaps	%xmm6,-0xa8(%rax)		# offload everything
++	movaps	%xmm7,-0x98(%rax)
++	movaps	%xmm8,-0x88(%rax)
++	movaps	%xmm9,-0x78(%rax)
++	movaps	%xmm10,-0x68(%rax)
++	movaps	%xmm11,-0x58(%rax)
++	movaps	%xmm12,-0x48(%rax)
++	movaps	%xmm13,-0x38(%rax)
++	movaps	%xmm14,-0x28(%rax)
++	movaps	%xmm15,-0x18(%rax)
++.Lctr32_body:
++___
++$code.=<<___;
++	lea	-8(%rax),%rbp
++
++	# 8 16-byte words on top of stack are counter values
++	# xor-ed with zero-round key
++
++	movdqu	($ivp),$inout0
++	movdqu	($key),$rndkey0
++	mov	12($ivp),$ctr			# counter LSB
++	pxor	$rndkey0,$inout0
++	mov	12($key),$key0			# 0-round key LSB
++	movdqa	$inout0,0x00(%rsp)		# populate counter block
++	bswap	$ctr
++	movdqa	$inout0,$inout1
++	movdqa	$inout0,$inout2
++	movdqa	$inout0,$inout3
++	movdqa	$inout0,0x40(%rsp)
++	movdqa	$inout0,0x50(%rsp)
++	movdqa	$inout0,0x60(%rsp)
++	mov	%rdx,%r10			# about to borrow %rdx
++	movdqa	$inout0,0x70(%rsp)
++
++	lea	1($ctr),%rax
++	 lea	2($ctr),%rdx
++	bswap	%eax
++	 bswap	%edx
++	xor	$key0,%eax
++	 xor	$key0,%edx
++	pinsrd	\$3,%eax,$inout1
++	lea	3($ctr),%rax
++	movdqa	$inout1,0x10(%rsp)
++	 pinsrd	\$3,%edx,$inout2
++	bswap	%eax
++	 mov	%r10,%rdx			# restore %rdx
++	 lea	4($ctr),%r10
++	 movdqa	$inout2,0x20(%rsp)
++	xor	$key0,%eax
++	 bswap	%r10d
++	pinsrd	\$3,%eax,$inout3
++	 xor	$key0,%r10d
++	movdqa	$inout3,0x30(%rsp)
++	lea	5($ctr),%r9
++	 mov	%r10d,0x40+12(%rsp)
++	bswap	%r9d
++	 lea	6($ctr),%r10
++	mov	240($key),$rounds		# key->rounds
++	xor	$key0,%r9d
++	 bswap	%r10d
++	mov	%r9d,0x50+12(%rsp)
++	 xor	$key0,%r10d
++	lea	7($ctr),%r9
++	 mov	%r10d,0x60+12(%rsp)
++	bswap	%r9d
++	 mov	OPENSSL_ia32cap_P+4(%rip),%r10d 
++	xor	$key0,%r9d
++	 and	\$`1<<26|1<<22`,%r10d		# isolate XSAVE+MOVBE
++	mov	%r9d,0x70+12(%rsp)
++
++	$movkey	0x10($key),$rndkey1
++
++	movdqa	0x40(%rsp),$inout4
++	movdqa	0x50(%rsp),$inout5
++
++	cmp	\$8,$len		# $len is in blocks
++	jb	.Lctr32_tail		# short input if ($len<8)
++
++	sub	\$6,$len		# $len is biased by -6
++	cmp	\$`1<<22`,%r10d		# check for MOVBE without XSAVE
++	je	.Lctr32_6x		# [which denotes Atom Silvermont]
++
++	lea	0x80($key),$key		# size optimization
++	sub	\$2,$len		# $len is biased by -8
++	jmp	.Lctr32_loop8
++
++.align	16
++.Lctr32_6x:
++	shl	\$4,$rounds
++	mov	\$48,$rnds_
++	bswap	$key0
++	lea	32($key,$rounds),$key	# end of key schedule
++	sub	%rax,%r10		# twisted $rounds
++	jmp	.Lctr32_loop6
++
++.align	16
++.Lctr32_loop6:
++	 add	\$6,$ctr		# next counter value
++	$movkey	-48($key,$rnds_),$rndkey0
++	aesenc	$rndkey1,$inout0
++	 mov	$ctr,%eax
++	 xor	$key0,%eax
++	aesenc	$rndkey1,$inout1
++	 movbe	%eax,`0x00+12`(%rsp)	# store next counter value
++	 lea	1($ctr),%eax
++	aesenc	$rndkey1,$inout2
++	 xor	$key0,%eax
++	 movbe	%eax,`0x10+12`(%rsp)
++	aesenc	$rndkey1,$inout3
++	 lea	2($ctr),%eax
++	 xor	$key0,%eax
++	aesenc	$rndkey1,$inout4
++	 movbe	%eax,`0x20+12`(%rsp)
++	 lea	3($ctr),%eax
++	aesenc	$rndkey1,$inout5
++	$movkey	-32($key,$rnds_),$rndkey1
++	 xor	$key0,%eax
++
++	aesenc	$rndkey0,$inout0
++	 movbe	%eax,`0x30+12`(%rsp)
++	 lea	4($ctr),%eax
++	aesenc	$rndkey0,$inout1
++	 xor	$key0,%eax
++	 movbe	%eax,`0x40+12`(%rsp)
++	aesenc	$rndkey0,$inout2
++	 lea	5($ctr),%eax
++	 xor	$key0,%eax
++	aesenc	$rndkey0,$inout3
++	 movbe	%eax,`0x50+12`(%rsp)
++	 mov	%r10,%rax		# mov	$rnds_,$rounds
++	aesenc	$rndkey0,$inout4
++	aesenc	$rndkey0,$inout5
++	$movkey	-16($key,$rnds_),$rndkey0
++
++	call	.Lenc_loop6
++
++	movdqu	($inp),$inout6		# load 6 input blocks
++	movdqu	0x10($inp),$inout7
++	movdqu	0x20($inp),$in0
++	movdqu	0x30($inp),$in1
++	movdqu	0x40($inp),$in2
++	movdqu	0x50($inp),$in3
++	lea	0x60($inp),$inp		# $inp+=6*16
++	$movkey	-64($key,$rnds_),$rndkey1
++	pxor	$inout0,$inout6		# inp^=E(ctr)
++	movaps	0x00(%rsp),$inout0	# load next counter [xor-ed with 0 round]
++	pxor	$inout1,$inout7
++	movaps	0x10(%rsp),$inout1
++	pxor	$inout2,$in0
++	movaps	0x20(%rsp),$inout2
++	pxor	$inout3,$in1
++	movaps	0x30(%rsp),$inout3
++	pxor	$inout4,$in2
++	movaps	0x40(%rsp),$inout4
++	pxor	$inout5,$in3
++	movaps	0x50(%rsp),$inout5
++	movdqu	$inout6,($out)		# store 6 output blocks
++	movdqu	$inout7,0x10($out)
++	movdqu	$in0,0x20($out)
++	movdqu	$in1,0x30($out)
++	movdqu	$in2,0x40($out)
++	movdqu	$in3,0x50($out)
++	lea	0x60($out),$out		# $out+=6*16
++
++	sub	\$6,$len
++	jnc	.Lctr32_loop6		# loop if $len-=6 didn't borrow
++
++	add	\$6,$len		# restore real remaining $len
++	jz	.Lctr32_done		# done if ($len==0)
++
++	lea	-48($rnds_),$rounds
++	lea	-80($key,$rnds_),$key	# restore $key
++	neg	$rounds
++	shr	\$4,$rounds		# restore $rounds
++	jmp	.Lctr32_tail
++
++.align	32
++.Lctr32_loop8:
++	 add		\$8,$ctr		# next counter value
++	movdqa		0x60(%rsp),$inout6
++	aesenc		$rndkey1,$inout0
++	 mov		$ctr,%r9d
++	movdqa		0x70(%rsp),$inout7
++	aesenc		$rndkey1,$inout1
++	 bswap		%r9d
++	$movkey		0x20-0x80($key),$rndkey0
++	aesenc		$rndkey1,$inout2
++	 xor		$key0,%r9d
++	 nop
++	aesenc		$rndkey1,$inout3
++	 mov		%r9d,0x00+12(%rsp)	# store next counter value
++	 lea		1($ctr),%r9
++	aesenc		$rndkey1,$inout4
++	aesenc		$rndkey1,$inout5
++	aesenc		$rndkey1,$inout6
++	aesenc		$rndkey1,$inout7
++	$movkey		0x30-0x80($key),$rndkey1
++___
++for($i=2;$i<8;$i++) {
++my $rndkeyx = ($i&1)?$rndkey1:$rndkey0;
++$code.=<<___;
++	 bswap		%r9d
++	aesenc		$rndkeyx,$inout0
++	aesenc		$rndkeyx,$inout1
++	 xor		$key0,%r9d
++	 .byte		0x66,0x90
++	aesenc		$rndkeyx,$inout2
++	aesenc		$rndkeyx,$inout3
++	 mov		%r9d,`0x10*($i-1)`+12(%rsp)
++	 lea		$i($ctr),%r9
++	aesenc		$rndkeyx,$inout4
++	aesenc		$rndkeyx,$inout5
++	aesenc		$rndkeyx,$inout6
++	aesenc		$rndkeyx,$inout7
++	$movkey		`0x20+0x10*$i`-0x80($key),$rndkeyx
++___
++}
++$code.=<<___;
++	 bswap		%r9d
++	aesenc		$rndkey0,$inout0
++	aesenc		$rndkey0,$inout1
++	aesenc		$rndkey0,$inout2
++	 xor		$key0,%r9d
++	 movdqu		0x00($inp),$in0		# start loading input
++	aesenc		$rndkey0,$inout3
++	 mov		%r9d,0x70+12(%rsp)
++	 cmp		\$11,$rounds
++	aesenc		$rndkey0,$inout4
++	aesenc		$rndkey0,$inout5
++	aesenc		$rndkey0,$inout6
++	aesenc		$rndkey0,$inout7
++	$movkey		0xa0-0x80($key),$rndkey0
++
++	jb		.Lctr32_enc_done
++
++	aesenc		$rndkey1,$inout0
++	aesenc		$rndkey1,$inout1
++	aesenc		$rndkey1,$inout2
++	aesenc		$rndkey1,$inout3
++	aesenc		$rndkey1,$inout4
++	aesenc		$rndkey1,$inout5
++	aesenc		$rndkey1,$inout6
++	aesenc		$rndkey1,$inout7
++	$movkey		0xb0-0x80($key),$rndkey1
++
++	aesenc		$rndkey0,$inout0
++	aesenc		$rndkey0,$inout1
++	aesenc		$rndkey0,$inout2
++	aesenc		$rndkey0,$inout3
++	aesenc		$rndkey0,$inout4
++	aesenc		$rndkey0,$inout5
++	aesenc		$rndkey0,$inout6
++	aesenc		$rndkey0,$inout7
++	$movkey		0xc0-0x80($key),$rndkey0
++	je		.Lctr32_enc_done
++
++	aesenc		$rndkey1,$inout0
++	aesenc		$rndkey1,$inout1
++	aesenc		$rndkey1,$inout2
++	aesenc		$rndkey1,$inout3
++	aesenc		$rndkey1,$inout4
++	aesenc		$rndkey1,$inout5
++	aesenc		$rndkey1,$inout6
++	aesenc		$rndkey1,$inout7
++	$movkey		0xd0-0x80($key),$rndkey1
++
++	aesenc		$rndkey0,$inout0
++	aesenc		$rndkey0,$inout1
++	aesenc		$rndkey0,$inout2
++	aesenc		$rndkey0,$inout3
++	aesenc		$rndkey0,$inout4
++	aesenc		$rndkey0,$inout5
++	aesenc		$rndkey0,$inout6
++	aesenc		$rndkey0,$inout7
++	$movkey		0xe0-0x80($key),$rndkey0
++	jmp		.Lctr32_enc_done
++
++.align	16
++.Lctr32_enc_done:
++	movdqu		0x10($inp),$in1
++	pxor		$rndkey0,$in0		# input^=round[last]
++	movdqu		0x20($inp),$in2
++	pxor		$rndkey0,$in1
++	movdqu		0x30($inp),$in3
++	pxor		$rndkey0,$in2
++	movdqu		0x40($inp),$in4
++	pxor		$rndkey0,$in3
++	movdqu		0x50($inp),$in5
++	pxor		$rndkey0,$in4
++	pxor		$rndkey0,$in5
++	aesenc		$rndkey1,$inout0
++	aesenc		$rndkey1,$inout1
++	aesenc		$rndkey1,$inout2
++	aesenc		$rndkey1,$inout3
++	aesenc		$rndkey1,$inout4
++	aesenc		$rndkey1,$inout5
++	aesenc		$rndkey1,$inout6
++	aesenc		$rndkey1,$inout7
++	movdqu		0x60($inp),$rndkey1	# borrow $rndkey1 for inp[6]
++	lea		0x80($inp),$inp		# $inp+=8*16
++
++	aesenclast	$in0,$inout0		# $inN is inp[N]^round[last]
++	pxor		$rndkey0,$rndkey1	# borrowed $rndkey
++	movdqu		0x70-0x80($inp),$in0
++	aesenclast	$in1,$inout1
++	pxor		$rndkey0,$in0
++	movdqa		0x00(%rsp),$in1		# load next counter block
++	aesenclast	$in2,$inout2
++	aesenclast	$in3,$inout3
++	movdqa		0x10(%rsp),$in2
++	movdqa		0x20(%rsp),$in3
++	aesenclast	$in4,$inout4
++	aesenclast	$in5,$inout5
++	movdqa		0x30(%rsp),$in4
++	movdqa		0x40(%rsp),$in5
++	aesenclast	$rndkey1,$inout6
++	movdqa		0x50(%rsp),$rndkey0
++	$movkey		0x10-0x80($key),$rndkey1#real 1st-round key
++	aesenclast	$in0,$inout7
++
++	movups		$inout0,($out)		# store 8 output blocks
++	movdqa		$in1,$inout0
++	movups		$inout1,0x10($out)
++	movdqa		$in2,$inout1
++	movups		$inout2,0x20($out)
++	movdqa		$in3,$inout2
++	movups		$inout3,0x30($out)
++	movdqa		$in4,$inout3
++	movups		$inout4,0x40($out)
++	movdqa		$in5,$inout4
++	movups		$inout5,0x50($out)
++	movdqa		$rndkey0,$inout5
++	movups		$inout6,0x60($out)
++	movups		$inout7,0x70($out)
++	lea		0x80($out),$out		# $out+=8*16
++
++	sub	\$8,$len
++	jnc	.Lctr32_loop8			# loop if $len-=8 didn't borrow
++
++	add	\$8,$len			# restore real remainig $len
++	jz	.Lctr32_done			# done if ($len==0)
++	lea	-0x80($key),$key
++
++.Lctr32_tail:
++	# note that at this point $inout0..5 are populated with
++	# counter values xor-ed with 0-round key 
++	lea	16($key),$key
++	cmp	\$4,$len
++	jb	.Lctr32_loop3
++	je	.Lctr32_loop4
++
++	# if ($len>4) compute 7 E(counter)
++	shl		\$4,$rounds
++	movdqa		0x60(%rsp),$inout6
++	pxor		$inout7,$inout7
++
++	$movkey		16($key),$rndkey0
++	aesenc		$rndkey1,$inout0
++	aesenc		$rndkey1,$inout1
++	lea		32-16($key,$rounds),$key# prepare for .Lenc_loop8_enter
++	neg		%rax
++	aesenc		$rndkey1,$inout2
++	add		\$16,%rax		# prepare for .Lenc_loop8_enter
++	 movups		($inp),$in0
++	aesenc		$rndkey1,$inout3
++	aesenc		$rndkey1,$inout4
++	 movups		0x10($inp),$in1		# pre-load input
++	 movups		0x20($inp),$in2
++	aesenc		$rndkey1,$inout5
++	aesenc		$rndkey1,$inout6
++
++	call            .Lenc_loop8_enter
++
++	movdqu	0x30($inp),$in3
++	pxor	$in0,$inout0
++	movdqu	0x40($inp),$in0
++	pxor	$in1,$inout1
++	movdqu	$inout0,($out)			# store output
++	pxor	$in2,$inout2
++	movdqu	$inout1,0x10($out)
++	pxor	$in3,$inout3
++	movdqu	$inout2,0x20($out)
++	pxor	$in0,$inout4
++	movdqu	$inout3,0x30($out)
++	movdqu	$inout4,0x40($out)
++	cmp	\$6,$len
++	jb	.Lctr32_done			# $len was 5, stop store
++
++	movups	0x50($inp),$in1
++	xorps	$in1,$inout5
++	movups	$inout5,0x50($out)
++	je	.Lctr32_done			# $len was 6, stop store
++
++	movups	0x60($inp),$in2
++	xorps	$in2,$inout6
++	movups	$inout6,0x60($out)
++	jmp	.Lctr32_done			# $len was 7, stop store
++
++.align	32
++.Lctr32_loop4:
++	aesenc		$rndkey1,$inout0
++	lea		16($key),$key
++	dec		$rounds
++	aesenc		$rndkey1,$inout1
++	aesenc		$rndkey1,$inout2
++	aesenc		$rndkey1,$inout3
++	$movkey		($key),$rndkey1
++	jnz		.Lctr32_loop4
++	aesenclast	$rndkey1,$inout0
++	aesenclast	$rndkey1,$inout1
++	 movups		($inp),$in0		# load input
++	 movups		0x10($inp),$in1
++	aesenclast	$rndkey1,$inout2
++	aesenclast	$rndkey1,$inout3
++	 movups		0x20($inp),$in2
++	 movups		0x30($inp),$in3
++
++	xorps	$in0,$inout0
++	movups	$inout0,($out)			# store output
++	xorps	$in1,$inout1
++	movups	$inout1,0x10($out)
++	pxor	$in2,$inout2
++	movdqu	$inout2,0x20($out)
++	pxor	$in3,$inout3
++	movdqu	$inout3,0x30($out)
++	jmp	.Lctr32_done			# $len was 4, stop store
++
++.align	32
++.Lctr32_loop3:
++	aesenc		$rndkey1,$inout0
++	lea		16($key),$key
++	dec		$rounds
++	aesenc		$rndkey1,$inout1
++	aesenc		$rndkey1,$inout2
++	$movkey		($key),$rndkey1
++	jnz		.Lctr32_loop3
++	aesenclast	$rndkey1,$inout0
++	aesenclast	$rndkey1,$inout1
++	aesenclast	$rndkey1,$inout2
++
++	movups	($inp),$in0			# load input
++	xorps	$in0,$inout0
++	movups	$inout0,($out)			# store output
++	cmp	\$2,$len
++	jb	.Lctr32_done			# $len was 1, stop store
++
++	movups	0x10($inp),$in1
++	xorps	$in1,$inout1
++	movups	$inout1,0x10($out)
++	je	.Lctr32_done			# $len was 2, stop store
++
++	movups	0x20($inp),$in2
++	xorps	$in2,$inout2
++	movups	$inout2,0x20($out)		# $len was 3, stop store
++
++.Lctr32_done:
++	xorps	%xmm0,%xmm0			# clear regiser bank
++	xor	$key0,$key0
++	pxor	%xmm1,%xmm1
++	pxor	%xmm2,%xmm2
++	pxor	%xmm3,%xmm3
++	pxor	%xmm4,%xmm4
++	pxor	%xmm5,%xmm5
++___
++$code.=<<___ if (!$win64);
++	pxor	%xmm6,%xmm6
++	pxor	%xmm7,%xmm7
++	movaps	%xmm0,0x00(%rsp)		# clear stack
++	pxor	%xmm8,%xmm8
++	movaps	%xmm0,0x10(%rsp)
++	pxor	%xmm9,%xmm9
++	movaps	%xmm0,0x20(%rsp)
++	pxor	%xmm10,%xmm10
++	movaps	%xmm0,0x30(%rsp)
++	pxor	%xmm11,%xmm11
++	movaps	%xmm0,0x40(%rsp)
++	pxor	%xmm12,%xmm12
++	movaps	%xmm0,0x50(%rsp)
++	pxor	%xmm13,%xmm13
++	movaps	%xmm0,0x60(%rsp)
++	pxor	%xmm14,%xmm14
++	movaps	%xmm0,0x70(%rsp)
++	pxor	%xmm15,%xmm15
++___
++$code.=<<___ if ($win64);
++	movaps	-0xa0(%rbp),%xmm6
++	movaps	%xmm0,-0xa0(%rbp)		# clear stack
++	movaps	-0x90(%rbp),%xmm7
++	movaps	%xmm0,-0x90(%rbp)
++	movaps	-0x80(%rbp),%xmm8
++	movaps	%xmm0,-0x80(%rbp)
++	movaps	-0x70(%rbp),%xmm9
++	movaps	%xmm0,-0x70(%rbp)
++	movaps	-0x60(%rbp),%xmm10
++	movaps	%xmm0,-0x60(%rbp)
++	movaps	-0x50(%rbp),%xmm11
++	movaps	%xmm0,-0x50(%rbp)
++	movaps	-0x40(%rbp),%xmm12
++	movaps	%xmm0,-0x40(%rbp)
++	movaps	-0x30(%rbp),%xmm13
++	movaps	%xmm0,-0x30(%rbp)
++	movaps	-0x20(%rbp),%xmm14
++	movaps	%xmm0,-0x20(%rbp)
++	movaps	-0x10(%rbp),%xmm15
++	movaps	%xmm0,-0x10(%rbp)
++	movaps	%xmm0,0x00(%rsp)
++	movaps	%xmm0,0x10(%rsp)
++	movaps	%xmm0,0x20(%rsp)
++	movaps	%xmm0,0x30(%rsp)
++	movaps	%xmm0,0x40(%rsp)
++	movaps	%xmm0,0x50(%rsp)
++	movaps	%xmm0,0x60(%rsp)
++	movaps	%xmm0,0x70(%rsp)
++___
++$code.=<<___;
++	lea	(%rbp),%rsp
++	pop	%rbp
++.Lctr32_epilogue:
++	ret
++.size	aesni_ctr32_encrypt_blocks,.-aesni_ctr32_encrypt_blocks
++___
++}
++
++######################################################################
++# void aesni_xts_[en|de]crypt(const char *inp,char *out,size_t len,
++#	const AES_KEY *key1, const AES_KEY *key2
++#	const unsigned char iv[16]);
++#
++{
++my @tweak=map("%xmm$_",(10..15));
++my ($twmask,$twres,$twtmp)=("%xmm8","%xmm9",@tweak[4]);
++my ($key2,$ivp,$len_)=("%r8","%r9","%r9");
++my $frame_size = 0x70 + ($win64?160:0);
++
++$code.=<<___;
++.globl	aesni_xts_encrypt
++.type	aesni_xts_encrypt,\@function,6
++.align	16
++aesni_xts_encrypt:
++	lea	(%rsp),%rax
++	push	%rbp
++	sub	\$$frame_size,%rsp
++	and	\$-16,%rsp	# Linux kernel stack can be incorrectly seeded
++___
++$code.=<<___ if ($win64);
++	movaps	%xmm6,-0xa8(%rax)		# offload everything
++	movaps	%xmm7,-0x98(%rax)
++	movaps	%xmm8,-0x88(%rax)
++	movaps	%xmm9,-0x78(%rax)
++	movaps	%xmm10,-0x68(%rax)
++	movaps	%xmm11,-0x58(%rax)
++	movaps	%xmm12,-0x48(%rax)
++	movaps	%xmm13,-0x38(%rax)
++	movaps	%xmm14,-0x28(%rax)
++	movaps	%xmm15,-0x18(%rax)
++.Lxts_enc_body:
++___
++$code.=<<___;
++	lea	-8(%rax),%rbp
++	movups	($ivp),$inout0			# load clear-text tweak
++	mov	240(%r8),$rounds		# key2->rounds
++	mov	240($key),$rnds_		# key1->rounds
++___
++	# generate the tweak
++	&aesni_generate1("enc",$key2,$rounds,$inout0);
++$code.=<<___;
++	$movkey	($key),$rndkey0			# zero round key
++	mov	$key,$key_			# backup $key
++	mov	$rnds_,$rounds			# backup $rounds
++	shl	\$4,$rnds_
++	mov	$len,$len_			# backup $len
++	and	\$-16,$len
++
++	$movkey	16($key,$rnds_),$rndkey1	# last round key
++
++	movdqa	.Lxts_magic(%rip),$twmask
++	movdqa	$inout0,@tweak[5]
++	pshufd	\$0x5f,$inout0,$twres
++	pxor	$rndkey0,$rndkey1
++___
++    # alternative tweak calculation algorithm is based on suggestions
++    # by Shay Gueron. psrad doesn't conflict with AES-NI instructions
++    # and should help in the future...
++    for ($i=0;$i<4;$i++) {
++    $code.=<<___;
++	movdqa	$twres,$twtmp
++	paddd	$twres,$twres
++	movdqa	@tweak[5],@tweak[$i]
++	psrad	\$31,$twtmp			# broadcast upper bits
++	paddq	@tweak[5],@tweak[5]
++	pand	$twmask,$twtmp
++	pxor	$rndkey0,@tweak[$i]
++	pxor	$twtmp,@tweak[5]
++___
++    }
++$code.=<<___;
++	movdqa	@tweak[5],@tweak[4]
++	psrad	\$31,$twres
++	paddq	@tweak[5],@tweak[5]
++	pand	$twmask,$twres
++	pxor	$rndkey0,@tweak[4]
++	pxor	$twres,@tweak[5]
++	movaps	$rndkey1,0x60(%rsp)		# save round[0]^round[last]
++
++	sub	\$16*6,$len
++	jc	.Lxts_enc_short			# if $len-=6*16 borrowed
++
++	mov	\$16+96,$rounds
++	lea	32($key_,$rnds_),$key		# end of key schedule
++	sub	%r10,%rax			# twisted $rounds
++	$movkey	16($key_),$rndkey1
++	mov	%rax,%r10			# backup twisted $rounds
++	lea	.Lxts_magic(%rip),%r8
++	jmp	.Lxts_enc_grandloop
++
++.align	32
++.Lxts_enc_grandloop:
++	movdqu	`16*0`($inp),$inout0		# load input
++	movdqa	$rndkey0,$twmask
++	movdqu	`16*1`($inp),$inout1
++	pxor	@tweak[0],$inout0		# input^=tweak^round[0]
++	movdqu	`16*2`($inp),$inout2
++	pxor	@tweak[1],$inout1
++	 aesenc		$rndkey1,$inout0
++	movdqu	`16*3`($inp),$inout3
++	pxor	@tweak[2],$inout2
++	 aesenc		$rndkey1,$inout1
++	movdqu	`16*4`($inp),$inout4
++	pxor	@tweak[3],$inout3
++	 aesenc		$rndkey1,$inout2
++	movdqu	`16*5`($inp),$inout5
++	pxor	@tweak[5],$twmask		# round[0]^=tweak[5]
++	 movdqa	0x60(%rsp),$twres		# load round[0]^round[last]
++	pxor	@tweak[4],$inout4
++	 aesenc		$rndkey1,$inout3
++	$movkey	32($key_),$rndkey0
++	lea	`16*6`($inp),$inp
++	pxor	$twmask,$inout5
++
++	 pxor	$twres,@tweak[0]		# calclulate tweaks^round[last]
++	aesenc		$rndkey1,$inout4
++	 pxor	$twres,@tweak[1]
++	 movdqa	@tweak[0],`16*0`(%rsp)		# put aside tweaks^round[last]
++	aesenc		$rndkey1,$inout5
++	$movkey		48($key_),$rndkey1
++	 pxor	$twres,@tweak[2]
++
++	aesenc		$rndkey0,$inout0
++	 pxor	$twres,@tweak[3]
++	 movdqa	@tweak[1],`16*1`(%rsp)
++	aesenc		$rndkey0,$inout1
++	 pxor	$twres,@tweak[4]
++	 movdqa	@tweak[2],`16*2`(%rsp)
++	aesenc		$rndkey0,$inout2
++	aesenc		$rndkey0,$inout3
++	 pxor	$twres,$twmask
++	 movdqa	@tweak[4],`16*4`(%rsp)
++	aesenc		$rndkey0,$inout4
++	aesenc		$rndkey0,$inout5
++	$movkey		64($key_),$rndkey0
++	 movdqa	$twmask,`16*5`(%rsp)
++	pshufd	\$0x5f,@tweak[5],$twres
++	jmp	.Lxts_enc_loop6
++.align	32
++.Lxts_enc_loop6:
++	aesenc		$rndkey1,$inout0
++	aesenc		$rndkey1,$inout1
++	aesenc		$rndkey1,$inout2
++	aesenc		$rndkey1,$inout3
++	aesenc		$rndkey1,$inout4
++	aesenc		$rndkey1,$inout5
++	$movkey		-64($key,%rax),$rndkey1
++	add		\$32,%rax
++
++	aesenc		$rndkey0,$inout0
++	aesenc		$rndkey0,$inout1
++	aesenc		$rndkey0,$inout2
++	aesenc		$rndkey0,$inout3
++	aesenc		$rndkey0,$inout4
++	aesenc		$rndkey0,$inout5
++	$movkey		-80($key,%rax),$rndkey0
++	jnz		.Lxts_enc_loop6
++
++	movdqa	(%r8),$twmask			# start calculating next tweak
++	movdqa	$twres,$twtmp
++	paddd	$twres,$twres
++	 aesenc		$rndkey1,$inout0
++	paddq	@tweak[5],@tweak[5]
++	psrad	\$31,$twtmp
++	 aesenc		$rndkey1,$inout1
++	pand	$twmask,$twtmp
++	$movkey	($key_),@tweak[0]		# load round[0]
++	 aesenc		$rndkey1,$inout2
++	 aesenc		$rndkey1,$inout3
++	 aesenc		$rndkey1,$inout4
++	pxor	$twtmp,@tweak[5]
++	movaps	@tweak[0],@tweak[1]		# copy round[0]
++	 aesenc		$rndkey1,$inout5
++	 $movkey	-64($key),$rndkey1
++
++	movdqa	$twres,$twtmp
++	 aesenc		$rndkey0,$inout0
++	paddd	$twres,$twres
++	pxor	@tweak[5],@tweak[0]
++	 aesenc		$rndkey0,$inout1
++	psrad	\$31,$twtmp
++	paddq	@tweak[5],@tweak[5]
++	 aesenc		$rndkey0,$inout2
++	 aesenc		$rndkey0,$inout3
++	pand	$twmask,$twtmp
++	movaps	@tweak[1],@tweak[2]
++	 aesenc		$rndkey0,$inout4
++	pxor	$twtmp,@tweak[5]
++	movdqa	$twres,$twtmp
++	 aesenc		$rndkey0,$inout5
++	 $movkey	-48($key),$rndkey0
++
++	paddd	$twres,$twres
++	 aesenc		$rndkey1,$inout0
++	pxor	@tweak[5],@tweak[1]
++	psrad	\$31,$twtmp
++	 aesenc		$rndkey1,$inout1
++	paddq	@tweak[5],@tweak[5]
++	pand	$twmask,$twtmp
++	 aesenc		$rndkey1,$inout2
++	 aesenc		$rndkey1,$inout3
++	 movdqa	@tweak[3],`16*3`(%rsp)
++	pxor	$twtmp,@tweak[5]
++	 aesenc		$rndkey1,$inout4
++	movaps	@tweak[2],@tweak[3]
++	movdqa	$twres,$twtmp
++	 aesenc		$rndkey1,$inout5
++	 $movkey	-32($key),$rndkey1
++
++	paddd	$twres,$twres
++	 aesenc		$rndkey0,$inout0
++	pxor	@tweak[5],@tweak[2]
++	psrad	\$31,$twtmp
++	 aesenc		$rndkey0,$inout1
++	paddq	@tweak[5],@tweak[5]
++	pand	$twmask,$twtmp
++	 aesenc		$rndkey0,$inout2
++	 aesenc		$rndkey0,$inout3
++	 aesenc		$rndkey0,$inout4
++	pxor	$twtmp,@tweak[5]
++	movaps	@tweak[3],@tweak[4]
++	 aesenc		$rndkey0,$inout5
++
++	movdqa	$twres,$rndkey0
++	paddd	$twres,$twres
++	 aesenc		$rndkey1,$inout0
++	pxor	@tweak[5],@tweak[3]
++	psrad	\$31,$rndkey0
++	 aesenc		$rndkey1,$inout1
++	paddq	@tweak[5],@tweak[5]
++	pand	$twmask,$rndkey0
++	 aesenc		$rndkey1,$inout2
++	 aesenc		$rndkey1,$inout3
++	pxor	$rndkey0,@tweak[5]
++	$movkey		($key_),$rndkey0
++	 aesenc		$rndkey1,$inout4
++	 aesenc		$rndkey1,$inout5
++	$movkey		16($key_),$rndkey1
++
++	pxor	@tweak[5],@tweak[4]
++	 aesenclast	`16*0`(%rsp),$inout0
++	psrad	\$31,$twres
++	paddq	@tweak[5],@tweak[5]
++	 aesenclast	`16*1`(%rsp),$inout1
++	 aesenclast	`16*2`(%rsp),$inout2
++	pand	$twmask,$twres
++	mov	%r10,%rax			# restore $rounds
++	 aesenclast	`16*3`(%rsp),$inout3
++	 aesenclast	`16*4`(%rsp),$inout4
++	 aesenclast	`16*5`(%rsp),$inout5
++	pxor	$twres,@tweak[5]
++
++	lea	`16*6`($out),$out		# $out+=6*16
++	movups	$inout0,`-16*6`($out)		# store 6 output blocks
++	movups	$inout1,`-16*5`($out)
++	movups	$inout2,`-16*4`($out)
++	movups	$inout3,`-16*3`($out)
++	movups	$inout4,`-16*2`($out)
++	movups	$inout5,`-16*1`($out)
++	sub	\$16*6,$len
++	jnc	.Lxts_enc_grandloop		# loop if $len-=6*16 didn't borrow
++
++	mov	\$16+96,$rounds
++	sub	$rnds_,$rounds
++	mov	$key_,$key			# restore $key
++	shr	\$4,$rounds			# restore original value
++
++.Lxts_enc_short:
++	# at the point @tweak[0..5] are populated with tweak values
++	mov	$rounds,$rnds_			# backup $rounds
++	pxor	$rndkey0,@tweak[0]
++	add	\$16*6,$len			# restore real remaining $len
++	jz	.Lxts_enc_done			# done if ($len==0)
++
++	pxor	$rndkey0,@tweak[1]
++	cmp	\$0x20,$len
++	jb	.Lxts_enc_one			# $len is 1*16
++	pxor	$rndkey0,@tweak[2]
++	je	.Lxts_enc_two			# $len is 2*16
++
++	pxor	$rndkey0,@tweak[3]
++	cmp	\$0x40,$len
++	jb	.Lxts_enc_three			# $len is 3*16
++	pxor	$rndkey0,@tweak[4]
++	je	.Lxts_enc_four			# $len is 4*16
++
++	movdqu	($inp),$inout0			# $len is 5*16
++	movdqu	16*1($inp),$inout1
++	movdqu	16*2($inp),$inout2
++	pxor	@tweak[0],$inout0
++	movdqu	16*3($inp),$inout3
++	pxor	@tweak[1],$inout1
++	movdqu	16*4($inp),$inout4
++	lea	16*5($inp),$inp			# $inp+=5*16
++	pxor	@tweak[2],$inout2
++	pxor	@tweak[3],$inout3
++	pxor	@tweak[4],$inout4
++	pxor	$inout5,$inout5
++
++	call	_aesni_encrypt6
++
++	xorps	@tweak[0],$inout0
++	movdqa	@tweak[5],@tweak[0]
++	xorps	@tweak[1],$inout1
++	xorps	@tweak[2],$inout2
++	movdqu	$inout0,($out)			# store 5 output blocks
++	xorps	@tweak[3],$inout3
++	movdqu	$inout1,16*1($out)
++	xorps	@tweak[4],$inout4
++	movdqu	$inout2,16*2($out)
++	movdqu	$inout3,16*3($out)
++	movdqu	$inout4,16*4($out)
++	lea	16*5($out),$out			# $out+=5*16
++	jmp	.Lxts_enc_done
++
++.align	16
++.Lxts_enc_one:
++	movups	($inp),$inout0
++	lea	16*1($inp),$inp			# inp+=1*16
++	xorps	@tweak[0],$inout0
++___
++	&aesni_generate1("enc",$key,$rounds);
++$code.=<<___;
++	xorps	@tweak[0],$inout0
++	movdqa	@tweak[1],@tweak[0]
++	movups	$inout0,($out)			# store one output block
++	lea	16*1($out),$out			# $out+=1*16
++	jmp	.Lxts_enc_done
++
++.align	16
++.Lxts_enc_two:
++	movups	($inp),$inout0
++	movups	16($inp),$inout1
++	lea	32($inp),$inp			# $inp+=2*16
++	xorps	@tweak[0],$inout0
++	xorps	@tweak[1],$inout1
++
++	call	_aesni_encrypt2
++
++	xorps	@tweak[0],$inout0
++	movdqa	@tweak[2],@tweak[0]
++	xorps	@tweak[1],$inout1
++	movups	$inout0,($out)			# store 2 output blocks
++	movups	$inout1,16*1($out)
++	lea	16*2($out),$out			# $out+=2*16
++	jmp	.Lxts_enc_done
++
++.align	16
++.Lxts_enc_three:
++	movups	($inp),$inout0
++	movups	16*1($inp),$inout1
++	movups	16*2($inp),$inout2
++	lea	16*3($inp),$inp			# $inp+=3*16
++	xorps	@tweak[0],$inout0
++	xorps	@tweak[1],$inout1
++	xorps	@tweak[2],$inout2
++
++	call	_aesni_encrypt3
++
++	xorps	@tweak[0],$inout0
++	movdqa	@tweak[3],@tweak[0]
++	xorps	@tweak[1],$inout1
++	xorps	@tweak[2],$inout2
++	movups	$inout0,($out)			# store 3 output blocks
++	movups	$inout1,16*1($out)
++	movups	$inout2,16*2($out)
++	lea	16*3($out),$out			# $out+=3*16
++	jmp	.Lxts_enc_done
++
++.align	16
++.Lxts_enc_four:
++	movups	($inp),$inout0
++	movups	16*1($inp),$inout1
++	movups	16*2($inp),$inout2
++	xorps	@tweak[0],$inout0
++	movups	16*3($inp),$inout3
++	lea	16*4($inp),$inp			# $inp+=4*16
++	xorps	@tweak[1],$inout1
++	xorps	@tweak[2],$inout2
++	xorps	@tweak[3],$inout3
++
++	call	_aesni_encrypt4
++
++	pxor	@tweak[0],$inout0
++	movdqa	@tweak[4],@tweak[0]
++	pxor	@tweak[1],$inout1
++	pxor	@tweak[2],$inout2
++	movdqu	$inout0,($out)			# store 4 output blocks
++	pxor	@tweak[3],$inout3
++	movdqu	$inout1,16*1($out)
++	movdqu	$inout2,16*2($out)
++	movdqu	$inout3,16*3($out)
++	lea	16*4($out),$out			# $out+=4*16
++	jmp	.Lxts_enc_done
++
++.align	16
++.Lxts_enc_done:
++	and	\$15,$len_			# see if $len%16 is 0
++	jz	.Lxts_enc_ret
++	mov	$len_,$len
++
++.Lxts_enc_steal:
++	movzb	($inp),%eax			# borrow $rounds ...
++	movzb	-16($out),%ecx			# ... and $key
++	lea	1($inp),$inp
++	mov	%al,-16($out)
++	mov	%cl,0($out)
++	lea	1($out),$out
++	sub	\$1,$len
++	jnz	.Lxts_enc_steal
++
++	sub	$len_,$out			# rewind $out
++	mov	$key_,$key			# restore $key
++	mov	$rnds_,$rounds			# restore $rounds
++
++	movups	-16($out),$inout0
++	xorps	@tweak[0],$inout0
++___
++	&aesni_generate1("enc",$key,$rounds);
++$code.=<<___;
++	xorps	@tweak[0],$inout0
++	movups	$inout0,-16($out)
++
++.Lxts_enc_ret:
++	xorps	%xmm0,%xmm0			# clear register bank
++	pxor	%xmm1,%xmm1
++	pxor	%xmm2,%xmm2
++	pxor	%xmm3,%xmm3
++	pxor	%xmm4,%xmm4
++	pxor	%xmm5,%xmm5
++___
++$code.=<<___ if (!$win64);
++	pxor	%xmm6,%xmm6
++	pxor	%xmm7,%xmm7
++	movaps	%xmm0,0x00(%rsp)		# clear stack
++	pxor	%xmm8,%xmm8
++	movaps	%xmm0,0x10(%rsp)
++	pxor	%xmm9,%xmm9
++	movaps	%xmm0,0x20(%rsp)
++	pxor	%xmm10,%xmm10
++	movaps	%xmm0,0x30(%rsp)
++	pxor	%xmm11,%xmm11
++	movaps	%xmm0,0x40(%rsp)
++	pxor	%xmm12,%xmm12
++	movaps	%xmm0,0x50(%rsp)
++	pxor	%xmm13,%xmm13
++	movaps	%xmm0,0x60(%rsp)
++	pxor	%xmm14,%xmm14
++	pxor	%xmm15,%xmm15
++___
++$code.=<<___ if ($win64);
++	movaps	-0xa0(%rbp),%xmm6
++	movaps	%xmm0,-0xa0(%rbp)		# clear stack
++	movaps	-0x90(%rbp),%xmm7
++	movaps	%xmm0,-0x90(%rbp)
++	movaps	-0x80(%rbp),%xmm8
++	movaps	%xmm0,-0x80(%rbp)
++	movaps	-0x70(%rbp),%xmm9
++	movaps	%xmm0,-0x70(%rbp)
++	movaps	-0x60(%rbp),%xmm10
++	movaps	%xmm0,-0x60(%rbp)
++	movaps	-0x50(%rbp),%xmm11
++	movaps	%xmm0,-0x50(%rbp)
++	movaps	-0x40(%rbp),%xmm12
++	movaps	%xmm0,-0x40(%rbp)
++	movaps	-0x30(%rbp),%xmm13
++	movaps	%xmm0,-0x30(%rbp)
++	movaps	-0x20(%rbp),%xmm14
++	movaps	%xmm0,-0x20(%rbp)
++	movaps	-0x10(%rbp),%xmm15
++	movaps	%xmm0,-0x10(%rbp)
++	movaps	%xmm0,0x00(%rsp)
++	movaps	%xmm0,0x10(%rsp)
++	movaps	%xmm0,0x20(%rsp)
++	movaps	%xmm0,0x30(%rsp)
++	movaps	%xmm0,0x40(%rsp)
++	movaps	%xmm0,0x50(%rsp)
++	movaps	%xmm0,0x60(%rsp)
++___
++$code.=<<___;
++	lea	(%rbp),%rsp
++	pop	%rbp
++.Lxts_enc_epilogue:
++	ret
++.size	aesni_xts_encrypt,.-aesni_xts_encrypt
++___
++
++$code.=<<___;
++.globl	aesni_xts_decrypt
++.type	aesni_xts_decrypt,\@function,6
++.align	16
++aesni_xts_decrypt:
++	lea	(%rsp),%rax
++	push	%rbp
++	sub	\$$frame_size,%rsp
++	and	\$-16,%rsp	# Linux kernel stack can be incorrectly seeded
++___
++$code.=<<___ if ($win64);
++	movaps	%xmm6,-0xa8(%rax)		# offload everything
++	movaps	%xmm7,-0x98(%rax)
++	movaps	%xmm8,-0x88(%rax)
++	movaps	%xmm9,-0x78(%rax)
++	movaps	%xmm10,-0x68(%rax)
++	movaps	%xmm11,-0x58(%rax)
++	movaps	%xmm12,-0x48(%rax)
++	movaps	%xmm13,-0x38(%rax)
++	movaps	%xmm14,-0x28(%rax)
++	movaps	%xmm15,-0x18(%rax)
++.Lxts_dec_body:
++___
++$code.=<<___;
++	lea	-8(%rax),%rbp
++	movups	($ivp),$inout0			# load clear-text tweak
++	mov	240($key2),$rounds		# key2->rounds
++	mov	240($key),$rnds_		# key1->rounds
++___
++	# generate the tweak
++	&aesni_generate1("enc",$key2,$rounds,$inout0);
++$code.=<<___;
++	xor	%eax,%eax			# if ($len%16) len-=16;
++	test	\$15,$len
++	setnz	%al
++	shl	\$4,%rax
++	sub	%rax,$len
++
++	$movkey	($key),$rndkey0			# zero round key
++	mov	$key,$key_			# backup $key
++	mov	$rnds_,$rounds			# backup $rounds
++	shl	\$4,$rnds_
++	mov	$len,$len_			# backup $len
++	and	\$-16,$len
++
++	$movkey	16($key,$rnds_),$rndkey1	# last round key
++
++	movdqa	.Lxts_magic(%rip),$twmask
++	movdqa	$inout0,@tweak[5]
++	pshufd	\$0x5f,$inout0,$twres
++	pxor	$rndkey0,$rndkey1
++___
++    for ($i=0;$i<4;$i++) {
++    $code.=<<___;
++	movdqa	$twres,$twtmp
++	paddd	$twres,$twres
++	movdqa	@tweak[5],@tweak[$i]
++	psrad	\$31,$twtmp			# broadcast upper bits
++	paddq	@tweak[5],@tweak[5]
++	pand	$twmask,$twtmp
++	pxor	$rndkey0,@tweak[$i]
++	pxor	$twtmp,@tweak[5]
++___
++    }
++$code.=<<___;
++	movdqa	@tweak[5],@tweak[4]
++	psrad	\$31,$twres
++	paddq	@tweak[5],@tweak[5]
++	pand	$twmask,$twres
++	pxor	$rndkey0,@tweak[4]
++	pxor	$twres,@tweak[5]
++	movaps	$rndkey1,0x60(%rsp)		# save round[0]^round[last]
++
++	sub	\$16*6,$len
++	jc	.Lxts_dec_short			# if $len-=6*16 borrowed
++
++	mov	\$16+96,$rounds
++	lea	32($key_,$rnds_),$key		# end of key schedule
++	sub	%r10,%rax			# twisted $rounds
++	$movkey	16($key_),$rndkey1
++	mov	%rax,%r10			# backup twisted $rounds
++	lea	.Lxts_magic(%rip),%r8
++	jmp	.Lxts_dec_grandloop
++
++.align	32
++.Lxts_dec_grandloop:
++	movdqu	`16*0`($inp),$inout0		# load input
++	movdqa	$rndkey0,$twmask
++	movdqu	`16*1`($inp),$inout1
++	pxor	@tweak[0],$inout0		# intput^=tweak^round[0]
++	movdqu	`16*2`($inp),$inout2
++	pxor	@tweak[1],$inout1
++	 aesdec		$rndkey1,$inout0
++	movdqu	`16*3`($inp),$inout3
++	pxor	@tweak[2],$inout2
++	 aesdec		$rndkey1,$inout1
++	movdqu	`16*4`($inp),$inout4
++	pxor	@tweak[3],$inout3
++	 aesdec		$rndkey1,$inout2
++	movdqu	`16*5`($inp),$inout5
++	pxor	@tweak[5],$twmask		# round[0]^=tweak[5]
++	 movdqa	0x60(%rsp),$twres		# load round[0]^round[last]
++	pxor	@tweak[4],$inout4
++	 aesdec		$rndkey1,$inout3
++	$movkey	32($key_),$rndkey0
++	lea	`16*6`($inp),$inp
++	pxor	$twmask,$inout5
++
++	 pxor	$twres,@tweak[0]		# calclulate tweaks^round[last]
++	aesdec		$rndkey1,$inout4
++	 pxor	$twres,@tweak[1]
++	 movdqa	@tweak[0],`16*0`(%rsp)		# put aside tweaks^last round key
++	aesdec		$rndkey1,$inout5
++	$movkey		48($key_),$rndkey1
++	 pxor	$twres,@tweak[2]
++
++	aesdec		$rndkey0,$inout0
++	 pxor	$twres,@tweak[3]
++	 movdqa	@tweak[1],`16*1`(%rsp)
++	aesdec		$rndkey0,$inout1
++	 pxor	$twres,@tweak[4]
++	 movdqa	@tweak[2],`16*2`(%rsp)
++	aesdec		$rndkey0,$inout2
++	aesdec		$rndkey0,$inout3
++	 pxor	$twres,$twmask
++	 movdqa	@tweak[4],`16*4`(%rsp)
++	aesdec		$rndkey0,$inout4
++	aesdec		$rndkey0,$inout5
++	$movkey		64($key_),$rndkey0
++	 movdqa	$twmask,`16*5`(%rsp)
++	pshufd	\$0x5f,@tweak[5],$twres
++	jmp	.Lxts_dec_loop6
++.align	32
++.Lxts_dec_loop6:
++	aesdec		$rndkey1,$inout0
++	aesdec		$rndkey1,$inout1
++	aesdec		$rndkey1,$inout2
++	aesdec		$rndkey1,$inout3
++	aesdec		$rndkey1,$inout4
++	aesdec		$rndkey1,$inout5
++	$movkey		-64($key,%rax),$rndkey1
++	add		\$32,%rax
++
++	aesdec		$rndkey0,$inout0
++	aesdec		$rndkey0,$inout1
++	aesdec		$rndkey0,$inout2
++	aesdec		$rndkey0,$inout3
++	aesdec		$rndkey0,$inout4
++	aesdec		$rndkey0,$inout5
++	$movkey		-80($key,%rax),$rndkey0
++	jnz		.Lxts_dec_loop6
++
++	movdqa	(%r8),$twmask			# start calculating next tweak
++	movdqa	$twres,$twtmp
++	paddd	$twres,$twres
++	 aesdec		$rndkey1,$inout0
++	paddq	@tweak[5],@tweak[5]
++	psrad	\$31,$twtmp
++	 aesdec		$rndkey1,$inout1
++	pand	$twmask,$twtmp
++	$movkey	($key_),@tweak[0]		# load round[0]
++	 aesdec		$rndkey1,$inout2
++	 aesdec		$rndkey1,$inout3
++	 aesdec		$rndkey1,$inout4
++	pxor	$twtmp,@tweak[5]
++	movaps	@tweak[0],@tweak[1]		# copy round[0]
++	 aesdec		$rndkey1,$inout5
++	 $movkey	-64($key),$rndkey1
++
++	movdqa	$twres,$twtmp
++	 aesdec		$rndkey0,$inout0
++	paddd	$twres,$twres
++	pxor	@tweak[5],@tweak[0]
++	 aesdec		$rndkey0,$inout1
++	psrad	\$31,$twtmp
++	paddq	@tweak[5],@tweak[5]
++	 aesdec		$rndkey0,$inout2
++	 aesdec		$rndkey0,$inout3
++	pand	$twmask,$twtmp
++	movaps	@tweak[1],@tweak[2]
++	 aesdec		$rndkey0,$inout4
++	pxor	$twtmp,@tweak[5]
++	movdqa	$twres,$twtmp
++	 aesdec		$rndkey0,$inout5
++	 $movkey	-48($key),$rndkey0
++
++	paddd	$twres,$twres
++	 aesdec		$rndkey1,$inout0
++	pxor	@tweak[5],@tweak[1]
++	psrad	\$31,$twtmp
++	 aesdec		$rndkey1,$inout1
++	paddq	@tweak[5],@tweak[5]
++	pand	$twmask,$twtmp
++	 aesdec		$rndkey1,$inout2
++	 aesdec		$rndkey1,$inout3
++	 movdqa	@tweak[3],`16*3`(%rsp)
++	pxor	$twtmp,@tweak[5]
++	 aesdec		$rndkey1,$inout4
++	movaps	@tweak[2],@tweak[3]
++	movdqa	$twres,$twtmp
++	 aesdec		$rndkey1,$inout5
++	 $movkey	-32($key),$rndkey1
++
++	paddd	$twres,$twres
++	 aesdec		$rndkey0,$inout0
++	pxor	@tweak[5],@tweak[2]
++	psrad	\$31,$twtmp
++	 aesdec		$rndkey0,$inout1
++	paddq	@tweak[5],@tweak[5]
++	pand	$twmask,$twtmp
++	 aesdec		$rndkey0,$inout2
++	 aesdec		$rndkey0,$inout3
++	 aesdec		$rndkey0,$inout4
++	pxor	$twtmp,@tweak[5]
++	movaps	@tweak[3],@tweak[4]
++	 aesdec		$rndkey0,$inout5
++
++	movdqa	$twres,$rndkey0
++	paddd	$twres,$twres
++	 aesdec		$rndkey1,$inout0
++	pxor	@tweak[5],@tweak[3]
++	psrad	\$31,$rndkey0
++	 aesdec		$rndkey1,$inout1
++	paddq	@tweak[5],@tweak[5]
++	pand	$twmask,$rndkey0
++	 aesdec		$rndkey1,$inout2
++	 aesdec		$rndkey1,$inout3
++	pxor	$rndkey0,@tweak[5]
++	$movkey		($key_),$rndkey0
++	 aesdec		$rndkey1,$inout4
++	 aesdec		$rndkey1,$inout5
++	$movkey		16($key_),$rndkey1
++
++	pxor	@tweak[5],@tweak[4]
++	 aesdeclast	`16*0`(%rsp),$inout0
++	psrad	\$31,$twres
++	paddq	@tweak[5],@tweak[5]
++	 aesdeclast	`16*1`(%rsp),$inout1
++	 aesdeclast	`16*2`(%rsp),$inout2
++	pand	$twmask,$twres
++	mov	%r10,%rax			# restore $rounds
++	 aesdeclast	`16*3`(%rsp),$inout3
++	 aesdeclast	`16*4`(%rsp),$inout4
++	 aesdeclast	`16*5`(%rsp),$inout5
++	pxor	$twres,@tweak[5]
++
++	lea	`16*6`($out),$out		# $out+=6*16
++	movups	$inout0,`-16*6`($out)		# store 6 output blocks
++	movups	$inout1,`-16*5`($out)
++	movups	$inout2,`-16*4`($out)
++	movups	$inout3,`-16*3`($out)
++	movups	$inout4,`-16*2`($out)
++	movups	$inout5,`-16*1`($out)
++	sub	\$16*6,$len
++	jnc	.Lxts_dec_grandloop		# loop if $len-=6*16 didn't borrow
++
++	mov	\$16+96,$rounds
++	sub	$rnds_,$rounds
++	mov	$key_,$key			# restore $key
++	shr	\$4,$rounds			# restore original value
++
++.Lxts_dec_short:
++	# at the point @tweak[0..5] are populated with tweak values
++	mov	$rounds,$rnds_			# backup $rounds
++	pxor	$rndkey0,@tweak[0]
++	pxor	$rndkey0,@tweak[1]
++	add	\$16*6,$len			# restore real remaining $len
++	jz	.Lxts_dec_done			# done if ($len==0)
++
++	pxor	$rndkey0,@tweak[2]
++	cmp	\$0x20,$len
++	jb	.Lxts_dec_one			# $len is 1*16
++	pxor	$rndkey0,@tweak[3]
++	je	.Lxts_dec_two			# $len is 2*16
++
++	pxor	$rndkey0,@tweak[4]
++	cmp	\$0x40,$len
++	jb	.Lxts_dec_three			# $len is 3*16
++	je	.Lxts_dec_four			# $len is 4*16
++
++	movdqu	($inp),$inout0			# $len is 5*16
++	movdqu	16*1($inp),$inout1
++	movdqu	16*2($inp),$inout2
++	pxor	@tweak[0],$inout0
++	movdqu	16*3($inp),$inout3
++	pxor	@tweak[1],$inout1
++	movdqu	16*4($inp),$inout4
++	lea	16*5($inp),$inp			# $inp+=5*16
++	pxor	@tweak[2],$inout2
++	pxor	@tweak[3],$inout3
++	pxor	@tweak[4],$inout4
++
++	call	_aesni_decrypt6
++
++	xorps	@tweak[0],$inout0
++	xorps	@tweak[1],$inout1
++	xorps	@tweak[2],$inout2
++	movdqu	$inout0,($out)			# store 5 output blocks
++	xorps	@tweak[3],$inout3
++	movdqu	$inout1,16*1($out)
++	xorps	@tweak[4],$inout4
++	movdqu	$inout2,16*2($out)
++	 pxor		$twtmp,$twtmp
++	movdqu	$inout3,16*3($out)
++	 pcmpgtd	@tweak[5],$twtmp
++	movdqu	$inout4,16*4($out)
++	lea	16*5($out),$out			# $out+=5*16
++	 pshufd		\$0x13,$twtmp,@tweak[1]	# $twres
++	and	\$15,$len_
++	jz	.Lxts_dec_ret
++
++	movdqa	@tweak[5],@tweak[0]
++	paddq	@tweak[5],@tweak[5]		# psllq 1,$tweak
++	pand	$twmask,@tweak[1]		# isolate carry and residue
++	pxor	@tweak[5],@tweak[1]
++	jmp	.Lxts_dec_done2
++
++.align	16
++.Lxts_dec_one:
++	movups	($inp),$inout0
++	lea	16*1($inp),$inp			# $inp+=1*16
++	xorps	@tweak[0],$inout0
++___
++	&aesni_generate1("dec",$key,$rounds);
++$code.=<<___;
++	xorps	@tweak[0],$inout0
++	movdqa	@tweak[1],@tweak[0]
++	movups	$inout0,($out)			# store one output block
++	movdqa	@tweak[2],@tweak[1]
++	lea	16*1($out),$out			# $out+=1*16
++	jmp	.Lxts_dec_done
++
++.align	16
++.Lxts_dec_two:
++	movups	($inp),$inout0
++	movups	16($inp),$inout1
++	lea	32($inp),$inp			# $inp+=2*16
++	xorps	@tweak[0],$inout0
++	xorps	@tweak[1],$inout1
++
++	call	_aesni_decrypt2
++
++	xorps	@tweak[0],$inout0
++	movdqa	@tweak[2],@tweak[0]
++	xorps	@tweak[1],$inout1
++	movdqa	@tweak[3],@tweak[1]
++	movups	$inout0,($out)			# store 2 output blocks
++	movups	$inout1,16*1($out)
++	lea	16*2($out),$out			# $out+=2*16
++	jmp	.Lxts_dec_done
++
++.align	16
++.Lxts_dec_three:
++	movups	($inp),$inout0
++	movups	16*1($inp),$inout1
++	movups	16*2($inp),$inout2
++	lea	16*3($inp),$inp			# $inp+=3*16
++	xorps	@tweak[0],$inout0
++	xorps	@tweak[1],$inout1
++	xorps	@tweak[2],$inout2
++
++	call	_aesni_decrypt3
++
++	xorps	@tweak[0],$inout0
++	movdqa	@tweak[3],@tweak[0]
++	xorps	@tweak[1],$inout1
++	movdqa	@tweak[4],@tweak[1]
++	xorps	@tweak[2],$inout2
++	movups	$inout0,($out)			# store 3 output blocks
++	movups	$inout1,16*1($out)
++	movups	$inout2,16*2($out)
++	lea	16*3($out),$out			# $out+=3*16
++	jmp	.Lxts_dec_done
++
++.align	16
++.Lxts_dec_four:
++	movups	($inp),$inout0
++	movups	16*1($inp),$inout1
++	movups	16*2($inp),$inout2
++	xorps	@tweak[0],$inout0
++	movups	16*3($inp),$inout3
++	lea	16*4($inp),$inp			# $inp+=4*16
++	xorps	@tweak[1],$inout1
++	xorps	@tweak[2],$inout2
++	xorps	@tweak[3],$inout3
++
++	call	_aesni_decrypt4
++
++	pxor	@tweak[0],$inout0
++	movdqa	@tweak[4],@tweak[0]
++	pxor	@tweak[1],$inout1
++	movdqa	@tweak[5],@tweak[1]
++	pxor	@tweak[2],$inout2
++	movdqu	$inout0,($out)			# store 4 output blocks
++	pxor	@tweak[3],$inout3
++	movdqu	$inout1,16*1($out)
++	movdqu	$inout2,16*2($out)
++	movdqu	$inout3,16*3($out)
++	lea	16*4($out),$out			# $out+=4*16
++	jmp	.Lxts_dec_done
++
++.align	16
++.Lxts_dec_done:
++	and	\$15,$len_			# see if $len%16 is 0
++	jz	.Lxts_dec_ret
++.Lxts_dec_done2:
++	mov	$len_,$len
++	mov	$key_,$key			# restore $key
++	mov	$rnds_,$rounds			# restore $rounds
++
++	movups	($inp),$inout0
++	xorps	@tweak[1],$inout0
++___
++	&aesni_generate1("dec",$key,$rounds);
++$code.=<<___;
++	xorps	@tweak[1],$inout0
++	movups	$inout0,($out)
++
++.Lxts_dec_steal:
++	movzb	16($inp),%eax			# borrow $rounds ...
++	movzb	($out),%ecx			# ... and $key
++	lea	1($inp),$inp
++	mov	%al,($out)
++	mov	%cl,16($out)
++	lea	1($out),$out
++	sub	\$1,$len
++	jnz	.Lxts_dec_steal
++
++	sub	$len_,$out			# rewind $out
++	mov	$key_,$key			# restore $key
++	mov	$rnds_,$rounds			# restore $rounds
++
++	movups	($out),$inout0
++	xorps	@tweak[0],$inout0
++___
++	&aesni_generate1("dec",$key,$rounds);
++$code.=<<___;
++	xorps	@tweak[0],$inout0
++	movups	$inout0,($out)
++
++.Lxts_dec_ret:
++	xorps	%xmm0,%xmm0			# clear register bank
++	pxor	%xmm1,%xmm1
++	pxor	%xmm2,%xmm2
++	pxor	%xmm3,%xmm3
++	pxor	%xmm4,%xmm4
++	pxor	%xmm5,%xmm5
++___
++$code.=<<___ if (!$win64);
++	pxor	%xmm6,%xmm6
++	pxor	%xmm7,%xmm7
++	movaps	%xmm0,0x00(%rsp)		# clear stack
++	pxor	%xmm8,%xmm8
++	movaps	%xmm0,0x10(%rsp)
++	pxor	%xmm9,%xmm9
++	movaps	%xmm0,0x20(%rsp)
++	pxor	%xmm10,%xmm10
++	movaps	%xmm0,0x30(%rsp)
++	pxor	%xmm11,%xmm11
++	movaps	%xmm0,0x40(%rsp)
++	pxor	%xmm12,%xmm12
++	movaps	%xmm0,0x50(%rsp)
++	pxor	%xmm13,%xmm13
++	movaps	%xmm0,0x60(%rsp)
++	pxor	%xmm14,%xmm14
++	pxor	%xmm15,%xmm15
++___
++$code.=<<___ if ($win64);
++	movaps	-0xa0(%rbp),%xmm6
++	movaps	%xmm0,-0xa0(%rbp)		# clear stack
++	movaps	-0x90(%rbp),%xmm7
++	movaps	%xmm0,-0x90(%rbp)
++	movaps	-0x80(%rbp),%xmm8
++	movaps	%xmm0,-0x80(%rbp)
++	movaps	-0x70(%rbp),%xmm9
++	movaps	%xmm0,-0x70(%rbp)
++	movaps	-0x60(%rbp),%xmm10
++	movaps	%xmm0,-0x60(%rbp)
++	movaps	-0x50(%rbp),%xmm11
++	movaps	%xmm0,-0x50(%rbp)
++	movaps	-0x40(%rbp),%xmm12
++	movaps	%xmm0,-0x40(%rbp)
++	movaps	-0x30(%rbp),%xmm13
++	movaps	%xmm0,-0x30(%rbp)
++	movaps	-0x20(%rbp),%xmm14
++	movaps	%xmm0,-0x20(%rbp)
++	movaps	-0x10(%rbp),%xmm15
++	movaps	%xmm0,-0x10(%rbp)
++	movaps	%xmm0,0x00(%rsp)
++	movaps	%xmm0,0x10(%rsp)
++	movaps	%xmm0,0x20(%rsp)
++	movaps	%xmm0,0x30(%rsp)
++	movaps	%xmm0,0x40(%rsp)
++	movaps	%xmm0,0x50(%rsp)
++	movaps	%xmm0,0x60(%rsp)
++___
++$code.=<<___;
++	lea	(%rbp),%rsp
++	pop	%rbp
++.Lxts_dec_epilogue:
++	ret
++.size	aesni_xts_decrypt,.-aesni_xts_decrypt
++___
++}
++
++######################################################################
++# void aesni_ocb_[en|de]crypt(const char *inp, char *out, size_t blocks,
++#	const AES_KEY *key, unsigned int start_block_num,
++#	unsigned char offset_i[16], const unsigned char L_[][16],
++#	unsigned char checksum[16]);
++#
++{
++my @offset=map("%xmm$_",(10..15));
++my ($checksum,$rndkey0l)=("%xmm8","%xmm9");
++my ($block_num,$offset_p)=("%r8","%r9");		# 5th and 6th arguments
++my ($L_p,$checksum_p) = ("%rbx","%rbp");
++my ($i1,$i3,$i5) = ("%r12","%r13","%r14");
++my $seventh_arg = $win64 ? 56 : 8;
++my $blocks = $len;
++
++$code.=<<___;
++.globl	aesni_ocb_encrypt
++.type	aesni_ocb_encrypt,\@function,6
++.align	32
++aesni_ocb_encrypt:
++	lea	(%rsp),%rax
++	push	%rbx
++	push	%rbp
++	push	%r12
++	push	%r13
++	push	%r14
++___
++$code.=<<___ if ($win64);
++	lea	-0xa0(%rsp),%rsp
++	movaps	%xmm6,0x00(%rsp)		# offload everything
++	movaps	%xmm7,0x10(%rsp)
++	movaps	%xmm8,0x20(%rsp)
++	movaps	%xmm9,0x30(%rsp)
++	movaps	%xmm10,0x40(%rsp)
++	movaps	%xmm11,0x50(%rsp)
++	movaps	%xmm12,0x60(%rsp)
++	movaps	%xmm13,0x70(%rsp)
++	movaps	%xmm14,0x80(%rsp)
++	movaps	%xmm15,0x90(%rsp)
++.Locb_enc_body:
++___
++$code.=<<___;
++	mov	$seventh_arg(%rax),$L_p		# 7th argument
++	mov	$seventh_arg+8(%rax),$checksum_p# 8th argument
++
++	mov	240($key),$rnds_
++	mov	$key,$key_
++	shl	\$4,$rnds_
++	$movkey	($key),$rndkey0l		# round[0]
++	$movkey	16($key,$rnds_),$rndkey1	# round[last]
++
++	movdqu	($offset_p),@offset[5]		# load last offset_i
++	pxor	$rndkey1,$rndkey0l		# round[0] ^ round[last]
++	pxor	$rndkey1,@offset[5]		# offset_i ^ round[last]
++
++	mov	\$16+32,$rounds
++	lea	32($key_,$rnds_),$key
++	$movkey	16($key_),$rndkey1		# round[1]
++	sub	%r10,%rax			# twisted $rounds
++	mov	%rax,%r10			# backup twisted $rounds
++
++	movdqu	($L_p),@offset[0]		# L_0 for all odd-numbered blocks
++	movdqu	($checksum_p),$checksum		# load checksum
++
++	test	\$1,$block_num			# is first block number odd?
++	jnz	.Locb_enc_odd
++
++	bsf	$block_num,$i1
++	add	\$1,$block_num
++	shl	\$4,$i1
++	movdqu	($L_p,$i1),$inout5		# borrow
++	movdqu	($inp),$inout0
++	lea	16($inp),$inp
++
++	call	__ocb_encrypt1
++
++	movdqa	$inout5,@offset[5]
++	movups	$inout0,($out)
++	lea	16($out),$out
++	sub	\$1,$blocks
++	jz	.Locb_enc_done
++
++.Locb_enc_odd:
++	lea	1($block_num),$i1		# even-numbered blocks
++	lea	3($block_num),$i3
++	lea	5($block_num),$i5
++	lea	6($block_num),$block_num
++	bsf	$i1,$i1				# ntz(block)
++	bsf	$i3,$i3
++	bsf	$i5,$i5
++	shl	\$4,$i1				# ntz(block) -> table offset
++	shl	\$4,$i3
++	shl	\$4,$i5
++
++	sub	\$6,$blocks
++	jc	.Locb_enc_short
++	jmp	.Locb_enc_grandloop
++
++.align	32
++.Locb_enc_grandloop:
++	movdqu	`16*0`($inp),$inout0		# load input
++	movdqu	`16*1`($inp),$inout1
++	movdqu	`16*2`($inp),$inout2
++	movdqu	`16*3`($inp),$inout3
++	movdqu	`16*4`($inp),$inout4
++	movdqu	`16*5`($inp),$inout5
++	lea	`16*6`($inp),$inp
++
++	call	__ocb_encrypt6
++
++	movups	$inout0,`16*0`($out)		# store output
++	movups	$inout1,`16*1`($out)
++	movups	$inout2,`16*2`($out)
++	movups	$inout3,`16*3`($out)
++	movups	$inout4,`16*4`($out)
++	movups	$inout5,`16*5`($out)
++	lea	`16*6`($out),$out
++	sub	\$6,$blocks
++	jnc	.Locb_enc_grandloop
++
++.Locb_enc_short:
++	add	\$6,$blocks
++	jz	.Locb_enc_done
++
++	movdqu	`16*0`($inp),$inout0
++	cmp	\$2,$blocks
++	jb	.Locb_enc_one
++	movdqu	`16*1`($inp),$inout1
++	je	.Locb_enc_two
++
++	movdqu	`16*2`($inp),$inout2
++	cmp	\$4,$blocks
++	jb	.Locb_enc_three
++	movdqu	`16*3`($inp),$inout3
++	je	.Locb_enc_four
++
++	movdqu	`16*4`($inp),$inout4
++	pxor	$inout5,$inout5
++
++	call	__ocb_encrypt6
++
++	movdqa	@offset[4],@offset[5]
++	movups	$inout0,`16*0`($out)
++	movups	$inout1,`16*1`($out)
++	movups	$inout2,`16*2`($out)
++	movups	$inout3,`16*3`($out)
++	movups	$inout4,`16*4`($out)
++
++	jmp	.Locb_enc_done
++
++.align	16
++.Locb_enc_one:
++	movdqa	@offset[0],$inout5		# borrow
++
++	call	__ocb_encrypt1
++
++	movdqa	$inout5,@offset[5]
++	movups	$inout0,`16*0`($out)
++	jmp	.Locb_enc_done
++
++.align	16
++.Locb_enc_two:
++	pxor	$inout2,$inout2
++	pxor	$inout3,$inout3
++
++	call	__ocb_encrypt4
++
++	movdqa	@offset[1],@offset[5]
++	movups	$inout0,`16*0`($out)
++	movups	$inout1,`16*1`($out)
++
++	jmp	.Locb_enc_done
++
++.align	16
++.Locb_enc_three:
++	pxor	$inout3,$inout3
++
++	call	__ocb_encrypt4
++
++	movdqa	@offset[2],@offset[5]
++	movups	$inout0,`16*0`($out)
++	movups	$inout1,`16*1`($out)
++	movups	$inout2,`16*2`($out)
++
++	jmp	.Locb_enc_done
++
++.align	16
++.Locb_enc_four:
++	call	__ocb_encrypt4
++
++	movdqa	@offset[3],@offset[5]
++	movups	$inout0,`16*0`($out)
++	movups	$inout1,`16*1`($out)
++	movups	$inout2,`16*2`($out)
++	movups	$inout3,`16*3`($out)
++
++.Locb_enc_done:
++	pxor	$rndkey0,@offset[5]		# "remove" round[last]
++	movdqu	$checksum,($checksum_p)		# store checksum
++	movdqu	@offset[5],($offset_p)		# store last offset_i
++
++	xorps	%xmm0,%xmm0			# clear register bank
++	pxor	%xmm1,%xmm1
++	pxor	%xmm2,%xmm2
++	pxor	%xmm3,%xmm3
++	pxor	%xmm4,%xmm4
++	pxor	%xmm5,%xmm5
++___
++$code.=<<___ if (!$win64);
++	pxor	%xmm6,%xmm6
++	pxor	%xmm7,%xmm7
++	pxor	%xmm8,%xmm8
++	pxor	%xmm9,%xmm9
++	pxor	%xmm10,%xmm10
++	pxor	%xmm11,%xmm11
++	pxor	%xmm12,%xmm12
++	pxor	%xmm13,%xmm13
++	pxor	%xmm14,%xmm14
++	pxor	%xmm15,%xmm15
++___
++$code.=<<___ if ($win64);
++	movaps	0x00(%rsp),%xmm6
++	movaps	%xmm0,0x00(%rsp)		# clear stack
++	movaps	0x10(%rsp),%xmm7
++	movaps	%xmm0,0x10(%rsp)
++	movaps	0x20(%rsp),%xmm8
++	movaps	%xmm0,0x20(%rsp)
++	movaps	0x30(%rsp),%xmm9
++	movaps	%xmm0,0x30(%rsp)
++	movaps	0x40(%rsp),%xmm10
++	movaps	%xmm0,0x40(%rsp)
++	movaps	0x50(%rsp),%xmm11
++	movaps	%xmm0,0x50(%rsp)
++	movaps	0x60(%rsp),%xmm12
++	movaps	%xmm0,0x60(%rsp)
++	movaps	0x70(%rsp),%xmm13
++	movaps	%xmm0,0x70(%rsp)
++	movaps	0x80(%rsp),%xmm14
++	movaps	%xmm0,0x80(%rsp)
++	movaps	0x90(%rsp),%xmm15
++	movaps	%xmm0,0x90(%rsp)
++	lea	0xa0+0x28(%rsp),%rax
++.Locb_enc_pop:
++	lea	0xa0(%rsp),%rsp
++___
++$code.=<<___;
++	pop	%r14
++	pop	%r13
++	pop	%r12
++	pop	%rbp
++	pop	%rbx
++.Locb_enc_epilogue:
++	ret
++.size	aesni_ocb_encrypt,.-aesni_ocb_encrypt
++
++.type	__ocb_encrypt6,\@abi-omnipotent
++.align	32
++__ocb_encrypt6:
++	 pxor		$rndkey0l,@offset[5]	# offset_i ^ round[0]
++	 movdqu		($L_p,$i1),@offset[1]
++	 movdqa		@offset[0],@offset[2]
++	 movdqu		($L_p,$i3),@offset[3]
++	 movdqa		@offset[0],@offset[4]
++	 pxor		@offset[5],@offset[0]
++	 movdqu		($L_p,$i5),@offset[5]
++	 pxor		@offset[0],@offset[1]
++	pxor		$inout0,$checksum	# accumulate checksum
++	pxor		@offset[0],$inout0	# input ^ round[0] ^ offset_i
++	 pxor		@offset[1],@offset[2]
++	pxor		$inout1,$checksum
++	pxor		@offset[1],$inout1
++	 pxor		@offset[2],@offset[3]
++	pxor		$inout2,$checksum
++	pxor		@offset[2],$inout2
++	 pxor		@offset[3],@offset[4]
++	pxor		$inout3,$checksum
++	pxor		@offset[3],$inout3
++	 pxor		@offset[4],@offset[5]
++	pxor		$inout4,$checksum
++	pxor		@offset[4],$inout4
++	pxor		$inout5,$checksum
++	pxor		@offset[5],$inout5
++	$movkey		32($key_),$rndkey0
++
++	lea		1($block_num),$i1	# even-numbered blocks
++	lea		3($block_num),$i3
++	lea		5($block_num),$i5
++	add		\$6,$block_num
++	 pxor		$rndkey0l,@offset[0]	# offset_i ^ round[last]
++	bsf		$i1,$i1			# ntz(block)
++	bsf		$i3,$i3
++	bsf		$i5,$i5
++
++	aesenc		$rndkey1,$inout0
++	aesenc		$rndkey1,$inout1
++	aesenc		$rndkey1,$inout2
++	aesenc		$rndkey1,$inout3
++	 pxor		$rndkey0l,@offset[1]
++	 pxor		$rndkey0l,@offset[2]
++	aesenc		$rndkey1,$inout4
++	 pxor		$rndkey0l,@offset[3]
++	 pxor		$rndkey0l,@offset[4]
++	aesenc		$rndkey1,$inout5
++	$movkey		48($key_),$rndkey1
++	 pxor		$rndkey0l,@offset[5]
++
++	aesenc		$rndkey0,$inout0
++	aesenc		$rndkey0,$inout1
++	aesenc		$rndkey0,$inout2
++	aesenc		$rndkey0,$inout3
++	aesenc		$rndkey0,$inout4
++	aesenc		$rndkey0,$inout5
++	$movkey		64($key_),$rndkey0
++	shl		\$4,$i1			# ntz(block) -> table offset
++	shl		\$4,$i3
++	jmp		.Locb_enc_loop6
++
++.align	32
++.Locb_enc_loop6:
++	aesenc		$rndkey1,$inout0
++	aesenc		$rndkey1,$inout1
++	aesenc		$rndkey1,$inout2
++	aesenc		$rndkey1,$inout3
++	aesenc		$rndkey1,$inout4
++	aesenc		$rndkey1,$inout5
++	$movkey		($key,%rax),$rndkey1
++	add		\$32,%rax
++
++	aesenc		$rndkey0,$inout0
++	aesenc		$rndkey0,$inout1
++	aesenc		$rndkey0,$inout2
++	aesenc		$rndkey0,$inout3
++	aesenc		$rndkey0,$inout4
++	aesenc		$rndkey0,$inout5
++	$movkey		-16($key,%rax),$rndkey0
++	jnz		.Locb_enc_loop6
++
++	aesenc		$rndkey1,$inout0
++	aesenc		$rndkey1,$inout1
++	aesenc		$rndkey1,$inout2
++	aesenc		$rndkey1,$inout3
++	aesenc		$rndkey1,$inout4
++	aesenc		$rndkey1,$inout5
++	$movkey		16($key_),$rndkey1
++	shl		\$4,$i5
++
++	aesenclast	@offset[0],$inout0
++	movdqu		($L_p),@offset[0]	# L_0 for all odd-numbered blocks
++	mov		%r10,%rax		# restore twisted rounds
++	aesenclast	@offset[1],$inout1
++	aesenclast	@offset[2],$inout2
++	aesenclast	@offset[3],$inout3
++	aesenclast	@offset[4],$inout4
++	aesenclast	@offset[5],$inout5
++	ret
++.size	__ocb_encrypt6,.-__ocb_encrypt6
++
++.type	__ocb_encrypt4,\@abi-omnipotent
++.align	32
++__ocb_encrypt4:
++	 pxor		$rndkey0l,@offset[5]	# offset_i ^ round[0]
++	 movdqu		($L_p,$i1),@offset[1]
++	 movdqa		@offset[0],@offset[2]
++	 movdqu		($L_p,$i3),@offset[3]
++	 pxor		@offset[5],@offset[0]
++	 pxor		@offset[0],@offset[1]
++	pxor		$inout0,$checksum	# accumulate checksum
++	pxor		@offset[0],$inout0	# input ^ round[0] ^ offset_i
++	 pxor		@offset[1],@offset[2]
++	pxor		$inout1,$checksum
++	pxor		@offset[1],$inout1
++	 pxor		@offset[2],@offset[3]
++	pxor		$inout2,$checksum
++	pxor		@offset[2],$inout2
++	pxor		$inout3,$checksum
++	pxor		@offset[3],$inout3
++	$movkey		32($key_),$rndkey0
++
++	 pxor		$rndkey0l,@offset[0]	# offset_i ^ round[last]
++	 pxor		$rndkey0l,@offset[1]
++	 pxor		$rndkey0l,@offset[2]
++	 pxor		$rndkey0l,@offset[3]
++
++	aesenc		$rndkey1,$inout0
++	aesenc		$rndkey1,$inout1
++	aesenc		$rndkey1,$inout2
++	aesenc		$rndkey1,$inout3
++	$movkey		48($key_),$rndkey1
++
++	aesenc		$rndkey0,$inout0
++	aesenc		$rndkey0,$inout1
++	aesenc		$rndkey0,$inout2
++	aesenc		$rndkey0,$inout3
++	$movkey		64($key_),$rndkey0
++	jmp		.Locb_enc_loop4
++
++.align	32
++.Locb_enc_loop4:
++	aesenc		$rndkey1,$inout0
++	aesenc		$rndkey1,$inout1
++	aesenc		$rndkey1,$inout2
++	aesenc		$rndkey1,$inout3
++	$movkey		($key,%rax),$rndkey1
++	add		\$32,%rax
++
++	aesenc		$rndkey0,$inout0
++	aesenc		$rndkey0,$inout1
++	aesenc		$rndkey0,$inout2
++	aesenc		$rndkey0,$inout3
++	$movkey		-16($key,%rax),$rndkey0
++	jnz		.Locb_enc_loop4
++
++	aesenc		$rndkey1,$inout0
++	aesenc		$rndkey1,$inout1
++	aesenc		$rndkey1,$inout2
++	aesenc		$rndkey1,$inout3
++	$movkey		16($key_),$rndkey1
++	mov		%r10,%rax		# restore twisted rounds
++
++	aesenclast	@offset[0],$inout0
++	aesenclast	@offset[1],$inout1
++	aesenclast	@offset[2],$inout2
++	aesenclast	@offset[3],$inout3
++	ret
++.size	__ocb_encrypt4,.-__ocb_encrypt4
++
++.type	__ocb_encrypt1,\@abi-omnipotent
++.align	32
++__ocb_encrypt1:
++	 pxor		@offset[5],$inout5	# offset_i
++	 pxor		$rndkey0l,$inout5	# offset_i ^ round[0]
++	pxor		$inout0,$checksum	# accumulate checksum
++	pxor		$inout5,$inout0		# input ^ round[0] ^ offset_i
++	$movkey		32($key_),$rndkey0
++
++	aesenc		$rndkey1,$inout0
++	$movkey		48($key_),$rndkey1
++	pxor		$rndkey0l,$inout5	# offset_i ^ round[last]
++
++	aesenc		$rndkey0,$inout0
++	$movkey		64($key_),$rndkey0
++	jmp		.Locb_enc_loop1
++
++.align	32
++.Locb_enc_loop1:
++	aesenc		$rndkey1,$inout0
++	$movkey		($key,%rax),$rndkey1
++	add		\$32,%rax
++
++	aesenc		$rndkey0,$inout0
++	$movkey		-16($key,%rax),$rndkey0
++	jnz		.Locb_enc_loop1
++
++	aesenc		$rndkey1,$inout0
++	$movkey		16($key_),$rndkey1	# redundant in tail
++	mov		%r10,%rax		# restore twisted rounds
++
++	aesenclast	$inout5,$inout0
++	ret
++.size	__ocb_encrypt1,.-__ocb_encrypt1
++
++.globl	aesni_ocb_decrypt
++.type	aesni_ocb_decrypt,\@function,6
++.align	32
++aesni_ocb_decrypt:
++	lea	(%rsp),%rax
++	push	%rbx
++	push	%rbp
++	push	%r12
++	push	%r13
++	push	%r14
++___
++$code.=<<___ if ($win64);
++	lea	-0xa0(%rsp),%rsp
++	movaps	%xmm6,0x00(%rsp)		# offload everything
++	movaps	%xmm7,0x10(%rsp)
++	movaps	%xmm8,0x20(%rsp)
++	movaps	%xmm9,0x30(%rsp)
++	movaps	%xmm10,0x40(%rsp)
++	movaps	%xmm11,0x50(%rsp)
++	movaps	%xmm12,0x60(%rsp)
++	movaps	%xmm13,0x70(%rsp)
++	movaps	%xmm14,0x80(%rsp)
++	movaps	%xmm15,0x90(%rsp)
++.Locb_dec_body:
++___
++$code.=<<___;
++	mov	$seventh_arg(%rax),$L_p		# 7th argument
++	mov	$seventh_arg+8(%rax),$checksum_p# 8th argument
++
++	mov	240($key),$rnds_
++	mov	$key,$key_
++	shl	\$4,$rnds_
++	$movkey	($key),$rndkey0l		# round[0]
++	$movkey	16($key,$rnds_),$rndkey1	# round[last]
++
++	movdqu	($offset_p),@offset[5]		# load last offset_i
++	pxor	$rndkey1,$rndkey0l		# round[0] ^ round[last]
++	pxor	$rndkey1,@offset[5]		# offset_i ^ round[last]
++
++	mov	\$16+32,$rounds
++	lea	32($key_,$rnds_),$key
++	$movkey	16($key_),$rndkey1		# round[1]
++	sub	%r10,%rax			# twisted $rounds
++	mov	%rax,%r10			# backup twisted $rounds
++
++	movdqu	($L_p),@offset[0]		# L_0 for all odd-numbered blocks
++	movdqu	($checksum_p),$checksum		# load checksum
++
++	test	\$1,$block_num			# is first block number odd?
++	jnz	.Locb_dec_odd
++
++	bsf	$block_num,$i1
++	add	\$1,$block_num
++	shl	\$4,$i1
++	movdqu	($L_p,$i1),$inout5		# borrow
++	movdqu	($inp),$inout0
++	lea	16($inp),$inp
++
++	call	__ocb_decrypt1
++
++	movdqa	$inout5,@offset[5]
++	movups	$inout0,($out)
++	xorps	$inout0,$checksum		# accumulate checksum
++	lea	16($out),$out
++	sub	\$1,$blocks
++	jz	.Locb_dec_done
++
++.Locb_dec_odd:
++	lea	1($block_num),$i1		# even-numbered blocks
++	lea	3($block_num),$i3
++	lea	5($block_num),$i5
++	lea	6($block_num),$block_num
++	bsf	$i1,$i1				# ntz(block)
++	bsf	$i3,$i3
++	bsf	$i5,$i5
++	shl	\$4,$i1				# ntz(block) -> table offset
++	shl	\$4,$i3
++	shl	\$4,$i5
++
++	sub	\$6,$blocks
++	jc	.Locb_dec_short
++	jmp	.Locb_dec_grandloop
++
++.align	32
++.Locb_dec_grandloop:
++	movdqu	`16*0`($inp),$inout0		# load input
++	movdqu	`16*1`($inp),$inout1
++	movdqu	`16*2`($inp),$inout2
++	movdqu	`16*3`($inp),$inout3
++	movdqu	`16*4`($inp),$inout4
++	movdqu	`16*5`($inp),$inout5
++	lea	`16*6`($inp),$inp
++
++	call	__ocb_decrypt6
++
++	movups	$inout0,`16*0`($out)		# store output
++	pxor	$inout0,$checksum		# accumulate checksum
++	movups	$inout1,`16*1`($out)
++	pxor	$inout1,$checksum
++	movups	$inout2,`16*2`($out)
++	pxor	$inout2,$checksum
++	movups	$inout3,`16*3`($out)
++	pxor	$inout3,$checksum
++	movups	$inout4,`16*4`($out)
++	pxor	$inout4,$checksum
++	movups	$inout5,`16*5`($out)
++	pxor	$inout5,$checksum
++	lea	`16*6`($out),$out
++	sub	\$6,$blocks
++	jnc	.Locb_dec_grandloop
++
++.Locb_dec_short:
++	add	\$6,$blocks
++	jz	.Locb_dec_done
++
++	movdqu	`16*0`($inp),$inout0
++	cmp	\$2,$blocks
++	jb	.Locb_dec_one
++	movdqu	`16*1`($inp),$inout1
++	je	.Locb_dec_two
++
++	movdqu	`16*2`($inp),$inout2
++	cmp	\$4,$blocks
++	jb	.Locb_dec_three
++	movdqu	`16*3`($inp),$inout3
++	je	.Locb_dec_four
++
++	movdqu	`16*4`($inp),$inout4
++	pxor	$inout5,$inout5
++
++	call	__ocb_decrypt6
++
++	movdqa	@offset[4],@offset[5]
++	movups	$inout0,`16*0`($out)		# store output
++	pxor	$inout0,$checksum		# accumulate checksum
++	movups	$inout1,`16*1`($out)
++	pxor	$inout1,$checksum
++	movups	$inout2,`16*2`($out)
++	pxor	$inout2,$checksum
++	movups	$inout3,`16*3`($out)
++	pxor	$inout3,$checksum
++	movups	$inout4,`16*4`($out)
++	pxor	$inout4,$checksum
++
++	jmp	.Locb_dec_done
++
++.align	16
++.Locb_dec_one:
++	movdqa	@offset[0],$inout5		# borrow
++
++	call	__ocb_decrypt1
++
++	movdqa	$inout5,@offset[5]
++	movups	$inout0,`16*0`($out)		# store output
++	xorps	$inout0,$checksum		# accumulate checksum
++	jmp	.Locb_dec_done
++
++.align	16
++.Locb_dec_two:
++	pxor	$inout2,$inout2
++	pxor	$inout3,$inout3
++
++	call	__ocb_decrypt4
++
++	movdqa	@offset[1],@offset[5]
++	movups	$inout0,`16*0`($out)		# store output
++	xorps	$inout0,$checksum		# accumulate checksum
++	movups	$inout1,`16*1`($out)
++	xorps	$inout1,$checksum
++
++	jmp	.Locb_dec_done
++
++.align	16
++.Locb_dec_three:
++	pxor	$inout3,$inout3
++
++	call	__ocb_decrypt4
++
++	movdqa	@offset[2],@offset[5]
++	movups	$inout0,`16*0`($out)		# store output
++	xorps	$inout0,$checksum		# accumulate checksum
++	movups	$inout1,`16*1`($out)
++	xorps	$inout1,$checksum
++	movups	$inout2,`16*2`($out)
++	xorps	$inout2,$checksum
++
++	jmp	.Locb_dec_done
++
++.align	16
++.Locb_dec_four:
++	call	__ocb_decrypt4
++
++	movdqa	@offset[3],@offset[5]
++	movups	$inout0,`16*0`($out)		# store output
++	pxor	$inout0,$checksum		# accumulate checksum
++	movups	$inout1,`16*1`($out)
++	pxor	$inout1,$checksum
++	movups	$inout2,`16*2`($out)
++	pxor	$inout2,$checksum
++	movups	$inout3,`16*3`($out)
++	pxor	$inout3,$checksum
++
++.Locb_dec_done:
++	pxor	$rndkey0,@offset[5]		# "remove" round[last]
++	movdqu	$checksum,($checksum_p)		# store checksum
++	movdqu	@offset[5],($offset_p)		# store last offset_i
++
++	xorps	%xmm0,%xmm0			# clear register bank
++	pxor	%xmm1,%xmm1
++	pxor	%xmm2,%xmm2
++	pxor	%xmm3,%xmm3
++	pxor	%xmm4,%xmm4
++	pxor	%xmm5,%xmm5
++___
++$code.=<<___ if (!$win64);
++	pxor	%xmm6,%xmm6
++	pxor	%xmm7,%xmm7
++	pxor	%xmm8,%xmm8
++	pxor	%xmm9,%xmm9
++	pxor	%xmm10,%xmm10
++	pxor	%xmm11,%xmm11
++	pxor	%xmm12,%xmm12
++	pxor	%xmm13,%xmm13
++	pxor	%xmm14,%xmm14
++	pxor	%xmm15,%xmm15
++___
++$code.=<<___ if ($win64);
++	movaps	0x00(%rsp),%xmm6
++	movaps	%xmm0,0x00(%rsp)		# clear stack
++	movaps	0x10(%rsp),%xmm7
++	movaps	%xmm0,0x10(%rsp)
++	movaps	0x20(%rsp),%xmm8
++	movaps	%xmm0,0x20(%rsp)
++	movaps	0x30(%rsp),%xmm9
++	movaps	%xmm0,0x30(%rsp)
++	movaps	0x40(%rsp),%xmm10
++	movaps	%xmm0,0x40(%rsp)
++	movaps	0x50(%rsp),%xmm11
++	movaps	%xmm0,0x50(%rsp)
++	movaps	0x60(%rsp),%xmm12
++	movaps	%xmm0,0x60(%rsp)
++	movaps	0x70(%rsp),%xmm13
++	movaps	%xmm0,0x70(%rsp)
++	movaps	0x80(%rsp),%xmm14
++	movaps	%xmm0,0x80(%rsp)
++	movaps	0x90(%rsp),%xmm15
++	movaps	%xmm0,0x90(%rsp)
++	lea	0xa0+0x28(%rsp),%rax
++.Locb_dec_pop:
++	lea	0xa0(%rsp),%rsp
++___
++$code.=<<___;
++	pop	%r14
++	pop	%r13
++	pop	%r12
++	pop	%rbp
++	pop	%rbx
++.Locb_dec_epilogue:
++	ret
++.size	aesni_ocb_decrypt,.-aesni_ocb_decrypt
++
++.type	__ocb_decrypt6,\@abi-omnipotent
++.align	32
++__ocb_decrypt6:
++	 pxor		$rndkey0l,@offset[5]	# offset_i ^ round[0]
++	 movdqu		($L_p,$i1),@offset[1]
++	 movdqa		@offset[0],@offset[2]
++	 movdqu		($L_p,$i3),@offset[3]
++	 movdqa		@offset[0],@offset[4]
++	 pxor		@offset[5],@offset[0]
++	 movdqu		($L_p,$i5),@offset[5]
++	 pxor		@offset[0],@offset[1]
++	pxor		@offset[0],$inout0	# input ^ round[0] ^ offset_i
++	 pxor		@offset[1],@offset[2]
++	pxor		@offset[1],$inout1
++	 pxor		@offset[2],@offset[3]
++	pxor		@offset[2],$inout2
++	 pxor		@offset[3],@offset[4]
++	pxor		@offset[3],$inout3
++	 pxor		@offset[4],@offset[5]
++	pxor		@offset[4],$inout4
++	pxor		@offset[5],$inout5
++	$movkey		32($key_),$rndkey0
++
++	lea		1($block_num),$i1	# even-numbered blocks
++	lea		3($block_num),$i3
++	lea		5($block_num),$i5
++	add		\$6,$block_num
++	 pxor		$rndkey0l,@offset[0]	# offset_i ^ round[last]
++	bsf		$i1,$i1			# ntz(block)
++	bsf		$i3,$i3
++	bsf		$i5,$i5
++
++	aesdec		$rndkey1,$inout0
++	aesdec		$rndkey1,$inout1
++	aesdec		$rndkey1,$inout2
++	aesdec		$rndkey1,$inout3
++	 pxor		$rndkey0l,@offset[1]
++	 pxor		$rndkey0l,@offset[2]
++	aesdec		$rndkey1,$inout4
++	 pxor		$rndkey0l,@offset[3]
++	 pxor		$rndkey0l,@offset[4]
++	aesdec		$rndkey1,$inout5
++	$movkey		48($key_),$rndkey1
++	 pxor		$rndkey0l,@offset[5]
++
++	aesdec		$rndkey0,$inout0
++	aesdec		$rndkey0,$inout1
++	aesdec		$rndkey0,$inout2
++	aesdec		$rndkey0,$inout3
++	aesdec		$rndkey0,$inout4
++	aesdec		$rndkey0,$inout5
++	$movkey		64($key_),$rndkey0
++	shl		\$4,$i1			# ntz(block) -> table offset
++	shl		\$4,$i3
++	jmp		.Locb_dec_loop6
++
++.align	32
++.Locb_dec_loop6:
++	aesdec		$rndkey1,$inout0
++	aesdec		$rndkey1,$inout1
++	aesdec		$rndkey1,$inout2
++	aesdec		$rndkey1,$inout3
++	aesdec		$rndkey1,$inout4
++	aesdec		$rndkey1,$inout5
++	$movkey		($key,%rax),$rndkey1
++	add		\$32,%rax
++
++	aesdec		$rndkey0,$inout0
++	aesdec		$rndkey0,$inout1
++	aesdec		$rndkey0,$inout2
++	aesdec		$rndkey0,$inout3
++	aesdec		$rndkey0,$inout4
++	aesdec		$rndkey0,$inout5
++	$movkey		-16($key,%rax),$rndkey0
++	jnz		.Locb_dec_loop6
++
++	aesdec		$rndkey1,$inout0
++	aesdec		$rndkey1,$inout1
++	aesdec		$rndkey1,$inout2
++	aesdec		$rndkey1,$inout3
++	aesdec		$rndkey1,$inout4
++	aesdec		$rndkey1,$inout5
++	$movkey		16($key_),$rndkey1
++	shl		\$4,$i5
++
++	aesdeclast	@offset[0],$inout0
++	movdqu		($L_p),@offset[0]	# L_0 for all odd-numbered blocks
++	mov		%r10,%rax		# restore twisted rounds
++	aesdeclast	@offset[1],$inout1
++	aesdeclast	@offset[2],$inout2
++	aesdeclast	@offset[3],$inout3
++	aesdeclast	@offset[4],$inout4
++	aesdeclast	@offset[5],$inout5
++	ret
++.size	__ocb_decrypt6,.-__ocb_decrypt6
++
++.type	__ocb_decrypt4,\@abi-omnipotent
++.align	32
++__ocb_decrypt4:
++	 pxor		$rndkey0l,@offset[5]	# offset_i ^ round[0]
++	 movdqu		($L_p,$i1),@offset[1]
++	 movdqa		@offset[0],@offset[2]
++	 movdqu		($L_p,$i3),@offset[3]
++	 pxor		@offset[5],@offset[0]
++	 pxor		@offset[0],@offset[1]
++	pxor		@offset[0],$inout0	# input ^ round[0] ^ offset_i
++	 pxor		@offset[1],@offset[2]
++	pxor		@offset[1],$inout1
++	 pxor		@offset[2],@offset[3]
++	pxor		@offset[2],$inout2
++	pxor		@offset[3],$inout3
++	$movkey		32($key_),$rndkey0
++
++	 pxor		$rndkey0l,@offset[0]	# offset_i ^ round[last]
++	 pxor		$rndkey0l,@offset[1]
++	 pxor		$rndkey0l,@offset[2]
++	 pxor		$rndkey0l,@offset[3]
++
++	aesdec		$rndkey1,$inout0
++	aesdec		$rndkey1,$inout1
++	aesdec		$rndkey1,$inout2
++	aesdec		$rndkey1,$inout3
++	$movkey		48($key_),$rndkey1
++
++	aesdec		$rndkey0,$inout0
++	aesdec		$rndkey0,$inout1
++	aesdec		$rndkey0,$inout2
++	aesdec		$rndkey0,$inout3
++	$movkey		64($key_),$rndkey0
++	jmp		.Locb_dec_loop4
++
++.align	32
++.Locb_dec_loop4:
++	aesdec		$rndkey1,$inout0
++	aesdec		$rndkey1,$inout1
++	aesdec		$rndkey1,$inout2
++	aesdec		$rndkey1,$inout3
++	$movkey		($key,%rax),$rndkey1
++	add		\$32,%rax
++
++	aesdec		$rndkey0,$inout0
++	aesdec		$rndkey0,$inout1
++	aesdec		$rndkey0,$inout2
++	aesdec		$rndkey0,$inout3
++	$movkey		-16($key,%rax),$rndkey0
++	jnz		.Locb_dec_loop4
++
++	aesdec		$rndkey1,$inout0
++	aesdec		$rndkey1,$inout1
++	aesdec		$rndkey1,$inout2
++	aesdec		$rndkey1,$inout3
++	$movkey		16($key_),$rndkey1
++	mov		%r10,%rax		# restore twisted rounds
++
++	aesdeclast	@offset[0],$inout0
++	aesdeclast	@offset[1],$inout1
++	aesdeclast	@offset[2],$inout2
++	aesdeclast	@offset[3],$inout3
++	ret
++.size	__ocb_decrypt4,.-__ocb_decrypt4
++
++.type	__ocb_decrypt1,\@abi-omnipotent
++.align	32
++__ocb_decrypt1:
++	 pxor		@offset[5],$inout5	# offset_i
++	 pxor		$rndkey0l,$inout5	# offset_i ^ round[0]
++	pxor		$inout5,$inout0		# input ^ round[0] ^ offset_i
++	$movkey		32($key_),$rndkey0
++
++	aesdec		$rndkey1,$inout0
++	$movkey		48($key_),$rndkey1
++	pxor		$rndkey0l,$inout5	# offset_i ^ round[last]
++
++	aesdec		$rndkey0,$inout0
++	$movkey		64($key_),$rndkey0
++	jmp		.Locb_dec_loop1
++
++.align	32
++.Locb_dec_loop1:
++	aesdec		$rndkey1,$inout0
++	$movkey		($key,%rax),$rndkey1
++	add		\$32,%rax
++
++	aesdec		$rndkey0,$inout0
++	$movkey		-16($key,%rax),$rndkey0
++	jnz		.Locb_dec_loop1
++
++	aesdec		$rndkey1,$inout0
++	$movkey		16($key_),$rndkey1	# redundant in tail
++	mov		%r10,%rax		# restore twisted rounds
++
++	aesdeclast	$inout5,$inout0
++	ret
++.size	__ocb_decrypt1,.-__ocb_decrypt1
++___
++} }}
++
++########################################################################
++# void $PREFIX_cbc_encrypt (const void *inp, void *out,
++#			    size_t length, const AES_KEY *key,
++#			    unsigned char *ivp,const int enc);
++{
++my $frame_size = 0x10 + ($win64?0xa0:0);	# used in decrypt
++my ($iv,$in0,$in1,$in2,$in3,$in4)=map("%xmm$_",(10..15));
++my $inp_=$key_;
++
++$code.=<<___;
++.globl	${PREFIX}_cbc_encrypt
++.type	${PREFIX}_cbc_encrypt,\@function,6
++.align	16
++${PREFIX}_cbc_encrypt:
++	test	$len,$len		# check length
++	jz	.Lcbc_ret
++
++	mov	240($key),$rnds_	# key->rounds
++	mov	$key,$key_		# backup $key
++	test	%r9d,%r9d		# 6th argument
++	jz	.Lcbc_decrypt
++#--------------------------- CBC ENCRYPT ------------------------------#
++	movups	($ivp),$inout0		# load iv as initial state
++	mov	$rnds_,$rounds
++	cmp	\$16,$len
++	jb	.Lcbc_enc_tail
++	sub	\$16,$len
++	jmp	.Lcbc_enc_loop
++.align	16
++.Lcbc_enc_loop:
++	movups	($inp),$inout1		# load input
++	lea	16($inp),$inp
++	#xorps	$inout1,$inout0
++___
++	&aesni_generate1("enc",$key,$rounds,$inout0,$inout1);
++$code.=<<___;
++	mov	$rnds_,$rounds		# restore $rounds
++	mov	$key_,$key		# restore $key
++	movups	$inout0,0($out)		# store output
++	lea	16($out),$out
++	sub	\$16,$len
++	jnc	.Lcbc_enc_loop
++	add	\$16,$len
++	jnz	.Lcbc_enc_tail
++	 pxor	$rndkey0,$rndkey0	# clear register bank
++	 pxor	$rndkey1,$rndkey1
++	movups	$inout0,($ivp)
++	 pxor	$inout0,$inout0
++	 pxor	$inout1,$inout1
++	jmp	.Lcbc_ret
++
++.Lcbc_enc_tail:
++	mov	$len,%rcx	# zaps $key
++	xchg	$inp,$out	# $inp is %rsi and $out is %rdi now
++	.long	0x9066A4F3	# rep movsb
++	mov	\$16,%ecx	# zero tail
++	sub	$len,%rcx
++	xor	%eax,%eax
++	.long	0x9066AAF3	# rep stosb
++	lea	-16(%rdi),%rdi	# rewind $out by 1 block
++	mov	$rnds_,$rounds	# restore $rounds
++	mov	%rdi,%rsi	# $inp and $out are the same
++	mov	$key_,$key	# restore $key
++	xor	$len,$len	# len=16
++	jmp	.Lcbc_enc_loop	# one more spin
++#--------------------------- CBC DECRYPT ------------------------------#
++.align	16
++.Lcbc_decrypt:
++	cmp	\$16,$len
++	jne	.Lcbc_decrypt_bulk
++
++	# handle single block without allocating stack frame,
++	# useful in ciphertext stealing mode
++	movdqu	($inp),$inout0		# load input
++	movdqu	($ivp),$inout1		# load iv
++	movdqa	$inout0,$inout2		# future iv
++___
++	&aesni_generate1("dec",$key,$rnds_);
++$code.=<<___;
++	 pxor	$rndkey0,$rndkey0	# clear register bank
++	 pxor	$rndkey1,$rndkey1
++	movdqu	$inout2,($ivp)		# store iv
++	xorps	$inout1,$inout0		# ^=iv
++	 pxor	$inout1,$inout1
++	movups	$inout0,($out)		# store output
++	 pxor	$inout0,$inout0
++	jmp	.Lcbc_ret
++.align	16
++.Lcbc_decrypt_bulk:
++	lea	(%rsp),%rax
++	push	%rbp
++	sub	\$$frame_size,%rsp
++	and	\$-16,%rsp	# Linux kernel stack can be incorrectly seeded
++___
++$code.=<<___ if ($win64);
++	movaps	%xmm6,0x10(%rsp)
++	movaps	%xmm7,0x20(%rsp)
++	movaps	%xmm8,0x30(%rsp)
++	movaps	%xmm9,0x40(%rsp)
++	movaps	%xmm10,0x50(%rsp)
++	movaps	%xmm11,0x60(%rsp)
++	movaps	%xmm12,0x70(%rsp)
++	movaps	%xmm13,0x80(%rsp)
++	movaps	%xmm14,0x90(%rsp)
++	movaps	%xmm15,0xa0(%rsp)
++.Lcbc_decrypt_body:
++___
++$code.=<<___;
++	lea	-8(%rax),%rbp
++	movups	($ivp),$iv
++	mov	$rnds_,$rounds
++	cmp	\$0x50,$len
++	jbe	.Lcbc_dec_tail
++
++	$movkey	($key),$rndkey0
++	movdqu	0x00($inp),$inout0	# load input
++	movdqu	0x10($inp),$inout1
++	movdqa	$inout0,$in0
++	movdqu	0x20($inp),$inout2
++	movdqa	$inout1,$in1
++	movdqu	0x30($inp),$inout3
++	movdqa	$inout2,$in2
++	movdqu	0x40($inp),$inout4
++	movdqa	$inout3,$in3
++	movdqu	0x50($inp),$inout5
++	movdqa	$inout4,$in4
++	mov	OPENSSL_ia32cap_P+4(%rip),%r9d
++	cmp	\$0x70,$len
++	jbe	.Lcbc_dec_six_or_seven
++
++	and	\$`1<<26|1<<22`,%r9d	# isolate XSAVE+MOVBE
++	sub	\$0x50,$len		# $len is biased by -5*16
++	cmp	\$`1<<22`,%r9d		# check for MOVBE without XSAVE
++	je	.Lcbc_dec_loop6_enter	# [which denotes Atom Silvermont]
++	sub	\$0x20,$len		# $len is biased by -7*16
++	lea	0x70($key),$key		# size optimization
++	jmp	.Lcbc_dec_loop8_enter
++.align	16
++.Lcbc_dec_loop8:
++	movups	$inout7,($out)
++	lea	0x10($out),$out
++.Lcbc_dec_loop8_enter:
++	movdqu		0x60($inp),$inout6
++	pxor		$rndkey0,$inout0
++	movdqu		0x70($inp),$inout7
++	pxor		$rndkey0,$inout1
++	$movkey		0x10-0x70($key),$rndkey1
++	pxor		$rndkey0,$inout2
++	xor		$inp_,$inp_
++	cmp		\$0x70,$len	# is there at least 0x60 bytes ahead?
++	pxor		$rndkey0,$inout3
++	pxor		$rndkey0,$inout4
++	pxor		$rndkey0,$inout5
++	pxor		$rndkey0,$inout6
++
++	aesdec		$rndkey1,$inout0
++	pxor		$rndkey0,$inout7
++	$movkey		0x20-0x70($key),$rndkey0
++	aesdec		$rndkey1,$inout1
++	aesdec		$rndkey1,$inout2
++	aesdec		$rndkey1,$inout3
++	aesdec		$rndkey1,$inout4
++	aesdec		$rndkey1,$inout5
++	aesdec		$rndkey1,$inout6
++	setnc		${inp_}b
++	shl		\$7,$inp_
++	aesdec		$rndkey1,$inout7
++	add		$inp,$inp_
++	$movkey		0x30-0x70($key),$rndkey1
++___
++for($i=1;$i<12;$i++) {
++my $rndkeyx = ($i&1)?$rndkey0:$rndkey1;
++$code.=<<___	if ($i==7);
++	cmp		\$11,$rounds
++___
++$code.=<<___;
++	aesdec		$rndkeyx,$inout0
++	aesdec		$rndkeyx,$inout1
++	aesdec		$rndkeyx,$inout2
++	aesdec		$rndkeyx,$inout3
++	aesdec		$rndkeyx,$inout4
++	aesdec		$rndkeyx,$inout5
++	aesdec		$rndkeyx,$inout6
++	aesdec		$rndkeyx,$inout7
++	$movkey		`0x30+0x10*$i`-0x70($key),$rndkeyx
++___
++$code.=<<___	if ($i<6 || (!($i&1) && $i>7));
++	nop
++___
++$code.=<<___	if ($i==7);
++	jb		.Lcbc_dec_done
++___
++$code.=<<___	if ($i==9);
++	je		.Lcbc_dec_done
++___
++$code.=<<___	if ($i==11);
++	jmp		.Lcbc_dec_done
++___
++}
++$code.=<<___;
++.align	16
++.Lcbc_dec_done:
++	aesdec		$rndkey1,$inout0
++	aesdec		$rndkey1,$inout1
++	pxor		$rndkey0,$iv
++	pxor		$rndkey0,$in0
++	aesdec		$rndkey1,$inout2
++	aesdec		$rndkey1,$inout3
++	pxor		$rndkey0,$in1
++	pxor		$rndkey0,$in2
++	aesdec		$rndkey1,$inout4
++	aesdec		$rndkey1,$inout5
++	pxor		$rndkey0,$in3
++	pxor		$rndkey0,$in4
++	aesdec		$rndkey1,$inout6
++	aesdec		$rndkey1,$inout7
++	movdqu		0x50($inp),$rndkey1
++
++	aesdeclast	$iv,$inout0
++	movdqu		0x60($inp),$iv		# borrow $iv
++	pxor		$rndkey0,$rndkey1
++	aesdeclast	$in0,$inout1
++	pxor		$rndkey0,$iv
++	movdqu		0x70($inp),$rndkey0	# next IV
++	aesdeclast	$in1,$inout2
++	lea		0x80($inp),$inp
++	movdqu		0x00($inp_),$in0
++	aesdeclast	$in2,$inout3
++	aesdeclast	$in3,$inout4
++	movdqu		0x10($inp_),$in1
++	movdqu		0x20($inp_),$in2
++	aesdeclast	$in4,$inout5
++	aesdeclast	$rndkey1,$inout6
++	movdqu		0x30($inp_),$in3
++	movdqu		0x40($inp_),$in4
++	aesdeclast	$iv,$inout7
++	movdqa		$rndkey0,$iv		# return $iv
++	movdqu		0x50($inp_),$rndkey1
++	$movkey		-0x70($key),$rndkey0
++
++	movups		$inout0,($out)		# store output
++	movdqa		$in0,$inout0
++	movups		$inout1,0x10($out)
++	movdqa		$in1,$inout1
++	movups		$inout2,0x20($out)
++	movdqa		$in2,$inout2
++	movups		$inout3,0x30($out)
++	movdqa		$in3,$inout3
++	movups		$inout4,0x40($out)
++	movdqa		$in4,$inout4
++	movups		$inout5,0x50($out)
++	movdqa		$rndkey1,$inout5
++	movups		$inout6,0x60($out)
++	lea		0x70($out),$out
++
++	sub	\$0x80,$len
++	ja	.Lcbc_dec_loop8
++
++	movaps	$inout7,$inout0
++	lea	-0x70($key),$key
++	add	\$0x70,$len
++	jle	.Lcbc_dec_clear_tail_collected
++	movups	$inout7,($out)
++	lea	0x10($out),$out
++	cmp	\$0x50,$len
++	jbe	.Lcbc_dec_tail
++
++	movaps	$in0,$inout0
++.Lcbc_dec_six_or_seven:
++	cmp	\$0x60,$len
++	ja	.Lcbc_dec_seven
++
++	movaps	$inout5,$inout6
++	call	_aesni_decrypt6
++	pxor	$iv,$inout0		# ^= IV
++	movaps	$inout6,$iv
++	pxor	$in0,$inout1
++	movdqu	$inout0,($out)
++	pxor	$in1,$inout2
++	movdqu	$inout1,0x10($out)
++	 pxor	$inout1,$inout1		# clear register bank
++	pxor	$in2,$inout3
++	movdqu	$inout2,0x20($out)
++	 pxor	$inout2,$inout2
++	pxor	$in3,$inout4
++	movdqu	$inout3,0x30($out)
++	 pxor	$inout3,$inout3
++	pxor	$in4,$inout5
++	movdqu	$inout4,0x40($out)
++	 pxor	$inout4,$inout4
++	lea	0x50($out),$out
++	movdqa	$inout5,$inout0
++	 pxor	$inout5,$inout5
++	jmp	.Lcbc_dec_tail_collected
++
++.align	16
++.Lcbc_dec_seven:
++	movups	0x60($inp),$inout6
++	xorps	$inout7,$inout7
++	call	_aesni_decrypt8
++	movups	0x50($inp),$inout7
++	pxor	$iv,$inout0		# ^= IV
++	movups	0x60($inp),$iv
++	pxor	$in0,$inout1
++	movdqu	$inout0,($out)
++	pxor	$in1,$inout2
++	movdqu	$inout1,0x10($out)
++	 pxor	$inout1,$inout1		# clear register bank
++	pxor	$in2,$inout3
++	movdqu	$inout2,0x20($out)
++	 pxor	$inout2,$inout2
++	pxor	$in3,$inout4
++	movdqu	$inout3,0x30($out)
++	 pxor	$inout3,$inout3
++	pxor	$in4,$inout5
++	movdqu	$inout4,0x40($out)
++	 pxor	$inout4,$inout4
++	pxor	$inout7,$inout6
++	movdqu	$inout5,0x50($out)
++	 pxor	$inout5,$inout5
++	lea	0x60($out),$out
++	movdqa	$inout6,$inout0
++	 pxor	$inout6,$inout6
++	 pxor	$inout7,$inout7
++	jmp	.Lcbc_dec_tail_collected
++
++.align	16
++.Lcbc_dec_loop6:
++	movups	$inout5,($out)
++	lea	0x10($out),$out
++	movdqu	0x00($inp),$inout0	# load input
++	movdqu	0x10($inp),$inout1
++	movdqa	$inout0,$in0
++	movdqu	0x20($inp),$inout2
++	movdqa	$inout1,$in1
++	movdqu	0x30($inp),$inout3
++	movdqa	$inout2,$in2
++	movdqu	0x40($inp),$inout4
++	movdqa	$inout3,$in3
++	movdqu	0x50($inp),$inout5
++	movdqa	$inout4,$in4
++.Lcbc_dec_loop6_enter:
++	lea	0x60($inp),$inp
++	movdqa	$inout5,$inout6
++
++	call	_aesni_decrypt6
++
++	pxor	$iv,$inout0		# ^= IV
++	movdqa	$inout6,$iv
++	pxor	$in0,$inout1
++	movdqu	$inout0,($out)
++	pxor	$in1,$inout2
++	movdqu	$inout1,0x10($out)
++	pxor	$in2,$inout3
++	movdqu	$inout2,0x20($out)
++	pxor	$in3,$inout4
++	mov	$key_,$key
++	movdqu	$inout3,0x30($out)
++	pxor	$in4,$inout5
++	mov	$rnds_,$rounds
++	movdqu	$inout4,0x40($out)
++	lea	0x50($out),$out
++	sub	\$0x60,$len
++	ja	.Lcbc_dec_loop6
++
++	movdqa	$inout5,$inout0
++	add	\$0x50,$len
++	jle	.Lcbc_dec_clear_tail_collected
++	movups	$inout5,($out)
++	lea	0x10($out),$out
++
++.Lcbc_dec_tail:
++	movups	($inp),$inout0
++	sub	\$0x10,$len
++	jbe	.Lcbc_dec_one		# $len is 1*16 or less
++
++	movups	0x10($inp),$inout1
++	movaps	$inout0,$in0
++	sub	\$0x10,$len
++	jbe	.Lcbc_dec_two		# $len is 2*16 or less
++
++	movups	0x20($inp),$inout2
++	movaps	$inout1,$in1
++	sub	\$0x10,$len
++	jbe	.Lcbc_dec_three		# $len is 3*16 or less
++
++	movups	0x30($inp),$inout3
++	movaps	$inout2,$in2
++	sub	\$0x10,$len
++	jbe	.Lcbc_dec_four		# $len is 4*16 or less
++
++	movups	0x40($inp),$inout4	# $len is 5*16 or less
++	movaps	$inout3,$in3
++	movaps	$inout4,$in4
++	xorps	$inout5,$inout5
++	call	_aesni_decrypt6
++	pxor	$iv,$inout0
++	movaps	$in4,$iv
++	pxor	$in0,$inout1
++	movdqu	$inout0,($out)
++	pxor	$in1,$inout2
++	movdqu	$inout1,0x10($out)
++	 pxor	$inout1,$inout1		# clear register bank
++	pxor	$in2,$inout3
++	movdqu	$inout2,0x20($out)
++	 pxor	$inout2,$inout2
++	pxor	$in3,$inout4
++	movdqu	$inout3,0x30($out)
++	 pxor	$inout3,$inout3
++	lea	0x40($out),$out
++	movdqa	$inout4,$inout0
++	 pxor	$inout4,$inout4
++	 pxor	$inout5,$inout5
++	sub	\$0x10,$len
++	jmp	.Lcbc_dec_tail_collected
++
++.align	16
++.Lcbc_dec_one:
++	movaps	$inout0,$in0
++___
++	&aesni_generate1("dec",$key,$rounds);
++$code.=<<___;
++	xorps	$iv,$inout0
++	movaps	$in0,$iv
++	jmp	.Lcbc_dec_tail_collected
++.align	16
++.Lcbc_dec_two:
++	movaps	$inout1,$in1
++	call	_aesni_decrypt2
++	pxor	$iv,$inout0
++	movaps	$in1,$iv
++	pxor	$in0,$inout1
++	movdqu	$inout0,($out)
++	movdqa	$inout1,$inout0
++	 pxor	$inout1,$inout1		# clear register bank
++	lea	0x10($out),$out
++	jmp	.Lcbc_dec_tail_collected
++.align	16
++.Lcbc_dec_three:
++	movaps	$inout2,$in2
++	call	_aesni_decrypt3
++	pxor	$iv,$inout0
++	movaps	$in2,$iv
++	pxor	$in0,$inout1
++	movdqu	$inout0,($out)
++	pxor	$in1,$inout2
++	movdqu	$inout1,0x10($out)
++	 pxor	$inout1,$inout1		# clear register bank
++	movdqa	$inout2,$inout0
++	 pxor	$inout2,$inout2
++	lea	0x20($out),$out
++	jmp	.Lcbc_dec_tail_collected
++.align	16
++.Lcbc_dec_four:
++	movaps	$inout3,$in3
++	call	_aesni_decrypt4
++	pxor	$iv,$inout0
++	movaps	$in3,$iv
++	pxor	$in0,$inout1
++	movdqu	$inout0,($out)
++	pxor	$in1,$inout2
++	movdqu	$inout1,0x10($out)
++	 pxor	$inout1,$inout1		# clear register bank
++	pxor	$in2,$inout3
++	movdqu	$inout2,0x20($out)
++	 pxor	$inout2,$inout2
++	movdqa	$inout3,$inout0
++	 pxor	$inout3,$inout3
++	lea	0x30($out),$out
++	jmp	.Lcbc_dec_tail_collected
++
++.align	16
++.Lcbc_dec_clear_tail_collected:
++	pxor	$inout1,$inout1		# clear register bank
++	pxor	$inout2,$inout2
++	pxor	$inout3,$inout3
++___
++$code.=<<___ if (!$win64);
++	pxor	$inout4,$inout4		# %xmm6..9
++	pxor	$inout5,$inout5
++	pxor	$inout6,$inout6
++	pxor	$inout7,$inout7
++___
++$code.=<<___;
++.Lcbc_dec_tail_collected:
++	movups	$iv,($ivp)
++	and	\$15,$len
++	jnz	.Lcbc_dec_tail_partial
++	movups	$inout0,($out)
++	pxor	$inout0,$inout0
++	jmp	.Lcbc_dec_ret
++.align	16
++.Lcbc_dec_tail_partial:
++	movaps	$inout0,(%rsp)
++	pxor	$inout0,$inout0
++	mov	\$16,%rcx
++	mov	$out,%rdi
++	sub	$len,%rcx
++	lea	(%rsp),%rsi
++	.long	0x9066A4F3		# rep movsb
++	movdqa	$inout0,(%rsp)
++
++.Lcbc_dec_ret:
++	xorps	$rndkey0,$rndkey0	# %xmm0
++	pxor	$rndkey1,$rndkey1
++___
++$code.=<<___ if ($win64);
++	movaps	0x10(%rsp),%xmm6
++	movaps	%xmm0,0x10(%rsp)	# clear stack
++	movaps	0x20(%rsp),%xmm7
++	movaps	%xmm0,0x20(%rsp)
++	movaps	0x30(%rsp),%xmm8
++	movaps	%xmm0,0x30(%rsp)
++	movaps	0x40(%rsp),%xmm9
++	movaps	%xmm0,0x40(%rsp)
++	movaps	0x50(%rsp),%xmm10
++	movaps	%xmm0,0x50(%rsp)
++	movaps	0x60(%rsp),%xmm11
++	movaps	%xmm0,0x60(%rsp)
++	movaps	0x70(%rsp),%xmm12
++	movaps	%xmm0,0x70(%rsp)
++	movaps	0x80(%rsp),%xmm13
++	movaps	%xmm0,0x80(%rsp)
++	movaps	0x90(%rsp),%xmm14
++	movaps	%xmm0,0x90(%rsp)
++	movaps	0xa0(%rsp),%xmm15
++	movaps	%xmm0,0xa0(%rsp)
++___
++$code.=<<___;
++	lea	(%rbp),%rsp
++	pop	%rbp
++.Lcbc_ret:
++	ret
++.size	${PREFIX}_cbc_encrypt,.-${PREFIX}_cbc_encrypt
++___
++} 
++# int ${PREFIX}_set_decrypt_key(const unsigned char *inp,
++#				int bits, AES_KEY *key)
++#
++# input:	$inp	user-supplied key
++#		$bits	$inp length in bits
++#		$key	pointer to key schedule
++# output:	%eax	0 denoting success, -1 or -2 - failure (see C)
++#		*$key	key schedule
++#
++{ my ($inp,$bits,$key) = @_4args;
++  $bits =~ s/%r/%e/;
++
++$code.=<<___;
++.globl	${PREFIX}_set_decrypt_key
++.type	${PREFIX}_set_decrypt_key,\@abi-omnipotent
++.align	16
++${PREFIX}_set_decrypt_key:
++	.byte	0x48,0x83,0xEC,0x08	# sub rsp,8
++	call	__aesni_set_encrypt_key
++	shl	\$4,$bits		# rounds-1 after _aesni_set_encrypt_key
++	test	%eax,%eax
++	jnz	.Ldec_key_ret
++	lea	16($key,$bits),$inp	# points at the end of key schedule
++
++	$movkey	($key),%xmm0		# just swap
++	$movkey	($inp),%xmm1
++	$movkey	%xmm0,($inp)
++	$movkey	%xmm1,($key)
++	lea	16($key),$key
++	lea	-16($inp),$inp
++
++.Ldec_key_inverse:
++	$movkey	($key),%xmm0		# swap and inverse
++	$movkey	($inp),%xmm1
++	aesimc	%xmm0,%xmm0
++	aesimc	%xmm1,%xmm1
++	lea	16($key),$key
++	lea	-16($inp),$inp
++	$movkey	%xmm0,16($inp)
++	$movkey	%xmm1,-16($key)
++	cmp	$key,$inp
++	ja	.Ldec_key_inverse
++
++	$movkey	($key),%xmm0		# inverse middle
++	aesimc	%xmm0,%xmm0
++	pxor	%xmm1,%xmm1
++	$movkey	%xmm0,($inp)
++	pxor	%xmm0,%xmm0
++.Ldec_key_ret:
++	add	\$8,%rsp
++	ret
++.LSEH_end_set_decrypt_key:
++.size	${PREFIX}_set_decrypt_key,.-${PREFIX}_set_decrypt_key
++___
++
++# This is based on submission by
++#
++#	Huang Ying 
++#	Vinodh Gopal 
++#	Kahraman Akdemir
++#
++# Aggressively optimized in respect to aeskeygenassist's critical path
++# and is contained in %xmm0-5 to meet Win64 ABI requirement.
++#
++# int ${PREFIX}_set_encrypt_key(const unsigned char *inp,
++#				int bits, AES_KEY * const key);
++#
++# input:	$inp	user-supplied key
++#		$bits	$inp length in bits
++#		$key	pointer to key schedule
++# output:	%eax	0 denoting success, -1 or -2 - failure (see C)
++#		$bits	rounds-1 (used in aesni_set_decrypt_key)
++#		*$key	key schedule
++#		$key	pointer to key schedule (used in
++#			aesni_set_decrypt_key)
++#
++# Subroutine is frame-less, which means that only volatile registers
++# are used. Note that it's declared "abi-omnipotent", which means that
++# amount of volatile registers is smaller on Windows.
++#
++$code.=<<___;
++.globl	${PREFIX}_set_encrypt_key
++.type	${PREFIX}_set_encrypt_key,\@abi-omnipotent
++.align	16
++${PREFIX}_set_encrypt_key:
++__aesni_set_encrypt_key:
++	.byte	0x48,0x83,0xEC,0x08	# sub rsp,8
++	mov	\$-1,%rax
++	test	$inp,$inp
++	jz	.Lenc_key_ret
++	test	$key,$key
++	jz	.Lenc_key_ret
++
++	mov	\$`1<<28|1<<11`,%r10d	# AVX and XOP bits
++	movups	($inp),%xmm0		# pull first 128 bits of *userKey
++	xorps	%xmm4,%xmm4		# low dword of xmm4 is assumed 0
++	and	OPENSSL_ia32cap_P+4(%rip),%r10d
++	lea	16($key),%rax		# %rax is used as modifiable copy of $key
++	cmp	\$256,$bits
++	je	.L14rounds
++	cmp	\$192,$bits
++	je	.L12rounds
++	cmp	\$128,$bits
++	jne	.Lbad_keybits
++
++.L10rounds:
++	mov	\$9,$bits			# 10 rounds for 128-bit key
++	cmp	\$`1<<28`,%r10d			# AVX, bit no XOP
++	je	.L10rounds_alt
++
++	$movkey	%xmm0,($key)			# round 0
++	aeskeygenassist	\$0x1,%xmm0,%xmm1	# round 1
++	call		.Lkey_expansion_128_cold
++	aeskeygenassist	\$0x2,%xmm0,%xmm1	# round 2
++	call		.Lkey_expansion_128
++	aeskeygenassist	\$0x4,%xmm0,%xmm1	# round 3
++	call		.Lkey_expansion_128
++	aeskeygenassist	\$0x8,%xmm0,%xmm1	# round 4
++	call		.Lkey_expansion_128
++	aeskeygenassist	\$0x10,%xmm0,%xmm1	# round 5
++	call		.Lkey_expansion_128
++	aeskeygenassist	\$0x20,%xmm0,%xmm1	# round 6
++	call		.Lkey_expansion_128
++	aeskeygenassist	\$0x40,%xmm0,%xmm1	# round 7
++	call		.Lkey_expansion_128
++	aeskeygenassist	\$0x80,%xmm0,%xmm1	# round 8
++	call		.Lkey_expansion_128
++	aeskeygenassist	\$0x1b,%xmm0,%xmm1	# round 9
++	call		.Lkey_expansion_128
++	aeskeygenassist	\$0x36,%xmm0,%xmm1	# round 10
++	call		.Lkey_expansion_128
++	$movkey	%xmm0,(%rax)
++	mov	$bits,80(%rax)	# 240(%rdx)
++	xor	%eax,%eax
++	jmp	.Lenc_key_ret
++
++.align	16
++.L10rounds_alt:
++	movdqa	.Lkey_rotate(%rip),%xmm5
++	mov	\$8,%r10d
++	movdqa	.Lkey_rcon1(%rip),%xmm4
++	movdqa	%xmm0,%xmm2
++	movdqu	%xmm0,($key)
++	jmp	.Loop_key128
++
++.align	16
++.Loop_key128:
++	pshufb		%xmm5,%xmm0
++	aesenclast	%xmm4,%xmm0
++	pslld		\$1,%xmm4
++	lea		16(%rax),%rax
++
++	movdqa		%xmm2,%xmm3
++	pslldq		\$4,%xmm2
++	pxor		%xmm2,%xmm3
++	pslldq		\$4,%xmm2
++	pxor		%xmm2,%xmm3
++	pslldq		\$4,%xmm2
++	pxor		%xmm3,%xmm2
++
++	pxor		%xmm2,%xmm0
++	movdqu		%xmm0,-16(%rax)
++	movdqa		%xmm0,%xmm2
++
++	dec	%r10d
++	jnz	.Loop_key128
++
++	movdqa		.Lkey_rcon1b(%rip),%xmm4
++
++	pshufb		%xmm5,%xmm0
++	aesenclast	%xmm4,%xmm0
++	pslld		\$1,%xmm4
++
++	movdqa		%xmm2,%xmm3
++	pslldq		\$4,%xmm2
++	pxor		%xmm2,%xmm3
++	pslldq		\$4,%xmm2
++	pxor		%xmm2,%xmm3
++	pslldq		\$4,%xmm2
++	pxor		%xmm3,%xmm2
++
++	pxor		%xmm2,%xmm0
++	movdqu		%xmm0,(%rax)
++
++	movdqa		%xmm0,%xmm2
++	pshufb		%xmm5,%xmm0
++	aesenclast	%xmm4,%xmm0
++
++	movdqa		%xmm2,%xmm3
++	pslldq		\$4,%xmm2
++	pxor		%xmm2,%xmm3
++	pslldq		\$4,%xmm2
++	pxor		%xmm2,%xmm3
++	pslldq		\$4,%xmm2
++	pxor		%xmm3,%xmm2
++
++	pxor		%xmm2,%xmm0
++	movdqu		%xmm0,16(%rax)
++
++	mov	$bits,96(%rax)	# 240($key)
++	xor	%eax,%eax
++	jmp	.Lenc_key_ret
++
++.align	16
++.L12rounds:
++	movq	16($inp),%xmm2			# remaining 1/3 of *userKey
++	mov	\$11,$bits			# 12 rounds for 192
++	cmp	\$`1<<28`,%r10d			# AVX, but no XOP
++	je	.L12rounds_alt
++
++	$movkey	%xmm0,($key)			# round 0
++	aeskeygenassist	\$0x1,%xmm2,%xmm1	# round 1,2
++	call		.Lkey_expansion_192a_cold
++	aeskeygenassist	\$0x2,%xmm2,%xmm1	# round 2,3
++	call		.Lkey_expansion_192b
++	aeskeygenassist	\$0x4,%xmm2,%xmm1	# round 4,5
++	call		.Lkey_expansion_192a
++	aeskeygenassist	\$0x8,%xmm2,%xmm1	# round 5,6
++	call		.Lkey_expansion_192b
++	aeskeygenassist	\$0x10,%xmm2,%xmm1	# round 7,8
++	call		.Lkey_expansion_192a
++	aeskeygenassist	\$0x20,%xmm2,%xmm1	# round 8,9
++	call		.Lkey_expansion_192b
++	aeskeygenassist	\$0x40,%xmm2,%xmm1	# round 10,11
++	call		.Lkey_expansion_192a
++	aeskeygenassist	\$0x80,%xmm2,%xmm1	# round 11,12
++	call		.Lkey_expansion_192b
++	$movkey	%xmm0,(%rax)
++	mov	$bits,48(%rax)	# 240(%rdx)
++	xor	%rax, %rax
++	jmp	.Lenc_key_ret
++
++.align	16
++.L12rounds_alt:
++	movdqa	.Lkey_rotate192(%rip),%xmm5
++	movdqa	.Lkey_rcon1(%rip),%xmm4
++	mov	\$8,%r10d
++	movdqu	%xmm0,($key)
++	jmp	.Loop_key192
++
++.align	16
++.Loop_key192:
++	movq		%xmm2,0(%rax)
++	movdqa		%xmm2,%xmm1
++	pshufb		%xmm5,%xmm2
++	aesenclast	%xmm4,%xmm2
++	pslld		\$1, %xmm4
++	lea		24(%rax),%rax
++
++	movdqa		%xmm0,%xmm3
++	pslldq		\$4,%xmm0
++	pxor		%xmm0,%xmm3
++	pslldq		\$4,%xmm0
++	pxor		%xmm0,%xmm3
++	pslldq		\$4,%xmm0
++	pxor		%xmm3,%xmm0
++
++	pshufd		\$0xff,%xmm0,%xmm3
++	pxor		%xmm1,%xmm3
++	pslldq		\$4,%xmm1
++	pxor		%xmm1,%xmm3
++
++	pxor		%xmm2,%xmm0
++	pxor		%xmm3,%xmm2
++	movdqu		%xmm0,-16(%rax)
++
++	dec	%r10d
++	jnz	.Loop_key192
++
++	mov	$bits,32(%rax)	# 240($key)
++	xor	%eax,%eax
++	jmp	.Lenc_key_ret
++
++.align	16
++.L14rounds:
++	movups	16($inp),%xmm2			# remaning half of *userKey
++	mov	\$13,$bits			# 14 rounds for 256
++	lea	16(%rax),%rax
++	cmp	\$`1<<28`,%r10d			# AVX, but no XOP
++	je	.L14rounds_alt
++
++	$movkey	%xmm0,($key)			# round 0
++	$movkey	%xmm2,16($key)			# round 1
++	aeskeygenassist	\$0x1,%xmm2,%xmm1	# round 2
++	call		.Lkey_expansion_256a_cold
++	aeskeygenassist	\$0x1,%xmm0,%xmm1	# round 3
++	call		.Lkey_expansion_256b
++	aeskeygenassist	\$0x2,%xmm2,%xmm1	# round 4
++	call		.Lkey_expansion_256a
++	aeskeygenassist	\$0x2,%xmm0,%xmm1	# round 5
++	call		.Lkey_expansion_256b
++	aeskeygenassist	\$0x4,%xmm2,%xmm1	# round 6
++	call		.Lkey_expansion_256a
++	aeskeygenassist	\$0x4,%xmm0,%xmm1	# round 7
++	call		.Lkey_expansion_256b
++	aeskeygenassist	\$0x8,%xmm2,%xmm1	# round 8
++	call		.Lkey_expansion_256a
++	aeskeygenassist	\$0x8,%xmm0,%xmm1	# round 9
++	call		.Lkey_expansion_256b
++	aeskeygenassist	\$0x10,%xmm2,%xmm1	# round 10
++	call		.Lkey_expansion_256a
++	aeskeygenassist	\$0x10,%xmm0,%xmm1	# round 11
++	call		.Lkey_expansion_256b
++	aeskeygenassist	\$0x20,%xmm2,%xmm1	# round 12
++	call		.Lkey_expansion_256a
++	aeskeygenassist	\$0x20,%xmm0,%xmm1	# round 13
++	call		.Lkey_expansion_256b
++	aeskeygenassist	\$0x40,%xmm2,%xmm1	# round 14
++	call		.Lkey_expansion_256a
++	$movkey	%xmm0,(%rax)
++	mov	$bits,16(%rax)	# 240(%rdx)
++	xor	%rax,%rax
++	jmp	.Lenc_key_ret
++
++.align	16
++.L14rounds_alt:
++	movdqa	.Lkey_rotate(%rip),%xmm5
++	movdqa	.Lkey_rcon1(%rip),%xmm4
++	mov	\$7,%r10d
++	movdqu	%xmm0,0($key)
++	movdqa	%xmm2,%xmm1
++	movdqu	%xmm2,16($key)
++	jmp	.Loop_key256
++
++.align	16
++.Loop_key256:
++	pshufb		%xmm5,%xmm2
++	aesenclast	%xmm4,%xmm2
++
++	movdqa		%xmm0,%xmm3
++	pslldq		\$4,%xmm0
++	pxor		%xmm0,%xmm3
++	pslldq		\$4,%xmm0
++	pxor		%xmm0,%xmm3
++	pslldq		\$4,%xmm0
++	pxor		%xmm3,%xmm0
++	pslld		\$1,%xmm4
++
++	pxor		%xmm2,%xmm0
++	movdqu		%xmm0,(%rax)
++
++	dec	%r10d
++	jz	.Ldone_key256
++
++	pshufd		\$0xff,%xmm0,%xmm2
++	pxor		%xmm3,%xmm3
++	aesenclast	%xmm3,%xmm2
++
++	movdqa		%xmm1,%xmm3
++	pslldq		\$4,%xmm1
++	pxor		%xmm1,%xmm3
++	pslldq		\$4,%xmm1
++	pxor		%xmm1,%xmm3
++	pslldq		\$4,%xmm1
++	pxor		%xmm3,%xmm1
++
++	pxor		%xmm1,%xmm2
++	movdqu		%xmm2,16(%rax)
++	lea		32(%rax),%rax
++	movdqa		%xmm2,%xmm1
++
++	jmp	.Loop_key256
++
++.Ldone_key256:
++	mov	$bits,16(%rax)	# 240($key)
++	xor	%eax,%eax
++	jmp	.Lenc_key_ret
++
++.align	16
++.Lbad_keybits:
++	mov	\$-2,%rax
++.Lenc_key_ret:
++	pxor	%xmm0,%xmm0
++	pxor	%xmm1,%xmm1
++	pxor	%xmm2,%xmm2
++	pxor	%xmm3,%xmm3
++	pxor	%xmm4,%xmm4
++	pxor	%xmm5,%xmm5
++	add	\$8,%rsp
++	ret
++.LSEH_end_set_encrypt_key:
++
++.align	16
++.Lkey_expansion_128:
++	$movkey	%xmm0,(%rax)
++	lea	16(%rax),%rax
++.Lkey_expansion_128_cold:
++	shufps	\$0b00010000,%xmm0,%xmm4
++	xorps	%xmm4, %xmm0
++	shufps	\$0b10001100,%xmm0,%xmm4
++	xorps	%xmm4, %xmm0
++	shufps	\$0b11111111,%xmm1,%xmm1	# critical path
++	xorps	%xmm1,%xmm0
++	ret
++
++.align 16
++.Lkey_expansion_192a:
++	$movkey	%xmm0,(%rax)
++	lea	16(%rax),%rax
++.Lkey_expansion_192a_cold:
++	movaps	%xmm2, %xmm5
++.Lkey_expansion_192b_warm:
++	shufps	\$0b00010000,%xmm0,%xmm4
++	movdqa	%xmm2,%xmm3
++	xorps	%xmm4,%xmm0
++	shufps	\$0b10001100,%xmm0,%xmm4
++	pslldq	\$4,%xmm3
++	xorps	%xmm4,%xmm0
++	pshufd	\$0b01010101,%xmm1,%xmm1	# critical path
++	pxor	%xmm3,%xmm2
++	pxor	%xmm1,%xmm0
++	pshufd	\$0b11111111,%xmm0,%xmm3
++	pxor	%xmm3,%xmm2
++	ret
++
++.align 16
++.Lkey_expansion_192b:
++	movaps	%xmm0,%xmm3
++	shufps	\$0b01000100,%xmm0,%xmm5
++	$movkey	%xmm5,(%rax)
++	shufps	\$0b01001110,%xmm2,%xmm3
++	$movkey	%xmm3,16(%rax)
++	lea	32(%rax),%rax
++	jmp	.Lkey_expansion_192b_warm
++
++.align	16
++.Lkey_expansion_256a:
++	$movkey	%xmm2,(%rax)
++	lea	16(%rax),%rax
++.Lkey_expansion_256a_cold:
++	shufps	\$0b00010000,%xmm0,%xmm4
++	xorps	%xmm4,%xmm0
++	shufps	\$0b10001100,%xmm0,%xmm4
++	xorps	%xmm4,%xmm0
++	shufps	\$0b11111111,%xmm1,%xmm1	# critical path
++	xorps	%xmm1,%xmm0
++	ret
++
++.align 16
++.Lkey_expansion_256b:
++	$movkey	%xmm0,(%rax)
++	lea	16(%rax),%rax
++
++	shufps	\$0b00010000,%xmm2,%xmm4
++	xorps	%xmm4,%xmm2
++	shufps	\$0b10001100,%xmm2,%xmm4
++	xorps	%xmm4,%xmm2
++	shufps	\$0b10101010,%xmm1,%xmm1	# critical path
++	xorps	%xmm1,%xmm2
++	ret
++.size	${PREFIX}_set_encrypt_key,.-${PREFIX}_set_encrypt_key
++.size	__aesni_set_encrypt_key,.-__aesni_set_encrypt_key
++___
++}
++
++$code.=<<___;
++.align	64
++.Lbswap_mask:
++	.byte	15,14,13,12,11,10,9,8,7,6,5,4,3,2,1,0
++.Lincrement32:
++	.long	6,6,6,0
++.Lincrement64:
++	.long	1,0,0,0
++.Lxts_magic:
++	.long	0x87,0,1,0
++.Lincrement1:
++	.byte	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1
++.Lkey_rotate:
++	.long	0x0c0f0e0d,0x0c0f0e0d,0x0c0f0e0d,0x0c0f0e0d
++.Lkey_rotate192:
++	.long	0x04070605,0x04070605,0x04070605,0x04070605
++.Lkey_rcon1:
++	.long	1,1,1,1
++.Lkey_rcon1b:
++	.long	0x1b,0x1b,0x1b,0x1b
++
++.asciz  "AES for Intel AES-NI, CRYPTOGAMS by "
++.align	64
++___
++
++# EXCEPTION_DISPOSITION handler (EXCEPTION_RECORD *rec,ULONG64 frame,
++#		CONTEXT *context,DISPATCHER_CONTEXT *disp)
++if ($win64) {
++$rec="%rcx";
++$frame="%rdx";
++$context="%r8";
++$disp="%r9";
++
++$code.=<<___;
++.extern	__imp_RtlVirtualUnwind
++___
++$code.=<<___ if ($PREFIX eq "aesni");
++.type	ecb_ccm64_se_handler,\@abi-omnipotent
++.align	16
++ecb_ccm64_se_handler:
++	push	%rsi
++	push	%rdi
++	push	%rbx
++	push	%rbp
++	push	%r12
++	push	%r13
++	push	%r14
++	push	%r15
++	pushfq
++	sub	\$64,%rsp
++
++	mov	120($context),%rax	# pull context->Rax
++	mov	248($context),%rbx	# pull context->Rip
++
++	mov	8($disp),%rsi		# disp->ImageBase
++	mov	56($disp),%r11		# disp->HandlerData
++
++	mov	0(%r11),%r10d		# HandlerData[0]
++	lea	(%rsi,%r10),%r10	# prologue label
++	cmp	%r10,%rbx		# context->RipRsp
++
++	mov	4(%r11),%r10d		# HandlerData[1]
++	lea	(%rsi,%r10),%r10	# epilogue label
++	cmp	%r10,%rbx		# context->Rip>=epilogue label
++	jae	.Lcommon_seh_tail
++
++	lea	0(%rax),%rsi		# %xmm save area
++	lea	512($context),%rdi	# &context.Xmm6
++	mov	\$8,%ecx		# 4*sizeof(%xmm0)/sizeof(%rax)
++	.long	0xa548f3fc		# cld; rep movsq
++	lea	0x58(%rax),%rax		# adjust stack pointer
++
++	jmp	.Lcommon_seh_tail
++.size	ecb_ccm64_se_handler,.-ecb_ccm64_se_handler
++
++.type	ctr_xts_se_handler,\@abi-omnipotent
++.align	16
++ctr_xts_se_handler:
++	push	%rsi
++	push	%rdi
++	push	%rbx
++	push	%rbp
++	push	%r12
++	push	%r13
++	push	%r14
++	push	%r15
++	pushfq
++	sub	\$64,%rsp
++
++	mov	120($context),%rax	# pull context->Rax
++	mov	248($context),%rbx	# pull context->Rip
++
++	mov	8($disp),%rsi		# disp->ImageBase
++	mov	56($disp),%r11		# disp->HandlerData
++
++	mov	0(%r11),%r10d		# HandlerData[0]
++	lea	(%rsi,%r10),%r10	# prologue lable
++	cmp	%r10,%rbx		# context->RipRsp
++
++	mov	4(%r11),%r10d		# HandlerData[1]
++	lea	(%rsi,%r10),%r10	# epilogue label
++	cmp	%r10,%rbx		# context->Rip>=epilogue label
++	jae	.Lcommon_seh_tail
++
++	mov	160($context),%rax	# pull context->Rbp
++	lea	-0xa0(%rax),%rsi	# %xmm save area
++	lea	512($context),%rdi	# & context.Xmm6
++	mov	\$20,%ecx		# 10*sizeof(%xmm0)/sizeof(%rax)
++	.long	0xa548f3fc		# cld; rep movsq
++
++	jmp	.Lcommon_rbp_tail
++.size	ctr_xts_se_handler,.-ctr_xts_se_handler
++
++.type	ocb_se_handler,\@abi-omnipotent
++.align	16
++ocb_se_handler:
++	push	%rsi
++	push	%rdi
++	push	%rbx
++	push	%rbp
++	push	%r12
++	push	%r13
++	push	%r14
++	push	%r15
++	pushfq
++	sub	\$64,%rsp
++
++	mov	120($context),%rax	# pull context->Rax
++	mov	248($context),%rbx	# pull context->Rip
++
++	mov	8($disp),%rsi		# disp->ImageBase
++	mov	56($disp),%r11		# disp->HandlerData
++
++	mov	0(%r11),%r10d		# HandlerData[0]
++	lea	(%rsi,%r10),%r10	# prologue lable
++	cmp	%r10,%rbx		# context->RipRip>=epilogue label
++	jae	.Lcommon_seh_tail
++
++	mov	8(%r11),%r10d		# HandlerData[2]
++	lea	(%rsi,%r10),%r10
++	cmp	%r10,%rbx		# context->Rip>=pop label
++	jae	.Locb_no_xmm
++
++	mov	152($context),%rax	# pull context->Rsp
++
++	lea	(%rax),%rsi		# %xmm save area
++	lea	512($context),%rdi	# & context.Xmm6
++	mov	\$20,%ecx		# 10*sizeof(%xmm0)/sizeof(%rax)
++	.long	0xa548f3fc		# cld; rep movsq
++	lea	0xa0+0x28(%rax),%rax
++
++.Locb_no_xmm:
++	mov	-8(%rax),%rbx
++	mov	-16(%rax),%rbp
++	mov	-24(%rax),%r12
++	mov	-32(%rax),%r13
++	mov	-40(%rax),%r14
++
++	mov	%rbx,144($context)	# restore context->Rbx
++	mov	%rbp,160($context)	# restore context->Rbp
++	mov	%r12,216($context)	# restore context->R12
++	mov	%r13,224($context)	# restore context->R13
++	mov	%r14,232($context)	# restore context->R14
++
++	jmp	.Lcommon_seh_tail
++.size	ocb_se_handler,.-ocb_se_handler
++___
++$code.=<<___;
++.type	cbc_se_handler,\@abi-omnipotent
++.align	16
++cbc_se_handler:
++	push	%rsi
++	push	%rdi
++	push	%rbx
++	push	%rbp
++	push	%r12
++	push	%r13
++	push	%r14
++	push	%r15
++	pushfq
++	sub	\$64,%rsp
++
++	mov	152($context),%rax	# pull context->Rsp
++	mov	248($context),%rbx	# pull context->Rip
++
++	lea	.Lcbc_decrypt_bulk(%rip),%r10
++	cmp	%r10,%rbx		# context->Rip<"prologue" label
++	jb	.Lcommon_seh_tail
++
++	lea	.Lcbc_decrypt_body(%rip),%r10
++	cmp	%r10,%rbx		# context->RipRip>="epilogue" label
++	jae	.Lcommon_seh_tail
++
++	lea	16(%rax),%rsi		# %xmm save area
++	lea	512($context),%rdi	# &context.Xmm6
++	mov	\$20,%ecx		# 10*sizeof(%xmm0)/sizeof(%rax)
++	.long	0xa548f3fc		# cld; rep movsq
++
++.Lcommon_rbp_tail:
++	mov	160($context),%rax	# pull context->Rbp
++	mov	(%rax),%rbp		# restore saved %rbp
++	lea	8(%rax),%rax		# adjust stack pointer
++	mov	%rbp,160($context)	# restore context->Rbp
++	jmp	.Lcommon_seh_tail
++
++.Lrestore_cbc_rax:
++	mov	120($context),%rax
++
++.Lcommon_seh_tail:
++	mov	8(%rax),%rdi
++	mov	16(%rax),%rsi
++	mov	%rax,152($context)	# restore context->Rsp
++	mov	%rsi,168($context)	# restore context->Rsi
++	mov	%rdi,176($context)	# restore context->Rdi
++
++	mov	40($disp),%rdi		# disp->ContextRecord
++	mov	$context,%rsi		# context
++	mov	\$154,%ecx		# sizeof(CONTEXT)
++	.long	0xa548f3fc		# cld; rep movsq
++
++	mov	$disp,%rsi
++	xor	%rcx,%rcx		# arg1, UNW_FLAG_NHANDLER
++	mov	8(%rsi),%rdx		# arg2, disp->ImageBase
++	mov	0(%rsi),%r8		# arg3, disp->ControlPc
++	mov	16(%rsi),%r9		# arg4, disp->FunctionEntry
++	mov	40(%rsi),%r10		# disp->ContextRecord
++	lea	56(%rsi),%r11		# &disp->HandlerData
++	lea	24(%rsi),%r12		# &disp->EstablisherFrame
++	mov	%r10,32(%rsp)		# arg5
++	mov	%r11,40(%rsp)		# arg6
++	mov	%r12,48(%rsp)		# arg7
++	mov	%rcx,56(%rsp)		# arg8, (NULL)
++	call	*__imp_RtlVirtualUnwind(%rip)
++
++	mov	\$1,%eax		# ExceptionContinueSearch
++	add	\$64,%rsp
++	popfq
++	pop	%r15
++	pop	%r14
++	pop	%r13
++	pop	%r12
++	pop	%rbp
++	pop	%rbx
++	pop	%rdi
++	pop	%rsi
++	ret
++.size	cbc_se_handler,.-cbc_se_handler
++
++.section	.pdata
++.align	4
++___
++$code.=<<___ if ($PREFIX eq "aesni");
++	.rva	.LSEH_begin_aesni_ecb_encrypt
++	.rva	.LSEH_end_aesni_ecb_encrypt
++	.rva	.LSEH_info_ecb
++
++	.rva	.LSEH_begin_aesni_ccm64_encrypt_blocks
++	.rva	.LSEH_end_aesni_ccm64_encrypt_blocks
++	.rva	.LSEH_info_ccm64_enc
++
++	.rva	.LSEH_begin_aesni_ccm64_decrypt_blocks
++	.rva	.LSEH_end_aesni_ccm64_decrypt_blocks
++	.rva	.LSEH_info_ccm64_dec
++
++	.rva	.LSEH_begin_aesni_ctr32_encrypt_blocks
++	.rva	.LSEH_end_aesni_ctr32_encrypt_blocks
++	.rva	.LSEH_info_ctr32
++
++	.rva	.LSEH_begin_aesni_xts_encrypt
++	.rva	.LSEH_end_aesni_xts_encrypt
++	.rva	.LSEH_info_xts_enc
++
++	.rva	.LSEH_begin_aesni_xts_decrypt
++	.rva	.LSEH_end_aesni_xts_decrypt
++	.rva	.LSEH_info_xts_dec
++
++	.rva	.LSEH_begin_aesni_ocb_encrypt
++	.rva	.LSEH_end_aesni_ocb_encrypt
++	.rva	.LSEH_info_ocb_enc
++
++	.rva	.LSEH_begin_aesni_ocb_decrypt
++	.rva	.LSEH_end_aesni_ocb_decrypt
++	.rva	.LSEH_info_ocb_dec
++___
++$code.=<<___;
++	.rva	.LSEH_begin_${PREFIX}_cbc_encrypt
++	.rva	.LSEH_end_${PREFIX}_cbc_encrypt
++	.rva	.LSEH_info_cbc
++
++	.rva	${PREFIX}_set_decrypt_key
++	.rva	.LSEH_end_set_decrypt_key
++	.rva	.LSEH_info_key
++
++	.rva	${PREFIX}_set_encrypt_key
++	.rva	.LSEH_end_set_encrypt_key
++	.rva	.LSEH_info_key
++.section	.xdata
++.align	8
++___
++$code.=<<___ if ($PREFIX eq "aesni");
++.LSEH_info_ecb:
++	.byte	9,0,0,0
++	.rva	ecb_ccm64_se_handler
++	.rva	.Lecb_enc_body,.Lecb_enc_ret		# HandlerData[]
++.LSEH_info_ccm64_enc:
++	.byte	9,0,0,0
++	.rva	ecb_ccm64_se_handler
++	.rva	.Lccm64_enc_body,.Lccm64_enc_ret	# HandlerData[]
++.LSEH_info_ccm64_dec:
++	.byte	9,0,0,0
++	.rva	ecb_ccm64_se_handler
++	.rva	.Lccm64_dec_body,.Lccm64_dec_ret	# HandlerData[]
++.LSEH_info_ctr32:
++	.byte	9,0,0,0
++	.rva	ctr_xts_se_handler
++	.rva	.Lctr32_body,.Lctr32_epilogue		# HandlerData[]
++.LSEH_info_xts_enc:
++	.byte	9,0,0,0
++	.rva	ctr_xts_se_handler
++	.rva	.Lxts_enc_body,.Lxts_enc_epilogue	# HandlerData[]
++.LSEH_info_xts_dec:
++	.byte	9,0,0,0
++	.rva	ctr_xts_se_handler
++	.rva	.Lxts_dec_body,.Lxts_dec_epilogue	# HandlerData[]
++.LSEH_info_ocb_enc:
++	.byte	9,0,0,0
++	.rva	ocb_se_handler
++	.rva	.Locb_enc_body,.Locb_enc_epilogue	# HandlerData[]
++	.rva	.Locb_enc_pop
++	.long	0
++.LSEH_info_ocb_dec:
++	.byte	9,0,0,0
++	.rva	ocb_se_handler
++	.rva	.Locb_dec_body,.Locb_dec_epilogue	# HandlerData[]
++	.rva	.Locb_dec_pop
++	.long	0
++___
++$code.=<<___;
++.LSEH_info_cbc:
++	.byte	9,0,0,0
++	.rva	cbc_se_handler
++.LSEH_info_key:
++	.byte	0x01,0x04,0x01,0x00
++	.byte	0x04,0x02,0x00,0x00	# sub rsp,8
++___
++}
++
++sub rex {
++  local *opcode=shift;
++  my ($dst,$src)=@_;
++  my $rex=0;
++
++    $rex|=0x04			if($dst>=8);
++    $rex|=0x01			if($src>=8);
++    push @opcode,$rex|0x40	if($rex);
++}
++
++sub aesni {
++  my $line=shift;
++  my @opcode=(0x66);
++
++    if ($line=~/(aeskeygenassist)\s+\$([x0-9a-f]+),\s*%xmm([0-9]+),\s*%xmm([0-9]+)/) {
++	rex(\@opcode,$4,$3);
++	push @opcode,0x0f,0x3a,0xdf;
++	push @opcode,0xc0|($3&7)|(($4&7)<<3);	# ModR/M
++	my $c=$2;
++	push @opcode,$c=~/^0/?oct($c):$c;
++	return ".byte\t".join(',',@opcode);
++    }
++    elsif ($line=~/(aes[a-z]+)\s+%xmm([0-9]+),\s*%xmm([0-9]+)/) {
++	my %opcodelet = (
++		"aesimc" => 0xdb,
++		"aesenc" => 0xdc,	"aesenclast" => 0xdd,
++		"aesdec" => 0xde,	"aesdeclast" => 0xdf
++	);
++	return undef if (!defined($opcodelet{$1}));
++	rex(\@opcode,$3,$2);
++	push @opcode,0x0f,0x38,$opcodelet{$1};
++	push @opcode,0xc0|($2&7)|(($3&7)<<3);	# ModR/M
++	return ".byte\t".join(',',@opcode);
++    }
++    elsif ($line=~/(aes[a-z]+)\s+([0x1-9a-fA-F]*)\(%rsp\),\s*%xmm([0-9]+)/) {
++	my %opcodelet = (
++		"aesenc" => 0xdc,	"aesenclast" => 0xdd,
++		"aesdec" => 0xde,	"aesdeclast" => 0xdf
++	);
++	return undef if (!defined($opcodelet{$1}));
++	my $off = $2;
++	push @opcode,0x44 if ($3>=8);
++	push @opcode,0x0f,0x38,$opcodelet{$1};
++	push @opcode,0x44|(($3&7)<<3),0x24;	# ModR/M
++	push @opcode,($off=~/^0/?oct($off):$off)&0xff;
++	return ".byte\t".join(',',@opcode);
++    }
++    return $line;
++}
++
++sub movbe {
++	".byte	0x0f,0x38,0xf1,0x44,0x24,".shift;
++}
++
++$code =~ s/\`([^\`]*)\`/eval($1)/gem;
++$code =~ s/\b(aes.*%xmm[0-9]+).*$/aesni($1)/gem;
++#$code =~ s/\bmovbe\s+%eax/bswap %eax; mov %eax/gm;	# debugging artefact
++$code =~ s/\bmovbe\s+%eax,\s*([0-9]+)\(%rsp\)/movbe($1)/gem;
++
++print $code;
++
++close STDOUT;
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/aes/asm/aesp8-ppc.pl b/CryptoPkg/Library/OpensslLib/openssl/crypto/aes/asm/aesp8-ppc.pl
+new file mode 100755
+index 0000000..b7e92f6
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/aes/asm/aesp8-ppc.pl
+@@ -0,0 +1,3805 @@
++#! /usr/bin/env perl
++# Copyright 2014-2016 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
++# in the file LICENSE in the source distribution or at
++# https://www.openssl.org/source/license.html
++
++#
++# ====================================================================
++# Written by Andy Polyakov  for the OpenSSL
++# project. The module is, however, dual licensed under OpenSSL and
++# CRYPTOGAMS licenses depending on where you obtain it. For further
++# details see http://www.openssl.org/~appro/cryptogams/.
++# ====================================================================
++#
++# This module implements support for AES instructions as per PowerISA
++# specification version 2.07, first implemented by POWER8 processor.
++# The module is endian-agnostic in sense that it supports both big-
++# and little-endian cases. Data alignment in parallelizable modes is
++# handled with VSX loads and stores, which implies MSR.VSX flag being
++# set. It should also be noted that ISA specification doesn't prohibit
++# alignment exceptions for these instructions on page boundaries.
++# Initially alignment was handled in pure AltiVec/VMX way [when data
++# is aligned programmatically, which in turn guarantees exception-
++# free execution], but it turned to hamper performance when vcipher
++# instructions are interleaved. It's reckoned that eventual
++# misalignment penalties at page boundaries are in average lower
++# than additional overhead in pure AltiVec approach.
++#
++# May 2016
++#
++# Add XTS subroutine, 9x on little- and 12x improvement on big-endian
++# systems were measured.
++#
++######################################################################
++# Current large-block performance in cycles per byte processed with
++# 128-bit key (less is better).
++#
++#		CBC en-/decrypt	CTR	XTS
++# POWER8[le]	3.96/0.72	0.74	1.1
++# POWER8[be]	3.75/0.65	0.66	1.0
++
++$flavour = shift;
++
++if ($flavour =~ /64/) {
++	$SIZE_T	=8;
++	$LRSAVE	=2*$SIZE_T;
++	$STU	="stdu";
++	$POP	="ld";
++	$PUSH	="std";
++	$UCMP	="cmpld";
++	$SHL	="sldi";
++} elsif ($flavour =~ /32/) {
++	$SIZE_T	=4;
++	$LRSAVE	=$SIZE_T;
++	$STU	="stwu";
++	$POP	="lwz";
++	$PUSH	="stw";
++	$UCMP	="cmplw";
++	$SHL	="slwi";
++} else { die "nonsense $flavour"; }
++
++$LITTLE_ENDIAN = ($flavour=~/le$/) ? $SIZE_T : 0;
++
++$0 =~ m/(.*[\/\\])[^\/\\]+$/; $dir=$1;
++( $xlate="${dir}ppc-xlate.pl" and -f $xlate ) or
++( $xlate="${dir}../../perlasm/ppc-xlate.pl" and -f $xlate) or
++die "can't locate ppc-xlate.pl";
++
++open STDOUT,"| $^X $xlate $flavour ".shift || die "can't call $xlate: $!";
++
++$FRAME=8*$SIZE_T;
++$prefix="aes_p8";
++
++$sp="r1";
++$vrsave="r12";
++
++#########################################################################
++{{{	# Key setup procedures						#
++my ($inp,$bits,$out,$ptr,$cnt,$rounds)=map("r$_",(3..8));
++my ($zero,$in0,$in1,$key,$rcon,$mask,$tmp)=map("v$_",(0..6));
++my ($stage,$outperm,$outmask,$outhead,$outtail)=map("v$_",(7..11));
++
++$code.=<<___;
++.machine	"any"
++
++.text
++
++.align	7
++rcon:
++.long	0x01000000, 0x01000000, 0x01000000, 0x01000000	?rev
++.long	0x1b000000, 0x1b000000, 0x1b000000, 0x1b000000	?rev
++.long	0x0d0e0f0c, 0x0d0e0f0c, 0x0d0e0f0c, 0x0d0e0f0c	?rev
++.long	0,0,0,0						?asis
++Lconsts:
++	mflr	r0
++	bcl	20,31,\$+4
++	mflr	$ptr	 #vvvvv "distance between . and rcon
++	addi	$ptr,$ptr,-0x48
++	mtlr	r0
++	blr
++	.long	0
++	.byte	0,12,0x14,0,0,0,0,0
++.asciz	"AES for PowerISA 2.07, CRYPTOGAMS by "
++
++.globl	.${prefix}_set_encrypt_key
++.align	5
++.${prefix}_set_encrypt_key:
++Lset_encrypt_key:
++	mflr		r11
++	$PUSH		r11,$LRSAVE($sp)
++
++	li		$ptr,-1
++	${UCMP}i	$inp,0
++	beq-		Lenc_key_abort		# if ($inp==0) return -1;
++	${UCMP}i	$out,0
++	beq-		Lenc_key_abort		# if ($out==0) return -1;
++	li		$ptr,-2
++	cmpwi		$bits,128
++	blt-		Lenc_key_abort
++	cmpwi		$bits,256
++	bgt-		Lenc_key_abort
++	andi.		r0,$bits,0x3f
++	bne-		Lenc_key_abort
++
++	lis		r0,0xfff0
++	mfspr		$vrsave,256
++	mtspr		256,r0
++
++	bl		Lconsts
++	mtlr		r11
++
++	neg		r9,$inp
++	lvx		$in0,0,$inp
++	addi		$inp,$inp,15		# 15 is not typo
++	lvsr		$key,0,r9		# borrow $key
++	li		r8,0x20
++	cmpwi		$bits,192
++	lvx		$in1,0,$inp
++	le?vspltisb	$mask,0x0f		# borrow $mask
++	lvx		$rcon,0,$ptr
++	le?vxor		$key,$key,$mask		# adjust for byte swap
++	lvx		$mask,r8,$ptr
++	addi		$ptr,$ptr,0x10
++	vperm		$in0,$in0,$in1,$key	# align [and byte swap in LE]
++	li		$cnt,8
++	vxor		$zero,$zero,$zero
++	mtctr		$cnt
++
++	?lvsr		$outperm,0,$out
++	vspltisb	$outmask,-1
++	lvx		$outhead,0,$out
++	?vperm		$outmask,$zero,$outmask,$outperm
++
++	blt		Loop128
++	addi		$inp,$inp,8
++	beq		L192
++	addi		$inp,$inp,8
++	b		L256
++
++.align	4
++Loop128:
++	vperm		$key,$in0,$in0,$mask	# rotate-n-splat
++	vsldoi		$tmp,$zero,$in0,12	# >>32
++	 vperm		$outtail,$in0,$in0,$outperm	# rotate
++	 vsel		$stage,$outhead,$outtail,$outmask
++	 vmr		$outhead,$outtail
++	vcipherlast	$key,$key,$rcon
++	 stvx		$stage,0,$out
++	 addi		$out,$out,16
++
++	vxor		$in0,$in0,$tmp
++	vsldoi		$tmp,$zero,$tmp,12	# >>32
++	vxor		$in0,$in0,$tmp
++	vsldoi		$tmp,$zero,$tmp,12	# >>32
++	vxor		$in0,$in0,$tmp
++	 vadduwm	$rcon,$rcon,$rcon
++	vxor		$in0,$in0,$key
++	bdnz		Loop128
++
++	lvx		$rcon,0,$ptr		# last two round keys
++
++	vperm		$key,$in0,$in0,$mask	# rotate-n-splat
++	vsldoi		$tmp,$zero,$in0,12	# >>32
++	 vperm		$outtail,$in0,$in0,$outperm	# rotate
++	 vsel		$stage,$outhead,$outtail,$outmask
++	 vmr		$outhead,$outtail
++	vcipherlast	$key,$key,$rcon
++	 stvx		$stage,0,$out
++	 addi		$out,$out,16
++
++	vxor		$in0,$in0,$tmp
++	vsldoi		$tmp,$zero,$tmp,12	# >>32
++	vxor		$in0,$in0,$tmp
++	vsldoi		$tmp,$zero,$tmp,12	# >>32
++	vxor		$in0,$in0,$tmp
++	 vadduwm	$rcon,$rcon,$rcon
++	vxor		$in0,$in0,$key
++
++	vperm		$key,$in0,$in0,$mask	# rotate-n-splat
++	vsldoi		$tmp,$zero,$in0,12	# >>32
++	 vperm		$outtail,$in0,$in0,$outperm	# rotate
++	 vsel		$stage,$outhead,$outtail,$outmask
++	 vmr		$outhead,$outtail
++	vcipherlast	$key,$key,$rcon
++	 stvx		$stage,0,$out
++	 addi		$out,$out,16
++
++	vxor		$in0,$in0,$tmp
++	vsldoi		$tmp,$zero,$tmp,12	# >>32
++	vxor		$in0,$in0,$tmp
++	vsldoi		$tmp,$zero,$tmp,12	# >>32
++	vxor		$in0,$in0,$tmp
++	vxor		$in0,$in0,$key
++	 vperm		$outtail,$in0,$in0,$outperm	# rotate
++	 vsel		$stage,$outhead,$outtail,$outmask
++	 vmr		$outhead,$outtail
++	 stvx		$stage,0,$out
++
++	addi		$inp,$out,15		# 15 is not typo
++	addi		$out,$out,0x50
++
++	li		$rounds,10
++	b		Ldone
++
++.align	4
++L192:
++	lvx		$tmp,0,$inp
++	li		$cnt,4
++	 vperm		$outtail,$in0,$in0,$outperm	# rotate
++	 vsel		$stage,$outhead,$outtail,$outmask
++	 vmr		$outhead,$outtail
++	 stvx		$stage,0,$out
++	 addi		$out,$out,16
++	vperm		$in1,$in1,$tmp,$key	# align [and byte swap in LE]
++	vspltisb	$key,8			# borrow $key
++	mtctr		$cnt
++	vsububm		$mask,$mask,$key	# adjust the mask
++
++Loop192:
++	vperm		$key,$in1,$in1,$mask	# roate-n-splat
++	vsldoi		$tmp,$zero,$in0,12	# >>32
++	vcipherlast	$key,$key,$rcon
++
++	vxor		$in0,$in0,$tmp
++	vsldoi		$tmp,$zero,$tmp,12	# >>32
++	vxor		$in0,$in0,$tmp
++	vsldoi		$tmp,$zero,$tmp,12	# >>32
++	vxor		$in0,$in0,$tmp
++
++	 vsldoi		$stage,$zero,$in1,8
++	vspltw		$tmp,$in0,3
++	vxor		$tmp,$tmp,$in1
++	vsldoi		$in1,$zero,$in1,12	# >>32
++	 vadduwm	$rcon,$rcon,$rcon
++	vxor		$in1,$in1,$tmp
++	vxor		$in0,$in0,$key
++	vxor		$in1,$in1,$key
++	 vsldoi		$stage,$stage,$in0,8
++
++	vperm		$key,$in1,$in1,$mask	# rotate-n-splat
++	vsldoi		$tmp,$zero,$in0,12	# >>32
++	 vperm		$outtail,$stage,$stage,$outperm	# rotate
++	 vsel		$stage,$outhead,$outtail,$outmask
++	 vmr		$outhead,$outtail
++	vcipherlast	$key,$key,$rcon
++	 stvx		$stage,0,$out
++	 addi		$out,$out,16
++
++	 vsldoi		$stage,$in0,$in1,8
++	vxor		$in0,$in0,$tmp
++	vsldoi		$tmp,$zero,$tmp,12	# >>32
++	 vperm		$outtail,$stage,$stage,$outperm	# rotate
++	 vsel		$stage,$outhead,$outtail,$outmask
++	 vmr		$outhead,$outtail
++	vxor		$in0,$in0,$tmp
++	vsldoi		$tmp,$zero,$tmp,12	# >>32
++	vxor		$in0,$in0,$tmp
++	 stvx		$stage,0,$out
++	 addi		$out,$out,16
++
++	vspltw		$tmp,$in0,3
++	vxor		$tmp,$tmp,$in1
++	vsldoi		$in1,$zero,$in1,12	# >>32
++	 vadduwm	$rcon,$rcon,$rcon
++	vxor		$in1,$in1,$tmp
++	vxor		$in0,$in0,$key
++	vxor		$in1,$in1,$key
++	 vperm		$outtail,$in0,$in0,$outperm	# rotate
++	 vsel		$stage,$outhead,$outtail,$outmask
++	 vmr		$outhead,$outtail
++	 stvx		$stage,0,$out
++	 addi		$inp,$out,15		# 15 is not typo
++	 addi		$out,$out,16
++	bdnz		Loop192
++
++	li		$rounds,12
++	addi		$out,$out,0x20
++	b		Ldone
++
++.align	4
++L256:
++	lvx		$tmp,0,$inp
++	li		$cnt,7
++	li		$rounds,14
++	 vperm		$outtail,$in0,$in0,$outperm	# rotate
++	 vsel		$stage,$outhead,$outtail,$outmask
++	 vmr		$outhead,$outtail
++	 stvx		$stage,0,$out
++	 addi		$out,$out,16
++	vperm		$in1,$in1,$tmp,$key	# align [and byte swap in LE]
++	mtctr		$cnt
++
++Loop256:
++	vperm		$key,$in1,$in1,$mask	# rotate-n-splat
++	vsldoi		$tmp,$zero,$in0,12	# >>32
++	 vperm		$outtail,$in1,$in1,$outperm	# rotate
++	 vsel		$stage,$outhead,$outtail,$outmask
++	 vmr		$outhead,$outtail
++	vcipherlast	$key,$key,$rcon
++	 stvx		$stage,0,$out
++	 addi		$out,$out,16
++
++	vxor		$in0,$in0,$tmp
++	vsldoi		$tmp,$zero,$tmp,12	# >>32
++	vxor		$in0,$in0,$tmp
++	vsldoi		$tmp,$zero,$tmp,12	# >>32
++	vxor		$in0,$in0,$tmp
++	 vadduwm	$rcon,$rcon,$rcon
++	vxor		$in0,$in0,$key
++	 vperm		$outtail,$in0,$in0,$outperm	# rotate
++	 vsel		$stage,$outhead,$outtail,$outmask
++	 vmr		$outhead,$outtail
++	 stvx		$stage,0,$out
++	 addi		$inp,$out,15		# 15 is not typo
++	 addi		$out,$out,16
++	bdz		Ldone
++
++	vspltw		$key,$in0,3		# just splat
++	vsldoi		$tmp,$zero,$in1,12	# >>32
++	vsbox		$key,$key
++
++	vxor		$in1,$in1,$tmp
++	vsldoi		$tmp,$zero,$tmp,12	# >>32
++	vxor		$in1,$in1,$tmp
++	vsldoi		$tmp,$zero,$tmp,12	# >>32
++	vxor		$in1,$in1,$tmp
++
++	vxor		$in1,$in1,$key
++	b		Loop256
++
++.align	4
++Ldone:
++	lvx		$in1,0,$inp		# redundant in aligned case
++	vsel		$in1,$outhead,$in1,$outmask
++	stvx		$in1,0,$inp
++	li		$ptr,0
++	mtspr		256,$vrsave
++	stw		$rounds,0($out)
++
++Lenc_key_abort:
++	mr		r3,$ptr
++	blr
++	.long		0
++	.byte		0,12,0x14,1,0,0,3,0
++	.long		0
++.size	.${prefix}_set_encrypt_key,.-.${prefix}_set_encrypt_key
++
++.globl	.${prefix}_set_decrypt_key
++.align	5
++.${prefix}_set_decrypt_key:
++	$STU		$sp,-$FRAME($sp)
++	mflr		r10
++	$PUSH		r10,$FRAME+$LRSAVE($sp)
++	bl		Lset_encrypt_key
++	mtlr		r10
++
++	cmpwi		r3,0
++	bne-		Ldec_key_abort
++
++	slwi		$cnt,$rounds,4
++	subi		$inp,$out,240		# first round key
++	srwi		$rounds,$rounds,1
++	add		$out,$inp,$cnt		# last round key
++	mtctr		$rounds
++
++Ldeckey:
++	lwz		r0, 0($inp)
++	lwz		r6, 4($inp)
++	lwz		r7, 8($inp)
++	lwz		r8, 12($inp)
++	addi		$inp,$inp,16
++	lwz		r9, 0($out)
++	lwz		r10,4($out)
++	lwz		r11,8($out)
++	lwz		r12,12($out)
++	stw		r0, 0($out)
++	stw		r6, 4($out)
++	stw		r7, 8($out)
++	stw		r8, 12($out)
++	subi		$out,$out,16
++	stw		r9, -16($inp)
++	stw		r10,-12($inp)
++	stw		r11,-8($inp)
++	stw		r12,-4($inp)
++	bdnz		Ldeckey
++
++	xor		r3,r3,r3		# return value
++Ldec_key_abort:
++	addi		$sp,$sp,$FRAME
++	blr
++	.long		0
++	.byte		0,12,4,1,0x80,0,3,0
++	.long		0
++.size	.${prefix}_set_decrypt_key,.-.${prefix}_set_decrypt_key
++___
++}}}
++#########################################################################
++{{{	# Single block en- and decrypt procedures			#
++sub gen_block () {
++my $dir = shift;
++my $n   = $dir eq "de" ? "n" : "";
++my ($inp,$out,$key,$rounds,$idx)=map("r$_",(3..7));
++
++$code.=<<___;
++.globl	.${prefix}_${dir}crypt
++.align	5
++.${prefix}_${dir}crypt:
++	lwz		$rounds,240($key)
++	lis		r0,0xfc00
++	mfspr		$vrsave,256
++	li		$idx,15			# 15 is not typo
++	mtspr		256,r0
++
++	lvx		v0,0,$inp
++	neg		r11,$out
++	lvx		v1,$idx,$inp
++	lvsl		v2,0,$inp		# inpperm
++	le?vspltisb	v4,0x0f
++	?lvsl		v3,0,r11		# outperm
++	le?vxor		v2,v2,v4
++	li		$idx,16
++	vperm		v0,v0,v1,v2		# align [and byte swap in LE]
++	lvx		v1,0,$key
++	?lvsl		v5,0,$key		# keyperm
++	srwi		$rounds,$rounds,1
++	lvx		v2,$idx,$key
++	addi		$idx,$idx,16
++	subi		$rounds,$rounds,1
++	?vperm		v1,v1,v2,v5		# align round key
++
++	vxor		v0,v0,v1
++	lvx		v1,$idx,$key
++	addi		$idx,$idx,16
++	mtctr		$rounds
++
++Loop_${dir}c:
++	?vperm		v2,v2,v1,v5
++	v${n}cipher	v0,v0,v2
++	lvx		v2,$idx,$key
++	addi		$idx,$idx,16
++	?vperm		v1,v1,v2,v5
++	v${n}cipher	v0,v0,v1
++	lvx		v1,$idx,$key
++	addi		$idx,$idx,16
++	bdnz		Loop_${dir}c
++
++	?vperm		v2,v2,v1,v5
++	v${n}cipher	v0,v0,v2
++	lvx		v2,$idx,$key
++	?vperm		v1,v1,v2,v5
++	v${n}cipherlast	v0,v0,v1
++
++	vspltisb	v2,-1
++	vxor		v1,v1,v1
++	li		$idx,15			# 15 is not typo
++	?vperm		v2,v1,v2,v3		# outmask
++	le?vxor		v3,v3,v4
++	lvx		v1,0,$out		# outhead
++	vperm		v0,v0,v0,v3		# rotate [and byte swap in LE]
++	vsel		v1,v1,v0,v2
++	lvx		v4,$idx,$out
++	stvx		v1,0,$out
++	vsel		v0,v0,v4,v2
++	stvx		v0,$idx,$out
++
++	mtspr		256,$vrsave
++	blr
++	.long		0
++	.byte		0,12,0x14,0,0,0,3,0
++	.long		0
++.size	.${prefix}_${dir}crypt,.-.${prefix}_${dir}crypt
++___
++}
++&gen_block("en");
++&gen_block("de");
++}}}
++#########################################################################
++{{{	# CBC en- and decrypt procedures				#
++my ($inp,$out,$len,$key,$ivp,$enc,$rounds,$idx)=map("r$_",(3..10));
++my ($rndkey0,$rndkey1,$inout,$tmp)=		map("v$_",(0..3));
++my ($ivec,$inptail,$inpperm,$outhead,$outperm,$outmask,$keyperm)=
++						map("v$_",(4..10));
++$code.=<<___;
++.globl	.${prefix}_cbc_encrypt
++.align	5
++.${prefix}_cbc_encrypt:
++	${UCMP}i	$len,16
++	bltlr-
++
++	cmpwi		$enc,0			# test direction
++	lis		r0,0xffe0
++	mfspr		$vrsave,256
++	mtspr		256,r0
++
++	li		$idx,15
++	vxor		$rndkey0,$rndkey0,$rndkey0
++	le?vspltisb	$tmp,0x0f
++
++	lvx		$ivec,0,$ivp		# load [unaligned] iv
++	lvsl		$inpperm,0,$ivp
++	lvx		$inptail,$idx,$ivp
++	le?vxor		$inpperm,$inpperm,$tmp
++	vperm		$ivec,$ivec,$inptail,$inpperm
++
++	neg		r11,$inp
++	?lvsl		$keyperm,0,$key		# prepare for unaligned key
++	lwz		$rounds,240($key)
++
++	lvsr		$inpperm,0,r11		# prepare for unaligned load
++	lvx		$inptail,0,$inp
++	addi		$inp,$inp,15		# 15 is not typo
++	le?vxor		$inpperm,$inpperm,$tmp
++
++	?lvsr		$outperm,0,$out		# prepare for unaligned store
++	vspltisb	$outmask,-1
++	lvx		$outhead,0,$out
++	?vperm		$outmask,$rndkey0,$outmask,$outperm
++	le?vxor		$outperm,$outperm,$tmp
++
++	srwi		$rounds,$rounds,1
++	li		$idx,16
++	subi		$rounds,$rounds,1
++	beq		Lcbc_dec
++
++Lcbc_enc:
++	vmr		$inout,$inptail
++	lvx		$inptail,0,$inp
++	addi		$inp,$inp,16
++	mtctr		$rounds
++	subi		$len,$len,16		# len-=16
++
++	lvx		$rndkey0,0,$key
++	 vperm		$inout,$inout,$inptail,$inpperm
++	lvx		$rndkey1,$idx,$key
++	addi		$idx,$idx,16
++	?vperm		$rndkey0,$rndkey0,$rndkey1,$keyperm
++	vxor		$inout,$inout,$rndkey0
++	lvx		$rndkey0,$idx,$key
++	addi		$idx,$idx,16
++	vxor		$inout,$inout,$ivec
++
++Loop_cbc_enc:
++	?vperm		$rndkey1,$rndkey1,$rndkey0,$keyperm
++	vcipher		$inout,$inout,$rndkey1
++	lvx		$rndkey1,$idx,$key
++	addi		$idx,$idx,16
++	?vperm		$rndkey0,$rndkey0,$rndkey1,$keyperm
++	vcipher		$inout,$inout,$rndkey0
++	lvx		$rndkey0,$idx,$key
++	addi		$idx,$idx,16
++	bdnz		Loop_cbc_enc
++
++	?vperm		$rndkey1,$rndkey1,$rndkey0,$keyperm
++	vcipher		$inout,$inout,$rndkey1
++	lvx		$rndkey1,$idx,$key
++	li		$idx,16
++	?vperm		$rndkey0,$rndkey0,$rndkey1,$keyperm
++	vcipherlast	$ivec,$inout,$rndkey0
++	${UCMP}i	$len,16
++
++	vperm		$tmp,$ivec,$ivec,$outperm
++	vsel		$inout,$outhead,$tmp,$outmask
++	vmr		$outhead,$tmp
++	stvx		$inout,0,$out
++	addi		$out,$out,16
++	bge		Lcbc_enc
++
++	b		Lcbc_done
++
++.align	4
++Lcbc_dec:
++	${UCMP}i	$len,128
++	bge		_aesp8_cbc_decrypt8x
++	vmr		$tmp,$inptail
++	lvx		$inptail,0,$inp
++	addi		$inp,$inp,16
++	mtctr		$rounds
++	subi		$len,$len,16		# len-=16
++
++	lvx		$rndkey0,0,$key
++	 vperm		$tmp,$tmp,$inptail,$inpperm
++	lvx		$rndkey1,$idx,$key
++	addi		$idx,$idx,16
++	?vperm		$rndkey0,$rndkey0,$rndkey1,$keyperm
++	vxor		$inout,$tmp,$rndkey0
++	lvx		$rndkey0,$idx,$key
++	addi		$idx,$idx,16
++
++Loop_cbc_dec:
++	?vperm		$rndkey1,$rndkey1,$rndkey0,$keyperm
++	vncipher	$inout,$inout,$rndkey1
++	lvx		$rndkey1,$idx,$key
++	addi		$idx,$idx,16
++	?vperm		$rndkey0,$rndkey0,$rndkey1,$keyperm
++	vncipher	$inout,$inout,$rndkey0
++	lvx		$rndkey0,$idx,$key
++	addi		$idx,$idx,16
++	bdnz		Loop_cbc_dec
++
++	?vperm		$rndkey1,$rndkey1,$rndkey0,$keyperm
++	vncipher	$inout,$inout,$rndkey1
++	lvx		$rndkey1,$idx,$key
++	li		$idx,16
++	?vperm		$rndkey0,$rndkey0,$rndkey1,$keyperm
++	vncipherlast	$inout,$inout,$rndkey0
++	${UCMP}i	$len,16
++
++	vxor		$inout,$inout,$ivec
++	vmr		$ivec,$tmp
++	vperm		$tmp,$inout,$inout,$outperm
++	vsel		$inout,$outhead,$tmp,$outmask
++	vmr		$outhead,$tmp
++	stvx		$inout,0,$out
++	addi		$out,$out,16
++	bge		Lcbc_dec
++
++Lcbc_done:
++	addi		$out,$out,-1
++	lvx		$inout,0,$out		# redundant in aligned case
++	vsel		$inout,$outhead,$inout,$outmask
++	stvx		$inout,0,$out
++
++	neg		$enc,$ivp		# write [unaligned] iv
++	li		$idx,15			# 15 is not typo
++	vxor		$rndkey0,$rndkey0,$rndkey0
++	vspltisb	$outmask,-1
++	le?vspltisb	$tmp,0x0f
++	?lvsl		$outperm,0,$enc
++	?vperm		$outmask,$rndkey0,$outmask,$outperm
++	le?vxor		$outperm,$outperm,$tmp
++	lvx		$outhead,0,$ivp
++	vperm		$ivec,$ivec,$ivec,$outperm
++	vsel		$inout,$outhead,$ivec,$outmask
++	lvx		$inptail,$idx,$ivp
++	stvx		$inout,0,$ivp
++	vsel		$inout,$ivec,$inptail,$outmask
++	stvx		$inout,$idx,$ivp
++
++	mtspr		256,$vrsave
++	blr
++	.long		0
++	.byte		0,12,0x14,0,0,0,6,0
++	.long		0
++___
++#########################################################################
++{{	# Optimized CBC decrypt procedure				#
++my $key_="r11";
++my ($x00,$x10,$x20,$x30,$x40,$x50,$x60,$x70)=map("r$_",(0,8,26..31));
++    $x00=0 if ($flavour =~ /osx/);
++my ($in0, $in1, $in2, $in3, $in4, $in5, $in6, $in7 )=map("v$_",(0..3,10..13));
++my ($out0,$out1,$out2,$out3,$out4,$out5,$out6,$out7)=map("v$_",(14..21));
++my $rndkey0="v23";	# v24-v25 rotating buffer for first found keys
++			# v26-v31 last 6 round keys
++my ($tmp,$keyperm)=($in3,$in4);	# aliases with "caller", redundant assignment
++
++$code.=<<___;
++.align	5
++_aesp8_cbc_decrypt8x:
++	$STU		$sp,-`($FRAME+21*16+6*$SIZE_T)`($sp)
++	li		r10,`$FRAME+8*16+15`
++	li		r11,`$FRAME+8*16+31`
++	stvx		v20,r10,$sp		# ABI says so
++	addi		r10,r10,32
++	stvx		v21,r11,$sp
++	addi		r11,r11,32
++	stvx		v22,r10,$sp
++	addi		r10,r10,32
++	stvx		v23,r11,$sp
++	addi		r11,r11,32
++	stvx		v24,r10,$sp
++	addi		r10,r10,32
++	stvx		v25,r11,$sp
++	addi		r11,r11,32
++	stvx		v26,r10,$sp
++	addi		r10,r10,32
++	stvx		v27,r11,$sp
++	addi		r11,r11,32
++	stvx		v28,r10,$sp
++	addi		r10,r10,32
++	stvx		v29,r11,$sp
++	addi		r11,r11,32
++	stvx		v30,r10,$sp
++	stvx		v31,r11,$sp
++	li		r0,-1
++	stw		$vrsave,`$FRAME+21*16-4`($sp)	# save vrsave
++	li		$x10,0x10
++	$PUSH		r26,`$FRAME+21*16+0*$SIZE_T`($sp)
++	li		$x20,0x20
++	$PUSH		r27,`$FRAME+21*16+1*$SIZE_T`($sp)
++	li		$x30,0x30
++	$PUSH		r28,`$FRAME+21*16+2*$SIZE_T`($sp)
++	li		$x40,0x40
++	$PUSH		r29,`$FRAME+21*16+3*$SIZE_T`($sp)
++	li		$x50,0x50
++	$PUSH		r30,`$FRAME+21*16+4*$SIZE_T`($sp)
++	li		$x60,0x60
++	$PUSH		r31,`$FRAME+21*16+5*$SIZE_T`($sp)
++	li		$x70,0x70
++	mtspr		256,r0
++
++	subi		$rounds,$rounds,3	# -4 in total
++	subi		$len,$len,128		# bias
++
++	lvx		$rndkey0,$x00,$key	# load key schedule
++	lvx		v30,$x10,$key
++	addi		$key,$key,0x20
++	lvx		v31,$x00,$key
++	?vperm		$rndkey0,$rndkey0,v30,$keyperm
++	addi		$key_,$sp,$FRAME+15
++	mtctr		$rounds
++
++Load_cbc_dec_key:
++	?vperm		v24,v30,v31,$keyperm
++	lvx		v30,$x10,$key
++	addi		$key,$key,0x20
++	stvx		v24,$x00,$key_		# off-load round[1]
++	?vperm		v25,v31,v30,$keyperm
++	lvx		v31,$x00,$key
++	stvx		v25,$x10,$key_		# off-load round[2]
++	addi		$key_,$key_,0x20
++	bdnz		Load_cbc_dec_key
++
++	lvx		v26,$x10,$key
++	?vperm		v24,v30,v31,$keyperm
++	lvx		v27,$x20,$key
++	stvx		v24,$x00,$key_		# off-load round[3]
++	?vperm		v25,v31,v26,$keyperm
++	lvx		v28,$x30,$key
++	stvx		v25,$x10,$key_		# off-load round[4]
++	addi		$key_,$sp,$FRAME+15	# rewind $key_
++	?vperm		v26,v26,v27,$keyperm
++	lvx		v29,$x40,$key
++	?vperm		v27,v27,v28,$keyperm
++	lvx		v30,$x50,$key
++	?vperm		v28,v28,v29,$keyperm
++	lvx		v31,$x60,$key
++	?vperm		v29,v29,v30,$keyperm
++	lvx		$out0,$x70,$key		# borrow $out0
++	?vperm		v30,v30,v31,$keyperm
++	lvx		v24,$x00,$key_		# pre-load round[1]
++	?vperm		v31,v31,$out0,$keyperm
++	lvx		v25,$x10,$key_		# pre-load round[2]
++
++	#lvx		$inptail,0,$inp		# "caller" already did this
++	#addi		$inp,$inp,15		# 15 is not typo
++	subi		$inp,$inp,15		# undo "caller"
++
++	 le?li		$idx,8
++	lvx_u		$in0,$x00,$inp		# load first 8 "words"
++	 le?lvsl	$inpperm,0,$idx
++	 le?vspltisb	$tmp,0x0f
++	lvx_u		$in1,$x10,$inp
++	 le?vxor	$inpperm,$inpperm,$tmp	# transform for lvx_u/stvx_u
++	lvx_u		$in2,$x20,$inp
++	 le?vperm	$in0,$in0,$in0,$inpperm
++	lvx_u		$in3,$x30,$inp
++	 le?vperm	$in1,$in1,$in1,$inpperm
++	lvx_u		$in4,$x40,$inp
++	 le?vperm	$in2,$in2,$in2,$inpperm
++	vxor		$out0,$in0,$rndkey0
++	lvx_u		$in5,$x50,$inp
++	 le?vperm	$in3,$in3,$in3,$inpperm
++	vxor		$out1,$in1,$rndkey0
++	lvx_u		$in6,$x60,$inp
++	 le?vperm	$in4,$in4,$in4,$inpperm
++	vxor		$out2,$in2,$rndkey0
++	lvx_u		$in7,$x70,$inp
++	addi		$inp,$inp,0x80
++	 le?vperm	$in5,$in5,$in5,$inpperm
++	vxor		$out3,$in3,$rndkey0
++	 le?vperm	$in6,$in6,$in6,$inpperm
++	vxor		$out4,$in4,$rndkey0
++	 le?vperm	$in7,$in7,$in7,$inpperm
++	vxor		$out5,$in5,$rndkey0
++	vxor		$out6,$in6,$rndkey0
++	vxor		$out7,$in7,$rndkey0
++
++	mtctr		$rounds
++	b		Loop_cbc_dec8x
++.align	5
++Loop_cbc_dec8x:
++	vncipher	$out0,$out0,v24
++	vncipher	$out1,$out1,v24
++	vncipher	$out2,$out2,v24
++	vncipher	$out3,$out3,v24
++	vncipher	$out4,$out4,v24
++	vncipher	$out5,$out5,v24
++	vncipher	$out6,$out6,v24
++	vncipher	$out7,$out7,v24
++	lvx		v24,$x20,$key_		# round[3]
++	addi		$key_,$key_,0x20
++
++	vncipher	$out0,$out0,v25
++	vncipher	$out1,$out1,v25
++	vncipher	$out2,$out2,v25
++	vncipher	$out3,$out3,v25
++	vncipher	$out4,$out4,v25
++	vncipher	$out5,$out5,v25
++	vncipher	$out6,$out6,v25
++	vncipher	$out7,$out7,v25
++	lvx		v25,$x10,$key_		# round[4]
++	bdnz		Loop_cbc_dec8x
++
++	subic		$len,$len,128		# $len-=128
++	vncipher	$out0,$out0,v24
++	vncipher	$out1,$out1,v24
++	vncipher	$out2,$out2,v24
++	vncipher	$out3,$out3,v24
++	vncipher	$out4,$out4,v24
++	vncipher	$out5,$out5,v24
++	vncipher	$out6,$out6,v24
++	vncipher	$out7,$out7,v24
++
++	subfe.		r0,r0,r0		# borrow?-1:0
++	vncipher	$out0,$out0,v25
++	vncipher	$out1,$out1,v25
++	vncipher	$out2,$out2,v25
++	vncipher	$out3,$out3,v25
++	vncipher	$out4,$out4,v25
++	vncipher	$out5,$out5,v25
++	vncipher	$out6,$out6,v25
++	vncipher	$out7,$out7,v25
++
++	and		r0,r0,$len
++	vncipher	$out0,$out0,v26
++	vncipher	$out1,$out1,v26
++	vncipher	$out2,$out2,v26
++	vncipher	$out3,$out3,v26
++	vncipher	$out4,$out4,v26
++	vncipher	$out5,$out5,v26
++	vncipher	$out6,$out6,v26
++	vncipher	$out7,$out7,v26
++
++	add		$inp,$inp,r0		# $inp is adjusted in such
++						# way that at exit from the
++						# loop inX-in7 are loaded
++						# with last "words"
++	vncipher	$out0,$out0,v27
++	vncipher	$out1,$out1,v27
++	vncipher	$out2,$out2,v27
++	vncipher	$out3,$out3,v27
++	vncipher	$out4,$out4,v27
++	vncipher	$out5,$out5,v27
++	vncipher	$out6,$out6,v27
++	vncipher	$out7,$out7,v27
++
++	addi		$key_,$sp,$FRAME+15	# rewind $key_
++	vncipher	$out0,$out0,v28
++	vncipher	$out1,$out1,v28
++	vncipher	$out2,$out2,v28
++	vncipher	$out3,$out3,v28
++	vncipher	$out4,$out4,v28
++	vncipher	$out5,$out5,v28
++	vncipher	$out6,$out6,v28
++	vncipher	$out7,$out7,v28
++	lvx		v24,$x00,$key_		# re-pre-load round[1]
++
++	vncipher	$out0,$out0,v29
++	vncipher	$out1,$out1,v29
++	vncipher	$out2,$out2,v29
++	vncipher	$out3,$out3,v29
++	vncipher	$out4,$out4,v29
++	vncipher	$out5,$out5,v29
++	vncipher	$out6,$out6,v29
++	vncipher	$out7,$out7,v29
++	lvx		v25,$x10,$key_		# re-pre-load round[2]
++
++	vncipher	$out0,$out0,v30
++	 vxor		$ivec,$ivec,v31		# xor with last round key
++	vncipher	$out1,$out1,v30
++	 vxor		$in0,$in0,v31
++	vncipher	$out2,$out2,v30
++	 vxor		$in1,$in1,v31
++	vncipher	$out3,$out3,v30
++	 vxor		$in2,$in2,v31
++	vncipher	$out4,$out4,v30
++	 vxor		$in3,$in3,v31
++	vncipher	$out5,$out5,v30
++	 vxor		$in4,$in4,v31
++	vncipher	$out6,$out6,v30
++	 vxor		$in5,$in5,v31
++	vncipher	$out7,$out7,v30
++	 vxor		$in6,$in6,v31
++
++	vncipherlast	$out0,$out0,$ivec
++	vncipherlast	$out1,$out1,$in0
++	 lvx_u		$in0,$x00,$inp		# load next input block
++	vncipherlast	$out2,$out2,$in1
++	 lvx_u		$in1,$x10,$inp
++	vncipherlast	$out3,$out3,$in2
++	 le?vperm	$in0,$in0,$in0,$inpperm
++	 lvx_u		$in2,$x20,$inp
++	vncipherlast	$out4,$out4,$in3
++	 le?vperm	$in1,$in1,$in1,$inpperm
++	 lvx_u		$in3,$x30,$inp
++	vncipherlast	$out5,$out5,$in4
++	 le?vperm	$in2,$in2,$in2,$inpperm
++	 lvx_u		$in4,$x40,$inp
++	vncipherlast	$out6,$out6,$in5
++	 le?vperm	$in3,$in3,$in3,$inpperm
++	 lvx_u		$in5,$x50,$inp
++	vncipherlast	$out7,$out7,$in6
++	 le?vperm	$in4,$in4,$in4,$inpperm
++	 lvx_u		$in6,$x60,$inp
++	vmr		$ivec,$in7
++	 le?vperm	$in5,$in5,$in5,$inpperm
++	 lvx_u		$in7,$x70,$inp
++	 addi		$inp,$inp,0x80
++
++	le?vperm	$out0,$out0,$out0,$inpperm
++	le?vperm	$out1,$out1,$out1,$inpperm
++	stvx_u		$out0,$x00,$out
++	 le?vperm	$in6,$in6,$in6,$inpperm
++	 vxor		$out0,$in0,$rndkey0
++	le?vperm	$out2,$out2,$out2,$inpperm
++	stvx_u		$out1,$x10,$out
++	 le?vperm	$in7,$in7,$in7,$inpperm
++	 vxor		$out1,$in1,$rndkey0
++	le?vperm	$out3,$out3,$out3,$inpperm
++	stvx_u		$out2,$x20,$out
++	 vxor		$out2,$in2,$rndkey0
++	le?vperm	$out4,$out4,$out4,$inpperm
++	stvx_u		$out3,$x30,$out
++	 vxor		$out3,$in3,$rndkey0
++	le?vperm	$out5,$out5,$out5,$inpperm
++	stvx_u		$out4,$x40,$out
++	 vxor		$out4,$in4,$rndkey0
++	le?vperm	$out6,$out6,$out6,$inpperm
++	stvx_u		$out5,$x50,$out
++	 vxor		$out5,$in5,$rndkey0
++	le?vperm	$out7,$out7,$out7,$inpperm
++	stvx_u		$out6,$x60,$out
++	 vxor		$out6,$in6,$rndkey0
++	stvx_u		$out7,$x70,$out
++	addi		$out,$out,0x80
++	 vxor		$out7,$in7,$rndkey0
++
++	mtctr		$rounds
++	beq		Loop_cbc_dec8x		# did $len-=128 borrow?
++
++	addic.		$len,$len,128
++	beq		Lcbc_dec8x_done
++	nop
++	nop
++
++Loop_cbc_dec8x_tail:				# up to 7 "words" tail...
++	vncipher	$out1,$out1,v24
++	vncipher	$out2,$out2,v24
++	vncipher	$out3,$out3,v24
++	vncipher	$out4,$out4,v24
++	vncipher	$out5,$out5,v24
++	vncipher	$out6,$out6,v24
++	vncipher	$out7,$out7,v24
++	lvx		v24,$x20,$key_		# round[3]
++	addi		$key_,$key_,0x20
++
++	vncipher	$out1,$out1,v25
++	vncipher	$out2,$out2,v25
++	vncipher	$out3,$out3,v25
++	vncipher	$out4,$out4,v25
++	vncipher	$out5,$out5,v25
++	vncipher	$out6,$out6,v25
++	vncipher	$out7,$out7,v25
++	lvx		v25,$x10,$key_		# round[4]
++	bdnz		Loop_cbc_dec8x_tail
++
++	vncipher	$out1,$out1,v24
++	vncipher	$out2,$out2,v24
++	vncipher	$out3,$out3,v24
++	vncipher	$out4,$out4,v24
++	vncipher	$out5,$out5,v24
++	vncipher	$out6,$out6,v24
++	vncipher	$out7,$out7,v24
++
++	vncipher	$out1,$out1,v25
++	vncipher	$out2,$out2,v25
++	vncipher	$out3,$out3,v25
++	vncipher	$out4,$out4,v25
++	vncipher	$out5,$out5,v25
++	vncipher	$out6,$out6,v25
++	vncipher	$out7,$out7,v25
++
++	vncipher	$out1,$out1,v26
++	vncipher	$out2,$out2,v26
++	vncipher	$out3,$out3,v26
++	vncipher	$out4,$out4,v26
++	vncipher	$out5,$out5,v26
++	vncipher	$out6,$out6,v26
++	vncipher	$out7,$out7,v26
++
++	vncipher	$out1,$out1,v27
++	vncipher	$out2,$out2,v27
++	vncipher	$out3,$out3,v27
++	vncipher	$out4,$out4,v27
++	vncipher	$out5,$out5,v27
++	vncipher	$out6,$out6,v27
++	vncipher	$out7,$out7,v27
++
++	vncipher	$out1,$out1,v28
++	vncipher	$out2,$out2,v28
++	vncipher	$out3,$out3,v28
++	vncipher	$out4,$out4,v28
++	vncipher	$out5,$out5,v28
++	vncipher	$out6,$out6,v28
++	vncipher	$out7,$out7,v28
++
++	vncipher	$out1,$out1,v29
++	vncipher	$out2,$out2,v29
++	vncipher	$out3,$out3,v29
++	vncipher	$out4,$out4,v29
++	vncipher	$out5,$out5,v29
++	vncipher	$out6,$out6,v29
++	vncipher	$out7,$out7,v29
++
++	vncipher	$out1,$out1,v30
++	 vxor		$ivec,$ivec,v31		# last round key
++	vncipher	$out2,$out2,v30
++	 vxor		$in1,$in1,v31
++	vncipher	$out3,$out3,v30
++	 vxor		$in2,$in2,v31
++	vncipher	$out4,$out4,v30
++	 vxor		$in3,$in3,v31
++	vncipher	$out5,$out5,v30
++	 vxor		$in4,$in4,v31
++	vncipher	$out6,$out6,v30
++	 vxor		$in5,$in5,v31
++	vncipher	$out7,$out7,v30
++	 vxor		$in6,$in6,v31
++
++	cmplwi		$len,32			# switch($len)
++	blt		Lcbc_dec8x_one
++	nop
++	beq		Lcbc_dec8x_two
++	cmplwi		$len,64
++	blt		Lcbc_dec8x_three
++	nop
++	beq		Lcbc_dec8x_four
++	cmplwi		$len,96
++	blt		Lcbc_dec8x_five
++	nop
++	beq		Lcbc_dec8x_six
++
++Lcbc_dec8x_seven:
++	vncipherlast	$out1,$out1,$ivec
++	vncipherlast	$out2,$out2,$in1
++	vncipherlast	$out3,$out3,$in2
++	vncipherlast	$out4,$out4,$in3
++	vncipherlast	$out5,$out5,$in4
++	vncipherlast	$out6,$out6,$in5
++	vncipherlast	$out7,$out7,$in6
++	vmr		$ivec,$in7
++
++	le?vperm	$out1,$out1,$out1,$inpperm
++	le?vperm	$out2,$out2,$out2,$inpperm
++	stvx_u		$out1,$x00,$out
++	le?vperm	$out3,$out3,$out3,$inpperm
++	stvx_u		$out2,$x10,$out
++	le?vperm	$out4,$out4,$out4,$inpperm
++	stvx_u		$out3,$x20,$out
++	le?vperm	$out5,$out5,$out5,$inpperm
++	stvx_u		$out4,$x30,$out
++	le?vperm	$out6,$out6,$out6,$inpperm
++	stvx_u		$out5,$x40,$out
++	le?vperm	$out7,$out7,$out7,$inpperm
++	stvx_u		$out6,$x50,$out
++	stvx_u		$out7,$x60,$out
++	addi		$out,$out,0x70
++	b		Lcbc_dec8x_done
++
++.align	5
++Lcbc_dec8x_six:
++	vncipherlast	$out2,$out2,$ivec
++	vncipherlast	$out3,$out3,$in2
++	vncipherlast	$out4,$out4,$in3
++	vncipherlast	$out5,$out5,$in4
++	vncipherlast	$out6,$out6,$in5
++	vncipherlast	$out7,$out7,$in6
++	vmr		$ivec,$in7
++
++	le?vperm	$out2,$out2,$out2,$inpperm
++	le?vperm	$out3,$out3,$out3,$inpperm
++	stvx_u		$out2,$x00,$out
++	le?vperm	$out4,$out4,$out4,$inpperm
++	stvx_u		$out3,$x10,$out
++	le?vperm	$out5,$out5,$out5,$inpperm
++	stvx_u		$out4,$x20,$out
++	le?vperm	$out6,$out6,$out6,$inpperm
++	stvx_u		$out5,$x30,$out
++	le?vperm	$out7,$out7,$out7,$inpperm
++	stvx_u		$out6,$x40,$out
++	stvx_u		$out7,$x50,$out
++	addi		$out,$out,0x60
++	b		Lcbc_dec8x_done
++
++.align	5
++Lcbc_dec8x_five:
++	vncipherlast	$out3,$out3,$ivec
++	vncipherlast	$out4,$out4,$in3
++	vncipherlast	$out5,$out5,$in4
++	vncipherlast	$out6,$out6,$in5
++	vncipherlast	$out7,$out7,$in6
++	vmr		$ivec,$in7
++
++	le?vperm	$out3,$out3,$out3,$inpperm
++	le?vperm	$out4,$out4,$out4,$inpperm
++	stvx_u		$out3,$x00,$out
++	le?vperm	$out5,$out5,$out5,$inpperm
++	stvx_u		$out4,$x10,$out
++	le?vperm	$out6,$out6,$out6,$inpperm
++	stvx_u		$out5,$x20,$out
++	le?vperm	$out7,$out7,$out7,$inpperm
++	stvx_u		$out6,$x30,$out
++	stvx_u		$out7,$x40,$out
++	addi		$out,$out,0x50
++	b		Lcbc_dec8x_done
++
++.align	5
++Lcbc_dec8x_four:
++	vncipherlast	$out4,$out4,$ivec
++	vncipherlast	$out5,$out5,$in4
++	vncipherlast	$out6,$out6,$in5
++	vncipherlast	$out7,$out7,$in6
++	vmr		$ivec,$in7
++
++	le?vperm	$out4,$out4,$out4,$inpperm
++	le?vperm	$out5,$out5,$out5,$inpperm
++	stvx_u		$out4,$x00,$out
++	le?vperm	$out6,$out6,$out6,$inpperm
++	stvx_u		$out5,$x10,$out
++	le?vperm	$out7,$out7,$out7,$inpperm
++	stvx_u		$out6,$x20,$out
++	stvx_u		$out7,$x30,$out
++	addi		$out,$out,0x40
++	b		Lcbc_dec8x_done
++
++.align	5
++Lcbc_dec8x_three:
++	vncipherlast	$out5,$out5,$ivec
++	vncipherlast	$out6,$out6,$in5
++	vncipherlast	$out7,$out7,$in6
++	vmr		$ivec,$in7
++
++	le?vperm	$out5,$out5,$out5,$inpperm
++	le?vperm	$out6,$out6,$out6,$inpperm
++	stvx_u		$out5,$x00,$out
++	le?vperm	$out7,$out7,$out7,$inpperm
++	stvx_u		$out6,$x10,$out
++	stvx_u		$out7,$x20,$out
++	addi		$out,$out,0x30
++	b		Lcbc_dec8x_done
++
++.align	5
++Lcbc_dec8x_two:
++	vncipherlast	$out6,$out6,$ivec
++	vncipherlast	$out7,$out7,$in6
++	vmr		$ivec,$in7
++
++	le?vperm	$out6,$out6,$out6,$inpperm
++	le?vperm	$out7,$out7,$out7,$inpperm
++	stvx_u		$out6,$x00,$out
++	stvx_u		$out7,$x10,$out
++	addi		$out,$out,0x20
++	b		Lcbc_dec8x_done
++
++.align	5
++Lcbc_dec8x_one:
++	vncipherlast	$out7,$out7,$ivec
++	vmr		$ivec,$in7
++
++	le?vperm	$out7,$out7,$out7,$inpperm
++	stvx_u		$out7,0,$out
++	addi		$out,$out,0x10
++
++Lcbc_dec8x_done:
++	le?vperm	$ivec,$ivec,$ivec,$inpperm
++	stvx_u		$ivec,0,$ivp		# write [unaligned] iv
++
++	li		r10,`$FRAME+15`
++	li		r11,`$FRAME+31`
++	stvx		$inpperm,r10,$sp	# wipe copies of round keys
++	addi		r10,r10,32
++	stvx		$inpperm,r11,$sp
++	addi		r11,r11,32
++	stvx		$inpperm,r10,$sp
++	addi		r10,r10,32
++	stvx		$inpperm,r11,$sp
++	addi		r11,r11,32
++	stvx		$inpperm,r10,$sp
++	addi		r10,r10,32
++	stvx		$inpperm,r11,$sp
++	addi		r11,r11,32
++	stvx		$inpperm,r10,$sp
++	addi		r10,r10,32
++	stvx		$inpperm,r11,$sp
++	addi		r11,r11,32
++
++	mtspr		256,$vrsave
++	lvx		v20,r10,$sp		# ABI says so
++	addi		r10,r10,32
++	lvx		v21,r11,$sp
++	addi		r11,r11,32
++	lvx		v22,r10,$sp
++	addi		r10,r10,32
++	lvx		v23,r11,$sp
++	addi		r11,r11,32
++	lvx		v24,r10,$sp
++	addi		r10,r10,32
++	lvx		v25,r11,$sp
++	addi		r11,r11,32
++	lvx		v26,r10,$sp
++	addi		r10,r10,32
++	lvx		v27,r11,$sp
++	addi		r11,r11,32
++	lvx		v28,r10,$sp
++	addi		r10,r10,32
++	lvx		v29,r11,$sp
++	addi		r11,r11,32
++	lvx		v30,r10,$sp
++	lvx		v31,r11,$sp
++	$POP		r26,`$FRAME+21*16+0*$SIZE_T`($sp)
++	$POP		r27,`$FRAME+21*16+1*$SIZE_T`($sp)
++	$POP		r28,`$FRAME+21*16+2*$SIZE_T`($sp)
++	$POP		r29,`$FRAME+21*16+3*$SIZE_T`($sp)
++	$POP		r30,`$FRAME+21*16+4*$SIZE_T`($sp)
++	$POP		r31,`$FRAME+21*16+5*$SIZE_T`($sp)
++	addi		$sp,$sp,`$FRAME+21*16+6*$SIZE_T`
++	blr
++	.long		0
++	.byte		0,12,0x04,0,0x80,6,6,0
++	.long		0
++.size	.${prefix}_cbc_encrypt,.-.${prefix}_cbc_encrypt
++___
++}}	}}}
++
++#########################################################################
++{{{	# CTR procedure[s]						#
++my ($inp,$out,$len,$key,$ivp,$x10,$rounds,$idx)=map("r$_",(3..10));
++my ($rndkey0,$rndkey1,$inout,$tmp)=		map("v$_",(0..3));
++my ($ivec,$inptail,$inpperm,$outhead,$outperm,$outmask,$keyperm,$one)=
++						map("v$_",(4..11));
++my $dat=$tmp;
++
++$code.=<<___;
++.globl	.${prefix}_ctr32_encrypt_blocks
++.align	5
++.${prefix}_ctr32_encrypt_blocks:
++	${UCMP}i	$len,1
++	bltlr-
++
++	lis		r0,0xfff0
++	mfspr		$vrsave,256
++	mtspr		256,r0
++
++	li		$idx,15
++	vxor		$rndkey0,$rndkey0,$rndkey0
++	le?vspltisb	$tmp,0x0f
++
++	lvx		$ivec,0,$ivp		# load [unaligned] iv
++	lvsl		$inpperm,0,$ivp
++	lvx		$inptail,$idx,$ivp
++	 vspltisb	$one,1
++	le?vxor		$inpperm,$inpperm,$tmp
++	vperm		$ivec,$ivec,$inptail,$inpperm
++	 vsldoi		$one,$rndkey0,$one,1
++
++	neg		r11,$inp
++	?lvsl		$keyperm,0,$key		# prepare for unaligned key
++	lwz		$rounds,240($key)
++
++	lvsr		$inpperm,0,r11		# prepare for unaligned load
++	lvx		$inptail,0,$inp
++	addi		$inp,$inp,15		# 15 is not typo
++	le?vxor		$inpperm,$inpperm,$tmp
++
++	srwi		$rounds,$rounds,1
++	li		$idx,16
++	subi		$rounds,$rounds,1
++
++	${UCMP}i	$len,8
++	bge		_aesp8_ctr32_encrypt8x
++
++	?lvsr		$outperm,0,$out		# prepare for unaligned store
++	vspltisb	$outmask,-1
++	lvx		$outhead,0,$out
++	?vperm		$outmask,$rndkey0,$outmask,$outperm
++	le?vxor		$outperm,$outperm,$tmp
++
++	lvx		$rndkey0,0,$key
++	mtctr		$rounds
++	lvx		$rndkey1,$idx,$key
++	addi		$idx,$idx,16
++	?vperm		$rndkey0,$rndkey0,$rndkey1,$keyperm
++	vxor		$inout,$ivec,$rndkey0
++	lvx		$rndkey0,$idx,$key
++	addi		$idx,$idx,16
++	b		Loop_ctr32_enc
++
++.align	5
++Loop_ctr32_enc:
++	?vperm		$rndkey1,$rndkey1,$rndkey0,$keyperm
++	vcipher		$inout,$inout,$rndkey1
++	lvx		$rndkey1,$idx,$key
++	addi		$idx,$idx,16
++	?vperm		$rndkey0,$rndkey0,$rndkey1,$keyperm
++	vcipher		$inout,$inout,$rndkey0
++	lvx		$rndkey0,$idx,$key
++	addi		$idx,$idx,16
++	bdnz		Loop_ctr32_enc
++
++	vadduwm		$ivec,$ivec,$one
++	 vmr		$dat,$inptail
++	 lvx		$inptail,0,$inp
++	 addi		$inp,$inp,16
++	 subic.		$len,$len,1		# blocks--
++
++	?vperm		$rndkey1,$rndkey1,$rndkey0,$keyperm
++	vcipher		$inout,$inout,$rndkey1
++	lvx		$rndkey1,$idx,$key
++	 vperm		$dat,$dat,$inptail,$inpperm
++	 li		$idx,16
++	?vperm		$rndkey1,$rndkey0,$rndkey1,$keyperm
++	 lvx		$rndkey0,0,$key
++	vxor		$dat,$dat,$rndkey1	# last round key
++	vcipherlast	$inout,$inout,$dat
++
++	 lvx		$rndkey1,$idx,$key
++	 addi		$idx,$idx,16
++	vperm		$inout,$inout,$inout,$outperm
++	vsel		$dat,$outhead,$inout,$outmask
++	 mtctr		$rounds
++	 ?vperm		$rndkey0,$rndkey0,$rndkey1,$keyperm
++	vmr		$outhead,$inout
++	 vxor		$inout,$ivec,$rndkey0
++	 lvx		$rndkey0,$idx,$key
++	 addi		$idx,$idx,16
++	stvx		$dat,0,$out
++	addi		$out,$out,16
++	bne		Loop_ctr32_enc
++
++	addi		$out,$out,-1
++	lvx		$inout,0,$out		# redundant in aligned case
++	vsel		$inout,$outhead,$inout,$outmask
++	stvx		$inout,0,$out
++
++	mtspr		256,$vrsave
++	blr
++	.long		0
++	.byte		0,12,0x14,0,0,0,6,0
++	.long		0
++___
++#########################################################################
++{{	# Optimized CTR procedure					#
++my $key_="r11";
++my ($x00,$x10,$x20,$x30,$x40,$x50,$x60,$x70)=map("r$_",(0,8,26..31));
++    $x00=0 if ($flavour =~ /osx/);
++my ($in0, $in1, $in2, $in3, $in4, $in5, $in6, $in7 )=map("v$_",(0..3,10,12..14));
++my ($out0,$out1,$out2,$out3,$out4,$out5,$out6,$out7)=map("v$_",(15..22));
++my $rndkey0="v23";	# v24-v25 rotating buffer for first found keys
++			# v26-v31 last 6 round keys
++my ($tmp,$keyperm)=($in3,$in4);	# aliases with "caller", redundant assignment
++my ($two,$three,$four)=($outhead,$outperm,$outmask);
++
++$code.=<<___;
++.align	5
++_aesp8_ctr32_encrypt8x:
++	$STU		$sp,-`($FRAME+21*16+6*$SIZE_T)`($sp)
++	li		r10,`$FRAME+8*16+15`
++	li		r11,`$FRAME+8*16+31`
++	stvx		v20,r10,$sp		# ABI says so
++	addi		r10,r10,32
++	stvx		v21,r11,$sp
++	addi		r11,r11,32
++	stvx		v22,r10,$sp
++	addi		r10,r10,32
++	stvx		v23,r11,$sp
++	addi		r11,r11,32
++	stvx		v24,r10,$sp
++	addi		r10,r10,32
++	stvx		v25,r11,$sp
++	addi		r11,r11,32
++	stvx		v26,r10,$sp
++	addi		r10,r10,32
++	stvx		v27,r11,$sp
++	addi		r11,r11,32
++	stvx		v28,r10,$sp
++	addi		r10,r10,32
++	stvx		v29,r11,$sp
++	addi		r11,r11,32
++	stvx		v30,r10,$sp
++	stvx		v31,r11,$sp
++	li		r0,-1
++	stw		$vrsave,`$FRAME+21*16-4`($sp)	# save vrsave
++	li		$x10,0x10
++	$PUSH		r26,`$FRAME+21*16+0*$SIZE_T`($sp)
++	li		$x20,0x20
++	$PUSH		r27,`$FRAME+21*16+1*$SIZE_T`($sp)
++	li		$x30,0x30
++	$PUSH		r28,`$FRAME+21*16+2*$SIZE_T`($sp)
++	li		$x40,0x40
++	$PUSH		r29,`$FRAME+21*16+3*$SIZE_T`($sp)
++	li		$x50,0x50
++	$PUSH		r30,`$FRAME+21*16+4*$SIZE_T`($sp)
++	li		$x60,0x60
++	$PUSH		r31,`$FRAME+21*16+5*$SIZE_T`($sp)
++	li		$x70,0x70
++	mtspr		256,r0
++
++	subi		$rounds,$rounds,3	# -4 in total
++
++	lvx		$rndkey0,$x00,$key	# load key schedule
++	lvx		v30,$x10,$key
++	addi		$key,$key,0x20
++	lvx		v31,$x00,$key
++	?vperm		$rndkey0,$rndkey0,v30,$keyperm
++	addi		$key_,$sp,$FRAME+15
++	mtctr		$rounds
++
++Load_ctr32_enc_key:
++	?vperm		v24,v30,v31,$keyperm
++	lvx		v30,$x10,$key
++	addi		$key,$key,0x20
++	stvx		v24,$x00,$key_		# off-load round[1]
++	?vperm		v25,v31,v30,$keyperm
++	lvx		v31,$x00,$key
++	stvx		v25,$x10,$key_		# off-load round[2]
++	addi		$key_,$key_,0x20
++	bdnz		Load_ctr32_enc_key
++
++	lvx		v26,$x10,$key
++	?vperm		v24,v30,v31,$keyperm
++	lvx		v27,$x20,$key
++	stvx		v24,$x00,$key_		# off-load round[3]
++	?vperm		v25,v31,v26,$keyperm
++	lvx		v28,$x30,$key
++	stvx		v25,$x10,$key_		# off-load round[4]
++	addi		$key_,$sp,$FRAME+15	# rewind $key_
++	?vperm		v26,v26,v27,$keyperm
++	lvx		v29,$x40,$key
++	?vperm		v27,v27,v28,$keyperm
++	lvx		v30,$x50,$key
++	?vperm		v28,v28,v29,$keyperm
++	lvx		v31,$x60,$key
++	?vperm		v29,v29,v30,$keyperm
++	lvx		$out0,$x70,$key		# borrow $out0
++	?vperm		v30,v30,v31,$keyperm
++	lvx		v24,$x00,$key_		# pre-load round[1]
++	?vperm		v31,v31,$out0,$keyperm
++	lvx		v25,$x10,$key_		# pre-load round[2]
++
++	vadduwm		$two,$one,$one
++	subi		$inp,$inp,15		# undo "caller"
++	$SHL		$len,$len,4
++
++	vadduwm		$out1,$ivec,$one	# counter values ...
++	vadduwm		$out2,$ivec,$two
++	vxor		$out0,$ivec,$rndkey0	# ... xored with rndkey[0]
++	 le?li		$idx,8
++	vadduwm		$out3,$out1,$two
++	vxor		$out1,$out1,$rndkey0
++	 le?lvsl	$inpperm,0,$idx
++	vadduwm		$out4,$out2,$two
++	vxor		$out2,$out2,$rndkey0
++	 le?vspltisb	$tmp,0x0f
++	vadduwm		$out5,$out3,$two
++	vxor		$out3,$out3,$rndkey0
++	 le?vxor	$inpperm,$inpperm,$tmp	# transform for lvx_u/stvx_u
++	vadduwm		$out6,$out4,$two
++	vxor		$out4,$out4,$rndkey0
++	vadduwm		$out7,$out5,$two
++	vxor		$out5,$out5,$rndkey0
++	vadduwm		$ivec,$out6,$two	# next counter value
++	vxor		$out6,$out6,$rndkey0
++	vxor		$out7,$out7,$rndkey0
++
++	mtctr		$rounds
++	b		Loop_ctr32_enc8x
++.align	5
++Loop_ctr32_enc8x:
++	vcipher 	$out0,$out0,v24
++	vcipher 	$out1,$out1,v24
++	vcipher 	$out2,$out2,v24
++	vcipher 	$out3,$out3,v24
++	vcipher 	$out4,$out4,v24
++	vcipher 	$out5,$out5,v24
++	vcipher 	$out6,$out6,v24
++	vcipher 	$out7,$out7,v24
++Loop_ctr32_enc8x_middle:
++	lvx		v24,$x20,$key_		# round[3]
++	addi		$key_,$key_,0x20
++
++	vcipher 	$out0,$out0,v25
++	vcipher 	$out1,$out1,v25
++	vcipher 	$out2,$out2,v25
++	vcipher 	$out3,$out3,v25
++	vcipher 	$out4,$out4,v25
++	vcipher 	$out5,$out5,v25
++	vcipher 	$out6,$out6,v25
++	vcipher 	$out7,$out7,v25
++	lvx		v25,$x10,$key_		# round[4]
++	bdnz		Loop_ctr32_enc8x
++
++	subic		r11,$len,256		# $len-256, borrow $key_
++	vcipher 	$out0,$out0,v24
++	vcipher 	$out1,$out1,v24
++	vcipher 	$out2,$out2,v24
++	vcipher 	$out3,$out3,v24
++	vcipher 	$out4,$out4,v24
++	vcipher 	$out5,$out5,v24
++	vcipher 	$out6,$out6,v24
++	vcipher 	$out7,$out7,v24
++
++	subfe		r0,r0,r0		# borrow?-1:0
++	vcipher 	$out0,$out0,v25
++	vcipher 	$out1,$out1,v25
++	vcipher 	$out2,$out2,v25
++	vcipher 	$out3,$out3,v25
++	vcipher 	$out4,$out4,v25
++	vcipher		$out5,$out5,v25
++	vcipher		$out6,$out6,v25
++	vcipher		$out7,$out7,v25
++
++	and		r0,r0,r11
++	addi		$key_,$sp,$FRAME+15	# rewind $key_
++	vcipher		$out0,$out0,v26
++	vcipher		$out1,$out1,v26
++	vcipher		$out2,$out2,v26
++	vcipher		$out3,$out3,v26
++	vcipher		$out4,$out4,v26
++	vcipher		$out5,$out5,v26
++	vcipher		$out6,$out6,v26
++	vcipher		$out7,$out7,v26
++	lvx		v24,$x00,$key_		# re-pre-load round[1]
++
++	subic		$len,$len,129		# $len-=129
++	vcipher		$out0,$out0,v27
++	addi		$len,$len,1		# $len-=128 really
++	vcipher		$out1,$out1,v27
++	vcipher		$out2,$out2,v27
++	vcipher		$out3,$out3,v27
++	vcipher		$out4,$out4,v27
++	vcipher		$out5,$out5,v27
++	vcipher		$out6,$out6,v27
++	vcipher		$out7,$out7,v27
++	lvx		v25,$x10,$key_		# re-pre-load round[2]
++
++	vcipher		$out0,$out0,v28
++	 lvx_u		$in0,$x00,$inp		# load input
++	vcipher		$out1,$out1,v28
++	 lvx_u		$in1,$x10,$inp
++	vcipher		$out2,$out2,v28
++	 lvx_u		$in2,$x20,$inp
++	vcipher		$out3,$out3,v28
++	 lvx_u		$in3,$x30,$inp
++	vcipher		$out4,$out4,v28
++	 lvx_u		$in4,$x40,$inp
++	vcipher		$out5,$out5,v28
++	 lvx_u		$in5,$x50,$inp
++	vcipher		$out6,$out6,v28
++	 lvx_u		$in6,$x60,$inp
++	vcipher		$out7,$out7,v28
++	 lvx_u		$in7,$x70,$inp
++	 addi		$inp,$inp,0x80
++
++	vcipher		$out0,$out0,v29
++	 le?vperm	$in0,$in0,$in0,$inpperm
++	vcipher		$out1,$out1,v29
++	 le?vperm	$in1,$in1,$in1,$inpperm
++	vcipher		$out2,$out2,v29
++	 le?vperm	$in2,$in2,$in2,$inpperm
++	vcipher		$out3,$out3,v29
++	 le?vperm	$in3,$in3,$in3,$inpperm
++	vcipher		$out4,$out4,v29
++	 le?vperm	$in4,$in4,$in4,$inpperm
++	vcipher		$out5,$out5,v29
++	 le?vperm	$in5,$in5,$in5,$inpperm
++	vcipher		$out6,$out6,v29
++	 le?vperm	$in6,$in6,$in6,$inpperm
++	vcipher		$out7,$out7,v29
++	 le?vperm	$in7,$in7,$in7,$inpperm
++
++	add		$inp,$inp,r0		# $inp is adjusted in such
++						# way that at exit from the
++						# loop inX-in7 are loaded
++						# with last "words"
++	subfe.		r0,r0,r0		# borrow?-1:0
++	vcipher		$out0,$out0,v30
++	 vxor		$in0,$in0,v31		# xor with last round key
++	vcipher		$out1,$out1,v30
++	 vxor		$in1,$in1,v31
++	vcipher		$out2,$out2,v30
++	 vxor		$in2,$in2,v31
++	vcipher		$out3,$out3,v30
++	 vxor		$in3,$in3,v31
++	vcipher		$out4,$out4,v30
++	 vxor		$in4,$in4,v31
++	vcipher		$out5,$out5,v30
++	 vxor		$in5,$in5,v31
++	vcipher		$out6,$out6,v30
++	 vxor		$in6,$in6,v31
++	vcipher		$out7,$out7,v30
++	 vxor		$in7,$in7,v31
++
++	bne		Lctr32_enc8x_break	# did $len-129 borrow?
++
++	vcipherlast	$in0,$out0,$in0
++	vcipherlast	$in1,$out1,$in1
++	 vadduwm	$out1,$ivec,$one	# counter values ...
++	vcipherlast	$in2,$out2,$in2
++	 vadduwm	$out2,$ivec,$two
++	 vxor		$out0,$ivec,$rndkey0	# ... xored with rndkey[0]
++	vcipherlast	$in3,$out3,$in3
++	 vadduwm	$out3,$out1,$two
++	 vxor		$out1,$out1,$rndkey0
++	vcipherlast	$in4,$out4,$in4
++	 vadduwm	$out4,$out2,$two
++	 vxor		$out2,$out2,$rndkey0
++	vcipherlast	$in5,$out5,$in5
++	 vadduwm	$out5,$out3,$two
++	 vxor		$out3,$out3,$rndkey0
++	vcipherlast	$in6,$out6,$in6
++	 vadduwm	$out6,$out4,$two
++	 vxor		$out4,$out4,$rndkey0
++	vcipherlast	$in7,$out7,$in7
++	 vadduwm	$out7,$out5,$two
++	 vxor		$out5,$out5,$rndkey0
++	le?vperm	$in0,$in0,$in0,$inpperm
++	 vadduwm	$ivec,$out6,$two	# next counter value
++	 vxor		$out6,$out6,$rndkey0
++	le?vperm	$in1,$in1,$in1,$inpperm
++	 vxor		$out7,$out7,$rndkey0
++	mtctr		$rounds
++
++	 vcipher	$out0,$out0,v24
++	stvx_u		$in0,$x00,$out
++	le?vperm	$in2,$in2,$in2,$inpperm
++	 vcipher	$out1,$out1,v24
++	stvx_u		$in1,$x10,$out
++	le?vperm	$in3,$in3,$in3,$inpperm
++	 vcipher	$out2,$out2,v24
++	stvx_u		$in2,$x20,$out
++	le?vperm	$in4,$in4,$in4,$inpperm
++	 vcipher	$out3,$out3,v24
++	stvx_u		$in3,$x30,$out
++	le?vperm	$in5,$in5,$in5,$inpperm
++	 vcipher	$out4,$out4,v24
++	stvx_u		$in4,$x40,$out
++	le?vperm	$in6,$in6,$in6,$inpperm
++	 vcipher	$out5,$out5,v24
++	stvx_u		$in5,$x50,$out
++	le?vperm	$in7,$in7,$in7,$inpperm
++	 vcipher	$out6,$out6,v24
++	stvx_u		$in6,$x60,$out
++	 vcipher	$out7,$out7,v24
++	stvx_u		$in7,$x70,$out
++	addi		$out,$out,0x80
++
++	b		Loop_ctr32_enc8x_middle
++
++.align	5
++Lctr32_enc8x_break:
++	cmpwi		$len,-0x60
++	blt		Lctr32_enc8x_one
++	nop
++	beq		Lctr32_enc8x_two
++	cmpwi		$len,-0x40
++	blt		Lctr32_enc8x_three
++	nop
++	beq		Lctr32_enc8x_four
++	cmpwi		$len,-0x20
++	blt		Lctr32_enc8x_five
++	nop
++	beq		Lctr32_enc8x_six
++	cmpwi		$len,0x00
++	blt		Lctr32_enc8x_seven
++
++Lctr32_enc8x_eight:
++	vcipherlast	$out0,$out0,$in0
++	vcipherlast	$out1,$out1,$in1
++	vcipherlast	$out2,$out2,$in2
++	vcipherlast	$out3,$out3,$in3
++	vcipherlast	$out4,$out4,$in4
++	vcipherlast	$out5,$out5,$in5
++	vcipherlast	$out6,$out6,$in6
++	vcipherlast	$out7,$out7,$in7
++
++	le?vperm	$out0,$out0,$out0,$inpperm
++	le?vperm	$out1,$out1,$out1,$inpperm
++	stvx_u		$out0,$x00,$out
++	le?vperm	$out2,$out2,$out2,$inpperm
++	stvx_u		$out1,$x10,$out
++	le?vperm	$out3,$out3,$out3,$inpperm
++	stvx_u		$out2,$x20,$out
++	le?vperm	$out4,$out4,$out4,$inpperm
++	stvx_u		$out3,$x30,$out
++	le?vperm	$out5,$out5,$out5,$inpperm
++	stvx_u		$out4,$x40,$out
++	le?vperm	$out6,$out6,$out6,$inpperm
++	stvx_u		$out5,$x50,$out
++	le?vperm	$out7,$out7,$out7,$inpperm
++	stvx_u		$out6,$x60,$out
++	stvx_u		$out7,$x70,$out
++	addi		$out,$out,0x80
++	b		Lctr32_enc8x_done
++
++.align	5
++Lctr32_enc8x_seven:
++	vcipherlast	$out0,$out0,$in1
++	vcipherlast	$out1,$out1,$in2
++	vcipherlast	$out2,$out2,$in3
++	vcipherlast	$out3,$out3,$in4
++	vcipherlast	$out4,$out4,$in5
++	vcipherlast	$out5,$out5,$in6
++	vcipherlast	$out6,$out6,$in7
++
++	le?vperm	$out0,$out0,$out0,$inpperm
++	le?vperm	$out1,$out1,$out1,$inpperm
++	stvx_u		$out0,$x00,$out
++	le?vperm	$out2,$out2,$out2,$inpperm
++	stvx_u		$out1,$x10,$out
++	le?vperm	$out3,$out3,$out3,$inpperm
++	stvx_u		$out2,$x20,$out
++	le?vperm	$out4,$out4,$out4,$inpperm
++	stvx_u		$out3,$x30,$out
++	le?vperm	$out5,$out5,$out5,$inpperm
++	stvx_u		$out4,$x40,$out
++	le?vperm	$out6,$out6,$out6,$inpperm
++	stvx_u		$out5,$x50,$out
++	stvx_u		$out6,$x60,$out
++	addi		$out,$out,0x70
++	b		Lctr32_enc8x_done
++
++.align	5
++Lctr32_enc8x_six:
++	vcipherlast	$out0,$out0,$in2
++	vcipherlast	$out1,$out1,$in3
++	vcipherlast	$out2,$out2,$in4
++	vcipherlast	$out3,$out3,$in5
++	vcipherlast	$out4,$out4,$in6
++	vcipherlast	$out5,$out5,$in7
++
++	le?vperm	$out0,$out0,$out0,$inpperm
++	le?vperm	$out1,$out1,$out1,$inpperm
++	stvx_u		$out0,$x00,$out
++	le?vperm	$out2,$out2,$out2,$inpperm
++	stvx_u		$out1,$x10,$out
++	le?vperm	$out3,$out3,$out3,$inpperm
++	stvx_u		$out2,$x20,$out
++	le?vperm	$out4,$out4,$out4,$inpperm
++	stvx_u		$out3,$x30,$out
++	le?vperm	$out5,$out5,$out5,$inpperm
++	stvx_u		$out4,$x40,$out
++	stvx_u		$out5,$x50,$out
++	addi		$out,$out,0x60
++	b		Lctr32_enc8x_done
++
++.align	5
++Lctr32_enc8x_five:
++	vcipherlast	$out0,$out0,$in3
++	vcipherlast	$out1,$out1,$in4
++	vcipherlast	$out2,$out2,$in5
++	vcipherlast	$out3,$out3,$in6
++	vcipherlast	$out4,$out4,$in7
++
++	le?vperm	$out0,$out0,$out0,$inpperm
++	le?vperm	$out1,$out1,$out1,$inpperm
++	stvx_u		$out0,$x00,$out
++	le?vperm	$out2,$out2,$out2,$inpperm
++	stvx_u		$out1,$x10,$out
++	le?vperm	$out3,$out3,$out3,$inpperm
++	stvx_u		$out2,$x20,$out
++	le?vperm	$out4,$out4,$out4,$inpperm
++	stvx_u		$out3,$x30,$out
++	stvx_u		$out4,$x40,$out
++	addi		$out,$out,0x50
++	b		Lctr32_enc8x_done
++
++.align	5
++Lctr32_enc8x_four:
++	vcipherlast	$out0,$out0,$in4
++	vcipherlast	$out1,$out1,$in5
++	vcipherlast	$out2,$out2,$in6
++	vcipherlast	$out3,$out3,$in7
++
++	le?vperm	$out0,$out0,$out0,$inpperm
++	le?vperm	$out1,$out1,$out1,$inpperm
++	stvx_u		$out0,$x00,$out
++	le?vperm	$out2,$out2,$out2,$inpperm
++	stvx_u		$out1,$x10,$out
++	le?vperm	$out3,$out3,$out3,$inpperm
++	stvx_u		$out2,$x20,$out
++	stvx_u		$out3,$x30,$out
++	addi		$out,$out,0x40
++	b		Lctr32_enc8x_done
++
++.align	5
++Lctr32_enc8x_three:
++	vcipherlast	$out0,$out0,$in5
++	vcipherlast	$out1,$out1,$in6
++	vcipherlast	$out2,$out2,$in7
++
++	le?vperm	$out0,$out0,$out0,$inpperm
++	le?vperm	$out1,$out1,$out1,$inpperm
++	stvx_u		$out0,$x00,$out
++	le?vperm	$out2,$out2,$out2,$inpperm
++	stvx_u		$out1,$x10,$out
++	stvx_u		$out2,$x20,$out
++	addi		$out,$out,0x30
++	b		Lcbc_dec8x_done
++
++.align	5
++Lctr32_enc8x_two:
++	vcipherlast	$out0,$out0,$in6
++	vcipherlast	$out1,$out1,$in7
++
++	le?vperm	$out0,$out0,$out0,$inpperm
++	le?vperm	$out1,$out1,$out1,$inpperm
++	stvx_u		$out0,$x00,$out
++	stvx_u		$out1,$x10,$out
++	addi		$out,$out,0x20
++	b		Lcbc_dec8x_done
++
++.align	5
++Lctr32_enc8x_one:
++	vcipherlast	$out0,$out0,$in7
++
++	le?vperm	$out0,$out0,$out0,$inpperm
++	stvx_u		$out0,0,$out
++	addi		$out,$out,0x10
++
++Lctr32_enc8x_done:
++	li		r10,`$FRAME+15`
++	li		r11,`$FRAME+31`
++	stvx		$inpperm,r10,$sp	# wipe copies of round keys
++	addi		r10,r10,32
++	stvx		$inpperm,r11,$sp
++	addi		r11,r11,32
++	stvx		$inpperm,r10,$sp
++	addi		r10,r10,32
++	stvx		$inpperm,r11,$sp
++	addi		r11,r11,32
++	stvx		$inpperm,r10,$sp
++	addi		r10,r10,32
++	stvx		$inpperm,r11,$sp
++	addi		r11,r11,32
++	stvx		$inpperm,r10,$sp
++	addi		r10,r10,32
++	stvx		$inpperm,r11,$sp
++	addi		r11,r11,32
++
++	mtspr		256,$vrsave
++	lvx		v20,r10,$sp		# ABI says so
++	addi		r10,r10,32
++	lvx		v21,r11,$sp
++	addi		r11,r11,32
++	lvx		v22,r10,$sp
++	addi		r10,r10,32
++	lvx		v23,r11,$sp
++	addi		r11,r11,32
++	lvx		v24,r10,$sp
++	addi		r10,r10,32
++	lvx		v25,r11,$sp
++	addi		r11,r11,32
++	lvx		v26,r10,$sp
++	addi		r10,r10,32
++	lvx		v27,r11,$sp
++	addi		r11,r11,32
++	lvx		v28,r10,$sp
++	addi		r10,r10,32
++	lvx		v29,r11,$sp
++	addi		r11,r11,32
++	lvx		v30,r10,$sp
++	lvx		v31,r11,$sp
++	$POP		r26,`$FRAME+21*16+0*$SIZE_T`($sp)
++	$POP		r27,`$FRAME+21*16+1*$SIZE_T`($sp)
++	$POP		r28,`$FRAME+21*16+2*$SIZE_T`($sp)
++	$POP		r29,`$FRAME+21*16+3*$SIZE_T`($sp)
++	$POP		r30,`$FRAME+21*16+4*$SIZE_T`($sp)
++	$POP		r31,`$FRAME+21*16+5*$SIZE_T`($sp)
++	addi		$sp,$sp,`$FRAME+21*16+6*$SIZE_T`
++	blr
++	.long		0
++	.byte		0,12,0x04,0,0x80,6,6,0
++	.long		0
++.size	.${prefix}_ctr32_encrypt_blocks,.-.${prefix}_ctr32_encrypt_blocks
++___
++}}	}}}
++
++#########################################################################
++{{{	# XTS procedures						#
++# int aes_p8_xts_[en|de]crypt(const char *inp, char *out, size_t len,	#
++#                             const AES_KEY *key1, const AES_KEY *key2,	#
++#                             [const] unsigned char iv[16]);		#
++# If $key2 is NULL, then a "tweak chaining" mode is engaged, in which	#
++# input tweak value is assumed to be encrypted already, and last tweak	#
++# value, one suitable for consecutive call on same chunk of data, is	#
++# written back to original buffer. In addition, in "tweak chaining"	#
++# mode only complete input blocks are processed.			#
++
++my ($inp,$out,$len,$key1,$key2,$ivp,$rounds,$idx) =	map("r$_",(3..10));
++my ($rndkey0,$rndkey1,$inout) =				map("v$_",(0..2));
++my ($output,$inptail,$inpperm,$leperm,$keyperm) =	map("v$_",(3..7));
++my ($tweak,$seven,$eighty7,$tmp,$tweak1) =		map("v$_",(8..12));
++my $taillen = $key2;
++
++   ($inp,$idx) = ($idx,$inp);				# reassign
++
++$code.=<<___;
++.globl	.${prefix}_xts_encrypt
++.align	5
++.${prefix}_xts_encrypt:
++	mr		$inp,r3				# reassign
++	li		r3,-1
++	${UCMP}i	$len,16
++	bltlr-
++
++	lis		r0,0xfff0
++	mfspr		r12,256				# save vrsave
++	li		r11,0
++	mtspr		256,r0
++
++	vspltisb	$seven,0x07			# 0x070707..07
++	le?lvsl		$leperm,r11,r11
++	le?vspltisb	$tmp,0x0f
++	le?vxor		$leperm,$leperm,$seven
++
++	li		$idx,15
++	lvx		$tweak,0,$ivp			# load [unaligned] iv
++	lvsl		$inpperm,0,$ivp
++	lvx		$inptail,$idx,$ivp
++	le?vxor		$inpperm,$inpperm,$tmp
++	vperm		$tweak,$tweak,$inptail,$inpperm
++
++	neg		r11,$inp
++	lvsr		$inpperm,0,r11			# prepare for unaligned load
++	lvx		$inout,0,$inp
++	addi		$inp,$inp,15			# 15 is not typo
++	le?vxor		$inpperm,$inpperm,$tmp
++
++	${UCMP}i	$key2,0				# key2==NULL?
++	beq		Lxts_enc_no_key2
++
++	?lvsl		$keyperm,0,$key2		# prepare for unaligned key
++	lwz		$rounds,240($key2)
++	srwi		$rounds,$rounds,1
++	subi		$rounds,$rounds,1
++	li		$idx,16
++
++	lvx		$rndkey0,0,$key2
++	lvx		$rndkey1,$idx,$key2
++	addi		$idx,$idx,16
++	?vperm		$rndkey0,$rndkey0,$rndkey1,$keyperm
++	vxor		$tweak,$tweak,$rndkey0
++	lvx		$rndkey0,$idx,$key2
++	addi		$idx,$idx,16
++	mtctr		$rounds
++
++Ltweak_xts_enc:
++	?vperm		$rndkey1,$rndkey1,$rndkey0,$keyperm
++	vcipher		$tweak,$tweak,$rndkey1
++	lvx		$rndkey1,$idx,$key2
++	addi		$idx,$idx,16
++	?vperm		$rndkey0,$rndkey0,$rndkey1,$keyperm
++	vcipher		$tweak,$tweak,$rndkey0
++	lvx		$rndkey0,$idx,$key2
++	addi		$idx,$idx,16
++	bdnz		Ltweak_xts_enc
++
++	?vperm		$rndkey1,$rndkey1,$rndkey0,$keyperm
++	vcipher		$tweak,$tweak,$rndkey1
++	lvx		$rndkey1,$idx,$key2
++	?vperm		$rndkey0,$rndkey0,$rndkey1,$keyperm
++	vcipherlast	$tweak,$tweak,$rndkey0
++
++	li		$ivp,0				# don't chain the tweak
++	b		Lxts_enc
++
++Lxts_enc_no_key2:
++	li		$idx,-16
++	and		$len,$len,$idx			# in "tweak chaining"
++							# mode only complete
++							# blocks are processed
++Lxts_enc:
++	lvx		$inptail,0,$inp
++	addi		$inp,$inp,16
++
++	?lvsl		$keyperm,0,$key1		# prepare for unaligned key
++	lwz		$rounds,240($key1)
++	srwi		$rounds,$rounds,1
++	subi		$rounds,$rounds,1
++	li		$idx,16
++
++	vslb		$eighty7,$seven,$seven		# 0x808080..80
++	vor		$eighty7,$eighty7,$seven	# 0x878787..87
++	vspltisb	$tmp,1				# 0x010101..01
++	vsldoi		$eighty7,$eighty7,$tmp,15	# 0x870101..01
++
++	${UCMP}i	$len,96
++	bge		_aesp8_xts_encrypt6x
++
++	andi.		$taillen,$len,15
++	subic		r0,$len,32
++	subi		$taillen,$taillen,16
++	subfe		r0,r0,r0
++	and		r0,r0,$taillen
++	add		$inp,$inp,r0
++
++	lvx		$rndkey0,0,$key1
++	lvx		$rndkey1,$idx,$key1
++	addi		$idx,$idx,16
++	vperm		$inout,$inout,$inptail,$inpperm
++	?vperm		$rndkey0,$rndkey0,$rndkey1,$keyperm
++	vxor		$inout,$inout,$tweak
++	vxor		$inout,$inout,$rndkey0
++	lvx		$rndkey0,$idx,$key1
++	addi		$idx,$idx,16
++	mtctr		$rounds
++	b		Loop_xts_enc
++
++.align	5
++Loop_xts_enc:
++	?vperm		$rndkey1,$rndkey1,$rndkey0,$keyperm
++	vcipher		$inout,$inout,$rndkey1
++	lvx		$rndkey1,$idx,$key1
++	addi		$idx,$idx,16
++	?vperm		$rndkey0,$rndkey0,$rndkey1,$keyperm
++	vcipher		$inout,$inout,$rndkey0
++	lvx		$rndkey0,$idx,$key1
++	addi		$idx,$idx,16
++	bdnz		Loop_xts_enc
++
++	?vperm		$rndkey1,$rndkey1,$rndkey0,$keyperm
++	vcipher		$inout,$inout,$rndkey1
++	lvx		$rndkey1,$idx,$key1
++	li		$idx,16
++	?vperm		$rndkey0,$rndkey0,$rndkey1,$keyperm
++	vxor		$rndkey0,$rndkey0,$tweak
++	vcipherlast	$output,$inout,$rndkey0
++
++	le?vperm	$tmp,$output,$output,$leperm
++	be?nop
++	le?stvx_u	$tmp,0,$out
++	be?stvx_u	$output,0,$out
++	addi		$out,$out,16
++
++	subic.		$len,$len,16
++	beq		Lxts_enc_done
++
++	vmr		$inout,$inptail
++	lvx		$inptail,0,$inp
++	addi		$inp,$inp,16
++	lvx		$rndkey0,0,$key1
++	lvx		$rndkey1,$idx,$key1
++	addi		$idx,$idx,16
++
++	subic		r0,$len,32
++	subfe		r0,r0,r0
++	and		r0,r0,$taillen
++	add		$inp,$inp,r0
++
++	vsrab		$tmp,$tweak,$seven		# next tweak value
++	vaddubm		$tweak,$tweak,$tweak
++	vsldoi		$tmp,$tmp,$tmp,15
++	vand		$tmp,$tmp,$eighty7
++	vxor		$tweak,$tweak,$tmp
++
++	vperm		$inout,$inout,$inptail,$inpperm
++	?vperm		$rndkey0,$rndkey0,$rndkey1,$keyperm
++	vxor		$inout,$inout,$tweak
++	vxor		$output,$output,$rndkey0	# just in case $len<16
++	vxor		$inout,$inout,$rndkey0
++	lvx		$rndkey0,$idx,$key1
++	addi		$idx,$idx,16
++
++	mtctr		$rounds
++	${UCMP}i	$len,16
++	bge		Loop_xts_enc
++
++	vxor		$output,$output,$tweak
++	lvsr		$inpperm,0,$len			# $inpperm is no longer needed
++	vxor		$inptail,$inptail,$inptail	# $inptail is no longer needed
++	vspltisb	$tmp,-1
++	vperm		$inptail,$inptail,$tmp,$inpperm
++	vsel		$inout,$inout,$output,$inptail
++
++	subi		r11,$out,17
++	subi		$out,$out,16
++	mtctr		$len
++	li		$len,16
++Loop_xts_enc_steal:
++	lbzu		r0,1(r11)
++	stb		r0,16(r11)
++	bdnz		Loop_xts_enc_steal
++
++	mtctr		$rounds
++	b		Loop_xts_enc			# one more time...
++
++Lxts_enc_done:
++	${UCMP}i	$ivp,0
++	beq		Lxts_enc_ret
++
++	vsrab		$tmp,$tweak,$seven		# next tweak value
++	vaddubm		$tweak,$tweak,$tweak
++	vsldoi		$tmp,$tmp,$tmp,15
++	vand		$tmp,$tmp,$eighty7
++	vxor		$tweak,$tweak,$tmp
++
++	le?vperm	$tweak,$tweak,$tweak,$leperm
++	stvx_u		$tweak,0,$ivp
++
++Lxts_enc_ret:
++	mtspr		256,r12				# restore vrsave
++	li		r3,0
++	blr
++	.long		0
++	.byte		0,12,0x04,0,0x80,6,6,0
++	.long		0
++.size	.${prefix}_xts_encrypt,.-.${prefix}_xts_encrypt
++
++.globl	.${prefix}_xts_decrypt
++.align	5
++.${prefix}_xts_decrypt:
++	mr		$inp,r3				# reassign
++	li		r3,-1
++	${UCMP}i	$len,16
++	bltlr-
++
++	lis		r0,0xfff8
++	mfspr		r12,256				# save vrsave
++	li		r11,0
++	mtspr		256,r0
++
++	andi.		r0,$len,15
++	neg		r0,r0
++	andi.		r0,r0,16
++	sub		$len,$len,r0
++
++	vspltisb	$seven,0x07			# 0x070707..07
++	le?lvsl		$leperm,r11,r11
++	le?vspltisb	$tmp,0x0f
++	le?vxor		$leperm,$leperm,$seven
++
++	li		$idx,15
++	lvx		$tweak,0,$ivp			# load [unaligned] iv
++	lvsl		$inpperm,0,$ivp
++	lvx		$inptail,$idx,$ivp
++	le?vxor		$inpperm,$inpperm,$tmp
++	vperm		$tweak,$tweak,$inptail,$inpperm
++
++	neg		r11,$inp
++	lvsr		$inpperm,0,r11			# prepare for unaligned load
++	lvx		$inout,0,$inp
++	addi		$inp,$inp,15			# 15 is not typo
++	le?vxor		$inpperm,$inpperm,$tmp
++
++	${UCMP}i	$key2,0				# key2==NULL?
++	beq		Lxts_dec_no_key2
++
++	?lvsl		$keyperm,0,$key2		# prepare for unaligned key
++	lwz		$rounds,240($key2)
++	srwi		$rounds,$rounds,1
++	subi		$rounds,$rounds,1
++	li		$idx,16
++
++	lvx		$rndkey0,0,$key2
++	lvx		$rndkey1,$idx,$key2
++	addi		$idx,$idx,16
++	?vperm		$rndkey0,$rndkey0,$rndkey1,$keyperm
++	vxor		$tweak,$tweak,$rndkey0
++	lvx		$rndkey0,$idx,$key2
++	addi		$idx,$idx,16
++	mtctr		$rounds
++
++Ltweak_xts_dec:
++	?vperm		$rndkey1,$rndkey1,$rndkey0,$keyperm
++	vcipher		$tweak,$tweak,$rndkey1
++	lvx		$rndkey1,$idx,$key2
++	addi		$idx,$idx,16
++	?vperm		$rndkey0,$rndkey0,$rndkey1,$keyperm
++	vcipher		$tweak,$tweak,$rndkey0
++	lvx		$rndkey0,$idx,$key2
++	addi		$idx,$idx,16
++	bdnz		Ltweak_xts_dec
++
++	?vperm		$rndkey1,$rndkey1,$rndkey0,$keyperm
++	vcipher		$tweak,$tweak,$rndkey1
++	lvx		$rndkey1,$idx,$key2
++	?vperm		$rndkey0,$rndkey0,$rndkey1,$keyperm
++	vcipherlast	$tweak,$tweak,$rndkey0
++
++	li		$ivp,0				# don't chain the tweak
++	b		Lxts_dec
++
++Lxts_dec_no_key2:
++	neg		$idx,$len
++	andi.		$idx,$idx,15
++	add		$len,$len,$idx			# in "tweak chaining"
++							# mode only complete
++							# blocks are processed
++Lxts_dec:
++	lvx		$inptail,0,$inp
++	addi		$inp,$inp,16
++
++	?lvsl		$keyperm,0,$key1		# prepare for unaligned key
++	lwz		$rounds,240($key1)
++	srwi		$rounds,$rounds,1
++	subi		$rounds,$rounds,1
++	li		$idx,16
++
++	vslb		$eighty7,$seven,$seven		# 0x808080..80
++	vor		$eighty7,$eighty7,$seven	# 0x878787..87
++	vspltisb	$tmp,1				# 0x010101..01
++	vsldoi		$eighty7,$eighty7,$tmp,15	# 0x870101..01
++
++	${UCMP}i	$len,96
++	bge		_aesp8_xts_decrypt6x
++
++	lvx		$rndkey0,0,$key1
++	lvx		$rndkey1,$idx,$key1
++	addi		$idx,$idx,16
++	vperm		$inout,$inout,$inptail,$inpperm
++	?vperm		$rndkey0,$rndkey0,$rndkey1,$keyperm
++	vxor		$inout,$inout,$tweak
++	vxor		$inout,$inout,$rndkey0
++	lvx		$rndkey0,$idx,$key1
++	addi		$idx,$idx,16
++	mtctr		$rounds
++
++	${UCMP}i	$len,16
++	blt		Ltail_xts_dec
++	be?b		Loop_xts_dec
++
++.align	5
++Loop_xts_dec:
++	?vperm		$rndkey1,$rndkey1,$rndkey0,$keyperm
++	vncipher	$inout,$inout,$rndkey1
++	lvx		$rndkey1,$idx,$key1
++	addi		$idx,$idx,16
++	?vperm		$rndkey0,$rndkey0,$rndkey1,$keyperm
++	vncipher	$inout,$inout,$rndkey0
++	lvx		$rndkey0,$idx,$key1
++	addi		$idx,$idx,16
++	bdnz		Loop_xts_dec
++
++	?vperm		$rndkey1,$rndkey1,$rndkey0,$keyperm
++	vncipher	$inout,$inout,$rndkey1
++	lvx		$rndkey1,$idx,$key1
++	li		$idx,16
++	?vperm		$rndkey0,$rndkey0,$rndkey1,$keyperm
++	vxor		$rndkey0,$rndkey0,$tweak
++	vncipherlast	$output,$inout,$rndkey0
++
++	le?vperm	$tmp,$output,$output,$leperm
++	be?nop
++	le?stvx_u	$tmp,0,$out
++	be?stvx_u	$output,0,$out
++	addi		$out,$out,16
++
++	subic.		$len,$len,16
++	beq		Lxts_dec_done
++
++	vmr		$inout,$inptail
++	lvx		$inptail,0,$inp
++	addi		$inp,$inp,16
++	lvx		$rndkey0,0,$key1
++	lvx		$rndkey1,$idx,$key1
++	addi		$idx,$idx,16
++
++	vsrab		$tmp,$tweak,$seven		# next tweak value
++	vaddubm		$tweak,$tweak,$tweak
++	vsldoi		$tmp,$tmp,$tmp,15
++	vand		$tmp,$tmp,$eighty7
++	vxor		$tweak,$tweak,$tmp
++
++	vperm		$inout,$inout,$inptail,$inpperm
++	?vperm		$rndkey0,$rndkey0,$rndkey1,$keyperm
++	vxor		$inout,$inout,$tweak
++	vxor		$inout,$inout,$rndkey0
++	lvx		$rndkey0,$idx,$key1
++	addi		$idx,$idx,16
++
++	mtctr		$rounds
++	${UCMP}i	$len,16
++	bge		Loop_xts_dec
++
++Ltail_xts_dec:
++	vsrab		$tmp,$tweak,$seven		# next tweak value
++	vaddubm		$tweak1,$tweak,$tweak
++	vsldoi		$tmp,$tmp,$tmp,15
++	vand		$tmp,$tmp,$eighty7
++	vxor		$tweak1,$tweak1,$tmp
++
++	subi		$inp,$inp,16
++	add		$inp,$inp,$len
++
++	vxor		$inout,$inout,$tweak		# :-(
++	vxor		$inout,$inout,$tweak1		# :-)
++
++Loop_xts_dec_short:
++	?vperm		$rndkey1,$rndkey1,$rndkey0,$keyperm
++	vncipher	$inout,$inout,$rndkey1
++	lvx		$rndkey1,$idx,$key1
++	addi		$idx,$idx,16
++	?vperm		$rndkey0,$rndkey0,$rndkey1,$keyperm
++	vncipher	$inout,$inout,$rndkey0
++	lvx		$rndkey0,$idx,$key1
++	addi		$idx,$idx,16
++	bdnz		Loop_xts_dec_short
++
++	?vperm		$rndkey1,$rndkey1,$rndkey0,$keyperm
++	vncipher	$inout,$inout,$rndkey1
++	lvx		$rndkey1,$idx,$key1
++	li		$idx,16
++	?vperm		$rndkey0,$rndkey0,$rndkey1,$keyperm
++	vxor		$rndkey0,$rndkey0,$tweak1
++	vncipherlast	$output,$inout,$rndkey0
++
++	le?vperm	$tmp,$output,$output,$leperm
++	be?nop
++	le?stvx_u	$tmp,0,$out
++	be?stvx_u	$output,0,$out
++
++	vmr		$inout,$inptail
++	lvx		$inptail,0,$inp
++	#addi		$inp,$inp,16
++	lvx		$rndkey0,0,$key1
++	lvx		$rndkey1,$idx,$key1
++	addi		$idx,$idx,16
++	vperm		$inout,$inout,$inptail,$inpperm
++	?vperm		$rndkey0,$rndkey0,$rndkey1,$keyperm
++
++	lvsr		$inpperm,0,$len			# $inpperm is no longer needed
++	vxor		$inptail,$inptail,$inptail	# $inptail is no longer needed
++	vspltisb	$tmp,-1
++	vperm		$inptail,$inptail,$tmp,$inpperm
++	vsel		$inout,$inout,$output,$inptail
++
++	vxor		$rndkey0,$rndkey0,$tweak
++	vxor		$inout,$inout,$rndkey0
++	lvx		$rndkey0,$idx,$key1
++	addi		$idx,$idx,16
++
++	subi		r11,$out,1
++	mtctr		$len
++	li		$len,16
++Loop_xts_dec_steal:
++	lbzu		r0,1(r11)
++	stb		r0,16(r11)
++	bdnz		Loop_xts_dec_steal
++
++	mtctr		$rounds
++	b		Loop_xts_dec			# one more time...
++
++Lxts_dec_done:
++	${UCMP}i	$ivp,0
++	beq		Lxts_dec_ret
++
++	vsrab		$tmp,$tweak,$seven		# next tweak value
++	vaddubm		$tweak,$tweak,$tweak
++	vsldoi		$tmp,$tmp,$tmp,15
++	vand		$tmp,$tmp,$eighty7
++	vxor		$tweak,$tweak,$tmp
++
++	le?vperm	$tweak,$tweak,$tweak,$leperm
++	stvx_u		$tweak,0,$ivp
++
++Lxts_dec_ret:
++	mtspr		256,r12				# restore vrsave
++	li		r3,0
++	blr
++	.long		0
++	.byte		0,12,0x04,0,0x80,6,6,0
++	.long		0
++.size	.${prefix}_xts_decrypt,.-.${prefix}_xts_decrypt
++___
++#########################################################################
++{{	# Optimized XTS procedures					#
++my $key_=$key2;
++my ($x00,$x10,$x20,$x30,$x40,$x50,$x60,$x70)=map("r$_",(0,3,26..31));
++    $x00=0 if ($flavour =~ /osx/);
++my ($in0,  $in1,  $in2,  $in3,  $in4,  $in5 )=map("v$_",(0..5));
++my ($out0, $out1, $out2, $out3, $out4, $out5)=map("v$_",(7,12..16));
++my ($twk0, $twk1, $twk2, $twk3, $twk4, $twk5)=map("v$_",(17..22));
++my $rndkey0="v23";	# v24-v25 rotating buffer for first found keys
++			# v26-v31 last 6 round keys
++my ($keyperm)=($out0);	# aliases with "caller", redundant assignment
++my $taillen=$x70;
++
++$code.=<<___;
++.align	5
++_aesp8_xts_encrypt6x:
++	$STU		$sp,-`($FRAME+21*16+6*$SIZE_T)`($sp)
++	mflr		r11
++	li		r7,`$FRAME+8*16+15`
++	li		r3,`$FRAME+8*16+31`
++	$PUSH		r11,`$FRAME+21*16+6*$SIZE_T+$LRSAVE`($sp)
++	stvx		v20,r7,$sp		# ABI says so
++	addi		r7,r7,32
++	stvx		v21,r3,$sp
++	addi		r3,r3,32
++	stvx		v22,r7,$sp
++	addi		r7,r7,32
++	stvx		v23,r3,$sp
++	addi		r3,r3,32
++	stvx		v24,r7,$sp
++	addi		r7,r7,32
++	stvx		v25,r3,$sp
++	addi		r3,r3,32
++	stvx		v26,r7,$sp
++	addi		r7,r7,32
++	stvx		v27,r3,$sp
++	addi		r3,r3,32
++	stvx		v28,r7,$sp
++	addi		r7,r7,32
++	stvx		v29,r3,$sp
++	addi		r3,r3,32
++	stvx		v30,r7,$sp
++	stvx		v31,r3,$sp
++	li		r0,-1
++	stw		$vrsave,`$FRAME+21*16-4`($sp)	# save vrsave
++	li		$x10,0x10
++	$PUSH		r26,`$FRAME+21*16+0*$SIZE_T`($sp)
++	li		$x20,0x20
++	$PUSH		r27,`$FRAME+21*16+1*$SIZE_T`($sp)
++	li		$x30,0x30
++	$PUSH		r28,`$FRAME+21*16+2*$SIZE_T`($sp)
++	li		$x40,0x40
++	$PUSH		r29,`$FRAME+21*16+3*$SIZE_T`($sp)
++	li		$x50,0x50
++	$PUSH		r30,`$FRAME+21*16+4*$SIZE_T`($sp)
++	li		$x60,0x60
++	$PUSH		r31,`$FRAME+21*16+5*$SIZE_T`($sp)
++	li		$x70,0x70
++	mtspr		256,r0
++
++	subi		$rounds,$rounds,3	# -4 in total
++
++	lvx		$rndkey0,$x00,$key1	# load key schedule
++	lvx		v30,$x10,$key1
++	addi		$key1,$key1,0x20
++	lvx		v31,$x00,$key1
++	?vperm		$rndkey0,$rndkey0,v30,$keyperm
++	addi		$key_,$sp,$FRAME+15
++	mtctr		$rounds
++
++Load_xts_enc_key:
++	?vperm		v24,v30,v31,$keyperm
++	lvx		v30,$x10,$key1
++	addi		$key1,$key1,0x20
++	stvx		v24,$x00,$key_		# off-load round[1]
++	?vperm		v25,v31,v30,$keyperm
++	lvx		v31,$x00,$key1
++	stvx		v25,$x10,$key_		# off-load round[2]
++	addi		$key_,$key_,0x20
++	bdnz		Load_xts_enc_key
++
++	lvx		v26,$x10,$key1
++	?vperm		v24,v30,v31,$keyperm
++	lvx		v27,$x20,$key1
++	stvx		v24,$x00,$key_		# off-load round[3]
++	?vperm		v25,v31,v26,$keyperm
++	lvx		v28,$x30,$key1
++	stvx		v25,$x10,$key_		# off-load round[4]
++	addi		$key_,$sp,$FRAME+15	# rewind $key_
++	?vperm		v26,v26,v27,$keyperm
++	lvx		v29,$x40,$key1
++	?vperm		v27,v27,v28,$keyperm
++	lvx		v30,$x50,$key1
++	?vperm		v28,v28,v29,$keyperm
++	lvx		v31,$x60,$key1
++	?vperm		v29,v29,v30,$keyperm
++	lvx		$twk5,$x70,$key1	# borrow $twk5
++	?vperm		v30,v30,v31,$keyperm
++	lvx		v24,$x00,$key_		# pre-load round[1]
++	?vperm		v31,v31,$twk5,$keyperm
++	lvx		v25,$x10,$key_		# pre-load round[2]
++
++	 vperm		$in0,$inout,$inptail,$inpperm
++	 subi		$inp,$inp,31		# undo "caller"
++	vxor		$twk0,$tweak,$rndkey0
++	vsrab		$tmp,$tweak,$seven	# next tweak value
++	vaddubm		$tweak,$tweak,$tweak
++	vsldoi		$tmp,$tmp,$tmp,15
++	vand		$tmp,$tmp,$eighty7
++	 vxor		$out0,$in0,$twk0
++	vxor		$tweak,$tweak,$tmp
++
++	 lvx_u		$in1,$x10,$inp
++	vxor		$twk1,$tweak,$rndkey0
++	vsrab		$tmp,$tweak,$seven	# next tweak value
++	vaddubm		$tweak,$tweak,$tweak
++	vsldoi		$tmp,$tmp,$tmp,15
++	 le?vperm	$in1,$in1,$in1,$leperm
++	vand		$tmp,$tmp,$eighty7
++	 vxor		$out1,$in1,$twk1
++	vxor		$tweak,$tweak,$tmp
++
++	 lvx_u		$in2,$x20,$inp
++	 andi.		$taillen,$len,15
++	vxor		$twk2,$tweak,$rndkey0
++	vsrab		$tmp,$tweak,$seven	# next tweak value
++	vaddubm		$tweak,$tweak,$tweak
++	vsldoi		$tmp,$tmp,$tmp,15
++	 le?vperm	$in2,$in2,$in2,$leperm
++	vand		$tmp,$tmp,$eighty7
++	 vxor		$out2,$in2,$twk2
++	vxor		$tweak,$tweak,$tmp
++
++	 lvx_u		$in3,$x30,$inp
++	 sub		$len,$len,$taillen
++	vxor		$twk3,$tweak,$rndkey0
++	vsrab		$tmp,$tweak,$seven	# next tweak value
++	vaddubm		$tweak,$tweak,$tweak
++	vsldoi		$tmp,$tmp,$tmp,15
++	 le?vperm	$in3,$in3,$in3,$leperm
++	vand		$tmp,$tmp,$eighty7
++	 vxor		$out3,$in3,$twk3
++	vxor		$tweak,$tweak,$tmp
++
++	 lvx_u		$in4,$x40,$inp
++	 subi		$len,$len,0x60
++	vxor		$twk4,$tweak,$rndkey0
++	vsrab		$tmp,$tweak,$seven	# next tweak value
++	vaddubm		$tweak,$tweak,$tweak
++	vsldoi		$tmp,$tmp,$tmp,15
++	 le?vperm	$in4,$in4,$in4,$leperm
++	vand		$tmp,$tmp,$eighty7
++	 vxor		$out4,$in4,$twk4
++	vxor		$tweak,$tweak,$tmp
++
++	 lvx_u		$in5,$x50,$inp
++	 addi		$inp,$inp,0x60
++	vxor		$twk5,$tweak,$rndkey0
++	vsrab		$tmp,$tweak,$seven	# next tweak value
++	vaddubm		$tweak,$tweak,$tweak
++	vsldoi		$tmp,$tmp,$tmp,15
++	 le?vperm	$in5,$in5,$in5,$leperm
++	vand		$tmp,$tmp,$eighty7
++	 vxor		$out5,$in5,$twk5
++	vxor		$tweak,$tweak,$tmp
++
++	vxor		v31,v31,$rndkey0
++	mtctr		$rounds
++	b		Loop_xts_enc6x
++
++.align	5
++Loop_xts_enc6x:
++	vcipher		$out0,$out0,v24
++	vcipher		$out1,$out1,v24
++	vcipher		$out2,$out2,v24
++	vcipher		$out3,$out3,v24
++	vcipher		$out4,$out4,v24
++	vcipher		$out5,$out5,v24
++	lvx		v24,$x20,$key_		# round[3]
++	addi		$key_,$key_,0x20
++
++	vcipher		$out0,$out0,v25
++	vcipher		$out1,$out1,v25
++	vcipher		$out2,$out2,v25
++	vcipher		$out3,$out3,v25
++	vcipher		$out4,$out4,v25
++	vcipher		$out5,$out5,v25
++	lvx		v25,$x10,$key_		# round[4]
++	bdnz		Loop_xts_enc6x
++
++	subic		$len,$len,96		# $len-=96
++	 vxor		$in0,$twk0,v31		# xor with last round key
++	vcipher		$out0,$out0,v24
++	vcipher		$out1,$out1,v24
++	 vsrab		$tmp,$tweak,$seven	# next tweak value
++	 vxor		$twk0,$tweak,$rndkey0
++	 vaddubm	$tweak,$tweak,$tweak
++	vcipher		$out2,$out2,v24
++	vcipher		$out3,$out3,v24
++	 vsldoi		$tmp,$tmp,$tmp,15
++	vcipher		$out4,$out4,v24
++	vcipher		$out5,$out5,v24
++
++	subfe.		r0,r0,r0		# borrow?-1:0
++	 vand		$tmp,$tmp,$eighty7
++	vcipher		$out0,$out0,v25
++	vcipher		$out1,$out1,v25
++	 vxor		$tweak,$tweak,$tmp
++	vcipher		$out2,$out2,v25
++	vcipher		$out3,$out3,v25
++	 vxor		$in1,$twk1,v31
++	 vsrab		$tmp,$tweak,$seven	# next tweak value
++	 vxor		$twk1,$tweak,$rndkey0
++	vcipher		$out4,$out4,v25
++	vcipher		$out5,$out5,v25
++
++	and		r0,r0,$len
++	 vaddubm	$tweak,$tweak,$tweak
++	 vsldoi		$tmp,$tmp,$tmp,15
++	vcipher		$out0,$out0,v26
++	vcipher		$out1,$out1,v26
++	 vand		$tmp,$tmp,$eighty7
++	vcipher		$out2,$out2,v26
++	vcipher		$out3,$out3,v26
++	 vxor		$tweak,$tweak,$tmp
++	vcipher		$out4,$out4,v26
++	vcipher		$out5,$out5,v26
++
++	add		$inp,$inp,r0		# $inp is adjusted in such
++						# way that at exit from the
++						# loop inX-in5 are loaded
++						# with last "words"
++	 vxor		$in2,$twk2,v31
++	 vsrab		$tmp,$tweak,$seven	# next tweak value
++	 vxor		$twk2,$tweak,$rndkey0
++	 vaddubm	$tweak,$tweak,$tweak
++	vcipher		$out0,$out0,v27
++	vcipher		$out1,$out1,v27
++	 vsldoi		$tmp,$tmp,$tmp,15
++	vcipher		$out2,$out2,v27
++	vcipher		$out3,$out3,v27
++	 vand		$tmp,$tmp,$eighty7
++	vcipher		$out4,$out4,v27
++	vcipher		$out5,$out5,v27
++
++	addi		$key_,$sp,$FRAME+15	# rewind $key_
++	 vxor		$tweak,$tweak,$tmp
++	vcipher		$out0,$out0,v28
++	vcipher		$out1,$out1,v28
++	 vxor		$in3,$twk3,v31
++	 vsrab		$tmp,$tweak,$seven	# next tweak value
++	 vxor		$twk3,$tweak,$rndkey0
++	vcipher		$out2,$out2,v28
++	vcipher		$out3,$out3,v28
++	 vaddubm	$tweak,$tweak,$tweak
++	 vsldoi		$tmp,$tmp,$tmp,15
++	vcipher		$out4,$out4,v28
++	vcipher		$out5,$out5,v28
++	lvx		v24,$x00,$key_		# re-pre-load round[1]
++	 vand		$tmp,$tmp,$eighty7
++
++	vcipher		$out0,$out0,v29
++	vcipher		$out1,$out1,v29
++	 vxor		$tweak,$tweak,$tmp
++	vcipher		$out2,$out2,v29
++	vcipher		$out3,$out3,v29
++	 vxor		$in4,$twk4,v31
++	 vsrab		$tmp,$tweak,$seven	# next tweak value
++	 vxor		$twk4,$tweak,$rndkey0
++	vcipher		$out4,$out4,v29
++	vcipher		$out5,$out5,v29
++	lvx		v25,$x10,$key_		# re-pre-load round[2]
++	 vaddubm	$tweak,$tweak,$tweak
++	 vsldoi		$tmp,$tmp,$tmp,15
++
++	vcipher		$out0,$out0,v30
++	vcipher		$out1,$out1,v30
++	 vand		$tmp,$tmp,$eighty7
++	vcipher		$out2,$out2,v30
++	vcipher		$out3,$out3,v30
++	 vxor		$tweak,$tweak,$tmp
++	vcipher		$out4,$out4,v30
++	vcipher		$out5,$out5,v30
++	 vxor		$in5,$twk5,v31
++	 vsrab		$tmp,$tweak,$seven	# next tweak value
++	 vxor		$twk5,$tweak,$rndkey0
++
++	vcipherlast	$out0,$out0,$in0
++	 lvx_u		$in0,$x00,$inp		# load next input block
++	 vaddubm	$tweak,$tweak,$tweak
++	 vsldoi		$tmp,$tmp,$tmp,15
++	vcipherlast	$out1,$out1,$in1
++	 lvx_u		$in1,$x10,$inp
++	vcipherlast	$out2,$out2,$in2
++	 le?vperm	$in0,$in0,$in0,$leperm
++	 lvx_u		$in2,$x20,$inp
++	 vand		$tmp,$tmp,$eighty7
++	vcipherlast	$out3,$out3,$in3
++	 le?vperm	$in1,$in1,$in1,$leperm
++	 lvx_u		$in3,$x30,$inp
++	vcipherlast	$out4,$out4,$in4
++	 le?vperm	$in2,$in2,$in2,$leperm
++	 lvx_u		$in4,$x40,$inp
++	 vxor		$tweak,$tweak,$tmp
++	vcipherlast	$tmp,$out5,$in5		# last block might be needed
++						# in stealing mode
++	 le?vperm	$in3,$in3,$in3,$leperm
++	 lvx_u		$in5,$x50,$inp
++	 addi		$inp,$inp,0x60
++	 le?vperm	$in4,$in4,$in4,$leperm
++	 le?vperm	$in5,$in5,$in5,$leperm
++
++	le?vperm	$out0,$out0,$out0,$leperm
++	le?vperm	$out1,$out1,$out1,$leperm
++	stvx_u		$out0,$x00,$out		# store output
++	 vxor		$out0,$in0,$twk0
++	le?vperm	$out2,$out2,$out2,$leperm
++	stvx_u		$out1,$x10,$out
++	 vxor		$out1,$in1,$twk1
++	le?vperm	$out3,$out3,$out3,$leperm
++	stvx_u		$out2,$x20,$out
++	 vxor		$out2,$in2,$twk2
++	le?vperm	$out4,$out4,$out4,$leperm
++	stvx_u		$out3,$x30,$out
++	 vxor		$out3,$in3,$twk3
++	le?vperm	$out5,$tmp,$tmp,$leperm
++	stvx_u		$out4,$x40,$out
++	 vxor		$out4,$in4,$twk4
++	le?stvx_u	$out5,$x50,$out
++	be?stvx_u	$tmp, $x50,$out
++	 vxor		$out5,$in5,$twk5
++	addi		$out,$out,0x60
++
++	mtctr		$rounds
++	beq		Loop_xts_enc6x		# did $len-=96 borrow?
++
++	addic.		$len,$len,0x60
++	beq		Lxts_enc6x_zero
++	cmpwi		$len,0x20
++	blt		Lxts_enc6x_one
++	nop
++	beq		Lxts_enc6x_two
++	cmpwi		$len,0x40
++	blt		Lxts_enc6x_three
++	nop
++	beq		Lxts_enc6x_four
++
++Lxts_enc6x_five:
++	vxor		$out0,$in1,$twk0
++	vxor		$out1,$in2,$twk1
++	vxor		$out2,$in3,$twk2
++	vxor		$out3,$in4,$twk3
++	vxor		$out4,$in5,$twk4
++
++	bl		_aesp8_xts_enc5x
++
++	le?vperm	$out0,$out0,$out0,$leperm
++	vmr		$twk0,$twk5		# unused tweak
++	le?vperm	$out1,$out1,$out1,$leperm
++	stvx_u		$out0,$x00,$out		# store output
++	le?vperm	$out2,$out2,$out2,$leperm
++	stvx_u		$out1,$x10,$out
++	le?vperm	$out3,$out3,$out3,$leperm
++	stvx_u		$out2,$x20,$out
++	vxor		$tmp,$out4,$twk5	# last block prep for stealing
++	le?vperm	$out4,$out4,$out4,$leperm
++	stvx_u		$out3,$x30,$out
++	stvx_u		$out4,$x40,$out
++	addi		$out,$out,0x50
++	bne		Lxts_enc6x_steal
++	b		Lxts_enc6x_done
++
++.align	4
++Lxts_enc6x_four:
++	vxor		$out0,$in2,$twk0
++	vxor		$out1,$in3,$twk1
++	vxor		$out2,$in4,$twk2
++	vxor		$out3,$in5,$twk3
++	vxor		$out4,$out4,$out4
++
++	bl		_aesp8_xts_enc5x
++
++	le?vperm	$out0,$out0,$out0,$leperm
++	vmr		$twk0,$twk4		# unused tweak
++	le?vperm	$out1,$out1,$out1,$leperm
++	stvx_u		$out0,$x00,$out		# store output
++	le?vperm	$out2,$out2,$out2,$leperm
++	stvx_u		$out1,$x10,$out
++	vxor		$tmp,$out3,$twk4	# last block prep for stealing
++	le?vperm	$out3,$out3,$out3,$leperm
++	stvx_u		$out2,$x20,$out
++	stvx_u		$out3,$x30,$out
++	addi		$out,$out,0x40
++	bne		Lxts_enc6x_steal
++	b		Lxts_enc6x_done
++
++.align	4
++Lxts_enc6x_three:
++	vxor		$out0,$in3,$twk0
++	vxor		$out1,$in4,$twk1
++	vxor		$out2,$in5,$twk2
++	vxor		$out3,$out3,$out3
++	vxor		$out4,$out4,$out4
++
++	bl		_aesp8_xts_enc5x
++
++	le?vperm	$out0,$out0,$out0,$leperm
++	vmr		$twk0,$twk3		# unused tweak
++	le?vperm	$out1,$out1,$out1,$leperm
++	stvx_u		$out0,$x00,$out		# store output
++	vxor		$tmp,$out2,$twk3	# last block prep for stealing
++	le?vperm	$out2,$out2,$out2,$leperm
++	stvx_u		$out1,$x10,$out
++	stvx_u		$out2,$x20,$out
++	addi		$out,$out,0x30
++	bne		Lxts_enc6x_steal
++	b		Lxts_enc6x_done
++
++.align	4
++Lxts_enc6x_two:
++	vxor		$out0,$in4,$twk0
++	vxor		$out1,$in5,$twk1
++	vxor		$out2,$out2,$out2
++	vxor		$out3,$out3,$out3
++	vxor		$out4,$out4,$out4
++
++	bl		_aesp8_xts_enc5x
++
++	le?vperm	$out0,$out0,$out0,$leperm
++	vmr		$twk0,$twk2		# unused tweak
++	vxor		$tmp,$out1,$twk2	# last block prep for stealing
++	le?vperm	$out1,$out1,$out1,$leperm
++	stvx_u		$out0,$x00,$out		# store output
++	stvx_u		$out1,$x10,$out
++	addi		$out,$out,0x20
++	bne		Lxts_enc6x_steal
++	b		Lxts_enc6x_done
++
++.align	4
++Lxts_enc6x_one:
++	vxor		$out0,$in5,$twk0
++	nop
++Loop_xts_enc1x:
++	vcipher		$out0,$out0,v24
++	lvx		v24,$x20,$key_		# round[3]
++	addi		$key_,$key_,0x20
++
++	vcipher		$out0,$out0,v25
++	lvx		v25,$x10,$key_		# round[4]
++	bdnz		Loop_xts_enc1x
++
++	add		$inp,$inp,$taillen
++	cmpwi		$taillen,0
++	vcipher		$out0,$out0,v24
++
++	subi		$inp,$inp,16
++	vcipher		$out0,$out0,v25
++
++	lvsr		$inpperm,0,$taillen
++	vcipher		$out0,$out0,v26
++
++	lvx_u		$in0,0,$inp
++	vcipher		$out0,$out0,v27
++
++	addi		$key_,$sp,$FRAME+15	# rewind $key_
++	vcipher		$out0,$out0,v28
++	lvx		v24,$x00,$key_		# re-pre-load round[1]
++
++	vcipher		$out0,$out0,v29
++	lvx		v25,$x10,$key_		# re-pre-load round[2]
++	 vxor		$twk0,$twk0,v31
++
++	le?vperm	$in0,$in0,$in0,$leperm
++	vcipher		$out0,$out0,v30
++
++	vperm		$in0,$in0,$in0,$inpperm
++	vcipherlast	$out0,$out0,$twk0
++
++	vmr		$twk0,$twk1		# unused tweak
++	vxor		$tmp,$out0,$twk1	# last block prep for stealing
++	le?vperm	$out0,$out0,$out0,$leperm
++	stvx_u		$out0,$x00,$out		# store output
++	addi		$out,$out,0x10
++	bne		Lxts_enc6x_steal
++	b		Lxts_enc6x_done
++
++.align	4
++Lxts_enc6x_zero:
++	cmpwi		$taillen,0
++	beq		Lxts_enc6x_done
++
++	add		$inp,$inp,$taillen
++	subi		$inp,$inp,16
++	lvx_u		$in0,0,$inp
++	lvsr		$inpperm,0,$taillen	# $in5 is no more
++	le?vperm	$in0,$in0,$in0,$leperm
++	vperm		$in0,$in0,$in0,$inpperm
++	vxor		$tmp,$tmp,$twk0
++Lxts_enc6x_steal:
++	vxor		$in0,$in0,$twk0
++	vxor		$out0,$out0,$out0
++	vspltisb	$out1,-1
++	vperm		$out0,$out0,$out1,$inpperm
++	vsel		$out0,$in0,$tmp,$out0	# $tmp is last block, remember?
++
++	subi		r30,$out,17
++	subi		$out,$out,16
++	mtctr		$taillen
++Loop_xts_enc6x_steal:
++	lbzu		r0,1(r30)
++	stb		r0,16(r30)
++	bdnz		Loop_xts_enc6x_steal
++
++	li		$taillen,0
++	mtctr		$rounds
++	b		Loop_xts_enc1x		# one more time...
++
++.align	4
++Lxts_enc6x_done:
++	${UCMP}i	$ivp,0
++	beq		Lxts_enc6x_ret
++
++	vxor		$tweak,$twk0,$rndkey0
++	le?vperm	$tweak,$tweak,$tweak,$leperm
++	stvx_u		$tweak,0,$ivp
++
++Lxts_enc6x_ret:
++	mtlr		r11
++	li		r10,`$FRAME+15`
++	li		r11,`$FRAME+31`
++	stvx		$seven,r10,$sp		# wipe copies of round keys
++	addi		r10,r10,32
++	stvx		$seven,r11,$sp
++	addi		r11,r11,32
++	stvx		$seven,r10,$sp
++	addi		r10,r10,32
++	stvx		$seven,r11,$sp
++	addi		r11,r11,32
++	stvx		$seven,r10,$sp
++	addi		r10,r10,32
++	stvx		$seven,r11,$sp
++	addi		r11,r11,32
++	stvx		$seven,r10,$sp
++	addi		r10,r10,32
++	stvx		$seven,r11,$sp
++	addi		r11,r11,32
++
++	mtspr		256,$vrsave
++	lvx		v20,r10,$sp		# ABI says so
++	addi		r10,r10,32
++	lvx		v21,r11,$sp
++	addi		r11,r11,32
++	lvx		v22,r10,$sp
++	addi		r10,r10,32
++	lvx		v23,r11,$sp
++	addi		r11,r11,32
++	lvx		v24,r10,$sp
++	addi		r10,r10,32
++	lvx		v25,r11,$sp
++	addi		r11,r11,32
++	lvx		v26,r10,$sp
++	addi		r10,r10,32
++	lvx		v27,r11,$sp
++	addi		r11,r11,32
++	lvx		v28,r10,$sp
++	addi		r10,r10,32
++	lvx		v29,r11,$sp
++	addi		r11,r11,32
++	lvx		v30,r10,$sp
++	lvx		v31,r11,$sp
++	$POP		r26,`$FRAME+21*16+0*$SIZE_T`($sp)
++	$POP		r27,`$FRAME+21*16+1*$SIZE_T`($sp)
++	$POP		r28,`$FRAME+21*16+2*$SIZE_T`($sp)
++	$POP		r29,`$FRAME+21*16+3*$SIZE_T`($sp)
++	$POP		r30,`$FRAME+21*16+4*$SIZE_T`($sp)
++	$POP		r31,`$FRAME+21*16+5*$SIZE_T`($sp)
++	addi		$sp,$sp,`$FRAME+21*16+6*$SIZE_T`
++	blr
++	.long		0
++	.byte		0,12,0x04,1,0x80,6,6,0
++	.long		0
++
++.align	5
++_aesp8_xts_enc5x:
++	vcipher		$out0,$out0,v24
++	vcipher		$out1,$out1,v24
++	vcipher		$out2,$out2,v24
++	vcipher		$out3,$out3,v24
++	vcipher		$out4,$out4,v24
++	lvx		v24,$x20,$key_		# round[3]
++	addi		$key_,$key_,0x20
++
++	vcipher		$out0,$out0,v25
++	vcipher		$out1,$out1,v25
++	vcipher		$out2,$out2,v25
++	vcipher		$out3,$out3,v25
++	vcipher		$out4,$out4,v25
++	lvx		v25,$x10,$key_		# round[4]
++	bdnz		_aesp8_xts_enc5x
++
++	add		$inp,$inp,$taillen
++	cmpwi		$taillen,0
++	vcipher		$out0,$out0,v24
++	vcipher		$out1,$out1,v24
++	vcipher		$out2,$out2,v24
++	vcipher		$out3,$out3,v24
++	vcipher		$out4,$out4,v24
++
++	subi		$inp,$inp,16
++	vcipher		$out0,$out0,v25
++	vcipher		$out1,$out1,v25
++	vcipher		$out2,$out2,v25
++	vcipher		$out3,$out3,v25
++	vcipher		$out4,$out4,v25
++	 vxor		$twk0,$twk0,v31
++
++	vcipher		$out0,$out0,v26
++	lvsr		$inpperm,0,$taillen	# $in5 is no more
++	vcipher		$out1,$out1,v26
++	vcipher		$out2,$out2,v26
++	vcipher		$out3,$out3,v26
++	vcipher		$out4,$out4,v26
++	 vxor		$in1,$twk1,v31
++
++	vcipher		$out0,$out0,v27
++	lvx_u		$in0,0,$inp
++	vcipher		$out1,$out1,v27
++	vcipher		$out2,$out2,v27
++	vcipher		$out3,$out3,v27
++	vcipher		$out4,$out4,v27
++	 vxor		$in2,$twk2,v31
++
++	addi		$key_,$sp,$FRAME+15	# rewind $key_
++	vcipher		$out0,$out0,v28
++	vcipher		$out1,$out1,v28
++	vcipher		$out2,$out2,v28
++	vcipher		$out3,$out3,v28
++	vcipher		$out4,$out4,v28
++	lvx		v24,$x00,$key_		# re-pre-load round[1]
++	 vxor		$in3,$twk3,v31
++
++	vcipher		$out0,$out0,v29
++	le?vperm	$in0,$in0,$in0,$leperm
++	vcipher		$out1,$out1,v29
++	vcipher		$out2,$out2,v29
++	vcipher		$out3,$out3,v29
++	vcipher		$out4,$out4,v29
++	lvx		v25,$x10,$key_		# re-pre-load round[2]
++	 vxor		$in4,$twk4,v31
++
++	vcipher		$out0,$out0,v30
++	vperm		$in0,$in0,$in0,$inpperm
++	vcipher		$out1,$out1,v30
++	vcipher		$out2,$out2,v30
++	vcipher		$out3,$out3,v30
++	vcipher		$out4,$out4,v30
++
++	vcipherlast	$out0,$out0,$twk0
++	vcipherlast	$out1,$out1,$in1
++	vcipherlast	$out2,$out2,$in2
++	vcipherlast	$out3,$out3,$in3
++	vcipherlast	$out4,$out4,$in4
++	blr
++        .long   	0
++        .byte   	0,12,0x14,0,0,0,0,0
++
++.align	5
++_aesp8_xts_decrypt6x:
++	$STU		$sp,-`($FRAME+21*16+6*$SIZE_T)`($sp)
++	mflr		r11
++	li		r7,`$FRAME+8*16+15`
++	li		r3,`$FRAME+8*16+31`
++	$PUSH		r11,`$FRAME+21*16+6*$SIZE_T+$LRSAVE`($sp)
++	stvx		v20,r7,$sp		# ABI says so
++	addi		r7,r7,32
++	stvx		v21,r3,$sp
++	addi		r3,r3,32
++	stvx		v22,r7,$sp
++	addi		r7,r7,32
++	stvx		v23,r3,$sp
++	addi		r3,r3,32
++	stvx		v24,r7,$sp
++	addi		r7,r7,32
++	stvx		v25,r3,$sp
++	addi		r3,r3,32
++	stvx		v26,r7,$sp
++	addi		r7,r7,32
++	stvx		v27,r3,$sp
++	addi		r3,r3,32
++	stvx		v28,r7,$sp
++	addi		r7,r7,32
++	stvx		v29,r3,$sp
++	addi		r3,r3,32
++	stvx		v30,r7,$sp
++	stvx		v31,r3,$sp
++	li		r0,-1
++	stw		$vrsave,`$FRAME+21*16-4`($sp)	# save vrsave
++	li		$x10,0x10
++	$PUSH		r26,`$FRAME+21*16+0*$SIZE_T`($sp)
++	li		$x20,0x20
++	$PUSH		r27,`$FRAME+21*16+1*$SIZE_T`($sp)
++	li		$x30,0x30
++	$PUSH		r28,`$FRAME+21*16+2*$SIZE_T`($sp)
++	li		$x40,0x40
++	$PUSH		r29,`$FRAME+21*16+3*$SIZE_T`($sp)
++	li		$x50,0x50
++	$PUSH		r30,`$FRAME+21*16+4*$SIZE_T`($sp)
++	li		$x60,0x60
++	$PUSH		r31,`$FRAME+21*16+5*$SIZE_T`($sp)
++	li		$x70,0x70
++	mtspr		256,r0
++
++	subi		$rounds,$rounds,3	# -4 in total
++
++	lvx		$rndkey0,$x00,$key1	# load key schedule
++	lvx		v30,$x10,$key1
++	addi		$key1,$key1,0x20
++	lvx		v31,$x00,$key1
++	?vperm		$rndkey0,$rndkey0,v30,$keyperm
++	addi		$key_,$sp,$FRAME+15
++	mtctr		$rounds
++
++Load_xts_dec_key:
++	?vperm		v24,v30,v31,$keyperm
++	lvx		v30,$x10,$key1
++	addi		$key1,$key1,0x20
++	stvx		v24,$x00,$key_		# off-load round[1]
++	?vperm		v25,v31,v30,$keyperm
++	lvx		v31,$x00,$key1
++	stvx		v25,$x10,$key_		# off-load round[2]
++	addi		$key_,$key_,0x20
++	bdnz		Load_xts_dec_key
++
++	lvx		v26,$x10,$key1
++	?vperm		v24,v30,v31,$keyperm
++	lvx		v27,$x20,$key1
++	stvx		v24,$x00,$key_		# off-load round[3]
++	?vperm		v25,v31,v26,$keyperm
++	lvx		v28,$x30,$key1
++	stvx		v25,$x10,$key_		# off-load round[4]
++	addi		$key_,$sp,$FRAME+15	# rewind $key_
++	?vperm		v26,v26,v27,$keyperm
++	lvx		v29,$x40,$key1
++	?vperm		v27,v27,v28,$keyperm
++	lvx		v30,$x50,$key1
++	?vperm		v28,v28,v29,$keyperm
++	lvx		v31,$x60,$key1
++	?vperm		v29,v29,v30,$keyperm
++	lvx		$twk5,$x70,$key1	# borrow $twk5
++	?vperm		v30,v30,v31,$keyperm
++	lvx		v24,$x00,$key_		# pre-load round[1]
++	?vperm		v31,v31,$twk5,$keyperm
++	lvx		v25,$x10,$key_		# pre-load round[2]
++
++	 vperm		$in0,$inout,$inptail,$inpperm
++	 subi		$inp,$inp,31		# undo "caller"
++	vxor		$twk0,$tweak,$rndkey0
++	vsrab		$tmp,$tweak,$seven	# next tweak value
++	vaddubm		$tweak,$tweak,$tweak
++	vsldoi		$tmp,$tmp,$tmp,15
++	vand		$tmp,$tmp,$eighty7
++	 vxor		$out0,$in0,$twk0
++	vxor		$tweak,$tweak,$tmp
++
++	 lvx_u		$in1,$x10,$inp
++	vxor		$twk1,$tweak,$rndkey0
++	vsrab		$tmp,$tweak,$seven	# next tweak value
++	vaddubm		$tweak,$tweak,$tweak
++	vsldoi		$tmp,$tmp,$tmp,15
++	 le?vperm	$in1,$in1,$in1,$leperm
++	vand		$tmp,$tmp,$eighty7
++	 vxor		$out1,$in1,$twk1
++	vxor		$tweak,$tweak,$tmp
++
++	 lvx_u		$in2,$x20,$inp
++	 andi.		$taillen,$len,15
++	vxor		$twk2,$tweak,$rndkey0
++	vsrab		$tmp,$tweak,$seven	# next tweak value
++	vaddubm		$tweak,$tweak,$tweak
++	vsldoi		$tmp,$tmp,$tmp,15
++	 le?vperm	$in2,$in2,$in2,$leperm
++	vand		$tmp,$tmp,$eighty7
++	 vxor		$out2,$in2,$twk2
++	vxor		$tweak,$tweak,$tmp
++
++	 lvx_u		$in3,$x30,$inp
++	 sub		$len,$len,$taillen
++	vxor		$twk3,$tweak,$rndkey0
++	vsrab		$tmp,$tweak,$seven	# next tweak value
++	vaddubm		$tweak,$tweak,$tweak
++	vsldoi		$tmp,$tmp,$tmp,15
++	 le?vperm	$in3,$in3,$in3,$leperm
++	vand		$tmp,$tmp,$eighty7
++	 vxor		$out3,$in3,$twk3
++	vxor		$tweak,$tweak,$tmp
++
++	 lvx_u		$in4,$x40,$inp
++	 subi		$len,$len,0x60
++	vxor		$twk4,$tweak,$rndkey0
++	vsrab		$tmp,$tweak,$seven	# next tweak value
++	vaddubm		$tweak,$tweak,$tweak
++	vsldoi		$tmp,$tmp,$tmp,15
++	 le?vperm	$in4,$in4,$in4,$leperm
++	vand		$tmp,$tmp,$eighty7
++	 vxor		$out4,$in4,$twk4
++	vxor		$tweak,$tweak,$tmp
++
++	 lvx_u		$in5,$x50,$inp
++	 addi		$inp,$inp,0x60
++	vxor		$twk5,$tweak,$rndkey0
++	vsrab		$tmp,$tweak,$seven	# next tweak value
++	vaddubm		$tweak,$tweak,$tweak
++	vsldoi		$tmp,$tmp,$tmp,15
++	 le?vperm	$in5,$in5,$in5,$leperm
++	vand		$tmp,$tmp,$eighty7
++	 vxor		$out5,$in5,$twk5
++	vxor		$tweak,$tweak,$tmp
++
++	vxor		v31,v31,$rndkey0
++	mtctr		$rounds
++	b		Loop_xts_dec6x
++
++.align	5
++Loop_xts_dec6x:
++	vncipher	$out0,$out0,v24
++	vncipher	$out1,$out1,v24
++	vncipher	$out2,$out2,v24
++	vncipher	$out3,$out3,v24
++	vncipher	$out4,$out4,v24
++	vncipher	$out5,$out5,v24
++	lvx		v24,$x20,$key_		# round[3]
++	addi		$key_,$key_,0x20
++
++	vncipher	$out0,$out0,v25
++	vncipher	$out1,$out1,v25
++	vncipher	$out2,$out2,v25
++	vncipher	$out3,$out3,v25
++	vncipher	$out4,$out4,v25
++	vncipher	$out5,$out5,v25
++	lvx		v25,$x10,$key_		# round[4]
++	bdnz		Loop_xts_dec6x
++
++	subic		$len,$len,96		# $len-=96
++	 vxor		$in0,$twk0,v31		# xor with last round key
++	vncipher	$out0,$out0,v24
++	vncipher	$out1,$out1,v24
++	 vsrab		$tmp,$tweak,$seven	# next tweak value
++	 vxor		$twk0,$tweak,$rndkey0
++	 vaddubm	$tweak,$tweak,$tweak
++	vncipher	$out2,$out2,v24
++	vncipher	$out3,$out3,v24
++	 vsldoi		$tmp,$tmp,$tmp,15
++	vncipher	$out4,$out4,v24
++	vncipher	$out5,$out5,v24
++
++	subfe.		r0,r0,r0		# borrow?-1:0
++	 vand		$tmp,$tmp,$eighty7
++	vncipher	$out0,$out0,v25
++	vncipher	$out1,$out1,v25
++	 vxor		$tweak,$tweak,$tmp
++	vncipher	$out2,$out2,v25
++	vncipher	$out3,$out3,v25
++	 vxor		$in1,$twk1,v31
++	 vsrab		$tmp,$tweak,$seven	# next tweak value
++	 vxor		$twk1,$tweak,$rndkey0
++	vncipher	$out4,$out4,v25
++	vncipher	$out5,$out5,v25
++
++	and		r0,r0,$len
++	 vaddubm	$tweak,$tweak,$tweak
++	 vsldoi		$tmp,$tmp,$tmp,15
++	vncipher	$out0,$out0,v26
++	vncipher	$out1,$out1,v26
++	 vand		$tmp,$tmp,$eighty7
++	vncipher	$out2,$out2,v26
++	vncipher	$out3,$out3,v26
++	 vxor		$tweak,$tweak,$tmp
++	vncipher	$out4,$out4,v26
++	vncipher	$out5,$out5,v26
++
++	add		$inp,$inp,r0		# $inp is adjusted in such
++						# way that at exit from the
++						# loop inX-in5 are loaded
++						# with last "words"
++	 vxor		$in2,$twk2,v31
++	 vsrab		$tmp,$tweak,$seven	# next tweak value
++	 vxor		$twk2,$tweak,$rndkey0
++	 vaddubm	$tweak,$tweak,$tweak
++	vncipher	$out0,$out0,v27
++	vncipher	$out1,$out1,v27
++	 vsldoi		$tmp,$tmp,$tmp,15
++	vncipher	$out2,$out2,v27
++	vncipher	$out3,$out3,v27
++	 vand		$tmp,$tmp,$eighty7
++	vncipher	$out4,$out4,v27
++	vncipher	$out5,$out5,v27
++
++	addi		$key_,$sp,$FRAME+15	# rewind $key_
++	 vxor		$tweak,$tweak,$tmp
++	vncipher	$out0,$out0,v28
++	vncipher	$out1,$out1,v28
++	 vxor		$in3,$twk3,v31
++	 vsrab		$tmp,$tweak,$seven	# next tweak value
++	 vxor		$twk3,$tweak,$rndkey0
++	vncipher	$out2,$out2,v28
++	vncipher	$out3,$out3,v28
++	 vaddubm	$tweak,$tweak,$tweak
++	 vsldoi		$tmp,$tmp,$tmp,15
++	vncipher	$out4,$out4,v28
++	vncipher	$out5,$out5,v28
++	lvx		v24,$x00,$key_		# re-pre-load round[1]
++	 vand		$tmp,$tmp,$eighty7
++
++	vncipher	$out0,$out0,v29
++	vncipher	$out1,$out1,v29
++	 vxor		$tweak,$tweak,$tmp
++	vncipher	$out2,$out2,v29
++	vncipher	$out3,$out3,v29
++	 vxor		$in4,$twk4,v31
++	 vsrab		$tmp,$tweak,$seven	# next tweak value
++	 vxor		$twk4,$tweak,$rndkey0
++	vncipher	$out4,$out4,v29
++	vncipher	$out5,$out5,v29
++	lvx		v25,$x10,$key_		# re-pre-load round[2]
++	 vaddubm	$tweak,$tweak,$tweak
++	 vsldoi		$tmp,$tmp,$tmp,15
++
++	vncipher	$out0,$out0,v30
++	vncipher	$out1,$out1,v30
++	 vand		$tmp,$tmp,$eighty7
++	vncipher	$out2,$out2,v30
++	vncipher	$out3,$out3,v30
++	 vxor		$tweak,$tweak,$tmp
++	vncipher	$out4,$out4,v30
++	vncipher	$out5,$out5,v30
++	 vxor		$in5,$twk5,v31
++	 vsrab		$tmp,$tweak,$seven	# next tweak value
++	 vxor		$twk5,$tweak,$rndkey0
++
++	vncipherlast	$out0,$out0,$in0
++	 lvx_u		$in0,$x00,$inp		# load next input block
++	 vaddubm	$tweak,$tweak,$tweak
++	 vsldoi		$tmp,$tmp,$tmp,15
++	vncipherlast	$out1,$out1,$in1
++	 lvx_u		$in1,$x10,$inp
++	vncipherlast	$out2,$out2,$in2
++	 le?vperm	$in0,$in0,$in0,$leperm
++	 lvx_u		$in2,$x20,$inp
++	 vand		$tmp,$tmp,$eighty7
++	vncipherlast	$out3,$out3,$in3
++	 le?vperm	$in1,$in1,$in1,$leperm
++	 lvx_u		$in3,$x30,$inp
++	vncipherlast	$out4,$out4,$in4
++	 le?vperm	$in2,$in2,$in2,$leperm
++	 lvx_u		$in4,$x40,$inp
++	 vxor		$tweak,$tweak,$tmp
++	vncipherlast	$out5,$out5,$in5
++	 le?vperm	$in3,$in3,$in3,$leperm
++	 lvx_u		$in5,$x50,$inp
++	 addi		$inp,$inp,0x60
++	 le?vperm	$in4,$in4,$in4,$leperm
++	 le?vperm	$in5,$in5,$in5,$leperm
++
++	le?vperm	$out0,$out0,$out0,$leperm
++	le?vperm	$out1,$out1,$out1,$leperm
++	stvx_u		$out0,$x00,$out		# store output
++	 vxor		$out0,$in0,$twk0
++	le?vperm	$out2,$out2,$out2,$leperm
++	stvx_u		$out1,$x10,$out
++	 vxor		$out1,$in1,$twk1
++	le?vperm	$out3,$out3,$out3,$leperm
++	stvx_u		$out2,$x20,$out
++	 vxor		$out2,$in2,$twk2
++	le?vperm	$out4,$out4,$out4,$leperm
++	stvx_u		$out3,$x30,$out
++	 vxor		$out3,$in3,$twk3
++	le?vperm	$out5,$out5,$out5,$leperm
++	stvx_u		$out4,$x40,$out
++	 vxor		$out4,$in4,$twk4
++	stvx_u		$out5,$x50,$out
++	 vxor		$out5,$in5,$twk5
++	addi		$out,$out,0x60
++
++	mtctr		$rounds
++	beq		Loop_xts_dec6x		# did $len-=96 borrow?
++
++	addic.		$len,$len,0x60
++	beq		Lxts_dec6x_zero
++	cmpwi		$len,0x20
++	blt		Lxts_dec6x_one
++	nop
++	beq		Lxts_dec6x_two
++	cmpwi		$len,0x40
++	blt		Lxts_dec6x_three
++	nop
++	beq		Lxts_dec6x_four
++
++Lxts_dec6x_five:
++	vxor		$out0,$in1,$twk0
++	vxor		$out1,$in2,$twk1
++	vxor		$out2,$in3,$twk2
++	vxor		$out3,$in4,$twk3
++	vxor		$out4,$in5,$twk4
++
++	bl		_aesp8_xts_dec5x
++
++	le?vperm	$out0,$out0,$out0,$leperm
++	vmr		$twk0,$twk5		# unused tweak
++	vxor		$twk1,$tweak,$rndkey0
++	le?vperm	$out1,$out1,$out1,$leperm
++	stvx_u		$out0,$x00,$out		# store output
++	vxor		$out0,$in0,$twk1
++	le?vperm	$out2,$out2,$out2,$leperm
++	stvx_u		$out1,$x10,$out
++	le?vperm	$out3,$out3,$out3,$leperm
++	stvx_u		$out2,$x20,$out
++	le?vperm	$out4,$out4,$out4,$leperm
++	stvx_u		$out3,$x30,$out
++	stvx_u		$out4,$x40,$out
++	addi		$out,$out,0x50
++	bne		Lxts_dec6x_steal
++	b		Lxts_dec6x_done
++
++.align	4
++Lxts_dec6x_four:
++	vxor		$out0,$in2,$twk0
++	vxor		$out1,$in3,$twk1
++	vxor		$out2,$in4,$twk2
++	vxor		$out3,$in5,$twk3
++	vxor		$out4,$out4,$out4
++
++	bl		_aesp8_xts_dec5x
++
++	le?vperm	$out0,$out0,$out0,$leperm
++	vmr		$twk0,$twk4		# unused tweak
++	vmr		$twk1,$twk5
++	le?vperm	$out1,$out1,$out1,$leperm
++	stvx_u		$out0,$x00,$out		# store output
++	vxor		$out0,$in0,$twk5
++	le?vperm	$out2,$out2,$out2,$leperm
++	stvx_u		$out1,$x10,$out
++	le?vperm	$out3,$out3,$out3,$leperm
++	stvx_u		$out2,$x20,$out
++	stvx_u		$out3,$x30,$out
++	addi		$out,$out,0x40
++	bne		Lxts_dec6x_steal
++	b		Lxts_dec6x_done
++
++.align	4
++Lxts_dec6x_three:
++	vxor		$out0,$in3,$twk0
++	vxor		$out1,$in4,$twk1
++	vxor		$out2,$in5,$twk2
++	vxor		$out3,$out3,$out3
++	vxor		$out4,$out4,$out4
++
++	bl		_aesp8_xts_dec5x
++
++	le?vperm	$out0,$out0,$out0,$leperm
++	vmr		$twk0,$twk3		# unused tweak
++	vmr		$twk1,$twk4
++	le?vperm	$out1,$out1,$out1,$leperm
++	stvx_u		$out0,$x00,$out		# store output
++	vxor		$out0,$in0,$twk4
++	le?vperm	$out2,$out2,$out2,$leperm
++	stvx_u		$out1,$x10,$out
++	stvx_u		$out2,$x20,$out
++	addi		$out,$out,0x30
++	bne		Lxts_dec6x_steal
++	b		Lxts_dec6x_done
++
++.align	4
++Lxts_dec6x_two:
++	vxor		$out0,$in4,$twk0
++	vxor		$out1,$in5,$twk1
++	vxor		$out2,$out2,$out2
++	vxor		$out3,$out3,$out3
++	vxor		$out4,$out4,$out4
++
++	bl		_aesp8_xts_dec5x
++
++	le?vperm	$out0,$out0,$out0,$leperm
++	vmr		$twk0,$twk2		# unused tweak
++	vmr		$twk1,$twk3
++	le?vperm	$out1,$out1,$out1,$leperm
++	stvx_u		$out0,$x00,$out		# store output
++	vxor		$out0,$in0,$twk3
++	stvx_u		$out1,$x10,$out
++	addi		$out,$out,0x20
++	bne		Lxts_dec6x_steal
++	b		Lxts_dec6x_done
++
++.align	4
++Lxts_dec6x_one:
++	vxor		$out0,$in5,$twk0
++	nop
++Loop_xts_dec1x:
++	vncipher	$out0,$out0,v24
++	lvx		v24,$x20,$key_		# round[3]
++	addi		$key_,$key_,0x20
++
++	vncipher	$out0,$out0,v25
++	lvx		v25,$x10,$key_		# round[4]
++	bdnz		Loop_xts_dec1x
++
++	subi		r0,$taillen,1
++	vncipher	$out0,$out0,v24
++
++	andi.		r0,r0,16
++	cmpwi		$taillen,0
++	vncipher	$out0,$out0,v25
++
++	sub		$inp,$inp,r0
++	vncipher	$out0,$out0,v26
++
++	lvx_u		$in0,0,$inp
++	vncipher	$out0,$out0,v27
++
++	addi		$key_,$sp,$FRAME+15	# rewind $key_
++	vncipher	$out0,$out0,v28
++	lvx		v24,$x00,$key_		# re-pre-load round[1]
++
++	vncipher	$out0,$out0,v29
++	lvx		v25,$x10,$key_		# re-pre-load round[2]
++	 vxor		$twk0,$twk0,v31
++
++	le?vperm	$in0,$in0,$in0,$leperm
++	vncipher	$out0,$out0,v30
++
++	mtctr		$rounds
++	vncipherlast	$out0,$out0,$twk0
++
++	vmr		$twk0,$twk1		# unused tweak
++	vmr		$twk1,$twk2
++	le?vperm	$out0,$out0,$out0,$leperm
++	stvx_u		$out0,$x00,$out		# store output
++	addi		$out,$out,0x10
++	vxor		$out0,$in0,$twk2
++	bne		Lxts_dec6x_steal
++	b		Lxts_dec6x_done
++
++.align	4
++Lxts_dec6x_zero:
++	cmpwi		$taillen,0
++	beq		Lxts_dec6x_done
++
++	lvx_u		$in0,0,$inp
++	le?vperm	$in0,$in0,$in0,$leperm
++	vxor		$out0,$in0,$twk1
++Lxts_dec6x_steal:
++	vncipher	$out0,$out0,v24
++	lvx		v24,$x20,$key_		# round[3]
++	addi		$key_,$key_,0x20
++
++	vncipher	$out0,$out0,v25
++	lvx		v25,$x10,$key_		# round[4]
++	bdnz		Lxts_dec6x_steal
++
++	add		$inp,$inp,$taillen
++	vncipher	$out0,$out0,v24
++
++	cmpwi		$taillen,0
++	vncipher	$out0,$out0,v25
++
++	lvx_u		$in0,0,$inp
++	vncipher	$out0,$out0,v26
++
++	lvsr		$inpperm,0,$taillen	# $in5 is no more
++	vncipher	$out0,$out0,v27
++
++	addi		$key_,$sp,$FRAME+15	# rewind $key_
++	vncipher	$out0,$out0,v28
++	lvx		v24,$x00,$key_		# re-pre-load round[1]
++
++	vncipher	$out0,$out0,v29
++	lvx		v25,$x10,$key_		# re-pre-load round[2]
++	 vxor		$twk1,$twk1,v31
++
++	le?vperm	$in0,$in0,$in0,$leperm
++	vncipher	$out0,$out0,v30
++
++	vperm		$in0,$in0,$in0,$inpperm
++	vncipherlast	$tmp,$out0,$twk1
++
++	le?vperm	$out0,$tmp,$tmp,$leperm
++	le?stvx_u	$out0,0,$out
++	be?stvx_u	$tmp,0,$out
++
++	vxor		$out0,$out0,$out0
++	vspltisb	$out1,-1
++	vperm		$out0,$out0,$out1,$inpperm
++	vsel		$out0,$in0,$tmp,$out0
++	vxor		$out0,$out0,$twk0
++
++	subi		r30,$out,1
++	mtctr		$taillen
++Loop_xts_dec6x_steal:
++	lbzu		r0,1(r30)
++	stb		r0,16(r30)
++	bdnz		Loop_xts_dec6x_steal
++
++	li		$taillen,0
++	mtctr		$rounds
++	b		Loop_xts_dec1x		# one more time...
++
++.align	4
++Lxts_dec6x_done:
++	${UCMP}i	$ivp,0
++	beq		Lxts_dec6x_ret
++
++	vxor		$tweak,$twk0,$rndkey0
++	le?vperm	$tweak,$tweak,$tweak,$leperm
++	stvx_u		$tweak,0,$ivp
++
++Lxts_dec6x_ret:
++	mtlr		r11
++	li		r10,`$FRAME+15`
++	li		r11,`$FRAME+31`
++	stvx		$seven,r10,$sp		# wipe copies of round keys
++	addi		r10,r10,32
++	stvx		$seven,r11,$sp
++	addi		r11,r11,32
++	stvx		$seven,r10,$sp
++	addi		r10,r10,32
++	stvx		$seven,r11,$sp
++	addi		r11,r11,32
++	stvx		$seven,r10,$sp
++	addi		r10,r10,32
++	stvx		$seven,r11,$sp
++	addi		r11,r11,32
++	stvx		$seven,r10,$sp
++	addi		r10,r10,32
++	stvx		$seven,r11,$sp
++	addi		r11,r11,32
++
++	mtspr		256,$vrsave
++	lvx		v20,r10,$sp		# ABI says so
++	addi		r10,r10,32
++	lvx		v21,r11,$sp
++	addi		r11,r11,32
++	lvx		v22,r10,$sp
++	addi		r10,r10,32
++	lvx		v23,r11,$sp
++	addi		r11,r11,32
++	lvx		v24,r10,$sp
++	addi		r10,r10,32
++	lvx		v25,r11,$sp
++	addi		r11,r11,32
++	lvx		v26,r10,$sp
++	addi		r10,r10,32
++	lvx		v27,r11,$sp
++	addi		r11,r11,32
++	lvx		v28,r10,$sp
++	addi		r10,r10,32
++	lvx		v29,r11,$sp
++	addi		r11,r11,32
++	lvx		v30,r10,$sp
++	lvx		v31,r11,$sp
++	$POP		r26,`$FRAME+21*16+0*$SIZE_T`($sp)
++	$POP		r27,`$FRAME+21*16+1*$SIZE_T`($sp)
++	$POP		r28,`$FRAME+21*16+2*$SIZE_T`($sp)
++	$POP		r29,`$FRAME+21*16+3*$SIZE_T`($sp)
++	$POP		r30,`$FRAME+21*16+4*$SIZE_T`($sp)
++	$POP		r31,`$FRAME+21*16+5*$SIZE_T`($sp)
++	addi		$sp,$sp,`$FRAME+21*16+6*$SIZE_T`
++	blr
++	.long		0
++	.byte		0,12,0x04,1,0x80,6,6,0
++	.long		0
++
++.align	5
++_aesp8_xts_dec5x:
++	vncipher	$out0,$out0,v24
++	vncipher	$out1,$out1,v24
++	vncipher	$out2,$out2,v24
++	vncipher	$out3,$out3,v24
++	vncipher	$out4,$out4,v24
++	lvx		v24,$x20,$key_		# round[3]
++	addi		$key_,$key_,0x20
++
++	vncipher	$out0,$out0,v25
++	vncipher	$out1,$out1,v25
++	vncipher	$out2,$out2,v25
++	vncipher	$out3,$out3,v25
++	vncipher	$out4,$out4,v25
++	lvx		v25,$x10,$key_		# round[4]
++	bdnz		_aesp8_xts_dec5x
++
++	subi		r0,$taillen,1
++	vncipher	$out0,$out0,v24
++	vncipher	$out1,$out1,v24
++	vncipher	$out2,$out2,v24
++	vncipher	$out3,$out3,v24
++	vncipher	$out4,$out4,v24
++
++	andi.		r0,r0,16
++	cmpwi		$taillen,0
++	vncipher	$out0,$out0,v25
++	vncipher	$out1,$out1,v25
++	vncipher	$out2,$out2,v25
++	vncipher	$out3,$out3,v25
++	vncipher	$out4,$out4,v25
++	 vxor		$twk0,$twk0,v31
++
++	sub		$inp,$inp,r0
++	vncipher	$out0,$out0,v26
++	vncipher	$out1,$out1,v26
++	vncipher	$out2,$out2,v26
++	vncipher	$out3,$out3,v26
++	vncipher	$out4,$out4,v26
++	 vxor		$in1,$twk1,v31
++
++	vncipher	$out0,$out0,v27
++	lvx_u		$in0,0,$inp
++	vncipher	$out1,$out1,v27
++	vncipher	$out2,$out2,v27
++	vncipher	$out3,$out3,v27
++	vncipher	$out4,$out4,v27
++	 vxor		$in2,$twk2,v31
++
++	addi		$key_,$sp,$FRAME+15	# rewind $key_
++	vncipher	$out0,$out0,v28
++	vncipher	$out1,$out1,v28
++	vncipher	$out2,$out2,v28
++	vncipher	$out3,$out3,v28
++	vncipher	$out4,$out4,v28
++	lvx		v24,$x00,$key_		# re-pre-load round[1]
++	 vxor		$in3,$twk3,v31
++
++	vncipher	$out0,$out0,v29
++	le?vperm	$in0,$in0,$in0,$leperm
++	vncipher	$out1,$out1,v29
++	vncipher	$out2,$out2,v29
++	vncipher	$out3,$out3,v29
++	vncipher	$out4,$out4,v29
++	lvx		v25,$x10,$key_		# re-pre-load round[2]
++	 vxor		$in4,$twk4,v31
++
++	vncipher	$out0,$out0,v30
++	vncipher	$out1,$out1,v30
++	vncipher	$out2,$out2,v30
++	vncipher	$out3,$out3,v30
++	vncipher	$out4,$out4,v30
++
++	vncipherlast	$out0,$out0,$twk0
++	vncipherlast	$out1,$out1,$in1
++	vncipherlast	$out2,$out2,$in2
++	vncipherlast	$out3,$out3,$in3
++	vncipherlast	$out4,$out4,$in4
++	mtctr		$rounds
++	blr
++        .long   	0
++        .byte   	0,12,0x14,0,0,0,0,0
++___
++}}	}}}
++
++my $consts=1;
++foreach(split("\n",$code)) {
++        s/\`([^\`]*)\`/eval($1)/geo;
++
++	# constants table endian-specific conversion
++	if ($consts && m/\.(long|byte)\s+(.+)\s+(\?[a-z]*)$/o) {
++	    my $conv=$3;
++	    my @bytes=();
++
++	    # convert to endian-agnostic format
++	    if ($1 eq "long") {
++	      foreach (split(/,\s*/,$2)) {
++		my $l = /^0/?oct:int;
++		push @bytes,($l>>24)&0xff,($l>>16)&0xff,($l>>8)&0xff,$l&0xff;
++	      }
++	    } else {
++		@bytes = map(/^0/?oct:int,split(/,\s*/,$2));
++	    }
++
++	    # little-endian conversion
++	    if ($flavour =~ /le$/o) {
++		SWITCH: for($conv)  {
++		    /\?inv/ && do   { @bytes=map($_^0xf,@bytes); last; };
++		    /\?rev/ && do   { @bytes=reverse(@bytes);    last; }; 
++		}
++	    }
++
++	    #emit
++	    print ".byte\t",join(',',map (sprintf("0x%02x",$_),@bytes)),"\n";
++	    next;
++	}
++	$consts=0 if (m/Lconsts:/o);	# end of table
++
++	# instructions prefixed with '?' are endian-specific and need
++	# to be adjusted accordingly...
++	if ($flavour =~ /le$/o) {	# little-endian
++	    s/le\?//o		or
++	    s/be\?/#be#/o	or
++	    s/\?lvsr/lvsl/o	or
++	    s/\?lvsl/lvsr/o	or
++	    s/\?(vperm\s+v[0-9]+,\s*)(v[0-9]+,\s*)(v[0-9]+,\s*)(v[0-9]+)/$1$3$2$4/o or
++	    s/\?(vsldoi\s+v[0-9]+,\s*)(v[0-9]+,)\s*(v[0-9]+,\s*)([0-9]+)/$1$3$2 16-$4/o or
++	    s/\?(vspltw\s+v[0-9]+,\s*)(v[0-9]+,)\s*([0-9])/$1$2 3-$3/o;
++	} else {			# big-endian
++	    s/le\?/#le#/o	or
++	    s/be\?//o		or
++	    s/\?([a-z]+)/$1/o;
++	}
++
++        print $_,"\n";
++}
++
++close STDOUT;
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/aes/asm/aest4-sparcv9.pl b/CryptoPkg/Library/OpensslLib/openssl/crypto/aes/asm/aest4-sparcv9.pl
+new file mode 100644
+index 0000000..bf479c6
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/aes/asm/aest4-sparcv9.pl
+@@ -0,0 +1,929 @@
++#! /usr/bin/env perl
++# Copyright 2012-2016 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
++# in the file LICENSE in the source distribution or at
++# https://www.openssl.org/source/license.html
++
++
++# ====================================================================
++# Written by David S. Miller  and Andy Polyakov
++# . The module is licensed under 2-clause BSD
++# license. October 2012. All rights reserved.
++# ====================================================================
++
++######################################################################
++# AES for SPARC T4.
++#
++# AES round instructions complete in 3 cycles and can be issued every
++# cycle. It means that round calculations should take 4*rounds cycles,
++# because any given round instruction depends on result of *both*
++# previous instructions:
++#
++#	|0 |1 |2 |3 |4
++#	|01|01|01|
++#	   |23|23|23|
++#	            |01|01|...
++#	               |23|...
++#
++# Provided that fxor [with IV] takes 3 cycles to complete, critical
++# path length for CBC encrypt would be 3+4*rounds, or in other words
++# it should process one byte in at least (3+4*rounds)/16 cycles. This
++# estimate doesn't account for "collateral" instructions, such as
++# fetching input from memory, xor-ing it with zero-round key and
++# storing the result. Yet, *measured* performance [for data aligned
++# at 64-bit boundary!] deviates from this equation by less than 0.5%:
++#
++#		128-bit key	192-		256-
++# CBC encrypt	2.70/2.90(*)	3.20/3.40	3.70/3.90
++#			 (*) numbers after slash are for
++#			     misaligned data.
++#
++# Out-of-order execution logic managed to fully overlap "collateral"
++# instructions with those on critical path. Amazing!
++#
++# As with Intel AES-NI, question is if it's possible to improve
++# performance of parallelizeable modes by interleaving round
++# instructions. Provided round instruction latency and throughput
++# optimal interleave factor is 2. But can we expect 2x performance
++# improvement? Well, as round instructions can be issued one per
++# cycle, they don't saturate the 2-way issue pipeline and therefore
++# there is room for "collateral" calculations... Yet, 2x speed-up
++# over CBC encrypt remains unattaintable:
++#
++#		128-bit key	192-		256-
++# CBC decrypt	1.64/2.11	1.89/2.37	2.23/2.61
++# CTR		1.64/2.08(*)	1.89/2.33	2.23/2.61
++#			 (*) numbers after slash are for
++#			     misaligned data.
++#
++# Estimates based on amount of instructions under assumption that
++# round instructions are not pairable with any other instruction
++# suggest that latter is the actual case and pipeline runs
++# underutilized. It should be noted that T4 out-of-order execution
++# logic is so capable that performance gain from 2x interleave is
++# not even impressive, ~7-13% over non-interleaved code, largest
++# for 256-bit keys.
++
++# To anchor to something else, software implementation processes
++# one byte in 29 cycles with 128-bit key on same processor. Intel
++# Sandy Bridge encrypts byte in 5.07 cycles in CBC mode and decrypts
++# in 0.93, naturally with AES-NI.
++
++$0 =~ m/(.*[\/\\])[^\/\\]+$/; $dir=$1;
++push(@INC,"${dir}","${dir}../../perlasm");
++require "sparcv9_modes.pl";
++
++$output = pop;
++open STDOUT,">$output";
++
++$::evp=1;	# if $evp is set to 0, script generates module with
++# AES_[en|de]crypt, AES_set_[en|de]crypt_key and AES_cbc_encrypt entry
++# points. These however are not fully compatible with openssl/aes.h,
++# because they expect AES_KEY to be aligned at 64-bit boundary. When
++# used through EVP, alignment is arranged at EVP layer. Second thing
++# that is arranged by EVP is at least 32-bit alignment of IV.
++
++######################################################################
++# single-round subroutines
++#
++{
++my ($inp,$out,$key,$rounds,$tmp,$mask)=map("%o$_",(0..5));
++
++$code.=<<___;
++#include "sparc_arch.h"
++
++#ifdef	__arch64__
++.register	%g2,#scratch
++.register	%g3,#scratch
++#endif
++
++.text
++
++.globl	aes_t4_encrypt
++.align	32
++aes_t4_encrypt:
++	andcc		$inp, 7, %g1		! is input aligned?
++	andn		$inp, 7, $inp
++
++	ldx		[$key + 0], %g4
++	ldx		[$key + 8], %g5
++
++	ldx		[$inp + 0], %o4
++	bz,pt		%icc, 1f
++	ldx		[$inp + 8], %o5
++	ldx		[$inp + 16], $inp
++	sll		%g1, 3, %g1
++	sub		%g0, %g1, %o3
++	sllx		%o4, %g1, %o4
++	sllx		%o5, %g1, %g1
++	srlx		%o5, %o3, %o5
++	srlx		$inp, %o3, %o3
++	or		%o5, %o4, %o4
++	or		%o3, %g1, %o5
++1:
++	ld		[$key + 240], $rounds
++	ldd		[$key + 16], %f12
++	ldd		[$key + 24], %f14
++	xor		%g4, %o4, %o4
++	xor		%g5, %o5, %o5
++	movxtod		%o4, %f0
++	movxtod		%o5, %f2
++	srl		$rounds, 1, $rounds
++	ldd		[$key + 32], %f16
++	sub		$rounds, 1, $rounds
++	ldd		[$key + 40], %f18
++	add		$key, 48, $key
++
++.Lenc:
++	aes_eround01	%f12, %f0, %f2, %f4
++	aes_eround23	%f14, %f0, %f2, %f2
++	ldd		[$key + 0], %f12
++	ldd		[$key + 8], %f14
++	sub		$rounds,1,$rounds
++	aes_eround01	%f16, %f4, %f2, %f0
++	aes_eround23	%f18, %f4, %f2, %f2
++	ldd		[$key + 16], %f16
++	ldd		[$key + 24], %f18
++	brnz,pt		$rounds, .Lenc
++	add		$key, 32, $key
++
++	andcc		$out, 7, $tmp		! is output aligned?
++	aes_eround01	%f12, %f0, %f2, %f4
++	aes_eround23	%f14, %f0, %f2, %f2
++	aes_eround01_l	%f16, %f4, %f2, %f0
++	aes_eround23_l	%f18, %f4, %f2, %f2
++
++	bnz,pn		%icc, 2f
++	nop
++
++	std		%f0, [$out + 0]
++	retl
++	std		%f2, [$out + 8]
++
++2:	alignaddrl	$out, %g0, $out
++	mov		0xff, $mask
++	srl		$mask, $tmp, $mask
++
++	faligndata	%f0, %f0, %f4
++	faligndata	%f0, %f2, %f6
++	faligndata	%f2, %f2, %f8
++
++	stda		%f4, [$out + $mask]0xc0	! partial store
++	std		%f6, [$out + 8]
++	add		$out, 16, $out
++	orn		%g0, $mask, $mask
++	retl
++	stda		%f8, [$out + $mask]0xc0	! partial store
++.type	aes_t4_encrypt,#function
++.size	aes_t4_encrypt,.-aes_t4_encrypt
++
++.globl	aes_t4_decrypt
++.align	32
++aes_t4_decrypt:
++	andcc		$inp, 7, %g1		! is input aligned?
++	andn		$inp, 7, $inp
++
++	ldx		[$key + 0], %g4
++	ldx		[$key + 8], %g5
++
++	ldx		[$inp + 0], %o4
++	bz,pt		%icc, 1f
++	ldx		[$inp + 8], %o5
++	ldx		[$inp + 16], $inp
++	sll		%g1, 3, %g1
++	sub		%g0, %g1, %o3
++	sllx		%o4, %g1, %o4
++	sllx		%o5, %g1, %g1
++	srlx		%o5, %o3, %o5
++	srlx		$inp, %o3, %o3
++	or		%o5, %o4, %o4
++	or		%o3, %g1, %o5
++1:
++	ld		[$key + 240], $rounds
++	ldd		[$key + 16], %f12
++	ldd		[$key + 24], %f14
++	xor		%g4, %o4, %o4
++	xor		%g5, %o5, %o5
++	movxtod		%o4, %f0
++	movxtod		%o5, %f2
++	srl		$rounds, 1, $rounds
++	ldd		[$key + 32], %f16
++	sub		$rounds, 1, $rounds
++	ldd		[$key + 40], %f18
++	add		$key, 48, $key
++
++.Ldec:
++	aes_dround01	%f12, %f0, %f2, %f4
++	aes_dround23	%f14, %f0, %f2, %f2
++	ldd		[$key + 0], %f12
++	ldd		[$key + 8], %f14
++	sub		$rounds,1,$rounds
++	aes_dround01	%f16, %f4, %f2, %f0
++	aes_dround23	%f18, %f4, %f2, %f2
++	ldd		[$key + 16], %f16
++	ldd		[$key + 24], %f18
++	brnz,pt		$rounds, .Ldec
++	add		$key, 32, $key
++
++	andcc		$out, 7, $tmp		! is output aligned?
++	aes_dround01	%f12, %f0, %f2, %f4
++	aes_dround23	%f14, %f0, %f2, %f2
++	aes_dround01_l	%f16, %f4, %f2, %f0
++	aes_dround23_l	%f18, %f4, %f2, %f2
++
++	bnz,pn		%icc, 2f
++	nop
++
++	std		%f0, [$out + 0]
++	retl
++	std		%f2, [$out + 8]
++
++2:	alignaddrl	$out, %g0, $out
++	mov		0xff, $mask
++	srl		$mask, $tmp, $mask
++
++	faligndata	%f0, %f0, %f4
++	faligndata	%f0, %f2, %f6
++	faligndata	%f2, %f2, %f8
++
++	stda		%f4, [$out + $mask]0xc0	! partial store
++	std		%f6, [$out + 8]
++	add		$out, 16, $out
++	orn		%g0, $mask, $mask
++	retl
++	stda		%f8, [$out + $mask]0xc0	! partial store
++.type	aes_t4_decrypt,#function
++.size	aes_t4_decrypt,.-aes_t4_decrypt
++___
++}
++
++######################################################################
++# key setup subroutines
++#
++{
++my ($inp,$bits,$out,$tmp)=map("%o$_",(0..5));
++$code.=<<___;
++.globl	aes_t4_set_encrypt_key
++.align	32
++aes_t4_set_encrypt_key:
++.Lset_encrypt_key:
++	and		$inp, 7, $tmp
++	alignaddr	$inp, %g0, $inp
++	cmp		$bits, 192
++	ldd		[$inp + 0], %f0
++	bl,pt		%icc,.L128
++	ldd		[$inp + 8], %f2
++
++	be,pt		%icc,.L192
++	ldd		[$inp + 16], %f4
++	brz,pt		$tmp, .L256aligned
++	ldd		[$inp + 24], %f6
++
++	ldd		[$inp + 32], %f8
++	faligndata	%f0, %f2, %f0
++	faligndata	%f2, %f4, %f2
++	faligndata	%f4, %f6, %f4
++	faligndata	%f6, %f8, %f6
++.L256aligned:
++___
++for ($i=0; $i<6; $i++) {
++    $code.=<<___;
++	std		%f0, [$out + `32*$i+0`]
++	aes_kexpand1	%f0, %f6, $i, %f0
++	std		%f2, [$out + `32*$i+8`]
++	aes_kexpand2	%f2, %f0, %f2
++	std		%f4, [$out + `32*$i+16`]
++	aes_kexpand0	%f4, %f2, %f4
++	std		%f6, [$out + `32*$i+24`]
++	aes_kexpand2	%f6, %f4, %f6
++___
++}
++$code.=<<___;
++	std		%f0, [$out + `32*$i+0`]
++	aes_kexpand1	%f0, %f6, $i, %f0
++	std		%f2, [$out + `32*$i+8`]
++	aes_kexpand2	%f2, %f0, %f2
++	std		%f4, [$out + `32*$i+16`]
++	std		%f6, [$out + `32*$i+24`]
++	std		%f0, [$out + `32*$i+32`]
++	std		%f2, [$out + `32*$i+40`]
++
++	mov		14, $tmp
++	st		$tmp, [$out + 240]
++	retl
++	xor		%o0, %o0, %o0
++
++.align	16
++.L192:
++	brz,pt		$tmp, .L192aligned
++	nop
++
++	ldd		[$inp + 24], %f6
++	faligndata	%f0, %f2, %f0
++	faligndata	%f2, %f4, %f2
++	faligndata	%f4, %f6, %f4
++.L192aligned:
++___
++for ($i=0; $i<7; $i++) {
++    $code.=<<___;
++	std		%f0, [$out + `24*$i+0`]
++	aes_kexpand1	%f0, %f4, $i, %f0
++	std		%f2, [$out + `24*$i+8`]
++	aes_kexpand2	%f2, %f0, %f2
++	std		%f4, [$out + `24*$i+16`]
++	aes_kexpand2	%f4, %f2, %f4
++___
++}
++$code.=<<___;
++	std		%f0, [$out + `24*$i+0`]
++	aes_kexpand1	%f0, %f4, $i, %f0
++	std		%f2, [$out + `24*$i+8`]
++	aes_kexpand2	%f2, %f0, %f2
++	std		%f4, [$out + `24*$i+16`]
++	std		%f0, [$out + `24*$i+24`]
++	std		%f2, [$out + `24*$i+32`]
++
++	mov		12, $tmp
++	st		$tmp, [$out + 240]
++	retl
++	xor		%o0, %o0, %o0
++
++.align	16
++.L128:
++	brz,pt		$tmp, .L128aligned
++	nop
++
++	ldd		[$inp + 16], %f4
++	faligndata	%f0, %f2, %f0
++	faligndata	%f2, %f4, %f2
++.L128aligned:
++___
++for ($i=0; $i<10; $i++) {
++    $code.=<<___;
++	std		%f0, [$out + `16*$i+0`]
++	aes_kexpand1	%f0, %f2, $i, %f0
++	std		%f2, [$out + `16*$i+8`]
++	aes_kexpand2	%f2, %f0, %f2
++___
++}
++$code.=<<___;
++	std		%f0, [$out + `16*$i+0`]
++	std		%f2, [$out + `16*$i+8`]
++
++	mov		10, $tmp
++	st		$tmp, [$out + 240]
++	retl
++	xor		%o0, %o0, %o0
++.type	aes_t4_set_encrypt_key,#function
++.size	aes_t4_set_encrypt_key,.-aes_t4_set_encrypt_key
++
++.globl	aes_t4_set_decrypt_key
++.align	32
++aes_t4_set_decrypt_key:
++	mov		%o7, %o5
++	call		.Lset_encrypt_key
++	nop
++
++	mov		%o5, %o7
++	sll		$tmp, 4, $inp		! $tmp is number of rounds
++	add		$tmp, 2, $tmp
++	add		$out, $inp, $inp	! $inp=$out+16*rounds
++	srl		$tmp, 2, $tmp		! $tmp=(rounds+2)/4
++
++.Lkey_flip:
++	ldd		[$out + 0],  %f0
++	ldd		[$out + 8],  %f2
++	ldd		[$out + 16], %f4
++	ldd		[$out + 24], %f6
++	ldd		[$inp + 0],  %f8
++	ldd		[$inp + 8],  %f10
++	ldd		[$inp - 16], %f12
++	ldd		[$inp - 8],  %f14
++	sub		$tmp, 1, $tmp
++	std		%f0, [$inp + 0]
++	std		%f2, [$inp + 8]
++	std		%f4, [$inp - 16]
++	std		%f6, [$inp - 8]
++	std		%f8, [$out + 0]
++	std		%f10, [$out + 8]
++	std		%f12, [$out + 16]
++	std		%f14, [$out + 24]
++	add		$out, 32, $out
++	brnz		$tmp, .Lkey_flip
++	sub		$inp, 32, $inp
++
++	retl
++	xor		%o0, %o0, %o0
++.type	aes_t4_set_decrypt_key,#function
++.size	aes_t4_set_decrypt_key,.-aes_t4_set_decrypt_key
++___
++}
++
++{{{
++my ($inp,$out,$len,$key,$ivec,$enc)=map("%i$_",(0..5));
++my ($ileft,$iright,$ooff,$omask,$ivoff)=map("%l$_",(1..7));
++
++$code.=<<___;
++.align	32
++_aes128_encrypt_1x:
++___
++for ($i=0; $i<4; $i++) {
++    $code.=<<___;
++	aes_eround01	%f`16+8*$i+0`, %f0, %f2, %f4
++	aes_eround23	%f`16+8*$i+2`, %f0, %f2, %f2
++	aes_eround01	%f`16+8*$i+4`, %f4, %f2, %f0
++	aes_eround23	%f`16+8*$i+6`, %f4, %f2, %f2
++___
++}
++$code.=<<___;
++	aes_eround01	%f48, %f0, %f2, %f4
++	aes_eround23	%f50, %f0, %f2, %f2
++	aes_eround01_l	%f52, %f4, %f2, %f0
++	retl
++	aes_eround23_l	%f54, %f4, %f2, %f2
++.type	_aes128_encrypt_1x,#function
++.size	_aes128_encrypt_1x,.-_aes128_encrypt_1x
++
++.align	32
++_aes128_encrypt_2x:
++___
++for ($i=0; $i<4; $i++) {
++    $code.=<<___;
++	aes_eround01	%f`16+8*$i+0`, %f0, %f2, %f8
++	aes_eround23	%f`16+8*$i+2`, %f0, %f2, %f2
++	aes_eround01	%f`16+8*$i+0`, %f4, %f6, %f10
++	aes_eround23	%f`16+8*$i+2`, %f4, %f6, %f6
++	aes_eround01	%f`16+8*$i+4`, %f8, %f2, %f0
++	aes_eround23	%f`16+8*$i+6`, %f8, %f2, %f2
++	aes_eround01	%f`16+8*$i+4`, %f10, %f6, %f4
++	aes_eround23	%f`16+8*$i+6`, %f10, %f6, %f6
++___
++}
++$code.=<<___;
++	aes_eround01	%f48, %f0, %f2, %f8
++	aes_eround23	%f50, %f0, %f2, %f2
++	aes_eround01	%f48, %f4, %f6, %f10
++	aes_eround23	%f50, %f4, %f6, %f6
++	aes_eround01_l	%f52, %f8, %f2, %f0
++	aes_eround23_l	%f54, %f8, %f2, %f2
++	aes_eround01_l	%f52, %f10, %f6, %f4
++	retl
++	aes_eround23_l	%f54, %f10, %f6, %f6
++.type	_aes128_encrypt_2x,#function
++.size	_aes128_encrypt_2x,.-_aes128_encrypt_2x
++
++.align	32
++_aes128_loadkey:
++	ldx		[$key + 0], %g4
++	ldx		[$key + 8], %g5
++___
++for ($i=2; $i<22;$i++) {			# load key schedule
++    $code.=<<___;
++	ldd		[$key + `8*$i`], %f`12+2*$i`
++___
++}
++$code.=<<___;
++	retl
++	nop
++.type	_aes128_loadkey,#function
++.size	_aes128_loadkey,.-_aes128_loadkey
++_aes128_load_enckey=_aes128_loadkey
++_aes128_load_deckey=_aes128_loadkey
++
++___
++
++&alg_cbc_encrypt_implement("aes",128);
++if ($::evp) {
++    &alg_ctr32_implement("aes",128);
++    &alg_xts_implement("aes",128,"en");
++    &alg_xts_implement("aes",128,"de");
++}
++&alg_cbc_decrypt_implement("aes",128);
++
++$code.=<<___;
++.align	32
++_aes128_decrypt_1x:
++___
++for ($i=0; $i<4; $i++) {
++    $code.=<<___;
++	aes_dround01	%f`16+8*$i+0`, %f0, %f2, %f4
++	aes_dround23	%f`16+8*$i+2`, %f0, %f2, %f2
++	aes_dround01	%f`16+8*$i+4`, %f4, %f2, %f0
++	aes_dround23	%f`16+8*$i+6`, %f4, %f2, %f2
++___
++}
++$code.=<<___;
++	aes_dround01	%f48, %f0, %f2, %f4
++	aes_dround23	%f50, %f0, %f2, %f2
++	aes_dround01_l	%f52, %f4, %f2, %f0
++	retl
++	aes_dround23_l	%f54, %f4, %f2, %f2
++.type	_aes128_decrypt_1x,#function
++.size	_aes128_decrypt_1x,.-_aes128_decrypt_1x
++
++.align	32
++_aes128_decrypt_2x:
++___
++for ($i=0; $i<4; $i++) {
++    $code.=<<___;
++	aes_dround01	%f`16+8*$i+0`, %f0, %f2, %f8
++	aes_dround23	%f`16+8*$i+2`, %f0, %f2, %f2
++	aes_dround01	%f`16+8*$i+0`, %f4, %f6, %f10
++	aes_dround23	%f`16+8*$i+2`, %f4, %f6, %f6
++	aes_dround01	%f`16+8*$i+4`, %f8, %f2, %f0
++	aes_dround23	%f`16+8*$i+6`, %f8, %f2, %f2
++	aes_dround01	%f`16+8*$i+4`, %f10, %f6, %f4
++	aes_dround23	%f`16+8*$i+6`, %f10, %f6, %f6
++___
++}
++$code.=<<___;
++	aes_dround01	%f48, %f0, %f2, %f8
++	aes_dround23	%f50, %f0, %f2, %f2
++	aes_dround01	%f48, %f4, %f6, %f10
++	aes_dround23	%f50, %f4, %f6, %f6
++	aes_dround01_l	%f52, %f8, %f2, %f0
++	aes_dround23_l	%f54, %f8, %f2, %f2
++	aes_dround01_l	%f52, %f10, %f6, %f4
++	retl
++	aes_dround23_l	%f54, %f10, %f6, %f6
++.type	_aes128_decrypt_2x,#function
++.size	_aes128_decrypt_2x,.-_aes128_decrypt_2x
++___
++
++$code.=<<___;
++.align	32
++_aes192_encrypt_1x:
++___
++for ($i=0; $i<5; $i++) {
++    $code.=<<___;
++	aes_eround01	%f`16+8*$i+0`, %f0, %f2, %f4
++	aes_eround23	%f`16+8*$i+2`, %f0, %f2, %f2
++	aes_eround01	%f`16+8*$i+4`, %f4, %f2, %f0
++	aes_eround23	%f`16+8*$i+6`, %f4, %f2, %f2
++___
++}
++$code.=<<___;
++	aes_eround01	%f56, %f0, %f2, %f4
++	aes_eround23	%f58, %f0, %f2, %f2
++	aes_eround01_l	%f60, %f4, %f2, %f0
++	retl
++	aes_eround23_l	%f62, %f4, %f2, %f2
++.type	_aes192_encrypt_1x,#function
++.size	_aes192_encrypt_1x,.-_aes192_encrypt_1x
++
++.align	32
++_aes192_encrypt_2x:
++___
++for ($i=0; $i<5; $i++) {
++    $code.=<<___;
++	aes_eround01	%f`16+8*$i+0`, %f0, %f2, %f8
++	aes_eround23	%f`16+8*$i+2`, %f0, %f2, %f2
++	aes_eround01	%f`16+8*$i+0`, %f4, %f6, %f10
++	aes_eround23	%f`16+8*$i+2`, %f4, %f6, %f6
++	aes_eround01	%f`16+8*$i+4`, %f8, %f2, %f0
++	aes_eround23	%f`16+8*$i+6`, %f8, %f2, %f2
++	aes_eround01	%f`16+8*$i+4`, %f10, %f6, %f4
++	aes_eround23	%f`16+8*$i+6`, %f10, %f6, %f6
++___
++}
++$code.=<<___;
++	aes_eround01	%f56, %f0, %f2, %f8
++	aes_eround23	%f58, %f0, %f2, %f2
++	aes_eround01	%f56, %f4, %f6, %f10
++	aes_eround23	%f58, %f4, %f6, %f6
++	aes_eround01_l	%f60, %f8, %f2, %f0
++	aes_eround23_l	%f62, %f8, %f2, %f2
++	aes_eround01_l	%f60, %f10, %f6, %f4
++	retl
++	aes_eround23_l	%f62, %f10, %f6, %f6
++.type	_aes192_encrypt_2x,#function
++.size	_aes192_encrypt_2x,.-_aes192_encrypt_2x
++
++.align	32
++_aes256_encrypt_1x:
++	aes_eround01	%f16, %f0, %f2, %f4
++	aes_eround23	%f18, %f0, %f2, %f2
++	ldd		[$key + 208], %f16
++	ldd		[$key + 216], %f18
++	aes_eround01	%f20, %f4, %f2, %f0
++	aes_eround23	%f22, %f4, %f2, %f2
++	ldd		[$key + 224], %f20
++	ldd		[$key + 232], %f22
++___
++for ($i=1; $i<6; $i++) {
++    $code.=<<___;
++	aes_eround01	%f`16+8*$i+0`, %f0, %f2, %f4
++	aes_eround23	%f`16+8*$i+2`, %f0, %f2, %f2
++	aes_eround01	%f`16+8*$i+4`, %f4, %f2, %f0
++	aes_eround23	%f`16+8*$i+6`, %f4, %f2, %f2
++___
++}
++$code.=<<___;
++	aes_eround01	%f16, %f0, %f2, %f4
++	aes_eround23	%f18, %f0, %f2, %f2
++	ldd		[$key + 16], %f16
++	ldd		[$key + 24], %f18
++	aes_eround01_l	%f20, %f4, %f2, %f0
++	aes_eround23_l	%f22, %f4, %f2, %f2
++	ldd		[$key + 32], %f20
++	retl
++	ldd		[$key + 40], %f22
++.type	_aes256_encrypt_1x,#function
++.size	_aes256_encrypt_1x,.-_aes256_encrypt_1x
++
++.align	32
++_aes256_encrypt_2x:
++	aes_eround01	%f16, %f0, %f2, %f8
++	aes_eround23	%f18, %f0, %f2, %f2
++	aes_eround01	%f16, %f4, %f6, %f10
++	aes_eround23	%f18, %f4, %f6, %f6
++	ldd		[$key + 208], %f16
++	ldd		[$key + 216], %f18
++	aes_eround01	%f20, %f8, %f2, %f0
++	aes_eround23	%f22, %f8, %f2, %f2
++	aes_eround01	%f20, %f10, %f6, %f4
++	aes_eround23	%f22, %f10, %f6, %f6
++	ldd		[$key + 224], %f20
++	ldd		[$key + 232], %f22
++___
++for ($i=1; $i<6; $i++) {
++    $code.=<<___;
++	aes_eround01	%f`16+8*$i+0`, %f0, %f2, %f8
++	aes_eround23	%f`16+8*$i+2`, %f0, %f2, %f2
++	aes_eround01	%f`16+8*$i+0`, %f4, %f6, %f10
++	aes_eround23	%f`16+8*$i+2`, %f4, %f6, %f6
++	aes_eround01	%f`16+8*$i+4`, %f8, %f2, %f0
++	aes_eround23	%f`16+8*$i+6`, %f8, %f2, %f2
++	aes_eround01	%f`16+8*$i+4`, %f10, %f6, %f4
++	aes_eround23	%f`16+8*$i+6`, %f10, %f6, %f6
++___
++}
++$code.=<<___;
++	aes_eround01	%f16, %f0, %f2, %f8
++	aes_eround23	%f18, %f0, %f2, %f2
++	aes_eround01	%f16, %f4, %f6, %f10
++	aes_eround23	%f18, %f4, %f6, %f6
++	ldd		[$key + 16], %f16
++	ldd		[$key + 24], %f18
++	aes_eround01_l	%f20, %f8, %f2, %f0
++	aes_eround23_l	%f22, %f8, %f2, %f2
++	aes_eround01_l	%f20, %f10, %f6, %f4
++	aes_eround23_l	%f22, %f10, %f6, %f6
++	ldd		[$key + 32], %f20
++	retl
++	ldd		[$key + 40], %f22
++.type	_aes256_encrypt_2x,#function
++.size	_aes256_encrypt_2x,.-_aes256_encrypt_2x
++
++.align	32
++_aes192_loadkey:
++	ldx		[$key + 0], %g4
++	ldx		[$key + 8], %g5
++___
++for ($i=2; $i<26;$i++) {			# load key schedule
++    $code.=<<___;
++	ldd		[$key + `8*$i`], %f`12+2*$i`
++___
++}
++$code.=<<___;
++	retl
++	nop
++.type	_aes192_loadkey,#function
++.size	_aes192_loadkey,.-_aes192_loadkey
++_aes256_loadkey=_aes192_loadkey
++_aes192_load_enckey=_aes192_loadkey
++_aes192_load_deckey=_aes192_loadkey
++_aes256_load_enckey=_aes192_loadkey
++_aes256_load_deckey=_aes192_loadkey
++___
++
++&alg_cbc_encrypt_implement("aes",256);
++&alg_cbc_encrypt_implement("aes",192);
++if ($::evp) {
++    &alg_ctr32_implement("aes",256);
++    &alg_xts_implement("aes",256,"en");
++    &alg_xts_implement("aes",256,"de");
++    &alg_ctr32_implement("aes",192);
++}
++&alg_cbc_decrypt_implement("aes",192);
++&alg_cbc_decrypt_implement("aes",256);
++
++$code.=<<___;
++.align	32
++_aes256_decrypt_1x:
++	aes_dround01	%f16, %f0, %f2, %f4
++	aes_dround23	%f18, %f0, %f2, %f2
++	ldd		[$key + 208], %f16
++	ldd		[$key + 216], %f18
++	aes_dround01	%f20, %f4, %f2, %f0
++	aes_dround23	%f22, %f4, %f2, %f2
++	ldd		[$key + 224], %f20
++	ldd		[$key + 232], %f22
++___
++for ($i=1; $i<6; $i++) {
++    $code.=<<___;
++	aes_dround01	%f`16+8*$i+0`, %f0, %f2, %f4
++	aes_dround23	%f`16+8*$i+2`, %f0, %f2, %f2
++	aes_dround01	%f`16+8*$i+4`, %f4, %f2, %f0
++	aes_dround23	%f`16+8*$i+6`, %f4, %f2, %f2
++___
++}
++$code.=<<___;
++	aes_dround01	%f16, %f0, %f2, %f4
++	aes_dround23	%f18, %f0, %f2, %f2
++	ldd		[$key + 16], %f16
++	ldd		[$key + 24], %f18
++	aes_dround01_l	%f20, %f4, %f2, %f0
++	aes_dround23_l	%f22, %f4, %f2, %f2
++	ldd		[$key + 32], %f20
++	retl
++	ldd		[$key + 40], %f22
++.type	_aes256_decrypt_1x,#function
++.size	_aes256_decrypt_1x,.-_aes256_decrypt_1x
++
++.align	32
++_aes256_decrypt_2x:
++	aes_dround01	%f16, %f0, %f2, %f8
++	aes_dround23	%f18, %f0, %f2, %f2
++	aes_dround01	%f16, %f4, %f6, %f10
++	aes_dround23	%f18, %f4, %f6, %f6
++	ldd		[$key + 208], %f16
++	ldd		[$key + 216], %f18
++	aes_dround01	%f20, %f8, %f2, %f0
++	aes_dround23	%f22, %f8, %f2, %f2
++	aes_dround01	%f20, %f10, %f6, %f4
++	aes_dround23	%f22, %f10, %f6, %f6
++	ldd		[$key + 224], %f20
++	ldd		[$key + 232], %f22
++___
++for ($i=1; $i<6; $i++) {
++    $code.=<<___;
++	aes_dround01	%f`16+8*$i+0`, %f0, %f2, %f8
++	aes_dround23	%f`16+8*$i+2`, %f0, %f2, %f2
++	aes_dround01	%f`16+8*$i+0`, %f4, %f6, %f10
++	aes_dround23	%f`16+8*$i+2`, %f4, %f6, %f6
++	aes_dround01	%f`16+8*$i+4`, %f8, %f2, %f0
++	aes_dround23	%f`16+8*$i+6`, %f8, %f2, %f2
++	aes_dround01	%f`16+8*$i+4`, %f10, %f6, %f4
++	aes_dround23	%f`16+8*$i+6`, %f10, %f6, %f6
++___
++}
++$code.=<<___;
++	aes_dround01	%f16, %f0, %f2, %f8
++	aes_dround23	%f18, %f0, %f2, %f2
++	aes_dround01	%f16, %f4, %f6, %f10
++	aes_dround23	%f18, %f4, %f6, %f6
++	ldd		[$key + 16], %f16
++	ldd		[$key + 24], %f18
++	aes_dround01_l	%f20, %f8, %f2, %f0
++	aes_dround23_l	%f22, %f8, %f2, %f2
++	aes_dround01_l	%f20, %f10, %f6, %f4
++	aes_dround23_l	%f22, %f10, %f6, %f6
++	ldd		[$key + 32], %f20
++	retl
++	ldd		[$key + 40], %f22
++.type	_aes256_decrypt_2x,#function
++.size	_aes256_decrypt_2x,.-_aes256_decrypt_2x
++
++.align	32
++_aes192_decrypt_1x:
++___
++for ($i=0; $i<5; $i++) {
++    $code.=<<___;
++	aes_dround01	%f`16+8*$i+0`, %f0, %f2, %f4
++	aes_dround23	%f`16+8*$i+2`, %f0, %f2, %f2
++	aes_dround01	%f`16+8*$i+4`, %f4, %f2, %f0
++	aes_dround23	%f`16+8*$i+6`, %f4, %f2, %f2
++___
++}
++$code.=<<___;
++	aes_dround01	%f56, %f0, %f2, %f4
++	aes_dround23	%f58, %f0, %f2, %f2
++	aes_dround01_l	%f60, %f4, %f2, %f0
++	retl
++	aes_dround23_l	%f62, %f4, %f2, %f2
++.type	_aes192_decrypt_1x,#function
++.size	_aes192_decrypt_1x,.-_aes192_decrypt_1x
++
++.align	32
++_aes192_decrypt_2x:
++___
++for ($i=0; $i<5; $i++) {
++    $code.=<<___;
++	aes_dround01	%f`16+8*$i+0`, %f0, %f2, %f8
++	aes_dround23	%f`16+8*$i+2`, %f0, %f2, %f2
++	aes_dround01	%f`16+8*$i+0`, %f4, %f6, %f10
++	aes_dround23	%f`16+8*$i+2`, %f4, %f6, %f6
++	aes_dround01	%f`16+8*$i+4`, %f8, %f2, %f0
++	aes_dround23	%f`16+8*$i+6`, %f8, %f2, %f2
++	aes_dround01	%f`16+8*$i+4`, %f10, %f6, %f4
++	aes_dround23	%f`16+8*$i+6`, %f10, %f6, %f6
++___
++}
++$code.=<<___;
++	aes_dround01	%f56, %f0, %f2, %f8
++	aes_dround23	%f58, %f0, %f2, %f2
++	aes_dround01	%f56, %f4, %f6, %f10
++	aes_dround23	%f58, %f4, %f6, %f6
++	aes_dround01_l	%f60, %f8, %f2, %f0
++	aes_dround23_l	%f62, %f8, %f2, %f2
++	aes_dround01_l	%f60, %f10, %f6, %f4
++	retl
++	aes_dround23_l	%f62, %f10, %f6, %f6
++.type	_aes192_decrypt_2x,#function
++.size	_aes192_decrypt_2x,.-_aes192_decrypt_2x
++___
++}}}
++
++if (!$::evp) {
++$code.=<<___;
++.global	AES_encrypt
++AES_encrypt=aes_t4_encrypt
++.global	AES_decrypt
++AES_decrypt=aes_t4_decrypt
++.global	AES_set_encrypt_key
++.align	32
++AES_set_encrypt_key:
++	andcc		%o2, 7, %g0		! check alignment
++	bnz,a,pn	%icc, 1f
++	mov		-1, %o0
++	brz,a,pn	%o0, 1f
++	mov		-1, %o0
++	brz,a,pn	%o2, 1f
++	mov		-1, %o0
++	andncc		%o1, 0x1c0, %g0
++	bnz,a,pn	%icc, 1f
++	mov		-2, %o0
++	cmp		%o1, 128
++	bl,a,pn		%icc, 1f
++	mov		-2, %o0
++	b		aes_t4_set_encrypt_key
++	nop
++1:	retl
++	nop
++.type	AES_set_encrypt_key,#function
++.size	AES_set_encrypt_key,.-AES_set_encrypt_key
++
++.global	AES_set_decrypt_key
++.align	32
++AES_set_decrypt_key:
++	andcc		%o2, 7, %g0		! check alignment
++	bnz,a,pn	%icc, 1f
++	mov		-1, %o0
++	brz,a,pn	%o0, 1f
++	mov		-1, %o0
++	brz,a,pn	%o2, 1f
++	mov		-1, %o0
++	andncc		%o1, 0x1c0, %g0
++	bnz,a,pn	%icc, 1f
++	mov		-2, %o0
++	cmp		%o1, 128
++	bl,a,pn		%icc, 1f
++	mov		-2, %o0
++	b		aes_t4_set_decrypt_key
++	nop
++1:	retl
++	nop
++.type	AES_set_decrypt_key,#function
++.size	AES_set_decrypt_key,.-AES_set_decrypt_key
++___
++
++my ($inp,$out,$len,$key,$ivec,$enc)=map("%o$_",(0..5));
++
++$code.=<<___;
++.globl	AES_cbc_encrypt
++.align	32
++AES_cbc_encrypt:
++	ld		[$key + 240], %g1
++	nop
++	brz		$enc, .Lcbc_decrypt
++	cmp		%g1, 12
++
++	bl,pt		%icc, aes128_t4_cbc_encrypt
++	nop
++	be,pn		%icc, aes192_t4_cbc_encrypt
++	nop
++	ba		aes256_t4_cbc_encrypt
++	nop
++
++.Lcbc_decrypt:
++	bl,pt		%icc, aes128_t4_cbc_decrypt
++	nop
++	be,pn		%icc, aes192_t4_cbc_decrypt
++	nop
++	ba		aes256_t4_cbc_decrypt
++	nop
++.type	AES_cbc_encrypt,#function
++.size	AES_cbc_encrypt,.-AES_cbc_encrypt
++___
++}
++$code.=<<___;
++.asciz	"AES for SPARC T4, David S. Miller, Andy Polyakov"
++.align	4
++___
++
++&emit_assembler();
++
++close STDOUT;
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/aes/asm/aesv8-armx.pl b/CryptoPkg/Library/OpensslLib/openssl/crypto/aes/asm/aesv8-armx.pl
+new file mode 100755
+index 0000000..1782d5b
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/aes/asm/aesv8-armx.pl
+@@ -0,0 +1,1008 @@
++#! /usr/bin/env perl
++# Copyright 2014-2016 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
++# in the file LICENSE in the source distribution or at
++# https://www.openssl.org/source/license.html
++
++#
++# ====================================================================
++# Written by Andy Polyakov  for the OpenSSL
++# project. The module is, however, dual licensed under OpenSSL and
++# CRYPTOGAMS licenses depending on where you obtain it. For further
++# details see http://www.openssl.org/~appro/cryptogams/.
++# ====================================================================
++#
++# This module implements support for ARMv8 AES instructions. The
++# module is endian-agnostic in sense that it supports both big- and
++# little-endian cases. As does it support both 32- and 64-bit modes
++# of operation. Latter is achieved by limiting amount of utilized
++# registers to 16, which implies additional NEON load and integer
++# instructions. This has no effect on mighty Apple A7, where results
++# are literally equal to the theoretical estimates based on AES
++# instruction latencies and issue rates. On Cortex-A53, an in-order
++# execution core, this costs up to 10-15%, which is partially
++# compensated by implementing dedicated code path for 128-bit
++# CBC encrypt case. On Cortex-A57 parallelizable mode performance
++# seems to be limited by sheer amount of NEON instructions...
++#
++# Performance in cycles per byte processed with 128-bit key:
++#
++#		CBC enc		CBC dec		CTR
++# Apple A7	2.39		1.20		1.20
++# Cortex-A53	1.32		1.29		1.46
++# Cortex-A57(*)	1.95		0.85		0.93
++# Denver	1.96		0.86		0.80
++# Mongoose	1.33		1.20		1.20
++#
++# (*)	original 3.64/1.34/1.32 results were for r0p0 revision
++#	and are still same even for updated module;
++
++$flavour = shift;
++$output  = shift;
++
++$0 =~ m/(.*[\/\\])[^\/\\]+$/; $dir=$1;
++( $xlate="${dir}arm-xlate.pl" and -f $xlate ) or
++( $xlate="${dir}../../perlasm/arm-xlate.pl" and -f $xlate) or
++die "can't locate arm-xlate.pl";
++
++open OUT,"| \"$^X\" $xlate $flavour $output";
++*STDOUT=*OUT;
++
++$prefix="aes_v8";
++
++$code=<<___;
++#include "arm_arch.h"
++
++#if __ARM_MAX_ARCH__>=7
++.text
++___
++$code.=".arch	armv8-a+crypto\n"			if ($flavour =~ /64/);
++$code.=<<___						if ($flavour !~ /64/);
++.arch	armv7-a	// don't confuse not-so-latest binutils with argv8 :-)
++.fpu	neon
++.code	32
++#undef	__thumb2__
++___
++
++# Assembler mnemonics are an eclectic mix of 32- and 64-bit syntax,
++# NEON is mostly 32-bit mnemonics, integer - mostly 64. Goal is to
++# maintain both 32- and 64-bit codes within single module and
++# transliterate common code to either flavour with regex vodoo.
++#
++{{{
++my ($inp,$bits,$out,$ptr,$rounds)=("x0","w1","x2","x3","w12");
++my ($zero,$rcon,$mask,$in0,$in1,$tmp,$key)=
++	$flavour=~/64/? map("q$_",(0..6)) : map("q$_",(0..3,8..10));
++
++
++$code.=<<___;
++.align	5
++.Lrcon:
++.long	0x01,0x01,0x01,0x01
++.long	0x0c0f0e0d,0x0c0f0e0d,0x0c0f0e0d,0x0c0f0e0d	// rotate-n-splat
++.long	0x1b,0x1b,0x1b,0x1b
++
++.globl	${prefix}_set_encrypt_key
++.type	${prefix}_set_encrypt_key,%function
++.align	5
++${prefix}_set_encrypt_key:
++.Lenc_key:
++___
++$code.=<<___	if ($flavour =~ /64/);
++	stp	x29,x30,[sp,#-16]!
++	add	x29,sp,#0
++___
++$code.=<<___;
++	mov	$ptr,#-1
++	cmp	$inp,#0
++	b.eq	.Lenc_key_abort
++	cmp	$out,#0
++	b.eq	.Lenc_key_abort
++	mov	$ptr,#-2
++	cmp	$bits,#128
++	b.lt	.Lenc_key_abort
++	cmp	$bits,#256
++	b.gt	.Lenc_key_abort
++	tst	$bits,#0x3f
++	b.ne	.Lenc_key_abort
++
++	adr	$ptr,.Lrcon
++	cmp	$bits,#192
++
++	veor	$zero,$zero,$zero
++	vld1.8	{$in0},[$inp],#16
++	mov	$bits,#8		// reuse $bits
++	vld1.32	{$rcon,$mask},[$ptr],#32
++
++	b.lt	.Loop128
++	b.eq	.L192
++	b	.L256
++
++.align	4
++.Loop128:
++	vtbl.8	$key,{$in0},$mask
++	vext.8	$tmp,$zero,$in0,#12
++	vst1.32	{$in0},[$out],#16
++	aese	$key,$zero
++	subs	$bits,$bits,#1
++
++	veor	$in0,$in0,$tmp
++	vext.8	$tmp,$zero,$tmp,#12
++	veor	$in0,$in0,$tmp
++	vext.8	$tmp,$zero,$tmp,#12
++	 veor	$key,$key,$rcon
++	veor	$in0,$in0,$tmp
++	vshl.u8	$rcon,$rcon,#1
++	veor	$in0,$in0,$key
++	b.ne	.Loop128
++
++	vld1.32	{$rcon},[$ptr]
++
++	vtbl.8	$key,{$in0},$mask
++	vext.8	$tmp,$zero,$in0,#12
++	vst1.32	{$in0},[$out],#16
++	aese	$key,$zero
++
++	veor	$in0,$in0,$tmp
++	vext.8	$tmp,$zero,$tmp,#12
++	veor	$in0,$in0,$tmp
++	vext.8	$tmp,$zero,$tmp,#12
++	 veor	$key,$key,$rcon
++	veor	$in0,$in0,$tmp
++	vshl.u8	$rcon,$rcon,#1
++	veor	$in0,$in0,$key
++
++	vtbl.8	$key,{$in0},$mask
++	vext.8	$tmp,$zero,$in0,#12
++	vst1.32	{$in0},[$out],#16
++	aese	$key,$zero
++
++	veor	$in0,$in0,$tmp
++	vext.8	$tmp,$zero,$tmp,#12
++	veor	$in0,$in0,$tmp
++	vext.8	$tmp,$zero,$tmp,#12
++	 veor	$key,$key,$rcon
++	veor	$in0,$in0,$tmp
++	veor	$in0,$in0,$key
++	vst1.32	{$in0},[$out]
++	add	$out,$out,#0x50
++
++	mov	$rounds,#10
++	b	.Ldone
++
++.align	4
++.L192:
++	vld1.8	{$in1},[$inp],#8
++	vmov.i8	$key,#8			// borrow $key
++	vst1.32	{$in0},[$out],#16
++	vsub.i8	$mask,$mask,$key	// adjust the mask
++
++.Loop192:
++	vtbl.8	$key,{$in1},$mask
++	vext.8	$tmp,$zero,$in0,#12
++	vst1.32	{$in1},[$out],#8
++	aese	$key,$zero
++	subs	$bits,$bits,#1
++
++	veor	$in0,$in0,$tmp
++	vext.8	$tmp,$zero,$tmp,#12
++	veor	$in0,$in0,$tmp
++	vext.8	$tmp,$zero,$tmp,#12
++	veor	$in0,$in0,$tmp
++
++	vdup.32	$tmp,${in0}[3]
++	veor	$tmp,$tmp,$in1
++	 veor	$key,$key,$rcon
++	vext.8	$in1,$zero,$in1,#12
++	vshl.u8	$rcon,$rcon,#1
++	veor	$in1,$in1,$tmp
++	veor	$in0,$in0,$key
++	veor	$in1,$in1,$key
++	vst1.32	{$in0},[$out],#16
++	b.ne	.Loop192
++
++	mov	$rounds,#12
++	add	$out,$out,#0x20
++	b	.Ldone
++
++.align	4
++.L256:
++	vld1.8	{$in1},[$inp]
++	mov	$bits,#7
++	mov	$rounds,#14
++	vst1.32	{$in0},[$out],#16
++
++.Loop256:
++	vtbl.8	$key,{$in1},$mask
++	vext.8	$tmp,$zero,$in0,#12
++	vst1.32	{$in1},[$out],#16
++	aese	$key,$zero
++	subs	$bits,$bits,#1
++
++	veor	$in0,$in0,$tmp
++	vext.8	$tmp,$zero,$tmp,#12
++	veor	$in0,$in0,$tmp
++	vext.8	$tmp,$zero,$tmp,#12
++	 veor	$key,$key,$rcon
++	veor	$in0,$in0,$tmp
++	vshl.u8	$rcon,$rcon,#1
++	veor	$in0,$in0,$key
++	vst1.32	{$in0},[$out],#16
++	b.eq	.Ldone
++
++	vdup.32	$key,${in0}[3]		// just splat
++	vext.8	$tmp,$zero,$in1,#12
++	aese	$key,$zero
++
++	veor	$in1,$in1,$tmp
++	vext.8	$tmp,$zero,$tmp,#12
++	veor	$in1,$in1,$tmp
++	vext.8	$tmp,$zero,$tmp,#12
++	veor	$in1,$in1,$tmp
++
++	veor	$in1,$in1,$key
++	b	.Loop256
++
++.Ldone:
++	str	$rounds,[$out]
++	mov	$ptr,#0
++
++.Lenc_key_abort:
++	mov	x0,$ptr			// return value
++	`"ldr	x29,[sp],#16"		if ($flavour =~ /64/)`
++	ret
++.size	${prefix}_set_encrypt_key,.-${prefix}_set_encrypt_key
++
++.globl	${prefix}_set_decrypt_key
++.type	${prefix}_set_decrypt_key,%function
++.align	5
++${prefix}_set_decrypt_key:
++___
++$code.=<<___	if ($flavour =~ /64/);
++	stp	x29,x30,[sp,#-16]!
++	add	x29,sp,#0
++___
++$code.=<<___	if ($flavour !~ /64/);
++	stmdb	sp!,{r4,lr}
++___
++$code.=<<___;
++	bl	.Lenc_key
++
++	cmp	x0,#0
++	b.ne	.Ldec_key_abort
++
++	sub	$out,$out,#240		// restore original $out
++	mov	x4,#-16
++	add	$inp,$out,x12,lsl#4	// end of key schedule
++
++	vld1.32	{v0.16b},[$out]
++	vld1.32	{v1.16b},[$inp]
++	vst1.32	{v0.16b},[$inp],x4
++	vst1.32	{v1.16b},[$out],#16
++
++.Loop_imc:
++	vld1.32	{v0.16b},[$out]
++	vld1.32	{v1.16b},[$inp]
++	aesimc	v0.16b,v0.16b
++	aesimc	v1.16b,v1.16b
++	vst1.32	{v0.16b},[$inp],x4
++	vst1.32	{v1.16b},[$out],#16
++	cmp	$inp,$out
++	b.hi	.Loop_imc
++
++	vld1.32	{v0.16b},[$out]
++	aesimc	v0.16b,v0.16b
++	vst1.32	{v0.16b},[$inp]
++
++	eor	x0,x0,x0		// return value
++.Ldec_key_abort:
++___
++$code.=<<___	if ($flavour !~ /64/);
++	ldmia	sp!,{r4,pc}
++___
++$code.=<<___	if ($flavour =~ /64/);
++	ldp	x29,x30,[sp],#16
++	ret
++___
++$code.=<<___;
++.size	${prefix}_set_decrypt_key,.-${prefix}_set_decrypt_key
++___
++}}}
++{{{
++sub gen_block () {
++my $dir = shift;
++my ($e,$mc) = $dir eq "en" ? ("e","mc") : ("d","imc");
++my ($inp,$out,$key)=map("x$_",(0..2));
++my $rounds="w3";
++my ($rndkey0,$rndkey1,$inout)=map("q$_",(0..3));
++
++$code.=<<___;
++.globl	${prefix}_${dir}crypt
++.type	${prefix}_${dir}crypt,%function
++.align	5
++${prefix}_${dir}crypt:
++	ldr	$rounds,[$key,#240]
++	vld1.32	{$rndkey0},[$key],#16
++	vld1.8	{$inout},[$inp]
++	sub	$rounds,$rounds,#2
++	vld1.32	{$rndkey1},[$key],#16
++
++.Loop_${dir}c:
++	aes$e	$inout,$rndkey0
++	aes$mc	$inout,$inout
++	vld1.32	{$rndkey0},[$key],#16
++	subs	$rounds,$rounds,#2
++	aes$e	$inout,$rndkey1
++	aes$mc	$inout,$inout
++	vld1.32	{$rndkey1},[$key],#16
++	b.gt	.Loop_${dir}c
++
++	aes$e	$inout,$rndkey0
++	aes$mc	$inout,$inout
++	vld1.32	{$rndkey0},[$key]
++	aes$e	$inout,$rndkey1
++	veor	$inout,$inout,$rndkey0
++
++	vst1.8	{$inout},[$out]
++	ret
++.size	${prefix}_${dir}crypt,.-${prefix}_${dir}crypt
++___
++}
++&gen_block("en");
++&gen_block("de");
++}}}
++{{{
++my ($inp,$out,$len,$key,$ivp)=map("x$_",(0..4)); my $enc="w5";
++my ($rounds,$cnt,$key_,$step,$step1)=($enc,"w6","x7","x8","x12");
++my ($dat0,$dat1,$in0,$in1,$tmp0,$tmp1,$ivec,$rndlast)=map("q$_",(0..7));
++
++my ($dat,$tmp,$rndzero_n_last)=($dat0,$tmp0,$tmp1);
++my ($key4,$key5,$key6,$key7)=("x6","x12","x14",$key);
++
++### q8-q15	preloaded key schedule
++
++$code.=<<___;
++.globl	${prefix}_cbc_encrypt
++.type	${prefix}_cbc_encrypt,%function
++.align	5
++${prefix}_cbc_encrypt:
++___
++$code.=<<___	if ($flavour =~ /64/);
++	stp	x29,x30,[sp,#-16]!
++	add	x29,sp,#0
++___
++$code.=<<___	if ($flavour !~ /64/);
++	mov	ip,sp
++	stmdb	sp!,{r4-r8,lr}
++	vstmdb	sp!,{d8-d15}            @ ABI specification says so
++	ldmia	ip,{r4-r5}		@ load remaining args
++___
++$code.=<<___;
++	subs	$len,$len,#16
++	mov	$step,#16
++	b.lo	.Lcbc_abort
++	cclr	$step,eq
++
++	cmp	$enc,#0			// en- or decrypting?
++	ldr	$rounds,[$key,#240]
++	and	$len,$len,#-16
++	vld1.8	{$ivec},[$ivp]
++	vld1.8	{$dat},[$inp],$step
++
++	vld1.32	{q8-q9},[$key]		// load key schedule...
++	sub	$rounds,$rounds,#6
++	add	$key_,$key,x5,lsl#4	// pointer to last 7 round keys
++	sub	$rounds,$rounds,#2
++	vld1.32	{q10-q11},[$key_],#32
++	vld1.32	{q12-q13},[$key_],#32
++	vld1.32	{q14-q15},[$key_],#32
++	vld1.32	{$rndlast},[$key_]
++
++	add	$key_,$key,#32
++	mov	$cnt,$rounds
++	b.eq	.Lcbc_dec
++
++	cmp	$rounds,#2
++	veor	$dat,$dat,$ivec
++	veor	$rndzero_n_last,q8,$rndlast
++	b.eq	.Lcbc_enc128
++
++	vld1.32	{$in0-$in1},[$key_]
++	add	$key_,$key,#16
++	add	$key4,$key,#16*4
++	add	$key5,$key,#16*5
++	aese	$dat,q8
++	aesmc	$dat,$dat
++	add	$key6,$key,#16*6
++	add	$key7,$key,#16*7
++	b	.Lenter_cbc_enc
++
++.align	4
++.Loop_cbc_enc:
++	aese	$dat,q8
++	aesmc	$dat,$dat
++	 vst1.8	{$ivec},[$out],#16
++.Lenter_cbc_enc:
++	aese	$dat,q9
++	aesmc	$dat,$dat
++	aese	$dat,$in0
++	aesmc	$dat,$dat
++	vld1.32	{q8},[$key4]
++	cmp	$rounds,#4
++	aese	$dat,$in1
++	aesmc	$dat,$dat
++	vld1.32	{q9},[$key5]
++	b.eq	.Lcbc_enc192
++
++	aese	$dat,q8
++	aesmc	$dat,$dat
++	vld1.32	{q8},[$key6]
++	aese	$dat,q9
++	aesmc	$dat,$dat
++	vld1.32	{q9},[$key7]
++	nop
++
++.Lcbc_enc192:
++	aese	$dat,q8
++	aesmc	$dat,$dat
++	 subs	$len,$len,#16
++	aese	$dat,q9
++	aesmc	$dat,$dat
++	 cclr	$step,eq
++	aese	$dat,q10
++	aesmc	$dat,$dat
++	aese	$dat,q11
++	aesmc	$dat,$dat
++	 vld1.8	{q8},[$inp],$step
++	aese	$dat,q12
++	aesmc	$dat,$dat
++	 veor	q8,q8,$rndzero_n_last
++	aese	$dat,q13
++	aesmc	$dat,$dat
++	 vld1.32 {q9},[$key_]		// re-pre-load rndkey[1]
++	aese	$dat,q14
++	aesmc	$dat,$dat
++	aese	$dat,q15
++	veor	$ivec,$dat,$rndlast
++	b.hs	.Loop_cbc_enc
++
++	vst1.8	{$ivec},[$out],#16
++	b	.Lcbc_done
++
++.align	5
++.Lcbc_enc128:
++	vld1.32	{$in0-$in1},[$key_]
++	aese	$dat,q8
++	aesmc	$dat,$dat
++	b	.Lenter_cbc_enc128
++.Loop_cbc_enc128:
++	aese	$dat,q8
++	aesmc	$dat,$dat
++	 vst1.8	{$ivec},[$out],#16
++.Lenter_cbc_enc128:
++	aese	$dat,q9
++	aesmc	$dat,$dat
++	 subs	$len,$len,#16
++	aese	$dat,$in0
++	aesmc	$dat,$dat
++	 cclr	$step,eq
++	aese	$dat,$in1
++	aesmc	$dat,$dat
++	aese	$dat,q10
++	aesmc	$dat,$dat
++	aese	$dat,q11
++	aesmc	$dat,$dat
++	 vld1.8	{q8},[$inp],$step
++	aese	$dat,q12
++	aesmc	$dat,$dat
++	aese	$dat,q13
++	aesmc	$dat,$dat
++	aese	$dat,q14
++	aesmc	$dat,$dat
++	 veor	q8,q8,$rndzero_n_last
++	aese	$dat,q15
++	veor	$ivec,$dat,$rndlast
++	b.hs	.Loop_cbc_enc128
++
++	vst1.8	{$ivec},[$out],#16
++	b	.Lcbc_done
++___
++{
++my ($dat2,$in2,$tmp2)=map("q$_",(10,11,9));
++$code.=<<___;
++.align	5
++.Lcbc_dec:
++	vld1.8	{$dat2},[$inp],#16
++	subs	$len,$len,#32		// bias
++	add	$cnt,$rounds,#2
++	vorr	$in1,$dat,$dat
++	vorr	$dat1,$dat,$dat
++	vorr	$in2,$dat2,$dat2
++	b.lo	.Lcbc_dec_tail
++
++	vorr	$dat1,$dat2,$dat2
++	vld1.8	{$dat2},[$inp],#16
++	vorr	$in0,$dat,$dat
++	vorr	$in1,$dat1,$dat1
++	vorr	$in2,$dat2,$dat2
++
++.Loop3x_cbc_dec:
++	aesd	$dat0,q8
++	aesimc	$dat0,$dat0
++	aesd	$dat1,q8
++	aesimc	$dat1,$dat1
++	aesd	$dat2,q8
++	aesimc	$dat2,$dat2
++	vld1.32	{q8},[$key_],#16
++	subs	$cnt,$cnt,#2
++	aesd	$dat0,q9
++	aesimc	$dat0,$dat0
++	aesd	$dat1,q9
++	aesimc	$dat1,$dat1
++	aesd	$dat2,q9
++	aesimc	$dat2,$dat2
++	vld1.32	{q9},[$key_],#16
++	b.gt	.Loop3x_cbc_dec
++
++	aesd	$dat0,q8
++	aesimc	$dat0,$dat0
++	aesd	$dat1,q8
++	aesimc	$dat1,$dat1
++	aesd	$dat2,q8
++	aesimc	$dat2,$dat2
++	 veor	$tmp0,$ivec,$rndlast
++	 subs	$len,$len,#0x30
++	 veor	$tmp1,$in0,$rndlast
++	 mov.lo	x6,$len			// x6, $cnt, is zero at this point
++	aesd	$dat0,q9
++	aesimc	$dat0,$dat0
++	aesd	$dat1,q9
++	aesimc	$dat1,$dat1
++	aesd	$dat2,q9
++	aesimc	$dat2,$dat2
++	 veor	$tmp2,$in1,$rndlast
++	 add	$inp,$inp,x6		// $inp is adjusted in such way that
++					// at exit from the loop $dat1-$dat2
++					// are loaded with last "words"
++	 vorr	$ivec,$in2,$in2
++	 mov	$key_,$key
++	aesd	$dat0,q12
++	aesimc	$dat0,$dat0
++	aesd	$dat1,q12
++	aesimc	$dat1,$dat1
++	aesd	$dat2,q12
++	aesimc	$dat2,$dat2
++	 vld1.8	{$in0},[$inp],#16
++	aesd	$dat0,q13
++	aesimc	$dat0,$dat0
++	aesd	$dat1,q13
++	aesimc	$dat1,$dat1
++	aesd	$dat2,q13
++	aesimc	$dat2,$dat2
++	 vld1.8	{$in1},[$inp],#16
++	aesd	$dat0,q14
++	aesimc	$dat0,$dat0
++	aesd	$dat1,q14
++	aesimc	$dat1,$dat1
++	aesd	$dat2,q14
++	aesimc	$dat2,$dat2
++	 vld1.8	{$in2},[$inp],#16
++	aesd	$dat0,q15
++	aesd	$dat1,q15
++	aesd	$dat2,q15
++	 vld1.32 {q8},[$key_],#16	// re-pre-load rndkey[0]
++	 add	$cnt,$rounds,#2
++	veor	$tmp0,$tmp0,$dat0
++	veor	$tmp1,$tmp1,$dat1
++	veor	$dat2,$dat2,$tmp2
++	 vld1.32 {q9},[$key_],#16	// re-pre-load rndkey[1]
++	vst1.8	{$tmp0},[$out],#16
++	 vorr	$dat0,$in0,$in0
++	vst1.8	{$tmp1},[$out],#16
++	 vorr	$dat1,$in1,$in1
++	vst1.8	{$dat2},[$out],#16
++	 vorr	$dat2,$in2,$in2
++	b.hs	.Loop3x_cbc_dec
++
++	cmn	$len,#0x30
++	b.eq	.Lcbc_done
++	nop
++
++.Lcbc_dec_tail:
++	aesd	$dat1,q8
++	aesimc	$dat1,$dat1
++	aesd	$dat2,q8
++	aesimc	$dat2,$dat2
++	vld1.32	{q8},[$key_],#16
++	subs	$cnt,$cnt,#2
++	aesd	$dat1,q9
++	aesimc	$dat1,$dat1
++	aesd	$dat2,q9
++	aesimc	$dat2,$dat2
++	vld1.32	{q9},[$key_],#16
++	b.gt	.Lcbc_dec_tail
++
++	aesd	$dat1,q8
++	aesimc	$dat1,$dat1
++	aesd	$dat2,q8
++	aesimc	$dat2,$dat2
++	aesd	$dat1,q9
++	aesimc	$dat1,$dat1
++	aesd	$dat2,q9
++	aesimc	$dat2,$dat2
++	aesd	$dat1,q12
++	aesimc	$dat1,$dat1
++	aesd	$dat2,q12
++	aesimc	$dat2,$dat2
++	 cmn	$len,#0x20
++	aesd	$dat1,q13
++	aesimc	$dat1,$dat1
++	aesd	$dat2,q13
++	aesimc	$dat2,$dat2
++	 veor	$tmp1,$ivec,$rndlast
++	aesd	$dat1,q14
++	aesimc	$dat1,$dat1
++	aesd	$dat2,q14
++	aesimc	$dat2,$dat2
++	 veor	$tmp2,$in1,$rndlast
++	aesd	$dat1,q15
++	aesd	$dat2,q15
++	b.eq	.Lcbc_dec_one
++	veor	$tmp1,$tmp1,$dat1
++	veor	$tmp2,$tmp2,$dat2
++	 vorr	$ivec,$in2,$in2
++	vst1.8	{$tmp1},[$out],#16
++	vst1.8	{$tmp2},[$out],#16
++	b	.Lcbc_done
++
++.Lcbc_dec_one:
++	veor	$tmp1,$tmp1,$dat2
++	 vorr	$ivec,$in2,$in2
++	vst1.8	{$tmp1},[$out],#16
++
++.Lcbc_done:
++	vst1.8	{$ivec},[$ivp]
++.Lcbc_abort:
++___
++}
++$code.=<<___	if ($flavour !~ /64/);
++	vldmia	sp!,{d8-d15}
++	ldmia	sp!,{r4-r8,pc}
++___
++$code.=<<___	if ($flavour =~ /64/);
++	ldr	x29,[sp],#16
++	ret
++___
++$code.=<<___;
++.size	${prefix}_cbc_encrypt,.-${prefix}_cbc_encrypt
++___
++}}}
++{{{
++my ($inp,$out,$len,$key,$ivp)=map("x$_",(0..4));
++my ($rounds,$cnt,$key_)=("w5","w6","x7");
++my ($ctr,$tctr0,$tctr1,$tctr2)=map("w$_",(8..10,12));
++my $step="x12";		# aliases with $tctr2
++
++my ($dat0,$dat1,$in0,$in1,$tmp0,$tmp1,$ivec,$rndlast)=map("q$_",(0..7));
++my ($dat2,$in2,$tmp2)=map("q$_",(10,11,9));
++
++my ($dat,$tmp)=($dat0,$tmp0);
++
++### q8-q15	preloaded key schedule
++
++$code.=<<___;
++.globl	${prefix}_ctr32_encrypt_blocks
++.type	${prefix}_ctr32_encrypt_blocks,%function
++.align	5
++${prefix}_ctr32_encrypt_blocks:
++___
++$code.=<<___	if ($flavour =~ /64/);
++	stp		x29,x30,[sp,#-16]!
++	add		x29,sp,#0
++___
++$code.=<<___	if ($flavour !~ /64/);
++	mov		ip,sp
++	stmdb		sp!,{r4-r10,lr}
++	vstmdb		sp!,{d8-d15}            @ ABI specification says so
++	ldr		r4, [ip]		@ load remaining arg
++___
++$code.=<<___;
++	ldr		$rounds,[$key,#240]
++
++	ldr		$ctr, [$ivp, #12]
++	vld1.32		{$dat0},[$ivp]
++
++	vld1.32		{q8-q9},[$key]		// load key schedule...
++	sub		$rounds,$rounds,#4
++	mov		$step,#16
++	cmp		$len,#2
++	add		$key_,$key,x5,lsl#4	// pointer to last 5 round keys
++	sub		$rounds,$rounds,#2
++	vld1.32		{q12-q13},[$key_],#32
++	vld1.32		{q14-q15},[$key_],#32
++	vld1.32		{$rndlast},[$key_]
++	add		$key_,$key,#32
++	mov		$cnt,$rounds
++	cclr		$step,lo
++#ifndef __ARMEB__
++	rev		$ctr, $ctr
++#endif
++	vorr		$dat1,$dat0,$dat0
++	add		$tctr1, $ctr, #1
++	vorr		$dat2,$dat0,$dat0
++	add		$ctr, $ctr, #2
++	vorr		$ivec,$dat0,$dat0
++	rev		$tctr1, $tctr1
++	vmov.32		${dat1}[3],$tctr1
++	b.ls		.Lctr32_tail
++	rev		$tctr2, $ctr
++	sub		$len,$len,#3		// bias
++	vmov.32		${dat2}[3],$tctr2
++	b		.Loop3x_ctr32
++
++.align	4
++.Loop3x_ctr32:
++	aese		$dat0,q8
++	aesmc		$dat0,$dat0
++	aese		$dat1,q8
++	aesmc		$dat1,$dat1
++	aese		$dat2,q8
++	aesmc		$dat2,$dat2
++	vld1.32		{q8},[$key_],#16
++	subs		$cnt,$cnt,#2
++	aese		$dat0,q9
++	aesmc		$dat0,$dat0
++	aese		$dat1,q9
++	aesmc		$dat1,$dat1
++	aese		$dat2,q9
++	aesmc		$dat2,$dat2
++	vld1.32		{q9},[$key_],#16
++	b.gt		.Loop3x_ctr32
++
++	aese		$dat0,q8
++	aesmc		$tmp0,$dat0
++	aese		$dat1,q8
++	aesmc		$tmp1,$dat1
++	 vld1.8		{$in0},[$inp],#16
++	 vorr		$dat0,$ivec,$ivec
++	aese		$dat2,q8
++	aesmc		$dat2,$dat2
++	 vld1.8		{$in1},[$inp],#16
++	 vorr		$dat1,$ivec,$ivec
++	aese		$tmp0,q9
++	aesmc		$tmp0,$tmp0
++	aese		$tmp1,q9
++	aesmc		$tmp1,$tmp1
++	 vld1.8		{$in2},[$inp],#16
++	 mov		$key_,$key
++	aese		$dat2,q9
++	aesmc		$tmp2,$dat2
++	 vorr		$dat2,$ivec,$ivec
++	 add		$tctr0,$ctr,#1
++	aese		$tmp0,q12
++	aesmc		$tmp0,$tmp0
++	aese		$tmp1,q12
++	aesmc		$tmp1,$tmp1
++	 veor		$in0,$in0,$rndlast
++	 add		$tctr1,$ctr,#2
++	aese		$tmp2,q12
++	aesmc		$tmp2,$tmp2
++	 veor		$in1,$in1,$rndlast
++	 add		$ctr,$ctr,#3
++	aese		$tmp0,q13
++	aesmc		$tmp0,$tmp0
++	aese		$tmp1,q13
++	aesmc		$tmp1,$tmp1
++	 veor		$in2,$in2,$rndlast
++	 rev		$tctr0,$tctr0
++	aese		$tmp2,q13
++	aesmc		$tmp2,$tmp2
++	 vmov.32	${dat0}[3], $tctr0
++	 rev		$tctr1,$tctr1
++	aese		$tmp0,q14
++	aesmc		$tmp0,$tmp0
++	aese		$tmp1,q14
++	aesmc		$tmp1,$tmp1
++	 vmov.32	${dat1}[3], $tctr1
++	 rev		$tctr2,$ctr
++	aese		$tmp2,q14
++	aesmc		$tmp2,$tmp2
++	 vmov.32	${dat2}[3], $tctr2
++	 subs		$len,$len,#3
++	aese		$tmp0,q15
++	aese		$tmp1,q15
++	aese		$tmp2,q15
++
++	veor		$in0,$in0,$tmp0
++	 vld1.32	 {q8},[$key_],#16	// re-pre-load rndkey[0]
++	vst1.8		{$in0},[$out],#16
++	veor		$in1,$in1,$tmp1
++	 mov		$cnt,$rounds
++	vst1.8		{$in1},[$out],#16
++	veor		$in2,$in2,$tmp2
++	 vld1.32	 {q9},[$key_],#16	// re-pre-load rndkey[1]
++	vst1.8		{$in2},[$out],#16
++	b.hs		.Loop3x_ctr32
++
++	adds		$len,$len,#3
++	b.eq		.Lctr32_done
++	cmp		$len,#1
++	mov		$step,#16
++	cclr		$step,eq
++
++.Lctr32_tail:
++	aese		$dat0,q8
++	aesmc		$dat0,$dat0
++	aese		$dat1,q8
++	aesmc		$dat1,$dat1
++	vld1.32		{q8},[$key_],#16
++	subs		$cnt,$cnt,#2
++	aese		$dat0,q9
++	aesmc		$dat0,$dat0
++	aese		$dat1,q9
++	aesmc		$dat1,$dat1
++	vld1.32		{q9},[$key_],#16
++	b.gt		.Lctr32_tail
++
++	aese		$dat0,q8
++	aesmc		$dat0,$dat0
++	aese		$dat1,q8
++	aesmc		$dat1,$dat1
++	aese		$dat0,q9
++	aesmc		$dat0,$dat0
++	aese		$dat1,q9
++	aesmc		$dat1,$dat1
++	 vld1.8		{$in0},[$inp],$step
++	aese		$dat0,q12
++	aesmc		$dat0,$dat0
++	aese		$dat1,q12
++	aesmc		$dat1,$dat1
++	 vld1.8		{$in1},[$inp]
++	aese		$dat0,q13
++	aesmc		$dat0,$dat0
++	aese		$dat1,q13
++	aesmc		$dat1,$dat1
++	 veor		$in0,$in0,$rndlast
++	aese		$dat0,q14
++	aesmc		$dat0,$dat0
++	aese		$dat1,q14
++	aesmc		$dat1,$dat1
++	 veor		$in1,$in1,$rndlast
++	aese		$dat0,q15
++	aese		$dat1,q15
++
++	cmp		$len,#1
++	veor		$in0,$in0,$dat0
++	veor		$in1,$in1,$dat1
++	vst1.8		{$in0},[$out],#16
++	b.eq		.Lctr32_done
++	vst1.8		{$in1},[$out]
++
++.Lctr32_done:
++___
++$code.=<<___	if ($flavour !~ /64/);
++	vldmia		sp!,{d8-d15}
++	ldmia		sp!,{r4-r10,pc}
++___
++$code.=<<___	if ($flavour =~ /64/);
++	ldr		x29,[sp],#16
++	ret
++___
++$code.=<<___;
++.size	${prefix}_ctr32_encrypt_blocks,.-${prefix}_ctr32_encrypt_blocks
++___
++}}}
++$code.=<<___;
++#endif
++___
++########################################
++if ($flavour =~ /64/) {			######## 64-bit code
++    my %opcode = (
++	"aesd"	=>	0x4e285800,	"aese"	=>	0x4e284800,
++	"aesimc"=>	0x4e287800,	"aesmc"	=>	0x4e286800	);
++
++    local *unaes = sub {
++	my ($mnemonic,$arg)=@_;
++
++	$arg =~ m/[qv]([0-9]+)[^,]*,\s*[qv]([0-9]+)/o	&&
++	sprintf ".inst\t0x%08x\t//%s %s",
++			$opcode{$mnemonic}|$1|($2<<5),
++			$mnemonic,$arg;
++    };
++
++    foreach(split("\n",$code)) {
++	s/\`([^\`]*)\`/eval($1)/geo;
++
++	s/\bq([0-9]+)\b/"v".($1<8?$1:$1+8).".16b"/geo;	# old->new registers
++	s/@\s/\/\//o;			# old->new style commentary
++
++	#s/[v]?(aes\w+)\s+([qv].*)/unaes($1,$2)/geo	or
++	s/cclr\s+([wx])([^,]+),\s*([a-z]+)/csel	$1$2,$1zr,$1$2,$3/o	or
++	s/mov\.([a-z]+)\s+([wx][0-9]+),\s*([wx][0-9]+)/csel	$2,$3,$2,$1/o	or
++	s/vmov\.i8/movi/o	or	# fix up legacy mnemonics
++	s/vext\.8/ext/o		or
++	s/vrev32\.8/rev32/o	or
++	s/vtst\.8/cmtst/o	or
++	s/vshr/ushr/o		or
++	s/^(\s+)v/$1/o		or	# strip off v prefix
++	s/\bbx\s+lr\b/ret/o;
++
++	# fix up remainig legacy suffixes
++	s/\.[ui]?8//o;
++	m/\],#8/o and s/\.16b/\.8b/go;
++	s/\.[ui]?32//o and s/\.16b/\.4s/go;
++	s/\.[ui]?64//o and s/\.16b/\.2d/go;
++	s/\.[42]([sd])\[([0-3])\]/\.$1\[$2\]/o;
++
++	print $_,"\n";
++    }
++} else {				######## 32-bit code
++    my %opcode = (
++	"aesd"	=>	0xf3b00340,	"aese"	=>	0xf3b00300,
++	"aesimc"=>	0xf3b003c0,	"aesmc"	=>	0xf3b00380	);
++
++    local *unaes = sub {
++	my ($mnemonic,$arg)=@_;
++
++	if ($arg =~ m/[qv]([0-9]+)[^,]*,\s*[qv]([0-9]+)/o) {
++	    my $word = $opcode{$mnemonic}|(($1&7)<<13)|(($1&8)<<19)
++					 |(($2&7)<<1) |(($2&8)<<2);
++	    # since ARMv7 instructions are always encoded little-endian.
++	    # correct solution is to use .inst directive, but older
++	    # assemblers don't implement it:-(
++	    sprintf ".byte\t0x%02x,0x%02x,0x%02x,0x%02x\t@ %s %s",
++			$word&0xff,($word>>8)&0xff,
++			($word>>16)&0xff,($word>>24)&0xff,
++			$mnemonic,$arg;
++	}
++    };
++
++    sub unvtbl {
++	my $arg=shift;
++
++	$arg =~ m/q([0-9]+),\s*\{q([0-9]+)\},\s*q([0-9]+)/o &&
++	sprintf	"vtbl.8	d%d,{q%d},d%d\n\t".
++		"vtbl.8	d%d,{q%d},d%d", 2*$1,$2,2*$3, 2*$1+1,$2,2*$3+1;	
++    }
++
++    sub unvdup32 {
++	my $arg=shift;
++
++	$arg =~ m/q([0-9]+),\s*q([0-9]+)\[([0-3])\]/o &&
++	sprintf	"vdup.32	q%d,d%d[%d]",$1,2*$2+($3>>1),$3&1;	
++    }
++
++    sub unvmov32 {
++	my $arg=shift;
++
++	$arg =~ m/q([0-9]+)\[([0-3])\],(.*)/o &&
++	sprintf	"vmov.32	d%d[%d],%s",2*$1+($2>>1),$2&1,$3;	
++    }
++
++    foreach(split("\n",$code)) {
++	s/\`([^\`]*)\`/eval($1)/geo;
++
++	s/\b[wx]([0-9]+)\b/r$1/go;		# new->old registers
++	s/\bv([0-9])\.[12468]+[bsd]\b/q$1/go;	# new->old registers
++	s/\/\/\s?/@ /o;				# new->old style commentary
++
++	# fix up remainig new-style suffixes
++	s/\{q([0-9]+)\},\s*\[(.+)\],#8/sprintf "{d%d},[$2]!",2*$1/eo	or
++	s/\],#[0-9]+/]!/o;
++
++	s/[v]?(aes\w+)\s+([qv].*)/unaes($1,$2)/geo	or
++	s/cclr\s+([^,]+),\s*([a-z]+)/mov$2	$1,#0/o	or
++	s/vtbl\.8\s+(.*)/unvtbl($1)/geo			or
++	s/vdup\.32\s+(.*)/unvdup32($1)/geo		or
++	s/vmov\.32\s+(.*)/unvmov32($1)/geo		or
++	s/^(\s+)b\./$1b/o				or
++	s/^(\s+)mov\./$1mov/o				or
++	s/^(\s+)ret/$1bx\tlr/o;
++
++	print $_,"\n";
++    }
++}
++
++close STDOUT;
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/aes/asm/bsaes-armv7.pl b/CryptoPkg/Library/OpensslLib/openssl/crypto/aes/asm/bsaes-armv7.pl
+new file mode 100644
+index 0000000..12091ef
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/aes/asm/bsaes-armv7.pl
+@@ -0,0 +1,2495 @@
++#! /usr/bin/env perl
++# Copyright 2012-2016 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
++# in the file LICENSE in the source distribution or at
++# https://www.openssl.org/source/license.html
++
++
++# ====================================================================
++# Written by Andy Polyakov  for the OpenSSL
++# project. The module is, however, dual licensed under OpenSSL and
++# CRYPTOGAMS licenses depending on where you obtain it. For further
++# details see http://www.openssl.org/~appro/cryptogams/.
++#
++# Specific modes and adaptation for Linux kernel by Ard Biesheuvel
++# . Permission to use under GPL terms is
++# granted.
++# ====================================================================
++
++# Bit-sliced AES for ARM NEON
++#
++# February 2012.
++#
++# This implementation is direct adaptation of bsaes-x86_64 module for
++# ARM NEON. Except that this module is endian-neutral [in sense that
++# it can be compiled for either endianness] by courtesy of vld1.8's
++# neutrality. Initial version doesn't implement interface to OpenSSL,
++# only low-level primitives and unsupported entry points, just enough
++# to collect performance results, which for Cortex-A8 core are:
++#
++# encrypt	19.5 cycles per byte processed with 128-bit key
++# decrypt	22.1 cycles per byte processed with 128-bit key
++# key conv.	440  cycles per 128-bit key/0.18 of 8x block
++#
++# Snapdragon S4 encrypts byte in 17.6 cycles and decrypts in 19.7,
++# which is [much] worse than anticipated (for further details see
++# http://www.openssl.org/~appro/Snapdragon-S4.html).
++#
++# Cortex-A15 manages in 14.2/16.1 cycles [when integer-only code
++# manages in 20.0 cycles].
++#
++# When comparing to x86_64 results keep in mind that NEON unit is
++# [mostly] single-issue and thus can't [fully] benefit from
++# instruction-level parallelism. And when comparing to aes-armv4
++# results keep in mind key schedule conversion overhead (see
++# bsaes-x86_64.pl for further details)...
++#
++#						
++
++# April-August 2013
++#
++# Add CBC, CTR and XTS subroutines, adapt for kernel use.
++#
++#					
++
++$flavour = shift;
++if ($flavour=~/\w[\w\-]*\.\w+$/) { $output=$flavour; undef $flavour; }
++else { while (($output=shift) && ($output!~/\w[\w\-]*\.\w+$/)) {} }
++
++if ($flavour && $flavour ne "void") {
++    $0 =~ m/(.*[\/\\])[^\/\\]+$/; $dir=$1;
++    ( $xlate="${dir}arm-xlate.pl" and -f $xlate ) or
++    ( $xlate="${dir}../../perlasm/arm-xlate.pl" and -f $xlate) or
++    die "can't locate arm-xlate.pl";
++
++    open STDOUT,"| \"$^X\" $xlate $flavour $output";
++} else {
++    open STDOUT,">$output";
++}
++
++my ($inp,$out,$len,$key)=("r0","r1","r2","r3");
++my @XMM=map("q$_",(0..15));
++
++{
++my ($key,$rounds,$const)=("r4","r5","r6");
++
++sub Dlo()   { shift=~m|q([1]?[0-9])|?"d".($1*2):"";     }
++sub Dhi()   { shift=~m|q([1]?[0-9])|?"d".($1*2+1):"";   }
++
++sub Sbox {
++# input in  lsb > [b0, b1, b2, b3, b4, b5, b6, b7] < msb
++# output in lsb > [b0, b1, b4, b6, b3, b7, b2, b5] < msb
++my @b=@_[0..7];
++my @t=@_[8..11];
++my @s=@_[12..15];
++	&InBasisChange	(@b);
++	&Inv_GF256	(@b[6,5,0,3,7,1,4,2],@t,@s);
++	&OutBasisChange	(@b[7,1,4,2,6,5,0,3]);
++}
++
++sub InBasisChange {
++# input in  lsb > [b0, b1, b2, b3, b4, b5, b6, b7] < msb
++# output in lsb > [b6, b5, b0, b3, b7, b1, b4, b2] < msb 
++my @b=@_[0..7];
++$code.=<<___;
++	veor	@b[2], @b[2], @b[1]
++	veor	@b[5], @b[5], @b[6]
++	veor	@b[3], @b[3], @b[0]
++	veor	@b[6], @b[6], @b[2]
++	veor	@b[5], @b[5], @b[0]
++
++	veor	@b[6], @b[6], @b[3]
++	veor	@b[3], @b[3], @b[7]
++	veor	@b[7], @b[7], @b[5]
++	veor	@b[3], @b[3], @b[4]
++	veor	@b[4], @b[4], @b[5]
++
++	veor	@b[2], @b[2], @b[7]
++	veor	@b[3], @b[3], @b[1]
++	veor	@b[1], @b[1], @b[5]
++___
++}
++
++sub OutBasisChange {
++# input in  lsb > [b0, b1, b2, b3, b4, b5, b6, b7] < msb
++# output in lsb > [b6, b1, b2, b4, b7, b0, b3, b5] < msb
++my @b=@_[0..7];
++$code.=<<___;
++	veor	@b[0], @b[0], @b[6]
++	veor	@b[1], @b[1], @b[4]
++	veor	@b[4], @b[4], @b[6]
++	veor	@b[2], @b[2], @b[0]
++	veor	@b[6], @b[6], @b[1]
++
++	veor	@b[1], @b[1], @b[5]
++	veor	@b[5], @b[5], @b[3]
++	veor	@b[3], @b[3], @b[7]
++	veor	@b[7], @b[7], @b[5]
++	veor	@b[2], @b[2], @b[5]
++
++	veor	@b[4], @b[4], @b[7]
++___
++}
++
++sub InvSbox {
++# input in lsb 	> [b0, b1, b2, b3, b4, b5, b6, b7] < msb
++# output in lsb	> [b0, b1, b6, b4, b2, b7, b3, b5] < msb
++my @b=@_[0..7];
++my @t=@_[8..11];
++my @s=@_[12..15];
++	&InvInBasisChange	(@b);
++	&Inv_GF256		(@b[5,1,2,6,3,7,0,4],@t,@s);
++	&InvOutBasisChange	(@b[3,7,0,4,5,1,2,6]);
++}
++
++sub InvInBasisChange {		# OutBasisChange in reverse (with twist)
++my @b=@_[5,1,2,6,3,7,0,4];
++$code.=<<___
++	 veor	@b[1], @b[1], @b[7]
++	veor	@b[4], @b[4], @b[7]
++
++	veor	@b[7], @b[7], @b[5]
++	 veor	@b[1], @b[1], @b[3]
++	veor	@b[2], @b[2], @b[5]
++	veor	@b[3], @b[3], @b[7]
++
++	veor	@b[6], @b[6], @b[1]
++	veor	@b[2], @b[2], @b[0]
++	 veor	@b[5], @b[5], @b[3]
++	veor	@b[4], @b[4], @b[6]
++	veor	@b[0], @b[0], @b[6]
++	veor	@b[1], @b[1], @b[4]
++___
++}
++
++sub InvOutBasisChange {		# InBasisChange in reverse
++my @b=@_[2,5,7,3,6,1,0,4];
++$code.=<<___;
++	veor	@b[1], @b[1], @b[5]
++	veor	@b[2], @b[2], @b[7]
++
++	veor	@b[3], @b[3], @b[1]
++	veor	@b[4], @b[4], @b[5]
++	veor	@b[7], @b[7], @b[5]
++	veor	@b[3], @b[3], @b[4]
++	 veor 	@b[5], @b[5], @b[0]
++	veor	@b[3], @b[3], @b[7]
++	 veor	@b[6], @b[6], @b[2]
++	 veor	@b[2], @b[2], @b[1]
++	veor	@b[6], @b[6], @b[3]
++
++	veor	@b[3], @b[3], @b[0]
++	veor	@b[5], @b[5], @b[6]
++___
++}
++
++sub Mul_GF4 {
++#;*************************************************************
++#;* Mul_GF4: Input x0-x1,y0-y1 Output x0-x1 Temp t0 (8) *
++#;*************************************************************
++my ($x0,$x1,$y0,$y1,$t0,$t1)=@_;
++$code.=<<___;
++	veor 	$t0, $y0, $y1
++	vand	$t0, $t0, $x0
++	veor	$x0, $x0, $x1
++	vand	$t1, $x1, $y0
++	vand	$x0, $x0, $y1
++	veor	$x1, $t1, $t0
++	veor	$x0, $x0, $t1
++___
++}
++
++sub Mul_GF4_N {				# not used, see next subroutine
++# multiply and scale by N
++my ($x0,$x1,$y0,$y1,$t0)=@_;
++$code.=<<___;
++	veor	$t0, $y0, $y1
++	vand	$t0, $t0, $x0
++	veor	$x0, $x0, $x1
++	vand	$x1, $x1, $y0
++	vand	$x0, $x0, $y1
++	veor	$x1, $x1, $x0
++	veor	$x0, $x0, $t0
++___
++}
++
++sub Mul_GF4_N_GF4 {
++# interleaved Mul_GF4_N and Mul_GF4
++my ($x0,$x1,$y0,$y1,$t0,
++    $x2,$x3,$y2,$y3,$t1)=@_;
++$code.=<<___;
++	veor	$t0, $y0, $y1
++	 veor 	$t1, $y2, $y3
++	vand	$t0, $t0, $x0
++	 vand	$t1, $t1, $x2
++	veor	$x0, $x0, $x1
++	 veor	$x2, $x2, $x3
++	vand	$x1, $x1, $y0
++	 vand	$x3, $x3, $y2
++	vand	$x0, $x0, $y1
++	 vand	$x2, $x2, $y3
++	veor	$x1, $x1, $x0
++	 veor	$x2, $x2, $x3
++	veor	$x0, $x0, $t0
++	 veor	$x3, $x3, $t1
++___
++}
++sub Mul_GF16_2 {
++my @x=@_[0..7];
++my @y=@_[8..11];
++my @t=@_[12..15];
++$code.=<<___;
++	veor	@t[0], @x[0], @x[2]
++	veor	@t[1], @x[1], @x[3]
++___
++	&Mul_GF4  	(@x[0], @x[1], @y[0], @y[1], @t[2..3]);
++$code.=<<___;
++	veor	@y[0], @y[0], @y[2]
++	veor	@y[1], @y[1], @y[3]
++___
++	Mul_GF4_N_GF4	(@t[0], @t[1], @y[0], @y[1], @t[3],
++			 @x[2], @x[3], @y[2], @y[3], @t[2]);
++$code.=<<___;
++	veor	@x[0], @x[0], @t[0]
++	veor	@x[2], @x[2], @t[0]
++	veor	@x[1], @x[1], @t[1]
++	veor	@x[3], @x[3], @t[1]
++
++	veor	@t[0], @x[4], @x[6]
++	veor	@t[1], @x[5], @x[7]
++___
++	&Mul_GF4_N_GF4	(@t[0], @t[1], @y[0], @y[1], @t[3],
++			 @x[6], @x[7], @y[2], @y[3], @t[2]);
++$code.=<<___;
++	veor	@y[0], @y[0], @y[2]
++	veor	@y[1], @y[1], @y[3]
++___
++	&Mul_GF4  	(@x[4], @x[5], @y[0], @y[1], @t[2..3]);
++$code.=<<___;
++	veor	@x[4], @x[4], @t[0]
++	veor	@x[6], @x[6], @t[0]
++	veor	@x[5], @x[5], @t[1]
++	veor	@x[7], @x[7], @t[1]
++___
++}
++sub Inv_GF256 {
++#;********************************************************************
++#;* Inv_GF256: Input x0-x7 Output x0-x7 Temp t0-t3,s0-s3 (144)       *
++#;********************************************************************
++my @x=@_[0..7];
++my @t=@_[8..11];
++my @s=@_[12..15];
++# direct optimizations from hardware
++$code.=<<___;
++	veor	@t[3], @x[4], @x[6]
++	veor	@t[2], @x[5], @x[7]
++	veor	@t[1], @x[1], @x[3]
++	veor	@s[1], @x[7], @x[6]
++	 vmov	@t[0], @t[2]
++	veor	@s[0], @x[0], @x[2]
++
++	vorr	@t[2], @t[2], @t[1]
++	veor	@s[3], @t[3], @t[0]
++	vand	@s[2], @t[3], @s[0]
++	vorr	@t[3], @t[3], @s[0]
++	veor	@s[0], @s[0], @t[1]
++	vand	@t[0], @t[0], @t[1]
++	veor	@t[1], @x[3], @x[2]
++	vand	@s[3], @s[3], @s[0]
++	vand	@s[1], @s[1], @t[1]
++	veor	@t[1], @x[4], @x[5]
++	veor	@s[0], @x[1], @x[0]
++	veor	@t[3], @t[3], @s[1]
++	veor	@t[2], @t[2], @s[1]
++	vand	@s[1], @t[1], @s[0]
++	vorr	@t[1], @t[1], @s[0]
++	veor	@t[3], @t[3], @s[3]
++	veor	@t[0], @t[0], @s[1]
++	veor	@t[2], @t[2], @s[2]
++	veor	@t[1], @t[1], @s[3]
++	veor	@t[0], @t[0], @s[2]
++	vand	@s[0], @x[7], @x[3]
++	veor	@t[1], @t[1], @s[2]
++	vand	@s[1], @x[6], @x[2]
++	vand	@s[2], @x[5], @x[1]
++	vorr	@s[3], @x[4], @x[0]
++	veor	@t[3], @t[3], @s[0]
++	veor	@t[1], @t[1], @s[2]
++	veor	@t[0], @t[0], @s[3]
++	veor	@t[2], @t[2], @s[1]
++
++	@ Inv_GF16 \t0, \t1, \t2, \t3, \s0, \s1, \s2, \s3
++
++	@ new smaller inversion
++
++	vand	@s[2], @t[3], @t[1]
++	vmov	@s[0], @t[0]
++
++	veor	@s[1], @t[2], @s[2]
++	veor	@s[3], @t[0], @s[2]
++	veor	@s[2], @t[0], @s[2]	@ @s[2]=@s[3]
++
++	vbsl	@s[1], @t[1], @t[0]
++	vbsl	@s[3], @t[3], @t[2]
++	veor	@t[3], @t[3], @t[2]
++
++	vbsl	@s[0], @s[1], @s[2]
++	vbsl	@t[0], @s[2], @s[1]
++
++	vand	@s[2], @s[0], @s[3]
++	veor	@t[1], @t[1], @t[0]
++
++	veor	@s[2], @s[2], @t[3]
++___
++# output in s3, s2, s1, t1
++
++# Mul_GF16_2 \x0, \x1, \x2, \x3, \x4, \x5, \x6, \x7, \t2, \t3, \t0, \t1, \s0, \s1, \s2, \s3
++
++# Mul_GF16_2 \x0, \x1, \x2, \x3, \x4, \x5, \x6, \x7, \s3, \s2, \s1, \t1, \s0, \t0, \t2, \t3
++	&Mul_GF16_2(@x,@s[3,2,1],@t[1],@s[0],@t[0,2,3]);
++
++### output msb > [x3,x2,x1,x0,x7,x6,x5,x4] < lsb
++}
++
++# AES linear components
++
++sub ShiftRows {
++my @x=@_[0..7];
++my @t=@_[8..11];
++my $mask=pop;
++$code.=<<___;
++	vldmia	$key!, {@t[0]-@t[3]}
++	veor	@t[0], @t[0], @x[0]
++	veor	@t[1], @t[1], @x[1]
++	vtbl.8	`&Dlo(@x[0])`, {@t[0]}, `&Dlo($mask)`
++	vtbl.8	`&Dhi(@x[0])`, {@t[0]}, `&Dhi($mask)`
++	vldmia	$key!, {@t[0]}
++	veor	@t[2], @t[2], @x[2]
++	vtbl.8	`&Dlo(@x[1])`, {@t[1]}, `&Dlo($mask)`
++	vtbl.8	`&Dhi(@x[1])`, {@t[1]}, `&Dhi($mask)`
++	vldmia	$key!, {@t[1]}
++	veor	@t[3], @t[3], @x[3]
++	vtbl.8	`&Dlo(@x[2])`, {@t[2]}, `&Dlo($mask)`
++	vtbl.8	`&Dhi(@x[2])`, {@t[2]}, `&Dhi($mask)`
++	vldmia	$key!, {@t[2]}
++	vtbl.8	`&Dlo(@x[3])`, {@t[3]}, `&Dlo($mask)`
++	vtbl.8	`&Dhi(@x[3])`, {@t[3]}, `&Dhi($mask)`
++	vldmia	$key!, {@t[3]}
++	veor	@t[0], @t[0], @x[4]
++	veor	@t[1], @t[1], @x[5]
++	vtbl.8	`&Dlo(@x[4])`, {@t[0]}, `&Dlo($mask)`
++	vtbl.8	`&Dhi(@x[4])`, {@t[0]}, `&Dhi($mask)`
++	veor	@t[2], @t[2], @x[6]
++	vtbl.8	`&Dlo(@x[5])`, {@t[1]}, `&Dlo($mask)`
++	vtbl.8	`&Dhi(@x[5])`, {@t[1]}, `&Dhi($mask)`
++	veor	@t[3], @t[3], @x[7]
++	vtbl.8	`&Dlo(@x[6])`, {@t[2]}, `&Dlo($mask)`
++	vtbl.8	`&Dhi(@x[6])`, {@t[2]}, `&Dhi($mask)`
++	vtbl.8	`&Dlo(@x[7])`, {@t[3]}, `&Dlo($mask)`
++	vtbl.8	`&Dhi(@x[7])`, {@t[3]}, `&Dhi($mask)`
++___
++}
++
++sub MixColumns {
++# modified to emit output in order suitable for feeding back to aesenc[last]
++my @x=@_[0..7];
++my @t=@_[8..15];
++my $inv=@_[16];	# optional
++$code.=<<___;
++	vext.8	@t[0], @x[0], @x[0], #12	@ x0 <<< 32
++	vext.8	@t[1], @x[1], @x[1], #12
++	 veor	@x[0], @x[0], @t[0]		@ x0 ^ (x0 <<< 32)
++	vext.8	@t[2], @x[2], @x[2], #12
++	 veor	@x[1], @x[1], @t[1]
++	vext.8	@t[3], @x[3], @x[3], #12
++	 veor	@x[2], @x[2], @t[2]
++	vext.8	@t[4], @x[4], @x[4], #12
++	 veor	@x[3], @x[3], @t[3]
++	vext.8	@t[5], @x[5], @x[5], #12
++	 veor	@x[4], @x[4], @t[4]
++	vext.8	@t[6], @x[6], @x[6], #12
++	 veor	@x[5], @x[5], @t[5]
++	vext.8	@t[7], @x[7], @x[7], #12
++	 veor	@x[6], @x[6], @t[6]
++
++	veor	@t[1], @t[1], @x[0]
++	 veor	@x[7], @x[7], @t[7]
++	 vext.8	@x[0], @x[0], @x[0], #8		@ (x0 ^ (x0 <<< 32)) <<< 64)
++	veor	@t[2], @t[2], @x[1]
++	veor	@t[0], @t[0], @x[7]
++	veor	@t[1], @t[1], @x[7]
++	 vext.8	@x[1], @x[1], @x[1], #8
++	veor	@t[5], @t[5], @x[4]
++	 veor	@x[0], @x[0], @t[0]
++	veor	@t[6], @t[6], @x[5]
++	 veor	@x[1], @x[1], @t[1]
++	 vext.8	@t[0], @x[4], @x[4], #8
++	veor	@t[4], @t[4], @x[3]
++	 vext.8	@t[1], @x[5], @x[5], #8
++	veor	@t[7], @t[7], @x[6]
++	 vext.8	@x[4], @x[3], @x[3], #8
++	veor	@t[3], @t[3], @x[2]
++	 vext.8	@x[5], @x[7], @x[7], #8
++	veor	@t[4], @t[4], @x[7]
++	 vext.8	@x[3], @x[6], @x[6], #8
++	veor	@t[3], @t[3], @x[7]
++	 vext.8	@x[6], @x[2], @x[2], #8
++	veor	@x[7], @t[1], @t[5]
++___
++$code.=<<___ if (!$inv);
++	veor	@x[2], @t[0], @t[4]
++	veor	@x[4], @x[4], @t[3]
++	veor	@x[5], @x[5], @t[7]
++	veor	@x[3], @x[3], @t[6]
++	 @ vmov	@x[2], @t[0]
++	veor	@x[6], @x[6], @t[2]
++	 @ vmov	@x[7], @t[1]
++___
++$code.=<<___ if ($inv);
++	veor	@t[3], @t[3], @x[4]
++	veor	@x[5], @x[5], @t[7]
++	veor	@x[2], @x[3], @t[6]
++	veor	@x[3], @t[0], @t[4]
++	veor	@x[4], @x[6], @t[2]
++	vmov	@x[6], @t[3]
++	 @ vmov	@x[7], @t[1]
++___
++}
++
++sub InvMixColumns_orig {
++my @x=@_[0..7];
++my @t=@_[8..15];
++
++$code.=<<___;
++	@ multiplication by 0x0e
++	vext.8	@t[7], @x[7], @x[7], #12
++	vmov	@t[2], @x[2]
++	veor	@x[2], @x[2], @x[5]		@ 2 5
++	veor	@x[7], @x[7], @x[5]		@ 7 5
++	vext.8	@t[0], @x[0], @x[0], #12
++	vmov	@t[5], @x[5]
++	veor	@x[5], @x[5], @x[0]		@ 5 0		[1]
++	veor	@x[0], @x[0], @x[1]		@ 0 1
++	vext.8	@t[1], @x[1], @x[1], #12
++	veor	@x[1], @x[1], @x[2]		@ 1 25
++	veor	@x[0], @x[0], @x[6]		@ 01 6		[2]
++	vext.8	@t[3], @x[3], @x[3], #12
++	veor	@x[1], @x[1], @x[3]		@ 125 3		[4]
++	veor	@x[2], @x[2], @x[0]		@ 25 016	[3]
++	veor	@x[3], @x[3], @x[7]		@ 3 75
++	veor	@x[7], @x[7], @x[6]		@ 75 6		[0]
++	vext.8	@t[6], @x[6], @x[6], #12
++	vmov	@t[4], @x[4]
++	veor	@x[6], @x[6], @x[4]		@ 6 4
++	veor	@x[4], @x[4], @x[3]		@ 4 375		[6]
++	veor	@x[3], @x[3], @x[7]		@ 375 756=36
++	veor	@x[6], @x[6], @t[5]		@ 64 5		[7]
++	veor	@x[3], @x[3], @t[2]		@ 36 2
++	vext.8	@t[5], @t[5], @t[5], #12
++	veor	@x[3], @x[3], @t[4]		@ 362 4		[5]
++___
++					my @y = @x[7,5,0,2,1,3,4,6];
++$code.=<<___;
++	@ multiplication by 0x0b
++	veor	@y[1], @y[1], @y[0]
++	veor	@y[0], @y[0], @t[0]
++	vext.8	@t[2], @t[2], @t[2], #12
++	veor	@y[1], @y[1], @t[1]
++	veor	@y[0], @y[0], @t[5]
++	vext.8	@t[4], @t[4], @t[4], #12
++	veor	@y[1], @y[1], @t[6]
++	veor	@y[0], @y[0], @t[7]
++	veor	@t[7], @t[7], @t[6]		@ clobber t[7]
++
++	veor	@y[3], @y[3], @t[0]
++	 veor	@y[1], @y[1], @y[0]
++	vext.8	@t[0], @t[0], @t[0], #12
++	veor	@y[2], @y[2], @t[1]
++	veor	@y[4], @y[4], @t[1]
++	vext.8	@t[1], @t[1], @t[1], #12
++	veor	@y[2], @y[2], @t[2]
++	veor	@y[3], @y[3], @t[2]
++	veor	@y[5], @y[5], @t[2]
++	veor	@y[2], @y[2], @t[7]
++	vext.8	@t[2], @t[2], @t[2], #12
++	veor	@y[3], @y[3], @t[3]
++	veor	@y[6], @y[6], @t[3]
++	veor	@y[4], @y[4], @t[3]
++	veor	@y[7], @y[7], @t[4]
++	vext.8	@t[3], @t[3], @t[3], #12
++	veor	@y[5], @y[5], @t[4]
++	veor	@y[7], @y[7], @t[7]
++	veor	@t[7], @t[7], @t[5]		@ clobber t[7] even more
++	veor	@y[3], @y[3], @t[5]
++	veor	@y[4], @y[4], @t[4]
++
++	veor	@y[5], @y[5], @t[7]
++	vext.8	@t[4], @t[4], @t[4], #12
++	veor	@y[6], @y[6], @t[7]
++	veor	@y[4], @y[4], @t[7]
++
++	veor	@t[7], @t[7], @t[5]
++	vext.8	@t[5], @t[5], @t[5], #12
++
++	@ multiplication by 0x0d
++	veor	@y[4], @y[4], @y[7]
++	 veor	@t[7], @t[7], @t[6]		@ restore t[7]
++	veor	@y[7], @y[7], @t[4]
++	vext.8	@t[6], @t[6], @t[6], #12
++	veor	@y[2], @y[2], @t[0]
++	veor	@y[7], @y[7], @t[5]
++	vext.8	@t[7], @t[7], @t[7], #12
++	veor	@y[2], @y[2], @t[2]
++
++	veor	@y[3], @y[3], @y[1]
++	veor	@y[1], @y[1], @t[1]
++	veor	@y[0], @y[0], @t[0]
++	veor	@y[3], @y[3], @t[0]
++	veor	@y[1], @y[1], @t[5]
++	veor	@y[0], @y[0], @t[5]
++	vext.8	@t[0], @t[0], @t[0], #12
++	veor	@y[1], @y[1], @t[7]
++	veor	@y[0], @y[0], @t[6]
++	veor	@y[3], @y[3], @y[1]
++	veor	@y[4], @y[4], @t[1]
++	vext.8	@t[1], @t[1], @t[1], #12
++
++	veor	@y[7], @y[7], @t[7]
++	veor	@y[4], @y[4], @t[2]
++	veor	@y[5], @y[5], @t[2]
++	veor	@y[2], @y[2], @t[6]
++	veor	@t[6], @t[6], @t[3]		@ clobber t[6]
++	vext.8	@t[2], @t[2], @t[2], #12
++	veor	@y[4], @y[4], @y[7]
++	veor	@y[3], @y[3], @t[6]
++
++	veor	@y[6], @y[6], @t[6]
++	veor	@y[5], @y[5], @t[5]
++	vext.8	@t[5], @t[5], @t[5], #12
++	veor	@y[6], @y[6], @t[4]
++	vext.8	@t[4], @t[4], @t[4], #12
++	veor	@y[5], @y[5], @t[6]
++	veor	@y[6], @y[6], @t[7]
++	vext.8	@t[7], @t[7], @t[7], #12
++	veor	@t[6], @t[6], @t[3]		@ restore t[6]
++	vext.8	@t[3], @t[3], @t[3], #12
++
++	@ multiplication by 0x09
++	veor	@y[4], @y[4], @y[1]
++	veor	@t[1], @t[1], @y[1]		@ t[1]=y[1]
++	veor	@t[0], @t[0], @t[5]		@ clobber t[0]
++	vext.8	@t[6], @t[6], @t[6], #12
++	veor	@t[1], @t[1], @t[5]
++	veor	@y[3], @y[3], @t[0]
++	veor	@t[0], @t[0], @y[0]		@ t[0]=y[0]
++	veor	@t[1], @t[1], @t[6]
++	veor	@t[6], @t[6], @t[7]		@ clobber t[6]
++	veor	@y[4], @y[4], @t[1]
++	veor	@y[7], @y[7], @t[4]
++	veor	@y[6], @y[6], @t[3]
++	veor	@y[5], @y[5], @t[2]
++	veor	@t[4], @t[4], @y[4]		@ t[4]=y[4]
++	veor	@t[3], @t[3], @y[3]		@ t[3]=y[3]
++	veor	@t[5], @t[5], @y[5]		@ t[5]=y[5]
++	veor	@t[2], @t[2], @y[2]		@ t[2]=y[2]
++	veor	@t[3], @t[3], @t[7]
++	veor	@XMM[5], @t[5], @t[6]
++	veor	@XMM[6], @t[6], @y[6]		@ t[6]=y[6]
++	veor	@XMM[2], @t[2], @t[6]
++	veor	@XMM[7], @t[7], @y[7]		@ t[7]=y[7]
++
++	vmov	@XMM[0], @t[0]
++	vmov	@XMM[1], @t[1]
++	@ vmov	@XMM[2], @t[2]
++	vmov	@XMM[3], @t[3]
++	vmov	@XMM[4], @t[4]
++	@ vmov	@XMM[5], @t[5]
++	@ vmov	@XMM[6], @t[6]
++	@ vmov	@XMM[7], @t[7]
++___
++}
++
++sub InvMixColumns {
++my @x=@_[0..7];
++my @t=@_[8..15];
++
++# Thanks to Jussi Kivilinna for providing pointer to
++#
++# | 0e 0b 0d 09 |   | 02 03 01 01 |   | 05 00 04 00 |
++# | 09 0e 0b 0d | = | 01 02 03 01 | x | 00 05 00 04 |
++# | 0d 09 0e 0b |   | 01 01 02 03 |   | 04 00 05 00 |
++# | 0b 0d 09 0e |   | 03 01 01 02 |   | 00 04 00 05 |
++
++$code.=<<___;
++	@ multiplication by 0x05-0x00-0x04-0x00
++	vext.8	@t[0], @x[0], @x[0], #8
++	vext.8	@t[6], @x[6], @x[6], #8
++	vext.8	@t[7], @x[7], @x[7], #8
++	veor	@t[0], @t[0], @x[0]
++	vext.8	@t[1], @x[1], @x[1], #8
++	veor	@t[6], @t[6], @x[6]
++	vext.8	@t[2], @x[2], @x[2], #8
++	veor	@t[7], @t[7], @x[7]
++	vext.8	@t[3], @x[3], @x[3], #8
++	veor	@t[1], @t[1], @x[1]
++	vext.8	@t[4], @x[4], @x[4], #8
++	veor	@t[2], @t[2], @x[2]
++	vext.8	@t[5], @x[5], @x[5], #8
++	veor	@t[3], @t[3], @x[3]
++	veor	@t[4], @t[4], @x[4]
++	veor	@t[5], @t[5], @x[5]
++
++	 veor	@x[0], @x[0], @t[6]
++	 veor	@x[1], @x[1], @t[6]
++	 veor	@x[2], @x[2], @t[0]
++	 veor	@x[4], @x[4], @t[2]
++	 veor	@x[3], @x[3], @t[1]
++	 veor	@x[1], @x[1], @t[7]
++	 veor	@x[2], @x[2], @t[7]
++	 veor	@x[4], @x[4], @t[6]
++	 veor	@x[5], @x[5], @t[3]
++	 veor	@x[3], @x[3], @t[6]
++	 veor	@x[6], @x[6], @t[4]
++	 veor	@x[4], @x[4], @t[7]
++	 veor	@x[5], @x[5], @t[7]
++	 veor	@x[7], @x[7], @t[5]
++___
++	&MixColumns	(@x,@t,1);	# flipped 2<->3 and 4<->6
++}
++
++sub swapmove {
++my ($a,$b,$n,$mask,$t)=@_;
++$code.=<<___;
++	vshr.u64	$t, $b, #$n
++	veor		$t, $t, $a
++	vand		$t, $t, $mask
++	veor		$a, $a, $t
++	vshl.u64	$t, $t, #$n
++	veor		$b, $b, $t
++___
++}
++sub swapmove2x {
++my ($a0,$b0,$a1,$b1,$n,$mask,$t0,$t1)=@_;
++$code.=<<___;
++	vshr.u64	$t0, $b0, #$n
++	 vshr.u64	$t1, $b1, #$n
++	veor		$t0, $t0, $a0
++	 veor		$t1, $t1, $a1
++	vand		$t0, $t0, $mask
++	 vand		$t1, $t1, $mask
++	veor		$a0, $a0, $t0
++	vshl.u64	$t0, $t0, #$n
++	 veor		$a1, $a1, $t1
++	 vshl.u64	$t1, $t1, #$n
++	veor		$b0, $b0, $t0
++	 veor		$b1, $b1, $t1
++___
++}
++
++sub bitslice {
++my @x=reverse(@_[0..7]);
++my ($t0,$t1,$t2,$t3)=@_[8..11];
++$code.=<<___;
++	vmov.i8	$t0,#0x55			@ compose .LBS0
++	vmov.i8	$t1,#0x33			@ compose .LBS1
++___
++	&swapmove2x(@x[0,1,2,3],1,$t0,$t2,$t3);
++	&swapmove2x(@x[4,5,6,7],1,$t0,$t2,$t3);
++$code.=<<___;
++	vmov.i8	$t0,#0x0f			@ compose .LBS2
++___
++	&swapmove2x(@x[0,2,1,3],2,$t1,$t2,$t3);
++	&swapmove2x(@x[4,6,5,7],2,$t1,$t2,$t3);
++
++	&swapmove2x(@x[0,4,1,5],4,$t0,$t2,$t3);
++	&swapmove2x(@x[2,6,3,7],4,$t0,$t2,$t3);
++}
++
++$code.=<<___;
++#ifndef __KERNEL__
++# include "arm_arch.h"
++
++# define VFP_ABI_PUSH	vstmdb	sp!,{d8-d15}
++# define VFP_ABI_POP	vldmia	sp!,{d8-d15}
++# define VFP_ABI_FRAME	0x40
++#else
++# define VFP_ABI_PUSH
++# define VFP_ABI_POP
++# define VFP_ABI_FRAME	0
++# define BSAES_ASM_EXTENDED_KEY
++# define XTS_CHAIN_TWEAK
++# define __ARM_ARCH__ __LINUX_ARM_ARCH__
++# define __ARM_MAX_ARCH__ 7
++#endif
++
++#ifdef __thumb__
++# define adrl adr
++#endif
++
++#if __ARM_MAX_ARCH__>=7
++.arch	armv7-a
++.fpu	neon
++
++.text
++.syntax	unified 	@ ARMv7-capable assembler is expected to handle this
++#if defined(__thumb2__) && !defined(__APPLE__)
++.thumb
++#else
++.code   32
++# undef __thumb2__
++#endif
++
++.type	_bsaes_decrypt8,%function
++.align	4
++_bsaes_decrypt8:
++	adr	$const,_bsaes_decrypt8
++	vldmia	$key!, {@XMM[9]}		@ round 0 key
++#ifdef	__APPLE__
++	adr	$const,.LM0ISR
++#else
++	add	$const,$const,#.LM0ISR-_bsaes_decrypt8
++#endif
++
++	vldmia	$const!, {@XMM[8]}		@ .LM0ISR
++	veor	@XMM[10], @XMM[0], @XMM[9]	@ xor with round0 key
++	veor	@XMM[11], @XMM[1], @XMM[9]
++	 vtbl.8	`&Dlo(@XMM[0])`, {@XMM[10]}, `&Dlo(@XMM[8])`
++	 vtbl.8	`&Dhi(@XMM[0])`, {@XMM[10]}, `&Dhi(@XMM[8])`
++	veor	@XMM[12], @XMM[2], @XMM[9]
++	 vtbl.8	`&Dlo(@XMM[1])`, {@XMM[11]}, `&Dlo(@XMM[8])`
++	 vtbl.8	`&Dhi(@XMM[1])`, {@XMM[11]}, `&Dhi(@XMM[8])`
++	veor	@XMM[13], @XMM[3], @XMM[9]
++	 vtbl.8	`&Dlo(@XMM[2])`, {@XMM[12]}, `&Dlo(@XMM[8])`
++	 vtbl.8	`&Dhi(@XMM[2])`, {@XMM[12]}, `&Dhi(@XMM[8])`
++	veor	@XMM[14], @XMM[4], @XMM[9]
++	 vtbl.8	`&Dlo(@XMM[3])`, {@XMM[13]}, `&Dlo(@XMM[8])`
++	 vtbl.8	`&Dhi(@XMM[3])`, {@XMM[13]}, `&Dhi(@XMM[8])`
++	veor	@XMM[15], @XMM[5], @XMM[9]
++	 vtbl.8	`&Dlo(@XMM[4])`, {@XMM[14]}, `&Dlo(@XMM[8])`
++	 vtbl.8	`&Dhi(@XMM[4])`, {@XMM[14]}, `&Dhi(@XMM[8])`
++	veor	@XMM[10], @XMM[6], @XMM[9]
++	 vtbl.8	`&Dlo(@XMM[5])`, {@XMM[15]}, `&Dlo(@XMM[8])`
++	 vtbl.8	`&Dhi(@XMM[5])`, {@XMM[15]}, `&Dhi(@XMM[8])`
++	veor	@XMM[11], @XMM[7], @XMM[9]
++	 vtbl.8	`&Dlo(@XMM[6])`, {@XMM[10]}, `&Dlo(@XMM[8])`
++	 vtbl.8	`&Dhi(@XMM[6])`, {@XMM[10]}, `&Dhi(@XMM[8])`
++	 vtbl.8	`&Dlo(@XMM[7])`, {@XMM[11]}, `&Dlo(@XMM[8])`
++	 vtbl.8	`&Dhi(@XMM[7])`, {@XMM[11]}, `&Dhi(@XMM[8])`
++___
++	&bitslice	(@XMM[0..7, 8..11]);
++$code.=<<___;
++	sub	$rounds,$rounds,#1
++	b	.Ldec_sbox
++.align	4
++.Ldec_loop:
++___
++	&ShiftRows	(@XMM[0..7, 8..12]);
++$code.=".Ldec_sbox:\n";
++	&InvSbox	(@XMM[0..7, 8..15]);
++$code.=<<___;
++	subs	$rounds,$rounds,#1
++	bcc	.Ldec_done
++___
++	&InvMixColumns	(@XMM[0,1,6,4,2,7,3,5, 8..15]);
++$code.=<<___;
++	vldmia	$const, {@XMM[12]}		@ .LISR
++	ite	eq				@ Thumb2 thing, sanity check in ARM
++	addeq	$const,$const,#0x10
++	bne	.Ldec_loop
++	vldmia	$const, {@XMM[12]}		@ .LISRM0
++	b	.Ldec_loop
++.align	4
++.Ldec_done:
++___
++	&bitslice	(@XMM[0,1,6,4,2,7,3,5, 8..11]);
++$code.=<<___;
++	vldmia	$key, {@XMM[8]}			@ last round key
++	veor	@XMM[6], @XMM[6], @XMM[8]
++	veor	@XMM[4], @XMM[4], @XMM[8]
++	veor	@XMM[2], @XMM[2], @XMM[8]
++	veor	@XMM[7], @XMM[7], @XMM[8]
++	veor	@XMM[3], @XMM[3], @XMM[8]
++	veor	@XMM[5], @XMM[5], @XMM[8]
++	veor	@XMM[0], @XMM[0], @XMM[8]
++	veor	@XMM[1], @XMM[1], @XMM[8]
++	bx	lr
++.size	_bsaes_decrypt8,.-_bsaes_decrypt8
++
++.type	_bsaes_const,%object
++.align	6
++_bsaes_const:
++.LM0ISR:	@ InvShiftRows constants
++	.quad	0x0a0e0206070b0f03, 0x0004080c0d010509
++.LISR:
++	.quad	0x0504070602010003, 0x0f0e0d0c080b0a09
++.LISRM0:
++	.quad	0x01040b0e0205080f, 0x0306090c00070a0d
++.LM0SR:		@ ShiftRows constants
++	.quad	0x0a0e02060f03070b, 0x0004080c05090d01
++.LSR:
++	.quad	0x0504070600030201, 0x0f0e0d0c0a09080b
++.LSRM0:
++	.quad	0x0304090e00050a0f, 0x01060b0c0207080d
++.LM0:
++	.quad	0x02060a0e03070b0f, 0x0004080c0105090d
++.LREVM0SR:
++	.quad	0x090d01050c000408, 0x03070b0f060a0e02
++.asciz	"Bit-sliced AES for NEON, CRYPTOGAMS by "
++.align	6
++.size	_bsaes_const,.-_bsaes_const
++
++.type	_bsaes_encrypt8,%function
++.align	4
++_bsaes_encrypt8:
++	adr	$const,_bsaes_encrypt8
++	vldmia	$key!, {@XMM[9]}		@ round 0 key
++#ifdef	__APPLE__
++	adr	$const,.LM0SR
++#else
++	sub	$const,$const,#_bsaes_encrypt8-.LM0SR
++#endif
++
++	vldmia	$const!, {@XMM[8]}		@ .LM0SR
++_bsaes_encrypt8_alt:
++	veor	@XMM[10], @XMM[0], @XMM[9]	@ xor with round0 key
++	veor	@XMM[11], @XMM[1], @XMM[9]
++	 vtbl.8	`&Dlo(@XMM[0])`, {@XMM[10]}, `&Dlo(@XMM[8])`
++	 vtbl.8	`&Dhi(@XMM[0])`, {@XMM[10]}, `&Dhi(@XMM[8])`
++	veor	@XMM[12], @XMM[2], @XMM[9]
++	 vtbl.8	`&Dlo(@XMM[1])`, {@XMM[11]}, `&Dlo(@XMM[8])`
++	 vtbl.8	`&Dhi(@XMM[1])`, {@XMM[11]}, `&Dhi(@XMM[8])`
++	veor	@XMM[13], @XMM[3], @XMM[9]
++	 vtbl.8	`&Dlo(@XMM[2])`, {@XMM[12]}, `&Dlo(@XMM[8])`
++	 vtbl.8	`&Dhi(@XMM[2])`, {@XMM[12]}, `&Dhi(@XMM[8])`
++	veor	@XMM[14], @XMM[4], @XMM[9]
++	 vtbl.8	`&Dlo(@XMM[3])`, {@XMM[13]}, `&Dlo(@XMM[8])`
++	 vtbl.8	`&Dhi(@XMM[3])`, {@XMM[13]}, `&Dhi(@XMM[8])`
++	veor	@XMM[15], @XMM[5], @XMM[9]
++	 vtbl.8	`&Dlo(@XMM[4])`, {@XMM[14]}, `&Dlo(@XMM[8])`
++	 vtbl.8	`&Dhi(@XMM[4])`, {@XMM[14]}, `&Dhi(@XMM[8])`
++	veor	@XMM[10], @XMM[6], @XMM[9]
++	 vtbl.8	`&Dlo(@XMM[5])`, {@XMM[15]}, `&Dlo(@XMM[8])`
++	 vtbl.8	`&Dhi(@XMM[5])`, {@XMM[15]}, `&Dhi(@XMM[8])`
++	veor	@XMM[11], @XMM[7], @XMM[9]
++	 vtbl.8	`&Dlo(@XMM[6])`, {@XMM[10]}, `&Dlo(@XMM[8])`
++	 vtbl.8	`&Dhi(@XMM[6])`, {@XMM[10]}, `&Dhi(@XMM[8])`
++	 vtbl.8	`&Dlo(@XMM[7])`, {@XMM[11]}, `&Dlo(@XMM[8])`
++	 vtbl.8	`&Dhi(@XMM[7])`, {@XMM[11]}, `&Dhi(@XMM[8])`
++_bsaes_encrypt8_bitslice:
++___
++	&bitslice	(@XMM[0..7, 8..11]);
++$code.=<<___;
++	sub	$rounds,$rounds,#1
++	b	.Lenc_sbox
++.align	4
++.Lenc_loop:
++___
++	&ShiftRows	(@XMM[0..7, 8..12]);
++$code.=".Lenc_sbox:\n";
++	&Sbox		(@XMM[0..7, 8..15]);
++$code.=<<___;
++	subs	$rounds,$rounds,#1
++	bcc	.Lenc_done
++___
++	&MixColumns	(@XMM[0,1,4,6,3,7,2,5, 8..15]);
++$code.=<<___;
++	vldmia	$const, {@XMM[12]}		@ .LSR
++	ite	eq				@ Thumb2 thing, samity check in ARM
++	addeq	$const,$const,#0x10
++	bne	.Lenc_loop
++	vldmia	$const, {@XMM[12]}		@ .LSRM0
++	b	.Lenc_loop
++.align	4
++.Lenc_done:
++___
++	# output in lsb > [t0, t1, t4, t6, t3, t7, t2, t5] < msb
++	&bitslice	(@XMM[0,1,4,6,3,7,2,5, 8..11]);
++$code.=<<___;
++	vldmia	$key, {@XMM[8]}			@ last round key
++	veor	@XMM[4], @XMM[4], @XMM[8]
++	veor	@XMM[6], @XMM[6], @XMM[8]
++	veor	@XMM[3], @XMM[3], @XMM[8]
++	veor	@XMM[7], @XMM[7], @XMM[8]
++	veor	@XMM[2], @XMM[2], @XMM[8]
++	veor	@XMM[5], @XMM[5], @XMM[8]
++	veor	@XMM[0], @XMM[0], @XMM[8]
++	veor	@XMM[1], @XMM[1], @XMM[8]
++	bx	lr
++.size	_bsaes_encrypt8,.-_bsaes_encrypt8
++___
++}
++{
++my ($out,$inp,$rounds,$const)=("r12","r4","r5","r6");
++
++sub bitslice_key {
++my @x=reverse(@_[0..7]);
++my ($bs0,$bs1,$bs2,$t2,$t3)=@_[8..12];
++
++	&swapmove	(@x[0,1],1,$bs0,$t2,$t3);
++$code.=<<___;
++	@ &swapmove(@x[2,3],1,$t0,$t2,$t3);
++	vmov	@x[2], @x[0]
++	vmov	@x[3], @x[1]
++___
++	#&swapmove2x(@x[4,5,6,7],1,$t0,$t2,$t3);
++
++	&swapmove2x	(@x[0,2,1,3],2,$bs1,$t2,$t3);
++$code.=<<___;
++	@ &swapmove2x(@x[4,6,5,7],2,$t1,$t2,$t3);
++	vmov	@x[4], @x[0]
++	vmov	@x[6], @x[2]
++	vmov	@x[5], @x[1]
++	vmov	@x[7], @x[3]
++___
++	&swapmove2x	(@x[0,4,1,5],4,$bs2,$t2,$t3);
++	&swapmove2x	(@x[2,6,3,7],4,$bs2,$t2,$t3);
++}
++
++$code.=<<___;
++.type	_bsaes_key_convert,%function
++.align	4
++_bsaes_key_convert:
++	adr	$const,_bsaes_key_convert
++	vld1.8	{@XMM[7]},  [$inp]!		@ load round 0 key
++#ifdef	__APPLE__
++	adr	$const,.LM0
++#else
++	sub	$const,$const,#_bsaes_key_convert-.LM0
++#endif
++	vld1.8	{@XMM[15]}, [$inp]!		@ load round 1 key
++
++	vmov.i8	@XMM[8],  #0x01			@ bit masks
++	vmov.i8	@XMM[9],  #0x02
++	vmov.i8	@XMM[10], #0x04
++	vmov.i8	@XMM[11], #0x08
++	vmov.i8	@XMM[12], #0x10
++	vmov.i8	@XMM[13], #0x20
++	vldmia	$const, {@XMM[14]}		@ .LM0
++
++#ifdef __ARMEL__
++	vrev32.8	@XMM[7],  @XMM[7]
++	vrev32.8	@XMM[15], @XMM[15]
++#endif
++	sub	$rounds,$rounds,#1
++	vstmia	$out!, {@XMM[7]}		@ save round 0 key
++	b	.Lkey_loop
++
++.align	4
++.Lkey_loop:
++	vtbl.8	`&Dlo(@XMM[7])`,{@XMM[15]},`&Dlo(@XMM[14])`
++	vtbl.8	`&Dhi(@XMM[7])`,{@XMM[15]},`&Dhi(@XMM[14])`
++	vmov.i8	@XMM[6],  #0x40
++	vmov.i8	@XMM[15], #0x80
++
++	vtst.8	@XMM[0], @XMM[7], @XMM[8]
++	vtst.8	@XMM[1], @XMM[7], @XMM[9]
++	vtst.8	@XMM[2], @XMM[7], @XMM[10]
++	vtst.8	@XMM[3], @XMM[7], @XMM[11]
++	vtst.8	@XMM[4], @XMM[7], @XMM[12]
++	vtst.8	@XMM[5], @XMM[7], @XMM[13]
++	vtst.8	@XMM[6], @XMM[7], @XMM[6]
++	vtst.8	@XMM[7], @XMM[7], @XMM[15]
++	vld1.8	{@XMM[15]}, [$inp]!		@ load next round key
++	vmvn	@XMM[0], @XMM[0]		@ "pnot"
++	vmvn	@XMM[1], @XMM[1]
++	vmvn	@XMM[5], @XMM[5]
++	vmvn	@XMM[6], @XMM[6]
++#ifdef __ARMEL__
++	vrev32.8	@XMM[15], @XMM[15]
++#endif
++	subs	$rounds,$rounds,#1
++	vstmia	$out!,{@XMM[0]-@XMM[7]}		@ write bit-sliced round key
++	bne	.Lkey_loop
++
++	vmov.i8	@XMM[7],#0x63			@ compose .L63
++	@ don't save last round key
++	bx	lr
++.size	_bsaes_key_convert,.-_bsaes_key_convert
++___
++}
++
++if (0) {		# following four functions are unsupported interface
++			# used for benchmarking...
++$code.=<<___;
++.globl	bsaes_enc_key_convert
++.type	bsaes_enc_key_convert,%function
++.align	4
++bsaes_enc_key_convert:
++	stmdb	sp!,{r4-r6,lr}
++	vstmdb	sp!,{d8-d15}		@ ABI specification says so
++
++	ldr	r5,[$inp,#240]			@ pass rounds
++	mov	r4,$inp				@ pass key
++	mov	r12,$out			@ pass key schedule
++	bl	_bsaes_key_convert
++	veor	@XMM[7],@XMM[7],@XMM[15]	@ fix up last round key
++	vstmia	r12, {@XMM[7]}			@ save last round key
++
++	vldmia	sp!,{d8-d15}
++	ldmia	sp!,{r4-r6,pc}
++.size	bsaes_enc_key_convert,.-bsaes_enc_key_convert
++
++.globl	bsaes_encrypt_128
++.type	bsaes_encrypt_128,%function
++.align	4
++bsaes_encrypt_128:
++	stmdb	sp!,{r4-r6,lr}
++	vstmdb	sp!,{d8-d15}		@ ABI specification says so
++.Lenc128_loop:
++	vld1.8	{@XMM[0]-@XMM[1]}, [$inp]!	@ load input
++	vld1.8	{@XMM[2]-@XMM[3]}, [$inp]!
++	mov	r4,$key				@ pass the key
++	vld1.8	{@XMM[4]-@XMM[5]}, [$inp]!
++	mov	r5,#10				@ pass rounds
++	vld1.8	{@XMM[6]-@XMM[7]}, [$inp]!
++
++	bl	_bsaes_encrypt8
++
++	vst1.8	{@XMM[0]-@XMM[1]}, [$out]!	@ write output
++	vst1.8	{@XMM[4]}, [$out]!
++	vst1.8	{@XMM[6]}, [$out]!
++	vst1.8	{@XMM[3]}, [$out]!
++	vst1.8	{@XMM[7]}, [$out]!
++	vst1.8	{@XMM[2]}, [$out]!
++	subs	$len,$len,#0x80
++	vst1.8	{@XMM[5]}, [$out]!
++	bhi	.Lenc128_loop
++
++	vldmia	sp!,{d8-d15}
++	ldmia	sp!,{r4-r6,pc}
++.size	bsaes_encrypt_128,.-bsaes_encrypt_128
++
++.globl	bsaes_dec_key_convert
++.type	bsaes_dec_key_convert,%function
++.align	4
++bsaes_dec_key_convert:
++	stmdb	sp!,{r4-r6,lr}
++	vstmdb	sp!,{d8-d15}		@ ABI specification says so
++
++	ldr	r5,[$inp,#240]			@ pass rounds
++	mov	r4,$inp				@ pass key
++	mov	r12,$out			@ pass key schedule
++	bl	_bsaes_key_convert
++	vldmia	$out, {@XMM[6]}
++	vstmia	r12,  {@XMM[15]}		@ save last round key
++	veor	@XMM[7], @XMM[7], @XMM[6]	@ fix up round 0 key
++	vstmia	$out, {@XMM[7]}
++
++	vldmia	sp!,{d8-d15}
++	ldmia	sp!,{r4-r6,pc}
++.size	bsaes_dec_key_convert,.-bsaes_dec_key_convert
++
++.globl	bsaes_decrypt_128
++.type	bsaes_decrypt_128,%function
++.align	4
++bsaes_decrypt_128:
++	stmdb	sp!,{r4-r6,lr}
++	vstmdb	sp!,{d8-d15}		@ ABI specification says so
++.Ldec128_loop:
++	vld1.8	{@XMM[0]-@XMM[1]}, [$inp]!	@ load input
++	vld1.8	{@XMM[2]-@XMM[3]}, [$inp]!
++	mov	r4,$key				@ pass the key
++	vld1.8	{@XMM[4]-@XMM[5]}, [$inp]!
++	mov	r5,#10				@ pass rounds
++	vld1.8	{@XMM[6]-@XMM[7]}, [$inp]!
++
++	bl	_bsaes_decrypt8
++
++	vst1.8	{@XMM[0]-@XMM[1]}, [$out]!	@ write output
++	vst1.8	{@XMM[6]}, [$out]!
++	vst1.8	{@XMM[4]}, [$out]!
++	vst1.8	{@XMM[2]}, [$out]!
++	vst1.8	{@XMM[7]}, [$out]!
++	vst1.8	{@XMM[3]}, [$out]!
++	subs	$len,$len,#0x80
++	vst1.8	{@XMM[5]}, [$out]!
++	bhi	.Ldec128_loop
++
++	vldmia	sp!,{d8-d15}
++	ldmia	sp!,{r4-r6,pc}
++.size	bsaes_decrypt_128,.-bsaes_decrypt_128
++___
++}
++{
++my ($inp,$out,$len,$key, $ivp,$fp,$rounds)=map("r$_",(0..3,8..10));
++my ($keysched)=("sp");
++
++$code.=<<___;
++.extern AES_cbc_encrypt
++.extern AES_decrypt
++
++.global	bsaes_cbc_encrypt
++.type	bsaes_cbc_encrypt,%function
++.align	5
++bsaes_cbc_encrypt:
++#ifndef	__KERNEL__
++	cmp	$len, #128
++#ifndef	__thumb__
++	blo	AES_cbc_encrypt
++#else
++	bhs	1f
++	b	AES_cbc_encrypt
++1:
++#endif
++#endif
++
++	@ it is up to the caller to make sure we are called with enc == 0
++
++	mov	ip, sp
++	stmdb	sp!, {r4-r10, lr}
++	VFP_ABI_PUSH
++	ldr	$ivp, [ip]			@ IV is 1st arg on the stack
++	mov	$len, $len, lsr#4		@ len in 16 byte blocks
++	sub	sp, #0x10			@ scratch space to carry over the IV
++	mov	$fp, sp				@ save sp
++
++	ldr	$rounds, [$key, #240]		@ get # of rounds
++#ifndef	BSAES_ASM_EXTENDED_KEY
++	@ allocate the key schedule on the stack
++	sub	r12, sp, $rounds, lsl#7		@ 128 bytes per inner round key
++	add	r12, #`128-32`			@ sifze of bit-slices key schedule
++
++	@ populate the key schedule
++	mov	r4, $key			@ pass key
++	mov	r5, $rounds			@ pass # of rounds
++	mov	sp, r12				@ sp is $keysched
++	bl	_bsaes_key_convert
++	vldmia	$keysched, {@XMM[6]}
++	vstmia	r12,  {@XMM[15]}		@ save last round key
++	veor	@XMM[7], @XMM[7], @XMM[6]	@ fix up round 0 key
++	vstmia	$keysched, {@XMM[7]}
++#else
++	ldr	r12, [$key, #244]
++	eors	r12, #1
++	beq	0f
++
++	@ populate the key schedule
++	str	r12, [$key, #244]
++	mov	r4, $key			@ pass key
++	mov	r5, $rounds			@ pass # of rounds
++	add	r12, $key, #248			@ pass key schedule
++	bl	_bsaes_key_convert
++	add	r4, $key, #248
++	vldmia	r4, {@XMM[6]}
++	vstmia	r12, {@XMM[15]}			@ save last round key
++	veor	@XMM[7], @XMM[7], @XMM[6]	@ fix up round 0 key
++	vstmia	r4, {@XMM[7]}
++
++.align	2
++0:
++#endif
++
++	vld1.8	{@XMM[15]}, [$ivp]		@ load IV
++	b	.Lcbc_dec_loop
++
++.align	4
++.Lcbc_dec_loop:
++	subs	$len, $len, #0x8
++	bmi	.Lcbc_dec_loop_finish
++
++	vld1.8	{@XMM[0]-@XMM[1]}, [$inp]!	@ load input
++	vld1.8	{@XMM[2]-@XMM[3]}, [$inp]!
++#ifndef	BSAES_ASM_EXTENDED_KEY
++	mov	r4, $keysched			@ pass the key
++#else
++	add	r4, $key, #248
++#endif
++	vld1.8	{@XMM[4]-@XMM[5]}, [$inp]!
++	mov	r5, $rounds
++	vld1.8	{@XMM[6]-@XMM[7]}, [$inp]
++	sub	$inp, $inp, #0x60
++	vstmia	$fp, {@XMM[15]}			@ put aside IV
++
++	bl	_bsaes_decrypt8
++
++	vldmia	$fp, {@XMM[14]}			@ reload IV
++	vld1.8	{@XMM[8]-@XMM[9]}, [$inp]!	@ reload input
++	veor	@XMM[0], @XMM[0], @XMM[14]	@ ^= IV
++	vld1.8	{@XMM[10]-@XMM[11]}, [$inp]!
++	veor	@XMM[1], @XMM[1], @XMM[8]
++	veor	@XMM[6], @XMM[6], @XMM[9]
++	vld1.8	{@XMM[12]-@XMM[13]}, [$inp]!
++	veor	@XMM[4], @XMM[4], @XMM[10]
++	veor	@XMM[2], @XMM[2], @XMM[11]
++	vld1.8	{@XMM[14]-@XMM[15]}, [$inp]!
++	veor	@XMM[7], @XMM[7], @XMM[12]
++	vst1.8	{@XMM[0]-@XMM[1]}, [$out]!	@ write output
++	veor	@XMM[3], @XMM[3], @XMM[13]
++	vst1.8	{@XMM[6]}, [$out]!
++	veor	@XMM[5], @XMM[5], @XMM[14]
++	vst1.8	{@XMM[4]}, [$out]!
++	vst1.8	{@XMM[2]}, [$out]!
++	vst1.8	{@XMM[7]}, [$out]!
++	vst1.8	{@XMM[3]}, [$out]!
++	vst1.8	{@XMM[5]}, [$out]!
++
++	b	.Lcbc_dec_loop
++
++.Lcbc_dec_loop_finish:
++	adds	$len, $len, #8
++	beq	.Lcbc_dec_done
++
++	vld1.8	{@XMM[0]}, [$inp]!		@ load input
++	cmp	$len, #2
++	blo	.Lcbc_dec_one
++	vld1.8	{@XMM[1]}, [$inp]!
++#ifndef	BSAES_ASM_EXTENDED_KEY
++	mov	r4, $keysched			@ pass the key
++#else
++	add	r4, $key, #248
++#endif
++	mov	r5, $rounds
++	vstmia	$fp, {@XMM[15]}			@ put aside IV
++	beq	.Lcbc_dec_two
++	vld1.8	{@XMM[2]}, [$inp]!
++	cmp	$len, #4
++	blo	.Lcbc_dec_three
++	vld1.8	{@XMM[3]}, [$inp]!
++	beq	.Lcbc_dec_four
++	vld1.8	{@XMM[4]}, [$inp]!
++	cmp	$len, #6
++	blo	.Lcbc_dec_five
++	vld1.8	{@XMM[5]}, [$inp]!
++	beq	.Lcbc_dec_six
++	vld1.8	{@XMM[6]}, [$inp]!
++	sub	$inp, $inp, #0x70
++
++	bl	_bsaes_decrypt8
++
++	vldmia	$fp, {@XMM[14]}			@ reload IV
++	vld1.8	{@XMM[8]-@XMM[9]}, [$inp]!	@ reload input
++	veor	@XMM[0], @XMM[0], @XMM[14]	@ ^= IV
++	vld1.8	{@XMM[10]-@XMM[11]}, [$inp]!
++	veor	@XMM[1], @XMM[1], @XMM[8]
++	veor	@XMM[6], @XMM[6], @XMM[9]
++	vld1.8	{@XMM[12]-@XMM[13]}, [$inp]!
++	veor	@XMM[4], @XMM[4], @XMM[10]
++	veor	@XMM[2], @XMM[2], @XMM[11]
++	vld1.8	{@XMM[15]}, [$inp]!
++	veor	@XMM[7], @XMM[7], @XMM[12]
++	vst1.8	{@XMM[0]-@XMM[1]}, [$out]!	@ write output
++	veor	@XMM[3], @XMM[3], @XMM[13]
++	vst1.8	{@XMM[6]}, [$out]!
++	vst1.8	{@XMM[4]}, [$out]!
++	vst1.8	{@XMM[2]}, [$out]!
++	vst1.8	{@XMM[7]}, [$out]!
++	vst1.8	{@XMM[3]}, [$out]!
++	b	.Lcbc_dec_done
++.align	4
++.Lcbc_dec_six:
++	sub	$inp, $inp, #0x60
++	bl	_bsaes_decrypt8
++	vldmia	$fp,{@XMM[14]}			@ reload IV
++	vld1.8	{@XMM[8]-@XMM[9]}, [$inp]!	@ reload input
++	veor	@XMM[0], @XMM[0], @XMM[14]	@ ^= IV
++	vld1.8	{@XMM[10]-@XMM[11]}, [$inp]!
++	veor	@XMM[1], @XMM[1], @XMM[8]
++	veor	@XMM[6], @XMM[6], @XMM[9]
++	vld1.8	{@XMM[12]}, [$inp]!
++	veor	@XMM[4], @XMM[4], @XMM[10]
++	veor	@XMM[2], @XMM[2], @XMM[11]
++	vld1.8	{@XMM[15]}, [$inp]!
++	veor	@XMM[7], @XMM[7], @XMM[12]
++	vst1.8	{@XMM[0]-@XMM[1]}, [$out]!	@ write output
++	vst1.8	{@XMM[6]}, [$out]!
++	vst1.8	{@XMM[4]}, [$out]!
++	vst1.8	{@XMM[2]}, [$out]!
++	vst1.8	{@XMM[7]}, [$out]!
++	b	.Lcbc_dec_done
++.align	4
++.Lcbc_dec_five:
++	sub	$inp, $inp, #0x50
++	bl	_bsaes_decrypt8
++	vldmia	$fp, {@XMM[14]}			@ reload IV
++	vld1.8	{@XMM[8]-@XMM[9]}, [$inp]!	@ reload input
++	veor	@XMM[0], @XMM[0], @XMM[14]	@ ^= IV
++	vld1.8	{@XMM[10]-@XMM[11]}, [$inp]!
++	veor	@XMM[1], @XMM[1], @XMM[8]
++	veor	@XMM[6], @XMM[6], @XMM[9]
++	vld1.8	{@XMM[15]}, [$inp]!
++	veor	@XMM[4], @XMM[4], @XMM[10]
++	vst1.8	{@XMM[0]-@XMM[1]}, [$out]!	@ write output
++	veor	@XMM[2], @XMM[2], @XMM[11]
++	vst1.8	{@XMM[6]}, [$out]!
++	vst1.8	{@XMM[4]}, [$out]!
++	vst1.8	{@XMM[2]}, [$out]!
++	b	.Lcbc_dec_done
++.align	4
++.Lcbc_dec_four:
++	sub	$inp, $inp, #0x40
++	bl	_bsaes_decrypt8
++	vldmia	$fp, {@XMM[14]}			@ reload IV
++	vld1.8	{@XMM[8]-@XMM[9]}, [$inp]!	@ reload input
++	veor	@XMM[0], @XMM[0], @XMM[14]	@ ^= IV
++	vld1.8	{@XMM[10]}, [$inp]!
++	veor	@XMM[1], @XMM[1], @XMM[8]
++	veor	@XMM[6], @XMM[6], @XMM[9]
++	vld1.8	{@XMM[15]}, [$inp]!
++	veor	@XMM[4], @XMM[4], @XMM[10]
++	vst1.8	{@XMM[0]-@XMM[1]}, [$out]!	@ write output
++	vst1.8	{@XMM[6]}, [$out]!
++	vst1.8	{@XMM[4]}, [$out]!
++	b	.Lcbc_dec_done
++.align	4
++.Lcbc_dec_three:
++	sub	$inp, $inp, #0x30
++	bl	_bsaes_decrypt8
++	vldmia	$fp, {@XMM[14]}			@ reload IV
++	vld1.8	{@XMM[8]-@XMM[9]}, [$inp]!	@ reload input
++	veor	@XMM[0], @XMM[0], @XMM[14]	@ ^= IV
++	vld1.8	{@XMM[15]}, [$inp]!
++	veor	@XMM[1], @XMM[1], @XMM[8]
++	veor	@XMM[6], @XMM[6], @XMM[9]
++	vst1.8	{@XMM[0]-@XMM[1]}, [$out]!	@ write output
++	vst1.8	{@XMM[6]}, [$out]!
++	b	.Lcbc_dec_done
++.align	4
++.Lcbc_dec_two:
++	sub	$inp, $inp, #0x20
++	bl	_bsaes_decrypt8
++	vldmia	$fp, {@XMM[14]}			@ reload IV
++	vld1.8	{@XMM[8]}, [$inp]!		@ reload input
++	veor	@XMM[0], @XMM[0], @XMM[14]	@ ^= IV
++	vld1.8	{@XMM[15]}, [$inp]!		@ reload input
++	veor	@XMM[1], @XMM[1], @XMM[8]
++	vst1.8	{@XMM[0]-@XMM[1]}, [$out]!	@ write output
++	b	.Lcbc_dec_done
++.align	4
++.Lcbc_dec_one:
++	sub	$inp, $inp, #0x10
++	mov	$rounds, $out			@ save original out pointer
++	mov	$out, $fp			@ use the iv scratch space as out buffer
++	mov	r2, $key
++	vmov	@XMM[4],@XMM[15]		@ just in case ensure that IV
++	vmov	@XMM[5],@XMM[0]			@ and input are preserved
++	bl	AES_decrypt
++	vld1.8	{@XMM[0]}, [$fp,:64]		@ load result
++	veor	@XMM[0], @XMM[0], @XMM[4]	@ ^= IV
++	vmov	@XMM[15], @XMM[5]		@ @XMM[5] holds input
++	vst1.8	{@XMM[0]}, [$rounds]		@ write output
++
++.Lcbc_dec_done:
++#ifndef	BSAES_ASM_EXTENDED_KEY
++	vmov.i32	q0, #0
++	vmov.i32	q1, #0
++.Lcbc_dec_bzero:				@ wipe key schedule [if any]
++	vstmia		$keysched!, {q0-q1}
++	cmp		$keysched, $fp
++	bne		.Lcbc_dec_bzero
++#endif
++
++	mov	sp, $fp
++	add	sp, #0x10			@ add sp,$fp,#0x10 is no good for thumb
++	vst1.8	{@XMM[15]}, [$ivp]		@ return IV
++	VFP_ABI_POP
++	ldmia	sp!, {r4-r10, pc}
++.size	bsaes_cbc_encrypt,.-bsaes_cbc_encrypt
++___
++}
++{
++my ($inp,$out,$len,$key, $ctr,$fp,$rounds)=(map("r$_",(0..3,8..10)));
++my $const = "r6";	# shared with _bsaes_encrypt8_alt
++my $keysched = "sp";
++
++$code.=<<___;
++.extern	AES_encrypt
++.global	bsaes_ctr32_encrypt_blocks
++.type	bsaes_ctr32_encrypt_blocks,%function
++.align	5
++bsaes_ctr32_encrypt_blocks:
++	cmp	$len, #8			@ use plain AES for
++	blo	.Lctr_enc_short			@ small sizes
++
++	mov	ip, sp
++	stmdb	sp!, {r4-r10, lr}
++	VFP_ABI_PUSH
++	ldr	$ctr, [ip]			@ ctr is 1st arg on the stack
++	sub	sp, sp, #0x10			@ scratch space to carry over the ctr
++	mov	$fp, sp				@ save sp
++
++	ldr	$rounds, [$key, #240]		@ get # of rounds
++#ifndef	BSAES_ASM_EXTENDED_KEY
++	@ allocate the key schedule on the stack
++	sub	r12, sp, $rounds, lsl#7		@ 128 bytes per inner round key
++	add	r12, #`128-32`			@ size of bit-sliced key schedule
++
++	@ populate the key schedule
++	mov	r4, $key			@ pass key
++	mov	r5, $rounds			@ pass # of rounds
++	mov	sp, r12				@ sp is $keysched
++	bl	_bsaes_key_convert
++	veor	@XMM[7],@XMM[7],@XMM[15]	@ fix up last round key
++	vstmia	r12, {@XMM[7]}			@ save last round key
++
++	vld1.8	{@XMM[0]}, [$ctr]		@ load counter
++#ifdef	__APPLE__
++	mov	$ctr, #:lower16:(.LREVM0SR-.LM0)
++	add	$ctr, $const, $ctr
++#else
++	add	$ctr, $const, #.LREVM0SR-.LM0	@ borrow $ctr
++#endif
++	vldmia	$keysched, {@XMM[4]}		@ load round0 key
++#else
++	ldr	r12, [$key, #244]
++	eors	r12, #1
++	beq	0f
++
++	@ populate the key schedule
++	str	r12, [$key, #244]
++	mov	r4, $key			@ pass key
++	mov	r5, $rounds			@ pass # of rounds
++	add	r12, $key, #248			@ pass key schedule
++	bl	_bsaes_key_convert
++	veor	@XMM[7],@XMM[7],@XMM[15]	@ fix up last round key
++	vstmia	r12, {@XMM[7]}			@ save last round key
++
++.align	2
++0:	add	r12, $key, #248
++	vld1.8	{@XMM[0]}, [$ctr]		@ load counter
++	adrl	$ctr, .LREVM0SR			@ borrow $ctr
++	vldmia	r12, {@XMM[4]}			@ load round0 key
++	sub	sp, #0x10			@ place for adjusted round0 key
++#endif
++
++	vmov.i32	@XMM[8],#1		@ compose 1<<96
++	veor		@XMM[9],@XMM[9],@XMM[9]
++	vrev32.8	@XMM[0],@XMM[0]
++	vext.8		@XMM[8],@XMM[9],@XMM[8],#4
++	vrev32.8	@XMM[4],@XMM[4]
++	vadd.u32	@XMM[9],@XMM[8],@XMM[8]	@ compose 2<<96
++	vstmia	$keysched, {@XMM[4]}		@ save adjusted round0 key
++	b	.Lctr_enc_loop
++
++.align	4
++.Lctr_enc_loop:
++	vadd.u32	@XMM[10], @XMM[8], @XMM[9]	@ compose 3<<96
++	vadd.u32	@XMM[1], @XMM[0], @XMM[8]	@ +1
++	vadd.u32	@XMM[2], @XMM[0], @XMM[9]	@ +2
++	vadd.u32	@XMM[3], @XMM[0], @XMM[10]	@ +3
++	vadd.u32	@XMM[4], @XMM[1], @XMM[10]
++	vadd.u32	@XMM[5], @XMM[2], @XMM[10]
++	vadd.u32	@XMM[6], @XMM[3], @XMM[10]
++	vadd.u32	@XMM[7], @XMM[4], @XMM[10]
++	vadd.u32	@XMM[10], @XMM[5], @XMM[10]	@ next counter
++
++	@ Borrow prologue from _bsaes_encrypt8 to use the opportunity
++	@ to flip byte order in 32-bit counter
++
++	vldmia		$keysched, {@XMM[9]}		@ load round0 key
++#ifndef	BSAES_ASM_EXTENDED_KEY
++	add		r4, $keysched, #0x10		@ pass next round key
++#else
++	add		r4, $key, #`248+16`
++#endif
++	vldmia		$ctr, {@XMM[8]}			@ .LREVM0SR
++	mov		r5, $rounds			@ pass rounds
++	vstmia		$fp, {@XMM[10]}			@ save next counter
++#ifdef	__APPLE__
++	mov		$const, #:lower16:(.LREVM0SR-.LSR)
++	sub		$const, $ctr, $const
++#else
++	sub		$const, $ctr, #.LREVM0SR-.LSR	@ pass constants
++#endif
++
++	bl		_bsaes_encrypt8_alt
++
++	subs		$len, $len, #8
++	blo		.Lctr_enc_loop_done
++
++	vld1.8		{@XMM[8]-@XMM[9]}, [$inp]!	@ load input
++	vld1.8		{@XMM[10]-@XMM[11]}, [$inp]!
++	veor		@XMM[0], @XMM[8]
++	veor		@XMM[1], @XMM[9]
++	vld1.8		{@XMM[12]-@XMM[13]}, [$inp]!
++	veor		@XMM[4], @XMM[10]
++	veor		@XMM[6], @XMM[11]
++	vld1.8		{@XMM[14]-@XMM[15]}, [$inp]!
++	veor		@XMM[3], @XMM[12]
++	vst1.8		{@XMM[0]-@XMM[1]}, [$out]!	@ write output
++	veor		@XMM[7], @XMM[13]
++	veor		@XMM[2], @XMM[14]
++	vst1.8		{@XMM[4]}, [$out]!
++	veor		@XMM[5], @XMM[15]
++	vst1.8		{@XMM[6]}, [$out]!
++	vmov.i32	@XMM[8], #1			@ compose 1<<96
++	vst1.8		{@XMM[3]}, [$out]!
++	veor		@XMM[9], @XMM[9], @XMM[9]
++	vst1.8		{@XMM[7]}, [$out]!
++	vext.8		@XMM[8], @XMM[9], @XMM[8], #4
++	vst1.8		{@XMM[2]}, [$out]!
++	vadd.u32	@XMM[9],@XMM[8],@XMM[8]		@ compose 2<<96
++	vst1.8		{@XMM[5]}, [$out]!
++	vldmia		$fp, {@XMM[0]}			@ load counter
++
++	bne		.Lctr_enc_loop
++	b		.Lctr_enc_done
++
++.align	4
++.Lctr_enc_loop_done:
++	add		$len, $len, #8
++	vld1.8		{@XMM[8]}, [$inp]!	@ load input
++	veor		@XMM[0], @XMM[8]
++	vst1.8		{@XMM[0]}, [$out]!	@ write output
++	cmp		$len, #2
++	blo		.Lctr_enc_done
++	vld1.8		{@XMM[9]}, [$inp]!
++	veor		@XMM[1], @XMM[9]
++	vst1.8		{@XMM[1]}, [$out]!
++	beq		.Lctr_enc_done
++	vld1.8		{@XMM[10]}, [$inp]!
++	veor		@XMM[4], @XMM[10]
++	vst1.8		{@XMM[4]}, [$out]!
++	cmp		$len, #4
++	blo		.Lctr_enc_done
++	vld1.8		{@XMM[11]}, [$inp]!
++	veor		@XMM[6], @XMM[11]
++	vst1.8		{@XMM[6]}, [$out]!
++	beq		.Lctr_enc_done
++	vld1.8		{@XMM[12]}, [$inp]!
++	veor		@XMM[3], @XMM[12]
++	vst1.8		{@XMM[3]}, [$out]!
++	cmp		$len, #6
++	blo		.Lctr_enc_done
++	vld1.8		{@XMM[13]}, [$inp]!
++	veor		@XMM[7], @XMM[13]
++	vst1.8		{@XMM[7]}, [$out]!
++	beq		.Lctr_enc_done
++	vld1.8		{@XMM[14]}, [$inp]
++	veor		@XMM[2], @XMM[14]
++	vst1.8		{@XMM[2]}, [$out]!
++
++.Lctr_enc_done:
++	vmov.i32	q0, #0
++	vmov.i32	q1, #0
++#ifndef	BSAES_ASM_EXTENDED_KEY
++.Lctr_enc_bzero:			@ wipe key schedule [if any]
++	vstmia		$keysched!, {q0-q1}
++	cmp		$keysched, $fp
++	bne		.Lctr_enc_bzero
++#else
++	vstmia		$keysched, {q0-q1}
++#endif
++
++	mov	sp, $fp
++	add	sp, #0x10		@ add sp,$fp,#0x10 is no good for thumb
++	VFP_ABI_POP
++	ldmia	sp!, {r4-r10, pc}	@ return
++
++.align	4
++.Lctr_enc_short:
++	ldr	ip, [sp]		@ ctr pointer is passed on stack
++	stmdb	sp!, {r4-r8, lr}
++
++	mov	r4, $inp		@ copy arguments
++	mov	r5, $out
++	mov	r6, $len
++	mov	r7, $key
++	ldr	r8, [ip, #12]		@ load counter LSW
++	vld1.8	{@XMM[1]}, [ip]		@ load whole counter value
++#ifdef __ARMEL__
++	rev	r8, r8
++#endif
++	sub	sp, sp, #0x10
++	vst1.8	{@XMM[1]}, [sp]		@ copy counter value
++	sub	sp, sp, #0x10
++
++.Lctr_enc_short_loop:
++	add	r0, sp, #0x10		@ input counter value
++	mov	r1, sp			@ output on the stack
++	mov	r2, r7			@ key
++
++	bl	AES_encrypt
++
++	vld1.8	{@XMM[0]}, [r4]!	@ load input
++	vld1.8	{@XMM[1]}, [sp]		@ load encrypted counter
++	add	r8, r8, #1
++#ifdef __ARMEL__
++	rev	r0, r8
++	str	r0, [sp, #0x1c]		@ next counter value
++#else
++	str	r8, [sp, #0x1c]		@ next counter value
++#endif
++	veor	@XMM[0],@XMM[0],@XMM[1]
++	vst1.8	{@XMM[0]}, [r5]!	@ store output
++	subs	r6, r6, #1
++	bne	.Lctr_enc_short_loop
++
++	vmov.i32	q0, #0
++	vmov.i32	q1, #0
++	vstmia		sp!, {q0-q1}
++
++	ldmia	sp!, {r4-r8, pc}
++.size	bsaes_ctr32_encrypt_blocks,.-bsaes_ctr32_encrypt_blocks
++___
++}
++{
++######################################################################
++# void bsaes_xts_[en|de]crypt(const char *inp,char *out,size_t len,
++#	const AES_KEY *key1, const AES_KEY *key2,
++#	const unsigned char iv[16]);
++#
++my ($inp,$out,$len,$key,$rounds,$magic,$fp)=(map("r$_",(7..10,1..3)));
++my $const="r6";		# returned by _bsaes_key_convert
++my $twmask=@XMM[5];
++my @T=@XMM[6..7];
++
++$code.=<<___;
++.globl	bsaes_xts_encrypt
++.type	bsaes_xts_encrypt,%function
++.align	4
++bsaes_xts_encrypt:
++	mov	ip, sp
++	stmdb	sp!, {r4-r10, lr}		@ 0x20
++	VFP_ABI_PUSH
++	mov	r6, sp				@ future $fp
++
++	mov	$inp, r0
++	mov	$out, r1
++	mov	$len, r2
++	mov	$key, r3
++
++	sub	r0, sp, #0x10			@ 0x10
++	bic	r0, #0xf			@ align at 16 bytes
++	mov	sp, r0
++
++#ifdef	XTS_CHAIN_TWEAK
++	ldr	r0, [ip]			@ pointer to input tweak
++#else
++	@ generate initial tweak
++	ldr	r0, [ip, #4]			@ iv[]
++	mov	r1, sp
++	ldr	r2, [ip, #0]			@ key2
++	bl	AES_encrypt
++	mov	r0,sp				@ pointer to initial tweak
++#endif
++
++	ldr	$rounds, [$key, #240]		@ get # of rounds
++	mov	$fp, r6
++#ifndef	BSAES_ASM_EXTENDED_KEY
++	@ allocate the key schedule on the stack
++	sub	r12, sp, $rounds, lsl#7		@ 128 bytes per inner round key
++	@ add	r12, #`128-32`			@ size of bit-sliced key schedule
++	sub	r12, #`32+16`			@ place for tweak[9]
++
++	@ populate the key schedule
++	mov	r4, $key			@ pass key
++	mov	r5, $rounds			@ pass # of rounds
++	mov	sp, r12
++	add	r12, #0x90			@ pass key schedule
++	bl	_bsaes_key_convert
++	veor	@XMM[7], @XMM[7], @XMM[15]	@ fix up last round key
++	vstmia	r12, {@XMM[7]}			@ save last round key
++#else
++	ldr	r12, [$key, #244]
++	eors	r12, #1
++	beq	0f
++
++	str	r12, [$key, #244]
++	mov	r4, $key			@ pass key
++	mov	r5, $rounds			@ pass # of rounds
++	add	r12, $key, #248			@ pass key schedule
++	bl	_bsaes_key_convert
++	veor	@XMM[7], @XMM[7], @XMM[15]	@ fix up last round key
++	vstmia	r12, {@XMM[7]}
++
++.align	2
++0:	sub	sp, #0x90			@ place for tweak[9]
++#endif
++
++	vld1.8	{@XMM[8]}, [r0]			@ initial tweak
++	adr	$magic, .Lxts_magic
++
++	subs	$len, #0x80
++	blo	.Lxts_enc_short
++	b	.Lxts_enc_loop
++
++.align	4
++.Lxts_enc_loop:
++	vldmia		$magic, {$twmask}	@ load XTS magic
++	vshr.s64	@T[0], @XMM[8], #63
++	mov		r0, sp
++	vand		@T[0], @T[0], $twmask
++___
++for($i=9;$i<16;$i++) {
++$code.=<<___;
++	vadd.u64	@XMM[$i], @XMM[$i-1], @XMM[$i-1]
++	vst1.64		{@XMM[$i-1]}, [r0,:128]!
++	vswp		`&Dhi("@T[0]")`,`&Dlo("@T[0]")`
++	vshr.s64	@T[1], @XMM[$i], #63
++	veor		@XMM[$i], @XMM[$i], @T[0]
++	vand		@T[1], @T[1], $twmask
++___
++	@T=reverse(@T);
++
++$code.=<<___ if ($i>=10);
++	vld1.8		{@XMM[$i-10]}, [$inp]!
++___
++$code.=<<___ if ($i>=11);
++	veor		@XMM[$i-11], @XMM[$i-11], @XMM[$i-3]
++___
++}
++$code.=<<___;
++	vadd.u64	@XMM[8], @XMM[15], @XMM[15]
++	vst1.64		{@XMM[15]}, [r0,:128]!
++	vswp		`&Dhi("@T[0]")`,`&Dlo("@T[0]")`
++	veor		@XMM[8], @XMM[8], @T[0]
++	vst1.64		{@XMM[8]}, [r0,:128]		@ next round tweak
++
++	vld1.8		{@XMM[6]-@XMM[7]}, [$inp]!
++	veor		@XMM[5], @XMM[5], @XMM[13]
++#ifndef	BSAES_ASM_EXTENDED_KEY
++	add		r4, sp, #0x90			@ pass key schedule
++#else
++	add		r4, $key, #248			@ pass key schedule
++#endif
++	veor		@XMM[6], @XMM[6], @XMM[14]
++	mov		r5, $rounds			@ pass rounds
++	veor		@XMM[7], @XMM[7], @XMM[15]
++	mov		r0, sp
++
++	bl		_bsaes_encrypt8
++
++	vld1.64		{@XMM[ 8]-@XMM[ 9]}, [r0,:128]!
++	vld1.64		{@XMM[10]-@XMM[11]}, [r0,:128]!
++	veor		@XMM[0], @XMM[0], @XMM[ 8]
++	vld1.64		{@XMM[12]-@XMM[13]}, [r0,:128]!
++	veor		@XMM[1], @XMM[1], @XMM[ 9]
++	veor		@XMM[8], @XMM[4], @XMM[10]
++	vst1.8		{@XMM[0]-@XMM[1]}, [$out]!
++	veor		@XMM[9], @XMM[6], @XMM[11]
++	vld1.64		{@XMM[14]-@XMM[15]}, [r0,:128]!
++	veor		@XMM[10], @XMM[3], @XMM[12]
++	vst1.8		{@XMM[8]-@XMM[9]}, [$out]!
++	veor		@XMM[11], @XMM[7], @XMM[13]
++	veor		@XMM[12], @XMM[2], @XMM[14]
++	vst1.8		{@XMM[10]-@XMM[11]}, [$out]!
++	veor		@XMM[13], @XMM[5], @XMM[15]
++	vst1.8		{@XMM[12]-@XMM[13]}, [$out]!
++
++	vld1.64		{@XMM[8]}, [r0,:128]		@ next round tweak
++
++	subs		$len, #0x80
++	bpl		.Lxts_enc_loop
++
++.Lxts_enc_short:
++	adds		$len, #0x70
++	bmi		.Lxts_enc_done
++
++	vldmia		$magic, {$twmask}	@ load XTS magic
++	vshr.s64	@T[0], @XMM[8], #63
++	mov		r0, sp
++	vand		@T[0], @T[0], $twmask
++___
++for($i=9;$i<16;$i++) {
++$code.=<<___;
++	vadd.u64	@XMM[$i], @XMM[$i-1], @XMM[$i-1]
++	vst1.64		{@XMM[$i-1]}, [r0,:128]!
++	vswp		`&Dhi("@T[0]")`,`&Dlo("@T[0]")`
++	vshr.s64	@T[1], @XMM[$i], #63
++	veor		@XMM[$i], @XMM[$i], @T[0]
++	vand		@T[1], @T[1], $twmask
++___
++	@T=reverse(@T);
++
++$code.=<<___ if ($i>=10);
++	vld1.8		{@XMM[$i-10]}, [$inp]!
++	subs		$len, #0x10
++	bmi		.Lxts_enc_`$i-9`
++___
++$code.=<<___ if ($i>=11);
++	veor		@XMM[$i-11], @XMM[$i-11], @XMM[$i-3]
++___
++}
++$code.=<<___;
++	sub		$len, #0x10
++	vst1.64		{@XMM[15]}, [r0,:128]		@ next round tweak
++
++	vld1.8		{@XMM[6]}, [$inp]!
++	veor		@XMM[5], @XMM[5], @XMM[13]
++#ifndef	BSAES_ASM_EXTENDED_KEY
++	add		r4, sp, #0x90			@ pass key schedule
++#else
++	add		r4, $key, #248			@ pass key schedule
++#endif
++	veor		@XMM[6], @XMM[6], @XMM[14]
++	mov		r5, $rounds			@ pass rounds
++	mov		r0, sp
++
++	bl		_bsaes_encrypt8
++
++	vld1.64		{@XMM[ 8]-@XMM[ 9]}, [r0,:128]!
++	vld1.64		{@XMM[10]-@XMM[11]}, [r0,:128]!
++	veor		@XMM[0], @XMM[0], @XMM[ 8]
++	vld1.64		{@XMM[12]-@XMM[13]}, [r0,:128]!
++	veor		@XMM[1], @XMM[1], @XMM[ 9]
++	veor		@XMM[8], @XMM[4], @XMM[10]
++	vst1.8		{@XMM[0]-@XMM[1]}, [$out]!
++	veor		@XMM[9], @XMM[6], @XMM[11]
++	vld1.64		{@XMM[14]}, [r0,:128]!
++	veor		@XMM[10], @XMM[3], @XMM[12]
++	vst1.8		{@XMM[8]-@XMM[9]}, [$out]!
++	veor		@XMM[11], @XMM[7], @XMM[13]
++	veor		@XMM[12], @XMM[2], @XMM[14]
++	vst1.8		{@XMM[10]-@XMM[11]}, [$out]!
++	vst1.8		{@XMM[12]}, [$out]!
++
++	vld1.64		{@XMM[8]}, [r0,:128]		@ next round tweak
++	b		.Lxts_enc_done
++.align	4
++.Lxts_enc_6:
++	veor		@XMM[4], @XMM[4], @XMM[12]
++#ifndef	BSAES_ASM_EXTENDED_KEY
++	add		r4, sp, #0x90			@ pass key schedule
++#else
++	add		r4, $key, #248			@ pass key schedule
++#endif
++	veor		@XMM[5], @XMM[5], @XMM[13]
++	mov		r5, $rounds			@ pass rounds
++	mov		r0, sp
++
++	bl		_bsaes_encrypt8
++
++	vld1.64		{@XMM[ 8]-@XMM[ 9]}, [r0,:128]!
++	vld1.64		{@XMM[10]-@XMM[11]}, [r0,:128]!
++	veor		@XMM[0], @XMM[0], @XMM[ 8]
++	vld1.64		{@XMM[12]-@XMM[13]}, [r0,:128]!
++	veor		@XMM[1], @XMM[1], @XMM[ 9]
++	veor		@XMM[8], @XMM[4], @XMM[10]
++	vst1.8		{@XMM[0]-@XMM[1]}, [$out]!
++	veor		@XMM[9], @XMM[6], @XMM[11]
++	veor		@XMM[10], @XMM[3], @XMM[12]
++	vst1.8		{@XMM[8]-@XMM[9]}, [$out]!
++	veor		@XMM[11], @XMM[7], @XMM[13]
++	vst1.8		{@XMM[10]-@XMM[11]}, [$out]!
++
++	vld1.64		{@XMM[8]}, [r0,:128]		@ next round tweak
++	b		.Lxts_enc_done
++
++@ put this in range for both ARM and Thumb mode adr instructions
++.align	5
++.Lxts_magic:
++	.quad	1, 0x87
++
++.align	5
++.Lxts_enc_5:
++	veor		@XMM[3], @XMM[3], @XMM[11]
++#ifndef	BSAES_ASM_EXTENDED_KEY
++	add		r4, sp, #0x90			@ pass key schedule
++#else
++	add		r4, $key, #248			@ pass key schedule
++#endif
++	veor		@XMM[4], @XMM[4], @XMM[12]
++	mov		r5, $rounds			@ pass rounds
++	mov		r0, sp
++
++	bl		_bsaes_encrypt8
++
++	vld1.64		{@XMM[ 8]-@XMM[ 9]}, [r0,:128]!
++	vld1.64		{@XMM[10]-@XMM[11]}, [r0,:128]!
++	veor		@XMM[0], @XMM[0], @XMM[ 8]
++	vld1.64		{@XMM[12]}, [r0,:128]!
++	veor		@XMM[1], @XMM[1], @XMM[ 9]
++	veor		@XMM[8], @XMM[4], @XMM[10]
++	vst1.8		{@XMM[0]-@XMM[1]}, [$out]!
++	veor		@XMM[9], @XMM[6], @XMM[11]
++	veor		@XMM[10], @XMM[3], @XMM[12]
++	vst1.8		{@XMM[8]-@XMM[9]}, [$out]!
++	vst1.8		{@XMM[10]}, [$out]!
++
++	vld1.64		{@XMM[8]}, [r0,:128]		@ next round tweak
++	b		.Lxts_enc_done
++.align	4
++.Lxts_enc_4:
++	veor		@XMM[2], @XMM[2], @XMM[10]
++#ifndef	BSAES_ASM_EXTENDED_KEY
++	add		r4, sp, #0x90			@ pass key schedule
++#else
++	add		r4, $key, #248			@ pass key schedule
++#endif
++	veor		@XMM[3], @XMM[3], @XMM[11]
++	mov		r5, $rounds			@ pass rounds
++	mov		r0, sp
++
++	bl		_bsaes_encrypt8
++
++	vld1.64		{@XMM[ 8]-@XMM[ 9]}, [r0,:128]!
++	vld1.64		{@XMM[10]-@XMM[11]}, [r0,:128]!
++	veor		@XMM[0], @XMM[0], @XMM[ 8]
++	veor		@XMM[1], @XMM[1], @XMM[ 9]
++	veor		@XMM[8], @XMM[4], @XMM[10]
++	vst1.8		{@XMM[0]-@XMM[1]}, [$out]!
++	veor		@XMM[9], @XMM[6], @XMM[11]
++	vst1.8		{@XMM[8]-@XMM[9]}, [$out]!
++
++	vld1.64		{@XMM[8]}, [r0,:128]		@ next round tweak
++	b		.Lxts_enc_done
++.align	4
++.Lxts_enc_3:
++	veor		@XMM[1], @XMM[1], @XMM[9]
++#ifndef	BSAES_ASM_EXTENDED_KEY
++	add		r4, sp, #0x90			@ pass key schedule
++#else
++	add		r4, $key, #248			@ pass key schedule
++#endif
++	veor		@XMM[2], @XMM[2], @XMM[10]
++	mov		r5, $rounds			@ pass rounds
++	mov		r0, sp
++
++	bl		_bsaes_encrypt8
++
++	vld1.64		{@XMM[8]-@XMM[9]}, [r0,:128]!
++	vld1.64		{@XMM[10]}, [r0,:128]!
++	veor		@XMM[0], @XMM[0], @XMM[ 8]
++	veor		@XMM[1], @XMM[1], @XMM[ 9]
++	veor		@XMM[8], @XMM[4], @XMM[10]
++	vst1.8		{@XMM[0]-@XMM[1]}, [$out]!
++	vst1.8		{@XMM[8]}, [$out]!
++
++	vld1.64		{@XMM[8]}, [r0,:128]		@ next round tweak
++	b		.Lxts_enc_done
++.align	4
++.Lxts_enc_2:
++	veor		@XMM[0], @XMM[0], @XMM[8]
++#ifndef	BSAES_ASM_EXTENDED_KEY
++	add		r4, sp, #0x90			@ pass key schedule
++#else
++	add		r4, $key, #248			@ pass key schedule
++#endif
++	veor		@XMM[1], @XMM[1], @XMM[9]
++	mov		r5, $rounds			@ pass rounds
++	mov		r0, sp
++
++	bl		_bsaes_encrypt8
++
++	vld1.64		{@XMM[8]-@XMM[9]}, [r0,:128]!
++	veor		@XMM[0], @XMM[0], @XMM[ 8]
++	veor		@XMM[1], @XMM[1], @XMM[ 9]
++	vst1.8		{@XMM[0]-@XMM[1]}, [$out]!
++
++	vld1.64		{@XMM[8]}, [r0,:128]		@ next round tweak
++	b		.Lxts_enc_done
++.align	4
++.Lxts_enc_1:
++	mov		r0, sp
++	veor		@XMM[0], @XMM[0], @XMM[8]
++	mov		r1, sp
++	vst1.8		{@XMM[0]}, [sp,:128]
++	mov		r2, $key
++	mov		r4, $fp				@ preserve fp
++
++	bl		AES_encrypt
++
++	vld1.8		{@XMM[0]}, [sp,:128]
++	veor		@XMM[0], @XMM[0], @XMM[8]
++	vst1.8		{@XMM[0]}, [$out]!
++	mov		$fp, r4
++
++	vmov		@XMM[8], @XMM[9]		@ next round tweak
++
++.Lxts_enc_done:
++#ifndef	XTS_CHAIN_TWEAK
++	adds		$len, #0x10
++	beq		.Lxts_enc_ret
++	sub		r6, $out, #0x10
++
++.Lxts_enc_steal:
++	ldrb		r0, [$inp], #1
++	ldrb		r1, [$out, #-0x10]
++	strb		r0, [$out, #-0x10]
++	strb		r1, [$out], #1
++
++	subs		$len, #1
++	bhi		.Lxts_enc_steal
++
++	vld1.8		{@XMM[0]}, [r6]
++	mov		r0, sp
++	veor		@XMM[0], @XMM[0], @XMM[8]
++	mov		r1, sp
++	vst1.8		{@XMM[0]}, [sp,:128]
++	mov		r2, $key
++	mov		r4, $fp			@ preserve fp
++
++	bl		AES_encrypt
++
++	vld1.8		{@XMM[0]}, [sp,:128]
++	veor		@XMM[0], @XMM[0], @XMM[8]
++	vst1.8		{@XMM[0]}, [r6]
++	mov		$fp, r4
++#endif
++
++.Lxts_enc_ret:
++	bic		r0, $fp, #0xf
++	vmov.i32	q0, #0
++	vmov.i32	q1, #0
++#ifdef	XTS_CHAIN_TWEAK
++	ldr		r1, [$fp, #0x20+VFP_ABI_FRAME]	@ chain tweak
++#endif
++.Lxts_enc_bzero:				@ wipe key schedule [if any]
++	vstmia		sp!, {q0-q1}
++	cmp		sp, r0
++	bne		.Lxts_enc_bzero
++
++	mov		sp, $fp
++#ifdef	XTS_CHAIN_TWEAK
++	vst1.8		{@XMM[8]}, [r1]
++#endif
++	VFP_ABI_POP
++	ldmia		sp!, {r4-r10, pc}	@ return
++
++.size	bsaes_xts_encrypt,.-bsaes_xts_encrypt
++
++.globl	bsaes_xts_decrypt
++.type	bsaes_xts_decrypt,%function
++.align	4
++bsaes_xts_decrypt:
++	mov	ip, sp
++	stmdb	sp!, {r4-r10, lr}		@ 0x20
++	VFP_ABI_PUSH
++	mov	r6, sp				@ future $fp
++
++	mov	$inp, r0
++	mov	$out, r1
++	mov	$len, r2
++	mov	$key, r3
++
++	sub	r0, sp, #0x10			@ 0x10
++	bic	r0, #0xf			@ align at 16 bytes
++	mov	sp, r0
++
++#ifdef	XTS_CHAIN_TWEAK
++	ldr	r0, [ip]			@ pointer to input tweak
++#else
++	@ generate initial tweak
++	ldr	r0, [ip, #4]			@ iv[]
++	mov	r1, sp
++	ldr	r2, [ip, #0]			@ key2
++	bl	AES_encrypt
++	mov	r0, sp				@ pointer to initial tweak
++#endif
++
++	ldr	$rounds, [$key, #240]		@ get # of rounds
++	mov	$fp, r6
++#ifndef	BSAES_ASM_EXTENDED_KEY
++	@ allocate the key schedule on the stack
++	sub	r12, sp, $rounds, lsl#7		@ 128 bytes per inner round key
++	@ add	r12, #`128-32`			@ size of bit-sliced key schedule
++	sub	r12, #`32+16`			@ place for tweak[9]
++
++	@ populate the key schedule
++	mov	r4, $key			@ pass key
++	mov	r5, $rounds			@ pass # of rounds
++	mov	sp, r12
++	add	r12, #0x90			@ pass key schedule
++	bl	_bsaes_key_convert
++	add	r4, sp, #0x90
++	vldmia	r4, {@XMM[6]}
++	vstmia	r12,  {@XMM[15]}		@ save last round key
++	veor	@XMM[7], @XMM[7], @XMM[6]	@ fix up round 0 key
++	vstmia	r4, {@XMM[7]}
++#else
++	ldr	r12, [$key, #244]
++	eors	r12, #1
++	beq	0f
++
++	str	r12, [$key, #244]
++	mov	r4, $key			@ pass key
++	mov	r5, $rounds			@ pass # of rounds
++	add	r12, $key, #248			@ pass key schedule
++	bl	_bsaes_key_convert
++	add	r4, $key, #248
++	vldmia	r4, {@XMM[6]}
++	vstmia	r12,  {@XMM[15]}		@ save last round key
++	veor	@XMM[7], @XMM[7], @XMM[6]	@ fix up round 0 key
++	vstmia	r4, {@XMM[7]}
++
++.align	2
++0:	sub	sp, #0x90			@ place for tweak[9]
++#endif
++	vld1.8	{@XMM[8]}, [r0]			@ initial tweak
++	adr	$magic, .Lxts_magic
++
++#ifndef	XTS_CHAIN_TWEAK
++	tst	$len, #0xf			@ if not multiple of 16
++	it	ne				@ Thumb2 thing, sanity check in ARM
++	subne	$len, #0x10			@ subtract another 16 bytes
++#endif
++	subs	$len, #0x80
++
++	blo	.Lxts_dec_short
++	b	.Lxts_dec_loop
++
++.align	4
++.Lxts_dec_loop:
++	vldmia		$magic, {$twmask}	@ load XTS magic
++	vshr.s64	@T[0], @XMM[8], #63
++	mov		r0, sp
++	vand		@T[0], @T[0], $twmask
++___
++for($i=9;$i<16;$i++) {
++$code.=<<___;
++	vadd.u64	@XMM[$i], @XMM[$i-1], @XMM[$i-1]
++	vst1.64		{@XMM[$i-1]}, [r0,:128]!
++	vswp		`&Dhi("@T[0]")`,`&Dlo("@T[0]")`
++	vshr.s64	@T[1], @XMM[$i], #63
++	veor		@XMM[$i], @XMM[$i], @T[0]
++	vand		@T[1], @T[1], $twmask
++___
++	@T=reverse(@T);
++
++$code.=<<___ if ($i>=10);
++	vld1.8		{@XMM[$i-10]}, [$inp]!
++___
++$code.=<<___ if ($i>=11);
++	veor		@XMM[$i-11], @XMM[$i-11], @XMM[$i-3]
++___
++}
++$code.=<<___;
++	vadd.u64	@XMM[8], @XMM[15], @XMM[15]
++	vst1.64		{@XMM[15]}, [r0,:128]!
++	vswp		`&Dhi("@T[0]")`,`&Dlo("@T[0]")`
++	veor		@XMM[8], @XMM[8], @T[0]
++	vst1.64		{@XMM[8]}, [r0,:128]		@ next round tweak
++
++	vld1.8		{@XMM[6]-@XMM[7]}, [$inp]!
++	veor		@XMM[5], @XMM[5], @XMM[13]
++#ifndef	BSAES_ASM_EXTENDED_KEY
++	add		r4, sp, #0x90			@ pass key schedule
++#else
++	add		r4, $key, #248			@ pass key schedule
++#endif
++	veor		@XMM[6], @XMM[6], @XMM[14]
++	mov		r5, $rounds			@ pass rounds
++	veor		@XMM[7], @XMM[7], @XMM[15]
++	mov		r0, sp
++
++	bl		_bsaes_decrypt8
++
++	vld1.64		{@XMM[ 8]-@XMM[ 9]}, [r0,:128]!
++	vld1.64		{@XMM[10]-@XMM[11]}, [r0,:128]!
++	veor		@XMM[0], @XMM[0], @XMM[ 8]
++	vld1.64		{@XMM[12]-@XMM[13]}, [r0,:128]!
++	veor		@XMM[1], @XMM[1], @XMM[ 9]
++	veor		@XMM[8], @XMM[6], @XMM[10]
++	vst1.8		{@XMM[0]-@XMM[1]}, [$out]!
++	veor		@XMM[9], @XMM[4], @XMM[11]
++	vld1.64		{@XMM[14]-@XMM[15]}, [r0,:128]!
++	veor		@XMM[10], @XMM[2], @XMM[12]
++	vst1.8		{@XMM[8]-@XMM[9]}, [$out]!
++	veor		@XMM[11], @XMM[7], @XMM[13]
++	veor		@XMM[12], @XMM[3], @XMM[14]
++	vst1.8		{@XMM[10]-@XMM[11]}, [$out]!
++	veor		@XMM[13], @XMM[5], @XMM[15]
++	vst1.8		{@XMM[12]-@XMM[13]}, [$out]!
++
++	vld1.64		{@XMM[8]}, [r0,:128]		@ next round tweak
++
++	subs		$len, #0x80
++	bpl		.Lxts_dec_loop
++
++.Lxts_dec_short:
++	adds		$len, #0x70
++	bmi		.Lxts_dec_done
++
++	vldmia		$magic, {$twmask}	@ load XTS magic
++	vshr.s64	@T[0], @XMM[8], #63
++	mov		r0, sp
++	vand		@T[0], @T[0], $twmask
++___
++for($i=9;$i<16;$i++) {
++$code.=<<___;
++	vadd.u64	@XMM[$i], @XMM[$i-1], @XMM[$i-1]
++	vst1.64		{@XMM[$i-1]}, [r0,:128]!
++	vswp		`&Dhi("@T[0]")`,`&Dlo("@T[0]")`
++	vshr.s64	@T[1], @XMM[$i], #63
++	veor		@XMM[$i], @XMM[$i], @T[0]
++	vand		@T[1], @T[1], $twmask
++___
++	@T=reverse(@T);
++
++$code.=<<___ if ($i>=10);
++	vld1.8		{@XMM[$i-10]}, [$inp]!
++	subs		$len, #0x10
++	bmi		.Lxts_dec_`$i-9`
++___
++$code.=<<___ if ($i>=11);
++	veor		@XMM[$i-11], @XMM[$i-11], @XMM[$i-3]
++___
++}
++$code.=<<___;
++	sub		$len, #0x10
++	vst1.64		{@XMM[15]}, [r0,:128]		@ next round tweak
++
++	vld1.8		{@XMM[6]}, [$inp]!
++	veor		@XMM[5], @XMM[5], @XMM[13]
++#ifndef	BSAES_ASM_EXTENDED_KEY
++	add		r4, sp, #0x90			@ pass key schedule
++#else
++	add		r4, $key, #248			@ pass key schedule
++#endif
++	veor		@XMM[6], @XMM[6], @XMM[14]
++	mov		r5, $rounds			@ pass rounds
++	mov		r0, sp
++
++	bl		_bsaes_decrypt8
++
++	vld1.64		{@XMM[ 8]-@XMM[ 9]}, [r0,:128]!
++	vld1.64		{@XMM[10]-@XMM[11]}, [r0,:128]!
++	veor		@XMM[0], @XMM[0], @XMM[ 8]
++	vld1.64		{@XMM[12]-@XMM[13]}, [r0,:128]!
++	veor		@XMM[1], @XMM[1], @XMM[ 9]
++	veor		@XMM[8], @XMM[6], @XMM[10]
++	vst1.8		{@XMM[0]-@XMM[1]}, [$out]!
++	veor		@XMM[9], @XMM[4], @XMM[11]
++	vld1.64		{@XMM[14]}, [r0,:128]!
++	veor		@XMM[10], @XMM[2], @XMM[12]
++	vst1.8		{@XMM[8]-@XMM[9]}, [$out]!
++	veor		@XMM[11], @XMM[7], @XMM[13]
++	veor		@XMM[12], @XMM[3], @XMM[14]
++	vst1.8		{@XMM[10]-@XMM[11]}, [$out]!
++	vst1.8		{@XMM[12]}, [$out]!
++
++	vld1.64		{@XMM[8]}, [r0,:128]		@ next round tweak
++	b		.Lxts_dec_done
++.align	4
++.Lxts_dec_6:
++	vst1.64		{@XMM[14]}, [r0,:128]		@ next round tweak
++
++	veor		@XMM[4], @XMM[4], @XMM[12]
++#ifndef	BSAES_ASM_EXTENDED_KEY
++	add		r4, sp, #0x90			@ pass key schedule
++#else
++	add		r4, $key, #248			@ pass key schedule
++#endif
++	veor		@XMM[5], @XMM[5], @XMM[13]
++	mov		r5, $rounds			@ pass rounds
++	mov		r0, sp
++
++	bl		_bsaes_decrypt8
++
++	vld1.64		{@XMM[ 8]-@XMM[ 9]}, [r0,:128]!
++	vld1.64		{@XMM[10]-@XMM[11]}, [r0,:128]!
++	veor		@XMM[0], @XMM[0], @XMM[ 8]
++	vld1.64		{@XMM[12]-@XMM[13]}, [r0,:128]!
++	veor		@XMM[1], @XMM[1], @XMM[ 9]
++	veor		@XMM[8], @XMM[6], @XMM[10]
++	vst1.8		{@XMM[0]-@XMM[1]}, [$out]!
++	veor		@XMM[9], @XMM[4], @XMM[11]
++	veor		@XMM[10], @XMM[2], @XMM[12]
++	vst1.8		{@XMM[8]-@XMM[9]}, [$out]!
++	veor		@XMM[11], @XMM[7], @XMM[13]
++	vst1.8		{@XMM[10]-@XMM[11]}, [$out]!
++
++	vld1.64		{@XMM[8]}, [r0,:128]		@ next round tweak
++	b		.Lxts_dec_done
++.align	4
++.Lxts_dec_5:
++	veor		@XMM[3], @XMM[3], @XMM[11]
++#ifndef	BSAES_ASM_EXTENDED_KEY
++	add		r4, sp, #0x90			@ pass key schedule
++#else
++	add		r4, $key, #248			@ pass key schedule
++#endif
++	veor		@XMM[4], @XMM[4], @XMM[12]
++	mov		r5, $rounds			@ pass rounds
++	mov		r0, sp
++
++	bl		_bsaes_decrypt8
++
++	vld1.64		{@XMM[ 8]-@XMM[ 9]}, [r0,:128]!
++	vld1.64		{@XMM[10]-@XMM[11]}, [r0,:128]!
++	veor		@XMM[0], @XMM[0], @XMM[ 8]
++	vld1.64		{@XMM[12]}, [r0,:128]!
++	veor		@XMM[1], @XMM[1], @XMM[ 9]
++	veor		@XMM[8], @XMM[6], @XMM[10]
++	vst1.8		{@XMM[0]-@XMM[1]}, [$out]!
++	veor		@XMM[9], @XMM[4], @XMM[11]
++	veor		@XMM[10], @XMM[2], @XMM[12]
++	vst1.8		{@XMM[8]-@XMM[9]}, [$out]!
++	vst1.8		{@XMM[10]}, [$out]!
++
++	vld1.64		{@XMM[8]}, [r0,:128]		@ next round tweak
++	b		.Lxts_dec_done
++.align	4
++.Lxts_dec_4:
++	veor		@XMM[2], @XMM[2], @XMM[10]
++#ifndef	BSAES_ASM_EXTENDED_KEY
++	add		r4, sp, #0x90			@ pass key schedule
++#else
++	add		r4, $key, #248			@ pass key schedule
++#endif
++	veor		@XMM[3], @XMM[3], @XMM[11]
++	mov		r5, $rounds			@ pass rounds
++	mov		r0, sp
++
++	bl		_bsaes_decrypt8
++
++	vld1.64		{@XMM[ 8]-@XMM[ 9]}, [r0,:128]!
++	vld1.64		{@XMM[10]-@XMM[11]}, [r0,:128]!
++	veor		@XMM[0], @XMM[0], @XMM[ 8]
++	veor		@XMM[1], @XMM[1], @XMM[ 9]
++	veor		@XMM[8], @XMM[6], @XMM[10]
++	vst1.8		{@XMM[0]-@XMM[1]}, [$out]!
++	veor		@XMM[9], @XMM[4], @XMM[11]
++	vst1.8		{@XMM[8]-@XMM[9]}, [$out]!
++
++	vld1.64		{@XMM[8]}, [r0,:128]		@ next round tweak
++	b		.Lxts_dec_done
++.align	4
++.Lxts_dec_3:
++	veor		@XMM[1], @XMM[1], @XMM[9]
++#ifndef	BSAES_ASM_EXTENDED_KEY
++	add		r4, sp, #0x90			@ pass key schedule
++#else
++	add		r4, $key, #248			@ pass key schedule
++#endif
++	veor		@XMM[2], @XMM[2], @XMM[10]
++	mov		r5, $rounds			@ pass rounds
++	mov		r0, sp
++
++	bl		_bsaes_decrypt8
++
++	vld1.64		{@XMM[8]-@XMM[9]}, [r0,:128]!
++	vld1.64		{@XMM[10]}, [r0,:128]!
++	veor		@XMM[0], @XMM[0], @XMM[ 8]
++	veor		@XMM[1], @XMM[1], @XMM[ 9]
++	veor		@XMM[8], @XMM[6], @XMM[10]
++	vst1.8		{@XMM[0]-@XMM[1]}, [$out]!
++	vst1.8		{@XMM[8]}, [$out]!
++
++	vld1.64		{@XMM[8]}, [r0,:128]		@ next round tweak
++	b		.Lxts_dec_done
++.align	4
++.Lxts_dec_2:
++	veor		@XMM[0], @XMM[0], @XMM[8]
++#ifndef	BSAES_ASM_EXTENDED_KEY
++	add		r4, sp, #0x90			@ pass key schedule
++#else
++	add		r4, $key, #248			@ pass key schedule
++#endif
++	veor		@XMM[1], @XMM[1], @XMM[9]
++	mov		r5, $rounds			@ pass rounds
++	mov		r0, sp
++
++	bl		_bsaes_decrypt8
++
++	vld1.64		{@XMM[8]-@XMM[9]}, [r0,:128]!
++	veor		@XMM[0], @XMM[0], @XMM[ 8]
++	veor		@XMM[1], @XMM[1], @XMM[ 9]
++	vst1.8		{@XMM[0]-@XMM[1]}, [$out]!
++
++	vld1.64		{@XMM[8]}, [r0,:128]		@ next round tweak
++	b		.Lxts_dec_done
++.align	4
++.Lxts_dec_1:
++	mov		r0, sp
++	veor		@XMM[0], @XMM[0], @XMM[8]
++	mov		r1, sp
++	vst1.8		{@XMM[0]}, [sp,:128]
++	mov		r5, $magic			@ preserve magic
++	mov		r2, $key
++	mov		r4, $fp				@ preserve fp
++
++	bl		AES_decrypt
++
++	vld1.8		{@XMM[0]}, [sp,:128]
++	veor		@XMM[0], @XMM[0], @XMM[8]
++	vst1.8		{@XMM[0]}, [$out]!
++	mov		$fp, r4
++	mov		$magic, r5
++
++	vmov		@XMM[8], @XMM[9]		@ next round tweak
++
++.Lxts_dec_done:
++#ifndef	XTS_CHAIN_TWEAK
++	adds		$len, #0x10
++	beq		.Lxts_dec_ret
++
++	@ calculate one round of extra tweak for the stolen ciphertext
++	vldmia		$magic, {$twmask}
++	vshr.s64	@XMM[6], @XMM[8], #63
++	vand		@XMM[6], @XMM[6], $twmask
++	vadd.u64	@XMM[9], @XMM[8], @XMM[8]
++	vswp		`&Dhi("@XMM[6]")`,`&Dlo("@XMM[6]")`
++	veor		@XMM[9], @XMM[9], @XMM[6]
++
++	@ perform the final decryption with the last tweak value
++	vld1.8		{@XMM[0]}, [$inp]!
++	mov		r0, sp
++	veor		@XMM[0], @XMM[0], @XMM[9]
++	mov		r1, sp
++	vst1.8		{@XMM[0]}, [sp,:128]
++	mov		r2, $key
++	mov		r4, $fp			@ preserve fp
++
++	bl		AES_decrypt
++
++	vld1.8		{@XMM[0]}, [sp,:128]
++	veor		@XMM[0], @XMM[0], @XMM[9]
++	vst1.8		{@XMM[0]}, [$out]
++
++	mov		r6, $out
++.Lxts_dec_steal:
++	ldrb		r1, [$out]
++	ldrb		r0, [$inp], #1
++	strb		r1, [$out, #0x10]
++	strb		r0, [$out], #1
++
++	subs		$len, #1
++	bhi		.Lxts_dec_steal
++
++	vld1.8		{@XMM[0]}, [r6]
++	mov		r0, sp
++	veor		@XMM[0], @XMM[8]
++	mov		r1, sp
++	vst1.8		{@XMM[0]}, [sp,:128]
++	mov		r2, $key
++
++	bl		AES_decrypt
++
++	vld1.8		{@XMM[0]}, [sp,:128]
++	veor		@XMM[0], @XMM[0], @XMM[8]
++	vst1.8		{@XMM[0]}, [r6]
++	mov		$fp, r4
++#endif
++
++.Lxts_dec_ret:
++	bic		r0, $fp, #0xf
++	vmov.i32	q0, #0
++	vmov.i32	q1, #0
++#ifdef	XTS_CHAIN_TWEAK
++	ldr		r1, [$fp, #0x20+VFP_ABI_FRAME]	@ chain tweak
++#endif
++.Lxts_dec_bzero:				@ wipe key schedule [if any]
++	vstmia		sp!, {q0-q1}
++	cmp		sp, r0
++	bne		.Lxts_dec_bzero
++
++	mov		sp, $fp
++#ifdef	XTS_CHAIN_TWEAK
++	vst1.8		{@XMM[8]}, [r1]
++#endif
++	VFP_ABI_POP
++	ldmia		sp!, {r4-r10, pc}	@ return
++
++.size	bsaes_xts_decrypt,.-bsaes_xts_decrypt
++___
++}
++$code.=<<___;
++#endif
++___
++
++$code =~ s/\`([^\`]*)\`/eval($1)/gem;
++
++open SELF,$0;
++while() {
++	next if (/^#!/);
++        last if (!s/^#/@/ and !/^$/);
++        print;
++}
++close SELF;
++
++print $code;
++
++close STDOUT;
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/aes/asm/bsaes-x86_64.pl b/CryptoPkg/Library/OpensslLib/openssl/crypto/aes/asm/bsaes-x86_64.pl
+new file mode 100644
+index 0000000..921d870
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/aes/asm/bsaes-x86_64.pl
+@@ -0,0 +1,3111 @@
++#! /usr/bin/env perl
++# Copyright 2011-2016 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
++# in the file LICENSE in the source distribution or at
++# https://www.openssl.org/source/license.html
++
++
++###################################################################
++### AES-128 [originally in CTR mode]				###
++### bitsliced implementation for Intel Core 2 processors	###
++### requires support of SSE extensions up to SSSE3		###
++### Author: Emilia Käsper and Peter Schwabe			###
++### Date: 2009-03-19						###
++### Public domain						###
++###								###
++### See http://homes.esat.kuleuven.be/~ekasper/#software for	###
++### further information.					###
++###################################################################
++#
++# September 2011.
++#
++# Started as transliteration to "perlasm" the original code has
++# undergone following changes:
++#
++# - code was made position-independent;
++# - rounds were folded into a loop resulting in >5x size reduction
++#   from 12.5KB to 2.2KB;
++# - above was possibile thanks to mixcolumns() modification that
++#   allowed to feed its output back to aesenc[last], this was
++#   achieved at cost of two additional inter-registers moves;
++# - some instruction reordering and interleaving;
++# - this module doesn't implement key setup subroutine, instead it
++#   relies on conversion of "conventional" key schedule as returned
++#   by AES_set_encrypt_key (see discussion below);
++# - first and last round keys are treated differently, which allowed
++#   to skip one shiftrows(), reduce bit-sliced key schedule and
++#   speed-up conversion by 22%;
++# - support for 192- and 256-bit keys was added;
++#
++# Resulting performance in CPU cycles spent to encrypt one byte out
++# of 4096-byte buffer with 128-bit key is:
++#
++#		Emilia's	this(*)		difference
++#
++# Core 2    	9.30		8.69		+7%
++# Nehalem(**) 	7.63		6.88		+11%
++# Atom	    	17.1		16.4		+4%
++# Silvermont	-		12.9
++# Goldmont	-		8.85
++#
++# (*)	Comparison is not completely fair, because "this" is ECB,
++#	i.e. no extra processing such as counter values calculation
++#	and xor-ing input as in Emilia's CTR implementation is
++#	performed. However, the CTR calculations stand for not more
++#	than 1% of total time, so comparison is *rather* fair.
++#
++# (**)	Results were collected on Westmere, which is considered to
++#	be equivalent to Nehalem for this code.
++#
++# As for key schedule conversion subroutine. Interface to OpenSSL
++# relies on per-invocation on-the-fly conversion. This naturally
++# has impact on performance, especially for short inputs. Conversion
++# time in CPU cycles and its ratio to CPU cycles spent in 8x block
++# function is:
++#
++# 		conversion	conversion/8x block
++# Core 2	240		0.22
++# Nehalem	180		0.20
++# Atom		430		0.20
++#
++# The ratio values mean that 128-byte blocks will be processed
++# 16-18% slower, 256-byte blocks - 9-10%, 384-byte blocks - 6-7%,
++# etc. Then keep in mind that input sizes not divisible by 128 are
++# *effectively* slower, especially shortest ones, e.g. consecutive
++# 144-byte blocks are processed 44% slower than one would expect,
++# 272 - 29%, 400 - 22%, etc. Yet, despite all these "shortcomings"
++# it's still faster than ["hyper-threading-safe" code path in]
++# aes-x86_64.pl on all lengths above 64 bytes...
++#
++# October 2011.
++#
++# Add decryption procedure. Performance in CPU cycles spent to decrypt
++# one byte out of 4096-byte buffer with 128-bit key is:
++#
++# Core 2	9.98
++# Nehalem	7.80
++# Atom		17.9
++# Silvermont	14.0
++# Goldmont	10.2
++#
++# November 2011.
++#
++# Add bsaes_xts_[en|de]crypt. Less-than-80-bytes-block performance is
++# suboptimal, but XTS is meant to be used with larger blocks...
++#
++#						
++
++$flavour = shift;
++$output  = shift;
++if ($flavour =~ /\./) { $output = $flavour; undef $flavour; }
++
++$win64=0; $win64=1 if ($flavour =~ /[nm]asm|mingw64/ || $output =~ /\.asm$/);
++
++$0 =~ m/(.*[\/\\])[^\/\\]+$/; $dir=$1;
++( $xlate="${dir}x86_64-xlate.pl" and -f $xlate ) or
++( $xlate="${dir}../../perlasm/x86_64-xlate.pl" and -f $xlate) or
++die "can't locate x86_64-xlate.pl";
++
++open OUT,"| \"$^X\" \"$xlate\" $flavour \"$output\"";
++*STDOUT=*OUT;
++
++my ($inp,$out,$len,$key,$ivp)=("%rdi","%rsi","%rdx","%rcx");
++my @XMM=map("%xmm$_",(15,0..14));	# best on Atom, +10% over (0..15)
++my $ecb=0;	# suppress unreferenced ECB subroutines, spare some space...
++
++{
++my ($key,$rounds,$const)=("%rax","%r10d","%r11");
++
++sub Sbox {
++# input in  lsb > [b0, b1, b2, b3, b4, b5, b6, b7] < msb
++# output in lsb > [b0, b1, b4, b6, b3, b7, b2, b5] < msb
++my @b=@_[0..7];
++my @t=@_[8..11];
++my @s=@_[12..15];
++	&InBasisChange	(@b);
++	&Inv_GF256	(@b[6,5,0,3,7,1,4,2],@t,@s);
++	&OutBasisChange	(@b[7,1,4,2,6,5,0,3]);
++}
++
++sub InBasisChange {
++# input in  lsb > [b0, b1, b2, b3, b4, b5, b6, b7] < msb
++# output in lsb > [b6, b5, b0, b3, b7, b1, b4, b2] < msb 
++my @b=@_[0..7];
++$code.=<<___;
++	pxor	@b[6], @b[5]
++	pxor	@b[1], @b[2]
++	pxor	@b[0], @b[3]
++	pxor	@b[2], @b[6]
++	pxor 	@b[0], @b[5]
++
++	pxor	@b[3], @b[6]
++	pxor	@b[7], @b[3]
++	pxor	@b[5], @b[7]
++	pxor	@b[4], @b[3]
++	pxor	@b[5], @b[4]
++	pxor	@b[1], @b[3]
++
++	pxor	@b[7], @b[2]
++	pxor	@b[5], @b[1]
++___
++}
++
++sub OutBasisChange {
++# input in  lsb > [b0, b1, b2, b3, b4, b5, b6, b7] < msb
++# output in lsb > [b6, b1, b2, b4, b7, b0, b3, b5] < msb
++my @b=@_[0..7];
++$code.=<<___;
++	pxor	@b[6], @b[0]
++	pxor	@b[4], @b[1]
++	pxor	@b[0], @b[2]
++	pxor	@b[6], @b[4]
++	pxor	@b[1], @b[6]
++
++	pxor	@b[5], @b[1]
++	pxor	@b[3], @b[5]
++	pxor	@b[7], @b[3]
++	pxor	@b[5], @b[7]
++	pxor	@b[5], @b[2]
++
++	pxor	@b[7], @b[4]
++___
++}
++
++sub InvSbox {
++# input in lsb 	> [b0, b1, b2, b3, b4, b5, b6, b7] < msb
++# output in lsb	> [b0, b1, b6, b4, b2, b7, b3, b5] < msb
++my @b=@_[0..7];
++my @t=@_[8..11];
++my @s=@_[12..15];
++	&InvInBasisChange	(@b);
++	&Inv_GF256		(@b[5,1,2,6,3,7,0,4],@t,@s);
++	&InvOutBasisChange	(@b[3,7,0,4,5,1,2,6]);
++}
++
++sub InvInBasisChange {		# OutBasisChange in reverse
++my @b=@_[5,1,2,6,3,7,0,4];
++$code.=<<___
++	pxor	@b[7], @b[4]
++
++	pxor	@b[5], @b[7]
++	pxor	@b[5], @b[2]
++	pxor	@b[7], @b[3]
++	pxor	@b[3], @b[5]
++	pxor	@b[5], @b[1]
++
++	pxor	@b[1], @b[6]
++	pxor	@b[0], @b[2]
++	pxor	@b[6], @b[4]
++	pxor	@b[6], @b[0]
++	pxor	@b[4], @b[1]
++___
++}
++
++sub InvOutBasisChange {		# InBasisChange in reverse
++my @b=@_[2,5,7,3,6,1,0,4];
++$code.=<<___;
++	pxor	@b[5], @b[1]
++	pxor	@b[7], @b[2]
++
++	pxor	@b[1], @b[3]
++	pxor	@b[5], @b[4]
++	pxor	@b[5], @b[7]
++	pxor	@b[4], @b[3]
++	 pxor 	@b[0], @b[5]
++	pxor	@b[7], @b[3]
++	 pxor	@b[2], @b[6]
++	 pxor	@b[1], @b[2]
++	pxor	@b[3], @b[6]
++
++	pxor	@b[0], @b[3]
++	pxor	@b[6], @b[5]
++___
++}
++
++sub Mul_GF4 {
++#;*************************************************************
++#;* Mul_GF4: Input x0-x1,y0-y1 Output x0-x1 Temp t0 (8) *
++#;*************************************************************
++my ($x0,$x1,$y0,$y1,$t0)=@_;
++$code.=<<___;
++	movdqa	$y0, $t0
++	pxor 	$y1, $t0
++	pand	$x0, $t0
++	pxor	$x1, $x0
++	pand	$y0, $x1
++	pand	$y1, $x0
++	pxor	$x1, $x0
++	pxor	$t0, $x1
++___
++}
++
++sub Mul_GF4_N {				# not used, see next subroutine
++# multiply and scale by N
++my ($x0,$x1,$y0,$y1,$t0)=@_;
++$code.=<<___;
++	movdqa	$y0, $t0
++	pxor	$y1, $t0
++	pand	$x0, $t0
++	pxor	$x1, $x0
++	pand	$y0, $x1
++	pand	$y1, $x0
++	pxor	$x0, $x1
++	pxor	$t0, $x0
++___
++}
++
++sub Mul_GF4_N_GF4 {
++# interleaved Mul_GF4_N and Mul_GF4
++my ($x0,$x1,$y0,$y1,$t0,
++    $x2,$x3,$y2,$y3,$t1)=@_;
++$code.=<<___;
++	movdqa	$y0, $t0
++	 movdqa	$y2, $t1
++	pxor	$y1, $t0
++	 pxor 	$y3, $t1
++	pand	$x0, $t0
++	 pand	$x2, $t1
++	pxor	$x1, $x0
++	 pxor	$x3, $x2
++	pand	$y0, $x1
++	 pand	$y2, $x3
++	pand	$y1, $x0
++	 pand	$y3, $x2
++	pxor	$x0, $x1
++	 pxor	$x3, $x2
++	pxor	$t0, $x0
++	 pxor	$t1, $x3
++___
++}
++sub Mul_GF16_2 {
++my @x=@_[0..7];
++my @y=@_[8..11];
++my @t=@_[12..15];
++$code.=<<___;
++	movdqa	@x[0], @t[0]
++	movdqa	@x[1], @t[1]
++___
++	&Mul_GF4  	(@x[0], @x[1], @y[0], @y[1], @t[2]);
++$code.=<<___;
++	pxor	@x[2], @t[0]
++	pxor	@x[3], @t[1]
++	pxor	@y[2], @y[0]
++	pxor	@y[3], @y[1]
++___
++	Mul_GF4_N_GF4	(@t[0], @t[1], @y[0], @y[1], @t[3],
++			 @x[2], @x[3], @y[2], @y[3], @t[2]);
++$code.=<<___;
++	pxor	@t[0], @x[0]
++	pxor	@t[0], @x[2]
++	pxor	@t[1], @x[1]
++	pxor	@t[1], @x[3]
++
++	movdqa	@x[4], @t[0]
++	movdqa	@x[5], @t[1]
++	pxor	@x[6], @t[0]
++	pxor	@x[7], @t[1]
++___
++	&Mul_GF4_N_GF4	(@t[0], @t[1], @y[0], @y[1], @t[3],
++			 @x[6], @x[7], @y[2], @y[3], @t[2]);
++$code.=<<___;
++	pxor	@y[2], @y[0]
++	pxor	@y[3], @y[1]
++___
++	&Mul_GF4  	(@x[4], @x[5], @y[0], @y[1], @t[3]);
++$code.=<<___;
++	pxor	@t[0], @x[4]
++	pxor	@t[0], @x[6]
++	pxor	@t[1], @x[5]
++	pxor	@t[1], @x[7]
++___
++}
++sub Inv_GF256 {
++#;********************************************************************
++#;* Inv_GF256: Input x0-x7 Output x0-x7 Temp t0-t3,s0-s3 (144)       *
++#;********************************************************************
++my @x=@_[0..7];
++my @t=@_[8..11];
++my @s=@_[12..15];
++# direct optimizations from hardware
++$code.=<<___;
++	movdqa	@x[4], @t[3]
++	movdqa	@x[5], @t[2]
++	movdqa	@x[1], @t[1]
++	movdqa	@x[7], @s[1]
++	movdqa	@x[0], @s[0]
++
++	pxor	@x[6], @t[3]
++	pxor	@x[7], @t[2]
++	pxor	@x[3], @t[1]
++	 movdqa	@t[3], @s[2]
++	pxor	@x[6], @s[1]
++	 movdqa	@t[2], @t[0]
++	pxor	@x[2], @s[0]
++	 movdqa	@t[3], @s[3]
++
++	por	@t[1], @t[2]
++	por	@s[0], @t[3]
++	pxor	@t[0], @s[3]
++	pand	@s[0], @s[2]
++	pxor	@t[1], @s[0]
++	pand	@t[1], @t[0]
++	pand	@s[0], @s[3]
++	movdqa	@x[3], @s[0]
++	pxor	@x[2], @s[0]
++	pand	@s[0], @s[1]
++	pxor	@s[1], @t[3]
++	pxor	@s[1], @t[2]
++	movdqa	@x[4], @s[1]
++	movdqa	@x[1], @s[0]
++	pxor	@x[5], @s[1]
++	pxor	@x[0], @s[0]
++	movdqa	@s[1], @t[1]
++	pand	@s[0], @s[1]
++	por	@s[0], @t[1]
++	pxor	@s[1], @t[0]
++	pxor	@s[3], @t[3]
++	pxor	@s[2], @t[2]
++	pxor	@s[3], @t[1]
++	movdqa	@x[7], @s[0]
++	pxor	@s[2], @t[0]
++	movdqa	@x[6], @s[1]
++	pxor	@s[2], @t[1]
++	movdqa	@x[5], @s[2]
++	pand	@x[3], @s[0]
++	movdqa	@x[4], @s[3]
++	pand	@x[2], @s[1]
++	pand	@x[1], @s[2]
++	por	@x[0], @s[3]
++	pxor	@s[0], @t[3]
++	pxor	@s[1], @t[2]
++	pxor	@s[2], @t[1]
++	pxor	@s[3], @t[0] 
++
++	#Inv_GF16 \t0, \t1, \t2, \t3, \s0, \s1, \s2, \s3
++
++	# new smaller inversion
++
++	movdqa	@t[3], @s[0]
++	pand	@t[1], @t[3]
++	pxor	@t[2], @s[0]
++
++	movdqa	@t[0], @s[2]
++	movdqa	@s[0], @s[3]
++	pxor	@t[3], @s[2]
++	pand	@s[2], @s[3]
++
++	movdqa	@t[1], @s[1]
++	pxor	@t[2], @s[3]
++	pxor	@t[0], @s[1]
++
++	pxor	@t[2], @t[3]
++
++	pand	@t[3], @s[1]
++
++	movdqa	@s[2], @t[2]
++	pxor	@t[0], @s[1]
++
++	pxor	@s[1], @t[2]
++	pxor	@s[1], @t[1]
++
++	pand	@t[0], @t[2]
++
++	pxor	@t[2], @s[2]
++	pxor	@t[2], @t[1]
++
++	pand	@s[3], @s[2]
++
++	pxor	@s[0], @s[2]
++___
++# output in s3, s2, s1, t1
++
++# Mul_GF16_2 \x0, \x1, \x2, \x3, \x4, \x5, \x6, \x7, \t2, \t3, \t0, \t1, \s0, \s1, \s2, \s3
++
++# Mul_GF16_2 \x0, \x1, \x2, \x3, \x4, \x5, \x6, \x7, \s3, \s2, \s1, \t1, \s0, \t0, \t2, \t3
++	&Mul_GF16_2(@x,@s[3,2,1],@t[1],@s[0],@t[0,2,3]);
++
++### output msb > [x3,x2,x1,x0,x7,x6,x5,x4] < lsb
++}
++
++# AES linear components
++
++sub ShiftRows {
++my @x=@_[0..7];
++my $mask=pop;
++$code.=<<___;
++	pxor	0x00($key),@x[0]
++	pxor	0x10($key),@x[1]
++	pxor	0x20($key),@x[2]
++	pxor	0x30($key),@x[3]
++	pshufb	$mask,@x[0]
++	pshufb	$mask,@x[1]
++	pxor	0x40($key),@x[4]
++	pxor	0x50($key),@x[5]
++	pshufb	$mask,@x[2]
++	pshufb	$mask,@x[3]
++	pxor	0x60($key),@x[6]
++	pxor	0x70($key),@x[7]
++	pshufb	$mask,@x[4]
++	pshufb	$mask,@x[5]
++	pshufb	$mask,@x[6]
++	pshufb	$mask,@x[7]
++	lea	0x80($key),$key
++___
++}
++
++sub MixColumns {
++# modified to emit output in order suitable for feeding back to aesenc[last]
++my @x=@_[0..7];
++my @t=@_[8..15];
++my $inv=@_[16];	# optional
++$code.=<<___;
++	pshufd	\$0x93, @x[0], @t[0]	# x0 <<< 32
++	pshufd	\$0x93, @x[1], @t[1]
++	 pxor	@t[0], @x[0]		# x0 ^ (x0 <<< 32)
++	pshufd	\$0x93, @x[2], @t[2]
++	 pxor	@t[1], @x[1]
++	pshufd	\$0x93, @x[3], @t[3]
++	 pxor	@t[2], @x[2]
++	pshufd	\$0x93, @x[4], @t[4]
++	 pxor	@t[3], @x[3]
++	pshufd	\$0x93, @x[5], @t[5]
++	 pxor	@t[4], @x[4]
++	pshufd	\$0x93, @x[6], @t[6]
++	 pxor	@t[5], @x[5]
++	pshufd	\$0x93, @x[7], @t[7]
++	 pxor	@t[6], @x[6]
++	 pxor	@t[7], @x[7]
++
++	pxor	@x[0], @t[1]
++	pxor	@x[7], @t[0]
++	pxor	@x[7], @t[1]
++	 pshufd	\$0x4E, @x[0], @x[0] 	# (x0 ^ (x0 <<< 32)) <<< 64)
++	pxor	@x[1], @t[2]
++	 pshufd	\$0x4E, @x[1], @x[1]
++	pxor	@x[4], @t[5]
++	 pxor	@t[0], @x[0]
++	pxor	@x[5], @t[6]
++	 pxor	@t[1], @x[1]
++	pxor	@x[3], @t[4]
++	 pshufd	\$0x4E, @x[4], @t[0]
++	pxor	@x[6], @t[7]
++	 pshufd	\$0x4E, @x[5], @t[1]
++	pxor	@x[2], @t[3]
++	 pshufd	\$0x4E, @x[3], @x[4]
++	pxor	@x[7], @t[3]
++	 pshufd	\$0x4E, @x[7], @x[5]
++	pxor	@x[7], @t[4]
++	 pshufd	\$0x4E, @x[6], @x[3]
++	pxor	@t[4], @t[0]
++	 pshufd	\$0x4E, @x[2], @x[6]
++	pxor	@t[5], @t[1]
++___
++$code.=<<___ if (!$inv);
++	pxor	@t[3], @x[4]
++	pxor	@t[7], @x[5]
++	pxor	@t[6], @x[3]
++	 movdqa	@t[0], @x[2]
++	pxor	@t[2], @x[6]
++	 movdqa	@t[1], @x[7]
++___
++$code.=<<___ if ($inv);
++	pxor	@x[4], @t[3]
++	pxor	@t[7], @x[5]
++	pxor	@x[3], @t[6]
++	 movdqa	@t[0], @x[3]
++	pxor	@t[2], @x[6]
++	 movdqa	@t[6], @x[2]
++	 movdqa	@t[1], @x[7]
++	 movdqa	@x[6], @x[4]
++	 movdqa	@t[3], @x[6]
++___
++}
++
++sub InvMixColumns_orig {
++my @x=@_[0..7];
++my @t=@_[8..15];
++
++$code.=<<___;
++	# multiplication by 0x0e
++	pshufd	\$0x93, @x[7], @t[7]
++	movdqa	@x[2], @t[2]
++	pxor	@x[5], @x[7]		# 7 5
++	pxor	@x[5], @x[2]		# 2 5
++	pshufd	\$0x93, @x[0], @t[0]
++	movdqa	@x[5], @t[5]
++	pxor	@x[0], @x[5]		# 5 0		[1]
++	pxor	@x[1], @x[0]		# 0 1
++	pshufd	\$0x93, @x[1], @t[1]
++	pxor	@x[2], @x[1]		# 1 25
++	pxor	@x[6], @x[0]		# 01 6		[2]
++	pxor	@x[3], @x[1]		# 125 3		[4]
++	pshufd	\$0x93, @x[3], @t[3]
++	pxor	@x[0], @x[2]		# 25 016	[3]
++	pxor	@x[7], @x[3]		# 3 75
++	pxor	@x[6], @x[7]		# 75 6		[0]
++	pshufd	\$0x93, @x[6], @t[6]
++	movdqa	@x[4], @t[4]
++	pxor	@x[4], @x[6]		# 6 4
++	pxor	@x[3], @x[4]		# 4 375		[6]
++	pxor	@x[7], @x[3]		# 375 756=36
++	pxor	@t[5], @x[6]		# 64 5		[7]
++	pxor	@t[2], @x[3]		# 36 2
++	pxor	@t[4], @x[3]		# 362 4		[5]
++	pshufd	\$0x93, @t[5], @t[5]
++___
++					my @y = @x[7,5,0,2,1,3,4,6];
++$code.=<<___;
++	# multiplication by 0x0b
++	pxor	@y[0], @y[1]
++	pxor	@t[0], @y[0]
++	pxor	@t[1], @y[1]
++	pshufd	\$0x93, @t[2], @t[2]
++	pxor	@t[5], @y[0]
++	pxor	@t[6], @y[1]
++	pxor	@t[7], @y[0]
++	pshufd	\$0x93, @t[4], @t[4]
++	pxor	@t[6], @t[7]		# clobber t[7]
++	pxor	@y[0], @y[1]
++
++	pxor	@t[0], @y[3]
++	pshufd	\$0x93, @t[0], @t[0]
++	pxor	@t[1], @y[2]
++	pxor	@t[1], @y[4]
++	pxor	@t[2], @y[2]
++	pshufd	\$0x93, @t[1], @t[1]
++	pxor	@t[2], @y[3]
++	pxor	@t[2], @y[5]
++	pxor	@t[7], @y[2]
++	pshufd	\$0x93, @t[2], @t[2]
++	pxor	@t[3], @y[3]
++	pxor	@t[3], @y[6]
++	pxor	@t[3], @y[4]
++	pshufd	\$0x93, @t[3], @t[3]
++	pxor	@t[4], @y[7]
++	pxor	@t[4], @y[5]
++	pxor	@t[7], @y[7]
++	pxor	@t[5], @y[3]
++	pxor	@t[4], @y[4]
++	pxor	@t[5], @t[7]		# clobber t[7] even more
++
++	pxor	@t[7], @y[5]
++	pshufd	\$0x93, @t[4], @t[4]
++	pxor	@t[7], @y[6]
++	pxor	@t[7], @y[4]
++
++	pxor	@t[5], @t[7]
++	pshufd	\$0x93, @t[5], @t[5]
++	pxor	@t[6], @t[7]		# restore t[7]
++
++	# multiplication by 0x0d
++	pxor	@y[7], @y[4]
++	pxor	@t[4], @y[7]
++	pshufd	\$0x93, @t[6], @t[6]
++	pxor	@t[0], @y[2]
++	pxor	@t[5], @y[7]
++	pxor	@t[2], @y[2]
++	pshufd	\$0x93, @t[7], @t[7]
++
++	pxor	@y[1], @y[3]
++	pxor	@t[1], @y[1]
++	pxor	@t[0], @y[0]
++	pxor	@t[0], @y[3]
++	pxor	@t[5], @y[1]
++	pxor	@t[5], @y[0]
++	pxor	@t[7], @y[1]
++	pshufd	\$0x93, @t[0], @t[0]
++	pxor	@t[6], @y[0]
++	pxor	@y[1], @y[3]
++	pxor	@t[1], @y[4]
++	pshufd	\$0x93, @t[1], @t[1]
++
++	pxor	@t[7], @y[7]
++	pxor	@t[2], @y[4]
++	pxor	@t[2], @y[5]
++	pshufd	\$0x93, @t[2], @t[2]
++	pxor	@t[6], @y[2]
++	pxor	@t[3], @t[6]		# clobber t[6]
++	pxor	@y[7], @y[4]
++	pxor	@t[6], @y[3]
++
++	pxor	@t[6], @y[6]
++	pxor	@t[5], @y[5]
++	pxor	@t[4], @y[6]
++	pshufd	\$0x93, @t[4], @t[4]
++	pxor	@t[6], @y[5]
++	pxor	@t[7], @y[6]
++	pxor	@t[3], @t[6]		# restore t[6]
++
++	pshufd	\$0x93, @t[5], @t[5]
++	pshufd	\$0x93, @t[6], @t[6]
++	pshufd	\$0x93, @t[7], @t[7]
++	pshufd	\$0x93, @t[3], @t[3]
++
++	# multiplication by 0x09
++	pxor	@y[1], @y[4]
++	pxor	@y[1], @t[1]		# t[1]=y[1]
++	pxor	@t[5], @t[0]		# clobber t[0]
++	pxor	@t[5], @t[1]
++	pxor	@t[0], @y[3]
++	pxor	@y[0], @t[0]		# t[0]=y[0]
++	pxor	@t[6], @t[1]
++	pxor	@t[7], @t[6]		# clobber t[6]
++	pxor	@t[1], @y[4]
++	pxor	@t[4], @y[7]
++	pxor	@y[4], @t[4]		# t[4]=y[4]
++	pxor	@t[3], @y[6]
++	pxor	@y[3], @t[3]		# t[3]=y[3]
++	pxor	@t[2], @y[5]
++	pxor	@y[2], @t[2]		# t[2]=y[2]
++	pxor	@t[7], @t[3]
++	pxor	@y[5], @t[5]		# t[5]=y[5]
++	pxor	@t[6], @t[2]
++	pxor	@t[6], @t[5]
++	pxor	@y[6], @t[6]		# t[6]=y[6]
++	pxor	@y[7], @t[7]		# t[7]=y[7]
++
++	movdqa	@t[0],@XMM[0]
++	movdqa	@t[1],@XMM[1]
++	movdqa	@t[2],@XMM[2]
++	movdqa	@t[3],@XMM[3]
++	movdqa	@t[4],@XMM[4]
++	movdqa	@t[5],@XMM[5]
++	movdqa	@t[6],@XMM[6]
++	movdqa	@t[7],@XMM[7]
++___
++}
++
++sub InvMixColumns {
++my @x=@_[0..7];
++my @t=@_[8..15];
++
++# Thanks to Jussi Kivilinna for providing pointer to
++#
++# | 0e 0b 0d 09 |   | 02 03 01 01 |   | 05 00 04 00 |
++# | 09 0e 0b 0d | = | 01 02 03 01 | x | 00 05 00 04 |
++# | 0d 09 0e 0b |   | 01 01 02 03 |   | 04 00 05 00 |
++# | 0b 0d 09 0e |   | 03 01 01 02 |   | 00 04 00 05 |
++
++$code.=<<___;
++	# multiplication by 0x05-0x00-0x04-0x00
++	pshufd	\$0x4E, @x[0], @t[0]
++	pshufd	\$0x4E, @x[6], @t[6]
++	pxor	@x[0], @t[0]
++	pshufd	\$0x4E, @x[7], @t[7]
++	pxor	@x[6], @t[6]
++	pshufd	\$0x4E, @x[1], @t[1]
++	pxor	@x[7], @t[7]
++	pshufd	\$0x4E, @x[2], @t[2]
++	pxor	@x[1], @t[1]
++	pshufd	\$0x4E, @x[3], @t[3]
++	pxor	@x[2], @t[2]
++	 pxor	@t[6], @x[0]
++	 pxor	@t[6], @x[1]
++	pshufd	\$0x4E, @x[4], @t[4]
++	pxor	@x[3], @t[3]
++	 pxor	@t[0], @x[2]
++	 pxor	@t[1], @x[3]
++	pshufd	\$0x4E, @x[5], @t[5]
++	pxor	@x[4], @t[4]
++	 pxor	@t[7], @x[1]
++	 pxor	@t[2], @x[4]
++	pxor	@x[5], @t[5]
++
++	 pxor	@t[7], @x[2]
++	 pxor	@t[6], @x[3]
++	 pxor	@t[6], @x[4]
++	 pxor	@t[3], @x[5]
++	 pxor	@t[4], @x[6]
++	 pxor	@t[7], @x[4]
++	 pxor	@t[7], @x[5]
++	 pxor	@t[5], @x[7]
++___
++	&MixColumns	(@x,@t,1);	# flipped 2<->3 and 4<->6
++}
++
++sub aesenc {				# not used
++my @b=@_[0..7];
++my @t=@_[8..15];
++$code.=<<___;
++	movdqa	0x30($const),@t[0]	# .LSR
++___
++	&ShiftRows	(@b,@t[0]);
++	&Sbox		(@b,@t);
++	&MixColumns	(@b[0,1,4,6,3,7,2,5],@t);
++}
++
++sub aesenclast {			# not used
++my @b=@_[0..7];
++my @t=@_[8..15];
++$code.=<<___;
++	movdqa	0x40($const),@t[0]	# .LSRM0
++___
++	&ShiftRows	(@b,@t[0]);
++	&Sbox		(@b,@t);
++$code.=<<___
++	pxor	0x00($key),@b[0]
++	pxor	0x10($key),@b[1]
++	pxor	0x20($key),@b[4]
++	pxor	0x30($key),@b[6]
++	pxor	0x40($key),@b[3]
++	pxor	0x50($key),@b[7]
++	pxor	0x60($key),@b[2]
++	pxor	0x70($key),@b[5]
++___
++}
++
++sub swapmove {
++my ($a,$b,$n,$mask,$t)=@_;
++$code.=<<___;
++	movdqa	$b,$t
++	psrlq	\$$n,$b
++	pxor  	$a,$b
++	pand	$mask,$b
++	pxor	$b,$a
++	psllq	\$$n,$b
++	pxor	$t,$b
++___
++}
++sub swapmove2x {
++my ($a0,$b0,$a1,$b1,$n,$mask,$t0,$t1)=@_;
++$code.=<<___;
++	movdqa	$b0,$t0
++	psrlq	\$$n,$b0
++	 movdqa	$b1,$t1
++	 psrlq	\$$n,$b1
++	pxor  	$a0,$b0
++	 pxor  	$a1,$b1
++	pand	$mask,$b0
++	 pand	$mask,$b1
++	pxor	$b0,$a0
++	psllq	\$$n,$b0
++	 pxor	$b1,$a1
++	 psllq	\$$n,$b1
++	pxor	$t0,$b0
++	 pxor	$t1,$b1
++___
++}
++
++sub bitslice {
++my @x=reverse(@_[0..7]);
++my ($t0,$t1,$t2,$t3)=@_[8..11];
++$code.=<<___;
++	movdqa	0x00($const),$t0	# .LBS0
++	movdqa	0x10($const),$t1	# .LBS1
++___
++	&swapmove2x(@x[0,1,2,3],1,$t0,$t2,$t3);
++	&swapmove2x(@x[4,5,6,7],1,$t0,$t2,$t3);
++$code.=<<___;
++	movdqa	0x20($const),$t0	# .LBS2
++___
++	&swapmove2x(@x[0,2,1,3],2,$t1,$t2,$t3);
++	&swapmove2x(@x[4,6,5,7],2,$t1,$t2,$t3);
++
++	&swapmove2x(@x[0,4,1,5],4,$t0,$t2,$t3);
++	&swapmove2x(@x[2,6,3,7],4,$t0,$t2,$t3);
++}
++
++$code.=<<___;
++.text
++
++.extern	asm_AES_encrypt
++.extern	asm_AES_decrypt
++
++.type	_bsaes_encrypt8,\@abi-omnipotent
++.align	64
++_bsaes_encrypt8:
++	lea	.LBS0(%rip), $const	# constants table
++
++	movdqa	($key), @XMM[9]		# round 0 key
++	lea	0x10($key), $key
++	movdqa	0x50($const), @XMM[8]	# .LM0SR
++	pxor	@XMM[9], @XMM[0]	# xor with round0 key
++	pxor	@XMM[9], @XMM[1]
++	pxor	@XMM[9], @XMM[2]
++	pxor	@XMM[9], @XMM[3]
++	 pshufb	@XMM[8], @XMM[0]
++	 pshufb	@XMM[8], @XMM[1]
++	pxor	@XMM[9], @XMM[4]
++	pxor	@XMM[9], @XMM[5]
++	 pshufb	@XMM[8], @XMM[2]
++	 pshufb	@XMM[8], @XMM[3]
++	pxor	@XMM[9], @XMM[6]
++	pxor	@XMM[9], @XMM[7]
++	 pshufb	@XMM[8], @XMM[4]
++	 pshufb	@XMM[8], @XMM[5]
++	 pshufb	@XMM[8], @XMM[6]
++	 pshufb	@XMM[8], @XMM[7]
++_bsaes_encrypt8_bitslice:
++___
++	&bitslice	(@XMM[0..7, 8..11]);
++$code.=<<___;
++	dec	$rounds
++	jmp	.Lenc_sbox
++.align	16
++.Lenc_loop:
++___
++	&ShiftRows	(@XMM[0..7, 8]);
++$code.=".Lenc_sbox:\n";
++	&Sbox		(@XMM[0..7, 8..15]);
++$code.=<<___;
++	dec	$rounds
++	jl	.Lenc_done
++___
++	&MixColumns	(@XMM[0,1,4,6,3,7,2,5, 8..15]);
++$code.=<<___;
++	movdqa	0x30($const), @XMM[8]	# .LSR
++	jnz	.Lenc_loop
++	movdqa	0x40($const), @XMM[8]	# .LSRM0
++	jmp	.Lenc_loop
++.align	16
++.Lenc_done:
++___
++	# output in lsb > [t0, t1, t4, t6, t3, t7, t2, t5] < msb
++	&bitslice	(@XMM[0,1,4,6,3,7,2,5, 8..11]);
++$code.=<<___;
++	movdqa	($key), @XMM[8]		# last round key
++	pxor	@XMM[8], @XMM[4]
++	pxor	@XMM[8], @XMM[6]
++	pxor	@XMM[8], @XMM[3]
++	pxor	@XMM[8], @XMM[7]
++	pxor	@XMM[8], @XMM[2]
++	pxor	@XMM[8], @XMM[5]
++	pxor	@XMM[8], @XMM[0]
++	pxor	@XMM[8], @XMM[1]
++	ret
++.size	_bsaes_encrypt8,.-_bsaes_encrypt8
++
++.type	_bsaes_decrypt8,\@abi-omnipotent
++.align	64
++_bsaes_decrypt8:
++	lea	.LBS0(%rip), $const	# constants table
++
++	movdqa	($key), @XMM[9]		# round 0 key
++	lea	0x10($key), $key
++	movdqa	-0x30($const), @XMM[8]	# .LM0ISR
++	pxor	@XMM[9], @XMM[0]	# xor with round0 key
++	pxor	@XMM[9], @XMM[1]
++	pxor	@XMM[9], @XMM[2]
++	pxor	@XMM[9], @XMM[3]
++	 pshufb	@XMM[8], @XMM[0]
++	 pshufb	@XMM[8], @XMM[1]
++	pxor	@XMM[9], @XMM[4]
++	pxor	@XMM[9], @XMM[5]
++	 pshufb	@XMM[8], @XMM[2]
++	 pshufb	@XMM[8], @XMM[3]
++	pxor	@XMM[9], @XMM[6]
++	pxor	@XMM[9], @XMM[7]
++	 pshufb	@XMM[8], @XMM[4]
++	 pshufb	@XMM[8], @XMM[5]
++	 pshufb	@XMM[8], @XMM[6]
++	 pshufb	@XMM[8], @XMM[7]
++___
++	&bitslice	(@XMM[0..7, 8..11]);
++$code.=<<___;
++	dec	$rounds
++	jmp	.Ldec_sbox
++.align	16
++.Ldec_loop:
++___
++	&ShiftRows	(@XMM[0..7, 8]);
++$code.=".Ldec_sbox:\n";
++	&InvSbox	(@XMM[0..7, 8..15]);
++$code.=<<___;
++	dec	$rounds
++	jl	.Ldec_done
++___
++	&InvMixColumns	(@XMM[0,1,6,4,2,7,3,5, 8..15]);
++$code.=<<___;
++	movdqa	-0x10($const), @XMM[8]	# .LISR
++	jnz	.Ldec_loop
++	movdqa	-0x20($const), @XMM[8]	# .LISRM0
++	jmp	.Ldec_loop
++.align	16
++.Ldec_done:
++___
++	&bitslice	(@XMM[0,1,6,4,2,7,3,5, 8..11]);
++$code.=<<___;
++	movdqa	($key), @XMM[8]		# last round key
++	pxor	@XMM[8], @XMM[6]
++	pxor	@XMM[8], @XMM[4]
++	pxor	@XMM[8], @XMM[2]
++	pxor	@XMM[8], @XMM[7]
++	pxor	@XMM[8], @XMM[3]
++	pxor	@XMM[8], @XMM[5]
++	pxor	@XMM[8], @XMM[0]
++	pxor	@XMM[8], @XMM[1]
++	ret
++.size	_bsaes_decrypt8,.-_bsaes_decrypt8
++___
++}
++{
++my ($out,$inp,$rounds,$const)=("%rax","%rcx","%r10d","%r11");
++
++sub bitslice_key {
++my @x=reverse(@_[0..7]);
++my ($bs0,$bs1,$bs2,$t2,$t3)=@_[8..12];
++
++	&swapmove	(@x[0,1],1,$bs0,$t2,$t3);
++$code.=<<___;
++	#&swapmove(@x[2,3],1,$t0,$t2,$t3);
++	movdqa	@x[0], @x[2]
++	movdqa	@x[1], @x[3]
++___
++	#&swapmove2x(@x[4,5,6,7],1,$t0,$t2,$t3);
++
++	&swapmove2x	(@x[0,2,1,3],2,$bs1,$t2,$t3);
++$code.=<<___;
++	#&swapmove2x(@x[4,6,5,7],2,$t1,$t2,$t3);
++	movdqa	@x[0], @x[4]
++	movdqa	@x[2], @x[6]
++	movdqa	@x[1], @x[5]
++	movdqa	@x[3], @x[7]
++___
++	&swapmove2x	(@x[0,4,1,5],4,$bs2,$t2,$t3);
++	&swapmove2x	(@x[2,6,3,7],4,$bs2,$t2,$t3);
++}
++
++$code.=<<___;
++.type	_bsaes_key_convert,\@abi-omnipotent
++.align	16
++_bsaes_key_convert:
++	lea	.Lmasks(%rip), $const
++	movdqu	($inp), %xmm7		# load round 0 key
++	lea	0x10($inp), $inp
++	movdqa	0x00($const), %xmm0	# 0x01...
++	movdqa	0x10($const), %xmm1	# 0x02...
++	movdqa	0x20($const), %xmm2	# 0x04...
++	movdqa	0x30($const), %xmm3	# 0x08...
++	movdqa	0x40($const), %xmm4	# .LM0
++	pcmpeqd	%xmm5, %xmm5		# .LNOT
++
++	movdqu	($inp), %xmm6		# load round 1 key
++	movdqa	%xmm7, ($out)		# save round 0 key
++	lea	0x10($out), $out
++	dec	$rounds
++	jmp	.Lkey_loop
++.align	16
++.Lkey_loop:
++	pshufb	%xmm4, %xmm6		# .LM0
++
++	movdqa	%xmm0,	%xmm8
++	movdqa	%xmm1,	%xmm9
++
++	pand	%xmm6,	%xmm8
++	pand	%xmm6,	%xmm9
++	movdqa	%xmm2,	%xmm10
++	pcmpeqb	%xmm0,	%xmm8
++	psllq	\$4,	%xmm0		# 0x10...
++	movdqa	%xmm3,	%xmm11
++	pcmpeqb	%xmm1,	%xmm9
++	psllq	\$4,	%xmm1		# 0x20...
++
++	pand	%xmm6,	%xmm10
++	pand	%xmm6,	%xmm11
++	movdqa	%xmm0,	%xmm12
++	pcmpeqb	%xmm2,	%xmm10
++	psllq	\$4,	%xmm2		# 0x40...
++	movdqa	%xmm1,	%xmm13
++	pcmpeqb	%xmm3,	%xmm11
++	psllq	\$4,	%xmm3		# 0x80...
++
++	movdqa	%xmm2,	%xmm14
++	movdqa	%xmm3,	%xmm15
++	 pxor	%xmm5,	%xmm8		# "pnot"
++	 pxor	%xmm5,	%xmm9
++
++	pand	%xmm6,	%xmm12
++	pand	%xmm6,	%xmm13
++	 movdqa	%xmm8, 0x00($out)	# write bit-sliced round key
++	pcmpeqb	%xmm0,	%xmm12
++	psrlq	\$4,	%xmm0		# 0x01...
++	 movdqa	%xmm9, 0x10($out)
++	pcmpeqb	%xmm1,	%xmm13
++	psrlq	\$4,	%xmm1		# 0x02...
++	 lea	0x10($inp), $inp
++
++	pand	%xmm6,	%xmm14
++	pand	%xmm6,	%xmm15
++	 movdqa	%xmm10, 0x20($out)
++	pcmpeqb	%xmm2,	%xmm14
++	psrlq	\$4,	%xmm2		# 0x04...
++	 movdqa	%xmm11, 0x30($out)
++	pcmpeqb	%xmm3,	%xmm15
++	psrlq	\$4,	%xmm3		# 0x08...
++	 movdqu	($inp), %xmm6		# load next round key
++
++	pxor	%xmm5, %xmm13		# "pnot"
++	pxor	%xmm5, %xmm14
++	movdqa	%xmm12, 0x40($out)
++	movdqa	%xmm13, 0x50($out)
++	movdqa	%xmm14, 0x60($out)
++	movdqa	%xmm15, 0x70($out)
++	lea	0x80($out),$out
++	dec	$rounds
++	jnz	.Lkey_loop
++
++	movdqa	0x50($const), %xmm7	# .L63
++	#movdqa	%xmm6, ($out)		# don't save last round key
++	ret
++.size	_bsaes_key_convert,.-_bsaes_key_convert
++___
++}
++
++if (0 && !$win64) {	# following four functions are unsupported interface
++			# used for benchmarking...
++$code.=<<___;
++.globl	bsaes_enc_key_convert
++.type	bsaes_enc_key_convert,\@function,2
++.align	16
++bsaes_enc_key_convert:
++	mov	240($inp),%r10d		# pass rounds
++	mov	$inp,%rcx		# pass key
++	mov	$out,%rax		# pass key schedule
++	call	_bsaes_key_convert
++	pxor	%xmm6,%xmm7		# fix up last round key
++	movdqa	%xmm7,(%rax)		# save last round key
++	ret
++.size	bsaes_enc_key_convert,.-bsaes_enc_key_convert
++
++.globl	bsaes_encrypt_128
++.type	bsaes_encrypt_128,\@function,4
++.align	16
++bsaes_encrypt_128:
++.Lenc128_loop:
++	movdqu	0x00($inp), @XMM[0]	# load input
++	movdqu	0x10($inp), @XMM[1]
++	movdqu	0x20($inp), @XMM[2]
++	movdqu	0x30($inp), @XMM[3]
++	movdqu	0x40($inp), @XMM[4]
++	movdqu	0x50($inp), @XMM[5]
++	movdqu	0x60($inp), @XMM[6]
++	movdqu	0x70($inp), @XMM[7]
++	mov	$key, %rax		# pass the $key
++	lea	0x80($inp), $inp
++	mov	\$10,%r10d
++
++	call	_bsaes_encrypt8
++
++	movdqu	@XMM[0], 0x00($out)	# write output
++	movdqu	@XMM[1], 0x10($out)
++	movdqu	@XMM[4], 0x20($out)
++	movdqu	@XMM[6], 0x30($out)
++	movdqu	@XMM[3], 0x40($out)
++	movdqu	@XMM[7], 0x50($out)
++	movdqu	@XMM[2], 0x60($out)
++	movdqu	@XMM[5], 0x70($out)
++	lea	0x80($out), $out
++	sub	\$0x80,$len
++	ja	.Lenc128_loop
++	ret
++.size	bsaes_encrypt_128,.-bsaes_encrypt_128
++
++.globl	bsaes_dec_key_convert
++.type	bsaes_dec_key_convert,\@function,2
++.align	16
++bsaes_dec_key_convert:
++	mov	240($inp),%r10d		# pass rounds
++	mov	$inp,%rcx		# pass key
++	mov	$out,%rax		# pass key schedule
++	call	_bsaes_key_convert
++	pxor	($out),%xmm7		# fix up round 0 key
++	movdqa	%xmm6,(%rax)		# save last round key
++	movdqa	%xmm7,($out)
++	ret
++.size	bsaes_dec_key_convert,.-bsaes_dec_key_convert
++
++.globl	bsaes_decrypt_128
++.type	bsaes_decrypt_128,\@function,4
++.align	16
++bsaes_decrypt_128:
++.Ldec128_loop:
++	movdqu	0x00($inp), @XMM[0]	# load input
++	movdqu	0x10($inp), @XMM[1]
++	movdqu	0x20($inp), @XMM[2]
++	movdqu	0x30($inp), @XMM[3]
++	movdqu	0x40($inp), @XMM[4]
++	movdqu	0x50($inp), @XMM[5]
++	movdqu	0x60($inp), @XMM[6]
++	movdqu	0x70($inp), @XMM[7]
++	mov	$key, %rax		# pass the $key
++	lea	0x80($inp), $inp
++	mov	\$10,%r10d
++
++	call	_bsaes_decrypt8
++
++	movdqu	@XMM[0], 0x00($out)	# write output
++	movdqu	@XMM[1], 0x10($out)
++	movdqu	@XMM[6], 0x20($out)
++	movdqu	@XMM[4], 0x30($out)
++	movdqu	@XMM[2], 0x40($out)
++	movdqu	@XMM[7], 0x50($out)
++	movdqu	@XMM[3], 0x60($out)
++	movdqu	@XMM[5], 0x70($out)
++	lea	0x80($out), $out
++	sub	\$0x80,$len
++	ja	.Ldec128_loop
++	ret
++.size	bsaes_decrypt_128,.-bsaes_decrypt_128
++___
++}
++{
++######################################################################
++#
++# OpenSSL interface
++#
++my ($arg1,$arg2,$arg3,$arg4,$arg5,$arg6)=$win64	? ("%rcx","%rdx","%r8","%r9","%r10","%r11d")
++						: ("%rdi","%rsi","%rdx","%rcx","%r8","%r9d");
++my ($inp,$out,$len,$key)=("%r12","%r13","%r14","%r15");
++
++if ($ecb) {
++$code.=<<___;
++.globl	bsaes_ecb_encrypt_blocks
++.type	bsaes_ecb_encrypt_blocks,\@abi-omnipotent
++.align	16
++bsaes_ecb_encrypt_blocks:
++	mov	%rsp, %rax
++.Lecb_enc_prologue:
++	push	%rbp
++	push	%rbx
++	push	%r12
++	push	%r13
++	push	%r14
++	push	%r15
++	lea	-0x48(%rsp),%rsp
++___
++$code.=<<___ if ($win64);
++	lea	-0xa0(%rsp), %rsp
++	movaps	%xmm6, 0x40(%rsp)
++	movaps	%xmm7, 0x50(%rsp)
++	movaps	%xmm8, 0x60(%rsp)
++	movaps	%xmm9, 0x70(%rsp)
++	movaps	%xmm10, 0x80(%rsp)
++	movaps	%xmm11, 0x90(%rsp)
++	movaps	%xmm12, 0xa0(%rsp)
++	movaps	%xmm13, 0xb0(%rsp)
++	movaps	%xmm14, 0xc0(%rsp)
++	movaps	%xmm15, 0xd0(%rsp)
++.Lecb_enc_body:
++___
++$code.=<<___;
++	mov	%rsp,%rbp		# backup %rsp
++	mov	240($arg4),%eax		# rounds
++	mov	$arg1,$inp		# backup arguments
++	mov	$arg2,$out
++	mov	$arg3,$len
++	mov	$arg4,$key
++	cmp	\$8,$arg3
++	jb	.Lecb_enc_short
++
++	mov	%eax,%ebx		# backup rounds
++	shl	\$7,%rax		# 128 bytes per inner round key
++	sub	\$`128-32`,%rax		# size of bit-sliced key schedule
++	sub	%rax,%rsp
++	mov	%rsp,%rax		# pass key schedule
++	mov	$key,%rcx		# pass key
++	mov	%ebx,%r10d		# pass rounds
++	call	_bsaes_key_convert
++	pxor	%xmm6,%xmm7		# fix up last round key
++	movdqa	%xmm7,(%rax)		# save last round key
++
++	sub	\$8,$len
++.Lecb_enc_loop:
++	movdqu	0x00($inp), @XMM[0]	# load input
++	movdqu	0x10($inp), @XMM[1]
++	movdqu	0x20($inp), @XMM[2]
++	movdqu	0x30($inp), @XMM[3]
++	movdqu	0x40($inp), @XMM[4]
++	movdqu	0x50($inp), @XMM[5]
++	mov	%rsp, %rax		# pass key schedule
++	movdqu	0x60($inp), @XMM[6]
++	mov	%ebx,%r10d		# pass rounds
++	movdqu	0x70($inp), @XMM[7]
++	lea	0x80($inp), $inp
++
++	call	_bsaes_encrypt8
++
++	movdqu	@XMM[0], 0x00($out)	# write output
++	movdqu	@XMM[1], 0x10($out)
++	movdqu	@XMM[4], 0x20($out)
++	movdqu	@XMM[6], 0x30($out)
++	movdqu	@XMM[3], 0x40($out)
++	movdqu	@XMM[7], 0x50($out)
++	movdqu	@XMM[2], 0x60($out)
++	movdqu	@XMM[5], 0x70($out)
++	lea	0x80($out), $out
++	sub	\$8,$len
++	jnc	.Lecb_enc_loop
++
++	add	\$8,$len
++	jz	.Lecb_enc_done
++
++	movdqu	0x00($inp), @XMM[0]	# load input
++	mov	%rsp, %rax		# pass key schedule
++	mov	%ebx,%r10d		# pass rounds
++	cmp	\$2,$len
++	jb	.Lecb_enc_one
++	movdqu	0x10($inp), @XMM[1]
++	je	.Lecb_enc_two
++	movdqu	0x20($inp), @XMM[2]
++	cmp	\$4,$len
++	jb	.Lecb_enc_three
++	movdqu	0x30($inp), @XMM[3]
++	je	.Lecb_enc_four
++	movdqu	0x40($inp), @XMM[4]
++	cmp	\$6,$len
++	jb	.Lecb_enc_five
++	movdqu	0x50($inp), @XMM[5]
++	je	.Lecb_enc_six
++	movdqu	0x60($inp), @XMM[6]
++	call	_bsaes_encrypt8
++	movdqu	@XMM[0], 0x00($out)	# write output
++	movdqu	@XMM[1], 0x10($out)
++	movdqu	@XMM[4], 0x20($out)
++	movdqu	@XMM[6], 0x30($out)
++	movdqu	@XMM[3], 0x40($out)
++	movdqu	@XMM[7], 0x50($out)
++	movdqu	@XMM[2], 0x60($out)
++	jmp	.Lecb_enc_done
++.align	16
++.Lecb_enc_six:
++	call	_bsaes_encrypt8
++	movdqu	@XMM[0], 0x00($out)	# write output
++	movdqu	@XMM[1], 0x10($out)
++	movdqu	@XMM[4], 0x20($out)
++	movdqu	@XMM[6], 0x30($out)
++	movdqu	@XMM[3], 0x40($out)
++	movdqu	@XMM[7], 0x50($out)
++	jmp	.Lecb_enc_done
++.align	16
++.Lecb_enc_five:
++	call	_bsaes_encrypt8
++	movdqu	@XMM[0], 0x00($out)	# write output
++	movdqu	@XMM[1], 0x10($out)
++	movdqu	@XMM[4], 0x20($out)
++	movdqu	@XMM[6], 0x30($out)
++	movdqu	@XMM[3], 0x40($out)
++	jmp	.Lecb_enc_done
++.align	16
++.Lecb_enc_four:
++	call	_bsaes_encrypt8
++	movdqu	@XMM[0], 0x00($out)	# write output
++	movdqu	@XMM[1], 0x10($out)
++	movdqu	@XMM[4], 0x20($out)
++	movdqu	@XMM[6], 0x30($out)
++	jmp	.Lecb_enc_done
++.align	16
++.Lecb_enc_three:
++	call	_bsaes_encrypt8
++	movdqu	@XMM[0], 0x00($out)	# write output
++	movdqu	@XMM[1], 0x10($out)
++	movdqu	@XMM[4], 0x20($out)
++	jmp	.Lecb_enc_done
++.align	16
++.Lecb_enc_two:
++	call	_bsaes_encrypt8
++	movdqu	@XMM[0], 0x00($out)	# write output
++	movdqu	@XMM[1], 0x10($out)
++	jmp	.Lecb_enc_done
++.align	16
++.Lecb_enc_one:
++	call	_bsaes_encrypt8
++	movdqu	@XMM[0], 0x00($out)	# write output
++	jmp	.Lecb_enc_done
++.align	16
++.Lecb_enc_short:
++	lea	($inp), $arg1
++	lea	($out), $arg2
++	lea	($key), $arg3
++	call	asm_AES_encrypt
++	lea	16($inp), $inp
++	lea	16($out), $out
++	dec	$len
++	jnz	.Lecb_enc_short
++
++.Lecb_enc_done:
++	lea	(%rsp),%rax
++	pxor	%xmm0, %xmm0
++.Lecb_enc_bzero:			# wipe key schedule [if any]
++	movdqa	%xmm0, 0x00(%rax)
++	movdqa	%xmm0, 0x10(%rax)
++	lea	0x20(%rax), %rax
++	cmp	%rax, %rbp
++	jb	.Lecb_enc_bzero
++
++	lea	(%rbp),%rsp		# restore %rsp
++___
++$code.=<<___ if ($win64);
++	movaps	0x40(%rbp), %xmm6
++	movaps	0x50(%rbp), %xmm7
++	movaps	0x60(%rbp), %xmm8
++	movaps	0x70(%rbp), %xmm9
++	movaps	0x80(%rbp), %xmm10
++	movaps	0x90(%rbp), %xmm11
++	movaps	0xa0(%rbp), %xmm12
++	movaps	0xb0(%rbp), %xmm13
++	movaps	0xc0(%rbp), %xmm14
++	movaps	0xd0(%rbp), %xmm15
++	lea	0xa0(%rbp), %rsp
++___
++$code.=<<___;
++	mov	0x48(%rsp), %r15
++	mov	0x50(%rsp), %r14
++	mov	0x58(%rsp), %r13
++	mov	0x60(%rsp), %r12
++	mov	0x68(%rsp), %rbx
++	mov	0x70(%rsp), %rax
++	lea	0x78(%rsp), %rsp
++	mov	%rax, %rbp
++.Lecb_enc_epilogue:
++	ret
++.size	bsaes_ecb_encrypt_blocks,.-bsaes_ecb_encrypt_blocks
++
++.globl	bsaes_ecb_decrypt_blocks
++.type	bsaes_ecb_decrypt_blocks,\@abi-omnipotent
++.align	16
++bsaes_ecb_decrypt_blocks:
++	mov	%rsp, %rax
++.Lecb_dec_prologue:
++	push	%rbp
++	push	%rbx
++	push	%r12
++	push	%r13
++	push	%r14
++	push	%r15
++	lea	-0x48(%rsp),%rsp
++___
++$code.=<<___ if ($win64);
++	lea	-0xa0(%rsp), %rsp
++	movaps	%xmm6, 0x40(%rsp)
++	movaps	%xmm7, 0x50(%rsp)
++	movaps	%xmm8, 0x60(%rsp)
++	movaps	%xmm9, 0x70(%rsp)
++	movaps	%xmm10, 0x80(%rsp)
++	movaps	%xmm11, 0x90(%rsp)
++	movaps	%xmm12, 0xa0(%rsp)
++	movaps	%xmm13, 0xb0(%rsp)
++	movaps	%xmm14, 0xc0(%rsp)
++	movaps	%xmm15, 0xd0(%rsp)
++.Lecb_dec_body:
++___
++$code.=<<___;
++	mov	%rsp,%rbp		# backup %rsp
++	mov	240($arg4),%eax		# rounds
++	mov	$arg1,$inp		# backup arguments
++	mov	$arg2,$out
++	mov	$arg3,$len
++	mov	$arg4,$key
++	cmp	\$8,$arg3
++	jb	.Lecb_dec_short
++
++	mov	%eax,%ebx		# backup rounds
++	shl	\$7,%rax		# 128 bytes per inner round key
++	sub	\$`128-32`,%rax		# size of bit-sliced key schedule
++	sub	%rax,%rsp
++	mov	%rsp,%rax		# pass key schedule
++	mov	$key,%rcx		# pass key
++	mov	%ebx,%r10d		# pass rounds
++	call	_bsaes_key_convert
++	pxor	(%rsp),%xmm7		# fix up 0 round key
++	movdqa	%xmm6,(%rax)		# save last round key
++	movdqa	%xmm7,(%rsp)
++
++	sub	\$8,$len
++.Lecb_dec_loop:
++	movdqu	0x00($inp), @XMM[0]	# load input
++	movdqu	0x10($inp), @XMM[1]
++	movdqu	0x20($inp), @XMM[2]
++	movdqu	0x30($inp), @XMM[3]
++	movdqu	0x40($inp), @XMM[4]
++	movdqu	0x50($inp), @XMM[5]
++	mov	%rsp, %rax		# pass key schedule
++	movdqu	0x60($inp), @XMM[6]
++	mov	%ebx,%r10d		# pass rounds
++	movdqu	0x70($inp), @XMM[7]
++	lea	0x80($inp), $inp
++
++	call	_bsaes_decrypt8
++
++	movdqu	@XMM[0], 0x00($out)	# write output
++	movdqu	@XMM[1], 0x10($out)
++	movdqu	@XMM[6], 0x20($out)
++	movdqu	@XMM[4], 0x30($out)
++	movdqu	@XMM[2], 0x40($out)
++	movdqu	@XMM[7], 0x50($out)
++	movdqu	@XMM[3], 0x60($out)
++	movdqu	@XMM[5], 0x70($out)
++	lea	0x80($out), $out
++	sub	\$8,$len
++	jnc	.Lecb_dec_loop
++
++	add	\$8,$len
++	jz	.Lecb_dec_done
++
++	movdqu	0x00($inp), @XMM[0]	# load input
++	mov	%rsp, %rax		# pass key schedule
++	mov	%ebx,%r10d		# pass rounds
++	cmp	\$2,$len
++	jb	.Lecb_dec_one
++	movdqu	0x10($inp), @XMM[1]
++	je	.Lecb_dec_two
++	movdqu	0x20($inp), @XMM[2]
++	cmp	\$4,$len
++	jb	.Lecb_dec_three
++	movdqu	0x30($inp), @XMM[3]
++	je	.Lecb_dec_four
++	movdqu	0x40($inp), @XMM[4]
++	cmp	\$6,$len
++	jb	.Lecb_dec_five
++	movdqu	0x50($inp), @XMM[5]
++	je	.Lecb_dec_six
++	movdqu	0x60($inp), @XMM[6]
++	call	_bsaes_decrypt8
++	movdqu	@XMM[0], 0x00($out)	# write output
++	movdqu	@XMM[1], 0x10($out)
++	movdqu	@XMM[6], 0x20($out)
++	movdqu	@XMM[4], 0x30($out)
++	movdqu	@XMM[2], 0x40($out)
++	movdqu	@XMM[7], 0x50($out)
++	movdqu	@XMM[3], 0x60($out)
++	jmp	.Lecb_dec_done
++.align	16
++.Lecb_dec_six:
++	call	_bsaes_decrypt8
++	movdqu	@XMM[0], 0x00($out)	# write output
++	movdqu	@XMM[1], 0x10($out)
++	movdqu	@XMM[6], 0x20($out)
++	movdqu	@XMM[4], 0x30($out)
++	movdqu	@XMM[2], 0x40($out)
++	movdqu	@XMM[7], 0x50($out)
++	jmp	.Lecb_dec_done
++.align	16
++.Lecb_dec_five:
++	call	_bsaes_decrypt8
++	movdqu	@XMM[0], 0x00($out)	# write output
++	movdqu	@XMM[1], 0x10($out)
++	movdqu	@XMM[6], 0x20($out)
++	movdqu	@XMM[4], 0x30($out)
++	movdqu	@XMM[2], 0x40($out)
++	jmp	.Lecb_dec_done
++.align	16
++.Lecb_dec_four:
++	call	_bsaes_decrypt8
++	movdqu	@XMM[0], 0x00($out)	# write output
++	movdqu	@XMM[1], 0x10($out)
++	movdqu	@XMM[6], 0x20($out)
++	movdqu	@XMM[4], 0x30($out)
++	jmp	.Lecb_dec_done
++.align	16
++.Lecb_dec_three:
++	call	_bsaes_decrypt8
++	movdqu	@XMM[0], 0x00($out)	# write output
++	movdqu	@XMM[1], 0x10($out)
++	movdqu	@XMM[6], 0x20($out)
++	jmp	.Lecb_dec_done
++.align	16
++.Lecb_dec_two:
++	call	_bsaes_decrypt8
++	movdqu	@XMM[0], 0x00($out)	# write output
++	movdqu	@XMM[1], 0x10($out)
++	jmp	.Lecb_dec_done
++.align	16
++.Lecb_dec_one:
++	call	_bsaes_decrypt8
++	movdqu	@XMM[0], 0x00($out)	# write output
++	jmp	.Lecb_dec_done
++.align	16
++.Lecb_dec_short:
++	lea	($inp), $arg1
++	lea	($out), $arg2
++	lea	($key), $arg3
++	call	asm_AES_decrypt
++	lea	16($inp), $inp
++	lea	16($out), $out
++	dec	$len
++	jnz	.Lecb_dec_short
++
++.Lecb_dec_done:
++	lea	(%rsp),%rax
++	pxor	%xmm0, %xmm0
++.Lecb_dec_bzero:			# wipe key schedule [if any]
++	movdqa	%xmm0, 0x00(%rax)
++	movdqa	%xmm0, 0x10(%rax)
++	lea	0x20(%rax), %rax
++	cmp	%rax, %rbp
++	jb	.Lecb_dec_bzero
++
++	lea	(%rbp),%rsp		# restore %rsp
++___
++$code.=<<___ if ($win64);
++	movaps	0x40(%rbp), %xmm6
++	movaps	0x50(%rbp), %xmm7
++	movaps	0x60(%rbp), %xmm8
++	movaps	0x70(%rbp), %xmm9
++	movaps	0x80(%rbp), %xmm10
++	movaps	0x90(%rbp), %xmm11
++	movaps	0xa0(%rbp), %xmm12
++	movaps	0xb0(%rbp), %xmm13
++	movaps	0xc0(%rbp), %xmm14
++	movaps	0xd0(%rbp), %xmm15
++	lea	0xa0(%rbp), %rsp
++___
++$code.=<<___;
++	mov	0x48(%rsp), %r15
++	mov	0x50(%rsp), %r14
++	mov	0x58(%rsp), %r13
++	mov	0x60(%rsp), %r12
++	mov	0x68(%rsp), %rbx
++	mov	0x70(%rsp), %rax
++	lea	0x78(%rsp), %rsp
++	mov	%rax, %rbp
++.Lecb_dec_epilogue:
++	ret
++.size	bsaes_ecb_decrypt_blocks,.-bsaes_ecb_decrypt_blocks
++___
++}
++$code.=<<___;
++.extern	asm_AES_cbc_encrypt
++.globl	bsaes_cbc_encrypt
++.type	bsaes_cbc_encrypt,\@abi-omnipotent
++.align	16
++bsaes_cbc_encrypt:
++___
++$code.=<<___ if ($win64);
++	mov	48(%rsp),$arg6		# pull direction flag
++___
++$code.=<<___;
++	cmp	\$0,$arg6
++	jne	asm_AES_cbc_encrypt
++	cmp	\$128,$arg3
++	jb	asm_AES_cbc_encrypt
++
++	mov	%rsp, %rax
++.Lcbc_dec_prologue:
++	push	%rbp
++	push	%rbx
++	push	%r12
++	push	%r13
++	push	%r14
++	push	%r15
++	lea	-0x48(%rsp), %rsp
++___
++$code.=<<___ if ($win64);
++	mov	0xa0(%rsp),$arg5	# pull ivp
++	lea	-0xa0(%rsp), %rsp
++	movaps	%xmm6, 0x40(%rsp)
++	movaps	%xmm7, 0x50(%rsp)
++	movaps	%xmm8, 0x60(%rsp)
++	movaps	%xmm9, 0x70(%rsp)
++	movaps	%xmm10, 0x80(%rsp)
++	movaps	%xmm11, 0x90(%rsp)
++	movaps	%xmm12, 0xa0(%rsp)
++	movaps	%xmm13, 0xb0(%rsp)
++	movaps	%xmm14, 0xc0(%rsp)
++	movaps	%xmm15, 0xd0(%rsp)
++.Lcbc_dec_body:
++___
++$code.=<<___;
++	mov	%rsp, %rbp		# backup %rsp
++	mov	240($arg4), %eax	# rounds
++	mov	$arg1, $inp		# backup arguments
++	mov	$arg2, $out
++	mov	$arg3, $len
++	mov	$arg4, $key
++	mov	$arg5, %rbx
++	shr	\$4, $len		# bytes to blocks
++
++	mov	%eax, %edx		# rounds
++	shl	\$7, %rax		# 128 bytes per inner round key
++	sub	\$`128-32`, %rax	# size of bit-sliced key schedule
++	sub	%rax, %rsp
++
++	mov	%rsp, %rax		# pass key schedule
++	mov	$key, %rcx		# pass key
++	mov	%edx, %r10d		# pass rounds
++	call	_bsaes_key_convert
++	pxor	(%rsp),%xmm7		# fix up 0 round key
++	movdqa	%xmm6,(%rax)		# save last round key
++	movdqa	%xmm7,(%rsp)
++
++	movdqu	(%rbx), @XMM[15]	# load IV
++	sub	\$8,$len
++.Lcbc_dec_loop:
++	movdqu	0x00($inp), @XMM[0]	# load input
++	movdqu	0x10($inp), @XMM[1]
++	movdqu	0x20($inp), @XMM[2]
++	movdqu	0x30($inp), @XMM[3]
++	movdqu	0x40($inp), @XMM[4]
++	movdqu	0x50($inp), @XMM[5]
++	mov	%rsp, %rax		# pass key schedule
++	movdqu	0x60($inp), @XMM[6]
++	mov	%edx,%r10d		# pass rounds
++	movdqu	0x70($inp), @XMM[7]
++	movdqa	@XMM[15], 0x20(%rbp)	# put aside IV
++
++	call	_bsaes_decrypt8
++
++	pxor	0x20(%rbp), @XMM[0]	# ^= IV
++	movdqu	0x00($inp), @XMM[8]	# re-load input
++	movdqu	0x10($inp), @XMM[9]
++	pxor	@XMM[8], @XMM[1]
++	movdqu	0x20($inp), @XMM[10]
++	pxor	@XMM[9], @XMM[6]
++	movdqu	0x30($inp), @XMM[11]
++	pxor	@XMM[10], @XMM[4]
++	movdqu	0x40($inp), @XMM[12]
++	pxor	@XMM[11], @XMM[2]
++	movdqu	0x50($inp), @XMM[13]
++	pxor	@XMM[12], @XMM[7]
++	movdqu	0x60($inp), @XMM[14]
++	pxor	@XMM[13], @XMM[3]
++	movdqu	0x70($inp), @XMM[15]	# IV
++	pxor	@XMM[14], @XMM[5]
++	movdqu	@XMM[0], 0x00($out)	# write output
++	lea	0x80($inp), $inp
++	movdqu	@XMM[1], 0x10($out)
++	movdqu	@XMM[6], 0x20($out)
++	movdqu	@XMM[4], 0x30($out)
++	movdqu	@XMM[2], 0x40($out)
++	movdqu	@XMM[7], 0x50($out)
++	movdqu	@XMM[3], 0x60($out)
++	movdqu	@XMM[5], 0x70($out)
++	lea	0x80($out), $out
++	sub	\$8,$len
++	jnc	.Lcbc_dec_loop
++
++	add	\$8,$len
++	jz	.Lcbc_dec_done
++
++	movdqu	0x00($inp), @XMM[0]	# load input
++	mov	%rsp, %rax		# pass key schedule
++	mov	%edx, %r10d		# pass rounds
++	cmp	\$2,$len
++	jb	.Lcbc_dec_one
++	movdqu	0x10($inp), @XMM[1]
++	je	.Lcbc_dec_two
++	movdqu	0x20($inp), @XMM[2]
++	cmp	\$4,$len
++	jb	.Lcbc_dec_three
++	movdqu	0x30($inp), @XMM[3]
++	je	.Lcbc_dec_four
++	movdqu	0x40($inp), @XMM[4]
++	cmp	\$6,$len
++	jb	.Lcbc_dec_five
++	movdqu	0x50($inp), @XMM[5]
++	je	.Lcbc_dec_six
++	movdqu	0x60($inp), @XMM[6]
++	movdqa	@XMM[15], 0x20(%rbp)	# put aside IV
++	call	_bsaes_decrypt8
++	pxor	0x20(%rbp), @XMM[0]	# ^= IV
++	movdqu	0x00($inp), @XMM[8]	# re-load input
++	movdqu	0x10($inp), @XMM[9]
++	pxor	@XMM[8], @XMM[1]
++	movdqu	0x20($inp), @XMM[10]
++	pxor	@XMM[9], @XMM[6]
++	movdqu	0x30($inp), @XMM[11]
++	pxor	@XMM[10], @XMM[4]
++	movdqu	0x40($inp), @XMM[12]
++	pxor	@XMM[11], @XMM[2]
++	movdqu	0x50($inp), @XMM[13]
++	pxor	@XMM[12], @XMM[7]
++	movdqu	0x60($inp), @XMM[15]	# IV
++	pxor	@XMM[13], @XMM[3]
++	movdqu	@XMM[0], 0x00($out)	# write output
++	movdqu	@XMM[1], 0x10($out)
++	movdqu	@XMM[6], 0x20($out)
++	movdqu	@XMM[4], 0x30($out)
++	movdqu	@XMM[2], 0x40($out)
++	movdqu	@XMM[7], 0x50($out)
++	movdqu	@XMM[3], 0x60($out)
++	jmp	.Lcbc_dec_done
++.align	16
++.Lcbc_dec_six:
++	movdqa	@XMM[15], 0x20(%rbp)	# put aside IV
++	call	_bsaes_decrypt8
++	pxor	0x20(%rbp), @XMM[0]	# ^= IV
++	movdqu	0x00($inp), @XMM[8]	# re-load input
++	movdqu	0x10($inp), @XMM[9]
++	pxor	@XMM[8], @XMM[1]
++	movdqu	0x20($inp), @XMM[10]
++	pxor	@XMM[9], @XMM[6]
++	movdqu	0x30($inp), @XMM[11]
++	pxor	@XMM[10], @XMM[4]
++	movdqu	0x40($inp), @XMM[12]
++	pxor	@XMM[11], @XMM[2]
++	movdqu	0x50($inp), @XMM[15]	# IV
++	pxor	@XMM[12], @XMM[7]
++	movdqu	@XMM[0], 0x00($out)	# write output
++	movdqu	@XMM[1], 0x10($out)
++	movdqu	@XMM[6], 0x20($out)
++	movdqu	@XMM[4], 0x30($out)
++	movdqu	@XMM[2], 0x40($out)
++	movdqu	@XMM[7], 0x50($out)
++	jmp	.Lcbc_dec_done
++.align	16
++.Lcbc_dec_five:
++	movdqa	@XMM[15], 0x20(%rbp)	# put aside IV
++	call	_bsaes_decrypt8
++	pxor	0x20(%rbp), @XMM[0]	# ^= IV
++	movdqu	0x00($inp), @XMM[8]	# re-load input
++	movdqu	0x10($inp), @XMM[9]
++	pxor	@XMM[8], @XMM[1]
++	movdqu	0x20($inp), @XMM[10]
++	pxor	@XMM[9], @XMM[6]
++	movdqu	0x30($inp), @XMM[11]
++	pxor	@XMM[10], @XMM[4]
++	movdqu	0x40($inp), @XMM[15]	# IV
++	pxor	@XMM[11], @XMM[2]
++	movdqu	@XMM[0], 0x00($out)	# write output
++	movdqu	@XMM[1], 0x10($out)
++	movdqu	@XMM[6], 0x20($out)
++	movdqu	@XMM[4], 0x30($out)
++	movdqu	@XMM[2], 0x40($out)
++	jmp	.Lcbc_dec_done
++.align	16
++.Lcbc_dec_four:
++	movdqa	@XMM[15], 0x20(%rbp)	# put aside IV
++	call	_bsaes_decrypt8
++	pxor	0x20(%rbp), @XMM[0]	# ^= IV
++	movdqu	0x00($inp), @XMM[8]	# re-load input
++	movdqu	0x10($inp), @XMM[9]
++	pxor	@XMM[8], @XMM[1]
++	movdqu	0x20($inp), @XMM[10]
++	pxor	@XMM[9], @XMM[6]
++	movdqu	0x30($inp), @XMM[15]	# IV
++	pxor	@XMM[10], @XMM[4]
++	movdqu	@XMM[0], 0x00($out)	# write output
++	movdqu	@XMM[1], 0x10($out)
++	movdqu	@XMM[6], 0x20($out)
++	movdqu	@XMM[4], 0x30($out)
++	jmp	.Lcbc_dec_done
++.align	16
++.Lcbc_dec_three:
++	movdqa	@XMM[15], 0x20(%rbp)	# put aside IV
++	call	_bsaes_decrypt8
++	pxor	0x20(%rbp), @XMM[0]	# ^= IV
++	movdqu	0x00($inp), @XMM[8]	# re-load input
++	movdqu	0x10($inp), @XMM[9]
++	pxor	@XMM[8], @XMM[1]
++	movdqu	0x20($inp), @XMM[15]	# IV
++	pxor	@XMM[9], @XMM[6]
++	movdqu	@XMM[0], 0x00($out)	# write output
++	movdqu	@XMM[1], 0x10($out)
++	movdqu	@XMM[6], 0x20($out)
++	jmp	.Lcbc_dec_done
++.align	16
++.Lcbc_dec_two:
++	movdqa	@XMM[15], 0x20(%rbp)	# put aside IV
++	call	_bsaes_decrypt8
++	pxor	0x20(%rbp), @XMM[0]	# ^= IV
++	movdqu	0x00($inp), @XMM[8]	# re-load input
++	movdqu	0x10($inp), @XMM[15]	# IV
++	pxor	@XMM[8], @XMM[1]
++	movdqu	@XMM[0], 0x00($out)	# write output
++	movdqu	@XMM[1], 0x10($out)
++	jmp	.Lcbc_dec_done
++.align	16
++.Lcbc_dec_one:
++	lea	($inp), $arg1
++	lea	0x20(%rbp), $arg2	# buffer output
++	lea	($key), $arg3
++	call	asm_AES_decrypt		# doesn't touch %xmm
++	pxor	0x20(%rbp), @XMM[15]	# ^= IV
++	movdqu	@XMM[15], ($out)	# write output
++	movdqa	@XMM[0], @XMM[15]	# IV
++
++.Lcbc_dec_done:
++	movdqu	@XMM[15], (%rbx)	# return IV
++	lea	(%rsp), %rax
++	pxor	%xmm0, %xmm0
++.Lcbc_dec_bzero:			# wipe key schedule [if any]
++	movdqa	%xmm0, 0x00(%rax)
++	movdqa	%xmm0, 0x10(%rax)
++	lea	0x20(%rax), %rax
++	cmp	%rax, %rbp
++	ja	.Lcbc_dec_bzero
++
++	lea	(%rbp),%rsp		# restore %rsp
++___
++$code.=<<___ if ($win64);
++	movaps	0x40(%rbp), %xmm6
++	movaps	0x50(%rbp), %xmm7
++	movaps	0x60(%rbp), %xmm8
++	movaps	0x70(%rbp), %xmm9
++	movaps	0x80(%rbp), %xmm10
++	movaps	0x90(%rbp), %xmm11
++	movaps	0xa0(%rbp), %xmm12
++	movaps	0xb0(%rbp), %xmm13
++	movaps	0xc0(%rbp), %xmm14
++	movaps	0xd0(%rbp), %xmm15
++	lea	0xa0(%rbp), %rsp
++___
++$code.=<<___;
++	mov	0x48(%rsp), %r15
++	mov	0x50(%rsp), %r14
++	mov	0x58(%rsp), %r13
++	mov	0x60(%rsp), %r12
++	mov	0x68(%rsp), %rbx
++	mov	0x70(%rsp), %rax
++	lea	0x78(%rsp), %rsp
++	mov	%rax, %rbp
++.Lcbc_dec_epilogue:
++	ret
++.size	bsaes_cbc_encrypt,.-bsaes_cbc_encrypt
++
++.globl	bsaes_ctr32_encrypt_blocks
++.type	bsaes_ctr32_encrypt_blocks,\@abi-omnipotent
++.align	16
++bsaes_ctr32_encrypt_blocks:
++	mov	%rsp, %rax
++.Lctr_enc_prologue:
++	push	%rbp
++	push	%rbx
++	push	%r12
++	push	%r13
++	push	%r14
++	push	%r15
++	lea	-0x48(%rsp), %rsp
++___
++$code.=<<___ if ($win64);
++	mov	0xa0(%rsp),$arg5	# pull ivp
++	lea	-0xa0(%rsp), %rsp
++	movaps	%xmm6, 0x40(%rsp)
++	movaps	%xmm7, 0x50(%rsp)
++	movaps	%xmm8, 0x60(%rsp)
++	movaps	%xmm9, 0x70(%rsp)
++	movaps	%xmm10, 0x80(%rsp)
++	movaps	%xmm11, 0x90(%rsp)
++	movaps	%xmm12, 0xa0(%rsp)
++	movaps	%xmm13, 0xb0(%rsp)
++	movaps	%xmm14, 0xc0(%rsp)
++	movaps	%xmm15, 0xd0(%rsp)
++.Lctr_enc_body:
++___
++$code.=<<___;
++	mov	%rsp, %rbp		# backup %rsp
++	movdqu	($arg5), %xmm0		# load counter
++	mov	240($arg4), %eax	# rounds
++	mov	$arg1, $inp		# backup arguments
++	mov	$arg2, $out
++	mov	$arg3, $len
++	mov	$arg4, $key
++	movdqa	%xmm0, 0x20(%rbp)	# copy counter
++	cmp	\$8, $arg3
++	jb	.Lctr_enc_short
++
++	mov	%eax, %ebx		# rounds
++	shl	\$7, %rax		# 128 bytes per inner round key
++	sub	\$`128-32`, %rax	# size of bit-sliced key schedule
++	sub	%rax, %rsp
++
++	mov	%rsp, %rax		# pass key schedule
++	mov	$key, %rcx		# pass key
++	mov	%ebx, %r10d		# pass rounds
++	call	_bsaes_key_convert
++	pxor	%xmm6,%xmm7		# fix up last round key
++	movdqa	%xmm7,(%rax)		# save last round key
++
++	movdqa	(%rsp), @XMM[9]		# load round0 key
++	lea	.LADD1(%rip), %r11
++	movdqa	0x20(%rbp), @XMM[0]	# counter copy
++	movdqa	-0x20(%r11), @XMM[8]	# .LSWPUP
++	pshufb	@XMM[8], @XMM[9]	# byte swap upper part
++	pshufb	@XMM[8], @XMM[0]
++	movdqa	@XMM[9], (%rsp)		# save adjusted round0 key
++	jmp	.Lctr_enc_loop
++.align	16
++.Lctr_enc_loop:
++	movdqa	@XMM[0], 0x20(%rbp)	# save counter
++	movdqa	@XMM[0], @XMM[1]	# prepare 8 counter values
++	movdqa	@XMM[0], @XMM[2]
++	paddd	0x00(%r11), @XMM[1]	# .LADD1
++	movdqa	@XMM[0], @XMM[3]
++	paddd	0x10(%r11), @XMM[2]	# .LADD2
++	movdqa	@XMM[0], @XMM[4]
++	paddd	0x20(%r11), @XMM[3]	# .LADD3
++	movdqa	@XMM[0], @XMM[5]
++	paddd	0x30(%r11), @XMM[4]	# .LADD4
++	movdqa	@XMM[0], @XMM[6]
++	paddd	0x40(%r11), @XMM[5]	# .LADD5
++	movdqa	@XMM[0], @XMM[7]
++	paddd	0x50(%r11), @XMM[6]	# .LADD6
++	paddd	0x60(%r11), @XMM[7]	# .LADD7
++
++	# Borrow prologue from _bsaes_encrypt8 to use the opportunity
++	# to flip byte order in 32-bit counter
++	movdqa	(%rsp), @XMM[9]		# round 0 key
++	lea	0x10(%rsp), %rax	# pass key schedule
++	movdqa	-0x10(%r11), @XMM[8]	# .LSWPUPM0SR
++	pxor	@XMM[9], @XMM[0]	# xor with round0 key
++	pxor	@XMM[9], @XMM[1]
++	pxor	@XMM[9], @XMM[2]
++	pxor	@XMM[9], @XMM[3]
++	 pshufb	@XMM[8], @XMM[0]
++	 pshufb	@XMM[8], @XMM[1]
++	pxor	@XMM[9], @XMM[4]
++	pxor	@XMM[9], @XMM[5]
++	 pshufb	@XMM[8], @XMM[2]
++	 pshufb	@XMM[8], @XMM[3]
++	pxor	@XMM[9], @XMM[6]
++	pxor	@XMM[9], @XMM[7]
++	 pshufb	@XMM[8], @XMM[4]
++	 pshufb	@XMM[8], @XMM[5]
++	 pshufb	@XMM[8], @XMM[6]
++	 pshufb	@XMM[8], @XMM[7]
++	lea	.LBS0(%rip), %r11	# constants table
++	mov	%ebx,%r10d		# pass rounds
++
++	call	_bsaes_encrypt8_bitslice
++
++	sub	\$8,$len
++	jc	.Lctr_enc_loop_done
++
++	movdqu	0x00($inp), @XMM[8]	# load input
++	movdqu	0x10($inp), @XMM[9]
++	movdqu	0x20($inp), @XMM[10]
++	movdqu	0x30($inp), @XMM[11]
++	movdqu	0x40($inp), @XMM[12]
++	movdqu	0x50($inp), @XMM[13]
++	movdqu	0x60($inp), @XMM[14]
++	movdqu	0x70($inp), @XMM[15]
++	lea	0x80($inp),$inp
++	pxor	@XMM[0], @XMM[8]
++	movdqa	0x20(%rbp), @XMM[0]	# load counter
++	pxor	@XMM[9], @XMM[1]
++	movdqu	@XMM[8], 0x00($out)	# write output
++	pxor	@XMM[10], @XMM[4]
++	movdqu	@XMM[1], 0x10($out)
++	pxor	@XMM[11], @XMM[6]
++	movdqu	@XMM[4], 0x20($out)
++	pxor	@XMM[12], @XMM[3]
++	movdqu	@XMM[6], 0x30($out)
++	pxor	@XMM[13], @XMM[7]
++	movdqu	@XMM[3], 0x40($out)
++	pxor	@XMM[14], @XMM[2]
++	movdqu	@XMM[7], 0x50($out)
++	pxor	@XMM[15], @XMM[5]
++	movdqu	@XMM[2], 0x60($out)
++	lea	.LADD1(%rip), %r11
++	movdqu	@XMM[5], 0x70($out)
++	lea	0x80($out), $out
++	paddd	0x70(%r11), @XMM[0]	# .LADD8
++	jnz	.Lctr_enc_loop
++
++	jmp	.Lctr_enc_done
++.align	16
++.Lctr_enc_loop_done:
++	add	\$8, $len
++	movdqu	0x00($inp), @XMM[8]	# load input
++	pxor	@XMM[8], @XMM[0]
++	movdqu	@XMM[0], 0x00($out)	# write output
++	cmp	\$2,$len
++	jb	.Lctr_enc_done
++	movdqu	0x10($inp), @XMM[9]
++	pxor	@XMM[9], @XMM[1]
++	movdqu	@XMM[1], 0x10($out)
++	je	.Lctr_enc_done
++	movdqu	0x20($inp), @XMM[10]
++	pxor	@XMM[10], @XMM[4]
++	movdqu	@XMM[4], 0x20($out)
++	cmp	\$4,$len
++	jb	.Lctr_enc_done
++	movdqu	0x30($inp), @XMM[11]
++	pxor	@XMM[11], @XMM[6]
++	movdqu	@XMM[6], 0x30($out)
++	je	.Lctr_enc_done
++	movdqu	0x40($inp), @XMM[12]
++	pxor	@XMM[12], @XMM[3]
++	movdqu	@XMM[3], 0x40($out)
++	cmp	\$6,$len
++	jb	.Lctr_enc_done
++	movdqu	0x50($inp), @XMM[13]
++	pxor	@XMM[13], @XMM[7]
++	movdqu	@XMM[7], 0x50($out)
++	je	.Lctr_enc_done
++	movdqu	0x60($inp), @XMM[14]
++	pxor	@XMM[14], @XMM[2]
++	movdqu	@XMM[2], 0x60($out)
++	jmp	.Lctr_enc_done
++
++.align	16
++.Lctr_enc_short:
++	lea	0x20(%rbp), $arg1
++	lea	0x30(%rbp), $arg2
++	lea	($key), $arg3
++	call	asm_AES_encrypt
++	movdqu	($inp), @XMM[1]
++	lea	16($inp), $inp
++	mov	0x2c(%rbp), %eax	# load 32-bit counter
++	bswap	%eax
++	pxor	0x30(%rbp), @XMM[1]
++	inc	%eax			# increment
++	movdqu	@XMM[1], ($out)
++	bswap	%eax
++	lea	16($out), $out
++	mov	%eax, 0x2c(%rsp)	# save 32-bit counter
++	dec	$len
++	jnz	.Lctr_enc_short
++
++.Lctr_enc_done:
++	lea	(%rsp), %rax
++	pxor	%xmm0, %xmm0
++.Lctr_enc_bzero:			# wipe key schedule [if any]
++	movdqa	%xmm0, 0x00(%rax)
++	movdqa	%xmm0, 0x10(%rax)
++	lea	0x20(%rax), %rax
++	cmp	%rax, %rbp
++	ja	.Lctr_enc_bzero
++
++	lea	(%rbp),%rsp		# restore %rsp
++___
++$code.=<<___ if ($win64);
++	movaps	0x40(%rbp), %xmm6
++	movaps	0x50(%rbp), %xmm7
++	movaps	0x60(%rbp), %xmm8
++	movaps	0x70(%rbp), %xmm9
++	movaps	0x80(%rbp), %xmm10
++	movaps	0x90(%rbp), %xmm11
++	movaps	0xa0(%rbp), %xmm12
++	movaps	0xb0(%rbp), %xmm13
++	movaps	0xc0(%rbp), %xmm14
++	movaps	0xd0(%rbp), %xmm15
++	lea	0xa0(%rbp), %rsp
++___
++$code.=<<___;
++	mov	0x48(%rsp), %r15
++	mov	0x50(%rsp), %r14
++	mov	0x58(%rsp), %r13
++	mov	0x60(%rsp), %r12
++	mov	0x68(%rsp), %rbx
++	mov	0x70(%rsp), %rax
++	lea	0x78(%rsp), %rsp
++	mov	%rax, %rbp
++.Lctr_enc_epilogue:
++	ret
++.size	bsaes_ctr32_encrypt_blocks,.-bsaes_ctr32_encrypt_blocks
++___
++######################################################################
++# void bsaes_xts_[en|de]crypt(const char *inp,char *out,size_t len,
++#	const AES_KEY *key1, const AES_KEY *key2,
++#	const unsigned char iv[16]);
++#
++my ($twmask,$twres,$twtmp)=@XMM[13..15];
++$arg6=~s/d$//;
++
++$code.=<<___;
++.globl	bsaes_xts_encrypt
++.type	bsaes_xts_encrypt,\@abi-omnipotent
++.align	16
++bsaes_xts_encrypt:
++	mov	%rsp, %rax
++.Lxts_enc_prologue:
++	push	%rbp
++	push	%rbx
++	push	%r12
++	push	%r13
++	push	%r14
++	push	%r15
++	lea	-0x48(%rsp), %rsp
++___
++$code.=<<___ if ($win64);
++	mov	0xa0(%rsp),$arg5	# pull key2
++	mov	0xa8(%rsp),$arg6	# pull ivp
++	lea	-0xa0(%rsp), %rsp
++	movaps	%xmm6, 0x40(%rsp)
++	movaps	%xmm7, 0x50(%rsp)
++	movaps	%xmm8, 0x60(%rsp)
++	movaps	%xmm9, 0x70(%rsp)
++	movaps	%xmm10, 0x80(%rsp)
++	movaps	%xmm11, 0x90(%rsp)
++	movaps	%xmm12, 0xa0(%rsp)
++	movaps	%xmm13, 0xb0(%rsp)
++	movaps	%xmm14, 0xc0(%rsp)
++	movaps	%xmm15, 0xd0(%rsp)
++.Lxts_enc_body:
++___
++$code.=<<___;
++	mov	%rsp, %rbp		# backup %rsp
++	mov	$arg1, $inp		# backup arguments
++	mov	$arg2, $out
++	mov	$arg3, $len
++	mov	$arg4, $key
++
++	lea	($arg6), $arg1
++	lea	0x20(%rbp), $arg2
++	lea	($arg5), $arg3
++	call	asm_AES_encrypt		# generate initial tweak
++
++	mov	240($key), %eax		# rounds
++	mov	$len, %rbx		# backup $len
++
++	mov	%eax, %edx		# rounds
++	shl	\$7, %rax		# 128 bytes per inner round key
++	sub	\$`128-32`, %rax	# size of bit-sliced key schedule
++	sub	%rax, %rsp
++
++	mov	%rsp, %rax		# pass key schedule
++	mov	$key, %rcx		# pass key
++	mov	%edx, %r10d		# pass rounds
++	call	_bsaes_key_convert
++	pxor	%xmm6, %xmm7		# fix up last round key
++	movdqa	%xmm7, (%rax)		# save last round key
++
++	and	\$-16, $len
++	sub	\$0x80, %rsp		# place for tweak[8]
++	movdqa	0x20(%rbp), @XMM[7]	# initial tweak
++
++	pxor	$twtmp, $twtmp
++	movdqa	.Lxts_magic(%rip), $twmask
++	pcmpgtd	@XMM[7], $twtmp		# broadcast upper bits
++
++	sub	\$0x80, $len
++	jc	.Lxts_enc_short
++	jmp	.Lxts_enc_loop
++
++.align	16
++.Lxts_enc_loop:
++___
++    for ($i=0;$i<7;$i++) {
++    $code.=<<___;
++	pshufd	\$0x13, $twtmp, $twres
++	pxor	$twtmp, $twtmp
++	movdqa	@XMM[7], @XMM[$i]
++	movdqa	@XMM[7], `0x10*$i`(%rsp)# save tweak[$i]
++	paddq	@XMM[7], @XMM[7]	# psllq	1,$tweak
++	pand	$twmask, $twres		# isolate carry and residue
++	pcmpgtd	@XMM[7], $twtmp		# broadcast upper bits
++	pxor	$twres, @XMM[7]
++___
++    $code.=<<___ if ($i>=1);
++	movdqu	`0x10*($i-1)`($inp), @XMM[8+$i-1]
++___
++    $code.=<<___ if ($i>=2);
++	pxor	@XMM[8+$i-2], @XMM[$i-2]# input[] ^ tweak[]
++___
++    }
++$code.=<<___;
++	movdqu	0x60($inp), @XMM[8+6]
++	pxor	@XMM[8+5], @XMM[5]
++	movdqu	0x70($inp), @XMM[8+7]
++	lea	0x80($inp), $inp
++	movdqa	@XMM[7], 0x70(%rsp)
++	pxor	@XMM[8+6], @XMM[6]
++	lea	0x80(%rsp), %rax	# pass key schedule
++	pxor	@XMM[8+7], @XMM[7]
++	mov	%edx, %r10d		# pass rounds
++
++	call	_bsaes_encrypt8
++
++	pxor	0x00(%rsp), @XMM[0]	# ^= tweak[]
++	pxor	0x10(%rsp), @XMM[1]
++	movdqu	@XMM[0], 0x00($out)	# write output
++	pxor	0x20(%rsp), @XMM[4]
++	movdqu	@XMM[1], 0x10($out)
++	pxor	0x30(%rsp), @XMM[6]
++	movdqu	@XMM[4], 0x20($out)
++	pxor	0x40(%rsp), @XMM[3]
++	movdqu	@XMM[6], 0x30($out)
++	pxor	0x50(%rsp), @XMM[7]
++	movdqu	@XMM[3], 0x40($out)
++	pxor	0x60(%rsp), @XMM[2]
++	movdqu	@XMM[7], 0x50($out)
++	pxor	0x70(%rsp), @XMM[5]
++	movdqu	@XMM[2], 0x60($out)
++	movdqu	@XMM[5], 0x70($out)
++	lea	0x80($out), $out
++
++	movdqa	0x70(%rsp), @XMM[7]	# prepare next iteration tweak
++	pxor	$twtmp, $twtmp
++	movdqa	.Lxts_magic(%rip), $twmask
++	pcmpgtd	@XMM[7], $twtmp
++	pshufd	\$0x13, $twtmp, $twres
++	pxor	$twtmp, $twtmp
++	paddq	@XMM[7], @XMM[7]	# psllq	1,$tweak
++	pand	$twmask, $twres		# isolate carry and residue
++	pcmpgtd	@XMM[7], $twtmp		# broadcast upper bits
++	pxor	$twres, @XMM[7]
++
++	sub	\$0x80,$len
++	jnc	.Lxts_enc_loop
++
++.Lxts_enc_short:
++	add	\$0x80, $len
++	jz	.Lxts_enc_done
++___
++    for ($i=0;$i<7;$i++) {
++    $code.=<<___;
++	pshufd	\$0x13, $twtmp, $twres
++	pxor	$twtmp, $twtmp
++	movdqa	@XMM[7], @XMM[$i]
++	movdqa	@XMM[7], `0x10*$i`(%rsp)# save tweak[$i]
++	paddq	@XMM[7], @XMM[7]	# psllq	1,$tweak
++	pand	$twmask, $twres		# isolate carry and residue
++	pcmpgtd	@XMM[7], $twtmp		# broadcast upper bits
++	pxor	$twres, @XMM[7]
++___
++    $code.=<<___ if ($i>=1);
++	movdqu	`0x10*($i-1)`($inp), @XMM[8+$i-1]
++	cmp	\$`0x10*$i`,$len
++	je	.Lxts_enc_$i
++___
++    $code.=<<___ if ($i>=2);
++	pxor	@XMM[8+$i-2], @XMM[$i-2]# input[] ^ tweak[]
++___
++    }
++$code.=<<___;
++	movdqu	0x60($inp), @XMM[8+6]
++	pxor	@XMM[8+5], @XMM[5]
++	movdqa	@XMM[7], 0x70(%rsp)
++	lea	0x70($inp), $inp
++	pxor	@XMM[8+6], @XMM[6]
++	lea	0x80(%rsp), %rax	# pass key schedule
++	mov	%edx, %r10d		# pass rounds
++
++	call	_bsaes_encrypt8
++
++	pxor	0x00(%rsp), @XMM[0]	# ^= tweak[]
++	pxor	0x10(%rsp), @XMM[1]
++	movdqu	@XMM[0], 0x00($out)	# write output
++	pxor	0x20(%rsp), @XMM[4]
++	movdqu	@XMM[1], 0x10($out)
++	pxor	0x30(%rsp), @XMM[6]
++	movdqu	@XMM[4], 0x20($out)
++	pxor	0x40(%rsp), @XMM[3]
++	movdqu	@XMM[6], 0x30($out)
++	pxor	0x50(%rsp), @XMM[7]
++	movdqu	@XMM[3], 0x40($out)
++	pxor	0x60(%rsp), @XMM[2]
++	movdqu	@XMM[7], 0x50($out)
++	movdqu	@XMM[2], 0x60($out)
++	lea	0x70($out), $out
++
++	movdqa	0x70(%rsp), @XMM[7]	# next iteration tweak
++	jmp	.Lxts_enc_done
++.align	16
++.Lxts_enc_6:
++	pxor	@XMM[8+4], @XMM[4]
++	lea	0x60($inp), $inp
++	pxor	@XMM[8+5], @XMM[5]
++	lea	0x80(%rsp), %rax	# pass key schedule
++	mov	%edx, %r10d		# pass rounds
++
++	call	_bsaes_encrypt8
++
++	pxor	0x00(%rsp), @XMM[0]	# ^= tweak[]
++	pxor	0x10(%rsp), @XMM[1]
++	movdqu	@XMM[0], 0x00($out)	# write output
++	pxor	0x20(%rsp), @XMM[4]
++	movdqu	@XMM[1], 0x10($out)
++	pxor	0x30(%rsp), @XMM[6]
++	movdqu	@XMM[4], 0x20($out)
++	pxor	0x40(%rsp), @XMM[3]
++	movdqu	@XMM[6], 0x30($out)
++	pxor	0x50(%rsp), @XMM[7]
++	movdqu	@XMM[3], 0x40($out)
++	movdqu	@XMM[7], 0x50($out)
++	lea	0x60($out), $out
++
++	movdqa	0x60(%rsp), @XMM[7]	# next iteration tweak
++	jmp	.Lxts_enc_done
++.align	16
++.Lxts_enc_5:
++	pxor	@XMM[8+3], @XMM[3]
++	lea	0x50($inp), $inp
++	pxor	@XMM[8+4], @XMM[4]
++	lea	0x80(%rsp), %rax	# pass key schedule
++	mov	%edx, %r10d		# pass rounds
++
++	call	_bsaes_encrypt8
++
++	pxor	0x00(%rsp), @XMM[0]	# ^= tweak[]
++	pxor	0x10(%rsp), @XMM[1]
++	movdqu	@XMM[0], 0x00($out)	# write output
++	pxor	0x20(%rsp), @XMM[4]
++	movdqu	@XMM[1], 0x10($out)
++	pxor	0x30(%rsp), @XMM[6]
++	movdqu	@XMM[4], 0x20($out)
++	pxor	0x40(%rsp), @XMM[3]
++	movdqu	@XMM[6], 0x30($out)
++	movdqu	@XMM[3], 0x40($out)
++	lea	0x50($out), $out
++
++	movdqa	0x50(%rsp), @XMM[7]	# next iteration tweak
++	jmp	.Lxts_enc_done
++.align	16
++.Lxts_enc_4:
++	pxor	@XMM[8+2], @XMM[2]
++	lea	0x40($inp), $inp
++	pxor	@XMM[8+3], @XMM[3]
++	lea	0x80(%rsp), %rax	# pass key schedule
++	mov	%edx, %r10d		# pass rounds
++
++	call	_bsaes_encrypt8
++
++	pxor	0x00(%rsp), @XMM[0]	# ^= tweak[]
++	pxor	0x10(%rsp), @XMM[1]
++	movdqu	@XMM[0], 0x00($out)	# write output
++	pxor	0x20(%rsp), @XMM[4]
++	movdqu	@XMM[1], 0x10($out)
++	pxor	0x30(%rsp), @XMM[6]
++	movdqu	@XMM[4], 0x20($out)
++	movdqu	@XMM[6], 0x30($out)
++	lea	0x40($out), $out
++
++	movdqa	0x40(%rsp), @XMM[7]	# next iteration tweak
++	jmp	.Lxts_enc_done
++.align	16
++.Lxts_enc_3:
++	pxor	@XMM[8+1], @XMM[1]
++	lea	0x30($inp), $inp
++	pxor	@XMM[8+2], @XMM[2]
++	lea	0x80(%rsp), %rax	# pass key schedule
++	mov	%edx, %r10d		# pass rounds
++
++	call	_bsaes_encrypt8
++
++	pxor	0x00(%rsp), @XMM[0]	# ^= tweak[]
++	pxor	0x10(%rsp), @XMM[1]
++	movdqu	@XMM[0], 0x00($out)	# write output
++	pxor	0x20(%rsp), @XMM[4]
++	movdqu	@XMM[1], 0x10($out)
++	movdqu	@XMM[4], 0x20($out)
++	lea	0x30($out), $out
++
++	movdqa	0x30(%rsp), @XMM[7]	# next iteration tweak
++	jmp	.Lxts_enc_done
++.align	16
++.Lxts_enc_2:
++	pxor	@XMM[8+0], @XMM[0]
++	lea	0x20($inp), $inp
++	pxor	@XMM[8+1], @XMM[1]
++	lea	0x80(%rsp), %rax	# pass key schedule
++	mov	%edx, %r10d		# pass rounds
++
++	call	_bsaes_encrypt8
++
++	pxor	0x00(%rsp), @XMM[0]	# ^= tweak[]
++	pxor	0x10(%rsp), @XMM[1]
++	movdqu	@XMM[0], 0x00($out)	# write output
++	movdqu	@XMM[1], 0x10($out)
++	lea	0x20($out), $out
++
++	movdqa	0x20(%rsp), @XMM[7]	# next iteration tweak
++	jmp	.Lxts_enc_done
++.align	16
++.Lxts_enc_1:
++	pxor	@XMM[0], @XMM[8]
++	lea	0x10($inp), $inp
++	movdqa	@XMM[8], 0x20(%rbp)
++	lea	0x20(%rbp), $arg1
++	lea	0x20(%rbp), $arg2
++	lea	($key), $arg3
++	call	asm_AES_encrypt		# doesn't touch %xmm
++	pxor	0x20(%rbp), @XMM[0]	# ^= tweak[]
++	#pxor	@XMM[8], @XMM[0]
++	#lea	0x80(%rsp), %rax	# pass key schedule
++	#mov	%edx, %r10d		# pass rounds
++	#call	_bsaes_encrypt8
++	#pxor	0x00(%rsp), @XMM[0]	# ^= tweak[]
++	movdqu	@XMM[0], 0x00($out)	# write output
++	lea	0x10($out), $out
++
++	movdqa	0x10(%rsp), @XMM[7]	# next iteration tweak
++
++.Lxts_enc_done:
++	and	\$15, %ebx
++	jz	.Lxts_enc_ret
++	mov	$out, %rdx
++
++.Lxts_enc_steal:
++	movzb	($inp), %eax
++	movzb	-16(%rdx), %ecx
++	lea	1($inp), $inp
++	mov	%al, -16(%rdx)
++	mov	%cl, 0(%rdx)
++	lea	1(%rdx), %rdx
++	sub	\$1,%ebx
++	jnz	.Lxts_enc_steal
++
++	movdqu	-16($out), @XMM[0]
++	lea	0x20(%rbp), $arg1
++	pxor	@XMM[7], @XMM[0]
++	lea	0x20(%rbp), $arg2
++	movdqa	@XMM[0], 0x20(%rbp)
++	lea	($key), $arg3
++	call	asm_AES_encrypt		# doesn't touch %xmm
++	pxor	0x20(%rbp), @XMM[7]
++	movdqu	@XMM[7], -16($out)
++
++.Lxts_enc_ret:
++	lea	(%rsp), %rax
++	pxor	%xmm0, %xmm0
++.Lxts_enc_bzero:			# wipe key schedule [if any]
++	movdqa	%xmm0, 0x00(%rax)
++	movdqa	%xmm0, 0x10(%rax)
++	lea	0x20(%rax), %rax
++	cmp	%rax, %rbp
++	ja	.Lxts_enc_bzero
++
++	lea	(%rbp),%rsp		# restore %rsp
++___
++$code.=<<___ if ($win64);
++	movaps	0x40(%rbp), %xmm6
++	movaps	0x50(%rbp), %xmm7
++	movaps	0x60(%rbp), %xmm8
++	movaps	0x70(%rbp), %xmm9
++	movaps	0x80(%rbp), %xmm10
++	movaps	0x90(%rbp), %xmm11
++	movaps	0xa0(%rbp), %xmm12
++	movaps	0xb0(%rbp), %xmm13
++	movaps	0xc0(%rbp), %xmm14
++	movaps	0xd0(%rbp), %xmm15
++	lea	0xa0(%rbp), %rsp
++___
++$code.=<<___;
++	mov	0x48(%rsp), %r15
++	mov	0x50(%rsp), %r14
++	mov	0x58(%rsp), %r13
++	mov	0x60(%rsp), %r12
++	mov	0x68(%rsp), %rbx
++	mov	0x70(%rsp), %rax
++	lea	0x78(%rsp), %rsp
++	mov	%rax, %rbp
++.Lxts_enc_epilogue:
++	ret
++.size	bsaes_xts_encrypt,.-bsaes_xts_encrypt
++
++.globl	bsaes_xts_decrypt
++.type	bsaes_xts_decrypt,\@abi-omnipotent
++.align	16
++bsaes_xts_decrypt:
++	mov	%rsp, %rax
++.Lxts_dec_prologue:
++	push	%rbp
++	push	%rbx
++	push	%r12
++	push	%r13
++	push	%r14
++	push	%r15
++	lea	-0x48(%rsp), %rsp
++___
++$code.=<<___ if ($win64);
++	mov	0xa0(%rsp),$arg5	# pull key2
++	mov	0xa8(%rsp),$arg6	# pull ivp
++	lea	-0xa0(%rsp), %rsp
++	movaps	%xmm6, 0x40(%rsp)
++	movaps	%xmm7, 0x50(%rsp)
++	movaps	%xmm8, 0x60(%rsp)
++	movaps	%xmm9, 0x70(%rsp)
++	movaps	%xmm10, 0x80(%rsp)
++	movaps	%xmm11, 0x90(%rsp)
++	movaps	%xmm12, 0xa0(%rsp)
++	movaps	%xmm13, 0xb0(%rsp)
++	movaps	%xmm14, 0xc0(%rsp)
++	movaps	%xmm15, 0xd0(%rsp)
++.Lxts_dec_body:
++___
++$code.=<<___;
++	mov	%rsp, %rbp		# backup %rsp
++	mov	$arg1, $inp		# backup arguments
++	mov	$arg2, $out
++	mov	$arg3, $len
++	mov	$arg4, $key
++
++	lea	($arg6), $arg1
++	lea	0x20(%rbp), $arg2
++	lea	($arg5), $arg3
++	call	asm_AES_encrypt		# generate initial tweak
++
++	mov	240($key), %eax		# rounds
++	mov	$len, %rbx		# backup $len
++
++	mov	%eax, %edx		# rounds
++	shl	\$7, %rax		# 128 bytes per inner round key
++	sub	\$`128-32`, %rax	# size of bit-sliced key schedule
++	sub	%rax, %rsp
++
++	mov	%rsp, %rax		# pass key schedule
++	mov	$key, %rcx		# pass key
++	mov	%edx, %r10d		# pass rounds
++	call	_bsaes_key_convert
++	pxor	(%rsp), %xmm7		# fix up round 0 key
++	movdqa	%xmm6, (%rax)		# save last round key
++	movdqa	%xmm7, (%rsp)
++
++	xor	%eax, %eax		# if ($len%16) len-=16;
++	and	\$-16, $len
++	test	\$15, %ebx
++	setnz	%al
++	shl	\$4, %rax
++	sub	%rax, $len
++
++	sub	\$0x80, %rsp		# place for tweak[8]
++	movdqa	0x20(%rbp), @XMM[7]	# initial tweak
++
++	pxor	$twtmp, $twtmp
++	movdqa	.Lxts_magic(%rip), $twmask
++	pcmpgtd	@XMM[7], $twtmp		# broadcast upper bits
++
++	sub	\$0x80, $len
++	jc	.Lxts_dec_short
++	jmp	.Lxts_dec_loop
++
++.align	16
++.Lxts_dec_loop:
++___
++    for ($i=0;$i<7;$i++) {
++    $code.=<<___;
++	pshufd	\$0x13, $twtmp, $twres
++	pxor	$twtmp, $twtmp
++	movdqa	@XMM[7], @XMM[$i]
++	movdqa	@XMM[7], `0x10*$i`(%rsp)# save tweak[$i]
++	paddq	@XMM[7], @XMM[7]	# psllq	1,$tweak
++	pand	$twmask, $twres		# isolate carry and residue
++	pcmpgtd	@XMM[7], $twtmp		# broadcast upper bits
++	pxor	$twres, @XMM[7]
++___
++    $code.=<<___ if ($i>=1);
++	movdqu	`0x10*($i-1)`($inp), @XMM[8+$i-1]
++___
++    $code.=<<___ if ($i>=2);
++	pxor	@XMM[8+$i-2], @XMM[$i-2]# input[] ^ tweak[]
++___
++    }
++$code.=<<___;
++	movdqu	0x60($inp), @XMM[8+6]
++	pxor	@XMM[8+5], @XMM[5]
++	movdqu	0x70($inp), @XMM[8+7]
++	lea	0x80($inp), $inp
++	movdqa	@XMM[7], 0x70(%rsp)
++	pxor	@XMM[8+6], @XMM[6]
++	lea	0x80(%rsp), %rax	# pass key schedule
++	pxor	@XMM[8+7], @XMM[7]
++	mov	%edx, %r10d		# pass rounds
++
++	call	_bsaes_decrypt8
++
++	pxor	0x00(%rsp), @XMM[0]	# ^= tweak[]
++	pxor	0x10(%rsp), @XMM[1]
++	movdqu	@XMM[0], 0x00($out)	# write output
++	pxor	0x20(%rsp), @XMM[6]
++	movdqu	@XMM[1], 0x10($out)
++	pxor	0x30(%rsp), @XMM[4]
++	movdqu	@XMM[6], 0x20($out)
++	pxor	0x40(%rsp), @XMM[2]
++	movdqu	@XMM[4], 0x30($out)
++	pxor	0x50(%rsp), @XMM[7]
++	movdqu	@XMM[2], 0x40($out)
++	pxor	0x60(%rsp), @XMM[3]
++	movdqu	@XMM[7], 0x50($out)
++	pxor	0x70(%rsp), @XMM[5]
++	movdqu	@XMM[3], 0x60($out)
++	movdqu	@XMM[5], 0x70($out)
++	lea	0x80($out), $out
++
++	movdqa	0x70(%rsp), @XMM[7]	# prepare next iteration tweak
++	pxor	$twtmp, $twtmp
++	movdqa	.Lxts_magic(%rip), $twmask
++	pcmpgtd	@XMM[7], $twtmp
++	pshufd	\$0x13, $twtmp, $twres
++	pxor	$twtmp, $twtmp
++	paddq	@XMM[7], @XMM[7]	# psllq	1,$tweak
++	pand	$twmask, $twres		# isolate carry and residue
++	pcmpgtd	@XMM[7], $twtmp		# broadcast upper bits
++	pxor	$twres, @XMM[7]
++
++	sub	\$0x80,$len
++	jnc	.Lxts_dec_loop
++
++.Lxts_dec_short:
++	add	\$0x80, $len
++	jz	.Lxts_dec_done
++___
++    for ($i=0;$i<7;$i++) {
++    $code.=<<___;
++	pshufd	\$0x13, $twtmp, $twres
++	pxor	$twtmp, $twtmp
++	movdqa	@XMM[7], @XMM[$i]
++	movdqa	@XMM[7], `0x10*$i`(%rsp)# save tweak[$i]
++	paddq	@XMM[7], @XMM[7]	# psllq	1,$tweak
++	pand	$twmask, $twres		# isolate carry and residue
++	pcmpgtd	@XMM[7], $twtmp		# broadcast upper bits
++	pxor	$twres, @XMM[7]
++___
++    $code.=<<___ if ($i>=1);
++	movdqu	`0x10*($i-1)`($inp), @XMM[8+$i-1]
++	cmp	\$`0x10*$i`,$len
++	je	.Lxts_dec_$i
++___
++    $code.=<<___ if ($i>=2);
++	pxor	@XMM[8+$i-2], @XMM[$i-2]# input[] ^ tweak[]
++___
++    }
++$code.=<<___;
++	movdqu	0x60($inp), @XMM[8+6]
++	pxor	@XMM[8+5], @XMM[5]
++	movdqa	@XMM[7], 0x70(%rsp)
++	lea	0x70($inp), $inp
++	pxor	@XMM[8+6], @XMM[6]
++	lea	0x80(%rsp), %rax	# pass key schedule
++	mov	%edx, %r10d		# pass rounds
++
++	call	_bsaes_decrypt8
++
++	pxor	0x00(%rsp), @XMM[0]	# ^= tweak[]
++	pxor	0x10(%rsp), @XMM[1]
++	movdqu	@XMM[0], 0x00($out)	# write output
++	pxor	0x20(%rsp), @XMM[6]
++	movdqu	@XMM[1], 0x10($out)
++	pxor	0x30(%rsp), @XMM[4]
++	movdqu	@XMM[6], 0x20($out)
++	pxor	0x40(%rsp), @XMM[2]
++	movdqu	@XMM[4], 0x30($out)
++	pxor	0x50(%rsp), @XMM[7]
++	movdqu	@XMM[2], 0x40($out)
++	pxor	0x60(%rsp), @XMM[3]
++	movdqu	@XMM[7], 0x50($out)
++	movdqu	@XMM[3], 0x60($out)
++	lea	0x70($out), $out
++
++	movdqa	0x70(%rsp), @XMM[7]	# next iteration tweak
++	jmp	.Lxts_dec_done
++.align	16
++.Lxts_dec_6:
++	pxor	@XMM[8+4], @XMM[4]
++	lea	0x60($inp), $inp
++	pxor	@XMM[8+5], @XMM[5]
++	lea	0x80(%rsp), %rax	# pass key schedule
++	mov	%edx, %r10d		# pass rounds
++
++	call	_bsaes_decrypt8
++
++	pxor	0x00(%rsp), @XMM[0]	# ^= tweak[]
++	pxor	0x10(%rsp), @XMM[1]
++	movdqu	@XMM[0], 0x00($out)	# write output
++	pxor	0x20(%rsp), @XMM[6]
++	movdqu	@XMM[1], 0x10($out)
++	pxor	0x30(%rsp), @XMM[4]
++	movdqu	@XMM[6], 0x20($out)
++	pxor	0x40(%rsp), @XMM[2]
++	movdqu	@XMM[4], 0x30($out)
++	pxor	0x50(%rsp), @XMM[7]
++	movdqu	@XMM[2], 0x40($out)
++	movdqu	@XMM[7], 0x50($out)
++	lea	0x60($out), $out
++
++	movdqa	0x60(%rsp), @XMM[7]	# next iteration tweak
++	jmp	.Lxts_dec_done
++.align	16
++.Lxts_dec_5:
++	pxor	@XMM[8+3], @XMM[3]
++	lea	0x50($inp), $inp
++	pxor	@XMM[8+4], @XMM[4]
++	lea	0x80(%rsp), %rax	# pass key schedule
++	mov	%edx, %r10d		# pass rounds
++
++	call	_bsaes_decrypt8
++
++	pxor	0x00(%rsp), @XMM[0]	# ^= tweak[]
++	pxor	0x10(%rsp), @XMM[1]
++	movdqu	@XMM[0], 0x00($out)	# write output
++	pxor	0x20(%rsp), @XMM[6]
++	movdqu	@XMM[1], 0x10($out)
++	pxor	0x30(%rsp), @XMM[4]
++	movdqu	@XMM[6], 0x20($out)
++	pxor	0x40(%rsp), @XMM[2]
++	movdqu	@XMM[4], 0x30($out)
++	movdqu	@XMM[2], 0x40($out)
++	lea	0x50($out), $out
++
++	movdqa	0x50(%rsp), @XMM[7]	# next iteration tweak
++	jmp	.Lxts_dec_done
++.align	16
++.Lxts_dec_4:
++	pxor	@XMM[8+2], @XMM[2]
++	lea	0x40($inp), $inp
++	pxor	@XMM[8+3], @XMM[3]
++	lea	0x80(%rsp), %rax	# pass key schedule
++	mov	%edx, %r10d		# pass rounds
++
++	call	_bsaes_decrypt8
++
++	pxor	0x00(%rsp), @XMM[0]	# ^= tweak[]
++	pxor	0x10(%rsp), @XMM[1]
++	movdqu	@XMM[0], 0x00($out)	# write output
++	pxor	0x20(%rsp), @XMM[6]
++	movdqu	@XMM[1], 0x10($out)
++	pxor	0x30(%rsp), @XMM[4]
++	movdqu	@XMM[6], 0x20($out)
++	movdqu	@XMM[4], 0x30($out)
++	lea	0x40($out), $out
++
++	movdqa	0x40(%rsp), @XMM[7]	# next iteration tweak
++	jmp	.Lxts_dec_done
++.align	16
++.Lxts_dec_3:
++	pxor	@XMM[8+1], @XMM[1]
++	lea	0x30($inp), $inp
++	pxor	@XMM[8+2], @XMM[2]
++	lea	0x80(%rsp), %rax	# pass key schedule
++	mov	%edx, %r10d		# pass rounds
++
++	call	_bsaes_decrypt8
++
++	pxor	0x00(%rsp), @XMM[0]	# ^= tweak[]
++	pxor	0x10(%rsp), @XMM[1]
++	movdqu	@XMM[0], 0x00($out)	# write output
++	pxor	0x20(%rsp), @XMM[6]
++	movdqu	@XMM[1], 0x10($out)
++	movdqu	@XMM[6], 0x20($out)
++	lea	0x30($out), $out
++
++	movdqa	0x30(%rsp), @XMM[7]	# next iteration tweak
++	jmp	.Lxts_dec_done
++.align	16
++.Lxts_dec_2:
++	pxor	@XMM[8+0], @XMM[0]
++	lea	0x20($inp), $inp
++	pxor	@XMM[8+1], @XMM[1]
++	lea	0x80(%rsp), %rax	# pass key schedule
++	mov	%edx, %r10d		# pass rounds
++
++	call	_bsaes_decrypt8
++
++	pxor	0x00(%rsp), @XMM[0]	# ^= tweak[]
++	pxor	0x10(%rsp), @XMM[1]
++	movdqu	@XMM[0], 0x00($out)	# write output
++	movdqu	@XMM[1], 0x10($out)
++	lea	0x20($out), $out
++
++	movdqa	0x20(%rsp), @XMM[7]	# next iteration tweak
++	jmp	.Lxts_dec_done
++.align	16
++.Lxts_dec_1:
++	pxor	@XMM[0], @XMM[8]
++	lea	0x10($inp), $inp
++	movdqa	@XMM[8], 0x20(%rbp)
++	lea	0x20(%rbp), $arg1
++	lea	0x20(%rbp), $arg2
++	lea	($key), $arg3
++	call	asm_AES_decrypt		# doesn't touch %xmm
++	pxor	0x20(%rbp), @XMM[0]	# ^= tweak[]
++	#pxor	@XMM[8], @XMM[0]
++	#lea	0x80(%rsp), %rax	# pass key schedule
++	#mov	%edx, %r10d		# pass rounds
++	#call	_bsaes_decrypt8
++	#pxor	0x00(%rsp), @XMM[0]	# ^= tweak[]
++	movdqu	@XMM[0], 0x00($out)	# write output
++	lea	0x10($out), $out
++
++	movdqa	0x10(%rsp), @XMM[7]	# next iteration tweak
++
++.Lxts_dec_done:
++	and	\$15, %ebx
++	jz	.Lxts_dec_ret
++
++	pxor	$twtmp, $twtmp
++	movdqa	.Lxts_magic(%rip), $twmask
++	pcmpgtd	@XMM[7], $twtmp
++	pshufd	\$0x13, $twtmp, $twres
++	movdqa	@XMM[7], @XMM[6]
++	paddq	@XMM[7], @XMM[7]	# psllq 1,$tweak
++	pand	$twmask, $twres		# isolate carry and residue
++	movdqu	($inp), @XMM[0]
++	pxor	$twres, @XMM[7]
++
++	lea	0x20(%rbp), $arg1
++	pxor	@XMM[7], @XMM[0]
++	lea	0x20(%rbp), $arg2
++	movdqa	@XMM[0], 0x20(%rbp)
++	lea	($key), $arg3
++	call	asm_AES_decrypt		# doesn't touch %xmm
++	pxor	0x20(%rbp), @XMM[7]
++	mov	$out, %rdx
++	movdqu	@XMM[7], ($out)
++
++.Lxts_dec_steal:
++	movzb	16($inp), %eax
++	movzb	(%rdx), %ecx
++	lea	1($inp), $inp
++	mov	%al, (%rdx)
++	mov	%cl, 16(%rdx)
++	lea	1(%rdx), %rdx
++	sub	\$1,%ebx
++	jnz	.Lxts_dec_steal
++
++	movdqu	($out), @XMM[0]
++	lea	0x20(%rbp), $arg1
++	pxor	@XMM[6], @XMM[0]
++	lea	0x20(%rbp), $arg2
++	movdqa	@XMM[0], 0x20(%rbp)
++	lea	($key), $arg3
++	call	asm_AES_decrypt		# doesn't touch %xmm
++	pxor	0x20(%rbp), @XMM[6]
++	movdqu	@XMM[6], ($out)
++
++.Lxts_dec_ret:
++	lea	(%rsp), %rax
++	pxor	%xmm0, %xmm0
++.Lxts_dec_bzero:			# wipe key schedule [if any]
++	movdqa	%xmm0, 0x00(%rax)
++	movdqa	%xmm0, 0x10(%rax)
++	lea	0x20(%rax), %rax
++	cmp	%rax, %rbp
++	ja	.Lxts_dec_bzero
++
++	lea	(%rbp),%rsp		# restore %rsp
++___
++$code.=<<___ if ($win64);
++	movaps	0x40(%rbp), %xmm6
++	movaps	0x50(%rbp), %xmm7
++	movaps	0x60(%rbp), %xmm8
++	movaps	0x70(%rbp), %xmm9
++	movaps	0x80(%rbp), %xmm10
++	movaps	0x90(%rbp), %xmm11
++	movaps	0xa0(%rbp), %xmm12
++	movaps	0xb0(%rbp), %xmm13
++	movaps	0xc0(%rbp), %xmm14
++	movaps	0xd0(%rbp), %xmm15
++	lea	0xa0(%rbp), %rsp
++___
++$code.=<<___;
++	mov	0x48(%rsp), %r15
++	mov	0x50(%rsp), %r14
++	mov	0x58(%rsp), %r13
++	mov	0x60(%rsp), %r12
++	mov	0x68(%rsp), %rbx
++	mov	0x70(%rsp), %rax
++	lea	0x78(%rsp), %rsp
++	mov	%rax, %rbp
++.Lxts_dec_epilogue:
++	ret
++.size	bsaes_xts_decrypt,.-bsaes_xts_decrypt
++___
++}
++$code.=<<___;
++.type	_bsaes_const,\@object
++.align	64
++_bsaes_const:
++.LM0ISR:	# InvShiftRows constants
++	.quad	0x0a0e0206070b0f03, 0x0004080c0d010509
++.LISRM0:
++	.quad	0x01040b0e0205080f, 0x0306090c00070a0d
++.LISR:
++	.quad	0x0504070602010003, 0x0f0e0d0c080b0a09
++.LBS0:		# bit-slice constants
++	.quad	0x5555555555555555, 0x5555555555555555
++.LBS1:
++	.quad	0x3333333333333333, 0x3333333333333333
++.LBS2:
++	.quad	0x0f0f0f0f0f0f0f0f, 0x0f0f0f0f0f0f0f0f
++.LSR:		# shiftrows constants
++	.quad	0x0504070600030201, 0x0f0e0d0c0a09080b
++.LSRM0:
++	.quad	0x0304090e00050a0f, 0x01060b0c0207080d
++.LM0SR:
++	.quad	0x0a0e02060f03070b, 0x0004080c05090d01
++.LSWPUP:	# byte-swap upper dword
++	.quad	0x0706050403020100, 0x0c0d0e0f0b0a0908
++.LSWPUPM0SR:
++	.quad	0x0a0d02060c03070b, 0x0004080f05090e01
++.LADD1:		# counter increment constants
++	.quad	0x0000000000000000, 0x0000000100000000
++.LADD2:
++	.quad	0x0000000000000000, 0x0000000200000000
++.LADD3:
++	.quad	0x0000000000000000, 0x0000000300000000
++.LADD4:
++	.quad	0x0000000000000000, 0x0000000400000000
++.LADD5:
++	.quad	0x0000000000000000, 0x0000000500000000
++.LADD6:
++	.quad	0x0000000000000000, 0x0000000600000000
++.LADD7:
++	.quad	0x0000000000000000, 0x0000000700000000
++.LADD8:
++	.quad	0x0000000000000000, 0x0000000800000000
++.Lxts_magic:
++	.long	0x87,0,1,0
++.Lmasks:
++	.quad	0x0101010101010101, 0x0101010101010101
++	.quad	0x0202020202020202, 0x0202020202020202
++	.quad	0x0404040404040404, 0x0404040404040404
++	.quad	0x0808080808080808, 0x0808080808080808
++.LM0:
++	.quad	0x02060a0e03070b0f, 0x0004080c0105090d
++.L63:
++	.quad	0x6363636363636363, 0x6363636363636363
++.asciz	"Bit-sliced AES for x86_64/SSSE3, Emilia Käsper, Peter Schwabe, Andy Polyakov"
++.align	64
++.size	_bsaes_const,.-_bsaes_const
++___
++
++# EXCEPTION_DISPOSITION handler (EXCEPTION_RECORD *rec,ULONG64 frame,
++#		CONTEXT *context,DISPATCHER_CONTEXT *disp)
++if ($win64) {
++$rec="%rcx";
++$frame="%rdx";
++$context="%r8";
++$disp="%r9";
++
++$code.=<<___;
++.extern	__imp_RtlVirtualUnwind
++.type	se_handler,\@abi-omnipotent
++.align	16
++se_handler:
++	push	%rsi
++	push	%rdi
++	push	%rbx
++	push	%rbp
++	push	%r12
++	push	%r13
++	push	%r14
++	push	%r15
++	pushfq
++	sub	\$64,%rsp
++
++	mov	120($context),%rax	# pull context->Rax
++	mov	248($context),%rbx	# pull context->Rip
++
++	mov	8($disp),%rsi		# disp->ImageBase
++	mov	56($disp),%r11		# disp->HandlerData
++
++	mov	0(%r11),%r10d		# HandlerData[0]
++	lea	(%rsi,%r10),%r10	# prologue label
++	cmp	%r10,%rbx		# context->RipRsp
++
++	mov	4(%r11),%r10d		# HandlerData[1]
++	lea	(%rsi,%r10),%r10	# epilogue label
++	cmp	%r10,%rbx		# context->Rip>=epilogue label
++	jae	.Lin_prologue
++
++	mov	160($context),%rax	# pull context->Rbp
++
++	lea	0x40(%rax),%rsi		# %xmm save area
++	lea	512($context),%rdi	# &context.Xmm6
++	mov	\$20,%ecx		# 10*sizeof(%xmm0)/sizeof(%rax)
++	.long	0xa548f3fc		# cld; rep movsq
++	lea	0xa0(%rax),%rax		# adjust stack pointer
++
++	mov	0x70(%rax),%rbp
++	mov	0x68(%rax),%rbx
++	mov	0x60(%rax),%r12
++	mov	0x58(%rax),%r13
++	mov	0x50(%rax),%r14
++	mov	0x48(%rax),%r15
++	lea	0x78(%rax),%rax		# adjust stack pointer
++	mov	%rbx,144($context)	# restore context->Rbx
++	mov	%rbp,160($context)	# restore context->Rbp
++	mov	%r12,216($context)	# restore context->R12
++	mov	%r13,224($context)	# restore context->R13
++	mov	%r14,232($context)	# restore context->R14
++	mov	%r15,240($context)	# restore context->R15
++
++.Lin_prologue:
++	mov	%rax,152($context)	# restore context->Rsp
++
++	mov	40($disp),%rdi		# disp->ContextRecord
++	mov	$context,%rsi		# context
++	mov	\$`1232/8`,%ecx		# sizeof(CONTEXT)
++	.long	0xa548f3fc		# cld; rep movsq
++
++	mov	$disp,%rsi
++	xor	%rcx,%rcx		# arg1, UNW_FLAG_NHANDLER
++	mov	8(%rsi),%rdx		# arg2, disp->ImageBase
++	mov	0(%rsi),%r8		# arg3, disp->ControlPc
++	mov	16(%rsi),%r9		# arg4, disp->FunctionEntry
++	mov	40(%rsi),%r10		# disp->ContextRecord
++	lea	56(%rsi),%r11		# &disp->HandlerData
++	lea	24(%rsi),%r12		# &disp->EstablisherFrame
++	mov	%r10,32(%rsp)		# arg5
++	mov	%r11,40(%rsp)		# arg6
++	mov	%r12,48(%rsp)		# arg7
++	mov	%rcx,56(%rsp)		# arg8, (NULL)
++	call	*__imp_RtlVirtualUnwind(%rip)
++
++	mov	\$1,%eax		# ExceptionContinueSearch
++	add	\$64,%rsp
++	popfq
++	pop	%r15
++	pop	%r14
++	pop	%r13
++	pop	%r12
++	pop	%rbp
++	pop	%rbx
++	pop	%rdi
++	pop	%rsi
++	ret
++.size	se_handler,.-se_handler
++
++.section	.pdata
++.align	4
++___
++$code.=<<___ if ($ecb);
++	.rva	.Lecb_enc_prologue
++	.rva	.Lecb_enc_epilogue
++	.rva	.Lecb_enc_info
++
++	.rva	.Lecb_dec_prologue
++	.rva	.Lecb_dec_epilogue
++	.rva	.Lecb_dec_info
++___
++$code.=<<___;
++	.rva	.Lcbc_dec_prologue
++	.rva	.Lcbc_dec_epilogue
++	.rva	.Lcbc_dec_info
++
++	.rva	.Lctr_enc_prologue
++	.rva	.Lctr_enc_epilogue
++	.rva	.Lctr_enc_info
++
++	.rva	.Lxts_enc_prologue
++	.rva	.Lxts_enc_epilogue
++	.rva	.Lxts_enc_info
++
++	.rva	.Lxts_dec_prologue
++	.rva	.Lxts_dec_epilogue
++	.rva	.Lxts_dec_info
++
++.section	.xdata
++.align	8
++___
++$code.=<<___ if ($ecb);
++.Lecb_enc_info:
++	.byte	9,0,0,0
++	.rva	se_handler
++	.rva	.Lecb_enc_body,.Lecb_enc_epilogue	# HandlerData[]
++.Lecb_dec_info:
++	.byte	9,0,0,0
++	.rva	se_handler
++	.rva	.Lecb_dec_body,.Lecb_dec_epilogue	# HandlerData[]
++___
++$code.=<<___;
++.Lcbc_dec_info:
++	.byte	9,0,0,0
++	.rva	se_handler
++	.rva	.Lcbc_dec_body,.Lcbc_dec_epilogue	# HandlerData[]
++.Lctr_enc_info:
++	.byte	9,0,0,0
++	.rva	se_handler
++	.rva	.Lctr_enc_body,.Lctr_enc_epilogue	# HandlerData[]
++.Lxts_enc_info:
++	.byte	9,0,0,0
++	.rva	se_handler
++	.rva	.Lxts_enc_body,.Lxts_enc_epilogue	# HandlerData[]
++.Lxts_dec_info:
++	.byte	9,0,0,0
++	.rva	se_handler
++	.rva	.Lxts_dec_body,.Lxts_dec_epilogue	# HandlerData[]
++___
++}
++
++$code =~ s/\`([^\`]*)\`/eval($1)/gem;
++
++print $code;
++
++close STDOUT;
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/aes/asm/vpaes-armv8.pl b/CryptoPkg/Library/OpensslLib/openssl/crypto/aes/asm/vpaes-armv8.pl
+new file mode 100755
+index 0000000..d6b5f56
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/aes/asm/vpaes-armv8.pl
+@@ -0,0 +1,1259 @@
++#! /usr/bin/env perl
++# Copyright 2015-2016 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
++# in the file LICENSE in the source distribution or at
++# https://www.openssl.org/source/license.html
++
++
++######################################################################
++## Constant-time SSSE3 AES core implementation.
++## version 0.1
++##
++## By Mike Hamburg (Stanford University), 2009
++## Public domain.
++##
++## For details see http://shiftleft.org/papers/vector_aes/ and
++## http://crypto.stanford.edu/vpaes/.
++##
++######################################################################
++# ARMv8 NEON adaptation by 
++#
++# Reason for undertaken effort is that there is at least one popular
++# SoC based on Cortex-A53 that doesn't have crypto extensions.
++#
++#                   CBC enc     ECB enc/dec(*)   [bit-sliced enc/dec]
++# Cortex-A53        21.5        18.1/20.6        [17.5/19.8         ]
++# Cortex-A57        36.0(**)    20.4/24.9(**)    [14.4/16.6         ]
++# X-Gene            45.9(**)    45.8/57.7(**)    [33.1/37.6(**)     ]
++# Denver(***)       16.6(**)    15.1/17.8(**)    [8.80/9.93         ]
++# Apple A7(***)     22.7(**)    10.9/14.3        [8.45/10.0         ]
++# Mongoose(***)     26.3(**)    21.0/25.0(**)    [13.3/16.8         ]
++#
++# (*)	ECB denotes approximate result for parallelizeable modes
++#	such as CBC decrypt, CTR, etc.;
++# (**)	these results are worse than scalar compiler-generated
++#	code, but it's constant-time and therefore preferred;
++# (***)	presented for reference/comparison purposes;
++
++$flavour = shift;
++while (($output=shift) && ($output!~/\w[\w\-]*\.\w+$/)) {}
++
++$0 =~ m/(.*[\/\\])[^\/\\]+$/; $dir=$1;
++( $xlate="${dir}arm-xlate.pl" and -f $xlate ) or
++( $xlate="${dir}../../perlasm/arm-xlate.pl" and -f $xlate) or
++die "can't locate arm-xlate.pl";
++
++open OUT,"| \"$^X\" $xlate $flavour $output";
++*STDOUT=*OUT;
++
++$code.=<<___;
++.text
++
++.type	_vpaes_consts,%object
++.align	7	// totally strategic alignment
++_vpaes_consts:
++.Lk_mc_forward:	// mc_forward
++	.quad	0x0407060500030201, 0x0C0F0E0D080B0A09
++	.quad	0x080B0A0904070605, 0x000302010C0F0E0D
++	.quad	0x0C0F0E0D080B0A09, 0x0407060500030201
++	.quad	0x000302010C0F0E0D, 0x080B0A0904070605
++.Lk_mc_backward:// mc_backward
++	.quad	0x0605040702010003, 0x0E0D0C0F0A09080B
++	.quad	0x020100030E0D0C0F, 0x0A09080B06050407
++	.quad	0x0E0D0C0F0A09080B, 0x0605040702010003
++	.quad	0x0A09080B06050407, 0x020100030E0D0C0F
++.Lk_sr:		// sr
++	.quad	0x0706050403020100, 0x0F0E0D0C0B0A0908
++	.quad	0x030E09040F0A0500, 0x0B06010C07020D08
++	.quad	0x0F060D040B020900, 0x070E050C030A0108
++	.quad	0x0B0E0104070A0D00, 0x0306090C0F020508
++
++//
++// "Hot" constants
++//
++.Lk_inv:	// inv, inva
++	.quad	0x0E05060F0D080180, 0x040703090A0B0C02
++	.quad	0x01040A060F0B0780, 0x030D0E0C02050809
++.Lk_ipt:	// input transform (lo, hi)
++	.quad	0xC2B2E8985A2A7000, 0xCABAE09052227808
++	.quad	0x4C01307D317C4D00, 0xCD80B1FCB0FDCC81
++.Lk_sbo:	// sbou, sbot
++	.quad	0xD0D26D176FBDC700, 0x15AABF7AC502A878
++	.quad	0xCFE474A55FBB6A00, 0x8E1E90D1412B35FA
++.Lk_sb1:	// sb1u, sb1t
++	.quad	0x3618D415FAE22300, 0x3BF7CCC10D2ED9EF
++	.quad	0xB19BE18FCB503E00, 0xA5DF7A6E142AF544
++.Lk_sb2:	// sb2u, sb2t
++	.quad	0x69EB88400AE12900, 0xC2A163C8AB82234A
++	.quad	0xE27A93C60B712400, 0x5EB7E955BC982FCD
++
++//
++//  Decryption stuff
++//
++.Lk_dipt:	// decryption input transform
++	.quad	0x0F505B040B545F00, 0x154A411E114E451A
++	.quad	0x86E383E660056500, 0x12771772F491F194
++.Lk_dsbo:	// decryption sbox final output
++	.quad	0x1387EA537EF94000, 0xC7AA6DB9D4943E2D
++	.quad	0x12D7560F93441D00, 0xCA4B8159D8C58E9C
++.Lk_dsb9:	// decryption sbox output *9*u, *9*t
++	.quad	0x851C03539A86D600, 0xCAD51F504F994CC9
++	.quad	0xC03B1789ECD74900, 0x725E2C9EB2FBA565
++.Lk_dsbd:	// decryption sbox output *D*u, *D*t
++	.quad	0x7D57CCDFE6B1A200, 0xF56E9B13882A4439
++	.quad	0x3CE2FAF724C6CB00, 0x2931180D15DEEFD3
++.Lk_dsbb:	// decryption sbox output *B*u, *B*t
++	.quad	0xD022649296B44200, 0x602646F6B0F2D404
++	.quad	0xC19498A6CD596700, 0xF3FF0C3E3255AA6B
++.Lk_dsbe:	// decryption sbox output *E*u, *E*t
++	.quad	0x46F2929626D4D000, 0x2242600464B4F6B0
++	.quad	0x0C55A6CDFFAAC100, 0x9467F36B98593E32
++
++//
++//  Key schedule constants
++//
++.Lk_dksd:	// decryption key schedule: invskew x*D
++	.quad	0xFEB91A5DA3E44700, 0x0740E3A45A1DBEF9
++	.quad	0x41C277F4B5368300, 0x5FDC69EAAB289D1E
++.Lk_dksb:	// decryption key schedule: invskew x*B
++	.quad	0x9A4FCA1F8550D500, 0x03D653861CC94C99
++	.quad	0x115BEDA7B6FC4A00, 0xD993256F7E3482C8
++.Lk_dkse:	// decryption key schedule: invskew x*E + 0x63
++	.quad	0xD5031CCA1FC9D600, 0x53859A4C994F5086
++	.quad	0xA23196054FDC7BE8, 0xCD5EF96A20B31487
++.Lk_dks9:	// decryption key schedule: invskew x*9
++	.quad	0xB6116FC87ED9A700, 0x4AED933482255BFC
++	.quad	0x4576516227143300, 0x8BB89FACE9DAFDCE
++
++.Lk_rcon:	// rcon
++	.quad	0x1F8391B9AF9DEEB6, 0x702A98084D7C7D81
++
++.Lk_opt:	// output transform
++	.quad	0xFF9F4929D6B66000, 0xF7974121DEBE6808
++	.quad	0x01EDBD5150BCEC00, 0xE10D5DB1B05C0CE0
++.Lk_deskew:	// deskew tables: inverts the sbox's "skew"
++	.quad	0x07E4A34047A4E300, 0x1DFEB95A5DBEF91A
++	.quad	0x5F36B5DC83EA6900, 0x2841C2ABF49D1E77
++
++.asciz  "Vector Permutaion AES for ARMv8, Mike Hamburg (Stanford University)"
++.size	_vpaes_consts,.-_vpaes_consts
++.align	6
++___
++
++{
++my ($inp,$out,$key) = map("x$_",(0..2));
++
++my ($invlo,$invhi,$iptlo,$ipthi,$sbou,$sbot) = map("v$_.16b",(18..23));
++my ($sb1u,$sb1t,$sb2u,$sb2t) = map("v$_.16b",(24..27));
++my ($sb9u,$sb9t,$sbdu,$sbdt,$sbbu,$sbbt,$sbeu,$sbet)=map("v$_.16b",(24..31));
++
++$code.=<<___;
++##
++##  _aes_preheat
++##
++##  Fills register %r10 -> .aes_consts (so you can -fPIC)
++##  and %xmm9-%xmm15 as specified below.
++##
++.type	_vpaes_encrypt_preheat,%function
++.align	4
++_vpaes_encrypt_preheat:
++	adr	x10, .Lk_inv
++	movi	v17.16b, #0x0f
++	ld1	{v18.2d-v19.2d}, [x10],#32	// .Lk_inv
++	ld1	{v20.2d-v23.2d}, [x10],#64	// .Lk_ipt, .Lk_sbo
++	ld1	{v24.2d-v27.2d}, [x10]		// .Lk_sb1, .Lk_sb2
++	ret
++.size	_vpaes_encrypt_preheat,.-_vpaes_encrypt_preheat
++
++##
++##  _aes_encrypt_core
++##
++##  AES-encrypt %xmm0.
++##
++##  Inputs:
++##     %xmm0 = input
++##     %xmm9-%xmm15 as in _vpaes_preheat
++##    (%rdx) = scheduled keys
++##
++##  Output in %xmm0
++##  Clobbers  %xmm1-%xmm5, %r9, %r10, %r11, %rax
++##  Preserves %xmm6 - %xmm8 so you get some local vectors
++##
++##
++.type	_vpaes_encrypt_core,%function
++.align 4
++_vpaes_encrypt_core:
++	mov	x9, $key
++	ldr	w8, [$key,#240]			// pull rounds
++	adr	x11, .Lk_mc_forward+16
++						// vmovdqa	.Lk_ipt(%rip),	%xmm2	# iptlo
++	ld1	{v16.2d}, [x9], #16		// vmovdqu	(%r9),	%xmm5		# round0 key
++	and	v1.16b, v7.16b, v17.16b		// vpand	%xmm9,	%xmm0,	%xmm1
++	ushr	v0.16b, v7.16b, #4		// vpsrlb	\$4,	%xmm0,	%xmm0
++	tbl	v1.16b, {$iptlo}, v1.16b	// vpshufb	%xmm1,	%xmm2,	%xmm1
++						// vmovdqa	.Lk_ipt+16(%rip), %xmm3	# ipthi
++	tbl	v2.16b, {$ipthi}, v0.16b	// vpshufb	%xmm0,	%xmm3,	%xmm2
++	eor	v0.16b, v1.16b, v16.16b		// vpxor	%xmm5,	%xmm1,	%xmm0
++	eor	v0.16b, v0.16b, v2.16b		// vpxor	%xmm2,	%xmm0,	%xmm0
++	b	.Lenc_entry
++
++.align 4
++.Lenc_loop:
++	// middle of middle round
++	add	x10, x11, #0x40
++	tbl	v4.16b, {$sb1t}, v2.16b		// vpshufb	%xmm2,	%xmm13,	%xmm4	# 4 = sb1u
++	ld1	{v1.2d}, [x11], #16		// vmovdqa	-0x40(%r11,%r10), %xmm1	# .Lk_mc_forward[]
++	tbl	v0.16b, {$sb1u}, v3.16b		// vpshufb	%xmm3,	%xmm12,	%xmm0	# 0 = sb1t
++	eor	v4.16b, v4.16b, v16.16b		// vpxor	%xmm5,	%xmm4,	%xmm4	# 4 = sb1u + k
++	tbl	v5.16b,	{$sb2t}, v2.16b		// vpshufb	%xmm2,	%xmm15,	%xmm5	# 4 = sb2u
++	eor	v0.16b, v0.16b, v4.16b		// vpxor	%xmm4,	%xmm0,	%xmm0	# 0 = A
++	tbl	v2.16b, {$sb2u}, v3.16b		// vpshufb	%xmm3,	%xmm14,	%xmm2	# 2 = sb2t
++	ld1	{v4.2d}, [x10]			// vmovdqa	(%r11,%r10), %xmm4	# .Lk_mc_backward[]
++	tbl	v3.16b, {v0.16b}, v1.16b	// vpshufb	%xmm1,	%xmm0,	%xmm3	# 0 = B
++	eor	v2.16b, v2.16b, v5.16b		// vpxor	%xmm5,	%xmm2,	%xmm2	# 2 = 2A
++	tbl	v0.16b, {v0.16b}, v4.16b	// vpshufb	%xmm4,	%xmm0,	%xmm0	# 3 = D
++	eor	v3.16b, v3.16b, v2.16b		// vpxor	%xmm2,	%xmm3,	%xmm3	# 0 = 2A+B
++	tbl	v4.16b, {v3.16b}, v1.16b	// vpshufb	%xmm1,	%xmm3,	%xmm4	# 0 = 2B+C
++	eor	v0.16b, v0.16b, v3.16b		// vpxor	%xmm3,	%xmm0,	%xmm0	# 3 = 2A+B+D
++	and	x11, x11, #~(1<<6)		// and		\$0x30,	%r11		# ... mod 4
++	eor	v0.16b, v0.16b, v4.16b		// vpxor	%xmm4,	%xmm0, %xmm0	# 0 = 2A+3B+C+D
++	sub	w8, w8, #1			// nr--
++
++.Lenc_entry:
++	// top of round
++	and	v1.16b, v0.16b, v17.16b		// vpand	%xmm0,	%xmm9,	%xmm1   # 0 = k
++	ushr	v0.16b, v0.16b, #4		// vpsrlb	\$4,	%xmm0,	%xmm0	# 1 = i
++	tbl	v5.16b, {$invhi}, v1.16b	// vpshufb	%xmm1,	%xmm11,	%xmm5	# 2 = a/k
++	eor	v1.16b, v1.16b, v0.16b		// vpxor	%xmm0,	%xmm1,	%xmm1	# 0 = j
++	tbl	v3.16b, {$invlo}, v0.16b	// vpshufb	%xmm0, 	%xmm10,	%xmm3  	# 3 = 1/i
++	tbl	v4.16b, {$invlo}, v1.16b	// vpshufb	%xmm1, 	%xmm10,	%xmm4  	# 4 = 1/j
++	eor	v3.16b, v3.16b, v5.16b		// vpxor	%xmm5,	%xmm3,	%xmm3	# 3 = iak = 1/i + a/k
++	eor	v4.16b, v4.16b, v5.16b		// vpxor	%xmm5,	%xmm4,	%xmm4  	# 4 = jak = 1/j + a/k
++	tbl	v2.16b, {$invlo}, v3.16b	// vpshufb	%xmm3,	%xmm10,	%xmm2  	# 2 = 1/iak
++	tbl	v3.16b, {$invlo}, v4.16b	// vpshufb	%xmm4,	%xmm10,	%xmm3	# 3 = 1/jak
++	eor	v2.16b, v2.16b, v1.16b		// vpxor	%xmm1,	%xmm2,	%xmm2  	# 2 = io
++	eor	v3.16b, v3.16b, v0.16b		// vpxor	%xmm0,	%xmm3,	%xmm3	# 3 = jo
++	ld1	{v16.2d}, [x9],#16		// vmovdqu	(%r9),	%xmm5
++	cbnz	w8, .Lenc_loop
++
++	// middle of last round
++	add	x10, x11, #0x80
++						// vmovdqa	-0x60(%r10), %xmm4	# 3 : sbou	.Lk_sbo
++						// vmovdqa	-0x50(%r10), %xmm0	# 0 : sbot	.Lk_sbo+16
++	tbl	v4.16b, {$sbou}, v2.16b		// vpshufb	%xmm2,	%xmm4,	%xmm4	# 4 = sbou
++	ld1	{v1.2d}, [x10]			// vmovdqa	0x40(%r11,%r10), %xmm1	# .Lk_sr[]
++	tbl	v0.16b, {$sbot}, v3.16b		// vpshufb	%xmm3,	%xmm0,	%xmm0	# 0 = sb1t
++	eor	v4.16b, v4.16b, v16.16b		// vpxor	%xmm5,	%xmm4,	%xmm4	# 4 = sb1u + k
++	eor	v0.16b, v0.16b, v4.16b		// vpxor	%xmm4,	%xmm0,	%xmm0	# 0 = A
++	tbl	v0.16b, {v0.16b}, v1.16b	// vpshufb	%xmm1,	%xmm0,	%xmm0
++	ret
++.size	_vpaes_encrypt_core,.-_vpaes_encrypt_core
++
++.globl	vpaes_encrypt
++.type	vpaes_encrypt,%function
++.align	4
++vpaes_encrypt:
++	stp	x29,x30,[sp,#-16]!
++	add	x29,sp,#0
++
++	ld1	{v7.16b}, [$inp]
++	bl	_vpaes_encrypt_preheat
++	bl	_vpaes_encrypt_core
++	st1	{v0.16b}, [$out]
++
++	ldp	x29,x30,[sp],#16
++	ret
++.size	vpaes_encrypt,.-vpaes_encrypt
++
++.type	_vpaes_encrypt_2x,%function
++.align 4
++_vpaes_encrypt_2x:
++	mov	x9, $key
++	ldr	w8, [$key,#240]			// pull rounds
++	adr	x11, .Lk_mc_forward+16
++						// vmovdqa	.Lk_ipt(%rip),	%xmm2	# iptlo
++	ld1	{v16.2d}, [x9], #16		// vmovdqu	(%r9),	%xmm5		# round0 key
++	and	v1.16b,  v14.16b,  v17.16b	// vpand	%xmm9,	%xmm0,	%xmm1
++	ushr	v0.16b,  v14.16b,  #4		// vpsrlb	\$4,	%xmm0,	%xmm0
++	 and	v9.16b,  v15.16b,  v17.16b
++	 ushr	v8.16b,  v15.16b,  #4
++	tbl	v1.16b,  {$iptlo}, v1.16b	// vpshufb	%xmm1,	%xmm2,	%xmm1
++	 tbl	v9.16b,  {$iptlo}, v9.16b
++						// vmovdqa	.Lk_ipt+16(%rip), %xmm3	# ipthi
++	tbl	v2.16b,  {$ipthi}, v0.16b	// vpshufb	%xmm0,	%xmm3,	%xmm2
++	 tbl	v10.16b, {$ipthi}, v8.16b
++	eor	v0.16b,  v1.16b,   v16.16b	// vpxor	%xmm5,	%xmm1,	%xmm0
++	 eor	v8.16b,  v9.16b,   v16.16b
++	eor	v0.16b,  v0.16b,   v2.16b	// vpxor	%xmm2,	%xmm0,	%xmm0
++	 eor	v8.16b,  v8.16b,   v10.16b
++	b	.Lenc_2x_entry
++
++.align 4
++.Lenc_2x_loop:
++	// middle of middle round
++	add	x10, x11, #0x40
++	tbl	v4.16b,  {$sb1t}, v2.16b	// vpshufb	%xmm2,	%xmm13,	%xmm4	# 4 = sb1u
++	 tbl	v12.16b, {$sb1t}, v10.16b
++	ld1	{v1.2d}, [x11], #16		// vmovdqa	-0x40(%r11,%r10), %xmm1	# .Lk_mc_forward[]
++	tbl	v0.16b,  {$sb1u}, v3.16b	// vpshufb	%xmm3,	%xmm12,	%xmm0	# 0 = sb1t
++	 tbl	v8.16b,  {$sb1u}, v11.16b
++	eor	v4.16b,  v4.16b,  v16.16b	// vpxor	%xmm5,	%xmm4,	%xmm4	# 4 = sb1u + k
++	 eor	v12.16b, v12.16b, v16.16b
++	tbl	v5.16b,	 {$sb2t}, v2.16b	// vpshufb	%xmm2,	%xmm15,	%xmm5	# 4 = sb2u
++	 tbl	v13.16b, {$sb2t}, v10.16b
++	eor	v0.16b,  v0.16b,  v4.16b	// vpxor	%xmm4,	%xmm0,	%xmm0	# 0 = A
++	 eor	v8.16b,  v8.16b,  v12.16b
++	tbl	v2.16b,  {$sb2u}, v3.16b	// vpshufb	%xmm3,	%xmm14,	%xmm2	# 2 = sb2t
++	 tbl	v10.16b, {$sb2u}, v11.16b
++	ld1	{v4.2d}, [x10]			// vmovdqa	(%r11,%r10), %xmm4	# .Lk_mc_backward[]
++	tbl	v3.16b,  {v0.16b}, v1.16b	// vpshufb	%xmm1,	%xmm0,	%xmm3	# 0 = B
++	 tbl	v11.16b, {v8.16b}, v1.16b
++	eor	v2.16b,  v2.16b,  v5.16b	// vpxor	%xmm5,	%xmm2,	%xmm2	# 2 = 2A
++	 eor	v10.16b, v10.16b, v13.16b
++	tbl	v0.16b,  {v0.16b}, v4.16b	// vpshufb	%xmm4,	%xmm0,	%xmm0	# 3 = D
++	 tbl	v8.16b,  {v8.16b}, v4.16b
++	eor	v3.16b,  v3.16b,  v2.16b	// vpxor	%xmm2,	%xmm3,	%xmm3	# 0 = 2A+B
++	 eor	v11.16b, v11.16b, v10.16b
++	tbl	v4.16b,  {v3.16b}, v1.16b	// vpshufb	%xmm1,	%xmm3,	%xmm4	# 0 = 2B+C
++	 tbl	v12.16b, {v11.16b},v1.16b
++	eor	v0.16b,  v0.16b,  v3.16b	// vpxor	%xmm3,	%xmm0,	%xmm0	# 3 = 2A+B+D
++	 eor	v8.16b,  v8.16b,  v11.16b
++	and	x11, x11, #~(1<<6)		// and		\$0x30,	%r11		# ... mod 4
++	eor	v0.16b,  v0.16b,  v4.16b	// vpxor	%xmm4,	%xmm0, %xmm0	# 0 = 2A+3B+C+D
++	 eor	v8.16b,  v8.16b,  v12.16b
++	sub	w8, w8, #1			// nr--
++
++.Lenc_2x_entry:
++	// top of round
++	and	v1.16b,  v0.16b, v17.16b	// vpand	%xmm0,	%xmm9,	%xmm1   # 0 = k
++	ushr	v0.16b,  v0.16b, #4		// vpsrlb	\$4,	%xmm0,	%xmm0	# 1 = i
++	 and	v9.16b,  v8.16b, v17.16b
++	 ushr	v8.16b,  v8.16b, #4
++	tbl	v5.16b,  {$invhi},v1.16b	// vpshufb	%xmm1,	%xmm11,	%xmm5	# 2 = a/k
++	 tbl	v13.16b, {$invhi},v9.16b
++	eor	v1.16b,  v1.16b,  v0.16b	// vpxor	%xmm0,	%xmm1,	%xmm1	# 0 = j
++	 eor	v9.16b,  v9.16b,  v8.16b
++	tbl	v3.16b,  {$invlo},v0.16b	// vpshufb	%xmm0, 	%xmm10,	%xmm3  	# 3 = 1/i
++	 tbl	v11.16b, {$invlo},v8.16b
++	tbl	v4.16b,  {$invlo},v1.16b	// vpshufb	%xmm1, 	%xmm10,	%xmm4  	# 4 = 1/j
++	 tbl	v12.16b, {$invlo},v9.16b
++	eor	v3.16b,  v3.16b,  v5.16b	// vpxor	%xmm5,	%xmm3,	%xmm3	# 3 = iak = 1/i + a/k
++	 eor	v11.16b, v11.16b, v13.16b
++	eor	v4.16b,  v4.16b,  v5.16b	// vpxor	%xmm5,	%xmm4,	%xmm4  	# 4 = jak = 1/j + a/k
++	 eor	v12.16b, v12.16b, v13.16b
++	tbl	v2.16b,  {$invlo},v3.16b	// vpshufb	%xmm3,	%xmm10,	%xmm2  	# 2 = 1/iak
++	 tbl	v10.16b, {$invlo},v11.16b
++	tbl	v3.16b,  {$invlo},v4.16b	// vpshufb	%xmm4,	%xmm10,	%xmm3	# 3 = 1/jak
++	 tbl	v11.16b, {$invlo},v12.16b
++	eor	v2.16b,  v2.16b,  v1.16b	// vpxor	%xmm1,	%xmm2,	%xmm2  	# 2 = io
++	 eor	v10.16b, v10.16b, v9.16b
++	eor	v3.16b,  v3.16b,  v0.16b	// vpxor	%xmm0,	%xmm3,	%xmm3	# 3 = jo
++	 eor	v11.16b, v11.16b, v8.16b
++	ld1	{v16.2d}, [x9],#16		// vmovdqu	(%r9),	%xmm5
++	cbnz	w8, .Lenc_2x_loop
++
++	// middle of last round
++	add	x10, x11, #0x80
++						// vmovdqa	-0x60(%r10), %xmm4	# 3 : sbou	.Lk_sbo
++						// vmovdqa	-0x50(%r10), %xmm0	# 0 : sbot	.Lk_sbo+16
++	tbl	v4.16b,  {$sbou}, v2.16b	// vpshufb	%xmm2,	%xmm4,	%xmm4	# 4 = sbou
++	 tbl	v12.16b, {$sbou}, v10.16b
++	ld1	{v1.2d}, [x10]			// vmovdqa	0x40(%r11,%r10), %xmm1	# .Lk_sr[]
++	tbl	v0.16b,  {$sbot}, v3.16b	// vpshufb	%xmm3,	%xmm0,	%xmm0	# 0 = sb1t
++	 tbl	v8.16b,  {$sbot}, v11.16b
++	eor	v4.16b,  v4.16b,  v16.16b	// vpxor	%xmm5,	%xmm4,	%xmm4	# 4 = sb1u + k
++	 eor	v12.16b, v12.16b, v16.16b
++	eor	v0.16b,  v0.16b,  v4.16b	// vpxor	%xmm4,	%xmm0,	%xmm0	# 0 = A
++	 eor	v8.16b,  v8.16b,  v12.16b
++	tbl	v0.16b,  {v0.16b},v1.16b	// vpshufb	%xmm1,	%xmm0,	%xmm0
++	 tbl	v1.16b,  {v8.16b},v1.16b
++	ret
++.size	_vpaes_encrypt_2x,.-_vpaes_encrypt_2x
++
++.type	_vpaes_decrypt_preheat,%function
++.align	4
++_vpaes_decrypt_preheat:
++	adr	x10, .Lk_inv
++	movi	v17.16b, #0x0f
++	adr	x11, .Lk_dipt
++	ld1	{v18.2d-v19.2d}, [x10],#32	// .Lk_inv
++	ld1	{v20.2d-v23.2d}, [x11],#64	// .Lk_dipt, .Lk_dsbo
++	ld1	{v24.2d-v27.2d}, [x11],#64	// .Lk_dsb9, .Lk_dsbd
++	ld1	{v28.2d-v31.2d}, [x11]		// .Lk_dsbb, .Lk_dsbe
++	ret
++.size	_vpaes_decrypt_preheat,.-_vpaes_decrypt_preheat
++
++##
++##  Decryption core
++##
++##  Same API as encryption core.
++##
++.type	_vpaes_decrypt_core,%function
++.align	4
++_vpaes_decrypt_core:
++	mov	x9, $key
++	ldr	w8, [$key,#240]			// pull rounds
++
++						// vmovdqa	.Lk_dipt(%rip), %xmm2	# iptlo
++	lsl	x11, x8, #4			// mov	%rax,	%r11;	shl	\$4, %r11
++	eor	x11, x11, #0x30			// xor		\$0x30,	%r11
++	adr	x10, .Lk_sr
++	and	x11, x11, #0x30			// and		\$0x30,	%r11
++	add	x11, x11, x10
++	adr	x10, .Lk_mc_forward+48
++
++	ld1	{v16.2d}, [x9],#16		// vmovdqu	(%r9),	%xmm4		# round0 key
++	and	v1.16b, v7.16b, v17.16b		// vpand	%xmm9,	%xmm0,	%xmm1
++	ushr	v0.16b, v7.16b, #4		// vpsrlb	\$4,	%xmm0,	%xmm0
++	tbl	v2.16b, {$iptlo}, v1.16b	// vpshufb	%xmm1,	%xmm2,	%xmm2
++	ld1	{v5.2d}, [x10]			// vmovdqa	.Lk_mc_forward+48(%rip), %xmm5
++						// vmovdqa	.Lk_dipt+16(%rip), %xmm1 # ipthi
++	tbl	v0.16b, {$ipthi}, v0.16b	// vpshufb	%xmm0,	%xmm1,	%xmm0
++	eor	v2.16b, v2.16b, v16.16b		// vpxor	%xmm4,	%xmm2,	%xmm2
++	eor	v0.16b, v0.16b, v2.16b		// vpxor	%xmm2,	%xmm0,	%xmm0
++	b	.Ldec_entry
++
++.align 4
++.Ldec_loop:
++//
++//  Inverse mix columns
++//
++						// vmovdqa	-0x20(%r10),%xmm4		# 4 : sb9u
++						// vmovdqa	-0x10(%r10),%xmm1		# 0 : sb9t
++	tbl	v4.16b, {$sb9u}, v2.16b		// vpshufb	%xmm2,	%xmm4,	%xmm4		# 4 = sb9u
++	tbl	v1.16b, {$sb9t}, v3.16b		// vpshufb	%xmm3,	%xmm1,	%xmm1		# 0 = sb9t
++	eor	v0.16b, v4.16b, v16.16b		// vpxor	%xmm4,	%xmm0,	%xmm0
++						// vmovdqa	0x00(%r10),%xmm4		# 4 : sbdu
++	eor	v0.16b, v0.16b, v1.16b		// vpxor	%xmm1,	%xmm0,	%xmm0		# 0 = ch
++						// vmovdqa	0x10(%r10),%xmm1		# 0 : sbdt
++
++	tbl	v4.16b, {$sbdu}, v2.16b		// vpshufb	%xmm2,	%xmm4,	%xmm4		# 4 = sbdu
++	tbl 	v0.16b, {v0.16b}, v5.16b	// vpshufb	%xmm5,	%xmm0,	%xmm0		# MC ch
++	tbl	v1.16b, {$sbdt}, v3.16b		// vpshufb	%xmm3,	%xmm1,	%xmm1		# 0 = sbdt
++	eor	v0.16b, v0.16b, v4.16b		// vpxor	%xmm4,	%xmm0,	%xmm0		# 4 = ch
++						// vmovdqa	0x20(%r10),	%xmm4		# 4 : sbbu
++	eor	v0.16b, v0.16b, v1.16b		// vpxor	%xmm1,	%xmm0,	%xmm0		# 0 = ch
++						// vmovdqa	0x30(%r10),	%xmm1		# 0 : sbbt
++
++	tbl	v4.16b, {$sbbu}, v2.16b		// vpshufb	%xmm2,	%xmm4,	%xmm4		# 4 = sbbu
++	tbl	v0.16b, {v0.16b}, v5.16b	// vpshufb	%xmm5,	%xmm0,	%xmm0		# MC ch
++	tbl	v1.16b, {$sbbt}, v3.16b		// vpshufb	%xmm3,	%xmm1,	%xmm1		# 0 = sbbt
++	eor	v0.16b, v0.16b, v4.16b		// vpxor	%xmm4,	%xmm0,	%xmm0		# 4 = ch
++						// vmovdqa	0x40(%r10),	%xmm4		# 4 : sbeu
++	eor	v0.16b, v0.16b, v1.16b		// vpxor	%xmm1,	%xmm0,	%xmm0		# 0 = ch
++						// vmovdqa	0x50(%r10),	%xmm1		# 0 : sbet
++
++	tbl	v4.16b, {$sbeu}, v2.16b		// vpshufb	%xmm2,	%xmm4,	%xmm4		# 4 = sbeu
++	tbl	v0.16b, {v0.16b}, v5.16b	// vpshufb	%xmm5,	%xmm0,	%xmm0		# MC ch
++	tbl	v1.16b, {$sbet}, v3.16b		// vpshufb	%xmm3,	%xmm1,	%xmm1		# 0 = sbet
++	eor	v0.16b, v0.16b, v4.16b		// vpxor	%xmm4,	%xmm0,	%xmm0		# 4 = ch
++	ext	v5.16b, v5.16b, v5.16b, #12	// vpalignr \$12,	%xmm5,	%xmm5,	%xmm5
++	eor	v0.16b, v0.16b, v1.16b		// vpxor	%xmm1,	%xmm0,	%xmm0		# 0 = ch
++	sub	w8, w8, #1			// sub		\$1,%rax			# nr--
++
++.Ldec_entry:
++	// top of round
++	and	v1.16b, v0.16b, v17.16b		// vpand	%xmm9,	%xmm0,	%xmm1	# 0 = k
++	ushr	v0.16b, v0.16b, #4		// vpsrlb	\$4,	%xmm0,	%xmm0	# 1 = i
++	tbl	v2.16b, {$invhi}, v1.16b	// vpshufb	%xmm1,	%xmm11,	%xmm2	# 2 = a/k
++	eor	v1.16b,	v1.16b, v0.16b		// vpxor	%xmm0,	%xmm1,	%xmm1	# 0 = j
++	tbl	v3.16b, {$invlo}, v0.16b	// vpshufb	%xmm0, 	%xmm10,	%xmm3	# 3 = 1/i
++	tbl	v4.16b, {$invlo}, v1.16b	// vpshufb	%xmm1,	%xmm10,	%xmm4	# 4 = 1/j
++	eor	v3.16b, v3.16b, v2.16b		// vpxor	%xmm2,	%xmm3,	%xmm3	# 3 = iak = 1/i + a/k
++	eor	v4.16b, v4.16b, v2.16b		// vpxor	%xmm2, 	%xmm4,	%xmm4	# 4 = jak = 1/j + a/k
++	tbl	v2.16b, {$invlo}, v3.16b	// vpshufb	%xmm3,	%xmm10,	%xmm2	# 2 = 1/iak
++	tbl	v3.16b, {$invlo}, v4.16b	// vpshufb	%xmm4,  %xmm10,	%xmm3	# 3 = 1/jak
++	eor	v2.16b, v2.16b, v1.16b		// vpxor	%xmm1,	%xmm2,	%xmm2	# 2 = io
++	eor	v3.16b, v3.16b, v0.16b		// vpxor	%xmm0,  %xmm3,	%xmm3	# 3 = jo
++	ld1	{v16.2d}, [x9],#16		// vmovdqu	(%r9),	%xmm0
++	cbnz	w8, .Ldec_loop
++
++	// middle of last round
++						// vmovdqa	0x60(%r10),	%xmm4	# 3 : sbou
++	tbl	v4.16b, {$sbou}, v2.16b		// vpshufb	%xmm2,	%xmm4,	%xmm4	# 4 = sbou
++						// vmovdqa	0x70(%r10),	%xmm1	# 0 : sbot
++	ld1	{v2.2d}, [x11]			// vmovdqa	-0x160(%r11),	%xmm2	# .Lk_sr-.Lk_dsbd=-0x160
++	tbl	v1.16b, {$sbot}, v3.16b		// vpshufb	%xmm3,	%xmm1,	%xmm1	# 0 = sb1t
++	eor	v4.16b, v4.16b, v16.16b		// vpxor	%xmm0,	%xmm4,	%xmm4	# 4 = sb1u + k
++	eor	v0.16b, v1.16b, v4.16b		// vpxor	%xmm4,	%xmm1,	%xmm0	# 0 = A
++	tbl	v0.16b, {v0.16b}, v2.16b	// vpshufb	%xmm2,	%xmm0,	%xmm0
++	ret
++.size	_vpaes_decrypt_core,.-_vpaes_decrypt_core
++
++.globl	vpaes_decrypt
++.type	vpaes_decrypt,%function
++.align	4
++vpaes_decrypt:
++	stp	x29,x30,[sp,#-16]!
++	add	x29,sp,#0
++
++	ld1	{v7.16b}, [$inp]
++	bl	_vpaes_decrypt_preheat
++	bl	_vpaes_decrypt_core
++	st1	{v0.16b}, [$out]
++
++	ldp	x29,x30,[sp],#16
++	ret
++.size	vpaes_decrypt,.-vpaes_decrypt
++
++// v14-v15 input, v0-v1 output
++.type	_vpaes_decrypt_2x,%function
++.align	4
++_vpaes_decrypt_2x:
++	mov	x9, $key
++	ldr	w8, [$key,#240]			// pull rounds
++
++						// vmovdqa	.Lk_dipt(%rip), %xmm2	# iptlo
++	lsl	x11, x8, #4			// mov	%rax,	%r11;	shl	\$4, %r11
++	eor	x11, x11, #0x30			// xor		\$0x30,	%r11
++	adr	x10, .Lk_sr
++	and	x11, x11, #0x30			// and		\$0x30,	%r11
++	add	x11, x11, x10
++	adr	x10, .Lk_mc_forward+48
++
++	ld1	{v16.2d}, [x9],#16		// vmovdqu	(%r9),	%xmm4		# round0 key
++	and	v1.16b,  v14.16b, v17.16b	// vpand	%xmm9,	%xmm0,	%xmm1
++	ushr	v0.16b,  v14.16b, #4		// vpsrlb	\$4,	%xmm0,	%xmm0
++	 and	v9.16b,  v15.16b, v17.16b
++	 ushr	v8.16b,  v15.16b, #4
++	tbl	v2.16b,  {$iptlo},v1.16b	// vpshufb	%xmm1,	%xmm2,	%xmm2
++	 tbl	v10.16b, {$iptlo},v9.16b
++	ld1	{v5.2d}, [x10]			// vmovdqa	.Lk_mc_forward+48(%rip), %xmm5
++						// vmovdqa	.Lk_dipt+16(%rip), %xmm1 # ipthi
++	tbl	v0.16b,  {$ipthi},v0.16b	// vpshufb	%xmm0,	%xmm1,	%xmm0
++	 tbl	v8.16b,  {$ipthi},v8.16b
++	eor	v2.16b,  v2.16b,  v16.16b	// vpxor	%xmm4,	%xmm2,	%xmm2
++	 eor	v10.16b, v10.16b, v16.16b
++	eor	v0.16b,  v0.16b,  v2.16b	// vpxor	%xmm2,	%xmm0,	%xmm0
++	 eor	v8.16b,  v8.16b,  v10.16b
++	b	.Ldec_2x_entry
++
++.align 4
++.Ldec_2x_loop:
++//
++//  Inverse mix columns
++//
++						// vmovdqa	-0x20(%r10),%xmm4		# 4 : sb9u
++						// vmovdqa	-0x10(%r10),%xmm1		# 0 : sb9t
++	tbl	v4.16b,  {$sb9u}, v2.16b	// vpshufb	%xmm2,	%xmm4,	%xmm4		# 4 = sb9u
++	 tbl	v12.16b, {$sb9u}, v10.16b
++	tbl	v1.16b,  {$sb9t}, v3.16b	// vpshufb	%xmm3,	%xmm1,	%xmm1		# 0 = sb9t
++	 tbl	v9.16b,  {$sb9t}, v11.16b
++	eor	v0.16b,  v4.16b,  v16.16b	// vpxor	%xmm4,	%xmm0,	%xmm0
++	 eor	v8.16b,  v12.16b, v16.16b
++						// vmovdqa	0x00(%r10),%xmm4		# 4 : sbdu
++	eor	v0.16b,  v0.16b,  v1.16b	// vpxor	%xmm1,	%xmm0,	%xmm0		# 0 = ch
++	 eor	v8.16b,  v8.16b,  v9.16b	// vpxor	%xmm1,	%xmm0,	%xmm0		# 0 = ch
++						// vmovdqa	0x10(%r10),%xmm1		# 0 : sbdt
++
++	tbl	v4.16b,  {$sbdu}, v2.16b	// vpshufb	%xmm2,	%xmm4,	%xmm4		# 4 = sbdu
++	 tbl	v12.16b, {$sbdu}, v10.16b
++	tbl 	v0.16b,  {v0.16b},v5.16b	// vpshufb	%xmm5,	%xmm0,	%xmm0		# MC ch
++	 tbl 	v8.16b,  {v8.16b},v5.16b
++	tbl	v1.16b,  {$sbdt}, v3.16b	// vpshufb	%xmm3,	%xmm1,	%xmm1		# 0 = sbdt
++	 tbl	v9.16b,  {$sbdt}, v11.16b
++	eor	v0.16b,  v0.16b,  v4.16b	// vpxor	%xmm4,	%xmm0,	%xmm0		# 4 = ch
++	 eor	v8.16b,  v8.16b,  v12.16b
++						// vmovdqa	0x20(%r10),	%xmm4		# 4 : sbbu
++	eor	v0.16b,  v0.16b,  v1.16b	// vpxor	%xmm1,	%xmm0,	%xmm0		# 0 = ch
++	 eor	v8.16b,  v8.16b,  v9.16b
++						// vmovdqa	0x30(%r10),	%xmm1		# 0 : sbbt
++
++	tbl	v4.16b,  {$sbbu}, v2.16b	// vpshufb	%xmm2,	%xmm4,	%xmm4		# 4 = sbbu
++	 tbl	v12.16b, {$sbbu}, v10.16b
++	tbl	v0.16b,  {v0.16b},v5.16b	// vpshufb	%xmm5,	%xmm0,	%xmm0		# MC ch
++	 tbl	v8.16b,  {v8.16b},v5.16b
++	tbl	v1.16b,  {$sbbt}, v3.16b	// vpshufb	%xmm3,	%xmm1,	%xmm1		# 0 = sbbt
++	 tbl	v9.16b,  {$sbbt}, v11.16b
++	eor	v0.16b,  v0.16b,  v4.16b	// vpxor	%xmm4,	%xmm0,	%xmm0		# 4 = ch
++	 eor	v8.16b,  v8.16b,  v12.16b
++						// vmovdqa	0x40(%r10),	%xmm4		# 4 : sbeu
++	eor	v0.16b,  v0.16b,  v1.16b	// vpxor	%xmm1,	%xmm0,	%xmm0		# 0 = ch
++	 eor	v8.16b,  v8.16b,  v9.16b
++						// vmovdqa	0x50(%r10),	%xmm1		# 0 : sbet
++
++	tbl	v4.16b,  {$sbeu}, v2.16b	// vpshufb	%xmm2,	%xmm4,	%xmm4		# 4 = sbeu
++	 tbl	v12.16b, {$sbeu}, v10.16b
++	tbl	v0.16b,  {v0.16b},v5.16b	// vpshufb	%xmm5,	%xmm0,	%xmm0		# MC ch
++	 tbl	v8.16b,  {v8.16b},v5.16b
++	tbl	v1.16b,  {$sbet}, v3.16b	// vpshufb	%xmm3,	%xmm1,	%xmm1		# 0 = sbet
++	 tbl	v9.16b,  {$sbet}, v11.16b
++	eor	v0.16b,  v0.16b,  v4.16b	// vpxor	%xmm4,	%xmm0,	%xmm0		# 4 = ch
++	 eor	v8.16b,  v8.16b,  v12.16b
++	ext	v5.16b,  v5.16b,  v5.16b, #12	// vpalignr \$12,	%xmm5,	%xmm5,	%xmm5
++	eor	v0.16b,  v0.16b,  v1.16b	// vpxor	%xmm1,	%xmm0,	%xmm0		# 0 = ch
++	 eor	v8.16b,  v8.16b,  v9.16b
++	sub	w8, w8, #1			// sub		\$1,%rax			# nr--
++
++.Ldec_2x_entry:
++	// top of round
++	and	v1.16b,  v0.16b,  v17.16b	// vpand	%xmm9,	%xmm0,	%xmm1	# 0 = k
++	ushr	v0.16b,  v0.16b,  #4		// vpsrlb	\$4,	%xmm0,	%xmm0	# 1 = i
++	 and	v9.16b,  v8.16b,  v17.16b
++	 ushr	v8.16b,  v8.16b,  #4
++	tbl	v2.16b,  {$invhi},v1.16b	// vpshufb	%xmm1,	%xmm11,	%xmm2	# 2 = a/k
++	 tbl	v10.16b, {$invhi},v9.16b
++	eor	v1.16b,	 v1.16b,  v0.16b	// vpxor	%xmm0,	%xmm1,	%xmm1	# 0 = j
++	 eor	v9.16b,	 v9.16b,  v8.16b
++	tbl	v3.16b,  {$invlo},v0.16b	// vpshufb	%xmm0, 	%xmm10,	%xmm3	# 3 = 1/i
++	 tbl	v11.16b, {$invlo},v8.16b
++	tbl	v4.16b,  {$invlo},v1.16b	// vpshufb	%xmm1,	%xmm10,	%xmm4	# 4 = 1/j
++	 tbl	v12.16b, {$invlo},v9.16b
++	eor	v3.16b,  v3.16b,  v2.16b	// vpxor	%xmm2,	%xmm3,	%xmm3	# 3 = iak = 1/i + a/k
++	 eor	v11.16b, v11.16b, v10.16b
++	eor	v4.16b,  v4.16b,  v2.16b	// vpxor	%xmm2, 	%xmm4,	%xmm4	# 4 = jak = 1/j + a/k
++	 eor	v12.16b, v12.16b, v10.16b
++	tbl	v2.16b,  {$invlo},v3.16b	// vpshufb	%xmm3,	%xmm10,	%xmm2	# 2 = 1/iak
++	 tbl	v10.16b, {$invlo},v11.16b
++	tbl	v3.16b,  {$invlo},v4.16b	// vpshufb	%xmm4,  %xmm10,	%xmm3	# 3 = 1/jak
++	 tbl	v11.16b, {$invlo},v12.16b
++	eor	v2.16b,  v2.16b,  v1.16b	// vpxor	%xmm1,	%xmm2,	%xmm2	# 2 = io
++	 eor	v10.16b, v10.16b, v9.16b
++	eor	v3.16b,  v3.16b,  v0.16b	// vpxor	%xmm0,  %xmm3,	%xmm3	# 3 = jo
++	 eor	v11.16b, v11.16b, v8.16b
++	ld1	{v16.2d}, [x9],#16		// vmovdqu	(%r9),	%xmm0
++	cbnz	w8, .Ldec_2x_loop
++
++	// middle of last round
++						// vmovdqa	0x60(%r10),	%xmm4	# 3 : sbou
++	tbl	v4.16b,  {$sbou}, v2.16b	// vpshufb	%xmm2,	%xmm4,	%xmm4	# 4 = sbou
++	 tbl	v12.16b, {$sbou}, v10.16b
++						// vmovdqa	0x70(%r10),	%xmm1	# 0 : sbot
++	tbl	v1.16b,  {$sbot}, v3.16b	// vpshufb	%xmm3,	%xmm1,	%xmm1	# 0 = sb1t
++	 tbl	v9.16b,  {$sbot}, v11.16b
++	ld1	{v2.2d}, [x11]			// vmovdqa	-0x160(%r11),	%xmm2	# .Lk_sr-.Lk_dsbd=-0x160
++	eor	v4.16b,  v4.16b,  v16.16b	// vpxor	%xmm0,	%xmm4,	%xmm4	# 4 = sb1u + k
++	 eor	v12.16b, v12.16b, v16.16b
++	eor	v0.16b,  v1.16b,  v4.16b	// vpxor	%xmm4,	%xmm1,	%xmm0	# 0 = A
++	 eor	v8.16b,  v9.16b,  v12.16b
++	tbl	v0.16b,  {v0.16b},v2.16b	// vpshufb	%xmm2,	%xmm0,	%xmm0
++	 tbl	v1.16b,  {v8.16b},v2.16b
++	ret
++.size	_vpaes_decrypt_2x,.-_vpaes_decrypt_2x
++___
++}
++{
++my ($inp,$bits,$out,$dir)=("x0","w1","x2","w3");
++my ($invlo,$invhi,$iptlo,$ipthi,$rcon) = map("v$_.16b",(18..21,8));
++
++$code.=<<___;
++########################################################
++##                                                    ##
++##                  AES key schedule                  ##
++##                                                    ##
++########################################################
++.type	_vpaes_key_preheat,%function
++.align	4
++_vpaes_key_preheat:
++	adr	x10, .Lk_inv
++	movi	v16.16b, #0x5b			// .Lk_s63
++	adr	x11, .Lk_sb1
++	movi	v17.16b, #0x0f			// .Lk_s0F
++	ld1	{v18.2d-v21.2d}, [x10]		// .Lk_inv, .Lk_ipt
++	adr	x10, .Lk_dksd
++	ld1	{v22.2d-v23.2d}, [x11]		// .Lk_sb1
++	adr	x11, .Lk_mc_forward
++	ld1	{v24.2d-v27.2d}, [x10],#64	// .Lk_dksd, .Lk_dksb
++	ld1	{v28.2d-v31.2d}, [x10],#64	// .Lk_dkse, .Lk_dks9
++	ld1	{v8.2d}, [x10]			// .Lk_rcon
++	ld1	{v9.2d}, [x11]			// .Lk_mc_forward[0]
++	ret
++.size	_vpaes_key_preheat,.-_vpaes_key_preheat
++
++.type	_vpaes_schedule_core,%function
++.align	4
++_vpaes_schedule_core:
++	stp	x29, x30, [sp,#-16]!
++	add	x29,sp,#0
++
++	bl	_vpaes_key_preheat		// load the tables
++
++	ld1	{v0.16b}, [$inp],#16		// vmovdqu	(%rdi),	%xmm0		# load key (unaligned)
++
++	// input transform
++	mov	v3.16b, v0.16b			// vmovdqa	%xmm0,	%xmm3
++	bl	_vpaes_schedule_transform
++	mov	v7.16b, v0.16b			// vmovdqa	%xmm0,	%xmm7
++
++	adr	x10, .Lk_sr			// lea	.Lk_sr(%rip),%r10
++	add	x8, x8, x10
++	cbnz	$dir, .Lschedule_am_decrypting
++
++	// encrypting, output zeroth round key after transform
++	st1	{v0.2d}, [$out]			// vmovdqu	%xmm0,	(%rdx)
++	b	.Lschedule_go
++
++.Lschedule_am_decrypting:
++	// decrypting, output zeroth round key after shiftrows
++	ld1	{v1.2d}, [x8]			// vmovdqa	(%r8,%r10),	%xmm1
++	tbl	v3.16b, {v3.16b}, v1.16b	// vpshufb  %xmm1,	%xmm3,	%xmm3
++	st1	{v3.2d}, [$out]			// vmovdqu	%xmm3,	(%rdx)
++	eor	x8, x8, #0x30			// xor	\$0x30, %r8
++
++.Lschedule_go:
++	cmp	$bits, #192			// cmp	\$192,	%esi
++	b.hi	.Lschedule_256
++	b.eq	.Lschedule_192
++	// 128: fall though
++
++##
++##  .schedule_128
++##
++##  128-bit specific part of key schedule.
++##
++##  This schedule is really simple, because all its parts
++##  are accomplished by the subroutines.
++##
++.Lschedule_128:
++	mov	$inp, #10			// mov	\$10, %esi
++
++.Loop_schedule_128:
++	sub	$inp, $inp, #1			// dec	%esi
++	bl 	_vpaes_schedule_round
++	cbz 	$inp, .Lschedule_mangle_last
++	bl	_vpaes_schedule_mangle		// write output
++	b 	.Loop_schedule_128
++
++##
++##  .aes_schedule_192
++##
++##  192-bit specific part of key schedule.
++##
++##  The main body of this schedule is the same as the 128-bit
++##  schedule, but with more smearing.  The long, high side is
++##  stored in %xmm7 as before, and the short, low side is in
++##  the high bits of %xmm6.
++##
++##  This schedule is somewhat nastier, however, because each
++##  round produces 192 bits of key material, or 1.5 round keys.
++##  Therefore, on each cycle we do 2 rounds and produce 3 round
++##  keys.
++##
++.align	4
++.Lschedule_192:
++	sub	$inp, $inp, #8
++	ld1	{v0.16b}, [$inp]		// vmovdqu	8(%rdi),%xmm0		# load key part 2 (very unaligned)
++	bl	_vpaes_schedule_transform	// input transform
++	mov	v6.16b, v0.16b			// vmovdqa	%xmm0,	%xmm6		# save short part
++	eor	v4.16b, v4.16b, v4.16b		// vpxor	%xmm4,	%xmm4, %xmm4	# clear 4
++	ins	v6.d[0], v4.d[0]		// vmovhlps	%xmm4,	%xmm6,	%xmm6		# clobber low side with zeros
++	mov	$inp, #4			// mov	\$4,	%esi
++
++.Loop_schedule_192:
++	sub	$inp, $inp, #1			// dec	%esi
++	bl	_vpaes_schedule_round
++	ext	v0.16b, v6.16b, v0.16b, #8	// vpalignr	\$8,%xmm6,%xmm0,%xmm0
++	bl	_vpaes_schedule_mangle		// save key n
++	bl	_vpaes_schedule_192_smear
++	bl	_vpaes_schedule_mangle		// save key n+1
++	bl	_vpaes_schedule_round
++	cbz 	$inp, .Lschedule_mangle_last
++	bl	_vpaes_schedule_mangle		// save key n+2
++	bl	_vpaes_schedule_192_smear
++	b	.Loop_schedule_192
++
++##
++##  .aes_schedule_256
++##
++##  256-bit specific part of key schedule.
++##
++##  The structure here is very similar to the 128-bit
++##  schedule, but with an additional "low side" in
++##  %xmm6.  The low side's rounds are the same as the
++##  high side's, except no rcon and no rotation.
++##
++.align	4
++.Lschedule_256:
++	ld1	{v0.16b}, [$inp]		// vmovdqu	16(%rdi),%xmm0		# load key part 2 (unaligned)
++	bl	_vpaes_schedule_transform	// input transform
++	mov	$inp, #7			// mov	\$7, %esi
++	
++.Loop_schedule_256:
++	sub	$inp, $inp, #1			// dec	%esi
++	bl	_vpaes_schedule_mangle		// output low result
++	mov	v6.16b, v0.16b			// vmovdqa	%xmm0,	%xmm6		# save cur_lo in xmm6
++
++	// high round
++	bl	_vpaes_schedule_round
++	cbz 	$inp, .Lschedule_mangle_last
++	bl	_vpaes_schedule_mangle	
++
++	// low round. swap xmm7 and xmm6
++	dup	v0.4s, v0.s[3]			// vpshufd	\$0xFF,	%xmm0,	%xmm0
++	movi	v4.16b, #0
++	mov	v5.16b, v7.16b			// vmovdqa	%xmm7,	%xmm5
++	mov	v7.16b, v6.16b			// vmovdqa	%xmm6,	%xmm7
++	bl	_vpaes_schedule_low_round
++	mov	v7.16b, v5.16b			// vmovdqa	%xmm5,	%xmm7
++	
++	b	.Loop_schedule_256
++
++##
++##  .aes_schedule_mangle_last
++##
++##  Mangler for last round of key schedule
++##  Mangles %xmm0
++##    when encrypting, outputs out(%xmm0) ^ 63
++##    when decrypting, outputs unskew(%xmm0)
++##
++##  Always called right before return... jumps to cleanup and exits
++##
++.align	4
++.Lschedule_mangle_last:
++	// schedule last round key from xmm0
++	adr	x11, .Lk_deskew			// lea	.Lk_deskew(%rip),%r11	# prepare to deskew
++	cbnz	$dir, .Lschedule_mangle_last_dec
++
++	// encrypting
++	ld1	{v1.2d}, [x8]			// vmovdqa	(%r8,%r10),%xmm1
++	adr	x11, .Lk_opt			// lea	.Lk_opt(%rip),	%r11		# prepare to output transform
++	add	$out, $out, #32			// add	\$32,	%rdx
++	tbl	v0.16b, {v0.16b}, v1.16b	// vpshufb	%xmm1,	%xmm0,	%xmm0		# output permute
++
++.Lschedule_mangle_last_dec:
++	ld1	{v20.2d-v21.2d}, [x11]		// reload constants
++	sub	$out, $out, #16			// add	\$-16,	%rdx 
++	eor	v0.16b, v0.16b, v16.16b		// vpxor	.Lk_s63(%rip),	%xmm0,	%xmm0
++	bl	_vpaes_schedule_transform	// output transform
++	st1	{v0.2d}, [$out]			// vmovdqu	%xmm0,	(%rdx)		# save last key
++
++	// cleanup
++	eor	v0.16b, v0.16b, v0.16b		// vpxor	%xmm0,	%xmm0,	%xmm0
++	eor	v1.16b, v1.16b, v1.16b		// vpxor	%xmm1,	%xmm1,	%xmm1
++	eor	v2.16b, v2.16b, v2.16b		// vpxor	%xmm2,	%xmm2,	%xmm2
++	eor	v3.16b, v3.16b, v3.16b		// vpxor	%xmm3,	%xmm3,	%xmm3
++	eor	v4.16b, v4.16b, v4.16b		// vpxor	%xmm4,	%xmm4,	%xmm4
++	eor	v5.16b, v5.16b, v5.16b		// vpxor	%xmm5,	%xmm5,	%xmm5
++	eor	v6.16b, v6.16b, v6.16b		// vpxor	%xmm6,	%xmm6,	%xmm6
++	eor	v7.16b, v7.16b, v7.16b		// vpxor	%xmm7,	%xmm7,	%xmm7
++	ldp	x29, x30, [sp],#16
++	ret
++.size	_vpaes_schedule_core,.-_vpaes_schedule_core
++
++##
++##  .aes_schedule_192_smear
++##
++##  Smear the short, low side in the 192-bit key schedule.
++##
++##  Inputs:
++##    %xmm7: high side, b  a  x  y
++##    %xmm6:  low side, d  c  0  0
++##    %xmm13: 0
++##
++##  Outputs:
++##    %xmm6: b+c+d  b+c  0  0
++##    %xmm0: b+c+d  b+c  b  a
++##
++.type	_vpaes_schedule_192_smear,%function
++.align	4
++_vpaes_schedule_192_smear:
++	movi	v1.16b, #0
++	dup	v0.4s, v7.s[3]
++	ins	v1.s[3], v6.s[2]	// vpshufd	\$0x80,	%xmm6,	%xmm1	# d c 0 0 -> c 0 0 0
++	ins	v0.s[0], v7.s[2]	// vpshufd	\$0xFE,	%xmm7,	%xmm0	# b a _ _ -> b b b a
++	eor	v6.16b, v6.16b, v1.16b	// vpxor	%xmm1,	%xmm6,	%xmm6	# -> c+d c 0 0
++	eor	v1.16b, v1.16b, v1.16b	// vpxor	%xmm1,	%xmm1,	%xmm1
++	eor	v6.16b, v6.16b, v0.16b	// vpxor	%xmm0,	%xmm6,	%xmm6	# -> b+c+d b+c b a
++	mov	v0.16b, v6.16b		// vmovdqa	%xmm6,	%xmm0
++	ins	v6.d[0], v1.d[0]	// vmovhlps	%xmm1,	%xmm6,	%xmm6	# clobber low side with zeros
++	ret
++.size	_vpaes_schedule_192_smear,.-_vpaes_schedule_192_smear
++
++##
++##  .aes_schedule_round
++##
++##  Runs one main round of the key schedule on %xmm0, %xmm7
++##
++##  Specifically, runs subbytes on the high dword of %xmm0
++##  then rotates it by one byte and xors into the low dword of
++##  %xmm7.
++##
++##  Adds rcon from low byte of %xmm8, then rotates %xmm8 for
++##  next rcon.
++##
++##  Smears the dwords of %xmm7 by xoring the low into the
++##  second low, result into third, result into highest.
++##
++##  Returns results in %xmm7 = %xmm0.
++##  Clobbers %xmm1-%xmm4, %r11.
++##
++.type	_vpaes_schedule_round,%function
++.align	4
++_vpaes_schedule_round:
++	// extract rcon from xmm8
++	movi	v4.16b, #0			// vpxor	%xmm4,	%xmm4,	%xmm4
++	ext	v1.16b, $rcon, v4.16b, #15	// vpalignr	\$15,	%xmm8,	%xmm4,	%xmm1
++	ext	$rcon, $rcon, $rcon, #15	// vpalignr	\$15,	%xmm8,	%xmm8,	%xmm8
++	eor	v7.16b, v7.16b, v1.16b		// vpxor	%xmm1,	%xmm7,	%xmm7
++
++	// rotate
++	dup	v0.4s, v0.s[3]			// vpshufd	\$0xFF,	%xmm0,	%xmm0
++	ext	v0.16b, v0.16b, v0.16b, #1	// vpalignr	\$1,	%xmm0,	%xmm0,	%xmm0
++
++	// fall through...
++
++	// low round: same as high round, but no rotation and no rcon.
++_vpaes_schedule_low_round:
++	// smear xmm7
++	ext	v1.16b, v4.16b, v7.16b, #12	// vpslldq	\$4,	%xmm7,	%xmm1
++	eor	v7.16b, v7.16b, v1.16b		// vpxor	%xmm1,	%xmm7,	%xmm7
++	ext	v4.16b, v4.16b, v7.16b, #8	// vpslldq	\$8,	%xmm7,	%xmm4
++
++	// subbytes
++	and	v1.16b, v0.16b, v17.16b		// vpand	%xmm9,	%xmm0,	%xmm1		# 0 = k
++	ushr	v0.16b, v0.16b, #4		// vpsrlb	\$4,	%xmm0,	%xmm0		# 1 = i
++	 eor	v7.16b, v7.16b, v4.16b		// vpxor	%xmm4,	%xmm7,	%xmm7
++	tbl	v2.16b, {$invhi}, v1.16b	// vpshufb	%xmm1,	%xmm11,	%xmm2		# 2 = a/k
++	eor	v1.16b, v1.16b, v0.16b		// vpxor	%xmm0,	%xmm1,	%xmm1		# 0 = j
++	tbl	v3.16b, {$invlo}, v0.16b	// vpshufb	%xmm0, 	%xmm10,	%xmm3		# 3 = 1/i
++	eor	v3.16b, v3.16b, v2.16b		// vpxor	%xmm2,	%xmm3,	%xmm3		# 3 = iak = 1/i + a/k
++	tbl	v4.16b, {$invlo}, v1.16b	// vpshufb	%xmm1,	%xmm10,	%xmm4		# 4 = 1/j
++	 eor	v7.16b, v7.16b, v16.16b		// vpxor	.Lk_s63(%rip),	%xmm7,	%xmm7
++	tbl	v3.16b, {$invlo}, v3.16b	// vpshufb	%xmm3,	%xmm10,	%xmm3		# 2 = 1/iak
++	eor	v4.16b, v4.16b, v2.16b		// vpxor	%xmm2,	%xmm4,	%xmm4		# 4 = jak = 1/j + a/k
++	tbl	v2.16b, {$invlo}, v4.16b	// vpshufb	%xmm4,	%xmm10,	%xmm2		# 3 = 1/jak
++	eor	v3.16b, v3.16b, v1.16b		// vpxor	%xmm1,	%xmm3,	%xmm3		# 2 = io
++	eor	v2.16b, v2.16b, v0.16b		// vpxor	%xmm0,	%xmm2,	%xmm2		# 3 = jo
++	tbl	v4.16b, {v23.16b}, v3.16b	// vpshufb	%xmm3,	%xmm13,	%xmm4		# 4 = sbou
++	tbl	v1.16b, {v22.16b}, v2.16b	// vpshufb	%xmm2,	%xmm12,	%xmm1		# 0 = sb1t
++	eor	v1.16b, v1.16b, v4.16b		// vpxor	%xmm4,	%xmm1,	%xmm1		# 0 = sbox output
++
++	// add in smeared stuff
++	eor	v0.16b, v1.16b, v7.16b		// vpxor	%xmm7,	%xmm1,	%xmm0
++	eor	v7.16b, v1.16b, v7.16b		// vmovdqa	%xmm0,	%xmm7
++	ret
++.size	_vpaes_schedule_round,.-_vpaes_schedule_round
++
++##
++##  .aes_schedule_transform
++##
++##  Linear-transform %xmm0 according to tables at (%r11)
++##
++##  Requires that %xmm9 = 0x0F0F... as in preheat
++##  Output in %xmm0
++##  Clobbers %xmm1, %xmm2
++##
++.type	_vpaes_schedule_transform,%function
++.align	4
++_vpaes_schedule_transform:
++	and	v1.16b, v0.16b, v17.16b		// vpand	%xmm9,	%xmm0,	%xmm1
++	ushr	v0.16b, v0.16b, #4		// vpsrlb	\$4,	%xmm0,	%xmm0
++						// vmovdqa	(%r11),	%xmm2 	# lo
++	tbl	v2.16b, {$iptlo}, v1.16b	// vpshufb	%xmm1,	%xmm2,	%xmm2
++						// vmovdqa	16(%r11),	%xmm1 # hi
++	tbl	v0.16b, {$ipthi}, v0.16b	// vpshufb	%xmm0,	%xmm1,	%xmm0
++	eor	v0.16b, v0.16b, v2.16b		// vpxor	%xmm2,	%xmm0,	%xmm0
++	ret
++.size	_vpaes_schedule_transform,.-_vpaes_schedule_transform
++
++##
++##  .aes_schedule_mangle
++##
++##  Mangle xmm0 from (basis-transformed) standard version
++##  to our version.
++##
++##  On encrypt,
++##    xor with 0x63
++##    multiply by circulant 0,1,1,1
++##    apply shiftrows transform
++##
++##  On decrypt,
++##    xor with 0x63
++##    multiply by "inverse mixcolumns" circulant E,B,D,9
++##    deskew
++##    apply shiftrows transform
++##
++##
++##  Writes out to (%rdx), and increments or decrements it
++##  Keeps track of round number mod 4 in %r8
++##  Preserves xmm0
++##  Clobbers xmm1-xmm5
++##
++.type	_vpaes_schedule_mangle,%function
++.align	4
++_vpaes_schedule_mangle:
++	mov	v4.16b, v0.16b			// vmovdqa	%xmm0,	%xmm4	# save xmm0 for later
++						// vmovdqa	.Lk_mc_forward(%rip),%xmm5
++	cbnz	$dir, .Lschedule_mangle_dec
++
++	// encrypting
++	eor	v4.16b, v0.16b, v16.16b		// vpxor	.Lk_s63(%rip),	%xmm0,	%xmm4
++	add	$out, $out, #16			// add	\$16,	%rdx
++	tbl	v4.16b, {v4.16b}, v9.16b	// vpshufb	%xmm5,	%xmm4,	%xmm4
++	tbl	v1.16b, {v4.16b}, v9.16b	// vpshufb	%xmm5,	%xmm4,	%xmm1
++	tbl	v3.16b, {v1.16b}, v9.16b	// vpshufb	%xmm5,	%xmm1,	%xmm3
++	eor	v4.16b, v4.16b, v1.16b		// vpxor	%xmm1,	%xmm4,	%xmm4
++	ld1	{v1.2d}, [x8]			// vmovdqa	(%r8,%r10),	%xmm1
++	eor	v3.16b, v3.16b, v4.16b		// vpxor	%xmm4,	%xmm3,	%xmm3
++
++	b	.Lschedule_mangle_both
++.align	4
++.Lschedule_mangle_dec:
++	// inverse mix columns
++						// lea	.Lk_dksd(%rip),%r11
++	ushr	v1.16b, v4.16b, #4		// vpsrlb	\$4,	%xmm4,	%xmm1	# 1 = hi
++	and	v4.16b, v4.16b, v17.16b		// vpand	%xmm9,	%xmm4,	%xmm4	# 4 = lo
++
++						// vmovdqa	0x00(%r11),	%xmm2
++	tbl	v2.16b, {v24.16b}, v4.16b	// vpshufb	%xmm4,	%xmm2,	%xmm2
++						// vmovdqa	0x10(%r11),	%xmm3
++	tbl	v3.16b,	{v25.16b}, v1.16b	// vpshufb	%xmm1,	%xmm3,	%xmm3
++	eor	v3.16b, v3.16b, v2.16b		// vpxor	%xmm2,	%xmm3,	%xmm3
++	tbl	v3.16b, {v3.16b}, v9.16b	// vpshufb	%xmm5,	%xmm3,	%xmm3
++
++						// vmovdqa	0x20(%r11),	%xmm2
++	tbl	v2.16b, {v26.16b}, v4.16b	// vpshufb	%xmm4,	%xmm2,	%xmm2
++	eor	v2.16b, v2.16b, v3.16b		// vpxor	%xmm3,	%xmm2,	%xmm2
++						// vmovdqa	0x30(%r11),	%xmm3
++	tbl	v3.16b, {v27.16b}, v1.16b	// vpshufb	%xmm1,	%xmm3,	%xmm3
++	eor	v3.16b, v3.16b, v2.16b		// vpxor	%xmm2,	%xmm3,	%xmm3
++	tbl	v3.16b, {v3.16b}, v9.16b	// vpshufb	%xmm5,	%xmm3,	%xmm3
++
++						// vmovdqa	0x40(%r11),	%xmm2
++	tbl	v2.16b, {v28.16b}, v4.16b	// vpshufb	%xmm4,	%xmm2,	%xmm2
++	eor	v2.16b, v2.16b, v3.16b		// vpxor	%xmm3,	%xmm2,	%xmm2
++						// vmovdqa	0x50(%r11),	%xmm3
++	tbl	v3.16b, {v29.16b}, v1.16b	// vpshufb	%xmm1,	%xmm3,	%xmm3
++	eor	v3.16b, v3.16b, v2.16b		// vpxor	%xmm2,	%xmm3,	%xmm3
++
++						// vmovdqa	0x60(%r11),	%xmm2
++	tbl	v2.16b, {v30.16b}, v4.16b	// vpshufb	%xmm4,	%xmm2,	%xmm2
++	tbl	v3.16b, {v3.16b}, v9.16b	// vpshufb	%xmm5,	%xmm3,	%xmm3
++						// vmovdqa	0x70(%r11),	%xmm4
++	tbl	v4.16b, {v31.16b}, v1.16b	// vpshufb	%xmm1,	%xmm4,	%xmm4
++	ld1	{v1.2d}, [x8]			// vmovdqa	(%r8,%r10),	%xmm1
++	eor	v2.16b, v2.16b, v3.16b		// vpxor	%xmm3,	%xmm2,	%xmm2
++	eor	v3.16b, v4.16b, v2.16b		// vpxor	%xmm2,	%xmm4,	%xmm3
++
++	sub	$out, $out, #16			// add	\$-16,	%rdx
++
++.Lschedule_mangle_both:
++	tbl	v3.16b, {v3.16b}, v1.16b	// vpshufb	%xmm1,	%xmm3,	%xmm3
++	add	x8, x8, #64-16			// add	\$-16,	%r8
++	and	x8, x8, #~(1<<6)		// and	\$0x30,	%r8
++	st1	{v3.2d}, [$out]			// vmovdqu	%xmm3,	(%rdx)
++	ret
++.size	_vpaes_schedule_mangle,.-_vpaes_schedule_mangle
++
++.globl	vpaes_set_encrypt_key
++.type	vpaes_set_encrypt_key,%function
++.align	4
++vpaes_set_encrypt_key:
++	stp	x29,x30,[sp,#-16]!
++	add	x29,sp,#0
++	stp	d8,d9,[sp,#-16]!	// ABI spec says so
++
++	lsr	w9, $bits, #5		// shr	\$5,%eax
++	add	w9, w9, #5		// \$5,%eax
++	str	w9, [$out,#240]		// mov	%eax,240(%rdx)	# AES_KEY->rounds = nbits/32+5;
++
++	mov	$dir, #0		// mov	\$0,%ecx
++	mov	x8, #0x30		// mov	\$0x30,%r8d
++	bl	_vpaes_schedule_core
++	eor	x0, x0, x0
++
++	ldp	d8,d9,[sp],#16
++	ldp	x29,x30,[sp],#16
++	ret
++.size	vpaes_set_encrypt_key,.-vpaes_set_encrypt_key
++
++.globl	vpaes_set_decrypt_key
++.type	vpaes_set_decrypt_key,%function
++.align	4
++vpaes_set_decrypt_key:
++	stp	x29,x30,[sp,#-16]!
++	add	x29,sp,#0
++	stp	d8,d9,[sp,#-16]!	// ABI spec says so
++
++	lsr	w9, $bits, #5		// shr	\$5,%eax
++	add	w9, w9, #5		// \$5,%eax
++	str	w9, [$out,#240]		// mov	%eax,240(%rdx)	# AES_KEY->rounds = nbits/32+5;
++	lsl	w9, w9, #4		// shl	\$4,%eax
++	add	$out, $out, #16		// lea	16(%rdx,%rax),%rdx
++	add	$out, $out, x9
++
++	mov	$dir, #1		// mov	\$1,%ecx
++	lsr	w8, $bits, #1		// shr	\$1,%r8d
++	and	x8, x8, #32		// and	\$32,%r8d
++	eor	x8, x8, #32		// xor	\$32,%r8d	# nbits==192?0:32
++	bl	_vpaes_schedule_core
++
++	ldp	d8,d9,[sp],#16
++	ldp	x29,x30,[sp],#16
++	ret
++.size	vpaes_set_decrypt_key,.-vpaes_set_decrypt_key
++___
++}
++{
++my ($inp,$out,$len,$key,$ivec,$dir) = map("x$_",(0..5));
++
++$code.=<<___;
++.globl	vpaes_cbc_encrypt
++.type	vpaes_cbc_encrypt,%function
++.align	4
++vpaes_cbc_encrypt:
++	cbz	$len, .Lcbc_abort
++	cmp	w5, #0			// check direction
++	b.eq	vpaes_cbc_decrypt
++
++	stp	x29,x30,[sp,#-16]!
++	add	x29,sp,#0
++
++	mov	x17, $len		// reassign
++	mov	x2,  $key		// reassign
++
++	ld1	{v0.16b}, [$ivec]	// load ivec
++	bl	_vpaes_encrypt_preheat
++	b	.Lcbc_enc_loop
++
++.align	4
++.Lcbc_enc_loop:
++	ld1	{v7.16b}, [$inp],#16	// load input
++	eor	v7.16b, v7.16b, v0.16b	// xor with ivec
++	bl	_vpaes_encrypt_core
++	st1	{v0.16b}, [$out],#16	// save output
++	subs	x17, x17, #16
++	b.hi	.Lcbc_enc_loop
++
++	st1	{v0.16b}, [$ivec]	// write ivec
++
++	ldp	x29,x30,[sp],#16
++.Lcbc_abort:
++	ret
++.size	vpaes_cbc_encrypt,.-vpaes_cbc_encrypt
++
++.type	vpaes_cbc_decrypt,%function
++.align	4
++vpaes_cbc_decrypt:
++	stp	x29,x30,[sp,#-16]!
++	add	x29,sp,#0
++	stp	d8,d9,[sp,#-16]!	// ABI spec says so
++	stp	d10,d11,[sp,#-16]!
++	stp	d12,d13,[sp,#-16]!
++	stp	d14,d15,[sp,#-16]!
++
++	mov	x17, $len		// reassign
++	mov	x2,  $key		// reassign
++	ld1	{v6.16b}, [$ivec]	// load ivec
++	bl	_vpaes_decrypt_preheat
++	tst	x17, #16
++	b.eq	.Lcbc_dec_loop2x
++
++	ld1	{v7.16b}, [$inp], #16	// load input
++	bl	_vpaes_decrypt_core
++	eor	v0.16b, v0.16b, v6.16b	// xor with ivec
++	orr	v6.16b, v7.16b, v7.16b	// next ivec value
++	st1	{v0.16b}, [$out], #16
++	subs	x17, x17, #16
++	b.ls	.Lcbc_dec_done
++
++.align	4
++.Lcbc_dec_loop2x:
++	ld1	{v14.16b,v15.16b}, [$inp], #32
++	bl	_vpaes_decrypt_2x
++	eor	v0.16b, v0.16b, v6.16b	// xor with ivec
++	eor	v1.16b, v1.16b, v14.16b
++	orr	v6.16b, v15.16b, v15.16b
++	st1	{v0.16b,v1.16b}, [$out], #32
++	subs	x17, x17, #32
++	b.hi	.Lcbc_dec_loop2x
++
++.Lcbc_dec_done:
++	st1	{v6.16b}, [$ivec]
++
++	ldp	d14,d15,[sp],#16
++	ldp	d12,d13,[sp],#16
++	ldp	d10,d11,[sp],#16
++	ldp	d8,d9,[sp],#16
++	ldp	x29,x30,[sp],#16
++	ret
++.size	vpaes_cbc_decrypt,.-vpaes_cbc_decrypt
++___
++if (1) {
++$code.=<<___;
++.globl	vpaes_ecb_encrypt
++.type	vpaes_ecb_encrypt,%function
++.align	4
++vpaes_ecb_encrypt:
++	stp	x29,x30,[sp,#-16]!
++	add	x29,sp,#0
++	stp	d8,d9,[sp,#-16]!	// ABI spec says so
++	stp	d10,d11,[sp,#-16]!
++	stp	d12,d13,[sp,#-16]!
++	stp	d14,d15,[sp,#-16]!
++
++	mov	x17, $len
++	mov	x2,  $key
++	bl	_vpaes_encrypt_preheat
++	tst	x17, #16
++	b.eq	.Lecb_enc_loop
++
++	ld1	{v7.16b}, [$inp],#16
++	bl	_vpaes_encrypt_core
++	st1	{v0.16b}, [$out],#16
++	subs	x17, x17, #16
++	b.ls	.Lecb_enc_done
++
++.align	4
++.Lecb_enc_loop:
++	ld1	{v14.16b,v15.16b}, [$inp], #32
++	bl	_vpaes_encrypt_2x
++	st1	{v0.16b,v1.16b}, [$out], #32
++	subs	x17, x17, #32
++	b.hi	.Lecb_enc_loop
++
++.Lecb_enc_done:
++	ldp	d14,d15,[sp],#16
++	ldp	d12,d13,[sp],#16
++	ldp	d10,d11,[sp],#16
++	ldp	d8,d9,[sp],#16
++	ldp	x29,x30,[sp],#16
++	ret
++.size	vpaes_ecb_encrypt,.-vpaes_ecb_encrypt
++
++.globl	vpaes_ecb_decrypt
++.type	vpaes_ecb_decrypt,%function
++.align	4
++vpaes_ecb_decrypt:
++	stp	x29,x30,[sp,#-16]!
++	add	x29,sp,#0
++	stp	d8,d9,[sp,#-16]!	// ABI spec says so
++	stp	d10,d11,[sp,#-16]!
++	stp	d12,d13,[sp,#-16]!
++	stp	d14,d15,[sp,#-16]!
++
++	mov	x17, $len
++	mov	x2,  $key
++	bl	_vpaes_decrypt_preheat
++	tst	x17, #16
++	b.eq	.Lecb_dec_loop
++
++	ld1	{v7.16b}, [$inp],#16
++	bl	_vpaes_encrypt_core
++	st1	{v0.16b}, [$out],#16
++	subs	x17, x17, #16
++	b.ls	.Lecb_dec_done
++
++.align	4
++.Lecb_dec_loop:
++	ld1	{v14.16b,v15.16b}, [$inp], #32
++	bl	_vpaes_decrypt_2x
++	st1	{v0.16b,v1.16b}, [$out], #32
++	subs	x17, x17, #32
++	b.hi	.Lecb_dec_loop
++
++.Lecb_dec_done:
++	ldp	d14,d15,[sp],#16
++	ldp	d12,d13,[sp],#16
++	ldp	d10,d11,[sp],#16
++	ldp	d8,d9,[sp],#16
++	ldp	x29,x30,[sp],#16
++	ret
++.size	vpaes_ecb_decrypt,.-vpaes_ecb_decrypt
++___
++}	}
++print $code;
++
++close STDOUT;
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/aes/asm/vpaes-ppc.pl b/CryptoPkg/Library/OpensslLib/openssl/crypto/aes/asm/vpaes-ppc.pl
+new file mode 100644
+index 0000000..bb38fbe
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/aes/asm/vpaes-ppc.pl
+@@ -0,0 +1,1594 @@
++#! /usr/bin/env perl
++# Copyright 2013-2016 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
++# in the file LICENSE in the source distribution or at
++# https://www.openssl.org/source/license.html
++
++
++######################################################################
++## Constant-time SSSE3 AES core implementation.
++## version 0.1
++##
++## By Mike Hamburg (Stanford University), 2009
++## Public domain.
++##
++## For details see http://shiftleft.org/papers/vector_aes/ and
++## http://crypto.stanford.edu/vpaes/.
++
++# CBC encrypt/decrypt performance in cycles per byte processed with
++# 128-bit key.
++#
++#		aes-ppc.pl		this
++# PPC74x0/G4e	35.5/52.1/(23.8)	11.9(*)/15.4
++# PPC970/G5	37.9/55.0/(28.5)	22.2/28.5
++# POWER6	42.7/54.3/(28.2)	63.0/92.8(**)
++# POWER7	32.3/42.9/(18.4)	18.5/23.3
++#
++# (*)	This is ~10% worse than reported in paper. The reason is
++#	twofold. This module doesn't make any assumption about
++#	key schedule (or data for that matter) alignment and handles
++#	it in-line. Secondly it, being transliterated from
++#	vpaes-x86_64.pl, relies on "nested inversion" better suited
++#	for Intel CPUs.
++# (**)	Inadequate POWER6 performance is due to astronomic AltiVec
++#	latency, 9 cycles per simple logical operation.
++
++$flavour = shift;
++
++if ($flavour =~ /64/) {
++	$SIZE_T	=8;
++	$LRSAVE	=2*$SIZE_T;
++	$STU	="stdu";
++	$POP	="ld";
++	$PUSH	="std";
++	$UCMP	="cmpld";
++} elsif ($flavour =~ /32/) {
++	$SIZE_T	=4;
++	$LRSAVE	=$SIZE_T;
++	$STU	="stwu";
++	$POP	="lwz";
++	$PUSH	="stw";
++	$UCMP	="cmplw";
++} else { die "nonsense $flavour"; }
++
++$sp="r1";
++$FRAME=6*$SIZE_T+13*16;	# 13*16 is for v20-v31 offload
++
++$0 =~ m/(.*[\/\\])[^\/\\]+$/; $dir=$1;
++( $xlate="${dir}ppc-xlate.pl" and -f $xlate ) or
++( $xlate="${dir}../../perlasm/ppc-xlate.pl" and -f $xlate) or
++die "can't locate ppc-xlate.pl";
++
++open STDOUT,"| $^X $xlate $flavour ".shift || die "can't call $xlate: $!";
++
++$code.=<<___;
++.machine	"any"
++
++.text
++
++.align	7	# totally strategic alignment
++_vpaes_consts:
++Lk_mc_forward:	# mc_forward
++	.long	0x01020300, 0x05060704, 0x090a0b08, 0x0d0e0f0c	?inv
++	.long	0x05060704, 0x090a0b08, 0x0d0e0f0c, 0x01020300	?inv
++	.long	0x090a0b08, 0x0d0e0f0c, 0x01020300, 0x05060704	?inv
++	.long	0x0d0e0f0c, 0x01020300, 0x05060704, 0x090a0b08	?inv
++Lk_mc_backward:	# mc_backward
++	.long	0x03000102, 0x07040506, 0x0b08090a, 0x0f0c0d0e	?inv
++	.long	0x0f0c0d0e, 0x03000102, 0x07040506, 0x0b08090a	?inv
++	.long	0x0b08090a, 0x0f0c0d0e, 0x03000102, 0x07040506	?inv
++	.long	0x07040506, 0x0b08090a, 0x0f0c0d0e, 0x03000102	?inv
++Lk_sr:		# sr
++	.long	0x00010203, 0x04050607, 0x08090a0b, 0x0c0d0e0f	?inv
++	.long	0x00050a0f, 0x04090e03, 0x080d0207, 0x0c01060b	?inv
++	.long	0x0009020b, 0x040d060f, 0x08010a03, 0x0c050e07	?inv
++	.long	0x000d0a07, 0x04010e0b, 0x0805020f, 0x0c090603	?inv
++
++##
++## "Hot" constants
++##
++Lk_inv:		# inv, inva
++	.long	0xf001080d, 0x0f06050e, 0x020c0b0a, 0x09030704	?rev
++	.long	0xf0070b0f, 0x060a0401, 0x09080502, 0x0c0e0d03	?rev
++Lk_ipt:		# input transform (lo, hi)
++	.long	0x00702a5a, 0x98e8b2c2, 0x08782252, 0x90e0baca	?rev
++	.long	0x004d7c31, 0x7d30014c, 0x81ccfdb0, 0xfcb180cd	?rev
++Lk_sbo:		# sbou, sbot
++	.long	0x00c7bd6f, 0x176dd2d0, 0x78a802c5, 0x7abfaa15	?rev
++	.long	0x006abb5f, 0xa574e4cf, 0xfa352b41, 0xd1901e8e	?rev
++Lk_sb1:		# sb1u, sb1t
++	.long	0x0023e2fa, 0x15d41836, 0xefd92e0d, 0xc1ccf73b	?rev
++	.long	0x003e50cb, 0x8fe19bb1, 0x44f52a14, 0x6e7adfa5	?rev
++Lk_sb2:		# sb2u, sb2t
++	.long	0x0029e10a, 0x4088eb69, 0x4a2382ab, 0xc863a1c2	?rev
++	.long	0x0024710b, 0xc6937ae2, 0xcd2f98bc, 0x55e9b75e	?rev
++
++##
++##  Decryption stuff
++##
++Lk_dipt:	# decryption input transform
++	.long	0x005f540b, 0x045b500f, 0x1a454e11, 0x1e414a15	?rev
++	.long	0x00650560, 0xe683e386, 0x94f191f4, 0x72177712	?rev
++Lk_dsbo:	# decryption sbox final output
++	.long	0x0040f97e, 0x53ea8713, 0x2d3e94d4, 0xb96daac7	?rev
++	.long	0x001d4493, 0x0f56d712, 0x9c8ec5d8, 0x59814bca	?rev
++Lk_dsb9:	# decryption sbox output *9*u, *9*t
++	.long	0x00d6869a, 0x53031c85, 0xc94c994f, 0x501fd5ca	?rev
++	.long	0x0049d7ec, 0x89173bc0, 0x65a5fbb2, 0x9e2c5e72	?rev
++Lk_dsbd:	# decryption sbox output *D*u, *D*t
++	.long	0x00a2b1e6, 0xdfcc577d, 0x39442a88, 0x139b6ef5	?rev
++	.long	0x00cbc624, 0xf7fae23c, 0xd3efde15, 0x0d183129	?rev
++Lk_dsbb:	# decryption sbox output *B*u, *B*t
++	.long	0x0042b496, 0x926422d0, 0x04d4f2b0, 0xf6462660	?rev
++	.long	0x006759cd, 0xa69894c1, 0x6baa5532, 0x3e0cfff3	?rev
++Lk_dsbe:	# decryption sbox output *E*u, *E*t
++	.long	0x00d0d426, 0x9692f246, 0xb0f6b464, 0x04604222	?rev
++	.long	0x00c1aaff, 0xcda6550c, 0x323e5998, 0x6bf36794	?rev
++
++##
++##  Key schedule constants
++##
++Lk_dksd:	# decryption key schedule: invskew x*D
++	.long	0x0047e4a3, 0x5d1ab9fe, 0xf9be1d5a, 0xa4e34007	?rev
++	.long	0x008336b5, 0xf477c241, 0x1e9d28ab, 0xea69dc5f	?rev
++Lk_dksb:	# decryption key schedule: invskew x*B
++	.long	0x00d55085, 0x1fca4f9a, 0x994cc91c, 0x8653d603	?rev
++	.long	0x004afcb6, 0xa7ed5b11, 0xc882347e, 0x6f2593d9	?rev
++Lk_dkse:	# decryption key schedule: invskew x*E + 0x63
++	.long	0x00d6c91f, 0xca1c03d5, 0x86504f99, 0x4c9a8553	?rev
++	.long	0xe87bdc4f, 0x059631a2, 0x8714b320, 0x6af95ecd	?rev
++Lk_dks9:	# decryption key schedule: invskew x*9
++	.long	0x00a7d97e, 0xc86f11b6, 0xfc5b2582, 0x3493ed4a	?rev
++	.long	0x00331427, 0x62517645, 0xcefddae9, 0xac9fb88b	?rev
++
++Lk_rcon:	# rcon
++	.long	0xb6ee9daf, 0xb991831f, 0x817d7c4d, 0x08982a70	?asis
++Lk_s63:
++	.long	0x5b5b5b5b, 0x5b5b5b5b, 0x5b5b5b5b, 0x5b5b5b5b	?asis
++
++Lk_opt:		# output transform
++	.long	0x0060b6d6, 0x29499fff, 0x0868bede, 0x214197f7	?rev
++	.long	0x00ecbc50, 0x51bded01, 0xe00c5cb0, 0xb15d0de1	?rev
++Lk_deskew:	# deskew tables: inverts the sbox's "skew"
++	.long	0x00e3a447, 0x40a3e407, 0x1af9be5d, 0x5ab9fe1d	?rev
++	.long	0x0069ea83, 0xdcb5365f, 0x771e9df4, 0xabc24128	?rev
++.align	5
++Lconsts:
++	mflr	r0
++	bcl	20,31,\$+4
++	mflr	r12	#vvvvv "distance between . and _vpaes_consts
++	addi	r12,r12,-0x308
++	mtlr	r0
++	blr
++	.long	0
++	.byte	0,12,0x14,0,0,0,0,0
++.asciz  "Vector Permutation AES for AltiVec, Mike Hamburg (Stanford University)"
++.align	6
++___
++
++my ($inptail,$inpperm,$outhead,$outperm,$outmask,$keyperm) = map("v$_",(26..31));
++{
++my ($inp,$out,$key) = map("r$_",(3..5));
++
++my ($invlo,$invhi,$iptlo,$ipthi,$sbou,$sbot) = map("v$_",(10..15));
++my ($sb1u,$sb1t,$sb2u,$sb2t) = map("v$_",(16..19));
++my ($sb9u,$sb9t,$sbdu,$sbdt,$sbbu,$sbbt,$sbeu,$sbet)=map("v$_",(16..23));
++
++$code.=<<___;
++##
++##  _aes_preheat
++##
++##  Fills register %r10 -> .aes_consts (so you can -fPIC)
++##  and %xmm9-%xmm15 as specified below.
++##
++.align	4
++_vpaes_encrypt_preheat:
++	mflr	r8
++	bl	Lconsts
++	mtlr	r8
++	li	r11, 0xc0		# Lk_inv
++	li	r10, 0xd0
++	li	r9,  0xe0		# Lk_ipt
++	li	r8,  0xf0
++	vxor	v7, v7, v7		# 0x00..00
++	vspltisb	v8,4		# 0x04..04
++	vspltisb	v9,0x0f		# 0x0f..0f
++	lvx	$invlo, r12, r11
++	li	r11, 0x100
++	lvx	$invhi, r12, r10
++	li	r10, 0x110
++	lvx	$iptlo, r12, r9
++	li	r9,  0x120
++	lvx	$ipthi, r12, r8
++	li	r8,  0x130
++	lvx	$sbou, r12, r11
++	li	r11, 0x140
++	lvx	$sbot, r12, r10
++	li	r10, 0x150
++	lvx	$sb1u, r12, r9
++	lvx	$sb1t, r12, r8
++	lvx	$sb2u, r12, r11
++	lvx	$sb2t, r12, r10
++	blr
++	.long	0
++	.byte	0,12,0x14,0,0,0,0,0
++
++##
++##  _aes_encrypt_core
++##
++##  AES-encrypt %xmm0.
++##
++##  Inputs:
++##     %xmm0 = input
++##     %xmm9-%xmm15 as in _vpaes_preheat
++##    (%rdx) = scheduled keys
++##
++##  Output in %xmm0
++##  Clobbers  %xmm1-%xmm6, %r9, %r10, %r11, %rax
++##
++##
++.align 5
++_vpaes_encrypt_core:
++	lwz	r8, 240($key)		# pull rounds
++	li	r9, 16
++	lvx	v5, 0, $key		# vmovdqu	(%r9),	%xmm5		# round0 key
++	li	r11, 0x10
++	lvx	v6, r9, $key
++	addi	r9, r9, 16
++	?vperm	v5, v5, v6, $keyperm	# align round key
++	addi	r10, r11, 0x40
++	vsrb	v1, v0, v8		# vpsrlb	\$4,	%xmm0,	%xmm0
++	vperm	v0, $iptlo, $iptlo, v0	# vpshufb	%xmm1,	%xmm2,	%xmm1
++	vperm	v1, $ipthi, $ipthi, v1	# vpshufb	%xmm0,	%xmm3,	%xmm2
++	vxor	v0, v0, v5		# vpxor	%xmm5,	%xmm1,	%xmm0
++	vxor	v0, v0, v1		# vpxor	%xmm2,	%xmm0,	%xmm0
++	mtctr	r8
++	b	Lenc_entry
++
++.align 4
++Lenc_loop:
++	# middle of middle round
++	vperm	v4, $sb1t, v7, v2	# vpshufb	%xmm2,	%xmm13,	%xmm4	# 4 = sb1u
++	lvx	v1, r12, r11		# vmovdqa	-0x40(%r11,%r10), %xmm1	# .Lk_mc_forward[]
++	addi	r11, r11, 16
++	vperm	v0, $sb1u, v7, v3	# vpshufb	%xmm3,	%xmm12,	%xmm0	# 0 = sb1t
++	vxor	v4, v4, v5		# vpxor		%xmm5,	%xmm4,	%xmm4	# 4 = sb1u + k
++	andi.	r11, r11, 0x30		# and		\$0x30, %r11	# ... mod 4
++	vperm	v5, $sb2t, v7, v2	# vpshufb	%xmm2,	%xmm15,	%xmm5	# 4 = sb2u
++	vxor	v0, v0, v4		# vpxor		%xmm4,	%xmm0,	%xmm0	# 0 = A
++	vperm	v2, $sb2u, v7, v3	# vpshufb	%xmm3,	%xmm14,	%xmm2	# 2 = sb2t
++	lvx	v4, r12, r10		# vmovdqa	(%r11,%r10), %xmm4	# .Lk_mc_backward[]
++	addi	r10, r11, 0x40
++	vperm	v3, v0, v7, v1		# vpshufb	%xmm1,	%xmm0,	%xmm3	# 0 = B
++	vxor	v2, v2, v5		# vpxor		%xmm5,	%xmm2,	%xmm2	# 2 = 2A
++	vperm	v0, v0, v7, v4		# vpshufb	%xmm4,	%xmm0,	%xmm0	# 3 = D
++	vxor	v3, v3, v2		# vpxor		%xmm2,	%xmm3,	%xmm3	# 0 = 2A+B
++	vperm	v4, v3, v7, v1		# vpshufb	%xmm1,	%xmm3,	%xmm4	# 0 = 2B+C
++	vxor	v0, v0, v3		# vpxor		%xmm3,	%xmm0,	%xmm0	# 3 = 2A+B+D
++	vxor	v0, v0, v4		# vpxor		%xmm4,	%xmm0, %xmm0	# 0 = 2A+3B+C+D
++
++Lenc_entry:
++	# top of round
++	vsrb	v1, v0, v8		# vpsrlb	\$4,	%xmm0,	%xmm0	# 1 = i
++	vperm	v5, $invhi, $invhi, v0	# vpshufb	%xmm1,	%xmm11,	%xmm5	# 2 = a/k
++	vxor	v0, v0, v1		# vpxor		%xmm0,	%xmm1,	%xmm1	# 0 = j
++	vperm	v3, $invlo, $invlo, v1	# vpshufb	%xmm0, 	%xmm10,	%xmm3  	# 3 = 1/i
++	vperm	v4, $invlo, $invlo, v0	# vpshufb	%xmm1, 	%xmm10,	%xmm4  	# 4 = 1/j
++	vand	v0, v0, v9
++	vxor	v3, v3, v5		# vpxor		%xmm5,	%xmm3,	%xmm3	# 3 = iak = 1/i + a/k
++	vxor	v4, v4, v5		# vpxor		%xmm5,	%xmm4,	%xmm4  	# 4 = jak = 1/j + a/k
++	vperm	v2, $invlo, v7, v3	# vpshufb	%xmm3,	%xmm10,	%xmm2  	# 2 = 1/iak
++	vmr	v5, v6
++	lvx	v6, r9, $key		# vmovdqu	(%r9), %xmm5
++	vperm	v3, $invlo, v7, v4	# vpshufb	%xmm4,	%xmm10,	%xmm3	# 3 = 1/jak
++	addi	r9, r9, 16
++	vxor	v2, v2, v0		# vpxor		%xmm1,	%xmm2,	%xmm2  	# 2 = io
++	?vperm	v5, v5, v6, $keyperm	# align round key
++	vxor	v3, v3, v1		# vpxor		%xmm0,	%xmm3,	%xmm3	# 3 = jo
++	bdnz	Lenc_loop
++
++	# middle of last round
++	addi	r10, r11, 0x80
++					# vmovdqa	-0x60(%r10), %xmm4	# 3 : sbou	.Lk_sbo
++					# vmovdqa	-0x50(%r10), %xmm0	# 0 : sbot	.Lk_sbo+16
++	vperm	v4, $sbou, v7, v2	# vpshufb	%xmm2,	%xmm4,	%xmm4	# 4 = sbou
++	lvx	v1, r12, r10		# vmovdqa	0x40(%r11,%r10), %xmm1	# .Lk_sr[]
++	vperm	v0, $sbot, v7, v3	# vpshufb	%xmm3,	%xmm0,	%xmm0	# 0 = sb1t
++	vxor	v4, v4, v5		# vpxor		%xmm5,	%xmm4,	%xmm4	# 4 = sb1u + k
++	vxor	v0, v0, v4		# vpxor		%xmm4,	%xmm0,	%xmm0	# 0 = A
++	vperm	v0, v0, v7, v1		# vpshufb	%xmm1,	%xmm0,	%xmm0
++	blr
++	.long	0
++	.byte	0,12,0x14,0,0,0,0,0
++
++.globl	.vpaes_encrypt
++.align	5
++.vpaes_encrypt:
++	$STU	$sp,-$FRAME($sp)
++	li	r10,`15+6*$SIZE_T`
++	li	r11,`31+6*$SIZE_T`
++	mflr	r6
++	mfspr	r7, 256			# save vrsave
++	stvx	v20,r10,$sp
++	addi	r10,r10,32
++	stvx	v21,r11,$sp
++	addi	r11,r11,32
++	stvx	v22,r10,$sp
++	addi	r10,r10,32
++	stvx	v23,r11,$sp
++	addi	r11,r11,32
++	stvx	v24,r10,$sp
++	addi	r10,r10,32
++	stvx	v25,r11,$sp
++	addi	r11,r11,32
++	stvx	v26,r10,$sp
++	addi	r10,r10,32
++	stvx	v27,r11,$sp
++	addi	r11,r11,32
++	stvx	v28,r10,$sp
++	addi	r10,r10,32
++	stvx	v29,r11,$sp
++	addi	r11,r11,32
++	stvx	v30,r10,$sp
++	stvx	v31,r11,$sp
++	stw	r7,`$FRAME-4`($sp)	# save vrsave
++	li	r0, -1
++	$PUSH	r6,`$FRAME+$LRSAVE`($sp)
++	mtspr	256, r0			# preserve all AltiVec registers
++
++	bl	_vpaes_encrypt_preheat
++
++	?lvsl	$inpperm, 0, $inp	# prepare for unaligned access
++	lvx	v0, 0, $inp
++	addi	$inp, $inp, 15		# 15 is not a typo
++	 ?lvsr	$outperm, 0, $out
++	?lvsl	$keyperm, 0, $key	# prepare for unaligned access
++	lvx	$inptail, 0, $inp	# redundant in aligned case
++	?vperm	v0, v0, $inptail, $inpperm
++
++	bl	_vpaes_encrypt_core
++
++	andi.	r8, $out, 15
++	li	r9, 16
++	beq	Lenc_out_aligned
++
++	vperm	v0, v0, v0, $outperm	# rotate right/left
++	mtctr	r9
++Lenc_out_unaligned:
++	stvebx	v0, 0, $out
++	addi	$out, $out, 1
++	bdnz	Lenc_out_unaligned
++	b	Lenc_done
++
++.align	4
++Lenc_out_aligned:
++	stvx	v0, 0, $out
++Lenc_done:
++
++	li	r10,`15+6*$SIZE_T`
++	li	r11,`31+6*$SIZE_T`
++	mtlr	r6
++	mtspr	256, r7			# restore vrsave
++	lvx	v20,r10,$sp
++	addi	r10,r10,32
++	lvx	v21,r11,$sp
++	addi	r11,r11,32
++	lvx	v22,r10,$sp
++	addi	r10,r10,32
++	lvx	v23,r11,$sp
++	addi	r11,r11,32
++	lvx	v24,r10,$sp
++	addi	r10,r10,32
++	lvx	v25,r11,$sp
++	addi	r11,r11,32
++	lvx	v26,r10,$sp
++	addi	r10,r10,32
++	lvx	v27,r11,$sp
++	addi	r11,r11,32
++	lvx	v28,r10,$sp
++	addi	r10,r10,32
++	lvx	v29,r11,$sp
++	addi	r11,r11,32
++	lvx	v30,r10,$sp
++	lvx	v31,r11,$sp
++	addi	$sp,$sp,$FRAME
++	blr
++	.long	0
++	.byte	0,12,0x04,1,0x80,0,3,0
++	.long	0
++.size	.vpaes_encrypt,.-.vpaes_encrypt
++
++.align	4
++_vpaes_decrypt_preheat:
++	mflr	r8
++	bl	Lconsts
++	mtlr	r8
++	li	r11, 0xc0		# Lk_inv
++	li	r10, 0xd0
++	li	r9,  0x160		# Ldipt
++	li	r8,  0x170
++	vxor	v7, v7, v7		# 0x00..00
++	vspltisb	v8,4		# 0x04..04
++	vspltisb	v9,0x0f		# 0x0f..0f
++	lvx	$invlo, r12, r11
++	li	r11, 0x180
++	lvx	$invhi, r12, r10
++	li	r10, 0x190
++	lvx	$iptlo, r12, r9
++	li	r9,  0x1a0
++	lvx	$ipthi, r12, r8
++	li	r8,  0x1b0
++	lvx	$sbou, r12, r11
++	li	r11, 0x1c0
++	lvx	$sbot, r12, r10
++	li	r10, 0x1d0
++	lvx	$sb9u, r12, r9
++	li	r9,  0x1e0
++	lvx	$sb9t, r12, r8
++	li	r8,  0x1f0
++	lvx	$sbdu, r12, r11
++	li	r11, 0x200
++	lvx	$sbdt, r12, r10
++	li	r10, 0x210
++	lvx	$sbbu, r12, r9
++	lvx	$sbbt, r12, r8
++	lvx	$sbeu, r12, r11
++	lvx	$sbet, r12, r10
++	blr
++	.long	0
++	.byte	0,12,0x14,0,0,0,0,0
++
++##
++##  Decryption core
++##
++##  Same API as encryption core.
++##
++.align	4
++_vpaes_decrypt_core:
++	lwz	r8, 240($key)		# pull rounds
++	li	r9, 16
++	lvx	v5, 0, $key		# vmovdqu	(%r9),	%xmm4		# round0 key
++	li	r11, 0x30
++	lvx	v6, r9, $key
++	addi	r9, r9, 16
++	?vperm	v5, v5, v6, $keyperm	# align round key
++	vsrb	v1, v0, v8		# vpsrlb	\$4,	%xmm0,	%xmm0
++	vperm	v0, $iptlo, $iptlo, v0	# vpshufb	%xmm1,	%xmm2,	%xmm2
++	vperm	v1, $ipthi, $ipthi, v1	# vpshufb	%xmm0,	%xmm1,	%xmm0
++	vxor	v0, v0, v5		# vpxor	%xmm4,	%xmm2,	%xmm2
++	vxor	v0, v0, v1		# vpxor	%xmm2,	%xmm0,	%xmm0
++	mtctr	r8
++	b	Ldec_entry
++
++.align 4
++Ldec_loop:
++#
++#  Inverse mix columns
++#
++	lvx	v0, r12, r11		# v5 and v0 are flipped
++					# vmovdqa	-0x20(%r10),%xmm4		# 4 : sb9u
++					# vmovdqa	-0x10(%r10),%xmm1		# 0 : sb9t
++	vperm	v4, $sb9u, v7, v2	# vpshufb	%xmm2,	%xmm4,	%xmm4		# 4 = sb9u
++	subi	r11, r11, 16
++	vperm	v1, $sb9t, v7, v3	# vpshufb	%xmm3,	%xmm1,	%xmm1		# 0 = sb9t
++	andi.	r11, r11, 0x30
++	vxor	v5, v5, v4		# vpxor		%xmm4,	%xmm0,	%xmm0
++					# vmovdqa	0x00(%r10),%xmm4		# 4 : sbdu
++	vxor	v5, v5, v1		# vpxor		%xmm1,	%xmm0,	%xmm0		# 0 = ch
++					# vmovdqa	0x10(%r10),%xmm1		# 0 : sbdt
++
++	vperm	v4, $sbdu, v7, v2	# vpshufb	%xmm2,	%xmm4,	%xmm4		# 4 = sbdu
++	vperm 	v5, v5, v7, v0		# vpshufb	%xmm5,	%xmm0,	%xmm0		# MC ch
++	vperm	v1, $sbdt, v7, v3	# vpshufb	%xmm3,	%xmm1,	%xmm1		# 0 = sbdt
++	vxor	v5, v5, v4		# vpxor		%xmm4,	%xmm0,	%xmm0		# 4 = ch
++					# vmovdqa	0x20(%r10),	%xmm4		# 4 : sbbu
++	vxor	v5, v5, v1		# vpxor		%xmm1,	%xmm0,	%xmm0		# 0 = ch
++					# vmovdqa	0x30(%r10),	%xmm1		# 0 : sbbt
++
++	vperm	v4, $sbbu, v7, v2	# vpshufb	%xmm2,	%xmm4,	%xmm4		# 4 = sbbu
++	vperm	v5, v5, v7, v0		# vpshufb	%xmm5,	%xmm0,	%xmm0		# MC ch
++	vperm	v1, $sbbt, v7, v3	# vpshufb	%xmm3,	%xmm1,	%xmm1		# 0 = sbbt
++	vxor	v5, v5, v4		# vpxor		%xmm4,	%xmm0,	%xmm0		# 4 = ch
++					# vmovdqa	0x40(%r10),	%xmm4		# 4 : sbeu
++	vxor	v5, v5, v1		# vpxor		%xmm1,	%xmm0,	%xmm0		# 0 = ch
++					# vmovdqa	0x50(%r10),	%xmm1		# 0 : sbet
++
++	vperm	v4, $sbeu, v7, v2	# vpshufb	%xmm2,	%xmm4,	%xmm4		# 4 = sbeu
++	vperm	v5, v5, v7, v0		# vpshufb	%xmm5,	%xmm0,	%xmm0		# MC ch
++	vperm	v1, $sbet, v7, v3	# vpshufb	%xmm3,	%xmm1,	%xmm1		# 0 = sbet
++	vxor	v0, v5, v4		# vpxor		%xmm4,	%xmm0,	%xmm0		# 4 = ch
++	vxor	v0, v0, v1		# vpxor		%xmm1,	%xmm0,	%xmm0		# 0 = ch
++
++Ldec_entry:
++	# top of round
++	vsrb	v1, v0, v8		# vpsrlb	\$4,	%xmm0,	%xmm0	# 1 = i
++	vperm	v2, $invhi, $invhi, v0	# vpshufb	%xmm1,	%xmm11,	%xmm2	# 2 = a/k
++	vxor	v0, v0, v1		# vpxor		%xmm0,	%xmm1,	%xmm1	# 0 = j
++	vperm	v3, $invlo, $invlo, v1	# vpshufb	%xmm0, 	%xmm10,	%xmm3	# 3 = 1/i
++	vperm	v4, $invlo, $invlo, v0	# vpshufb	%xmm1,	%xmm10,	%xmm4	# 4 = 1/j
++	vand	v0, v0, v9
++	vxor	v3, v3, v2		# vpxor		%xmm2,	%xmm3,	%xmm3	# 3 = iak = 1/i + a/k
++	vxor	v4, v4, v2		# vpxor		%xmm2, 	%xmm4,	%xmm4	# 4 = jak = 1/j + a/k
++	vperm	v2, $invlo, v7, v3	# vpshufb	%xmm3,	%xmm10,	%xmm2	# 2 = 1/iak
++	vmr	v5, v6
++	lvx	v6, r9, $key		# vmovdqu	(%r9),	%xmm0
++	vperm	v3, $invlo, v7, v4	# vpshufb	%xmm4,  %xmm10,	%xmm3	# 3 = 1/jak
++	addi	r9, r9, 16
++	vxor	v2, v2, v0		# vpxor		%xmm1,	%xmm2,	%xmm2	# 2 = io
++	?vperm	v5, v5, v6, $keyperm	# align round key
++	vxor	v3, v3, v1		# vpxor		%xmm0,  %xmm3,	%xmm3	# 3 = jo
++	bdnz	Ldec_loop
++
++	# middle of last round
++	addi	r10, r11, 0x80
++					# vmovdqa	0x60(%r10),	%xmm4	# 3 : sbou
++	vperm	v4, $sbou, v7, v2	# vpshufb	%xmm2,	%xmm4,	%xmm4	# 4 = sbou
++					# vmovdqa	0x70(%r10),	%xmm1	# 0 : sbot
++	lvx	v2, r12, r10		# vmovdqa	-0x160(%r11),	%xmm2	# .Lk_sr-.Lk_dsbd=-0x160
++	vperm	v1, $sbot, v7, v3	# vpshufb	%xmm3,	%xmm1,	%xmm1	# 0 = sb1t
++	vxor	v4, v4, v5		# vpxor		%xmm0,	%xmm4,	%xmm4	# 4 = sb1u + k
++	vxor	v0, v1, v4		# vpxor		%xmm4,	%xmm1,	%xmm0	# 0 = A
++	vperm	v0, v0, v7, v2		# vpshufb	%xmm2,	%xmm0,	%xmm0
++	blr
++	.long	0
++	.byte	0,12,0x14,0,0,0,0,0
++
++.globl	.vpaes_decrypt
++.align	5
++.vpaes_decrypt:
++	$STU	$sp,-$FRAME($sp)
++	li	r10,`15+6*$SIZE_T`
++	li	r11,`31+6*$SIZE_T`
++	mflr	r6
++	mfspr	r7, 256			# save vrsave
++	stvx	v20,r10,$sp
++	addi	r10,r10,32
++	stvx	v21,r11,$sp
++	addi	r11,r11,32
++	stvx	v22,r10,$sp
++	addi	r10,r10,32
++	stvx	v23,r11,$sp
++	addi	r11,r11,32
++	stvx	v24,r10,$sp
++	addi	r10,r10,32
++	stvx	v25,r11,$sp
++	addi	r11,r11,32
++	stvx	v26,r10,$sp
++	addi	r10,r10,32
++	stvx	v27,r11,$sp
++	addi	r11,r11,32
++	stvx	v28,r10,$sp
++	addi	r10,r10,32
++	stvx	v29,r11,$sp
++	addi	r11,r11,32
++	stvx	v30,r10,$sp
++	stvx	v31,r11,$sp
++	stw	r7,`$FRAME-4`($sp)	# save vrsave
++	li	r0, -1
++	$PUSH	r6,`$FRAME+$LRSAVE`($sp)
++	mtspr	256, r0			# preserve all AltiVec registers
++
++	bl	_vpaes_decrypt_preheat
++
++	?lvsl	$inpperm, 0, $inp	# prepare for unaligned access
++	lvx	v0, 0, $inp
++	addi	$inp, $inp, 15		# 15 is not a typo
++	 ?lvsr	$outperm, 0, $out
++	?lvsl	$keyperm, 0, $key
++	lvx	$inptail, 0, $inp	# redundant in aligned case
++	?vperm	v0, v0, $inptail, $inpperm
++
++	bl	_vpaes_decrypt_core
++
++	andi.	r8, $out, 15
++	li	r9, 16
++	beq	Ldec_out_aligned
++
++	vperm	v0, v0, v0, $outperm	# rotate right/left
++	mtctr	r9
++Ldec_out_unaligned:
++	stvebx	v0, 0, $out
++	addi	$out, $out, 1
++	bdnz	Ldec_out_unaligned
++	b	Ldec_done
++
++.align	4
++Ldec_out_aligned:
++	stvx	v0, 0, $out
++Ldec_done:
++
++	li	r10,`15+6*$SIZE_T`
++	li	r11,`31+6*$SIZE_T`
++	mtlr	r6
++	mtspr	256, r7			# restore vrsave
++	lvx	v20,r10,$sp
++	addi	r10,r10,32
++	lvx	v21,r11,$sp
++	addi	r11,r11,32
++	lvx	v22,r10,$sp
++	addi	r10,r10,32
++	lvx	v23,r11,$sp
++	addi	r11,r11,32
++	lvx	v24,r10,$sp
++	addi	r10,r10,32
++	lvx	v25,r11,$sp
++	addi	r11,r11,32
++	lvx	v26,r10,$sp
++	addi	r10,r10,32
++	lvx	v27,r11,$sp
++	addi	r11,r11,32
++	lvx	v28,r10,$sp
++	addi	r10,r10,32
++	lvx	v29,r11,$sp
++	addi	r11,r11,32
++	lvx	v30,r10,$sp
++	lvx	v31,r11,$sp
++	addi	$sp,$sp,$FRAME
++	blr
++	.long	0
++	.byte	0,12,0x04,1,0x80,0,3,0
++	.long	0
++.size	.vpaes_decrypt,.-.vpaes_decrypt
++
++.globl	.vpaes_cbc_encrypt
++.align	5
++.vpaes_cbc_encrypt:
++	${UCMP}i r5,16
++	bltlr-
++
++	$STU	$sp,-`($FRAME+2*$SIZE_T)`($sp)
++	mflr	r0
++	li	r10,`15+6*$SIZE_T`
++	li	r11,`31+6*$SIZE_T`
++	mfspr	r12, 256
++	stvx	v20,r10,$sp
++	addi	r10,r10,32
++	stvx	v21,r11,$sp
++	addi	r11,r11,32
++	stvx	v22,r10,$sp
++	addi	r10,r10,32
++	stvx	v23,r11,$sp
++	addi	r11,r11,32
++	stvx	v24,r10,$sp
++	addi	r10,r10,32
++	stvx	v25,r11,$sp
++	addi	r11,r11,32
++	stvx	v26,r10,$sp
++	addi	r10,r10,32
++	stvx	v27,r11,$sp
++	addi	r11,r11,32
++	stvx	v28,r10,$sp
++	addi	r10,r10,32
++	stvx	v29,r11,$sp
++	addi	r11,r11,32
++	stvx	v30,r10,$sp
++	stvx	v31,r11,$sp
++	stw	r12,`$FRAME-4`($sp)	# save vrsave
++	$PUSH	r30,`$FRAME+$SIZE_T*0`($sp)
++	$PUSH	r31,`$FRAME+$SIZE_T*1`($sp)
++	li	r9, -16
++	$PUSH	r0, `$FRAME+$SIZE_T*2+$LRSAVE`($sp)
++
++	and	r30, r5, r9		# copy length&-16
++	andi.	r9, $out, 15		# is $out aligned?
++	mr	r5, r6			# copy pointer to key
++	mr	r31, r7			# copy pointer to iv
++	li	r6, -1
++	mcrf	cr1, cr0		# put aside $out alignment flag
++	mr	r7, r12			# copy vrsave
++	mtspr	256, r6			# preserve all AltiVec registers
++
++	lvx	v24, 0, r31		# load [potentially unaligned] iv
++	li	r9, 15
++	?lvsl	$inpperm, 0, r31
++	lvx	v25, r9, r31
++	?vperm	v24, v24, v25, $inpperm
++
++	cmpwi	r8, 0			# test direction
++	neg	r8, $inp		# prepare for unaligned access
++	 vxor	v7, v7, v7
++	?lvsl	$keyperm, 0, $key
++	 ?lvsr	$outperm, 0, $out
++	?lvsr	$inpperm, 0, r8		# -$inp
++	 vnor	$outmask, v7, v7	# 0xff..ff
++	lvx	$inptail, 0, $inp
++	 ?vperm	$outmask, v7, $outmask, $outperm
++	addi	$inp, $inp, 15		# 15 is not a typo
++
++	beq	Lcbc_decrypt
++
++	bl	_vpaes_encrypt_preheat
++	li	r0, 16
++
++	beq	cr1, Lcbc_enc_loop	# $out is aligned
++
++	vmr	v0, $inptail
++	lvx	$inptail, 0, $inp
++	addi	$inp, $inp, 16
++	?vperm	v0, v0, $inptail, $inpperm
++	vxor	v0, v0, v24		# ^= iv
++
++	bl	_vpaes_encrypt_core
++
++	andi.	r8, $out, 15
++	vmr	v24, v0			# put aside iv
++	sub	r9, $out, r8
++	vperm	$outhead, v0, v0, $outperm	# rotate right/left
++
++Lcbc_enc_head:
++	stvebx	$outhead, r8, r9
++	cmpwi	r8, 15
++	addi	r8, r8, 1
++	bne	Lcbc_enc_head
++
++	sub.	r30, r30, r0		# len -= 16
++	addi	$out, $out, 16
++	beq	Lcbc_unaligned_done
++
++Lcbc_enc_loop:
++	vmr	v0, $inptail
++	lvx	$inptail, 0, $inp
++	addi	$inp, $inp, 16
++	?vperm	v0, v0, $inptail, $inpperm
++	vxor	v0, v0, v24		# ^= iv
++
++	bl	_vpaes_encrypt_core
++
++	vmr	v24, v0			# put aside iv
++	sub.	r30, r30, r0		# len -= 16
++	vperm	v0, v0, v0, $outperm	# rotate right/left
++	vsel	v1, $outhead, v0, $outmask
++	vmr	$outhead, v0
++	stvx	v1, 0, $out
++	addi	$out, $out, 16
++	bne	Lcbc_enc_loop
++
++	b	Lcbc_done
++
++.align	5
++Lcbc_decrypt:
++	bl	_vpaes_decrypt_preheat
++	li	r0, 16
++
++	beq	cr1, Lcbc_dec_loop	# $out is aligned
++
++	vmr	v0, $inptail
++	lvx	$inptail, 0, $inp
++	addi	$inp, $inp, 16
++	?vperm	v0, v0, $inptail, $inpperm
++	vmr	v25, v0			# put aside input
++
++	bl	_vpaes_decrypt_core
++
++	andi.	r8, $out, 15
++	vxor	v0, v0, v24		# ^= iv
++	vmr	v24, v25
++	sub	r9, $out, r8
++	vperm	$outhead, v0, v0, $outperm	# rotate right/left
++
++Lcbc_dec_head:
++	stvebx	$outhead, r8, r9
++	cmpwi	r8, 15
++	addi	r8, r8, 1
++	bne	Lcbc_dec_head
++
++	sub.	r30, r30, r0		# len -= 16
++	addi	$out, $out, 16
++	beq	Lcbc_unaligned_done
++
++Lcbc_dec_loop:
++	vmr	v0, $inptail
++	lvx	$inptail, 0, $inp
++	addi	$inp, $inp, 16
++	?vperm	v0, v0, $inptail, $inpperm
++	vmr	v25, v0			# put aside input
++
++	bl	_vpaes_decrypt_core
++
++	vxor	v0, v0, v24		# ^= iv
++	vmr	v24, v25
++	sub.	r30, r30, r0		# len -= 16
++	vperm	v0, v0, v0, $outperm	# rotate right/left
++	vsel	v1, $outhead, v0, $outmask
++	vmr	$outhead, v0
++	stvx	v1, 0, $out
++	addi	$out, $out, 16
++	bne	Lcbc_dec_loop
++
++Lcbc_done:
++	beq	cr1, Lcbc_write_iv	# $out is aligned
++
++Lcbc_unaligned_done:
++	andi.	r8, $out, 15
++	sub	$out, $out, r8
++	li	r9, 0
++Lcbc_tail:
++	stvebx	$outhead, r9, $out
++	addi	r9, r9, 1
++	cmpw	r9, r8
++	bne	Lcbc_tail
++
++Lcbc_write_iv:
++	neg	r8, r31			# write [potentially unaligned] iv
++	li	r10, 4
++	?lvsl	$outperm, 0, r8
++	li	r11, 8
++	li	r12, 12
++	vperm	v24, v24, v24, $outperm	# rotate right/left
++	stvewx	v24, 0, r31		# ivp is at least 32-bit aligned
++	stvewx	v24, r10, r31
++	stvewx	v24, r11, r31
++	stvewx	v24, r12, r31
++
++	mtspr	256, r7			# restore vrsave
++	li	r10,`15+6*$SIZE_T`
++	li	r11,`31+6*$SIZE_T`
++	lvx	v20,r10,$sp
++	addi	r10,r10,32
++	lvx	v21,r11,$sp
++	addi	r11,r11,32
++	lvx	v22,r10,$sp
++	addi	r10,r10,32
++	lvx	v23,r11,$sp
++	addi	r11,r11,32
++	lvx	v24,r10,$sp
++	addi	r10,r10,32
++	lvx	v25,r11,$sp
++	addi	r11,r11,32
++	lvx	v26,r10,$sp
++	addi	r10,r10,32
++	lvx	v27,r11,$sp
++	addi	r11,r11,32
++	lvx	v28,r10,$sp
++	addi	r10,r10,32
++	lvx	v29,r11,$sp
++	addi	r11,r11,32
++	lvx	v30,r10,$sp
++	lvx	v31,r11,$sp
++Lcbc_abort:
++	$POP	r0, `$FRAME+$SIZE_T*2+$LRSAVE`($sp)
++	$POP	r30,`$FRAME+$SIZE_T*0`($sp)
++	$POP	r31,`$FRAME+$SIZE_T*1`($sp)
++	mtlr	r0
++	addi	$sp,$sp,`$FRAME+$SIZE_T*2`
++	blr
++	.long	0
++	.byte	0,12,0x04,1,0x80,2,6,0
++	.long	0
++.size	.vpaes_cbc_encrypt,.-.vpaes_cbc_encrypt
++___
++}
++{
++my ($inp,$bits,$out)=map("r$_",(3..5));
++my $dir="cr1";
++my ($invlo,$invhi,$iptlo,$ipthi,$rcon) = map("v$_",(10..13,24));
++
++$code.=<<___;
++########################################################
++##                                                    ##
++##                  AES key schedule                  ##
++##                                                    ##
++########################################################
++.align	4
++_vpaes_key_preheat:
++	mflr	r8
++	bl	Lconsts
++	mtlr	r8
++	li	r11, 0xc0		# Lk_inv
++	li	r10, 0xd0
++	li	r9,  0xe0		# L_ipt
++	li	r8,  0xf0
++
++	vspltisb	v8,4		# 0x04..04
++	vxor	v9,v9,v9		# 0x00..00
++	lvx	$invlo, r12, r11	# Lk_inv
++	li	r11, 0x120
++	lvx	$invhi, r12, r10
++	li	r10, 0x130
++	lvx	$iptlo, r12, r9		# Lk_ipt
++	li	r9, 0x220
++	lvx	$ipthi, r12, r8
++	li	r8, 0x230
++
++	lvx	v14, r12, r11		# Lk_sb1
++	li	r11, 0x240
++	lvx	v15, r12, r10
++	li	r10, 0x250
++
++	lvx	v16, r12, r9		# Lk_dksd
++	li	r9, 0x260
++	lvx	v17, r12, r8
++	li	r8, 0x270
++	lvx	v18, r12, r11		# Lk_dksb
++	li	r11, 0x280
++	lvx	v19, r12, r10
++	li	r10, 0x290
++	lvx	v20, r12, r9		# Lk_dkse
++	li	r9, 0x2a0
++	lvx	v21, r12, r8
++	li	r8, 0x2b0
++	lvx	v22, r12, r11		# Lk_dks9
++	lvx	v23, r12, r10
++
++	lvx	v24, r12, r9		# Lk_rcon
++	lvx	v25, 0, r12		# Lk_mc_forward[0]
++	lvx	v26, r12, r8		# Lks63
++	blr
++	.long	0
++	.byte	0,12,0x14,0,0,0,0,0
++
++.align	4
++_vpaes_schedule_core:
++	mflr	r7
++
++	bl	_vpaes_key_preheat	# load the tables
++
++	#lvx	v0, 0, $inp		# vmovdqu	(%rdi),	%xmm0		# load key (unaligned)
++	neg	r8, $inp		# prepare for unaligned access
++	lvx	v0, 0, $inp
++	addi	$inp, $inp, 15		# 15 is not typo
++	?lvsr	$inpperm, 0, r8		# -$inp
++	lvx	v6, 0, $inp		# v6 serves as inptail
++	addi	$inp, $inp, 8
++	?vperm	v0, v0, v6, $inpperm
++
++	# input transform
++	vmr	v3, v0			# vmovdqa	%xmm0,	%xmm3
++	bl	_vpaes_schedule_transform
++	vmr	v7, v0			# vmovdqa	%xmm0,	%xmm7
++
++	bne	$dir, Lschedule_am_decrypting
++
++	# encrypting, output zeroth round key after transform
++	li	r8, 0x30		# mov	\$0x30,%r8d
++	li	r9, 4
++	li	r10, 8
++	li	r11, 12
++
++	?lvsr	$outperm, 0, $out	# prepare for unaligned access
++	vnor	$outmask, v9, v9	# 0xff..ff
++	?vperm	$outmask, v9, $outmask, $outperm
++
++	#stvx	v0, 0, $out		# vmovdqu	%xmm0,	(%rdx)
++	vperm	$outhead, v0, v0, $outperm	# rotate right/left
++	stvewx	$outhead, 0, $out	# some are superfluous
++	stvewx	$outhead, r9, $out
++	stvewx	$outhead, r10, $out
++	addi	r10, r12, 0x80		# lea	.Lk_sr(%rip),%r10
++	stvewx	$outhead, r11, $out
++	b	Lschedule_go
++
++Lschedule_am_decrypting:
++	srwi	r8, $bits, 1		# shr	\$1,%r8d
++	andi.	r8, r8, 32		# and	\$32,%r8d
++	xori	r8, r8, 32		# xor	\$32,%r8d	# nbits==192?0:32
++	addi	r10, r12, 0x80		# lea	.Lk_sr(%rip),%r10
++	# decrypting, output zeroth round key after shiftrows
++	lvx	v1, r8, r10		# vmovdqa	(%r8,%r10),	%xmm1
++	li	r9, 4
++	li	r10, 8
++	li	r11, 12
++	vperm	v4, v3, v3, v1		# vpshufb	%xmm1,	%xmm3,	%xmm3
++
++	neg	r0, $out		# prepare for unaligned access
++	?lvsl	$outperm, 0, r0
++	vnor	$outmask, v9, v9	# 0xff..ff
++	?vperm	$outmask, $outmask, v9, $outperm
++
++	#stvx	v4, 0, $out		# vmovdqu	%xmm3,	(%rdx)
++	vperm	$outhead, v4, v4, $outperm	# rotate right/left
++	stvewx	$outhead, 0, $out	# some are superfluous
++	stvewx	$outhead, r9, $out
++	stvewx	$outhead, r10, $out
++	addi	r10, r12, 0x80		# lea	.Lk_sr(%rip),%r10
++	stvewx	$outhead, r11, $out
++	addi	$out, $out, 15		# 15 is not typo
++	xori	r8, r8, 0x30		# xor	\$0x30, %r8
++
++Lschedule_go:
++	cmplwi	$bits, 192		# cmp	\$192,	%esi
++	bgt	Lschedule_256
++	beq	Lschedule_192
++	# 128: fall though
++
++##
++##  .schedule_128
++##
++##  128-bit specific part of key schedule.
++##
++##  This schedule is really simple, because all its parts
++##  are accomplished by the subroutines.
++##
++Lschedule_128:
++	li	r0, 10			# mov	\$10, %esi
++	mtctr	r0
++
++Loop_schedule_128:
++	bl 	_vpaes_schedule_round
++	bdz 	Lschedule_mangle_last	# dec	%esi
++	bl	_vpaes_schedule_mangle	# write output
++	b 	Loop_schedule_128
++
++##
++##  .aes_schedule_192
++##
++##  192-bit specific part of key schedule.
++##
++##  The main body of this schedule is the same as the 128-bit
++##  schedule, but with more smearing.  The long, high side is
++##  stored in %xmm7 as before, and the short, low side is in
++##  the high bits of %xmm6.
++##
++##  This schedule is somewhat nastier, however, because each
++##  round produces 192 bits of key material, or 1.5 round keys.
++##  Therefore, on each cycle we do 2 rounds and produce 3 round
++##  keys.
++##
++.align	4
++Lschedule_192:
++	li	r0, 4			# mov	\$4,	%esi
++	lvx	v0, 0, $inp
++	?vperm	v0, v6, v0, $inpperm
++	?vsldoi	v0, v3, v0, 8		# vmovdqu	8(%rdi),%xmm0		# load key part 2 (very unaligned)
++	bl	_vpaes_schedule_transform	# input transform
++	?vsldoi	v6, v0, v9, 8
++	?vsldoi	v6, v9, v6, 8		# clobber "low" side with zeros
++	mtctr	r0
++
++Loop_schedule_192:
++	bl	_vpaes_schedule_round
++	?vsldoi	v0, v6, v0, 8		# vpalignr	\$8,%xmm6,%xmm0,%xmm0
++	bl	_vpaes_schedule_mangle	# save key n
++	bl	_vpaes_schedule_192_smear
++	bl	_vpaes_schedule_mangle	# save key n+1
++	bl	_vpaes_schedule_round
++	bdz 	Lschedule_mangle_last	# dec	%esi
++	bl	_vpaes_schedule_mangle	# save key n+2
++	bl	_vpaes_schedule_192_smear
++	b	Loop_schedule_192
++
++##
++##  .aes_schedule_256
++##
++##  256-bit specific part of key schedule.
++##
++##  The structure here is very similar to the 128-bit
++##  schedule, but with an additional "low side" in
++##  %xmm6.  The low side's rounds are the same as the
++##  high side's, except no rcon and no rotation.
++##
++.align	4
++Lschedule_256:
++	li	r0, 7			# mov	\$7, %esi
++	addi	$inp, $inp, 8
++	lvx	v0, 0, $inp		# vmovdqu	16(%rdi),%xmm0		# load key part 2 (unaligned)
++	?vperm	v0, v6, v0, $inpperm
++	bl	_vpaes_schedule_transform	# input transform
++	mtctr	r0
++
++Loop_schedule_256:
++	bl	_vpaes_schedule_mangle	# output low result
++	vmr	v6, v0			# vmovdqa	%xmm0,	%xmm6		# save cur_lo in xmm6
++
++	# high round
++	bl	_vpaes_schedule_round
++	bdz 	Lschedule_mangle_last	# dec	%esi
++	bl	_vpaes_schedule_mangle	
++
++	# low round. swap xmm7 and xmm6
++	?vspltw	v0, v0, 3		# vpshufd	\$0xFF,	%xmm0,	%xmm0
++	vmr	v5, v7			# vmovdqa	%xmm7,	%xmm5
++	vmr	v7, v6			# vmovdqa	%xmm6,	%xmm7
++	bl	_vpaes_schedule_low_round
++	vmr	v7, v5			# vmovdqa	%xmm5,	%xmm7
++	
++	b	Loop_schedule_256
++##
++##  .aes_schedule_mangle_last
++##
++##  Mangler for last round of key schedule
++##  Mangles %xmm0
++##    when encrypting, outputs out(%xmm0) ^ 63
++##    when decrypting, outputs unskew(%xmm0)
++##
++##  Always called right before return... jumps to cleanup and exits
++##
++.align	4
++Lschedule_mangle_last:
++	# schedule last round key from xmm0
++	li	r11, 0x2e0		# lea	.Lk_deskew(%rip),%r11
++	li	r9,  0x2f0
++	bne	$dir, Lschedule_mangle_last_dec
++
++	# encrypting
++	lvx	v1, r8, r10		# vmovdqa	(%r8,%r10),%xmm1
++	li	r11, 0x2c0		# lea		.Lk_opt(%rip),	%r11	# prepare to output transform
++	li	r9,  0x2d0		# prepare to output transform
++	vperm	v0, v0, v0, v1		# vpshufb	%xmm1,	%xmm0,	%xmm0	# output permute
++
++	lvx	$iptlo, r11, r12	# reload $ipt
++	lvx	$ipthi, r9, r12
++	addi	$out, $out, 16		# add	\$16,	%rdx
++	vxor	v0, v0, v26		# vpxor		.Lk_s63(%rip),	%xmm0,	%xmm0
++	bl	_vpaes_schedule_transform	# output transform
++
++	#stvx	v0, r0, $out		# vmovdqu	%xmm0,	(%rdx)		# save last key
++	vperm	v0, v0, v0, $outperm	# rotate right/left
++	li	r10, 4
++	vsel	v2, $outhead, v0, $outmask
++	li	r11, 8
++	stvx	v2, 0, $out
++	li	r12, 12
++	stvewx	v0, 0, $out		# some (or all) are redundant
++	stvewx	v0, r10, $out
++	stvewx	v0, r11, $out
++	stvewx	v0, r12, $out
++	b	Lschedule_mangle_done
++
++.align	4
++Lschedule_mangle_last_dec:
++	lvx	$iptlo, r11, r12	# reload $ipt
++	lvx	$ipthi, r9,  r12
++	addi	$out, $out, -16		# add	\$-16,	%rdx 
++	vxor	v0, v0, v26		# vpxor	.Lk_s63(%rip),	%xmm0,	%xmm0
++	bl	_vpaes_schedule_transform	# output transform
++
++	#stvx	v0, r0, $out		# vmovdqu	%xmm0,	(%rdx)		# save last key
++	addi	r9, $out, -15		# -15 is not typo
++	vperm	v0, v0, v0, $outperm	# rotate right/left
++	li	r10, 4
++	vsel	v2, $outhead, v0, $outmask
++	li	r11, 8
++	stvx	v2, 0, $out
++	li	r12, 12
++	stvewx	v0, 0, r9		# some (or all) are redundant
++	stvewx	v0, r10, r9
++	stvewx	v0, r11, r9
++	stvewx	v0, r12, r9
++
++
++Lschedule_mangle_done:
++	mtlr	r7
++	# cleanup
++	vxor	v0, v0, v0		# vpxor		%xmm0,	%xmm0,	%xmm0
++	vxor	v1, v1, v1		# vpxor		%xmm1,	%xmm1,	%xmm1
++	vxor	v2, v2, v2		# vpxor		%xmm2,	%xmm2,	%xmm2
++	vxor	v3, v3, v3		# vpxor		%xmm3,	%xmm3,	%xmm3
++	vxor	v4, v4, v4		# vpxor		%xmm4,	%xmm4,	%xmm4
++	vxor	v5, v5, v5		# vpxor		%xmm5,	%xmm5,	%xmm5
++	vxor	v6, v6, v6		# vpxor		%xmm6,	%xmm6,	%xmm6
++	vxor	v7, v7, v7		# vpxor		%xmm7,	%xmm7,	%xmm7
++
++	blr
++	.long	0
++	.byte	0,12,0x14,0,0,0,0,0
++
++##
++##  .aes_schedule_192_smear
++##
++##  Smear the short, low side in the 192-bit key schedule.
++##
++##  Inputs:
++##    %xmm7: high side, b  a  x  y
++##    %xmm6:  low side, d  c  0  0
++##    %xmm13: 0
++##
++##  Outputs:
++##    %xmm6: b+c+d  b+c  0  0
++##    %xmm0: b+c+d  b+c  b  a
++##
++.align	4
++_vpaes_schedule_192_smear:
++	?vspltw	v0, v7, 3
++	?vsldoi	v1, v9, v6, 12		# vpshufd	\$0x80,	%xmm6,	%xmm1	# d c 0 0 -> c 0 0 0
++	?vsldoi	v0, v7, v0, 8		# vpshufd	\$0xFE,	%xmm7,	%xmm0	# b a _ _ -> b b b a
++	vxor	v6, v6, v1		# vpxor		%xmm1,	%xmm6,	%xmm6	# -> c+d c 0 0
++	vxor	v6, v6, v0		# vpxor		%xmm0,	%xmm6,	%xmm6	# -> b+c+d b+c b a
++	vmr	v0, v6
++	?vsldoi	v6, v6, v9, 8
++	?vsldoi	v6, v9, v6, 8		# clobber low side with zeros
++	blr
++	.long	0
++	.byte	0,12,0x14,0,0,0,0,0
++
++##
++##  .aes_schedule_round
++##
++##  Runs one main round of the key schedule on %xmm0, %xmm7
++##
++##  Specifically, runs subbytes on the high dword of %xmm0
++##  then rotates it by one byte and xors into the low dword of
++##  %xmm7.
++##
++##  Adds rcon from low byte of %xmm8, then rotates %xmm8 for
++##  next rcon.
++##
++##  Smears the dwords of %xmm7 by xoring the low into the
++##  second low, result into third, result into highest.
++##
++##  Returns results in %xmm7 = %xmm0.
++##  Clobbers %xmm1-%xmm4, %r11.
++##
++.align	4
++_vpaes_schedule_round:
++	# extract rcon from xmm8
++	#vxor	v4, v4, v4		# vpxor		%xmm4,	%xmm4,	%xmm4
++	?vsldoi	v1, $rcon, v9, 15	# vpalignr	\$15,	%xmm8,	%xmm4,	%xmm1
++	?vsldoi	$rcon, $rcon, $rcon, 15	# vpalignr	\$15,	%xmm8,	%xmm8,	%xmm8
++	vxor	v7, v7, v1		# vpxor		%xmm1,	%xmm7,	%xmm7
++
++	# rotate
++	?vspltw	v0, v0, 3		# vpshufd	\$0xFF,	%xmm0,	%xmm0
++	?vsldoi	v0, v0, v0, 1		# vpalignr	\$1,	%xmm0,	%xmm0,	%xmm0
++
++	# fall through...
++
++	# low round: same as high round, but no rotation and no rcon.
++_vpaes_schedule_low_round:
++	# smear xmm7
++	?vsldoi	v1, v9, v7, 12		# vpslldq	\$4,	%xmm7,	%xmm1
++	vxor	v7, v7, v1		# vpxor		%xmm1,	%xmm7,	%xmm7
++	vspltisb	v1, 0x0f	# 0x0f..0f
++	?vsldoi	v4, v9, v7, 8		# vpslldq	\$8,	%xmm7,	%xmm4
++
++	# subbytes
++	vand	v1, v1, v0		# vpand		%xmm9,	%xmm0,	%xmm1		# 0 = k
++	vsrb	v0, v0, v8		# vpsrlb	\$4,	%xmm0,	%xmm0		# 1 = i
++	 vxor	v7, v7, v4		# vpxor		%xmm4,	%xmm7,	%xmm7
++	vperm	v2, $invhi, v9, v1	# vpshufb	%xmm1,	%xmm11,	%xmm2		# 2 = a/k
++	vxor	v1, v1, v0		# vpxor		%xmm0,	%xmm1,	%xmm1		# 0 = j
++	vperm	v3, $invlo, v9, v0	# vpshufb	%xmm0, 	%xmm10,	%xmm3		# 3 = 1/i
++	vxor	v3, v3, v2		# vpxor		%xmm2,	%xmm3,	%xmm3		# 3 = iak = 1/i + a/k
++	vperm	v4, $invlo, v9, v1	# vpshufb	%xmm1,	%xmm10,	%xmm4		# 4 = 1/j
++	 vxor	v7, v7, v26		# vpxor		.Lk_s63(%rip),	%xmm7,	%xmm7
++	vperm	v3, $invlo, v9, v3	# vpshufb	%xmm3,	%xmm10,	%xmm3		# 2 = 1/iak
++	vxor	v4, v4, v2		# vpxor		%xmm2,	%xmm4,	%xmm4		# 4 = jak = 1/j + a/k
++	vperm	v2, $invlo, v9, v4	# vpshufb	%xmm4,	%xmm10,	%xmm2		# 3 = 1/jak
++	vxor	v3, v3, v1		# vpxor		%xmm1,	%xmm3,	%xmm3		# 2 = io
++	vxor	v2, v2, v0		# vpxor		%xmm0,	%xmm2,	%xmm2		# 3 = jo
++	vperm	v4, v15, v9, v3		# vpshufb	%xmm3,	%xmm13,	%xmm4		# 4 = sbou
++	vperm	v1, v14, v9, v2		# vpshufb	%xmm2,	%xmm12,	%xmm1		# 0 = sb1t
++	vxor	v1, v1, v4		# vpxor		%xmm4,	%xmm1,	%xmm1		# 0 = sbox output
++
++	# add in smeared stuff
++	vxor	v0, v1, v7		# vpxor		%xmm7,	%xmm1,	%xmm0
++	vxor	v7, v1, v7		# vmovdqa	%xmm0,	%xmm7
++	blr
++	.long	0
++	.byte	0,12,0x14,0,0,0,0,0
++
++##
++##  .aes_schedule_transform
++##
++##  Linear-transform %xmm0 according to tables at (%r11)
++##
++##  Requires that %xmm9 = 0x0F0F... as in preheat
++##  Output in %xmm0
++##  Clobbers %xmm2
++##
++.align	4
++_vpaes_schedule_transform:
++	#vand	v1, v0, v9		# vpand		%xmm9,	%xmm0,	%xmm1
++	vsrb	v2, v0, v8		# vpsrlb	\$4,	%xmm0,	%xmm0
++					# vmovdqa	(%r11),	%xmm2 	# lo
++	vperm	v0, $iptlo, $iptlo, v0	# vpshufb	%xmm1,	%xmm2,	%xmm2
++					# vmovdqa	16(%r11),	%xmm1 # hi
++	vperm	v2, $ipthi, $ipthi, v2	# vpshufb	%xmm0,	%xmm1,	%xmm0
++	vxor	v0, v0, v2		# vpxor		%xmm2,	%xmm0,	%xmm0
++	blr
++	.long	0
++	.byte	0,12,0x14,0,0,0,0,0
++
++##
++##  .aes_schedule_mangle
++##
++##  Mangle xmm0 from (basis-transformed) standard version
++##  to our version.
++##
++##  On encrypt,
++##    xor with 0x63
++##    multiply by circulant 0,1,1,1
++##    apply shiftrows transform
++##
++##  On decrypt,
++##    xor with 0x63
++##    multiply by "inverse mixcolumns" circulant E,B,D,9
++##    deskew
++##    apply shiftrows transform
++##
++##
++##  Writes out to (%rdx), and increments or decrements it
++##  Keeps track of round number mod 4 in %r8
++##  Preserves xmm0
++##  Clobbers xmm1-xmm5
++##
++.align	4
++_vpaes_schedule_mangle:
++	#vmr	v4, v0			# vmovdqa	%xmm0,	%xmm4	# save xmm0 for later
++					# vmovdqa	.Lk_mc_forward(%rip),%xmm5
++	bne	$dir, Lschedule_mangle_dec
++
++	# encrypting
++	vxor	v4, v0, v26		# vpxor	.Lk_s63(%rip),	%xmm0,	%xmm4
++	addi	$out, $out, 16		# add	\$16,	%rdx
++	vperm	v4, v4, v4, v25		# vpshufb	%xmm5,	%xmm4,	%xmm4
++	vperm	v1, v4, v4, v25		# vpshufb	%xmm5,	%xmm4,	%xmm1
++	vperm	v3, v1, v1, v25		# vpshufb	%xmm5,	%xmm1,	%xmm3
++	vxor	v4, v4, v1		# vpxor		%xmm1,	%xmm4,	%xmm4
++	lvx	v1, r8, r10		# vmovdqa	(%r8,%r10),	%xmm1
++	vxor	v3, v3, v4		# vpxor		%xmm4,	%xmm3,	%xmm3
++
++	vperm	v3, v3, v3, v1		# vpshufb	%xmm1,	%xmm3,	%xmm3
++	addi	r8, r8, -16		# add	\$-16,	%r8
++	andi.	r8, r8, 0x30		# and	\$0x30,	%r8
++
++	#stvx	v3, 0, $out		# vmovdqu	%xmm3,	(%rdx)
++	vperm	v1, v3, v3, $outperm	# rotate right/left
++	vsel	v2, $outhead, v1, $outmask
++	vmr	$outhead, v1
++	stvx	v2, 0, $out
++	blr
++
++.align	4
++Lschedule_mangle_dec:
++	# inverse mix columns
++					# lea	.Lk_dksd(%rip),%r11
++	vsrb	v1, v0, v8		# vpsrlb	\$4,	%xmm4,	%xmm1	# 1 = hi
++	#and	v4, v0, v9		# vpand		%xmm9,	%xmm4,	%xmm4	# 4 = lo
++
++					# vmovdqa	0x00(%r11),	%xmm2
++	vperm	v2, v16, v16, v0	# vpshufb	%xmm4,	%xmm2,	%xmm2
++					# vmovdqa	0x10(%r11),	%xmm3
++	vperm	v3, v17, v17, v1	# vpshufb	%xmm1,	%xmm3,	%xmm3
++	vxor	v3, v3, v2		# vpxor		%xmm2,	%xmm3,	%xmm3
++	vperm	v3, v3, v9, v25		# vpshufb	%xmm5,	%xmm3,	%xmm3
++
++					# vmovdqa	0x20(%r11),	%xmm2
++	vperm	v2, v18, v18, v0	# vpshufb	%xmm4,	%xmm2,	%xmm2
++	vxor	v2, v2, v3		# vpxor		%xmm3,	%xmm2,	%xmm2
++					# vmovdqa	0x30(%r11),	%xmm3
++	vperm	v3, v19, v19, v1	# vpshufb	%xmm1,	%xmm3,	%xmm3
++	vxor	v3, v3, v2		# vpxor		%xmm2,	%xmm3,	%xmm3
++	vperm	v3, v3, v9, v25		# vpshufb	%xmm5,	%xmm3,	%xmm3
++
++					# vmovdqa	0x40(%r11),	%xmm2
++	vperm	v2, v20, v20, v0	# vpshufb	%xmm4,	%xmm2,	%xmm2
++	vxor	v2, v2, v3		# vpxor		%xmm3,	%xmm2,	%xmm2
++					# vmovdqa	0x50(%r11),	%xmm3
++	vperm	v3, v21, v21, v1	# vpshufb	%xmm1,	%xmm3,	%xmm3
++	vxor	v3, v3, v2		# vpxor		%xmm2,	%xmm3,	%xmm3
++
++					# vmovdqa	0x60(%r11),	%xmm2
++	vperm	v2, v22, v22, v0	# vpshufb	%xmm4,	%xmm2,	%xmm2
++	vperm	v3, v3, v9, v25		# vpshufb	%xmm5,	%xmm3,	%xmm3
++					# vmovdqa	0x70(%r11),	%xmm4
++	vperm	v4, v23, v23, v1	# vpshufb	%xmm1,	%xmm4,	%xmm4
++	lvx	v1, r8, r10		# vmovdqa	(%r8,%r10),	%xmm1
++	vxor	v2, v2, v3		# vpxor		%xmm3,	%xmm2,	%xmm2
++	vxor	v3, v4, v2		# vpxor		%xmm2,	%xmm4,	%xmm3
++
++	addi	$out, $out, -16		# add	\$-16,	%rdx
++
++	vperm	v3, v3, v3, v1		# vpshufb	%xmm1,	%xmm3,	%xmm3
++	addi	r8, r8, -16		# add	\$-16,	%r8
++	andi.	r8, r8, 0x30		# and	\$0x30,	%r8
++
++	#stvx	v3, 0, $out		# vmovdqu	%xmm3,	(%rdx)
++	vperm	v1, v3, v3, $outperm	# rotate right/left
++	vsel	v2, $outhead, v1, $outmask
++	vmr	$outhead, v1
++	stvx	v2, 0, $out
++	blr
++	.long	0
++	.byte	0,12,0x14,0,0,0,0,0
++
++.globl	.vpaes_set_encrypt_key
++.align	5
++.vpaes_set_encrypt_key:
++	$STU	$sp,-$FRAME($sp)
++	li	r10,`15+6*$SIZE_T`
++	li	r11,`31+6*$SIZE_T`
++	mflr	r0
++	mfspr	r6, 256			# save vrsave
++	stvx	v20,r10,$sp
++	addi	r10,r10,32
++	stvx	v21,r11,$sp
++	addi	r11,r11,32
++	stvx	v22,r10,$sp
++	addi	r10,r10,32
++	stvx	v23,r11,$sp
++	addi	r11,r11,32
++	stvx	v24,r10,$sp
++	addi	r10,r10,32
++	stvx	v25,r11,$sp
++	addi	r11,r11,32
++	stvx	v26,r10,$sp
++	addi	r10,r10,32
++	stvx	v27,r11,$sp
++	addi	r11,r11,32
++	stvx	v28,r10,$sp
++	addi	r10,r10,32
++	stvx	v29,r11,$sp
++	addi	r11,r11,32
++	stvx	v30,r10,$sp
++	stvx	v31,r11,$sp
++	stw	r6,`$FRAME-4`($sp)	# save vrsave
++	li	r7, -1
++	$PUSH	r0, `$FRAME+$LRSAVE`($sp)
++	mtspr	256, r7			# preserve all AltiVec registers
++
++	srwi	r9, $bits, 5		# shr	\$5,%eax
++	addi	r9, r9, 6		# add	\$5,%eax
++	stw	r9, 240($out)		# mov	%eax,240(%rdx)	# AES_KEY->rounds = nbits/32+5;
++
++	cmplw	$dir, $bits, $bits	# set encrypt direction
++	li	r8, 0x30		# mov	\$0x30,%r8d
++	bl	_vpaes_schedule_core
++
++	$POP	r0, `$FRAME+$LRSAVE`($sp)
++	li	r10,`15+6*$SIZE_T`
++	li	r11,`31+6*$SIZE_T`
++	mtspr	256, r6			# restore vrsave
++	mtlr	r0
++	xor	r3, r3, r3
++	lvx	v20,r10,$sp
++	addi	r10,r10,32
++	lvx	v21,r11,$sp
++	addi	r11,r11,32
++	lvx	v22,r10,$sp
++	addi	r10,r10,32
++	lvx	v23,r11,$sp
++	addi	r11,r11,32
++	lvx	v24,r10,$sp
++	addi	r10,r10,32
++	lvx	v25,r11,$sp
++	addi	r11,r11,32
++	lvx	v26,r10,$sp
++	addi	r10,r10,32
++	lvx	v27,r11,$sp
++	addi	r11,r11,32
++	lvx	v28,r10,$sp
++	addi	r10,r10,32
++	lvx	v29,r11,$sp
++	addi	r11,r11,32
++	lvx	v30,r10,$sp
++	lvx	v31,r11,$sp
++	addi	$sp,$sp,$FRAME
++	blr
++	.long	0
++	.byte	0,12,0x04,1,0x80,0,3,0
++	.long	0
++.size	.vpaes_set_encrypt_key,.-.vpaes_set_encrypt_key
++
++.globl	.vpaes_set_decrypt_key
++.align	4
++.vpaes_set_decrypt_key:
++	$STU	$sp,-$FRAME($sp)
++	li	r10,`15+6*$SIZE_T`
++	li	r11,`31+6*$SIZE_T`
++	mflr	r0
++	mfspr	r6, 256			# save vrsave
++	stvx	v20,r10,$sp
++	addi	r10,r10,32
++	stvx	v21,r11,$sp
++	addi	r11,r11,32
++	stvx	v22,r10,$sp
++	addi	r10,r10,32
++	stvx	v23,r11,$sp
++	addi	r11,r11,32
++	stvx	v24,r10,$sp
++	addi	r10,r10,32
++	stvx	v25,r11,$sp
++	addi	r11,r11,32
++	stvx	v26,r10,$sp
++	addi	r10,r10,32
++	stvx	v27,r11,$sp
++	addi	r11,r11,32
++	stvx	v28,r10,$sp
++	addi	r10,r10,32
++	stvx	v29,r11,$sp
++	addi	r11,r11,32
++	stvx	v30,r10,$sp
++	stvx	v31,r11,$sp
++	stw	r6,`$FRAME-4`($sp)	# save vrsave
++	li	r7, -1
++	$PUSH	r0, `$FRAME+$LRSAVE`($sp)
++	mtspr	256, r7			# preserve all AltiVec registers
++
++	srwi	r9, $bits, 5		# shr	\$5,%eax
++	addi	r9, r9, 6		# add	\$5,%eax
++	stw	r9, 240($out)		# mov	%eax,240(%rdx)	# AES_KEY->rounds = nbits/32+5;
++
++	slwi	r9, r9, 4		# shl	\$4,%eax
++	add	$out, $out, r9		# lea	(%rdx,%rax),%rdx
++
++	cmplwi	$dir, $bits, 0		# set decrypt direction
++	srwi	r8, $bits, 1		# shr	\$1,%r8d
++	andi.	r8, r8, 32		# and	\$32,%r8d
++	xori	r8, r8, 32		# xor	\$32,%r8d	# nbits==192?0:32
++	bl	_vpaes_schedule_core
++
++	$POP	r0,  `$FRAME+$LRSAVE`($sp)
++	li	r10,`15+6*$SIZE_T`
++	li	r11,`31+6*$SIZE_T`
++	mtspr	256, r6			# restore vrsave
++	mtlr	r0
++	xor	r3, r3, r3
++	lvx	v20,r10,$sp
++	addi	r10,r10,32
++	lvx	v21,r11,$sp
++	addi	r11,r11,32
++	lvx	v22,r10,$sp
++	addi	r10,r10,32
++	lvx	v23,r11,$sp
++	addi	r11,r11,32
++	lvx	v24,r10,$sp
++	addi	r10,r10,32
++	lvx	v25,r11,$sp
++	addi	r11,r11,32
++	lvx	v26,r10,$sp
++	addi	r10,r10,32
++	lvx	v27,r11,$sp
++	addi	r11,r11,32
++	lvx	v28,r10,$sp
++	addi	r10,r10,32
++	lvx	v29,r11,$sp
++	addi	r11,r11,32
++	lvx	v30,r10,$sp
++	lvx	v31,r11,$sp
++	addi	$sp,$sp,$FRAME
++	blr
++	.long	0
++	.byte	0,12,0x04,1,0x80,0,3,0
++	.long	0
++.size	.vpaes_set_decrypt_key,.-.vpaes_set_decrypt_key
++___
++}
++
++my $consts=1;
++foreach  (split("\n",$code)) {
++	s/\`([^\`]*)\`/eval $1/geo;
++
++	# constants table endian-specific conversion
++	if ($consts && m/\.long\s+(.+)\s+(\?[a-z]*)$/o) {
++	    my $conv=$2;
++	    my @bytes=();
++
++	    # convert to endian-agnostic format
++	    foreach (split(/,\s+/,$1)) {
++		my $l = /^0/?oct:int;
++		push @bytes,($l>>24)&0xff,($l>>16)&0xff,($l>>8)&0xff,$l&0xff;
++	    }
++
++	    # little-endian conversion
++	    if ($flavour =~ /le$/o) {
++		SWITCH: for($conv)  {
++		    /\?inv/ && do   { @bytes=map($_^0xf,@bytes); last; };
++		    /\?rev/ && do   { @bytes=reverse(@bytes);    last; }; 
++		}
++	    }
++
++	    #emit
++	    print ".byte\t",join(',',map (sprintf("0x%02x",$_),@bytes)),"\n";
++	    next;
++	}
++	$consts=0 if (m/Lconsts:/o);	# end of table
++
++	# instructions prefixed with '?' are endian-specific and need
++	# to be adjusted accordingly...
++	if ($flavour =~ /le$/o) {	# little-endian
++	    s/\?lvsr/lvsl/o or
++	    s/\?lvsl/lvsr/o or
++	    s/\?(vperm\s+v[0-9]+,\s*)(v[0-9]+,\s*)(v[0-9]+,\s*)(v[0-9]+)/$1$3$2$4/o or
++	    s/\?(vsldoi\s+v[0-9]+,\s*)(v[0-9]+,)\s*(v[0-9]+,\s*)([0-9]+)/$1$3$2 16-$4/o or
++	    s/\?(vspltw\s+v[0-9]+,\s*)(v[0-9]+,)\s*([0-9])/$1$2 3-$3/o;
++	} else {			# big-endian
++	    s/\?([a-z]+)/$1/o;
++	}
++
++	print $_,"\n";
++}
++
++close STDOUT;
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/aes/asm/vpaes-x86.pl b/CryptoPkg/Library/OpensslLib/openssl/crypto/aes/asm/vpaes-x86.pl
+new file mode 100644
+index 0000000..47615c0
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/aes/asm/vpaes-x86.pl
+@@ -0,0 +1,916 @@
++#! /usr/bin/env perl
++# Copyright 2011-2016 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
++# in the file LICENSE in the source distribution or at
++# https://www.openssl.org/source/license.html
++
++
++######################################################################
++## Constant-time SSSE3 AES core implementation.
++## version 0.1
++##
++## By Mike Hamburg (Stanford University), 2009
++## Public domain.
++##
++## For details see http://shiftleft.org/papers/vector_aes/ and
++## http://crypto.stanford.edu/vpaes/.
++
++######################################################################
++# September 2011.
++#
++# Port vpaes-x86_64.pl as 32-bit "almost" drop-in replacement for
++# aes-586.pl. "Almost" refers to the fact that AES_cbc_encrypt
++# doesn't handle partial vectors (doesn't have to if called from
++# EVP only). "Drop-in" implies that this module doesn't share key
++# schedule structure with the original nor does it make assumption
++# about its alignment...
++#
++# Performance summary. aes-586.pl column lists large-block CBC
++# encrypt/decrypt/with-hyper-threading-off(*) results in cycles per
++# byte processed with 128-bit key, and vpaes-x86.pl column - [also
++# large-block CBC] encrypt/decrypt.
++#
++#		aes-586.pl		vpaes-x86.pl
++#
++# Core 2(**)	28.1/41.4/18.3		21.9/25.2(***)
++# Nehalem	27.9/40.4/18.1		10.2/11.9
++# Atom		70.7/92.1/60.1		61.1/75.4(***)
++# Silvermont	45.4/62.9/24.1		49.2/61.1(***)
++#
++# (*)	"Hyper-threading" in the context refers rather to cache shared
++#	among multiple cores, than to specifically Intel HTT. As vast
++#	majority of contemporary cores share cache, slower code path
++#	is common place. In other words "with-hyper-threading-off"
++#	results are presented mostly for reference purposes.
++#
++# (**)	"Core 2" refers to initial 65nm design, a.k.a. Conroe.
++#
++# (***)	Less impressive improvement on Core 2 and Atom is due to slow
++#	pshufb,	yet it's respectable +28%/64%  improvement on Core 2
++#	and +15% on Atom (as implied, over "hyper-threading-safe"
++#	code path).
++#
++#						
++
++$0 =~ m/(.*[\/\\])[^\/\\]+$/; $dir=$1;
++push(@INC,"${dir}","${dir}../../perlasm");
++require "x86asm.pl";
++
++$output = pop;
++open OUT,">$output";
++*STDOUT=*OUT;
++
++&asm_init($ARGV[0],"vpaes-x86.pl",$x86only = $ARGV[$#ARGV] eq "386");
++
++$PREFIX="vpaes";
++
++my  ($round, $base, $magic, $key, $const, $inp, $out)=
++    ("eax",  "ebx", "ecx",  "edx","ebp",  "esi","edi");
++
++&static_label("_vpaes_consts");
++&static_label("_vpaes_schedule_low_round");
++
++&set_label("_vpaes_consts",64);
++$k_inv=-0x30;		# inv, inva
++	&data_word(0x0D080180,0x0E05060F,0x0A0B0C02,0x04070309);
++	&data_word(0x0F0B0780,0x01040A06,0x02050809,0x030D0E0C);
++
++$k_s0F=-0x10;		# s0F
++	&data_word(0x0F0F0F0F,0x0F0F0F0F,0x0F0F0F0F,0x0F0F0F0F);
++
++$k_ipt=0x00;		# input transform (lo, hi)
++	&data_word(0x5A2A7000,0xC2B2E898,0x52227808,0xCABAE090);
++	&data_word(0x317C4D00,0x4C01307D,0xB0FDCC81,0xCD80B1FC);
++
++$k_sb1=0x20;		# sb1u, sb1t
++	&data_word(0xCB503E00,0xB19BE18F,0x142AF544,0xA5DF7A6E);
++	&data_word(0xFAE22300,0x3618D415,0x0D2ED9EF,0x3BF7CCC1);
++$k_sb2=0x40;		# sb2u, sb2t
++	&data_word(0x0B712400,0xE27A93C6,0xBC982FCD,0x5EB7E955);
++	&data_word(0x0AE12900,0x69EB8840,0xAB82234A,0xC2A163C8);
++$k_sbo=0x60;		# sbou, sbot
++	&data_word(0x6FBDC700,0xD0D26D17,0xC502A878,0x15AABF7A);
++	&data_word(0x5FBB6A00,0xCFE474A5,0x412B35FA,0x8E1E90D1);
++
++$k_mc_forward=0x80;	# mc_forward
++	&data_word(0x00030201,0x04070605,0x080B0A09,0x0C0F0E0D);
++	&data_word(0x04070605,0x080B0A09,0x0C0F0E0D,0x00030201);
++	&data_word(0x080B0A09,0x0C0F0E0D,0x00030201,0x04070605);
++	&data_word(0x0C0F0E0D,0x00030201,0x04070605,0x080B0A09);
++
++$k_mc_backward=0xc0;	# mc_backward
++	&data_word(0x02010003,0x06050407,0x0A09080B,0x0E0D0C0F);
++	&data_word(0x0E0D0C0F,0x02010003,0x06050407,0x0A09080B);
++	&data_word(0x0A09080B,0x0E0D0C0F,0x02010003,0x06050407);
++	&data_word(0x06050407,0x0A09080B,0x0E0D0C0F,0x02010003);
++
++$k_sr=0x100;		# sr
++	&data_word(0x03020100,0x07060504,0x0B0A0908,0x0F0E0D0C);
++	&data_word(0x0F0A0500,0x030E0904,0x07020D08,0x0B06010C);
++	&data_word(0x0B020900,0x0F060D04,0x030A0108,0x070E050C);
++	&data_word(0x070A0D00,0x0B0E0104,0x0F020508,0x0306090C);
++
++$k_rcon=0x140;		# rcon
++	&data_word(0xAF9DEEB6,0x1F8391B9,0x4D7C7D81,0x702A9808);
++
++$k_s63=0x150;		# s63: all equal to 0x63 transformed
++	&data_word(0x5B5B5B5B,0x5B5B5B5B,0x5B5B5B5B,0x5B5B5B5B);
++
++$k_opt=0x160;		# output transform
++	&data_word(0xD6B66000,0xFF9F4929,0xDEBE6808,0xF7974121);
++	&data_word(0x50BCEC00,0x01EDBD51,0xB05C0CE0,0xE10D5DB1);
++
++$k_deskew=0x180;	# deskew tables: inverts the sbox's "skew"
++	&data_word(0x47A4E300,0x07E4A340,0x5DBEF91A,0x1DFEB95A);
++	&data_word(0x83EA6900,0x5F36B5DC,0xF49D1E77,0x2841C2AB);
++##
++##  Decryption stuff
++##  Key schedule constants
++##
++$k_dksd=0x1a0;		# decryption key schedule: invskew x*D
++	&data_word(0xA3E44700,0xFEB91A5D,0x5A1DBEF9,0x0740E3A4);
++	&data_word(0xB5368300,0x41C277F4,0xAB289D1E,0x5FDC69EA);
++$k_dksb=0x1c0;		# decryption key schedule: invskew x*B
++	&data_word(0x8550D500,0x9A4FCA1F,0x1CC94C99,0x03D65386);
++	&data_word(0xB6FC4A00,0x115BEDA7,0x7E3482C8,0xD993256F);
++$k_dkse=0x1e0;		# decryption key schedule: invskew x*E + 0x63
++	&data_word(0x1FC9D600,0xD5031CCA,0x994F5086,0x53859A4C);
++	&data_word(0x4FDC7BE8,0xA2319605,0x20B31487,0xCD5EF96A);
++$k_dks9=0x200;		# decryption key schedule: invskew x*9
++	&data_word(0x7ED9A700,0xB6116FC8,0x82255BFC,0x4AED9334);
++	&data_word(0x27143300,0x45765162,0xE9DAFDCE,0x8BB89FAC);
++
++##
++##  Decryption stuff
++##  Round function constants
++##
++$k_dipt=0x220;		# decryption input transform
++	&data_word(0x0B545F00,0x0F505B04,0x114E451A,0x154A411E);
++	&data_word(0x60056500,0x86E383E6,0xF491F194,0x12771772);
++
++$k_dsb9=0x240;		# decryption sbox output *9*u, *9*t
++	&data_word(0x9A86D600,0x851C0353,0x4F994CC9,0xCAD51F50);
++	&data_word(0xECD74900,0xC03B1789,0xB2FBA565,0x725E2C9E);
++$k_dsbd=0x260;		# decryption sbox output *D*u, *D*t
++	&data_word(0xE6B1A200,0x7D57CCDF,0x882A4439,0xF56E9B13);
++	&data_word(0x24C6CB00,0x3CE2FAF7,0x15DEEFD3,0x2931180D);
++$k_dsbb=0x280;		# decryption sbox output *B*u, *B*t
++	&data_word(0x96B44200,0xD0226492,0xB0F2D404,0x602646F6);
++	&data_word(0xCD596700,0xC19498A6,0x3255AA6B,0xF3FF0C3E);
++$k_dsbe=0x2a0;		# decryption sbox output *E*u, *E*t
++	&data_word(0x26D4D000,0x46F29296,0x64B4F6B0,0x22426004);
++	&data_word(0xFFAAC100,0x0C55A6CD,0x98593E32,0x9467F36B);
++$k_dsbo=0x2c0;		# decryption sbox final output
++	&data_word(0x7EF94000,0x1387EA53,0xD4943E2D,0xC7AA6DB9);
++	&data_word(0x93441D00,0x12D7560F,0xD8C58E9C,0xCA4B8159);
++&asciz	("Vector Permutation AES for x86/SSSE3, Mike Hamburg (Stanford University)");
++&align	(64);
++
++&function_begin_B("_vpaes_preheat");
++	&add	($const,&DWP(0,"esp"));
++	&movdqa	("xmm7",&QWP($k_inv,$const));
++	&movdqa	("xmm6",&QWP($k_s0F,$const));
++	&ret	();
++&function_end_B("_vpaes_preheat");
++
++##
++##  _aes_encrypt_core
++##
++##  AES-encrypt %xmm0.
++##
++##  Inputs:
++##     %xmm0 = input
++##     %xmm6-%xmm7 as in _vpaes_preheat
++##    (%edx) = scheduled keys
++##
++##  Output in %xmm0
++##  Clobbers  %xmm1-%xmm5, %eax, %ebx, %ecx, %edx
++##
++##
++&function_begin_B("_vpaes_encrypt_core");
++	&mov	($magic,16);
++	&mov	($round,&DWP(240,$key));
++	&movdqa	("xmm1","xmm6")
++	&movdqa	("xmm2",&QWP($k_ipt,$const));
++	&pandn	("xmm1","xmm0");
++	&pand	("xmm0","xmm6");
++	&movdqu	("xmm5",&QWP(0,$key));
++	&pshufb	("xmm2","xmm0");
++	&movdqa	("xmm0",&QWP($k_ipt+16,$const));
++	&pxor	("xmm2","xmm5");
++	&psrld	("xmm1",4);
++	&add	($key,16);
++	&pshufb	("xmm0","xmm1");
++	&lea	($base,&DWP($k_mc_backward,$const));
++	&pxor	("xmm0","xmm2");
++	&jmp	(&label("enc_entry"));
++
++
++&set_label("enc_loop",16);
++	# middle of middle round
++	&movdqa	("xmm4",&QWP($k_sb1,$const));	# 4 : sb1u
++	&movdqa	("xmm0",&QWP($k_sb1+16,$const));# 0 : sb1t
++	&pshufb	("xmm4","xmm2");		# 4 = sb1u
++	&pshufb	("xmm0","xmm3");		# 0 = sb1t
++	&pxor	("xmm4","xmm5");		# 4 = sb1u + k
++	&movdqa	("xmm5",&QWP($k_sb2,$const));	# 4 : sb2u
++	&pxor	("xmm0","xmm4");		# 0 = A
++	&movdqa	("xmm1",&QWP(-0x40,$base,$magic));# .Lk_mc_forward[]
++	&pshufb	("xmm5","xmm2");		# 4 = sb2u
++	&movdqa	("xmm2",&QWP($k_sb2+16,$const));# 2 : sb2t
++	&movdqa	("xmm4",&QWP(0,$base,$magic));	# .Lk_mc_backward[]
++	&pshufb	("xmm2","xmm3");		# 2 = sb2t
++	&movdqa	("xmm3","xmm0");		# 3 = A
++	&pxor	("xmm2","xmm5");		# 2 = 2A
++	&pshufb	("xmm0","xmm1");		# 0 = B
++	&add	($key,16);			# next key
++	&pxor	("xmm0","xmm2");		# 0 = 2A+B
++	&pshufb	("xmm3","xmm4");		# 3 = D
++	&add	($magic,16);			# next mc
++	&pxor	("xmm3","xmm0");		# 3 = 2A+B+D
++	&pshufb	("xmm0","xmm1");		# 0 = 2B+C
++	&and	($magic,0x30);			# ... mod 4
++	&sub	($round,1);			# nr--
++	&pxor	("xmm0","xmm3");		# 0 = 2A+3B+C+D
++
++&set_label("enc_entry");
++	# top of round
++	&movdqa	("xmm1","xmm6");		# 1 : i
++	&movdqa	("xmm5",&QWP($k_inv+16,$const));# 2 : a/k
++	&pandn	("xmm1","xmm0");		# 1 = i<<4
++	&psrld	("xmm1",4);			# 1 = i
++	&pand	("xmm0","xmm6");		# 0 = k
++	&pshufb	("xmm5","xmm0");		# 2 = a/k
++	&movdqa	("xmm3","xmm7");		# 3 : 1/i
++	&pxor	("xmm0","xmm1");		# 0 = j
++	&pshufb	("xmm3","xmm1");		# 3 = 1/i
++	&movdqa	("xmm4","xmm7");		# 4 : 1/j
++	&pxor	("xmm3","xmm5");		# 3 = iak = 1/i + a/k
++	&pshufb	("xmm4","xmm0");		# 4 = 1/j
++	&movdqa	("xmm2","xmm7");		# 2 : 1/iak
++	&pxor	("xmm4","xmm5");		# 4 = jak = 1/j + a/k
++	&pshufb	("xmm2","xmm3");		# 2 = 1/iak
++	&movdqa	("xmm3","xmm7");		# 3 : 1/jak
++	&pxor	("xmm2","xmm0");		# 2 = io
++	&pshufb	("xmm3","xmm4");		# 3 = 1/jak
++	&movdqu	("xmm5",&QWP(0,$key));
++	&pxor	("xmm3","xmm1");		# 3 = jo
++	&jnz	(&label("enc_loop"));
++
++	# middle of last round
++	&movdqa	("xmm4",&QWP($k_sbo,$const));	# 3 : sbou      .Lk_sbo
++	&movdqa	("xmm0",&QWP($k_sbo+16,$const));# 3 : sbot      .Lk_sbo+16
++	&pshufb	("xmm4","xmm2");		# 4 = sbou
++	&pxor	("xmm4","xmm5");		# 4 = sb1u + k
++	&pshufb	("xmm0","xmm3");		# 0 = sb1t
++	&movdqa	("xmm1",&QWP(0x40,$base,$magic));# .Lk_sr[]
++	&pxor	("xmm0","xmm4");		# 0 = A
++	&pshufb	("xmm0","xmm1");
++	&ret	();
++&function_end_B("_vpaes_encrypt_core");
++
++##
++##  Decryption core
++##
++##  Same API as encryption core.
++##
++&function_begin_B("_vpaes_decrypt_core");
++	&lea	($base,&DWP($k_dsbd,$const));
++	&mov	($round,&DWP(240,$key));
++	&movdqa	("xmm1","xmm6");
++	&movdqa	("xmm2",&QWP($k_dipt-$k_dsbd,$base));
++	&pandn	("xmm1","xmm0");
++	&mov	($magic,$round);
++	&psrld	("xmm1",4)
++	&movdqu	("xmm5",&QWP(0,$key));
++	&shl	($magic,4);
++	&pand	("xmm0","xmm6");
++	&pshufb	("xmm2","xmm0");
++	&movdqa	("xmm0",&QWP($k_dipt-$k_dsbd+16,$base));
++	&xor	($magic,0x30);
++	&pshufb	("xmm0","xmm1");
++	&and	($magic,0x30);
++	&pxor	("xmm2","xmm5");
++	&movdqa	("xmm5",&QWP($k_mc_forward+48,$const));
++	&pxor	("xmm0","xmm2");
++	&add	($key,16);
++	&lea	($magic,&DWP($k_sr-$k_dsbd,$base,$magic));
++	&jmp	(&label("dec_entry"));
++
++&set_label("dec_loop",16);
++##
++##  Inverse mix columns
++##
++	&movdqa	("xmm4",&QWP(-0x20,$base));	# 4 : sb9u
++	&movdqa	("xmm1",&QWP(-0x10,$base));	# 0 : sb9t
++	&pshufb	("xmm4","xmm2");		# 4 = sb9u
++	&pshufb	("xmm1","xmm3");		# 0 = sb9t
++	&pxor	("xmm0","xmm4");
++	&movdqa	("xmm4",&QWP(0,$base));		# 4 : sbdu
++	&pxor	("xmm0","xmm1");		# 0 = ch
++	&movdqa	("xmm1",&QWP(0x10,$base));	# 0 : sbdt
++
++	&pshufb	("xmm4","xmm2");		# 4 = sbdu
++	&pshufb	("xmm0","xmm5");		# MC ch
++	&pshufb	("xmm1","xmm3");		# 0 = sbdt
++	&pxor	("xmm0","xmm4");		# 4 = ch
++	&movdqa	("xmm4",&QWP(0x20,$base));	# 4 : sbbu
++	&pxor	("xmm0","xmm1");		# 0 = ch
++	&movdqa	("xmm1",&QWP(0x30,$base));	# 0 : sbbt
++
++	&pshufb	("xmm4","xmm2");		# 4 = sbbu
++	&pshufb	("xmm0","xmm5");		# MC ch
++	&pshufb	("xmm1","xmm3");		# 0 = sbbt
++	&pxor	("xmm0","xmm4");		# 4 = ch
++	&movdqa	("xmm4",&QWP(0x40,$base));	# 4 : sbeu
++	&pxor	("xmm0","xmm1");		# 0 = ch
++	&movdqa	("xmm1",&QWP(0x50,$base));	# 0 : sbet
++
++	&pshufb	("xmm4","xmm2");		# 4 = sbeu
++	&pshufb	("xmm0","xmm5");		# MC ch
++	&pshufb	("xmm1","xmm3");		# 0 = sbet
++	&pxor	("xmm0","xmm4");		# 4 = ch
++	&add	($key,16);			# next round key
++	&palignr("xmm5","xmm5",12);
++	&pxor	("xmm0","xmm1");		# 0 = ch
++	&sub	($round,1);			# nr--
++
++&set_label("dec_entry");
++	# top of round
++	&movdqa	("xmm1","xmm6");		# 1 : i
++	&movdqa	("xmm2",&QWP($k_inv+16,$const));# 2 : a/k
++	&pandn	("xmm1","xmm0");		# 1 = i<<4
++	&pand	("xmm0","xmm6");		# 0 = k
++	&psrld	("xmm1",4);			# 1 = i
++	&pshufb	("xmm2","xmm0");		# 2 = a/k
++	&movdqa	("xmm3","xmm7");		# 3 : 1/i
++	&pxor	("xmm0","xmm1");		# 0 = j
++	&pshufb	("xmm3","xmm1");		# 3 = 1/i
++	&movdqa	("xmm4","xmm7");		# 4 : 1/j
++	&pxor	("xmm3","xmm2");		# 3 = iak = 1/i + a/k
++	&pshufb	("xmm4","xmm0");		# 4 = 1/j
++	&pxor	("xmm4","xmm2");		# 4 = jak = 1/j + a/k
++	&movdqa	("xmm2","xmm7");		# 2 : 1/iak
++	&pshufb	("xmm2","xmm3");		# 2 = 1/iak
++	&movdqa	("xmm3","xmm7");		# 3 : 1/jak
++	&pxor	("xmm2","xmm0");		# 2 = io
++	&pshufb	("xmm3","xmm4");		# 3 = 1/jak
++	&movdqu	("xmm0",&QWP(0,$key));
++	&pxor	("xmm3","xmm1");		# 3 = jo
++	&jnz	(&label("dec_loop"));
++
++	# middle of last round
++	&movdqa	("xmm4",&QWP(0x60,$base));	# 3 : sbou
++	&pshufb	("xmm4","xmm2");		# 4 = sbou
++	&pxor	("xmm4","xmm0");		# 4 = sb1u + k
++	&movdqa	("xmm0",&QWP(0x70,$base));	# 0 : sbot
++	&movdqa	("xmm2",&QWP(0,$magic));
++	&pshufb	("xmm0","xmm3");		# 0 = sb1t
++	&pxor	("xmm0","xmm4");		# 0 = A
++	&pshufb	("xmm0","xmm2");
++	&ret	();
++&function_end_B("_vpaes_decrypt_core");
++
++########################################################
++##                                                    ##
++##                  AES key schedule                  ##
++##                                                    ##
++########################################################
++&function_begin_B("_vpaes_schedule_core");
++	&add	($const,&DWP(0,"esp"));
++	&movdqu	("xmm0",&QWP(0,$inp));		# load key (unaligned)
++	&movdqa	("xmm2",&QWP($k_rcon,$const));	# load rcon
++
++	# input transform
++	&movdqa	("xmm3","xmm0");
++	&lea	($base,&DWP($k_ipt,$const));
++	&movdqa	(&QWP(4,"esp"),"xmm2");		# xmm8
++	&call	("_vpaes_schedule_transform");
++	&movdqa	("xmm7","xmm0");
++
++	&test	($out,$out);
++	&jnz	(&label("schedule_am_decrypting"));
++
++	# encrypting, output zeroth round key after transform
++	&movdqu	(&QWP(0,$key),"xmm0");
++	&jmp	(&label("schedule_go"));
++
++&set_label("schedule_am_decrypting");
++	# decrypting, output zeroth round key after shiftrows
++	&movdqa	("xmm1",&QWP($k_sr,$const,$magic));
++	&pshufb	("xmm3","xmm1");
++	&movdqu	(&QWP(0,$key),"xmm3");
++	&xor	($magic,0x30);
++
++&set_label("schedule_go");
++	&cmp	($round,192);
++	&ja	(&label("schedule_256"));
++	&je	(&label("schedule_192"));
++	# 128: fall though
++
++##
++##  .schedule_128
++##
++##  128-bit specific part of key schedule.
++##
++##  This schedule is really simple, because all its parts
++##  are accomplished by the subroutines.
++##
++&set_label("schedule_128");
++	&mov	($round,10);
++
++&set_label("loop_schedule_128");
++	&call	("_vpaes_schedule_round");
++	&dec	($round);
++	&jz	(&label("schedule_mangle_last"));
++	&call	("_vpaes_schedule_mangle");	# write output
++	&jmp	(&label("loop_schedule_128"));
++
++##
++##  .aes_schedule_192
++##
++##  192-bit specific part of key schedule.
++##
++##  The main body of this schedule is the same as the 128-bit
++##  schedule, but with more smearing.  The long, high side is
++##  stored in %xmm7 as before, and the short, low side is in
++##  the high bits of %xmm6.
++##
++##  This schedule is somewhat nastier, however, because each
++##  round produces 192 bits of key material, or 1.5 round keys.
++##  Therefore, on each cycle we do 2 rounds and produce 3 round
++##  keys.
++##
++&set_label("schedule_192",16);
++	&movdqu	("xmm0",&QWP(8,$inp));		# load key part 2 (very unaligned)
++	&call	("_vpaes_schedule_transform");	# input transform	
++	&movdqa	("xmm6","xmm0");		# save short part
++	&pxor	("xmm4","xmm4");		# clear 4
++	&movhlps("xmm6","xmm4");		# clobber low side with zeros
++	&mov	($round,4);
++
++&set_label("loop_schedule_192");
++	&call	("_vpaes_schedule_round");
++	&palignr("xmm0","xmm6",8);
++	&call	("_vpaes_schedule_mangle");	# save key n
++	&call	("_vpaes_schedule_192_smear");
++	&call	("_vpaes_schedule_mangle");	# save key n+1
++	&call	("_vpaes_schedule_round");
++	&dec	($round);
++	&jz	(&label("schedule_mangle_last"));
++	&call	("_vpaes_schedule_mangle");	# save key n+2
++	&call	("_vpaes_schedule_192_smear");
++	&jmp	(&label("loop_schedule_192"));
++
++##
++##  .aes_schedule_256
++##
++##  256-bit specific part of key schedule.
++##
++##  The structure here is very similar to the 128-bit
++##  schedule, but with an additional "low side" in
++##  %xmm6.  The low side's rounds are the same as the
++##  high side's, except no rcon and no rotation.
++##
++&set_label("schedule_256",16);
++	&movdqu	("xmm0",&QWP(16,$inp));		# load key part 2 (unaligned)
++	&call	("_vpaes_schedule_transform");	# input transform	
++	&mov	($round,7);
++
++&set_label("loop_schedule_256");
++	&call	("_vpaes_schedule_mangle");	# output low result
++	&movdqa	("xmm6","xmm0");		# save cur_lo in xmm6
++
++	# high round
++	&call	("_vpaes_schedule_round");
++	&dec	($round);
++	&jz	(&label("schedule_mangle_last"));
++	&call	("_vpaes_schedule_mangle");	
++
++	# low round. swap xmm7 and xmm6
++	&pshufd	("xmm0","xmm0",0xFF);
++	&movdqa	(&QWP(20,"esp"),"xmm7");
++	&movdqa	("xmm7","xmm6");
++	&call	("_vpaes_schedule_low_round");
++	&movdqa	("xmm7",&QWP(20,"esp"));
++
++	&jmp	(&label("loop_schedule_256"));
++
++##
++##  .aes_schedule_mangle_last
++##
++##  Mangler for last round of key schedule
++##  Mangles %xmm0
++##    when encrypting, outputs out(%xmm0) ^ 63
++##    when decrypting, outputs unskew(%xmm0)
++##
++##  Always called right before return... jumps to cleanup and exits
++##
++&set_label("schedule_mangle_last",16);
++	# schedule last round key from xmm0
++	&lea	($base,&DWP($k_deskew,$const));
++	&test	($out,$out);
++	&jnz	(&label("schedule_mangle_last_dec"));
++
++	# encrypting
++	&movdqa	("xmm1",&QWP($k_sr,$const,$magic));
++	&pshufb	("xmm0","xmm1");		# output permute
++	&lea	($base,&DWP($k_opt,$const));	# prepare to output transform
++	&add	($key,32);
++
++&set_label("schedule_mangle_last_dec");
++	&add	($key,-16);
++	&pxor	("xmm0",&QWP($k_s63,$const));
++	&call	("_vpaes_schedule_transform");	# output transform
++	&movdqu	(&QWP(0,$key),"xmm0");		# save last key
++
++	# cleanup
++	&pxor	("xmm0","xmm0");
++	&pxor	("xmm1","xmm1");
++	&pxor	("xmm2","xmm2");
++	&pxor	("xmm3","xmm3");
++	&pxor	("xmm4","xmm4");
++	&pxor	("xmm5","xmm5");
++	&pxor	("xmm6","xmm6");
++	&pxor	("xmm7","xmm7");
++	&ret	();
++&function_end_B("_vpaes_schedule_core");
++
++##
++##  .aes_schedule_192_smear
++##
++##  Smear the short, low side in the 192-bit key schedule.
++##
++##  Inputs:
++##    %xmm7: high side, b  a  x  y
++##    %xmm6:  low side, d  c  0  0
++##    %xmm13: 0
++##
++##  Outputs:
++##    %xmm6: b+c+d  b+c  0  0
++##    %xmm0: b+c+d  b+c  b  a
++##
++&function_begin_B("_vpaes_schedule_192_smear");
++	&pshufd	("xmm1","xmm6",0x80);		# d c 0 0 -> c 0 0 0
++	&pshufd	("xmm0","xmm7",0xFE);		# b a _ _ -> b b b a
++	&pxor	("xmm6","xmm1");		# -> c+d c 0 0
++	&pxor	("xmm1","xmm1");
++	&pxor	("xmm6","xmm0");		# -> b+c+d b+c b a
++	&movdqa	("xmm0","xmm6");
++	&movhlps("xmm6","xmm1");		# clobber low side with zeros
++	&ret	();
++&function_end_B("_vpaes_schedule_192_smear");
++
++##
++##  .aes_schedule_round
++##
++##  Runs one main round of the key schedule on %xmm0, %xmm7
++##
++##  Specifically, runs subbytes on the high dword of %xmm0
++##  then rotates it by one byte and xors into the low dword of
++##  %xmm7.
++##
++##  Adds rcon from low byte of %xmm8, then rotates %xmm8 for
++##  next rcon.
++##
++##  Smears the dwords of %xmm7 by xoring the low into the
++##  second low, result into third, result into highest.
++##
++##  Returns results in %xmm7 = %xmm0.
++##  Clobbers %xmm1-%xmm5.
++##
++&function_begin_B("_vpaes_schedule_round");
++	# extract rcon from xmm8
++	&movdqa	("xmm2",&QWP(8,"esp"));		# xmm8
++	&pxor	("xmm1","xmm1");
++	&palignr("xmm1","xmm2",15);
++	&palignr("xmm2","xmm2",15);
++	&pxor	("xmm7","xmm1");
++
++	# rotate
++	&pshufd	("xmm0","xmm0",0xFF);
++	&palignr("xmm0","xmm0",1);
++
++	# fall through...
++	&movdqa	(&QWP(8,"esp"),"xmm2");		# xmm8
++
++	# low round: same as high round, but no rotation and no rcon.
++&set_label("_vpaes_schedule_low_round");
++	# smear xmm7
++	&movdqa	("xmm1","xmm7");
++	&pslldq	("xmm7",4);
++	&pxor	("xmm7","xmm1");
++	&movdqa	("xmm1","xmm7");
++	&pslldq	("xmm7",8);
++	&pxor	("xmm7","xmm1");
++	&pxor	("xmm7",&QWP($k_s63,$const));
++
++	# subbyte
++	&movdqa	("xmm4",&QWP($k_s0F,$const));
++	&movdqa	("xmm5",&QWP($k_inv,$const));	# 4 : 1/j
++	&movdqa	("xmm1","xmm4");	
++	&pandn	("xmm1","xmm0");
++	&psrld	("xmm1",4);			# 1 = i
++	&pand	("xmm0","xmm4");		# 0 = k
++	&movdqa	("xmm2",&QWP($k_inv+16,$const));# 2 : a/k
++	&pshufb	("xmm2","xmm0");		# 2 = a/k
++	&pxor	("xmm0","xmm1");		# 0 = j
++	&movdqa	("xmm3","xmm5");		# 3 : 1/i
++	&pshufb	("xmm3","xmm1");		# 3 = 1/i
++	&pxor	("xmm3","xmm2");		# 3 = iak = 1/i + a/k
++	&movdqa	("xmm4","xmm5");		# 4 : 1/j
++	&pshufb	("xmm4","xmm0");		# 4 = 1/j
++	&pxor	("xmm4","xmm2");		# 4 = jak = 1/j + a/k
++	&movdqa	("xmm2","xmm5");		# 2 : 1/iak
++	&pshufb	("xmm2","xmm3");		# 2 = 1/iak
++	&pxor	("xmm2","xmm0");		# 2 = io
++	&movdqa	("xmm3","xmm5");		# 3 : 1/jak
++	&pshufb	("xmm3","xmm4");		# 3 = 1/jak
++	&pxor	("xmm3","xmm1");		# 3 = jo
++	&movdqa	("xmm4",&QWP($k_sb1,$const));	# 4 : sbou
++	&pshufb	("xmm4","xmm2");		# 4 = sbou
++	&movdqa	("xmm0",&QWP($k_sb1+16,$const));# 0 : sbot
++	&pshufb	("xmm0","xmm3");		# 0 = sb1t
++	&pxor	("xmm0","xmm4");		# 0 = sbox output
++
++	# add in smeared stuff
++	&pxor	("xmm0","xmm7");
++	&movdqa	("xmm7","xmm0");
++	&ret	();
++&function_end_B("_vpaes_schedule_round");
++
++##
++##  .aes_schedule_transform
++##
++##  Linear-transform %xmm0 according to tables at (%ebx)
++##
++##  Output in %xmm0
++##  Clobbers %xmm1, %xmm2
++##
++&function_begin_B("_vpaes_schedule_transform");
++	&movdqa	("xmm2",&QWP($k_s0F,$const));
++	&movdqa	("xmm1","xmm2");
++	&pandn	("xmm1","xmm0");
++	&psrld	("xmm1",4);
++	&pand	("xmm0","xmm2");
++	&movdqa	("xmm2",&QWP(0,$base));
++	&pshufb	("xmm2","xmm0");
++	&movdqa	("xmm0",&QWP(16,$base));
++	&pshufb	("xmm0","xmm1");
++	&pxor	("xmm0","xmm2");
++	&ret	();
++&function_end_B("_vpaes_schedule_transform");
++
++##
++##  .aes_schedule_mangle
++##
++##  Mangle xmm0 from (basis-transformed) standard version
++##  to our version.
++##
++##  On encrypt,
++##    xor with 0x63
++##    multiply by circulant 0,1,1,1
++##    apply shiftrows transform
++##
++##  On decrypt,
++##    xor with 0x63
++##    multiply by "inverse mixcolumns" circulant E,B,D,9
++##    deskew
++##    apply shiftrows transform
++##
++##
++##  Writes out to (%edx), and increments or decrements it
++##  Keeps track of round number mod 4 in %ecx
++##  Preserves xmm0
++##  Clobbers xmm1-xmm5
++##
++&function_begin_B("_vpaes_schedule_mangle");
++	&movdqa	("xmm4","xmm0");	# save xmm0 for later
++	&movdqa	("xmm5",&QWP($k_mc_forward,$const));
++	&test	($out,$out);
++	&jnz	(&label("schedule_mangle_dec"));
++
++	# encrypting
++	&add	($key,16);
++	&pxor	("xmm4",&QWP($k_s63,$const));
++	&pshufb	("xmm4","xmm5");
++	&movdqa	("xmm3","xmm4");
++	&pshufb	("xmm4","xmm5");
++	&pxor	("xmm3","xmm4");
++	&pshufb	("xmm4","xmm5");
++	&pxor	("xmm3","xmm4");
++
++	&jmp	(&label("schedule_mangle_both"));
++
++&set_label("schedule_mangle_dec",16);
++	# inverse mix columns
++	&movdqa	("xmm2",&QWP($k_s0F,$const));
++	&lea	($inp,&DWP($k_dksd,$const));
++	&movdqa	("xmm1","xmm2");
++	&pandn	("xmm1","xmm4");
++	&psrld	("xmm1",4);			# 1 = hi
++	&pand	("xmm4","xmm2");		# 4 = lo
++
++	&movdqa	("xmm2",&QWP(0,$inp));
++	&pshufb	("xmm2","xmm4");
++	&movdqa	("xmm3",&QWP(0x10,$inp));
++	&pshufb	("xmm3","xmm1");
++	&pxor	("xmm3","xmm2");
++	&pshufb	("xmm3","xmm5");
++
++	&movdqa	("xmm2",&QWP(0x20,$inp));
++	&pshufb	("xmm2","xmm4");
++	&pxor	("xmm2","xmm3");
++	&movdqa	("xmm3",&QWP(0x30,$inp));
++	&pshufb	("xmm3","xmm1");
++	&pxor	("xmm3","xmm2");
++	&pshufb	("xmm3","xmm5");
++
++	&movdqa	("xmm2",&QWP(0x40,$inp));
++	&pshufb	("xmm2","xmm4");
++	&pxor	("xmm2","xmm3");
++	&movdqa	("xmm3",&QWP(0x50,$inp));
++	&pshufb	("xmm3","xmm1");
++	&pxor	("xmm3","xmm2");
++	&pshufb	("xmm3","xmm5");
++
++	&movdqa	("xmm2",&QWP(0x60,$inp));
++	&pshufb	("xmm2","xmm4");
++	&pxor	("xmm2","xmm3");
++	&movdqa	("xmm3",&QWP(0x70,$inp));
++	&pshufb	("xmm3","xmm1");
++	&pxor	("xmm3","xmm2");
++
++	&add	($key,-16);
++
++&set_label("schedule_mangle_both");
++	&movdqa	("xmm1",&QWP($k_sr,$const,$magic));
++	&pshufb	("xmm3","xmm1");
++	&add	($magic,-16);
++	&and	($magic,0x30);
++	&movdqu	(&QWP(0,$key),"xmm3");
++	&ret	();
++&function_end_B("_vpaes_schedule_mangle");
++
++#
++# Interface to OpenSSL
++#
++&function_begin("${PREFIX}_set_encrypt_key");
++	&mov	($inp,&wparam(0));		# inp
++	&lea	($base,&DWP(-56,"esp"));
++	&mov	($round,&wparam(1));		# bits
++	&and	($base,-16);
++	&mov	($key,&wparam(2));		# key
++	&xchg	($base,"esp");			# alloca
++	&mov	(&DWP(48,"esp"),$base);
++
++	&mov	($base,$round);
++	&shr	($base,5);
++	&add	($base,5);
++	&mov	(&DWP(240,$key),$base);		# AES_KEY->rounds = nbits/32+5;
++	&mov	($magic,0x30);
++	&mov	($out,0);
++
++	&lea	($const,&DWP(&label("_vpaes_consts")."+0x30-".&label("pic_point")));
++	&call	("_vpaes_schedule_core");
++&set_label("pic_point");
++
++	&mov	("esp",&DWP(48,"esp"));
++	&xor	("eax","eax");
++&function_end("${PREFIX}_set_encrypt_key");
++
++&function_begin("${PREFIX}_set_decrypt_key");
++	&mov	($inp,&wparam(0));		# inp
++	&lea	($base,&DWP(-56,"esp"));
++	&mov	($round,&wparam(1));		# bits
++	&and	($base,-16);
++	&mov	($key,&wparam(2));		# key
++	&xchg	($base,"esp");			# alloca
++	&mov	(&DWP(48,"esp"),$base);
++
++	&mov	($base,$round);
++	&shr	($base,5);
++	&add	($base,5);
++	&mov	(&DWP(240,$key),$base);	# AES_KEY->rounds = nbits/32+5;
++	&shl	($base,4);
++	&lea	($key,&DWP(16,$key,$base));
++
++	&mov	($out,1);
++	&mov	($magic,$round);
++	&shr	($magic,1);
++	&and	($magic,32);
++	&xor	($magic,32);			# nbist==192?0:32;
++
++	&lea	($const,&DWP(&label("_vpaes_consts")."+0x30-".&label("pic_point")));
++	&call	("_vpaes_schedule_core");
++&set_label("pic_point");
++
++	&mov	("esp",&DWP(48,"esp"));
++	&xor	("eax","eax");
++&function_end("${PREFIX}_set_decrypt_key");
++
++&function_begin("${PREFIX}_encrypt");
++	&lea	($const,&DWP(&label("_vpaes_consts")."+0x30-".&label("pic_point")));
++	&call	("_vpaes_preheat");
++&set_label("pic_point");
++	&mov	($inp,&wparam(0));		# inp
++	&lea	($base,&DWP(-56,"esp"));
++	&mov	($out,&wparam(1));		# out
++	&and	($base,-16);
++	&mov	($key,&wparam(2));		# key
++	&xchg	($base,"esp");			# alloca
++	&mov	(&DWP(48,"esp"),$base);
++
++	&movdqu	("xmm0",&QWP(0,$inp));
++	&call	("_vpaes_encrypt_core");
++	&movdqu	(&QWP(0,$out),"xmm0");
++
++	&mov	("esp",&DWP(48,"esp"));
++&function_end("${PREFIX}_encrypt");
++
++&function_begin("${PREFIX}_decrypt");
++	&lea	($const,&DWP(&label("_vpaes_consts")."+0x30-".&label("pic_point")));
++	&call	("_vpaes_preheat");
++&set_label("pic_point");
++	&mov	($inp,&wparam(0));		# inp
++	&lea	($base,&DWP(-56,"esp"));
++	&mov	($out,&wparam(1));		# out
++	&and	($base,-16);
++	&mov	($key,&wparam(2));		# key
++	&xchg	($base,"esp");			# alloca
++	&mov	(&DWP(48,"esp"),$base);
++
++	&movdqu	("xmm0",&QWP(0,$inp));
++	&call	("_vpaes_decrypt_core");
++	&movdqu	(&QWP(0,$out),"xmm0");
++
++	&mov	("esp",&DWP(48,"esp"));
++&function_end("${PREFIX}_decrypt");
++
++&function_begin("${PREFIX}_cbc_encrypt");
++	&mov	($inp,&wparam(0));		# inp
++	&mov	($out,&wparam(1));		# out
++	&mov	($round,&wparam(2));		# len
++	&mov	($key,&wparam(3));		# key
++	&sub	($round,16);
++	&jc	(&label("cbc_abort"));
++	&lea	($base,&DWP(-56,"esp"));
++	&mov	($const,&wparam(4));		# ivp
++	&and	($base,-16);
++	&mov	($magic,&wparam(5));		# enc
++	&xchg	($base,"esp");			# alloca
++	&movdqu	("xmm1",&QWP(0,$const));	# load IV
++	&sub	($out,$inp);
++	&mov	(&DWP(48,"esp"),$base);
++
++	&mov	(&DWP(0,"esp"),$out);		# save out
++	&mov	(&DWP(4,"esp"),$key)		# save key
++	&mov	(&DWP(8,"esp"),$const);		# save ivp
++	&mov	($out,$round);			# $out works as $len
++
++	&lea	($const,&DWP(&label("_vpaes_consts")."+0x30-".&label("pic_point")));
++	&call	("_vpaes_preheat");
++&set_label("pic_point");
++	&cmp	($magic,0);
++	&je	(&label("cbc_dec_loop"));
++	&jmp	(&label("cbc_enc_loop"));
++
++&set_label("cbc_enc_loop",16);
++	&movdqu	("xmm0",&QWP(0,$inp));		# load input
++	&pxor	("xmm0","xmm1");		# inp^=iv
++	&call	("_vpaes_encrypt_core");
++	&mov	($base,&DWP(0,"esp"));		# restore out
++	&mov	($key,&DWP(4,"esp"));		# restore key
++	&movdqa	("xmm1","xmm0");
++	&movdqu	(&QWP(0,$base,$inp),"xmm0");	# write output
++	&lea	($inp,&DWP(16,$inp));
++	&sub	($out,16);
++	&jnc	(&label("cbc_enc_loop"));
++	&jmp	(&label("cbc_done"));
++
++&set_label("cbc_dec_loop",16);
++	&movdqu	("xmm0",&QWP(0,$inp));		# load input
++	&movdqa	(&QWP(16,"esp"),"xmm1");	# save IV
++	&movdqa	(&QWP(32,"esp"),"xmm0");	# save future IV
++	&call	("_vpaes_decrypt_core");
++	&mov	($base,&DWP(0,"esp"));		# restore out
++	&mov	($key,&DWP(4,"esp"));		# restore key
++	&pxor	("xmm0",&QWP(16,"esp"));	# out^=iv
++	&movdqa	("xmm1",&QWP(32,"esp"));	# load next IV
++	&movdqu	(&QWP(0,$base,$inp),"xmm0");	# write output
++	&lea	($inp,&DWP(16,$inp));
++	&sub	($out,16);
++	&jnc	(&label("cbc_dec_loop"));
++
++&set_label("cbc_done");
++	&mov	($base,&DWP(8,"esp"));		# restore ivp
++	&mov	("esp",&DWP(48,"esp"));
++	&movdqu	(&QWP(0,$base),"xmm1");		# write IV
++&set_label("cbc_abort");
++&function_end("${PREFIX}_cbc_encrypt");
++
++&asm_finish();
++
++close STDOUT;
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/aes/asm/vpaes-x86_64.pl b/CryptoPkg/Library/OpensslLib/openssl/crypto/aes/asm/vpaes-x86_64.pl
+new file mode 100644
+index 0000000..422e8ee
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/aes/asm/vpaes-x86_64.pl
+@@ -0,0 +1,1215 @@
++#! /usr/bin/env perl
++# Copyright 2011-2016 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
++# in the file LICENSE in the source distribution or at
++# https://www.openssl.org/source/license.html
++
++
++######################################################################
++## Constant-time SSSE3 AES core implementation.
++## version 0.1
++##
++## By Mike Hamburg (Stanford University), 2009
++## Public domain.
++##
++## For details see http://shiftleft.org/papers/vector_aes/ and
++## http://crypto.stanford.edu/vpaes/.
++
++######################################################################
++# September 2011.
++#
++# Interface to OpenSSL as "almost" drop-in replacement for
++# aes-x86_64.pl. "Almost" refers to the fact that AES_cbc_encrypt
++# doesn't handle partial vectors (doesn't have to if called from
++# EVP only). "Drop-in" implies that this module doesn't share key
++# schedule structure with the original nor does it make assumption
++# about its alignment...
++#
++# Performance summary. aes-x86_64.pl column lists large-block CBC
++# encrypt/decrypt/with-hyper-threading-off(*) results in cycles per
++# byte processed with 128-bit key, and vpaes-x86_64.pl column -
++# [also large-block CBC] encrypt/decrypt.
++#
++#		aes-x86_64.pl		vpaes-x86_64.pl
++#
++# Core 2(**)	29.6/41.1/14.3		21.9/25.2(***)
++# Nehalem	29.6/40.3/14.6		10.0/11.8
++# Atom		57.3/74.2/32.1		60.9/77.2(***)
++# Silvermont	52.7/64.0/19.5		48.8/60.8(***)
++# Goldmont	38.9/49.0/17.8		10.6/12.6
++#
++# (*)	"Hyper-threading" in the context refers rather to cache shared
++#	among multiple cores, than to specifically Intel HTT. As vast
++#	majority of contemporary cores share cache, slower code path
++#	is common place. In other words "with-hyper-threading-off"
++#	results are presented mostly for reference purposes.
++#
++# (**)	"Core 2" refers to initial 65nm design, a.k.a. Conroe.
++#
++# (***)	Less impressive improvement on Core 2 and Atom is due to slow
++#	pshufb,	yet it's respectable +36%/62% improvement on Core 2
++#	(as implied, over "hyper-threading-safe" code path).
++#
++#						
++
++$flavour = shift;
++$output  = shift;
++if ($flavour =~ /\./) { $output = $flavour; undef $flavour; }
++
++$win64=0; $win64=1 if ($flavour =~ /[nm]asm|mingw64/ || $output =~ /\.asm$/);
++
++$0 =~ m/(.*[\/\\])[^\/\\]+$/; $dir=$1;
++( $xlate="${dir}x86_64-xlate.pl" and -f $xlate ) or
++( $xlate="${dir}../../perlasm/x86_64-xlate.pl" and -f $xlate) or
++die "can't locate x86_64-xlate.pl";
++
++open OUT,"| \"$^X\" \"$xlate\" $flavour \"$output\"";
++*STDOUT=*OUT;
++
++$PREFIX="vpaes";
++
++$code.=<<___;
++.text
++
++##
++##  _aes_encrypt_core
++##
++##  AES-encrypt %xmm0.
++##
++##  Inputs:
++##     %xmm0 = input
++##     %xmm9-%xmm15 as in _vpaes_preheat
++##    (%rdx) = scheduled keys
++##
++##  Output in %xmm0
++##  Clobbers  %xmm1-%xmm5, %r9, %r10, %r11, %rax
++##  Preserves %xmm6 - %xmm8 so you get some local vectors
++##
++##
++.type	_vpaes_encrypt_core,\@abi-omnipotent
++.align 16
++_vpaes_encrypt_core:
++	mov	%rdx,	%r9
++	mov	\$16,	%r11
++	mov	240(%rdx),%eax
++	movdqa	%xmm9,	%xmm1
++	movdqa	.Lk_ipt(%rip), %xmm2	# iptlo
++	pandn	%xmm0,	%xmm1
++	movdqu	(%r9),	%xmm5		# round0 key
++	psrld	\$4,	%xmm1
++	pand	%xmm9,	%xmm0
++	pshufb	%xmm0,	%xmm2
++	movdqa	.Lk_ipt+16(%rip), %xmm0	# ipthi
++	pshufb	%xmm1,	%xmm0
++	pxor	%xmm5,	%xmm2
++	add	\$16,	%r9
++	pxor	%xmm2,	%xmm0
++	lea	.Lk_mc_backward(%rip),%r10
++	jmp	.Lenc_entry
++
++.align 16
++.Lenc_loop:
++	# middle of middle round
++	movdqa  %xmm13,	%xmm4	# 4 : sb1u
++	movdqa  %xmm12,	%xmm0	# 0 : sb1t
++	pshufb  %xmm2,	%xmm4	# 4 = sb1u
++	pshufb  %xmm3,	%xmm0	# 0 = sb1t
++	pxor	%xmm5,	%xmm4	# 4 = sb1u + k
++	movdqa  %xmm15,	%xmm5	# 4 : sb2u
++	pxor	%xmm4,	%xmm0	# 0 = A
++	movdqa	-0x40(%r11,%r10), %xmm1		# .Lk_mc_forward[]
++	pshufb	%xmm2,	%xmm5	# 4 = sb2u
++	movdqa	(%r11,%r10), %xmm4		# .Lk_mc_backward[]
++	movdqa	%xmm14, %xmm2	# 2 : sb2t
++	pshufb	%xmm3,  %xmm2	# 2 = sb2t
++	movdqa	%xmm0,  %xmm3	# 3 = A
++	pxor	%xmm5,	%xmm2	# 2 = 2A
++	pshufb  %xmm1,  %xmm0	# 0 = B
++	add	\$16,	%r9	# next key
++	pxor	%xmm2,  %xmm0	# 0 = 2A+B
++	pshufb	%xmm4,	%xmm3	# 3 = D
++	add	\$16,	%r11	# next mc
++	pxor	%xmm0,	%xmm3	# 3 = 2A+B+D
++	pshufb  %xmm1,	%xmm0	# 0 = 2B+C
++	and	\$0x30,	%r11	# ... mod 4
++	sub	\$1,%rax	# nr--
++	pxor	%xmm3,	%xmm0	# 0 = 2A+3B+C+D
++
++.Lenc_entry:
++	# top of round
++	movdqa  %xmm9, 	%xmm1	# 1 : i
++	movdqa	%xmm11, %xmm5	# 2 : a/k
++	pandn	%xmm0, 	%xmm1	# 1 = i<<4
++	psrld	\$4,   	%xmm1   # 1 = i
++	pand	%xmm9, 	%xmm0   # 0 = k
++	pshufb  %xmm0,  %xmm5	# 2 = a/k
++	movdqa	%xmm10,	%xmm3  	# 3 : 1/i
++	pxor	%xmm1,	%xmm0	# 0 = j
++	pshufb  %xmm1, 	%xmm3  	# 3 = 1/i
++	movdqa	%xmm10,	%xmm4  	# 4 : 1/j
++	pxor	%xmm5, 	%xmm3  	# 3 = iak = 1/i + a/k
++	pshufb	%xmm0, 	%xmm4  	# 4 = 1/j
++	movdqa	%xmm10,	%xmm2  	# 2 : 1/iak
++	pxor	%xmm5, 	%xmm4  	# 4 = jak = 1/j + a/k
++	pshufb  %xmm3,	%xmm2  	# 2 = 1/iak
++	movdqa	%xmm10, %xmm3   # 3 : 1/jak
++	pxor	%xmm0, 	%xmm2  	# 2 = io
++	pshufb  %xmm4,  %xmm3   # 3 = 1/jak
++	movdqu	(%r9),	%xmm5
++	pxor	%xmm1,  %xmm3   # 3 = jo
++	jnz	.Lenc_loop
++
++	# middle of last round
++	movdqa	-0x60(%r10), %xmm4	# 3 : sbou	.Lk_sbo
++	movdqa	-0x50(%r10), %xmm0	# 0 : sbot	.Lk_sbo+16
++	pshufb  %xmm2,  %xmm4	# 4 = sbou
++	pxor	%xmm5,  %xmm4	# 4 = sb1u + k
++	pshufb  %xmm3,	%xmm0	# 0 = sb1t
++	movdqa	0x40(%r11,%r10), %xmm1		# .Lk_sr[]
++	pxor	%xmm4,	%xmm0	# 0 = A
++	pshufb	%xmm1,	%xmm0
++	ret
++.size	_vpaes_encrypt_core,.-_vpaes_encrypt_core
++	
++##
++##  Decryption core
++##
++##  Same API as encryption core.
++##
++.type	_vpaes_decrypt_core,\@abi-omnipotent
++.align	16
++_vpaes_decrypt_core:
++	mov	%rdx,	%r9		# load key
++	mov	240(%rdx),%eax
++	movdqa	%xmm9,	%xmm1
++	movdqa	.Lk_dipt(%rip), %xmm2	# iptlo
++	pandn	%xmm0,	%xmm1
++	mov	%rax,	%r11
++	psrld	\$4,	%xmm1
++	movdqu	(%r9),	%xmm5		# round0 key
++	shl	\$4,	%r11
++	pand	%xmm9,	%xmm0
++	pshufb	%xmm0,	%xmm2
++	movdqa	.Lk_dipt+16(%rip), %xmm0 # ipthi
++	xor	\$0x30,	%r11
++	lea	.Lk_dsbd(%rip),%r10
++	pshufb	%xmm1,	%xmm0
++	and	\$0x30,	%r11
++	pxor	%xmm5,	%xmm2
++	movdqa	.Lk_mc_forward+48(%rip), %xmm5
++	pxor	%xmm2,	%xmm0
++	add	\$16,	%r9
++	add	%r10,	%r11
++	jmp	.Ldec_entry
++
++.align 16
++.Ldec_loop:
++##
++##  Inverse mix columns
++##
++	movdqa  -0x20(%r10),%xmm4	# 4 : sb9u
++	movdqa  -0x10(%r10),%xmm1	# 0 : sb9t
++	pshufb	%xmm2,	%xmm4		# 4 = sb9u
++	pshufb	%xmm3,	%xmm1		# 0 = sb9t
++	pxor	%xmm4,	%xmm0
++	movdqa  0x00(%r10),%xmm4	# 4 : sbdu
++	pxor	%xmm1,	%xmm0		# 0 = ch
++	movdqa  0x10(%r10),%xmm1	# 0 : sbdt
++
++	pshufb	%xmm2,	%xmm4		# 4 = sbdu
++	pshufb	%xmm5,	%xmm0		# MC ch
++	pshufb	%xmm3,	%xmm1		# 0 = sbdt
++	pxor	%xmm4,	%xmm0		# 4 = ch
++	movdqa  0x20(%r10),%xmm4	# 4 : sbbu
++	pxor	%xmm1,	%xmm0		# 0 = ch
++	movdqa  0x30(%r10),%xmm1	# 0 : sbbt
++
++	pshufb	%xmm2,	%xmm4		# 4 = sbbu
++	pshufb	%xmm5,	%xmm0		# MC ch
++	pshufb	%xmm3,	%xmm1		# 0 = sbbt
++	pxor	%xmm4,	%xmm0		# 4 = ch
++	movdqa  0x40(%r10),%xmm4	# 4 : sbeu
++	pxor	%xmm1,	%xmm0		# 0 = ch
++	movdqa  0x50(%r10),%xmm1	# 0 : sbet
++
++	pshufb	%xmm2,	%xmm4		# 4 = sbeu
++	pshufb	%xmm5,	%xmm0		# MC ch
++	pshufb	%xmm3,	%xmm1		# 0 = sbet
++	pxor	%xmm4,	%xmm0		# 4 = ch
++	add	\$16, %r9		# next round key
++	palignr	\$12,	%xmm5,	%xmm5
++	pxor	%xmm1,	%xmm0		# 0 = ch
++	sub	\$1,%rax		# nr--
++
++.Ldec_entry:
++	# top of round
++	movdqa  %xmm9, 	%xmm1	# 1 : i
++	pandn	%xmm0, 	%xmm1	# 1 = i<<4
++	movdqa	%xmm11, %xmm2	# 2 : a/k
++	psrld	\$4,    %xmm1	# 1 = i
++	pand	%xmm9, 	%xmm0	# 0 = k
++	pshufb  %xmm0,  %xmm2	# 2 = a/k
++	movdqa	%xmm10,	%xmm3	# 3 : 1/i
++	pxor	%xmm1,	%xmm0	# 0 = j
++	pshufb  %xmm1, 	%xmm3	# 3 = 1/i
++	movdqa	%xmm10,	%xmm4	# 4 : 1/j
++	pxor	%xmm2, 	%xmm3	# 3 = iak = 1/i + a/k
++	pshufb	%xmm0, 	%xmm4	# 4 = 1/j
++	pxor	%xmm2, 	%xmm4	# 4 = jak = 1/j + a/k
++	movdqa	%xmm10,	%xmm2	# 2 : 1/iak
++	pshufb  %xmm3,	%xmm2	# 2 = 1/iak
++	movdqa	%xmm10, %xmm3	# 3 : 1/jak
++	pxor	%xmm0, 	%xmm2	# 2 = io
++	pshufb  %xmm4,  %xmm3	# 3 = 1/jak
++	movdqu	(%r9),	%xmm0
++	pxor	%xmm1,  %xmm3	# 3 = jo
++	jnz	.Ldec_loop
++
++	# middle of last round
++	movdqa	0x60(%r10), %xmm4	# 3 : sbou
++	pshufb  %xmm2,  %xmm4	# 4 = sbou
++	pxor	%xmm0,  %xmm4	# 4 = sb1u + k
++	movdqa	0x70(%r10), %xmm0	# 0 : sbot
++	movdqa	-0x160(%r11), %xmm2	# .Lk_sr-.Lk_dsbd=-0x160
++	pshufb  %xmm3,	%xmm0	# 0 = sb1t
++	pxor	%xmm4,	%xmm0	# 0 = A
++	pshufb	%xmm2,	%xmm0
++	ret
++.size	_vpaes_decrypt_core,.-_vpaes_decrypt_core
++
++########################################################
++##                                                    ##
++##                  AES key schedule                  ##
++##                                                    ##
++########################################################
++.type	_vpaes_schedule_core,\@abi-omnipotent
++.align	16
++_vpaes_schedule_core:
++	# rdi = key
++	# rsi = size in bits
++	# rdx = buffer
++	# rcx = direction.  0=encrypt, 1=decrypt
++
++	call	_vpaes_preheat		# load the tables
++	movdqa	.Lk_rcon(%rip), %xmm8	# load rcon
++	movdqu	(%rdi),	%xmm0		# load key (unaligned)
++
++	# input transform
++	movdqa	%xmm0,	%xmm3
++	lea	.Lk_ipt(%rip), %r11
++	call	_vpaes_schedule_transform
++	movdqa	%xmm0,	%xmm7
++
++	lea	.Lk_sr(%rip),%r10
++	test	%rcx,	%rcx
++	jnz	.Lschedule_am_decrypting
++
++	# encrypting, output zeroth round key after transform
++	movdqu	%xmm0,	(%rdx)
++	jmp	.Lschedule_go
++
++.Lschedule_am_decrypting:
++	# decrypting, output zeroth round key after shiftrows
++	movdqa	(%r8,%r10),%xmm1
++	pshufb  %xmm1,	%xmm3
++	movdqu	%xmm3,	(%rdx)
++	xor	\$0x30, %r8
++
++.Lschedule_go:
++	cmp	\$192,	%esi
++	ja	.Lschedule_256
++	je	.Lschedule_192
++	# 128: fall though
++
++##
++##  .schedule_128
++##
++##  128-bit specific part of key schedule.
++##
++##  This schedule is really simple, because all its parts
++##  are accomplished by the subroutines.
++##
++.Lschedule_128:
++	mov	\$10, %esi
++	
++.Loop_schedule_128:
++	call 	_vpaes_schedule_round
++	dec	%rsi
++	jz 	.Lschedule_mangle_last
++	call	_vpaes_schedule_mangle	# write output
++	jmp 	.Loop_schedule_128
++
++##
++##  .aes_schedule_192
++##
++##  192-bit specific part of key schedule.
++##
++##  The main body of this schedule is the same as the 128-bit
++##  schedule, but with more smearing.  The long, high side is
++##  stored in %xmm7 as before, and the short, low side is in
++##  the high bits of %xmm6.
++##
++##  This schedule is somewhat nastier, however, because each
++##  round produces 192 bits of key material, or 1.5 round keys.
++##  Therefore, on each cycle we do 2 rounds and produce 3 round
++##  keys.
++##
++.align	16
++.Lschedule_192:
++	movdqu	8(%rdi),%xmm0		# load key part 2 (very unaligned)
++	call	_vpaes_schedule_transform	# input transform
++	movdqa	%xmm0,	%xmm6		# save short part
++	pxor	%xmm4,	%xmm4		# clear 4
++	movhlps	%xmm4,	%xmm6		# clobber low side with zeros
++	mov	\$4,	%esi
++
++.Loop_schedule_192:
++	call	_vpaes_schedule_round
++	palignr	\$8,%xmm6,%xmm0	
++	call	_vpaes_schedule_mangle	# save key n
++	call	_vpaes_schedule_192_smear
++	call	_vpaes_schedule_mangle	# save key n+1
++	call	_vpaes_schedule_round
++	dec	%rsi
++	jz 	.Lschedule_mangle_last
++	call	_vpaes_schedule_mangle	# save key n+2
++	call	_vpaes_schedule_192_smear
++	jmp	.Loop_schedule_192
++
++##
++##  .aes_schedule_256
++##
++##  256-bit specific part of key schedule.
++##
++##  The structure here is very similar to the 128-bit
++##  schedule, but with an additional "low side" in
++##  %xmm6.  The low side's rounds are the same as the
++##  high side's, except no rcon and no rotation.
++##
++.align	16
++.Lschedule_256:
++	movdqu	16(%rdi),%xmm0		# load key part 2 (unaligned)
++	call	_vpaes_schedule_transform	# input transform
++	mov	\$7, %esi
++	
++.Loop_schedule_256:
++	call	_vpaes_schedule_mangle	# output low result
++	movdqa	%xmm0,	%xmm6		# save cur_lo in xmm6
++
++	# high round
++	call	_vpaes_schedule_round
++	dec	%rsi
++	jz 	.Lschedule_mangle_last
++	call	_vpaes_schedule_mangle	
++
++	# low round. swap xmm7 and xmm6
++	pshufd	\$0xFF,	%xmm0,	%xmm0
++	movdqa	%xmm7,	%xmm5
++	movdqa	%xmm6,	%xmm7
++	call	_vpaes_schedule_low_round
++	movdqa	%xmm5,	%xmm7
++	
++	jmp	.Loop_schedule_256
++
++	
++##
++##  .aes_schedule_mangle_last
++##
++##  Mangler for last round of key schedule
++##  Mangles %xmm0
++##    when encrypting, outputs out(%xmm0) ^ 63
++##    when decrypting, outputs unskew(%xmm0)
++##
++##  Always called right before return... jumps to cleanup and exits
++##
++.align	16
++.Lschedule_mangle_last:
++	# schedule last round key from xmm0
++	lea	.Lk_deskew(%rip),%r11	# prepare to deskew
++	test	%rcx, 	%rcx
++	jnz	.Lschedule_mangle_last_dec
++
++	# encrypting
++	movdqa	(%r8,%r10),%xmm1
++	pshufb	%xmm1,	%xmm0		# output permute
++	lea	.Lk_opt(%rip),	%r11	# prepare to output transform
++	add	\$32,	%rdx
++
++.Lschedule_mangle_last_dec:
++	add	\$-16,	%rdx
++	pxor	.Lk_s63(%rip),	%xmm0
++	call	_vpaes_schedule_transform # output transform
++	movdqu	%xmm0,	(%rdx)		# save last key
++
++	# cleanup
++	pxor	%xmm0,  %xmm0
++	pxor	%xmm1,  %xmm1
++	pxor	%xmm2,  %xmm2
++	pxor	%xmm3,  %xmm3
++	pxor	%xmm4,  %xmm4
++	pxor	%xmm5,  %xmm5
++	pxor	%xmm6,  %xmm6
++	pxor	%xmm7,  %xmm7
++	ret
++.size	_vpaes_schedule_core,.-_vpaes_schedule_core
++
++##
++##  .aes_schedule_192_smear
++##
++##  Smear the short, low side in the 192-bit key schedule.
++##
++##  Inputs:
++##    %xmm7: high side, b  a  x  y
++##    %xmm6:  low side, d  c  0  0
++##    %xmm13: 0
++##
++##  Outputs:
++##    %xmm6: b+c+d  b+c  0  0
++##    %xmm0: b+c+d  b+c  b  a
++##
++.type	_vpaes_schedule_192_smear,\@abi-omnipotent
++.align	16
++_vpaes_schedule_192_smear:
++	pshufd	\$0x80,	%xmm6,	%xmm1	# d c 0 0 -> c 0 0 0
++	pshufd	\$0xFE,	%xmm7,	%xmm0	# b a _ _ -> b b b a
++	pxor	%xmm1,	%xmm6		# -> c+d c 0 0
++	pxor	%xmm1,	%xmm1
++	pxor	%xmm0,	%xmm6		# -> b+c+d b+c b a
++	movdqa	%xmm6,	%xmm0
++	movhlps	%xmm1,	%xmm6		# clobber low side with zeros
++	ret
++.size	_vpaes_schedule_192_smear,.-_vpaes_schedule_192_smear
++
++##
++##  .aes_schedule_round
++##
++##  Runs one main round of the key schedule on %xmm0, %xmm7
++##
++##  Specifically, runs subbytes on the high dword of %xmm0
++##  then rotates it by one byte and xors into the low dword of
++##  %xmm7.
++##
++##  Adds rcon from low byte of %xmm8, then rotates %xmm8 for
++##  next rcon.
++##
++##  Smears the dwords of %xmm7 by xoring the low into the
++##  second low, result into third, result into highest.
++##
++##  Returns results in %xmm7 = %xmm0.
++##  Clobbers %xmm1-%xmm4, %r11.
++##
++.type	_vpaes_schedule_round,\@abi-omnipotent
++.align	16
++_vpaes_schedule_round:
++	# extract rcon from xmm8
++	pxor	%xmm1,	%xmm1
++	palignr	\$15,	%xmm8,	%xmm1
++	palignr	\$15,	%xmm8,	%xmm8
++	pxor	%xmm1,	%xmm7
++
++	# rotate
++	pshufd	\$0xFF,	%xmm0,	%xmm0
++	palignr	\$1,	%xmm0,	%xmm0
++	
++	# fall through...
++	
++	# low round: same as high round, but no rotation and no rcon.
++_vpaes_schedule_low_round:
++	# smear xmm7
++	movdqa	%xmm7,	%xmm1
++	pslldq	\$4,	%xmm7
++	pxor	%xmm1,	%xmm7
++	movdqa	%xmm7,	%xmm1
++	pslldq	\$8,	%xmm7
++	pxor	%xmm1,	%xmm7
++	pxor	.Lk_s63(%rip), %xmm7
++
++	# subbytes
++	movdqa  %xmm9, 	%xmm1
++	pandn	%xmm0, 	%xmm1
++	psrld	\$4,    %xmm1		# 1 = i
++	pand	%xmm9, 	%xmm0		# 0 = k
++	movdqa	%xmm11, %xmm2		# 2 : a/k
++	pshufb  %xmm0,  %xmm2		# 2 = a/k
++	pxor	%xmm1,	%xmm0		# 0 = j
++	movdqa	%xmm10,	%xmm3		# 3 : 1/i
++	pshufb  %xmm1, 	%xmm3		# 3 = 1/i
++	pxor	%xmm2, 	%xmm3		# 3 = iak = 1/i + a/k
++	movdqa	%xmm10,	%xmm4		# 4 : 1/j
++	pshufb	%xmm0, 	%xmm4		# 4 = 1/j
++	pxor	%xmm2, 	%xmm4		# 4 = jak = 1/j + a/k
++	movdqa	%xmm10,	%xmm2		# 2 : 1/iak
++	pshufb  %xmm3,	%xmm2		# 2 = 1/iak
++	pxor	%xmm0, 	%xmm2		# 2 = io
++	movdqa	%xmm10, %xmm3		# 3 : 1/jak
++	pshufb  %xmm4,  %xmm3		# 3 = 1/jak
++	pxor	%xmm1,  %xmm3		# 3 = jo
++	movdqa	%xmm13, %xmm4		# 4 : sbou
++	pshufb  %xmm2,  %xmm4		# 4 = sbou
++	movdqa	%xmm12, %xmm0		# 0 : sbot
++	pshufb  %xmm3,	%xmm0		# 0 = sb1t
++	pxor	%xmm4, 	%xmm0		# 0 = sbox output
++
++	# add in smeared stuff
++	pxor	%xmm7,	%xmm0	
++	movdqa	%xmm0,	%xmm7
++	ret
++.size	_vpaes_schedule_round,.-_vpaes_schedule_round
++
++##
++##  .aes_schedule_transform
++##
++##  Linear-transform %xmm0 according to tables at (%r11)
++##
++##  Requires that %xmm9 = 0x0F0F... as in preheat
++##  Output in %xmm0
++##  Clobbers %xmm1, %xmm2
++##
++.type	_vpaes_schedule_transform,\@abi-omnipotent
++.align	16
++_vpaes_schedule_transform:
++	movdqa	%xmm9,	%xmm1
++	pandn	%xmm0,	%xmm1
++	psrld	\$4,	%xmm1
++	pand	%xmm9,	%xmm0
++	movdqa	(%r11), %xmm2 	# lo
++	pshufb	%xmm0,	%xmm2
++	movdqa	16(%r11), %xmm0 # hi
++	pshufb	%xmm1,	%xmm0
++	pxor	%xmm2,	%xmm0
++	ret
++.size	_vpaes_schedule_transform,.-_vpaes_schedule_transform
++
++##
++##  .aes_schedule_mangle
++##
++##  Mangle xmm0 from (basis-transformed) standard version
++##  to our version.
++##
++##  On encrypt,
++##    xor with 0x63
++##    multiply by circulant 0,1,1,1
++##    apply shiftrows transform
++##
++##  On decrypt,
++##    xor with 0x63
++##    multiply by "inverse mixcolumns" circulant E,B,D,9
++##    deskew
++##    apply shiftrows transform
++##
++##
++##  Writes out to (%rdx), and increments or decrements it
++##  Keeps track of round number mod 4 in %r8
++##  Preserves xmm0
++##  Clobbers xmm1-xmm5
++##
++.type	_vpaes_schedule_mangle,\@abi-omnipotent
++.align	16
++_vpaes_schedule_mangle:
++	movdqa	%xmm0,	%xmm4	# save xmm0 for later
++	movdqa	.Lk_mc_forward(%rip),%xmm5
++	test	%rcx, 	%rcx
++	jnz	.Lschedule_mangle_dec
++
++	# encrypting
++	add	\$16,	%rdx
++	pxor	.Lk_s63(%rip),%xmm4
++	pshufb	%xmm5,	%xmm4
++	movdqa	%xmm4,	%xmm3
++	pshufb	%xmm5,	%xmm4
++	pxor	%xmm4,	%xmm3
++	pshufb	%xmm5,	%xmm4
++	pxor	%xmm4,	%xmm3
++
++	jmp	.Lschedule_mangle_both
++.align	16
++.Lschedule_mangle_dec:
++	# inverse mix columns
++	lea	.Lk_dksd(%rip),%r11
++	movdqa	%xmm9,	%xmm1
++	pandn	%xmm4,	%xmm1
++	psrld	\$4,	%xmm1	# 1 = hi
++	pand	%xmm9,	%xmm4	# 4 = lo
++
++	movdqa	0x00(%r11), %xmm2
++	pshufb	%xmm4,	%xmm2
++	movdqa	0x10(%r11), %xmm3
++	pshufb	%xmm1,	%xmm3
++	pxor	%xmm2,	%xmm3
++	pshufb	%xmm5,	%xmm3
++
++	movdqa	0x20(%r11), %xmm2
++	pshufb	%xmm4,	%xmm2
++	pxor	%xmm3,	%xmm2
++	movdqa	0x30(%r11), %xmm3
++	pshufb	%xmm1,	%xmm3
++	pxor	%xmm2,	%xmm3
++	pshufb	%xmm5,	%xmm3
++
++	movdqa	0x40(%r11), %xmm2
++	pshufb	%xmm4,	%xmm2
++	pxor	%xmm3,	%xmm2
++	movdqa	0x50(%r11), %xmm3
++	pshufb	%xmm1,	%xmm3
++	pxor	%xmm2,	%xmm3
++	pshufb	%xmm5,	%xmm3
++
++	movdqa	0x60(%r11), %xmm2
++	pshufb	%xmm4,	%xmm2
++	pxor	%xmm3,	%xmm2
++	movdqa	0x70(%r11), %xmm3
++	pshufb	%xmm1,	%xmm3
++	pxor	%xmm2,	%xmm3
++
++	add	\$-16,	%rdx
++
++.Lschedule_mangle_both:
++	movdqa	(%r8,%r10),%xmm1
++	pshufb	%xmm1,%xmm3
++	add	\$-16,	%r8
++	and	\$0x30,	%r8
++	movdqu	%xmm3,	(%rdx)
++	ret
++.size	_vpaes_schedule_mangle,.-_vpaes_schedule_mangle
++
++#
++# Interface to OpenSSL
++#
++.globl	${PREFIX}_set_encrypt_key
++.type	${PREFIX}_set_encrypt_key,\@function,3
++.align	16
++${PREFIX}_set_encrypt_key:
++___
++$code.=<<___ if ($win64);
++	lea	-0xb8(%rsp),%rsp
++	movaps	%xmm6,0x10(%rsp)
++	movaps	%xmm7,0x20(%rsp)
++	movaps	%xmm8,0x30(%rsp)
++	movaps	%xmm9,0x40(%rsp)
++	movaps	%xmm10,0x50(%rsp)
++	movaps	%xmm11,0x60(%rsp)
++	movaps	%xmm12,0x70(%rsp)
++	movaps	%xmm13,0x80(%rsp)
++	movaps	%xmm14,0x90(%rsp)
++	movaps	%xmm15,0xa0(%rsp)
++.Lenc_key_body:
++___
++$code.=<<___;
++	mov	%esi,%eax
++	shr	\$5,%eax
++	add	\$5,%eax
++	mov	%eax,240(%rdx)	# AES_KEY->rounds = nbits/32+5;
++
++	mov	\$0,%ecx
++	mov	\$0x30,%r8d
++	call	_vpaes_schedule_core
++___
++$code.=<<___ if ($win64);
++	movaps	0x10(%rsp),%xmm6
++	movaps	0x20(%rsp),%xmm7
++	movaps	0x30(%rsp),%xmm8
++	movaps	0x40(%rsp),%xmm9
++	movaps	0x50(%rsp),%xmm10
++	movaps	0x60(%rsp),%xmm11
++	movaps	0x70(%rsp),%xmm12
++	movaps	0x80(%rsp),%xmm13
++	movaps	0x90(%rsp),%xmm14
++	movaps	0xa0(%rsp),%xmm15
++	lea	0xb8(%rsp),%rsp
++.Lenc_key_epilogue:
++___
++$code.=<<___;
++	xor	%eax,%eax
++	ret
++.size	${PREFIX}_set_encrypt_key,.-${PREFIX}_set_encrypt_key
++
++.globl	${PREFIX}_set_decrypt_key
++.type	${PREFIX}_set_decrypt_key,\@function,3
++.align	16
++${PREFIX}_set_decrypt_key:
++___
++$code.=<<___ if ($win64);
++	lea	-0xb8(%rsp),%rsp
++	movaps	%xmm6,0x10(%rsp)
++	movaps	%xmm7,0x20(%rsp)
++	movaps	%xmm8,0x30(%rsp)
++	movaps	%xmm9,0x40(%rsp)
++	movaps	%xmm10,0x50(%rsp)
++	movaps	%xmm11,0x60(%rsp)
++	movaps	%xmm12,0x70(%rsp)
++	movaps	%xmm13,0x80(%rsp)
++	movaps	%xmm14,0x90(%rsp)
++	movaps	%xmm15,0xa0(%rsp)
++.Ldec_key_body:
++___
++$code.=<<___;
++	mov	%esi,%eax
++	shr	\$5,%eax
++	add	\$5,%eax
++	mov	%eax,240(%rdx)	# AES_KEY->rounds = nbits/32+5;
++	shl	\$4,%eax
++	lea	16(%rdx,%rax),%rdx
++
++	mov	\$1,%ecx
++	mov	%esi,%r8d
++	shr	\$1,%r8d
++	and	\$32,%r8d
++	xor	\$32,%r8d	# nbits==192?0:32
++	call	_vpaes_schedule_core
++___
++$code.=<<___ if ($win64);
++	movaps	0x10(%rsp),%xmm6
++	movaps	0x20(%rsp),%xmm7
++	movaps	0x30(%rsp),%xmm8
++	movaps	0x40(%rsp),%xmm9
++	movaps	0x50(%rsp),%xmm10
++	movaps	0x60(%rsp),%xmm11
++	movaps	0x70(%rsp),%xmm12
++	movaps	0x80(%rsp),%xmm13
++	movaps	0x90(%rsp),%xmm14
++	movaps	0xa0(%rsp),%xmm15
++	lea	0xb8(%rsp),%rsp
++.Ldec_key_epilogue:
++___
++$code.=<<___;
++	xor	%eax,%eax
++	ret
++.size	${PREFIX}_set_decrypt_key,.-${PREFIX}_set_decrypt_key
++
++.globl	${PREFIX}_encrypt
++.type	${PREFIX}_encrypt,\@function,3
++.align	16
++${PREFIX}_encrypt:
++___
++$code.=<<___ if ($win64);
++	lea	-0xb8(%rsp),%rsp
++	movaps	%xmm6,0x10(%rsp)
++	movaps	%xmm7,0x20(%rsp)
++	movaps	%xmm8,0x30(%rsp)
++	movaps	%xmm9,0x40(%rsp)
++	movaps	%xmm10,0x50(%rsp)
++	movaps	%xmm11,0x60(%rsp)
++	movaps	%xmm12,0x70(%rsp)
++	movaps	%xmm13,0x80(%rsp)
++	movaps	%xmm14,0x90(%rsp)
++	movaps	%xmm15,0xa0(%rsp)
++.Lenc_body:
++___
++$code.=<<___;
++	movdqu	(%rdi),%xmm0
++	call	_vpaes_preheat
++	call	_vpaes_encrypt_core
++	movdqu	%xmm0,(%rsi)
++___
++$code.=<<___ if ($win64);
++	movaps	0x10(%rsp),%xmm6
++	movaps	0x20(%rsp),%xmm7
++	movaps	0x30(%rsp),%xmm8
++	movaps	0x40(%rsp),%xmm9
++	movaps	0x50(%rsp),%xmm10
++	movaps	0x60(%rsp),%xmm11
++	movaps	0x70(%rsp),%xmm12
++	movaps	0x80(%rsp),%xmm13
++	movaps	0x90(%rsp),%xmm14
++	movaps	0xa0(%rsp),%xmm15
++	lea	0xb8(%rsp),%rsp
++.Lenc_epilogue:
++___
++$code.=<<___;
++	ret
++.size	${PREFIX}_encrypt,.-${PREFIX}_encrypt
++
++.globl	${PREFIX}_decrypt
++.type	${PREFIX}_decrypt,\@function,3
++.align	16
++${PREFIX}_decrypt:
++___
++$code.=<<___ if ($win64);
++	lea	-0xb8(%rsp),%rsp
++	movaps	%xmm6,0x10(%rsp)
++	movaps	%xmm7,0x20(%rsp)
++	movaps	%xmm8,0x30(%rsp)
++	movaps	%xmm9,0x40(%rsp)
++	movaps	%xmm10,0x50(%rsp)
++	movaps	%xmm11,0x60(%rsp)
++	movaps	%xmm12,0x70(%rsp)
++	movaps	%xmm13,0x80(%rsp)
++	movaps	%xmm14,0x90(%rsp)
++	movaps	%xmm15,0xa0(%rsp)
++.Ldec_body:
++___
++$code.=<<___;
++	movdqu	(%rdi),%xmm0
++	call	_vpaes_preheat
++	call	_vpaes_decrypt_core
++	movdqu	%xmm0,(%rsi)
++___
++$code.=<<___ if ($win64);
++	movaps	0x10(%rsp),%xmm6
++	movaps	0x20(%rsp),%xmm7
++	movaps	0x30(%rsp),%xmm8
++	movaps	0x40(%rsp),%xmm9
++	movaps	0x50(%rsp),%xmm10
++	movaps	0x60(%rsp),%xmm11
++	movaps	0x70(%rsp),%xmm12
++	movaps	0x80(%rsp),%xmm13
++	movaps	0x90(%rsp),%xmm14
++	movaps	0xa0(%rsp),%xmm15
++	lea	0xb8(%rsp),%rsp
++.Ldec_epilogue:
++___
++$code.=<<___;
++	ret
++.size	${PREFIX}_decrypt,.-${PREFIX}_decrypt
++___
++{
++my ($inp,$out,$len,$key,$ivp,$enc)=("%rdi","%rsi","%rdx","%rcx","%r8","%r9");
++# void AES_cbc_encrypt (const void char *inp, unsigned char *out,
++#                       size_t length, const AES_KEY *key,
++#                       unsigned char *ivp,const int enc);
++$code.=<<___;
++.globl	${PREFIX}_cbc_encrypt
++.type	${PREFIX}_cbc_encrypt,\@function,6
++.align	16
++${PREFIX}_cbc_encrypt:
++	xchg	$key,$len
++___
++($len,$key)=($key,$len);
++$code.=<<___;
++	sub	\$16,$len
++	jc	.Lcbc_abort
++___
++$code.=<<___ if ($win64);
++	lea	-0xb8(%rsp),%rsp
++	movaps	%xmm6,0x10(%rsp)
++	movaps	%xmm7,0x20(%rsp)
++	movaps	%xmm8,0x30(%rsp)
++	movaps	%xmm9,0x40(%rsp)
++	movaps	%xmm10,0x50(%rsp)
++	movaps	%xmm11,0x60(%rsp)
++	movaps	%xmm12,0x70(%rsp)
++	movaps	%xmm13,0x80(%rsp)
++	movaps	%xmm14,0x90(%rsp)
++	movaps	%xmm15,0xa0(%rsp)
++.Lcbc_body:
++___
++$code.=<<___;
++	movdqu	($ivp),%xmm6		# load IV
++	sub	$inp,$out
++	call	_vpaes_preheat
++	cmp	\$0,${enc}d
++	je	.Lcbc_dec_loop
++	jmp	.Lcbc_enc_loop
++.align	16
++.Lcbc_enc_loop:
++	movdqu	($inp),%xmm0
++	pxor	%xmm6,%xmm0
++	call	_vpaes_encrypt_core
++	movdqa	%xmm0,%xmm6
++	movdqu	%xmm0,($out,$inp)
++	lea	16($inp),$inp
++	sub	\$16,$len
++	jnc	.Lcbc_enc_loop
++	jmp	.Lcbc_done
++.align	16
++.Lcbc_dec_loop:
++	movdqu	($inp),%xmm0
++	movdqa	%xmm0,%xmm7
++	call	_vpaes_decrypt_core
++	pxor	%xmm6,%xmm0
++	movdqa	%xmm7,%xmm6
++	movdqu	%xmm0,($out,$inp)
++	lea	16($inp),$inp
++	sub	\$16,$len
++	jnc	.Lcbc_dec_loop
++.Lcbc_done:
++	movdqu	%xmm6,($ivp)		# save IV
++___
++$code.=<<___ if ($win64);
++	movaps	0x10(%rsp),%xmm6
++	movaps	0x20(%rsp),%xmm7
++	movaps	0x30(%rsp),%xmm8
++	movaps	0x40(%rsp),%xmm9
++	movaps	0x50(%rsp),%xmm10
++	movaps	0x60(%rsp),%xmm11
++	movaps	0x70(%rsp),%xmm12
++	movaps	0x80(%rsp),%xmm13
++	movaps	0x90(%rsp),%xmm14
++	movaps	0xa0(%rsp),%xmm15
++	lea	0xb8(%rsp),%rsp
++.Lcbc_epilogue:
++___
++$code.=<<___;
++.Lcbc_abort:
++	ret
++.size	${PREFIX}_cbc_encrypt,.-${PREFIX}_cbc_encrypt
++___
++}
++$code.=<<___;
++##
++##  _aes_preheat
++##
++##  Fills register %r10 -> .aes_consts (so you can -fPIC)
++##  and %xmm9-%xmm15 as specified below.
++##
++.type	_vpaes_preheat,\@abi-omnipotent
++.align	16
++_vpaes_preheat:
++	lea	.Lk_s0F(%rip), %r10
++	movdqa	-0x20(%r10), %xmm10	# .Lk_inv
++	movdqa	-0x10(%r10), %xmm11	# .Lk_inv+16
++	movdqa	0x00(%r10), %xmm9	# .Lk_s0F
++	movdqa	0x30(%r10), %xmm13	# .Lk_sb1
++	movdqa	0x40(%r10), %xmm12	# .Lk_sb1+16
++	movdqa	0x50(%r10), %xmm15	# .Lk_sb2
++	movdqa	0x60(%r10), %xmm14	# .Lk_sb2+16
++	ret
++.size	_vpaes_preheat,.-_vpaes_preheat
++########################################################
++##                                                    ##
++##                     Constants                      ##
++##                                                    ##
++########################################################
++.type	_vpaes_consts,\@object
++.align	64
++_vpaes_consts:
++.Lk_inv:	# inv, inva
++	.quad	0x0E05060F0D080180, 0x040703090A0B0C02
++	.quad	0x01040A060F0B0780, 0x030D0E0C02050809
++
++.Lk_s0F:	# s0F
++	.quad	0x0F0F0F0F0F0F0F0F, 0x0F0F0F0F0F0F0F0F
++
++.Lk_ipt:	# input transform (lo, hi)
++	.quad	0xC2B2E8985A2A7000, 0xCABAE09052227808
++	.quad	0x4C01307D317C4D00, 0xCD80B1FCB0FDCC81
++
++.Lk_sb1:	# sb1u, sb1t
++	.quad	0xB19BE18FCB503E00, 0xA5DF7A6E142AF544
++	.quad	0x3618D415FAE22300, 0x3BF7CCC10D2ED9EF
++.Lk_sb2:	# sb2u, sb2t
++	.quad	0xE27A93C60B712400, 0x5EB7E955BC982FCD
++	.quad	0x69EB88400AE12900, 0xC2A163C8AB82234A
++.Lk_sbo:	# sbou, sbot
++	.quad	0xD0D26D176FBDC700, 0x15AABF7AC502A878
++	.quad	0xCFE474A55FBB6A00, 0x8E1E90D1412B35FA
++
++.Lk_mc_forward:	# mc_forward
++	.quad	0x0407060500030201, 0x0C0F0E0D080B0A09
++	.quad	0x080B0A0904070605, 0x000302010C0F0E0D
++	.quad	0x0C0F0E0D080B0A09, 0x0407060500030201
++	.quad	0x000302010C0F0E0D, 0x080B0A0904070605
++
++.Lk_mc_backward:# mc_backward
++	.quad	0x0605040702010003, 0x0E0D0C0F0A09080B
++	.quad	0x020100030E0D0C0F, 0x0A09080B06050407
++	.quad	0x0E0D0C0F0A09080B, 0x0605040702010003
++	.quad	0x0A09080B06050407, 0x020100030E0D0C0F
++
++.Lk_sr:		# sr
++	.quad	0x0706050403020100, 0x0F0E0D0C0B0A0908
++	.quad	0x030E09040F0A0500, 0x0B06010C07020D08
++	.quad	0x0F060D040B020900, 0x070E050C030A0108
++	.quad	0x0B0E0104070A0D00, 0x0306090C0F020508
++
++.Lk_rcon:	# rcon
++	.quad	0x1F8391B9AF9DEEB6, 0x702A98084D7C7D81
++
++.Lk_s63:	# s63: all equal to 0x63 transformed
++	.quad	0x5B5B5B5B5B5B5B5B, 0x5B5B5B5B5B5B5B5B
++
++.Lk_opt:	# output transform
++	.quad	0xFF9F4929D6B66000, 0xF7974121DEBE6808
++	.quad	0x01EDBD5150BCEC00, 0xE10D5DB1B05C0CE0
++
++.Lk_deskew:	# deskew tables: inverts the sbox's "skew"
++	.quad	0x07E4A34047A4E300, 0x1DFEB95A5DBEF91A
++	.quad	0x5F36B5DC83EA6900, 0x2841C2ABF49D1E77
++
++##
++##  Decryption stuff
++##  Key schedule constants
++##
++.Lk_dksd:	# decryption key schedule: invskew x*D
++	.quad	0xFEB91A5DA3E44700, 0x0740E3A45A1DBEF9
++	.quad	0x41C277F4B5368300, 0x5FDC69EAAB289D1E
++.Lk_dksb:	# decryption key schedule: invskew x*B
++	.quad	0x9A4FCA1F8550D500, 0x03D653861CC94C99
++	.quad	0x115BEDA7B6FC4A00, 0xD993256F7E3482C8
++.Lk_dkse:	# decryption key schedule: invskew x*E + 0x63
++	.quad	0xD5031CCA1FC9D600, 0x53859A4C994F5086
++	.quad	0xA23196054FDC7BE8, 0xCD5EF96A20B31487
++.Lk_dks9:	# decryption key schedule: invskew x*9
++	.quad	0xB6116FC87ED9A700, 0x4AED933482255BFC
++	.quad	0x4576516227143300, 0x8BB89FACE9DAFDCE
++
++##
++##  Decryption stuff
++##  Round function constants
++##
++.Lk_dipt:	# decryption input transform
++	.quad	0x0F505B040B545F00, 0x154A411E114E451A
++	.quad	0x86E383E660056500, 0x12771772F491F194
++
++.Lk_dsb9:	# decryption sbox output *9*u, *9*t
++	.quad	0x851C03539A86D600, 0xCAD51F504F994CC9
++	.quad	0xC03B1789ECD74900, 0x725E2C9EB2FBA565
++.Lk_dsbd:	# decryption sbox output *D*u, *D*t
++	.quad	0x7D57CCDFE6B1A200, 0xF56E9B13882A4439
++	.quad	0x3CE2FAF724C6CB00, 0x2931180D15DEEFD3
++.Lk_dsbb:	# decryption sbox output *B*u, *B*t
++	.quad	0xD022649296B44200, 0x602646F6B0F2D404
++	.quad	0xC19498A6CD596700, 0xF3FF0C3E3255AA6B
++.Lk_dsbe:	# decryption sbox output *E*u, *E*t
++	.quad	0x46F2929626D4D000, 0x2242600464B4F6B0
++	.quad	0x0C55A6CDFFAAC100, 0x9467F36B98593E32
++.Lk_dsbo:	# decryption sbox final output
++	.quad	0x1387EA537EF94000, 0xC7AA6DB9D4943E2D
++	.quad	0x12D7560F93441D00, 0xCA4B8159D8C58E9C
++.asciz	"Vector Permutation AES for x86_64/SSSE3, Mike Hamburg (Stanford University)"
++.align	64
++.size	_vpaes_consts,.-_vpaes_consts
++___
++
++if ($win64) {
++# EXCEPTION_DISPOSITION handler (EXCEPTION_RECORD *rec,ULONG64 frame,
++#		CONTEXT *context,DISPATCHER_CONTEXT *disp)
++$rec="%rcx";
++$frame="%rdx";
++$context="%r8";
++$disp="%r9";
++
++$code.=<<___;
++.extern	__imp_RtlVirtualUnwind
++.type	se_handler,\@abi-omnipotent
++.align	16
++se_handler:
++	push	%rsi
++	push	%rdi
++	push	%rbx
++	push	%rbp
++	push	%r12
++	push	%r13
++	push	%r14
++	push	%r15
++	pushfq
++	sub	\$64,%rsp
++
++	mov	120($context),%rax	# pull context->Rax
++	mov	248($context),%rbx	# pull context->Rip
++
++	mov	8($disp),%rsi		# disp->ImageBase
++	mov	56($disp),%r11		# disp->HandlerData
++
++	mov	0(%r11),%r10d		# HandlerData[0]
++	lea	(%rsi,%r10),%r10	# prologue label
++	cmp	%r10,%rbx		# context->RipRsp
++
++	mov	4(%r11),%r10d		# HandlerData[1]
++	lea	(%rsi,%r10),%r10	# epilogue label
++	cmp	%r10,%rbx		# context->Rip>=epilogue label
++	jae	.Lin_prologue
++
++	lea	16(%rax),%rsi		# %xmm save area
++	lea	512($context),%rdi	# &context.Xmm6
++	mov	\$20,%ecx		# 10*sizeof(%xmm0)/sizeof(%rax)
++	.long	0xa548f3fc		# cld; rep movsq
++	lea	0xb8(%rax),%rax		# adjust stack pointer
++
++.Lin_prologue:
++	mov	8(%rax),%rdi
++	mov	16(%rax),%rsi
++	mov	%rax,152($context)	# restore context->Rsp
++	mov	%rsi,168($context)	# restore context->Rsi
++	mov	%rdi,176($context)	# restore context->Rdi
++
++	mov	40($disp),%rdi		# disp->ContextRecord
++	mov	$context,%rsi		# context
++	mov	\$`1232/8`,%ecx		# sizeof(CONTEXT)
++	.long	0xa548f3fc		# cld; rep movsq
++
++	mov	$disp,%rsi
++	xor	%rcx,%rcx		# arg1, UNW_FLAG_NHANDLER
++	mov	8(%rsi),%rdx		# arg2, disp->ImageBase
++	mov	0(%rsi),%r8		# arg3, disp->ControlPc
++	mov	16(%rsi),%r9		# arg4, disp->FunctionEntry
++	mov	40(%rsi),%r10		# disp->ContextRecord
++	lea	56(%rsi),%r11		# &disp->HandlerData
++	lea	24(%rsi),%r12		# &disp->EstablisherFrame
++	mov	%r10,32(%rsp)		# arg5
++	mov	%r11,40(%rsp)		# arg6
++	mov	%r12,48(%rsp)		# arg7
++	mov	%rcx,56(%rsp)		# arg8, (NULL)
++	call	*__imp_RtlVirtualUnwind(%rip)
++
++	mov	\$1,%eax		# ExceptionContinueSearch
++	add	\$64,%rsp
++	popfq
++	pop	%r15
++	pop	%r14
++	pop	%r13
++	pop	%r12
++	pop	%rbp
++	pop	%rbx
++	pop	%rdi
++	pop	%rsi
++	ret
++.size	se_handler,.-se_handler
++
++.section	.pdata
++.align	4
++	.rva	.LSEH_begin_${PREFIX}_set_encrypt_key
++	.rva	.LSEH_end_${PREFIX}_set_encrypt_key
++	.rva	.LSEH_info_${PREFIX}_set_encrypt_key
++
++	.rva	.LSEH_begin_${PREFIX}_set_decrypt_key
++	.rva	.LSEH_end_${PREFIX}_set_decrypt_key
++	.rva	.LSEH_info_${PREFIX}_set_decrypt_key
++
++	.rva	.LSEH_begin_${PREFIX}_encrypt
++	.rva	.LSEH_end_${PREFIX}_encrypt
++	.rva	.LSEH_info_${PREFIX}_encrypt
++
++	.rva	.LSEH_begin_${PREFIX}_decrypt
++	.rva	.LSEH_end_${PREFIX}_decrypt
++	.rva	.LSEH_info_${PREFIX}_decrypt
++
++	.rva	.LSEH_begin_${PREFIX}_cbc_encrypt
++	.rva	.LSEH_end_${PREFIX}_cbc_encrypt
++	.rva	.LSEH_info_${PREFIX}_cbc_encrypt
++
++.section	.xdata
++.align	8
++.LSEH_info_${PREFIX}_set_encrypt_key:
++	.byte	9,0,0,0
++	.rva	se_handler
++	.rva	.Lenc_key_body,.Lenc_key_epilogue	# HandlerData[]
++.LSEH_info_${PREFIX}_set_decrypt_key:
++	.byte	9,0,0,0
++	.rva	se_handler
++	.rva	.Ldec_key_body,.Ldec_key_epilogue	# HandlerData[]
++.LSEH_info_${PREFIX}_encrypt:
++	.byte	9,0,0,0
++	.rva	se_handler
++	.rva	.Lenc_body,.Lenc_epilogue		# HandlerData[]
++.LSEH_info_${PREFIX}_decrypt:
++	.byte	9,0,0,0
++	.rva	se_handler
++	.rva	.Ldec_body,.Ldec_epilogue		# HandlerData[]
++.LSEH_info_${PREFIX}_cbc_encrypt:
++	.byte	9,0,0,0
++	.rva	se_handler
++	.rva	.Lcbc_body,.Lcbc_epilogue		# HandlerData[]
++___
++}
++
++$code =~ s/\`([^\`]*)\`/eval($1)/gem;
++
++print $code;
++
++close STDOUT;
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/aes/build.info b/CryptoPkg/Library/OpensslLib/openssl/crypto/aes/build.info
+new file mode 100644
+index 0000000..cf6cb5e
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/aes/build.info
+@@ -0,0 +1,57 @@
++LIBS=../../libcrypto
++SOURCE[../../libcrypto]=\
++        aes_misc.c aes_ecb.c aes_cfb.c aes_ofb.c \
++        aes_ige.c aes_wrap.c {- $target{aes_asm_src} -}
++
++GENERATE[aes-ia64.s]=asm/aes-ia64.S
++
++GENERATE[aes-586.s]=asm/aes-586.pl $(PERLASM_SCHEME) $(CFLAGS) $(LIB_CFLAGS) $(PROCESSOR)
++DEPEND[aes-586.s]=../perlasm/x86asm.pl
++GENERATE[vpaes-x86.s]=asm/vpaes-x86.pl $(PERLASM_SCHEME) $(CFLAGS) $(LIB_CFLAGS) $(PROCESSOR)
++DEPEND[vpaes-586.s]=../perlasm/x86asm.pl
++GENERATE[aesni-x86.s]=asm/aesni-x86.pl $(PERLASM_SCHEME) $(CFLAGS) $(LIB_CFLAGS) $(PROCESSOR)
++DEPEND[aesni-586.s]=../perlasm/x86asm.pl
++
++GENERATE[aes-x86_64.s]=asm/aes-x86_64.pl $(PERLASM_SCHEME)
++GENERATE[vpaes-x86_64.s]=asm/vpaes-x86_64.pl $(PERLASM_SCHEME)
++GENERATE[bsaes-x86_64.s]=asm/bsaes-x86_64.pl $(PERLASM_SCHEME)
++GENERATE[aesni-x86_64.s]=asm/aesni-x86_64.pl $(PERLASM_SCHEME)
++GENERATE[aesni-sha1-x86_64.s]=asm/aesni-sha1-x86_64.pl $(PERLASM_SCHEME)
++GENERATE[aesni-sha256-x86_64.s]=asm/aesni-sha256-x86_64.pl $(PERLASM_SCHEME)
++GENERATE[aesni-mb-x86_64.s]=asm/aesni-mb-x86_64.pl $(PERLASM_SCHEME)
++
++GENERATE[aes-sparcv9.S]=asm/aes-sparcv9.pl $(PERLASM_SCHEME)
++INCLUDE[aes-sparcv9.o]=..
++GENERATE[aest4-sparcv9.S]=asm/aest4-sparcv9.pl $(PERLASM_SCHEME)
++INCLUDE[aest4-sparcv9.o]=..
++DEPEND[aest4-sparcv9.S]=../perlasm/sparcv9_modes.pl
++GENERATE[aesfx-sparcv9.S]=asm/aesfx-sparcv9.pl $(PERLASM_SCHEME)
++INCLUDE[aesfx-sparcv9.o]=..
++
++GENERATE[aes-ppc.s]=asm/aes-ppc.pl $(PERLASM_SCHEME)
++GENERATE[vpaes-ppc.s]=asm/vpaes-ppc.pl $(PERLASM_SCHEME)
++GENERATE[aesp8-ppc.s]=asm/aesp8-ppc.pl $(PERLASM_SCHEME)
++
++GENERATE[aes-parisc.s]=asm/aes-parisc.pl $(PERLASM_SCHEME)
++
++GENERATE[aes-mips.S]=asm/aes-mips.pl $(PERLASM_SCHEME)
++
++GENERATE[aesv8-armx.S]=asm/aesv8-armx.pl $(PERLASM_SCHEME)
++INCLUDE[aesv8-armx.o]=..
++GENERATE[vpaes-armv8.S]=asm/vpaes-armv8.pl $(PERLASM_SCHEME)
++
++GENERATE[aes-armv4.S]=asm/aes-armv4.pl $(PERLASM_SCHEME)
++INCLUDE[aes-armv4.o]=..
++GENERATE[bsaes-armv7.S]=asm/bsaes-armv7.pl $(PERLASM_SCHEME)
++INCLUDE[bsaes-armv7.o]=..
++
++BEGINRAW[Makefile]
++##### AES assembler implementations
++
++# GNU make "catch all"
++{- $builddir -}/aes-%.S:	{- $sourcedir -}/asm/aes-%.pl
++	CC="$(CC)" $(PERL) $< $(PERLASM_SCHEME) $@
++{- $builddir -}/bsaes-%.S:	{- $sourcedir -}/asm/bsaes-%.pl
++	CC="$(CC)" $(PERL) $< $(PERLASM_SCHEME) $@
++
++ENDRAW[Makefile]
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/alphacpuid.pl b/CryptoPkg/Library/OpensslLib/openssl/crypto/alphacpuid.pl
+new file mode 100644
+index 0000000..6c7fd4c
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/alphacpuid.pl
+@@ -0,0 +1,257 @@
++#! /usr/bin/env perl
++# Copyright 2010-2016 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
++# in the file LICENSE in the source distribution or at
++# https://www.openssl.org/source/license.html
++
++
++$output = pop;
++open STDOUT,">$output";
++
++print <<'___';
++.text
++
++.set	noat
++
++.globl	OPENSSL_cpuid_setup
++.ent	OPENSSL_cpuid_setup
++OPENSSL_cpuid_setup:
++	.frame	$30,0,$26
++	.prologue 0
++	ret	($26)
++.end	OPENSSL_cpuid_setup
++
++.globl	OPENSSL_wipe_cpu
++.ent	OPENSSL_wipe_cpu
++OPENSSL_wipe_cpu:
++	.frame	$30,0,$26
++	.prologue 0
++	clr	$1
++	clr	$2
++	clr	$3
++	clr	$4
++	clr	$5
++	clr	$6
++	clr	$7
++	clr	$8
++	clr	$16
++	clr	$17
++	clr	$18
++	clr	$19
++	clr	$20
++	clr	$21
++	clr	$22
++	clr	$23
++	clr	$24
++	clr	$25
++	clr	$27
++	clr	$at
++	clr	$29
++	fclr	$f0
++	fclr	$f1
++	fclr	$f10
++	fclr	$f11
++	fclr	$f12
++	fclr	$f13
++	fclr	$f14
++	fclr	$f15
++	fclr	$f16
++	fclr	$f17
++	fclr	$f18
++	fclr	$f19
++	fclr	$f20
++	fclr	$f21
++	fclr	$f22
++	fclr	$f23
++	fclr	$f24
++	fclr	$f25
++	fclr	$f26
++	fclr	$f27
++	fclr	$f28
++	fclr	$f29
++	fclr	$f30
++	mov	$sp,$0
++	ret	($26)
++.end	OPENSSL_wipe_cpu
++
++.globl	OPENSSL_atomic_add
++.ent	OPENSSL_atomic_add
++OPENSSL_atomic_add:
++	.frame	$30,0,$26
++	.prologue 0
++1:	ldl_l	$0,0($16)
++	addl	$0,$17,$1
++	stl_c	$1,0($16)
++	beq	$1,1b
++	addl	$0,$17,$0
++	ret	($26)
++.end	OPENSSL_atomic_add
++
++.globl	OPENSSL_rdtsc
++.ent	OPENSSL_rdtsc
++OPENSSL_rdtsc:
++	.frame	$30,0,$26
++	.prologue 0
++	rpcc	$0
++	ret	($26)
++.end	OPENSSL_rdtsc
++
++.globl	OPENSSL_cleanse
++.ent	OPENSSL_cleanse
++OPENSSL_cleanse:
++	.frame	$30,0,$26
++	.prologue 0
++	beq	$17,.Ldone
++	and	$16,7,$0
++	bic	$17,7,$at
++	beq	$at,.Little
++	beq	$0,.Laligned
++
++.Little:
++	subq	$0,8,$0
++	ldq_u	$1,0($16)
++	mov	$16,$2
++.Lalign:
++	mskbl	$1,$16,$1
++	lda	$16,1($16)
++	subq	$17,1,$17
++	addq	$0,1,$0
++	beq	$17,.Lout
++	bne	$0,.Lalign
++.Lout:	stq_u	$1,0($2)
++	beq	$17,.Ldone
++	bic	$17,7,$at
++	beq	$at,.Little
++
++.Laligned:
++	stq	$31,0($16)
++	subq	$17,8,$17
++	lda	$16,8($16)
++	bic	$17,7,$at
++	bne	$at,.Laligned
++	bne	$17,.Little
++.Ldone: ret	($26)
++.end	OPENSSL_cleanse
++
++.globl	CRYPTO_memcmp
++.ent	CRYPTO_memcmp
++CRYPTO_memcmp:
++	.frame	$30,0,$26
++	.prologue 0
++	xor	$0,$0,$0
++	beq	$18,.Lno_data
++
++	xor	$1,$1,$1
++	nop
++.Loop_cmp:
++	ldq_u	$2,0($16)
++	subq	$18,1,$18
++	ldq_u	$3,0($17)
++	extbl	$2,$16,$2
++	lda	$16,1($16)
++	extbl	$3,$17,$3
++	lda	$17,1($17)
++	xor	$3,$2,$2
++	or	$2,$0,$0
++	bne	$18,.Loop_cmp
++
++	subq	$31,$0,$0
++	srl	$0,63,$0
++.Lno_data:
++	ret	($26)
++.end	CRYPTO_memcmp
++___
++{
++my ($out,$cnt,$max)=("\$16","\$17","\$18");
++my ($tick,$lasttick)=("\$19","\$20");
++my ($diff,$lastdiff)=("\$21","\$22");
++my ($v0,$ra,$sp,$zero)=("\$0","\$26","\$30","\$31");
++
++print <<___;
++.globl	OPENSSL_instrument_bus
++.ent	OPENSSL_instrument_bus
++OPENSSL_instrument_bus:
++	.frame	$sp,0,$ra
++	.prologue 0
++	mov	$cnt,$v0
++
++	rpcc	$lasttick
++	mov	0,$diff
++
++	ecb	($out)
++	ldl_l	$tick,0($out)
++	addl	$diff,$tick,$tick
++	mov	$tick,$diff
++	stl_c	$tick,0($out)
++	stl	$diff,0($out)
++
++.Loop:	rpcc	$tick
++	subq	$tick,$lasttick,$diff
++	mov	$tick,$lasttick
++
++	ecb	($out)
++	ldl_l	$tick,0($out)
++	addl	$diff,$tick,$tick
++	mov	$tick,$diff
++	stl_c	$tick,0($out)
++	stl	$diff,0($out)
++
++	subl	$cnt,1,$cnt
++	lda	$out,4($out)
++	bne	$cnt,.Loop
++
++	ret	($ra)
++.end	OPENSSL_instrument_bus
++
++.globl	OPENSSL_instrument_bus2
++.ent	OPENSSL_instrument_bus2
++OPENSSL_instrument_bus2:
++	.frame	$sp,0,$ra
++	.prologue 0
++	mov	$cnt,$v0
++
++	rpcc	$lasttick
++	mov	0,$diff
++
++	ecb	($out)
++	ldl_l	$tick,0($out)
++	addl	$diff,$tick,$tick
++	mov	$tick,$diff
++	stl_c	$tick,0($out)
++	stl	$diff,0($out)
++
++	rpcc	$tick
++	subq	$tick,$lasttick,$diff
++	mov	$tick,$lasttick
++	mov	$diff,$lastdiff
++.Loop2:
++	ecb	($out)
++	ldl_l	$tick,0($out)
++	addl	$diff,$tick,$tick
++	mov	$tick,$diff
++	stl_c	$tick,0($out)
++	stl	$diff,0($out)
++
++	subl	$max,1,$max
++	beq	$max,.Ldone2
++
++	rpcc	$tick
++	subq	$tick,$lasttick,$diff
++	mov	$tick,$lasttick
++	subq	$lastdiff,$diff,$tick
++	mov	$diff,$lastdiff
++	cmovne	$tick,1,$tick
++	subl	$cnt,$tick,$cnt
++	s4addq	$tick,$out,$out
++	bne	$cnt,.Loop2
++
++.Ldone2:
++	subl	$v0,$cnt,$v0
++	ret	($ra)
++.end	OPENSSL_instrument_bus2
++___
++}
++
++close STDOUT;
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/arm64cpuid.pl b/CryptoPkg/Library/OpensslLib/openssl/crypto/arm64cpuid.pl
+new file mode 100755
+index 0000000..caa3387
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/arm64cpuid.pl
+@@ -0,0 +1,126 @@
++#! /usr/bin/env perl
++# Copyright 2015-2016 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
++# in the file LICENSE in the source distribution or at
++# https://www.openssl.org/source/license.html
++
++
++$flavour = shift;
++$output  = shift;
++
++$0 =~ m/(.*[\/\\])[^\/\\]+$/; $dir=$1;
++( $xlate="${dir}arm-xlate.pl" and -f $xlate ) or
++( $xlate="${dir}perlasm/arm-xlate.pl" and -f $xlate) or
++die "can't locate arm-xlate.pl";
++
++open OUT,"| \"$^X\" $xlate $flavour $output";
++*STDOUT=*OUT;
++
++$code.=<<___;
++#include "arm_arch.h"
++
++.text
++.arch	armv8-a+crypto
++
++.align	5
++.globl	_armv7_neon_probe
++.type	_armv7_neon_probe,%function
++_armv7_neon_probe:
++	orr	v15.16b, v15.16b, v15.16b
++	ret
++.size	_armv7_neon_probe,.-_armv7_neon_probe
++
++.globl	_armv7_tick
++.type	_armv7_tick,%function
++_armv7_tick:
++#ifdef	__APPLE__
++	mrs	x0, CNTPCT_EL0
++#else
++	mrs	x0, CNTVCT_EL0
++#endif
++	ret
++.size	_armv7_tick,.-_armv7_tick
++
++.globl	_armv8_aes_probe
++.type	_armv8_aes_probe,%function
++_armv8_aes_probe:
++	aese	v0.16b, v0.16b
++	ret
++.size	_armv8_aes_probe,.-_armv8_aes_probe
++
++.globl	_armv8_sha1_probe
++.type	_armv8_sha1_probe,%function
++_armv8_sha1_probe:
++	sha1h	s0, s0
++	ret
++.size	_armv8_sha1_probe,.-_armv8_sha1_probe
++
++.globl	_armv8_sha256_probe
++.type	_armv8_sha256_probe,%function
++_armv8_sha256_probe:
++	sha256su0	v0.4s, v0.4s
++	ret
++.size	_armv8_sha256_probe,.-_armv8_sha256_probe
++.globl	_armv8_pmull_probe
++.type	_armv8_pmull_probe,%function
++_armv8_pmull_probe:
++	pmull	v0.1q, v0.1d, v0.1d
++	ret
++.size	_armv8_pmull_probe,.-_armv8_pmull_probe
++
++.globl	OPENSSL_cleanse
++.type	OPENSSL_cleanse,%function
++.align	5
++OPENSSL_cleanse:
++	cbz	x1,.Lret	// len==0?
++	cmp	x1,#15
++	b.hi	.Lot		// len>15
++	nop
++.Little:
++	strb	wzr,[x0],#1	// store byte-by-byte
++	subs	x1,x1,#1
++	b.ne	.Little
++.Lret:	ret
++
++.align	4
++.Lot:	tst	x0,#7
++	b.eq	.Laligned	// inp is aligned
++	strb	wzr,[x0],#1	// store byte-by-byte
++	sub	x1,x1,#1
++	b	.Lot
++
++.align	4
++.Laligned:
++	str	xzr,[x0],#8	// store word-by-word
++	sub	x1,x1,#8
++	tst	x1,#-8
++	b.ne	.Laligned	// len>=8
++	cbnz	x1,.Little	// len!=0?
++	ret
++.size	OPENSSL_cleanse,.-OPENSSL_cleanse
++
++.globl	CRYPTO_memcmp
++.type	CRYPTO_memcmp,%function
++.align	4
++CRYPTO_memcmp:
++	eor	w3,w3,w3
++	cbz	x2,.Lno_data	// len==0?
++.Loop_cmp:
++	ldrb	w4,[x0],#1
++	ldrb	w5,[x1],#1
++	eor	w4,w4,w5
++	orr	w3,w3,w4
++	subs	x2,x2,#1
++	b.ne	.Loop_cmp
++
++.Lno_data:
++	neg	w0,w3
++	lsr	w0,w0,#31
++	ret
++.size	CRYPTO_memcmp,.-CRYPTO_memcmp
++___
++
++print $code;
++close STDOUT;
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/arm_arch.h b/CryptoPkg/Library/OpensslLib/openssl/crypto/arm_arch.h
+new file mode 100644
+index 0000000..3fc9e69
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/arm_arch.h
+@@ -0,0 +1,83 @@
++/*
++ * Copyright 2011-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#ifndef __ARM_ARCH_H__
++# define __ARM_ARCH_H__
++
++# if !defined(__ARM_ARCH__)
++#  if defined(__CC_ARM)
++#   define __ARM_ARCH__ __TARGET_ARCH_ARM
++#   if defined(__BIG_ENDIAN)
++#    define __ARMEB__
++#   else
++#    define __ARMEL__
++#   endif
++#  elif defined(__GNUC__)
++#   if   defined(__aarch64__)
++#    define __ARM_ARCH__ 8
++#    if __BYTE_ORDER__==__ORDER_BIG_ENDIAN__
++#     define __ARMEB__
++#    else
++#     define __ARMEL__
++#    endif
++  /*
++   * Why doesn't gcc define __ARM_ARCH__? Instead it defines
++   * bunch of below macros. See all_architectires[] table in
++   * gcc/config/arm/arm.c. On a side note it defines
++   * __ARMEL__/__ARMEB__ for little-/big-endian.
++   */
++#   elif defined(__ARM_ARCH)
++#    define __ARM_ARCH__ __ARM_ARCH
++#   elif defined(__ARM_ARCH_8A__)
++#    define __ARM_ARCH__ 8
++#   elif defined(__ARM_ARCH_7__) || defined(__ARM_ARCH_7A__)     || \
++        defined(__ARM_ARCH_7R__)|| defined(__ARM_ARCH_7M__)     || \
++        defined(__ARM_ARCH_7EM__)
++#    define __ARM_ARCH__ 7
++#   elif defined(__ARM_ARCH_6__) || defined(__ARM_ARCH_6J__)     || \
++        defined(__ARM_ARCH_6K__)|| defined(__ARM_ARCH_6M__)     || \
++        defined(__ARM_ARCH_6Z__)|| defined(__ARM_ARCH_6ZK__)    || \
++        defined(__ARM_ARCH_6T2__)
++#    define __ARM_ARCH__ 6
++#   elif defined(__ARM_ARCH_5__) || defined(__ARM_ARCH_5T__)     || \
++        defined(__ARM_ARCH_5E__)|| defined(__ARM_ARCH_5TE__)    || \
++        defined(__ARM_ARCH_5TEJ__)
++#    define __ARM_ARCH__ 5
++#   elif defined(__ARM_ARCH_4__) || defined(__ARM_ARCH_4T__)
++#    define __ARM_ARCH__ 4
++#   else
++#    error "unsupported ARM architecture"
++#   endif
++#  endif
++# endif
++
++# if !defined(__ARM_MAX_ARCH__)
++#  define __ARM_MAX_ARCH__ __ARM_ARCH__
++# endif
++
++# if __ARM_MAX_ARCH__<__ARM_ARCH__
++#  error "__ARM_MAX_ARCH__ can't be less than __ARM_ARCH__"
++# elif __ARM_MAX_ARCH__!=__ARM_ARCH__
++#  if __ARM_ARCH__<7 && __ARM_MAX_ARCH__>=7 && defined(__ARMEB__)
++#   error "can't build universal big-endian binary"
++#  endif
++# endif
++
++# if !__ASSEMBLER__
++extern unsigned int OPENSSL_armcap_P;
++# endif
++
++# define ARMV7_NEON      (1<<0)
++# define ARMV7_TICK      (1<<1)
++# define ARMV8_AES       (1<<2)
++# define ARMV8_SHA1      (1<<3)
++# define ARMV8_SHA256    (1<<4)
++# define ARMV8_PMULL     (1<<5)
++
++#endif
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/armcap.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/armcap.c
+new file mode 100644
+index 0000000..2953484
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/armcap.c
+@@ -0,0 +1,193 @@
++/*
++ * Copyright 2011-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include 
++#include 
++#include 
++#include 
++#include 
++
++#include "arm_arch.h"
++
++unsigned int OPENSSL_armcap_P = 0;
++
++#if __ARM_MAX_ARCH__<7
++void OPENSSL_cpuid_setup(void)
++{
++}
++
++unsigned long OPENSSL_rdtsc(void)
++{
++    return 0;
++}
++#else
++static sigset_t all_masked;
++
++static sigjmp_buf ill_jmp;
++static void ill_handler(int sig)
++{
++    siglongjmp(ill_jmp, sig);
++}
++
++/*
++ * Following subroutines could have been inlined, but it's not all
++ * ARM compilers support inline assembler...
++ */
++void _armv7_neon_probe(void);
++void _armv8_aes_probe(void);
++void _armv8_sha1_probe(void);
++void _armv8_sha256_probe(void);
++void _armv8_pmull_probe(void);
++unsigned long _armv7_tick(void);
++
++unsigned long OPENSSL_rdtsc(void)
++{
++    if (OPENSSL_armcap_P & ARMV7_TICK)
++        return _armv7_tick();
++    else
++        return 0;
++}
++
++# if defined(__GNUC__) && __GNUC__>=2
++void OPENSSL_cpuid_setup(void) __attribute__ ((constructor));
++# endif
++/*
++ * Use a weak reference to getauxval() so we can use it if it is available but
++ * don't break the build if it is not.
++ */
++# if defined(__GNUC__) && __GNUC__>=2 && defined(__ELF__)
++extern unsigned long getauxval(unsigned long type) __attribute__ ((weak));
++# else
++static unsigned long (*getauxval) (unsigned long) = NULL;
++# endif
++
++/*
++ * ARM puts the the feature bits for Crypto Extensions in AT_HWCAP2, whereas
++ * AArch64 used AT_HWCAP.
++ */
++# if defined(__arm__) || defined (__arm)
++#  define HWCAP                  16
++                                  /* AT_HWCAP */
++#  define HWCAP_NEON             (1 << 12)
++
++#  define HWCAP_CE               26
++                                  /* AT_HWCAP2 */
++#  define HWCAP_CE_AES           (1 << 0)
++#  define HWCAP_CE_PMULL         (1 << 1)
++#  define HWCAP_CE_SHA1          (1 << 2)
++#  define HWCAP_CE_SHA256        (1 << 3)
++# elif defined(__aarch64__)
++#  define HWCAP                  16
++                                  /* AT_HWCAP */
++#  define HWCAP_NEON             (1 << 1)
++
++#  define HWCAP_CE               HWCAP
++#  define HWCAP_CE_AES           (1 << 3)
++#  define HWCAP_CE_PMULL         (1 << 4)
++#  define HWCAP_CE_SHA1          (1 << 5)
++#  define HWCAP_CE_SHA256        (1 << 6)
++# endif
++
++void OPENSSL_cpuid_setup(void)
++{
++    char *e;
++    struct sigaction ill_oact, ill_act;
++    sigset_t oset;
++    static int trigger = 0;
++
++    if (trigger)
++        return;
++    trigger = 1;
++
++    if ((e = getenv("OPENSSL_armcap"))) {
++        OPENSSL_armcap_P = (unsigned int)strtoul(e, NULL, 0);
++        return;
++    }
++
++# if defined(__APPLE__) && !defined(__aarch64__)
++    /*
++     * Capability probing by catching SIGILL appears to be problematic
++     * on iOS. But since Apple universe is "monocultural", it's actually
++     * possible to simply set pre-defined processor capability mask.
++     */
++    if (1) {
++        OPENSSL_armcap_P = ARMV7_NEON;
++        return;
++    }
++    /*
++     * One could do same even for __aarch64__ iOS builds. It's not done
++     * exclusively for reasons of keeping code unified across platforms.
++     * Unified code works because it never triggers SIGILL on Apple
++     * devices...
++     */
++# endif
++
++    sigfillset(&all_masked);
++    sigdelset(&all_masked, SIGILL);
++    sigdelset(&all_masked, SIGTRAP);
++    sigdelset(&all_masked, SIGFPE);
++    sigdelset(&all_masked, SIGBUS);
++    sigdelset(&all_masked, SIGSEGV);
++
++    OPENSSL_armcap_P = 0;
++
++    memset(&ill_act, 0, sizeof(ill_act));
++    ill_act.sa_handler = ill_handler;
++    ill_act.sa_mask = all_masked;
++
++    sigprocmask(SIG_SETMASK, &ill_act.sa_mask, &oset);
++    sigaction(SIGILL, &ill_act, &ill_oact);
++
++    if (getauxval != NULL) {
++        if (getauxval(HWCAP) & HWCAP_NEON) {
++            unsigned long hwcap = getauxval(HWCAP_CE);
++
++            OPENSSL_armcap_P |= ARMV7_NEON;
++
++            if (hwcap & HWCAP_CE_AES)
++                OPENSSL_armcap_P |= ARMV8_AES;
++
++            if (hwcap & HWCAP_CE_PMULL)
++                OPENSSL_armcap_P |= ARMV8_PMULL;
++
++            if (hwcap & HWCAP_CE_SHA1)
++                OPENSSL_armcap_P |= ARMV8_SHA1;
++
++            if (hwcap & HWCAP_CE_SHA256)
++                OPENSSL_armcap_P |= ARMV8_SHA256;
++        }
++    } else if (sigsetjmp(ill_jmp, 1) == 0) {
++        _armv7_neon_probe();
++        OPENSSL_armcap_P |= ARMV7_NEON;
++        if (sigsetjmp(ill_jmp, 1) == 0) {
++            _armv8_pmull_probe();
++            OPENSSL_armcap_P |= ARMV8_PMULL | ARMV8_AES;
++        } else if (sigsetjmp(ill_jmp, 1) == 0) {
++            _armv8_aes_probe();
++            OPENSSL_armcap_P |= ARMV8_AES;
++        }
++        if (sigsetjmp(ill_jmp, 1) == 0) {
++            _armv8_sha1_probe();
++            OPENSSL_armcap_P |= ARMV8_SHA1;
++        }
++        if (sigsetjmp(ill_jmp, 1) == 0) {
++            _armv8_sha256_probe();
++            OPENSSL_armcap_P |= ARMV8_SHA256;
++        }
++    }
++    if (sigsetjmp(ill_jmp, 1) == 0) {
++        _armv7_tick();
++        OPENSSL_armcap_P |= ARMV7_TICK;
++    }
++
++    sigaction(SIGILL, &ill_oact, NULL);
++    sigprocmask(SIG_SETMASK, &oset, NULL);
++}
++#endif
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/armv4cpuid.pl b/CryptoPkg/Library/OpensslLib/openssl/crypto/armv4cpuid.pl
+new file mode 100644
+index 0000000..f7d31a6
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/armv4cpuid.pl
+@@ -0,0 +1,296 @@
++#! /usr/bin/env perl
++# Copyright 2015-2016 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
++# in the file LICENSE in the source distribution or at
++# https://www.openssl.org/source/license.html
++
++
++$flavour = shift;
++$output  = shift;
++
++$0 =~ m/(.*[\/\\])[^\/\\]+$/; $dir=$1;
++( $xlate="${dir}arm-xlate.pl" and -f $xlate ) or
++( $xlate="${dir}perlasm/arm-xlate.pl" and -f $xlate) or
++die "can't locate arm-xlate.pl";
++
++open OUT,"| \"$^X\" $xlate $flavour $output";
++*STDOUT=*OUT;
++
++$code.=<<___;
++#include "arm_arch.h"
++
++.text
++#if defined(__thumb2__) && !defined(__APPLE__)
++.syntax	unified
++.thumb
++#else
++.code	32
++#undef	__thumb2__
++#endif
++
++.align	5
++.global	OPENSSL_atomic_add
++.type	OPENSSL_atomic_add,%function
++OPENSSL_atomic_add:
++#if __ARM_ARCH__>=6
++.Ladd:	ldrex	r2,[r0]
++	add	r3,r2,r1
++	strex	r2,r3,[r0]
++	cmp	r2,#0
++	bne	.Ladd
++	mov	r0,r3
++	bx	lr
++#else
++	stmdb	sp!,{r4-r6,lr}
++	ldr	r2,.Lspinlock
++	adr	r3,.Lspinlock
++	mov	r4,r0
++	mov	r5,r1
++	add	r6,r3,r2	@ &spinlock
++	b	.+8
++.Lspin:	bl	sched_yield
++	mov	r0,#-1
++	swp	r0,r0,[r6]
++	cmp	r0,#0
++	bne	.Lspin
++
++	ldr	r2,[r4]
++	add	r2,r2,r5
++	str	r2,[r4]
++	str	r0,[r6]		@ release spinlock
++	ldmia	sp!,{r4-r6,lr}
++	tst	lr,#1
++	moveq	pc,lr
++	.word	0xe12fff1e	@ bx	lr
++#endif
++.size	OPENSSL_atomic_add,.-OPENSSL_atomic_add
++
++.global	OPENSSL_cleanse
++.type	OPENSSL_cleanse,%function
++OPENSSL_cleanse:
++	eor	ip,ip,ip
++	cmp	r1,#7
++#ifdef	__thumb2__
++	itt	hs
++#endif
++	subhs	r1,r1,#4
++	bhs	.Lot
++	cmp	r1,#0
++	beq	.Lcleanse_done
++.Little:
++	strb	ip,[r0],#1
++	subs	r1,r1,#1
++	bhi	.Little
++	b	.Lcleanse_done
++
++.Lot:	tst	r0,#3
++	beq	.Laligned
++	strb	ip,[r0],#1
++	sub	r1,r1,#1
++	b	.Lot
++.Laligned:
++	str	ip,[r0],#4
++	subs	r1,r1,#4
++	bhs	.Laligned
++	adds	r1,r1,#4
++	bne	.Little
++.Lcleanse_done:
++#if __ARM_ARCH__>=5
++	bx	lr
++#else
++	tst	lr,#1
++	moveq	pc,lr
++	.word	0xe12fff1e	@ bx	lr
++#endif
++.size	OPENSSL_cleanse,.-OPENSSL_cleanse
++
++.global	CRYPTO_memcmp
++.type	CRYPTO_memcmp,%function
++.align	4
++CRYPTO_memcmp:
++	eor	ip,ip,ip
++	cmp	r2,#0
++	beq	.Lno_data
++	stmdb	sp!,{r4,r5}
++
++.Loop_cmp:
++	ldrb	r4,[r0],#1
++	ldrb	r5,[r1],#1
++	eor	r4,r4,r5
++	orr	ip,ip,r4
++	subs	r2,r2,#1
++	bne	.Loop_cmp
++
++	ldmia	sp!,{r4,r5}
++.Lno_data:
++	neg	r0,ip
++	mov	r0,r0,lsr#31
++#if __ARM_ARCH__>=5
++	bx	lr
++#else
++	tst	lr,#1
++	moveq	pc,lr
++	.word	0xe12fff1e	@ bx	lr
++#endif
++.size	CRYPTO_memcmp,.-CRYPTO_memcmp
++
++#if __ARM_MAX_ARCH__>=7
++.arch	armv7-a
++.fpu	neon
++
++.align	5
++.global	_armv7_neon_probe
++.type	_armv7_neon_probe,%function
++_armv7_neon_probe:
++	vorr	q0,q0,q0
++	bx	lr
++.size	_armv7_neon_probe,.-_armv7_neon_probe
++
++.global	_armv7_tick
++.type	_armv7_tick,%function
++_armv7_tick:
++#ifdef	__APPLE__
++	mrrc	p15,0,r0,r1,c14		@ CNTPCT
++#else
++	mrrc	p15,1,r0,r1,c14		@ CNTVCT
++#endif
++	bx	lr
++.size	_armv7_tick,.-_armv7_tick
++
++.global	_armv8_aes_probe
++.type	_armv8_aes_probe,%function
++_armv8_aes_probe:
++#if defined(__thumb2__) && !defined(__APPLE__)
++	.byte	0xb0,0xff,0x00,0x03	@ aese.8	q0,q0
++#else
++	.byte	0x00,0x03,0xb0,0xf3	@ aese.8	q0,q0
++#endif
++	bx	lr
++.size	_armv8_aes_probe,.-_armv8_aes_probe
++
++.global	_armv8_sha1_probe
++.type	_armv8_sha1_probe,%function
++_armv8_sha1_probe:
++#if defined(__thumb2__) && !defined(__APPLE__)
++	.byte	0x00,0xef,0x40,0x0c	@ sha1c.32	q0,q0,q0
++#else
++	.byte	0x40,0x0c,0x00,0xf2	@ sha1c.32	q0,q0,q0
++#endif
++	bx	lr
++.size	_armv8_sha1_probe,.-_armv8_sha1_probe
++
++.global	_armv8_sha256_probe
++.type	_armv8_sha256_probe,%function
++_armv8_sha256_probe:
++#if defined(__thumb2__) && !defined(__APPLE__)
++	.byte	0x00,0xff,0x40,0x0c	@ sha256h.32	q0,q0,q0
++#else
++	.byte	0x40,0x0c,0x00,0xf3	@ sha256h.32	q0,q0,q0
++#endif
++	bx	lr
++.size	_armv8_sha256_probe,.-_armv8_sha256_probe
++.global	_armv8_pmull_probe
++.type	_armv8_pmull_probe,%function
++_armv8_pmull_probe:
++#if defined(__thumb2__) && !defined(__APPLE__)
++	.byte	0xa0,0xef,0x00,0x0e	@ vmull.p64	q0,d0,d0
++#else
++	.byte	0x00,0x0e,0xa0,0xf2	@ vmull.p64	q0,d0,d0
++#endif
++	bx	lr
++.size	_armv8_pmull_probe,.-_armv8_pmull_probe
++#endif
++
++.global	OPENSSL_wipe_cpu
++.type	OPENSSL_wipe_cpu,%function
++OPENSSL_wipe_cpu:
++#if __ARM_MAX_ARCH__>=7
++	ldr	r0,.LOPENSSL_armcap
++	adr	r1,.LOPENSSL_armcap
++	ldr	r0,[r1,r0]
++#ifdef	__APPLE__
++	ldr	r0,[r0]
++#endif
++#endif
++	eor	r2,r2,r2
++	eor	r3,r3,r3
++	eor	ip,ip,ip
++#if __ARM_MAX_ARCH__>=7
++	tst	r0,#1
++	beq	.Lwipe_done
++	veor	q0, q0, q0
++	veor	q1, q1, q1
++	veor	q2, q2, q2
++	veor	q3, q3, q3
++	veor	q8, q8, q8
++	veor	q9, q9, q9
++	veor	q10, q10, q10
++	veor	q11, q11, q11
++	veor	q12, q12, q12
++	veor	q13, q13, q13
++	veor	q14, q14, q14
++	veor	q15, q15, q15
++.Lwipe_done:
++#endif
++	mov	r0,sp
++#if __ARM_ARCH__>=5
++	bx	lr
++#else
++	tst	lr,#1
++	moveq	pc,lr
++	.word	0xe12fff1e	@ bx	lr
++#endif
++.size	OPENSSL_wipe_cpu,.-OPENSSL_wipe_cpu
++
++.global	OPENSSL_instrument_bus
++.type	OPENSSL_instrument_bus,%function
++OPENSSL_instrument_bus:
++	eor	r0,r0,r0
++#if __ARM_ARCH__>=5
++	bx	lr
++#else
++	tst	lr,#1
++	moveq	pc,lr
++	.word	0xe12fff1e	@ bx	lr
++#endif
++.size	OPENSSL_instrument_bus,.-OPENSSL_instrument_bus
++
++.global	OPENSSL_instrument_bus2
++.type	OPENSSL_instrument_bus2,%function
++OPENSSL_instrument_bus2:
++	eor	r0,r0,r0
++#if __ARM_ARCH__>=5
++	bx	lr
++#else
++	tst	lr,#1
++	moveq	pc,lr
++	.word	0xe12fff1e	@ bx	lr
++#endif
++.size	OPENSSL_instrument_bus2,.-OPENSSL_instrument_bus2
++
++.align	5
++#if __ARM_MAX_ARCH__>=7
++.LOPENSSL_armcap:
++.word	OPENSSL_armcap_P-.
++#endif
++#if __ARM_ARCH__>=6
++.align	5
++#else
++.Lspinlock:
++.word	atomic_add_spinlock-.Lspinlock
++.align	5
++
++.data
++.align	2
++atomic_add_spinlock:
++.word	0
++#endif
++
++.comm	OPENSSL_armcap_P,4,4
++.hidden	OPENSSL_armcap_P
++___
++
++print $code;
++close STDOUT;
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/asn1/a_bitstr.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/asn1/a_bitstr.c
+new file mode 100644
+index 0000000..33be907
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/asn1/a_bitstr.c
+@@ -0,0 +1,210 @@
++/*
++ * Copyright 1995-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include "internal/cryptlib.h"
++#include 
++#include "asn1_locl.h"
++
++int ASN1_BIT_STRING_set(ASN1_BIT_STRING *x, unsigned char *d, int len)
++{
++    return ASN1_STRING_set(x, d, len);
++}
++
++int i2c_ASN1_BIT_STRING(ASN1_BIT_STRING *a, unsigned char **pp)
++{
++    int ret, j, bits, len;
++    unsigned char *p, *d;
++
++    if (a == NULL)
++        return (0);
++
++    len = a->length;
++
++    if (len > 0) {
++        if (a->flags & ASN1_STRING_FLAG_BITS_LEFT) {
++            bits = (int)a->flags & 0x07;
++        } else {
++            for (; len > 0; len--) {
++                if (a->data[len - 1])
++                    break;
++            }
++            j = a->data[len - 1];
++            if (j & 0x01)
++                bits = 0;
++            else if (j & 0x02)
++                bits = 1;
++            else if (j & 0x04)
++                bits = 2;
++            else if (j & 0x08)
++                bits = 3;
++            else if (j & 0x10)
++                bits = 4;
++            else if (j & 0x20)
++                bits = 5;
++            else if (j & 0x40)
++                bits = 6;
++            else if (j & 0x80)
++                bits = 7;
++            else
++                bits = 0;       /* should not happen */
++        }
++    } else
++        bits = 0;
++
++    ret = 1 + len;
++    if (pp == NULL)
++        return (ret);
++
++    p = *pp;
++
++    *(p++) = (unsigned char)bits;
++    d = a->data;
++    if (len > 0) {
++        memcpy(p, d, len);
++        p += len;
++        p[-1] &= (0xff << bits);
++    }
++    *pp = p;
++    return (ret);
++}
++
++ASN1_BIT_STRING *c2i_ASN1_BIT_STRING(ASN1_BIT_STRING **a,
++                                     const unsigned char **pp, long len)
++{
++    ASN1_BIT_STRING *ret = NULL;
++    const unsigned char *p;
++    unsigned char *s;
++    int i;
++
++    if (len < 1) {
++        i = ASN1_R_STRING_TOO_SHORT;
++        goto err;
++    }
++
++    if ((a == NULL) || ((*a) == NULL)) {
++        if ((ret = ASN1_BIT_STRING_new()) == NULL)
++            return (NULL);
++    } else
++        ret = (*a);
++
++    p = *pp;
++    i = *(p++);
++    if (i > 7) {
++        i = ASN1_R_INVALID_BIT_STRING_BITS_LEFT;
++        goto err;
++    }
++    /*
++     * We do this to preserve the settings.  If we modify the settings, via
++     * the _set_bit function, we will recalculate on output
++     */
++    ret->flags &= ~(ASN1_STRING_FLAG_BITS_LEFT | 0x07); /* clear */
++    ret->flags |= (ASN1_STRING_FLAG_BITS_LEFT | i); /* set */
++
++    if (len-- > 1) {            /* using one because of the bits left byte */
++        s = OPENSSL_malloc((int)len);
++        if (s == NULL) {
++            i = ERR_R_MALLOC_FAILURE;
++            goto err;
++        }
++        memcpy(s, p, (int)len);
++        s[len - 1] &= (0xff << i);
++        p += len;
++    } else
++        s = NULL;
++
++    ret->length = (int)len;
++    OPENSSL_free(ret->data);
++    ret->data = s;
++    ret->type = V_ASN1_BIT_STRING;
++    if (a != NULL)
++        (*a) = ret;
++    *pp = p;
++    return (ret);
++ err:
++    ASN1err(ASN1_F_C2I_ASN1_BIT_STRING, i);
++    if ((a == NULL) || (*a != ret))
++        ASN1_BIT_STRING_free(ret);
++    return (NULL);
++}
++
++/*
++ * These next 2 functions from Goetz Babin-Ebell 
++ */
++int ASN1_BIT_STRING_set_bit(ASN1_BIT_STRING *a, int n, int value)
++{
++    int w, v, iv;
++    unsigned char *c;
++
++    w = n / 8;
++    v = 1 << (7 - (n & 0x07));
++    iv = ~v;
++    if (!value)
++        v = 0;
++
++    if (a == NULL)
++        return 0;
++
++    a->flags &= ~(ASN1_STRING_FLAG_BITS_LEFT | 0x07); /* clear, set on write */
++
++    if ((a->length < (w + 1)) || (a->data == NULL)) {
++        if (!value)
++            return (1);         /* Don't need to set */
++        c = OPENSSL_clear_realloc(a->data, a->length, w + 1);
++        if (c == NULL) {
++            ASN1err(ASN1_F_ASN1_BIT_STRING_SET_BIT, ERR_R_MALLOC_FAILURE);
++            return 0;
++        }
++        if (w + 1 - a->length > 0)
++            memset(c + a->length, 0, w + 1 - a->length);
++        a->data = c;
++        a->length = w + 1;
++    }
++    a->data[w] = ((a->data[w]) & iv) | v;
++    while ((a->length > 0) && (a->data[a->length - 1] == 0))
++        a->length--;
++    return (1);
++}
++
++int ASN1_BIT_STRING_get_bit(const ASN1_BIT_STRING *a, int n)
++{
++    int w, v;
++
++    w = n / 8;
++    v = 1 << (7 - (n & 0x07));
++    if ((a == NULL) || (a->length < (w + 1)) || (a->data == NULL))
++        return (0);
++    return ((a->data[w] & v) != 0);
++}
++
++/*
++ * Checks if the given bit string contains only bits specified by
++ * the flags vector. Returns 0 if there is at least one bit set in 'a'
++ * which is not specified in 'flags', 1 otherwise.
++ * 'len' is the length of 'flags'.
++ */
++int ASN1_BIT_STRING_check(const ASN1_BIT_STRING *a,
++                          const unsigned char *flags, int flags_len)
++{
++    int i, ok;
++    /* Check if there is one bit set at all. */
++    if (!a || !a->data)
++        return 1;
++
++    /*
++     * Check each byte of the internal representation of the bit string.
++     */
++    ok = 1;
++    for (i = 0; i < a->length && ok; ++i) {
++        unsigned char mask = i < flags_len ? ~flags[i] : 0xff;
++        /* We are done if there is an unneeded bit set. */
++        ok = (a->data[i] & mask) == 0;
++    }
++    return ok;
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/asn1/a_d2i_fp.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/asn1/a_d2i_fp.c
+new file mode 100644
+index 0000000..e5c1d0e
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/asn1/a_d2i_fp.c
+@@ -0,0 +1,235 @@
++/*
++ * Copyright 1995-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include 
++#include "internal/cryptlib.h"
++#include "internal/numbers.h"
++#include 
++#include 
++
++static int asn1_d2i_read_bio(BIO *in, BUF_MEM **pb);
++
++#ifndef NO_OLD_ASN1
++# ifndef OPENSSL_NO_STDIO
++
++void *ASN1_d2i_fp(void *(*xnew) (void), d2i_of_void *d2i, FILE *in, void **x)
++{
++    BIO *b;
++    void *ret;
++
++    if ((b = BIO_new(BIO_s_file())) == NULL) {
++        ASN1err(ASN1_F_ASN1_D2I_FP, ERR_R_BUF_LIB);
++        return (NULL);
++    }
++    BIO_set_fp(b, in, BIO_NOCLOSE);
++    ret = ASN1_d2i_bio(xnew, d2i, b, x);
++    BIO_free(b);
++    return (ret);
++}
++# endif
++
++void *ASN1_d2i_bio(void *(*xnew) (void), d2i_of_void *d2i, BIO *in, void **x)
++{
++    BUF_MEM *b = NULL;
++    const unsigned char *p;
++    void *ret = NULL;
++    int len;
++
++    len = asn1_d2i_read_bio(in, &b);
++    if (len < 0)
++        goto err;
++
++    p = (unsigned char *)b->data;
++    ret = d2i(x, &p, len);
++ err:
++    BUF_MEM_free(b);
++    return (ret);
++}
++
++#endif
++
++void *ASN1_item_d2i_bio(const ASN1_ITEM *it, BIO *in, void *x)
++{
++    BUF_MEM *b = NULL;
++    const unsigned char *p;
++    void *ret = NULL;
++    int len;
++
++    len = asn1_d2i_read_bio(in, &b);
++    if (len < 0)
++        goto err;
++
++    p = (const unsigned char *)b->data;
++    ret = ASN1_item_d2i(x, &p, len, it);
++ err:
++    BUF_MEM_free(b);
++    return (ret);
++}
++
++#ifndef OPENSSL_NO_STDIO
++void *ASN1_item_d2i_fp(const ASN1_ITEM *it, FILE *in, void *x)
++{
++    BIO *b;
++    char *ret;
++
++    if ((b = BIO_new(BIO_s_file())) == NULL) {
++        ASN1err(ASN1_F_ASN1_ITEM_D2I_FP, ERR_R_BUF_LIB);
++        return (NULL);
++    }
++    BIO_set_fp(b, in, BIO_NOCLOSE);
++    ret = ASN1_item_d2i_bio(it, b, x);
++    BIO_free(b);
++    return (ret);
++}
++#endif
++
++#define HEADER_SIZE   8
++#define ASN1_CHUNK_INITIAL_SIZE (16 * 1024)
++static int asn1_d2i_read_bio(BIO *in, BUF_MEM **pb)
++{
++    BUF_MEM *b;
++    unsigned char *p;
++    int i;
++    size_t want = HEADER_SIZE;
++    uint32_t eos = 0;
++    size_t off = 0;
++    size_t len = 0;
++
++    const unsigned char *q;
++    long slen;
++    int inf, tag, xclass;
++
++    b = BUF_MEM_new();
++    if (b == NULL) {
++        ASN1err(ASN1_F_ASN1_D2I_READ_BIO, ERR_R_MALLOC_FAILURE);
++        return -1;
++    }
++
++    ERR_clear_error();
++    for (;;) {
++        if (want >= (len - off)) {
++            want -= (len - off);
++
++            if (len + want < len || !BUF_MEM_grow_clean(b, len + want)) {
++                ASN1err(ASN1_F_ASN1_D2I_READ_BIO, ERR_R_MALLOC_FAILURE);
++                goto err;
++            }
++            i = BIO_read(in, &(b->data[len]), want);
++            if ((i < 0) && ((len - off) == 0)) {
++                ASN1err(ASN1_F_ASN1_D2I_READ_BIO, ASN1_R_NOT_ENOUGH_DATA);
++                goto err;
++            }
++            if (i > 0) {
++                if (len + i < len) {
++                    ASN1err(ASN1_F_ASN1_D2I_READ_BIO, ASN1_R_TOO_LONG);
++                    goto err;
++                }
++                len += i;
++            }
++        }
++        /* else data already loaded */
++
++        p = (unsigned char *)&(b->data[off]);
++        q = p;
++        inf = ASN1_get_object(&q, &slen, &tag, &xclass, len - off);
++        if (inf & 0x80) {
++            unsigned long e;
++
++            e = ERR_GET_REASON(ERR_peek_error());
++            if (e != ASN1_R_TOO_LONG)
++                goto err;
++            else
++                ERR_clear_error(); /* clear error */
++        }
++        i = q - p;            /* header length */
++        off += i;               /* end of data */
++
++        if (inf & 1) {
++            /* no data body so go round again */
++            if (eos == UINT32_MAX) {
++                ASN1err(ASN1_F_ASN1_D2I_READ_BIO, ASN1_R_HEADER_TOO_LONG);
++                goto err;
++            }
++            eos++;
++            want = HEADER_SIZE;
++        } else if (eos && (slen == 0) && (tag == V_ASN1_EOC)) {
++            /* eos value, so go back and read another header */
++            eos--;
++            if (eos == 0)
++                break;
++            else
++                want = HEADER_SIZE;
++        } else {
++            /* suck in slen bytes of data */
++            want = slen;
++            if (want > (len - off)) {
++                size_t chunk_max = ASN1_CHUNK_INITIAL_SIZE;
++
++                want -= (len - off);
++                if (want > INT_MAX /* BIO_read takes an int length */  ||
++                    len + want < len) {
++                    ASN1err(ASN1_F_ASN1_D2I_READ_BIO, ASN1_R_TOO_LONG);
++                    goto err;
++                }
++                while (want > 0) {
++                    /*
++                     * Read content in chunks of increasing size
++                     * so we can return an error for EOF without
++                     * having to allocate the entire content length
++                     * in one go.
++                     */
++                    size_t chunk = want > chunk_max ? chunk_max : want;
++
++                    if (!BUF_MEM_grow_clean(b, len + chunk)) {
++                        ASN1err(ASN1_F_ASN1_D2I_READ_BIO, ERR_R_MALLOC_FAILURE);
++                        goto err;
++                    }
++                    want -= chunk;
++                    while (chunk > 0) {
++                        i = BIO_read(in, &(b->data[len]), chunk);
++                        if (i <= 0) {
++                            ASN1err(ASN1_F_ASN1_D2I_READ_BIO,
++                                    ASN1_R_NOT_ENOUGH_DATA);
++                            goto err;
++                        }
++                    /*
++                     * This can't overflow because |len+want| didn't
++                     * overflow.
++                     */
++                        len += i;
++                        chunk -= i;
++                    }
++                    if (chunk_max < INT_MAX/2)
++                        chunk_max *= 2;
++                }
++            }
++            if (off + slen < off) {
++                ASN1err(ASN1_F_ASN1_D2I_READ_BIO, ASN1_R_TOO_LONG);
++                goto err;
++            }
++            off += slen;
++            if (eos == 0) {
++                break;
++            } else
++                want = HEADER_SIZE;
++        }
++    }
++
++    if (off > INT_MAX) {
++        ASN1err(ASN1_F_ASN1_D2I_READ_BIO, ASN1_R_TOO_LONG);
++        goto err;
++    }
++
++    *pb = b;
++    return off;
++ err:
++    BUF_MEM_free(b);
++    return -1;
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/asn1/a_digest.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/asn1/a_digest.c
+new file mode 100644
+index 0000000..46bff0d
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/asn1/a_digest.c
+@@ -0,0 +1,66 @@
++/*
++ * Copyright 1995-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include 
++
++#include "internal/cryptlib.h"
++
++#ifndef NO_SYS_TYPES_H
++# include 
++#endif
++
++#include 
++#include 
++#include 
++#include 
++
++#ifndef NO_ASN1_OLD
++
++int ASN1_digest(i2d_of_void *i2d, const EVP_MD *type, char *data,
++                unsigned char *md, unsigned int *len)
++{
++    int i;
++    unsigned char *str, *p;
++
++    i = i2d(data, NULL);
++    if ((str = OPENSSL_malloc(i)) == NULL) {
++        ASN1err(ASN1_F_ASN1_DIGEST, ERR_R_MALLOC_FAILURE);
++        return (0);
++    }
++    p = str;
++    i2d(data, &p);
++
++    if (!EVP_Digest(str, i, md, len, type, NULL)) {
++        OPENSSL_free(str);
++        return 0;
++    }
++    OPENSSL_free(str);
++    return (1);
++}
++
++#endif
++
++int ASN1_item_digest(const ASN1_ITEM *it, const EVP_MD *type, void *asn,
++                     unsigned char *md, unsigned int *len)
++{
++    int i;
++    unsigned char *str = NULL;
++
++    i = ASN1_item_i2d(asn, &str, it);
++    if (!str)
++        return (0);
++
++    if (!EVP_Digest(str, i, md, len, type, NULL)) {
++        OPENSSL_free(str);
++        return 0;
++    }
++    OPENSSL_free(str);
++    return (1);
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/asn1/a_dup.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/asn1/a_dup.c
+new file mode 100644
+index 0000000..d9a57b2
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/asn1/a_dup.c
+@@ -0,0 +1,68 @@
++/*
++ * Copyright 1995-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include "internal/cryptlib.h"
++#include 
++
++#ifndef NO_OLD_ASN1
++
++void *ASN1_dup(i2d_of_void *i2d, d2i_of_void *d2i, void *x)
++{
++    unsigned char *b, *p;
++    const unsigned char *p2;
++    int i;
++    char *ret;
++
++    if (x == NULL)
++        return (NULL);
++
++    i = i2d(x, NULL);
++    b = OPENSSL_malloc(i + 10);
++    if (b == NULL) {
++        ASN1err(ASN1_F_ASN1_DUP, ERR_R_MALLOC_FAILURE);
++        return (NULL);
++    }
++    p = b;
++    i = i2d(x, &p);
++    p2 = b;
++    ret = d2i(NULL, &p2, i);
++    OPENSSL_free(b);
++    return (ret);
++}
++
++#endif
++
++/*
++ * ASN1_ITEM version of dup: this follows the model above except we don't
++ * need to allocate the buffer. At some point this could be rewritten to
++ * directly dup the underlying structure instead of doing and encode and
++ * decode.
++ */
++
++void *ASN1_item_dup(const ASN1_ITEM *it, void *x)
++{
++    unsigned char *b = NULL;
++    const unsigned char *p;
++    long i;
++    void *ret;
++
++    if (x == NULL)
++        return (NULL);
++
++    i = ASN1_item_i2d(x, &b, it);
++    if (b == NULL) {
++        ASN1err(ASN1_F_ASN1_ITEM_DUP, ERR_R_MALLOC_FAILURE);
++        return (NULL);
++    }
++    p = b;
++    ret = ASN1_item_d2i(NULL, &p, i, it);
++    OPENSSL_free(b);
++    return (ret);
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/asn1/a_gentm.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/asn1/a_gentm.c
+new file mode 100644
+index 0000000..c02c8d9
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/asn1/a_gentm.c
+@@ -0,0 +1,273 @@
++/*
++ * Copyright 1995-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++/*
++ * GENERALIZEDTIME implementation. Based on UTCTIME
++ */
++
++#include 
++#include 
++#include "internal/cryptlib.h"
++#include 
++#include "asn1_locl.h"
++
++int asn1_generalizedtime_to_tm(struct tm *tm, const ASN1_GENERALIZEDTIME *d)
++{
++    static const int min[9] = { 0, 0, 1, 1, 0, 0, 0, 0, 0 };
++    static const int max[9] = { 99, 99, 12, 31, 23, 59, 59, 12, 59 };
++    char *a;
++    int n, i, l, o;
++
++    if (d->type != V_ASN1_GENERALIZEDTIME)
++        return (0);
++    l = d->length;
++    a = (char *)d->data;
++    o = 0;
++    /*
++     * GENERALIZEDTIME is similar to UTCTIME except the year is represented
++     * as YYYY. This stuff treats everything as a two digit field so make
++     * first two fields 00 to 99
++     */
++    if (l < 13)
++        goto err;
++    for (i = 0; i < 7; i++) {
++        if ((i == 6) && ((a[o] == 'Z') || (a[o] == '+') || (a[o] == '-'))) {
++            i++;
++            if (tm)
++                tm->tm_sec = 0;
++            break;
++        }
++        if ((a[o] < '0') || (a[o] > '9'))
++            goto err;
++        n = a[o] - '0';
++        if (++o > l)
++            goto err;
++
++        if ((a[o] < '0') || (a[o] > '9'))
++            goto err;
++        n = (n * 10) + a[o] - '0';
++        if (++o > l)
++            goto err;
++
++        if ((n < min[i]) || (n > max[i]))
++            goto err;
++        if (tm) {
++            switch (i) {
++            case 0:
++                tm->tm_year = n * 100 - 1900;
++                break;
++            case 1:
++                tm->tm_year += n;
++                break;
++            case 2:
++                tm->tm_mon = n - 1;
++                break;
++            case 3:
++                tm->tm_mday = n;
++                break;
++            case 4:
++                tm->tm_hour = n;
++                break;
++            case 5:
++                tm->tm_min = n;
++                break;
++            case 6:
++                tm->tm_sec = n;
++                break;
++            }
++        }
++    }
++    /*
++     * Optional fractional seconds: decimal point followed by one or more
++     * digits.
++     */
++    if (a[o] == '.') {
++        if (++o > l)
++            goto err;
++        i = o;
++        while ((a[o] >= '0') && (a[o] <= '9') && (o <= l))
++            o++;
++        /* Must have at least one digit after decimal point */
++        if (i == o)
++            goto err;
++    }
++
++    if (a[o] == 'Z')
++        o++;
++    else if ((a[o] == '+') || (a[o] == '-')) {
++        int offsign = a[o] == '-' ? -1 : 1, offset = 0;
++        o++;
++        if (o + 4 > l)
++            goto err;
++        for (i = 7; i < 9; i++) {
++            if ((a[o] < '0') || (a[o] > '9'))
++                goto err;
++            n = a[o] - '0';
++            o++;
++            if ((a[o] < '0') || (a[o] > '9'))
++                goto err;
++            n = (n * 10) + a[o] - '0';
++            if ((n < min[i]) || (n > max[i]))
++                goto err;
++            if (tm) {
++                if (i == 7)
++                    offset = n * 3600;
++                else if (i == 8)
++                    offset += n * 60;
++            }
++            o++;
++        }
++        if (offset && !OPENSSL_gmtime_adj(tm, 0, offset * offsign))
++            return 0;
++    } else if (a[o]) {
++        /* Missing time zone information. */
++        goto err;
++    }
++    return (o == l);
++ err:
++    return (0);
++}
++
++int ASN1_GENERALIZEDTIME_check(const ASN1_GENERALIZEDTIME *d)
++{
++    return asn1_generalizedtime_to_tm(NULL, d);
++}
++
++int ASN1_GENERALIZEDTIME_set_string(ASN1_GENERALIZEDTIME *s, const char *str)
++{
++    ASN1_GENERALIZEDTIME t;
++
++    t.type = V_ASN1_GENERALIZEDTIME;
++    t.length = strlen(str);
++    t.data = (unsigned char *)str;
++    if (ASN1_GENERALIZEDTIME_check(&t)) {
++        if (s != NULL) {
++            if (!ASN1_STRING_set((ASN1_STRING *)s, str, t.length))
++                return 0;
++            s->type = V_ASN1_GENERALIZEDTIME;
++        }
++        return (1);
++    } else
++        return (0);
++}
++
++ASN1_GENERALIZEDTIME *ASN1_GENERALIZEDTIME_set(ASN1_GENERALIZEDTIME *s,
++                                               time_t t)
++{
++    return ASN1_GENERALIZEDTIME_adj(s, t, 0, 0);
++}
++
++ASN1_GENERALIZEDTIME *ASN1_GENERALIZEDTIME_adj(ASN1_GENERALIZEDTIME *s,
++                                               time_t t, int offset_day,
++                                               long offset_sec)
++{
++    char *p;
++    struct tm *ts;
++    struct tm data;
++    size_t len = 20;
++    ASN1_GENERALIZEDTIME *tmps = NULL;
++
++    if (s == NULL)
++        tmps = ASN1_GENERALIZEDTIME_new();
++    else
++        tmps = s;
++    if (tmps == NULL)
++        return NULL;
++
++    ts = OPENSSL_gmtime(&t, &data);
++    if (ts == NULL)
++        goto err;
++
++    if (offset_day || offset_sec) {
++        if (!OPENSSL_gmtime_adj(ts, offset_day, offset_sec))
++            goto err;
++    }
++
++    p = (char *)tmps->data;
++    if ((p == NULL) || ((size_t)tmps->length < len)) {
++        p = OPENSSL_malloc(len);
++        if (p == NULL) {
++            ASN1err(ASN1_F_ASN1_GENERALIZEDTIME_ADJ, ERR_R_MALLOC_FAILURE);
++            goto err;
++        }
++        OPENSSL_free(tmps->data);
++        tmps->data = (unsigned char *)p;
++    }
++
++    BIO_snprintf(p, len, "%04d%02d%02d%02d%02d%02dZ", ts->tm_year + 1900,
++                 ts->tm_mon + 1, ts->tm_mday, ts->tm_hour, ts->tm_min,
++                 ts->tm_sec);
++    tmps->length = strlen(p);
++    tmps->type = V_ASN1_GENERALIZEDTIME;
++#ifdef CHARSET_EBCDIC_not
++    ebcdic2ascii(tmps->data, tmps->data, tmps->length);
++#endif
++    return tmps;
++ err:
++    if (s == NULL)
++        ASN1_GENERALIZEDTIME_free(tmps);
++    return NULL;
++}
++
++const char *_asn1_mon[12] = {
++    "Jan", "Feb", "Mar", "Apr", "May", "Jun",
++    "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
++};
++
++int ASN1_GENERALIZEDTIME_print(BIO *bp, const ASN1_GENERALIZEDTIME *tm)
++{
++    char *v;
++    int gmt = 0;
++    int i;
++    int y = 0, M = 0, d = 0, h = 0, m = 0, s = 0;
++    char *f = NULL;
++    int f_len = 0;
++
++    i = tm->length;
++    v = (char *)tm->data;
++
++    if (i < 12)
++        goto err;
++    if (v[i - 1] == 'Z')
++        gmt = 1;
++    for (i = 0; i < 12; i++)
++        if ((v[i] > '9') || (v[i] < '0'))
++            goto err;
++    y = (v[0] - '0') * 1000 + (v[1] - '0') * 100
++        + (v[2] - '0') * 10 + (v[3] - '0');
++    M = (v[4] - '0') * 10 + (v[5] - '0');
++    if ((M > 12) || (M < 1))
++        goto err;
++    d = (v[6] - '0') * 10 + (v[7] - '0');
++    h = (v[8] - '0') * 10 + (v[9] - '0');
++    m = (v[10] - '0') * 10 + (v[11] - '0');
++    if (tm->length >= 14 &&
++        (v[12] >= '0') && (v[12] <= '9') &&
++        (v[13] >= '0') && (v[13] <= '9')) {
++        s = (v[12] - '0') * 10 + (v[13] - '0');
++        /* Check for fractions of seconds. */
++        if (tm->length >= 15 && v[14] == '.') {
++            int l = tm->length;
++            f = &v[14];         /* The decimal point. */
++            f_len = 1;
++            while (14 + f_len < l && f[f_len] >= '0' && f[f_len] <= '9')
++                ++f_len;
++        }
++    }
++
++    if (BIO_printf(bp, "%s %2d %02d:%02d:%02d%.*s %d%s",
++                   _asn1_mon[M - 1], d, h, m, s, f_len, f, y,
++                   (gmt) ? " GMT" : "") <= 0)
++        return (0);
++    else
++        return (1);
++ err:
++    BIO_write(bp, "Bad time value", 14);
++    return (0);
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/asn1/a_i2d_fp.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/asn1/a_i2d_fp.c
+new file mode 100644
+index 0000000..1514ede
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/asn1/a_i2d_fp.c
+@@ -0,0 +1,108 @@
++/*
++ * Copyright 1995-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include "internal/cryptlib.h"
++#include 
++#include 
++
++#ifndef NO_OLD_ASN1
++
++# ifndef OPENSSL_NO_STDIO
++int ASN1_i2d_fp(i2d_of_void *i2d, FILE *out, void *x)
++{
++    BIO *b;
++    int ret;
++
++    if ((b = BIO_new(BIO_s_file())) == NULL) {
++        ASN1err(ASN1_F_ASN1_I2D_FP, ERR_R_BUF_LIB);
++        return (0);
++    }
++    BIO_set_fp(b, out, BIO_NOCLOSE);
++    ret = ASN1_i2d_bio(i2d, b, x);
++    BIO_free(b);
++    return (ret);
++}
++# endif
++
++int ASN1_i2d_bio(i2d_of_void *i2d, BIO *out, unsigned char *x)
++{
++    char *b;
++    unsigned char *p;
++    int i, j = 0, n, ret = 1;
++
++    n = i2d(x, NULL);
++    b = OPENSSL_malloc(n);
++    if (b == NULL) {
++        ASN1err(ASN1_F_ASN1_I2D_BIO, ERR_R_MALLOC_FAILURE);
++        return (0);
++    }
++
++    p = (unsigned char *)b;
++    i2d(x, &p);
++
++    for (;;) {
++        i = BIO_write(out, &(b[j]), n);
++        if (i == n)
++            break;
++        if (i <= 0) {
++            ret = 0;
++            break;
++        }
++        j += i;
++        n -= i;
++    }
++    OPENSSL_free(b);
++    return (ret);
++}
++
++#endif
++
++#ifndef OPENSSL_NO_STDIO
++int ASN1_item_i2d_fp(const ASN1_ITEM *it, FILE *out, void *x)
++{
++    BIO *b;
++    int ret;
++
++    if ((b = BIO_new(BIO_s_file())) == NULL) {
++        ASN1err(ASN1_F_ASN1_ITEM_I2D_FP, ERR_R_BUF_LIB);
++        return (0);
++    }
++    BIO_set_fp(b, out, BIO_NOCLOSE);
++    ret = ASN1_item_i2d_bio(it, b, x);
++    BIO_free(b);
++    return (ret);
++}
++#endif
++
++int ASN1_item_i2d_bio(const ASN1_ITEM *it, BIO *out, void *x)
++{
++    unsigned char *b = NULL;
++    int i, j = 0, n, ret = 1;
++
++    n = ASN1_item_i2d(x, &b, it);
++    if (b == NULL) {
++        ASN1err(ASN1_F_ASN1_ITEM_I2D_BIO, ERR_R_MALLOC_FAILURE);
++        return (0);
++    }
++
++    for (;;) {
++        i = BIO_write(out, &(b[j]), n);
++        if (i == n)
++            break;
++        if (i <= 0) {
++            ret = 0;
++            break;
++        }
++        j += i;
++        n -= i;
++    }
++    OPENSSL_free(b);
++    return (ret);
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/asn1/a_int.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/asn1/a_int.c
+new file mode 100644
+index 0000000..e0bcd6e
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/asn1/a_int.c
+@@ -0,0 +1,624 @@
++/*
++ * Copyright 1995-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include "internal/cryptlib.h"
++#include "internal/numbers.h"
++#include 
++#include 
++#include 
++#include "asn1_locl.h"
++
++ASN1_INTEGER *ASN1_INTEGER_dup(const ASN1_INTEGER *x)
++{
++    return ASN1_STRING_dup(x);
++}
++
++int ASN1_INTEGER_cmp(const ASN1_INTEGER *x, const ASN1_INTEGER *y)
++{
++    int neg, ret;
++    /* Compare signs */
++    neg = x->type & V_ASN1_NEG;
++    if (neg != (y->type & V_ASN1_NEG)) {
++        if (neg)
++            return -1;
++        else
++            return 1;
++    }
++
++    ret = ASN1_STRING_cmp(x, y);
++
++    if (neg)
++        return -ret;
++    else
++        return ret;
++}
++
++/*-
++ * This converts a big endian buffer and sign into its content encoding.
++ * This is used for INTEGER and ENUMERATED types.
++ * The internal representation is an ASN1_STRING whose data is a big endian
++ * representation of the value, ignoring the sign. The sign is determined by
++ * the type: if type & V_ASN1_NEG is true it is negative, otherwise positive.
++ *
++ * Positive integers are no problem: they are almost the same as the DER
++ * encoding, except if the first byte is >= 0x80 we need to add a zero pad.
++ *
++ * Negative integers are a bit trickier...
++ * The DER representation of negative integers is in 2s complement form.
++ * The internal form is converted by complementing each octet and finally
++ * adding one to the result. This can be done less messily with a little trick.
++ * If the internal form has trailing zeroes then they will become FF by the
++ * complement and 0 by the add one (due to carry) so just copy as many trailing
++ * zeros to the destination as there are in the source. The carry will add one
++ * to the last none zero octet: so complement this octet and add one and finally
++ * complement any left over until you get to the start of the string.
++ *
++ * Padding is a little trickier too. If the first bytes is > 0x80 then we pad
++ * with 0xff. However if the first byte is 0x80 and one of the following bytes
++ * is non-zero we pad with 0xff. The reason for this distinction is that 0x80
++ * followed by optional zeros isn't padded.
++ */
++
++static size_t i2c_ibuf(const unsigned char *b, size_t blen, int neg,
++                       unsigned char **pp)
++{
++    int pad = 0;
++    size_t ret, i;
++    unsigned char *p, pb = 0;
++    const unsigned char *n;
++
++    if (b == NULL || blen == 0)
++        ret = 1;
++    else {
++        ret = blen;
++        i = b[0];
++        if (ret == 1 && i == 0)
++            neg = 0;
++        if (!neg && (i > 127)) {
++            pad = 1;
++            pb = 0;
++        } else if (neg) {
++            if (i > 128) {
++                pad = 1;
++                pb = 0xFF;
++            } else if (i == 128) {
++                /*
++                 * Special case: if any other bytes non zero we pad:
++                 * otherwise we don't.
++                 */
++                for (i = 1; i < blen; i++)
++                    if (b[i]) {
++                        pad = 1;
++                        pb = 0xFF;
++                        break;
++                    }
++            }
++        }
++        ret += pad;
++    }
++    if (pp == NULL)
++        return ret;
++    p = *pp;
++
++    if (pad)
++        *(p++) = pb;
++    if (b == NULL || blen == 0)
++        *p = 0;
++    else if (!neg)
++        memcpy(p, b, blen);
++    else {
++        /* Begin at the end of the encoding */
++        n = b + blen;
++        p += blen;
++        i = blen;
++        /* Copy zeros to destination as long as source is zero */
++        while (!n[-1] && i > 1) {
++            *(--p) = 0;
++            n--;
++            i--;
++        }
++        /* Complement and increment next octet */
++        *(--p) = ((*(--n)) ^ 0xff) + 1;
++        i--;
++        /* Complement any octets left */
++        for (; i > 0; i--)
++            *(--p) = *(--n) ^ 0xff;
++    }
++
++    *pp += ret;
++    return ret;
++}
++
++/*
++ * convert content octets into a big endian buffer. Returns the length
++ * of buffer or 0 on error: for malformed INTEGER. If output buffer is
++ * NULL just return length.
++ */
++
++static size_t c2i_ibuf(unsigned char *b, int *pneg,
++                       const unsigned char *p, size_t plen)
++{
++    size_t i;
++    int neg, pad;
++    /* Zero content length is illegal */
++    if (plen == 0) {
++        ASN1err(ASN1_F_C2I_IBUF, ASN1_R_ILLEGAL_ZERO_CONTENT);
++        return 0;
++    }
++    neg = p[0] & 0x80;
++    if (pneg)
++        *pneg = neg;
++    /* Handle common case where length is 1 octet separately */
++    if (plen == 1) {
++        if (b) {
++            if (neg)
++                b[0] = (p[0] ^ 0xFF) + 1;
++            else
++                b[0] = p[0];
++        }
++        return 1;
++    }
++    if (p[0] == 0 || p[0] == 0xFF)
++        pad = 1;
++    else
++        pad = 0;
++    /* reject illegal padding: first two octets MSB can't match */
++    if (pad && (neg == (p[1] & 0x80))) {
++        ASN1err(ASN1_F_C2I_IBUF, ASN1_R_ILLEGAL_PADDING);
++        return 0;
++    }
++    /* If positive just copy across */
++    if (neg == 0) {
++        if (b)
++            memcpy(b, p + pad, plen - pad);
++        return plen - pad;
++    }
++
++    if (neg && pad) {
++        /* check is any following octets are non zero */
++        for (i = 1; i < plen; i++) {
++            if (p[i] != 0)
++                break;
++        }
++        /* if all bytes are zero handle as special case */
++        if (i == plen) {
++            if (b) {
++                b[0] = 1;
++                memset(b + 1, 0, plen - 1);
++            }
++            return plen;
++        }
++    }
++
++    plen -= pad;
++    /* Must be negative: calculate twos complement */
++    if (b) {
++        const unsigned char *from = p + plen - 1 + pad;
++        unsigned char *to = b + plen;
++        i = plen;
++        while (*from == 0 && i) {
++            *--to = 0;
++            i--;
++            from--;
++        }
++        *--to = (*from-- ^ 0xff) + 1;
++        OPENSSL_assert(i != 0);
++        i--;
++        for (; i > 0; i--)
++            *--to = *from-- ^ 0xff;
++    }
++    return plen;
++}
++
++int i2c_ASN1_INTEGER(ASN1_INTEGER *a, unsigned char **pp)
++{
++    return i2c_ibuf(a->data, a->length, a->type & V_ASN1_NEG, pp);
++}
++
++/* Convert big endian buffer into uint64_t, return 0 on error */
++static int asn1_get_uint64(uint64_t *pr, const unsigned char *b, size_t blen)
++{
++    size_t i;
++    if (blen > sizeof(*pr)) {
++        ASN1err(ASN1_F_ASN1_GET_UINT64, ASN1_R_TOO_LARGE);
++        return 0;
++    }
++    *pr = 0;
++    if (b == NULL)
++        return 0;
++    for (i = 0; i < blen; i++) {
++        *pr <<= 8;
++        *pr |= b[i];
++    }
++    return 1;
++}
++
++static size_t asn1_put_uint64(unsigned char *b, uint64_t r)
++{
++    if (r >= 0x100) {
++        unsigned char *p;
++        uint64_t rtmp = r;
++        size_t i = 0;
++
++        /* Work out how many bytes we need */
++        while (rtmp) {
++            rtmp >>= 8;
++            i++;
++        }
++
++        /* Copy from end to beginning */
++        p = b + i - 1;
++
++        do {
++            *p-- = r & 0xFF;
++            r >>= 8;
++        } while (p >= b);
++
++        return i;
++    }
++
++    b[0] = (unsigned char)r;
++    return 1;
++
++}
++
++/*
++ * Absolute value of INT64_MIN: we can't just use -INT64_MIN as it produces
++ * overflow warnings.
++ */
++
++#define ABS_INT64_MIN \
++    ((uint64_t)INT64_MAX + (uint64_t)(-(INT64_MIN + INT64_MAX)))
++
++/* signed version of asn1_get_uint64 */
++static int asn1_get_int64(int64_t *pr, const unsigned char *b, size_t blen,
++                          int neg)
++{
++    uint64_t r;
++    if (asn1_get_uint64(&r, b, blen) == 0)
++        return 0;
++    if (neg) {
++        if (r > ABS_INT64_MIN) {
++            ASN1err(ASN1_F_ASN1_GET_INT64, ASN1_R_TOO_SMALL);
++            return 0;
++        }
++        *pr = 0 - (uint64_t)r;
++    } else {
++        if (r > INT64_MAX) {
++            ASN1err(ASN1_F_ASN1_GET_INT64, ASN1_R_TOO_LARGE);
++            return 0;
++        }
++        *pr = (int64_t)r;
++    }
++    return 1;
++}
++
++/* Convert ASN1 INTEGER content octets to ASN1_INTEGER structure */
++ASN1_INTEGER *c2i_ASN1_INTEGER(ASN1_INTEGER **a, const unsigned char **pp,
++                               long len)
++{
++    ASN1_INTEGER *ret = NULL;
++    size_t r;
++    int neg;
++
++    r = c2i_ibuf(NULL, NULL, *pp, len);
++
++    if (r == 0)
++        return NULL;
++
++    if ((a == NULL) || ((*a) == NULL)) {
++        ret = ASN1_INTEGER_new();
++        if (ret == NULL)
++            return NULL;
++        ret->type = V_ASN1_INTEGER;
++    } else
++        ret = *a;
++
++    if (ASN1_STRING_set(ret, NULL, r) == 0)
++        goto err;
++
++    c2i_ibuf(ret->data, &neg, *pp, len);
++
++    if (neg)
++        ret->type |= V_ASN1_NEG;
++
++    *pp += len;
++    if (a != NULL)
++        (*a) = ret;
++    return ret;
++ err:
++    ASN1err(ASN1_F_C2I_ASN1_INTEGER, ERR_R_MALLOC_FAILURE);
++    if ((a == NULL) || (*a != ret))
++        ASN1_INTEGER_free(ret);
++    return NULL;
++}
++
++static int asn1_string_get_int64(int64_t *pr, const ASN1_STRING *a, int itype)
++{
++    if (a == NULL) {
++        ASN1err(ASN1_F_ASN1_STRING_GET_INT64, ERR_R_PASSED_NULL_PARAMETER);
++        return 0;
++    }
++    if ((a->type & ~V_ASN1_NEG) != itype) {
++        ASN1err(ASN1_F_ASN1_STRING_GET_INT64, ASN1_R_WRONG_INTEGER_TYPE);
++        return 0;
++    }
++    return asn1_get_int64(pr, a->data, a->length, a->type & V_ASN1_NEG);
++}
++
++static int asn1_string_set_int64(ASN1_STRING *a, int64_t r, int itype)
++{
++    unsigned char tbuf[sizeof(r)];
++    size_t l;
++    a->type = itype;
++    if (r < 0) {
++        l = asn1_put_uint64(tbuf, -r);
++        a->type |= V_ASN1_NEG;
++    } else {
++        l = asn1_put_uint64(tbuf, r);
++        a->type &= ~V_ASN1_NEG;
++    }
++    if (l == 0)
++        return 0;
++    return ASN1_STRING_set(a, tbuf, l);
++}
++
++static int asn1_string_get_uint64(uint64_t *pr, const ASN1_STRING *a,
++                                  int itype)
++{
++    if (a == NULL) {
++        ASN1err(ASN1_F_ASN1_STRING_GET_UINT64, ERR_R_PASSED_NULL_PARAMETER);
++        return 0;
++    }
++    if ((a->type & ~V_ASN1_NEG) != itype) {
++        ASN1err(ASN1_F_ASN1_STRING_GET_UINT64, ASN1_R_WRONG_INTEGER_TYPE);
++        return 0;
++    }
++    if (a->type & V_ASN1_NEG) {
++        ASN1err(ASN1_F_ASN1_STRING_GET_UINT64, ASN1_R_ILLEGAL_NEGATIVE_VALUE);
++        return 0;
++    }
++    return asn1_get_uint64(pr, a->data, a->length);
++}
++
++static int asn1_string_set_uint64(ASN1_STRING *a, uint64_t r, int itype)
++{
++    unsigned char tbuf[sizeof(r)];
++    size_t l;
++    a->type = itype;
++    l = asn1_put_uint64(tbuf, r);
++    if (l == 0)
++        return 0;
++    return ASN1_STRING_set(a, tbuf, l);
++}
++
++/*
++ * This is a version of d2i_ASN1_INTEGER that ignores the sign bit of ASN1
++ * integers: some broken software can encode a positive INTEGER with its MSB
++ * set as negative (it doesn't add a padding zero).
++ */
++
++ASN1_INTEGER *d2i_ASN1_UINTEGER(ASN1_INTEGER **a, const unsigned char **pp,
++                                long length)
++{
++    ASN1_INTEGER *ret = NULL;
++    const unsigned char *p;
++    unsigned char *s;
++    long len;
++    int inf, tag, xclass;
++    int i;
++
++    if ((a == NULL) || ((*a) == NULL)) {
++        if ((ret = ASN1_INTEGER_new()) == NULL)
++            return (NULL);
++        ret->type = V_ASN1_INTEGER;
++    } else
++        ret = (*a);
++
++    p = *pp;
++    inf = ASN1_get_object(&p, &len, &tag, &xclass, length);
++    if (inf & 0x80) {
++        i = ASN1_R_BAD_OBJECT_HEADER;
++        goto err;
++    }
++
++    if (tag != V_ASN1_INTEGER) {
++        i = ASN1_R_EXPECTING_AN_INTEGER;
++        goto err;
++    }
++
++    /*
++     * We must OPENSSL_malloc stuff, even for 0 bytes otherwise it signifies
++     * a missing NULL parameter.
++     */
++    s = OPENSSL_malloc((int)len + 1);
++    if (s == NULL) {
++        i = ERR_R_MALLOC_FAILURE;
++        goto err;
++    }
++    ret->type = V_ASN1_INTEGER;
++    if (len) {
++        if ((*p == 0) && (len != 1)) {
++            p++;
++            len--;
++        }
++        memcpy(s, p, (int)len);
++        p += len;
++    }
++
++    OPENSSL_free(ret->data);
++    ret->data = s;
++    ret->length = (int)len;
++    if (a != NULL)
++        (*a) = ret;
++    *pp = p;
++    return (ret);
++ err:
++    ASN1err(ASN1_F_D2I_ASN1_UINTEGER, i);
++    if ((a == NULL) || (*a != ret))
++        ASN1_INTEGER_free(ret);
++    return (NULL);
++}
++
++static ASN1_STRING *bn_to_asn1_string(const BIGNUM *bn, ASN1_STRING *ai,
++                                      int atype)
++{
++    ASN1_INTEGER *ret;
++    int len;
++
++    if (ai == NULL) {
++        ret = ASN1_STRING_type_new(atype);
++    } else {
++        ret = ai;
++        ret->type = atype;
++    }
++
++    if (ret == NULL) {
++        ASN1err(ASN1_F_BN_TO_ASN1_STRING, ERR_R_NESTED_ASN1_ERROR);
++        goto err;
++    }
++
++    if (BN_is_negative(bn) && !BN_is_zero(bn))
++        ret->type |= V_ASN1_NEG_INTEGER;
++
++    len = BN_num_bytes(bn);
++
++    if (len == 0)
++        len = 1;
++
++    if (ASN1_STRING_set(ret, NULL, len) == 0) {
++        ASN1err(ASN1_F_BN_TO_ASN1_STRING, ERR_R_MALLOC_FAILURE);
++        goto err;
++    }
++
++    /* Correct zero case */
++    if (BN_is_zero(bn))
++        ret->data[0] = 0;
++    else
++        len = BN_bn2bin(bn, ret->data);
++    ret->length = len;
++    return ret;
++ err:
++    if (ret != ai)
++        ASN1_INTEGER_free(ret);
++    return (NULL);
++}
++
++static BIGNUM *asn1_string_to_bn(const ASN1_INTEGER *ai, BIGNUM *bn,
++                                 int itype)
++{
++    BIGNUM *ret;
++
++    if ((ai->type & ~V_ASN1_NEG) != itype) {
++        ASN1err(ASN1_F_ASN1_STRING_TO_BN, ASN1_R_WRONG_INTEGER_TYPE);
++        return NULL;
++    }
++
++    ret = BN_bin2bn(ai->data, ai->length, bn);
++    if (ret == 0) {
++        ASN1err(ASN1_F_ASN1_STRING_TO_BN, ASN1_R_BN_LIB);
++        return NULL;
++    }
++    if (ai->type & V_ASN1_NEG)
++        BN_set_negative(ret, 1);
++    return ret;
++}
++
++int ASN1_INTEGER_get_int64(int64_t *pr, const ASN1_INTEGER *a)
++{
++    return asn1_string_get_int64(pr, a, V_ASN1_INTEGER);
++}
++
++int ASN1_INTEGER_set_int64(ASN1_INTEGER *a, int64_t r)
++{
++    return asn1_string_set_int64(a, r, V_ASN1_INTEGER);
++}
++
++int ASN1_INTEGER_get_uint64(uint64_t *pr, const ASN1_INTEGER *a)
++{
++    return asn1_string_get_uint64(pr, a, V_ASN1_INTEGER);
++}
++
++int ASN1_INTEGER_set_uint64(ASN1_INTEGER *a, uint64_t r)
++{
++    return asn1_string_set_uint64(a, r, V_ASN1_INTEGER);
++}
++
++int ASN1_INTEGER_set(ASN1_INTEGER *a, long v)
++{
++    return ASN1_INTEGER_set_int64(a, v);
++}
++
++long ASN1_INTEGER_get(const ASN1_INTEGER *a)
++{
++    int i;
++    int64_t r;
++    if (a == NULL)
++        return 0;
++    i = ASN1_INTEGER_get_int64(&r, a);
++    if (i == 0)
++        return -1;
++    if (r > LONG_MAX || r < LONG_MIN)
++        return -1;
++    return (long)r;
++}
++
++ASN1_INTEGER *BN_to_ASN1_INTEGER(const BIGNUM *bn, ASN1_INTEGER *ai)
++{
++    return bn_to_asn1_string(bn, ai, V_ASN1_INTEGER);
++}
++
++BIGNUM *ASN1_INTEGER_to_BN(const ASN1_INTEGER *ai, BIGNUM *bn)
++{
++    return asn1_string_to_bn(ai, bn, V_ASN1_INTEGER);
++}
++
++int ASN1_ENUMERATED_get_int64(int64_t *pr, const ASN1_ENUMERATED *a)
++{
++    return asn1_string_get_int64(pr, a, V_ASN1_ENUMERATED);
++}
++
++int ASN1_ENUMERATED_set_int64(ASN1_ENUMERATED *a, int64_t r)
++{
++    return asn1_string_set_int64(a, r, V_ASN1_ENUMERATED);
++}
++
++int ASN1_ENUMERATED_set(ASN1_ENUMERATED *a, long v)
++{
++    return ASN1_ENUMERATED_set_int64(a, v);
++}
++
++long ASN1_ENUMERATED_get(const ASN1_ENUMERATED *a)
++{
++    int i;
++    int64_t r;
++    if (a == NULL)
++        return 0;
++    if ((a->type & ~V_ASN1_NEG) != V_ASN1_ENUMERATED)
++        return -1;
++    if (a->length > (int)sizeof(long))
++        return 0xffffffffL;
++    i = ASN1_ENUMERATED_get_int64(&r, a);
++    if (i == 0)
++        return -1;
++    if (r > LONG_MAX || r < LONG_MIN)
++        return -1;
++    return (long)r;
++}
++
++ASN1_ENUMERATED *BN_to_ASN1_ENUMERATED(const BIGNUM *bn, ASN1_ENUMERATED *ai)
++{
++    return bn_to_asn1_string(bn, ai, V_ASN1_ENUMERATED);
++}
++
++BIGNUM *ASN1_ENUMERATED_to_BN(const ASN1_ENUMERATED *ai, BIGNUM *bn)
++{
++    return asn1_string_to_bn(ai, bn, V_ASN1_ENUMERATED);
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/asn1/a_mbstr.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/asn1/a_mbstr.c
+new file mode 100644
+index 0000000..5578e92
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/asn1/a_mbstr.c
+@@ -0,0 +1,395 @@
++/*
++ * Copyright 1999-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include 
++#include "internal/cryptlib.h"
++#include 
++
++static int traverse_string(const unsigned char *p, int len, int inform,
++                           int (*rfunc) (unsigned long value, void *in),
++                           void *arg);
++static int in_utf8(unsigned long value, void *arg);
++static int out_utf8(unsigned long value, void *arg);
++static int type_str(unsigned long value, void *arg);
++static int cpy_asc(unsigned long value, void *arg);
++static int cpy_bmp(unsigned long value, void *arg);
++static int cpy_univ(unsigned long value, void *arg);
++static int cpy_utf8(unsigned long value, void *arg);
++static int is_numeric(unsigned long value);
++static int is_printable(unsigned long value);
++
++/*
++ * These functions take a string in UTF8, ASCII or multibyte form and a mask
++ * of permissible ASN1 string types. It then works out the minimal type
++ * (using the order Numeric < Printable < IA5 < T61 < BMP < Universal < UTF8)
++ * and creates a string of the correct type with the supplied data. Yes this is
++ * horrible: it has to be :-( The 'ncopy' form checks minimum and maximum
++ * size limits too.
++ */
++
++int ASN1_mbstring_copy(ASN1_STRING **out, const unsigned char *in, int len,
++                       int inform, unsigned long mask)
++{
++    return ASN1_mbstring_ncopy(out, in, len, inform, mask, 0, 0);
++}
++
++int ASN1_mbstring_ncopy(ASN1_STRING **out, const unsigned char *in, int len,
++                        int inform, unsigned long mask,
++                        long minsize, long maxsize)
++{
++    int str_type;
++    int ret;
++    char free_out;
++    int outform, outlen = 0;
++    ASN1_STRING *dest;
++    unsigned char *p;
++    int nchar;
++    char strbuf[32];
++    int (*cpyfunc) (unsigned long, void *) = NULL;
++    if (len == -1)
++        len = strlen((const char *)in);
++    if (!mask)
++        mask = DIRSTRING_TYPE;
++
++    /* First do a string check and work out the number of characters */
++    switch (inform) {
++
++    case MBSTRING_BMP:
++        if (len & 1) {
++            ASN1err(ASN1_F_ASN1_MBSTRING_NCOPY,
++                    ASN1_R_INVALID_BMPSTRING_LENGTH);
++            return -1;
++        }
++        nchar = len >> 1;
++        break;
++
++    case MBSTRING_UNIV:
++        if (len & 3) {
++            ASN1err(ASN1_F_ASN1_MBSTRING_NCOPY,
++                    ASN1_R_INVALID_UNIVERSALSTRING_LENGTH);
++            return -1;
++        }
++        nchar = len >> 2;
++        break;
++
++    case MBSTRING_UTF8:
++        nchar = 0;
++        /* This counts the characters and does utf8 syntax checking */
++        ret = traverse_string(in, len, MBSTRING_UTF8, in_utf8, &nchar);
++        if (ret < 0) {
++            ASN1err(ASN1_F_ASN1_MBSTRING_NCOPY, ASN1_R_INVALID_UTF8STRING);
++            return -1;
++        }
++        break;
++
++    case MBSTRING_ASC:
++        nchar = len;
++        break;
++
++    default:
++        ASN1err(ASN1_F_ASN1_MBSTRING_NCOPY, ASN1_R_UNKNOWN_FORMAT);
++        return -1;
++    }
++
++    if ((minsize > 0) && (nchar < minsize)) {
++        ASN1err(ASN1_F_ASN1_MBSTRING_NCOPY, ASN1_R_STRING_TOO_SHORT);
++        BIO_snprintf(strbuf, sizeof strbuf, "%ld", minsize);
++        ERR_add_error_data(2, "minsize=", strbuf);
++        return -1;
++    }
++
++    if ((maxsize > 0) && (nchar > maxsize)) {
++        ASN1err(ASN1_F_ASN1_MBSTRING_NCOPY, ASN1_R_STRING_TOO_LONG);
++        BIO_snprintf(strbuf, sizeof strbuf, "%ld", maxsize);
++        ERR_add_error_data(2, "maxsize=", strbuf);
++        return -1;
++    }
++
++    /* Now work out minimal type (if any) */
++    if (traverse_string(in, len, inform, type_str, &mask) < 0) {
++        ASN1err(ASN1_F_ASN1_MBSTRING_NCOPY, ASN1_R_ILLEGAL_CHARACTERS);
++        return -1;
++    }
++
++    /* Now work out output format and string type */
++    outform = MBSTRING_ASC;
++    if (mask & B_ASN1_NUMERICSTRING)
++        str_type = V_ASN1_NUMERICSTRING;
++    else if (mask & B_ASN1_PRINTABLESTRING)
++        str_type = V_ASN1_PRINTABLESTRING;
++    else if (mask & B_ASN1_IA5STRING)
++        str_type = V_ASN1_IA5STRING;
++    else if (mask & B_ASN1_T61STRING)
++        str_type = V_ASN1_T61STRING;
++    else if (mask & B_ASN1_BMPSTRING) {
++        str_type = V_ASN1_BMPSTRING;
++        outform = MBSTRING_BMP;
++    } else if (mask & B_ASN1_UNIVERSALSTRING) {
++        str_type = V_ASN1_UNIVERSALSTRING;
++        outform = MBSTRING_UNIV;
++    } else {
++        str_type = V_ASN1_UTF8STRING;
++        outform = MBSTRING_UTF8;
++    }
++    if (!out)
++        return str_type;
++    if (*out) {
++        free_out = 0;
++        dest = *out;
++        OPENSSL_free(dest->data);
++        dest->data = NULL;
++        dest->length = 0;
++        dest->type = str_type;
++    } else {
++        free_out = 1;
++        dest = ASN1_STRING_type_new(str_type);
++        if (dest == NULL) {
++            ASN1err(ASN1_F_ASN1_MBSTRING_NCOPY, ERR_R_MALLOC_FAILURE);
++            return -1;
++        }
++        *out = dest;
++    }
++    /* If both the same type just copy across */
++    if (inform == outform) {
++        if (!ASN1_STRING_set(dest, in, len)) {
++            ASN1err(ASN1_F_ASN1_MBSTRING_NCOPY, ERR_R_MALLOC_FAILURE);
++            return -1;
++        }
++        return str_type;
++    }
++
++    /* Work out how much space the destination will need */
++    switch (outform) {
++    case MBSTRING_ASC:
++        outlen = nchar;
++        cpyfunc = cpy_asc;
++        break;
++
++    case MBSTRING_BMP:
++        outlen = nchar << 1;
++        cpyfunc = cpy_bmp;
++        break;
++
++    case MBSTRING_UNIV:
++        outlen = nchar << 2;
++        cpyfunc = cpy_univ;
++        break;
++
++    case MBSTRING_UTF8:
++        outlen = 0;
++        traverse_string(in, len, inform, out_utf8, &outlen);
++        cpyfunc = cpy_utf8;
++        break;
++    }
++    if ((p = OPENSSL_malloc(outlen + 1)) == NULL) {
++        if (free_out)
++            ASN1_STRING_free(dest);
++        ASN1err(ASN1_F_ASN1_MBSTRING_NCOPY, ERR_R_MALLOC_FAILURE);
++        return -1;
++    }
++    dest->length = outlen;
++    dest->data = p;
++    p[outlen] = 0;
++    traverse_string(in, len, inform, cpyfunc, &p);
++    return str_type;
++}
++
++/*
++ * This function traverses a string and passes the value of each character to
++ * an optional function along with a void * argument.
++ */
++
++static int traverse_string(const unsigned char *p, int len, int inform,
++                           int (*rfunc) (unsigned long value, void *in),
++                           void *arg)
++{
++    unsigned long value;
++    int ret;
++    while (len) {
++        if (inform == MBSTRING_ASC) {
++            value = *p++;
++            len--;
++        } else if (inform == MBSTRING_BMP) {
++            value = *p++ << 8;
++            value |= *p++;
++            len -= 2;
++        } else if (inform == MBSTRING_UNIV) {
++            value = ((unsigned long)*p++) << 24;
++            value |= ((unsigned long)*p++) << 16;
++            value |= *p++ << 8;
++            value |= *p++;
++            len -= 4;
++        } else {
++            ret = UTF8_getc(p, len, &value);
++            if (ret < 0)
++                return -1;
++            len -= ret;
++            p += ret;
++        }
++        if (rfunc) {
++            ret = rfunc(value, arg);
++            if (ret <= 0)
++                return ret;
++        }
++    }
++    return 1;
++}
++
++/* Various utility functions for traverse_string */
++
++/* Just count number of characters */
++
++static int in_utf8(unsigned long value, void *arg)
++{
++    int *nchar;
++    nchar = arg;
++    (*nchar)++;
++    return 1;
++}
++
++/* Determine size of output as a UTF8 String */
++
++static int out_utf8(unsigned long value, void *arg)
++{
++    int *outlen;
++    outlen = arg;
++    *outlen += UTF8_putc(NULL, -1, value);
++    return 1;
++}
++
++/*
++ * Determine the "type" of a string: check each character against a supplied
++ * "mask".
++ */
++
++static int type_str(unsigned long value, void *arg)
++{
++    unsigned long types;
++    types = *((unsigned long *)arg);
++    if ((types & B_ASN1_NUMERICSTRING) && !is_numeric(value))
++        types &= ~B_ASN1_NUMERICSTRING;
++    if ((types & B_ASN1_PRINTABLESTRING) && !is_printable(value))
++        types &= ~B_ASN1_PRINTABLESTRING;
++    if ((types & B_ASN1_IA5STRING) && (value > 127))
++        types &= ~B_ASN1_IA5STRING;
++    if ((types & B_ASN1_T61STRING) && (value > 0xff))
++        types &= ~B_ASN1_T61STRING;
++    if ((types & B_ASN1_BMPSTRING) && (value > 0xffff))
++        types &= ~B_ASN1_BMPSTRING;
++    if (!types)
++        return -1;
++    *((unsigned long *)arg) = types;
++    return 1;
++}
++
++/* Copy one byte per character ASCII like strings */
++
++static int cpy_asc(unsigned long value, void *arg)
++{
++    unsigned char **p, *q;
++    p = arg;
++    q = *p;
++    *q = (unsigned char)value;
++    (*p)++;
++    return 1;
++}
++
++/* Copy two byte per character BMPStrings */
++
++static int cpy_bmp(unsigned long value, void *arg)
++{
++    unsigned char **p, *q;
++    p = arg;
++    q = *p;
++    *q++ = (unsigned char)((value >> 8) & 0xff);
++    *q = (unsigned char)(value & 0xff);
++    *p += 2;
++    return 1;
++}
++
++/* Copy four byte per character UniversalStrings */
++
++static int cpy_univ(unsigned long value, void *arg)
++{
++    unsigned char **p, *q;
++    p = arg;
++    q = *p;
++    *q++ = (unsigned char)((value >> 24) & 0xff);
++    *q++ = (unsigned char)((value >> 16) & 0xff);
++    *q++ = (unsigned char)((value >> 8) & 0xff);
++    *q = (unsigned char)(value & 0xff);
++    *p += 4;
++    return 1;
++}
++
++/* Copy to a UTF8String */
++
++static int cpy_utf8(unsigned long value, void *arg)
++{
++    unsigned char **p;
++    int ret;
++    p = arg;
++    /* We already know there is enough room so pass 0xff as the length */
++    ret = UTF8_putc(*p, 0xff, value);
++    *p += ret;
++    return 1;
++}
++
++/* Return 1 if the character is permitted in a PrintableString */
++static int is_printable(unsigned long value)
++{
++    int ch;
++    if (value > 0x7f)
++        return 0;
++    ch = (int)value;
++    /*
++     * Note: we can't use 'isalnum' because certain accented characters may
++     * count as alphanumeric in some environments.
++     */
++#ifndef CHARSET_EBCDIC
++    if ((ch >= 'a') && (ch <= 'z'))
++        return 1;
++    if ((ch >= 'A') && (ch <= 'Z'))
++        return 1;
++    if ((ch >= '0') && (ch <= '9'))
++        return 1;
++    if ((ch == ' ') || strchr("'()+,-./:=?", ch))
++        return 1;
++#else                           /* CHARSET_EBCDIC */
++    if ((ch >= os_toascii['a']) && (ch <= os_toascii['z']))
++        return 1;
++    if ((ch >= os_toascii['A']) && (ch <= os_toascii['Z']))
++        return 1;
++    if ((ch >= os_toascii['0']) && (ch <= os_toascii['9']))
++        return 1;
++    if ((ch == os_toascii[' ']) || strchr("'()+,-./:=?", os_toebcdic[ch]))
++        return 1;
++#endif                          /* CHARSET_EBCDIC */
++    return 0;
++}
++
++/* Return 1 if the character is a digit or space */
++static int is_numeric(unsigned long value)
++{
++    int ch;
++    if (value > 0x7f)
++        return 0;
++    ch = (int)value;
++#ifndef CHARSET_EBCDIC
++    if (!isdigit(ch) && ch != ' ')
++        return 0;
++#else
++    if (ch > os_toascii['9'])
++        return 0;
++    if (ch < os_toascii['0'] && ch != os_toascii[' '])
++        return 0;
++#endif
++    return 1;
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/asn1/a_object.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/asn1/a_object.c
+new file mode 100644
+index 0000000..79f0ecd
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/asn1/a_object.c
+@@ -0,0 +1,370 @@
++/*
++ * Copyright 1995-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include 
++#include "internal/cryptlib.h"
++#include 
++#include 
++#include 
++#include 
++#include "internal/asn1_int.h"
++#include "asn1_locl.h"
++
++int i2d_ASN1_OBJECT(const ASN1_OBJECT *a, unsigned char **pp)
++{
++    unsigned char *p;
++    int objsize;
++
++    if ((a == NULL) || (a->data == NULL))
++        return (0);
++
++    objsize = ASN1_object_size(0, a->length, V_ASN1_OBJECT);
++    if (pp == NULL || objsize == -1)
++        return objsize;
++
++    p = *pp;
++    ASN1_put_object(&p, 0, a->length, V_ASN1_OBJECT, V_ASN1_UNIVERSAL);
++    memcpy(p, a->data, a->length);
++    p += a->length;
++
++    *pp = p;
++    return (objsize);
++}
++
++int a2d_ASN1_OBJECT(unsigned char *out, int olen, const char *buf, int num)
++{
++    int i, first, len = 0, c, use_bn;
++    char ftmp[24], *tmp = ftmp;
++    int tmpsize = sizeof ftmp;
++    const char *p;
++    unsigned long l;
++    BIGNUM *bl = NULL;
++
++    if (num == 0)
++        return (0);
++    else if (num == -1)
++        num = strlen(buf);
++
++    p = buf;
++    c = *(p++);
++    num--;
++    if ((c >= '0') && (c <= '2')) {
++        first = c - '0';
++    } else {
++        ASN1err(ASN1_F_A2D_ASN1_OBJECT, ASN1_R_FIRST_NUM_TOO_LARGE);
++        goto err;
++    }
++
++    if (num <= 0) {
++        ASN1err(ASN1_F_A2D_ASN1_OBJECT, ASN1_R_MISSING_SECOND_NUMBER);
++        goto err;
++    }
++    c = *(p++);
++    num--;
++    for (;;) {
++        if (num <= 0)
++            break;
++        if ((c != '.') && (c != ' ')) {
++            ASN1err(ASN1_F_A2D_ASN1_OBJECT, ASN1_R_INVALID_SEPARATOR);
++            goto err;
++        }
++        l = 0;
++        use_bn = 0;
++        for (;;) {
++            if (num <= 0)
++                break;
++            num--;
++            c = *(p++);
++            if ((c == ' ') || (c == '.'))
++                break;
++            if ((c < '0') || (c > '9')) {
++                ASN1err(ASN1_F_A2D_ASN1_OBJECT, ASN1_R_INVALID_DIGIT);
++                goto err;
++            }
++            if (!use_bn && l >= ((ULONG_MAX - 80) / 10L)) {
++                use_bn = 1;
++                if (bl == NULL)
++                    bl = BN_new();
++                if (bl == NULL || !BN_set_word(bl, l))
++                    goto err;
++            }
++            if (use_bn) {
++                if (!BN_mul_word(bl, 10L)
++                    || !BN_add_word(bl, c - '0'))
++                    goto err;
++            } else
++                l = l * 10L + (long)(c - '0');
++        }
++        if (len == 0) {
++            if ((first < 2) && (l >= 40)) {
++                ASN1err(ASN1_F_A2D_ASN1_OBJECT,
++                        ASN1_R_SECOND_NUMBER_TOO_LARGE);
++                goto err;
++            }
++            if (use_bn) {
++                if (!BN_add_word(bl, first * 40))
++                    goto err;
++            } else
++                l += (long)first *40;
++        }
++        i = 0;
++        if (use_bn) {
++            int blsize;
++            blsize = BN_num_bits(bl);
++            blsize = (blsize + 6) / 7;
++            if (blsize > tmpsize) {
++                if (tmp != ftmp)
++                    OPENSSL_free(tmp);
++                tmpsize = blsize + 32;
++                tmp = OPENSSL_malloc(tmpsize);
++                if (tmp == NULL)
++                    goto err;
++            }
++            while (blsize--) {
++                BN_ULONG t = BN_div_word(bl, 0x80L);
++                if (t == (BN_ULONG)-1)
++                    goto err;
++                tmp[i++] = (unsigned char)t;
++            }
++        } else {
++
++            for (;;) {
++                tmp[i++] = (unsigned char)l & 0x7f;
++                l >>= 7L;
++                if (l == 0L)
++                    break;
++            }
++
++        }
++        if (out != NULL) {
++            if (len + i > olen) {
++                ASN1err(ASN1_F_A2D_ASN1_OBJECT, ASN1_R_BUFFER_TOO_SMALL);
++                goto err;
++            }
++            while (--i > 0)
++                out[len++] = tmp[i] | 0x80;
++            out[len++] = tmp[0];
++        } else
++            len += i;
++    }
++    if (tmp != ftmp)
++        OPENSSL_free(tmp);
++    BN_free(bl);
++    return (len);
++ err:
++    if (tmp != ftmp)
++        OPENSSL_free(tmp);
++    BN_free(bl);
++    return (0);
++}
++
++int i2t_ASN1_OBJECT(char *buf, int buf_len, const ASN1_OBJECT *a)
++{
++    return OBJ_obj2txt(buf, buf_len, a, 0);
++}
++
++int i2a_ASN1_OBJECT(BIO *bp, const ASN1_OBJECT *a)
++{
++    char buf[80], *p = buf;
++    int i;
++
++    if ((a == NULL) || (a->data == NULL))
++        return (BIO_write(bp, "NULL", 4));
++    i = i2t_ASN1_OBJECT(buf, sizeof buf, a);
++    if (i > (int)(sizeof(buf) - 1)) {
++        p = OPENSSL_malloc(i + 1);
++        if (p == NULL)
++            return -1;
++        i2t_ASN1_OBJECT(p, i + 1, a);
++    }
++    if (i <= 0) {
++        i = BIO_write(bp, "", 9);
++        i += BIO_dump(bp, (const char *)a->data, a->length);
++        return i;
++    }
++    BIO_write(bp, p, i);
++    if (p != buf)
++        OPENSSL_free(p);
++    return (i);
++}
++
++ASN1_OBJECT *d2i_ASN1_OBJECT(ASN1_OBJECT **a, const unsigned char **pp,
++                             long length)
++{
++    const unsigned char *p;
++    long len;
++    int tag, xclass;
++    int inf, i;
++    ASN1_OBJECT *ret = NULL;
++    p = *pp;
++    inf = ASN1_get_object(&p, &len, &tag, &xclass, length);
++    if (inf & 0x80) {
++        i = ASN1_R_BAD_OBJECT_HEADER;
++        goto err;
++    }
++
++    if (tag != V_ASN1_OBJECT) {
++        i = ASN1_R_EXPECTING_AN_OBJECT;
++        goto err;
++    }
++    ret = c2i_ASN1_OBJECT(a, &p, len);
++    if (ret)
++        *pp = p;
++    return ret;
++ err:
++    ASN1err(ASN1_F_D2I_ASN1_OBJECT, i);
++    return (NULL);
++}
++
++ASN1_OBJECT *c2i_ASN1_OBJECT(ASN1_OBJECT **a, const unsigned char **pp,
++                             long len)
++{
++    ASN1_OBJECT *ret = NULL, tobj;
++    const unsigned char *p;
++    unsigned char *data;
++    int i, length;
++
++    /*
++     * Sanity check OID encoding. Need at least one content octet. MSB must
++     * be clear in the last octet. can't have leading 0x80 in subidentifiers,
++     * see: X.690 8.19.2
++     */
++    if (len <= 0 || len > INT_MAX || pp == NULL || (p = *pp) == NULL ||
++        p[len - 1] & 0x80) {
++        ASN1err(ASN1_F_C2I_ASN1_OBJECT, ASN1_R_INVALID_OBJECT_ENCODING);
++        return NULL;
++    }
++    /* Now 0 < len <= INT_MAX, so the cast is safe. */
++    length = (int)len;
++    /*
++     * Try to lookup OID in table: these are all valid encodings so if we get
++     * a match we know the OID is valid.
++     */
++    tobj.nid = NID_undef;
++    tobj.data = p;
++    tobj.length = length;
++    tobj.flags = 0;
++    i = OBJ_obj2nid(&tobj);
++    if (i != NID_undef) {
++        /*
++         * Return shared registered OID object: this improves efficiency
++         * because we don't have to return a dynamically allocated OID
++         * and NID lookups can use the cached value.
++         */
++        ret = OBJ_nid2obj(i);
++        if (a) {
++            ASN1_OBJECT_free(*a);
++            *a = ret;
++        }
++        *pp += len;
++        return ret;
++    }
++    for (i = 0; i < length; i++, p++) {
++        if (*p == 0x80 && (!i || !(p[-1] & 0x80))) {
++            ASN1err(ASN1_F_C2I_ASN1_OBJECT, ASN1_R_INVALID_OBJECT_ENCODING);
++            return NULL;
++        }
++    }
++
++    /*
++     * only the ASN1_OBJECTs from the 'table' will have values for ->sn or
++     * ->ln
++     */
++    if ((a == NULL) || ((*a) == NULL) ||
++        !((*a)->flags & ASN1_OBJECT_FLAG_DYNAMIC)) {
++        if ((ret = ASN1_OBJECT_new()) == NULL)
++            return (NULL);
++    } else
++        ret = (*a);
++
++    p = *pp;
++    /* detach data from object */
++    data = (unsigned char *)ret->data;
++    ret->data = NULL;
++    /* once detached we can change it */
++    if ((data == NULL) || (ret->length < length)) {
++        ret->length = 0;
++        OPENSSL_free(data);
++        data = OPENSSL_malloc(length);
++        if (data == NULL) {
++            i = ERR_R_MALLOC_FAILURE;
++            goto err;
++        }
++        ret->flags |= ASN1_OBJECT_FLAG_DYNAMIC_DATA;
++    }
++    memcpy(data, p, length);
++    /* reattach data to object, after which it remains const */
++    ret->data = data;
++    ret->length = length;
++    ret->sn = NULL;
++    ret->ln = NULL;
++    /* ret->flags=ASN1_OBJECT_FLAG_DYNAMIC; we know it is dynamic */
++    p += length;
++
++    if (a != NULL)
++        (*a) = ret;
++    *pp = p;
++    return (ret);
++ err:
++    ASN1err(ASN1_F_C2I_ASN1_OBJECT, i);
++    if ((a == NULL) || (*a != ret))
++        ASN1_OBJECT_free(ret);
++    return (NULL);
++}
++
++ASN1_OBJECT *ASN1_OBJECT_new(void)
++{
++    ASN1_OBJECT *ret;
++
++    ret = OPENSSL_zalloc(sizeof(*ret));
++    if (ret == NULL) {
++        ASN1err(ASN1_F_ASN1_OBJECT_NEW, ERR_R_MALLOC_FAILURE);
++        return (NULL);
++    }
++    ret->flags = ASN1_OBJECT_FLAG_DYNAMIC;
++    return (ret);
++}
++
++void ASN1_OBJECT_free(ASN1_OBJECT *a)
++{
++    if (a == NULL)
++        return;
++    if (a->flags & ASN1_OBJECT_FLAG_DYNAMIC_STRINGS) {
++#ifndef CONST_STRICT            /* disable purely for compile-time strict
++                                 * const checking. Doing this on a "real"
++                                 * compile will cause memory leaks */
++        OPENSSL_free((void*)a->sn);
++        OPENSSL_free((void*)a->ln);
++#endif
++        a->sn = a->ln = NULL;
++    }
++    if (a->flags & ASN1_OBJECT_FLAG_DYNAMIC_DATA) {
++        OPENSSL_free((void*)a->data);
++        a->data = NULL;
++        a->length = 0;
++    }
++    if (a->flags & ASN1_OBJECT_FLAG_DYNAMIC)
++        OPENSSL_free(a);
++}
++
++ASN1_OBJECT *ASN1_OBJECT_create(int nid, unsigned char *data, int len,
++                                const char *sn, const char *ln)
++{
++    ASN1_OBJECT o;
++
++    o.sn = sn;
++    o.ln = ln;
++    o.data = data;
++    o.nid = nid;
++    o.length = len;
++    o.flags = ASN1_OBJECT_FLAG_DYNAMIC | ASN1_OBJECT_FLAG_DYNAMIC_STRINGS |
++        ASN1_OBJECT_FLAG_DYNAMIC_DATA;
++    return (OBJ_dup(&o));
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/asn1/a_octet.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/asn1/a_octet.c
+new file mode 100644
+index 0000000..2e1205c
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/asn1/a_octet.c
+@@ -0,0 +1,29 @@
++/*
++ * Copyright 1995-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include "internal/cryptlib.h"
++#include 
++
++ASN1_OCTET_STRING *ASN1_OCTET_STRING_dup(const ASN1_OCTET_STRING *x)
++{
++    return ASN1_STRING_dup(x);
++}
++
++int ASN1_OCTET_STRING_cmp(const ASN1_OCTET_STRING *a,
++                          const ASN1_OCTET_STRING *b)
++{
++    return ASN1_STRING_cmp(a, b);
++}
++
++int ASN1_OCTET_STRING_set(ASN1_OCTET_STRING *x, const unsigned char *d,
++                          int len)
++{
++    return ASN1_STRING_set(x, d, len);
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/asn1/a_print.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/asn1/a_print.c
+new file mode 100644
+index 0000000..1aafe7c
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/asn1/a_print.c
+@@ -0,0 +1,109 @@
++/*
++ * Copyright 1995-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include 
++#include "internal/cryptlib.h"
++#include 
++
++int ASN1_PRINTABLE_type(const unsigned char *s, int len)
++{
++    int c;
++    int ia5 = 0;
++    int t61 = 0;
++
++    if (len <= 0)
++        len = -1;
++    if (s == NULL)
++        return (V_ASN1_PRINTABLESTRING);
++
++    while ((*s) && (len-- != 0)) {
++        c = *(s++);
++#ifndef CHARSET_EBCDIC
++        if (!(((c >= 'a') && (c <= 'z')) ||
++              ((c >= 'A') && (c <= 'Z')) ||
++              ((c >= '0') && (c <= '9')) ||
++              (c == ' ') || (c == '\'') ||
++              (c == '(') || (c == ')') ||
++              (c == '+') || (c == ',') ||
++              (c == '-') || (c == '.') ||
++              (c == '/') || (c == ':') || (c == '=') || (c == '?')))
++            ia5 = 1;
++        if (c & 0x80)
++            t61 = 1;
++#else
++        if (!isalnum(c) && (c != ' ') && strchr("'()+,-./:=?", c) == NULL)
++            ia5 = 1;
++        if (os_toascii[c] & 0x80)
++            t61 = 1;
++#endif
++    }
++    if (t61)
++        return (V_ASN1_T61STRING);
++    if (ia5)
++        return (V_ASN1_IA5STRING);
++    return (V_ASN1_PRINTABLESTRING);
++}
++
++int ASN1_UNIVERSALSTRING_to_string(ASN1_UNIVERSALSTRING *s)
++{
++    int i;
++    unsigned char *p;
++
++    if (s->type != V_ASN1_UNIVERSALSTRING)
++        return (0);
++    if ((s->length % 4) != 0)
++        return (0);
++    p = s->data;
++    for (i = 0; i < s->length; i += 4) {
++        if ((p[0] != '\0') || (p[1] != '\0') || (p[2] != '\0'))
++            break;
++        else
++            p += 4;
++    }
++    if (i < s->length)
++        return (0);
++    p = s->data;
++    for (i = 3; i < s->length; i += 4) {
++        *(p++) = s->data[i];
++    }
++    *(p) = '\0';
++    s->length /= 4;
++    s->type = ASN1_PRINTABLE_type(s->data, s->length);
++    return (1);
++}
++
++int ASN1_STRING_print(BIO *bp, const ASN1_STRING *v)
++{
++    int i, n;
++    char buf[80];
++    const char *p;
++
++    if (v == NULL)
++        return (0);
++    n = 0;
++    p = (const char *)v->data;
++    for (i = 0; i < v->length; i++) {
++        if ((p[i] > '~') || ((p[i] < ' ') &&
++                             (p[i] != '\n') && (p[i] != '\r')))
++            buf[n] = '.';
++        else
++            buf[n] = p[i];
++        n++;
++        if (n >= 80) {
++            if (BIO_write(bp, buf, n) <= 0)
++                return (0);
++            n = 0;
++        }
++    }
++    if (n > 0)
++        if (BIO_write(bp, buf, n) <= 0)
++            return (0);
++    return (1);
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/asn1/a_sign.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/asn1/a_sign.c
+new file mode 100644
+index 0000000..7e21a5e
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/asn1/a_sign.c
+@@ -0,0 +1,228 @@
++/*
++ * Copyright 1995-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include 
++
++#include "internal/cryptlib.h"
++
++#ifndef NO_SYS_TYPES_H
++# include 
++#endif
++
++#include 
++#include 
++#include 
++#include 
++#include 
++#include "internal/asn1_int.h"
++#include "internal/evp_int.h"
++
++#ifndef NO_ASN1_OLD
++
++int ASN1_sign(i2d_of_void *i2d, X509_ALGOR *algor1, X509_ALGOR *algor2,
++              ASN1_BIT_STRING *signature, char *data, EVP_PKEY *pkey,
++              const EVP_MD *type)
++{
++    EVP_MD_CTX *ctx = EVP_MD_CTX_new();
++    unsigned char *p, *buf_in = NULL, *buf_out = NULL;
++    int i, inl = 0, outl = 0, outll = 0;
++    X509_ALGOR *a;
++
++    if (ctx == NULL) {
++        ASN1err(ASN1_F_ASN1_SIGN, ERR_R_MALLOC_FAILURE);
++        goto err;
++    }
++    for (i = 0; i < 2; i++) {
++        if (i == 0)
++            a = algor1;
++        else
++            a = algor2;
++        if (a == NULL)
++            continue;
++        if (type->pkey_type == NID_dsaWithSHA1) {
++            /*
++             * special case: RFC 2459 tells us to omit 'parameters' with
++             * id-dsa-with-sha1
++             */
++            ASN1_TYPE_free(a->parameter);
++            a->parameter = NULL;
++        } else if ((a->parameter == NULL) ||
++                   (a->parameter->type != V_ASN1_NULL)) {
++            ASN1_TYPE_free(a->parameter);
++            if ((a->parameter = ASN1_TYPE_new()) == NULL)
++                goto err;
++            a->parameter->type = V_ASN1_NULL;
++        }
++        ASN1_OBJECT_free(a->algorithm);
++        a->algorithm = OBJ_nid2obj(type->pkey_type);
++        if (a->algorithm == NULL) {
++            ASN1err(ASN1_F_ASN1_SIGN, ASN1_R_UNKNOWN_OBJECT_TYPE);
++            goto err;
++        }
++        if (a->algorithm->length == 0) {
++            ASN1err(ASN1_F_ASN1_SIGN,
++                    ASN1_R_THE_ASN1_OBJECT_IDENTIFIER_IS_NOT_KNOWN_FOR_THIS_MD);
++            goto err;
++        }
++    }
++    inl = i2d(data, NULL);
++    buf_in = OPENSSL_malloc((unsigned int)inl);
++    outll = outl = EVP_PKEY_size(pkey);
++    buf_out = OPENSSL_malloc((unsigned int)outl);
++    if ((buf_in == NULL) || (buf_out == NULL)) {
++        outl = 0;
++        ASN1err(ASN1_F_ASN1_SIGN, ERR_R_MALLOC_FAILURE);
++        goto err;
++    }
++    p = buf_in;
++
++    i2d(data, &p);
++    if (!EVP_SignInit_ex(ctx, type, NULL)
++        || !EVP_SignUpdate(ctx, (unsigned char *)buf_in, inl)
++        || !EVP_SignFinal(ctx, (unsigned char *)buf_out,
++                          (unsigned int *)&outl, pkey)) {
++        outl = 0;
++        ASN1err(ASN1_F_ASN1_SIGN, ERR_R_EVP_LIB);
++        goto err;
++    }
++    OPENSSL_free(signature->data);
++    signature->data = buf_out;
++    buf_out = NULL;
++    signature->length = outl;
++    /*
++     * In the interests of compatibility, I'll make sure that the bit string
++     * has a 'not-used bits' value of 0
++     */
++    signature->flags &= ~(ASN1_STRING_FLAG_BITS_LEFT | 0x07);
++    signature->flags |= ASN1_STRING_FLAG_BITS_LEFT;
++ err:
++    EVP_MD_CTX_free(ctx);
++    OPENSSL_clear_free((char *)buf_in, (unsigned int)inl);
++    OPENSSL_clear_free((char *)buf_out, outll);
++    return (outl);
++}
++
++#endif
++
++int ASN1_item_sign(const ASN1_ITEM *it, X509_ALGOR *algor1,
++                   X509_ALGOR *algor2, ASN1_BIT_STRING *signature, void *asn,
++                   EVP_PKEY *pkey, const EVP_MD *type)
++{
++    int rv;
++    EVP_MD_CTX *ctx = EVP_MD_CTX_new();
++
++    if (ctx == NULL) {
++        ASN1err(ASN1_F_ASN1_ITEM_SIGN, ERR_R_MALLOC_FAILURE);
++        return 0;
++    }
++    if (!EVP_DigestSignInit(ctx, NULL, type, NULL, pkey)) {
++        EVP_MD_CTX_free(ctx);
++        return 0;
++    }
++
++    rv = ASN1_item_sign_ctx(it, algor1, algor2, signature, asn, ctx);
++
++    EVP_MD_CTX_free(ctx);
++    return rv;
++}
++
++int ASN1_item_sign_ctx(const ASN1_ITEM *it,
++                       X509_ALGOR *algor1, X509_ALGOR *algor2,
++                       ASN1_BIT_STRING *signature, void *asn, EVP_MD_CTX *ctx)
++{
++    const EVP_MD *type;
++    EVP_PKEY *pkey;
++    unsigned char *buf_in = NULL, *buf_out = NULL;
++    size_t inl = 0, outl = 0, outll = 0;
++    int signid, paramtype;
++    int rv;
++
++    type = EVP_MD_CTX_md(ctx);
++    pkey = EVP_PKEY_CTX_get0_pkey(EVP_MD_CTX_pkey_ctx(ctx));
++
++    if (type == NULL || pkey == NULL) {
++        ASN1err(ASN1_F_ASN1_ITEM_SIGN_CTX, ASN1_R_CONTEXT_NOT_INITIALISED);
++        goto err;
++    }
++
++    if (pkey->ameth == NULL) {
++        ASN1err(ASN1_F_ASN1_ITEM_SIGN_CTX, ASN1_R_DIGEST_AND_KEY_TYPE_NOT_SUPPORTED);
++        goto err;
++    }
++
++    if (pkey->ameth->item_sign) {
++        rv = pkey->ameth->item_sign(ctx, it, asn, algor1, algor2, signature);
++        if (rv == 1)
++            outl = signature->length;
++        /*-
++         * Return value meanings:
++         * <=0: error.
++         *   1: method does everything.
++         *   2: carry on as normal.
++         *   3: ASN1 method sets algorithm identifiers: just sign.
++         */
++        if (rv <= 0)
++            ASN1err(ASN1_F_ASN1_ITEM_SIGN_CTX, ERR_R_EVP_LIB);
++        if (rv <= 1)
++            goto err;
++    } else
++        rv = 2;
++
++    if (rv == 2) {
++        if (!OBJ_find_sigid_by_algs(&signid,
++                                    EVP_MD_nid(type),
++                                    pkey->ameth->pkey_id)) {
++            ASN1err(ASN1_F_ASN1_ITEM_SIGN_CTX,
++                    ASN1_R_DIGEST_AND_KEY_TYPE_NOT_SUPPORTED);
++            goto err;
++        }
++
++        if (pkey->ameth->pkey_flags & ASN1_PKEY_SIGPARAM_NULL)
++            paramtype = V_ASN1_NULL;
++        else
++            paramtype = V_ASN1_UNDEF;
++
++        if (algor1)
++            X509_ALGOR_set0(algor1, OBJ_nid2obj(signid), paramtype, NULL);
++        if (algor2)
++            X509_ALGOR_set0(algor2, OBJ_nid2obj(signid), paramtype, NULL);
++
++    }
++
++    inl = ASN1_item_i2d(asn, &buf_in, it);
++    outll = outl = EVP_PKEY_size(pkey);
++    buf_out = OPENSSL_malloc((unsigned int)outl);
++    if ((buf_in == NULL) || (buf_out == NULL)) {
++        outl = 0;
++        ASN1err(ASN1_F_ASN1_ITEM_SIGN_CTX, ERR_R_MALLOC_FAILURE);
++        goto err;
++    }
++
++    if (!EVP_DigestSignUpdate(ctx, buf_in, inl)
++        || !EVP_DigestSignFinal(ctx, buf_out, &outl)) {
++        outl = 0;
++        ASN1err(ASN1_F_ASN1_ITEM_SIGN_CTX, ERR_R_EVP_LIB);
++        goto err;
++    }
++    OPENSSL_free(signature->data);
++    signature->data = buf_out;
++    buf_out = NULL;
++    signature->length = outl;
++    /*
++     * In the interests of compatibility, I'll make sure that the bit string
++     * has a 'not-used bits' value of 0
++     */
++    signature->flags &= ~(ASN1_STRING_FLAG_BITS_LEFT | 0x07);
++    signature->flags |= ASN1_STRING_FLAG_BITS_LEFT;
++ err:
++    OPENSSL_clear_free((char *)buf_in, (unsigned int)inl);
++    OPENSSL_clear_free((char *)buf_out, outll);
++    return (outl);
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/asn1/a_strex.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/asn1/a_strex.c
+new file mode 100644
+index 0000000..9839f5c
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/asn1/a_strex.c
+@@ -0,0 +1,645 @@
++/*
++ * Copyright 2000-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include 
++#include "internal/cryptlib.h"
++#include "internal/asn1_int.h"
++#include 
++#include 
++#include 
++
++#include "charmap.h"
++
++/*
++ * ASN1_STRING_print_ex() and X509_NAME_print_ex(). Enhanced string and name
++ * printing routines handling multibyte characters, RFC2253 and a host of
++ * other options.
++ */
++
++#define CHARTYPE_BS_ESC         (ASN1_STRFLGS_ESC_2253 | CHARTYPE_FIRST_ESC_2253 | CHARTYPE_LAST_ESC_2253)
++
++#define ESC_FLAGS (ASN1_STRFLGS_ESC_2253 | \
++                  ASN1_STRFLGS_ESC_2254 | \
++                  ASN1_STRFLGS_ESC_QUOTE | \
++                  ASN1_STRFLGS_ESC_CTRL | \
++                  ASN1_STRFLGS_ESC_MSB)
++
++/*
++ * Three IO functions for sending data to memory, a BIO and and a FILE
++ * pointer.
++ */
++static int send_bio_chars(void *arg, const void *buf, int len)
++{
++    if (!arg)
++        return 1;
++    if (BIO_write(arg, buf, len) != len)
++        return 0;
++    return 1;
++}
++
++#ifndef OPENSSL_NO_STDIO
++static int send_fp_chars(void *arg, const void *buf, int len)
++{
++    if (!arg)
++        return 1;
++    if (fwrite(buf, 1, len, arg) != (unsigned int)len)
++        return 0;
++    return 1;
++}
++#endif
++
++typedef int char_io (void *arg, const void *buf, int len);
++
++/*
++ * This function handles display of strings, one character at a time. It is
++ * passed an unsigned long for each character because it could come from 2 or
++ * even 4 byte forms.
++ */
++
++static int do_esc_char(unsigned long c, unsigned char flags, char *do_quotes,
++                       char_io *io_ch, void *arg)
++{
++    unsigned short chflgs;
++    unsigned char chtmp;
++    char tmphex[HEX_SIZE(long) + 3];
++
++    if (c > 0xffffffffL)
++        return -1;
++    if (c > 0xffff) {
++        BIO_snprintf(tmphex, sizeof tmphex, "\\W%08lX", c);
++        if (!io_ch(arg, tmphex, 10))
++            return -1;
++        return 10;
++    }
++    if (c > 0xff) {
++        BIO_snprintf(tmphex, sizeof tmphex, "\\U%04lX", c);
++        if (!io_ch(arg, tmphex, 6))
++            return -1;
++        return 6;
++    }
++    chtmp = (unsigned char)c;
++    if (chtmp > 0x7f)
++        chflgs = flags & ASN1_STRFLGS_ESC_MSB;
++    else
++        chflgs = char_type[chtmp] & flags;
++    if (chflgs & CHARTYPE_BS_ESC) {
++        /* If we don't escape with quotes, signal we need quotes */
++        if (chflgs & ASN1_STRFLGS_ESC_QUOTE) {
++            if (do_quotes)
++                *do_quotes = 1;
++            if (!io_ch(arg, &chtmp, 1))
++                return -1;
++            return 1;
++        }
++        if (!io_ch(arg, "\\", 1))
++            return -1;
++        if (!io_ch(arg, &chtmp, 1))
++            return -1;
++        return 2;
++    }
++    if (chflgs & (ASN1_STRFLGS_ESC_CTRL
++                  | ASN1_STRFLGS_ESC_MSB
++                  | ASN1_STRFLGS_ESC_2254)) {
++        BIO_snprintf(tmphex, 11, "\\%02X", chtmp);
++        if (!io_ch(arg, tmphex, 3))
++            return -1;
++        return 3;
++    }
++    /*
++     * If we get this far and do any escaping at all must escape the escape
++     * character itself: backslash.
++     */
++    if (chtmp == '\\' && flags & ESC_FLAGS) {
++        if (!io_ch(arg, "\\\\", 2))
++            return -1;
++        return 2;
++    }
++    if (!io_ch(arg, &chtmp, 1))
++        return -1;
++    return 1;
++}
++
++#define BUF_TYPE_WIDTH_MASK     0x7
++#define BUF_TYPE_CONVUTF8       0x8
++
++/*
++ * This function sends each character in a buffer to do_esc_char(). It
++ * interprets the content formats and converts to or from UTF8 as
++ * appropriate.
++ */
++
++static int do_buf(unsigned char *buf, int buflen,
++                  int type, unsigned short flags, char *quotes, char_io *io_ch,
++                  void *arg)
++{
++    int i, outlen, len;
++    unsigned short orflags;
++    unsigned char *p, *q;
++    unsigned long c;
++    p = buf;
++    q = buf + buflen;
++    outlen = 0;
++    while (p != q) {
++        if (p == buf && flags & ASN1_STRFLGS_ESC_2253)
++            orflags = CHARTYPE_FIRST_ESC_2253;
++        else
++            orflags = 0;
++        switch (type & BUF_TYPE_WIDTH_MASK) {
++        case 4:
++            c = ((unsigned long)*p++) << 24;
++            c |= ((unsigned long)*p++) << 16;
++            c |= ((unsigned long)*p++) << 8;
++            c |= *p++;
++            break;
++
++        case 2:
++            c = ((unsigned long)*p++) << 8;
++            c |= *p++;
++            break;
++
++        case 1:
++            c = *p++;
++            break;
++
++        case 0:
++            i = UTF8_getc(p, buflen, &c);
++            if (i < 0)
++                return -1;      /* Invalid UTF8String */
++            p += i;
++            break;
++        default:
++            return -1;          /* invalid width */
++        }
++        if (p == q && flags & ASN1_STRFLGS_ESC_2253)
++            orflags = CHARTYPE_LAST_ESC_2253;
++        if (type & BUF_TYPE_CONVUTF8) {
++            unsigned char utfbuf[6];
++            int utflen;
++            utflen = UTF8_putc(utfbuf, sizeof utfbuf, c);
++            for (i = 0; i < utflen; i++) {
++                /*
++                 * We don't need to worry about setting orflags correctly
++                 * because if utflen==1 its value will be correct anyway
++                 * otherwise each character will be > 0x7f and so the
++                 * character will never be escaped on first and last.
++                 */
++                len =
++                    do_esc_char(utfbuf[i], (unsigned short)(flags | orflags),
++                                quotes, io_ch, arg);
++                if (len < 0)
++                    return -1;
++                outlen += len;
++            }
++        } else {
++            len =
++                do_esc_char(c, (unsigned short)(flags | orflags), quotes,
++                            io_ch, arg);
++            if (len < 0)
++                return -1;
++            outlen += len;
++        }
++    }
++    return outlen;
++}
++
++/* This function hex dumps a buffer of characters */
++
++static int do_hex_dump(char_io *io_ch, void *arg, unsigned char *buf,
++                       int buflen)
++{
++    static const char hexdig[] = "0123456789ABCDEF";
++    unsigned char *p, *q;
++    char hextmp[2];
++    if (arg) {
++        p = buf;
++        q = buf + buflen;
++        while (p != q) {
++            hextmp[0] = hexdig[*p >> 4];
++            hextmp[1] = hexdig[*p & 0xf];
++            if (!io_ch(arg, hextmp, 2))
++                return -1;
++            p++;
++        }
++    }
++    return buflen << 1;
++}
++
++/*
++ * "dump" a string. This is done when the type is unknown, or the flags
++ * request it. We can either dump the content octets or the entire DER
++ * encoding. This uses the RFC2253 #01234 format.
++ */
++
++static int do_dump(unsigned long lflags, char_io *io_ch, void *arg,
++                   const ASN1_STRING *str)
++{
++    /*
++     * Placing the ASN1_STRING in a temp ASN1_TYPE allows the DER encoding to
++     * readily obtained
++     */
++    ASN1_TYPE t;
++    unsigned char *der_buf, *p;
++    int outlen, der_len;
++
++    if (!io_ch(arg, "#", 1))
++        return -1;
++    /* If we don't dump DER encoding just dump content octets */
++    if (!(lflags & ASN1_STRFLGS_DUMP_DER)) {
++        outlen = do_hex_dump(io_ch, arg, str->data, str->length);
++        if (outlen < 0)
++            return -1;
++        return outlen + 1;
++    }
++    t.type = str->type;
++    t.value.ptr = (char *)str;
++    der_len = i2d_ASN1_TYPE(&t, NULL);
++    der_buf = OPENSSL_malloc(der_len);
++    if (der_buf == NULL)
++        return -1;
++    p = der_buf;
++    i2d_ASN1_TYPE(&t, &p);
++    outlen = do_hex_dump(io_ch, arg, der_buf, der_len);
++    OPENSSL_free(der_buf);
++    if (outlen < 0)
++        return -1;
++    return outlen + 1;
++}
++
++/*
++ * Lookup table to convert tags to character widths, 0 = UTF8 encoded, -1 is
++ * used for non string types otherwise it is the number of bytes per
++ * character
++ */
++
++static const signed char tag2nbyte[] = {
++    -1, -1, -1, -1, -1,         /* 0-4 */
++    -1, -1, -1, -1, -1,         /* 5-9 */
++    -1, -1, 0, -1,              /* 10-13 */
++    -1, -1, -1, -1,             /* 15-17 */
++    1, 1, 1,                    /* 18-20 */
++    -1, 1, 1, 1,                /* 21-24 */
++    -1, 1, -1,                  /* 25-27 */
++    4, -1, 2                    /* 28-30 */
++};
++
++/*
++ * This is the main function, print out an ASN1_STRING taking note of various
++ * escape and display options. Returns number of characters written or -1 if
++ * an error occurred.
++ */
++
++static int do_print_ex(char_io *io_ch, void *arg, unsigned long lflags,
++                       const ASN1_STRING *str)
++{
++    int outlen, len;
++    int type;
++    char quotes;
++    unsigned short flags;
++    quotes = 0;
++    /* Keep a copy of escape flags */
++    flags = (unsigned short)(lflags & ESC_FLAGS);
++
++    type = str->type;
++
++    outlen = 0;
++
++    if (lflags & ASN1_STRFLGS_SHOW_TYPE) {
++        const char *tagname;
++        tagname = ASN1_tag2str(type);
++        outlen += strlen(tagname);
++        if (!io_ch(arg, tagname, outlen) || !io_ch(arg, ":", 1))
++            return -1;
++        outlen++;
++    }
++
++    /* Decide what to do with type, either dump content or display it */
++
++    /* Dump everything */
++    if (lflags & ASN1_STRFLGS_DUMP_ALL)
++        type = -1;
++    /* Ignore the string type */
++    else if (lflags & ASN1_STRFLGS_IGNORE_TYPE)
++        type = 1;
++    else {
++        /* Else determine width based on type */
++        if ((type > 0) && (type < 31))
++            type = tag2nbyte[type];
++        else
++            type = -1;
++        if ((type == -1) && !(lflags & ASN1_STRFLGS_DUMP_UNKNOWN))
++            type = 1;
++    }
++
++    if (type == -1) {
++        len = do_dump(lflags, io_ch, arg, str);
++        if (len < 0)
++            return -1;
++        outlen += len;
++        return outlen;
++    }
++
++    if (lflags & ASN1_STRFLGS_UTF8_CONVERT) {
++        /*
++         * Note: if string is UTF8 and we want to convert to UTF8 then we
++         * just interpret it as 1 byte per character to avoid converting
++         * twice.
++         */
++        if (!type)
++            type = 1;
++        else
++            type |= BUF_TYPE_CONVUTF8;
++    }
++
++    len = do_buf(str->data, str->length, type, flags, "es, io_ch, NULL);
++    if (len < 0)
++        return -1;
++    outlen += len;
++    if (quotes)
++        outlen += 2;
++    if (!arg)
++        return outlen;
++    if (quotes && !io_ch(arg, "\"", 1))
++        return -1;
++    if (do_buf(str->data, str->length, type, flags, NULL, io_ch, arg) < 0)
++        return -1;
++    if (quotes && !io_ch(arg, "\"", 1))
++        return -1;
++    return outlen;
++}
++
++/* Used for line indenting: print 'indent' spaces */
++
++static int do_indent(char_io *io_ch, void *arg, int indent)
++{
++    int i;
++    for (i = 0; i < indent; i++)
++        if (!io_ch(arg, " ", 1))
++            return 0;
++    return 1;
++}
++
++#define FN_WIDTH_LN     25
++#define FN_WIDTH_SN     10
++
++static int do_name_ex(char_io *io_ch, void *arg, const X509_NAME *n,
++                      int indent, unsigned long flags)
++{
++    int i, prev = -1, orflags, cnt;
++    int fn_opt, fn_nid;
++    ASN1_OBJECT *fn;
++    const ASN1_STRING *val;
++    const X509_NAME_ENTRY *ent;
++    char objtmp[80];
++    const char *objbuf;
++    int outlen, len;
++    char *sep_dn, *sep_mv, *sep_eq;
++    int sep_dn_len, sep_mv_len, sep_eq_len;
++    if (indent < 0)
++        indent = 0;
++    outlen = indent;
++    if (!do_indent(io_ch, arg, indent))
++        return -1;
++    switch (flags & XN_FLAG_SEP_MASK) {
++    case XN_FLAG_SEP_MULTILINE:
++        sep_dn = "\n";
++        sep_dn_len = 1;
++        sep_mv = " + ";
++        sep_mv_len = 3;
++        break;
++
++    case XN_FLAG_SEP_COMMA_PLUS:
++        sep_dn = ",";
++        sep_dn_len = 1;
++        sep_mv = "+";
++        sep_mv_len = 1;
++        indent = 0;
++        break;
++
++    case XN_FLAG_SEP_CPLUS_SPC:
++        sep_dn = ", ";
++        sep_dn_len = 2;
++        sep_mv = " + ";
++        sep_mv_len = 3;
++        indent = 0;
++        break;
++
++    case XN_FLAG_SEP_SPLUS_SPC:
++        sep_dn = "; ";
++        sep_dn_len = 2;
++        sep_mv = " + ";
++        sep_mv_len = 3;
++        indent = 0;
++        break;
++
++    default:
++        return -1;
++    }
++
++    if (flags & XN_FLAG_SPC_EQ) {
++        sep_eq = " = ";
++        sep_eq_len = 3;
++    } else {
++        sep_eq = "=";
++        sep_eq_len = 1;
++    }
++
++    fn_opt = flags & XN_FLAG_FN_MASK;
++
++    cnt = X509_NAME_entry_count(n);
++    for (i = 0; i < cnt; i++) {
++        if (flags & XN_FLAG_DN_REV)
++            ent = X509_NAME_get_entry(n, cnt - i - 1);
++        else
++            ent = X509_NAME_get_entry(n, i);
++        if (prev != -1) {
++            if (prev == X509_NAME_ENTRY_set(ent)) {
++                if (!io_ch(arg, sep_mv, sep_mv_len))
++                    return -1;
++                outlen += sep_mv_len;
++            } else {
++                if (!io_ch(arg, sep_dn, sep_dn_len))
++                    return -1;
++                outlen += sep_dn_len;
++                if (!do_indent(io_ch, arg, indent))
++                    return -1;
++                outlen += indent;
++            }
++        }
++        prev = X509_NAME_ENTRY_set(ent);
++        fn = X509_NAME_ENTRY_get_object(ent);
++        val = X509_NAME_ENTRY_get_data(ent);
++        fn_nid = OBJ_obj2nid(fn);
++        if (fn_opt != XN_FLAG_FN_NONE) {
++            int objlen, fld_len;
++            if ((fn_opt == XN_FLAG_FN_OID) || (fn_nid == NID_undef)) {
++                OBJ_obj2txt(objtmp, sizeof objtmp, fn, 1);
++                fld_len = 0;    /* XXX: what should this be? */
++                objbuf = objtmp;
++            } else {
++                if (fn_opt == XN_FLAG_FN_SN) {
++                    fld_len = FN_WIDTH_SN;
++                    objbuf = OBJ_nid2sn(fn_nid);
++                } else if (fn_opt == XN_FLAG_FN_LN) {
++                    fld_len = FN_WIDTH_LN;
++                    objbuf = OBJ_nid2ln(fn_nid);
++                } else {
++                    fld_len = 0; /* XXX: what should this be? */
++                    objbuf = "";
++                }
++            }
++            objlen = strlen(objbuf);
++            if (!io_ch(arg, objbuf, objlen))
++                return -1;
++            if ((objlen < fld_len) && (flags & XN_FLAG_FN_ALIGN)) {
++                if (!do_indent(io_ch, arg, fld_len - objlen))
++                    return -1;
++                outlen += fld_len - objlen;
++            }
++            if (!io_ch(arg, sep_eq, sep_eq_len))
++                return -1;
++            outlen += objlen + sep_eq_len;
++        }
++        /*
++         * If the field name is unknown then fix up the DER dump flag. We
++         * might want to limit this further so it will DER dump on anything
++         * other than a few 'standard' fields.
++         */
++        if ((fn_nid == NID_undef) && (flags & XN_FLAG_DUMP_UNKNOWN_FIELDS))
++            orflags = ASN1_STRFLGS_DUMP_ALL;
++        else
++            orflags = 0;
++
++        len = do_print_ex(io_ch, arg, flags | orflags, val);
++        if (len < 0)
++            return -1;
++        outlen += len;
++    }
++    return outlen;
++}
++
++/* Wrappers round the main functions */
++
++int X509_NAME_print_ex(BIO *out, const X509_NAME *nm, int indent,
++                       unsigned long flags)
++{
++    if (flags == XN_FLAG_COMPAT)
++        return X509_NAME_print(out, nm, indent);
++    return do_name_ex(send_bio_chars, out, nm, indent, flags);
++}
++
++#ifndef OPENSSL_NO_STDIO
++int X509_NAME_print_ex_fp(FILE *fp, const X509_NAME *nm, int indent,
++                          unsigned long flags)
++{
++    if (flags == XN_FLAG_COMPAT) {
++        BIO *btmp;
++        int ret;
++        btmp = BIO_new_fp(fp, BIO_NOCLOSE);
++        if (!btmp)
++            return -1;
++        ret = X509_NAME_print(btmp, nm, indent);
++        BIO_free(btmp);
++        return ret;
++    }
++    return do_name_ex(send_fp_chars, fp, nm, indent, flags);
++}
++#endif
++
++int ASN1_STRING_print_ex(BIO *out, const ASN1_STRING *str, unsigned long flags)
++{
++    return do_print_ex(send_bio_chars, out, flags, str);
++}
++
++#ifndef OPENSSL_NO_STDIO
++int ASN1_STRING_print_ex_fp(FILE *fp, const ASN1_STRING *str, unsigned long flags)
++{
++    return do_print_ex(send_fp_chars, fp, flags, str);
++}
++#endif
++
++/*
++ * Utility function: convert any string type to UTF8, returns number of bytes
++ * in output string or a negative error code
++ */
++
++int ASN1_STRING_to_UTF8(unsigned char **out, const ASN1_STRING *in)
++{
++    ASN1_STRING stmp, *str = &stmp;
++    int mbflag, type, ret;
++    if (!in)
++        return -1;
++    type = in->type;
++    if ((type < 0) || (type > 30))
++        return -1;
++    mbflag = tag2nbyte[type];
++    if (mbflag == -1)
++        return -1;
++    mbflag |= MBSTRING_FLAG;
++    stmp.data = NULL;
++    stmp.length = 0;
++    stmp.flags = 0;
++    ret =
++        ASN1_mbstring_copy(&str, in->data, in->length, mbflag,
++                           B_ASN1_UTF8STRING);
++    if (ret < 0)
++        return ret;
++    *out = stmp.data;
++    return stmp.length;
++}
++
++/* Return 1 if host is a valid hostname and 0 otherwise */
++int asn1_valid_host(const ASN1_STRING *host)
++{
++    int hostlen = host->length;
++    const unsigned char *hostptr = host->data;
++    int type = host->type;
++    int i;
++    char width = -1;
++    unsigned short chflags = 0, prevchflags;
++
++    if (type > 0 && type < 31)
++        width = tag2nbyte[type];
++    if (width == -1 || hostlen == 0)
++        return 0;
++    /* Treat UTF8String as width 1 as any MSB set is invalid */
++    if (width == 0)
++        width = 1;
++    for (i = 0 ; i < hostlen; i+= width) {
++        prevchflags = chflags;
++        /* Value must be <= 0x7F: check upper bytes are all zeroes */
++        if (width == 4) {
++            if (*hostptr++ != 0 || *hostptr++ != 0 || *hostptr++ != 0)
++                return 0;
++        } else if (width == 2) {
++            if (*hostptr++ != 0)
++                return 0;
++        }
++        if (*hostptr > 0x7f)
++            return 0;
++        chflags = char_type[*hostptr++];
++        if (!(chflags & (CHARTYPE_HOST_ANY | CHARTYPE_HOST_WILD))) {
++            /* Nothing else allowed at start or end of string */
++            if (i == 0 || i == hostlen - 1)
++                return 0;
++            /* Otherwise invalid if not dot or hyphen */
++            if (!(chflags & (CHARTYPE_HOST_DOT | CHARTYPE_HOST_HYPHEN)))
++                return 0;
++            /*
++             * If previous is dot or hyphen then illegal unless both
++             * are hyphens: as .- -. .. are all illegal
++             */
++            if (prevchflags & (CHARTYPE_HOST_DOT | CHARTYPE_HOST_HYPHEN)
++                && ((prevchflags & CHARTYPE_HOST_DOT)
++                    || (chflags & CHARTYPE_HOST_DOT)))
++                return 0;
++        }
++    }
++    return 1;
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/asn1/a_strnid.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/asn1/a_strnid.c
+new file mode 100644
+index 0000000..53832c8
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/asn1/a_strnid.c
+@@ -0,0 +1,287 @@
++/*
++ * Copyright 1999-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include 
++#include "internal/cryptlib.h"
++#include 
++#include 
++
++static STACK_OF(ASN1_STRING_TABLE) *stable = NULL;
++static void st_free(ASN1_STRING_TABLE *tbl);
++static int sk_table_cmp(const ASN1_STRING_TABLE *const *a,
++                        const ASN1_STRING_TABLE *const *b);
++
++/*
++ * This is the global mask for the mbstring functions: this is use to mask
++ * out certain types (such as BMPString and UTF8String) because certain
++ * software (e.g. Netscape) has problems with them.
++ */
++
++static unsigned long global_mask = B_ASN1_UTF8STRING;
++
++void ASN1_STRING_set_default_mask(unsigned long mask)
++{
++    global_mask = mask;
++}
++
++unsigned long ASN1_STRING_get_default_mask(void)
++{
++    return global_mask;
++}
++
++/*-
++ * This function sets the default to various "flavours" of configuration.
++ * based on an ASCII string. Currently this is:
++ * MASK:XXXX : a numerical mask value.
++ * nobmp : Don't use BMPStrings (just Printable, T61).
++ * pkix : PKIX recommendation in RFC2459.
++ * utf8only : only use UTF8Strings (RFC2459 recommendation for 2004).
++ * default:   the default value, Printable, T61, BMP.
++ */
++
++int ASN1_STRING_set_default_mask_asc(const char *p)
++{
++    unsigned long mask;
++    char *end;
++    if (strncmp(p, "MASK:", 5) == 0) {
++        if (!p[5])
++            return 0;
++        mask = strtoul(p + 5, &end, 0);
++        if (*end)
++            return 0;
++    } else if (strcmp(p, "nombstr") == 0)
++        mask = ~((unsigned long)(B_ASN1_BMPSTRING | B_ASN1_UTF8STRING));
++    else if (strcmp(p, "pkix") == 0)
++        mask = ~((unsigned long)B_ASN1_T61STRING);
++    else if (strcmp(p, "utf8only") == 0)
++        mask = B_ASN1_UTF8STRING;
++    else if (strcmp(p, "default") == 0)
++        mask = 0xFFFFFFFFL;
++    else
++        return 0;
++    ASN1_STRING_set_default_mask(mask);
++    return 1;
++}
++
++/*
++ * The following function generates an ASN1_STRING based on limits in a
++ * table. Frequently the types and length of an ASN1_STRING are restricted by
++ * a corresponding OID. For example certificates and certificate requests.
++ */
++
++ASN1_STRING *ASN1_STRING_set_by_NID(ASN1_STRING **out,
++                                    const unsigned char *in, int inlen,
++                                    int inform, int nid)
++{
++    ASN1_STRING_TABLE *tbl;
++    ASN1_STRING *str = NULL;
++    unsigned long mask;
++    int ret;
++    if (!out)
++        out = &str;
++    tbl = ASN1_STRING_TABLE_get(nid);
++    if (tbl) {
++        mask = tbl->mask;
++        if (!(tbl->flags & STABLE_NO_MASK))
++            mask &= global_mask;
++        ret = ASN1_mbstring_ncopy(out, in, inlen, inform, mask,
++                                  tbl->minsize, tbl->maxsize);
++    } else
++        ret =
++            ASN1_mbstring_copy(out, in, inlen, inform,
++                               DIRSTRING_TYPE & global_mask);
++    if (ret <= 0)
++        return NULL;
++    return *out;
++}
++
++/*
++ * Now the tables and helper functions for the string table:
++ */
++
++/* size limits: this stuff is taken straight from RFC3280 */
++
++#define ub_name                         32768
++#define ub_common_name                  64
++#define ub_locality_name                128
++#define ub_state_name                   128
++#define ub_organization_name            64
++#define ub_organization_unit_name       64
++#define ub_title                        64
++#define ub_email_address                128
++#define ub_serial_number                64
++
++/* From RFC4524 */
++
++#define ub_rfc822_mailbox               256
++
++/* This table must be kept in NID order */
++
++static const ASN1_STRING_TABLE tbl_standard[] = {
++    {NID_commonName, 1, ub_common_name, DIRSTRING_TYPE, 0},
++    {NID_countryName, 2, 2, B_ASN1_PRINTABLESTRING, STABLE_NO_MASK},
++    {NID_localityName, 1, ub_locality_name, DIRSTRING_TYPE, 0},
++    {NID_stateOrProvinceName, 1, ub_state_name, DIRSTRING_TYPE, 0},
++    {NID_organizationName, 1, ub_organization_name, DIRSTRING_TYPE, 0},
++    {NID_organizationalUnitName, 1, ub_organization_unit_name, DIRSTRING_TYPE,
++     0},
++    {NID_pkcs9_emailAddress, 1, ub_email_address, B_ASN1_IA5STRING,
++     STABLE_NO_MASK},
++    {NID_pkcs9_unstructuredName, 1, -1, PKCS9STRING_TYPE, 0},
++    {NID_pkcs9_challengePassword, 1, -1, PKCS9STRING_TYPE, 0},
++    {NID_pkcs9_unstructuredAddress, 1, -1, DIRSTRING_TYPE, 0},
++    {NID_givenName, 1, ub_name, DIRSTRING_TYPE, 0},
++    {NID_surname, 1, ub_name, DIRSTRING_TYPE, 0},
++    {NID_initials, 1, ub_name, DIRSTRING_TYPE, 0},
++    {NID_serialNumber, 1, ub_serial_number, B_ASN1_PRINTABLESTRING,
++     STABLE_NO_MASK},
++    {NID_friendlyName, -1, -1, B_ASN1_BMPSTRING, STABLE_NO_MASK},
++    {NID_name, 1, ub_name, DIRSTRING_TYPE, 0},
++    {NID_dnQualifier, -1, -1, B_ASN1_PRINTABLESTRING, STABLE_NO_MASK},
++    {NID_domainComponent, 1, -1, B_ASN1_IA5STRING, STABLE_NO_MASK},
++    {NID_ms_csp_name, -1, -1, B_ASN1_BMPSTRING, STABLE_NO_MASK},
++    {NID_rfc822Mailbox, 1, ub_rfc822_mailbox, B_ASN1_IA5STRING,
++     STABLE_NO_MASK},
++    {NID_INN, 1, 12, B_ASN1_NUMERICSTRING, STABLE_NO_MASK},
++    {NID_OGRN, 1, 13, B_ASN1_NUMERICSTRING, STABLE_NO_MASK},
++    {NID_SNILS, 1, 11, B_ASN1_NUMERICSTRING, STABLE_NO_MASK}
++};
++
++static int sk_table_cmp(const ASN1_STRING_TABLE *const *a,
++                        const ASN1_STRING_TABLE *const *b)
++{
++    return (*a)->nid - (*b)->nid;
++}
++
++DECLARE_OBJ_BSEARCH_CMP_FN(ASN1_STRING_TABLE, ASN1_STRING_TABLE, table);
++
++static int table_cmp(const ASN1_STRING_TABLE *a, const ASN1_STRING_TABLE *b)
++{
++    return a->nid - b->nid;
++}
++
++IMPLEMENT_OBJ_BSEARCH_CMP_FN(ASN1_STRING_TABLE, ASN1_STRING_TABLE, table);
++
++ASN1_STRING_TABLE *ASN1_STRING_TABLE_get(int nid)
++{
++    int idx;
++    ASN1_STRING_TABLE fnd;
++    fnd.nid = nid;
++    if (stable) {
++        idx = sk_ASN1_STRING_TABLE_find(stable, &fnd);
++        if (idx >= 0)
++            return sk_ASN1_STRING_TABLE_value(stable, idx);
++    }
++    return OBJ_bsearch_table(&fnd, tbl_standard, OSSL_NELEM(tbl_standard));
++}
++
++/*
++ * Return a string table pointer which can be modified: either directly from
++ * table or a copy of an internal value added to the table.
++ */
++
++static ASN1_STRING_TABLE *stable_get(int nid)
++{
++    ASN1_STRING_TABLE *tmp, *rv;
++    /* Always need a string table so allocate one if NULL */
++    if (stable == NULL) {
++        stable = sk_ASN1_STRING_TABLE_new(sk_table_cmp);
++        if (stable == NULL)
++            return NULL;
++    }
++    tmp = ASN1_STRING_TABLE_get(nid);
++    if (tmp && tmp->flags & STABLE_FLAGS_MALLOC)
++        return tmp;
++    rv = OPENSSL_zalloc(sizeof(*rv));
++    if (rv == NULL)
++        return NULL;
++    if (!sk_ASN1_STRING_TABLE_push(stable, rv)) {
++        OPENSSL_free(rv);
++        return NULL;
++    }
++    if (tmp) {
++        rv->nid = tmp->nid;
++        rv->minsize = tmp->minsize;
++        rv->maxsize = tmp->maxsize;
++        rv->mask = tmp->mask;
++        rv->flags = tmp->flags | STABLE_FLAGS_MALLOC;
++    } else {
++        rv->minsize = -1;
++        rv->maxsize = -1;
++        rv->flags = STABLE_FLAGS_MALLOC;
++    }
++    return rv;
++}
++
++int ASN1_STRING_TABLE_add(int nid,
++                          long minsize, long maxsize, unsigned long mask,
++                          unsigned long flags)
++{
++    ASN1_STRING_TABLE *tmp;
++    tmp = stable_get(nid);
++    if (!tmp) {
++        ASN1err(ASN1_F_ASN1_STRING_TABLE_ADD, ERR_R_MALLOC_FAILURE);
++        return 0;
++    }
++    if (minsize >= 0)
++        tmp->minsize = minsize;
++    if (maxsize >= 0)
++        tmp->maxsize = maxsize;
++    if (mask)
++        tmp->mask = mask;
++    if (flags)
++        tmp->flags = STABLE_FLAGS_MALLOC | flags;
++    return 1;
++}
++
++void ASN1_STRING_TABLE_cleanup(void)
++{
++    STACK_OF(ASN1_STRING_TABLE) *tmp;
++    tmp = stable;
++    if (!tmp)
++        return;
++    stable = NULL;
++    sk_ASN1_STRING_TABLE_pop_free(tmp, st_free);
++}
++
++static void st_free(ASN1_STRING_TABLE *tbl)
++{
++    if (tbl->flags & STABLE_FLAGS_MALLOC)
++        OPENSSL_free(tbl);
++}
++
++
++#ifdef STRING_TABLE_TEST
++
++main()
++{
++    ASN1_STRING_TABLE *tmp;
++    int i, last_nid = -1;
++
++    for (tmp = tbl_standard, i = 0; i < OSSL_NELEM(tbl_standard); i++, tmp++) {
++        if (tmp->nid < last_nid) {
++            last_nid = 0;
++            break;
++        }
++        last_nid = tmp->nid;
++    }
++
++    if (last_nid != 0) {
++        printf("Table order OK\n");
++        exit(0);
++    }
++
++    for (tmp = tbl_standard, i = 0; i < OSSL_NELEM(tbl_standard); i++, tmp++)
++        printf("Index %d, NID %d, Name=%s\n", i, tmp->nid,
++               OBJ_nid2ln(tmp->nid));
++
++}
++
++#endif
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/asn1/a_time.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/asn1/a_time.c
+new file mode 100644
+index 0000000..3f82c2b
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/asn1/a_time.c
+@@ -0,0 +1,163 @@
++/*
++ * Copyright 1999-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++/*-
++ * This is an implementation of the ASN1 Time structure which is:
++ *    Time ::= CHOICE {
++ *      utcTime        UTCTime,
++ *      generalTime    GeneralizedTime }
++ */
++
++#include 
++#include 
++#include "internal/cryptlib.h"
++#include 
++#include "asn1_locl.h"
++
++IMPLEMENT_ASN1_MSTRING(ASN1_TIME, B_ASN1_TIME)
++
++IMPLEMENT_ASN1_FUNCTIONS(ASN1_TIME)
++
++ASN1_TIME *ASN1_TIME_set(ASN1_TIME *s, time_t t)
++{
++    return ASN1_TIME_adj(s, t, 0, 0);
++}
++
++ASN1_TIME *ASN1_TIME_adj(ASN1_TIME *s, time_t t,
++                         int offset_day, long offset_sec)
++{
++    struct tm *ts;
++    struct tm data;
++
++    ts = OPENSSL_gmtime(&t, &data);
++    if (ts == NULL) {
++        ASN1err(ASN1_F_ASN1_TIME_ADJ, ASN1_R_ERROR_GETTING_TIME);
++        return NULL;
++    }
++    if (offset_day || offset_sec) {
++        if (!OPENSSL_gmtime_adj(ts, offset_day, offset_sec))
++            return NULL;
++    }
++    if ((ts->tm_year >= 50) && (ts->tm_year < 150))
++        return ASN1_UTCTIME_adj(s, t, offset_day, offset_sec);
++    return ASN1_GENERALIZEDTIME_adj(s, t, offset_day, offset_sec);
++}
++
++int ASN1_TIME_check(const ASN1_TIME *t)
++{
++    if (t->type == V_ASN1_GENERALIZEDTIME)
++        return ASN1_GENERALIZEDTIME_check(t);
++    else if (t->type == V_ASN1_UTCTIME)
++        return ASN1_UTCTIME_check(t);
++    return 0;
++}
++
++/* Convert an ASN1_TIME structure to GeneralizedTime */
++ASN1_GENERALIZEDTIME *ASN1_TIME_to_generalizedtime(ASN1_TIME *t,
++                                                   ASN1_GENERALIZEDTIME **out)
++{
++    ASN1_GENERALIZEDTIME *ret;
++    char *str;
++    int newlen;
++
++    if (!ASN1_TIME_check(t))
++        return NULL;
++
++    if (out == NULL || *out == NULL) {
++        if ((ret = ASN1_GENERALIZEDTIME_new()) == NULL)
++            return NULL;
++        if (out)
++            *out = ret;
++    } else
++        ret = *out;
++
++    /* If already GeneralizedTime just copy across */
++    if (t->type == V_ASN1_GENERALIZEDTIME) {
++        if (!ASN1_STRING_set(ret, t->data, t->length))
++            return NULL;
++        return ret;
++    }
++
++    /* grow the string */
++    if (!ASN1_STRING_set(ret, NULL, t->length + 2))
++        return NULL;
++    /* ASN1_STRING_set() allocated 'len + 1' bytes. */
++    newlen = t->length + 2 + 1;
++    str = (char *)ret->data;
++    /* Work out the century and prepend */
++    if (t->data[0] >= '5')
++        OPENSSL_strlcpy(str, "19", newlen);
++    else
++        OPENSSL_strlcpy(str, "20", newlen);
++
++    OPENSSL_strlcat(str, (char *)t->data, newlen);
++
++    return ret;
++}
++
++int ASN1_TIME_set_string(ASN1_TIME *s, const char *str)
++{
++    ASN1_TIME t;
++
++    t.length = strlen(str);
++    t.data = (unsigned char *)str;
++    t.flags = 0;
++
++    t.type = V_ASN1_UTCTIME;
++
++    if (!ASN1_TIME_check(&t)) {
++        t.type = V_ASN1_GENERALIZEDTIME;
++        if (!ASN1_TIME_check(&t))
++            return 0;
++    }
++
++    if (s && !ASN1_STRING_copy((ASN1_STRING *)s, (ASN1_STRING *)&t))
++        return 0;
++
++    return 1;
++}
++
++static int asn1_time_to_tm(struct tm *tm, const ASN1_TIME *t)
++{
++    if (t == NULL) {
++        time_t now_t;
++        time(&now_t);
++        if (OPENSSL_gmtime(&now_t, tm))
++            return 1;
++        return 0;
++    }
++
++    if (t->type == V_ASN1_UTCTIME)
++        return asn1_utctime_to_tm(tm, t);
++    else if (t->type == V_ASN1_GENERALIZEDTIME)
++        return asn1_generalizedtime_to_tm(tm, t);
++
++    return 0;
++}
++
++int ASN1_TIME_diff(int *pday, int *psec,
++                   const ASN1_TIME *from, const ASN1_TIME *to)
++{
++    struct tm tm_from, tm_to;
++    if (!asn1_time_to_tm(&tm_from, from))
++        return 0;
++    if (!asn1_time_to_tm(&tm_to, to))
++        return 0;
++    return OPENSSL_gmtime_diff(pday, psec, &tm_from, &tm_to);
++}
++
++int ASN1_TIME_print(BIO *bp, const ASN1_TIME *tm)
++{
++    if (tm->type == V_ASN1_UTCTIME)
++        return ASN1_UTCTIME_print(bp, tm);
++    if (tm->type == V_ASN1_GENERALIZEDTIME)
++        return ASN1_GENERALIZEDTIME_print(bp, tm);
++    BIO_write(bp, "Bad time value", 14);
++    return (0);
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/asn1/a_type.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/asn1/a_type.c
+new file mode 100644
+index 0000000..df42360
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/asn1/a_type.c
+@@ -0,0 +1,134 @@
++/*
++ * Copyright 1995-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include "internal/cryptlib.h"
++#include 
++#include 
++#include "asn1_locl.h"
++
++int ASN1_TYPE_get(const ASN1_TYPE *a)
++{
++    if ((a->value.ptr != NULL) || (a->type == V_ASN1_NULL))
++        return (a->type);
++    else
++        return (0);
++}
++
++void ASN1_TYPE_set(ASN1_TYPE *a, int type, void *value)
++{
++    if (a->value.ptr != NULL) {
++        ASN1_TYPE **tmp_a = &a;
++        asn1_primitive_free((ASN1_VALUE **)tmp_a, NULL, 0);
++    }
++    a->type = type;
++    if (type == V_ASN1_BOOLEAN)
++        a->value.boolean = value ? 0xff : 0;
++    else
++        a->value.ptr = value;
++}
++
++int ASN1_TYPE_set1(ASN1_TYPE *a, int type, const void *value)
++{
++    if (!value || (type == V_ASN1_BOOLEAN)) {
++        void *p = (void *)value;
++        ASN1_TYPE_set(a, type, p);
++    } else if (type == V_ASN1_OBJECT) {
++        ASN1_OBJECT *odup;
++        odup = OBJ_dup(value);
++        if (!odup)
++            return 0;
++        ASN1_TYPE_set(a, type, odup);
++    } else {
++        ASN1_STRING *sdup;
++        sdup = ASN1_STRING_dup(value);
++        if (!sdup)
++            return 0;
++        ASN1_TYPE_set(a, type, sdup);
++    }
++    return 1;
++}
++
++/* Returns 0 if they are equal, != 0 otherwise. */
++int ASN1_TYPE_cmp(const ASN1_TYPE *a, const ASN1_TYPE *b)
++{
++    int result = -1;
++
++    if (!a || !b || a->type != b->type)
++        return -1;
++
++    switch (a->type) {
++    case V_ASN1_OBJECT:
++        result = OBJ_cmp(a->value.object, b->value.object);
++        break;
++    case V_ASN1_BOOLEAN:
++        result = a->value.boolean - b->value.boolean;
++        break;
++    case V_ASN1_NULL:
++        result = 0;             /* They do not have content. */
++        break;
++    case V_ASN1_INTEGER:
++    case V_ASN1_ENUMERATED:
++    case V_ASN1_BIT_STRING:
++    case V_ASN1_OCTET_STRING:
++    case V_ASN1_SEQUENCE:
++    case V_ASN1_SET:
++    case V_ASN1_NUMERICSTRING:
++    case V_ASN1_PRINTABLESTRING:
++    case V_ASN1_T61STRING:
++    case V_ASN1_VIDEOTEXSTRING:
++    case V_ASN1_IA5STRING:
++    case V_ASN1_UTCTIME:
++    case V_ASN1_GENERALIZEDTIME:
++    case V_ASN1_GRAPHICSTRING:
++    case V_ASN1_VISIBLESTRING:
++    case V_ASN1_GENERALSTRING:
++    case V_ASN1_UNIVERSALSTRING:
++    case V_ASN1_BMPSTRING:
++    case V_ASN1_UTF8STRING:
++    case V_ASN1_OTHER:
++    default:
++        result = ASN1_STRING_cmp((ASN1_STRING *)a->value.ptr,
++                                 (ASN1_STRING *)b->value.ptr);
++        break;
++    }
++
++    return result;
++}
++
++ASN1_TYPE *ASN1_TYPE_pack_sequence(const ASN1_ITEM *it, void *s, ASN1_TYPE **t)
++{
++    ASN1_OCTET_STRING *oct;
++    ASN1_TYPE *rt;
++
++    oct = ASN1_item_pack(s, it, NULL);
++    if (oct == NULL)
++        return NULL;
++
++    if (t && *t) {
++        rt = *t;
++    } else {
++        rt = ASN1_TYPE_new();
++        if (rt == NULL) {
++            ASN1_OCTET_STRING_free(oct);
++            return NULL;
++        }
++        if (t)
++            *t = rt;
++    }
++    ASN1_TYPE_set(rt, V_ASN1_SEQUENCE, oct);
++    return rt;
++}
++
++void *ASN1_TYPE_unpack_sequence(const ASN1_ITEM *it, const ASN1_TYPE *t)
++{
++    if (t == NULL || t->type != V_ASN1_SEQUENCE || t->value.sequence == NULL)
++        return NULL;
++    return ASN1_item_unpack(t->value.sequence, it);
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/asn1/a_utctm.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/asn1/a_utctm.c
+new file mode 100644
+index 0000000..7916e30
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/asn1/a_utctm.c
+@@ -0,0 +1,254 @@
++/*
++ * Copyright 1995-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include 
++#include "internal/cryptlib.h"
++#include 
++#include "asn1_locl.h"
++
++int asn1_utctime_to_tm(struct tm *tm, const ASN1_UTCTIME *d)
++{
++    static const int min[8] = { 0, 1, 1, 0, 0, 0, 0, 0 };
++    static const int max[8] = { 99, 12, 31, 23, 59, 59, 12, 59 };
++    char *a;
++    int n, i, l, o;
++
++    if (d->type != V_ASN1_UTCTIME)
++        return (0);
++    l = d->length;
++    a = (char *)d->data;
++    o = 0;
++
++    if (l < 11)
++        goto err;
++    for (i = 0; i < 6; i++) {
++        if ((i == 5) && ((a[o] == 'Z') || (a[o] == '+') || (a[o] == '-'))) {
++            i++;
++            if (tm)
++                tm->tm_sec = 0;
++            break;
++        }
++        if ((a[o] < '0') || (a[o] > '9'))
++            goto err;
++        n = a[o] - '0';
++        if (++o > l)
++            goto err;
++
++        if ((a[o] < '0') || (a[o] > '9'))
++            goto err;
++        n = (n * 10) + a[o] - '0';
++        if (++o > l)
++            goto err;
++
++        if ((n < min[i]) || (n > max[i]))
++            goto err;
++        if (tm) {
++            switch (i) {
++            case 0:
++                tm->tm_year = n < 50 ? n + 100 : n;
++                break;
++            case 1:
++                tm->tm_mon = n - 1;
++                break;
++            case 2:
++                tm->tm_mday = n;
++                break;
++            case 3:
++                tm->tm_hour = n;
++                break;
++            case 4:
++                tm->tm_min = n;
++                break;
++            case 5:
++                tm->tm_sec = n;
++                break;
++            }
++        }
++    }
++    if (a[o] == 'Z')
++        o++;
++    else if ((a[o] == '+') || (a[o] == '-')) {
++        int offsign = a[o] == '-' ? -1 : 1, offset = 0;
++        o++;
++        if (o + 4 > l)
++            goto err;
++        for (i = 6; i < 8; i++) {
++            if ((a[o] < '0') || (a[o] > '9'))
++                goto err;
++            n = a[o] - '0';
++            o++;
++            if ((a[o] < '0') || (a[o] > '9'))
++                goto err;
++            n = (n * 10) + a[o] - '0';
++            if ((n < min[i]) || (n > max[i]))
++                goto err;
++            if (tm) {
++                if (i == 6)
++                    offset = n * 3600;
++                else if (i == 7)
++                    offset += n * 60;
++            }
++            o++;
++        }
++        if (offset && !OPENSSL_gmtime_adj(tm, 0, offset * offsign))
++            return 0;
++    }
++    return o == l;
++ err:
++    return 0;
++}
++
++int ASN1_UTCTIME_check(const ASN1_UTCTIME *d)
++{
++    return asn1_utctime_to_tm(NULL, d);
++}
++
++int ASN1_UTCTIME_set_string(ASN1_UTCTIME *s, const char *str)
++{
++    ASN1_UTCTIME t;
++
++    t.type = V_ASN1_UTCTIME;
++    t.length = strlen(str);
++    t.data = (unsigned char *)str;
++    if (ASN1_UTCTIME_check(&t)) {
++        if (s != NULL) {
++            if (!ASN1_STRING_set((ASN1_STRING *)s, str, t.length))
++                return 0;
++            s->type = V_ASN1_UTCTIME;
++        }
++        return (1);
++    } else
++        return (0);
++}
++
++ASN1_UTCTIME *ASN1_UTCTIME_set(ASN1_UTCTIME *s, time_t t)
++{
++    return ASN1_UTCTIME_adj(s, t, 0, 0);
++}
++
++ASN1_UTCTIME *ASN1_UTCTIME_adj(ASN1_UTCTIME *s, time_t t,
++                               int offset_day, long offset_sec)
++{
++    char *p;
++    struct tm *ts;
++    struct tm data;
++    size_t len = 20;
++    int free_s = 0;
++
++    if (s == NULL) {
++        s = ASN1_UTCTIME_new();
++        if (s == NULL)
++            goto err;
++        free_s = 1;
++    }
++
++    ts = OPENSSL_gmtime(&t, &data);
++    if (ts == NULL)
++        goto err;
++
++    if (offset_day || offset_sec) {
++        if (!OPENSSL_gmtime_adj(ts, offset_day, offset_sec))
++            goto err;
++    }
++
++    if ((ts->tm_year < 50) || (ts->tm_year >= 150))
++        goto err;
++
++    p = (char *)s->data;
++    if ((p == NULL) || ((size_t)s->length < len)) {
++        p = OPENSSL_malloc(len);
++        if (p == NULL) {
++            ASN1err(ASN1_F_ASN1_UTCTIME_ADJ, ERR_R_MALLOC_FAILURE);
++            goto err;
++        }
++        OPENSSL_free(s->data);
++        s->data = (unsigned char *)p;
++    }
++
++    BIO_snprintf(p, len, "%02d%02d%02d%02d%02d%02dZ", ts->tm_year % 100,
++                 ts->tm_mon + 1, ts->tm_mday, ts->tm_hour, ts->tm_min,
++                 ts->tm_sec);
++    s->length = strlen(p);
++    s->type = V_ASN1_UTCTIME;
++#ifdef CHARSET_EBCDIC_not
++    ebcdic2ascii(s->data, s->data, s->length);
++#endif
++    return (s);
++ err:
++    if (free_s)
++        ASN1_UTCTIME_free(s);
++    return NULL;
++}
++
++int ASN1_UTCTIME_cmp_time_t(const ASN1_UTCTIME *s, time_t t)
++{
++    struct tm stm, ttm;
++    int day, sec;
++
++    if (!asn1_utctime_to_tm(&stm, s))
++        return -2;
++
++    if (!OPENSSL_gmtime(&t, &ttm))
++        return -2;
++
++    if (!OPENSSL_gmtime_diff(&day, &sec, &ttm, &stm))
++        return -2;
++
++    if (day > 0)
++        return 1;
++    if (day < 0)
++        return -1;
++    if (sec > 0)
++        return 1;
++    if (sec < 0)
++        return -1;
++    return 0;
++}
++
++int ASN1_UTCTIME_print(BIO *bp, const ASN1_UTCTIME *tm)
++{
++    const char *v;
++    int gmt = 0;
++    int i;
++    int y = 0, M = 0, d = 0, h = 0, m = 0, s = 0;
++
++    i = tm->length;
++    v = (const char *)tm->data;
++
++    if (i < 10)
++        goto err;
++    if (v[i - 1] == 'Z')
++        gmt = 1;
++    for (i = 0; i < 10; i++)
++        if ((v[i] > '9') || (v[i] < '0'))
++            goto err;
++    y = (v[0] - '0') * 10 + (v[1] - '0');
++    if (y < 50)
++        y += 100;
++    M = (v[2] - '0') * 10 + (v[3] - '0');
++    if ((M > 12) || (M < 1))
++        goto err;
++    d = (v[4] - '0') * 10 + (v[5] - '0');
++    h = (v[6] - '0') * 10 + (v[7] - '0');
++    m = (v[8] - '0') * 10 + (v[9] - '0');
++    if (tm->length >= 12 &&
++        (v[10] >= '0') && (v[10] <= '9') && (v[11] >= '0') && (v[11] <= '9'))
++        s = (v[10] - '0') * 10 + (v[11] - '0');
++
++    if (BIO_printf(bp, "%s %2d %02d:%02d:%02d %d%s",
++                   _asn1_mon[M - 1], d, h, m, s, y + 1900,
++                   (gmt) ? " GMT" : "") <= 0)
++        return (0);
++    else
++        return (1);
++ err:
++    BIO_write(bp, "Bad time value", 14);
++    return (0);
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/asn1/a_utf8.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/asn1/a_utf8.c
+new file mode 100644
+index 0000000..e2dc09f
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/asn1/a_utf8.c
+@@ -0,0 +1,188 @@
++/*
++ * Copyright 1995-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include "internal/cryptlib.h"
++#include 
++
++/* UTF8 utilities */
++
++/*-
++ * This parses a UTF8 string one character at a time. It is passed a pointer
++ * to the string and the length of the string. It sets 'value' to the value of
++ * the current character. It returns the number of characters read or a
++ * negative error code:
++ * -1 = string too short
++ * -2 = illegal character
++ * -3 = subsequent characters not of the form 10xxxxxx
++ * -4 = character encoded incorrectly (not minimal length).
++ */
++
++int UTF8_getc(const unsigned char *str, int len, unsigned long *val)
++{
++    const unsigned char *p;
++    unsigned long value;
++    int ret;
++    if (len <= 0)
++        return 0;
++    p = str;
++
++    /* Check syntax and work out the encoded value (if correct) */
++    if ((*p & 0x80) == 0) {
++        value = *p++ & 0x7f;
++        ret = 1;
++    } else if ((*p & 0xe0) == 0xc0) {
++        if (len < 2)
++            return -1;
++        if ((p[1] & 0xc0) != 0x80)
++            return -3;
++        value = (*p++ & 0x1f) << 6;
++        value |= *p++ & 0x3f;
++        if (value < 0x80)
++            return -4;
++        ret = 2;
++    } else if ((*p & 0xf0) == 0xe0) {
++        if (len < 3)
++            return -1;
++        if (((p[1] & 0xc0) != 0x80)
++            || ((p[2] & 0xc0) != 0x80))
++            return -3;
++        value = (*p++ & 0xf) << 12;
++        value |= (*p++ & 0x3f) << 6;
++        value |= *p++ & 0x3f;
++        if (value < 0x800)
++            return -4;
++        ret = 3;
++    } else if ((*p & 0xf8) == 0xf0) {
++        if (len < 4)
++            return -1;
++        if (((p[1] & 0xc0) != 0x80)
++            || ((p[2] & 0xc0) != 0x80)
++            || ((p[3] & 0xc0) != 0x80))
++            return -3;
++        value = ((unsigned long)(*p++ & 0x7)) << 18;
++        value |= (*p++ & 0x3f) << 12;
++        value |= (*p++ & 0x3f) << 6;
++        value |= *p++ & 0x3f;
++        if (value < 0x10000)
++            return -4;
++        ret = 4;
++    } else if ((*p & 0xfc) == 0xf8) {
++        if (len < 5)
++            return -1;
++        if (((p[1] & 0xc0) != 0x80)
++            || ((p[2] & 0xc0) != 0x80)
++            || ((p[3] & 0xc0) != 0x80)
++            || ((p[4] & 0xc0) != 0x80))
++            return -3;
++        value = ((unsigned long)(*p++ & 0x3)) << 24;
++        value |= ((unsigned long)(*p++ & 0x3f)) << 18;
++        value |= ((unsigned long)(*p++ & 0x3f)) << 12;
++        value |= (*p++ & 0x3f) << 6;
++        value |= *p++ & 0x3f;
++        if (value < 0x200000)
++            return -4;
++        ret = 5;
++    } else if ((*p & 0xfe) == 0xfc) {
++        if (len < 6)
++            return -1;
++        if (((p[1] & 0xc0) != 0x80)
++            || ((p[2] & 0xc0) != 0x80)
++            || ((p[3] & 0xc0) != 0x80)
++            || ((p[4] & 0xc0) != 0x80)
++            || ((p[5] & 0xc0) != 0x80))
++            return -3;
++        value = ((unsigned long)(*p++ & 0x1)) << 30;
++        value |= ((unsigned long)(*p++ & 0x3f)) << 24;
++        value |= ((unsigned long)(*p++ & 0x3f)) << 18;
++        value |= ((unsigned long)(*p++ & 0x3f)) << 12;
++        value |= (*p++ & 0x3f) << 6;
++        value |= *p++ & 0x3f;
++        if (value < 0x4000000)
++            return -4;
++        ret = 6;
++    } else
++        return -2;
++    *val = value;
++    return ret;
++}
++
++/*
++ * This takes a character 'value' and writes the UTF8 encoded value in 'str'
++ * where 'str' is a buffer containing 'len' characters. Returns the number of
++ * characters written or -1 if 'len' is too small. 'str' can be set to NULL
++ * in which case it just returns the number of characters. It will need at
++ * most 6 characters.
++ */
++
++int UTF8_putc(unsigned char *str, int len, unsigned long value)
++{
++    if (!str)
++        len = 6;                /* Maximum we will need */
++    else if (len <= 0)
++        return -1;
++    if (value < 0x80) {
++        if (str)
++            *str = (unsigned char)value;
++        return 1;
++    }
++    if (value < 0x800) {
++        if (len < 2)
++            return -1;
++        if (str) {
++            *str++ = (unsigned char)(((value >> 6) & 0x1f) | 0xc0);
++            *str = (unsigned char)((value & 0x3f) | 0x80);
++        }
++        return 2;
++    }
++    if (value < 0x10000) {
++        if (len < 3)
++            return -1;
++        if (str) {
++            *str++ = (unsigned char)(((value >> 12) & 0xf) | 0xe0);
++            *str++ = (unsigned char)(((value >> 6) & 0x3f) | 0x80);
++            *str = (unsigned char)((value & 0x3f) | 0x80);
++        }
++        return 3;
++    }
++    if (value < 0x200000) {
++        if (len < 4)
++            return -1;
++        if (str) {
++            *str++ = (unsigned char)(((value >> 18) & 0x7) | 0xf0);
++            *str++ = (unsigned char)(((value >> 12) & 0x3f) | 0x80);
++            *str++ = (unsigned char)(((value >> 6) & 0x3f) | 0x80);
++            *str = (unsigned char)((value & 0x3f) | 0x80);
++        }
++        return 4;
++    }
++    if (value < 0x4000000) {
++        if (len < 5)
++            return -1;
++        if (str) {
++            *str++ = (unsigned char)(((value >> 24) & 0x3) | 0xf8);
++            *str++ = (unsigned char)(((value >> 18) & 0x3f) | 0x80);
++            *str++ = (unsigned char)(((value >> 12) & 0x3f) | 0x80);
++            *str++ = (unsigned char)(((value >> 6) & 0x3f) | 0x80);
++            *str = (unsigned char)((value & 0x3f) | 0x80);
++        }
++        return 5;
++    }
++    if (len < 6)
++        return -1;
++    if (str) {
++        *str++ = (unsigned char)(((value >> 30) & 0x1) | 0xfc);
++        *str++ = (unsigned char)(((value >> 24) & 0x3f) | 0x80);
++        *str++ = (unsigned char)(((value >> 18) & 0x3f) | 0x80);
++        *str++ = (unsigned char)(((value >> 12) & 0x3f) | 0x80);
++        *str++ = (unsigned char)(((value >> 6) & 0x3f) | 0x80);
++        *str = (unsigned char)((value & 0x3f) | 0x80);
++    }
++    return 6;
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/asn1/a_verify.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/asn1/a_verify.c
+new file mode 100644
+index 0000000..00ab136
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/asn1/a_verify.c
+@@ -0,0 +1,182 @@
++/*
++ * Copyright 1995-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include 
++
++#include "internal/cryptlib.h"
++
++#ifndef NO_SYS_TYPES_H
++# include 
++#endif
++
++#include 
++#include 
++#include 
++#include 
++#include 
++#include "internal/asn1_int.h"
++#include "internal/evp_int.h"
++
++#ifndef NO_ASN1_OLD
++
++int ASN1_verify(i2d_of_void *i2d, X509_ALGOR *a, ASN1_BIT_STRING *signature,
++                char *data, EVP_PKEY *pkey)
++{
++    EVP_MD_CTX *ctx = EVP_MD_CTX_new();
++    const EVP_MD *type;
++    unsigned char *p, *buf_in = NULL;
++    int ret = -1, i, inl;
++
++    if (ctx == NULL) {
++        ASN1err(ASN1_F_ASN1_VERIFY, ERR_R_MALLOC_FAILURE);
++        goto err;
++    }
++    i = OBJ_obj2nid(a->algorithm);
++    type = EVP_get_digestbyname(OBJ_nid2sn(i));
++    if (type == NULL) {
++        ASN1err(ASN1_F_ASN1_VERIFY, ASN1_R_UNKNOWN_MESSAGE_DIGEST_ALGORITHM);
++        goto err;
++    }
++
++    if (signature->type == V_ASN1_BIT_STRING && signature->flags & 0x7) {
++        ASN1err(ASN1_F_ASN1_VERIFY, ASN1_R_INVALID_BIT_STRING_BITS_LEFT);
++        goto err;
++    }
++
++    inl = i2d(data, NULL);
++    buf_in = OPENSSL_malloc((unsigned int)inl);
++    if (buf_in == NULL) {
++        ASN1err(ASN1_F_ASN1_VERIFY, ERR_R_MALLOC_FAILURE);
++        goto err;
++    }
++    p = buf_in;
++
++    i2d(data, &p);
++    ret = EVP_VerifyInit_ex(ctx, type, NULL)
++        && EVP_VerifyUpdate(ctx, (unsigned char *)buf_in, inl);
++
++    OPENSSL_clear_free(buf_in, (unsigned int)inl);
++
++    if (!ret) {
++        ASN1err(ASN1_F_ASN1_VERIFY, ERR_R_EVP_LIB);
++        goto err;
++    }
++    ret = -1;
++
++    if (EVP_VerifyFinal(ctx, (unsigned char *)signature->data,
++                        (unsigned int)signature->length, pkey) <= 0) {
++        ASN1err(ASN1_F_ASN1_VERIFY, ERR_R_EVP_LIB);
++        ret = 0;
++        goto err;
++    }
++    ret = 1;
++ err:
++    EVP_MD_CTX_free(ctx);
++    return (ret);
++}
++
++#endif
++
++int ASN1_item_verify(const ASN1_ITEM *it, X509_ALGOR *a,
++                     ASN1_BIT_STRING *signature, void *asn, EVP_PKEY *pkey)
++{
++    EVP_MD_CTX *ctx = NULL;
++    unsigned char *buf_in = NULL;
++    int ret = -1, inl;
++
++    int mdnid, pknid;
++
++    if (!pkey) {
++        ASN1err(ASN1_F_ASN1_ITEM_VERIFY, ERR_R_PASSED_NULL_PARAMETER);
++        return -1;
++    }
++
++    if (signature->type == V_ASN1_BIT_STRING && signature->flags & 0x7) {
++        ASN1err(ASN1_F_ASN1_ITEM_VERIFY, ASN1_R_INVALID_BIT_STRING_BITS_LEFT);
++        return -1;
++    }
++
++    ctx = EVP_MD_CTX_new();
++    if (ctx == NULL) {
++        ASN1err(ASN1_F_ASN1_ITEM_VERIFY, ERR_R_MALLOC_FAILURE);
++        goto err;
++    }
++
++    /* Convert signature OID into digest and public key OIDs */
++    if (!OBJ_find_sigid_algs(OBJ_obj2nid(a->algorithm), &mdnid, &pknid)) {
++        ASN1err(ASN1_F_ASN1_ITEM_VERIFY, ASN1_R_UNKNOWN_SIGNATURE_ALGORITHM);
++        goto err;
++    }
++    if (mdnid == NID_undef) {
++        if (!pkey->ameth || !pkey->ameth->item_verify) {
++            ASN1err(ASN1_F_ASN1_ITEM_VERIFY,
++                    ASN1_R_UNKNOWN_SIGNATURE_ALGORITHM);
++            goto err;
++        }
++        ret = pkey->ameth->item_verify(ctx, it, asn, a, signature, pkey);
++        /*
++         * Return value of 2 means carry on, anything else means we exit
++         * straight away: either a fatal error of the underlying verification
++         * routine handles all verification.
++         */
++        if (ret != 2)
++            goto err;
++        ret = -1;
++    } else {
++        const EVP_MD *type;
++        type = EVP_get_digestbynid(mdnid);
++        if (type == NULL) {
++            ASN1err(ASN1_F_ASN1_ITEM_VERIFY,
++                    ASN1_R_UNKNOWN_MESSAGE_DIGEST_ALGORITHM);
++            goto err;
++        }
++
++        /* Check public key OID matches public key type */
++        if (EVP_PKEY_type(pknid) != pkey->ameth->pkey_id) {
++            ASN1err(ASN1_F_ASN1_ITEM_VERIFY, ASN1_R_WRONG_PUBLIC_KEY_TYPE);
++            goto err;
++        }
++
++        if (!EVP_DigestVerifyInit(ctx, NULL, type, NULL, pkey)) {
++            ASN1err(ASN1_F_ASN1_ITEM_VERIFY, ERR_R_EVP_LIB);
++            ret = 0;
++            goto err;
++        }
++
++    }
++
++    inl = ASN1_item_i2d(asn, &buf_in, it);
++
++    if (buf_in == NULL) {
++        ASN1err(ASN1_F_ASN1_ITEM_VERIFY, ERR_R_MALLOC_FAILURE);
++        goto err;
++    }
++
++    ret = EVP_DigestVerifyUpdate(ctx, buf_in, inl);
++
++    OPENSSL_clear_free(buf_in, (unsigned int)inl);
++
++    if (!ret) {
++        ASN1err(ASN1_F_ASN1_ITEM_VERIFY, ERR_R_EVP_LIB);
++        goto err;
++    }
++    ret = -1;
++
++    if (EVP_DigestVerifyFinal(ctx, signature->data,
++                              (size_t)signature->length) <= 0) {
++        ASN1err(ASN1_F_ASN1_ITEM_VERIFY, ERR_R_EVP_LIB);
++        ret = 0;
++        goto err;
++    }
++    ret = 1;
++ err:
++    EVP_MD_CTX_free(ctx);
++    return (ret);
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/asn1/ameth_lib.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/asn1/ameth_lib.c
+new file mode 100644
+index 0000000..cfde49a
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/asn1/ameth_lib.c
+@@ -0,0 +1,400 @@
++/*
++ * Copyright 2006-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include "internal/cryptlib.h"
++#include 
++#include 
++#include 
++#include "internal/asn1_int.h"
++#include "internal/evp_int.h"
++
++/* Keep this sorted in type order !! */
++static const EVP_PKEY_ASN1_METHOD *standard_methods[] = {
++#ifndef OPENSSL_NO_RSA
++    &rsa_asn1_meths[0],
++    &rsa_asn1_meths[1],
++#endif
++#ifndef OPENSSL_NO_DH
++    &dh_asn1_meth,
++#endif
++#ifndef OPENSSL_NO_DSA
++    &dsa_asn1_meths[0],
++    &dsa_asn1_meths[1],
++    &dsa_asn1_meths[2],
++    &dsa_asn1_meths[3],
++    &dsa_asn1_meths[4],
++#endif
++#ifndef OPENSSL_NO_EC
++    &eckey_asn1_meth,
++#endif
++    &hmac_asn1_meth,
++#ifndef OPENSSL_NO_CMAC
++    &cmac_asn1_meth,
++#endif
++#ifndef OPENSSL_NO_DH
++    &dhx_asn1_meth,
++#endif
++#ifndef OPENSSL_NO_EC
++    &ecx25519_asn1_meth
++#endif
++};
++
++typedef int sk_cmp_fn_type(const char *const *a, const char *const *b);
++static STACK_OF(EVP_PKEY_ASN1_METHOD) *app_methods = NULL;
++
++#ifdef TEST
++void main()
++{
++    int i;
++    for (i = 0; i < OSSL_NELEM(standard_methods); i++)
++        fprintf(stderr, "Number %d id=%d (%s)\n", i,
++                standard_methods[i]->pkey_id,
++                OBJ_nid2sn(standard_methods[i]->pkey_id));
++}
++#endif
++
++DECLARE_OBJ_BSEARCH_CMP_FN(const EVP_PKEY_ASN1_METHOD *,
++                           const EVP_PKEY_ASN1_METHOD *, ameth);
++
++static int ameth_cmp(const EVP_PKEY_ASN1_METHOD *const *a,
++                     const EVP_PKEY_ASN1_METHOD *const *b)
++{
++    return ((*a)->pkey_id - (*b)->pkey_id);
++}
++
++IMPLEMENT_OBJ_BSEARCH_CMP_FN(const EVP_PKEY_ASN1_METHOD *,
++                             const EVP_PKEY_ASN1_METHOD *, ameth);
++
++int EVP_PKEY_asn1_get_count(void)
++{
++    int num = OSSL_NELEM(standard_methods);
++    if (app_methods)
++        num += sk_EVP_PKEY_ASN1_METHOD_num(app_methods);
++    return num;
++}
++
++const EVP_PKEY_ASN1_METHOD *EVP_PKEY_asn1_get0(int idx)
++{
++    int num = OSSL_NELEM(standard_methods);
++    if (idx < 0)
++        return NULL;
++    if (idx < num)
++        return standard_methods[idx];
++    idx -= num;
++    return sk_EVP_PKEY_ASN1_METHOD_value(app_methods, idx);
++}
++
++static const EVP_PKEY_ASN1_METHOD *pkey_asn1_find(int type)
++{
++    EVP_PKEY_ASN1_METHOD tmp;
++    const EVP_PKEY_ASN1_METHOD *t = &tmp, **ret;
++    tmp.pkey_id = type;
++    if (app_methods) {
++        int idx;
++        idx = sk_EVP_PKEY_ASN1_METHOD_find(app_methods, &tmp);
++        if (idx >= 0)
++            return sk_EVP_PKEY_ASN1_METHOD_value(app_methods, idx);
++    }
++    ret = OBJ_bsearch_ameth(&t, standard_methods, OSSL_NELEM(standard_methods));
++    if (!ret || !*ret)
++        return NULL;
++    return *ret;
++}
++
++/*
++ * Find an implementation of an ASN1 algorithm. If 'pe' is not NULL also
++ * search through engines and set *pe to a functional reference to the engine
++ * implementing 'type' or NULL if no engine implements it.
++ */
++
++const EVP_PKEY_ASN1_METHOD *EVP_PKEY_asn1_find(ENGINE **pe, int type)
++{
++    const EVP_PKEY_ASN1_METHOD *t;
++
++    for (;;) {
++        t = pkey_asn1_find(type);
++        if (!t || !(t->pkey_flags & ASN1_PKEY_ALIAS))
++            break;
++        type = t->pkey_base_id;
++    }
++    if (pe) {
++#ifndef OPENSSL_NO_ENGINE
++        ENGINE *e;
++        /* type will contain the final unaliased type */
++        e = ENGINE_get_pkey_asn1_meth_engine(type);
++        if (e) {
++            *pe = e;
++            return ENGINE_get_pkey_asn1_meth(e, type);
++        }
++#endif
++        *pe = NULL;
++    }
++    return t;
++}
++
++const EVP_PKEY_ASN1_METHOD *EVP_PKEY_asn1_find_str(ENGINE **pe,
++                                                   const char *str, int len)
++{
++    int i;
++    const EVP_PKEY_ASN1_METHOD *ameth;
++    if (len == -1)
++        len = strlen(str);
++    if (pe) {
++#ifndef OPENSSL_NO_ENGINE
++        ENGINE *e;
++        ameth = ENGINE_pkey_asn1_find_str(&e, str, len);
++        if (ameth) {
++            /*
++             * Convert structural into functional reference
++             */
++            if (!ENGINE_init(e))
++                ameth = NULL;
++            ENGINE_free(e);
++            *pe = e;
++            return ameth;
++        }
++#endif
++        *pe = NULL;
++    }
++    for (i = 0; i < EVP_PKEY_asn1_get_count(); i++) {
++        ameth = EVP_PKEY_asn1_get0(i);
++        if (ameth->pkey_flags & ASN1_PKEY_ALIAS)
++            continue;
++        if (((int)strlen(ameth->pem_str) == len)
++            && (strncasecmp(ameth->pem_str, str, len) == 0))
++            return ameth;
++    }
++    return NULL;
++}
++
++int EVP_PKEY_asn1_add0(const EVP_PKEY_ASN1_METHOD *ameth)
++{
++    if (app_methods == NULL) {
++        app_methods = sk_EVP_PKEY_ASN1_METHOD_new(ameth_cmp);
++        if (app_methods == NULL)
++            return 0;
++    }
++    if (!sk_EVP_PKEY_ASN1_METHOD_push(app_methods, ameth))
++        return 0;
++    sk_EVP_PKEY_ASN1_METHOD_sort(app_methods);
++    return 1;
++}
++
++int EVP_PKEY_asn1_add_alias(int to, int from)
++{
++    EVP_PKEY_ASN1_METHOD *ameth;
++    ameth = EVP_PKEY_asn1_new(from, ASN1_PKEY_ALIAS, NULL, NULL);
++    if (ameth == NULL)
++        return 0;
++    ameth->pkey_base_id = to;
++    if (!EVP_PKEY_asn1_add0(ameth)) {
++        EVP_PKEY_asn1_free(ameth);
++        return 0;
++    }
++    return 1;
++}
++
++int EVP_PKEY_asn1_get0_info(int *ppkey_id, int *ppkey_base_id,
++                            int *ppkey_flags, const char **pinfo,
++                            const char **ppem_str,
++                            const EVP_PKEY_ASN1_METHOD *ameth)
++{
++    if (!ameth)
++        return 0;
++    if (ppkey_id)
++        *ppkey_id = ameth->pkey_id;
++    if (ppkey_base_id)
++        *ppkey_base_id = ameth->pkey_base_id;
++    if (ppkey_flags)
++        *ppkey_flags = ameth->pkey_flags;
++    if (pinfo)
++        *pinfo = ameth->info;
++    if (ppem_str)
++        *ppem_str = ameth->pem_str;
++    return 1;
++}
++
++const EVP_PKEY_ASN1_METHOD *EVP_PKEY_get0_asn1(const EVP_PKEY *pkey)
++{
++    return pkey->ameth;
++}
++
++EVP_PKEY_ASN1_METHOD *EVP_PKEY_asn1_new(int id, int flags,
++                                        const char *pem_str, const char *info)
++{
++    EVP_PKEY_ASN1_METHOD *ameth = OPENSSL_zalloc(sizeof(*ameth));
++
++    if (ameth == NULL)
++        return NULL;
++
++    ameth->pkey_id = id;
++    ameth->pkey_base_id = id;
++    ameth->pkey_flags = flags | ASN1_PKEY_DYNAMIC;
++
++    if (info) {
++        ameth->info = OPENSSL_strdup(info);
++        if (!ameth->info)
++            goto err;
++    }
++
++    if (pem_str) {
++        ameth->pem_str = OPENSSL_strdup(pem_str);
++        if (!ameth->pem_str)
++            goto err;
++    }
++
++    return ameth;
++
++ err:
++    EVP_PKEY_asn1_free(ameth);
++    return NULL;
++
++}
++
++void EVP_PKEY_asn1_copy(EVP_PKEY_ASN1_METHOD *dst,
++                        const EVP_PKEY_ASN1_METHOD *src)
++{
++
++    dst->pub_decode = src->pub_decode;
++    dst->pub_encode = src->pub_encode;
++    dst->pub_cmp = src->pub_cmp;
++    dst->pub_print = src->pub_print;
++
++    dst->priv_decode = src->priv_decode;
++    dst->priv_encode = src->priv_encode;
++    dst->priv_print = src->priv_print;
++
++    dst->old_priv_encode = src->old_priv_encode;
++    dst->old_priv_decode = src->old_priv_decode;
++
++    dst->pkey_size = src->pkey_size;
++    dst->pkey_bits = src->pkey_bits;
++
++    dst->param_decode = src->param_decode;
++    dst->param_encode = src->param_encode;
++    dst->param_missing = src->param_missing;
++    dst->param_copy = src->param_copy;
++    dst->param_cmp = src->param_cmp;
++    dst->param_print = src->param_print;
++
++    dst->pkey_free = src->pkey_free;
++    dst->pkey_ctrl = src->pkey_ctrl;
++
++    dst->item_sign = src->item_sign;
++    dst->item_verify = src->item_verify;
++
++}
++
++void EVP_PKEY_asn1_free(EVP_PKEY_ASN1_METHOD *ameth)
++{
++    if (ameth && (ameth->pkey_flags & ASN1_PKEY_DYNAMIC)) {
++        OPENSSL_free(ameth->pem_str);
++        OPENSSL_free(ameth->info);
++        OPENSSL_free(ameth);
++    }
++}
++
++void EVP_PKEY_asn1_set_public(EVP_PKEY_ASN1_METHOD *ameth,
++                              int (*pub_decode) (EVP_PKEY *pk,
++                                                 X509_PUBKEY *pub),
++                              int (*pub_encode) (X509_PUBKEY *pub,
++                                                 const EVP_PKEY *pk),
++                              int (*pub_cmp) (const EVP_PKEY *a,
++                                              const EVP_PKEY *b),
++                              int (*pub_print) (BIO *out,
++                                                const EVP_PKEY *pkey,
++                                                int indent, ASN1_PCTX *pctx),
++                              int (*pkey_size) (const EVP_PKEY *pk),
++                              int (*pkey_bits) (const EVP_PKEY *pk))
++{
++    ameth->pub_decode = pub_decode;
++    ameth->pub_encode = pub_encode;
++    ameth->pub_cmp = pub_cmp;
++    ameth->pub_print = pub_print;
++    ameth->pkey_size = pkey_size;
++    ameth->pkey_bits = pkey_bits;
++}
++
++void EVP_PKEY_asn1_set_private(EVP_PKEY_ASN1_METHOD *ameth,
++                               int (*priv_decode) (EVP_PKEY *pk,
++                                                   const PKCS8_PRIV_KEY_INFO
++                                                   *p8inf),
++                               int (*priv_encode) (PKCS8_PRIV_KEY_INFO *p8,
++                                                   const EVP_PKEY *pk),
++                               int (*priv_print) (BIO *out,
++                                                  const EVP_PKEY *pkey,
++                                                  int indent,
++                                                  ASN1_PCTX *pctx))
++{
++    ameth->priv_decode = priv_decode;
++    ameth->priv_encode = priv_encode;
++    ameth->priv_print = priv_print;
++}
++
++void EVP_PKEY_asn1_set_param(EVP_PKEY_ASN1_METHOD *ameth,
++                             int (*param_decode) (EVP_PKEY *pkey,
++                                                  const unsigned char **pder,
++                                                  int derlen),
++                             int (*param_encode) (const EVP_PKEY *pkey,
++                                                  unsigned char **pder),
++                             int (*param_missing) (const EVP_PKEY *pk),
++                             int (*param_copy) (EVP_PKEY *to,
++                                                const EVP_PKEY *from),
++                             int (*param_cmp) (const EVP_PKEY *a,
++                                               const EVP_PKEY *b),
++                             int (*param_print) (BIO *out,
++                                                 const EVP_PKEY *pkey,
++                                                 int indent, ASN1_PCTX *pctx))
++{
++    ameth->param_decode = param_decode;
++    ameth->param_encode = param_encode;
++    ameth->param_missing = param_missing;
++    ameth->param_copy = param_copy;
++    ameth->param_cmp = param_cmp;
++    ameth->param_print = param_print;
++}
++
++void EVP_PKEY_asn1_set_free(EVP_PKEY_ASN1_METHOD *ameth,
++                            void (*pkey_free) (EVP_PKEY *pkey))
++{
++    ameth->pkey_free = pkey_free;
++}
++
++void EVP_PKEY_asn1_set_ctrl(EVP_PKEY_ASN1_METHOD *ameth,
++                            int (*pkey_ctrl) (EVP_PKEY *pkey, int op,
++                                              long arg1, void *arg2))
++{
++    ameth->pkey_ctrl = pkey_ctrl;
++}
++
++void EVP_PKEY_asn1_set_security_bits(EVP_PKEY_ASN1_METHOD *ameth,
++                                     int (*pkey_security_bits) (const EVP_PKEY
++                                                                *pk))
++{
++    ameth->pkey_security_bits = pkey_security_bits;
++}
++
++void EVP_PKEY_asn1_set_item(EVP_PKEY_ASN1_METHOD *ameth,
++                            int (*item_verify) (EVP_MD_CTX *ctx,
++                                                const ASN1_ITEM *it,
++                                                void *asn,
++                                                X509_ALGOR *a,
++                                                ASN1_BIT_STRING *sig,
++                                                EVP_PKEY *pkey),
++                            int (*item_sign) (EVP_MD_CTX *ctx,
++                                              const ASN1_ITEM *it,
++                                              void *asn,
++                                              X509_ALGOR *alg1,
++                                              X509_ALGOR *alg2,
++                                              ASN1_BIT_STRING *sig))
++{
++    ameth->item_sign = item_sign;
++    ameth->item_verify = item_verify;
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/asn1/asn1_err.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/asn1/asn1_err.c
+new file mode 100644
+index 0000000..97c3dec
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/asn1/asn1_err.c
+@@ -0,0 +1,267 @@
++/*
++ * Generated by util/mkerr.pl DO NOT EDIT
++ * Copyright 1995-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include 
++#include 
++
++/* BEGIN ERROR CODES */
++#ifndef OPENSSL_NO_ERR
++
++# define ERR_FUNC(func) ERR_PACK(ERR_LIB_ASN1,func,0)
++# define ERR_REASON(reason) ERR_PACK(ERR_LIB_ASN1,0,reason)
++
++static ERR_STRING_DATA ASN1_str_functs[] = {
++    {ERR_FUNC(ASN1_F_A2D_ASN1_OBJECT), "a2d_ASN1_OBJECT"},
++    {ERR_FUNC(ASN1_F_A2I_ASN1_INTEGER), "a2i_ASN1_INTEGER"},
++    {ERR_FUNC(ASN1_F_A2I_ASN1_STRING), "a2i_ASN1_STRING"},
++    {ERR_FUNC(ASN1_F_APPEND_EXP), "append_exp"},
++    {ERR_FUNC(ASN1_F_ASN1_BIT_STRING_SET_BIT), "ASN1_BIT_STRING_set_bit"},
++    {ERR_FUNC(ASN1_F_ASN1_CB), "asn1_cb"},
++    {ERR_FUNC(ASN1_F_ASN1_CHECK_TLEN), "asn1_check_tlen"},
++    {ERR_FUNC(ASN1_F_ASN1_COLLECT), "asn1_collect"},
++    {ERR_FUNC(ASN1_F_ASN1_D2I_EX_PRIMITIVE), "asn1_d2i_ex_primitive"},
++    {ERR_FUNC(ASN1_F_ASN1_D2I_FP), "ASN1_d2i_fp"},
++    {ERR_FUNC(ASN1_F_ASN1_D2I_READ_BIO), "asn1_d2i_read_bio"},
++    {ERR_FUNC(ASN1_F_ASN1_DIGEST), "ASN1_digest"},
++    {ERR_FUNC(ASN1_F_ASN1_DO_ADB), "asn1_do_adb"},
++    {ERR_FUNC(ASN1_F_ASN1_DO_LOCK), "asn1_do_lock"},
++    {ERR_FUNC(ASN1_F_ASN1_DUP), "ASN1_dup"},
++    {ERR_FUNC(ASN1_F_ASN1_EX_C2I), "asn1_ex_c2i"},
++    {ERR_FUNC(ASN1_F_ASN1_FIND_END), "asn1_find_end"},
++    {ERR_FUNC(ASN1_F_ASN1_GENERALIZEDTIME_ADJ), "ASN1_GENERALIZEDTIME_adj"},
++    {ERR_FUNC(ASN1_F_ASN1_GENERATE_V3), "ASN1_generate_v3"},
++    {ERR_FUNC(ASN1_F_ASN1_GET_INT64), "asn1_get_int64"},
++    {ERR_FUNC(ASN1_F_ASN1_GET_OBJECT), "ASN1_get_object"},
++    {ERR_FUNC(ASN1_F_ASN1_GET_UINT64), "asn1_get_uint64"},
++    {ERR_FUNC(ASN1_F_ASN1_I2D_BIO), "ASN1_i2d_bio"},
++    {ERR_FUNC(ASN1_F_ASN1_I2D_FP), "ASN1_i2d_fp"},
++    {ERR_FUNC(ASN1_F_ASN1_ITEM_D2I_FP), "ASN1_item_d2i_fp"},
++    {ERR_FUNC(ASN1_F_ASN1_ITEM_DUP), "ASN1_item_dup"},
++    {ERR_FUNC(ASN1_F_ASN1_ITEM_EMBED_D2I), "asn1_item_embed_d2i"},
++    {ERR_FUNC(ASN1_F_ASN1_ITEM_EMBED_NEW), "asn1_item_embed_new"},
++    {ERR_FUNC(ASN1_F_ASN1_ITEM_I2D_BIO), "ASN1_item_i2d_bio"},
++    {ERR_FUNC(ASN1_F_ASN1_ITEM_I2D_FP), "ASN1_item_i2d_fp"},
++    {ERR_FUNC(ASN1_F_ASN1_ITEM_PACK), "ASN1_item_pack"},
++    {ERR_FUNC(ASN1_F_ASN1_ITEM_SIGN), "ASN1_item_sign"},
++    {ERR_FUNC(ASN1_F_ASN1_ITEM_SIGN_CTX), "ASN1_item_sign_ctx"},
++    {ERR_FUNC(ASN1_F_ASN1_ITEM_UNPACK), "ASN1_item_unpack"},
++    {ERR_FUNC(ASN1_F_ASN1_ITEM_VERIFY), "ASN1_item_verify"},
++    {ERR_FUNC(ASN1_F_ASN1_MBSTRING_NCOPY), "ASN1_mbstring_ncopy"},
++    {ERR_FUNC(ASN1_F_ASN1_OBJECT_NEW), "ASN1_OBJECT_new"},
++    {ERR_FUNC(ASN1_F_ASN1_OUTPUT_DATA), "asn1_output_data"},
++    {ERR_FUNC(ASN1_F_ASN1_PCTX_NEW), "ASN1_PCTX_new"},
++    {ERR_FUNC(ASN1_F_ASN1_SCTX_NEW), "ASN1_SCTX_new"},
++    {ERR_FUNC(ASN1_F_ASN1_SIGN), "ASN1_sign"},
++    {ERR_FUNC(ASN1_F_ASN1_STR2TYPE), "asn1_str2type"},
++    {ERR_FUNC(ASN1_F_ASN1_STRING_GET_INT64), "asn1_string_get_int64"},
++    {ERR_FUNC(ASN1_F_ASN1_STRING_GET_UINT64), "asn1_string_get_uint64"},
++    {ERR_FUNC(ASN1_F_ASN1_STRING_SET), "ASN1_STRING_set"},
++    {ERR_FUNC(ASN1_F_ASN1_STRING_TABLE_ADD), "ASN1_STRING_TABLE_add"},
++    {ERR_FUNC(ASN1_F_ASN1_STRING_TO_BN), "asn1_string_to_bn"},
++    {ERR_FUNC(ASN1_F_ASN1_STRING_TYPE_NEW), "ASN1_STRING_type_new"},
++    {ERR_FUNC(ASN1_F_ASN1_TEMPLATE_EX_D2I), "asn1_template_ex_d2i"},
++    {ERR_FUNC(ASN1_F_ASN1_TEMPLATE_NEW), "asn1_template_new"},
++    {ERR_FUNC(ASN1_F_ASN1_TEMPLATE_NOEXP_D2I), "asn1_template_noexp_d2i"},
++    {ERR_FUNC(ASN1_F_ASN1_TIME_ADJ), "ASN1_TIME_adj"},
++    {ERR_FUNC(ASN1_F_ASN1_TYPE_GET_INT_OCTETSTRING),
++     "ASN1_TYPE_get_int_octetstring"},
++    {ERR_FUNC(ASN1_F_ASN1_TYPE_GET_OCTETSTRING), "ASN1_TYPE_get_octetstring"},
++    {ERR_FUNC(ASN1_F_ASN1_UTCTIME_ADJ), "ASN1_UTCTIME_adj"},
++    {ERR_FUNC(ASN1_F_ASN1_VERIFY), "ASN1_verify"},
++    {ERR_FUNC(ASN1_F_B64_READ_ASN1), "b64_read_asn1"},
++    {ERR_FUNC(ASN1_F_B64_WRITE_ASN1), "B64_write_ASN1"},
++    {ERR_FUNC(ASN1_F_BIO_NEW_NDEF), "BIO_new_NDEF"},
++    {ERR_FUNC(ASN1_F_BITSTR_CB), "bitstr_cb"},
++    {ERR_FUNC(ASN1_F_BN_TO_ASN1_STRING), "bn_to_asn1_string"},
++    {ERR_FUNC(ASN1_F_C2I_ASN1_BIT_STRING), "c2i_ASN1_BIT_STRING"},
++    {ERR_FUNC(ASN1_F_C2I_ASN1_INTEGER), "c2i_ASN1_INTEGER"},
++    {ERR_FUNC(ASN1_F_C2I_ASN1_OBJECT), "c2i_ASN1_OBJECT"},
++    {ERR_FUNC(ASN1_F_C2I_IBUF), "c2i_ibuf"},
++    {ERR_FUNC(ASN1_F_COLLECT_DATA), "collect_data"},
++    {ERR_FUNC(ASN1_F_D2I_ASN1_OBJECT), "d2i_ASN1_OBJECT"},
++    {ERR_FUNC(ASN1_F_D2I_ASN1_UINTEGER), "d2i_ASN1_UINTEGER"},
++    {ERR_FUNC(ASN1_F_D2I_AUTOPRIVATEKEY), "d2i_AutoPrivateKey"},
++    {ERR_FUNC(ASN1_F_D2I_PRIVATEKEY), "d2i_PrivateKey"},
++    {ERR_FUNC(ASN1_F_D2I_PUBLICKEY), "d2i_PublicKey"},
++    {ERR_FUNC(ASN1_F_DO_TCREATE), "do_tcreate"},
++    {ERR_FUNC(ASN1_F_I2D_ASN1_BIO_STREAM), "i2d_ASN1_bio_stream"},
++    {ERR_FUNC(ASN1_F_I2D_DSA_PUBKEY), "i2d_DSA_PUBKEY"},
++    {ERR_FUNC(ASN1_F_I2D_EC_PUBKEY), "i2d_EC_PUBKEY"},
++    {ERR_FUNC(ASN1_F_I2D_PRIVATEKEY), "i2d_PrivateKey"},
++    {ERR_FUNC(ASN1_F_I2D_PUBLICKEY), "i2d_PublicKey"},
++    {ERR_FUNC(ASN1_F_I2D_RSA_PUBKEY), "i2d_RSA_PUBKEY"},
++    {ERR_FUNC(ASN1_F_LONG_C2I), "long_c2i"},
++    {ERR_FUNC(ASN1_F_OID_MODULE_INIT), "oid_module_init"},
++    {ERR_FUNC(ASN1_F_PARSE_TAGGING), "parse_tagging"},
++    {ERR_FUNC(ASN1_F_PKCS5_PBE2_SET_IV), "PKCS5_pbe2_set_iv"},
++    {ERR_FUNC(ASN1_F_PKCS5_PBE2_SET_SCRYPT), "PKCS5_pbe2_set_scrypt"},
++    {ERR_FUNC(ASN1_F_PKCS5_PBE_SET), "PKCS5_pbe_set"},
++    {ERR_FUNC(ASN1_F_PKCS5_PBE_SET0_ALGOR), "PKCS5_pbe_set0_algor"},
++    {ERR_FUNC(ASN1_F_PKCS5_PBKDF2_SET), "PKCS5_pbkdf2_set"},
++    {ERR_FUNC(ASN1_F_PKCS5_SCRYPT_SET), "pkcs5_scrypt_set"},
++    {ERR_FUNC(ASN1_F_SMIME_READ_ASN1), "SMIME_read_ASN1"},
++    {ERR_FUNC(ASN1_F_SMIME_TEXT), "SMIME_text"},
++    {ERR_FUNC(ASN1_F_STBL_MODULE_INIT), "stbl_module_init"},
++    {ERR_FUNC(ASN1_F_X509_CRL_ADD0_REVOKED), "X509_CRL_add0_revoked"},
++    {ERR_FUNC(ASN1_F_X509_INFO_NEW), "X509_INFO_new"},
++    {ERR_FUNC(ASN1_F_X509_NAME_ENCODE), "x509_name_encode"},
++    {ERR_FUNC(ASN1_F_X509_NAME_EX_D2I), "x509_name_ex_d2i"},
++    {ERR_FUNC(ASN1_F_X509_NAME_EX_NEW), "x509_name_ex_new"},
++    {ERR_FUNC(ASN1_F_X509_PKEY_NEW), "X509_PKEY_new"},
++    {0, NULL}
++};
++
++static ERR_STRING_DATA ASN1_str_reasons[] = {
++    {ERR_REASON(ASN1_R_ADDING_OBJECT), "adding object"},
++    {ERR_REASON(ASN1_R_ASN1_PARSE_ERROR), "asn1 parse error"},
++    {ERR_REASON(ASN1_R_ASN1_SIG_PARSE_ERROR), "asn1 sig parse error"},
++    {ERR_REASON(ASN1_R_AUX_ERROR), "aux error"},
++    {ERR_REASON(ASN1_R_BAD_OBJECT_HEADER), "bad object header"},
++    {ERR_REASON(ASN1_R_BMPSTRING_IS_WRONG_LENGTH),
++     "bmpstring is wrong length"},
++    {ERR_REASON(ASN1_R_BN_LIB), "bn lib"},
++    {ERR_REASON(ASN1_R_BOOLEAN_IS_WRONG_LENGTH), "boolean is wrong length"},
++    {ERR_REASON(ASN1_R_BUFFER_TOO_SMALL), "buffer too small"},
++    {ERR_REASON(ASN1_R_CIPHER_HAS_NO_OBJECT_IDENTIFIER),
++     "cipher has no object identifier"},
++    {ERR_REASON(ASN1_R_CONTEXT_NOT_INITIALISED), "context not initialised"},
++    {ERR_REASON(ASN1_R_DATA_IS_WRONG), "data is wrong"},
++    {ERR_REASON(ASN1_R_DECODE_ERROR), "decode error"},
++    {ERR_REASON(ASN1_R_DEPTH_EXCEEDED), "depth exceeded"},
++    {ERR_REASON(ASN1_R_DIGEST_AND_KEY_TYPE_NOT_SUPPORTED),
++     "digest and key type not supported"},
++    {ERR_REASON(ASN1_R_ENCODE_ERROR), "encode error"},
++    {ERR_REASON(ASN1_R_ERROR_GETTING_TIME), "error getting time"},
++    {ERR_REASON(ASN1_R_ERROR_LOADING_SECTION), "error loading section"},
++    {ERR_REASON(ASN1_R_ERROR_SETTING_CIPHER_PARAMS),
++     "error setting cipher params"},
++    {ERR_REASON(ASN1_R_EXPECTING_AN_INTEGER), "expecting an integer"},
++    {ERR_REASON(ASN1_R_EXPECTING_AN_OBJECT), "expecting an object"},
++    {ERR_REASON(ASN1_R_EXPLICIT_LENGTH_MISMATCH), "explicit length mismatch"},
++    {ERR_REASON(ASN1_R_EXPLICIT_TAG_NOT_CONSTRUCTED),
++     "explicit tag not constructed"},
++    {ERR_REASON(ASN1_R_FIELD_MISSING), "field missing"},
++    {ERR_REASON(ASN1_R_FIRST_NUM_TOO_LARGE), "first num too large"},
++    {ERR_REASON(ASN1_R_HEADER_TOO_LONG), "header too long"},
++    {ERR_REASON(ASN1_R_ILLEGAL_BITSTRING_FORMAT), "illegal bitstring format"},
++    {ERR_REASON(ASN1_R_ILLEGAL_BOOLEAN), "illegal boolean"},
++    {ERR_REASON(ASN1_R_ILLEGAL_CHARACTERS), "illegal characters"},
++    {ERR_REASON(ASN1_R_ILLEGAL_FORMAT), "illegal format"},
++    {ERR_REASON(ASN1_R_ILLEGAL_HEX), "illegal hex"},
++    {ERR_REASON(ASN1_R_ILLEGAL_IMPLICIT_TAG), "illegal implicit tag"},
++    {ERR_REASON(ASN1_R_ILLEGAL_INTEGER), "illegal integer"},
++    {ERR_REASON(ASN1_R_ILLEGAL_NEGATIVE_VALUE), "illegal negative value"},
++    {ERR_REASON(ASN1_R_ILLEGAL_NESTED_TAGGING), "illegal nested tagging"},
++    {ERR_REASON(ASN1_R_ILLEGAL_NULL), "illegal null"},
++    {ERR_REASON(ASN1_R_ILLEGAL_NULL_VALUE), "illegal null value"},
++    {ERR_REASON(ASN1_R_ILLEGAL_OBJECT), "illegal object"},
++    {ERR_REASON(ASN1_R_ILLEGAL_OPTIONAL_ANY), "illegal optional any"},
++    {ERR_REASON(ASN1_R_ILLEGAL_OPTIONS_ON_ITEM_TEMPLATE),
++     "illegal options on item template"},
++    {ERR_REASON(ASN1_R_ILLEGAL_PADDING), "illegal padding"},
++    {ERR_REASON(ASN1_R_ILLEGAL_TAGGED_ANY), "illegal tagged any"},
++    {ERR_REASON(ASN1_R_ILLEGAL_TIME_VALUE), "illegal time value"},
++    {ERR_REASON(ASN1_R_ILLEGAL_ZERO_CONTENT), "illegal zero content"},
++    {ERR_REASON(ASN1_R_INTEGER_NOT_ASCII_FORMAT), "integer not ascii format"},
++    {ERR_REASON(ASN1_R_INTEGER_TOO_LARGE_FOR_LONG),
++     "integer too large for long"},
++    {ERR_REASON(ASN1_R_INVALID_BIT_STRING_BITS_LEFT),
++     "invalid bit string bits left"},
++    {ERR_REASON(ASN1_R_INVALID_BMPSTRING_LENGTH), "invalid bmpstring length"},
++    {ERR_REASON(ASN1_R_INVALID_DIGIT), "invalid digit"},
++    {ERR_REASON(ASN1_R_INVALID_MIME_TYPE), "invalid mime type"},
++    {ERR_REASON(ASN1_R_INVALID_MODIFIER), "invalid modifier"},
++    {ERR_REASON(ASN1_R_INVALID_NUMBER), "invalid number"},
++    {ERR_REASON(ASN1_R_INVALID_OBJECT_ENCODING), "invalid object encoding"},
++    {ERR_REASON(ASN1_R_INVALID_SCRYPT_PARAMETERS),
++     "invalid scrypt parameters"},
++    {ERR_REASON(ASN1_R_INVALID_SEPARATOR), "invalid separator"},
++    {ERR_REASON(ASN1_R_INVALID_STRING_TABLE_VALUE),
++     "invalid string table value"},
++    {ERR_REASON(ASN1_R_INVALID_UNIVERSALSTRING_LENGTH),
++     "invalid universalstring length"},
++    {ERR_REASON(ASN1_R_INVALID_UTF8STRING), "invalid utf8string"},
++    {ERR_REASON(ASN1_R_INVALID_VALUE), "invalid value"},
++    {ERR_REASON(ASN1_R_LIST_ERROR), "list error"},
++    {ERR_REASON(ASN1_R_MIME_NO_CONTENT_TYPE), "mime no content type"},
++    {ERR_REASON(ASN1_R_MIME_PARSE_ERROR), "mime parse error"},
++    {ERR_REASON(ASN1_R_MIME_SIG_PARSE_ERROR), "mime sig parse error"},
++    {ERR_REASON(ASN1_R_MISSING_EOC), "missing eoc"},
++    {ERR_REASON(ASN1_R_MISSING_SECOND_NUMBER), "missing second number"},
++    {ERR_REASON(ASN1_R_MISSING_VALUE), "missing value"},
++    {ERR_REASON(ASN1_R_MSTRING_NOT_UNIVERSAL), "mstring not universal"},
++    {ERR_REASON(ASN1_R_MSTRING_WRONG_TAG), "mstring wrong tag"},
++    {ERR_REASON(ASN1_R_NESTED_ASN1_STRING), "nested asn1 string"},
++    {ERR_REASON(ASN1_R_NON_HEX_CHARACTERS), "non hex characters"},
++    {ERR_REASON(ASN1_R_NOT_ASCII_FORMAT), "not ascii format"},
++    {ERR_REASON(ASN1_R_NOT_ENOUGH_DATA), "not enough data"},
++    {ERR_REASON(ASN1_R_NO_CONTENT_TYPE), "no content type"},
++    {ERR_REASON(ASN1_R_NO_MATCHING_CHOICE_TYPE), "no matching choice type"},
++    {ERR_REASON(ASN1_R_NO_MULTIPART_BODY_FAILURE),
++     "no multipart body failure"},
++    {ERR_REASON(ASN1_R_NO_MULTIPART_BOUNDARY), "no multipart boundary"},
++    {ERR_REASON(ASN1_R_NO_SIG_CONTENT_TYPE), "no sig content type"},
++    {ERR_REASON(ASN1_R_NULL_IS_WRONG_LENGTH), "null is wrong length"},
++    {ERR_REASON(ASN1_R_OBJECT_NOT_ASCII_FORMAT), "object not ascii format"},
++    {ERR_REASON(ASN1_R_ODD_NUMBER_OF_CHARS), "odd number of chars"},
++    {ERR_REASON(ASN1_R_SECOND_NUMBER_TOO_LARGE), "second number too large"},
++    {ERR_REASON(ASN1_R_SEQUENCE_LENGTH_MISMATCH), "sequence length mismatch"},
++    {ERR_REASON(ASN1_R_SEQUENCE_NOT_CONSTRUCTED), "sequence not constructed"},
++    {ERR_REASON(ASN1_R_SEQUENCE_OR_SET_NEEDS_CONFIG),
++     "sequence or set needs config"},
++    {ERR_REASON(ASN1_R_SHORT_LINE), "short line"},
++    {ERR_REASON(ASN1_R_SIG_INVALID_MIME_TYPE), "sig invalid mime type"},
++    {ERR_REASON(ASN1_R_STREAMING_NOT_SUPPORTED), "streaming not supported"},
++    {ERR_REASON(ASN1_R_STRING_TOO_LONG), "string too long"},
++    {ERR_REASON(ASN1_R_STRING_TOO_SHORT), "string too short"},
++    {ERR_REASON(ASN1_R_THE_ASN1_OBJECT_IDENTIFIER_IS_NOT_KNOWN_FOR_THIS_MD),
++     "the asn1 object identifier is not known for this md"},
++    {ERR_REASON(ASN1_R_TIME_NOT_ASCII_FORMAT), "time not ascii format"},
++    {ERR_REASON(ASN1_R_TOO_LARGE), "too large"},
++    {ERR_REASON(ASN1_R_TOO_LONG), "too long"},
++    {ERR_REASON(ASN1_R_TOO_SMALL), "too small"},
++    {ERR_REASON(ASN1_R_TYPE_NOT_CONSTRUCTED), "type not constructed"},
++    {ERR_REASON(ASN1_R_TYPE_NOT_PRIMITIVE), "type not primitive"},
++    {ERR_REASON(ASN1_R_UNEXPECTED_EOC), "unexpected eoc"},
++    {ERR_REASON(ASN1_R_UNIVERSALSTRING_IS_WRONG_LENGTH),
++     "universalstring is wrong length"},
++    {ERR_REASON(ASN1_R_UNKNOWN_FORMAT), "unknown format"},
++    {ERR_REASON(ASN1_R_UNKNOWN_MESSAGE_DIGEST_ALGORITHM),
++     "unknown message digest algorithm"},
++    {ERR_REASON(ASN1_R_UNKNOWN_OBJECT_TYPE), "unknown object type"},
++    {ERR_REASON(ASN1_R_UNKNOWN_PUBLIC_KEY_TYPE), "unknown public key type"},
++    {ERR_REASON(ASN1_R_UNKNOWN_SIGNATURE_ALGORITHM),
++     "unknown signature algorithm"},
++    {ERR_REASON(ASN1_R_UNKNOWN_TAG), "unknown tag"},
++    {ERR_REASON(ASN1_R_UNSUPPORTED_ANY_DEFINED_BY_TYPE),
++     "unsupported any defined by type"},
++    {ERR_REASON(ASN1_R_UNSUPPORTED_PUBLIC_KEY_TYPE),
++     "unsupported public key type"},
++    {ERR_REASON(ASN1_R_UNSUPPORTED_TYPE), "unsupported type"},
++    {ERR_REASON(ASN1_R_WRONG_INTEGER_TYPE), "wrong integer type"},
++    {ERR_REASON(ASN1_R_WRONG_PUBLIC_KEY_TYPE), "wrong public key type"},
++    {ERR_REASON(ASN1_R_WRONG_TAG), "wrong tag"},
++    {0, NULL}
++};
++
++#endif
++
++int ERR_load_ASN1_strings(void)
++{
++#ifndef OPENSSL_NO_ERR
++
++    if (ERR_func_error_string(ASN1_str_functs[0].error) == NULL) {
++        ERR_load_strings(0, ASN1_str_functs);
++        ERR_load_strings(0, ASN1_str_reasons);
++    }
++#endif
++    return 1;
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/asn1/asn1_gen.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/asn1/asn1_gen.c
+new file mode 100644
+index 0000000..493a693
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/asn1/asn1_gen.c
+@@ -0,0 +1,789 @@
++/*
++ * Copyright 2002-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include "internal/cryptlib.h"
++#include 
++#include 
++
++#define ASN1_GEN_FLAG           0x10000
++#define ASN1_GEN_FLAG_IMP       (ASN1_GEN_FLAG|1)
++#define ASN1_GEN_FLAG_EXP       (ASN1_GEN_FLAG|2)
++#define ASN1_GEN_FLAG_TAG       (ASN1_GEN_FLAG|3)
++#define ASN1_GEN_FLAG_BITWRAP   (ASN1_GEN_FLAG|4)
++#define ASN1_GEN_FLAG_OCTWRAP   (ASN1_GEN_FLAG|5)
++#define ASN1_GEN_FLAG_SEQWRAP   (ASN1_GEN_FLAG|6)
++#define ASN1_GEN_FLAG_SETWRAP   (ASN1_GEN_FLAG|7)
++#define ASN1_GEN_FLAG_FORMAT    (ASN1_GEN_FLAG|8)
++
++#define ASN1_GEN_STR(str,val)   {str, sizeof(str) - 1, val}
++
++#define ASN1_FLAG_EXP_MAX       20
++/* Maximum number of nested sequences */
++#define ASN1_GEN_SEQ_MAX_DEPTH  50
++
++/* Input formats */
++
++/* ASCII: default */
++#define ASN1_GEN_FORMAT_ASCII   1
++/* UTF8 */
++#define ASN1_GEN_FORMAT_UTF8    2
++/* Hex */
++#define ASN1_GEN_FORMAT_HEX     3
++/* List of bits */
++#define ASN1_GEN_FORMAT_BITLIST 4
++
++struct tag_name_st {
++    const char *strnam;
++    int len;
++    int tag;
++};
++
++typedef struct {
++    int exp_tag;
++    int exp_class;
++    int exp_constructed;
++    int exp_pad;
++    long exp_len;
++} tag_exp_type;
++
++typedef struct {
++    int imp_tag;
++    int imp_class;
++    int utype;
++    int format;
++    const char *str;
++    tag_exp_type exp_list[ASN1_FLAG_EXP_MAX];
++    int exp_count;
++} tag_exp_arg;
++
++static ASN1_TYPE *generate_v3(const char *str, X509V3_CTX *cnf, int depth,
++                              int *perr);
++static int bitstr_cb(const char *elem, int len, void *bitstr);
++static int asn1_cb(const char *elem, int len, void *bitstr);
++static int append_exp(tag_exp_arg *arg, int exp_tag, int exp_class,
++                      int exp_constructed, int exp_pad, int imp_ok);
++static int parse_tagging(const char *vstart, int vlen, int *ptag,
++                         int *pclass);
++static ASN1_TYPE *asn1_multi(int utype, const char *section, X509V3_CTX *cnf,
++                             int depth, int *perr);
++static ASN1_TYPE *asn1_str2type(const char *str, int format, int utype);
++static int asn1_str2tag(const char *tagstr, int len);
++
++ASN1_TYPE *ASN1_generate_nconf(const char *str, CONF *nconf)
++{
++    X509V3_CTX cnf;
++
++    if (!nconf)
++        return ASN1_generate_v3(str, NULL);
++
++    X509V3_set_nconf(&cnf, nconf);
++    return ASN1_generate_v3(str, &cnf);
++}
++
++ASN1_TYPE *ASN1_generate_v3(const char *str, X509V3_CTX *cnf)
++{
++    int err = 0;
++    ASN1_TYPE *ret = generate_v3(str, cnf, 0, &err);
++    if (err)
++        ASN1err(ASN1_F_ASN1_GENERATE_V3, err);
++    return ret;
++}
++
++static ASN1_TYPE *generate_v3(const char *str, X509V3_CTX *cnf, int depth,
++                              int *perr)
++{
++    ASN1_TYPE *ret;
++    tag_exp_arg asn1_tags;
++    tag_exp_type *etmp;
++
++    int i, len;
++
++    unsigned char *orig_der = NULL, *new_der = NULL;
++    const unsigned char *cpy_start;
++    unsigned char *p;
++    const unsigned char *cp;
++    int cpy_len;
++    long hdr_len = 0;
++    int hdr_constructed = 0, hdr_tag, hdr_class;
++    int r;
++
++    asn1_tags.imp_tag = -1;
++    asn1_tags.imp_class = -1;
++    asn1_tags.format = ASN1_GEN_FORMAT_ASCII;
++    asn1_tags.exp_count = 0;
++    if (CONF_parse_list(str, ',', 1, asn1_cb, &asn1_tags) != 0) {
++        *perr = ASN1_R_UNKNOWN_TAG;
++        return NULL;
++    }
++
++    if ((asn1_tags.utype == V_ASN1_SEQUENCE)
++        || (asn1_tags.utype == V_ASN1_SET)) {
++        if (!cnf) {
++            *perr = ASN1_R_SEQUENCE_OR_SET_NEEDS_CONFIG;
++            return NULL;
++        }
++        if (depth >= ASN1_GEN_SEQ_MAX_DEPTH) {
++            *perr = ASN1_R_ILLEGAL_NESTED_TAGGING;
++            return NULL;
++        }
++        ret = asn1_multi(asn1_tags.utype, asn1_tags.str, cnf, depth, perr);
++    } else
++        ret = asn1_str2type(asn1_tags.str, asn1_tags.format, asn1_tags.utype);
++
++    if (!ret)
++        return NULL;
++
++    /* If no tagging return base type */
++    if ((asn1_tags.imp_tag == -1) && (asn1_tags.exp_count == 0))
++        return ret;
++
++    /* Generate the encoding */
++    cpy_len = i2d_ASN1_TYPE(ret, &orig_der);
++    ASN1_TYPE_free(ret);
++    ret = NULL;
++    /* Set point to start copying for modified encoding */
++    cpy_start = orig_der;
++
++    /* Do we need IMPLICIT tagging? */
++    if (asn1_tags.imp_tag != -1) {
++        /* If IMPLICIT we will replace the underlying tag */
++        /* Skip existing tag+len */
++        r = ASN1_get_object(&cpy_start, &hdr_len, &hdr_tag, &hdr_class,
++                            cpy_len);
++        if (r & 0x80)
++            goto err;
++        /* Update copy length */
++        cpy_len -= cpy_start - orig_der;
++        /*
++         * For IMPLICIT tagging the length should match the original length
++         * and constructed flag should be consistent.
++         */
++        if (r & 0x1) {
++            /* Indefinite length constructed */
++            hdr_constructed = 2;
++            hdr_len = 0;
++        } else
++            /* Just retain constructed flag */
++            hdr_constructed = r & V_ASN1_CONSTRUCTED;
++        /*
++         * Work out new length with IMPLICIT tag: ignore constructed because
++         * it will mess up if indefinite length
++         */
++        len = ASN1_object_size(0, hdr_len, asn1_tags.imp_tag);
++    } else
++        len = cpy_len;
++
++    /* Work out length in any EXPLICIT, starting from end */
++
++    for (i = 0, etmp = asn1_tags.exp_list + asn1_tags.exp_count - 1;
++         i < asn1_tags.exp_count; i++, etmp--) {
++        /* Content length: number of content octets + any padding */
++        len += etmp->exp_pad;
++        etmp->exp_len = len;
++        /* Total object length: length including new header */
++        len = ASN1_object_size(0, len, etmp->exp_tag);
++    }
++
++    /* Allocate buffer for new encoding */
++
++    new_der = OPENSSL_malloc(len);
++    if (new_der == NULL)
++        goto err;
++
++    /* Generate tagged encoding */
++
++    p = new_der;
++
++    /* Output explicit tags first */
++
++    for (i = 0, etmp = asn1_tags.exp_list; i < asn1_tags.exp_count;
++         i++, etmp++) {
++        ASN1_put_object(&p, etmp->exp_constructed, etmp->exp_len,
++                        etmp->exp_tag, etmp->exp_class);
++        if (etmp->exp_pad)
++            *p++ = 0;
++    }
++
++    /* If IMPLICIT, output tag */
++
++    if (asn1_tags.imp_tag != -1) {
++        if (asn1_tags.imp_class == V_ASN1_UNIVERSAL
++            && (asn1_tags.imp_tag == V_ASN1_SEQUENCE
++                || asn1_tags.imp_tag == V_ASN1_SET))
++            hdr_constructed = V_ASN1_CONSTRUCTED;
++        ASN1_put_object(&p, hdr_constructed, hdr_len,
++                        asn1_tags.imp_tag, asn1_tags.imp_class);
++    }
++
++    /* Copy across original encoding */
++    memcpy(p, cpy_start, cpy_len);
++
++    cp = new_der;
++
++    /* Obtain new ASN1_TYPE structure */
++    ret = d2i_ASN1_TYPE(NULL, &cp, len);
++
++ err:
++    OPENSSL_free(orig_der);
++    OPENSSL_free(new_der);
++
++    return ret;
++
++}
++
++static int asn1_cb(const char *elem, int len, void *bitstr)
++{
++    tag_exp_arg *arg = bitstr;
++    int i;
++    int utype;
++    int vlen = 0;
++    const char *p, *vstart = NULL;
++
++    int tmp_tag, tmp_class;
++
++    if (elem == NULL)
++        return -1;
++
++    for (i = 0, p = elem; i < len; p++, i++) {
++        /* Look for the ':' in name value pairs */
++        if (*p == ':') {
++            vstart = p + 1;
++            vlen = len - (vstart - elem);
++            len = p - elem;
++            break;
++        }
++    }
++
++    utype = asn1_str2tag(elem, len);
++
++    if (utype == -1) {
++        ASN1err(ASN1_F_ASN1_CB, ASN1_R_UNKNOWN_TAG);
++        ERR_add_error_data(2, "tag=", elem);
++        return -1;
++    }
++
++    /* If this is not a modifier mark end of string and exit */
++    if (!(utype & ASN1_GEN_FLAG)) {
++        arg->utype = utype;
++        arg->str = vstart;
++        /* If no value and not end of string, error */
++        if (!vstart && elem[len]) {
++            ASN1err(ASN1_F_ASN1_CB, ASN1_R_MISSING_VALUE);
++            return -1;
++        }
++        return 0;
++    }
++
++    switch (utype) {
++
++    case ASN1_GEN_FLAG_IMP:
++        /* Check for illegal multiple IMPLICIT tagging */
++        if (arg->imp_tag != -1) {
++            ASN1err(ASN1_F_ASN1_CB, ASN1_R_ILLEGAL_NESTED_TAGGING);
++            return -1;
++        }
++        if (!parse_tagging(vstart, vlen, &arg->imp_tag, &arg->imp_class))
++            return -1;
++        break;
++
++    case ASN1_GEN_FLAG_EXP:
++
++        if (!parse_tagging(vstart, vlen, &tmp_tag, &tmp_class))
++            return -1;
++        if (!append_exp(arg, tmp_tag, tmp_class, 1, 0, 0))
++            return -1;
++        break;
++
++    case ASN1_GEN_FLAG_SEQWRAP:
++        if (!append_exp(arg, V_ASN1_SEQUENCE, V_ASN1_UNIVERSAL, 1, 0, 1))
++            return -1;
++        break;
++
++    case ASN1_GEN_FLAG_SETWRAP:
++        if (!append_exp(arg, V_ASN1_SET, V_ASN1_UNIVERSAL, 1, 0, 1))
++            return -1;
++        break;
++
++    case ASN1_GEN_FLAG_BITWRAP:
++        if (!append_exp(arg, V_ASN1_BIT_STRING, V_ASN1_UNIVERSAL, 0, 1, 1))
++            return -1;
++        break;
++
++    case ASN1_GEN_FLAG_OCTWRAP:
++        if (!append_exp(arg, V_ASN1_OCTET_STRING, V_ASN1_UNIVERSAL, 0, 0, 1))
++            return -1;
++        break;
++
++    case ASN1_GEN_FLAG_FORMAT:
++        if (!vstart) {
++            ASN1err(ASN1_F_ASN1_CB, ASN1_R_UNKNOWN_FORMAT);
++            return -1;
++        }
++        if (strncmp(vstart, "ASCII", 5) == 0)
++            arg->format = ASN1_GEN_FORMAT_ASCII;
++        else if (strncmp(vstart, "UTF8", 4) == 0)
++            arg->format = ASN1_GEN_FORMAT_UTF8;
++        else if (strncmp(vstart, "HEX", 3) == 0)
++            arg->format = ASN1_GEN_FORMAT_HEX;
++        else if (strncmp(vstart, "BITLIST", 7) == 0)
++            arg->format = ASN1_GEN_FORMAT_BITLIST;
++        else {
++            ASN1err(ASN1_F_ASN1_CB, ASN1_R_UNKNOWN_FORMAT);
++            return -1;
++        }
++        break;
++
++    }
++
++    return 1;
++
++}
++
++static int parse_tagging(const char *vstart, int vlen, int *ptag, int *pclass)
++{
++    char erch[2];
++    long tag_num;
++    char *eptr;
++    if (!vstart)
++        return 0;
++    tag_num = strtoul(vstart, &eptr, 10);
++    /* Check we haven't gone past max length: should be impossible */
++    if (eptr && *eptr && (eptr > vstart + vlen))
++        return 0;
++    if (tag_num < 0) {
++        ASN1err(ASN1_F_PARSE_TAGGING, ASN1_R_INVALID_NUMBER);
++        return 0;
++    }
++    *ptag = tag_num;
++    /* If we have non numeric characters, parse them */
++    if (eptr)
++        vlen -= eptr - vstart;
++    else
++        vlen = 0;
++    if (vlen) {
++        switch (*eptr) {
++
++        case 'U':
++            *pclass = V_ASN1_UNIVERSAL;
++            break;
++
++        case 'A':
++            *pclass = V_ASN1_APPLICATION;
++            break;
++
++        case 'P':
++            *pclass = V_ASN1_PRIVATE;
++            break;
++
++        case 'C':
++            *pclass = V_ASN1_CONTEXT_SPECIFIC;
++            break;
++
++        default:
++            erch[0] = *eptr;
++            erch[1] = 0;
++            ASN1err(ASN1_F_PARSE_TAGGING, ASN1_R_INVALID_MODIFIER);
++            ERR_add_error_data(2, "Char=", erch);
++            return 0;
++
++        }
++    } else
++        *pclass = V_ASN1_CONTEXT_SPECIFIC;
++
++    return 1;
++
++}
++
++/* Handle multiple types: SET and SEQUENCE */
++
++static ASN1_TYPE *asn1_multi(int utype, const char *section, X509V3_CTX *cnf,
++                             int depth, int *perr)
++{
++    ASN1_TYPE *ret = NULL;
++    STACK_OF(ASN1_TYPE) *sk = NULL;
++    STACK_OF(CONF_VALUE) *sect = NULL;
++    unsigned char *der = NULL;
++    int derlen;
++    int i;
++    sk = sk_ASN1_TYPE_new_null();
++    if (!sk)
++        goto bad;
++    if (section) {
++        if (!cnf)
++            goto bad;
++        sect = X509V3_get_section(cnf, (char *)section);
++        if (!sect)
++            goto bad;
++        for (i = 0; i < sk_CONF_VALUE_num(sect); i++) {
++            ASN1_TYPE *typ =
++                generate_v3(sk_CONF_VALUE_value(sect, i)->value, cnf,
++                            depth + 1, perr);
++            if (!typ)
++                goto bad;
++            if (!sk_ASN1_TYPE_push(sk, typ))
++                goto bad;
++        }
++    }
++
++    /*
++     * Now we has a STACK of the components, convert to the correct form
++     */
++
++    if (utype == V_ASN1_SET)
++        derlen = i2d_ASN1_SET_ANY(sk, &der);
++    else
++        derlen = i2d_ASN1_SEQUENCE_ANY(sk, &der);
++
++    if (derlen < 0)
++        goto bad;
++    if ((ret = ASN1_TYPE_new()) == NULL)
++        goto bad;
++    if ((ret->value.asn1_string = ASN1_STRING_type_new(utype)) == NULL)
++        goto bad;
++
++    ret->type = utype;
++    ret->value.asn1_string->data = der;
++    ret->value.asn1_string->length = derlen;
++
++    der = NULL;
++
++ bad:
++
++    OPENSSL_free(der);
++
++    sk_ASN1_TYPE_pop_free(sk, ASN1_TYPE_free);
++    X509V3_section_free(cnf, sect);
++
++    return ret;
++}
++
++static int append_exp(tag_exp_arg *arg, int exp_tag, int exp_class,
++                      int exp_constructed, int exp_pad, int imp_ok)
++{
++    tag_exp_type *exp_tmp;
++    /* Can only have IMPLICIT if permitted */
++    if ((arg->imp_tag != -1) && !imp_ok) {
++        ASN1err(ASN1_F_APPEND_EXP, ASN1_R_ILLEGAL_IMPLICIT_TAG);
++        return 0;
++    }
++
++    if (arg->exp_count == ASN1_FLAG_EXP_MAX) {
++        ASN1err(ASN1_F_APPEND_EXP, ASN1_R_DEPTH_EXCEEDED);
++        return 0;
++    }
++
++    exp_tmp = &arg->exp_list[arg->exp_count++];
++
++    /*
++     * If IMPLICIT set tag to implicit value then reset implicit tag since it
++     * has been used.
++     */
++    if (arg->imp_tag != -1) {
++        exp_tmp->exp_tag = arg->imp_tag;
++        exp_tmp->exp_class = arg->imp_class;
++        arg->imp_tag = -1;
++        arg->imp_class = -1;
++    } else {
++        exp_tmp->exp_tag = exp_tag;
++        exp_tmp->exp_class = exp_class;
++    }
++    exp_tmp->exp_constructed = exp_constructed;
++    exp_tmp->exp_pad = exp_pad;
++
++    return 1;
++}
++
++static int asn1_str2tag(const char *tagstr, int len)
++{
++    unsigned int i;
++    static const struct tag_name_st *tntmp, tnst[] = {
++        ASN1_GEN_STR("BOOL", V_ASN1_BOOLEAN),
++        ASN1_GEN_STR("BOOLEAN", V_ASN1_BOOLEAN),
++        ASN1_GEN_STR("NULL", V_ASN1_NULL),
++        ASN1_GEN_STR("INT", V_ASN1_INTEGER),
++        ASN1_GEN_STR("INTEGER", V_ASN1_INTEGER),
++        ASN1_GEN_STR("ENUM", V_ASN1_ENUMERATED),
++        ASN1_GEN_STR("ENUMERATED", V_ASN1_ENUMERATED),
++        ASN1_GEN_STR("OID", V_ASN1_OBJECT),
++        ASN1_GEN_STR("OBJECT", V_ASN1_OBJECT),
++        ASN1_GEN_STR("UTCTIME", V_ASN1_UTCTIME),
++        ASN1_GEN_STR("UTC", V_ASN1_UTCTIME),
++        ASN1_GEN_STR("GENERALIZEDTIME", V_ASN1_GENERALIZEDTIME),
++        ASN1_GEN_STR("GENTIME", V_ASN1_GENERALIZEDTIME),
++        ASN1_GEN_STR("OCT", V_ASN1_OCTET_STRING),
++        ASN1_GEN_STR("OCTETSTRING", V_ASN1_OCTET_STRING),
++        ASN1_GEN_STR("BITSTR", V_ASN1_BIT_STRING),
++        ASN1_GEN_STR("BITSTRING", V_ASN1_BIT_STRING),
++        ASN1_GEN_STR("UNIVERSALSTRING", V_ASN1_UNIVERSALSTRING),
++        ASN1_GEN_STR("UNIV", V_ASN1_UNIVERSALSTRING),
++        ASN1_GEN_STR("IA5", V_ASN1_IA5STRING),
++        ASN1_GEN_STR("IA5STRING", V_ASN1_IA5STRING),
++        ASN1_GEN_STR("UTF8", V_ASN1_UTF8STRING),
++        ASN1_GEN_STR("UTF8String", V_ASN1_UTF8STRING),
++        ASN1_GEN_STR("BMP", V_ASN1_BMPSTRING),
++        ASN1_GEN_STR("BMPSTRING", V_ASN1_BMPSTRING),
++        ASN1_GEN_STR("VISIBLESTRING", V_ASN1_VISIBLESTRING),
++        ASN1_GEN_STR("VISIBLE", V_ASN1_VISIBLESTRING),
++        ASN1_GEN_STR("PRINTABLESTRING", V_ASN1_PRINTABLESTRING),
++        ASN1_GEN_STR("PRINTABLE", V_ASN1_PRINTABLESTRING),
++        ASN1_GEN_STR("T61", V_ASN1_T61STRING),
++        ASN1_GEN_STR("T61STRING", V_ASN1_T61STRING),
++        ASN1_GEN_STR("TELETEXSTRING", V_ASN1_T61STRING),
++        ASN1_GEN_STR("GeneralString", V_ASN1_GENERALSTRING),
++        ASN1_GEN_STR("GENSTR", V_ASN1_GENERALSTRING),
++        ASN1_GEN_STR("NUMERIC", V_ASN1_NUMERICSTRING),
++        ASN1_GEN_STR("NUMERICSTRING", V_ASN1_NUMERICSTRING),
++
++        /* Special cases */
++        ASN1_GEN_STR("SEQUENCE", V_ASN1_SEQUENCE),
++        ASN1_GEN_STR("SEQ", V_ASN1_SEQUENCE),
++        ASN1_GEN_STR("SET", V_ASN1_SET),
++        /* type modifiers */
++        /* Explicit tag */
++        ASN1_GEN_STR("EXP", ASN1_GEN_FLAG_EXP),
++        ASN1_GEN_STR("EXPLICIT", ASN1_GEN_FLAG_EXP),
++        /* Implicit tag */
++        ASN1_GEN_STR("IMP", ASN1_GEN_FLAG_IMP),
++        ASN1_GEN_STR("IMPLICIT", ASN1_GEN_FLAG_IMP),
++        /* OCTET STRING wrapper */
++        ASN1_GEN_STR("OCTWRAP", ASN1_GEN_FLAG_OCTWRAP),
++        /* SEQUENCE wrapper */
++        ASN1_GEN_STR("SEQWRAP", ASN1_GEN_FLAG_SEQWRAP),
++        /* SET wrapper */
++        ASN1_GEN_STR("SETWRAP", ASN1_GEN_FLAG_SETWRAP),
++        /* BIT STRING wrapper */
++        ASN1_GEN_STR("BITWRAP", ASN1_GEN_FLAG_BITWRAP),
++        ASN1_GEN_STR("FORM", ASN1_GEN_FLAG_FORMAT),
++        ASN1_GEN_STR("FORMAT", ASN1_GEN_FLAG_FORMAT),
++    };
++
++    if (len == -1)
++        len = strlen(tagstr);
++
++    tntmp = tnst;
++    for (i = 0; i < OSSL_NELEM(tnst); i++, tntmp++) {
++        if ((len == tntmp->len) && (strncmp(tntmp->strnam, tagstr, len) == 0))
++            return tntmp->tag;
++    }
++
++    return -1;
++}
++
++static ASN1_TYPE *asn1_str2type(const char *str, int format, int utype)
++{
++    ASN1_TYPE *atmp = NULL;
++    CONF_VALUE vtmp;
++    unsigned char *rdata;
++    long rdlen;
++    int no_unused = 1;
++
++    if ((atmp = ASN1_TYPE_new()) == NULL) {
++        ASN1err(ASN1_F_ASN1_STR2TYPE, ERR_R_MALLOC_FAILURE);
++        return NULL;
++    }
++
++    if (!str)
++        str = "";
++
++    switch (utype) {
++
++    case V_ASN1_NULL:
++        if (str && *str) {
++            ASN1err(ASN1_F_ASN1_STR2TYPE, ASN1_R_ILLEGAL_NULL_VALUE);
++            goto bad_form;
++        }
++        break;
++
++    case V_ASN1_BOOLEAN:
++        if (format != ASN1_GEN_FORMAT_ASCII) {
++            ASN1err(ASN1_F_ASN1_STR2TYPE, ASN1_R_NOT_ASCII_FORMAT);
++            goto bad_form;
++        }
++        vtmp.name = NULL;
++        vtmp.section = NULL;
++        vtmp.value = (char *)str;
++        if (!X509V3_get_value_bool(&vtmp, &atmp->value.boolean)) {
++            ASN1err(ASN1_F_ASN1_STR2TYPE, ASN1_R_ILLEGAL_BOOLEAN);
++            goto bad_str;
++        }
++        break;
++
++    case V_ASN1_INTEGER:
++    case V_ASN1_ENUMERATED:
++        if (format != ASN1_GEN_FORMAT_ASCII) {
++            ASN1err(ASN1_F_ASN1_STR2TYPE, ASN1_R_INTEGER_NOT_ASCII_FORMAT);
++            goto bad_form;
++        }
++        if ((atmp->value.integer
++                    = s2i_ASN1_INTEGER(NULL, str)) == NULL) {
++            ASN1err(ASN1_F_ASN1_STR2TYPE, ASN1_R_ILLEGAL_INTEGER);
++            goto bad_str;
++        }
++        break;
++
++    case V_ASN1_OBJECT:
++        if (format != ASN1_GEN_FORMAT_ASCII) {
++            ASN1err(ASN1_F_ASN1_STR2TYPE, ASN1_R_OBJECT_NOT_ASCII_FORMAT);
++            goto bad_form;
++        }
++        if ((atmp->value.object = OBJ_txt2obj(str, 0)) == NULL) {
++            ASN1err(ASN1_F_ASN1_STR2TYPE, ASN1_R_ILLEGAL_OBJECT);
++            goto bad_str;
++        }
++        break;
++
++    case V_ASN1_UTCTIME:
++    case V_ASN1_GENERALIZEDTIME:
++        if (format != ASN1_GEN_FORMAT_ASCII) {
++            ASN1err(ASN1_F_ASN1_STR2TYPE, ASN1_R_TIME_NOT_ASCII_FORMAT);
++            goto bad_form;
++        }
++        if ((atmp->value.asn1_string = ASN1_STRING_new()) == NULL) {
++            ASN1err(ASN1_F_ASN1_STR2TYPE, ERR_R_MALLOC_FAILURE);
++            goto bad_str;
++        }
++        if (!ASN1_STRING_set(atmp->value.asn1_string, str, -1)) {
++            ASN1err(ASN1_F_ASN1_STR2TYPE, ERR_R_MALLOC_FAILURE);
++            goto bad_str;
++        }
++        atmp->value.asn1_string->type = utype;
++        if (!ASN1_TIME_check(atmp->value.asn1_string)) {
++            ASN1err(ASN1_F_ASN1_STR2TYPE, ASN1_R_ILLEGAL_TIME_VALUE);
++            goto bad_str;
++        }
++
++        break;
++
++    case V_ASN1_BMPSTRING:
++    case V_ASN1_PRINTABLESTRING:
++    case V_ASN1_IA5STRING:
++    case V_ASN1_T61STRING:
++    case V_ASN1_UTF8STRING:
++    case V_ASN1_VISIBLESTRING:
++    case V_ASN1_UNIVERSALSTRING:
++    case V_ASN1_GENERALSTRING:
++    case V_ASN1_NUMERICSTRING:
++        if (format == ASN1_GEN_FORMAT_ASCII)
++            format = MBSTRING_ASC;
++        else if (format == ASN1_GEN_FORMAT_UTF8)
++            format = MBSTRING_UTF8;
++        else {
++            ASN1err(ASN1_F_ASN1_STR2TYPE, ASN1_R_ILLEGAL_FORMAT);
++            goto bad_form;
++        }
++
++        if (ASN1_mbstring_copy(&atmp->value.asn1_string, (unsigned char *)str,
++                               -1, format, ASN1_tag2bit(utype)) <= 0) {
++            ASN1err(ASN1_F_ASN1_STR2TYPE, ERR_R_MALLOC_FAILURE);
++            goto bad_str;
++        }
++
++        break;
++
++    case V_ASN1_BIT_STRING:
++    case V_ASN1_OCTET_STRING:
++        if ((atmp->value.asn1_string = ASN1_STRING_new()) == NULL) {
++            ASN1err(ASN1_F_ASN1_STR2TYPE, ERR_R_MALLOC_FAILURE);
++            goto bad_form;
++        }
++
++        if (format == ASN1_GEN_FORMAT_HEX) {
++            if ((rdata = OPENSSL_hexstr2buf(str, &rdlen)) == NULL) {
++                ASN1err(ASN1_F_ASN1_STR2TYPE, ASN1_R_ILLEGAL_HEX);
++                goto bad_str;
++            }
++            atmp->value.asn1_string->data = rdata;
++            atmp->value.asn1_string->length = rdlen;
++            atmp->value.asn1_string->type = utype;
++        } else if (format == ASN1_GEN_FORMAT_ASCII)
++            ASN1_STRING_set(atmp->value.asn1_string, str, -1);
++        else if ((format == ASN1_GEN_FORMAT_BITLIST)
++                 && (utype == V_ASN1_BIT_STRING)) {
++            if (!CONF_parse_list
++                (str, ',', 1, bitstr_cb, atmp->value.bit_string)) {
++                ASN1err(ASN1_F_ASN1_STR2TYPE, ASN1_R_LIST_ERROR);
++                goto bad_str;
++            }
++            no_unused = 0;
++
++        } else {
++            ASN1err(ASN1_F_ASN1_STR2TYPE, ASN1_R_ILLEGAL_BITSTRING_FORMAT);
++            goto bad_form;
++        }
++
++        if ((utype == V_ASN1_BIT_STRING) && no_unused) {
++            atmp->value.asn1_string->flags
++                &= ~(ASN1_STRING_FLAG_BITS_LEFT | 0x07);
++            atmp->value.asn1_string->flags |= ASN1_STRING_FLAG_BITS_LEFT;
++        }
++
++        break;
++
++    default:
++        ASN1err(ASN1_F_ASN1_STR2TYPE, ASN1_R_UNSUPPORTED_TYPE);
++        goto bad_str;
++    }
++
++    atmp->type = utype;
++    return atmp;
++
++ bad_str:
++    ERR_add_error_data(2, "string=", str);
++ bad_form:
++
++    ASN1_TYPE_free(atmp);
++    return NULL;
++
++}
++
++static int bitstr_cb(const char *elem, int len, void *bitstr)
++{
++    long bitnum;
++    char *eptr;
++    if (!elem)
++        return 0;
++    bitnum = strtoul(elem, &eptr, 10);
++    if (eptr && *eptr && (eptr != elem + len))
++        return 0;
++    if (bitnum < 0) {
++        ASN1err(ASN1_F_BITSTR_CB, ASN1_R_INVALID_NUMBER);
++        return 0;
++    }
++    if (!ASN1_BIT_STRING_set_bit(bitstr, bitnum, 1)) {
++        ASN1err(ASN1_F_BITSTR_CB, ERR_R_MALLOC_FAILURE);
++        return 0;
++    }
++    return 1;
++}
++
++static int mask_cb(const char *elem, int len, void *arg)
++{
++    unsigned long *pmask = arg, tmpmask;
++    int tag;
++    if (elem == NULL)
++        return 0;
++    if ((len == 3) && (strncmp(elem, "DIR", 3) == 0)) {
++        *pmask |= B_ASN1_DIRECTORYSTRING;
++        return 1;
++    }
++    tag = asn1_str2tag(elem, len);
++    if (!tag || (tag & ASN1_GEN_FLAG))
++        return 0;
++    tmpmask = ASN1_tag2bit(tag);
++    if (!tmpmask)
++        return 0;
++    *pmask |= tmpmask;
++    return 1;
++}
++
++int ASN1_str2mask(const char *str, unsigned long *pmask)
++{
++    *pmask = 0;
++    return CONF_parse_list(str, '|', 1, mask_cb, pmask);
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/asn1/asn1_lib.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/asn1/asn1_lib.c
+new file mode 100644
+index 0000000..8ca53b4
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/asn1/asn1_lib.c
+@@ -0,0 +1,384 @@
++/*
++ * Copyright 1995-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include 
++#include "internal/cryptlib.h"
++#include 
++#include "asn1_locl.h"
++
++static int asn1_get_length(const unsigned char **pp, int *inf, long *rl,
++                           long max);
++static void asn1_put_length(unsigned char **pp, int length);
++
++static int _asn1_check_infinite_end(const unsigned char **p, long len)
++{
++    /*
++     * If there is 0 or 1 byte left, the length check should pick things up
++     */
++    if (len <= 0)
++        return (1);
++    else if ((len >= 2) && ((*p)[0] == 0) && ((*p)[1] == 0)) {
++        (*p) += 2;
++        return (1);
++    }
++    return (0);
++}
++
++int ASN1_check_infinite_end(unsigned char **p, long len)
++{
++    return _asn1_check_infinite_end((const unsigned char **)p, len);
++}
++
++int ASN1_const_check_infinite_end(const unsigned char **p, long len)
++{
++    return _asn1_check_infinite_end(p, len);
++}
++
++int ASN1_get_object(const unsigned char **pp, long *plength, int *ptag,
++                    int *pclass, long omax)
++{
++    int i, ret;
++    long l;
++    const unsigned char *p = *pp;
++    int tag, xclass, inf;
++    long max = omax;
++
++    if (!max)
++        goto err;
++    ret = (*p & V_ASN1_CONSTRUCTED);
++    xclass = (*p & V_ASN1_PRIVATE);
++    i = *p & V_ASN1_PRIMITIVE_TAG;
++    if (i == V_ASN1_PRIMITIVE_TAG) { /* high-tag */
++        p++;
++        if (--max == 0)
++            goto err;
++        l = 0;
++        while (*p & 0x80) {
++            l <<= 7L;
++            l |= *(p++) & 0x7f;
++            if (--max == 0)
++                goto err;
++            if (l > (INT_MAX >> 7L))
++                goto err;
++        }
++        l <<= 7L;
++        l |= *(p++) & 0x7f;
++        tag = (int)l;
++        if (--max == 0)
++            goto err;
++    } else {
++        tag = i;
++        p++;
++        if (--max == 0)
++            goto err;
++    }
++    *ptag = tag;
++    *pclass = xclass;
++    if (!asn1_get_length(&p, &inf, plength, max))
++        goto err;
++
++    if (inf && !(ret & V_ASN1_CONSTRUCTED))
++        goto err;
++
++    if (*plength > (omax - (p - *pp))) {
++        ASN1err(ASN1_F_ASN1_GET_OBJECT, ASN1_R_TOO_LONG);
++        /*
++         * Set this so that even if things are not long enough the values are
++         * set correctly
++         */
++        ret |= 0x80;
++    }
++    *pp = p;
++    return (ret | inf);
++ err:
++    ASN1err(ASN1_F_ASN1_GET_OBJECT, ASN1_R_HEADER_TOO_LONG);
++    return (0x80);
++}
++
++static int asn1_get_length(const unsigned char **pp, int *inf, long *rl,
++                           long max)
++{
++    const unsigned char *p = *pp;
++    unsigned long ret = 0;
++    unsigned long i;
++
++    if (max-- < 1)
++        return 0;
++    if (*p == 0x80) {
++        *inf = 1;
++        ret = 0;
++        p++;
++    } else {
++        *inf = 0;
++        i = *p & 0x7f;
++        if (*(p++) & 0x80) {
++            if (max < (long)i + 1)
++                return 0;
++            /* Skip leading zeroes */
++            while (i && *p == 0) {
++                p++;
++                i--;
++            }
++            if (i > sizeof(long))
++                return 0;
++            while (i-- > 0) {
++                ret <<= 8L;
++                ret |= *(p++);
++            }
++        } else
++            ret = i;
++    }
++    if (ret > LONG_MAX)
++        return 0;
++    *pp = p;
++    *rl = (long)ret;
++    return 1;
++}
++
++/*
++ * class 0 is constructed constructed == 2 for indefinite length constructed
++ */
++void ASN1_put_object(unsigned char **pp, int constructed, int length, int tag,
++                     int xclass)
++{
++    unsigned char *p = *pp;
++    int i, ttag;
++
++    i = (constructed) ? V_ASN1_CONSTRUCTED : 0;
++    i |= (xclass & V_ASN1_PRIVATE);
++    if (tag < 31)
++        *(p++) = i | (tag & V_ASN1_PRIMITIVE_TAG);
++    else {
++        *(p++) = i | V_ASN1_PRIMITIVE_TAG;
++        for (i = 0, ttag = tag; ttag > 0; i++)
++            ttag >>= 7;
++        ttag = i;
++        while (i-- > 0) {
++            p[i] = tag & 0x7f;
++            if (i != (ttag - 1))
++                p[i] |= 0x80;
++            tag >>= 7;
++        }
++        p += ttag;
++    }
++    if (constructed == 2)
++        *(p++) = 0x80;
++    else
++        asn1_put_length(&p, length);
++    *pp = p;
++}
++
++int ASN1_put_eoc(unsigned char **pp)
++{
++    unsigned char *p = *pp;
++    *p++ = 0;
++    *p++ = 0;
++    *pp = p;
++    return 2;
++}
++
++static void asn1_put_length(unsigned char **pp, int length)
++{
++    unsigned char *p = *pp;
++    int i, l;
++    if (length <= 127)
++        *(p++) = (unsigned char)length;
++    else {
++        l = length;
++        for (i = 0; l > 0; i++)
++            l >>= 8;
++        *(p++) = i | 0x80;
++        l = i;
++        while (i-- > 0) {
++            p[i] = length & 0xff;
++            length >>= 8;
++        }
++        p += l;
++    }
++    *pp = p;
++}
++
++int ASN1_object_size(int constructed, int length, int tag)
++{
++    int ret = 1;
++    if (length < 0)
++        return -1;
++    if (tag >= 31) {
++        while (tag > 0) {
++            tag >>= 7;
++            ret++;
++        }
++    }
++    if (constructed == 2) {
++        ret += 3;
++    } else {
++        ret++;
++        if (length > 127) {
++            int tmplen = length;
++            while (tmplen > 0) {
++                tmplen >>= 8;
++                ret++;
++            }
++        }
++    }
++    if (ret >= INT_MAX - length)
++        return -1;
++    return ret + length;
++}
++
++int ASN1_STRING_copy(ASN1_STRING *dst, const ASN1_STRING *str)
++{
++    if (str == NULL)
++        return 0;
++    dst->type = str->type;
++    if (!ASN1_STRING_set(dst, str->data, str->length))
++        return 0;
++    /* Copy flags but preserve embed value */
++    dst->flags &= ASN1_STRING_FLAG_EMBED;
++    dst->flags |= str->flags & ~ASN1_STRING_FLAG_EMBED;
++    return 1;
++}
++
++ASN1_STRING *ASN1_STRING_dup(const ASN1_STRING *str)
++{
++    ASN1_STRING *ret;
++    if (!str)
++        return NULL;
++    ret = ASN1_STRING_new();
++    if (ret == NULL)
++        return NULL;
++    if (!ASN1_STRING_copy(ret, str)) {
++        ASN1_STRING_free(ret);
++        return NULL;
++    }
++    return ret;
++}
++
++int ASN1_STRING_set(ASN1_STRING *str, const void *_data, int len)
++{
++    unsigned char *c;
++    const char *data = _data;
++
++    if (len < 0) {
++        if (data == NULL)
++            return (0);
++        else
++            len = strlen(data);
++    }
++    if ((str->length <= len) || (str->data == NULL)) {
++        c = str->data;
++        str->data = OPENSSL_realloc(c, len + 1);
++        if (str->data == NULL) {
++            ASN1err(ASN1_F_ASN1_STRING_SET, ERR_R_MALLOC_FAILURE);
++            str->data = c;
++            return (0);
++        }
++    }
++    str->length = len;
++    if (data != NULL) {
++        memcpy(str->data, data, len);
++        /* an allowance for strings :-) */
++        str->data[len] = '\0';
++    }
++    return (1);
++}
++
++void ASN1_STRING_set0(ASN1_STRING *str, void *data, int len)
++{
++    OPENSSL_free(str->data);
++    str->data = data;
++    str->length = len;
++}
++
++ASN1_STRING *ASN1_STRING_new(void)
++{
++    return (ASN1_STRING_type_new(V_ASN1_OCTET_STRING));
++}
++
++ASN1_STRING *ASN1_STRING_type_new(int type)
++{
++    ASN1_STRING *ret;
++
++    ret = OPENSSL_zalloc(sizeof(*ret));
++    if (ret == NULL) {
++        ASN1err(ASN1_F_ASN1_STRING_TYPE_NEW, ERR_R_MALLOC_FAILURE);
++        return (NULL);
++    }
++    ret->type = type;
++    return (ret);
++}
++
++void asn1_string_embed_free(ASN1_STRING *a, int embed)
++{
++    if (a == NULL)
++        return;
++    if (!(a->flags & ASN1_STRING_FLAG_NDEF))
++        OPENSSL_free(a->data);
++    if (embed == 0)
++        OPENSSL_free(a);
++}
++
++void ASN1_STRING_free(ASN1_STRING *a)
++{
++    if (a == NULL)
++        return;
++    asn1_string_embed_free(a, a->flags & ASN1_STRING_FLAG_EMBED);
++}
++
++void ASN1_STRING_clear_free(ASN1_STRING *a)
++{
++    if (a == NULL)
++        return;
++    if (a->data && !(a->flags & ASN1_STRING_FLAG_NDEF))
++        OPENSSL_cleanse(a->data, a->length);
++    ASN1_STRING_free(a);
++}
++
++int ASN1_STRING_cmp(const ASN1_STRING *a, const ASN1_STRING *b)
++{
++    int i;
++
++    i = (a->length - b->length);
++    if (i == 0) {
++        i = memcmp(a->data, b->data, a->length);
++        if (i == 0)
++            return (a->type - b->type);
++        else
++            return (i);
++    } else
++        return (i);
++}
++
++int ASN1_STRING_length(const ASN1_STRING *x)
++{
++    return x->length;
++}
++
++void ASN1_STRING_length_set(ASN1_STRING *x, int len)
++{
++    x->length = len;
++}
++
++int ASN1_STRING_type(const ASN1_STRING *x)
++{
++    return x->type;
++}
++
++const unsigned char *ASN1_STRING_get0_data(const ASN1_STRING *x)
++{
++    return x->data;
++}
++
++# if OPENSSL_API_COMPAT < 0x10100000L
++unsigned char *ASN1_STRING_data(ASN1_STRING *x)
++{
++    return x->data;
++}
++#endif
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/asn1/asn1_locl.h b/CryptoPkg/Library/OpensslLib/openssl/crypto/asn1/asn1_locl.h
+new file mode 100644
+index 0000000..5f597bd
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/asn1/asn1_locl.h
+@@ -0,0 +1,78 @@
++/*
++ * Copyright 2005-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++/* Internal ASN1 structures and functions: not for application use */
++
++int asn1_utctime_to_tm(struct tm *tm, const ASN1_UTCTIME *d);
++int asn1_generalizedtime_to_tm(struct tm *tm, const ASN1_GENERALIZEDTIME *d);
++
++/* ASN1 scan context structure */
++
++struct asn1_sctx_st {
++    /* The ASN1_ITEM associated with this field */
++    const ASN1_ITEM *it;
++    /* If ASN1_TEMPLATE associated with this field */
++    const ASN1_TEMPLATE *tt;
++    /* Various flags associated with field and context */
++    unsigned long flags;
++    /* If SEQUENCE OF or SET OF, field index */
++    int skidx;
++    /* ASN1 depth of field */
++    int depth;
++    /* Structure and field name */
++    const char *sname, *fname;
++    /* If a primitive type the type of underlying field */
++    int prim_type;
++    /* The field value itself */
++    ASN1_VALUE **field;
++    /* Callback to pass information to */
++    int (*scan_cb) (ASN1_SCTX *ctx);
++    /* Context specific application data */
++    void *app_data;
++} /* ASN1_SCTX */ ;
++
++typedef struct mime_param_st MIME_PARAM;
++DEFINE_STACK_OF(MIME_PARAM)
++typedef struct mime_header_st MIME_HEADER;
++DEFINE_STACK_OF(MIME_HEADER)
++
++/* Month values for printing out times */
++extern const char *_asn1_mon[12];
++
++void asn1_string_embed_free(ASN1_STRING *a, int embed);
++
++int asn1_get_choice_selector(ASN1_VALUE **pval, const ASN1_ITEM *it);
++int asn1_set_choice_selector(ASN1_VALUE **pval, int value,
++                             const ASN1_ITEM *it);
++
++ASN1_VALUE **asn1_get_field_ptr(ASN1_VALUE **pval, const ASN1_TEMPLATE *tt);
++
++const ASN1_TEMPLATE *asn1_do_adb(ASN1_VALUE **pval, const ASN1_TEMPLATE *tt,
++                                 int nullerr);
++
++int asn1_do_lock(ASN1_VALUE **pval, int op, const ASN1_ITEM *it);
++
++void asn1_enc_init(ASN1_VALUE **pval, const ASN1_ITEM *it);
++void asn1_enc_free(ASN1_VALUE **pval, const ASN1_ITEM *it);
++int asn1_enc_restore(int *len, unsigned char **out, ASN1_VALUE **pval,
++                     const ASN1_ITEM *it);
++int asn1_enc_save(ASN1_VALUE **pval, const unsigned char *in, int inlen,
++                  const ASN1_ITEM *it);
++
++void asn1_primitive_free(ASN1_VALUE **pval, const ASN1_ITEM *it, int embed);
++void asn1_template_free(ASN1_VALUE **pval, const ASN1_TEMPLATE *tt);
++
++ASN1_OBJECT *c2i_ASN1_OBJECT(ASN1_OBJECT **a, const unsigned char **pp,
++                             long length);
++int i2c_ASN1_BIT_STRING(ASN1_BIT_STRING *a, unsigned char **pp);
++ASN1_BIT_STRING *c2i_ASN1_BIT_STRING(ASN1_BIT_STRING **a,
++                                     const unsigned char **pp, long length);
++int i2c_ASN1_INTEGER(ASN1_INTEGER *a, unsigned char **pp);
++ASN1_INTEGER *c2i_ASN1_INTEGER(ASN1_INTEGER **a, const unsigned char **pp,
++                               long length);
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/asn1/asn1_par.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/asn1/asn1_par.c
+new file mode 100644
+index 0000000..4db3df9
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/asn1/asn1_par.c
+@@ -0,0 +1,375 @@
++/*
++ * Copyright 1995-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include "internal/cryptlib.h"
++#include 
++#include 
++#include 
++
++#ifndef ASN1_PARSE_MAXDEPTH
++#define ASN1_PARSE_MAXDEPTH 128
++#endif
++
++static int asn1_print_info(BIO *bp, int tag, int xclass, int constructed,
++                           int indent);
++static int asn1_parse2(BIO *bp, const unsigned char **pp, long length,
++                       int offset, int depth, int indent, int dump);
++static int asn1_print_info(BIO *bp, int tag, int xclass, int constructed,
++                           int indent)
++{
++    static const char fmt[] = "%-18s";
++    char str[128];
++    const char *p;
++
++    if (constructed & V_ASN1_CONSTRUCTED)
++        p = "cons: ";
++    else
++        p = "prim: ";
++    if (BIO_write(bp, p, 6) < 6)
++        goto err;
++    BIO_indent(bp, indent, 128);
++
++    p = str;
++    if ((xclass & V_ASN1_PRIVATE) == V_ASN1_PRIVATE)
++        BIO_snprintf(str, sizeof str, "priv [ %d ] ", tag);
++    else if ((xclass & V_ASN1_CONTEXT_SPECIFIC) == V_ASN1_CONTEXT_SPECIFIC)
++        BIO_snprintf(str, sizeof str, "cont [ %d ]", tag);
++    else if ((xclass & V_ASN1_APPLICATION) == V_ASN1_APPLICATION)
++        BIO_snprintf(str, sizeof str, "appl [ %d ]", tag);
++    else if (tag > 30)
++        BIO_snprintf(str, sizeof str, "", tag);
++    else
++        p = ASN1_tag2str(tag);
++
++    if (BIO_printf(bp, fmt, p) <= 0)
++        goto err;
++    return (1);
++ err:
++    return (0);
++}
++
++int ASN1_parse(BIO *bp, const unsigned char *pp, long len, int indent)
++{
++    return (asn1_parse2(bp, &pp, len, 0, 0, indent, 0));
++}
++
++int ASN1_parse_dump(BIO *bp, const unsigned char *pp, long len, int indent,
++                    int dump)
++{
++    return (asn1_parse2(bp, &pp, len, 0, 0, indent, dump));
++}
++
++static int asn1_parse2(BIO *bp, const unsigned char **pp, long length,
++                       int offset, int depth, int indent, int dump)
++{
++    const unsigned char *p, *ep, *tot, *op, *opp;
++    long len;
++    int tag, xclass, ret = 0;
++    int nl, hl, j, r;
++    ASN1_OBJECT *o = NULL;
++    ASN1_OCTET_STRING *os = NULL;
++    /* ASN1_BMPSTRING *bmp=NULL; */
++    int dump_indent, dump_cont = 0;
++
++    if (depth > ASN1_PARSE_MAXDEPTH) {
++            BIO_puts(bp, "BAD RECURSION DEPTH\n");
++            return 0;
++    }
++
++    dump_indent = 6;            /* Because we know BIO_dump_indent() */
++    p = *pp;
++    tot = p + length;
++    while (length > 0) {
++        op = p;
++        j = ASN1_get_object(&p, &len, &tag, &xclass, length);
++        if (j & 0x80) {
++            if (BIO_write(bp, "Error in encoding\n", 18) <= 0)
++                goto end;
++            ret = 0;
++            goto end;
++        }
++        hl = (p - op);
++        length -= hl;
++        /*
++         * if j == 0x21 it is a constructed indefinite length object
++         */
++        if (BIO_printf(bp, "%5ld:", (long)offset + (long)(op - *pp))
++            <= 0)
++            goto end;
++
++        if (j != (V_ASN1_CONSTRUCTED | 1)) {
++            if (BIO_printf(bp, "d=%-2d hl=%ld l=%4ld ",
++                           depth, (long)hl, len) <= 0)
++                goto end;
++        } else {
++            if (BIO_printf(bp, "d=%-2d hl=%ld l=inf  ", depth, (long)hl) <= 0)
++                goto end;
++        }
++        if (!asn1_print_info(bp, tag, xclass, j, (indent) ? depth : 0))
++            goto end;
++        if (j & V_ASN1_CONSTRUCTED) {
++            const unsigned char *sp = p;
++
++            ep = p + len;
++            if (BIO_write(bp, "\n", 1) <= 0)
++                goto end;
++            if (len > length) {
++                BIO_printf(bp, "length is greater than %ld\n", length);
++                ret = 0;
++                goto end;
++            }
++            if ((j == 0x21) && (len == 0)) {
++                for (;;) {
++                    r = asn1_parse2(bp, &p, (long)(tot - p),
++                                    offset + (p - *pp), depth + 1,
++                                    indent, dump);
++                    if (r == 0) {
++                        ret = 0;
++                        goto end;
++                    }
++                    if ((r == 2) || (p >= tot)) {
++                        len = p - sp;
++                        break;
++                    }
++                }
++            } else {
++                long tmp = len;
++
++                while (p < ep) {
++                    sp = p;
++                    r = asn1_parse2(bp, &p, tmp,
++                                    offset + (p - *pp), depth + 1,
++                                    indent, dump);
++                    if (r == 0) {
++                        ret = 0;
++                        goto end;
++                    }
++                    tmp -= p - sp;
++                }
++            }
++        } else if (xclass != 0) {
++            p += len;
++            if (BIO_write(bp, "\n", 1) <= 0)
++                goto end;
++        } else {
++            nl = 0;
++            if ((tag == V_ASN1_PRINTABLESTRING) ||
++                (tag == V_ASN1_T61STRING) ||
++                (tag == V_ASN1_IA5STRING) ||
++                (tag == V_ASN1_VISIBLESTRING) ||
++                (tag == V_ASN1_NUMERICSTRING) ||
++                (tag == V_ASN1_UTF8STRING) ||
++                (tag == V_ASN1_UTCTIME) || (tag == V_ASN1_GENERALIZEDTIME)) {
++                if (BIO_write(bp, ":", 1) <= 0)
++                    goto end;
++                if ((len > 0) && BIO_write(bp, (const char *)p, (int)len)
++                    != (int)len)
++                    goto end;
++            } else if (tag == V_ASN1_OBJECT) {
++                opp = op;
++                if (d2i_ASN1_OBJECT(&o, &opp, len + hl) != NULL) {
++                    if (BIO_write(bp, ":", 1) <= 0)
++                        goto end;
++                    i2a_ASN1_OBJECT(bp, o);
++                } else {
++                    if (BIO_puts(bp, ":BAD OBJECT") <= 0)
++                        goto end;
++                    dump_cont = 1;
++                }
++            } else if (tag == V_ASN1_BOOLEAN) {
++                if (len != 1) {
++                    if (BIO_puts(bp, ":BAD BOOLEAN") <= 0)
++                        goto end;
++                    dump_cont = 1;
++                }
++                if (len > 0)
++                    BIO_printf(bp, ":%u", p[0]);
++            } else if (tag == V_ASN1_BMPSTRING) {
++                /* do the BMP thang */
++            } else if (tag == V_ASN1_OCTET_STRING) {
++                int i, printable = 1;
++
++                opp = op;
++                os = d2i_ASN1_OCTET_STRING(NULL, &opp, len + hl);
++                if (os != NULL && os->length > 0) {
++                    opp = os->data;
++                    /*
++                     * testing whether the octet string is printable
++                     */
++                    for (i = 0; i < os->length; i++) {
++                        if (((opp[i] < ' ') &&
++                             (opp[i] != '\n') &&
++                             (opp[i] != '\r') &&
++                             (opp[i] != '\t')) || (opp[i] > '~')) {
++                            printable = 0;
++                            break;
++                        }
++                    }
++                    if (printable)
++                        /* printable string */
++                    {
++                        if (BIO_write(bp, ":", 1) <= 0)
++                            goto end;
++                        if (BIO_write(bp, (const char *)opp, os->length) <= 0)
++                            goto end;
++                    } else if (!dump)
++                        /*
++                         * not printable => print octet string as hex dump
++                         */
++                    {
++                        if (BIO_write(bp, "[HEX DUMP]:", 11) <= 0)
++                            goto end;
++                        for (i = 0; i < os->length; i++) {
++                            if (BIO_printf(bp, "%02X", opp[i]) <= 0)
++                                goto end;
++                        }
++                    } else
++                        /* print the normal dump */
++                    {
++                        if (!nl) {
++                            if (BIO_write(bp, "\n", 1) <= 0)
++                                goto end;
++                        }
++                        if (BIO_dump_indent(bp,
++                                            (const char *)opp,
++                                            ((dump == -1 || dump >
++                                              os->
++                                              length) ? os->length : dump),
++                                            dump_indent) <= 0)
++                            goto end;
++                        nl = 1;
++                    }
++                }
++                ASN1_OCTET_STRING_free(os);
++                os = NULL;
++            } else if (tag == V_ASN1_INTEGER) {
++                ASN1_INTEGER *bs;
++                int i;
++
++                opp = op;
++                bs = d2i_ASN1_INTEGER(NULL, &opp, len + hl);
++                if (bs != NULL) {
++                    if (BIO_write(bp, ":", 1) <= 0)
++                        goto end;
++                    if (bs->type == V_ASN1_NEG_INTEGER)
++                        if (BIO_write(bp, "-", 1) <= 0)
++                            goto end;
++                    for (i = 0; i < bs->length; i++) {
++                        if (BIO_printf(bp, "%02X", bs->data[i]) <= 0)
++                            goto end;
++                    }
++                    if (bs->length == 0) {
++                        if (BIO_write(bp, "00", 2) <= 0)
++                            goto end;
++                    }
++                } else {
++                    if (BIO_puts(bp, ":BAD INTEGER") <= 0)
++                        goto end;
++                    dump_cont = 1;
++                }
++                ASN1_INTEGER_free(bs);
++            } else if (tag == V_ASN1_ENUMERATED) {
++                ASN1_ENUMERATED *bs;
++                int i;
++
++                opp = op;
++                bs = d2i_ASN1_ENUMERATED(NULL, &opp, len + hl);
++                if (bs != NULL) {
++                    if (BIO_write(bp, ":", 1) <= 0)
++                        goto end;
++                    if (bs->type == V_ASN1_NEG_ENUMERATED)
++                        if (BIO_write(bp, "-", 1) <= 0)
++                            goto end;
++                    for (i = 0; i < bs->length; i++) {
++                        if (BIO_printf(bp, "%02X", bs->data[i]) <= 0)
++                            goto end;
++                    }
++                    if (bs->length == 0) {
++                        if (BIO_write(bp, "00", 2) <= 0)
++                            goto end;
++                    }
++                } else {
++                    if (BIO_puts(bp, ":BAD ENUMERATED") <= 0)
++                        goto end;
++                    dump_cont = 1;
++                }
++                ASN1_ENUMERATED_free(bs);
++            } else if (len > 0 && dump) {
++                if (!nl) {
++                    if (BIO_write(bp, "\n", 1) <= 0)
++                        goto end;
++                }
++                if (BIO_dump_indent(bp, (const char *)p,
++                                    ((dump == -1 || dump > len) ? len : dump),
++                                    dump_indent) <= 0)
++                    goto end;
++                nl = 1;
++            }
++            if (dump_cont) {
++                int i;
++                const unsigned char *tmp = op + hl;
++                if (BIO_puts(bp, ":[") <= 0)
++                    goto end;
++                for (i = 0; i < len; i++) {
++                    if (BIO_printf(bp, "%02X", tmp[i]) <= 0)
++                        goto end;
++                }
++                if (BIO_puts(bp, "]") <= 0)
++                    goto end;
++            }
++
++            if (!nl) {
++                if (BIO_write(bp, "\n", 1) <= 0)
++                    goto end;
++            }
++            p += len;
++            if ((tag == V_ASN1_EOC) && (xclass == 0)) {
++                ret = 2;        /* End of sequence */
++                goto end;
++            }
++        }
++        length -= len;
++    }
++    ret = 1;
++ end:
++    ASN1_OBJECT_free(o);
++    ASN1_OCTET_STRING_free(os);
++    *pp = p;
++    return (ret);
++}
++
++const char *ASN1_tag2str(int tag)
++{
++    static const char *const tag2str[] = {
++        /* 0-4 */
++        "EOC", "BOOLEAN", "INTEGER", "BIT STRING", "OCTET STRING",
++        /* 5-9 */
++        "NULL", "OBJECT", "OBJECT DESCRIPTOR", "EXTERNAL", "REAL",
++        /* 10-13 */
++        "ENUMERATED", "", "UTF8STRING", "",
++        /* 15-17 */
++        "", "", "SEQUENCE", "SET",
++        /* 18-20 */
++        "NUMERICSTRING", "PRINTABLESTRING", "T61STRING",
++        /* 21-24 */
++        "VIDEOTEXSTRING", "IA5STRING", "UTCTIME", "GENERALIZEDTIME",
++        /* 25-27 */
++        "GRAPHICSTRING", "VISIBLESTRING", "GENERALSTRING",
++        /* 28-30 */
++        "UNIVERSALSTRING", "", "BMPSTRING"
++    };
++
++    if ((tag == V_ASN1_NEG_INTEGER) || (tag == V_ASN1_NEG_ENUMERATED))
++        tag &= ~0x100;
++
++    if (tag < 0 || tag > 30)
++        return "(unknown)";
++    return tag2str[tag];
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/asn1/asn_mime.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/asn1/asn_mime.c
+new file mode 100644
+index 0000000..d7ec801
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/asn1/asn_mime.c
+@@ -0,0 +1,980 @@
++/*
++ * Copyright 2008-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include 
++#include "internal/cryptlib.h"
++#include 
++#include 
++#include 
++#include 
++#include "internal/evp_int.h"
++#include "internal/bio.h"
++#include "asn1_locl.h"
++
++/*
++ * Generalised MIME like utilities for streaming ASN1. Although many have a
++ * PKCS7/CMS like flavour others are more general purpose.
++ */
++
++/*
++ * MIME format structures Note that all are translated to lower case apart
++ * from parameter values. Quotes are stripped off
++ */
++
++struct mime_param_st {
++    char *param_name;           /* Param name e.g. "micalg" */
++    char *param_value;          /* Param value e.g. "sha1" */
++};
++
++struct mime_header_st {
++    char *name;                 /* Name of line e.g. "content-type" */
++    char *value;                /* Value of line e.g. "text/plain" */
++    STACK_OF(MIME_PARAM) *params; /* Zero or more parameters */
++};
++
++static int asn1_output_data(BIO *out, BIO *data, ASN1_VALUE *val, int flags,
++                            const ASN1_ITEM *it);
++static char *strip_ends(char *name);
++static char *strip_start(char *name);
++static char *strip_end(char *name);
++static MIME_HEADER *mime_hdr_new(const char *name, const char *value);
++static int mime_hdr_addparam(MIME_HEADER *mhdr, const char *name, const char *value);
++static STACK_OF(MIME_HEADER) *mime_parse_hdr(BIO *bio);
++static int mime_hdr_cmp(const MIME_HEADER *const *a,
++                        const MIME_HEADER *const *b);
++static int mime_param_cmp(const MIME_PARAM *const *a,
++                          const MIME_PARAM *const *b);
++static void mime_param_free(MIME_PARAM *param);
++static int mime_bound_check(char *line, int linelen, const char *bound, int blen);
++static int multi_split(BIO *bio, const char *bound, STACK_OF(BIO) **ret);
++static int strip_eol(char *linebuf, int *plen, int flags);
++static MIME_HEADER *mime_hdr_find(STACK_OF(MIME_HEADER) *hdrs, const char *name);
++static MIME_PARAM *mime_param_find(MIME_HEADER *hdr, const char *name);
++static void mime_hdr_free(MIME_HEADER *hdr);
++
++#define MAX_SMLEN 1024
++#define mime_debug(x)           /* x */
++
++/* Output an ASN1 structure in BER format streaming if necessary */
++
++int i2d_ASN1_bio_stream(BIO *out, ASN1_VALUE *val, BIO *in, int flags,
++                        const ASN1_ITEM *it)
++{
++    /* If streaming create stream BIO and copy all content through it */
++    if (flags & SMIME_STREAM) {
++        BIO *bio, *tbio;
++        bio = BIO_new_NDEF(out, val, it);
++        if (!bio) {
++            ASN1err(ASN1_F_I2D_ASN1_BIO_STREAM, ERR_R_MALLOC_FAILURE);
++            return 0;
++        }
++        SMIME_crlf_copy(in, bio, flags);
++        (void)BIO_flush(bio);
++        /* Free up successive BIOs until we hit the old output BIO */
++        do {
++            tbio = BIO_pop(bio);
++            BIO_free(bio);
++            bio = tbio;
++        } while (bio != out);
++    }
++    /*
++     * else just write out ASN1 structure which will have all content stored
++     * internally
++     */
++    else
++        ASN1_item_i2d_bio(it, out, val);
++    return 1;
++}
++
++/* Base 64 read and write of ASN1 structure */
++
++static int B64_write_ASN1(BIO *out, ASN1_VALUE *val, BIO *in, int flags,
++                          const ASN1_ITEM *it)
++{
++    BIO *b64;
++    int r;
++    b64 = BIO_new(BIO_f_base64());
++    if (b64 == NULL) {
++        ASN1err(ASN1_F_B64_WRITE_ASN1, ERR_R_MALLOC_FAILURE);
++        return 0;
++    }
++    /*
++     * prepend the b64 BIO so all data is base64 encoded.
++     */
++    out = BIO_push(b64, out);
++    r = i2d_ASN1_bio_stream(out, val, in, flags, it);
++    (void)BIO_flush(out);
++    BIO_pop(out);
++    BIO_free(b64);
++    return r;
++}
++
++/* Streaming ASN1 PEM write */
++
++int PEM_write_bio_ASN1_stream(BIO *out, ASN1_VALUE *val, BIO *in, int flags,
++                              const char *hdr, const ASN1_ITEM *it)
++{
++    int r;
++    BIO_printf(out, "-----BEGIN %s-----\n", hdr);
++    r = B64_write_ASN1(out, val, in, flags, it);
++    BIO_printf(out, "-----END %s-----\n", hdr);
++    return r;
++}
++
++static ASN1_VALUE *b64_read_asn1(BIO *bio, const ASN1_ITEM *it)
++{
++    BIO *b64;
++    ASN1_VALUE *val;
++
++    if ((b64 = BIO_new(BIO_f_base64())) == NULL) {
++        ASN1err(ASN1_F_B64_READ_ASN1, ERR_R_MALLOC_FAILURE);
++        return 0;
++    }
++    bio = BIO_push(b64, bio);
++    val = ASN1_item_d2i_bio(it, bio, NULL);
++    if (!val)
++        ASN1err(ASN1_F_B64_READ_ASN1, ASN1_R_DECODE_ERROR);
++    (void)BIO_flush(bio);
++    BIO_pop(bio);
++    BIO_free(b64);
++    return val;
++}
++
++/* Generate the MIME "micalg" parameter from RFC3851, RFC4490 */
++
++static int asn1_write_micalg(BIO *out, STACK_OF(X509_ALGOR) *mdalgs)
++{
++    const EVP_MD *md;
++    int i, have_unknown = 0, write_comma, ret = 0, md_nid;
++    have_unknown = 0;
++    write_comma = 0;
++    for (i = 0; i < sk_X509_ALGOR_num(mdalgs); i++) {
++        if (write_comma)
++            BIO_write(out, ",", 1);
++        write_comma = 1;
++        md_nid = OBJ_obj2nid(sk_X509_ALGOR_value(mdalgs, i)->algorithm);
++        md = EVP_get_digestbynid(md_nid);
++        if (md && md->md_ctrl) {
++            int rv;
++            char *micstr;
++            rv = md->md_ctrl(NULL, EVP_MD_CTRL_MICALG, 0, &micstr);
++            if (rv > 0) {
++                BIO_puts(out, micstr);
++                OPENSSL_free(micstr);
++                continue;
++            }
++            if (rv != -2)
++                goto err;
++        }
++        switch (md_nid) {
++        case NID_sha1:
++            BIO_puts(out, "sha1");
++            break;
++
++        case NID_md5:
++            BIO_puts(out, "md5");
++            break;
++
++        case NID_sha256:
++            BIO_puts(out, "sha-256");
++            break;
++
++        case NID_sha384:
++            BIO_puts(out, "sha-384");
++            break;
++
++        case NID_sha512:
++            BIO_puts(out, "sha-512");
++            break;
++
++        case NID_id_GostR3411_94:
++            BIO_puts(out, "gostr3411-94");
++            goto err;
++
++        default:
++            if (have_unknown)
++                write_comma = 0;
++            else {
++                BIO_puts(out, "unknown");
++                have_unknown = 1;
++            }
++            break;
++
++        }
++    }
++
++    ret = 1;
++ err:
++
++    return ret;
++
++}
++
++/* SMIME sender */
++
++int SMIME_write_ASN1(BIO *bio, ASN1_VALUE *val, BIO *data, int flags,
++                     int ctype_nid, int econt_nid,
++                     STACK_OF(X509_ALGOR) *mdalgs, const ASN1_ITEM *it)
++{
++    char bound[33], c;
++    int i;
++    const char *mime_prefix, *mime_eol, *cname = "smime.p7m";
++    const char *msg_type = NULL;
++    if (flags & SMIME_OLDMIME)
++        mime_prefix = "application/x-pkcs7-";
++    else
++        mime_prefix = "application/pkcs7-";
++
++    if (flags & SMIME_CRLFEOL)
++        mime_eol = "\r\n";
++    else
++        mime_eol = "\n";
++    if ((flags & SMIME_DETACHED) && data) {
++        /* We want multipart/signed */
++        /* Generate a random boundary */
++        if (RAND_bytes((unsigned char *)bound, 32) <= 0)
++            return 0;
++        for (i = 0; i < 32; i++) {
++            c = bound[i] & 0xf;
++            if (c < 10)
++                c += '0';
++            else
++                c += 'A' - 10;
++            bound[i] = c;
++        }
++        bound[32] = 0;
++        BIO_printf(bio, "MIME-Version: 1.0%s", mime_eol);
++        BIO_printf(bio, "Content-Type: multipart/signed;");
++        BIO_printf(bio, " protocol=\"%ssignature\";", mime_prefix);
++        BIO_puts(bio, " micalg=\"");
++        asn1_write_micalg(bio, mdalgs);
++        BIO_printf(bio, "\"; boundary=\"----%s\"%s%s",
++                   bound, mime_eol, mime_eol);
++        BIO_printf(bio, "This is an S/MIME signed message%s%s",
++                   mime_eol, mime_eol);
++        /* Now write out the first part */
++        BIO_printf(bio, "------%s%s", bound, mime_eol);
++        if (!asn1_output_data(bio, data, val, flags, it))
++            return 0;
++        BIO_printf(bio, "%s------%s%s", mime_eol, bound, mime_eol);
++
++        /* Headers for signature */
++
++        BIO_printf(bio, "Content-Type: %ssignature;", mime_prefix);
++        BIO_printf(bio, " name=\"smime.p7s\"%s", mime_eol);
++        BIO_printf(bio, "Content-Transfer-Encoding: base64%s", mime_eol);
++        BIO_printf(bio, "Content-Disposition: attachment;");
++        BIO_printf(bio, " filename=\"smime.p7s\"%s%s", mime_eol, mime_eol);
++        B64_write_ASN1(bio, val, NULL, 0, it);
++        BIO_printf(bio, "%s------%s--%s%s", mime_eol, bound,
++                   mime_eol, mime_eol);
++        return 1;
++    }
++
++    /* Determine smime-type header */
++
++    if (ctype_nid == NID_pkcs7_enveloped)
++        msg_type = "enveloped-data";
++    else if (ctype_nid == NID_pkcs7_signed) {
++        if (econt_nid == NID_id_smime_ct_receipt)
++            msg_type = "signed-receipt";
++        else if (sk_X509_ALGOR_num(mdalgs) >= 0)
++            msg_type = "signed-data";
++        else
++            msg_type = "certs-only";
++    } else if (ctype_nid == NID_id_smime_ct_compressedData) {
++        msg_type = "compressed-data";
++        cname = "smime.p7z";
++    }
++    /* MIME headers */
++    BIO_printf(bio, "MIME-Version: 1.0%s", mime_eol);
++    BIO_printf(bio, "Content-Disposition: attachment;");
++    BIO_printf(bio, " filename=\"%s\"%s", cname, mime_eol);
++    BIO_printf(bio, "Content-Type: %smime;", mime_prefix);
++    if (msg_type)
++        BIO_printf(bio, " smime-type=%s;", msg_type);
++    BIO_printf(bio, " name=\"%s\"%s", cname, mime_eol);
++    BIO_printf(bio, "Content-Transfer-Encoding: base64%s%s",
++               mime_eol, mime_eol);
++    if (!B64_write_ASN1(bio, val, data, flags, it))
++        return 0;
++    BIO_printf(bio, "%s", mime_eol);
++    return 1;
++}
++
++/* Handle output of ASN1 data */
++
++static int asn1_output_data(BIO *out, BIO *data, ASN1_VALUE *val, int flags,
++                            const ASN1_ITEM *it)
++{
++    BIO *tmpbio;
++    const ASN1_AUX *aux = it->funcs;
++    ASN1_STREAM_ARG sarg;
++    int rv = 1;
++
++    /*
++     * If data is not detached or resigning then the output BIO is already
++     * set up to finalise when it is written through.
++     */
++    if (!(flags & SMIME_DETACHED) || (flags & PKCS7_REUSE_DIGEST)) {
++        SMIME_crlf_copy(data, out, flags);
++        return 1;
++    }
++
++    if (!aux || !aux->asn1_cb) {
++        ASN1err(ASN1_F_ASN1_OUTPUT_DATA, ASN1_R_STREAMING_NOT_SUPPORTED);
++        return 0;
++    }
++
++    sarg.out = out;
++    sarg.ndef_bio = NULL;
++    sarg.boundary = NULL;
++
++    /* Let ASN1 code prepend any needed BIOs */
++
++    if (aux->asn1_cb(ASN1_OP_DETACHED_PRE, &val, it, &sarg) <= 0)
++        return 0;
++
++    /* Copy data across, passing through filter BIOs for processing */
++    SMIME_crlf_copy(data, sarg.ndef_bio, flags);
++
++    /* Finalize structure */
++    if (aux->asn1_cb(ASN1_OP_DETACHED_POST, &val, it, &sarg) <= 0)
++        rv = 0;
++
++    /* Now remove any digests prepended to the BIO */
++
++    while (sarg.ndef_bio != out) {
++        tmpbio = BIO_pop(sarg.ndef_bio);
++        BIO_free(sarg.ndef_bio);
++        sarg.ndef_bio = tmpbio;
++    }
++
++    return rv;
++
++}
++
++/*
++ * SMIME reader: handle multipart/signed and opaque signing. in multipart
++ * case the content is placed in a memory BIO pointed to by "bcont". In
++ * opaque this is set to NULL
++ */
++
++ASN1_VALUE *SMIME_read_ASN1(BIO *bio, BIO **bcont, const ASN1_ITEM *it)
++{
++    BIO *asnin;
++    STACK_OF(MIME_HEADER) *headers = NULL;
++    STACK_OF(BIO) *parts = NULL;
++    MIME_HEADER *hdr;
++    MIME_PARAM *prm;
++    ASN1_VALUE *val;
++    int ret;
++
++    if (bcont)
++        *bcont = NULL;
++
++    if ((headers = mime_parse_hdr(bio)) == NULL) {
++        ASN1err(ASN1_F_SMIME_READ_ASN1, ASN1_R_MIME_PARSE_ERROR);
++        return NULL;
++    }
++
++    if ((hdr = mime_hdr_find(headers, "content-type")) == NULL
++        || hdr->value == NULL) {
++        sk_MIME_HEADER_pop_free(headers, mime_hdr_free);
++        ASN1err(ASN1_F_SMIME_READ_ASN1, ASN1_R_NO_CONTENT_TYPE);
++        return NULL;
++    }
++
++    /* Handle multipart/signed */
++
++    if (strcmp(hdr->value, "multipart/signed") == 0) {
++        /* Split into two parts */
++        prm = mime_param_find(hdr, "boundary");
++        if (!prm || !prm->param_value) {
++            sk_MIME_HEADER_pop_free(headers, mime_hdr_free);
++            ASN1err(ASN1_F_SMIME_READ_ASN1, ASN1_R_NO_MULTIPART_BOUNDARY);
++            return NULL;
++        }
++        ret = multi_split(bio, prm->param_value, &parts);
++        sk_MIME_HEADER_pop_free(headers, mime_hdr_free);
++        if (!ret || (sk_BIO_num(parts) != 2)) {
++            ASN1err(ASN1_F_SMIME_READ_ASN1, ASN1_R_NO_MULTIPART_BODY_FAILURE);
++            sk_BIO_pop_free(parts, BIO_vfree);
++            return NULL;
++        }
++
++        /* Parse the signature piece */
++        asnin = sk_BIO_value(parts, 1);
++
++        if ((headers = mime_parse_hdr(asnin)) == NULL) {
++            ASN1err(ASN1_F_SMIME_READ_ASN1, ASN1_R_MIME_SIG_PARSE_ERROR);
++            sk_BIO_pop_free(parts, BIO_vfree);
++            return NULL;
++        }
++
++        /* Get content type */
++
++        if ((hdr = mime_hdr_find(headers, "content-type")) == NULL
++            || hdr->value == NULL) {
++            sk_MIME_HEADER_pop_free(headers, mime_hdr_free);
++            ASN1err(ASN1_F_SMIME_READ_ASN1, ASN1_R_NO_SIG_CONTENT_TYPE);
++            return NULL;
++        }
++
++        if (strcmp(hdr->value, "application/x-pkcs7-signature") &&
++            strcmp(hdr->value, "application/pkcs7-signature")) {
++            ASN1err(ASN1_F_SMIME_READ_ASN1, ASN1_R_SIG_INVALID_MIME_TYPE);
++            ERR_add_error_data(2, "type: ", hdr->value);
++            sk_MIME_HEADER_pop_free(headers, mime_hdr_free);
++            sk_BIO_pop_free(parts, BIO_vfree);
++            return NULL;
++        }
++        sk_MIME_HEADER_pop_free(headers, mime_hdr_free);
++        /* Read in ASN1 */
++        if ((val = b64_read_asn1(asnin, it)) == NULL) {
++            ASN1err(ASN1_F_SMIME_READ_ASN1, ASN1_R_ASN1_SIG_PARSE_ERROR);
++            sk_BIO_pop_free(parts, BIO_vfree);
++            return NULL;
++        }
++
++        if (bcont) {
++            *bcont = sk_BIO_value(parts, 0);
++            BIO_free(asnin);
++            sk_BIO_free(parts);
++        } else
++            sk_BIO_pop_free(parts, BIO_vfree);
++        return val;
++    }
++
++    /* OK, if not multipart/signed try opaque signature */
++
++    if (strcmp(hdr->value, "application/x-pkcs7-mime") &&
++        strcmp(hdr->value, "application/pkcs7-mime")) {
++        ASN1err(ASN1_F_SMIME_READ_ASN1, ASN1_R_INVALID_MIME_TYPE);
++        ERR_add_error_data(2, "type: ", hdr->value);
++        sk_MIME_HEADER_pop_free(headers, mime_hdr_free);
++        return NULL;
++    }
++
++    sk_MIME_HEADER_pop_free(headers, mime_hdr_free);
++
++    if ((val = b64_read_asn1(bio, it)) == NULL) {
++        ASN1err(ASN1_F_SMIME_READ_ASN1, ASN1_R_ASN1_PARSE_ERROR);
++        return NULL;
++    }
++    return val;
++
++}
++
++/* Copy text from one BIO to another making the output CRLF at EOL */
++int SMIME_crlf_copy(BIO *in, BIO *out, int flags)
++{
++    BIO *bf;
++    char eol;
++    int len;
++    char linebuf[MAX_SMLEN];
++    /*
++     * Buffer output so we don't write one line at a time. This is useful
++     * when streaming as we don't end up with one OCTET STRING per line.
++     */
++    bf = BIO_new(BIO_f_buffer());
++    if (bf == NULL)
++        return 0;
++    out = BIO_push(bf, out);
++    if (flags & SMIME_BINARY) {
++        while ((len = BIO_read(in, linebuf, MAX_SMLEN)) > 0)
++            BIO_write(out, linebuf, len);
++    } else {
++        int eolcnt = 0;
++        if (flags & SMIME_TEXT)
++            BIO_printf(out, "Content-Type: text/plain\r\n\r\n");
++        while ((len = BIO_gets(in, linebuf, MAX_SMLEN)) > 0) {
++            eol = strip_eol(linebuf, &len, flags);
++            if (len) {
++                /* Not EOF: write out all CRLF */
++                if (flags & SMIME_ASCIICRLF) {
++                    int i;
++                    for (i = 0; i < eolcnt; i++)
++                        BIO_write(out, "\r\n", 2);
++                    eolcnt = 0;
++                }
++                BIO_write(out, linebuf, len);
++                if (eol)
++                    BIO_write(out, "\r\n", 2);
++            } else if (flags & SMIME_ASCIICRLF)
++                eolcnt++;
++            else if (eol)
++                BIO_write(out, "\r\n", 2);
++        }
++    }
++    (void)BIO_flush(out);
++    BIO_pop(out);
++    BIO_free(bf);
++    return 1;
++}
++
++/* Strip off headers if they are text/plain */
++int SMIME_text(BIO *in, BIO *out)
++{
++    char iobuf[4096];
++    int len;
++    STACK_OF(MIME_HEADER) *headers;
++    MIME_HEADER *hdr;
++
++    if ((headers = mime_parse_hdr(in)) == NULL) {
++        ASN1err(ASN1_F_SMIME_TEXT, ASN1_R_MIME_PARSE_ERROR);
++        return 0;
++    }
++    if ((hdr = mime_hdr_find(headers, "content-type")) == NULL
++        || hdr->value == NULL) {
++        ASN1err(ASN1_F_SMIME_TEXT, ASN1_R_MIME_NO_CONTENT_TYPE);
++        sk_MIME_HEADER_pop_free(headers, mime_hdr_free);
++        return 0;
++    }
++    if (strcmp(hdr->value, "text/plain")) {
++        ASN1err(ASN1_F_SMIME_TEXT, ASN1_R_INVALID_MIME_TYPE);
++        ERR_add_error_data(2, "type: ", hdr->value);
++        sk_MIME_HEADER_pop_free(headers, mime_hdr_free);
++        return 0;
++    }
++    sk_MIME_HEADER_pop_free(headers, mime_hdr_free);
++    while ((len = BIO_read(in, iobuf, sizeof(iobuf))) > 0)
++        BIO_write(out, iobuf, len);
++    if (len < 0)
++        return 0;
++    return 1;
++}
++
++/*
++ * Split a multipart/XXX message body into component parts: result is
++ * canonical parts in a STACK of bios
++ */
++
++static int multi_split(BIO *bio, const char *bound, STACK_OF(BIO) **ret)
++{
++    char linebuf[MAX_SMLEN];
++    int len, blen;
++    int eol = 0, next_eol = 0;
++    BIO *bpart = NULL;
++    STACK_OF(BIO) *parts;
++    char state, part, first;
++
++    blen = strlen(bound);
++    part = 0;
++    state = 0;
++    first = 1;
++    parts = sk_BIO_new_null();
++    *ret = parts;
++    if (*ret == NULL)
++        return 0;
++    while ((len = BIO_gets(bio, linebuf, MAX_SMLEN)) > 0) {
++        state = mime_bound_check(linebuf, len, bound, blen);
++        if (state == 1) {
++            first = 1;
++            part++;
++        } else if (state == 2) {
++            if (!sk_BIO_push(parts, bpart)) {
++                BIO_free(bpart);
++                return 0;
++            }
++            return 1;
++        } else if (part) {
++            /* Strip CR+LF from linebuf */
++            next_eol = strip_eol(linebuf, &len, 0);
++            if (first) {
++                first = 0;
++                if (bpart)
++                    if (!sk_BIO_push(parts, bpart)) {
++                        BIO_free(bpart);
++                        return 0;
++                    }
++                bpart = BIO_new(BIO_s_mem());
++                if (bpart == NULL)
++                    return 0;
++                BIO_set_mem_eof_return(bpart, 0);
++            } else if (eol)
++                BIO_write(bpart, "\r\n", 2);
++            eol = next_eol;
++            if (len)
++                BIO_write(bpart, linebuf, len);
++        }
++    }
++    BIO_free(bpart);
++    return 0;
++}
++
++/* This is the big one: parse MIME header lines up to message body */
++
++#define MIME_INVALID    0
++#define MIME_START      1
++#define MIME_TYPE       2
++#define MIME_NAME       3
++#define MIME_VALUE      4
++#define MIME_QUOTE      5
++#define MIME_COMMENT    6
++
++static STACK_OF(MIME_HEADER) *mime_parse_hdr(BIO *bio)
++{
++    char *p, *q, c;
++    char *ntmp;
++    char linebuf[MAX_SMLEN];
++    MIME_HEADER *mhdr = NULL, *new_hdr = NULL;
++    STACK_OF(MIME_HEADER) *headers;
++    int len, state, save_state = 0;
++
++    headers = sk_MIME_HEADER_new(mime_hdr_cmp);
++    if (headers == NULL)
++        return NULL;
++    while ((len = BIO_gets(bio, linebuf, MAX_SMLEN)) > 0) {
++        /* If whitespace at line start then continuation line */
++        if (mhdr && isspace((unsigned char)linebuf[0]))
++            state = MIME_NAME;
++        else
++            state = MIME_START;
++        ntmp = NULL;
++        /* Go through all characters */
++        for (p = linebuf, q = linebuf; (c = *p) && (c != '\r') && (c != '\n');
++             p++) {
++
++            /*
++             * State machine to handle MIME headers if this looks horrible
++             * that's because it *is*
++             */
++
++            switch (state) {
++            case MIME_START:
++                if (c == ':') {
++                    state = MIME_TYPE;
++                    *p = 0;
++                    ntmp = strip_ends(q);
++                    q = p + 1;
++                }
++                break;
++
++            case MIME_TYPE:
++                if (c == ';') {
++                    mime_debug("Found End Value\n");
++                    *p = 0;
++                    new_hdr = mime_hdr_new(ntmp, strip_ends(q));
++                    if (new_hdr == NULL)
++                        goto err;
++                    if (!sk_MIME_HEADER_push(headers, new_hdr))
++                        goto err;
++                    mhdr = new_hdr;
++                    new_hdr = NULL;
++                    ntmp = NULL;
++                    q = p + 1;
++                    state = MIME_NAME;
++                } else if (c == '(') {
++                    save_state = state;
++                    state = MIME_COMMENT;
++                }
++                break;
++
++            case MIME_COMMENT:
++                if (c == ')') {
++                    state = save_state;
++                }
++                break;
++
++            case MIME_NAME:
++                if (c == '=') {
++                    state = MIME_VALUE;
++                    *p = 0;
++                    ntmp = strip_ends(q);
++                    q = p + 1;
++                }
++                break;
++
++            case MIME_VALUE:
++                if (c == ';') {
++                    state = MIME_NAME;
++                    *p = 0;
++                    mime_hdr_addparam(mhdr, ntmp, strip_ends(q));
++                    ntmp = NULL;
++                    q = p + 1;
++                } else if (c == '"') {
++                    mime_debug("Found Quote\n");
++                    state = MIME_QUOTE;
++                } else if (c == '(') {
++                    save_state = state;
++                    state = MIME_COMMENT;
++                }
++                break;
++
++            case MIME_QUOTE:
++                if (c == '"') {
++                    mime_debug("Found Match Quote\n");
++                    state = MIME_VALUE;
++                }
++                break;
++            }
++        }
++
++        if (state == MIME_TYPE) {
++            new_hdr = mime_hdr_new(ntmp, strip_ends(q));
++            if (new_hdr == NULL)
++                goto err;
++            if (!sk_MIME_HEADER_push(headers, new_hdr))
++                goto err;
++            mhdr = new_hdr;
++            new_hdr = NULL;
++        } else if (state == MIME_VALUE)
++            mime_hdr_addparam(mhdr, ntmp, strip_ends(q));
++        if (p == linebuf)
++            break;              /* Blank line means end of headers */
++    }
++
++    return headers;
++
++err:
++    mime_hdr_free(new_hdr);
++    sk_MIME_HEADER_pop_free(headers, mime_hdr_free);
++    return NULL;
++}
++
++static char *strip_ends(char *name)
++{
++    return strip_end(strip_start(name));
++}
++
++/* Strip a parameter of whitespace from start of param */
++static char *strip_start(char *name)
++{
++    char *p, c;
++    /* Look for first non white space or quote */
++    for (p = name; (c = *p); p++) {
++        if (c == '"') {
++            /* Next char is start of string if non null */
++            if (p[1])
++                return p + 1;
++            /* Else null string */
++            return NULL;
++        }
++        if (!isspace((unsigned char)c))
++            return p;
++    }
++    return NULL;
++}
++
++/* As above but strip from end of string : maybe should handle brackets? */
++static char *strip_end(char *name)
++{
++    char *p, c;
++    if (!name)
++        return NULL;
++    /* Look for first non white space or quote */
++    for (p = name + strlen(name) - 1; p >= name; p--) {
++        c = *p;
++        if (c == '"') {
++            if (p - 1 == name)
++                return NULL;
++            *p = 0;
++            return name;
++        }
++        if (isspace((unsigned char)c))
++            *p = 0;
++        else
++            return name;
++    }
++    return NULL;
++}
++
++static MIME_HEADER *mime_hdr_new(const char *name, const char *value)
++{
++    MIME_HEADER *mhdr = NULL;
++    char *tmpname = NULL, *tmpval = NULL, *p;
++    int c;
++
++    if (name) {
++        if ((tmpname = OPENSSL_strdup(name)) == NULL)
++            return NULL;
++        for (p = tmpname; *p; p++) {
++            c = (unsigned char)*p;
++            if (isupper(c)) {
++                c = tolower(c);
++                *p = c;
++            }
++        }
++    }
++    if (value) {
++        if ((tmpval = OPENSSL_strdup(value)) == NULL)
++            goto err;
++        for (p = tmpval; *p; p++) {
++            c = (unsigned char)*p;
++            if (isupper(c)) {
++                c = tolower(c);
++                *p = c;
++            }
++        }
++    }
++    mhdr = OPENSSL_malloc(sizeof(*mhdr));
++    if (mhdr == NULL)
++        goto err;
++    mhdr->name = tmpname;
++    mhdr->value = tmpval;
++    if ((mhdr->params = sk_MIME_PARAM_new(mime_param_cmp)) == NULL)
++        goto err;
++    return mhdr;
++
++ err:
++    OPENSSL_free(tmpname);
++    OPENSSL_free(tmpval);
++    OPENSSL_free(mhdr);
++    return NULL;
++}
++
++static int mime_hdr_addparam(MIME_HEADER *mhdr, const char *name, const char *value)
++{
++    char *tmpname = NULL, *tmpval = NULL, *p;
++    int c;
++    MIME_PARAM *mparam = NULL;
++    if (name) {
++        tmpname = OPENSSL_strdup(name);
++        if (!tmpname)
++            goto err;
++        for (p = tmpname; *p; p++) {
++            c = (unsigned char)*p;
++            if (isupper(c)) {
++                c = tolower(c);
++                *p = c;
++            }
++        }
++    }
++    if (value) {
++        tmpval = OPENSSL_strdup(value);
++        if (!tmpval)
++            goto err;
++    }
++    /* Parameter values are case sensitive so leave as is */
++    mparam = OPENSSL_malloc(sizeof(*mparam));
++    if (mparam == NULL)
++        goto err;
++    mparam->param_name = tmpname;
++    mparam->param_value = tmpval;
++    if (!sk_MIME_PARAM_push(mhdr->params, mparam))
++        goto err;
++    return 1;
++ err:
++    OPENSSL_free(tmpname);
++    OPENSSL_free(tmpval);
++    OPENSSL_free(mparam);
++    return 0;
++}
++
++static int mime_hdr_cmp(const MIME_HEADER *const *a,
++                        const MIME_HEADER *const *b)
++{
++    if (!(*a)->name || !(*b)->name)
++        return ! !(*a)->name - ! !(*b)->name;
++
++    return (strcmp((*a)->name, (*b)->name));
++}
++
++static int mime_param_cmp(const MIME_PARAM *const *a,
++                          const MIME_PARAM *const *b)
++{
++    if (!(*a)->param_name || !(*b)->param_name)
++        return ! !(*a)->param_name - ! !(*b)->param_name;
++    return (strcmp((*a)->param_name, (*b)->param_name));
++}
++
++/* Find a header with a given name (if possible) */
++
++static MIME_HEADER *mime_hdr_find(STACK_OF(MIME_HEADER) *hdrs, const char *name)
++{
++    MIME_HEADER htmp;
++    int idx;
++
++    htmp.name = (char *)name;
++    htmp.value = NULL;
++    htmp.params = NULL;
++
++    idx = sk_MIME_HEADER_find(hdrs, &htmp);
++    if (idx < 0)
++        return NULL;
++    return sk_MIME_HEADER_value(hdrs, idx);
++}
++
++static MIME_PARAM *mime_param_find(MIME_HEADER *hdr, const char *name)
++{
++    MIME_PARAM param;
++    int idx;
++
++    param.param_name = (char *)name;
++    param.param_value = NULL;
++    idx = sk_MIME_PARAM_find(hdr->params, ¶m);
++    if (idx < 0)
++        return NULL;
++    return sk_MIME_PARAM_value(hdr->params, idx);
++}
++
++static void mime_hdr_free(MIME_HEADER *hdr)
++{
++    if (hdr == NULL)
++        return;
++    OPENSSL_free(hdr->name);
++    OPENSSL_free(hdr->value);
++    if (hdr->params)
++        sk_MIME_PARAM_pop_free(hdr->params, mime_param_free);
++    OPENSSL_free(hdr);
++}
++
++static void mime_param_free(MIME_PARAM *param)
++{
++    OPENSSL_free(param->param_name);
++    OPENSSL_free(param->param_value);
++    OPENSSL_free(param);
++}
++
++/*-
++ * Check for a multipart boundary. Returns:
++ * 0 : no boundary
++ * 1 : part boundary
++ * 2 : final boundary
++ */
++static int mime_bound_check(char *line, int linelen, const char *bound, int blen)
++{
++    if (linelen == -1)
++        linelen = strlen(line);
++    if (blen == -1)
++        blen = strlen(bound);
++    /* Quickly eliminate if line length too short */
++    if (blen + 2 > linelen)
++        return 0;
++    /* Check for part boundary */
++    if ((strncmp(line, "--", 2) == 0)
++        && strncmp(line + 2, bound, blen) == 0) {
++        if (strncmp(line + blen + 2, "--", 2) == 0)
++            return 2;
++        else
++            return 1;
++    }
++    return 0;
++}
++
++static int strip_eol(char *linebuf, int *plen, int flags)
++{
++    int len = *plen;
++    char *p, c;
++    int is_eol = 0;
++    p = linebuf + len - 1;
++    for (p = linebuf + len - 1; len > 0; len--, p--) {
++        c = *p;
++        if (c == '\n')
++            is_eol = 1;
++        else if (is_eol && flags & SMIME_ASCIICRLF && c < 33)
++            continue;
++        else if (c != '\r')
++            break;
++    }
++    *plen = len;
++    return is_eol;
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/asn1/asn_moid.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/asn1/asn_moid.c
+new file mode 100644
+index 0000000..8176b76
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/asn1/asn_moid.c
+@@ -0,0 +1,105 @@
++/*
++ * Copyright 2002-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include 
++#include 
++#include "internal/cryptlib.h"
++#include 
++#include 
++#include "internal/asn1_int.h"
++#include "internal/objects.h"
++
++/* Simple ASN1 OID module: add all objects in a given section */
++
++static int do_create(const char *value, const char *name);
++
++static int oid_module_init(CONF_IMODULE *md, const CONF *cnf)
++{
++    int i;
++    const char *oid_section;
++    STACK_OF(CONF_VALUE) *sktmp;
++    CONF_VALUE *oval;
++
++    oid_section = CONF_imodule_get_value(md);
++    if ((sktmp = NCONF_get_section(cnf, oid_section)) == NULL) {
++        ASN1err(ASN1_F_OID_MODULE_INIT, ASN1_R_ERROR_LOADING_SECTION);
++        return 0;
++    }
++    for (i = 0; i < sk_CONF_VALUE_num(sktmp); i++) {
++        oval = sk_CONF_VALUE_value(sktmp, i);
++        if (!do_create(oval->value, oval->name)) {
++            ASN1err(ASN1_F_OID_MODULE_INIT, ASN1_R_ADDING_OBJECT);
++            return 0;
++        }
++    }
++    return 1;
++}
++
++static void oid_module_finish(CONF_IMODULE *md)
++{
++}
++
++void ASN1_add_oid_module(void)
++{
++    CONF_module_add("oid_section", oid_module_init, oid_module_finish);
++}
++
++/*-
++ * Create an OID based on a name value pair. Accept two formats.
++ * shortname = 1.2.3.4
++ * shortname = some long name, 1.2.3.4
++ */
++
++static int do_create(const char *value, const char *name)
++{
++    int nid;
++    ASN1_OBJECT *oid;
++    const char *ln, *ostr, *p;
++    char *lntmp;
++    p = strrchr(value, ',');
++    if (!p) {
++        ln = name;
++        ostr = value;
++    } else {
++        ln = NULL;
++        ostr = p + 1;
++        if (!*ostr)
++            return 0;
++        while (isspace((unsigned char)*ostr))
++            ostr++;
++    }
++
++    nid = OBJ_create(ostr, name, ln);
++
++    if (nid == NID_undef)
++        return 0;
++
++    if (p) {
++        ln = value;
++        while (isspace((unsigned char)*ln))
++            ln++;
++        p--;
++        while (isspace((unsigned char)*p)) {
++            if (p == ln)
++                return 0;
++            p--;
++        }
++        p++;
++        lntmp = OPENSSL_malloc((p - ln) + 1);
++        if (lntmp == NULL)
++            return 0;
++        memcpy(lntmp, ln, p - ln);
++        lntmp[p - ln] = 0;
++        oid = OBJ_nid2obj(nid);
++        oid->ln = lntmp;
++    }
++
++    return 1;
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/asn1/asn_mstbl.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/asn1/asn_mstbl.c
+new file mode 100644
+index 0000000..8260939
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/asn1/asn_mstbl.c
+@@ -0,0 +1,114 @@
++/*
++ * Copyright 2012-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include 
++#include 
++#include "internal/cryptlib.h"
++#include 
++#include 
++
++/* Multi string module: add table entries from a given section */
++
++static int do_tcreate(const char *value, const char *name);
++
++static int stbl_module_init(CONF_IMODULE *md, const CONF *cnf)
++{
++    int i;
++    const char *stbl_section;
++    STACK_OF(CONF_VALUE) *sktmp;
++    CONF_VALUE *mval;
++
++    stbl_section = CONF_imodule_get_value(md);
++    if ((sktmp = NCONF_get_section(cnf, stbl_section)) == NULL) {
++        ASN1err(ASN1_F_STBL_MODULE_INIT, ASN1_R_ERROR_LOADING_SECTION);
++        return 0;
++    }
++    for (i = 0; i < sk_CONF_VALUE_num(sktmp); i++) {
++        mval = sk_CONF_VALUE_value(sktmp, i);
++        if (!do_tcreate(mval->value, mval->name)) {
++            ASN1err(ASN1_F_STBL_MODULE_INIT, ASN1_R_INVALID_VALUE);
++            return 0;
++        }
++    }
++    return 1;
++}
++
++static void stbl_module_finish(CONF_IMODULE *md)
++{
++    ASN1_STRING_TABLE_cleanup();
++}
++
++void ASN1_add_stable_module(void)
++{
++    CONF_module_add("stbl_section", stbl_module_init, stbl_module_finish);
++}
++
++/*
++ * Create an table entry based on a name value pair. format is oid_name =
++ * n1:v1, n2:v2,... where name is "min", "max", "mask" or "flags".
++ */
++
++static int do_tcreate(const char *value, const char *name)
++{
++    char *eptr;
++    int nid, i, rv = 0;
++    long tbl_min = -1, tbl_max = -1;
++    unsigned long tbl_mask = 0, tbl_flags = 0;
++    STACK_OF(CONF_VALUE) *lst = NULL;
++    CONF_VALUE *cnf = NULL;
++    nid = OBJ_sn2nid(name);
++    if (nid == NID_undef)
++        nid = OBJ_ln2nid(name);
++    if (nid == NID_undef)
++        goto err;
++    lst = X509V3_parse_list(value);
++    if (!lst)
++        goto err;
++    for (i = 0; i < sk_CONF_VALUE_num(lst); i++) {
++        cnf = sk_CONF_VALUE_value(lst, i);
++        if (strcmp(cnf->name, "min") == 0) {
++            tbl_min = strtoul(cnf->value, &eptr, 0);
++            if (*eptr)
++                goto err;
++        } else if (strcmp(cnf->name, "max") == 0) {
++            tbl_max = strtoul(cnf->value, &eptr, 0);
++            if (*eptr)
++                goto err;
++        } else if (strcmp(cnf->name, "mask") == 0) {
++            if (!ASN1_str2mask(cnf->value, &tbl_mask) || !tbl_mask)
++                goto err;
++        } else if (strcmp(cnf->name, "flags") == 0) {
++            if (strcmp(cnf->value, "nomask") == 0)
++                tbl_flags = STABLE_NO_MASK;
++            else if (strcmp(cnf->value, "none") == 0)
++                tbl_flags = STABLE_FLAGS_CLEAR;
++            else
++                goto err;
++        } else
++            goto err;
++    }
++    rv = 1;
++ err:
++    if (rv == 0) {
++        ASN1err(ASN1_F_DO_TCREATE, ASN1_R_INVALID_STRING_TABLE_VALUE);
++        if (cnf)
++            ERR_add_error_data(4, "field=", cnf->name,
++                               ", value=", cnf->value);
++        else
++            ERR_add_error_data(4, "name=", name, ", value=", value);
++    } else {
++        rv = ASN1_STRING_TABLE_add(nid, tbl_min, tbl_max,
++                                   tbl_mask, tbl_flags);
++        if (!rv)
++            ASN1err(ASN1_F_DO_TCREATE, ERR_R_MALLOC_FAILURE);
++    }
++    sk_CONF_VALUE_pop_free(lst, X509V3_conf_free);
++    return rv;
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/asn1/asn_pack.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/asn1/asn_pack.c
+new file mode 100644
+index 0000000..63bc306
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/asn1/asn_pack.c
+@@ -0,0 +1,62 @@
++/*
++ * Copyright 1999-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include "internal/cryptlib.h"
++#include 
++
++/* ASN1 packing and unpacking functions */
++
++ASN1_STRING *ASN1_item_pack(void *obj, const ASN1_ITEM *it, ASN1_STRING **oct)
++{
++    ASN1_STRING *octmp;
++
++     if (oct == NULL || *oct == NULL) {
++        if ((octmp = ASN1_STRING_new()) == NULL) {
++            ASN1err(ASN1_F_ASN1_ITEM_PACK, ERR_R_MALLOC_FAILURE);
++            return NULL;
++        }
++    } else {
++        octmp = *oct;
++    }
++
++    OPENSSL_free(octmp->data);
++    octmp->data = NULL;
++
++    if ((octmp->length = ASN1_item_i2d(obj, &octmp->data, it)) == 0) {
++        ASN1err(ASN1_F_ASN1_ITEM_PACK, ASN1_R_ENCODE_ERROR);
++        goto err;
++    }
++    if (octmp->data == NULL) {
++        ASN1err(ASN1_F_ASN1_ITEM_PACK, ERR_R_MALLOC_FAILURE);
++        goto err;
++    }
++
++    if (oct != NULL && *oct == NULL)
++        *oct = octmp;
++
++    return octmp;
++ err:
++    if (oct == NULL || *oct == NULL)
++        ASN1_STRING_free(octmp);
++    return NULL;
++}
++
++/* Extract an ASN1 object from an ASN1_STRING */
++
++void *ASN1_item_unpack(const ASN1_STRING *oct, const ASN1_ITEM *it)
++{
++    const unsigned char *p;
++    void *ret;
++
++    p = oct->data;
++    if ((ret = ASN1_item_d2i(NULL, &p, oct->length, it)) == NULL)
++        ASN1err(ASN1_F_ASN1_ITEM_UNPACK, ASN1_R_DECODE_ERROR);
++    return ret;
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/asn1/bio_asn1.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/asn1/bio_asn1.c
+new file mode 100644
+index 0000000..400effa
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/asn1/bio_asn1.c
+@@ -0,0 +1,437 @@
++/*
++ * Copyright 2006-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++/*
++ * Experimental ASN1 BIO. When written through the data is converted to an
++ * ASN1 string type: default is OCTET STRING. Additional functions can be
++ * provided to add prefix and suffix data.
++ */
++
++#include 
++#include 
++#include 
++
++/* Must be large enough for biggest tag+length */
++#define DEFAULT_ASN1_BUF_SIZE 20
++
++typedef enum {
++    ASN1_STATE_START,
++    ASN1_STATE_PRE_COPY,
++    ASN1_STATE_HEADER,
++    ASN1_STATE_HEADER_COPY,
++    ASN1_STATE_DATA_COPY,
++    ASN1_STATE_POST_COPY,
++    ASN1_STATE_DONE
++} asn1_bio_state_t;
++
++typedef struct BIO_ASN1_EX_FUNCS_st {
++    asn1_ps_func *ex_func;
++    asn1_ps_func *ex_free_func;
++} BIO_ASN1_EX_FUNCS;
++
++typedef struct BIO_ASN1_BUF_CTX_t {
++    /* Internal state */
++    asn1_bio_state_t state;
++    /* Internal buffer */
++    unsigned char *buf;
++    /* Size of buffer */
++    int bufsize;
++    /* Current position in buffer */
++    int bufpos;
++    /* Current buffer length */
++    int buflen;
++    /* Amount of data to copy */
++    int copylen;
++    /* Class and tag to use */
++    int asn1_class, asn1_tag;
++    asn1_ps_func *prefix, *prefix_free, *suffix, *suffix_free;
++    /* Extra buffer for prefix and suffix data */
++    unsigned char *ex_buf;
++    int ex_len;
++    int ex_pos;
++    void *ex_arg;
++} BIO_ASN1_BUF_CTX;
++
++static int asn1_bio_write(BIO *h, const char *buf, int num);
++static int asn1_bio_read(BIO *h, char *buf, int size);
++static int asn1_bio_puts(BIO *h, const char *str);
++static int asn1_bio_gets(BIO *h, char *str, int size);
++static long asn1_bio_ctrl(BIO *h, int cmd, long arg1, void *arg2);
++static int asn1_bio_new(BIO *h);
++static int asn1_bio_free(BIO *data);
++static long asn1_bio_callback_ctrl(BIO *h, int cmd, bio_info_cb *fp);
++
++static int asn1_bio_init(BIO_ASN1_BUF_CTX *ctx, int size);
++static int asn1_bio_flush_ex(BIO *b, BIO_ASN1_BUF_CTX *ctx,
++                             asn1_ps_func *cleanup, asn1_bio_state_t next);
++static int asn1_bio_setup_ex(BIO *b, BIO_ASN1_BUF_CTX *ctx,
++                             asn1_ps_func *setup,
++                             asn1_bio_state_t ex_state,
++                             asn1_bio_state_t other_state);
++
++static const BIO_METHOD methods_asn1 = {
++    BIO_TYPE_ASN1,
++    "asn1",
++    asn1_bio_write,
++    asn1_bio_read,
++    asn1_bio_puts,
++    asn1_bio_gets,
++    asn1_bio_ctrl,
++    asn1_bio_new,
++    asn1_bio_free,
++    asn1_bio_callback_ctrl,
++};
++
++const BIO_METHOD *BIO_f_asn1(void)
++{
++    return (&methods_asn1);
++}
++
++static int asn1_bio_new(BIO *b)
++{
++    BIO_ASN1_BUF_CTX *ctx = OPENSSL_zalloc(sizeof(*ctx));
++
++    if (ctx == NULL)
++        return 0;
++    if (!asn1_bio_init(ctx, DEFAULT_ASN1_BUF_SIZE)) {
++        OPENSSL_free(ctx);
++        return 0;
++    }
++    BIO_set_data(b, ctx);
++    BIO_set_init(b, 1);
++
++    return 1;
++}
++
++static int asn1_bio_init(BIO_ASN1_BUF_CTX *ctx, int size)
++{
++    ctx->buf = OPENSSL_malloc(size);
++    if (ctx->buf == NULL)
++        return 0;
++    ctx->bufsize = size;
++    ctx->asn1_class = V_ASN1_UNIVERSAL;
++    ctx->asn1_tag = V_ASN1_OCTET_STRING;
++    ctx->state = ASN1_STATE_START;
++    return 1;
++}
++
++static int asn1_bio_free(BIO *b)
++{
++    BIO_ASN1_BUF_CTX *ctx;
++
++    if (b == NULL)
++        return 0;
++
++    ctx = BIO_get_data(b);
++    if (ctx == NULL)
++        return 0;
++
++    OPENSSL_free(ctx->buf);
++    OPENSSL_free(ctx);
++    BIO_set_data(b, NULL);
++    BIO_set_init(b, 0);
++
++    return 1;
++}
++
++static int asn1_bio_write(BIO *b, const char *in, int inl)
++{
++    BIO_ASN1_BUF_CTX *ctx;
++    int wrmax, wrlen, ret;
++    unsigned char *p;
++    BIO *next;
++
++    ctx = BIO_get_data(b);
++    next = BIO_next(b);
++    if (in == NULL || inl < 0 || ctx == NULL || next == NULL)
++        return 0;
++
++    wrlen = 0;
++    ret = -1;
++
++    for (;;) {
++        switch (ctx->state) {
++
++            /* Setup prefix data, call it */
++        case ASN1_STATE_START:
++            if (!asn1_bio_setup_ex(b, ctx, ctx->prefix,
++                                   ASN1_STATE_PRE_COPY, ASN1_STATE_HEADER))
++                return 0;
++            break;
++
++            /* Copy any pre data first */
++        case ASN1_STATE_PRE_COPY:
++
++            ret = asn1_bio_flush_ex(b, ctx, ctx->prefix_free,
++                                    ASN1_STATE_HEADER);
++
++            if (ret <= 0)
++                goto done;
++
++            break;
++
++        case ASN1_STATE_HEADER:
++            ctx->buflen = ASN1_object_size(0, inl, ctx->asn1_tag) - inl;
++            OPENSSL_assert(ctx->buflen <= ctx->bufsize);
++            p = ctx->buf;
++            ASN1_put_object(&p, 0, inl, ctx->asn1_tag, ctx->asn1_class);
++            ctx->copylen = inl;
++            ctx->state = ASN1_STATE_HEADER_COPY;
++
++            break;
++
++        case ASN1_STATE_HEADER_COPY:
++            ret = BIO_write(next, ctx->buf + ctx->bufpos, ctx->buflen);
++            if (ret <= 0)
++                goto done;
++
++            ctx->buflen -= ret;
++            if (ctx->buflen)
++                ctx->bufpos += ret;
++            else {
++                ctx->bufpos = 0;
++                ctx->state = ASN1_STATE_DATA_COPY;
++            }
++
++            break;
++
++        case ASN1_STATE_DATA_COPY:
++
++            if (inl > ctx->copylen)
++                wrmax = ctx->copylen;
++            else
++                wrmax = inl;
++            ret = BIO_write(next, in, wrmax);
++            if (ret <= 0)
++                break;
++            wrlen += ret;
++            ctx->copylen -= ret;
++            in += ret;
++            inl -= ret;
++
++            if (ctx->copylen == 0)
++                ctx->state = ASN1_STATE_HEADER;
++
++            if (inl == 0)
++                goto done;
++
++            break;
++
++        default:
++            BIO_clear_retry_flags(b);
++            return 0;
++
++        }
++
++    }
++
++ done:
++    BIO_clear_retry_flags(b);
++    BIO_copy_next_retry(b);
++
++    return (wrlen > 0) ? wrlen : ret;
++
++}
++
++static int asn1_bio_flush_ex(BIO *b, BIO_ASN1_BUF_CTX *ctx,
++                             asn1_ps_func *cleanup, asn1_bio_state_t next)
++{
++    int ret;
++
++    if (ctx->ex_len <= 0)
++        return 1;
++    for (;;) {
++        ret = BIO_write(BIO_next(b), ctx->ex_buf + ctx->ex_pos, ctx->ex_len);
++        if (ret <= 0)
++            break;
++        ctx->ex_len -= ret;
++        if (ctx->ex_len > 0)
++            ctx->ex_pos += ret;
++        else {
++            if (cleanup)
++                cleanup(b, &ctx->ex_buf, &ctx->ex_len, &ctx->ex_arg);
++            ctx->state = next;
++            ctx->ex_pos = 0;
++            break;
++        }
++    }
++    return ret;
++}
++
++static int asn1_bio_setup_ex(BIO *b, BIO_ASN1_BUF_CTX *ctx,
++                             asn1_ps_func *setup,
++                             asn1_bio_state_t ex_state,
++                             asn1_bio_state_t other_state)
++{
++    if (setup && !setup(b, &ctx->ex_buf, &ctx->ex_len, &ctx->ex_arg)) {
++        BIO_clear_retry_flags(b);
++        return 0;
++    }
++    if (ctx->ex_len > 0)
++        ctx->state = ex_state;
++    else
++        ctx->state = other_state;
++    return 1;
++}
++
++static int asn1_bio_read(BIO *b, char *in, int inl)
++{
++    BIO *next = BIO_next(b);
++    if (next == NULL)
++        return 0;
++    return BIO_read(next, in, inl);
++}
++
++static int asn1_bio_puts(BIO *b, const char *str)
++{
++    return asn1_bio_write(b, str, strlen(str));
++}
++
++static int asn1_bio_gets(BIO *b, char *str, int size)
++{
++    BIO *next = BIO_next(b);
++    if (next == NULL)
++        return 0;
++    return BIO_gets(next, str, size);
++}
++
++static long asn1_bio_callback_ctrl(BIO *b, int cmd, bio_info_cb *fp)
++{
++    BIO *next = BIO_next(b);
++    if (next == NULL)
++        return 0;
++    return BIO_callback_ctrl(next, cmd, fp);
++}
++
++static long asn1_bio_ctrl(BIO *b, int cmd, long arg1, void *arg2)
++{
++    BIO_ASN1_BUF_CTX *ctx;
++    BIO_ASN1_EX_FUNCS *ex_func;
++    long ret = 1;
++    BIO *next;
++
++    ctx = BIO_get_data(b);
++    if (ctx == NULL)
++        return 0;
++    next = BIO_next(b);
++    switch (cmd) {
++
++    case BIO_C_SET_PREFIX:
++        ex_func = arg2;
++        ctx->prefix = ex_func->ex_func;
++        ctx->prefix_free = ex_func->ex_free_func;
++        break;
++
++    case BIO_C_GET_PREFIX:
++        ex_func = arg2;
++        ex_func->ex_func = ctx->prefix;
++        ex_func->ex_free_func = ctx->prefix_free;
++        break;
++
++    case BIO_C_SET_SUFFIX:
++        ex_func = arg2;
++        ctx->suffix = ex_func->ex_func;
++        ctx->suffix_free = ex_func->ex_free_func;
++        break;
++
++    case BIO_C_GET_SUFFIX:
++        ex_func = arg2;
++        ex_func->ex_func = ctx->suffix;
++        ex_func->ex_free_func = ctx->suffix_free;
++        break;
++
++    case BIO_C_SET_EX_ARG:
++        ctx->ex_arg = arg2;
++        break;
++
++    case BIO_C_GET_EX_ARG:
++        *(void **)arg2 = ctx->ex_arg;
++        break;
++
++    case BIO_CTRL_FLUSH:
++        if (next == NULL)
++            return 0;
++
++        /* Call post function if possible */
++        if (ctx->state == ASN1_STATE_HEADER) {
++            if (!asn1_bio_setup_ex(b, ctx, ctx->suffix,
++                                   ASN1_STATE_POST_COPY, ASN1_STATE_DONE))
++                return 0;
++        }
++
++        if (ctx->state == ASN1_STATE_POST_COPY) {
++            ret = asn1_bio_flush_ex(b, ctx, ctx->suffix_free,
++                                    ASN1_STATE_DONE);
++            if (ret <= 0)
++                return ret;
++        }
++
++        if (ctx->state == ASN1_STATE_DONE)
++            return BIO_ctrl(next, cmd, arg1, arg2);
++        else {
++            BIO_clear_retry_flags(b);
++            return 0;
++        }
++
++    default:
++        if (next == NULL)
++            return 0;
++        return BIO_ctrl(next, cmd, arg1, arg2);
++
++    }
++
++    return ret;
++}
++
++static int asn1_bio_set_ex(BIO *b, int cmd,
++                           asn1_ps_func *ex_func, asn1_ps_func *ex_free_func)
++{
++    BIO_ASN1_EX_FUNCS extmp;
++    extmp.ex_func = ex_func;
++    extmp.ex_free_func = ex_free_func;
++    return BIO_ctrl(b, cmd, 0, &extmp);
++}
++
++static int asn1_bio_get_ex(BIO *b, int cmd,
++                           asn1_ps_func **ex_func,
++                           asn1_ps_func **ex_free_func)
++{
++    BIO_ASN1_EX_FUNCS extmp;
++    int ret;
++    ret = BIO_ctrl(b, cmd, 0, &extmp);
++    if (ret > 0) {
++        *ex_func = extmp.ex_func;
++        *ex_free_func = extmp.ex_free_func;
++    }
++    return ret;
++}
++
++int BIO_asn1_set_prefix(BIO *b, asn1_ps_func *prefix,
++                        asn1_ps_func *prefix_free)
++{
++    return asn1_bio_set_ex(b, BIO_C_SET_PREFIX, prefix, prefix_free);
++}
++
++int BIO_asn1_get_prefix(BIO *b, asn1_ps_func **pprefix,
++                        asn1_ps_func **pprefix_free)
++{
++    return asn1_bio_get_ex(b, BIO_C_GET_PREFIX, pprefix, pprefix_free);
++}
++
++int BIO_asn1_set_suffix(BIO *b, asn1_ps_func *suffix,
++                        asn1_ps_func *suffix_free)
++{
++    return asn1_bio_set_ex(b, BIO_C_SET_SUFFIX, suffix, suffix_free);
++}
++
++int BIO_asn1_get_suffix(BIO *b, asn1_ps_func **psuffix,
++                        asn1_ps_func **psuffix_free)
++{
++    return asn1_bio_get_ex(b, BIO_C_GET_SUFFIX, psuffix, psuffix_free);
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/asn1/bio_ndef.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/asn1/bio_ndef.c
+new file mode 100644
+index 0000000..0f206b2
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/asn1/bio_ndef.c
+@@ -0,0 +1,199 @@
++/*
++ * Copyright 2008-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include 
++#include 
++#include 
++
++#include 
++
++/* Experimental NDEF ASN1 BIO support routines */
++
++/*
++ * The usage is quite simple, initialize an ASN1 structure, get a BIO from it
++ * then any data written through the BIO will end up translated to
++ * appropriate format on the fly. The data is streamed out and does *not*
++ * need to be all held in memory at once. When the BIO is flushed the output
++ * is finalized and any signatures etc written out. The BIO is a 'proper'
++ * BIO and can handle non blocking I/O correctly. The usage is simple. The
++ * implementation is *not*...
++ */
++
++/* BIO support data stored in the ASN1 BIO ex_arg */
++
++typedef struct ndef_aux_st {
++    /* ASN1 structure this BIO refers to */
++    ASN1_VALUE *val;
++    const ASN1_ITEM *it;
++    /* Top of the BIO chain */
++    BIO *ndef_bio;
++    /* Output BIO */
++    BIO *out;
++    /* Boundary where content is inserted */
++    unsigned char **boundary;
++    /* DER buffer start */
++    unsigned char *derbuf;
++} NDEF_SUPPORT;
++
++static int ndef_prefix(BIO *b, unsigned char **pbuf, int *plen, void *parg);
++static int ndef_prefix_free(BIO *b, unsigned char **pbuf, int *plen,
++                            void *parg);
++static int ndef_suffix(BIO *b, unsigned char **pbuf, int *plen, void *parg);
++static int ndef_suffix_free(BIO *b, unsigned char **pbuf, int *plen,
++                            void *parg);
++
++BIO *BIO_new_NDEF(BIO *out, ASN1_VALUE *val, const ASN1_ITEM *it)
++{
++    NDEF_SUPPORT *ndef_aux = NULL;
++    BIO *asn_bio = NULL;
++    const ASN1_AUX *aux = it->funcs;
++    ASN1_STREAM_ARG sarg;
++
++    if (!aux || !aux->asn1_cb) {
++        ASN1err(ASN1_F_BIO_NEW_NDEF, ASN1_R_STREAMING_NOT_SUPPORTED);
++        return NULL;
++    }
++    ndef_aux = OPENSSL_zalloc(sizeof(*ndef_aux));
++    asn_bio = BIO_new(BIO_f_asn1());
++    if (ndef_aux == NULL || asn_bio == NULL)
++        goto err;
++
++    /* ASN1 bio needs to be next to output BIO */
++    out = BIO_push(asn_bio, out);
++    if (out == NULL)
++        goto err;
++
++    BIO_asn1_set_prefix(asn_bio, ndef_prefix, ndef_prefix_free);
++    BIO_asn1_set_suffix(asn_bio, ndef_suffix, ndef_suffix_free);
++
++    /*
++     * Now let callback prepends any digest, cipher etc BIOs ASN1 structure
++     * needs.
++     */
++
++    sarg.out = out;
++    sarg.ndef_bio = NULL;
++    sarg.boundary = NULL;
++
++    if (aux->asn1_cb(ASN1_OP_STREAM_PRE, &val, it, &sarg) <= 0)
++        goto err;
++
++    ndef_aux->val = val;
++    ndef_aux->it = it;
++    ndef_aux->ndef_bio = sarg.ndef_bio;
++    ndef_aux->boundary = sarg.boundary;
++    ndef_aux->out = out;
++
++    BIO_ctrl(asn_bio, BIO_C_SET_EX_ARG, 0, ndef_aux);
++
++    return sarg.ndef_bio;
++
++ err:
++    BIO_free(asn_bio);
++    OPENSSL_free(ndef_aux);
++    return NULL;
++}
++
++static int ndef_prefix(BIO *b, unsigned char **pbuf, int *plen, void *parg)
++{
++    NDEF_SUPPORT *ndef_aux;
++    unsigned char *p;
++    int derlen;
++
++    if (!parg)
++        return 0;
++
++    ndef_aux = *(NDEF_SUPPORT **)parg;
++
++    derlen = ASN1_item_ndef_i2d(ndef_aux->val, NULL, ndef_aux->it);
++    p = OPENSSL_malloc(derlen);
++    if (p == NULL)
++        return 0;
++
++    ndef_aux->derbuf = p;
++    *pbuf = p;
++    derlen = ASN1_item_ndef_i2d(ndef_aux->val, &p, ndef_aux->it);
++
++    if (!*ndef_aux->boundary)
++        return 0;
++
++    *plen = *ndef_aux->boundary - *pbuf;
++
++    return 1;
++}
++
++static int ndef_prefix_free(BIO *b, unsigned char **pbuf, int *plen,
++                            void *parg)
++{
++    NDEF_SUPPORT *ndef_aux;
++
++    if (!parg)
++        return 0;
++
++    ndef_aux = *(NDEF_SUPPORT **)parg;
++
++    OPENSSL_free(ndef_aux->derbuf);
++
++    ndef_aux->derbuf = NULL;
++    *pbuf = NULL;
++    *plen = 0;
++    return 1;
++}
++
++static int ndef_suffix_free(BIO *b, unsigned char **pbuf, int *plen,
++                            void *parg)
++{
++    NDEF_SUPPORT **pndef_aux = (NDEF_SUPPORT **)parg;
++    if (!ndef_prefix_free(b, pbuf, plen, parg))
++        return 0;
++    OPENSSL_free(*pndef_aux);
++    *pndef_aux = NULL;
++    return 1;
++}
++
++static int ndef_suffix(BIO *b, unsigned char **pbuf, int *plen, void *parg)
++{
++    NDEF_SUPPORT *ndef_aux;
++    unsigned char *p;
++    int derlen;
++    const ASN1_AUX *aux;
++    ASN1_STREAM_ARG sarg;
++
++    if (!parg)
++        return 0;
++
++    ndef_aux = *(NDEF_SUPPORT **)parg;
++
++    aux = ndef_aux->it->funcs;
++
++    /* Finalize structures */
++    sarg.ndef_bio = ndef_aux->ndef_bio;
++    sarg.out = ndef_aux->out;
++    sarg.boundary = ndef_aux->boundary;
++    if (aux->asn1_cb(ASN1_OP_STREAM_POST,
++                     &ndef_aux->val, ndef_aux->it, &sarg) <= 0)
++        return 0;
++
++    derlen = ASN1_item_ndef_i2d(ndef_aux->val, NULL, ndef_aux->it);
++    p = OPENSSL_malloc(derlen);
++    if (p == NULL)
++        return 0;
++
++    ndef_aux->derbuf = p;
++    *pbuf = p;
++    derlen = ASN1_item_ndef_i2d(ndef_aux->val, &p, ndef_aux->it);
++
++    if (!*ndef_aux->boundary)
++        return 0;
++    *pbuf = *ndef_aux->boundary;
++    *plen = derlen - (*ndef_aux->boundary - ndef_aux->derbuf);
++
++    return 1;
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/asn1/build.info b/CryptoPkg/Library/OpensslLib/openssl/crypto/asn1/build.info
+new file mode 100644
+index 0000000..02d1120
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/asn1/build.info
+@@ -0,0 +1,16 @@
++LIBS=../../libcrypto
++SOURCE[../../libcrypto]=\
++        a_object.c a_bitstr.c a_utctm.c a_gentm.c a_time.c a_int.c a_octet.c \
++        a_print.c a_type.c a_dup.c a_d2i_fp.c a_i2d_fp.c \
++        a_utf8.c a_sign.c a_digest.c a_verify.c a_mbstr.c a_strex.c \
++        x_algor.c x_val.c x_sig.c x_bignum.c \
++        x_long.c x_info.c x_spki.c nsseq.c \
++        d2i_pu.c d2i_pr.c i2d_pu.c i2d_pr.c\
++        t_pkey.c t_spki.c t_bitst.c \
++        tasn_new.c tasn_fre.c tasn_enc.c tasn_dec.c tasn_utl.c tasn_typ.c \
++        tasn_prn.c tasn_scn.c ameth_lib.c \
++        f_int.c f_string.c n_pkey.c \
++        x_pkey.c bio_asn1.c bio_ndef.c asn_mime.c \
++        asn1_gen.c asn1_par.c asn1_lib.c asn1_err.c a_strnid.c \
++        evp_asn1.c asn_pack.c p5_pbe.c p5_pbev2.c p5_scrypt.c p8_pkey.c \
++        asn_moid.c asn_mstbl.c
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/asn1/charmap.h b/CryptoPkg/Library/OpensslLib/openssl/crypto/asn1/charmap.h
+new file mode 100644
+index 0000000..2a75925
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/asn1/charmap.h
+@@ -0,0 +1,34 @@
++/*
++ * WARNING: do not edit!
++ * Generated by crypto/asn1/charmap.pl
++ *
++ * Copyright 2000-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#define CHARTYPE_HOST_ANY 4096
++#define CHARTYPE_HOST_DOT 8192
++#define CHARTYPE_HOST_HYPHEN 16384
++#define CHARTYPE_HOST_WILD 32768
++
++/*
++ * Mask of various character properties
++ */
++
++static const unsigned short char_type[] = {
++    1026,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,
++       2,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,
++       2,    2,    2,    2,    2,    2,    2,    2,  120,    0,    1,   40,
++       0,    0,    0,   16, 1040, 1040, 33792,   25,   25, 16400, 8208,   16,
++    4112, 4112, 4112, 4112, 4112, 4112, 4112, 4112, 4112, 4112,   16,    9,
++       9,   16,    9,   16,    0, 4112, 4112, 4112, 4112, 4112, 4112, 4112,
++    4112, 4112, 4112, 4112, 4112, 4112, 4112, 4112, 4112, 4112, 4112, 4112,
++    4112, 4112, 4112, 4112, 4112, 4112, 4112,    0, 1025,    0,    0,    0,
++       0, 4112, 4112, 4112, 4112, 4112, 4112, 4112, 4112, 4112, 4112, 4112,
++    4112, 4112, 4112, 4112, 4112, 4112, 4112, 4112, 4112, 4112, 4112, 4112,
++    4112, 4112, 4112,    0,    0,    0,    0,    2
++};
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/asn1/charmap.pl b/CryptoPkg/Library/OpensslLib/openssl/crypto/asn1/charmap.pl
+new file mode 100644
+index 0000000..26ca325
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/asn1/charmap.pl
+@@ -0,0 +1,117 @@
++#! /usr/bin/env perl
++# Copyright 2000-2016 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
++# in the file LICENSE in the source distribution or at
++# https://www.openssl.org/source/license.html
++
++use strict;
++
++my ($i, @arr);
++
++# Set up an array with the type of ASCII characters
++# Each set bit represents a character property.
++
++# RFC2253 character properties
++my $RFC2253_ESC = 1;	# Character escaped with \
++my $ESC_CTRL	= 2;	# Escaped control character
++# These are used with RFC1779 quoting using "
++my $NOESC_QUOTE	= 8;	# Not escaped if quoted
++my $PSTRING_CHAR = 0x10;	# Valid PrintableString character
++my $RFC2253_FIRST_ESC = 0x20; # Escaped with \ if first character
++my $RFC2253_LAST_ESC = 0x40;  # Escaped with \ if last character
++my $RFC2254_ESC = 0x400;	# Character escaped \XX
++my $HOST_ANY = 0x1000;      # Valid hostname character anywhere in label
++my $HOST_DOT = 0x2000;  # Dot: hostname label separator
++my $HOST_HYPHEN = 0x4000; # Hyphen: not valid at start or end.
++my $HOST_WILD = 0x8000; # Wildcard character
++
++for($i = 0; $i < 128; $i++) {
++	# Set the RFC2253 escape characters (control)
++	$arr[$i] = 0;
++	if(($i < 32) || ($i > 126)) {
++		$arr[$i] |= $ESC_CTRL;
++	}
++
++	# Some PrintableString characters
++	if(		   ( ( $i >= ord("a")) && ( $i <= ord("z")) )
++			|| (  ( $i >= ord("A")) && ( $i <= ord("Z")) )
++			|| (  ( $i >= ord("0")) && ( $i <= ord("9")) )  ) {
++		$arr[$i] |= $PSTRING_CHAR | $HOST_ANY;
++	}
++}
++
++# Now setup the rest
++
++# Remaining RFC2253 escaped characters
++
++$arr[ord(" ")] |= $NOESC_QUOTE | $RFC2253_FIRST_ESC | $RFC2253_LAST_ESC;
++$arr[ord("#")] |= $NOESC_QUOTE | $RFC2253_FIRST_ESC;
++
++$arr[ord(",")] |= $NOESC_QUOTE | $RFC2253_ESC;
++$arr[ord("+")] |= $NOESC_QUOTE | $RFC2253_ESC;
++$arr[ord("\"")] |= $RFC2253_ESC;
++$arr[ord("\\")] |= $RFC2253_ESC;
++$arr[ord("<")] |= $NOESC_QUOTE | $RFC2253_ESC;
++$arr[ord(">")] |= $NOESC_QUOTE | $RFC2253_ESC;
++$arr[ord(";")] |= $NOESC_QUOTE | $RFC2253_ESC;
++
++# Remaining RFC2254 characters
++
++$arr[0] |= $RFC2254_ESC;
++$arr[ord("(")] |= $RFC2254_ESC;
++$arr[ord(")")] |= $RFC2254_ESC;
++$arr[ord("*")] |= $RFC2254_ESC | $HOST_WILD;
++$arr[ord("\\")] |= $RFC2254_ESC;
++
++# Remaining PrintableString characters
++
++$arr[ord(" ")] |= $PSTRING_CHAR;
++$arr[ord("'")] |= $PSTRING_CHAR;
++$arr[ord("(")] |= $PSTRING_CHAR;
++$arr[ord(")")] |= $PSTRING_CHAR;
++$arr[ord("+")] |= $PSTRING_CHAR;
++$arr[ord(",")] |= $PSTRING_CHAR;
++$arr[ord("-")] |= $PSTRING_CHAR | $HOST_HYPHEN;
++$arr[ord(".")] |= $PSTRING_CHAR | $HOST_DOT;
++$arr[ord("/")] |= $PSTRING_CHAR;
++$arr[ord(":")] |= $PSTRING_CHAR;
++$arr[ord("=")] |= $PSTRING_CHAR;
++$arr[ord("?")] |= $PSTRING_CHAR;
++
++# Now generate the C code
++
++print <
++#include "internal/cryptlib.h"
++#include 
++#include 
++#include 
++#include 
++#include 
++#include 
++#include "internal/asn1_int.h"
++#include "internal/evp_int.h"
++
++EVP_PKEY *d2i_PrivateKey(int type, EVP_PKEY **a, const unsigned char **pp,
++                         long length)
++{
++    EVP_PKEY *ret;
++    const unsigned char *p = *pp;
++
++    if ((a == NULL) || (*a == NULL)) {
++        if ((ret = EVP_PKEY_new()) == NULL) {
++            ASN1err(ASN1_F_D2I_PRIVATEKEY, ERR_R_EVP_LIB);
++            return (NULL);
++        }
++    } else {
++        ret = *a;
++#ifndef OPENSSL_NO_ENGINE
++        ENGINE_finish(ret->engine);
++        ret->engine = NULL;
++#endif
++    }
++
++    if (!EVP_PKEY_set_type(ret, type)) {
++        ASN1err(ASN1_F_D2I_PRIVATEKEY, ASN1_R_UNKNOWN_PUBLIC_KEY_TYPE);
++        goto err;
++    }
++
++    if (!ret->ameth->old_priv_decode ||
++        !ret->ameth->old_priv_decode(ret, &p, length)) {
++        if (ret->ameth->priv_decode) {
++            EVP_PKEY *tmp;
++            PKCS8_PRIV_KEY_INFO *p8 = NULL;
++            p8 = d2i_PKCS8_PRIV_KEY_INFO(NULL, &p, length);
++            if (!p8)
++                goto err;
++            tmp = EVP_PKCS82PKEY(p8);
++            PKCS8_PRIV_KEY_INFO_free(p8);
++            if (tmp == NULL)
++                goto err;
++            EVP_PKEY_free(ret);
++            ret = tmp;
++        } else {
++            ASN1err(ASN1_F_D2I_PRIVATEKEY, ERR_R_ASN1_LIB);
++            goto err;
++        }
++    }
++    *pp = p;
++    if (a != NULL)
++        (*a) = ret;
++    return (ret);
++ err:
++    if (a == NULL || *a != ret)
++        EVP_PKEY_free(ret);
++    return (NULL);
++}
++
++/*
++ * This works like d2i_PrivateKey() except it automatically works out the
++ * type
++ */
++
++EVP_PKEY *d2i_AutoPrivateKey(EVP_PKEY **a, const unsigned char **pp,
++                             long length)
++{
++    STACK_OF(ASN1_TYPE) *inkey;
++    const unsigned char *p;
++    int keytype;
++    p = *pp;
++    /*
++     * Dirty trick: read in the ASN1 data into a STACK_OF(ASN1_TYPE): by
++     * analyzing it we can determine the passed structure: this assumes the
++     * input is surrounded by an ASN1 SEQUENCE.
++     */
++    inkey = d2i_ASN1_SEQUENCE_ANY(NULL, &p, length);
++    p = *pp;
++    /*
++     * Since we only need to discern "traditional format" RSA and DSA keys we
++     * can just count the elements.
++     */
++    if (sk_ASN1_TYPE_num(inkey) == 6)
++        keytype = EVP_PKEY_DSA;
++    else if (sk_ASN1_TYPE_num(inkey) == 4)
++        keytype = EVP_PKEY_EC;
++    else if (sk_ASN1_TYPE_num(inkey) == 3) { /* This seems to be PKCS8, not
++                                              * traditional format */
++        PKCS8_PRIV_KEY_INFO *p8 = d2i_PKCS8_PRIV_KEY_INFO(NULL, &p, length);
++        EVP_PKEY *ret;
++
++        sk_ASN1_TYPE_pop_free(inkey, ASN1_TYPE_free);
++        if (!p8) {
++            ASN1err(ASN1_F_D2I_AUTOPRIVATEKEY,
++                    ASN1_R_UNSUPPORTED_PUBLIC_KEY_TYPE);
++            return NULL;
++        }
++        ret = EVP_PKCS82PKEY(p8);
++        PKCS8_PRIV_KEY_INFO_free(p8);
++        if (ret == NULL)
++            return NULL;
++        *pp = p;
++        if (a) {
++            *a = ret;
++        }
++        return ret;
++    } else
++        keytype = EVP_PKEY_RSA;
++    sk_ASN1_TYPE_pop_free(inkey, ASN1_TYPE_free);
++    return d2i_PrivateKey(keytype, a, pp, length);
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/asn1/d2i_pu.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/asn1/d2i_pu.c
+new file mode 100644
+index 0000000..dfdc1a6
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/asn1/d2i_pu.c
+@@ -0,0 +1,78 @@
++/*
++ * Copyright 1995-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include "internal/cryptlib.h"
++#include 
++#include 
++#include 
++#include 
++#include 
++#include 
++#include 
++
++#include "internal/evp_int.h"
++
++EVP_PKEY *d2i_PublicKey(int type, EVP_PKEY **a, const unsigned char **pp,
++                        long length)
++{
++    EVP_PKEY *ret;
++
++    if ((a == NULL) || (*a == NULL)) {
++        if ((ret = EVP_PKEY_new()) == NULL) {
++            ASN1err(ASN1_F_D2I_PUBLICKEY, ERR_R_EVP_LIB);
++            return (NULL);
++        }
++    } else
++        ret = *a;
++
++    if (!EVP_PKEY_set_type(ret, type)) {
++        ASN1err(ASN1_F_D2I_PUBLICKEY, ERR_R_EVP_LIB);
++        goto err;
++    }
++
++    switch (EVP_PKEY_id(ret)) {
++#ifndef OPENSSL_NO_RSA
++    case EVP_PKEY_RSA:
++        if ((ret->pkey.rsa = d2i_RSAPublicKey(NULL, pp, length)) == NULL) {
++            ASN1err(ASN1_F_D2I_PUBLICKEY, ERR_R_ASN1_LIB);
++            goto err;
++        }
++        break;
++#endif
++#ifndef OPENSSL_NO_DSA
++    case EVP_PKEY_DSA:
++        /* TMP UGLY CAST */
++        if (!d2i_DSAPublicKey(&ret->pkey.dsa, pp, length)) {
++            ASN1err(ASN1_F_D2I_PUBLICKEY, ERR_R_ASN1_LIB);
++            goto err;
++        }
++        break;
++#endif
++#ifndef OPENSSL_NO_EC
++    case EVP_PKEY_EC:
++        if (!o2i_ECPublicKey(&ret->pkey.ec, pp, length)) {
++            ASN1err(ASN1_F_D2I_PUBLICKEY, ERR_R_ASN1_LIB);
++            goto err;
++        }
++        break;
++#endif
++    default:
++        ASN1err(ASN1_F_D2I_PUBLICKEY, ASN1_R_UNKNOWN_PUBLIC_KEY_TYPE);
++        goto err;
++        /* break; */
++    }
++    if (a != NULL)
++        (*a) = ret;
++    return (ret);
++ err:
++    if (a == NULL || *a != ret)
++        EVP_PKEY_free(ret);
++    return (NULL);
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/asn1/evp_asn1.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/asn1/evp_asn1.c
+new file mode 100644
+index 0000000..a458367
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/asn1/evp_asn1.c
+@@ -0,0 +1,115 @@
++/*
++ * Copyright 1995-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include "internal/cryptlib.h"
++#include 
++#include 
++
++int ASN1_TYPE_set_octetstring(ASN1_TYPE *a, unsigned char *data, int len)
++{
++    ASN1_STRING *os;
++
++    if ((os = ASN1_OCTET_STRING_new()) == NULL)
++        return (0);
++    if (!ASN1_OCTET_STRING_set(os, data, len)) {
++        ASN1_OCTET_STRING_free(os);
++        return 0;
++    }
++    ASN1_TYPE_set(a, V_ASN1_OCTET_STRING, os);
++    return (1);
++}
++
++/* int max_len:  for returned value    */
++int ASN1_TYPE_get_octetstring(const ASN1_TYPE *a, unsigned char *data, int max_len)
++{
++    int ret, num;
++    const unsigned char *p;
++
++    if ((a->type != V_ASN1_OCTET_STRING) || (a->value.octet_string == NULL)) {
++        ASN1err(ASN1_F_ASN1_TYPE_GET_OCTETSTRING, ASN1_R_DATA_IS_WRONG);
++        return (-1);
++    }
++    p = ASN1_STRING_get0_data(a->value.octet_string);
++    ret = ASN1_STRING_length(a->value.octet_string);
++    if (ret < max_len)
++        num = ret;
++    else
++        num = max_len;
++    memcpy(data, p, num);
++    return (ret);
++}
++
++typedef struct {
++    long num;
++    ASN1_OCTET_STRING *oct;
++} asn1_int_oct;
++
++ASN1_SEQUENCE(asn1_int_oct) = {
++        ASN1_SIMPLE(asn1_int_oct, num, LONG),
++        ASN1_SIMPLE(asn1_int_oct, oct, ASN1_OCTET_STRING)
++} static_ASN1_SEQUENCE_END(asn1_int_oct)
++
++DECLARE_ASN1_ITEM(asn1_int_oct)
++
++int ASN1_TYPE_set_int_octetstring(ASN1_TYPE *a, long num, unsigned char *data,
++                                  int len)
++{
++    asn1_int_oct atmp;
++    ASN1_OCTET_STRING oct;
++
++    atmp.num = num;
++    atmp.oct = &oct;
++    oct.data = data;
++    oct.type = V_ASN1_OCTET_STRING;
++    oct.length = len;
++    oct.flags = 0;
++
++    if (ASN1_TYPE_pack_sequence(ASN1_ITEM_rptr(asn1_int_oct), &atmp, &a))
++        return 1;
++    return 0;
++}
++
++/*
++ * we return the actual length...
++ */
++/* int max_len:  for returned value    */
++int ASN1_TYPE_get_int_octetstring(const ASN1_TYPE *a, long *num,
++                                  unsigned char *data, int max_len)
++{
++    asn1_int_oct *atmp = NULL;
++    int ret = -1, n;
++
++    if ((a->type != V_ASN1_SEQUENCE) || (a->value.sequence == NULL)) {
++        goto err;
++    }
++
++    atmp = ASN1_TYPE_unpack_sequence(ASN1_ITEM_rptr(asn1_int_oct), a);
++
++    if (atmp == NULL)
++        goto err;
++
++    if (num != NULL)
++        *num = atmp->num;
++
++    ret = ASN1_STRING_length(atmp->oct);
++    if (max_len > ret)
++        n = ret;
++    else
++        n = max_len;
++
++    if (data != NULL)
++        memcpy(data, ASN1_STRING_get0_data(atmp->oct), n);
++    if (ret == -1) {
++ err:
++        ASN1err(ASN1_F_ASN1_TYPE_GET_INT_OCTETSTRING, ASN1_R_DATA_IS_WRONG);
++    }
++    M_ASN1_free_of(atmp, asn1_int_oct);
++    return ret;
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/asn1/f_int.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/asn1/f_int.c
+new file mode 100644
+index 0000000..51fc884
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/asn1/f_int.c
+@@ -0,0 +1,167 @@
++/*
++ * Copyright 1995-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include 
++#include "internal/cryptlib.h"
++#include 
++#include 
++
++int i2a_ASN1_INTEGER(BIO *bp, const ASN1_INTEGER *a)
++{
++    int i, n = 0;
++    static const char *h = "0123456789ABCDEF";
++    char buf[2];
++
++    if (a == NULL)
++        return (0);
++
++    if (a->type & V_ASN1_NEG) {
++        if (BIO_write(bp, "-", 1) != 1)
++            goto err;
++        n = 1;
++    }
++
++    if (a->length == 0) {
++        if (BIO_write(bp, "00", 2) != 2)
++            goto err;
++        n += 2;
++    } else {
++        for (i = 0; i < a->length; i++) {
++            if ((i != 0) && (i % 35 == 0)) {
++                if (BIO_write(bp, "\\\n", 2) != 2)
++                    goto err;
++                n += 2;
++            }
++            buf[0] = h[((unsigned char)a->data[i] >> 4) & 0x0f];
++            buf[1] = h[((unsigned char)a->data[i]) & 0x0f];
++            if (BIO_write(bp, buf, 2) != 2)
++                goto err;
++            n += 2;
++        }
++    }
++    return (n);
++ err:
++    return (-1);
++}
++
++int a2i_ASN1_INTEGER(BIO *bp, ASN1_INTEGER *bs, char *buf, int size)
++{
++    int i, j, k, m, n, again, bufsize;
++    unsigned char *s = NULL, *sp;
++    unsigned char *bufp;
++    int num = 0, slen = 0, first = 1;
++
++    bs->type = V_ASN1_INTEGER;
++
++    bufsize = BIO_gets(bp, buf, size);
++    for (;;) {
++        if (bufsize < 1)
++            goto err;
++        i = bufsize;
++        if (buf[i - 1] == '\n')
++            buf[--i] = '\0';
++        if (i == 0)
++            goto err;
++        if (buf[i - 1] == '\r')
++            buf[--i] = '\0';
++        if (i == 0)
++            goto err;
++        again = (buf[i - 1] == '\\');
++
++        for (j = 0; j < i; j++) {
++#ifndef CHARSET_EBCDIC
++            if (!(((buf[j] >= '0') && (buf[j] <= '9')) ||
++                  ((buf[j] >= 'a') && (buf[j] <= 'f')) ||
++                  ((buf[j] >= 'A') && (buf[j] <= 'F'))))
++#else
++            /*
++             * This #ifdef is not strictly necessary, since the characters
++             * A...F a...f 0...9 are contiguous (yes, even in EBCDIC - but
++             * not the whole alphabet). Nevertheless, isxdigit() is faster.
++             */
++            if (!isxdigit(buf[j]))
++#endif
++            {
++                i = j;
++                break;
++            }
++        }
++        buf[i] = '\0';
++        /*
++         * We have now cleared all the crap off the end of the line
++         */
++        if (i < 2)
++            goto err;
++
++        bufp = (unsigned char *)buf;
++        if (first) {
++            first = 0;
++            if ((bufp[0] == '0') && (buf[1] == '0')) {
++                bufp += 2;
++                i -= 2;
++            }
++        }
++        k = 0;
++        i -= again;
++        if (i % 2 != 0) {
++            ASN1err(ASN1_F_A2I_ASN1_INTEGER, ASN1_R_ODD_NUMBER_OF_CHARS);
++            OPENSSL_free(s);
++            return 0;
++        }
++        i /= 2;
++        if (num + i > slen) {
++            sp = OPENSSL_clear_realloc(s, slen, num + i * 2);
++            if (sp == NULL) {
++                ASN1err(ASN1_F_A2I_ASN1_INTEGER, ERR_R_MALLOC_FAILURE);
++                OPENSSL_free(s);
++                return 0;
++            }
++            s = sp;
++            slen = num + i * 2;
++        }
++        for (j = 0; j < i; j++, k += 2) {
++            for (n = 0; n < 2; n++) {
++                m = OPENSSL_hexchar2int(bufp[k + n]);
++                if (m < 0) {
++                    ASN1err(ASN1_F_A2I_ASN1_INTEGER,
++                            ASN1_R_NON_HEX_CHARACTERS);
++                    goto err;
++                }
++                s[num + j] <<= 4;
++                s[num + j] |= m;
++            }
++        }
++        num += i;
++        if (again)
++            bufsize = BIO_gets(bp, buf, size);
++        else
++            break;
++    }
++    bs->length = num;
++    bs->data = s;
++    return 1;
++ err:
++    ASN1err(ASN1_F_A2I_ASN1_INTEGER, ASN1_R_SHORT_LINE);
++    OPENSSL_free(s);
++    return 0;
++}
++
++int i2a_ASN1_ENUMERATED(BIO *bp, const ASN1_ENUMERATED *a)
++{
++    return i2a_ASN1_INTEGER(bp, a);
++}
++
++int a2i_ASN1_ENUMERATED(BIO *bp, ASN1_ENUMERATED *bs, char *buf, int size)
++{
++    int rv = a2i_ASN1_INTEGER(bp, bs, buf, size);
++    if (rv == 1)
++        bs->type = V_ASN1_INTEGER | (bs->type & V_ASN1_NEG);
++    return rv;
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/asn1/f_string.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/asn1/f_string.c
+new file mode 100644
+index 0000000..b9258bb
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/asn1/f_string.c
+@@ -0,0 +1,148 @@
++/*
++ * Copyright 1995-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include 
++#include "internal/cryptlib.h"
++#include 
++#include 
++
++int i2a_ASN1_STRING(BIO *bp, const ASN1_STRING *a, int type)
++{
++    int i, n = 0;
++    static const char *h = "0123456789ABCDEF";
++    char buf[2];
++
++    if (a == NULL)
++        return (0);
++
++    if (a->length == 0) {
++        if (BIO_write(bp, "0", 1) != 1)
++            goto err;
++        n = 1;
++    } else {
++        for (i = 0; i < a->length; i++) {
++            if ((i != 0) && (i % 35 == 0)) {
++                if (BIO_write(bp, "\\\n", 2) != 2)
++                    goto err;
++                n += 2;
++            }
++            buf[0] = h[((unsigned char)a->data[i] >> 4) & 0x0f];
++            buf[1] = h[((unsigned char)a->data[i]) & 0x0f];
++            if (BIO_write(bp, buf, 2) != 2)
++                goto err;
++            n += 2;
++        }
++    }
++    return (n);
++ err:
++    return (-1);
++}
++
++int a2i_ASN1_STRING(BIO *bp, ASN1_STRING *bs, char *buf, int size)
++{
++    int i, j, k, m, n, again, bufsize, spec_char;
++    unsigned char *s = NULL, *sp;
++    unsigned char *bufp;
++    int num = 0, slen = 0, first = 1;
++
++    bufsize = BIO_gets(bp, buf, size);
++    for (;;) {
++        if (bufsize < 1) {
++            if (first)
++                break;
++            else
++                goto err;
++        }
++        first = 0;
++
++        i = bufsize;
++        if (buf[i - 1] == '\n')
++            buf[--i] = '\0';
++        if (i == 0)
++            goto err;
++        if (buf[i - 1] == '\r')
++            buf[--i] = '\0';
++        if (i == 0)
++            goto err;
++        again = (buf[i - 1] == '\\');
++
++        for (j = i - 1; j > 0; j--) {
++#ifndef CHARSET_EBCDIC
++            spec_char = (!(((buf[j] >= '0') && (buf[j] <= '9')) ||
++                  ((buf[j] >= 'a') && (buf[j] <= 'f')) ||
++                  ((buf[j] >= 'A') && (buf[j] <= 'F'))));
++#else
++            /*
++             * This #ifdef is not strictly necessary, since the characters
++             * A...F a...f 0...9 are contiguous (yes, even in EBCDIC - but
++             * not the whole alphabet). Nevertheless, isxdigit() is faster.
++             */
++            spec_char = (!isxdigit(buf[j]));
++#endif
++            if (spec_char) {
++                i = j;
++                break;
++            }
++        }
++        buf[i] = '\0';
++        /*
++         * We have now cleared all the crap off the end of the line
++         */
++        if (i < 2)
++            goto err;
++
++        bufp = (unsigned char *)buf;
++
++        k = 0;
++        i -= again;
++        if (i % 2 != 0) {
++            ASN1err(ASN1_F_A2I_ASN1_STRING, ASN1_R_ODD_NUMBER_OF_CHARS);
++            OPENSSL_free(s);
++            return 0;
++        }
++        i /= 2;
++        if (num + i > slen) {
++            sp = OPENSSL_realloc(s, (unsigned int)num + i * 2);
++            if (sp == NULL) {
++                ASN1err(ASN1_F_A2I_ASN1_STRING, ERR_R_MALLOC_FAILURE);
++                OPENSSL_free(s);
++                return 0;
++            }
++            s = sp;
++            slen = num + i * 2;
++        }
++        for (j = 0; j < i; j++, k += 2) {
++            for (n = 0; n < 2; n++) {
++                m = OPENSSL_hexchar2int(bufp[k + n]);
++                if (m < 0) {
++                    ASN1err(ASN1_F_A2I_ASN1_STRING,
++                            ASN1_R_NON_HEX_CHARACTERS);
++                    OPENSSL_free(s);
++                    return 0;
++                }
++                s[num + j] <<= 4;
++                s[num + j] |= m;
++            }
++        }
++        num += i;
++        if (again)
++            bufsize = BIO_gets(bp, buf, size);
++        else
++            break;
++    }
++    bs->length = num;
++    bs->data = s;
++    return 1;
++
++ err:
++    ASN1err(ASN1_F_A2I_ASN1_STRING, ASN1_R_SHORT_LINE);
++    OPENSSL_free(s);
++    return 0;
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/asn1/i2d_pr.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/asn1/i2d_pr.c
+new file mode 100644
+index 0000000..445b0c8
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/asn1/i2d_pr.c
+@@ -0,0 +1,33 @@
++/*
++ * Copyright 1995-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include "internal/cryptlib.h"
++#include 
++#include 
++#include "internal/asn1_int.h"
++#include "internal/evp_int.h"
++
++int i2d_PrivateKey(EVP_PKEY *a, unsigned char **pp)
++{
++    if (a->ameth && a->ameth->old_priv_encode) {
++        return a->ameth->old_priv_encode(a, pp);
++    }
++    if (a->ameth && a->ameth->priv_encode) {
++        PKCS8_PRIV_KEY_INFO *p8 = EVP_PKEY2PKCS8(a);
++        int ret = 0;
++        if (p8 != NULL) {
++            ret = i2d_PKCS8_PRIV_KEY_INFO(p8, pp);
++            PKCS8_PRIV_KEY_INFO_free(p8);
++        }
++        return ret;
++    }
++    ASN1err(ASN1_F_I2D_PRIVATEKEY, ASN1_R_UNSUPPORTED_PUBLIC_KEY_TYPE);
++    return -1;
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/asn1/i2d_pu.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/asn1/i2d_pu.c
+new file mode 100644
+index 0000000..8986c43
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/asn1/i2d_pu.c
+@@ -0,0 +1,38 @@
++/*
++ * Copyright 1995-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include "internal/cryptlib.h"
++#include 
++#include 
++#include 
++#include 
++#include 
++#include 
++
++int i2d_PublicKey(EVP_PKEY *a, unsigned char **pp)
++{
++    switch (EVP_PKEY_id(a)) {
++#ifndef OPENSSL_NO_RSA
++    case EVP_PKEY_RSA:
++        return i2d_RSAPublicKey(EVP_PKEY_get0_RSA(a), pp);
++#endif
++#ifndef OPENSSL_NO_DSA
++    case EVP_PKEY_DSA:
++        return i2d_DSAPublicKey(EVP_PKEY_get0_DSA(a), pp);
++#endif
++#ifndef OPENSSL_NO_EC
++    case EVP_PKEY_EC:
++        return i2o_ECPublicKey(EVP_PKEY_get0_EC_KEY(a), pp);
++#endif
++    default:
++        ASN1err(ASN1_F_I2D_PUBLICKEY, ASN1_R_UNSUPPORTED_PUBLIC_KEY_TYPE);
++        return -1;
++    }
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/asn1/n_pkey.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/asn1/n_pkey.c
+new file mode 100644
+index 0000000..267ce60
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/asn1/n_pkey.c
+@@ -0,0 +1,62 @@
++/*
++ * Copyright 1995-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include "openssl/opensslconf.h"
++#ifdef OPENSSL_NO_RSA
++NON_EMPTY_TRANSLATION_UNIT
++#else
++
++# include "internal/cryptlib.h"
++# include 
++# include 
++# include 
++# include 
++# include 
++# include 
++
++# ifndef OPENSSL_NO_RC4
++
++typedef struct netscape_pkey_st {
++    long version;
++    X509_ALGOR *algor;
++    ASN1_OCTET_STRING *private_key;
++} NETSCAPE_PKEY;
++
++typedef struct netscape_encrypted_pkey_st {
++    ASN1_OCTET_STRING *os;
++    /*
++     * This is the same structure as DigestInfo so use it: although this
++     * isn't really anything to do with digests.
++     */
++    X509_SIG *enckey;
++} NETSCAPE_ENCRYPTED_PKEY;
++
++
++ASN1_BROKEN_SEQUENCE(NETSCAPE_ENCRYPTED_PKEY) = {
++        ASN1_SIMPLE(NETSCAPE_ENCRYPTED_PKEY, os, ASN1_OCTET_STRING),
++        ASN1_SIMPLE(NETSCAPE_ENCRYPTED_PKEY, enckey, X509_SIG)
++} static_ASN1_BROKEN_SEQUENCE_END(NETSCAPE_ENCRYPTED_PKEY)
++
++DECLARE_ASN1_FUNCTIONS_const(NETSCAPE_ENCRYPTED_PKEY)
++DECLARE_ASN1_ENCODE_FUNCTIONS_const(NETSCAPE_ENCRYPTED_PKEY,NETSCAPE_ENCRYPTED_PKEY)
++IMPLEMENT_ASN1_FUNCTIONS_const(NETSCAPE_ENCRYPTED_PKEY)
++
++ASN1_SEQUENCE(NETSCAPE_PKEY) = {
++        ASN1_SIMPLE(NETSCAPE_PKEY, version, LONG),
++        ASN1_SIMPLE(NETSCAPE_PKEY, algor, X509_ALGOR),
++        ASN1_SIMPLE(NETSCAPE_PKEY, private_key, ASN1_OCTET_STRING)
++} static_ASN1_SEQUENCE_END(NETSCAPE_PKEY)
++
++DECLARE_ASN1_FUNCTIONS_const(NETSCAPE_PKEY)
++DECLARE_ASN1_ENCODE_FUNCTIONS_const(NETSCAPE_PKEY,NETSCAPE_PKEY)
++IMPLEMENT_ASN1_FUNCTIONS_const(NETSCAPE_PKEY)
++
++# endif                         /* OPENSSL_NO_RC4 */
++
++#endif
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/asn1/nsseq.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/asn1/nsseq.c
+new file mode 100644
+index 0000000..c7baf40
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/asn1/nsseq.c
+@@ -0,0 +1,34 @@
++/*
++ * Copyright 1999-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include 
++#include 
++#include 
++#include 
++
++static int nsseq_cb(int operation, ASN1_VALUE **pval, const ASN1_ITEM *it,
++                    void *exarg)
++{
++    if (operation == ASN1_OP_NEW_POST) {
++        NETSCAPE_CERT_SEQUENCE *nsseq;
++        nsseq = (NETSCAPE_CERT_SEQUENCE *)*pval;
++        nsseq->type = OBJ_nid2obj(NID_netscape_cert_sequence);
++    }
++    return 1;
++}
++
++/* Netscape certificate sequence structure */
++
++ASN1_SEQUENCE_cb(NETSCAPE_CERT_SEQUENCE, nsseq_cb) = {
++        ASN1_SIMPLE(NETSCAPE_CERT_SEQUENCE, type, ASN1_OBJECT),
++        ASN1_EXP_SEQUENCE_OF_OPT(NETSCAPE_CERT_SEQUENCE, certs, X509, 0)
++} ASN1_SEQUENCE_END_cb(NETSCAPE_CERT_SEQUENCE, NETSCAPE_CERT_SEQUENCE)
++
++IMPLEMENT_ASN1_FUNCTIONS(NETSCAPE_CERT_SEQUENCE)
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/asn1/p5_pbe.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/asn1/p5_pbe.c
+new file mode 100644
+index 0000000..ab7e168
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/asn1/p5_pbe.c
+@@ -0,0 +1,96 @@
++/*
++ * Copyright 1999-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include "internal/cryptlib.h"
++#include 
++#include 
++#include 
++
++/* PKCS#5 password based encryption structure */
++
++ASN1_SEQUENCE(PBEPARAM) = {
++        ASN1_SIMPLE(PBEPARAM, salt, ASN1_OCTET_STRING),
++        ASN1_SIMPLE(PBEPARAM, iter, ASN1_INTEGER)
++} ASN1_SEQUENCE_END(PBEPARAM)
++
++IMPLEMENT_ASN1_FUNCTIONS(PBEPARAM)
++
++/* Set an algorithm identifier for a PKCS#5 PBE algorithm */
++
++int PKCS5_pbe_set0_algor(X509_ALGOR *algor, int alg, int iter,
++                         const unsigned char *salt, int saltlen)
++{
++    PBEPARAM *pbe = NULL;
++    ASN1_STRING *pbe_str = NULL;
++    unsigned char *sstr = NULL;
++
++    pbe = PBEPARAM_new();
++    if (pbe == NULL) {
++        ASN1err(ASN1_F_PKCS5_PBE_SET0_ALGOR, ERR_R_MALLOC_FAILURE);
++        goto err;
++    }
++    if (iter <= 0)
++        iter = PKCS5_DEFAULT_ITER;
++    if (!ASN1_INTEGER_set(pbe->iter, iter)) {
++        ASN1err(ASN1_F_PKCS5_PBE_SET0_ALGOR, ERR_R_MALLOC_FAILURE);
++        goto err;
++    }
++    if (!saltlen)
++        saltlen = PKCS5_SALT_LEN;
++
++    sstr = OPENSSL_malloc(saltlen);
++    if (sstr == NULL) {
++        ASN1err(ASN1_F_PKCS5_PBE_SET0_ALGOR, ERR_R_MALLOC_FAILURE);
++        goto err;
++    }
++    if (salt)
++        memcpy(sstr, salt, saltlen);
++    else if (RAND_bytes(sstr, saltlen) <= 0)
++        goto err;
++
++    ASN1_STRING_set0(pbe->salt, sstr, saltlen);
++    sstr = NULL;
++
++    if (!ASN1_item_pack(pbe, ASN1_ITEM_rptr(PBEPARAM), &pbe_str)) {
++        ASN1err(ASN1_F_PKCS5_PBE_SET0_ALGOR, ERR_R_MALLOC_FAILURE);
++        goto err;
++    }
++
++    PBEPARAM_free(pbe);
++    pbe = NULL;
++
++    if (X509_ALGOR_set0(algor, OBJ_nid2obj(alg), V_ASN1_SEQUENCE, pbe_str))
++        return 1;
++
++ err:
++    OPENSSL_free(sstr);
++    PBEPARAM_free(pbe);
++    ASN1_STRING_free(pbe_str);
++    return 0;
++}
++
++/* Return an algorithm identifier for a PKCS#5 PBE algorithm */
++
++X509_ALGOR *PKCS5_pbe_set(int alg, int iter,
++                          const unsigned char *salt, int saltlen)
++{
++    X509_ALGOR *ret;
++    ret = X509_ALGOR_new();
++    if (ret == NULL) {
++        ASN1err(ASN1_F_PKCS5_PBE_SET, ERR_R_MALLOC_FAILURE);
++        return NULL;
++    }
++
++    if (PKCS5_pbe_set0_algor(ret, alg, iter, salt, saltlen))
++        return ret;
++
++    X509_ALGOR_free(ret);
++    return NULL;
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/asn1/p5_pbev2.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/asn1/p5_pbev2.c
+new file mode 100644
+index 0000000..14e8700
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/asn1/p5_pbev2.c
+@@ -0,0 +1,221 @@
++/*
++ * Copyright 1999-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include "internal/cryptlib.h"
++#include 
++#include 
++#include 
++
++/* PKCS#5 v2.0 password based encryption structures */
++
++ASN1_SEQUENCE(PBE2PARAM) = {
++        ASN1_SIMPLE(PBE2PARAM, keyfunc, X509_ALGOR),
++        ASN1_SIMPLE(PBE2PARAM, encryption, X509_ALGOR)
++} ASN1_SEQUENCE_END(PBE2PARAM)
++
++IMPLEMENT_ASN1_FUNCTIONS(PBE2PARAM)
++
++ASN1_SEQUENCE(PBKDF2PARAM) = {
++        ASN1_SIMPLE(PBKDF2PARAM, salt, ASN1_ANY),
++        ASN1_SIMPLE(PBKDF2PARAM, iter, ASN1_INTEGER),
++        ASN1_OPT(PBKDF2PARAM, keylength, ASN1_INTEGER),
++        ASN1_OPT(PBKDF2PARAM, prf, X509_ALGOR)
++} ASN1_SEQUENCE_END(PBKDF2PARAM)
++
++IMPLEMENT_ASN1_FUNCTIONS(PBKDF2PARAM)
++
++/*
++ * Return an algorithm identifier for a PKCS#5 v2.0 PBE algorithm: yes I know
++ * this is horrible! Extended version to allow application supplied PRF NID
++ * and IV.
++ */
++
++X509_ALGOR *PKCS5_pbe2_set_iv(const EVP_CIPHER *cipher, int iter,
++                              unsigned char *salt, int saltlen,
++                              unsigned char *aiv, int prf_nid)
++{
++    X509_ALGOR *scheme = NULL, *ret = NULL;
++    int alg_nid, keylen;
++    EVP_CIPHER_CTX *ctx = NULL;
++    unsigned char iv[EVP_MAX_IV_LENGTH];
++    PBE2PARAM *pbe2 = NULL;
++
++    alg_nid = EVP_CIPHER_type(cipher);
++    if (alg_nid == NID_undef) {
++        ASN1err(ASN1_F_PKCS5_PBE2_SET_IV,
++                ASN1_R_CIPHER_HAS_NO_OBJECT_IDENTIFIER);
++        goto err;
++    }
++
++    if ((pbe2 = PBE2PARAM_new()) == NULL)
++        goto merr;
++
++    /* Setup the AlgorithmIdentifier for the encryption scheme */
++    scheme = pbe2->encryption;
++    scheme->algorithm = OBJ_nid2obj(alg_nid);
++    if ((scheme->parameter = ASN1_TYPE_new()) == NULL)
++        goto merr;
++
++    /* Create random IV */
++    if (EVP_CIPHER_iv_length(cipher)) {
++        if (aiv)
++            memcpy(iv, aiv, EVP_CIPHER_iv_length(cipher));
++        else if (RAND_bytes(iv, EVP_CIPHER_iv_length(cipher)) <= 0)
++            goto err;
++    }
++
++    ctx = EVP_CIPHER_CTX_new();
++    if (ctx == NULL)
++        goto merr;
++
++    /* Dummy cipherinit to just setup the IV, and PRF */
++    if (!EVP_CipherInit_ex(ctx, cipher, NULL, NULL, iv, 0))
++        goto err;
++    if (EVP_CIPHER_param_to_asn1(ctx, scheme->parameter) < 0) {
++        ASN1err(ASN1_F_PKCS5_PBE2_SET_IV, ASN1_R_ERROR_SETTING_CIPHER_PARAMS);
++        goto err;
++    }
++    /*
++     * If prf NID unspecified see if cipher has a preference. An error is OK
++     * here: just means use default PRF.
++     */
++    if ((prf_nid == -1) &&
++        EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_PBE_PRF_NID, 0, &prf_nid) <= 0) {
++        ERR_clear_error();
++        prf_nid = NID_hmacWithSHA256;
++    }
++    EVP_CIPHER_CTX_free(ctx);
++    ctx = NULL;
++
++    /* If its RC2 then we'd better setup the key length */
++
++    if (alg_nid == NID_rc2_cbc)
++        keylen = EVP_CIPHER_key_length(cipher);
++    else
++        keylen = -1;
++
++    /* Setup keyfunc */
++
++    X509_ALGOR_free(pbe2->keyfunc);
++
++    pbe2->keyfunc = PKCS5_pbkdf2_set(iter, salt, saltlen, prf_nid, keylen);
++
++    if (!pbe2->keyfunc)
++        goto merr;
++
++    /* Now set up top level AlgorithmIdentifier */
++
++    if ((ret = X509_ALGOR_new()) == NULL)
++        goto merr;
++
++    ret->algorithm = OBJ_nid2obj(NID_pbes2);
++
++    /* Encode PBE2PARAM into parameter */
++
++    if (!ASN1_TYPE_pack_sequence(ASN1_ITEM_rptr(PBE2PARAM), pbe2,
++                                 &ret->parameter))
++         goto merr;
++
++    PBE2PARAM_free(pbe2);
++    pbe2 = NULL;
++
++    return ret;
++
++ merr:
++    ASN1err(ASN1_F_PKCS5_PBE2_SET_IV, ERR_R_MALLOC_FAILURE);
++
++ err:
++    EVP_CIPHER_CTX_free(ctx);
++    PBE2PARAM_free(pbe2);
++    /* Note 'scheme' is freed as part of pbe2 */
++    X509_ALGOR_free(ret);
++
++    return NULL;
++}
++
++X509_ALGOR *PKCS5_pbe2_set(const EVP_CIPHER *cipher, int iter,
++                           unsigned char *salt, int saltlen)
++{
++    return PKCS5_pbe2_set_iv(cipher, iter, salt, saltlen, NULL, -1);
++}
++
++X509_ALGOR *PKCS5_pbkdf2_set(int iter, unsigned char *salt, int saltlen,
++                             int prf_nid, int keylen)
++{
++    X509_ALGOR *keyfunc = NULL;
++    PBKDF2PARAM *kdf = NULL;
++    ASN1_OCTET_STRING *osalt = NULL;
++
++    if ((kdf = PBKDF2PARAM_new()) == NULL)
++        goto merr;
++    if ((osalt = ASN1_OCTET_STRING_new()) == NULL)
++        goto merr;
++
++    kdf->salt->value.octet_string = osalt;
++    kdf->salt->type = V_ASN1_OCTET_STRING;
++
++    if (saltlen == 0)
++        saltlen = PKCS5_SALT_LEN;
++    if ((osalt->data = OPENSSL_malloc(saltlen)) == NULL)
++        goto merr;
++
++    osalt->length = saltlen;
++
++    if (salt)
++        memcpy(osalt->data, salt, saltlen);
++    else if (RAND_bytes(osalt->data, saltlen) <= 0)
++        goto merr;
++
++    if (iter <= 0)
++        iter = PKCS5_DEFAULT_ITER;
++
++    if (!ASN1_INTEGER_set(kdf->iter, iter))
++        goto merr;
++
++    /* If have a key len set it up */
++
++    if (keylen > 0) {
++        if ((kdf->keylength = ASN1_INTEGER_new()) == NULL)
++            goto merr;
++        if (!ASN1_INTEGER_set(kdf->keylength, keylen))
++            goto merr;
++    }
++
++    /* prf can stay NULL if we are using hmacWithSHA1 */
++    if (prf_nid > 0 && prf_nid != NID_hmacWithSHA1) {
++        kdf->prf = X509_ALGOR_new();
++        if (kdf->prf == NULL)
++            goto merr;
++        X509_ALGOR_set0(kdf->prf, OBJ_nid2obj(prf_nid), V_ASN1_NULL, NULL);
++    }
++
++    /* Finally setup the keyfunc structure */
++
++    keyfunc = X509_ALGOR_new();
++    if (keyfunc == NULL)
++        goto merr;
++
++    keyfunc->algorithm = OBJ_nid2obj(NID_id_pbkdf2);
++
++    /* Encode PBKDF2PARAM into parameter of pbe2 */
++
++    if (!ASN1_TYPE_pack_sequence(ASN1_ITEM_rptr(PBKDF2PARAM), kdf,
++                                 &keyfunc->parameter))
++         goto merr;
++
++    PBKDF2PARAM_free(kdf);
++    return keyfunc;
++
++ merr:
++    ASN1err(ASN1_F_PKCS5_PBKDF2_SET, ERR_R_MALLOC_FAILURE);
++    PBKDF2PARAM_free(kdf);
++    X509_ALGOR_free(keyfunc);
++    return NULL;
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/asn1/p5_scrypt.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/asn1/p5_scrypt.c
+new file mode 100644
+index 0000000..4cb7837
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/asn1/p5_scrypt.c
+@@ -0,0 +1,283 @@
++/*
++ * Copyright 2015-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include "internal/cryptlib.h"
++#include 
++#include 
++#include 
++#include 
++#include 
++
++#ifndef OPENSSL_NO_SCRYPT
++/* PKCS#5 scrypt password based encryption structures */
++
++typedef struct {
++    ASN1_OCTET_STRING *salt;
++    ASN1_INTEGER *costParameter;
++    ASN1_INTEGER *blockSize;
++    ASN1_INTEGER *parallelizationParameter;
++    ASN1_INTEGER *keyLength;
++} SCRYPT_PARAMS;
++
++ASN1_SEQUENCE(SCRYPT_PARAMS) = {
++        ASN1_SIMPLE(SCRYPT_PARAMS, salt, ASN1_OCTET_STRING),
++        ASN1_SIMPLE(SCRYPT_PARAMS, costParameter, ASN1_INTEGER),
++        ASN1_SIMPLE(SCRYPT_PARAMS, blockSize, ASN1_INTEGER),
++        ASN1_SIMPLE(SCRYPT_PARAMS, parallelizationParameter, ASN1_INTEGER),
++        ASN1_OPT(SCRYPT_PARAMS, keyLength, ASN1_INTEGER),
++} static_ASN1_SEQUENCE_END(SCRYPT_PARAMS)
++
++DECLARE_ASN1_ALLOC_FUNCTIONS(SCRYPT_PARAMS)
++IMPLEMENT_ASN1_ALLOC_FUNCTIONS(SCRYPT_PARAMS)
++
++static X509_ALGOR *pkcs5_scrypt_set(const unsigned char *salt, size_t saltlen,
++                                    size_t keylen, uint64_t N, uint64_t r,
++                                    uint64_t p);
++
++/*
++ * Return an algorithm identifier for a PKCS#5 v2.0 PBE algorithm using scrypt
++ */
++
++X509_ALGOR *PKCS5_pbe2_set_scrypt(const EVP_CIPHER *cipher,
++                                  const unsigned char *salt, int saltlen,
++                                  unsigned char *aiv, uint64_t N, uint64_t r,
++                                  uint64_t p)
++{
++    X509_ALGOR *scheme = NULL, *ret = NULL;
++    int alg_nid;
++    size_t keylen = 0;
++    EVP_CIPHER_CTX *ctx = NULL;
++    unsigned char iv[EVP_MAX_IV_LENGTH];
++    PBE2PARAM *pbe2 = NULL;
++
++    if (!cipher) {
++        ASN1err(ASN1_F_PKCS5_PBE2_SET_SCRYPT, ERR_R_PASSED_NULL_PARAMETER);
++        goto err;
++    }
++
++    if (EVP_PBE_scrypt(NULL, 0, NULL, 0, N, r, p, 0, NULL, 0) == 0) {
++        ASN1err(ASN1_F_PKCS5_PBE2_SET_SCRYPT,
++                ASN1_R_INVALID_SCRYPT_PARAMETERS);
++        goto err;
++    }
++
++    alg_nid = EVP_CIPHER_type(cipher);
++    if (alg_nid == NID_undef) {
++        ASN1err(ASN1_F_PKCS5_PBE2_SET_SCRYPT,
++                ASN1_R_CIPHER_HAS_NO_OBJECT_IDENTIFIER);
++        goto err;
++    }
++
++    pbe2 = PBE2PARAM_new();
++    if (pbe2 == NULL)
++        goto merr;
++
++    /* Setup the AlgorithmIdentifier for the encryption scheme */
++    scheme = pbe2->encryption;
++
++    scheme->algorithm = OBJ_nid2obj(alg_nid);
++    scheme->parameter = ASN1_TYPE_new();
++    if (scheme->parameter == NULL)
++        goto merr;
++
++    /* Create random IV */
++    if (EVP_CIPHER_iv_length(cipher)) {
++        if (aiv)
++            memcpy(iv, aiv, EVP_CIPHER_iv_length(cipher));
++        else if (RAND_bytes(iv, EVP_CIPHER_iv_length(cipher)) < 0)
++            goto err;
++    }
++
++    ctx = EVP_CIPHER_CTX_new();
++    if (ctx == NULL)
++        goto merr;
++
++    /* Dummy cipherinit to just setup the IV */
++    if (EVP_CipherInit_ex(ctx, cipher, NULL, NULL, iv, 0) == 0)
++        goto err;
++    if (EVP_CIPHER_param_to_asn1(ctx, scheme->parameter) < 0) {
++        ASN1err(ASN1_F_PKCS5_PBE2_SET_SCRYPT,
++                ASN1_R_ERROR_SETTING_CIPHER_PARAMS);
++        goto err;
++    }
++    EVP_CIPHER_CTX_free(ctx);
++    ctx = NULL;
++
++    /* If its RC2 then we'd better setup the key length */
++
++    if (alg_nid == NID_rc2_cbc)
++        keylen = EVP_CIPHER_key_length(cipher);
++
++    /* Setup keyfunc */
++
++    X509_ALGOR_free(pbe2->keyfunc);
++
++    pbe2->keyfunc = pkcs5_scrypt_set(salt, saltlen, keylen, N, r, p);
++
++    if (pbe2->keyfunc == NULL)
++        goto merr;
++
++    /* Now set up top level AlgorithmIdentifier */
++
++    ret = X509_ALGOR_new();
++    if (ret == NULL)
++        goto merr;
++
++    ret->algorithm = OBJ_nid2obj(NID_pbes2);
++
++    /* Encode PBE2PARAM into parameter */
++
++    if (ASN1_TYPE_pack_sequence(ASN1_ITEM_rptr(PBE2PARAM), pbe2,
++                                &ret->parameter) == NULL)
++        goto merr;
++
++    PBE2PARAM_free(pbe2);
++    pbe2 = NULL;
++
++    return ret;
++
++ merr:
++    ASN1err(ASN1_F_PKCS5_PBE2_SET_SCRYPT, ERR_R_MALLOC_FAILURE);
++
++ err:
++    PBE2PARAM_free(pbe2);
++    X509_ALGOR_free(ret);
++    EVP_CIPHER_CTX_free(ctx);
++
++    return NULL;
++}
++
++static X509_ALGOR *pkcs5_scrypt_set(const unsigned char *salt, size_t saltlen,
++                                    size_t keylen, uint64_t N, uint64_t r,
++                                    uint64_t p)
++{
++    X509_ALGOR *keyfunc = NULL;
++    SCRYPT_PARAMS *sparam = SCRYPT_PARAMS_new();
++
++    if (sparam == NULL)
++        goto merr;
++
++    if (!saltlen)
++        saltlen = PKCS5_SALT_LEN;
++
++    /* This will either copy salt or grow the buffer */
++    if (ASN1_STRING_set(sparam->salt, salt, saltlen) == 0)
++        goto merr;
++
++    if (salt == NULL && RAND_bytes(sparam->salt->data, saltlen) <= 0)
++        goto err;
++
++    if (ASN1_INTEGER_set_uint64(sparam->costParameter, N) == 0)
++        goto merr;
++
++    if (ASN1_INTEGER_set_uint64(sparam->blockSize, r) == 0)
++        goto merr;
++
++    if (ASN1_INTEGER_set_uint64(sparam->parallelizationParameter, p) == 0)
++        goto merr;
++
++    /* If have a key len set it up */
++
++    if (keylen > 0) {
++        sparam->keyLength = ASN1_INTEGER_new();
++        if (sparam->keyLength == NULL)
++            goto merr;
++        if (ASN1_INTEGER_set_int64(sparam->keyLength, keylen) == 0)
++            goto merr;
++    }
++
++    /* Finally setup the keyfunc structure */
++
++    keyfunc = X509_ALGOR_new();
++    if (keyfunc == NULL)
++        goto merr;
++
++    keyfunc->algorithm = OBJ_nid2obj(NID_id_scrypt);
++
++    /* Encode SCRYPT_PARAMS into parameter of pbe2 */
++
++    if (ASN1_TYPE_pack_sequence(ASN1_ITEM_rptr(SCRYPT_PARAMS), sparam,
++                                &keyfunc->parameter) == NULL)
++        goto merr;
++
++    SCRYPT_PARAMS_free(sparam);
++    return keyfunc;
++
++ merr:
++    ASN1err(ASN1_F_PKCS5_SCRYPT_SET, ERR_R_MALLOC_FAILURE);
++ err:
++    SCRYPT_PARAMS_free(sparam);
++    X509_ALGOR_free(keyfunc);
++    return NULL;
++}
++
++int PKCS5_v2_scrypt_keyivgen(EVP_CIPHER_CTX *ctx, const char *pass,
++                             int passlen, ASN1_TYPE *param,
++                             const EVP_CIPHER *c, const EVP_MD *md, int en_de)
++{
++    unsigned char *salt, key[EVP_MAX_KEY_LENGTH];
++    uint64_t p, r, N;
++    size_t saltlen;
++    size_t keylen = 0;
++    int rv = 0;
++    SCRYPT_PARAMS *sparam = NULL;
++
++    if (EVP_CIPHER_CTX_cipher(ctx) == NULL) {
++        EVPerr(EVP_F_PKCS5_V2_SCRYPT_KEYIVGEN, EVP_R_NO_CIPHER_SET);
++        goto err;
++    }
++
++    /* Decode parameter */
++
++    sparam = ASN1_TYPE_unpack_sequence(ASN1_ITEM_rptr(SCRYPT_PARAMS), param);
++
++    if (sparam == NULL) {
++        EVPerr(EVP_F_PKCS5_V2_SCRYPT_KEYIVGEN, EVP_R_DECODE_ERROR);
++        goto err;
++    }
++
++    keylen = EVP_CIPHER_CTX_key_length(ctx);
++
++    /* Now check the parameters of sparam */
++
++    if (sparam->keyLength) {
++        uint64_t spkeylen;
++        if ((ASN1_INTEGER_get_uint64(&spkeylen, sparam->keyLength) == 0)
++            || (spkeylen != keylen)) {
++            EVPerr(EVP_F_PKCS5_V2_SCRYPT_KEYIVGEN,
++                   EVP_R_UNSUPPORTED_KEYLENGTH);
++            goto err;
++        }
++    }
++    /* Check all parameters fit in uint64_t and are acceptable to scrypt */
++    if (ASN1_INTEGER_get_uint64(&N, sparam->costParameter) == 0
++        || ASN1_INTEGER_get_uint64(&r, sparam->blockSize) == 0
++        || ASN1_INTEGER_get_uint64(&p, sparam->parallelizationParameter) == 0
++        || EVP_PBE_scrypt(NULL, 0, NULL, 0, N, r, p, 0, NULL, 0) == 0) {
++        EVPerr(EVP_F_PKCS5_V2_SCRYPT_KEYIVGEN,
++               EVP_R_ILLEGAL_SCRYPT_PARAMETERS);
++        goto err;
++    }
++
++    /* it seems that its all OK */
++
++    salt = sparam->salt->data;
++    saltlen = sparam->salt->length;
++    if (EVP_PBE_scrypt(pass, passlen, salt, saltlen, N, r, p, 0, key, keylen)
++        == 0)
++        goto err;
++    rv = EVP_CipherInit_ex(ctx, NULL, NULL, key, NULL, en_de);
++ err:
++    if (keylen)
++        OPENSSL_cleanse(key, keylen);
++    SCRYPT_PARAMS_free(sparam);
++    return rv;
++}
++#endif /* OPENSSL_NO_SCRYPT */
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/asn1/p8_pkey.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/asn1/p8_pkey.c
+new file mode 100644
+index 0000000..dbee827
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/asn1/p8_pkey.c
+@@ -0,0 +1,80 @@
++/*
++ * Copyright 1999-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include "internal/cryptlib.h"
++#include 
++#include 
++#include "internal/x509_int.h"
++
++/* Minor tweak to operation: zero private key data */
++static int pkey_cb(int operation, ASN1_VALUE **pval, const ASN1_ITEM *it,
++                   void *exarg)
++{
++    /* Since the structure must still be valid use ASN1_OP_FREE_PRE */
++    if (operation == ASN1_OP_FREE_PRE) {
++        PKCS8_PRIV_KEY_INFO *key = (PKCS8_PRIV_KEY_INFO *)*pval;
++        if (key->pkey)
++            OPENSSL_cleanse(key->pkey->data, key->pkey->length);
++    }
++    return 1;
++}
++
++ASN1_SEQUENCE_cb(PKCS8_PRIV_KEY_INFO, pkey_cb) = {
++        ASN1_SIMPLE(PKCS8_PRIV_KEY_INFO, version, ASN1_INTEGER),
++        ASN1_SIMPLE(PKCS8_PRIV_KEY_INFO, pkeyalg, X509_ALGOR),
++        ASN1_SIMPLE(PKCS8_PRIV_KEY_INFO, pkey, ASN1_OCTET_STRING),
++        ASN1_IMP_SET_OF_OPT(PKCS8_PRIV_KEY_INFO, attributes, X509_ATTRIBUTE, 0)
++} ASN1_SEQUENCE_END_cb(PKCS8_PRIV_KEY_INFO, PKCS8_PRIV_KEY_INFO)
++
++IMPLEMENT_ASN1_FUNCTIONS(PKCS8_PRIV_KEY_INFO)
++
++int PKCS8_pkey_set0(PKCS8_PRIV_KEY_INFO *priv, ASN1_OBJECT *aobj,
++                    int version,
++                    int ptype, void *pval, unsigned char *penc, int penclen)
++{
++    if (version >= 0) {
++        if (!ASN1_INTEGER_set(priv->version, version))
++            return 0;
++    }
++    if (!X509_ALGOR_set0(priv->pkeyalg, aobj, ptype, pval))
++        return 0;
++    if (penc)
++        ASN1_STRING_set0(priv->pkey, penc, penclen);
++    return 1;
++}
++
++int PKCS8_pkey_get0(const ASN1_OBJECT **ppkalg,
++                    const unsigned char **pk, int *ppklen,
++                    const X509_ALGOR **pa, const PKCS8_PRIV_KEY_INFO *p8)
++{
++    if (ppkalg)
++        *ppkalg = p8->pkeyalg->algorithm;
++    if (pk) {
++        *pk = ASN1_STRING_get0_data(p8->pkey);
++        *ppklen = ASN1_STRING_length(p8->pkey);
++    }
++    if (pa)
++        *pa = p8->pkeyalg;
++    return 1;
++}
++
++const STACK_OF(X509_ATTRIBUTE) *
++PKCS8_pkey_get0_attrs(const PKCS8_PRIV_KEY_INFO *p8)
++{
++    return p8->attributes;
++}
++
++int PKCS8_pkey_add1_attr_by_NID(PKCS8_PRIV_KEY_INFO *p8, int nid, int type,
++                                const unsigned char *bytes, int len)
++{
++    if (X509at_add1_attr_by_NID(&p8->attributes, nid, type, bytes, len) != NULL)
++        return 1;
++    return 0;
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/asn1/t_bitst.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/asn1/t_bitst.c
+new file mode 100644
+index 0000000..c0aeca4
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/asn1/t_bitst.c
+@@ -0,0 +1,56 @@
++/*
++ * Copyright 1999-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include "internal/cryptlib.h"
++#include 
++#include 
++
++int ASN1_BIT_STRING_name_print(BIO *out, ASN1_BIT_STRING *bs,
++                               BIT_STRING_BITNAME *tbl, int indent)
++{
++    BIT_STRING_BITNAME *bnam;
++    char first = 1;
++    BIO_printf(out, "%*s", indent, "");
++    for (bnam = tbl; bnam->lname; bnam++) {
++        if (ASN1_BIT_STRING_get_bit(bs, bnam->bitnum)) {
++            if (!first)
++                BIO_puts(out, ", ");
++            BIO_puts(out, bnam->lname);
++            first = 0;
++        }
++    }
++    BIO_puts(out, "\n");
++    return 1;
++}
++
++int ASN1_BIT_STRING_set_asc(ASN1_BIT_STRING *bs, const char *name, int value,
++                            BIT_STRING_BITNAME *tbl)
++{
++    int bitnum;
++    bitnum = ASN1_BIT_STRING_num_asc(name, tbl);
++    if (bitnum < 0)
++        return 0;
++    if (bs) {
++        if (!ASN1_BIT_STRING_set_bit(bs, bitnum, value))
++            return 0;
++    }
++    return 1;
++}
++
++int ASN1_BIT_STRING_num_asc(const char *name, BIT_STRING_BITNAME *tbl)
++{
++    BIT_STRING_BITNAME *bnam;
++    for (bnam = tbl; bnam->lname; bnam++) {
++        if ((strcmp(bnam->sname, name) == 0)
++            || (strcmp(bnam->lname, name) == 0))
++            return bnam->bitnum;
++    }
++    return -1;
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/asn1/t_pkey.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/asn1/t_pkey.c
+new file mode 100644
+index 0000000..3b2c9df
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/asn1/t_pkey.c
+@@ -0,0 +1,93 @@
++/*
++ * Copyright 1995-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include "internal/cryptlib.h"
++#include 
++#include 
++#include "internal/bn_int.h"
++
++/* Number of octets per line */
++#define ASN1_BUF_PRINT_WIDTH    15
++/* Maximum indent */
++#define ASN1_PRINT_MAX_INDENT 128
++
++int ASN1_buf_print(BIO *bp, const unsigned char *buf, size_t buflen, int indent)
++{
++    size_t i;
++
++    for (i = 0; i < buflen; i++) {
++        if ((i % ASN1_BUF_PRINT_WIDTH) == 0) {
++            if (i > 0 && BIO_puts(bp, "\n") <= 0)
++                return 0;
++            if (!BIO_indent(bp, indent, ASN1_PRINT_MAX_INDENT))
++                return 0;
++        }
++        /*
++         * Use colon separators for each octet for compatibility as
++         * this function is used to print out key components.
++         */
++        if (BIO_printf(bp, "%02x%s", buf[i],
++                       (i == buflen - 1) ? "" : ":") <= 0)
++                return 0;
++    }
++    if (BIO_write(bp, "\n", 1) <= 0)
++        return 0;
++    return 1;
++}
++
++int ASN1_bn_print(BIO *bp, const char *number, const BIGNUM *num,
++                  unsigned char *ign, int indent)
++{
++    int n, rv = 0;
++    const char *neg;
++    unsigned char *buf = NULL, *tmp = NULL;
++    int buflen;
++
++    if (num == NULL)
++        return 1;
++    neg = BN_is_negative(num) ? "-" : "";
++    if (!BIO_indent(bp, indent, ASN1_PRINT_MAX_INDENT))
++        return 0;
++    if (BN_is_zero(num)) {
++        if (BIO_printf(bp, "%s 0\n", number) <= 0)
++            return 0;
++        return 1;
++    }
++
++    if (BN_num_bytes(num) <= BN_BYTES) {
++        if (BIO_printf(bp, "%s %s%lu (%s0x%lx)\n", number, neg,
++                       (unsigned long)bn_get_words(num)[0], neg,
++                       (unsigned long)bn_get_words(num)[0]) <= 0)
++            return 0;
++        return 1;
++    }
++
++    buflen = BN_num_bytes(num) + 1;
++    buf = tmp = OPENSSL_malloc(buflen);
++    if (buf == NULL)
++        goto err;
++    buf[0] = 0;
++    if (BIO_printf(bp, "%s%s\n", number,
++                   (neg[0] == '-') ? " (Negative)" : "") <= 0)
++        goto err;
++    n = BN_bn2bin(num, buf + 1);
++
++    if (buf[1] & 0x80)
++        n++;
++    else
++        tmp++;
++
++    if (ASN1_buf_print(bp, tmp, n, indent + 4) == 0)
++        goto err;
++    rv = 1;
++    err:
++    OPENSSL_clear_free(buf, buflen);
++    return rv;
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/asn1/t_spki.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/asn1/t_spki.c
+new file mode 100644
+index 0000000..51b56d0
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/asn1/t_spki.c
+@@ -0,0 +1,56 @@
++/*
++ * Copyright 1999-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include "internal/cryptlib.h"
++#include 
++#include 
++#include 
++#include 
++#include 
++
++/* Print out an SPKI */
++
++int NETSCAPE_SPKI_print(BIO *out, NETSCAPE_SPKI *spki)
++{
++    EVP_PKEY *pkey;
++    ASN1_IA5STRING *chal;
++    ASN1_OBJECT *spkioid;
++    int i, n;
++    char *s;
++    BIO_printf(out, "Netscape SPKI:\n");
++    X509_PUBKEY_get0_param(&spkioid, NULL, NULL, NULL, spki->spkac->pubkey);
++    i = OBJ_obj2nid(spkioid);
++    BIO_printf(out, "  Public Key Algorithm: %s\n",
++               (i == NID_undef) ? "UNKNOWN" : OBJ_nid2ln(i));
++    pkey = X509_PUBKEY_get(spki->spkac->pubkey);
++    if (!pkey)
++        BIO_printf(out, "  Unable to load public key\n");
++    else {
++        EVP_PKEY_print_public(out, pkey, 4, NULL);
++        EVP_PKEY_free(pkey);
++    }
++    chal = spki->spkac->challenge;
++    if (chal->length)
++        BIO_printf(out, "  Challenge String: %s\n", chal->data);
++    i = OBJ_obj2nid(spki->sig_algor.algorithm);
++    BIO_printf(out, "  Signature Algorithm: %s",
++               (i == NID_undef) ? "UNKNOWN" : OBJ_nid2ln(i));
++
++    n = spki->signature->length;
++    s = (char *)spki->signature->data;
++    for (i = 0; i < n; i++) {
++        if ((i % 18) == 0)
++            BIO_write(out, "\n      ", 7);
++        BIO_printf(out, "%02x%s", (unsigned char)s[i],
++                   ((i + 1) == n) ? "" : ":");
++    }
++    BIO_write(out, "\n", 1);
++    return 1;
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/asn1/tasn_dec.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/asn1/tasn_dec.c
+new file mode 100644
+index 0000000..c9b6375
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/asn1/tasn_dec.c
+@@ -0,0 +1,1142 @@
++/*
++ * Copyright 2000-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include 
++#include 
++#include 
++#include 
++#include 
++#include 
++#include "internal/numbers.h"
++#include "asn1_locl.h"
++
++static int asn1_item_embed_d2i(ASN1_VALUE **pval, const unsigned char **in,
++                               long len, const ASN1_ITEM *it,
++                               int tag, int aclass, char opt, ASN1_TLC *ctx);
++
++static int asn1_check_eoc(const unsigned char **in, long len);
++static int asn1_find_end(const unsigned char **in, long len, char inf);
++
++static int asn1_collect(BUF_MEM *buf, const unsigned char **in, long len,
++                        char inf, int tag, int aclass, int depth);
++
++static int collect_data(BUF_MEM *buf, const unsigned char **p, long plen);
++
++static int asn1_check_tlen(long *olen, int *otag, unsigned char *oclass,
++                           char *inf, char *cst,
++                           const unsigned char **in, long len,
++                           int exptag, int expclass, char opt, ASN1_TLC *ctx);
++
++static int asn1_template_ex_d2i(ASN1_VALUE **pval,
++                                const unsigned char **in, long len,
++                                const ASN1_TEMPLATE *tt, char opt,
++                                ASN1_TLC *ctx);
++static int asn1_template_noexp_d2i(ASN1_VALUE **val,
++                                   const unsigned char **in, long len,
++                                   const ASN1_TEMPLATE *tt, char opt,
++                                   ASN1_TLC *ctx);
++static int asn1_d2i_ex_primitive(ASN1_VALUE **pval,
++                                 const unsigned char **in, long len,
++                                 const ASN1_ITEM *it,
++                                 int tag, int aclass, char opt,
++                                 ASN1_TLC *ctx);
++static int asn1_ex_c2i(ASN1_VALUE **pval, const unsigned char *cont, int len,
++                       int utype, char *free_cont, const ASN1_ITEM *it);
++
++/* Table to convert tags to bit values, used for MSTRING type */
++static const unsigned long tag2bit[32] = {
++    /* tags  0 -  3 */
++    0, 0, 0, B_ASN1_BIT_STRING,
++    /* tags  4- 7 */
++    B_ASN1_OCTET_STRING, 0, 0, B_ASN1_UNKNOWN,
++    /* tags  8-11 */
++    B_ASN1_UNKNOWN, B_ASN1_UNKNOWN, B_ASN1_UNKNOWN, B_ASN1_UNKNOWN,
++    /* tags 12-15 */
++    B_ASN1_UTF8STRING, B_ASN1_UNKNOWN, B_ASN1_UNKNOWN, B_ASN1_UNKNOWN,
++    /* tags 16-19 */
++    B_ASN1_SEQUENCE, 0, B_ASN1_NUMERICSTRING, B_ASN1_PRINTABLESTRING,
++    /* tags 20-22 */
++    B_ASN1_T61STRING, B_ASN1_VIDEOTEXSTRING, B_ASN1_IA5STRING,
++    /* tags 23-24 */
++    B_ASN1_UTCTIME, B_ASN1_GENERALIZEDTIME,
++    /* tags 25-27 */
++    B_ASN1_GRAPHICSTRING, B_ASN1_ISO64STRING, B_ASN1_GENERALSTRING,
++    /* tags 28-31 */
++    B_ASN1_UNIVERSALSTRING, B_ASN1_UNKNOWN, B_ASN1_BMPSTRING, B_ASN1_UNKNOWN,
++};
++
++unsigned long ASN1_tag2bit(int tag)
++{
++    if ((tag < 0) || (tag > 30))
++        return 0;
++    return tag2bit[tag];
++}
++
++/* Macro to initialize and invalidate the cache */
++
++#define asn1_tlc_clear(c)       if (c) (c)->valid = 0
++/* Version to avoid compiler warning about 'c' always non-NULL */
++#define asn1_tlc_clear_nc(c)    (c)->valid = 0
++
++/*
++ * Decode an ASN1 item, this currently behaves just like a standard 'd2i'
++ * function. 'in' points to a buffer to read the data from, in future we
++ * will have more advanced versions that can input data a piece at a time and
++ * this will simply be a special case.
++ */
++
++ASN1_VALUE *ASN1_item_d2i(ASN1_VALUE **pval,
++                          const unsigned char **in, long len,
++                          const ASN1_ITEM *it)
++{
++    ASN1_TLC c;
++    ASN1_VALUE *ptmpval = NULL;
++    if (!pval)
++        pval = &ptmpval;
++    asn1_tlc_clear_nc(&c);
++    if (ASN1_item_ex_d2i(pval, in, len, it, -1, 0, 0, &c) > 0)
++        return *pval;
++    return NULL;
++}
++
++int ASN1_item_ex_d2i(ASN1_VALUE **pval, const unsigned char **in, long len,
++                     const ASN1_ITEM *it,
++                     int tag, int aclass, char opt, ASN1_TLC *ctx)
++{
++    int rv;
++    rv = asn1_item_embed_d2i(pval, in, len, it, tag, aclass, opt, ctx);
++    if (rv <= 0)
++        ASN1_item_ex_free(pval, it);
++    return rv;
++}
++
++/*
++ * Decode an item, taking care of IMPLICIT tagging, if any. If 'opt' set and
++ * tag mismatch return -1 to handle OPTIONAL
++ */
++
++static int asn1_item_embed_d2i(ASN1_VALUE **pval, const unsigned char **in,
++                               long len, const ASN1_ITEM *it,
++                               int tag, int aclass, char opt, ASN1_TLC *ctx)
++{
++    const ASN1_TEMPLATE *tt, *errtt = NULL;
++    const ASN1_EXTERN_FUNCS *ef;
++    const ASN1_AUX *aux = it->funcs;
++    ASN1_aux_cb *asn1_cb;
++    const unsigned char *p = NULL, *q;
++    unsigned char oclass;
++    char seq_eoc, seq_nolen, cst, isopt;
++    long tmplen;
++    int i;
++    int otag;
++    int ret = 0;
++    ASN1_VALUE **pchptr;
++    if (!pval)
++        return 0;
++    if (aux && aux->asn1_cb)
++        asn1_cb = aux->asn1_cb;
++    else
++        asn1_cb = 0;
++
++    switch (it->itype) {
++    case ASN1_ITYPE_PRIMITIVE:
++        if (it->templates) {
++            /*
++             * tagging or OPTIONAL is currently illegal on an item template
++             * because the flags can't get passed down. In practice this
++             * isn't a problem: we include the relevant flags from the item
++             * template in the template itself.
++             */
++            if ((tag != -1) || opt) {
++                ASN1err(ASN1_F_ASN1_ITEM_EMBED_D2I,
++                        ASN1_R_ILLEGAL_OPTIONS_ON_ITEM_TEMPLATE);
++                goto err;
++            }
++            return asn1_template_ex_d2i(pval, in, len,
++                                        it->templates, opt, ctx);
++        }
++        return asn1_d2i_ex_primitive(pval, in, len, it,
++                                     tag, aclass, opt, ctx);
++
++    case ASN1_ITYPE_MSTRING:
++        p = *in;
++        /* Just read in tag and class */
++        ret = asn1_check_tlen(NULL, &otag, &oclass, NULL, NULL,
++                              &p, len, -1, 0, 1, ctx);
++        if (!ret) {
++            ASN1err(ASN1_F_ASN1_ITEM_EMBED_D2I, ERR_R_NESTED_ASN1_ERROR);
++            goto err;
++        }
++
++        /* Must be UNIVERSAL class */
++        if (oclass != V_ASN1_UNIVERSAL) {
++            /* If OPTIONAL, assume this is OK */
++            if (opt)
++                return -1;
++            ASN1err(ASN1_F_ASN1_ITEM_EMBED_D2I, ASN1_R_MSTRING_NOT_UNIVERSAL);
++            goto err;
++        }
++        /* Check tag matches bit map */
++        if (!(ASN1_tag2bit(otag) & it->utype)) {
++            /* If OPTIONAL, assume this is OK */
++            if (opt)
++                return -1;
++            ASN1err(ASN1_F_ASN1_ITEM_EMBED_D2I, ASN1_R_MSTRING_WRONG_TAG);
++            goto err;
++        }
++        return asn1_d2i_ex_primitive(pval, in, len, it, otag, 0, 0, ctx);
++
++    case ASN1_ITYPE_EXTERN:
++        /* Use new style d2i */
++        ef = it->funcs;
++        return ef->asn1_ex_d2i(pval, in, len, it, tag, aclass, opt, ctx);
++
++    case ASN1_ITYPE_CHOICE:
++        if (asn1_cb && !asn1_cb(ASN1_OP_D2I_PRE, pval, it, NULL))
++            goto auxerr;
++        if (*pval) {
++            /* Free up and zero CHOICE value if initialised */
++            i = asn1_get_choice_selector(pval, it);
++            if ((i >= 0) && (i < it->tcount)) {
++                tt = it->templates + i;
++                pchptr = asn1_get_field_ptr(pval, tt);
++                asn1_template_free(pchptr, tt);
++                asn1_set_choice_selector(pval, -1, it);
++            }
++        } else if (!ASN1_item_ex_new(pval, it)) {
++            ASN1err(ASN1_F_ASN1_ITEM_EMBED_D2I, ERR_R_NESTED_ASN1_ERROR);
++            goto err;
++        }
++        /* CHOICE type, try each possibility in turn */
++        p = *in;
++        for (i = 0, tt = it->templates; i < it->tcount; i++, tt++) {
++            pchptr = asn1_get_field_ptr(pval, tt);
++            /*
++             * We mark field as OPTIONAL so its absence can be recognised.
++             */
++            ret = asn1_template_ex_d2i(pchptr, &p, len, tt, 1, ctx);
++            /* If field not present, try the next one */
++            if (ret == -1)
++                continue;
++            /* If positive return, read OK, break loop */
++            if (ret > 0)
++                break;
++            /*
++             * Must be an ASN1 parsing error.
++             * Free up any partial choice value
++             */
++            asn1_template_free(pchptr, tt);
++            errtt = tt;
++            ASN1err(ASN1_F_ASN1_ITEM_EMBED_D2I, ERR_R_NESTED_ASN1_ERROR);
++            goto err;
++        }
++
++        /* Did we fall off the end without reading anything? */
++        if (i == it->tcount) {
++            /* If OPTIONAL, this is OK */
++            if (opt) {
++                /* Free and zero it */
++                ASN1_item_ex_free(pval, it);
++                return -1;
++            }
++            ASN1err(ASN1_F_ASN1_ITEM_EMBED_D2I, ASN1_R_NO_MATCHING_CHOICE_TYPE);
++            goto err;
++        }
++
++        asn1_set_choice_selector(pval, i, it);
++
++        if (asn1_cb && !asn1_cb(ASN1_OP_D2I_POST, pval, it, NULL))
++            goto auxerr;
++        *in = p;
++        return 1;
++
++    case ASN1_ITYPE_NDEF_SEQUENCE:
++    case ASN1_ITYPE_SEQUENCE:
++        p = *in;
++        tmplen = len;
++
++        /* If no IMPLICIT tagging set to SEQUENCE, UNIVERSAL */
++        if (tag == -1) {
++            tag = V_ASN1_SEQUENCE;
++            aclass = V_ASN1_UNIVERSAL;
++        }
++        /* Get SEQUENCE length and update len, p */
++        ret = asn1_check_tlen(&len, NULL, NULL, &seq_eoc, &cst,
++                              &p, len, tag, aclass, opt, ctx);
++        if (!ret) {
++            ASN1err(ASN1_F_ASN1_ITEM_EMBED_D2I, ERR_R_NESTED_ASN1_ERROR);
++            goto err;
++        } else if (ret == -1)
++            return -1;
++        if (aux && (aux->flags & ASN1_AFLG_BROKEN)) {
++            len = tmplen - (p - *in);
++            seq_nolen = 1;
++        }
++        /* If indefinite we don't do a length check */
++        else
++            seq_nolen = seq_eoc;
++        if (!cst) {
++            ASN1err(ASN1_F_ASN1_ITEM_EMBED_D2I, ASN1_R_SEQUENCE_NOT_CONSTRUCTED);
++            goto err;
++        }
++
++        if (!*pval && !ASN1_item_ex_new(pval, it)) {
++            ASN1err(ASN1_F_ASN1_ITEM_EMBED_D2I, ERR_R_NESTED_ASN1_ERROR);
++            goto err;
++        }
++
++        if (asn1_cb && !asn1_cb(ASN1_OP_D2I_PRE, pval, it, NULL))
++            goto auxerr;
++
++        /* Free up and zero any ADB found */
++        for (i = 0, tt = it->templates; i < it->tcount; i++, tt++) {
++            if (tt->flags & ASN1_TFLG_ADB_MASK) {
++                const ASN1_TEMPLATE *seqtt;
++                ASN1_VALUE **pseqval;
++                seqtt = asn1_do_adb(pval, tt, 0);
++                if (seqtt == NULL)
++                    continue;
++                pseqval = asn1_get_field_ptr(pval, seqtt);
++                asn1_template_free(pseqval, seqtt);
++            }
++        }
++
++        /* Get each field entry */
++        for (i = 0, tt = it->templates; i < it->tcount; i++, tt++) {
++            const ASN1_TEMPLATE *seqtt;
++            ASN1_VALUE **pseqval;
++            seqtt = asn1_do_adb(pval, tt, 1);
++            if (seqtt == NULL)
++                goto err;
++            pseqval = asn1_get_field_ptr(pval, seqtt);
++            /* Have we ran out of data? */
++            if (!len)
++                break;
++            q = p;
++            if (asn1_check_eoc(&p, len)) {
++                if (!seq_eoc) {
++                    ASN1err(ASN1_F_ASN1_ITEM_EMBED_D2I, ASN1_R_UNEXPECTED_EOC);
++                    goto err;
++                }
++                len -= p - q;
++                seq_eoc = 0;
++                q = p;
++                break;
++            }
++            /*
++             * This determines the OPTIONAL flag value. The field cannot be
++             * omitted if it is the last of a SEQUENCE and there is still
++             * data to be read. This isn't strictly necessary but it
++             * increases efficiency in some cases.
++             */
++            if (i == (it->tcount - 1))
++                isopt = 0;
++            else
++                isopt = (char)(seqtt->flags & ASN1_TFLG_OPTIONAL);
++            /*
++             * attempt to read in field, allowing each to be OPTIONAL
++             */
++
++            ret = asn1_template_ex_d2i(pseqval, &p, len, seqtt, isopt, ctx);
++            if (!ret) {
++                errtt = seqtt;
++                goto err;
++            } else if (ret == -1) {
++                /*
++                 * OPTIONAL component absent. Free and zero the field.
++                 */
++                asn1_template_free(pseqval, seqtt);
++                continue;
++            }
++            /* Update length */
++            len -= p - q;
++        }
++
++        /* Check for EOC if expecting one */
++        if (seq_eoc && !asn1_check_eoc(&p, len)) {
++            ASN1err(ASN1_F_ASN1_ITEM_EMBED_D2I, ASN1_R_MISSING_EOC);
++            goto err;
++        }
++        /* Check all data read */
++        if (!seq_nolen && len) {
++            ASN1err(ASN1_F_ASN1_ITEM_EMBED_D2I, ASN1_R_SEQUENCE_LENGTH_MISMATCH);
++            goto err;
++        }
++
++        /*
++         * If we get here we've got no more data in the SEQUENCE, however we
++         * may not have read all fields so check all remaining are OPTIONAL
++         * and clear any that are.
++         */
++        for (; i < it->tcount; tt++, i++) {
++            const ASN1_TEMPLATE *seqtt;
++            seqtt = asn1_do_adb(pval, tt, 1);
++            if (seqtt == NULL)
++                goto err;
++            if (seqtt->flags & ASN1_TFLG_OPTIONAL) {
++                ASN1_VALUE **pseqval;
++                pseqval = asn1_get_field_ptr(pval, seqtt);
++                asn1_template_free(pseqval, seqtt);
++            } else {
++                errtt = seqtt;
++                ASN1err(ASN1_F_ASN1_ITEM_EMBED_D2I, ASN1_R_FIELD_MISSING);
++                goto err;
++            }
++        }
++        /* Save encoding */
++        if (!asn1_enc_save(pval, *in, p - *in, it))
++            goto auxerr;
++        if (asn1_cb && !asn1_cb(ASN1_OP_D2I_POST, pval, it, NULL))
++            goto auxerr;
++        *in = p;
++        return 1;
++
++    default:
++        return 0;
++    }
++ auxerr:
++    ASN1err(ASN1_F_ASN1_ITEM_EMBED_D2I, ASN1_R_AUX_ERROR);
++ err:
++    if (errtt)
++        ERR_add_error_data(4, "Field=", errtt->field_name,
++                           ", Type=", it->sname);
++    else
++        ERR_add_error_data(2, "Type=", it->sname);
++    return 0;
++}
++
++/*
++ * Templates are handled with two separate functions. One handles any
++ * EXPLICIT tag and the other handles the rest.
++ */
++
++static int asn1_template_ex_d2i(ASN1_VALUE **val,
++                                const unsigned char **in, long inlen,
++                                const ASN1_TEMPLATE *tt, char opt,
++                                ASN1_TLC *ctx)
++{
++    int flags, aclass;
++    int ret;
++    long len;
++    const unsigned char *p, *q;
++    char exp_eoc;
++    if (!val)
++        return 0;
++    flags = tt->flags;
++    aclass = flags & ASN1_TFLG_TAG_CLASS;
++
++    p = *in;
++
++    /* Check if EXPLICIT tag expected */
++    if (flags & ASN1_TFLG_EXPTAG) {
++        char cst;
++        /*
++         * Need to work out amount of data available to the inner content and
++         * where it starts: so read in EXPLICIT header to get the info.
++         */
++        ret = asn1_check_tlen(&len, NULL, NULL, &exp_eoc, &cst,
++                              &p, inlen, tt->tag, aclass, opt, ctx);
++        q = p;
++        if (!ret) {
++            ASN1err(ASN1_F_ASN1_TEMPLATE_EX_D2I, ERR_R_NESTED_ASN1_ERROR);
++            return 0;
++        } else if (ret == -1)
++            return -1;
++        if (!cst) {
++            ASN1err(ASN1_F_ASN1_TEMPLATE_EX_D2I,
++                    ASN1_R_EXPLICIT_TAG_NOT_CONSTRUCTED);
++            return 0;
++        }
++        /* We've found the field so it can't be OPTIONAL now */
++        ret = asn1_template_noexp_d2i(val, &p, len, tt, 0, ctx);
++        if (!ret) {
++            ASN1err(ASN1_F_ASN1_TEMPLATE_EX_D2I, ERR_R_NESTED_ASN1_ERROR);
++            return 0;
++        }
++        /* We read the field in OK so update length */
++        len -= p - q;
++        if (exp_eoc) {
++            /* If NDEF we must have an EOC here */
++            if (!asn1_check_eoc(&p, len)) {
++                ASN1err(ASN1_F_ASN1_TEMPLATE_EX_D2I, ASN1_R_MISSING_EOC);
++                goto err;
++            }
++        } else {
++            /*
++             * Otherwise we must hit the EXPLICIT tag end or its an error
++             */
++            if (len) {
++                ASN1err(ASN1_F_ASN1_TEMPLATE_EX_D2I,
++                        ASN1_R_EXPLICIT_LENGTH_MISMATCH);
++                goto err;
++            }
++        }
++    } else
++        return asn1_template_noexp_d2i(val, in, inlen, tt, opt, ctx);
++
++    *in = p;
++    return 1;
++
++ err:
++    return 0;
++}
++
++static int asn1_template_noexp_d2i(ASN1_VALUE **val,
++                                   const unsigned char **in, long len,
++                                   const ASN1_TEMPLATE *tt, char opt,
++                                   ASN1_TLC *ctx)
++{
++    int flags, aclass;
++    int ret;
++    ASN1_VALUE *tval;
++    const unsigned char *p, *q;
++    if (!val)
++        return 0;
++    flags = tt->flags;
++    aclass = flags & ASN1_TFLG_TAG_CLASS;
++
++    p = *in;
++    q = p;
++
++    /*
++     * If field is embedded then val needs fixing so it is a pointer to
++     * a pointer to a field.
++     */
++    if (tt->flags & ASN1_TFLG_EMBED) {
++        tval = (ASN1_VALUE *)val;
++        val = &tval;
++    }
++
++    if (flags & ASN1_TFLG_SK_MASK) {
++        /* SET OF, SEQUENCE OF */
++        int sktag, skaclass;
++        char sk_eoc;
++        /* First work out expected inner tag value */
++        if (flags & ASN1_TFLG_IMPTAG) {
++            sktag = tt->tag;
++            skaclass = aclass;
++        } else {
++            skaclass = V_ASN1_UNIVERSAL;
++            if (flags & ASN1_TFLG_SET_OF)
++                sktag = V_ASN1_SET;
++            else
++                sktag = V_ASN1_SEQUENCE;
++        }
++        /* Get the tag */
++        ret = asn1_check_tlen(&len, NULL, NULL, &sk_eoc, NULL,
++                              &p, len, sktag, skaclass, opt, ctx);
++        if (!ret) {
++            ASN1err(ASN1_F_ASN1_TEMPLATE_NOEXP_D2I, ERR_R_NESTED_ASN1_ERROR);
++            return 0;
++        } else if (ret == -1)
++            return -1;
++        if (!*val)
++            *val = (ASN1_VALUE *)OPENSSL_sk_new_null();
++        else {
++            /*
++             * We've got a valid STACK: free up any items present
++             */
++            STACK_OF(ASN1_VALUE) *sktmp = (STACK_OF(ASN1_VALUE) *)*val;
++            ASN1_VALUE *vtmp;
++            while (sk_ASN1_VALUE_num(sktmp) > 0) {
++                vtmp = sk_ASN1_VALUE_pop(sktmp);
++                ASN1_item_ex_free(&vtmp, ASN1_ITEM_ptr(tt->item));
++            }
++        }
++
++        if (!*val) {
++            ASN1err(ASN1_F_ASN1_TEMPLATE_NOEXP_D2I, ERR_R_MALLOC_FAILURE);
++            goto err;
++        }
++
++        /* Read as many items as we can */
++        while (len > 0) {
++            ASN1_VALUE *skfield;
++            q = p;
++            /* See if EOC found */
++            if (asn1_check_eoc(&p, len)) {
++                if (!sk_eoc) {
++                    ASN1err(ASN1_F_ASN1_TEMPLATE_NOEXP_D2I,
++                            ASN1_R_UNEXPECTED_EOC);
++                    goto err;
++                }
++                len -= p - q;
++                sk_eoc = 0;
++                break;
++            }
++            skfield = NULL;
++            if (!asn1_item_embed_d2i(&skfield, &p, len,
++                                     ASN1_ITEM_ptr(tt->item), -1, 0, 0, ctx)) {
++                ASN1err(ASN1_F_ASN1_TEMPLATE_NOEXP_D2I,
++                        ERR_R_NESTED_ASN1_ERROR);
++                /* |skfield| may be partially allocated despite failure. */
++                ASN1_item_free(skfield, ASN1_ITEM_ptr(tt->item));
++                goto err;
++            }
++            len -= p - q;
++            if (!sk_ASN1_VALUE_push((STACK_OF(ASN1_VALUE) *)*val, skfield)) {
++                ASN1err(ASN1_F_ASN1_TEMPLATE_NOEXP_D2I, ERR_R_MALLOC_FAILURE);
++                ASN1_item_free(skfield, ASN1_ITEM_ptr(tt->item));
++                goto err;
++            }
++        }
++        if (sk_eoc) {
++            ASN1err(ASN1_F_ASN1_TEMPLATE_NOEXP_D2I, ASN1_R_MISSING_EOC);
++            goto err;
++        }
++    } else if (flags & ASN1_TFLG_IMPTAG) {
++        /* IMPLICIT tagging */
++        ret = asn1_item_embed_d2i(val, &p, len,
++                                  ASN1_ITEM_ptr(tt->item), tt->tag, aclass, opt,
++                                  ctx);
++        if (!ret) {
++            ASN1err(ASN1_F_ASN1_TEMPLATE_NOEXP_D2I, ERR_R_NESTED_ASN1_ERROR);
++            goto err;
++        } else if (ret == -1)
++            return -1;
++    } else {
++        /* Nothing special */
++        ret = asn1_item_embed_d2i(val, &p, len, ASN1_ITEM_ptr(tt->item),
++                                  -1, 0, opt, ctx);
++        if (!ret) {
++            ASN1err(ASN1_F_ASN1_TEMPLATE_NOEXP_D2I, ERR_R_NESTED_ASN1_ERROR);
++            goto err;
++        } else if (ret == -1)
++            return -1;
++    }
++
++    *in = p;
++    return 1;
++
++ err:
++    return 0;
++}
++
++static int asn1_d2i_ex_primitive(ASN1_VALUE **pval,
++                                 const unsigned char **in, long inlen,
++                                 const ASN1_ITEM *it,
++                                 int tag, int aclass, char opt, ASN1_TLC *ctx)
++{
++    int ret = 0, utype;
++    long plen;
++    char cst, inf, free_cont = 0;
++    const unsigned char *p;
++    BUF_MEM buf = { 0, NULL, 0, 0 };
++    const unsigned char *cont = NULL;
++    long len;
++    if (!pval) {
++        ASN1err(ASN1_F_ASN1_D2I_EX_PRIMITIVE, ASN1_R_ILLEGAL_NULL);
++        return 0;               /* Should never happen */
++    }
++
++    if (it->itype == ASN1_ITYPE_MSTRING) {
++        utype = tag;
++        tag = -1;
++    } else
++        utype = it->utype;
++
++    if (utype == V_ASN1_ANY) {
++        /* If type is ANY need to figure out type from tag */
++        unsigned char oclass;
++        if (tag >= 0) {
++            ASN1err(ASN1_F_ASN1_D2I_EX_PRIMITIVE, ASN1_R_ILLEGAL_TAGGED_ANY);
++            return 0;
++        }
++        if (opt) {
++            ASN1err(ASN1_F_ASN1_D2I_EX_PRIMITIVE,
++                    ASN1_R_ILLEGAL_OPTIONAL_ANY);
++            return 0;
++        }
++        p = *in;
++        ret = asn1_check_tlen(NULL, &utype, &oclass, NULL, NULL,
++                              &p, inlen, -1, 0, 0, ctx);
++        if (!ret) {
++            ASN1err(ASN1_F_ASN1_D2I_EX_PRIMITIVE, ERR_R_NESTED_ASN1_ERROR);
++            return 0;
++        }
++        if (oclass != V_ASN1_UNIVERSAL)
++            utype = V_ASN1_OTHER;
++    }
++    if (tag == -1) {
++        tag = utype;
++        aclass = V_ASN1_UNIVERSAL;
++    }
++    p = *in;
++    /* Check header */
++    ret = asn1_check_tlen(&plen, NULL, NULL, &inf, &cst,
++                          &p, inlen, tag, aclass, opt, ctx);
++    if (!ret) {
++        ASN1err(ASN1_F_ASN1_D2I_EX_PRIMITIVE, ERR_R_NESTED_ASN1_ERROR);
++        return 0;
++    } else if (ret == -1)
++        return -1;
++    ret = 0;
++    /* SEQUENCE, SET and "OTHER" are left in encoded form */
++    if ((utype == V_ASN1_SEQUENCE)
++        || (utype == V_ASN1_SET) || (utype == V_ASN1_OTHER)) {
++        /*
++         * Clear context cache for type OTHER because the auto clear when we
++         * have a exact match won't work
++         */
++        if (utype == V_ASN1_OTHER) {
++            asn1_tlc_clear(ctx);
++        }
++        /* SEQUENCE and SET must be constructed */
++        else if (!cst) {
++            ASN1err(ASN1_F_ASN1_D2I_EX_PRIMITIVE,
++                    ASN1_R_TYPE_NOT_CONSTRUCTED);
++            return 0;
++        }
++
++        cont = *in;
++        /* If indefinite length constructed find the real end */
++        if (inf) {
++            if (!asn1_find_end(&p, plen, inf))
++                goto err;
++            len = p - cont;
++        } else {
++            len = p - cont + plen;
++            p += plen;
++        }
++    } else if (cst) {
++        if (utype == V_ASN1_NULL || utype == V_ASN1_BOOLEAN
++            || utype == V_ASN1_OBJECT || utype == V_ASN1_INTEGER
++            || utype == V_ASN1_ENUMERATED) {
++            ASN1err(ASN1_F_ASN1_D2I_EX_PRIMITIVE, ASN1_R_TYPE_NOT_PRIMITIVE);
++            return 0;
++        }
++
++        /* Free any returned 'buf' content */
++        free_cont = 1;
++        /*
++         * Should really check the internal tags are correct but some things
++         * may get this wrong. The relevant specs say that constructed string
++         * types should be OCTET STRINGs internally irrespective of the type.
++         * So instead just check for UNIVERSAL class and ignore the tag.
++         */
++        if (!asn1_collect(&buf, &p, plen, inf, -1, V_ASN1_UNIVERSAL, 0)) {
++            goto err;
++        }
++        len = buf.length;
++        /* Append a final null to string */
++        if (!BUF_MEM_grow_clean(&buf, len + 1)) {
++            ASN1err(ASN1_F_ASN1_D2I_EX_PRIMITIVE, ERR_R_MALLOC_FAILURE);
++            goto err;
++        }
++        buf.data[len] = 0;
++        cont = (const unsigned char *)buf.data;
++    } else {
++        cont = p;
++        len = plen;
++        p += plen;
++    }
++
++    /* We now have content length and type: translate into a structure */
++    /* asn1_ex_c2i may reuse allocated buffer, and so sets free_cont to 0 */
++    if (!asn1_ex_c2i(pval, cont, len, utype, &free_cont, it))
++        goto err;
++
++    *in = p;
++    ret = 1;
++ err:
++    if (free_cont)
++        OPENSSL_free(buf.data);
++    return ret;
++}
++
++/* Translate ASN1 content octets into a structure */
++
++static int asn1_ex_c2i(ASN1_VALUE **pval, const unsigned char *cont, int len,
++                       int utype, char *free_cont, const ASN1_ITEM *it)
++{
++    ASN1_VALUE **opval = NULL;
++    ASN1_STRING *stmp;
++    ASN1_TYPE *typ = NULL;
++    int ret = 0;
++    const ASN1_PRIMITIVE_FUNCS *pf;
++    ASN1_INTEGER **tint;
++    pf = it->funcs;
++
++    if (pf && pf->prim_c2i)
++        return pf->prim_c2i(pval, cont, len, utype, free_cont, it);
++    /* If ANY type clear type and set pointer to internal value */
++    if (it->utype == V_ASN1_ANY) {
++        if (!*pval) {
++            typ = ASN1_TYPE_new();
++            if (typ == NULL)
++                goto err;
++            *pval = (ASN1_VALUE *)typ;
++        } else
++            typ = (ASN1_TYPE *)*pval;
++
++        if (utype != typ->type)
++            ASN1_TYPE_set(typ, utype, NULL);
++        opval = pval;
++        pval = &typ->value.asn1_value;
++    }
++    switch (utype) {
++    case V_ASN1_OBJECT:
++        if (!c2i_ASN1_OBJECT((ASN1_OBJECT **)pval, &cont, len))
++            goto err;
++        break;
++
++    case V_ASN1_NULL:
++        if (len) {
++            ASN1err(ASN1_F_ASN1_EX_C2I, ASN1_R_NULL_IS_WRONG_LENGTH);
++            goto err;
++        }
++        *pval = (ASN1_VALUE *)1;
++        break;
++
++    case V_ASN1_BOOLEAN:
++        if (len != 1) {
++            ASN1err(ASN1_F_ASN1_EX_C2I, ASN1_R_BOOLEAN_IS_WRONG_LENGTH);
++            goto err;
++        } else {
++            ASN1_BOOLEAN *tbool;
++            tbool = (ASN1_BOOLEAN *)pval;
++            *tbool = *cont;
++        }
++        break;
++
++    case V_ASN1_BIT_STRING:
++        if (!c2i_ASN1_BIT_STRING((ASN1_BIT_STRING **)pval, &cont, len))
++            goto err;
++        break;
++
++    case V_ASN1_INTEGER:
++    case V_ASN1_ENUMERATED:
++        tint = (ASN1_INTEGER **)pval;
++        if (!c2i_ASN1_INTEGER(tint, &cont, len))
++            goto err;
++        /* Fixup type to match the expected form */
++        (*tint)->type = utype | ((*tint)->type & V_ASN1_NEG);
++        break;
++
++    case V_ASN1_OCTET_STRING:
++    case V_ASN1_NUMERICSTRING:
++    case V_ASN1_PRINTABLESTRING:
++    case V_ASN1_T61STRING:
++    case V_ASN1_VIDEOTEXSTRING:
++    case V_ASN1_IA5STRING:
++    case V_ASN1_UTCTIME:
++    case V_ASN1_GENERALIZEDTIME:
++    case V_ASN1_GRAPHICSTRING:
++    case V_ASN1_VISIBLESTRING:
++    case V_ASN1_GENERALSTRING:
++    case V_ASN1_UNIVERSALSTRING:
++    case V_ASN1_BMPSTRING:
++    case V_ASN1_UTF8STRING:
++    case V_ASN1_OTHER:
++    case V_ASN1_SET:
++    case V_ASN1_SEQUENCE:
++    default:
++        if (utype == V_ASN1_BMPSTRING && (len & 1)) {
++            ASN1err(ASN1_F_ASN1_EX_C2I, ASN1_R_BMPSTRING_IS_WRONG_LENGTH);
++            goto err;
++        }
++        if (utype == V_ASN1_UNIVERSALSTRING && (len & 3)) {
++            ASN1err(ASN1_F_ASN1_EX_C2I,
++                    ASN1_R_UNIVERSALSTRING_IS_WRONG_LENGTH);
++            goto err;
++        }
++        /* All based on ASN1_STRING and handled the same */
++        if (!*pval) {
++            stmp = ASN1_STRING_type_new(utype);
++            if (stmp == NULL) {
++                ASN1err(ASN1_F_ASN1_EX_C2I, ERR_R_MALLOC_FAILURE);
++                goto err;
++            }
++            *pval = (ASN1_VALUE *)stmp;
++        } else {
++            stmp = (ASN1_STRING *)*pval;
++            stmp->type = utype;
++        }
++        /* If we've already allocated a buffer use it */
++        if (*free_cont) {
++            OPENSSL_free(stmp->data);
++            stmp->data = (unsigned char *)cont; /* UGLY CAST! RL */
++            stmp->length = len;
++            *free_cont = 0;
++        } else {
++            if (!ASN1_STRING_set(stmp, cont, len)) {
++                ASN1err(ASN1_F_ASN1_EX_C2I, ERR_R_MALLOC_FAILURE);
++                ASN1_STRING_free(stmp);
++                *pval = NULL;
++                goto err;
++            }
++        }
++        break;
++    }
++    /* If ASN1_ANY and NULL type fix up value */
++    if (typ && (utype == V_ASN1_NULL))
++        typ->value.ptr = NULL;
++
++    ret = 1;
++ err:
++    if (!ret) {
++        ASN1_TYPE_free(typ);
++        if (opval)
++            *opval = NULL;
++    }
++    return ret;
++}
++
++/*
++ * This function finds the end of an ASN1 structure when passed its maximum
++ * length, whether it is indefinite length and a pointer to the content. This
++ * is more efficient than calling asn1_collect because it does not recurse on
++ * each indefinite length header.
++ */
++
++static int asn1_find_end(const unsigned char **in, long len, char inf)
++{
++    uint32_t expected_eoc;
++    long plen;
++    const unsigned char *p = *in, *q;
++    /* If not indefinite length constructed just add length */
++    if (inf == 0) {
++        *in += len;
++        return 1;
++    }
++    expected_eoc = 1;
++    /*
++     * Indefinite length constructed form. Find the end when enough EOCs are
++     * found. If more indefinite length constructed headers are encountered
++     * increment the expected eoc count otherwise just skip to the end of the
++     * data.
++     */
++    while (len > 0) {
++        if (asn1_check_eoc(&p, len)) {
++            expected_eoc--;
++            if (expected_eoc == 0)
++                break;
++            len -= 2;
++            continue;
++        }
++        q = p;
++        /* Just read in a header: only care about the length */
++        if (!asn1_check_tlen(&plen, NULL, NULL, &inf, NULL, &p, len,
++                             -1, 0, 0, NULL)) {
++            ASN1err(ASN1_F_ASN1_FIND_END, ERR_R_NESTED_ASN1_ERROR);
++            return 0;
++        }
++        if (inf) {
++            if (expected_eoc == UINT32_MAX) {
++                ASN1err(ASN1_F_ASN1_FIND_END, ERR_R_NESTED_ASN1_ERROR);
++                return 0;
++            }
++            expected_eoc++;
++        } else {
++            p += plen;
++        }
++        len -= p - q;
++    }
++    if (expected_eoc) {
++        ASN1err(ASN1_F_ASN1_FIND_END, ASN1_R_MISSING_EOC);
++        return 0;
++    }
++    *in = p;
++    return 1;
++}
++
++/*
++ * This function collects the asn1 data from a constructed string type into
++ * a buffer. The values of 'in' and 'len' should refer to the contents of the
++ * constructed type and 'inf' should be set if it is indefinite length.
++ */
++
++#ifndef ASN1_MAX_STRING_NEST
++/*
++ * This determines how many levels of recursion are permitted in ASN1 string
++ * types. If it is not limited stack overflows can occur. If set to zero no
++ * recursion is allowed at all. Although zero should be adequate examples
++ * exist that require a value of 1. So 5 should be more than enough.
++ */
++# define ASN1_MAX_STRING_NEST 5
++#endif
++
++static int asn1_collect(BUF_MEM *buf, const unsigned char **in, long len,
++                        char inf, int tag, int aclass, int depth)
++{
++    const unsigned char *p, *q;
++    long plen;
++    char cst, ininf;
++    p = *in;
++    inf &= 1;
++    /*
++     * If no buffer and not indefinite length constructed just pass over the
++     * encoded data
++     */
++    if (!buf && !inf) {
++        *in += len;
++        return 1;
++    }
++    while (len > 0) {
++        q = p;
++        /* Check for EOC */
++        if (asn1_check_eoc(&p, len)) {
++            /*
++             * EOC is illegal outside indefinite length constructed form
++             */
++            if (!inf) {
++                ASN1err(ASN1_F_ASN1_COLLECT, ASN1_R_UNEXPECTED_EOC);
++                return 0;
++            }
++            inf = 0;
++            break;
++        }
++
++        if (!asn1_check_tlen(&plen, NULL, NULL, &ininf, &cst, &p,
++                             len, tag, aclass, 0, NULL)) {
++            ASN1err(ASN1_F_ASN1_COLLECT, ERR_R_NESTED_ASN1_ERROR);
++            return 0;
++        }
++
++        /* If indefinite length constructed update max length */
++        if (cst) {
++            if (depth >= ASN1_MAX_STRING_NEST) {
++                ASN1err(ASN1_F_ASN1_COLLECT, ASN1_R_NESTED_ASN1_STRING);
++                return 0;
++            }
++            if (!asn1_collect(buf, &p, plen, ininf, tag, aclass, depth + 1))
++                return 0;
++        } else if (plen && !collect_data(buf, &p, plen))
++            return 0;
++        len -= p - q;
++    }
++    if (inf) {
++        ASN1err(ASN1_F_ASN1_COLLECT, ASN1_R_MISSING_EOC);
++        return 0;
++    }
++    *in = p;
++    return 1;
++}
++
++static int collect_data(BUF_MEM *buf, const unsigned char **p, long plen)
++{
++    int len;
++    if (buf) {
++        len = buf->length;
++        if (!BUF_MEM_grow_clean(buf, len + plen)) {
++            ASN1err(ASN1_F_COLLECT_DATA, ERR_R_MALLOC_FAILURE);
++            return 0;
++        }
++        memcpy(buf->data + len, *p, plen);
++    }
++    *p += plen;
++    return 1;
++}
++
++/* Check for ASN1 EOC and swallow it if found */
++
++static int asn1_check_eoc(const unsigned char **in, long len)
++{
++    const unsigned char *p;
++    if (len < 2)
++        return 0;
++    p = *in;
++    if (!p[0] && !p[1]) {
++        *in += 2;
++        return 1;
++    }
++    return 0;
++}
++
++/*
++ * Check an ASN1 tag and length: a bit like ASN1_get_object but it sets the
++ * length for indefinite length constructed form, we don't know the exact
++ * length but we can set an upper bound to the amount of data available minus
++ * the header length just read.
++ */
++
++static int asn1_check_tlen(long *olen, int *otag, unsigned char *oclass,
++                           char *inf, char *cst,
++                           const unsigned char **in, long len,
++                           int exptag, int expclass, char opt, ASN1_TLC *ctx)
++{
++    int i;
++    int ptag, pclass;
++    long plen;
++    const unsigned char *p, *q;
++    p = *in;
++    q = p;
++
++    if (ctx && ctx->valid) {
++        i = ctx->ret;
++        plen = ctx->plen;
++        pclass = ctx->pclass;
++        ptag = ctx->ptag;
++        p += ctx->hdrlen;
++    } else {
++        i = ASN1_get_object(&p, &plen, &ptag, &pclass, len);
++        if (ctx) {
++            ctx->ret = i;
++            ctx->plen = plen;
++            ctx->pclass = pclass;
++            ctx->ptag = ptag;
++            ctx->hdrlen = p - q;
++            ctx->valid = 1;
++            /*
++             * If definite length, and no error, length + header can't exceed
++             * total amount of data available.
++             */
++            if (!(i & 0x81) && ((plen + ctx->hdrlen) > len)) {
++                ASN1err(ASN1_F_ASN1_CHECK_TLEN, ASN1_R_TOO_LONG);
++                asn1_tlc_clear(ctx);
++                return 0;
++            }
++        }
++    }
++
++    if (i & 0x80) {
++        ASN1err(ASN1_F_ASN1_CHECK_TLEN, ASN1_R_BAD_OBJECT_HEADER);
++        asn1_tlc_clear(ctx);
++        return 0;
++    }
++    if (exptag >= 0) {
++        if ((exptag != ptag) || (expclass != pclass)) {
++            /*
++             * If type is OPTIONAL, not an error: indicate missing type.
++             */
++            if (opt)
++                return -1;
++            asn1_tlc_clear(ctx);
++            ASN1err(ASN1_F_ASN1_CHECK_TLEN, ASN1_R_WRONG_TAG);
++            return 0;
++        }
++        /*
++         * We have a tag and class match: assume we are going to do something
++         * with it
++         */
++        asn1_tlc_clear(ctx);
++    }
++
++    if (i & 1)
++        plen = len - (p - q);
++
++    if (inf)
++        *inf = i & 1;
++
++    if (cst)
++        *cst = i & V_ASN1_CONSTRUCTED;
++
++    if (olen)
++        *olen = plen;
++
++    if (oclass)
++        *oclass = pclass;
++
++    if (otag)
++        *otag = ptag;
++
++    *in = p;
++    return 1;
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/asn1/tasn_enc.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/asn1/tasn_enc.c
+new file mode 100644
+index 0000000..caa4869
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/asn1/tasn_enc.c
+@@ -0,0 +1,605 @@
++/*
++ * Copyright 2000-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include 
++#include "internal/cryptlib.h"
++#include 
++#include 
++#include 
++#include "internal/asn1_int.h"
++#include "asn1_locl.h"
++
++static int asn1_i2d_ex_primitive(ASN1_VALUE **pval, unsigned char **out,
++                                 const ASN1_ITEM *it, int tag, int aclass);
++static int asn1_set_seq_out(STACK_OF(ASN1_VALUE) *sk, unsigned char **out,
++                            int skcontlen, const ASN1_ITEM *item,
++                            int do_sort, int iclass);
++static int asn1_template_ex_i2d(ASN1_VALUE **pval, unsigned char **out,
++                                const ASN1_TEMPLATE *tt, int tag, int aclass);
++static int asn1_item_flags_i2d(ASN1_VALUE *val, unsigned char **out,
++                               const ASN1_ITEM *it, int flags);
++static int asn1_ex_i2c(ASN1_VALUE **pval, unsigned char *cout, int *putype,
++                       const ASN1_ITEM *it);
++
++/*
++ * Top level i2d equivalents: the 'ndef' variant instructs the encoder to use
++ * indefinite length constructed encoding, where appropriate
++ */
++
++int ASN1_item_ndef_i2d(ASN1_VALUE *val, unsigned char **out,
++                       const ASN1_ITEM *it)
++{
++    return asn1_item_flags_i2d(val, out, it, ASN1_TFLG_NDEF);
++}
++
++int ASN1_item_i2d(ASN1_VALUE *val, unsigned char **out, const ASN1_ITEM *it)
++{
++    return asn1_item_flags_i2d(val, out, it, 0);
++}
++
++/*
++ * Encode an ASN1 item, this is use by the standard 'i2d' function. 'out'
++ * points to a buffer to output the data to. The new i2d has one additional
++ * feature. If the output buffer is NULL (i.e. *out == NULL) then a buffer is
++ * allocated and populated with the encoding.
++ */
++
++static int asn1_item_flags_i2d(ASN1_VALUE *val, unsigned char **out,
++                               const ASN1_ITEM *it, int flags)
++{
++    if (out && !*out) {
++        unsigned char *p, *buf;
++        int len;
++        len = ASN1_item_ex_i2d(&val, NULL, it, -1, flags);
++        if (len <= 0)
++            return len;
++        buf = OPENSSL_malloc(len);
++        if (buf == NULL)
++            return -1;
++        p = buf;
++        ASN1_item_ex_i2d(&val, &p, it, -1, flags);
++        *out = buf;
++        return len;
++    }
++
++    return ASN1_item_ex_i2d(&val, out, it, -1, flags);
++}
++
++/*
++ * Encode an item, taking care of IMPLICIT tagging (if any). This function
++ * performs the normal item handling: it can be used in external types.
++ */
++
++int ASN1_item_ex_i2d(ASN1_VALUE **pval, unsigned char **out,
++                     const ASN1_ITEM *it, int tag, int aclass)
++{
++    const ASN1_TEMPLATE *tt = NULL;
++    int i, seqcontlen, seqlen, ndef = 1;
++    const ASN1_EXTERN_FUNCS *ef;
++    const ASN1_AUX *aux = it->funcs;
++    ASN1_aux_cb *asn1_cb = 0;
++
++    if ((it->itype != ASN1_ITYPE_PRIMITIVE) && !*pval)
++        return 0;
++
++    if (aux && aux->asn1_cb)
++        asn1_cb = aux->asn1_cb;
++
++    switch (it->itype) {
++
++    case ASN1_ITYPE_PRIMITIVE:
++        if (it->templates)
++            return asn1_template_ex_i2d(pval, out, it->templates,
++                                        tag, aclass);
++        return asn1_i2d_ex_primitive(pval, out, it, tag, aclass);
++
++    case ASN1_ITYPE_MSTRING:
++        return asn1_i2d_ex_primitive(pval, out, it, -1, aclass);
++
++    case ASN1_ITYPE_CHOICE:
++        if (asn1_cb && !asn1_cb(ASN1_OP_I2D_PRE, pval, it, NULL))
++            return 0;
++        i = asn1_get_choice_selector(pval, it);
++        if ((i >= 0) && (i < it->tcount)) {
++            ASN1_VALUE **pchval;
++            const ASN1_TEMPLATE *chtt;
++            chtt = it->templates + i;
++            pchval = asn1_get_field_ptr(pval, chtt);
++            return asn1_template_ex_i2d(pchval, out, chtt, -1, aclass);
++        }
++        /* Fixme: error condition if selector out of range */
++        if (asn1_cb && !asn1_cb(ASN1_OP_I2D_POST, pval, it, NULL))
++            return 0;
++        break;
++
++    case ASN1_ITYPE_EXTERN:
++        /* If new style i2d it does all the work */
++        ef = it->funcs;
++        return ef->asn1_ex_i2d(pval, out, it, tag, aclass);
++
++    case ASN1_ITYPE_NDEF_SEQUENCE:
++        /* Use indefinite length constructed if requested */
++        if (aclass & ASN1_TFLG_NDEF)
++            ndef = 2;
++        /* fall through */
++
++    case ASN1_ITYPE_SEQUENCE:
++        i = asn1_enc_restore(&seqcontlen, out, pval, it);
++        /* An error occurred */
++        if (i < 0)
++            return 0;
++        /* We have a valid cached encoding... */
++        if (i > 0)
++            return seqcontlen;
++        /* Otherwise carry on */
++        seqcontlen = 0;
++        /* If no IMPLICIT tagging set to SEQUENCE, UNIVERSAL */
++        if (tag == -1) {
++            tag = V_ASN1_SEQUENCE;
++            /* Retain any other flags in aclass */
++            aclass = (aclass & ~ASN1_TFLG_TAG_CLASS)
++                | V_ASN1_UNIVERSAL;
++        }
++        if (asn1_cb && !asn1_cb(ASN1_OP_I2D_PRE, pval, it, NULL))
++            return 0;
++        /* First work out sequence content length */
++        for (i = 0, tt = it->templates; i < it->tcount; tt++, i++) {
++            const ASN1_TEMPLATE *seqtt;
++            ASN1_VALUE **pseqval;
++            int tmplen;
++            seqtt = asn1_do_adb(pval, tt, 1);
++            if (!seqtt)
++                return 0;
++            pseqval = asn1_get_field_ptr(pval, seqtt);
++            tmplen = asn1_template_ex_i2d(pseqval, NULL, seqtt, -1, aclass);
++            if (tmplen == -1 || (tmplen > INT_MAX - seqcontlen))
++                return -1;
++            seqcontlen += tmplen;
++        }
++
++        seqlen = ASN1_object_size(ndef, seqcontlen, tag);
++        if (!out || seqlen == -1)
++            return seqlen;
++        /* Output SEQUENCE header */
++        ASN1_put_object(out, ndef, seqcontlen, tag, aclass);
++        for (i = 0, tt = it->templates; i < it->tcount; tt++, i++) {
++            const ASN1_TEMPLATE *seqtt;
++            ASN1_VALUE **pseqval;
++            seqtt = asn1_do_adb(pval, tt, 1);
++            if (!seqtt)
++                return 0;
++            pseqval = asn1_get_field_ptr(pval, seqtt);
++            /* FIXME: check for errors in enhanced version */
++            asn1_template_ex_i2d(pseqval, out, seqtt, -1, aclass);
++        }
++        if (ndef == 2)
++            ASN1_put_eoc(out);
++        if (asn1_cb && !asn1_cb(ASN1_OP_I2D_POST, pval, it, NULL))
++            return 0;
++        return seqlen;
++
++    default:
++        return 0;
++
++    }
++    return 0;
++}
++
++static int asn1_template_ex_i2d(ASN1_VALUE **pval, unsigned char **out,
++                                const ASN1_TEMPLATE *tt, int tag, int iclass)
++{
++    int i, ret, flags, ttag, tclass, ndef;
++    ASN1_VALUE *tval;
++    flags = tt->flags;
++
++    /*
++     * If field is embedded then val needs fixing so it is a pointer to
++     * a pointer to a field.
++     */
++    if (flags & ASN1_TFLG_EMBED) {
++        tval = (ASN1_VALUE *)pval;
++        pval = &tval;
++    }
++    /*
++     * Work out tag and class to use: tagging may come either from the
++     * template or the arguments, not both because this would create
++     * ambiguity. Additionally the iclass argument may contain some
++     * additional flags which should be noted and passed down to other
++     * levels.
++     */
++    if (flags & ASN1_TFLG_TAG_MASK) {
++        /* Error if argument and template tagging */
++        if (tag != -1)
++            /* FIXME: error code here */
++            return -1;
++        /* Get tagging from template */
++        ttag = tt->tag;
++        tclass = flags & ASN1_TFLG_TAG_CLASS;
++    } else if (tag != -1) {
++        /* No template tagging, get from arguments */
++        ttag = tag;
++        tclass = iclass & ASN1_TFLG_TAG_CLASS;
++    } else {
++        ttag = -1;
++        tclass = 0;
++    }
++    /*
++     * Remove any class mask from iflag.
++     */
++    iclass &= ~ASN1_TFLG_TAG_CLASS;
++
++    /*
++     * At this point 'ttag' contains the outer tag to use, 'tclass' is the
++     * class and iclass is any flags passed to this function.
++     */
++
++    /* if template and arguments require ndef, use it */
++    if ((flags & ASN1_TFLG_NDEF) && (iclass & ASN1_TFLG_NDEF))
++        ndef = 2;
++    else
++        ndef = 1;
++
++    if (flags & ASN1_TFLG_SK_MASK) {
++        /* SET OF, SEQUENCE OF */
++        STACK_OF(ASN1_VALUE) *sk = (STACK_OF(ASN1_VALUE) *)*pval;
++        int isset, sktag, skaclass;
++        int skcontlen, sklen;
++        ASN1_VALUE *skitem;
++
++        if (!*pval)
++            return 0;
++
++        if (flags & ASN1_TFLG_SET_OF) {
++            isset = 1;
++            /* 2 means we reorder */
++            if (flags & ASN1_TFLG_SEQUENCE_OF)
++                isset = 2;
++        } else
++            isset = 0;
++
++        /*
++         * Work out inner tag value: if EXPLICIT or no tagging use underlying
++         * type.
++         */
++        if ((ttag != -1) && !(flags & ASN1_TFLG_EXPTAG)) {
++            sktag = ttag;
++            skaclass = tclass;
++        } else {
++            skaclass = V_ASN1_UNIVERSAL;
++            if (isset)
++                sktag = V_ASN1_SET;
++            else
++                sktag = V_ASN1_SEQUENCE;
++        }
++
++        /* Determine total length of items */
++        skcontlen = 0;
++        for (i = 0; i < sk_ASN1_VALUE_num(sk); i++) {
++            int tmplen;
++            skitem = sk_ASN1_VALUE_value(sk, i);
++            tmplen = ASN1_item_ex_i2d(&skitem, NULL, ASN1_ITEM_ptr(tt->item),
++                                      -1, iclass);
++            if (tmplen == -1 || (skcontlen > INT_MAX - tmplen))
++                return -1;
++            skcontlen += tmplen;
++        }
++        sklen = ASN1_object_size(ndef, skcontlen, sktag);
++        if (sklen == -1)
++            return -1;
++        /* If EXPLICIT need length of surrounding tag */
++        if (flags & ASN1_TFLG_EXPTAG)
++            ret = ASN1_object_size(ndef, sklen, ttag);
++        else
++            ret = sklen;
++
++        if (!out || ret == -1)
++            return ret;
++
++        /* Now encode this lot... */
++        /* EXPLICIT tag */
++        if (flags & ASN1_TFLG_EXPTAG)
++            ASN1_put_object(out, ndef, sklen, ttag, tclass);
++        /* SET or SEQUENCE and IMPLICIT tag */
++        ASN1_put_object(out, ndef, skcontlen, sktag, skaclass);
++        /* And the stuff itself */
++        asn1_set_seq_out(sk, out, skcontlen, ASN1_ITEM_ptr(tt->item),
++                         isset, iclass);
++        if (ndef == 2) {
++            ASN1_put_eoc(out);
++            if (flags & ASN1_TFLG_EXPTAG)
++                ASN1_put_eoc(out);
++        }
++
++        return ret;
++    }
++
++    if (flags & ASN1_TFLG_EXPTAG) {
++        /* EXPLICIT tagging */
++        /* Find length of tagged item */
++        i = ASN1_item_ex_i2d(pval, NULL, ASN1_ITEM_ptr(tt->item), -1, iclass);
++        if (!i)
++            return 0;
++        /* Find length of EXPLICIT tag */
++        ret = ASN1_object_size(ndef, i, ttag);
++        if (out && ret != -1) {
++            /* Output tag and item */
++            ASN1_put_object(out, ndef, i, ttag, tclass);
++            ASN1_item_ex_i2d(pval, out, ASN1_ITEM_ptr(tt->item), -1, iclass);
++            if (ndef == 2)
++                ASN1_put_eoc(out);
++        }
++        return ret;
++    }
++
++    /* Either normal or IMPLICIT tagging: combine class and flags */
++    return ASN1_item_ex_i2d(pval, out, ASN1_ITEM_ptr(tt->item),
++                            ttag, tclass | iclass);
++
++}
++
++/* Temporary structure used to hold DER encoding of items for SET OF */
++
++typedef struct {
++    unsigned char *data;
++    int length;
++    ASN1_VALUE *field;
++} DER_ENC;
++
++static int der_cmp(const void *a, const void *b)
++{
++    const DER_ENC *d1 = a, *d2 = b;
++    int cmplen, i;
++    cmplen = (d1->length < d2->length) ? d1->length : d2->length;
++    i = memcmp(d1->data, d2->data, cmplen);
++    if (i)
++        return i;
++    return d1->length - d2->length;
++}
++
++/* Output the content octets of SET OF or SEQUENCE OF */
++
++static int asn1_set_seq_out(STACK_OF(ASN1_VALUE) *sk, unsigned char **out,
++                            int skcontlen, const ASN1_ITEM *item,
++                            int do_sort, int iclass)
++{
++    int i;
++    ASN1_VALUE *skitem;
++    unsigned char *tmpdat = NULL, *p = NULL;
++    DER_ENC *derlst = NULL, *tder;
++    if (do_sort) {
++        /* Don't need to sort less than 2 items */
++        if (sk_ASN1_VALUE_num(sk) < 2)
++            do_sort = 0;
++        else {
++            derlst = OPENSSL_malloc(sk_ASN1_VALUE_num(sk)
++                                    * sizeof(*derlst));
++            if (derlst == NULL)
++                return 0;
++            tmpdat = OPENSSL_malloc(skcontlen);
++            if (tmpdat == NULL) {
++                OPENSSL_free(derlst);
++                return 0;
++            }
++        }
++    }
++    /* If not sorting just output each item */
++    if (!do_sort) {
++        for (i = 0; i < sk_ASN1_VALUE_num(sk); i++) {
++            skitem = sk_ASN1_VALUE_value(sk, i);
++            ASN1_item_ex_i2d(&skitem, out, item, -1, iclass);
++        }
++        return 1;
++    }
++    p = tmpdat;
++
++    /* Doing sort: build up a list of each member's DER encoding */
++    for (i = 0, tder = derlst; i < sk_ASN1_VALUE_num(sk); i++, tder++) {
++        skitem = sk_ASN1_VALUE_value(sk, i);
++        tder->data = p;
++        tder->length = ASN1_item_ex_i2d(&skitem, &p, item, -1, iclass);
++        tder->field = skitem;
++    }
++
++    /* Now sort them */
++    qsort(derlst, sk_ASN1_VALUE_num(sk), sizeof(*derlst), der_cmp);
++    /* Output sorted DER encoding */
++    p = *out;
++    for (i = 0, tder = derlst; i < sk_ASN1_VALUE_num(sk); i++, tder++) {
++        memcpy(p, tder->data, tder->length);
++        p += tder->length;
++    }
++    *out = p;
++    /* If do_sort is 2 then reorder the STACK */
++    if (do_sort == 2) {
++        for (i = 0, tder = derlst; i < sk_ASN1_VALUE_num(sk); i++, tder++)
++            (void)sk_ASN1_VALUE_set(sk, i, tder->field);
++    }
++    OPENSSL_free(derlst);
++    OPENSSL_free(tmpdat);
++    return 1;
++}
++
++static int asn1_i2d_ex_primitive(ASN1_VALUE **pval, unsigned char **out,
++                                 const ASN1_ITEM *it, int tag, int aclass)
++{
++    int len;
++    int utype;
++    int usetag;
++    int ndef = 0;
++
++    utype = it->utype;
++
++    /*
++     * Get length of content octets and maybe find out the underlying type.
++     */
++
++    len = asn1_ex_i2c(pval, NULL, &utype, it);
++
++    /*
++     * If SEQUENCE, SET or OTHER then header is included in pseudo content
++     * octets so don't include tag+length. We need to check here because the
++     * call to asn1_ex_i2c() could change utype.
++     */
++    if ((utype == V_ASN1_SEQUENCE) || (utype == V_ASN1_SET) ||
++        (utype == V_ASN1_OTHER))
++        usetag = 0;
++    else
++        usetag = 1;
++
++    /* -1 means omit type */
++
++    if (len == -1)
++        return 0;
++
++    /* -2 return is special meaning use ndef */
++    if (len == -2) {
++        ndef = 2;
++        len = 0;
++    }
++
++    /* If not implicitly tagged get tag from underlying type */
++    if (tag == -1)
++        tag = utype;
++
++    /* Output tag+length followed by content octets */
++    if (out) {
++        if (usetag)
++            ASN1_put_object(out, ndef, len, tag, aclass);
++        asn1_ex_i2c(pval, *out, &utype, it);
++        if (ndef)
++            ASN1_put_eoc(out);
++        else
++            *out += len;
++    }
++
++    if (usetag)
++        return ASN1_object_size(ndef, len, tag);
++    return len;
++}
++
++/* Produce content octets from a structure */
++
++static int asn1_ex_i2c(ASN1_VALUE **pval, unsigned char *cout, int *putype,
++                       const ASN1_ITEM *it)
++{
++    ASN1_BOOLEAN *tbool = NULL;
++    ASN1_STRING *strtmp;
++    ASN1_OBJECT *otmp;
++    int utype;
++    const unsigned char *cont;
++    unsigned char c;
++    int len;
++    const ASN1_PRIMITIVE_FUNCS *pf;
++    pf = it->funcs;
++    if (pf && pf->prim_i2c)
++        return pf->prim_i2c(pval, cout, putype, it);
++
++    /* Should type be omitted? */
++    if ((it->itype != ASN1_ITYPE_PRIMITIVE)
++        || (it->utype != V_ASN1_BOOLEAN)) {
++        if (!*pval)
++            return -1;
++    }
++
++    if (it->itype == ASN1_ITYPE_MSTRING) {
++        /* If MSTRING type set the underlying type */
++        strtmp = (ASN1_STRING *)*pval;
++        utype = strtmp->type;
++        *putype = utype;
++    } else if (it->utype == V_ASN1_ANY) {
++        /* If ANY set type and pointer to value */
++        ASN1_TYPE *typ;
++        typ = (ASN1_TYPE *)*pval;
++        utype = typ->type;
++        *putype = utype;
++        pval = &typ->value.asn1_value;
++    } else
++        utype = *putype;
++
++    switch (utype) {
++    case V_ASN1_OBJECT:
++        otmp = (ASN1_OBJECT *)*pval;
++        cont = otmp->data;
++        len = otmp->length;
++        break;
++
++    case V_ASN1_NULL:
++        cont = NULL;
++        len = 0;
++        break;
++
++    case V_ASN1_BOOLEAN:
++        tbool = (ASN1_BOOLEAN *)pval;
++        if (*tbool == -1)
++            return -1;
++        if (it->utype != V_ASN1_ANY) {
++            /*
++             * Default handling if value == size field then omit
++             */
++            if (*tbool && (it->size > 0))
++                return -1;
++            if (!*tbool && !it->size)
++                return -1;
++        }
++        c = (unsigned char)*tbool;
++        cont = &c;
++        len = 1;
++        break;
++
++    case V_ASN1_BIT_STRING:
++        return i2c_ASN1_BIT_STRING((ASN1_BIT_STRING *)*pval,
++                                   cout ? &cout : NULL);
++
++    case V_ASN1_INTEGER:
++    case V_ASN1_ENUMERATED:
++        /*
++         * These are all have the same content format as ASN1_INTEGER
++         */
++        return i2c_ASN1_INTEGER((ASN1_INTEGER *)*pval, cout ? &cout : NULL);
++
++    case V_ASN1_OCTET_STRING:
++    case V_ASN1_NUMERICSTRING:
++    case V_ASN1_PRINTABLESTRING:
++    case V_ASN1_T61STRING:
++    case V_ASN1_VIDEOTEXSTRING:
++    case V_ASN1_IA5STRING:
++    case V_ASN1_UTCTIME:
++    case V_ASN1_GENERALIZEDTIME:
++    case V_ASN1_GRAPHICSTRING:
++    case V_ASN1_VISIBLESTRING:
++    case V_ASN1_GENERALSTRING:
++    case V_ASN1_UNIVERSALSTRING:
++    case V_ASN1_BMPSTRING:
++    case V_ASN1_UTF8STRING:
++    case V_ASN1_SEQUENCE:
++    case V_ASN1_SET:
++    default:
++        /* All based on ASN1_STRING and handled the same */
++        strtmp = (ASN1_STRING *)*pval;
++        /* Special handling for NDEF */
++        if ((it->size == ASN1_TFLG_NDEF)
++            && (strtmp->flags & ASN1_STRING_FLAG_NDEF)) {
++            if (cout) {
++                strtmp->data = cout;
++                strtmp->length = 0;
++            }
++            /* Special return code */
++            return -2;
++        }
++        cont = strtmp->data;
++        len = strtmp->length;
++
++        break;
++
++    }
++    if (cout && len)
++        memcpy(cout, cont, len);
++    return len;
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/asn1/tasn_fre.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/asn1/tasn_fre.c
+new file mode 100644
+index 0000000..3c98efb
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/asn1/tasn_fre.c
+@@ -0,0 +1,207 @@
++/*
++ * Copyright 2000-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include 
++#include 
++#include 
++#include "asn1_locl.h"
++
++static void asn1_item_embed_free(ASN1_VALUE **pval, const ASN1_ITEM *it,
++                                 int embed);
++
++/* Free up an ASN1 structure */
++
++void ASN1_item_free(ASN1_VALUE *val, const ASN1_ITEM *it)
++{
++    asn1_item_embed_free(&val, it, 0);
++}
++
++void ASN1_item_ex_free(ASN1_VALUE **pval, const ASN1_ITEM *it)
++{
++    asn1_item_embed_free(pval, it, 0);
++}
++
++static void asn1_item_embed_free(ASN1_VALUE **pval, const ASN1_ITEM *it,
++                                 int embed)
++{
++    const ASN1_TEMPLATE *tt = NULL, *seqtt;
++    const ASN1_EXTERN_FUNCS *ef;
++    const ASN1_AUX *aux = it->funcs;
++    ASN1_aux_cb *asn1_cb;
++    int i;
++
++    if (!pval)
++        return;
++    if ((it->itype != ASN1_ITYPE_PRIMITIVE) && !*pval)
++        return;
++    if (aux && aux->asn1_cb)
++        asn1_cb = aux->asn1_cb;
++    else
++        asn1_cb = 0;
++
++    switch (it->itype) {
++
++    case ASN1_ITYPE_PRIMITIVE:
++        if (it->templates)
++            asn1_template_free(pval, it->templates);
++        else
++            asn1_primitive_free(pval, it, embed);
++        break;
++
++    case ASN1_ITYPE_MSTRING:
++        asn1_primitive_free(pval, it, embed);
++        break;
++
++    case ASN1_ITYPE_CHOICE:
++        if (asn1_cb) {
++            i = asn1_cb(ASN1_OP_FREE_PRE, pval, it, NULL);
++            if (i == 2)
++                return;
++        }
++        i = asn1_get_choice_selector(pval, it);
++        if ((i >= 0) && (i < it->tcount)) {
++            ASN1_VALUE **pchval;
++
++            tt = it->templates + i;
++            pchval = asn1_get_field_ptr(pval, tt);
++            asn1_template_free(pchval, tt);
++        }
++        if (asn1_cb)
++            asn1_cb(ASN1_OP_FREE_POST, pval, it, NULL);
++        if (embed == 0) {
++            OPENSSL_free(*pval);
++            *pval = NULL;
++        }
++        break;
++
++    case ASN1_ITYPE_EXTERN:
++        ef = it->funcs;
++        if (ef && ef->asn1_ex_free)
++            ef->asn1_ex_free(pval, it);
++        break;
++
++    case ASN1_ITYPE_NDEF_SEQUENCE:
++    case ASN1_ITYPE_SEQUENCE:
++        if (asn1_do_lock(pval, -1, it) != 0) /* if error or ref-counter > 0 */
++            return;
++        if (asn1_cb) {
++            i = asn1_cb(ASN1_OP_FREE_PRE, pval, it, NULL);
++            if (i == 2)
++                return;
++        }
++        asn1_enc_free(pval, it);
++        /*
++         * If we free up as normal we will invalidate any ANY DEFINED BY
++         * field and we won't be able to determine the type of the field it
++         * defines. So free up in reverse order.
++         */
++        tt = it->templates + it->tcount;
++        for (i = 0; i < it->tcount; i++) {
++            ASN1_VALUE **pseqval;
++
++            tt--;
++            seqtt = asn1_do_adb(pval, tt, 0);
++            if (!seqtt)
++                continue;
++            pseqval = asn1_get_field_ptr(pval, seqtt);
++            asn1_template_free(pseqval, seqtt);
++        }
++        if (asn1_cb)
++            asn1_cb(ASN1_OP_FREE_POST, pval, it, NULL);
++        if (embed == 0) {
++            OPENSSL_free(*pval);
++            *pval = NULL;
++        }
++        break;
++    }
++}
++
++void asn1_template_free(ASN1_VALUE **pval, const ASN1_TEMPLATE *tt)
++{
++    int embed = tt->flags & ASN1_TFLG_EMBED;
++    ASN1_VALUE *tval;
++    if (embed) {
++        tval = (ASN1_VALUE *)pval;
++        pval = &tval;
++    }
++    if (tt->flags & ASN1_TFLG_SK_MASK) {
++        STACK_OF(ASN1_VALUE) *sk = (STACK_OF(ASN1_VALUE) *)*pval;
++        int i;
++
++        for (i = 0; i < sk_ASN1_VALUE_num(sk); i++) {
++            ASN1_VALUE *vtmp = sk_ASN1_VALUE_value(sk, i);
++
++            asn1_item_embed_free(&vtmp, ASN1_ITEM_ptr(tt->item), embed);
++        }
++        sk_ASN1_VALUE_free(sk);
++        *pval = NULL;
++    } else {
++        asn1_item_embed_free(pval, ASN1_ITEM_ptr(tt->item), embed);
++    }
++}
++
++void asn1_primitive_free(ASN1_VALUE **pval, const ASN1_ITEM *it, int embed)
++{
++    int utype;
++
++    /* Special case: if 'it' is a primitive with a free_func, use that. */
++    if (it) {
++        const ASN1_PRIMITIVE_FUNCS *pf = it->funcs;
++
++        if (pf && pf->prim_free) {
++            pf->prim_free(pval, it);
++            return;
++        }
++    }
++
++    /* Special case: if 'it' is NULL, free contents of ASN1_TYPE */
++    if (!it) {
++        ASN1_TYPE *typ = (ASN1_TYPE *)*pval;
++
++        utype = typ->type;
++        pval = &typ->value.asn1_value;
++        if (!*pval)
++            return;
++    } else if (it->itype == ASN1_ITYPE_MSTRING) {
++        utype = -1;
++        if (!*pval)
++            return;
++    } else {
++        utype = it->utype;
++        if ((utype != V_ASN1_BOOLEAN) && !*pval)
++            return;
++    }
++
++    switch (utype) {
++    case V_ASN1_OBJECT:
++        ASN1_OBJECT_free((ASN1_OBJECT *)*pval);
++        break;
++
++    case V_ASN1_BOOLEAN:
++        if (it)
++            *(ASN1_BOOLEAN *)pval = it->size;
++        else
++            *(ASN1_BOOLEAN *)pval = -1;
++        return;
++
++    case V_ASN1_NULL:
++        break;
++
++    case V_ASN1_ANY:
++        asn1_primitive_free(pval, NULL, 0);
++        OPENSSL_free(*pval);
++        break;
++
++    default:
++        asn1_string_embed_free((ASN1_STRING *)*pval, embed);
++        break;
++    }
++    *pval = NULL;
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/asn1/tasn_new.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/asn1/tasn_new.c
+new file mode 100644
+index 0000000..e9b8377
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/asn1/tasn_new.c
+@@ -0,0 +1,337 @@
++/*
++ * Copyright 2000-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include 
++#include 
++#include 
++#include 
++#include 
++#include "asn1_locl.h"
++
++static int asn1_item_embed_new(ASN1_VALUE **pval, const ASN1_ITEM *it,
++                               int embed);
++static int asn1_primitive_new(ASN1_VALUE **pval, const ASN1_ITEM *it,
++                              int embed);
++static void asn1_item_clear(ASN1_VALUE **pval, const ASN1_ITEM *it);
++static int asn1_template_new(ASN1_VALUE **pval, const ASN1_TEMPLATE *tt);
++static void asn1_template_clear(ASN1_VALUE **pval, const ASN1_TEMPLATE *tt);
++static void asn1_primitive_clear(ASN1_VALUE **pval, const ASN1_ITEM *it);
++
++ASN1_VALUE *ASN1_item_new(const ASN1_ITEM *it)
++{
++    ASN1_VALUE *ret = NULL;
++    if (ASN1_item_ex_new(&ret, it) > 0)
++        return ret;
++    return NULL;
++}
++
++/* Allocate an ASN1 structure */
++
++int ASN1_item_ex_new(ASN1_VALUE **pval, const ASN1_ITEM *it)
++{
++    return asn1_item_embed_new(pval, it, 0);
++}
++
++int asn1_item_embed_new(ASN1_VALUE **pval, const ASN1_ITEM *it, int embed)
++{
++    const ASN1_TEMPLATE *tt = NULL;
++    const ASN1_EXTERN_FUNCS *ef;
++    const ASN1_AUX *aux = it->funcs;
++    ASN1_aux_cb *asn1_cb;
++    ASN1_VALUE **pseqval;
++    int i;
++    if (aux && aux->asn1_cb)
++        asn1_cb = aux->asn1_cb;
++    else
++        asn1_cb = 0;
++
++#ifndef OPENSSL_NO_CRYPTO_MDEBUG
++    OPENSSL_mem_debug_push(it->sname ? it->sname : "asn1_item_embed_new");
++#endif
++
++    switch (it->itype) {
++
++    case ASN1_ITYPE_EXTERN:
++        ef = it->funcs;
++        if (ef && ef->asn1_ex_new) {
++            if (!ef->asn1_ex_new(pval, it))
++                goto memerr;
++        }
++        break;
++
++    case ASN1_ITYPE_PRIMITIVE:
++        if (it->templates) {
++            if (!asn1_template_new(pval, it->templates))
++                goto memerr;
++        } else if (!asn1_primitive_new(pval, it, embed))
++            goto memerr;
++        break;
++
++    case ASN1_ITYPE_MSTRING:
++        if (!asn1_primitive_new(pval, it, embed))
++            goto memerr;
++        break;
++
++    case ASN1_ITYPE_CHOICE:
++        if (asn1_cb) {
++            i = asn1_cb(ASN1_OP_NEW_PRE, pval, it, NULL);
++            if (!i)
++                goto auxerr;
++            if (i == 2) {
++#ifndef OPENSSL_NO_CRYPTO_MDEBUG
++                OPENSSL_mem_debug_pop();
++#endif
++                return 1;
++            }
++        }
++        if (embed) {
++            memset(*pval, 0, it->size);
++        } else {
++            *pval = OPENSSL_zalloc(it->size);
++            if (*pval == NULL)
++                goto memerr;
++        }
++        asn1_set_choice_selector(pval, -1, it);
++        if (asn1_cb && !asn1_cb(ASN1_OP_NEW_POST, pval, it, NULL))
++            goto auxerr2;
++        break;
++
++    case ASN1_ITYPE_NDEF_SEQUENCE:
++    case ASN1_ITYPE_SEQUENCE:
++        if (asn1_cb) {
++            i = asn1_cb(ASN1_OP_NEW_PRE, pval, it, NULL);
++            if (!i)
++                goto auxerr;
++            if (i == 2) {
++#ifndef OPENSSL_NO_CRYPTO_MDEBUG
++                OPENSSL_mem_debug_pop();
++#endif
++                return 1;
++            }
++        }
++        if (embed) {
++            memset(*pval, 0, it->size);
++        } else {
++            *pval = OPENSSL_zalloc(it->size);
++            if (*pval == NULL)
++                goto memerr;
++        }
++        /* 0 : init. lock */
++        if (asn1_do_lock(pval, 0, it) < 0)
++            goto memerr2;
++        asn1_enc_init(pval, it);
++        for (i = 0, tt = it->templates; i < it->tcount; tt++, i++) {
++            pseqval = asn1_get_field_ptr(pval, tt);
++            if (!asn1_template_new(pseqval, tt))
++                goto memerr2;
++        }
++        if (asn1_cb && !asn1_cb(ASN1_OP_NEW_POST, pval, it, NULL))
++            goto auxerr2;
++        break;
++    }
++#ifndef OPENSSL_NO_CRYPTO_MDEBUG
++    OPENSSL_mem_debug_pop();
++#endif
++    return 1;
++
++ memerr2:
++    ASN1_item_ex_free(pval, it);
++ memerr:
++    ASN1err(ASN1_F_ASN1_ITEM_EMBED_NEW, ERR_R_MALLOC_FAILURE);
++#ifndef OPENSSL_NO_CRYPTO_MDEBUG
++    OPENSSL_mem_debug_pop();
++#endif
++    return 0;
++
++ auxerr2:
++    ASN1_item_ex_free(pval, it);
++ auxerr:
++    ASN1err(ASN1_F_ASN1_ITEM_EMBED_NEW, ASN1_R_AUX_ERROR);
++#ifndef OPENSSL_NO_CRYPTO_MDEBUG
++    OPENSSL_mem_debug_pop();
++#endif
++    return 0;
++
++}
++
++static void asn1_item_clear(ASN1_VALUE **pval, const ASN1_ITEM *it)
++{
++    const ASN1_EXTERN_FUNCS *ef;
++
++    switch (it->itype) {
++
++    case ASN1_ITYPE_EXTERN:
++        ef = it->funcs;
++        if (ef && ef->asn1_ex_clear)
++            ef->asn1_ex_clear(pval, it);
++        else
++            *pval = NULL;
++        break;
++
++    case ASN1_ITYPE_PRIMITIVE:
++        if (it->templates)
++            asn1_template_clear(pval, it->templates);
++        else
++            asn1_primitive_clear(pval, it);
++        break;
++
++    case ASN1_ITYPE_MSTRING:
++        asn1_primitive_clear(pval, it);
++        break;
++
++    case ASN1_ITYPE_CHOICE:
++    case ASN1_ITYPE_SEQUENCE:
++    case ASN1_ITYPE_NDEF_SEQUENCE:
++        *pval = NULL;
++        break;
++    }
++}
++
++static int asn1_template_new(ASN1_VALUE **pval, const ASN1_TEMPLATE *tt)
++{
++    const ASN1_ITEM *it = ASN1_ITEM_ptr(tt->item);
++    int embed = tt->flags & ASN1_TFLG_EMBED;
++    ASN1_VALUE *tval;
++    int ret;
++    if (embed) {
++        tval = (ASN1_VALUE *)pval;
++        pval = &tval;
++    }
++    if (tt->flags & ASN1_TFLG_OPTIONAL) {
++        asn1_template_clear(pval, tt);
++        return 1;
++    }
++    /* If ANY DEFINED BY nothing to do */
++
++    if (tt->flags & ASN1_TFLG_ADB_MASK) {
++        *pval = NULL;
++        return 1;
++    }
++#ifndef OPENSSL_NO_CRYPTO_MDEBUG
++    OPENSSL_mem_debug_push(tt->field_name
++            ? tt->field_name : "asn1_template_new");
++#endif
++    /* If SET OF or SEQUENCE OF, its a STACK */
++    if (tt->flags & ASN1_TFLG_SK_MASK) {
++        STACK_OF(ASN1_VALUE) *skval;
++        skval = sk_ASN1_VALUE_new_null();
++        if (!skval) {
++            ASN1err(ASN1_F_ASN1_TEMPLATE_NEW, ERR_R_MALLOC_FAILURE);
++            ret = 0;
++            goto done;
++        }
++        *pval = (ASN1_VALUE *)skval;
++        ret = 1;
++        goto done;
++    }
++    /* Otherwise pass it back to the item routine */
++    ret = asn1_item_embed_new(pval, it, embed);
++ done:
++#ifndef OPENSSL_NO_CRYPTO_MDEBUG
++    OPENSSL_mem_debug_pop();
++#endif
++    return ret;
++}
++
++static void asn1_template_clear(ASN1_VALUE **pval, const ASN1_TEMPLATE *tt)
++{
++    /* If ADB or STACK just NULL the field */
++    if (tt->flags & (ASN1_TFLG_ADB_MASK | ASN1_TFLG_SK_MASK))
++        *pval = NULL;
++    else
++        asn1_item_clear(pval, ASN1_ITEM_ptr(tt->item));
++}
++
++/*
++ * NB: could probably combine most of the real XXX_new() behaviour and junk
++ * all the old functions.
++ */
++
++static int asn1_primitive_new(ASN1_VALUE **pval, const ASN1_ITEM *it,
++                              int embed)
++{
++    ASN1_TYPE *typ;
++    ASN1_STRING *str;
++    int utype;
++
++    if (!it)
++        return 0;
++
++    if (it->funcs) {
++        const ASN1_PRIMITIVE_FUNCS *pf = it->funcs;
++        if (pf->prim_new)
++            return pf->prim_new(pval, it);
++    }
++
++    if (it->itype == ASN1_ITYPE_MSTRING)
++        utype = -1;
++    else
++        utype = it->utype;
++    switch (utype) {
++    case V_ASN1_OBJECT:
++        *pval = (ASN1_VALUE *)OBJ_nid2obj(NID_undef);
++        return 1;
++
++    case V_ASN1_BOOLEAN:
++        *(ASN1_BOOLEAN *)pval = it->size;
++        return 1;
++
++    case V_ASN1_NULL:
++        *pval = (ASN1_VALUE *)1;
++        return 1;
++
++    case V_ASN1_ANY:
++        typ = OPENSSL_malloc(sizeof(*typ));
++        if (typ == NULL)
++            return 0;
++        typ->value.ptr = NULL;
++        typ->type = -1;
++        *pval = (ASN1_VALUE *)typ;
++        break;
++
++    default:
++        if (embed) {
++            str = *(ASN1_STRING **)pval;
++            memset(str, 0, sizeof(*str));
++            str->type = utype;
++            str->flags = ASN1_STRING_FLAG_EMBED;
++        } else {
++            str = ASN1_STRING_type_new(utype);
++            *pval = (ASN1_VALUE *)str;
++        }
++        if (it->itype == ASN1_ITYPE_MSTRING && str)
++            str->flags |= ASN1_STRING_FLAG_MSTRING;
++        break;
++    }
++    if (*pval)
++        return 1;
++    return 0;
++}
++
++static void asn1_primitive_clear(ASN1_VALUE **pval, const ASN1_ITEM *it)
++{
++    int utype;
++    if (it && it->funcs) {
++        const ASN1_PRIMITIVE_FUNCS *pf = it->funcs;
++        if (pf->prim_clear)
++            pf->prim_clear(pval, it);
++        else
++            *pval = NULL;
++        return;
++    }
++    if (!it || (it->itype == ASN1_ITYPE_MSTRING))
++        utype = -1;
++    else
++        utype = it->utype;
++    if (utype == V_ASN1_BOOLEAN)
++        *(ASN1_BOOLEAN *)pval = it->size;
++    else
++        *pval = NULL;
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/asn1/tasn_prn.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/asn1/tasn_prn.c
+new file mode 100644
+index 0000000..f53e905
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/asn1/tasn_prn.c
+@@ -0,0 +1,538 @@
++/*
++ * Copyright 2000-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include "internal/cryptlib.h"
++#include 
++#include 
++#include 
++#include 
++#include 
++#include 
++#include "internal/asn1_int.h"
++#include "asn1_locl.h"
++
++/*
++ * Print routines.
++ */
++
++/* ASN1_PCTX routines */
++
++static ASN1_PCTX default_pctx = {
++    ASN1_PCTX_FLAGS_SHOW_ABSENT, /* flags */
++    0,                          /* nm_flags */
++    0,                          /* cert_flags */
++    0,                          /* oid_flags */
++    0                           /* str_flags */
++};
++
++ASN1_PCTX *ASN1_PCTX_new(void)
++{
++    ASN1_PCTX *ret;
++
++    ret = OPENSSL_zalloc(sizeof(*ret));
++    if (ret == NULL) {
++        ASN1err(ASN1_F_ASN1_PCTX_NEW, ERR_R_MALLOC_FAILURE);
++        return NULL;
++    }
++    return ret;
++}
++
++void ASN1_PCTX_free(ASN1_PCTX *p)
++{
++    OPENSSL_free(p);
++}
++
++unsigned long ASN1_PCTX_get_flags(const ASN1_PCTX *p)
++{
++    return p->flags;
++}
++
++void ASN1_PCTX_set_flags(ASN1_PCTX *p, unsigned long flags)
++{
++    p->flags = flags;
++}
++
++unsigned long ASN1_PCTX_get_nm_flags(const ASN1_PCTX *p)
++{
++    return p->nm_flags;
++}
++
++void ASN1_PCTX_set_nm_flags(ASN1_PCTX *p, unsigned long flags)
++{
++    p->nm_flags = flags;
++}
++
++unsigned long ASN1_PCTX_get_cert_flags(const ASN1_PCTX *p)
++{
++    return p->cert_flags;
++}
++
++void ASN1_PCTX_set_cert_flags(ASN1_PCTX *p, unsigned long flags)
++{
++    p->cert_flags = flags;
++}
++
++unsigned long ASN1_PCTX_get_oid_flags(const ASN1_PCTX *p)
++{
++    return p->oid_flags;
++}
++
++void ASN1_PCTX_set_oid_flags(ASN1_PCTX *p, unsigned long flags)
++{
++    p->oid_flags = flags;
++}
++
++unsigned long ASN1_PCTX_get_str_flags(const ASN1_PCTX *p)
++{
++    return p->str_flags;
++}
++
++void ASN1_PCTX_set_str_flags(ASN1_PCTX *p, unsigned long flags)
++{
++    p->str_flags = flags;
++}
++
++/* Main print routines */
++
++static int asn1_item_print_ctx(BIO *out, ASN1_VALUE **fld, int indent,
++                               const ASN1_ITEM *it,
++                               const char *fname, const char *sname,
++                               int nohdr, const ASN1_PCTX *pctx);
++
++static int asn1_template_print_ctx(BIO *out, ASN1_VALUE **fld, int indent,
++                            const ASN1_TEMPLATE *tt, const ASN1_PCTX *pctx);
++
++static int asn1_primitive_print(BIO *out, ASN1_VALUE **fld,
++                                const ASN1_ITEM *it, int indent,
++                                const char *fname, const char *sname,
++                                const ASN1_PCTX *pctx);
++
++static int asn1_print_fsname(BIO *out, int indent,
++                             const char *fname, const char *sname,
++                             const ASN1_PCTX *pctx);
++
++int ASN1_item_print(BIO *out, ASN1_VALUE *ifld, int indent,
++                    const ASN1_ITEM *it, const ASN1_PCTX *pctx)
++{
++    const char *sname;
++    if (pctx == NULL)
++        pctx = &default_pctx;
++    if (pctx->flags & ASN1_PCTX_FLAGS_NO_STRUCT_NAME)
++        sname = NULL;
++    else
++        sname = it->sname;
++    return asn1_item_print_ctx(out, &ifld, indent, it, NULL, sname, 0, pctx);
++}
++
++static int asn1_item_print_ctx(BIO *out, ASN1_VALUE **fld, int indent,
++                               const ASN1_ITEM *it,
++                               const char *fname, const char *sname,
++                               int nohdr, const ASN1_PCTX *pctx)
++{
++    const ASN1_TEMPLATE *tt;
++    const ASN1_EXTERN_FUNCS *ef;
++    ASN1_VALUE **tmpfld;
++    const ASN1_AUX *aux = it->funcs;
++    ASN1_aux_cb *asn1_cb;
++    ASN1_PRINT_ARG parg;
++    int i;
++    if (aux && aux->asn1_cb) {
++        parg.out = out;
++        parg.indent = indent;
++        parg.pctx = pctx;
++        asn1_cb = aux->asn1_cb;
++    } else
++        asn1_cb = 0;
++
++   if (((it->itype != ASN1_ITYPE_PRIMITIVE)
++       || (it->utype != V_ASN1_BOOLEAN)) && *fld == NULL) {
++        if (pctx->flags & ASN1_PCTX_FLAGS_SHOW_ABSENT) {
++            if (!nohdr && !asn1_print_fsname(out, indent, fname, sname, pctx))
++                return 0;
++            if (BIO_puts(out, "\n") <= 0)
++                return 0;
++        }
++        return 1;
++    }
++
++    switch (it->itype) {
++    case ASN1_ITYPE_PRIMITIVE:
++        if (it->templates) {
++            if (!asn1_template_print_ctx(out, fld, indent,
++                                         it->templates, pctx))
++                return 0;
++            break;
++        }
++        /* fall through */
++    case ASN1_ITYPE_MSTRING:
++        if (!asn1_primitive_print(out, fld, it, indent, fname, sname, pctx))
++            return 0;
++        break;
++
++    case ASN1_ITYPE_EXTERN:
++        if (!nohdr && !asn1_print_fsname(out, indent, fname, sname, pctx))
++            return 0;
++        /* Use new style print routine if possible */
++        ef = it->funcs;
++        if (ef && ef->asn1_ex_print) {
++            i = ef->asn1_ex_print(out, fld, indent, "", pctx);
++            if (!i)
++                return 0;
++            if ((i == 2) && (BIO_puts(out, "\n") <= 0))
++                return 0;
++            return 1;
++        } else if (sname &&
++                   BIO_printf(out, ":EXTERNAL TYPE %s\n", sname) <= 0)
++            return 0;
++        break;
++
++    case ASN1_ITYPE_CHOICE:
++        /* CHOICE type, get selector */
++        i = asn1_get_choice_selector(fld, it);
++        /* This should never happen... */
++        if ((i < 0) || (i >= it->tcount)) {
++            if (BIO_printf(out, "ERROR: selector [%d] invalid\n", i) <= 0)
++                return 0;
++            return 1;
++        }
++        tt = it->templates + i;
++        tmpfld = asn1_get_field_ptr(fld, tt);
++        if (!asn1_template_print_ctx(out, tmpfld, indent, tt, pctx))
++            return 0;
++        break;
++
++    case ASN1_ITYPE_SEQUENCE:
++    case ASN1_ITYPE_NDEF_SEQUENCE:
++        if (!nohdr && !asn1_print_fsname(out, indent, fname, sname, pctx))
++            return 0;
++        if (fname || sname) {
++            if (pctx->flags & ASN1_PCTX_FLAGS_SHOW_SEQUENCE) {
++                if (BIO_puts(out, " {\n") <= 0)
++                    return 0;
++            } else {
++                if (BIO_puts(out, "\n") <= 0)
++                    return 0;
++            }
++        }
++
++        if (asn1_cb) {
++            i = asn1_cb(ASN1_OP_PRINT_PRE, fld, it, &parg);
++            if (i == 0)
++                return 0;
++            if (i == 2)
++                return 1;
++        }
++
++        /* Print each field entry */
++        for (i = 0, tt = it->templates; i < it->tcount; i++, tt++) {
++            const ASN1_TEMPLATE *seqtt;
++            seqtt = asn1_do_adb(fld, tt, 1);
++            if (!seqtt)
++                return 0;
++            tmpfld = asn1_get_field_ptr(fld, seqtt);
++            if (!asn1_template_print_ctx(out, tmpfld,
++                                         indent + 2, seqtt, pctx))
++                return 0;
++        }
++        if (pctx->flags & ASN1_PCTX_FLAGS_SHOW_SEQUENCE) {
++            if (BIO_printf(out, "%*s}\n", indent, "") < 0)
++                return 0;
++        }
++
++        if (asn1_cb) {
++            i = asn1_cb(ASN1_OP_PRINT_POST, fld, it, &parg);
++            if (i == 0)
++                return 0;
++        }
++        break;
++
++    default:
++        BIO_printf(out, "Unprocessed type %d\n", it->itype);
++        return 0;
++    }
++
++    return 1;
++}
++
++static int asn1_template_print_ctx(BIO *out, ASN1_VALUE **fld, int indent,
++                            const ASN1_TEMPLATE *tt, const ASN1_PCTX *pctx)
++{
++    int i, flags;
++    const char *sname, *fname;
++    ASN1_VALUE *tfld;
++    flags = tt->flags;
++    if (pctx->flags & ASN1_PCTX_FLAGS_SHOW_FIELD_STRUCT_NAME)
++        sname = ASN1_ITEM_ptr(tt->item)->sname;
++    else
++        sname = NULL;
++    if (pctx->flags & ASN1_PCTX_FLAGS_NO_FIELD_NAME)
++        fname = NULL;
++    else
++        fname = tt->field_name;
++
++    /*
++     * If field is embedded then fld needs fixing so it is a pointer to
++     * a pointer to a field.
++     */
++    if (flags & ASN1_TFLG_EMBED) {
++        tfld = (ASN1_VALUE *)fld;
++        fld = &tfld;
++    }
++
++    if (flags & ASN1_TFLG_SK_MASK) {
++        char *tname;
++        ASN1_VALUE *skitem;
++        STACK_OF(ASN1_VALUE) *stack;
++
++        /* SET OF, SEQUENCE OF */
++        if (fname) {
++            if (pctx->flags & ASN1_PCTX_FLAGS_SHOW_SSOF) {
++                if (flags & ASN1_TFLG_SET_OF)
++                    tname = "SET";
++                else
++                    tname = "SEQUENCE";
++                if (BIO_printf(out, "%*s%s OF %s {\n",
++                               indent, "", tname, tt->field_name) <= 0)
++                    return 0;
++            } else if (BIO_printf(out, "%*s%s:\n", indent, "", fname) <= 0)
++                return 0;
++        }
++        stack = (STACK_OF(ASN1_VALUE) *)*fld;
++        for (i = 0; i < sk_ASN1_VALUE_num(stack); i++) {
++            if ((i > 0) && (BIO_puts(out, "\n") <= 0))
++                return 0;
++
++            skitem = sk_ASN1_VALUE_value(stack, i);
++            if (!asn1_item_print_ctx(out, &skitem, indent + 2,
++                                     ASN1_ITEM_ptr(tt->item), NULL, NULL, 1,
++                                     pctx))
++                return 0;
++        }
++        if (!i && BIO_printf(out, "%*s\n", indent + 2, "") <= 0)
++            return 0;
++        if (pctx->flags & ASN1_PCTX_FLAGS_SHOW_SEQUENCE) {
++            if (BIO_printf(out, "%*s}\n", indent, "") <= 0)
++                return 0;
++        }
++        return 1;
++    }
++    return asn1_item_print_ctx(out, fld, indent, ASN1_ITEM_ptr(tt->item),
++                               fname, sname, 0, pctx);
++}
++
++static int asn1_print_fsname(BIO *out, int indent,
++                             const char *fname, const char *sname,
++                             const ASN1_PCTX *pctx)
++{
++    static const char spaces[] = "                    ";
++    static const int nspaces = sizeof(spaces) - 1;
++
++    while (indent > nspaces) {
++        if (BIO_write(out, spaces, nspaces) != nspaces)
++            return 0;
++        indent -= nspaces;
++    }
++    if (BIO_write(out, spaces, indent) != indent)
++        return 0;
++    if (pctx->flags & ASN1_PCTX_FLAGS_NO_STRUCT_NAME)
++        sname = NULL;
++    if (pctx->flags & ASN1_PCTX_FLAGS_NO_FIELD_NAME)
++        fname = NULL;
++    if (!sname && !fname)
++        return 1;
++    if (fname) {
++        if (BIO_puts(out, fname) <= 0)
++            return 0;
++    }
++    if (sname) {
++        if (fname) {
++            if (BIO_printf(out, " (%s)", sname) <= 0)
++                return 0;
++        } else {
++            if (BIO_puts(out, sname) <= 0)
++                return 0;
++        }
++    }
++    if (BIO_write(out, ": ", 2) != 2)
++        return 0;
++    return 1;
++}
++
++static int asn1_print_boolean(BIO *out, int boolval)
++{
++    const char *str;
++    switch (boolval) {
++    case -1:
++        str = "BOOL ABSENT";
++        break;
++
++    case 0:
++        str = "FALSE";
++        break;
++
++    default:
++        str = "TRUE";
++        break;
++
++    }
++
++    if (BIO_puts(out, str) <= 0)
++        return 0;
++    return 1;
++
++}
++
++static int asn1_print_integer(BIO *out, const ASN1_INTEGER *str)
++{
++    char *s;
++    int ret = 1;
++    s = i2s_ASN1_INTEGER(NULL, str);
++    if (s == NULL)
++        return 0;
++    if (BIO_puts(out, s) <= 0)
++        ret = 0;
++    OPENSSL_free(s);
++    return ret;
++}
++
++static int asn1_print_oid(BIO *out, const ASN1_OBJECT *oid)
++{
++    char objbuf[80];
++    const char *ln;
++    ln = OBJ_nid2ln(OBJ_obj2nid(oid));
++    if (!ln)
++        ln = "";
++    OBJ_obj2txt(objbuf, sizeof objbuf, oid, 1);
++    if (BIO_printf(out, "%s (%s)", ln, objbuf) <= 0)
++        return 0;
++    return 1;
++}
++
++static int asn1_print_obstring(BIO *out, const ASN1_STRING *str, int indent)
++{
++    if (str->type == V_ASN1_BIT_STRING) {
++        if (BIO_printf(out, " (%ld unused bits)\n", str->flags & 0x7) <= 0)
++            return 0;
++    } else if (BIO_puts(out, "\n") <= 0)
++        return 0;
++    if ((str->length > 0)
++        && BIO_dump_indent(out, (const char *)str->data, str->length,
++                           indent + 2) <= 0)
++        return 0;
++    return 1;
++}
++
++static int asn1_primitive_print(BIO *out, ASN1_VALUE **fld,
++                                const ASN1_ITEM *it, int indent,
++                                const char *fname, const char *sname,
++                                const ASN1_PCTX *pctx)
++{
++    long utype;
++    ASN1_STRING *str;
++    int ret = 1, needlf = 1;
++    const char *pname;
++    const ASN1_PRIMITIVE_FUNCS *pf;
++    pf = it->funcs;
++    if (!asn1_print_fsname(out, indent, fname, sname, pctx))
++        return 0;
++    if (pf && pf->prim_print)
++        return pf->prim_print(out, fld, it, indent, pctx);
++    if (it->itype == ASN1_ITYPE_MSTRING) {
++        str = (ASN1_STRING *)*fld;
++        utype = str->type & ~V_ASN1_NEG;
++    } else {
++        utype = it->utype;
++        if (utype == V_ASN1_BOOLEAN)
++            str = NULL;
++        else
++            str = (ASN1_STRING *)*fld;
++    }
++    if (utype == V_ASN1_ANY) {
++        ASN1_TYPE *atype = (ASN1_TYPE *)*fld;
++        utype = atype->type;
++        fld = &atype->value.asn1_value;
++        str = (ASN1_STRING *)*fld;
++        if (pctx->flags & ASN1_PCTX_FLAGS_NO_ANY_TYPE)
++            pname = NULL;
++        else
++            pname = ASN1_tag2str(utype);
++    } else {
++        if (pctx->flags & ASN1_PCTX_FLAGS_SHOW_TYPE)
++            pname = ASN1_tag2str(utype);
++        else
++            pname = NULL;
++    }
++
++    if (utype == V_ASN1_NULL) {
++        if (BIO_puts(out, "NULL\n") <= 0)
++            return 0;
++        return 1;
++    }
++
++    if (pname) {
++        if (BIO_puts(out, pname) <= 0)
++            return 0;
++        if (BIO_puts(out, ":") <= 0)
++            return 0;
++    }
++
++    switch (utype) {
++    case V_ASN1_BOOLEAN:
++        {
++            int boolval = *(int *)fld;
++            if (boolval == -1)
++                boolval = it->size;
++            ret = asn1_print_boolean(out, boolval);
++        }
++        break;
++
++    case V_ASN1_INTEGER:
++    case V_ASN1_ENUMERATED:
++        ret = asn1_print_integer(out, str);
++        break;
++
++    case V_ASN1_UTCTIME:
++        ret = ASN1_UTCTIME_print(out, str);
++        break;
++
++    case V_ASN1_GENERALIZEDTIME:
++        ret = ASN1_GENERALIZEDTIME_print(out, str);
++        break;
++
++    case V_ASN1_OBJECT:
++        ret = asn1_print_oid(out, (const ASN1_OBJECT *)*fld);
++        break;
++
++    case V_ASN1_OCTET_STRING:
++    case V_ASN1_BIT_STRING:
++        ret = asn1_print_obstring(out, str, indent);
++        needlf = 0;
++        break;
++
++    case V_ASN1_SEQUENCE:
++    case V_ASN1_SET:
++    case V_ASN1_OTHER:
++        if (BIO_puts(out, "\n") <= 0)
++            return 0;
++        if (ASN1_parse_dump(out, str->data, str->length, indent, 0) <= 0)
++            ret = 0;
++        needlf = 0;
++        break;
++
++    default:
++        ret = ASN1_STRING_print_ex(out, str, pctx->str_flags);
++
++    }
++    if (!ret)
++        return 0;
++    if (needlf && BIO_puts(out, "\n") <= 0)
++        return 0;
++    return 1;
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/asn1/tasn_scn.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/asn1/tasn_scn.c
+new file mode 100644
+index 0000000..e1df2cf
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/asn1/tasn_scn.c
+@@ -0,0 +1,65 @@
++/*
++ * Copyright 2010-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include "internal/cryptlib.h"
++#include 
++#include 
++#include 
++#include 
++#include 
++#include 
++#include "asn1_locl.h"
++
++/*
++ * General ASN1 structure recursive scanner: iterate through all fields
++ * passing details to a callback.
++ */
++
++ASN1_SCTX *ASN1_SCTX_new(int (*scan_cb) (ASN1_SCTX *ctx))
++{
++    ASN1_SCTX *ret = OPENSSL_zalloc(sizeof(*ret));
++
++    if (ret == NULL) {
++        ASN1err(ASN1_F_ASN1_SCTX_NEW, ERR_R_MALLOC_FAILURE);
++        return NULL;
++    }
++    ret->scan_cb = scan_cb;
++    return ret;
++}
++
++void ASN1_SCTX_free(ASN1_SCTX *p)
++{
++    OPENSSL_free(p);
++}
++
++const ASN1_ITEM *ASN1_SCTX_get_item(ASN1_SCTX *p)
++{
++    return p->it;
++}
++
++const ASN1_TEMPLATE *ASN1_SCTX_get_template(ASN1_SCTX *p)
++{
++    return p->tt;
++}
++
++unsigned long ASN1_SCTX_get_flags(ASN1_SCTX *p)
++{
++    return p->flags;
++}
++
++void ASN1_SCTX_set_app_data(ASN1_SCTX *p, void *data)
++{
++    p->app_data = data;
++}
++
++void *ASN1_SCTX_get_app_data(ASN1_SCTX *p)
++{
++    return p->app_data;
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/asn1/tasn_typ.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/asn1/tasn_typ.c
+new file mode 100644
+index 0000000..98d9879
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/asn1/tasn_typ.c
+@@ -0,0 +1,84 @@
++/*
++ * Copyright 2000-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include 
++#include 
++
++/* Declarations for string types */
++
++#define IMPLEMENT_ASN1_STRING_FUNCTIONS(sname) \
++    IMPLEMENT_ASN1_TYPE(sname) \
++    IMPLEMENT_ASN1_ENCODE_FUNCTIONS_fname(sname, sname, sname) \
++sname *sname##_new(void) \
++{ \
++    return ASN1_STRING_type_new(V_##sname); \
++} \
++void sname##_free(sname *x) \
++{ \
++    ASN1_STRING_free(x); \
++}
++
++IMPLEMENT_ASN1_STRING_FUNCTIONS(ASN1_OCTET_STRING)
++IMPLEMENT_ASN1_STRING_FUNCTIONS(ASN1_INTEGER)
++IMPLEMENT_ASN1_STRING_FUNCTIONS(ASN1_ENUMERATED)
++IMPLEMENT_ASN1_STRING_FUNCTIONS(ASN1_BIT_STRING)
++IMPLEMENT_ASN1_STRING_FUNCTIONS(ASN1_UTF8STRING)
++IMPLEMENT_ASN1_STRING_FUNCTIONS(ASN1_PRINTABLESTRING)
++IMPLEMENT_ASN1_STRING_FUNCTIONS(ASN1_T61STRING)
++IMPLEMENT_ASN1_STRING_FUNCTIONS(ASN1_IA5STRING)
++IMPLEMENT_ASN1_STRING_FUNCTIONS(ASN1_GENERALSTRING)
++IMPLEMENT_ASN1_STRING_FUNCTIONS(ASN1_UTCTIME)
++IMPLEMENT_ASN1_STRING_FUNCTIONS(ASN1_GENERALIZEDTIME)
++IMPLEMENT_ASN1_STRING_FUNCTIONS(ASN1_VISIBLESTRING)
++IMPLEMENT_ASN1_STRING_FUNCTIONS(ASN1_UNIVERSALSTRING)
++IMPLEMENT_ASN1_STRING_FUNCTIONS(ASN1_BMPSTRING)
++
++IMPLEMENT_ASN1_TYPE(ASN1_NULL)
++IMPLEMENT_ASN1_FUNCTIONS(ASN1_NULL)
++
++IMPLEMENT_ASN1_TYPE(ASN1_OBJECT)
++
++IMPLEMENT_ASN1_TYPE(ASN1_ANY)
++
++/* Just swallow an ASN1_SEQUENCE in an ASN1_STRING */
++IMPLEMENT_ASN1_TYPE(ASN1_SEQUENCE)
++
++IMPLEMENT_ASN1_FUNCTIONS_fname(ASN1_TYPE, ASN1_ANY, ASN1_TYPE)
++
++/* Multistring types */
++
++IMPLEMENT_ASN1_MSTRING(ASN1_PRINTABLE, B_ASN1_PRINTABLE)
++IMPLEMENT_ASN1_FUNCTIONS_name(ASN1_STRING, ASN1_PRINTABLE)
++
++IMPLEMENT_ASN1_MSTRING(DISPLAYTEXT, B_ASN1_DISPLAYTEXT)
++IMPLEMENT_ASN1_FUNCTIONS_name(ASN1_STRING, DISPLAYTEXT)
++
++IMPLEMENT_ASN1_MSTRING(DIRECTORYSTRING, B_ASN1_DIRECTORYSTRING)
++IMPLEMENT_ASN1_FUNCTIONS_name(ASN1_STRING, DIRECTORYSTRING)
++
++/* Three separate BOOLEAN type: normal, DEFAULT TRUE and DEFAULT FALSE */
++IMPLEMENT_ASN1_TYPE_ex(ASN1_BOOLEAN, ASN1_BOOLEAN, -1)
++IMPLEMENT_ASN1_TYPE_ex(ASN1_TBOOLEAN, ASN1_BOOLEAN, 1)
++IMPLEMENT_ASN1_TYPE_ex(ASN1_FBOOLEAN, ASN1_BOOLEAN, 0)
++
++/* Special, OCTET STRING with indefinite length constructed support */
++
++IMPLEMENT_ASN1_TYPE_ex(ASN1_OCTET_STRING_NDEF, ASN1_OCTET_STRING, ASN1_TFLG_NDEF)
++
++ASN1_ITEM_TEMPLATE(ASN1_SEQUENCE_ANY) =
++        ASN1_EX_TEMPLATE_TYPE(ASN1_TFLG_SEQUENCE_OF, 0, ASN1_SEQUENCE_ANY, ASN1_ANY)
++ASN1_ITEM_TEMPLATE_END(ASN1_SEQUENCE_ANY)
++
++ASN1_ITEM_TEMPLATE(ASN1_SET_ANY) =
++        ASN1_EX_TEMPLATE_TYPE(ASN1_TFLG_SET_OF, 0, ASN1_SET_ANY, ASN1_ANY)
++ASN1_ITEM_TEMPLATE_END(ASN1_SET_ANY)
++
++IMPLEMENT_ASN1_ENCODE_FUNCTIONS_const_fname(ASN1_SEQUENCE_ANY, ASN1_SEQUENCE_ANY, ASN1_SEQUENCE_ANY)
++IMPLEMENT_ASN1_ENCODE_FUNCTIONS_const_fname(ASN1_SEQUENCE_ANY, ASN1_SET_ANY, ASN1_SET_ANY)
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/asn1/tasn_utl.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/asn1/tasn_utl.c
+new file mode 100644
+index 0000000..f79d7d6
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/asn1/tasn_utl.c
+@@ -0,0 +1,240 @@
++/*
++ * Copyright 2000-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include 
++#include 
++#include 
++#include 
++#include 
++#include 
++#include "asn1_locl.h"
++
++/* Utility functions for manipulating fields and offsets */
++
++/* Add 'offset' to 'addr' */
++#define offset2ptr(addr, offset) (void *)(((char *) addr) + offset)
++
++/*
++ * Given an ASN1_ITEM CHOICE type return the selector value
++ */
++
++int asn1_get_choice_selector(ASN1_VALUE **pval, const ASN1_ITEM *it)
++{
++    int *sel = offset2ptr(*pval, it->utype);
++    return *sel;
++}
++
++/*
++ * Given an ASN1_ITEM CHOICE type set the selector value, return old value.
++ */
++
++int asn1_set_choice_selector(ASN1_VALUE **pval, int value,
++                             const ASN1_ITEM *it)
++{
++    int *sel, ret;
++    sel = offset2ptr(*pval, it->utype);
++    ret = *sel;
++    *sel = value;
++    return ret;
++}
++
++/*
++ * Do atomic reference counting. The value 'op' decides what to do.
++ * If it is +1 then the count is incremented.
++ * If |op| is 0, lock is initialised and count is set to 1.
++ * If |op| is -1, count is decremented and the return value is the current
++ * reference count or 0 if no reference count is active.
++ * It returns -1 on initialisation error.
++ * Used by ASN1_SEQUENCE construct of X509, X509_REQ, X509_CRL objects
++ */
++int asn1_do_lock(ASN1_VALUE **pval, int op, const ASN1_ITEM *it)
++{
++    const ASN1_AUX *aux;
++    int *lck, ret;
++    CRYPTO_RWLOCK **lock;
++    if ((it->itype != ASN1_ITYPE_SEQUENCE)
++        && (it->itype != ASN1_ITYPE_NDEF_SEQUENCE))
++        return 0;
++    aux = it->funcs;
++    if (!aux || !(aux->flags & ASN1_AFLG_REFCOUNT))
++        return 0;
++    lck = offset2ptr(*pval, aux->ref_offset);
++    lock = offset2ptr(*pval, aux->ref_lock);
++    if (op == 0) {
++        *lck = 1;
++        *lock = CRYPTO_THREAD_lock_new();
++        if (*lock == NULL) {
++            ASN1err(ASN1_F_ASN1_DO_LOCK, ERR_R_MALLOC_FAILURE);
++            return -1;
++        }
++        return 1;
++    }
++    if (CRYPTO_atomic_add(lck, op, &ret, *lock) < 0)
++        return -1;  /* failed */
++#ifdef REF_PRINT
++    fprintf(stderr, "%p:%4d:%s\n", it, *lck, it->sname);
++#endif
++    REF_ASSERT_ISNT(ret < 0);
++    if (ret == 0) {
++        CRYPTO_THREAD_lock_free(*lock);
++        *lock = NULL;
++    }
++    return ret;
++}
++
++static ASN1_ENCODING *asn1_get_enc_ptr(ASN1_VALUE **pval, const ASN1_ITEM *it)
++{
++    const ASN1_AUX *aux;
++    if (!pval || !*pval)
++        return NULL;
++    aux = it->funcs;
++    if (!aux || !(aux->flags & ASN1_AFLG_ENCODING))
++        return NULL;
++    return offset2ptr(*pval, aux->enc_offset);
++}
++
++void asn1_enc_init(ASN1_VALUE **pval, const ASN1_ITEM *it)
++{
++    ASN1_ENCODING *enc;
++    enc = asn1_get_enc_ptr(pval, it);
++    if (enc) {
++        enc->enc = NULL;
++        enc->len = 0;
++        enc->modified = 1;
++    }
++}
++
++void asn1_enc_free(ASN1_VALUE **pval, const ASN1_ITEM *it)
++{
++    ASN1_ENCODING *enc;
++    enc = asn1_get_enc_ptr(pval, it);
++    if (enc) {
++        OPENSSL_free(enc->enc);
++        enc->enc = NULL;
++        enc->len = 0;
++        enc->modified = 1;
++    }
++}
++
++int asn1_enc_save(ASN1_VALUE **pval, const unsigned char *in, int inlen,
++                  const ASN1_ITEM *it)
++{
++    ASN1_ENCODING *enc;
++    enc = asn1_get_enc_ptr(pval, it);
++    if (!enc)
++        return 1;
++
++    OPENSSL_free(enc->enc);
++    enc->enc = OPENSSL_malloc(inlen);
++    if (enc->enc == NULL)
++        return 0;
++    memcpy(enc->enc, in, inlen);
++    enc->len = inlen;
++    enc->modified = 0;
++
++    return 1;
++}
++
++int asn1_enc_restore(int *len, unsigned char **out, ASN1_VALUE **pval,
++                     const ASN1_ITEM *it)
++{
++    ASN1_ENCODING *enc;
++    enc = asn1_get_enc_ptr(pval, it);
++    if (!enc || enc->modified)
++        return 0;
++    if (out) {
++        memcpy(*out, enc->enc, enc->len);
++        *out += enc->len;
++    }
++    if (len)
++        *len = enc->len;
++    return 1;
++}
++
++/* Given an ASN1_TEMPLATE get a pointer to a field */
++ASN1_VALUE **asn1_get_field_ptr(ASN1_VALUE **pval, const ASN1_TEMPLATE *tt)
++{
++    ASN1_VALUE **pvaltmp;
++    pvaltmp = offset2ptr(*pval, tt->offset);
++    /*
++     * NOTE for BOOLEAN types the field is just a plain int so we can't
++     * return int **, so settle for (int *).
++     */
++    return pvaltmp;
++}
++
++/*
++ * Handle ANY DEFINED BY template, find the selector, look up the relevant
++ * ASN1_TEMPLATE in the table and return it.
++ */
++
++const ASN1_TEMPLATE *asn1_do_adb(ASN1_VALUE **pval, const ASN1_TEMPLATE *tt,
++                                 int nullerr)
++{
++    const ASN1_ADB *adb;
++    const ASN1_ADB_TABLE *atbl;
++    long selector;
++    ASN1_VALUE **sfld;
++    int i;
++    if (!(tt->flags & ASN1_TFLG_ADB_MASK))
++        return tt;
++
++    /* Else ANY DEFINED BY ... get the table */
++    adb = ASN1_ADB_ptr(tt->item);
++
++    /* Get the selector field */
++    sfld = offset2ptr(*pval, adb->offset);
++
++    /* Check if NULL */
++    if (*sfld == NULL) {
++        if (!adb->null_tt)
++            goto err;
++        return adb->null_tt;
++    }
++
++    /*
++     * Convert type to a long: NB: don't check for NID_undef here because it
++     * might be a legitimate value in the table
++     */
++    if (tt->flags & ASN1_TFLG_ADB_OID)
++        selector = OBJ_obj2nid((ASN1_OBJECT *)*sfld);
++    else
++        selector = ASN1_INTEGER_get((ASN1_INTEGER *)*sfld);
++
++    /* Let application callback translate value */
++    if (adb->adb_cb != NULL && adb->adb_cb(&selector) == 0) {
++        ASN1err(ASN1_F_ASN1_DO_ADB, ASN1_R_UNSUPPORTED_ANY_DEFINED_BY_TYPE);
++        return NULL;
++    }
++
++    /*
++     * Try to find matching entry in table Maybe should check application
++     * types first to allow application override? Might also be useful to
++     * have a flag which indicates table is sorted and we can do a binary
++     * search. For now stick to a linear search.
++     */
++
++    for (atbl = adb->tbl, i = 0; i < adb->tblcount; i++, atbl++)
++        if (atbl->value == selector)
++            return &atbl->tt;
++
++    /* FIXME: need to search application table too */
++
++    /* No match, return default type */
++    if (!adb->default_tt)
++        goto err;
++    return adb->default_tt;
++
++ err:
++    /* FIXME: should log the value or OID of unsupported type */
++    if (nullerr)
++        ASN1err(ASN1_F_ASN1_DO_ADB, ASN1_R_UNSUPPORTED_ANY_DEFINED_BY_TYPE);
++    return NULL;
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/asn1/x_algor.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/asn1/x_algor.c
+new file mode 100644
+index 0000000..72378db
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/asn1/x_algor.c
+@@ -0,0 +1,93 @@
++/*
++ * Copyright 1998-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include 
++#include 
++#include 
++#include "internal/evp_int.h"
++
++ASN1_SEQUENCE(X509_ALGOR) = {
++        ASN1_SIMPLE(X509_ALGOR, algorithm, ASN1_OBJECT),
++        ASN1_OPT(X509_ALGOR, parameter, ASN1_ANY)
++} ASN1_SEQUENCE_END(X509_ALGOR)
++
++ASN1_ITEM_TEMPLATE(X509_ALGORS) =
++        ASN1_EX_TEMPLATE_TYPE(ASN1_TFLG_SEQUENCE_OF, 0, algorithms, X509_ALGOR)
++ASN1_ITEM_TEMPLATE_END(X509_ALGORS)
++
++IMPLEMENT_ASN1_FUNCTIONS(X509_ALGOR)
++IMPLEMENT_ASN1_ENCODE_FUNCTIONS_fname(X509_ALGORS, X509_ALGORS, X509_ALGORS)
++IMPLEMENT_ASN1_DUP_FUNCTION(X509_ALGOR)
++
++int X509_ALGOR_set0(X509_ALGOR *alg, ASN1_OBJECT *aobj, int ptype, void *pval)
++{
++    if (!alg)
++        return 0;
++    if (ptype != V_ASN1_UNDEF) {
++        if (alg->parameter == NULL)
++            alg->parameter = ASN1_TYPE_new();
++        if (alg->parameter == NULL)
++            return 0;
++    }
++    if (alg) {
++        ASN1_OBJECT_free(alg->algorithm);
++        alg->algorithm = aobj;
++    }
++    if (ptype == 0)
++        return 1;
++    if (ptype == V_ASN1_UNDEF) {
++        ASN1_TYPE_free(alg->parameter);
++        alg->parameter = NULL;
++    } else
++        ASN1_TYPE_set(alg->parameter, ptype, pval);
++    return 1;
++}
++
++void X509_ALGOR_get0(const ASN1_OBJECT **paobj, int *pptype,
++                     const void **ppval, const X509_ALGOR *algor)
++{
++    if (paobj)
++        *paobj = algor->algorithm;
++    if (pptype) {
++        if (algor->parameter == NULL) {
++            *pptype = V_ASN1_UNDEF;
++            return;
++        } else
++            *pptype = algor->parameter->type;
++        if (ppval)
++            *ppval = algor->parameter->value.ptr;
++    }
++}
++
++/* Set up an X509_ALGOR DigestAlgorithmIdentifier from an EVP_MD */
++
++void X509_ALGOR_set_md(X509_ALGOR *alg, const EVP_MD *md)
++{
++    int param_type;
++
++    if (md->flags & EVP_MD_FLAG_DIGALGID_ABSENT)
++        param_type = V_ASN1_UNDEF;
++    else
++        param_type = V_ASN1_NULL;
++
++    X509_ALGOR_set0(alg, OBJ_nid2obj(EVP_MD_type(md)), param_type, NULL);
++
++}
++
++int X509_ALGOR_cmp(const X509_ALGOR *a, const X509_ALGOR *b)
++{
++    int rv;
++    rv = OBJ_cmp(a->algorithm, b->algorithm);
++    if (rv)
++        return rv;
++    if (!a->parameter && !b->parameter)
++        return 0;
++    return ASN1_TYPE_cmp(a->parameter, b->parameter);
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/asn1/x_bignum.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/asn1/x_bignum.c
+new file mode 100644
+index 0000000..da57e77
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/asn1/x_bignum.c
+@@ -0,0 +1,146 @@
++/*
++ * Copyright 2000-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include "internal/cryptlib.h"
++#include 
++#include 
++
++/*
++ * Custom primitive type for BIGNUM handling. This reads in an ASN1_INTEGER
++ * as a BIGNUM directly. Currently it ignores the sign which isn't a problem
++ * since all BIGNUMs used are non negative and anything that looks negative
++ * is normally due to an encoding error.
++ */
++
++#define BN_SENSITIVE    1
++
++static int bn_new(ASN1_VALUE **pval, const ASN1_ITEM *it);
++static int bn_secure_new(ASN1_VALUE **pval, const ASN1_ITEM *it);
++static void bn_free(ASN1_VALUE **pval, const ASN1_ITEM *it);
++
++static int bn_i2c(ASN1_VALUE **pval, unsigned char *cont, int *putype,
++                  const ASN1_ITEM *it);
++static int bn_c2i(ASN1_VALUE **pval, const unsigned char *cont, int len,
++                  int utype, char *free_cont, const ASN1_ITEM *it);
++static int bn_secure_c2i(ASN1_VALUE **pval, const unsigned char *cont, int len,
++                         int utype, char *free_cont, const ASN1_ITEM *it);
++static int bn_print(BIO *out, ASN1_VALUE **pval, const ASN1_ITEM *it,
++                    int indent, const ASN1_PCTX *pctx);
++
++static ASN1_PRIMITIVE_FUNCS bignum_pf = {
++    NULL, 0,
++    bn_new,
++    bn_free,
++    0,
++    bn_c2i,
++    bn_i2c,
++    bn_print
++};
++
++static ASN1_PRIMITIVE_FUNCS cbignum_pf = {
++    NULL, 0,
++    bn_secure_new,
++    bn_free,
++    0,
++    bn_secure_c2i,
++    bn_i2c,
++    bn_print
++};
++
++ASN1_ITEM_start(BIGNUM)
++        ASN1_ITYPE_PRIMITIVE, V_ASN1_INTEGER, NULL, 0, &bignum_pf, 0, "BIGNUM"
++ASN1_ITEM_end(BIGNUM)
++
++ASN1_ITEM_start(CBIGNUM)
++        ASN1_ITYPE_PRIMITIVE, V_ASN1_INTEGER, NULL, 0, &cbignum_pf, BN_SENSITIVE, "CBIGNUM"
++ASN1_ITEM_end(CBIGNUM)
++
++static int bn_new(ASN1_VALUE **pval, const ASN1_ITEM *it)
++{
++    *pval = (ASN1_VALUE *)BN_new();
++    if (*pval != NULL)
++        return 1;
++    else
++        return 0;
++}
++
++static int bn_secure_new(ASN1_VALUE **pval, const ASN1_ITEM *it)
++{
++    *pval = (ASN1_VALUE *)BN_secure_new();
++    if (*pval != NULL)
++        return 1;
++    else
++        return 0;
++}
++
++static void bn_free(ASN1_VALUE **pval, const ASN1_ITEM *it)
++{
++    if (!*pval)
++        return;
++    if (it->size & BN_SENSITIVE)
++        BN_clear_free((BIGNUM *)*pval);
++    else
++        BN_free((BIGNUM *)*pval);
++    *pval = NULL;
++}
++
++static int bn_i2c(ASN1_VALUE **pval, unsigned char *cont, int *putype,
++                  const ASN1_ITEM *it)
++{
++    BIGNUM *bn;
++    int pad;
++    if (!*pval)
++        return -1;
++    bn = (BIGNUM *)*pval;
++    /* If MSB set in an octet we need a padding byte */
++    if (BN_num_bits(bn) & 0x7)
++        pad = 0;
++    else
++        pad = 1;
++    if (cont) {
++        if (pad)
++            *cont++ = 0;
++        BN_bn2bin(bn, cont);
++    }
++    return pad + BN_num_bytes(bn);
++}
++
++static int bn_c2i(ASN1_VALUE **pval, const unsigned char *cont, int len,
++                  int utype, char *free_cont, const ASN1_ITEM *it)
++{
++    BIGNUM *bn;
++
++    if (*pval == NULL && !bn_new(pval, it))
++        return 0;
++    bn = (BIGNUM *)*pval;
++    if (!BN_bin2bn(cont, len, bn)) {
++        bn_free(pval, it);
++        return 0;
++    }
++    return 1;
++}
++
++static int bn_secure_c2i(ASN1_VALUE **pval, const unsigned char *cont, int len,
++                         int utype, char *free_cont, const ASN1_ITEM *it)
++{
++    if (!*pval)
++        bn_secure_new(pval, it);
++    return bn_c2i(pval, cont, len, utype, free_cont, it);
++}
++
++static int bn_print(BIO *out, ASN1_VALUE **pval, const ASN1_ITEM *it,
++                    int indent, const ASN1_PCTX *pctx)
++{
++    if (!BN_print(out, *(BIGNUM **)pval))
++        return 0;
++    if (BIO_puts(out, "\n") <= 0)
++        return 0;
++    return 1;
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/asn1/x_info.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/asn1/x_info.c
+new file mode 100644
+index 0000000..8d99f07
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/asn1/x_info.c
+@@ -0,0 +1,39 @@
++/*
++ * Copyright 1995-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include "internal/cryptlib.h"
++#include 
++#include 
++#include 
++
++X509_INFO *X509_INFO_new(void)
++{
++    X509_INFO *ret;
++
++    ret = OPENSSL_zalloc(sizeof(*ret));
++    if (ret == NULL) {
++        ASN1err(ASN1_F_X509_INFO_NEW, ERR_R_MALLOC_FAILURE);
++        return NULL;
++    }
++
++    return ret;
++}
++
++void X509_INFO_free(X509_INFO *x)
++{
++    if (x == NULL)
++        return;
++
++    X509_free(x->x509);
++    X509_CRL_free(x->crl);
++    X509_PKEY_free(x->x_pkey);
++    OPENSSL_free(x->enc_data);
++    OPENSSL_free(x);
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/asn1/x_long.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/asn1/x_long.c
+new file mode 100644
+index 0000000..c284471
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/asn1/x_long.c
+@@ -0,0 +1,146 @@
++/*
++ * Copyright 2000-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include "internal/cryptlib.h"
++#include 
++#include 
++
++/*
++ * Custom primitive type for long handling. This converts between an
++ * ASN1_INTEGER and a long directly.
++ */
++
++static int long_new(ASN1_VALUE **pval, const ASN1_ITEM *it);
++static void long_free(ASN1_VALUE **pval, const ASN1_ITEM *it);
++
++static int long_i2c(ASN1_VALUE **pval, unsigned char *cont, int *putype,
++                    const ASN1_ITEM *it);
++static int long_c2i(ASN1_VALUE **pval, const unsigned char *cont, int len,
++                    int utype, char *free_cont, const ASN1_ITEM *it);
++static int long_print(BIO *out, ASN1_VALUE **pval, const ASN1_ITEM *it,
++                      int indent, const ASN1_PCTX *pctx);
++
++static ASN1_PRIMITIVE_FUNCS long_pf = {
++    NULL, 0,
++    long_new,
++    long_free,
++    long_free,                  /* Clear should set to initial value */
++    long_c2i,
++    long_i2c,
++    long_print
++};
++
++ASN1_ITEM_start(LONG)
++        ASN1_ITYPE_PRIMITIVE, V_ASN1_INTEGER, NULL, 0, &long_pf, ASN1_LONG_UNDEF, "LONG"
++ASN1_ITEM_end(LONG)
++
++ASN1_ITEM_start(ZLONG)
++        ASN1_ITYPE_PRIMITIVE, V_ASN1_INTEGER, NULL, 0, &long_pf, 0, "ZLONG"
++ASN1_ITEM_end(ZLONG)
++
++static int long_new(ASN1_VALUE **pval, const ASN1_ITEM *it)
++{
++    *(long *)pval = it->size;
++    return 1;
++}
++
++static void long_free(ASN1_VALUE **pval, const ASN1_ITEM *it)
++{
++    *(long *)pval = it->size;
++}
++
++static int long_i2c(ASN1_VALUE **pval, unsigned char *cont, int *putype,
++                    const ASN1_ITEM *it)
++{
++    long ltmp;
++    unsigned long utmp;
++    int clen, pad, i;
++    /* this exists to bypass broken gcc optimization */
++    char *cp = (char *)pval;
++
++    /* use memcpy, because we may not be long aligned */
++    memcpy(<mp, cp, sizeof(long));
++
++    if (ltmp == it->size)
++        return -1;
++    /*
++     * Convert the long to positive: we subtract one if negative so we can
++     * cleanly handle the padding if only the MSB of the leading octet is
++     * set.
++     */
++    if (ltmp < 0)
++        utmp = 0 - (unsigned long)ltmp - 1;
++    else
++        utmp = ltmp;
++    clen = BN_num_bits_word(utmp);
++    /* If MSB of leading octet set we need to pad */
++    if (!(clen & 0x7))
++        pad = 1;
++    else
++        pad = 0;
++
++    /* Convert number of bits to number of octets */
++    clen = (clen + 7) >> 3;
++
++    if (cont) {
++        if (pad)
++            *cont++ = (ltmp < 0) ? 0xff : 0;
++        for (i = clen - 1; i >= 0; i--) {
++            cont[i] = (unsigned char)(utmp & 0xff);
++            if (ltmp < 0)
++                cont[i] ^= 0xff;
++            utmp >>= 8;
++        }
++    }
++    return clen + pad;
++}
++
++static int long_c2i(ASN1_VALUE **pval, const unsigned char *cont, int len,
++                    int utype, char *free_cont, const ASN1_ITEM *it)
++{
++    int neg, i;
++    long ltmp;
++    unsigned long utmp = 0;
++    char *cp = (char *)pval;
++    if (len > (int)sizeof(long)) {
++        ASN1err(ASN1_F_LONG_C2I, ASN1_R_INTEGER_TOO_LARGE_FOR_LONG);
++        return 0;
++    }
++    /* Is it negative? */
++    if (len && (cont[0] & 0x80))
++        neg = 1;
++    else
++        neg = 0;
++    utmp = 0;
++    for (i = 0; i < len; i++) {
++        utmp <<= 8;
++        if (neg)
++            utmp |= cont[i] ^ 0xff;
++        else
++            utmp |= cont[i];
++    }
++    ltmp = (long)utmp;
++    if (neg) {
++        ltmp = -ltmp;
++        ltmp--;
++    }
++    if (ltmp == it->size) {
++        ASN1err(ASN1_F_LONG_C2I, ASN1_R_INTEGER_TOO_LARGE_FOR_LONG);
++        return 0;
++    }
++    memcpy(cp, <mp, sizeof(long));
++    return 1;
++}
++
++static int long_print(BIO *out, ASN1_VALUE **pval, const ASN1_ITEM *it,
++                      int indent, const ASN1_PCTX *pctx)
++{
++    return BIO_printf(out, "%ld\n", *(long *)pval);
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/asn1/x_pkey.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/asn1/x_pkey.c
+new file mode 100644
+index 0000000..593049f
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/asn1/x_pkey.c
+@@ -0,0 +1,47 @@
++/*
++ * Copyright 1995-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include "internal/cryptlib.h"
++#include 
++#include 
++#include 
++
++X509_PKEY *X509_PKEY_new(void)
++{
++    X509_PKEY *ret = NULL;
++
++    ret = OPENSSL_zalloc(sizeof(*ret));
++    if (ret == NULL)
++        goto err;
++
++    ret->enc_algor = X509_ALGOR_new();
++    ret->enc_pkey = ASN1_OCTET_STRING_new();
++    if (ret->enc_algor == NULL || ret->enc_pkey == NULL)
++        goto err;
++
++    return ret;
++err:
++    X509_PKEY_free(ret);
++    ASN1err(ASN1_F_X509_PKEY_NEW, ERR_R_MALLOC_FAILURE);
++    return NULL;
++}
++
++void X509_PKEY_free(X509_PKEY *x)
++{
++    if (x == NULL)
++        return;
++
++    X509_ALGOR_free(x->enc_algor);
++    ASN1_OCTET_STRING_free(x->enc_pkey);
++    EVP_PKEY_free(x->dec_pkey);
++    if (x->key_free)
++        OPENSSL_free(x->key_data);
++    OPENSSL_free(x);
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/asn1/x_sig.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/asn1/x_sig.c
+new file mode 100644
+index 0000000..e465cf2
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/asn1/x_sig.c
+@@ -0,0 +1,39 @@
++/*
++ * Copyright 1995-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include "internal/cryptlib.h"
++#include 
++#include 
++#include "internal/x509_int.h"
++
++ASN1_SEQUENCE(X509_SIG) = {
++        ASN1_SIMPLE(X509_SIG, algor, X509_ALGOR),
++        ASN1_SIMPLE(X509_SIG, digest, ASN1_OCTET_STRING)
++} ASN1_SEQUENCE_END(X509_SIG)
++
++IMPLEMENT_ASN1_FUNCTIONS(X509_SIG)
++
++void X509_SIG_get0(const X509_SIG *sig, const X509_ALGOR **palg,
++                   const ASN1_OCTET_STRING **pdigest)
++{
++    if (palg)
++        *palg = sig->algor;
++    if (pdigest)
++        *pdigest = sig->digest;
++}
++
++void X509_SIG_getm(X509_SIG *sig, X509_ALGOR **palg,
++                   ASN1_OCTET_STRING **pdigest)
++{
++    if (palg)
++        *palg = sig->algor;
++    if (pdigest)
++        *pdigest = sig->digest;
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/asn1/x_spki.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/asn1/x_spki.c
+new file mode 100644
+index 0000000..c45400b
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/asn1/x_spki.c
+@@ -0,0 +1,33 @@
++/*
++ * Copyright 1995-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++ /*
++  * This module was send to me my Pat Richards  who wrote it.
++  * It is under my Copyright with his permission
++  */
++
++#include 
++#include "internal/cryptlib.h"
++#include 
++#include 
++
++ASN1_SEQUENCE(NETSCAPE_SPKAC) = {
++        ASN1_SIMPLE(NETSCAPE_SPKAC, pubkey, X509_PUBKEY),
++        ASN1_SIMPLE(NETSCAPE_SPKAC, challenge, ASN1_IA5STRING)
++} ASN1_SEQUENCE_END(NETSCAPE_SPKAC)
++
++IMPLEMENT_ASN1_FUNCTIONS(NETSCAPE_SPKAC)
++
++ASN1_SEQUENCE(NETSCAPE_SPKI) = {
++        ASN1_SIMPLE(NETSCAPE_SPKI, spkac, NETSCAPE_SPKAC),
++        ASN1_EMBED(NETSCAPE_SPKI, sig_algor, X509_ALGOR),
++        ASN1_SIMPLE(NETSCAPE_SPKI, signature, ASN1_BIT_STRING)
++} ASN1_SEQUENCE_END(NETSCAPE_SPKI)
++
++IMPLEMENT_ASN1_FUNCTIONS(NETSCAPE_SPKI)
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/asn1/x_val.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/asn1/x_val.c
+new file mode 100644
+index 0000000..d1f1d3b
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/asn1/x_val.c
+@@ -0,0 +1,20 @@
++/*
++ * Copyright 1995-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include "internal/cryptlib.h"
++#include 
++#include 
++
++ASN1_SEQUENCE(X509_VAL) = {
++        ASN1_SIMPLE(X509_VAL, notBefore, ASN1_TIME),
++        ASN1_SIMPLE(X509_VAL, notAfter, ASN1_TIME)
++} ASN1_SEQUENCE_END(X509_VAL)
++
++IMPLEMENT_ASN1_FUNCTIONS(X509_VAL)
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/async/arch/async_null.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/async/arch/async_null.c
+new file mode 100644
+index 0000000..3eaf170
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/async/arch/async_null.c
+@@ -0,0 +1,23 @@
++/*
++ * Copyright 2015-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++/* This must be the first #include file */
++#include "../async_locl.h"
++
++#ifdef ASYNC_NULL
++int ASYNC_is_capable(void)
++{
++    return 0;
++}
++
++void async_local_cleanup(void)
++{
++}
++#endif
++
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/async/arch/async_null.h b/CryptoPkg/Library/OpensslLib/openssl/crypto/async/arch/async_null.h
+new file mode 100644
+index 0000000..aef40b5
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/async/arch/async_null.h
+@@ -0,0 +1,30 @@
++/*
++ * Copyright 2015-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++
++/*
++ * If we haven't managed to detect any other async architecture then we default
++ * to NULL.
++ */
++#ifndef ASYNC_ARCH
++# define ASYNC_NULL
++# define ASYNC_ARCH
++
++typedef struct async_fibre_st {
++    int dummy;
++} async_fibre;
++
++
++# define async_fibre_swapcontext(o,n,r)         0
++# define async_fibre_makecontext(c)             0
++# define async_fibre_free(f)
++# define async_fibre_init_dispatcher(f)
++
++#endif
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/async/arch/async_posix.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/async/arch/async_posix.c
+new file mode 100644
+index 0000000..02c342d
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/async/arch/async_posix.c
+@@ -0,0 +1,58 @@
++/*
++ * Copyright 2015-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++/* This must be the first #include file */
++#include "../async_locl.h"
++
++#ifdef ASYNC_POSIX
++
++# include 
++# include 
++
++#define STACKSIZE       32768
++
++int ASYNC_is_capable(void)
++{
++    ucontext_t ctx;
++
++    /*
++     * Some platforms provide getcontext() but it does not work (notably
++     * MacOSX PPC64). Check for a working getcontext();
++     */
++    return getcontext(&ctx) == 0;
++}
++
++void async_local_cleanup(void)
++{
++}
++
++int async_fibre_makecontext(async_fibre *fibre)
++{
++    fibre->env_init = 0;
++    if (getcontext(&fibre->fibre) == 0) {
++        fibre->fibre.uc_stack.ss_sp = OPENSSL_malloc(STACKSIZE);
++        if (fibre->fibre.uc_stack.ss_sp != NULL) {
++            fibre->fibre.uc_stack.ss_size = STACKSIZE;
++            fibre->fibre.uc_link = NULL;
++            makecontext(&fibre->fibre, async_start_func, 0);
++            return 1;
++        }
++    } else {
++        fibre->fibre.uc_stack.ss_sp = NULL;
++    }
++    return 0;
++}
++
++void async_fibre_free(async_fibre *fibre)
++{
++    OPENSSL_free(fibre->fibre.uc_stack.ss_sp);
++    fibre->fibre.uc_stack.ss_sp = NULL;
++}
++
++#endif
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/async/arch/async_posix.h b/CryptoPkg/Library/OpensslLib/openssl/crypto/async/arch/async_posix.h
+new file mode 100644
+index 0000000..3c61f7f
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/async/arch/async_posix.h
+@@ -0,0 +1,58 @@
++/*
++ * Copyright 2015-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#ifndef OPENSSL_ASYNC_ARCH_ASYNC_POSIX_H
++#define OPENSSL_ASYNC_ARCH_ASYNC_POSIX_H
++#include 
++
++#if (defined(OPENSSL_SYS_UNIX) || defined(OPENSSL_SYS_CYGWIN)) \
++    && defined(OPENSSL_THREADS) && !defined(OPENSSL_NO_ASYNC) \
++    && !defined(__ANDROID__) && !defined(__OpenBSD__)
++
++# include 
++
++# if _POSIX_VERSION >= 200112L
++
++# include 
++
++#  define ASYNC_POSIX
++#  define ASYNC_ARCH
++
++#  include 
++#  include 
++#  include "e_os.h"
++
++typedef struct async_fibre_st {
++    ucontext_t fibre;
++    jmp_buf env;
++    int env_init;
++} async_fibre;
++
++static ossl_inline int async_fibre_swapcontext(async_fibre *o, async_fibre *n, int r)
++{
++    o->env_init = 1;
++
++    if (!r || !_setjmp(o->env)) {
++        if (n->env_init)
++            _longjmp(n->env, 1);
++        else
++            setcontext(&n->fibre);
++    }
++
++    return 1;
++}
++
++#  define async_fibre_init_dispatcher(d)
++
++int async_fibre_makecontext(async_fibre *fibre);
++void async_fibre_free(async_fibre *fibre);
++
++# endif
++#endif
++#endif /* OPENSSL_ASYNC_ARCH_ASYNC_POSIX_H */
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/async/arch/async_win.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/async/arch/async_win.c
+new file mode 100644
+index 0000000..077d56c
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/async/arch/async_win.c
+@@ -0,0 +1,55 @@
++/*
++ * Copyright 2015-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++/* This must be the first #include file */
++#include "../async_locl.h"
++
++#ifdef ASYNC_WIN
++
++# include 
++# include "internal/cryptlib.h"
++
++int ASYNC_is_capable(void)
++{
++    return 1;
++}
++
++void async_local_cleanup(void)
++{
++    async_ctx *ctx = async_get_ctx();
++    if (ctx != NULL) {
++        async_fibre *fibre = &ctx->dispatcher;
++        if (fibre != NULL && fibre->fibre != NULL && fibre->converted) {
++            ConvertFiberToThread();
++            fibre->fibre = NULL;
++        }
++    }
++}
++
++int async_fibre_init_dispatcher(async_fibre *fibre)
++{
++    fibre->fibre = ConvertThreadToFiber(NULL);
++    if (fibre->fibre == NULL) {
++        fibre->converted = 0;
++        fibre->fibre = GetCurrentFiber();
++        if (fibre->fibre == NULL)
++            return 0;
++    } else {
++        fibre->converted = 1;
++    }
++
++    return 1;
++}
++
++VOID CALLBACK async_start_func_win(PVOID unused)
++{
++    async_start_func();
++}
++
++#endif
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/async/arch/async_win.h b/CryptoPkg/Library/OpensslLib/openssl/crypto/async/arch/async_win.h
+new file mode 100644
+index 0000000..61cfdd7
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/async/arch/async_win.h
+@@ -0,0 +1,36 @@
++/*
++ * Copyright 2015-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++/*
++ * This is the same detection used in cryptlib to set up the thread local
++ * storage that we depend on, so just copy that
++ */
++#if defined(_WIN32) && !defined(OPENSSL_NO_ASYNC)
++#include 
++# define ASYNC_WIN
++# define ASYNC_ARCH
++
++# include 
++# include "internal/cryptlib.h"
++
++typedef struct async_fibre_st {
++    LPVOID fibre;
++    int converted;
++} async_fibre;
++
++# define async_fibre_swapcontext(o,n,r) \
++        (SwitchToFiber((n)->fibre), 1)
++# define async_fibre_makecontext(c) \
++        ((c)->fibre = CreateFiber(0, async_start_func_win, 0))
++# define async_fibre_free(f)             (DeleteFiber((f)->fibre))
++
++int async_fibre_init_dispatcher(async_fibre *fibre);
++VOID CALLBACK async_start_func_win(PVOID unused);
++
++#endif
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/async/async.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/async/async.c
+new file mode 100644
+index 0000000..8c699af
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/async/async.c
+@@ -0,0 +1,433 @@
++/*
++ * Copyright 2015-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++/*
++ * Without this we start getting longjmp crashes because it thinks we're jumping
++ * up the stack when in fact we are jumping to an entirely different stack. The
++ * cost of this is not having certain buffer overrun/underrun checks etc for
++ * this source file :-(
++ */
++#undef _FORTIFY_SOURCE
++
++/* This must be the first #include file */
++#include "async_locl.h"
++
++#include 
++#include 
++#include 
++
++#define ASYNC_JOB_RUNNING   0
++#define ASYNC_JOB_PAUSING   1
++#define ASYNC_JOB_PAUSED    2
++#define ASYNC_JOB_STOPPING  3
++
++static CRYPTO_THREAD_LOCAL ctxkey;
++static CRYPTO_THREAD_LOCAL poolkey;
++
++static void async_free_pool_internal(async_pool *pool);
++
++static async_ctx *async_ctx_new(void)
++{
++    async_ctx *nctx = NULL;
++
++    nctx = OPENSSL_malloc(sizeof (async_ctx));
++    if (nctx == NULL) {
++        ASYNCerr(ASYNC_F_ASYNC_CTX_NEW, ERR_R_MALLOC_FAILURE);
++        goto err;
++    }
++
++    async_fibre_init_dispatcher(&nctx->dispatcher);
++    nctx->currjob = NULL;
++    nctx->blocked = 0;
++    if (!CRYPTO_THREAD_set_local(&ctxkey, nctx))
++        goto err;
++
++    return nctx;
++err:
++    OPENSSL_free(nctx);
++
++    return NULL;
++}
++
++async_ctx *async_get_ctx(void)
++{
++    if (!OPENSSL_init_crypto(OPENSSL_INIT_ASYNC, NULL))
++        return NULL;
++
++    return (async_ctx *)CRYPTO_THREAD_get_local(&ctxkey);
++}
++
++static int async_ctx_free(void)
++{
++    async_ctx *ctx;
++
++    ctx = async_get_ctx();
++
++    if (!CRYPTO_THREAD_set_local(&ctxkey, NULL))
++        return 0;
++
++    OPENSSL_free(ctx);
++
++    return 1;
++}
++
++static ASYNC_JOB *async_job_new(void)
++{
++    ASYNC_JOB *job = NULL;
++
++    job = OPENSSL_zalloc(sizeof (ASYNC_JOB));
++    if (job == NULL) {
++        ASYNCerr(ASYNC_F_ASYNC_JOB_NEW, ERR_R_MALLOC_FAILURE);
++        return NULL;
++    }
++
++    job->status = ASYNC_JOB_RUNNING;
++
++    return job;
++}
++
++static void async_job_free(ASYNC_JOB *job)
++{
++    if (job != NULL) {
++        OPENSSL_free(job->funcargs);
++        async_fibre_free(&job->fibrectx);
++        OPENSSL_free(job);
++    }
++}
++
++static ASYNC_JOB *async_get_pool_job(void) {
++    ASYNC_JOB *job;
++    async_pool *pool;
++
++    pool = (async_pool *)CRYPTO_THREAD_get_local(&poolkey);
++    if (pool == NULL) {
++        /*
++         * Pool has not been initialised, so init with the defaults, i.e.
++         * no max size and no pre-created jobs
++         */
++        if (ASYNC_init_thread(0, 0) == 0)
++            return NULL;
++        pool = (async_pool *)CRYPTO_THREAD_get_local(&poolkey);
++    }
++
++    job = sk_ASYNC_JOB_pop(pool->jobs);
++    if (job == NULL) {
++        /* Pool is empty */
++        if ((pool->max_size != 0) && (pool->curr_size >= pool->max_size))
++            return NULL;
++
++        job = async_job_new();
++        if (job != NULL) {
++            if (! async_fibre_makecontext(&job->fibrectx)) {
++                async_job_free(job);
++                return NULL;
++            }
++            pool->curr_size++;
++        }
++    }
++    return job;
++}
++
++static void async_release_job(ASYNC_JOB *job) {
++    async_pool *pool;
++
++    pool = (async_pool *)CRYPTO_THREAD_get_local(&poolkey);
++    OPENSSL_free(job->funcargs);
++    job->funcargs = NULL;
++    sk_ASYNC_JOB_push(pool->jobs, job);
++}
++
++void async_start_func(void)
++{
++    ASYNC_JOB *job;
++    async_ctx *ctx = async_get_ctx();
++
++    while (1) {
++        /* Run the job */
++        job = ctx->currjob;
++        job->ret = job->func(job->funcargs);
++
++        /* Stop the job */
++        job->status = ASYNC_JOB_STOPPING;
++        if (!async_fibre_swapcontext(&job->fibrectx,
++                                     &ctx->dispatcher, 1)) {
++            /*
++             * Should not happen. Getting here will close the thread...can't do
++             * much about it
++             */
++            ASYNCerr(ASYNC_F_ASYNC_START_FUNC, ASYNC_R_FAILED_TO_SWAP_CONTEXT);
++        }
++    }
++}
++
++int ASYNC_start_job(ASYNC_JOB **job, ASYNC_WAIT_CTX *wctx, int *ret,
++                    int (*func)(void *), void *args, size_t size)
++{
++    async_ctx *ctx = async_get_ctx();
++    if (ctx == NULL)
++        ctx = async_ctx_new();
++    if (ctx == NULL) {
++        return ASYNC_ERR;
++    }
++
++    if (*job) {
++        ctx->currjob = *job;
++    }
++
++    for (;;) {
++        if (ctx->currjob != NULL) {
++            if (ctx->currjob->status == ASYNC_JOB_STOPPING) {
++                *ret = ctx->currjob->ret;
++                ctx->currjob->waitctx = NULL;
++                async_release_job(ctx->currjob);
++                ctx->currjob = NULL;
++                *job = NULL;
++                return ASYNC_FINISH;
++            }
++
++            if (ctx->currjob->status == ASYNC_JOB_PAUSING) {
++                *job = ctx->currjob;
++                ctx->currjob->status = ASYNC_JOB_PAUSED;
++                ctx->currjob = NULL;
++                return ASYNC_PAUSE;
++            }
++
++            if (ctx->currjob->status == ASYNC_JOB_PAUSED) {
++                ctx->currjob = *job;
++                /* Resume previous job */
++                if (!async_fibre_swapcontext(&ctx->dispatcher,
++                        &ctx->currjob->fibrectx, 1)) {
++                    ASYNCerr(ASYNC_F_ASYNC_START_JOB,
++                             ASYNC_R_FAILED_TO_SWAP_CONTEXT);
++                    goto err;
++                }
++                continue;
++            }
++
++            /* Should not happen */
++            ASYNCerr(ASYNC_F_ASYNC_START_JOB, ERR_R_INTERNAL_ERROR);
++            async_release_job(ctx->currjob);
++            ctx->currjob = NULL;
++            *job = NULL;
++            return ASYNC_ERR;
++        }
++
++        /* Start a new job */
++        if ((ctx->currjob = async_get_pool_job()) == NULL) {
++            return ASYNC_NO_JOBS;
++        }
++
++        if (args != NULL) {
++            ctx->currjob->funcargs = OPENSSL_malloc(size);
++            if (ctx->currjob->funcargs == NULL) {
++                ASYNCerr(ASYNC_F_ASYNC_START_JOB, ERR_R_MALLOC_FAILURE);
++                async_release_job(ctx->currjob);
++                ctx->currjob = NULL;
++                return ASYNC_ERR;
++            }
++            memcpy(ctx->currjob->funcargs, args, size);
++        } else {
++            ctx->currjob->funcargs = NULL;
++        }
++
++        ctx->currjob->func = func;
++        ctx->currjob->waitctx = wctx;
++        if (!async_fibre_swapcontext(&ctx->dispatcher,
++                &ctx->currjob->fibrectx, 1)) {
++            ASYNCerr(ASYNC_F_ASYNC_START_JOB, ASYNC_R_FAILED_TO_SWAP_CONTEXT);
++            goto err;
++        }
++    }
++
++err:
++    async_release_job(ctx->currjob);
++    ctx->currjob = NULL;
++    *job = NULL;
++    return ASYNC_ERR;
++}
++
++int ASYNC_pause_job(void)
++{
++    ASYNC_JOB *job;
++    async_ctx *ctx = async_get_ctx();
++
++    if (ctx == NULL
++            || ctx->currjob == NULL
++            || ctx->blocked) {
++        /*
++         * Could be we've deliberately not been started within a job so this is
++         * counted as success.
++         */
++        return 1;
++    }
++
++    job = ctx->currjob;
++    job->status = ASYNC_JOB_PAUSING;
++
++    if (!async_fibre_swapcontext(&job->fibrectx,
++                                 &ctx->dispatcher, 1)) {
++        ASYNCerr(ASYNC_F_ASYNC_PAUSE_JOB, ASYNC_R_FAILED_TO_SWAP_CONTEXT);
++        return 0;
++    }
++    /* Reset counts of added and deleted fds */
++    async_wait_ctx_reset_counts(job->waitctx);
++
++    return 1;
++}
++
++static void async_empty_pool(async_pool *pool)
++{
++    ASYNC_JOB *job;
++
++    if (!pool || !pool->jobs)
++        return;
++
++    do {
++        job = sk_ASYNC_JOB_pop(pool->jobs);
++        async_job_free(job);
++    } while (job);
++}
++
++int async_init(void)
++{
++    if (!CRYPTO_THREAD_init_local(&ctxkey, NULL))
++        return 0;
++
++    if (!CRYPTO_THREAD_init_local(&poolkey, NULL)) {
++        CRYPTO_THREAD_cleanup_local(&ctxkey);
++        return 0;
++    }
++
++    return 1;
++}
++
++void async_deinit(void)
++{
++    CRYPTO_THREAD_cleanup_local(&ctxkey);
++    CRYPTO_THREAD_cleanup_local(&poolkey);
++}
++
++int ASYNC_init_thread(size_t max_size, size_t init_size)
++{
++    async_pool *pool;
++    size_t curr_size = 0;
++
++    if (init_size > max_size) {
++        ASYNCerr(ASYNC_F_ASYNC_INIT_THREAD, ASYNC_R_INVALID_POOL_SIZE);
++        return 0;
++    }
++
++    if (!OPENSSL_init_crypto(OPENSSL_INIT_ASYNC, NULL)) {
++        return 0;
++    }
++    if (!ossl_init_thread_start(OPENSSL_INIT_THREAD_ASYNC)) {
++        return 0;
++    }
++
++    pool = OPENSSL_zalloc(sizeof *pool);
++    if (pool == NULL) {
++        ASYNCerr(ASYNC_F_ASYNC_INIT_THREAD, ERR_R_MALLOC_FAILURE);
++        return 0;
++    }
++
++    pool->jobs = sk_ASYNC_JOB_new_null();
++    if (pool->jobs == NULL) {
++        ASYNCerr(ASYNC_F_ASYNC_INIT_THREAD, ERR_R_MALLOC_FAILURE);
++        OPENSSL_free(pool);
++        return 0;
++    }
++
++    pool->max_size = max_size;
++
++    /* Pre-create jobs as required */
++    while (init_size--) {
++        ASYNC_JOB *job;
++        job = async_job_new();
++        if (job == NULL || !async_fibre_makecontext(&job->fibrectx)) {
++            /*
++             * Not actually fatal because we already created the pool, just
++             * skip creation of any more jobs
++             */
++            async_job_free(job);
++            break;
++        }
++        job->funcargs = NULL;
++        sk_ASYNC_JOB_push(pool->jobs, job);
++        curr_size++;
++    }
++    pool->curr_size = curr_size;
++    if (!CRYPTO_THREAD_set_local(&poolkey, pool)) {
++        ASYNCerr(ASYNC_F_ASYNC_INIT_THREAD, ASYNC_R_FAILED_TO_SET_POOL);
++        goto err;
++    }
++
++    return 1;
++err:
++    async_free_pool_internal(pool);
++    return 0;
++}
++
++static void async_free_pool_internal(async_pool *pool)
++{
++    if (pool == NULL)
++        return;
++
++    async_empty_pool(pool);
++    sk_ASYNC_JOB_free(pool->jobs);
++    OPENSSL_free(pool);
++    CRYPTO_THREAD_set_local(&poolkey, NULL);
++    async_local_cleanup();
++    async_ctx_free();
++}
++
++void ASYNC_cleanup_thread(void)
++{
++    async_free_pool_internal((async_pool *)CRYPTO_THREAD_get_local(&poolkey));
++}
++
++ASYNC_JOB *ASYNC_get_current_job(void)
++{
++    async_ctx *ctx;
++
++    ctx = async_get_ctx();
++    if (ctx == NULL)
++        return NULL;
++
++    return ctx->currjob;
++}
++
++ASYNC_WAIT_CTX *ASYNC_get_wait_ctx(ASYNC_JOB *job)
++{
++    return job->waitctx;
++}
++
++void ASYNC_block_pause(void)
++{
++    async_ctx *ctx = async_get_ctx();
++    if (ctx == NULL || ctx->currjob == NULL) {
++        /*
++         * We're not in a job anyway so ignore this
++         */
++        return;
++    }
++    ctx->blocked++;
++}
++
++void ASYNC_unblock_pause(void)
++{
++    async_ctx *ctx = async_get_ctx();
++    if (ctx == NULL || ctx->currjob == NULL) {
++        /*
++         * We're not in a job anyway so ignore this
++         */
++        return;
++    }
++    if (ctx->blocked > 0)
++        ctx->blocked--;
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/async/async_err.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/async/async_err.c
+new file mode 100644
+index 0000000..ae97e96
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/async/async_err.c
+@@ -0,0 +1,51 @@
++/*
++ * Generated by util/mkerr.pl DO NOT EDIT
++ * Copyright 1995-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include 
++#include 
++
++/* BEGIN ERROR CODES */
++#ifndef OPENSSL_NO_ERR
++
++# define ERR_FUNC(func) ERR_PACK(ERR_LIB_ASYNC,func,0)
++# define ERR_REASON(reason) ERR_PACK(ERR_LIB_ASYNC,0,reason)
++
++static ERR_STRING_DATA ASYNC_str_functs[] = {
++    {ERR_FUNC(ASYNC_F_ASYNC_CTX_NEW), "async_ctx_new"},
++    {ERR_FUNC(ASYNC_F_ASYNC_INIT_THREAD), "ASYNC_init_thread"},
++    {ERR_FUNC(ASYNC_F_ASYNC_JOB_NEW), "async_job_new"},
++    {ERR_FUNC(ASYNC_F_ASYNC_PAUSE_JOB), "ASYNC_pause_job"},
++    {ERR_FUNC(ASYNC_F_ASYNC_START_FUNC), "async_start_func"},
++    {ERR_FUNC(ASYNC_F_ASYNC_START_JOB), "ASYNC_start_job"},
++    {0, NULL}
++};
++
++static ERR_STRING_DATA ASYNC_str_reasons[] = {
++    {ERR_REASON(ASYNC_R_FAILED_TO_SET_POOL), "failed to set pool"},
++    {ERR_REASON(ASYNC_R_FAILED_TO_SWAP_CONTEXT), "failed to swap context"},
++    {ERR_REASON(ASYNC_R_INIT_FAILED), "init failed"},
++    {ERR_REASON(ASYNC_R_INVALID_POOL_SIZE), "invalid pool size"},
++    {0, NULL}
++};
++
++#endif
++
++int ERR_load_ASYNC_strings(void)
++{
++#ifndef OPENSSL_NO_ERR
++
++    if (ERR_func_error_string(ASYNC_str_functs[0].error) == NULL) {
++        ERR_load_strings(0, ASYNC_str_functs);
++        ERR_load_strings(0, ASYNC_str_reasons);
++    }
++#endif
++    return 1;
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/async/async_locl.h b/CryptoPkg/Library/OpensslLib/openssl/crypto/async/async_locl.h
+new file mode 100644
+index 0000000..f0ac05a
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/async/async_locl.h
+@@ -0,0 +1,77 @@
++/*
++ * Copyright 2015-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++/*
++ * Must do this before including any header files, because on MacOS/X 
++ * includes  which includes 
++ */
++#if defined(__APPLE__) && defined(__MACH__) && !defined(_XOPEN_SOURCE)
++# define _XOPEN_SOURCE          /* Otherwise incomplete ucontext_t structure */
++# pragma GCC diagnostic ignored "-Wdeprecated-declarations"
++#endif
++
++#if defined(_WIN32)
++# include 
++#endif
++
++#include 
++#include 
++
++typedef struct async_ctx_st async_ctx;
++typedef struct async_pool_st async_pool;
++
++#include "arch/async_win.h"
++#include "arch/async_posix.h"
++#include "arch/async_null.h"
++
++struct async_ctx_st {
++    async_fibre dispatcher;
++    ASYNC_JOB *currjob;
++    unsigned int blocked;
++};
++
++struct async_job_st {
++    async_fibre fibrectx;
++    int (*func) (void *);
++    void *funcargs;
++    int ret;
++    int status;
++    ASYNC_WAIT_CTX *waitctx;
++};
++
++struct fd_lookup_st {
++    const void *key;
++    OSSL_ASYNC_FD fd;
++    void *custom_data;
++    void (*cleanup)(ASYNC_WAIT_CTX *, const void *, OSSL_ASYNC_FD, void *);
++    int add;
++    int del;
++    struct fd_lookup_st *next;
++};
++
++struct async_wait_ctx_st {
++    struct fd_lookup_st *fds;
++    size_t numadd;
++    size_t numdel;
++};
++
++DEFINE_STACK_OF(ASYNC_JOB)
++
++struct async_pool_st {
++    STACK_OF(ASYNC_JOB) *jobs;
++    size_t curr_size;
++    size_t max_size;
++};
++
++void async_local_cleanup(void);
++void async_start_func(void);
++async_ctx *async_get_ctx(void);
++
++void async_wait_ctx_reset_counts(ASYNC_WAIT_CTX *ctx);
++
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/async/async_wait.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/async/async_wait.c
+new file mode 100644
+index 0000000..e115985
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/async/async_wait.c
+@@ -0,0 +1,211 @@
++/*
++ * Copyright 2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++/* This must be the first #include file */
++#include "async_locl.h"
++
++#include 
++
++ASYNC_WAIT_CTX *ASYNC_WAIT_CTX_new(void)
++{
++    return OPENSSL_zalloc(sizeof(ASYNC_WAIT_CTX));
++}
++
++void ASYNC_WAIT_CTX_free(ASYNC_WAIT_CTX *ctx)
++{
++    struct fd_lookup_st *curr;
++    struct fd_lookup_st *next;
++
++    if (ctx == NULL)
++        return;
++
++    curr = ctx->fds;
++    while (curr != NULL) {
++        if (!curr->del) {
++            /* Only try and cleanup if it hasn't been marked deleted */
++            if (curr->cleanup != NULL)
++                curr->cleanup(ctx, curr->key, curr->fd, curr->custom_data);
++        }
++        /* Always free the fd_lookup_st */
++        next = curr->next;
++        OPENSSL_free(curr);
++        curr = next;
++    }
++
++    OPENSSL_free(ctx);
++}
++int ASYNC_WAIT_CTX_set_wait_fd(ASYNC_WAIT_CTX *ctx, const void *key,
++                               OSSL_ASYNC_FD fd, void *custom_data,
++                               void (*cleanup)(ASYNC_WAIT_CTX *, const void *,
++                                               OSSL_ASYNC_FD, void *))
++{
++    struct fd_lookup_st *fdlookup;
++
++    fdlookup = OPENSSL_zalloc(sizeof *fdlookup);
++    if (fdlookup == NULL)
++        return 0;
++
++    fdlookup->key = key;
++    fdlookup->fd = fd;
++    fdlookup->custom_data = custom_data;
++    fdlookup->cleanup = cleanup;
++    fdlookup->add = 1;
++    fdlookup->next = ctx->fds;
++    ctx->fds = fdlookup;
++    ctx->numadd++;
++    return 1;
++}
++
++int ASYNC_WAIT_CTX_get_fd(ASYNC_WAIT_CTX *ctx, const void *key,
++                          OSSL_ASYNC_FD *fd, void **custom_data)
++{
++    struct fd_lookup_st *curr;
++
++    curr = ctx->fds;
++    while (curr != NULL) {
++        if (curr->del) {
++            /* This one has been marked deleted so do nothing */
++            curr = curr->next;
++            continue;
++        }
++        if (curr->key == key) {
++            *fd = curr->fd;
++            *custom_data = curr->custom_data;
++            return 1;
++        }
++        curr = curr->next;
++    }
++    return 0;
++}
++
++int ASYNC_WAIT_CTX_get_all_fds(ASYNC_WAIT_CTX *ctx, OSSL_ASYNC_FD *fd,
++                               size_t *numfds)
++{
++    struct fd_lookup_st *curr;
++
++    curr = ctx->fds;
++    *numfds = 0;
++    while (curr != NULL) {
++        if (curr->del) {
++            /* This one has been marked deleted so do nothing */
++            curr = curr->next;
++            continue;
++        }
++        if (fd != NULL) {
++            *fd = curr->fd;
++            fd++;
++        }
++        (*numfds)++;
++        curr = curr->next;
++    }
++    return 1;
++}
++
++int ASYNC_WAIT_CTX_get_changed_fds(ASYNC_WAIT_CTX *ctx, OSSL_ASYNC_FD *addfd,
++                                   size_t *numaddfds, OSSL_ASYNC_FD *delfd,
++                                   size_t *numdelfds)
++{
++    struct fd_lookup_st *curr;
++
++    *numaddfds = ctx->numadd;
++    *numdelfds = ctx->numdel;
++    if (addfd == NULL && delfd == NULL)
++        return 1;
++
++    curr = ctx->fds;
++
++    while (curr != NULL) {
++        /* We ignore fds that have been marked as both added and deleted */
++        if (curr->del && !curr->add && (delfd != NULL)) {
++            *delfd = curr->fd;
++            delfd++;
++        }
++        if (curr->add && !curr->del && (addfd != NULL)) {
++            *addfd = curr->fd;
++            addfd++;
++        }
++        curr = curr->next;
++    }
++
++    return 1;
++}
++
++int ASYNC_WAIT_CTX_clear_fd(ASYNC_WAIT_CTX *ctx, const void *key)
++{
++    struct fd_lookup_st *curr, *prev;
++
++    curr = ctx->fds;
++    prev = NULL;
++    while (curr != NULL) {
++        if (curr->del == 1) {
++            /* This one has been marked deleted already so do nothing */
++            curr = curr->next;
++            continue;
++        }
++        if (curr->key == key) {
++            /* If fd has just been added, remove it from the list */
++            if (curr->add == 1) {
++                if (ctx->fds == curr) {
++                    ctx->fds = curr->next;
++                } else {
++                    prev->next = curr->next;
++                }
++
++                /* It is responsibility of the caller to cleanup before calling
++                 * ASYNC_WAIT_CTX_clear_fd
++                 */
++                OPENSSL_free(curr);
++                ctx->numadd--;
++                return 1;
++            }
++
++            /*
++             * Mark it as deleted. We don't call cleanup if explicitly asked
++             * to clear an fd. We assume the caller is going to do that (if
++             * appropriate).
++             */
++            curr->del = 1;
++            ctx->numdel++;
++            return 1;
++        }
++        prev = curr;
++        curr = curr->next;
++    }
++    return 0;
++}
++
++void async_wait_ctx_reset_counts(ASYNC_WAIT_CTX *ctx)
++{
++    struct fd_lookup_st *curr, *prev = NULL;
++
++    ctx->numadd = 0;
++    ctx->numdel = 0;
++
++    curr = ctx->fds;
++
++    while (curr != NULL) {
++        if (curr->del) {
++            if (prev == NULL)
++                ctx->fds = curr->next;
++            else
++                prev->next = curr->next;
++            OPENSSL_free(curr);
++            if (prev == NULL)
++                curr = ctx->fds;
++            else
++                curr = prev->next;
++            continue;
++        }
++        if (curr->add) {
++            curr->add = 0;
++        }
++        prev = curr;
++        curr = curr->next;
++    }
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/async/build.info b/CryptoPkg/Library/OpensslLib/openssl/crypto/async/build.info
+new file mode 100644
+index 0000000..278e3e9
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/async/build.info
+@@ -0,0 +1,4 @@
++LIBS=../../libcrypto
++SOURCE[../../libcrypto]=\
++        async.c async_wait.c async_err.c arch/async_posix.c arch/async_win.c \
++        arch/async_null.c
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/bf/asm/bf-586.pl b/CryptoPkg/Library/OpensslLib/openssl/crypto/bf/asm/bf-586.pl
+new file mode 100644
+index 0000000..ebc24f4
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/bf/asm/bf-586.pl
+@@ -0,0 +1,149 @@
++#! /usr/bin/env perl
++# Copyright 1995-2016 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
++# in the file LICENSE in the source distribution or at
++# https://www.openssl.org/source/license.html
++
++
++$0 =~ m/(.*[\/\\])[^\/\\]+$/; $dir=$1;
++push(@INC,"${dir}","${dir}../../perlasm");
++require "x86asm.pl";
++require "cbc.pl";
++
++$output = pop;
++open STDOUT,">$output";
++
++&asm_init($ARGV[0],"bf-586.pl",$ARGV[$#ARGV] eq "386");
++
++$BF_ROUNDS=16;
++$BF_OFF=($BF_ROUNDS+2)*4;
++$L="edi";
++$R="esi";
++$P="ebp";
++$tmp1="eax";
++$tmp2="ebx";
++$tmp3="ecx";
++$tmp4="edx";
++
++&BF_encrypt("BF_encrypt",1);
++&BF_encrypt("BF_decrypt",0);
++&cbc("BF_cbc_encrypt","BF_encrypt","BF_decrypt",1,4,5,3,-1,-1);
++&asm_finish();
++
++close STDOUT;
++
++sub BF_encrypt
++	{
++	local($name,$enc)=@_;
++
++	&function_begin_B($name,"");
++
++	&comment("");
++
++	&push("ebp");
++	&push("ebx");
++	&mov($tmp2,&wparam(0));
++	&mov($P,&wparam(1));
++	&push("esi");
++	&push("edi");
++
++	&comment("Load the 2 words");
++	&mov($L,&DWP(0,$tmp2,"",0));
++	&mov($R,&DWP(4,$tmp2,"",0));
++
++	&xor(	$tmp1,	$tmp1);
++
++	# encrypting part
++
++	if ($enc)
++		{
++		 &mov($tmp2,&DWP(0,$P,"",0));
++		&xor(	$tmp3,	$tmp3);
++
++		&xor($L,$tmp2);
++		for ($i=0; $i<$BF_ROUNDS; $i+=2)
++			{
++			&comment("");
++			&comment("Round $i");
++			&BF_ENCRYPT($i+1,$R,$L,$P,$tmp1,$tmp2,$tmp3,$tmp4,1);
++
++			&comment("");
++			&comment("Round ".sprintf("%d",$i+1));
++			&BF_ENCRYPT($i+2,$L,$R,$P,$tmp1,$tmp2,$tmp3,$tmp4,1);
++			}
++		# &mov($tmp1,&wparam(0)); In last loop
++		&mov($tmp4,&DWP(($BF_ROUNDS+1)*4,$P,"",0));
++		}
++	else
++		{
++		 &mov($tmp2,&DWP(($BF_ROUNDS+1)*4,$P,"",0));
++		&xor(	$tmp3,	$tmp3);
++
++		&xor($L,$tmp2);
++		for ($i=$BF_ROUNDS; $i>0; $i-=2)
++			{
++			&comment("");
++			&comment("Round $i");
++			&BF_ENCRYPT($i,$R,$L,$P,$tmp1,$tmp2,$tmp3,$tmp4,0);
++			&comment("");
++			&comment("Round ".sprintf("%d",$i-1));
++			&BF_ENCRYPT($i-1,$L,$R,$P,$tmp1,$tmp2,$tmp3,$tmp4,0);
++			}
++		# &mov($tmp1,&wparam(0)); In last loop
++		&mov($tmp4,&DWP(0,$P,"",0));
++		}
++
++	&xor($R,$tmp4);
++	&mov(&DWP(4,$tmp1,"",0),$L);
++
++	&mov(&DWP(0,$tmp1,"",0),$R);
++	&function_end($name);
++	}
++
++sub BF_ENCRYPT
++	{
++	local($i,$L,$R,$P,$tmp1,$tmp2,$tmp3,$tmp4,$enc)=@_;
++
++	&mov(	$tmp4,		&DWP(&n2a($i*4),$P,"",0)); # for next round
++
++	&mov(	$tmp2,		$R);
++	&xor(	$L,		$tmp4);
++
++	&shr(	$tmp2,		16);
++	&mov(	$tmp4,		$R);
++
++	&movb(	&LB($tmp1),	&HB($tmp2));	# A
++	&and(	$tmp2,		0xff);		# B
++
++	&movb(	&LB($tmp3),	&HB($tmp4));	# C
++	&and(	$tmp4,		0xff);		# D
++
++	&mov(	$tmp1,		&DWP(&n2a($BF_OFF+0x0000),$P,$tmp1,4));
++	&mov(	$tmp2,		&DWP(&n2a($BF_OFF+0x0400),$P,$tmp2,4));
++
++	&add(	$tmp2,		$tmp1);
++	&mov(	$tmp1,		&DWP(&n2a($BF_OFF+0x0800),$P,$tmp3,4));
++
++	&xor(	$tmp2,		$tmp1);
++	&mov(	$tmp4,		&DWP(&n2a($BF_OFF+0x0C00),$P,$tmp4,4));
++
++	&add(	$tmp2,		$tmp4);
++	if (($enc && ($i != 16)) || ((!$enc) && ($i != 1)))
++		{ &xor(	$tmp1,		$tmp1); }
++	else
++		{
++		&comment("Load parameter 0 ($i) enc=$enc");
++		&mov($tmp1,&wparam(0));
++		} # In last loop
++
++	&xor(	$L,		$tmp2);
++	# delay
++	}
++
++sub n2a
++	{
++	sprintf("%d",$_[0]);
++	}
++
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/bf/bf_cbc.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/bf/bf_cbc.c
+new file mode 100644
+index 0000000..6ed6257
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/bf/bf_cbc.c
+@@ -0,0 +1,86 @@
++/*
++ * Copyright 1995-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include "bf_locl.h"
++
++void BF_cbc_encrypt(const unsigned char *in, unsigned char *out, long length,
++                    const BF_KEY *schedule, unsigned char *ivec, int encrypt)
++{
++    register BF_LONG tin0, tin1;
++    register BF_LONG tout0, tout1, xor0, xor1;
++    register long l = length;
++    BF_LONG tin[2];
++
++    if (encrypt) {
++        n2l(ivec, tout0);
++        n2l(ivec, tout1);
++        ivec -= 8;
++        for (l -= 8; l >= 0; l -= 8) {
++            n2l(in, tin0);
++            n2l(in, tin1);
++            tin0 ^= tout0;
++            tin1 ^= tout1;
++            tin[0] = tin0;
++            tin[1] = tin1;
++            BF_encrypt(tin, schedule);
++            tout0 = tin[0];
++            tout1 = tin[1];
++            l2n(tout0, out);
++            l2n(tout1, out);
++        }
++        if (l != -8) {
++            n2ln(in, tin0, tin1, l + 8);
++            tin0 ^= tout0;
++            tin1 ^= tout1;
++            tin[0] = tin0;
++            tin[1] = tin1;
++            BF_encrypt(tin, schedule);
++            tout0 = tin[0];
++            tout1 = tin[1];
++            l2n(tout0, out);
++            l2n(tout1, out);
++        }
++        l2n(tout0, ivec);
++        l2n(tout1, ivec);
++    } else {
++        n2l(ivec, xor0);
++        n2l(ivec, xor1);
++        ivec -= 8;
++        for (l -= 8; l >= 0; l -= 8) {
++            n2l(in, tin0);
++            n2l(in, tin1);
++            tin[0] = tin0;
++            tin[1] = tin1;
++            BF_decrypt(tin, schedule);
++            tout0 = tin[0] ^ xor0;
++            tout1 = tin[1] ^ xor1;
++            l2n(tout0, out);
++            l2n(tout1, out);
++            xor0 = tin0;
++            xor1 = tin1;
++        }
++        if (l != -8) {
++            n2l(in, tin0);
++            n2l(in, tin1);
++            tin[0] = tin0;
++            tin[1] = tin1;
++            BF_decrypt(tin, schedule);
++            tout0 = tin[0] ^ xor0;
++            tout1 = tin[1] ^ xor1;
++            l2nn(tout0, tout1, out, l + 8);
++            xor0 = tin0;
++            xor1 = tin1;
++        }
++        l2n(xor0, ivec);
++        l2n(xor1, ivec);
++    }
++    tin0 = tin1 = tout0 = tout1 = xor0 = xor1 = 0;
++    tin[0] = tin[1] = 0;
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/bf/bf_cfb64.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/bf/bf_cfb64.c
+new file mode 100644
+index 0000000..ce6e13b
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/bf/bf_cfb64.c
+@@ -0,0 +1,74 @@
++/*
++ * Copyright 1995-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include "bf_locl.h"
++
++/*
++ * The input and output encrypted as though 64bit cfb mode is being used.
++ * The extra state information to record how much of the 64bit block we have
++ * used is contained in *num;
++ */
++
++void BF_cfb64_encrypt(const unsigned char *in, unsigned char *out,
++                      long length, const BF_KEY *schedule,
++                      unsigned char *ivec, int *num, int encrypt)
++{
++    register BF_LONG v0, v1, t;
++    register int n = *num;
++    register long l = length;
++    BF_LONG ti[2];
++    unsigned char *iv, c, cc;
++
++    iv = (unsigned char *)ivec;
++    if (encrypt) {
++        while (l--) {
++            if (n == 0) {
++                n2l(iv, v0);
++                ti[0] = v0;
++                n2l(iv, v1);
++                ti[1] = v1;
++                BF_encrypt((BF_LONG *)ti, schedule);
++                iv = (unsigned char *)ivec;
++                t = ti[0];
++                l2n(t, iv);
++                t = ti[1];
++                l2n(t, iv);
++                iv = (unsigned char *)ivec;
++            }
++            c = *(in++) ^ iv[n];
++            *(out++) = c;
++            iv[n] = c;
++            n = (n + 1) & 0x07;
++        }
++    } else {
++        while (l--) {
++            if (n == 0) {
++                n2l(iv, v0);
++                ti[0] = v0;
++                n2l(iv, v1);
++                ti[1] = v1;
++                BF_encrypt((BF_LONG *)ti, schedule);
++                iv = (unsigned char *)ivec;
++                t = ti[0];
++                l2n(t, iv);
++                t = ti[1];
++                l2n(t, iv);
++                iv = (unsigned char *)ivec;
++            }
++            cc = *(in++);
++            c = iv[n];
++            iv[n] = cc;
++            *(out++) = c ^ cc;
++            n = (n + 1) & 0x07;
++        }
++    }
++    v0 = v1 = ti[0] = ti[1] = t = c = cc = 0;
++    *num = n;
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/bf/bf_ecb.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/bf/bf_ecb.c
+new file mode 100644
+index 0000000..aa73540
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/bf/bf_ecb.c
+@@ -0,0 +1,43 @@
++/*
++ * Copyright 1995-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include "bf_locl.h"
++#include 
++
++/*
++ * Blowfish as implemented from 'Blowfish: Springer-Verlag paper' (From
++ * LECTURE NOTES IN COMPUTER SCIENCE 809, FAST SOFTWARE ENCRYPTION, CAMBRIDGE
++ * SECURITY WORKSHOP, CAMBRIDGE, U.K., DECEMBER 9-11, 1993)
++ */
++
++const char *BF_options(void)
++{
++    return ("blowfish(ptr)");
++}
++
++void BF_ecb_encrypt(const unsigned char *in, unsigned char *out,
++                    const BF_KEY *key, int encrypt)
++{
++    BF_LONG l, d[2];
++
++    n2l(in, l);
++    d[0] = l;
++    n2l(in, l);
++    d[1] = l;
++    if (encrypt)
++        BF_encrypt(d, key);
++    else
++        BF_decrypt(d, key);
++    l = d[0];
++    l2n(l, out);
++    l = d[1];
++    l2n(l, out);
++    l = d[0] = d[1] = 0;
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/bf/bf_enc.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/bf/bf_enc.c
+new file mode 100644
+index 0000000..9f80c56
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/bf/bf_enc.c
+@@ -0,0 +1,179 @@
++/*
++ * Copyright 1995-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include "bf_locl.h"
++
++/*
++ * Blowfish as implemented from 'Blowfish: Springer-Verlag paper' (From
++ * LECTURE NOTES IN COMPUTER SCIENCE 809, FAST SOFTWARE ENCRYPTION, CAMBRIDGE
++ * SECURITY WORKSHOP, CAMBRIDGE, U.K., DECEMBER 9-11, 1993)
++ */
++
++#if (BF_ROUNDS != 16) && (BF_ROUNDS != 20)
++# error If you set BF_ROUNDS to some value other than 16 or 20, you will have \
++to modify the code.
++#endif
++
++void BF_encrypt(BF_LONG *data, const BF_KEY *key)
++{
++    register BF_LONG l, r;
++    register const BF_LONG *p, *s;
++
++    p = key->P;
++    s = &(key->S[0]);
++    l = data[0];
++    r = data[1];
++
++    l ^= p[0];
++    BF_ENC(r, l, s, p[1]);
++    BF_ENC(l, r, s, p[2]);
++    BF_ENC(r, l, s, p[3]);
++    BF_ENC(l, r, s, p[4]);
++    BF_ENC(r, l, s, p[5]);
++    BF_ENC(l, r, s, p[6]);
++    BF_ENC(r, l, s, p[7]);
++    BF_ENC(l, r, s, p[8]);
++    BF_ENC(r, l, s, p[9]);
++    BF_ENC(l, r, s, p[10]);
++    BF_ENC(r, l, s, p[11]);
++    BF_ENC(l, r, s, p[12]);
++    BF_ENC(r, l, s, p[13]);
++    BF_ENC(l, r, s, p[14]);
++    BF_ENC(r, l, s, p[15]);
++    BF_ENC(l, r, s, p[16]);
++# if BF_ROUNDS == 20
++    BF_ENC(r, l, s, p[17]);
++    BF_ENC(l, r, s, p[18]);
++    BF_ENC(r, l, s, p[19]);
++    BF_ENC(l, r, s, p[20]);
++# endif
++    r ^= p[BF_ROUNDS + 1];
++
++    data[1] = l & 0xffffffffU;
++    data[0] = r & 0xffffffffU;
++}
++
++#ifndef BF_DEFAULT_OPTIONS
++
++void BF_decrypt(BF_LONG *data, const BF_KEY *key)
++{
++    register BF_LONG l, r;
++    register const BF_LONG *p, *s;
++
++    p = key->P;
++    s = &(key->S[0]);
++    l = data[0];
++    r = data[1];
++
++    l ^= p[BF_ROUNDS + 1];
++#  if BF_ROUNDS == 20
++    BF_ENC(r, l, s, p[20]);
++    BF_ENC(l, r, s, p[19]);
++    BF_ENC(r, l, s, p[18]);
++    BF_ENC(l, r, s, p[17]);
++#  endif
++    BF_ENC(r, l, s, p[16]);
++    BF_ENC(l, r, s, p[15]);
++    BF_ENC(r, l, s, p[14]);
++    BF_ENC(l, r, s, p[13]);
++    BF_ENC(r, l, s, p[12]);
++    BF_ENC(l, r, s, p[11]);
++    BF_ENC(r, l, s, p[10]);
++    BF_ENC(l, r, s, p[9]);
++    BF_ENC(r, l, s, p[8]);
++    BF_ENC(l, r, s, p[7]);
++    BF_ENC(r, l, s, p[6]);
++    BF_ENC(l, r, s, p[5]);
++    BF_ENC(r, l, s, p[4]);
++    BF_ENC(l, r, s, p[3]);
++    BF_ENC(r, l, s, p[2]);
++    BF_ENC(l, r, s, p[1]);
++    r ^= p[0];
++
++    data[1] = l & 0xffffffffU;
++    data[0] = r & 0xffffffffU;
++}
++
++void BF_cbc_encrypt(const unsigned char *in, unsigned char *out, long length,
++                    const BF_KEY *schedule, unsigned char *ivec, int encrypt)
++{
++    register BF_LONG tin0, tin1;
++    register BF_LONG tout0, tout1, xor0, xor1;
++    register long l = length;
++    BF_LONG tin[2];
++
++    if (encrypt) {
++        n2l(ivec, tout0);
++        n2l(ivec, tout1);
++        ivec -= 8;
++        for (l -= 8; l >= 0; l -= 8) {
++            n2l(in, tin0);
++            n2l(in, tin1);
++            tin0 ^= tout0;
++            tin1 ^= tout1;
++            tin[0] = tin0;
++            tin[1] = tin1;
++            BF_encrypt(tin, schedule);
++            tout0 = tin[0];
++            tout1 = tin[1];
++            l2n(tout0, out);
++            l2n(tout1, out);
++        }
++        if (l != -8) {
++            n2ln(in, tin0, tin1, l + 8);
++            tin0 ^= tout0;
++            tin1 ^= tout1;
++            tin[0] = tin0;
++            tin[1] = tin1;
++            BF_encrypt(tin, schedule);
++            tout0 = tin[0];
++            tout1 = tin[1];
++            l2n(tout0, out);
++            l2n(tout1, out);
++        }
++        l2n(tout0, ivec);
++        l2n(tout1, ivec);
++    } else {
++        n2l(ivec, xor0);
++        n2l(ivec, xor1);
++        ivec -= 8;
++        for (l -= 8; l >= 0; l -= 8) {
++            n2l(in, tin0);
++            n2l(in, tin1);
++            tin[0] = tin0;
++            tin[1] = tin1;
++            BF_decrypt(tin, schedule);
++            tout0 = tin[0] ^ xor0;
++            tout1 = tin[1] ^ xor1;
++            l2n(tout0, out);
++            l2n(tout1, out);
++            xor0 = tin0;
++            xor1 = tin1;
++        }
++        if (l != -8) {
++            n2l(in, tin0);
++            n2l(in, tin1);
++            tin[0] = tin0;
++            tin[1] = tin1;
++            BF_decrypt(tin, schedule);
++            tout0 = tin[0] ^ xor0;
++            tout1 = tin[1] ^ xor1;
++            l2nn(tout0, tout1, out, l + 8);
++            xor0 = tin0;
++            xor1 = tin1;
++        }
++        l2n(xor0, ivec);
++        l2n(xor1, ivec);
++    }
++    tin0 = tin1 = tout0 = tout1 = xor0 = xor1 = 0;
++    tin[0] = tin[1] = 0;
++}
++
++#endif
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/bf/bf_locl.h b/CryptoPkg/Library/OpensslLib/openssl/crypto/bf/bf_locl.h
+new file mode 100644
+index 0000000..7e5f92c
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/bf/bf_locl.h
+@@ -0,0 +1,70 @@
++/*
++ * Copyright 1995-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#ifndef HEADER_BF_LOCL_H
++# define HEADER_BF_LOCL_H
++# include 
++
++/* NOTE - c is not incremented as per n2l */
++# define n2ln(c,l1,l2,n) { \
++                        c+=n; \
++                        l1=l2=0; \
++                        switch (n) { \
++                        case 8: l2 =((unsigned long)(*(--(c))))    ; \
++                        case 7: l2|=((unsigned long)(*(--(c))))<< 8; \
++                        case 6: l2|=((unsigned long)(*(--(c))))<<16; \
++                        case 5: l2|=((unsigned long)(*(--(c))))<<24; \
++                        case 4: l1 =((unsigned long)(*(--(c))))    ; \
++                        case 3: l1|=((unsigned long)(*(--(c))))<< 8; \
++                        case 2: l1|=((unsigned long)(*(--(c))))<<16; \
++                        case 1: l1|=((unsigned long)(*(--(c))))<<24; \
++                                } \
++                        }
++
++/* NOTE - c is not incremented as per l2n */
++# define l2nn(l1,l2,c,n) { \
++                        c+=n; \
++                        switch (n) { \
++                        case 8: *(--(c))=(unsigned char)(((l2)    )&0xff); \
++                        case 7: *(--(c))=(unsigned char)(((l2)>> 8)&0xff); \
++                        case 6: *(--(c))=(unsigned char)(((l2)>>16)&0xff); \
++                        case 5: *(--(c))=(unsigned char)(((l2)>>24)&0xff); \
++                        case 4: *(--(c))=(unsigned char)(((l1)    )&0xff); \
++                        case 3: *(--(c))=(unsigned char)(((l1)>> 8)&0xff); \
++                        case 2: *(--(c))=(unsigned char)(((l1)>>16)&0xff); \
++                        case 1: *(--(c))=(unsigned char)(((l1)>>24)&0xff); \
++                                } \
++                        }
++
++# undef n2l
++# define n2l(c,l)        (l =((unsigned long)(*((c)++)))<<24L, \
++                         l|=((unsigned long)(*((c)++)))<<16L, \
++                         l|=((unsigned long)(*((c)++)))<< 8L, \
++                         l|=((unsigned long)(*((c)++))))
++
++# undef l2n
++# define l2n(l,c)        (*((c)++)=(unsigned char)(((l)>>24L)&0xff), \
++                         *((c)++)=(unsigned char)(((l)>>16L)&0xff), \
++                         *((c)++)=(unsigned char)(((l)>> 8L)&0xff), \
++                         *((c)++)=(unsigned char)(((l)     )&0xff))
++
++/*
++ * This is actually a big endian algorithm, the most significant byte is used
++ * to lookup array 0
++ */
++
++# define BF_ENC(LL,R,S,P) ( \
++        LL^=P, \
++        LL^=((( S[       ((R>>24)&0xff)] + \
++                S[0x0100+((R>>16)&0xff)])^ \
++                S[0x0200+((R>> 8)&0xff)])+ \
++                S[0x0300+((R    )&0xff)])&0xffffffffU \
++        )
++
++#endif
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/bf/bf_ofb64.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/bf/bf_ofb64.c
+new file mode 100644
+index 0000000..6418217
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/bf/bf_ofb64.c
+@@ -0,0 +1,61 @@
++/*
++ * Copyright 1995-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include "bf_locl.h"
++
++/*
++ * The input and output encrypted as though 64bit ofb mode is being used.
++ * The extra state information to record how much of the 64bit block we have
++ * used is contained in *num;
++ */
++void BF_ofb64_encrypt(const unsigned char *in, unsigned char *out,
++                      long length, const BF_KEY *schedule,
++                      unsigned char *ivec, int *num)
++{
++    register BF_LONG v0, v1, t;
++    register int n = *num;
++    register long l = length;
++    unsigned char d[8];
++    register char *dp;
++    BF_LONG ti[2];
++    unsigned char *iv;
++    int save = 0;
++
++    iv = (unsigned char *)ivec;
++    n2l(iv, v0);
++    n2l(iv, v1);
++    ti[0] = v0;
++    ti[1] = v1;
++    dp = (char *)d;
++    l2n(v0, dp);
++    l2n(v1, dp);
++    while (l--) {
++        if (n == 0) {
++            BF_encrypt((BF_LONG *)ti, schedule);
++            dp = (char *)d;
++            t = ti[0];
++            l2n(t, dp);
++            t = ti[1];
++            l2n(t, dp);
++            save++;
++        }
++        *(out++) = *(in++) ^ d[n];
++        n = (n + 1) & 0x07;
++    }
++    if (save) {
++        v0 = ti[0];
++        v1 = ti[1];
++        iv = (unsigned char *)ivec;
++        l2n(v0, iv);
++        l2n(v1, iv);
++    }
++    t = v0 = v1 = ti[0] = ti[1] = 0;
++    *num = n;
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/bf/bf_pi.h b/CryptoPkg/Library/OpensslLib/openssl/crypto/bf/bf_pi.h
+new file mode 100644
+index 0000000..a054b03
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/bf/bf_pi.h
+@@ -0,0 +1,530 @@
++/*
++ * Copyright 1995-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++static const BF_KEY bf_init = {
++    {
++     0x243f6a88L, 0x85a308d3L, 0x13198a2eL, 0x03707344L,
++     0xa4093822L, 0x299f31d0L, 0x082efa98L, 0xec4e6c89L,
++     0x452821e6L, 0x38d01377L, 0xbe5466cfL, 0x34e90c6cL,
++     0xc0ac29b7L, 0xc97c50ddL, 0x3f84d5b5L, 0xb5470917L,
++     0x9216d5d9L, 0x8979fb1b}, {
++                                0xd1310ba6L, 0x98dfb5acL, 0x2ffd72dbL,
++                                0xd01adfb7L,
++                                0xb8e1afedL, 0x6a267e96L, 0xba7c9045L,
++                                0xf12c7f99L,
++                                0x24a19947L, 0xb3916cf7L, 0x0801f2e2L,
++                                0x858efc16L,
++                                0x636920d8L, 0x71574e69L, 0xa458fea3L,
++                                0xf4933d7eL,
++                                0x0d95748fL, 0x728eb658L, 0x718bcd58L,
++                                0x82154aeeL,
++                                0x7b54a41dL, 0xc25a59b5L, 0x9c30d539L,
++                                0x2af26013L,
++                                0xc5d1b023L, 0x286085f0L, 0xca417918L,
++                                0xb8db38efL,
++                                0x8e79dcb0L, 0x603a180eL, 0x6c9e0e8bL,
++                                0xb01e8a3eL,
++                                0xd71577c1L, 0xbd314b27L, 0x78af2fdaL,
++                                0x55605c60L,
++                                0xe65525f3L, 0xaa55ab94L, 0x57489862L,
++                                0x63e81440L,
++                                0x55ca396aL, 0x2aab10b6L, 0xb4cc5c34L,
++                                0x1141e8ceL,
++                                0xa15486afL, 0x7c72e993L, 0xb3ee1411L,
++                                0x636fbc2aL,
++                                0x2ba9c55dL, 0x741831f6L, 0xce5c3e16L,
++                                0x9b87931eL,
++                                0xafd6ba33L, 0x6c24cf5cL, 0x7a325381L,
++                                0x28958677L,
++                                0x3b8f4898L, 0x6b4bb9afL, 0xc4bfe81bL,
++                                0x66282193L,
++                                0x61d809ccL, 0xfb21a991L, 0x487cac60L,
++                                0x5dec8032L,
++                                0xef845d5dL, 0xe98575b1L, 0xdc262302L,
++                                0xeb651b88L,
++                                0x23893e81L, 0xd396acc5L, 0x0f6d6ff3L,
++                                0x83f44239L,
++                                0x2e0b4482L, 0xa4842004L, 0x69c8f04aL,
++                                0x9e1f9b5eL,
++                                0x21c66842L, 0xf6e96c9aL, 0x670c9c61L,
++                                0xabd388f0L,
++                                0x6a51a0d2L, 0xd8542f68L, 0x960fa728L,
++                                0xab5133a3L,
++                                0x6eef0b6cL, 0x137a3be4L, 0xba3bf050L,
++                                0x7efb2a98L,
++                                0xa1f1651dL, 0x39af0176L, 0x66ca593eL,
++                                0x82430e88L,
++                                0x8cee8619L, 0x456f9fb4L, 0x7d84a5c3L,
++                                0x3b8b5ebeL,
++                                0xe06f75d8L, 0x85c12073L, 0x401a449fL,
++                                0x56c16aa6L,
++                                0x4ed3aa62L, 0x363f7706L, 0x1bfedf72L,
++                                0x429b023dL,
++                                0x37d0d724L, 0xd00a1248L, 0xdb0fead3L,
++                                0x49f1c09bL,
++                                0x075372c9L, 0x80991b7bL, 0x25d479d8L,
++                                0xf6e8def7L,
++                                0xe3fe501aL, 0xb6794c3bL, 0x976ce0bdL,
++                                0x04c006baL,
++                                0xc1a94fb6L, 0x409f60c4L, 0x5e5c9ec2L,
++                                0x196a2463L,
++                                0x68fb6fafL, 0x3e6c53b5L, 0x1339b2ebL,
++                                0x3b52ec6fL,
++                                0x6dfc511fL, 0x9b30952cL, 0xcc814544L,
++                                0xaf5ebd09L,
++                                0xbee3d004L, 0xde334afdL, 0x660f2807L,
++                                0x192e4bb3L,
++                                0xc0cba857L, 0x45c8740fL, 0xd20b5f39L,
++                                0xb9d3fbdbL,
++                                0x5579c0bdL, 0x1a60320aL, 0xd6a100c6L,
++                                0x402c7279L,
++                                0x679f25feL, 0xfb1fa3ccL, 0x8ea5e9f8L,
++                                0xdb3222f8L,
++                                0x3c7516dfL, 0xfd616b15L, 0x2f501ec8L,
++                                0xad0552abL,
++                                0x323db5faL, 0xfd238760L, 0x53317b48L,
++                                0x3e00df82L,
++                                0x9e5c57bbL, 0xca6f8ca0L, 0x1a87562eL,
++                                0xdf1769dbL,
++                                0xd542a8f6L, 0x287effc3L, 0xac6732c6L,
++                                0x8c4f5573L,
++                                0x695b27b0L, 0xbbca58c8L, 0xe1ffa35dL,
++                                0xb8f011a0L,
++                                0x10fa3d98L, 0xfd2183b8L, 0x4afcb56cL,
++                                0x2dd1d35bL,
++                                0x9a53e479L, 0xb6f84565L, 0xd28e49bcL,
++                                0x4bfb9790L,
++                                0xe1ddf2daL, 0xa4cb7e33L, 0x62fb1341L,
++                                0xcee4c6e8L,
++                                0xef20cadaL, 0x36774c01L, 0xd07e9efeL,
++                                0x2bf11fb4L,
++                                0x95dbda4dL, 0xae909198L, 0xeaad8e71L,
++                                0x6b93d5a0L,
++                                0xd08ed1d0L, 0xafc725e0L, 0x8e3c5b2fL,
++                                0x8e7594b7L,
++                                0x8ff6e2fbL, 0xf2122b64L, 0x8888b812L,
++                                0x900df01cL,
++                                0x4fad5ea0L, 0x688fc31cL, 0xd1cff191L,
++                                0xb3a8c1adL,
++                                0x2f2f2218L, 0xbe0e1777L, 0xea752dfeL,
++                                0x8b021fa1L,
++                                0xe5a0cc0fL, 0xb56f74e8L, 0x18acf3d6L,
++                                0xce89e299L,
++                                0xb4a84fe0L, 0xfd13e0b7L, 0x7cc43b81L,
++                                0xd2ada8d9L,
++                                0x165fa266L, 0x80957705L, 0x93cc7314L,
++                                0x211a1477L,
++                                0xe6ad2065L, 0x77b5fa86L, 0xc75442f5L,
++                                0xfb9d35cfL,
++                                0xebcdaf0cL, 0x7b3e89a0L, 0xd6411bd3L,
++                                0xae1e7e49L,
++                                0x00250e2dL, 0x2071b35eL, 0x226800bbL,
++                                0x57b8e0afL,
++                                0x2464369bL, 0xf009b91eL, 0x5563911dL,
++                                0x59dfa6aaL,
++                                0x78c14389L, 0xd95a537fL, 0x207d5ba2L,
++                                0x02e5b9c5L,
++                                0x83260376L, 0x6295cfa9L, 0x11c81968L,
++                                0x4e734a41L,
++                                0xb3472dcaL, 0x7b14a94aL, 0x1b510052L,
++                                0x9a532915L,
++                                0xd60f573fL, 0xbc9bc6e4L, 0x2b60a476L,
++                                0x81e67400L,
++                                0x08ba6fb5L, 0x571be91fL, 0xf296ec6bL,
++                                0x2a0dd915L,
++                                0xb6636521L, 0xe7b9f9b6L, 0xff34052eL,
++                                0xc5855664L,
++                                0x53b02d5dL, 0xa99f8fa1L, 0x08ba4799L,
++                                0x6e85076aL,
++                                0x4b7a70e9L, 0xb5b32944L, 0xdb75092eL,
++                                0xc4192623L,
++                                0xad6ea6b0L, 0x49a7df7dL, 0x9cee60b8L,
++                                0x8fedb266L,
++                                0xecaa8c71L, 0x699a17ffL, 0x5664526cL,
++                                0xc2b19ee1L,
++                                0x193602a5L, 0x75094c29L, 0xa0591340L,
++                                0xe4183a3eL,
++                                0x3f54989aL, 0x5b429d65L, 0x6b8fe4d6L,
++                                0x99f73fd6L,
++                                0xa1d29c07L, 0xefe830f5L, 0x4d2d38e6L,
++                                0xf0255dc1L,
++                                0x4cdd2086L, 0x8470eb26L, 0x6382e9c6L,
++                                0x021ecc5eL,
++                                0x09686b3fL, 0x3ebaefc9L, 0x3c971814L,
++                                0x6b6a70a1L,
++                                0x687f3584L, 0x52a0e286L, 0xb79c5305L,
++                                0xaa500737L,
++                                0x3e07841cL, 0x7fdeae5cL, 0x8e7d44ecL,
++                                0x5716f2b8L,
++                                0xb03ada37L, 0xf0500c0dL, 0xf01c1f04L,
++                                0x0200b3ffL,
++                                0xae0cf51aL, 0x3cb574b2L, 0x25837a58L,
++                                0xdc0921bdL,
++                                0xd19113f9L, 0x7ca92ff6L, 0x94324773L,
++                                0x22f54701L,
++                                0x3ae5e581L, 0x37c2dadcL, 0xc8b57634L,
++                                0x9af3dda7L,
++                                0xa9446146L, 0x0fd0030eL, 0xecc8c73eL,
++                                0xa4751e41L,
++                                0xe238cd99L, 0x3bea0e2fL, 0x3280bba1L,
++                                0x183eb331L,
++                                0x4e548b38L, 0x4f6db908L, 0x6f420d03L,
++                                0xf60a04bfL,
++                                0x2cb81290L, 0x24977c79L, 0x5679b072L,
++                                0xbcaf89afL,
++                                0xde9a771fL, 0xd9930810L, 0xb38bae12L,
++                                0xdccf3f2eL,
++                                0x5512721fL, 0x2e6b7124L, 0x501adde6L,
++                                0x9f84cd87L,
++                                0x7a584718L, 0x7408da17L, 0xbc9f9abcL,
++                                0xe94b7d8cL,
++                                0xec7aec3aL, 0xdb851dfaL, 0x63094366L,
++                                0xc464c3d2L,
++                                0xef1c1847L, 0x3215d908L, 0xdd433b37L,
++                                0x24c2ba16L,
++                                0x12a14d43L, 0x2a65c451L, 0x50940002L,
++                                0x133ae4ddL,
++                                0x71dff89eL, 0x10314e55L, 0x81ac77d6L,
++                                0x5f11199bL,
++                                0x043556f1L, 0xd7a3c76bL, 0x3c11183bL,
++                                0x5924a509L,
++                                0xf28fe6edL, 0x97f1fbfaL, 0x9ebabf2cL,
++                                0x1e153c6eL,
++                                0x86e34570L, 0xeae96fb1L, 0x860e5e0aL,
++                                0x5a3e2ab3L,
++                                0x771fe71cL, 0x4e3d06faL, 0x2965dcb9L,
++                                0x99e71d0fL,
++                                0x803e89d6L, 0x5266c825L, 0x2e4cc978L,
++                                0x9c10b36aL,
++                                0xc6150ebaL, 0x94e2ea78L, 0xa5fc3c53L,
++                                0x1e0a2df4L,
++                                0xf2f74ea7L, 0x361d2b3dL, 0x1939260fL,
++                                0x19c27960L,
++                                0x5223a708L, 0xf71312b6L, 0xebadfe6eL,
++                                0xeac31f66L,
++                                0xe3bc4595L, 0xa67bc883L, 0xb17f37d1L,
++                                0x018cff28L,
++                                0xc332ddefL, 0xbe6c5aa5L, 0x65582185L,
++                                0x68ab9802L,
++                                0xeecea50fL, 0xdb2f953bL, 0x2aef7dadL,
++                                0x5b6e2f84L,
++                                0x1521b628L, 0x29076170L, 0xecdd4775L,
++                                0x619f1510L,
++                                0x13cca830L, 0xeb61bd96L, 0x0334fe1eL,
++                                0xaa0363cfL,
++                                0xb5735c90L, 0x4c70a239L, 0xd59e9e0bL,
++                                0xcbaade14L,
++                                0xeecc86bcL, 0x60622ca7L, 0x9cab5cabL,
++                                0xb2f3846eL,
++                                0x648b1eafL, 0x19bdf0caL, 0xa02369b9L,
++                                0x655abb50L,
++                                0x40685a32L, 0x3c2ab4b3L, 0x319ee9d5L,
++                                0xc021b8f7L,
++                                0x9b540b19L, 0x875fa099L, 0x95f7997eL,
++                                0x623d7da8L,
++                                0xf837889aL, 0x97e32d77L, 0x11ed935fL,
++                                0x16681281L,
++                                0x0e358829L, 0xc7e61fd6L, 0x96dedfa1L,
++                                0x7858ba99L,
++                                0x57f584a5L, 0x1b227263L, 0x9b83c3ffL,
++                                0x1ac24696L,
++                                0xcdb30aebL, 0x532e3054L, 0x8fd948e4L,
++                                0x6dbc3128L,
++                                0x58ebf2efL, 0x34c6ffeaL, 0xfe28ed61L,
++                                0xee7c3c73L,
++                                0x5d4a14d9L, 0xe864b7e3L, 0x42105d14L,
++                                0x203e13e0L,
++                                0x45eee2b6L, 0xa3aaabeaL, 0xdb6c4f15L,
++                                0xfacb4fd0L,
++                                0xc742f442L, 0xef6abbb5L, 0x654f3b1dL,
++                                0x41cd2105L,
++                                0xd81e799eL, 0x86854dc7L, 0xe44b476aL,
++                                0x3d816250L,
++                                0xcf62a1f2L, 0x5b8d2646L, 0xfc8883a0L,
++                                0xc1c7b6a3L,
++                                0x7f1524c3L, 0x69cb7492L, 0x47848a0bL,
++                                0x5692b285L,
++                                0x095bbf00L, 0xad19489dL, 0x1462b174L,
++                                0x23820e00L,
++                                0x58428d2aL, 0x0c55f5eaL, 0x1dadf43eL,
++                                0x233f7061L,
++                                0x3372f092L, 0x8d937e41L, 0xd65fecf1L,
++                                0x6c223bdbL,
++                                0x7cde3759L, 0xcbee7460L, 0x4085f2a7L,
++                                0xce77326eL,
++                                0xa6078084L, 0x19f8509eL, 0xe8efd855L,
++                                0x61d99735L,
++                                0xa969a7aaL, 0xc50c06c2L, 0x5a04abfcL,
++                                0x800bcadcL,
++                                0x9e447a2eL, 0xc3453484L, 0xfdd56705L,
++                                0x0e1e9ec9L,
++                                0xdb73dbd3L, 0x105588cdL, 0x675fda79L,
++                                0xe3674340L,
++                                0xc5c43465L, 0x713e38d8L, 0x3d28f89eL,
++                                0xf16dff20L,
++                                0x153e21e7L, 0x8fb03d4aL, 0xe6e39f2bL,
++                                0xdb83adf7L,
++                                0xe93d5a68L, 0x948140f7L, 0xf64c261cL,
++                                0x94692934L,
++                                0x411520f7L, 0x7602d4f7L, 0xbcf46b2eL,
++                                0xd4a20068L,
++                                0xd4082471L, 0x3320f46aL, 0x43b7d4b7L,
++                                0x500061afL,
++                                0x1e39f62eL, 0x97244546L, 0x14214f74L,
++                                0xbf8b8840L,
++                                0x4d95fc1dL, 0x96b591afL, 0x70f4ddd3L,
++                                0x66a02f45L,
++                                0xbfbc09ecL, 0x03bd9785L, 0x7fac6dd0L,
++                                0x31cb8504L,
++                                0x96eb27b3L, 0x55fd3941L, 0xda2547e6L,
++                                0xabca0a9aL,
++                                0x28507825L, 0x530429f4L, 0x0a2c86daL,
++                                0xe9b66dfbL,
++                                0x68dc1462L, 0xd7486900L, 0x680ec0a4L,
++                                0x27a18deeL,
++                                0x4f3ffea2L, 0xe887ad8cL, 0xb58ce006L,
++                                0x7af4d6b6L,
++                                0xaace1e7cL, 0xd3375fecL, 0xce78a399L,
++                                0x406b2a42L,
++                                0x20fe9e35L, 0xd9f385b9L, 0xee39d7abL,
++                                0x3b124e8bL,
++                                0x1dc9faf7L, 0x4b6d1856L, 0x26a36631L,
++                                0xeae397b2L,
++                                0x3a6efa74L, 0xdd5b4332L, 0x6841e7f7L,
++                                0xca7820fbL,
++                                0xfb0af54eL, 0xd8feb397L, 0x454056acL,
++                                0xba489527L,
++                                0x55533a3aL, 0x20838d87L, 0xfe6ba9b7L,
++                                0xd096954bL,
++                                0x55a867bcL, 0xa1159a58L, 0xcca92963L,
++                                0x99e1db33L,
++                                0xa62a4a56L, 0x3f3125f9L, 0x5ef47e1cL,
++                                0x9029317cL,
++                                0xfdf8e802L, 0x04272f70L, 0x80bb155cL,
++                                0x05282ce3L,
++                                0x95c11548L, 0xe4c66d22L, 0x48c1133fL,
++                                0xc70f86dcL,
++                                0x07f9c9eeL, 0x41041f0fL, 0x404779a4L,
++                                0x5d886e17L,
++                                0x325f51ebL, 0xd59bc0d1L, 0xf2bcc18fL,
++                                0x41113564L,
++                                0x257b7834L, 0x602a9c60L, 0xdff8e8a3L,
++                                0x1f636c1bL,
++                                0x0e12b4c2L, 0x02e1329eL, 0xaf664fd1L,
++                                0xcad18115L,
++                                0x6b2395e0L, 0x333e92e1L, 0x3b240b62L,
++                                0xeebeb922L,
++                                0x85b2a20eL, 0xe6ba0d99L, 0xde720c8cL,
++                                0x2da2f728L,
++                                0xd0127845L, 0x95b794fdL, 0x647d0862L,
++                                0xe7ccf5f0L,
++                                0x5449a36fL, 0x877d48faL, 0xc39dfd27L,
++                                0xf33e8d1eL,
++                                0x0a476341L, 0x992eff74L, 0x3a6f6eabL,
++                                0xf4f8fd37L,
++                                0xa812dc60L, 0xa1ebddf8L, 0x991be14cL,
++                                0xdb6e6b0dL,
++                                0xc67b5510L, 0x6d672c37L, 0x2765d43bL,
++                                0xdcd0e804L,
++                                0xf1290dc7L, 0xcc00ffa3L, 0xb5390f92L,
++                                0x690fed0bL,
++                                0x667b9ffbL, 0xcedb7d9cL, 0xa091cf0bL,
++                                0xd9155ea3L,
++                                0xbb132f88L, 0x515bad24L, 0x7b9479bfL,
++                                0x763bd6ebL,
++                                0x37392eb3L, 0xcc115979L, 0x8026e297L,
++                                0xf42e312dL,
++                                0x6842ada7L, 0xc66a2b3bL, 0x12754cccL,
++                                0x782ef11cL,
++                                0x6a124237L, 0xb79251e7L, 0x06a1bbe6L,
++                                0x4bfb6350L,
++                                0x1a6b1018L, 0x11caedfaL, 0x3d25bdd8L,
++                                0xe2e1c3c9L,
++                                0x44421659L, 0x0a121386L, 0xd90cec6eL,
++                                0xd5abea2aL,
++                                0x64af674eL, 0xda86a85fL, 0xbebfe988L,
++                                0x64e4c3feL,
++                                0x9dbc8057L, 0xf0f7c086L, 0x60787bf8L,
++                                0x6003604dL,
++                                0xd1fd8346L, 0xf6381fb0L, 0x7745ae04L,
++                                0xd736fcccL,
++                                0x83426b33L, 0xf01eab71L, 0xb0804187L,
++                                0x3c005e5fL,
++                                0x77a057beL, 0xbde8ae24L, 0x55464299L,
++                                0xbf582e61L,
++                                0x4e58f48fL, 0xf2ddfda2L, 0xf474ef38L,
++                                0x8789bdc2L,
++                                0x5366f9c3L, 0xc8b38e74L, 0xb475f255L,
++                                0x46fcd9b9L,
++                                0x7aeb2661L, 0x8b1ddf84L, 0x846a0e79L,
++                                0x915f95e2L,
++                                0x466e598eL, 0x20b45770L, 0x8cd55591L,
++                                0xc902de4cL,
++                                0xb90bace1L, 0xbb8205d0L, 0x11a86248L,
++                                0x7574a99eL,
++                                0xb77f19b6L, 0xe0a9dc09L, 0x662d09a1L,
++                                0xc4324633L,
++                                0xe85a1f02L, 0x09f0be8cL, 0x4a99a025L,
++                                0x1d6efe10L,
++                                0x1ab93d1dL, 0x0ba5a4dfL, 0xa186f20fL,
++                                0x2868f169L,
++                                0xdcb7da83L, 0x573906feL, 0xa1e2ce9bL,
++                                0x4fcd7f52L,
++                                0x50115e01L, 0xa70683faL, 0xa002b5c4L,
++                                0x0de6d027L,
++                                0x9af88c27L, 0x773f8641L, 0xc3604c06L,
++                                0x61a806b5L,
++                                0xf0177a28L, 0xc0f586e0L, 0x006058aaL,
++                                0x30dc7d62L,
++                                0x11e69ed7L, 0x2338ea63L, 0x53c2dd94L,
++                                0xc2c21634L,
++                                0xbbcbee56L, 0x90bcb6deL, 0xebfc7da1L,
++                                0xce591d76L,
++                                0x6f05e409L, 0x4b7c0188L, 0x39720a3dL,
++                                0x7c927c24L,
++                                0x86e3725fL, 0x724d9db9L, 0x1ac15bb4L,
++                                0xd39eb8fcL,
++                                0xed545578L, 0x08fca5b5L, 0xd83d7cd3L,
++                                0x4dad0fc4L,
++                                0x1e50ef5eL, 0xb161e6f8L, 0xa28514d9L,
++                                0x6c51133cL,
++                                0x6fd5c7e7L, 0x56e14ec4L, 0x362abfceL,
++                                0xddc6c837L,
++                                0xd79a3234L, 0x92638212L, 0x670efa8eL,
++                                0x406000e0L,
++                                0x3a39ce37L, 0xd3faf5cfL, 0xabc27737L,
++                                0x5ac52d1bL,
++                                0x5cb0679eL, 0x4fa33742L, 0xd3822740L,
++                                0x99bc9bbeL,
++                                0xd5118e9dL, 0xbf0f7315L, 0xd62d1c7eL,
++                                0xc700c47bL,
++                                0xb78c1b6bL, 0x21a19045L, 0xb26eb1beL,
++                                0x6a366eb4L,
++                                0x5748ab2fL, 0xbc946e79L, 0xc6a376d2L,
++                                0x6549c2c8L,
++                                0x530ff8eeL, 0x468dde7dL, 0xd5730a1dL,
++                                0x4cd04dc6L,
++                                0x2939bbdbL, 0xa9ba4650L, 0xac9526e8L,
++                                0xbe5ee304L,
++                                0xa1fad5f0L, 0x6a2d519aL, 0x63ef8ce2L,
++                                0x9a86ee22L,
++                                0xc089c2b8L, 0x43242ef6L, 0xa51e03aaL,
++                                0x9cf2d0a4L,
++                                0x83c061baL, 0x9be96a4dL, 0x8fe51550L,
++                                0xba645bd6L,
++                                0x2826a2f9L, 0xa73a3ae1L, 0x4ba99586L,
++                                0xef5562e9L,
++                                0xc72fefd3L, 0xf752f7daL, 0x3f046f69L,
++                                0x77fa0a59L,
++                                0x80e4a915L, 0x87b08601L, 0x9b09e6adL,
++                                0x3b3ee593L,
++                                0xe990fd5aL, 0x9e34d797L, 0x2cf0b7d9L,
++                                0x022b8b51L,
++                                0x96d5ac3aL, 0x017da67dL, 0xd1cf3ed6L,
++                                0x7c7d2d28L,
++                                0x1f9f25cfL, 0xadf2b89bL, 0x5ad6b472L,
++                                0x5a88f54cL,
++                                0xe029ac71L, 0xe019a5e6L, 0x47b0acfdL,
++                                0xed93fa9bL,
++                                0xe8d3c48dL, 0x283b57ccL, 0xf8d56629L,
++                                0x79132e28L,
++                                0x785f0191L, 0xed756055L, 0xf7960e44L,
++                                0xe3d35e8cL,
++                                0x15056dd4L, 0x88f46dbaL, 0x03a16125L,
++                                0x0564f0bdL,
++                                0xc3eb9e15L, 0x3c9057a2L, 0x97271aecL,
++                                0xa93a072aL,
++                                0x1b3f6d9bL, 0x1e6321f5L, 0xf59c66fbL,
++                                0x26dcf319L,
++                                0x7533d928L, 0xb155fdf5L, 0x03563482L,
++                                0x8aba3cbbL,
++                                0x28517711L, 0xc20ad9f8L, 0xabcc5167L,
++                                0xccad925fL,
++                                0x4de81751L, 0x3830dc8eL, 0x379d5862L,
++                                0x9320f991L,
++                                0xea7a90c2L, 0xfb3e7bceL, 0x5121ce64L,
++                                0x774fbe32L,
++                                0xa8b6e37eL, 0xc3293d46L, 0x48de5369L,
++                                0x6413e680L,
++                                0xa2ae0810L, 0xdd6db224L, 0x69852dfdL,
++                                0x09072166L,
++                                0xb39a460aL, 0x6445c0ddL, 0x586cdecfL,
++                                0x1c20c8aeL,
++                                0x5bbef7ddL, 0x1b588d40L, 0xccd2017fL,
++                                0x6bb4e3bbL,
++                                0xdda26a7eL, 0x3a59ff45L, 0x3e350a44L,
++                                0xbcb4cdd5L,
++                                0x72eacea8L, 0xfa6484bbL, 0x8d6612aeL,
++                                0xbf3c6f47L,
++                                0xd29be463L, 0x542f5d9eL, 0xaec2771bL,
++                                0xf64e6370L,
++                                0x740e0d8dL, 0xe75b1357L, 0xf8721671L,
++                                0xaf537d5dL,
++                                0x4040cb08L, 0x4eb4e2ccL, 0x34d2466aL,
++                                0x0115af84L,
++                                0xe1b00428L, 0x95983a1dL, 0x06b89fb4L,
++                                0xce6ea048L,
++                                0x6f3f3b82L, 0x3520ab82L, 0x011a1d4bL,
++                                0x277227f8L,
++                                0x611560b1L, 0xe7933fdcL, 0xbb3a792bL,
++                                0x344525bdL,
++                                0xa08839e1L, 0x51ce794bL, 0x2f32c9b7L,
++                                0xa01fbac9L,
++                                0xe01cc87eL, 0xbcc7d1f6L, 0xcf0111c3L,
++                                0xa1e8aac7L,
++                                0x1a908749L, 0xd44fbd9aL, 0xd0dadecbL,
++                                0xd50ada38L,
++                                0x0339c32aL, 0xc6913667L, 0x8df9317cL,
++                                0xe0b12b4fL,
++                                0xf79e59b7L, 0x43f5bb3aL, 0xf2d519ffL,
++                                0x27d9459cL,
++                                0xbf97222cL, 0x15e6fc2aL, 0x0f91fc71L,
++                                0x9b941525L,
++                                0xfae59361L, 0xceb69cebL, 0xc2a86459L,
++                                0x12baa8d1L,
++                                0xb6c1075eL, 0xe3056a0cL, 0x10d25065L,
++                                0xcb03a442L,
++                                0xe0ec6e0eL, 0x1698db3bL, 0x4c98a0beL,
++                                0x3278e964L,
++                                0x9f1f9532L, 0xe0d392dfL, 0xd3a0342bL,
++                                0x8971f21eL,
++                                0x1b0a7441L, 0x4ba3348cL, 0xc5be7120L,
++                                0xc37632d8L,
++                                0xdf359f8dL, 0x9b992f2eL, 0xe60b6f47L,
++                                0x0fe3f11dL,
++                                0xe54cda54L, 0x1edad891L, 0xce6279cfL,
++                                0xcd3e7e6fL,
++                                0x1618b166L, 0xfd2c1d05L, 0x848fd2c5L,
++                                0xf6fb2299L,
++                                0xf523f357L, 0xa6327623L, 0x93a83531L,
++                                0x56cccd02L,
++                                0xacf08162L, 0x5a75ebb5L, 0x6e163697L,
++                                0x88d273ccL,
++                                0xde966292L, 0x81b949d0L, 0x4c50901bL,
++                                0x71c65614L,
++                                0xe6c6c7bdL, 0x327a140aL, 0x45e1d006L,
++                                0xc3f27b9aL,
++                                0xc9aa53fdL, 0x62a80f00L, 0xbb25bfe2L,
++                                0x35bdd2f6L,
++                                0x71126905L, 0xb2040222L, 0xb6cbcf7cL,
++                                0xcd769c2bL,
++                                0x53113ec0L, 0x1640e3d3L, 0x38abbd60L,
++                                0x2547adf0L,
++                                0xba38209cL, 0xf746ce76L, 0x77afa1c5L,
++                                0x20756060L,
++                                0x85cbfe4eL, 0x8ae88dd8L, 0x7aaaf9b0L,
++                                0x4cf9aa7eL,
++                                0x1948c25cL, 0x02fb8a8cL, 0x01c36ae4L,
++                                0xd6ebe1f9L,
++                                0x90d4f869L, 0xa65cdea0L, 0x3f09252dL,
++                                0xc208e69fL,
++                                0xb74e6132L, 0xce77e25bL, 0x578fdfe3L,
++                                0x3ac372e6L,
++                                }
++};
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/bf/bf_skey.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/bf/bf_skey.c
+new file mode 100644
+index 0000000..a4903a2
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/bf/bf_skey.c
+@@ -0,0 +1,67 @@
++/*
++ * Copyright 1995-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include 
++#include 
++#include "bf_locl.h"
++#include "bf_pi.h"
++
++void BF_set_key(BF_KEY *key, int len, const unsigned char *data)
++{
++    int i;
++    BF_LONG *p, ri, in[2];
++    const unsigned char *d, *end;
++
++    memcpy(key, &bf_init, sizeof(BF_KEY));
++    p = key->P;
++
++    if (len > ((BF_ROUNDS + 2) * 4))
++        len = (BF_ROUNDS + 2) * 4;
++
++    d = data;
++    end = &(data[len]);
++    for (i = 0; i < (BF_ROUNDS + 2); i++) {
++        ri = *(d++);
++        if (d >= end)
++            d = data;
++
++        ri <<= 8;
++        ri |= *(d++);
++        if (d >= end)
++            d = data;
++
++        ri <<= 8;
++        ri |= *(d++);
++        if (d >= end)
++            d = data;
++
++        ri <<= 8;
++        ri |= *(d++);
++        if (d >= end)
++            d = data;
++
++        p[i] ^= ri;
++    }
++
++    in[0] = 0L;
++    in[1] = 0L;
++    for (i = 0; i < (BF_ROUNDS + 2); i += 2) {
++        BF_encrypt(in, key);
++        p[i] = in[0];
++        p[i + 1] = in[1];
++    }
++
++    p = key->S;
++    for (i = 0; i < 4 * 256; i += 2) {
++        BF_encrypt(in, key);
++        p[i] = in[0];
++        p[i + 1] = in[1];
++    }
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/bf/build.info b/CryptoPkg/Library/OpensslLib/openssl/crypto/bf/build.info
+new file mode 100644
+index 0000000..37a004e
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/bf/build.info
+@@ -0,0 +1,6 @@
++LIBS=../../libcrypto
++SOURCE[../../libcrypto]=bf_skey.c bf_ecb.c bf_cfb64.c bf_ofb64.c \
++        {- $target{bf_asm_src} -}
++
++GENERATE[bf-586.s]=asm/bf-586.pl $(PERLASM_SCHEME) $(CFLAGS) $(LIB_CFLAGS) $(PROCESSOR)
++DEPEND[bf-586.s]=../perlasm/x86asm.pl ../perlasm/cbc.pl
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/bio/b_addr.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/bio/b_addr.c
+new file mode 100644
+index 0000000..0f1900d
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/bio/b_addr.c
+@@ -0,0 +1,897 @@
++/*
++ * Copyright 2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++
++#include "bio_lcl.h"
++#include 
++
++#ifndef OPENSSL_NO_SOCK
++#include 
++#include 
++#include 
++#include 
++
++#ifdef _HPUX_SOURCE
++static const char *ossl_hstrerror(int herr)
++{
++    switch (herr) {
++    case -1:
++        return strerror(errno);
++    case 0:
++        return "No error";
++    case HOST_NOT_FOUND:
++        return "Host not found";
++    case NO_DATA:                /* NO_ADDRESS is a synonym */
++        return "No data";
++    case NO_RECOVERY:
++        return "Non recoverable error";
++    case TRY_AGAIN:
++        return "Try again";
++    default:
++        break;
++    }
++    return "unknown error";
++}
++# define hstrerror(e) ossl_hstrerror(e)
++#endif
++
++CRYPTO_RWLOCK *bio_lookup_lock;
++static CRYPTO_ONCE bio_lookup_init = CRYPTO_ONCE_STATIC_INIT;
++
++/*
++ * Throughout this file and bio_lcl.h, the existence of the macro
++ * AI_PASSIVE is used to detect the availability of struct addrinfo,
++ * getnameinfo() and getaddrinfo().  If that macro doesn't exist,
++ * we use our own implementation instead, using gethostbyname,
++ * getservbyname and a few other.
++ */
++
++/**********************************************************************
++ *
++ * Address structure
++ *
++ */
++
++BIO_ADDR *BIO_ADDR_new(void)
++{
++    BIO_ADDR *ret = OPENSSL_zalloc(sizeof(*ret));
++
++    if (ret == NULL) {
++        BIOerr(BIO_F_BIO_ADDR_NEW, ERR_R_MALLOC_FAILURE);
++        return NULL;
++    }
++
++    ret->sa.sa_family = AF_UNSPEC;
++    return ret;
++}
++
++void BIO_ADDR_free(BIO_ADDR *ap)
++{
++    OPENSSL_free(ap);
++}
++
++void BIO_ADDR_clear(BIO_ADDR *ap)
++{
++    memset(ap, 0, sizeof(*ap));
++    ap->sa.sa_family = AF_UNSPEC;
++}
++
++/*
++ * BIO_ADDR_make - non-public routine to fill a BIO_ADDR with the contents
++ * of a struct sockaddr.
++ */
++int BIO_ADDR_make(BIO_ADDR *ap, const struct sockaddr *sa)
++{
++    if (sa->sa_family == AF_INET) {
++        ap->s_in = *(const struct sockaddr_in *)sa;
++        return 1;
++    }
++#ifdef AF_INET6
++    if (sa->sa_family == AF_INET6) {
++        ap->s_in6 = *(const struct sockaddr_in6 *)sa;
++        return 1;
++    }
++#endif
++#ifdef AF_UNIX
++    if (ap->sa.sa_family == AF_UNIX) {
++        ap->s_un = *(const struct sockaddr_un *)sa;
++        return 1;
++    }
++#endif
++
++    return 0;
++}
++
++int BIO_ADDR_rawmake(BIO_ADDR *ap, int family,
++                     const void *where, size_t wherelen,
++                     unsigned short port)
++{
++#ifdef AF_UNIX
++    if (family == AF_UNIX) {
++        if (wherelen + 1 > sizeof(ap->s_un.sun_path))
++            return 0;
++        memset(&ap->s_un, 0, sizeof(ap->s_un));
++        ap->s_un.sun_family = family;
++        strncpy(ap->s_un.sun_path, where, sizeof(ap->s_un.sun_path) - 1);
++        return 1;
++    }
++#endif
++    if (family == AF_INET) {
++        if (wherelen != sizeof(struct in_addr))
++            return 0;
++        memset(&ap->s_in, 0, sizeof(ap->s_in));
++        ap->s_in.sin_family = family;
++        ap->s_in.sin_port = port;
++        ap->s_in.sin_addr = *(struct in_addr *)where;
++        return 1;
++    }
++#ifdef AF_INET6
++    if (family == AF_INET6) {
++        if (wherelen != sizeof(struct in6_addr))
++            return 0;
++        memset(&ap->s_in6, 0, sizeof(ap->s_in6));
++        ap->s_in6.sin6_family = family;
++        ap->s_in6.sin6_port = port;
++        ap->s_in6.sin6_addr = *(struct in6_addr *)where;
++        return 1;
++    }
++#endif
++
++    return 0;
++}
++
++int BIO_ADDR_family(const BIO_ADDR *ap)
++{
++    return ap->sa.sa_family;
++}
++
++int BIO_ADDR_rawaddress(const BIO_ADDR *ap, void *p, size_t *l)
++{
++    size_t len = 0;
++    const void *addrptr = NULL;
++
++    if (ap->sa.sa_family == AF_INET) {
++        len = sizeof(ap->s_in.sin_addr);
++        addrptr = &ap->s_in.sin_addr;
++    }
++#ifdef AF_INET6
++    else if (ap->sa.sa_family == AF_INET6) {
++        len = sizeof(ap->s_in6.sin6_addr);
++        addrptr = &ap->s_in6.sin6_addr;
++    }
++#endif
++#ifdef AF_UNIX
++    else if (ap->sa.sa_family == AF_UNIX) {
++        len = strlen(ap->s_un.sun_path);
++        addrptr = &ap->s_un.sun_path;
++    }
++#endif
++
++    if (addrptr == NULL)
++        return 0;
++
++    if (p != NULL) {
++        memcpy(p, addrptr, len);
++    }
++    if (l != NULL)
++        *l = len;
++
++    return 1;
++}
++
++unsigned short BIO_ADDR_rawport(const BIO_ADDR *ap)
++{
++    if (ap->sa.sa_family == AF_INET)
++        return ap->s_in.sin_port;
++#ifdef AF_INET6
++    if (ap->sa.sa_family == AF_INET6)
++        return ap->s_in6.sin6_port;
++#endif
++    return 0;
++}
++
++/*-
++ * addr_strings - helper function to get host and service names
++ * @ap: the BIO_ADDR that has the input info
++ * @numeric: 0 if actual names should be returned, 1 if the numeric
++ * representation should be returned.
++ * @hostname: a pointer to a pointer to a memory area to store the
++ * host name or numeric representation.  Unused if NULL.
++ * @service: a pointer to a pointer to a memory area to store the
++ * service name or numeric representation.  Unused if NULL.
++ *
++ * The return value is 0 on failure, with the error code in the error
++ * stack, and 1 on success.
++ */
++static int addr_strings(const BIO_ADDR *ap, int numeric,
++                        char **hostname, char **service)
++{
++    if (BIO_sock_init() != 1)
++        return 0;
++
++    if (1) {
++#ifdef AI_PASSIVE
++        int ret = 0;
++        char host[NI_MAXHOST] = "", serv[NI_MAXSERV] = "";
++        int flags = 0;
++
++        if (numeric)
++            flags |= NI_NUMERICHOST | NI_NUMERICSERV;
++
++        if ((ret = getnameinfo(BIO_ADDR_sockaddr(ap),
++                               BIO_ADDR_sockaddr_size(ap),
++                               host, sizeof(host), serv, sizeof(serv),
++                               flags)) != 0) {
++# ifdef EAI_SYSTEM
++            if (ret == EAI_SYSTEM) {
++                SYSerr(SYS_F_GETNAMEINFO, get_last_socket_error());
++                BIOerr(BIO_F_ADDR_STRINGS, ERR_R_SYS_LIB);
++            } else
++# endif
++            {
++                BIOerr(BIO_F_ADDR_STRINGS, ERR_R_SYS_LIB);
++                ERR_add_error_data(1, gai_strerror(ret));
++            }
++            return 0;
++        }
++
++        /* VMS getnameinfo() has a bug, it doesn't fill in serv, which
++         * leaves it with whatever garbage that happens to be there.
++         * However, we initialise serv with the empty string (serv[0]
++         * is therefore NUL), so it gets real easy to detect when things
++         * didn't go the way one might expect.
++         */
++        if (serv[0] == '\0') {
++            BIO_snprintf(serv, sizeof(serv), "%d",
++                         ntohs(BIO_ADDR_rawport(ap)));
++        }
++
++        if (hostname != NULL)
++            *hostname = OPENSSL_strdup(host);
++        if (service != NULL)
++            *service = OPENSSL_strdup(serv);
++    } else {
++#endif
++        if (hostname != NULL)
++            *hostname = OPENSSL_strdup(inet_ntoa(ap->s_in.sin_addr));
++        if (service != NULL) {
++            char serv[6];        /* port is 16 bits => max 5 decimal digits */
++            BIO_snprintf(serv, sizeof(serv), "%d", ntohs(ap->s_in.sin_port));
++            *service = OPENSSL_strdup(serv);
++        }
++    }
++
++    if ((hostname != NULL && *hostname == NULL)
++            || (service != NULL && *service == NULL)) {
++        if (hostname != NULL) {
++            OPENSSL_free(*hostname);
++            *hostname = NULL;
++        }
++        if (service != NULL) {
++            OPENSSL_free(*service);
++            *service = NULL;
++        }
++        BIOerr(BIO_F_ADDR_STRINGS, ERR_R_MALLOC_FAILURE);
++        return 0;
++    }
++
++    return 1;
++}
++
++char *BIO_ADDR_hostname_string(const BIO_ADDR *ap, int numeric)
++{
++    char *hostname = NULL;
++
++    if (addr_strings(ap, numeric, &hostname, NULL))
++        return hostname;
++
++    return NULL;
++}
++
++char *BIO_ADDR_service_string(const BIO_ADDR *ap, int numeric)
++{
++    char *service = NULL;
++
++    if (addr_strings(ap, numeric, NULL, &service))
++        return service;
++
++    return NULL;
++}
++
++char *BIO_ADDR_path_string(const BIO_ADDR *ap)
++{
++#ifdef AF_UNIX
++    if (ap->sa.sa_family == AF_UNIX)
++        return OPENSSL_strdup(ap->s_un.sun_path);
++#endif
++    return NULL;
++}
++
++/*
++ * BIO_ADDR_sockaddr - non-public routine to return the struct sockaddr
++ * for a given BIO_ADDR.  In reality, this is simply a type safe cast.
++ * The returned struct sockaddr is const, so it can't be tampered with.
++ */
++const struct sockaddr *BIO_ADDR_sockaddr(const BIO_ADDR *ap)
++{
++    return &(ap->sa);
++}
++
++/*
++ * BIO_ADDR_sockaddr_noconst - non-public function that does the same
++ * as BIO_ADDR_sockaddr, but returns a non-const.  USE WITH CARE, as
++ * it allows you to tamper with the data (and thereby the contents
++ * of the input BIO_ADDR).
++ */
++struct sockaddr *BIO_ADDR_sockaddr_noconst(BIO_ADDR *ap)
++{
++    return &(ap->sa);
++}
++
++/*
++ * BIO_ADDR_sockaddr_size - non-public function that returns the size
++ * of the struct sockaddr the BIO_ADDR is using.  If the protocol family
++ * isn't set or is something other than AF_INET, AF_INET6 or AF_UNIX,
++ * the size of the BIO_ADDR type is returned.
++ */
++socklen_t BIO_ADDR_sockaddr_size(const BIO_ADDR *ap)
++{
++    if (ap->sa.sa_family == AF_INET)
++        return sizeof(ap->s_in);
++#ifdef AF_INET6
++    if (ap->sa.sa_family == AF_INET6)
++        return sizeof(ap->s_in6);
++#endif
++#ifdef AF_UNIX
++    if (ap->sa.sa_family == AF_UNIX)
++        return sizeof(ap->s_un);
++#endif
++    return sizeof(*ap);
++}
++
++/**********************************************************************
++ *
++ * Address info database
++ *
++ */
++
++const BIO_ADDRINFO *BIO_ADDRINFO_next(const BIO_ADDRINFO *bai)
++{
++    if (bai != NULL)
++        return bai->bai_next;
++    return NULL;
++}
++
++int BIO_ADDRINFO_family(const BIO_ADDRINFO *bai)
++{
++    if (bai != NULL)
++        return bai->bai_family;
++    return 0;
++}
++
++int BIO_ADDRINFO_socktype(const BIO_ADDRINFO *bai)
++{
++    if (bai != NULL)
++        return bai->bai_socktype;
++    return 0;
++}
++
++int BIO_ADDRINFO_protocol(const BIO_ADDRINFO *bai)
++{
++    if (bai != NULL) {
++        if (bai->bai_protocol != 0)
++            return bai->bai_protocol;
++
++#ifdef AF_UNIX
++        if (bai->bai_family == AF_UNIX)
++            return 0;
++#endif
++
++        switch (bai->bai_socktype) {
++        case SOCK_STREAM:
++            return IPPROTO_TCP;
++        case SOCK_DGRAM:
++            return IPPROTO_UDP;
++        default:
++            break;
++        }
++    }
++    return 0;
++}
++
++/*
++ * BIO_ADDRINFO_sockaddr_size - non-public function that returns the size
++ * of the struct sockaddr inside the BIO_ADDRINFO.
++ */
++socklen_t BIO_ADDRINFO_sockaddr_size(const BIO_ADDRINFO *bai)
++{
++    if (bai != NULL)
++        return bai->bai_addrlen;
++    return 0;
++}
++
++/*
++ * BIO_ADDRINFO_sockaddr - non-public function that returns bai_addr
++ * as the struct sockaddr it is.
++ */
++const struct sockaddr *BIO_ADDRINFO_sockaddr(const BIO_ADDRINFO *bai)
++{
++    if (bai != NULL)
++        return bai->bai_addr;
++    return NULL;
++}
++
++const BIO_ADDR *BIO_ADDRINFO_address(const BIO_ADDRINFO *bai)
++{
++    if (bai != NULL)
++        return (BIO_ADDR *)bai->bai_addr;
++    return NULL;
++}
++
++void BIO_ADDRINFO_free(BIO_ADDRINFO *bai)
++{
++    if (bai == NULL)
++        return;
++
++#ifdef AI_PASSIVE
++# ifdef AF_UNIX
++#  define _cond bai->bai_family != AF_UNIX
++# else
++#  define _cond 1
++# endif
++    if (_cond) {
++        freeaddrinfo(bai);
++        return;
++    }
++#endif
++
++    /* Free manually when we know that addrinfo_wrap() was used.
++     * See further comment above addrinfo_wrap()
++     */
++    while (bai != NULL) {
++        BIO_ADDRINFO *next = bai->bai_next;
++        OPENSSL_free(bai->bai_addr);
++        OPENSSL_free(bai);
++        bai = next;
++    }
++}
++
++/**********************************************************************
++ *
++ * Service functions
++ *
++ */
++
++/*-
++ * The specs in hostserv can take these forms:
++ *
++ * host:service         => *host = "host", *service = "service"
++ * host:*               => *host = "host", *service = NULL
++ * host:                => *host = "host", *service = NULL
++ * :service             => *host = NULL, *service = "service"
++ * *:service            => *host = NULL, *service = "service"
++ *
++ * in case no : is present in the string, the result depends on
++ * hostserv_prio, as follows:
++ *
++ * when hostserv_prio == BIO_PARSE_PRIO_HOST
++ * host                 => *host = "host", *service untouched
++ *
++ * when hostserv_prio == BIO_PARSE_PRIO_SERV
++ * service              => *host untouched, *service = "service"
++ *
++ */
++int BIO_parse_hostserv(const char *hostserv, char **host, char **service,
++                       enum BIO_hostserv_priorities hostserv_prio)
++{
++    const char *h = NULL; size_t hl = 0;
++    const char *p = NULL; size_t pl = 0;
++
++    if (*hostserv == '[') {
++        if ((p = strchr(hostserv, ']')) == NULL)
++            goto spec_err;
++        h = hostserv + 1;
++        hl = p - h;
++        p++;
++        if (*p == '\0')
++            p = NULL;
++        else if (*p != ':')
++            goto spec_err;
++        else {
++            p++;
++            pl = strlen(p);
++        }
++    } else {
++        const char *p2 = strrchr(hostserv, ':');
++        p = strchr(hostserv, ':');
++
++        /*-
++         * Check for more than one colon.  There are three possible
++         * interpretations:
++         * 1. IPv6 address with port number, last colon being separator.
++         * 2. IPv6 address only.
++         * 3. IPv6 address only if hostserv_prio == BIO_PARSE_PRIO_HOST,
++         *    IPv6 address and port number if hostserv_prio == BIO_PARSE_PRIO_SERV
++         * Because of this ambiguity, we currently choose to make it an
++         * error.
++         */
++        if (p != p2)
++            goto amb_err;
++
++        if (p != NULL) {
++            h = hostserv;
++            hl = p - h;
++            p++;
++            pl = strlen(p);
++        } else if (hostserv_prio == BIO_PARSE_PRIO_HOST) {
++            h = hostserv;
++            hl = strlen(h);
++        } else {
++            p = hostserv;
++            pl = strlen(p);
++        }
++    }
++
++    if (p != NULL && strchr(p, ':'))
++        goto spec_err;
++
++    if (h != NULL && host != NULL) {
++        if (hl == 0
++            || (hl == 1 && h[0] == '*')) {
++            *host = NULL;
++        } else {
++            *host = OPENSSL_strndup(h, hl);
++            if (*host == NULL)
++                goto memerr;
++        }
++    }
++    if (p != NULL && service != NULL) {
++        if (pl == 0
++            || (pl == 1 && p[0] == '*')) {
++            *service = NULL;
++        } else {
++            *service = OPENSSL_strndup(p, pl);
++            if (*service == NULL)
++                goto memerr;
++        }
++    }
++
++    return 1;
++ amb_err:
++    BIOerr(BIO_F_BIO_PARSE_HOSTSERV, BIO_R_AMBIGUOUS_HOST_OR_SERVICE);
++    return 0;
++ spec_err:
++    BIOerr(BIO_F_BIO_PARSE_HOSTSERV, BIO_R_MALFORMED_HOST_OR_SERVICE);
++    return 0;
++ memerr:
++    BIOerr(BIO_F_BIO_PARSE_HOSTSERV, ERR_R_MALLOC_FAILURE);
++    return 0;
++}
++
++/* addrinfo_wrap is used to build our own addrinfo "chain".
++ * (it has only one entry, so calling it a chain may be a stretch)
++ * It should ONLY be called when getaddrinfo() and friends
++ * aren't available, OR when dealing with a non IP protocol
++ * family, such as AF_UNIX
++ *
++ * the return value is 1 on success, or 0 on failure, which
++ * only happens if a memory allocation error occurred.
++ */
++static int addrinfo_wrap(int family, int socktype,
++                         const void *where, size_t wherelen,
++                         unsigned short port,
++                         BIO_ADDRINFO **bai)
++{
++    OPENSSL_assert(bai != NULL);
++
++    *bai = OPENSSL_zalloc(sizeof(**bai));
++    if (*bai == NULL)
++        return 0;
++
++    (*bai)->bai_family = family;
++    (*bai)->bai_socktype = socktype;
++    if (socktype == SOCK_STREAM)
++        (*bai)->bai_protocol = IPPROTO_TCP;
++    if (socktype == SOCK_DGRAM)
++        (*bai)->bai_protocol = IPPROTO_UDP;
++#ifdef AF_UNIX
++    if (family == AF_UNIX)
++        (*bai)->bai_protocol = 0;
++#endif
++    {
++        /* Magic: We know that BIO_ADDR_sockaddr_noconst is really
++           just an advanced cast of BIO_ADDR* to struct sockaddr *
++           by the power of union, so while it may seem that we're
++           creating a memory leak here, we are not.  It will be
++           all right. */
++        BIO_ADDR *addr = BIO_ADDR_new();
++        if (addr != NULL) {
++            BIO_ADDR_rawmake(addr, family, where, wherelen, port);
++            (*bai)->bai_addr = BIO_ADDR_sockaddr_noconst(addr);
++        }
++    }
++    (*bai)->bai_next = NULL;
++    if ((*bai)->bai_addr == NULL) {
++        BIO_ADDRINFO_free(*bai);
++        *bai = NULL;
++        return 0;
++    }
++    return 1;
++}
++
++DEFINE_RUN_ONCE_STATIC(do_bio_lookup_init)
++{
++    OPENSSL_init_crypto(0, NULL);
++    bio_lookup_lock = CRYPTO_THREAD_lock_new();
++    return bio_lookup_lock != NULL;
++}
++
++/*-
++ * BIO_lookup - look up the node and service you want to connect to.
++ * @node: the node you want to connect to.
++ * @service: the service you want to connect to.
++ * @lookup_type: declare intent with the result, client or server.
++ * @family: the address family you want to use.  Use AF_UNSPEC for any, or
++ *  AF_INET, AF_INET6 or AF_UNIX.
++ * @socktype: The socket type you want to use.  Can be SOCK_STREAM, SOCK_DGRAM
++ *  or 0 for all.
++ * @res: Storage place for the resulting list of returned addresses
++ *
++ * This will do a lookup of the node and service that you want to connect to.
++ * It returns a linked list of different addresses you can try to connect to.
++ *
++ * When no longer needed you should call BIO_ADDRINFO_free() to free the result.
++ *
++ * The return value is 1 on success or 0 in case of error.
++ */
++int BIO_lookup(const char *host, const char *service,
++               enum BIO_lookup_type lookup_type,
++               int family, int socktype, BIO_ADDRINFO **res)
++{
++    int ret = 0;                 /* Assume failure */
++
++    switch(family) {
++    case AF_INET:
++#ifdef AF_INET6
++    case AF_INET6:
++#endif
++#ifdef AF_UNIX
++    case AF_UNIX:
++#endif
++#ifdef AF_UNSPEC
++    case AF_UNSPEC:
++#endif
++        break;
++    default:
++        BIOerr(BIO_F_BIO_LOOKUP, BIO_R_UNSUPPORTED_PROTOCOL_FAMILY);
++        return 0;
++    }
++
++#ifdef AF_UNIX
++    if (family == AF_UNIX) {
++        if (addrinfo_wrap(family, socktype, host, strlen(host), 0, res))
++            return 1;
++        else
++            BIOerr(BIO_F_BIO_LOOKUP, ERR_R_MALLOC_FAILURE);
++        return 0;
++    }
++#endif
++
++    if (BIO_sock_init() != 1)
++        return 0;
++
++    if (1) {
++        int gai_ret = 0;
++#ifdef AI_PASSIVE
++        struct addrinfo hints;
++        memset(&hints, 0, sizeof hints);
++
++        hints.ai_family = family;
++        hints.ai_socktype = socktype;
++
++        if (lookup_type == BIO_LOOKUP_SERVER)
++            hints.ai_flags |= AI_PASSIVE;
++
++        /* Note that |res| SHOULD be a 'struct addrinfo **' thanks to
++         * macro magic in bio_lcl.h
++         */
++        switch ((gai_ret = getaddrinfo(host, service, &hints, res))) {
++# ifdef EAI_SYSTEM
++        case EAI_SYSTEM:
++            SYSerr(SYS_F_GETADDRINFO, get_last_socket_error());
++            BIOerr(BIO_F_BIO_LOOKUP, ERR_R_SYS_LIB);
++            break;
++# endif
++        case 0:
++            ret = 1;             /* Success */
++            break;
++        default:
++            BIOerr(BIO_F_BIO_LOOKUP, ERR_R_SYS_LIB);
++            ERR_add_error_data(1, gai_strerror(gai_ret));
++            break;
++        }
++    } else {
++#endif
++        const struct hostent *he;
++/*
++ * Because struct hostent is defined for 32-bit pointers only with
++ * VMS C, we need to make sure that '&he_fallback_address' and
++ * '&he_fallback_addresses' are 32-bit pointers
++ */
++#if defined(OPENSSL_SYS_VMS) && defined(__DECC)
++# pragma pointer_size save
++# pragma pointer_size 32
++#endif
++        /* Windows doesn't seem to have in_addr_t */
++#ifdef OPENSSL_SYS_WINDOWS
++        static uint32_t he_fallback_address;
++        static const char *he_fallback_addresses[] =
++            { (char *)&he_fallback_address, NULL };
++#else
++        static in_addr_t he_fallback_address;
++        static const char *he_fallback_addresses[] =
++            { (char *)&he_fallback_address, NULL };
++#endif
++        static const struct hostent he_fallback =
++            { NULL, NULL, AF_INET, sizeof(he_fallback_address),
++              (char **)&he_fallback_addresses };
++#if defined(OPENSSL_SYS_VMS) && defined(__DECC)
++# pragma pointer_size restore
++#endif
++
++        struct servent *se;
++        /* Apparently, on WIN64, s_proto and s_port have traded places... */
++#ifdef _WIN64
++        struct servent se_fallback = { NULL, NULL, NULL, 0 };
++#else
++        struct servent se_fallback = { NULL, NULL, 0, NULL };
++#endif
++
++        if (!RUN_ONCE(&bio_lookup_init, do_bio_lookup_init)) {
++            BIOerr(BIO_F_BIO_LOOKUP, ERR_R_MALLOC_FAILURE);
++            ret = 0;
++            goto err;
++        }
++
++        CRYPTO_THREAD_write_lock(bio_lookup_lock);
++        he_fallback_address = INADDR_ANY;
++        if (host == NULL) {
++            he = &he_fallback;
++            switch(lookup_type) {
++            case BIO_LOOKUP_CLIENT:
++                he_fallback_address = INADDR_LOOPBACK;
++                break;
++            case BIO_LOOKUP_SERVER:
++                he_fallback_address = INADDR_ANY;
++                break;
++            default:
++                OPENSSL_assert(("We forgot to handle a lookup type!" == 0));
++                break;
++            }
++        } else {
++            he = gethostbyname(host);
++
++            if (he == NULL) {
++#ifndef OPENSSL_SYS_WINDOWS
++                BIOerr(BIO_F_BIO_LOOKUP, ERR_R_SYS_LIB);
++                ERR_add_error_data(1, hstrerror(h_errno));
++#else
++                SYSerr(SYS_F_GETHOSTBYNAME, WSAGetLastError());
++#endif
++                ret = 0;
++                goto err;
++            }
++        }
++
++        if (service == NULL) {
++            se_fallback.s_port = 0;
++            se_fallback.s_proto = NULL;
++            se = &se_fallback;
++        } else {
++            char *endp = NULL;
++            long portnum = strtol(service, &endp, 10);
++
++/*
++ * Because struct servent is defined for 32-bit pointers only with
++ * VMS C, we need to make sure that 'proto' is a 32-bit pointer.
++ */
++#if defined(OPENSSL_SYS_VMS) && defined(__DECC)
++# pragma pointer_size save
++# pragma pointer_size 32
++#endif
++            char *proto = NULL;
++#if defined(OPENSSL_SYS_VMS) && defined(__DECC)
++# pragma pointer_size restore
++#endif
++
++            switch (socktype) {
++            case SOCK_STREAM:
++                proto = "tcp";
++                break;
++            case SOCK_DGRAM:
++                proto = "udp";
++                break;
++            }
++
++            if (endp != service && *endp == '\0'
++                    && portnum > 0 && portnum < 65536) {
++                se_fallback.s_port = htons(portnum);
++                se_fallback.s_proto = proto;
++                se = &se_fallback;
++            } else if (endp == service) {
++                se = getservbyname(service, proto);
++
++                if (se == NULL) {
++#ifndef OPENSSL_SYS_WINDOWS
++                    BIOerr(BIO_F_BIO_LOOKUP, ERR_R_SYS_LIB);
++                    ERR_add_error_data(1, hstrerror(h_errno));
++#else
++                    SYSerr(SYS_F_GETSERVBYNAME, WSAGetLastError());
++#endif
++                    goto err;
++                }
++            } else {
++                BIOerr(BIO_F_BIO_LOOKUP, BIO_R_MALFORMED_HOST_OR_SERVICE);
++                goto err;
++            }
++        }
++
++        *res = NULL;
++
++        {
++/*
++ * Because hostent::h_addr_list is an array of 32-bit pointers with VMS C,
++ * we must make sure our iterator designates the same element type, hence
++ * the pointer size dance.
++ */
++#if defined(OPENSSL_SYS_VMS) && defined(__DECC)
++# pragma pointer_size save
++# pragma pointer_size 32
++#endif
++            char **addrlistp;
++#if defined(OPENSSL_SYS_VMS) && defined(__DECC)
++# pragma pointer_size restore
++#endif
++            size_t addresses;
++            BIO_ADDRINFO *tmp_bai = NULL;
++
++            /* The easiest way to create a linked list from an
++               array is to start from the back */
++            for(addrlistp = he->h_addr_list; *addrlistp != NULL;
++                addrlistp++)
++                ;
++
++            for(addresses = addrlistp - he->h_addr_list;
++                addrlistp--, addresses-- > 0; ) {
++                if (!addrinfo_wrap(he->h_addrtype, socktype,
++                                   *addrlistp, he->h_length,
++                                   se->s_port, &tmp_bai))
++                    goto addrinfo_malloc_err;
++                tmp_bai->bai_next = *res;
++                *res = tmp_bai;
++                continue;
++             addrinfo_malloc_err:
++                BIO_ADDRINFO_free(*res);
++                *res = NULL;
++                BIOerr(BIO_F_BIO_LOOKUP, ERR_R_MALLOC_FAILURE);
++                ret = 0;
++                goto err;
++            }
++
++            ret = 1;
++        }
++     err:
++        CRYPTO_THREAD_unlock(bio_lookup_lock);
++    }
++
++    return ret;
++}
++
++#endif /* OPENSSL_NO_SOCK */
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/bio/b_dump.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/bio/b_dump.c
+new file mode 100644
+index 0000000..a27954f
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/bio/b_dump.c
+@@ -0,0 +1,158 @@
++/*
++ * Copyright 1995-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++/*
++ * Stolen from tjh's ssl/ssl_trc.c stuff.
++ */
++
++#include 
++#include "bio_lcl.h"
++
++#define TRUNCATE
++#define DUMP_WIDTH      16
++#define DUMP_WIDTH_LESS_INDENT(i) (DUMP_WIDTH-((i-(i>6?6:i)+3)/4))
++
++int BIO_dump_cb(int (*cb) (const void *data, size_t len, void *u),
++                void *u, const char *s, int len)
++{
++    return BIO_dump_indent_cb(cb, u, s, len, 0);
++}
++
++int BIO_dump_indent_cb(int (*cb) (const void *data, size_t len, void *u),
++                       void *u, const char *s, int len, int indent)
++{
++    int ret = 0;
++    char buf[288 + 1], tmp[20], str[128 + 1];
++    int i, j, rows, trc;
++    unsigned char ch;
++    int dump_width;
++
++    trc = 0;
++
++#ifdef TRUNCATE
++    for (; (len > 0) && ((s[len - 1] == ' ') || (s[len - 1] == '\0')); len--)
++        trc++;
++#endif
++
++    if (indent < 0)
++        indent = 0;
++    if (indent) {
++        if (indent > 128)
++            indent = 128;
++        memset(str, ' ', indent);
++    }
++    str[indent] = '\0';
++
++    dump_width = DUMP_WIDTH_LESS_INDENT(indent);
++    rows = (len / dump_width);
++    if ((rows * dump_width) < len)
++        rows++;
++    for (i = 0; i < rows; i++) {
++        OPENSSL_strlcpy(buf, str, sizeof buf);
++        BIO_snprintf(tmp, sizeof tmp, "%04x - ", i * dump_width);
++        OPENSSL_strlcat(buf, tmp, sizeof buf);
++        for (j = 0; j < dump_width; j++) {
++            if (((i * dump_width) + j) >= len) {
++                OPENSSL_strlcat(buf, "   ", sizeof buf);
++            } else {
++                ch = ((unsigned char)*(s + i * dump_width + j)) & 0xff;
++                BIO_snprintf(tmp, sizeof tmp, "%02x%c", ch,
++                             j == 7 ? '-' : ' ');
++                OPENSSL_strlcat(buf, tmp, sizeof buf);
++            }
++        }
++        OPENSSL_strlcat(buf, "  ", sizeof buf);
++        for (j = 0; j < dump_width; j++) {
++            if (((i * dump_width) + j) >= len)
++                break;
++            ch = ((unsigned char)*(s + i * dump_width + j)) & 0xff;
++#ifndef CHARSET_EBCDIC
++            BIO_snprintf(tmp, sizeof tmp, "%c",
++                         ((ch >= ' ') && (ch <= '~')) ? ch : '.');
++#else
++            BIO_snprintf(tmp, sizeof tmp, "%c",
++                         ((ch >= os_toascii[' ']) && (ch <= os_toascii['~']))
++                         ? os_toebcdic[ch]
++                         : '.');
++#endif
++            OPENSSL_strlcat(buf, tmp, sizeof buf);
++        }
++        OPENSSL_strlcat(buf, "\n", sizeof buf);
++        /*
++         * if this is the last call then update the ddt_dump thing so that we
++         * will move the selection point in the debug window
++         */
++        ret += cb((void *)buf, strlen(buf), u);
++    }
++#ifdef TRUNCATE
++    if (trc > 0) {
++        BIO_snprintf(buf, sizeof buf, "%s%04x - \n", str,
++                     len + trc);
++        ret += cb((void *)buf, strlen(buf), u);
++    }
++#endif
++    return (ret);
++}
++
++#ifndef OPENSSL_NO_STDIO
++static int write_fp(const void *data, size_t len, void *fp)
++{
++    return UP_fwrite(data, len, 1, fp);
++}
++
++int BIO_dump_fp(FILE *fp, const char *s, int len)
++{
++    return BIO_dump_cb(write_fp, fp, s, len);
++}
++
++int BIO_dump_indent_fp(FILE *fp, const char *s, int len, int indent)
++{
++    return BIO_dump_indent_cb(write_fp, fp, s, len, indent);
++}
++#endif
++
++static int write_bio(const void *data, size_t len, void *bp)
++{
++    return BIO_write((BIO *)bp, (const char *)data, len);
++}
++
++int BIO_dump(BIO *bp, const char *s, int len)
++{
++    return BIO_dump_cb(write_bio, bp, s, len);
++}
++
++int BIO_dump_indent(BIO *bp, const char *s, int len, int indent)
++{
++    return BIO_dump_indent_cb(write_bio, bp, s, len, indent);
++}
++
++int BIO_hex_string(BIO *out, int indent, int width, unsigned char *data,
++                   int datalen)
++{
++    int i, j = 0;
++
++    if (datalen < 1)
++        return 1;
++
++    for (i = 0; i < datalen - 1; i++) {
++        if (i && !j)
++            BIO_printf(out, "%*s", indent, "");
++
++        BIO_printf(out, "%02X:", data[i]);
++
++        j = (j + 1) % width;
++        if (!j)
++            BIO_printf(out, "\n");
++    }
++
++    if (i && !j)
++        BIO_printf(out, "%*s", indent, "");
++    BIO_printf(out, "%02X", data[datalen - 1]);
++    return 1;
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/bio/b_print.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/bio/b_print.c
+new file mode 100644
+index 0000000..e91ab6d
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/bio/b_print.c
+@@ -0,0 +1,944 @@
++/*
++ * Copyright 1995-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include 
++#include 
++#include "internal/numbers.h"
++#include "internal/cryptlib.h"
++#ifndef NO_SYS_TYPES_H
++# include 
++#endif
++#include          /* To get BN_LLONG properly defined */
++#include 
++
++#if defined(BN_LLONG) || defined(SIXTY_FOUR_BIT)
++# ifndef HAVE_LONG_LONG
++#  define HAVE_LONG_LONG 1
++# endif
++#endif
++
++/*
++ * Copyright Patrick Powell 1995
++ * This code is based on code written by Patrick Powell 
++ * It may be used for any purpose as long as this notice remains intact
++ * on all source code distributions.
++ */
++
++#ifdef HAVE_LONG_DOUBLE
++# define LDOUBLE long double
++#else
++# define LDOUBLE double
++#endif
++
++#ifdef HAVE_LONG_LONG
++# if defined(_WIN32) && !defined(__GNUC__)
++#  define LLONG __int64
++# else
++#  define LLONG long long
++# endif
++#else
++# define LLONG long
++#endif
++
++static int fmtstr(char **, char **, size_t *, size_t *,
++                  const char *, int, int, int);
++static int fmtint(char **, char **, size_t *, size_t *,
++                  LLONG, int, int, int, int);
++static int fmtfp(char **, char **, size_t *, size_t *,
++                 LDOUBLE, int, int, int, int);
++static int doapr_outch(char **, char **, size_t *, size_t *, int);
++static int _dopr(char **sbuffer, char **buffer,
++                 size_t *maxlen, size_t *retlen, int *truncated,
++                 const char *format, va_list args);
++
++/* format read states */
++#define DP_S_DEFAULT    0
++#define DP_S_FLAGS      1
++#define DP_S_MIN        2
++#define DP_S_DOT        3
++#define DP_S_MAX        4
++#define DP_S_MOD        5
++#define DP_S_CONV       6
++#define DP_S_DONE       7
++
++/* format flags - Bits */
++/* left-aligned padding */
++#define DP_F_MINUS      (1 << 0)
++/* print an explicit '+' for a value with positive sign */
++#define DP_F_PLUS       (1 << 1)
++/* print an explicit ' ' for a value with positive sign */
++#define DP_F_SPACE      (1 << 2)
++/* print 0/0x prefix for octal/hex and decimal point for floating point */
++#define DP_F_NUM        (1 << 3)
++/* print leading zeroes */
++#define DP_F_ZERO       (1 << 4)
++/* print HEX in UPPPERcase */
++#define DP_F_UP         (1 << 5)
++/* treat value as unsigned */
++#define DP_F_UNSIGNED   (1 << 6)
++
++/* conversion flags */
++#define DP_C_SHORT      1
++#define DP_C_LONG       2
++#define DP_C_LDOUBLE    3
++#define DP_C_LLONG      4
++
++/* Floating point formats */
++#define F_FORMAT        0
++#define E_FORMAT        1
++#define G_FORMAT        2
++
++/* some handy macros */
++#define char_to_int(p) (p - '0')
++#define OSSL_MAX(p,q) ((p >= q) ? p : q)
++
++static int
++_dopr(char **sbuffer,
++      char **buffer,
++      size_t *maxlen,
++      size_t *retlen, int *truncated, const char *format, va_list args)
++{
++    char ch;
++    LLONG value;
++    LDOUBLE fvalue;
++    char *strvalue;
++    int min;
++    int max;
++    int state;
++    int flags;
++    int cflags;
++    size_t currlen;
++
++    state = DP_S_DEFAULT;
++    flags = currlen = cflags = min = 0;
++    max = -1;
++    ch = *format++;
++
++    while (state != DP_S_DONE) {
++        if (ch == '\0' || (buffer == NULL && currlen >= *maxlen))
++            state = DP_S_DONE;
++
++        switch (state) {
++        case DP_S_DEFAULT:
++            if (ch == '%')
++                state = DP_S_FLAGS;
++            else
++                if(!doapr_outch(sbuffer, buffer, &currlen, maxlen, ch))
++                    return 0;
++            ch = *format++;
++            break;
++        case DP_S_FLAGS:
++            switch (ch) {
++            case '-':
++                flags |= DP_F_MINUS;
++                ch = *format++;
++                break;
++            case '+':
++                flags |= DP_F_PLUS;
++                ch = *format++;
++                break;
++            case ' ':
++                flags |= DP_F_SPACE;
++                ch = *format++;
++                break;
++            case '#':
++                flags |= DP_F_NUM;
++                ch = *format++;
++                break;
++            case '0':
++                flags |= DP_F_ZERO;
++                ch = *format++;
++                break;
++            default:
++                state = DP_S_MIN;
++                break;
++            }
++            break;
++        case DP_S_MIN:
++            if (isdigit((unsigned char)ch)) {
++                min = 10 * min + char_to_int(ch);
++                ch = *format++;
++            } else if (ch == '*') {
++                min = va_arg(args, int);
++                ch = *format++;
++                state = DP_S_DOT;
++            } else
++                state = DP_S_DOT;
++            break;
++        case DP_S_DOT:
++            if (ch == '.') {
++                state = DP_S_MAX;
++                ch = *format++;
++            } else
++                state = DP_S_MOD;
++            break;
++        case DP_S_MAX:
++            if (isdigit((unsigned char)ch)) {
++                if (max < 0)
++                    max = 0;
++                max = 10 * max + char_to_int(ch);
++                ch = *format++;
++            } else if (ch == '*') {
++                max = va_arg(args, int);
++                ch = *format++;
++                state = DP_S_MOD;
++            } else
++                state = DP_S_MOD;
++            break;
++        case DP_S_MOD:
++            switch (ch) {
++            case 'h':
++                cflags = DP_C_SHORT;
++                ch = *format++;
++                break;
++            case 'l':
++                if (*format == 'l') {
++                    cflags = DP_C_LLONG;
++                    format++;
++                } else
++                    cflags = DP_C_LONG;
++                ch = *format++;
++                break;
++            case 'q':
++                cflags = DP_C_LLONG;
++                ch = *format++;
++                break;
++            case 'L':
++                cflags = DP_C_LDOUBLE;
++                ch = *format++;
++                break;
++            default:
++                break;
++            }
++            state = DP_S_CONV;
++            break;
++        case DP_S_CONV:
++            switch (ch) {
++            case 'd':
++            case 'i':
++                switch (cflags) {
++                case DP_C_SHORT:
++                    value = (short int)va_arg(args, int);
++                    break;
++                case DP_C_LONG:
++                    value = va_arg(args, long int);
++                    break;
++                case DP_C_LLONG:
++                    value = va_arg(args, LLONG);
++                    break;
++                default:
++                    value = va_arg(args, int);
++                    break;
++                }
++                if (!fmtint(sbuffer, buffer, &currlen, maxlen, value, 10, min,
++                            max, flags))
++                    return 0;
++                break;
++            case 'X':
++                flags |= DP_F_UP;
++                /* FALLTHROUGH */
++            case 'x':
++            case 'o':
++            case 'u':
++                flags |= DP_F_UNSIGNED;
++                switch (cflags) {
++                case DP_C_SHORT:
++                    value = (unsigned short int)va_arg(args, unsigned int);
++                    break;
++                case DP_C_LONG:
++                    value = (LLONG) va_arg(args, unsigned long int);
++                    break;
++                case DP_C_LLONG:
++                    value = va_arg(args, unsigned LLONG);
++                    break;
++                default:
++                    value = (LLONG) va_arg(args, unsigned int);
++                    break;
++                }
++                if (!fmtint(sbuffer, buffer, &currlen, maxlen, value,
++                            ch == 'o' ? 8 : (ch == 'u' ? 10 : 16),
++                            min, max, flags))
++                    return 0;
++                break;
++            case 'f':
++                if (cflags == DP_C_LDOUBLE)
++                    fvalue = va_arg(args, LDOUBLE);
++                else
++                    fvalue = va_arg(args, double);
++                if (!fmtfp(sbuffer, buffer, &currlen, maxlen, fvalue, min, max,
++                           flags, F_FORMAT))
++                    return 0;
++                break;
++            case 'E':
++                flags |= DP_F_UP;
++            case 'e':
++                if (cflags == DP_C_LDOUBLE)
++                    fvalue = va_arg(args, LDOUBLE);
++                else
++                    fvalue = va_arg(args, double);
++                if (!fmtfp(sbuffer, buffer, &currlen, maxlen, fvalue, min, max,
++                           flags, E_FORMAT))
++                    return 0;
++                break;
++            case 'G':
++                flags |= DP_F_UP;
++            case 'g':
++                if (cflags == DP_C_LDOUBLE)
++                    fvalue = va_arg(args, LDOUBLE);
++                else
++                    fvalue = va_arg(args, double);
++                if (!fmtfp(sbuffer, buffer, &currlen, maxlen, fvalue, min, max,
++                           flags, G_FORMAT))
++                    return 0;
++                break;
++            case 'c':
++                if(!doapr_outch(sbuffer, buffer, &currlen, maxlen,
++                            va_arg(args, int)))
++                    return 0;
++                break;
++            case 's':
++                strvalue = va_arg(args, char *);
++                if (max < 0) {
++                    if (buffer)
++                        max = INT_MAX;
++                    else
++                        max = *maxlen;
++                }
++                if (!fmtstr(sbuffer, buffer, &currlen, maxlen, strvalue,
++                            flags, min, max))
++                    return 0;
++                break;
++            case 'p':
++                value = (size_t)va_arg(args, void *);
++                if (!fmtint(sbuffer, buffer, &currlen, maxlen,
++                            value, 16, min, max, flags | DP_F_NUM))
++                    return 0;
++                break;
++            case 'n':          /* XXX */
++                if (cflags == DP_C_SHORT) {
++                    short int *num;
++                    num = va_arg(args, short int *);
++                    *num = currlen;
++                } else if (cflags == DP_C_LONG) { /* XXX */
++                    long int *num;
++                    num = va_arg(args, long int *);
++                    *num = (long int)currlen;
++                } else if (cflags == DP_C_LLONG) { /* XXX */
++                    LLONG *num;
++                    num = va_arg(args, LLONG *);
++                    *num = (LLONG) currlen;
++                } else {
++                    int *num;
++                    num = va_arg(args, int *);
++                    *num = currlen;
++                }
++                break;
++            case '%':
++                if(!doapr_outch(sbuffer, buffer, &currlen, maxlen, ch))
++                    return 0;
++                break;
++            case 'w':
++                /* not supported yet, treat as next char */
++                ch = *format++;
++                break;
++            default:
++                /* unknown, skip */
++                break;
++            }
++            ch = *format++;
++            state = DP_S_DEFAULT;
++            flags = cflags = min = 0;
++            max = -1;
++            break;
++        case DP_S_DONE:
++            break;
++        default:
++            break;
++        }
++    }
++    /*
++     * We have to truncate if there is no dynamic buffer and we have filled the
++     * static buffer.
++     */
++    if (buffer == NULL) {
++        *truncated = (currlen > *maxlen - 1);
++        if (*truncated)
++            currlen = *maxlen - 1;
++    }
++    if(!doapr_outch(sbuffer, buffer, &currlen, maxlen, '\0'))
++        return 0;
++    *retlen = currlen - 1;
++    return 1;
++}
++
++static int
++fmtstr(char **sbuffer,
++       char **buffer,
++       size_t *currlen,
++       size_t *maxlen, const char *value, int flags, int min, int max)
++{
++    int padlen;
++    size_t strln;
++    int cnt = 0;
++
++    if (value == 0)
++        value = "";
++
++    strln = OPENSSL_strnlen(value, max < 0 ? SIZE_MAX : (size_t)max);
++
++    padlen = min - strln;
++    if (min < 0 || padlen < 0)
++        padlen = 0;
++    if (max >= 0) {
++        /*
++         * Calculate the maximum output including padding.
++         * Make sure max doesn't overflow into negativity
++         */
++        if (max < INT_MAX - padlen)
++            max += padlen;
++        else
++            max = INT_MAX;
++    }
++    if (flags & DP_F_MINUS)
++        padlen = -padlen;
++
++    while ((padlen > 0) && (max < 0 || cnt < max)) {
++        if(!doapr_outch(sbuffer, buffer, currlen, maxlen, ' '))
++            return 0;
++        --padlen;
++        ++cnt;
++    }
++    while (strln > 0 && (max < 0 || cnt < max)) {
++        if(!doapr_outch(sbuffer, buffer, currlen, maxlen, *value++))
++            return 0;
++        --strln;
++        ++cnt;
++    }
++    while ((padlen < 0) && (max < 0 || cnt < max)) {
++        if(!doapr_outch(sbuffer, buffer, currlen, maxlen, ' '))
++            return 0;
++        ++padlen;
++        ++cnt;
++    }
++    return 1;
++}
++
++static int
++fmtint(char **sbuffer,
++       char **buffer,
++       size_t *currlen,
++       size_t *maxlen, LLONG value, int base, int min, int max, int flags)
++{
++    int signvalue = 0;
++    const char *prefix = "";
++    unsigned LLONG uvalue;
++    char convert[DECIMAL_SIZE(value) + 3];
++    int place = 0;
++    int spadlen = 0;
++    int zpadlen = 0;
++    int caps = 0;
++
++    if (max < 0)
++        max = 0;
++    uvalue = value;
++    if (!(flags & DP_F_UNSIGNED)) {
++        if (value < 0) {
++            signvalue = '-';
++            uvalue = 0 - (unsigned LLONG)value;
++        } else if (flags & DP_F_PLUS)
++            signvalue = '+';
++        else if (flags & DP_F_SPACE)
++            signvalue = ' ';
++    }
++    if (flags & DP_F_NUM) {
++        if (base == 8)
++            prefix = "0";
++        if (base == 16)
++            prefix = "0x";
++    }
++    if (flags & DP_F_UP)
++        caps = 1;
++    do {
++        convert[place++] = (caps ? "0123456789ABCDEF" : "0123456789abcdef")
++            [uvalue % (unsigned)base];
++        uvalue = (uvalue / (unsigned)base);
++    } while (uvalue && (place < (int)sizeof(convert)));
++    if (place == sizeof(convert))
++        place--;
++    convert[place] = 0;
++
++    zpadlen = max - place;
++    spadlen =
++        min - OSSL_MAX(max, place) - (signvalue ? 1 : 0) - strlen(prefix);
++    if (zpadlen < 0)
++        zpadlen = 0;
++    if (spadlen < 0)
++        spadlen = 0;
++    if (flags & DP_F_ZERO) {
++        zpadlen = OSSL_MAX(zpadlen, spadlen);
++        spadlen = 0;
++    }
++    if (flags & DP_F_MINUS)
++        spadlen = -spadlen;
++
++    /* spaces */
++    while (spadlen > 0) {
++        if(!doapr_outch(sbuffer, buffer, currlen, maxlen, ' '))
++            return 0;
++        --spadlen;
++    }
++
++    /* sign */
++    if (signvalue)
++        if(!doapr_outch(sbuffer, buffer, currlen, maxlen, signvalue))
++            return 0;
++
++    /* prefix */
++    while (*prefix) {
++        if(!doapr_outch(sbuffer, buffer, currlen, maxlen, *prefix))
++            return 0;
++        prefix++;
++    }
++
++    /* zeros */
++    if (zpadlen > 0) {
++        while (zpadlen > 0) {
++            if(!doapr_outch(sbuffer, buffer, currlen, maxlen, '0'))
++                return 0;
++            --zpadlen;
++        }
++    }
++    /* digits */
++    while (place > 0) {
++        if (!doapr_outch(sbuffer, buffer, currlen, maxlen, convert[--place]))
++            return 0;
++    }
++
++    /* left justified spaces */
++    while (spadlen < 0) {
++        if (!doapr_outch(sbuffer, buffer, currlen, maxlen, ' '))
++            return 0;
++        ++spadlen;
++    }
++    return 1;
++}
++
++static LDOUBLE abs_val(LDOUBLE value)
++{
++    LDOUBLE result = value;
++    if (value < 0)
++        result = -value;
++    return result;
++}
++
++static LDOUBLE pow_10(int in_exp)
++{
++    LDOUBLE result = 1;
++    while (in_exp) {
++        result *= 10;
++        in_exp--;
++    }
++    return result;
++}
++
++static long roundv(LDOUBLE value)
++{
++    long intpart;
++    intpart = (long)value;
++    value = value - intpart;
++    if (value >= 0.5)
++        intpart++;
++    return intpart;
++}
++
++static int
++fmtfp(char **sbuffer,
++      char **buffer,
++      size_t *currlen,
++      size_t *maxlen, LDOUBLE fvalue, int min, int max, int flags, int style)
++{
++    int signvalue = 0;
++    LDOUBLE ufvalue;
++    LDOUBLE tmpvalue;
++    char iconvert[20];
++    char fconvert[20];
++    char econvert[20];
++    int iplace = 0;
++    int fplace = 0;
++    int eplace = 0;
++    int padlen = 0;
++    int zpadlen = 0;
++    long exp = 0;
++    unsigned long intpart;
++    unsigned long fracpart;
++    unsigned long max10;
++    int realstyle;
++
++    if (max < 0)
++        max = 6;
++
++    if (fvalue < 0)
++        signvalue = '-';
++    else if (flags & DP_F_PLUS)
++        signvalue = '+';
++    else if (flags & DP_F_SPACE)
++        signvalue = ' ';
++
++    /*
++     * G_FORMAT sometimes prints like E_FORMAT and sometimes like F_FORMAT
++     * depending on the number to be printed. Work out which one it is and use
++     * that from here on.
++     */
++    if (style == G_FORMAT) {
++        if (fvalue == 0.0) {
++            realstyle = F_FORMAT;
++        } else if (fvalue < 0.0001) {
++            realstyle = E_FORMAT;
++        } else if ((max == 0 && fvalue >= 10)
++                    || (max > 0 && fvalue >= pow_10(max))) {
++            realstyle = E_FORMAT;
++        } else {
++            realstyle = F_FORMAT;
++        }
++    } else {
++        realstyle = style;
++    }
++
++    if (style != F_FORMAT) {
++        tmpvalue = fvalue;
++        /* Calculate the exponent */
++        if (fvalue != 0.0) {
++            while (tmpvalue < 1) {
++                tmpvalue *= 10;
++                exp--;
++            }
++            while (tmpvalue > 10) {
++                tmpvalue /= 10;
++                exp++;
++            }
++        }
++        if (style == G_FORMAT) {
++            /*
++             * In G_FORMAT the "precision" represents significant digits. We
++             * always have at least 1 significant digit.
++             */
++            if (max == 0)
++                max = 1;
++            /* Now convert significant digits to decimal places */
++            if (realstyle == F_FORMAT) {
++                max -= (exp + 1);
++                if (max < 0) {
++                    /*
++                     * Should not happen. If we're in F_FORMAT then exp < max?
++                     */
++                    return 0;
++                }
++            } else {
++                /*
++                 * In E_FORMAT there is always one significant digit in front
++                 * of the decimal point, so:
++                 * significant digits == 1 + decimal places
++                 */
++                max--;
++            }
++        }
++        if (realstyle == E_FORMAT)
++            fvalue = tmpvalue;
++    }
++    ufvalue = abs_val(fvalue);
++    if (ufvalue > ULONG_MAX) {
++        /* Number too big */
++        return 0;
++    }
++    intpart = (unsigned long)ufvalue;
++
++    /*
++     * sorry, we only support 9 digits past the decimal because of our
++     * conversion method
++     */
++    if (max > 9)
++        max = 9;
++
++    /*
++     * we "cheat" by converting the fractional part to integer by multiplying
++     * by a factor of 10
++     */
++    max10 = roundv(pow_10(max));
++    fracpart = roundv(pow_10(max) * (ufvalue - intpart));
++
++    if (fracpart >= max10) {
++        intpart++;
++        fracpart -= max10;
++    }
++
++    /* convert integer part */
++    do {
++        iconvert[iplace++] = "0123456789"[intpart % 10];
++        intpart = (intpart / 10);
++    } while (intpart && (iplace < (int)sizeof(iconvert)));
++    if (iplace == sizeof iconvert)
++        iplace--;
++    iconvert[iplace] = 0;
++
++    /* convert fractional part */
++    while (fplace < max) {
++        if (style == G_FORMAT && fplace == 0 && (fracpart % 10) == 0) {
++            /* We strip trailing zeros in G_FORMAT */
++            max--;
++            fracpart = fracpart / 10;
++            if (fplace < max)
++                continue;
++            break;
++        }
++        fconvert[fplace++] = "0123456789"[fracpart % 10];
++        fracpart = (fracpart / 10);
++    }
++
++    if (fplace == sizeof fconvert)
++        fplace--;
++    fconvert[fplace] = 0;
++
++    /* convert exponent part */
++    if (realstyle == E_FORMAT) {
++        int tmpexp;
++        if (exp < 0)
++            tmpexp = -exp;
++        else
++            tmpexp = exp;
++
++        do {
++            econvert[eplace++] = "0123456789"[tmpexp % 10];
++            tmpexp = (tmpexp / 10);
++        } while (tmpexp > 0 && eplace < (int)sizeof(econvert));
++        /* Exponent is huge!! Too big to print */
++        if (tmpexp > 0)
++            return 0;
++        /* Add a leading 0 for single digit exponents */
++        if (eplace == 1)
++            econvert[eplace++] = '0';
++    }
++
++    /*
++     * -1 for decimal point (if we have one, i.e. max > 0),
++     * another -1 if we are printing a sign
++     */
++    padlen = min - iplace - max - (max > 0 ? 1 : 0) - ((signvalue) ? 1 : 0);
++    /* Take some off for exponent prefix "+e" and exponent */
++    if (realstyle == E_FORMAT)
++        padlen -= 2 + eplace;
++    zpadlen = max - fplace;
++    if (zpadlen < 0)
++        zpadlen = 0;
++    if (padlen < 0)
++        padlen = 0;
++    if (flags & DP_F_MINUS)
++        padlen = -padlen;
++
++    if ((flags & DP_F_ZERO) && (padlen > 0)) {
++        if (signvalue) {
++            if (!doapr_outch(sbuffer, buffer, currlen, maxlen, signvalue))
++                return 0;
++            --padlen;
++            signvalue = 0;
++        }
++        while (padlen > 0) {
++            if (!doapr_outch(sbuffer, buffer, currlen, maxlen, '0'))
++                return 0;
++            --padlen;
++        }
++    }
++    while (padlen > 0) {
++        if (!doapr_outch(sbuffer, buffer, currlen, maxlen, ' '))
++            return 0;
++        --padlen;
++    }
++    if (signvalue && !doapr_outch(sbuffer, buffer, currlen, maxlen, signvalue))
++        return 0;
++
++    while (iplace > 0) {
++        if (!doapr_outch(sbuffer, buffer, currlen, maxlen, iconvert[--iplace]))
++            return 0;
++    }
++
++    /*
++     * Decimal point. This should probably use locale to find the correct
++     * char to print out.
++     */
++    if (max > 0 || (flags & DP_F_NUM)) {
++        if (!doapr_outch(sbuffer, buffer, currlen, maxlen, '.'))
++            return 0;
++
++        while (fplace > 0) {
++            if(!doapr_outch(sbuffer, buffer, currlen, maxlen,
++                            fconvert[--fplace]))
++                return 0;
++        }
++    }
++    while (zpadlen > 0) {
++        if (!doapr_outch(sbuffer, buffer, currlen, maxlen, '0'))
++            return 0;
++        --zpadlen;
++    }
++    if (realstyle == E_FORMAT) {
++        char ech;
++
++        if ((flags & DP_F_UP) == 0)
++            ech = 'e';
++        else
++            ech = 'E';
++        if (!doapr_outch(sbuffer, buffer, currlen, maxlen, ech))
++                return 0;
++        if (exp < 0) {
++            if (!doapr_outch(sbuffer, buffer, currlen, maxlen, '-'))
++                    return 0;
++        } else {
++            if (!doapr_outch(sbuffer, buffer, currlen, maxlen, '+'))
++                    return 0;
++        }
++        while (eplace > 0) {
++            if (!doapr_outch(sbuffer, buffer, currlen, maxlen,
++                             econvert[--eplace]))
++                return 0;
++        }
++    }
++
++    while (padlen < 0) {
++        if (!doapr_outch(sbuffer, buffer, currlen, maxlen, ' '))
++            return 0;
++        ++padlen;
++    }
++    return 1;
++}
++
++#define BUFFER_INC  1024
++
++static int
++doapr_outch(char **sbuffer,
++            char **buffer, size_t *currlen, size_t *maxlen, int c)
++{
++    /* If we haven't at least one buffer, someone has doe a big booboo */
++    OPENSSL_assert(*sbuffer != NULL || buffer != NULL);
++
++    /* |currlen| must always be <= |*maxlen| */
++    OPENSSL_assert(*currlen <= *maxlen);
++
++    if (buffer && *currlen == *maxlen) {
++        if (*maxlen > INT_MAX - BUFFER_INC)
++            return 0;
++
++        *maxlen += BUFFER_INC;
++        if (*buffer == NULL) {
++            *buffer = OPENSSL_malloc(*maxlen);
++            if (*buffer == NULL)
++                return 0;
++            if (*currlen > 0) {
++                OPENSSL_assert(*sbuffer != NULL);
++                memcpy(*buffer, *sbuffer, *currlen);
++            }
++            *sbuffer = NULL;
++        } else {
++            char *tmpbuf;
++            tmpbuf = OPENSSL_realloc(*buffer, *maxlen);
++            if (tmpbuf == NULL)
++                return 0;
++            *buffer = tmpbuf;
++        }
++    }
++
++    if (*currlen < *maxlen) {
++        if (*sbuffer)
++            (*sbuffer)[(*currlen)++] = (char)c;
++        else
++            (*buffer)[(*currlen)++] = (char)c;
++    }
++
++    return 1;
++}
++
++/***************************************************************************/
++
++int BIO_printf(BIO *bio, const char *format, ...)
++{
++    va_list args;
++    int ret;
++
++    va_start(args, format);
++
++    ret = BIO_vprintf(bio, format, args);
++
++    va_end(args);
++    return (ret);
++}
++
++int BIO_vprintf(BIO *bio, const char *format, va_list args)
++{
++    int ret;
++    size_t retlen;
++    char hugebuf[1024 * 2];     /* Was previously 10k, which is unreasonable
++                                 * in small-stack environments, like threads
++                                 * or DOS programs. */
++    char *hugebufp = hugebuf;
++    size_t hugebufsize = sizeof(hugebuf);
++    char *dynbuf = NULL;
++    int ignored;
++
++    dynbuf = NULL;
++    if (!_dopr(&hugebufp, &dynbuf, &hugebufsize, &retlen, &ignored, format,
++                args)) {
++        OPENSSL_free(dynbuf);
++        return -1;
++    }
++    if (dynbuf) {
++        ret = BIO_write(bio, dynbuf, (int)retlen);
++        OPENSSL_free(dynbuf);
++    } else {
++        ret = BIO_write(bio, hugebuf, (int)retlen);
++    }
++    return (ret);
++}
++
++/*
++ * As snprintf is not available everywhere, we provide our own
++ * implementation. This function has nothing to do with BIOs, but it's
++ * closely related to BIO_printf, and we need *some* name prefix ... (XXX the
++ * function should be renamed, but to what?)
++ */
++int BIO_snprintf(char *buf, size_t n, const char *format, ...)
++{
++    va_list args;
++    int ret;
++
++    va_start(args, format);
++
++    ret = BIO_vsnprintf(buf, n, format, args);
++
++    va_end(args);
++    return (ret);
++}
++
++int BIO_vsnprintf(char *buf, size_t n, const char *format, va_list args)
++{
++    size_t retlen;
++    int truncated;
++
++    if(!_dopr(&buf, NULL, &n, &retlen, &truncated, format, args))
++        return -1;
++
++    if (truncated)
++        /*
++         * In case of truncation, return -1 like traditional snprintf.
++         * (Current drafts for ISO/IEC 9899 say snprintf should return the
++         * number of characters that would have been written, had the buffer
++         * been large enough.)
++         */
++        return -1;
++    else
++        return (retlen <= INT_MAX) ? (int)retlen : -1;
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/bio/b_sock.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/bio/b_sock.c
+new file mode 100644
+index 0000000..ac2c2d1
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/bio/b_sock.c
+@@ -0,0 +1,381 @@
++/*
++ * Copyright 1995-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include 
++#include 
++#include "bio_lcl.h"
++#if defined(NETWARE_CLIB)
++# include 
++NETDB_DEFINE_CONTEXT
++#endif
++#ifndef OPENSSL_NO_SOCK
++# define SOCKET_PROTOCOL IPPROTO_TCP
++# ifdef SO_MAXCONN
++#  define MAX_LISTEN  SO_MAXCONN
++# elif defined(SOMAXCONN)
++#  define MAX_LISTEN  SOMAXCONN
++# else
++#  define MAX_LISTEN  32
++# endif
++# if defined(OPENSSL_SYS_WINDOWS)
++static int wsa_init_done = 0;
++# endif
++
++# if OPENSSL_API_COMPAT < 0x10100000L
++int BIO_get_host_ip(const char *str, unsigned char *ip)
++{
++    BIO_ADDRINFO *res = NULL;
++    int ret = 0;
++
++    if (BIO_sock_init() != 1)
++        return 0;               /* don't generate another error code here */
++
++    if (BIO_lookup(str, NULL, BIO_LOOKUP_CLIENT, AF_INET, SOCK_STREAM, &res)) {
++        size_t l;
++
++        if (BIO_ADDRINFO_family(res) != AF_INET) {
++            BIOerr(BIO_F_BIO_GET_HOST_IP,
++                   BIO_R_GETHOSTBYNAME_ADDR_IS_NOT_AF_INET);
++        } else {
++            BIO_ADDR_rawaddress(BIO_ADDRINFO_address(res), NULL, &l);
++            /* Because only AF_INET addresses will reach this far,
++               we can assert that l should be 4 */
++            OPENSSL_assert(l == 4);
++
++            BIO_ADDR_rawaddress(BIO_ADDRINFO_address(res), ip, &l);
++            ret = 1;
++        }
++        BIO_ADDRINFO_free(res);
++    } else {
++        ERR_add_error_data(2, "host=", str);
++    }
++
++    return ret;
++}
++
++int BIO_get_port(const char *str, unsigned short *port_ptr)
++{
++    BIO_ADDRINFO *res = NULL;
++    int ret = 0;
++
++    if (str == NULL) {
++        BIOerr(BIO_F_BIO_GET_PORT, BIO_R_NO_PORT_DEFINED);
++        return (0);
++    }
++
++    if (BIO_sock_init() != 1)
++        return 0;               /* don't generate another error code here */
++
++    if (BIO_lookup(NULL, str, BIO_LOOKUP_CLIENT, AF_INET, SOCK_STREAM, &res)) {
++        if (BIO_ADDRINFO_family(res) != AF_INET) {
++            BIOerr(BIO_F_BIO_GET_PORT,
++                   BIO_R_ADDRINFO_ADDR_IS_NOT_AF_INET);
++        } else {
++            *port_ptr = ntohs(BIO_ADDR_rawport(BIO_ADDRINFO_address(res)));
++            ret = 1;
++        }
++        BIO_ADDRINFO_free(res);
++    } else {
++        ERR_add_error_data(2, "host=", str);
++    }
++
++    return ret;
++}
++# endif
++
++int BIO_sock_error(int sock)
++{
++    int j = 0, i;
++    socklen_t size = sizeof(j);
++
++    /*
++     * Note: under Windows the third parameter is of type (char *) whereas
++     * under other systems it is (void *) if you don't have a cast it will
++     * choke the compiler: if you do have a cast then you can either go for
++     * (char *) or (void *).
++     */
++    i = getsockopt(sock, SOL_SOCKET, SO_ERROR, (void *)&j, &size);
++    if (i < 0)
++        return (get_last_socket_error());
++    else
++        return (j);
++}
++
++# if OPENSSL_API_COMPAT < 0x10100000L
++struct hostent *BIO_gethostbyname(const char *name)
++{
++    /*
++     * Caching gethostbyname() results forever is wrong, so we have to let
++     * the true gethostbyname() worry about this
++     */
++#  if (defined(NETWARE_BSDSOCK) && !defined(__NOVELL_LIBC__))
++    return gethostbyname((char *)name);
++#  else
++    return gethostbyname(name);
++#  endif
++}
++# endif
++
++int BIO_sock_init(void)
++{
++# ifdef OPENSSL_SYS_WINDOWS
++    static struct WSAData wsa_state;
++
++    if (!wsa_init_done) {
++        int err;
++
++        wsa_init_done = 1;
++        memset(&wsa_state, 0, sizeof(wsa_state));
++        /*
++         * Not making wsa_state available to the rest of the code is formally
++         * wrong. But the structures we use are [believed to be] invariable
++         * among Winsock DLLs, while API availability is [expected to be]
++         * probed at run-time with DSO_global_lookup.
++         */
++        if (WSAStartup(0x0202, &wsa_state) != 0) {
++            err = WSAGetLastError();
++            SYSerr(SYS_F_WSASTARTUP, err);
++            BIOerr(BIO_F_BIO_SOCK_INIT, BIO_R_WSASTARTUP);
++            return (-1);
++        }
++    }
++# endif                         /* OPENSSL_SYS_WINDOWS */
++# ifdef WATT32
++    extern int _watt_do_exit;
++    _watt_do_exit = 0;          /* don't make sock_init() call exit() */
++    if (sock_init())
++        return (-1);
++# endif
++
++    return (1);
++}
++
++void bio_sock_cleanup_int(void)
++{
++# ifdef OPENSSL_SYS_WINDOWS
++    if (wsa_init_done) {
++        wsa_init_done = 0;
++        WSACleanup();
++    }
++# endif
++}
++
++# if !defined(OPENSSL_SYS_VMS) || __VMS_VER >= 70000000
++
++int BIO_socket_ioctl(int fd, long type, void *arg)
++{
++    int i;
++
++#  ifdef __DJGPP__
++    i = ioctlsocket(fd, type, (char *)arg);
++#  else
++#   if defined(OPENSSL_SYS_VMS)
++    /*-
++     * 2011-02-18 SMS.
++     * VMS ioctl() can't tolerate a 64-bit "void *arg", but we
++     * observe that all the consumers pass in an "unsigned long *",
++     * so we arrange a local copy with a short pointer, and use
++     * that, instead.
++     */
++#    if __INITIAL_POINTER_SIZE == 64
++#     define ARG arg_32p
++#     pragma pointer_size save
++#     pragma pointer_size 32
++    unsigned long arg_32;
++    unsigned long *arg_32p;
++#     pragma pointer_size restore
++    arg_32p = &arg_32;
++    arg_32 = *((unsigned long *)arg);
++#    else                       /* __INITIAL_POINTER_SIZE == 64 */
++#     define ARG arg
++#    endif                      /* __INITIAL_POINTER_SIZE == 64 [else] */
++#   else                        /* defined(OPENSSL_SYS_VMS) */
++#    define ARG arg
++#   endif                       /* defined(OPENSSL_SYS_VMS) [else] */
++
++    i = ioctlsocket(fd, type, ARG);
++#  endif                        /* __DJGPP__ */
++    if (i < 0)
++        SYSerr(SYS_F_IOCTLSOCKET, get_last_socket_error());
++    return (i);
++}
++# endif                         /* __VMS_VER */
++
++# if OPENSSL_API_COMPAT < 0x10100000L
++int BIO_get_accept_socket(char *host, int bind_mode)
++{
++    int s = INVALID_SOCKET;
++    char *h = NULL, *p = NULL;
++    BIO_ADDRINFO *res = NULL;
++
++    if (!BIO_parse_hostserv(host, &h, &p, BIO_PARSE_PRIO_SERV))
++        return INVALID_SOCKET;
++
++    if (BIO_sock_init() != 1)
++        return INVALID_SOCKET;
++
++    if (BIO_lookup(h, p, BIO_LOOKUP_SERVER, AF_UNSPEC, SOCK_STREAM, &res) != 0)
++        goto err;
++
++    if ((s = BIO_socket(BIO_ADDRINFO_family(res), BIO_ADDRINFO_socktype(res),
++                        BIO_ADDRINFO_protocol(res), 0)) == INVALID_SOCKET) {
++        s = INVALID_SOCKET;
++        goto err;
++    }
++
++    if (!BIO_listen(s, BIO_ADDRINFO_address(res),
++                    bind_mode ? BIO_SOCK_REUSEADDR : 0)) {
++        BIO_closesocket(s);
++        s = INVALID_SOCKET;
++    }
++
++ err:
++    BIO_ADDRINFO_free(res);
++    OPENSSL_free(h);
++    OPENSSL_free(p);
++
++    return s;
++}
++
++int BIO_accept(int sock, char **ip_port)
++{
++    BIO_ADDR res;
++    int ret = -1;
++
++    ret = BIO_accept_ex(sock, &res, 0);
++    if (ret == (int)INVALID_SOCKET) {
++        if (BIO_sock_should_retry(ret)) {
++            ret = -2;
++            goto end;
++        }
++        SYSerr(SYS_F_ACCEPT, get_last_socket_error());
++        BIOerr(BIO_F_BIO_ACCEPT, BIO_R_ACCEPT_ERROR);
++        goto end;
++    }
++
++    if (ip_port != NULL) {
++        char *host = BIO_ADDR_hostname_string(&res, 1);
++        char *port = BIO_ADDR_service_string(&res, 1);
++        if (host != NULL && port != NULL)
++            *ip_port = OPENSSL_zalloc(strlen(host) + strlen(port) + 2);
++        else
++            *ip_port = NULL;
++
++        if (*ip_port == NULL) {
++            BIOerr(BIO_F_BIO_ACCEPT, ERR_R_MALLOC_FAILURE);
++            BIO_closesocket(ret);
++            ret = (int)INVALID_SOCKET;
++        } else {
++            strcpy(*ip_port, host);
++            strcat(*ip_port, ":");
++            strcat(*ip_port, port);
++        }
++        OPENSSL_free(host);
++        OPENSSL_free(port);
++    }
++
++ end:
++    return ret;
++}
++# endif
++
++int BIO_set_tcp_ndelay(int s, int on)
++{
++    int ret = 0;
++# if defined(TCP_NODELAY) && (defined(IPPROTO_TCP) || defined(SOL_TCP))
++    int opt;
++
++#  ifdef SOL_TCP
++    opt = SOL_TCP;
++#  else
++#   ifdef IPPROTO_TCP
++    opt = IPPROTO_TCP;
++#   endif
++#  endif
++
++    ret = setsockopt(s, opt, TCP_NODELAY, (char *)&on, sizeof(on));
++# endif
++    return (ret == 0);
++}
++
++int BIO_socket_nbio(int s, int mode)
++{
++    int ret = -1;
++    int l;
++
++    l = mode;
++# ifdef FIONBIO
++    l = mode;
++
++    ret = BIO_socket_ioctl(s, FIONBIO, &l);
++# elif defined(F_GETFL) && defined(F_SETFL) && (defined(O_NONBLOCK) || defined(FNDELAY))
++    /* make sure this call always pushes an error level; BIO_socket_ioctl() does so, so we do too. */
++
++    l = fcntl(s, F_GETFL, 0);
++    if (l == -1) {
++        SYSerr(SYS_F_FCNTL, get_last_rtl_error());
++        ret = -1;
++    } else {
++#  if defined(O_NONBLOCK)
++        l &= ~O_NONBLOCK;
++#  else
++        l &= ~FNDELAY; /* BSD4.x */
++#  endif
++        if (mode) {
++#  if defined(O_NONBLOCK)
++            l |= O_NONBLOCK;
++#  else
++            l |= FNDELAY; /* BSD4.x */
++#  endif
++        }
++        ret = fcntl(s, F_SETFL, l);
++
++        if (ret < 0) {
++            SYSerr(SYS_F_FCNTL, get_last_rtl_error());
++        }
++    }
++# else
++    /* make sure this call always pushes an error level; BIO_socket_ioctl() does so, so we do too. */
++    BIOerr(BIO_F_BIO_SOCKET_NBIO, ERR_R_PASSED_INVALID_ARGUMENT);
++# endif
++
++    return (ret == 0);
++}
++
++int BIO_sock_info(int sock,
++                  enum BIO_sock_info_type type, union BIO_sock_info_u *info)
++{
++    switch (type) {
++    case BIO_SOCK_INFO_ADDRESS:
++        {
++            socklen_t addr_len;
++            int ret = 0;
++            addr_len = sizeof(*info->addr);
++            ret = getsockname(sock, BIO_ADDR_sockaddr_noconst(info->addr),
++                              &addr_len);
++            if (ret == -1) {
++                SYSerr(SYS_F_GETSOCKNAME, get_last_socket_error());
++                BIOerr(BIO_F_BIO_SOCK_INFO, BIO_R_GETSOCKNAME_ERROR);
++                return 0;
++            }
++            if ((size_t)addr_len > sizeof(*info->addr)) {
++                BIOerr(BIO_F_BIO_SOCK_INFO, BIO_R_GETSOCKNAME_TRUNCATED_ADDRESS);
++                return 0;
++            }
++        }
++        break;
++    default:
++        BIOerr(BIO_F_BIO_SOCK_INFO, BIO_R_UNKNOWN_INFO_TYPE);
++        return 0;
++    }
++    return 1;
++}
++
++#endif
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/bio/b_sock2.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/bio/b_sock2.c
+new file mode 100644
+index 0000000..7f4d89e
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/bio/b_sock2.c
+@@ -0,0 +1,270 @@
++/*
++ * Copyright 2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include 
++#include 
++
++#include "bio_lcl.h"
++
++#include 
++
++#ifndef OPENSSL_NO_SOCK
++# ifdef SO_MAXCONN
++#  define MAX_LISTEN  SO_MAXCONN
++# elif defined(SOMAXCONN)
++#  define MAX_LISTEN  SOMAXCONN
++# else
++#  define MAX_LISTEN  32
++# endif
++
++/*-
++ * BIO_socket - create a socket
++ * @domain: the socket domain (AF_INET, AF_INET6, AF_UNIX, ...)
++ * @socktype: the socket type (SOCK_STEAM, SOCK_DGRAM)
++ * @protocol: the protocol to use (IPPROTO_TCP, IPPROTO_UDP)
++ * @options: BIO socket options (currently unused)
++ *
++ * Creates a socket.  This should be called before calling any
++ * of BIO_connect and BIO_listen.
++ *
++ * Returns the file descriptor on success or INVALID_SOCKET on failure.  On
++ * failure errno is set, and a status is added to the OpenSSL error stack.
++ */
++int BIO_socket(int domain, int socktype, int protocol, int options)
++{
++    int sock = -1;
++
++    if (BIO_sock_init() != 1)
++        return INVALID_SOCKET;
++
++    sock = socket(domain, socktype, protocol);
++    if (sock == -1) {
++        SYSerr(SYS_F_SOCKET, get_last_socket_error());
++        BIOerr(BIO_F_BIO_SOCKET, BIO_R_UNABLE_TO_CREATE_SOCKET);
++        return INVALID_SOCKET;
++    }
++
++    return sock;
++}
++
++/*-
++ * BIO_connect - connect to an address
++ * @sock: the socket to connect with
++ * @addr: the address to connect to
++ * @options: BIO socket options
++ *
++ * Connects to the address using the given socket and options.
++ *
++ * Options can be a combination of the following:
++ * - BIO_SOCK_KEEPALIVE: enable regularly sending keep-alive messages.
++ * - BIO_SOCK_NONBLOCK: Make the socket non-blocking.
++ * - BIO_SOCK_NODELAY: don't delay small messages.
++ *
++ * options holds BIO socket options that can be used
++ * You should call this for every address returned by BIO_lookup
++ * until the connection is successful.
++ *
++ * Returns 1 on success or 0 on failure.  On failure errno is set
++ * and an error status is added to the OpenSSL error stack.
++ */
++int BIO_connect(int sock, const BIO_ADDR *addr, int options)
++{
++    int on = 1;
++
++    if (sock == -1) {
++        BIOerr(BIO_F_BIO_CONNECT, BIO_R_INVALID_SOCKET);
++        return 0;
++    }
++
++    if (!BIO_socket_nbio(sock, (options & BIO_SOCK_NONBLOCK) != 0))
++        return 0;
++
++    if (options & BIO_SOCK_KEEPALIVE) {
++        if (setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, &on, sizeof(on)) != 0) {
++            SYSerr(SYS_F_SETSOCKOPT, get_last_socket_error());
++            BIOerr(BIO_F_BIO_CONNECT, BIO_R_UNABLE_TO_KEEPALIVE);
++            return 0;
++        }
++    }
++
++    if (options & BIO_SOCK_NODELAY) {
++        if (setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, &on, sizeof(on)) != 0) {
++            SYSerr(SYS_F_SETSOCKOPT, get_last_socket_error());
++            BIOerr(BIO_F_BIO_CONNECT, BIO_R_UNABLE_TO_NODELAY);
++            return 0;
++        }
++    }
++
++    if (connect(sock, BIO_ADDR_sockaddr(addr),
++                BIO_ADDR_sockaddr_size(addr)) == -1) {
++        if (!BIO_sock_should_retry(-1)) {
++            SYSerr(SYS_F_CONNECT, get_last_socket_error());
++            BIOerr(BIO_F_BIO_CONNECT, BIO_R_CONNECT_ERROR);
++        }
++        return 0;
++    }
++    return 1;
++}
++
++/*-
++ * BIO_listen - Creates a listen socket
++ * @sock: the socket to listen with
++ * @addr: local address to bind to
++ * @options: BIO socket options
++ *
++ * Binds to the address using the given socket and options, then
++ * starts listening for incoming connections.
++ *
++ * Options can be a combination of the following:
++ * - BIO_SOCK_KEEPALIVE: enable regularly sending keep-alive messages.
++ * - BIO_SOCK_NONBLOCK: Make the socket non-blocking.
++ * - BIO_SOCK_NODELAY: don't delay small messages.
++ * - BIO_SOCK_REUSEADDR: Try to reuse the address and port combination
++ *   for a recently closed port.
++ * - BIO_SOCK_V6_ONLY: When creating an IPv6 socket, make it listen only
++ *   for IPv6 addresses and not IPv4 addresses mapped to IPv6.
++ *
++ * It's recommended that you set up both an IPv6 and IPv4 listen socket, and
++ * then check both for new clients that connect to it.  You want to set up
++ * the socket as non-blocking in that case since else it could hang.
++ *
++ * Not all operating systems support IPv4 addresses on an IPv6 socket, and for
++ * others it's an option.  If you pass the BIO_LISTEN_V6_ONLY it will try to
++ * create the IPv6 sockets to only listen for IPv6 connection.
++ *
++ * It could be that the first BIO_listen() call will listen to all the IPv6
++ * and IPv4 addresses and that then trying to bind to the IPv4 address will
++ * fail.  We can't tell the difference between already listening ourself to
++ * it and someone else listening to it when failing and errno is EADDRINUSE, so
++ * it's recommended to not give an error in that case if the first call was
++ * successful.
++ *
++ * When restarting the program it could be that the port is still in use.  If
++ * you set to BIO_SOCK_REUSEADDR option it will try to reuse the port anyway.
++ * It's recommended that you use this.
++ */
++int BIO_listen(int sock, const BIO_ADDR *addr, int options)
++{
++    int on = 1;
++    int socktype;
++    socklen_t socktype_len = sizeof(socktype);
++
++    if (sock == -1) {
++        BIOerr(BIO_F_BIO_LISTEN, BIO_R_INVALID_SOCKET);
++        return 0;
++    }
++
++    if (getsockopt(sock, SOL_SOCKET, SO_TYPE, &socktype, &socktype_len) != 0
++        || socktype_len != sizeof(socktype)) {
++        SYSerr(SYS_F_GETSOCKOPT, get_last_socket_error());
++        BIOerr(BIO_F_BIO_LISTEN, BIO_R_GETTING_SOCKTYPE);
++        return 0;
++    }
++
++    if (!BIO_socket_nbio(sock, (options & BIO_SOCK_NONBLOCK) != 0))
++        return 0;
++
++# ifndef OPENSSL_SYS_WINDOWS
++    /* SO_REUSEADDR has different behavior on Windows than on
++     * other operating systems, don't set it there. */
++    if (options & BIO_SOCK_REUSEADDR) {
++        if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) != 0) {
++            SYSerr(SYS_F_SETSOCKOPT, get_last_socket_error());
++            BIOerr(BIO_F_BIO_LISTEN, BIO_R_UNABLE_TO_REUSEADDR);
++            return 0;
++        }
++    }
++# endif
++
++    if (options & BIO_SOCK_KEEPALIVE) {
++        if (setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, &on, sizeof(on)) != 0) {
++            SYSerr(SYS_F_SETSOCKOPT, get_last_socket_error());
++            BIOerr(BIO_F_BIO_LISTEN, BIO_R_UNABLE_TO_KEEPALIVE);
++            return 0;
++        }
++    }
++
++    if (options & BIO_SOCK_NODELAY) {
++        if (setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, &on, sizeof(on)) != 0) {
++            SYSerr(SYS_F_SETSOCKOPT, get_last_socket_error());
++            BIOerr(BIO_F_BIO_LISTEN, BIO_R_UNABLE_TO_NODELAY);
++            return 0;
++        }
++    }
++
++# ifdef IPV6_V6ONLY
++    if ((options & BIO_SOCK_V6_ONLY) && BIO_ADDR_family(addr) == AF_INET6) {
++        if (setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof(on)) != 0) {
++            SYSerr(SYS_F_SETSOCKOPT, get_last_socket_error());
++            BIOerr(BIO_F_BIO_LISTEN, BIO_R_LISTEN_V6_ONLY);
++            return 0;
++        }
++    }
++# endif
++
++    if (bind(sock, BIO_ADDR_sockaddr(addr), BIO_ADDR_sockaddr_size(addr)) != 0) {
++        SYSerr(SYS_F_BIND, get_last_socket_error());
++        BIOerr(BIO_F_BIO_LISTEN, BIO_R_UNABLE_TO_BIND_SOCKET);
++        return 0;
++    }
++
++    if (socktype != SOCK_DGRAM && listen(sock, MAX_LISTEN) == -1) {
++        SYSerr(SYS_F_LISTEN, get_last_socket_error());
++        BIOerr(BIO_F_BIO_LISTEN, BIO_R_UNABLE_TO_LISTEN_SOCKET);
++        return 0;
++    }
++
++    return 1;
++}
++
++/*-
++ * BIO_accept_ex - Accept new incoming connections
++ * @sock: the listening socket
++ * @addr: the BIO_ADDR to store the peer address in
++ * @options: BIO socket options, applied on the accepted socket.
++ *
++ */
++int BIO_accept_ex(int accept_sock, BIO_ADDR *addr_, int options)
++{
++    socklen_t len;
++    int accepted_sock;
++    BIO_ADDR locaddr;
++    BIO_ADDR *addr = addr_ == NULL ? &locaddr : addr_;
++
++    len = sizeof(*addr);
++    accepted_sock = accept(accept_sock,
++                           BIO_ADDR_sockaddr_noconst(addr), &len);
++    if (accepted_sock == -1) {
++        if (!BIO_sock_should_retry(accepted_sock)) {
++            SYSerr(SYS_F_ACCEPT, get_last_socket_error());
++            BIOerr(BIO_F_BIO_ACCEPT_EX, BIO_R_ACCEPT_ERROR);
++        }
++        return INVALID_SOCKET;
++    }
++
++    if (!BIO_socket_nbio(accepted_sock, (options & BIO_SOCK_NONBLOCK) != 0)) {
++        closesocket(accepted_sock);
++        return INVALID_SOCKET;
++    }
++
++    return accepted_sock;
++}
++
++/*-
++ * BIO_closesocket - Close a socket
++ * @sock: the socket to close
++ */
++int BIO_closesocket(int sock)
++{
++    if (closesocket(sock) < 0)
++        return 0;
++    return 1;
++}
++#endif
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/bio/bf_buff.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/bio/bf_buff.c
+new file mode 100644
+index 0000000..b2a387b
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/bio/bf_buff.c
+@@ -0,0 +1,455 @@
++/*
++ * Copyright 1995-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include 
++#include "bio_lcl.h"
++#include "internal/cryptlib.h"
++
++static int buffer_write(BIO *h, const char *buf, int num);
++static int buffer_read(BIO *h, char *buf, int size);
++static int buffer_puts(BIO *h, const char *str);
++static int buffer_gets(BIO *h, char *str, int size);
++static long buffer_ctrl(BIO *h, int cmd, long arg1, void *arg2);
++static int buffer_new(BIO *h);
++static int buffer_free(BIO *data);
++static long buffer_callback_ctrl(BIO *h, int cmd, bio_info_cb *fp);
++#define DEFAULT_BUFFER_SIZE     4096
++
++static const BIO_METHOD methods_buffer = {
++    BIO_TYPE_BUFFER,
++    "buffer",
++    buffer_write,
++    buffer_read,
++    buffer_puts,
++    buffer_gets,
++    buffer_ctrl,
++    buffer_new,
++    buffer_free,
++    buffer_callback_ctrl,
++};
++
++const BIO_METHOD *BIO_f_buffer(void)
++{
++    return (&methods_buffer);
++}
++
++static int buffer_new(BIO *bi)
++{
++    BIO_F_BUFFER_CTX *ctx = OPENSSL_zalloc(sizeof(*ctx));
++
++    if (ctx == NULL)
++        return (0);
++    ctx->ibuf_size = DEFAULT_BUFFER_SIZE;
++    ctx->ibuf = OPENSSL_malloc(DEFAULT_BUFFER_SIZE);
++    if (ctx->ibuf == NULL) {
++        OPENSSL_free(ctx);
++        return (0);
++    }
++    ctx->obuf_size = DEFAULT_BUFFER_SIZE;
++    ctx->obuf = OPENSSL_malloc(DEFAULT_BUFFER_SIZE);
++    if (ctx->obuf == NULL) {
++        OPENSSL_free(ctx->ibuf);
++        OPENSSL_free(ctx);
++        return (0);
++    }
++
++    bi->init = 1;
++    bi->ptr = (char *)ctx;
++    bi->flags = 0;
++    return (1);
++}
++
++static int buffer_free(BIO *a)
++{
++    BIO_F_BUFFER_CTX *b;
++
++    if (a == NULL)
++        return (0);
++    b = (BIO_F_BUFFER_CTX *)a->ptr;
++    OPENSSL_free(b->ibuf);
++    OPENSSL_free(b->obuf);
++    OPENSSL_free(a->ptr);
++    a->ptr = NULL;
++    a->init = 0;
++    a->flags = 0;
++    return (1);
++}
++
++static int buffer_read(BIO *b, char *out, int outl)
++{
++    int i, num = 0;
++    BIO_F_BUFFER_CTX *ctx;
++
++    if (out == NULL)
++        return (0);
++    ctx = (BIO_F_BUFFER_CTX *)b->ptr;
++
++    if ((ctx == NULL) || (b->next_bio == NULL))
++        return (0);
++    num = 0;
++    BIO_clear_retry_flags(b);
++
++ start:
++    i = ctx->ibuf_len;
++    /* If there is stuff left over, grab it */
++    if (i != 0) {
++        if (i > outl)
++            i = outl;
++        memcpy(out, &(ctx->ibuf[ctx->ibuf_off]), i);
++        ctx->ibuf_off += i;
++        ctx->ibuf_len -= i;
++        num += i;
++        if (outl == i)
++            return (num);
++        outl -= i;
++        out += i;
++    }
++
++    /*
++     * We may have done a partial read. try to do more. We have nothing in
++     * the buffer. If we get an error and have read some data, just return it
++     * and let them retry to get the error again. copy direct to parent
++     * address space
++     */
++    if (outl > ctx->ibuf_size) {
++        for (;;) {
++            i = BIO_read(b->next_bio, out, outl);
++            if (i <= 0) {
++                BIO_copy_next_retry(b);
++                if (i < 0)
++                    return ((num > 0) ? num : i);
++                if (i == 0)
++                    return (num);
++            }
++            num += i;
++            if (outl == i)
++                return (num);
++            out += i;
++            outl -= i;
++        }
++    }
++    /* else */
++
++    /* we are going to be doing some buffering */
++    i = BIO_read(b->next_bio, ctx->ibuf, ctx->ibuf_size);
++    if (i <= 0) {
++        BIO_copy_next_retry(b);
++        if (i < 0)
++            return ((num > 0) ? num : i);
++        if (i == 0)
++            return (num);
++    }
++    ctx->ibuf_off = 0;
++    ctx->ibuf_len = i;
++
++    /* Lets re-read using ourselves :-) */
++    goto start;
++}
++
++static int buffer_write(BIO *b, const char *in, int inl)
++{
++    int i, num = 0;
++    BIO_F_BUFFER_CTX *ctx;
++
++    if ((in == NULL) || (inl <= 0))
++        return (0);
++    ctx = (BIO_F_BUFFER_CTX *)b->ptr;
++    if ((ctx == NULL) || (b->next_bio == NULL))
++        return (0);
++
++    BIO_clear_retry_flags(b);
++ start:
++    i = ctx->obuf_size - (ctx->obuf_len + ctx->obuf_off);
++    /* add to buffer and return */
++    if (i >= inl) {
++        memcpy(&(ctx->obuf[ctx->obuf_off + ctx->obuf_len]), in, inl);
++        ctx->obuf_len += inl;
++        return (num + inl);
++    }
++    /* else */
++    /* stuff already in buffer, so add to it first, then flush */
++    if (ctx->obuf_len != 0) {
++        if (i > 0) {            /* lets fill it up if we can */
++            memcpy(&(ctx->obuf[ctx->obuf_off + ctx->obuf_len]), in, i);
++            in += i;
++            inl -= i;
++            num += i;
++            ctx->obuf_len += i;
++        }
++        /* we now have a full buffer needing flushing */
++        for (;;) {
++            i = BIO_write(b->next_bio, &(ctx->obuf[ctx->obuf_off]),
++                          ctx->obuf_len);
++            if (i <= 0) {
++                BIO_copy_next_retry(b);
++
++                if (i < 0)
++                    return ((num > 0) ? num : i);
++                if (i == 0)
++                    return (num);
++            }
++            ctx->obuf_off += i;
++            ctx->obuf_len -= i;
++            if (ctx->obuf_len == 0)
++                break;
++        }
++    }
++    /*
++     * we only get here if the buffer has been flushed and we still have
++     * stuff to write
++     */
++    ctx->obuf_off = 0;
++
++    /* we now have inl bytes to write */
++    while (inl >= ctx->obuf_size) {
++        i = BIO_write(b->next_bio, in, inl);
++        if (i <= 0) {
++            BIO_copy_next_retry(b);
++            if (i < 0)
++                return ((num > 0) ? num : i);
++            if (i == 0)
++                return (num);
++        }
++        num += i;
++        in += i;
++        inl -= i;
++        if (inl == 0)
++            return (num);
++    }
++
++    /*
++     * copy the rest into the buffer since we have only a small amount left
++     */
++    goto start;
++}
++
++static long buffer_ctrl(BIO *b, int cmd, long num, void *ptr)
++{
++    BIO *dbio;
++    BIO_F_BUFFER_CTX *ctx;
++    long ret = 1;
++    char *p1, *p2;
++    int r, i, *ip;
++    int ibs, obs;
++
++    ctx = (BIO_F_BUFFER_CTX *)b->ptr;
++
++    switch (cmd) {
++    case BIO_CTRL_RESET:
++        ctx->ibuf_off = 0;
++        ctx->ibuf_len = 0;
++        ctx->obuf_off = 0;
++        ctx->obuf_len = 0;
++        if (b->next_bio == NULL)
++            return (0);
++        ret = BIO_ctrl(b->next_bio, cmd, num, ptr);
++        break;
++    case BIO_CTRL_INFO:
++        ret = (long)ctx->obuf_len;
++        break;
++    case BIO_C_GET_BUFF_NUM_LINES:
++        ret = 0;
++        p1 = ctx->ibuf;
++        for (i = 0; i < ctx->ibuf_len; i++) {
++            if (p1[ctx->ibuf_off + i] == '\n')
++                ret++;
++        }
++        break;
++    case BIO_CTRL_WPENDING:
++        ret = (long)ctx->obuf_len;
++        if (ret == 0) {
++            if (b->next_bio == NULL)
++                return (0);
++            ret = BIO_ctrl(b->next_bio, cmd, num, ptr);
++        }
++        break;
++    case BIO_CTRL_PENDING:
++        ret = (long)ctx->ibuf_len;
++        if (ret == 0) {
++            if (b->next_bio == NULL)
++                return (0);
++            ret = BIO_ctrl(b->next_bio, cmd, num, ptr);
++        }
++        break;
++    case BIO_C_SET_BUFF_READ_DATA:
++        if (num > ctx->ibuf_size) {
++            p1 = OPENSSL_malloc((int)num);
++            if (p1 == NULL)
++                goto malloc_error;
++            OPENSSL_free(ctx->ibuf);
++            ctx->ibuf = p1;
++        }
++        ctx->ibuf_off = 0;
++        ctx->ibuf_len = (int)num;
++        memcpy(ctx->ibuf, ptr, (int)num);
++        ret = 1;
++        break;
++    case BIO_C_SET_BUFF_SIZE:
++        if (ptr != NULL) {
++            ip = (int *)ptr;
++            if (*ip == 0) {
++                ibs = (int)num;
++                obs = ctx->obuf_size;
++            } else {            /* if (*ip == 1) */
++
++                ibs = ctx->ibuf_size;
++                obs = (int)num;
++            }
++        } else {
++            ibs = (int)num;
++            obs = (int)num;
++        }
++        p1 = ctx->ibuf;
++        p2 = ctx->obuf;
++        if ((ibs > DEFAULT_BUFFER_SIZE) && (ibs != ctx->ibuf_size)) {
++            p1 = OPENSSL_malloc((int)num);
++            if (p1 == NULL)
++                goto malloc_error;
++        }
++        if ((obs > DEFAULT_BUFFER_SIZE) && (obs != ctx->obuf_size)) {
++            p2 = OPENSSL_malloc((int)num);
++            if (p2 == NULL) {
++                if (p1 != ctx->ibuf)
++                    OPENSSL_free(p1);
++                goto malloc_error;
++            }
++        }
++        if (ctx->ibuf != p1) {
++            OPENSSL_free(ctx->ibuf);
++            ctx->ibuf = p1;
++            ctx->ibuf_off = 0;
++            ctx->ibuf_len = 0;
++            ctx->ibuf_size = ibs;
++        }
++        if (ctx->obuf != p2) {
++            OPENSSL_free(ctx->obuf);
++            ctx->obuf = p2;
++            ctx->obuf_off = 0;
++            ctx->obuf_len = 0;
++            ctx->obuf_size = obs;
++        }
++        break;
++    case BIO_C_DO_STATE_MACHINE:
++        if (b->next_bio == NULL)
++            return (0);
++        BIO_clear_retry_flags(b);
++        ret = BIO_ctrl(b->next_bio, cmd, num, ptr);
++        BIO_copy_next_retry(b);
++        break;
++
++    case BIO_CTRL_FLUSH:
++        if (b->next_bio == NULL)
++            return (0);
++        if (ctx->obuf_len <= 0) {
++            ret = BIO_ctrl(b->next_bio, cmd, num, ptr);
++            break;
++        }
++
++        for (;;) {
++            BIO_clear_retry_flags(b);
++            if (ctx->obuf_len > 0) {
++                r = BIO_write(b->next_bio,
++                              &(ctx->obuf[ctx->obuf_off]), ctx->obuf_len);
++                BIO_copy_next_retry(b);
++                if (r <= 0)
++                    return ((long)r);
++                ctx->obuf_off += r;
++                ctx->obuf_len -= r;
++            } else {
++                ctx->obuf_len = 0;
++                ctx->obuf_off = 0;
++                break;
++            }
++        }
++        ret = BIO_ctrl(b->next_bio, cmd, num, ptr);
++        break;
++    case BIO_CTRL_DUP:
++        dbio = (BIO *)ptr;
++        if (!BIO_set_read_buffer_size(dbio, ctx->ibuf_size) ||
++            !BIO_set_write_buffer_size(dbio, ctx->obuf_size))
++            ret = 0;
++        break;
++    default:
++        if (b->next_bio == NULL)
++            return (0);
++        ret = BIO_ctrl(b->next_bio, cmd, num, ptr);
++        break;
++    }
++    return (ret);
++ malloc_error:
++    BIOerr(BIO_F_BUFFER_CTRL, ERR_R_MALLOC_FAILURE);
++    return (0);
++}
++
++static long buffer_callback_ctrl(BIO *b, int cmd, bio_info_cb *fp)
++{
++    long ret = 1;
++
++    if (b->next_bio == NULL)
++        return (0);
++    switch (cmd) {
++    default:
++        ret = BIO_callback_ctrl(b->next_bio, cmd, fp);
++        break;
++    }
++    return (ret);
++}
++
++static int buffer_gets(BIO *b, char *buf, int size)
++{
++    BIO_F_BUFFER_CTX *ctx;
++    int num = 0, i, flag;
++    char *p;
++
++    ctx = (BIO_F_BUFFER_CTX *)b->ptr;
++    size--;                     /* reserve space for a '\0' */
++    BIO_clear_retry_flags(b);
++
++    for (;;) {
++        if (ctx->ibuf_len > 0) {
++            p = &(ctx->ibuf[ctx->ibuf_off]);
++            flag = 0;
++            for (i = 0; (i < ctx->ibuf_len) && (i < size); i++) {
++                *(buf++) = p[i];
++                if (p[i] == '\n') {
++                    flag = 1;
++                    i++;
++                    break;
++                }
++            }
++            num += i;
++            size -= i;
++            ctx->ibuf_len -= i;
++            ctx->ibuf_off += i;
++            if (flag || size == 0) {
++                *buf = '\0';
++                return (num);
++            }
++        } else {                /* read another chunk */
++
++            i = BIO_read(b->next_bio, ctx->ibuf, ctx->ibuf_size);
++            if (i <= 0) {
++                BIO_copy_next_retry(b);
++                *buf = '\0';
++                if (i < 0)
++                    return ((num > 0) ? num : i);
++                if (i == 0)
++                    return (num);
++            }
++            ctx->ibuf_len = i;
++            ctx->ibuf_off = 0;
++        }
++    }
++}
++
++static int buffer_puts(BIO *b, const char *str)
++{
++    return (buffer_write(b, str, strlen(str)));
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/bio/bf_lbuf.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/bio/bf_lbuf.c
+new file mode 100644
+index 0000000..b3c2b5e
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/bio/bf_lbuf.c
+@@ -0,0 +1,319 @@
++/*
++ * Copyright 1995-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include 
++#include "bio_lcl.h"
++#include "internal/cryptlib.h"
++#include 
++
++static int linebuffer_write(BIO *h, const char *buf, int num);
++static int linebuffer_read(BIO *h, char *buf, int size);
++static int linebuffer_puts(BIO *h, const char *str);
++static int linebuffer_gets(BIO *h, char *str, int size);
++static long linebuffer_ctrl(BIO *h, int cmd, long arg1, void *arg2);
++static int linebuffer_new(BIO *h);
++static int linebuffer_free(BIO *data);
++static long linebuffer_callback_ctrl(BIO *h, int cmd, bio_info_cb *fp);
++
++/* A 10k maximum should be enough for most purposes */
++#define DEFAULT_LINEBUFFER_SIZE 1024*10
++
++/* #define DEBUG */
++
++static const BIO_METHOD methods_linebuffer = {
++    BIO_TYPE_LINEBUFFER,
++    "linebuffer",
++    linebuffer_write,
++    linebuffer_read,
++    linebuffer_puts,
++    linebuffer_gets,
++    linebuffer_ctrl,
++    linebuffer_new,
++    linebuffer_free,
++    linebuffer_callback_ctrl,
++};
++
++const BIO_METHOD *BIO_f_linebuffer(void)
++{
++    return (&methods_linebuffer);
++}
++
++typedef struct bio_linebuffer_ctx_struct {
++    char *obuf;                 /* the output char array */
++    int obuf_size;              /* how big is the output buffer */
++    int obuf_len;               /* how many bytes are in it */
++} BIO_LINEBUFFER_CTX;
++
++static int linebuffer_new(BIO *bi)
++{
++    BIO_LINEBUFFER_CTX *ctx;
++
++    ctx = OPENSSL_malloc(sizeof(*ctx));
++    if (ctx == NULL)
++        return (0);
++    ctx->obuf = OPENSSL_malloc(DEFAULT_LINEBUFFER_SIZE);
++    if (ctx->obuf == NULL) {
++        OPENSSL_free(ctx);
++        return (0);
++    }
++    ctx->obuf_size = DEFAULT_LINEBUFFER_SIZE;
++    ctx->obuf_len = 0;
++
++    bi->init = 1;
++    bi->ptr = (char *)ctx;
++    bi->flags = 0;
++    return (1);
++}
++
++static int linebuffer_free(BIO *a)
++{
++    BIO_LINEBUFFER_CTX *b;
++
++    if (a == NULL)
++        return (0);
++    b = (BIO_LINEBUFFER_CTX *)a->ptr;
++    OPENSSL_free(b->obuf);
++    OPENSSL_free(a->ptr);
++    a->ptr = NULL;
++    a->init = 0;
++    a->flags = 0;
++    return (1);
++}
++
++static int linebuffer_read(BIO *b, char *out, int outl)
++{
++    int ret = 0;
++
++    if (out == NULL)
++        return (0);
++    if (b->next_bio == NULL)
++        return (0);
++    ret = BIO_read(b->next_bio, out, outl);
++    BIO_clear_retry_flags(b);
++    BIO_copy_next_retry(b);
++    return (ret);
++}
++
++static int linebuffer_write(BIO *b, const char *in, int inl)
++{
++    int i, num = 0, foundnl;
++    BIO_LINEBUFFER_CTX *ctx;
++
++    if ((in == NULL) || (inl <= 0))
++        return (0);
++    ctx = (BIO_LINEBUFFER_CTX *)b->ptr;
++    if ((ctx == NULL) || (b->next_bio == NULL))
++        return (0);
++
++    BIO_clear_retry_flags(b);
++
++    do {
++        const char *p;
++
++        for (p = in; p < in + inl && *p != '\n'; p++) ;
++        if (*p == '\n') {
++            p++;
++            foundnl = 1;
++        } else
++            foundnl = 0;
++
++        /*
++         * If a NL was found and we already have text in the save buffer,
++         * concatenate them and write
++         */
++        while ((foundnl || p - in > ctx->obuf_size - ctx->obuf_len)
++               && ctx->obuf_len > 0) {
++            int orig_olen = ctx->obuf_len;
++
++            i = ctx->obuf_size - ctx->obuf_len;
++            if (p - in > 0) {
++                if (i >= p - in) {
++                    memcpy(&(ctx->obuf[ctx->obuf_len]), in, p - in);
++                    ctx->obuf_len += p - in;
++                    inl -= p - in;
++                    num += p - in;
++                    in = p;
++                } else {
++                    memcpy(&(ctx->obuf[ctx->obuf_len]), in, i);
++                    ctx->obuf_len += i;
++                    inl -= i;
++                    in += i;
++                    num += i;
++                }
++            }
++            i = BIO_write(b->next_bio, ctx->obuf, ctx->obuf_len);
++            if (i <= 0) {
++                ctx->obuf_len = orig_olen;
++                BIO_copy_next_retry(b);
++
++                if (i < 0)
++                    return ((num > 0) ? num : i);
++                if (i == 0)
++                    return (num);
++            }
++            if (i < ctx->obuf_len)
++                memmove(ctx->obuf, ctx->obuf + i, ctx->obuf_len - i);
++            ctx->obuf_len -= i;
++        }
++
++        /*
++         * Now that the save buffer is emptied, let's write the input buffer
++         * if a NL was found and there is anything to write.
++         */
++        if ((foundnl || p - in > ctx->obuf_size) && p - in > 0) {
++            i = BIO_write(b->next_bio, in, p - in);
++            if (i <= 0) {
++                BIO_copy_next_retry(b);
++                if (i < 0)
++                    return ((num > 0) ? num : i);
++                if (i == 0)
++                    return (num);
++            }
++            num += i;
++            in += i;
++            inl -= i;
++        }
++    }
++    while (foundnl && inl > 0);
++    /*
++     * We've written as much as we can.  The rest of the input buffer, if
++     * any, is text that doesn't and with a NL and therefore needs to be
++     * saved for the next trip.
++     */
++    if (inl > 0) {
++        memcpy(&(ctx->obuf[ctx->obuf_len]), in, inl);
++        ctx->obuf_len += inl;
++        num += inl;
++    }
++    return num;
++}
++
++static long linebuffer_ctrl(BIO *b, int cmd, long num, void *ptr)
++{
++    BIO *dbio;
++    BIO_LINEBUFFER_CTX *ctx;
++    long ret = 1;
++    char *p;
++    int r;
++    int obs;
++
++    ctx = (BIO_LINEBUFFER_CTX *)b->ptr;
++
++    switch (cmd) {
++    case BIO_CTRL_RESET:
++        ctx->obuf_len = 0;
++        if (b->next_bio == NULL)
++            return (0);
++        ret = BIO_ctrl(b->next_bio, cmd, num, ptr);
++        break;
++    case BIO_CTRL_INFO:
++        ret = (long)ctx->obuf_len;
++        break;
++    case BIO_CTRL_WPENDING:
++        ret = (long)ctx->obuf_len;
++        if (ret == 0) {
++            if (b->next_bio == NULL)
++                return (0);
++            ret = BIO_ctrl(b->next_bio, cmd, num, ptr);
++        }
++        break;
++    case BIO_C_SET_BUFF_SIZE:
++        obs = (int)num;
++        p = ctx->obuf;
++        if ((obs > DEFAULT_LINEBUFFER_SIZE) && (obs != ctx->obuf_size)) {
++            p = OPENSSL_malloc((int)num);
++            if (p == NULL)
++                goto malloc_error;
++        }
++        if (ctx->obuf != p) {
++            if (ctx->obuf_len > obs) {
++                ctx->obuf_len = obs;
++            }
++            memcpy(p, ctx->obuf, ctx->obuf_len);
++            OPENSSL_free(ctx->obuf);
++            ctx->obuf = p;
++            ctx->obuf_size = obs;
++        }
++        break;
++    case BIO_C_DO_STATE_MACHINE:
++        if (b->next_bio == NULL)
++            return (0);
++        BIO_clear_retry_flags(b);
++        ret = BIO_ctrl(b->next_bio, cmd, num, ptr);
++        BIO_copy_next_retry(b);
++        break;
++
++    case BIO_CTRL_FLUSH:
++        if (b->next_bio == NULL)
++            return (0);
++        if (ctx->obuf_len <= 0) {
++            ret = BIO_ctrl(b->next_bio, cmd, num, ptr);
++            break;
++        }
++
++        for (;;) {
++            BIO_clear_retry_flags(b);
++            if (ctx->obuf_len > 0) {
++                r = BIO_write(b->next_bio, ctx->obuf, ctx->obuf_len);
++                BIO_copy_next_retry(b);
++                if (r <= 0)
++                    return ((long)r);
++                if (r < ctx->obuf_len)
++                    memmove(ctx->obuf, ctx->obuf + r, ctx->obuf_len - r);
++                ctx->obuf_len -= r;
++            } else {
++                ctx->obuf_len = 0;
++                break;
++            }
++        }
++        ret = BIO_ctrl(b->next_bio, cmd, num, ptr);
++        break;
++    case BIO_CTRL_DUP:
++        dbio = (BIO *)ptr;
++        if (!BIO_set_write_buffer_size(dbio, ctx->obuf_size))
++            ret = 0;
++        break;
++    default:
++        if (b->next_bio == NULL)
++            return (0);
++        ret = BIO_ctrl(b->next_bio, cmd, num, ptr);
++        break;
++    }
++    return (ret);
++ malloc_error:
++    BIOerr(BIO_F_LINEBUFFER_CTRL, ERR_R_MALLOC_FAILURE);
++    return (0);
++}
++
++static long linebuffer_callback_ctrl(BIO *b, int cmd, bio_info_cb *fp)
++{
++    long ret = 1;
++
++    if (b->next_bio == NULL)
++        return (0);
++    switch (cmd) {
++    default:
++        ret = BIO_callback_ctrl(b->next_bio, cmd, fp);
++        break;
++    }
++    return (ret);
++}
++
++static int linebuffer_gets(BIO *b, char *buf, int size)
++{
++    if (b->next_bio == NULL)
++        return (0);
++    return (BIO_gets(b->next_bio, buf, size));
++}
++
++static int linebuffer_puts(BIO *b, const char *str)
++{
++    return (linebuffer_write(b, str, strlen(str)));
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/bio/bf_nbio.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/bio/bf_nbio.c
+new file mode 100644
+index 0000000..364d9fb
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/bio/bf_nbio.c
+@@ -0,0 +1,194 @@
++/*
++ * Copyright 1995-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include 
++#include "bio_lcl.h"
++#include "internal/cryptlib.h"
++#include 
++
++/*
++ * BIO_put and BIO_get both add to the digest, BIO_gets returns the digest
++ */
++
++static int nbiof_write(BIO *h, const char *buf, int num);
++static int nbiof_read(BIO *h, char *buf, int size);
++static int nbiof_puts(BIO *h, const char *str);
++static int nbiof_gets(BIO *h, char *str, int size);
++static long nbiof_ctrl(BIO *h, int cmd, long arg1, void *arg2);
++static int nbiof_new(BIO *h);
++static int nbiof_free(BIO *data);
++static long nbiof_callback_ctrl(BIO *h, int cmd, bio_info_cb *fp);
++typedef struct nbio_test_st {
++    /* only set if we sent a 'should retry' error */
++    int lrn;
++    int lwn;
++} NBIO_TEST;
++
++static const BIO_METHOD methods_nbiof = {
++    BIO_TYPE_NBIO_TEST,
++    "non-blocking IO test filter",
++    nbiof_write,
++    nbiof_read,
++    nbiof_puts,
++    nbiof_gets,
++    nbiof_ctrl,
++    nbiof_new,
++    nbiof_free,
++    nbiof_callback_ctrl,
++};
++
++const BIO_METHOD *BIO_f_nbio_test(void)
++{
++    return (&methods_nbiof);
++}
++
++static int nbiof_new(BIO *bi)
++{
++    NBIO_TEST *nt;
++
++    if ((nt = OPENSSL_zalloc(sizeof(*nt))) == NULL)
++        return (0);
++    nt->lrn = -1;
++    nt->lwn = -1;
++    bi->ptr = (char *)nt;
++    bi->init = 1;
++    return (1);
++}
++
++static int nbiof_free(BIO *a)
++{
++    if (a == NULL)
++        return (0);
++    OPENSSL_free(a->ptr);
++    a->ptr = NULL;
++    a->init = 0;
++    a->flags = 0;
++    return (1);
++}
++
++static int nbiof_read(BIO *b, char *out, int outl)
++{
++    int ret = 0;
++    int num;
++    unsigned char n;
++
++    if (out == NULL)
++        return (0);
++    if (b->next_bio == NULL)
++        return (0);
++
++    BIO_clear_retry_flags(b);
++    if (RAND_bytes(&n, 1) <= 0)
++        return -1;
++    num = (n & 0x07);
++
++    if (outl > num)
++        outl = num;
++
++    if (num == 0) {
++        ret = -1;
++        BIO_set_retry_read(b);
++    } else {
++        ret = BIO_read(b->next_bio, out, outl);
++        if (ret < 0)
++            BIO_copy_next_retry(b);
++    }
++    return (ret);
++}
++
++static int nbiof_write(BIO *b, const char *in, int inl)
++{
++    NBIO_TEST *nt;
++    int ret = 0;
++    int num;
++    unsigned char n;
++
++    if ((in == NULL) || (inl <= 0))
++        return (0);
++    if (b->next_bio == NULL)
++        return (0);
++    nt = (NBIO_TEST *)b->ptr;
++
++    BIO_clear_retry_flags(b);
++
++    if (nt->lwn > 0) {
++        num = nt->lwn;
++        nt->lwn = 0;
++    } else {
++        if (RAND_bytes(&n, 1) <= 0)
++            return -1;
++        num = (n & 7);
++    }
++
++    if (inl > num)
++        inl = num;
++
++    if (num == 0) {
++        ret = -1;
++        BIO_set_retry_write(b);
++    } else {
++        ret = BIO_write(b->next_bio, in, inl);
++        if (ret < 0) {
++            BIO_copy_next_retry(b);
++            nt->lwn = inl;
++        }
++    }
++    return (ret);
++}
++
++static long nbiof_ctrl(BIO *b, int cmd, long num, void *ptr)
++{
++    long ret;
++
++    if (b->next_bio == NULL)
++        return (0);
++    switch (cmd) {
++    case BIO_C_DO_STATE_MACHINE:
++        BIO_clear_retry_flags(b);
++        ret = BIO_ctrl(b->next_bio, cmd, num, ptr);
++        BIO_copy_next_retry(b);
++        break;
++    case BIO_CTRL_DUP:
++        ret = 0L;
++        break;
++    default:
++        ret = BIO_ctrl(b->next_bio, cmd, num, ptr);
++        break;
++    }
++    return (ret);
++}
++
++static long nbiof_callback_ctrl(BIO *b, int cmd, bio_info_cb *fp)
++{
++    long ret = 1;
++
++    if (b->next_bio == NULL)
++        return (0);
++    switch (cmd) {
++    default:
++        ret = BIO_callback_ctrl(b->next_bio, cmd, fp);
++        break;
++    }
++    return (ret);
++}
++
++static int nbiof_gets(BIO *bp, char *buf, int size)
++{
++    if (bp->next_bio == NULL)
++        return (0);
++    return (BIO_gets(bp->next_bio, buf, size));
++}
++
++static int nbiof_puts(BIO *bp, const char *str)
++{
++    if (bp->next_bio == NULL)
++        return (0);
++    return (BIO_puts(bp->next_bio, str));
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/bio/bf_null.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/bio/bf_null.c
+new file mode 100644
+index 0000000..0736b3f
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/bio/bf_null.c
+@@ -0,0 +1,140 @@
++/*
++ * Copyright 1995-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include 
++#include "bio_lcl.h"
++#include "internal/cryptlib.h"
++
++/*
++ * BIO_put and BIO_get both add to the digest, BIO_gets returns the digest
++ */
++
++static int nullf_write(BIO *h, const char *buf, int num);
++static int nullf_read(BIO *h, char *buf, int size);
++static int nullf_puts(BIO *h, const char *str);
++static int nullf_gets(BIO *h, char *str, int size);
++static long nullf_ctrl(BIO *h, int cmd, long arg1, void *arg2);
++static int nullf_new(BIO *h);
++static int nullf_free(BIO *data);
++static long nullf_callback_ctrl(BIO *h, int cmd, bio_info_cb *fp);
++static const BIO_METHOD methods_nullf = {
++    BIO_TYPE_NULL_FILTER,
++    "NULL filter",
++    nullf_write,
++    nullf_read,
++    nullf_puts,
++    nullf_gets,
++    nullf_ctrl,
++    nullf_new,
++    nullf_free,
++    nullf_callback_ctrl,
++};
++
++const BIO_METHOD *BIO_f_null(void)
++{
++    return (&methods_nullf);
++}
++
++static int nullf_new(BIO *bi)
++{
++    bi->init = 1;
++    bi->ptr = NULL;
++    bi->flags = 0;
++    return (1);
++}
++
++static int nullf_free(BIO *a)
++{
++    if (a == NULL)
++        return (0);
++    /*-
++    a->ptr=NULL;
++    a->init=0;
++    a->flags=0;
++    */
++    return (1);
++}
++
++static int nullf_read(BIO *b, char *out, int outl)
++{
++    int ret = 0;
++
++    if (out == NULL)
++        return (0);
++    if (b->next_bio == NULL)
++        return (0);
++    ret = BIO_read(b->next_bio, out, outl);
++    BIO_clear_retry_flags(b);
++    BIO_copy_next_retry(b);
++    return (ret);
++}
++
++static int nullf_write(BIO *b, const char *in, int inl)
++{
++    int ret = 0;
++
++    if ((in == NULL) || (inl <= 0))
++        return (0);
++    if (b->next_bio == NULL)
++        return (0);
++    ret = BIO_write(b->next_bio, in, inl);
++    BIO_clear_retry_flags(b);
++    BIO_copy_next_retry(b);
++    return (ret);
++}
++
++static long nullf_ctrl(BIO *b, int cmd, long num, void *ptr)
++{
++    long ret;
++
++    if (b->next_bio == NULL)
++        return (0);
++    switch (cmd) {
++    case BIO_C_DO_STATE_MACHINE:
++        BIO_clear_retry_flags(b);
++        ret = BIO_ctrl(b->next_bio, cmd, num, ptr);
++        BIO_copy_next_retry(b);
++        break;
++    case BIO_CTRL_DUP:
++        ret = 0L;
++        break;
++    default:
++        ret = BIO_ctrl(b->next_bio, cmd, num, ptr);
++    }
++    return (ret);
++}
++
++static long nullf_callback_ctrl(BIO *b, int cmd, bio_info_cb *fp)
++{
++    long ret = 1;
++
++    if (b->next_bio == NULL)
++        return (0);
++    switch (cmd) {
++    default:
++        ret = BIO_callback_ctrl(b->next_bio, cmd, fp);
++        break;
++    }
++    return (ret);
++}
++
++static int nullf_gets(BIO *bp, char *buf, int size)
++{
++    if (bp->next_bio == NULL)
++        return (0);
++    return (BIO_gets(bp->next_bio, buf, size));
++}
++
++static int nullf_puts(BIO *bp, const char *str)
++{
++    if (bp->next_bio == NULL)
++        return (0);
++    return (BIO_puts(bp->next_bio, str));
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/bio/bio_cb.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/bio/bio_cb.c
+new file mode 100644
+index 0000000..69ea3d0
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/bio/bio_cb.c
+@@ -0,0 +1,99 @@
++/*
++ * Copyright 1995-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include 
++#include 
++#include "bio_lcl.h"
++#include "internal/cryptlib.h"
++#include 
++
++long BIO_debug_callback(BIO *bio, int cmd, const char *argp,
++                        int argi, long argl, long ret)
++{
++    BIO *b;
++    char buf[256];
++    char *p;
++    long r = 1;
++    int len;
++    size_t p_maxlen;
++
++    if (BIO_CB_RETURN & cmd)
++        r = ret;
++
++    len = BIO_snprintf(buf, sizeof buf, "BIO[%p]: ", (void *)bio);
++
++    /* Ignore errors and continue printing the other information. */
++    if (len < 0)
++        len = 0;
++    p = buf + len;
++    p_maxlen = sizeof(buf) - len;
++
++    switch (cmd) {
++    case BIO_CB_FREE:
++        BIO_snprintf(p, p_maxlen, "Free - %s\n", bio->method->name);
++        break;
++    case BIO_CB_READ:
++        if (bio->method->type & BIO_TYPE_DESCRIPTOR)
++            BIO_snprintf(p, p_maxlen, "read(%d,%lu) - %s fd=%d\n",
++                         bio->num, (unsigned long)argi,
++                         bio->method->name, bio->num);
++        else
++            BIO_snprintf(p, p_maxlen, "read(%d,%lu) - %s\n",
++                         bio->num, (unsigned long)argi, bio->method->name);
++        break;
++    case BIO_CB_WRITE:
++        if (bio->method->type & BIO_TYPE_DESCRIPTOR)
++            BIO_snprintf(p, p_maxlen, "write(%d,%lu) - %s fd=%d\n",
++                         bio->num, (unsigned long)argi,
++                         bio->method->name, bio->num);
++        else
++            BIO_snprintf(p, p_maxlen, "write(%d,%lu) - %s\n",
++                         bio->num, (unsigned long)argi, bio->method->name);
++        break;
++    case BIO_CB_PUTS:
++        BIO_snprintf(p, p_maxlen, "puts() - %s\n", bio->method->name);
++        break;
++    case BIO_CB_GETS:
++        BIO_snprintf(p, p_maxlen, "gets(%lu) - %s\n", (unsigned long)argi,
++                     bio->method->name);
++        break;
++    case BIO_CB_CTRL:
++        BIO_snprintf(p, p_maxlen, "ctrl(%lu) - %s\n", (unsigned long)argi,
++                     bio->method->name);
++        break;
++    case BIO_CB_RETURN | BIO_CB_READ:
++        BIO_snprintf(p, p_maxlen, "read return %ld\n", ret);
++        break;
++    case BIO_CB_RETURN | BIO_CB_WRITE:
++        BIO_snprintf(p, p_maxlen, "write return %ld\n", ret);
++        break;
++    case BIO_CB_RETURN | BIO_CB_GETS:
++        BIO_snprintf(p, p_maxlen, "gets return %ld\n", ret);
++        break;
++    case BIO_CB_RETURN | BIO_CB_PUTS:
++        BIO_snprintf(p, p_maxlen, "puts return %ld\n", ret);
++        break;
++    case BIO_CB_RETURN | BIO_CB_CTRL:
++        BIO_snprintf(p, p_maxlen, "ctrl return %ld\n", ret);
++        break;
++    default:
++        BIO_snprintf(p, p_maxlen, "bio callback - unknown type (%d)\n", cmd);
++        break;
++    }
++
++    b = (BIO *)bio->cb_arg;
++    if (b != NULL)
++        BIO_write(b, buf, strlen(buf));
++#if !defined(OPENSSL_NO_STDIO)
++    else
++        fputs(buf, stderr);
++#endif
++    return (r);
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/bio/bio_err.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/bio/bio_err.c
+new file mode 100644
+index 0000000..98c90d6
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/bio/bio_err.c
+@@ -0,0 +1,125 @@
++/*
++ * Generated by util/mkerr.pl DO NOT EDIT
++ * Copyright 1995-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include 
++#include 
++
++/* BEGIN ERROR CODES */
++#ifndef OPENSSL_NO_ERR
++
++# define ERR_FUNC(func) ERR_PACK(ERR_LIB_BIO,func,0)
++# define ERR_REASON(reason) ERR_PACK(ERR_LIB_BIO,0,reason)
++
++static ERR_STRING_DATA BIO_str_functs[] = {
++    {ERR_FUNC(BIO_F_ACPT_STATE), "acpt_state"},
++    {ERR_FUNC(BIO_F_ADDR_STRINGS), "addr_strings"},
++    {ERR_FUNC(BIO_F_BIO_ACCEPT), "BIO_accept"},
++    {ERR_FUNC(BIO_F_BIO_ACCEPT_EX), "BIO_accept_ex"},
++    {ERR_FUNC(BIO_F_BIO_ADDR_NEW), "BIO_ADDR_new"},
++    {ERR_FUNC(BIO_F_BIO_CALLBACK_CTRL), "BIO_callback_ctrl"},
++    {ERR_FUNC(BIO_F_BIO_CONNECT), "BIO_connect"},
++    {ERR_FUNC(BIO_F_BIO_CTRL), "BIO_ctrl"},
++    {ERR_FUNC(BIO_F_BIO_GETS), "BIO_gets"},
++    {ERR_FUNC(BIO_F_BIO_GET_HOST_IP), "BIO_get_host_ip"},
++    {ERR_FUNC(BIO_F_BIO_GET_NEW_INDEX), "BIO_get_new_index"},
++    {ERR_FUNC(BIO_F_BIO_GET_PORT), "BIO_get_port"},
++    {ERR_FUNC(BIO_F_BIO_LISTEN), "BIO_listen"},
++    {ERR_FUNC(BIO_F_BIO_LOOKUP), "BIO_lookup"},
++    {ERR_FUNC(BIO_F_BIO_MAKE_PAIR), "bio_make_pair"},
++    {ERR_FUNC(BIO_F_BIO_NEW), "BIO_new"},
++    {ERR_FUNC(BIO_F_BIO_NEW_FILE), "BIO_new_file"},
++    {ERR_FUNC(BIO_F_BIO_NEW_MEM_BUF), "BIO_new_mem_buf"},
++    {ERR_FUNC(BIO_F_BIO_NREAD), "BIO_nread"},
++    {ERR_FUNC(BIO_F_BIO_NREAD0), "BIO_nread0"},
++    {ERR_FUNC(BIO_F_BIO_NWRITE), "BIO_nwrite"},
++    {ERR_FUNC(BIO_F_BIO_NWRITE0), "BIO_nwrite0"},
++    {ERR_FUNC(BIO_F_BIO_PARSE_HOSTSERV), "BIO_parse_hostserv"},
++    {ERR_FUNC(BIO_F_BIO_PUTS), "BIO_puts"},
++    {ERR_FUNC(BIO_F_BIO_READ), "BIO_read"},
++    {ERR_FUNC(BIO_F_BIO_SOCKET), "BIO_socket"},
++    {ERR_FUNC(BIO_F_BIO_SOCKET_NBIO), "BIO_socket_nbio"},
++    {ERR_FUNC(BIO_F_BIO_SOCK_INFO), "BIO_sock_info"},
++    {ERR_FUNC(BIO_F_BIO_SOCK_INIT), "BIO_sock_init"},
++    {ERR_FUNC(BIO_F_BIO_WRITE), "BIO_write"},
++    {ERR_FUNC(BIO_F_BUFFER_CTRL), "buffer_ctrl"},
++    {ERR_FUNC(BIO_F_CONN_CTRL), "conn_ctrl"},
++    {ERR_FUNC(BIO_F_CONN_STATE), "conn_state"},
++    {ERR_FUNC(BIO_F_DGRAM_SCTP_READ), "dgram_sctp_read"},
++    {ERR_FUNC(BIO_F_DGRAM_SCTP_WRITE), "dgram_sctp_write"},
++    {ERR_FUNC(BIO_F_FILE_CTRL), "file_ctrl"},
++    {ERR_FUNC(BIO_F_FILE_READ), "file_read"},
++    {ERR_FUNC(BIO_F_LINEBUFFER_CTRL), "linebuffer_ctrl"},
++    {ERR_FUNC(BIO_F_MEM_WRITE), "mem_write"},
++    {ERR_FUNC(BIO_F_SSL_NEW), "SSL_new"},
++    {0, NULL}
++};
++
++static ERR_STRING_DATA BIO_str_reasons[] = {
++    {ERR_REASON(BIO_R_ACCEPT_ERROR), "accept error"},
++    {ERR_REASON(BIO_R_ADDRINFO_ADDR_IS_NOT_AF_INET),
++     "addrinfo addr is not af inet"},
++    {ERR_REASON(BIO_R_AMBIGUOUS_HOST_OR_SERVICE),
++     "ambiguous host or service"},
++    {ERR_REASON(BIO_R_BAD_FOPEN_MODE), "bad fopen mode"},
++    {ERR_REASON(BIO_R_BROKEN_PIPE), "broken pipe"},
++    {ERR_REASON(BIO_R_CONNECT_ERROR), "connect error"},
++    {ERR_REASON(BIO_R_GETHOSTBYNAME_ADDR_IS_NOT_AF_INET),
++     "gethostbyname addr is not af inet"},
++    {ERR_REASON(BIO_R_GETSOCKNAME_ERROR), "getsockname error"},
++    {ERR_REASON(BIO_R_GETSOCKNAME_TRUNCATED_ADDRESS),
++     "getsockname truncated address"},
++    {ERR_REASON(BIO_R_GETTING_SOCKTYPE), "getting socktype"},
++    {ERR_REASON(BIO_R_INVALID_ARGUMENT), "invalid argument"},
++    {ERR_REASON(BIO_R_INVALID_SOCKET), "invalid socket"},
++    {ERR_REASON(BIO_R_IN_USE), "in use"},
++    {ERR_REASON(BIO_R_LISTEN_V6_ONLY), "listen v6 only"},
++    {ERR_REASON(BIO_R_LOOKUP_RETURNED_NOTHING), "lookup returned nothing"},
++    {ERR_REASON(BIO_R_MALFORMED_HOST_OR_SERVICE),
++     "malformed host or service"},
++    {ERR_REASON(BIO_R_NBIO_CONNECT_ERROR), "nbio connect error"},
++    {ERR_REASON(BIO_R_NO_ACCEPT_ADDR_OR_SERVICE_SPECIFIED),
++     "no accept addr or service specified"},
++    {ERR_REASON(BIO_R_NO_HOSTNAME_OR_SERVICE_SPECIFIED),
++     "no hostname or service specified"},
++    {ERR_REASON(BIO_R_NO_PORT_DEFINED), "no port defined"},
++    {ERR_REASON(BIO_R_NO_SUCH_FILE), "no such file"},
++    {ERR_REASON(BIO_R_NULL_PARAMETER), "null parameter"},
++    {ERR_REASON(BIO_R_UNABLE_TO_BIND_SOCKET), "unable to bind socket"},
++    {ERR_REASON(BIO_R_UNABLE_TO_CREATE_SOCKET), "unable to create socket"},
++    {ERR_REASON(BIO_R_UNABLE_TO_KEEPALIVE), "unable to keepalive"},
++    {ERR_REASON(BIO_R_UNABLE_TO_LISTEN_SOCKET), "unable to listen socket"},
++    {ERR_REASON(BIO_R_UNABLE_TO_NODELAY), "unable to nodelay"},
++    {ERR_REASON(BIO_R_UNABLE_TO_REUSEADDR), "unable to reuseaddr"},
++    {ERR_REASON(BIO_R_UNAVAILABLE_IP_FAMILY), "unavailable ip family"},
++    {ERR_REASON(BIO_R_UNINITIALIZED), "uninitialized"},
++    {ERR_REASON(BIO_R_UNKNOWN_INFO_TYPE), "unknown info type"},
++    {ERR_REASON(BIO_R_UNSUPPORTED_IP_FAMILY), "unsupported ip family"},
++    {ERR_REASON(BIO_R_UNSUPPORTED_METHOD), "unsupported method"},
++    {ERR_REASON(BIO_R_UNSUPPORTED_PROTOCOL_FAMILY),
++     "unsupported protocol family"},
++    {ERR_REASON(BIO_R_WRITE_TO_READ_ONLY_BIO), "write to read only BIO"},
++    {ERR_REASON(BIO_R_WSASTARTUP), "WSAStartup"},
++    {0, NULL}
++};
++
++#endif
++
++int ERR_load_BIO_strings(void)
++{
++#ifndef OPENSSL_NO_ERR
++
++    if (ERR_func_error_string(BIO_str_functs[0].error) == NULL) {
++        ERR_load_strings(0, BIO_str_functs);
++        ERR_load_strings(0, BIO_str_reasons);
++    }
++#endif
++    return 1;
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/bio/bio_lcl.h b/CryptoPkg/Library/OpensslLib/openssl/crypto/bio/bio_lcl.h
+new file mode 100644
+index 0000000..39178cf
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/bio/bio_lcl.h
+@@ -0,0 +1,188 @@
++/*
++ * Copyright 2005-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#define USE_SOCKETS
++#include "e_os.h"
++
++/* BEGIN BIO_ADDRINFO/BIO_ADDR stuff. */
++
++#ifndef OPENSSL_NO_SOCK
++/*
++ * Throughout this file and b_addr.c, the existence of the macro
++ * AI_PASSIVE is used to detect the availability of struct addrinfo,
++ * getnameinfo() and getaddrinfo().  If that macro doesn't exist,
++ * we use our own implementation instead.
++ */
++
++/*
++ * It's imperative that these macros get defined before openssl/bio.h gets
++ * included.  Otherwise, the AI_PASSIVE hack will not work properly.
++ * For clarity, we check for internal/cryptlib.h since it's a common header
++ * that also includes bio.h.
++ */
++# ifdef HEADER_CRYPTLIB_H
++#  error internal/cryptlib.h included before bio_lcl.h
++# endif
++# ifdef HEADER_BIO_H
++#  error openssl/bio.h included before bio_lcl.h
++# endif
++
++/*
++ * Undefine AF_UNIX on systems that define it but don't support it.
++ */
++# if defined(OPENSSL_SYS_WINDOWS) || defined(OPENSSL_SYS_VMS)
++#  undef AF_UNIX
++# endif
++
++# ifdef AI_PASSIVE
++
++/*
++ * There's a bug in VMS C header file netdb.h, where struct addrinfo
++ * always is the P32 variant, but the functions that handle that structure,
++ * such as getaddrinfo() and freeaddrinfo() adapt to the initial pointer
++ * size.  The easiest workaround is to force struct addrinfo to be the
++ * 64-bit variant when compiling in P64 mode.
++ */
++#  if defined(OPENSSL_SYS_VMS) && __INITIAL_POINTER_SIZE == 64
++#   define addrinfo __addrinfo64
++#  endif
++
++#  define bio_addrinfo_st addrinfo
++#  define bai_family      ai_family
++#  define bai_socktype    ai_socktype
++#  define bai_protocol    ai_protocol
++#  define bai_addrlen     ai_addrlen
++#  define bai_addr        ai_addr
++#  define bai_next        ai_next
++# else
++struct bio_addrinfo_st {
++    int bai_family;
++    int bai_socktype;
++    int bai_protocol;
++    size_t bai_addrlen;
++    struct sockaddr *bai_addr;
++    struct bio_addrinfo_st *bai_next;
++};
++# endif
++
++union bio_addr_st {
++    struct sockaddr sa;
++# ifdef AF_INET6
++    struct sockaddr_in6 s_in6;
++# endif
++    struct sockaddr_in s_in;
++# ifdef AF_UNIX
++    struct sockaddr_un s_un;
++# endif
++};
++#endif
++
++/* END BIO_ADDRINFO/BIO_ADDR stuff. */
++
++#include "internal/cryptlib.h"
++#include 
++
++typedef struct bio_f_buffer_ctx_struct {
++    /*-
++     * Buffers are setup like this:
++     *
++     * <---------------------- size ----------------------->
++     * +---------------------------------------------------+
++     * | consumed | remaining          | free space        |
++     * +---------------------------------------------------+
++     * <-- off --><------- len ------->
++     */
++    /*- BIO *bio; *//*
++     * this is now in the BIO struct
++     */
++    int ibuf_size;              /* how big is the input buffer */
++    int obuf_size;              /* how big is the output buffer */
++    char *ibuf;                 /* the char array */
++    int ibuf_len;               /* how many bytes are in it */
++    int ibuf_off;               /* write/read offset */
++    char *obuf;                 /* the char array */
++    int obuf_len;               /* how many bytes are in it */
++    int obuf_off;               /* write/read offset */
++} BIO_F_BUFFER_CTX;
++
++struct bio_st {
++    const BIO_METHOD *method;
++    /* bio, mode, argp, argi, argl, ret */
++    long (*callback) (struct bio_st *, int, const char *, int, long, long);
++    char *cb_arg;               /* first argument for the callback */
++    int init;
++    int shutdown;
++    int flags;                  /* extra storage */
++    int retry_reason;
++    int num;
++    void *ptr;
++    struct bio_st *next_bio;    /* used by filter BIOs */
++    struct bio_st *prev_bio;    /* used by filter BIOs */
++    int references;
++    uint64_t num_read;
++    uint64_t num_write;
++    CRYPTO_EX_DATA ex_data;
++    CRYPTO_RWLOCK *lock;
++};
++
++#ifndef OPENSSL_NO_SOCK
++# ifdef OPENSSL_SYS_VMS
++typedef unsigned int socklen_t;
++# endif
++
++extern CRYPTO_RWLOCK *bio_lookup_lock;
++
++int BIO_ADDR_make(BIO_ADDR *ap, const struct sockaddr *sa);
++const struct sockaddr *BIO_ADDR_sockaddr(const BIO_ADDR *ap);
++struct sockaddr *BIO_ADDR_sockaddr_noconst(BIO_ADDR *ap);
++socklen_t BIO_ADDR_sockaddr_size(const BIO_ADDR *ap);
++socklen_t BIO_ADDRINFO_sockaddr_size(const BIO_ADDRINFO *bai);
++const struct sockaddr *BIO_ADDRINFO_sockaddr(const BIO_ADDRINFO *bai);
++#endif
++
++extern CRYPTO_RWLOCK *bio_type_lock;
++
++void bio_sock_cleanup_int(void);
++
++#if BIO_FLAGS_UPLINK==0
++/* Shortcut UPLINK calls on most platforms... */
++# define UP_stdin        stdin
++# define UP_stdout       stdout
++# define UP_stderr       stderr
++# define UP_fprintf      fprintf
++# define UP_fgets        fgets
++# define UP_fread        fread
++# define UP_fwrite       fwrite
++# undef  UP_fsetmod
++# define UP_feof         feof
++# define UP_fclose       fclose
++
++# define UP_fopen        fopen
++# define UP_fseek        fseek
++# define UP_ftell        ftell
++# define UP_fflush       fflush
++# define UP_ferror       ferror
++# ifdef _WIN32
++#  define UP_fileno       _fileno
++#  define UP_open         _open
++#  define UP_read         _read
++#  define UP_write        _write
++#  define UP_lseek        _lseek
++#  define UP_close        _close
++# else
++#  define UP_fileno       fileno
++#  define UP_open         open
++#  define UP_read         read
++#  define UP_write        write
++#  define UP_lseek        lseek
++#  define UP_close        close
++# endif
++
++#endif
++
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/bio/bio_lib.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/bio/bio_lib.c
+new file mode 100644
+index 0000000..62392c3
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/bio/bio_lib.c
+@@ -0,0 +1,600 @@
++/*
++ * Copyright 1995-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include 
++#include 
++#include "bio_lcl.h"
++#include "internal/cryptlib.h"
++
++BIO *BIO_new(const BIO_METHOD *method)
++{
++    BIO *bio = OPENSSL_zalloc(sizeof(*bio));
++
++    if (bio == NULL) {
++        BIOerr(BIO_F_BIO_NEW, ERR_R_MALLOC_FAILURE);
++        return (NULL);
++    }
++
++    bio->method = method;
++    bio->shutdown = 1;
++    bio->references = 1;
++
++    if (!CRYPTO_new_ex_data(CRYPTO_EX_INDEX_BIO, bio, &bio->ex_data))
++        goto err;
++
++    bio->lock = CRYPTO_THREAD_lock_new();
++    if (bio->lock == NULL) {
++        BIOerr(BIO_F_BIO_NEW, ERR_R_MALLOC_FAILURE);
++        CRYPTO_free_ex_data(CRYPTO_EX_INDEX_BIO, bio, &bio->ex_data);
++        goto err;
++    }
++
++    if (method->create != NULL && !method->create(bio)) {
++        BIOerr(BIO_F_BIO_NEW, ERR_R_INIT_FAIL);
++        CRYPTO_free_ex_data(CRYPTO_EX_INDEX_BIO, bio, &bio->ex_data);
++        CRYPTO_THREAD_lock_free(bio->lock);
++        goto err;
++    }
++
++    return bio;
++
++err:
++    OPENSSL_free(bio);
++    return NULL;
++}
++
++int BIO_free(BIO *a)
++{
++    int i;
++
++    if (a == NULL)
++        return 0;
++
++    if (CRYPTO_atomic_add(&a->references, -1, &i, a->lock) <= 0)
++        return 0;
++
++    REF_PRINT_COUNT("BIO", a);
++    if (i > 0)
++        return 1;
++    REF_ASSERT_ISNT(i < 0);
++    if ((a->callback != NULL) &&
++        ((i = (int)a->callback(a, BIO_CB_FREE, NULL, 0, 0L, 1L)) <= 0))
++        return i;
++
++    if ((a->method != NULL) && (a->method->destroy != NULL))
++        a->method->destroy(a);
++
++    CRYPTO_free_ex_data(CRYPTO_EX_INDEX_BIO, a, &a->ex_data);
++
++    CRYPTO_THREAD_lock_free(a->lock);
++
++    OPENSSL_free(a);
++
++    return 1;
++}
++
++void BIO_set_data(BIO *a, void *ptr)
++{
++    a->ptr = ptr;
++}
++
++void *BIO_get_data(BIO *a)
++{
++    return a->ptr;
++}
++
++void BIO_set_init(BIO *a, int init)
++{
++    a->init = init;
++}
++
++int BIO_get_init(BIO *a)
++{
++    return a->init;
++}
++
++void BIO_set_shutdown(BIO *a, int shut)
++{
++    a->shutdown = shut;
++}
++
++int BIO_get_shutdown(BIO *a)
++{
++    return a->shutdown;
++}
++
++void BIO_vfree(BIO *a)
++{
++    BIO_free(a);
++}
++
++int BIO_up_ref(BIO *a)
++{
++    int i;
++
++    if (CRYPTO_atomic_add(&a->references, 1, &i, a->lock) <= 0)
++        return 0;
++
++    REF_PRINT_COUNT("BIO", a);
++    REF_ASSERT_ISNT(i < 2);
++    return ((i > 1) ? 1 : 0);
++}
++
++void BIO_clear_flags(BIO *b, int flags)
++{
++    b->flags &= ~flags;
++}
++
++int BIO_test_flags(const BIO *b, int flags)
++{
++    return (b->flags & flags);
++}
++
++void BIO_set_flags(BIO *b, int flags)
++{
++    b->flags |= flags;
++}
++
++long (*BIO_get_callback(const BIO *b)) (struct bio_st *, int, const char *,
++                                        int, long, long) {
++    return b->callback;
++}
++
++void BIO_set_callback(BIO *b,
++                      long (*cb) (struct bio_st *, int, const char *, int,
++                                  long, long))
++{
++    b->callback = cb;
++}
++
++void BIO_set_callback_arg(BIO *b, char *arg)
++{
++    b->cb_arg = arg;
++}
++
++char *BIO_get_callback_arg(const BIO *b)
++{
++    return b->cb_arg;
++}
++
++const char *BIO_method_name(const BIO *b)
++{
++    return b->method->name;
++}
++
++int BIO_method_type(const BIO *b)
++{
++    return b->method->type;
++}
++
++int BIO_read(BIO *b, void *out, int outl)
++{
++    int i;
++    long (*cb) (BIO *, int, const char *, int, long, long);
++
++    if ((b == NULL) || (b->method == NULL) || (b->method->bread == NULL)) {
++        BIOerr(BIO_F_BIO_READ, BIO_R_UNSUPPORTED_METHOD);
++        return (-2);
++    }
++
++    cb = b->callback;
++    if ((cb != NULL) &&
++        ((i = (int)cb(b, BIO_CB_READ, out, outl, 0L, 1L)) <= 0))
++        return (i);
++
++    if (!b->init) {
++        BIOerr(BIO_F_BIO_READ, BIO_R_UNINITIALIZED);
++        return (-2);
++    }
++
++    i = b->method->bread(b, out, outl);
++
++    if (i > 0)
++        b->num_read += (uint64_t)i;
++
++    if (cb != NULL)
++        i = (int)cb(b, BIO_CB_READ | BIO_CB_RETURN, out, outl, 0L, (long)i);
++    return (i);
++}
++
++int BIO_write(BIO *b, const void *in, int inl)
++{
++    int i;
++    long (*cb) (BIO *, int, const char *, int, long, long);
++
++    if (b == NULL)
++        return (0);
++
++    cb = b->callback;
++    if ((b->method == NULL) || (b->method->bwrite == NULL)) {
++        BIOerr(BIO_F_BIO_WRITE, BIO_R_UNSUPPORTED_METHOD);
++        return (-2);
++    }
++
++    if ((cb != NULL) &&
++        ((i = (int)cb(b, BIO_CB_WRITE, in, inl, 0L, 1L)) <= 0))
++        return (i);
++
++    if (!b->init) {
++        BIOerr(BIO_F_BIO_WRITE, BIO_R_UNINITIALIZED);
++        return (-2);
++    }
++
++    i = b->method->bwrite(b, in, inl);
++
++    if (i > 0)
++        b->num_write += (uint64_t)i;
++
++    if (cb != NULL)
++        i = (int)cb(b, BIO_CB_WRITE | BIO_CB_RETURN, in, inl, 0L, (long)i);
++    return (i);
++}
++
++int BIO_puts(BIO *b, const char *in)
++{
++    int i;
++    long (*cb) (BIO *, int, const char *, int, long, long);
++
++    if ((b == NULL) || (b->method == NULL) || (b->method->bputs == NULL)) {
++        BIOerr(BIO_F_BIO_PUTS, BIO_R_UNSUPPORTED_METHOD);
++        return (-2);
++    }
++
++    cb = b->callback;
++
++    if ((cb != NULL) && ((i = (int)cb(b, BIO_CB_PUTS, in, 0, 0L, 1L)) <= 0))
++        return (i);
++
++    if (!b->init) {
++        BIOerr(BIO_F_BIO_PUTS, BIO_R_UNINITIALIZED);
++        return (-2);
++    }
++
++    i = b->method->bputs(b, in);
++
++    if (i > 0)
++        b->num_write += (uint64_t)i;
++
++    if (cb != NULL)
++        i = (int)cb(b, BIO_CB_PUTS | BIO_CB_RETURN, in, 0, 0L, (long)i);
++    return (i);
++}
++
++int BIO_gets(BIO *b, char *in, int inl)
++{
++    int i;
++    long (*cb) (BIO *, int, const char *, int, long, long);
++
++    if ((b == NULL) || (b->method == NULL) || (b->method->bgets == NULL)) {
++        BIOerr(BIO_F_BIO_GETS, BIO_R_UNSUPPORTED_METHOD);
++        return (-2);
++    }
++
++    cb = b->callback;
++
++    if ((cb != NULL) && ((i = (int)cb(b, BIO_CB_GETS, in, inl, 0L, 1L)) <= 0))
++        return (i);
++
++    if (!b->init) {
++        BIOerr(BIO_F_BIO_GETS, BIO_R_UNINITIALIZED);
++        return (-2);
++    }
++
++    i = b->method->bgets(b, in, inl);
++
++    if (cb != NULL)
++        i = (int)cb(b, BIO_CB_GETS | BIO_CB_RETURN, in, inl, 0L, (long)i);
++    return (i);
++}
++
++int BIO_indent(BIO *b, int indent, int max)
++{
++    if (indent < 0)
++        indent = 0;
++    if (indent > max)
++        indent = max;
++    while (indent--)
++        if (BIO_puts(b, " ") != 1)
++            return 0;
++    return 1;
++}
++
++long BIO_int_ctrl(BIO *b, int cmd, long larg, int iarg)
++{
++    int i;
++
++    i = iarg;
++    return (BIO_ctrl(b, cmd, larg, (char *)&i));
++}
++
++void *BIO_ptr_ctrl(BIO *b, int cmd, long larg)
++{
++    void *p = NULL;
++
++    if (BIO_ctrl(b, cmd, larg, (char *)&p) <= 0)
++        return (NULL);
++    else
++        return (p);
++}
++
++long BIO_ctrl(BIO *b, int cmd, long larg, void *parg)
++{
++    long ret;
++    long (*cb) (BIO *, int, const char *, int, long, long);
++
++    if (b == NULL)
++        return (0);
++
++    if ((b->method == NULL) || (b->method->ctrl == NULL)) {
++        BIOerr(BIO_F_BIO_CTRL, BIO_R_UNSUPPORTED_METHOD);
++        return (-2);
++    }
++
++    cb = b->callback;
++
++    if ((cb != NULL) &&
++        ((ret = cb(b, BIO_CB_CTRL, parg, cmd, larg, 1L)) <= 0))
++        return (ret);
++
++    ret = b->method->ctrl(b, cmd, larg, parg);
++
++    if (cb != NULL)
++        ret = cb(b, BIO_CB_CTRL | BIO_CB_RETURN, parg, cmd, larg, ret);
++    return (ret);
++}
++
++long BIO_callback_ctrl(BIO *b, int cmd,
++                       void (*fp) (struct bio_st *, int, const char *, int,
++                                   long, long))
++{
++    long ret;
++    long (*cb) (BIO *, int, const char *, int, long, long);
++
++    if (b == NULL)
++        return (0);
++
++    if ((b->method == NULL) || (b->method->callback_ctrl == NULL)) {
++        BIOerr(BIO_F_BIO_CALLBACK_CTRL, BIO_R_UNSUPPORTED_METHOD);
++        return (-2);
++    }
++
++    cb = b->callback;
++
++    if ((cb != NULL) &&
++        ((ret = cb(b, BIO_CB_CTRL, (void *)&fp, cmd, 0, 1L)) <= 0))
++        return (ret);
++
++    ret = b->method->callback_ctrl(b, cmd, fp);
++
++    if (cb != NULL)
++        ret = cb(b, BIO_CB_CTRL | BIO_CB_RETURN, (void *)&fp, cmd, 0, ret);
++    return (ret);
++}
++
++/*
++ * It is unfortunate to duplicate in functions what the BIO_(w)pending macros
++ * do; but those macros have inappropriate return type, and for interfacing
++ * from other programming languages, C macros aren't much of a help anyway.
++ */
++size_t BIO_ctrl_pending(BIO *bio)
++{
++    return BIO_ctrl(bio, BIO_CTRL_PENDING, 0, NULL);
++}
++
++size_t BIO_ctrl_wpending(BIO *bio)
++{
++    return BIO_ctrl(bio, BIO_CTRL_WPENDING, 0, NULL);
++}
++
++/* put the 'bio' on the end of b's list of operators */
++BIO *BIO_push(BIO *b, BIO *bio)
++{
++    BIO *lb;
++
++    if (b == NULL)
++        return (bio);
++    lb = b;
++    while (lb->next_bio != NULL)
++        lb = lb->next_bio;
++    lb->next_bio = bio;
++    if (bio != NULL)
++        bio->prev_bio = lb;
++    /* called to do internal processing */
++    BIO_ctrl(b, BIO_CTRL_PUSH, 0, lb);
++    return (b);
++}
++
++/* Remove the first and return the rest */
++BIO *BIO_pop(BIO *b)
++{
++    BIO *ret;
++
++    if (b == NULL)
++        return (NULL);
++    ret = b->next_bio;
++
++    BIO_ctrl(b, BIO_CTRL_POP, 0, b);
++
++    if (b->prev_bio != NULL)
++        b->prev_bio->next_bio = b->next_bio;
++    if (b->next_bio != NULL)
++        b->next_bio->prev_bio = b->prev_bio;
++
++    b->next_bio = NULL;
++    b->prev_bio = NULL;
++    return (ret);
++}
++
++BIO *BIO_get_retry_BIO(BIO *bio, int *reason)
++{
++    BIO *b, *last;
++
++    b = last = bio;
++    for (;;) {
++        if (!BIO_should_retry(b))
++            break;
++        last = b;
++        b = b->next_bio;
++        if (b == NULL)
++            break;
++    }
++    if (reason != NULL)
++        *reason = last->retry_reason;
++    return (last);
++}
++
++int BIO_get_retry_reason(BIO *bio)
++{
++    return (bio->retry_reason);
++}
++
++void BIO_set_retry_reason(BIO *bio, int reason)
++{
++    bio->retry_reason = reason;
++}
++
++BIO *BIO_find_type(BIO *bio, int type)
++{
++    int mt, mask;
++
++    if (bio == NULL)
++        return NULL;
++    mask = type & 0xff;
++    do {
++        if (bio->method != NULL) {
++            mt = bio->method->type;
++
++            if (!mask) {
++                if (mt & type)
++                    return (bio);
++            } else if (mt == type)
++                return (bio);
++        }
++        bio = bio->next_bio;
++    } while (bio != NULL);
++    return (NULL);
++}
++
++BIO *BIO_next(BIO *b)
++{
++    if (b == NULL)
++        return NULL;
++    return b->next_bio;
++}
++
++void BIO_set_next(BIO *b, BIO *next)
++{
++    b->next_bio = next;
++}
++
++void BIO_free_all(BIO *bio)
++{
++    BIO *b;
++    int ref;
++
++    while (bio != NULL) {
++        b = bio;
++        ref = b->references;
++        bio = bio->next_bio;
++        BIO_free(b);
++        /* Since ref count > 1, don't free anyone else. */
++        if (ref > 1)
++            break;
++    }
++}
++
++BIO *BIO_dup_chain(BIO *in)
++{
++    BIO *ret = NULL, *eoc = NULL, *bio, *new_bio;
++
++    for (bio = in; bio != NULL; bio = bio->next_bio) {
++        if ((new_bio = BIO_new(bio->method)) == NULL)
++            goto err;
++        new_bio->callback = bio->callback;
++        new_bio->cb_arg = bio->cb_arg;
++        new_bio->init = bio->init;
++        new_bio->shutdown = bio->shutdown;
++        new_bio->flags = bio->flags;
++
++        /* This will let SSL_s_sock() work with stdin/stdout */
++        new_bio->num = bio->num;
++
++        if (!BIO_dup_state(bio, (char *)new_bio)) {
++            BIO_free(new_bio);
++            goto err;
++        }
++
++        /* copy app data */
++        if (!CRYPTO_dup_ex_data(CRYPTO_EX_INDEX_BIO, &new_bio->ex_data,
++                                &bio->ex_data)) {
++            BIO_free(new_bio);
++            goto err;
++        }
++
++        if (ret == NULL) {
++            eoc = new_bio;
++            ret = eoc;
++        } else {
++            BIO_push(eoc, new_bio);
++            eoc = new_bio;
++        }
++    }
++    return (ret);
++ err:
++    BIO_free_all(ret);
++
++    return (NULL);
++}
++
++void BIO_copy_next_retry(BIO *b)
++{
++    BIO_set_flags(b, BIO_get_retry_flags(b->next_bio));
++    b->retry_reason = b->next_bio->retry_reason;
++}
++
++int BIO_set_ex_data(BIO *bio, int idx, void *data)
++{
++    return (CRYPTO_set_ex_data(&(bio->ex_data), idx, data));
++}
++
++void *BIO_get_ex_data(BIO *bio, int idx)
++{
++    return (CRYPTO_get_ex_data(&(bio->ex_data), idx));
++}
++
++uint64_t BIO_number_read(BIO *bio)
++{
++    if (bio)
++        return bio->num_read;
++    return 0;
++}
++
++uint64_t BIO_number_written(BIO *bio)
++{
++    if (bio)
++        return bio->num_write;
++    return 0;
++}
++
++void bio_free_ex_data(BIO *bio)
++{
++    CRYPTO_free_ex_data(CRYPTO_EX_INDEX_BIO, bio, &bio->ex_data);
++}
++
++void bio_cleanup(void)
++{
++#ifndef OPENSSL_NO_SOCK
++    bio_sock_cleanup_int();
++    CRYPTO_THREAD_lock_free(bio_lookup_lock);
++    bio_lookup_lock = NULL;
++#endif
++    CRYPTO_THREAD_lock_free(bio_type_lock);
++    bio_type_lock = NULL;
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/bio/bio_meth.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/bio/bio_meth.c
+new file mode 100644
+index 0000000..c5f9f7e
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/bio/bio_meth.c
+@@ -0,0 +1,145 @@
++/*
++ * Copyright 2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include "bio_lcl.h"
++#include 
++
++CRYPTO_RWLOCK *bio_type_lock = NULL;
++static CRYPTO_ONCE bio_type_init = CRYPTO_ONCE_STATIC_INIT;
++
++DEFINE_RUN_ONCE_STATIC(do_bio_type_init)
++{
++    bio_type_lock = CRYPTO_THREAD_lock_new();
++    return bio_type_lock != NULL;
++}
++
++int BIO_get_new_index()
++{
++    static int bio_count = BIO_TYPE_START;
++    int newval;
++
++    if (!RUN_ONCE(&bio_type_init, do_bio_type_init)) {
++        BIOerr(BIO_F_BIO_GET_NEW_INDEX, ERR_R_MALLOC_FAILURE);
++        return -1;
++    }
++    if (!CRYPTO_atomic_add(&bio_count, 1, &newval, bio_type_lock))
++        return -1;
++    return newval;
++}
++
++BIO_METHOD *BIO_meth_new(int type, const char *name)
++{
++    BIO_METHOD *biom = OPENSSL_zalloc(sizeof(BIO_METHOD));
++
++    if (biom != NULL) {
++        biom->type = type;
++        biom->name = name;
++    }
++    return biom;
++}
++
++void BIO_meth_free(BIO_METHOD *biom)
++{
++    OPENSSL_free(biom);
++}
++
++int (*BIO_meth_get_write(BIO_METHOD *biom)) (BIO *, const char *, int)
++{
++    return biom->bwrite;
++}
++
++int BIO_meth_set_write(BIO_METHOD *biom,
++                       int (*bwrite) (BIO *, const char *, int))
++{
++    biom->bwrite = bwrite;
++    return 1;
++}
++
++int (*BIO_meth_get_read(BIO_METHOD *biom)) (BIO *, char *, int)
++{
++    return biom->bread;
++}
++
++int BIO_meth_set_read(BIO_METHOD *biom,
++                      int (*bread) (BIO *, char *, int))
++{
++    biom->bread = bread;
++    return 1;
++}
++
++int (*BIO_meth_get_puts(BIO_METHOD *biom)) (BIO *, const char *)
++{
++    return biom->bputs;
++}
++
++int BIO_meth_set_puts(BIO_METHOD *biom,
++                      int (*bputs) (BIO *, const char *))
++{
++    biom->bputs = bputs;
++    return 1;
++}
++
++int (*BIO_meth_get_gets(BIO_METHOD *biom)) (BIO *, char *, int)
++{
++    return biom->bgets;
++}
++
++int BIO_meth_set_gets(BIO_METHOD *biom,
++                      int (*bgets) (BIO *, char *, int))
++{
++    biom->bgets = bgets;
++    return 1;
++}
++
++long (*BIO_meth_get_ctrl(BIO_METHOD *biom)) (BIO *, int, long, void *)
++{
++    return biom->ctrl;
++}
++
++int BIO_meth_set_ctrl(BIO_METHOD *biom,
++                      long (*ctrl) (BIO *, int, long, void *))
++{
++    biom->ctrl = ctrl;
++    return 1;
++}
++
++int (*BIO_meth_get_create(BIO_METHOD *biom)) (BIO *)
++{
++    return biom->create;
++}
++
++int BIO_meth_set_create(BIO_METHOD *biom, int (*create) (BIO *))
++{
++    biom->create = create;
++    return 1;
++}
++
++int (*BIO_meth_get_destroy(BIO_METHOD *biom)) (BIO *)
++{
++    return biom->destroy;
++}
++
++int BIO_meth_set_destroy(BIO_METHOD *biom, int (*destroy) (BIO *))
++{
++    biom->destroy = destroy;
++    return 1;
++}
++
++long (*BIO_meth_get_callback_ctrl(BIO_METHOD *biom)) (BIO *, int, bio_info_cb *)
++{
++    return biom->callback_ctrl;
++}
++
++int BIO_meth_set_callback_ctrl(BIO_METHOD *biom,
++                               long (*callback_ctrl) (BIO *, int,
++                                                      bio_info_cb *))
++{
++    biom->callback_ctrl = callback_ctrl;
++    return 1;
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/bio/bss_acpt.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/bio/bss_acpt.c
+new file mode 100644
+index 0000000..6fb971a
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/bio/bss_acpt.c
+@@ -0,0 +1,557 @@
++/*
++ * Copyright 1995-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include 
++#include "bio_lcl.h"
++
++#ifndef OPENSSL_NO_SOCK
++
++typedef struct bio_accept_st {
++    int state;
++    int accept_family;
++    int bind_mode;     /* Socket mode for BIO_listen */
++    int accepted_mode; /* Socket mode for BIO_accept (set on accepted sock) */
++    char *param_addr;
++    char *param_serv;
++
++    int accept_sock;
++
++    BIO_ADDRINFO *addr_first;
++    const BIO_ADDRINFO *addr_iter;
++    BIO_ADDR cache_accepting_addr;   /* Useful if we asked for port 0 */
++    char *cache_accepting_name, *cache_accepting_serv;
++    BIO_ADDR cache_peer_addr;
++    char *cache_peer_name, *cache_peer_serv;
++
++    BIO *bio_chain;
++} BIO_ACCEPT;
++
++static int acpt_write(BIO *h, const char *buf, int num);
++static int acpt_read(BIO *h, char *buf, int size);
++static int acpt_puts(BIO *h, const char *str);
++static long acpt_ctrl(BIO *h, int cmd, long arg1, void *arg2);
++static int acpt_new(BIO *h);
++static int acpt_free(BIO *data);
++static int acpt_state(BIO *b, BIO_ACCEPT *c);
++static void acpt_close_socket(BIO *data);
++static BIO_ACCEPT *BIO_ACCEPT_new(void);
++static void BIO_ACCEPT_free(BIO_ACCEPT *a);
++
++# define ACPT_S_BEFORE                   1
++# define ACPT_S_GET_ADDR                 2
++# define ACPT_S_CREATE_SOCKET            3
++# define ACPT_S_LISTEN                   4
++# define ACPT_S_ACCEPT                   5
++# define ACPT_S_OK                       6
++
++static const BIO_METHOD methods_acceptp = {
++    BIO_TYPE_ACCEPT,
++    "socket accept",
++    acpt_write,
++    acpt_read,
++    acpt_puts,
++    NULL,                       /* connect_gets, */
++    acpt_ctrl,
++    acpt_new,
++    acpt_free,
++    NULL,
++};
++
++const BIO_METHOD *BIO_s_accept(void)
++{
++    return (&methods_acceptp);
++}
++
++static int acpt_new(BIO *bi)
++{
++    BIO_ACCEPT *ba;
++
++    bi->init = 0;
++    bi->num = (int)INVALID_SOCKET;
++    bi->flags = 0;
++    if ((ba = BIO_ACCEPT_new()) == NULL)
++        return (0);
++    bi->ptr = (char *)ba;
++    ba->state = ACPT_S_BEFORE;
++    bi->shutdown = 1;
++    return (1);
++}
++
++static BIO_ACCEPT *BIO_ACCEPT_new(void)
++{
++    BIO_ACCEPT *ret;
++
++    if ((ret = OPENSSL_zalloc(sizeof(*ret))) == NULL)
++        return (NULL);
++    ret->accept_family = BIO_FAMILY_IPANY;
++    ret->accept_sock = (int)INVALID_SOCKET;
++    return (ret);
++}
++
++static void BIO_ACCEPT_free(BIO_ACCEPT *a)
++{
++    if (a == NULL)
++        return;
++
++    OPENSSL_free(a->param_addr);
++    OPENSSL_free(a->param_serv);
++    BIO_ADDRINFO_free(a->addr_first);
++    OPENSSL_free(a->cache_accepting_name);
++    OPENSSL_free(a->cache_accepting_serv);
++    OPENSSL_free(a->cache_peer_name);
++    OPENSSL_free(a->cache_peer_serv);
++    BIO_free(a->bio_chain);
++    OPENSSL_free(a);
++}
++
++static void acpt_close_socket(BIO *bio)
++{
++    BIO_ACCEPT *c;
++
++    c = (BIO_ACCEPT *)bio->ptr;
++    if (c->accept_sock != (int)INVALID_SOCKET) {
++        shutdown(c->accept_sock, 2);
++        closesocket(c->accept_sock);
++        c->accept_sock = (int)INVALID_SOCKET;
++        bio->num = (int)INVALID_SOCKET;
++    }
++}
++
++static int acpt_free(BIO *a)
++{
++    BIO_ACCEPT *data;
++
++    if (a == NULL)
++        return (0);
++    data = (BIO_ACCEPT *)a->ptr;
++
++    if (a->shutdown) {
++        acpt_close_socket(a);
++        BIO_ACCEPT_free(data);
++        a->ptr = NULL;
++        a->flags = 0;
++        a->init = 0;
++    }
++    return (1);
++}
++
++static int acpt_state(BIO *b, BIO_ACCEPT *c)
++{
++    BIO *bio = NULL, *dbio;
++    int s = -1, ret = -1;
++
++    for (;;) {
++        switch (c->state) {
++        case ACPT_S_BEFORE:
++            if (c->param_addr == NULL && c->param_serv == NULL) {
++                BIOerr(BIO_F_ACPT_STATE, BIO_R_NO_ACCEPT_ADDR_OR_SERVICE_SPECIFIED);
++                ERR_add_error_data(4,
++                                   "hostname=", c->param_addr,
++                                   " service=", c->param_serv);
++                goto exit_loop;
++            }
++
++            /* Because we're starting a new bind, any cached name and serv
++             * are now obsolete and need to be cleaned out.
++             * QUESTION: should this be done in acpt_close_socket() instead?
++             */
++            OPENSSL_free(c->cache_accepting_name);
++            c->cache_accepting_name = NULL;
++            OPENSSL_free(c->cache_accepting_serv);
++            c->cache_accepting_serv = NULL;
++            OPENSSL_free(c->cache_peer_name);
++            c->cache_peer_name = NULL;
++            OPENSSL_free(c->cache_peer_serv);
++            c->cache_peer_serv = NULL;
++
++            c->state = ACPT_S_GET_ADDR;
++            break;
++
++        case ACPT_S_GET_ADDR:
++            {
++                int family = AF_UNSPEC;
++                switch (c->accept_family) {
++                case BIO_FAMILY_IPV6:
++                    if (1) { /* This is a trick we use to avoid bit rot.
++                              * at least the "else" part will always be
++                              * compiled.
++                              */
++#ifdef AF_INET6
++                        family = AF_INET6;
++                    } else {
++#endif
++                        BIOerr(BIO_F_ACPT_STATE, BIO_R_UNAVAILABLE_IP_FAMILY);
++                        goto exit_loop;
++                    }
++                    break;
++                case BIO_FAMILY_IPV4:
++                    family = AF_INET;
++                    break;
++                case BIO_FAMILY_IPANY:
++                    family = AF_UNSPEC;
++                    break;
++                default:
++                    BIOerr(BIO_F_ACPT_STATE, BIO_R_UNSUPPORTED_IP_FAMILY);
++                    goto exit_loop;
++                }
++                if (BIO_lookup(c->param_addr, c->param_serv, BIO_LOOKUP_SERVER,
++                               family, SOCK_STREAM, &c->addr_first) == 0)
++                    goto exit_loop;
++            }
++            if (c->addr_first == NULL) {
++                BIOerr(BIO_F_ACPT_STATE, BIO_R_LOOKUP_RETURNED_NOTHING);
++                goto exit_loop;
++            }
++            /* We're currently not iterating, but set this as preparation
++             * for possible future development in that regard
++             */
++            c->addr_iter = c->addr_first;
++            c->state = ACPT_S_CREATE_SOCKET;
++            break;
++
++        case ACPT_S_CREATE_SOCKET:
++            ret = BIO_socket(BIO_ADDRINFO_family(c->addr_iter),
++                             BIO_ADDRINFO_socktype(c->addr_iter),
++                             BIO_ADDRINFO_protocol(c->addr_iter), 0);
++            if (ret == (int)INVALID_SOCKET) {
++                SYSerr(SYS_F_SOCKET, get_last_socket_error());
++                ERR_add_error_data(4,
++                                   "hostname=", c->param_addr,
++                                   " service=", c->param_serv);
++                BIOerr(BIO_F_ACPT_STATE, BIO_R_UNABLE_TO_CREATE_SOCKET);
++                goto exit_loop;
++            }
++            c->accept_sock = ret;
++            b->num = ret;
++            c->state = ACPT_S_LISTEN;
++            break;
++
++        case ACPT_S_LISTEN:
++            {
++                if (!BIO_listen(c->accept_sock,
++                                BIO_ADDRINFO_address(c->addr_iter),
++                                c->bind_mode)) {
++                    BIO_closesocket(c->accept_sock);
++                    goto exit_loop;
++                }
++            }
++
++            {
++                union BIO_sock_info_u info;
++
++                info.addr = &c->cache_accepting_addr;
++                if (!BIO_sock_info(c->accept_sock, BIO_SOCK_INFO_ADDRESS,
++                                   &info)) {
++                    BIO_closesocket(c->accept_sock);
++                    goto exit_loop;
++                }
++            }
++
++            c->cache_accepting_name =
++                BIO_ADDR_hostname_string(&c->cache_accepting_addr, 1);
++            c->cache_accepting_serv =
++                BIO_ADDR_service_string(&c->cache_accepting_addr, 1);
++            c->state = ACPT_S_ACCEPT;
++            s = -1;
++            ret = 1;
++            goto end;
++
++        case ACPT_S_ACCEPT:
++            if (b->next_bio != NULL) {
++                c->state = ACPT_S_OK;
++                break;
++            }
++            BIO_clear_retry_flags(b);
++            b->retry_reason = 0;
++
++            s = BIO_accept_ex(c->accept_sock, &c->cache_peer_addr,
++                              c->accepted_mode);
++
++            /* If the returned socket is invalid, this might still be
++             * retryable
++             */
++            if (s < 0) {
++                if (BIO_sock_should_retry(s)) {
++                    BIO_set_retry_special(b);
++                    b->retry_reason = BIO_RR_ACCEPT;
++                    goto end;
++                }
++            }
++
++            /* If it wasn't retryable, we fail */
++            if (s < 0) {
++                ret = s;
++                goto exit_loop;
++            }
++
++            bio = BIO_new_socket(s, BIO_CLOSE);
++            if (bio == NULL)
++                goto exit_loop;
++
++            BIO_set_callback(bio, BIO_get_callback(b));
++            BIO_set_callback_arg(bio, BIO_get_callback_arg(b));
++
++            /*
++             * If the accept BIO has an bio_chain, we dup it and put the new
++             * socket at the end.
++             */
++            if (c->bio_chain != NULL) {
++                if ((dbio = BIO_dup_chain(c->bio_chain)) == NULL)
++                    goto exit_loop;
++                if (!BIO_push(dbio, bio))
++                    goto exit_loop;
++                bio = dbio;
++            }
++            if (BIO_push(b, bio) == NULL)
++                goto exit_loop;
++
++            c->cache_peer_name =
++                BIO_ADDR_hostname_string(&c->cache_peer_addr, 1);
++            c->cache_peer_serv =
++                BIO_ADDR_service_string(&c->cache_peer_addr, 1);
++            c->state = ACPT_S_OK;
++            bio = NULL;
++            ret = 1;
++            goto end;
++
++        case ACPT_S_OK:
++            if (b->next_bio == NULL) {
++                c->state = ACPT_S_ACCEPT;
++                break;
++            }
++            ret = 1;
++            goto end;
++
++        default:
++            ret = 0;
++            goto end;
++        }
++    }
++
++  exit_loop:
++    if (bio != NULL)
++        BIO_free(bio);
++    else if (s >= 0)
++        BIO_closesocket(s);
++  end:
++    return ret;
++}
++
++static int acpt_read(BIO *b, char *out, int outl)
++{
++    int ret = 0;
++    BIO_ACCEPT *data;
++
++    BIO_clear_retry_flags(b);
++    data = (BIO_ACCEPT *)b->ptr;
++
++    while (b->next_bio == NULL) {
++        ret = acpt_state(b, data);
++        if (ret <= 0)
++            return (ret);
++    }
++
++    ret = BIO_read(b->next_bio, out, outl);
++    BIO_copy_next_retry(b);
++    return (ret);
++}
++
++static int acpt_write(BIO *b, const char *in, int inl)
++{
++    int ret;
++    BIO_ACCEPT *data;
++
++    BIO_clear_retry_flags(b);
++    data = (BIO_ACCEPT *)b->ptr;
++
++    while (b->next_bio == NULL) {
++        ret = acpt_state(b, data);
++        if (ret <= 0)
++            return (ret);
++    }
++
++    ret = BIO_write(b->next_bio, in, inl);
++    BIO_copy_next_retry(b);
++    return (ret);
++}
++
++static long acpt_ctrl(BIO *b, int cmd, long num, void *ptr)
++{
++    int *ip;
++    long ret = 1;
++    BIO_ACCEPT *data;
++    char **pp;
++
++    data = (BIO_ACCEPT *)b->ptr;
++
++    switch (cmd) {
++    case BIO_CTRL_RESET:
++        ret = 0;
++        data->state = ACPT_S_BEFORE;
++        acpt_close_socket(b);
++        BIO_ADDRINFO_free(data->addr_first);
++        data->addr_first = NULL;
++        b->flags = 0;
++        break;
++    case BIO_C_DO_STATE_MACHINE:
++        /* use this one to start the connection */
++        ret = (long)acpt_state(b, data);
++        break;
++    case BIO_C_SET_ACCEPT:
++        if (ptr != NULL) {
++            if (num == 0) {
++                char *hold_serv = data->param_serv;
++                /* We affect the hostname regardless.  However, the input
++                 * string might contain a host:service spec, so we must
++                 * parse it, which might or might not affect the service
++                 */
++                OPENSSL_free(data->param_addr);
++                data->param_addr = NULL;
++                ret = BIO_parse_hostserv(ptr,
++                                         &data->param_addr,
++                                         &data->param_serv,
++                                         BIO_PARSE_PRIO_SERV);
++                if (hold_serv != data->param_serv)
++                    OPENSSL_free(hold_serv);
++                b->init = 1;
++            } else if (num == 1) {
++                OPENSSL_free(data->param_serv);
++                data->param_serv = BUF_strdup(ptr);
++                b->init = 1;
++            } else if (num == 2) {
++                data->bind_mode |= BIO_SOCK_NONBLOCK;
++            } else if (num == 3) {
++                BIO_free(data->bio_chain);
++                data->bio_chain = (BIO *)ptr;
++            } else if (num == 4) {
++                data->accept_family = *(int *)ptr;
++            }
++        } else {
++            if (num == 2) {
++                data->bind_mode &= ~BIO_SOCK_NONBLOCK;
++            }
++        }
++        break;
++    case BIO_C_SET_NBIO:
++        if (num != 0)
++            data->accepted_mode |= BIO_SOCK_NONBLOCK;
++        else
++            data->accepted_mode &= ~BIO_SOCK_NONBLOCK;
++        break;
++    case BIO_C_SET_FD:
++        b->init = 1;
++        b->num = *((int *)ptr);
++        data->accept_sock = b->num;
++        data->state = ACPT_S_ACCEPT;
++        b->shutdown = (int)num;
++        b->init = 1;
++        break;
++    case BIO_C_GET_FD:
++        if (b->init) {
++            ip = (int *)ptr;
++            if (ip != NULL)
++                *ip = data->accept_sock;
++            ret = data->accept_sock;
++        } else
++            ret = -1;
++        break;
++    case BIO_C_GET_ACCEPT:
++        if (b->init) {
++            if (num == 0 && ptr != NULL) {
++                pp = (char **)ptr;
++                *pp = data->cache_accepting_name;
++            } else if (num == 1 && ptr != NULL) {
++                pp = (char **)ptr;
++                *pp = data->cache_accepting_serv;
++            } else if (num == 2 && ptr != NULL) {
++                pp = (char **)ptr;
++                *pp = data->cache_peer_name;
++            } else if (num == 3 && ptr != NULL) {
++                pp = (char **)ptr;
++                *pp = data->cache_peer_serv;
++            } else if (num == 4) {
++                switch (BIO_ADDRINFO_family(data->addr_iter)) {
++#ifdef AF_INET6
++                case AF_INET6:
++                    ret = BIO_FAMILY_IPV6;
++                    break;
++#endif
++                case AF_INET:
++                    ret = BIO_FAMILY_IPV4;
++                    break;
++                case 0:
++                    ret = data->accept_family;
++                    break;
++                default:
++                    ret = -1;
++                    break;
++                }
++            } else
++                ret = -1;
++        } else
++            ret = -1;
++        break;
++    case BIO_CTRL_GET_CLOSE:
++        ret = b->shutdown;
++        break;
++    case BIO_CTRL_SET_CLOSE:
++        b->shutdown = (int)num;
++        break;
++    case BIO_CTRL_PENDING:
++    case BIO_CTRL_WPENDING:
++        ret = 0;
++        break;
++    case BIO_CTRL_FLUSH:
++        break;
++    case BIO_C_SET_BIND_MODE:
++        data->bind_mode = (int)num;
++        break;
++    case BIO_C_GET_BIND_MODE:
++        ret = (long)data->bind_mode;
++        break;
++    case BIO_CTRL_DUP:
++/*-     dbio=(BIO *)ptr;
++        if (data->param_port) EAY EAY
++                BIO_set_port(dbio,data->param_port);
++        if (data->param_hostname)
++                BIO_set_hostname(dbio,data->param_hostname);
++        BIO_set_nbio(dbio,data->nbio); */
++        break;
++
++    default:
++        ret = 0;
++        break;
++    }
++    return (ret);
++}
++
++static int acpt_puts(BIO *bp, const char *str)
++{
++    int n, ret;
++
++    n = strlen(str);
++    ret = acpt_write(bp, str, n);
++    return (ret);
++}
++
++BIO *BIO_new_accept(const char *str)
++{
++    BIO *ret;
++
++    ret = BIO_new(BIO_s_accept());
++    if (ret == NULL)
++        return (NULL);
++    if (BIO_set_accept_name(ret, str))
++        return (ret);
++    BIO_free(ret);
++    return (NULL);
++}
++
++#endif
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/bio/bss_bio.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/bio/bss_bio.c
+new file mode 100644
+index 0000000..de34f6b
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/bio/bss_bio.c
+@@ -0,0 +1,805 @@
++/*
++ * Copyright 1999-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++/*
++ * Special method for a BIO where the other endpoint is also a BIO of this
++ * kind, handled by the same thread (i.e. the "peer" is actually ourselves,
++ * wearing a different hat). Such "BIO pairs" are mainly for using the SSL
++ * library with I/O interfaces for which no specific BIO method is available.
++ * See ssl/ssltest.c for some hints on how this can be used.
++ */
++
++#include 
++#include 
++#include 
++#include 
++
++#include "bio_lcl.h"
++#include 
++#include 
++
++#include "e_os.h"
++
++static int bio_new(BIO *bio);
++static int bio_free(BIO *bio);
++static int bio_read(BIO *bio, char *buf, int size);
++static int bio_write(BIO *bio, const char *buf, int num);
++static long bio_ctrl(BIO *bio, int cmd, long num, void *ptr);
++static int bio_puts(BIO *bio, const char *str);
++
++static int bio_make_pair(BIO *bio1, BIO *bio2);
++static void bio_destroy_pair(BIO *bio);
++
++static const BIO_METHOD methods_biop = {
++    BIO_TYPE_BIO,
++    "BIO pair",
++    bio_write,
++    bio_read,
++    bio_puts,
++    NULL /* no bio_gets */ ,
++    bio_ctrl,
++    bio_new,
++    bio_free,
++    NULL                        /* no bio_callback_ctrl */
++};
++
++const BIO_METHOD *BIO_s_bio(void)
++{
++    return &methods_biop;
++}
++
++struct bio_bio_st {
++    BIO *peer;                  /* NULL if buf == NULL. If peer != NULL, then
++                                 * peer->ptr is also a bio_bio_st, and its
++                                 * "peer" member points back to us. peer !=
++                                 * NULL iff init != 0 in the BIO. */
++    /* This is for what we write (i.e. reading uses peer's struct): */
++    int closed;                 /* valid iff peer != NULL */
++    size_t len;                 /* valid iff buf != NULL; 0 if peer == NULL */
++    size_t offset;              /* valid iff buf != NULL; 0 if len == 0 */
++    size_t size;
++    char *buf;                  /* "size" elements (if != NULL) */
++    size_t request;             /* valid iff peer != NULL; 0 if len != 0,
++                                 * otherwise set by peer to number of bytes
++                                 * it (unsuccessfully) tried to read, never
++                                 * more than buffer space (size-len)
++                                 * warrants. */
++};
++
++static int bio_new(BIO *bio)
++{
++    struct bio_bio_st *b = OPENSSL_zalloc(sizeof(*b));
++
++    if (b == NULL)
++        return 0;
++
++    /* enough for one TLS record (just a default) */
++    b->size = 17 * 1024;
++
++    bio->ptr = b;
++    return 1;
++}
++
++static int bio_free(BIO *bio)
++{
++    struct bio_bio_st *b;
++
++    if (bio == NULL)
++        return 0;
++    b = bio->ptr;
++
++    assert(b != NULL);
++
++    if (b->peer)
++        bio_destroy_pair(bio);
++
++    OPENSSL_free(b->buf);
++    OPENSSL_free(b);
++
++    return 1;
++}
++
++static int bio_read(BIO *bio, char *buf, int size_)
++{
++    size_t size = size_;
++    size_t rest;
++    struct bio_bio_st *b, *peer_b;
++
++    BIO_clear_retry_flags(bio);
++
++    if (!bio->init)
++        return 0;
++
++    b = bio->ptr;
++    assert(b != NULL);
++    assert(b->peer != NULL);
++    peer_b = b->peer->ptr;
++    assert(peer_b != NULL);
++    assert(peer_b->buf != NULL);
++
++    peer_b->request = 0;        /* will be set in "retry_read" situation */
++
++    if (buf == NULL || size == 0)
++        return 0;
++
++    if (peer_b->len == 0) {
++        if (peer_b->closed)
++            return 0;           /* writer has closed, and no data is left */
++        else {
++            BIO_set_retry_read(bio); /* buffer is empty */
++            if (size <= peer_b->size)
++                peer_b->request = size;
++            else
++                /*
++                 * don't ask for more than the peer can deliver in one write
++                 */
++                peer_b->request = peer_b->size;
++            return -1;
++        }
++    }
++
++    /* we can read */
++    if (peer_b->len < size)
++        size = peer_b->len;
++
++    /* now read "size" bytes */
++
++    rest = size;
++
++    assert(rest > 0);
++    do {                        /* one or two iterations */
++        size_t chunk;
++
++        assert(rest <= peer_b->len);
++        if (peer_b->offset + rest <= peer_b->size)
++            chunk = rest;
++        else
++            /* wrap around ring buffer */
++            chunk = peer_b->size - peer_b->offset;
++        assert(peer_b->offset + chunk <= peer_b->size);
++
++        memcpy(buf, peer_b->buf + peer_b->offset, chunk);
++
++        peer_b->len -= chunk;
++        if (peer_b->len) {
++            peer_b->offset += chunk;
++            assert(peer_b->offset <= peer_b->size);
++            if (peer_b->offset == peer_b->size)
++                peer_b->offset = 0;
++            buf += chunk;
++        } else {
++            /* buffer now empty, no need to advance "buf" */
++            assert(chunk == rest);
++            peer_b->offset = 0;
++        }
++        rest -= chunk;
++    }
++    while (rest);
++
++    return size;
++}
++
++/*-
++ * non-copying interface: provide pointer to available data in buffer
++ *    bio_nread0:  return number of available bytes
++ *    bio_nread:   also advance index
++ * (example usage:  bio_nread0(), read from buffer, bio_nread()
++ *  or just         bio_nread(), read from buffer)
++ */
++/*
++ * WARNING: The non-copying interface is largely untested as of yet and may
++ * contain bugs.
++ */
++static ossl_ssize_t bio_nread0(BIO *bio, char **buf)
++{
++    struct bio_bio_st *b, *peer_b;
++    ossl_ssize_t num;
++
++    BIO_clear_retry_flags(bio);
++
++    if (!bio->init)
++        return 0;
++
++    b = bio->ptr;
++    assert(b != NULL);
++    assert(b->peer != NULL);
++    peer_b = b->peer->ptr;
++    assert(peer_b != NULL);
++    assert(peer_b->buf != NULL);
++
++    peer_b->request = 0;
++
++    if (peer_b->len == 0) {
++        char dummy;
++
++        /* avoid code duplication -- nothing available for reading */
++        return bio_read(bio, &dummy, 1); /* returns 0 or -1 */
++    }
++
++    num = peer_b->len;
++    if (peer_b->size < peer_b->offset + num)
++        /* no ring buffer wrap-around for non-copying interface */
++        num = peer_b->size - peer_b->offset;
++    assert(num > 0);
++
++    if (buf != NULL)
++        *buf = peer_b->buf + peer_b->offset;
++    return num;
++}
++
++static ossl_ssize_t bio_nread(BIO *bio, char **buf, size_t num_)
++{
++    struct bio_bio_st *b, *peer_b;
++    ossl_ssize_t num, available;
++
++    if (num_ > OSSL_SSIZE_MAX)
++        num = OSSL_SSIZE_MAX;
++    else
++        num = (ossl_ssize_t) num_;
++
++    available = bio_nread0(bio, buf);
++    if (num > available)
++        num = available;
++    if (num <= 0)
++        return num;
++
++    b = bio->ptr;
++    peer_b = b->peer->ptr;
++
++    peer_b->len -= num;
++    if (peer_b->len) {
++        peer_b->offset += num;
++        assert(peer_b->offset <= peer_b->size);
++        if (peer_b->offset == peer_b->size)
++            peer_b->offset = 0;
++    } else
++        peer_b->offset = 0;
++
++    return num;
++}
++
++static int bio_write(BIO *bio, const char *buf, int num_)
++{
++    size_t num = num_;
++    size_t rest;
++    struct bio_bio_st *b;
++
++    BIO_clear_retry_flags(bio);
++
++    if (!bio->init || buf == NULL || num == 0)
++        return 0;
++
++    b = bio->ptr;
++    assert(b != NULL);
++    assert(b->peer != NULL);
++    assert(b->buf != NULL);
++
++    b->request = 0;
++    if (b->closed) {
++        /* we already closed */
++        BIOerr(BIO_F_BIO_WRITE, BIO_R_BROKEN_PIPE);
++        return -1;
++    }
++
++    assert(b->len <= b->size);
++
++    if (b->len == b->size) {
++        BIO_set_retry_write(bio); /* buffer is full */
++        return -1;
++    }
++
++    /* we can write */
++    if (num > b->size - b->len)
++        num = b->size - b->len;
++
++    /* now write "num" bytes */
++
++    rest = num;
++
++    assert(rest > 0);
++    do {                        /* one or two iterations */
++        size_t write_offset;
++        size_t chunk;
++
++        assert(b->len + rest <= b->size);
++
++        write_offset = b->offset + b->len;
++        if (write_offset >= b->size)
++            write_offset -= b->size;
++        /* b->buf[write_offset] is the first byte we can write to. */
++
++        if (write_offset + rest <= b->size)
++            chunk = rest;
++        else
++            /* wrap around ring buffer */
++            chunk = b->size - write_offset;
++
++        memcpy(b->buf + write_offset, buf, chunk);
++
++        b->len += chunk;
++
++        assert(b->len <= b->size);
++
++        rest -= chunk;
++        buf += chunk;
++    }
++    while (rest);
++
++    return num;
++}
++
++/*-
++ * non-copying interface: provide pointer to region to write to
++ *   bio_nwrite0:  check how much space is available
++ *   bio_nwrite:   also increase length
++ * (example usage:  bio_nwrite0(), write to buffer, bio_nwrite()
++ *  or just         bio_nwrite(), write to buffer)
++ */
++static ossl_ssize_t bio_nwrite0(BIO *bio, char **buf)
++{
++    struct bio_bio_st *b;
++    size_t num;
++    size_t write_offset;
++
++    BIO_clear_retry_flags(bio);
++
++    if (!bio->init)
++        return 0;
++
++    b = bio->ptr;
++    assert(b != NULL);
++    assert(b->peer != NULL);
++    assert(b->buf != NULL);
++
++    b->request = 0;
++    if (b->closed) {
++        BIOerr(BIO_F_BIO_NWRITE0, BIO_R_BROKEN_PIPE);
++        return -1;
++    }
++
++    assert(b->len <= b->size);
++
++    if (b->len == b->size) {
++        BIO_set_retry_write(bio);
++        return -1;
++    }
++
++    num = b->size - b->len;
++    write_offset = b->offset + b->len;
++    if (write_offset >= b->size)
++        write_offset -= b->size;
++    if (write_offset + num > b->size)
++        /*
++         * no ring buffer wrap-around for non-copying interface (to fulfil
++         * the promise by BIO_ctrl_get_write_guarantee, BIO_nwrite may have
++         * to be called twice)
++         */
++        num = b->size - write_offset;
++
++    if (buf != NULL)
++        *buf = b->buf + write_offset;
++    assert(write_offset + num <= b->size);
++
++    return num;
++}
++
++static ossl_ssize_t bio_nwrite(BIO *bio, char **buf, size_t num_)
++{
++    struct bio_bio_st *b;
++    ossl_ssize_t num, space;
++
++    if (num_ > OSSL_SSIZE_MAX)
++        num = OSSL_SSIZE_MAX;
++    else
++        num = (ossl_ssize_t) num_;
++
++    space = bio_nwrite0(bio, buf);
++    if (num > space)
++        num = space;
++    if (num <= 0)
++        return num;
++    b = bio->ptr;
++    assert(b != NULL);
++    b->len += num;
++    assert(b->len <= b->size);
++
++    return num;
++}
++
++static long bio_ctrl(BIO *bio, int cmd, long num, void *ptr)
++{
++    long ret;
++    struct bio_bio_st *b = bio->ptr;
++
++    assert(b != NULL);
++
++    switch (cmd) {
++        /* specific CTRL codes */
++
++    case BIO_C_SET_WRITE_BUF_SIZE:
++        if (b->peer) {
++            BIOerr(BIO_F_BIO_CTRL, BIO_R_IN_USE);
++            ret = 0;
++        } else if (num == 0) {
++            BIOerr(BIO_F_BIO_CTRL, BIO_R_INVALID_ARGUMENT);
++            ret = 0;
++        } else {
++            size_t new_size = num;
++
++            if (b->size != new_size) {
++                OPENSSL_free(b->buf);
++                b->buf = NULL;
++                b->size = new_size;
++            }
++            ret = 1;
++        }
++        break;
++
++    case BIO_C_GET_WRITE_BUF_SIZE:
++        ret = (long)b->size;
++        break;
++
++    case BIO_C_MAKE_BIO_PAIR:
++        {
++            BIO *other_bio = ptr;
++
++            if (bio_make_pair(bio, other_bio))
++                ret = 1;
++            else
++                ret = 0;
++        }
++        break;
++
++    case BIO_C_DESTROY_BIO_PAIR:
++        /*
++         * Affects both BIOs in the pair -- call just once! Or let
++         * BIO_free(bio1); BIO_free(bio2); do the job.
++         */
++        bio_destroy_pair(bio);
++        ret = 1;
++        break;
++
++    case BIO_C_GET_WRITE_GUARANTEE:
++        /*
++         * How many bytes can the caller feed to the next write without
++         * having to keep any?
++         */
++        if (b->peer == NULL || b->closed)
++            ret = 0;
++        else
++            ret = (long)b->size - b->len;
++        break;
++
++    case BIO_C_GET_READ_REQUEST:
++        /*
++         * If the peer unsuccessfully tried to read, how many bytes were
++         * requested? (As with BIO_CTRL_PENDING, that number can usually be
++         * treated as boolean.)
++         */
++        ret = (long)b->request;
++        break;
++
++    case BIO_C_RESET_READ_REQUEST:
++        /*
++         * Reset request.  (Can be useful after read attempts at the other
++         * side that are meant to be non-blocking, e.g. when probing SSL_read
++         * to see if any data is available.)
++         */
++        b->request = 0;
++        ret = 1;
++        break;
++
++    case BIO_C_SHUTDOWN_WR:
++        /* similar to shutdown(..., SHUT_WR) */
++        b->closed = 1;
++        ret = 1;
++        break;
++
++    case BIO_C_NREAD0:
++        /* prepare for non-copying read */
++        ret = (long)bio_nread0(bio, ptr);
++        break;
++
++    case BIO_C_NREAD:
++        /* non-copying read */
++        ret = (long)bio_nread(bio, ptr, (size_t)num);
++        break;
++
++    case BIO_C_NWRITE0:
++        /* prepare for non-copying write */
++        ret = (long)bio_nwrite0(bio, ptr);
++        break;
++
++    case BIO_C_NWRITE:
++        /* non-copying write */
++        ret = (long)bio_nwrite(bio, ptr, (size_t)num);
++        break;
++
++        /* standard CTRL codes follow */
++
++    case BIO_CTRL_RESET:
++        if (b->buf != NULL) {
++            b->len = 0;
++            b->offset = 0;
++        }
++        ret = 0;
++        break;
++
++    case BIO_CTRL_GET_CLOSE:
++        ret = bio->shutdown;
++        break;
++
++    case BIO_CTRL_SET_CLOSE:
++        bio->shutdown = (int)num;
++        ret = 1;
++        break;
++
++    case BIO_CTRL_PENDING:
++        if (b->peer != NULL) {
++            struct bio_bio_st *peer_b = b->peer->ptr;
++
++            ret = (long)peer_b->len;
++        } else
++            ret = 0;
++        break;
++
++    case BIO_CTRL_WPENDING:
++        if (b->buf != NULL)
++            ret = (long)b->len;
++        else
++            ret = 0;
++        break;
++
++    case BIO_CTRL_DUP:
++        /* See BIO_dup_chain for circumstances we have to expect. */
++        {
++            BIO *other_bio = ptr;
++            struct bio_bio_st *other_b;
++
++            assert(other_bio != NULL);
++            other_b = other_bio->ptr;
++            assert(other_b != NULL);
++
++            assert(other_b->buf == NULL); /* other_bio is always fresh */
++
++            other_b->size = b->size;
++        }
++
++        ret = 1;
++        break;
++
++    case BIO_CTRL_FLUSH:
++        ret = 1;
++        break;
++
++    case BIO_CTRL_EOF:
++        if (b->peer != NULL) {
++            struct bio_bio_st *peer_b = b->peer->ptr;
++
++            if (peer_b->len == 0 && peer_b->closed)
++                ret = 1;
++            else
++                ret = 0;
++        } else {
++            ret = 1;
++        }
++        break;
++
++    default:
++        ret = 0;
++    }
++    return ret;
++}
++
++static int bio_puts(BIO *bio, const char *str)
++{
++    return bio_write(bio, str, strlen(str));
++}
++
++static int bio_make_pair(BIO *bio1, BIO *bio2)
++{
++    struct bio_bio_st *b1, *b2;
++
++    assert(bio1 != NULL);
++    assert(bio2 != NULL);
++
++    b1 = bio1->ptr;
++    b2 = bio2->ptr;
++
++    if (b1->peer != NULL || b2->peer != NULL) {
++        BIOerr(BIO_F_BIO_MAKE_PAIR, BIO_R_IN_USE);
++        return 0;
++    }
++
++    if (b1->buf == NULL) {
++        b1->buf = OPENSSL_malloc(b1->size);
++        if (b1->buf == NULL) {
++            BIOerr(BIO_F_BIO_MAKE_PAIR, ERR_R_MALLOC_FAILURE);
++            return 0;
++        }
++        b1->len = 0;
++        b1->offset = 0;
++    }
++
++    if (b2->buf == NULL) {
++        b2->buf = OPENSSL_malloc(b2->size);
++        if (b2->buf == NULL) {
++            BIOerr(BIO_F_BIO_MAKE_PAIR, ERR_R_MALLOC_FAILURE);
++            return 0;
++        }
++        b2->len = 0;
++        b2->offset = 0;
++    }
++
++    b1->peer = bio2;
++    b1->closed = 0;
++    b1->request = 0;
++    b2->peer = bio1;
++    b2->closed = 0;
++    b2->request = 0;
++
++    bio1->init = 1;
++    bio2->init = 1;
++
++    return 1;
++}
++
++static void bio_destroy_pair(BIO *bio)
++{
++    struct bio_bio_st *b = bio->ptr;
++
++    if (b != NULL) {
++        BIO *peer_bio = b->peer;
++
++        if (peer_bio != NULL) {
++            struct bio_bio_st *peer_b = peer_bio->ptr;
++
++            assert(peer_b != NULL);
++            assert(peer_b->peer == bio);
++
++            peer_b->peer = NULL;
++            peer_bio->init = 0;
++            assert(peer_b->buf != NULL);
++            peer_b->len = 0;
++            peer_b->offset = 0;
++
++            b->peer = NULL;
++            bio->init = 0;
++            assert(b->buf != NULL);
++            b->len = 0;
++            b->offset = 0;
++        }
++    }
++}
++
++/* Exported convenience functions */
++int BIO_new_bio_pair(BIO **bio1_p, size_t writebuf1,
++                     BIO **bio2_p, size_t writebuf2)
++{
++    BIO *bio1 = NULL, *bio2 = NULL;
++    long r;
++    int ret = 0;
++
++    bio1 = BIO_new(BIO_s_bio());
++    if (bio1 == NULL)
++        goto err;
++    bio2 = BIO_new(BIO_s_bio());
++    if (bio2 == NULL)
++        goto err;
++
++    if (writebuf1) {
++        r = BIO_set_write_buf_size(bio1, writebuf1);
++        if (!r)
++            goto err;
++    }
++    if (writebuf2) {
++        r = BIO_set_write_buf_size(bio2, writebuf2);
++        if (!r)
++            goto err;
++    }
++
++    r = BIO_make_bio_pair(bio1, bio2);
++    if (!r)
++        goto err;
++    ret = 1;
++
++ err:
++    if (ret == 0) {
++        BIO_free(bio1);
++        bio1 = NULL;
++        BIO_free(bio2);
++        bio2 = NULL;
++    }
++
++    *bio1_p = bio1;
++    *bio2_p = bio2;
++    return ret;
++}
++
++size_t BIO_ctrl_get_write_guarantee(BIO *bio)
++{
++    return BIO_ctrl(bio, BIO_C_GET_WRITE_GUARANTEE, 0, NULL);
++}
++
++size_t BIO_ctrl_get_read_request(BIO *bio)
++{
++    return BIO_ctrl(bio, BIO_C_GET_READ_REQUEST, 0, NULL);
++}
++
++int BIO_ctrl_reset_read_request(BIO *bio)
++{
++    return (BIO_ctrl(bio, BIO_C_RESET_READ_REQUEST, 0, NULL) != 0);
++}
++
++/*
++ * BIO_nread0/nread/nwrite0/nwrite are available only for BIO pairs for now
++ * (conceivably some other BIOs could allow non-copying reads and writes
++ * too.)
++ */
++int BIO_nread0(BIO *bio, char **buf)
++{
++    long ret;
++
++    if (!bio->init) {
++        BIOerr(BIO_F_BIO_NREAD0, BIO_R_UNINITIALIZED);
++        return -2;
++    }
++
++    ret = BIO_ctrl(bio, BIO_C_NREAD0, 0, buf);
++    if (ret > INT_MAX)
++        return INT_MAX;
++    else
++        return (int)ret;
++}
++
++int BIO_nread(BIO *bio, char **buf, int num)
++{
++    int ret;
++
++    if (!bio->init) {
++        BIOerr(BIO_F_BIO_NREAD, BIO_R_UNINITIALIZED);
++        return -2;
++    }
++
++    ret = (int)BIO_ctrl(bio, BIO_C_NREAD, num, buf);
++    if (ret > 0)
++        bio->num_read += ret;
++    return ret;
++}
++
++int BIO_nwrite0(BIO *bio, char **buf)
++{
++    long ret;
++
++    if (!bio->init) {
++        BIOerr(BIO_F_BIO_NWRITE0, BIO_R_UNINITIALIZED);
++        return -2;
++    }
++
++    ret = BIO_ctrl(bio, BIO_C_NWRITE0, 0, buf);
++    if (ret > INT_MAX)
++        return INT_MAX;
++    else
++        return (int)ret;
++}
++
++int BIO_nwrite(BIO *bio, char **buf, int num)
++{
++    int ret;
++
++    if (!bio->init) {
++        BIOerr(BIO_F_BIO_NWRITE, BIO_R_UNINITIALIZED);
++        return -2;
++    }
++
++    ret = BIO_ctrl(bio, BIO_C_NWRITE, num, buf);
++    if (ret > 0)
++        bio->num_write += ret;
++    return ret;
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/bio/bss_conn.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/bio/bss_conn.c
+new file mode 100644
+index 0000000..dfd0988
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/bio/bss_conn.c
+@@ -0,0 +1,545 @@
++/*
++ * Copyright 1995-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include 
++
++#include "bio_lcl.h"
++
++#ifndef OPENSSL_NO_SOCK
++
++typedef struct bio_connect_st {
++    int state;
++    int connect_family;
++    char *param_hostname;
++    char *param_service;
++    int connect_mode;
++
++    BIO_ADDRINFO *addr_first;
++    const BIO_ADDRINFO *addr_iter;
++    /*
++     * int socket; this will be kept in bio->num so that it is compatible
++     * with the bss_sock bio
++     */
++    /*
++     * called when the connection is initially made callback(BIO,state,ret);
++     * The callback should return 'ret'.  state is for compatibility with the
++     * ssl info_callback
++     */
++    int (*info_callback) (const BIO *bio, int state, int ret);
++} BIO_CONNECT;
++
++static int conn_write(BIO *h, const char *buf, int num);
++static int conn_read(BIO *h, char *buf, int size);
++static int conn_puts(BIO *h, const char *str);
++static long conn_ctrl(BIO *h, int cmd, long arg1, void *arg2);
++static int conn_new(BIO *h);
++static int conn_free(BIO *data);
++static long conn_callback_ctrl(BIO *h, int cmd, bio_info_cb *);
++
++static int conn_state(BIO *b, BIO_CONNECT *c);
++static void conn_close_socket(BIO *data);
++BIO_CONNECT *BIO_CONNECT_new(void);
++void BIO_CONNECT_free(BIO_CONNECT *a);
++
++#define BIO_CONN_S_BEFORE                1
++#define BIO_CONN_S_GET_ADDR              2
++#define BIO_CONN_S_CREATE_SOCKET         3
++#define BIO_CONN_S_CONNECT               4
++#define BIO_CONN_S_OK                    5
++#define BIO_CONN_S_BLOCKED_CONNECT       6
++
++static const BIO_METHOD methods_connectp = {
++    BIO_TYPE_CONNECT,
++    "socket connect",
++    conn_write,
++    conn_read,
++    conn_puts,
++    NULL,                       /* connect_gets, */
++    conn_ctrl,
++    conn_new,
++    conn_free,
++    conn_callback_ctrl,
++};
++
++static int conn_state(BIO *b, BIO_CONNECT *c)
++{
++    int ret = -1, i;
++    int (*cb) (const BIO *, int, int) = NULL;
++
++    if (c->info_callback != NULL)
++        cb = c->info_callback;
++
++    for (;;) {
++        switch (c->state) {
++        case BIO_CONN_S_BEFORE:
++            if (c->param_hostname == NULL && c->param_service == NULL) {
++                BIOerr(BIO_F_CONN_STATE, BIO_R_NO_HOSTNAME_OR_SERVICE_SPECIFIED);
++                ERR_add_error_data(4,
++                                   "hostname=", c->param_hostname,
++                                   " service=", c->param_service);
++                goto exit_loop;
++            }
++            c->state = BIO_CONN_S_GET_ADDR;
++            break;
++
++        case BIO_CONN_S_GET_ADDR:
++            {
++                int family = AF_UNSPEC;
++                switch (c->connect_family) {
++                case BIO_FAMILY_IPV6:
++                    if (1) { /* This is a trick we use to avoid bit rot.
++                              * at least the "else" part will always be
++                              * compiled.
++                              */
++#ifdef AF_INET6
++                        family = AF_INET6;
++                    } else {
++#endif
++                        BIOerr(BIO_F_CONN_STATE, BIO_R_UNAVAILABLE_IP_FAMILY);
++                        goto exit_loop;
++                    }
++                    break;
++                case BIO_FAMILY_IPV4:
++                    family = AF_INET;
++                    break;
++                case BIO_FAMILY_IPANY:
++                    family = AF_UNSPEC;
++                    break;
++                default:
++                    BIOerr(BIO_F_CONN_STATE, BIO_R_UNSUPPORTED_IP_FAMILY);
++                    goto exit_loop;
++                }
++                if (BIO_lookup(c->param_hostname, c->param_service,
++                               BIO_LOOKUP_CLIENT,
++                               family, SOCK_STREAM, &c->addr_first) == 0)
++                    goto exit_loop;
++            }
++            if (c->addr_first == NULL) {
++                BIOerr(BIO_F_CONN_STATE, BIO_R_LOOKUP_RETURNED_NOTHING);
++                goto exit_loop;
++            }
++            c->addr_iter = c->addr_first;
++            c->state = BIO_CONN_S_CREATE_SOCKET;
++            break;
++
++        case BIO_CONN_S_CREATE_SOCKET:
++            ret = BIO_socket(BIO_ADDRINFO_family(c->addr_iter),
++                             BIO_ADDRINFO_socktype(c->addr_iter),
++                             BIO_ADDRINFO_protocol(c->addr_iter), 0);
++            if (ret == (int)INVALID_SOCKET) {
++                SYSerr(SYS_F_SOCKET, get_last_socket_error());
++                ERR_add_error_data(4,
++                                   "hostname=", c->param_hostname,
++                                   " service=", c->param_service);
++                BIOerr(BIO_F_CONN_STATE, BIO_R_UNABLE_TO_CREATE_SOCKET);
++                goto exit_loop;
++            }
++            b->num = ret;
++            c->state = BIO_CONN_S_CONNECT;
++            break;
++
++        case BIO_CONN_S_CONNECT:
++            BIO_clear_retry_flags(b);
++            ret = BIO_connect(b->num, BIO_ADDRINFO_address(c->addr_iter),
++                              BIO_SOCK_KEEPALIVE | c->connect_mode);
++            b->retry_reason = 0;
++            if (ret == 0) {
++                if (BIO_sock_should_retry(ret)) {
++                    BIO_set_retry_special(b);
++                    c->state = BIO_CONN_S_BLOCKED_CONNECT;
++                    b->retry_reason = BIO_RR_CONNECT;
++                    ERR_clear_error();
++                } else if ((c->addr_iter = BIO_ADDRINFO_next(c->addr_iter))
++                           != NULL) {
++                    /*
++                     * if there are more addresses to try, do that first
++                     */
++                    BIO_closesocket(b->num);
++                    c->state = BIO_CONN_S_CREATE_SOCKET;
++                    ERR_clear_error();
++                    break;
++                } else {
++                    SYSerr(SYS_F_CONNECT, get_last_socket_error());
++                    ERR_add_error_data(4,
++                                       "hostname=", c->param_hostname,
++                                       " service=", c->param_service);
++                    BIOerr(BIO_F_CONN_STATE, BIO_R_CONNECT_ERROR);
++                }
++                goto exit_loop;
++            } else {
++                c->state = BIO_CONN_S_OK;
++            }
++            break;
++
++        case BIO_CONN_S_BLOCKED_CONNECT:
++            i = BIO_sock_error(b->num);
++            if (i) {
++                BIO_clear_retry_flags(b);
++                SYSerr(SYS_F_CONNECT, i);
++                ERR_add_error_data(4,
++                                   "hostname=", c->param_hostname,
++                                   " service=", c->param_service);
++                BIOerr(BIO_F_CONN_STATE, BIO_R_NBIO_CONNECT_ERROR);
++                ret = 0;
++                goto exit_loop;
++            } else
++                c->state = BIO_CONN_S_OK;
++            break;
++
++        case BIO_CONN_S_OK:
++            ret = 1;
++            goto exit_loop;
++        default:
++            /* abort(); */
++            goto exit_loop;
++        }
++
++        if (cb != NULL) {
++            if ((ret = cb((BIO *)b, c->state, ret)) == 0)
++                goto end;
++        }
++    }
++
++    /* Loop does not exit */
++ exit_loop:
++    if (cb != NULL)
++        ret = cb((BIO *)b, c->state, ret);
++ end:
++    return (ret);
++}
++
++BIO_CONNECT *BIO_CONNECT_new(void)
++{
++    BIO_CONNECT *ret;
++
++    if ((ret = OPENSSL_zalloc(sizeof(*ret))) == NULL)
++        return (NULL);
++    ret->state = BIO_CONN_S_BEFORE;
++    ret->connect_family = BIO_FAMILY_IPANY;
++    return (ret);
++}
++
++void BIO_CONNECT_free(BIO_CONNECT *a)
++{
++    if (a == NULL)
++        return;
++
++    OPENSSL_free(a->param_hostname);
++    OPENSSL_free(a->param_service);
++    BIO_ADDRINFO_free(a->addr_first);
++    OPENSSL_free(a);
++}
++
++const BIO_METHOD *BIO_s_connect(void)
++{
++    return (&methods_connectp);
++}
++
++static int conn_new(BIO *bi)
++{
++    bi->init = 0;
++    bi->num = (int)INVALID_SOCKET;
++    bi->flags = 0;
++    if ((bi->ptr = (char *)BIO_CONNECT_new()) == NULL)
++        return (0);
++    else
++        return (1);
++}
++
++static void conn_close_socket(BIO *bio)
++{
++    BIO_CONNECT *c;
++
++    c = (BIO_CONNECT *)bio->ptr;
++    if (bio->num != (int)INVALID_SOCKET) {
++        /* Only do a shutdown if things were established */
++        if (c->state == BIO_CONN_S_OK)
++            shutdown(bio->num, 2);
++        BIO_closesocket(bio->num);
++        bio->num = (int)INVALID_SOCKET;
++    }
++}
++
++static int conn_free(BIO *a)
++{
++    BIO_CONNECT *data;
++
++    if (a == NULL)
++        return (0);
++    data = (BIO_CONNECT *)a->ptr;
++
++    if (a->shutdown) {
++        conn_close_socket(a);
++        BIO_CONNECT_free(data);
++        a->ptr = NULL;
++        a->flags = 0;
++        a->init = 0;
++    }
++    return (1);
++}
++
++static int conn_read(BIO *b, char *out, int outl)
++{
++    int ret = 0;
++    BIO_CONNECT *data;
++
++    data = (BIO_CONNECT *)b->ptr;
++    if (data->state != BIO_CONN_S_OK) {
++        ret = conn_state(b, data);
++        if (ret <= 0)
++            return (ret);
++    }
++
++    if (out != NULL) {
++        clear_socket_error();
++        ret = readsocket(b->num, out, outl);
++        BIO_clear_retry_flags(b);
++        if (ret <= 0) {
++            if (BIO_sock_should_retry(ret))
++                BIO_set_retry_read(b);
++        }
++    }
++    return (ret);
++}
++
++static int conn_write(BIO *b, const char *in, int inl)
++{
++    int ret;
++    BIO_CONNECT *data;
++
++    data = (BIO_CONNECT *)b->ptr;
++    if (data->state != BIO_CONN_S_OK) {
++        ret = conn_state(b, data);
++        if (ret <= 0)
++            return (ret);
++    }
++
++    clear_socket_error();
++    ret = writesocket(b->num, in, inl);
++    BIO_clear_retry_flags(b);
++    if (ret <= 0) {
++        if (BIO_sock_should_retry(ret))
++            BIO_set_retry_write(b);
++    }
++    return (ret);
++}
++
++static long conn_ctrl(BIO *b, int cmd, long num, void *ptr)
++{
++    BIO *dbio;
++    int *ip;
++    const char **pptr = NULL;
++    long ret = 1;
++    BIO_CONNECT *data;
++
++    data = (BIO_CONNECT *)b->ptr;
++
++    switch (cmd) {
++    case BIO_CTRL_RESET:
++        ret = 0;
++        data->state = BIO_CONN_S_BEFORE;
++        conn_close_socket(b);
++        BIO_ADDRINFO_free(data->addr_first);
++        data->addr_first = NULL;
++        b->flags = 0;
++        break;
++    case BIO_C_DO_STATE_MACHINE:
++        /* use this one to start the connection */
++        if (data->state != BIO_CONN_S_OK)
++            ret = (long)conn_state(b, data);
++        else
++            ret = 1;
++        break;
++    case BIO_C_GET_CONNECT:
++        if (ptr != NULL) {
++            pptr = (const char **)ptr;
++            if (num == 0) {
++                *pptr = data->param_hostname;
++            } else if (num == 1) {
++                *pptr = data->param_service;
++            } else if (num == 2) {
++                *pptr = (const char *)BIO_ADDRINFO_address(data->addr_iter);
++            } else if (num == 3) {
++                switch (BIO_ADDRINFO_family(data->addr_iter)) {
++# ifdef AF_INET6
++                case AF_INET6:
++                    ret = BIO_FAMILY_IPV6;
++                    break;
++# endif
++                case AF_INET:
++                    ret = BIO_FAMILY_IPV4;
++                    break;
++                case 0:
++                    ret = data->connect_family;
++                    break;
++                default:
++                    ret = -1;
++                    break;
++                }
++            } else {
++                ret = 0;
++            }
++        } else {
++            ret = 0;
++        }
++        break;
++    case BIO_C_SET_CONNECT:
++        if (ptr != NULL) {
++            b->init = 1;
++            if (num == 0) {
++                char *hold_service = data->param_service;
++                /* We affect the hostname regardless.  However, the input
++                 * string might contain a host:service spec, so we must
++                 * parse it, which might or might not affect the service
++                 */
++                OPENSSL_free(data->param_hostname);
++                data->param_hostname = NULL;
++                ret = BIO_parse_hostserv(ptr,
++                                         &data->param_hostname,
++                                         &data->param_service,
++                                         BIO_PARSE_PRIO_HOST);
++                if (hold_service != data->param_service)
++                    OPENSSL_free(hold_service);
++            } else if (num == 1) {
++                OPENSSL_free(data->param_service);
++                data->param_service = BUF_strdup(ptr);
++            } else if (num == 2) {
++                const BIO_ADDR *addr = (const BIO_ADDR *)ptr;
++                if (ret) {
++                    data->param_hostname = BIO_ADDR_hostname_string(addr, 1);
++                    data->param_service = BIO_ADDR_service_string(addr, 1);
++                    BIO_ADDRINFO_free(data->addr_first);
++                    data->addr_first = NULL;
++                    data->addr_iter = NULL;
++                }
++            } else if (num == 3) {
++                data->connect_family = *(int *)ptr;
++            } else {
++                ret = 0;
++            }
++        }
++        break;
++    case BIO_C_SET_NBIO:
++        if (num != 0)
++            data->connect_mode |= BIO_SOCK_NONBLOCK;
++        else
++            data->connect_mode &= ~BIO_SOCK_NONBLOCK;
++        break;
++    case BIO_C_SET_CONNECT_MODE:
++        data->connect_mode = (int)num;
++        break;
++    case BIO_C_GET_FD:
++        if (b->init) {
++            ip = (int *)ptr;
++            if (ip != NULL)
++                *ip = b->num;
++            ret = b->num;
++        } else
++            ret = -1;
++        break;
++    case BIO_CTRL_GET_CLOSE:
++        ret = b->shutdown;
++        break;
++    case BIO_CTRL_SET_CLOSE:
++        b->shutdown = (int)num;
++        break;
++    case BIO_CTRL_PENDING:
++    case BIO_CTRL_WPENDING:
++        ret = 0;
++        break;
++    case BIO_CTRL_FLUSH:
++        break;
++    case BIO_CTRL_DUP:
++        {
++            dbio = (BIO *)ptr;
++            if (data->param_hostname)
++                BIO_set_conn_hostname(dbio, data->param_hostname);
++            if (data->param_service)
++                BIO_set_conn_port(dbio, data->param_service);
++            BIO_set_conn_ip_family(dbio, data->connect_family);
++            BIO_set_conn_mode(dbio, data->connect_mode);
++            /*
++             * FIXME: the cast of the function seems unlikely to be a good
++             * idea
++             */
++            (void)BIO_set_info_callback(dbio,
++                                        (bio_info_cb *)data->info_callback);
++        }
++        break;
++    case BIO_CTRL_SET_CALLBACK:
++        {
++# if 0                          /* FIXME: Should this be used? -- Richard
++                                 * Levitte */
++            BIOerr(BIO_F_CONN_CTRL, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
++            ret = -1;
++# else
++            ret = 0;
++# endif
++        }
++        break;
++    case BIO_CTRL_GET_CALLBACK:
++        {
++            int (**fptr) (const BIO *bio, int state, int xret);
++
++            fptr = (int (**)(const BIO *bio, int state, int xret))ptr;
++            *fptr = data->info_callback;
++        }
++        break;
++    default:
++        ret = 0;
++        break;
++    }
++    return (ret);
++}
++
++static long conn_callback_ctrl(BIO *b, int cmd, bio_info_cb *fp)
++{
++    long ret = 1;
++    BIO_CONNECT *data;
++
++    data = (BIO_CONNECT *)b->ptr;
++
++    switch (cmd) {
++    case BIO_CTRL_SET_CALLBACK:
++        {
++            data->info_callback =
++                (int (*)(const struct bio_st *, int, int))fp;
++        }
++        break;
++    default:
++        ret = 0;
++        break;
++    }
++    return (ret);
++}
++
++static int conn_puts(BIO *bp, const char *str)
++{
++    int n, ret;
++
++    n = strlen(str);
++    ret = conn_write(bp, str, n);
++    return (ret);
++}
++
++BIO *BIO_new_connect(const char *str)
++{
++    BIO *ret;
++
++    ret = BIO_new(BIO_s_connect());
++    if (ret == NULL)
++        return (NULL);
++    if (BIO_set_conn_hostname(ret, str))
++        return (ret);
++    BIO_free(ret);
++    return (NULL);
++}
++
++#endif
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/bio/bss_dgram.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/bio/bss_dgram.c
+new file mode 100644
+index 0000000..6dfcc9b
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/bio/bss_dgram.c
+@@ -0,0 +1,1944 @@
++/*
++ * Copyright 2005-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include 
++
++#include "bio_lcl.h"
++#ifndef OPENSSL_NO_DGRAM
++
++# if !(defined(_WIN32) || defined(OPENSSL_SYS_VMS))
++#  include 
++# endif
++# if defined(OPENSSL_SYS_VMS)
++#  include 
++# endif
++
++# ifndef OPENSSL_NO_SCTP
++#  include 
++#  include 
++#  define OPENSSL_SCTP_DATA_CHUNK_TYPE            0x00
++#  define OPENSSL_SCTP_FORWARD_CUM_TSN_CHUNK_TYPE 0xc0
++# endif
++
++# if defined(OPENSSL_SYS_LINUX) && !defined(IP_MTU)
++#  define IP_MTU      14        /* linux is lame */
++# endif
++
++# if OPENSSL_USE_IPV6 && !defined(IPPROTO_IPV6)
++#  define IPPROTO_IPV6 41       /* windows is lame */
++# endif
++
++# if defined(__FreeBSD__) && defined(IN6_IS_ADDR_V4MAPPED)
++/* Standard definition causes type-punning problems. */
++#  undef IN6_IS_ADDR_V4MAPPED
++#  define s6_addr32 __u6_addr.__u6_addr32
++#  define IN6_IS_ADDR_V4MAPPED(a)               \
++        (((a)->s6_addr32[0] == 0) &&          \
++         ((a)->s6_addr32[1] == 0) &&          \
++         ((a)->s6_addr32[2] == htonl(0x0000ffff)))
++# endif
++
++static int dgram_write(BIO *h, const char *buf, int num);
++static int dgram_read(BIO *h, char *buf, int size);
++static int dgram_puts(BIO *h, const char *str);
++static long dgram_ctrl(BIO *h, int cmd, long arg1, void *arg2);
++static int dgram_new(BIO *h);
++static int dgram_free(BIO *data);
++static int dgram_clear(BIO *bio);
++
++# ifndef OPENSSL_NO_SCTP
++static int dgram_sctp_write(BIO *h, const char *buf, int num);
++static int dgram_sctp_read(BIO *h, char *buf, int size);
++static int dgram_sctp_puts(BIO *h, const char *str);
++static long dgram_sctp_ctrl(BIO *h, int cmd, long arg1, void *arg2);
++static int dgram_sctp_new(BIO *h);
++static int dgram_sctp_free(BIO *data);
++#  ifdef SCTP_AUTHENTICATION_EVENT
++static void dgram_sctp_handle_auth_free_key_event(BIO *b, union sctp_notification
++                                                  *snp);
++#  endif
++# endif
++
++static int BIO_dgram_should_retry(int s);
++
++static void get_current_time(struct timeval *t);
++
++static const BIO_METHOD methods_dgramp = {
++    BIO_TYPE_DGRAM,
++    "datagram socket",
++    dgram_write,
++    dgram_read,
++    dgram_puts,
++    NULL,                       /* dgram_gets, */
++    dgram_ctrl,
++    dgram_new,
++    dgram_free,
++    NULL,
++};
++
++# ifndef OPENSSL_NO_SCTP
++static const BIO_METHOD methods_dgramp_sctp = {
++    BIO_TYPE_DGRAM_SCTP,
++    "datagram sctp socket",
++    dgram_sctp_write,
++    dgram_sctp_read,
++    dgram_sctp_puts,
++    NULL,                       /* dgram_gets, */
++    dgram_sctp_ctrl,
++    dgram_sctp_new,
++    dgram_sctp_free,
++    NULL,
++};
++# endif
++
++typedef struct bio_dgram_data_st {
++    BIO_ADDR peer;
++    unsigned int connected;
++    unsigned int _errno;
++    unsigned int mtu;
++    struct timeval next_timeout;
++    struct timeval socket_timeout;
++    unsigned int peekmode;
++} bio_dgram_data;
++
++# ifndef OPENSSL_NO_SCTP
++typedef struct bio_dgram_sctp_save_message_st {
++    BIO *bio;
++    char *data;
++    int length;
++} bio_dgram_sctp_save_message;
++
++typedef struct bio_dgram_sctp_data_st {
++    BIO_ADDR peer;
++    unsigned int connected;
++    unsigned int _errno;
++    unsigned int mtu;
++    struct bio_dgram_sctp_sndinfo sndinfo;
++    struct bio_dgram_sctp_rcvinfo rcvinfo;
++    struct bio_dgram_sctp_prinfo prinfo;
++    void (*handle_notifications) (BIO *bio, void *context, void *buf);
++    void *notification_context;
++    int in_handshake;
++    int ccs_rcvd;
++    int ccs_sent;
++    int save_shutdown;
++    int peer_auth_tested;
++    bio_dgram_sctp_save_message saved_message;
++} bio_dgram_sctp_data;
++# endif
++
++const BIO_METHOD *BIO_s_datagram(void)
++{
++    return (&methods_dgramp);
++}
++
++BIO *BIO_new_dgram(int fd, int close_flag)
++{
++    BIO *ret;
++
++    ret = BIO_new(BIO_s_datagram());
++    if (ret == NULL)
++        return (NULL);
++    BIO_set_fd(ret, fd, close_flag);
++    return (ret);
++}
++
++static int dgram_new(BIO *bi)
++{
++    bio_dgram_data *data = OPENSSL_zalloc(sizeof(*data));
++
++    if (data == NULL)
++        return 0;
++    bi->ptr = data;
++    return (1);
++}
++
++static int dgram_free(BIO *a)
++{
++    bio_dgram_data *data;
++
++    if (a == NULL)
++        return (0);
++    if (!dgram_clear(a))
++        return 0;
++
++    data = (bio_dgram_data *)a->ptr;
++    OPENSSL_free(data);
++
++    return (1);
++}
++
++static int dgram_clear(BIO *a)
++{
++    if (a == NULL)
++        return (0);
++    if (a->shutdown) {
++        if (a->init) {
++            BIO_closesocket(a->num);
++        }
++        a->init = 0;
++        a->flags = 0;
++    }
++    return (1);
++}
++
++static void dgram_adjust_rcv_timeout(BIO *b)
++{
++# if defined(SO_RCVTIMEO)
++    bio_dgram_data *data = (bio_dgram_data *)b->ptr;
++    union {
++        size_t s;
++        int i;
++    } sz = {
++        0
++    };
++
++    /* Is a timer active? */
++    if (data->next_timeout.tv_sec > 0 || data->next_timeout.tv_usec > 0) {
++        struct timeval timenow, timeleft;
++
++        /* Read current socket timeout */
++#  ifdef OPENSSL_SYS_WINDOWS
++        int timeout;
++
++        sz.i = sizeof(timeout);
++        if (getsockopt(b->num, SOL_SOCKET, SO_RCVTIMEO,
++                       (void *)&timeout, &sz.i) < 0) {
++            perror("getsockopt");
++        } else {
++            data->socket_timeout.tv_sec = timeout / 1000;
++            data->socket_timeout.tv_usec = (timeout % 1000) * 1000;
++        }
++#  else
++        sz.i = sizeof(data->socket_timeout);
++        if (getsockopt(b->num, SOL_SOCKET, SO_RCVTIMEO,
++                       &(data->socket_timeout), (void *)&sz) < 0) {
++            perror("getsockopt");
++        } else if (sizeof(sz.s) != sizeof(sz.i) && sz.i == 0)
++            OPENSSL_assert(sz.s <= sizeof(data->socket_timeout));
++#  endif
++
++        /* Get current time */
++        get_current_time(&timenow);
++
++        /* Calculate time left until timer expires */
++        memcpy(&timeleft, &(data->next_timeout), sizeof(struct timeval));
++        if (timeleft.tv_usec < timenow.tv_usec) {
++            timeleft.tv_usec = 1000000 - timenow.tv_usec + timeleft.tv_usec;
++            timeleft.tv_sec--;
++        } else {
++            timeleft.tv_usec -= timenow.tv_usec;
++        }
++        if (timeleft.tv_sec < timenow.tv_sec) {
++            timeleft.tv_sec = 0;
++            timeleft.tv_usec = 1;
++        } else {
++            timeleft.tv_sec -= timenow.tv_sec;
++        }
++
++        /*
++         * Adjust socket timeout if next handshake message timer will expire
++         * earlier.
++         */
++        if ((data->socket_timeout.tv_sec == 0
++             && data->socket_timeout.tv_usec == 0)
++            || (data->socket_timeout.tv_sec > timeleft.tv_sec)
++            || (data->socket_timeout.tv_sec == timeleft.tv_sec
++                && data->socket_timeout.tv_usec >= timeleft.tv_usec)) {
++#  ifdef OPENSSL_SYS_WINDOWS
++            timeout = timeleft.tv_sec * 1000 + timeleft.tv_usec / 1000;
++            if (setsockopt(b->num, SOL_SOCKET, SO_RCVTIMEO,
++                           (void *)&timeout, sizeof(timeout)) < 0) {
++                perror("setsockopt");
++            }
++#  else
++            if (setsockopt(b->num, SOL_SOCKET, SO_RCVTIMEO, &timeleft,
++                           sizeof(struct timeval)) < 0) {
++                perror("setsockopt");
++            }
++#  endif
++        }
++    }
++# endif
++}
++
++static void dgram_reset_rcv_timeout(BIO *b)
++{
++# if defined(SO_RCVTIMEO)
++    bio_dgram_data *data = (bio_dgram_data *)b->ptr;
++
++    /* Is a timer active? */
++    if (data->next_timeout.tv_sec > 0 || data->next_timeout.tv_usec > 0) {
++#  ifdef OPENSSL_SYS_WINDOWS
++        int timeout = data->socket_timeout.tv_sec * 1000 +
++            data->socket_timeout.tv_usec / 1000;
++        if (setsockopt(b->num, SOL_SOCKET, SO_RCVTIMEO,
++                       (void *)&timeout, sizeof(timeout)) < 0) {
++            perror("setsockopt");
++        }
++#  else
++        if (setsockopt
++            (b->num, SOL_SOCKET, SO_RCVTIMEO, &(data->socket_timeout),
++             sizeof(struct timeval)) < 0) {
++            perror("setsockopt");
++        }
++#  endif
++    }
++# endif
++}
++
++static int dgram_read(BIO *b, char *out, int outl)
++{
++    int ret = 0;
++    bio_dgram_data *data = (bio_dgram_data *)b->ptr;
++    int flags = 0;
++
++    BIO_ADDR peer;
++    socklen_t len = sizeof(peer);
++
++    if (out != NULL) {
++        clear_socket_error();
++        memset(&peer, 0, sizeof(peer));
++        dgram_adjust_rcv_timeout(b);
++        if (data->peekmode)
++            flags = MSG_PEEK;
++        ret = recvfrom(b->num, out, outl, flags,
++                       BIO_ADDR_sockaddr_noconst(&peer), &len);
++
++        if (!data->connected && ret >= 0)
++            BIO_ctrl(b, BIO_CTRL_DGRAM_SET_PEER, 0, &peer);
++
++        BIO_clear_retry_flags(b);
++        if (ret < 0) {
++            if (BIO_dgram_should_retry(ret)) {
++                BIO_set_retry_read(b);
++                data->_errno = get_last_socket_error();
++            }
++        }
++
++        dgram_reset_rcv_timeout(b);
++    }
++    return (ret);
++}
++
++static int dgram_write(BIO *b, const char *in, int inl)
++{
++    int ret;
++    bio_dgram_data *data = (bio_dgram_data *)b->ptr;
++    clear_socket_error();
++
++    if (data->connected)
++        ret = writesocket(b->num, in, inl);
++    else {
++        int peerlen = BIO_ADDR_sockaddr_size(&data->peer);
++
++# if defined(NETWARE_CLIB) && defined(NETWARE_BSDSOCK)
++        ret = sendto(b->num, (char *)in, inl, 0,
++                     BIO_ADDR_sockaddr(&data->peer), peerlen);
++# else
++        ret = sendto(b->num, in, inl, 0,
++                     BIO_ADDR_sockaddr(&data->peer), peerlen);
++# endif
++    }
++
++    BIO_clear_retry_flags(b);
++    if (ret <= 0) {
++        if (BIO_dgram_should_retry(ret)) {
++            BIO_set_retry_write(b);
++            data->_errno = get_last_socket_error();
++        }
++    }
++    return (ret);
++}
++
++static long dgram_get_mtu_overhead(bio_dgram_data *data)
++{
++    long ret;
++
++    switch (BIO_ADDR_family(&data->peer)) {
++    case AF_INET:
++        /*
++         * Assume this is UDP - 20 bytes for IP, 8 bytes for UDP
++         */
++        ret = 28;
++        break;
++# ifdef AF_INET6
++    case AF_INET6:
++        {
++#  ifdef IN6_IS_ADDR_V4MAPPED
++            struct in6_addr tmp_addr;
++            if (BIO_ADDR_rawaddress(&data->peer, &tmp_addr, NULL)
++                && IN6_IS_ADDR_V4MAPPED(&tmp_addr))
++                /*
++                 * Assume this is UDP - 20 bytes for IP, 8 bytes for UDP
++                 */
++                ret = 28;
++            else
++#  endif
++            /*
++             * Assume this is UDP - 40 bytes for IP, 8 bytes for UDP
++             */
++            ret = 48;
++        }
++        break;
++# endif
++    default:
++        /* We don't know. Go with the historical default */
++        ret = 28;
++        break;
++    }
++    return ret;
++}
++
++static long dgram_ctrl(BIO *b, int cmd, long num, void *ptr)
++{
++    long ret = 1;
++    int *ip;
++    bio_dgram_data *data = NULL;
++    int sockopt_val = 0;
++    int d_errno;
++# if defined(OPENSSL_SYS_LINUX) && (defined(IP_MTU_DISCOVER) || defined(IP_MTU))
++    socklen_t sockopt_len;      /* assume that system supporting IP_MTU is
++                                 * modern enough to define socklen_t */
++    socklen_t addr_len;
++    BIO_ADDR addr;
++# endif
++
++    data = (bio_dgram_data *)b->ptr;
++
++    switch (cmd) {
++    case BIO_CTRL_RESET:
++        num = 0;
++        ret = 0;
++        break;
++    case BIO_CTRL_INFO:
++        ret = 0;
++        break;
++    case BIO_C_SET_FD:
++        dgram_clear(b);
++        b->num = *((int *)ptr);
++        b->shutdown = (int)num;
++        b->init = 1;
++        break;
++    case BIO_C_GET_FD:
++        if (b->init) {
++            ip = (int *)ptr;
++            if (ip != NULL)
++                *ip = b->num;
++            ret = b->num;
++        } else
++            ret = -1;
++        break;
++    case BIO_CTRL_GET_CLOSE:
++        ret = b->shutdown;
++        break;
++    case BIO_CTRL_SET_CLOSE:
++        b->shutdown = (int)num;
++        break;
++    case BIO_CTRL_PENDING:
++    case BIO_CTRL_WPENDING:
++        ret = 0;
++        break;
++    case BIO_CTRL_DUP:
++    case BIO_CTRL_FLUSH:
++        ret = 1;
++        break;
++    case BIO_CTRL_DGRAM_CONNECT:
++        BIO_ADDR_make(&data->peer, BIO_ADDR_sockaddr((BIO_ADDR *)ptr));
++        break;
++        /* (Linux)kernel sets DF bit on outgoing IP packets */
++    case BIO_CTRL_DGRAM_MTU_DISCOVER:
++# if defined(OPENSSL_SYS_LINUX) && defined(IP_MTU_DISCOVER) && defined(IP_PMTUDISC_DO)
++        addr_len = (socklen_t) sizeof(addr);
++        memset(&addr, 0, sizeof(addr));
++        if (getsockname(b->num, &addr.sa, &addr_len) < 0) {
++            ret = 0;
++            break;
++        }
++        switch (addr.sa.sa_family) {
++        case AF_INET:
++            sockopt_val = IP_PMTUDISC_DO;
++            if ((ret = setsockopt(b->num, IPPROTO_IP, IP_MTU_DISCOVER,
++                                  &sockopt_val, sizeof(sockopt_val))) < 0)
++                perror("setsockopt");
++            break;
++#  if OPENSSL_USE_IPV6 && defined(IPV6_MTU_DISCOVER) && defined(IPV6_PMTUDISC_DO)
++        case AF_INET6:
++            sockopt_val = IPV6_PMTUDISC_DO;
++            if ((ret = setsockopt(b->num, IPPROTO_IPV6, IPV6_MTU_DISCOVER,
++                                  &sockopt_val, sizeof(sockopt_val))) < 0)
++                perror("setsockopt");
++            break;
++#  endif
++        default:
++            ret = -1;
++            break;
++        }
++# else
++        ret = -1;
++# endif
++        break;
++    case BIO_CTRL_DGRAM_QUERY_MTU:
++# if defined(OPENSSL_SYS_LINUX) && defined(IP_MTU)
++        addr_len = (socklen_t) sizeof(addr);
++        memset(&addr, 0, sizeof(addr));
++        if (getsockname(b->num, &addr.sa, &addr_len) < 0) {
++            ret = 0;
++            break;
++        }
++        sockopt_len = sizeof(sockopt_val);
++        switch (addr.sa.sa_family) {
++        case AF_INET:
++            if ((ret =
++                 getsockopt(b->num, IPPROTO_IP, IP_MTU, (void *)&sockopt_val,
++                            &sockopt_len)) < 0 || sockopt_val < 0) {
++                ret = 0;
++            } else {
++                /*
++                 * we assume that the transport protocol is UDP and no IP
++                 * options are used.
++                 */
++                data->mtu = sockopt_val - 8 - 20;
++                ret = data->mtu;
++            }
++            break;
++#  if OPENSSL_USE_IPV6 && defined(IPV6_MTU)
++        case AF_INET6:
++            if ((ret =
++                 getsockopt(b->num, IPPROTO_IPV6, IPV6_MTU,
++                            (void *)&sockopt_val, &sockopt_len)) < 0
++                || sockopt_val < 0) {
++                ret = 0;
++            } else {
++                /*
++                 * we assume that the transport protocol is UDP and no IPV6
++                 * options are used.
++                 */
++                data->mtu = sockopt_val - 8 - 40;
++                ret = data->mtu;
++            }
++            break;
++#  endif
++        default:
++            ret = 0;
++            break;
++        }
++# else
++        ret = 0;
++# endif
++        break;
++    case BIO_CTRL_DGRAM_GET_FALLBACK_MTU:
++        ret = -dgram_get_mtu_overhead(data);
++        switch (BIO_ADDR_family(&data->peer)) {
++        case AF_INET:
++            ret += 576;
++            break;
++# if OPENSSL_USE_IPV6
++        case AF_INET6:
++            {
++#  ifdef IN6_IS_ADDR_V4MAPPED
++                struct in6_addr tmp_addr;
++                if (BIO_ADDR_rawaddress(&data->peer, &tmp_addr, NULL)
++                    && IN6_IS_ADDR_V4MAPPED(&tmp_addr))
++                    ret += 576;
++                else
++#  endif
++                    ret += 1280;
++            }
++            break;
++# endif
++        default:
++            ret += 576;
++            break;
++        }
++        break;
++    case BIO_CTRL_DGRAM_GET_MTU:
++        return data->mtu;
++    case BIO_CTRL_DGRAM_SET_MTU:
++        data->mtu = num;
++        ret = num;
++        break;
++    case BIO_CTRL_DGRAM_SET_CONNECTED:
++        if (ptr != NULL) {
++            data->connected = 1;
++            BIO_ADDR_make(&data->peer, BIO_ADDR_sockaddr((BIO_ADDR *)ptr));
++        } else {
++            data->connected = 0;
++            memset(&data->peer, 0, sizeof(data->peer));
++        }
++        break;
++    case BIO_CTRL_DGRAM_GET_PEER:
++        ret = BIO_ADDR_sockaddr_size(&data->peer);
++        /* FIXME: if num < ret, we will only return part of an address.
++           That should bee an error, no? */
++        if (num == 0 || num > ret)
++            num = ret;
++        memcpy(ptr, &data->peer, (ret = num));
++        break;
++    case BIO_CTRL_DGRAM_SET_PEER:
++        BIO_ADDR_make(&data->peer, BIO_ADDR_sockaddr((BIO_ADDR *)ptr));
++        break;
++    case BIO_CTRL_DGRAM_SET_NEXT_TIMEOUT:
++        memcpy(&(data->next_timeout), ptr, sizeof(struct timeval));
++        break;
++# if defined(SO_RCVTIMEO)
++    case BIO_CTRL_DGRAM_SET_RECV_TIMEOUT:
++#  ifdef OPENSSL_SYS_WINDOWS
++        {
++            struct timeval *tv = (struct timeval *)ptr;
++            int timeout = tv->tv_sec * 1000 + tv->tv_usec / 1000;
++            if (setsockopt(b->num, SOL_SOCKET, SO_RCVTIMEO,
++                           (void *)&timeout, sizeof(timeout)) < 0) {
++                perror("setsockopt");
++                ret = -1;
++            }
++        }
++#  else
++        if (setsockopt(b->num, SOL_SOCKET, SO_RCVTIMEO, ptr,
++                       sizeof(struct timeval)) < 0) {
++            perror("setsockopt");
++            ret = -1;
++        }
++#  endif
++        break;
++    case BIO_CTRL_DGRAM_GET_RECV_TIMEOUT:
++        {
++            union {
++                size_t s;
++                int i;
++            } sz = {
++                0
++            };
++#  ifdef OPENSSL_SYS_WINDOWS
++            int timeout;
++            struct timeval *tv = (struct timeval *)ptr;
++
++            sz.i = sizeof(timeout);
++            if (getsockopt(b->num, SOL_SOCKET, SO_RCVTIMEO,
++                           (void *)&timeout, &sz.i) < 0) {
++                perror("getsockopt");
++                ret = -1;
++            } else {
++                tv->tv_sec = timeout / 1000;
++                tv->tv_usec = (timeout % 1000) * 1000;
++                ret = sizeof(*tv);
++            }
++#  else
++            sz.i = sizeof(struct timeval);
++            if (getsockopt(b->num, SOL_SOCKET, SO_RCVTIMEO,
++                           ptr, (void *)&sz) < 0) {
++                perror("getsockopt");
++                ret = -1;
++            } else if (sizeof(sz.s) != sizeof(sz.i) && sz.i == 0) {
++                OPENSSL_assert(sz.s <= sizeof(struct timeval));
++                ret = (int)sz.s;
++            } else
++                ret = sz.i;
++#  endif
++        }
++        break;
++# endif
++# if defined(SO_SNDTIMEO)
++    case BIO_CTRL_DGRAM_SET_SEND_TIMEOUT:
++#  ifdef OPENSSL_SYS_WINDOWS
++        {
++            struct timeval *tv = (struct timeval *)ptr;
++            int timeout = tv->tv_sec * 1000 + tv->tv_usec / 1000;
++            if (setsockopt(b->num, SOL_SOCKET, SO_SNDTIMEO,
++                           (void *)&timeout, sizeof(timeout)) < 0) {
++                perror("setsockopt");
++                ret = -1;
++            }
++        }
++#  else
++        if (setsockopt(b->num, SOL_SOCKET, SO_SNDTIMEO, ptr,
++                       sizeof(struct timeval)) < 0) {
++            perror("setsockopt");
++            ret = -1;
++        }
++#  endif
++        break;
++    case BIO_CTRL_DGRAM_GET_SEND_TIMEOUT:
++        {
++            union {
++                size_t s;
++                int i;
++            } sz = {
++                0
++            };
++#  ifdef OPENSSL_SYS_WINDOWS
++            int timeout;
++            struct timeval *tv = (struct timeval *)ptr;
++
++            sz.i = sizeof(timeout);
++            if (getsockopt(b->num, SOL_SOCKET, SO_SNDTIMEO,
++                           (void *)&timeout, &sz.i) < 0) {
++                perror("getsockopt");
++                ret = -1;
++            } else {
++                tv->tv_sec = timeout / 1000;
++                tv->tv_usec = (timeout % 1000) * 1000;
++                ret = sizeof(*tv);
++            }
++#  else
++            sz.i = sizeof(struct timeval);
++            if (getsockopt(b->num, SOL_SOCKET, SO_SNDTIMEO,
++                           ptr, (void *)&sz) < 0) {
++                perror("getsockopt");
++                ret = -1;
++            } else if (sizeof(sz.s) != sizeof(sz.i) && sz.i == 0) {
++                OPENSSL_assert(sz.s <= sizeof(struct timeval));
++                ret = (int)sz.s;
++            } else
++                ret = sz.i;
++#  endif
++        }
++        break;
++# endif
++    case BIO_CTRL_DGRAM_GET_SEND_TIMER_EXP:
++        /* fall-through */
++    case BIO_CTRL_DGRAM_GET_RECV_TIMER_EXP:
++# ifdef OPENSSL_SYS_WINDOWS
++        d_errno = (data->_errno == WSAETIMEDOUT);
++# else
++        d_errno = (data->_errno == EAGAIN);
++# endif
++        if (d_errno) {
++            ret = 1;
++            data->_errno = 0;
++        } else
++            ret = 0;
++        break;
++# ifdef EMSGSIZE
++    case BIO_CTRL_DGRAM_MTU_EXCEEDED:
++        if (data->_errno == EMSGSIZE) {
++            ret = 1;
++            data->_errno = 0;
++        } else
++            ret = 0;
++        break;
++# endif
++    case BIO_CTRL_DGRAM_SET_DONT_FRAG:
++        sockopt_val = num ? 1 : 0;
++
++        switch (data->peer.sa.sa_family) {
++        case AF_INET:
++# if defined(IP_DONTFRAG)
++            if ((ret = setsockopt(b->num, IPPROTO_IP, IP_DONTFRAG,
++                                  &sockopt_val, sizeof(sockopt_val))) < 0) {
++                perror("setsockopt");
++                ret = -1;
++            }
++# elif defined(OPENSSL_SYS_LINUX) && defined(IP_MTU_DISCOVER) && defined (IP_PMTUDISC_PROBE)
++            if ((sockopt_val = num ? IP_PMTUDISC_PROBE : IP_PMTUDISC_DONT),
++                (ret = setsockopt(b->num, IPPROTO_IP, IP_MTU_DISCOVER,
++                                  &sockopt_val, sizeof(sockopt_val))) < 0) {
++                perror("setsockopt");
++                ret = -1;
++            }
++# elif defined(OPENSSL_SYS_WINDOWS) && defined(IP_DONTFRAGMENT)
++            if ((ret = setsockopt(b->num, IPPROTO_IP, IP_DONTFRAGMENT,
++                                  (const char *)&sockopt_val,
++                                  sizeof(sockopt_val))) < 0) {
++                perror("setsockopt");
++                ret = -1;
++            }
++# else
++            ret = -1;
++# endif
++            break;
++# if OPENSSL_USE_IPV6
++        case AF_INET6:
++#  if defined(IPV6_DONTFRAG)
++            if ((ret = setsockopt(b->num, IPPROTO_IPV6, IPV6_DONTFRAG,
++                                  (const void *)&sockopt_val,
++                                  sizeof(sockopt_val))) < 0) {
++                perror("setsockopt");
++                ret = -1;
++            }
++#  elif defined(OPENSSL_SYS_LINUX) && defined(IPV6_MTUDISCOVER)
++            if ((sockopt_val = num ? IP_PMTUDISC_PROBE : IP_PMTUDISC_DONT),
++                (ret = setsockopt(b->num, IPPROTO_IPV6, IPV6_MTU_DISCOVER,
++                                  &sockopt_val, sizeof(sockopt_val))) < 0) {
++                perror("setsockopt");
++                ret = -1;
++            }
++#  else
++            ret = -1;
++#  endif
++            break;
++# endif
++        default:
++            ret = -1;
++            break;
++        }
++        break;
++    case BIO_CTRL_DGRAM_GET_MTU_OVERHEAD:
++        ret = dgram_get_mtu_overhead(data);
++        break;
++    case BIO_CTRL_DGRAM_SET_PEEK_MODE:
++        data->peekmode = (unsigned int)num;
++        break;
++    default:
++        ret = 0;
++        break;
++    }
++    return (ret);
++}
++
++static int dgram_puts(BIO *bp, const char *str)
++{
++    int n, ret;
++
++    n = strlen(str);
++    ret = dgram_write(bp, str, n);
++    return (ret);
++}
++
++# ifndef OPENSSL_NO_SCTP
++const BIO_METHOD *BIO_s_datagram_sctp(void)
++{
++    return (&methods_dgramp_sctp);
++}
++
++BIO *BIO_new_dgram_sctp(int fd, int close_flag)
++{
++    BIO *bio;
++    int ret, optval = 20000;
++    int auth_data = 0, auth_forward = 0;
++    unsigned char *p;
++    struct sctp_authchunk auth;
++    struct sctp_authchunks *authchunks;
++    socklen_t sockopt_len;
++#  ifdef SCTP_AUTHENTICATION_EVENT
++#   ifdef SCTP_EVENT
++    struct sctp_event event;
++#   else
++    struct sctp_event_subscribe event;
++#   endif
++#  endif
++
++    bio = BIO_new(BIO_s_datagram_sctp());
++    if (bio == NULL)
++        return (NULL);
++    BIO_set_fd(bio, fd, close_flag);
++
++    /* Activate SCTP-AUTH for DATA and FORWARD-TSN chunks */
++    auth.sauth_chunk = OPENSSL_SCTP_DATA_CHUNK_TYPE;
++    ret =
++        setsockopt(fd, IPPROTO_SCTP, SCTP_AUTH_CHUNK, &auth,
++                   sizeof(struct sctp_authchunk));
++    if (ret < 0) {
++        BIO_vfree(bio);
++        return (NULL);
++    }
++    auth.sauth_chunk = OPENSSL_SCTP_FORWARD_CUM_TSN_CHUNK_TYPE;
++    ret =
++        setsockopt(fd, IPPROTO_SCTP, SCTP_AUTH_CHUNK, &auth,
++                   sizeof(struct sctp_authchunk));
++    if (ret < 0) {
++        BIO_vfree(bio);
++        return (NULL);
++    }
++
++    /*
++     * Test if activation was successful. When using accept(), SCTP-AUTH has
++     * to be activated for the listening socket already, otherwise the
++     * connected socket won't use it.
++     */
++    sockopt_len = (socklen_t) (sizeof(sctp_assoc_t) + 256 * sizeof(uint8_t));
++    authchunks = OPENSSL_zalloc(sockopt_len);
++    if (authchunks == NULL) {
++        BIO_vfree(bio);
++        return (NULL);
++    }
++    ret = getsockopt(fd, IPPROTO_SCTP, SCTP_LOCAL_AUTH_CHUNKS, authchunks,
++                   &sockopt_len);
++    if (ret < 0) {
++        OPENSSL_free(authchunks);
++        BIO_vfree(bio);
++        return (NULL);
++    }
++
++    for (p = (unsigned char *)authchunks->gauth_chunks;
++         p < (unsigned char *)authchunks + sockopt_len;
++         p += sizeof(uint8_t)) {
++        if (*p == OPENSSL_SCTP_DATA_CHUNK_TYPE)
++            auth_data = 1;
++        if (*p == OPENSSL_SCTP_FORWARD_CUM_TSN_CHUNK_TYPE)
++            auth_forward = 1;
++    }
++
++    OPENSSL_free(authchunks);
++
++    OPENSSL_assert(auth_data);
++    OPENSSL_assert(auth_forward);
++
++#  ifdef SCTP_AUTHENTICATION_EVENT
++#   ifdef SCTP_EVENT
++    memset(&event, 0, sizeof(event));
++    event.se_assoc_id = 0;
++    event.se_type = SCTP_AUTHENTICATION_EVENT;
++    event.se_on = 1;
++    ret =
++        setsockopt(fd, IPPROTO_SCTP, SCTP_EVENT, &event,
++                   sizeof(struct sctp_event));
++    if (ret < 0) {
++        BIO_vfree(bio);
++        return (NULL);
++    }
++#   else
++    sockopt_len = (socklen_t) sizeof(struct sctp_event_subscribe);
++    ret = getsockopt(fd, IPPROTO_SCTP, SCTP_EVENTS, &event, &sockopt_len);
++    if (ret < 0) {
++        BIO_vfree(bio);
++        return (NULL);
++    }
++
++    event.sctp_authentication_event = 1;
++
++    ret =
++        setsockopt(fd, IPPROTO_SCTP, SCTP_EVENTS, &event,
++                   sizeof(struct sctp_event_subscribe));
++    if (ret < 0) {
++        BIO_vfree(bio);
++        return (NULL);
++    }
++#   endif
++#  endif
++
++    /*
++     * Disable partial delivery by setting the min size larger than the max
++     * record size of 2^14 + 2048 + 13
++     */
++    ret =
++        setsockopt(fd, IPPROTO_SCTP, SCTP_PARTIAL_DELIVERY_POINT, &optval,
++                   sizeof(optval));
++    if (ret < 0) {
++        BIO_vfree(bio);
++        return (NULL);
++    }
++
++    return (bio);
++}
++
++int BIO_dgram_is_sctp(BIO *bio)
++{
++    return (BIO_method_type(bio) == BIO_TYPE_DGRAM_SCTP);
++}
++
++static int dgram_sctp_new(BIO *bi)
++{
++    bio_dgram_sctp_data *data = NULL;
++
++    bi->init = 0;
++    bi->num = 0;
++    data = OPENSSL_zalloc(sizeof(*data));
++    if (data == NULL)
++        return 0;
++#  ifdef SCTP_PR_SCTP_NONE
++    data->prinfo.pr_policy = SCTP_PR_SCTP_NONE;
++#  endif
++    bi->ptr = data;
++
++    bi->flags = 0;
++    return (1);
++}
++
++static int dgram_sctp_free(BIO *a)
++{
++    bio_dgram_sctp_data *data;
++
++    if (a == NULL)
++        return (0);
++    if (!dgram_clear(a))
++        return 0;
++
++    data = (bio_dgram_sctp_data *) a->ptr;
++    if (data != NULL) {
++        OPENSSL_free(data->saved_message.data);
++        OPENSSL_free(data);
++    }
++
++    return (1);
++}
++
++#  ifdef SCTP_AUTHENTICATION_EVENT
++void dgram_sctp_handle_auth_free_key_event(BIO *b,
++                                           union sctp_notification *snp)
++{
++    int ret;
++    struct sctp_authkey_event *authkeyevent = &snp->sn_auth_event;
++
++    if (authkeyevent->auth_indication == SCTP_AUTH_FREE_KEY) {
++        struct sctp_authkeyid authkeyid;
++
++        /* delete key */
++        authkeyid.scact_keynumber = authkeyevent->auth_keynumber;
++        ret = setsockopt(b->num, IPPROTO_SCTP, SCTP_AUTH_DELETE_KEY,
++                         &authkeyid, sizeof(struct sctp_authkeyid));
++    }
++}
++#  endif
++
++static int dgram_sctp_read(BIO *b, char *out, int outl)
++{
++    int ret = 0, n = 0, i, optval;
++    socklen_t optlen;
++    bio_dgram_sctp_data *data = (bio_dgram_sctp_data *) b->ptr;
++    union sctp_notification *snp;
++    struct msghdr msg;
++    struct iovec iov;
++    struct cmsghdr *cmsg;
++    char cmsgbuf[512];
++
++    if (out != NULL) {
++        clear_socket_error();
++
++        do {
++            memset(&data->rcvinfo, 0, sizeof(data->rcvinfo));
++            iov.iov_base = out;
++            iov.iov_len = outl;
++            msg.msg_name = NULL;
++            msg.msg_namelen = 0;
++            msg.msg_iov = &iov;
++            msg.msg_iovlen = 1;
++            msg.msg_control = cmsgbuf;
++            msg.msg_controllen = 512;
++            msg.msg_flags = 0;
++            n = recvmsg(b->num, &msg, 0);
++
++            if (n <= 0) {
++                if (n < 0)
++                    ret = n;
++                break;
++            }
++
++            if (msg.msg_controllen > 0) {
++                for (cmsg = CMSG_FIRSTHDR(&msg); cmsg;
++                     cmsg = CMSG_NXTHDR(&msg, cmsg)) {
++                    if (cmsg->cmsg_level != IPPROTO_SCTP)
++                        continue;
++#  ifdef SCTP_RCVINFO
++                    if (cmsg->cmsg_type == SCTP_RCVINFO) {
++                        struct sctp_rcvinfo *rcvinfo;
++
++                        rcvinfo = (struct sctp_rcvinfo *)CMSG_DATA(cmsg);
++                        data->rcvinfo.rcv_sid = rcvinfo->rcv_sid;
++                        data->rcvinfo.rcv_ssn = rcvinfo->rcv_ssn;
++                        data->rcvinfo.rcv_flags = rcvinfo->rcv_flags;
++                        data->rcvinfo.rcv_ppid = rcvinfo->rcv_ppid;
++                        data->rcvinfo.rcv_tsn = rcvinfo->rcv_tsn;
++                        data->rcvinfo.rcv_cumtsn = rcvinfo->rcv_cumtsn;
++                        data->rcvinfo.rcv_context = rcvinfo->rcv_context;
++                    }
++#  endif
++#  ifdef SCTP_SNDRCV
++                    if (cmsg->cmsg_type == SCTP_SNDRCV) {
++                        struct sctp_sndrcvinfo *sndrcvinfo;
++
++                        sndrcvinfo =
++                            (struct sctp_sndrcvinfo *)CMSG_DATA(cmsg);
++                        data->rcvinfo.rcv_sid = sndrcvinfo->sinfo_stream;
++                        data->rcvinfo.rcv_ssn = sndrcvinfo->sinfo_ssn;
++                        data->rcvinfo.rcv_flags = sndrcvinfo->sinfo_flags;
++                        data->rcvinfo.rcv_ppid = sndrcvinfo->sinfo_ppid;
++                        data->rcvinfo.rcv_tsn = sndrcvinfo->sinfo_tsn;
++                        data->rcvinfo.rcv_cumtsn = sndrcvinfo->sinfo_cumtsn;
++                        data->rcvinfo.rcv_context = sndrcvinfo->sinfo_context;
++                    }
++#  endif
++                }
++            }
++
++            if (msg.msg_flags & MSG_NOTIFICATION) {
++                snp = (union sctp_notification *)out;
++                if (snp->sn_header.sn_type == SCTP_SENDER_DRY_EVENT) {
++#  ifdef SCTP_EVENT
++                    struct sctp_event event;
++#  else
++                    struct sctp_event_subscribe event;
++                    socklen_t eventsize;
++#  endif
++                    /*
++                     * If a message has been delayed until the socket is dry,
++                     * it can be sent now.
++                     */
++                    if (data->saved_message.length > 0) {
++                        i = dgram_sctp_write(data->saved_message.bio,
++                                         data->saved_message.data,
++                                         data->saved_message.length);
++                        if (i < 0) {
++                            ret = i;
++                            break;
++                        }
++                        OPENSSL_free(data->saved_message.data);
++                        data->saved_message.data = NULL;
++                        data->saved_message.length = 0;
++                    }
++
++                    /* disable sender dry event */
++#  ifdef SCTP_EVENT
++                    memset(&event, 0, sizeof(event));
++                    event.se_assoc_id = 0;
++                    event.se_type = SCTP_SENDER_DRY_EVENT;
++                    event.se_on = 0;
++                    i = setsockopt(b->num, IPPROTO_SCTP, SCTP_EVENT, &event,
++                                   sizeof(struct sctp_event));
++                    if (i < 0) {
++                        ret = i;
++                        break;
++                    }
++#  else
++                    eventsize = sizeof(struct sctp_event_subscribe);
++                    i = getsockopt(b->num, IPPROTO_SCTP, SCTP_EVENTS, &event,
++                                   &eventsize);
++                    if (i < 0) {
++                        ret = i;
++                        break;
++                    }
++
++                    event.sctp_sender_dry_event = 0;
++
++                    i = setsockopt(b->num, IPPROTO_SCTP, SCTP_EVENTS, &event,
++                                   sizeof(struct sctp_event_subscribe));
++                    if (i < 0) {
++                        ret = i;
++                        break;
++                    }
++#  endif
++                }
++#  ifdef SCTP_AUTHENTICATION_EVENT
++                if (snp->sn_header.sn_type == SCTP_AUTHENTICATION_EVENT)
++                    dgram_sctp_handle_auth_free_key_event(b, snp);
++#  endif
++
++                if (data->handle_notifications != NULL)
++                    data->handle_notifications(b, data->notification_context,
++                                               (void *)out);
++
++                memset(out, 0, outl);
++            } else
++                ret += n;
++        }
++        while ((msg.msg_flags & MSG_NOTIFICATION) && (msg.msg_flags & MSG_EOR)
++               && (ret < outl));
++
++        if (ret > 0 && !(msg.msg_flags & MSG_EOR)) {
++            /* Partial message read, this should never happen! */
++
++            /*
++             * The buffer was too small, this means the peer sent a message
++             * that was larger than allowed.
++             */
++            if (ret == outl)
++                return -1;
++
++            /*
++             * Test if socket buffer can handle max record size (2^14 + 2048
++             * + 13)
++             */
++            optlen = (socklen_t) sizeof(int);
++            ret = getsockopt(b->num, SOL_SOCKET, SO_RCVBUF, &optval, &optlen);
++            if (ret >= 0)
++                OPENSSL_assert(optval >= 18445);
++
++            /*
++             * Test if SCTP doesn't partially deliver below max record size
++             * (2^14 + 2048 + 13)
++             */
++            optlen = (socklen_t) sizeof(int);
++            ret =
++                getsockopt(b->num, IPPROTO_SCTP, SCTP_PARTIAL_DELIVERY_POINT,
++                           &optval, &optlen);
++            if (ret >= 0)
++                OPENSSL_assert(optval >= 18445);
++
++            /*
++             * Partially delivered notification??? Probably a bug....
++             */
++            OPENSSL_assert(!(msg.msg_flags & MSG_NOTIFICATION));
++
++            /*
++             * Everything seems ok till now, so it's most likely a message
++             * dropped by PR-SCTP.
++             */
++            memset(out, 0, outl);
++            BIO_set_retry_read(b);
++            return -1;
++        }
++
++        BIO_clear_retry_flags(b);
++        if (ret < 0) {
++            if (BIO_dgram_should_retry(ret)) {
++                BIO_set_retry_read(b);
++                data->_errno = get_last_socket_error();
++            }
++        }
++
++        /* Test if peer uses SCTP-AUTH before continuing */
++        if (!data->peer_auth_tested) {
++            int ii, auth_data = 0, auth_forward = 0;
++            unsigned char *p;
++            struct sctp_authchunks *authchunks;
++
++            optlen =
++                (socklen_t) (sizeof(sctp_assoc_t) + 256 * sizeof(uint8_t));
++            authchunks = OPENSSL_malloc(optlen);
++            if (authchunks == NULL) {
++                BIOerr(BIO_F_DGRAM_SCTP_READ, ERR_R_MALLOC_FAILURE);
++                return -1;
++            }
++            memset(authchunks, 0, optlen);
++            ii = getsockopt(b->num, IPPROTO_SCTP, SCTP_PEER_AUTH_CHUNKS,
++                            authchunks, &optlen);
++
++            if (ii >= 0)
++                for (p = (unsigned char *)authchunks->gauth_chunks;
++                     p < (unsigned char *)authchunks + optlen;
++                     p += sizeof(uint8_t)) {
++                    if (*p == OPENSSL_SCTP_DATA_CHUNK_TYPE)
++                        auth_data = 1;
++                    if (*p == OPENSSL_SCTP_FORWARD_CUM_TSN_CHUNK_TYPE)
++                        auth_forward = 1;
++                }
++
++            OPENSSL_free(authchunks);
++
++            if (!auth_data || !auth_forward) {
++                BIOerr(BIO_F_DGRAM_SCTP_READ, BIO_R_CONNECT_ERROR);
++                return -1;
++            }
++
++            data->peer_auth_tested = 1;
++        }
++    }
++    return (ret);
++}
++
++/*
++ * dgram_sctp_write - send message on SCTP socket
++ * @b: BIO to write to
++ * @in: data to send
++ * @inl: amount of bytes in @in to send
++ *
++ * Returns -1 on error or the sent amount of bytes on success
++ */
++static int dgram_sctp_write(BIO *b, const char *in, int inl)
++{
++    int ret;
++    bio_dgram_sctp_data *data = (bio_dgram_sctp_data *) b->ptr;
++    struct bio_dgram_sctp_sndinfo *sinfo = &(data->sndinfo);
++    struct bio_dgram_sctp_prinfo *pinfo = &(data->prinfo);
++    struct bio_dgram_sctp_sndinfo handshake_sinfo;
++    struct iovec iov[1];
++    struct msghdr msg;
++    struct cmsghdr *cmsg;
++#  if defined(SCTP_SNDINFO) && defined(SCTP_PRINFO)
++    char cmsgbuf[CMSG_SPACE(sizeof(struct sctp_sndinfo)) +
++                 CMSG_SPACE(sizeof(struct sctp_prinfo))];
++    struct sctp_sndinfo *sndinfo;
++    struct sctp_prinfo *prinfo;
++#  else
++    char cmsgbuf[CMSG_SPACE(sizeof(struct sctp_sndrcvinfo))];
++    struct sctp_sndrcvinfo *sndrcvinfo;
++#  endif
++
++    clear_socket_error();
++
++    /*
++     * If we're send anything else than application data, disable all user
++     * parameters and flags.
++     */
++    if (in[0] != 23) {
++        memset(&handshake_sinfo, 0, sizeof(handshake_sinfo));
++#  ifdef SCTP_SACK_IMMEDIATELY
++        handshake_sinfo.snd_flags = SCTP_SACK_IMMEDIATELY;
++#  endif
++        sinfo = &handshake_sinfo;
++    }
++
++    /*
++     * If we have to send a shutdown alert message and the socket is not dry
++     * yet, we have to save it and send it as soon as the socket gets dry.
++     */
++    if (data->save_shutdown) {
++        ret = BIO_dgram_sctp_wait_for_dry(b);
++        if (ret < 0) {
++            return -1;
++        }
++        if (ret == 0) {
++            char *tmp;
++            data->saved_message.bio = b;
++            if ((tmp = OPENSSL_malloc(inl)) == NULL) {
++                BIOerr(BIO_F_DGRAM_SCTP_WRITE, ERR_R_MALLOC_FAILURE);
++                return -1;
++            }
++            OPENSSL_free(data->saved_message.data);
++            data->saved_message.data = tmp;
++            memcpy(data->saved_message.data, in, inl);
++            data->saved_message.length = inl;
++            return inl;
++        }
++    }
++
++    iov[0].iov_base = (char *)in;
++    iov[0].iov_len = inl;
++    msg.msg_name = NULL;
++    msg.msg_namelen = 0;
++    msg.msg_iov = iov;
++    msg.msg_iovlen = 1;
++    msg.msg_control = (caddr_t) cmsgbuf;
++    msg.msg_controllen = 0;
++    msg.msg_flags = 0;
++#  if defined(SCTP_SNDINFO) && defined(SCTP_PRINFO)
++    cmsg = (struct cmsghdr *)cmsgbuf;
++    cmsg->cmsg_level = IPPROTO_SCTP;
++    cmsg->cmsg_type = SCTP_SNDINFO;
++    cmsg->cmsg_len = CMSG_LEN(sizeof(struct sctp_sndinfo));
++    sndinfo = (struct sctp_sndinfo *)CMSG_DATA(cmsg);
++    memset(sndinfo, 0, sizeof(*sndinfo));
++    sndinfo->snd_sid = sinfo->snd_sid;
++    sndinfo->snd_flags = sinfo->snd_flags;
++    sndinfo->snd_ppid = sinfo->snd_ppid;
++    sndinfo->snd_context = sinfo->snd_context;
++    msg.msg_controllen += CMSG_SPACE(sizeof(struct sctp_sndinfo));
++
++    cmsg =
++        (struct cmsghdr *)&cmsgbuf[CMSG_SPACE(sizeof(struct sctp_sndinfo))];
++    cmsg->cmsg_level = IPPROTO_SCTP;
++    cmsg->cmsg_type = SCTP_PRINFO;
++    cmsg->cmsg_len = CMSG_LEN(sizeof(struct sctp_prinfo));
++    prinfo = (struct sctp_prinfo *)CMSG_DATA(cmsg);
++    memset(prinfo, 0, sizeof(*prinfo));
++    prinfo->pr_policy = pinfo->pr_policy;
++    prinfo->pr_value = pinfo->pr_value;
++    msg.msg_controllen += CMSG_SPACE(sizeof(struct sctp_prinfo));
++#  else
++    cmsg = (struct cmsghdr *)cmsgbuf;
++    cmsg->cmsg_level = IPPROTO_SCTP;
++    cmsg->cmsg_type = SCTP_SNDRCV;
++    cmsg->cmsg_len = CMSG_LEN(sizeof(struct sctp_sndrcvinfo));
++    sndrcvinfo = (struct sctp_sndrcvinfo *)CMSG_DATA(cmsg);
++    memset(sndrcvinfo, 0, sizeof(*sndrcvinfo));
++    sndrcvinfo->sinfo_stream = sinfo->snd_sid;
++    sndrcvinfo->sinfo_flags = sinfo->snd_flags;
++#   ifdef __FreeBSD__
++    sndrcvinfo->sinfo_flags |= pinfo->pr_policy;
++#   endif
++    sndrcvinfo->sinfo_ppid = sinfo->snd_ppid;
++    sndrcvinfo->sinfo_context = sinfo->snd_context;
++    sndrcvinfo->sinfo_timetolive = pinfo->pr_value;
++    msg.msg_controllen += CMSG_SPACE(sizeof(struct sctp_sndrcvinfo));
++#  endif
++
++    ret = sendmsg(b->num, &msg, 0);
++
++    BIO_clear_retry_flags(b);
++    if (ret <= 0) {
++        if (BIO_dgram_should_retry(ret)) {
++            BIO_set_retry_write(b);
++            data->_errno = get_last_socket_error();
++        }
++    }
++    return (ret);
++}
++
++static long dgram_sctp_ctrl(BIO *b, int cmd, long num, void *ptr)
++{
++    long ret = 1;
++    bio_dgram_sctp_data *data = NULL;
++    socklen_t sockopt_len = 0;
++    struct sctp_authkeyid authkeyid;
++    struct sctp_authkey *authkey = NULL;
++
++    data = (bio_dgram_sctp_data *) b->ptr;
++
++    switch (cmd) {
++    case BIO_CTRL_DGRAM_QUERY_MTU:
++        /*
++         * Set to maximum (2^14) and ignore user input to enable transport
++         * protocol fragmentation. Returns always 2^14.
++         */
++        data->mtu = 16384;
++        ret = data->mtu;
++        break;
++    case BIO_CTRL_DGRAM_SET_MTU:
++        /*
++         * Set to maximum (2^14) and ignore input to enable transport
++         * protocol fragmentation. Returns always 2^14.
++         */
++        data->mtu = 16384;
++        ret = data->mtu;
++        break;
++    case BIO_CTRL_DGRAM_SET_CONNECTED:
++    case BIO_CTRL_DGRAM_CONNECT:
++        /* Returns always -1. */
++        ret = -1;
++        break;
++    case BIO_CTRL_DGRAM_SET_NEXT_TIMEOUT:
++        /*
++         * SCTP doesn't need the DTLS timer Returns always 1.
++         */
++        break;
++    case BIO_CTRL_DGRAM_GET_MTU_OVERHEAD:
++        /*
++         * We allow transport protocol fragmentation so this is irrelevant
++         */
++        ret = 0;
++        break;
++    case BIO_CTRL_DGRAM_SCTP_SET_IN_HANDSHAKE:
++        if (num > 0)
++            data->in_handshake = 1;
++        else
++            data->in_handshake = 0;
++
++        ret =
++            setsockopt(b->num, IPPROTO_SCTP, SCTP_NODELAY,
++                       &data->in_handshake, sizeof(int));
++        break;
++    case BIO_CTRL_DGRAM_SCTP_ADD_AUTH_KEY:
++        /*
++         * New shared key for SCTP AUTH. Returns 0 on success, -1 otherwise.
++         */
++
++        /* Get active key */
++        sockopt_len = sizeof(struct sctp_authkeyid);
++        ret =
++            getsockopt(b->num, IPPROTO_SCTP, SCTP_AUTH_ACTIVE_KEY, &authkeyid,
++                       &sockopt_len);
++        if (ret < 0)
++            break;
++
++        /* Add new key */
++        sockopt_len = sizeof(struct sctp_authkey) + 64 * sizeof(uint8_t);
++        authkey = OPENSSL_malloc(sockopt_len);
++        if (authkey == NULL) {
++            ret = -1;
++            break;
++        }
++        memset(authkey, 0, sockopt_len);
++        authkey->sca_keynumber = authkeyid.scact_keynumber + 1;
++#  ifndef __FreeBSD__
++        /*
++         * This field is missing in FreeBSD 8.2 and earlier, and FreeBSD 8.3
++         * and higher work without it.
++         */
++        authkey->sca_keylength = 64;
++#  endif
++        memcpy(&authkey->sca_key[0], ptr, 64 * sizeof(uint8_t));
++
++        ret =
++            setsockopt(b->num, IPPROTO_SCTP, SCTP_AUTH_KEY, authkey,
++                       sockopt_len);
++        OPENSSL_free(authkey);
++        authkey = NULL;
++        if (ret < 0)
++            break;
++
++        /* Reset active key */
++        ret = setsockopt(b->num, IPPROTO_SCTP, SCTP_AUTH_ACTIVE_KEY,
++                         &authkeyid, sizeof(struct sctp_authkeyid));
++        if (ret < 0)
++            break;
++
++        break;
++    case BIO_CTRL_DGRAM_SCTP_NEXT_AUTH_KEY:
++        /* Returns 0 on success, -1 otherwise. */
++
++        /* Get active key */
++        sockopt_len = sizeof(struct sctp_authkeyid);
++        ret =
++            getsockopt(b->num, IPPROTO_SCTP, SCTP_AUTH_ACTIVE_KEY, &authkeyid,
++                       &sockopt_len);
++        if (ret < 0)
++            break;
++
++        /* Set active key */
++        authkeyid.scact_keynumber = authkeyid.scact_keynumber + 1;
++        ret = setsockopt(b->num, IPPROTO_SCTP, SCTP_AUTH_ACTIVE_KEY,
++                         &authkeyid, sizeof(struct sctp_authkeyid));
++        if (ret < 0)
++            break;
++
++        /*
++         * CCS has been sent, so remember that and fall through to check if
++         * we need to deactivate an old key
++         */
++        data->ccs_sent = 1;
++
++    case BIO_CTRL_DGRAM_SCTP_AUTH_CCS_RCVD:
++        /* Returns 0 on success, -1 otherwise. */
++
++        /*
++         * Has this command really been called or is this just a
++         * fall-through?
++         */
++        if (cmd == BIO_CTRL_DGRAM_SCTP_AUTH_CCS_RCVD)
++            data->ccs_rcvd = 1;
++
++        /*
++         * CSS has been both, received and sent, so deactivate an old key
++         */
++        if (data->ccs_rcvd == 1 && data->ccs_sent == 1) {
++            /* Get active key */
++            sockopt_len = sizeof(struct sctp_authkeyid);
++            ret =
++                getsockopt(b->num, IPPROTO_SCTP, SCTP_AUTH_ACTIVE_KEY,
++                           &authkeyid, &sockopt_len);
++            if (ret < 0)
++                break;
++
++            /*
++             * Deactivate key or delete second last key if
++             * SCTP_AUTHENTICATION_EVENT is not available.
++             */
++            authkeyid.scact_keynumber = authkeyid.scact_keynumber - 1;
++#  ifdef SCTP_AUTH_DEACTIVATE_KEY
++            sockopt_len = sizeof(struct sctp_authkeyid);
++            ret = setsockopt(b->num, IPPROTO_SCTP, SCTP_AUTH_DEACTIVATE_KEY,
++                             &authkeyid, sockopt_len);
++            if (ret < 0)
++                break;
++#  endif
++#  ifndef SCTP_AUTHENTICATION_EVENT
++            if (authkeyid.scact_keynumber > 0) {
++                authkeyid.scact_keynumber = authkeyid.scact_keynumber - 1;
++                ret = setsockopt(b->num, IPPROTO_SCTP, SCTP_AUTH_DELETE_KEY,
++                                 &authkeyid, sizeof(struct sctp_authkeyid));
++                if (ret < 0)
++                    break;
++            }
++#  endif
++
++            data->ccs_rcvd = 0;
++            data->ccs_sent = 0;
++        }
++        break;
++    case BIO_CTRL_DGRAM_SCTP_GET_SNDINFO:
++        /* Returns the size of the copied struct. */
++        if (num > (long)sizeof(struct bio_dgram_sctp_sndinfo))
++            num = sizeof(struct bio_dgram_sctp_sndinfo);
++
++        memcpy(ptr, &(data->sndinfo), num);
++        ret = num;
++        break;
++    case BIO_CTRL_DGRAM_SCTP_SET_SNDINFO:
++        /* Returns the size of the copied struct. */
++        if (num > (long)sizeof(struct bio_dgram_sctp_sndinfo))
++            num = sizeof(struct bio_dgram_sctp_sndinfo);
++
++        memcpy(&(data->sndinfo), ptr, num);
++        break;
++    case BIO_CTRL_DGRAM_SCTP_GET_RCVINFO:
++        /* Returns the size of the copied struct. */
++        if (num > (long)sizeof(struct bio_dgram_sctp_rcvinfo))
++            num = sizeof(struct bio_dgram_sctp_rcvinfo);
++
++        memcpy(ptr, &data->rcvinfo, num);
++
++        ret = num;
++        break;
++    case BIO_CTRL_DGRAM_SCTP_SET_RCVINFO:
++        /* Returns the size of the copied struct. */
++        if (num > (long)sizeof(struct bio_dgram_sctp_rcvinfo))
++            num = sizeof(struct bio_dgram_sctp_rcvinfo);
++
++        memcpy(&(data->rcvinfo), ptr, num);
++        break;
++    case BIO_CTRL_DGRAM_SCTP_GET_PRINFO:
++        /* Returns the size of the copied struct. */
++        if (num > (long)sizeof(struct bio_dgram_sctp_prinfo))
++            num = sizeof(struct bio_dgram_sctp_prinfo);
++
++        memcpy(ptr, &(data->prinfo), num);
++        ret = num;
++        break;
++    case BIO_CTRL_DGRAM_SCTP_SET_PRINFO:
++        /* Returns the size of the copied struct. */
++        if (num > (long)sizeof(struct bio_dgram_sctp_prinfo))
++            num = sizeof(struct bio_dgram_sctp_prinfo);
++
++        memcpy(&(data->prinfo), ptr, num);
++        break;
++    case BIO_CTRL_DGRAM_SCTP_SAVE_SHUTDOWN:
++        /* Returns always 1. */
++        if (num > 0)
++            data->save_shutdown = 1;
++        else
++            data->save_shutdown = 0;
++        break;
++
++    default:
++        /*
++         * Pass to default ctrl function to process SCTP unspecific commands
++         */
++        ret = dgram_ctrl(b, cmd, num, ptr);
++        break;
++    }
++    return (ret);
++}
++
++int BIO_dgram_sctp_notification_cb(BIO *b,
++                                   void (*handle_notifications) (BIO *bio,
++                                                                 void
++                                                                 *context,
++                                                                 void *buf),
++                                   void *context)
++{
++    bio_dgram_sctp_data *data = (bio_dgram_sctp_data *) b->ptr;
++
++    if (handle_notifications != NULL) {
++        data->handle_notifications = handle_notifications;
++        data->notification_context = context;
++    } else
++        return -1;
++
++    return 0;
++}
++
++/*
++ * BIO_dgram_sctp_wait_for_dry - Wait for SCTP SENDER_DRY event
++ * @b: The BIO to check for the dry event
++ *
++ * Wait until the peer confirms all packets have been received, and so that
++ * our kernel doesn't have anything to send anymore.  This is only received by
++ * the peer's kernel, not the application.
++ *
++ * Returns:
++ * -1 on error
++ *  0 when not dry yet
++ *  1 when dry
++ */
++int BIO_dgram_sctp_wait_for_dry(BIO *b)
++{
++    int is_dry = 0;
++    int sockflags = 0;
++    int n, ret;
++    union sctp_notification snp;
++    struct msghdr msg;
++    struct iovec iov;
++#  ifdef SCTP_EVENT
++    struct sctp_event event;
++#  else
++    struct sctp_event_subscribe event;
++    socklen_t eventsize;
++#  endif
++    bio_dgram_sctp_data *data = (bio_dgram_sctp_data *) b->ptr;
++
++    /* set sender dry event */
++#  ifdef SCTP_EVENT
++    memset(&event, 0, sizeof(event));
++    event.se_assoc_id = 0;
++    event.se_type = SCTP_SENDER_DRY_EVENT;
++    event.se_on = 1;
++    ret =
++        setsockopt(b->num, IPPROTO_SCTP, SCTP_EVENT, &event,
++                   sizeof(struct sctp_event));
++#  else
++    eventsize = sizeof(struct sctp_event_subscribe);
++    ret = getsockopt(b->num, IPPROTO_SCTP, SCTP_EVENTS, &event, &eventsize);
++    if (ret < 0)
++        return -1;
++
++    event.sctp_sender_dry_event = 1;
++
++    ret =
++        setsockopt(b->num, IPPROTO_SCTP, SCTP_EVENTS, &event,
++                   sizeof(struct sctp_event_subscribe));
++#  endif
++    if (ret < 0)
++        return -1;
++
++    /* peek for notification */
++    memset(&snp, 0, sizeof(snp));
++    iov.iov_base = (char *)&snp;
++    iov.iov_len = sizeof(union sctp_notification);
++    msg.msg_name = NULL;
++    msg.msg_namelen = 0;
++    msg.msg_iov = &iov;
++    msg.msg_iovlen = 1;
++    msg.msg_control = NULL;
++    msg.msg_controllen = 0;
++    msg.msg_flags = 0;
++
++    n = recvmsg(b->num, &msg, MSG_PEEK);
++    if (n <= 0) {
++        if ((n < 0) && (get_last_socket_error() != EAGAIN)
++            && (get_last_socket_error() != EWOULDBLOCK))
++            return -1;
++        else
++            return 0;
++    }
++
++    /* if we find a notification, process it and try again if necessary */
++    while (msg.msg_flags & MSG_NOTIFICATION) {
++        memset(&snp, 0, sizeof(snp));
++        iov.iov_base = (char *)&snp;
++        iov.iov_len = sizeof(union sctp_notification);
++        msg.msg_name = NULL;
++        msg.msg_namelen = 0;
++        msg.msg_iov = &iov;
++        msg.msg_iovlen = 1;
++        msg.msg_control = NULL;
++        msg.msg_controllen = 0;
++        msg.msg_flags = 0;
++
++        n = recvmsg(b->num, &msg, 0);
++        if (n <= 0) {
++            if ((n < 0) && (get_last_socket_error() != EAGAIN)
++                && (get_last_socket_error() != EWOULDBLOCK))
++                return -1;
++            else
++                return is_dry;
++        }
++
++        if (snp.sn_header.sn_type == SCTP_SENDER_DRY_EVENT) {
++            is_dry = 1;
++
++            /* disable sender dry event */
++#  ifdef SCTP_EVENT
++            memset(&event, 0, sizeof(event));
++            event.se_assoc_id = 0;
++            event.se_type = SCTP_SENDER_DRY_EVENT;
++            event.se_on = 0;
++            ret =
++                setsockopt(b->num, IPPROTO_SCTP, SCTP_EVENT, &event,
++                           sizeof(struct sctp_event));
++#  else
++            eventsize = (socklen_t) sizeof(struct sctp_event_subscribe);
++            ret =
++                getsockopt(b->num, IPPROTO_SCTP, SCTP_EVENTS, &event,
++                           &eventsize);
++            if (ret < 0)
++                return -1;
++
++            event.sctp_sender_dry_event = 0;
++
++            ret =
++                setsockopt(b->num, IPPROTO_SCTP, SCTP_EVENTS, &event,
++                           sizeof(struct sctp_event_subscribe));
++#  endif
++            if (ret < 0)
++                return -1;
++        }
++#  ifdef SCTP_AUTHENTICATION_EVENT
++        if (snp.sn_header.sn_type == SCTP_AUTHENTICATION_EVENT)
++            dgram_sctp_handle_auth_free_key_event(b, &snp);
++#  endif
++
++        if (data->handle_notifications != NULL)
++            data->handle_notifications(b, data->notification_context,
++                                       (void *)&snp);
++
++        /* found notification, peek again */
++        memset(&snp, 0, sizeof(snp));
++        iov.iov_base = (char *)&snp;
++        iov.iov_len = sizeof(union sctp_notification);
++        msg.msg_name = NULL;
++        msg.msg_namelen = 0;
++        msg.msg_iov = &iov;
++        msg.msg_iovlen = 1;
++        msg.msg_control = NULL;
++        msg.msg_controllen = 0;
++        msg.msg_flags = 0;
++
++        /* if we have seen the dry already, don't wait */
++        if (is_dry) {
++            sockflags = fcntl(b->num, F_GETFL, 0);
++            fcntl(b->num, F_SETFL, O_NONBLOCK);
++        }
++
++        n = recvmsg(b->num, &msg, MSG_PEEK);
++
++        if (is_dry) {
++            fcntl(b->num, F_SETFL, sockflags);
++        }
++
++        if (n <= 0) {
++            if ((n < 0) && (get_last_socket_error() != EAGAIN)
++                && (get_last_socket_error() != EWOULDBLOCK))
++                return -1;
++            else
++                return is_dry;
++        }
++    }
++
++    /* read anything else */
++    return is_dry;
++}
++
++int BIO_dgram_sctp_msg_waiting(BIO *b)
++{
++    int n, sockflags;
++    union sctp_notification snp;
++    struct msghdr msg;
++    struct iovec iov;
++    bio_dgram_sctp_data *data = (bio_dgram_sctp_data *) b->ptr;
++
++    /* Check if there are any messages waiting to be read */
++    do {
++        memset(&snp, 0, sizeof(snp));
++        iov.iov_base = (char *)&snp;
++        iov.iov_len = sizeof(union sctp_notification);
++        msg.msg_name = NULL;
++        msg.msg_namelen = 0;
++        msg.msg_iov = &iov;
++        msg.msg_iovlen = 1;
++        msg.msg_control = NULL;
++        msg.msg_controllen = 0;
++        msg.msg_flags = 0;
++
++        sockflags = fcntl(b->num, F_GETFL, 0);
++        fcntl(b->num, F_SETFL, O_NONBLOCK);
++        n = recvmsg(b->num, &msg, MSG_PEEK);
++        fcntl(b->num, F_SETFL, sockflags);
++
++        /* if notification, process and try again */
++        if (n > 0 && (msg.msg_flags & MSG_NOTIFICATION)) {
++#  ifdef SCTP_AUTHENTICATION_EVENT
++            if (snp.sn_header.sn_type == SCTP_AUTHENTICATION_EVENT)
++                dgram_sctp_handle_auth_free_key_event(b, &snp);
++#  endif
++
++            memset(&snp, 0, sizeof(snp));
++            iov.iov_base = (char *)&snp;
++            iov.iov_len = sizeof(union sctp_notification);
++            msg.msg_name = NULL;
++            msg.msg_namelen = 0;
++            msg.msg_iov = &iov;
++            msg.msg_iovlen = 1;
++            msg.msg_control = NULL;
++            msg.msg_controllen = 0;
++            msg.msg_flags = 0;
++            n = recvmsg(b->num, &msg, 0);
++
++            if (data->handle_notifications != NULL)
++                data->handle_notifications(b, data->notification_context,
++                                           (void *)&snp);
++        }
++
++    } while (n > 0 && (msg.msg_flags & MSG_NOTIFICATION));
++
++    /* Return 1 if there is a message to be read, return 0 otherwise. */
++    if (n > 0)
++        return 1;
++    else
++        return 0;
++}
++
++static int dgram_sctp_puts(BIO *bp, const char *str)
++{
++    int n, ret;
++
++    n = strlen(str);
++    ret = dgram_sctp_write(bp, str, n);
++    return (ret);
++}
++# endif
++
++static int BIO_dgram_should_retry(int i)
++{
++    int err;
++
++    if ((i == 0) || (i == -1)) {
++        err = get_last_socket_error();
++
++# if defined(OPENSSL_SYS_WINDOWS)
++        /*
++         * If the socket return value (i) is -1 and err is unexpectedly 0 at
++         * this point, the error code was overwritten by another system call
++         * before this error handling is called.
++         */
++# endif
++
++        return (BIO_dgram_non_fatal_error(err));
++    }
++    return (0);
++}
++
++int BIO_dgram_non_fatal_error(int err)
++{
++    switch (err) {
++# if defined(OPENSSL_SYS_WINDOWS)
++#  if defined(WSAEWOULDBLOCK)
++    case WSAEWOULDBLOCK:
++#  endif
++# endif
++
++# ifdef EWOULDBLOCK
++#  ifdef WSAEWOULDBLOCK
++#   if WSAEWOULDBLOCK != EWOULDBLOCK
++    case EWOULDBLOCK:
++#   endif
++#  else
++    case EWOULDBLOCK:
++#  endif
++# endif
++
++# ifdef EINTR
++    case EINTR:
++# endif
++
++# ifdef EAGAIN
++#  if EWOULDBLOCK != EAGAIN
++    case EAGAIN:
++#  endif
++# endif
++
++# ifdef EPROTO
++    case EPROTO:
++# endif
++
++# ifdef EINPROGRESS
++    case EINPROGRESS:
++# endif
++
++# ifdef EALREADY
++    case EALREADY:
++# endif
++
++        return (1);
++        /* break; */
++    default:
++        break;
++    }
++    return (0);
++}
++
++static void get_current_time(struct timeval *t)
++{
++# if defined(_WIN32)
++    SYSTEMTIME st;
++    union {
++        unsigned __int64 ul;
++        FILETIME ft;
++    } now;
++
++    GetSystemTime(&st);
++    SystemTimeToFileTime(&st, &now.ft);
++#  ifdef  __MINGW32__
++    now.ul -= 116444736000000000ULL;
++#  else
++    now.ul -= 116444736000000000UI64; /* re-bias to 1/1/1970 */
++#  endif
++    t->tv_sec = (long)(now.ul / 10000000);
++    t->tv_usec = ((int)(now.ul % 10000000)) / 10;
++# elif defined(OPENSSL_SYS_VMS)
++    struct timeb tb;
++    ftime(&tb);
++    t->tv_sec = (long)tb.time;
++    t->tv_usec = (long)tb.millitm * 1000;
++# else
++    gettimeofday(t, NULL);
++# endif
++}
++
++#endif
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/bio/bss_fd.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/bio/bss_fd.c
+new file mode 100644
+index 0000000..1e56cb6
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/bio/bss_fd.c
+@@ -0,0 +1,273 @@
++/*
++ * Copyright 1995-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include 
++
++#include "bio_lcl.h"
++
++#if defined(OPENSSL_NO_POSIX_IO)
++/*
++ * Dummy placeholder for BIO_s_fd...
++ */
++BIO *BIO_new_fd(int fd, int close_flag)
++{
++    return NULL;
++}
++
++int BIO_fd_non_fatal_error(int err)
++{
++    return 0;
++}
++
++int BIO_fd_should_retry(int i)
++{
++    return 0;
++}
++
++const BIO_METHOD *BIO_s_fd(void)
++{
++    return NULL;
++}
++#else
++/*
++ * As for unconditional usage of "UPLINK" interface in this module.
++ * Trouble is that unlike Unix file descriptors [which are indexes
++ * in kernel-side per-process table], corresponding descriptors on
++ * platforms which require "UPLINK" interface seem to be indexes
++ * in a user-land, non-global table. Well, in fact they are indexes
++ * in stdio _iob[], and recall that _iob[] was the very reason why
++ * "UPLINK" interface was introduced in first place. But one way on
++ * another. Neither libcrypto or libssl use this BIO meaning that
++ * file descriptors can only be provided by application. Therefore
++ * "UPLINK" calls are due...
++ */
++static int fd_write(BIO *h, const char *buf, int num);
++static int fd_read(BIO *h, char *buf, int size);
++static int fd_puts(BIO *h, const char *str);
++static int fd_gets(BIO *h, char *buf, int size);
++static long fd_ctrl(BIO *h, int cmd, long arg1, void *arg2);
++static int fd_new(BIO *h);
++static int fd_free(BIO *data);
++int BIO_fd_should_retry(int s);
++
++static const BIO_METHOD methods_fdp = {
++    BIO_TYPE_FD, "file descriptor",
++    fd_write,
++    fd_read,
++    fd_puts,
++    fd_gets,
++    fd_ctrl,
++    fd_new,
++    fd_free,
++    NULL,
++};
++
++const BIO_METHOD *BIO_s_fd(void)
++{
++    return (&methods_fdp);
++}
++
++BIO *BIO_new_fd(int fd, int close_flag)
++{
++    BIO *ret;
++    ret = BIO_new(BIO_s_fd());
++    if (ret == NULL)
++        return (NULL);
++    BIO_set_fd(ret, fd, close_flag);
++    return (ret);
++}
++
++static int fd_new(BIO *bi)
++{
++    bi->init = 0;
++    bi->num = -1;
++    bi->ptr = NULL;
++    bi->flags = BIO_FLAGS_UPLINK; /* essentially redundant */
++    return (1);
++}
++
++static int fd_free(BIO *a)
++{
++    if (a == NULL)
++        return (0);
++    if (a->shutdown) {
++        if (a->init) {
++            UP_close(a->num);
++        }
++        a->init = 0;
++        a->flags = BIO_FLAGS_UPLINK;
++    }
++    return (1);
++}
++
++static int fd_read(BIO *b, char *out, int outl)
++{
++    int ret = 0;
++
++    if (out != NULL) {
++        clear_sys_error();
++        ret = UP_read(b->num, out, outl);
++        BIO_clear_retry_flags(b);
++        if (ret <= 0) {
++            if (BIO_fd_should_retry(ret))
++                BIO_set_retry_read(b);
++        }
++    }
++    return (ret);
++}
++
++static int fd_write(BIO *b, const char *in, int inl)
++{
++    int ret;
++    clear_sys_error();
++    ret = UP_write(b->num, in, inl);
++    BIO_clear_retry_flags(b);
++    if (ret <= 0) {
++        if (BIO_fd_should_retry(ret))
++            BIO_set_retry_write(b);
++    }
++    return (ret);
++}
++
++static long fd_ctrl(BIO *b, int cmd, long num, void *ptr)
++{
++    long ret = 1;
++    int *ip;
++
++    switch (cmd) {
++    case BIO_CTRL_RESET:
++        num = 0;
++    case BIO_C_FILE_SEEK:
++        ret = (long)UP_lseek(b->num, num, 0);
++        break;
++    case BIO_C_FILE_TELL:
++    case BIO_CTRL_INFO:
++        ret = (long)UP_lseek(b->num, 0, 1);
++        break;
++    case BIO_C_SET_FD:
++        fd_free(b);
++        b->num = *((int *)ptr);
++        b->shutdown = (int)num;
++        b->init = 1;
++        break;
++    case BIO_C_GET_FD:
++        if (b->init) {
++            ip = (int *)ptr;
++            if (ip != NULL)
++                *ip = b->num;
++            ret = b->num;
++        } else
++            ret = -1;
++        break;
++    case BIO_CTRL_GET_CLOSE:
++        ret = b->shutdown;
++        break;
++    case BIO_CTRL_SET_CLOSE:
++        b->shutdown = (int)num;
++        break;
++    case BIO_CTRL_PENDING:
++    case BIO_CTRL_WPENDING:
++        ret = 0;
++        break;
++    case BIO_CTRL_DUP:
++    case BIO_CTRL_FLUSH:
++        ret = 1;
++        break;
++    default:
++        ret = 0;
++        break;
++    }
++    return (ret);
++}
++
++static int fd_puts(BIO *bp, const char *str)
++{
++    int n, ret;
++
++    n = strlen(str);
++    ret = fd_write(bp, str, n);
++    return (ret);
++}
++
++static int fd_gets(BIO *bp, char *buf, int size)
++{
++    int ret = 0;
++    char *ptr = buf;
++    char *end = buf + size - 1;
++
++    while ((ptr < end) && (fd_read(bp, ptr, 1) > 0) && (ptr[0] != '\n'))
++        ptr++;
++
++    ptr[0] = '\0';
++
++    if (buf[0] != '\0')
++        ret = strlen(buf);
++    return (ret);
++}
++
++int BIO_fd_should_retry(int i)
++{
++    int err;
++
++    if ((i == 0) || (i == -1)) {
++        err = get_last_sys_error();
++
++        return (BIO_fd_non_fatal_error(err));
++    }
++    return (0);
++}
++
++int BIO_fd_non_fatal_error(int err)
++{
++    switch (err) {
++
++# ifdef EWOULDBLOCK
++#  ifdef WSAEWOULDBLOCK
++#   if WSAEWOULDBLOCK != EWOULDBLOCK
++    case EWOULDBLOCK:
++#   endif
++#  else
++    case EWOULDBLOCK:
++#  endif
++# endif
++
++# if defined(ENOTCONN)
++    case ENOTCONN:
++# endif
++
++# ifdef EINTR
++    case EINTR:
++# endif
++
++# ifdef EAGAIN
++#  if EWOULDBLOCK != EAGAIN
++    case EAGAIN:
++#  endif
++# endif
++
++# ifdef EPROTO
++    case EPROTO:
++# endif
++
++# ifdef EINPROGRESS
++    case EINPROGRESS:
++# endif
++
++# ifdef EALREADY
++    case EALREADY:
++# endif
++        return (1);
++        /* break; */
++    default:
++        break;
++    }
++    return (0);
++}
++#endif
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/bio/bss_file.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/bio/bss_file.c
+new file mode 100644
+index 0000000..6af2d9c
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/bio/bss_file.c
+@@ -0,0 +1,419 @@
++/*
++ * Copyright 1995-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++/*-
++ * 03-Dec-1997  rdenny@dc3.com  Fix bug preventing use of stdin/stdout
++ *              with binary data (e.g. asn1parse -inform DER < xxx) under
++ *              Windows
++ */
++
++#ifndef HEADER_BSS_FILE_C
++# define HEADER_BSS_FILE_C
++
++# if defined(__linux) || defined(__sun) || defined(__hpux)
++/*
++ * Following definition aliases fopen to fopen64 on above mentioned
++ * platforms. This makes it possible to open and sequentially access files
++ * larger than 2GB from 32-bit application. It does not allow to traverse
++ * them beyond 2GB with fseek/ftell, but on the other hand *no* 32-bit
++ * platform permits that, not with fseek/ftell. Not to mention that breaking
++ * 2GB limit for seeking would require surgery to *our* API. But sequential
++ * access suffices for practical cases when you can run into large files,
++ * such as fingerprinting, so we can let API alone. For reference, the list
++ * of 32-bit platforms which allow for sequential access of large files
++ * without extra "magic" comprise *BSD, Darwin, IRIX...
++ */
++#  ifndef _FILE_OFFSET_BITS
++#   define _FILE_OFFSET_BITS 64
++#  endif
++# endif
++
++# include 
++# include 
++# include "bio_lcl.h"
++# include 
++
++# if !defined(OPENSSL_NO_STDIO)
++
++static int file_write(BIO *h, const char *buf, int num);
++static int file_read(BIO *h, char *buf, int size);
++static int file_puts(BIO *h, const char *str);
++static int file_gets(BIO *h, char *str, int size);
++static long file_ctrl(BIO *h, int cmd, long arg1, void *arg2);
++static int file_new(BIO *h);
++static int file_free(BIO *data);
++static const BIO_METHOD methods_filep = {
++    BIO_TYPE_FILE,
++    "FILE pointer",
++    file_write,
++    file_read,
++    file_puts,
++    file_gets,
++    file_ctrl,
++    file_new,
++    file_free,
++    NULL,
++};
++
++BIO *BIO_new_file(const char *filename, const char *mode)
++{
++    BIO  *ret;
++    FILE *file = openssl_fopen(filename, mode);
++    int fp_flags = BIO_CLOSE;
++
++    if (strchr(mode, 'b') == NULL)
++        fp_flags |= BIO_FP_TEXT;
++
++    if (file == NULL) {
++        SYSerr(SYS_F_FOPEN, get_last_sys_error());
++        ERR_add_error_data(5, "fopen('", filename, "','", mode, "')");
++        if (errno == ENOENT
++# ifdef ENXIO
++            || errno == ENXIO
++# endif
++            )
++            BIOerr(BIO_F_BIO_NEW_FILE, BIO_R_NO_SUCH_FILE);
++        else
++            BIOerr(BIO_F_BIO_NEW_FILE, ERR_R_SYS_LIB);
++        return (NULL);
++    }
++    if ((ret = BIO_new(BIO_s_file())) == NULL) {
++        fclose(file);
++        return (NULL);
++    }
++
++    BIO_clear_flags(ret, BIO_FLAGS_UPLINK); /* we did fopen -> we disengage
++                                             * UPLINK */
++    BIO_set_fp(ret, file, fp_flags);
++    return (ret);
++}
++
++BIO *BIO_new_fp(FILE *stream, int close_flag)
++{
++    BIO *ret;
++
++    if ((ret = BIO_new(BIO_s_file())) == NULL)
++        return (NULL);
++
++    /* redundant flag, left for documentation purposes */
++    BIO_set_flags(ret, BIO_FLAGS_UPLINK);
++    BIO_set_fp(ret, stream, close_flag);
++    return (ret);
++}
++
++const BIO_METHOD *BIO_s_file(void)
++{
++    return (&methods_filep);
++}
++
++static int file_new(BIO *bi)
++{
++    bi->init = 0;
++    bi->num = 0;
++    bi->ptr = NULL;
++    bi->flags = BIO_FLAGS_UPLINK; /* default to UPLINK */
++    return (1);
++}
++
++static int file_free(BIO *a)
++{
++    if (a == NULL)
++        return (0);
++    if (a->shutdown) {
++        if ((a->init) && (a->ptr != NULL)) {
++            if (a->flags & BIO_FLAGS_UPLINK)
++                UP_fclose(a->ptr);
++            else
++                fclose(a->ptr);
++            a->ptr = NULL;
++            a->flags = BIO_FLAGS_UPLINK;
++        }
++        a->init = 0;
++    }
++    return (1);
++}
++
++static int file_read(BIO *b, char *out, int outl)
++{
++    int ret = 0;
++
++    if (b->init && (out != NULL)) {
++        if (b->flags & BIO_FLAGS_UPLINK)
++            ret = UP_fread(out, 1, (int)outl, b->ptr);
++        else
++            ret = fread(out, 1, (int)outl, (FILE *)b->ptr);
++        if (ret == 0
++            && (b->flags & BIO_FLAGS_UPLINK) ? UP_ferror((FILE *)b->ptr) :
++                                               ferror((FILE *)b->ptr)) {
++            SYSerr(SYS_F_FREAD, get_last_sys_error());
++            BIOerr(BIO_F_FILE_READ, ERR_R_SYS_LIB);
++            ret = -1;
++        }
++    }
++    return (ret);
++}
++
++static int file_write(BIO *b, const char *in, int inl)
++{
++    int ret = 0;
++
++    if (b->init && (in != NULL)) {
++        if (b->flags & BIO_FLAGS_UPLINK)
++            ret = UP_fwrite(in, (int)inl, 1, b->ptr);
++        else
++            ret = fwrite(in, (int)inl, 1, (FILE *)b->ptr);
++        if (ret)
++            ret = inl;
++        /* ret=fwrite(in,1,(int)inl,(FILE *)b->ptr); */
++        /*
++         * according to Tim Hudson , the commented out
++         * version above can cause 'inl' write calls under some stupid stdio
++         * implementations (VMS)
++         */
++    }
++    return (ret);
++}
++
++static long file_ctrl(BIO *b, int cmd, long num, void *ptr)
++{
++    long ret = 1;
++    FILE *fp = (FILE *)b->ptr;
++    FILE **fpp;
++    char p[4];
++
++    switch (cmd) {
++    case BIO_C_FILE_SEEK:
++    case BIO_CTRL_RESET:
++        if (b->flags & BIO_FLAGS_UPLINK)
++            ret = (long)UP_fseek(b->ptr, num, 0);
++        else
++            ret = (long)fseek(fp, num, 0);
++        break;
++    case BIO_CTRL_EOF:
++        if (b->flags & BIO_FLAGS_UPLINK)
++            ret = (long)UP_feof(fp);
++        else
++            ret = (long)feof(fp);
++        break;
++    case BIO_C_FILE_TELL:
++    case BIO_CTRL_INFO:
++        if (b->flags & BIO_FLAGS_UPLINK)
++            ret = UP_ftell(b->ptr);
++        else
++            ret = ftell(fp);
++        break;
++    case BIO_C_SET_FILE_PTR:
++        file_free(b);
++        b->shutdown = (int)num & BIO_CLOSE;
++        b->ptr = ptr;
++        b->init = 1;
++#  if BIO_FLAGS_UPLINK!=0
++#   if defined(__MINGW32__) && defined(__MSVCRT__) && !defined(_IOB_ENTRIES)
++#    define _IOB_ENTRIES 20
++#   endif
++        /* Safety net to catch purely internal BIO_set_fp calls */
++#   if defined(_MSC_VER) && _MSC_VER>=1900
++        if (ptr == stdin || ptr == stdout || ptr == stderr)
++            BIO_clear_flags(b, BIO_FLAGS_UPLINK);
++#   elif defined(_IOB_ENTRIES)
++        if ((size_t)ptr >= (size_t)stdin &&
++            (size_t)ptr < (size_t)(stdin + _IOB_ENTRIES))
++            BIO_clear_flags(b, BIO_FLAGS_UPLINK);
++#   endif
++#  endif
++#  ifdef UP_fsetmod
++        if (b->flags & BIO_FLAGS_UPLINK)
++            UP_fsetmod(b->ptr, (char)((num & BIO_FP_TEXT) ? 't' : 'b'));
++        else
++#  endif
++        {
++#  if defined(OPENSSL_SYS_WINDOWS)
++            int fd = _fileno((FILE *)ptr);
++            if (num & BIO_FP_TEXT)
++                _setmode(fd, _O_TEXT);
++            else
++                _setmode(fd, _O_BINARY);
++#  elif defined(OPENSSL_SYS_MSDOS)
++            int fd = fileno((FILE *)ptr);
++            /* Set correct text/binary mode */
++            if (num & BIO_FP_TEXT)
++                _setmode(fd, _O_TEXT);
++            /* Dangerous to set stdin/stdout to raw (unless redirected) */
++            else {
++                if (fd == STDIN_FILENO || fd == STDOUT_FILENO) {
++                    if (isatty(fd) <= 0)
++                        _setmode(fd, _O_BINARY);
++                } else
++                    _setmode(fd, _O_BINARY);
++            }
++#  elif defined(OPENSSL_SYS_WIN32_CYGWIN)
++            int fd = fileno((FILE *)ptr);
++            if (num & BIO_FP_TEXT)
++                setmode(fd, O_TEXT);
++            else
++                setmode(fd, O_BINARY);
++#  endif
++        }
++        break;
++    case BIO_C_SET_FILENAME:
++        file_free(b);
++        b->shutdown = (int)num & BIO_CLOSE;
++        if (num & BIO_FP_APPEND) {
++            if (num & BIO_FP_READ)
++                OPENSSL_strlcpy(p, "a+", sizeof p);
++            else
++                OPENSSL_strlcpy(p, "a", sizeof p);
++        } else if ((num & BIO_FP_READ) && (num & BIO_FP_WRITE))
++            OPENSSL_strlcpy(p, "r+", sizeof p);
++        else if (num & BIO_FP_WRITE)
++            OPENSSL_strlcpy(p, "w", sizeof p);
++        else if (num & BIO_FP_READ)
++            OPENSSL_strlcpy(p, "r", sizeof p);
++        else {
++            BIOerr(BIO_F_FILE_CTRL, BIO_R_BAD_FOPEN_MODE);
++            ret = 0;
++            break;
++        }
++#  if defined(OPENSSL_SYS_MSDOS) || defined(OPENSSL_SYS_WINDOWS) || defined(OPENSSL_SYS_WIN32_CYGWIN)
++        if (!(num & BIO_FP_TEXT))
++            strcat(p, "b");
++        else
++            strcat(p, "t");
++#  endif
++        fp = openssl_fopen(ptr, p);
++        if (fp == NULL) {
++            SYSerr(SYS_F_FOPEN, get_last_sys_error());
++            ERR_add_error_data(5, "fopen('", ptr, "','", p, "')");
++            BIOerr(BIO_F_FILE_CTRL, ERR_R_SYS_LIB);
++            ret = 0;
++            break;
++        }
++        b->ptr = fp;
++        b->init = 1;
++        BIO_clear_flags(b, BIO_FLAGS_UPLINK); /* we did fopen -> we disengage
++                                               * UPLINK */
++        break;
++    case BIO_C_GET_FILE_PTR:
++        /* the ptr parameter is actually a FILE ** in this case. */
++        if (ptr != NULL) {
++            fpp = (FILE **)ptr;
++            *fpp = (FILE *)b->ptr;
++        }
++        break;
++    case BIO_CTRL_GET_CLOSE:
++        ret = (long)b->shutdown;
++        break;
++    case BIO_CTRL_SET_CLOSE:
++        b->shutdown = (int)num;
++        break;
++    case BIO_CTRL_FLUSH:
++        if (b->flags & BIO_FLAGS_UPLINK)
++            UP_fflush(b->ptr);
++        else
++            fflush((FILE *)b->ptr);
++        break;
++    case BIO_CTRL_DUP:
++        ret = 1;
++        break;
++
++    case BIO_CTRL_WPENDING:
++    case BIO_CTRL_PENDING:
++    case BIO_CTRL_PUSH:
++    case BIO_CTRL_POP:
++    default:
++        ret = 0;
++        break;
++    }
++    return (ret);
++}
++
++static int file_gets(BIO *bp, char *buf, int size)
++{
++    int ret = 0;
++
++    buf[0] = '\0';
++    if (bp->flags & BIO_FLAGS_UPLINK) {
++        if (!UP_fgets(buf, size, bp->ptr))
++            goto err;
++    } else {
++        if (!fgets(buf, size, (FILE *)bp->ptr))
++            goto err;
++    }
++    if (buf[0] != '\0')
++        ret = strlen(buf);
++ err:
++    return (ret);
++}
++
++static int file_puts(BIO *bp, const char *str)
++{
++    int n, ret;
++
++    n = strlen(str);
++    ret = file_write(bp, str, n);
++    return (ret);
++}
++
++#else
++
++static int file_write(BIO *b, const char *in, int inl)
++{
++    return -1;
++}
++static int file_read(BIO *b, char *out, int outl)
++{
++    return -1;
++}
++static int file_puts(BIO *bp, const char *str)
++{
++    return -1;
++}
++static int file_gets(BIO *bp, char *buf, int size)
++{
++    return 0;
++}
++static long file_ctrl(BIO *b, int cmd, long num, void *ptr)
++{
++    return 0;
++}
++static int file_new(BIO *bi)
++{
++    return 0;
++}
++static int file_free(BIO *a)
++{
++    return 0;
++}
++
++static const BIO_METHOD methods_filep = {
++    BIO_TYPE_FILE,
++    "FILE pointer",
++    file_write,
++    file_read,
++    file_puts,
++    file_gets,
++    file_ctrl,
++    file_new,
++    file_free,
++    NULL,
++};
++
++const BIO_METHOD *BIO_s_file(void)
++{
++    return (&methods_filep);
++}
++
++BIO *BIO_new_file(const char *filename, const char *mode)
++{
++    return NULL;
++}
++
++# endif                         /* OPENSSL_NO_STDIO */
++
++#endif                          /* HEADER_BSS_FILE_C */
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/bio/bss_log.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/bio/bss_log.c
+new file mode 100644
+index 0000000..6cbde4d
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/bio/bss_log.c
+@@ -0,0 +1,406 @@
++/*
++ * Copyright 1999-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++/*
++ * Why BIO_s_log?
++ *
++ * BIO_s_log is useful for system daemons (or services under NT). It is
++ * one-way BIO, it sends all stuff to syslogd (on system that commonly use
++ * that), or event log (on NT), or OPCOM (on OpenVMS).
++ *
++ */
++
++#include 
++#include 
++
++#include "bio_lcl.h"
++#include "internal/cryptlib.h"
++
++#if defined(OPENSSL_SYS_WINCE)
++#elif defined(OPENSSL_SYS_WIN32)
++#elif defined(OPENSSL_SYS_VMS)
++# include 
++# include 
++# include 
++# include 
++/* Some compiler options may mask the declaration of "_malloc32". */
++# if __INITIAL_POINTER_SIZE && defined _ANSI_C_SOURCE
++#  if __INITIAL_POINTER_SIZE == 64
++#   pragma pointer_size save
++#   pragma pointer_size 32
++void *_malloc32(__size_t);
++#   pragma pointer_size restore
++#  endif                        /* __INITIAL_POINTER_SIZE == 64 */
++# endif                         /* __INITIAL_POINTER_SIZE && defined
++                                 * _ANSI_C_SOURCE */
++#elif defined(OPENSSL_SYS_NETWARE)
++# define NO_SYSLOG
++#elif (!defined(MSDOS) || defined(WATT32)) && !defined(OPENSSL_SYS_VXWORKS) && !defined(NO_SYSLOG)
++# include 
++#endif
++
++#include 
++#include 
++
++#ifndef NO_SYSLOG
++
++# if defined(OPENSSL_SYS_WIN32)
++#  define LOG_EMERG       0
++#  define LOG_ALERT       1
++#  define LOG_CRIT        2
++#  define LOG_ERR         3
++#  define LOG_WARNING     4
++#  define LOG_NOTICE      5
++#  define LOG_INFO        6
++#  define LOG_DEBUG       7
++
++#  define LOG_DAEMON      (3<<3)
++# elif defined(OPENSSL_SYS_VMS)
++/* On VMS, we don't really care about these, but we need them to compile */
++#  define LOG_EMERG       0
++#  define LOG_ALERT       1
++#  define LOG_CRIT        2
++#  define LOG_ERR         3
++#  define LOG_WARNING     4
++#  define LOG_NOTICE      5
++#  define LOG_INFO        6
++#  define LOG_DEBUG       7
++
++#  define LOG_DAEMON      OPC$M_NM_NTWORK
++# endif
++
++static int slg_write(BIO *h, const char *buf, int num);
++static int slg_puts(BIO *h, const char *str);
++static long slg_ctrl(BIO *h, int cmd, long arg1, void *arg2);
++static int slg_new(BIO *h);
++static int slg_free(BIO *data);
++static void xopenlog(BIO *bp, char *name, int level);
++static void xsyslog(BIO *bp, int priority, const char *string);
++static void xcloselog(BIO *bp);
++
++static const BIO_METHOD methods_slg = {
++    BIO_TYPE_MEM, "syslog",
++    slg_write,
++    NULL,
++    slg_puts,
++    NULL,
++    slg_ctrl,
++    slg_new,
++    slg_free,
++    NULL,
++};
++
++const BIO_METHOD *BIO_s_log(void)
++{
++    return (&methods_slg);
++}
++
++static int slg_new(BIO *bi)
++{
++    bi->init = 1;
++    bi->num = 0;
++    bi->ptr = NULL;
++    xopenlog(bi, "application", LOG_DAEMON);
++    return (1);
++}
++
++static int slg_free(BIO *a)
++{
++    if (a == NULL)
++        return (0);
++    xcloselog(a);
++    return (1);
++}
++
++static int slg_write(BIO *b, const char *in, int inl)
++{
++    int ret = inl;
++    char *buf;
++    char *pp;
++    int priority, i;
++    static const struct {
++        int strl;
++        char str[10];
++        int log_level;
++    } mapping[] = {
++        {
++            6, "PANIC ", LOG_EMERG
++        },
++        {
++            6, "EMERG ", LOG_EMERG
++        },
++        {
++            4, "EMR ", LOG_EMERG
++        },
++        {
++            6, "ALERT ", LOG_ALERT
++        },
++        {
++            4, "ALR ", LOG_ALERT
++        },
++        {
++            5, "CRIT ", LOG_CRIT
++        },
++        {
++            4, "CRI ", LOG_CRIT
++        },
++        {
++            6, "ERROR ", LOG_ERR
++        },
++        {
++            4, "ERR ", LOG_ERR
++        },
++        {
++            8, "WARNING ", LOG_WARNING
++        },
++        {
++            5, "WARN ", LOG_WARNING
++        },
++        {
++            4, "WAR ", LOG_WARNING
++        },
++        {
++            7, "NOTICE ", LOG_NOTICE
++        },
++        {
++            5, "NOTE ", LOG_NOTICE
++        },
++        {
++            4, "NOT ", LOG_NOTICE
++        },
++        {
++            5, "INFO ", LOG_INFO
++        },
++        {
++            4, "INF ", LOG_INFO
++        },
++        {
++            6, "DEBUG ", LOG_DEBUG
++        },
++        {
++            4, "DBG ", LOG_DEBUG
++        },
++        {
++            0, "", LOG_ERR
++        }
++        /* The default */
++    };
++
++    if ((buf = OPENSSL_malloc(inl + 1)) == NULL) {
++        return (0);
++    }
++    strncpy(buf, in, inl);
++    buf[inl] = '\0';
++
++    i = 0;
++    while (strncmp(buf, mapping[i].str, mapping[i].strl) != 0)
++        i++;
++    priority = mapping[i].log_level;
++    pp = buf + mapping[i].strl;
++
++    xsyslog(b, priority, pp);
++
++    OPENSSL_free(buf);
++    return (ret);
++}
++
++static long slg_ctrl(BIO *b, int cmd, long num, void *ptr)
++{
++    switch (cmd) {
++    case BIO_CTRL_SET:
++        xcloselog(b);
++        xopenlog(b, ptr, num);
++        break;
++    default:
++        break;
++    }
++    return (0);
++}
++
++static int slg_puts(BIO *bp, const char *str)
++{
++    int n, ret;
++
++    n = strlen(str);
++    ret = slg_write(bp, str, n);
++    return (ret);
++}
++
++# if defined(OPENSSL_SYS_WIN32)
++
++static void xopenlog(BIO *bp, char *name, int level)
++{
++    if (check_winnt())
++        bp->ptr = RegisterEventSourceA(NULL, name);
++    else
++        bp->ptr = NULL;
++}
++
++static void xsyslog(BIO *bp, int priority, const char *string)
++{
++    LPCSTR lpszStrings[2];
++    WORD evtype = EVENTLOG_ERROR_TYPE;
++    char pidbuf[DECIMAL_SIZE(DWORD) + 4];
++
++    if (bp->ptr == NULL)
++        return;
++
++    switch (priority) {
++    case LOG_EMERG:
++    case LOG_ALERT:
++    case LOG_CRIT:
++    case LOG_ERR:
++        evtype = EVENTLOG_ERROR_TYPE;
++        break;
++    case LOG_WARNING:
++        evtype = EVENTLOG_WARNING_TYPE;
++        break;
++    case LOG_NOTICE:
++    case LOG_INFO:
++    case LOG_DEBUG:
++        evtype = EVENTLOG_INFORMATION_TYPE;
++        break;
++    default:
++        /*
++         * Should never happen, but set it
++         * as error anyway.
++         */
++        evtype = EVENTLOG_ERROR_TYPE;
++        break;
++    }
++
++    sprintf(pidbuf, "[%lu] ", GetCurrentProcessId());
++    lpszStrings[0] = pidbuf;
++    lpszStrings[1] = string;
++
++    ReportEventA(bp->ptr, evtype, 0, 1024, NULL, 2, 0, lpszStrings, NULL);
++}
++
++static void xcloselog(BIO *bp)
++{
++    if (bp->ptr)
++        DeregisterEventSource((HANDLE) (bp->ptr));
++    bp->ptr = NULL;
++}
++
++# elif defined(OPENSSL_SYS_VMS)
++
++static int VMS_OPC_target = LOG_DAEMON;
++
++static void xopenlog(BIO *bp, char *name, int level)
++{
++    VMS_OPC_target = level;
++}
++
++static void xsyslog(BIO *bp, int priority, const char *string)
++{
++    struct dsc$descriptor_s opc_dsc;
++
++/* Arrange 32-bit pointer to opcdef buffer and malloc(), if needed. */
++#  if __INITIAL_POINTER_SIZE == 64
++#   pragma pointer_size save
++#   pragma pointer_size 32
++#   define OPCDEF_TYPE __char_ptr32
++#   define OPCDEF_MALLOC _malloc32
++#  else                         /* __INITIAL_POINTER_SIZE == 64 */
++#   define OPCDEF_TYPE char *
++#   define OPCDEF_MALLOC OPENSSL_malloc
++#  endif                        /* __INITIAL_POINTER_SIZE == 64 [else] */
++
++    struct opcdef *opcdef_p;
++
++#  if __INITIAL_POINTER_SIZE == 64
++#   pragma pointer_size restore
++#  endif                        /* __INITIAL_POINTER_SIZE == 64 */
++
++    char buf[10240];
++    unsigned int len;
++    struct dsc$descriptor_s buf_dsc;
++    $DESCRIPTOR(fao_cmd, "!AZ: !AZ");
++    char *priority_tag;
++
++    switch (priority) {
++    case LOG_EMERG:
++        priority_tag = "Emergency";
++        break;
++    case LOG_ALERT:
++        priority_tag = "Alert";
++        break;
++    case LOG_CRIT:
++        priority_tag = "Critical";
++        break;
++    case LOG_ERR:
++        priority_tag = "Error";
++        break;
++    case LOG_WARNING:
++        priority_tag = "Warning";
++        break;
++    case LOG_NOTICE:
++        priority_tag = "Notice";
++        break;
++    case LOG_INFO:
++        priority_tag = "Info";
++        break;
++    case LOG_DEBUG:
++        priority_tag = "DEBUG";
++        break;
++    }
++
++    buf_dsc.dsc$b_dtype = DSC$K_DTYPE_T;
++    buf_dsc.dsc$b_class = DSC$K_CLASS_S;
++    buf_dsc.dsc$a_pointer = buf;
++    buf_dsc.dsc$w_length = sizeof(buf) - 1;
++
++    lib$sys_fao(&fao_cmd, &len, &buf_dsc, priority_tag, string);
++
++    /* We know there's an 8-byte header.  That's documented. */
++    opcdef_p = OPCDEF_MALLOC(8 + len);
++    opcdef_p->opc$b_ms_type = OPC$_RQ_RQST;
++    memcpy(opcdef_p->opc$z_ms_target_classes, &VMS_OPC_target, 3);
++    opcdef_p->opc$l_ms_rqstid = 0;
++    memcpy(&opcdef_p->opc$l_ms_text, buf, len);
++
++    opc_dsc.dsc$b_dtype = DSC$K_DTYPE_T;
++    opc_dsc.dsc$b_class = DSC$K_CLASS_S;
++    opc_dsc.dsc$a_pointer = (OPCDEF_TYPE) opcdef_p;
++    opc_dsc.dsc$w_length = len + 8;
++
++    sys$sndopr(opc_dsc, 0);
++
++    OPENSSL_free(opcdef_p);
++}
++
++static void xcloselog(BIO *bp)
++{
++}
++
++# else                          /* Unix/Watt32 */
++
++static void xopenlog(BIO *bp, char *name, int level)
++{
++#  ifdef WATT32                 /* djgpp/DOS */
++    openlog(name, LOG_PID | LOG_CONS | LOG_NDELAY, level);
++#  else
++    openlog(name, LOG_PID | LOG_CONS, level);
++#  endif
++}
++
++static void xsyslog(BIO *bp, int priority, const char *string)
++{
++    syslog(priority, "%s", string);
++}
++
++static void xcloselog(BIO *bp)
++{
++    closelog();
++}
++
++# endif                         /* Unix */
++
++#endif                          /* NO_SYSLOG */
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/bio/bss_mem.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/bio/bss_mem.c
+new file mode 100644
+index 0000000..6dc075d
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/bio/bss_mem.c
+@@ -0,0 +1,347 @@
++/*
++ * Copyright 1995-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include 
++#include "bio_lcl.h"
++#include "internal/cryptlib.h"
++
++static int mem_write(BIO *h, const char *buf, int num);
++static int mem_read(BIO *h, char *buf, int size);
++static int mem_puts(BIO *h, const char *str);
++static int mem_gets(BIO *h, char *str, int size);
++static long mem_ctrl(BIO *h, int cmd, long arg1, void *arg2);
++static int mem_new(BIO *h);
++static int secmem_new(BIO *h);
++static int mem_free(BIO *data);
++static int mem_buf_free(BIO *data, int free_all);
++static int mem_buf_sync(BIO *h);
++
++static const BIO_METHOD mem_method = {
++    BIO_TYPE_MEM,
++    "memory buffer",
++    mem_write,
++    mem_read,
++    mem_puts,
++    mem_gets,
++    mem_ctrl,
++    mem_new,
++    mem_free,
++    NULL,
++};
++
++static const BIO_METHOD secmem_method = {
++    BIO_TYPE_MEM,
++    "secure memory buffer",
++    mem_write,
++    mem_read,
++    mem_puts,
++    mem_gets,
++    mem_ctrl,
++    secmem_new,
++    mem_free,
++    NULL,
++};
++
++/* BIO memory stores buffer and read pointer  */
++typedef struct bio_buf_mem_st {
++    struct buf_mem_st *buf;   /* allocated buffer */
++    struct buf_mem_st *readp; /* read pointer */
++} BIO_BUF_MEM;
++
++/*
++ * bio->num is used to hold the value to return on 'empty', if it is 0,
++ * should_retry is not set
++ */
++
++const BIO_METHOD *BIO_s_mem(void)
++{
++    return (&mem_method);
++}
++
++const BIO_METHOD *BIO_s_secmem(void)
++{
++    return(&secmem_method);
++}
++
++BIO *BIO_new_mem_buf(const void *buf, int len)
++{
++    BIO *ret;
++    BUF_MEM *b;
++    BIO_BUF_MEM *bb;
++    size_t sz;
++
++    if (buf == NULL) {
++        BIOerr(BIO_F_BIO_NEW_MEM_BUF, BIO_R_NULL_PARAMETER);
++        return NULL;
++    }
++    sz = (len < 0) ? strlen(buf) : (size_t)len;
++    if ((ret = BIO_new(BIO_s_mem())) == NULL)
++        return NULL;
++    bb = (BIO_BUF_MEM *)ret->ptr;
++    b = bb->buf;
++    /* Cast away const and trust in the MEM_RDONLY flag. */
++    b->data = (void *)buf;
++    b->length = sz;
++    b->max = sz;
++    *bb->readp = *bb->buf;
++    ret->flags |= BIO_FLAGS_MEM_RDONLY;
++    /* Since this is static data retrying won't help */
++    ret->num = 0;
++    return ret;
++}
++
++static int mem_init(BIO *bi, unsigned long flags)
++{
++    BIO_BUF_MEM *bb = OPENSSL_zalloc(sizeof(*bb));
++
++    if (bb == NULL)
++        return 0;
++    if ((bb->buf = BUF_MEM_new_ex(flags)) == NULL) {
++        OPENSSL_free(bb);
++        return 0;
++    }
++    if ((bb->readp = OPENSSL_zalloc(sizeof(*bb->readp))) == NULL) {
++        BUF_MEM_free(bb->buf);
++        OPENSSL_free(bb);
++        return 0;
++    }
++    *bb->readp = *bb->buf;
++    bi->shutdown = 1;
++    bi->init = 1;
++    bi->num = -1;
++    bi->ptr = (char *)bb;
++    return 1;
++}
++
++static int mem_new(BIO *bi)
++{
++    return (mem_init(bi, 0L));
++}
++
++static int secmem_new(BIO *bi)
++{
++    return (mem_init(bi, BUF_MEM_FLAG_SECURE));
++}
++
++static int mem_free(BIO *a)
++{
++    return (mem_buf_free(a, 1));
++}
++
++static int mem_buf_free(BIO *a, int free_all)
++{
++    if (a == NULL)
++        return (0);
++    if (a->shutdown) {
++        if ((a->init) && (a->ptr != NULL)) {
++            BUF_MEM *b;
++            BIO_BUF_MEM *bb = (BIO_BUF_MEM *)a->ptr;
++
++            if (bb != NULL) {
++                b = bb->buf;
++                if (a->flags & BIO_FLAGS_MEM_RDONLY)
++                    b->data = NULL;
++                BUF_MEM_free(b);
++                if (free_all) {
++                    OPENSSL_free(bb->readp);
++                    OPENSSL_free(bb);
++                }
++            }
++            a->ptr = NULL;
++        }
++    }
++    return (1);
++}
++
++/*
++ * Reallocate memory buffer if read pointer differs
++ */
++static int mem_buf_sync(BIO *b)
++{
++    if (b != NULL && b->init != 0 && b->ptr != NULL) {
++        BIO_BUF_MEM *bbm = (BIO_BUF_MEM *)b->ptr;
++
++        if (bbm->readp->data != bbm->buf->data) {
++            memmove(bbm->buf->data, bbm->readp->data, bbm->readp->length);
++            bbm->buf->length = bbm->readp->length;
++            bbm->readp->data = bbm->buf->data;
++        }
++    }
++    return (0);
++}
++
++static int mem_read(BIO *b, char *out, int outl)
++{
++    int ret = -1;
++    BIO_BUF_MEM *bbm = (BIO_BUF_MEM *)b->ptr;
++    BUF_MEM *bm = bbm->readp;
++
++    BIO_clear_retry_flags(b);
++    ret = (outl >= 0 && (size_t)outl > bm->length) ? (int)bm->length : outl;
++    if ((out != NULL) && (ret > 0)) {
++        memcpy(out, bm->data, ret);
++        bm->length -= ret;
++        bm->data += ret;
++    } else if (bm->length == 0) {
++        ret = b->num;
++        if (ret != 0)
++            BIO_set_retry_read(b);
++    }
++    return (ret);
++}
++
++static int mem_write(BIO *b, const char *in, int inl)
++{
++    int ret = -1;
++    int blen;
++    BIO_BUF_MEM *bbm = (BIO_BUF_MEM *)b->ptr;
++
++    if (in == NULL) {
++        BIOerr(BIO_F_MEM_WRITE, BIO_R_NULL_PARAMETER);
++        goto end;
++    }
++    if (b->flags & BIO_FLAGS_MEM_RDONLY) {
++        BIOerr(BIO_F_MEM_WRITE, BIO_R_WRITE_TO_READ_ONLY_BIO);
++        goto end;
++    }
++    BIO_clear_retry_flags(b);
++    blen = bbm->readp->length;
++    mem_buf_sync(b);
++    if (BUF_MEM_grow_clean(bbm->buf, blen + inl) == 0)
++        goto end;
++    memcpy(bbm->buf->data + blen, in, inl);
++    *bbm->readp = *bbm->buf;
++    ret = inl;
++ end:
++    return (ret);
++}
++
++static long mem_ctrl(BIO *b, int cmd, long num, void *ptr)
++{
++    long ret = 1;
++    char **pptr;
++    BIO_BUF_MEM *bbm = (BIO_BUF_MEM *)b->ptr;
++    BUF_MEM *bm;
++
++    switch (cmd) {
++    case BIO_CTRL_RESET:
++        bm = bbm->buf;
++        if (bm->data != NULL) {
++            /* For read only case reset to the start again */
++            if ((b->flags & BIO_FLAGS_MEM_RDONLY) || (b->flags & BIO_FLAGS_NONCLEAR_RST)) {
++                bm->length = bm->max;
++            } else {
++                memset(bm->data, 0, bm->max);
++                bm->length = 0;
++            }
++            *bbm->readp = *bbm->buf;
++        }
++        break;
++    case BIO_CTRL_EOF:
++        bm = bbm->readp;
++        ret = (long)(bm->length == 0);
++        break;
++    case BIO_C_SET_BUF_MEM_EOF_RETURN:
++        b->num = (int)num;
++        break;
++    case BIO_CTRL_INFO:
++        bm = bbm->readp;
++        ret = (long)bm->length;
++        if (ptr != NULL) {
++            pptr = (char **)ptr;
++            *pptr = (char *)&(bm->data[0]);
++        }
++        break;
++    case BIO_C_SET_BUF_MEM:
++        mem_buf_free(b, 0);
++        b->shutdown = (int)num;
++        bbm->buf = ptr;
++        *bbm->readp = *bbm->buf;
++        b->ptr = bbm;
++        break;
++    case BIO_C_GET_BUF_MEM_PTR:
++        if (ptr != NULL) {
++            mem_buf_sync(b);
++            bm = bbm->readp;
++            pptr = (char **)ptr;
++            *pptr = (char *)bm;
++        }
++        break;
++    case BIO_CTRL_GET_CLOSE:
++        ret = (long)b->shutdown;
++        break;
++    case BIO_CTRL_SET_CLOSE:
++        b->shutdown = (int)num;
++        break;
++    case BIO_CTRL_WPENDING:
++        ret = 0L;
++        break;
++    case BIO_CTRL_PENDING:
++        bm = bbm->readp;
++        ret = (long)bm->length;
++        break;
++    case BIO_CTRL_DUP:
++    case BIO_CTRL_FLUSH:
++        ret = 1;
++        break;
++    case BIO_CTRL_PUSH:
++    case BIO_CTRL_POP:
++    default:
++        ret = 0;
++        break;
++    }
++    return (ret);
++}
++
++static int mem_gets(BIO *bp, char *buf, int size)
++{
++    int i, j;
++    int ret = -1;
++    char *p;
++    BIO_BUF_MEM *bbm = (BIO_BUF_MEM *)bp->ptr;
++    BUF_MEM *bm = bbm->readp;
++
++    BIO_clear_retry_flags(bp);
++    j = bm->length;
++    if ((size - 1) < j)
++        j = size - 1;
++    if (j <= 0) {
++        *buf = '\0';
++        return 0;
++    }
++    p = bm->data;
++    for (i = 0; i < j; i++) {
++        if (p[i] == '\n') {
++            i++;
++            break;
++        }
++    }
++
++    /*
++     * i is now the max num of bytes to copy, either j or up to
++     * and including the first newline
++     */
++
++    i = mem_read(bp, buf, i);
++    if (i > 0)
++        buf[i] = '\0';
++    ret = i;
++    return (ret);
++}
++
++static int mem_puts(BIO *bp, const char *str)
++{
++    int n, ret;
++
++    n = strlen(str);
++    ret = mem_write(bp, str, n);
++    /* memory semantics is that it will always work */
++    return (ret);
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/bio/bss_null.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/bio/bss_null.c
+new file mode 100644
+index 0000000..e5c4adc
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/bio/bss_null.c
+@@ -0,0 +1,100 @@
++/*
++ * Copyright 1995-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include 
++#include "bio_lcl.h"
++#include "internal/cryptlib.h"
++
++static int null_write(BIO *h, const char *buf, int num);
++static int null_read(BIO *h, char *buf, int size);
++static int null_puts(BIO *h, const char *str);
++static int null_gets(BIO *h, char *str, int size);
++static long null_ctrl(BIO *h, int cmd, long arg1, void *arg2);
++static int null_new(BIO *h);
++static int null_free(BIO *data);
++static const BIO_METHOD null_method = {
++    BIO_TYPE_NULL,
++    "NULL",
++    null_write,
++    null_read,
++    null_puts,
++    null_gets,
++    null_ctrl,
++    null_new,
++    null_free,
++    NULL,
++};
++
++const BIO_METHOD *BIO_s_null(void)
++{
++    return (&null_method);
++}
++
++static int null_new(BIO *bi)
++{
++    bi->init = 1;
++    bi->num = 0;
++    bi->ptr = (NULL);
++    return (1);
++}
++
++static int null_free(BIO *a)
++{
++    if (a == NULL)
++        return (0);
++    return (1);
++}
++
++static int null_read(BIO *b, char *out, int outl)
++{
++    return (0);
++}
++
++static int null_write(BIO *b, const char *in, int inl)
++{
++    return (inl);
++}
++
++static long null_ctrl(BIO *b, int cmd, long num, void *ptr)
++{
++    long ret = 1;
++
++    switch (cmd) {
++    case BIO_CTRL_RESET:
++    case BIO_CTRL_EOF:
++    case BIO_CTRL_SET:
++    case BIO_CTRL_SET_CLOSE:
++    case BIO_CTRL_FLUSH:
++    case BIO_CTRL_DUP:
++        ret = 1;
++        break;
++    case BIO_CTRL_GET_CLOSE:
++    case BIO_CTRL_INFO:
++    case BIO_CTRL_GET:
++    case BIO_CTRL_PENDING:
++    case BIO_CTRL_WPENDING:
++    default:
++        ret = 0;
++        break;
++    }
++    return (ret);
++}
++
++static int null_gets(BIO *bp, char *buf, int size)
++{
++    return (0);
++}
++
++static int null_puts(BIO *bp, const char *str)
++{
++    if (str == NULL)
++        return (0);
++    return (strlen(str));
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/bio/bss_sock.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/bio/bss_sock.c
+new file mode 100644
+index 0000000..570e898
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/bio/bss_sock.c
+@@ -0,0 +1,231 @@
++/*
++ * Copyright 1995-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include 
++#define USE_SOCKETS
++#include "bio_lcl.h"
++#include "internal/cryptlib.h"
++
++#ifndef OPENSSL_NO_SOCK
++
++# include 
++
++# ifdef WATT32
++/* Watt-32 uses same names */
++#  undef sock_write
++#  undef sock_read
++#  undef sock_puts
++#  define sock_write SockWrite
++#  define sock_read  SockRead
++#  define sock_puts  SockPuts
++# endif
++
++static int sock_write(BIO *h, const char *buf, int num);
++static int sock_read(BIO *h, char *buf, int size);
++static int sock_puts(BIO *h, const char *str);
++static long sock_ctrl(BIO *h, int cmd, long arg1, void *arg2);
++static int sock_new(BIO *h);
++static int sock_free(BIO *data);
++int BIO_sock_should_retry(int s);
++
++static const BIO_METHOD methods_sockp = {
++    BIO_TYPE_SOCKET,
++    "socket",
++    sock_write,
++    sock_read,
++    sock_puts,
++    NULL,                       /* sock_gets, */
++    sock_ctrl,
++    sock_new,
++    sock_free,
++    NULL,
++};
++
++const BIO_METHOD *BIO_s_socket(void)
++{
++    return (&methods_sockp);
++}
++
++BIO *BIO_new_socket(int fd, int close_flag)
++{
++    BIO *ret;
++
++    ret = BIO_new(BIO_s_socket());
++    if (ret == NULL)
++        return (NULL);
++    BIO_set_fd(ret, fd, close_flag);
++    return (ret);
++}
++
++static int sock_new(BIO *bi)
++{
++    bi->init = 0;
++    bi->num = 0;
++    bi->ptr = NULL;
++    bi->flags = 0;
++    return (1);
++}
++
++static int sock_free(BIO *a)
++{
++    if (a == NULL)
++        return (0);
++    if (a->shutdown) {
++        if (a->init) {
++            BIO_closesocket(a->num);
++        }
++        a->init = 0;
++        a->flags = 0;
++    }
++    return (1);
++}
++
++static int sock_read(BIO *b, char *out, int outl)
++{
++    int ret = 0;
++
++    if (out != NULL) {
++        clear_socket_error();
++        ret = readsocket(b->num, out, outl);
++        BIO_clear_retry_flags(b);
++        if (ret <= 0) {
++            if (BIO_sock_should_retry(ret))
++                BIO_set_retry_read(b);
++        }
++    }
++    return (ret);
++}
++
++static int sock_write(BIO *b, const char *in, int inl)
++{
++    int ret;
++
++    clear_socket_error();
++    ret = writesocket(b->num, in, inl);
++    BIO_clear_retry_flags(b);
++    if (ret <= 0) {
++        if (BIO_sock_should_retry(ret))
++            BIO_set_retry_write(b);
++    }
++    return (ret);
++}
++
++static long sock_ctrl(BIO *b, int cmd, long num, void *ptr)
++{
++    long ret = 1;
++    int *ip;
++
++    switch (cmd) {
++    case BIO_C_SET_FD:
++        sock_free(b);
++        b->num = *((int *)ptr);
++        b->shutdown = (int)num;
++        b->init = 1;
++        break;
++    case BIO_C_GET_FD:
++        if (b->init) {
++            ip = (int *)ptr;
++            if (ip != NULL)
++                *ip = b->num;
++            ret = b->num;
++        } else
++            ret = -1;
++        break;
++    case BIO_CTRL_GET_CLOSE:
++        ret = b->shutdown;
++        break;
++    case BIO_CTRL_SET_CLOSE:
++        b->shutdown = (int)num;
++        break;
++    case BIO_CTRL_DUP:
++    case BIO_CTRL_FLUSH:
++        ret = 1;
++        break;
++    default:
++        ret = 0;
++        break;
++    }
++    return (ret);
++}
++
++static int sock_puts(BIO *bp, const char *str)
++{
++    int n, ret;
++
++    n = strlen(str);
++    ret = sock_write(bp, str, n);
++    return (ret);
++}
++
++int BIO_sock_should_retry(int i)
++{
++    int err;
++
++    if ((i == 0) || (i == -1)) {
++        err = get_last_socket_error();
++
++        return (BIO_sock_non_fatal_error(err));
++    }
++    return (0);
++}
++
++int BIO_sock_non_fatal_error(int err)
++{
++    switch (err) {
++# if defined(OPENSSL_SYS_WINDOWS)
++#  if defined(WSAEWOULDBLOCK)
++    case WSAEWOULDBLOCK:
++#  endif
++# endif
++
++# ifdef EWOULDBLOCK
++#  ifdef WSAEWOULDBLOCK
++#   if WSAEWOULDBLOCK != EWOULDBLOCK
++    case EWOULDBLOCK:
++#   endif
++#  else
++    case EWOULDBLOCK:
++#  endif
++# endif
++
++# if defined(ENOTCONN)
++    case ENOTCONN:
++# endif
++
++# ifdef EINTR
++    case EINTR:
++# endif
++
++# ifdef EAGAIN
++#  if EWOULDBLOCK != EAGAIN
++    case EAGAIN:
++#  endif
++# endif
++
++# ifdef EPROTO
++    case EPROTO:
++# endif
++
++# ifdef EINPROGRESS
++    case EINPROGRESS:
++# endif
++
++# ifdef EALREADY
++    case EALREADY:
++# endif
++        return (1);
++        /* break; */
++    default:
++        break;
++    }
++    return (0);
++}
++
++#endif                          /* #ifndef OPENSSL_NO_SOCK */
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/bio/build.info b/CryptoPkg/Library/OpensslLib/openssl/crypto/bio/build.info
+new file mode 100644
+index 0000000..d1e7d73
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/bio/build.info
+@@ -0,0 +1,8 @@
++LIBS=../../libcrypto
++SOURCE[../../libcrypto]=\
++        bio_lib.c bio_cb.c bio_err.c \
++        bss_mem.c bss_null.c bss_fd.c \
++        bss_file.c bss_sock.c bss_conn.c \
++        bf_null.c bf_buff.c b_print.c b_dump.c b_addr.c \
++        b_sock.c b_sock2.c bss_acpt.c bf_nbio.c bss_log.c bss_bio.c \
++        bss_dgram.c bio_meth.c bf_lbuf.c
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/blake2/blake2_impl.h b/CryptoPkg/Library/OpensslLib/openssl/crypto/blake2/blake2_impl.h
+new file mode 100644
+index 0000000..8fe5c95
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/blake2/blake2_impl.h
+@@ -0,0 +1,130 @@
++/*
++ * Copyright 2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++/*
++ * Derived from the BLAKE2 reference implementation written by Samuel Neves.
++ * Copyright 2012, Samuel Neves 
++ * More information about the BLAKE2 hash function and its implementations
++ * can be found at https://blake2.net.
++ */
++
++#include 
++#include "e_os.h"
++
++static ossl_inline uint32_t load32(const uint8_t *src)
++{
++    const union {
++        long one;
++        char little;
++    } is_endian = { 1 };
++
++    if (is_endian.little) {
++        uint32_t w;
++        memcpy(&w, src, sizeof(w));
++        return w;
++    } else {
++        uint32_t w = ((uint32_t)src[0])
++                   | ((uint32_t)src[1] <<  8)
++                   | ((uint32_t)src[2] << 16)
++                   | ((uint32_t)src[3] << 24);
++        return w;
++    }
++}
++
++static ossl_inline uint64_t load64(const uint8_t *src)
++{
++    const union {
++        long one;
++        char little;
++    } is_endian = { 1 };
++
++    if (is_endian.little) {
++        uint64_t w;
++        memcpy(&w, src, sizeof(w));
++        return w;
++    } else {
++        uint64_t w = ((uint64_t)src[0])
++                   | ((uint64_t)src[1] <<  8)
++                   | ((uint64_t)src[2] << 16)
++                   | ((uint64_t)src[3] << 24)
++                   | ((uint64_t)src[4] << 32)
++                   | ((uint64_t)src[5] << 40)
++                   | ((uint64_t)src[6] << 48)
++                   | ((uint64_t)src[7] << 56);
++        return w;
++    }
++}
++
++static ossl_inline void store32(uint8_t *dst, uint32_t w)
++{
++    const union {
++        long one;
++        char little;
++    } is_endian = { 1 };
++
++    if (is_endian.little) {
++        memcpy(dst, &w, sizeof(w));
++    } else {
++        uint8_t *p = (uint8_t *)dst;
++        int i;
++
++        for (i = 0; i < 4; i++)
++            p[i] = (uint8_t)(w >> (8 * i));
++    }
++}
++
++static ossl_inline void store64(uint8_t *dst, uint64_t w)
++{
++    const union {
++        long one;
++        char little;
++    } is_endian = { 1 };
++
++    if (is_endian.little) {
++        memcpy(dst, &w, sizeof(w));
++    } else {
++        uint8_t *p = (uint8_t *)dst;
++        int i;
++
++        for (i = 0; i < 8; i++)
++            p[i] = (uint8_t)(w >> (8 * i));
++    }
++}
++
++static ossl_inline uint64_t load48(const uint8_t *src)
++{
++    uint64_t w = ((uint64_t)src[0])
++               | ((uint64_t)src[1] <<  8)
++               | ((uint64_t)src[2] << 16)
++               | ((uint64_t)src[3] << 24)
++               | ((uint64_t)src[4] << 32)
++               | ((uint64_t)src[5] << 40);
++    return w;
++}
++
++static ossl_inline void store48(uint8_t *dst, uint64_t w)
++{
++    uint8_t *p = (uint8_t *)dst;
++    p[0] = (uint8_t)w;
++    p[1] = (uint8_t)(w>>8);
++    p[2] = (uint8_t)(w>>16);
++    p[3] = (uint8_t)(w>>24);
++    p[4] = (uint8_t)(w>>32);
++    p[5] = (uint8_t)(w>>40);
++}
++
++static ossl_inline uint32_t rotr32(const uint32_t w, const unsigned int c)
++{
++    return (w >> c) | (w << (32 - c));
++}
++
++static ossl_inline uint64_t rotr64(const uint64_t w, const unsigned int c)
++{
++    return (w >> c) | (w << (64 - c));
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/blake2/blake2_locl.h b/CryptoPkg/Library/OpensslLib/openssl/crypto/blake2/blake2_locl.h
+new file mode 100644
+index 0000000..fb7beb9
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/blake2/blake2_locl.h
+@@ -0,0 +1,91 @@
++/*
++ * Copyright 2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++/*
++ * Derived from the BLAKE2 reference implementation written by Samuel Neves.
++ * Copyright 2012, Samuel Neves 
++ * More information about the BLAKE2 hash function and its implementations
++ * can be found at https://blake2.net.
++ */
++
++#include 
++#include "e_os.h"
++
++#define BLAKE2S_BLOCKBYTES    64
++#define BLAKE2S_OUTBYTES      32
++#define BLAKE2S_KEYBYTES      32
++#define BLAKE2S_SALTBYTES     8
++#define BLAKE2S_PERSONALBYTES 8
++
++#define BLAKE2B_BLOCKBYTES    128
++#define BLAKE2B_OUTBYTES      64
++#define BLAKE2B_KEYBYTES      64
++#define BLAKE2B_SALTBYTES     16
++#define BLAKE2B_PERSONALBYTES 16
++
++struct blake2s_param_st {
++    uint8_t  digest_length; /* 1 */
++    uint8_t  key_length;    /* 2 */
++    uint8_t  fanout;        /* 3 */
++    uint8_t  depth;         /* 4 */
++    uint8_t  leaf_length[4];/* 8 */
++    uint8_t  node_offset[6];/* 14 */
++    uint8_t  node_depth;    /* 15 */
++    uint8_t  inner_length;  /* 16 */
++    uint8_t  salt[BLAKE2S_SALTBYTES]; /* 24 */
++    uint8_t  personal[BLAKE2S_PERSONALBYTES];  /* 32 */
++};
++
++typedef struct blake2s_param_st BLAKE2S_PARAM;
++
++struct blake2s_ctx_st {
++    uint32_t h[8];
++    uint32_t t[2];
++    uint32_t f[2];
++    uint8_t  buf[BLAKE2S_BLOCKBYTES];
++    size_t   buflen;
++};
++
++struct blake2b_param_st {
++    uint8_t  digest_length; /* 1 */
++    uint8_t  key_length;    /* 2 */
++    uint8_t  fanout;        /* 3 */
++    uint8_t  depth;         /* 4 */
++    uint8_t  leaf_length[4];/* 8 */
++    uint8_t  node_offset[8];/* 16 */
++    uint8_t  node_depth;    /* 17 */
++    uint8_t  inner_length;  /* 18 */
++    uint8_t  reserved[14];  /* 32 */
++    uint8_t  salt[BLAKE2B_SALTBYTES]; /* 48 */
++    uint8_t  personal[BLAKE2B_PERSONALBYTES];  /* 64 */
++};
++
++typedef struct blake2b_param_st BLAKE2B_PARAM;
++
++struct blake2b_ctx_st {
++    uint64_t h[8];
++    uint64_t t[2];
++    uint64_t f[2];
++    uint8_t  buf[BLAKE2B_BLOCKBYTES];
++    size_t   buflen;
++};
++
++#define BLAKE2B_DIGEST_LENGTH 64
++#define BLAKE2S_DIGEST_LENGTH 32
++
++typedef struct blake2s_ctx_st BLAKE2S_CTX;
++typedef struct blake2b_ctx_st BLAKE2B_CTX;
++
++int BLAKE2b_Init(BLAKE2B_CTX *c);
++int BLAKE2b_Update(BLAKE2B_CTX *c, const void *data, size_t datalen);
++int BLAKE2b_Final(unsigned char *md, BLAKE2B_CTX *c);
++
++int BLAKE2s_Init(BLAKE2S_CTX *c);
++int BLAKE2s_Update(BLAKE2S_CTX *c, const void *data, size_t datalen);
++int BLAKE2s_Final(unsigned char *md, BLAKE2S_CTX *c);
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/blake2/blake2b.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/blake2/blake2b.c
+new file mode 100644
+index 0000000..e77bd9a
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/blake2/blake2b.c
+@@ -0,0 +1,270 @@
++/*
++ * Copyright 2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++/*
++ * Derived from the BLAKE2 reference implementation written by Samuel Neves.
++ * Copyright 2012, Samuel Neves 
++ * More information about the BLAKE2 hash function and its implementations
++ * can be found at https://blake2.net.
++ */
++
++#include 
++#include 
++#include 
++#include "e_os.h"
++
++#include "blake2_locl.h"
++#include "blake2_impl.h"
++
++static const uint64_t blake2b_IV[8] =
++{
++    0x6a09e667f3bcc908U, 0xbb67ae8584caa73bU,
++    0x3c6ef372fe94f82bU, 0xa54ff53a5f1d36f1U,
++    0x510e527fade682d1U, 0x9b05688c2b3e6c1fU,
++    0x1f83d9abfb41bd6bU, 0x5be0cd19137e2179U
++};
++
++static const uint8_t blake2b_sigma[12][16] =
++{
++    {  0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14, 15 } ,
++    { 14, 10,  4,  8,  9, 15, 13,  6,  1, 12,  0,  2, 11,  7,  5,  3 } ,
++    { 11,  8, 12,  0,  5,  2, 15, 13, 10, 14,  3,  6,  7,  1,  9,  4 } ,
++    {  7,  9,  3,  1, 13, 12, 11, 14,  2,  6,  5, 10,  4,  0, 15,  8 } ,
++    {  9,  0,  5,  7,  2,  4, 10, 15, 14,  1, 11, 12,  6,  8,  3, 13 } ,
++    {  2, 12,  6, 10,  0, 11,  8,  3,  4, 13,  7,  5, 15, 14,  1,  9 } ,
++    { 12,  5,  1, 15, 14, 13,  4, 10,  0,  7,  6,  3,  9,  2,  8, 11 } ,
++    { 13, 11,  7, 14, 12,  1,  3,  9,  5,  0, 15,  4,  8,  6,  2, 10 } ,
++    {  6, 15, 14,  9, 11,  3,  0,  8, 12,  2, 13,  7,  1,  4, 10,  5 } ,
++    { 10,  2,  8,  4,  7,  6,  1,  5, 15, 11,  9, 14,  3, 12, 13 , 0 } ,
++    {  0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14, 15 } ,
++    { 14, 10,  4,  8,  9, 15, 13,  6,  1, 12,  0,  2, 11,  7,  5,  3 }
++};
++
++/* Set that it's the last block we'll compress */
++static ossl_inline void blake2b_set_lastblock(BLAKE2B_CTX *S)
++{
++    S->f[0] = -1;
++}
++
++/* Initialize the hashing state. */
++static ossl_inline void blake2b_init0(BLAKE2B_CTX *S)
++{
++    int i;
++
++    memset(S, 0, sizeof(BLAKE2B_CTX));
++    for (i = 0; i < 8; ++i) {
++        S->h[i] = blake2b_IV[i];
++    }
++}
++
++/* init xors IV with input parameter block */
++static void blake2b_init_param(BLAKE2B_CTX *S, const BLAKE2B_PARAM *P)
++{
++    size_t i;
++    const uint8_t *p = (const uint8_t *)(P);
++    blake2b_init0(S);
++
++    /* The param struct is carefully hand packed, and should be 64 bytes on
++     * every platform. */
++    assert(sizeof(BLAKE2B_PARAM) == 64);
++    /* IV XOR ParamBlock */
++    for (i = 0; i < 8; ++i) {
++        S->h[i] ^= load64(p + sizeof(S->h[i]) * i);
++    }
++}
++
++/* Initialize the hashing context.  Always returns 1. */
++int BLAKE2b_Init(BLAKE2B_CTX *c)
++{
++    BLAKE2B_PARAM P[1];
++    P->digest_length = BLAKE2B_DIGEST_LENGTH;
++    P->key_length    = 0;
++    P->fanout        = 1;
++    P->depth         = 1;
++    store32(P->leaf_length, 0);
++    store64(P->node_offset, 0);
++    P->node_depth    = 0;
++    P->inner_length  = 0;
++    memset(P->reserved, 0, sizeof(P->reserved));
++    memset(P->salt,     0, sizeof(P->salt));
++    memset(P->personal, 0, sizeof(P->personal));
++    blake2b_init_param(c, P);
++    return 1;
++}
++
++/* Permute the state while xoring in the block of data. */
++static void blake2b_compress(BLAKE2B_CTX *S,
++                            const uint8_t *blocks,
++                            size_t len)
++{
++    uint64_t m[16];
++    uint64_t v[16];
++    int i;
++    size_t increment;
++
++    /*
++     * There are two distinct usage vectors for this function:
++     *
++     * a) BLAKE2b_Update uses it to process complete blocks,
++     *    possibly more than one at a time;
++     *
++     * b) BLAK2b_Final uses it to process last block, always
++     *    single but possibly incomplete, in which case caller
++     *    pads input with zeros.
++     */
++    assert(len < BLAKE2B_BLOCKBYTES || len % BLAKE2B_BLOCKBYTES == 0);
++
++    /*
++     * Since last block is always processed with separate call,
++     * |len| not being multiple of complete blocks can be observed
++     * only with |len| being less than BLAKE2B_BLOCKBYTES ("less"
++     * including even zero), which is why following assignment doesn't
++     * have to reside inside the main loop below.
++     */
++    increment = len < BLAKE2B_BLOCKBYTES ? len : BLAKE2B_BLOCKBYTES;
++
++    for (i = 0; i < 8; ++i) {
++        v[i] = S->h[i];
++    }
++
++    do {
++        for (i = 0; i < 16; ++i) {
++            m[i] = load64(blocks + i * sizeof(m[i]));
++        }
++
++        /* blake2b_increment_counter */
++        S->t[0] += increment;
++        S->t[1] += (S->t[0] < increment);
++
++        v[8]  = blake2b_IV[0];
++        v[9]  = blake2b_IV[1];
++        v[10] = blake2b_IV[2];
++        v[11] = blake2b_IV[3];
++        v[12] = S->t[0] ^ blake2b_IV[4];
++        v[13] = S->t[1] ^ blake2b_IV[5];
++        v[14] = S->f[0] ^ blake2b_IV[6];
++        v[15] = S->f[1] ^ blake2b_IV[7];
++#define G(r,i,a,b,c,d) \
++        do { \
++            a = a + b + m[blake2b_sigma[r][2*i+0]]; \
++            d = rotr64(d ^ a, 32); \
++            c = c + d; \
++            b = rotr64(b ^ c, 24); \
++            a = a + b + m[blake2b_sigma[r][2*i+1]]; \
++            d = rotr64(d ^ a, 16); \
++            c = c + d; \
++            b = rotr64(b ^ c, 63); \
++        } while (0)
++#define ROUND(r)  \
++        do { \
++            G(r,0,v[ 0],v[ 4],v[ 8],v[12]); \
++            G(r,1,v[ 1],v[ 5],v[ 9],v[13]); \
++            G(r,2,v[ 2],v[ 6],v[10],v[14]); \
++            G(r,3,v[ 3],v[ 7],v[11],v[15]); \
++            G(r,4,v[ 0],v[ 5],v[10],v[15]); \
++            G(r,5,v[ 1],v[ 6],v[11],v[12]); \
++            G(r,6,v[ 2],v[ 7],v[ 8],v[13]); \
++            G(r,7,v[ 3],v[ 4],v[ 9],v[14]); \
++        } while (0)
++#if defined(OPENSSL_SMALL_FOOTPRINT)
++        /* 3x size reduction on x86_64, almost 7x on ARMv8, 9x on ARMv4 */
++        for (i = 0; i < 12; i++) {
++            ROUND(i);
++        }
++#else
++        ROUND(0);
++        ROUND(1);
++        ROUND(2);
++        ROUND(3);
++        ROUND(4);
++        ROUND(5);
++        ROUND(6);
++        ROUND(7);
++        ROUND(8);
++        ROUND(9);
++        ROUND(10);
++        ROUND(11);
++#endif
++
++        for (i = 0; i < 8; ++i) {
++            S->h[i] = v[i] ^= v[i + 8] ^ S->h[i];
++        }
++#undef G
++#undef ROUND
++        blocks += increment;
++        len -= increment;
++    } while (len);
++}
++
++/* Absorb the input data into the hash state.  Always returns 1. */
++int BLAKE2b_Update(BLAKE2B_CTX *c, const void *data, size_t datalen)
++{
++    const uint8_t *in = data;
++    size_t fill;
++
++    /*
++     * Intuitively one would expect intermediate buffer, c->buf, to
++     * store incomplete blocks. But in this case we are interested to
++     * temporarily stash even complete blocks, because last one in the
++     * stream has to be treated in special way, and at this point we
++     * don't know if last block in *this* call is last one "ever". This
++     * is the reason for why |datalen| is compared as >, and not >=.
++     */
++    fill = sizeof(c->buf) - c->buflen;
++    if (datalen > fill) {
++        if (c->buflen) {
++            memcpy(c->buf + c->buflen, in, fill); /* Fill buffer */
++            blake2b_compress(c, c->buf, BLAKE2B_BLOCKBYTES);
++            c->buflen = 0;
++            in += fill;
++            datalen -= fill;
++        }
++        if (datalen > BLAKE2B_BLOCKBYTES) {
++            size_t stashlen = datalen % BLAKE2B_BLOCKBYTES;
++            /*
++             * If |datalen| is a multiple of the blocksize, stash
++             * last complete block, it can be final one...
++             */
++            stashlen = stashlen ? stashlen : BLAKE2B_BLOCKBYTES;
++            datalen -= stashlen;
++            blake2b_compress(c, in, datalen);
++            in += datalen;
++            datalen = stashlen;
++        }
++    }
++
++    assert(datalen <= BLAKE2B_BLOCKBYTES);
++
++    memcpy(c->buf + c->buflen, in, datalen);
++    c->buflen += datalen; /* Be lazy, do not compress */
++
++    return 1;
++}
++
++/*
++ * Calculate the final hash and save it in md.
++ * Always returns 1.
++ */
++int BLAKE2b_Final(unsigned char *md, BLAKE2B_CTX *c)
++{
++    int i;
++
++    blake2b_set_lastblock(c);
++    /* Padding */
++    memset(c->buf + c->buflen, 0, sizeof(c->buf) - c->buflen);
++    blake2b_compress(c, c->buf, c->buflen);
++
++    /* Output full hash to message digest */
++    for (i = 0; i < 8; ++i) {
++        store64(md + sizeof(c->h[i]) * i, c->h[i]);
++    }
++
++    OPENSSL_cleanse(c, sizeof(BLAKE2B_CTX));
++    return 1;
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/blake2/blake2s.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/blake2/blake2s.c
+new file mode 100644
+index 0000000..0b3503e
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/blake2/blake2s.c
+@@ -0,0 +1,264 @@
++/*
++ * Copyright 2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++/*
++ * Derived from the BLAKE2 reference implementation written by Samuel Neves.
++ * Copyright 2012, Samuel Neves 
++ * More information about the BLAKE2 hash function and its implementations
++ * can be found at https://blake2.net.
++ */
++
++#include 
++#include 
++#include 
++#include "e_os.h"
++
++#include "blake2_locl.h"
++#include "blake2_impl.h"
++
++static const uint32_t blake2s_IV[8] =
++{
++    0x6A09E667U, 0xBB67AE85U, 0x3C6EF372U, 0xA54FF53AU,
++    0x510E527FU, 0x9B05688CU, 0x1F83D9ABU, 0x5BE0CD19U
++};
++
++static const uint8_t blake2s_sigma[10][16] =
++{
++    {  0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14, 15 } ,
++    { 14, 10,  4,  8,  9, 15, 13,  6,  1, 12,  0,  2, 11,  7,  5,  3 } ,
++    { 11,  8, 12,  0,  5,  2, 15, 13, 10, 14,  3,  6,  7,  1,  9,  4 } ,
++    {  7,  9,  3,  1, 13, 12, 11, 14,  2,  6,  5, 10,  4,  0, 15,  8 } ,
++    {  9,  0,  5,  7,  2,  4, 10, 15, 14,  1, 11, 12,  6,  8,  3, 13 } ,
++    {  2, 12,  6, 10,  0, 11,  8,  3,  4, 13,  7,  5, 15, 14,  1,  9 } ,
++    { 12,  5,  1, 15, 14, 13,  4, 10,  0,  7,  6,  3,  9,  2,  8, 11 } ,
++    { 13, 11,  7, 14, 12,  1,  3,  9,  5,  0, 15,  4,  8,  6,  2, 10 } ,
++    {  6, 15, 14,  9, 11,  3,  0,  8, 12,  2, 13,  7,  1,  4, 10,  5 } ,
++    { 10,  2,  8,  4,  7,  6,  1,  5, 15, 11,  9, 14,  3, 12, 13 , 0 } ,
++};
++
++/* Set that it's the last block we'll compress */
++static ossl_inline void blake2s_set_lastblock(BLAKE2S_CTX *S)
++{
++    S->f[0] = -1;
++}
++
++/* Initialize the hashing state. */
++static ossl_inline void blake2s_init0(BLAKE2S_CTX *S)
++{
++    int i;
++
++    memset(S, 0, sizeof(BLAKE2S_CTX));
++    for (i = 0; i < 8; ++i) {
++        S->h[i] = blake2s_IV[i];
++    }
++}
++
++/* init2 xors IV with input parameter block */
++static void blake2s_init_param(BLAKE2S_CTX *S, const BLAKE2S_PARAM *P)
++{
++    const uint8_t *p = (const uint8_t *)(P);
++    size_t i;
++
++    /* The param struct is carefully hand packed, and should be 32 bytes on
++     * every platform. */
++    assert(sizeof(BLAKE2S_PARAM) == 32);
++    blake2s_init0(S);
++    /* IV XOR ParamBlock */
++    for (i = 0; i < 8; ++i) {
++        S->h[i] ^= load32(&p[i*4]);
++    }
++}
++
++/* Initialize the hashing context.  Always returns 1. */
++int BLAKE2s_Init(BLAKE2S_CTX *c)
++{
++    BLAKE2S_PARAM P[1];
++
++    P->digest_length = BLAKE2S_DIGEST_LENGTH;
++    P->key_length    = 0;
++    P->fanout        = 1;
++    P->depth         = 1;
++    store32(P->leaf_length, 0);
++    store48(P->node_offset, 0);
++    P->node_depth    = 0;
++    P->inner_length  = 0;
++    memset(P->salt,     0, sizeof(P->salt));
++    memset(P->personal, 0, sizeof(P->personal));
++    blake2s_init_param(c, P);
++    return 1;
++}
++
++/* Permute the state while xoring in the block of data. */
++static void blake2s_compress(BLAKE2S_CTX *S,
++                            const uint8_t *blocks,
++                            size_t len)
++{
++    uint32_t m[16];
++    uint32_t v[16];
++    size_t i;
++    size_t increment;
++
++    /*
++     * There are two distinct usage vectors for this function:
++     *
++     * a) BLAKE2s_Update uses it to process complete blocks,
++     *    possibly more than one at a time;
++     *
++     * b) BLAK2s_Final uses it to process last block, always
++     *    single but possibly incomplete, in which case caller
++     *    pads input with zeros.
++     */
++    assert(len < BLAKE2S_BLOCKBYTES || len % BLAKE2S_BLOCKBYTES == 0);
++
++    /*
++     * Since last block is always processed with separate call,
++     * |len| not being multiple of complete blocks can be observed
++     * only with |len| being less than BLAKE2S_BLOCKBYTES ("less"
++     * including even zero), which is why following assignment doesn't
++     * have to reside inside the main loop below.
++     */
++    increment = len < BLAKE2S_BLOCKBYTES ? len : BLAKE2S_BLOCKBYTES;
++
++    for (i = 0; i < 8; ++i) {
++        v[i] = S->h[i];
++    }
++
++    do {
++        for (i = 0; i < 16; ++i) {
++            m[i] = load32(blocks + i * sizeof(m[i]));
++        }
++
++        /* blake2s_increment_counter */
++        S->t[0] += increment;
++        S->t[1] += (S->t[0] < increment);
++
++        v[ 8] = blake2s_IV[0];
++        v[ 9] = blake2s_IV[1];
++        v[10] = blake2s_IV[2];
++        v[11] = blake2s_IV[3];
++        v[12] = S->t[0] ^ blake2s_IV[4];
++        v[13] = S->t[1] ^ blake2s_IV[5];
++        v[14] = S->f[0] ^ blake2s_IV[6];
++        v[15] = S->f[1] ^ blake2s_IV[7];
++#define G(r,i,a,b,c,d) \
++        do { \
++            a = a + b + m[blake2s_sigma[r][2*i+0]]; \
++            d = rotr32(d ^ a, 16); \
++            c = c + d; \
++            b = rotr32(b ^ c, 12); \
++            a = a + b + m[blake2s_sigma[r][2*i+1]]; \
++            d = rotr32(d ^ a, 8); \
++            c = c + d; \
++            b = rotr32(b ^ c, 7); \
++        } while (0)
++#define ROUND(r)  \
++        do { \
++            G(r,0,v[ 0],v[ 4],v[ 8],v[12]); \
++            G(r,1,v[ 1],v[ 5],v[ 9],v[13]); \
++            G(r,2,v[ 2],v[ 6],v[10],v[14]); \
++            G(r,3,v[ 3],v[ 7],v[11],v[15]); \
++            G(r,4,v[ 0],v[ 5],v[10],v[15]); \
++            G(r,5,v[ 1],v[ 6],v[11],v[12]); \
++            G(r,6,v[ 2],v[ 7],v[ 8],v[13]); \
++            G(r,7,v[ 3],v[ 4],v[ 9],v[14]); \
++        } while (0)
++#if defined(OPENSSL_SMALL_FOOTPRINT)
++        /* almost 3x reduction on x86_64, 4.5x on ARMv8, 4x on ARMv4 */
++        for (i = 0; i < 10; i++) {
++            ROUND(i);
++        }
++#else
++        ROUND(0);
++        ROUND(1);
++        ROUND(2);
++        ROUND(3);
++        ROUND(4);
++        ROUND(5);
++        ROUND(6);
++        ROUND(7);
++        ROUND(8);
++        ROUND(9);
++#endif
++
++        for (i = 0; i < 8; ++i) {
++            S->h[i] = v[i] ^= v[i + 8] ^ S->h[i];
++        }
++#undef G
++#undef ROUND
++        blocks += increment;
++        len -= increment;
++    } while (len);
++}
++
++/* Absorb the input data into the hash state.  Always returns 1. */
++int BLAKE2s_Update(BLAKE2S_CTX *c, const void *data, size_t datalen)
++{
++    const uint8_t *in = data;
++    size_t fill;
++
++    /*
++     * Intuitively one would expect intermediate buffer, c->buf, to
++     * store incomplete blocks. But in this case we are interested to
++     * temporarily stash even complete blocks, because last one in the
++     * stream has to be treated in special way, and at this point we
++     * don't know if last block in *this* call is last one "ever". This
++     * is the reason for why |datalen| is compared as >, and not >=.
++     */
++    fill = sizeof(c->buf) - c->buflen;
++    if (datalen > fill) {
++        if (c->buflen) {
++            memcpy(c->buf + c->buflen, in, fill); /* Fill buffer */
++            blake2s_compress(c, c->buf, BLAKE2S_BLOCKBYTES);
++            c->buflen = 0;
++            in += fill;
++            datalen -= fill;
++        }
++        if (datalen > BLAKE2S_BLOCKBYTES)  {
++            size_t stashlen = datalen % BLAKE2S_BLOCKBYTES;
++            /*
++             * If |datalen| is a multiple of the blocksize, stash
++             * last complete block, it can be final one...
++             */
++            stashlen = stashlen ? stashlen : BLAKE2S_BLOCKBYTES;
++            datalen -= stashlen;
++            blake2s_compress(c, in, datalen);
++            in += datalen;
++            datalen = stashlen;
++        }
++    }
++
++    assert(datalen <= BLAKE2S_BLOCKBYTES);
++
++    memcpy(c->buf + c->buflen, in, datalen);
++    c->buflen += datalen; /* Be lazy, do not compress */
++
++    return 1;
++}
++
++/*
++ * Calculate the final hash and save it in md.
++ * Always returns 1.
++ */
++int BLAKE2s_Final(unsigned char *md, BLAKE2S_CTX *c)
++{
++    int i;
++
++    blake2s_set_lastblock(c);
++    /* Padding */
++    memset(c->buf + c->buflen, 0, sizeof(c->buf) - c->buflen);
++    blake2s_compress(c, c->buf, c->buflen);
++
++    /* Output full hash to temp buffer */
++    for (i = 0; i < 8; ++i) {
++        store32(md + sizeof(c->h[i]) * i, c->h[i]);
++    }
++
++    OPENSSL_cleanse(c, sizeof(BLAKE2S_CTX));
++    return 1;
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/blake2/build.info b/CryptoPkg/Library/OpensslLib/openssl/crypto/blake2/build.info
+new file mode 100644
+index 0000000..0036f08
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/blake2/build.info
+@@ -0,0 +1,3 @@
++LIBS=../../libcrypto
++SOURCE[../../libcrypto]=\
++        blake2b.c blake2s.c m_blake2b.c m_blake2s.c
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/blake2/m_blake2b.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/blake2/m_blake2b.c
+new file mode 100644
+index 0000000..82c6f6b
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/blake2/m_blake2b.c
+@@ -0,0 +1,59 @@
++/*
++ * Copyright 2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++/*
++ * Derived from the BLAKE2 reference implementation written by Samuel Neves.
++ * Copyright 2012, Samuel Neves 
++ * More information about the BLAKE2 hash function and its implementations
++ * can be found at https://blake2.net.
++ */
++
++#include "internal/cryptlib.h"
++
++#ifndef OPENSSL_NO_BLAKE2
++
++# include 
++# include 
++# include "blake2_locl.h"
++# include "internal/evp_int.h"
++
++static int init(EVP_MD_CTX *ctx)
++{
++    return BLAKE2b_Init(EVP_MD_CTX_md_data(ctx));
++}
++
++static int update(EVP_MD_CTX *ctx, const void *data, size_t count)
++{
++    return BLAKE2b_Update(EVP_MD_CTX_md_data(ctx), data, count);
++}
++
++static int final(EVP_MD_CTX *ctx, unsigned char *md)
++{
++    return BLAKE2b_Final(md, EVP_MD_CTX_md_data(ctx));
++}
++
++static const EVP_MD blake2b_md = {
++    NID_blake2b512,
++    0,
++    BLAKE2B_DIGEST_LENGTH,
++    0,
++    init,
++    update,
++    final,
++    NULL,
++    NULL,
++    BLAKE2B_BLOCKBYTES,
++    sizeof(EVP_MD *) + sizeof(BLAKE2B_CTX),
++};
++
++const EVP_MD *EVP_blake2b512(void)
++{
++    return (&blake2b_md);
++}
++#endif
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/blake2/m_blake2s.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/blake2/m_blake2s.c
+new file mode 100644
+index 0000000..467e91a
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/blake2/m_blake2s.c
+@@ -0,0 +1,59 @@
++/*
++ * Copyright 2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++/*
++ * Derived from the BLAKE2 reference implementation written by Samuel Neves.
++ * Copyright 2012, Samuel Neves 
++ * More information about the BLAKE2 hash function and its implementations
++ * can be found at https://blake2.net.
++ */
++
++#include "internal/cryptlib.h"
++
++#ifndef OPENSSL_NO_BLAKE2
++
++# include 
++# include 
++# include "blake2_locl.h"
++# include "internal/evp_int.h"
++
++static int init(EVP_MD_CTX *ctx)
++{
++    return BLAKE2s_Init(EVP_MD_CTX_md_data(ctx));
++}
++
++static int update(EVP_MD_CTX *ctx, const void *data, size_t count)
++{
++    return BLAKE2s_Update(EVP_MD_CTX_md_data(ctx), data, count);
++}
++
++static int final(EVP_MD_CTX *ctx, unsigned char *md)
++{
++    return BLAKE2s_Final(md, EVP_MD_CTX_md_data(ctx));
++}
++
++static const EVP_MD blake2s_md = {
++    NID_blake2s256,
++    0,
++    BLAKE2S_DIGEST_LENGTH,
++    0,
++    init,
++    update,
++    final,
++    NULL,
++    NULL,
++    BLAKE2S_BLOCKBYTES,
++    sizeof(EVP_MD *) + sizeof(BLAKE2S_CTX),
++};
++
++const EVP_MD *EVP_blake2s256(void)
++{
++    return (&blake2s_md);
++}
++#endif
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/bn/README.pod b/CryptoPkg/Library/OpensslLib/openssl/crypto/bn/README.pod
+new file mode 100644
+index 0000000..109ab0d
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/bn/README.pod
+@@ -0,0 +1,247 @@
++=pod
++
++=head1 NAME
++
++bn_mul_words, bn_mul_add_words, bn_sqr_words, bn_div_words,
++bn_add_words, bn_sub_words, bn_mul_comba4, bn_mul_comba8,
++bn_sqr_comba4, bn_sqr_comba8, bn_cmp_words, bn_mul_normal,
++bn_mul_low_normal, bn_mul_recursive, bn_mul_part_recursive,
++bn_mul_low_recursive, bn_mul_high, bn_sqr_normal, bn_sqr_recursive,
++bn_expand, bn_wexpand, bn_expand2, bn_fix_top, bn_check_top,
++bn_print, bn_dump, bn_set_max, bn_set_high, bn_set_low - BIGNUM
++library internal functions
++
++=head1 SYNOPSIS
++
++ #include 
++
++ BN_ULONG bn_mul_words(BN_ULONG *rp, BN_ULONG *ap, int num, BN_ULONG w);
++ BN_ULONG bn_mul_add_words(BN_ULONG *rp, BN_ULONG *ap, int num,
++   BN_ULONG w);
++ void     bn_sqr_words(BN_ULONG *rp, BN_ULONG *ap, int num);
++ BN_ULONG bn_div_words(BN_ULONG h, BN_ULONG l, BN_ULONG d);
++ BN_ULONG bn_add_words(BN_ULONG *rp, BN_ULONG *ap, BN_ULONG *bp,
++   int num);
++ BN_ULONG bn_sub_words(BN_ULONG *rp, BN_ULONG *ap, BN_ULONG *bp,
++   int num);
++
++ void bn_mul_comba4(BN_ULONG *r, BN_ULONG *a, BN_ULONG *b);
++ void bn_mul_comba8(BN_ULONG *r, BN_ULONG *a, BN_ULONG *b);
++ void bn_sqr_comba4(BN_ULONG *r, BN_ULONG *a);
++ void bn_sqr_comba8(BN_ULONG *r, BN_ULONG *a);
++
++ int bn_cmp_words(BN_ULONG *a, BN_ULONG *b, int n);
++
++ void bn_mul_normal(BN_ULONG *r, BN_ULONG *a, int na, BN_ULONG *b,
++   int nb);
++ void bn_mul_low_normal(BN_ULONG *r, BN_ULONG *a, BN_ULONG *b, int n);
++ void bn_mul_recursive(BN_ULONG *r, BN_ULONG *a, BN_ULONG *b, int n2,
++   int dna, int dnb, BN_ULONG *tmp);
++ void bn_mul_part_recursive(BN_ULONG *r, BN_ULONG *a, BN_ULONG *b,
++   int n, int tna, int tnb, BN_ULONG *tmp);
++ void bn_mul_low_recursive(BN_ULONG *r, BN_ULONG *a, BN_ULONG *b,
++   int n2, BN_ULONG *tmp);
++ void bn_mul_high(BN_ULONG *r, BN_ULONG *a, BN_ULONG *b, BN_ULONG *l,
++   int n2, BN_ULONG *tmp);
++
++ void bn_sqr_normal(BN_ULONG *r, BN_ULONG *a, int n, BN_ULONG *tmp);
++ void bn_sqr_recursive(BN_ULONG *r, BN_ULONG *a, int n2, BN_ULONG *tmp);
++
++ void mul(BN_ULONG r, BN_ULONG a, BN_ULONG w, BN_ULONG c);
++ void mul_add(BN_ULONG r, BN_ULONG a, BN_ULONG w, BN_ULONG c);
++ void sqr(BN_ULONG r0, BN_ULONG r1, BN_ULONG a);
++
++ BIGNUM *bn_expand(BIGNUM *a, int bits);
++ BIGNUM *bn_wexpand(BIGNUM *a, int n);
++ BIGNUM *bn_expand2(BIGNUM *a, int n);
++ void bn_fix_top(BIGNUM *a);
++
++ void bn_check_top(BIGNUM *a);
++ void bn_print(BIGNUM *a);
++ void bn_dump(BN_ULONG *d, int n);
++ void bn_set_max(BIGNUM *a);
++ void bn_set_high(BIGNUM *r, BIGNUM *a, int n);
++ void bn_set_low(BIGNUM *r, BIGNUM *a, int n);
++
++=head1 DESCRIPTION
++
++This page documents the internal functions used by the OpenSSL
++B implementation. They are described here to facilitate
++debugging and extending the library. They are I to be used by
++applications.
++
++=head2 The BIGNUM structure
++
++ typedef struct bignum_st BIGNUM;
++
++ struct bignum_st
++        {
++        BN_ULONG *d;    /* Pointer to an array of 'BN_BITS2' bit chunks. */
++        int top;        /* Index of last used d +1. */
++        /* The next are internal book keeping for bn_expand. */
++        int dmax;       /* Size of the d array. */
++        int neg;        /* one if the number is negative */
++        int flags;
++        };
++
++
++The integer value is stored in B, a malloc()ed array of words (B),
++least significant word first. A B can be either 16, 32 or 64 bits
++in size, depending on the 'number of bits' (B) specified in
++C.
++
++B is the size of the B array that has been allocated.  B
++is the number of words being used, so for a value of 4, bn.d[0]=4 and
++bn.top=1.  B is 1 if the number is negative.  When a B is
++B<0>, the B field can be B and B == B<0>.
++
++B is a bit field of flags which are defined in C. The
++flags begin with B. The macros BN_set_flags(b, n) and
++BN_get_flags(b, n) exist to enable or fetch flag(s) B from B
++structure B.
++
++Various routines in this library require the use of temporary
++B variables during their execution.  Since dynamic memory
++allocation to create Bs is rather expensive when used in
++conjunction with repeated subroutine calls, the B structure is
++used.  This structure contains B Bs, see
++L.
++
++=head2 Low-level arithmetic operations
++
++These functions are implemented in C and for several platforms in
++assembly language:
++
++bn_mul_words(B, B, B, B) operates on the B word
++arrays B and B.  It computes B * B, places the result
++in B, and returns the high word (carry).
++
++bn_mul_add_words(B, B, B, B) operates on the B
++word arrays B and B.  It computes B * B + B, places
++the result in B, and returns the high word (carry).
++
++bn_sqr_words(B, B, B) operates on the B word array
++B and the 2*B word array B.  It computes B * B
++word-wise, and places the low and high bytes of the result in B.
++
++bn_div_words(B, B, B) divides the two word number (B, B)
++by B and returns the result.
++
++bn_add_words(B, B, B, B) operates on the B word
++arrays B, B and B.  It computes B + B, places the
++result in B, and returns the high word (carry).
++
++bn_sub_words(B, B, B, B) operates on the B word
++arrays B, B and B.  It computes B - B, places the
++result in B, and returns the carry (1 if B E B, 0
++otherwise).
++
++bn_mul_comba4(B, B, B) operates on the 4 word arrays B and
++B and the 8 word array B.  It computes B*B and places the
++result in B.
++
++bn_mul_comba8(B, B, B) operates on the 8 word arrays B and
++B and the 16 word array B.  It computes B*B and places the
++result in B.
++
++bn_sqr_comba4(B, B, B) operates on the 4 word arrays B and
++B and the 8 word array B.
++
++bn_sqr_comba8(B, B, B) operates on the 8 word arrays B and
++B and the 16 word array B.
++
++The following functions are implemented in C:
++
++bn_cmp_words(B, B, B) operates on the B word arrays B
++and B.  It returns 1, 0 and -1 if B is greater than, equal and
++less than B.
++
++bn_mul_normal(B, B, B, B, B) operates on the B
++word array B, the B word array B and the B+B word
++array B.  It computes B*B and places the result in B.
++
++bn_mul_low_normal(B, B, B, B) operates on the B word
++arrays B, B and B.  It computes the B low words of
++B*B and places the result in B.
++
++bn_mul_recursive(B, B, B, B, B, B, B) operates
++on the word arrays B and B of length B+B and B+B
++(B and B are currently allowed to be 0 or negative) and the 2*B
++word arrays B and B.  B must be a power of 2.  It computes
++B*B and places the result in B.
++
++bn_mul_part_recursive(B, B, B, B, B, B, B)
++operates on the word arrays B and B of length B+B and
++B+B and the 4*B word arrays B and B.
++
++bn_mul_low_recursive(B, B, B, B, B) operates on the
++B word arrays B and B and the B/2 word arrays B
++and B.
++
++bn_mul_high(B, B, B, B, B, B) operates on the
++B word arrays B, B, B and B (?) and the 3*B word
++array B.
++
++BN_mul() calls bn_mul_normal(), or an optimized implementation if the
++factors have the same size: bn_mul_comba8() is used if they are 8
++words long, bn_mul_recursive() if they are larger than
++B and the size is an exact multiple of the word
++size, and bn_mul_part_recursive() for others that are larger than
++B.
++
++bn_sqr_normal(B, B, B, B) operates on the B word array
++B and the 2*B word arrays B and B.
++
++The implementations use the following macros which, depending on the
++architecture, may use "long long" C operations or inline assembler.
++They are defined in C.
++
++mul(B, B, B, B) computes B*B+B and places the
++low word of the result in B and the high word in B.
++
++mul_add(B, B, B, B) computes B*B+B+B and
++places the low word of the result in B and the high word in B.
++
++sqr(B, B, B) computes B*B and places the low word
++of the result in B and the high word in B.
++
++=head2 Size changes
++
++bn_expand() ensures that B has enough space for a B bit
++number.  bn_wexpand() ensures that B has enough space for an
++B word number.  If the number has to be expanded, both macros
++call bn_expand2(), which allocates a new B array and copies the
++data.  They return B on error, B otherwise.
++
++The bn_fix_top() macro reduces Btop> to point to the most
++significant non-zero word plus one when B has shrunk.
++
++=head2 Debugging
++
++bn_check_top() verifies that C<((a)-Etop E= 0 && (a)-Etop
++E= (a)-Edmax)>.  A violation will cause the program to abort.
++
++bn_print() prints B to stderr. bn_dump() prints B words at B
++(in reverse order, i.e. most significant word first) to stderr.
++
++bn_set_max() makes B a static number with a B of its current size.
++This is used by bn_set_low() and bn_set_high() to make B a read-only
++B that contains the B low or high words of B.
++
++If B is not defined, bn_check_top(), bn_print(), bn_dump()
++and bn_set_max() are defined as empty macros.
++
++=head1 SEE ALSO
++
++L
++
++=head1 COPYRIGHT
++
++Copyright 2000-2016 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
++in the file LICENSE in the source distribution or at
++L.
++
++=cut
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/bn/asm/alpha-mont.pl b/CryptoPkg/Library/OpensslLib/openssl/crypto/bn/asm/alpha-mont.pl
+new file mode 100644
+index 0000000..1d68d6d
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/bn/asm/alpha-mont.pl
+@@ -0,0 +1,331 @@
++#! /usr/bin/env perl
++# Copyright 2006-2016 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
++# in the file LICENSE in the source distribution or at
++# https://www.openssl.org/source/license.html
++
++#
++# ====================================================================
++# Written by Andy Polyakov  for the OpenSSL
++# project. The module is, however, dual licensed under OpenSSL and
++# CRYPTOGAMS licenses depending on where you obtain it. For further
++# details see http://www.openssl.org/~appro/cryptogams/.
++# ====================================================================
++#
++# On 21264 RSA sign performance improves by 70/35/20/15 percent for
++# 512/1024/2048/4096 bit key lengths. This is against vendor compiler
++# instructed to '-tune host' code with in-line assembler. Other
++# benchmarks improve by 15-20%. To anchor it to something else, the
++# code provides approximately the same performance per GHz as AMD64.
++# I.e. if you compare 1GHz 21264 and 2GHz Opteron, you'll observe ~2x
++# difference.
++
++$output=pop;
++open STDOUT,">$output";
++
++# int bn_mul_mont(
++$rp="a0";	# BN_ULONG *rp,
++$ap="a1";	# const BN_ULONG *ap,
++$bp="a2";	# const BN_ULONG *bp,
++$np="a3";	# const BN_ULONG *np,
++$n0="a4";	# const BN_ULONG *n0,
++$num="a5";	# int num);
++
++$lo0="t0";
++$hi0="t1";
++$lo1="t2";
++$hi1="t3";
++$aj="t4";
++$bi="t5";
++$nj="t6";
++$tp="t7";
++$alo="t8";
++$ahi="t9";
++$nlo="t10";
++$nhi="t11";
++$tj="t12";
++$i="s3";
++$j="s4";
++$m1="s5";
++
++$code=<<___;
++#ifdef __linux__
++#include 
++#else
++#include 
++#include 
++#endif
++
++.text
++
++.set	noat
++.set	noreorder
++
++.globl	bn_mul_mont
++.align	5
++.ent	bn_mul_mont
++bn_mul_mont:
++	lda	sp,-48(sp)
++	stq	ra,0(sp)
++	stq	s3,8(sp)
++	stq	s4,16(sp)
++	stq	s5,24(sp)
++	stq	fp,32(sp)
++	mov	sp,fp
++	.mask	0x0400f000,-48
++	.frame	fp,48,ra
++	.prologue 0
++
++	.align	4
++	.set	reorder
++	sextl	$num,$num
++	mov	0,v0
++	cmplt	$num,4,AT
++	bne	AT,.Lexit
++
++	ldq	$hi0,0($ap)	# ap[0]
++	s8addq	$num,16,AT
++	ldq	$aj,8($ap)
++	subq	sp,AT,sp
++	ldq	$bi,0($bp)	# bp[0]
++	lda	AT,-4096(zero)	# mov	-4096,AT
++	ldq	$n0,0($n0)
++	and	sp,AT,sp
++
++	mulq	$hi0,$bi,$lo0
++	ldq	$hi1,0($np)	# np[0]
++	umulh	$hi0,$bi,$hi0
++	ldq	$nj,8($np)
++
++	mulq	$lo0,$n0,$m1
++
++	mulq	$hi1,$m1,$lo1
++	umulh	$hi1,$m1,$hi1
++
++	addq	$lo1,$lo0,$lo1
++	cmpult	$lo1,$lo0,AT
++	addq	$hi1,AT,$hi1
++
++	mulq	$aj,$bi,$alo
++	mov	2,$j
++	umulh	$aj,$bi,$ahi
++	mov	sp,$tp
++
++	mulq	$nj,$m1,$nlo
++	s8addq	$j,$ap,$aj
++	umulh	$nj,$m1,$nhi
++	s8addq	$j,$np,$nj
++.align	4
++.L1st:
++	.set	noreorder
++	ldq	$aj,0($aj)
++	addl	$j,1,$j
++	ldq	$nj,0($nj)
++	lda	$tp,8($tp)
++
++	addq	$alo,$hi0,$lo0
++	mulq	$aj,$bi,$alo
++	cmpult	$lo0,$hi0,AT
++	addq	$nlo,$hi1,$lo1
++
++	mulq	$nj,$m1,$nlo
++	addq	$ahi,AT,$hi0
++	cmpult	$lo1,$hi1,v0
++	cmplt	$j,$num,$tj
++
++	umulh	$aj,$bi,$ahi
++	addq	$nhi,v0,$hi1
++	addq	$lo1,$lo0,$lo1
++	s8addq	$j,$ap,$aj
++
++	umulh	$nj,$m1,$nhi
++	cmpult	$lo1,$lo0,v0
++	addq	$hi1,v0,$hi1
++	s8addq	$j,$np,$nj
++
++	stq	$lo1,-8($tp)
++	nop
++	unop
++	bne	$tj,.L1st
++	.set	reorder
++
++	addq	$alo,$hi0,$lo0
++	addq	$nlo,$hi1,$lo1
++	cmpult	$lo0,$hi0,AT
++	cmpult	$lo1,$hi1,v0
++	addq	$ahi,AT,$hi0
++	addq	$nhi,v0,$hi1
++
++	addq	$lo1,$lo0,$lo1
++	cmpult	$lo1,$lo0,v0
++	addq	$hi1,v0,$hi1
++
++	stq	$lo1,0($tp)
++
++	addq	$hi1,$hi0,$hi1
++	cmpult	$hi1,$hi0,AT
++	stq	$hi1,8($tp)
++	stq	AT,16($tp)
++
++	mov	1,$i
++.align	4
++.Louter:
++	s8addq	$i,$bp,$bi
++	ldq	$hi0,0($ap)
++	ldq	$aj,8($ap)
++	ldq	$bi,0($bi)
++	ldq	$hi1,0($np)
++	ldq	$nj,8($np)
++	ldq	$tj,0(sp)
++
++	mulq	$hi0,$bi,$lo0
++	umulh	$hi0,$bi,$hi0
++
++	addq	$lo0,$tj,$lo0
++	cmpult	$lo0,$tj,AT
++	addq	$hi0,AT,$hi0
++
++	mulq	$lo0,$n0,$m1
++
++	mulq	$hi1,$m1,$lo1
++	umulh	$hi1,$m1,$hi1
++
++	addq	$lo1,$lo0,$lo1
++	cmpult	$lo1,$lo0,AT
++	mov	2,$j
++	addq	$hi1,AT,$hi1
++
++	mulq	$aj,$bi,$alo
++	mov	sp,$tp
++	umulh	$aj,$bi,$ahi
++
++	mulq	$nj,$m1,$nlo
++	s8addq	$j,$ap,$aj
++	umulh	$nj,$m1,$nhi
++.align	4
++.Linner:
++	.set	noreorder
++	ldq	$tj,8($tp)	#L0
++	nop			#U1
++	ldq	$aj,0($aj)	#L1
++	s8addq	$j,$np,$nj	#U0
++
++	ldq	$nj,0($nj)	#L0
++	nop			#U1
++	addq	$alo,$hi0,$lo0	#L1
++	lda	$tp,8($tp)
++
++	mulq	$aj,$bi,$alo	#U1
++	cmpult	$lo0,$hi0,AT	#L0
++	addq	$nlo,$hi1,$lo1	#L1
++	addl	$j,1,$j
++
++	mulq	$nj,$m1,$nlo	#U1
++	addq	$ahi,AT,$hi0	#L0
++	addq	$lo0,$tj,$lo0	#L1
++	cmpult	$lo1,$hi1,v0	#U0
++
++	umulh	$aj,$bi,$ahi	#U1
++	cmpult	$lo0,$tj,AT	#L0
++	addq	$lo1,$lo0,$lo1	#L1
++	addq	$nhi,v0,$hi1	#U0
++
++	umulh	$nj,$m1,$nhi	#U1
++	s8addq	$j,$ap,$aj	#L0
++	cmpult	$lo1,$lo0,v0	#L1
++	cmplt	$j,$num,$tj	#U0	# borrow $tj
++
++	addq	$hi0,AT,$hi0	#L0
++	addq	$hi1,v0,$hi1	#U1
++	stq	$lo1,-8($tp)	#L1
++	bne	$tj,.Linner	#U0
++	.set	reorder
++
++	ldq	$tj,8($tp)
++	addq	$alo,$hi0,$lo0
++	addq	$nlo,$hi1,$lo1
++	cmpult	$lo0,$hi0,AT
++	cmpult	$lo1,$hi1,v0
++	addq	$ahi,AT,$hi0
++	addq	$nhi,v0,$hi1
++
++	addq	$lo0,$tj,$lo0
++	cmpult	$lo0,$tj,AT
++	addq	$hi0,AT,$hi0
++
++	ldq	$tj,16($tp)
++	addq	$lo1,$lo0,$j
++	cmpult	$j,$lo0,v0
++	addq	$hi1,v0,$hi1
++
++	addq	$hi1,$hi0,$lo1
++	stq	$j,0($tp)
++	cmpult	$lo1,$hi0,$hi1
++	addq	$lo1,$tj,$lo1
++	cmpult	$lo1,$tj,AT
++	addl	$i,1,$i
++	addq	$hi1,AT,$hi1
++	stq	$lo1,8($tp)
++	cmplt	$i,$num,$tj	# borrow $tj
++	stq	$hi1,16($tp)
++	bne	$tj,.Louter
++
++	s8addq	$num,sp,$tj	# &tp[num]
++	mov	$rp,$bp		# put rp aside
++	mov	sp,$tp
++	mov	sp,$ap
++	mov	0,$hi0		# clear borrow bit
++
++.align	4
++.Lsub:	ldq	$lo0,0($tp)
++	ldq	$lo1,0($np)
++	lda	$tp,8($tp)
++	lda	$np,8($np)
++	subq	$lo0,$lo1,$lo1	# tp[i]-np[i]
++	cmpult	$lo0,$lo1,AT
++	subq	$lo1,$hi0,$lo0
++	cmpult	$lo1,$lo0,$hi0
++	or	$hi0,AT,$hi0
++	stq	$lo0,0($rp)
++	cmpult	$tp,$tj,v0
++	lda	$rp,8($rp)
++	bne	v0,.Lsub
++
++	subq	$hi1,$hi0,$hi0	# handle upmost overflow bit
++	mov	sp,$tp
++	mov	$bp,$rp		# restore rp
++
++	and	sp,$hi0,$ap
++	bic	$bp,$hi0,$bp
++	bis	$bp,$ap,$ap	# ap=borrow?tp:rp
++
++.align	4
++.Lcopy:	ldq	$aj,0($ap)	# copy or in-place refresh
++	lda	$tp,8($tp)
++	lda	$rp,8($rp)
++	lda	$ap,8($ap)
++	stq	zero,-8($tp)	# zap tp
++	cmpult	$tp,$tj,AT
++	stq	$aj,-8($rp)
++	bne	AT,.Lcopy
++	mov	1,v0
++
++.Lexit:
++	.set	noreorder
++	mov	fp,sp
++	/*ldq	ra,0(sp)*/
++	ldq	s3,8(sp)
++	ldq	s4,16(sp)
++	ldq	s5,24(sp)
++	ldq	fp,32(sp)
++	lda	sp,48(sp)
++	ret	(ra)
++.end	bn_mul_mont
++.ascii	"Montgomery Multiplication for Alpha, CRYPTOGAMS by "
++.align	2
++___
++
++print $code;
++close STDOUT;
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/bn/asm/armv4-gf2m.pl b/CryptoPkg/Library/OpensslLib/openssl/crypto/bn/asm/armv4-gf2m.pl
+new file mode 100644
+index 0000000..0bb5433
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/bn/asm/armv4-gf2m.pl
+@@ -0,0 +1,332 @@
++#! /usr/bin/env perl
++# Copyright 2011-2016 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
++# in the file LICENSE in the source distribution or at
++# https://www.openssl.org/source/license.html
++
++#
++# ====================================================================
++# Written by Andy Polyakov  for the OpenSSL
++# project. The module is, however, dual licensed under OpenSSL and
++# CRYPTOGAMS licenses depending on where you obtain it. For further
++# details see http://www.openssl.org/~appro/cryptogams/.
++# ====================================================================
++#
++# May 2011
++#
++# The module implements bn_GF2m_mul_2x2 polynomial multiplication
++# used in bn_gf2m.c. It's kind of low-hanging mechanical port from
++# C for the time being... Except that it has two code paths: pure
++# integer code suitable for any ARMv4 and later CPU and NEON code
++# suitable for ARMv7. Pure integer 1x1 multiplication subroutine runs
++# in ~45 cycles on dual-issue core such as Cortex A8, which is ~50%
++# faster than compiler-generated code. For ECDH and ECDSA verify (but
++# not for ECDSA sign) it means 25%-45% improvement depending on key
++# length, more for longer keys. Even though NEON 1x1 multiplication
++# runs in even less cycles, ~30, improvement is measurable only on
++# longer keys. One has to optimize code elsewhere to get NEON glow...
++#
++# April 2014
++#
++# Double bn_GF2m_mul_2x2 performance by using algorithm from paper
++# referred below, which improves ECDH and ECDSA verify benchmarks
++# by 18-40%.
++#
++# Câmara, D.; Gouvêa, C. P. L.; López, J. & Dahab, R.: Fast Software
++# Polynomial Multiplication on ARM Processors using the NEON Engine.
++# 
++# http://conradoplg.cryptoland.net/files/2010/12/mocrysen13.pdf
++
++$flavour = shift;
++if ($flavour=~/\w[\w\-]*\.\w+$/) { $output=$flavour; undef $flavour; }
++else { while (($output=shift) && ($output!~/\w[\w\-]*\.\w+$/)) {} }
++
++if ($flavour && $flavour ne "void") {
++    $0 =~ m/(.*[\/\\])[^\/\\]+$/; $dir=$1;
++    ( $xlate="${dir}arm-xlate.pl" and -f $xlate ) or
++    ( $xlate="${dir}../../perlasm/arm-xlate.pl" and -f $xlate) or
++    die "can't locate arm-xlate.pl";
++
++    open STDOUT,"| \"$^X\" $xlate $flavour $output";
++} else {
++    open STDOUT,">$output";
++}
++
++$code=<<___;
++#include "arm_arch.h"
++
++.text
++#if defined(__thumb2__)
++.syntax	unified
++.thumb
++#else
++.code	32
++#endif
++___
++################
++# private interface to mul_1x1_ialu
++#
++$a="r1";
++$b="r0";
++
++($a0,$a1,$a2,$a12,$a4,$a14)=
++($hi,$lo,$t0,$t1, $i0,$i1 )=map("r$_",(4..9),12);
++
++$mask="r12";
++
++$code.=<<___;
++.type	mul_1x1_ialu,%function
++.align	5
++mul_1x1_ialu:
++	mov	$a0,#0
++	bic	$a1,$a,#3<<30		@ a1=a&0x3fffffff
++	str	$a0,[sp,#0]		@ tab[0]=0
++	add	$a2,$a1,$a1		@ a2=a1<<1
++	str	$a1,[sp,#4]		@ tab[1]=a1
++	eor	$a12,$a1,$a2		@ a1^a2
++	str	$a2,[sp,#8]		@ tab[2]=a2
++	mov	$a4,$a1,lsl#2		@ a4=a1<<2
++	str	$a12,[sp,#12]		@ tab[3]=a1^a2
++	eor	$a14,$a1,$a4		@ a1^a4
++	str	$a4,[sp,#16]		@ tab[4]=a4
++	eor	$a0,$a2,$a4		@ a2^a4
++	str	$a14,[sp,#20]		@ tab[5]=a1^a4
++	eor	$a12,$a12,$a4		@ a1^a2^a4
++	str	$a0,[sp,#24]		@ tab[6]=a2^a4
++	and	$i0,$mask,$b,lsl#2
++	str	$a12,[sp,#28]		@ tab[7]=a1^a2^a4
++
++	and	$i1,$mask,$b,lsr#1
++	ldr	$lo,[sp,$i0]		@ tab[b       & 0x7]
++	and	$i0,$mask,$b,lsr#4
++	ldr	$t1,[sp,$i1]		@ tab[b >>  3 & 0x7]
++	and	$i1,$mask,$b,lsr#7
++	ldr	$t0,[sp,$i0]		@ tab[b >>  6 & 0x7]
++	eor	$lo,$lo,$t1,lsl#3	@ stall
++	mov	$hi,$t1,lsr#29
++	ldr	$t1,[sp,$i1]		@ tab[b >>  9 & 0x7]
++
++	and	$i0,$mask,$b,lsr#10
++	eor	$lo,$lo,$t0,lsl#6
++	eor	$hi,$hi,$t0,lsr#26
++	ldr	$t0,[sp,$i0]		@ tab[b >> 12 & 0x7]
++
++	and	$i1,$mask,$b,lsr#13
++	eor	$lo,$lo,$t1,lsl#9
++	eor	$hi,$hi,$t1,lsr#23
++	ldr	$t1,[sp,$i1]		@ tab[b >> 15 & 0x7]
++
++	and	$i0,$mask,$b,lsr#16
++	eor	$lo,$lo,$t0,lsl#12
++	eor	$hi,$hi,$t0,lsr#20
++	ldr	$t0,[sp,$i0]		@ tab[b >> 18 & 0x7]
++
++	and	$i1,$mask,$b,lsr#19
++	eor	$lo,$lo,$t1,lsl#15
++	eor	$hi,$hi,$t1,lsr#17
++	ldr	$t1,[sp,$i1]		@ tab[b >> 21 & 0x7]
++
++	and	$i0,$mask,$b,lsr#22
++	eor	$lo,$lo,$t0,lsl#18
++	eor	$hi,$hi,$t0,lsr#14
++	ldr	$t0,[sp,$i0]		@ tab[b >> 24 & 0x7]
++
++	and	$i1,$mask,$b,lsr#25
++	eor	$lo,$lo,$t1,lsl#21
++	eor	$hi,$hi,$t1,lsr#11
++	ldr	$t1,[sp,$i1]		@ tab[b >> 27 & 0x7]
++
++	tst	$a,#1<<30
++	and	$i0,$mask,$b,lsr#28
++	eor	$lo,$lo,$t0,lsl#24
++	eor	$hi,$hi,$t0,lsr#8
++	ldr	$t0,[sp,$i0]		@ tab[b >> 30      ]
++
++#ifdef	__thumb2__
++	itt	ne
++#endif
++	eorne	$lo,$lo,$b,lsl#30
++	eorne	$hi,$hi,$b,lsr#2
++	tst	$a,#1<<31
++	eor	$lo,$lo,$t1,lsl#27
++	eor	$hi,$hi,$t1,lsr#5
++#ifdef	__thumb2__
++	itt	ne
++#endif
++	eorne	$lo,$lo,$b,lsl#31
++	eorne	$hi,$hi,$b,lsr#1
++	eor	$lo,$lo,$t0,lsl#30
++	eor	$hi,$hi,$t0,lsr#2
++
++	mov	pc,lr
++.size	mul_1x1_ialu,.-mul_1x1_ialu
++___
++################
++# void	bn_GF2m_mul_2x2(BN_ULONG *r,
++#	BN_ULONG a1,BN_ULONG a0,
++#	BN_ULONG b1,BN_ULONG b0);	# r[3..0]=a1a0·b1b0
++{
++$code.=<<___;
++.global	bn_GF2m_mul_2x2
++.type	bn_GF2m_mul_2x2,%function
++.align	5
++bn_GF2m_mul_2x2:
++#if __ARM_MAX_ARCH__>=7
++	stmdb	sp!,{r10,lr}
++	ldr	r12,.LOPENSSL_armcap
++	adr	r10,.LOPENSSL_armcap
++	ldr	r12,[r12,r10]
++#ifdef	__APPLE__
++	ldr	r12,[r12]
++#endif
++	tst	r12,#ARMV7_NEON
++	itt	ne
++	ldrne	r10,[sp],#8
++	bne	.LNEON
++	stmdb	sp!,{r4-r9}
++#else
++	stmdb	sp!,{r4-r10,lr}
++#endif
++___
++$ret="r10";	# reassigned 1st argument
++$code.=<<___;
++	mov	$ret,r0			@ reassign 1st argument
++	mov	$b,r3			@ $b=b1
++	sub	r7,sp,#36
++	mov	r8,sp
++	and	r7,r7,#-32
++	ldr	r3,[sp,#32]		@ load b0
++	mov	$mask,#7<<2
++	mov	sp,r7			@ allocate tab[8]
++	str	r8,[r7,#32]
++
++	bl	mul_1x1_ialu		@ a1·b1
++	str	$lo,[$ret,#8]
++	str	$hi,[$ret,#12]
++
++	eor	$b,$b,r3		@ flip b0 and b1
++	 eor	$a,$a,r2		@ flip a0 and a1
++	eor	r3,r3,$b
++	 eor	r2,r2,$a
++	eor	$b,$b,r3
++	 eor	$a,$a,r2
++	bl	mul_1x1_ialu		@ a0·b0
++	str	$lo,[$ret]
++	str	$hi,[$ret,#4]
++
++	eor	$a,$a,r2
++	eor	$b,$b,r3
++	bl	mul_1x1_ialu		@ (a1+a0)·(b1+b0)
++___
++@r=map("r$_",(6..9));
++$code.=<<___;
++	ldmia	$ret,{@r[0]-@r[3]}
++	eor	$lo,$lo,$hi
++	ldr	sp,[sp,#32]		@ destroy tab[8]
++	eor	$hi,$hi,@r[1]
++	eor	$lo,$lo,@r[0]
++	eor	$hi,$hi,@r[2]
++	eor	$lo,$lo,@r[3]
++	eor	$hi,$hi,@r[3]
++	str	$hi,[$ret,#8]
++	eor	$lo,$lo,$hi
++	str	$lo,[$ret,#4]
++
++#if __ARM_ARCH__>=5
++	ldmia	sp!,{r4-r10,pc}
++#else
++	ldmia	sp!,{r4-r10,lr}
++	tst	lr,#1
++	moveq	pc,lr			@ be binary compatible with V4, yet
++	bx	lr			@ interoperable with Thumb ISA:-)
++#endif
++___
++}
++{
++my ($r,$t0,$t1,$t2,$t3)=map("q$_",(0..3,8..12));
++my ($a,$b,$k48,$k32,$k16)=map("d$_",(26..31));
++
++$code.=<<___;
++#if __ARM_MAX_ARCH__>=7
++.arch	armv7-a
++.fpu	neon
++
++.align	5
++.LNEON:
++	ldr		r12, [sp]		@ 5th argument
++	vmov		$a, r2, r1
++	vmov		$b, r12, r3
++	vmov.i64	$k48, #0x0000ffffffffffff
++	vmov.i64	$k32, #0x00000000ffffffff
++	vmov.i64	$k16, #0x000000000000ffff
++
++	vext.8		$t0#lo, $a, $a, #1	@ A1
++	vmull.p8	$t0, $t0#lo, $b		@ F = A1*B
++	vext.8		$r#lo, $b, $b, #1	@ B1
++	vmull.p8	$r, $a, $r#lo		@ E = A*B1
++	vext.8		$t1#lo, $a, $a, #2	@ A2
++	vmull.p8	$t1, $t1#lo, $b		@ H = A2*B
++	vext.8		$t3#lo, $b, $b, #2	@ B2
++	vmull.p8	$t3, $a, $t3#lo		@ G = A*B2
++	vext.8		$t2#lo, $a, $a, #3	@ A3
++	veor		$t0, $t0, $r		@ L = E + F
++	vmull.p8	$t2, $t2#lo, $b		@ J = A3*B
++	vext.8		$r#lo, $b, $b, #3	@ B3
++	veor		$t1, $t1, $t3		@ M = G + H
++	vmull.p8	$r, $a, $r#lo		@ I = A*B3
++	veor		$t0#lo, $t0#lo, $t0#hi	@ t0 = (L) (P0 + P1) << 8
++	vand		$t0#hi, $t0#hi, $k48
++	vext.8		$t3#lo, $b, $b, #4	@ B4
++	veor		$t1#lo, $t1#lo, $t1#hi	@ t1 = (M) (P2 + P3) << 16
++	vand		$t1#hi, $t1#hi, $k32
++	vmull.p8	$t3, $a, $t3#lo		@ K = A*B4
++	veor		$t2, $t2, $r		@ N = I + J
++	veor		$t0#lo, $t0#lo, $t0#hi
++	veor		$t1#lo, $t1#lo, $t1#hi
++	veor		$t2#lo, $t2#lo, $t2#hi	@ t2 = (N) (P4 + P5) << 24
++	vand		$t2#hi, $t2#hi, $k16
++	vext.8		$t0, $t0, $t0, #15
++	veor		$t3#lo, $t3#lo, $t3#hi	@ t3 = (K) (P6 + P7) << 32
++	vmov.i64	$t3#hi, #0
++	vext.8		$t1, $t1, $t1, #14
++	veor		$t2#lo, $t2#lo, $t2#hi
++	vmull.p8	$r, $a, $b		@ D = A*B
++	vext.8		$t3, $t3, $t3, #12
++	vext.8		$t2, $t2, $t2, #13
++	veor		$t0, $t0, $t1
++	veor		$t2, $t2, $t3
++	veor		$r, $r, $t0
++	veor		$r, $r, $t2
++
++	vst1.32		{$r}, [r0]
++	ret		@ bx lr
++#endif
++___
++}
++$code.=<<___;
++.size	bn_GF2m_mul_2x2,.-bn_GF2m_mul_2x2
++#if __ARM_MAX_ARCH__>=7
++.align	5
++.LOPENSSL_armcap:
++.word	OPENSSL_armcap_P-.
++#endif
++.asciz	"GF(2^m) Multiplication for ARMv4/NEON, CRYPTOGAMS by "
++.align	5
++
++#if __ARM_MAX_ARCH__>=7
++.comm	OPENSSL_armcap_P,4,4
++#endif
++___
++
++foreach (split("\n",$code)) {
++	s/\`([^\`]*)\`/eval $1/geo;
++
++	s/\bq([0-9]+)#(lo|hi)/sprintf "d%d",2*$1+($2 eq "hi")/geo	or
++	s/\bret\b/bx	lr/go		or
++	s/\bbx\s+lr\b/.word\t0xe12fff1e/go;    # make it possible to compile with -march=armv4
++
++	print $_,"\n";
++}
++close STDOUT;   # enforce flush
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/bn/asm/armv4-mont.pl b/CryptoPkg/Library/OpensslLib/openssl/crypto/bn/asm/armv4-mont.pl
+new file mode 100644
+index 0000000..0dc4fe9
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/bn/asm/armv4-mont.pl
+@@ -0,0 +1,756 @@
++#! /usr/bin/env perl
++# Copyright 2007-2016 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
++# in the file LICENSE in the source distribution or at
++# https://www.openssl.org/source/license.html
++
++
++# ====================================================================
++# Written by Andy Polyakov  for the OpenSSL
++# project. The module is, however, dual licensed under OpenSSL and
++# CRYPTOGAMS licenses depending on where you obtain it. For further
++# details see http://www.openssl.org/~appro/cryptogams/.
++# ====================================================================
++
++# January 2007.
++
++# Montgomery multiplication for ARMv4.
++#
++# Performance improvement naturally varies among CPU implementations
++# and compilers. The code was observed to provide +65-35% improvement
++# [depending on key length, less for longer keys] on ARM920T, and
++# +115-80% on Intel IXP425. This is compared to pre-bn_mul_mont code
++# base and compiler generated code with in-lined umull and even umlal
++# instructions. The latter means that this code didn't really have an 
++# "advantage" of utilizing some "secret" instruction.
++#
++# The code is interoperable with Thumb ISA and is rather compact, less
++# than 1/2KB. Windows CE port would be trivial, as it's exclusively
++# about decorations, ABI and instruction syntax are identical.
++
++# November 2013
++#
++# Add NEON code path, which handles lengths divisible by 8. RSA/DSA
++# performance improvement on Cortex-A8 is ~45-100% depending on key
++# length, more for longer keys. On Cortex-A15 the span is ~10-105%.
++# On Snapdragon S4 improvement was measured to vary from ~70% to
++# incredible ~380%, yes, 4.8x faster, for RSA4096 sign. But this is
++# rather because original integer-only code seems to perform
++# suboptimally on S4. Situation on Cortex-A9 is unfortunately
++# different. It's being looked into, but the trouble is that
++# performance for vectors longer than 256 bits is actually couple
++# of percent worse than for integer-only code. The code is chosen
++# for execution on all NEON-capable processors, because gain on
++# others outweighs the marginal loss on Cortex-A9.
++
++# September 2015
++#
++# Align Cortex-A9 performance with November 2013 improvements, i.e.
++# NEON code is now ~20-105% faster than integer-only one on this
++# processor. But this optimization further improved performance even
++# on other processors: NEON code path is ~45-180% faster than original
++# integer-only on Cortex-A8, ~10-210% on Cortex-A15, ~70-450% on
++# Snapdragon S4.
++
++$flavour = shift;
++if ($flavour=~/\w[\w\-]*\.\w+$/) { $output=$flavour; undef $flavour; }
++else { while (($output=shift) && ($output!~/\w[\w\-]*\.\w+$/)) {} }
++
++if ($flavour && $flavour ne "void") {
++    $0 =~ m/(.*[\/\\])[^\/\\]+$/; $dir=$1;
++    ( $xlate="${dir}arm-xlate.pl" and -f $xlate ) or
++    ( $xlate="${dir}../../perlasm/arm-xlate.pl" and -f $xlate) or
++    die "can't locate arm-xlate.pl";
++
++    open STDOUT,"| \"$^X\" $xlate $flavour $output";
++} else {
++    open STDOUT,">$output";
++}
++
++$num="r0";	# starts as num argument, but holds &tp[num-1]
++$ap="r1";
++$bp="r2"; $bi="r2"; $rp="r2";
++$np="r3";
++$tp="r4";
++$aj="r5";
++$nj="r6";
++$tj="r7";
++$n0="r8";
++###########	# r9 is reserved by ELF as platform specific, e.g. TLS pointer
++$alo="r10";	# sl, gcc uses it to keep @GOT
++$ahi="r11";	# fp
++$nlo="r12";	# ip
++###########	# r13 is stack pointer
++$nhi="r14";	# lr
++###########	# r15 is program counter
++
++#### argument block layout relative to &tp[num-1], a.k.a. $num
++$_rp="$num,#12*4";
++# ap permanently resides in r1
++$_bp="$num,#13*4";
++# np permanently resides in r3
++$_n0="$num,#14*4";
++$_num="$num,#15*4";	$_bpend=$_num;
++
++$code=<<___;
++#include "arm_arch.h"
++
++.text
++#if defined(__thumb2__)
++.syntax	unified
++.thumb
++#else
++.code	32
++#endif
++
++#if __ARM_MAX_ARCH__>=7
++.align	5
++.LOPENSSL_armcap:
++.word	OPENSSL_armcap_P-.Lbn_mul_mont
++#endif
++
++.global	bn_mul_mont
++.type	bn_mul_mont,%function
++
++.align	5
++bn_mul_mont:
++.Lbn_mul_mont:
++	ldr	ip,[sp,#4]		@ load num
++	stmdb	sp!,{r0,r2}		@ sp points at argument block
++#if __ARM_MAX_ARCH__>=7
++	tst	ip,#7
++	bne	.Lialu
++	adr	r0,.Lbn_mul_mont
++	ldr	r2,.LOPENSSL_armcap
++	ldr	r0,[r0,r2]
++#ifdef	__APPLE__
++	ldr	r0,[r0]
++#endif
++	tst	r0,#ARMV7_NEON		@ NEON available?
++	ldmia	sp, {r0,r2}
++	beq	.Lialu
++	add	sp,sp,#8
++	b	bn_mul8x_mont_neon
++.align	4
++.Lialu:
++#endif
++	cmp	ip,#2
++	mov	$num,ip			@ load num
++#ifdef	__thumb2__
++	ittt	lt
++#endif
++	movlt	r0,#0
++	addlt	sp,sp,#2*4
++	blt	.Labrt
++
++	stmdb	sp!,{r4-r12,lr}		@ save 10 registers
++
++	mov	$num,$num,lsl#2		@ rescale $num for byte count
++	sub	sp,sp,$num		@ alloca(4*num)
++	sub	sp,sp,#4		@ +extra dword
++	sub	$num,$num,#4		@ "num=num-1"
++	add	$tp,$bp,$num		@ &bp[num-1]
++
++	add	$num,sp,$num		@ $num to point at &tp[num-1]
++	ldr	$n0,[$_n0]		@ &n0
++	ldr	$bi,[$bp]		@ bp[0]
++	ldr	$aj,[$ap],#4		@ ap[0],ap++
++	ldr	$nj,[$np],#4		@ np[0],np++
++	ldr	$n0,[$n0]		@ *n0
++	str	$tp,[$_bpend]		@ save &bp[num]
++
++	umull	$alo,$ahi,$aj,$bi	@ ap[0]*bp[0]
++	str	$n0,[$_n0]		@ save n0 value
++	mul	$n0,$alo,$n0		@ "tp[0]"*n0
++	mov	$nlo,#0
++	umlal	$alo,$nlo,$nj,$n0	@ np[0]*n0+"t[0]"
++	mov	$tp,sp
++
++.L1st:
++	ldr	$aj,[$ap],#4		@ ap[j],ap++
++	mov	$alo,$ahi
++	ldr	$nj,[$np],#4		@ np[j],np++
++	mov	$ahi,#0
++	umlal	$alo,$ahi,$aj,$bi	@ ap[j]*bp[0]
++	mov	$nhi,#0
++	umlal	$nlo,$nhi,$nj,$n0	@ np[j]*n0
++	adds	$nlo,$nlo,$alo
++	str	$nlo,[$tp],#4		@ tp[j-1]=,tp++
++	adc	$nlo,$nhi,#0
++	cmp	$tp,$num
++	bne	.L1st
++
++	adds	$nlo,$nlo,$ahi
++	ldr	$tp,[$_bp]		@ restore bp
++	mov	$nhi,#0
++	ldr	$n0,[$_n0]		@ restore n0
++	adc	$nhi,$nhi,#0
++	str	$nlo,[$num]		@ tp[num-1]=
++	mov	$tj,sp
++	str	$nhi,[$num,#4]		@ tp[num]=
++
++.Louter:
++	sub	$tj,$num,$tj		@ "original" $num-1 value
++	sub	$ap,$ap,$tj		@ "rewind" ap to &ap[1]
++	ldr	$bi,[$tp,#4]!		@ *(++bp)
++	sub	$np,$np,$tj		@ "rewind" np to &np[1]
++	ldr	$aj,[$ap,#-4]		@ ap[0]
++	ldr	$alo,[sp]		@ tp[0]
++	ldr	$nj,[$np,#-4]		@ np[0]
++	ldr	$tj,[sp,#4]		@ tp[1]
++
++	mov	$ahi,#0
++	umlal	$alo,$ahi,$aj,$bi	@ ap[0]*bp[i]+tp[0]
++	str	$tp,[$_bp]		@ save bp
++	mul	$n0,$alo,$n0
++	mov	$nlo,#0
++	umlal	$alo,$nlo,$nj,$n0	@ np[0]*n0+"tp[0]"
++	mov	$tp,sp
++
++.Linner:
++	ldr	$aj,[$ap],#4		@ ap[j],ap++
++	adds	$alo,$ahi,$tj		@ +=tp[j]
++	ldr	$nj,[$np],#4		@ np[j],np++
++	mov	$ahi,#0
++	umlal	$alo,$ahi,$aj,$bi	@ ap[j]*bp[i]
++	mov	$nhi,#0
++	umlal	$nlo,$nhi,$nj,$n0	@ np[j]*n0
++	adc	$ahi,$ahi,#0
++	ldr	$tj,[$tp,#8]		@ tp[j+1]
++	adds	$nlo,$nlo,$alo
++	str	$nlo,[$tp],#4		@ tp[j-1]=,tp++
++	adc	$nlo,$nhi,#0
++	cmp	$tp,$num
++	bne	.Linner
++
++	adds	$nlo,$nlo,$ahi
++	mov	$nhi,#0
++	ldr	$tp,[$_bp]		@ restore bp
++	adc	$nhi,$nhi,#0
++	ldr	$n0,[$_n0]		@ restore n0
++	adds	$nlo,$nlo,$tj
++	ldr	$tj,[$_bpend]		@ restore &bp[num]
++	adc	$nhi,$nhi,#0
++	str	$nlo,[$num]		@ tp[num-1]=
++	str	$nhi,[$num,#4]		@ tp[num]=
++
++	cmp	$tp,$tj
++#ifdef	__thumb2__
++	itt	ne
++#endif
++	movne	$tj,sp
++	bne	.Louter
++
++	ldr	$rp,[$_rp]		@ pull rp
++	mov	$aj,sp
++	add	$num,$num,#4		@ $num to point at &tp[num]
++	sub	$aj,$num,$aj		@ "original" num value
++	mov	$tp,sp			@ "rewind" $tp
++	mov	$ap,$tp			@ "borrow" $ap
++	sub	$np,$np,$aj		@ "rewind" $np to &np[0]
++
++	subs	$tj,$tj,$tj		@ "clear" carry flag
++.Lsub:	ldr	$tj,[$tp],#4
++	ldr	$nj,[$np],#4
++	sbcs	$tj,$tj,$nj		@ tp[j]-np[j]
++	str	$tj,[$rp],#4		@ rp[j]=
++	teq	$tp,$num		@ preserve carry
++	bne	.Lsub
++	sbcs	$nhi,$nhi,#0		@ upmost carry
++	mov	$tp,sp			@ "rewind" $tp
++	sub	$rp,$rp,$aj		@ "rewind" $rp
++
++	and	$ap,$tp,$nhi
++	bic	$np,$rp,$nhi
++	orr	$ap,$ap,$np		@ ap=borrow?tp:rp
++
++.Lcopy:	ldr	$tj,[$ap],#4		@ copy or in-place refresh
++	str	sp,[$tp],#4		@ zap tp
++	str	$tj,[$rp],#4
++	cmp	$tp,$num
++	bne	.Lcopy
++
++	mov	sp,$num
++	add	sp,sp,#4		@ skip over tp[num+1]
++	ldmia	sp!,{r4-r12,lr}		@ restore registers
++	add	sp,sp,#2*4		@ skip over {r0,r2}
++	mov	r0,#1
++.Labrt:
++#if __ARM_ARCH__>=5
++	ret				@ bx lr
++#else
++	tst	lr,#1
++	moveq	pc,lr			@ be binary compatible with V4, yet
++	bx	lr			@ interoperable with Thumb ISA:-)
++#endif
++.size	bn_mul_mont,.-bn_mul_mont
++___
++{
++my ($A0,$A1,$A2,$A3)=map("d$_",(0..3));
++my ($N0,$N1,$N2,$N3)=map("d$_",(4..7));
++my ($Z,$Temp)=("q4","q5");
++my @ACC=map("q$_",(6..13));
++my ($Bi,$Ni,$M0)=map("d$_",(28..31));
++my $zero="$Z#lo";
++my $temp="$Temp#lo";
++
++my ($rptr,$aptr,$bptr,$nptr,$n0,$num)=map("r$_",(0..5));
++my ($tinptr,$toutptr,$inner,$outer,$bnptr)=map("r$_",(6..11));
++
++$code.=<<___;
++#if __ARM_MAX_ARCH__>=7
++.arch	armv7-a
++.fpu	neon
++
++.type	bn_mul8x_mont_neon,%function
++.align	5
++bn_mul8x_mont_neon:
++	mov	ip,sp
++	stmdb	sp!,{r4-r11}
++	vstmdb	sp!,{d8-d15}		@ ABI specification says so
++	ldmia	ip,{r4-r5}		@ load rest of parameter block
++	mov	ip,sp
++
++	cmp	$num,#8
++	bhi	.LNEON_8n
++
++	@ special case for $num==8, everything is in register bank...
++
++	vld1.32		{${Bi}[0]}, [$bptr,:32]!
++	veor		$zero,$zero,$zero
++	sub		$toutptr,sp,$num,lsl#4
++	vld1.32		{$A0-$A3},  [$aptr]!		@ can't specify :32 :-(
++	and		$toutptr,$toutptr,#-64
++	vld1.32		{${M0}[0]}, [$n0,:32]
++	mov		sp,$toutptr			@ alloca
++	vzip.16		$Bi,$zero
++
++	vmull.u32	@ACC[0],$Bi,${A0}[0]
++	vmull.u32	@ACC[1],$Bi,${A0}[1]
++	vmull.u32	@ACC[2],$Bi,${A1}[0]
++	vshl.i64	$Ni,@ACC[0]#hi,#16
++	vmull.u32	@ACC[3],$Bi,${A1}[1]
++
++	vadd.u64	$Ni,$Ni,@ACC[0]#lo
++	veor		$zero,$zero,$zero
++	vmul.u32	$Ni,$Ni,$M0
++
++	vmull.u32	@ACC[4],$Bi,${A2}[0]
++	 vld1.32	{$N0-$N3}, [$nptr]!
++	vmull.u32	@ACC[5],$Bi,${A2}[1]
++	vmull.u32	@ACC[6],$Bi,${A3}[0]
++	vzip.16		$Ni,$zero
++	vmull.u32	@ACC[7],$Bi,${A3}[1]
++
++	vmlal.u32	@ACC[0],$Ni,${N0}[0]
++	sub		$outer,$num,#1
++	vmlal.u32	@ACC[1],$Ni,${N0}[1]
++	vmlal.u32	@ACC[2],$Ni,${N1}[0]
++	vmlal.u32	@ACC[3],$Ni,${N1}[1]
++
++	vmlal.u32	@ACC[4],$Ni,${N2}[0]
++	vmov		$Temp,@ACC[0]
++	vmlal.u32	@ACC[5],$Ni,${N2}[1]
++	vmov		@ACC[0],@ACC[1]
++	vmlal.u32	@ACC[6],$Ni,${N3}[0]
++	vmov		@ACC[1],@ACC[2]
++	vmlal.u32	@ACC[7],$Ni,${N3}[1]
++	vmov		@ACC[2],@ACC[3]
++	vmov		@ACC[3],@ACC[4]
++	vshr.u64	$temp,$temp,#16
++	vmov		@ACC[4],@ACC[5]
++	vmov		@ACC[5],@ACC[6]
++	vadd.u64	$temp,$temp,$Temp#hi
++	vmov		@ACC[6],@ACC[7]
++	veor		@ACC[7],@ACC[7]
++	vshr.u64	$temp,$temp,#16
++
++	b	.LNEON_outer8
++
++.align	4
++.LNEON_outer8:
++	vld1.32		{${Bi}[0]}, [$bptr,:32]!
++	veor		$zero,$zero,$zero
++	vzip.16		$Bi,$zero
++	vadd.u64	@ACC[0]#lo,@ACC[0]#lo,$temp
++
++	vmlal.u32	@ACC[0],$Bi,${A0}[0]
++	vmlal.u32	@ACC[1],$Bi,${A0}[1]
++	vmlal.u32	@ACC[2],$Bi,${A1}[0]
++	vshl.i64	$Ni,@ACC[0]#hi,#16
++	vmlal.u32	@ACC[3],$Bi,${A1}[1]
++
++	vadd.u64	$Ni,$Ni,@ACC[0]#lo
++	veor		$zero,$zero,$zero
++	subs		$outer,$outer,#1
++	vmul.u32	$Ni,$Ni,$M0
++
++	vmlal.u32	@ACC[4],$Bi,${A2}[0]
++	vmlal.u32	@ACC[5],$Bi,${A2}[1]
++	vmlal.u32	@ACC[6],$Bi,${A3}[0]
++	vzip.16		$Ni,$zero
++	vmlal.u32	@ACC[7],$Bi,${A3}[1]
++
++	vmlal.u32	@ACC[0],$Ni,${N0}[0]
++	vmlal.u32	@ACC[1],$Ni,${N0}[1]
++	vmlal.u32	@ACC[2],$Ni,${N1}[0]
++	vmlal.u32	@ACC[3],$Ni,${N1}[1]
++
++	vmlal.u32	@ACC[4],$Ni,${N2}[0]
++	vmov		$Temp,@ACC[0]
++	vmlal.u32	@ACC[5],$Ni,${N2}[1]
++	vmov		@ACC[0],@ACC[1]
++	vmlal.u32	@ACC[6],$Ni,${N3}[0]
++	vmov		@ACC[1],@ACC[2]
++	vmlal.u32	@ACC[7],$Ni,${N3}[1]
++	vmov		@ACC[2],@ACC[3]
++	vmov		@ACC[3],@ACC[4]
++	vshr.u64	$temp,$temp,#16
++	vmov		@ACC[4],@ACC[5]
++	vmov		@ACC[5],@ACC[6]
++	vadd.u64	$temp,$temp,$Temp#hi
++	vmov		@ACC[6],@ACC[7]
++	veor		@ACC[7],@ACC[7]
++	vshr.u64	$temp,$temp,#16
++
++	bne	.LNEON_outer8
++
++	vadd.u64	@ACC[0]#lo,@ACC[0]#lo,$temp
++	mov		$toutptr,sp
++	vshr.u64	$temp,@ACC[0]#lo,#16
++	mov		$inner,$num
++	vadd.u64	@ACC[0]#hi,@ACC[0]#hi,$temp
++	add		$tinptr,sp,#96
++	vshr.u64	$temp,@ACC[0]#hi,#16
++	vzip.16		@ACC[0]#lo,@ACC[0]#hi
++
++	b	.LNEON_tail_entry
++
++.align	4
++.LNEON_8n:
++	veor		@ACC[0],@ACC[0],@ACC[0]
++	 sub		$toutptr,sp,#128
++	veor		@ACC[1],@ACC[1],@ACC[1]
++	 sub		$toutptr,$toutptr,$num,lsl#4
++	veor		@ACC[2],@ACC[2],@ACC[2]
++	 and		$toutptr,$toutptr,#-64
++	veor		@ACC[3],@ACC[3],@ACC[3]
++	 mov		sp,$toutptr			@ alloca
++	veor		@ACC[4],@ACC[4],@ACC[4]
++	 add		$toutptr,$toutptr,#256
++	veor		@ACC[5],@ACC[5],@ACC[5]
++	 sub		$inner,$num,#8
++	veor		@ACC[6],@ACC[6],@ACC[6]
++	veor		@ACC[7],@ACC[7],@ACC[7]
++
++.LNEON_8n_init:
++	vst1.64		{@ACC[0]-@ACC[1]},[$toutptr,:256]!
++	subs		$inner,$inner,#8
++	vst1.64		{@ACC[2]-@ACC[3]},[$toutptr,:256]!
++	vst1.64		{@ACC[4]-@ACC[5]},[$toutptr,:256]!
++	vst1.64		{@ACC[6]-@ACC[7]},[$toutptr,:256]!
++	bne		.LNEON_8n_init
++
++	add		$tinptr,sp,#256
++	vld1.32		{$A0-$A3},[$aptr]!
++	add		$bnptr,sp,#8
++	vld1.32		{${M0}[0]},[$n0,:32]
++	mov		$outer,$num
++	b		.LNEON_8n_outer
++
++.align	4
++.LNEON_8n_outer:
++	vld1.32		{${Bi}[0]},[$bptr,:32]!	@ *b++
++	veor		$zero,$zero,$zero
++	vzip.16		$Bi,$zero
++	add		$toutptr,sp,#128
++	vld1.32		{$N0-$N3},[$nptr]!
++
++	vmlal.u32	@ACC[0],$Bi,${A0}[0]
++	vmlal.u32	@ACC[1],$Bi,${A0}[1]
++	 veor		$zero,$zero,$zero
++	vmlal.u32	@ACC[2],$Bi,${A1}[0]
++	 vshl.i64	$Ni,@ACC[0]#hi,#16
++	vmlal.u32	@ACC[3],$Bi,${A1}[1]
++	 vadd.u64	$Ni,$Ni,@ACC[0]#lo
++	vmlal.u32	@ACC[4],$Bi,${A2}[0]
++	 vmul.u32	$Ni,$Ni,$M0
++	vmlal.u32	@ACC[5],$Bi,${A2}[1]
++	vst1.32		{$Bi},[sp,:64]		@ put aside smashed b[8*i+0]
++	vmlal.u32	@ACC[6],$Bi,${A3}[0]
++	 vzip.16	$Ni,$zero
++	vmlal.u32	@ACC[7],$Bi,${A3}[1]
++___
++for ($i=0; $i<7;) {
++$code.=<<___;
++	vld1.32		{${Bi}[0]},[$bptr,:32]!	@ *b++
++	vmlal.u32	@ACC[0],$Ni,${N0}[0]
++	veor		$temp,$temp,$temp
++	vmlal.u32	@ACC[1],$Ni,${N0}[1]
++	vzip.16		$Bi,$temp
++	vmlal.u32	@ACC[2],$Ni,${N1}[0]
++	 vshr.u64	@ACC[0]#lo,@ACC[0]#lo,#16
++	vmlal.u32	@ACC[3],$Ni,${N1}[1]
++	vmlal.u32	@ACC[4],$Ni,${N2}[0]
++	 vadd.u64	@ACC[0]#lo,@ACC[0]#lo,@ACC[0]#hi
++	vmlal.u32	@ACC[5],$Ni,${N2}[1]
++	 vshr.u64	@ACC[0]#lo,@ACC[0]#lo,#16
++	vmlal.u32	@ACC[6],$Ni,${N3}[0]
++	vmlal.u32	@ACC[7],$Ni,${N3}[1]
++	 vadd.u64	@ACC[1]#lo,@ACC[1]#lo,@ACC[0]#lo
++	vst1.32		{$Ni},[$bnptr,:64]!	@ put aside smashed m[8*i+$i]
++___
++	push(@ACC,shift(@ACC));	$i++;
++$code.=<<___;
++	vmlal.u32	@ACC[0],$Bi,${A0}[0]
++	vld1.64		{@ACC[7]},[$tinptr,:128]!
++	vmlal.u32	@ACC[1],$Bi,${A0}[1]
++	 veor		$zero,$zero,$zero
++	vmlal.u32	@ACC[2],$Bi,${A1}[0]
++	 vshl.i64	$Ni,@ACC[0]#hi,#16
++	vmlal.u32	@ACC[3],$Bi,${A1}[1]
++	 vadd.u64	$Ni,$Ni,@ACC[0]#lo
++	vmlal.u32	@ACC[4],$Bi,${A2}[0]
++	 vmul.u32	$Ni,$Ni,$M0
++	vmlal.u32	@ACC[5],$Bi,${A2}[1]
++	vst1.32		{$Bi},[$bnptr,:64]!	@ put aside smashed b[8*i+$i]
++	vmlal.u32	@ACC[6],$Bi,${A3}[0]
++	 vzip.16	$Ni,$zero
++	vmlal.u32	@ACC[7],$Bi,${A3}[1]
++___
++}
++$code.=<<___;
++	vld1.32		{$Bi},[sp,:64]		@ pull smashed b[8*i+0]
++	vmlal.u32	@ACC[0],$Ni,${N0}[0]
++	vld1.32		{$A0-$A3},[$aptr]!
++	vmlal.u32	@ACC[1],$Ni,${N0}[1]
++	vmlal.u32	@ACC[2],$Ni,${N1}[0]
++	 vshr.u64	@ACC[0]#lo,@ACC[0]#lo,#16
++	vmlal.u32	@ACC[3],$Ni,${N1}[1]
++	vmlal.u32	@ACC[4],$Ni,${N2}[0]
++	 vadd.u64	@ACC[0]#lo,@ACC[0]#lo,@ACC[0]#hi
++	vmlal.u32	@ACC[5],$Ni,${N2}[1]
++	 vshr.u64	@ACC[0]#lo,@ACC[0]#lo,#16
++	vmlal.u32	@ACC[6],$Ni,${N3}[0]
++	vmlal.u32	@ACC[7],$Ni,${N3}[1]
++	 vadd.u64	@ACC[1]#lo,@ACC[1]#lo,@ACC[0]#lo
++	vst1.32		{$Ni},[$bnptr,:64]	@ put aside smashed m[8*i+$i]
++	add		$bnptr,sp,#8		@ rewind
++___
++	push(@ACC,shift(@ACC));
++$code.=<<___;
++	sub		$inner,$num,#8
++	b		.LNEON_8n_inner
++
++.align	4
++.LNEON_8n_inner:
++	subs		$inner,$inner,#8
++	vmlal.u32	@ACC[0],$Bi,${A0}[0]
++	vld1.64		{@ACC[7]},[$tinptr,:128]
++	vmlal.u32	@ACC[1],$Bi,${A0}[1]
++	vld1.32		{$Ni},[$bnptr,:64]!	@ pull smashed m[8*i+0]
++	vmlal.u32	@ACC[2],$Bi,${A1}[0]
++	vld1.32		{$N0-$N3},[$nptr]!
++	vmlal.u32	@ACC[3],$Bi,${A1}[1]
++	it		ne
++	addne		$tinptr,$tinptr,#16	@ don't advance in last iteration
++	vmlal.u32	@ACC[4],$Bi,${A2}[0]
++	vmlal.u32	@ACC[5],$Bi,${A2}[1]
++	vmlal.u32	@ACC[6],$Bi,${A3}[0]
++	vmlal.u32	@ACC[7],$Bi,${A3}[1]
++___
++for ($i=1; $i<8; $i++) {
++$code.=<<___;
++	vld1.32		{$Bi},[$bnptr,:64]!	@ pull smashed b[8*i+$i]
++	vmlal.u32	@ACC[0],$Ni,${N0}[0]
++	vmlal.u32	@ACC[1],$Ni,${N0}[1]
++	vmlal.u32	@ACC[2],$Ni,${N1}[0]
++	vmlal.u32	@ACC[3],$Ni,${N1}[1]
++	vmlal.u32	@ACC[4],$Ni,${N2}[0]
++	vmlal.u32	@ACC[5],$Ni,${N2}[1]
++	vmlal.u32	@ACC[6],$Ni,${N3}[0]
++	vmlal.u32	@ACC[7],$Ni,${N3}[1]
++	vst1.64		{@ACC[0]},[$toutptr,:128]!
++___
++	push(@ACC,shift(@ACC));
++$code.=<<___;
++	vmlal.u32	@ACC[0],$Bi,${A0}[0]
++	vld1.64		{@ACC[7]},[$tinptr,:128]
++	vmlal.u32	@ACC[1],$Bi,${A0}[1]
++	vld1.32		{$Ni},[$bnptr,:64]!	@ pull smashed m[8*i+$i]
++	vmlal.u32	@ACC[2],$Bi,${A1}[0]
++	it		ne
++	addne		$tinptr,$tinptr,#16	@ don't advance in last iteration
++	vmlal.u32	@ACC[3],$Bi,${A1}[1]
++	vmlal.u32	@ACC[4],$Bi,${A2}[0]
++	vmlal.u32	@ACC[5],$Bi,${A2}[1]
++	vmlal.u32	@ACC[6],$Bi,${A3}[0]
++	vmlal.u32	@ACC[7],$Bi,${A3}[1]
++___
++}
++$code.=<<___;
++	it		eq
++	subeq		$aptr,$aptr,$num,lsl#2	@ rewind
++	vmlal.u32	@ACC[0],$Ni,${N0}[0]
++	vld1.32		{$Bi},[sp,:64]		@ pull smashed b[8*i+0]
++	vmlal.u32	@ACC[1],$Ni,${N0}[1]
++	vld1.32		{$A0-$A3},[$aptr]!
++	vmlal.u32	@ACC[2],$Ni,${N1}[0]
++	add		$bnptr,sp,#8		@ rewind
++	vmlal.u32	@ACC[3],$Ni,${N1}[1]
++	vmlal.u32	@ACC[4],$Ni,${N2}[0]
++	vmlal.u32	@ACC[5],$Ni,${N2}[1]
++	vmlal.u32	@ACC[6],$Ni,${N3}[0]
++	vst1.64		{@ACC[0]},[$toutptr,:128]!
++	vmlal.u32	@ACC[7],$Ni,${N3}[1]
++
++	bne		.LNEON_8n_inner
++___
++	push(@ACC,shift(@ACC));
++$code.=<<___;
++	add		$tinptr,sp,#128
++	vst1.64		{@ACC[0]-@ACC[1]},[$toutptr,:256]!
++	veor		q2,q2,q2		@ $N0-$N1
++	vst1.64		{@ACC[2]-@ACC[3]},[$toutptr,:256]!
++	veor		q3,q3,q3		@ $N2-$N3
++	vst1.64		{@ACC[4]-@ACC[5]},[$toutptr,:256]!
++	vst1.64		{@ACC[6]},[$toutptr,:128]
++
++	subs		$outer,$outer,#8
++	vld1.64		{@ACC[0]-@ACC[1]},[$tinptr,:256]!
++	vld1.64		{@ACC[2]-@ACC[3]},[$tinptr,:256]!
++	vld1.64		{@ACC[4]-@ACC[5]},[$tinptr,:256]!
++	vld1.64		{@ACC[6]-@ACC[7]},[$tinptr,:256]!
++
++	itt		ne
++	subne		$nptr,$nptr,$num,lsl#2	@ rewind
++	bne		.LNEON_8n_outer
++
++	add		$toutptr,sp,#128
++	vst1.64		{q2-q3}, [sp,:256]!	@ start wiping stack frame
++	vshr.u64	$temp,@ACC[0]#lo,#16
++	vst1.64		{q2-q3},[sp,:256]!
++	vadd.u64	@ACC[0]#hi,@ACC[0]#hi,$temp
++	vst1.64		{q2-q3}, [sp,:256]!
++	vshr.u64	$temp,@ACC[0]#hi,#16
++	vst1.64		{q2-q3}, [sp,:256]!
++	vzip.16		@ACC[0]#lo,@ACC[0]#hi
++
++	mov		$inner,$num
++	b		.LNEON_tail_entry
++
++.align	4
++.LNEON_tail:
++	vadd.u64	@ACC[0]#lo,@ACC[0]#lo,$temp
++	vshr.u64	$temp,@ACC[0]#lo,#16
++	vld1.64		{@ACC[2]-@ACC[3]}, [$tinptr, :256]!
++	vadd.u64	@ACC[0]#hi,@ACC[0]#hi,$temp
++	vld1.64		{@ACC[4]-@ACC[5]}, [$tinptr, :256]!
++	vshr.u64	$temp,@ACC[0]#hi,#16
++	vld1.64		{@ACC[6]-@ACC[7]}, [$tinptr, :256]!
++	vzip.16		@ACC[0]#lo,@ACC[0]#hi
++
++.LNEON_tail_entry:
++___
++for ($i=1; $i<8; $i++) {
++$code.=<<___;
++	vadd.u64	@ACC[1]#lo,@ACC[1]#lo,$temp
++	vst1.32		{@ACC[0]#lo[0]}, [$toutptr, :32]!
++	vshr.u64	$temp,@ACC[1]#lo,#16
++	vadd.u64	@ACC[1]#hi,@ACC[1]#hi,$temp
++	vshr.u64	$temp,@ACC[1]#hi,#16
++	vzip.16		@ACC[1]#lo,@ACC[1]#hi
++___
++	push(@ACC,shift(@ACC));
++}
++	push(@ACC,shift(@ACC));
++$code.=<<___;
++	vld1.64		{@ACC[0]-@ACC[1]}, [$tinptr, :256]!
++	subs		$inner,$inner,#8
++	vst1.32		{@ACC[7]#lo[0]},   [$toutptr, :32]!
++	bne	.LNEON_tail
++
++	vst1.32	{${temp}[0]}, [$toutptr, :32]		@ top-most bit
++	sub	$nptr,$nptr,$num,lsl#2			@ rewind $nptr
++	subs	$aptr,sp,#0				@ clear carry flag
++	add	$bptr,sp,$num,lsl#2
++
++.LNEON_sub:
++	ldmia	$aptr!, {r4-r7}
++	ldmia	$nptr!, {r8-r11}
++	sbcs	r8, r4,r8
++	sbcs	r9, r5,r9
++	sbcs	r10,r6,r10
++	sbcs	r11,r7,r11
++	teq	$aptr,$bptr				@ preserves carry
++	stmia	$rptr!, {r8-r11}
++	bne	.LNEON_sub
++
++	ldr	r10, [$aptr]				@ load top-most bit
++	mov	r11,sp
++	veor	q0,q0,q0
++	sub	r11,$bptr,r11				@ this is num*4
++	veor	q1,q1,q1
++	mov	$aptr,sp
++	sub	$rptr,$rptr,r11				@ rewind $rptr
++	mov	$nptr,$bptr				@ second 3/4th of frame
++	sbcs	r10,r10,#0				@ result is carry flag
++
++.LNEON_copy_n_zap:
++	ldmia	$aptr!, {r4-r7}
++	ldmia	$rptr,  {r8-r11}
++	it	cc
++	movcc	r8, r4
++	vst1.64	{q0-q1}, [$nptr,:256]!			@ wipe
++	itt	cc
++	movcc	r9, r5
++	movcc	r10,r6
++	vst1.64	{q0-q1}, [$nptr,:256]!			@ wipe
++	it	cc
++	movcc	r11,r7
++	ldmia	$aptr, {r4-r7}
++	stmia	$rptr!, {r8-r11}
++	sub	$aptr,$aptr,#16
++	ldmia	$rptr, {r8-r11}
++	it	cc
++	movcc	r8, r4
++	vst1.64	{q0-q1}, [$aptr,:256]!			@ wipe
++	itt	cc
++	movcc	r9, r5
++	movcc	r10,r6
++	vst1.64	{q0-q1}, [$nptr,:256]!			@ wipe
++	it	cc
++	movcc	r11,r7
++	teq	$aptr,$bptr				@ preserves carry
++	stmia	$rptr!, {r8-r11}
++	bne	.LNEON_copy_n_zap
++
++	mov	sp,ip
++        vldmia  sp!,{d8-d15}
++        ldmia   sp!,{r4-r11}
++	ret						@ bx lr
++.size	bn_mul8x_mont_neon,.-bn_mul8x_mont_neon
++#endif
++___
++}
++$code.=<<___;
++.asciz	"Montgomery multiplication for ARMv4/NEON, CRYPTOGAMS by "
++.align	2
++#if __ARM_MAX_ARCH__>=7
++.comm	OPENSSL_armcap_P,4,4
++#endif
++___
++
++foreach (split("\n",$code)) {
++	s/\`([^\`]*)\`/eval $1/ge;
++
++	s/\bq([0-9]+)#(lo|hi)/sprintf "d%d",2*$1+($2 eq "hi")/ge	or
++	s/\bret\b/bx    lr/g						or
++	s/\bbx\s+lr\b/.word\t0xe12fff1e/g;	# make it possible to compile with -march=armv4
++
++	print $_,"\n";
++}
++
++close STDOUT;
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/bn/asm/armv8-mont.pl b/CryptoPkg/Library/OpensslLib/openssl/crypto/bn/asm/armv8-mont.pl
+new file mode 100755
+index 0000000..5d5af1b
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/bn/asm/armv8-mont.pl
+@@ -0,0 +1,1510 @@
++#! /usr/bin/env perl
++# Copyright 2015-2016 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
++# in the file LICENSE in the source distribution or at
++# https://www.openssl.org/source/license.html
++
++
++# ====================================================================
++# Written by Andy Polyakov  for the OpenSSL
++# project. The module is, however, dual licensed under OpenSSL and
++# CRYPTOGAMS licenses depending on where you obtain it. For further
++# details see http://www.openssl.org/~appro/cryptogams/.
++# ====================================================================
++
++# March 2015
++#
++# "Teaser" Montgomery multiplication module for ARMv8. Needs more
++# work. While it does improve RSA sign performance by 20-30% (less for
++# longer keys) on most processors, for some reason RSA2048 is not
++# faster and RSA4096 goes 15-20% slower on Cortex-A57. Multiplication
++# instruction issue rate is limited on processor in question, meaning
++# that dedicated squaring procedure is a must. Well, actually all
++# contemporary AArch64 processors seem to have limited multiplication
++# issue rate, i.e. they can't issue multiplication every cycle, which
++# explains moderate improvement coefficients in comparison to
++# compiler-generated code. Recall that compiler is instructed to use
++# umulh and therefore uses same amount of multiplication instructions
++# to do the job. Assembly's edge is to minimize number of "collateral"
++# instructions and of course instruction scheduling.
++#
++# April 2015
++#
++# Squaring procedure that handles lengths divisible by 8 improves
++# RSA/DSA performance by 25-40-60% depending on processor and key
++# length. Overall improvement coefficients are always positive in
++# comparison to compiler-generated code. On Cortex-A57 improvement
++# is still modest on longest key lengths, while others exhibit e.g.
++# 50-70% improvement for RSA4096 sign. RSA2048 sign is ~25% faster
++# on Cortex-A57 and ~60-100% faster on others.
++
++$flavour = shift;
++$output  = shift;
++
++$0 =~ m/(.*[\/\\])[^\/\\]+$/; $dir=$1;
++( $xlate="${dir}arm-xlate.pl" and -f $xlate ) or
++( $xlate="${dir}../../perlasm/arm-xlate.pl" and -f $xlate) or
++die "can't locate arm-xlate.pl";
++
++open OUT,"| \"$^X\" $xlate $flavour $output";
++*STDOUT=*OUT;
++
++($lo0,$hi0,$aj,$m0,$alo,$ahi,
++ $lo1,$hi1,$nj,$m1,$nlo,$nhi,
++ $ovf, $i,$j,$tp,$tj) = map("x$_",6..17,19..24);
++
++# int bn_mul_mont(
++$rp="x0";	# BN_ULONG *rp,
++$ap="x1";	# const BN_ULONG *ap,
++$bp="x2";	# const BN_ULONG *bp,
++$np="x3";	# const BN_ULONG *np,
++$n0="x4";	# const BN_ULONG *n0,
++$num="x5";	# int num);
++
++$code.=<<___;
++.text
++
++.globl	bn_mul_mont
++.type	bn_mul_mont,%function
++.align	5
++bn_mul_mont:
++	tst	$num,#7
++	b.eq	__bn_sqr8x_mont
++	tst	$num,#3
++	b.eq	__bn_mul4x_mont
++.Lmul_mont:
++	stp	x29,x30,[sp,#-64]!
++	add	x29,sp,#0
++	stp	x19,x20,[sp,#16]
++	stp	x21,x22,[sp,#32]
++	stp	x23,x24,[sp,#48]
++
++	ldr	$m0,[$bp],#8		// bp[0]
++	sub	$tp,sp,$num,lsl#3
++	ldp	$hi0,$aj,[$ap],#16	// ap[0..1]
++	lsl	$num,$num,#3
++	ldr	$n0,[$n0]		// *n0
++	and	$tp,$tp,#-16		// ABI says so
++	ldp	$hi1,$nj,[$np],#16	// np[0..1]
++
++	mul	$lo0,$hi0,$m0		// ap[0]*bp[0]
++	sub	$j,$num,#16		// j=num-2
++	umulh	$hi0,$hi0,$m0
++	mul	$alo,$aj,$m0		// ap[1]*bp[0]
++	umulh	$ahi,$aj,$m0
++
++	mul	$m1,$lo0,$n0		// "tp[0]"*n0
++	mov	sp,$tp			// alloca
++
++	// (*)	mul	$lo1,$hi1,$m1	// np[0]*m1
++	umulh	$hi1,$hi1,$m1
++	mul	$nlo,$nj,$m1		// np[1]*m1
++	// (*)	adds	$lo1,$lo1,$lo0	// discarded
++	// (*)	As for removal of first multiplication and addition
++	//	instructions. The outcome of first addition is
++	//	guaranteed to be zero, which leaves two computationally
++	//	significant outcomes: it either carries or not. Then
++	//	question is when does it carry? Is there alternative
++	//	way to deduce it? If you follow operations, you can
++	//	observe that condition for carry is quite simple:
++	//	$lo0 being non-zero. So that carry can be calculated
++	//	by adding -1 to $lo0. That's what next instruction does.
++	subs	xzr,$lo0,#1		// (*)
++	umulh	$nhi,$nj,$m1
++	adc	$hi1,$hi1,xzr
++	cbz	$j,.L1st_skip
++
++.L1st:
++	ldr	$aj,[$ap],#8
++	adds	$lo0,$alo,$hi0
++	sub	$j,$j,#8		// j--
++	adc	$hi0,$ahi,xzr
++
++	ldr	$nj,[$np],#8
++	adds	$lo1,$nlo,$hi1
++	mul	$alo,$aj,$m0		// ap[j]*bp[0]
++	adc	$hi1,$nhi,xzr
++	umulh	$ahi,$aj,$m0
++
++	adds	$lo1,$lo1,$lo0
++	mul	$nlo,$nj,$m1		// np[j]*m1
++	adc	$hi1,$hi1,xzr
++	umulh	$nhi,$nj,$m1
++	str	$lo1,[$tp],#8		// tp[j-1]
++	cbnz	$j,.L1st
++
++.L1st_skip:
++	adds	$lo0,$alo,$hi0
++	sub	$ap,$ap,$num		// rewind $ap
++	adc	$hi0,$ahi,xzr
++
++	adds	$lo1,$nlo,$hi1
++	sub	$np,$np,$num		// rewind $np
++	adc	$hi1,$nhi,xzr
++
++	adds	$lo1,$lo1,$lo0
++	sub	$i,$num,#8		// i=num-1
++	adcs	$hi1,$hi1,$hi0
++
++	adc	$ovf,xzr,xzr		// upmost overflow bit
++	stp	$lo1,$hi1,[$tp]
++
++.Louter:
++	ldr	$m0,[$bp],#8		// bp[i]
++	ldp	$hi0,$aj,[$ap],#16
++	ldr	$tj,[sp]		// tp[0]
++	add	$tp,sp,#8
++
++	mul	$lo0,$hi0,$m0		// ap[0]*bp[i]
++	sub	$j,$num,#16		// j=num-2
++	umulh	$hi0,$hi0,$m0
++	ldp	$hi1,$nj,[$np],#16
++	mul	$alo,$aj,$m0		// ap[1]*bp[i]
++	adds	$lo0,$lo0,$tj
++	umulh	$ahi,$aj,$m0
++	adc	$hi0,$hi0,xzr
++
++	mul	$m1,$lo0,$n0
++	sub	$i,$i,#8		// i--
++
++	// (*)	mul	$lo1,$hi1,$m1	// np[0]*m1
++	umulh	$hi1,$hi1,$m1
++	mul	$nlo,$nj,$m1		// np[1]*m1
++	// (*)	adds	$lo1,$lo1,$lo0
++	subs	xzr,$lo0,#1		// (*)
++	umulh	$nhi,$nj,$m1
++	cbz	$j,.Linner_skip
++
++.Linner:
++	ldr	$aj,[$ap],#8
++	adc	$hi1,$hi1,xzr
++	ldr	$tj,[$tp],#8		// tp[j]
++	adds	$lo0,$alo,$hi0
++	sub	$j,$j,#8		// j--
++	adc	$hi0,$ahi,xzr
++
++	adds	$lo1,$nlo,$hi1
++	ldr	$nj,[$np],#8
++	adc	$hi1,$nhi,xzr
++
++	mul	$alo,$aj,$m0		// ap[j]*bp[i]
++	adds	$lo0,$lo0,$tj
++	umulh	$ahi,$aj,$m0
++	adc	$hi0,$hi0,xzr
++
++	mul	$nlo,$nj,$m1		// np[j]*m1
++	adds	$lo1,$lo1,$lo0
++	umulh	$nhi,$nj,$m1
++	str	$lo1,[$tp,#-16]		// tp[j-1]
++	cbnz	$j,.Linner
++
++.Linner_skip:
++	ldr	$tj,[$tp],#8		// tp[j]
++	adc	$hi1,$hi1,xzr
++	adds	$lo0,$alo,$hi0
++	sub	$ap,$ap,$num		// rewind $ap
++	adc	$hi0,$ahi,xzr
++
++	adds	$lo1,$nlo,$hi1
++	sub	$np,$np,$num		// rewind $np
++	adcs	$hi1,$nhi,$ovf
++	adc	$ovf,xzr,xzr
++
++	adds	$lo0,$lo0,$tj
++	adc	$hi0,$hi0,xzr
++
++	adds	$lo1,$lo1,$lo0
++	adcs	$hi1,$hi1,$hi0
++	adc	$ovf,$ovf,xzr		// upmost overflow bit
++	stp	$lo1,$hi1,[$tp,#-16]
++
++	cbnz	$i,.Louter
++
++	// Final step. We see if result is larger than modulus, and
++	// if it is, subtract the modulus. But comparison implies
++	// subtraction. So we subtract modulus, see if it borrowed,
++	// and conditionally copy original value.
++	ldr	$tj,[sp]		// tp[0]
++	add	$tp,sp,#8
++	ldr	$nj,[$np],#8		// np[0]
++	subs	$j,$num,#8		// j=num-1 and clear borrow
++	mov	$ap,$rp
++.Lsub:
++	sbcs	$aj,$tj,$nj		// tp[j]-np[j]
++	ldr	$tj,[$tp],#8
++	sub	$j,$j,#8		// j--
++	ldr	$nj,[$np],#8
++	str	$aj,[$ap],#8		// rp[j]=tp[j]-np[j]
++	cbnz	$j,.Lsub
++
++	sbcs	$aj,$tj,$nj
++	sbcs	$ovf,$ovf,xzr		// did it borrow?
++	str	$aj,[$ap],#8		// rp[num-1]
++
++	ldr	$tj,[sp]		// tp[0]
++	add	$tp,sp,#8
++	ldr	$aj,[$rp],#8		// rp[0]
++	sub	$num,$num,#8		// num--
++	nop
++.Lcond_copy:
++	sub	$num,$num,#8		// num--
++	csel	$nj,$tj,$aj,lo		// did it borrow?
++	ldr	$tj,[$tp],#8
++	ldr	$aj,[$rp],#8
++	str	xzr,[$tp,#-16]		// wipe tp
++	str	$nj,[$rp,#-16]
++	cbnz	$num,.Lcond_copy
++
++	csel	$nj,$tj,$aj,lo
++	str	xzr,[$tp,#-8]		// wipe tp
++	str	$nj,[$rp,#-8]
++
++	ldp	x19,x20,[x29,#16]
++	mov	sp,x29
++	ldp	x21,x22,[x29,#32]
++	mov	x0,#1
++	ldp	x23,x24,[x29,#48]
++	ldr	x29,[sp],#64
++	ret
++.size	bn_mul_mont,.-bn_mul_mont
++___
++{
++########################################################################
++# Following is ARMv8 adaptation of sqrx8x_mont from x86_64-mont5 module.
++
++my ($a0,$a1,$a2,$a3,$a4,$a5,$a6,$a7)=map("x$_",(6..13));
++my ($t0,$t1,$t2,$t3)=map("x$_",(14..17));
++my ($acc0,$acc1,$acc2,$acc3,$acc4,$acc5,$acc6,$acc7)=map("x$_",(19..26));
++my ($cnt,$carry,$topmost)=("x27","x28","x30");
++my ($tp,$ap_end,$na0)=($bp,$np,$carry);
++
++$code.=<<___;
++.type	__bn_sqr8x_mont,%function
++.align	5
++__bn_sqr8x_mont:
++	cmp	$ap,$bp
++	b.ne	__bn_mul4x_mont
++.Lsqr8x_mont:
++	stp	x29,x30,[sp,#-128]!
++	add	x29,sp,#0
++	stp	x19,x20,[sp,#16]
++	stp	x21,x22,[sp,#32]
++	stp	x23,x24,[sp,#48]
++	stp	x25,x26,[sp,#64]
++	stp	x27,x28,[sp,#80]
++	stp	$rp,$np,[sp,#96]	// offload rp and np
++
++	ldp	$a0,$a1,[$ap,#8*0]
++	ldp	$a2,$a3,[$ap,#8*2]
++	ldp	$a4,$a5,[$ap,#8*4]
++	ldp	$a6,$a7,[$ap,#8*6]
++
++	sub	$tp,sp,$num,lsl#4
++	lsl	$num,$num,#3
++	ldr	$n0,[$n0]		// *n0
++	mov	sp,$tp			// alloca
++	sub	$cnt,$num,#8*8
++	b	.Lsqr8x_zero_start
++
++.Lsqr8x_zero:
++	sub	$cnt,$cnt,#8*8
++	stp	xzr,xzr,[$tp,#8*0]
++	stp	xzr,xzr,[$tp,#8*2]
++	stp	xzr,xzr,[$tp,#8*4]
++	stp	xzr,xzr,[$tp,#8*6]
++.Lsqr8x_zero_start:
++	stp	xzr,xzr,[$tp,#8*8]
++	stp	xzr,xzr,[$tp,#8*10]
++	stp	xzr,xzr,[$tp,#8*12]
++	stp	xzr,xzr,[$tp,#8*14]
++	add	$tp,$tp,#8*16
++	cbnz	$cnt,.Lsqr8x_zero
++
++	add	$ap_end,$ap,$num
++	add	$ap,$ap,#8*8
++	mov	$acc0,xzr
++	mov	$acc1,xzr
++	mov	$acc2,xzr
++	mov	$acc3,xzr
++	mov	$acc4,xzr
++	mov	$acc5,xzr
++	mov	$acc6,xzr
++	mov	$acc7,xzr
++	mov	$tp,sp
++	str	$n0,[x29,#112]		// offload n0
++
++	// Multiply everything but a[i]*a[i]
++.align	4
++.Lsqr8x_outer_loop:
++        //                                                 a[1]a[0]	(i)
++        //                                             a[2]a[0]
++        //                                         a[3]a[0]
++        //                                     a[4]a[0]
++        //                                 a[5]a[0]
++        //                             a[6]a[0]
++        //                         a[7]a[0]
++        //                                         a[2]a[1]		(ii)
++        //                                     a[3]a[1]
++        //                                 a[4]a[1]
++        //                             a[5]a[1]
++        //                         a[6]a[1]
++        //                     a[7]a[1]
++        //                                 a[3]a[2]			(iii)
++        //                             a[4]a[2]
++        //                         a[5]a[2]
++        //                     a[6]a[2]
++        //                 a[7]a[2]
++        //                         a[4]a[3]				(iv)
++        //                     a[5]a[3]
++        //                 a[6]a[3]
++        //             a[7]a[3]
++        //                 a[5]a[4]					(v)
++        //             a[6]a[4]
++        //         a[7]a[4]
++        //         a[6]a[5]						(vi)
++        //     a[7]a[5]
++        // a[7]a[6]							(vii)
++
++	mul	$t0,$a1,$a0		// lo(a[1..7]*a[0])		(i)
++	mul	$t1,$a2,$a0
++	mul	$t2,$a3,$a0
++	mul	$t3,$a4,$a0
++	adds	$acc1,$acc1,$t0		// t[1]+lo(a[1]*a[0])
++	mul	$t0,$a5,$a0
++	adcs	$acc2,$acc2,$t1
++	mul	$t1,$a6,$a0
++	adcs	$acc3,$acc3,$t2
++	mul	$t2,$a7,$a0
++	adcs	$acc4,$acc4,$t3
++	umulh	$t3,$a1,$a0		// hi(a[1..7]*a[0])
++	adcs	$acc5,$acc5,$t0
++	umulh	$t0,$a2,$a0
++	adcs	$acc6,$acc6,$t1
++	umulh	$t1,$a3,$a0
++	adcs	$acc7,$acc7,$t2
++	umulh	$t2,$a4,$a0
++	stp	$acc0,$acc1,[$tp],#8*2	// t[0..1]
++	adc	$acc0,xzr,xzr		// t[8]
++	adds	$acc2,$acc2,$t3		// t[2]+lo(a[1]*a[0])
++	umulh	$t3,$a5,$a0
++	adcs	$acc3,$acc3,$t0
++	umulh	$t0,$a6,$a0
++	adcs	$acc4,$acc4,$t1
++	umulh	$t1,$a7,$a0
++	adcs	$acc5,$acc5,$t2
++	 mul	$t2,$a2,$a1		// lo(a[2..7]*a[1])		(ii)
++	adcs	$acc6,$acc6,$t3
++	 mul	$t3,$a3,$a1
++	adcs	$acc7,$acc7,$t0
++	 mul	$t0,$a4,$a1
++	adc	$acc0,$acc0,$t1
++
++	mul	$t1,$a5,$a1
++	adds	$acc3,$acc3,$t2
++	mul	$t2,$a6,$a1
++	adcs	$acc4,$acc4,$t3
++	mul	$t3,$a7,$a1
++	adcs	$acc5,$acc5,$t0
++	umulh	$t0,$a2,$a1		// hi(a[2..7]*a[1])
++	adcs	$acc6,$acc6,$t1
++	umulh	$t1,$a3,$a1
++	adcs	$acc7,$acc7,$t2
++	umulh	$t2,$a4,$a1
++	adcs	$acc0,$acc0,$t3
++	umulh	$t3,$a5,$a1
++	stp	$acc2,$acc3,[$tp],#8*2	// t[2..3]
++	adc	$acc1,xzr,xzr		// t[9]
++	adds	$acc4,$acc4,$t0
++	umulh	$t0,$a6,$a1
++	adcs	$acc5,$acc5,$t1
++	umulh	$t1,$a7,$a1
++	adcs	$acc6,$acc6,$t2
++	 mul	$t2,$a3,$a2		// lo(a[3..7]*a[2])		(iii)
++	adcs	$acc7,$acc7,$t3
++	 mul	$t3,$a4,$a2
++	adcs	$acc0,$acc0,$t0
++	 mul	$t0,$a5,$a2
++	adc	$acc1,$acc1,$t1
++
++	mul	$t1,$a6,$a2
++	adds	$acc5,$acc5,$t2
++	mul	$t2,$a7,$a2
++	adcs	$acc6,$acc6,$t3
++	umulh	$t3,$a3,$a2		// hi(a[3..7]*a[2])
++	adcs	$acc7,$acc7,$t0
++	umulh	$t0,$a4,$a2
++	adcs	$acc0,$acc0,$t1
++	umulh	$t1,$a5,$a2
++	adcs	$acc1,$acc1,$t2
++	umulh	$t2,$a6,$a2
++	stp	$acc4,$acc5,[$tp],#8*2	// t[4..5]
++	adc	$acc2,xzr,xzr		// t[10]
++	adds	$acc6,$acc6,$t3
++	umulh	$t3,$a7,$a2
++	adcs	$acc7,$acc7,$t0
++	 mul	$t0,$a4,$a3		// lo(a[4..7]*a[3])		(iv)
++	adcs	$acc0,$acc0,$t1
++	 mul	$t1,$a5,$a3
++	adcs	$acc1,$acc1,$t2
++	 mul	$t2,$a6,$a3
++	adc	$acc2,$acc2,$t3
++
++	mul	$t3,$a7,$a3
++	adds	$acc7,$acc7,$t0
++	umulh	$t0,$a4,$a3		// hi(a[4..7]*a[3])
++	adcs	$acc0,$acc0,$t1
++	umulh	$t1,$a5,$a3
++	adcs	$acc1,$acc1,$t2
++	umulh	$t2,$a6,$a3
++	adcs	$acc2,$acc2,$t3
++	umulh	$t3,$a7,$a3
++	stp	$acc6,$acc7,[$tp],#8*2	// t[6..7]
++	adc	$acc3,xzr,xzr		// t[11]
++	adds	$acc0,$acc0,$t0
++	 mul	$t0,$a5,$a4		// lo(a[5..7]*a[4])		(v)
++	adcs	$acc1,$acc1,$t1
++	 mul	$t1,$a6,$a4
++	adcs	$acc2,$acc2,$t2
++	 mul	$t2,$a7,$a4
++	adc	$acc3,$acc3,$t3
++
++	umulh	$t3,$a5,$a4		// hi(a[5..7]*a[4])
++	adds	$acc1,$acc1,$t0
++	umulh	$t0,$a6,$a4
++	adcs	$acc2,$acc2,$t1
++	umulh	$t1,$a7,$a4
++	adcs	$acc3,$acc3,$t2
++	 mul	$t2,$a6,$a5		// lo(a[6..7]*a[5])		(vi)
++	adc	$acc4,xzr,xzr		// t[12]
++	adds	$acc2,$acc2,$t3
++	 mul	$t3,$a7,$a5
++	adcs	$acc3,$acc3,$t0
++	 umulh	$t0,$a6,$a5		// hi(a[6..7]*a[5])
++	adc	$acc4,$acc4,$t1
++
++	umulh	$t1,$a7,$a5
++	adds	$acc3,$acc3,$t2
++	 mul	$t2,$a7,$a6		// lo(a[7]*a[6])		(vii)
++	adcs	$acc4,$acc4,$t3
++	 umulh	$t3,$a7,$a6		// hi(a[7]*a[6])
++	adc	$acc5,xzr,xzr		// t[13]
++	adds	$acc4,$acc4,$t0
++	sub	$cnt,$ap_end,$ap	// done yet?
++	adc	$acc5,$acc5,$t1
++
++	adds	$acc5,$acc5,$t2
++	sub	$t0,$ap_end,$num	// rewinded ap
++	adc	$acc6,xzr,xzr		// t[14]
++	add	$acc6,$acc6,$t3
++
++	cbz	$cnt,.Lsqr8x_outer_break
++
++	mov	$n0,$a0
++	ldp	$a0,$a1,[$tp,#8*0]
++	ldp	$a2,$a3,[$tp,#8*2]
++	ldp	$a4,$a5,[$tp,#8*4]
++	ldp	$a6,$a7,[$tp,#8*6]
++	adds	$acc0,$acc0,$a0
++	adcs	$acc1,$acc1,$a1
++	ldp	$a0,$a1,[$ap,#8*0]
++	adcs	$acc2,$acc2,$a2
++	adcs	$acc3,$acc3,$a3
++	ldp	$a2,$a3,[$ap,#8*2]
++	adcs	$acc4,$acc4,$a4
++	adcs	$acc5,$acc5,$a5
++	ldp	$a4,$a5,[$ap,#8*4]
++	adcs	$acc6,$acc6,$a6
++	mov	$rp,$ap
++	adcs	$acc7,xzr,$a7
++	ldp	$a6,$a7,[$ap,#8*6]
++	add	$ap,$ap,#8*8
++	//adc	$carry,xzr,xzr		// moved below
++	mov	$cnt,#-8*8
++
++	//                                                         a[8]a[0]
++	//                                                     a[9]a[0]
++	//                                                 a[a]a[0]
++	//                                             a[b]a[0]
++	//                                         a[c]a[0]
++	//                                     a[d]a[0]
++	//                                 a[e]a[0]
++	//                             a[f]a[0]
++	//                                                     a[8]a[1]
++	//                         a[f]a[1]........................
++	//                                                 a[8]a[2]
++	//                     a[f]a[2]........................
++	//                                             a[8]a[3]
++	//                 a[f]a[3]........................
++	//                                         a[8]a[4]
++	//             a[f]a[4]........................
++	//                                     a[8]a[5]
++	//         a[f]a[5]........................
++	//                                 a[8]a[6]
++	//     a[f]a[6]........................
++	//                             a[8]a[7]
++	// a[f]a[7]........................
++.Lsqr8x_mul:
++	mul	$t0,$a0,$n0
++	adc	$carry,xzr,xzr		// carry bit, modulo-scheduled
++	mul	$t1,$a1,$n0
++	add	$cnt,$cnt,#8
++	mul	$t2,$a2,$n0
++	mul	$t3,$a3,$n0
++	adds	$acc0,$acc0,$t0
++	mul	$t0,$a4,$n0
++	adcs	$acc1,$acc1,$t1
++	mul	$t1,$a5,$n0
++	adcs	$acc2,$acc2,$t2
++	mul	$t2,$a6,$n0
++	adcs	$acc3,$acc3,$t3
++	mul	$t3,$a7,$n0
++	adcs	$acc4,$acc4,$t0
++	umulh	$t0,$a0,$n0
++	adcs	$acc5,$acc5,$t1
++	umulh	$t1,$a1,$n0
++	adcs	$acc6,$acc6,$t2
++	umulh	$t2,$a2,$n0
++	adcs	$acc7,$acc7,$t3
++	umulh	$t3,$a3,$n0
++	adc	$carry,$carry,xzr
++	str	$acc0,[$tp],#8
++	adds	$acc0,$acc1,$t0
++	umulh	$t0,$a4,$n0
++	adcs	$acc1,$acc2,$t1
++	umulh	$t1,$a5,$n0
++	adcs	$acc2,$acc3,$t2
++	umulh	$t2,$a6,$n0
++	adcs	$acc3,$acc4,$t3
++	umulh	$t3,$a7,$n0
++	ldr	$n0,[$rp,$cnt]
++	adcs	$acc4,$acc5,$t0
++	adcs	$acc5,$acc6,$t1
++	adcs	$acc6,$acc7,$t2
++	adcs	$acc7,$carry,$t3
++	//adc	$carry,xzr,xzr		// moved above
++	cbnz	$cnt,.Lsqr8x_mul
++					// note that carry flag is guaranteed
++					// to be zero at this point
++	cmp	$ap,$ap_end		// done yet?
++	b.eq	.Lsqr8x_break
++
++	ldp	$a0,$a1,[$tp,#8*0]
++	ldp	$a2,$a3,[$tp,#8*2]
++	ldp	$a4,$a5,[$tp,#8*4]
++	ldp	$a6,$a7,[$tp,#8*6]
++	adds	$acc0,$acc0,$a0
++	ldr	$n0,[$rp,#-8*8]
++	adcs	$acc1,$acc1,$a1
++	ldp	$a0,$a1,[$ap,#8*0]
++	adcs	$acc2,$acc2,$a2
++	adcs	$acc3,$acc3,$a3
++	ldp	$a2,$a3,[$ap,#8*2]
++	adcs	$acc4,$acc4,$a4
++	adcs	$acc5,$acc5,$a5
++	ldp	$a4,$a5,[$ap,#8*4]
++	adcs	$acc6,$acc6,$a6
++	mov	$cnt,#-8*8
++	adcs	$acc7,$acc7,$a7
++	ldp	$a6,$a7,[$ap,#8*6]
++	add	$ap,$ap,#8*8
++	//adc	$carry,xzr,xzr		// moved above
++	b	.Lsqr8x_mul
++
++.align	4
++.Lsqr8x_break:
++	ldp	$a0,$a1,[$rp,#8*0]
++	add	$ap,$rp,#8*8
++	ldp	$a2,$a3,[$rp,#8*2]
++	sub	$t0,$ap_end,$ap		// is it last iteration?
++	ldp	$a4,$a5,[$rp,#8*4]
++	sub	$t1,$tp,$t0
++	ldp	$a6,$a7,[$rp,#8*6]
++	cbz	$t0,.Lsqr8x_outer_loop
++
++	stp	$acc0,$acc1,[$tp,#8*0]
++	ldp	$acc0,$acc1,[$t1,#8*0]
++	stp	$acc2,$acc3,[$tp,#8*2]
++	ldp	$acc2,$acc3,[$t1,#8*2]
++	stp	$acc4,$acc5,[$tp,#8*4]
++	ldp	$acc4,$acc5,[$t1,#8*4]
++	stp	$acc6,$acc7,[$tp,#8*6]
++	mov	$tp,$t1
++	ldp	$acc6,$acc7,[$t1,#8*6]
++	b	.Lsqr8x_outer_loop
++
++.align	4
++.Lsqr8x_outer_break:
++	// Now multiply above result by 2 and add a[n-1]*a[n-1]|...|a[0]*a[0]
++	ldp	$a1,$a3,[$t0,#8*0]	// recall that $t0 is &a[0]
++	ldp	$t1,$t2,[sp,#8*1]
++	ldp	$a5,$a7,[$t0,#8*2]
++	add	$ap,$t0,#8*4
++	ldp	$t3,$t0,[sp,#8*3]
++
++	stp	$acc0,$acc1,[$tp,#8*0]
++	mul	$acc0,$a1,$a1
++	stp	$acc2,$acc3,[$tp,#8*2]
++	umulh	$a1,$a1,$a1
++	stp	$acc4,$acc5,[$tp,#8*4]
++	mul	$a2,$a3,$a3
++	stp	$acc6,$acc7,[$tp,#8*6]
++	mov	$tp,sp
++	umulh	$a3,$a3,$a3
++	adds	$acc1,$a1,$t1,lsl#1
++	extr	$t1,$t2,$t1,#63
++	sub	$cnt,$num,#8*4
++
++.Lsqr4x_shift_n_add:
++	adcs	$acc2,$a2,$t1
++	extr	$t2,$t3,$t2,#63
++	sub	$cnt,$cnt,#8*4
++	adcs	$acc3,$a3,$t2
++	ldp	$t1,$t2,[$tp,#8*5]
++	mul	$a4,$a5,$a5
++	ldp	$a1,$a3,[$ap],#8*2
++	umulh	$a5,$a5,$a5
++	mul	$a6,$a7,$a7
++	umulh	$a7,$a7,$a7
++	extr	$t3,$t0,$t3,#63
++	stp	$acc0,$acc1,[$tp,#8*0]
++	adcs	$acc4,$a4,$t3
++	extr	$t0,$t1,$t0,#63
++	stp	$acc2,$acc3,[$tp,#8*2]
++	adcs	$acc5,$a5,$t0
++	ldp	$t3,$t0,[$tp,#8*7]
++	extr	$t1,$t2,$t1,#63
++	adcs	$acc6,$a6,$t1
++	extr	$t2,$t3,$t2,#63
++	adcs	$acc7,$a7,$t2
++	ldp	$t1,$t2,[$tp,#8*9]
++	mul	$a0,$a1,$a1
++	ldp	$a5,$a7,[$ap],#8*2
++	umulh	$a1,$a1,$a1
++	mul	$a2,$a3,$a3
++	umulh	$a3,$a3,$a3
++	stp	$acc4,$acc5,[$tp,#8*4]
++	extr	$t3,$t0,$t3,#63
++	stp	$acc6,$acc7,[$tp,#8*6]
++	add	$tp,$tp,#8*8
++	adcs	$acc0,$a0,$t3
++	extr	$t0,$t1,$t0,#63
++	adcs	$acc1,$a1,$t0
++	ldp	$t3,$t0,[$tp,#8*3]
++	extr	$t1,$t2,$t1,#63
++	cbnz	$cnt,.Lsqr4x_shift_n_add
++___
++my ($np,$np_end)=($ap,$ap_end);
++$code.=<<___;
++	 ldp	$np,$n0,[x29,#104]	// pull np and n0
++
++	adcs	$acc2,$a2,$t1
++	extr	$t2,$t3,$t2,#63
++	adcs	$acc3,$a3,$t2
++	ldp	$t1,$t2,[$tp,#8*5]
++	mul	$a4,$a5,$a5
++	umulh	$a5,$a5,$a5
++	stp	$acc0,$acc1,[$tp,#8*0]
++	mul	$a6,$a7,$a7
++	umulh	$a7,$a7,$a7
++	stp	$acc2,$acc3,[$tp,#8*2]
++	extr	$t3,$t0,$t3,#63
++	adcs	$acc4,$a4,$t3
++	extr	$t0,$t1,$t0,#63
++	 ldp	$acc0,$acc1,[sp,#8*0]
++	adcs	$acc5,$a5,$t0
++	extr	$t1,$t2,$t1,#63
++	 ldp	$a0,$a1,[$np,#8*0]
++	adcs	$acc6,$a6,$t1
++	extr	$t2,xzr,$t2,#63
++	 ldp	$a2,$a3,[$np,#8*2]
++	adc	$acc7,$a7,$t2
++	 ldp	$a4,$a5,[$np,#8*4]
++
++	// Reduce by 512 bits per iteration
++	mul	$na0,$n0,$acc0		// t[0]*n0
++	ldp	$a6,$a7,[$np,#8*6]
++	add	$np_end,$np,$num
++	ldp	$acc2,$acc3,[sp,#8*2]
++	stp	$acc4,$acc5,[$tp,#8*4]
++	ldp	$acc4,$acc5,[sp,#8*4]
++	stp	$acc6,$acc7,[$tp,#8*6]
++	ldp	$acc6,$acc7,[sp,#8*6]
++	add	$np,$np,#8*8
++	mov	$topmost,xzr		// initial top-most carry
++	mov	$tp,sp
++	mov	$cnt,#8
++
++.Lsqr8x_reduction:
++	// (*)	mul	$t0,$a0,$na0	// lo(n[0-7])*lo(t[0]*n0)
++	mul	$t1,$a1,$na0
++	sub	$cnt,$cnt,#1
++	mul	$t2,$a2,$na0
++	str	$na0,[$tp],#8		// put aside t[0]*n0 for tail processing
++	mul	$t3,$a3,$na0
++	// (*)	adds	xzr,$acc0,$t0
++	subs	xzr,$acc0,#1		// (*)
++	mul	$t0,$a4,$na0
++	adcs	$acc0,$acc1,$t1
++	mul	$t1,$a5,$na0
++	adcs	$acc1,$acc2,$t2
++	mul	$t2,$a6,$na0
++	adcs	$acc2,$acc3,$t3
++	mul	$t3,$a7,$na0
++	adcs	$acc3,$acc4,$t0
++	umulh	$t0,$a0,$na0		// hi(n[0-7])*lo(t[0]*n0)
++	adcs	$acc4,$acc5,$t1
++	umulh	$t1,$a1,$na0
++	adcs	$acc5,$acc6,$t2
++	umulh	$t2,$a2,$na0
++	adcs	$acc6,$acc7,$t3
++	umulh	$t3,$a3,$na0
++	adc	$acc7,xzr,xzr
++	adds	$acc0,$acc0,$t0
++	umulh	$t0,$a4,$na0
++	adcs	$acc1,$acc1,$t1
++	umulh	$t1,$a5,$na0
++	adcs	$acc2,$acc2,$t2
++	umulh	$t2,$a6,$na0
++	adcs	$acc3,$acc3,$t3
++	umulh	$t3,$a7,$na0
++	mul	$na0,$n0,$acc0		// next t[0]*n0
++	adcs	$acc4,$acc4,$t0
++	adcs	$acc5,$acc5,$t1
++	adcs	$acc6,$acc6,$t2
++	adc	$acc7,$acc7,$t3
++	cbnz	$cnt,.Lsqr8x_reduction
++
++	ldp	$t0,$t1,[$tp,#8*0]
++	ldp	$t2,$t3,[$tp,#8*2]
++	mov	$rp,$tp
++	sub	$cnt,$np_end,$np	// done yet?
++	adds	$acc0,$acc0,$t0
++	adcs	$acc1,$acc1,$t1
++	ldp	$t0,$t1,[$tp,#8*4]
++	adcs	$acc2,$acc2,$t2
++	adcs	$acc3,$acc3,$t3
++	ldp	$t2,$t3,[$tp,#8*6]
++	adcs	$acc4,$acc4,$t0
++	adcs	$acc5,$acc5,$t1
++	adcs	$acc6,$acc6,$t2
++	adcs	$acc7,$acc7,$t3
++	//adc	$carry,xzr,xzr		// moved below
++	cbz	$cnt,.Lsqr8x8_post_condition
++
++	ldr	$n0,[$tp,#-8*8]
++	ldp	$a0,$a1,[$np,#8*0]
++	ldp	$a2,$a3,[$np,#8*2]
++	ldp	$a4,$a5,[$np,#8*4]
++	mov	$cnt,#-8*8
++	ldp	$a6,$a7,[$np,#8*6]
++	add	$np,$np,#8*8
++
++.Lsqr8x_tail:
++	mul	$t0,$a0,$n0
++	adc	$carry,xzr,xzr		// carry bit, modulo-scheduled
++	mul	$t1,$a1,$n0
++	add	$cnt,$cnt,#8
++	mul	$t2,$a2,$n0
++	mul	$t3,$a3,$n0
++	adds	$acc0,$acc0,$t0
++	mul	$t0,$a4,$n0
++	adcs	$acc1,$acc1,$t1
++	mul	$t1,$a5,$n0
++	adcs	$acc2,$acc2,$t2
++	mul	$t2,$a6,$n0
++	adcs	$acc3,$acc3,$t3
++	mul	$t3,$a7,$n0
++	adcs	$acc4,$acc4,$t0
++	umulh	$t0,$a0,$n0
++	adcs	$acc5,$acc5,$t1
++	umulh	$t1,$a1,$n0
++	adcs	$acc6,$acc6,$t2
++	umulh	$t2,$a2,$n0
++	adcs	$acc7,$acc7,$t3
++	umulh	$t3,$a3,$n0
++	adc	$carry,$carry,xzr
++	str	$acc0,[$tp],#8
++	adds	$acc0,$acc1,$t0
++	umulh	$t0,$a4,$n0
++	adcs	$acc1,$acc2,$t1
++	umulh	$t1,$a5,$n0
++	adcs	$acc2,$acc3,$t2
++	umulh	$t2,$a6,$n0
++	adcs	$acc3,$acc4,$t3
++	umulh	$t3,$a7,$n0
++	ldr	$n0,[$rp,$cnt]
++	adcs	$acc4,$acc5,$t0
++	adcs	$acc5,$acc6,$t1
++	adcs	$acc6,$acc7,$t2
++	adcs	$acc7,$carry,$t3
++	//adc	$carry,xzr,xzr		// moved above
++	cbnz	$cnt,.Lsqr8x_tail
++					// note that carry flag is guaranteed
++					// to be zero at this point
++	ldp	$a0,$a1,[$tp,#8*0]
++	sub	$cnt,$np_end,$np	// done yet?
++	sub	$t2,$np_end,$num	// rewinded np
++	ldp	$a2,$a3,[$tp,#8*2]
++	ldp	$a4,$a5,[$tp,#8*4]
++	ldp	$a6,$a7,[$tp,#8*6]
++	cbz	$cnt,.Lsqr8x_tail_break
++
++	ldr	$n0,[$rp,#-8*8]
++	adds	$acc0,$acc0,$a0
++	adcs	$acc1,$acc1,$a1
++	ldp	$a0,$a1,[$np,#8*0]
++	adcs	$acc2,$acc2,$a2
++	adcs	$acc3,$acc3,$a3
++	ldp	$a2,$a3,[$np,#8*2]
++	adcs	$acc4,$acc4,$a4
++	adcs	$acc5,$acc5,$a5
++	ldp	$a4,$a5,[$np,#8*4]
++	adcs	$acc6,$acc6,$a6
++	mov	$cnt,#-8*8
++	adcs	$acc7,$acc7,$a7
++	ldp	$a6,$a7,[$np,#8*6]
++	add	$np,$np,#8*8
++	//adc	$carry,xzr,xzr		// moved above
++	b	.Lsqr8x_tail
++
++.align	4
++.Lsqr8x_tail_break:
++	ldr	$n0,[x29,#112]		// pull n0
++	add	$cnt,$tp,#8*8		// end of current t[num] window
++
++	subs	xzr,$topmost,#1		// "move" top-most carry to carry bit
++	adcs	$t0,$acc0,$a0
++	adcs	$t1,$acc1,$a1
++	ldp	$acc0,$acc1,[$rp,#8*0]
++	adcs	$acc2,$acc2,$a2
++	ldp	$a0,$a1,[$t2,#8*0]	// recall that $t2 is &n[0]
++	adcs	$acc3,$acc3,$a3
++	ldp	$a2,$a3,[$t2,#8*2]
++	adcs	$acc4,$acc4,$a4
++	adcs	$acc5,$acc5,$a5
++	ldp	$a4,$a5,[$t2,#8*4]
++	adcs	$acc6,$acc6,$a6
++	adcs	$acc7,$acc7,$a7
++	ldp	$a6,$a7,[$t2,#8*6]
++	add	$np,$t2,#8*8
++	adc	$topmost,xzr,xzr	// top-most carry
++	mul	$na0,$n0,$acc0
++	stp	$t0,$t1,[$tp,#8*0]
++	stp	$acc2,$acc3,[$tp,#8*2]
++	ldp	$acc2,$acc3,[$rp,#8*2]
++	stp	$acc4,$acc5,[$tp,#8*4]
++	ldp	$acc4,$acc5,[$rp,#8*4]
++	cmp	$cnt,x29		// did we hit the bottom?
++	stp	$acc6,$acc7,[$tp,#8*6]
++	mov	$tp,$rp			// slide the window
++	ldp	$acc6,$acc7,[$rp,#8*6]
++	mov	$cnt,#8
++	b.ne	.Lsqr8x_reduction
++
++	// Final step. We see if result is larger than modulus, and
++	// if it is, subtract the modulus. But comparison implies
++	// subtraction. So we subtract modulus, see if it borrowed,
++	// and conditionally copy original value.
++	ldr	$rp,[x29,#96]		// pull rp
++	add	$tp,$tp,#8*8
++	subs	$t0,$acc0,$a0
++	sbcs	$t1,$acc1,$a1
++	sub	$cnt,$num,#8*8
++	mov	$ap_end,$rp		// $rp copy
++
++.Lsqr8x_sub:
++	sbcs	$t2,$acc2,$a2
++	ldp	$a0,$a1,[$np,#8*0]
++	sbcs	$t3,$acc3,$a3
++	stp	$t0,$t1,[$rp,#8*0]
++	sbcs	$t0,$acc4,$a4
++	ldp	$a2,$a3,[$np,#8*2]
++	sbcs	$t1,$acc5,$a5
++	stp	$t2,$t3,[$rp,#8*2]
++	sbcs	$t2,$acc6,$a6
++	ldp	$a4,$a5,[$np,#8*4]
++	sbcs	$t3,$acc7,$a7
++	ldp	$a6,$a7,[$np,#8*6]
++	add	$np,$np,#8*8
++	ldp	$acc0,$acc1,[$tp,#8*0]
++	sub	$cnt,$cnt,#8*8
++	ldp	$acc2,$acc3,[$tp,#8*2]
++	ldp	$acc4,$acc5,[$tp,#8*4]
++	ldp	$acc6,$acc7,[$tp,#8*6]
++	add	$tp,$tp,#8*8
++	stp	$t0,$t1,[$rp,#8*4]
++	sbcs	$t0,$acc0,$a0
++	stp	$t2,$t3,[$rp,#8*6]
++	add	$rp,$rp,#8*8
++	sbcs	$t1,$acc1,$a1
++	cbnz	$cnt,.Lsqr8x_sub
++
++	sbcs	$t2,$acc2,$a2
++	 mov	$tp,sp
++	 add	$ap,sp,$num
++	 ldp	$a0,$a1,[$ap_end,#8*0]
++	sbcs	$t3,$acc3,$a3
++	stp	$t0,$t1,[$rp,#8*0]
++	sbcs	$t0,$acc4,$a4
++	 ldp	$a2,$a3,[$ap_end,#8*2]
++	sbcs	$t1,$acc5,$a5
++	stp	$t2,$t3,[$rp,#8*2]
++	sbcs	$t2,$acc6,$a6
++	 ldp	$acc0,$acc1,[$ap,#8*0]
++	sbcs	$t3,$acc7,$a7
++	 ldp	$acc2,$acc3,[$ap,#8*2]
++	sbcs	xzr,$topmost,xzr	// did it borrow?
++	ldr	x30,[x29,#8]		// pull return address
++	stp	$t0,$t1,[$rp,#8*4]
++	stp	$t2,$t3,[$rp,#8*6]
++
++	sub	$cnt,$num,#8*4
++.Lsqr4x_cond_copy:
++	sub	$cnt,$cnt,#8*4
++	csel	$t0,$acc0,$a0,lo
++	 stp	xzr,xzr,[$tp,#8*0]
++	csel	$t1,$acc1,$a1,lo
++	ldp	$a0,$a1,[$ap_end,#8*4]
++	ldp	$acc0,$acc1,[$ap,#8*4]
++	csel	$t2,$acc2,$a2,lo
++	 stp	xzr,xzr,[$tp,#8*2]
++	 add	$tp,$tp,#8*4
++	csel	$t3,$acc3,$a3,lo
++	ldp	$a2,$a3,[$ap_end,#8*6]
++	ldp	$acc2,$acc3,[$ap,#8*6]
++	add	$ap,$ap,#8*4
++	stp	$t0,$t1,[$ap_end,#8*0]
++	stp	$t2,$t3,[$ap_end,#8*2]
++	add	$ap_end,$ap_end,#8*4
++	 stp	xzr,xzr,[$ap,#8*0]
++	 stp	xzr,xzr,[$ap,#8*2]
++	cbnz	$cnt,.Lsqr4x_cond_copy
++
++	csel	$t0,$acc0,$a0,lo
++	 stp	xzr,xzr,[$tp,#8*0]
++	csel	$t1,$acc1,$a1,lo
++	 stp	xzr,xzr,[$tp,#8*2]
++	csel	$t2,$acc2,$a2,lo
++	csel	$t3,$acc3,$a3,lo
++	stp	$t0,$t1,[$ap_end,#8*0]
++	stp	$t2,$t3,[$ap_end,#8*2]
++
++	b	.Lsqr8x_done
++
++.align	4
++.Lsqr8x8_post_condition:
++	adc	$carry,xzr,xzr
++	ldr	x30,[x29,#8]		// pull return address
++	// $acc0-7,$carry hold result, $a0-7 hold modulus
++	subs	$a0,$acc0,$a0
++	ldr	$ap,[x29,#96]		// pull rp
++	sbcs	$a1,$acc1,$a1
++	 stp	xzr,xzr,[sp,#8*0]
++	sbcs	$a2,$acc2,$a2
++	 stp	xzr,xzr,[sp,#8*2]
++	sbcs	$a3,$acc3,$a3
++	 stp	xzr,xzr,[sp,#8*4]
++	sbcs	$a4,$acc4,$a4
++	 stp	xzr,xzr,[sp,#8*6]
++	sbcs	$a5,$acc5,$a5
++	 stp	xzr,xzr,[sp,#8*8]
++	sbcs	$a6,$acc6,$a6
++	 stp	xzr,xzr,[sp,#8*10]
++	sbcs	$a7,$acc7,$a7
++	 stp	xzr,xzr,[sp,#8*12]
++	sbcs	$carry,$carry,xzr	// did it borrow?
++	 stp	xzr,xzr,[sp,#8*14]
++
++	// $a0-7 hold result-modulus
++	csel	$a0,$acc0,$a0,lo
++	csel	$a1,$acc1,$a1,lo
++	csel	$a2,$acc2,$a2,lo
++	csel	$a3,$acc3,$a3,lo
++	stp	$a0,$a1,[$ap,#8*0]
++	csel	$a4,$acc4,$a4,lo
++	csel	$a5,$acc5,$a5,lo
++	stp	$a2,$a3,[$ap,#8*2]
++	csel	$a6,$acc6,$a6,lo
++	csel	$a7,$acc7,$a7,lo
++	stp	$a4,$a5,[$ap,#8*4]
++	stp	$a6,$a7,[$ap,#8*6]
++
++.Lsqr8x_done:
++	ldp	x19,x20,[x29,#16]
++	mov	sp,x29
++	ldp	x21,x22,[x29,#32]
++	mov	x0,#1
++	ldp	x23,x24,[x29,#48]
++	ldp	x25,x26,[x29,#64]
++	ldp	x27,x28,[x29,#80]
++	ldr	x29,[sp],#128
++	ret
++.size	__bn_sqr8x_mont,.-__bn_sqr8x_mont
++___
++}
++
++{
++########################################################################
++# Even though this might look as ARMv8 adaptation of mulx4x_mont from
++# x86_64-mont5 module, it's different in sense that it performs
++# reduction 256 bits at a time.
++
++my ($a0,$a1,$a2,$a3,
++    $t0,$t1,$t2,$t3,
++    $m0,$m1,$m2,$m3,
++    $acc0,$acc1,$acc2,$acc3,$acc4,
++    $bi,$mi,$tp,$ap_end,$cnt) = map("x$_",(6..17,19..28));
++my  $bp_end=$rp;
++my  ($carry,$topmost) = ($rp,"x30");
++
++$code.=<<___;
++.type	__bn_mul4x_mont,%function
++.align	5
++__bn_mul4x_mont:
++	stp	x29,x30,[sp,#-128]!
++	add	x29,sp,#0
++	stp	x19,x20,[sp,#16]
++	stp	x21,x22,[sp,#32]
++	stp	x23,x24,[sp,#48]
++	stp	x25,x26,[sp,#64]
++	stp	x27,x28,[sp,#80]
++
++	sub	$tp,sp,$num,lsl#3
++	lsl	$num,$num,#3
++	ldr	$n0,[$n0]		// *n0
++	sub	sp,$tp,#8*4		// alloca
++
++	add	$t0,$bp,$num
++	add	$ap_end,$ap,$num
++	stp	$rp,$t0,[x29,#96]	// offload rp and &b[num]
++
++	ldr	$bi,[$bp,#8*0]		// b[0]
++	ldp	$a0,$a1,[$ap,#8*0]	// a[0..3]
++	ldp	$a2,$a3,[$ap,#8*2]
++	add	$ap,$ap,#8*4
++	mov	$acc0,xzr
++	mov	$acc1,xzr
++	mov	$acc2,xzr
++	mov	$acc3,xzr
++	ldp	$m0,$m1,[$np,#8*0]	// n[0..3]
++	ldp	$m2,$m3,[$np,#8*2]
++	adds	$np,$np,#8*4		// clear carry bit
++	mov	$carry,xzr
++	mov	$cnt,#0
++	mov	$tp,sp
++
++.Loop_mul4x_1st_reduction:
++	mul	$t0,$a0,$bi		// lo(a[0..3]*b[0])
++	adc	$carry,$carry,xzr	// modulo-scheduled
++	mul	$t1,$a1,$bi
++	add	$cnt,$cnt,#8
++	mul	$t2,$a2,$bi
++	and	$cnt,$cnt,#31
++	mul	$t3,$a3,$bi
++	adds	$acc0,$acc0,$t0
++	umulh	$t0,$a0,$bi		// hi(a[0..3]*b[0])
++	adcs	$acc1,$acc1,$t1
++	mul	$mi,$acc0,$n0		// t[0]*n0
++	adcs	$acc2,$acc2,$t2
++	umulh	$t1,$a1,$bi
++	adcs	$acc3,$acc3,$t3
++	umulh	$t2,$a2,$bi
++	adc	$acc4,xzr,xzr
++	umulh	$t3,$a3,$bi
++	ldr	$bi,[$bp,$cnt]		// next b[i] (or b[0])
++	adds	$acc1,$acc1,$t0
++	// (*)	mul	$t0,$m0,$mi	// lo(n[0..3]*t[0]*n0)
++	str	$mi,[$tp],#8		// put aside t[0]*n0 for tail processing
++	adcs	$acc2,$acc2,$t1
++	mul	$t1,$m1,$mi
++	adcs	$acc3,$acc3,$t2
++	mul	$t2,$m2,$mi
++	adc	$acc4,$acc4,$t3		// can't overflow
++	mul	$t3,$m3,$mi
++	// (*)	adds	xzr,$acc0,$t0
++	subs	xzr,$acc0,#1		// (*)
++	umulh	$t0,$m0,$mi		// hi(n[0..3]*t[0]*n0)
++	adcs	$acc0,$acc1,$t1
++	umulh	$t1,$m1,$mi
++	adcs	$acc1,$acc2,$t2
++	umulh	$t2,$m2,$mi
++	adcs	$acc2,$acc3,$t3
++	umulh	$t3,$m3,$mi
++	adcs	$acc3,$acc4,$carry
++	adc	$carry,xzr,xzr
++	adds	$acc0,$acc0,$t0
++	sub	$t0,$ap_end,$ap
++	adcs	$acc1,$acc1,$t1
++	adcs	$acc2,$acc2,$t2
++	adcs	$acc3,$acc3,$t3
++	//adc	$carry,$carry,xzr
++	cbnz	$cnt,.Loop_mul4x_1st_reduction
++
++	cbz	$t0,.Lmul4x4_post_condition
++
++	ldp	$a0,$a1,[$ap,#8*0]	// a[4..7]
++	ldp	$a2,$a3,[$ap,#8*2]
++	add	$ap,$ap,#8*4
++	ldr	$mi,[sp]		// a[0]*n0
++	ldp	$m0,$m1,[$np,#8*0]	// n[4..7]
++	ldp	$m2,$m3,[$np,#8*2]
++	add	$np,$np,#8*4
++
++.Loop_mul4x_1st_tail:
++	mul	$t0,$a0,$bi		// lo(a[4..7]*b[i])
++	adc	$carry,$carry,xzr	// modulo-scheduled
++	mul	$t1,$a1,$bi
++	add	$cnt,$cnt,#8
++	mul	$t2,$a2,$bi
++	and	$cnt,$cnt,#31
++	mul	$t3,$a3,$bi
++	adds	$acc0,$acc0,$t0
++	umulh	$t0,$a0,$bi		// hi(a[4..7]*b[i])
++	adcs	$acc1,$acc1,$t1
++	umulh	$t1,$a1,$bi
++	adcs	$acc2,$acc2,$t2
++	umulh	$t2,$a2,$bi
++	adcs	$acc3,$acc3,$t3
++	umulh	$t3,$a3,$bi
++	adc	$acc4,xzr,xzr
++	ldr	$bi,[$bp,$cnt]		// next b[i] (or b[0])
++	adds	$acc1,$acc1,$t0
++	mul	$t0,$m0,$mi		// lo(n[4..7]*a[0]*n0)
++	adcs	$acc2,$acc2,$t1
++	mul	$t1,$m1,$mi
++	adcs	$acc3,$acc3,$t2
++	mul	$t2,$m2,$mi
++	adc	$acc4,$acc4,$t3		// can't overflow
++	mul	$t3,$m3,$mi
++	adds	$acc0,$acc0,$t0
++	umulh	$t0,$m0,$mi		// hi(n[4..7]*a[0]*n0)
++	adcs	$acc1,$acc1,$t1
++	umulh	$t1,$m1,$mi
++	adcs	$acc2,$acc2,$t2
++	umulh	$t2,$m2,$mi
++	adcs	$acc3,$acc3,$t3
++	adcs	$acc4,$acc4,$carry
++	umulh	$t3,$m3,$mi
++	adc	$carry,xzr,xzr
++	ldr	$mi,[sp,$cnt]		// next t[0]*n0
++	str	$acc0,[$tp],#8		// result!!!
++	adds	$acc0,$acc1,$t0
++	sub	$t0,$ap_end,$ap		// done yet?
++	adcs	$acc1,$acc2,$t1
++	adcs	$acc2,$acc3,$t2
++	adcs	$acc3,$acc4,$t3
++	//adc	$carry,$carry,xzr
++	cbnz	$cnt,.Loop_mul4x_1st_tail
++
++	sub	$t1,$ap_end,$num	// rewinded $ap
++	cbz	$t0,.Lmul4x_proceed
++
++	ldp	$a0,$a1,[$ap,#8*0]
++	ldp	$a2,$a3,[$ap,#8*2]
++	add	$ap,$ap,#8*4
++	ldp	$m0,$m1,[$np,#8*0]
++	ldp	$m2,$m3,[$np,#8*2]
++	add	$np,$np,#8*4
++	b	.Loop_mul4x_1st_tail
++
++.align	5
++.Lmul4x_proceed:
++	ldr	$bi,[$bp,#8*4]!		// *++b
++	adc	$topmost,$carry,xzr
++	ldp	$a0,$a1,[$t1,#8*0]	// a[0..3]
++	sub	$np,$np,$num		// rewind np
++	ldp	$a2,$a3,[$t1,#8*2]
++	add	$ap,$t1,#8*4
++
++	stp	$acc0,$acc1,[$tp,#8*0]	// result!!!
++	ldp	$acc0,$acc1,[sp,#8*4]	// t[0..3]
++	stp	$acc2,$acc3,[$tp,#8*2]	// result!!!
++	ldp	$acc2,$acc3,[sp,#8*6]
++
++	ldp	$m0,$m1,[$np,#8*0]	// n[0..3]
++	mov	$tp,sp
++	ldp	$m2,$m3,[$np,#8*2]
++	adds	$np,$np,#8*4		// clear carry bit
++	mov	$carry,xzr
++
++.align	4
++.Loop_mul4x_reduction:
++	mul	$t0,$a0,$bi		// lo(a[0..3]*b[4])
++	adc	$carry,$carry,xzr	// modulo-scheduled
++	mul	$t1,$a1,$bi
++	add	$cnt,$cnt,#8
++	mul	$t2,$a2,$bi
++	and	$cnt,$cnt,#31
++	mul	$t3,$a3,$bi
++	adds	$acc0,$acc0,$t0
++	umulh	$t0,$a0,$bi		// hi(a[0..3]*b[4])
++	adcs	$acc1,$acc1,$t1
++	mul	$mi,$acc0,$n0		// t[0]*n0
++	adcs	$acc2,$acc2,$t2
++	umulh	$t1,$a1,$bi
++	adcs	$acc3,$acc3,$t3
++	umulh	$t2,$a2,$bi
++	adc	$acc4,xzr,xzr
++	umulh	$t3,$a3,$bi
++	ldr	$bi,[$bp,$cnt]		// next b[i]
++	adds	$acc1,$acc1,$t0
++	// (*)	mul	$t0,$m0,$mi
++	str	$mi,[$tp],#8		// put aside t[0]*n0 for tail processing
++	adcs	$acc2,$acc2,$t1
++	mul	$t1,$m1,$mi		// lo(n[0..3]*t[0]*n0
++	adcs	$acc3,$acc3,$t2
++	mul	$t2,$m2,$mi
++	adc	$acc4,$acc4,$t3		// can't overflow
++	mul	$t3,$m3,$mi
++	// (*)	adds	xzr,$acc0,$t0
++	subs	xzr,$acc0,#1		// (*)
++	umulh	$t0,$m0,$mi		// hi(n[0..3]*t[0]*n0
++	adcs	$acc0,$acc1,$t1
++	umulh	$t1,$m1,$mi
++	adcs	$acc1,$acc2,$t2
++	umulh	$t2,$m2,$mi
++	adcs	$acc2,$acc3,$t3
++	umulh	$t3,$m3,$mi
++	adcs	$acc3,$acc4,$carry
++	adc	$carry,xzr,xzr
++	adds	$acc0,$acc0,$t0
++	adcs	$acc1,$acc1,$t1
++	adcs	$acc2,$acc2,$t2
++	adcs	$acc3,$acc3,$t3
++	//adc	$carry,$carry,xzr
++	cbnz	$cnt,.Loop_mul4x_reduction
++
++	adc	$carry,$carry,xzr
++	ldp	$t0,$t1,[$tp,#8*4]	// t[4..7]
++	ldp	$t2,$t3,[$tp,#8*6]
++	ldp	$a0,$a1,[$ap,#8*0]	// a[4..7]
++	ldp	$a2,$a3,[$ap,#8*2]
++	add	$ap,$ap,#8*4
++	adds	$acc0,$acc0,$t0
++	adcs	$acc1,$acc1,$t1
++	adcs	$acc2,$acc2,$t2
++	adcs	$acc3,$acc3,$t3
++	//adc	$carry,$carry,xzr
++
++	ldr	$mi,[sp]		// t[0]*n0
++	ldp	$m0,$m1,[$np,#8*0]	// n[4..7]
++	ldp	$m2,$m3,[$np,#8*2]
++	add	$np,$np,#8*4
++
++.align	4
++.Loop_mul4x_tail:
++	mul	$t0,$a0,$bi		// lo(a[4..7]*b[4])
++	adc	$carry,$carry,xzr	// modulo-scheduled
++	mul	$t1,$a1,$bi
++	add	$cnt,$cnt,#8
++	mul	$t2,$a2,$bi
++	and	$cnt,$cnt,#31
++	mul	$t3,$a3,$bi
++	adds	$acc0,$acc0,$t0
++	umulh	$t0,$a0,$bi		// hi(a[4..7]*b[4])
++	adcs	$acc1,$acc1,$t1
++	umulh	$t1,$a1,$bi
++	adcs	$acc2,$acc2,$t2
++	umulh	$t2,$a2,$bi
++	adcs	$acc3,$acc3,$t3
++	umulh	$t3,$a3,$bi
++	adc	$acc4,xzr,xzr
++	ldr	$bi,[$bp,$cnt]		// next b[i]
++	adds	$acc1,$acc1,$t0
++	mul	$t0,$m0,$mi		// lo(n[4..7]*t[0]*n0)
++	adcs	$acc2,$acc2,$t1
++	mul	$t1,$m1,$mi
++	adcs	$acc3,$acc3,$t2
++	mul	$t2,$m2,$mi
++	adc	$acc4,$acc4,$t3		// can't overflow
++	mul	$t3,$m3,$mi
++	adds	$acc0,$acc0,$t0
++	umulh	$t0,$m0,$mi		// hi(n[4..7]*t[0]*n0)
++	adcs	$acc1,$acc1,$t1
++	umulh	$t1,$m1,$mi
++	adcs	$acc2,$acc2,$t2
++	umulh	$t2,$m2,$mi
++	adcs	$acc3,$acc3,$t3
++	umulh	$t3,$m3,$mi
++	adcs	$acc4,$acc4,$carry
++	ldr	$mi,[sp,$cnt]		// next a[0]*n0
++	adc	$carry,xzr,xzr
++	str	$acc0,[$tp],#8		// result!!!
++	adds	$acc0,$acc1,$t0
++	sub	$t0,$ap_end,$ap		// done yet?
++	adcs	$acc1,$acc2,$t1
++	adcs	$acc2,$acc3,$t2
++	adcs	$acc3,$acc4,$t3
++	//adc	$carry,$carry,xzr
++	cbnz	$cnt,.Loop_mul4x_tail
++
++	sub	$t1,$np,$num		// rewinded np?
++	adc	$carry,$carry,xzr
++	cbz	$t0,.Loop_mul4x_break
++
++	ldp	$t0,$t1,[$tp,#8*4]
++	ldp	$t2,$t3,[$tp,#8*6]
++	ldp	$a0,$a1,[$ap,#8*0]
++	ldp	$a2,$a3,[$ap,#8*2]
++	add	$ap,$ap,#8*4
++	adds	$acc0,$acc0,$t0
++	adcs	$acc1,$acc1,$t1
++	adcs	$acc2,$acc2,$t2
++	adcs	$acc3,$acc3,$t3
++	//adc	$carry,$carry,xzr
++	ldp	$m0,$m1,[$np,#8*0]
++	ldp	$m2,$m3,[$np,#8*2]
++	add	$np,$np,#8*4
++	b	.Loop_mul4x_tail
++
++.align	4
++.Loop_mul4x_break:
++	ldp	$t2,$t3,[x29,#96]	// pull rp and &b[num]
++	adds	$acc0,$acc0,$topmost
++	add	$bp,$bp,#8*4		// bp++
++	adcs	$acc1,$acc1,xzr
++	sub	$ap,$ap,$num		// rewind ap
++	adcs	$acc2,$acc2,xzr
++	stp	$acc0,$acc1,[$tp,#8*0]	// result!!!
++	adcs	$acc3,$acc3,xzr
++	ldp	$acc0,$acc1,[sp,#8*4]	// t[0..3]
++	adc	$topmost,$carry,xzr
++	stp	$acc2,$acc3,[$tp,#8*2]	// result!!!
++	cmp	$bp,$t3			// done yet?
++	ldp	$acc2,$acc3,[sp,#8*6]
++	ldp	$m0,$m1,[$t1,#8*0]	// n[0..3]
++	ldp	$m2,$m3,[$t1,#8*2]
++	add	$np,$t1,#8*4
++	b.eq	.Lmul4x_post
++
++	ldr	$bi,[$bp]
++	ldp	$a0,$a1,[$ap,#8*0]	// a[0..3]
++	ldp	$a2,$a3,[$ap,#8*2]
++	adds	$ap,$ap,#8*4		// clear carry bit
++	mov	$carry,xzr
++	mov	$tp,sp
++	b	.Loop_mul4x_reduction
++
++.align	4
++.Lmul4x_post:
++	// Final step. We see if result is larger than modulus, and
++	// if it is, subtract the modulus. But comparison implies
++	// subtraction. So we subtract modulus, see if it borrowed,
++	// and conditionally copy original value.
++	mov	$rp,$t2
++	mov	$ap_end,$t2		// $rp copy
++	subs	$t0,$acc0,$m0
++	add	$tp,sp,#8*8
++	sbcs	$t1,$acc1,$m1
++	sub	$cnt,$num,#8*4
++
++.Lmul4x_sub:
++	sbcs	$t2,$acc2,$m2
++	ldp	$m0,$m1,[$np,#8*0]
++	sub	$cnt,$cnt,#8*4
++	ldp	$acc0,$acc1,[$tp,#8*0]
++	sbcs	$t3,$acc3,$m3
++	ldp	$m2,$m3,[$np,#8*2]
++	add	$np,$np,#8*4
++	ldp	$acc2,$acc3,[$tp,#8*2]
++	add	$tp,$tp,#8*4
++	stp	$t0,$t1,[$rp,#8*0]
++	sbcs	$t0,$acc0,$m0
++	stp	$t2,$t3,[$rp,#8*2]
++	add	$rp,$rp,#8*4
++	sbcs	$t1,$acc1,$m1
++	cbnz	$cnt,.Lmul4x_sub
++
++	sbcs	$t2,$acc2,$m2
++	 mov	$tp,sp
++	 add	$ap,sp,#8*4
++	 ldp	$a0,$a1,[$ap_end,#8*0]
++	sbcs	$t3,$acc3,$m3
++	stp	$t0,$t1,[$rp,#8*0]
++	 ldp	$a2,$a3,[$ap_end,#8*2]
++	stp	$t2,$t3,[$rp,#8*2]
++	 ldp	$acc0,$acc1,[$ap,#8*0]
++	 ldp	$acc2,$acc3,[$ap,#8*2]
++	sbcs	xzr,$topmost,xzr	// did it borrow?
++	ldr	x30,[x29,#8]		// pull return address
++
++	sub	$cnt,$num,#8*4
++.Lmul4x_cond_copy:
++	sub	$cnt,$cnt,#8*4
++	csel	$t0,$acc0,$a0,lo
++	 stp	xzr,xzr,[$tp,#8*0]
++	csel	$t1,$acc1,$a1,lo
++	ldp	$a0,$a1,[$ap_end,#8*4]
++	ldp	$acc0,$acc1,[$ap,#8*4]
++	csel	$t2,$acc2,$a2,lo
++	 stp	xzr,xzr,[$tp,#8*2]
++	 add	$tp,$tp,#8*4
++	csel	$t3,$acc3,$a3,lo
++	ldp	$a2,$a3,[$ap_end,#8*6]
++	ldp	$acc2,$acc3,[$ap,#8*6]
++	add	$ap,$ap,#8*4
++	stp	$t0,$t1,[$ap_end,#8*0]
++	stp	$t2,$t3,[$ap_end,#8*2]
++	add	$ap_end,$ap_end,#8*4
++	cbnz	$cnt,.Lmul4x_cond_copy
++
++	csel	$t0,$acc0,$a0,lo
++	 stp	xzr,xzr,[$tp,#8*0]
++	csel	$t1,$acc1,$a1,lo
++	 stp	xzr,xzr,[$tp,#8*2]
++	csel	$t2,$acc2,$a2,lo
++	 stp	xzr,xzr,[$tp,#8*3]
++	csel	$t3,$acc3,$a3,lo
++	 stp	xzr,xzr,[$tp,#8*4]
++	stp	$t0,$t1,[$ap_end,#8*0]
++	stp	$t2,$t3,[$ap_end,#8*2]
++
++	b	.Lmul4x_done
++
++.align	4
++.Lmul4x4_post_condition:
++	adc	$carry,$carry,xzr
++	ldr	$ap,[x29,#96]		// pull rp
++	// $acc0-3,$carry hold result, $m0-7 hold modulus
++	subs	$a0,$acc0,$m0
++	ldr	x30,[x29,#8]		// pull return address
++	sbcs	$a1,$acc1,$m1
++	 stp	xzr,xzr,[sp,#8*0]
++	sbcs	$a2,$acc2,$m2
++	 stp	xzr,xzr,[sp,#8*2]
++	sbcs	$a3,$acc3,$m3
++	 stp	xzr,xzr,[sp,#8*4]
++	sbcs	xzr,$carry,xzr		// did it borrow?
++	 stp	xzr,xzr,[sp,#8*6]
++
++	// $a0-3 hold result-modulus
++	csel	$a0,$acc0,$a0,lo
++	csel	$a1,$acc1,$a1,lo
++	csel	$a2,$acc2,$a2,lo
++	csel	$a3,$acc3,$a3,lo
++	stp	$a0,$a1,[$ap,#8*0]
++	stp	$a2,$a3,[$ap,#8*2]
++
++.Lmul4x_done:
++	ldp	x19,x20,[x29,#16]
++	mov	sp,x29
++	ldp	x21,x22,[x29,#32]
++	mov	x0,#1
++	ldp	x23,x24,[x29,#48]
++	ldp	x25,x26,[x29,#64]
++	ldp	x27,x28,[x29,#80]
++	ldr	x29,[sp],#128
++	ret
++.size	__bn_mul4x_mont,.-__bn_mul4x_mont
++___
++}
++$code.=<<___;
++.asciz	"Montgomery Multiplication for ARMv8, CRYPTOGAMS by "
++.align	4
++___
++
++print $code;
++
++close STDOUT;
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/bn/asm/bn-586.pl b/CryptoPkg/Library/OpensslLib/openssl/crypto/bn/asm/bn-586.pl
+new file mode 100644
+index 0000000..1ca1bbf
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/bn/asm/bn-586.pl
+@@ -0,0 +1,785 @@
++#! /usr/bin/env perl
++# Copyright 1995-2016 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
++# in the file LICENSE in the source distribution or at
++# https://www.openssl.org/source/license.html
++
++
++$0 =~ m/(.*[\/\\])[^\/\\]+$/; $dir=$1;
++push(@INC,"${dir}","${dir}../../perlasm");
++require "x86asm.pl";
++
++$output = pop;
++open STDOUT,">$output";
++
++&asm_init($ARGV[0],$0);
++
++$sse2=0;
++for (@ARGV) { $sse2=1 if (/-DOPENSSL_IA32_SSE2/); }
++
++&external_label("OPENSSL_ia32cap_P") if ($sse2);
++
++&bn_mul_add_words("bn_mul_add_words");
++&bn_mul_words("bn_mul_words");
++&bn_sqr_words("bn_sqr_words");
++&bn_div_words("bn_div_words");
++&bn_add_words("bn_add_words");
++&bn_sub_words("bn_sub_words");
++&bn_sub_part_words("bn_sub_part_words");
++
++&asm_finish();
++
++close STDOUT;
++
++sub bn_mul_add_words
++	{
++	local($name)=@_;
++
++	&function_begin_B($name,$sse2?"EXTRN\t_OPENSSL_ia32cap_P:DWORD":"");
++
++	$r="eax";
++	$a="edx";
++	$c="ecx";
++
++	if ($sse2) {
++		&picmeup("eax","OPENSSL_ia32cap_P");
++		&bt(&DWP(0,"eax"),26);
++		&jnc(&label("maw_non_sse2"));
++
++		&mov($r,&wparam(0));
++		&mov($a,&wparam(1));
++		&mov($c,&wparam(2));
++		&movd("mm0",&wparam(3));	# mm0 = w
++		&pxor("mm1","mm1");		# mm1 = carry_in
++		&jmp(&label("maw_sse2_entry"));
++		
++	&set_label("maw_sse2_unrolled",16);
++		&movd("mm3",&DWP(0,$r,"",0));	# mm3 = r[0]
++		&paddq("mm1","mm3");		# mm1 = carry_in + r[0]
++		&movd("mm2",&DWP(0,$a,"",0));	# mm2 = a[0]
++		&pmuludq("mm2","mm0");		# mm2 = w*a[0]
++		&movd("mm4",&DWP(4,$a,"",0));	# mm4 = a[1]
++		&pmuludq("mm4","mm0");		# mm4 = w*a[1]
++		&movd("mm6",&DWP(8,$a,"",0));	# mm6 = a[2]
++		&pmuludq("mm6","mm0");		# mm6 = w*a[2]
++		&movd("mm7",&DWP(12,$a,"",0));	# mm7 = a[3]
++		&pmuludq("mm7","mm0");		# mm7 = w*a[3]
++		&paddq("mm1","mm2");		# mm1 = carry_in + r[0] + w*a[0]
++		&movd("mm3",&DWP(4,$r,"",0));	# mm3 = r[1]
++		&paddq("mm3","mm4");		# mm3 = r[1] + w*a[1]
++		&movd("mm5",&DWP(8,$r,"",0));	# mm5 = r[2]
++		&paddq("mm5","mm6");		# mm5 = r[2] + w*a[2]
++		&movd("mm4",&DWP(12,$r,"",0));	# mm4 = r[3]
++		&paddq("mm7","mm4");		# mm7 = r[3] + w*a[3]
++		&movd(&DWP(0,$r,"",0),"mm1");
++		&movd("mm2",&DWP(16,$a,"",0));	# mm2 = a[4]
++		&pmuludq("mm2","mm0");		# mm2 = w*a[4]
++		&psrlq("mm1",32);		# mm1 = carry0
++		&movd("mm4",&DWP(20,$a,"",0));	# mm4 = a[5]
++		&pmuludq("mm4","mm0");		# mm4 = w*a[5]
++		&paddq("mm1","mm3");		# mm1 = carry0 + r[1] + w*a[1]
++		&movd("mm6",&DWP(24,$a,"",0));	# mm6 = a[6]
++		&pmuludq("mm6","mm0");		# mm6 = w*a[6]
++		&movd(&DWP(4,$r,"",0),"mm1");
++		&psrlq("mm1",32);		# mm1 = carry1
++		&movd("mm3",&DWP(28,$a,"",0));	# mm3 = a[7]
++		&add($a,32);
++		&pmuludq("mm3","mm0");		# mm3 = w*a[7]
++		&paddq("mm1","mm5");		# mm1 = carry1 + r[2] + w*a[2]
++		&movd("mm5",&DWP(16,$r,"",0));	# mm5 = r[4]
++		&paddq("mm2","mm5");		# mm2 = r[4] + w*a[4]
++		&movd(&DWP(8,$r,"",0),"mm1");
++		&psrlq("mm1",32);		# mm1 = carry2
++		&paddq("mm1","mm7");		# mm1 = carry2 + r[3] + w*a[3]
++		&movd("mm5",&DWP(20,$r,"",0));	# mm5 = r[5]
++		&paddq("mm4","mm5");		# mm4 = r[5] + w*a[5]
++		&movd(&DWP(12,$r,"",0),"mm1");
++		&psrlq("mm1",32);		# mm1 = carry3
++		&paddq("mm1","mm2");		# mm1 = carry3 + r[4] + w*a[4]
++		&movd("mm5",&DWP(24,$r,"",0));	# mm5 = r[6]
++		&paddq("mm6","mm5");		# mm6 = r[6] + w*a[6]
++		&movd(&DWP(16,$r,"",0),"mm1");
++		&psrlq("mm1",32);		# mm1 = carry4
++		&paddq("mm1","mm4");		# mm1 = carry4 + r[5] + w*a[5]
++		&movd("mm5",&DWP(28,$r,"",0));	# mm5 = r[7]
++		&paddq("mm3","mm5");		# mm3 = r[7] + w*a[7]
++		&movd(&DWP(20,$r,"",0),"mm1");
++		&psrlq("mm1",32);		# mm1 = carry5
++		&paddq("mm1","mm6");		# mm1 = carry5 + r[6] + w*a[6]
++		&movd(&DWP(24,$r,"",0),"mm1");
++		&psrlq("mm1",32);		# mm1 = carry6
++		&paddq("mm1","mm3");		# mm1 = carry6 + r[7] + w*a[7]
++		&movd(&DWP(28,$r,"",0),"mm1");
++		&lea($r,&DWP(32,$r));
++		&psrlq("mm1",32);		# mm1 = carry_out
++
++		&sub($c,8);
++		&jz(&label("maw_sse2_exit"));
++	&set_label("maw_sse2_entry");
++		&test($c,0xfffffff8);
++		&jnz(&label("maw_sse2_unrolled"));
++
++	&set_label("maw_sse2_loop",4);
++		&movd("mm2",&DWP(0,$a));	# mm2 = a[i]
++		&movd("mm3",&DWP(0,$r));	# mm3 = r[i]
++		&pmuludq("mm2","mm0");		# a[i] *= w
++		&lea($a,&DWP(4,$a));
++		&paddq("mm1","mm3");		# carry += r[i]
++		&paddq("mm1","mm2");		# carry += a[i]*w
++		&movd(&DWP(0,$r),"mm1");	# r[i] = carry_low
++		&sub($c,1);
++		&psrlq("mm1",32);		# carry = carry_high
++		&lea($r,&DWP(4,$r));
++		&jnz(&label("maw_sse2_loop"));
++	&set_label("maw_sse2_exit");
++		&movd("eax","mm1");		# c = carry_out
++		&emms();
++		&ret();
++
++	&set_label("maw_non_sse2",16);
++	}
++
++	# function_begin prologue
++	&push("ebp");
++	&push("ebx");
++	&push("esi");
++	&push("edi");
++
++	&comment("");
++	$Low="eax";
++	$High="edx";
++	$a="ebx";
++	$w="ebp";
++	$r="edi";
++	$c="esi";
++
++	&xor($c,$c);		# clear carry
++	&mov($r,&wparam(0));	#
++
++	&mov("ecx",&wparam(2));	#
++	&mov($a,&wparam(1));	#
++
++	&and("ecx",0xfffffff8);	# num / 8
++	&mov($w,&wparam(3));	#
++
++	&push("ecx");		# Up the stack for a tmp variable
++
++	&jz(&label("maw_finish"));
++
++	&set_label("maw_loop",16);
++
++	for ($i=0; $i<32; $i+=4)
++		{
++		&comment("Round $i");
++
++		 &mov("eax",&DWP($i,$a)); 	# *a
++		&mul($w);			# *a * w
++		&add("eax",$c);			# L(t)+= c
++		&adc("edx",0);			# H(t)+=carry
++		 &add("eax",&DWP($i,$r));	# L(t)+= *r
++		&adc("edx",0);			# H(t)+=carry
++		 &mov(&DWP($i,$r),"eax");	# *r= L(t);
++		&mov($c,"edx");			# c=  H(t);
++		}
++
++	&comment("");
++	&sub("ecx",8);
++	&lea($a,&DWP(32,$a));
++	&lea($r,&DWP(32,$r));
++	&jnz(&label("maw_loop"));
++
++	&set_label("maw_finish",0);
++	&mov("ecx",&wparam(2));	# get num
++	&and("ecx",7);
++	&jnz(&label("maw_finish2"));	# helps branch prediction
++	&jmp(&label("maw_end"));
++
++	&set_label("maw_finish2",1);
++	for ($i=0; $i<7; $i++)
++		{
++		&comment("Tail Round $i");
++		 &mov("eax",&DWP($i*4,$a));	# *a
++		&mul($w);			# *a * w
++		&add("eax",$c);			# L(t)+=c
++		&adc("edx",0);			# H(t)+=carry
++		 &add("eax",&DWP($i*4,$r));	# L(t)+= *r
++		&adc("edx",0);			# H(t)+=carry
++		 &dec("ecx") if ($i != 7-1);
++		&mov(&DWP($i*4,$r),"eax");	# *r= L(t);
++		 &mov($c,"edx");		# c=  H(t);
++		&jz(&label("maw_end")) if ($i != 7-1);
++		}
++	&set_label("maw_end",0);
++	&mov("eax",$c);
++
++	&pop("ecx");	# clear variable from
++
++	&function_end($name);
++	}
++
++sub bn_mul_words
++	{
++	local($name)=@_;
++
++	&function_begin_B($name,$sse2?"EXTRN\t_OPENSSL_ia32cap_P:DWORD":"");
++
++	$r="eax";
++	$a="edx";
++	$c="ecx";
++
++	if ($sse2) {
++		&picmeup("eax","OPENSSL_ia32cap_P");
++		&bt(&DWP(0,"eax"),26);
++		&jnc(&label("mw_non_sse2"));
++
++		&mov($r,&wparam(0));
++		&mov($a,&wparam(1));
++		&mov($c,&wparam(2));
++		&movd("mm0",&wparam(3));	# mm0 = w
++		&pxor("mm1","mm1");		# mm1 = carry = 0
++
++	&set_label("mw_sse2_loop",16);
++		&movd("mm2",&DWP(0,$a));	# mm2 = a[i]
++		&pmuludq("mm2","mm0");		# a[i] *= w
++		&lea($a,&DWP(4,$a));
++		&paddq("mm1","mm2");		# carry += a[i]*w
++		&movd(&DWP(0,$r),"mm1");	# r[i] = carry_low
++		&sub($c,1);
++		&psrlq("mm1",32);		# carry = carry_high
++		&lea($r,&DWP(4,$r));
++		&jnz(&label("mw_sse2_loop"));
++
++		&movd("eax","mm1");		# return carry
++		&emms();
++		&ret();
++	&set_label("mw_non_sse2",16);
++	}
++
++	# function_begin prologue
++	&push("ebp");
++	&push("ebx");
++	&push("esi");
++	&push("edi");
++
++	&comment("");
++	$Low="eax";
++	$High="edx";
++	$a="ebx";
++	$w="ecx";
++	$r="edi";
++	$c="esi";
++	$num="ebp";
++
++	&xor($c,$c);		# clear carry
++	&mov($r,&wparam(0));	#
++	&mov($a,&wparam(1));	#
++	&mov($num,&wparam(2));	#
++	&mov($w,&wparam(3));	#
++
++	&and($num,0xfffffff8);	# num / 8
++	&jz(&label("mw_finish"));
++
++	&set_label("mw_loop",0);
++	for ($i=0; $i<32; $i+=4)
++		{
++		&comment("Round $i");
++
++		 &mov("eax",&DWP($i,$a,"",0)); 	# *a
++		&mul($w);			# *a * w
++		&add("eax",$c);			# L(t)+=c
++		 # XXX
++
++		&adc("edx",0);			# H(t)+=carry
++		 &mov(&DWP($i,$r,"",0),"eax");	# *r= L(t);
++
++		&mov($c,"edx");			# c=  H(t);
++		}
++
++	&comment("");
++	&add($a,32);
++	&add($r,32);
++	&sub($num,8);
++	&jz(&label("mw_finish"));
++	&jmp(&label("mw_loop"));
++
++	&set_label("mw_finish",0);
++	&mov($num,&wparam(2));	# get num
++	&and($num,7);
++	&jnz(&label("mw_finish2"));
++	&jmp(&label("mw_end"));
++
++	&set_label("mw_finish2",1);
++	for ($i=0; $i<7; $i++)
++		{
++		&comment("Tail Round $i");
++		 &mov("eax",&DWP($i*4,$a,"",0));# *a
++		&mul($w);			# *a * w
++		&add("eax",$c);			# L(t)+=c
++		 # XXX
++		&adc("edx",0);			# H(t)+=carry
++		 &mov(&DWP($i*4,$r,"",0),"eax");# *r= L(t);
++		&mov($c,"edx");			# c=  H(t);
++		 &dec($num) if ($i != 7-1);
++		&jz(&label("mw_end")) if ($i != 7-1);
++		}
++	&set_label("mw_end",0);
++	&mov("eax",$c);
++
++	&function_end($name);
++	}
++
++sub bn_sqr_words
++	{
++	local($name)=@_;
++
++	&function_begin_B($name,$sse2?"EXTRN\t_OPENSSL_ia32cap_P:DWORD":"");
++
++	$r="eax";
++	$a="edx";
++	$c="ecx";
++
++	if ($sse2) {
++		&picmeup("eax","OPENSSL_ia32cap_P");
++		&bt(&DWP(0,"eax"),26);
++		&jnc(&label("sqr_non_sse2"));
++
++		&mov($r,&wparam(0));
++		&mov($a,&wparam(1));
++		&mov($c,&wparam(2));
++
++	&set_label("sqr_sse2_loop",16);
++		&movd("mm0",&DWP(0,$a));	# mm0 = a[i]
++		&pmuludq("mm0","mm0");		# a[i] *= a[i]
++		&lea($a,&DWP(4,$a));		# a++
++		&movq(&QWP(0,$r),"mm0");	# r[i] = a[i]*a[i]
++		&sub($c,1);
++		&lea($r,&DWP(8,$r));		# r += 2
++		&jnz(&label("sqr_sse2_loop"));
++
++		&emms();
++		&ret();
++	&set_label("sqr_non_sse2",16);
++	}
++
++	# function_begin prologue
++	&push("ebp");
++	&push("ebx");
++	&push("esi");
++	&push("edi");
++
++	&comment("");
++	$r="esi";
++	$a="edi";
++	$num="ebx";
++
++	&mov($r,&wparam(0));	#
++	&mov($a,&wparam(1));	#
++	&mov($num,&wparam(2));	#
++
++	&and($num,0xfffffff8);	# num / 8
++	&jz(&label("sw_finish"));
++
++	&set_label("sw_loop",0);
++	for ($i=0; $i<32; $i+=4)
++		{
++		&comment("Round $i");
++		&mov("eax",&DWP($i,$a,"",0)); 	# *a
++		 # XXX
++		&mul("eax");			# *a * *a
++		&mov(&DWP($i*2,$r,"",0),"eax");	#
++		 &mov(&DWP($i*2+4,$r,"",0),"edx");#
++		}
++
++	&comment("");
++	&add($a,32);
++	&add($r,64);
++	&sub($num,8);
++	&jnz(&label("sw_loop"));
++
++	&set_label("sw_finish",0);
++	&mov($num,&wparam(2));	# get num
++	&and($num,7);
++	&jz(&label("sw_end"));
++
++	for ($i=0; $i<7; $i++)
++		{
++		&comment("Tail Round $i");
++		&mov("eax",&DWP($i*4,$a,"",0));	# *a
++		 # XXX
++		&mul("eax");			# *a * *a
++		&mov(&DWP($i*8,$r,"",0),"eax");	#
++		 &dec($num) if ($i != 7-1);
++		&mov(&DWP($i*8+4,$r,"",0),"edx");
++		 &jz(&label("sw_end")) if ($i != 7-1);
++		}
++	&set_label("sw_end",0);
++
++	&function_end($name);
++	}
++
++sub bn_div_words
++	{
++	local($name)=@_;
++
++	&function_begin_B($name,"");
++	&mov("edx",&wparam(0));	#
++	&mov("eax",&wparam(1));	#
++	&mov("ecx",&wparam(2));	#
++	&div("ecx");
++	&ret();
++	&function_end_B($name);
++	}
++
++sub bn_add_words
++	{
++	local($name)=@_;
++
++	&function_begin($name,"");
++
++	&comment("");
++	$a="esi";
++	$b="edi";
++	$c="eax";
++	$r="ebx";
++	$tmp1="ecx";
++	$tmp2="edx";
++	$num="ebp";
++
++	&mov($r,&wparam(0));	# get r
++	 &mov($a,&wparam(1));	# get a
++	&mov($b,&wparam(2));	# get b
++	 &mov($num,&wparam(3));	# get num
++	&xor($c,$c);		# clear carry
++	 &and($num,0xfffffff8);	# num / 8
++
++	&jz(&label("aw_finish"));
++
++	&set_label("aw_loop",0);
++	for ($i=0; $i<8; $i++)
++		{
++		&comment("Round $i");
++
++		&mov($tmp1,&DWP($i*4,$a,"",0)); 	# *a
++		 &mov($tmp2,&DWP($i*4,$b,"",0)); 	# *b
++		&add($tmp1,$c);
++		 &mov($c,0);
++		&adc($c,$c);
++		 &add($tmp1,$tmp2);
++		&adc($c,0);
++		 &mov(&DWP($i*4,$r,"",0),$tmp1); 	# *r
++		}
++
++	&comment("");
++	&add($a,32);
++	 &add($b,32);
++	&add($r,32);
++	 &sub($num,8);
++	&jnz(&label("aw_loop"));
++
++	&set_label("aw_finish",0);
++	&mov($num,&wparam(3));	# get num
++	&and($num,7);
++	 &jz(&label("aw_end"));
++
++	for ($i=0; $i<7; $i++)
++		{
++		&comment("Tail Round $i");
++		&mov($tmp1,&DWP($i*4,$a,"",0));	# *a
++		 &mov($tmp2,&DWP($i*4,$b,"",0));# *b
++		&add($tmp1,$c);
++		 &mov($c,0);
++		&adc($c,$c);
++		 &add($tmp1,$tmp2);
++		&adc($c,0);
++		 &dec($num) if ($i != 6);
++		&mov(&DWP($i*4,$r,"",0),$tmp1);	# *r
++		 &jz(&label("aw_end")) if ($i != 6);
++		}
++	&set_label("aw_end",0);
++
++#	&mov("eax",$c);		# $c is "eax"
++
++	&function_end($name);
++	}
++
++sub bn_sub_words
++	{
++	local($name)=@_;
++
++	&function_begin($name,"");
++
++	&comment("");
++	$a="esi";
++	$b="edi";
++	$c="eax";
++	$r="ebx";
++	$tmp1="ecx";
++	$tmp2="edx";
++	$num="ebp";
++
++	&mov($r,&wparam(0));	# get r
++	 &mov($a,&wparam(1));	# get a
++	&mov($b,&wparam(2));	# get b
++	 &mov($num,&wparam(3));	# get num
++	&xor($c,$c);		# clear carry
++	 &and($num,0xfffffff8);	# num / 8
++
++	&jz(&label("aw_finish"));
++
++	&set_label("aw_loop",0);
++	for ($i=0; $i<8; $i++)
++		{
++		&comment("Round $i");
++
++		&mov($tmp1,&DWP($i*4,$a,"",0)); 	# *a
++		 &mov($tmp2,&DWP($i*4,$b,"",0)); 	# *b
++		&sub($tmp1,$c);
++		 &mov($c,0);
++		&adc($c,$c);
++		 &sub($tmp1,$tmp2);
++		&adc($c,0);
++		 &mov(&DWP($i*4,$r,"",0),$tmp1); 	# *r
++		}
++
++	&comment("");
++	&add($a,32);
++	 &add($b,32);
++	&add($r,32);
++	 &sub($num,8);
++	&jnz(&label("aw_loop"));
++
++	&set_label("aw_finish",0);
++	&mov($num,&wparam(3));	# get num
++	&and($num,7);
++	 &jz(&label("aw_end"));
++
++	for ($i=0; $i<7; $i++)
++		{
++		&comment("Tail Round $i");
++		&mov($tmp1,&DWP($i*4,$a,"",0));	# *a
++		 &mov($tmp2,&DWP($i*4,$b,"",0));# *b
++		&sub($tmp1,$c);
++		 &mov($c,0);
++		&adc($c,$c);
++		 &sub($tmp1,$tmp2);
++		&adc($c,0);
++		 &dec($num) if ($i != 6);
++		&mov(&DWP($i*4,$r,"",0),$tmp1);	# *r
++		 &jz(&label("aw_end")) if ($i != 6);
++		}
++	&set_label("aw_end",0);
++
++#	&mov("eax",$c);		# $c is "eax"
++
++	&function_end($name);
++	}
++
++sub bn_sub_part_words
++	{
++	local($name)=@_;
++
++	&function_begin($name,"");
++
++	&comment("");
++	$a="esi";
++	$b="edi";
++	$c="eax";
++	$r="ebx";
++	$tmp1="ecx";
++	$tmp2="edx";
++	$num="ebp";
++
++	&mov($r,&wparam(0));	# get r
++	 &mov($a,&wparam(1));	# get a
++	&mov($b,&wparam(2));	# get b
++	 &mov($num,&wparam(3));	# get num
++	&xor($c,$c);		# clear carry
++	 &and($num,0xfffffff8);	# num / 8
++
++	&jz(&label("aw_finish"));
++
++	&set_label("aw_loop",0);
++	for ($i=0; $i<8; $i++)
++		{
++		&comment("Round $i");
++
++		&mov($tmp1,&DWP($i*4,$a,"",0)); 	# *a
++		 &mov($tmp2,&DWP($i*4,$b,"",0)); 	# *b
++		&sub($tmp1,$c);
++		 &mov($c,0);
++		&adc($c,$c);
++		 &sub($tmp1,$tmp2);
++		&adc($c,0);
++		 &mov(&DWP($i*4,$r,"",0),$tmp1); 	# *r
++		}
++
++	&comment("");
++	&add($a,32);
++	 &add($b,32);
++	&add($r,32);
++	 &sub($num,8);
++	&jnz(&label("aw_loop"));
++
++	&set_label("aw_finish",0);
++	&mov($num,&wparam(3));	# get num
++	&and($num,7);
++	 &jz(&label("aw_end"));
++
++	for ($i=0; $i<7; $i++)
++		{
++		&comment("Tail Round $i");
++		&mov($tmp1,&DWP(0,$a,"",0));	# *a
++		 &mov($tmp2,&DWP(0,$b,"",0));# *b
++		&sub($tmp1,$c);
++		 &mov($c,0);
++		&adc($c,$c);
++		 &sub($tmp1,$tmp2);
++		&adc($c,0);
++		&mov(&DWP(0,$r,"",0),$tmp1);	# *r
++		&add($a, 4);
++		&add($b, 4);
++		&add($r, 4);
++		 &dec($num) if ($i != 6);
++		 &jz(&label("aw_end")) if ($i != 6);
++		}
++	&set_label("aw_end",0);
++
++	&cmp(&wparam(4),0);
++	&je(&label("pw_end"));
++
++	&mov($num,&wparam(4));	# get dl
++	&cmp($num,0);
++	&je(&label("pw_end"));
++	&jge(&label("pw_pos"));
++
++	&comment("pw_neg");
++	&mov($tmp2,0);
++	&sub($tmp2,$num);
++	&mov($num,$tmp2);
++	&and($num,0xfffffff8);	# num / 8
++	&jz(&label("pw_neg_finish"));
++
++	&set_label("pw_neg_loop",0);
++	for ($i=0; $i<8; $i++)
++	{
++	    &comment("dl<0 Round $i");
++
++	    &mov($tmp1,0);
++	    &mov($tmp2,&DWP($i*4,$b,"",0)); 	# *b
++	    &sub($tmp1,$c);
++	    &mov($c,0);
++	    &adc($c,$c);
++	    &sub($tmp1,$tmp2);
++	    &adc($c,0);
++	    &mov(&DWP($i*4,$r,"",0),$tmp1); 	# *r
++	}
++	    
++	&comment("");
++	&add($b,32);
++	&add($r,32);
++	&sub($num,8);
++	&jnz(&label("pw_neg_loop"));
++	    
++	&set_label("pw_neg_finish",0);
++	&mov($tmp2,&wparam(4));	# get dl
++	&mov($num,0);
++	&sub($num,$tmp2);
++	&and($num,7);
++	&jz(&label("pw_end"));
++	    
++	for ($i=0; $i<7; $i++)
++	{
++	    &comment("dl<0 Tail Round $i");
++	    &mov($tmp1,0);
++	    &mov($tmp2,&DWP($i*4,$b,"",0));# *b
++	    &sub($tmp1,$c);
++	    &mov($c,0);
++	    &adc($c,$c);
++	    &sub($tmp1,$tmp2);
++	    &adc($c,0);
++	    &dec($num) if ($i != 6);
++	    &mov(&DWP($i*4,$r,"",0),$tmp1);	# *r
++	    &jz(&label("pw_end")) if ($i != 6);
++	}
++
++	&jmp(&label("pw_end"));
++	
++	&set_label("pw_pos",0);
++	
++	&and($num,0xfffffff8);	# num / 8
++	&jz(&label("pw_pos_finish"));
++
++	&set_label("pw_pos_loop",0);
++
++	for ($i=0; $i<8; $i++)
++	{
++	    &comment("dl>0 Round $i");
++
++	    &mov($tmp1,&DWP($i*4,$a,"",0));	# *a
++	    &sub($tmp1,$c);
++	    &mov(&DWP($i*4,$r,"",0),$tmp1);	# *r
++	    &jnc(&label("pw_nc".$i));
++	}
++	    
++	&comment("");
++	&add($a,32);
++	&add($r,32);
++	&sub($num,8);
++	&jnz(&label("pw_pos_loop"));
++	    
++	&set_label("pw_pos_finish",0);
++	&mov($num,&wparam(4));	# get dl
++	&and($num,7);
++	&jz(&label("pw_end"));
++	    
++	for ($i=0; $i<7; $i++)
++	{
++	    &comment("dl>0 Tail Round $i");
++	    &mov($tmp1,&DWP($i*4,$a,"",0));	# *a
++	    &sub($tmp1,$c);
++	    &mov(&DWP($i*4,$r,"",0),$tmp1);	# *r
++	    &jnc(&label("pw_tail_nc".$i));
++	    &dec($num) if ($i != 6);
++	    &jz(&label("pw_end")) if ($i != 6);
++	}
++	&mov($c,1);
++	&jmp(&label("pw_end"));
++
++	&set_label("pw_nc_loop",0);
++	for ($i=0; $i<8; $i++)
++	{
++	    &mov($tmp1,&DWP($i*4,$a,"",0));	# *a
++	    &mov(&DWP($i*4,$r,"",0),$tmp1);	# *r
++	    &set_label("pw_nc".$i,0);
++	}
++	    
++	&comment("");
++	&add($a,32);
++	&add($r,32);
++	&sub($num,8);
++	&jnz(&label("pw_nc_loop"));
++	    
++	&mov($num,&wparam(4));	# get dl
++	&and($num,7);
++	&jz(&label("pw_nc_end"));
++	    
++	for ($i=0; $i<7; $i++)
++	{
++	    &mov($tmp1,&DWP($i*4,$a,"",0));	# *a
++	    &mov(&DWP($i*4,$r,"",0),$tmp1);	# *r
++	    &set_label("pw_tail_nc".$i,0);
++	    &dec($num) if ($i != 6);
++	    &jz(&label("pw_nc_end")) if ($i != 6);
++	}
++
++	&set_label("pw_nc_end",0);
++	&mov($c,0);
++
++	&set_label("pw_end",0);
++
++#	&mov("eax",$c);		# $c is "eax"
++
++	&function_end($name);
++	}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/bn/asm/bn-c64xplus.asm b/CryptoPkg/Library/OpensslLib/openssl/crypto/bn/asm/bn-c64xplus.asm
+new file mode 100644
+index 0000000..de6d377
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/bn/asm/bn-c64xplus.asm
+@@ -0,0 +1,382 @@
++;; Copyright 2012-2016 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
++;; in the file LICENSE in the source distribution or at
++;; https://www.openssl.org/source/license.html
++;;
++;;====================================================================
++;; Written by Andy Polyakov  for the OpenSSL
++;; project.
++;;
++;; Rights for redistribution and usage in source and binary forms are
++;; granted according to the OpenSSL license. Warranty of any kind is
++;; disclaimed.
++;;====================================================================
++;; Compiler-generated multiply-n-add SPLOOP runs at 12*n cycles, n
++;; being the number of 32-bit words, addition - 8*n. Corresponding 4x
++;; unrolled SPLOOP-free loops - at ~8*n and ~5*n. Below assembler
++;; SPLOOPs spin at ... 2*n cycles [plus epilogue].
++;;====================================================================
++	.text
++
++	.if	.ASSEMBLER_VERSION<7000000
++	.asg	0,__TI_EABI__
++	.endif
++	.if	__TI_EABI__
++	.asg	bn_mul_add_words,_bn_mul_add_words
++	.asg	bn_mul_words,_bn_mul_words
++	.asg	bn_sqr_words,_bn_sqr_words
++	.asg	bn_add_words,_bn_add_words
++	.asg	bn_sub_words,_bn_sub_words
++	.asg	bn_div_words,_bn_div_words
++	.asg	bn_sqr_comba8,_bn_sqr_comba8
++	.asg	bn_mul_comba8,_bn_mul_comba8
++	.asg	bn_sqr_comba4,_bn_sqr_comba4
++	.asg	bn_mul_comba4,_bn_mul_comba4
++	.endif
++
++	.asg	B3,RA
++	.asg	A4,ARG0
++	.asg	B4,ARG1
++	.asg	A6,ARG2
++	.asg	B6,ARG3
++	.asg	A8,ARG4
++	.asg	B8,ARG5
++	.asg	A4,RET
++	.asg	A15,FP
++	.asg	B14,DP
++	.asg	B15,SP
++
++	.global	_bn_mul_add_words
++_bn_mul_add_words:
++	.asmfunc
++	MV	ARG2,B0
++  [!B0]	BNOP	RA
++||[!B0]	MVK	0,RET
++   [B0]	MVC	B0,ILC
++   [B0]	ZERO	A19		; high part of accumulator
++|| [B0]	MV	ARG0,A2
++|| [B0]	MV	ARG3,A3
++	NOP	3
++
++	SPLOOP	2		; 2*n+10
++;;====================================================================
++	LDW	*ARG1++,B7	; ap[i]
++	NOP	3
++	LDW	*ARG0++,A7	; rp[i]
++	MPY32U	B7,A3,A17:A16
++	NOP	3		; [2,0] in epilogue
++	ADDU	A16,A7,A21:A20
++	ADDU	A19,A21:A20,A19:A18
++||	MV.S	A17,A23
++	SPKERNEL 2,1		; leave slot for "return value"
++||	STW	A18,*A2++	; rp[i]
++||	ADD	A19,A23,A19
++;;====================================================================
++	BNOP	RA,4
++	MV	A19,RET		; return value
++	.endasmfunc
++
++	.global	_bn_mul_words
++_bn_mul_words:
++	.asmfunc
++	MV	ARG2,B0
++  [!B0]	BNOP	RA
++||[!B0]	MVK	0,RET
++   [B0]	MVC	B0,ILC
++   [B0]	ZERO	A19		; high part of accumulator
++	NOP	3
++
++	SPLOOP	2		; 2*n+10
++;;====================================================================
++	LDW	*ARG1++,A7	; ap[i]
++	NOP	4
++	MPY32U	A7,ARG3,A17:A16
++	NOP	4		; [2,0] in epiloque
++	ADDU	A19,A16,A19:A18
++||	MV.S	A17,A21
++	SPKERNEL 2,1		; leave slot for "return value"
++||	STW	A18,*ARG0++	; rp[i]
++||	ADD.L	A19,A21,A19
++;;====================================================================
++	BNOP	RA,4
++	MV	A19,RET		; return value
++	.endasmfunc
++
++	.global	_bn_sqr_words
++_bn_sqr_words:
++	.asmfunc
++	MV	ARG2,B0
++  [!B0]	BNOP	RA
++||[!B0]	MVK	0,RET
++   [B0]	MVC	B0,ILC
++   [B0]	MV	ARG0,B2
++|| [B0]	ADD	4,ARG0,ARG0
++	NOP	3
++
++	SPLOOP	2		; 2*n+10
++;;====================================================================
++	LDW	*ARG1++,B7	; ap[i]
++	NOP	4
++	MPY32U	B7,B7,B1:B0
++	NOP	3		; [2,0] in epilogue
++	STW	B0,*B2++(8)	; rp[2*i]
++	MV	B1,A1
++	SPKERNEL 2,0		; fully overlap BNOP RA,5
++||	STW	A1,*ARG0++(8)	; rp[2*i+1]
++;;====================================================================
++	BNOP	RA,5
++	.endasmfunc
++
++	.global	_bn_add_words
++_bn_add_words:
++	.asmfunc
++	MV	ARG3,B0
++  [!B0]	BNOP	RA
++||[!B0]	MVK	0,RET
++   [B0]	MVC	B0,ILC
++   [B0]	ZERO	A1		; carry flag
++|| [B0]	MV	ARG0,A3
++	NOP	3
++
++	SPLOOP	2		; 2*n+6
++;;====================================================================
++	LDW	*ARG2++,A7	; bp[i]
++||	LDW	*ARG1++,B7	; ap[i]
++	NOP	4
++	ADDU	A7,B7,A9:A8
++	ADDU	A1,A9:A8,A1:A0
++	SPKERNEL 0,0		; fully overlap BNOP RA,5
++||	STW	A0,*A3++	; write result
++||	MV	A1,RET		; keep carry flag in RET
++;;====================================================================
++	BNOP	RA,5
++	.endasmfunc
++
++	.global	_bn_sub_words
++_bn_sub_words:
++	.asmfunc
++	MV	ARG3,B0
++  [!B0]	BNOP	RA
++||[!B0]	MVK	0,RET
++   [B0]	MVC	B0,ILC
++   [B0]	ZERO	A2		; borrow flag
++|| [B0]	MV	ARG0,A3
++	NOP	3
++
++	SPLOOP	2		; 2*n+6
++;;====================================================================
++	LDW	*ARG2++,A7	; bp[i]
++||	LDW	*ARG1++,B7	; ap[i]
++	NOP	4
++	SUBU	B7,A7,A1:A0
++  [A2]	SUB	A1:A0,1,A1:A0
++	SPKERNEL 0,1		; leave slot for "return borrow flag"
++||	STW	A0,*A3++	; write result
++||	AND	1,A1,A2		; pass on borrow flag
++;;====================================================================
++	BNOP	RA,4
++	AND	1,A1,RET	; return borrow flag
++	.endasmfunc
++
++	.global	_bn_div_words
++_bn_div_words:
++	.asmfunc
++	LMBD	1,A6,A0		; leading zero bits in dv
++	LMBD	1,A4,A1		; leading zero bits in hi
++||	MVK	32,B0
++	CMPLTU	A1,A0,A2
++||	ADD	A0,B0,B0
++  [ A2]	BNOP	RA
++||[ A2]	MVK	-1,A4		; return overflow
++||[!A2]	MV	A4,A3		; reassign hi
++  [!A2]	MV	B4,A4		; reassign lo, will be quotient
++||[!A2]	MVC	B0,ILC
++  [!A2]	SHL	A6,A0,A6	; normalize dv
++||	MVK	1,A1
++
++  [!A2]	CMPLTU	A3,A6,A1	; hi>31
++
++	SPLOOP	3
++  [!A1]	CMPLTU	A3,A6,A1	; hi>31
++	SPKERNEL
++
++	BNOP	RA,5
++	.endasmfunc
++
++;;====================================================================
++;; Not really Comba algorithm, just straightforward NxM... Dedicated
++;; fully unrolled real Comba implementations are asymptotically 2x
++;; faster, but naturally larger undertaking. Purpose of this exercise
++;; was rather to learn to master nested SPLOOPs...
++;;====================================================================
++	.global	_bn_sqr_comba8
++	.global	_bn_mul_comba8
++_bn_sqr_comba8:
++	MV	ARG1,ARG2
++_bn_mul_comba8:
++	.asmfunc
++	MVK	8,B0		; N, RILC
++||	MVK	8,A0		; M, outer loop counter
++||	MV	ARG1,A5		; copy ap
++||	MV	ARG0,B4		; copy rp
++||	ZERO	B19		; high part of accumulator
++	MVC	B0,RILC
++||	SUB	B0,2,B1		; N-2, initial ILC
++||	SUB	B0,1,B2		; const B2=N-1
++||	LDW	*A5++,B6	; ap[0]
++||	MV	A0,A3		; const A3=M
++sploopNxM?:			; for best performance arrange M<=N
++   [A0]	SPLOOPD	2		; 2*n+10
++||	MVC	B1,ILC
++||	ADDAW	B4,B0,B5
++||	ZERO	B7
++||	LDW	*A5++,A9	; pre-fetch ap[1]
++||	ZERO	A1
++||	SUB	A0,1,A0
++;;====================================================================
++;; SPLOOP from bn_mul_add_words, but with flipped A<>B register files.
++;; This is because of Advisory 15 from TI publication SPRZ247I.
++	LDW	*ARG2++,A7	; bp[i]
++	NOP	3
++   [A1]	LDW	*B5++,B7	; rp[i]
++	MPY32U	A7,B6,B17:B16
++	NOP	3
++	ADDU	B16,B7,B21:B20
++	ADDU	B19,B21:B20,B19:B18
++||	MV.S	B17,B23
++	SPKERNEL
++||	STW	B18,*B4++	; rp[i]
++||	ADD.S	B19,B23,B19
++;;====================================================================
++outer?:				; m*2*(n+1)+10
++	SUBAW	ARG2,A3,ARG2	; rewind bp to bp[0]
++	SPMASKR
++||	CMPGT	A0,1,A2		; done pre-fetching ap[i+1]?
++	MVD	A9,B6		; move through .M unit(*)
++   [A2]	LDW	*A5++,A9	; pre-fetch ap[i+1]
++	SUBAW	B5,B2,B5	; rewind rp to rp[1]
++	MVK	1,A1
++   [A0]	BNOP.S1	outer?,4
++|| [A0]	SUB.L	A0,1,A0
++	STW	B19,*B4--[B2]	; rewind rp tp rp[1]
++||	ZERO.S	B19		; high part of accumulator
++;; end of outer?
++	BNOP	RA,5		; return
++	.endasmfunc
++;; (*)	It should be noted that B6 is used as input to MPY32U in
++;;	chronologically next cycle in *preceding* SPLOOP iteration.
++;;	Normally such arrangement would require DINT, but at this
++;;	point SPLOOP is draining and interrupts are disabled
++;;	implicitly.
++
++	.global	_bn_sqr_comba4
++	.global	_bn_mul_comba4
++_bn_sqr_comba4:
++	MV	ARG1,ARG2
++_bn_mul_comba4:
++	.asmfunc
++	.if	0
++	BNOP	sploopNxM?,3
++	;; Above mentioned m*2*(n+1)+10 does not apply in n=m=4 case,
++	;; because of low-counter effect, when prologue phase finishes
++	;; before SPKERNEL instruction is reached. As result it's 25%
++	;; slower than expected...
++	MVK	4,B0		; N, RILC
++||	MVK	4,A0		; M, outer loop counter
++||	MV	ARG1,A5		; copy ap
++||	MV	ARG0,B4		; copy rp
++||	ZERO	B19		; high part of accumulator
++	MVC	B0,RILC
++||	SUB	B0,2,B1		; first ILC
++||	SUB	B0,1,B2		; const B2=N-1
++||	LDW	*A5++,B6	; ap[0]
++||	MV	A0,A3		; const A3=M
++	.else
++	;; This alternative is an exercise in fully unrolled Comba
++	;; algorithm implementation that operates at n*(n+1)+12, or
++	;; as little as 32 cycles...
++	LDW	*ARG1[0],B16	; a[0]
++||	LDW	*ARG2[0],A16	; b[0]
++	LDW	*ARG1[1],B17	; a[1]
++||	LDW	*ARG2[1],A17	; b[1]
++	LDW	*ARG1[2],B18	; a[2]
++||	LDW	*ARG2[2],A18	; b[2]
++	LDW	*ARG1[3],B19	; a[3]
++||	LDW	*ARG2[3],A19	; b[3]
++	NOP
++	MPY32U	A16,B16,A1:A0	; a[0]*b[0]
++	MPY32U	A17,B16,A23:A22	; a[0]*b[1]
++	MPY32U	A16,B17,A25:A24	; a[1]*b[0]
++	MPY32U	A16,B18,A27:A26	; a[2]*b[0]
++	STW	A0,*ARG0[0]
++||	MPY32U	A17,B17,A29:A28	; a[1]*b[1]
++	MPY32U	A18,B16,A31:A30	; a[0]*b[2]
++||	ADDU	A22,A1,A1:A0
++	MV	A23,B0
++||	MPY32U	A19,B16,A21:A20	; a[3]*b[0]
++||	ADDU	A24,A1:A0,A1:A0
++	ADDU	A25,B0,B1:B0
++||	STW	A0,*ARG0[1]
++||	MPY32U	A18,B17,A23:A22	; a[2]*b[1]
++||	ADDU	A26,A1,A9:A8
++	ADDU	A27,B1,B9:B8
++||	MPY32U	A17,B18,A25:A24	; a[1]*b[2]
++||	ADDU	A28,A9:A8,A9:A8
++	ADDU	A29,B9:B8,B9:B8
++||	MPY32U	A16,B19,A27:A26	; a[0]*b[3]
++||	ADDU	A30,A9:A8,A9:A8
++	ADDU	A31,B9:B8,B9:B8
++||	ADDU	B0,A9:A8,A9:A8
++	STW	A8,*ARG0[2]
++||	ADDU	A20,A9,A1:A0
++	ADDU	A21,B9,B1:B0
++||	MPY32U	A19,B17,A21:A20	; a[3]*b[1]
++||	ADDU	A22,A1:A0,A1:A0
++	ADDU	A23,B1:B0,B1:B0
++||	MPY32U	A18,B18,A23:A22	; a[2]*b[2]
++||	ADDU	A24,A1:A0,A1:A0
++	ADDU	A25,B1:B0,B1:B0
++||	MPY32U	A17,B19,A25:A24	; a[1]*b[3]
++||	ADDU	A26,A1:A0,A1:A0
++	ADDU	A27,B1:B0,B1:B0
++||	ADDU	B8,A1:A0,A1:A0
++	STW	A0,*ARG0[3]
++||	MPY32U	A19,B18,A27:A26	; a[3]*b[2]
++||	ADDU	A20,A1,A9:A8
++	ADDU	A21,B1,B9:B8
++||	MPY32U	A18,B19,A29:A28	; a[2]*b[3]
++||	ADDU	A22,A9:A8,A9:A8
++	ADDU	A23,B9:B8,B9:B8
++||	MPY32U	A19,B19,A31:A30	; a[3]*b[3]
++||	ADDU	A24,A9:A8,A9:A8
++	ADDU	A25,B9:B8,B9:B8
++||	ADDU	B0,A9:A8,A9:A8
++	STW	A8,*ARG0[4]
++||	ADDU	A26,A9,A1:A0
++	ADDU	A27,B9,B1:B0
++||	ADDU	A28,A1:A0,A1:A0
++	ADDU	A29,B1:B0,B1:B0
++||	BNOP	RA
++||	ADDU	B8,A1:A0,A1:A0
++	STW	A0,*ARG0[5]
++||	ADDU	A30,A1,A9:A8
++	ADD	A31,B1,B8
++	ADDU	B0,A9:A8,A9:A8	; removed || to avoid cross-path stall below
++	ADD	B8,A9,A9
++||	STW	A8,*ARG0[6]
++	STW	A9,*ARG0[7]
++	.endif
++	.endasmfunc
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/bn/asm/c64xplus-gf2m.pl b/CryptoPkg/Library/OpensslLib/openssl/crypto/bn/asm/c64xplus-gf2m.pl
+new file mode 100644
+index 0000000..c0e5400
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/bn/asm/c64xplus-gf2m.pl
+@@ -0,0 +1,160 @@
++#! /usr/bin/env perl
++# Copyright 2012-2016 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
++# in the file LICENSE in the source distribution or at
++# https://www.openssl.org/source/license.html
++
++#
++# ====================================================================
++# Written by Andy Polyakov  for the OpenSSL
++# project. The module is, however, dual licensed under OpenSSL and
++# CRYPTOGAMS licenses depending on where you obtain it. For further
++# details see http://www.openssl.org/~appro/cryptogams/.
++# ====================================================================
++#
++# February 2012
++#
++# The module implements bn_GF2m_mul_2x2 polynomial multiplication
++# used in bn_gf2m.c. It's kind of low-hanging mechanical port from
++# C for the time being... The subroutine runs in 37 cycles, which is
++# 4.5x faster than compiler-generated code. Though comparison is
++# totally unfair, because this module utilizes Galois Field Multiply
++# instruction.
++
++while (($output=shift) && ($output!~/\w[\w\-]*\.\w+$/)) {}
++open STDOUT,">$output";
++
++($rp,$a1,$a0,$b1,$b0)=("A4","B4","A6","B6","A8");   # argument vector
++
++($Alo,$Alox0,$Alox1,$Alox2,$Alox3)=map("A$_",(16..20));
++($Ahi,$Ahix0,$Ahix1,$Ahix2,$Ahix3)=map("B$_",(16..20));
++($B_0,$B_1,$B_2,$B_3)=("B5","A5","A7","B7");
++($A,$B)=($Alo,$B_1);
++$xFF="B1";
++
++sub mul_1x1_upper {
++my ($A,$B)=@_;
++$code.=<<___;
++	EXTU	$B,8,24,$B_2		; smash $B to 4 bytes
++||	AND	$B,$xFF,$B_0
++||	SHRU	$B,24,$B_3
++	SHRU	$A,16,   $Ahi		; smash $A to two halfwords
++||	EXTU	$A,16,16,$Alo
++
++	XORMPY	$Alo,$B_2,$Alox2	; 16x8 bits muliplication
++||	XORMPY	$Ahi,$B_2,$Ahix2
++||	EXTU	$B,16,24,$B_1
++	XORMPY	$Alo,$B_0,$Alox0
++||	XORMPY	$Ahi,$B_0,$Ahix0
++	XORMPY	$Alo,$B_3,$Alox3
++||	XORMPY	$Ahi,$B_3,$Ahix3
++	XORMPY	$Alo,$B_1,$Alox1
++||	XORMPY	$Ahi,$B_1,$Ahix1
++___
++}
++sub mul_1x1_merged {
++my ($OUTlo,$OUThi,$A,$B)=@_;
++$code.=<<___;
++	 EXTU	$B,8,24,$B_2		; smash $B to 4 bytes
++||	 AND	$B,$xFF,$B_0
++||	 SHRU	$B,24,$B_3
++	 SHRU	$A,16,   $Ahi		; smash $A to two halfwords
++||	 EXTU	$A,16,16,$Alo
++
++	XOR	$Ahix0,$Alox2,$Ahix0
++||	MV	$Ahix2,$OUThi
++||	 XORMPY	$Alo,$B_2,$Alox2
++	 XORMPY	$Ahi,$B_2,$Ahix2
++||	 EXTU	$B,16,24,$B_1
++||	 XORMPY	$Alo,$B_0,A1		; $Alox0
++	XOR	$Ahix1,$Alox3,$Ahix1
++||	SHL	$Ahix0,16,$OUTlo
++||	SHRU	$Ahix0,16,$Ahix0
++	XOR	$Alox0,$OUTlo,$OUTlo
++||	XOR	$Ahix0,$OUThi,$OUThi
++||	 XORMPY	$Ahi,$B_0,$Ahix0
++||	 XORMPY	$Alo,$B_3,$Alox3
++||	SHL	$Alox1,8,$Alox1
++||	SHL	$Ahix3,8,$Ahix3
++	XOR	$Alox1,$OUTlo,$OUTlo
++||	XOR	$Ahix3,$OUThi,$OUThi
++||	 XORMPY	$Ahi,$B_3,$Ahix3
++||	SHL	$Ahix1,24,$Alox1
++||	SHRU	$Ahix1,8, $Ahix1
++	XOR	$Alox1,$OUTlo,$OUTlo
++||	XOR	$Ahix1,$OUThi,$OUThi
++||	 XORMPY	$Alo,$B_1,$Alox1
++||	 XORMPY	$Ahi,$B_1,$Ahix1
++||	 MV	A1,$Alox0
++___
++}
++sub mul_1x1_lower {
++my ($OUTlo,$OUThi)=@_;
++$code.=<<___;
++	;NOP
++	XOR	$Ahix0,$Alox2,$Ahix0
++||	MV	$Ahix2,$OUThi
++	NOP
++	XOR	$Ahix1,$Alox3,$Ahix1
++||	SHL	$Ahix0,16,$OUTlo
++||	SHRU	$Ahix0,16,$Ahix0
++	XOR	$Alox0,$OUTlo,$OUTlo
++||	XOR	$Ahix0,$OUThi,$OUThi
++||	SHL	$Alox1,8,$Alox1
++||	SHL	$Ahix3,8,$Ahix3
++	XOR	$Alox1,$OUTlo,$OUTlo
++||	XOR	$Ahix3,$OUThi,$OUThi
++||	SHL	$Ahix1,24,$Alox1
++||	SHRU	$Ahix1,8, $Ahix1
++	XOR	$Alox1,$OUTlo,$OUTlo
++||	XOR	$Ahix1,$OUThi,$OUThi
++___
++}
++$code.=<<___;
++	.text
++
++	.if	.ASSEMBLER_VERSION<7000000
++	.asg	0,__TI_EABI__
++	.endif
++	.if	__TI_EABI__
++	.asg	bn_GF2m_mul_2x2,_bn_GF2m_mul_2x2
++	.endif
++
++	.global	_bn_GF2m_mul_2x2
++_bn_GF2m_mul_2x2:
++	.asmfunc
++	MVK	0xFF,$xFF
++___
++	&mul_1x1_upper($a0,$b0);		# a0·b0
++$code.=<<___;
++||	MV	$b1,$B
++	MV	$a1,$A
++___
++	&mul_1x1_merged("A28","B28",$A,$B);	# a0·b0/a1·b1
++$code.=<<___;
++||	XOR	$b0,$b1,$B
++	XOR	$a0,$a1,$A
++___
++	&mul_1x1_merged("A31","B31",$A,$B);	# a1·b1/(a0+a1)·(b0+b1)
++$code.=<<___;
++	XOR	A28,A31,A29
++||	XOR	B28,B31,B29			; a0·b0+a1·b1
++___
++	&mul_1x1_lower("A30","B30");		# (a0+a1)·(b0+b1)
++$code.=<<___;
++||	BNOP	B3
++	XOR	A29,A30,A30
++||	XOR	B29,B30,B30			; (a0+a1)·(b0+b1)-a0·b0-a1·b1
++	XOR	B28,A30,A30
++||	STW	A28,*${rp}[0]
++	XOR	B30,A31,A31
++||	STW	A30,*${rp}[1]
++	STW	A31,*${rp}[2]
++	STW	B31,*${rp}[3]
++	.endasmfunc
++___
++
++print $code;
++close STDOUT;
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/bn/asm/co-586.pl b/CryptoPkg/Library/OpensslLib/openssl/crypto/bn/asm/co-586.pl
+new file mode 100644
+index 0000000..60d0363
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/bn/asm/co-586.pl
+@@ -0,0 +1,298 @@
++#! /usr/bin/env perl
++# Copyright 1995-2016 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
++# in the file LICENSE in the source distribution or at
++# https://www.openssl.org/source/license.html
++
++$0 =~ m/(.*[\/\\])[^\/\\]+$/; $dir=$1;
++push(@INC,"${dir}","${dir}../../perlasm");
++require "x86asm.pl";
++
++$output = pop;
++open STDOUT,">$output";
++
++&asm_init($ARGV[0],$0);
++
++&bn_mul_comba("bn_mul_comba8",8);
++&bn_mul_comba("bn_mul_comba4",4);
++&bn_sqr_comba("bn_sqr_comba8",8);
++&bn_sqr_comba("bn_sqr_comba4",4);
++
++&asm_finish();
++
++close STDOUT;
++
++sub mul_add_c
++	{
++	local($a,$ai,$b,$bi,$c0,$c1,$c2,$pos,$i,$na,$nb)=@_;
++
++	# pos == -1 if eax and edx are pre-loaded, 0 to load from next
++	# words, and 1 if load return value
++
++	&comment("mul a[$ai]*b[$bi]");
++
++	# "eax" and "edx" will always be pre-loaded.
++	# &mov("eax",&DWP($ai*4,$a,"",0)) ;
++	# &mov("edx",&DWP($bi*4,$b,"",0));
++
++	&mul("edx");
++	&add($c0,"eax");
++	 &mov("eax",&DWP(($na)*4,$a,"",0)) if $pos == 0;	# laod next a
++	 &mov("eax",&wparam(0)) if $pos > 0;			# load r[]
++	 ###
++	&adc($c1,"edx");
++	 &mov("edx",&DWP(($nb)*4,$b,"",0)) if $pos == 0;	# laod next b
++	 &mov("edx",&DWP(($nb)*4,$b,"",0)) if $pos == 1;	# laod next b
++	 ###
++	&adc($c2,0);
++	 # is pos > 1, it means it is the last loop 
++	 &mov(&DWP($i*4,"eax","",0),$c0) if $pos > 0;		# save r[];
++	&mov("eax",&DWP(($na)*4,$a,"",0)) if $pos == 1;		# laod next a
++	}
++
++sub sqr_add_c
++	{
++	local($r,$a,$ai,$bi,$c0,$c1,$c2,$pos,$i,$na,$nb)=@_;
++
++	# pos == -1 if eax and edx are pre-loaded, 0 to load from next
++	# words, and 1 if load return value
++
++	&comment("sqr a[$ai]*a[$bi]");
++
++	# "eax" and "edx" will always be pre-loaded.
++	# &mov("eax",&DWP($ai*4,$a,"",0)) ;
++	# &mov("edx",&DWP($bi*4,$b,"",0));
++
++	if ($ai == $bi)
++		{ &mul("eax");}
++	else
++		{ &mul("edx");}
++	&add($c0,"eax");
++	 &mov("eax",&DWP(($na)*4,$a,"",0)) if $pos == 0;	# load next a
++	 ###
++	&adc($c1,"edx");
++	 &mov("edx",&DWP(($nb)*4,$a,"",0)) if ($pos == 1) && ($na != $nb);
++	 ###
++	&adc($c2,0);
++	 # is pos > 1, it means it is the last loop 
++	 &mov(&DWP($i*4,$r,"",0),$c0) if $pos > 0;		# save r[];
++	&mov("eax",&DWP(($na)*4,$a,"",0)) if $pos == 1;		# load next b
++	}
++
++sub sqr_add_c2
++	{
++	local($r,$a,$ai,$bi,$c0,$c1,$c2,$pos,$i,$na,$nb)=@_;
++
++	# pos == -1 if eax and edx are pre-loaded, 0 to load from next
++	# words, and 1 if load return value
++
++	&comment("sqr a[$ai]*a[$bi]");
++
++	# "eax" and "edx" will always be pre-loaded.
++	# &mov("eax",&DWP($ai*4,$a,"",0)) ;
++	# &mov("edx",&DWP($bi*4,$a,"",0));
++
++	if ($ai == $bi)
++		{ &mul("eax");}
++	else
++		{ &mul("edx");}
++	&add("eax","eax");
++	 ###
++	&adc("edx","edx");
++	 ###
++	&adc($c2,0);
++	 &add($c0,"eax");
++	&adc($c1,"edx");
++	 &mov("eax",&DWP(($na)*4,$a,"",0)) if $pos == 0;	# load next a
++	 &mov("eax",&DWP(($na)*4,$a,"",0)) if $pos == 1;	# load next b
++	&adc($c2,0);
++	&mov(&DWP($i*4,$r,"",0),$c0) if $pos > 0;		# save r[];
++	 &mov("edx",&DWP(($nb)*4,$a,"",0)) if ($pos <= 1) && ($na != $nb);
++	 ###
++	}
++
++sub bn_mul_comba
++	{
++	local($name,$num)=@_;
++	local($a,$b,$c0,$c1,$c2);
++	local($i,$as,$ae,$bs,$be,$ai,$bi);
++	local($tot,$end);
++
++	&function_begin_B($name,"");
++
++	$c0="ebx";
++	$c1="ecx";
++	$c2="ebp";
++	$a="esi";
++	$b="edi";
++	
++	$as=0;
++	$ae=0;
++	$bs=0;
++	$be=0;
++	$tot=$num+$num-1;
++
++	&push("esi");
++	 &mov($a,&wparam(1));
++	&push("edi");
++	 &mov($b,&wparam(2));
++	&push("ebp");
++	 &push("ebx");
++
++	&xor($c0,$c0);
++	 &mov("eax",&DWP(0,$a,"",0));	# load the first word 
++	&xor($c1,$c1);
++	 &mov("edx",&DWP(0,$b,"",0));	# load the first second 
++
++	for ($i=0; $i<$tot; $i++)
++		{
++		$ai=$as;
++		$bi=$bs;
++		$end=$be+1;
++
++		&comment("################## Calculate word $i"); 
++
++		for ($j=$bs; $j<$end; $j++)
++			{
++			&xor($c2,$c2) if ($j == $bs);
++			if (($j+1) == $end)
++				{
++				$v=1;
++				$v=2 if (($i+1) == $tot);
++				}
++			else
++				{ $v=0; }
++			if (($j+1) != $end)
++				{
++				$na=($ai-1);
++				$nb=($bi+1);
++				}
++			else
++				{
++				$na=$as+($i < ($num-1));
++				$nb=$bs+($i >= ($num-1));
++				}
++#printf STDERR "[$ai,$bi] -> [$na,$nb]\n";
++			&mul_add_c($a,$ai,$b,$bi,$c0,$c1,$c2,$v,$i,$na,$nb);
++			if ($v)
++				{
++				&comment("saved r[$i]");
++				# &mov("eax",&wparam(0));
++				# &mov(&DWP($i*4,"eax","",0),$c0);
++				($c0,$c1,$c2)=($c1,$c2,$c0);
++				}
++			$ai--;
++			$bi++;
++			}
++		$as++ if ($i < ($num-1));
++		$ae++ if ($i >= ($num-1));
++
++		$bs++ if ($i >= ($num-1));
++		$be++ if ($i < ($num-1));
++		}
++	&comment("save r[$i]");
++	# &mov("eax",&wparam(0));
++	&mov(&DWP($i*4,"eax","",0),$c0);
++
++	&pop("ebx");
++	&pop("ebp");
++	&pop("edi");
++	&pop("esi");
++	&ret();
++	&function_end_B($name);
++	}
++
++sub bn_sqr_comba
++	{
++	local($name,$num)=@_;
++	local($r,$a,$c0,$c1,$c2)=@_;
++	local($i,$as,$ae,$bs,$be,$ai,$bi);
++	local($b,$tot,$end,$half);
++
++	&function_begin_B($name,"");
++
++	$c0="ebx";
++	$c1="ecx";
++	$c2="ebp";
++	$a="esi";
++	$r="edi";
++
++	&push("esi");
++	 &push("edi");
++	&push("ebp");
++	 &push("ebx");
++	&mov($r,&wparam(0));
++	 &mov($a,&wparam(1));
++	&xor($c0,$c0);
++	 &xor($c1,$c1);
++	&mov("eax",&DWP(0,$a,"",0)); # load the first word
++
++	$as=0;
++	$ae=0;
++	$bs=0;
++	$be=0;
++	$tot=$num+$num-1;
++
++	for ($i=0; $i<$tot; $i++)
++		{
++		$ai=$as;
++		$bi=$bs;
++		$end=$be+1;
++
++		&comment("############### Calculate word $i");
++		for ($j=$bs; $j<$end; $j++)
++			{
++			&xor($c2,$c2) if ($j == $bs);
++			if (($ai-1) < ($bi+1))
++				{
++				$v=1;
++				$v=2 if ($i+1) == $tot;
++				}
++			else
++				{ $v=0; }
++			if (!$v)
++				{
++				$na=$ai-1;
++				$nb=$bi+1;
++				}
++			else
++				{
++				$na=$as+($i < ($num-1));
++				$nb=$bs+($i >= ($num-1));
++				}
++			if ($ai == $bi)
++				{
++				&sqr_add_c($r,$a,$ai,$bi,
++					$c0,$c1,$c2,$v,$i,$na,$nb);
++				}
++			else
++				{
++				&sqr_add_c2($r,$a,$ai,$bi,
++					$c0,$c1,$c2,$v,$i,$na,$nb);
++				}
++			if ($v)
++				{
++				&comment("saved r[$i]");
++				#&mov(&DWP($i*4,$r,"",0),$c0);
++				($c0,$c1,$c2)=($c1,$c2,$c0);
++				last;
++				}
++			$ai--;
++			$bi++;
++			}
++		$as++ if ($i < ($num-1));
++		$ae++ if ($i >= ($num-1));
++
++		$bs++ if ($i >= ($num-1));
++		$be++ if ($i < ($num-1));
++		}
++	&mov(&DWP($i*4,$r,"",0),$c0);
++	&pop("ebx");
++	&pop("ebp");
++	&pop("edi");
++	&pop("esi");
++	&ret();
++	&function_end_B($name);
++	}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/bn/asm/ia64-mont.pl b/CryptoPkg/Library/OpensslLib/openssl/crypto/bn/asm/ia64-mont.pl
+new file mode 100644
+index 0000000..5cc5c59
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/bn/asm/ia64-mont.pl
+@@ -0,0 +1,860 @@
++#! /usr/bin/env perl
++# Copyright 2010-2016 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
++# in the file LICENSE in the source distribution or at
++# https://www.openssl.org/source/license.html
++
++#
++# ====================================================================
++# Written by Andy Polyakov  for the OpenSSL
++# project. The module is, however, dual licensed under OpenSSL and
++# CRYPTOGAMS licenses depending on where you obtain it. For further
++# details see http://www.openssl.org/~appro/cryptogams/.
++# ====================================================================
++
++# January 2010
++#
++# "Teaser" Montgomery multiplication module for IA-64. There are
++# several possibilities for improvement:
++#
++# - modulo-scheduling outer loop would eliminate quite a number of
++#   stalls after ldf8, xma and getf.sig outside inner loop and
++#   improve shorter key performance;
++# - shorter vector support [with input vectors being fetched only
++#   once] should be added;
++# - 2x unroll with help of n0[1] would make the code scalable on
++#   "wider" IA-64, "wider" than Itanium 2 that is, which is not of
++#   acute interest, because upcoming Tukwila's individual cores are
++#   reportedly based on Itanium 2 design;
++# - dedicated squaring procedure(?);
++#
++# January 2010
++#
++# Shorter vector support is implemented by zero-padding ap and np
++# vectors up to 8 elements, or 512 bits. This means that 256-bit
++# inputs will be processed only 2 times faster than 512-bit inputs,
++# not 4 [as one would expect, because algorithm complexity is n^2].
++# The reason for padding is that inputs shorter than 512 bits won't
++# be processed faster anyway, because minimal critical path of the
++# core loop happens to match 512-bit timing. Either way, it resulted
++# in >100% improvement of 512-bit RSA sign benchmark and 50% - of
++# 1024-bit one [in comparison to original version of *this* module].
++#
++# So far 'openssl speed rsa dsa' output on 900MHz Itanium 2 *with*
++# this module is:
++#                   sign    verify    sign/s verify/s
++# rsa  512 bits 0.000290s 0.000024s   3452.8  42031.4
++# rsa 1024 bits 0.000793s 0.000058s   1261.7  17172.0
++# rsa 2048 bits 0.005908s 0.000148s    169.3   6754.0
++# rsa 4096 bits 0.033456s 0.000469s     29.9   2133.6
++# dsa  512 bits 0.000253s 0.000198s   3949.9   5057.0
++# dsa 1024 bits 0.000585s 0.000607s   1708.4   1647.4
++# dsa 2048 bits 0.001453s 0.001703s    688.1    587.4
++#
++# ... and *without* (but still with ia64.S):
++#
++# rsa  512 bits 0.000670s 0.000041s   1491.8  24145.5
++# rsa 1024 bits 0.001988s 0.000080s    502.9  12499.3
++# rsa 2048 bits 0.008702s 0.000189s    114.9   5293.9
++# rsa 4096 bits 0.043860s 0.000533s     22.8   1875.9
++# dsa  512 bits 0.000441s 0.000427s   2265.3   2340.6
++# dsa 1024 bits 0.000823s 0.000867s   1215.6   1153.2
++# dsa 2048 bits 0.001894s 0.002179s    528.1    458.9
++#
++# As it can be seen, RSA sign performance improves by 130-30%,
++# hereafter less for longer keys, while verify - by 74-13%.
++# DSA performance improves by 115-30%.
++
++$output=pop;
++
++if ($^O eq "hpux") {
++    $ADDP="addp4";
++    for (@ARGV) { $ADDP="add" if (/[\+DD|\-mlp]64/); }
++} else { $ADDP="add"; }
++
++$code=<<___;
++.explicit
++.text
++
++// int bn_mul_mont (BN_ULONG *rp,const BN_ULONG *ap,
++//		    const BN_ULONG *bp,const BN_ULONG *np,
++//		    const BN_ULONG *n0p,int num);			
++.align	64
++.global	bn_mul_mont#
++.proc	bn_mul_mont#
++bn_mul_mont:
++	.prologue
++	.body
++{ .mmi;	cmp4.le		p6,p7=2,r37;;
++(p6)	cmp4.lt.unc	p8,p9=8,r37
++	mov		ret0=r0		};;
++{ .bbb;
++(p9)	br.cond.dptk.many	bn_mul_mont_8
++(p8)	br.cond.dpnt.many	bn_mul_mont_general
++(p7)	br.ret.spnt.many	b0	};;
++.endp	bn_mul_mont#
++
++prevfs=r2;	prevpr=r3;	prevlc=r10;	prevsp=r11;
++
++rptr=r8;	aptr=r9;	bptr=r14;	nptr=r15;
++tptr=r16;	// &tp[0]
++tp_1=r17;	// &tp[-1]
++num=r18;	len=r19;	lc=r20;
++topbit=r21;	// carry bit from tmp[num]
++
++n0=f6;
++m0=f7;
++bi=f8;
++
++.align	64
++.local	bn_mul_mont_general#
++.proc	bn_mul_mont_general#
++bn_mul_mont_general:
++	.prologue
++{ .mmi;	.save	ar.pfs,prevfs
++	alloc	prevfs=ar.pfs,6,2,0,8
++	$ADDP	aptr=0,in1
++	.save	ar.lc,prevlc
++	mov	prevlc=ar.lc		}
++{ .mmi;	.vframe	prevsp
++	mov	prevsp=sp
++	$ADDP	bptr=0,in2
++	.save	pr,prevpr
++	mov	prevpr=pr		};;
++
++	.body
++	.rotf		alo[6],nlo[4],ahi[8],nhi[6]
++	.rotr		a[3],n[3],t[2]
++
++{ .mmi;	ldf8		bi=[bptr],8		// (*bp++)
++	ldf8		alo[4]=[aptr],16	// ap[0]
++	$ADDP		r30=8,in1	};;
++{ .mmi;	ldf8		alo[3]=[r30],16		// ap[1]
++	ldf8		alo[2]=[aptr],16	// ap[2]
++	$ADDP		in4=0,in4	};;
++{ .mmi;	ldf8		alo[1]=[r30]		// ap[3]
++	ldf8		n0=[in4]		// n0
++	$ADDP		rptr=0,in0		}
++{ .mmi;	$ADDP		nptr=0,in3
++	mov		r31=16
++	zxt4		num=in5		};;
++{ .mmi;	ldf8		nlo[2]=[nptr],8		// np[0]
++	shladd		len=num,3,r0
++	shladd		r31=num,3,r31	};;
++{ .mmi;	ldf8		nlo[1]=[nptr],8		// np[1]
++	add		lc=-5,num
++	sub		r31=sp,r31	};;
++{ .mfb;	and		sp=-16,r31		// alloca
++	xmpy.hu		ahi[2]=alo[4],bi	// ap[0]*bp[0]
++	nop.b		0		}
++{ .mfb;	nop.m		0
++	xmpy.lu		alo[4]=alo[4],bi
++	brp.loop.imp	.L1st_ctop,.L1st_cend-16
++					};;
++{ .mfi;	nop.m		0
++	xma.hu		ahi[1]=alo[3],bi,ahi[2]	// ap[1]*bp[0]
++	add		tp_1=8,sp	}
++{ .mfi;	nop.m		0
++	xma.lu		alo[3]=alo[3],bi,ahi[2]
++	mov		pr.rot=0x20001f<<16
++			// ------^----- (p40) at first (p23)
++			// ----------^^ p[16:20]=1
++					};;
++{ .mfi;	nop.m		0
++	xmpy.lu		m0=alo[4],n0		// (ap[0]*bp[0])*n0
++	mov		ar.lc=lc	}
++{ .mfi;	nop.m		0
++	fcvt.fxu.s1	nhi[1]=f0
++	mov		ar.ec=8		};;
++
++.align	32
++.L1st_ctop:
++.pred.rel	"mutex",p40,p42
++{ .mfi;	(p16)	ldf8		alo[0]=[aptr],8		    // *(aptr++)
++	(p18)	xma.hu		ahi[0]=alo[2],bi,ahi[1]
++	(p40)	add		n[2]=n[2],a[2]		}   // (p23)					}
++{ .mfi;	(p18)	ldf8		nlo[0]=[nptr],8		    // *(nptr++)(p16)
++	(p18)	xma.lu		alo[2]=alo[2],bi,ahi[1]
++	(p42)	add		n[2]=n[2],a[2],1	};; // (p23)
++{ .mfi;	(p21)	getf.sig	a[0]=alo[5]
++	(p20)	xma.hu		nhi[0]=nlo[2],m0,nhi[1]
++	(p42)	cmp.leu		p41,p39=n[2],a[2]   	}   // (p23)
++{ .mfi;	(p23)	st8		[tp_1]=n[2],8
++	(p20)	xma.lu		nlo[2]=nlo[2],m0,nhi[1]
++	(p40)	cmp.ltu		p41,p39=n[2],a[2]	}   // (p23)
++{ .mmb;	(p21)	getf.sig	n[0]=nlo[3]
++	(p16)	nop.m		0
++	br.ctop.sptk	.L1st_ctop			};;
++.L1st_cend:
++
++{ .mmi;	getf.sig	a[0]=ahi[6]		// (p24)
++	getf.sig	n[0]=nhi[4]
++	add		num=-1,num	};;	// num--
++{ .mmi;	.pred.rel	"mutex",p40,p42
++(p40)	add		n[0]=n[0],a[0]
++(p42)	add		n[0]=n[0],a[0],1
++	sub		aptr=aptr,len	};;	// rewind
++{ .mmi;	.pred.rel	"mutex",p40,p42
++(p40)	cmp.ltu		p41,p39=n[0],a[0]
++(p42)	cmp.leu		p41,p39=n[0],a[0]
++	sub		nptr=nptr,len	};;
++{ .mmi;	.pred.rel	"mutex",p39,p41
++(p39)	add		topbit=r0,r0
++(p41)	add		topbit=r0,r0,1
++	nop.i		0		}	
++{ .mmi;	st8		[tp_1]=n[0]
++	add		tptr=16,sp
++	add		tp_1=8,sp	};;
++
++.Louter:
++{ .mmi;	ldf8		bi=[bptr],8		// (*bp++)
++	ldf8		ahi[3]=[tptr]		// tp[0]
++	add		r30=8,aptr	};;
++{ .mmi;	ldf8		alo[4]=[aptr],16	// ap[0]
++	ldf8		alo[3]=[r30],16		// ap[1]
++	add		r31=8,nptr	};;
++{ .mfb;	ldf8		alo[2]=[aptr],16	// ap[2]
++	xma.hu		ahi[2]=alo[4],bi,ahi[3]	// ap[0]*bp[i]+tp[0]
++	brp.loop.imp	.Linner_ctop,.Linner_cend-16
++					}
++{ .mfb;	ldf8		alo[1]=[r30]		// ap[3]
++	xma.lu		alo[4]=alo[4],bi,ahi[3]
++	clrrrb.pr			};;
++{ .mfi;	ldf8		nlo[2]=[nptr],16	// np[0]
++	xma.hu		ahi[1]=alo[3],bi,ahi[2]	// ap[1]*bp[i]
++	nop.i		0		}
++{ .mfi;	ldf8		nlo[1]=[r31]		// np[1]
++	xma.lu		alo[3]=alo[3],bi,ahi[2]
++	mov		pr.rot=0x20101f<<16
++			// ------^----- (p40) at first (p23)
++			// --------^--- (p30) at first (p22)
++			// ----------^^ p[16:20]=1
++					};;
++{ .mfi;	st8		[tptr]=r0		// tp[0] is already accounted
++	xmpy.lu		m0=alo[4],n0		// (ap[0]*bp[i]+tp[0])*n0
++	mov		ar.lc=lc	}
++{ .mfi;
++	fcvt.fxu.s1	nhi[1]=f0
++	mov		ar.ec=8		};;
++
++// This loop spins in 4*(n+7) ticks on Itanium 2 and should spin in
++// 7*(n+7) ticks on Itanium (the one codenamed Merced). Factor of 7
++// in latter case accounts for two-tick pipeline stall, which means
++// that its performance would be ~20% lower than optimal one. No
++// attempt was made to address this, because original Itanium is
++// hardly represented out in the wild...
++.align	32
++.Linner_ctop:
++.pred.rel	"mutex",p40,p42
++.pred.rel	"mutex",p30,p32
++{ .mfi;	(p16)	ldf8		alo[0]=[aptr],8		    // *(aptr++)
++	(p18)	xma.hu		ahi[0]=alo[2],bi,ahi[1]
++	(p40)	add		n[2]=n[2],a[2]		}   // (p23)
++{ .mfi;	(p16)	nop.m		0
++	(p18)	xma.lu		alo[2]=alo[2],bi,ahi[1]
++	(p42)	add		n[2]=n[2],a[2],1	};; // (p23)
++{ .mfi;	(p21)	getf.sig	a[0]=alo[5]
++	(p16)	nop.f		0
++	(p40)	cmp.ltu		p41,p39=n[2],a[2]	}   // (p23)
++{ .mfi;	(p21)	ld8		t[0]=[tptr],8
++	(p16)	nop.f		0
++	(p42)	cmp.leu		p41,p39=n[2],a[2]	};; // (p23)
++{ .mfi;	(p18)	ldf8		nlo[0]=[nptr],8		    // *(nptr++)
++	(p20)	xma.hu		nhi[0]=nlo[2],m0,nhi[1]
++	(p30)	add		a[1]=a[1],t[1]		}   // (p22)
++{ .mfi;	(p16)	nop.m		0
++	(p20)	xma.lu		nlo[2]=nlo[2],m0,nhi[1]
++	(p32)	add		a[1]=a[1],t[1],1	};; // (p22)
++{ .mmi;	(p21)	getf.sig	n[0]=nlo[3]
++	(p16)	nop.m		0
++	(p30)	cmp.ltu		p31,p29=a[1],t[1]	}   // (p22)
++{ .mmb;	(p23)	st8		[tp_1]=n[2],8
++	(p32)	cmp.leu		p31,p29=a[1],t[1]	    // (p22)
++	br.ctop.sptk	.Linner_ctop			};;
++.Linner_cend:
++
++{ .mmi;	getf.sig	a[0]=ahi[6]		// (p24)
++	getf.sig	n[0]=nhi[4]
++	nop.i		0		};;
++
++{ .mmi;	.pred.rel	"mutex",p31,p33
++(p31)	add		a[0]=a[0],topbit
++(p33)	add		a[0]=a[0],topbit,1
++	mov		topbit=r0	};;
++{ .mfi; .pred.rel	"mutex",p31,p33
++(p31)	cmp.ltu		p32,p30=a[0],topbit
++(p33)	cmp.leu		p32,p30=a[0],topbit
++					}
++{ .mfi;	.pred.rel	"mutex",p40,p42
++(p40)	add		n[0]=n[0],a[0]
++(p42)	add		n[0]=n[0],a[0],1
++					};;
++{ .mmi;	.pred.rel	"mutex",p44,p46
++(p40)	cmp.ltu		p41,p39=n[0],a[0]
++(p42)	cmp.leu		p41,p39=n[0],a[0]
++(p32)	add		topbit=r0,r0,1	}
++
++{ .mmi;	st8		[tp_1]=n[0],8
++	cmp4.ne		p6,p0=1,num
++	sub		aptr=aptr,len	};;	// rewind
++{ .mmi;	sub		nptr=nptr,len
++(p41)	add		topbit=r0,r0,1
++	add		tptr=16,sp	}
++{ .mmb;	add		tp_1=8,sp
++	add		num=-1,num		// num--
++(p6)	br.cond.sptk.many	.Louter	};;
++
++{ .mbb;	add		lc=4,lc
++	brp.loop.imp	.Lsub_ctop,.Lsub_cend-16
++	clrrrb.pr			};;
++{ .mii;	nop.m		0
++	mov		pr.rot=0x10001<<16
++			// ------^---- (p33) at first (p17)
++	mov		ar.lc=lc	}
++{ .mii;	nop.m		0
++	mov		ar.ec=3
++	nop.i		0		};;
++
++.Lsub_ctop:
++.pred.rel	"mutex",p33,p35
++{ .mfi;	(p16)	ld8		t[0]=[tptr],8		    // t=*(tp++)
++	(p16)	nop.f		0
++	(p33)	sub		n[1]=t[1],n[1]		}   // (p17)
++{ .mfi;	(p16)	ld8		n[0]=[nptr],8		    // n=*(np++)
++	(p16)	nop.f		0
++	(p35)	sub		n[1]=t[1],n[1],1	};; // (p17)
++{ .mib;	(p18)	st8		[rptr]=n[2],8		    // *(rp++)=r
++	(p33)	cmp.gtu		p34,p32=n[1],t[1]	    // (p17)
++	(p18)	nop.b		0			}
++{ .mib;	(p18)	nop.m		0
++	(p35)	cmp.geu		p34,p32=n[1],t[1]	    // (p17)
++	br.ctop.sptk	.Lsub_ctop			};;
++.Lsub_cend:
++
++{ .mmb;	.pred.rel	"mutex",p34,p36
++(p34)	sub	topbit=topbit,r0	// (p19)
++(p36)	sub	topbit=topbit,r0,1
++	brp.loop.imp	.Lcopy_ctop,.Lcopy_cend-16
++					}
++{ .mmb;	sub	rptr=rptr,len		// rewind
++	sub	tptr=tptr,len
++	clrrrb.pr			};;
++{ .mmi;	and	aptr=tptr,topbit
++	andcm	bptr=rptr,topbit
++	mov	pr.rot=1<<16		};;
++{ .mii;	or	nptr=aptr,bptr
++	mov	ar.lc=lc
++	mov	ar.ec=3			};;
++
++.Lcopy_ctop:
++{ .mmb;	(p16)	ld8	n[0]=[nptr],8
++	(p18)	st8	[tptr]=r0,8
++	(p16)	nop.b	0		}
++{ .mmb;	(p16)	nop.m	0
++	(p18)	st8	[rptr]=n[2],8
++	br.ctop.sptk	.Lcopy_ctop	};;
++.Lcopy_cend:
++
++{ .mmi;	mov		ret0=1			// signal "handled"
++	rum		1<<5			// clear um.mfh
++	mov		ar.lc=prevlc	}
++{ .mib;	.restore	sp
++	mov		sp=prevsp
++	mov		pr=prevpr,0x1ffff
++	br.ret.sptk.many	b0	};;
++.endp	bn_mul_mont_general#
++
++a1=r16;  a2=r17;  a3=r18;  a4=r19;  a5=r20;  a6=r21;  a7=r22;  a8=r23;
++n1=r24;  n2=r25;  n3=r26;  n4=r27;  n5=r28;  n6=r29;  n7=r30;  n8=r31;
++t0=r15;
++
++ai0=f8;  ai1=f9;  ai2=f10; ai3=f11; ai4=f12; ai5=f13; ai6=f14; ai7=f15;
++ni0=f16; ni1=f17; ni2=f18; ni3=f19; ni4=f20; ni5=f21; ni6=f22; ni7=f23;
++
++.align	64
++.skip	48		// aligns loop body
++.local	bn_mul_mont_8#
++.proc	bn_mul_mont_8#
++bn_mul_mont_8:
++	.prologue
++{ .mmi;	.save		ar.pfs,prevfs
++	alloc		prevfs=ar.pfs,6,2,0,8
++	.vframe		prevsp
++	mov		prevsp=sp
++	.save		ar.lc,prevlc
++	mov		prevlc=ar.lc	}
++{ .mmi;	add		r17=-6*16,sp
++	add		sp=-7*16,sp
++	.save		pr,prevpr
++	mov		prevpr=pr	};;
++
++{ .mmi;	.save.gf	0,0x10
++	stf.spill	[sp]=f16,-16
++	.save.gf	0,0x20
++	stf.spill	[r17]=f17,32
++	add		r16=-5*16,prevsp};;
++{ .mmi;	.save.gf	0,0x40
++	stf.spill	[r16]=f18,32
++	.save.gf	0,0x80
++	stf.spill	[r17]=f19,32
++	$ADDP		aptr=0,in1	};;
++{ .mmi;	.save.gf	0,0x100
++	stf.spill	[r16]=f20,32
++	.save.gf	0,0x200
++	stf.spill	[r17]=f21,32
++	$ADDP		r29=8,in1	};;
++{ .mmi;	.save.gf	0,0x400
++	stf.spill	[r16]=f22
++	.save.gf	0,0x800
++	stf.spill	[r17]=f23
++	$ADDP		rptr=0,in0	};;
++
++	.body
++	.rotf		bj[8],mj[2],tf[2],alo[10],ahi[10],nlo[10],nhi[10]
++	.rotr		t[8]
++
++// load input vectors padding them to 8 elements
++{ .mmi;	ldf8		ai0=[aptr],16		// ap[0]
++	ldf8		ai1=[r29],16		// ap[1]
++	$ADDP		bptr=0,in2	}
++{ .mmi;	$ADDP		r30=8,in2
++	$ADDP		nptr=0,in3
++	$ADDP		r31=8,in3	};;
++{ .mmi;	ldf8		bj[7]=[bptr],16		// bp[0]
++	ldf8		bj[6]=[r30],16		// bp[1]
++	cmp4.le		p4,p5=3,in5	}
++{ .mmi;	ldf8		ni0=[nptr],16		// np[0]
++	ldf8		ni1=[r31],16		// np[1]
++	cmp4.le		p6,p7=4,in5	};;
++
++{ .mfi;	(p4)ldf8	ai2=[aptr],16		// ap[2]
++	(p5)fcvt.fxu	ai2=f0
++	cmp4.le		p8,p9=5,in5	}
++{ .mfi;	(p6)ldf8	ai3=[r29],16		// ap[3]
++	(p7)fcvt.fxu	ai3=f0
++	cmp4.le		p10,p11=6,in5	}
++{ .mfi;	(p4)ldf8	bj[5]=[bptr],16		// bp[2]
++	(p5)fcvt.fxu	bj[5]=f0
++	cmp4.le		p12,p13=7,in5	}
++{ .mfi;	(p6)ldf8	bj[4]=[r30],16		// bp[3]
++	(p7)fcvt.fxu	bj[4]=f0
++	cmp4.le		p14,p15=8,in5	}
++{ .mfi;	(p4)ldf8	ni2=[nptr],16		// np[2]
++	(p5)fcvt.fxu	ni2=f0
++	addp4		r28=-1,in5	}
++{ .mfi;	(p6)ldf8	ni3=[r31],16		// np[3]
++	(p7)fcvt.fxu	ni3=f0
++	$ADDP		in4=0,in4	};;
++
++{ .mfi;	ldf8		n0=[in4]
++	fcvt.fxu	tf[1]=f0
++	nop.i		0		}
++
++{ .mfi;	(p8)ldf8	ai4=[aptr],16		// ap[4]
++	(p9)fcvt.fxu	ai4=f0
++	mov		t[0]=r0		}
++{ .mfi;	(p10)ldf8	ai5=[r29],16		// ap[5]
++	(p11)fcvt.fxu	ai5=f0
++	mov		t[1]=r0		}
++{ .mfi;	(p8)ldf8	bj[3]=[bptr],16		// bp[4]
++	(p9)fcvt.fxu	bj[3]=f0
++	mov		t[2]=r0		}
++{ .mfi;	(p10)ldf8	bj[2]=[r30],16		// bp[5]
++	(p11)fcvt.fxu	bj[2]=f0
++	mov		t[3]=r0		}
++{ .mfi;	(p8)ldf8	ni4=[nptr],16		// np[4]
++	(p9)fcvt.fxu	ni4=f0
++	mov		t[4]=r0		}
++{ .mfi;	(p10)ldf8	ni5=[r31],16		// np[5]
++	(p11)fcvt.fxu	ni5=f0
++	mov		t[5]=r0		};;
++
++{ .mfi;	(p12)ldf8	ai6=[aptr],16		// ap[6]
++	(p13)fcvt.fxu	ai6=f0
++	mov		t[6]=r0		}
++{ .mfi;	(p14)ldf8	ai7=[r29],16		// ap[7]
++	(p15)fcvt.fxu	ai7=f0
++	mov		t[7]=r0		}
++{ .mfi;	(p12)ldf8	bj[1]=[bptr],16		// bp[6]
++	(p13)fcvt.fxu	bj[1]=f0
++	mov		ar.lc=r28	}
++{ .mfi;	(p14)ldf8	bj[0]=[r30],16		// bp[7]
++	(p15)fcvt.fxu	bj[0]=f0
++	mov		ar.ec=1		}
++{ .mfi;	(p12)ldf8	ni6=[nptr],16		// np[6]
++	(p13)fcvt.fxu	ni6=f0
++	mov		pr.rot=1<<16	}
++{ .mfb;	(p14)ldf8	ni7=[r31],16		// np[7]
++	(p15)fcvt.fxu	ni7=f0
++	brp.loop.imp	.Louter_8_ctop,.Louter_8_cend-16
++					};;
++
++// The loop is scheduled for 32*n ticks on Itanium 2. Actual attempt
++// to measure with help of Interval Time Counter indicated that the
++// factor is a tad higher: 33 or 34, if not 35. Exact measurement and
++// addressing the issue is problematic, because I don't have access
++// to platform-specific instruction-level profiler. On Itanium it
++// should run in 56*n ticks, because of higher xma latency...
++.Louter_8_ctop:
++	.pred.rel		"mutex",p40,p42
++	.pred.rel		"mutex",p48,p50
++{ .mfi;	(p16)	nop.m		0			// 0:
++	(p16)	xma.hu		ahi[0]=ai0,bj[7],tf[1]	//	ap[0]*b[i]+t[0]
++	(p40)	add		a3=a3,n3	}	//	(p17) a3+=n3
++{ .mfi;	(p42)	add		a3=a3,n3,1
++	(p16)	xma.lu		alo[0]=ai0,bj[7],tf[1]
++	(p16)	nop.i		0		};;
++{ .mii;	(p17)	getf.sig	a7=alo[8]		// 1:
++	(p48)	add		t[6]=t[6],a3		//	(p17) t[6]+=a3
++	(p50)	add		t[6]=t[6],a3,1	};;
++{ .mfi;	(p17)	getf.sig	a8=ahi[8]		// 2:
++	(p17)	xma.hu		nhi[7]=ni6,mj[1],nhi[6]	//	np[6]*m0
++	(p40)	cmp.ltu		p43,p41=a3,n3	}
++{ .mfi;	(p42)	cmp.leu		p43,p41=a3,n3
++	(p17)	xma.lu		nlo[7]=ni6,mj[1],nhi[6]
++	(p16)	nop.i		0		};;
++{ .mii;	(p17)	getf.sig	n5=nlo[6]		// 3:
++	(p48)	cmp.ltu		p51,p49=t[6],a3
++	(p50)	cmp.leu		p51,p49=t[6],a3	};;
++	.pred.rel		"mutex",p41,p43
++	.pred.rel		"mutex",p49,p51
++{ .mfi;	(p16)	nop.m		0			// 4:
++	(p16)	xma.hu		ahi[1]=ai1,bj[7],ahi[0]	//	ap[1]*b[i]
++	(p41)	add		a4=a4,n4	}	//	(p17) a4+=n4
++{ .mfi;	(p43)	add		a4=a4,n4,1
++	(p16)	xma.lu		alo[1]=ai1,bj[7],ahi[0]
++	(p16)	nop.i		0		};;
++{ .mfi;	(p49)	add		t[5]=t[5],a4		// 5:	(p17) t[5]+=a4
++	(p16)	xmpy.lu		mj[0]=alo[0],n0		//	(ap[0]*b[i]+t[0])*n0
++	(p51)	add		t[5]=t[5],a4,1	};;
++{ .mfi;	(p16)	nop.m		0			// 6:
++	(p17)	xma.hu		nhi[8]=ni7,mj[1],nhi[7]	//	np[7]*m0
++	(p41)	cmp.ltu		p42,p40=a4,n4	}
++{ .mfi;	(p43)	cmp.leu		p42,p40=a4,n4
++	(p17)	xma.lu		nlo[8]=ni7,mj[1],nhi[7]
++	(p16)	nop.i		0		};;
++{ .mii;	(p17)	getf.sig	n6=nlo[7]		// 7:
++	(p49)	cmp.ltu		p50,p48=t[5],a4
++	(p51)	cmp.leu		p50,p48=t[5],a4	};;
++	.pred.rel		"mutex",p40,p42
++	.pred.rel		"mutex",p48,p50
++{ .mfi;	(p16)	nop.m		0			// 8:
++	(p16)	xma.hu		ahi[2]=ai2,bj[7],ahi[1]	//	ap[2]*b[i]
++	(p40)	add		a5=a5,n5	}	//	(p17) a5+=n5
++{ .mfi;	(p42)	add		a5=a5,n5,1
++	(p16)	xma.lu		alo[2]=ai2,bj[7],ahi[1]
++	(p16)	nop.i		0		};;
++{ .mii;	(p16)	getf.sig	a1=alo[1]		// 9:
++	(p48)	add		t[4]=t[4],a5		//	p(17) t[4]+=a5
++	(p50)	add		t[4]=t[4],a5,1	};;
++{ .mfi;	(p16)	nop.m		0			// 10:
++	(p16)	xma.hu		nhi[0]=ni0,mj[0],alo[0]	//	np[0]*m0
++	(p40)	cmp.ltu		p43,p41=a5,n5	}
++{ .mfi;	(p42)	cmp.leu		p43,p41=a5,n5
++	(p16)	xma.lu		nlo[0]=ni0,mj[0],alo[0]
++	(p16)	nop.i		0		};;
++{ .mii;	(p17)	getf.sig	n7=nlo[8]		// 11:
++	(p48)	cmp.ltu		p51,p49=t[4],a5
++	(p50)	cmp.leu		p51,p49=t[4],a5	};;
++	.pred.rel		"mutex",p41,p43
++	.pred.rel		"mutex",p49,p51
++{ .mfi;	(p17)	getf.sig	n8=nhi[8]		// 12:
++	(p16)	xma.hu		ahi[3]=ai3,bj[7],ahi[2]	//	ap[3]*b[i]
++	(p41)	add		a6=a6,n6	}	//	(p17) a6+=n6
++{ .mfi;	(p43)	add		a6=a6,n6,1
++	(p16)	xma.lu		alo[3]=ai3,bj[7],ahi[2]
++	(p16)	nop.i		0		};;
++{ .mii;	(p16)	getf.sig	a2=alo[2]		// 13:
++	(p49)	add		t[3]=t[3],a6		//	(p17) t[3]+=a6
++	(p51)	add		t[3]=t[3],a6,1	};;
++{ .mfi;	(p16)	nop.m		0			// 14:
++	(p16)	xma.hu		nhi[1]=ni1,mj[0],nhi[0]	//	np[1]*m0
++	(p41)	cmp.ltu		p42,p40=a6,n6	}
++{ .mfi;	(p43)	cmp.leu		p42,p40=a6,n6
++	(p16)	xma.lu		nlo[1]=ni1,mj[0],nhi[0]
++	(p16)	nop.i		0		};;
++{ .mii;	(p16)	nop.m		0			// 15:
++	(p49)	cmp.ltu		p50,p48=t[3],a6
++	(p51)	cmp.leu		p50,p48=t[3],a6	};;
++	.pred.rel		"mutex",p40,p42
++	.pred.rel		"mutex",p48,p50
++{ .mfi;	(p16)	nop.m		0			// 16:
++	(p16)	xma.hu		ahi[4]=ai4,bj[7],ahi[3]	//	ap[4]*b[i]
++	(p40)	add		a7=a7,n7	}	//	(p17) a7+=n7
++{ .mfi;	(p42)	add		a7=a7,n7,1
++	(p16)	xma.lu		alo[4]=ai4,bj[7],ahi[3]
++	(p16)	nop.i		0		};;
++{ .mii;	(p16)	getf.sig	a3=alo[3]		// 17:
++	(p48)	add		t[2]=t[2],a7		//	(p17) t[2]+=a7
++	(p50)	add		t[2]=t[2],a7,1	};;
++{ .mfi;	(p16)	nop.m		0			// 18:
++	(p16)	xma.hu		nhi[2]=ni2,mj[0],nhi[1]	//	np[2]*m0
++	(p40)	cmp.ltu		p43,p41=a7,n7	}
++{ .mfi;	(p42)	cmp.leu		p43,p41=a7,n7
++	(p16)	xma.lu		nlo[2]=ni2,mj[0],nhi[1]
++	(p16)	nop.i		0		};;
++{ .mii;	(p16)	getf.sig	n1=nlo[1]		// 19:
++	(p48)	cmp.ltu		p51,p49=t[2],a7
++	(p50)	cmp.leu		p51,p49=t[2],a7	};;
++	.pred.rel		"mutex",p41,p43
++	.pred.rel		"mutex",p49,p51
++{ .mfi;	(p16)	nop.m		0			// 20:
++	(p16)	xma.hu		ahi[5]=ai5,bj[7],ahi[4]	//	ap[5]*b[i]
++	(p41)	add		a8=a8,n8	}	//	(p17) a8+=n8
++{ .mfi;	(p43)	add		a8=a8,n8,1
++	(p16)	xma.lu		alo[5]=ai5,bj[7],ahi[4]
++	(p16)	nop.i		0		};;
++{ .mii;	(p16)	getf.sig	a4=alo[4]		// 21:
++	(p49)	add		t[1]=t[1],a8		//	(p17) t[1]+=a8
++	(p51)	add		t[1]=t[1],a8,1	};;
++{ .mfi;	(p16)	nop.m		0			// 22:
++	(p16)	xma.hu		nhi[3]=ni3,mj[0],nhi[2]	//	np[3]*m0
++	(p41)	cmp.ltu		p42,p40=a8,n8	}
++{ .mfi;	(p43)	cmp.leu		p42,p40=a8,n8
++	(p16)	xma.lu		nlo[3]=ni3,mj[0],nhi[2]
++	(p16)	nop.i		0		};;
++{ .mii;	(p16)	getf.sig	n2=nlo[2]		// 23:
++	(p49)	cmp.ltu		p50,p48=t[1],a8
++	(p51)	cmp.leu		p50,p48=t[1],a8	};;
++{ .mfi;	(p16)	nop.m		0			// 24:
++	(p16)	xma.hu		ahi[6]=ai6,bj[7],ahi[5]	//	ap[6]*b[i]
++	(p16)	add		a1=a1,n1	}	//	(p16) a1+=n1
++{ .mfi;	(p16)	nop.m		0
++	(p16)	xma.lu		alo[6]=ai6,bj[7],ahi[5]
++	(p17)	mov		t[0]=r0		};;
++{ .mii;	(p16)	getf.sig	a5=alo[5]		// 25:
++	(p16)	add		t0=t[7],a1		//	(p16) t[7]+=a1
++	(p42)	add		t[0]=t[0],r0,1	};;
++{ .mfi;	(p16)	setf.sig	tf[0]=t0		// 26:
++	(p16)	xma.hu		nhi[4]=ni4,mj[0],nhi[3]	//	np[4]*m0
++	(p50)	add		t[0]=t[0],r0,1	}
++{ .mfi;	(p16)	cmp.ltu.unc	p42,p40=a1,n1
++	(p16)	xma.lu		nlo[4]=ni4,mj[0],nhi[3]
++	(p16)	nop.i		0		};;
++{ .mii;	(p16)	getf.sig	n3=nlo[3]		// 27:
++	(p16)	cmp.ltu.unc	p50,p48=t0,a1
++	(p16)	nop.i		0		};;
++	.pred.rel		"mutex",p40,p42
++	.pred.rel		"mutex",p48,p50
++{ .mfi;	(p16)	nop.m		0			// 28:
++	(p16)	xma.hu		ahi[7]=ai7,bj[7],ahi[6]	//	ap[7]*b[i]
++	(p40)	add		a2=a2,n2	}	//	(p16) a2+=n2
++{ .mfi;	(p42)	add		a2=a2,n2,1
++	(p16)	xma.lu		alo[7]=ai7,bj[7],ahi[6]
++	(p16)	nop.i		0		};;
++{ .mii;	(p16)	getf.sig	a6=alo[6]		// 29:
++	(p48)	add		t[6]=t[6],a2		//	(p16) t[6]+=a2
++	(p50)	add		t[6]=t[6],a2,1	};;
++{ .mfi;	(p16)	nop.m		0			// 30:
++	(p16)	xma.hu		nhi[5]=ni5,mj[0],nhi[4]	//	np[5]*m0
++	(p40)	cmp.ltu		p41,p39=a2,n2	}
++{ .mfi;	(p42)	cmp.leu		p41,p39=a2,n2
++	(p16)	xma.lu		nlo[5]=ni5,mj[0],nhi[4]
++	(p16)	nop.i		0		};;
++{ .mfi;	(p16)	getf.sig	n4=nlo[4]		// 31:
++	(p16)	nop.f		0
++	(p48)	cmp.ltu		p49,p47=t[6],a2	}
++{ .mfb;	(p50)	cmp.leu		p49,p47=t[6],a2
++	(p16)	nop.f		0
++	br.ctop.sptk.many	.Louter_8_ctop	};;
++.Louter_8_cend:
++
++// above loop has to execute one more time, without (p16), which is
++// replaced with merged move of np[8] to GPR bank
++	.pred.rel		"mutex",p40,p42
++	.pred.rel		"mutex",p48,p50
++{ .mmi;	(p0)	getf.sig	n1=ni0			// 0:
++	(p40)	add		a3=a3,n3		//	(p17) a3+=n3
++	(p42)	add		a3=a3,n3,1	};;
++{ .mii;	(p17)	getf.sig	a7=alo[8]		// 1:
++	(p48)	add		t[6]=t[6],a3		//	(p17) t[6]+=a3
++	(p50)	add		t[6]=t[6],a3,1	};;
++{ .mfi;	(p17)	getf.sig	a8=ahi[8]		// 2:
++	(p17)	xma.hu		nhi[7]=ni6,mj[1],nhi[6]	//	np[6]*m0
++	(p40)	cmp.ltu		p43,p41=a3,n3	}
++{ .mfi;	(p42)	cmp.leu		p43,p41=a3,n3
++	(p17)	xma.lu		nlo[7]=ni6,mj[1],nhi[6]
++	(p0)	nop.i		0		};;
++{ .mii;	(p17)	getf.sig	n5=nlo[6]		// 3:
++	(p48)	cmp.ltu		p51,p49=t[6],a3
++	(p50)	cmp.leu		p51,p49=t[6],a3	};;
++	.pred.rel		"mutex",p41,p43
++	.pred.rel		"mutex",p49,p51
++{ .mmi;	(p0)	getf.sig	n2=ni1			// 4:
++	(p41)	add		a4=a4,n4		//	(p17) a4+=n4
++	(p43)	add		a4=a4,n4,1	};;
++{ .mfi;	(p49)	add		t[5]=t[5],a4		// 5:	(p17) t[5]+=a4
++	(p0)	nop.f		0
++	(p51)	add		t[5]=t[5],a4,1	};;
++{ .mfi;	(p0)	getf.sig	n3=ni2			// 6:
++	(p17)	xma.hu		nhi[8]=ni7,mj[1],nhi[7]	//	np[7]*m0
++	(p41)	cmp.ltu		p42,p40=a4,n4	}
++{ .mfi;	(p43)	cmp.leu		p42,p40=a4,n4
++	(p17)	xma.lu		nlo[8]=ni7,mj[1],nhi[7]
++	(p0)	nop.i		0		};;
++{ .mii;	(p17)	getf.sig	n6=nlo[7]		// 7:
++	(p49)	cmp.ltu		p50,p48=t[5],a4
++	(p51)	cmp.leu		p50,p48=t[5],a4	};;
++	.pred.rel		"mutex",p40,p42
++	.pred.rel		"mutex",p48,p50
++{ .mii;	(p0)	getf.sig	n4=ni3			// 8:
++	(p40)	add		a5=a5,n5		//	(p17) a5+=n5
++	(p42)	add		a5=a5,n5,1	};;
++{ .mii;	(p0)	nop.m		0			// 9:
++	(p48)	add		t[4]=t[4],a5		//	p(17) t[4]+=a5
++	(p50)	add		t[4]=t[4],a5,1	};;
++{ .mii;	(p0)	nop.m		0			// 10:
++	(p40)	cmp.ltu		p43,p41=a5,n5
++	(p42)	cmp.leu		p43,p41=a5,n5	};;
++{ .mii;	(p17)	getf.sig	n7=nlo[8]		// 11:
++	(p48)	cmp.ltu		p51,p49=t[4],a5
++	(p50)	cmp.leu		p51,p49=t[4],a5	};;
++	.pred.rel		"mutex",p41,p43
++	.pred.rel		"mutex",p49,p51
++{ .mii;	(p17)	getf.sig	n8=nhi[8]		// 12:
++	(p41)	add		a6=a6,n6		//	(p17) a6+=n6
++	(p43)	add		a6=a6,n6,1	};;
++{ .mii;	(p0)	getf.sig	n5=ni4			// 13:
++	(p49)	add		t[3]=t[3],a6		//	(p17) t[3]+=a6
++	(p51)	add		t[3]=t[3],a6,1	};;
++{ .mii;	(p0)	nop.m		0			// 14:
++	(p41)	cmp.ltu		p42,p40=a6,n6
++	(p43)	cmp.leu		p42,p40=a6,n6	};;
++{ .mii;	(p0)	getf.sig	n6=ni5			// 15:
++	(p49)	cmp.ltu		p50,p48=t[3],a6
++	(p51)	cmp.leu		p50,p48=t[3],a6	};;
++	.pred.rel		"mutex",p40,p42
++	.pred.rel		"mutex",p48,p50
++{ .mii;	(p0)	nop.m		0			// 16:
++	(p40)	add		a7=a7,n7		//	(p17) a7+=n7
++	(p42)	add		a7=a7,n7,1	};;
++{ .mii;	(p0)	nop.m		0			// 17:
++	(p48)	add		t[2]=t[2],a7		//	(p17) t[2]+=a7
++	(p50)	add		t[2]=t[2],a7,1	};;
++{ .mii;	(p0)	nop.m		0			// 18:
++	(p40)	cmp.ltu		p43,p41=a7,n7
++	(p42)	cmp.leu		p43,p41=a7,n7	};;
++{ .mii;	(p0)	getf.sig	n7=ni6			// 19:
++	(p48)	cmp.ltu		p51,p49=t[2],a7
++	(p50)	cmp.leu		p51,p49=t[2],a7	};;
++	.pred.rel		"mutex",p41,p43
++	.pred.rel		"mutex",p49,p51
++{ .mii;	(p0)	nop.m		0			// 20:
++	(p41)	add		a8=a8,n8		//	(p17) a8+=n8
++	(p43)	add		a8=a8,n8,1	};;
++{ .mmi;	(p0)	nop.m		0			// 21:
++	(p49)	add		t[1]=t[1],a8		//	(p17) t[1]+=a8
++	(p51)	add		t[1]=t[1],a8,1	}
++{ .mmi;	(p17)	mov		t[0]=r0
++	(p41)	cmp.ltu		p42,p40=a8,n8
++	(p43)	cmp.leu		p42,p40=a8,n8	};;
++{ .mmi;	(p0)	getf.sig	n8=ni7			// 22:
++	(p49)	cmp.ltu		p50,p48=t[1],a8
++	(p51)	cmp.leu		p50,p48=t[1],a8	}
++{ .mmi;	(p42)	add		t[0]=t[0],r0,1
++	(p0)	add		r16=-7*16,prevsp
++	(p0)	add		r17=-6*16,prevsp	};;
++
++// subtract np[8] from carrybit|tmp[8]
++// carrybit|tmp[8] layout upon exit from above loop is:
++//	t[0]|t[1]|t[2]|t[3]|t[4]|t[5]|t[6]|t[7]|t0 (least significant)
++{ .mmi;	(p50)add	t[0]=t[0],r0,1
++	add		r18=-5*16,prevsp
++	sub		n1=t0,n1	};;
++{ .mmi;	cmp.gtu		p34,p32=n1,t0;;
++	.pred.rel	"mutex",p32,p34
++	(p32)sub	n2=t[7],n2
++	(p34)sub	n2=t[7],n2,1	};;
++{ .mii;	(p32)cmp.gtu	p35,p33=n2,t[7]
++	(p34)cmp.geu	p35,p33=n2,t[7];;
++	.pred.rel	"mutex",p33,p35
++	(p33)sub	n3=t[6],n3	}
++{ .mmi;	(p35)sub	n3=t[6],n3,1;;
++	(p33)cmp.gtu	p34,p32=n3,t[6]
++	(p35)cmp.geu	p34,p32=n3,t[6]	};;
++	.pred.rel	"mutex",p32,p34
++{ .mii;	(p32)sub	n4=t[5],n4
++	(p34)sub	n4=t[5],n4,1;;
++	(p32)cmp.gtu	p35,p33=n4,t[5]	}
++{ .mmi;	(p34)cmp.geu	p35,p33=n4,t[5];;
++	.pred.rel	"mutex",p33,p35
++	(p33)sub	n5=t[4],n5
++	(p35)sub	n5=t[4],n5,1	};;
++{ .mii;	(p33)cmp.gtu	p34,p32=n5,t[4]
++	(p35)cmp.geu	p34,p32=n5,t[4];;
++	.pred.rel	"mutex",p32,p34
++	(p32)sub	n6=t[3],n6	}
++{ .mmi;	(p34)sub	n6=t[3],n6,1;;
++	(p32)cmp.gtu	p35,p33=n6,t[3]
++	(p34)cmp.geu	p35,p33=n6,t[3]	};;
++	.pred.rel	"mutex",p33,p35
++{ .mii;	(p33)sub	n7=t[2],n7
++	(p35)sub	n7=t[2],n7,1;;
++	(p33)cmp.gtu	p34,p32=n7,t[2]	}
++{ .mmi;	(p35)cmp.geu	p34,p32=n7,t[2];;
++	.pred.rel	"mutex",p32,p34
++	(p32)sub	n8=t[1],n8
++	(p34)sub	n8=t[1],n8,1	};;
++{ .mii;	(p32)cmp.gtu	p35,p33=n8,t[1]
++	(p34)cmp.geu	p35,p33=n8,t[1];;
++	.pred.rel	"mutex",p33,p35
++	(p33)sub	a8=t[0],r0	}
++{ .mmi;	(p35)sub	a8=t[0],r0,1;;
++	(p33)cmp.gtu	p34,p32=a8,t[0]
++	(p35)cmp.geu	p34,p32=a8,t[0]	};;
++
++// save the result, either tmp[num] or tmp[num]-np[num]
++	.pred.rel	"mutex",p32,p34
++{ .mmi;	(p32)st8	[rptr]=n1,8
++	(p34)st8	[rptr]=t0,8
++	add		r19=-4*16,prevsp};;
++{ .mmb;	(p32)st8	[rptr]=n2,8
++	(p34)st8	[rptr]=t[7],8
++	(p5)br.cond.dpnt.few	.Ldone	};;
++{ .mmb;	(p32)st8	[rptr]=n3,8
++	(p34)st8	[rptr]=t[6],8
++	(p7)br.cond.dpnt.few	.Ldone	};;
++{ .mmb;	(p32)st8	[rptr]=n4,8
++	(p34)st8	[rptr]=t[5],8
++	(p9)br.cond.dpnt.few	.Ldone	};;
++{ .mmb;	(p32)st8	[rptr]=n5,8
++	(p34)st8	[rptr]=t[4],8
++	(p11)br.cond.dpnt.few	.Ldone	};;
++{ .mmb;	(p32)st8	[rptr]=n6,8
++	(p34)st8	[rptr]=t[3],8
++	(p13)br.cond.dpnt.few	.Ldone	};;
++{ .mmb;	(p32)st8	[rptr]=n7,8
++	(p34)st8	[rptr]=t[2],8
++	(p15)br.cond.dpnt.few	.Ldone	};;
++{ .mmb;	(p32)st8	[rptr]=n8,8
++	(p34)st8	[rptr]=t[1],8
++	nop.b		0		};;
++.Ldone:						// epilogue
++{ .mmi;	ldf.fill	f16=[r16],64
++	ldf.fill	f17=[r17],64
++	nop.i		0		}
++{ .mmi;	ldf.fill	f18=[r18],64
++	ldf.fill	f19=[r19],64
++	mov		pr=prevpr,0x1ffff	};;
++{ .mmi;	ldf.fill	f20=[r16]
++	ldf.fill	f21=[r17]
++	mov		ar.lc=prevlc	}
++{ .mmi;	ldf.fill	f22=[r18]
++	ldf.fill	f23=[r19]
++	mov		ret0=1		}	// signal "handled"
++{ .mib;	rum		1<<5
++	.restore	sp
++	mov		sp=prevsp
++	br.ret.sptk.many	b0	};;
++.endp	bn_mul_mont_8#
++
++.type	copyright#,\@object
++copyright:
++stringz	"Montgomery multiplication for IA-64, CRYPTOGAMS by "
++___
++
++open STDOUT,">$output" if $output;
++print $code;
++close STDOUT;
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/bn/asm/ia64.S b/CryptoPkg/Library/OpensslLib/openssl/crypto/bn/asm/ia64.S
+new file mode 100644
+index 0000000..f2404a3
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/bn/asm/ia64.S
+@@ -0,0 +1,1562 @@
++.explicit
++.text
++.ident	"ia64.S, Version 2.1"
++.ident	"IA-64 ISA artwork by Andy Polyakov "
++
++// Copyright 2001-2016 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
++// in the file LICENSE in the source distribution or at
++// https://www.openssl.org/source/license.html
++
++//
++// ====================================================================
++// Written by Andy Polyakov  for the OpenSSL
++// project.
++//
++// Rights for redistribution and usage in source and binary forms are
++// granted according to the OpenSSL license. Warranty of any kind is
++// disclaimed.
++// ====================================================================
++//
++// Version 2.x is Itanium2 re-tune. Few words about how Itanum2 is
++// different from Itanium to this module viewpoint. Most notably, is it
++// "wider" than Itanium? Can you experience loop scalability as
++// discussed in commentary sections? Not really:-( Itanium2 has 6
++// integer ALU ports, i.e. it's 2 ports wider, but it's not enough to
++// spin twice as fast, as I need 8 IALU ports. Amount of floating point
++// ports is the same, i.e. 2, while I need 4. In other words, to this
++// module Itanium2 remains effectively as "wide" as Itanium. Yet it's
++// essentially different in respect to this module, and a re-tune was
++// required. Well, because some instruction latencies has changed. Most
++// noticeably those intensively used:
++//
++//			Itanium	Itanium2
++//	ldf8		9	6		L2 hit
++//	ld8		2	1		L1 hit
++//	getf		2	5
++//	xma[->getf]	7[+1]	4[+0]
++//	add[->st8]	1[+1]	1[+0]
++//
++// What does it mean? You might ratiocinate that the original code
++// should run just faster... Because sum of latencies is smaller...
++// Wrong! Note that getf latency increased. This means that if a loop is
++// scheduled for lower latency (as they were), then it will suffer from
++// stall condition and the code will therefore turn anti-scalable, e.g.
++// original bn_mul_words spun at 5*n or 2.5 times slower than expected
++// on Itanium2! What to do? Reschedule loops for Itanium2? But then
++// Itanium would exhibit anti-scalability. So I've chosen to reschedule
++// for worst latency for every instruction aiming for best *all-round*
++// performance.  
++
++// Q.	How much faster does it get?
++// A.	Here is the output from 'openssl speed rsa dsa' for vanilla
++//	0.9.6a compiled with gcc version 2.96 20000731 (Red Hat
++//	Linux 7.1 2.96-81):
++//
++//	                  sign    verify    sign/s verify/s
++//	rsa  512 bits   0.0036s   0.0003s    275.3   2999.2
++//	rsa 1024 bits   0.0203s   0.0011s     49.3    894.1
++//	rsa 2048 bits   0.1331s   0.0040s      7.5    250.9
++//	rsa 4096 bits   0.9270s   0.0147s      1.1     68.1
++//	                  sign    verify    sign/s verify/s
++//	dsa  512 bits   0.0035s   0.0043s    288.3    234.8
++//	dsa 1024 bits   0.0111s   0.0135s     90.0     74.2
++//
++//	And here is similar output but for this assembler
++//	implementation:-)
++//
++//	                  sign    verify    sign/s verify/s
++//	rsa  512 bits   0.0021s   0.0001s    549.4   9638.5
++//	rsa 1024 bits   0.0055s   0.0002s    183.8   4481.1
++//	rsa 2048 bits   0.0244s   0.0006s     41.4   1726.3
++//	rsa 4096 bits   0.1295s   0.0018s      7.7    561.5
++//	                  sign    verify    sign/s verify/s
++//	dsa  512 bits   0.0012s   0.0013s    891.9    756.6
++//	dsa 1024 bits   0.0023s   0.0028s    440.4    376.2
++//	
++//	Yes, you may argue that it's not fair comparison as it's
++//	possible to craft the C implementation with BN_UMULT_HIGH
++//	inline assembler macro. But of course! Here is the output
++//	with the macro:
++//
++//	                  sign    verify    sign/s verify/s
++//	rsa  512 bits   0.0020s   0.0002s    495.0   6561.0
++//	rsa 1024 bits   0.0086s   0.0004s    116.2   2235.7
++//	rsa 2048 bits   0.0519s   0.0015s     19.3    667.3
++//	rsa 4096 bits   0.3464s   0.0053s      2.9    187.7
++//	                  sign    verify    sign/s verify/s
++//	dsa  512 bits   0.0016s   0.0020s    613.1    510.5
++//	dsa 1024 bits   0.0045s   0.0054s    221.0    183.9
++//
++//	My code is still way faster, huh:-) And I believe that even
++//	higher performance can be achieved. Note that as keys get
++//	longer, performance gain is larger. Why? According to the
++//	profiler there is another player in the field, namely
++//	BN_from_montgomery consuming larger and larger portion of CPU
++//	time as keysize decreases. I therefore consider putting effort
++//	to assembler implementation of the following routine:
++//
++//	void bn_mul_add_mont (BN_ULONG *rp,BN_ULONG *np,int nl,BN_ULONG n0)
++//	{
++//	int      i,j;
++//	BN_ULONG v;
++//
++//	for (i=0; i for the OpenSSL
++# project. The module is, however, dual licensed under OpenSSL and
++# CRYPTOGAMS licenses depending on where you obtain it. For further
++# details see http://www.openssl.org/~appro/cryptogams/.
++# ====================================================================
++
++# This module doesn't present direct interest for OpenSSL, because it
++# doesn't provide better performance for longer keys, at least not on
++# in-order-execution cores. While 512-bit RSA sign operations can be
++# 65% faster in 64-bit mode, 1024-bit ones are only 15% faster, and
++# 4096-bit ones are up to 15% slower. In 32-bit mode it varies from
++# 16% improvement for 512-bit RSA sign to -33% for 4096-bit RSA
++# verify:-( All comparisons are against bn_mul_mont-free assembler.
++# The module might be of interest to embedded system developers, as
++# the code is smaller than 1KB, yet offers >3x improvement on MIPS64
++# and 75-30% [less for longer keys] on MIPS32 over compiler-generated
++# code.
++
++######################################################################
++# There is a number of MIPS ABI in use, O32 and N32/64 are most
++# widely used. Then there is a new contender: NUBI. It appears that if
++# one picks the latter, it's possible to arrange code in ABI neutral
++# manner. Therefore let's stick to NUBI register layout:
++#
++($zero,$at,$t0,$t1,$t2)=map("\$$_",(0..2,24,25));
++($a0,$a1,$a2,$a3,$a4,$a5,$a6,$a7)=map("\$$_",(4..11));
++($s0,$s1,$s2,$s3,$s4,$s5,$s6,$s7,$s8,$s9,$s10,$s11)=map("\$$_",(12..23));
++($gp,$tp,$sp,$fp,$ra)=map("\$$_",(3,28..31));
++#
++# The return value is placed in $a0. Following coding rules facilitate
++# interoperability:
++#
++# - never ever touch $tp, "thread pointer", former $gp;
++# - copy return value to $t0, former $v0 [or to $a0 if you're adapting
++#   old code];
++# - on O32 populate $a4-$a7 with 'lw $aN,4*N($sp)' if necessary;
++#
++# For reference here is register layout for N32/64 MIPS ABIs:
++#
++# ($zero,$at,$v0,$v1)=map("\$$_",(0..3));
++# ($a0,$a1,$a2,$a3,$a4,$a5,$a6,$a7)=map("\$$_",(4..11));
++# ($t0,$t1,$t2,$t3,$t8,$t9)=map("\$$_",(12..15,24,25));
++# ($s0,$s1,$s2,$s3,$s4,$s5,$s6,$s7)=map("\$$_",(16..23));
++# ($gp,$sp,$fp,$ra)=map("\$$_",(28..31));
++#
++$flavour = shift || "o32"; # supported flavours are o32,n32,64,nubi32,nubi64
++
++if ($flavour =~ /64|n32/i) {
++	$PTR_ADD="dadd";	# incidentally works even on n32
++	$PTR_SUB="dsub";	# incidentally works even on n32
++	$REG_S="sd";
++	$REG_L="ld";
++	$SZREG=8;
++} else {
++	$PTR_ADD="add";
++	$PTR_SUB="sub";
++	$REG_S="sw";
++	$REG_L="lw";
++	$SZREG=4;
++}
++$SAVED_REGS_MASK = ($flavour =~ /nubi/i) ? 0x00fff000 : 0x00ff0000;
++#
++# 
++#
++######################################################################
++
++while (($output=shift) && ($output!~/\w[\w\-]*\.\w+$/)) {}
++open STDOUT,">$output";
++
++if ($flavour =~ /64|n32/i) {
++	$LD="ld";
++	$ST="sd";
++	$MULTU="dmultu";
++	$ADDU="daddu";
++	$SUBU="dsubu";
++	$BNSZ=8;
++} else {
++	$LD="lw";
++	$ST="sw";
++	$MULTU="multu";
++	$ADDU="addu";
++	$SUBU="subu";
++	$BNSZ=4;
++}
++
++# int bn_mul_mont(
++$rp=$a0;	# BN_ULONG *rp,
++$ap=$a1;	# const BN_ULONG *ap,
++$bp=$a2;	# const BN_ULONG *bp,
++$np=$a3;	# const BN_ULONG *np,
++$n0=$a4;	# const BN_ULONG *n0,
++$num=$a5;	# int num);
++
++$lo0=$a6;
++$hi0=$a7;
++$lo1=$t1;
++$hi1=$t2;
++$aj=$s0;
++$bi=$s1;
++$nj=$s2;
++$tp=$s3;
++$alo=$s4;
++$ahi=$s5;
++$nlo=$s6;
++$nhi=$s7;
++$tj=$s8;
++$i=$s9;
++$j=$s10;
++$m1=$s11;
++
++$FRAMESIZE=14;
++
++$code=<<___;
++.text
++
++.set	noat
++.set	noreorder
++
++.align	5
++.globl	bn_mul_mont
++.ent	bn_mul_mont
++bn_mul_mont:
++___
++$code.=<<___ if ($flavour =~ /o32/i);
++	lw	$n0,16($sp)
++	lw	$num,20($sp)
++___
++$code.=<<___;
++	slt	$at,$num,4
++	bnez	$at,1f
++	li	$t0,0
++	slt	$at,$num,17	# on in-order CPU
++	bnez	$at,bn_mul_mont_internal
++	nop
++1:	jr	$ra
++	li	$a0,0
++.end	bn_mul_mont
++
++.align	5
++.ent	bn_mul_mont_internal
++bn_mul_mont_internal:
++	.frame	$fp,$FRAMESIZE*$SZREG,$ra
++	.mask	0x40000000|$SAVED_REGS_MASK,-$SZREG
++	$PTR_SUB $sp,$FRAMESIZE*$SZREG
++	$REG_S	$fp,($FRAMESIZE-1)*$SZREG($sp)
++	$REG_S	$s11,($FRAMESIZE-2)*$SZREG($sp)
++	$REG_S	$s10,($FRAMESIZE-3)*$SZREG($sp)
++	$REG_S	$s9,($FRAMESIZE-4)*$SZREG($sp)
++	$REG_S	$s8,($FRAMESIZE-5)*$SZREG($sp)
++	$REG_S	$s7,($FRAMESIZE-6)*$SZREG($sp)
++	$REG_S	$s6,($FRAMESIZE-7)*$SZREG($sp)
++	$REG_S	$s5,($FRAMESIZE-8)*$SZREG($sp)
++	$REG_S	$s4,($FRAMESIZE-9)*$SZREG($sp)
++___
++$code.=<<___ if ($flavour =~ /nubi/i);
++	$REG_S	$s3,($FRAMESIZE-10)*$SZREG($sp)
++	$REG_S	$s2,($FRAMESIZE-11)*$SZREG($sp)
++	$REG_S	$s1,($FRAMESIZE-12)*$SZREG($sp)
++	$REG_S	$s0,($FRAMESIZE-13)*$SZREG($sp)
++___
++$code.=<<___;
++	move	$fp,$sp
++
++	.set	reorder
++	$LD	$n0,0($n0)
++	$LD	$bi,0($bp)	# bp[0]
++	$LD	$aj,0($ap)	# ap[0]
++	$LD	$nj,0($np)	# np[0]
++
++	$PTR_SUB $sp,2*$BNSZ	# place for two extra words
++	sll	$num,`log($BNSZ)/log(2)`
++	li	$at,-4096
++	$PTR_SUB $sp,$num
++	and	$sp,$at
++
++	$MULTU	$aj,$bi
++	$LD	$alo,$BNSZ($ap)
++	$LD	$nlo,$BNSZ($np)
++	mflo	$lo0
++	mfhi	$hi0
++	$MULTU	$lo0,$n0
++	mflo	$m1
++
++	$MULTU	$alo,$bi
++	mflo	$alo
++	mfhi	$ahi
++
++	$MULTU	$nj,$m1
++	mflo	$lo1
++	mfhi	$hi1
++	$MULTU	$nlo,$m1
++	$ADDU	$lo1,$lo0
++	sltu	$at,$lo1,$lo0
++	$ADDU	$hi1,$at
++	mflo	$nlo
++	mfhi	$nhi
++
++	move	$tp,$sp
++	li	$j,2*$BNSZ
++.align	4
++.L1st:
++	.set	noreorder
++	$PTR_ADD $aj,$ap,$j
++	$PTR_ADD $nj,$np,$j
++	$LD	$aj,($aj)
++	$LD	$nj,($nj)
++
++	$MULTU	$aj,$bi
++	$ADDU	$lo0,$alo,$hi0
++	$ADDU	$lo1,$nlo,$hi1
++	sltu	$at,$lo0,$hi0
++	sltu	$t0,$lo1,$hi1
++	$ADDU	$hi0,$ahi,$at
++	$ADDU	$hi1,$nhi,$t0
++	mflo	$alo
++	mfhi	$ahi
++
++	$ADDU	$lo1,$lo0
++	sltu	$at,$lo1,$lo0
++	$MULTU	$nj,$m1
++	$ADDU	$hi1,$at
++	addu	$j,$BNSZ
++	$ST	$lo1,($tp)
++	sltu	$t0,$j,$num
++	mflo	$nlo
++	mfhi	$nhi
++
++	bnez	$t0,.L1st
++	$PTR_ADD $tp,$BNSZ
++	.set	reorder
++
++	$ADDU	$lo0,$alo,$hi0
++	sltu	$at,$lo0,$hi0
++	$ADDU	$hi0,$ahi,$at
++
++	$ADDU	$lo1,$nlo,$hi1
++	sltu	$t0,$lo1,$hi1
++	$ADDU	$hi1,$nhi,$t0
++	$ADDU	$lo1,$lo0
++	sltu	$at,$lo1,$lo0
++	$ADDU	$hi1,$at
++
++	$ST	$lo1,($tp)
++
++	$ADDU	$hi1,$hi0
++	sltu	$at,$hi1,$hi0
++	$ST	$hi1,$BNSZ($tp)
++	$ST	$at,2*$BNSZ($tp)
++
++	li	$i,$BNSZ
++.align	4
++.Louter:
++	$PTR_ADD $bi,$bp,$i
++	$LD	$bi,($bi)
++	$LD	$aj,($ap)
++	$LD	$alo,$BNSZ($ap)
++	$LD	$tj,($sp)
++
++	$MULTU	$aj,$bi
++	$LD	$nj,($np)
++	$LD	$nlo,$BNSZ($np)
++	mflo	$lo0
++	mfhi	$hi0
++	$ADDU	$lo0,$tj
++	$MULTU	$lo0,$n0
++	sltu	$at,$lo0,$tj
++	$ADDU	$hi0,$at
++	mflo	$m1
++
++	$MULTU	$alo,$bi
++	mflo	$alo
++	mfhi	$ahi
++
++	$MULTU	$nj,$m1
++	mflo	$lo1
++	mfhi	$hi1
++
++	$MULTU	$nlo,$m1
++	$ADDU	$lo1,$lo0
++	sltu	$at,$lo1,$lo0
++	$ADDU	$hi1,$at
++	mflo	$nlo
++	mfhi	$nhi
++
++	move	$tp,$sp
++	li	$j,2*$BNSZ
++	$LD	$tj,$BNSZ($tp)
++.align	4
++.Linner:
++	.set	noreorder
++	$PTR_ADD $aj,$ap,$j
++	$PTR_ADD $nj,$np,$j
++	$LD	$aj,($aj)
++	$LD	$nj,($nj)
++
++	$MULTU	$aj,$bi
++	$ADDU	$lo0,$alo,$hi0
++	$ADDU	$lo1,$nlo,$hi1
++	sltu	$at,$lo0,$hi0
++	sltu	$t0,$lo1,$hi1
++	$ADDU	$hi0,$ahi,$at
++	$ADDU	$hi1,$nhi,$t0
++	mflo	$alo
++	mfhi	$ahi
++
++	$ADDU	$lo0,$tj
++	addu	$j,$BNSZ
++	$MULTU	$nj,$m1
++	sltu	$at,$lo0,$tj
++	$ADDU	$lo1,$lo0
++	$ADDU	$hi0,$at
++	sltu	$t0,$lo1,$lo0
++	$LD	$tj,2*$BNSZ($tp)
++	$ADDU	$hi1,$t0
++	sltu	$at,$j,$num
++	mflo	$nlo
++	mfhi	$nhi
++	$ST	$lo1,($tp)
++	bnez	$at,.Linner
++	$PTR_ADD $tp,$BNSZ
++	.set	reorder
++
++	$ADDU	$lo0,$alo,$hi0
++	sltu	$at,$lo0,$hi0
++	$ADDU	$hi0,$ahi,$at
++	$ADDU	$lo0,$tj
++	sltu	$t0,$lo0,$tj
++	$ADDU	$hi0,$t0
++
++	$LD	$tj,2*$BNSZ($tp)
++	$ADDU	$lo1,$nlo,$hi1
++	sltu	$at,$lo1,$hi1
++	$ADDU	$hi1,$nhi,$at
++	$ADDU	$lo1,$lo0
++	sltu	$t0,$lo1,$lo0
++	$ADDU	$hi1,$t0
++	$ST	$lo1,($tp)
++
++	$ADDU	$lo1,$hi1,$hi0
++	sltu	$hi1,$lo1,$hi0
++	$ADDU	$lo1,$tj
++	sltu	$at,$lo1,$tj
++	$ADDU	$hi1,$at
++	$ST	$lo1,$BNSZ($tp)
++	$ST	$hi1,2*$BNSZ($tp)
++
++	addu	$i,$BNSZ
++	sltu	$t0,$i,$num
++	bnez	$t0,.Louter
++
++	.set	noreorder
++	$PTR_ADD $tj,$sp,$num	# &tp[num]
++	move	$tp,$sp
++	move	$ap,$sp
++	li	$hi0,0		# clear borrow bit
++
++.align	4
++.Lsub:	$LD	$lo0,($tp)
++	$LD	$lo1,($np)
++	$PTR_ADD $tp,$BNSZ
++	$PTR_ADD $np,$BNSZ
++	$SUBU	$lo1,$lo0,$lo1	# tp[i]-np[i]
++	sgtu	$at,$lo1,$lo0
++	$SUBU	$lo0,$lo1,$hi0
++	sgtu	$hi0,$lo0,$lo1
++	$ST	$lo0,($rp)
++	or	$hi0,$at
++	sltu	$at,$tp,$tj
++	bnez	$at,.Lsub
++	$PTR_ADD $rp,$BNSZ
++
++	$SUBU	$hi0,$hi1,$hi0	# handle upmost overflow bit
++	move	$tp,$sp
++	$PTR_SUB $rp,$num	# restore rp
++	not	$hi1,$hi0
++
++	and	$ap,$hi0,$sp
++	and	$bp,$hi1,$rp
++	or	$ap,$ap,$bp	# ap=borrow?tp:rp
++
++.align	4
++.Lcopy:	$LD	$aj,($ap)
++	$PTR_ADD $ap,$BNSZ
++	$ST	$zero,($tp)
++	$PTR_ADD $tp,$BNSZ
++	sltu	$at,$tp,$tj
++	$ST	$aj,($rp)
++	bnez	$at,.Lcopy
++	$PTR_ADD $rp,$BNSZ
++
++	li	$a0,1
++	li	$t0,1
++
++	.set	noreorder
++	move	$sp,$fp
++	$REG_L	$fp,($FRAMESIZE-1)*$SZREG($sp)
++	$REG_L	$s11,($FRAMESIZE-2)*$SZREG($sp)
++	$REG_L	$s10,($FRAMESIZE-3)*$SZREG($sp)
++	$REG_L	$s9,($FRAMESIZE-4)*$SZREG($sp)
++	$REG_L	$s8,($FRAMESIZE-5)*$SZREG($sp)
++	$REG_L	$s7,($FRAMESIZE-6)*$SZREG($sp)
++	$REG_L	$s6,($FRAMESIZE-7)*$SZREG($sp)
++	$REG_L	$s5,($FRAMESIZE-8)*$SZREG($sp)
++	$REG_L	$s4,($FRAMESIZE-9)*$SZREG($sp)
++___
++$code.=<<___ if ($flavour =~ /nubi/i);
++	$REG_L	$s3,($FRAMESIZE-10)*$SZREG($sp)
++	$REG_L	$s2,($FRAMESIZE-11)*$SZREG($sp)
++	$REG_L	$s1,($FRAMESIZE-12)*$SZREG($sp)
++	$REG_L	$s0,($FRAMESIZE-13)*$SZREG($sp)
++___
++$code.=<<___;
++	jr	$ra
++	$PTR_ADD $sp,$FRAMESIZE*$SZREG
++.end	bn_mul_mont_internal
++.rdata
++.asciiz	"Montgomery Multiplication for MIPS, CRYPTOGAMS by "
++___
++
++$code =~ s/\`([^\`]*)\`/eval $1/gem;
++
++print $code;
++close STDOUT;
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/bn/asm/mips.pl b/CryptoPkg/Library/OpensslLib/openssl/crypto/bn/asm/mips.pl
+new file mode 100644
+index 0000000..420f01f
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/bn/asm/mips.pl
+@@ -0,0 +1,2241 @@
++#! /usr/bin/env perl
++# Copyright 2010-2016 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
++# in the file LICENSE in the source distribution or at
++# https://www.openssl.org/source/license.html
++
++#
++# ====================================================================
++# Written by Andy Polyakov  for the OpenSSL
++# project.
++#
++# Rights for redistribution and usage in source and binary forms are
++# granted according to the OpenSSL license. Warranty of any kind is
++# disclaimed.
++# ====================================================================
++
++
++# July 1999
++#
++# This is drop-in MIPS III/IV ISA replacement for crypto/bn/bn_asm.c.
++#
++# The module is designed to work with either of the "new" MIPS ABI(5),
++# namely N32 or N64, offered by IRIX 6.x. It's not meant to work under
++# IRIX 5.x not only because it doesn't support new ABIs but also
++# because 5.x kernels put R4x00 CPU into 32-bit mode and all those
++# 64-bit instructions (daddu, dmultu, etc.) found below gonna only
++# cause illegal instruction exception:-(
++#
++# In addition the code depends on preprocessor flags set up by MIPSpro
++# compiler driver (either as or cc) and therefore (probably?) can't be
++# compiled by the GNU assembler. GNU C driver manages fine though...
++# I mean as long as -mmips-as is specified or is the default option,
++# because then it simply invokes /usr/bin/as which in turn takes
++# perfect care of the preprocessor definitions. Another neat feature
++# offered by the MIPSpro assembler is an optimization pass. This gave
++# me the opportunity to have the code looking more regular as all those
++# architecture dependent instruction rescheduling details were left to
++# the assembler. Cool, huh?
++#
++# Performance improvement is astonishing! 'apps/openssl speed rsa dsa'
++# goes way over 3 times faster!
++#
++#					
++
++# October 2010
++#
++# Adapt the module even for 32-bit ABIs and other OSes. The former was
++# achieved by mechanical replacement of 64-bit arithmetic instructions
++# such as dmultu, daddu, etc. with their 32-bit counterparts and
++# adjusting offsets denoting multiples of BN_ULONG. Above mentioned
++# >3x performance improvement naturally does not apply to 32-bit code
++# [because there is no instruction 32-bit compiler can't use], one
++# has to content with 40-85% improvement depending on benchmark and
++# key length, more for longer keys.
++
++$flavour = shift || "o32";
++while (($output=shift) && ($output!~/\w[\w\-]*\.\w+$/)) {}
++open STDOUT,">$output";
++
++if ($flavour =~ /64|n32/i) {
++	$LD="ld";
++	$ST="sd";
++	$MULTU="dmultu";
++	$DIVU="ddivu";
++	$ADDU="daddu";
++	$SUBU="dsubu";
++	$SRL="dsrl";
++	$SLL="dsll";
++	$BNSZ=8;
++	$PTR_ADD="daddu";
++	$PTR_SUB="dsubu";
++	$SZREG=8;
++	$REG_S="sd";
++	$REG_L="ld";
++} else {
++	$LD="lw";
++	$ST="sw";
++	$MULTU="multu";
++	$DIVU="divu";
++	$ADDU="addu";
++	$SUBU="subu";
++	$SRL="srl";
++	$SLL="sll";
++	$BNSZ=4;
++	$PTR_ADD="addu";
++	$PTR_SUB="subu";
++	$SZREG=4;
++	$REG_S="sw";
++	$REG_L="lw";
++	$code=".set	mips2\n";
++}
++
++# Below is N32/64 register layout used in the original module.
++#
++($zero,$at,$v0,$v1)=map("\$$_",(0..3));
++($a0,$a1,$a2,$a3,$a4,$a5,$a6,$a7)=map("\$$_",(4..11));
++($t0,$t1,$t2,$t3,$t8,$t9)=map("\$$_",(12..15,24,25));
++($s0,$s1,$s2,$s3,$s4,$s5,$s6,$s7)=map("\$$_",(16..23));
++($gp,$sp,$fp,$ra)=map("\$$_",(28..31));
++($ta0,$ta1,$ta2,$ta3)=($a4,$a5,$a6,$a7);
++#
++# No special adaptation is required for O32. NUBI on the other hand
++# is treated by saving/restoring ($v1,$t0..$t3).
++
++$gp=$v1 if ($flavour =~ /nubi/i);
++
++$minus4=$v1;
++
++$code.=<<___;
++.rdata
++.asciiz	"mips3.s, Version 1.2"
++.asciiz	"MIPS II/III/IV ISA artwork by Andy Polyakov "
++
++.text
++.set	noat
++
++.align	5
++.globl	bn_mul_add_words
++.ent	bn_mul_add_words
++bn_mul_add_words:
++	.set	noreorder
++	bgtz	$a2,bn_mul_add_words_internal
++	move	$v0,$zero
++	jr	$ra
++	move	$a0,$v0
++.end	bn_mul_add_words
++
++.align	5
++.ent	bn_mul_add_words_internal
++bn_mul_add_words_internal:
++___
++$code.=<<___ if ($flavour =~ /nubi/i);
++	.frame	$sp,6*$SZREG,$ra
++	.mask	0x8000f008,-$SZREG
++	.set	noreorder
++	$PTR_SUB $sp,6*$SZREG
++	$REG_S	$ra,5*$SZREG($sp)
++	$REG_S	$t3,4*$SZREG($sp)
++	$REG_S	$t2,3*$SZREG($sp)
++	$REG_S	$t1,2*$SZREG($sp)
++	$REG_S	$t0,1*$SZREG($sp)
++	$REG_S	$gp,0*$SZREG($sp)
++___
++$code.=<<___;
++	.set	reorder
++	li	$minus4,-4
++	and	$ta0,$a2,$minus4
++	beqz	$ta0,.L_bn_mul_add_words_tail
++
++.L_bn_mul_add_words_loop:
++	$LD	$t0,0($a1)
++	$MULTU	$t0,$a3
++	$LD	$t1,0($a0)
++	$LD	$t2,$BNSZ($a1)
++	$LD	$t3,$BNSZ($a0)
++	$LD	$ta0,2*$BNSZ($a1)
++	$LD	$ta1,2*$BNSZ($a0)
++	$ADDU	$t1,$v0
++	sltu	$v0,$t1,$v0	# All manuals say it "compares 32-bit
++				# values", but it seems to work fine
++				# even on 64-bit registers.
++	mflo	$at
++	mfhi	$t0
++	$ADDU	$t1,$at
++	$ADDU	$v0,$t0
++	 $MULTU	$t2,$a3
++	sltu	$at,$t1,$at
++	$ST	$t1,0($a0)
++	$ADDU	$v0,$at
++
++	$LD	$ta2,3*$BNSZ($a1)
++	$LD	$ta3,3*$BNSZ($a0)
++	$ADDU	$t3,$v0
++	sltu	$v0,$t3,$v0
++	mflo	$at
++	mfhi	$t2
++	$ADDU	$t3,$at
++	$ADDU	$v0,$t2
++	 $MULTU	$ta0,$a3
++	sltu	$at,$t3,$at
++	$ST	$t3,$BNSZ($a0)
++	$ADDU	$v0,$at
++
++	subu	$a2,4
++	$PTR_ADD $a0,4*$BNSZ
++	$PTR_ADD $a1,4*$BNSZ
++	$ADDU	$ta1,$v0
++	sltu	$v0,$ta1,$v0
++	mflo	$at
++	mfhi	$ta0
++	$ADDU	$ta1,$at
++	$ADDU	$v0,$ta0
++	 $MULTU	$ta2,$a3
++	sltu	$at,$ta1,$at
++	$ST	$ta1,-2*$BNSZ($a0)
++	$ADDU	$v0,$at
++
++
++	and	$ta0,$a2,$minus4
++	$ADDU	$ta3,$v0
++	sltu	$v0,$ta3,$v0
++	mflo	$at
++	mfhi	$ta2
++	$ADDU	$ta3,$at
++	$ADDU	$v0,$ta2
++	sltu	$at,$ta3,$at
++	$ST	$ta3,-$BNSZ($a0)
++	.set	noreorder
++	bgtz	$ta0,.L_bn_mul_add_words_loop
++	$ADDU	$v0,$at
++
++	beqz	$a2,.L_bn_mul_add_words_return
++	nop
++
++.L_bn_mul_add_words_tail:
++	.set	reorder
++	$LD	$t0,0($a1)
++	$MULTU	$t0,$a3
++	$LD	$t1,0($a0)
++	subu	$a2,1
++	$ADDU	$t1,$v0
++	sltu	$v0,$t1,$v0
++	mflo	$at
++	mfhi	$t0
++	$ADDU	$t1,$at
++	$ADDU	$v0,$t0
++	sltu	$at,$t1,$at
++	$ST	$t1,0($a0)
++	$ADDU	$v0,$at
++	beqz	$a2,.L_bn_mul_add_words_return
++
++	$LD	$t0,$BNSZ($a1)
++	$MULTU	$t0,$a3
++	$LD	$t1,$BNSZ($a0)
++	subu	$a2,1
++	$ADDU	$t1,$v0
++	sltu	$v0,$t1,$v0
++	mflo	$at
++	mfhi	$t0
++	$ADDU	$t1,$at
++	$ADDU	$v0,$t0
++	sltu	$at,$t1,$at
++	$ST	$t1,$BNSZ($a0)
++	$ADDU	$v0,$at
++	beqz	$a2,.L_bn_mul_add_words_return
++
++	$LD	$t0,2*$BNSZ($a1)
++	$MULTU	$t0,$a3
++	$LD	$t1,2*$BNSZ($a0)
++	$ADDU	$t1,$v0
++	sltu	$v0,$t1,$v0
++	mflo	$at
++	mfhi	$t0
++	$ADDU	$t1,$at
++	$ADDU	$v0,$t0
++	sltu	$at,$t1,$at
++	$ST	$t1,2*$BNSZ($a0)
++	$ADDU	$v0,$at
++
++.L_bn_mul_add_words_return:
++	.set	noreorder
++___
++$code.=<<___ if ($flavour =~ /nubi/i);
++	$REG_L	$t3,4*$SZREG($sp)
++	$REG_L	$t2,3*$SZREG($sp)
++	$REG_L	$t1,2*$SZREG($sp)
++	$REG_L	$t0,1*$SZREG($sp)
++	$REG_L	$gp,0*$SZREG($sp)
++	$PTR_ADD $sp,6*$SZREG
++___
++$code.=<<___;
++	jr	$ra
++	move	$a0,$v0
++.end	bn_mul_add_words_internal
++
++.align	5
++.globl	bn_mul_words
++.ent	bn_mul_words
++bn_mul_words:
++	.set	noreorder
++	bgtz	$a2,bn_mul_words_internal
++	move	$v0,$zero
++	jr	$ra
++	move	$a0,$v0
++.end	bn_mul_words
++
++.align	5
++.ent	bn_mul_words_internal
++bn_mul_words_internal:
++___
++$code.=<<___ if ($flavour =~ /nubi/i);
++	.frame	$sp,6*$SZREG,$ra
++	.mask	0x8000f008,-$SZREG
++	.set	noreorder
++	$PTR_SUB $sp,6*$SZREG
++	$REG_S	$ra,5*$SZREG($sp)
++	$REG_S	$t3,4*$SZREG($sp)
++	$REG_S	$t2,3*$SZREG($sp)
++	$REG_S	$t1,2*$SZREG($sp)
++	$REG_S	$t0,1*$SZREG($sp)
++	$REG_S	$gp,0*$SZREG($sp)
++___
++$code.=<<___;
++	.set	reorder
++	li	$minus4,-4
++	and	$ta0,$a2,$minus4
++	beqz	$ta0,.L_bn_mul_words_tail
++
++.L_bn_mul_words_loop:
++	$LD	$t0,0($a1)
++	$MULTU	$t0,$a3
++	$LD	$t2,$BNSZ($a1)
++	$LD	$ta0,2*$BNSZ($a1)
++	$LD	$ta2,3*$BNSZ($a1)
++	mflo	$at
++	mfhi	$t0
++	$ADDU	$v0,$at
++	sltu	$t1,$v0,$at
++	 $MULTU	$t2,$a3
++	$ST	$v0,0($a0)
++	$ADDU	$v0,$t1,$t0
++
++	subu	$a2,4
++	$PTR_ADD $a0,4*$BNSZ
++	$PTR_ADD $a1,4*$BNSZ
++	mflo	$at
++	mfhi	$t2
++	$ADDU	$v0,$at
++	sltu	$t3,$v0,$at
++	 $MULTU	$ta0,$a3
++	$ST	$v0,-3*$BNSZ($a0)
++	$ADDU	$v0,$t3,$t2
++
++	mflo	$at
++	mfhi	$ta0
++	$ADDU	$v0,$at
++	sltu	$ta1,$v0,$at
++	 $MULTU	$ta2,$a3
++	$ST	$v0,-2*$BNSZ($a0)
++	$ADDU	$v0,$ta1,$ta0
++
++	and	$ta0,$a2,$minus4
++	mflo	$at
++	mfhi	$ta2
++	$ADDU	$v0,$at
++	sltu	$ta3,$v0,$at
++	$ST	$v0,-$BNSZ($a0)
++	.set	noreorder
++	bgtz	$ta0,.L_bn_mul_words_loop
++	$ADDU	$v0,$ta3,$ta2
++
++	beqz	$a2,.L_bn_mul_words_return
++	nop
++
++.L_bn_mul_words_tail:
++	.set	reorder
++	$LD	$t0,0($a1)
++	$MULTU	$t0,$a3
++	subu	$a2,1
++	mflo	$at
++	mfhi	$t0
++	$ADDU	$v0,$at
++	sltu	$t1,$v0,$at
++	$ST	$v0,0($a0)
++	$ADDU	$v0,$t1,$t0
++	beqz	$a2,.L_bn_mul_words_return
++
++	$LD	$t0,$BNSZ($a1)
++	$MULTU	$t0,$a3
++	subu	$a2,1
++	mflo	$at
++	mfhi	$t0
++	$ADDU	$v0,$at
++	sltu	$t1,$v0,$at
++	$ST	$v0,$BNSZ($a0)
++	$ADDU	$v0,$t1,$t0
++	beqz	$a2,.L_bn_mul_words_return
++
++	$LD	$t0,2*$BNSZ($a1)
++	$MULTU	$t0,$a3
++	mflo	$at
++	mfhi	$t0
++	$ADDU	$v0,$at
++	sltu	$t1,$v0,$at
++	$ST	$v0,2*$BNSZ($a0)
++	$ADDU	$v0,$t1,$t0
++
++.L_bn_mul_words_return:
++	.set	noreorder
++___
++$code.=<<___ if ($flavour =~ /nubi/i);
++	$REG_L	$t3,4*$SZREG($sp)
++	$REG_L	$t2,3*$SZREG($sp)
++	$REG_L	$t1,2*$SZREG($sp)
++	$REG_L	$t0,1*$SZREG($sp)
++	$REG_L	$gp,0*$SZREG($sp)
++	$PTR_ADD $sp,6*$SZREG
++___
++$code.=<<___;
++	jr	$ra
++	move	$a0,$v0
++.end	bn_mul_words_internal
++
++.align	5
++.globl	bn_sqr_words
++.ent	bn_sqr_words
++bn_sqr_words:
++	.set	noreorder
++	bgtz	$a2,bn_sqr_words_internal
++	move	$v0,$zero
++	jr	$ra
++	move	$a0,$v0
++.end	bn_sqr_words
++
++.align	5
++.ent	bn_sqr_words_internal
++bn_sqr_words_internal:
++___
++$code.=<<___ if ($flavour =~ /nubi/i);
++	.frame	$sp,6*$SZREG,$ra
++	.mask	0x8000f008,-$SZREG
++	.set	noreorder
++	$PTR_SUB $sp,6*$SZREG
++	$REG_S	$ra,5*$SZREG($sp)
++	$REG_S	$t3,4*$SZREG($sp)
++	$REG_S	$t2,3*$SZREG($sp)
++	$REG_S	$t1,2*$SZREG($sp)
++	$REG_S	$t0,1*$SZREG($sp)
++	$REG_S	$gp,0*$SZREG($sp)
++___
++$code.=<<___;
++	.set	reorder
++	li	$minus4,-4
++	and	$ta0,$a2,$minus4
++	beqz	$ta0,.L_bn_sqr_words_tail
++
++.L_bn_sqr_words_loop:
++	$LD	$t0,0($a1)
++	$MULTU	$t0,$t0
++	$LD	$t2,$BNSZ($a1)
++	$LD	$ta0,2*$BNSZ($a1)
++	$LD	$ta2,3*$BNSZ($a1)
++	mflo	$t1
++	mfhi	$t0
++	$ST	$t1,0($a0)
++	$ST	$t0,$BNSZ($a0)
++
++	$MULTU	$t2,$t2
++	subu	$a2,4
++	$PTR_ADD $a0,8*$BNSZ
++	$PTR_ADD $a1,4*$BNSZ
++	mflo	$t3
++	mfhi	$t2
++	$ST	$t3,-6*$BNSZ($a0)
++	$ST	$t2,-5*$BNSZ($a0)
++
++	$MULTU	$ta0,$ta0
++	mflo	$ta1
++	mfhi	$ta0
++	$ST	$ta1,-4*$BNSZ($a0)
++	$ST	$ta0,-3*$BNSZ($a0)
++
++
++	$MULTU	$ta2,$ta2
++	and	$ta0,$a2,$minus4
++	mflo	$ta3
++	mfhi	$ta2
++	$ST	$ta3,-2*$BNSZ($a0)
++
++	.set	noreorder
++	bgtz	$ta0,.L_bn_sqr_words_loop
++	$ST	$ta2,-$BNSZ($a0)
++
++	beqz	$a2,.L_bn_sqr_words_return
++	nop
++
++.L_bn_sqr_words_tail:
++	.set	reorder
++	$LD	$t0,0($a1)
++	$MULTU	$t0,$t0
++	subu	$a2,1
++	mflo	$t1
++	mfhi	$t0
++	$ST	$t1,0($a0)
++	$ST	$t0,$BNSZ($a0)
++	beqz	$a2,.L_bn_sqr_words_return
++
++	$LD	$t0,$BNSZ($a1)
++	$MULTU	$t0,$t0
++	subu	$a2,1
++	mflo	$t1
++	mfhi	$t0
++	$ST	$t1,2*$BNSZ($a0)
++	$ST	$t0,3*$BNSZ($a0)
++	beqz	$a2,.L_bn_sqr_words_return
++
++	$LD	$t0,2*$BNSZ($a1)
++	$MULTU	$t0,$t0
++	mflo	$t1
++	mfhi	$t0
++	$ST	$t1,4*$BNSZ($a0)
++	$ST	$t0,5*$BNSZ($a0)
++
++.L_bn_sqr_words_return:
++	.set	noreorder
++___
++$code.=<<___ if ($flavour =~ /nubi/i);
++	$REG_L	$t3,4*$SZREG($sp)
++	$REG_L	$t2,3*$SZREG($sp)
++	$REG_L	$t1,2*$SZREG($sp)
++	$REG_L	$t0,1*$SZREG($sp)
++	$REG_L	$gp,0*$SZREG($sp)
++	$PTR_ADD $sp,6*$SZREG
++___
++$code.=<<___;
++	jr	$ra
++	move	$a0,$v0
++
++.end	bn_sqr_words_internal
++
++.align	5
++.globl	bn_add_words
++.ent	bn_add_words
++bn_add_words:
++	.set	noreorder
++	bgtz	$a3,bn_add_words_internal
++	move	$v0,$zero
++	jr	$ra
++	move	$a0,$v0
++.end	bn_add_words
++
++.align	5
++.ent	bn_add_words_internal
++bn_add_words_internal:
++___
++$code.=<<___ if ($flavour =~ /nubi/i);
++	.frame	$sp,6*$SZREG,$ra
++	.mask	0x8000f008,-$SZREG
++	.set	noreorder
++	$PTR_SUB $sp,6*$SZREG
++	$REG_S	$ra,5*$SZREG($sp)
++	$REG_S	$t3,4*$SZREG($sp)
++	$REG_S	$t2,3*$SZREG($sp)
++	$REG_S	$t1,2*$SZREG($sp)
++	$REG_S	$t0,1*$SZREG($sp)
++	$REG_S	$gp,0*$SZREG($sp)
++___
++$code.=<<___;
++	.set	reorder
++	li	$minus4,-4
++	and	$at,$a3,$minus4
++	beqz	$at,.L_bn_add_words_tail
++
++.L_bn_add_words_loop:
++	$LD	$t0,0($a1)
++	$LD	$ta0,0($a2)
++	subu	$a3,4
++	$LD	$t1,$BNSZ($a1)
++	and	$at,$a3,$minus4
++	$LD	$t2,2*$BNSZ($a1)
++	$PTR_ADD $a2,4*$BNSZ
++	$LD	$t3,3*$BNSZ($a1)
++	$PTR_ADD $a0,4*$BNSZ
++	$LD	$ta1,-3*$BNSZ($a2)
++	$PTR_ADD $a1,4*$BNSZ
++	$LD	$ta2,-2*$BNSZ($a2)
++	$LD	$ta3,-$BNSZ($a2)
++	$ADDU	$ta0,$t0
++	sltu	$t8,$ta0,$t0
++	$ADDU	$t0,$ta0,$v0
++	sltu	$v0,$t0,$ta0
++	$ST	$t0,-4*$BNSZ($a0)
++	$ADDU	$v0,$t8
++
++	$ADDU	$ta1,$t1
++	sltu	$t9,$ta1,$t1
++	$ADDU	$t1,$ta1,$v0
++	sltu	$v0,$t1,$ta1
++	$ST	$t1,-3*$BNSZ($a0)
++	$ADDU	$v0,$t9
++
++	$ADDU	$ta2,$t2
++	sltu	$t8,$ta2,$t2
++	$ADDU	$t2,$ta2,$v0
++	sltu	$v0,$t2,$ta2
++	$ST	$t2,-2*$BNSZ($a0)
++	$ADDU	$v0,$t8
++	
++	$ADDU	$ta3,$t3
++	sltu	$t9,$ta3,$t3
++	$ADDU	$t3,$ta3,$v0
++	sltu	$v0,$t3,$ta3
++	$ST	$t3,-$BNSZ($a0)
++	
++	.set	noreorder
++	bgtz	$at,.L_bn_add_words_loop
++	$ADDU	$v0,$t9
++
++	beqz	$a3,.L_bn_add_words_return
++	nop
++
++.L_bn_add_words_tail:
++	.set	reorder
++	$LD	$t0,0($a1)
++	$LD	$ta0,0($a2)
++	$ADDU	$ta0,$t0
++	subu	$a3,1
++	sltu	$t8,$ta0,$t0
++	$ADDU	$t0,$ta0,$v0
++	sltu	$v0,$t0,$ta0
++	$ST	$t0,0($a0)
++	$ADDU	$v0,$t8
++	beqz	$a3,.L_bn_add_words_return
++
++	$LD	$t1,$BNSZ($a1)
++	$LD	$ta1,$BNSZ($a2)
++	$ADDU	$ta1,$t1
++	subu	$a3,1
++	sltu	$t9,$ta1,$t1
++	$ADDU	$t1,$ta1,$v0
++	sltu	$v0,$t1,$ta1
++	$ST	$t1,$BNSZ($a0)
++	$ADDU	$v0,$t9
++	beqz	$a3,.L_bn_add_words_return
++
++	$LD	$t2,2*$BNSZ($a1)
++	$LD	$ta2,2*$BNSZ($a2)
++	$ADDU	$ta2,$t2
++	sltu	$t8,$ta2,$t2
++	$ADDU	$t2,$ta2,$v0
++	sltu	$v0,$t2,$ta2
++	$ST	$t2,2*$BNSZ($a0)
++	$ADDU	$v0,$t8
++
++.L_bn_add_words_return:
++	.set	noreorder
++___
++$code.=<<___ if ($flavour =~ /nubi/i);
++	$REG_L	$t3,4*$SZREG($sp)
++	$REG_L	$t2,3*$SZREG($sp)
++	$REG_L	$t1,2*$SZREG($sp)
++	$REG_L	$t0,1*$SZREG($sp)
++	$REG_L	$gp,0*$SZREG($sp)
++	$PTR_ADD $sp,6*$SZREG
++___
++$code.=<<___;
++	jr	$ra
++	move	$a0,$v0
++
++.end	bn_add_words_internal
++
++.align	5
++.globl	bn_sub_words
++.ent	bn_sub_words
++bn_sub_words:
++	.set	noreorder
++	bgtz	$a3,bn_sub_words_internal
++	move	$v0,$zero
++	jr	$ra
++	move	$a0,$zero
++.end	bn_sub_words
++
++.align	5
++.ent	bn_sub_words_internal
++bn_sub_words_internal:
++___
++$code.=<<___ if ($flavour =~ /nubi/i);
++	.frame	$sp,6*$SZREG,$ra
++	.mask	0x8000f008,-$SZREG
++	.set	noreorder
++	$PTR_SUB $sp,6*$SZREG
++	$REG_S	$ra,5*$SZREG($sp)
++	$REG_S	$t3,4*$SZREG($sp)
++	$REG_S	$t2,3*$SZREG($sp)
++	$REG_S	$t1,2*$SZREG($sp)
++	$REG_S	$t0,1*$SZREG($sp)
++	$REG_S	$gp,0*$SZREG($sp)
++___
++$code.=<<___;
++	.set	reorder
++	li	$minus4,-4
++	and	$at,$a3,$minus4
++	beqz	$at,.L_bn_sub_words_tail
++
++.L_bn_sub_words_loop:
++	$LD	$t0,0($a1)
++	$LD	$ta0,0($a2)
++	subu	$a3,4
++	$LD	$t1,$BNSZ($a1)
++	and	$at,$a3,$minus4
++	$LD	$t2,2*$BNSZ($a1)
++	$PTR_ADD $a2,4*$BNSZ
++	$LD	$t3,3*$BNSZ($a1)
++	$PTR_ADD $a0,4*$BNSZ
++	$LD	$ta1,-3*$BNSZ($a2)
++	$PTR_ADD $a1,4*$BNSZ
++	$LD	$ta2,-2*$BNSZ($a2)
++	$LD	$ta3,-$BNSZ($a2)
++	sltu	$t8,$t0,$ta0
++	$SUBU	$ta0,$t0,$ta0
++	$SUBU	$t0,$ta0,$v0
++	sgtu	$v0,$t0,$ta0
++	$ST	$t0,-4*$BNSZ($a0)
++	$ADDU	$v0,$t8
++
++	sltu	$t9,$t1,$ta1
++	$SUBU	$ta1,$t1,$ta1
++	$SUBU	$t1,$ta1,$v0
++	sgtu	$v0,$t1,$ta1
++	$ST	$t1,-3*$BNSZ($a0)
++	$ADDU	$v0,$t9
++
++
++	sltu	$t8,$t2,$ta2
++	$SUBU	$ta2,$t2,$ta2
++	$SUBU	$t2,$ta2,$v0
++	sgtu	$v0,$t2,$ta2
++	$ST	$t2,-2*$BNSZ($a0)
++	$ADDU	$v0,$t8
++
++	sltu	$t9,$t3,$ta3
++	$SUBU	$ta3,$t3,$ta3
++	$SUBU	$t3,$ta3,$v0
++	sgtu	$v0,$t3,$ta3
++	$ST	$t3,-$BNSZ($a0)
++
++	.set	noreorder
++	bgtz	$at,.L_bn_sub_words_loop
++	$ADDU	$v0,$t9
++
++	beqz	$a3,.L_bn_sub_words_return
++	nop
++
++.L_bn_sub_words_tail:
++	.set	reorder
++	$LD	$t0,0($a1)
++	$LD	$ta0,0($a2)
++	subu	$a3,1
++	sltu	$t8,$t0,$ta0
++	$SUBU	$ta0,$t0,$ta0
++	$SUBU	$t0,$ta0,$v0
++	sgtu	$v0,$t0,$ta0
++	$ST	$t0,0($a0)
++	$ADDU	$v0,$t8
++	beqz	$a3,.L_bn_sub_words_return
++
++	$LD	$t1,$BNSZ($a1)
++	subu	$a3,1
++	$LD	$ta1,$BNSZ($a2)
++	sltu	$t9,$t1,$ta1
++	$SUBU	$ta1,$t1,$ta1
++	$SUBU	$t1,$ta1,$v0
++	sgtu	$v0,$t1,$ta1
++	$ST	$t1,$BNSZ($a0)
++	$ADDU	$v0,$t9
++	beqz	$a3,.L_bn_sub_words_return
++
++	$LD	$t2,2*$BNSZ($a1)
++	$LD	$ta2,2*$BNSZ($a2)
++	sltu	$t8,$t2,$ta2
++	$SUBU	$ta2,$t2,$ta2
++	$SUBU	$t2,$ta2,$v0
++	sgtu	$v0,$t2,$ta2
++	$ST	$t2,2*$BNSZ($a0)
++	$ADDU	$v0,$t8
++
++.L_bn_sub_words_return:
++	.set	noreorder
++___
++$code.=<<___ if ($flavour =~ /nubi/i);
++	$REG_L	$t3,4*$SZREG($sp)
++	$REG_L	$t2,3*$SZREG($sp)
++	$REG_L	$t1,2*$SZREG($sp)
++	$REG_L	$t0,1*$SZREG($sp)
++	$REG_L	$gp,0*$SZREG($sp)
++	$PTR_ADD $sp,6*$SZREG
++___
++$code.=<<___;
++	jr	$ra
++	move	$a0,$v0
++.end	bn_sub_words_internal
++
++.align 5
++.globl	bn_div_3_words
++.ent	bn_div_3_words
++bn_div_3_words:
++	.set	noreorder
++	move	$a3,$a0		# we know that bn_div_words does not
++				# touch $a3, $ta2, $ta3 and preserves $a2
++				# so that we can save two arguments
++				# and return address in registers
++				# instead of stack:-)
++				
++	$LD	$a0,($a3)
++	move	$ta2,$a1
++	bne	$a0,$a2,bn_div_3_words_internal
++	$LD	$a1,-$BNSZ($a3)
++	li	$v0,-1
++	jr	$ra
++	move	$a0,$v0
++.end	bn_div_3_words
++
++.align	5
++.ent	bn_div_3_words_internal
++bn_div_3_words_internal:
++___
++$code.=<<___ if ($flavour =~ /nubi/i);
++	.frame	$sp,6*$SZREG,$ra
++	.mask	0x8000f008,-$SZREG
++	.set	noreorder
++	$PTR_SUB $sp,6*$SZREG
++	$REG_S	$ra,5*$SZREG($sp)
++	$REG_S	$t3,4*$SZREG($sp)
++	$REG_S	$t2,3*$SZREG($sp)
++	$REG_S	$t1,2*$SZREG($sp)
++	$REG_S	$t0,1*$SZREG($sp)
++	$REG_S	$gp,0*$SZREG($sp)
++___
++$code.=<<___;
++	.set	reorder
++	move	$ta3,$ra
++	bal	bn_div_words_internal
++	move	$ra,$ta3
++	$MULTU	$ta2,$v0
++	$LD	$t2,-2*$BNSZ($a3)
++	move	$ta0,$zero
++	mfhi	$t1
++	mflo	$t0
++	sltu	$t8,$t1,$a1
++.L_bn_div_3_words_inner_loop:
++	bnez	$t8,.L_bn_div_3_words_inner_loop_done
++	sgeu	$at,$t2,$t0
++	seq	$t9,$t1,$a1
++	and	$at,$t9
++	sltu	$t3,$t0,$ta2
++	$ADDU	$a1,$a2
++	$SUBU	$t1,$t3
++	$SUBU	$t0,$ta2
++	sltu	$t8,$t1,$a1
++	sltu	$ta0,$a1,$a2
++	or	$t8,$ta0
++	.set	noreorder
++	beqz	$at,.L_bn_div_3_words_inner_loop
++	$SUBU	$v0,1
++	$ADDU	$v0,1
++	.set	reorder
++.L_bn_div_3_words_inner_loop_done:
++	.set	noreorder
++___
++$code.=<<___ if ($flavour =~ /nubi/i);
++	$REG_L	$t3,4*$SZREG($sp)
++	$REG_L	$t2,3*$SZREG($sp)
++	$REG_L	$t1,2*$SZREG($sp)
++	$REG_L	$t0,1*$SZREG($sp)
++	$REG_L	$gp,0*$SZREG($sp)
++	$PTR_ADD $sp,6*$SZREG
++___
++$code.=<<___;
++	jr	$ra
++	move	$a0,$v0
++.end	bn_div_3_words_internal
++
++.align	5
++.globl	bn_div_words
++.ent	bn_div_words
++bn_div_words:
++	.set	noreorder
++	bnez	$a2,bn_div_words_internal
++	li	$v0,-1		# I would rather signal div-by-zero
++				# which can be done with 'break 7'
++	jr	$ra
++	move	$a0,$v0
++.end	bn_div_words
++
++.align	5
++.ent	bn_div_words_internal
++bn_div_words_internal:
++___
++$code.=<<___ if ($flavour =~ /nubi/i);
++	.frame	$sp,6*$SZREG,$ra
++	.mask	0x8000f008,-$SZREG
++	.set	noreorder
++	$PTR_SUB $sp,6*$SZREG
++	$REG_S	$ra,5*$SZREG($sp)
++	$REG_S	$t3,4*$SZREG($sp)
++	$REG_S	$t2,3*$SZREG($sp)
++	$REG_S	$t1,2*$SZREG($sp)
++	$REG_S	$t0,1*$SZREG($sp)
++	$REG_S	$gp,0*$SZREG($sp)
++___
++$code.=<<___;
++	move	$v1,$zero
++	bltz	$a2,.L_bn_div_words_body
++	move	$t9,$v1
++	$SLL	$a2,1
++	bgtz	$a2,.-4
++	addu	$t9,1
++
++	.set	reorder
++	negu	$t1,$t9
++	li	$t2,-1
++	$SLL	$t2,$t1
++	and	$t2,$a0
++	$SRL	$at,$a1,$t1
++	.set	noreorder
++	beqz	$t2,.+12
++	nop
++	break	6		# signal overflow
++	.set	reorder
++	$SLL	$a0,$t9
++	$SLL	$a1,$t9
++	or	$a0,$at
++___
++$QT=$ta0;
++$HH=$ta1;
++$DH=$v1;
++$code.=<<___;
++.L_bn_div_words_body:
++	$SRL	$DH,$a2,4*$BNSZ	# bits
++	sgeu	$at,$a0,$a2
++	.set	noreorder
++	beqz	$at,.+12
++	nop
++	$SUBU	$a0,$a2
++	.set	reorder
++
++	li	$QT,-1
++	$SRL	$HH,$a0,4*$BNSZ	# bits
++	$SRL	$QT,4*$BNSZ	# q=0xffffffff
++	beq	$DH,$HH,.L_bn_div_words_skip_div1
++	$DIVU	$zero,$a0,$DH
++	mflo	$QT
++.L_bn_div_words_skip_div1:
++	$MULTU	$a2,$QT
++	$SLL	$t3,$a0,4*$BNSZ	# bits
++	$SRL	$at,$a1,4*$BNSZ	# bits
++	or	$t3,$at
++	mflo	$t0
++	mfhi	$t1
++.L_bn_div_words_inner_loop1:
++	sltu	$t2,$t3,$t0
++	seq	$t8,$HH,$t1
++	sltu	$at,$HH,$t1
++	and	$t2,$t8
++	sltu	$v0,$t0,$a2
++	or	$at,$t2
++	.set	noreorder
++	beqz	$at,.L_bn_div_words_inner_loop1_done
++	$SUBU	$t1,$v0
++	$SUBU	$t0,$a2
++	b	.L_bn_div_words_inner_loop1
++	$SUBU	$QT,1
++	.set	reorder
++.L_bn_div_words_inner_loop1_done:
++
++	$SLL	$a1,4*$BNSZ	# bits
++	$SUBU	$a0,$t3,$t0
++	$SLL	$v0,$QT,4*$BNSZ	# bits
++
++	li	$QT,-1
++	$SRL	$HH,$a0,4*$BNSZ	# bits
++	$SRL	$QT,4*$BNSZ	# q=0xffffffff
++	beq	$DH,$HH,.L_bn_div_words_skip_div2
++	$DIVU	$zero,$a0,$DH
++	mflo	$QT
++.L_bn_div_words_skip_div2:
++	$MULTU	$a2,$QT
++	$SLL	$t3,$a0,4*$BNSZ	# bits
++	$SRL	$at,$a1,4*$BNSZ	# bits
++	or	$t3,$at
++	mflo	$t0
++	mfhi	$t1
++.L_bn_div_words_inner_loop2:
++	sltu	$t2,$t3,$t0
++	seq	$t8,$HH,$t1
++	sltu	$at,$HH,$t1
++	and	$t2,$t8
++	sltu	$v1,$t0,$a2
++	or	$at,$t2
++	.set	noreorder
++	beqz	$at,.L_bn_div_words_inner_loop2_done
++	$SUBU	$t1,$v1
++	$SUBU	$t0,$a2
++	b	.L_bn_div_words_inner_loop2
++	$SUBU	$QT,1
++	.set	reorder
++.L_bn_div_words_inner_loop2_done:
++
++	$SUBU	$a0,$t3,$t0
++	or	$v0,$QT
++	$SRL	$v1,$a0,$t9	# $v1 contains remainder if anybody wants it
++	$SRL	$a2,$t9		# restore $a2
++
++	.set	noreorder
++	move	$a1,$v1
++___
++$code.=<<___ if ($flavour =~ /nubi/i);
++	$REG_L	$t3,4*$SZREG($sp)
++	$REG_L	$t2,3*$SZREG($sp)
++	$REG_L	$t1,2*$SZREG($sp)
++	$REG_L	$t0,1*$SZREG($sp)
++	$REG_L	$gp,0*$SZREG($sp)
++	$PTR_ADD $sp,6*$SZREG
++___
++$code.=<<___;
++	jr	$ra
++	move	$a0,$v0
++.end	bn_div_words_internal
++___
++undef $HH; undef $QT; undef $DH;
++
++($a_0,$a_1,$a_2,$a_3)=($t0,$t1,$t2,$t3);
++($b_0,$b_1,$b_2,$b_3)=($ta0,$ta1,$ta2,$ta3);
++
++($a_4,$a_5,$a_6,$a_7)=($s0,$s2,$s4,$a1); # once we load a[7], no use for $a1
++($b_4,$b_5,$b_6,$b_7)=($s1,$s3,$s5,$a2); # once we load b[7], no use for $a2
++
++($t_1,$t_2,$c_1,$c_2,$c_3)=($t8,$t9,$v0,$v1,$a3);
++
++$code.=<<___;
++
++.align	5
++.globl	bn_mul_comba8
++.ent	bn_mul_comba8
++bn_mul_comba8:
++	.set	noreorder
++___
++$code.=<<___ if ($flavour =~ /nubi/i);
++	.frame	$sp,12*$SZREG,$ra
++	.mask	0x803ff008,-$SZREG
++	$PTR_SUB $sp,12*$SZREG
++	$REG_S	$ra,11*$SZREG($sp)
++	$REG_S	$s5,10*$SZREG($sp)
++	$REG_S	$s4,9*$SZREG($sp)
++	$REG_S	$s3,8*$SZREG($sp)
++	$REG_S	$s2,7*$SZREG($sp)
++	$REG_S	$s1,6*$SZREG($sp)
++	$REG_S	$s0,5*$SZREG($sp)
++	$REG_S	$t3,4*$SZREG($sp)
++	$REG_S	$t2,3*$SZREG($sp)
++	$REG_S	$t1,2*$SZREG($sp)
++	$REG_S	$t0,1*$SZREG($sp)
++	$REG_S	$gp,0*$SZREG($sp)
++___
++$code.=<<___ if ($flavour !~ /nubi/i);
++	.frame	$sp,6*$SZREG,$ra
++	.mask	0x003f0000,-$SZREG
++	$PTR_SUB $sp,6*$SZREG
++	$REG_S	$s5,5*$SZREG($sp)
++	$REG_S	$s4,4*$SZREG($sp)
++	$REG_S	$s3,3*$SZREG($sp)
++	$REG_S	$s2,2*$SZREG($sp)
++	$REG_S	$s1,1*$SZREG($sp)
++	$REG_S	$s0,0*$SZREG($sp)
++___
++$code.=<<___;
++
++	.set	reorder
++	$LD	$a_0,0($a1)	# If compiled with -mips3 option on
++				# R5000 box assembler barks on this
++				# 1ine with "should not have mult/div
++				# as last instruction in bb (R10K
++				# bug)" warning. If anybody out there
++				# has a clue about how to circumvent
++				# this do send me a note.
++				#		
++
++	$LD	$b_0,0($a2)
++	$LD	$a_1,$BNSZ($a1)
++	$LD	$a_2,2*$BNSZ($a1)
++	$MULTU	$a_0,$b_0		# mul_add_c(a[0],b[0],c1,c2,c3);
++	$LD	$a_3,3*$BNSZ($a1)
++	$LD	$b_1,$BNSZ($a2)
++	$LD	$b_2,2*$BNSZ($a2)
++	$LD	$b_3,3*$BNSZ($a2)
++	mflo	$c_1
++	mfhi	$c_2
++
++	$LD	$a_4,4*$BNSZ($a1)
++	$LD	$a_5,5*$BNSZ($a1)
++	$MULTU	$a_0,$b_1		# mul_add_c(a[0],b[1],c2,c3,c1);
++	$LD	$a_6,6*$BNSZ($a1)
++	$LD	$a_7,7*$BNSZ($a1)
++	$LD	$b_4,4*$BNSZ($a2)
++	$LD	$b_5,5*$BNSZ($a2)
++	mflo	$t_1
++	mfhi	$t_2
++	$ADDU	$c_2,$t_1
++	sltu	$at,$c_2,$t_1
++	$MULTU	$a_1,$b_0		# mul_add_c(a[1],b[0],c2,c3,c1);
++	$ADDU	$c_3,$t_2,$at
++	$LD	$b_6,6*$BNSZ($a2)
++	$LD	$b_7,7*$BNSZ($a2)
++	$ST	$c_1,0($a0)	# r[0]=c1;
++	mflo	$t_1
++	mfhi	$t_2
++	$ADDU	$c_2,$t_1
++	sltu	$at,$c_2,$t_1
++	 $MULTU	$a_2,$b_0		# mul_add_c(a[2],b[0],c3,c1,c2);
++	$ADDU	$t_2,$at
++	$ADDU	$c_3,$t_2
++	sltu	$c_1,$c_3,$t_2
++	$ST	$c_2,$BNSZ($a0)	# r[1]=c2;
++
++	mflo	$t_1
++	mfhi	$t_2
++	$ADDU	$c_3,$t_1
++	sltu	$at,$c_3,$t_1
++	$MULTU	$a_1,$b_1		# mul_add_c(a[1],b[1],c3,c1,c2);
++	$ADDU	$t_2,$at
++	$ADDU	$c_1,$t_2
++	mflo	$t_1
++	mfhi	$t_2
++	$ADDU	$c_3,$t_1
++	sltu	$at,$c_3,$t_1
++	$MULTU	$a_0,$b_2		# mul_add_c(a[0],b[2],c3,c1,c2);
++	$ADDU	$t_2,$at
++	$ADDU	$c_1,$t_2
++	sltu	$c_2,$c_1,$t_2
++	mflo	$t_1
++	mfhi	$t_2
++	$ADDU	$c_3,$t_1
++	sltu	$at,$c_3,$t_1
++	 $MULTU	$a_0,$b_3		# mul_add_c(a[0],b[3],c1,c2,c3);
++	$ADDU	$t_2,$at
++	$ADDU	$c_1,$t_2
++	sltu	$at,$c_1,$t_2
++	$ADDU	$c_2,$at
++	$ST	$c_3,2*$BNSZ($a0)	# r[2]=c3;
++
++	mflo	$t_1
++	mfhi	$t_2
++	$ADDU	$c_1,$t_1
++	sltu	$at,$c_1,$t_1
++	$MULTU	$a_1,$b_2		# mul_add_c(a[1],b[2],c1,c2,c3);
++	$ADDU	$t_2,$at
++	$ADDU	$c_2,$t_2
++	sltu	$c_3,$c_2,$t_2
++	mflo	$t_1
++	mfhi	$t_2
++	$ADDU	$c_1,$t_1
++	sltu	$at,$c_1,$t_1
++	$MULTU	$a_2,$b_1		# mul_add_c(a[2],b[1],c1,c2,c3);
++	$ADDU	$t_2,$at
++	$ADDU	$c_2,$t_2
++	sltu	$at,$c_2,$t_2
++	$ADDU	$c_3,$at
++	mflo	$t_1
++	mfhi	$t_2
++	$ADDU	$c_1,$t_1
++	sltu	$at,$c_1,$t_1
++	$MULTU	$a_3,$b_0		# mul_add_c(a[3],b[0],c1,c2,c3);
++	$ADDU	$t_2,$at
++	$ADDU	$c_2,$t_2
++	sltu	$at,$c_2,$t_2
++	$ADDU	$c_3,$at
++	mflo	$t_1
++	mfhi	$t_2
++	$ADDU	$c_1,$t_1
++	sltu	$at,$c_1,$t_1
++	 $MULTU	$a_4,$b_0		# mul_add_c(a[4],b[0],c2,c3,c1);
++	$ADDU	$t_2,$at
++	$ADDU	$c_2,$t_2
++	sltu	$at,$c_2,$t_2
++	$ADDU	$c_3,$at
++	$ST	$c_1,3*$BNSZ($a0)	# r[3]=c1;
++
++	mflo	$t_1
++	mfhi	$t_2
++	$ADDU	$c_2,$t_1
++	sltu	$at,$c_2,$t_1
++	$MULTU	$a_3,$b_1		# mul_add_c(a[3],b[1],c2,c3,c1);
++	$ADDU	$t_2,$at
++	$ADDU	$c_3,$t_2
++	sltu	$c_1,$c_3,$t_2
++	mflo	$t_1
++	mfhi	$t_2
++	$ADDU	$c_2,$t_1
++	sltu	$at,$c_2,$t_1
++	$MULTU	$a_2,$b_2		# mul_add_c(a[2],b[2],c2,c3,c1);
++	$ADDU	$t_2,$at
++	$ADDU	$c_3,$t_2
++	sltu	$at,$c_3,$t_2
++	$ADDU	$c_1,$at
++	mflo	$t_1
++	mfhi	$t_2
++	$ADDU	$c_2,$t_1
++	sltu	$at,$c_2,$t_1
++	$MULTU	$a_1,$b_3		# mul_add_c(a[1],b[3],c2,c3,c1);
++	$ADDU	$t_2,$at
++	$ADDU	$c_3,$t_2
++	sltu	$at,$c_3,$t_2
++	$ADDU	$c_1,$at
++	mflo	$t_1
++	mfhi	$t_2
++	$ADDU	$c_2,$t_1
++	sltu	$at,$c_2,$t_1
++	$MULTU	$a_0,$b_4		# mul_add_c(a[0],b[4],c2,c3,c1);
++	$ADDU	$t_2,$at
++	$ADDU	$c_3,$t_2
++	sltu	$at,$c_3,$t_2
++	$ADDU	$c_1,$at
++	mflo	$t_1
++	mfhi	$t_2
++	$ADDU	$c_2,$t_1
++	sltu	$at,$c_2,$t_1
++	 $MULTU	$a_0,$b_5		# mul_add_c(a[0],b[5],c3,c1,c2);
++	$ADDU	$t_2,$at
++	$ADDU	$c_3,$t_2
++	sltu	$at,$c_3,$t_2
++	$ADDU	$c_1,$at
++	$ST	$c_2,4*$BNSZ($a0)	# r[4]=c2;
++
++	mflo	$t_1
++	mfhi	$t_2
++	$ADDU	$c_3,$t_1
++	sltu	$at,$c_3,$t_1
++	$MULTU	$a_1,$b_4		# mul_add_c(a[1],b[4],c3,c1,c2);
++	$ADDU	$t_2,$at
++	$ADDU	$c_1,$t_2
++	sltu	$c_2,$c_1,$t_2
++	mflo	$t_1
++	mfhi	$t_2
++	$ADDU	$c_3,$t_1
++	sltu	$at,$c_3,$t_1
++	$MULTU	$a_2,$b_3		# mul_add_c(a[2],b[3],c3,c1,c2);
++	$ADDU	$t_2,$at
++	$ADDU	$c_1,$t_2
++	sltu	$at,$c_1,$t_2
++	$ADDU	$c_2,$at
++	mflo	$t_1
++	mfhi	$t_2
++	$ADDU	$c_3,$t_1
++	sltu	$at,$c_3,$t_1
++	$MULTU	$a_3,$b_2		# mul_add_c(a[3],b[2],c3,c1,c2);
++	$ADDU	$t_2,$at
++	$ADDU	$c_1,$t_2
++	sltu	$at,$c_1,$t_2
++	$ADDU	$c_2,$at
++	mflo	$t_1
++	mfhi	$t_2
++	$ADDU	$c_3,$t_1
++	sltu	$at,$c_3,$t_1
++	$MULTU	$a_4,$b_1		# mul_add_c(a[4],b[1],c3,c1,c2);
++	$ADDU	$t_2,$at
++	$ADDU	$c_1,$t_2
++	sltu	$at,$c_1,$t_2
++	$ADDU	$c_2,$at
++	mflo	$t_1
++	mfhi	$t_2
++	$ADDU	$c_3,$t_1
++	sltu	$at,$c_3,$t_1
++	$MULTU	$a_5,$b_0		# mul_add_c(a[5],b[0],c3,c1,c2);
++	$ADDU	$t_2,$at
++	$ADDU	$c_1,$t_2
++	sltu	$at,$c_1,$t_2
++	$ADDU	$c_2,$at
++	mflo	$t_1
++	mfhi	$t_2
++	$ADDU	$c_3,$t_1
++	sltu	$at,$c_3,$t_1
++	 $MULTU	$a_6,$b_0		# mul_add_c(a[6],b[0],c1,c2,c3);
++	$ADDU	$t_2,$at
++	$ADDU	$c_1,$t_2
++	sltu	$at,$c_1,$t_2
++	$ADDU	$c_2,$at
++	$ST	$c_3,5*$BNSZ($a0)	# r[5]=c3;
++
++	mflo	$t_1
++	mfhi	$t_2
++	$ADDU	$c_1,$t_1
++	sltu	$at,$c_1,$t_1
++	$MULTU	$a_5,$b_1		# mul_add_c(a[5],b[1],c1,c2,c3);
++	$ADDU	$t_2,$at
++	$ADDU	$c_2,$t_2
++	sltu	$c_3,$c_2,$t_2
++	mflo	$t_1
++	mfhi	$t_2
++	$ADDU	$c_1,$t_1
++	sltu	$at,$c_1,$t_1
++	$MULTU	$a_4,$b_2		# mul_add_c(a[4],b[2],c1,c2,c3);
++	$ADDU	$t_2,$at
++	$ADDU	$c_2,$t_2
++	sltu	$at,$c_2,$t_2
++	$ADDU	$c_3,$at
++	mflo	$t_1
++	mfhi	$t_2
++	$ADDU	$c_1,$t_1
++	sltu	$at,$c_1,$t_1
++	$MULTU	$a_3,$b_3		# mul_add_c(a[3],b[3],c1,c2,c3);
++	$ADDU	$t_2,$at
++	$ADDU	$c_2,$t_2
++	sltu	$at,$c_2,$t_2
++	$ADDU	$c_3,$at
++	mflo	$t_1
++	mfhi	$t_2
++	$ADDU	$c_1,$t_1
++	sltu	$at,$c_1,$t_1
++	$MULTU	$a_2,$b_4		# mul_add_c(a[2],b[4],c1,c2,c3);
++	$ADDU	$t_2,$at
++	$ADDU	$c_2,$t_2
++	sltu	$at,$c_2,$t_2
++	$ADDU	$c_3,$at
++	mflo	$t_1
++	mfhi	$t_2
++	$ADDU	$c_1,$t_1
++	sltu	$at,$c_1,$t_1
++	$MULTU	$a_1,$b_5		# mul_add_c(a[1],b[5],c1,c2,c3);
++	$ADDU	$t_2,$at
++	$ADDU	$c_2,$t_2
++	sltu	$at,$c_2,$t_2
++	$ADDU	$c_3,$at
++	mflo	$t_1
++	mfhi	$t_2
++	$ADDU	$c_1,$t_1
++	sltu	$at,$c_1,$t_1
++	$MULTU	$a_0,$b_6		# mul_add_c(a[0],b[6],c1,c2,c3);
++	$ADDU	$t_2,$at
++	$ADDU	$c_2,$t_2
++	sltu	$at,$c_2,$t_2
++	$ADDU	$c_3,$at
++	mflo	$t_1
++	mfhi	$t_2
++	$ADDU	$c_1,$t_1
++	sltu	$at,$c_1,$t_1
++	 $MULTU	$a_0,$b_7		# mul_add_c(a[0],b[7],c2,c3,c1);
++	$ADDU	$t_2,$at
++	$ADDU	$c_2,$t_2
++	sltu	$at,$c_2,$t_2
++	$ADDU	$c_3,$at
++	$ST	$c_1,6*$BNSZ($a0)	# r[6]=c1;
++
++	mflo	$t_1
++	mfhi	$t_2
++	$ADDU	$c_2,$t_1
++	sltu	$at,$c_2,$t_1
++	$MULTU	$a_1,$b_6		# mul_add_c(a[1],b[6],c2,c3,c1);
++	$ADDU	$t_2,$at
++	$ADDU	$c_3,$t_2
++	sltu	$c_1,$c_3,$t_2
++	mflo	$t_1
++	mfhi	$t_2
++	$ADDU	$c_2,$t_1
++	sltu	$at,$c_2,$t_1
++	$MULTU	$a_2,$b_5		# mul_add_c(a[2],b[5],c2,c3,c1);
++	$ADDU	$t_2,$at
++	$ADDU	$c_3,$t_2
++	sltu	$at,$c_3,$t_2
++	$ADDU	$c_1,$at
++	mflo	$t_1
++	mfhi	$t_2
++	$ADDU	$c_2,$t_1
++	sltu	$at,$c_2,$t_1
++	$MULTU	$a_3,$b_4		# mul_add_c(a[3],b[4],c2,c3,c1);
++	$ADDU	$t_2,$at
++	$ADDU	$c_3,$t_2
++	sltu	$at,$c_3,$t_2
++	$ADDU	$c_1,$at
++	mflo	$t_1
++	mfhi	$t_2
++	$ADDU	$c_2,$t_1
++	sltu	$at,$c_2,$t_1
++	$MULTU	$a_4,$b_3		# mul_add_c(a[4],b[3],c2,c3,c1);
++	$ADDU	$t_2,$at
++	$ADDU	$c_3,$t_2
++	sltu	$at,$c_3,$t_2
++	$ADDU	$c_1,$at
++	mflo	$t_1
++	mfhi	$t_2
++	$ADDU	$c_2,$t_1
++	sltu	$at,$c_2,$t_1
++	$MULTU	$a_5,$b_2		# mul_add_c(a[5],b[2],c2,c3,c1);
++	$ADDU	$t_2,$at
++	$ADDU	$c_3,$t_2
++	sltu	$at,$c_3,$t_2
++	$ADDU	$c_1,$at
++	mflo	$t_1
++	mfhi	$t_2
++	$ADDU	$c_2,$t_1
++	sltu	$at,$c_2,$t_1
++	$MULTU	$a_6,$b_1		# mul_add_c(a[6],b[1],c2,c3,c1);
++	$ADDU	$t_2,$at
++	$ADDU	$c_3,$t_2
++	sltu	$at,$c_3,$t_2
++	$ADDU	$c_1,$at
++	mflo	$t_1
++	mfhi	$t_2
++	$ADDU	$c_2,$t_1
++	sltu	$at,$c_2,$t_1
++	$MULTU	$a_7,$b_0		# mul_add_c(a[7],b[0],c2,c3,c1);
++	$ADDU	$t_2,$at
++	$ADDU	$c_3,$t_2
++	sltu	$at,$c_3,$t_2
++	$ADDU	$c_1,$at
++	mflo	$t_1
++	mfhi	$t_2
++	$ADDU	$c_2,$t_1
++	sltu	$at,$c_2,$t_1
++	 $MULTU	$a_7,$b_1		# mul_add_c(a[7],b[1],c3,c1,c2);
++	$ADDU	$t_2,$at
++	$ADDU	$c_3,$t_2
++	sltu	$at,$c_3,$t_2
++	$ADDU	$c_1,$at
++	$ST	$c_2,7*$BNSZ($a0)	# r[7]=c2;
++
++	mflo	$t_1
++	mfhi	$t_2
++	$ADDU	$c_3,$t_1
++	sltu	$at,$c_3,$t_1
++	$MULTU	$a_6,$b_2		# mul_add_c(a[6],b[2],c3,c1,c2);
++	$ADDU	$t_2,$at
++	$ADDU	$c_1,$t_2
++	sltu	$c_2,$c_1,$t_2
++	mflo	$t_1
++	mfhi	$t_2
++	$ADDU	$c_3,$t_1
++	sltu	$at,$c_3,$t_1
++	$MULTU	$a_5,$b_3		# mul_add_c(a[5],b[3],c3,c1,c2);
++	$ADDU	$t_2,$at
++	$ADDU	$c_1,$t_2
++	sltu	$at,$c_1,$t_2
++	$ADDU	$c_2,$at
++	mflo	$t_1
++	mfhi	$t_2
++	$ADDU	$c_3,$t_1
++	sltu	$at,$c_3,$t_1
++	$MULTU	$a_4,$b_4		# mul_add_c(a[4],b[4],c3,c1,c2);
++	$ADDU	$t_2,$at
++	$ADDU	$c_1,$t_2
++	sltu	$at,$c_1,$t_2
++	$ADDU	$c_2,$at
++	mflo	$t_1
++	mfhi	$t_2
++	$ADDU	$c_3,$t_1
++	sltu	$at,$c_3,$t_1
++	$MULTU	$a_3,$b_5		# mul_add_c(a[3],b[5],c3,c1,c2);
++	$ADDU	$t_2,$at
++	$ADDU	$c_1,$t_2
++	sltu	$at,$c_1,$t_2
++	$ADDU	$c_2,$at
++	mflo	$t_1
++	mfhi	$t_2
++	$ADDU	$c_3,$t_1
++	sltu	$at,$c_3,$t_1
++	$MULTU	$a_2,$b_6		# mul_add_c(a[2],b[6],c3,c1,c2);
++	$ADDU	$t_2,$at
++	$ADDU	$c_1,$t_2
++	sltu	$at,$c_1,$t_2
++	$ADDU	$c_2,$at
++	mflo	$t_1
++	mfhi	$t_2
++	$ADDU	$c_3,$t_1
++	sltu	$at,$c_3,$t_1
++	$MULTU	$a_1,$b_7		# mul_add_c(a[1],b[7],c3,c1,c2);
++	$ADDU	$t_2,$at
++	$ADDU	$c_1,$t_2
++	sltu	$at,$c_1,$t_2
++	$ADDU	$c_2,$at
++	mflo	$t_1
++	mfhi	$t_2
++	$ADDU	$c_3,$t_1
++	sltu	$at,$c_3,$t_1
++	 $MULTU	$a_2,$b_7		# mul_add_c(a[2],b[7],c1,c2,c3);
++	$ADDU	$t_2,$at
++	$ADDU	$c_1,$t_2
++	sltu	$at,$c_1,$t_2
++	$ADDU	$c_2,$at
++	$ST	$c_3,8*$BNSZ($a0)	# r[8]=c3;
++
++	mflo	$t_1
++	mfhi	$t_2
++	$ADDU	$c_1,$t_1
++	sltu	$at,$c_1,$t_1
++	$MULTU	$a_3,$b_6		# mul_add_c(a[3],b[6],c1,c2,c3);
++	$ADDU	$t_2,$at
++	$ADDU	$c_2,$t_2
++	sltu	$c_3,$c_2,$t_2
++	mflo	$t_1
++	mfhi	$t_2
++	$ADDU	$c_1,$t_1
++	sltu	$at,$c_1,$t_1
++	$MULTU	$a_4,$b_5		# mul_add_c(a[4],b[5],c1,c2,c3);
++	$ADDU	$t_2,$at
++	$ADDU	$c_2,$t_2
++	sltu	$at,$c_2,$t_2
++	$ADDU	$c_3,$at
++	mflo	$t_1
++	mfhi	$t_2
++	$ADDU	$c_1,$t_1
++	sltu	$at,$c_1,$t_1
++	$MULTU	$a_5,$b_4		# mul_add_c(a[5],b[4],c1,c2,c3);
++	$ADDU	$t_2,$at
++	$ADDU	$c_2,$t_2
++	sltu	$at,$c_2,$t_2
++	$ADDU	$c_3,$at
++	mflo	$t_1
++	mfhi	$t_2
++	$ADDU	$c_1,$t_1
++	sltu	$at,$c_1,$t_1
++	$MULTU	$a_6,$b_3		# mul_add_c(a[6],b[3],c1,c2,c3);
++	$ADDU	$t_2,$at
++	$ADDU	$c_2,$t_2
++	sltu	$at,$c_2,$t_2
++	$ADDU	$c_3,$at
++	mflo	$t_1
++	mfhi	$t_2
++	$ADDU	$c_1,$t_1
++	sltu	$at,$c_1,$t_1
++	$MULTU	$a_7,$b_2		# mul_add_c(a[7],b[2],c1,c2,c3);
++	$ADDU	$t_2,$at
++	$ADDU	$c_2,$t_2
++	sltu	$at,$c_2,$t_2
++	$ADDU	$c_3,$at
++	mflo	$t_1
++	mfhi	$t_2
++	$ADDU	$c_1,$t_1
++	sltu	$at,$c_1,$t_1
++	 $MULTU	$a_7,$b_3		# mul_add_c(a[7],b[3],c2,c3,c1);
++	$ADDU	$t_2,$at
++	$ADDU	$c_2,$t_2
++	sltu	$at,$c_2,$t_2
++	$ADDU	$c_3,$at
++	$ST	$c_1,9*$BNSZ($a0)	# r[9]=c1;
++
++	mflo	$t_1
++	mfhi	$t_2
++	$ADDU	$c_2,$t_1
++	sltu	$at,$c_2,$t_1
++	$MULTU	$a_6,$b_4		# mul_add_c(a[6],b[4],c2,c3,c1);
++	$ADDU	$t_2,$at
++	$ADDU	$c_3,$t_2
++	sltu	$c_1,$c_3,$t_2
++	mflo	$t_1
++	mfhi	$t_2
++	$ADDU	$c_2,$t_1
++	sltu	$at,$c_2,$t_1
++	$MULTU	$a_5,$b_5		# mul_add_c(a[5],b[5],c2,c3,c1);
++	$ADDU	$t_2,$at
++	$ADDU	$c_3,$t_2
++	sltu	$at,$c_3,$t_2
++	$ADDU	$c_1,$at
++	mflo	$t_1
++	mfhi	$t_2
++	$ADDU	$c_2,$t_1
++	sltu	$at,$c_2,$t_1
++	$MULTU	$a_4,$b_6		# mul_add_c(a[4],b[6],c2,c3,c1);
++	$ADDU	$t_2,$at
++	$ADDU	$c_3,$t_2
++	sltu	$at,$c_3,$t_2
++	$ADDU	$c_1,$at
++	mflo	$t_1
++	mfhi	$t_2
++	$ADDU	$c_2,$t_1
++	sltu	$at,$c_2,$t_1
++	$MULTU	$a_3,$b_7		# mul_add_c(a[3],b[7],c2,c3,c1);
++	$ADDU	$t_2,$at
++	$ADDU	$c_3,$t_2
++	sltu	$at,$c_3,$t_2
++	$ADDU	$c_1,$at
++	mflo	$t_1
++	mfhi	$t_2
++	$ADDU	$c_2,$t_1
++	sltu	$at,$c_2,$t_1
++	$MULTU	$a_4,$b_7		# mul_add_c(a[4],b[7],c3,c1,c2);
++	$ADDU	$t_2,$at
++	$ADDU	$c_3,$t_2
++	sltu	$at,$c_3,$t_2
++	$ADDU	$c_1,$at
++	$ST	$c_2,10*$BNSZ($a0)	# r[10]=c2;
++
++	mflo	$t_1
++	mfhi	$t_2
++	$ADDU	$c_3,$t_1
++	sltu	$at,$c_3,$t_1
++	$MULTU	$a_5,$b_6		# mul_add_c(a[5],b[6],c3,c1,c2);
++	$ADDU	$t_2,$at
++	$ADDU	$c_1,$t_2
++	sltu	$c_2,$c_1,$t_2
++	mflo	$t_1
++	mfhi	$t_2
++	$ADDU	$c_3,$t_1
++	sltu	$at,$c_3,$t_1
++	$MULTU	$a_6,$b_5		# mul_add_c(a[6],b[5],c3,c1,c2);
++	$ADDU	$t_2,$at
++	$ADDU	$c_1,$t_2
++	sltu	$at,$c_1,$t_2
++	$ADDU	$c_2,$at
++	mflo	$t_1
++	mfhi	$t_2
++	$ADDU	$c_3,$t_1
++	sltu	$at,$c_3,$t_1
++	$MULTU	$a_7,$b_4		# mul_add_c(a[7],b[4],c3,c1,c2);
++	$ADDU	$t_2,$at
++	$ADDU	$c_1,$t_2
++	sltu	$at,$c_1,$t_2
++	$ADDU	$c_2,$at
++	mflo	$t_1
++	mfhi	$t_2
++	$ADDU	$c_3,$t_1
++	sltu	$at,$c_3,$t_1
++	 $MULTU	$a_7,$b_5		# mul_add_c(a[7],b[5],c1,c2,c3);
++	$ADDU	$t_2,$at
++	$ADDU	$c_1,$t_2
++	sltu	$at,$c_1,$t_2
++	$ADDU	$c_2,$at
++	$ST	$c_3,11*$BNSZ($a0)	# r[11]=c3;
++
++	mflo	$t_1
++	mfhi	$t_2
++	$ADDU	$c_1,$t_1
++	sltu	$at,$c_1,$t_1
++	$MULTU	$a_6,$b_6		# mul_add_c(a[6],b[6],c1,c2,c3);
++	$ADDU	$t_2,$at
++	$ADDU	$c_2,$t_2
++	sltu	$c_3,$c_2,$t_2
++	mflo	$t_1
++	mfhi	$t_2
++	$ADDU	$c_1,$t_1
++	sltu	$at,$c_1,$t_1
++	$MULTU	$a_5,$b_7		# mul_add_c(a[5],b[7],c1,c2,c3);
++	$ADDU	$t_2,$at
++	$ADDU	$c_2,$t_2
++	sltu	$at,$c_2,$t_2
++	$ADDU	$c_3,$at
++	mflo	$t_1
++	mfhi	$t_2
++	$ADDU	$c_1,$t_1
++	sltu	$at,$c_1,$t_1
++	 $MULTU	$a_6,$b_7		# mul_add_c(a[6],b[7],c2,c3,c1);
++	$ADDU	$t_2,$at
++	$ADDU	$c_2,$t_2
++	sltu	$at,$c_2,$t_2
++	$ADDU	$c_3,$at
++	$ST	$c_1,12*$BNSZ($a0)	# r[12]=c1;
++
++	mflo	$t_1
++	mfhi	$t_2
++	$ADDU	$c_2,$t_1
++	sltu	$at,$c_2,$t_1
++	$MULTU	$a_7,$b_6		# mul_add_c(a[7],b[6],c2,c3,c1);
++	$ADDU	$t_2,$at
++	$ADDU	$c_3,$t_2
++	sltu	$c_1,$c_3,$t_2
++	mflo	$t_1
++	mfhi	$t_2
++	$ADDU	$c_2,$t_1
++	sltu	$at,$c_2,$t_1
++	$MULTU	$a_7,$b_7		# mul_add_c(a[7],b[7],c3,c1,c2);
++	$ADDU	$t_2,$at
++	$ADDU	$c_3,$t_2
++	sltu	$at,$c_3,$t_2
++	$ADDU	$c_1,$at
++	$ST	$c_2,13*$BNSZ($a0)	# r[13]=c2;
++
++	mflo	$t_1
++	mfhi	$t_2
++	$ADDU	$c_3,$t_1
++	sltu	$at,$c_3,$t_1
++	$ADDU	$t_2,$at
++	$ADDU	$c_1,$t_2
++	$ST	$c_3,14*$BNSZ($a0)	# r[14]=c3;
++	$ST	$c_1,15*$BNSZ($a0)	# r[15]=c1;
++
++	.set	noreorder
++___
++$code.=<<___ if ($flavour =~ /nubi/i);
++	$REG_L	$s5,10*$SZREG($sp)
++	$REG_L	$s4,9*$SZREG($sp)
++	$REG_L	$s3,8*$SZREG($sp)
++	$REG_L	$s2,7*$SZREG($sp)
++	$REG_L	$s1,6*$SZREG($sp)
++	$REG_L	$s0,5*$SZREG($sp)
++	$REG_L	$t3,4*$SZREG($sp)
++	$REG_L	$t2,3*$SZREG($sp)
++	$REG_L	$t1,2*$SZREG($sp)
++	$REG_L	$t0,1*$SZREG($sp)
++	$REG_L	$gp,0*$SZREG($sp)
++	jr	$ra
++	$PTR_ADD $sp,12*$SZREG
++___
++$code.=<<___ if ($flavour !~ /nubi/i);
++	$REG_L	$s5,5*$SZREG($sp)
++	$REG_L	$s4,4*$SZREG($sp)
++	$REG_L	$s3,3*$SZREG($sp)
++	$REG_L	$s2,2*$SZREG($sp)
++	$REG_L	$s1,1*$SZREG($sp)
++	$REG_L	$s0,0*$SZREG($sp)
++	jr	$ra
++	$PTR_ADD $sp,6*$SZREG
++___
++$code.=<<___;
++.end	bn_mul_comba8
++
++.align	5
++.globl	bn_mul_comba4
++.ent	bn_mul_comba4
++bn_mul_comba4:
++___
++$code.=<<___ if ($flavour =~ /nubi/i);
++	.frame	$sp,6*$SZREG,$ra
++	.mask	0x8000f008,-$SZREG
++	.set	noreorder
++	$PTR_SUB $sp,6*$SZREG
++	$REG_S	$ra,5*$SZREG($sp)
++	$REG_S	$t3,4*$SZREG($sp)
++	$REG_S	$t2,3*$SZREG($sp)
++	$REG_S	$t1,2*$SZREG($sp)
++	$REG_S	$t0,1*$SZREG($sp)
++	$REG_S	$gp,0*$SZREG($sp)
++___
++$code.=<<___;
++	.set	reorder
++	$LD	$a_0,0($a1)
++	$LD	$b_0,0($a2)
++	$LD	$a_1,$BNSZ($a1)
++	$LD	$a_2,2*$BNSZ($a1)
++	$MULTU	$a_0,$b_0		# mul_add_c(a[0],b[0],c1,c2,c3);
++	$LD	$a_3,3*$BNSZ($a1)
++	$LD	$b_1,$BNSZ($a2)
++	$LD	$b_2,2*$BNSZ($a2)
++	$LD	$b_3,3*$BNSZ($a2)
++	mflo	$c_1
++	mfhi	$c_2
++	$ST	$c_1,0($a0)
++
++	$MULTU	$a_0,$b_1		# mul_add_c(a[0],b[1],c2,c3,c1);
++	mflo	$t_1
++	mfhi	$t_2
++	$ADDU	$c_2,$t_1
++	sltu	$at,$c_2,$t_1
++	$MULTU	$a_1,$b_0		# mul_add_c(a[1],b[0],c2,c3,c1);
++	$ADDU	$c_3,$t_2,$at
++	mflo	$t_1
++	mfhi	$t_2
++	$ADDU	$c_2,$t_1
++	sltu	$at,$c_2,$t_1
++	 $MULTU	$a_2,$b_0		# mul_add_c(a[2],b[0],c3,c1,c2);
++	$ADDU	$t_2,$at
++	$ADDU	$c_3,$t_2
++	sltu	$c_1,$c_3,$t_2
++	$ST	$c_2,$BNSZ($a0)
++
++	mflo	$t_1
++	mfhi	$t_2
++	$ADDU	$c_3,$t_1
++	sltu	$at,$c_3,$t_1
++	$MULTU	$a_1,$b_1		# mul_add_c(a[1],b[1],c3,c1,c2);
++	$ADDU	$t_2,$at
++	$ADDU	$c_1,$t_2
++	mflo	$t_1
++	mfhi	$t_2
++	$ADDU	$c_3,$t_1
++	sltu	$at,$c_3,$t_1
++	$MULTU	$a_0,$b_2		# mul_add_c(a[0],b[2],c3,c1,c2);
++	$ADDU	$t_2,$at
++	$ADDU	$c_1,$t_2
++	sltu	$c_2,$c_1,$t_2
++	mflo	$t_1
++	mfhi	$t_2
++	$ADDU	$c_3,$t_1
++	sltu	$at,$c_3,$t_1
++	 $MULTU	$a_0,$b_3		# mul_add_c(a[0],b[3],c1,c2,c3);
++	$ADDU	$t_2,$at
++	$ADDU	$c_1,$t_2
++	sltu	$at,$c_1,$t_2
++	$ADDU	$c_2,$at
++	$ST	$c_3,2*$BNSZ($a0)
++
++	mflo	$t_1
++	mfhi	$t_2
++	$ADDU	$c_1,$t_1
++	sltu	$at,$c_1,$t_1
++	$MULTU	$a_1,$b_2		# mul_add_c(a[1],b[2],c1,c2,c3);
++	$ADDU	$t_2,$at
++	$ADDU	$c_2,$t_2
++	sltu	$c_3,$c_2,$t_2
++	mflo	$t_1
++	mfhi	$t_2
++	$ADDU	$c_1,$t_1
++	sltu	$at,$c_1,$t_1
++	$MULTU	$a_2,$b_1		# mul_add_c(a[2],b[1],c1,c2,c3);
++	$ADDU	$t_2,$at
++	$ADDU	$c_2,$t_2
++	sltu	$at,$c_2,$t_2
++	$ADDU	$c_3,$at
++	mflo	$t_1
++	mfhi	$t_2
++	$ADDU	$c_1,$t_1
++	sltu	$at,$c_1,$t_1
++	$MULTU	$a_3,$b_0		# mul_add_c(a[3],b[0],c1,c2,c3);
++	$ADDU	$t_2,$at
++	$ADDU	$c_2,$t_2
++	sltu	$at,$c_2,$t_2
++	$ADDU	$c_3,$at
++	mflo	$t_1
++	mfhi	$t_2
++	$ADDU	$c_1,$t_1
++	sltu	$at,$c_1,$t_1
++	 $MULTU	$a_3,$b_1		# mul_add_c(a[3],b[1],c2,c3,c1);
++	$ADDU	$t_2,$at
++	$ADDU	$c_2,$t_2
++	sltu	$at,$c_2,$t_2
++	$ADDU	$c_3,$at
++	$ST	$c_1,3*$BNSZ($a0)
++
++	mflo	$t_1
++	mfhi	$t_2
++	$ADDU	$c_2,$t_1
++	sltu	$at,$c_2,$t_1
++	$MULTU	$a_2,$b_2		# mul_add_c(a[2],b[2],c2,c3,c1);
++	$ADDU	$t_2,$at
++	$ADDU	$c_3,$t_2
++	sltu	$c_1,$c_3,$t_2
++	mflo	$t_1
++	mfhi	$t_2
++	$ADDU	$c_2,$t_1
++	sltu	$at,$c_2,$t_1
++	$MULTU	$a_1,$b_3		# mul_add_c(a[1],b[3],c2,c3,c1);
++	$ADDU	$t_2,$at
++	$ADDU	$c_3,$t_2
++	sltu	$at,$c_3,$t_2
++	$ADDU	$c_1,$at
++	mflo	$t_1
++	mfhi	$t_2
++	$ADDU	$c_2,$t_1
++	sltu	$at,$c_2,$t_1
++	 $MULTU	$a_2,$b_3		# mul_add_c(a[2],b[3],c3,c1,c2);
++	$ADDU	$t_2,$at
++	$ADDU	$c_3,$t_2
++	sltu	$at,$c_3,$t_2
++	$ADDU	$c_1,$at
++	$ST	$c_2,4*$BNSZ($a0)
++
++	mflo	$t_1
++	mfhi	$t_2
++	$ADDU	$c_3,$t_1
++	sltu	$at,$c_3,$t_1
++	$MULTU	$a_3,$b_2		# mul_add_c(a[3],b[2],c3,c1,c2);
++	$ADDU	$t_2,$at
++	$ADDU	$c_1,$t_2
++	sltu	$c_2,$c_1,$t_2
++	mflo	$t_1
++	mfhi	$t_2
++	$ADDU	$c_3,$t_1
++	sltu	$at,$c_3,$t_1
++	 $MULTU	$a_3,$b_3		# mul_add_c(a[3],b[3],c1,c2,c3);
++	$ADDU	$t_2,$at
++	$ADDU	$c_1,$t_2
++	sltu	$at,$c_1,$t_2
++	$ADDU	$c_2,$at
++	$ST	$c_3,5*$BNSZ($a0)
++
++	mflo	$t_1
++	mfhi	$t_2
++	$ADDU	$c_1,$t_1
++	sltu	$at,$c_1,$t_1
++	$ADDU	$t_2,$at
++	$ADDU	$c_2,$t_2
++	$ST	$c_1,6*$BNSZ($a0)
++	$ST	$c_2,7*$BNSZ($a0)
++
++	.set	noreorder
++___
++$code.=<<___ if ($flavour =~ /nubi/i);
++	$REG_L	$t3,4*$SZREG($sp)
++	$REG_L	$t2,3*$SZREG($sp)
++	$REG_L	$t1,2*$SZREG($sp)
++	$REG_L	$t0,1*$SZREG($sp)
++	$REG_L	$gp,0*$SZREG($sp)
++	$PTR_ADD $sp,6*$SZREG
++___
++$code.=<<___;
++	jr	$ra
++	nop
++.end	bn_mul_comba4
++___
++
++($a_4,$a_5,$a_6,$a_7)=($b_0,$b_1,$b_2,$b_3);
++
++sub add_c2 () {
++my ($hi,$lo,$c0,$c1,$c2,
++    $warm,      # !$warm denotes first call with specific sequence of
++                # $c_[XYZ] when there is no Z-carry to accumulate yet;
++    $an,$bn     # these two are arguments for multiplication which
++                # result is used in *next* step [which is why it's
++                # commented as "forward multiplication" below];
++    )=@_;
++$code.=<<___;
++	mflo	$lo
++	mfhi	$hi
++	$ADDU	$c0,$lo
++	sltu	$at,$c0,$lo
++	 $MULTU	$an,$bn			# forward multiplication
++	$ADDU	$c0,$lo
++	$ADDU	$at,$hi
++	sltu	$lo,$c0,$lo
++	$ADDU	$c1,$at
++	$ADDU	$hi,$lo
++___
++$code.=<<___	if (!$warm);
++	sltu	$c2,$c1,$at
++	$ADDU	$c1,$hi
++	sltu	$hi,$c1,$hi
++	$ADDU	$c2,$hi
++___
++$code.=<<___	if ($warm);
++	sltu	$at,$c1,$at
++	$ADDU	$c1,$hi
++	$ADDU	$c2,$at
++	sltu	$hi,$c1,$hi
++	$ADDU	$c2,$hi
++___
++}
++
++$code.=<<___;
++
++.align	5
++.globl	bn_sqr_comba8
++.ent	bn_sqr_comba8
++bn_sqr_comba8:
++___
++$code.=<<___ if ($flavour =~ /nubi/i);
++	.frame	$sp,6*$SZREG,$ra
++	.mask	0x8000f008,-$SZREG
++	.set	noreorder
++	$PTR_SUB $sp,6*$SZREG
++	$REG_S	$ra,5*$SZREG($sp)
++	$REG_S	$t3,4*$SZREG($sp)
++	$REG_S	$t2,3*$SZREG($sp)
++	$REG_S	$t1,2*$SZREG($sp)
++	$REG_S	$t0,1*$SZREG($sp)
++	$REG_S	$gp,0*$SZREG($sp)
++___
++$code.=<<___;
++	.set	reorder
++	$LD	$a_0,0($a1)
++	$LD	$a_1,$BNSZ($a1)
++	$LD	$a_2,2*$BNSZ($a1)
++	$LD	$a_3,3*$BNSZ($a1)
++
++	$MULTU	$a_0,$a_0		# mul_add_c(a[0],b[0],c1,c2,c3);
++	$LD	$a_4,4*$BNSZ($a1)
++	$LD	$a_5,5*$BNSZ($a1)
++	$LD	$a_6,6*$BNSZ($a1)
++	$LD	$a_7,7*$BNSZ($a1)
++	mflo	$c_1
++	mfhi	$c_2
++	$ST	$c_1,0($a0)
++
++	$MULTU	$a_0,$a_1		# mul_add_c2(a[0],b[1],c2,c3,c1);
++	mflo	$t_1
++	mfhi	$t_2
++	slt	$c_1,$t_2,$zero
++	$SLL	$t_2,1
++	 $MULTU	$a_2,$a_0		# mul_add_c2(a[2],b[0],c3,c1,c2);
++	slt	$a2,$t_1,$zero
++	$ADDU	$t_2,$a2
++	$SLL	$t_1,1
++	$ADDU	$c_2,$t_1
++	sltu	$at,$c_2,$t_1
++	$ADDU	$c_3,$t_2,$at
++	$ST	$c_2,$BNSZ($a0)
++___
++	&add_c2($t_2,$t_1,$c_3,$c_1,$c_2,0,
++		$a_1,$a_1);		# mul_add_c(a[1],b[1],c3,c1,c2);
++$code.=<<___;
++	mflo	$t_1
++	mfhi	$t_2
++	$ADDU	$c_3,$t_1
++	sltu	$at,$c_3,$t_1
++	 $MULTU	$a_0,$a_3		# mul_add_c2(a[0],b[3],c1,c2,c3);
++	$ADDU	$t_2,$at
++	$ADDU	$c_1,$t_2
++	sltu	$at,$c_1,$t_2
++	$ADDU	$c_2,$at
++	$ST	$c_3,2*$BNSZ($a0)
++___
++	&add_c2($t_2,$t_1,$c_1,$c_2,$c_3,0,
++		$a_1,$a_2);		# mul_add_c2(a[1],b[2],c1,c2,c3);
++	&add_c2($t_2,$t_1,$c_1,$c_2,$c_3,1,
++		$a_4,$a_0);		# mul_add_c2(a[4],b[0],c2,c3,c1);
++$code.=<<___;
++	$ST	$c_1,3*$BNSZ($a0)
++___
++	&add_c2($t_2,$t_1,$c_2,$c_3,$c_1,0,
++		$a_3,$a_1);		# mul_add_c2(a[3],b[1],c2,c3,c1);
++	&add_c2($t_2,$t_1,$c_2,$c_3,$c_1,1,
++		$a_2,$a_2);		# mul_add_c(a[2],b[2],c2,c3,c1);
++$code.=<<___;
++	mflo	$t_1
++	mfhi	$t_2
++	$ADDU	$c_2,$t_1
++	sltu	$at,$c_2,$t_1
++	 $MULTU	$a_0,$a_5		# mul_add_c2(a[0],b[5],c3,c1,c2);
++	$ADDU	$t_2,$at
++	$ADDU	$c_3,$t_2
++	sltu	$at,$c_3,$t_2
++	$ADDU	$c_1,$at
++	$ST	$c_2,4*$BNSZ($a0)
++___
++	&add_c2($t_2,$t_1,$c_3,$c_1,$c_2,0,
++		$a_1,$a_4);		# mul_add_c2(a[1],b[4],c3,c1,c2);
++	&add_c2($t_2,$t_1,$c_3,$c_1,$c_2,1,
++		$a_2,$a_3);		# mul_add_c2(a[2],b[3],c3,c1,c2);
++	&add_c2($t_2,$t_1,$c_3,$c_1,$c_2,1,
++		$a_6,$a_0);		# mul_add_c2(a[6],b[0],c1,c2,c3);
++$code.=<<___;
++	$ST	$c_3,5*$BNSZ($a0)
++___
++	&add_c2($t_2,$t_1,$c_1,$c_2,$c_3,0,
++		$a_5,$a_1);		# mul_add_c2(a[5],b[1],c1,c2,c3);
++	&add_c2($t_2,$t_1,$c_1,$c_2,$c_3,1,
++		$a_4,$a_2);		# mul_add_c2(a[4],b[2],c1,c2,c3);
++	&add_c2($t_2,$t_1,$c_1,$c_2,$c_3,1,
++		$a_3,$a_3);		# mul_add_c(a[3],b[3],c1,c2,c3);
++$code.=<<___;
++	mflo	$t_1
++	mfhi	$t_2
++	$ADDU	$c_1,$t_1
++	sltu	$at,$c_1,$t_1
++	 $MULTU	$a_0,$a_7		# mul_add_c2(a[0],b[7],c2,c3,c1);
++	$ADDU	$t_2,$at
++	$ADDU	$c_2,$t_2
++	sltu	$at,$c_2,$t_2
++	$ADDU	$c_3,$at
++	$ST	$c_1,6*$BNSZ($a0)
++___
++	&add_c2($t_2,$t_1,$c_2,$c_3,$c_1,0,
++		$a_1,$a_6);		# mul_add_c2(a[1],b[6],c2,c3,c1);
++	&add_c2($t_2,$t_1,$c_2,$c_3,$c_1,1,
++		$a_2,$a_5);		# mul_add_c2(a[2],b[5],c2,c3,c1);
++	&add_c2($t_2,$t_1,$c_2,$c_3,$c_1,1,
++		$a_3,$a_4);		# mul_add_c2(a[3],b[4],c2,c3,c1);
++	&add_c2($t_2,$t_1,$c_2,$c_3,$c_1,1,
++		$a_7,$a_1);		# mul_add_c2(a[7],b[1],c3,c1,c2);
++$code.=<<___;
++	$ST	$c_2,7*$BNSZ($a0)
++___
++	&add_c2($t_2,$t_1,$c_3,$c_1,$c_2,0,
++		$a_6,$a_2);		# mul_add_c2(a[6],b[2],c3,c1,c2);
++	&add_c2($t_2,$t_1,$c_3,$c_1,$c_2,1,
++		$a_5,$a_3);		# mul_add_c2(a[5],b[3],c3,c1,c2);
++	&add_c2($t_2,$t_1,$c_3,$c_1,$c_2,1,
++		$a_4,$a_4);		# mul_add_c(a[4],b[4],c3,c1,c2);
++$code.=<<___;
++	mflo	$t_1
++	mfhi	$t_2
++	$ADDU	$c_3,$t_1
++	sltu	$at,$c_3,$t_1
++	 $MULTU	$a_2,$a_7		# mul_add_c2(a[2],b[7],c1,c2,c3);
++	$ADDU	$t_2,$at
++	$ADDU	$c_1,$t_2
++	sltu	$at,$c_1,$t_2
++	$ADDU	$c_2,$at
++	$ST	$c_3,8*$BNSZ($a0)
++___
++	&add_c2($t_2,$t_1,$c_1,$c_2,$c_3,0,
++		$a_3,$a_6);		# mul_add_c2(a[3],b[6],c1,c2,c3);
++	&add_c2($t_2,$t_1,$c_1,$c_2,$c_3,1,
++		$a_4,$a_5);		# mul_add_c2(a[4],b[5],c1,c2,c3);
++	&add_c2($t_2,$t_1,$c_1,$c_2,$c_3,1,
++		$a_7,$a_3);		# mul_add_c2(a[7],b[3],c2,c3,c1);
++$code.=<<___;
++	$ST	$c_1,9*$BNSZ($a0)
++___
++	&add_c2($t_2,$t_1,$c_2,$c_3,$c_1,0,
++		$a_6,$a_4);		# mul_add_c2(a[6],b[4],c2,c3,c1);
++	&add_c2($t_2,$t_1,$c_2,$c_3,$c_1,1,
++		$a_5,$a_5);		# mul_add_c(a[5],b[5],c2,c3,c1);
++$code.=<<___;
++	mflo	$t_1
++	mfhi	$t_2
++	$ADDU	$c_2,$t_1
++	sltu	$at,$c_2,$t_1
++	 $MULTU	$a_4,$a_7		# mul_add_c2(a[4],b[7],c3,c1,c2);
++	$ADDU	$t_2,$at
++	$ADDU	$c_3,$t_2
++	sltu	$at,$c_3,$t_2
++	$ADDU	$c_1,$at
++	$ST	$c_2,10*$BNSZ($a0)
++___
++	&add_c2($t_2,$t_1,$c_3,$c_1,$c_2,0,
++		$a_5,$a_6);		# mul_add_c2(a[5],b[6],c3,c1,c2);
++	&add_c2($t_2,$t_1,$c_3,$c_1,$c_2,1,
++		$a_7,$a_5);		# mul_add_c2(a[7],b[5],c1,c2,c3);
++$code.=<<___;
++	$ST	$c_3,11*$BNSZ($a0)
++___
++	&add_c2($t_2,$t_1,$c_1,$c_2,$c_3,0,
++		$a_6,$a_6);		# mul_add_c(a[6],b[6],c1,c2,c3);
++$code.=<<___;
++	mflo	$t_1
++	mfhi	$t_2
++	$ADDU	$c_1,$t_1
++	sltu	$at,$c_1,$t_1
++	 $MULTU	$a_6,$a_7		# mul_add_c2(a[6],b[7],c2,c3,c1);
++	$ADDU	$t_2,$at
++	$ADDU	$c_2,$t_2
++	sltu	$at,$c_2,$t_2
++	$ADDU	$c_3,$at
++	$ST	$c_1,12*$BNSZ($a0)
++___
++	&add_c2($t_2,$t_1,$c_2,$c_3,$c_1,0,
++		$a_7,$a_7);		# mul_add_c(a[7],b[7],c3,c1,c2);
++$code.=<<___;
++	$ST	$c_2,13*$BNSZ($a0)
++
++	mflo	$t_1
++	mfhi	$t_2
++	$ADDU	$c_3,$t_1
++	sltu	$at,$c_3,$t_1
++	$ADDU	$t_2,$at
++	$ADDU	$c_1,$t_2
++	$ST	$c_3,14*$BNSZ($a0)
++	$ST	$c_1,15*$BNSZ($a0)
++
++	.set	noreorder
++___
++$code.=<<___ if ($flavour =~ /nubi/i);
++	$REG_L	$t3,4*$SZREG($sp)
++	$REG_L	$t2,3*$SZREG($sp)
++	$REG_L	$t1,2*$SZREG($sp)
++	$REG_L	$t0,1*$SZREG($sp)
++	$REG_L	$gp,0*$SZREG($sp)
++	$PTR_ADD $sp,6*$SZREG
++___
++$code.=<<___;
++	jr	$ra
++	nop
++.end	bn_sqr_comba8
++
++.align	5
++.globl	bn_sqr_comba4
++.ent	bn_sqr_comba4
++bn_sqr_comba4:
++___
++$code.=<<___ if ($flavour =~ /nubi/i);
++	.frame	$sp,6*$SZREG,$ra
++	.mask	0x8000f008,-$SZREG
++	.set	noreorder
++	$PTR_SUB $sp,6*$SZREG
++	$REG_S	$ra,5*$SZREG($sp)
++	$REG_S	$t3,4*$SZREG($sp)
++	$REG_S	$t2,3*$SZREG($sp)
++	$REG_S	$t1,2*$SZREG($sp)
++	$REG_S	$t0,1*$SZREG($sp)
++	$REG_S	$gp,0*$SZREG($sp)
++___
++$code.=<<___;
++	.set	reorder
++	$LD	$a_0,0($a1)
++	$LD	$a_1,$BNSZ($a1)
++	$MULTU	$a_0,$a_0		# mul_add_c(a[0],b[0],c1,c2,c3);
++	$LD	$a_2,2*$BNSZ($a1)
++	$LD	$a_3,3*$BNSZ($a1)
++	mflo	$c_1
++	mfhi	$c_2
++	$ST	$c_1,0($a0)
++
++	$MULTU	$a_0,$a_1		# mul_add_c2(a[0],b[1],c2,c3,c1);
++	mflo	$t_1
++	mfhi	$t_2
++	slt	$c_1,$t_2,$zero
++	$SLL	$t_2,1
++	 $MULTU	$a_2,$a_0		# mul_add_c2(a[2],b[0],c3,c1,c2);
++	slt	$a2,$t_1,$zero
++	$ADDU	$t_2,$a2
++	$SLL	$t_1,1
++	$ADDU	$c_2,$t_1
++	sltu	$at,$c_2,$t_1
++	$ADDU	$c_3,$t_2,$at
++	$ST	$c_2,$BNSZ($a0)
++___
++	&add_c2($t_2,$t_1,$c_3,$c_1,$c_2,0,
++		$a_1,$a_1);		# mul_add_c(a[1],b[1],c3,c1,c2);
++$code.=<<___;
++	mflo	$t_1
++	mfhi	$t_2
++	$ADDU	$c_3,$t_1
++	sltu	$at,$c_3,$t_1
++	 $MULTU	$a_0,$a_3		# mul_add_c2(a[0],b[3],c1,c2,c3);
++	$ADDU	$t_2,$at
++	$ADDU	$c_1,$t_2
++	sltu	$at,$c_1,$t_2
++	$ADDU	$c_2,$at
++	$ST	$c_3,2*$BNSZ($a0)
++___
++	&add_c2($t_2,$t_1,$c_1,$c_2,$c_3,0,
++		$a_1,$a_2);		# mul_add_c2(a2[1],b[2],c1,c2,c3);
++	&add_c2($t_2,$t_1,$c_1,$c_2,$c_3,1,
++		$a_3,$a_1);		# mul_add_c2(a[3],b[1],c2,c3,c1);
++$code.=<<___;
++	$ST	$c_1,3*$BNSZ($a0)
++___
++	&add_c2($t_2,$t_1,$c_2,$c_3,$c_1,0,
++		$a_2,$a_2);		# mul_add_c(a[2],b[2],c2,c3,c1);
++$code.=<<___;
++	mflo	$t_1
++	mfhi	$t_2
++	$ADDU	$c_2,$t_1
++	sltu	$at,$c_2,$t_1
++	 $MULTU	$a_2,$a_3		# mul_add_c2(a[2],b[3],c3,c1,c2);
++	$ADDU	$t_2,$at
++	$ADDU	$c_3,$t_2
++	sltu	$at,$c_3,$t_2
++	$ADDU	$c_1,$at
++	$ST	$c_2,4*$BNSZ($a0)
++___
++	&add_c2($t_2,$t_1,$c_3,$c_1,$c_2,0,
++		$a_3,$a_3);		# mul_add_c(a[3],b[3],c1,c2,c3);
++$code.=<<___;
++	$ST	$c_3,5*$BNSZ($a0)
++
++	mflo	$t_1
++	mfhi	$t_2
++	$ADDU	$c_1,$t_1
++	sltu	$at,$c_1,$t_1
++	$ADDU	$t_2,$at
++	$ADDU	$c_2,$t_2
++	$ST	$c_1,6*$BNSZ($a0)
++	$ST	$c_2,7*$BNSZ($a0)
++
++	.set	noreorder
++___
++$code.=<<___ if ($flavour =~ /nubi/i);
++	$REG_L	$t3,4*$SZREG($sp)
++	$REG_L	$t2,3*$SZREG($sp)
++	$REG_L	$t1,2*$SZREG($sp)
++	$REG_L	$t0,1*$SZREG($sp)
++	$REG_L	$gp,0*$SZREG($sp)
++	$PTR_ADD $sp,6*$SZREG
++___
++$code.=<<___;
++	jr	$ra
++	nop
++.end	bn_sqr_comba4
++___
++print $code;
++close STDOUT;
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/bn/asm/pa-risc2.s b/CryptoPkg/Library/OpensslLib/openssl/crypto/bn/asm/pa-risc2.s
+new file mode 100644
+index 0000000..413eac7
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/bn/asm/pa-risc2.s
+@@ -0,0 +1,1624 @@
++; Copyright 1998-2016 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
++; in the file LICENSE in the source distribution or at
++; https://www.openssl.org/source/license.html
++;
++; PA-RISC 2.0 implementation of bn_asm code, based on the
++; 64-bit version of the code.  This code is effectively the
++; same as the 64-bit version except the register model is
++; slightly different given all values must be 32-bit between
++; function calls.  Thus the 64-bit return values are returned
++; in %ret0 and %ret1 vs just %ret0 as is done in 64-bit
++;
++;
++; This code is approximately 2x faster than the C version
++; for RSA/DSA.
++;
++; See http://devresource.hp.com/  for more details on the PA-RISC
++; architecture.  Also see the book "PA-RISC 2.0 Architecture"
++; by Gerry Kane for information on the instruction set architecture.
++;
++; Code written by Chris Ruemmler (with some help from the HP C
++; compiler).
++;
++; The code compiles with HP's assembler
++;
++
++	.level	2.0N
++	.space	$TEXT$
++	.subspa	$CODE$,QUAD=0,ALIGN=8,ACCESS=0x2c,CODE_ONLY
++
++;
++; Global Register definitions used for the routines.
++;
++; Some information about HP's runtime architecture for 32-bits.
++;
++; "Caller save" means the calling function must save the register
++; if it wants the register to be preserved.
++; "Callee save" means if a function uses the register, it must save
++; the value before using it.
++;
++; For the floating point registers 
++;
++;    "caller save" registers: fr4-fr11, fr22-fr31
++;    "callee save" registers: fr12-fr21
++;    "special" registers: fr0-fr3 (status and exception registers)
++;
++; For the integer registers
++;     value zero             :  r0
++;     "caller save" registers: r1,r19-r26
++;     "callee save" registers: r3-r18
++;     return register        :  r2  (rp)
++;     return values          ; r28,r29  (ret0,ret1)
++;     Stack pointer          ; r30  (sp) 
++;     millicode return ptr   ; r31  (also a caller save register)
++
++
++;
++; Arguments to the routines
++;
++r_ptr       .reg %r26
++a_ptr       .reg %r25
++b_ptr       .reg %r24
++num         .reg %r24
++n           .reg %r23
++
++;
++; Note that the "w" argument for bn_mul_add_words and bn_mul_words
++; is passed on the stack at a delta of -56 from the top of stack
++; as the routine is entered.
++;
++
++;
++; Globals used in some routines
++;
++
++top_overflow .reg %r23
++high_mask    .reg %r22    ; value 0xffffffff80000000L
++
++
++;------------------------------------------------------------------------------
++;
++; bn_mul_add_words
++;
++;BN_ULONG bn_mul_add_words(BN_ULONG *r_ptr, BN_ULONG *a_ptr, 
++;								int num, BN_ULONG w)
++;
++; arg0 = r_ptr
++; arg1 = a_ptr
++; arg3 = num
++; -56(sp) =  w
++;
++; Local register definitions
++;
++
++fm1          .reg %fr22
++fm           .reg %fr23
++ht_temp      .reg %fr24
++ht_temp_1    .reg %fr25
++lt_temp      .reg %fr26
++lt_temp_1    .reg %fr27
++fm1_1        .reg %fr28
++fm_1         .reg %fr29
++
++fw_h         .reg %fr7L
++fw_l         .reg %fr7R
++fw           .reg %fr7
++
++fht_0        .reg %fr8L
++flt_0        .reg %fr8R
++t_float_0    .reg %fr8
++
++fht_1        .reg %fr9L
++flt_1        .reg %fr9R
++t_float_1    .reg %fr9
++
++tmp_0        .reg %r31
++tmp_1        .reg %r21
++m_0          .reg %r20 
++m_1          .reg %r19 
++ht_0         .reg %r1  
++ht_1         .reg %r3
++lt_0         .reg %r4
++lt_1         .reg %r5
++m1_0         .reg %r6 
++m1_1         .reg %r7 
++rp_val       .reg %r8
++rp_val_1     .reg %r9
++
++bn_mul_add_words
++	.export	bn_mul_add_words,entry,NO_RELOCATION,LONG_RETURN
++	.proc
++	.callinfo frame=128
++    .entry
++	.align 64
++
++    STD     %r3,0(%sp)          ; save r3  
++    STD     %r4,8(%sp)          ; save r4  
++	NOP                         ; Needed to make the loop 16-byte aligned
++	NOP                         ; needed to make the loop 16-byte aligned
++
++    STD     %r5,16(%sp)         ; save r5  
++	NOP
++    STD     %r6,24(%sp)         ; save r6  
++    STD     %r7,32(%sp)         ; save r7  
++
++    STD     %r8,40(%sp)         ; save r8  
++    STD     %r9,48(%sp)         ; save r9  
++    COPY    %r0,%ret1           ; return 0 by default
++    DEPDI,Z 1,31,1,top_overflow ; top_overflow = 1 << 32    
++
++    CMPIB,>= 0,num,bn_mul_add_words_exit  ; if (num <= 0) then exit
++	LDO     128(%sp),%sp        ; bump stack
++
++	;
++	; The loop is unrolled twice, so if there is only 1 number
++    ; then go straight to the cleanup code.
++	;
++	CMPIB,= 1,num,bn_mul_add_words_single_top
++	FLDD    -184(%sp),fw        ; (-56-128) load up w into fw (fw_h/fw_l)
++
++	;
++	; This loop is unrolled 2 times (64-byte aligned as well)
++	;
++	; PA-RISC 2.0 chips have two fully pipelined multipliers, thus
++    ; two 32-bit mutiplies can be issued per cycle.
++    ; 
++bn_mul_add_words_unroll2
++
++    FLDD    0(a_ptr),t_float_0       ; load up 64-bit value (fr8L) ht(L)/lt(R)
++    FLDD    8(a_ptr),t_float_1       ; load up 64-bit value (fr8L) ht(L)/lt(R)
++    LDD     0(r_ptr),rp_val          ; rp[0]
++    LDD     8(r_ptr),rp_val_1        ; rp[1]
++
++    XMPYU   fht_0,fw_l,fm1           ; m1[0] = fht_0*fw_l
++    XMPYU   fht_1,fw_l,fm1_1         ; m1[1] = fht_1*fw_l
++    FSTD    fm1,-16(%sp)             ; -16(sp) = m1[0]
++    FSTD    fm1_1,-48(%sp)           ; -48(sp) = m1[1]
++
++    XMPYU   flt_0,fw_h,fm            ; m[0] = flt_0*fw_h
++    XMPYU   flt_1,fw_h,fm_1          ; m[1] = flt_1*fw_h
++    FSTD    fm,-8(%sp)               ; -8(sp) = m[0]
++    FSTD    fm_1,-40(%sp)            ; -40(sp) = m[1]
++
++    XMPYU   fht_0,fw_h,ht_temp       ; ht_temp   = fht_0*fw_h
++    XMPYU   fht_1,fw_h,ht_temp_1     ; ht_temp_1 = fht_1*fw_h
++    FSTD    ht_temp,-24(%sp)         ; -24(sp)   = ht_temp
++    FSTD    ht_temp_1,-56(%sp)       ; -56(sp)   = ht_temp_1
++
++    XMPYU   flt_0,fw_l,lt_temp       ; lt_temp = lt*fw_l
++    XMPYU   flt_1,fw_l,lt_temp_1     ; lt_temp = lt*fw_l
++    FSTD    lt_temp,-32(%sp)         ; -32(sp) = lt_temp 
++    FSTD    lt_temp_1,-64(%sp)       ; -64(sp) = lt_temp_1 
++
++    LDD     -8(%sp),m_0              ; m[0] 
++    LDD     -40(%sp),m_1             ; m[1]
++    LDD     -16(%sp),m1_0            ; m1[0]
++    LDD     -48(%sp),m1_1            ; m1[1]
++
++    LDD     -24(%sp),ht_0            ; ht[0]
++    LDD     -56(%sp),ht_1            ; ht[1]
++    ADD,L   m1_0,m_0,tmp_0           ; tmp_0 = m[0] + m1[0]; 
++    ADD,L   m1_1,m_1,tmp_1           ; tmp_1 = m[1] + m1[1]; 
++
++    LDD     -32(%sp),lt_0            
++    LDD     -64(%sp),lt_1            
++    CMPCLR,*>>= tmp_0,m1_0, %r0      ; if (m[0] < m1[0])
++    ADD,L   ht_0,top_overflow,ht_0   ; ht[0] += (1<<32)
++
++    CMPCLR,*>>= tmp_1,m1_1,%r0       ; if (m[1] < m1[1])
++    ADD,L   ht_1,top_overflow,ht_1   ; ht[1] += (1<<32)
++    EXTRD,U tmp_0,31,32,m_0          ; m[0]>>32  
++    DEPD,Z  tmp_0,31,32,m1_0         ; m1[0] = m[0]<<32 
++
++    EXTRD,U tmp_1,31,32,m_1          ; m[1]>>32  
++    DEPD,Z  tmp_1,31,32,m1_1         ; m1[1] = m[1]<<32 
++    ADD,L   ht_0,m_0,ht_0            ; ht[0]+= (m[0]>>32)
++    ADD,L   ht_1,m_1,ht_1            ; ht[1]+= (m[1]>>32)
++
++    ADD     lt_0,m1_0,lt_0           ; lt[0] = lt[0]+m1[0];
++	ADD,DC  ht_0,%r0,ht_0            ; ht[0]++
++    ADD     lt_1,m1_1,lt_1           ; lt[1] = lt[1]+m1[1];
++    ADD,DC  ht_1,%r0,ht_1            ; ht[1]++
++
++    ADD    %ret1,lt_0,lt_0           ; lt[0] = lt[0] + c;
++	ADD,DC  ht_0,%r0,ht_0            ; ht[0]++
++    ADD     lt_0,rp_val,lt_0         ; lt[0] = lt[0]+rp[0]
++    ADD,DC  ht_0,%r0,ht_0            ; ht[0]++
++
++	LDO    -2(num),num               ; num = num - 2;
++    ADD     ht_0,lt_1,lt_1           ; lt[1] = lt[1] + ht_0 (c);
++    ADD,DC  ht_1,%r0,ht_1            ; ht[1]++
++    STD     lt_0,0(r_ptr)            ; rp[0] = lt[0]
++
++    ADD     lt_1,rp_val_1,lt_1       ; lt[1] = lt[1]+rp[1]
++    ADD,DC  ht_1,%r0,%ret1           ; ht[1]++
++    LDO     16(a_ptr),a_ptr          ; a_ptr += 2
++
++    STD     lt_1,8(r_ptr)            ; rp[1] = lt[1]
++	CMPIB,<= 2,num,bn_mul_add_words_unroll2 ; go again if more to do
++    LDO     16(r_ptr),r_ptr          ; r_ptr += 2
++
++    CMPIB,=,N 0,num,bn_mul_add_words_exit ; are we done, or cleanup last one
++
++	;
++	; Top of loop aligned on 64-byte boundary
++	;
++bn_mul_add_words_single_top
++    FLDD    0(a_ptr),t_float_0        ; load up 64-bit value (fr8L) ht(L)/lt(R)
++    LDD     0(r_ptr),rp_val           ; rp[0]
++    LDO     8(a_ptr),a_ptr            ; a_ptr++
++    XMPYU   fht_0,fw_l,fm1            ; m1 = ht*fw_l
++    FSTD    fm1,-16(%sp)              ; -16(sp) = m1
++    XMPYU   flt_0,fw_h,fm             ; m = lt*fw_h
++    FSTD    fm,-8(%sp)                ; -8(sp) = m
++    XMPYU   fht_0,fw_h,ht_temp        ; ht_temp = ht*fw_h
++    FSTD    ht_temp,-24(%sp)          ; -24(sp) = ht
++    XMPYU   flt_0,fw_l,lt_temp        ; lt_temp = lt*fw_l
++    FSTD    lt_temp,-32(%sp)          ; -32(sp) = lt 
++
++    LDD     -8(%sp),m_0               
++    LDD    -16(%sp),m1_0              ; m1 = temp1 
++    ADD,L   m_0,m1_0,tmp_0            ; tmp_0 = m + m1; 
++    LDD     -24(%sp),ht_0             
++    LDD     -32(%sp),lt_0             
++
++    CMPCLR,*>>= tmp_0,m1_0,%r0        ; if (m < m1)
++    ADD,L   ht_0,top_overflow,ht_0    ; ht += (1<<32)
++
++    EXTRD,U tmp_0,31,32,m_0           ; m>>32  
++    DEPD,Z  tmp_0,31,32,m1_0          ; m1 = m<<32 
++
++    ADD,L   ht_0,m_0,ht_0             ; ht+= (m>>32)
++    ADD     lt_0,m1_0,tmp_0           ; tmp_0 = lt+m1;
++    ADD,DC  ht_0,%r0,ht_0             ; ht++
++    ADD     %ret1,tmp_0,lt_0          ; lt = lt + c;
++    ADD,DC  ht_0,%r0,ht_0             ; ht++
++    ADD     lt_0,rp_val,lt_0          ; lt = lt+rp[0]
++    ADD,DC  ht_0,%r0,%ret1            ; ht++
++    STD     lt_0,0(r_ptr)             ; rp[0] = lt
++
++bn_mul_add_words_exit
++    .EXIT
++	
++    EXTRD,U %ret1,31,32,%ret0         ; for 32-bit, return in ret0/ret1
++    LDD     -80(%sp),%r9              ; restore r9  
++    LDD     -88(%sp),%r8              ; restore r8  
++    LDD     -96(%sp),%r7              ; restore r7  
++    LDD     -104(%sp),%r6             ; restore r6  
++    LDD     -112(%sp),%r5             ; restore r5  
++    LDD     -120(%sp),%r4             ; restore r4  
++    BVE     (%rp)
++    LDD,MB  -128(%sp),%r3             ; restore r3
++	.PROCEND	;in=23,24,25,26,29;out=28;
++
++;----------------------------------------------------------------------------
++;
++;BN_ULONG bn_mul_words(BN_ULONG *rp, BN_ULONG *ap, int num, BN_ULONG w)
++;
++; arg0 = rp
++; arg1 = ap
++; arg3 = num
++; w on stack at -56(sp)
++
++bn_mul_words
++	.proc
++	.callinfo frame=128
++    .entry
++	.EXPORT	bn_mul_words,ENTRY,PRIV_LEV=3,NO_RELOCATION,LONG_RETURN
++	.align 64
++
++    STD     %r3,0(%sp)          ; save r3  
++    STD     %r4,8(%sp)          ; save r4  
++	NOP
++    STD     %r5,16(%sp)         ; save r5  
++
++    STD     %r6,24(%sp)         ; save r6  
++    STD     %r7,32(%sp)         ; save r7  
++    COPY    %r0,%ret1           ; return 0 by default
++    DEPDI,Z 1,31,1,top_overflow ; top_overflow = 1 << 32    
++
++    CMPIB,>= 0,num,bn_mul_words_exit
++	LDO     128(%sp),%sp    ; bump stack
++
++	;
++	; See if only 1 word to do, thus just do cleanup
++	;
++	CMPIB,= 1,num,bn_mul_words_single_top
++	FLDD    -184(%sp),fw        ; (-56-128) load up w into fw (fw_h/fw_l)
++
++	;
++	; This loop is unrolled 2 times (64-byte aligned as well)
++	;
++	; PA-RISC 2.0 chips have two fully pipelined multipliers, thus
++    ; two 32-bit mutiplies can be issued per cycle.
++    ; 
++bn_mul_words_unroll2
++
++    FLDD    0(a_ptr),t_float_0        ; load up 64-bit value (fr8L) ht(L)/lt(R)
++    FLDD    8(a_ptr),t_float_1        ; load up 64-bit value (fr8L) ht(L)/lt(R)
++    XMPYU   fht_0,fw_l,fm1            ; m1[0] = fht_0*fw_l
++    XMPYU   fht_1,fw_l,fm1_1          ; m1[1] = ht*fw_l
++
++    FSTD    fm1,-16(%sp)              ; -16(sp) = m1
++    FSTD    fm1_1,-48(%sp)            ; -48(sp) = m1
++    XMPYU   flt_0,fw_h,fm             ; m = lt*fw_h
++    XMPYU   flt_1,fw_h,fm_1           ; m = lt*fw_h
++
++    FSTD    fm,-8(%sp)                ; -8(sp) = m
++    FSTD    fm_1,-40(%sp)             ; -40(sp) = m
++    XMPYU   fht_0,fw_h,ht_temp        ; ht_temp = fht_0*fw_h
++    XMPYU   fht_1,fw_h,ht_temp_1      ; ht_temp = ht*fw_h
++
++    FSTD    ht_temp,-24(%sp)          ; -24(sp) = ht
++    FSTD    ht_temp_1,-56(%sp)        ; -56(sp) = ht
++    XMPYU   flt_0,fw_l,lt_temp        ; lt_temp = lt*fw_l
++    XMPYU   flt_1,fw_l,lt_temp_1      ; lt_temp = lt*fw_l
++
++    FSTD    lt_temp,-32(%sp)          ; -32(sp) = lt 
++    FSTD    lt_temp_1,-64(%sp)        ; -64(sp) = lt 
++    LDD     -8(%sp),m_0               
++    LDD     -40(%sp),m_1              
++
++    LDD    -16(%sp),m1_0              
++    LDD    -48(%sp),m1_1              
++    LDD     -24(%sp),ht_0             
++    LDD     -56(%sp),ht_1             
++
++    ADD,L   m1_0,m_0,tmp_0            ; tmp_0 = m + m1; 
++    ADD,L   m1_1,m_1,tmp_1            ; tmp_1 = m + m1; 
++    LDD     -32(%sp),lt_0             
++    LDD     -64(%sp),lt_1             
++
++    CMPCLR,*>>= tmp_0,m1_0, %r0       ; if (m < m1)
++    ADD,L   ht_0,top_overflow,ht_0    ; ht += (1<<32)
++    CMPCLR,*>>= tmp_1,m1_1,%r0        ; if (m < m1)
++    ADD,L   ht_1,top_overflow,ht_1    ; ht += (1<<32)
++
++    EXTRD,U tmp_0,31,32,m_0           ; m>>32  
++    DEPD,Z  tmp_0,31,32,m1_0          ; m1 = m<<32 
++    EXTRD,U tmp_1,31,32,m_1           ; m>>32  
++    DEPD,Z  tmp_1,31,32,m1_1          ; m1 = m<<32 
++
++    ADD,L   ht_0,m_0,ht_0             ; ht+= (m>>32)
++    ADD,L   ht_1,m_1,ht_1             ; ht+= (m>>32)
++    ADD     lt_0,m1_0,lt_0            ; lt = lt+m1;
++	ADD,DC  ht_0,%r0,ht_0             ; ht++
++
++    ADD     lt_1,m1_1,lt_1            ; lt = lt+m1;
++    ADD,DC  ht_1,%r0,ht_1             ; ht++
++    ADD    %ret1,lt_0,lt_0            ; lt = lt + c (ret1);
++	ADD,DC  ht_0,%r0,ht_0             ; ht++
++
++    ADD     ht_0,lt_1,lt_1            ; lt = lt + c (ht_0)
++    ADD,DC  ht_1,%r0,ht_1             ; ht++
++    STD     lt_0,0(r_ptr)             ; rp[0] = lt
++    STD     lt_1,8(r_ptr)             ; rp[1] = lt
++
++	COPY    ht_1,%ret1                ; carry = ht
++	LDO    -2(num),num                ; num = num - 2;
++    LDO     16(a_ptr),a_ptr           ; ap += 2
++	CMPIB,<= 2,num,bn_mul_words_unroll2
++    LDO     16(r_ptr),r_ptr           ; rp++
++
++    CMPIB,=,N 0,num,bn_mul_words_exit ; are we done?
++
++	;
++	; Top of loop aligned on 64-byte boundary
++	;
++bn_mul_words_single_top
++    FLDD    0(a_ptr),t_float_0        ; load up 64-bit value (fr8L) ht(L)/lt(R)
++
++    XMPYU   fht_0,fw_l,fm1            ; m1 = ht*fw_l
++    FSTD    fm1,-16(%sp)              ; -16(sp) = m1
++    XMPYU   flt_0,fw_h,fm             ; m = lt*fw_h
++    FSTD    fm,-8(%sp)                ; -8(sp) = m
++    XMPYU   fht_0,fw_h,ht_temp        ; ht_temp = ht*fw_h
++    FSTD    ht_temp,-24(%sp)          ; -24(sp) = ht
++    XMPYU   flt_0,fw_l,lt_temp        ; lt_temp = lt*fw_l
++    FSTD    lt_temp,-32(%sp)          ; -32(sp) = lt 
++
++    LDD     -8(%sp),m_0               
++    LDD    -16(%sp),m1_0              
++    ADD,L   m_0,m1_0,tmp_0            ; tmp_0 = m + m1; 
++    LDD     -24(%sp),ht_0             
++    LDD     -32(%sp),lt_0             
++
++    CMPCLR,*>>= tmp_0,m1_0,%r0        ; if (m < m1)
++    ADD,L   ht_0,top_overflow,ht_0    ; ht += (1<<32)
++
++    EXTRD,U tmp_0,31,32,m_0           ; m>>32  
++    DEPD,Z  tmp_0,31,32,m1_0          ; m1 = m<<32 
++
++    ADD,L   ht_0,m_0,ht_0             ; ht+= (m>>32)
++    ADD     lt_0,m1_0,lt_0            ; lt= lt+m1;
++    ADD,DC  ht_0,%r0,ht_0             ; ht++
++
++    ADD     %ret1,lt_0,lt_0           ; lt = lt + c;
++    ADD,DC  ht_0,%r0,ht_0             ; ht++
++
++    COPY    ht_0,%ret1                ; copy carry
++    STD     lt_0,0(r_ptr)             ; rp[0] = lt
++
++bn_mul_words_exit
++    .EXIT
++    EXTRD,U %ret1,31,32,%ret0           ; for 32-bit, return in ret0/ret1
++    LDD     -96(%sp),%r7              ; restore r7  
++    LDD     -104(%sp),%r6             ; restore r6  
++    LDD     -112(%sp),%r5             ; restore r5  
++    LDD     -120(%sp),%r4             ; restore r4  
++    BVE     (%rp)
++    LDD,MB  -128(%sp),%r3             ; restore r3
++	.PROCEND	
++
++;----------------------------------------------------------------------------
++;
++;void bn_sqr_words(BN_ULONG *rp, BN_ULONG *ap, int num)
++;
++; arg0 = rp
++; arg1 = ap
++; arg2 = num
++;
++
++bn_sqr_words
++	.proc
++	.callinfo FRAME=128,ENTRY_GR=%r3,ARGS_SAVED,ORDERING_AWARE
++	.EXPORT	bn_sqr_words,ENTRY,PRIV_LEV=3,NO_RELOCATION,LONG_RETURN
++    .entry
++	.align 64
++
++    STD     %r3,0(%sp)          ; save r3  
++    STD     %r4,8(%sp)          ; save r4  
++	NOP
++    STD     %r5,16(%sp)         ; save r5  
++
++    CMPIB,>= 0,num,bn_sqr_words_exit
++	LDO     128(%sp),%sp       ; bump stack
++
++	;
++	; If only 1, the goto straight to cleanup
++	;
++	CMPIB,= 1,num,bn_sqr_words_single_top
++    DEPDI,Z -1,32,33,high_mask   ; Create Mask 0xffffffff80000000L
++
++	;
++	; This loop is unrolled 2 times (64-byte aligned as well)
++	;
++
++bn_sqr_words_unroll2
++    FLDD    0(a_ptr),t_float_0        ; a[0]
++    FLDD    8(a_ptr),t_float_1        ; a[1]
++    XMPYU   fht_0,flt_0,fm            ; m[0]
++    XMPYU   fht_1,flt_1,fm_1          ; m[1]
++
++    FSTD    fm,-24(%sp)               ; store m[0]
++    FSTD    fm_1,-56(%sp)             ; store m[1]
++    XMPYU   flt_0,flt_0,lt_temp       ; lt[0]
++    XMPYU   flt_1,flt_1,lt_temp_1     ; lt[1]
++
++    FSTD    lt_temp,-16(%sp)          ; store lt[0]
++    FSTD    lt_temp_1,-48(%sp)        ; store lt[1]
++    XMPYU   fht_0,fht_0,ht_temp       ; ht[0]
++    XMPYU   fht_1,fht_1,ht_temp_1     ; ht[1]
++
++    FSTD    ht_temp,-8(%sp)           ; store ht[0]
++    FSTD    ht_temp_1,-40(%sp)        ; store ht[1]
++    LDD     -24(%sp),m_0             
++    LDD     -56(%sp),m_1              
++
++    AND     m_0,high_mask,tmp_0       ; m[0] & Mask
++    AND     m_1,high_mask,tmp_1       ; m[1] & Mask
++    DEPD,Z  m_0,30,31,m_0             ; m[0] << 32+1
++    DEPD,Z  m_1,30,31,m_1             ; m[1] << 32+1
++
++    LDD     -16(%sp),lt_0        
++    LDD     -48(%sp),lt_1        
++    EXTRD,U tmp_0,32,33,tmp_0         ; tmp_0 = m[0]&Mask >> 32-1
++    EXTRD,U tmp_1,32,33,tmp_1         ; tmp_1 = m[1]&Mask >> 32-1
++
++    LDD     -8(%sp),ht_0            
++    LDD     -40(%sp),ht_1           
++    ADD,L   ht_0,tmp_0,ht_0           ; ht[0] += tmp_0
++    ADD,L   ht_1,tmp_1,ht_1           ; ht[1] += tmp_1
++
++    ADD     lt_0,m_0,lt_0             ; lt = lt+m
++    ADD,DC  ht_0,%r0,ht_0             ; ht[0]++
++    STD     lt_0,0(r_ptr)             ; rp[0] = lt[0]
++    STD     ht_0,8(r_ptr)             ; rp[1] = ht[1]
++
++    ADD     lt_1,m_1,lt_1             ; lt = lt+m
++    ADD,DC  ht_1,%r0,ht_1             ; ht[1]++
++    STD     lt_1,16(r_ptr)            ; rp[2] = lt[1]
++    STD     ht_1,24(r_ptr)            ; rp[3] = ht[1]
++
++	LDO    -2(num),num                ; num = num - 2;
++    LDO     16(a_ptr),a_ptr           ; ap += 2
++	CMPIB,<= 2,num,bn_sqr_words_unroll2
++    LDO     32(r_ptr),r_ptr           ; rp += 4
++
++    CMPIB,=,N 0,num,bn_sqr_words_exit ; are we done?
++
++	;
++	; Top of loop aligned on 64-byte boundary
++	;
++bn_sqr_words_single_top
++    FLDD    0(a_ptr),t_float_0        ; load up 64-bit value (fr8L) ht(L)/lt(R)
++
++    XMPYU   fht_0,flt_0,fm            ; m
++    FSTD    fm,-24(%sp)               ; store m
++
++    XMPYU   flt_0,flt_0,lt_temp       ; lt
++    FSTD    lt_temp,-16(%sp)          ; store lt
++
++    XMPYU   fht_0,fht_0,ht_temp       ; ht
++    FSTD    ht_temp,-8(%sp)           ; store ht
++
++    LDD     -24(%sp),m_0              ; load m
++    AND     m_0,high_mask,tmp_0       ; m & Mask
++    DEPD,Z  m_0,30,31,m_0             ; m << 32+1
++    LDD     -16(%sp),lt_0             ; lt
++
++    LDD     -8(%sp),ht_0              ; ht
++    EXTRD,U tmp_0,32,33,tmp_0         ; tmp_0 = m&Mask >> 32-1
++    ADD     m_0,lt_0,lt_0             ; lt = lt+m
++    ADD,L   ht_0,tmp_0,ht_0           ; ht += tmp_0
++    ADD,DC  ht_0,%r0,ht_0             ; ht++
++
++    STD     lt_0,0(r_ptr)             ; rp[0] = lt
++    STD     ht_0,8(r_ptr)             ; rp[1] = ht
++
++bn_sqr_words_exit
++    .EXIT
++    LDD     -112(%sp),%r5       ; restore r5  
++    LDD     -120(%sp),%r4       ; restore r4  
++    BVE     (%rp)
++    LDD,MB  -128(%sp),%r3 
++	.PROCEND	;in=23,24,25,26,29;out=28;
++
++
++;----------------------------------------------------------------------------
++;
++;BN_ULONG bn_add_words(BN_ULONG *r, BN_ULONG *a, BN_ULONG *b, int n)
++;
++; arg0 = rp 
++; arg1 = ap
++; arg2 = bp 
++; arg3 = n
++
++t  .reg %r22
++b  .reg %r21
++l  .reg %r20
++
++bn_add_words
++	.proc
++    .entry
++	.callinfo
++	.EXPORT	bn_add_words,ENTRY,PRIV_LEV=3,NO_RELOCATION,LONG_RETURN
++	.align 64
++
++    CMPIB,>= 0,n,bn_add_words_exit
++    COPY    %r0,%ret1           ; return 0 by default
++
++	;
++	; If 2 or more numbers do the loop
++	;
++	CMPIB,= 1,n,bn_add_words_single_top
++	NOP
++
++	;
++	; This loop is unrolled 2 times (64-byte aligned as well)
++	;
++bn_add_words_unroll2
++	LDD     0(a_ptr),t
++	LDD     0(b_ptr),b
++	ADD     t,%ret1,t                    ; t = t+c;
++	ADD,DC  %r0,%r0,%ret1                ; set c to carry
++	ADD     t,b,l                        ; l = t + b[0]
++	ADD,DC  %ret1,%r0,%ret1              ; c+= carry
++	STD     l,0(r_ptr)
++
++	LDD     8(a_ptr),t
++	LDD     8(b_ptr),b
++	ADD     t,%ret1,t                     ; t = t+c;
++	ADD,DC  %r0,%r0,%ret1                 ; set c to carry
++	ADD     t,b,l                         ; l = t + b[0]
++	ADD,DC  %ret1,%r0,%ret1               ; c+= carry
++	STD     l,8(r_ptr)
++
++	LDO     -2(n),n
++	LDO     16(a_ptr),a_ptr
++	LDO     16(b_ptr),b_ptr
++
++	CMPIB,<= 2,n,bn_add_words_unroll2
++	LDO     16(r_ptr),r_ptr
++
++    CMPIB,=,N 0,n,bn_add_words_exit ; are we done?
++
++bn_add_words_single_top
++	LDD     0(a_ptr),t
++	LDD     0(b_ptr),b
++
++	ADD     t,%ret1,t                 ; t = t+c;
++	ADD,DC  %r0,%r0,%ret1             ; set c to carry (could use CMPCLR??)
++	ADD     t,b,l                     ; l = t + b[0]
++	ADD,DC  %ret1,%r0,%ret1           ; c+= carry
++	STD     l,0(r_ptr)
++
++bn_add_words_exit
++    .EXIT
++    BVE     (%rp)
++    EXTRD,U %ret1,31,32,%ret0           ; for 32-bit, return in ret0/ret1
++	.PROCEND	;in=23,24,25,26,29;out=28;
++
++;----------------------------------------------------------------------------
++;
++;BN_ULONG bn_sub_words(BN_ULONG *r, BN_ULONG *a, BN_ULONG *b, int n)
++;
++; arg0 = rp 
++; arg1 = ap
++; arg2 = bp 
++; arg3 = n
++
++t1       .reg %r22
++t2       .reg %r21
++sub_tmp1 .reg %r20
++sub_tmp2 .reg %r19
++
++
++bn_sub_words
++	.proc
++	.callinfo 
++	.EXPORT	bn_sub_words,ENTRY,PRIV_LEV=3,NO_RELOCATION,LONG_RETURN
++    .entry
++	.align 64
++
++    CMPIB,>=  0,n,bn_sub_words_exit
++    COPY    %r0,%ret1           ; return 0 by default
++
++	;
++	; If 2 or more numbers do the loop
++	;
++	CMPIB,= 1,n,bn_sub_words_single_top
++	NOP
++
++	;
++	; This loop is unrolled 2 times (64-byte aligned as well)
++	;
++bn_sub_words_unroll2
++	LDD     0(a_ptr),t1
++	LDD     0(b_ptr),t2
++	SUB     t1,t2,sub_tmp1           ; t3 = t1-t2; 
++	SUB     sub_tmp1,%ret1,sub_tmp1  ; t3 = t3- c; 
++
++	CMPCLR,*>> t1,t2,sub_tmp2        ; clear if t1 > t2
++	LDO      1(%r0),sub_tmp2
++	
++	CMPCLR,*= t1,t2,%r0
++	COPY    sub_tmp2,%ret1
++	STD     sub_tmp1,0(r_ptr)
++
++	LDD     8(a_ptr),t1
++	LDD     8(b_ptr),t2
++	SUB     t1,t2,sub_tmp1            ; t3 = t1-t2; 
++	SUB     sub_tmp1,%ret1,sub_tmp1   ; t3 = t3- c; 
++	CMPCLR,*>> t1,t2,sub_tmp2         ; clear if t1 > t2
++	LDO      1(%r0),sub_tmp2
++	
++	CMPCLR,*= t1,t2,%r0
++	COPY    sub_tmp2,%ret1
++	STD     sub_tmp1,8(r_ptr)
++
++	LDO     -2(n),n
++	LDO     16(a_ptr),a_ptr
++	LDO     16(b_ptr),b_ptr
++
++	CMPIB,<= 2,n,bn_sub_words_unroll2
++	LDO     16(r_ptr),r_ptr
++
++    CMPIB,=,N 0,n,bn_sub_words_exit ; are we done?
++
++bn_sub_words_single_top
++	LDD     0(a_ptr),t1
++	LDD     0(b_ptr),t2
++	SUB     t1,t2,sub_tmp1            ; t3 = t1-t2; 
++	SUB     sub_tmp1,%ret1,sub_tmp1   ; t3 = t3- c; 
++	CMPCLR,*>> t1,t2,sub_tmp2         ; clear if t1 > t2
++	LDO      1(%r0),sub_tmp2
++	
++	CMPCLR,*= t1,t2,%r0
++	COPY    sub_tmp2,%ret1
++
++	STD     sub_tmp1,0(r_ptr)
++
++bn_sub_words_exit
++    .EXIT
++    BVE     (%rp)
++    EXTRD,U %ret1,31,32,%ret0           ; for 32-bit, return in ret0/ret1
++	.PROCEND	;in=23,24,25,26,29;out=28;
++
++;------------------------------------------------------------------------------
++;
++; unsigned long bn_div_words(unsigned long h, unsigned long l, unsigned long d)
++;
++; arg0 = h
++; arg1 = l
++; arg2 = d
++;
++; This is mainly just output from the HP C compiler.  
++;
++;------------------------------------------------------------------------------
++bn_div_words
++	.PROC
++	.EXPORT	bn_div_words,ENTRY,PRIV_LEV=3,ARGW0=GR,ARGW1=GR,ARGW2=GR,ARGW3=GR,RTNVAL=GR,LONG_RETURN
++	.IMPORT	BN_num_bits_word,CODE
++	;--- not PIC	.IMPORT	__iob,DATA
++	;--- not PIC	.IMPORT	fprintf,CODE
++	.IMPORT	abort,CODE
++	.IMPORT	$$div2U,MILLICODE
++	.CALLINFO CALLER,FRAME=144,ENTRY_GR=%r9,SAVE_RP,ARGS_SAVED,ORDERING_AWARE
++        .ENTRY
++        STW     %r2,-20(%r30)   ;offset 0x8ec
++        STW,MA  %r3,192(%r30)   ;offset 0x8f0
++        STW     %r4,-188(%r30)  ;offset 0x8f4
++        DEPD    %r5,31,32,%r6   ;offset 0x8f8
++        STD     %r6,-184(%r30)  ;offset 0x8fc
++        DEPD    %r7,31,32,%r8   ;offset 0x900
++        STD     %r8,-176(%r30)  ;offset 0x904
++        STW     %r9,-168(%r30)  ;offset 0x908
++        LDD     -248(%r30),%r3  ;offset 0x90c
++        COPY    %r26,%r4        ;offset 0x910
++        COPY    %r24,%r5        ;offset 0x914
++        DEPD    %r25,31,32,%r4  ;offset 0x918
++        CMPB,*<>        %r3,%r0,$0006000C       ;offset 0x91c
++        DEPD    %r23,31,32,%r5  ;offset 0x920
++        MOVIB,TR        -1,%r29,$00060002       ;offset 0x924
++        EXTRD,U %r29,31,32,%r28 ;offset 0x928
++$0006002A
++        LDO     -1(%r29),%r29   ;offset 0x92c
++        SUB     %r23,%r7,%r23   ;offset 0x930
++$00060024
++        SUB     %r4,%r31,%r25   ;offset 0x934
++        AND     %r25,%r19,%r26  ;offset 0x938
++        CMPB,*<>,N      %r0,%r26,$00060046      ;offset 0x93c
++        DEPD,Z  %r25,31,32,%r20 ;offset 0x940
++        OR      %r20,%r24,%r21  ;offset 0x944
++        CMPB,*<<,N      %r21,%r23,$0006002A     ;offset 0x948
++        SUB     %r31,%r2,%r31   ;offset 0x94c
++$00060046
++$0006002E
++        DEPD,Z  %r23,31,32,%r25 ;offset 0x950
++        EXTRD,U %r23,31,32,%r26 ;offset 0x954
++        AND     %r25,%r19,%r24  ;offset 0x958
++        ADD,L   %r31,%r26,%r31  ;offset 0x95c
++        CMPCLR,*>>=     %r5,%r24,%r0    ;offset 0x960
++        LDO     1(%r31),%r31    ;offset 0x964
++$00060032
++        CMPB,*<<=,N     %r31,%r4,$00060036      ;offset 0x968
++        LDO     -1(%r29),%r29   ;offset 0x96c
++        ADD,L   %r4,%r3,%r4     ;offset 0x970
++$00060036
++        ADDIB,=,N       -1,%r8,$D0      ;offset 0x974
++        SUB     %r5,%r24,%r28   ;offset 0x978
++$0006003A
++        SUB     %r4,%r31,%r24   ;offset 0x97c
++        SHRPD   %r24,%r28,32,%r4        ;offset 0x980
++        DEPD,Z  %r29,31,32,%r9  ;offset 0x984
++        DEPD,Z  %r28,31,32,%r5  ;offset 0x988
++$0006001C
++        EXTRD,U %r4,31,32,%r31  ;offset 0x98c
++        CMPB,*<>,N      %r31,%r2,$00060020      ;offset 0x990
++        MOVB,TR %r6,%r29,$D1    ;offset 0x994
++        STD     %r29,-152(%r30) ;offset 0x998
++$0006000C
++        EXTRD,U %r3,31,32,%r25  ;offset 0x99c
++        COPY    %r3,%r26        ;offset 0x9a0
++        EXTRD,U %r3,31,32,%r9   ;offset 0x9a4
++        EXTRD,U %r4,31,32,%r8   ;offset 0x9a8
++        .CALL   ARGW0=GR,ARGW1=GR,RTNVAL=GR     ;in=25,26;out=28;
++        B,L     BN_num_bits_word,%r2    ;offset 0x9ac
++        EXTRD,U %r5,31,32,%r7   ;offset 0x9b0
++        LDI     64,%r20 ;offset 0x9b4
++        DEPD    %r7,31,32,%r5   ;offset 0x9b8
++        DEPD    %r8,31,32,%r4   ;offset 0x9bc
++        DEPD    %r9,31,32,%r3   ;offset 0x9c0
++        CMPB,=  %r28,%r20,$00060012     ;offset 0x9c4
++        COPY    %r28,%r24       ;offset 0x9c8
++        MTSARCM %r24    ;offset 0x9cc
++        DEPDI,Z -1,%sar,1,%r19  ;offset 0x9d0
++        CMPB,*>>,N      %r4,%r19,$D2    ;offset 0x9d4
++$00060012
++        SUBI    64,%r24,%r31    ;offset 0x9d8
++        CMPCLR,*<<      %r4,%r3,%r0     ;offset 0x9dc
++        SUB     %r4,%r3,%r4     ;offset 0x9e0
++$00060016
++        CMPB,=  %r31,%r0,$0006001A      ;offset 0x9e4
++        COPY    %r0,%r9 ;offset 0x9e8
++        MTSARCM %r31    ;offset 0x9ec
++        DEPD,Z  %r3,%sar,64,%r3 ;offset 0x9f0
++        SUBI    64,%r31,%r26    ;offset 0x9f4
++        MTSAR   %r26    ;offset 0x9f8
++        SHRPD   %r4,%r5,%sar,%r4        ;offset 0x9fc
++        MTSARCM %r31    ;offset 0xa00
++        DEPD,Z  %r5,%sar,64,%r5 ;offset 0xa04
++$0006001A
++        DEPDI,Z -1,31,32,%r19   ;offset 0xa08
++        AND     %r3,%r19,%r29   ;offset 0xa0c
++        EXTRD,U %r29,31,32,%r2  ;offset 0xa10
++        DEPDI,Z -1,63,32,%r6    ;offset 0xa14
++        MOVIB,TR        2,%r8,$0006001C ;offset 0xa18
++        EXTRD,U %r3,63,32,%r7   ;offset 0xa1c
++$D2
++        ;--- not PIC	ADDIL   LR'__iob-$global$,%r27,%r1      ;offset 0xa20
++        ;--- not PIC	LDIL    LR'C$7,%r21     ;offset 0xa24
++        ;--- not PIC	LDO     RR'__iob-$global$+32(%r1),%r26  ;offset 0xa28
++        ;--- not PIC	.CALL   ARGW0=GR,ARGW1=GR,ARGW2=GR,RTNVAL=GR    ;in=24,25,26;out=28;
++        ;--- not PIC	B,L     fprintf,%r2     ;offset 0xa2c
++        ;--- not PIC	LDO     RR'C$7(%r21),%r25       ;offset 0xa30
++        .CALL           ;
++        B,L     abort,%r2       ;offset 0xa34
++        NOP             ;offset 0xa38
++        B       $D3     ;offset 0xa3c
++        LDW     -212(%r30),%r2  ;offset 0xa40
++$00060020
++        COPY    %r4,%r26        ;offset 0xa44
++        EXTRD,U %r4,31,32,%r25  ;offset 0xa48
++        COPY    %r2,%r24        ;offset 0xa4c
++        .CALL   ;in=23,24,25,26;out=20,21,22,28,29; (MILLICALL)
++        B,L     $$div2U,%r31    ;offset 0xa50
++        EXTRD,U %r2,31,32,%r23  ;offset 0xa54
++        DEPD    %r28,31,32,%r29 ;offset 0xa58
++$00060022
++        STD     %r29,-152(%r30) ;offset 0xa5c
++$D1
++        AND     %r5,%r19,%r24   ;offset 0xa60
++        EXTRD,U %r24,31,32,%r24 ;offset 0xa64
++        STW     %r2,-160(%r30)  ;offset 0xa68
++        STW     %r7,-128(%r30)  ;offset 0xa6c
++        FLDD    -152(%r30),%fr4 ;offset 0xa70
++        FLDD    -152(%r30),%fr7 ;offset 0xa74
++        FLDW    -160(%r30),%fr8L        ;offset 0xa78
++        FLDW    -128(%r30),%fr5L        ;offset 0xa7c
++        XMPYU   %fr8L,%fr7L,%fr10       ;offset 0xa80
++        FSTD    %fr10,-136(%r30)        ;offset 0xa84
++        XMPYU   %fr8L,%fr7R,%fr22       ;offset 0xa88
++        FSTD    %fr22,-144(%r30)        ;offset 0xa8c
++        XMPYU   %fr5L,%fr4L,%fr11       ;offset 0xa90
++        XMPYU   %fr5L,%fr4R,%fr23       ;offset 0xa94
++        FSTD    %fr11,-112(%r30)        ;offset 0xa98
++        FSTD    %fr23,-120(%r30)        ;offset 0xa9c
++        LDD     -136(%r30),%r28 ;offset 0xaa0
++        DEPD,Z  %r28,31,32,%r31 ;offset 0xaa4
++        LDD     -144(%r30),%r20 ;offset 0xaa8
++        ADD,L   %r20,%r31,%r31  ;offset 0xaac
++        LDD     -112(%r30),%r22 ;offset 0xab0
++        DEPD,Z  %r22,31,32,%r22 ;offset 0xab4
++        LDD     -120(%r30),%r21 ;offset 0xab8
++        B       $00060024       ;offset 0xabc
++        ADD,L   %r21,%r22,%r23  ;offset 0xac0
++$D0
++        OR      %r9,%r29,%r29   ;offset 0xac4
++$00060040
++        EXTRD,U %r29,31,32,%r28 ;offset 0xac8
++$00060002
++$L2
++        LDW     -212(%r30),%r2  ;offset 0xacc
++$D3
++        LDW     -168(%r30),%r9  ;offset 0xad0
++        LDD     -176(%r30),%r8  ;offset 0xad4
++        EXTRD,U %r8,31,32,%r7   ;offset 0xad8
++        LDD     -184(%r30),%r6  ;offset 0xadc
++        EXTRD,U %r6,31,32,%r5   ;offset 0xae0
++        LDW     -188(%r30),%r4  ;offset 0xae4
++        BVE     (%r2)   ;offset 0xae8
++        .EXIT
++        LDW,MB  -192(%r30),%r3  ;offset 0xaec
++	.PROCEND	;in=23,25;out=28,29;fpin=105,107;
++
++
++
++
++;----------------------------------------------------------------------------
++;
++; Registers to hold 64-bit values to manipulate.  The "L" part
++; of the register corresponds to the upper 32-bits, while the "R"
++; part corresponds to the lower 32-bits
++; 
++; Note, that when using b6 and b7, the code must save these before
++; using them because they are callee save registers 
++; 
++;
++; Floating point registers to use to save values that
++; are manipulated.  These don't collide with ftemp1-6 and
++; are all caller save registers
++;
++a0        .reg %fr22
++a0L       .reg %fr22L
++a0R       .reg %fr22R
++
++a1        .reg %fr23
++a1L       .reg %fr23L
++a1R       .reg %fr23R
++
++a2        .reg %fr24
++a2L       .reg %fr24L
++a2R       .reg %fr24R
++
++a3        .reg %fr25
++a3L       .reg %fr25L
++a3R       .reg %fr25R
++
++a4        .reg %fr26
++a4L       .reg %fr26L
++a4R       .reg %fr26R
++
++a5        .reg %fr27
++a5L       .reg %fr27L
++a5R       .reg %fr27R
++
++a6        .reg %fr28
++a6L       .reg %fr28L
++a6R       .reg %fr28R
++
++a7        .reg %fr29
++a7L       .reg %fr29L
++a7R       .reg %fr29R
++
++b0        .reg %fr30
++b0L       .reg %fr30L
++b0R       .reg %fr30R
++
++b1        .reg %fr31
++b1L       .reg %fr31L
++b1R       .reg %fr31R
++
++;
++; Temporary floating point variables, these are all caller save
++; registers
++;
++ftemp1    .reg %fr4
++ftemp2    .reg %fr5
++ftemp3    .reg %fr6
++ftemp4    .reg %fr7
++
++;
++; The B set of registers when used.
++;
++
++b2        .reg %fr8
++b2L       .reg %fr8L
++b2R       .reg %fr8R
++
++b3        .reg %fr9
++b3L       .reg %fr9L
++b3R       .reg %fr9R
++
++b4        .reg %fr10
++b4L       .reg %fr10L
++b4R       .reg %fr10R
++
++b5        .reg %fr11
++b5L       .reg %fr11L
++b5R       .reg %fr11R
++
++b6        .reg %fr12
++b6L       .reg %fr12L
++b6R       .reg %fr12R
++
++b7        .reg %fr13
++b7L       .reg %fr13L
++b7R       .reg %fr13R
++
++c1           .reg %r21   ; only reg
++temp1        .reg %r20   ; only reg
++temp2        .reg %r19   ; only reg
++temp3        .reg %r31   ; only reg
++
++m1           .reg %r28   
++c2           .reg %r23   
++high_one     .reg %r1
++ht           .reg %r6
++lt           .reg %r5
++m            .reg %r4
++c3           .reg %r3
++
++SQR_ADD_C  .macro  A0L,A0R,C1,C2,C3
++    XMPYU   A0L,A0R,ftemp1       ; m
++    FSTD    ftemp1,-24(%sp)      ; store m
++
++    XMPYU   A0R,A0R,ftemp2       ; lt
++    FSTD    ftemp2,-16(%sp)      ; store lt
++
++    XMPYU   A0L,A0L,ftemp3       ; ht
++    FSTD    ftemp3,-8(%sp)       ; store ht
++
++    LDD     -24(%sp),m           ; load m
++    AND     m,high_mask,temp2    ; m & Mask
++    DEPD,Z  m,30,31,temp3        ; m << 32+1
++    LDD     -16(%sp),lt          ; lt
++
++    LDD     -8(%sp),ht           ; ht
++    EXTRD,U temp2,32,33,temp1    ; temp1 = m&Mask >> 32-1
++    ADD     temp3,lt,lt          ; lt = lt+m
++    ADD,L   ht,temp1,ht          ; ht += temp1
++    ADD,DC  ht,%r0,ht            ; ht++
++
++    ADD     C1,lt,C1             ; c1=c1+lt
++    ADD,DC  ht,%r0,ht            ; ht++
++
++    ADD     C2,ht,C2             ; c2=c2+ht
++    ADD,DC  C3,%r0,C3            ; c3++
++.endm
++
++SQR_ADD_C2 .macro  A0L,A0R,A1L,A1R,C1,C2,C3
++    XMPYU   A0L,A1R,ftemp1          ; m1 = bl*ht
++    FSTD    ftemp1,-16(%sp)         ;
++    XMPYU   A0R,A1L,ftemp2          ; m = bh*lt
++    FSTD    ftemp2,-8(%sp)          ;
++    XMPYU   A0R,A1R,ftemp3          ; lt = bl*lt
++    FSTD    ftemp3,-32(%sp)
++    XMPYU   A0L,A1L,ftemp4          ; ht = bh*ht
++    FSTD    ftemp4,-24(%sp)         ;
++
++    LDD     -8(%sp),m               ; r21 = m
++    LDD     -16(%sp),m1             ; r19 = m1
++    ADD,L   m,m1,m                  ; m+m1
++
++    DEPD,Z  m,31,32,temp3           ; (m+m1<<32)
++    LDD     -24(%sp),ht             ; r24 = ht
++
++    CMPCLR,*>>= m,m1,%r0            ; if (m < m1)
++    ADD,L   ht,high_one,ht          ; ht+=high_one
++
++    EXTRD,U m,31,32,temp1           ; m >> 32
++    LDD     -32(%sp),lt             ; lt
++    ADD,L   ht,temp1,ht             ; ht+= m>>32
++    ADD     lt,temp3,lt             ; lt = lt+m1
++    ADD,DC  ht,%r0,ht               ; ht++
++
++    ADD     ht,ht,ht                ; ht=ht+ht;
++    ADD,DC  C3,%r0,C3               ; add in carry (c3++)
++
++    ADD     lt,lt,lt                ; lt=lt+lt;
++    ADD,DC  ht,%r0,ht               ; add in carry (ht++)
++
++    ADD     C1,lt,C1                ; c1=c1+lt
++    ADD,DC,*NUV ht,%r0,ht           ; add in carry (ht++)
++    LDO     1(C3),C3              ; bump c3 if overflow,nullify otherwise
++
++    ADD     C2,ht,C2                ; c2 = c2 + ht
++    ADD,DC  C3,%r0,C3             ; add in carry (c3++)
++.endm
++
++;
++;void bn_sqr_comba8(BN_ULONG *r, BN_ULONG *a)
++; arg0 = r_ptr
++; arg1 = a_ptr
++;
++
++bn_sqr_comba8
++	.PROC
++	.CALLINFO FRAME=128,ENTRY_GR=%r3,ARGS_SAVED,ORDERING_AWARE
++	.EXPORT	bn_sqr_comba8,ENTRY,PRIV_LEV=3,NO_RELOCATION,LONG_RETURN
++    .ENTRY
++	.align 64
++
++    STD     %r3,0(%sp)          ; save r3
++    STD     %r4,8(%sp)          ; save r4
++    STD     %r5,16(%sp)         ; save r5
++    STD     %r6,24(%sp)         ; save r6
++
++	;
++	; Zero out carries
++	;
++	COPY     %r0,c1
++	COPY     %r0,c2
++	COPY     %r0,c3
++
++	LDO      128(%sp),%sp       ; bump stack
++    DEPDI,Z -1,32,33,high_mask   ; Create Mask 0xffffffff80000000L
++    DEPDI,Z  1,31,1,high_one     ; Create Value  1 << 32
++
++	;
++	; Load up all of the values we are going to use
++	;
++    FLDD     0(a_ptr),a0       
++    FLDD     8(a_ptr),a1       
++    FLDD    16(a_ptr),a2       
++    FLDD    24(a_ptr),a3       
++    FLDD    32(a_ptr),a4       
++    FLDD    40(a_ptr),a5       
++    FLDD    48(a_ptr),a6       
++    FLDD    56(a_ptr),a7       
++
++	SQR_ADD_C a0L,a0R,c1,c2,c3
++	STD     c1,0(r_ptr)          ; r[0] = c1;
++	COPY    %r0,c1
++
++	SQR_ADD_C2 a1L,a1R,a0L,a0R,c2,c3,c1
++	STD     c2,8(r_ptr)          ; r[1] = c2;
++	COPY    %r0,c2
++
++	SQR_ADD_C a1L,a1R,c3,c1,c2
++	SQR_ADD_C2 a2L,a2R,a0L,a0R,c3,c1,c2
++	STD     c3,16(r_ptr)            ; r[2] = c3;
++	COPY    %r0,c3
++
++	SQR_ADD_C2 a3L,a3R,a0L,a0R,c1,c2,c3
++	SQR_ADD_C2 a2L,a2R,a1L,a1R,c1,c2,c3
++	STD     c1,24(r_ptr)           ; r[3] = c1;
++	COPY    %r0,c1
++
++	SQR_ADD_C a2L,a2R,c2,c3,c1
++	SQR_ADD_C2 a3L,a3R,a1L,a1R,c2,c3,c1
++	SQR_ADD_C2 a4L,a4R,a0L,a0R,c2,c3,c1
++	STD     c2,32(r_ptr)          ; r[4] = c2;
++	COPY    %r0,c2
++
++	SQR_ADD_C2 a5L,a5R,a0L,a0R,c3,c1,c2
++	SQR_ADD_C2 a4L,a4R,a1L,a1R,c3,c1,c2
++	SQR_ADD_C2 a3L,a3R,a2L,a2R,c3,c1,c2
++	STD     c3,40(r_ptr)          ; r[5] = c3;
++	COPY    %r0,c3
++
++	SQR_ADD_C a3L,a3R,c1,c2,c3
++	SQR_ADD_C2 a4L,a4R,a2L,a2R,c1,c2,c3
++	SQR_ADD_C2 a5L,a5R,a1L,a1R,c1,c2,c3
++	SQR_ADD_C2 a6L,a6R,a0L,a0R,c1,c2,c3
++	STD     c1,48(r_ptr)          ; r[6] = c1;
++	COPY    %r0,c1
++
++	SQR_ADD_C2 a7L,a7R,a0L,a0R,c2,c3,c1
++	SQR_ADD_C2 a6L,a6R,a1L,a1R,c2,c3,c1
++	SQR_ADD_C2 a5L,a5R,a2L,a2R,c2,c3,c1
++	SQR_ADD_C2 a4L,a4R,a3L,a3R,c2,c3,c1
++	STD     c2,56(r_ptr)          ; r[7] = c2;
++	COPY    %r0,c2
++
++	SQR_ADD_C a4L,a4R,c3,c1,c2
++	SQR_ADD_C2 a5L,a5R,a3L,a3R,c3,c1,c2
++	SQR_ADD_C2 a6L,a6R,a2L,a2R,c3,c1,c2
++	SQR_ADD_C2 a7L,a7R,a1L,a1R,c3,c1,c2
++	STD     c3,64(r_ptr)          ; r[8] = c3;
++	COPY    %r0,c3
++
++	SQR_ADD_C2 a7L,a7R,a2L,a2R,c1,c2,c3
++	SQR_ADD_C2 a6L,a6R,a3L,a3R,c1,c2,c3
++	SQR_ADD_C2 a5L,a5R,a4L,a4R,c1,c2,c3
++	STD     c1,72(r_ptr)          ; r[9] = c1;
++	COPY    %r0,c1
++
++	SQR_ADD_C a5L,a5R,c2,c3,c1
++	SQR_ADD_C2 a6L,a6R,a4L,a4R,c2,c3,c1
++	SQR_ADD_C2 a7L,a7R,a3L,a3R,c2,c3,c1
++	STD     c2,80(r_ptr)          ; r[10] = c2;
++	COPY    %r0,c2
++
++	SQR_ADD_C2 a7L,a7R,a4L,a4R,c3,c1,c2
++	SQR_ADD_C2 a6L,a6R,a5L,a5R,c3,c1,c2
++	STD     c3,88(r_ptr)          ; r[11] = c3;
++	COPY    %r0,c3
++	
++	SQR_ADD_C a6L,a6R,c1,c2,c3
++	SQR_ADD_C2 a7L,a7R,a5L,a5R,c1,c2,c3
++	STD     c1,96(r_ptr)          ; r[12] = c1;
++	COPY    %r0,c1
++
++	SQR_ADD_C2 a7L,a7R,a6L,a6R,c2,c3,c1
++	STD     c2,104(r_ptr)         ; r[13] = c2;
++	COPY    %r0,c2
++
++	SQR_ADD_C a7L,a7R,c3,c1,c2
++	STD     c3, 112(r_ptr)       ; r[14] = c3
++	STD     c1, 120(r_ptr)       ; r[15] = c1
++
++    .EXIT
++    LDD     -104(%sp),%r6        ; restore r6
++    LDD     -112(%sp),%r5        ; restore r5
++    LDD     -120(%sp),%r4        ; restore r4
++    BVE     (%rp)
++    LDD,MB  -128(%sp),%r3
++
++	.PROCEND	
++
++;-----------------------------------------------------------------------------
++;
++;void bn_sqr_comba4(BN_ULONG *r, BN_ULONG *a)
++; arg0 = r_ptr
++; arg1 = a_ptr
++;
++
++bn_sqr_comba4
++	.proc
++	.callinfo FRAME=128,ENTRY_GR=%r3,ARGS_SAVED,ORDERING_AWARE
++	.EXPORT	bn_sqr_comba4,ENTRY,PRIV_LEV=3,NO_RELOCATION,LONG_RETURN
++    .entry
++	.align 64
++    STD     %r3,0(%sp)          ; save r3
++    STD     %r4,8(%sp)          ; save r4
++    STD     %r5,16(%sp)         ; save r5
++    STD     %r6,24(%sp)         ; save r6
++
++	;
++	; Zero out carries
++	;
++	COPY     %r0,c1
++	COPY     %r0,c2
++	COPY     %r0,c3
++
++	LDO      128(%sp),%sp       ; bump stack
++    DEPDI,Z -1,32,33,high_mask   ; Create Mask 0xffffffff80000000L
++    DEPDI,Z  1,31,1,high_one     ; Create Value  1 << 32
++
++	;
++	; Load up all of the values we are going to use
++	;
++    FLDD     0(a_ptr),a0       
++    FLDD     8(a_ptr),a1       
++    FLDD    16(a_ptr),a2       
++    FLDD    24(a_ptr),a3       
++    FLDD    32(a_ptr),a4       
++    FLDD    40(a_ptr),a5       
++    FLDD    48(a_ptr),a6       
++    FLDD    56(a_ptr),a7       
++
++	SQR_ADD_C a0L,a0R,c1,c2,c3
++
++	STD     c1,0(r_ptr)          ; r[0] = c1;
++	COPY    %r0,c1
++
++	SQR_ADD_C2 a1L,a1R,a0L,a0R,c2,c3,c1
++
++	STD     c2,8(r_ptr)          ; r[1] = c2;
++	COPY    %r0,c2
++
++	SQR_ADD_C a1L,a1R,c3,c1,c2
++	SQR_ADD_C2 a2L,a2R,a0L,a0R,c3,c1,c2
++
++	STD     c3,16(r_ptr)            ; r[2] = c3;
++	COPY    %r0,c3
++
++	SQR_ADD_C2 a3L,a3R,a0L,a0R,c1,c2,c3
++	SQR_ADD_C2 a2L,a2R,a1L,a1R,c1,c2,c3
++
++	STD     c1,24(r_ptr)           ; r[3] = c1;
++	COPY    %r0,c1
++
++	SQR_ADD_C a2L,a2R,c2,c3,c1
++	SQR_ADD_C2 a3L,a3R,a1L,a1R,c2,c3,c1
++
++	STD     c2,32(r_ptr)           ; r[4] = c2;
++	COPY    %r0,c2
++
++	SQR_ADD_C2 a3L,a3R,a2L,a2R,c3,c1,c2
++	STD     c3,40(r_ptr)           ; r[5] = c3;
++	COPY    %r0,c3
++
++	SQR_ADD_C a3L,a3R,c1,c2,c3
++	STD     c1,48(r_ptr)           ; r[6] = c1;
++	STD     c2,56(r_ptr)           ; r[7] = c2;
++
++    .EXIT
++    LDD     -104(%sp),%r6        ; restore r6
++    LDD     -112(%sp),%r5        ; restore r5
++    LDD     -120(%sp),%r4        ; restore r4
++    BVE     (%rp)
++    LDD,MB  -128(%sp),%r3
++
++	.PROCEND	
++
++
++;---------------------------------------------------------------------------
++
++MUL_ADD_C  .macro  A0L,A0R,B0L,B0R,C1,C2,C3
++    XMPYU   A0L,B0R,ftemp1        ; m1 = bl*ht
++    FSTD    ftemp1,-16(%sp)       ;
++    XMPYU   A0R,B0L,ftemp2        ; m = bh*lt
++    FSTD    ftemp2,-8(%sp)        ;
++    XMPYU   A0R,B0R,ftemp3        ; lt = bl*lt
++    FSTD    ftemp3,-32(%sp)
++    XMPYU   A0L,B0L,ftemp4        ; ht = bh*ht
++    FSTD    ftemp4,-24(%sp)       ;
++
++    LDD     -8(%sp),m             ; r21 = m
++    LDD     -16(%sp),m1           ; r19 = m1
++    ADD,L   m,m1,m                ; m+m1
++
++    DEPD,Z  m,31,32,temp3         ; (m+m1<<32)
++    LDD     -24(%sp),ht           ; r24 = ht
++
++    CMPCLR,*>>= m,m1,%r0          ; if (m < m1)
++    ADD,L   ht,high_one,ht        ; ht+=high_one
++
++    EXTRD,U m,31,32,temp1         ; m >> 32
++    LDD     -32(%sp),lt           ; lt
++    ADD,L   ht,temp1,ht           ; ht+= m>>32
++    ADD     lt,temp3,lt           ; lt = lt+m1
++    ADD,DC  ht,%r0,ht             ; ht++
++
++    ADD     C1,lt,C1              ; c1=c1+lt
++    ADD,DC  ht,%r0,ht             ; bump c3 if overflow,nullify otherwise
++
++    ADD     C2,ht,C2              ; c2 = c2 + ht
++    ADD,DC  C3,%r0,C3             ; add in carry (c3++)
++.endm
++
++
++;
++;void bn_mul_comba8(BN_ULONG *r, BN_ULONG *a, BN_ULONG *b)
++; arg0 = r_ptr
++; arg1 = a_ptr
++; arg2 = b_ptr
++;
++
++bn_mul_comba8
++	.proc
++	.callinfo FRAME=128,ENTRY_GR=%r3,ARGS_SAVED,ORDERING_AWARE
++	.EXPORT	bn_mul_comba8,ENTRY,PRIV_LEV=3,NO_RELOCATION,LONG_RETURN
++    .entry
++	.align 64
++
++    STD     %r3,0(%sp)          ; save r3
++    STD     %r4,8(%sp)          ; save r4
++    STD     %r5,16(%sp)         ; save r5
++    STD     %r6,24(%sp)         ; save r6
++    FSTD    %fr12,32(%sp)       ; save r6
++    FSTD    %fr13,40(%sp)       ; save r7
++
++	;
++	; Zero out carries
++	;
++	COPY     %r0,c1
++	COPY     %r0,c2
++	COPY     %r0,c3
++
++	LDO      128(%sp),%sp       ; bump stack
++    DEPDI,Z  1,31,1,high_one     ; Create Value  1 << 32
++
++	;
++	; Load up all of the values we are going to use
++	;
++    FLDD      0(a_ptr),a0       
++    FLDD      8(a_ptr),a1       
++    FLDD     16(a_ptr),a2       
++    FLDD     24(a_ptr),a3       
++    FLDD     32(a_ptr),a4       
++    FLDD     40(a_ptr),a5       
++    FLDD     48(a_ptr),a6       
++    FLDD     56(a_ptr),a7       
++
++    FLDD      0(b_ptr),b0       
++    FLDD      8(b_ptr),b1       
++    FLDD     16(b_ptr),b2       
++    FLDD     24(b_ptr),b3       
++    FLDD     32(b_ptr),b4       
++    FLDD     40(b_ptr),b5       
++    FLDD     48(b_ptr),b6       
++    FLDD     56(b_ptr),b7       
++
++	MUL_ADD_C a0L,a0R,b0L,b0R,c1,c2,c3
++	STD       c1,0(r_ptr)
++	COPY      %r0,c1
++
++	MUL_ADD_C a0L,a0R,b1L,b1R,c2,c3,c1
++	MUL_ADD_C a1L,a1R,b0L,b0R,c2,c3,c1
++	STD       c2,8(r_ptr)
++	COPY      %r0,c2
++
++	MUL_ADD_C a2L,a2R,b0L,b0R,c3,c1,c2
++	MUL_ADD_C a1L,a1R,b1L,b1R,c3,c1,c2
++	MUL_ADD_C a0L,a0R,b2L,b2R,c3,c1,c2
++	STD       c3,16(r_ptr)
++	COPY      %r0,c3
++
++	MUL_ADD_C a0L,a0R,b3L,b3R,c1,c2,c3
++	MUL_ADD_C a1L,a1R,b2L,b2R,c1,c2,c3
++	MUL_ADD_C a2L,a2R,b1L,b1R,c1,c2,c3
++	MUL_ADD_C a3L,a3R,b0L,b0R,c1,c2,c3
++	STD       c1,24(r_ptr)
++	COPY      %r0,c1
++
++	MUL_ADD_C a4L,a4R,b0L,b0R,c2,c3,c1
++	MUL_ADD_C a3L,a3R,b1L,b1R,c2,c3,c1
++	MUL_ADD_C a2L,a2R,b2L,b2R,c2,c3,c1
++	MUL_ADD_C a1L,a1R,b3L,b3R,c2,c3,c1
++	MUL_ADD_C a0L,a0R,b4L,b4R,c2,c3,c1
++	STD       c2,32(r_ptr)
++	COPY      %r0,c2
++
++	MUL_ADD_C a0L,a0R,b5L,b5R,c3,c1,c2
++	MUL_ADD_C a1L,a1R,b4L,b4R,c3,c1,c2
++	MUL_ADD_C a2L,a2R,b3L,b3R,c3,c1,c2
++	MUL_ADD_C a3L,a3R,b2L,b2R,c3,c1,c2
++	MUL_ADD_C a4L,a4R,b1L,b1R,c3,c1,c2
++	MUL_ADD_C a5L,a5R,b0L,b0R,c3,c1,c2
++	STD       c3,40(r_ptr)
++	COPY      %r0,c3
++
++	MUL_ADD_C a6L,a6R,b0L,b0R,c1,c2,c3
++	MUL_ADD_C a5L,a5R,b1L,b1R,c1,c2,c3
++	MUL_ADD_C a4L,a4R,b2L,b2R,c1,c2,c3
++	MUL_ADD_C a3L,a3R,b3L,b3R,c1,c2,c3
++	MUL_ADD_C a2L,a2R,b4L,b4R,c1,c2,c3
++	MUL_ADD_C a1L,a1R,b5L,b5R,c1,c2,c3
++	MUL_ADD_C a0L,a0R,b6L,b6R,c1,c2,c3
++	STD       c1,48(r_ptr)
++	COPY      %r0,c1
++	
++	MUL_ADD_C a0L,a0R,b7L,b7R,c2,c3,c1
++	MUL_ADD_C a1L,a1R,b6L,b6R,c2,c3,c1
++	MUL_ADD_C a2L,a2R,b5L,b5R,c2,c3,c1
++	MUL_ADD_C a3L,a3R,b4L,b4R,c2,c3,c1
++	MUL_ADD_C a4L,a4R,b3L,b3R,c2,c3,c1
++	MUL_ADD_C a5L,a5R,b2L,b2R,c2,c3,c1
++	MUL_ADD_C a6L,a6R,b1L,b1R,c2,c3,c1
++	MUL_ADD_C a7L,a7R,b0L,b0R,c2,c3,c1
++	STD       c2,56(r_ptr)
++	COPY      %r0,c2
++
++	MUL_ADD_C a7L,a7R,b1L,b1R,c3,c1,c2
++	MUL_ADD_C a6L,a6R,b2L,b2R,c3,c1,c2
++	MUL_ADD_C a5L,a5R,b3L,b3R,c3,c1,c2
++	MUL_ADD_C a4L,a4R,b4L,b4R,c3,c1,c2
++	MUL_ADD_C a3L,a3R,b5L,b5R,c3,c1,c2
++	MUL_ADD_C a2L,a2R,b6L,b6R,c3,c1,c2
++	MUL_ADD_C a1L,a1R,b7L,b7R,c3,c1,c2
++	STD       c3,64(r_ptr)
++	COPY      %r0,c3
++
++	MUL_ADD_C a2L,a2R,b7L,b7R,c1,c2,c3
++	MUL_ADD_C a3L,a3R,b6L,b6R,c1,c2,c3
++	MUL_ADD_C a4L,a4R,b5L,b5R,c1,c2,c3
++	MUL_ADD_C a5L,a5R,b4L,b4R,c1,c2,c3
++	MUL_ADD_C a6L,a6R,b3L,b3R,c1,c2,c3
++	MUL_ADD_C a7L,a7R,b2L,b2R,c1,c2,c3
++	STD       c1,72(r_ptr)
++	COPY      %r0,c1
++
++	MUL_ADD_C a7L,a7R,b3L,b3R,c2,c3,c1
++	MUL_ADD_C a6L,a6R,b4L,b4R,c2,c3,c1
++	MUL_ADD_C a5L,a5R,b5L,b5R,c2,c3,c1
++	MUL_ADD_C a4L,a4R,b6L,b6R,c2,c3,c1
++	MUL_ADD_C a3L,a3R,b7L,b7R,c2,c3,c1
++	STD       c2,80(r_ptr)
++	COPY      %r0,c2
++
++	MUL_ADD_C a4L,a4R,b7L,b7R,c3,c1,c2
++	MUL_ADD_C a5L,a5R,b6L,b6R,c3,c1,c2
++	MUL_ADD_C a6L,a6R,b5L,b5R,c3,c1,c2
++	MUL_ADD_C a7L,a7R,b4L,b4R,c3,c1,c2
++	STD       c3,88(r_ptr)
++	COPY      %r0,c3
++
++	MUL_ADD_C a7L,a7R,b5L,b5R,c1,c2,c3
++	MUL_ADD_C a6L,a6R,b6L,b6R,c1,c2,c3
++	MUL_ADD_C a5L,a5R,b7L,b7R,c1,c2,c3
++	STD       c1,96(r_ptr)
++	COPY      %r0,c1
++
++	MUL_ADD_C a6L,a6R,b7L,b7R,c2,c3,c1
++	MUL_ADD_C a7L,a7R,b6L,b6R,c2,c3,c1
++	STD       c2,104(r_ptr)
++	COPY      %r0,c2
++
++	MUL_ADD_C a7L,a7R,b7L,b7R,c3,c1,c2
++	STD       c3,112(r_ptr)
++	STD       c1,120(r_ptr)
++
++    .EXIT
++    FLDD    -88(%sp),%fr13 
++    FLDD    -96(%sp),%fr12 
++    LDD     -104(%sp),%r6        ; restore r6
++    LDD     -112(%sp),%r5        ; restore r5
++    LDD     -120(%sp),%r4        ; restore r4
++    BVE     (%rp)
++    LDD,MB  -128(%sp),%r3
++
++	.PROCEND	
++
++;-----------------------------------------------------------------------------
++;
++;void bn_mul_comba4(BN_ULONG *r, BN_ULONG *a, BN_ULONG *b)
++; arg0 = r_ptr
++; arg1 = a_ptr
++; arg2 = b_ptr
++;
++
++bn_mul_comba4
++	.proc
++	.callinfo FRAME=128,ENTRY_GR=%r3,ARGS_SAVED,ORDERING_AWARE
++	.EXPORT	bn_mul_comba4,ENTRY,PRIV_LEV=3,NO_RELOCATION,LONG_RETURN
++    .entry
++	.align 64
++
++    STD     %r3,0(%sp)          ; save r3
++    STD     %r4,8(%sp)          ; save r4
++    STD     %r5,16(%sp)         ; save r5
++    STD     %r6,24(%sp)         ; save r6
++    FSTD    %fr12,32(%sp)       ; save r6
++    FSTD    %fr13,40(%sp)       ; save r7
++
++	;
++	; Zero out carries
++	;
++	COPY     %r0,c1
++	COPY     %r0,c2
++	COPY     %r0,c3
++
++	LDO      128(%sp),%sp       ; bump stack
++    DEPDI,Z  1,31,1,high_one     ; Create Value  1 << 32
++
++	;
++	; Load up all of the values we are going to use
++	;
++    FLDD      0(a_ptr),a0       
++    FLDD      8(a_ptr),a1       
++    FLDD     16(a_ptr),a2       
++    FLDD     24(a_ptr),a3       
++
++    FLDD      0(b_ptr),b0       
++    FLDD      8(b_ptr),b1       
++    FLDD     16(b_ptr),b2       
++    FLDD     24(b_ptr),b3       
++
++	MUL_ADD_C a0L,a0R,b0L,b0R,c1,c2,c3
++	STD       c1,0(r_ptr)
++	COPY      %r0,c1
++
++	MUL_ADD_C a0L,a0R,b1L,b1R,c2,c3,c1
++	MUL_ADD_C a1L,a1R,b0L,b0R,c2,c3,c1
++	STD       c2,8(r_ptr)
++	COPY      %r0,c2
++
++	MUL_ADD_C a2L,a2R,b0L,b0R,c3,c1,c2
++	MUL_ADD_C a1L,a1R,b1L,b1R,c3,c1,c2
++	MUL_ADD_C a0L,a0R,b2L,b2R,c3,c1,c2
++	STD       c3,16(r_ptr)
++	COPY      %r0,c3
++
++	MUL_ADD_C a0L,a0R,b3L,b3R,c1,c2,c3
++	MUL_ADD_C a1L,a1R,b2L,b2R,c1,c2,c3
++	MUL_ADD_C a2L,a2R,b1L,b1R,c1,c2,c3
++	MUL_ADD_C a3L,a3R,b0L,b0R,c1,c2,c3
++	STD       c1,24(r_ptr)
++	COPY      %r0,c1
++
++	MUL_ADD_C a3L,a3R,b1L,b1R,c2,c3,c1
++	MUL_ADD_C a2L,a2R,b2L,b2R,c2,c3,c1
++	MUL_ADD_C a1L,a1R,b3L,b3R,c2,c3,c1
++	STD       c2,32(r_ptr)
++	COPY      %r0,c2
++
++	MUL_ADD_C a2L,a2R,b3L,b3R,c3,c1,c2
++	MUL_ADD_C a3L,a3R,b2L,b2R,c3,c1,c2
++	STD       c3,40(r_ptr)
++	COPY      %r0,c3
++
++	MUL_ADD_C a3L,a3R,b3L,b3R,c1,c2,c3
++	STD       c1,48(r_ptr)
++	STD       c2,56(r_ptr)
++
++    .EXIT
++    FLDD    -88(%sp),%fr13 
++    FLDD    -96(%sp),%fr12 
++    LDD     -104(%sp),%r6        ; restore r6
++    LDD     -112(%sp),%r5        ; restore r5
++    LDD     -120(%sp),%r4        ; restore r4
++    BVE     (%rp)
++    LDD,MB  -128(%sp),%r3
++
++	.PROCEND	
++
++
++;--- not PIC	.SPACE	$TEXT$
++;--- not PIC	.SUBSPA	$CODE$
++;--- not PIC	.SPACE	$PRIVATE$,SORT=16
++;--- not PIC	.IMPORT	$global$,DATA
++;--- not PIC	.SPACE	$TEXT$
++;--- not PIC	.SUBSPA	$CODE$
++;--- not PIC	.SUBSPA	$LIT$,ACCESS=0x2c
++;--- not PIC	C$7
++;--- not PIC	.ALIGN	8
++;--- not PIC	.STRINGZ	"Division would overflow (%d)\n"
++	.END
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/bn/asm/pa-risc2W.s b/CryptoPkg/Library/OpensslLib/openssl/crypto/bn/asm/pa-risc2W.s
+new file mode 100644
+index 0000000..9738117
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/bn/asm/pa-risc2W.s
+@@ -0,0 +1,1612 @@
++; Copyright 2000-2016 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
++; in the file LICENSE in the source distribution or at
++; https://www.openssl.org/source/license.html
++
++;
++; PA-RISC 64-bit implementation of bn_asm code
++;
++; This code is approximately 2x faster than the C version
++; for RSA/DSA.
++;
++; See http://devresource.hp.com/  for more details on the PA-RISC
++; architecture.  Also see the book "PA-RISC 2.0 Architecture"
++; by Gerry Kane for information on the instruction set architecture.
++;
++; Code written by Chris Ruemmler (with some help from the HP C
++; compiler).
++;
++; The code compiles with HP's assembler
++;
++
++	.level	2.0W
++	.space	$TEXT$
++	.subspa	$CODE$,QUAD=0,ALIGN=8,ACCESS=0x2c,CODE_ONLY
++
++;
++; Global Register definitions used for the routines.
++;
++; Some information about HP's runtime architecture for 64-bits.
++;
++; "Caller save" means the calling function must save the register
++; if it wants the register to be preserved.
++; "Callee save" means if a function uses the register, it must save
++; the value before using it.
++;
++; For the floating point registers 
++;
++;    "caller save" registers: fr4-fr11, fr22-fr31
++;    "callee save" registers: fr12-fr21
++;    "special" registers: fr0-fr3 (status and exception registers)
++;
++; For the integer registers
++;     value zero             :  r0
++;     "caller save" registers: r1,r19-r26
++;     "callee save" registers: r3-r18
++;     return register        :  r2  (rp)
++;     return values          ; r28  (ret0,ret1)
++;     Stack pointer          ; r30  (sp) 
++;     global data pointer    ; r27  (dp)
++;     argument pointer       ; r29  (ap)
++;     millicode return ptr   ; r31  (also a caller save register)
++
++
++;
++; Arguments to the routines
++;
++r_ptr       .reg %r26
++a_ptr       .reg %r25
++b_ptr       .reg %r24
++num         .reg %r24
++w           .reg %r23
++n           .reg %r23
++
++
++;
++; Globals used in some routines
++;
++
++top_overflow .reg %r29
++high_mask    .reg %r22    ; value 0xffffffff80000000L
++
++
++;------------------------------------------------------------------------------
++;
++; bn_mul_add_words
++;
++;BN_ULONG bn_mul_add_words(BN_ULONG *r_ptr, BN_ULONG *a_ptr, 
++;								int num, BN_ULONG w)
++;
++; arg0 = r_ptr
++; arg1 = a_ptr
++; arg2 = num
++; arg3 = w
++;
++; Local register definitions
++;
++
++fm1          .reg %fr22
++fm           .reg %fr23
++ht_temp      .reg %fr24
++ht_temp_1    .reg %fr25
++lt_temp      .reg %fr26
++lt_temp_1    .reg %fr27
++fm1_1        .reg %fr28
++fm_1         .reg %fr29
++
++fw_h         .reg %fr7L
++fw_l         .reg %fr7R
++fw           .reg %fr7
++
++fht_0        .reg %fr8L
++flt_0        .reg %fr8R
++t_float_0    .reg %fr8
++
++fht_1        .reg %fr9L
++flt_1        .reg %fr9R
++t_float_1    .reg %fr9
++
++tmp_0        .reg %r31
++tmp_1        .reg %r21
++m_0          .reg %r20 
++m_1          .reg %r19 
++ht_0         .reg %r1  
++ht_1         .reg %r3
++lt_0         .reg %r4
++lt_1         .reg %r5
++m1_0         .reg %r6 
++m1_1         .reg %r7 
++rp_val       .reg %r8
++rp_val_1     .reg %r9
++
++bn_mul_add_words
++	.export	bn_mul_add_words,entry,NO_RELOCATION,LONG_RETURN
++	.proc
++	.callinfo frame=128
++    .entry
++	.align 64
++
++    STD     %r3,0(%sp)          ; save r3  
++    STD     %r4,8(%sp)          ; save r4  
++	NOP                         ; Needed to make the loop 16-byte aligned
++	NOP                         ; Needed to make the loop 16-byte aligned
++
++    STD     %r5,16(%sp)         ; save r5  
++    STD     %r6,24(%sp)         ; save r6  
++    STD     %r7,32(%sp)         ; save r7  
++    STD     %r8,40(%sp)         ; save r8  
++
++    STD     %r9,48(%sp)         ; save r9  
++    COPY    %r0,%ret0           ; return 0 by default
++    DEPDI,Z 1,31,1,top_overflow ; top_overflow = 1 << 32    
++	STD     w,56(%sp)           ; store w on stack
++
++    CMPIB,>= 0,num,bn_mul_add_words_exit  ; if (num <= 0) then exit
++	LDO     128(%sp),%sp       ; bump stack
++
++	;
++	; The loop is unrolled twice, so if there is only 1 number
++    ; then go straight to the cleanup code.
++	;
++	CMPIB,= 1,num,bn_mul_add_words_single_top
++	FLDD    -72(%sp),fw     ; load up w into fp register fw (fw_h/fw_l)
++
++	;
++	; This loop is unrolled 2 times (64-byte aligned as well)
++	;
++	; PA-RISC 2.0 chips have two fully pipelined multipliers, thus
++    ; two 32-bit mutiplies can be issued per cycle.
++    ; 
++bn_mul_add_words_unroll2
++
++    FLDD    0(a_ptr),t_float_0       ; load up 64-bit value (fr8L) ht(L)/lt(R)
++    FLDD    8(a_ptr),t_float_1       ; load up 64-bit value (fr8L) ht(L)/lt(R)
++    LDD     0(r_ptr),rp_val          ; rp[0]
++    LDD     8(r_ptr),rp_val_1        ; rp[1]
++
++    XMPYU   fht_0,fw_l,fm1           ; m1[0] = fht_0*fw_l
++    XMPYU   fht_1,fw_l,fm1_1         ; m1[1] = fht_1*fw_l
++    FSTD    fm1,-16(%sp)             ; -16(sp) = m1[0]
++    FSTD    fm1_1,-48(%sp)           ; -48(sp) = m1[1]
++
++    XMPYU   flt_0,fw_h,fm            ; m[0] = flt_0*fw_h
++    XMPYU   flt_1,fw_h,fm_1          ; m[1] = flt_1*fw_h
++    FSTD    fm,-8(%sp)               ; -8(sp) = m[0]
++    FSTD    fm_1,-40(%sp)            ; -40(sp) = m[1]
++
++    XMPYU   fht_0,fw_h,ht_temp       ; ht_temp   = fht_0*fw_h
++    XMPYU   fht_1,fw_h,ht_temp_1     ; ht_temp_1 = fht_1*fw_h
++    FSTD    ht_temp,-24(%sp)         ; -24(sp)   = ht_temp
++    FSTD    ht_temp_1,-56(%sp)       ; -56(sp)   = ht_temp_1
++
++    XMPYU   flt_0,fw_l,lt_temp       ; lt_temp = lt*fw_l
++    XMPYU   flt_1,fw_l,lt_temp_1     ; lt_temp = lt*fw_l
++    FSTD    lt_temp,-32(%sp)         ; -32(sp) = lt_temp 
++    FSTD    lt_temp_1,-64(%sp)       ; -64(sp) = lt_temp_1 
++
++    LDD     -8(%sp),m_0              ; m[0] 
++    LDD     -40(%sp),m_1             ; m[1]
++    LDD     -16(%sp),m1_0            ; m1[0]
++    LDD     -48(%sp),m1_1            ; m1[1]
++
++    LDD     -24(%sp),ht_0            ; ht[0]
++    LDD     -56(%sp),ht_1            ; ht[1]
++    ADD,L   m1_0,m_0,tmp_0           ; tmp_0 = m[0] + m1[0]; 
++    ADD,L   m1_1,m_1,tmp_1           ; tmp_1 = m[1] + m1[1]; 
++
++    LDD     -32(%sp),lt_0            
++    LDD     -64(%sp),lt_1            
++    CMPCLR,*>>= tmp_0,m1_0, %r0      ; if (m[0] < m1[0])
++    ADD,L   ht_0,top_overflow,ht_0   ; ht[0] += (1<<32)
++
++    CMPCLR,*>>= tmp_1,m1_1,%r0       ; if (m[1] < m1[1])
++    ADD,L   ht_1,top_overflow,ht_1   ; ht[1] += (1<<32)
++    EXTRD,U tmp_0,31,32,m_0          ; m[0]>>32  
++    DEPD,Z  tmp_0,31,32,m1_0         ; m1[0] = m[0]<<32 
++
++    EXTRD,U tmp_1,31,32,m_1          ; m[1]>>32  
++    DEPD,Z  tmp_1,31,32,m1_1         ; m1[1] = m[1]<<32 
++    ADD,L   ht_0,m_0,ht_0            ; ht[0]+= (m[0]>>32)
++    ADD,L   ht_1,m_1,ht_1            ; ht[1]+= (m[1]>>32)
++
++    ADD     lt_0,m1_0,lt_0           ; lt[0] = lt[0]+m1[0];
++	ADD,DC  ht_0,%r0,ht_0            ; ht[0]++
++    ADD     lt_1,m1_1,lt_1           ; lt[1] = lt[1]+m1[1];
++    ADD,DC  ht_1,%r0,ht_1            ; ht[1]++
++
++    ADD    %ret0,lt_0,lt_0           ; lt[0] = lt[0] + c;
++	ADD,DC  ht_0,%r0,ht_0            ; ht[0]++
++    ADD     lt_0,rp_val,lt_0         ; lt[0] = lt[0]+rp[0]
++    ADD,DC  ht_0,%r0,ht_0            ; ht[0]++
++
++	LDO    -2(num),num               ; num = num - 2;
++    ADD     ht_0,lt_1,lt_1           ; lt[1] = lt[1] + ht_0 (c);
++    ADD,DC  ht_1,%r0,ht_1            ; ht[1]++
++    STD     lt_0,0(r_ptr)            ; rp[0] = lt[0]
++
++    ADD     lt_1,rp_val_1,lt_1       ; lt[1] = lt[1]+rp[1]
++    ADD,DC  ht_1,%r0,%ret0           ; ht[1]++
++    LDO     16(a_ptr),a_ptr          ; a_ptr += 2
++
++    STD     lt_1,8(r_ptr)            ; rp[1] = lt[1]
++	CMPIB,<= 2,num,bn_mul_add_words_unroll2 ; go again if more to do
++    LDO     16(r_ptr),r_ptr          ; r_ptr += 2
++
++    CMPIB,=,N 0,num,bn_mul_add_words_exit ; are we done, or cleanup last one
++
++	;
++	; Top of loop aligned on 64-byte boundary
++	;
++bn_mul_add_words_single_top
++    FLDD    0(a_ptr),t_float_0        ; load up 64-bit value (fr8L) ht(L)/lt(R)
++    LDD     0(r_ptr),rp_val           ; rp[0]
++    LDO     8(a_ptr),a_ptr            ; a_ptr++
++    XMPYU   fht_0,fw_l,fm1            ; m1 = ht*fw_l
++    FSTD    fm1,-16(%sp)              ; -16(sp) = m1
++    XMPYU   flt_0,fw_h,fm             ; m = lt*fw_h
++    FSTD    fm,-8(%sp)                ; -8(sp) = m
++    XMPYU   fht_0,fw_h,ht_temp        ; ht_temp = ht*fw_h
++    FSTD    ht_temp,-24(%sp)          ; -24(sp) = ht
++    XMPYU   flt_0,fw_l,lt_temp        ; lt_temp = lt*fw_l
++    FSTD    lt_temp,-32(%sp)          ; -32(sp) = lt 
++
++    LDD     -8(%sp),m_0               
++    LDD    -16(%sp),m1_0              ; m1 = temp1 
++    ADD,L   m_0,m1_0,tmp_0            ; tmp_0 = m + m1; 
++    LDD     -24(%sp),ht_0             
++    LDD     -32(%sp),lt_0             
++
++    CMPCLR,*>>= tmp_0,m1_0,%r0        ; if (m < m1)
++    ADD,L   ht_0,top_overflow,ht_0    ; ht += (1<<32)
++
++    EXTRD,U tmp_0,31,32,m_0           ; m>>32  
++    DEPD,Z  tmp_0,31,32,m1_0          ; m1 = m<<32 
++
++    ADD,L   ht_0,m_0,ht_0             ; ht+= (m>>32)
++    ADD     lt_0,m1_0,tmp_0           ; tmp_0 = lt+m1;
++    ADD,DC  ht_0,%r0,ht_0             ; ht++
++    ADD     %ret0,tmp_0,lt_0          ; lt = lt + c;
++    ADD,DC  ht_0,%r0,ht_0             ; ht++
++    ADD     lt_0,rp_val,lt_0          ; lt = lt+rp[0]
++    ADD,DC  ht_0,%r0,%ret0            ; ht++
++    STD     lt_0,0(r_ptr)             ; rp[0] = lt
++
++bn_mul_add_words_exit
++    .EXIT
++    LDD     -80(%sp),%r9              ; restore r9  
++    LDD     -88(%sp),%r8              ; restore r8  
++    LDD     -96(%sp),%r7              ; restore r7  
++    LDD     -104(%sp),%r6             ; restore r6  
++    LDD     -112(%sp),%r5             ; restore r5  
++    LDD     -120(%sp),%r4             ; restore r4  
++    BVE     (%rp)
++    LDD,MB  -128(%sp),%r3             ; restore r3
++	.PROCEND	;in=23,24,25,26,29;out=28;
++
++;----------------------------------------------------------------------------
++;
++;BN_ULONG bn_mul_words(BN_ULONG *rp, BN_ULONG *ap, int num, BN_ULONG w)
++;
++; arg0 = rp
++; arg1 = ap
++; arg2 = num
++; arg3 = w
++
++bn_mul_words
++	.proc
++	.callinfo frame=128
++    .entry
++	.EXPORT	bn_mul_words,ENTRY,PRIV_LEV=3,NO_RELOCATION,LONG_RETURN
++	.align 64
++
++    STD     %r3,0(%sp)          ; save r3  
++    STD     %r4,8(%sp)          ; save r4  
++    STD     %r5,16(%sp)         ; save r5  
++    STD     %r6,24(%sp)         ; save r6  
++
++    STD     %r7,32(%sp)         ; save r7  
++    COPY    %r0,%ret0           ; return 0 by default
++    DEPDI,Z 1,31,1,top_overflow ; top_overflow = 1 << 32    
++	STD     w,56(%sp)           ; w on stack
++
++    CMPIB,>= 0,num,bn_mul_words_exit
++	LDO     128(%sp),%sp       ; bump stack
++
++	;
++	; See if only 1 word to do, thus just do cleanup
++	;
++	CMPIB,= 1,num,bn_mul_words_single_top
++	FLDD    -72(%sp),fw     ; load up w into fp register fw (fw_h/fw_l)
++
++	;
++	; This loop is unrolled 2 times (64-byte aligned as well)
++	;
++	; PA-RISC 2.0 chips have two fully pipelined multipliers, thus
++    ; two 32-bit mutiplies can be issued per cycle.
++    ; 
++bn_mul_words_unroll2
++
++    FLDD    0(a_ptr),t_float_0        ; load up 64-bit value (fr8L) ht(L)/lt(R)
++    FLDD    8(a_ptr),t_float_1        ; load up 64-bit value (fr8L) ht(L)/lt(R)
++    XMPYU   fht_0,fw_l,fm1            ; m1[0] = fht_0*fw_l
++    XMPYU   fht_1,fw_l,fm1_1          ; m1[1] = ht*fw_l
++
++    FSTD    fm1,-16(%sp)              ; -16(sp) = m1
++    FSTD    fm1_1,-48(%sp)            ; -48(sp) = m1
++    XMPYU   flt_0,fw_h,fm             ; m = lt*fw_h
++    XMPYU   flt_1,fw_h,fm_1           ; m = lt*fw_h
++
++    FSTD    fm,-8(%sp)                ; -8(sp) = m
++    FSTD    fm_1,-40(%sp)             ; -40(sp) = m
++    XMPYU   fht_0,fw_h,ht_temp        ; ht_temp = fht_0*fw_h
++    XMPYU   fht_1,fw_h,ht_temp_1      ; ht_temp = ht*fw_h
++
++    FSTD    ht_temp,-24(%sp)          ; -24(sp) = ht
++    FSTD    ht_temp_1,-56(%sp)        ; -56(sp) = ht
++    XMPYU   flt_0,fw_l,lt_temp        ; lt_temp = lt*fw_l
++    XMPYU   flt_1,fw_l,lt_temp_1      ; lt_temp = lt*fw_l
++
++    FSTD    lt_temp,-32(%sp)          ; -32(sp) = lt 
++    FSTD    lt_temp_1,-64(%sp)        ; -64(sp) = lt 
++    LDD     -8(%sp),m_0               
++    LDD     -40(%sp),m_1              
++
++    LDD    -16(%sp),m1_0              
++    LDD    -48(%sp),m1_1              
++    LDD     -24(%sp),ht_0             
++    LDD     -56(%sp),ht_1             
++
++    ADD,L   m1_0,m_0,tmp_0            ; tmp_0 = m + m1; 
++    ADD,L   m1_1,m_1,tmp_1            ; tmp_1 = m + m1; 
++    LDD     -32(%sp),lt_0             
++    LDD     -64(%sp),lt_1             
++
++    CMPCLR,*>>= tmp_0,m1_0, %r0       ; if (m < m1)
++    ADD,L   ht_0,top_overflow,ht_0    ; ht += (1<<32)
++    CMPCLR,*>>= tmp_1,m1_1,%r0        ; if (m < m1)
++    ADD,L   ht_1,top_overflow,ht_1    ; ht += (1<<32)
++
++    EXTRD,U tmp_0,31,32,m_0           ; m>>32  
++    DEPD,Z  tmp_0,31,32,m1_0          ; m1 = m<<32 
++    EXTRD,U tmp_1,31,32,m_1           ; m>>32  
++    DEPD,Z  tmp_1,31,32,m1_1          ; m1 = m<<32 
++
++    ADD,L   ht_0,m_0,ht_0             ; ht+= (m>>32)
++    ADD,L   ht_1,m_1,ht_1             ; ht+= (m>>32)
++    ADD     lt_0,m1_0,lt_0            ; lt = lt+m1;
++	ADD,DC  ht_0,%r0,ht_0             ; ht++
++
++    ADD     lt_1,m1_1,lt_1            ; lt = lt+m1;
++    ADD,DC  ht_1,%r0,ht_1             ; ht++
++    ADD    %ret0,lt_0,lt_0            ; lt = lt + c (ret0);
++	ADD,DC  ht_0,%r0,ht_0             ; ht++
++
++    ADD     ht_0,lt_1,lt_1            ; lt = lt + c (ht_0)
++    ADD,DC  ht_1,%r0,ht_1             ; ht++
++    STD     lt_0,0(r_ptr)             ; rp[0] = lt
++    STD     lt_1,8(r_ptr)             ; rp[1] = lt
++
++	COPY    ht_1,%ret0                ; carry = ht
++	LDO    -2(num),num                ; num = num - 2;
++    LDO     16(a_ptr),a_ptr           ; ap += 2
++	CMPIB,<= 2,num,bn_mul_words_unroll2
++    LDO     16(r_ptr),r_ptr           ; rp++
++
++    CMPIB,=,N 0,num,bn_mul_words_exit ; are we done?
++
++	;
++	; Top of loop aligned on 64-byte boundary
++	;
++bn_mul_words_single_top
++    FLDD    0(a_ptr),t_float_0        ; load up 64-bit value (fr8L) ht(L)/lt(R)
++
++    XMPYU   fht_0,fw_l,fm1            ; m1 = ht*fw_l
++    FSTD    fm1,-16(%sp)              ; -16(sp) = m1
++    XMPYU   flt_0,fw_h,fm             ; m = lt*fw_h
++    FSTD    fm,-8(%sp)                ; -8(sp) = m
++    XMPYU   fht_0,fw_h,ht_temp        ; ht_temp = ht*fw_h
++    FSTD    ht_temp,-24(%sp)          ; -24(sp) = ht
++    XMPYU   flt_0,fw_l,lt_temp        ; lt_temp = lt*fw_l
++    FSTD    lt_temp,-32(%sp)          ; -32(sp) = lt 
++
++    LDD     -8(%sp),m_0               
++    LDD    -16(%sp),m1_0              
++    ADD,L   m_0,m1_0,tmp_0            ; tmp_0 = m + m1; 
++    LDD     -24(%sp),ht_0             
++    LDD     -32(%sp),lt_0             
++
++    CMPCLR,*>>= tmp_0,m1_0,%r0        ; if (m < m1)
++    ADD,L   ht_0,top_overflow,ht_0    ; ht += (1<<32)
++
++    EXTRD,U tmp_0,31,32,m_0           ; m>>32  
++    DEPD,Z  tmp_0,31,32,m1_0          ; m1 = m<<32 
++
++    ADD,L   ht_0,m_0,ht_0             ; ht+= (m>>32)
++    ADD     lt_0,m1_0,lt_0            ; lt= lt+m1;
++    ADD,DC  ht_0,%r0,ht_0             ; ht++
++
++    ADD     %ret0,lt_0,lt_0           ; lt = lt + c;
++    ADD,DC  ht_0,%r0,ht_0             ; ht++
++
++    COPY    ht_0,%ret0                ; copy carry
++    STD     lt_0,0(r_ptr)             ; rp[0] = lt
++
++bn_mul_words_exit
++    .EXIT
++    LDD     -96(%sp),%r7              ; restore r7  
++    LDD     -104(%sp),%r6             ; restore r6  
++    LDD     -112(%sp),%r5             ; restore r5  
++    LDD     -120(%sp),%r4             ; restore r4  
++    BVE     (%rp)
++    LDD,MB  -128(%sp),%r3             ; restore r3
++	.PROCEND	;in=23,24,25,26,29;out=28;
++
++;----------------------------------------------------------------------------
++;
++;void bn_sqr_words(BN_ULONG *rp, BN_ULONG *ap, int num)
++;
++; arg0 = rp
++; arg1 = ap
++; arg2 = num
++;
++
++bn_sqr_words
++	.proc
++	.callinfo FRAME=128,ENTRY_GR=%r3,ARGS_SAVED,ORDERING_AWARE
++	.EXPORT	bn_sqr_words,ENTRY,PRIV_LEV=3,NO_RELOCATION,LONG_RETURN
++    .entry
++	.align 64
++
++    STD     %r3,0(%sp)          ; save r3  
++    STD     %r4,8(%sp)          ; save r4  
++	NOP
++    STD     %r5,16(%sp)         ; save r5  
++
++    CMPIB,>= 0,num,bn_sqr_words_exit
++	LDO     128(%sp),%sp       ; bump stack
++
++	;
++	; If only 1, the goto straight to cleanup
++	;
++	CMPIB,= 1,num,bn_sqr_words_single_top
++    DEPDI,Z -1,32,33,high_mask   ; Create Mask 0xffffffff80000000L
++
++	;
++	; This loop is unrolled 2 times (64-byte aligned as well)
++	;
++
++bn_sqr_words_unroll2
++    FLDD    0(a_ptr),t_float_0        ; a[0]
++    FLDD    8(a_ptr),t_float_1        ; a[1]
++    XMPYU   fht_0,flt_0,fm            ; m[0]
++    XMPYU   fht_1,flt_1,fm_1          ; m[1]
++
++    FSTD    fm,-24(%sp)               ; store m[0]
++    FSTD    fm_1,-56(%sp)             ; store m[1]
++    XMPYU   flt_0,flt_0,lt_temp       ; lt[0]
++    XMPYU   flt_1,flt_1,lt_temp_1     ; lt[1]
++
++    FSTD    lt_temp,-16(%sp)          ; store lt[0]
++    FSTD    lt_temp_1,-48(%sp)        ; store lt[1]
++    XMPYU   fht_0,fht_0,ht_temp       ; ht[0]
++    XMPYU   fht_1,fht_1,ht_temp_1     ; ht[1]
++
++    FSTD    ht_temp,-8(%sp)           ; store ht[0]
++    FSTD    ht_temp_1,-40(%sp)        ; store ht[1]
++    LDD     -24(%sp),m_0             
++    LDD     -56(%sp),m_1              
++
++    AND     m_0,high_mask,tmp_0       ; m[0] & Mask
++    AND     m_1,high_mask,tmp_1       ; m[1] & Mask
++    DEPD,Z  m_0,30,31,m_0             ; m[0] << 32+1
++    DEPD,Z  m_1,30,31,m_1             ; m[1] << 32+1
++
++    LDD     -16(%sp),lt_0        
++    LDD     -48(%sp),lt_1        
++    EXTRD,U tmp_0,32,33,tmp_0         ; tmp_0 = m[0]&Mask >> 32-1
++    EXTRD,U tmp_1,32,33,tmp_1         ; tmp_1 = m[1]&Mask >> 32-1
++
++    LDD     -8(%sp),ht_0            
++    LDD     -40(%sp),ht_1           
++    ADD,L   ht_0,tmp_0,ht_0           ; ht[0] += tmp_0
++    ADD,L   ht_1,tmp_1,ht_1           ; ht[1] += tmp_1
++
++    ADD     lt_0,m_0,lt_0             ; lt = lt+m
++    ADD,DC  ht_0,%r0,ht_0             ; ht[0]++
++    STD     lt_0,0(r_ptr)             ; rp[0] = lt[0]
++    STD     ht_0,8(r_ptr)             ; rp[1] = ht[1]
++
++    ADD     lt_1,m_1,lt_1             ; lt = lt+m
++    ADD,DC  ht_1,%r0,ht_1             ; ht[1]++
++    STD     lt_1,16(r_ptr)            ; rp[2] = lt[1]
++    STD     ht_1,24(r_ptr)            ; rp[3] = ht[1]
++
++	LDO    -2(num),num                ; num = num - 2;
++    LDO     16(a_ptr),a_ptr           ; ap += 2
++	CMPIB,<= 2,num,bn_sqr_words_unroll2
++    LDO     32(r_ptr),r_ptr           ; rp += 4
++
++    CMPIB,=,N 0,num,bn_sqr_words_exit ; are we done?
++
++	;
++	; Top of loop aligned on 64-byte boundary
++	;
++bn_sqr_words_single_top
++    FLDD    0(a_ptr),t_float_0        ; load up 64-bit value (fr8L) ht(L)/lt(R)
++
++    XMPYU   fht_0,flt_0,fm            ; m
++    FSTD    fm,-24(%sp)               ; store m
++
++    XMPYU   flt_0,flt_0,lt_temp       ; lt
++    FSTD    lt_temp,-16(%sp)          ; store lt
++
++    XMPYU   fht_0,fht_0,ht_temp       ; ht
++    FSTD    ht_temp,-8(%sp)           ; store ht
++
++    LDD     -24(%sp),m_0              ; load m
++    AND     m_0,high_mask,tmp_0       ; m & Mask
++    DEPD,Z  m_0,30,31,m_0             ; m << 32+1
++    LDD     -16(%sp),lt_0             ; lt
++
++    LDD     -8(%sp),ht_0              ; ht
++    EXTRD,U tmp_0,32,33,tmp_0         ; tmp_0 = m&Mask >> 32-1
++    ADD     m_0,lt_0,lt_0             ; lt = lt+m
++    ADD,L   ht_0,tmp_0,ht_0           ; ht += tmp_0
++    ADD,DC  ht_0,%r0,ht_0             ; ht++
++
++    STD     lt_0,0(r_ptr)             ; rp[0] = lt
++    STD     ht_0,8(r_ptr)             ; rp[1] = ht
++
++bn_sqr_words_exit
++    .EXIT
++    LDD     -112(%sp),%r5       ; restore r5  
++    LDD     -120(%sp),%r4       ; restore r4  
++    BVE     (%rp)
++    LDD,MB  -128(%sp),%r3 
++	.PROCEND	;in=23,24,25,26,29;out=28;
++
++
++;----------------------------------------------------------------------------
++;
++;BN_ULONG bn_add_words(BN_ULONG *r, BN_ULONG *a, BN_ULONG *b, int n)
++;
++; arg0 = rp 
++; arg1 = ap
++; arg2 = bp 
++; arg3 = n
++
++t  .reg %r22
++b  .reg %r21
++l  .reg %r20
++
++bn_add_words
++	.proc
++    .entry
++	.callinfo
++	.EXPORT	bn_add_words,ENTRY,PRIV_LEV=3,NO_RELOCATION,LONG_RETURN
++	.align 64
++
++    CMPIB,>= 0,n,bn_add_words_exit
++    COPY    %r0,%ret0           ; return 0 by default
++
++	;
++	; If 2 or more numbers do the loop
++	;
++	CMPIB,= 1,n,bn_add_words_single_top
++	NOP
++
++	;
++	; This loop is unrolled 2 times (64-byte aligned as well)
++	;
++bn_add_words_unroll2
++	LDD     0(a_ptr),t
++	LDD     0(b_ptr),b
++	ADD     t,%ret0,t                    ; t = t+c;
++	ADD,DC  %r0,%r0,%ret0                ; set c to carry
++	ADD     t,b,l                        ; l = t + b[0]
++	ADD,DC  %ret0,%r0,%ret0              ; c+= carry
++	STD     l,0(r_ptr)
++
++	LDD     8(a_ptr),t
++	LDD     8(b_ptr),b
++	ADD     t,%ret0,t                     ; t = t+c;
++	ADD,DC  %r0,%r0,%ret0                 ; set c to carry
++	ADD     t,b,l                         ; l = t + b[0]
++	ADD,DC  %ret0,%r0,%ret0               ; c+= carry
++	STD     l,8(r_ptr)
++
++	LDO     -2(n),n
++	LDO     16(a_ptr),a_ptr
++	LDO     16(b_ptr),b_ptr
++
++	CMPIB,<= 2,n,bn_add_words_unroll2
++	LDO     16(r_ptr),r_ptr
++
++    CMPIB,=,N 0,n,bn_add_words_exit ; are we done?
++
++bn_add_words_single_top
++	LDD     0(a_ptr),t
++	LDD     0(b_ptr),b
++
++	ADD     t,%ret0,t                 ; t = t+c;
++	ADD,DC  %r0,%r0,%ret0             ; set c to carry (could use CMPCLR??)
++	ADD     t,b,l                     ; l = t + b[0]
++	ADD,DC  %ret0,%r0,%ret0           ; c+= carry
++	STD     l,0(r_ptr)
++
++bn_add_words_exit
++    .EXIT
++    BVE     (%rp)
++	NOP
++	.PROCEND	;in=23,24,25,26,29;out=28;
++
++;----------------------------------------------------------------------------
++;
++;BN_ULONG bn_sub_words(BN_ULONG *r, BN_ULONG *a, BN_ULONG *b, int n)
++;
++; arg0 = rp 
++; arg1 = ap
++; arg2 = bp 
++; arg3 = n
++
++t1       .reg %r22
++t2       .reg %r21
++sub_tmp1 .reg %r20
++sub_tmp2 .reg %r19
++
++
++bn_sub_words
++	.proc
++	.callinfo 
++	.EXPORT	bn_sub_words,ENTRY,PRIV_LEV=3,NO_RELOCATION,LONG_RETURN
++    .entry
++	.align 64
++
++    CMPIB,>=  0,n,bn_sub_words_exit
++    COPY    %r0,%ret0           ; return 0 by default
++
++	;
++	; If 2 or more numbers do the loop
++	;
++	CMPIB,= 1,n,bn_sub_words_single_top
++	NOP
++
++	;
++	; This loop is unrolled 2 times (64-byte aligned as well)
++	;
++bn_sub_words_unroll2
++	LDD     0(a_ptr),t1
++	LDD     0(b_ptr),t2
++	SUB     t1,t2,sub_tmp1           ; t3 = t1-t2; 
++	SUB     sub_tmp1,%ret0,sub_tmp1  ; t3 = t3- c; 
++
++	CMPCLR,*>> t1,t2,sub_tmp2        ; clear if t1 > t2
++	LDO      1(%r0),sub_tmp2
++	
++	CMPCLR,*= t1,t2,%r0
++	COPY    sub_tmp2,%ret0
++	STD     sub_tmp1,0(r_ptr)
++
++	LDD     8(a_ptr),t1
++	LDD     8(b_ptr),t2
++	SUB     t1,t2,sub_tmp1            ; t3 = t1-t2; 
++	SUB     sub_tmp1,%ret0,sub_tmp1   ; t3 = t3- c; 
++	CMPCLR,*>> t1,t2,sub_tmp2         ; clear if t1 > t2
++	LDO      1(%r0),sub_tmp2
++	
++	CMPCLR,*= t1,t2,%r0
++	COPY    sub_tmp2,%ret0
++	STD     sub_tmp1,8(r_ptr)
++
++	LDO     -2(n),n
++	LDO     16(a_ptr),a_ptr
++	LDO     16(b_ptr),b_ptr
++
++	CMPIB,<= 2,n,bn_sub_words_unroll2
++	LDO     16(r_ptr),r_ptr
++
++    CMPIB,=,N 0,n,bn_sub_words_exit ; are we done?
++
++bn_sub_words_single_top
++	LDD     0(a_ptr),t1
++	LDD     0(b_ptr),t2
++	SUB     t1,t2,sub_tmp1            ; t3 = t1-t2; 
++	SUB     sub_tmp1,%ret0,sub_tmp1   ; t3 = t3- c; 
++	CMPCLR,*>> t1,t2,sub_tmp2         ; clear if t1 > t2
++	LDO      1(%r0),sub_tmp2
++	
++	CMPCLR,*= t1,t2,%r0
++	COPY    sub_tmp2,%ret0
++
++	STD     sub_tmp1,0(r_ptr)
++
++bn_sub_words_exit
++    .EXIT
++    BVE     (%rp)
++	NOP
++	.PROCEND	;in=23,24,25,26,29;out=28;
++
++;------------------------------------------------------------------------------
++;
++; unsigned long bn_div_words(unsigned long h, unsigned long l, unsigned long d)
++;
++; arg0 = h
++; arg1 = l
++; arg2 = d
++;
++; This is mainly just modified assembly from the compiler, thus the
++; lack of variable names.
++;
++;------------------------------------------------------------------------------
++bn_div_words
++	.proc
++	.callinfo CALLER,FRAME=272,ENTRY_GR=%r10,SAVE_RP,ARGS_SAVED,ORDERING_AWARE
++	.EXPORT	bn_div_words,ENTRY,PRIV_LEV=3,NO_RELOCATION,LONG_RETURN
++	.IMPORT	BN_num_bits_word,CODE,NO_RELOCATION
++	.IMPORT	__iob,DATA
++	.IMPORT	fprintf,CODE,NO_RELOCATION
++	.IMPORT	abort,CODE,NO_RELOCATION
++	.IMPORT	$$div2U,MILLICODE
++    .entry
++    STD     %r2,-16(%r30)   
++    STD,MA  %r3,352(%r30)   
++    STD     %r4,-344(%r30)  
++    STD     %r5,-336(%r30)  
++    STD     %r6,-328(%r30)  
++    STD     %r7,-320(%r30)  
++    STD     %r8,-312(%r30)  
++    STD     %r9,-304(%r30)  
++    STD     %r10,-296(%r30)
++
++    STD     %r27,-288(%r30)             ; save gp
++
++    COPY    %r24,%r3           ; save d 
++    COPY    %r26,%r4           ; save h (high 64-bits)
++    LDO      -1(%r0),%ret0     ; return -1 by default	
++
++    CMPB,*=  %r0,%arg2,$D3     ; if (d == 0)
++    COPY    %r25,%r5           ; save l (low 64-bits)
++
++    LDO     -48(%r30),%r29     ; create ap 
++    .CALL   ;in=26,29;out=28;
++    B,L     BN_num_bits_word,%r2 
++    COPY    %r3,%r26        
++    LDD     -288(%r30),%r27    ; restore gp 
++    LDI     64,%r21 
++
++    CMPB,=  %r21,%ret0,$00000012   ;if (i == 64) (forward) 
++    COPY    %ret0,%r24             ; i   
++    MTSARCM %r24    
++    DEPDI,Z -1,%sar,1,%r29  
++    CMPB,*<<,N %r29,%r4,bn_div_err_case ; if (h > 1<= d)
++    SUB     %r4,%r3,%r4                        ; h -= d
++    CMPB,=  %r31,%r0,$0000001A                 ; if (i)
++    COPY    %r0,%r10                           ; ret = 0
++    MTSARCM %r31                               ; i to shift
++    DEPD,Z  %r3,%sar,64,%r3                    ; d <<= i;
++    SUBI    64,%r31,%r19                       ; 64 - i; redundent
++    MTSAR   %r19                               ; (64 -i) to shift
++    SHRPD   %r4,%r5,%sar,%r4                   ; l>> (64-i)
++    MTSARCM %r31                               ; i to shift
++    DEPD,Z  %r5,%sar,64,%r5                    ; l <<= i;
++
++$0000001A
++    DEPDI,Z -1,31,32,%r19                      
++    EXTRD,U %r3,31,32,%r6                      ; dh=(d&0xfff)>>32
++    EXTRD,U %r3,63,32,%r8                      ; dl = d&0xffffff
++    LDO     2(%r0),%r9
++    STD    %r3,-280(%r30)                      ; "d" to stack
++
++$0000001C
++    DEPDI,Z -1,63,32,%r29                      ; 
++    EXTRD,U %r4,31,32,%r31                     ; h >> 32
++    CMPB,*=,N  %r31,%r6,$D2     	       ; if ((h>>32) != dh)(forward) div
++    COPY    %r4,%r26       
++    EXTRD,U %r4,31,32,%r25 
++    COPY    %r6,%r24      
++    .CALL   ;in=23,24,25,26;out=20,21,22,28,29; (MILLICALL)
++    B,L     $$div2U,%r2     
++    EXTRD,U %r6,31,32,%r23  
++    DEPD    %r28,31,32,%r29 
++$D2
++    STD     %r29,-272(%r30)                   ; q
++    AND     %r5,%r19,%r24                   ; t & 0xffffffff00000000;
++    EXTRD,U %r24,31,32,%r24                 ; ??? 
++    FLDD    -272(%r30),%fr7                 ; q
++    FLDD    -280(%r30),%fr8                 ; d
++    XMPYU   %fr8L,%fr7L,%fr10  
++    FSTD    %fr10,-256(%r30)   
++    XMPYU   %fr8L,%fr7R,%fr22  
++    FSTD    %fr22,-264(%r30)   
++    XMPYU   %fr8R,%fr7L,%fr11 
++    XMPYU   %fr8R,%fr7R,%fr23
++    FSTD    %fr11,-232(%r30)
++    FSTD    %fr23,-240(%r30)
++    LDD     -256(%r30),%r28
++    DEPD,Z  %r28,31,32,%r2 
++    LDD     -264(%r30),%r20
++    ADD,L   %r20,%r2,%r31   
++    LDD     -232(%r30),%r22 
++    DEPD,Z  %r22,31,32,%r22 
++    LDD     -240(%r30),%r21 
++    B       $00000024       ; enter loop  
++    ADD,L   %r21,%r22,%r23 
++
++$0000002A
++    LDO     -1(%r29),%r29   
++    SUB     %r23,%r8,%r23   
++$00000024
++    SUB     %r4,%r31,%r25   
++    AND     %r25,%r19,%r26  
++    CMPB,*<>,N      %r0,%r26,$00000046  ; (forward)
++    DEPD,Z  %r25,31,32,%r20 
++    OR      %r20,%r24,%r21  
++    CMPB,*<<,N  %r21,%r23,$0000002A ;(backward) 
++    SUB     %r31,%r6,%r31   
++;-------------Break path---------------------
++
++$00000046
++    DEPD,Z  %r23,31,32,%r25              ;tl
++    EXTRD,U %r23,31,32,%r26              ;t
++    AND     %r25,%r19,%r24               ;tl = (tl<<32)&0xfffffff0000000L
++    ADD,L   %r31,%r26,%r31               ;th += t; 
++    CMPCLR,*>>=     %r5,%r24,%r0         ;if (l>32));
++    DEPD,Z  %r29,31,32,%r10              ; ret = q<<32
++    b      $0000001C
++    DEPD,Z  %r28,31,32,%r5               ; l = l << 32 
++
++$D1
++    OR      %r10,%r29,%r28           ; ret |= q
++$D3
++    LDD     -368(%r30),%r2  
++$D0
++    LDD     -296(%r30),%r10 
++    LDD     -304(%r30),%r9  
++    LDD     -312(%r30),%r8  
++    LDD     -320(%r30),%r7  
++    LDD     -328(%r30),%r6  
++    LDD     -336(%r30),%r5  
++    LDD     -344(%r30),%r4  
++    BVE     (%r2)   
++        .EXIT
++    LDD,MB  -352(%r30),%r3 
++
++bn_div_err_case
++    MFIA    %r6     
++    ADDIL   L'bn_div_words-bn_div_err_case,%r6,%r1 
++    LDO     R'bn_div_words-bn_div_err_case(%r1),%r6  
++    ADDIL   LT'__iob,%r27,%r1       
++    LDD     RT'__iob(%r1),%r26      
++    ADDIL   L'C$4-bn_div_words,%r6,%r1    
++    LDO     R'C$4-bn_div_words(%r1),%r25  
++    LDO     64(%r26),%r26   
++    .CALL           ;in=24,25,26,29;out=28;
++    B,L     fprintf,%r2    
++    LDO     -48(%r30),%r29 
++    LDD     -288(%r30),%r27
++    .CALL           ;in=29;
++    B,L     abort,%r2      
++    LDO     -48(%r30),%r29 
++    LDD     -288(%r30),%r27
++    B       $D0         
++    LDD     -368(%r30),%r2  
++	.PROCEND	;in=24,25,26,29;out=28;
++
++;----------------------------------------------------------------------------
++;
++; Registers to hold 64-bit values to manipulate.  The "L" part
++; of the register corresponds to the upper 32-bits, while the "R"
++; part corresponds to the lower 32-bits
++; 
++; Note, that when using b6 and b7, the code must save these before
++; using them because they are callee save registers 
++; 
++;
++; Floating point registers to use to save values that
++; are manipulated.  These don't collide with ftemp1-6 and
++; are all caller save registers
++;
++a0        .reg %fr22
++a0L       .reg %fr22L
++a0R       .reg %fr22R
++
++a1        .reg %fr23
++a1L       .reg %fr23L
++a1R       .reg %fr23R
++
++a2        .reg %fr24
++a2L       .reg %fr24L
++a2R       .reg %fr24R
++
++a3        .reg %fr25
++a3L       .reg %fr25L
++a3R       .reg %fr25R
++
++a4        .reg %fr26
++a4L       .reg %fr26L
++a4R       .reg %fr26R
++
++a5        .reg %fr27
++a5L       .reg %fr27L
++a5R       .reg %fr27R
++
++a6        .reg %fr28
++a6L       .reg %fr28L
++a6R       .reg %fr28R
++
++a7        .reg %fr29
++a7L       .reg %fr29L
++a7R       .reg %fr29R
++
++b0        .reg %fr30
++b0L       .reg %fr30L
++b0R       .reg %fr30R
++
++b1        .reg %fr31
++b1L       .reg %fr31L
++b1R       .reg %fr31R
++
++;
++; Temporary floating point variables, these are all caller save
++; registers
++;
++ftemp1    .reg %fr4
++ftemp2    .reg %fr5
++ftemp3    .reg %fr6
++ftemp4    .reg %fr7
++
++;
++; The B set of registers when used.
++;
++
++b2        .reg %fr8
++b2L       .reg %fr8L
++b2R       .reg %fr8R
++
++b3        .reg %fr9
++b3L       .reg %fr9L
++b3R       .reg %fr9R
++
++b4        .reg %fr10
++b4L       .reg %fr10L
++b4R       .reg %fr10R
++
++b5        .reg %fr11
++b5L       .reg %fr11L
++b5R       .reg %fr11R
++
++b6        .reg %fr12
++b6L       .reg %fr12L
++b6R       .reg %fr12R
++
++b7        .reg %fr13
++b7L       .reg %fr13L
++b7R       .reg %fr13R
++
++c1           .reg %r21   ; only reg
++temp1        .reg %r20   ; only reg
++temp2        .reg %r19   ; only reg
++temp3        .reg %r31   ; only reg
++
++m1           .reg %r28   
++c2           .reg %r23   
++high_one     .reg %r1
++ht           .reg %r6
++lt           .reg %r5
++m            .reg %r4
++c3           .reg %r3
++
++SQR_ADD_C  .macro  A0L,A0R,C1,C2,C3
++    XMPYU   A0L,A0R,ftemp1       ; m
++    FSTD    ftemp1,-24(%sp)      ; store m
++
++    XMPYU   A0R,A0R,ftemp2       ; lt
++    FSTD    ftemp2,-16(%sp)      ; store lt
++
++    XMPYU   A0L,A0L,ftemp3       ; ht
++    FSTD    ftemp3,-8(%sp)       ; store ht
++
++    LDD     -24(%sp),m           ; load m
++    AND     m,high_mask,temp2    ; m & Mask
++    DEPD,Z  m,30,31,temp3        ; m << 32+1
++    LDD     -16(%sp),lt          ; lt
++
++    LDD     -8(%sp),ht           ; ht
++    EXTRD,U temp2,32,33,temp1    ; temp1 = m&Mask >> 32-1
++    ADD     temp3,lt,lt          ; lt = lt+m
++    ADD,L   ht,temp1,ht          ; ht += temp1
++    ADD,DC  ht,%r0,ht            ; ht++
++
++    ADD     C1,lt,C1             ; c1=c1+lt
++    ADD,DC  ht,%r0,ht            ; ht++
++
++    ADD     C2,ht,C2             ; c2=c2+ht
++    ADD,DC  C3,%r0,C3            ; c3++
++.endm
++
++SQR_ADD_C2 .macro  A0L,A0R,A1L,A1R,C1,C2,C3
++    XMPYU   A0L,A1R,ftemp1          ; m1 = bl*ht
++    FSTD    ftemp1,-16(%sp)         ;
++    XMPYU   A0R,A1L,ftemp2          ; m = bh*lt
++    FSTD    ftemp2,-8(%sp)          ;
++    XMPYU   A0R,A1R,ftemp3          ; lt = bl*lt
++    FSTD    ftemp3,-32(%sp)
++    XMPYU   A0L,A1L,ftemp4          ; ht = bh*ht
++    FSTD    ftemp4,-24(%sp)         ;
++
++    LDD     -8(%sp),m               ; r21 = m
++    LDD     -16(%sp),m1             ; r19 = m1
++    ADD,L   m,m1,m                  ; m+m1
++
++    DEPD,Z  m,31,32,temp3           ; (m+m1<<32)
++    LDD     -24(%sp),ht             ; r24 = ht
++
++    CMPCLR,*>>= m,m1,%r0            ; if (m < m1)
++    ADD,L   ht,high_one,ht          ; ht+=high_one
++
++    EXTRD,U m,31,32,temp1           ; m >> 32
++    LDD     -32(%sp),lt             ; lt
++    ADD,L   ht,temp1,ht             ; ht+= m>>32
++    ADD     lt,temp3,lt             ; lt = lt+m1
++    ADD,DC  ht,%r0,ht               ; ht++
++
++    ADD     ht,ht,ht                ; ht=ht+ht;
++    ADD,DC  C3,%r0,C3               ; add in carry (c3++)
++
++    ADD     lt,lt,lt                ; lt=lt+lt;
++    ADD,DC  ht,%r0,ht               ; add in carry (ht++)
++
++    ADD     C1,lt,C1                ; c1=c1+lt
++    ADD,DC,*NUV ht,%r0,ht           ; add in carry (ht++)
++    LDO     1(C3),C3              ; bump c3 if overflow,nullify otherwise
++
++    ADD     C2,ht,C2                ; c2 = c2 + ht
++    ADD,DC  C3,%r0,C3             ; add in carry (c3++)
++.endm
++
++;
++;void bn_sqr_comba8(BN_ULONG *r, BN_ULONG *a)
++; arg0 = r_ptr
++; arg1 = a_ptr
++;
++
++bn_sqr_comba8
++	.PROC
++	.CALLINFO FRAME=128,ENTRY_GR=%r3,ARGS_SAVED,ORDERING_AWARE
++	.EXPORT	bn_sqr_comba8,ENTRY,PRIV_LEV=3,NO_RELOCATION,LONG_RETURN
++    .ENTRY
++	.align 64
++
++    STD     %r3,0(%sp)          ; save r3
++    STD     %r4,8(%sp)          ; save r4
++    STD     %r5,16(%sp)         ; save r5
++    STD     %r6,24(%sp)         ; save r6
++
++	;
++	; Zero out carries
++	;
++	COPY     %r0,c1
++	COPY     %r0,c2
++	COPY     %r0,c3
++
++	LDO      128(%sp),%sp       ; bump stack
++    DEPDI,Z -1,32,33,high_mask   ; Create Mask 0xffffffff80000000L
++    DEPDI,Z  1,31,1,high_one     ; Create Value  1 << 32
++
++	;
++	; Load up all of the values we are going to use
++	;
++    FLDD     0(a_ptr),a0       
++    FLDD     8(a_ptr),a1       
++    FLDD    16(a_ptr),a2       
++    FLDD    24(a_ptr),a3       
++    FLDD    32(a_ptr),a4       
++    FLDD    40(a_ptr),a5       
++    FLDD    48(a_ptr),a6       
++    FLDD    56(a_ptr),a7       
++
++	SQR_ADD_C a0L,a0R,c1,c2,c3
++	STD     c1,0(r_ptr)          ; r[0] = c1;
++	COPY    %r0,c1
++
++	SQR_ADD_C2 a1L,a1R,a0L,a0R,c2,c3,c1
++	STD     c2,8(r_ptr)          ; r[1] = c2;
++	COPY    %r0,c2
++
++	SQR_ADD_C a1L,a1R,c3,c1,c2
++	SQR_ADD_C2 a2L,a2R,a0L,a0R,c3,c1,c2
++	STD     c3,16(r_ptr)            ; r[2] = c3;
++	COPY    %r0,c3
++
++	SQR_ADD_C2 a3L,a3R,a0L,a0R,c1,c2,c3
++	SQR_ADD_C2 a2L,a2R,a1L,a1R,c1,c2,c3
++	STD     c1,24(r_ptr)           ; r[3] = c1;
++	COPY    %r0,c1
++
++	SQR_ADD_C a2L,a2R,c2,c3,c1
++	SQR_ADD_C2 a3L,a3R,a1L,a1R,c2,c3,c1
++	SQR_ADD_C2 a4L,a4R,a0L,a0R,c2,c3,c1
++	STD     c2,32(r_ptr)          ; r[4] = c2;
++	COPY    %r0,c2
++
++	SQR_ADD_C2 a5L,a5R,a0L,a0R,c3,c1,c2
++	SQR_ADD_C2 a4L,a4R,a1L,a1R,c3,c1,c2
++	SQR_ADD_C2 a3L,a3R,a2L,a2R,c3,c1,c2
++	STD     c3,40(r_ptr)          ; r[5] = c3;
++	COPY    %r0,c3
++
++	SQR_ADD_C a3L,a3R,c1,c2,c3
++	SQR_ADD_C2 a4L,a4R,a2L,a2R,c1,c2,c3
++	SQR_ADD_C2 a5L,a5R,a1L,a1R,c1,c2,c3
++	SQR_ADD_C2 a6L,a6R,a0L,a0R,c1,c2,c3
++	STD     c1,48(r_ptr)          ; r[6] = c1;
++	COPY    %r0,c1
++
++	SQR_ADD_C2 a7L,a7R,a0L,a0R,c2,c3,c1
++	SQR_ADD_C2 a6L,a6R,a1L,a1R,c2,c3,c1
++	SQR_ADD_C2 a5L,a5R,a2L,a2R,c2,c3,c1
++	SQR_ADD_C2 a4L,a4R,a3L,a3R,c2,c3,c1
++	STD     c2,56(r_ptr)          ; r[7] = c2;
++	COPY    %r0,c2
++
++	SQR_ADD_C a4L,a4R,c3,c1,c2
++	SQR_ADD_C2 a5L,a5R,a3L,a3R,c3,c1,c2
++	SQR_ADD_C2 a6L,a6R,a2L,a2R,c3,c1,c2
++	SQR_ADD_C2 a7L,a7R,a1L,a1R,c3,c1,c2
++	STD     c3,64(r_ptr)          ; r[8] = c3;
++	COPY    %r0,c3
++
++	SQR_ADD_C2 a7L,a7R,a2L,a2R,c1,c2,c3
++	SQR_ADD_C2 a6L,a6R,a3L,a3R,c1,c2,c3
++	SQR_ADD_C2 a5L,a5R,a4L,a4R,c1,c2,c3
++	STD     c1,72(r_ptr)          ; r[9] = c1;
++	COPY    %r0,c1
++
++	SQR_ADD_C a5L,a5R,c2,c3,c1
++	SQR_ADD_C2 a6L,a6R,a4L,a4R,c2,c3,c1
++	SQR_ADD_C2 a7L,a7R,a3L,a3R,c2,c3,c1
++	STD     c2,80(r_ptr)          ; r[10] = c2;
++	COPY    %r0,c2
++
++	SQR_ADD_C2 a7L,a7R,a4L,a4R,c3,c1,c2
++	SQR_ADD_C2 a6L,a6R,a5L,a5R,c3,c1,c2
++	STD     c3,88(r_ptr)          ; r[11] = c3;
++	COPY    %r0,c3
++	
++	SQR_ADD_C a6L,a6R,c1,c2,c3
++	SQR_ADD_C2 a7L,a7R,a5L,a5R,c1,c2,c3
++	STD     c1,96(r_ptr)          ; r[12] = c1;
++	COPY    %r0,c1
++
++	SQR_ADD_C2 a7L,a7R,a6L,a6R,c2,c3,c1
++	STD     c2,104(r_ptr)         ; r[13] = c2;
++	COPY    %r0,c2
++
++	SQR_ADD_C a7L,a7R,c3,c1,c2
++	STD     c3, 112(r_ptr)       ; r[14] = c3
++	STD     c1, 120(r_ptr)       ; r[15] = c1
++
++    .EXIT
++    LDD     -104(%sp),%r6        ; restore r6
++    LDD     -112(%sp),%r5        ; restore r5
++    LDD     -120(%sp),%r4        ; restore r4
++    BVE     (%rp)
++    LDD,MB  -128(%sp),%r3
++
++	.PROCEND	
++
++;-----------------------------------------------------------------------------
++;
++;void bn_sqr_comba4(BN_ULONG *r, BN_ULONG *a)
++; arg0 = r_ptr
++; arg1 = a_ptr
++;
++
++bn_sqr_comba4
++	.proc
++	.callinfo FRAME=128,ENTRY_GR=%r3,ARGS_SAVED,ORDERING_AWARE
++	.EXPORT	bn_sqr_comba4,ENTRY,PRIV_LEV=3,NO_RELOCATION,LONG_RETURN
++    .entry
++	.align 64
++    STD     %r3,0(%sp)          ; save r3
++    STD     %r4,8(%sp)          ; save r4
++    STD     %r5,16(%sp)         ; save r5
++    STD     %r6,24(%sp)         ; save r6
++
++	;
++	; Zero out carries
++	;
++	COPY     %r0,c1
++	COPY     %r0,c2
++	COPY     %r0,c3
++
++	LDO      128(%sp),%sp       ; bump stack
++    DEPDI,Z -1,32,33,high_mask   ; Create Mask 0xffffffff80000000L
++    DEPDI,Z  1,31,1,high_one     ; Create Value  1 << 32
++
++	;
++	; Load up all of the values we are going to use
++	;
++    FLDD     0(a_ptr),a0       
++    FLDD     8(a_ptr),a1       
++    FLDD    16(a_ptr),a2       
++    FLDD    24(a_ptr),a3       
++    FLDD    32(a_ptr),a4       
++    FLDD    40(a_ptr),a5       
++    FLDD    48(a_ptr),a6       
++    FLDD    56(a_ptr),a7       
++
++	SQR_ADD_C a0L,a0R,c1,c2,c3
++
++	STD     c1,0(r_ptr)          ; r[0] = c1;
++	COPY    %r0,c1
++
++	SQR_ADD_C2 a1L,a1R,a0L,a0R,c2,c3,c1
++
++	STD     c2,8(r_ptr)          ; r[1] = c2;
++	COPY    %r0,c2
++
++	SQR_ADD_C a1L,a1R,c3,c1,c2
++	SQR_ADD_C2 a2L,a2R,a0L,a0R,c3,c1,c2
++
++	STD     c3,16(r_ptr)            ; r[2] = c3;
++	COPY    %r0,c3
++
++	SQR_ADD_C2 a3L,a3R,a0L,a0R,c1,c2,c3
++	SQR_ADD_C2 a2L,a2R,a1L,a1R,c1,c2,c3
++
++	STD     c1,24(r_ptr)           ; r[3] = c1;
++	COPY    %r0,c1
++
++	SQR_ADD_C a2L,a2R,c2,c3,c1
++	SQR_ADD_C2 a3L,a3R,a1L,a1R,c2,c3,c1
++
++	STD     c2,32(r_ptr)           ; r[4] = c2;
++	COPY    %r0,c2
++
++	SQR_ADD_C2 a3L,a3R,a2L,a2R,c3,c1,c2
++	STD     c3,40(r_ptr)           ; r[5] = c3;
++	COPY    %r0,c3
++
++	SQR_ADD_C a3L,a3R,c1,c2,c3
++	STD     c1,48(r_ptr)           ; r[6] = c1;
++	STD     c2,56(r_ptr)           ; r[7] = c2;
++
++    .EXIT
++    LDD     -104(%sp),%r6        ; restore r6
++    LDD     -112(%sp),%r5        ; restore r5
++    LDD     -120(%sp),%r4        ; restore r4
++    BVE     (%rp)
++    LDD,MB  -128(%sp),%r3
++
++	.PROCEND	
++
++
++;---------------------------------------------------------------------------
++
++MUL_ADD_C  .macro  A0L,A0R,B0L,B0R,C1,C2,C3
++    XMPYU   A0L,B0R,ftemp1        ; m1 = bl*ht
++    FSTD    ftemp1,-16(%sp)       ;
++    XMPYU   A0R,B0L,ftemp2        ; m = bh*lt
++    FSTD    ftemp2,-8(%sp)        ;
++    XMPYU   A0R,B0R,ftemp3        ; lt = bl*lt
++    FSTD    ftemp3,-32(%sp)
++    XMPYU   A0L,B0L,ftemp4        ; ht = bh*ht
++    FSTD    ftemp4,-24(%sp)       ;
++
++    LDD     -8(%sp),m             ; r21 = m
++    LDD     -16(%sp),m1           ; r19 = m1
++    ADD,L   m,m1,m                ; m+m1
++
++    DEPD,Z  m,31,32,temp3         ; (m+m1<<32)
++    LDD     -24(%sp),ht           ; r24 = ht
++
++    CMPCLR,*>>= m,m1,%r0          ; if (m < m1)
++    ADD,L   ht,high_one,ht        ; ht+=high_one
++
++    EXTRD,U m,31,32,temp1         ; m >> 32
++    LDD     -32(%sp),lt           ; lt
++    ADD,L   ht,temp1,ht           ; ht+= m>>32
++    ADD     lt,temp3,lt           ; lt = lt+m1
++    ADD,DC  ht,%r0,ht             ; ht++
++
++    ADD     C1,lt,C1              ; c1=c1+lt
++    ADD,DC  ht,%r0,ht             ; bump c3 if overflow,nullify otherwise
++
++    ADD     C2,ht,C2              ; c2 = c2 + ht
++    ADD,DC  C3,%r0,C3             ; add in carry (c3++)
++.endm
++
++
++;
++;void bn_mul_comba8(BN_ULONG *r, BN_ULONG *a, BN_ULONG *b)
++; arg0 = r_ptr
++; arg1 = a_ptr
++; arg2 = b_ptr
++;
++
++bn_mul_comba8
++	.proc
++	.callinfo FRAME=128,ENTRY_GR=%r3,ARGS_SAVED,ORDERING_AWARE
++	.EXPORT	bn_mul_comba8,ENTRY,PRIV_LEV=3,NO_RELOCATION,LONG_RETURN
++    .entry
++	.align 64
++
++    STD     %r3,0(%sp)          ; save r3
++    STD     %r4,8(%sp)          ; save r4
++    STD     %r5,16(%sp)         ; save r5
++    STD     %r6,24(%sp)         ; save r6
++    FSTD    %fr12,32(%sp)       ; save r6
++    FSTD    %fr13,40(%sp)       ; save r7
++
++	;
++	; Zero out carries
++	;
++	COPY     %r0,c1
++	COPY     %r0,c2
++	COPY     %r0,c3
++
++	LDO      128(%sp),%sp       ; bump stack
++    DEPDI,Z  1,31,1,high_one     ; Create Value  1 << 32
++
++	;
++	; Load up all of the values we are going to use
++	;
++    FLDD      0(a_ptr),a0       
++    FLDD      8(a_ptr),a1       
++    FLDD     16(a_ptr),a2       
++    FLDD     24(a_ptr),a3       
++    FLDD     32(a_ptr),a4       
++    FLDD     40(a_ptr),a5       
++    FLDD     48(a_ptr),a6       
++    FLDD     56(a_ptr),a7       
++
++    FLDD      0(b_ptr),b0       
++    FLDD      8(b_ptr),b1       
++    FLDD     16(b_ptr),b2       
++    FLDD     24(b_ptr),b3       
++    FLDD     32(b_ptr),b4       
++    FLDD     40(b_ptr),b5       
++    FLDD     48(b_ptr),b6       
++    FLDD     56(b_ptr),b7       
++
++	MUL_ADD_C a0L,a0R,b0L,b0R,c1,c2,c3
++	STD       c1,0(r_ptr)
++	COPY      %r0,c1
++
++	MUL_ADD_C a0L,a0R,b1L,b1R,c2,c3,c1
++	MUL_ADD_C a1L,a1R,b0L,b0R,c2,c3,c1
++	STD       c2,8(r_ptr)
++	COPY      %r0,c2
++
++	MUL_ADD_C a2L,a2R,b0L,b0R,c3,c1,c2
++	MUL_ADD_C a1L,a1R,b1L,b1R,c3,c1,c2
++	MUL_ADD_C a0L,a0R,b2L,b2R,c3,c1,c2
++	STD       c3,16(r_ptr)
++	COPY      %r0,c3
++
++	MUL_ADD_C a0L,a0R,b3L,b3R,c1,c2,c3
++	MUL_ADD_C a1L,a1R,b2L,b2R,c1,c2,c3
++	MUL_ADD_C a2L,a2R,b1L,b1R,c1,c2,c3
++	MUL_ADD_C a3L,a3R,b0L,b0R,c1,c2,c3
++	STD       c1,24(r_ptr)
++	COPY      %r0,c1
++
++	MUL_ADD_C a4L,a4R,b0L,b0R,c2,c3,c1
++	MUL_ADD_C a3L,a3R,b1L,b1R,c2,c3,c1
++	MUL_ADD_C a2L,a2R,b2L,b2R,c2,c3,c1
++	MUL_ADD_C a1L,a1R,b3L,b3R,c2,c3,c1
++	MUL_ADD_C a0L,a0R,b4L,b4R,c2,c3,c1
++	STD       c2,32(r_ptr)
++	COPY      %r0,c2
++
++	MUL_ADD_C a0L,a0R,b5L,b5R,c3,c1,c2
++	MUL_ADD_C a1L,a1R,b4L,b4R,c3,c1,c2
++	MUL_ADD_C a2L,a2R,b3L,b3R,c3,c1,c2
++	MUL_ADD_C a3L,a3R,b2L,b2R,c3,c1,c2
++	MUL_ADD_C a4L,a4R,b1L,b1R,c3,c1,c2
++	MUL_ADD_C a5L,a5R,b0L,b0R,c3,c1,c2
++	STD       c3,40(r_ptr)
++	COPY      %r0,c3
++
++	MUL_ADD_C a6L,a6R,b0L,b0R,c1,c2,c3
++	MUL_ADD_C a5L,a5R,b1L,b1R,c1,c2,c3
++	MUL_ADD_C a4L,a4R,b2L,b2R,c1,c2,c3
++	MUL_ADD_C a3L,a3R,b3L,b3R,c1,c2,c3
++	MUL_ADD_C a2L,a2R,b4L,b4R,c1,c2,c3
++	MUL_ADD_C a1L,a1R,b5L,b5R,c1,c2,c3
++	MUL_ADD_C a0L,a0R,b6L,b6R,c1,c2,c3
++	STD       c1,48(r_ptr)
++	COPY      %r0,c1
++	
++	MUL_ADD_C a0L,a0R,b7L,b7R,c2,c3,c1
++	MUL_ADD_C a1L,a1R,b6L,b6R,c2,c3,c1
++	MUL_ADD_C a2L,a2R,b5L,b5R,c2,c3,c1
++	MUL_ADD_C a3L,a3R,b4L,b4R,c2,c3,c1
++	MUL_ADD_C a4L,a4R,b3L,b3R,c2,c3,c1
++	MUL_ADD_C a5L,a5R,b2L,b2R,c2,c3,c1
++	MUL_ADD_C a6L,a6R,b1L,b1R,c2,c3,c1
++	MUL_ADD_C a7L,a7R,b0L,b0R,c2,c3,c1
++	STD       c2,56(r_ptr)
++	COPY      %r0,c2
++
++	MUL_ADD_C a7L,a7R,b1L,b1R,c3,c1,c2
++	MUL_ADD_C a6L,a6R,b2L,b2R,c3,c1,c2
++	MUL_ADD_C a5L,a5R,b3L,b3R,c3,c1,c2
++	MUL_ADD_C a4L,a4R,b4L,b4R,c3,c1,c2
++	MUL_ADD_C a3L,a3R,b5L,b5R,c3,c1,c2
++	MUL_ADD_C a2L,a2R,b6L,b6R,c3,c1,c2
++	MUL_ADD_C a1L,a1R,b7L,b7R,c3,c1,c2
++	STD       c3,64(r_ptr)
++	COPY      %r0,c3
++
++	MUL_ADD_C a2L,a2R,b7L,b7R,c1,c2,c3
++	MUL_ADD_C a3L,a3R,b6L,b6R,c1,c2,c3
++	MUL_ADD_C a4L,a4R,b5L,b5R,c1,c2,c3
++	MUL_ADD_C a5L,a5R,b4L,b4R,c1,c2,c3
++	MUL_ADD_C a6L,a6R,b3L,b3R,c1,c2,c3
++	MUL_ADD_C a7L,a7R,b2L,b2R,c1,c2,c3
++	STD       c1,72(r_ptr)
++	COPY      %r0,c1
++
++	MUL_ADD_C a7L,a7R,b3L,b3R,c2,c3,c1
++	MUL_ADD_C a6L,a6R,b4L,b4R,c2,c3,c1
++	MUL_ADD_C a5L,a5R,b5L,b5R,c2,c3,c1
++	MUL_ADD_C a4L,a4R,b6L,b6R,c2,c3,c1
++	MUL_ADD_C a3L,a3R,b7L,b7R,c2,c3,c1
++	STD       c2,80(r_ptr)
++	COPY      %r0,c2
++
++	MUL_ADD_C a4L,a4R,b7L,b7R,c3,c1,c2
++	MUL_ADD_C a5L,a5R,b6L,b6R,c3,c1,c2
++	MUL_ADD_C a6L,a6R,b5L,b5R,c3,c1,c2
++	MUL_ADD_C a7L,a7R,b4L,b4R,c3,c1,c2
++	STD       c3,88(r_ptr)
++	COPY      %r0,c3
++
++	MUL_ADD_C a7L,a7R,b5L,b5R,c1,c2,c3
++	MUL_ADD_C a6L,a6R,b6L,b6R,c1,c2,c3
++	MUL_ADD_C a5L,a5R,b7L,b7R,c1,c2,c3
++	STD       c1,96(r_ptr)
++	COPY      %r0,c1
++
++	MUL_ADD_C a6L,a6R,b7L,b7R,c2,c3,c1
++	MUL_ADD_C a7L,a7R,b6L,b6R,c2,c3,c1
++	STD       c2,104(r_ptr)
++	COPY      %r0,c2
++
++	MUL_ADD_C a7L,a7R,b7L,b7R,c3,c1,c2
++	STD       c3,112(r_ptr)
++	STD       c1,120(r_ptr)
++
++    .EXIT
++    FLDD    -88(%sp),%fr13 
++    FLDD    -96(%sp),%fr12 
++    LDD     -104(%sp),%r6        ; restore r6
++    LDD     -112(%sp),%r5        ; restore r5
++    LDD     -120(%sp),%r4        ; restore r4
++    BVE     (%rp)
++    LDD,MB  -128(%sp),%r3
++
++	.PROCEND	
++
++;-----------------------------------------------------------------------------
++;
++;void bn_mul_comba4(BN_ULONG *r, BN_ULONG *a, BN_ULONG *b)
++; arg0 = r_ptr
++; arg1 = a_ptr
++; arg2 = b_ptr
++;
++
++bn_mul_comba4
++	.proc
++	.callinfo FRAME=128,ENTRY_GR=%r3,ARGS_SAVED,ORDERING_AWARE
++	.EXPORT	bn_mul_comba4,ENTRY,PRIV_LEV=3,NO_RELOCATION,LONG_RETURN
++    .entry
++	.align 64
++
++    STD     %r3,0(%sp)          ; save r3
++    STD     %r4,8(%sp)          ; save r4
++    STD     %r5,16(%sp)         ; save r5
++    STD     %r6,24(%sp)         ; save r6
++    FSTD    %fr12,32(%sp)       ; save r6
++    FSTD    %fr13,40(%sp)       ; save r7
++
++	;
++	; Zero out carries
++	;
++	COPY     %r0,c1
++	COPY     %r0,c2
++	COPY     %r0,c3
++
++	LDO      128(%sp),%sp       ; bump stack
++    DEPDI,Z  1,31,1,high_one     ; Create Value  1 << 32
++
++	;
++	; Load up all of the values we are going to use
++	;
++    FLDD      0(a_ptr),a0       
++    FLDD      8(a_ptr),a1       
++    FLDD     16(a_ptr),a2       
++    FLDD     24(a_ptr),a3       
++
++    FLDD      0(b_ptr),b0       
++    FLDD      8(b_ptr),b1       
++    FLDD     16(b_ptr),b2       
++    FLDD     24(b_ptr),b3       
++
++	MUL_ADD_C a0L,a0R,b0L,b0R,c1,c2,c3
++	STD       c1,0(r_ptr)
++	COPY      %r0,c1
++
++	MUL_ADD_C a0L,a0R,b1L,b1R,c2,c3,c1
++	MUL_ADD_C a1L,a1R,b0L,b0R,c2,c3,c1
++	STD       c2,8(r_ptr)
++	COPY      %r0,c2
++
++	MUL_ADD_C a2L,a2R,b0L,b0R,c3,c1,c2
++	MUL_ADD_C a1L,a1R,b1L,b1R,c3,c1,c2
++	MUL_ADD_C a0L,a0R,b2L,b2R,c3,c1,c2
++	STD       c3,16(r_ptr)
++	COPY      %r0,c3
++
++	MUL_ADD_C a0L,a0R,b3L,b3R,c1,c2,c3
++	MUL_ADD_C a1L,a1R,b2L,b2R,c1,c2,c3
++	MUL_ADD_C a2L,a2R,b1L,b1R,c1,c2,c3
++	MUL_ADD_C a3L,a3R,b0L,b0R,c1,c2,c3
++	STD       c1,24(r_ptr)
++	COPY      %r0,c1
++
++	MUL_ADD_C a3L,a3R,b1L,b1R,c2,c3,c1
++	MUL_ADD_C a2L,a2R,b2L,b2R,c2,c3,c1
++	MUL_ADD_C a1L,a1R,b3L,b3R,c2,c3,c1
++	STD       c2,32(r_ptr)
++	COPY      %r0,c2
++
++	MUL_ADD_C a2L,a2R,b3L,b3R,c3,c1,c2
++	MUL_ADD_C a3L,a3R,b2L,b2R,c3,c1,c2
++	STD       c3,40(r_ptr)
++	COPY      %r0,c3
++
++	MUL_ADD_C a3L,a3R,b3L,b3R,c1,c2,c3
++	STD       c1,48(r_ptr)
++	STD       c2,56(r_ptr)
++
++    .EXIT
++    FLDD    -88(%sp),%fr13 
++    FLDD    -96(%sp),%fr12 
++    LDD     -104(%sp),%r6        ; restore r6
++    LDD     -112(%sp),%r5        ; restore r5
++    LDD     -120(%sp),%r4        ; restore r4
++    BVE     (%rp)
++    LDD,MB  -128(%sp),%r3
++
++	.PROCEND	
++
++
++	.SPACE	$TEXT$
++	.SUBSPA	$CODE$
++	.SPACE	$PRIVATE$,SORT=16
++	.IMPORT	$global$,DATA
++	.SPACE	$TEXT$
++	.SUBSPA	$CODE$
++	.SUBSPA	$LIT$,ACCESS=0x2c
++C$4
++	.ALIGN	8
++	.STRINGZ	"Division would overflow (%d)\n"
++	.END
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/bn/asm/parisc-mont.pl b/CryptoPkg/Library/OpensslLib/openssl/crypto/bn/asm/parisc-mont.pl
+new file mode 100644
+index 0000000..8aa94e8
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/bn/asm/parisc-mont.pl
+@@ -0,0 +1,1002 @@
++#! /usr/bin/env perl
++# Copyright 2009-2016 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
++# in the file LICENSE in the source distribution or at
++# https://www.openssl.org/source/license.html
++
++
++# ====================================================================
++# Written by Andy Polyakov  for the OpenSSL
++# project. The module is, however, dual licensed under OpenSSL and
++# CRYPTOGAMS licenses depending on where you obtain it. For further
++# details see http://www.openssl.org/~appro/cryptogams/.
++# ====================================================================
++
++# On PA-7100LC this module performs ~90-50% better, less for longer
++# keys, than code generated by gcc 3.2 for PA-RISC 1.1. Latter means
++# that compiler utilized xmpyu instruction to perform 32x32=64-bit
++# multiplication, which in turn means that "baseline" performance was
++# optimal in respect to instruction set capabilities. Fair comparison
++# with vendor compiler is problematic, because OpenSSL doesn't define
++# BN_LLONG [presumably] for historical reasons, which drives compiler
++# toward 4 times 16x16=32-bit multiplicatons [plus complementary
++# shifts and additions] instead. This means that you should observe
++# several times improvement over code generated by vendor compiler
++# for PA-RISC 1.1, but the "baseline" is far from optimal. The actual
++# improvement coefficient was never collected on PA-7100LC, or any
++# other 1.1 CPU, because I don't have access to such machine with
++# vendor compiler. But to give you a taste, PA-RISC 1.1 code path
++# reportedly outperformed code generated by cc +DA1.1 +O3 by factor
++# of ~5x on PA-8600.
++#
++# On PA-RISC 2.0 it has to compete with pa-risc2[W].s, which is
++# reportedly ~2x faster than vendor compiler generated code [according
++# to comment in pa-risc2[W].s]. Here comes a catch. Execution core of
++# this implementation is actually 32-bit one, in the sense that it
++# operates on 32-bit values. But pa-risc2[W].s operates on arrays of
++# 64-bit BN_LONGs... How do they interoperate then? No problem. This
++# module picks halves of 64-bit values in reverse order and pretends
++# they were 32-bit BN_LONGs. But can 32-bit core compete with "pure"
++# 64-bit code such as pa-risc2[W].s then? Well, the thing is that
++# 32x32=64-bit multiplication is the best even PA-RISC 2.0 can do,
++# i.e. there is no "wider" multiplication like on most other 64-bit
++# platforms. This means that even being effectively 32-bit, this
++# implementation performs "64-bit" computational task in same amount
++# of arithmetic operations, most notably multiplications. It requires
++# more memory references, most notably to tp[num], but this doesn't
++# seem to exhaust memory port capacity. And indeed, dedicated PA-RISC
++# 2.0 code path provides virtually same performance as pa-risc2[W].s:
++# it's ~10% better for shortest key length and ~10% worse for longest
++# one.
++#
++# In case it wasn't clear. The module has two distinct code paths:
++# PA-RISC 1.1 and PA-RISC 2.0 ones. Latter features carry-free 64-bit
++# additions and 64-bit integer loads, not to mention specific
++# instruction scheduling. In 64-bit build naturally only 2.0 code path
++# is assembled. In 32-bit application context both code paths are
++# assembled, PA-RISC 2.0 CPU is detected at run-time and proper path
++# is taken automatically. Also, in 32-bit build the module imposes
++# couple of limitations: vector lengths has to be even and vector
++# addresses has to be 64-bit aligned. Normally neither is a problem:
++# most common key lengths are even and vectors are commonly malloc-ed,
++# which ensures alignment.
++#
++# Special thanks to polarhome.com for providing HP-UX account on
++# PA-RISC 1.1 machine, and to correspondent who chose to remain
++# anonymous for testing the code on PA-RISC 2.0 machine.
++
++$0 =~ m/(.*[\/\\])[^\/\\]+$/; $dir=$1;
++
++$flavour = shift;
++$output = shift;
++
++open STDOUT,">$output";
++
++if ($flavour =~ /64/) {
++	$LEVEL		="2.0W";
++	$SIZE_T		=8;
++	$FRAME_MARKER	=80;
++	$SAVED_RP	=16;
++	$PUSH		="std";
++	$PUSHMA		="std,ma";
++	$POP		="ldd";
++	$POPMB		="ldd,mb";
++	$BN_SZ		=$SIZE_T;
++} else {
++	$LEVEL		="1.1";	#$LEVEL.="\n\t.ALLOW\t2.0";
++	$SIZE_T		=4;
++	$FRAME_MARKER	=48;
++	$SAVED_RP	=20;
++	$PUSH		="stw";
++	$PUSHMA		="stwm";
++	$POP		="ldw";
++	$POPMB		="ldwm";
++	$BN_SZ		=$SIZE_T;
++	if (open CONF,"<${dir}../../opensslconf.h") {
++	    while() {
++		if (m/#\s*define\s+SIXTY_FOUR_BIT/) {
++		    $BN_SZ=8;
++		    $LEVEL="2.0";
++		    last;
++		}
++	    }
++	    close CONF;
++	}
++}
++
++$FRAME=8*$SIZE_T+$FRAME_MARKER;	# 8 saved regs + frame marker
++				#                [+ argument transfer]
++$LOCALS=$FRAME-$FRAME_MARKER;
++$FRAME+=32;			# local variables
++
++$tp="%r31";
++$ti1="%r29";
++$ti0="%r28";
++
++$rp="%r26";
++$ap="%r25";
++$bp="%r24";
++$np="%r23";
++$n0="%r22";	# passed through stack in 32-bit
++$num="%r21";	# passed through stack in 32-bit
++$idx="%r20";
++$arrsz="%r19";
++
++$nm1="%r7";
++$nm0="%r6";
++$ab1="%r5";
++$ab0="%r4";
++
++$fp="%r3";
++$hi1="%r2";
++$hi0="%r1";
++
++$xfer=$n0;	# accommodates [-16..15] offset in fld[dw]s
++
++$fm0="%fr4";	$fti=$fm0;
++$fbi="%fr5L";
++$fn0="%fr5R";
++$fai="%fr6";	$fab0="%fr7";	$fab1="%fr8";
++$fni="%fr9";	$fnm0="%fr10";	$fnm1="%fr11";
++
++$code=<<___;
++	.LEVEL	$LEVEL
++	.SPACE	\$TEXT\$
++	.SUBSPA	\$CODE\$,QUAD=0,ALIGN=8,ACCESS=0x2C,CODE_ONLY
++
++	.EXPORT	bn_mul_mont,ENTRY,ARGW0=GR,ARGW1=GR,ARGW2=GR,ARGW3=GR
++	.ALIGN	64
++bn_mul_mont
++	.PROC
++	.CALLINFO	FRAME=`$FRAME-8*$SIZE_T`,NO_CALLS,SAVE_RP,SAVE_SP,ENTRY_GR=6
++	.ENTRY
++	$PUSH	%r2,-$SAVED_RP(%sp)		; standard prologue
++	$PUSHMA	%r3,$FRAME(%sp)
++	$PUSH	%r4,`-$FRAME+1*$SIZE_T`(%sp)
++	$PUSH	%r5,`-$FRAME+2*$SIZE_T`(%sp)
++	$PUSH	%r6,`-$FRAME+3*$SIZE_T`(%sp)
++	$PUSH	%r7,`-$FRAME+4*$SIZE_T`(%sp)
++	$PUSH	%r8,`-$FRAME+5*$SIZE_T`(%sp)
++	$PUSH	%r9,`-$FRAME+6*$SIZE_T`(%sp)
++	$PUSH	%r10,`-$FRAME+7*$SIZE_T`(%sp)
++	ldo	-$FRAME(%sp),$fp
++___
++$code.=<<___ if ($SIZE_T==4);
++	ldw	`-$FRAME_MARKER-4`($fp),$n0
++	ldw	`-$FRAME_MARKER-8`($fp),$num
++	nop
++	nop					; alignment
++___
++$code.=<<___ if ($BN_SZ==4);
++	comiclr,<=	6,$num,%r0		; are vectors long enough?
++	b		L\$abort
++	ldi		0,%r28			; signal "unhandled"
++	add,ev		%r0,$num,$num		; is $num even?
++	b		L\$abort
++	nop
++	or		$ap,$np,$ti1
++	extru,=		$ti1,31,3,%r0		; are ap and np 64-bit aligned?
++	b		L\$abort
++	nop
++	nop					; alignment
++	nop
++
++	fldws		0($n0),${fn0}
++	fldws,ma	4($bp),${fbi}		; bp[0]
++___
++$code.=<<___ if ($BN_SZ==8);
++	comib,>		3,$num,L\$abort		; are vectors long enough?
++	ldi		0,%r28			; signal "unhandled"
++	addl		$num,$num,$num		; I operate on 32-bit values
++
++	fldws		4($n0),${fn0}		; only low part of n0
++	fldws		4($bp),${fbi}		; bp[0] in flipped word order
++___
++$code.=<<___;
++	fldds		0($ap),${fai}		; ap[0,1]
++	fldds		0($np),${fni}		; np[0,1]
++
++	sh2addl		$num,%r0,$arrsz
++	ldi		31,$hi0
++	ldo		36($arrsz),$hi1		; space for tp[num+1]
++	andcm		$hi1,$hi0,$hi1		; align
++	addl		$hi1,%sp,%sp
++	$PUSH		$fp,-$SIZE_T(%sp)
++
++	ldo		`$LOCALS+16`($fp),$xfer
++	ldo		`$LOCALS+32+4`($fp),$tp
++
++	xmpyu		${fai}L,${fbi},${fab0}	; ap[0]*bp[0]
++	xmpyu		${fai}R,${fbi},${fab1}	; ap[1]*bp[0]
++	xmpyu		${fn0},${fab0}R,${fm0}
++
++	addl		$arrsz,$ap,$ap		; point at the end
++	addl		$arrsz,$np,$np
++	subi		0,$arrsz,$idx		; j=0
++	ldo		8($idx),$idx		; j++++
++
++	xmpyu		${fni}L,${fm0}R,${fnm0}	; np[0]*m
++	xmpyu		${fni}R,${fm0}R,${fnm1}	; np[1]*m
++	fstds		${fab0},-16($xfer)
++	fstds		${fnm0},-8($xfer)
++	fstds		${fab1},0($xfer)
++	fstds		${fnm1},8($xfer)
++	 flddx		$idx($ap),${fai}	; ap[2,3]
++	 flddx		$idx($np),${fni}	; np[2,3]
++___
++$code.=<<___ if ($BN_SZ==4);
++	mtctl		$hi0,%cr11		; $hi0 still holds 31
++	extrd,u,*=	$hi0,%sar,1,$hi0	; executes on PA-RISC 1.0
++	b		L\$parisc11
++	nop
++___
++$code.=<<___;					# PA-RISC 2.0 code-path
++	xmpyu		${fai}L,${fbi},${fab0}	; ap[j]*bp[0]
++	xmpyu		${fni}L,${fm0}R,${fnm0}	; np[j]*m
++	ldd		-16($xfer),$ab0
++	fstds		${fab0},-16($xfer)
++
++	extrd,u		$ab0,31,32,$hi0
++	extrd,u		$ab0,63,32,$ab0
++	ldd		-8($xfer),$nm0
++	fstds		${fnm0},-8($xfer)
++	 ldo		8($idx),$idx		; j++++
++	 addl		$ab0,$nm0,$nm0		; low part is discarded
++	 extrd,u	$nm0,31,32,$hi1
++
++L\$1st
++	xmpyu		${fai}R,${fbi},${fab1}	; ap[j+1]*bp[0]
++	xmpyu		${fni}R,${fm0}R,${fnm1}	; np[j+1]*m
++	ldd		0($xfer),$ab1
++	fstds		${fab1},0($xfer)
++	 addl		$hi0,$ab1,$ab1
++	 extrd,u	$ab1,31,32,$hi0
++	ldd		8($xfer),$nm1
++	fstds		${fnm1},8($xfer)
++	 extrd,u	$ab1,63,32,$ab1
++	 addl		$hi1,$nm1,$nm1
++	flddx		$idx($ap),${fai}	; ap[j,j+1]
++	flddx		$idx($np),${fni}	; np[j,j+1]
++	 addl		$ab1,$nm1,$nm1
++	 extrd,u	$nm1,31,32,$hi1
++
++	xmpyu		${fai}L,${fbi},${fab0}	; ap[j]*bp[0]
++	xmpyu		${fni}L,${fm0}R,${fnm0}	; np[j]*m
++	ldd		-16($xfer),$ab0
++	fstds		${fab0},-16($xfer)
++	 addl		$hi0,$ab0,$ab0
++	 extrd,u	$ab0,31,32,$hi0
++	ldd		-8($xfer),$nm0
++	fstds		${fnm0},-8($xfer)
++	 extrd,u	$ab0,63,32,$ab0
++	 addl		$hi1,$nm0,$nm0
++	stw		$nm1,-4($tp)		; tp[j-1]
++	 addl		$ab0,$nm0,$nm0
++	 stw,ma		$nm0,8($tp)		; tp[j-1]
++	addib,<>	8,$idx,L\$1st		; j++++
++	 extrd,u	$nm0,31,32,$hi1
++
++	xmpyu		${fai}R,${fbi},${fab1}	; ap[j]*bp[0]
++	xmpyu		${fni}R,${fm0}R,${fnm1}	; np[j]*m
++	ldd		0($xfer),$ab1
++	fstds		${fab1},0($xfer)
++	 addl		$hi0,$ab1,$ab1
++	 extrd,u	$ab1,31,32,$hi0
++	ldd		8($xfer),$nm1
++	fstds		${fnm1},8($xfer)
++	 extrd,u	$ab1,63,32,$ab1
++	 addl		$hi1,$nm1,$nm1
++	ldd		-16($xfer),$ab0
++	 addl		$ab1,$nm1,$nm1
++	ldd		-8($xfer),$nm0
++	 extrd,u	$nm1,31,32,$hi1
++
++	 addl		$hi0,$ab0,$ab0
++	 extrd,u	$ab0,31,32,$hi0
++	stw		$nm1,-4($tp)		; tp[j-1]
++	 extrd,u	$ab0,63,32,$ab0
++	 addl		$hi1,$nm0,$nm0
++	ldd		0($xfer),$ab1
++	 addl		$ab0,$nm0,$nm0
++	ldd,mb		8($xfer),$nm1
++	 extrd,u	$nm0,31,32,$hi1
++	stw,ma		$nm0,8($tp)		; tp[j-1]
++
++	ldo		-1($num),$num		; i--
++	subi		0,$arrsz,$idx		; j=0
++___
++$code.=<<___ if ($BN_SZ==4);
++	fldws,ma	4($bp),${fbi}		; bp[1]
++___
++$code.=<<___ if ($BN_SZ==8);
++	fldws		0($bp),${fbi}		; bp[1] in flipped word order
++___
++$code.=<<___;
++	 flddx		$idx($ap),${fai}	; ap[0,1]
++	 flddx		$idx($np),${fni}	; np[0,1]
++	 fldws		8($xfer),${fti}R	; tp[0]
++	addl		$hi0,$ab1,$ab1
++	 extrd,u	$ab1,31,32,$hi0
++	 extrd,u	$ab1,63,32,$ab1
++	 ldo		8($idx),$idx		; j++++
++	 xmpyu		${fai}L,${fbi},${fab0}	; ap[0]*bp[1]
++	 xmpyu		${fai}R,${fbi},${fab1}	; ap[1]*bp[1]
++	addl		$hi1,$nm1,$nm1
++	addl		$ab1,$nm1,$nm1
++	extrd,u		$nm1,31,32,$hi1
++	 fstws,mb	${fab0}L,-8($xfer)	; save high part
++	stw		$nm1,-4($tp)		; tp[j-1]
++
++	 fcpy,sgl	%fr0,${fti}L		; zero high part
++	 fcpy,sgl	%fr0,${fab0}L
++	addl		$hi1,$hi0,$hi0
++	extrd,u		$hi0,31,32,$hi1
++	 fcnvxf,dbl,dbl	${fti},${fti}		; 32-bit unsigned int -> double
++	 fcnvxf,dbl,dbl	${fab0},${fab0}
++	stw		$hi0,0($tp)
++	stw		$hi1,4($tp)
++
++	fadd,dbl	${fti},${fab0},${fab0}	; add tp[0]
++	fcnvfx,dbl,dbl	${fab0},${fab0}		; double -> 33-bit unsigned int
++	xmpyu		${fn0},${fab0}R,${fm0}
++	ldo		`$LOCALS+32+4`($fp),$tp
++L\$outer
++	xmpyu		${fni}L,${fm0}R,${fnm0}	; np[0]*m
++	xmpyu		${fni}R,${fm0}R,${fnm1}	; np[1]*m
++	fstds		${fab0},-16($xfer)	; 33-bit value
++	fstds		${fnm0},-8($xfer)
++	 flddx		$idx($ap),${fai}	; ap[2]
++	 flddx		$idx($np),${fni}	; np[2]
++	 ldo		8($idx),$idx		; j++++
++	ldd		-16($xfer),$ab0		; 33-bit value
++	ldd		-8($xfer),$nm0
++	ldw		0($xfer),$hi0		; high part
++
++	xmpyu		${fai}L,${fbi},${fab0}	; ap[j]*bp[i]
++	xmpyu		${fni}L,${fm0}R,${fnm0}	; np[j]*m
++	 extrd,u	$ab0,31,32,$ti0		; carry bit
++	 extrd,u	$ab0,63,32,$ab0
++	fstds		${fab1},0($xfer)
++	 addl		$ti0,$hi0,$hi0		; account carry bit
++	fstds		${fnm1},8($xfer)
++	 addl		$ab0,$nm0,$nm0		; low part is discarded
++	ldw		0($tp),$ti1		; tp[1]
++	 extrd,u	$nm0,31,32,$hi1
++	fstds		${fab0},-16($xfer)
++	fstds		${fnm0},-8($xfer)
++
++L\$inner
++	xmpyu		${fai}R,${fbi},${fab1}	; ap[j+1]*bp[i]
++	xmpyu		${fni}R,${fm0}R,${fnm1}	; np[j+1]*m
++	ldd		0($xfer),$ab1
++	fstds		${fab1},0($xfer)
++	 addl		$hi0,$ti1,$ti1
++	 addl		$ti1,$ab1,$ab1
++	ldd		8($xfer),$nm1
++	fstds		${fnm1},8($xfer)
++	 extrd,u	$ab1,31,32,$hi0
++	 extrd,u	$ab1,63,32,$ab1
++	flddx		$idx($ap),${fai}	; ap[j,j+1]
++	flddx		$idx($np),${fni}	; np[j,j+1]
++	 addl		$hi1,$nm1,$nm1
++	 addl		$ab1,$nm1,$nm1
++	ldw		4($tp),$ti0		; tp[j]
++	stw		$nm1,-4($tp)		; tp[j-1]
++
++	xmpyu		${fai}L,${fbi},${fab0}	; ap[j]*bp[i]
++	xmpyu		${fni}L,${fm0}R,${fnm0}	; np[j]*m
++	ldd		-16($xfer),$ab0
++	fstds		${fab0},-16($xfer)
++	 addl		$hi0,$ti0,$ti0
++	 addl		$ti0,$ab0,$ab0
++	ldd		-8($xfer),$nm0
++	fstds		${fnm0},-8($xfer)
++	 extrd,u	$ab0,31,32,$hi0
++	 extrd,u	$nm1,31,32,$hi1
++	ldw		8($tp),$ti1		; tp[j]
++	 extrd,u	$ab0,63,32,$ab0
++	 addl		$hi1,$nm0,$nm0
++	 addl		$ab0,$nm0,$nm0
++	 stw,ma		$nm0,8($tp)		; tp[j-1]
++	addib,<>	8,$idx,L\$inner		; j++++
++	 extrd,u	$nm0,31,32,$hi1
++
++	xmpyu		${fai}R,${fbi},${fab1}	; ap[j]*bp[i]
++	xmpyu		${fni}R,${fm0}R,${fnm1}	; np[j]*m
++	ldd		0($xfer),$ab1
++	fstds		${fab1},0($xfer)
++	 addl		$hi0,$ti1,$ti1
++	 addl		$ti1,$ab1,$ab1
++	ldd		8($xfer),$nm1
++	fstds		${fnm1},8($xfer)
++	 extrd,u	$ab1,31,32,$hi0
++	 extrd,u	$ab1,63,32,$ab1
++	ldw		4($tp),$ti0		; tp[j]
++	 addl		$hi1,$nm1,$nm1
++	 addl		$ab1,$nm1,$nm1
++	ldd		-16($xfer),$ab0
++	ldd		-8($xfer),$nm0
++	 extrd,u	$nm1,31,32,$hi1
++
++	addl		$hi0,$ab0,$ab0
++	 addl		$ti0,$ab0,$ab0
++	 stw		$nm1,-4($tp)		; tp[j-1]
++	 extrd,u	$ab0,31,32,$hi0
++	ldw		8($tp),$ti1		; tp[j]
++	 extrd,u	$ab0,63,32,$ab0
++	 addl		$hi1,$nm0,$nm0
++	ldd		0($xfer),$ab1
++	 addl		$ab0,$nm0,$nm0
++	ldd,mb		8($xfer),$nm1
++	 extrd,u	$nm0,31,32,$hi1
++	 stw,ma		$nm0,8($tp)		; tp[j-1]
++
++	addib,=		-1,$num,L\$outerdone	; i--
++	subi		0,$arrsz,$idx		; j=0
++___
++$code.=<<___ if ($BN_SZ==4);
++	fldws,ma	4($bp),${fbi}		; bp[i]
++___
++$code.=<<___ if ($BN_SZ==8);
++	ldi		12,$ti0			; bp[i] in flipped word order
++	addl,ev		%r0,$num,$num
++	ldi		-4,$ti0
++	addl		$ti0,$bp,$bp
++	fldws		0($bp),${fbi}
++___
++$code.=<<___;
++	 flddx		$idx($ap),${fai}	; ap[0]
++	addl		$hi0,$ab1,$ab1
++	 flddx		$idx($np),${fni}	; np[0]
++	 fldws		8($xfer),${fti}R	; tp[0]
++	addl		$ti1,$ab1,$ab1
++	extrd,u		$ab1,31,32,$hi0
++	extrd,u		$ab1,63,32,$ab1
++
++	 ldo		8($idx),$idx		; j++++
++	 xmpyu		${fai}L,${fbi},${fab0}	; ap[0]*bp[i]
++	 xmpyu		${fai}R,${fbi},${fab1}	; ap[1]*bp[i]
++	ldw		4($tp),$ti0		; tp[j]
++
++	addl		$hi1,$nm1,$nm1
++	 fstws,mb	${fab0}L,-8($xfer)	; save high part
++	addl		$ab1,$nm1,$nm1
++	extrd,u		$nm1,31,32,$hi1
++	 fcpy,sgl	%fr0,${fti}L		; zero high part
++	 fcpy,sgl	%fr0,${fab0}L
++	stw		$nm1,-4($tp)		; tp[j-1]
++
++	 fcnvxf,dbl,dbl	${fti},${fti}		; 32-bit unsigned int -> double
++	 fcnvxf,dbl,dbl	${fab0},${fab0}
++	addl		$hi1,$hi0,$hi0
++	 fadd,dbl	${fti},${fab0},${fab0}	; add tp[0]
++	addl		$ti0,$hi0,$hi0
++	extrd,u		$hi0,31,32,$hi1
++	 fcnvfx,dbl,dbl	${fab0},${fab0}		; double -> 33-bit unsigned int
++	stw		$hi0,0($tp)
++	stw		$hi1,4($tp)
++	 xmpyu		${fn0},${fab0}R,${fm0}
++
++	b		L\$outer
++	ldo		`$LOCALS+32+4`($fp),$tp
++
++L\$outerdone
++	addl		$hi0,$ab1,$ab1
++	addl		$ti1,$ab1,$ab1
++	extrd,u		$ab1,31,32,$hi0
++	extrd,u		$ab1,63,32,$ab1
++
++	ldw		4($tp),$ti0		; tp[j]
++
++	addl		$hi1,$nm1,$nm1
++	addl		$ab1,$nm1,$nm1
++	extrd,u		$nm1,31,32,$hi1
++	stw		$nm1,-4($tp)		; tp[j-1]
++
++	addl		$hi1,$hi0,$hi0
++	addl		$ti0,$hi0,$hi0
++	extrd,u		$hi0,31,32,$hi1
++	stw		$hi0,0($tp)
++	stw		$hi1,4($tp)
++
++	ldo		`$LOCALS+32`($fp),$tp
++	sub		%r0,%r0,%r0		; clear borrow
++___
++$code.=<<___ if ($BN_SZ==4);
++	ldws,ma		4($tp),$ti0
++	extru,=		$rp,31,3,%r0		; is rp 64-bit aligned?
++	b		L\$sub_pa11
++	addl		$tp,$arrsz,$tp
++L\$sub
++	ldwx		$idx($np),$hi0
++	subb		$ti0,$hi0,$hi1
++	ldwx		$idx($tp),$ti0
++	addib,<>	4,$idx,L\$sub
++	stws,ma		$hi1,4($rp)
++
++	subb		$ti0,%r0,$hi1
++	ldo		-4($tp),$tp
++___
++$code.=<<___ if ($BN_SZ==8);
++	ldd,ma		8($tp),$ti0
++L\$sub
++	ldd		$idx($np),$hi0
++	shrpd		$ti0,$ti0,32,$ti0	; flip word order
++	std		$ti0,-8($tp)		; save flipped value
++	sub,db		$ti0,$hi0,$hi1
++	ldd,ma		8($tp),$ti0
++	addib,<>	8,$idx,L\$sub
++	std,ma		$hi1,8($rp)
++
++	extrd,u		$ti0,31,32,$ti0		; carry in flipped word order
++	sub,db		$ti0,%r0,$hi1
++	ldo		-8($tp),$tp
++___
++$code.=<<___;
++	and		$tp,$hi1,$ap
++	andcm		$rp,$hi1,$bp
++	or		$ap,$bp,$np
++
++	sub		$rp,$arrsz,$rp		; rewind rp
++	subi		0,$arrsz,$idx
++	ldo		`$LOCALS+32`($fp),$tp
++L\$copy
++	ldd		$idx($np),$hi0
++	std,ma		%r0,8($tp)
++	addib,<>	8,$idx,.-8		; L\$copy
++	std,ma		$hi0,8($rp)	
++___
++
++if ($BN_SZ==4) {				# PA-RISC 1.1 code-path
++$ablo=$ab0;
++$abhi=$ab1;
++$nmlo0=$nm0;
++$nmhi0=$nm1;
++$nmlo1="%r9";
++$nmhi1="%r8";
++
++$code.=<<___;
++	b		L\$done
++	nop
++
++	.ALIGN		8
++L\$parisc11
++	xmpyu		${fai}L,${fbi},${fab0}	; ap[j]*bp[0]
++	xmpyu		${fni}L,${fm0}R,${fnm0}	; np[j]*m
++	ldw		-12($xfer),$ablo
++	ldw		-16($xfer),$hi0
++	ldw		-4($xfer),$nmlo0
++	ldw		-8($xfer),$nmhi0
++	fstds		${fab0},-16($xfer)
++	fstds		${fnm0},-8($xfer)
++
++	 ldo		8($idx),$idx		; j++++
++	 add		$ablo,$nmlo0,$nmlo0	; discarded
++	 addc		%r0,$nmhi0,$hi1
++	ldw		4($xfer),$ablo
++	ldw		0($xfer),$abhi
++	nop
++
++L\$1st_pa11
++	xmpyu		${fai}R,${fbi},${fab1}	; ap[j+1]*bp[0]
++	flddx		$idx($ap),${fai}	; ap[j,j+1]
++	xmpyu		${fni}R,${fm0}R,${fnm1}	; np[j+1]*m
++	flddx		$idx($np),${fni}	; np[j,j+1]
++	 add		$hi0,$ablo,$ablo
++	ldw		12($xfer),$nmlo1
++	 addc		%r0,$abhi,$hi0
++	ldw		8($xfer),$nmhi1
++	 add		$ablo,$nmlo1,$nmlo1
++	fstds		${fab1},0($xfer)
++	 addc		%r0,$nmhi1,$nmhi1
++	fstds		${fnm1},8($xfer)
++	 add		$hi1,$nmlo1,$nmlo1
++	ldw		-12($xfer),$ablo
++	 addc		%r0,$nmhi1,$hi1
++	ldw		-16($xfer),$abhi
++
++	xmpyu		${fai}L,${fbi},${fab0}	; ap[j]*bp[0]
++	ldw		-4($xfer),$nmlo0
++	xmpyu		${fni}L,${fm0}R,${fnm0}	; np[j]*m
++	ldw		-8($xfer),$nmhi0
++	 add		$hi0,$ablo,$ablo
++	stw		$nmlo1,-4($tp)		; tp[j-1]
++	 addc		%r0,$abhi,$hi0
++	fstds		${fab0},-16($xfer)
++	 add		$ablo,$nmlo0,$nmlo0
++	fstds		${fnm0},-8($xfer)
++	 addc		%r0,$nmhi0,$nmhi0
++	ldw		0($xfer),$abhi
++	 add		$hi1,$nmlo0,$nmlo0
++	ldw		4($xfer),$ablo
++	 stws,ma	$nmlo0,8($tp)		; tp[j-1]
++	addib,<>	8,$idx,L\$1st_pa11	; j++++
++	 addc		%r0,$nmhi0,$hi1
++
++	 ldw		8($xfer),$nmhi1
++	 ldw		12($xfer),$nmlo1
++	xmpyu		${fai}R,${fbi},${fab1}	; ap[j]*bp[0]
++	xmpyu		${fni}R,${fm0}R,${fnm1}	; np[j]*m
++	 add		$hi0,$ablo,$ablo
++	fstds		${fab1},0($xfer)
++	 addc		%r0,$abhi,$hi0
++	fstds		${fnm1},8($xfer)
++	 add		$ablo,$nmlo1,$nmlo1
++	ldw		-16($xfer),$abhi
++	 addc		%r0,$nmhi1,$nmhi1
++	ldw		-12($xfer),$ablo
++	 add		$hi1,$nmlo1,$nmlo1
++	ldw		-8($xfer),$nmhi0
++	 addc		%r0,$nmhi1,$hi1
++	ldw		-4($xfer),$nmlo0
++
++	 add		$hi0,$ablo,$ablo
++	stw		$nmlo1,-4($tp)		; tp[j-1]
++	 addc		%r0,$abhi,$hi0
++	ldw		0($xfer),$abhi
++	 add		$ablo,$nmlo0,$nmlo0
++	ldw		4($xfer),$ablo
++	 addc		%r0,$nmhi0,$nmhi0
++	ldws,mb		8($xfer),$nmhi1
++	 add		$hi1,$nmlo0,$nmlo0
++	ldw		4($xfer),$nmlo1
++	 addc		%r0,$nmhi0,$hi1
++	stws,ma		$nmlo0,8($tp)		; tp[j-1]
++
++	ldo		-1($num),$num		; i--
++	subi		0,$arrsz,$idx		; j=0
++
++	 fldws,ma	4($bp),${fbi}		; bp[1]
++	 flddx		$idx($ap),${fai}	; ap[0,1]
++	 flddx		$idx($np),${fni}	; np[0,1]
++	 fldws		8($xfer),${fti}R	; tp[0]
++	add		$hi0,$ablo,$ablo
++	addc		%r0,$abhi,$hi0
++	 ldo		8($idx),$idx		; j++++
++	 xmpyu		${fai}L,${fbi},${fab0}	; ap[0]*bp[1]
++	 xmpyu		${fai}R,${fbi},${fab1}	; ap[1]*bp[1]
++	add		$hi1,$nmlo1,$nmlo1
++	addc		%r0,$nmhi1,$nmhi1
++	add		$ablo,$nmlo1,$nmlo1
++	addc		%r0,$nmhi1,$hi1
++	 fstws,mb	${fab0}L,-8($xfer)	; save high part
++	stw		$nmlo1,-4($tp)		; tp[j-1]
++
++	 fcpy,sgl	%fr0,${fti}L		; zero high part
++	 fcpy,sgl	%fr0,${fab0}L
++	add		$hi1,$hi0,$hi0
++	addc		%r0,%r0,$hi1
++	 fcnvxf,dbl,dbl	${fti},${fti}		; 32-bit unsigned int -> double
++	 fcnvxf,dbl,dbl	${fab0},${fab0}
++	stw		$hi0,0($tp)
++	stw		$hi1,4($tp)
++
++	fadd,dbl	${fti},${fab0},${fab0}	; add tp[0]
++	fcnvfx,dbl,dbl	${fab0},${fab0}		; double -> 33-bit unsigned int
++	xmpyu		${fn0},${fab0}R,${fm0}
++	ldo		`$LOCALS+32+4`($fp),$tp
++L\$outer_pa11
++	xmpyu		${fni}L,${fm0}R,${fnm0}	; np[0]*m
++	xmpyu		${fni}R,${fm0}R,${fnm1}	; np[1]*m
++	fstds		${fab0},-16($xfer)	; 33-bit value
++	fstds		${fnm0},-8($xfer)
++	 flddx		$idx($ap),${fai}	; ap[2,3]
++	 flddx		$idx($np),${fni}	; np[2,3]
++	ldw		-16($xfer),$abhi	; carry bit actually
++	 ldo		8($idx),$idx		; j++++
++	ldw		-12($xfer),$ablo
++	ldw		-8($xfer),$nmhi0
++	ldw		-4($xfer),$nmlo0
++	ldw		0($xfer),$hi0		; high part
++
++	xmpyu		${fai}L,${fbi},${fab0}	; ap[j]*bp[i]
++	xmpyu		${fni}L,${fm0}R,${fnm0}	; np[j]*m
++	fstds		${fab1},0($xfer)
++	 addl		$abhi,$hi0,$hi0		; account carry bit
++	fstds		${fnm1},8($xfer)
++	 add		$ablo,$nmlo0,$nmlo0	; discarded
++	ldw		0($tp),$ti1		; tp[1]
++	 addc		%r0,$nmhi0,$hi1
++	fstds		${fab0},-16($xfer)
++	fstds		${fnm0},-8($xfer)
++	ldw		4($xfer),$ablo
++	ldw		0($xfer),$abhi
++
++L\$inner_pa11
++	xmpyu		${fai}R,${fbi},${fab1}	; ap[j+1]*bp[i]
++	flddx		$idx($ap),${fai}	; ap[j,j+1]
++	xmpyu		${fni}R,${fm0}R,${fnm1}	; np[j+1]*m
++	flddx		$idx($np),${fni}	; np[j,j+1]
++	 add		$hi0,$ablo,$ablo
++	ldw		4($tp),$ti0		; tp[j]
++	 addc		%r0,$abhi,$abhi
++	ldw		12($xfer),$nmlo1
++	 add		$ti1,$ablo,$ablo
++	ldw		8($xfer),$nmhi1
++	 addc		%r0,$abhi,$hi0
++	fstds		${fab1},0($xfer)
++	 add		$ablo,$nmlo1,$nmlo1
++	fstds		${fnm1},8($xfer)
++	 addc		%r0,$nmhi1,$nmhi1
++	ldw		-12($xfer),$ablo
++	 add		$hi1,$nmlo1,$nmlo1
++	ldw		-16($xfer),$abhi
++	 addc		%r0,$nmhi1,$hi1
++
++	xmpyu		${fai}L,${fbi},${fab0}	; ap[j]*bp[i]
++	ldw		8($tp),$ti1		; tp[j]
++	xmpyu		${fni}L,${fm0}R,${fnm0}	; np[j]*m
++	ldw		-4($xfer),$nmlo0
++	 add		$hi0,$ablo,$ablo
++	ldw		-8($xfer),$nmhi0
++	 addc		%r0,$abhi,$abhi
++	stw		$nmlo1,-4($tp)		; tp[j-1]
++	 add		$ti0,$ablo,$ablo
++	fstds		${fab0},-16($xfer)
++	 addc		%r0,$abhi,$hi0
++	fstds		${fnm0},-8($xfer)
++	 add		$ablo,$nmlo0,$nmlo0
++	ldw		4($xfer),$ablo
++	 addc		%r0,$nmhi0,$nmhi0
++	ldw		0($xfer),$abhi
++	 add		$hi1,$nmlo0,$nmlo0
++	 stws,ma	$nmlo0,8($tp)		; tp[j-1]
++	addib,<>	8,$idx,L\$inner_pa11	; j++++
++	 addc		%r0,$nmhi0,$hi1
++
++	xmpyu		${fai}R,${fbi},${fab1}	; ap[j]*bp[i]
++	ldw		12($xfer),$nmlo1
++	xmpyu		${fni}R,${fm0}R,${fnm1}	; np[j]*m
++	ldw		8($xfer),$nmhi1
++	 add		$hi0,$ablo,$ablo
++	ldw		4($tp),$ti0		; tp[j]
++	 addc		%r0,$abhi,$abhi
++	fstds		${fab1},0($xfer)
++	 add		$ti1,$ablo,$ablo
++	fstds		${fnm1},8($xfer)
++	 addc		%r0,$abhi,$hi0
++	ldw		-16($xfer),$abhi
++	 add		$ablo,$nmlo1,$nmlo1
++	ldw		-12($xfer),$ablo
++	 addc		%r0,$nmhi1,$nmhi1
++	ldw		-8($xfer),$nmhi0
++	 add		$hi1,$nmlo1,$nmlo1
++	ldw		-4($xfer),$nmlo0
++	 addc		%r0,$nmhi1,$hi1
++
++	add		$hi0,$ablo,$ablo
++	 stw		$nmlo1,-4($tp)		; tp[j-1]
++	addc		%r0,$abhi,$abhi
++	 add		$ti0,$ablo,$ablo
++	ldw		8($tp),$ti1		; tp[j]
++	 addc		%r0,$abhi,$hi0
++	ldw		0($xfer),$abhi
++	 add		$ablo,$nmlo0,$nmlo0
++	ldw		4($xfer),$ablo
++	 addc		%r0,$nmhi0,$nmhi0
++	ldws,mb		8($xfer),$nmhi1
++	 add		$hi1,$nmlo0,$nmlo0
++	ldw		4($xfer),$nmlo1
++	 addc		%r0,$nmhi0,$hi1
++	 stws,ma	$nmlo0,8($tp)		; tp[j-1]
++
++	addib,=		-1,$num,L\$outerdone_pa11; i--
++	subi		0,$arrsz,$idx		; j=0
++
++	 fldws,ma	4($bp),${fbi}		; bp[i]
++	 flddx		$idx($ap),${fai}	; ap[0]
++	add		$hi0,$ablo,$ablo
++	addc		%r0,$abhi,$abhi
++	 flddx		$idx($np),${fni}	; np[0]
++	 fldws		8($xfer),${fti}R	; tp[0]
++	add		$ti1,$ablo,$ablo
++	addc		%r0,$abhi,$hi0
++
++	 ldo		8($idx),$idx		; j++++
++	 xmpyu		${fai}L,${fbi},${fab0}	; ap[0]*bp[i]
++	 xmpyu		${fai}R,${fbi},${fab1}	; ap[1]*bp[i]
++	ldw		4($tp),$ti0		; tp[j]
++
++	add		$hi1,$nmlo1,$nmlo1
++	addc		%r0,$nmhi1,$nmhi1
++	 fstws,mb	${fab0}L,-8($xfer)	; save high part
++	add		$ablo,$nmlo1,$nmlo1
++	addc		%r0,$nmhi1,$hi1
++	 fcpy,sgl	%fr0,${fti}L		; zero high part
++	 fcpy,sgl	%fr0,${fab0}L
++	stw		$nmlo1,-4($tp)		; tp[j-1]
++
++	 fcnvxf,dbl,dbl	${fti},${fti}		; 32-bit unsigned int -> double
++	 fcnvxf,dbl,dbl	${fab0},${fab0}
++	add		$hi1,$hi0,$hi0
++	addc		%r0,%r0,$hi1
++	 fadd,dbl	${fti},${fab0},${fab0}	; add tp[0]
++	add		$ti0,$hi0,$hi0
++	addc		%r0,$hi1,$hi1
++	 fcnvfx,dbl,dbl	${fab0},${fab0}		; double -> 33-bit unsigned int
++	stw		$hi0,0($tp)
++	stw		$hi1,4($tp)
++	 xmpyu		${fn0},${fab0}R,${fm0}
++
++	b		L\$outer_pa11
++	ldo		`$LOCALS+32+4`($fp),$tp
++
++L\$outerdone_pa11
++	add		$hi0,$ablo,$ablo
++	addc		%r0,$abhi,$abhi
++	add		$ti1,$ablo,$ablo
++	addc		%r0,$abhi,$hi0
++
++	ldw		4($tp),$ti0		; tp[j]
++
++	add		$hi1,$nmlo1,$nmlo1
++	addc		%r0,$nmhi1,$nmhi1
++	add		$ablo,$nmlo1,$nmlo1
++	addc		%r0,$nmhi1,$hi1
++	stw		$nmlo1,-4($tp)		; tp[j-1]
++
++	add		$hi1,$hi0,$hi0
++	addc		%r0,%r0,$hi1
++	add		$ti0,$hi0,$hi0
++	addc		%r0,$hi1,$hi1
++	stw		$hi0,0($tp)
++	stw		$hi1,4($tp)
++
++	ldo		`$LOCALS+32+4`($fp),$tp
++	sub		%r0,%r0,%r0		; clear borrow
++	ldw		-4($tp),$ti0
++	addl		$tp,$arrsz,$tp
++L\$sub_pa11
++	ldwx		$idx($np),$hi0
++	subb		$ti0,$hi0,$hi1
++	ldwx		$idx($tp),$ti0
++	addib,<>	4,$idx,L\$sub_pa11
++	stws,ma		$hi1,4($rp)
++
++	subb		$ti0,%r0,$hi1
++	ldo		-4($tp),$tp
++	and		$tp,$hi1,$ap
++	andcm		$rp,$hi1,$bp
++	or		$ap,$bp,$np
++
++	sub		$rp,$arrsz,$rp		; rewind rp
++	subi		0,$arrsz,$idx
++	ldo		`$LOCALS+32`($fp),$tp
++L\$copy_pa11
++	ldwx		$idx($np),$hi0
++	stws,ma		%r0,4($tp)
++	addib,<>	4,$idx,L\$copy_pa11
++	stws,ma		$hi0,4($rp)	
++
++	nop					; alignment
++L\$done
++___
++}
++
++$code.=<<___;
++	ldi		1,%r28			; signal "handled"
++	ldo		$FRAME($fp),%sp		; destroy tp[num+1]
++
++	$POP	`-$FRAME-$SAVED_RP`(%sp),%r2	; standard epilogue
++	$POP	`-$FRAME+1*$SIZE_T`(%sp),%r4
++	$POP	`-$FRAME+2*$SIZE_T`(%sp),%r5
++	$POP	`-$FRAME+3*$SIZE_T`(%sp),%r6
++	$POP	`-$FRAME+4*$SIZE_T`(%sp),%r7
++	$POP	`-$FRAME+5*$SIZE_T`(%sp),%r8
++	$POP	`-$FRAME+6*$SIZE_T`(%sp),%r9
++	$POP	`-$FRAME+7*$SIZE_T`(%sp),%r10
++L\$abort
++	bv	(%r2)
++	.EXIT
++	$POPMB	-$FRAME(%sp),%r3
++	.PROCEND
++	.STRINGZ "Montgomery Multiplication for PA-RISC, CRYPTOGAMS by "
++___
++
++# Explicitly encode PA-RISC 2.0 instructions used in this module, so
++# that it can be compiled with .LEVEL 1.0. It should be noted that I
++# wouldn't have to do this, if GNU assembler understood .ALLOW 2.0
++# directive...
++
++my $ldd = sub {
++  my ($mod,$args) = @_;
++  my $orig = "ldd$mod\t$args";
++
++    if ($args =~ /%r([0-9]+)\(%r([0-9]+)\),%r([0-9]+)/)		# format 4
++    {	my $opcode=(0x03<<26)|($2<<21)|($1<<16)|(3<<6)|$3;
++	sprintf "\t.WORD\t0x%08x\t; %s",$opcode,$orig;
++    }
++    elsif ($args =~ /(\-?[0-9]+)\(%r([0-9]+)\),%r([0-9]+)/)	# format 5
++    {	my $opcode=(0x03<<26)|($2<<21)|(1<<12)|(3<<6)|$3;
++	$opcode|=(($1&0xF)<<17)|(($1&0x10)<<12);		# encode offset
++	$opcode|=(1<<5)  if ($mod =~ /^,m/);
++	$opcode|=(1<<13) if ($mod =~ /^,mb/);
++	sprintf "\t.WORD\t0x%08x\t; %s",$opcode,$orig;
++    }
++    else { "\t".$orig; }
++};
++
++my $std = sub {
++  my ($mod,$args) = @_;
++  my $orig = "std$mod\t$args";
++
++    if ($args =~ /%r([0-9]+),(\-?[0-9]+)\(%r([0-9]+)\)/)	# format 6
++    {	my $opcode=(0x03<<26)|($3<<21)|($1<<16)|(1<<12)|(0xB<<6);
++	$opcode|=(($2&0xF)<<1)|(($2&0x10)>>4);			# encode offset
++	$opcode|=(1<<5)  if ($mod =~ /^,m/);
++	$opcode|=(1<<13) if ($mod =~ /^,mb/);
++	sprintf "\t.WORD\t0x%08x\t; %s",$opcode,$orig;
++    }
++    else { "\t".$orig; }
++};
++
++my $extrd = sub {
++  my ($mod,$args) = @_;
++  my $orig = "extrd$mod\t$args";
++
++    # I only have ",u" completer, it's implicitly encoded...
++    if ($args =~ /%r([0-9]+),([0-9]+),([0-9]+),%r([0-9]+)/)	# format 15
++    {	my $opcode=(0x36<<26)|($1<<21)|($4<<16);
++	my $len=32-$3;
++	$opcode |= (($2&0x20)<<6)|(($2&0x1f)<<5);		# encode pos
++	$opcode |= (($len&0x20)<<7)|($len&0x1f);		# encode len
++	sprintf "\t.WORD\t0x%08x\t; %s",$opcode,$orig;
++    }
++    elsif ($args =~ /%r([0-9]+),%sar,([0-9]+),%r([0-9]+)/)	# format 12
++    {	my $opcode=(0x34<<26)|($1<<21)|($3<<16)|(2<<11)|(1<<9);
++	my $len=32-$2;
++	$opcode |= (($len&0x20)<<3)|($len&0x1f);		# encode len
++	$opcode |= (1<<13) if ($mod =~ /,\**=/);
++	sprintf "\t.WORD\t0x%08x\t; %s",$opcode,$orig;
++    }
++    else { "\t".$orig; }
++};
++
++my $shrpd = sub {
++  my ($mod,$args) = @_;
++  my $orig = "shrpd$mod\t$args";
++
++    if ($args =~ /%r([0-9]+),%r([0-9]+),([0-9]+),%r([0-9]+)/)	# format 14
++    {	my $opcode=(0x34<<26)|($2<<21)|($1<<16)|(1<<10)|$4;
++	my $cpos=63-$3;
++	$opcode |= (($cpos&0x20)<<6)|(($cpos&0x1f)<<5);		# encode sa
++	sprintf "\t.WORD\t0x%08x\t; %s",$opcode,$orig;
++    }
++    else { "\t".$orig; }
++};
++
++my $sub = sub {
++  my ($mod,$args) = @_;
++  my $orig = "sub$mod\t$args";
++
++    if ($mod eq ",db" && $args =~ /%r([0-9]+),%r([0-9]+),%r([0-9]+)/) {
++	my $opcode=(0x02<<26)|($2<<21)|($1<<16)|$3;
++	$opcode|=(1<<10);	# e1
++	$opcode|=(1<<8);	# e2
++	$opcode|=(1<<5);	# d
++	sprintf "\t.WORD\t0x%08x\t; %s",$opcode,$orig
++    }
++    else { "\t".$orig; }
++};
++
++sub assemble {
++  my ($mnemonic,$mod,$args)=@_;
++  my $opcode = eval("\$$mnemonic");
++
++    ref($opcode) eq 'CODE' ? &$opcode($mod,$args) : "\t$mnemonic$mod\t$args";
++}
++
++foreach (split("\n",$code)) {
++	s/\`([^\`]*)\`/eval $1/ge;
++	# flip word order in 64-bit mode...
++	s/(xmpyu\s+)($fai|$fni)([LR])/$1.$2.($3 eq "L"?"R":"L")/e if ($BN_SZ==8);
++	# assemble 2.0 instructions in 32-bit mode...
++	s/^\s+([a-z]+)([\S]*)\s+([\S]*)/&assemble($1,$2,$3)/e if ($BN_SZ==4);
++
++	s/\bbv\b/bve/gm	if ($SIZE_T==8);
++
++	print $_,"\n";
++}
++close STDOUT;
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/bn/asm/ppc-mont.pl b/CryptoPkg/Library/OpensslLib/openssl/crypto/bn/asm/ppc-mont.pl
+new file mode 100644
+index 0000000..5802260
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/bn/asm/ppc-mont.pl
+@@ -0,0 +1,342 @@
++#! /usr/bin/env perl
++# Copyright 2006-2016 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
++# in the file LICENSE in the source distribution or at
++# https://www.openssl.org/source/license.html
++
++
++# ====================================================================
++# Written by Andy Polyakov  for the OpenSSL
++# project. The module is, however, dual licensed under OpenSSL and
++# CRYPTOGAMS licenses depending on where you obtain it. For further
++# details see http://www.openssl.org/~appro/cryptogams/.
++# ====================================================================
++
++# April 2006
++
++# "Teaser" Montgomery multiplication module for PowerPC. It's possible
++# to gain a bit more by modulo-scheduling outer loop, then dedicated
++# squaring procedure should give further 20% and code can be adapted
++# for 32-bit application running on 64-bit CPU. As for the latter.
++# It won't be able to achieve "native" 64-bit performance, because in
++# 32-bit application context every addc instruction will have to be
++# expanded as addc, twice right shift by 32 and finally adde, etc.
++# So far RSA *sign* performance improvement over pre-bn_mul_mont asm
++# for 64-bit application running on PPC970/G5 is:
++#
++# 512-bit	+65%	
++# 1024-bit	+35%
++# 2048-bit	+18%
++# 4096-bit	+4%
++
++$flavour = shift;
++
++if ($flavour =~ /32/) {
++	$BITS=	32;
++	$BNSZ=	$BITS/8;
++	$SIZE_T=4;
++	$RZONE=	224;
++
++	$LD=	"lwz";		# load
++	$LDU=	"lwzu";		# load and update
++	$LDX=	"lwzx";		# load indexed
++	$ST=	"stw";		# store
++	$STU=	"stwu";		# store and update
++	$STX=	"stwx";		# store indexed
++	$STUX=	"stwux";	# store indexed and update
++	$UMULL=	"mullw";	# unsigned multiply low
++	$UMULH=	"mulhwu";	# unsigned multiply high
++	$UCMP=	"cmplw";	# unsigned compare
++	$SHRI=	"srwi";		# unsigned shift right by immediate	
++	$PUSH=	$ST;
++	$POP=	$LD;
++} elsif ($flavour =~ /64/) {
++	$BITS=	64;
++	$BNSZ=	$BITS/8;
++	$SIZE_T=8;
++	$RZONE=	288;
++
++	# same as above, but 64-bit mnemonics...
++	$LD=	"ld";		# load
++	$LDU=	"ldu";		# load and update
++	$LDX=	"ldx";		# load indexed
++	$ST=	"std";		# store
++	$STU=	"stdu";		# store and update
++	$STX=	"stdx";		# store indexed
++	$STUX=	"stdux";	# store indexed and update
++	$UMULL=	"mulld";	# unsigned multiply low
++	$UMULH=	"mulhdu";	# unsigned multiply high
++	$UCMP=	"cmpld";	# unsigned compare
++	$SHRI=	"srdi";		# unsigned shift right by immediate	
++	$PUSH=	$ST;
++	$POP=	$LD;
++} else { die "nonsense $flavour"; }
++
++$FRAME=8*$SIZE_T+$RZONE;
++$LOCALS=8*$SIZE_T;
++
++$0 =~ m/(.*[\/\\])[^\/\\]+$/; $dir=$1;
++( $xlate="${dir}ppc-xlate.pl" and -f $xlate ) or
++( $xlate="${dir}../../perlasm/ppc-xlate.pl" and -f $xlate) or
++die "can't locate ppc-xlate.pl";
++
++open STDOUT,"| $^X $xlate $flavour ".shift || die "can't call $xlate: $!";
++
++$sp="r1";
++$toc="r2";
++$rp="r3";	$ovf="r3";
++$ap="r4";
++$bp="r5";
++$np="r6";
++$n0="r7";
++$num="r8";
++$rp="r9";	# $rp is reassigned
++$aj="r10";
++$nj="r11";
++$tj="r12";
++# non-volatile registers
++$i="r20";
++$j="r21";
++$tp="r22";
++$m0="r23";
++$m1="r24";
++$lo0="r25";
++$hi0="r26";
++$lo1="r27";
++$hi1="r28";
++$alo="r29";
++$ahi="r30";
++$nlo="r31";
++#
++$nhi="r0";
++
++$code=<<___;
++.machine "any"
++.text
++
++.globl	.bn_mul_mont_int
++.align	4
++.bn_mul_mont_int:
++	cmpwi	$num,4
++	mr	$rp,r3		; $rp is reassigned
++	li	r3,0
++	bltlr
++___
++$code.=<<___ if ($BNSZ==4);
++	cmpwi	$num,32		; longer key performance is not better
++	bgelr
++___
++$code.=<<___;
++	slwi	$num,$num,`log($BNSZ)/log(2)`
++	li	$tj,-4096
++	addi	$ovf,$num,$FRAME
++	subf	$ovf,$ovf,$sp	; $sp-$ovf
++	and	$ovf,$ovf,$tj	; minimize TLB usage
++	subf	$ovf,$sp,$ovf	; $ovf-$sp
++	mr	$tj,$sp
++	srwi	$num,$num,`log($BNSZ)/log(2)`
++	$STUX	$sp,$sp,$ovf
++
++	$PUSH	r20,`-12*$SIZE_T`($tj)
++	$PUSH	r21,`-11*$SIZE_T`($tj)
++	$PUSH	r22,`-10*$SIZE_T`($tj)
++	$PUSH	r23,`-9*$SIZE_T`($tj)
++	$PUSH	r24,`-8*$SIZE_T`($tj)
++	$PUSH	r25,`-7*$SIZE_T`($tj)
++	$PUSH	r26,`-6*$SIZE_T`($tj)
++	$PUSH	r27,`-5*$SIZE_T`($tj)
++	$PUSH	r28,`-4*$SIZE_T`($tj)
++	$PUSH	r29,`-3*$SIZE_T`($tj)
++	$PUSH	r30,`-2*$SIZE_T`($tj)
++	$PUSH	r31,`-1*$SIZE_T`($tj)
++
++	$LD	$n0,0($n0)	; pull n0[0] value
++	addi	$num,$num,-2	; adjust $num for counter register
++
++	$LD	$m0,0($bp)	; m0=bp[0]
++	$LD	$aj,0($ap)	; ap[0]
++	addi	$tp,$sp,$LOCALS
++	$UMULL	$lo0,$aj,$m0	; ap[0]*bp[0]
++	$UMULH	$hi0,$aj,$m0
++
++	$LD	$aj,$BNSZ($ap)	; ap[1]
++	$LD	$nj,0($np)	; np[0]
++
++	$UMULL	$m1,$lo0,$n0	; "tp[0]"*n0
++
++	$UMULL	$alo,$aj,$m0	; ap[1]*bp[0]
++	$UMULH	$ahi,$aj,$m0
++
++	$UMULL	$lo1,$nj,$m1	; np[0]*m1
++	$UMULH	$hi1,$nj,$m1
++	$LD	$nj,$BNSZ($np)	; np[1]
++	addc	$lo1,$lo1,$lo0
++	addze	$hi1,$hi1
++
++	$UMULL	$nlo,$nj,$m1	; np[1]*m1
++	$UMULH	$nhi,$nj,$m1
++
++	mtctr	$num
++	li	$j,`2*$BNSZ`
++.align	4
++L1st:
++	$LDX	$aj,$ap,$j	; ap[j]
++	addc	$lo0,$alo,$hi0
++	$LDX	$nj,$np,$j	; np[j]
++	addze	$hi0,$ahi
++	$UMULL	$alo,$aj,$m0	; ap[j]*bp[0]
++	addc	$lo1,$nlo,$hi1
++	$UMULH	$ahi,$aj,$m0
++	addze	$hi1,$nhi
++	$UMULL	$nlo,$nj,$m1	; np[j]*m1
++	addc	$lo1,$lo1,$lo0	; np[j]*m1+ap[j]*bp[0]
++	$UMULH	$nhi,$nj,$m1
++	addze	$hi1,$hi1
++	$ST	$lo1,0($tp)	; tp[j-1]
++
++	addi	$j,$j,$BNSZ	; j++
++	addi	$tp,$tp,$BNSZ	; tp++
++	bdnz	L1st
++;L1st
++	addc	$lo0,$alo,$hi0
++	addze	$hi0,$ahi
++
++	addc	$lo1,$nlo,$hi1
++	addze	$hi1,$nhi
++	addc	$lo1,$lo1,$lo0	; np[j]*m1+ap[j]*bp[0]
++	addze	$hi1,$hi1
++	$ST	$lo1,0($tp)	; tp[j-1]
++
++	li	$ovf,0
++	addc	$hi1,$hi1,$hi0
++	addze	$ovf,$ovf	; upmost overflow bit
++	$ST	$hi1,$BNSZ($tp)
++
++	li	$i,$BNSZ
++.align	4
++Louter:
++	$LDX	$m0,$bp,$i	; m0=bp[i]
++	$LD	$aj,0($ap)	; ap[0]
++	addi	$tp,$sp,$LOCALS
++	$LD	$tj,$LOCALS($sp); tp[0]
++	$UMULL	$lo0,$aj,$m0	; ap[0]*bp[i]
++	$UMULH	$hi0,$aj,$m0
++	$LD	$aj,$BNSZ($ap)	; ap[1]
++	$LD	$nj,0($np)	; np[0]
++	addc	$lo0,$lo0,$tj	; ap[0]*bp[i]+tp[0]
++	$UMULL	$alo,$aj,$m0	; ap[j]*bp[i]
++	addze	$hi0,$hi0
++	$UMULL	$m1,$lo0,$n0	; tp[0]*n0
++	$UMULH	$ahi,$aj,$m0
++	$UMULL	$lo1,$nj,$m1	; np[0]*m1
++	$UMULH	$hi1,$nj,$m1
++	$LD	$nj,$BNSZ($np)	; np[1]
++	addc	$lo1,$lo1,$lo0
++	$UMULL	$nlo,$nj,$m1	; np[1]*m1
++	addze	$hi1,$hi1
++	$UMULH	$nhi,$nj,$m1
++
++	mtctr	$num
++	li	$j,`2*$BNSZ`
++.align	4
++Linner:
++	$LDX	$aj,$ap,$j	; ap[j]
++	addc	$lo0,$alo,$hi0
++	$LD	$tj,$BNSZ($tp)	; tp[j]
++	addze	$hi0,$ahi
++	$LDX	$nj,$np,$j	; np[j]
++	addc	$lo1,$nlo,$hi1
++	$UMULL	$alo,$aj,$m0	; ap[j]*bp[i]
++	addze	$hi1,$nhi
++	$UMULH	$ahi,$aj,$m0
++	addc	$lo0,$lo0,$tj	; ap[j]*bp[i]+tp[j]
++	$UMULL	$nlo,$nj,$m1	; np[j]*m1
++	addze	$hi0,$hi0
++	$UMULH	$nhi,$nj,$m1
++	addc	$lo1,$lo1,$lo0	; np[j]*m1+ap[j]*bp[i]+tp[j]
++	addi	$j,$j,$BNSZ	; j++
++	addze	$hi1,$hi1
++	$ST	$lo1,0($tp)	; tp[j-1]
++	addi	$tp,$tp,$BNSZ	; tp++
++	bdnz	Linner
++;Linner
++	$LD	$tj,$BNSZ($tp)	; tp[j]
++	addc	$lo0,$alo,$hi0
++	addze	$hi0,$ahi
++	addc	$lo0,$lo0,$tj	; ap[j]*bp[i]+tp[j]
++	addze	$hi0,$hi0
++
++	addc	$lo1,$nlo,$hi1
++	addze	$hi1,$nhi
++	addc	$lo1,$lo1,$lo0	; np[j]*m1+ap[j]*bp[i]+tp[j]
++	addze	$hi1,$hi1
++	$ST	$lo1,0($tp)	; tp[j-1]
++
++	addic	$ovf,$ovf,-1	; move upmost overflow to XER[CA]
++	li	$ovf,0
++	adde	$hi1,$hi1,$hi0
++	addze	$ovf,$ovf
++	$ST	$hi1,$BNSZ($tp)
++;
++	slwi	$tj,$num,`log($BNSZ)/log(2)`
++	$UCMP	$i,$tj
++	addi	$i,$i,$BNSZ
++	ble	Louter
++
++	addi	$num,$num,2	; restore $num
++	subfc	$j,$j,$j	; j=0 and "clear" XER[CA]
++	addi	$tp,$sp,$LOCALS
++	mtctr	$num
++
++.align	4
++Lsub:	$LDX	$tj,$tp,$j
++	$LDX	$nj,$np,$j
++	subfe	$aj,$nj,$tj	; tp[j]-np[j]
++	$STX	$aj,$rp,$j
++	addi	$j,$j,$BNSZ
++	bdnz	Lsub
++
++	li	$j,0
++	mtctr	$num
++	subfe	$ovf,$j,$ovf	; handle upmost overflow bit
++	and	$ap,$tp,$ovf
++	andc	$np,$rp,$ovf
++	or	$ap,$ap,$np	; ap=borrow?tp:rp
++
++.align	4
++Lcopy:				; copy or in-place refresh
++	$LDX	$tj,$ap,$j
++	$STX	$tj,$rp,$j
++	$STX	$j,$tp,$j	; zap at once
++	addi	$j,$j,$BNSZ
++	bdnz	Lcopy
++
++	$POP	$tj,0($sp)
++	li	r3,1
++	$POP	r20,`-12*$SIZE_T`($tj)
++	$POP	r21,`-11*$SIZE_T`($tj)
++	$POP	r22,`-10*$SIZE_T`($tj)
++	$POP	r23,`-9*$SIZE_T`($tj)
++	$POP	r24,`-8*$SIZE_T`($tj)
++	$POP	r25,`-7*$SIZE_T`($tj)
++	$POP	r26,`-6*$SIZE_T`($tj)
++	$POP	r27,`-5*$SIZE_T`($tj)
++	$POP	r28,`-4*$SIZE_T`($tj)
++	$POP	r29,`-3*$SIZE_T`($tj)
++	$POP	r30,`-2*$SIZE_T`($tj)
++	$POP	r31,`-1*$SIZE_T`($tj)
++	mr	$sp,$tj
++	blr
++	.long	0
++	.byte	0,12,4,0,0x80,12,6,0
++	.long	0
++.size	.bn_mul_mont_int,.-.bn_mul_mont_int
++
++.asciz  "Montgomery Multiplication for PPC, CRYPTOGAMS by "
++___
++
++$code =~ s/\`([^\`]*)\`/eval $1/gem;
++print $code;
++close STDOUT;
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/bn/asm/ppc.pl b/CryptoPkg/Library/OpensslLib/openssl/crypto/bn/asm/ppc.pl
+new file mode 100644
+index 0000000..4ea534a
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/bn/asm/ppc.pl
+@@ -0,0 +1,2014 @@
++#! /usr/bin/env perl
++# Copyright 2004-2016 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
++# in the file LICENSE in the source distribution or at
++# https://www.openssl.org/source/license.html
++
++# Implemented as a Perl wrapper as we want to support several different
++# architectures with single file. We pick up the target based on the
++# file name we are asked to generate.
++#
++# It should be noted though that this perl code is nothing like
++# /crypto/perlasm/x86*. In this case perl is used pretty much
++# as pre-processor to cover for platform differences in name decoration,
++# linker tables, 32-/64-bit instruction sets...
++#
++# As you might know there're several PowerPC ABI in use. Most notably
++# Linux and AIX use different 32-bit ABIs. Good news are that these ABIs
++# are similar enough to implement leaf(!) functions, which would be ABI
++# neutral. And that's what you find here: ABI neutral leaf functions.
++# In case you wonder what that is...
++#
++#       AIX performance
++#
++#	MEASUREMENTS WITH cc ON a 200 MhZ PowerPC 604e.
++#
++#	The following is the performance of 32-bit compiler
++#	generated code:
++#
++#	OpenSSL 0.9.6c 21 dec 2001
++#	built on: Tue Jun 11 11:06:51 EDT 2002
++#	options:bn(64,32) ...
++#compiler: cc -DTHREADS  -DAIX -DB_ENDIAN -DBN_LLONG -O3
++#                  sign    verify    sign/s verify/s
++#rsa  512 bits   0.0098s   0.0009s    102.0   1170.6
++#rsa 1024 bits   0.0507s   0.0026s     19.7    387.5
++#rsa 2048 bits   0.3036s   0.0085s      3.3    117.1
++#rsa 4096 bits   2.0040s   0.0299s      0.5     33.4
++#dsa  512 bits   0.0087s   0.0106s    114.3     94.5
++#dsa 1024 bits   0.0256s   0.0313s     39.0     32.0	
++#
++#	Same bechmark with this assembler code:
++#
++#rsa  512 bits   0.0056s   0.0005s    178.6   2049.2
++#rsa 1024 bits   0.0283s   0.0015s     35.3    674.1
++#rsa 2048 bits   0.1744s   0.0050s      5.7    201.2
++#rsa 4096 bits   1.1644s   0.0179s      0.9     55.7
++#dsa  512 bits   0.0052s   0.0062s    191.6    162.0
++#dsa 1024 bits   0.0149s   0.0180s     67.0     55.5
++#
++#	Number of operations increases by at almost 75%
++#
++#	Here are performance numbers for 64-bit compiler
++#	generated code:
++#
++#	OpenSSL 0.9.6g [engine] 9 Aug 2002
++#	built on: Fri Apr 18 16:59:20 EDT 2003
++#	options:bn(64,64) ...
++#	compiler: cc -DTHREADS -D_REENTRANT -q64 -DB_ENDIAN -O3
++#                  sign    verify    sign/s verify/s
++#rsa  512 bits   0.0028s   0.0003s    357.1   3844.4
++#rsa 1024 bits   0.0148s   0.0008s     67.5   1239.7
++#rsa 2048 bits   0.0963s   0.0028s     10.4    353.0
++#rsa 4096 bits   0.6538s   0.0102s      1.5     98.1
++#dsa  512 bits   0.0026s   0.0032s    382.5    313.7
++#dsa 1024 bits   0.0081s   0.0099s    122.8    100.6
++#
++#	Same benchmark with this assembler code:
++#
++#rsa  512 bits   0.0020s   0.0002s    510.4   6273.7
++#rsa 1024 bits   0.0088s   0.0005s    114.1   2128.3
++#rsa 2048 bits   0.0540s   0.0016s     18.5    622.5
++#rsa 4096 bits   0.3700s   0.0058s      2.7    171.0
++#dsa  512 bits   0.0016s   0.0020s    610.7    507.1
++#dsa 1024 bits   0.0047s   0.0058s    212.5    173.2
++#	
++#	Again, performance increases by at about 75%
++#
++#       Mac OS X, Apple G5 1.8GHz (Note this is 32 bit code)
++#       OpenSSL 0.9.7c 30 Sep 2003
++#
++#       Original code.
++#
++#rsa  512 bits   0.0011s   0.0001s    906.1  11012.5
++#rsa 1024 bits   0.0060s   0.0003s    166.6   3363.1
++#rsa 2048 bits   0.0370s   0.0010s     27.1    982.4
++#rsa 4096 bits   0.2426s   0.0036s      4.1    280.4
++#dsa  512 bits   0.0010s   0.0012s   1038.1    841.5
++#dsa 1024 bits   0.0030s   0.0037s    329.6    269.7
++#dsa 2048 bits   0.0101s   0.0127s     98.9     78.6
++#
++#       Same benchmark with this assembler code:
++#
++#rsa  512 bits   0.0007s   0.0001s   1416.2  16645.9
++#rsa 1024 bits   0.0036s   0.0002s    274.4   5380.6
++#rsa 2048 bits   0.0222s   0.0006s     45.1   1589.5
++#rsa 4096 bits   0.1469s   0.0022s      6.8    449.6
++#dsa  512 bits   0.0006s   0.0007s   1664.2   1376.2
++#dsa 1024 bits   0.0018s   0.0023s    545.0    442.2
++#dsa 2048 bits   0.0061s   0.0075s    163.5    132.8
++#
++#        Performance increase of ~60%
++#
++#	If you have comments or suggestions to improve code send
++#	me a note at schari@us.ibm.com
++#
++
++$flavour = shift;
++
++if ($flavour =~ /32/) {
++	$BITS=	32;
++	$BNSZ=	$BITS/8;
++	$ISA=	"\"ppc\"";
++
++	$LD=	"lwz";		# load
++	$LDU=	"lwzu";		# load and update
++	$ST=	"stw";		# store
++	$STU=	"stwu";		# store and update
++	$UMULL=	"mullw";	# unsigned multiply low
++	$UMULH=	"mulhwu";	# unsigned multiply high
++	$UDIV=	"divwu";	# unsigned divide
++	$UCMPI=	"cmplwi";	# unsigned compare with immediate
++	$UCMP=	"cmplw";	# unsigned compare
++	$CNTLZ=	"cntlzw";	# count leading zeros
++	$SHL=	"slw";		# shift left
++	$SHR=	"srw";		# unsigned shift right
++	$SHRI=	"srwi";		# unsigned shift right by immediate	
++	$SHLI=	"slwi";		# shift left by immediate
++	$CLRU=	"clrlwi";	# clear upper bits
++	$INSR=	"insrwi";	# insert right
++	$ROTL=	"rotlwi";	# rotate left by immediate
++	$TR=	"tw";		# conditional trap
++} elsif ($flavour =~ /64/) {
++	$BITS=	64;
++	$BNSZ=	$BITS/8;
++	$ISA=	"\"ppc64\"";
++
++	# same as above, but 64-bit mnemonics...
++	$LD=	"ld";		# load
++	$LDU=	"ldu";		# load and update
++	$ST=	"std";		# store
++	$STU=	"stdu";		# store and update
++	$UMULL=	"mulld";	# unsigned multiply low
++	$UMULH=	"mulhdu";	# unsigned multiply high
++	$UDIV=	"divdu";	# unsigned divide
++	$UCMPI=	"cmpldi";	# unsigned compare with immediate
++	$UCMP=	"cmpld";	# unsigned compare
++	$CNTLZ=	"cntlzd";	# count leading zeros
++	$SHL=	"sld";		# shift left
++	$SHR=	"srd";		# unsigned shift right
++	$SHRI=	"srdi";		# unsigned shift right by immediate	
++	$SHLI=	"sldi";		# shift left by immediate
++	$CLRU=	"clrldi";	# clear upper bits
++	$INSR=	"insrdi";	# insert right 
++	$ROTL=	"rotldi";	# rotate left by immediate
++	$TR=	"td";		# conditional trap
++} else { die "nonsense $flavour"; }
++
++$0 =~ m/(.*[\/\\])[^\/\\]+$/; $dir=$1;
++( $xlate="${dir}ppc-xlate.pl" and -f $xlate ) or
++( $xlate="${dir}../../perlasm/ppc-xlate.pl" and -f $xlate) or
++die "can't locate ppc-xlate.pl";
++
++open STDOUT,"| $^X $xlate $flavour ".shift || die "can't call $xlate: $!";
++
++$data=< 0 then result !=0
++				# In either case carry bit is set.
++	beq	Lppcasm_sub_adios
++	addi	r4,r4,-$BNSZ
++	addi	r3,r3,-$BNSZ
++	addi	r5,r5,-$BNSZ
++	mtctr	r6
++Lppcasm_sub_mainloop:	
++	$LDU	r7,$BNSZ(r4)
++	$LDU	r8,$BNSZ(r5)
++	subfe	r6,r8,r7	# r6 = r7+carry bit + onescomplement(r8)
++				# if carry = 1 this is r7-r8. Else it
++				# is r7-r8 -1 as we need.
++	$STU	r6,$BNSZ(r3)
++	bdnz	Lppcasm_sub_mainloop
++Lppcasm_sub_adios:	
++	subfze	r3,r0		# if carry bit is set then r3 = 0 else -1
++	andi.	r3,r3,1         # keep only last bit.
++	blr
++	.long	0
++	.byte	0,12,0x14,0,0,0,4,0
++	.long	0
++.size	.bn_sub_words,.-.bn_sub_words
++
++#
++#	NOTE:	The following label name should be changed to
++#		"bn_add_words" i.e. remove the first dot
++#		for the gcc compiler. This should be automatically
++#		done in the build
++#
++
++.align	4
++.bn_add_words:
++#
++#	Handcoded version of bn_add_words
++#
++#BN_ULONG bn_add_words(BN_ULONG *r, BN_ULONG *a, BN_ULONG *b, int n)
++#
++#	r3 = r
++#	r4 = a
++#	r5 = b
++#	r6 = n
++#
++#       Note:	No loop unrolling done since this is not a performance
++#               critical loop.
++
++	xor	r0,r0,r0
++#
++#	check for r6 = 0. Is this needed?
++#
++	addic.	r6,r6,0		#test r6 and clear carry bit.
++	beq	Lppcasm_add_adios
++	addi	r4,r4,-$BNSZ
++	addi	r3,r3,-$BNSZ
++	addi	r5,r5,-$BNSZ
++	mtctr	r6
++Lppcasm_add_mainloop:	
++	$LDU	r7,$BNSZ(r4)
++	$LDU	r8,$BNSZ(r5)
++	adde	r8,r7,r8
++	$STU	r8,$BNSZ(r3)
++	bdnz	Lppcasm_add_mainloop
++Lppcasm_add_adios:	
++	addze	r3,r0			#return carry bit.
++	blr
++	.long	0
++	.byte	0,12,0x14,0,0,0,4,0
++	.long	0
++.size	.bn_add_words,.-.bn_add_words
++
++#
++#	NOTE:	The following label name should be changed to
++#		"bn_div_words" i.e. remove the first dot
++#		for the gcc compiler. This should be automatically
++#		done in the build
++#
++
++.align	4
++.bn_div_words:
++#
++#	This is a cleaned up version of code generated by
++#	the AIX compiler. The only optimization is to use
++#	the PPC instruction to count leading zeros instead
++#	of call to num_bits_word. Since this was compiled
++#	only at level -O2 we can possibly squeeze it more?
++#	
++#	r3 = h
++#	r4 = l
++#	r5 = d
++	
++	$UCMPI	0,r5,0			# compare r5 and 0
++	bne	Lppcasm_div1		# proceed if d!=0
++	li	r3,-1			# d=0 return -1
++	blr
++Lppcasm_div1:
++	xor	r0,r0,r0		#r0=0
++	li	r8,$BITS
++	$CNTLZ.	r7,r5			#r7 = num leading 0s in d.
++	beq	Lppcasm_div2		#proceed if no leading zeros
++	subf	r8,r7,r8		#r8 = BN_num_bits_word(d)
++	$SHR.	r9,r3,r8		#are there any bits above r8'th?
++	$TR	16,r9,r0		#if there're, signal to dump core...
++Lppcasm_div2:
++	$UCMP	0,r3,r5			#h>=d?
++	blt	Lppcasm_div3		#goto Lppcasm_div3 if not
++	subf	r3,r5,r3		#h-=d ; 
++Lppcasm_div3:				#r7 = BN_BITS2-i. so r7=i
++	cmpi	0,0,r7,0		# is (i == 0)?
++	beq	Lppcasm_div4
++	$SHL	r3,r3,r7		# h = (h<< i)
++	$SHR	r8,r4,r8		# r8 = (l >> BN_BITS2 -i)
++	$SHL	r5,r5,r7		# d<<=i
++	or	r3,r3,r8		# h = (h<>(BN_BITS2-i))
++	$SHL	r4,r4,r7		# l <<=i
++Lppcasm_div4:
++	$SHRI	r9,r5,`$BITS/2`		# r9 = dh
++					# dl will be computed when needed
++					# as it saves registers.
++	li	r6,2			#r6=2
++	mtctr	r6			#counter will be in count.
++Lppcasm_divouterloop: 
++	$SHRI	r8,r3,`$BITS/2`		#r8 = (h>>BN_BITS4)
++	$SHRI	r11,r4,`$BITS/2`	#r11= (l&BN_MASK2h)>>BN_BITS4
++					# compute here for innerloop.
++	$UCMP	0,r8,r9			# is (h>>BN_BITS4)==dh
++	bne	Lppcasm_div5		# goto Lppcasm_div5 if not
++
++	li	r8,-1
++	$CLRU	r8,r8,`$BITS/2`		#q = BN_MASK2l 
++	b	Lppcasm_div6
++Lppcasm_div5:
++	$UDIV	r8,r3,r9		#q = h/dh
++Lppcasm_div6:
++	$UMULL	r12,r9,r8		#th = q*dh
++	$CLRU	r10,r5,`$BITS/2`	#r10=dl
++	$UMULL	r6,r8,r10		#tl = q*dl
++	
++Lppcasm_divinnerloop:
++	subf	r10,r12,r3		#t = h -th
++	$SHRI	r7,r10,`$BITS/2`	#r7= (t &BN_MASK2H), sort of...
++	addic.	r7,r7,0			#test if r7 == 0. used below.
++					# now want to compute
++					# r7 = (t<>BN_BITS4)
++					# the following 2 instructions do that
++	$SHLI	r7,r10,`$BITS/2`	# r7 = (t<>BN_BITS4)
++	$UCMP	cr1,r6,r7		# compare (tl <= r7)
++	bne	Lppcasm_divinnerexit
++	ble	cr1,Lppcasm_divinnerexit
++	addi	r8,r8,-1		#q--
++	subf	r12,r9,r12		#th -=dh
++	$CLRU	r10,r5,`$BITS/2`	#r10=dl. t is no longer needed in loop.
++	subf	r6,r10,r6		#tl -=dl
++	b	Lppcasm_divinnerloop
++Lppcasm_divinnerexit:
++	$SHRI	r10,r6,`$BITS/2`	#t=(tl>>BN_BITS4)
++	$SHLI	r11,r6,`$BITS/2`	#tl=(tl<=tl) goto Lppcasm_div7
++	addi	r12,r12,1		# th++
++Lppcasm_div7:
++	subf	r11,r11,r4		#r11=l-tl
++	$UCMP	cr1,r3,r12		#compare h and th
++	bge	cr1,Lppcasm_div8	#if (h>=th) goto Lppcasm_div8
++	addi	r8,r8,-1		# q--
++	add	r3,r5,r3		# h+=d
++Lppcasm_div8:
++	subf	r12,r12,r3		#r12 = h-th
++	$SHLI	r4,r11,`$BITS/2`	#l=(l&BN_MASK2l)<>BN_BITS4))&BN_MASK2
++					# the following 2 instructions will do this.
++	$INSR	r11,r12,`$BITS/2`,`$BITS/2`	# r11 is the value we want rotated $BITS/2.
++	$ROTL	r3,r11,`$BITS/2`	# rotate by $BITS/2 and store in r3
++	bdz	Lppcasm_div9		#if (count==0) break ;
++	$SHLI	r0,r8,`$BITS/2`		#ret =q<> 2
++	beq	Lppcasm_mw_REM
++	mtctr	r7
++Lppcasm_mw_LOOP:	
++					#mul(rp[0],ap[0],w,c1);
++	$LD	r8,`0*$BNSZ`(r4)
++	$UMULL	r9,r6,r8
++	$UMULH  r10,r6,r8
++	addc	r9,r9,r12
++	#addze	r10,r10			#carry is NOT ignored.
++					#will be taken care of
++					#in second spin below
++					#using adde.
++	$ST	r9,`0*$BNSZ`(r3)
++					#mul(rp[1],ap[1],w,c1);
++	$LD	r8,`1*$BNSZ`(r4)	
++	$UMULL	r11,r6,r8
++	$UMULH  r12,r6,r8
++	adde	r11,r11,r10
++	#addze	r12,r12
++	$ST	r11,`1*$BNSZ`(r3)
++					#mul(rp[2],ap[2],w,c1);
++	$LD	r8,`2*$BNSZ`(r4)
++	$UMULL	r9,r6,r8
++	$UMULH  r10,r6,r8
++	adde	r9,r9,r12
++	#addze	r10,r10
++	$ST	r9,`2*$BNSZ`(r3)
++					#mul_add(rp[3],ap[3],w,c1);
++	$LD	r8,`3*$BNSZ`(r4)
++	$UMULL	r11,r6,r8
++	$UMULH  r12,r6,r8
++	adde	r11,r11,r10
++	addze	r12,r12			#this spin we collect carry into
++					#r12
++	$ST	r11,`3*$BNSZ`(r3)
++	
++	addi	r3,r3,`4*$BNSZ`
++	addi	r4,r4,`4*$BNSZ`
++	bdnz	Lppcasm_mw_LOOP
++
++Lppcasm_mw_REM:
++	andi.	r5,r5,0x3
++	beq	Lppcasm_mw_OVER
++					#mul(rp[0],ap[0],w,c1);
++	$LD	r8,`0*$BNSZ`(r4)
++	$UMULL	r9,r6,r8
++	$UMULH  r10,r6,r8
++	addc	r9,r9,r12
++	addze	r10,r10
++	$ST	r9,`0*$BNSZ`(r3)
++	addi	r12,r10,0
++	
++	addi	r5,r5,-1
++	cmpli	0,0,r5,0
++	beq	Lppcasm_mw_OVER
++
++	
++					#mul(rp[1],ap[1],w,c1);
++	$LD	r8,`1*$BNSZ`(r4)	
++	$UMULL	r9,r6,r8
++	$UMULH  r10,r6,r8
++	addc	r9,r9,r12
++	addze	r10,r10
++	$ST	r9,`1*$BNSZ`(r3)
++	addi	r12,r10,0
++	
++	addi	r5,r5,-1
++	cmpli	0,0,r5,0
++	beq	Lppcasm_mw_OVER
++	
++					#mul_add(rp[2],ap[2],w,c1);
++	$LD	r8,`2*$BNSZ`(r4)
++	$UMULL	r9,r6,r8
++	$UMULH  r10,r6,r8
++	addc	r9,r9,r12
++	addze	r10,r10
++	$ST	r9,`2*$BNSZ`(r3)
++	addi	r12,r10,0
++		
++Lppcasm_mw_OVER:	
++	addi	r3,r12,0
++	blr
++	.long	0
++	.byte	0,12,0x14,0,0,0,4,0
++	.long	0
++.size	bn_mul_words,.-bn_mul_words
++
++#
++#	NOTE:	The following label name should be changed to
++#		"bn_mul_add_words" i.e. remove the first dot
++#		for the gcc compiler. This should be automatically
++#		done in the build
++#
++
++.align	4
++.bn_mul_add_words:
++#
++# BN_ULONG bn_mul_add_words(BN_ULONG *rp, BN_ULONG *ap, int num, BN_ULONG w)
++#
++# r3 = rp
++# r4 = ap
++# r5 = num
++# r6 = w
++#
++# empirical evidence suggests that unrolled version performs best!!
++#
++	xor	r0,r0,r0		#r0 = 0
++	xor	r12,r12,r12  		#r12 = 0 . used for carry		
++	rlwinm.	r7,r5,30,2,31		# num >> 2
++	beq	Lppcasm_maw_leftover	# if (num < 4) go LPPCASM_maw_leftover
++	mtctr	r7
++Lppcasm_maw_mainloop:	
++					#mul_add(rp[0],ap[0],w,c1);
++	$LD	r8,`0*$BNSZ`(r4)
++	$LD	r11,`0*$BNSZ`(r3)
++	$UMULL	r9,r6,r8
++	$UMULH  r10,r6,r8
++	addc	r9,r9,r12		#r12 is carry.
++	addze	r10,r10
++	addc	r9,r9,r11
++	#addze	r10,r10
++					#the above instruction addze
++					#is NOT needed. Carry will NOT
++					#be ignored. It's not affected
++					#by multiply and will be collected
++					#in the next spin
++	$ST	r9,`0*$BNSZ`(r3)
++	
++					#mul_add(rp[1],ap[1],w,c1);
++	$LD	r8,`1*$BNSZ`(r4)	
++	$LD	r9,`1*$BNSZ`(r3)
++	$UMULL	r11,r6,r8
++	$UMULH  r12,r6,r8
++	adde	r11,r11,r10		#r10 is carry.
++	addze	r12,r12
++	addc	r11,r11,r9
++	#addze	r12,r12
++	$ST	r11,`1*$BNSZ`(r3)
++	
++					#mul_add(rp[2],ap[2],w,c1);
++	$LD	r8,`2*$BNSZ`(r4)
++	$UMULL	r9,r6,r8
++	$LD	r11,`2*$BNSZ`(r3)
++	$UMULH  r10,r6,r8
++	adde	r9,r9,r12
++	addze	r10,r10
++	addc	r9,r9,r11
++	#addze	r10,r10
++	$ST	r9,`2*$BNSZ`(r3)
++	
++					#mul_add(rp[3],ap[3],w,c1);
++	$LD	r8,`3*$BNSZ`(r4)
++	$UMULL	r11,r6,r8
++	$LD	r9,`3*$BNSZ`(r3)
++	$UMULH  r12,r6,r8
++	adde	r11,r11,r10
++	addze	r12,r12
++	addc	r11,r11,r9
++	addze	r12,r12
++	$ST	r11,`3*$BNSZ`(r3)
++	addi	r3,r3,`4*$BNSZ`
++	addi	r4,r4,`4*$BNSZ`
++	bdnz	Lppcasm_maw_mainloop
++	
++Lppcasm_maw_leftover:
++	andi.	r5,r5,0x3
++	beq	Lppcasm_maw_adios
++	addi	r3,r3,-$BNSZ
++	addi	r4,r4,-$BNSZ
++					#mul_add(rp[0],ap[0],w,c1);
++	mtctr	r5
++	$LDU	r8,$BNSZ(r4)
++	$UMULL	r9,r6,r8
++	$UMULH  r10,r6,r8
++	$LDU	r11,$BNSZ(r3)
++	addc	r9,r9,r11
++	addze	r10,r10
++	addc	r9,r9,r12
++	addze	r12,r10
++	$ST	r9,0(r3)
++	
++	bdz	Lppcasm_maw_adios
++					#mul_add(rp[1],ap[1],w,c1);
++	$LDU	r8,$BNSZ(r4)	
++	$UMULL	r9,r6,r8
++	$UMULH  r10,r6,r8
++	$LDU	r11,$BNSZ(r3)
++	addc	r9,r9,r11
++	addze	r10,r10
++	addc	r9,r9,r12
++	addze	r12,r10
++	$ST	r9,0(r3)
++	
++	bdz	Lppcasm_maw_adios
++					#mul_add(rp[2],ap[2],w,c1);
++	$LDU	r8,$BNSZ(r4)
++	$UMULL	r9,r6,r8
++	$UMULH  r10,r6,r8
++	$LDU	r11,$BNSZ(r3)
++	addc	r9,r9,r11
++	addze	r10,r10
++	addc	r9,r9,r12
++	addze	r12,r10
++	$ST	r9,0(r3)
++		
++Lppcasm_maw_adios:	
++	addi	r3,r12,0
++	blr
++	.long	0
++	.byte	0,12,0x14,0,0,0,4,0
++	.long	0
++.size	.bn_mul_add_words,.-.bn_mul_add_words
++	.align	4
++EOF
++$data =~ s/\`([^\`]*)\`/eval $1/gem;
++print $data;
++close STDOUT;
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/bn/asm/ppc64-mont.pl b/CryptoPkg/Library/OpensslLib/openssl/crypto/bn/asm/ppc64-mont.pl
+new file mode 100644
+index 0000000..1e19c95
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/bn/asm/ppc64-mont.pl
+@@ -0,0 +1,1635 @@
++#! /usr/bin/env perl
++# Copyright 2007-2016 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
++# in the file LICENSE in the source distribution or at
++# https://www.openssl.org/source/license.html
++
++
++# ====================================================================
++# Written by Andy Polyakov  for the OpenSSL
++# project. The module is, however, dual licensed under OpenSSL and
++# CRYPTOGAMS licenses depending on where you obtain it. For further
++# details see http://www.openssl.org/~appro/cryptogams/.
++# ====================================================================
++
++# December 2007
++
++# The reason for undertaken effort is basically following. Even though
++# Power 6 CPU operates at incredible 4.7GHz clock frequency, its PKI
++# performance was observed to be less than impressive, essentially as
++# fast as 1.8GHz PPC970, or 2.6 times(!) slower than one would hope.
++# Well, it's not surprising that IBM had to make some sacrifices to
++# boost the clock frequency that much, but no overall improvement?
++# Having observed how much difference did switching to FPU make on
++# UltraSPARC, playing same stunt on Power 6 appeared appropriate...
++# Unfortunately the resulting performance improvement is not as
++# impressive, ~30%, and in absolute terms is still very far from what
++# one would expect from 4.7GHz CPU. There is a chance that I'm doing
++# something wrong, but in the lack of assembler level micro-profiling
++# data or at least decent platform guide I can't tell... Or better
++# results might be achieved with VMX... Anyway, this module provides
++# *worse* performance on other PowerPC implementations, ~40-15% slower
++# on PPC970 depending on key length and ~40% slower on Power 5 for all
++# key lengths. As it's obviously inappropriate as "best all-round"
++# alternative, it has to be complemented with run-time CPU family
++# detection. Oh! It should also be noted that unlike other PowerPC
++# implementation IALU ppc-mont.pl module performs *suboptimaly* on
++# >=1024-bit key lengths on Power 6. It should also be noted that
++# *everything* said so far applies to 64-bit builds! As far as 32-bit
++# application executed on 64-bit CPU goes, this module is likely to
++# become preferred choice, because it's easy to adapt it for such
++# case and *is* faster than 32-bit ppc-mont.pl on *all* processors.
++
++# February 2008
++
++# Micro-profiling assisted optimization results in ~15% improvement
++# over original ppc64-mont.pl version, or overall ~50% improvement
++# over ppc.pl module on Power 6. If compared to ppc-mont.pl on same
++# Power 6 CPU, this module is 5-150% faster depending on key length,
++# [hereafter] more for longer keys. But if compared to ppc-mont.pl
++# on 1.8GHz PPC970, it's only 5-55% faster. Still far from impressive
++# in absolute terms, but it's apparently the way Power 6 is...
++
++# December 2009
++
++# Adapted for 32-bit build this module delivers 25-120%, yes, more
++# than *twice* for longer keys, performance improvement over 32-bit
++# ppc-mont.pl on 1.8GHz PPC970. However! This implementation utilizes
++# even 64-bit integer operations and the trouble is that most PPC
++# operating systems don't preserve upper halves of general purpose
++# registers upon 32-bit signal delivery. They do preserve them upon
++# context switch, but not signalling:-( This means that asynchronous
++# signals have to be blocked upon entry to this subroutine. Signal
++# masking (and of course complementary unmasking) has quite an impact
++# on performance, naturally larger for shorter keys. It's so severe
++# that 512-bit key performance can be as low as 1/3 of expected one.
++# This is why this routine can be engaged for longer key operations
++# only on these OSes, see crypto/ppccap.c for further details. MacOS X
++# is an exception from this and doesn't require signal masking, and
++# that's where above improvement coefficients were collected. For
++# others alternative would be to break dependence on upper halves of
++# GPRs by sticking to 32-bit integer operations...
++
++# December 2012
++
++# Remove above mentioned dependence on GPRs' upper halves in 32-bit
++# build. No signal masking overhead, but integer instructions are
++# *more* numerous... It's still "universally" faster than 32-bit
++# ppc-mont.pl, but improvement coefficient is not as impressive
++# for longer keys...
++
++$flavour = shift;
++
++if ($flavour =~ /32/) {
++	$SIZE_T=4;
++	$RZONE=	224;
++	$fname=	"bn_mul_mont_fpu64";
++
++	$STUX=	"stwux";	# store indexed and update
++	$PUSH=	"stw";
++	$POP=	"lwz";
++} elsif ($flavour =~ /64/) {
++	$SIZE_T=8;
++	$RZONE=	288;
++	$fname=	"bn_mul_mont_fpu64";
++
++	# same as above, but 64-bit mnemonics...
++	$STUX=	"stdux";	# store indexed and update
++	$PUSH=	"std";
++	$POP=	"ld";
++} else { die "nonsense $flavour"; }
++
++$LITTLE_ENDIAN = ($flavour=~/le$/) ? 4 : 0;
++
++$0 =~ m/(.*[\/\\])[^\/\\]+$/; $dir=$1;
++( $xlate="${dir}ppc-xlate.pl" and -f $xlate ) or
++( $xlate="${dir}../../perlasm/ppc-xlate.pl" and -f $xlate) or
++die "can't locate ppc-xlate.pl";
++
++open STDOUT,"| $^X $xlate $flavour ".shift || die "can't call $xlate: $!";
++
++$FRAME=64;	# padded frame header
++$TRANSFER=16*8;
++
++$carry="r0";
++$sp="r1";
++$toc="r2";
++$rp="r3";	$ovf="r3";
++$ap="r4";
++$bp="r5";
++$np="r6";
++$n0="r7";
++$num="r8";
++$rp="r9";	# $rp is reassigned
++$tp="r10";
++$j="r11";
++$i="r12";
++# non-volatile registers
++$c1="r19";
++$n1="r20";
++$a1="r21";
++$nap_d="r22";	# interleaved ap and np in double format
++$a0="r23";	# ap[0]
++$t0="r24";	# temporary registers
++$t1="r25";
++$t2="r26";
++$t3="r27";
++$t4="r28";
++$t5="r29";
++$t6="r30";
++$t7="r31";
++
++# PPC offers enough register bank capacity to unroll inner loops twice
++#
++#     ..A3A2A1A0
++#           dcba
++#    -----------
++#            A0a
++#           A0b
++#          A0c
++#         A0d
++#          A1a
++#         A1b
++#        A1c
++#       A1d
++#        A2a
++#       A2b
++#      A2c
++#     A2d
++#      A3a
++#     A3b
++#    A3c
++#   A3d
++#    ..a
++#   ..b
++#
++$ba="f0";	$bb="f1";	$bc="f2";	$bd="f3";
++$na="f4";	$nb="f5";	$nc="f6";	$nd="f7";
++$dota="f8";	$dotb="f9";
++$A0="f10";	$A1="f11";	$A2="f12";	$A3="f13";
++$N0="f20";	$N1="f21";	$N2="f22";	$N3="f23";
++$T0a="f24";	$T0b="f25";
++$T1a="f26";	$T1b="f27";
++$T2a="f28";	$T2b="f29";
++$T3a="f30";	$T3b="f31";
++
++# sp----------->+-------------------------------+
++#		| saved sp			|
++#		+-------------------------------+
++#		.				.
++#   +64		+-------------------------------+
++#		| 16 gpr<->fpr transfer zone	|
++#		.				.
++#		.				.
++#   +16*8	+-------------------------------+
++#		| __int64 tmp[-1]		|
++#		+-------------------------------+
++#		| __int64 tmp[num]		|
++#		.				.
++#		.				.
++#		.				.
++#   +(num+1)*8	+-------------------------------+
++#		| padding to 64 byte boundary	|
++#		.				.
++#   +X		+-------------------------------+
++#		| double nap_d[4*num]		|
++#		.				.
++#		.				.
++#		.				.
++#		+-------------------------------+
++#		.				.
++#   -13*size_t	+-------------------------------+
++#		| 13 saved gpr, r19-r31		|
++#		.				.
++#		.				.
++#   -12*8	+-------------------------------+
++#		| 12 saved fpr, f20-f31		|
++#		.				.
++#		.				.
++#		+-------------------------------+
++
++$code=<<___;
++.machine "any"
++.text
++
++.globl	.$fname
++.align	5
++.$fname:
++	cmpwi	$num,`3*8/$SIZE_T`
++	mr	$rp,r3		; $rp is reassigned
++	li	r3,0		; possible "not handled" return code
++	bltlr-
++	andi.	r0,$num,`16/$SIZE_T-1`		; $num has to be "even"
++	bnelr-
++
++	slwi	$num,$num,`log($SIZE_T)/log(2)`	; num*=sizeof(BN_LONG)
++	li	$i,-4096
++	slwi	$tp,$num,2	; place for {an}p_{lh}[num], i.e. 4*num
++	add	$tp,$tp,$num	; place for tp[num+1]
++	addi	$tp,$tp,`$FRAME+$TRANSFER+8+64+$RZONE`
++	subf	$tp,$tp,$sp	; $sp-$tp
++	and	$tp,$tp,$i	; minimize TLB usage
++	subf	$tp,$sp,$tp	; $tp-$sp
++	mr	$i,$sp
++	$STUX	$sp,$sp,$tp	; alloca
++
++	$PUSH	r19,`-12*8-13*$SIZE_T`($i)
++	$PUSH	r20,`-12*8-12*$SIZE_T`($i)
++	$PUSH	r21,`-12*8-11*$SIZE_T`($i)
++	$PUSH	r22,`-12*8-10*$SIZE_T`($i)
++	$PUSH	r23,`-12*8-9*$SIZE_T`($i)
++	$PUSH	r24,`-12*8-8*$SIZE_T`($i)
++	$PUSH	r25,`-12*8-7*$SIZE_T`($i)
++	$PUSH	r26,`-12*8-6*$SIZE_T`($i)
++	$PUSH	r27,`-12*8-5*$SIZE_T`($i)
++	$PUSH	r28,`-12*8-4*$SIZE_T`($i)
++	$PUSH	r29,`-12*8-3*$SIZE_T`($i)
++	$PUSH	r30,`-12*8-2*$SIZE_T`($i)
++	$PUSH	r31,`-12*8-1*$SIZE_T`($i)
++	stfd	f20,`-12*8`($i)
++	stfd	f21,`-11*8`($i)
++	stfd	f22,`-10*8`($i)
++	stfd	f23,`-9*8`($i)
++	stfd	f24,`-8*8`($i)
++	stfd	f25,`-7*8`($i)
++	stfd	f26,`-6*8`($i)
++	stfd	f27,`-5*8`($i)
++	stfd	f28,`-4*8`($i)
++	stfd	f29,`-3*8`($i)
++	stfd	f30,`-2*8`($i)
++	stfd	f31,`-1*8`($i)
++
++	addi	$tp,$sp,`$FRAME+$TRANSFER+8+64`
++	li	$i,-64
++	add	$nap_d,$tp,$num
++	and	$nap_d,$nap_d,$i	; align to 64 bytes
++	; nap_d is off by 1, because it's used with stfdu/lfdu
++	addi	$nap_d,$nap_d,-8
++	srwi	$j,$num,`3+1`	; counter register, num/2
++	addi	$j,$j,-1
++	addi	$tp,$sp,`$FRAME+$TRANSFER-8`
++	li	$carry,0
++	mtctr	$j
++___
++
++$code.=<<___ if ($SIZE_T==8);
++	ld	$a0,0($ap)		; pull ap[0] value
++	ld	$t3,0($bp)		; bp[0]
++	ld	$n0,0($n0)		; pull n0[0] value
++
++	mulld	$t7,$a0,$t3		; ap[0]*bp[0]
++	; transfer bp[0] to FPU as 4x16-bit values
++	extrdi	$t0,$t3,16,48
++	extrdi	$t1,$t3,16,32
++	extrdi	$t2,$t3,16,16
++	extrdi	$t3,$t3,16,0
++	std	$t0,`$FRAME+0`($sp)
++	std	$t1,`$FRAME+8`($sp)
++	std	$t2,`$FRAME+16`($sp)
++	std	$t3,`$FRAME+24`($sp)
++
++	mulld	$t7,$t7,$n0		; tp[0]*n0
++	; transfer (ap[0]*bp[0])*n0 to FPU as 4x16-bit values
++	extrdi	$t4,$t7,16,48
++	extrdi	$t5,$t7,16,32
++	extrdi	$t6,$t7,16,16
++	extrdi	$t7,$t7,16,0
++	std	$t4,`$FRAME+32`($sp)
++	std	$t5,`$FRAME+40`($sp)
++	std	$t6,`$FRAME+48`($sp)
++	std	$t7,`$FRAME+56`($sp)
++
++	extrdi	$t0,$a0,32,32		; lwz	$t0,4($ap)
++	extrdi	$t1,$a0,32,0		; lwz	$t1,0($ap)
++	lwz	$t2,`12^$LITTLE_ENDIAN`($ap)	; load a[1] as 32-bit word pair
++	lwz	$t3,`8^$LITTLE_ENDIAN`($ap)
++	lwz	$t4,`4^$LITTLE_ENDIAN`($np)	; load n[0] as 32-bit word pair
++	lwz	$t5,`0^$LITTLE_ENDIAN`($np)
++	lwz	$t6,`12^$LITTLE_ENDIAN`($np)	; load n[1] as 32-bit word pair
++	lwz	$t7,`8^$LITTLE_ENDIAN`($np)
++___
++$code.=<<___ if ($SIZE_T==4);
++	lwz	$a0,0($ap)		; pull ap[0,1] value
++	mr	$n1,$n0
++	lwz	$a1,4($ap)
++	li	$c1,0
++	lwz	$t1,0($bp)		; bp[0,1]
++	lwz	$t3,4($bp)
++	lwz	$n0,0($n1)		; pull n0[0,1] value
++	lwz	$n1,4($n1)
++
++	mullw	$t4,$a0,$t1		; mulld ap[0]*bp[0]
++	mulhwu	$t5,$a0,$t1
++	mullw	$t6,$a1,$t1
++	mullw	$t7,$a0,$t3
++	add	$t5,$t5,$t6
++	add	$t5,$t5,$t7
++	; transfer bp[0] to FPU as 4x16-bit values
++	extrwi	$t0,$t1,16,16
++	extrwi	$t1,$t1,16,0
++	extrwi	$t2,$t3,16,16
++	extrwi	$t3,$t3,16,0
++	std	$t0,`$FRAME+0`($sp)	; yes, std in 32-bit build
++	std	$t1,`$FRAME+8`($sp)
++	std	$t2,`$FRAME+16`($sp)
++	std	$t3,`$FRAME+24`($sp)
++
++	mullw	$t0,$t4,$n0		; mulld tp[0]*n0
++	mulhwu	$t1,$t4,$n0
++	mullw	$t2,$t5,$n0
++	mullw	$t3,$t4,$n1
++	add	$t1,$t1,$t2
++	add	$t1,$t1,$t3
++	; transfer (ap[0]*bp[0])*n0 to FPU as 4x16-bit values
++	extrwi	$t4,$t0,16,16
++	extrwi	$t5,$t0,16,0
++	extrwi	$t6,$t1,16,16
++	extrwi	$t7,$t1,16,0
++	std	$t4,`$FRAME+32`($sp)	; yes, std in 32-bit build
++	std	$t5,`$FRAME+40`($sp)
++	std	$t6,`$FRAME+48`($sp)
++	std	$t7,`$FRAME+56`($sp)
++
++	mr	$t0,$a0			; lwz	$t0,0($ap)
++	mr	$t1,$a1			; lwz	$t1,4($ap)
++	lwz	$t2,8($ap)		; load a[j..j+3] as 32-bit word pairs
++	lwz	$t3,12($ap)
++	lwz	$t4,0($np)		; load n[j..j+3] as 32-bit word pairs
++	lwz	$t5,4($np)
++	lwz	$t6,8($np)
++	lwz	$t7,12($np)
++___
++$code.=<<___;
++	lfd	$ba,`$FRAME+0`($sp)
++	lfd	$bb,`$FRAME+8`($sp)
++	lfd	$bc,`$FRAME+16`($sp)
++	lfd	$bd,`$FRAME+24`($sp)
++	lfd	$na,`$FRAME+32`($sp)
++	lfd	$nb,`$FRAME+40`($sp)
++	lfd	$nc,`$FRAME+48`($sp)
++	lfd	$nd,`$FRAME+56`($sp)
++	std	$t0,`$FRAME+64`($sp)	; yes, std even in 32-bit build
++	std	$t1,`$FRAME+72`($sp)
++	std	$t2,`$FRAME+80`($sp)
++	std	$t3,`$FRAME+88`($sp)
++	std	$t4,`$FRAME+96`($sp)
++	std	$t5,`$FRAME+104`($sp)
++	std	$t6,`$FRAME+112`($sp)
++	std	$t7,`$FRAME+120`($sp)
++	fcfid	$ba,$ba
++	fcfid	$bb,$bb
++	fcfid	$bc,$bc
++	fcfid	$bd,$bd
++	fcfid	$na,$na
++	fcfid	$nb,$nb
++	fcfid	$nc,$nc
++	fcfid	$nd,$nd
++
++	lfd	$A0,`$FRAME+64`($sp)
++	lfd	$A1,`$FRAME+72`($sp)
++	lfd	$A2,`$FRAME+80`($sp)
++	lfd	$A3,`$FRAME+88`($sp)
++	lfd	$N0,`$FRAME+96`($sp)
++	lfd	$N1,`$FRAME+104`($sp)
++	lfd	$N2,`$FRAME+112`($sp)
++	lfd	$N3,`$FRAME+120`($sp)
++	fcfid	$A0,$A0
++	fcfid	$A1,$A1
++	fcfid	$A2,$A2
++	fcfid	$A3,$A3
++	fcfid	$N0,$N0
++	fcfid	$N1,$N1
++	fcfid	$N2,$N2
++	fcfid	$N3,$N3
++	addi	$ap,$ap,16
++	addi	$np,$np,16
++
++	fmul	$T1a,$A1,$ba
++	fmul	$T1b,$A1,$bb
++	stfd	$A0,8($nap_d)		; save a[j] in double format
++	stfd	$A1,16($nap_d)
++	fmul	$T2a,$A2,$ba
++	fmul	$T2b,$A2,$bb
++	stfd	$A2,24($nap_d)		; save a[j+1] in double format
++	stfd	$A3,32($nap_d)
++	fmul	$T3a,$A3,$ba
++	fmul	$T3b,$A3,$bb
++	stfd	$N0,40($nap_d)		; save n[j] in double format
++	stfd	$N1,48($nap_d)
++	fmul	$T0a,$A0,$ba
++	fmul	$T0b,$A0,$bb
++	stfd	$N2,56($nap_d)		; save n[j+1] in double format
++	stfdu	$N3,64($nap_d)
++
++	fmadd	$T1a,$A0,$bc,$T1a
++	fmadd	$T1b,$A0,$bd,$T1b
++	fmadd	$T2a,$A1,$bc,$T2a
++	fmadd	$T2b,$A1,$bd,$T2b
++	fmadd	$T3a,$A2,$bc,$T3a
++	fmadd	$T3b,$A2,$bd,$T3b
++	fmul	$dota,$A3,$bc
++	fmul	$dotb,$A3,$bd
++
++	fmadd	$T1a,$N1,$na,$T1a
++	fmadd	$T1b,$N1,$nb,$T1b
++	fmadd	$T2a,$N2,$na,$T2a
++	fmadd	$T2b,$N2,$nb,$T2b
++	fmadd	$T3a,$N3,$na,$T3a
++	fmadd	$T3b,$N3,$nb,$T3b
++	fmadd	$T0a,$N0,$na,$T0a
++	fmadd	$T0b,$N0,$nb,$T0b
++
++	fmadd	$T1a,$N0,$nc,$T1a
++	fmadd	$T1b,$N0,$nd,$T1b
++	fmadd	$T2a,$N1,$nc,$T2a
++	fmadd	$T2b,$N1,$nd,$T2b
++	fmadd	$T3a,$N2,$nc,$T3a
++	fmadd	$T3b,$N2,$nd,$T3b
++	fmadd	$dota,$N3,$nc,$dota
++	fmadd	$dotb,$N3,$nd,$dotb
++
++	fctid	$T0a,$T0a
++	fctid	$T0b,$T0b
++	fctid	$T1a,$T1a
++	fctid	$T1b,$T1b
++	fctid	$T2a,$T2a
++	fctid	$T2b,$T2b
++	fctid	$T3a,$T3a
++	fctid	$T3b,$T3b
++
++	stfd	$T0a,`$FRAME+0`($sp)
++	stfd	$T0b,`$FRAME+8`($sp)
++	stfd	$T1a,`$FRAME+16`($sp)
++	stfd	$T1b,`$FRAME+24`($sp)
++	stfd	$T2a,`$FRAME+32`($sp)
++	stfd	$T2b,`$FRAME+40`($sp)
++	stfd	$T3a,`$FRAME+48`($sp)
++	stfd	$T3b,`$FRAME+56`($sp)
++
++.align	5
++L1st:
++___
++$code.=<<___ if ($SIZE_T==8);
++	lwz	$t0,`4^$LITTLE_ENDIAN`($ap)	; load a[j] as 32-bit word pair
++	lwz	$t1,`0^$LITTLE_ENDIAN`($ap)
++	lwz	$t2,`12^$LITTLE_ENDIAN`($ap)	; load a[j+1] as 32-bit word pair
++	lwz	$t3,`8^$LITTLE_ENDIAN`($ap)
++	lwz	$t4,`4^$LITTLE_ENDIAN`($np)	; load n[j] as 32-bit word pair
++	lwz	$t5,`0^$LITTLE_ENDIAN`($np)
++	lwz	$t6,`12^$LITTLE_ENDIAN`($np)	; load n[j+1] as 32-bit word pair
++	lwz	$t7,`8^$LITTLE_ENDIAN`($np)
++___
++$code.=<<___ if ($SIZE_T==4);
++	lwz	$t0,0($ap)		; load a[j..j+3] as 32-bit word pairs
++	lwz	$t1,4($ap)
++	lwz	$t2,8($ap)
++	lwz	$t3,12($ap)
++	lwz	$t4,0($np)		; load n[j..j+3] as 32-bit word pairs
++	lwz	$t5,4($np)
++	lwz	$t6,8($np)
++	lwz	$t7,12($np)
++___
++$code.=<<___;
++	std	$t0,`$FRAME+64`($sp)	; yes, std even in 32-bit build
++	std	$t1,`$FRAME+72`($sp)
++	std	$t2,`$FRAME+80`($sp)
++	std	$t3,`$FRAME+88`($sp)
++	std	$t4,`$FRAME+96`($sp)
++	std	$t5,`$FRAME+104`($sp)
++	std	$t6,`$FRAME+112`($sp)
++	std	$t7,`$FRAME+120`($sp)
++___
++if ($SIZE_T==8 or $flavour =~ /osx/) {
++$code.=<<___;
++	ld	$t0,`$FRAME+0`($sp)
++	ld	$t1,`$FRAME+8`($sp)
++	ld	$t2,`$FRAME+16`($sp)
++	ld	$t3,`$FRAME+24`($sp)
++	ld	$t4,`$FRAME+32`($sp)
++	ld	$t5,`$FRAME+40`($sp)
++	ld	$t6,`$FRAME+48`($sp)
++	ld	$t7,`$FRAME+56`($sp)
++___
++} else {
++$code.=<<___;
++	lwz	$t1,`$FRAME+0^$LITTLE_ENDIAN`($sp)
++	lwz	$t0,`$FRAME+4^$LITTLE_ENDIAN`($sp)
++	lwz	$t3,`$FRAME+8^$LITTLE_ENDIAN`($sp)
++	lwz	$t2,`$FRAME+12^$LITTLE_ENDIAN`($sp)
++	lwz	$t5,`$FRAME+16^$LITTLE_ENDIAN`($sp)
++	lwz	$t4,`$FRAME+20^$LITTLE_ENDIAN`($sp)
++	lwz	$t7,`$FRAME+24^$LITTLE_ENDIAN`($sp)
++	lwz	$t6,`$FRAME+28^$LITTLE_ENDIAN`($sp)
++___
++}
++$code.=<<___;
++	lfd	$A0,`$FRAME+64`($sp)
++	lfd	$A1,`$FRAME+72`($sp)
++	lfd	$A2,`$FRAME+80`($sp)
++	lfd	$A3,`$FRAME+88`($sp)
++	lfd	$N0,`$FRAME+96`($sp)
++	lfd	$N1,`$FRAME+104`($sp)
++	lfd	$N2,`$FRAME+112`($sp)
++	lfd	$N3,`$FRAME+120`($sp)
++	fcfid	$A0,$A0
++	fcfid	$A1,$A1
++	fcfid	$A2,$A2
++	fcfid	$A3,$A3
++	fcfid	$N0,$N0
++	fcfid	$N1,$N1
++	fcfid	$N2,$N2
++	fcfid	$N3,$N3
++	addi	$ap,$ap,16
++	addi	$np,$np,16
++
++	fmul	$T1a,$A1,$ba
++	fmul	$T1b,$A1,$bb
++	fmul	$T2a,$A2,$ba
++	fmul	$T2b,$A2,$bb
++	stfd	$A0,8($nap_d)		; save a[j] in double format
++	stfd	$A1,16($nap_d)
++	fmul	$T3a,$A3,$ba
++	fmul	$T3b,$A3,$bb
++	fmadd	$T0a,$A0,$ba,$dota
++	fmadd	$T0b,$A0,$bb,$dotb
++	stfd	$A2,24($nap_d)		; save a[j+1] in double format
++	stfd	$A3,32($nap_d)
++___
++if ($SIZE_T==8 or $flavour =~ /osx/) {
++$code.=<<___;
++	fmadd	$T1a,$A0,$bc,$T1a
++	fmadd	$T1b,$A0,$bd,$T1b
++	fmadd	$T2a,$A1,$bc,$T2a
++	fmadd	$T2b,$A1,$bd,$T2b
++	stfd	$N0,40($nap_d)		; save n[j] in double format
++	stfd	$N1,48($nap_d)
++	fmadd	$T3a,$A2,$bc,$T3a
++	fmadd	$T3b,$A2,$bd,$T3b
++	 add	$t0,$t0,$carry		; can not overflow
++	fmul	$dota,$A3,$bc
++	fmul	$dotb,$A3,$bd
++	stfd	$N2,56($nap_d)		; save n[j+1] in double format
++	stfdu	$N3,64($nap_d)
++	 srdi	$carry,$t0,16
++	 add	$t1,$t1,$carry
++	 srdi	$carry,$t1,16
++
++	fmadd	$T1a,$N1,$na,$T1a
++	fmadd	$T1b,$N1,$nb,$T1b
++	 insrdi	$t0,$t1,16,32
++	fmadd	$T2a,$N2,$na,$T2a
++	fmadd	$T2b,$N2,$nb,$T2b
++	 add	$t2,$t2,$carry
++	fmadd	$T3a,$N3,$na,$T3a
++	fmadd	$T3b,$N3,$nb,$T3b
++	 srdi	$carry,$t2,16
++	fmadd	$T0a,$N0,$na,$T0a
++	fmadd	$T0b,$N0,$nb,$T0b
++	 insrdi	$t0,$t2,16,16
++	 add	$t3,$t3,$carry
++	 srdi	$carry,$t3,16
++
++	fmadd	$T1a,$N0,$nc,$T1a
++	fmadd	$T1b,$N0,$nd,$T1b
++	 insrdi	$t0,$t3,16,0		; 0..63 bits
++	fmadd	$T2a,$N1,$nc,$T2a
++	fmadd	$T2b,$N1,$nd,$T2b
++	 add	$t4,$t4,$carry
++	fmadd	$T3a,$N2,$nc,$T3a
++	fmadd	$T3b,$N2,$nd,$T3b
++	 srdi	$carry,$t4,16
++	fmadd	$dota,$N3,$nc,$dota
++	fmadd	$dotb,$N3,$nd,$dotb
++	 add	$t5,$t5,$carry
++	 srdi	$carry,$t5,16
++	 insrdi	$t4,$t5,16,32
++
++	fctid	$T0a,$T0a
++	fctid	$T0b,$T0b
++	 add	$t6,$t6,$carry
++	fctid	$T1a,$T1a
++	fctid	$T1b,$T1b
++	 srdi	$carry,$t6,16
++	fctid	$T2a,$T2a
++	fctid	$T2b,$T2b
++	 insrdi	$t4,$t6,16,16
++	fctid	$T3a,$T3a
++	fctid	$T3b,$T3b
++	 add	$t7,$t7,$carry
++	 insrdi	$t4,$t7,16,0		; 64..127 bits
++	 srdi	$carry,$t7,16		; upper 33 bits
++
++	stfd	$T0a,`$FRAME+0`($sp)
++	stfd	$T0b,`$FRAME+8`($sp)
++	stfd	$T1a,`$FRAME+16`($sp)
++	stfd	$T1b,`$FRAME+24`($sp)
++	stfd	$T2a,`$FRAME+32`($sp)
++	stfd	$T2b,`$FRAME+40`($sp)
++	stfd	$T3a,`$FRAME+48`($sp)
++	stfd	$T3b,`$FRAME+56`($sp)
++	 std	$t0,8($tp)		; tp[j-1]
++	 stdu	$t4,16($tp)		; tp[j]
++___
++} else {
++$code.=<<___;
++	fmadd	$T1a,$A0,$bc,$T1a
++	fmadd	$T1b,$A0,$bd,$T1b
++	 addc	$t0,$t0,$carry
++	 adde	$t1,$t1,$c1
++	 srwi	$carry,$t0,16
++	fmadd	$T2a,$A1,$bc,$T2a
++	fmadd	$T2b,$A1,$bd,$T2b
++	stfd	$N0,40($nap_d)		; save n[j] in double format
++	stfd	$N1,48($nap_d)
++	 srwi	$c1,$t1,16
++	 insrwi	$carry,$t1,16,0
++	fmadd	$T3a,$A2,$bc,$T3a
++	fmadd	$T3b,$A2,$bd,$T3b
++	 addc	$t2,$t2,$carry
++	 adde	$t3,$t3,$c1
++	 srwi	$carry,$t2,16
++	fmul	$dota,$A3,$bc
++	fmul	$dotb,$A3,$bd
++	stfd	$N2,56($nap_d)		; save n[j+1] in double format
++	stfdu	$N3,64($nap_d)
++	 insrwi	$t0,$t2,16,0		; 0..31 bits
++	 srwi	$c1,$t3,16
++	 insrwi	$carry,$t3,16,0
++
++	fmadd	$T1a,$N1,$na,$T1a
++	fmadd	$T1b,$N1,$nb,$T1b
++	 lwz	$t3,`$FRAME+32^$LITTLE_ENDIAN`($sp)	; permuted $t1
++	 lwz	$t2,`$FRAME+36^$LITTLE_ENDIAN`($sp)	; permuted $t0
++	 addc	$t4,$t4,$carry
++	 adde	$t5,$t5,$c1
++	 srwi	$carry,$t4,16
++	fmadd	$T2a,$N2,$na,$T2a
++	fmadd	$T2b,$N2,$nb,$T2b
++	 srwi	$c1,$t5,16
++	 insrwi	$carry,$t5,16,0
++	fmadd	$T3a,$N3,$na,$T3a
++	fmadd	$T3b,$N3,$nb,$T3b
++	 addc	$t6,$t6,$carry
++	 adde	$t7,$t7,$c1
++	 srwi	$carry,$t6,16
++	fmadd	$T0a,$N0,$na,$T0a
++	fmadd	$T0b,$N0,$nb,$T0b
++	 insrwi	$t4,$t6,16,0		; 32..63 bits
++	 srwi	$c1,$t7,16
++	 insrwi	$carry,$t7,16,0
++
++	fmadd	$T1a,$N0,$nc,$T1a
++	fmadd	$T1b,$N0,$nd,$T1b
++	 lwz	$t7,`$FRAME+40^$LITTLE_ENDIAN`($sp)	; permuted $t3
++	 lwz	$t6,`$FRAME+44^$LITTLE_ENDIAN`($sp)	; permuted $t2
++	 addc	$t2,$t2,$carry
++	 adde	$t3,$t3,$c1
++	 srwi	$carry,$t2,16
++	fmadd	$T2a,$N1,$nc,$T2a
++	fmadd	$T2b,$N1,$nd,$T2b
++	 stw	$t0,12($tp)		; tp[j-1]
++	 stw	$t4,8($tp)
++	 srwi	$c1,$t3,16
++	 insrwi	$carry,$t3,16,0
++	fmadd	$T3a,$N2,$nc,$T3a
++	fmadd	$T3b,$N2,$nd,$T3b
++	 lwz	$t1,`$FRAME+48^$LITTLE_ENDIAN`($sp)	; permuted $t5
++	 lwz	$t0,`$FRAME+52^$LITTLE_ENDIAN`($sp)	; permuted $t4
++	 addc	$t6,$t6,$carry
++	 adde	$t7,$t7,$c1
++	 srwi	$carry,$t6,16
++	fmadd	$dota,$N3,$nc,$dota
++	fmadd	$dotb,$N3,$nd,$dotb
++	 insrwi	$t2,$t6,16,0		; 64..95 bits
++	 srwi	$c1,$t7,16
++	 insrwi	$carry,$t7,16,0
++
++	fctid	$T0a,$T0a
++	fctid	$T0b,$T0b
++	 lwz	$t5,`$FRAME+56^$LITTLE_ENDIAN`($sp)	; permuted $t7
++	 lwz	$t4,`$FRAME+60^$LITTLE_ENDIAN`($sp)	; permuted $t6
++	 addc	$t0,$t0,$carry
++	 adde	$t1,$t1,$c1
++	 srwi	$carry,$t0,16
++	fctid	$T1a,$T1a
++	fctid	$T1b,$T1b
++	 srwi	$c1,$t1,16
++	 insrwi	$carry,$t1,16,0
++	fctid	$T2a,$T2a
++	fctid	$T2b,$T2b
++	 addc	$t4,$t4,$carry
++	 adde	$t5,$t5,$c1
++	 srwi	$carry,$t4,16
++	fctid	$T3a,$T3a
++	fctid	$T3b,$T3b
++	 insrwi	$t0,$t4,16,0		; 96..127 bits
++	 srwi	$c1,$t5,16
++	 insrwi	$carry,$t5,16,0
++
++	stfd	$T0a,`$FRAME+0`($sp)
++	stfd	$T0b,`$FRAME+8`($sp)
++	stfd	$T1a,`$FRAME+16`($sp)
++	stfd	$T1b,`$FRAME+24`($sp)
++	stfd	$T2a,`$FRAME+32`($sp)
++	stfd	$T2b,`$FRAME+40`($sp)
++	stfd	$T3a,`$FRAME+48`($sp)
++	stfd	$T3b,`$FRAME+56`($sp)
++	 stw	$t2,20($tp)		; tp[j]
++	 stwu	$t0,16($tp)
++___
++}
++$code.=<<___;
++	bdnz	L1st
++
++	fctid	$dota,$dota
++	fctid	$dotb,$dotb
++___
++if ($SIZE_T==8 or $flavour =~ /osx/) {
++$code.=<<___;
++	ld	$t0,`$FRAME+0`($sp)
++	ld	$t1,`$FRAME+8`($sp)
++	ld	$t2,`$FRAME+16`($sp)
++	ld	$t3,`$FRAME+24`($sp)
++	ld	$t4,`$FRAME+32`($sp)
++	ld	$t5,`$FRAME+40`($sp)
++	ld	$t6,`$FRAME+48`($sp)
++	ld	$t7,`$FRAME+56`($sp)
++	stfd	$dota,`$FRAME+64`($sp)
++	stfd	$dotb,`$FRAME+72`($sp)
++
++	add	$t0,$t0,$carry		; can not overflow
++	srdi	$carry,$t0,16
++	add	$t1,$t1,$carry
++	srdi	$carry,$t1,16
++	insrdi	$t0,$t1,16,32
++	add	$t2,$t2,$carry
++	srdi	$carry,$t2,16
++	insrdi	$t0,$t2,16,16
++	add	$t3,$t3,$carry
++	srdi	$carry,$t3,16
++	insrdi	$t0,$t3,16,0		; 0..63 bits
++	add	$t4,$t4,$carry
++	srdi	$carry,$t4,16
++	add	$t5,$t5,$carry
++	srdi	$carry,$t5,16
++	insrdi	$t4,$t5,16,32
++	add	$t6,$t6,$carry
++	srdi	$carry,$t6,16
++	insrdi	$t4,$t6,16,16
++	add	$t7,$t7,$carry
++	insrdi	$t4,$t7,16,0		; 64..127 bits
++	srdi	$carry,$t7,16		; upper 33 bits
++	ld	$t6,`$FRAME+64`($sp)
++	ld	$t7,`$FRAME+72`($sp)
++
++	std	$t0,8($tp)		; tp[j-1]
++	stdu	$t4,16($tp)		; tp[j]
++
++	add	$t6,$t6,$carry		; can not overflow
++	srdi	$carry,$t6,16
++	add	$t7,$t7,$carry
++	insrdi	$t6,$t7,48,0
++	srdi	$ovf,$t7,48
++	std	$t6,8($tp)		; tp[num-1]
++___
++} else {
++$code.=<<___;
++	lwz	$t1,`$FRAME+0^$LITTLE_ENDIAN`($sp)
++	lwz	$t0,`$FRAME+4^$LITTLE_ENDIAN`($sp)
++	lwz	$t3,`$FRAME+8^$LITTLE_ENDIAN`($sp)
++	lwz	$t2,`$FRAME+12^$LITTLE_ENDIAN`($sp)
++	lwz	$t5,`$FRAME+16^$LITTLE_ENDIAN`($sp)
++	lwz	$t4,`$FRAME+20^$LITTLE_ENDIAN`($sp)
++	lwz	$t7,`$FRAME+24^$LITTLE_ENDIAN`($sp)
++	lwz	$t6,`$FRAME+28^$LITTLE_ENDIAN`($sp)
++	stfd	$dota,`$FRAME+64`($sp)
++	stfd	$dotb,`$FRAME+72`($sp)
++
++	addc	$t0,$t0,$carry
++	adde	$t1,$t1,$c1
++	srwi	$carry,$t0,16
++	insrwi	$carry,$t1,16,0
++	srwi	$c1,$t1,16
++	addc	$t2,$t2,$carry
++	adde	$t3,$t3,$c1
++	srwi	$carry,$t2,16
++	 insrwi	$t0,$t2,16,0		; 0..31 bits
++	insrwi	$carry,$t3,16,0
++	srwi	$c1,$t3,16
++	addc	$t4,$t4,$carry
++	adde	$t5,$t5,$c1
++	srwi	$carry,$t4,16
++	insrwi	$carry,$t5,16,0
++	srwi	$c1,$t5,16
++	addc	$t6,$t6,$carry
++	adde	$t7,$t7,$c1
++	srwi	$carry,$t6,16
++	 insrwi	$t4,$t6,16,0		; 32..63 bits
++	insrwi	$carry,$t7,16,0
++	srwi	$c1,$t7,16
++	 stw	$t0,12($tp)		; tp[j-1]
++	 stw	$t4,8($tp)
++
++	lwz	$t3,`$FRAME+32^$LITTLE_ENDIAN`($sp)	; permuted $t1
++	lwz	$t2,`$FRAME+36^$LITTLE_ENDIAN`($sp)	; permuted $t0
++	lwz	$t7,`$FRAME+40^$LITTLE_ENDIAN`($sp)	; permuted $t3
++	lwz	$t6,`$FRAME+44^$LITTLE_ENDIAN`($sp)	; permuted $t2
++	lwz	$t1,`$FRAME+48^$LITTLE_ENDIAN`($sp)	; permuted $t5
++	lwz	$t0,`$FRAME+52^$LITTLE_ENDIAN`($sp)	; permuted $t4
++	lwz	$t5,`$FRAME+56^$LITTLE_ENDIAN`($sp)	; permuted $t7
++	lwz	$t4,`$FRAME+60^$LITTLE_ENDIAN`($sp)	; permuted $t6
++
++	addc	$t2,$t2,$carry
++	adde	$t3,$t3,$c1
++	srwi	$carry,$t2,16
++	insrwi	$carry,$t3,16,0
++	srwi	$c1,$t3,16
++	addc	$t6,$t6,$carry
++	adde	$t7,$t7,$c1
++	srwi	$carry,$t6,16
++	 insrwi	$t2,$t6,16,0		; 64..95 bits
++	insrwi	$carry,$t7,16,0
++	srwi	$c1,$t7,16
++	addc	$t0,$t0,$carry
++	adde	$t1,$t1,$c1
++	srwi	$carry,$t0,16
++	insrwi	$carry,$t1,16,0
++	srwi	$c1,$t1,16
++	addc	$t4,$t4,$carry
++	adde	$t5,$t5,$c1
++	srwi	$carry,$t4,16
++	 insrwi	$t0,$t4,16,0		; 96..127 bits
++	insrwi	$carry,$t5,16,0
++	srwi	$c1,$t5,16
++	 stw	$t2,20($tp)		; tp[j]
++	 stwu	$t0,16($tp)
++
++	lwz	$t7,`$FRAME+64^$LITTLE_ENDIAN`($sp)
++	lwz	$t6,`$FRAME+68^$LITTLE_ENDIAN`($sp)
++	lwz	$t5,`$FRAME+72^$LITTLE_ENDIAN`($sp)
++	lwz	$t4,`$FRAME+76^$LITTLE_ENDIAN`($sp)
++
++	addc	$t6,$t6,$carry
++	adde	$t7,$t7,$c1
++	srwi	$carry,$t6,16
++	insrwi	$carry,$t7,16,0
++	srwi	$c1,$t7,16
++	addc	$t4,$t4,$carry
++	adde	$t5,$t5,$c1
++
++	insrwi	$t6,$t4,16,0
++	srwi	$t4,$t4,16
++	insrwi	$t4,$t5,16,0
++	srwi	$ovf,$t5,16
++	stw	$t6,12($tp)		; tp[num-1]
++	stw	$t4,8($tp)
++___
++}
++$code.=<<___;
++	slwi	$t7,$num,2
++	subf	$nap_d,$t7,$nap_d	; rewind pointer
++
++	li	$i,8			; i=1
++.align	5
++Louter:
++	addi	$tp,$sp,`$FRAME+$TRANSFER`
++	li	$carry,0
++	mtctr	$j
++___
++$code.=<<___ if ($SIZE_T==8);
++	ldx	$t3,$bp,$i		; bp[i]
++
++	ld	$t6,`$FRAME+$TRANSFER+8`($sp)	; tp[0]
++	mulld	$t7,$a0,$t3		; ap[0]*bp[i]
++	add	$t7,$t7,$t6		; ap[0]*bp[i]+tp[0]
++	; transfer bp[i] to FPU as 4x16-bit values
++	extrdi	$t0,$t3,16,48
++	extrdi	$t1,$t3,16,32
++	extrdi	$t2,$t3,16,16
++	extrdi	$t3,$t3,16,0
++	std	$t0,`$FRAME+0`($sp)
++	std	$t1,`$FRAME+8`($sp)
++	std	$t2,`$FRAME+16`($sp)
++	std	$t3,`$FRAME+24`($sp)
++
++	mulld	$t7,$t7,$n0		; tp[0]*n0
++	; transfer (ap[0]*bp[i]+tp[0])*n0 to FPU as 4x16-bit values
++	extrdi	$t4,$t7,16,48
++	extrdi	$t5,$t7,16,32
++	extrdi	$t6,$t7,16,16
++	extrdi	$t7,$t7,16,0
++	std	$t4,`$FRAME+32`($sp)
++	std	$t5,`$FRAME+40`($sp)
++	std	$t6,`$FRAME+48`($sp)
++	std	$t7,`$FRAME+56`($sp)
++___
++$code.=<<___ if ($SIZE_T==4);
++	add	$t0,$bp,$i
++	li	$c1,0
++	lwz	$t1,0($t0)		; bp[i,i+1]
++	lwz	$t3,4($t0)
++
++	mullw	$t4,$a0,$t1		; ap[0]*bp[i]
++	lwz	$t0,`$FRAME+$TRANSFER+8+4`($sp)	; tp[0]
++	mulhwu	$t5,$a0,$t1
++	lwz	$t2,`$FRAME+$TRANSFER+8`($sp)	; tp[0]
++	mullw	$t6,$a1,$t1
++	mullw	$t7,$a0,$t3
++	add	$t5,$t5,$t6
++	add	$t5,$t5,$t7
++	addc	$t4,$t4,$t0		; ap[0]*bp[i]+tp[0]
++	adde	$t5,$t5,$t2
++	; transfer bp[i] to FPU as 4x16-bit values
++	extrwi	$t0,$t1,16,16
++	extrwi	$t1,$t1,16,0
++	extrwi	$t2,$t3,16,16
++	extrwi	$t3,$t3,16,0
++	std	$t0,`$FRAME+0`($sp)	; yes, std in 32-bit build
++	std	$t1,`$FRAME+8`($sp)
++	std	$t2,`$FRAME+16`($sp)
++	std	$t3,`$FRAME+24`($sp)
++
++	mullw	$t0,$t4,$n0		; mulld tp[0]*n0
++	mulhwu	$t1,$t4,$n0
++	mullw	$t2,$t5,$n0
++	mullw	$t3,$t4,$n1
++	add	$t1,$t1,$t2
++	add	$t1,$t1,$t3
++	; transfer (ap[0]*bp[i]+tp[0])*n0 to FPU as 4x16-bit values
++	extrwi	$t4,$t0,16,16
++	extrwi	$t5,$t0,16,0
++	extrwi	$t6,$t1,16,16
++	extrwi	$t7,$t1,16,0
++	std	$t4,`$FRAME+32`($sp)	; yes, std in 32-bit build
++	std	$t5,`$FRAME+40`($sp)
++	std	$t6,`$FRAME+48`($sp)
++	std	$t7,`$FRAME+56`($sp)
++___
++$code.=<<___;
++	lfd	$A0,8($nap_d)		; load a[j] in double format
++	lfd	$A1,16($nap_d)
++	lfd	$A2,24($nap_d)		; load a[j+1] in double format
++	lfd	$A3,32($nap_d)
++	lfd	$N0,40($nap_d)		; load n[j] in double format
++	lfd	$N1,48($nap_d)
++	lfd	$N2,56($nap_d)		; load n[j+1] in double format
++	lfdu	$N3,64($nap_d)
++
++	lfd	$ba,`$FRAME+0`($sp)
++	lfd	$bb,`$FRAME+8`($sp)
++	lfd	$bc,`$FRAME+16`($sp)
++	lfd	$bd,`$FRAME+24`($sp)
++	lfd	$na,`$FRAME+32`($sp)
++	lfd	$nb,`$FRAME+40`($sp)
++	lfd	$nc,`$FRAME+48`($sp)
++	lfd	$nd,`$FRAME+56`($sp)
++
++	fcfid	$ba,$ba
++	fcfid	$bb,$bb
++	fcfid	$bc,$bc
++	fcfid	$bd,$bd
++	fcfid	$na,$na
++	fcfid	$nb,$nb
++	fcfid	$nc,$nc
++	fcfid	$nd,$nd
++
++	fmul	$T1a,$A1,$ba
++	fmul	$T1b,$A1,$bb
++	fmul	$T2a,$A2,$ba
++	fmul	$T2b,$A2,$bb
++	fmul	$T3a,$A3,$ba
++	fmul	$T3b,$A3,$bb
++	fmul	$T0a,$A0,$ba
++	fmul	$T0b,$A0,$bb
++
++	fmadd	$T1a,$A0,$bc,$T1a
++	fmadd	$T1b,$A0,$bd,$T1b
++	fmadd	$T2a,$A1,$bc,$T2a
++	fmadd	$T2b,$A1,$bd,$T2b
++	fmadd	$T3a,$A2,$bc,$T3a
++	fmadd	$T3b,$A2,$bd,$T3b
++	fmul	$dota,$A3,$bc
++	fmul	$dotb,$A3,$bd
++
++	fmadd	$T1a,$N1,$na,$T1a
++	fmadd	$T1b,$N1,$nb,$T1b
++	 lfd	$A0,8($nap_d)		; load a[j] in double format
++	 lfd	$A1,16($nap_d)
++	fmadd	$T2a,$N2,$na,$T2a
++	fmadd	$T2b,$N2,$nb,$T2b
++	 lfd	$A2,24($nap_d)		; load a[j+1] in double format
++	 lfd	$A3,32($nap_d)
++	fmadd	$T3a,$N3,$na,$T3a
++	fmadd	$T3b,$N3,$nb,$T3b
++	fmadd	$T0a,$N0,$na,$T0a
++	fmadd	$T0b,$N0,$nb,$T0b
++
++	fmadd	$T1a,$N0,$nc,$T1a
++	fmadd	$T1b,$N0,$nd,$T1b
++	fmadd	$T2a,$N1,$nc,$T2a
++	fmadd	$T2b,$N1,$nd,$T2b
++	fmadd	$T3a,$N2,$nc,$T3a
++	fmadd	$T3b,$N2,$nd,$T3b
++	fmadd	$dota,$N3,$nc,$dota
++	fmadd	$dotb,$N3,$nd,$dotb
++
++	fctid	$T0a,$T0a
++	fctid	$T0b,$T0b
++	fctid	$T1a,$T1a
++	fctid	$T1b,$T1b
++	fctid	$T2a,$T2a
++	fctid	$T2b,$T2b
++	fctid	$T3a,$T3a
++	fctid	$T3b,$T3b
++
++	stfd	$T0a,`$FRAME+0`($sp)
++	stfd	$T0b,`$FRAME+8`($sp)
++	stfd	$T1a,`$FRAME+16`($sp)
++	stfd	$T1b,`$FRAME+24`($sp)
++	stfd	$T2a,`$FRAME+32`($sp)
++	stfd	$T2b,`$FRAME+40`($sp)
++	stfd	$T3a,`$FRAME+48`($sp)
++	stfd	$T3b,`$FRAME+56`($sp)
++
++.align	5
++Linner:
++	fmul	$T1a,$A1,$ba
++	fmul	$T1b,$A1,$bb
++	fmul	$T2a,$A2,$ba
++	fmul	$T2b,$A2,$bb
++	lfd	$N0,40($nap_d)		; load n[j] in double format
++	lfd	$N1,48($nap_d)
++	fmul	$T3a,$A3,$ba
++	fmul	$T3b,$A3,$bb
++	fmadd	$T0a,$A0,$ba,$dota
++	fmadd	$T0b,$A0,$bb,$dotb
++	lfd	$N2,56($nap_d)		; load n[j+1] in double format
++	lfdu	$N3,64($nap_d)
++
++	fmadd	$T1a,$A0,$bc,$T1a
++	fmadd	$T1b,$A0,$bd,$T1b
++	fmadd	$T2a,$A1,$bc,$T2a
++	fmadd	$T2b,$A1,$bd,$T2b
++	 lfd	$A0,8($nap_d)		; load a[j] in double format
++	 lfd	$A1,16($nap_d)
++	fmadd	$T3a,$A2,$bc,$T3a
++	fmadd	$T3b,$A2,$bd,$T3b
++	fmul	$dota,$A3,$bc
++	fmul	$dotb,$A3,$bd
++	 lfd	$A2,24($nap_d)		; load a[j+1] in double format
++	 lfd	$A3,32($nap_d)
++___
++if ($SIZE_T==8 or $flavour =~ /osx/) {
++$code.=<<___;
++	fmadd	$T1a,$N1,$na,$T1a
++	fmadd	$T1b,$N1,$nb,$T1b
++	 ld	$t0,`$FRAME+0`($sp)
++	 ld	$t1,`$FRAME+8`($sp)
++	fmadd	$T2a,$N2,$na,$T2a
++	fmadd	$T2b,$N2,$nb,$T2b
++	 ld	$t2,`$FRAME+16`($sp)
++	 ld	$t3,`$FRAME+24`($sp)
++	fmadd	$T3a,$N3,$na,$T3a
++	fmadd	$T3b,$N3,$nb,$T3b
++	 add	$t0,$t0,$carry		; can not overflow
++	 ld	$t4,`$FRAME+32`($sp)
++	 ld	$t5,`$FRAME+40`($sp)
++	fmadd	$T0a,$N0,$na,$T0a
++	fmadd	$T0b,$N0,$nb,$T0b
++	 srdi	$carry,$t0,16
++	 add	$t1,$t1,$carry
++	 srdi	$carry,$t1,16
++	 ld	$t6,`$FRAME+48`($sp)
++	 ld	$t7,`$FRAME+56`($sp)
++
++	fmadd	$T1a,$N0,$nc,$T1a
++	fmadd	$T1b,$N0,$nd,$T1b
++	 insrdi	$t0,$t1,16,32
++	 ld	$t1,8($tp)		; tp[j]
++	fmadd	$T2a,$N1,$nc,$T2a
++	fmadd	$T2b,$N1,$nd,$T2b
++	 add	$t2,$t2,$carry
++	fmadd	$T3a,$N2,$nc,$T3a
++	fmadd	$T3b,$N2,$nd,$T3b
++	 srdi	$carry,$t2,16
++	 insrdi	$t0,$t2,16,16
++	fmadd	$dota,$N3,$nc,$dota
++	fmadd	$dotb,$N3,$nd,$dotb
++	 add	$t3,$t3,$carry
++	 ldu	$t2,16($tp)		; tp[j+1]
++	 srdi	$carry,$t3,16
++	 insrdi	$t0,$t3,16,0		; 0..63 bits
++	 add	$t4,$t4,$carry
++
++	fctid	$T0a,$T0a
++	fctid	$T0b,$T0b
++	 srdi	$carry,$t4,16
++	fctid	$T1a,$T1a
++	fctid	$T1b,$T1b
++	 add	$t5,$t5,$carry
++	fctid	$T2a,$T2a
++	fctid	$T2b,$T2b
++	 srdi	$carry,$t5,16
++	 insrdi	$t4,$t5,16,32
++	fctid	$T3a,$T3a
++	fctid	$T3b,$T3b
++	 add	$t6,$t6,$carry
++	 srdi	$carry,$t6,16
++	 insrdi	$t4,$t6,16,16
++
++	stfd	$T0a,`$FRAME+0`($sp)
++	stfd	$T0b,`$FRAME+8`($sp)
++	 add	$t7,$t7,$carry
++	 addc	$t3,$t0,$t1
++___
++$code.=<<___ if ($SIZE_T==4);		# adjust XER[CA]
++	extrdi	$t0,$t0,32,0
++	extrdi	$t1,$t1,32,0
++	adde	$t0,$t0,$t1
++___
++$code.=<<___;
++	stfd	$T1a,`$FRAME+16`($sp)
++	stfd	$T1b,`$FRAME+24`($sp)
++	 insrdi	$t4,$t7,16,0		; 64..127 bits
++	 srdi	$carry,$t7,16		; upper 33 bits
++	stfd	$T2a,`$FRAME+32`($sp)
++	stfd	$T2b,`$FRAME+40`($sp)
++	 adde	$t5,$t4,$t2
++___
++$code.=<<___ if ($SIZE_T==4);		# adjust XER[CA]
++	extrdi	$t4,$t4,32,0
++	extrdi	$t2,$t2,32,0
++	adde	$t4,$t4,$t2
++___
++$code.=<<___;
++	stfd	$T3a,`$FRAME+48`($sp)
++	stfd	$T3b,`$FRAME+56`($sp)
++	 addze	$carry,$carry
++	 std	$t3,-16($tp)		; tp[j-1]
++	 std	$t5,-8($tp)		; tp[j]
++___
++} else {
++$code.=<<___;
++	fmadd	$T1a,$N1,$na,$T1a
++	fmadd	$T1b,$N1,$nb,$T1b
++	 lwz	$t1,`$FRAME+0^$LITTLE_ENDIAN`($sp)
++	 lwz	$t0,`$FRAME+4^$LITTLE_ENDIAN`($sp)
++	fmadd	$T2a,$N2,$na,$T2a
++	fmadd	$T2b,$N2,$nb,$T2b
++	 lwz	$t3,`$FRAME+8^$LITTLE_ENDIAN`($sp)
++	 lwz	$t2,`$FRAME+12^$LITTLE_ENDIAN`($sp)
++	fmadd	$T3a,$N3,$na,$T3a
++	fmadd	$T3b,$N3,$nb,$T3b
++	 lwz	$t5,`$FRAME+16^$LITTLE_ENDIAN`($sp)
++	 lwz	$t4,`$FRAME+20^$LITTLE_ENDIAN`($sp)
++	 addc	$t0,$t0,$carry
++	 adde	$t1,$t1,$c1
++	 srwi	$carry,$t0,16
++	fmadd	$T0a,$N0,$na,$T0a
++	fmadd	$T0b,$N0,$nb,$T0b
++	 lwz	$t7,`$FRAME+24^$LITTLE_ENDIAN`($sp)
++	 lwz	$t6,`$FRAME+28^$LITTLE_ENDIAN`($sp)
++	 srwi	$c1,$t1,16
++	 insrwi	$carry,$t1,16,0
++
++	fmadd	$T1a,$N0,$nc,$T1a
++	fmadd	$T1b,$N0,$nd,$T1b
++	 addc	$t2,$t2,$carry
++	 adde	$t3,$t3,$c1
++	 srwi	$carry,$t2,16
++	fmadd	$T2a,$N1,$nc,$T2a
++	fmadd	$T2b,$N1,$nd,$T2b
++	 insrwi	$t0,$t2,16,0		; 0..31 bits
++	 srwi	$c1,$t3,16
++	 insrwi	$carry,$t3,16,0
++	fmadd	$T3a,$N2,$nc,$T3a
++	fmadd	$T3b,$N2,$nd,$T3b
++	 lwz	$t2,12($tp)		; tp[j]
++	 lwz	$t3,8($tp)
++	 addc	$t4,$t4,$carry
++	 adde	$t5,$t5,$c1
++	 srwi	$carry,$t4,16
++	fmadd	$dota,$N3,$nc,$dota
++	fmadd	$dotb,$N3,$nd,$dotb
++	 srwi	$c1,$t5,16
++	 insrwi	$carry,$t5,16,0
++
++	fctid	$T0a,$T0a
++	 addc	$t6,$t6,$carry
++	 adde	$t7,$t7,$c1
++	 srwi	$carry,$t6,16
++	fctid	$T0b,$T0b
++	 insrwi	$t4,$t6,16,0		; 32..63 bits
++	 srwi	$c1,$t7,16
++	 insrwi	$carry,$t7,16,0
++	fctid	$T1a,$T1a
++	 addc	$t0,$t0,$t2
++	 adde	$t4,$t4,$t3
++	 lwz	$t3,`$FRAME+32^$LITTLE_ENDIAN`($sp)	; permuted $t1
++	 lwz	$t2,`$FRAME+36^$LITTLE_ENDIAN`($sp)	; permuted $t0
++	fctid	$T1b,$T1b
++	 addze	$carry,$carry
++	 addze	$c1,$c1
++	 stw	$t0,4($tp)		; tp[j-1]
++	 stw	$t4,0($tp)
++	fctid	$T2a,$T2a
++	 addc	$t2,$t2,$carry
++	 adde	$t3,$t3,$c1
++	 srwi	$carry,$t2,16
++	 lwz	$t7,`$FRAME+40^$LITTLE_ENDIAN`($sp)	; permuted $t3
++	 lwz	$t6,`$FRAME+44^$LITTLE_ENDIAN`($sp)	; permuted $t2
++	fctid	$T2b,$T2b
++	 srwi	$c1,$t3,16
++	 insrwi	$carry,$t3,16,0
++	 lwz	$t1,`$FRAME+48^$LITTLE_ENDIAN`($sp)	; permuted $t5
++	 lwz	$t0,`$FRAME+52^$LITTLE_ENDIAN`($sp)	; permuted $t4
++	fctid	$T3a,$T3a
++	 addc	$t6,$t6,$carry
++	 adde	$t7,$t7,$c1
++	 srwi	$carry,$t6,16
++	 lwz	$t5,`$FRAME+56^$LITTLE_ENDIAN`($sp)	; permuted $t7
++	 lwz	$t4,`$FRAME+60^$LITTLE_ENDIAN`($sp)	; permuted $t6
++	fctid	$T3b,$T3b
++
++	 insrwi	$t2,$t6,16,0		; 64..95 bits
++	insrwi	$carry,$t7,16,0
++	srwi	$c1,$t7,16
++	 lwz	$t6,20($tp)
++	 lwzu	$t7,16($tp)
++	addc	$t0,$t0,$carry
++	 stfd	$T0a,`$FRAME+0`($sp)
++	adde	$t1,$t1,$c1
++	srwi	$carry,$t0,16
++	 stfd	$T0b,`$FRAME+8`($sp)
++	insrwi	$carry,$t1,16,0
++	srwi	$c1,$t1,16
++	addc	$t4,$t4,$carry
++	 stfd	$T1a,`$FRAME+16`($sp)
++	adde	$t5,$t5,$c1
++	srwi	$carry,$t4,16
++	 insrwi	$t0,$t4,16,0		; 96..127 bits
++	 stfd	$T1b,`$FRAME+24`($sp)
++	insrwi	$carry,$t5,16,0
++	srwi	$c1,$t5,16
++
++	addc	$t2,$t2,$t6
++	 stfd	$T2a,`$FRAME+32`($sp)
++	adde	$t0,$t0,$t7
++	 stfd	$T2b,`$FRAME+40`($sp)
++	addze	$carry,$carry
++	 stfd	$T3a,`$FRAME+48`($sp)
++	addze	$c1,$c1
++	 stfd	$T3b,`$FRAME+56`($sp)
++	 stw	$t2,-4($tp)		; tp[j]
++	 stw	$t0,-8($tp)
++___
++}
++$code.=<<___;
++	bdnz	Linner
++
++	fctid	$dota,$dota
++	fctid	$dotb,$dotb
++___
++if ($SIZE_T==8 or $flavour =~ /osx/) {
++$code.=<<___;
++	ld	$t0,`$FRAME+0`($sp)
++	ld	$t1,`$FRAME+8`($sp)
++	ld	$t2,`$FRAME+16`($sp)
++	ld	$t3,`$FRAME+24`($sp)
++	ld	$t4,`$FRAME+32`($sp)
++	ld	$t5,`$FRAME+40`($sp)
++	ld	$t6,`$FRAME+48`($sp)
++	ld	$t7,`$FRAME+56`($sp)
++	stfd	$dota,`$FRAME+64`($sp)
++	stfd	$dotb,`$FRAME+72`($sp)
++
++	add	$t0,$t0,$carry		; can not overflow
++	srdi	$carry,$t0,16
++	add	$t1,$t1,$carry
++	srdi	$carry,$t1,16
++	insrdi	$t0,$t1,16,32
++	add	$t2,$t2,$carry
++	ld	$t1,8($tp)		; tp[j]
++	srdi	$carry,$t2,16
++	insrdi	$t0,$t2,16,16
++	add	$t3,$t3,$carry
++	ldu	$t2,16($tp)		; tp[j+1]
++	srdi	$carry,$t3,16
++	insrdi	$t0,$t3,16,0		; 0..63 bits
++	add	$t4,$t4,$carry
++	srdi	$carry,$t4,16
++	add	$t5,$t5,$carry
++	srdi	$carry,$t5,16
++	insrdi	$t4,$t5,16,32
++	add	$t6,$t6,$carry
++	srdi	$carry,$t6,16
++	insrdi	$t4,$t6,16,16
++	add	$t7,$t7,$carry
++	insrdi	$t4,$t7,16,0		; 64..127 bits
++	srdi	$carry,$t7,16		; upper 33 bits
++	ld	$t6,`$FRAME+64`($sp)
++	ld	$t7,`$FRAME+72`($sp)
++
++	addc	$t3,$t0,$t1
++___
++$code.=<<___ if ($SIZE_T==4);		# adjust XER[CA]
++	extrdi	$t0,$t0,32,0
++	extrdi	$t1,$t1,32,0
++	adde	$t0,$t0,$t1
++___
++$code.=<<___;
++	adde	$t5,$t4,$t2
++___
++$code.=<<___ if ($SIZE_T==4);		# adjust XER[CA]
++	extrdi	$t4,$t4,32,0
++	extrdi	$t2,$t2,32,0
++	adde	$t4,$t4,$t2
++___
++$code.=<<___;
++	addze	$carry,$carry
++
++	std	$t3,-16($tp)		; tp[j-1]
++	std	$t5,-8($tp)		; tp[j]
++
++	add	$carry,$carry,$ovf	; comsume upmost overflow
++	add	$t6,$t6,$carry		; can not overflow
++	srdi	$carry,$t6,16
++	add	$t7,$t7,$carry
++	insrdi	$t6,$t7,48,0
++	srdi	$ovf,$t7,48
++	std	$t6,0($tp)		; tp[num-1]
++___
++} else {
++$code.=<<___;
++	lwz	$t1,`$FRAME+0^$LITTLE_ENDIAN`($sp)
++	lwz	$t0,`$FRAME+4^$LITTLE_ENDIAN`($sp)
++	lwz	$t3,`$FRAME+8^$LITTLE_ENDIAN`($sp)
++	lwz	$t2,`$FRAME+12^$LITTLE_ENDIAN`($sp)
++	lwz	$t5,`$FRAME+16^$LITTLE_ENDIAN`($sp)
++	lwz	$t4,`$FRAME+20^$LITTLE_ENDIAN`($sp)
++	lwz	$t7,`$FRAME+24^$LITTLE_ENDIAN`($sp)
++	lwz	$t6,`$FRAME+28^$LITTLE_ENDIAN`($sp)
++	stfd	$dota,`$FRAME+64`($sp)
++	stfd	$dotb,`$FRAME+72`($sp)
++
++	addc	$t0,$t0,$carry
++	adde	$t1,$t1,$c1
++	srwi	$carry,$t0,16
++	insrwi	$carry,$t1,16,0
++	srwi	$c1,$t1,16
++	addc	$t2,$t2,$carry
++	adde	$t3,$t3,$c1
++	srwi	$carry,$t2,16
++	 insrwi	$t0,$t2,16,0		; 0..31 bits
++	 lwz	$t2,12($tp)		; tp[j]
++	insrwi	$carry,$t3,16,0
++	srwi	$c1,$t3,16
++	 lwz	$t3,8($tp)
++	addc	$t4,$t4,$carry
++	adde	$t5,$t5,$c1
++	srwi	$carry,$t4,16
++	insrwi	$carry,$t5,16,0
++	srwi	$c1,$t5,16
++	addc	$t6,$t6,$carry
++	adde	$t7,$t7,$c1
++	srwi	$carry,$t6,16
++	 insrwi	$t4,$t6,16,0		; 32..63 bits
++	insrwi	$carry,$t7,16,0
++	srwi	$c1,$t7,16
++
++	addc	$t0,$t0,$t2
++	adde	$t4,$t4,$t3
++	addze	$carry,$carry
++	addze	$c1,$c1
++	 stw	$t0,4($tp)		; tp[j-1]
++	 stw	$t4,0($tp)
++
++	lwz	$t3,`$FRAME+32^$LITTLE_ENDIAN`($sp)	; permuted $t1
++	lwz	$t2,`$FRAME+36^$LITTLE_ENDIAN`($sp)	; permuted $t0
++	lwz	$t7,`$FRAME+40^$LITTLE_ENDIAN`($sp)	; permuted $t3
++	lwz	$t6,`$FRAME+44^$LITTLE_ENDIAN`($sp)	; permuted $t2
++	lwz	$t1,`$FRAME+48^$LITTLE_ENDIAN`($sp)	; permuted $t5
++	lwz	$t0,`$FRAME+52^$LITTLE_ENDIAN`($sp)	; permuted $t4
++	lwz	$t5,`$FRAME+56^$LITTLE_ENDIAN`($sp)	; permuted $t7
++	lwz	$t4,`$FRAME+60^$LITTLE_ENDIAN`($sp)	; permuted $t6
++
++	addc	$t2,$t2,$carry
++	adde	$t3,$t3,$c1
++	srwi	$carry,$t2,16
++	insrwi	$carry,$t3,16,0
++	srwi	$c1,$t3,16
++	addc	$t6,$t6,$carry
++	adde	$t7,$t7,$c1
++	srwi	$carry,$t6,16
++	 insrwi	$t2,$t6,16,0		; 64..95 bits
++	 lwz	$t6,20($tp)
++	insrwi	$carry,$t7,16,0
++	srwi	$c1,$t7,16
++	 lwzu	$t7,16($tp)
++	addc	$t0,$t0,$carry
++	adde	$t1,$t1,$c1
++	srwi	$carry,$t0,16
++	insrwi	$carry,$t1,16,0
++	srwi	$c1,$t1,16
++	addc	$t4,$t4,$carry
++	adde	$t5,$t5,$c1
++	srwi	$carry,$t4,16
++	 insrwi	$t0,$t4,16,0		; 96..127 bits
++	insrwi	$carry,$t5,16,0
++	srwi	$c1,$t5,16
++
++	addc	$t2,$t2,$t6
++	adde	$t0,$t0,$t7
++	 lwz	$t7,`$FRAME+64^$LITTLE_ENDIAN`($sp)
++	 lwz	$t6,`$FRAME+68^$LITTLE_ENDIAN`($sp)
++	addze	$carry,$carry
++	addze	$c1,$c1
++	 lwz	$t5,`$FRAME+72^$LITTLE_ENDIAN`($sp)
++	 lwz	$t4,`$FRAME+76^$LITTLE_ENDIAN`($sp)
++
++	addc	$t6,$t6,$carry
++	adde	$t7,$t7,$c1
++	 stw	$t2,-4($tp)		; tp[j]
++	 stw	$t0,-8($tp)
++	addc	$t6,$t6,$ovf
++	addze	$t7,$t7
++	srwi	$carry,$t6,16
++	insrwi	$carry,$t7,16,0
++	srwi	$c1,$t7,16
++	addc	$t4,$t4,$carry
++	adde	$t5,$t5,$c1
++
++	insrwi	$t6,$t4,16,0
++	srwi	$t4,$t4,16
++	insrwi	$t4,$t5,16,0
++	srwi	$ovf,$t5,16
++	stw	$t6,4($tp)		; tp[num-1]
++	stw	$t4,0($tp)
++___
++}
++$code.=<<___;
++	slwi	$t7,$num,2
++	addi	$i,$i,8
++	subf	$nap_d,$t7,$nap_d	; rewind pointer
++	cmpw	$i,$num
++	blt-	Louter
++___
++
++$code.=<<___ if ($SIZE_T==8);
++	subf	$np,$num,$np	; rewind np
++	addi	$j,$j,1		; restore counter
++	subfc	$i,$i,$i	; j=0 and "clear" XER[CA]
++	addi	$tp,$sp,`$FRAME+$TRANSFER+8`
++	addi	$t4,$sp,`$FRAME+$TRANSFER+16`
++	addi	$t5,$np,8
++	addi	$t6,$rp,8
++	mtctr	$j
++
++.align	4
++Lsub:	ldx	$t0,$tp,$i
++	ldx	$t1,$np,$i
++	ldx	$t2,$t4,$i
++	ldx	$t3,$t5,$i
++	subfe	$t0,$t1,$t0	; tp[j]-np[j]
++	subfe	$t2,$t3,$t2	; tp[j+1]-np[j+1]
++	stdx	$t0,$rp,$i
++	stdx	$t2,$t6,$i
++	addi	$i,$i,16
++	bdnz	Lsub
++
++	li	$i,0
++	subfe	$ovf,$i,$ovf	; handle upmost overflow bit
++	and	$ap,$tp,$ovf
++	andc	$np,$rp,$ovf
++	or	$ap,$ap,$np	; ap=borrow?tp:rp
++	addi	$t7,$ap,8
++	mtctr	$j
++
++.align	4
++Lcopy:				; copy or in-place refresh
++	ldx	$t0,$ap,$i
++	ldx	$t1,$t7,$i
++	std	$i,8($nap_d)	; zap nap_d
++	std	$i,16($nap_d)
++	std	$i,24($nap_d)
++	std	$i,32($nap_d)
++	std	$i,40($nap_d)
++	std	$i,48($nap_d)
++	std	$i,56($nap_d)
++	stdu	$i,64($nap_d)
++	stdx	$t0,$rp,$i
++	stdx	$t1,$t6,$i
++	stdx	$i,$tp,$i	; zap tp at once
++	stdx	$i,$t4,$i
++	addi	$i,$i,16
++	bdnz	Lcopy
++___
++$code.=<<___ if ($SIZE_T==4);
++	subf	$np,$num,$np	; rewind np
++	addi	$j,$j,1		; restore counter
++	subfc	$i,$i,$i	; j=0 and "clear" XER[CA]
++	addi	$tp,$sp,`$FRAME+$TRANSFER`
++	addi	$np,$np,-4
++	addi	$rp,$rp,-4
++	addi	$ap,$sp,`$FRAME+$TRANSFER+4`
++	mtctr	$j
++
++.align	4
++Lsub:	lwz	$t0,12($tp)	; load tp[j..j+3] in 64-bit word order
++	lwz	$t1,8($tp)
++	lwz	$t2,20($tp)
++	lwzu	$t3,16($tp)
++	lwz	$t4,4($np)	; load np[j..j+3] in 32-bit word order
++	lwz	$t5,8($np)
++	lwz	$t6,12($np)
++	lwzu	$t7,16($np)
++	subfe	$t4,$t4,$t0	; tp[j]-np[j]
++	 stw	$t0,4($ap)	; save tp[j..j+3] in 32-bit word order
++	subfe	$t5,$t5,$t1	; tp[j+1]-np[j+1]
++	 stw	$t1,8($ap)
++	subfe	$t6,$t6,$t2	; tp[j+2]-np[j+2]
++	 stw	$t2,12($ap)
++	subfe	$t7,$t7,$t3	; tp[j+3]-np[j+3]
++	 stwu	$t3,16($ap)
++	stw	$t4,4($rp)
++	stw	$t5,8($rp)
++	stw	$t6,12($rp)
++	stwu	$t7,16($rp)
++	bdnz	Lsub
++
++	li	$i,0
++	subfe	$ovf,$i,$ovf	; handle upmost overflow bit
++	addi	$tp,$sp,`$FRAME+$TRANSFER+4`
++	subf	$rp,$num,$rp	; rewind rp
++	and	$ap,$tp,$ovf
++	andc	$np,$rp,$ovf
++	or	$ap,$ap,$np	; ap=borrow?tp:rp
++	addi	$tp,$sp,`$FRAME+$TRANSFER`
++	mtctr	$j
++
++.align	4
++Lcopy:				; copy or in-place refresh
++	lwz	$t0,4($ap)
++	lwz	$t1,8($ap)
++	lwz	$t2,12($ap)
++	lwzu	$t3,16($ap)
++	std	$i,8($nap_d)	; zap nap_d
++	std	$i,16($nap_d)
++	std	$i,24($nap_d)
++	std	$i,32($nap_d)
++	std	$i,40($nap_d)
++	std	$i,48($nap_d)
++	std	$i,56($nap_d)
++	stdu	$i,64($nap_d)
++	stw	$t0,4($rp)
++	stw	$t1,8($rp)
++	stw	$t2,12($rp)
++	stwu	$t3,16($rp)
++	std	$i,8($tp)	; zap tp at once
++	stdu	$i,16($tp)
++	bdnz	Lcopy
++___
++
++$code.=<<___;
++	$POP	$i,0($sp)
++	li	r3,1	; signal "handled"
++	$POP	r19,`-12*8-13*$SIZE_T`($i)
++	$POP	r20,`-12*8-12*$SIZE_T`($i)
++	$POP	r21,`-12*8-11*$SIZE_T`($i)
++	$POP	r22,`-12*8-10*$SIZE_T`($i)
++	$POP	r23,`-12*8-9*$SIZE_T`($i)
++	$POP	r24,`-12*8-8*$SIZE_T`($i)
++	$POP	r25,`-12*8-7*$SIZE_T`($i)
++	$POP	r26,`-12*8-6*$SIZE_T`($i)
++	$POP	r27,`-12*8-5*$SIZE_T`($i)
++	$POP	r28,`-12*8-4*$SIZE_T`($i)
++	$POP	r29,`-12*8-3*$SIZE_T`($i)
++	$POP	r30,`-12*8-2*$SIZE_T`($i)
++	$POP	r31,`-12*8-1*$SIZE_T`($i)
++	lfd	f20,`-12*8`($i)
++	lfd	f21,`-11*8`($i)
++	lfd	f22,`-10*8`($i)
++	lfd	f23,`-9*8`($i)
++	lfd	f24,`-8*8`($i)
++	lfd	f25,`-7*8`($i)
++	lfd	f26,`-6*8`($i)
++	lfd	f27,`-5*8`($i)
++	lfd	f28,`-4*8`($i)
++	lfd	f29,`-3*8`($i)
++	lfd	f30,`-2*8`($i)
++	lfd	f31,`-1*8`($i)
++	mr	$sp,$i
++	blr
++	.long	0
++	.byte	0,12,4,0,0x8c,13,6,0
++	.long	0
++.size	.$fname,.-.$fname
++
++.asciz  "Montgomery Multiplication for PPC64, CRYPTOGAMS by "
++___
++
++$code =~ s/\`([^\`]*)\`/eval $1/gem;
++print $code;
++close STDOUT;
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/bn/asm/rsaz-avx2.pl b/CryptoPkg/Library/OpensslLib/openssl/crypto/bn/asm/rsaz-avx2.pl
+new file mode 100755
+index 0000000..0c1b236
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/bn/asm/rsaz-avx2.pl
+@@ -0,0 +1,1968 @@
++#! /usr/bin/env perl
++# Copyright 2013-2016 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
++# in the file LICENSE in the source distribution or at
++# https://www.openssl.org/source/license.html
++
++
++##############################################################################
++#                                                                            #
++#  Copyright (c) 2012, Intel Corporation                                     #
++#                                                                            #
++#  All rights reserved.                                                      #
++#                                                                            #
++#  Redistribution and use in source and binary forms, with or without        #
++#  modification, are permitted provided that the following conditions are    #
++#  met:                                                                      #
++#                                                                            #
++#  *  Redistributions of source code must retain the above copyright         #
++#     notice, this list of conditions and the following disclaimer.          #
++#                                                                            #
++#  *  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.                                                          #
++#                                                                            #
++#  *  Neither the name of the Intel Corporation nor the names of its         #
++#     contributors may be used to endorse or promote products derived from   #
++#     this software without specific prior written permission.               #
++#                                                                            #
++#                                                                            #
++#  THIS SOFTWARE IS PROVIDED BY INTEL CORPORATION ""AS IS"" AND ANY          #
++#  EXPRESS 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 INTEL CORPORATION OR            #
++#  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.              #
++#                                                                            #
++##############################################################################
++# Developers and authors:                                                    #
++# Shay Gueron (1, 2), and Vlad Krasnov (1)                                   #
++# (1) Intel Corporation, Israel Development Center, Haifa, Israel            #
++# (2) University of Haifa, Israel                                            #
++##############################################################################
++# Reference:                                                                 #
++# [1] S. Gueron, V. Krasnov: "Software Implementation of Modular             #
++#     Exponentiation,  Using Advanced Vector Instructions Architectures",    #
++#     F. Ozbudak and F. Rodriguez-Henriquez (Eds.): WAIFI 2012, LNCS 7369,   #
++#     pp. 119?135, 2012. Springer-Verlag Berlin Heidelberg 2012              #
++# [2] S. Gueron: "Efficient Software Implementations of Modular              #
++#     Exponentiation", Journal of Cryptographic Engineering 2:31-43 (2012).  #
++# [3] S. Gueron, V. Krasnov: "Speeding up Big-numbers Squaring",IEEE         #
++#     Proceedings of 9th International Conference on Information Technology: #
++#     New Generations (ITNG 2012), pp.821-823 (2012)                         #
++# [4] S. Gueron, V. Krasnov: "[PATCH] Efficient and side channel analysis    #
++#     resistant 1024-bit modular exponentiation, for optimizing RSA2048      #
++#     on AVX2 capable x86_64 platforms",                                     #
++#     http://rt.openssl.org/Ticket/Display.html?id=2850&user=guest&pass=guest#
++##############################################################################
++#
++# +13% improvement over original submission by 
++#
++# rsa2048 sign/sec	OpenSSL 1.0.1	scalar(*)	this
++# 2.3GHz Haswell	621		765/+23%	1113/+79%
++# 2.3GHz Broadwell(**)	688		1200(***)/+74%	1120/+63%
++#
++# (*)	if system doesn't support AVX2, for reference purposes;
++# (**)	scaled to 2.3GHz to simplify comparison;
++# (***)	scalar AD*X code is faster than AVX2 and is preferred code
++#	path for Broadwell;
++
++$flavour = shift;
++$output  = shift;
++if ($flavour =~ /\./) { $output = $flavour; undef $flavour; }
++
++$win64=0; $win64=1 if ($flavour =~ /[nm]asm|mingw64/ || $output =~ /\.asm$/);
++
++$0 =~ m/(.*[\/\\])[^\/\\]+$/; $dir=$1;
++( $xlate="${dir}x86_64-xlate.pl" and -f $xlate ) or
++( $xlate="${dir}../../perlasm/x86_64-xlate.pl" and -f $xlate) or
++die "can't locate x86_64-xlate.pl";
++
++if (`$ENV{CC} -Wa,-v -c -o /dev/null -x assembler /dev/null 2>&1`
++		=~ /GNU assembler version ([2-9]\.[0-9]+)/) {
++	$avx = ($1>=2.19) + ($1>=2.22);
++	$addx = ($1>=2.23);
++}
++
++if (!$avx && $win64 && ($flavour =~ /nasm/ || $ENV{ASM} =~ /nasm/) &&
++	    `nasm -v 2>&1` =~ /NASM version ([2-9]\.[0-9]+)/) {
++	$avx = ($1>=2.09) + ($1>=2.10);
++	$addx = ($1>=2.10);
++}
++
++if (!$avx && $win64 && ($flavour =~ /masm/ || $ENV{ASM} =~ /ml64/) &&
++	    `ml64 2>&1` =~ /Version ([0-9]+)\./) {
++	$avx = ($1>=10) + ($1>=11);
++	$addx = ($1>=11);
++}
++
++if (!$avx && `$ENV{CC} -v 2>&1` =~ /(^clang version|based on LLVM) ([3-9])\.([0-9]+)/) {
++	my $ver = $2 + $3/100.0;	# 3.1->3.01, 3.10->3.10
++	$avx = ($ver>=3.0) + ($ver>=3.01);
++	$addx = ($ver>=3.03);
++}
++
++open OUT,"| \"$^X\" \"$xlate\" $flavour \"$output\"";
++*STDOUT = *OUT;
++
++if ($avx>1) {{{
++{ # void AMS_WW(
++my $rp="%rdi";	# BN_ULONG *rp,
++my $ap="%rsi";	# const BN_ULONG *ap,
++my $np="%rdx";	# const BN_ULONG *np,
++my $n0="%ecx";	# const BN_ULONG n0,
++my $rep="%r8d";	# int repeat);
++
++# The registers that hold the accumulated redundant result
++# The AMM works on 1024 bit operands, and redundant word size is 29
++# Therefore: ceil(1024/29)/4 = 9
++my $ACC0="%ymm0";
++my $ACC1="%ymm1";
++my $ACC2="%ymm2";
++my $ACC3="%ymm3";
++my $ACC4="%ymm4";
++my $ACC5="%ymm5";
++my $ACC6="%ymm6";
++my $ACC7="%ymm7";
++my $ACC8="%ymm8";
++my $ACC9="%ymm9";
++# Registers that hold the broadcasted words of bp, currently used
++my $B1="%ymm10";
++my $B2="%ymm11";
++# Registers that hold the broadcasted words of Y, currently used
++my $Y1="%ymm12";
++my $Y2="%ymm13";
++# Helper registers
++my $TEMP1="%ymm14";
++my $AND_MASK="%ymm15";
++# alu registers that hold the first words of the ACC
++my $r0="%r9";
++my $r1="%r10";
++my $r2="%r11";
++my $r3="%r12";
++
++my $i="%r14d";			# loop counter
++my $tmp = "%r15";
++
++my $FrameSize=32*18+32*8;	# place for A^2 and 2*A
++
++my $aap=$r0;
++my $tp0="%rbx";
++my $tp1=$r3;
++my $tpa=$tmp;
++
++$np="%r13";			# reassigned argument
++
++$code.=<<___;
++.text
++
++.globl	rsaz_1024_sqr_avx2
++.type	rsaz_1024_sqr_avx2,\@function,5
++.align	64
++rsaz_1024_sqr_avx2:		# 702 cycles, 14% faster than rsaz_1024_mul_avx2
++	lea	(%rsp), %rax
++	push	%rbx
++	push	%rbp
++	push	%r12
++	push	%r13
++	push	%r14
++	push	%r15
++	vzeroupper
++___
++$code.=<<___ if ($win64);
++	lea	-0xa8(%rsp),%rsp
++	vmovaps	%xmm6,-0xd8(%rax)
++	vmovaps	%xmm7,-0xc8(%rax)
++	vmovaps	%xmm8,-0xb8(%rax)
++	vmovaps	%xmm9,-0xa8(%rax)
++	vmovaps	%xmm10,-0x98(%rax)
++	vmovaps	%xmm11,-0x88(%rax)
++	vmovaps	%xmm12,-0x78(%rax)
++	vmovaps	%xmm13,-0x68(%rax)
++	vmovaps	%xmm14,-0x58(%rax)
++	vmovaps	%xmm15,-0x48(%rax)
++.Lsqr_1024_body:
++___
++$code.=<<___;
++	mov	%rax,%rbp
++	mov	%rdx, $np			# reassigned argument
++	sub	\$$FrameSize, %rsp
++	mov	$np, $tmp
++	sub	\$-128, $rp			# size optimization
++	sub	\$-128, $ap
++	sub	\$-128, $np
++
++	and	\$4095, $tmp			# see if $np crosses page
++	add	\$32*10, $tmp
++	shr	\$12, $tmp
++	vpxor	$ACC9,$ACC9,$ACC9
++	jz	.Lsqr_1024_no_n_copy
++
++	# unaligned 256-bit load that crosses page boundary can
++	# cause >2x performance degradation here, so if $np does
++	# cross page boundary, copy it to stack and make sure stack
++	# frame doesn't...
++	sub		\$32*10,%rsp
++	vmovdqu		32*0-128($np), $ACC0
++	and		\$-2048, %rsp
++	vmovdqu		32*1-128($np), $ACC1
++	vmovdqu		32*2-128($np), $ACC2
++	vmovdqu		32*3-128($np), $ACC3
++	vmovdqu		32*4-128($np), $ACC4
++	vmovdqu		32*5-128($np), $ACC5
++	vmovdqu		32*6-128($np), $ACC6
++	vmovdqu		32*7-128($np), $ACC7
++	vmovdqu		32*8-128($np), $ACC8
++	lea		$FrameSize+128(%rsp),$np
++	vmovdqu		$ACC0, 32*0-128($np)
++	vmovdqu		$ACC1, 32*1-128($np)
++	vmovdqu		$ACC2, 32*2-128($np)
++	vmovdqu		$ACC3, 32*3-128($np)
++	vmovdqu		$ACC4, 32*4-128($np)
++	vmovdqu		$ACC5, 32*5-128($np)
++	vmovdqu		$ACC6, 32*6-128($np)
++	vmovdqu		$ACC7, 32*7-128($np)
++	vmovdqu		$ACC8, 32*8-128($np)
++	vmovdqu		$ACC9, 32*9-128($np)	# $ACC9 is zero
++
++.Lsqr_1024_no_n_copy:
++	and		\$-1024, %rsp
++
++	vmovdqu		32*1-128($ap), $ACC1
++	vmovdqu		32*2-128($ap), $ACC2
++	vmovdqu		32*3-128($ap), $ACC3
++	vmovdqu		32*4-128($ap), $ACC4
++	vmovdqu		32*5-128($ap), $ACC5
++	vmovdqu		32*6-128($ap), $ACC6
++	vmovdqu		32*7-128($ap), $ACC7
++	vmovdqu		32*8-128($ap), $ACC8
++
++	lea	192(%rsp), $tp0			# 64+128=192
++	vpbroadcastq	.Land_mask(%rip), $AND_MASK
++	jmp	.LOOP_GRANDE_SQR_1024
++
++.align	32
++.LOOP_GRANDE_SQR_1024:
++	lea	32*18+128(%rsp), $aap		# size optimization
++	lea	448(%rsp), $tp1			# 64+128+256=448
++
++	# the squaring is performed as described in Variant B of
++	# "Speeding up Big-Number Squaring", so start by calculating
++	# the A*2=A+A vector
++	vpaddq		$ACC1, $ACC1, $ACC1
++	 vpbroadcastq	32*0-128($ap), $B1
++	vpaddq		$ACC2, $ACC2, $ACC2
++	vmovdqa		$ACC1, 32*0-128($aap)
++	vpaddq		$ACC3, $ACC3, $ACC3
++	vmovdqa		$ACC2, 32*1-128($aap)
++	vpaddq		$ACC4, $ACC4, $ACC4
++	vmovdqa		$ACC3, 32*2-128($aap)
++	vpaddq		$ACC5, $ACC5, $ACC5
++	vmovdqa		$ACC4, 32*3-128($aap)
++	vpaddq		$ACC6, $ACC6, $ACC6
++	vmovdqa		$ACC5, 32*4-128($aap)
++	vpaddq		$ACC7, $ACC7, $ACC7
++	vmovdqa		$ACC6, 32*5-128($aap)
++	vpaddq		$ACC8, $ACC8, $ACC8
++	vmovdqa		$ACC7, 32*6-128($aap)
++	vpxor		$ACC9, $ACC9, $ACC9
++	vmovdqa		$ACC8, 32*7-128($aap)
++
++	vpmuludq	32*0-128($ap), $B1, $ACC0
++	 vpbroadcastq	32*1-128($ap), $B2
++	 vmovdqu	$ACC9, 32*9-192($tp0)	# zero upper half
++	vpmuludq	$B1, $ACC1, $ACC1
++	 vmovdqu	$ACC9, 32*10-448($tp1)
++	vpmuludq	$B1, $ACC2, $ACC2
++	 vmovdqu	$ACC9, 32*11-448($tp1)
++	vpmuludq	$B1, $ACC3, $ACC3
++	 vmovdqu	$ACC9, 32*12-448($tp1)
++	vpmuludq	$B1, $ACC4, $ACC4
++	 vmovdqu	$ACC9, 32*13-448($tp1)
++	vpmuludq	$B1, $ACC5, $ACC5
++	 vmovdqu	$ACC9, 32*14-448($tp1)
++	vpmuludq	$B1, $ACC6, $ACC6
++	 vmovdqu	$ACC9, 32*15-448($tp1)
++	vpmuludq	$B1, $ACC7, $ACC7
++	 vmovdqu	$ACC9, 32*16-448($tp1)
++	vpmuludq	$B1, $ACC8, $ACC8
++	 vpbroadcastq	32*2-128($ap), $B1
++	 vmovdqu	$ACC9, 32*17-448($tp1)
++
++	mov	$ap, $tpa
++	mov 	\$4, $i
++	jmp	.Lsqr_entry_1024
++___
++$TEMP0=$Y1;
++$TEMP2=$Y2;
++$code.=<<___;
++.align	32
++.LOOP_SQR_1024:
++	 vpbroadcastq	32*1-128($tpa), $B2
++	vpmuludq	32*0-128($ap), $B1, $ACC0
++	vpaddq		32*0-192($tp0), $ACC0, $ACC0
++	vpmuludq	32*0-128($aap), $B1, $ACC1
++	vpaddq		32*1-192($tp0), $ACC1, $ACC1
++	vpmuludq	32*1-128($aap), $B1, $ACC2
++	vpaddq		32*2-192($tp0), $ACC2, $ACC2
++	vpmuludq	32*2-128($aap), $B1, $ACC3
++	vpaddq		32*3-192($tp0), $ACC3, $ACC3
++	vpmuludq	32*3-128($aap), $B1, $ACC4
++	vpaddq		32*4-192($tp0), $ACC4, $ACC4
++	vpmuludq	32*4-128($aap), $B1, $ACC5
++	vpaddq		32*5-192($tp0), $ACC5, $ACC5
++	vpmuludq	32*5-128($aap), $B1, $ACC6
++	vpaddq		32*6-192($tp0), $ACC6, $ACC6
++	vpmuludq	32*6-128($aap), $B1, $ACC7
++	vpaddq		32*7-192($tp0), $ACC7, $ACC7
++	vpmuludq	32*7-128($aap), $B1, $ACC8
++	 vpbroadcastq	32*2-128($tpa), $B1
++	vpaddq		32*8-192($tp0), $ACC8, $ACC8
++.Lsqr_entry_1024:
++	vmovdqu		$ACC0, 32*0-192($tp0)
++	vmovdqu		$ACC1, 32*1-192($tp0)
++
++	vpmuludq	32*1-128($ap), $B2, $TEMP0
++	vpaddq		$TEMP0, $ACC2, $ACC2
++	vpmuludq	32*1-128($aap), $B2, $TEMP1
++	vpaddq		$TEMP1, $ACC3, $ACC3
++	vpmuludq	32*2-128($aap), $B2, $TEMP2
++	vpaddq		$TEMP2, $ACC4, $ACC4
++	vpmuludq	32*3-128($aap), $B2, $TEMP0
++	vpaddq		$TEMP0, $ACC5, $ACC5
++	vpmuludq	32*4-128($aap), $B2, $TEMP1
++	vpaddq		$TEMP1, $ACC6, $ACC6
++	vpmuludq	32*5-128($aap), $B2, $TEMP2
++	vpaddq		$TEMP2, $ACC7, $ACC7
++	vpmuludq	32*6-128($aap), $B2, $TEMP0
++	vpaddq		$TEMP0, $ACC8, $ACC8
++	vpmuludq	32*7-128($aap), $B2, $ACC0
++	 vpbroadcastq	32*3-128($tpa), $B2
++	vpaddq		32*9-192($tp0), $ACC0, $ACC0
++
++	vmovdqu		$ACC2, 32*2-192($tp0)
++	vmovdqu		$ACC3, 32*3-192($tp0)
++
++	vpmuludq	32*2-128($ap), $B1, $TEMP2
++	vpaddq		$TEMP2, $ACC4, $ACC4
++	vpmuludq	32*2-128($aap), $B1, $TEMP0
++	vpaddq		$TEMP0, $ACC5, $ACC5
++	vpmuludq	32*3-128($aap), $B1, $TEMP1
++	vpaddq		$TEMP1, $ACC6, $ACC6
++	vpmuludq	32*4-128($aap), $B1, $TEMP2
++	vpaddq		$TEMP2, $ACC7, $ACC7
++	vpmuludq	32*5-128($aap), $B1, $TEMP0
++	vpaddq		$TEMP0, $ACC8, $ACC8
++	vpmuludq	32*6-128($aap), $B1, $TEMP1
++	vpaddq		$TEMP1, $ACC0, $ACC0
++	vpmuludq	32*7-128($aap), $B1, $ACC1
++	 vpbroadcastq	32*4-128($tpa), $B1
++	vpaddq		32*10-448($tp1), $ACC1, $ACC1
++
++	vmovdqu		$ACC4, 32*4-192($tp0)
++	vmovdqu		$ACC5, 32*5-192($tp0)
++
++	vpmuludq	32*3-128($ap), $B2, $TEMP0
++	vpaddq		$TEMP0, $ACC6, $ACC6
++	vpmuludq	32*3-128($aap), $B2, $TEMP1
++	vpaddq		$TEMP1, $ACC7, $ACC7
++	vpmuludq	32*4-128($aap), $B2, $TEMP2
++	vpaddq		$TEMP2, $ACC8, $ACC8
++	vpmuludq	32*5-128($aap), $B2, $TEMP0
++	vpaddq		$TEMP0, $ACC0, $ACC0
++	vpmuludq	32*6-128($aap), $B2, $TEMP1
++	vpaddq		$TEMP1, $ACC1, $ACC1
++	vpmuludq	32*7-128($aap), $B2, $ACC2
++	 vpbroadcastq	32*5-128($tpa), $B2
++	vpaddq		32*11-448($tp1), $ACC2, $ACC2	
++
++	vmovdqu		$ACC6, 32*6-192($tp0)
++	vmovdqu		$ACC7, 32*7-192($tp0)
++
++	vpmuludq	32*4-128($ap), $B1, $TEMP0
++	vpaddq		$TEMP0, $ACC8, $ACC8
++	vpmuludq	32*4-128($aap), $B1, $TEMP1
++	vpaddq		$TEMP1, $ACC0, $ACC0
++	vpmuludq	32*5-128($aap), $B1, $TEMP2
++	vpaddq		$TEMP2, $ACC1, $ACC1
++	vpmuludq	32*6-128($aap), $B1, $TEMP0
++	vpaddq		$TEMP0, $ACC2, $ACC2
++	vpmuludq	32*7-128($aap), $B1, $ACC3
++	 vpbroadcastq	32*6-128($tpa), $B1
++	vpaddq		32*12-448($tp1), $ACC3, $ACC3
++
++	vmovdqu		$ACC8, 32*8-192($tp0)
++	vmovdqu		$ACC0, 32*9-192($tp0)
++	lea		8($tp0), $tp0
++
++	vpmuludq	32*5-128($ap), $B2, $TEMP2
++	vpaddq		$TEMP2, $ACC1, $ACC1
++	vpmuludq	32*5-128($aap), $B2, $TEMP0
++	vpaddq		$TEMP0, $ACC2, $ACC2
++	vpmuludq	32*6-128($aap), $B2, $TEMP1
++	vpaddq		$TEMP1, $ACC3, $ACC3
++	vpmuludq	32*7-128($aap), $B2, $ACC4
++	 vpbroadcastq	32*7-128($tpa), $B2
++	vpaddq		32*13-448($tp1), $ACC4, $ACC4
++
++	vmovdqu		$ACC1, 32*10-448($tp1)
++	vmovdqu		$ACC2, 32*11-448($tp1)
++
++	vpmuludq	32*6-128($ap), $B1, $TEMP0
++	vpaddq		$TEMP0, $ACC3, $ACC3
++	vpmuludq	32*6-128($aap), $B1, $TEMP1
++	 vpbroadcastq	32*8-128($tpa), $ACC0		# borrow $ACC0 for $B1
++	vpaddq		$TEMP1, $ACC4, $ACC4
++	vpmuludq	32*7-128($aap), $B1, $ACC5
++	 vpbroadcastq	32*0+8-128($tpa), $B1		# for next iteration
++	vpaddq		32*14-448($tp1), $ACC5, $ACC5
++
++	vmovdqu		$ACC3, 32*12-448($tp1)
++	vmovdqu		$ACC4, 32*13-448($tp1)
++	lea		8($tpa), $tpa
++
++	vpmuludq	32*7-128($ap), $B2, $TEMP0
++	vpaddq		$TEMP0, $ACC5, $ACC5
++	vpmuludq	32*7-128($aap), $B2, $ACC6
++	vpaddq		32*15-448($tp1), $ACC6, $ACC6
++
++	vpmuludq	32*8-128($ap), $ACC0, $ACC7
++	vmovdqu		$ACC5, 32*14-448($tp1)
++	vpaddq		32*16-448($tp1), $ACC7, $ACC7
++	vmovdqu		$ACC6, 32*15-448($tp1)
++	vmovdqu		$ACC7, 32*16-448($tp1)
++	lea		8($tp1), $tp1
++
++	dec	$i        
++	jnz	.LOOP_SQR_1024
++___
++$ZERO = $ACC9;
++$TEMP0 = $B1;
++$TEMP2 = $B2;
++$TEMP3 = $Y1;
++$TEMP4 = $Y2;
++$code.=<<___;
++	# we need to fix indices 32-39 to avoid overflow
++	vmovdqu		32*8(%rsp), $ACC8		# 32*8-192($tp0),
++	vmovdqu		32*9(%rsp), $ACC1		# 32*9-192($tp0)
++	vmovdqu		32*10(%rsp), $ACC2		# 32*10-192($tp0)
++	lea		192(%rsp), $tp0			# 64+128=192
++
++	vpsrlq		\$29, $ACC8, $TEMP1
++	vpand		$AND_MASK, $ACC8, $ACC8
++	vpsrlq		\$29, $ACC1, $TEMP2
++	vpand		$AND_MASK, $ACC1, $ACC1
++
++	vpermq		\$0x93, $TEMP1, $TEMP1
++	vpxor		$ZERO, $ZERO, $ZERO
++	vpermq		\$0x93, $TEMP2, $TEMP2
++
++	vpblendd	\$3, $ZERO, $TEMP1, $TEMP0
++	vpblendd	\$3, $TEMP1, $TEMP2, $TEMP1
++	vpaddq		$TEMP0, $ACC8, $ACC8
++	vpblendd	\$3, $TEMP2, $ZERO, $TEMP2
++	vpaddq		$TEMP1, $ACC1, $ACC1
++	vpaddq		$TEMP2, $ACC2, $ACC2
++	vmovdqu		$ACC1, 32*9-192($tp0)
++	vmovdqu		$ACC2, 32*10-192($tp0)
++
++	mov	(%rsp), %rax
++	mov	8(%rsp), $r1
++	mov	16(%rsp), $r2
++	mov	24(%rsp), $r3
++	vmovdqu	32*1(%rsp), $ACC1
++	vmovdqu	32*2-192($tp0), $ACC2
++	vmovdqu	32*3-192($tp0), $ACC3
++	vmovdqu	32*4-192($tp0), $ACC4
++	vmovdqu	32*5-192($tp0), $ACC5
++	vmovdqu	32*6-192($tp0), $ACC6
++	vmovdqu	32*7-192($tp0), $ACC7
++
++	mov	%rax, $r0
++	imull	$n0, %eax
++	and	\$0x1fffffff, %eax
++	vmovd	%eax, $Y1
++
++	mov	%rax, %rdx
++	imulq	-128($np), %rax
++	 vpbroadcastq	$Y1, $Y1
++	add	%rax, $r0
++	mov	%rdx, %rax
++	imulq	8-128($np), %rax
++	shr	\$29, $r0
++	add	%rax, $r1
++	mov	%rdx, %rax
++	imulq	16-128($np), %rax
++	add	$r0, $r1
++	add	%rax, $r2
++	imulq	24-128($np), %rdx
++	add	%rdx, $r3
++
++	mov	$r1, %rax
++	imull	$n0, %eax
++	and	\$0x1fffffff, %eax
++
++	mov \$9, $i
++	jmp .LOOP_REDUCE_1024
++
++.align	32
++.LOOP_REDUCE_1024:
++	vmovd	%eax, $Y2
++	vpbroadcastq	$Y2, $Y2
++
++	vpmuludq	32*1-128($np), $Y1, $TEMP0
++	 mov	%rax, %rdx
++	 imulq	-128($np), %rax
++	vpaddq		$TEMP0, $ACC1, $ACC1
++	 add	%rax, $r1
++	vpmuludq	32*2-128($np), $Y1, $TEMP1
++	 mov	%rdx, %rax
++	 imulq	8-128($np), %rax
++	vpaddq		$TEMP1, $ACC2, $ACC2
++	vpmuludq	32*3-128($np), $Y1, $TEMP2
++	 .byte	0x67
++	 add	%rax, $r2
++	 .byte	0x67
++	 mov	%rdx, %rax
++	 imulq	16-128($np), %rax
++	 shr	\$29, $r1
++	vpaddq		$TEMP2, $ACC3, $ACC3
++	vpmuludq	32*4-128($np), $Y1, $TEMP0
++	 add	%rax, $r3
++	 add	$r1, $r2
++	vpaddq		$TEMP0, $ACC4, $ACC4
++	vpmuludq	32*5-128($np), $Y1, $TEMP1
++	 mov	$r2, %rax
++	 imull	$n0, %eax
++	vpaddq		$TEMP1, $ACC5, $ACC5
++	vpmuludq	32*6-128($np), $Y1, $TEMP2
++	 and	\$0x1fffffff, %eax
++	vpaddq		$TEMP2, $ACC6, $ACC6
++	vpmuludq	32*7-128($np), $Y1, $TEMP0
++	vpaddq		$TEMP0, $ACC7, $ACC7
++	vpmuludq	32*8-128($np), $Y1, $TEMP1
++	 vmovd	%eax, $Y1
++	 #vmovdqu	32*1-8-128($np), $TEMP2		# moved below
++	vpaddq		$TEMP1, $ACC8, $ACC8
++	 #vmovdqu	32*2-8-128($np), $TEMP0		# moved below
++	 vpbroadcastq	$Y1, $Y1
++
++	vpmuludq	32*1-8-128($np), $Y2, $TEMP2	# see above
++	vmovdqu		32*3-8-128($np), $TEMP1
++	 mov	%rax, %rdx
++	 imulq	-128($np), %rax
++	vpaddq		$TEMP2, $ACC1, $ACC1
++	vpmuludq	32*2-8-128($np), $Y2, $TEMP0	# see above
++	vmovdqu		32*4-8-128($np), $TEMP2
++	 add	%rax, $r2
++	 mov	%rdx, %rax
++	 imulq	8-128($np), %rax
++	vpaddq		$TEMP0, $ACC2, $ACC2
++	 add	$r3, %rax
++	 shr	\$29, $r2
++	vpmuludq	$Y2, $TEMP1, $TEMP1
++	vmovdqu		32*5-8-128($np), $TEMP0
++	 add	$r2, %rax
++	vpaddq		$TEMP1, $ACC3, $ACC3
++	vpmuludq	$Y2, $TEMP2, $TEMP2
++	vmovdqu		32*6-8-128($np), $TEMP1
++	 .byte	0x67
++	 mov	%rax, $r3
++	 imull	$n0, %eax
++	vpaddq		$TEMP2, $ACC4, $ACC4
++	vpmuludq	$Y2, $TEMP0, $TEMP0
++	.byte	0xc4,0x41,0x7e,0x6f,0x9d,0x58,0x00,0x00,0x00	# vmovdqu		32*7-8-128($np), $TEMP2
++	 and	\$0x1fffffff, %eax
++	vpaddq		$TEMP0, $ACC5, $ACC5
++	vpmuludq	$Y2, $TEMP1, $TEMP1
++	vmovdqu		32*8-8-128($np), $TEMP0
++	vpaddq		$TEMP1, $ACC6, $ACC6
++	vpmuludq	$Y2, $TEMP2, $TEMP2
++	vmovdqu		32*9-8-128($np), $ACC9
++	 vmovd	%eax, $ACC0			# borrow ACC0 for Y2
++	 imulq	-128($np), %rax
++	vpaddq		$TEMP2, $ACC7, $ACC7
++	vpmuludq	$Y2, $TEMP0, $TEMP0
++	 vmovdqu	32*1-16-128($np), $TEMP1
++	 vpbroadcastq	$ACC0, $ACC0
++	vpaddq		$TEMP0, $ACC8, $ACC8
++	vpmuludq	$Y2, $ACC9, $ACC9
++	 vmovdqu	32*2-16-128($np), $TEMP2
++	 add	%rax, $r3
++
++___
++($ACC0,$Y2)=($Y2,$ACC0);
++$code.=<<___;
++	 vmovdqu	32*1-24-128($np), $ACC0
++	vpmuludq	$Y1, $TEMP1, $TEMP1
++	vmovdqu		32*3-16-128($np), $TEMP0
++	vpaddq		$TEMP1, $ACC1, $ACC1
++	 vpmuludq	$Y2, $ACC0, $ACC0
++	vpmuludq	$Y1, $TEMP2, $TEMP2
++	.byte	0xc4,0x41,0x7e,0x6f,0xb5,0xf0,0xff,0xff,0xff	# vmovdqu		32*4-16-128($np), $TEMP1
++	 vpaddq		$ACC1, $ACC0, $ACC0
++	vpaddq		$TEMP2, $ACC2, $ACC2
++	vpmuludq	$Y1, $TEMP0, $TEMP0
++	vmovdqu		32*5-16-128($np), $TEMP2
++	 .byte	0x67
++	 vmovq		$ACC0, %rax
++	 vmovdqu	$ACC0, (%rsp)		# transfer $r0-$r3
++	vpaddq		$TEMP0, $ACC3, $ACC3
++	vpmuludq	$Y1, $TEMP1, $TEMP1
++	vmovdqu		32*6-16-128($np), $TEMP0
++	vpaddq		$TEMP1, $ACC4, $ACC4
++	vpmuludq	$Y1, $TEMP2, $TEMP2
++	vmovdqu		32*7-16-128($np), $TEMP1
++	vpaddq		$TEMP2, $ACC5, $ACC5
++	vpmuludq	$Y1, $TEMP0, $TEMP0
++	vmovdqu		32*8-16-128($np), $TEMP2
++	vpaddq		$TEMP0, $ACC6, $ACC6
++	vpmuludq	$Y1, $TEMP1, $TEMP1
++	 shr	\$29, $r3
++	vmovdqu		32*9-16-128($np), $TEMP0
++	 add	$r3, %rax
++	vpaddq		$TEMP1, $ACC7, $ACC7
++	vpmuludq	$Y1, $TEMP2, $TEMP2
++	 #vmovdqu	32*2-24-128($np), $TEMP1	# moved below
++	 mov	%rax, $r0
++	 imull	$n0, %eax
++	vpaddq		$TEMP2, $ACC8, $ACC8
++	vpmuludq	$Y1, $TEMP0, $TEMP0
++	 and	\$0x1fffffff, %eax
++	 vmovd	%eax, $Y1
++	 vmovdqu	32*3-24-128($np), $TEMP2
++	.byte	0x67
++	vpaddq		$TEMP0, $ACC9, $ACC9
++	 vpbroadcastq	$Y1, $Y1
++
++	vpmuludq	32*2-24-128($np), $Y2, $TEMP1	# see above
++	vmovdqu		32*4-24-128($np), $TEMP0
++	 mov	%rax, %rdx
++	 imulq	-128($np), %rax
++	 mov	8(%rsp), $r1
++	vpaddq		$TEMP1, $ACC2, $ACC1
++	vpmuludq	$Y2, $TEMP2, $TEMP2
++	vmovdqu		32*5-24-128($np), $TEMP1
++	 add	%rax, $r0
++	 mov	%rdx, %rax
++	 imulq	8-128($np), %rax
++	 .byte	0x67
++	 shr	\$29, $r0
++	 mov	16(%rsp), $r2
++	vpaddq		$TEMP2, $ACC3, $ACC2
++	vpmuludq	$Y2, $TEMP0, $TEMP0
++	vmovdqu		32*6-24-128($np), $TEMP2
++	 add	%rax, $r1
++	 mov	%rdx, %rax
++	 imulq	16-128($np), %rax
++	vpaddq		$TEMP0, $ACC4, $ACC3
++	vpmuludq	$Y2, $TEMP1, $TEMP1
++	vmovdqu		32*7-24-128($np), $TEMP0
++	 imulq	24-128($np), %rdx		# future $r3
++	 add	%rax, $r2
++	 lea	($r0,$r1), %rax
++	vpaddq		$TEMP1, $ACC5, $ACC4
++	vpmuludq	$Y2, $TEMP2, $TEMP2
++	vmovdqu		32*8-24-128($np), $TEMP1
++	 mov	%rax, $r1
++	 imull	$n0, %eax
++	vpmuludq	$Y2, $TEMP0, $TEMP0
++	vpaddq		$TEMP2, $ACC6, $ACC5
++	vmovdqu		32*9-24-128($np), $TEMP2
++	 and	\$0x1fffffff, %eax
++	vpaddq		$TEMP0, $ACC7, $ACC6
++	vpmuludq	$Y2, $TEMP1, $TEMP1
++	 add	24(%rsp), %rdx
++	vpaddq		$TEMP1, $ACC8, $ACC7
++	vpmuludq	$Y2, $TEMP2, $TEMP2
++	vpaddq		$TEMP2, $ACC9, $ACC8
++	 vmovq	$r3, $ACC9
++	 mov	%rdx, $r3
++
++	dec	$i
++	jnz	.LOOP_REDUCE_1024
++___
++($ACC0,$Y2)=($Y2,$ACC0);
++$code.=<<___;
++	lea	448(%rsp), $tp1			# size optimization
++	vpaddq	$ACC9, $Y2, $ACC0
++	vpxor	$ZERO, $ZERO, $ZERO
++
++	vpaddq		32*9-192($tp0), $ACC0, $ACC0
++	vpaddq		32*10-448($tp1), $ACC1, $ACC1
++	vpaddq		32*11-448($tp1), $ACC2, $ACC2
++	vpaddq		32*12-448($tp1), $ACC3, $ACC3
++	vpaddq		32*13-448($tp1), $ACC4, $ACC4
++	vpaddq		32*14-448($tp1), $ACC5, $ACC5
++	vpaddq		32*15-448($tp1), $ACC6, $ACC6
++	vpaddq		32*16-448($tp1), $ACC7, $ACC7
++	vpaddq		32*17-448($tp1), $ACC8, $ACC8
++
++	vpsrlq		\$29, $ACC0, $TEMP1
++	vpand		$AND_MASK, $ACC0, $ACC0
++	vpsrlq		\$29, $ACC1, $TEMP2
++	vpand		$AND_MASK, $ACC1, $ACC1
++	vpsrlq		\$29, $ACC2, $TEMP3
++	vpermq		\$0x93, $TEMP1, $TEMP1
++	vpand		$AND_MASK, $ACC2, $ACC2
++	vpsrlq		\$29, $ACC3, $TEMP4
++	vpermq		\$0x93, $TEMP2, $TEMP2
++	vpand		$AND_MASK, $ACC3, $ACC3
++	vpermq		\$0x93, $TEMP3, $TEMP3
++
++	vpblendd	\$3, $ZERO, $TEMP1, $TEMP0
++	vpermq		\$0x93, $TEMP4, $TEMP4
++	vpblendd	\$3, $TEMP1, $TEMP2, $TEMP1
++	vpaddq		$TEMP0, $ACC0, $ACC0
++	vpblendd	\$3, $TEMP2, $TEMP3, $TEMP2
++	vpaddq		$TEMP1, $ACC1, $ACC1
++	vpblendd	\$3, $TEMP3, $TEMP4, $TEMP3
++	vpaddq		$TEMP2, $ACC2, $ACC2
++	vpblendd	\$3, $TEMP4, $ZERO, $TEMP4
++	vpaddq		$TEMP3, $ACC3, $ACC3
++	vpaddq		$TEMP4, $ACC4, $ACC4
++
++	vpsrlq		\$29, $ACC0, $TEMP1
++	vpand		$AND_MASK, $ACC0, $ACC0
++	vpsrlq		\$29, $ACC1, $TEMP2
++	vpand		$AND_MASK, $ACC1, $ACC1
++	vpsrlq		\$29, $ACC2, $TEMP3
++	vpermq		\$0x93, $TEMP1, $TEMP1
++	vpand		$AND_MASK, $ACC2, $ACC2
++	vpsrlq		\$29, $ACC3, $TEMP4
++	vpermq		\$0x93, $TEMP2, $TEMP2
++	vpand		$AND_MASK, $ACC3, $ACC3
++	vpermq		\$0x93, $TEMP3, $TEMP3
++
++	vpblendd	\$3, $ZERO, $TEMP1, $TEMP0
++	vpermq		\$0x93, $TEMP4, $TEMP4
++	vpblendd	\$3, $TEMP1, $TEMP2, $TEMP1
++	vpaddq		$TEMP0, $ACC0, $ACC0
++	vpblendd	\$3, $TEMP2, $TEMP3, $TEMP2
++	vpaddq		$TEMP1, $ACC1, $ACC1
++	vmovdqu		$ACC0, 32*0-128($rp)
++	vpblendd	\$3, $TEMP3, $TEMP4, $TEMP3
++	vpaddq		$TEMP2, $ACC2, $ACC2
++	vmovdqu		$ACC1, 32*1-128($rp)
++	vpblendd	\$3, $TEMP4, $ZERO, $TEMP4
++	vpaddq		$TEMP3, $ACC3, $ACC3
++	vmovdqu		$ACC2, 32*2-128($rp)
++	vpaddq		$TEMP4, $ACC4, $ACC4
++	vmovdqu		$ACC3, 32*3-128($rp)
++___
++$TEMP5=$ACC0;
++$code.=<<___;
++	vpsrlq		\$29, $ACC4, $TEMP1
++	vpand		$AND_MASK, $ACC4, $ACC4
++	vpsrlq		\$29, $ACC5, $TEMP2
++	vpand		$AND_MASK, $ACC5, $ACC5
++	vpsrlq		\$29, $ACC6, $TEMP3
++	vpermq		\$0x93, $TEMP1, $TEMP1
++	vpand		$AND_MASK, $ACC6, $ACC6
++	vpsrlq		\$29, $ACC7, $TEMP4
++	vpermq		\$0x93, $TEMP2, $TEMP2
++	vpand		$AND_MASK, $ACC7, $ACC7
++	vpsrlq		\$29, $ACC8, $TEMP5
++	vpermq		\$0x93, $TEMP3, $TEMP3
++	vpand		$AND_MASK, $ACC8, $ACC8
++	vpermq		\$0x93, $TEMP4, $TEMP4
++
++	vpblendd	\$3, $ZERO, $TEMP1, $TEMP0
++	vpermq		\$0x93, $TEMP5, $TEMP5
++	vpblendd	\$3, $TEMP1, $TEMP2, $TEMP1
++	vpaddq		$TEMP0, $ACC4, $ACC4
++	vpblendd	\$3, $TEMP2, $TEMP3, $TEMP2
++	vpaddq		$TEMP1, $ACC5, $ACC5
++	vpblendd	\$3, $TEMP3, $TEMP4, $TEMP3
++	vpaddq		$TEMP2, $ACC6, $ACC6
++	vpblendd	\$3, $TEMP4, $TEMP5, $TEMP4
++	vpaddq		$TEMP3, $ACC7, $ACC7
++	vpaddq		$TEMP4, $ACC8, $ACC8
++     
++	vpsrlq		\$29, $ACC4, $TEMP1
++	vpand		$AND_MASK, $ACC4, $ACC4
++	vpsrlq		\$29, $ACC5, $TEMP2
++	vpand		$AND_MASK, $ACC5, $ACC5
++	vpsrlq		\$29, $ACC6, $TEMP3
++	vpermq		\$0x93, $TEMP1, $TEMP1
++	vpand		$AND_MASK, $ACC6, $ACC6
++	vpsrlq		\$29, $ACC7, $TEMP4
++	vpermq		\$0x93, $TEMP2, $TEMP2
++	vpand		$AND_MASK, $ACC7, $ACC7
++	vpsrlq		\$29, $ACC8, $TEMP5
++	vpermq		\$0x93, $TEMP3, $TEMP3
++	vpand		$AND_MASK, $ACC8, $ACC8
++	vpermq		\$0x93, $TEMP4, $TEMP4
++
++	vpblendd	\$3, $ZERO, $TEMP1, $TEMP0
++	vpermq		\$0x93, $TEMP5, $TEMP5
++	vpblendd	\$3, $TEMP1, $TEMP2, $TEMP1
++	vpaddq		$TEMP0, $ACC4, $ACC4
++	vpblendd	\$3, $TEMP2, $TEMP3, $TEMP2
++	vpaddq		$TEMP1, $ACC5, $ACC5
++	vmovdqu		$ACC4, 32*4-128($rp)
++	vpblendd	\$3, $TEMP3, $TEMP4, $TEMP3
++	vpaddq		$TEMP2, $ACC6, $ACC6
++	vmovdqu		$ACC5, 32*5-128($rp)
++	vpblendd	\$3, $TEMP4, $TEMP5, $TEMP4
++	vpaddq		$TEMP3, $ACC7, $ACC7
++	vmovdqu		$ACC6, 32*6-128($rp)
++	vpaddq		$TEMP4, $ACC8, $ACC8
++	vmovdqu		$ACC7, 32*7-128($rp)
++	vmovdqu		$ACC8, 32*8-128($rp)
++
++	mov	$rp, $ap
++	dec	$rep
++	jne	.LOOP_GRANDE_SQR_1024
++
++	vzeroall
++	mov	%rbp, %rax
++___
++$code.=<<___ if ($win64);
++	movaps	-0xd8(%rax),%xmm6
++	movaps	-0xc8(%rax),%xmm7
++	movaps	-0xb8(%rax),%xmm8
++	movaps	-0xa8(%rax),%xmm9
++	movaps	-0x98(%rax),%xmm10
++	movaps	-0x88(%rax),%xmm11
++	movaps	-0x78(%rax),%xmm12
++	movaps	-0x68(%rax),%xmm13
++	movaps	-0x58(%rax),%xmm14
++	movaps	-0x48(%rax),%xmm15
++___
++$code.=<<___;
++	mov	-48(%rax),%r15
++	mov	-40(%rax),%r14
++	mov	-32(%rax),%r13
++	mov	-24(%rax),%r12
++	mov	-16(%rax),%rbp
++	mov	-8(%rax),%rbx
++	lea	(%rax),%rsp		# restore %rsp
++.Lsqr_1024_epilogue:
++	ret
++.size	rsaz_1024_sqr_avx2,.-rsaz_1024_sqr_avx2
++___
++}
++
++{ # void AMM_WW(
++my $rp="%rdi";	# BN_ULONG *rp,
++my $ap="%rsi";	# const BN_ULONG *ap,
++my $bp="%rdx";	# const BN_ULONG *bp,
++my $np="%rcx";	# const BN_ULONG *np,
++my $n0="%r8d";	# unsigned int n0);
++
++# The registers that hold the accumulated redundant result
++# The AMM works on 1024 bit operands, and redundant word size is 29
++# Therefore: ceil(1024/29)/4 = 9
++my $ACC0="%ymm0";
++my $ACC1="%ymm1";
++my $ACC2="%ymm2";
++my $ACC3="%ymm3";
++my $ACC4="%ymm4";
++my $ACC5="%ymm5";
++my $ACC6="%ymm6";
++my $ACC7="%ymm7";
++my $ACC8="%ymm8";
++my $ACC9="%ymm9";
++
++# Registers that hold the broadcasted words of multiplier, currently used
++my $Bi="%ymm10";
++my $Yi="%ymm11";
++
++# Helper registers
++my $TEMP0=$ACC0;
++my $TEMP1="%ymm12";
++my $TEMP2="%ymm13";
++my $ZERO="%ymm14";
++my $AND_MASK="%ymm15";
++
++# alu registers that hold the first words of the ACC
++my $r0="%r9";
++my $r1="%r10";
++my $r2="%r11";
++my $r3="%r12";
++
++my $i="%r14d";
++my $tmp="%r15";
++
++$bp="%r13";	# reassigned argument
++
++$code.=<<___;
++.globl	rsaz_1024_mul_avx2
++.type	rsaz_1024_mul_avx2,\@function,5
++.align	64
++rsaz_1024_mul_avx2:
++	lea	(%rsp), %rax
++	push	%rbx
++	push	%rbp
++	push	%r12
++	push	%r13
++	push	%r14
++	push	%r15
++___
++$code.=<<___ if ($win64);
++	vzeroupper
++	lea	-0xa8(%rsp),%rsp
++	vmovaps	%xmm6,-0xd8(%rax)
++	vmovaps	%xmm7,-0xc8(%rax)
++	vmovaps	%xmm8,-0xb8(%rax)
++	vmovaps	%xmm9,-0xa8(%rax)
++	vmovaps	%xmm10,-0x98(%rax)
++	vmovaps	%xmm11,-0x88(%rax)
++	vmovaps	%xmm12,-0x78(%rax)
++	vmovaps	%xmm13,-0x68(%rax)
++	vmovaps	%xmm14,-0x58(%rax)
++	vmovaps	%xmm15,-0x48(%rax)
++.Lmul_1024_body:
++___
++$code.=<<___;
++	mov	%rax,%rbp
++	vzeroall
++	mov	%rdx, $bp	# reassigned argument
++	sub	\$64,%rsp
++
++	# unaligned 256-bit load that crosses page boundary can
++	# cause severe performance degradation here, so if $ap does
++	# cross page boundary, swap it with $bp [meaning that caller
++	# is advised to lay down $ap and $bp next to each other, so
++	# that only one can cross page boundary].
++	.byte	0x67,0x67
++	mov	$ap, $tmp
++	and	\$4095, $tmp
++	add	\$32*10, $tmp
++	shr	\$12, $tmp
++	mov	$ap, $tmp
++	cmovnz	$bp, $ap
++	cmovnz	$tmp, $bp
++
++	mov	$np, $tmp
++	sub	\$-128,$ap	# size optimization
++	sub	\$-128,$np
++	sub	\$-128,$rp
++
++	and	\$4095, $tmp	# see if $np crosses page
++	add	\$32*10, $tmp
++	.byte	0x67,0x67
++	shr	\$12, $tmp
++	jz	.Lmul_1024_no_n_copy
++
++	# unaligned 256-bit load that crosses page boundary can
++	# cause severe performance degradation here, so if $np does
++	# cross page boundary, copy it to stack and make sure stack
++	# frame doesn't...
++	sub		\$32*10,%rsp
++	vmovdqu		32*0-128($np), $ACC0
++	and		\$-512, %rsp
++	vmovdqu		32*1-128($np), $ACC1
++	vmovdqu		32*2-128($np), $ACC2
++	vmovdqu		32*3-128($np), $ACC3
++	vmovdqu		32*4-128($np), $ACC4
++	vmovdqu		32*5-128($np), $ACC5
++	vmovdqu		32*6-128($np), $ACC6
++	vmovdqu		32*7-128($np), $ACC7
++	vmovdqu		32*8-128($np), $ACC8
++	lea		64+128(%rsp),$np
++	vmovdqu		$ACC0, 32*0-128($np)
++	vpxor		$ACC0, $ACC0, $ACC0
++	vmovdqu		$ACC1, 32*1-128($np)
++	vpxor		$ACC1, $ACC1, $ACC1
++	vmovdqu		$ACC2, 32*2-128($np)
++	vpxor		$ACC2, $ACC2, $ACC2
++	vmovdqu		$ACC3, 32*3-128($np)
++	vpxor		$ACC3, $ACC3, $ACC3
++	vmovdqu		$ACC4, 32*4-128($np)
++	vpxor		$ACC4, $ACC4, $ACC4
++	vmovdqu		$ACC5, 32*5-128($np)
++	vpxor		$ACC5, $ACC5, $ACC5
++	vmovdqu		$ACC6, 32*6-128($np)
++	vpxor		$ACC6, $ACC6, $ACC6
++	vmovdqu		$ACC7, 32*7-128($np)
++	vpxor		$ACC7, $ACC7, $ACC7
++	vmovdqu		$ACC8, 32*8-128($np)
++	vmovdqa		$ACC0, $ACC8
++	vmovdqu		$ACC9, 32*9-128($np)	# $ACC9 is zero after vzeroall
++.Lmul_1024_no_n_copy:
++	and	\$-64,%rsp
++
++	mov	($bp), %rbx
++	vpbroadcastq ($bp), $Bi
++	vmovdqu	$ACC0, (%rsp)			# clear top of stack
++	xor	$r0, $r0
++	.byte	0x67
++	xor	$r1, $r1
++	xor	$r2, $r2
++	xor	$r3, $r3
++
++	vmovdqu	.Land_mask(%rip), $AND_MASK
++	mov	\$9, $i
++	vmovdqu	$ACC9, 32*9-128($rp)		# $ACC9 is zero after vzeroall
++	jmp	.Loop_mul_1024
++
++.align	32
++.Loop_mul_1024:
++	 vpsrlq		\$29, $ACC3, $ACC9		# correct $ACC3(*)
++	mov	%rbx, %rax
++	imulq	-128($ap), %rax
++	add	$r0, %rax
++	mov	%rbx, $r1
++	imulq	8-128($ap), $r1
++	add	8(%rsp), $r1
++
++	mov	%rax, $r0
++	imull	$n0, %eax
++	and	\$0x1fffffff, %eax
++
++	 mov	%rbx, $r2
++	 imulq	16-128($ap), $r2
++	 add	16(%rsp), $r2
++
++	 mov	%rbx, $r3
++	 imulq	24-128($ap), $r3
++	 add	24(%rsp), $r3
++	vpmuludq	32*1-128($ap),$Bi,$TEMP0
++	 vmovd		%eax, $Yi
++	vpaddq		$TEMP0,$ACC1,$ACC1
++	vpmuludq	32*2-128($ap),$Bi,$TEMP1
++	 vpbroadcastq	$Yi, $Yi
++	vpaddq		$TEMP1,$ACC2,$ACC2
++	vpmuludq	32*3-128($ap),$Bi,$TEMP2
++	 vpand		$AND_MASK, $ACC3, $ACC3		# correct $ACC3
++	vpaddq		$TEMP2,$ACC3,$ACC3
++	vpmuludq	32*4-128($ap),$Bi,$TEMP0
++	vpaddq		$TEMP0,$ACC4,$ACC4
++	vpmuludq	32*5-128($ap),$Bi,$TEMP1
++	vpaddq		$TEMP1,$ACC5,$ACC5
++	vpmuludq	32*6-128($ap),$Bi,$TEMP2
++	vpaddq		$TEMP2,$ACC6,$ACC6
++	vpmuludq	32*7-128($ap),$Bi,$TEMP0
++	 vpermq		\$0x93, $ACC9, $ACC9		# correct $ACC3
++	vpaddq		$TEMP0,$ACC7,$ACC7
++	vpmuludq	32*8-128($ap),$Bi,$TEMP1
++	 vpbroadcastq	8($bp), $Bi
++	vpaddq		$TEMP1,$ACC8,$ACC8
++
++	mov	%rax,%rdx
++	imulq	-128($np),%rax
++	add	%rax,$r0
++	mov	%rdx,%rax
++	imulq	8-128($np),%rax
++	add	%rax,$r1
++	mov	%rdx,%rax
++	imulq	16-128($np),%rax
++	add	%rax,$r2
++	shr	\$29, $r0
++	imulq	24-128($np),%rdx
++	add	%rdx,$r3
++	add	$r0, $r1
++
++	vpmuludq	32*1-128($np),$Yi,$TEMP2
++	 vmovq		$Bi, %rbx
++	vpaddq		$TEMP2,$ACC1,$ACC1
++	vpmuludq	32*2-128($np),$Yi,$TEMP0
++	vpaddq		$TEMP0,$ACC2,$ACC2
++	vpmuludq	32*3-128($np),$Yi,$TEMP1
++	vpaddq		$TEMP1,$ACC3,$ACC3
++	vpmuludq	32*4-128($np),$Yi,$TEMP2
++	vpaddq		$TEMP2,$ACC4,$ACC4
++	vpmuludq	32*5-128($np),$Yi,$TEMP0
++	vpaddq		$TEMP0,$ACC5,$ACC5
++	vpmuludq	32*6-128($np),$Yi,$TEMP1
++	vpaddq		$TEMP1,$ACC6,$ACC6
++	vpmuludq	32*7-128($np),$Yi,$TEMP2
++	 vpblendd	\$3, $ZERO, $ACC9, $ACC9	# correct $ACC3
++	vpaddq		$TEMP2,$ACC7,$ACC7
++	vpmuludq	32*8-128($np),$Yi,$TEMP0
++	 vpaddq		$ACC9, $ACC3, $ACC3		# correct $ACC3
++	vpaddq		$TEMP0,$ACC8,$ACC8
++
++	mov	%rbx, %rax
++	imulq	-128($ap),%rax
++	add	%rax,$r1
++	 vmovdqu	-8+32*1-128($ap),$TEMP1
++	mov	%rbx, %rax
++	imulq	8-128($ap),%rax
++	add	%rax,$r2
++	 vmovdqu	-8+32*2-128($ap),$TEMP2
++
++	mov	$r1, %rax
++	imull	$n0, %eax
++	and	\$0x1fffffff, %eax
++
++	 imulq	16-128($ap),%rbx
++	 add	%rbx,$r3
++	vpmuludq	$Bi,$TEMP1,$TEMP1
++	 vmovd		%eax, $Yi
++	vmovdqu		-8+32*3-128($ap),$TEMP0
++	vpaddq		$TEMP1,$ACC1,$ACC1
++	vpmuludq	$Bi,$TEMP2,$TEMP2
++	 vpbroadcastq	$Yi, $Yi
++	vmovdqu		-8+32*4-128($ap),$TEMP1
++	vpaddq		$TEMP2,$ACC2,$ACC2
++	vpmuludq	$Bi,$TEMP0,$TEMP0
++	vmovdqu		-8+32*5-128($ap),$TEMP2
++	vpaddq		$TEMP0,$ACC3,$ACC3
++	vpmuludq	$Bi,$TEMP1,$TEMP1
++	vmovdqu		-8+32*6-128($ap),$TEMP0
++	vpaddq		$TEMP1,$ACC4,$ACC4
++	vpmuludq	$Bi,$TEMP2,$TEMP2
++	vmovdqu		-8+32*7-128($ap),$TEMP1
++	vpaddq		$TEMP2,$ACC5,$ACC5
++	vpmuludq	$Bi,$TEMP0,$TEMP0
++	vmovdqu		-8+32*8-128($ap),$TEMP2
++	vpaddq		$TEMP0,$ACC6,$ACC6
++	vpmuludq	$Bi,$TEMP1,$TEMP1
++	vmovdqu		-8+32*9-128($ap),$ACC9
++	vpaddq		$TEMP1,$ACC7,$ACC7
++	vpmuludq	$Bi,$TEMP2,$TEMP2
++	vpaddq		$TEMP2,$ACC8,$ACC8
++	vpmuludq	$Bi,$ACC9,$ACC9
++	 vpbroadcastq	16($bp), $Bi
++
++	mov	%rax,%rdx
++	imulq	-128($np),%rax
++	add	%rax,$r1
++	 vmovdqu	-8+32*1-128($np),$TEMP0
++	mov	%rdx,%rax
++	imulq	8-128($np),%rax
++	add	%rax,$r2
++	 vmovdqu	-8+32*2-128($np),$TEMP1
++	shr	\$29, $r1
++	imulq	16-128($np),%rdx
++	add	%rdx,$r3
++	add	$r1, $r2
++
++	vpmuludq	$Yi,$TEMP0,$TEMP0
++	 vmovq		$Bi, %rbx
++	vmovdqu		-8+32*3-128($np),$TEMP2
++	vpaddq		$TEMP0,$ACC1,$ACC1
++	vpmuludq	$Yi,$TEMP1,$TEMP1
++	vmovdqu		-8+32*4-128($np),$TEMP0
++	vpaddq		$TEMP1,$ACC2,$ACC2
++	vpmuludq	$Yi,$TEMP2,$TEMP2
++	vmovdqu		-8+32*5-128($np),$TEMP1
++	vpaddq		$TEMP2,$ACC3,$ACC3
++	vpmuludq	$Yi,$TEMP0,$TEMP0
++	vmovdqu		-8+32*6-128($np),$TEMP2
++	vpaddq		$TEMP0,$ACC4,$ACC4
++	vpmuludq	$Yi,$TEMP1,$TEMP1
++	vmovdqu		-8+32*7-128($np),$TEMP0
++	vpaddq		$TEMP1,$ACC5,$ACC5
++	vpmuludq	$Yi,$TEMP2,$TEMP2
++	vmovdqu		-8+32*8-128($np),$TEMP1
++	vpaddq		$TEMP2,$ACC6,$ACC6
++	vpmuludq	$Yi,$TEMP0,$TEMP0
++	vmovdqu		-8+32*9-128($np),$TEMP2
++	vpaddq		$TEMP0,$ACC7,$ACC7
++	vpmuludq	$Yi,$TEMP1,$TEMP1
++	vpaddq		$TEMP1,$ACC8,$ACC8
++	vpmuludq	$Yi,$TEMP2,$TEMP2
++	vpaddq		$TEMP2,$ACC9,$ACC9
++
++	 vmovdqu	-16+32*1-128($ap),$TEMP0
++	mov	%rbx,%rax
++	imulq	-128($ap),%rax
++	add	$r2,%rax
++
++	 vmovdqu	-16+32*2-128($ap),$TEMP1
++	mov	%rax,$r2
++	imull	$n0, %eax
++	and	\$0x1fffffff, %eax
++
++	 imulq	8-128($ap),%rbx
++	 add	%rbx,$r3
++	vpmuludq	$Bi,$TEMP0,$TEMP0
++	 vmovd		%eax, $Yi
++	vmovdqu		-16+32*3-128($ap),$TEMP2
++	vpaddq		$TEMP0,$ACC1,$ACC1
++	vpmuludq	$Bi,$TEMP1,$TEMP1
++	 vpbroadcastq	$Yi, $Yi
++	vmovdqu		-16+32*4-128($ap),$TEMP0
++	vpaddq		$TEMP1,$ACC2,$ACC2
++	vpmuludq	$Bi,$TEMP2,$TEMP2
++	vmovdqu		-16+32*5-128($ap),$TEMP1
++	vpaddq		$TEMP2,$ACC3,$ACC3
++	vpmuludq	$Bi,$TEMP0,$TEMP0
++	vmovdqu		-16+32*6-128($ap),$TEMP2
++	vpaddq		$TEMP0,$ACC4,$ACC4
++	vpmuludq	$Bi,$TEMP1,$TEMP1
++	vmovdqu		-16+32*7-128($ap),$TEMP0
++	vpaddq		$TEMP1,$ACC5,$ACC5
++	vpmuludq	$Bi,$TEMP2,$TEMP2
++	vmovdqu		-16+32*8-128($ap),$TEMP1
++	vpaddq		$TEMP2,$ACC6,$ACC6
++	vpmuludq	$Bi,$TEMP0,$TEMP0
++	vmovdqu		-16+32*9-128($ap),$TEMP2
++	vpaddq		$TEMP0,$ACC7,$ACC7
++	vpmuludq	$Bi,$TEMP1,$TEMP1
++	vpaddq		$TEMP1,$ACC8,$ACC8
++	vpmuludq	$Bi,$TEMP2,$TEMP2
++	 vpbroadcastq	24($bp), $Bi
++	vpaddq		$TEMP2,$ACC9,$ACC9
++
++	 vmovdqu	-16+32*1-128($np),$TEMP0
++	mov	%rax,%rdx
++	imulq	-128($np),%rax
++	add	%rax,$r2
++	 vmovdqu	-16+32*2-128($np),$TEMP1
++	imulq	8-128($np),%rdx
++	add	%rdx,$r3
++	shr	\$29, $r2
++
++	vpmuludq	$Yi,$TEMP0,$TEMP0
++	 vmovq		$Bi, %rbx
++	vmovdqu		-16+32*3-128($np),$TEMP2
++	vpaddq		$TEMP0,$ACC1,$ACC1
++	vpmuludq	$Yi,$TEMP1,$TEMP1
++	vmovdqu		-16+32*4-128($np),$TEMP0
++	vpaddq		$TEMP1,$ACC2,$ACC2
++	vpmuludq	$Yi,$TEMP2,$TEMP2
++	vmovdqu		-16+32*5-128($np),$TEMP1
++	vpaddq		$TEMP2,$ACC3,$ACC3
++	vpmuludq	$Yi,$TEMP0,$TEMP0
++	vmovdqu		-16+32*6-128($np),$TEMP2
++	vpaddq		$TEMP0,$ACC4,$ACC4
++	vpmuludq	$Yi,$TEMP1,$TEMP1
++	vmovdqu		-16+32*7-128($np),$TEMP0
++	vpaddq		$TEMP1,$ACC5,$ACC5
++	vpmuludq	$Yi,$TEMP2,$TEMP2
++	vmovdqu		-16+32*8-128($np),$TEMP1
++	vpaddq		$TEMP2,$ACC6,$ACC6
++	vpmuludq	$Yi,$TEMP0,$TEMP0
++	vmovdqu		-16+32*9-128($np),$TEMP2
++	vpaddq		$TEMP0,$ACC7,$ACC7
++	vpmuludq	$Yi,$TEMP1,$TEMP1
++	 vmovdqu	-24+32*1-128($ap),$TEMP0
++	vpaddq		$TEMP1,$ACC8,$ACC8
++	vpmuludq	$Yi,$TEMP2,$TEMP2
++	 vmovdqu	-24+32*2-128($ap),$TEMP1
++	vpaddq		$TEMP2,$ACC9,$ACC9
++
++	add	$r2, $r3
++	imulq	-128($ap),%rbx
++	add	%rbx,$r3
++
++	mov	$r3, %rax
++	imull	$n0, %eax
++	and	\$0x1fffffff, %eax
++
++	vpmuludq	$Bi,$TEMP0,$TEMP0
++	 vmovd		%eax, $Yi
++	vmovdqu		-24+32*3-128($ap),$TEMP2
++	vpaddq		$TEMP0,$ACC1,$ACC1
++	vpmuludq	$Bi,$TEMP1,$TEMP1
++	 vpbroadcastq	$Yi, $Yi
++	vmovdqu		-24+32*4-128($ap),$TEMP0
++	vpaddq		$TEMP1,$ACC2,$ACC2
++	vpmuludq	$Bi,$TEMP2,$TEMP2
++	vmovdqu		-24+32*5-128($ap),$TEMP1
++	vpaddq		$TEMP2,$ACC3,$ACC3
++	vpmuludq	$Bi,$TEMP0,$TEMP0
++	vmovdqu		-24+32*6-128($ap),$TEMP2
++	vpaddq		$TEMP0,$ACC4,$ACC4
++	vpmuludq	$Bi,$TEMP1,$TEMP1
++	vmovdqu		-24+32*7-128($ap),$TEMP0
++	vpaddq		$TEMP1,$ACC5,$ACC5
++	vpmuludq	$Bi,$TEMP2,$TEMP2
++	vmovdqu		-24+32*8-128($ap),$TEMP1
++	vpaddq		$TEMP2,$ACC6,$ACC6
++	vpmuludq	$Bi,$TEMP0,$TEMP0
++	vmovdqu		-24+32*9-128($ap),$TEMP2
++	vpaddq		$TEMP0,$ACC7,$ACC7
++	vpmuludq	$Bi,$TEMP1,$TEMP1
++	vpaddq		$TEMP1,$ACC8,$ACC8
++	vpmuludq	$Bi,$TEMP2,$TEMP2
++	 vpbroadcastq	32($bp), $Bi
++	vpaddq		$TEMP2,$ACC9,$ACC9
++	 add		\$32, $bp			# $bp++
++
++	vmovdqu		-24+32*1-128($np),$TEMP0
++	imulq	-128($np),%rax
++	add	%rax,$r3
++	shr	\$29, $r3
++
++	vmovdqu		-24+32*2-128($np),$TEMP1
++	vpmuludq	$Yi,$TEMP0,$TEMP0
++	 vmovq		$Bi, %rbx
++	vmovdqu		-24+32*3-128($np),$TEMP2
++	vpaddq		$TEMP0,$ACC1,$ACC0		# $ACC0==$TEMP0
++	vpmuludq	$Yi,$TEMP1,$TEMP1
++	 vmovdqu	$ACC0, (%rsp)			# transfer $r0-$r3
++	vpaddq		$TEMP1,$ACC2,$ACC1
++	vmovdqu		-24+32*4-128($np),$TEMP0
++	vpmuludq	$Yi,$TEMP2,$TEMP2
++	vmovdqu		-24+32*5-128($np),$TEMP1
++	vpaddq		$TEMP2,$ACC3,$ACC2
++	vpmuludq	$Yi,$TEMP0,$TEMP0
++	vmovdqu		-24+32*6-128($np),$TEMP2
++	vpaddq		$TEMP0,$ACC4,$ACC3
++	vpmuludq	$Yi,$TEMP1,$TEMP1
++	vmovdqu		-24+32*7-128($np),$TEMP0
++	vpaddq		$TEMP1,$ACC5,$ACC4
++	vpmuludq	$Yi,$TEMP2,$TEMP2
++	vmovdqu		-24+32*8-128($np),$TEMP1
++	vpaddq		$TEMP2,$ACC6,$ACC5
++	vpmuludq	$Yi,$TEMP0,$TEMP0
++	vmovdqu		-24+32*9-128($np),$TEMP2
++	 mov	$r3, $r0
++	vpaddq		$TEMP0,$ACC7,$ACC6
++	vpmuludq	$Yi,$TEMP1,$TEMP1
++	 add	(%rsp), $r0
++	vpaddq		$TEMP1,$ACC8,$ACC7
++	vpmuludq	$Yi,$TEMP2,$TEMP2
++	 vmovq	$r3, $TEMP1
++	vpaddq		$TEMP2,$ACC9,$ACC8
++
++	dec	$i
++	jnz	.Loop_mul_1024
++___
++
++# (*)	Original implementation was correcting ACC1-ACC3 for overflow
++#	after 7 loop runs, or after 28 iterations, or 56 additions.
++#	But as we underutilize resources, it's possible to correct in
++#	each iteration with marginal performance loss. But then, as
++#	we do it in each iteration, we can correct less digits, and
++#	avoid performance penalties completely. Also note that we
++#	correct only three digits out of four. This works because
++#	most significant digit is subjected to less additions.
++
++$TEMP0 = $ACC9;
++$TEMP3 = $Bi;
++$TEMP4 = $Yi;
++$code.=<<___;
++	vpermq		\$0, $AND_MASK, $AND_MASK
++	vpaddq		(%rsp), $TEMP1, $ACC0
++
++	vpsrlq		\$29, $ACC0, $TEMP1
++	vpand		$AND_MASK, $ACC0, $ACC0
++	vpsrlq		\$29, $ACC1, $TEMP2
++	vpand		$AND_MASK, $ACC1, $ACC1
++	vpsrlq		\$29, $ACC2, $TEMP3
++	vpermq		\$0x93, $TEMP1, $TEMP1
++	vpand		$AND_MASK, $ACC2, $ACC2
++	vpsrlq		\$29, $ACC3, $TEMP4
++	vpermq		\$0x93, $TEMP2, $TEMP2
++	vpand		$AND_MASK, $ACC3, $ACC3
++
++	vpblendd	\$3, $ZERO, $TEMP1, $TEMP0
++	vpermq		\$0x93, $TEMP3, $TEMP3
++	vpblendd	\$3, $TEMP1, $TEMP2, $TEMP1
++	vpermq		\$0x93, $TEMP4, $TEMP4
++	vpaddq		$TEMP0, $ACC0, $ACC0
++	vpblendd	\$3, $TEMP2, $TEMP3, $TEMP2
++	vpaddq		$TEMP1, $ACC1, $ACC1
++	vpblendd	\$3, $TEMP3, $TEMP4, $TEMP3
++	vpaddq		$TEMP2, $ACC2, $ACC2
++	vpblendd	\$3, $TEMP4, $ZERO, $TEMP4
++	vpaddq		$TEMP3, $ACC3, $ACC3
++	vpaddq		$TEMP4, $ACC4, $ACC4
++
++	vpsrlq		\$29, $ACC0, $TEMP1
++	vpand		$AND_MASK, $ACC0, $ACC0
++	vpsrlq		\$29, $ACC1, $TEMP2
++	vpand		$AND_MASK, $ACC1, $ACC1
++	vpsrlq		\$29, $ACC2, $TEMP3
++	vpermq		\$0x93, $TEMP1, $TEMP1
++	vpand		$AND_MASK, $ACC2, $ACC2
++	vpsrlq		\$29, $ACC3, $TEMP4
++	vpermq		\$0x93, $TEMP2, $TEMP2
++	vpand		$AND_MASK, $ACC3, $ACC3
++	vpermq		\$0x93, $TEMP3, $TEMP3
++
++	vpblendd	\$3, $ZERO, $TEMP1, $TEMP0
++	vpermq		\$0x93, $TEMP4, $TEMP4
++	vpblendd	\$3, $TEMP1, $TEMP2, $TEMP1
++	vpaddq		$TEMP0, $ACC0, $ACC0
++	vpblendd	\$3, $TEMP2, $TEMP3, $TEMP2
++	vpaddq		$TEMP1, $ACC1, $ACC1
++	vpblendd	\$3, $TEMP3, $TEMP4, $TEMP3
++	vpaddq		$TEMP2, $ACC2, $ACC2
++	vpblendd	\$3, $TEMP4, $ZERO, $TEMP4
++	vpaddq		$TEMP3, $ACC3, $ACC3
++	vpaddq		$TEMP4, $ACC4, $ACC4
++
++	vmovdqu		$ACC0, 0-128($rp)
++	vmovdqu		$ACC1, 32-128($rp)
++	vmovdqu		$ACC2, 64-128($rp)
++	vmovdqu		$ACC3, 96-128($rp)
++___
++
++$TEMP5=$ACC0;
++$code.=<<___;
++	vpsrlq		\$29, $ACC4, $TEMP1
++	vpand		$AND_MASK, $ACC4, $ACC4
++	vpsrlq		\$29, $ACC5, $TEMP2
++	vpand		$AND_MASK, $ACC5, $ACC5
++	vpsrlq		\$29, $ACC6, $TEMP3
++	vpermq		\$0x93, $TEMP1, $TEMP1
++	vpand		$AND_MASK, $ACC6, $ACC6
++	vpsrlq		\$29, $ACC7, $TEMP4
++	vpermq		\$0x93, $TEMP2, $TEMP2
++	vpand		$AND_MASK, $ACC7, $ACC7
++	vpsrlq		\$29, $ACC8, $TEMP5
++	vpermq		\$0x93, $TEMP3, $TEMP3
++	vpand		$AND_MASK, $ACC8, $ACC8
++	vpermq		\$0x93, $TEMP4, $TEMP4
++
++	vpblendd	\$3, $ZERO, $TEMP1, $TEMP0
++	vpermq		\$0x93, $TEMP5, $TEMP5
++	vpblendd	\$3, $TEMP1, $TEMP2, $TEMP1
++	vpaddq		$TEMP0, $ACC4, $ACC4
++	vpblendd	\$3, $TEMP2, $TEMP3, $TEMP2
++	vpaddq		$TEMP1, $ACC5, $ACC5
++	vpblendd	\$3, $TEMP3, $TEMP4, $TEMP3
++	vpaddq		$TEMP2, $ACC6, $ACC6
++	vpblendd	\$3, $TEMP4, $TEMP5, $TEMP4
++	vpaddq		$TEMP3, $ACC7, $ACC7
++	vpaddq		$TEMP4, $ACC8, $ACC8
++
++	vpsrlq		\$29, $ACC4, $TEMP1
++	vpand		$AND_MASK, $ACC4, $ACC4
++	vpsrlq		\$29, $ACC5, $TEMP2
++	vpand		$AND_MASK, $ACC5, $ACC5
++	vpsrlq		\$29, $ACC6, $TEMP3
++	vpermq		\$0x93, $TEMP1, $TEMP1
++	vpand		$AND_MASK, $ACC6, $ACC6
++	vpsrlq		\$29, $ACC7, $TEMP4
++	vpermq		\$0x93, $TEMP2, $TEMP2
++	vpand		$AND_MASK, $ACC7, $ACC7
++	vpsrlq		\$29, $ACC8, $TEMP5
++	vpermq		\$0x93, $TEMP3, $TEMP3
++	vpand		$AND_MASK, $ACC8, $ACC8
++	vpermq		\$0x93, $TEMP4, $TEMP4
++
++	vpblendd	\$3, $ZERO, $TEMP1, $TEMP0
++	vpermq		\$0x93, $TEMP5, $TEMP5
++	vpblendd	\$3, $TEMP1, $TEMP2, $TEMP1
++	vpaddq		$TEMP0, $ACC4, $ACC4
++	vpblendd	\$3, $TEMP2, $TEMP3, $TEMP2
++	vpaddq		$TEMP1, $ACC5, $ACC5
++	vpblendd	\$3, $TEMP3, $TEMP4, $TEMP3
++	vpaddq		$TEMP2, $ACC6, $ACC6
++	vpblendd	\$3, $TEMP4, $TEMP5, $TEMP4
++	vpaddq		$TEMP3, $ACC7, $ACC7
++	vpaddq		$TEMP4, $ACC8, $ACC8
++
++	vmovdqu		$ACC4, 128-128($rp)
++	vmovdqu		$ACC5, 160-128($rp)    
++	vmovdqu		$ACC6, 192-128($rp)
++	vmovdqu		$ACC7, 224-128($rp)
++	vmovdqu		$ACC8, 256-128($rp)
++	vzeroupper
++
++	mov	%rbp, %rax
++___
++$code.=<<___ if ($win64);
++	movaps	-0xd8(%rax),%xmm6
++	movaps	-0xc8(%rax),%xmm7
++	movaps	-0xb8(%rax),%xmm8
++	movaps	-0xa8(%rax),%xmm9
++	movaps	-0x98(%rax),%xmm10
++	movaps	-0x88(%rax),%xmm11
++	movaps	-0x78(%rax),%xmm12
++	movaps	-0x68(%rax),%xmm13
++	movaps	-0x58(%rax),%xmm14
++	movaps	-0x48(%rax),%xmm15
++___
++$code.=<<___;
++	mov	-48(%rax),%r15
++	mov	-40(%rax),%r14
++	mov	-32(%rax),%r13
++	mov	-24(%rax),%r12
++	mov	-16(%rax),%rbp
++	mov	-8(%rax),%rbx
++	lea	(%rax),%rsp		# restore %rsp
++.Lmul_1024_epilogue:
++	ret
++.size	rsaz_1024_mul_avx2,.-rsaz_1024_mul_avx2
++___
++}
++{
++my ($out,$inp) = $win64 ? ("%rcx","%rdx") : ("%rdi","%rsi");
++my @T = map("%r$_",(8..11));
++
++$code.=<<___;
++.globl	rsaz_1024_red2norm_avx2
++.type	rsaz_1024_red2norm_avx2,\@abi-omnipotent
++.align	32
++rsaz_1024_red2norm_avx2:
++	sub	\$-128,$inp	# size optimization
++	xor	%rax,%rax
++___
++
++for ($j=0,$i=0; $i<16; $i++) {
++    my $k=0;
++    while (29*$j<64*($i+1)) {	# load data till boundary
++	$code.="	mov	`8*$j-128`($inp), @T[0]\n";
++	$j++; $k++; push(@T,shift(@T));
++    }
++    $l=$k;
++    while ($k>1) {		# shift loaded data but last value
++	$code.="	shl	\$`29*($j-$k)`,@T[-$k]\n";
++	$k--;
++    }
++    $code.=<<___;		# shift last value
++	mov	@T[-1], @T[0]
++	shl	\$`29*($j-1)`, @T[-1]
++	shr	\$`-29*($j-1)`, @T[0]
++___
++    while ($l) {		# accumulate all values
++	$code.="	add	@T[-$l], %rax\n";
++	$l--;
++    }
++	$code.=<<___;
++	adc	\$0, @T[0]	# consume eventual carry
++	mov	%rax, 8*$i($out)
++	mov	@T[0], %rax
++___
++    push(@T,shift(@T));
++}
++$code.=<<___;
++	ret
++.size	rsaz_1024_red2norm_avx2,.-rsaz_1024_red2norm_avx2
++
++.globl	rsaz_1024_norm2red_avx2
++.type	rsaz_1024_norm2red_avx2,\@abi-omnipotent
++.align	32
++rsaz_1024_norm2red_avx2:
++	sub	\$-128,$out	# size optimization
++	mov	($inp),@T[0]
++	mov	\$0x1fffffff,%eax
++___
++for ($j=0,$i=0; $i<16; $i++) {
++    $code.="	mov	`8*($i+1)`($inp),@T[1]\n"	if ($i<15);
++    $code.="	xor	@T[1],@T[1]\n"			if ($i==15);
++    my $k=1;
++    while (29*($j+1)<64*($i+1)) {
++    	$code.=<<___;
++	mov	@T[0],@T[-$k]
++	shr	\$`29*$j`,@T[-$k]
++	and	%rax,@T[-$k]				# &0x1fffffff
++	mov	@T[-$k],`8*$j-128`($out)
++___
++	$j++; $k++;
++    }
++    $code.=<<___;
++	shrd	\$`29*$j`,@T[1],@T[0]
++	and	%rax,@T[0]
++	mov	@T[0],`8*$j-128`($out)
++___
++    $j++;
++    push(@T,shift(@T));
++}
++$code.=<<___;
++	mov	@T[0],`8*$j-128`($out)			# zero
++	mov	@T[0],`8*($j+1)-128`($out)
++	mov	@T[0],`8*($j+2)-128`($out)
++	mov	@T[0],`8*($j+3)-128`($out)
++	ret
++.size	rsaz_1024_norm2red_avx2,.-rsaz_1024_norm2red_avx2
++___
++}
++{
++my ($out,$inp,$power) = $win64 ? ("%rcx","%rdx","%r8d") : ("%rdi","%rsi","%edx");
++
++$code.=<<___;
++.globl	rsaz_1024_scatter5_avx2
++.type	rsaz_1024_scatter5_avx2,\@abi-omnipotent
++.align	32
++rsaz_1024_scatter5_avx2:
++	vzeroupper
++	vmovdqu	.Lscatter_permd(%rip),%ymm5
++	shl	\$4,$power
++	lea	($out,$power),$out
++	mov	\$9,%eax
++	jmp	.Loop_scatter_1024
++
++.align	32
++.Loop_scatter_1024:
++	vmovdqu		($inp),%ymm0
++	lea		32($inp),$inp
++	vpermd		%ymm0,%ymm5,%ymm0
++	vmovdqu		%xmm0,($out)
++	lea		16*32($out),$out
++	dec	%eax
++	jnz	.Loop_scatter_1024
++
++	vzeroupper
++	ret
++.size	rsaz_1024_scatter5_avx2,.-rsaz_1024_scatter5_avx2
++
++.globl	rsaz_1024_gather5_avx2
++.type	rsaz_1024_gather5_avx2,\@abi-omnipotent
++.align	32
++rsaz_1024_gather5_avx2:
++	vzeroupper
++	mov	%rsp,%r11
++___
++$code.=<<___ if ($win64);
++	lea	-0x88(%rsp),%rax
++.LSEH_begin_rsaz_1024_gather5:
++	# I can't trust assembler to use specific encoding:-(
++	.byte	0x48,0x8d,0x60,0xe0		# lea	-0x20(%rax),%rsp
++	.byte	0xc5,0xf8,0x29,0x70,0xe0	# vmovaps %xmm6,-0x20(%rax)
++	.byte	0xc5,0xf8,0x29,0x78,0xf0	# vmovaps %xmm7,-0x10(%rax)
++	.byte	0xc5,0x78,0x29,0x40,0x00	# vmovaps %xmm8,0(%rax)
++	.byte	0xc5,0x78,0x29,0x48,0x10	# vmovaps %xmm9,0x10(%rax)
++	.byte	0xc5,0x78,0x29,0x50,0x20	# vmovaps %xmm10,0x20(%rax)
++	.byte	0xc5,0x78,0x29,0x58,0x30	# vmovaps %xmm11,0x30(%rax)
++	.byte	0xc5,0x78,0x29,0x60,0x40	# vmovaps %xmm12,0x40(%rax)
++	.byte	0xc5,0x78,0x29,0x68,0x50	# vmovaps %xmm13,0x50(%rax)
++	.byte	0xc5,0x78,0x29,0x70,0x60	# vmovaps %xmm14,0x60(%rax)
++	.byte	0xc5,0x78,0x29,0x78,0x70	# vmovaps %xmm15,0x70(%rax)
++___
++$code.=<<___;
++	lea	-0x100(%rsp),%rsp
++	and	\$-32, %rsp
++	lea	.Linc(%rip), %r10
++	lea	-128(%rsp),%rax			# control u-op density
++
++	vmovd		$power, %xmm4
++	vmovdqa		(%r10),%ymm0
++	vmovdqa		32(%r10),%ymm1
++	vmovdqa		64(%r10),%ymm5
++	vpbroadcastd	%xmm4,%ymm4
++
++	vpaddd		%ymm5, %ymm0, %ymm2
++	vpcmpeqd	%ymm4, %ymm0, %ymm0
++	vpaddd		%ymm5, %ymm1, %ymm3
++	vpcmpeqd	%ymm4, %ymm1, %ymm1
++	vmovdqa		%ymm0, 32*0+128(%rax)
++	vpaddd		%ymm5, %ymm2, %ymm0
++	vpcmpeqd	%ymm4, %ymm2, %ymm2
++	vmovdqa		%ymm1, 32*1+128(%rax)
++	vpaddd		%ymm5, %ymm3, %ymm1
++	vpcmpeqd	%ymm4, %ymm3, %ymm3
++	vmovdqa		%ymm2, 32*2+128(%rax)
++	vpaddd		%ymm5, %ymm0, %ymm2
++	vpcmpeqd	%ymm4, %ymm0, %ymm0
++	vmovdqa		%ymm3, 32*3+128(%rax)
++	vpaddd		%ymm5, %ymm1, %ymm3
++	vpcmpeqd	%ymm4, %ymm1, %ymm1
++	vmovdqa		%ymm0, 32*4+128(%rax)
++	vpaddd		%ymm5, %ymm2, %ymm8
++	vpcmpeqd	%ymm4, %ymm2, %ymm2
++	vmovdqa		%ymm1, 32*5+128(%rax)
++	vpaddd		%ymm5, %ymm3, %ymm9
++	vpcmpeqd	%ymm4, %ymm3, %ymm3
++	vmovdqa		%ymm2, 32*6+128(%rax)
++	vpaddd		%ymm5, %ymm8, %ymm10
++	vpcmpeqd	%ymm4, %ymm8, %ymm8
++	vmovdqa		%ymm3, 32*7+128(%rax)
++	vpaddd		%ymm5, %ymm9, %ymm11
++	vpcmpeqd	%ymm4, %ymm9, %ymm9
++	vpaddd		%ymm5, %ymm10, %ymm12
++	vpcmpeqd	%ymm4, %ymm10, %ymm10
++	vpaddd		%ymm5, %ymm11, %ymm13
++	vpcmpeqd	%ymm4, %ymm11, %ymm11
++	vpaddd		%ymm5, %ymm12, %ymm14
++	vpcmpeqd	%ymm4, %ymm12, %ymm12
++	vpaddd		%ymm5, %ymm13, %ymm15
++	vpcmpeqd	%ymm4, %ymm13, %ymm13
++	vpcmpeqd	%ymm4, %ymm14, %ymm14
++	vpcmpeqd	%ymm4, %ymm15, %ymm15
++
++	vmovdqa	-32(%r10),%ymm7			# .Lgather_permd
++	lea	128($inp), $inp
++	mov	\$9,$power
++
++.Loop_gather_1024:
++	vmovdqa		32*0-128($inp),	%ymm0
++	vmovdqa		32*1-128($inp),	%ymm1
++	vmovdqa		32*2-128($inp),	%ymm2
++	vmovdqa		32*3-128($inp),	%ymm3
++	vpand		32*0+128(%rax),	%ymm0,	%ymm0
++	vpand		32*1+128(%rax),	%ymm1,	%ymm1
++	vpand		32*2+128(%rax),	%ymm2,	%ymm2
++	vpor		%ymm0, %ymm1, %ymm4
++	vpand		32*3+128(%rax),	%ymm3,	%ymm3
++	vmovdqa		32*4-128($inp),	%ymm0
++	vmovdqa		32*5-128($inp),	%ymm1
++	vpor		%ymm2, %ymm3, %ymm5
++	vmovdqa		32*6-128($inp),	%ymm2
++	vmovdqa		32*7-128($inp),	%ymm3
++	vpand		32*4+128(%rax),	%ymm0,	%ymm0
++	vpand		32*5+128(%rax),	%ymm1,	%ymm1
++	vpand		32*6+128(%rax),	%ymm2,	%ymm2
++	vpor		%ymm0, %ymm4, %ymm4
++	vpand		32*7+128(%rax),	%ymm3,	%ymm3
++	vpand		32*8-128($inp),	%ymm8,	%ymm0
++	vpor		%ymm1, %ymm5, %ymm5
++	vpand		32*9-128($inp),	%ymm9,	%ymm1
++	vpor		%ymm2, %ymm4, %ymm4
++	vpand		32*10-128($inp),%ymm10,	%ymm2
++	vpor		%ymm3, %ymm5, %ymm5
++	vpand		32*11-128($inp),%ymm11,	%ymm3
++	vpor		%ymm0, %ymm4, %ymm4
++	vpand		32*12-128($inp),%ymm12,	%ymm0
++	vpor		%ymm1, %ymm5, %ymm5
++	vpand		32*13-128($inp),%ymm13,	%ymm1
++	vpor		%ymm2, %ymm4, %ymm4
++	vpand		32*14-128($inp),%ymm14,	%ymm2
++	vpor		%ymm3, %ymm5, %ymm5
++	vpand		32*15-128($inp),%ymm15,	%ymm3
++	lea		32*16($inp), $inp
++	vpor		%ymm0, %ymm4, %ymm4
++	vpor		%ymm1, %ymm5, %ymm5
++	vpor		%ymm2, %ymm4, %ymm4
++	vpor		%ymm3, %ymm5, %ymm5
++
++	vpor		%ymm5, %ymm4, %ymm4
++	vextracti128	\$1, %ymm4, %xmm5	# upper half is cleared
++	vpor		%xmm4, %xmm5, %xmm5
++	vpermd		%ymm5,%ymm7,%ymm5
++	vmovdqu		%ymm5,($out)
++	lea		32($out),$out
++	dec	$power
++	jnz	.Loop_gather_1024
++
++	vpxor	%ymm0,%ymm0,%ymm0
++	vmovdqu	%ymm0,($out)
++	vzeroupper
++___
++$code.=<<___ if ($win64);
++	movaps	-0xa8(%r11),%xmm6
++	movaps	-0x98(%r11),%xmm7
++	movaps	-0x88(%r11),%xmm8
++	movaps	-0x78(%r11),%xmm9
++	movaps	-0x68(%r11),%xmm10
++	movaps	-0x58(%r11),%xmm11
++	movaps	-0x48(%r11),%xmm12
++	movaps	-0x38(%r11),%xmm13
++	movaps	-0x28(%r11),%xmm14
++	movaps	-0x18(%r11),%xmm15
++.LSEH_end_rsaz_1024_gather5:
++___
++$code.=<<___;
++	lea	(%r11),%rsp
++	ret
++.size	rsaz_1024_gather5_avx2,.-rsaz_1024_gather5_avx2
++___
++}
++
++$code.=<<___;
++.extern	OPENSSL_ia32cap_P
++.globl	rsaz_avx2_eligible
++.type	rsaz_avx2_eligible,\@abi-omnipotent
++.align	32
++rsaz_avx2_eligible:
++	mov	OPENSSL_ia32cap_P+8(%rip),%eax
++___
++$code.=<<___	if ($addx);
++	mov	\$`1<<8|1<<19`,%ecx
++	mov	\$0,%edx
++	and	%eax,%ecx
++	cmp	\$`1<<8|1<<19`,%ecx	# check for BMI2+AD*X
++	cmove	%edx,%eax
++___
++$code.=<<___;
++	and	\$`1<<5`,%eax
++	shr	\$5,%eax
++	ret
++.size	rsaz_avx2_eligible,.-rsaz_avx2_eligible
++
++.align	64
++.Land_mask:
++	.quad	0x1fffffff,0x1fffffff,0x1fffffff,-1
++.Lscatter_permd:
++	.long	0,2,4,6,7,7,7,7
++.Lgather_permd:
++	.long	0,7,1,7,2,7,3,7
++.Linc:
++	.long	0,0,0,0, 1,1,1,1
++	.long	2,2,2,2, 3,3,3,3
++	.long	4,4,4,4, 4,4,4,4
++.align	64
++___
++
++if ($win64) {
++$rec="%rcx";
++$frame="%rdx";
++$context="%r8";
++$disp="%r9";
++
++$code.=<<___
++.extern	__imp_RtlVirtualUnwind
++.type	rsaz_se_handler,\@abi-omnipotent
++.align	16
++rsaz_se_handler:
++	push	%rsi
++	push	%rdi
++	push	%rbx
++	push	%rbp
++	push	%r12
++	push	%r13
++	push	%r14
++	push	%r15
++	pushfq
++	sub	\$64,%rsp
++
++	mov	120($context),%rax	# pull context->Rax
++	mov	248($context),%rbx	# pull context->Rip
++
++	mov	8($disp),%rsi		# disp->ImageBase
++	mov	56($disp),%r11		# disp->HandlerData
++
++	mov	0(%r11),%r10d		# HandlerData[0]
++	lea	(%rsi,%r10),%r10	# prologue label
++	cmp	%r10,%rbx		# context->RipRsp
++
++	mov	4(%r11),%r10d		# HandlerData[1]
++	lea	(%rsi,%r10),%r10	# epilogue label
++	cmp	%r10,%rbx		# context->Rip>=epilogue label
++	jae	.Lcommon_seh_tail
++
++	mov	160($context),%rax	# pull context->Rbp
++
++	mov	-48(%rax),%r15
++	mov	-40(%rax),%r14
++	mov	-32(%rax),%r13
++	mov	-24(%rax),%r12
++	mov	-16(%rax),%rbp
++	mov	-8(%rax),%rbx
++	mov	%r15,240($context)
++	mov	%r14,232($context)
++	mov	%r13,224($context)
++	mov	%r12,216($context)
++	mov	%rbp,160($context)
++	mov	%rbx,144($context)
++
++	lea	-0xd8(%rax),%rsi	# %xmm save area
++	lea	512($context),%rdi	# & context.Xmm6
++	mov	\$20,%ecx		# 10*sizeof(%xmm0)/sizeof(%rax)
++	.long	0xa548f3fc		# cld; rep movsq
++
++.Lcommon_seh_tail:
++	mov	8(%rax),%rdi
++	mov	16(%rax),%rsi
++	mov	%rax,152($context)	# restore context->Rsp
++	mov	%rsi,168($context)	# restore context->Rsi
++	mov	%rdi,176($context)	# restore context->Rdi
++
++	mov	40($disp),%rdi		# disp->ContextRecord
++	mov	$context,%rsi		# context
++	mov	\$154,%ecx		# sizeof(CONTEXT)
++	.long	0xa548f3fc		# cld; rep movsq
++
++	mov	$disp,%rsi
++	xor	%rcx,%rcx		# arg1, UNW_FLAG_NHANDLER
++	mov	8(%rsi),%rdx		# arg2, disp->ImageBase
++	mov	0(%rsi),%r8		# arg3, disp->ControlPc
++	mov	16(%rsi),%r9		# arg4, disp->FunctionEntry
++	mov	40(%rsi),%r10		# disp->ContextRecord
++	lea	56(%rsi),%r11		# &disp->HandlerData
++	lea	24(%rsi),%r12		# &disp->EstablisherFrame
++	mov	%r10,32(%rsp)		# arg5
++	mov	%r11,40(%rsp)		# arg6
++	mov	%r12,48(%rsp)		# arg7
++	mov	%rcx,56(%rsp)		# arg8, (NULL)
++	call	*__imp_RtlVirtualUnwind(%rip)
++
++	mov	\$1,%eax		# ExceptionContinueSearch
++	add	\$64,%rsp
++	popfq
++	pop	%r15
++	pop	%r14
++	pop	%r13
++	pop	%r12
++	pop	%rbp
++	pop	%rbx
++	pop	%rdi
++	pop	%rsi
++	ret
++.size	rsaz_se_handler,.-rsaz_se_handler
++
++.section	.pdata
++.align	4
++	.rva	.LSEH_begin_rsaz_1024_sqr_avx2
++	.rva	.LSEH_end_rsaz_1024_sqr_avx2
++	.rva	.LSEH_info_rsaz_1024_sqr_avx2
++
++	.rva	.LSEH_begin_rsaz_1024_mul_avx2
++	.rva	.LSEH_end_rsaz_1024_mul_avx2
++	.rva	.LSEH_info_rsaz_1024_mul_avx2
++
++	.rva	.LSEH_begin_rsaz_1024_gather5
++	.rva	.LSEH_end_rsaz_1024_gather5
++	.rva	.LSEH_info_rsaz_1024_gather5
++.section	.xdata
++.align	8
++.LSEH_info_rsaz_1024_sqr_avx2:
++	.byte	9,0,0,0
++	.rva	rsaz_se_handler
++	.rva	.Lsqr_1024_body,.Lsqr_1024_epilogue
++.LSEH_info_rsaz_1024_mul_avx2:
++	.byte	9,0,0,0
++	.rva	rsaz_se_handler
++	.rva	.Lmul_1024_body,.Lmul_1024_epilogue
++.LSEH_info_rsaz_1024_gather5:
++	.byte	0x01,0x36,0x17,0x0b
++	.byte	0x36,0xf8,0x09,0x00	# vmovaps 0x90(rsp),xmm15
++	.byte	0x31,0xe8,0x08,0x00	# vmovaps 0x80(rsp),xmm14
++	.byte	0x2c,0xd8,0x07,0x00	# vmovaps 0x70(rsp),xmm13
++	.byte	0x27,0xc8,0x06,0x00	# vmovaps 0x60(rsp),xmm12
++	.byte	0x22,0xb8,0x05,0x00	# vmovaps 0x50(rsp),xmm11
++	.byte	0x1d,0xa8,0x04,0x00	# vmovaps 0x40(rsp),xmm10
++	.byte	0x18,0x98,0x03,0x00	# vmovaps 0x30(rsp),xmm9
++	.byte	0x13,0x88,0x02,0x00	# vmovaps 0x20(rsp),xmm8
++	.byte	0x0e,0x78,0x01,0x00	# vmovaps 0x10(rsp),xmm7
++	.byte	0x09,0x68,0x00,0x00	# vmovaps 0x00(rsp),xmm6
++	.byte	0x04,0x01,0x15,0x00	# sub	  rsp,0xa8
++	.byte	0x00,0xb3,0x00,0x00	# set_frame r11
++___
++}
++
++foreach (split("\n",$code)) {
++	s/\`([^\`]*)\`/eval($1)/ge;
++
++	s/\b(sh[rl]d?\s+\$)(-?[0-9]+)/$1.$2%64/ge		or
++
++	s/\b(vmov[dq])\b(.+)%ymm([0-9]+)/$1$2%xmm$3/go		or
++	s/\b(vmovdqu)\b(.+)%x%ymm([0-9]+)/$1$2%xmm$3/go		or
++	s/\b(vpinsr[qd])\b(.+)%ymm([0-9]+)/$1$2%xmm$3/go	or
++	s/\b(vpextr[qd])\b(.+)%ymm([0-9]+)/$1$2%xmm$3/go	or
++	s/\b(vpbroadcast[qd]\s+)%ymm([0-9]+)/$1%xmm$2/go;
++	print $_,"\n";
++}
++
++}}} else {{{
++print <<___;	# assembler is too old
++.text
++
++.globl	rsaz_avx2_eligible
++.type	rsaz_avx2_eligible,\@abi-omnipotent
++rsaz_avx2_eligible:
++	xor	%eax,%eax
++	ret
++.size	rsaz_avx2_eligible,.-rsaz_avx2_eligible
++
++.globl	rsaz_1024_sqr_avx2
++.globl	rsaz_1024_mul_avx2
++.globl	rsaz_1024_norm2red_avx2
++.globl	rsaz_1024_red2norm_avx2
++.globl	rsaz_1024_scatter5_avx2
++.globl	rsaz_1024_gather5_avx2
++.type	rsaz_1024_sqr_avx2,\@abi-omnipotent
++rsaz_1024_sqr_avx2:
++rsaz_1024_mul_avx2:
++rsaz_1024_norm2red_avx2:
++rsaz_1024_red2norm_avx2:
++rsaz_1024_scatter5_avx2:
++rsaz_1024_gather5_avx2:
++	.byte	0x0f,0x0b	# ud2
++	ret
++.size	rsaz_1024_sqr_avx2,.-rsaz_1024_sqr_avx2
++___
++}}}
++
++close STDOUT;
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/bn/asm/rsaz-x86_64.pl b/CryptoPkg/Library/OpensslLib/openssl/crypto/bn/asm/rsaz-x86_64.pl
+new file mode 100755
+index 0000000..6f3b664
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/bn/asm/rsaz-x86_64.pl
+@@ -0,0 +1,2358 @@
++#! /usr/bin/env perl
++# Copyright 2013-2016 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
++# in the file LICENSE in the source distribution or at
++# https://www.openssl.org/source/license.html
++
++
++##############################################################################
++#                                                                            #
++#  Copyright (c) 2012, Intel Corporation                                     #
++#                                                                            #
++#  All rights reserved.                                                      #
++#                                                                            #
++#  Redistribution and use in source and binary forms, with or without        #
++#  modification, are permitted provided that the following conditions are    #
++#  met:                                                                      #
++#                                                                            #
++#  *  Redistributions of source code must retain the above copyright         #
++#     notice, this list of conditions and the following disclaimer.          #
++#                                                                            #
++#  *  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.                                                          #
++#                                                                            #
++#  *  Neither the name of the Intel Corporation nor the names of its         #
++#     contributors may be used to endorse or promote products derived from   #
++#     this software without specific prior written permission.               #
++#                                                                            #
++#                                                                            #
++#  THIS SOFTWARE IS PROVIDED BY INTEL CORPORATION ""AS IS"" AND ANY          #
++#  EXPRESS 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 INTEL CORPORATION OR            #
++#  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.              #
++#                                                                            #
++##############################################################################
++# Developers and authors:                                                    #
++# Shay Gueron (1, 2), and Vlad Krasnov (1)                                   #
++# (1) Intel Architecture Group, Microprocessor and Chipset Development,      #
++#     Israel Development Center, Haifa, Israel                               #
++# (2) University of Haifa                                                    #
++##############################################################################
++# Reference:                                                                 #
++# [1] S. Gueron, "Efficient Software Implementations of Modular              #
++#     Exponentiation", http://eprint.iacr.org/2011/239                       #
++# [2] S. Gueron, V. Krasnov. "Speeding up Big-Numbers Squaring".             #
++#     IEEE Proceedings of 9th International Conference on Information        #
++#     Technology: New Generations (ITNG 2012), 821-823 (2012).               #
++# [3] S. Gueron, Efficient Software Implementations of Modular Exponentiation#
++#     Journal of Cryptographic Engineering 2:31-43 (2012).                   #
++# [4] S. Gueron, V. Krasnov: "[PATCH] Efficient and side channel analysis    #
++#     resistant 512-bit and 1024-bit modular exponentiation for optimizing   #
++#     RSA1024 and RSA2048 on x86_64 platforms",                              #
++#     http://rt.openssl.org/Ticket/Display.html?id=2582&user=guest&pass=guest#
++##############################################################################
++
++# While original submission covers 512- and 1024-bit exponentiation,
++# this module is limited to 512-bit version only (and as such
++# accelerates RSA1024 sign). This is because improvement for longer
++# keys is not high enough to justify the effort, highest measured
++# was ~5% on Westmere. [This is relative to OpenSSL 1.0.2, upcoming
++# for the moment of this writing!] Nor does this module implement
++# "monolithic" complete exponentiation jumbo-subroutine, but adheres
++# to more modular mixture of C and assembly. And it's optimized even
++# for processors other than Intel Core family (see table below for
++# improvement coefficients).
++# 						
++#
++# RSA1024 sign/sec	this/original	|this/rsax(*)	this/fips(*)
++#			----------------+---------------------------
++# Opteron		+13%		|+5%		+20%
++# Bulldozer		-0%		|-1%		+10%
++# P4			+11%		|+7%		+8%
++# Westmere		+5%		|+14%		+17%
++# Sandy Bridge		+2%		|+12%		+29%
++# Ivy Bridge		+1%		|+11%		+35%
++# Haswell(**)		-0%		|+12%		+39%
++# Atom			+13%		|+11%		+4%
++# VIA Nano		+70%		|+9%		+25%
++#
++# (*)	rsax engine and fips numbers are presented for reference
++#	purposes;
++# (**)	MULX was attempted, but found to give only marginal improvement;
++
++$flavour = shift;
++$output  = shift;
++if ($flavour =~ /\./) { $output = $flavour; undef $flavour; }
++
++$win64=0; $win64=1 if ($flavour =~ /[nm]asm|mingw64/ || $output =~ /\.asm$/);
++
++$0 =~ m/(.*[\/\\])[^\/\\]+$/; $dir=$1;
++( $xlate="${dir}x86_64-xlate.pl" and -f $xlate ) or
++( $xlate="${dir}../../perlasm/x86_64-xlate.pl" and -f $xlate) or
++die "can't locate x86_64-xlate.pl";
++
++open OUT,"| \"$^X\" \"$xlate\" $flavour \"$output\"";
++*STDOUT=*OUT;
++
++if (`$ENV{CC} -Wa,-v -c -o /dev/null -x assembler /dev/null 2>&1`
++		=~ /GNU assembler version ([2-9]\.[0-9]+)/) {
++	$addx = ($1>=2.23);
++}
++
++if (!$addx && $win64 && ($flavour =~ /nasm/ || $ENV{ASM} =~ /nasm/) &&
++	    `nasm -v 2>&1` =~ /NASM version ([2-9]\.[0-9]+)/) {
++	$addx = ($1>=2.10);
++}
++
++if (!$addx && $win64 && ($flavour =~ /masm/ || $ENV{ASM} =~ /ml64/) &&
++	    `ml64 2>&1` =~ /Version ([0-9]+)\./) {
++	$addx = ($1>=12);
++}
++
++if (!$addx && `$ENV{CC} -v 2>&1` =~ /((?:^clang|LLVM) version|.*based on LLVM) ([3-9])\.([0-9]+)/) {
++	my $ver = $2 + $3/100.0;	# 3.1->3.01, 3.10->3.10
++	$addx = ($ver>=3.03);
++}
++
++($out, $inp, $mod) = ("%rdi", "%rsi", "%rbp");	# common internal API
++{
++my ($out,$inp,$mod,$n0,$times) = ("%rdi","%rsi","%rdx","%rcx","%r8d");
++
++$code.=<<___;
++.text
++
++.extern	OPENSSL_ia32cap_P
++
++.globl	rsaz_512_sqr
++.type	rsaz_512_sqr,\@function,5
++.align	32
++rsaz_512_sqr:				# 25-29% faster than rsaz_512_mul
++	push	%rbx
++	push	%rbp
++	push	%r12
++	push	%r13
++	push	%r14
++	push	%r15
++
++	subq	\$128+24, %rsp
++.Lsqr_body:
++	movq	$mod, %rbp		# common argument
++	movq	($inp), %rdx
++	movq	8($inp), %rax
++	movq	$n0, 128(%rsp)
++___
++$code.=<<___ if ($addx);
++	movl	\$0x80100,%r11d
++	andl	OPENSSL_ia32cap_P+8(%rip),%r11d
++	cmpl	\$0x80100,%r11d		# check for MULX and ADO/CX
++	je	.Loop_sqrx
++___
++$code.=<<___;
++	jmp	.Loop_sqr
++
++.align	32
++.Loop_sqr:
++	movl	$times,128+8(%rsp)
++#first iteration
++	movq	%rdx, %rbx
++	mulq	%rdx
++	movq	%rax, %r8
++	movq	16($inp), %rax
++	movq	%rdx, %r9
++
++	mulq	%rbx
++	addq	%rax, %r9
++	movq	24($inp), %rax
++	movq	%rdx, %r10
++	adcq	\$0, %r10
++
++	mulq	%rbx
++	addq	%rax, %r10
++	movq	32($inp), %rax
++	movq	%rdx, %r11
++	adcq	\$0, %r11
++
++	mulq	%rbx
++	addq	%rax, %r11
++	movq	40($inp), %rax
++	movq	%rdx, %r12
++	adcq	\$0, %r12
++
++	mulq	%rbx
++	addq	%rax, %r12
++	movq	48($inp), %rax
++	movq	%rdx, %r13
++	adcq	\$0, %r13
++
++	mulq	%rbx
++	addq	%rax, %r13
++	movq	56($inp), %rax
++	movq	%rdx, %r14
++	adcq	\$0, %r14
++
++	mulq	%rbx
++	addq	%rax, %r14
++	movq	%rbx, %rax
++	movq	%rdx, %r15
++	adcq	\$0, %r15
++
++	addq	%r8, %r8		#shlq	\$1, %r8
++	movq	%r9, %rcx
++	adcq	%r9, %r9		#shld	\$1, %r8, %r9
++
++	mulq	%rax
++	movq	%rax, (%rsp)
++	addq	%rdx, %r8
++	adcq	\$0, %r9
++
++	movq	%r8, 8(%rsp)
++	shrq	\$63, %rcx
++
++#second iteration
++	movq	8($inp), %r8
++	movq	16($inp), %rax
++	mulq	%r8
++	addq	%rax, %r10
++	movq	24($inp), %rax
++	movq	%rdx, %rbx
++	adcq	\$0, %rbx
++
++	mulq	%r8
++	addq	%rax, %r11
++	movq	32($inp), %rax
++	adcq	\$0, %rdx
++	addq	%rbx, %r11
++	movq	%rdx, %rbx
++	adcq	\$0, %rbx
++
++	mulq	%r8
++	addq	%rax, %r12
++	movq	40($inp), %rax
++	adcq	\$0, %rdx
++	addq	%rbx, %r12
++	movq	%rdx, %rbx
++	adcq	\$0, %rbx
++
++	mulq	%r8
++	addq	%rax, %r13
++	movq	48($inp), %rax
++	adcq	\$0, %rdx
++	addq	%rbx, %r13
++	movq	%rdx, %rbx
++	adcq	\$0, %rbx
++
++	mulq	%r8
++	addq	%rax, %r14
++	movq	56($inp), %rax
++	adcq	\$0, %rdx
++	addq	%rbx, %r14
++	movq	%rdx, %rbx
++	adcq	\$0, %rbx
++
++	mulq	%r8
++	addq	%rax, %r15
++	movq	%r8, %rax
++	adcq	\$0, %rdx
++	addq	%rbx, %r15
++	movq	%rdx, %r8
++	movq	%r10, %rdx
++	adcq	\$0, %r8
++
++	add	%rdx, %rdx
++	lea	(%rcx,%r10,2), %r10	#shld	\$1, %rcx, %r10
++	movq	%r11, %rbx
++	adcq	%r11, %r11		#shld	\$1, %r10, %r11
++
++	mulq	%rax
++	addq	%rax, %r9
++	adcq	%rdx, %r10
++	adcq	\$0, %r11
++
++	movq	%r9, 16(%rsp)
++	movq	%r10, 24(%rsp)
++	shrq	\$63, %rbx
++	
++#third iteration
++	movq	16($inp), %r9	
++	movq	24($inp), %rax
++	mulq	%r9
++	addq	%rax, %r12
++	movq	32($inp), %rax
++	movq	%rdx, %rcx
++	adcq	\$0, %rcx
++
++	mulq	%r9
++	addq	%rax, %r13
++	movq	40($inp), %rax
++	adcq	\$0, %rdx
++	addq	%rcx, %r13
++	movq	%rdx, %rcx
++	adcq	\$0, %rcx
++
++	mulq	%r9
++	addq	%rax, %r14
++	movq	48($inp), %rax
++	adcq	\$0, %rdx
++	addq	%rcx, %r14
++	movq	%rdx, %rcx
++	adcq	\$0, %rcx
++
++	mulq	%r9
++	 movq	%r12, %r10
++	 lea	(%rbx,%r12,2), %r12	#shld	\$1, %rbx, %r12
++	addq	%rax, %r15
++	movq	56($inp), %rax
++	adcq	\$0, %rdx
++	addq	%rcx, %r15
++	movq	%rdx, %rcx
++	adcq	\$0, %rcx
++
++	mulq	%r9
++	 shrq	\$63, %r10
++	addq	%rax, %r8
++	movq	%r9, %rax
++	adcq	\$0, %rdx
++	addq	%rcx, %r8
++	movq	%rdx, %r9
++	adcq	\$0, %r9
++
++	movq	%r13, %rcx
++	leaq	(%r10,%r13,2), %r13	#shld	\$1, %r12, %r13
++
++	mulq	%rax
++	addq	%rax, %r11
++	adcq	%rdx, %r12
++	adcq	\$0, %r13
++
++	movq	%r11, 32(%rsp)
++	movq	%r12, 40(%rsp)
++	shrq	\$63, %rcx
++
++#fourth iteration
++	movq	24($inp), %r10
++	movq	32($inp), %rax
++	mulq	%r10
++	addq	%rax, %r14
++	movq	40($inp), %rax
++	movq	%rdx, %rbx
++	adcq	\$0, %rbx
++
++	mulq	%r10
++	addq	%rax, %r15
++	movq	48($inp), %rax
++	adcq	\$0, %rdx
++	addq	%rbx, %r15
++	movq	%rdx, %rbx
++	adcq	\$0, %rbx
++
++	mulq	%r10
++	 movq	%r14, %r12
++	 leaq	(%rcx,%r14,2), %r14	#shld	\$1, %rcx, %r14
++	addq	%rax, %r8
++	movq	56($inp), %rax
++	adcq	\$0, %rdx
++	addq	%rbx, %r8
++	movq	%rdx, %rbx
++	adcq	\$0, %rbx
++
++	mulq	%r10
++	 shrq	\$63, %r12
++	addq	%rax, %r9
++	movq	%r10, %rax
++	adcq	\$0, %rdx
++	addq	%rbx, %r9
++	movq	%rdx, %r10
++	adcq	\$0, %r10
++
++	movq	%r15, %rbx
++	leaq	(%r12,%r15,2),%r15	#shld	\$1, %r14, %r15
++
++	mulq	%rax
++	addq	%rax, %r13
++	adcq	%rdx, %r14
++	adcq	\$0, %r15
++
++	movq	%r13, 48(%rsp)
++	movq	%r14, 56(%rsp)
++	shrq	\$63, %rbx
++
++#fifth iteration
++	movq	32($inp), %r11
++	movq	40($inp), %rax
++	mulq	%r11
++	addq	%rax, %r8
++	movq	48($inp), %rax
++	movq	%rdx, %rcx
++	adcq	\$0, %rcx
++
++	mulq	%r11
++	addq	%rax, %r9
++	movq	56($inp), %rax
++	adcq	\$0, %rdx
++	 movq	%r8, %r12
++	 leaq	(%rbx,%r8,2), %r8	#shld	\$1, %rbx, %r8
++	addq	%rcx, %r9
++	movq	%rdx, %rcx
++	adcq	\$0, %rcx
++
++	mulq	%r11
++	 shrq	\$63, %r12
++	addq	%rax, %r10
++	movq	%r11, %rax
++	adcq	\$0, %rdx
++	addq	%rcx, %r10
++	movq	%rdx, %r11
++	adcq	\$0, %r11
++
++	movq	%r9, %rcx
++	leaq	(%r12,%r9,2), %r9	#shld	\$1, %r8, %r9
++
++	mulq	%rax
++	addq	%rax, %r15
++	adcq	%rdx, %r8
++	adcq	\$0, %r9
++
++	movq	%r15, 64(%rsp)
++	movq	%r8, 72(%rsp)
++	shrq	\$63, %rcx
++
++#sixth iteration
++	movq	40($inp), %r12
++	movq	48($inp), %rax
++	mulq	%r12
++	addq	%rax, %r10
++	movq	56($inp), %rax
++	movq	%rdx, %rbx
++	adcq	\$0, %rbx
++
++	mulq	%r12
++	addq	%rax, %r11
++	movq	%r12, %rax
++	 movq	%r10, %r15
++	 leaq	(%rcx,%r10,2), %r10	#shld	\$1, %rcx, %r10
++	adcq	\$0, %rdx
++	 shrq	\$63, %r15
++	addq	%rbx, %r11
++	movq	%rdx, %r12
++	adcq	\$0, %r12
++
++	movq	%r11, %rbx
++	leaq	(%r15,%r11,2), %r11	#shld	\$1, %r10, %r11
++
++	mulq	%rax
++	addq	%rax, %r9
++	adcq	%rdx, %r10
++	adcq	\$0, %r11
++
++	movq	%r9, 80(%rsp)
++	movq	%r10, 88(%rsp)
++
++#seventh iteration
++	movq	48($inp), %r13
++	movq	56($inp), %rax
++	mulq	%r13
++	addq	%rax, %r12
++	movq	%r13, %rax
++	movq	%rdx, %r13
++	adcq	\$0, %r13
++
++	xorq	%r14, %r14
++	shlq	\$1, %rbx
++	adcq	%r12, %r12		#shld	\$1, %rbx, %r12
++	adcq	%r13, %r13		#shld	\$1, %r12, %r13
++	adcq	%r14, %r14		#shld	\$1, %r13, %r14
++
++	mulq	%rax
++	addq	%rax, %r11
++	adcq	%rdx, %r12
++	adcq	\$0, %r13
++
++	movq	%r11, 96(%rsp)
++	movq	%r12, 104(%rsp)
++
++#eighth iteration
++	movq	56($inp), %rax
++	mulq	%rax
++	addq	%rax, %r13
++	adcq	\$0, %rdx
++
++	addq	%rdx, %r14
++
++	movq	%r13, 112(%rsp)
++	movq	%r14, 120(%rsp)
++
++	movq	(%rsp), %r8
++	movq	8(%rsp), %r9
++	movq	16(%rsp), %r10
++	movq	24(%rsp), %r11
++	movq	32(%rsp), %r12
++	movq	40(%rsp), %r13
++	movq	48(%rsp), %r14
++	movq	56(%rsp), %r15
++
++	call	__rsaz_512_reduce
++
++	addq	64(%rsp), %r8
++	adcq	72(%rsp), %r9
++	adcq	80(%rsp), %r10
++	adcq	88(%rsp), %r11
++	adcq	96(%rsp), %r12
++	adcq	104(%rsp), %r13
++	adcq	112(%rsp), %r14
++	adcq	120(%rsp), %r15
++	sbbq	%rcx, %rcx
++
++	call	__rsaz_512_subtract
++
++	movq	%r8, %rdx
++	movq	%r9, %rax
++	movl	128+8(%rsp), $times
++	movq	$out, $inp
++
++	decl	$times
++	jnz	.Loop_sqr
++___
++if ($addx) {
++$code.=<<___;
++	jmp	.Lsqr_tail
++
++.align	32
++.Loop_sqrx:
++	movl	$times,128+8(%rsp)
++	movq	$out, %xmm0		# off-load
++	movq	%rbp, %xmm1		# off-load
++#first iteration	
++	mulx	%rax, %r8, %r9
++
++	mulx	16($inp), %rcx, %r10
++	xor	%rbp, %rbp		# cf=0, of=0
++
++	mulx	24($inp), %rax, %r11
++	adcx	%rcx, %r9
++
++	mulx	32($inp), %rcx, %r12
++	adcx	%rax, %r10
++
++	mulx	40($inp), %rax, %r13
++	adcx	%rcx, %r11
++
++	.byte	0xc4,0x62,0xf3,0xf6,0xb6,0x30,0x00,0x00,0x00	# mulx	48($inp), %rcx, %r14
++	adcx	%rax, %r12
++	adcx	%rcx, %r13
++
++	.byte	0xc4,0x62,0xfb,0xf6,0xbe,0x38,0x00,0x00,0x00	# mulx	56($inp), %rax, %r15
++	adcx	%rax, %r14
++	adcx	%rbp, %r15		# %rbp is 0
++
++	mov	%r9, %rcx
++	shld	\$1, %r8, %r9
++	shl	\$1, %r8
++
++	xor	%ebp, %ebp
++	mulx	%rdx, %rax, %rdx
++	adcx	%rdx, %r8
++	 mov	8($inp), %rdx
++	adcx	%rbp, %r9
++
++	mov	%rax, (%rsp)
++	mov	%r8, 8(%rsp)
++
++#second iteration	
++	mulx	16($inp), %rax, %rbx
++	adox	%rax, %r10
++	adcx	%rbx, %r11
++
++	.byte	0xc4,0x62,0xc3,0xf6,0x86,0x18,0x00,0x00,0x00	# mulx	24($inp), $out, %r8
++	adox	$out, %r11
++	adcx	%r8, %r12
++
++	mulx	32($inp), %rax, %rbx
++	adox	%rax, %r12
++	adcx	%rbx, %r13
++
++	mulx	40($inp), $out, %r8
++	adox	$out, %r13
++	adcx	%r8, %r14
++
++	.byte	0xc4,0xe2,0xfb,0xf6,0x9e,0x30,0x00,0x00,0x00	# mulx	48($inp), %rax, %rbx
++	adox	%rax, %r14
++	adcx	%rbx, %r15
++
++	.byte	0xc4,0x62,0xc3,0xf6,0x86,0x38,0x00,0x00,0x00	# mulx	56($inp), $out, %r8
++	adox	$out, %r15
++	adcx	%rbp, %r8
++	adox	%rbp, %r8
++
++	mov	%r11, %rbx
++	shld	\$1, %r10, %r11
++	shld	\$1, %rcx, %r10
++
++	xor	%ebp,%ebp
++	mulx	%rdx, %rax, %rcx
++	 mov	16($inp), %rdx
++	adcx	%rax, %r9
++	adcx	%rcx, %r10
++	adcx	%rbp, %r11
++
++	mov	%r9, 16(%rsp)
++	.byte	0x4c,0x89,0x94,0x24,0x18,0x00,0x00,0x00		# mov	%r10, 24(%rsp)
++	
++#third iteration	
++	.byte	0xc4,0x62,0xc3,0xf6,0x8e,0x18,0x00,0x00,0x00	# mulx	24($inp), $out, %r9
++	adox	$out, %r12
++	adcx	%r9, %r13
++
++	mulx	32($inp), %rax, %rcx
++	adox	%rax, %r13
++	adcx	%rcx, %r14
++
++	mulx	40($inp), $out, %r9
++	adox	$out, %r14
++	adcx	%r9, %r15
++
++	.byte	0xc4,0xe2,0xfb,0xf6,0x8e,0x30,0x00,0x00,0x00	# mulx	48($inp), %rax, %rcx
++	adox	%rax, %r15
++	adcx	%rcx, %r8
++
++	.byte	0xc4,0x62,0xc3,0xf6,0x8e,0x38,0x00,0x00,0x00	# mulx	56($inp), $out, %r9
++	adox	$out, %r8
++	adcx	%rbp, %r9
++	adox	%rbp, %r9
++
++	mov	%r13, %rcx
++	shld	\$1, %r12, %r13
++	shld	\$1, %rbx, %r12
++
++	xor	%ebp, %ebp
++	mulx	%rdx, %rax, %rdx
++	adcx	%rax, %r11
++	adcx	%rdx, %r12
++	 mov	24($inp), %rdx
++	adcx	%rbp, %r13
++
++	mov	%r11, 32(%rsp)
++	.byte	0x4c,0x89,0xa4,0x24,0x28,0x00,0x00,0x00		# mov	%r12, 40(%rsp)
++	
++#fourth iteration	
++	.byte	0xc4,0xe2,0xfb,0xf6,0x9e,0x20,0x00,0x00,0x00	# mulx	32($inp), %rax, %rbx
++	adox	%rax, %r14
++	adcx	%rbx, %r15
++
++	mulx	40($inp), $out, %r10
++	adox	$out, %r15
++	adcx	%r10, %r8
++
++	mulx	48($inp), %rax, %rbx
++	adox	%rax, %r8
++	adcx	%rbx, %r9
++
++	mulx	56($inp), $out, %r10
++	adox	$out, %r9
++	adcx	%rbp, %r10
++	adox	%rbp, %r10
++
++	.byte	0x66
++	mov	%r15, %rbx
++	shld	\$1, %r14, %r15
++	shld	\$1, %rcx, %r14
++
++	xor	%ebp, %ebp
++	mulx	%rdx, %rax, %rdx
++	adcx	%rax, %r13
++	adcx	%rdx, %r14
++	 mov	32($inp), %rdx
++	adcx	%rbp, %r15
++
++	mov	%r13, 48(%rsp)
++	mov	%r14, 56(%rsp)
++	
++#fifth iteration	
++	.byte	0xc4,0x62,0xc3,0xf6,0x9e,0x28,0x00,0x00,0x00	# mulx	40($inp), $out, %r11
++	adox	$out, %r8
++	adcx	%r11, %r9
++
++	mulx	48($inp), %rax, %rcx
++	adox	%rax, %r9
++	adcx	%rcx, %r10
++
++	mulx	56($inp), $out, %r11
++	adox	$out, %r10
++	adcx	%rbp, %r11
++	adox	%rbp, %r11
++
++	mov	%r9, %rcx
++	shld	\$1, %r8, %r9
++	shld	\$1, %rbx, %r8
++
++	xor	%ebp, %ebp
++	mulx	%rdx, %rax, %rdx
++	adcx	%rax, %r15
++	adcx	%rdx, %r8
++	 mov	40($inp), %rdx
++	adcx	%rbp, %r9
++
++	mov	%r15, 64(%rsp)
++	mov	%r8, 72(%rsp)
++	
++#sixth iteration	
++	.byte	0xc4,0xe2,0xfb,0xf6,0x9e,0x30,0x00,0x00,0x00	# mulx	48($inp), %rax, %rbx
++	adox	%rax, %r10
++	adcx	%rbx, %r11
++
++	.byte	0xc4,0x62,0xc3,0xf6,0xa6,0x38,0x00,0x00,0x00	# mulx	56($inp), $out, %r12
++	adox	$out, %r11
++	adcx	%rbp, %r12
++	adox	%rbp, %r12
++
++	mov	%r11, %rbx
++	shld	\$1, %r10, %r11
++	shld	\$1, %rcx, %r10
++
++	xor	%ebp, %ebp
++	mulx	%rdx, %rax, %rdx
++	adcx	%rax, %r9
++	adcx	%rdx, %r10
++	 mov	48($inp), %rdx
++	adcx	%rbp, %r11
++
++	mov	%r9, 80(%rsp)
++	mov	%r10, 88(%rsp)
++
++#seventh iteration
++	.byte	0xc4,0x62,0xfb,0xf6,0xae,0x38,0x00,0x00,0x00	# mulx	56($inp), %rax, %r13
++	adox	%rax, %r12
++	adox	%rbp, %r13
++
++	xor	%r14, %r14
++	shld	\$1, %r13, %r14
++	shld	\$1, %r12, %r13
++	shld	\$1, %rbx, %r12
++
++	xor	%ebp, %ebp
++	mulx	%rdx, %rax, %rdx
++	adcx	%rax, %r11
++	adcx	%rdx, %r12
++	 mov	56($inp), %rdx
++	adcx	%rbp, %r13
++
++	.byte	0x4c,0x89,0x9c,0x24,0x60,0x00,0x00,0x00		# mov	%r11, 96(%rsp)
++	.byte	0x4c,0x89,0xa4,0x24,0x68,0x00,0x00,0x00		# mov	%r12, 104(%rsp)
++
++#eighth iteration
++	mulx	%rdx, %rax, %rdx
++	adox	%rax, %r13
++	adox	%rbp, %rdx
++
++	.byte	0x66
++	add	%rdx, %r14
++
++	movq	%r13, 112(%rsp)
++	movq	%r14, 120(%rsp)
++	movq	%xmm0, $out
++	movq	%xmm1, %rbp
++
++	movq	128(%rsp), %rdx		# pull $n0
++	movq	(%rsp), %r8
++	movq	8(%rsp), %r9
++	movq	16(%rsp), %r10
++	movq	24(%rsp), %r11
++	movq	32(%rsp), %r12
++	movq	40(%rsp), %r13
++	movq	48(%rsp), %r14
++	movq	56(%rsp), %r15
++
++	call	__rsaz_512_reducex
++
++	addq	64(%rsp), %r8
++	adcq	72(%rsp), %r9
++	adcq	80(%rsp), %r10
++	adcq	88(%rsp), %r11
++	adcq	96(%rsp), %r12
++	adcq	104(%rsp), %r13
++	adcq	112(%rsp), %r14
++	adcq	120(%rsp), %r15
++	sbbq	%rcx, %rcx
++
++	call	__rsaz_512_subtract
++
++	movq	%r8, %rdx
++	movq	%r9, %rax
++	movl	128+8(%rsp), $times
++	movq	$out, $inp
++
++	decl	$times
++	jnz	.Loop_sqrx
++
++.Lsqr_tail:
++___
++}
++$code.=<<___;
++
++	leaq	128+24+48(%rsp), %rax
++	movq	-48(%rax), %r15
++	movq	-40(%rax), %r14
++	movq	-32(%rax), %r13
++	movq	-24(%rax), %r12
++	movq	-16(%rax), %rbp
++	movq	-8(%rax), %rbx
++	leaq	(%rax), %rsp
++.Lsqr_epilogue:
++	ret
++.size	rsaz_512_sqr,.-rsaz_512_sqr
++___
++}
++{
++my ($out,$ap,$bp,$mod,$n0) = ("%rdi","%rsi","%rdx","%rcx","%r8");
++$code.=<<___;
++.globl	rsaz_512_mul
++.type	rsaz_512_mul,\@function,5
++.align	32
++rsaz_512_mul:
++	push	%rbx
++	push	%rbp
++	push	%r12
++	push	%r13
++	push	%r14
++	push	%r15
++
++	subq	\$128+24, %rsp
++.Lmul_body:
++	movq	$out, %xmm0		# off-load arguments
++	movq	$mod, %xmm1
++	movq	$n0, 128(%rsp)
++___
++$code.=<<___ if ($addx);
++	movl	\$0x80100,%r11d
++	andl	OPENSSL_ia32cap_P+8(%rip),%r11d
++	cmpl	\$0x80100,%r11d		# check for MULX and ADO/CX
++	je	.Lmulx
++___
++$code.=<<___;
++	movq	($bp), %rbx		# pass b[0]
++	movq	$bp, %rbp		# pass argument
++	call	__rsaz_512_mul
++
++	movq	%xmm0, $out
++	movq	%xmm1, %rbp
++
++	movq	(%rsp), %r8
++	movq	8(%rsp), %r9
++	movq	16(%rsp), %r10
++	movq	24(%rsp), %r11
++	movq	32(%rsp), %r12
++	movq	40(%rsp), %r13
++	movq	48(%rsp), %r14
++	movq	56(%rsp), %r15
++
++	call	__rsaz_512_reduce
++___
++$code.=<<___ if ($addx);
++	jmp	.Lmul_tail
++
++.align	32
++.Lmulx:
++	movq	$bp, %rbp		# pass argument
++	movq	($bp), %rdx		# pass b[0]
++	call	__rsaz_512_mulx
++
++	movq	%xmm0, $out
++	movq	%xmm1, %rbp
++
++	movq	128(%rsp), %rdx		# pull $n0
++	movq	(%rsp), %r8
++	movq	8(%rsp), %r9
++	movq	16(%rsp), %r10
++	movq	24(%rsp), %r11
++	movq	32(%rsp), %r12
++	movq	40(%rsp), %r13
++	movq	48(%rsp), %r14
++	movq	56(%rsp), %r15
++
++	call	__rsaz_512_reducex
++.Lmul_tail:
++___
++$code.=<<___;
++	addq	64(%rsp), %r8
++	adcq	72(%rsp), %r9
++	adcq	80(%rsp), %r10
++	adcq	88(%rsp), %r11
++	adcq	96(%rsp), %r12
++	adcq	104(%rsp), %r13
++	adcq	112(%rsp), %r14
++	adcq	120(%rsp), %r15
++	sbbq	%rcx, %rcx
++
++	call	__rsaz_512_subtract
++
++	leaq	128+24+48(%rsp), %rax
++	movq	-48(%rax), %r15
++	movq	-40(%rax), %r14
++	movq	-32(%rax), %r13
++	movq	-24(%rax), %r12
++	movq	-16(%rax), %rbp
++	movq	-8(%rax), %rbx
++	leaq	(%rax), %rsp
++.Lmul_epilogue:
++	ret
++.size	rsaz_512_mul,.-rsaz_512_mul
++___
++}
++{
++my ($out,$ap,$bp,$mod,$n0,$pwr) = ("%rdi","%rsi","%rdx","%rcx","%r8","%r9d");
++$code.=<<___;
++.globl	rsaz_512_mul_gather4
++.type	rsaz_512_mul_gather4,\@function,6
++.align	32
++rsaz_512_mul_gather4:
++	push	%rbx
++	push	%rbp
++	push	%r12
++	push	%r13
++	push	%r14
++	push	%r15
++
++	subq	\$`128+24+($win64?0xb0:0)`, %rsp
++___
++$code.=<<___	if ($win64);
++	movaps	%xmm6,0xa0(%rsp)
++	movaps	%xmm7,0xb0(%rsp)
++	movaps	%xmm8,0xc0(%rsp)
++	movaps	%xmm9,0xd0(%rsp)
++	movaps	%xmm10,0xe0(%rsp)
++	movaps	%xmm11,0xf0(%rsp)
++	movaps	%xmm12,0x100(%rsp)
++	movaps	%xmm13,0x110(%rsp)
++	movaps	%xmm14,0x120(%rsp)
++	movaps	%xmm15,0x130(%rsp)
++___
++$code.=<<___;
++.Lmul_gather4_body:
++	movd	$pwr,%xmm8
++	movdqa	.Linc+16(%rip),%xmm1	# 00000002000000020000000200000002
++	movdqa	.Linc(%rip),%xmm0	# 00000001000000010000000000000000
++
++	pshufd	\$0,%xmm8,%xmm8		# broadcast $power
++	movdqa	%xmm1,%xmm7
++	movdqa	%xmm1,%xmm2
++___
++########################################################################
++# calculate mask by comparing 0..15 to $power
++#
++for($i=0;$i<4;$i++) {
++$code.=<<___;
++	paddd	%xmm`$i`,%xmm`$i+1`
++	pcmpeqd	%xmm8,%xmm`$i`
++	movdqa	%xmm7,%xmm`$i+3`
++___
++}
++for(;$i<7;$i++) {
++$code.=<<___;
++	paddd	%xmm`$i`,%xmm`$i+1`
++	pcmpeqd	%xmm8,%xmm`$i`
++___
++}
++$code.=<<___;
++	pcmpeqd	%xmm8,%xmm7
++
++	movdqa	16*0($bp),%xmm8
++	movdqa	16*1($bp),%xmm9
++	movdqa	16*2($bp),%xmm10
++	movdqa	16*3($bp),%xmm11
++	pand	%xmm0,%xmm8
++	movdqa	16*4($bp),%xmm12
++	pand	%xmm1,%xmm9
++	movdqa	16*5($bp),%xmm13
++	pand	%xmm2,%xmm10
++	movdqa	16*6($bp),%xmm14
++	pand	%xmm3,%xmm11
++	movdqa	16*7($bp),%xmm15
++	leaq	128($bp), %rbp
++	pand	%xmm4,%xmm12
++	pand	%xmm5,%xmm13
++	pand	%xmm6,%xmm14
++	pand	%xmm7,%xmm15
++	por	%xmm10,%xmm8
++	por	%xmm11,%xmm9
++	por	%xmm12,%xmm8
++	por	%xmm13,%xmm9
++	por	%xmm14,%xmm8
++	por	%xmm15,%xmm9
++
++	por	%xmm9,%xmm8
++	pshufd	\$0x4e,%xmm8,%xmm9
++	por	%xmm9,%xmm8
++___
++$code.=<<___ if ($addx);
++	movl	\$0x80100,%r11d
++	andl	OPENSSL_ia32cap_P+8(%rip),%r11d
++	cmpl	\$0x80100,%r11d		# check for MULX and ADO/CX
++	je	.Lmulx_gather
++___
++$code.=<<___;
++	movq	%xmm8,%rbx
++
++	movq	$n0, 128(%rsp)		# off-load arguments
++	movq	$out, 128+8(%rsp)
++	movq	$mod, 128+16(%rsp)
++
++	movq	($ap), %rax
++	 movq	8($ap), %rcx
++	mulq	%rbx			# 0 iteration
++	movq	%rax, (%rsp)
++	movq	%rcx, %rax
++	movq	%rdx, %r8
++
++	mulq	%rbx
++	addq	%rax, %r8
++	movq	16($ap), %rax
++	movq	%rdx, %r9
++	adcq	\$0, %r9
++
++	mulq	%rbx
++	addq	%rax, %r9
++	movq	24($ap), %rax
++	movq	%rdx, %r10
++	adcq	\$0, %r10
++
++	mulq	%rbx
++	addq	%rax, %r10
++	movq	32($ap), %rax
++	movq	%rdx, %r11
++	adcq	\$0, %r11
++
++	mulq	%rbx
++	addq	%rax, %r11
++	movq	40($ap), %rax
++	movq	%rdx, %r12
++	adcq	\$0, %r12
++
++	mulq	%rbx
++	addq	%rax, %r12
++	movq	48($ap), %rax
++	movq	%rdx, %r13
++	adcq	\$0, %r13
++
++	mulq	%rbx
++	addq	%rax, %r13
++	movq	56($ap), %rax
++	movq	%rdx, %r14
++	adcq	\$0, %r14
++	
++	mulq	%rbx
++	addq	%rax, %r14
++	 movq	($ap), %rax
++	movq	%rdx, %r15
++	adcq	\$0, %r15
++
++	leaq	8(%rsp), %rdi
++	movl	\$7, %ecx
++	jmp	.Loop_mul_gather
++
++.align	32
++.Loop_mul_gather:
++	movdqa	16*0(%rbp),%xmm8
++	movdqa	16*1(%rbp),%xmm9
++	movdqa	16*2(%rbp),%xmm10
++	movdqa	16*3(%rbp),%xmm11
++	pand	%xmm0,%xmm8
++	movdqa	16*4(%rbp),%xmm12
++	pand	%xmm1,%xmm9
++	movdqa	16*5(%rbp),%xmm13
++	pand	%xmm2,%xmm10
++	movdqa	16*6(%rbp),%xmm14
++	pand	%xmm3,%xmm11
++	movdqa	16*7(%rbp),%xmm15
++	leaq	128(%rbp), %rbp
++	pand	%xmm4,%xmm12
++	pand	%xmm5,%xmm13
++	pand	%xmm6,%xmm14
++	pand	%xmm7,%xmm15
++	por	%xmm10,%xmm8
++	por	%xmm11,%xmm9
++	por	%xmm12,%xmm8
++	por	%xmm13,%xmm9
++	por	%xmm14,%xmm8
++	por	%xmm15,%xmm9
++
++	por	%xmm9,%xmm8
++	pshufd	\$0x4e,%xmm8,%xmm9
++	por	%xmm9,%xmm8
++	movq	%xmm8,%rbx
++
++	mulq	%rbx
++	addq	%rax, %r8
++	movq	8($ap), %rax
++	movq	%r8, (%rdi)
++	movq	%rdx, %r8
++	adcq	\$0, %r8
++
++	mulq	%rbx
++	addq	%rax, %r9
++	movq	16($ap), %rax
++	adcq	\$0, %rdx
++	addq	%r9, %r8
++	movq	%rdx, %r9
++	adcq	\$0, %r9
++
++	mulq	%rbx
++	addq	%rax, %r10
++	movq	24($ap), %rax
++	adcq	\$0, %rdx
++	addq	%r10, %r9
++	movq	%rdx, %r10
++	adcq	\$0, %r10
++
++	mulq	%rbx
++	addq	%rax, %r11
++	movq	32($ap), %rax
++	adcq	\$0, %rdx
++	addq	%r11, %r10
++	movq	%rdx, %r11
++	adcq	\$0, %r11
++
++	mulq	%rbx
++	addq	%rax, %r12
++	movq	40($ap), %rax
++	adcq	\$0, %rdx
++	addq	%r12, %r11
++	movq	%rdx, %r12
++	adcq	\$0, %r12
++
++	mulq	%rbx
++	addq	%rax, %r13
++	movq	48($ap), %rax
++	adcq	\$0, %rdx
++	addq	%r13, %r12
++	movq	%rdx, %r13
++	adcq	\$0, %r13
++
++	mulq	%rbx
++	addq	%rax, %r14
++	movq	56($ap), %rax
++	adcq	\$0, %rdx
++	addq	%r14, %r13
++	movq	%rdx, %r14
++	adcq	\$0, %r14
++
++	mulq	%rbx
++	addq	%rax, %r15
++	 movq	($ap), %rax
++	adcq	\$0, %rdx
++	addq	%r15, %r14
++	movq	%rdx, %r15	
++	adcq	\$0, %r15
++
++	leaq	8(%rdi), %rdi
++
++	decl	%ecx
++	jnz	.Loop_mul_gather
++
++	movq	%r8, (%rdi)
++	movq	%r9, 8(%rdi)
++	movq	%r10, 16(%rdi)
++	movq	%r11, 24(%rdi)
++	movq	%r12, 32(%rdi)
++	movq	%r13, 40(%rdi)
++	movq	%r14, 48(%rdi)
++	movq	%r15, 56(%rdi)
++
++	movq	128+8(%rsp), $out
++	movq	128+16(%rsp), %rbp
++
++	movq	(%rsp), %r8
++	movq	8(%rsp), %r9
++	movq	16(%rsp), %r10
++	movq	24(%rsp), %r11
++	movq	32(%rsp), %r12
++	movq	40(%rsp), %r13
++	movq	48(%rsp), %r14
++	movq	56(%rsp), %r15
++
++	call	__rsaz_512_reduce
++___
++$code.=<<___ if ($addx);
++	jmp	.Lmul_gather_tail
++
++.align	32
++.Lmulx_gather:
++	movq	%xmm8,%rdx
++
++	mov	$n0, 128(%rsp)		# off-load arguments
++	mov	$out, 128+8(%rsp)
++	mov	$mod, 128+16(%rsp)
++
++	mulx	($ap), %rbx, %r8	# 0 iteration
++	mov	%rbx, (%rsp)
++	xor	%edi, %edi		# cf=0, of=0
++
++	mulx	8($ap), %rax, %r9
++
++	mulx	16($ap), %rbx, %r10
++	adcx	%rax, %r8
++
++	mulx	24($ap), %rax, %r11
++	adcx	%rbx, %r9
++
++	mulx	32($ap), %rbx, %r12
++	adcx	%rax, %r10
++
++	mulx	40($ap), %rax, %r13
++	adcx	%rbx, %r11
++
++	mulx	48($ap), %rbx, %r14
++	adcx	%rax, %r12
++	
++	mulx	56($ap), %rax, %r15
++	adcx	%rbx, %r13
++	adcx	%rax, %r14
++	.byte	0x67
++	mov	%r8, %rbx
++	adcx	%rdi, %r15		# %rdi is 0
++
++	mov	\$-7, %rcx
++	jmp	.Loop_mulx_gather
++
++.align	32
++.Loop_mulx_gather:
++	movdqa	16*0(%rbp),%xmm8
++	movdqa	16*1(%rbp),%xmm9
++	movdqa	16*2(%rbp),%xmm10
++	movdqa	16*3(%rbp),%xmm11
++	pand	%xmm0,%xmm8
++	movdqa	16*4(%rbp),%xmm12
++	pand	%xmm1,%xmm9
++	movdqa	16*5(%rbp),%xmm13
++	pand	%xmm2,%xmm10
++	movdqa	16*6(%rbp),%xmm14
++	pand	%xmm3,%xmm11
++	movdqa	16*7(%rbp),%xmm15
++	leaq	128(%rbp), %rbp
++	pand	%xmm4,%xmm12
++	pand	%xmm5,%xmm13
++	pand	%xmm6,%xmm14
++	pand	%xmm7,%xmm15
++	por	%xmm10,%xmm8
++	por	%xmm11,%xmm9
++	por	%xmm12,%xmm8
++	por	%xmm13,%xmm9
++	por	%xmm14,%xmm8
++	por	%xmm15,%xmm9
++
++	por	%xmm9,%xmm8
++	pshufd	\$0x4e,%xmm8,%xmm9
++	por	%xmm9,%xmm8
++	movq	%xmm8,%rdx
++
++	.byte	0xc4,0x62,0xfb,0xf6,0x86,0x00,0x00,0x00,0x00	# mulx	($ap), %rax, %r8
++	adcx	%rax, %rbx
++	adox	%r9, %r8
++
++	mulx	8($ap), %rax, %r9
++	adcx	%rax, %r8
++	adox	%r10, %r9
++
++	mulx	16($ap), %rax, %r10
++	adcx	%rax, %r9
++	adox	%r11, %r10
++
++	.byte	0xc4,0x62,0xfb,0xf6,0x9e,0x18,0x00,0x00,0x00	# mulx	24($ap), %rax, %r11
++	adcx	%rax, %r10
++	adox	%r12, %r11
++
++	mulx	32($ap), %rax, %r12
++	adcx	%rax, %r11
++	adox	%r13, %r12
++
++	mulx	40($ap), %rax, %r13
++	adcx	%rax, %r12
++	adox	%r14, %r13
++
++	.byte	0xc4,0x62,0xfb,0xf6,0xb6,0x30,0x00,0x00,0x00	# mulx	48($ap), %rax, %r14
++	adcx	%rax, %r13
++	.byte	0x67
++	adox	%r15, %r14
++
++	mulx	56($ap), %rax, %r15
++	 mov	%rbx, 64(%rsp,%rcx,8)
++	adcx	%rax, %r14
++	adox	%rdi, %r15
++	mov	%r8, %rbx
++	adcx	%rdi, %r15		# cf=0
++
++	inc	%rcx			# of=0
++	jnz	.Loop_mulx_gather
++
++	mov	%r8, 64(%rsp)
++	mov	%r9, 64+8(%rsp)
++	mov	%r10, 64+16(%rsp)
++	mov	%r11, 64+24(%rsp)
++	mov	%r12, 64+32(%rsp)
++	mov	%r13, 64+40(%rsp)
++	mov	%r14, 64+48(%rsp)
++	mov	%r15, 64+56(%rsp)
++
++	mov	128(%rsp), %rdx		# pull arguments
++	mov	128+8(%rsp), $out
++	mov	128+16(%rsp), %rbp
++
++	mov	(%rsp), %r8
++	mov	8(%rsp), %r9
++	mov	16(%rsp), %r10
++	mov	24(%rsp), %r11
++	mov	32(%rsp), %r12
++	mov	40(%rsp), %r13
++	mov	48(%rsp), %r14
++	mov	56(%rsp), %r15
++
++	call	__rsaz_512_reducex
++
++.Lmul_gather_tail:
++___
++$code.=<<___;
++	addq	64(%rsp), %r8
++	adcq	72(%rsp), %r9
++	adcq	80(%rsp), %r10
++	adcq	88(%rsp), %r11
++	adcq	96(%rsp), %r12
++	adcq	104(%rsp), %r13
++	adcq	112(%rsp), %r14
++	adcq	120(%rsp), %r15
++	sbbq	%rcx, %rcx
++
++	call	__rsaz_512_subtract
++
++	leaq	128+24+48(%rsp), %rax
++___
++$code.=<<___	if ($win64);
++	movaps	0xa0-0xc8(%rax),%xmm6
++	movaps	0xb0-0xc8(%rax),%xmm7
++	movaps	0xc0-0xc8(%rax),%xmm8
++	movaps	0xd0-0xc8(%rax),%xmm9
++	movaps	0xe0-0xc8(%rax),%xmm10
++	movaps	0xf0-0xc8(%rax),%xmm11
++	movaps	0x100-0xc8(%rax),%xmm12
++	movaps	0x110-0xc8(%rax),%xmm13
++	movaps	0x120-0xc8(%rax),%xmm14
++	movaps	0x130-0xc8(%rax),%xmm15
++	lea	0xb0(%rax),%rax
++___
++$code.=<<___;
++	movq	-48(%rax), %r15
++	movq	-40(%rax), %r14
++	movq	-32(%rax), %r13
++	movq	-24(%rax), %r12
++	movq	-16(%rax), %rbp
++	movq	-8(%rax), %rbx
++	leaq	(%rax), %rsp
++.Lmul_gather4_epilogue:
++	ret
++.size	rsaz_512_mul_gather4,.-rsaz_512_mul_gather4
++___
++}
++{
++my ($out,$ap,$mod,$n0,$tbl,$pwr) = ("%rdi","%rsi","%rdx","%rcx","%r8","%r9d");
++$code.=<<___;
++.globl	rsaz_512_mul_scatter4
++.type	rsaz_512_mul_scatter4,\@function,6
++.align	32
++rsaz_512_mul_scatter4:
++	push	%rbx
++	push	%rbp
++	push	%r12
++	push	%r13
++	push	%r14
++	push	%r15
++
++	mov	$pwr, $pwr
++	subq	\$128+24, %rsp
++.Lmul_scatter4_body:
++	leaq	($tbl,$pwr,8), $tbl
++	movq	$out, %xmm0		# off-load arguments
++	movq	$mod, %xmm1
++	movq	$tbl, %xmm2
++	movq	$n0, 128(%rsp)
++
++	movq	$out, %rbp
++___
++$code.=<<___ if ($addx);
++	movl	\$0x80100,%r11d
++	andl	OPENSSL_ia32cap_P+8(%rip),%r11d
++	cmpl	\$0x80100,%r11d		# check for MULX and ADO/CX
++	je	.Lmulx_scatter
++___
++$code.=<<___;
++	movq	($out),%rbx		# pass b[0]
++	call	__rsaz_512_mul
++
++	movq	%xmm0, $out
++	movq	%xmm1, %rbp
++
++	movq	(%rsp), %r8
++	movq	8(%rsp), %r9
++	movq	16(%rsp), %r10
++	movq	24(%rsp), %r11
++	movq	32(%rsp), %r12
++	movq	40(%rsp), %r13
++	movq	48(%rsp), %r14
++	movq	56(%rsp), %r15
++
++	call	__rsaz_512_reduce
++___
++$code.=<<___ if ($addx);
++	jmp	.Lmul_scatter_tail
++	
++.align	32
++.Lmulx_scatter:
++	movq	($out), %rdx		# pass b[0]
++	call	__rsaz_512_mulx
++
++	movq	%xmm0, $out
++	movq	%xmm1, %rbp
++
++	movq	128(%rsp), %rdx		# pull $n0
++	movq	(%rsp), %r8
++	movq	8(%rsp), %r9
++	movq	16(%rsp), %r10
++	movq	24(%rsp), %r11
++	movq	32(%rsp), %r12
++	movq	40(%rsp), %r13
++	movq	48(%rsp), %r14
++	movq	56(%rsp), %r15
++
++	call	__rsaz_512_reducex
++
++.Lmul_scatter_tail:
++___
++$code.=<<___;
++	addq	64(%rsp), %r8
++	adcq	72(%rsp), %r9
++	adcq	80(%rsp), %r10
++	adcq	88(%rsp), %r11
++	adcq	96(%rsp), %r12
++	adcq	104(%rsp), %r13
++	adcq	112(%rsp), %r14
++	adcq	120(%rsp), %r15
++	movq	%xmm2, $inp
++	sbbq	%rcx, %rcx
++
++	call	__rsaz_512_subtract
++
++	movq	%r8, 128*0($inp)	# scatter
++	movq	%r9, 128*1($inp)
++	movq	%r10, 128*2($inp)
++	movq	%r11, 128*3($inp)
++	movq	%r12, 128*4($inp)
++	movq	%r13, 128*5($inp)
++	movq	%r14, 128*6($inp)
++	movq	%r15, 128*7($inp)
++
++	leaq	128+24+48(%rsp), %rax
++	movq	-48(%rax), %r15
++	movq	-40(%rax), %r14
++	movq	-32(%rax), %r13
++	movq	-24(%rax), %r12
++	movq	-16(%rax), %rbp
++	movq	-8(%rax), %rbx
++	leaq	(%rax), %rsp
++.Lmul_scatter4_epilogue:
++	ret
++.size	rsaz_512_mul_scatter4,.-rsaz_512_mul_scatter4
++___
++}
++{
++my ($out,$inp,$mod,$n0) = ("%rdi","%rsi","%rdx","%rcx");
++$code.=<<___;
++.globl	rsaz_512_mul_by_one
++.type	rsaz_512_mul_by_one,\@function,4
++.align	32
++rsaz_512_mul_by_one:
++	push	%rbx
++	push	%rbp
++	push	%r12
++	push	%r13
++	push	%r14
++	push	%r15
++
++	subq	\$128+24, %rsp
++.Lmul_by_one_body:
++___
++$code.=<<___ if ($addx);
++	movl	OPENSSL_ia32cap_P+8(%rip),%eax
++___
++$code.=<<___;
++	movq	$mod, %rbp	# reassign argument
++	movq	$n0, 128(%rsp)
++
++	movq	($inp), %r8
++	pxor	%xmm0, %xmm0
++	movq	8($inp), %r9
++	movq	16($inp), %r10
++	movq	24($inp), %r11
++	movq	32($inp), %r12
++	movq	40($inp), %r13
++	movq	48($inp), %r14
++	movq	56($inp), %r15
++
++	movdqa	%xmm0, (%rsp)
++	movdqa	%xmm0, 16(%rsp)
++	movdqa	%xmm0, 32(%rsp)
++	movdqa	%xmm0, 48(%rsp)
++	movdqa	%xmm0, 64(%rsp)
++	movdqa	%xmm0, 80(%rsp)
++	movdqa	%xmm0, 96(%rsp)
++___
++$code.=<<___ if ($addx);
++	andl	\$0x80100,%eax
++	cmpl	\$0x80100,%eax		# check for MULX and ADO/CX
++	je	.Lby_one_callx
++___
++$code.=<<___;
++	call	__rsaz_512_reduce
++___
++$code.=<<___ if ($addx);
++	jmp	.Lby_one_tail
++.align	32
++.Lby_one_callx:
++	movq	128(%rsp), %rdx		# pull $n0
++	call	__rsaz_512_reducex
++.Lby_one_tail:
++___
++$code.=<<___;
++	movq	%r8, ($out)
++	movq	%r9, 8($out)
++	movq	%r10, 16($out)
++	movq	%r11, 24($out)
++	movq	%r12, 32($out)
++	movq	%r13, 40($out)
++	movq	%r14, 48($out)
++	movq	%r15, 56($out)
++
++	leaq	128+24+48(%rsp), %rax
++	movq	-48(%rax), %r15
++	movq	-40(%rax), %r14
++	movq	-32(%rax), %r13
++	movq	-24(%rax), %r12
++	movq	-16(%rax), %rbp
++	movq	-8(%rax), %rbx
++	leaq	(%rax), %rsp
++.Lmul_by_one_epilogue:
++	ret
++.size	rsaz_512_mul_by_one,.-rsaz_512_mul_by_one
++___
++}
++{	# __rsaz_512_reduce
++	#
++	# input:	%r8-%r15, %rbp - mod, 128(%rsp) - n0
++	# output:	%r8-%r15
++	# clobbers:	everything except %rbp and %rdi
++$code.=<<___;
++.type	__rsaz_512_reduce,\@abi-omnipotent
++.align	32
++__rsaz_512_reduce:
++	movq	%r8, %rbx
++	imulq	128+8(%rsp), %rbx
++	movq	0(%rbp), %rax
++	movl	\$8, %ecx
++	jmp	.Lreduction_loop
++
++.align	32
++.Lreduction_loop:
++	mulq	%rbx
++	movq	8(%rbp), %rax
++	negq	%r8
++	movq	%rdx, %r8
++	adcq	\$0, %r8
++
++	mulq	%rbx
++	addq	%rax, %r9
++	movq	16(%rbp), %rax
++	adcq	\$0, %rdx
++	addq	%r9, %r8
++	movq	%rdx, %r9
++	adcq	\$0, %r9
++
++	mulq	%rbx
++	addq	%rax, %r10
++	movq	24(%rbp), %rax
++	adcq	\$0, %rdx
++	addq	%r10, %r9
++	movq	%rdx, %r10
++	adcq	\$0, %r10
++
++	mulq	%rbx
++	addq	%rax, %r11
++	movq	32(%rbp), %rax
++	adcq	\$0, %rdx
++	addq	%r11, %r10
++	 movq	128+8(%rsp), %rsi
++	#movq	%rdx, %r11
++	#adcq	\$0, %r11
++	adcq	\$0, %rdx
++	movq	%rdx, %r11
++
++	mulq	%rbx
++	addq	%rax, %r12
++	movq	40(%rbp), %rax
++	adcq	\$0, %rdx
++	 imulq	%r8, %rsi
++	addq	%r12, %r11
++	movq	%rdx, %r12
++	adcq	\$0, %r12
++
++	mulq	%rbx
++	addq	%rax, %r13
++	movq	48(%rbp), %rax
++	adcq	\$0, %rdx
++	addq	%r13, %r12
++	movq	%rdx, %r13
++	adcq	\$0, %r13
++
++	mulq	%rbx
++	addq	%rax, %r14
++	movq	56(%rbp), %rax
++	adcq	\$0, %rdx
++	addq	%r14, %r13
++	movq	%rdx, %r14
++	adcq	\$0, %r14
++
++	mulq	%rbx
++	 movq	%rsi, %rbx
++	addq	%rax, %r15
++	 movq	0(%rbp), %rax
++	adcq	\$0, %rdx
++	addq	%r15, %r14
++	movq	%rdx, %r15
++	adcq	\$0, %r15
++
++	decl	%ecx
++	jne	.Lreduction_loop
++
++	ret
++.size	__rsaz_512_reduce,.-__rsaz_512_reduce
++___
++}
++if ($addx) {
++	# __rsaz_512_reducex
++	#
++	# input:	%r8-%r15, %rbp - mod, 128(%rsp) - n0
++	# output:	%r8-%r15
++	# clobbers:	everything except %rbp and %rdi
++$code.=<<___;
++.type	__rsaz_512_reducex,\@abi-omnipotent
++.align	32
++__rsaz_512_reducex:
++	#movq	128+8(%rsp), %rdx		# pull $n0
++	imulq	%r8, %rdx
++	xorq	%rsi, %rsi			# cf=0,of=0
++	movl	\$8, %ecx
++	jmp	.Lreduction_loopx
++
++.align	32
++.Lreduction_loopx:
++	mov	%r8, %rbx
++	mulx	0(%rbp), %rax, %r8
++	adcx	%rbx, %rax
++	adox	%r9, %r8
++
++	mulx	8(%rbp), %rax, %r9
++	adcx	%rax, %r8
++	adox	%r10, %r9
++
++	mulx	16(%rbp), %rbx, %r10
++	adcx	%rbx, %r9
++	adox	%r11, %r10
++
++	mulx	24(%rbp), %rbx, %r11
++	adcx	%rbx, %r10
++	adox	%r12, %r11
++
++	.byte	0xc4,0x62,0xe3,0xf6,0xa5,0x20,0x00,0x00,0x00	# mulx	32(%rbp), %rbx, %r12
++	 mov	%rdx, %rax
++	 mov	%r8, %rdx
++	adcx	%rbx, %r11
++	adox	%r13, %r12
++
++	 mulx	128+8(%rsp), %rbx, %rdx
++	 mov	%rax, %rdx
++
++	mulx	40(%rbp), %rax, %r13
++	adcx	%rax, %r12
++	adox	%r14, %r13
++
++	.byte	0xc4,0x62,0xfb,0xf6,0xb5,0x30,0x00,0x00,0x00	# mulx	48(%rbp), %rax, %r14
++	adcx	%rax, %r13
++	adox	%r15, %r14
++
++	mulx	56(%rbp), %rax, %r15
++	 mov	%rbx, %rdx
++	adcx	%rax, %r14
++	adox	%rsi, %r15			# %rsi is 0
++	adcx	%rsi, %r15			# cf=0
++
++	decl	%ecx				# of=0
++	jne	.Lreduction_loopx
++
++	ret
++.size	__rsaz_512_reducex,.-__rsaz_512_reducex
++___
++}
++{	# __rsaz_512_subtract
++	# input: %r8-%r15, %rdi - $out, %rbp - $mod, %rcx - mask
++	# output:
++	# clobbers: everything but %rdi, %rsi and %rbp
++$code.=<<___;
++.type	__rsaz_512_subtract,\@abi-omnipotent
++.align	32
++__rsaz_512_subtract:
++	movq	%r8, ($out)
++	movq	%r9, 8($out)
++	movq	%r10, 16($out)
++	movq	%r11, 24($out)
++	movq	%r12, 32($out)
++	movq	%r13, 40($out)
++	movq	%r14, 48($out)
++	movq	%r15, 56($out)
++
++	movq	0($mod), %r8
++	movq	8($mod), %r9
++	negq	%r8
++	notq	%r9
++	andq	%rcx, %r8
++	movq	16($mod), %r10
++	andq	%rcx, %r9
++	notq	%r10
++	movq	24($mod), %r11
++	andq	%rcx, %r10
++	notq	%r11
++	movq	32($mod), %r12
++	andq	%rcx, %r11
++	notq	%r12
++	movq	40($mod), %r13
++	andq	%rcx, %r12
++	notq	%r13
++	movq	48($mod), %r14
++	andq	%rcx, %r13
++	notq	%r14
++	movq	56($mod), %r15
++	andq	%rcx, %r14
++	notq	%r15
++	andq	%rcx, %r15
++
++	addq	($out), %r8
++	adcq	8($out), %r9
++	adcq	16($out), %r10
++	adcq	24($out), %r11
++	adcq	32($out), %r12
++	adcq	40($out), %r13
++	adcq	48($out), %r14
++	adcq	56($out), %r15
++
++	movq	%r8, ($out)
++	movq	%r9, 8($out)
++	movq	%r10, 16($out)
++	movq	%r11, 24($out)
++	movq	%r12, 32($out)
++	movq	%r13, 40($out)
++	movq	%r14, 48($out)
++	movq	%r15, 56($out)
++
++	ret
++.size	__rsaz_512_subtract,.-__rsaz_512_subtract
++___
++}
++{	# __rsaz_512_mul
++	#
++	# input: %rsi - ap, %rbp - bp
++	# output:
++	# clobbers: everything
++my ($ap,$bp) = ("%rsi","%rbp");
++$code.=<<___;
++.type	__rsaz_512_mul,\@abi-omnipotent
++.align	32
++__rsaz_512_mul:
++	leaq	8(%rsp), %rdi
++
++	movq	($ap), %rax
++	mulq	%rbx
++	movq	%rax, (%rdi)
++	movq	8($ap), %rax
++	movq	%rdx, %r8
++
++	mulq	%rbx
++	addq	%rax, %r8
++	movq	16($ap), %rax
++	movq	%rdx, %r9
++	adcq	\$0, %r9
++
++	mulq	%rbx
++	addq	%rax, %r9
++	movq	24($ap), %rax
++	movq	%rdx, %r10
++	adcq	\$0, %r10
++
++	mulq	%rbx
++	addq	%rax, %r10
++	movq	32($ap), %rax
++	movq	%rdx, %r11
++	adcq	\$0, %r11
++
++	mulq	%rbx
++	addq	%rax, %r11
++	movq	40($ap), %rax
++	movq	%rdx, %r12
++	adcq	\$0, %r12
++
++	mulq	%rbx
++	addq	%rax, %r12
++	movq	48($ap), %rax
++	movq	%rdx, %r13
++	adcq	\$0, %r13
++
++	mulq	%rbx
++	addq	%rax, %r13
++	movq	56($ap), %rax
++	movq	%rdx, %r14
++	adcq	\$0, %r14
++	
++	mulq	%rbx
++	addq	%rax, %r14
++	 movq	($ap), %rax
++	movq	%rdx, %r15
++	adcq	\$0, %r15
++
++	leaq	8($bp), $bp
++	leaq	8(%rdi), %rdi
++
++	movl	\$7, %ecx
++	jmp	.Loop_mul
++
++.align	32
++.Loop_mul:
++	movq	($bp), %rbx
++	mulq	%rbx
++	addq	%rax, %r8
++	movq	8($ap), %rax
++	movq	%r8, (%rdi)
++	movq	%rdx, %r8
++	adcq	\$0, %r8
++
++	mulq	%rbx
++	addq	%rax, %r9
++	movq	16($ap), %rax
++	adcq	\$0, %rdx
++	addq	%r9, %r8
++	movq	%rdx, %r9
++	adcq	\$0, %r9
++
++	mulq	%rbx
++	addq	%rax, %r10
++	movq	24($ap), %rax
++	adcq	\$0, %rdx
++	addq	%r10, %r9
++	movq	%rdx, %r10
++	adcq	\$0, %r10
++
++	mulq	%rbx
++	addq	%rax, %r11
++	movq	32($ap), %rax
++	adcq	\$0, %rdx
++	addq	%r11, %r10
++	movq	%rdx, %r11
++	adcq	\$0, %r11
++
++	mulq	%rbx
++	addq	%rax, %r12
++	movq	40($ap), %rax
++	adcq	\$0, %rdx
++	addq	%r12, %r11
++	movq	%rdx, %r12
++	adcq	\$0, %r12
++
++	mulq	%rbx
++	addq	%rax, %r13
++	movq	48($ap), %rax
++	adcq	\$0, %rdx
++	addq	%r13, %r12
++	movq	%rdx, %r13
++	adcq	\$0, %r13
++
++	mulq	%rbx
++	addq	%rax, %r14
++	movq	56($ap), %rax
++	adcq	\$0, %rdx
++	addq	%r14, %r13
++	movq	%rdx, %r14
++	 leaq	8($bp), $bp
++	adcq	\$0, %r14
++
++	mulq	%rbx
++	addq	%rax, %r15
++	 movq	($ap), %rax
++	adcq	\$0, %rdx
++	addq	%r15, %r14
++	movq	%rdx, %r15	
++	adcq	\$0, %r15
++
++	leaq	8(%rdi), %rdi
++
++	decl	%ecx
++	jnz	.Loop_mul
++
++	movq	%r8, (%rdi)
++	movq	%r9, 8(%rdi)
++	movq	%r10, 16(%rdi)
++	movq	%r11, 24(%rdi)
++	movq	%r12, 32(%rdi)
++	movq	%r13, 40(%rdi)
++	movq	%r14, 48(%rdi)
++	movq	%r15, 56(%rdi)
++
++	ret
++.size	__rsaz_512_mul,.-__rsaz_512_mul
++___
++}
++if ($addx) {
++	# __rsaz_512_mulx
++	#
++	# input: %rsi - ap, %rbp - bp
++	# output:
++	# clobbers: everything
++my ($ap,$bp,$zero) = ("%rsi","%rbp","%rdi");
++$code.=<<___;
++.type	__rsaz_512_mulx,\@abi-omnipotent
++.align	32
++__rsaz_512_mulx:
++	mulx	($ap), %rbx, %r8	# initial %rdx preloaded by caller
++	mov	\$-6, %rcx
++
++	mulx	8($ap), %rax, %r9
++	movq	%rbx, 8(%rsp)
++
++	mulx	16($ap), %rbx, %r10
++	adc	%rax, %r8
++
++	mulx	24($ap), %rax, %r11
++	adc	%rbx, %r9
++
++	mulx	32($ap), %rbx, %r12
++	adc	%rax, %r10
++
++	mulx	40($ap), %rax, %r13
++	adc	%rbx, %r11
++
++	mulx	48($ap), %rbx, %r14
++	adc	%rax, %r12
++
++	mulx	56($ap), %rax, %r15
++	 mov	8($bp), %rdx
++	adc	%rbx, %r13
++	adc	%rax, %r14
++	adc	\$0, %r15
++
++	xor	$zero, $zero		# cf=0,of=0
++	jmp	.Loop_mulx
++
++.align	32
++.Loop_mulx:
++	movq	%r8, %rbx
++	mulx	($ap), %rax, %r8
++	adcx	%rax, %rbx
++	adox	%r9, %r8
++
++	mulx	8($ap), %rax, %r9
++	adcx	%rax, %r8
++	adox	%r10, %r9
++
++	mulx	16($ap), %rax, %r10
++	adcx	%rax, %r9
++	adox	%r11, %r10
++
++	mulx	24($ap), %rax, %r11
++	adcx	%rax, %r10
++	adox	%r12, %r11
++
++	.byte	0x3e,0xc4,0x62,0xfb,0xf6,0xa6,0x20,0x00,0x00,0x00	# mulx	32($ap), %rax, %r12
++	adcx	%rax, %r11
++	adox	%r13, %r12
++
++	mulx	40($ap), %rax, %r13
++	adcx	%rax, %r12
++	adox	%r14, %r13
++
++	mulx	48($ap), %rax, %r14
++	adcx	%rax, %r13
++	adox	%r15, %r14
++
++	mulx	56($ap), %rax, %r15
++	 movq	64($bp,%rcx,8), %rdx
++	 movq	%rbx, 8+64-8(%rsp,%rcx,8)
++	adcx	%rax, %r14
++	adox	$zero, %r15
++	adcx	$zero, %r15		# cf=0
++
++	inc	%rcx			# of=0
++	jnz	.Loop_mulx
++
++	movq	%r8, %rbx
++	mulx	($ap), %rax, %r8
++	adcx	%rax, %rbx
++	adox	%r9, %r8
++
++	.byte	0xc4,0x62,0xfb,0xf6,0x8e,0x08,0x00,0x00,0x00	# mulx	8($ap), %rax, %r9
++	adcx	%rax, %r8
++	adox	%r10, %r9
++
++	.byte	0xc4,0x62,0xfb,0xf6,0x96,0x10,0x00,0x00,0x00	# mulx	16($ap), %rax, %r10
++	adcx	%rax, %r9
++	adox	%r11, %r10
++
++	mulx	24($ap), %rax, %r11
++	adcx	%rax, %r10
++	adox	%r12, %r11
++
++	mulx	32($ap), %rax, %r12
++	adcx	%rax, %r11
++	adox	%r13, %r12
++
++	mulx	40($ap), %rax, %r13
++	adcx	%rax, %r12
++	adox	%r14, %r13
++
++	.byte	0xc4,0x62,0xfb,0xf6,0xb6,0x30,0x00,0x00,0x00	# mulx	48($ap), %rax, %r14
++	adcx	%rax, %r13
++	adox	%r15, %r14
++
++	.byte	0xc4,0x62,0xfb,0xf6,0xbe,0x38,0x00,0x00,0x00	# mulx	56($ap), %rax, %r15
++	adcx	%rax, %r14
++	adox	$zero, %r15
++	adcx	$zero, %r15
++
++	mov	%rbx, 8+64-8(%rsp)
++	mov	%r8, 8+64(%rsp)
++	mov	%r9, 8+64+8(%rsp)
++	mov	%r10, 8+64+16(%rsp)
++	mov	%r11, 8+64+24(%rsp)
++	mov	%r12, 8+64+32(%rsp)
++	mov	%r13, 8+64+40(%rsp)
++	mov	%r14, 8+64+48(%rsp)
++	mov	%r15, 8+64+56(%rsp)
++
++	ret
++.size	__rsaz_512_mulx,.-__rsaz_512_mulx
++___
++}
++{
++my ($out,$inp,$power)= $win64 ? ("%rcx","%rdx","%r8d") : ("%rdi","%rsi","%edx");
++$code.=<<___;
++.globl	rsaz_512_scatter4
++.type	rsaz_512_scatter4,\@abi-omnipotent
++.align	16
++rsaz_512_scatter4:
++	leaq	($out,$power,8), $out
++	movl	\$8, %r9d
++	jmp	.Loop_scatter
++.align	16
++.Loop_scatter:
++	movq	($inp), %rax
++	leaq	8($inp), $inp
++	movq	%rax, ($out)
++	leaq	128($out), $out
++	decl	%r9d
++	jnz	.Loop_scatter
++	ret
++.size	rsaz_512_scatter4,.-rsaz_512_scatter4
++
++.globl	rsaz_512_gather4
++.type	rsaz_512_gather4,\@abi-omnipotent
++.align	16
++rsaz_512_gather4:
++___
++$code.=<<___	if ($win64);
++.LSEH_begin_rsaz_512_gather4:
++	.byte	0x48,0x81,0xec,0xa8,0x00,0x00,0x00	# sub    $0xa8,%rsp
++	.byte	0x0f,0x29,0x34,0x24			# movaps %xmm6,(%rsp)
++	.byte	0x0f,0x29,0x7c,0x24,0x10		# movaps %xmm7,0x10(%rsp)
++	.byte	0x44,0x0f,0x29,0x44,0x24,0x20		# movaps %xmm8,0x20(%rsp)
++	.byte	0x44,0x0f,0x29,0x4c,0x24,0x30		# movaps %xmm9,0x30(%rsp)
++	.byte	0x44,0x0f,0x29,0x54,0x24,0x40		# movaps %xmm10,0x40(%rsp)
++	.byte	0x44,0x0f,0x29,0x5c,0x24,0x50		# movaps %xmm11,0x50(%rsp)
++	.byte	0x44,0x0f,0x29,0x64,0x24,0x60		# movaps %xmm12,0x60(%rsp)
++	.byte	0x44,0x0f,0x29,0x6c,0x24,0x70		# movaps %xmm13,0x70(%rsp)
++	.byte	0x44,0x0f,0x29,0xb4,0x24,0x80,0,0,0	# movaps %xmm14,0x80(%rsp)
++	.byte	0x44,0x0f,0x29,0xbc,0x24,0x90,0,0,0	# movaps %xmm15,0x90(%rsp)
++___
++$code.=<<___;
++	movd	$power,%xmm8
++	movdqa	.Linc+16(%rip),%xmm1	# 00000002000000020000000200000002
++	movdqa	.Linc(%rip),%xmm0	# 00000001000000010000000000000000
++
++	pshufd	\$0,%xmm8,%xmm8		# broadcast $power
++	movdqa	%xmm1,%xmm7
++	movdqa	%xmm1,%xmm2
++___
++########################################################################
++# calculate mask by comparing 0..15 to $power
++#
++for($i=0;$i<4;$i++) {
++$code.=<<___;
++	paddd	%xmm`$i`,%xmm`$i+1`
++	pcmpeqd	%xmm8,%xmm`$i`
++	movdqa	%xmm7,%xmm`$i+3`
++___
++}
++for(;$i<7;$i++) {
++$code.=<<___;
++	paddd	%xmm`$i`,%xmm`$i+1`
++	pcmpeqd	%xmm8,%xmm`$i`
++___
++}
++$code.=<<___;
++	pcmpeqd	%xmm8,%xmm7
++	movl	\$8, %r9d
++	jmp	.Loop_gather
++.align	16
++.Loop_gather:
++	movdqa	16*0($inp),%xmm8
++	movdqa	16*1($inp),%xmm9
++	movdqa	16*2($inp),%xmm10
++	movdqa	16*3($inp),%xmm11
++	pand	%xmm0,%xmm8
++	movdqa	16*4($inp),%xmm12
++	pand	%xmm1,%xmm9
++	movdqa	16*5($inp),%xmm13
++	pand	%xmm2,%xmm10
++	movdqa	16*6($inp),%xmm14
++	pand	%xmm3,%xmm11
++	movdqa	16*7($inp),%xmm15
++	leaq	128($inp), $inp
++	pand	%xmm4,%xmm12
++	pand	%xmm5,%xmm13
++	pand	%xmm6,%xmm14
++	pand	%xmm7,%xmm15
++	por	%xmm10,%xmm8
++	por	%xmm11,%xmm9
++	por	%xmm12,%xmm8
++	por	%xmm13,%xmm9
++	por	%xmm14,%xmm8
++	por	%xmm15,%xmm9
++
++	por	%xmm9,%xmm8
++	pshufd	\$0x4e,%xmm8,%xmm9
++	por	%xmm9,%xmm8
++	movq	%xmm8,($out)
++	leaq	8($out), $out
++	decl	%r9d
++	jnz	.Loop_gather
++___
++$code.=<<___	if ($win64);
++	movaps	0x00(%rsp),%xmm6
++	movaps	0x10(%rsp),%xmm7
++	movaps	0x20(%rsp),%xmm8
++	movaps	0x30(%rsp),%xmm9
++	movaps	0x40(%rsp),%xmm10
++	movaps	0x50(%rsp),%xmm11
++	movaps	0x60(%rsp),%xmm12
++	movaps	0x70(%rsp),%xmm13
++	movaps	0x80(%rsp),%xmm14
++	movaps	0x90(%rsp),%xmm15
++	add	\$0xa8,%rsp
++___
++$code.=<<___;
++	ret
++.LSEH_end_rsaz_512_gather4:
++.size	rsaz_512_gather4,.-rsaz_512_gather4
++
++.align	64
++.Linc:
++	.long	0,0, 1,1
++	.long	2,2, 2,2
++___
++}
++
++# EXCEPTION_DISPOSITION handler (EXCEPTION_RECORD *rec,ULONG64 frame,
++#		CONTEXT *context,DISPATCHER_CONTEXT *disp)
++if ($win64) {
++$rec="%rcx";
++$frame="%rdx";
++$context="%r8";
++$disp="%r9";
++
++$code.=<<___;
++.extern	__imp_RtlVirtualUnwind
++.type	se_handler,\@abi-omnipotent
++.align	16
++se_handler:
++	push	%rsi
++	push	%rdi
++	push	%rbx
++	push	%rbp
++	push	%r12
++	push	%r13
++	push	%r14
++	push	%r15
++	pushfq
++	sub	\$64,%rsp
++
++	mov	120($context),%rax	# pull context->Rax
++	mov	248($context),%rbx	# pull context->Rip
++
++	mov	8($disp),%rsi		# disp->ImageBase
++	mov	56($disp),%r11		# disp->HandlerData
++
++	mov	0(%r11),%r10d		# HandlerData[0]
++	lea	(%rsi,%r10),%r10	# end of prologue label
++	cmp	%r10,%rbx		# context->RipRsp
++
++	mov	4(%r11),%r10d		# HandlerData[1]
++	lea	(%rsi,%r10),%r10	# epilogue label
++	cmp	%r10,%rbx		# context->Rip>=epilogue label
++	jae	.Lcommon_seh_tail
++
++	lea	128+24+48(%rax),%rax
++
++	lea	.Lmul_gather4_epilogue(%rip),%rbx
++	cmp	%r10,%rbx
++	jne	.Lse_not_in_mul_gather4
++
++	lea	0xb0(%rax),%rax
++
++	lea	-48-0xa8(%rax),%rsi
++	lea	512($context),%rdi
++	mov	\$20,%ecx
++	.long	0xa548f3fc		# cld; rep movsq
++
++.Lse_not_in_mul_gather4:
++	mov	-8(%rax),%rbx
++	mov	-16(%rax),%rbp
++	mov	-24(%rax),%r12
++	mov	-32(%rax),%r13
++	mov	-40(%rax),%r14
++	mov	-48(%rax),%r15
++	mov	%rbx,144($context)	# restore context->Rbx
++	mov	%rbp,160($context)	# restore context->Rbp
++	mov	%r12,216($context)	# restore context->R12
++	mov	%r13,224($context)	# restore context->R13
++	mov	%r14,232($context)	# restore context->R14
++	mov	%r15,240($context)	# restore context->R15
++
++.Lcommon_seh_tail:
++	mov	8(%rax),%rdi
++	mov	16(%rax),%rsi
++	mov	%rax,152($context)	# restore context->Rsp
++	mov	%rsi,168($context)	# restore context->Rsi
++	mov	%rdi,176($context)	# restore context->Rdi
++
++	mov	40($disp),%rdi		# disp->ContextRecord
++	mov	$context,%rsi		# context
++	mov	\$154,%ecx		# sizeof(CONTEXT)
++	.long	0xa548f3fc		# cld; rep movsq
++
++	mov	$disp,%rsi
++	xor	%rcx,%rcx		# arg1, UNW_FLAG_NHANDLER
++	mov	8(%rsi),%rdx		# arg2, disp->ImageBase
++	mov	0(%rsi),%r8		# arg3, disp->ControlPc
++	mov	16(%rsi),%r9		# arg4, disp->FunctionEntry
++	mov	40(%rsi),%r10		# disp->ContextRecord
++	lea	56(%rsi),%r11		# &disp->HandlerData
++	lea	24(%rsi),%r12		# &disp->EstablisherFrame
++	mov	%r10,32(%rsp)		# arg5
++	mov	%r11,40(%rsp)		# arg6
++	mov	%r12,48(%rsp)		# arg7
++	mov	%rcx,56(%rsp)		# arg8, (NULL)
++	call	*__imp_RtlVirtualUnwind(%rip)
++
++	mov	\$1,%eax		# ExceptionContinueSearch
++	add	\$64,%rsp
++	popfq
++	pop	%r15
++	pop	%r14
++	pop	%r13
++	pop	%r12
++	pop	%rbp
++	pop	%rbx
++	pop	%rdi
++	pop	%rsi
++	ret
++.size	se_handler,.-se_handler
++
++.section	.pdata
++.align	4
++	.rva	.LSEH_begin_rsaz_512_sqr
++	.rva	.LSEH_end_rsaz_512_sqr
++	.rva	.LSEH_info_rsaz_512_sqr
++
++	.rva	.LSEH_begin_rsaz_512_mul
++	.rva	.LSEH_end_rsaz_512_mul
++	.rva	.LSEH_info_rsaz_512_mul
++
++	.rva	.LSEH_begin_rsaz_512_mul_gather4
++	.rva	.LSEH_end_rsaz_512_mul_gather4
++	.rva	.LSEH_info_rsaz_512_mul_gather4
++
++	.rva	.LSEH_begin_rsaz_512_mul_scatter4
++	.rva	.LSEH_end_rsaz_512_mul_scatter4
++	.rva	.LSEH_info_rsaz_512_mul_scatter4
++
++	.rva	.LSEH_begin_rsaz_512_mul_by_one
++	.rva	.LSEH_end_rsaz_512_mul_by_one
++	.rva	.LSEH_info_rsaz_512_mul_by_one
++
++	.rva	.LSEH_begin_rsaz_512_gather4
++	.rva	.LSEH_end_rsaz_512_gather4
++	.rva	.LSEH_info_rsaz_512_gather4
++
++.section	.xdata
++.align	8
++.LSEH_info_rsaz_512_sqr:
++	.byte	9,0,0,0
++	.rva	se_handler
++	.rva	.Lsqr_body,.Lsqr_epilogue			# HandlerData[]
++.LSEH_info_rsaz_512_mul:
++	.byte	9,0,0,0
++	.rva	se_handler
++	.rva	.Lmul_body,.Lmul_epilogue			# HandlerData[]
++.LSEH_info_rsaz_512_mul_gather4:
++	.byte	9,0,0,0
++	.rva	se_handler
++	.rva	.Lmul_gather4_body,.Lmul_gather4_epilogue	# HandlerData[]
++.LSEH_info_rsaz_512_mul_scatter4:
++	.byte	9,0,0,0
++	.rva	se_handler
++	.rva	.Lmul_scatter4_body,.Lmul_scatter4_epilogue	# HandlerData[]
++.LSEH_info_rsaz_512_mul_by_one:
++	.byte	9,0,0,0
++	.rva	se_handler
++	.rva	.Lmul_by_one_body,.Lmul_by_one_epilogue		# HandlerData[]
++.LSEH_info_rsaz_512_gather4:
++	.byte	0x01,0x46,0x16,0x00
++	.byte	0x46,0xf8,0x09,0x00	# vmovaps 0x90(rsp),xmm15
++	.byte	0x3d,0xe8,0x08,0x00	# vmovaps 0x80(rsp),xmm14
++	.byte	0x34,0xd8,0x07,0x00	# vmovaps 0x70(rsp),xmm13
++	.byte	0x2e,0xc8,0x06,0x00	# vmovaps 0x60(rsp),xmm12
++	.byte	0x28,0xb8,0x05,0x00	# vmovaps 0x50(rsp),xmm11
++	.byte	0x22,0xa8,0x04,0x00	# vmovaps 0x40(rsp),xmm10
++	.byte	0x1c,0x98,0x03,0x00	# vmovaps 0x30(rsp),xmm9
++	.byte	0x16,0x88,0x02,0x00	# vmovaps 0x20(rsp),xmm8
++	.byte	0x10,0x78,0x01,0x00	# vmovaps 0x10(rsp),xmm7
++	.byte	0x0b,0x68,0x00,0x00	# vmovaps 0x00(rsp),xmm6
++	.byte	0x07,0x01,0x15,0x00	# sub     rsp,0xa8
++___
++}
++
++$code =~ s/\`([^\`]*)\`/eval $1/gem;
++print $code;
++close STDOUT;
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/bn/asm/s390x-gf2m.pl b/CryptoPkg/Library/OpensslLib/openssl/crypto/bn/asm/s390x-gf2m.pl
+new file mode 100644
+index 0000000..cbd16f4
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/bn/asm/s390x-gf2m.pl
+@@ -0,0 +1,228 @@
++#! /usr/bin/env perl
++# Copyright 2011-2016 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
++# in the file LICENSE in the source distribution or at
++# https://www.openssl.org/source/license.html
++
++#
++# ====================================================================
++# Written by Andy Polyakov  for the OpenSSL
++# project. The module is, however, dual licensed under OpenSSL and
++# CRYPTOGAMS licenses depending on where you obtain it. For further
++# details see http://www.openssl.org/~appro/cryptogams/.
++# ====================================================================
++#
++# May 2011
++#
++# The module implements bn_GF2m_mul_2x2 polynomial multiplication used
++# in bn_gf2m.c. It's kind of low-hanging mechanical port from C for
++# the time being... gcc 4.3 appeared to generate poor code, therefore
++# the effort. And indeed, the module delivers 55%-90%(*) improvement
++# on haviest ECDSA verify and ECDH benchmarks for 163- and 571-bit
++# key lengths on z990, 30%-55%(*) - on z10, and 70%-110%(*) - on z196.
++# This is for 64-bit build. In 32-bit "highgprs" case improvement is
++# even higher, for example on z990 it was measured 80%-150%. ECDSA
++# sign is modest 9%-12% faster. Keep in mind that these coefficients
++# are not ones for bn_GF2m_mul_2x2 itself, as not all CPU time is
++# burnt in it...
++#
++# (*)	gcc 4.1 was observed to deliver better results than gcc 4.3,
++#	so that improvement coefficients can vary from one specific
++#	setup to another.
++
++$flavour = shift;
++
++if ($flavour =~ /3[12]/) {
++        $SIZE_T=4;
++        $g="";
++} else {
++        $SIZE_T=8;
++        $g="g";
++}
++
++while (($output=shift) && ($output!~/\w[\w\-]*\.\w+$/)) {}
++open STDOUT,">$output";
++
++$stdframe=16*$SIZE_T+4*8;
++
++$rp="%r2";
++$a1="%r3";
++$a0="%r4";
++$b1="%r5";
++$b0="%r6";
++
++$ra="%r14";
++$sp="%r15";
++
++@T=("%r0","%r1");
++@i=("%r12","%r13");
++
++($a1,$a2,$a4,$a8,$a12,$a48)=map("%r$_",(6..11));
++($lo,$hi,$b)=map("%r$_",(3..5)); $a=$lo; $mask=$a8;
++
++$code.=<<___;
++.text
++
++.type	_mul_1x1,\@function
++.align	16
++_mul_1x1:
++	lgr	$a1,$a
++	sllg	$a2,$a,1
++	sllg	$a4,$a,2
++	sllg	$a8,$a,3
++
++	srag	$lo,$a1,63			# broadcast 63rd bit
++	nihh	$a1,0x1fff
++	srag	@i[0],$a2,63			# broadcast 62nd bit
++	nihh	$a2,0x3fff
++	srag	@i[1],$a4,63			# broadcast 61st bit
++	nihh	$a4,0x7fff
++	ngr	$lo,$b
++	ngr	@i[0],$b
++	ngr	@i[1],$b
++
++	lghi	@T[0],0
++	lgr	$a12,$a1
++	stg	@T[0],`$stdframe+0*8`($sp)	# tab[0]=0
++	xgr	$a12,$a2
++	stg	$a1,`$stdframe+1*8`($sp)	# tab[1]=a1
++	 lgr	$a48,$a4
++	stg	$a2,`$stdframe+2*8`($sp)	# tab[2]=a2
++	 xgr	$a48,$a8
++	stg	$a12,`$stdframe+3*8`($sp)	# tab[3]=a1^a2
++	 xgr	$a1,$a4
++
++	stg	$a4,`$stdframe+4*8`($sp)	# tab[4]=a4
++	xgr	$a2,$a4
++	stg	$a1,`$stdframe+5*8`($sp)	# tab[5]=a1^a4
++	xgr	$a12,$a4
++	stg	$a2,`$stdframe+6*8`($sp)	# tab[6]=a2^a4
++	 xgr	$a1,$a48
++	stg	$a12,`$stdframe+7*8`($sp)	# tab[7]=a1^a2^a4
++	 xgr	$a2,$a48
++
++	stg	$a8,`$stdframe+8*8`($sp)	# tab[8]=a8
++	xgr	$a12,$a48
++	stg	$a1,`$stdframe+9*8`($sp)	# tab[9]=a1^a8
++	 xgr	$a1,$a4
++	stg	$a2,`$stdframe+10*8`($sp)	# tab[10]=a2^a8
++	 xgr	$a2,$a4
++	stg	$a12,`$stdframe+11*8`($sp)	# tab[11]=a1^a2^a8
++
++	xgr	$a12,$a4
++	stg	$a48,`$stdframe+12*8`($sp)	# tab[12]=a4^a8
++	 srlg	$hi,$lo,1
++	stg	$a1,`$stdframe+13*8`($sp)	# tab[13]=a1^a4^a8
++	 sllg	$lo,$lo,63
++	stg	$a2,`$stdframe+14*8`($sp)	# tab[14]=a2^a4^a8
++	 srlg	@T[0],@i[0],2
++	stg	$a12,`$stdframe+15*8`($sp)	# tab[15]=a1^a2^a4^a8
++
++	lghi	$mask,`0xf<<3`
++	sllg	$a1,@i[0],62
++	 sllg	@i[0],$b,3
++	srlg	@T[1],@i[1],3
++	 ngr	@i[0],$mask
++	sllg	$a2,@i[1],61
++	 srlg	@i[1],$b,4-3
++	xgr	$hi,@T[0]
++	 ngr	@i[1],$mask
++	xgr	$lo,$a1
++	xgr	$hi,@T[1]
++	xgr	$lo,$a2
++
++	xg	$lo,$stdframe(@i[0],$sp)
++	srlg	@i[0],$b,8-3
++	ngr	@i[0],$mask
++___
++for($n=1;$n<14;$n++) {
++$code.=<<___;
++	lg	@T[1],$stdframe(@i[1],$sp)
++	srlg	@i[1],$b,`($n+2)*4`-3
++	sllg	@T[0],@T[1],`$n*4`
++	ngr	@i[1],$mask
++	srlg	@T[1],@T[1],`64-$n*4`
++	xgr	$lo,@T[0]
++	xgr	$hi,@T[1]
++___
++	push(@i,shift(@i)); push(@T,shift(@T));
++}
++$code.=<<___;
++	lg	@T[1],$stdframe(@i[1],$sp)
++	sllg	@T[0],@T[1],`$n*4`
++	srlg	@T[1],@T[1],`64-$n*4`
++	xgr	$lo,@T[0]
++	xgr	$hi,@T[1]
++
++	lg	@T[0],$stdframe(@i[0],$sp)
++	sllg	@T[1],@T[0],`($n+1)*4`
++	srlg	@T[0],@T[0],`64-($n+1)*4`
++	xgr	$lo,@T[1]
++	xgr	$hi,@T[0]
++
++	br	$ra
++.size	_mul_1x1,.-_mul_1x1
++
++.globl	bn_GF2m_mul_2x2
++.type	bn_GF2m_mul_2x2,\@function
++.align	16
++bn_GF2m_mul_2x2:
++	stm${g}	%r3,%r15,3*$SIZE_T($sp)
++
++	lghi	%r1,-$stdframe-128
++	la	%r0,0($sp)
++	la	$sp,0(%r1,$sp)			# alloca
++	st${g}	%r0,0($sp)			# back chain
++___
++if ($SIZE_T==8) {
++my @r=map("%r$_",(6..9));
++$code.=<<___;
++	bras	$ra,_mul_1x1			# a1·b1
++	stmg	$lo,$hi,16($rp)
++
++	lg	$a,`$stdframe+128+4*$SIZE_T`($sp)
++	lg	$b,`$stdframe+128+6*$SIZE_T`($sp)
++	bras	$ra,_mul_1x1			# a0·b0
++	stmg	$lo,$hi,0($rp)
++
++	lg	$a,`$stdframe+128+3*$SIZE_T`($sp)
++	lg	$b,`$stdframe+128+5*$SIZE_T`($sp)
++	xg	$a,`$stdframe+128+4*$SIZE_T`($sp)
++	xg	$b,`$stdframe+128+6*$SIZE_T`($sp)
++	bras	$ra,_mul_1x1			# (a0+a1)·(b0+b1)
++	lmg	@r[0],@r[3],0($rp)
++
++	xgr	$lo,$hi
++	xgr	$hi,@r[1]
++	xgr	$lo,@r[0]
++	xgr	$hi,@r[2]
++	xgr	$lo,@r[3]	
++	xgr	$hi,@r[3]
++	xgr	$lo,$hi
++	stg	$hi,16($rp)
++	stg	$lo,8($rp)
++___
++} else {
++$code.=<<___;
++	sllg	%r3,%r3,32
++	sllg	%r5,%r5,32
++	or	%r3,%r4
++	or	%r5,%r6
++	bras	$ra,_mul_1x1
++	rllg	$lo,$lo,32
++	rllg	$hi,$hi,32
++	stmg	$lo,$hi,0($rp)
++___
++}
++$code.=<<___;
++	lm${g}	%r6,%r15,`$stdframe+128+6*$SIZE_T`($sp)
++	br	$ra
++.size	bn_GF2m_mul_2x2,.-bn_GF2m_mul_2x2
++.string	"GF(2^m) Multiplication for s390x, CRYPTOGAMS by "
++___
++
++$code =~ s/\`([^\`]*)\`/eval($1)/gem;
++print $code;
++close STDOUT;
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/bn/asm/s390x-mont.pl b/CryptoPkg/Library/OpensslLib/openssl/crypto/bn/asm/s390x-mont.pl
+new file mode 100644
+index 0000000..2205bc2
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/bn/asm/s390x-mont.pl
+@@ -0,0 +1,284 @@
++#! /usr/bin/env perl
++# Copyright 2007-2016 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
++# in the file LICENSE in the source distribution or at
++# https://www.openssl.org/source/license.html
++
++
++# ====================================================================
++# Written by Andy Polyakov  for the OpenSSL
++# project. The module is, however, dual licensed under OpenSSL and
++# CRYPTOGAMS licenses depending on where you obtain it. For further
++# details see http://www.openssl.org/~appro/cryptogams/.
++# ====================================================================
++
++# April 2007.
++#
++# Performance improvement over vanilla C code varies from 85% to 45%
++# depending on key length and benchmark. Unfortunately in this context
++# these are not very impressive results [for code that utilizes "wide"
++# 64x64=128-bit multiplication, which is not commonly available to C
++# programmers], at least hand-coded bn_asm.c replacement is known to
++# provide 30-40% better results for longest keys. Well, on a second
++# thought it's not very surprising, because z-CPUs are single-issue
++# and _strictly_ in-order execution, while bn_mul_mont is more or less
++# dependent on CPU ability to pipe-line instructions and have several
++# of them "in-flight" at the same time. I mean while other methods,
++# for example Karatsuba, aim to minimize amount of multiplications at
++# the cost of other operations increase, bn_mul_mont aim to neatly
++# "overlap" multiplications and the other operations [and on most
++# platforms even minimize the amount of the other operations, in
++# particular references to memory]. But it's possible to improve this
++# module performance by implementing dedicated squaring code-path and
++# possibly by unrolling loops...
++
++# January 2009.
++#
++# Reschedule to minimize/avoid Address Generation Interlock hazard,
++# make inner loops counter-based.
++
++# November 2010.
++#
++# Adapt for -m31 build. If kernel supports what's called "highgprs"
++# feature on Linux [see /proc/cpuinfo], it's possible to use 64-bit
++# instructions and achieve "64-bit" performance even in 31-bit legacy
++# application context. The feature is not specific to any particular
++# processor, as long as it's "z-CPU". Latter implies that the code
++# remains z/Architecture specific. Compatibility with 32-bit BN_ULONG
++# is achieved by swapping words after 64-bit loads, follow _dswap-s.
++# On z990 it was measured to perform 2.6-2.2 times better than
++# compiler-generated code, less for longer keys...
++
++$flavour = shift;
++
++if ($flavour =~ /3[12]/) {
++	$SIZE_T=4;
++	$g="";
++} else {
++	$SIZE_T=8;
++	$g="g";
++}
++
++while (($output=shift) && ($output!~/\w[\w\-]*\.\w+$/)) {}
++open STDOUT,">$output";
++
++$stdframe=16*$SIZE_T+4*8;
++
++$mn0="%r0";
++$num="%r1";
++
++# int bn_mul_mont(
++$rp="%r2";		# BN_ULONG *rp,
++$ap="%r3";		# const BN_ULONG *ap,
++$bp="%r4";		# const BN_ULONG *bp,
++$np="%r5";		# const BN_ULONG *np,
++$n0="%r6";		# const BN_ULONG *n0,
++#$num="160(%r15)"	# int num);
++
++$bi="%r2";	# zaps rp
++$j="%r7";
++
++$ahi="%r8";
++$alo="%r9";
++$nhi="%r10";
++$nlo="%r11";
++$AHI="%r12";
++$NHI="%r13";
++$count="%r14";
++$sp="%r15";
++
++$code.=<<___;
++.text
++.globl	bn_mul_mont
++.type	bn_mul_mont,\@function
++bn_mul_mont:
++	lgf	$num,`$stdframe+$SIZE_T-4`($sp)	# pull $num
++	sla	$num,`log($SIZE_T)/log(2)`	# $num to enumerate bytes
++	la	$bp,0($num,$bp)
++
++	st${g}	%r2,2*$SIZE_T($sp)
++
++	cghi	$num,16		#
++	lghi	%r2,0		#
++	blr	%r14		# if($num<16) return 0;
++___
++$code.=<<___ if ($flavour =~ /3[12]/);
++	tmll	$num,4
++	bnzr	%r14		# if ($num&1) return 0;
++___
++$code.=<<___ if ($flavour !~ /3[12]/);
++	cghi	$num,96		#
++	bhr	%r14		# if($num>96) return 0;
++___
++$code.=<<___;
++	stm${g}	%r3,%r15,3*$SIZE_T($sp)
++
++	lghi	$rp,-$stdframe-8	# leave room for carry bit
++	lcgr	$j,$num		# -$num
++	lgr	%r0,$sp
++	la	$rp,0($rp,$sp)
++	la	$sp,0($j,$rp)	# alloca
++	st${g}	%r0,0($sp)	# back chain
++
++	sra	$num,3		# restore $num
++	la	$bp,0($j,$bp)	# restore $bp
++	ahi	$num,-1		# adjust $num for inner loop
++	lg	$n0,0($n0)	# pull n0
++	_dswap	$n0
++
++	lg	$bi,0($bp)
++	_dswap	$bi
++	lg	$alo,0($ap)
++	_dswap	$alo
++	mlgr	$ahi,$bi	# ap[0]*bp[0]
++	lgr	$AHI,$ahi
++
++	lgr	$mn0,$alo	# "tp[0]"*n0
++	msgr	$mn0,$n0
++
++	lg	$nlo,0($np)	#
++	_dswap	$nlo
++	mlgr	$nhi,$mn0	# np[0]*m1
++	algr	$nlo,$alo	# +="tp[0]"
++	lghi	$NHI,0
++	alcgr	$NHI,$nhi
++
++	la	$j,8(%r0)	# j=1
++	lr	$count,$num
++
++.align	16
++.L1st:
++	lg	$alo,0($j,$ap)
++	_dswap	$alo
++	mlgr	$ahi,$bi	# ap[j]*bp[0]
++	algr	$alo,$AHI
++	lghi	$AHI,0
++	alcgr	$AHI,$ahi
++
++	lg	$nlo,0($j,$np)
++	_dswap	$nlo
++	mlgr	$nhi,$mn0	# np[j]*m1
++	algr	$nlo,$NHI
++	lghi	$NHI,0
++	alcgr	$nhi,$NHI	# +="tp[j]"
++	algr	$nlo,$alo
++	alcgr	$NHI,$nhi
++
++	stg	$nlo,$stdframe-8($j,$sp)	# tp[j-1]=
++	la	$j,8($j)	# j++
++	brct	$count,.L1st
++
++	algr	$NHI,$AHI
++	lghi	$AHI,0
++	alcgr	$AHI,$AHI	# upmost overflow bit
++	stg	$NHI,$stdframe-8($j,$sp)
++	stg	$AHI,$stdframe($j,$sp)
++	la	$bp,8($bp)	# bp++
++
++.Louter:
++	lg	$bi,0($bp)	# bp[i]
++	_dswap	$bi
++	lg	$alo,0($ap)
++	_dswap	$alo
++	mlgr	$ahi,$bi	# ap[0]*bp[i]
++	alg	$alo,$stdframe($sp)	# +=tp[0]
++	lghi	$AHI,0
++	alcgr	$AHI,$ahi
++
++	lgr	$mn0,$alo
++	msgr	$mn0,$n0	# tp[0]*n0
++
++	lg	$nlo,0($np)	# np[0]
++	_dswap	$nlo
++	mlgr	$nhi,$mn0	# np[0]*m1
++	algr	$nlo,$alo	# +="tp[0]"
++	lghi	$NHI,0
++	alcgr	$NHI,$nhi
++
++	la	$j,8(%r0)	# j=1
++	lr	$count,$num
++
++.align	16
++.Linner:
++	lg	$alo,0($j,$ap)
++	_dswap	$alo
++	mlgr	$ahi,$bi	# ap[j]*bp[i]
++	algr	$alo,$AHI
++	lghi	$AHI,0
++	alcgr	$ahi,$AHI
++	alg	$alo,$stdframe($j,$sp)# +=tp[j]
++	alcgr	$AHI,$ahi
++
++	lg	$nlo,0($j,$np)
++	_dswap	$nlo
++	mlgr	$nhi,$mn0	# np[j]*m1
++	algr	$nlo,$NHI
++	lghi	$NHI,0
++	alcgr	$nhi,$NHI
++	algr	$nlo,$alo	# +="tp[j]"
++	alcgr	$NHI,$nhi
++
++	stg	$nlo,$stdframe-8($j,$sp)	# tp[j-1]=
++	la	$j,8($j)	# j++
++	brct	$count,.Linner
++
++	algr	$NHI,$AHI
++	lghi	$AHI,0
++	alcgr	$AHI,$AHI
++	alg	$NHI,$stdframe($j,$sp)# accumulate previous upmost overflow bit
++	lghi	$ahi,0
++	alcgr	$AHI,$ahi	# new upmost overflow bit
++	stg	$NHI,$stdframe-8($j,$sp)
++	stg	$AHI,$stdframe($j,$sp)
++
++	la	$bp,8($bp)	# bp++
++	cl${g}	$bp,`$stdframe+8+4*$SIZE_T`($j,$sp)	# compare to &bp[num]
++	jne	.Louter
++
++	l${g}	$rp,`$stdframe+8+2*$SIZE_T`($j,$sp)	# reincarnate rp
++	la	$ap,$stdframe($sp)
++	ahi	$num,1		# restore $num, incidentally clears "borrow"
++
++	la	$j,0(%r0)
++	lr	$count,$num
++.Lsub:	lg	$alo,0($j,$ap)
++	lg	$nlo,0($j,$np)
++	_dswap	$nlo
++	slbgr	$alo,$nlo
++	stg	$alo,0($j,$rp)
++	la	$j,8($j)
++	brct	$count,.Lsub
++	lghi	$ahi,0
++	slbgr	$AHI,$ahi	# handle upmost carry
++
++	ngr	$ap,$AHI
++	lghi	$np,-1
++	xgr	$np,$AHI
++	ngr	$np,$rp
++	ogr	$ap,$np		# ap=borrow?tp:rp
++
++	la	$j,0(%r0)
++	lgr	$count,$num
++.Lcopy:	lg	$alo,0($j,$ap)		# copy or in-place refresh
++	_dswap	$alo
++	stg	$j,$stdframe($j,$sp)	# zap tp
++	stg	$alo,0($j,$rp)
++	la	$j,8($j)
++	brct	$count,.Lcopy
++
++	la	%r1,`$stdframe+8+6*$SIZE_T`($j,$sp)
++	lm${g}	%r6,%r15,0(%r1)
++	lghi	%r2,1		# signal "processed"
++	br	%r14
++.size	bn_mul_mont,.-bn_mul_mont
++.string	"Montgomery Multiplication for s390x, CRYPTOGAMS by "
++___
++
++foreach (split("\n",$code)) {
++	s/\`([^\`]*)\`/eval $1/ge;
++	s/_dswap\s+(%r[0-9]+)/sprintf("rllg\t%s,%s,32",$1,$1) if($SIZE_T==4)/e;
++	print $_,"\n";
++}
++close STDOUT;
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/bn/asm/s390x.S b/CryptoPkg/Library/OpensslLib/openssl/crypto/bn/asm/s390x.S
+new file mode 100755
+index 0000000..292a7a9
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/bn/asm/s390x.S
+@@ -0,0 +1,713 @@
++.ident "s390x.S, version 1.1"
++// ====================================================================
++// Copyright 2007-2016 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
++// in the file LICENSE in the source distribution or at
++// https://www.openssl.org/source/license.html
++// ====================================================================
++
++.text
++
++#define zero	%r0
++
++// BN_ULONG bn_mul_add_words(BN_ULONG *r2,BN_ULONG *r3,int r4,BN_ULONG r5);
++.globl	bn_mul_add_words
++.type	bn_mul_add_words,@function
++.align	4
++bn_mul_add_words:
++	lghi	zero,0		// zero = 0
++	la	%r1,0(%r2)	// put rp aside [to give way to]
++	lghi	%r2,0		// return value
++	ltgfr	%r4,%r4
++	bler	%r14		// if (len<=0) return 0;
++
++	stmg	%r6,%r13,48(%r15)
++	lghi	%r2,3
++	lghi	%r12,0		// carry = 0
++	slgr	%r1,%r3		// rp-=ap
++	nr	%r2,%r4		// len%4
++	sra	%r4,2		// cnt=len/4
++	jz	.Loop1_madd	// carry is incidentally cleared if branch taken
++	algr	zero,zero	// clear carry
++
++	lg	%r7,0(%r3)	// ap[0]
++	lg	%r9,8(%r3)	// ap[1]
++	mlgr	%r6,%r5		// *=w
++	brct	%r4,.Loop4_madd
++	j	.Loop4_madd_tail
++
++.Loop4_madd:
++	mlgr	%r8,%r5
++	lg	%r11,16(%r3)	// ap[i+2]
++	alcgr	%r7,%r12	// +=carry
++	alcgr	%r6,zero
++	alg	%r7,0(%r3,%r1)	// +=rp[i]
++	stg	%r7,0(%r3,%r1)	// rp[i]=
++
++	mlgr	%r10,%r5
++	lg	%r13,24(%r3)
++	alcgr	%r9,%r6
++	alcgr	%r8,zero
++	alg	%r9,8(%r3,%r1)
++	stg	%r9,8(%r3,%r1)
++
++	mlgr	%r12,%r5
++	lg	%r7,32(%r3)
++	alcgr	%r11,%r8
++	alcgr	%r10,zero
++	alg	%r11,16(%r3,%r1)
++	stg	%r11,16(%r3,%r1)
++
++	mlgr	%r6,%r5
++	lg	%r9,40(%r3)
++	alcgr	%r13,%r10
++	alcgr	%r12,zero
++	alg	%r13,24(%r3,%r1)
++	stg	%r13,24(%r3,%r1)
++
++	la	%r3,32(%r3)	// i+=4
++	brct	%r4,.Loop4_madd
++
++.Loop4_madd_tail:
++	mlgr	%r8,%r5
++	lg	%r11,16(%r3)
++	alcgr	%r7,%r12	// +=carry
++	alcgr	%r6,zero
++	alg	%r7,0(%r3,%r1)	// +=rp[i]
++	stg	%r7,0(%r3,%r1)	// rp[i]=
++
++	mlgr	%r10,%r5
++	lg	%r13,24(%r3)
++	alcgr	%r9,%r6
++	alcgr	%r8,zero
++	alg	%r9,8(%r3,%r1)
++	stg	%r9,8(%r3,%r1)
++
++	mlgr	%r12,%r5
++	alcgr	%r11,%r8
++	alcgr	%r10,zero
++	alg	%r11,16(%r3,%r1)
++	stg	%r11,16(%r3,%r1)
++
++	alcgr	%r13,%r10
++	alcgr	%r12,zero
++	alg	%r13,24(%r3,%r1)
++	stg	%r13,24(%r3,%r1)
++
++	la	%r3,32(%r3)	// i+=4
++
++	la	%r2,1(%r2)	// see if len%4 is zero ...
++	brct	%r2,.Loop1_madd	// without touching condition code:-)
++
++.Lend_madd:
++	lgr	%r2,zero	// return value
++	alcgr	%r2,%r12	// collect even carry bit
++	lmg	%r6,%r13,48(%r15)
++	br	%r14
++
++.Loop1_madd:
++	lg	%r7,0(%r3)	// ap[i]
++	mlgr	%r6,%r5		// *=w
++	alcgr	%r7,%r12	// +=carry
++	alcgr	%r6,zero
++	alg	%r7,0(%r3,%r1)	// +=rp[i]
++	stg	%r7,0(%r3,%r1)	// rp[i]=
++
++	lgr	%r12,%r6
++	la	%r3,8(%r3)	// i++
++	brct	%r2,.Loop1_madd
++
++	j	.Lend_madd
++.size	bn_mul_add_words,.-bn_mul_add_words
++
++// BN_ULONG bn_mul_words(BN_ULONG *r2,BN_ULONG *r3,int r4,BN_ULONG r5);
++.globl	bn_mul_words
++.type	bn_mul_words,@function
++.align	4
++bn_mul_words:
++	lghi	zero,0		// zero = 0
++	la	%r1,0(%r2)	// put rp aside
++	lghi	%r2,0		// i=0;
++	ltgfr	%r4,%r4
++	bler	%r14		// if (len<=0) return 0;
++
++	stmg	%r6,%r10,48(%r15)
++	lghi	%r10,3
++	lghi	%r8,0		// carry = 0
++	nr	%r10,%r4	// len%4
++	sra	%r4,2		// cnt=len/4
++	jz	.Loop1_mul	// carry is incidentally cleared if branch taken
++	algr	zero,zero	// clear carry
++
++.Loop4_mul:
++	lg	%r7,0(%r2,%r3)	// ap[i]
++	mlgr	%r6,%r5		// *=w
++	alcgr	%r7,%r8		// +=carry
++	stg	%r7,0(%r2,%r1)	// rp[i]=
++
++	lg	%r9,8(%r2,%r3)
++	mlgr	%r8,%r5
++	alcgr	%r9,%r6
++	stg	%r9,8(%r2,%r1)
++
++	lg	%r7,16(%r2,%r3)
++	mlgr	%r6,%r5
++	alcgr	%r7,%r8
++	stg	%r7,16(%r2,%r1)
++
++	lg	%r9,24(%r2,%r3)
++	mlgr	%r8,%r5
++	alcgr	%r9,%r6
++	stg	%r9,24(%r2,%r1)
++
++	la	%r2,32(%r2)	// i+=4
++	brct	%r4,.Loop4_mul
++
++	la	%r10,1(%r10)		// see if len%4 is zero ...
++	brct	%r10,.Loop1_mul		// without touching condition code:-)
++
++.Lend_mul:
++	alcgr	%r8,zero	// collect carry bit
++	lgr	%r2,%r8
++	lmg	%r6,%r10,48(%r15)
++	br	%r14
++
++.Loop1_mul:
++	lg	%r7,0(%r2,%r3)	// ap[i]
++	mlgr	%r6,%r5		// *=w
++	alcgr	%r7,%r8		// +=carry
++	stg	%r7,0(%r2,%r1)	// rp[i]=
++
++	lgr	%r8,%r6
++	la	%r2,8(%r2)	// i++
++	brct	%r10,.Loop1_mul
++
++	j	.Lend_mul
++.size	bn_mul_words,.-bn_mul_words
++
++// void bn_sqr_words(BN_ULONG *r2,BN_ULONG *r2,int r4)
++.globl	bn_sqr_words
++.type	bn_sqr_words,@function
++.align	4
++bn_sqr_words:
++	ltgfr	%r4,%r4
++	bler	%r14
++
++	stmg	%r6,%r7,48(%r15)
++	srag	%r1,%r4,2	// cnt=len/4
++	jz	.Loop1_sqr
++
++.Loop4_sqr:
++	lg	%r7,0(%r3)
++	mlgr	%r6,%r7
++	stg	%r7,0(%r2)
++	stg	%r6,8(%r2)
++
++	lg	%r7,8(%r3)
++	mlgr	%r6,%r7
++	stg	%r7,16(%r2)
++	stg	%r6,24(%r2)
++
++	lg	%r7,16(%r3)
++	mlgr	%r6,%r7
++	stg	%r7,32(%r2)
++	stg	%r6,40(%r2)
++
++	lg	%r7,24(%r3)
++	mlgr	%r6,%r7
++	stg	%r7,48(%r2)
++	stg	%r6,56(%r2)
++
++	la	%r3,32(%r3)
++	la	%r2,64(%r2)
++	brct	%r1,.Loop4_sqr
++
++	lghi	%r1,3
++	nr	%r4,%r1		// cnt=len%4
++	jz	.Lend_sqr
++
++.Loop1_sqr:
++	lg	%r7,0(%r3)
++	mlgr	%r6,%r7
++	stg	%r7,0(%r2)
++	stg	%r6,8(%r2)
++
++	la	%r3,8(%r3)
++	la	%r2,16(%r2)
++	brct	%r4,.Loop1_sqr
++
++.Lend_sqr:
++	lmg	%r6,%r7,48(%r15)
++	br	%r14
++.size	bn_sqr_words,.-bn_sqr_words
++
++// BN_ULONG bn_div_words(BN_ULONG h,BN_ULONG l,BN_ULONG d);
++.globl	bn_div_words
++.type	bn_div_words,@function
++.align	4
++bn_div_words:
++	dlgr	%r2,%r4
++	lgr	%r2,%r3
++	br	%r14
++.size	bn_div_words,.-bn_div_words
++
++// BN_ULONG bn_add_words(BN_ULONG *r2,BN_ULONG *r3,BN_ULONG *r4,int r5);
++.globl	bn_add_words
++.type	bn_add_words,@function
++.align	4
++bn_add_words:
++	la	%r1,0(%r2)	// put rp aside
++	lghi	%r2,0		// i=0
++	ltgfr	%r5,%r5
++	bler	%r14		// if (len<=0) return 0;
++
++	stg	%r6,48(%r15)
++	lghi	%r6,3
++	nr	%r6,%r5		// len%4
++	sra	%r5,2		// len/4, use sra because it sets condition code
++	jz	.Loop1_add	// carry is incidentally cleared if branch taken
++	algr	%r2,%r2		// clear carry
++
++.Loop4_add:
++	lg	%r0,0(%r2,%r3)
++	alcg	%r0,0(%r2,%r4)
++	stg	%r0,0(%r2,%r1)
++	lg	%r0,8(%r2,%r3)
++	alcg	%r0,8(%r2,%r4)
++	stg	%r0,8(%r2,%r1)
++	lg	%r0,16(%r2,%r3)
++	alcg	%r0,16(%r2,%r4)
++	stg	%r0,16(%r2,%r1)
++	lg	%r0,24(%r2,%r3)
++	alcg	%r0,24(%r2,%r4)
++	stg	%r0,24(%r2,%r1)
++
++	la	%r2,32(%r2)	// i+=4
++	brct	%r5,.Loop4_add
++
++	la	%r6,1(%r6)	// see if len%4 is zero ...
++	brct	%r6,.Loop1_add	// without touching condition code:-)
++
++.Lexit_add:
++	lghi	%r2,0
++	alcgr	%r2,%r2
++	lg	%r6,48(%r15)
++	br	%r14
++
++.Loop1_add:
++	lg	%r0,0(%r2,%r3)
++	alcg	%r0,0(%r2,%r4)
++	stg	%r0,0(%r2,%r1)
++
++	la	%r2,8(%r2)	// i++
++	brct	%r6,.Loop1_add
++
++	j	.Lexit_add
++.size	bn_add_words,.-bn_add_words
++
++// BN_ULONG bn_sub_words(BN_ULONG *r2,BN_ULONG *r3,BN_ULONG *r4,int r5);
++.globl	bn_sub_words
++.type	bn_sub_words,@function
++.align	4
++bn_sub_words:
++	la	%r1,0(%r2)	// put rp aside
++	lghi	%r2,0		// i=0
++	ltgfr	%r5,%r5
++	bler	%r14		// if (len<=0) return 0;
++
++	stg	%r6,48(%r15)
++	lghi	%r6,3
++	nr	%r6,%r5		// len%4
++	sra	%r5,2		// len/4, use sra because it sets condition code
++	jnz	.Loop4_sub	// borrow is incidentally cleared if branch taken
++	slgr	%r2,%r2		// clear borrow
++
++.Loop1_sub:
++	lg	%r0,0(%r2,%r3)
++	slbg	%r0,0(%r2,%r4)
++	stg	%r0,0(%r2,%r1)
++
++	la	%r2,8(%r2)	// i++
++	brct	%r6,.Loop1_sub
++	j	.Lexit_sub
++
++.Loop4_sub:
++	lg	%r0,0(%r2,%r3)
++	slbg	%r0,0(%r2,%r4)
++	stg	%r0,0(%r2,%r1)
++	lg	%r0,8(%r2,%r3)
++	slbg	%r0,8(%r2,%r4)
++	stg	%r0,8(%r2,%r1)
++	lg	%r0,16(%r2,%r3)
++	slbg	%r0,16(%r2,%r4)
++	stg	%r0,16(%r2,%r1)
++	lg	%r0,24(%r2,%r3)
++	slbg	%r0,24(%r2,%r4)
++	stg	%r0,24(%r2,%r1)
++
++	la	%r2,32(%r2)	// i+=4
++	brct	%r5,.Loop4_sub
++
++	la	%r6,1(%r6)	// see if len%4 is zero ...
++	brct	%r6,.Loop1_sub	// without touching condition code:-)
++
++.Lexit_sub:
++	lghi	%r2,0
++	slbgr	%r2,%r2
++	lcgr	%r2,%r2
++	lg	%r6,48(%r15)
++	br	%r14
++.size	bn_sub_words,.-bn_sub_words
++
++#define c1	%r1
++#define c2	%r5
++#define c3	%r8
++
++#define mul_add_c(ai,bi,c1,c2,c3)	\
++	lg	%r7,ai*8(%r3);		\
++	mlg	%r6,bi*8(%r4);		\
++	algr	c1,%r7;			\
++	alcgr	c2,%r6;			\
++	alcgr	c3,zero
++
++// void bn_mul_comba8(BN_ULONG *r2,BN_ULONG *r3,BN_ULONG *r4);
++.globl	bn_mul_comba8
++.type	bn_mul_comba8,@function
++.align	4
++bn_mul_comba8:
++	stmg	%r6,%r8,48(%r15)
++
++	lghi	c1,0
++	lghi	c2,0
++	lghi	c3,0
++	lghi	zero,0
++
++	mul_add_c(0,0,c1,c2,c3);
++	stg	c1,0*8(%r2)
++	lghi	c1,0
++
++	mul_add_c(0,1,c2,c3,c1);
++	mul_add_c(1,0,c2,c3,c1);
++	stg	c2,1*8(%r2)
++	lghi	c2,0
++
++	mul_add_c(2,0,c3,c1,c2);
++	mul_add_c(1,1,c3,c1,c2);
++	mul_add_c(0,2,c3,c1,c2);
++	stg	c3,2*8(%r2)
++	lghi	c3,0
++
++	mul_add_c(0,3,c1,c2,c3);
++	mul_add_c(1,2,c1,c2,c3);
++	mul_add_c(2,1,c1,c2,c3);
++	mul_add_c(3,0,c1,c2,c3);
++	stg	c1,3*8(%r2)
++	lghi	c1,0
++
++	mul_add_c(4,0,c2,c3,c1);
++	mul_add_c(3,1,c2,c3,c1);
++	mul_add_c(2,2,c2,c3,c1);
++	mul_add_c(1,3,c2,c3,c1);
++	mul_add_c(0,4,c2,c3,c1);
++	stg	c2,4*8(%r2)
++	lghi	c2,0
++
++	mul_add_c(0,5,c3,c1,c2);
++	mul_add_c(1,4,c3,c1,c2);
++	mul_add_c(2,3,c3,c1,c2);
++	mul_add_c(3,2,c3,c1,c2);
++	mul_add_c(4,1,c3,c1,c2);
++	mul_add_c(5,0,c3,c1,c2);
++	stg	c3,5*8(%r2)
++	lghi	c3,0
++
++	mul_add_c(6,0,c1,c2,c3);
++	mul_add_c(5,1,c1,c2,c3);
++	mul_add_c(4,2,c1,c2,c3);
++	mul_add_c(3,3,c1,c2,c3);
++	mul_add_c(2,4,c1,c2,c3);
++	mul_add_c(1,5,c1,c2,c3);
++	mul_add_c(0,6,c1,c2,c3);
++	stg	c1,6*8(%r2)
++	lghi	c1,0
++
++	mul_add_c(0,7,c2,c3,c1);
++	mul_add_c(1,6,c2,c3,c1);
++	mul_add_c(2,5,c2,c3,c1);
++	mul_add_c(3,4,c2,c3,c1);
++	mul_add_c(4,3,c2,c3,c1);
++	mul_add_c(5,2,c2,c3,c1);
++	mul_add_c(6,1,c2,c3,c1);
++	mul_add_c(7,0,c2,c3,c1);
++	stg	c2,7*8(%r2)
++	lghi	c2,0
++
++	mul_add_c(7,1,c3,c1,c2);
++	mul_add_c(6,2,c3,c1,c2);
++	mul_add_c(5,3,c3,c1,c2);
++	mul_add_c(4,4,c3,c1,c2);
++	mul_add_c(3,5,c3,c1,c2);
++	mul_add_c(2,6,c3,c1,c2);
++	mul_add_c(1,7,c3,c1,c2);
++	stg	c3,8*8(%r2)
++	lghi	c3,0
++
++	mul_add_c(2,7,c1,c2,c3);
++	mul_add_c(3,6,c1,c2,c3);
++	mul_add_c(4,5,c1,c2,c3);
++	mul_add_c(5,4,c1,c2,c3);
++	mul_add_c(6,3,c1,c2,c3);
++	mul_add_c(7,2,c1,c2,c3);
++	stg	c1,9*8(%r2)
++	lghi	c1,0
++
++	mul_add_c(7,3,c2,c3,c1);
++	mul_add_c(6,4,c2,c3,c1);
++	mul_add_c(5,5,c2,c3,c1);
++	mul_add_c(4,6,c2,c3,c1);
++	mul_add_c(3,7,c2,c3,c1);
++	stg	c2,10*8(%r2)
++	lghi	c2,0
++
++	mul_add_c(4,7,c3,c1,c2);
++	mul_add_c(5,6,c3,c1,c2);
++	mul_add_c(6,5,c3,c1,c2);
++	mul_add_c(7,4,c3,c1,c2);
++	stg	c3,11*8(%r2)
++	lghi	c3,0
++
++	mul_add_c(7,5,c1,c2,c3);
++	mul_add_c(6,6,c1,c2,c3);
++	mul_add_c(5,7,c1,c2,c3);
++	stg	c1,12*8(%r2)
++	lghi	c1,0
++
++
++	mul_add_c(6,7,c2,c3,c1);
++	mul_add_c(7,6,c2,c3,c1);
++	stg	c2,13*8(%r2)
++	lghi	c2,0
++
++	mul_add_c(7,7,c3,c1,c2);
++	stg	c3,14*8(%r2)
++	stg	c1,15*8(%r2)
++
++	lmg	%r6,%r8,48(%r15)
++	br	%r14
++.size	bn_mul_comba8,.-bn_mul_comba8
++
++// void bn_mul_comba4(BN_ULONG *r2,BN_ULONG *r3,BN_ULONG *r4);
++.globl	bn_mul_comba4
++.type	bn_mul_comba4,@function
++.align	4
++bn_mul_comba4:
++	stmg	%r6,%r8,48(%r15)
++
++	lghi	c1,0
++	lghi	c2,0
++	lghi	c3,0
++	lghi	zero,0
++
++	mul_add_c(0,0,c1,c2,c3);
++	stg	c1,0*8(%r3)
++	lghi	c1,0
++
++	mul_add_c(0,1,c2,c3,c1);
++	mul_add_c(1,0,c2,c3,c1);
++	stg	c2,1*8(%r2)
++	lghi	c2,0
++
++	mul_add_c(2,0,c3,c1,c2);
++	mul_add_c(1,1,c3,c1,c2);
++	mul_add_c(0,2,c3,c1,c2);
++	stg	c3,2*8(%r2)
++	lghi	c3,0
++
++	mul_add_c(0,3,c1,c2,c3);
++	mul_add_c(1,2,c1,c2,c3);
++	mul_add_c(2,1,c1,c2,c3);
++	mul_add_c(3,0,c1,c2,c3);
++	stg	c1,3*8(%r2)
++	lghi	c1,0
++
++	mul_add_c(3,1,c2,c3,c1);
++	mul_add_c(2,2,c2,c3,c1);
++	mul_add_c(1,3,c2,c3,c1);
++	stg	c2,4*8(%r2)
++	lghi	c2,0
++
++	mul_add_c(2,3,c3,c1,c2);
++	mul_add_c(3,2,c3,c1,c2);
++	stg	c3,5*8(%r2)
++	lghi	c3,0
++
++	mul_add_c(3,3,c1,c2,c3);
++	stg	c1,6*8(%r2)
++	stg	c2,7*8(%r2)
++
++	stmg	%r6,%r8,48(%r15)
++	br	%r14
++.size	bn_mul_comba4,.-bn_mul_comba4
++
++#define sqr_add_c(ai,c1,c2,c3)		\
++	lg	%r7,ai*8(%r3);		\
++	mlgr	%r6,%r7;		\
++	algr	c1,%r7;			\
++	alcgr	c2,%r6;			\
++	alcgr	c3,zero
++
++#define sqr_add_c2(ai,aj,c1,c2,c3)	\
++	lg	%r7,ai*8(%r3);		\
++	mlg	%r6,aj*8(%r3);		\
++	algr	c1,%r7;			\
++	alcgr	c2,%r6;			\
++	alcgr	c3,zero;		\
++	algr	c1,%r7;			\
++	alcgr	c2,%r6;			\
++	alcgr	c3,zero
++
++// void bn_sqr_comba8(BN_ULONG *r2,BN_ULONG *r3);
++.globl	bn_sqr_comba8
++.type	bn_sqr_comba8,@function
++.align	4
++bn_sqr_comba8:
++	stmg	%r6,%r8,48(%r15)
++
++	lghi	c1,0
++	lghi	c2,0
++	lghi	c3,0
++	lghi	zero,0
++
++	sqr_add_c(0,c1,c2,c3);
++	stg	c1,0*8(%r2)
++	lghi	c1,0
++
++	sqr_add_c2(1,0,c2,c3,c1);
++	stg	c2,1*8(%r2)
++	lghi	c2,0
++
++	sqr_add_c(1,c3,c1,c2);
++	sqr_add_c2(2,0,c3,c1,c2);
++	stg	c3,2*8(%r2)
++	lghi	c3,0
++
++	sqr_add_c2(3,0,c1,c2,c3);
++	sqr_add_c2(2,1,c1,c2,c3);
++	stg	c1,3*8(%r2)
++	lghi	c1,0
++
++	sqr_add_c(2,c2,c3,c1);
++	sqr_add_c2(3,1,c2,c3,c1);
++	sqr_add_c2(4,0,c2,c3,c1);
++	stg	c2,4*8(%r2)
++	lghi	c2,0
++
++	sqr_add_c2(5,0,c3,c1,c2);
++	sqr_add_c2(4,1,c3,c1,c2);
++	sqr_add_c2(3,2,c3,c1,c2);
++	stg	c3,5*8(%r2)
++	lghi	c3,0
++
++	sqr_add_c(3,c1,c2,c3);
++	sqr_add_c2(4,2,c1,c2,c3);
++	sqr_add_c2(5,1,c1,c2,c3);
++	sqr_add_c2(6,0,c1,c2,c3);
++	stg	c1,6*8(%r2)
++	lghi	c1,0
++
++	sqr_add_c2(7,0,c2,c3,c1);
++	sqr_add_c2(6,1,c2,c3,c1);
++	sqr_add_c2(5,2,c2,c3,c1);
++	sqr_add_c2(4,3,c2,c3,c1);
++	stg	c2,7*8(%r2)
++	lghi	c2,0
++
++	sqr_add_c(4,c3,c1,c2);
++	sqr_add_c2(5,3,c3,c1,c2);
++	sqr_add_c2(6,2,c3,c1,c2);
++	sqr_add_c2(7,1,c3,c1,c2);
++	stg	c3,8*8(%r2)
++	lghi	c3,0
++
++	sqr_add_c2(7,2,c1,c2,c3);
++	sqr_add_c2(6,3,c1,c2,c3);
++	sqr_add_c2(5,4,c1,c2,c3);
++	stg	c1,9*8(%r2)
++	lghi	c1,0
++
++	sqr_add_c(5,c2,c3,c1);
++	sqr_add_c2(6,4,c2,c3,c1);
++	sqr_add_c2(7,3,c2,c3,c1);
++	stg	c2,10*8(%r2)
++	lghi	c2,0
++
++	sqr_add_c2(7,4,c3,c1,c2);
++	sqr_add_c2(6,5,c3,c1,c2);
++	stg	c3,11*8(%r2)
++	lghi	c3,0
++
++	sqr_add_c(6,c1,c2,c3);
++	sqr_add_c2(7,5,c1,c2,c3);
++	stg	c1,12*8(%r2)
++	lghi	c1,0
++
++	sqr_add_c2(7,6,c2,c3,c1);
++	stg	c2,13*8(%r2)
++	lghi	c2,0
++
++	sqr_add_c(7,c3,c1,c2);
++	stg	c3,14*8(%r2)
++	stg	c1,15*8(%r2)
++
++	lmg	%r6,%r8,48(%r15)
++	br	%r14
++.size	bn_sqr_comba8,.-bn_sqr_comba8
++
++// void bn_sqr_comba4(BN_ULONG *r2,BN_ULONG *r3);
++.globl bn_sqr_comba4
++.type	bn_sqr_comba4,@function
++.align	4
++bn_sqr_comba4:
++	stmg	%r6,%r8,48(%r15)
++
++	lghi	c1,0
++	lghi	c2,0
++	lghi	c3,0
++	lghi	zero,0
++
++	sqr_add_c(0,c1,c2,c3);
++	stg	c1,0*8(%r2)
++	lghi	c1,0
++
++	sqr_add_c2(1,0,c2,c3,c1);
++	stg	c2,1*8(%r2)
++	lghi	c2,0
++
++	sqr_add_c(1,c3,c1,c2);
++	sqr_add_c2(2,0,c3,c1,c2);
++	stg	c3,2*8(%r2)
++	lghi	c3,0
++
++	sqr_add_c2(3,0,c1,c2,c3);
++	sqr_add_c2(2,1,c1,c2,c3);
++	stg	c1,3*8(%r2)
++	lghi	c1,0
++
++	sqr_add_c(2,c2,c3,c1);
++	sqr_add_c2(3,1,c2,c3,c1);
++	stg	c2,4*8(%r2)
++	lghi	c2,0
++
++	sqr_add_c2(3,2,c3,c1,c2);
++	stg	c3,5*8(%r2)
++	lghi	c3,0
++
++	sqr_add_c(3,c1,c2,c3);
++	stg	c1,6*8(%r2)
++	stg	c2,7*8(%r2)
++
++	lmg	%r6,%r8,48(%r15)
++	br	%r14
++.size	bn_sqr_comba4,.-bn_sqr_comba4
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/bn/asm/sparct4-mont.pl b/CryptoPkg/Library/OpensslLib/openssl/crypto/bn/asm/sparct4-mont.pl
+new file mode 100755
+index 0000000..4faf66f
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/bn/asm/sparct4-mont.pl
+@@ -0,0 +1,1232 @@
++#! /usr/bin/env perl
++# Copyright 2012-2016 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
++# in the file LICENSE in the source distribution or at
++# https://www.openssl.org/source/license.html
++
++
++# ====================================================================
++# Written by David S. Miller  and Andy Polyakov
++# . The module is licensed under 2-clause BSD
++# license. November 2012. All rights reserved.
++# ====================================================================
++
++######################################################################
++# Montgomery squaring-n-multiplication module for SPARC T4.
++#
++# The module consists of three parts:
++#
++# 1) collection of "single-op" subroutines that perform single
++#    operation, Montgomery squaring or multiplication, on 512-,
++#    1024-, 1536- and 2048-bit operands;
++# 2) collection of "multi-op" subroutines that perform 5 squaring and
++#    1 multiplication operations on operands of above lengths;
++# 3) fall-back and helper VIS3 subroutines.
++#
++# RSA sign is dominated by multi-op subroutine, while RSA verify and
++# DSA - by single-op. Special note about 4096-bit RSA verify result.
++# Operands are too long for dedicated hardware and it's handled by
++# VIS3 code, which is why you don't see any improvement. It's surely
++# possible to improve it [by deploying 'mpmul' instruction], maybe in
++# the future...
++#
++# Performance improvement.
++#
++# 64-bit process, VIS3:
++#                   sign    verify    sign/s verify/s
++# rsa 1024 bits 0.000628s 0.000028s   1592.4  35434.4
++# rsa 2048 bits 0.003282s 0.000106s    304.7   9438.3
++# rsa 4096 bits 0.025866s 0.000340s     38.7   2940.9
++# dsa 1024 bits 0.000301s 0.000332s   3323.7   3013.9
++# dsa 2048 bits 0.001056s 0.001233s    946.9    810.8
++#
++# 64-bit process, this module:
++#                   sign    verify    sign/s verify/s
++# rsa 1024 bits 0.000256s 0.000016s   3904.4  61411.9
++# rsa 2048 bits 0.000946s 0.000029s   1056.8  34292.7
++# rsa 4096 bits 0.005061s 0.000340s    197.6   2940.5
++# dsa 1024 bits 0.000176s 0.000195s   5674.7   5130.5
++# dsa 2048 bits 0.000296s 0.000354s   3383.2   2827.6
++#
++######################################################################
++# 32-bit process, VIS3:
++#                   sign    verify    sign/s verify/s
++# rsa 1024 bits 0.000665s 0.000028s   1504.8  35233.3
++# rsa 2048 bits 0.003349s 0.000106s    298.6   9433.4
++# rsa 4096 bits 0.025959s 0.000341s     38.5   2934.8
++# dsa 1024 bits 0.000320s 0.000341s   3123.3   2929.6
++# dsa 2048 bits 0.001101s 0.001260s    908.2    793.4
++#
++# 32-bit process, this module:
++#                   sign    verify    sign/s verify/s
++# rsa 1024 bits 0.000301s 0.000017s   3317.1  60240.0
++# rsa 2048 bits 0.001034s 0.000030s    966.9  33812.7
++# rsa 4096 bits 0.005244s 0.000341s    190.7   2935.4
++# dsa 1024 bits 0.000201s 0.000205s   4976.1   4879.2
++# dsa 2048 bits 0.000328s 0.000360s   3051.1   2774.2
++#
++# 32-bit code is prone to performance degradation as interrupt rate
++# dispatched to CPU executing the code grows. This is because in
++# standard process of handling interrupt in 32-bit process context
++# upper halves of most integer registers used as input or output are
++# zeroed. This renders result invalid, and operation has to be re-run.
++# If CPU is "bothered" with timer interrupts only, the penalty is
++# hardly measurable. But in order to mitigate this problem for higher
++# interrupt rates contemporary Linux kernel recognizes biased stack
++# even in 32-bit process context and preserves full register contents.
++# See http://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/commit/?id=517ffce4e1a03aea979fe3a18a3dd1761a24fafb
++# for details.
++
++$0 =~ m/(.*[\/\\])[^\/\\]+$/; $dir=$1;
++push(@INC,"${dir}","${dir}../../perlasm");
++require "sparcv9_modes.pl";
++
++$output = pop;
++open STDOUT,">$output";
++
++$code.=<<___;
++#include "sparc_arch.h"
++
++#ifdef	__arch64__
++.register	%g2,#scratch
++.register	%g3,#scratch
++#endif
++
++.section	".text",#alloc,#execinstr
++
++#ifdef	__PIC__
++SPARC_PIC_THUNK(%g1)
++#endif
++___
++
++########################################################################
++# Register layout for mont[mul|sqr] instructions.
++# For details see "Oracle SPARC Architecture 2011" manual at
++# http://www.oracle.com/technetwork/server-storage/sun-sparc-enterprise/documentation/.
++#
++my @R=map("%f".2*$_,(0..11,30,31,12..29));
++my @N=(map("%l$_",(0..7)),map("%o$_",(0..5))); @N=(@N,@N,@N[0..3]);
++my @A=(@N[0..13],@R[14..31]);
++my @B=(map("%i$_",(0..5)),map("%l$_",(0..7))); @B=(@B,@B,map("%o$_",(0..3)));
++
++########################################################################
++# int bn_mul_mont_t4_$NUM(u64 *rp,const u64 *ap,const u64 *bp,
++#			  const u64 *np,const BN_ULONG *n0);
++#
++sub generate_bn_mul_mont_t4() {
++my $NUM=shift;
++my ($rp,$ap,$bp,$np,$sentinel)=map("%g$_",(1..5));
++
++$code.=<<___;
++.globl	bn_mul_mont_t4_$NUM
++.align	32
++bn_mul_mont_t4_$NUM:
++#ifdef	__arch64__
++	mov	0,$sentinel
++	mov	-128,%g4
++#elif defined(SPARCV9_64BIT_STACK)
++	SPARC_LOAD_ADDRESS_LEAF(OPENSSL_sparcv9cap_P,%g1,%g5)
++	ld	[%g1+0],%g1	! OPENSSL_sparcv9_P[0]
++	mov	-2047,%g4
++	and	%g1,SPARCV9_64BIT_STACK,%g1
++	movrz	%g1,0,%g4
++	mov	-1,$sentinel
++	add	%g4,-128,%g4
++#else
++	mov	-1,$sentinel
++	mov	-128,%g4
++#endif
++	sllx	$sentinel,32,$sentinel
++	save	%sp,%g4,%sp
++#ifndef	__arch64__
++	save	%sp,-128,%sp	! warm it up
++	save	%sp,-128,%sp
++	save	%sp,-128,%sp
++	save	%sp,-128,%sp
++	save	%sp,-128,%sp
++	save	%sp,-128,%sp
++	restore
++	restore
++	restore
++	restore
++	restore
++	restore
++#endif
++	and	%sp,1,%g4
++	or	$sentinel,%fp,%fp
++	or	%g4,$sentinel,$sentinel
++
++	! copy arguments to global registers
++	mov	%i0,$rp
++	mov	%i1,$ap
++	mov	%i2,$bp
++	mov	%i3,$np
++	ld	[%i4+0],%f1	! load *n0
++	ld	[%i4+4],%f0
++	fsrc2	%f0,%f60
++___
++
++# load ap[$NUM] ########################################################
++$code.=<<___;
++	save	%sp,-128,%sp;		or	$sentinel,%fp,%fp
++___
++for($i=0; $i<14 && $i<$NUM; $i++) {
++my $lo=$i<13?@A[$i+1]:"%o7";
++$code.=<<___;
++	ld	[$ap+$i*8+0],$lo
++	ld	[$ap+$i*8+4],@A[$i]
++	sllx	@A[$i],32,@A[$i]
++	or	$lo,@A[$i],@A[$i]
++___
++}
++for(; $i<$NUM; $i++) {
++my ($hi,$lo)=("%f".2*($i%4),"%f".(2*($i%4)+1));
++$code.=<<___;
++	ld	[$ap+$i*8+0],$lo
++	ld	[$ap+$i*8+4],$hi
++	fsrc2	$hi,@A[$i]
++___
++}
++# load np[$NUM] ########################################################
++$code.=<<___;
++	save	%sp,-128,%sp;		or	$sentinel,%fp,%fp
++___
++for($i=0; $i<14 && $i<$NUM; $i++) {
++my $lo=$i<13?@N[$i+1]:"%o7";
++$code.=<<___;
++	ld	[$np+$i*8+0],$lo
++	ld	[$np+$i*8+4],@N[$i]
++	sllx	@N[$i],32,@N[$i]
++	or	$lo,@N[$i],@N[$i]
++___
++}
++$code.=<<___;
++	save	%sp,-128,%sp;		or	$sentinel,%fp,%fp
++___
++for(; $i<28 && $i<$NUM; $i++) {
++my $lo=$i<27?@N[$i+1]:"%o7";
++$code.=<<___;
++	ld	[$np+$i*8+0],$lo
++	ld	[$np+$i*8+4],@N[$i]
++	sllx	@N[$i],32,@N[$i]
++	or	$lo,@N[$i],@N[$i]
++___
++}
++$code.=<<___;
++	save	%sp,-128,%sp;		or	$sentinel,%fp,%fp
++___
++for(; $i<$NUM; $i++) {
++my $lo=($i<$NUM-1)?@N[$i+1]:"%o7";
++$code.=<<___;
++	ld	[$np+$i*8+0],$lo
++	ld	[$np+$i*8+4],@N[$i]
++	sllx	@N[$i],32,@N[$i]
++	or	$lo,@N[$i],@N[$i]
++___
++}
++$code.=<<___;
++	cmp	$ap,$bp
++	be	SIZE_T_CC,.Lmsquare_$NUM
++	nop
++___
++
++# load bp[$NUM] ########################################################
++$code.=<<___;
++	save	%sp,-128,%sp;		or	$sentinel,%fp,%fp
++___
++for($i=0; $i<14 && $i<$NUM; $i++) {
++my $lo=$i<13?@B[$i+1]:"%o7";
++$code.=<<___;
++	ld	[$bp+$i*8+0],$lo
++	ld	[$bp+$i*8+4],@B[$i]
++	sllx	@B[$i],32,@B[$i]
++	or	$lo,@B[$i],@B[$i]
++___
++}
++$code.=<<___;
++	save	%sp,-128,%sp;		or	$sentinel,%fp,%fp
++___
++for(; $i<$NUM; $i++) {
++my $lo=($i<$NUM-1)?@B[$i+1]:"%o7";
++$code.=<<___;
++	ld	[$bp+$i*8+0],$lo
++	ld	[$bp+$i*8+4],@B[$i]
++	sllx	@B[$i],32,@B[$i]
++	or	$lo,@B[$i],@B[$i]
++___
++}
++# magic ################################################################
++$code.=<<___;
++	.word	0x81b02920+$NUM-1	! montmul	$NUM-1
++.Lmresume_$NUM:
++	fbu,pn	%fcc3,.Lmabort_$NUM
++#ifndef	__arch64__
++	and	%fp,$sentinel,$sentinel
++	brz,pn	$sentinel,.Lmabort_$NUM
++#endif
++	nop
++#ifdef	__arch64__
++	restore
++	restore
++	restore
++	restore
++	restore
++#else
++	restore;		and	%fp,$sentinel,$sentinel
++	restore;		and	%fp,$sentinel,$sentinel
++	restore;		and	%fp,$sentinel,$sentinel
++	restore;		and	%fp,$sentinel,$sentinel
++	 brz,pn	$sentinel,.Lmabort1_$NUM
++	restore
++#endif
++___
++
++# save tp[$NUM] ########################################################
++for($i=0; $i<14 && $i<$NUM; $i++) {
++$code.=<<___;
++	movxtod	@A[$i],@R[$i]
++___
++}
++$code.=<<___;
++#ifdef	__arch64__
++	restore
++#else
++	 and	%fp,$sentinel,$sentinel
++	restore
++	 and	$sentinel,1,%o7
++	 and	%fp,$sentinel,$sentinel
++	 srl	%fp,0,%fp		! just in case?
++	 or	%o7,$sentinel,$sentinel
++	brz,a,pn $sentinel,.Lmdone_$NUM
++	mov	0,%i0		! return failure
++#endif
++___
++for($i=0; $i<12 && $i<$NUM; $i++) {
++@R[$i] =~ /%f([0-9]+)/;
++my $lo = "%f".($1+1);
++$code.=<<___;
++	st	$lo,[$rp+$i*8+0]
++	st	@R[$i],[$rp+$i*8+4]
++___
++}
++for(; $i<$NUM; $i++) {
++my ($hi,$lo)=("%f".2*($i%4),"%f".(2*($i%4)+1));
++$code.=<<___;
++	fsrc2	@R[$i],$hi
++	st	$lo,[$rp+$i*8+0]
++	st	$hi,[$rp+$i*8+4]
++___
++}
++$code.=<<___;
++	mov	1,%i0		! return success
++.Lmdone_$NUM:
++	ret
++	restore
++
++.Lmabort_$NUM:
++	restore
++	restore
++	restore
++	restore
++	restore
++.Lmabort1_$NUM:
++	restore
++
++	mov	0,%i0		! return failure
++	ret
++	restore
++
++.align	32
++.Lmsquare_$NUM:
++	save	%sp,-128,%sp;		or	$sentinel,%fp,%fp
++	save	%sp,-128,%sp;		or	$sentinel,%fp,%fp
++	.word   0x81b02940+$NUM-1	! montsqr	$NUM-1
++	ba	.Lmresume_$NUM
++	nop
++.type	bn_mul_mont_t4_$NUM, #function
++.size	bn_mul_mont_t4_$NUM, .-bn_mul_mont_t4_$NUM
++___
++}
++
++for ($i=8;$i<=32;$i+=8) {
++	&generate_bn_mul_mont_t4($i);
++}
++
++########################################################################
++#
++sub load_ccr {
++my ($ptbl,$pwr,$ccr,$skip_wr)=@_;
++$code.=<<___;
++	srl	$pwr,	2,	%o4
++	and	$pwr,	3,	%o5
++	and	%o4,	7,	%o4
++	sll	%o5,	3,	%o5	! offset within first cache line
++	add	%o5,	$ptbl,	$ptbl	! of the pwrtbl
++	or	%g0,	1,	%o5
++	sll	%o5,	%o4,	$ccr
++___
++$code.=<<___	if (!$skip_wr);
++	wr	$ccr,	%g0,	%ccr
++___
++}
++sub load_b_pair {
++my ($pwrtbl,$B0,$B1)=@_;
++
++$code.=<<___;
++	ldx	[$pwrtbl+0*32],	$B0
++	ldx	[$pwrtbl+8*32],	$B1
++	ldx	[$pwrtbl+1*32],	%o4
++	ldx	[$pwrtbl+9*32],	%o5
++	movvs	%icc,	%o4,	$B0
++	ldx	[$pwrtbl+2*32],	%o4
++	movvs	%icc,	%o5,	$B1
++	ldx	[$pwrtbl+10*32],%o5
++	move	%icc,	%o4,	$B0
++	ldx	[$pwrtbl+3*32],	%o4
++	move	%icc,	%o5,	$B1
++	ldx	[$pwrtbl+11*32],%o5
++	movneg	%icc,	%o4,	$B0
++	ldx	[$pwrtbl+4*32],	%o4
++	movneg	%icc,	%o5,	$B1
++	ldx	[$pwrtbl+12*32],%o5
++	movcs	%xcc,	%o4,	$B0
++	ldx	[$pwrtbl+5*32],%o4
++	movcs	%xcc,	%o5,	$B1
++	ldx	[$pwrtbl+13*32],%o5
++	movvs	%xcc,	%o4,	$B0
++	ldx	[$pwrtbl+6*32],	%o4
++	movvs	%xcc,	%o5,	$B1
++	ldx	[$pwrtbl+14*32],%o5
++	move	%xcc,	%o4,	$B0
++	ldx	[$pwrtbl+7*32],	%o4
++	move	%xcc,	%o5,	$B1
++	ldx	[$pwrtbl+15*32],%o5
++	movneg	%xcc,	%o4,	$B0
++	add	$pwrtbl,16*32,	$pwrtbl
++	movneg	%xcc,	%o5,	$B1
++___
++}
++sub load_b {
++my ($pwrtbl,$Bi)=@_;
++
++$code.=<<___;
++	ldx	[$pwrtbl+0*32],	$Bi
++	ldx	[$pwrtbl+1*32],	%o4
++	ldx	[$pwrtbl+2*32],	%o5
++	movvs	%icc,	%o4,	$Bi
++	ldx	[$pwrtbl+3*32],	%o4
++	move	%icc,	%o5,	$Bi
++	ldx	[$pwrtbl+4*32],	%o5
++	movneg	%icc,	%o4,	$Bi
++	ldx	[$pwrtbl+5*32],	%o4
++	movcs	%xcc,	%o5,	$Bi
++	ldx	[$pwrtbl+6*32],	%o5
++	movvs	%xcc,	%o4,	$Bi
++	ldx	[$pwrtbl+7*32],	%o4
++	move	%xcc,	%o5,	$Bi
++	add	$pwrtbl,8*32,	$pwrtbl
++	movneg	%xcc,	%o4,	$Bi
++___
++}
++
++########################################################################
++# int bn_pwr5_mont_t4_$NUM(u64 *tp,const u64 *np,const BN_ULONG *n0,
++#			   const u64 *pwrtbl,int pwr,int stride);
++#
++sub generate_bn_pwr5_mont_t4() {
++my $NUM=shift;
++my ($tp,$np,$pwrtbl,$pwr,$sentinel)=map("%g$_",(1..5));
++
++$code.=<<___;
++.globl	bn_pwr5_mont_t4_$NUM
++.align	32
++bn_pwr5_mont_t4_$NUM:
++#ifdef	__arch64__
++	mov	0,$sentinel
++	mov	-128,%g4
++#elif defined(SPARCV9_64BIT_STACK)
++	SPARC_LOAD_ADDRESS_LEAF(OPENSSL_sparcv9cap_P,%g1,%g5)
++	ld	[%g1+0],%g1	! OPENSSL_sparcv9_P[0]
++	mov	-2047,%g4
++	and	%g1,SPARCV9_64BIT_STACK,%g1
++	movrz	%g1,0,%g4
++	mov	-1,$sentinel
++	add	%g4,-128,%g4
++#else
++	mov	-1,$sentinel
++	mov	-128,%g4
++#endif
++	sllx	$sentinel,32,$sentinel
++	save	%sp,%g4,%sp
++#ifndef	__arch64__
++	save	%sp,-128,%sp	! warm it up
++	save	%sp,-128,%sp
++	save	%sp,-128,%sp
++	save	%sp,-128,%sp
++	save	%sp,-128,%sp
++	save	%sp,-128,%sp
++	restore
++	restore
++	restore
++	restore
++	restore
++	restore
++#endif
++	and	%sp,1,%g4
++	or	$sentinel,%fp,%fp
++	or	%g4,$sentinel,$sentinel
++
++	! copy arguments to global registers
++	mov	%i0,$tp
++	mov	%i1,$np
++	ld	[%i2+0],%f1	! load *n0
++	ld	[%i2+4],%f0
++	mov	%i3,$pwrtbl
++	srl	%i4,%g0,%i4	! pack last arguments
++	sllx	%i5,32,$pwr
++	or	%i4,$pwr,$pwr
++	fsrc2	%f0,%f60
++___
++
++# load tp[$NUM] ########################################################
++$code.=<<___;
++	save	%sp,-128,%sp;		or	$sentinel,%fp,%fp
++___
++for($i=0; $i<14 && $i<$NUM; $i++) {
++$code.=<<___;
++	ldx	[$tp+$i*8],@A[$i]
++___
++}
++for(; $i<$NUM; $i++) {
++$code.=<<___;
++	ldd	[$tp+$i*8],@A[$i]
++___
++}
++# load np[$NUM] ########################################################
++$code.=<<___;
++	save	%sp,-128,%sp;		or	$sentinel,%fp,%fp
++___
++for($i=0; $i<14 && $i<$NUM; $i++) {
++$code.=<<___;
++	ldx	[$np+$i*8],@N[$i]
++___
++}
++$code.=<<___;
++	save	%sp,-128,%sp;		or	$sentinel,%fp,%fp
++___
++for(; $i<28 && $i<$NUM; $i++) {
++$code.=<<___;
++	ldx	[$np+$i*8],@N[$i]
++___
++}
++$code.=<<___;
++	save	%sp,-128,%sp;		or	$sentinel,%fp,%fp
++___
++for(; $i<$NUM; $i++) {
++$code.=<<___;
++	ldx	[$np+$i*8],@N[$i]
++___
++}
++# load pwrtbl[pwr] ########################################################
++$code.=<<___;
++	save	%sp,-128,%sp;		or	$sentinel,%fp,%fp
++
++	srlx	$pwr,	32,	%o4		! unpack $pwr
++	srl	$pwr,	%g0,	%o5
++	sub	%o4,	5,	%o4
++	mov	$pwrtbl,	%o7
++	sllx	%o4,	32,	$pwr		! re-pack $pwr
++	or	%o5,	$pwr,	$pwr
++	srl	%o5,	%o4,	%o5
++___
++	&load_ccr("%o7","%o5","%o4");
++$code.=<<___;
++	b	.Lstride_$NUM
++	nop
++.align	16
++.Lstride_$NUM:
++___
++for($i=0; $i<14 && $i<$NUM; $i+=2) {
++	&load_b_pair("%o7",@B[$i],@B[$i+1]);
++}
++$code.=<<___;
++	save	%sp,-128,%sp;		or	$sentinel,%fp,%fp
++___
++for(; $i<$NUM; $i+=2) {
++	&load_b_pair("%i7",@B[$i],@B[$i+1]);
++}
++$code.=<<___;
++	srax	$pwr,	32,	%o4		! unpack $pwr
++	srl	$pwr,	%g0,	%o5
++	sub	%o4,	5,	%o4
++	mov	$pwrtbl,	%i7
++	sllx	%o4,	32,	$pwr		! re-pack $pwr
++	or	%o5,	$pwr,	$pwr
++	srl	%o5,	%o4,	%o5
++___
++	&load_ccr("%i7","%o5","%o4",1);
++
++# magic ################################################################
++for($i=0; $i<5; $i++) {
++$code.=<<___;
++	.word	0x81b02940+$NUM-1	! montsqr	$NUM-1
++	fbu,pn	%fcc3,.Labort_$NUM
++#ifndef	__arch64__
++	and	%fp,$sentinel,$sentinel
++	brz,pn	$sentinel,.Labort_$NUM
++#endif
++	nop
++___
++}
++$code.=<<___;
++	wr	%o4,	%g0,	%ccr
++	.word	0x81b02920+$NUM-1	! montmul	$NUM-1
++	fbu,pn	%fcc3,.Labort_$NUM
++#ifndef	__arch64__
++	and	%fp,$sentinel,$sentinel
++	brz,pn	$sentinel,.Labort_$NUM
++#endif
++
++	srax	$pwr,	32,	%o4
++#ifdef	__arch64__
++	brgez	%o4,.Lstride_$NUM
++	restore
++	restore
++	restore
++	restore
++	restore
++#else
++	brgez	%o4,.Lstride_$NUM
++	restore;		and	%fp,$sentinel,$sentinel
++	restore;		and	%fp,$sentinel,$sentinel
++	restore;		and	%fp,$sentinel,$sentinel
++	restore;		and	%fp,$sentinel,$sentinel
++	 brz,pn	$sentinel,.Labort1_$NUM
++	restore
++#endif
++___
++
++# save tp[$NUM] ########################################################
++for($i=0; $i<14 && $i<$NUM; $i++) {
++$code.=<<___;
++	movxtod	@A[$i],@R[$i]
++___
++}
++$code.=<<___;
++#ifdef	__arch64__
++	restore
++#else
++	 and	%fp,$sentinel,$sentinel
++	restore
++	 and	$sentinel,1,%o7
++	 and	%fp,$sentinel,$sentinel
++	 srl	%fp,0,%fp		! just in case?
++	 or	%o7,$sentinel,$sentinel
++	brz,a,pn $sentinel,.Ldone_$NUM
++	mov	0,%i0		! return failure
++#endif
++___
++for($i=0; $i<$NUM; $i++) {
++$code.=<<___;
++	std	@R[$i],[$tp+$i*8]
++___
++}
++$code.=<<___;
++	mov	1,%i0		! return success
++.Ldone_$NUM:
++	ret
++	restore
++
++.Labort_$NUM:
++	restore
++	restore
++	restore
++	restore
++	restore
++.Labort1_$NUM:
++	restore
++
++	mov	0,%i0		! return failure
++	ret
++	restore
++.type	bn_pwr5_mont_t4_$NUM, #function
++.size	bn_pwr5_mont_t4_$NUM, .-bn_pwr5_mont_t4_$NUM
++___
++}
++
++for ($i=8;$i<=32;$i+=8) {
++	&generate_bn_pwr5_mont_t4($i);
++}
++
++{
++########################################################################
++# Fall-back subroutines
++#
++# copy of bn_mul_mont_vis3 adjusted for vectors of 64-bit values
++#
++($n0,$m0,$m1,$lo0,$hi0, $lo1,$hi1,$aj,$alo,$nj,$nlo,$tj)=
++	(map("%g$_",(1..5)),map("%o$_",(0..5,7)));
++
++# int bn_mul_mont(
++$rp="%o0";	# u64 *rp,
++$ap="%o1";	# const u64 *ap,
++$bp="%o2";	# const u64 *bp,
++$np="%o3";	# const u64 *np,
++$n0p="%o4";	# const BN_ULONG *n0,
++$num="%o5";	# int num);	# caller ensures that num is >=3
++$code.=<<___;
++.globl	bn_mul_mont_t4
++.align	32
++bn_mul_mont_t4:
++	add	%sp,	STACK_BIAS,	%g4	! real top of stack
++	sll	$num,	3,	$num		! size in bytes
++	add	$num,	63,	%g1
++	andn	%g1,	63,	%g1		! buffer size rounded up to 64 bytes
++	sub	%g4,	%g1,	%g1
++	andn	%g1,	63,	%g1		! align at 64 byte
++	sub	%g1,	STACK_FRAME,	%g1	! new top of stack
++	sub	%g1,	%g4,	%g1
++
++	save	%sp,	%g1,	%sp
++___
++#	+-------------------------------+<-----	%sp
++#	.				.
++#	+-------------------------------+<-----	aligned at 64 bytes
++#	| __int64 tmp[0]		|
++#	+-------------------------------+
++#	.				.
++#	.				.
++#	+-------------------------------+<-----	aligned at 64 bytes
++#	.				.
++($rp,$ap,$bp,$np,$n0p,$num)=map("%i$_",(0..5));
++($t0,$t1,$t2,$t3,$cnt,$tp,$bufsz)=map("%l$_",(0..7));
++($ovf,$i)=($t0,$t1);
++$code.=<<___;
++	ld	[$n0p+0],	$t0	! pull n0[0..1] value
++	ld	[$n0p+4],	$t1
++	add	%sp, STACK_BIAS+STACK_FRAME, $tp
++	ldx	[$bp+0],	$m0	! m0=bp[0]
++	sllx	$t1,	32,	$n0
++	add	$bp,	8,	$bp
++	or	$t0,	$n0,	$n0
++
++	ldx	[$ap+0],	$aj	! ap[0]
++
++	mulx	$aj,	$m0,	$lo0	! ap[0]*bp[0]
++	umulxhi	$aj,	$m0,	$hi0
++
++	ldx	[$ap+8],	$aj	! ap[1]
++	add	$ap,	16,	$ap
++	ldx	[$np+0],	$nj	! np[0]
++
++	mulx	$lo0,	$n0,	$m1	! "tp[0]"*n0
++
++	mulx	$aj,	$m0,	$alo	! ap[1]*bp[0]
++	umulxhi	$aj,	$m0,	$aj	! ahi=aj
++
++	mulx	$nj,	$m1,	$lo1	! np[0]*m1
++	umulxhi	$nj,	$m1,	$hi1
++
++	ldx	[$np+8],	$nj	! np[1]
++
++	addcc	$lo0,	$lo1,	$lo1
++	add	$np,	16,	$np
++	addxc	%g0,	$hi1,	$hi1
++
++	mulx	$nj,	$m1,	$nlo	! np[1]*m1
++	umulxhi	$nj,	$m1,	$nj	! nhi=nj
++
++	ba	.L1st
++	sub	$num,	24,	$cnt	! cnt=num-3
++
++.align	16
++.L1st:
++	addcc	$alo,	$hi0,	$lo0
++	addxc	$aj,	%g0,	$hi0
++
++	ldx	[$ap+0],	$aj	! ap[j]
++	addcc	$nlo,	$hi1,	$lo1
++	add	$ap,	8,	$ap
++	addxc	$nj,	%g0,	$hi1	! nhi=nj
++
++	ldx	[$np+0],	$nj	! np[j]
++	mulx	$aj,	$m0,	$alo	! ap[j]*bp[0]
++	add	$np,	8,	$np
++	umulxhi	$aj,	$m0,	$aj	! ahi=aj
++
++	mulx	$nj,	$m1,	$nlo	! np[j]*m1
++	addcc	$lo0,	$lo1,	$lo1	! np[j]*m1+ap[j]*bp[0]
++	umulxhi	$nj,	$m1,	$nj	! nhi=nj
++	addxc	%g0,	$hi1,	$hi1
++	stxa	$lo1,	[$tp]0xe2	! tp[j-1]
++	add	$tp,	8,	$tp	! tp++
++
++	brnz,pt	$cnt,	.L1st
++	sub	$cnt,	8,	$cnt	! j--
++!.L1st
++	addcc	$alo,	$hi0,	$lo0
++	addxc	$aj,	%g0,	$hi0	! ahi=aj
++
++	addcc	$nlo,	$hi1,	$lo1
++	addxc	$nj,	%g0,	$hi1
++	addcc	$lo0,	$lo1,	$lo1	! np[j]*m1+ap[j]*bp[0]
++	addxc	%g0,	$hi1,	$hi1
++	stxa	$lo1,	[$tp]0xe2	! tp[j-1]
++	add	$tp,	8,	$tp
++
++	addcc	$hi0,	$hi1,	$hi1
++	addxc	%g0,	%g0,	$ovf	! upmost overflow bit
++	stxa	$hi1,	[$tp]0xe2
++	add	$tp,	8,	$tp
++
++	ba	.Louter
++	sub	$num,	16,	$i	! i=num-2
++
++.align	16
++.Louter:
++	ldx	[$bp+0],	$m0	! m0=bp[i]
++	add	$bp,	8,	$bp
++
++	sub	$ap,	$num,	$ap	! rewind
++	sub	$np,	$num,	$np
++	sub	$tp,	$num,	$tp
++
++	ldx	[$ap+0],	$aj	! ap[0]
++	ldx	[$np+0],	$nj	! np[0]
++
++	mulx	$aj,	$m0,	$lo0	! ap[0]*bp[i]
++	ldx	[$tp],		$tj	! tp[0]
++	umulxhi	$aj,	$m0,	$hi0
++	ldx	[$ap+8],	$aj	! ap[1]
++	addcc	$lo0,	$tj,	$lo0	! ap[0]*bp[i]+tp[0]
++	mulx	$aj,	$m0,	$alo	! ap[1]*bp[i]
++	addxc	%g0,	$hi0,	$hi0
++	mulx	$lo0,	$n0,	$m1	! tp[0]*n0
++	umulxhi	$aj,	$m0,	$aj	! ahi=aj
++	mulx	$nj,	$m1,	$lo1	! np[0]*m1
++	add	$ap,	16,	$ap
++	umulxhi	$nj,	$m1,	$hi1
++	ldx	[$np+8],	$nj	! np[1]
++	add	$np,	16,	$np
++	addcc	$lo1,	$lo0,	$lo1
++	mulx	$nj,	$m1,	$nlo	! np[1]*m1
++	addxc	%g0,	$hi1,	$hi1
++	umulxhi	$nj,	$m1,	$nj	! nhi=nj
++
++	ba	.Linner
++	sub	$num,	24,	$cnt	! cnt=num-3
++.align	16
++.Linner:
++	addcc	$alo,	$hi0,	$lo0
++	ldx	[$tp+8],	$tj	! tp[j]
++	addxc	$aj,	%g0,	$hi0	! ahi=aj
++	ldx	[$ap+0],	$aj	! ap[j]
++	add	$ap,	8,	$ap
++	addcc	$nlo,	$hi1,	$lo1
++	mulx	$aj,	$m0,	$alo	! ap[j]*bp[i]
++	addxc	$nj,	%g0,	$hi1	! nhi=nj
++	ldx	[$np+0],	$nj	! np[j]
++	add	$np,	8,	$np
++	umulxhi	$aj,	$m0,	$aj	! ahi=aj
++	addcc	$lo0,	$tj,	$lo0	! ap[j]*bp[i]+tp[j]
++	mulx	$nj,	$m1,	$nlo	! np[j]*m1
++	addxc	%g0,	$hi0,	$hi0
++	umulxhi	$nj,	$m1,	$nj	! nhi=nj
++	addcc	$lo1,	$lo0,	$lo1	! np[j]*m1+ap[j]*bp[i]+tp[j]
++	addxc	%g0,	$hi1,	$hi1
++	stx	$lo1,	[$tp]		! tp[j-1]
++	add	$tp,	8,	$tp
++	brnz,pt	$cnt,	.Linner
++	sub	$cnt,	8,	$cnt
++!.Linner
++	ldx	[$tp+8],	$tj	! tp[j]
++	addcc	$alo,	$hi0,	$lo0
++	addxc	$aj,	%g0,	$hi0	! ahi=aj
++	addcc	$lo0,	$tj,	$lo0	! ap[j]*bp[i]+tp[j]
++	addxc	%g0,	$hi0,	$hi0
++
++	addcc	$nlo,	$hi1,	$lo1
++	addxc	$nj,	%g0,	$hi1	! nhi=nj
++	addcc	$lo1,	$lo0,	$lo1	! np[j]*m1+ap[j]*bp[i]+tp[j]
++	addxc	%g0,	$hi1,	$hi1
++	stx	$lo1,	[$tp]		! tp[j-1]
++
++	subcc	%g0,	$ovf,	%g0	! move upmost overflow to CCR.xcc
++	addxccc	$hi1,	$hi0,	$hi1
++	addxc	%g0,	%g0,	$ovf
++	stx	$hi1,	[$tp+8]
++	add	$tp,	16,	$tp
++
++	brnz,pt	$i,	.Louter
++	sub	$i,	8,	$i
++
++	sub	$ap,	$num,	$ap	! rewind
++	sub	$np,	$num,	$np
++	sub	$tp,	$num,	$tp
++	ba	.Lsub
++	subcc	$num,	8,	$cnt	! cnt=num-1 and clear CCR.xcc
++
++.align	16
++.Lsub:
++	ldx	[$tp],		$tj
++	add	$tp,	8,	$tp
++	ldx	[$np+0],	$nj
++	add	$np,	8,	$np
++	subccc	$tj,	$nj,	$t2	! tp[j]-np[j]
++	srlx	$tj,	32,	$tj
++	srlx	$nj,	32,	$nj
++	subccc	$tj,	$nj,	$t3
++	add	$rp,	8,	$rp
++	st	$t2,	[$rp-4]		! reverse order
++	st	$t3,	[$rp-8]
++	brnz,pt	$cnt,	.Lsub
++	sub	$cnt,	8,	$cnt
++
++	sub	$np,	$num,	$np	! rewind
++	sub	$tp,	$num,	$tp
++	sub	$rp,	$num,	$rp
++
++	subc	$ovf,	%g0,	$ovf	! handle upmost overflow bit
++	and	$tp,	$ovf,	$ap
++	andn	$rp,	$ovf,	$np
++	or	$np,	$ap,	$ap	! ap=borrow?tp:rp
++	ba	.Lcopy
++	sub	$num,	8,	$cnt
++
++.align	16
++.Lcopy:					! copy or in-place refresh
++	ldx	[$ap+0],	$t2
++	add	$ap,	8,	$ap
++	stx	%g0,	[$tp]		! zap
++	add	$tp,	8,	$tp
++	stx	$t2,	[$rp+0]
++	add	$rp,	8,	$rp
++	brnz	$cnt,	.Lcopy
++	sub	$cnt,	8,	$cnt
++
++	mov	1,	%o0
++	ret
++	restore
++.type	bn_mul_mont_t4, #function
++.size	bn_mul_mont_t4, .-bn_mul_mont_t4
++___
++
++# int bn_mul_mont_gather5(
++$rp="%o0";	# u64 *rp,
++$ap="%o1";	# const u64 *ap,
++$bp="%o2";	# const u64 *pwrtbl,
++$np="%o3";	# const u64 *np,
++$n0p="%o4";	# const BN_ULONG *n0,
++$num="%o5";	# int num,	# caller ensures that num is >=3
++		# int power);
++$code.=<<___;
++.globl	bn_mul_mont_gather5_t4
++.align	32
++bn_mul_mont_gather5_t4:
++	add	%sp,	STACK_BIAS,	%g4	! real top of stack
++	sll	$num,	3,	$num		! size in bytes
++	add	$num,	63,	%g1
++	andn	%g1,	63,	%g1		! buffer size rounded up to 64 bytes
++	sub	%g4,	%g1,	%g1
++	andn	%g1,	63,	%g1		! align at 64 byte
++	sub	%g1,	STACK_FRAME,	%g1	! new top of stack
++	sub	%g1,	%g4,	%g1
++	LDPTR	[%sp+STACK_7thARG],	%g4	! load power, 7th argument
++
++	save	%sp,	%g1,	%sp
++___
++#	+-------------------------------+<-----	%sp
++#	.				.
++#	+-------------------------------+<-----	aligned at 64 bytes
++#	| __int64 tmp[0]		|
++#	+-------------------------------+
++#	.				.
++#	.				.
++#	+-------------------------------+<-----	aligned at 64 bytes
++#	.				.
++($rp,$ap,$bp,$np,$n0p,$num)=map("%i$_",(0..5));
++($t0,$t1,$t2,$t3,$cnt,$tp,$bufsz,$ccr)=map("%l$_",(0..7));
++($ovf,$i)=($t0,$t1);
++	&load_ccr($bp,"%g4",$ccr);
++	&load_b($bp,$m0,"%o7");		# m0=bp[0]
++
++$code.=<<___;
++	ld	[$n0p+0],	$t0	! pull n0[0..1] value
++	ld	[$n0p+4],	$t1
++	add	%sp, STACK_BIAS+STACK_FRAME, $tp
++	sllx	$t1,	32,	$n0
++	or	$t0,	$n0,	$n0
++
++	ldx	[$ap+0],	$aj	! ap[0]
++
++	mulx	$aj,	$m0,	$lo0	! ap[0]*bp[0]
++	umulxhi	$aj,	$m0,	$hi0
++
++	ldx	[$ap+8],	$aj	! ap[1]
++	add	$ap,	16,	$ap
++	ldx	[$np+0],	$nj	! np[0]
++
++	mulx	$lo0,	$n0,	$m1	! "tp[0]"*n0
++
++	mulx	$aj,	$m0,	$alo	! ap[1]*bp[0]
++	umulxhi	$aj,	$m0,	$aj	! ahi=aj
++
++	mulx	$nj,	$m1,	$lo1	! np[0]*m1
++	umulxhi	$nj,	$m1,	$hi1
++
++	ldx	[$np+8],	$nj	! np[1]
++
++	addcc	$lo0,	$lo1,	$lo1
++	add	$np,	16,	$np
++	addxc	%g0,	$hi1,	$hi1
++
++	mulx	$nj,	$m1,	$nlo	! np[1]*m1
++	umulxhi	$nj,	$m1,	$nj	! nhi=nj
++
++	ba	.L1st_g5
++	sub	$num,	24,	$cnt	! cnt=num-3
++
++.align	16
++.L1st_g5:
++	addcc	$alo,	$hi0,	$lo0
++	addxc	$aj,	%g0,	$hi0
++
++	ldx	[$ap+0],	$aj	! ap[j]
++	addcc	$nlo,	$hi1,	$lo1
++	add	$ap,	8,	$ap
++	addxc	$nj,	%g0,	$hi1	! nhi=nj
++
++	ldx	[$np+0],	$nj	! np[j]
++	mulx	$aj,	$m0,	$alo	! ap[j]*bp[0]
++	add	$np,	8,	$np
++	umulxhi	$aj,	$m0,	$aj	! ahi=aj
++
++	mulx	$nj,	$m1,	$nlo	! np[j]*m1
++	addcc	$lo0,	$lo1,	$lo1	! np[j]*m1+ap[j]*bp[0]
++	umulxhi	$nj,	$m1,	$nj	! nhi=nj
++	addxc	%g0,	$hi1,	$hi1
++	stxa	$lo1,	[$tp]0xe2	! tp[j-1]
++	add	$tp,	8,	$tp	! tp++
++
++	brnz,pt	$cnt,	.L1st_g5
++	sub	$cnt,	8,	$cnt	! j--
++!.L1st_g5
++	addcc	$alo,	$hi0,	$lo0
++	addxc	$aj,	%g0,	$hi0	! ahi=aj
++
++	addcc	$nlo,	$hi1,	$lo1
++	addxc	$nj,	%g0,	$hi1
++	addcc	$lo0,	$lo1,	$lo1	! np[j]*m1+ap[j]*bp[0]
++	addxc	%g0,	$hi1,	$hi1
++	stxa	$lo1,	[$tp]0xe2	! tp[j-1]
++	add	$tp,	8,	$tp
++
++	addcc	$hi0,	$hi1,	$hi1
++	addxc	%g0,	%g0,	$ovf	! upmost overflow bit
++	stxa	$hi1,	[$tp]0xe2
++	add	$tp,	8,	$tp
++
++	ba	.Louter_g5
++	sub	$num,	16,	$i	! i=num-2
++
++.align	16
++.Louter_g5:
++	wr	$ccr,	%g0,	%ccr
++___
++	&load_b($bp,$m0);		# m0=bp[i]
++$code.=<<___;
++	sub	$ap,	$num,	$ap	! rewind
++	sub	$np,	$num,	$np
++	sub	$tp,	$num,	$tp
++
++	ldx	[$ap+0],	$aj	! ap[0]
++	ldx	[$np+0],	$nj	! np[0]
++
++	mulx	$aj,	$m0,	$lo0	! ap[0]*bp[i]
++	ldx	[$tp],		$tj	! tp[0]
++	umulxhi	$aj,	$m0,	$hi0
++	ldx	[$ap+8],	$aj	! ap[1]
++	addcc	$lo0,	$tj,	$lo0	! ap[0]*bp[i]+tp[0]
++	mulx	$aj,	$m0,	$alo	! ap[1]*bp[i]
++	addxc	%g0,	$hi0,	$hi0
++	mulx	$lo0,	$n0,	$m1	! tp[0]*n0
++	umulxhi	$aj,	$m0,	$aj	! ahi=aj
++	mulx	$nj,	$m1,	$lo1	! np[0]*m1
++	add	$ap,	16,	$ap
++	umulxhi	$nj,	$m1,	$hi1
++	ldx	[$np+8],	$nj	! np[1]
++	add	$np,	16,	$np
++	addcc	$lo1,	$lo0,	$lo1
++	mulx	$nj,	$m1,	$nlo	! np[1]*m1
++	addxc	%g0,	$hi1,	$hi1
++	umulxhi	$nj,	$m1,	$nj	! nhi=nj
++
++	ba	.Linner_g5
++	sub	$num,	24,	$cnt	! cnt=num-3
++.align	16
++.Linner_g5:
++	addcc	$alo,	$hi0,	$lo0
++	ldx	[$tp+8],	$tj	! tp[j]
++	addxc	$aj,	%g0,	$hi0	! ahi=aj
++	ldx	[$ap+0],	$aj	! ap[j]
++	add	$ap,	8,	$ap
++	addcc	$nlo,	$hi1,	$lo1
++	mulx	$aj,	$m0,	$alo	! ap[j]*bp[i]
++	addxc	$nj,	%g0,	$hi1	! nhi=nj
++	ldx	[$np+0],	$nj	! np[j]
++	add	$np,	8,	$np
++	umulxhi	$aj,	$m0,	$aj	! ahi=aj
++	addcc	$lo0,	$tj,	$lo0	! ap[j]*bp[i]+tp[j]
++	mulx	$nj,	$m1,	$nlo	! np[j]*m1
++	addxc	%g0,	$hi0,	$hi0
++	umulxhi	$nj,	$m1,	$nj	! nhi=nj
++	addcc	$lo1,	$lo0,	$lo1	! np[j]*m1+ap[j]*bp[i]+tp[j]
++	addxc	%g0,	$hi1,	$hi1
++	stx	$lo1,	[$tp]		! tp[j-1]
++	add	$tp,	8,	$tp
++	brnz,pt	$cnt,	.Linner_g5
++	sub	$cnt,	8,	$cnt
++!.Linner_g5
++	ldx	[$tp+8],	$tj	! tp[j]
++	addcc	$alo,	$hi0,	$lo0
++	addxc	$aj,	%g0,	$hi0	! ahi=aj
++	addcc	$lo0,	$tj,	$lo0	! ap[j]*bp[i]+tp[j]
++	addxc	%g0,	$hi0,	$hi0
++
++	addcc	$nlo,	$hi1,	$lo1
++	addxc	$nj,	%g0,	$hi1	! nhi=nj
++	addcc	$lo1,	$lo0,	$lo1	! np[j]*m1+ap[j]*bp[i]+tp[j]
++	addxc	%g0,	$hi1,	$hi1
++	stx	$lo1,	[$tp]		! tp[j-1]
++
++	subcc	%g0,	$ovf,	%g0	! move upmost overflow to CCR.xcc
++	addxccc	$hi1,	$hi0,	$hi1
++	addxc	%g0,	%g0,	$ovf
++	stx	$hi1,	[$tp+8]
++	add	$tp,	16,	$tp
++
++	brnz,pt	$i,	.Louter_g5
++	sub	$i,	8,	$i
++
++	sub	$ap,	$num,	$ap	! rewind
++	sub	$np,	$num,	$np
++	sub	$tp,	$num,	$tp
++	ba	.Lsub_g5
++	subcc	$num,	8,	$cnt	! cnt=num-1 and clear CCR.xcc
++
++.align	16
++.Lsub_g5:
++	ldx	[$tp],		$tj
++	add	$tp,	8,	$tp
++	ldx	[$np+0],	$nj
++	add	$np,	8,	$np
++	subccc	$tj,	$nj,	$t2	! tp[j]-np[j]
++	srlx	$tj,	32,	$tj
++	srlx	$nj,	32,	$nj
++	subccc	$tj,	$nj,	$t3
++	add	$rp,	8,	$rp
++	st	$t2,	[$rp-4]		! reverse order
++	st	$t3,	[$rp-8]
++	brnz,pt	$cnt,	.Lsub_g5
++	sub	$cnt,	8,	$cnt
++
++	sub	$np,	$num,	$np	! rewind
++	sub	$tp,	$num,	$tp
++	sub	$rp,	$num,	$rp
++
++	subc	$ovf,	%g0,	$ovf	! handle upmost overflow bit
++	and	$tp,	$ovf,	$ap
++	andn	$rp,	$ovf,	$np
++	or	$np,	$ap,	$ap	! ap=borrow?tp:rp
++	ba	.Lcopy_g5
++	sub	$num,	8,	$cnt
++
++.align	16
++.Lcopy_g5:				! copy or in-place refresh
++	ldx	[$ap+0],	$t2
++	add	$ap,	8,	$ap
++	stx	%g0,	[$tp]		! zap
++	add	$tp,	8,	$tp
++	stx	$t2,	[$rp+0]
++	add	$rp,	8,	$rp
++	brnz	$cnt,	.Lcopy_g5
++	sub	$cnt,	8,	$cnt
++
++	mov	1,	%o0
++	ret
++	restore
++.type	bn_mul_mont_gather5_t4, #function
++.size	bn_mul_mont_gather5_t4, .-bn_mul_mont_gather5_t4
++___
++}
++
++$code.=<<___;
++.globl	bn_flip_t4
++.align	32
++bn_flip_t4:
++.Loop_flip:
++	ld	[%o1+0],	%o4
++	sub	%o2,	1,	%o2
++	ld	[%o1+4],	%o5
++	add	%o1,	8,	%o1
++	st	%o5,	[%o0+0]
++	st	%o4,	[%o0+4]
++	brnz	%o2,	.Loop_flip
++	add	%o0,	8,	%o0
++	retl
++	nop
++.type	bn_flip_t4, #function
++.size	bn_flip_t4, .-bn_flip_t4
++
++.globl	bn_flip_n_scatter5_t4
++.align	32
++bn_flip_n_scatter5_t4:
++	sll	%o3,	3,	%o3
++	srl	%o1,	1,	%o1
++	add	%o3,	%o2,	%o2	! &pwrtbl[pwr]
++	sub	%o1,	1,	%o1
++.Loop_flip_n_scatter5:
++	ld	[%o0+0],	%o4	! inp[i]
++	ld	[%o0+4],	%o5
++	add	%o0,	8,	%o0
++	sllx	%o5,	32,	%o5
++	or	%o4,	%o5,	%o5
++	stx	%o5,	[%o2]
++	add	%o2,	32*8,	%o2
++	brnz	%o1,	.Loop_flip_n_scatter5
++	sub	%o1,	1,	%o1
++	retl
++	nop
++.type	bn_flip_n_scatter5_t4, #function
++.size	bn_flip_n_scatter5_t4, .-bn_flip_n_scatter5_t4
++
++.globl	bn_gather5_t4
++.align	32
++bn_gather5_t4:
++___
++	&load_ccr("%o2","%o3","%g1");
++$code.=<<___;
++	sub	%o1,	1,	%o1
++.Loop_gather5:
++___
++	&load_b("%o2","%g1");
++$code.=<<___;
++	stx	%g1,	[%o0]
++	add	%o0,	8,	%o0
++	brnz	%o1,	.Loop_gather5
++	sub	%o1,	1,	%o1
++
++	retl
++	nop
++.type	bn_gather5_t4, #function
++.size	bn_gather5_t4, .-bn_gather5_t4
++
++.asciz	"Montgomery Multiplication for SPARC T4, David S. Miller, Andy Polyakov"
++.align	4
++___
++
++&emit_assembler();
++
++close STDOUT;
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/bn/asm/sparcv8.S b/CryptoPkg/Library/OpensslLib/openssl/crypto/bn/asm/sparcv8.S
+new file mode 100644
+index 0000000..9c31073
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/bn/asm/sparcv8.S
+@@ -0,0 +1,1458 @@
++.ident	"sparcv8.s, Version 1.4"
++.ident	"SPARC v8 ISA artwork by Andy Polyakov "
++
++/*
++ * ====================================================================
++ * Copyright 1999-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ * ====================================================================
++ */
++
++/*
++ * This is my modest contributon to OpenSSL project (see
++ * http://www.openssl.org/ for more information about it) and is
++ * a drop-in SuperSPARC ISA replacement for crypto/bn/bn_asm.c
++ * module. For updates see http://fy.chalmers.se/~appro/hpe/.
++ *
++ * See bn_asm.sparc.v8plus.S for more details.
++ */
++
++/*
++ * Revision history.
++ *
++ * 1.1	- new loop unrolling model(*);
++ * 1.2	- made gas friendly;
++ * 1.3	- fixed problem with /usr/ccs/lib/cpp;
++ * 1.4	- some retunes;
++ *
++ * (*)	see bn_asm.sparc.v8plus.S for details
++ */
++
++.section	".text",#alloc,#execinstr
++.file		"bn_asm.sparc.v8.S"
++
++.align	32
++
++.global bn_mul_add_words
++/*
++ * BN_ULONG bn_mul_add_words(rp,ap,num,w)
++ * BN_ULONG *rp,*ap;
++ * int num;
++ * BN_ULONG w;
++ */
++bn_mul_add_words:
++	cmp	%o2,0
++	bg,a	.L_bn_mul_add_words_proceed
++	ld	[%o1],%g2
++	retl
++	clr	%o0
++
++.L_bn_mul_add_words_proceed:
++	andcc	%o2,-4,%g0
++	bz	.L_bn_mul_add_words_tail
++	clr	%o5
++
++.L_bn_mul_add_words_loop:
++	ld	[%o0],%o4
++	ld	[%o1+4],%g3
++	umul	%o3,%g2,%g2
++	rd	%y,%g1
++	addcc	%o4,%o5,%o4
++	addx	%g1,0,%g1
++	addcc	%o4,%g2,%o4
++	st	%o4,[%o0]
++	addx	%g1,0,%o5
++
++	ld	[%o0+4],%o4
++	ld	[%o1+8],%g2
++	umul	%o3,%g3,%g3
++	dec	4,%o2
++	rd	%y,%g1
++	addcc	%o4,%o5,%o4
++	addx	%g1,0,%g1
++	addcc	%o4,%g3,%o4
++	st	%o4,[%o0+4]
++	addx	%g1,0,%o5
++
++	ld	[%o0+8],%o4
++	ld	[%o1+12],%g3
++	umul	%o3,%g2,%g2
++	inc	16,%o1
++	rd	%y,%g1
++	addcc	%o4,%o5,%o4
++	addx	%g1,0,%g1
++	addcc	%o4,%g2,%o4
++	st	%o4,[%o0+8]
++	addx	%g1,0,%o5
++
++	ld	[%o0+12],%o4
++	umul	%o3,%g3,%g3
++	inc	16,%o0
++	rd	%y,%g1
++	addcc	%o4,%o5,%o4
++	addx	%g1,0,%g1
++	addcc	%o4,%g3,%o4
++	st	%o4,[%o0-4]
++	addx	%g1,0,%o5
++	andcc	%o2,-4,%g0
++	bnz,a	.L_bn_mul_add_words_loop
++	ld	[%o1],%g2
++
++	tst	%o2
++	bnz,a	.L_bn_mul_add_words_tail
++	ld	[%o1],%g2
++.L_bn_mul_add_words_return:
++	retl
++	mov	%o5,%o0
++	nop
++
++.L_bn_mul_add_words_tail:
++	ld	[%o0],%o4
++	umul	%o3,%g2,%g2
++	addcc	%o4,%o5,%o4
++	rd	%y,%g1
++	addx	%g1,0,%g1
++	addcc	%o4,%g2,%o4
++	addx	%g1,0,%o5
++	deccc	%o2
++	bz	.L_bn_mul_add_words_return
++	st	%o4,[%o0]
++
++	ld	[%o1+4],%g2
++	ld	[%o0+4],%o4
++	umul	%o3,%g2,%g2
++	rd	%y,%g1
++	addcc	%o4,%o5,%o4
++	addx	%g1,0,%g1
++	addcc	%o4,%g2,%o4
++	addx	%g1,0,%o5
++	deccc	%o2
++	bz	.L_bn_mul_add_words_return
++	st	%o4,[%o0+4]
++
++	ld	[%o1+8],%g2
++	ld	[%o0+8],%o4
++	umul	%o3,%g2,%g2
++	rd	%y,%g1
++	addcc	%o4,%o5,%o4
++	addx	%g1,0,%g1
++	addcc	%o4,%g2,%o4
++	st	%o4,[%o0+8]
++	retl
++	addx	%g1,0,%o0
++
++.type	bn_mul_add_words,#function
++.size	bn_mul_add_words,(.-bn_mul_add_words)
++
++.align	32
++
++.global bn_mul_words
++/*
++ * BN_ULONG bn_mul_words(rp,ap,num,w)
++ * BN_ULONG *rp,*ap;
++ * int num;
++ * BN_ULONG w;
++ */
++bn_mul_words:
++	cmp	%o2,0
++	bg,a	.L_bn_mul_words_proceeed
++	ld	[%o1],%g2
++	retl
++	clr	%o0
++
++.L_bn_mul_words_proceeed:
++	andcc	%o2,-4,%g0
++	bz	.L_bn_mul_words_tail
++	clr	%o5
++
++.L_bn_mul_words_loop:
++	ld	[%o1+4],%g3
++	umul	%o3,%g2,%g2
++	addcc	%g2,%o5,%g2
++	rd	%y,%g1
++	addx	%g1,0,%o5
++	st	%g2,[%o0]
++
++	ld	[%o1+8],%g2
++	umul	%o3,%g3,%g3
++	addcc	%g3,%o5,%g3
++	rd	%y,%g1
++	dec	4,%o2
++	addx	%g1,0,%o5
++	st	%g3,[%o0+4]
++
++	ld	[%o1+12],%g3
++	umul	%o3,%g2,%g2
++	addcc	%g2,%o5,%g2
++	rd	%y,%g1
++	inc	16,%o1
++	st	%g2,[%o0+8]
++	addx	%g1,0,%o5
++
++	umul	%o3,%g3,%g3
++	addcc	%g3,%o5,%g3
++	rd	%y,%g1
++	inc	16,%o0
++	addx	%g1,0,%o5
++	st	%g3,[%o0-4]
++	andcc	%o2,-4,%g0
++	nop
++	bnz,a	.L_bn_mul_words_loop
++	ld	[%o1],%g2
++
++	tst	%o2
++	bnz,a	.L_bn_mul_words_tail
++	ld	[%o1],%g2
++.L_bn_mul_words_return:
++	retl
++	mov	%o5,%o0
++	nop
++
++.L_bn_mul_words_tail:
++	umul	%o3,%g2,%g2
++	addcc	%g2,%o5,%g2
++	rd	%y,%g1
++	addx	%g1,0,%o5
++	deccc	%o2
++	bz	.L_bn_mul_words_return
++	st	%g2,[%o0]
++	nop
++
++	ld	[%o1+4],%g2
++	umul	%o3,%g2,%g2
++	addcc	%g2,%o5,%g2
++	rd	%y,%g1
++	addx	%g1,0,%o5
++	deccc	%o2
++	bz	.L_bn_mul_words_return
++	st	%g2,[%o0+4]
++
++	ld	[%o1+8],%g2
++	umul	%o3,%g2,%g2
++	addcc	%g2,%o5,%g2
++	rd	%y,%g1
++	st	%g2,[%o0+8]
++	retl
++	addx	%g1,0,%o0
++
++.type	bn_mul_words,#function
++.size	bn_mul_words,(.-bn_mul_words)
++
++.align  32
++.global	bn_sqr_words
++/*
++ * void bn_sqr_words(r,a,n)
++ * BN_ULONG *r,*a;
++ * int n;
++ */
++bn_sqr_words:
++	cmp	%o2,0
++	bg,a	.L_bn_sqr_words_proceeed
++	ld	[%o1],%g2
++	retl
++	clr	%o0
++
++.L_bn_sqr_words_proceeed:
++	andcc	%o2,-4,%g0
++	bz	.L_bn_sqr_words_tail
++	clr	%o5
++
++.L_bn_sqr_words_loop:
++	ld	[%o1+4],%g3
++	umul	%g2,%g2,%o4
++	st	%o4,[%o0]
++	rd	%y,%o5
++	st	%o5,[%o0+4]
++
++	ld	[%o1+8],%g2
++	umul	%g3,%g3,%o4
++	dec	4,%o2
++	st	%o4,[%o0+8]
++	rd	%y,%o5
++	st	%o5,[%o0+12]
++	nop
++
++	ld	[%o1+12],%g3
++	umul	%g2,%g2,%o4
++	st	%o4,[%o0+16]
++	rd	%y,%o5
++	inc	16,%o1
++	st	%o5,[%o0+20]
++
++	umul	%g3,%g3,%o4
++	inc	32,%o0
++	st	%o4,[%o0-8]
++	rd	%y,%o5
++	st	%o5,[%o0-4]
++	andcc	%o2,-4,%g2
++	bnz,a	.L_bn_sqr_words_loop
++	ld	[%o1],%g2
++
++	tst	%o2
++	nop
++	bnz,a	.L_bn_sqr_words_tail
++	ld	[%o1],%g2
++.L_bn_sqr_words_return:
++	retl
++	clr	%o0
++
++.L_bn_sqr_words_tail:
++	umul	%g2,%g2,%o4
++	st	%o4,[%o0]
++	deccc	%o2
++	rd	%y,%o5
++	bz	.L_bn_sqr_words_return
++	st	%o5,[%o0+4]
++
++	ld	[%o1+4],%g2
++	umul	%g2,%g2,%o4
++	st	%o4,[%o0+8]
++	deccc	%o2
++	rd	%y,%o5
++	nop
++	bz	.L_bn_sqr_words_return
++	st	%o5,[%o0+12]
++
++	ld	[%o1+8],%g2
++	umul	%g2,%g2,%o4
++	st	%o4,[%o0+16]
++	rd	%y,%o5
++	st	%o5,[%o0+20]
++	retl
++	clr	%o0
++
++.type	bn_sqr_words,#function
++.size	bn_sqr_words,(.-bn_sqr_words)
++
++.align	32
++
++.global bn_div_words
++/*
++ * BN_ULONG bn_div_words(h,l,d)
++ * BN_ULONG h,l,d;
++ */
++bn_div_words:
++	wr	%o0,%y
++	udiv	%o1,%o2,%o0
++	retl
++	nop
++
++.type	bn_div_words,#function
++.size	bn_div_words,(.-bn_div_words)
++
++.align	32
++
++.global bn_add_words
++/*
++ * BN_ULONG bn_add_words(rp,ap,bp,n)
++ * BN_ULONG *rp,*ap,*bp;
++ * int n;
++ */
++bn_add_words:
++	cmp	%o3,0
++	bg,a	.L_bn_add_words_proceed
++	ld	[%o1],%o4
++	retl
++	clr	%o0
++
++.L_bn_add_words_proceed:
++	andcc	%o3,-4,%g0
++	bz	.L_bn_add_words_tail
++	clr	%g1
++	ba	.L_bn_add_words_warn_loop
++	addcc	%g0,0,%g0	! clear carry flag
++
++.L_bn_add_words_loop:
++	ld	[%o1],%o4
++.L_bn_add_words_warn_loop:
++	ld	[%o2],%o5
++	ld	[%o1+4],%g3
++	ld	[%o2+4],%g4
++	dec	4,%o3
++	addxcc	%o5,%o4,%o5
++	st	%o5,[%o0]
++
++	ld	[%o1+8],%o4
++	ld	[%o2+8],%o5
++	inc	16,%o1
++	addxcc	%g3,%g4,%g3
++	st	%g3,[%o0+4]
++	
++	ld	[%o1-4],%g3
++	ld	[%o2+12],%g4
++	inc	16,%o2
++	addxcc	%o5,%o4,%o5
++	st	%o5,[%o0+8]
++
++	inc	16,%o0
++	addxcc	%g3,%g4,%g3
++	st	%g3,[%o0-4]
++	addx	%g0,0,%g1
++	andcc	%o3,-4,%g0
++	bnz,a	.L_bn_add_words_loop
++	addcc	%g1,-1,%g0
++
++	tst	%o3
++	bnz,a	.L_bn_add_words_tail
++	ld	[%o1],%o4
++.L_bn_add_words_return:
++	retl
++	mov	%g1,%o0
++
++.L_bn_add_words_tail:
++	addcc	%g1,-1,%g0
++	ld	[%o2],%o5
++	addxcc	%o5,%o4,%o5
++	addx	%g0,0,%g1
++	deccc	%o3
++	bz	.L_bn_add_words_return
++	st	%o5,[%o0]
++
++	ld	[%o1+4],%o4
++	addcc	%g1,-1,%g0
++	ld	[%o2+4],%o5
++	addxcc	%o5,%o4,%o5
++	addx	%g0,0,%g1
++	deccc	%o3
++	bz	.L_bn_add_words_return
++	st	%o5,[%o0+4]
++
++	ld	[%o1+8],%o4
++	addcc	%g1,-1,%g0
++	ld	[%o2+8],%o5
++	addxcc	%o5,%o4,%o5
++	st	%o5,[%o0+8]
++	retl
++	addx	%g0,0,%o0
++
++.type	bn_add_words,#function
++.size	bn_add_words,(.-bn_add_words)
++
++.align	32
++
++.global bn_sub_words
++/*
++ * BN_ULONG bn_sub_words(rp,ap,bp,n)
++ * BN_ULONG *rp,*ap,*bp;
++ * int n;
++ */
++bn_sub_words:
++	cmp	%o3,0
++	bg,a	.L_bn_sub_words_proceed
++	ld	[%o1],%o4
++	retl
++	clr	%o0
++
++.L_bn_sub_words_proceed:
++	andcc	%o3,-4,%g0
++	bz	.L_bn_sub_words_tail
++	clr	%g1
++	ba	.L_bn_sub_words_warm_loop
++	addcc	%g0,0,%g0	! clear carry flag
++
++.L_bn_sub_words_loop:
++	ld	[%o1],%o4
++.L_bn_sub_words_warm_loop:
++	ld	[%o2],%o5
++	ld	[%o1+4],%g3
++	ld	[%o2+4],%g4
++	dec	4,%o3
++	subxcc	%o4,%o5,%o5
++	st	%o5,[%o0]
++
++	ld	[%o1+8],%o4
++	ld	[%o2+8],%o5
++	inc	16,%o1
++	subxcc	%g3,%g4,%g4
++	st	%g4,[%o0+4]
++	
++	ld	[%o1-4],%g3
++	ld	[%o2+12],%g4
++	inc	16,%o2
++	subxcc	%o4,%o5,%o5
++	st	%o5,[%o0+8]
++
++	inc	16,%o0
++	subxcc	%g3,%g4,%g4
++	st	%g4,[%o0-4]
++	addx	%g0,0,%g1
++	andcc	%o3,-4,%g0
++	bnz,a	.L_bn_sub_words_loop
++	addcc	%g1,-1,%g0
++
++	tst	%o3
++	nop
++	bnz,a	.L_bn_sub_words_tail
++	ld	[%o1],%o4
++.L_bn_sub_words_return:
++	retl
++	mov	%g1,%o0
++
++.L_bn_sub_words_tail:
++	addcc	%g1,-1,%g0
++	ld	[%o2],%o5
++	subxcc	%o4,%o5,%o5
++	addx	%g0,0,%g1
++	deccc	%o3
++	bz	.L_bn_sub_words_return
++	st	%o5,[%o0]
++	nop
++
++	ld	[%o1+4],%o4
++	addcc	%g1,-1,%g0
++	ld	[%o2+4],%o5
++	subxcc	%o4,%o5,%o5
++	addx	%g0,0,%g1
++	deccc	%o3
++	bz	.L_bn_sub_words_return
++	st	%o5,[%o0+4]
++
++	ld	[%o1+8],%o4
++	addcc	%g1,-1,%g0
++	ld	[%o2+8],%o5
++	subxcc	%o4,%o5,%o5
++	st	%o5,[%o0+8]
++	retl
++	addx	%g0,0,%o0
++
++.type	bn_sub_words,#function
++.size	bn_sub_words,(.-bn_sub_words)
++
++#define FRAME_SIZE	-96
++
++/*
++ * Here is register usage map for *all* routines below.
++ */
++#define t_1	%o0
++#define	t_2	%o1
++#define c_1	%o2
++#define c_2	%o3
++#define c_3	%o4
++
++#define ap(I)	[%i1+4*I]
++#define bp(I)	[%i2+4*I]
++#define rp(I)	[%i0+4*I]
++
++#define	a_0	%l0
++#define	a_1	%l1
++#define	a_2	%l2
++#define	a_3	%l3
++#define	a_4	%l4
++#define	a_5	%l5
++#define	a_6	%l6
++#define	a_7	%l7
++
++#define	b_0	%i3
++#define	b_1	%i4
++#define	b_2	%i5
++#define	b_3	%o5
++#define	b_4	%g1
++#define	b_5	%g2
++#define	b_6	%g3
++#define	b_7	%g4
++
++.align	32
++.global bn_mul_comba8
++/*
++ * void bn_mul_comba8(r,a,b)
++ * BN_ULONG *r,*a,*b;
++ */
++bn_mul_comba8:
++	save	%sp,FRAME_SIZE,%sp
++	ld	ap(0),a_0
++	ld	bp(0),b_0
++	umul	a_0,b_0,c_1	!=!mul_add_c(a[0],b[0],c1,c2,c3);
++	ld	bp(1),b_1
++	rd	%y,c_2
++	st	c_1,rp(0)	!r[0]=c1;
++
++	umul	a_0,b_1,t_1	!=!mul_add_c(a[0],b[1],c2,c3,c1);
++	ld	ap(1),a_1
++	addcc	c_2,t_1,c_2
++	rd	%y,t_2
++	addxcc	%g0,t_2,c_3	!=
++	addx	%g0,%g0,c_1
++	ld	ap(2),a_2
++	umul	a_1,b_0,t_1	!mul_add_c(a[1],b[0],c2,c3,c1);
++	addcc	c_2,t_1,c_2	!=
++	rd	%y,t_2
++	addxcc	c_3,t_2,c_3
++	st	c_2,rp(1)	!r[1]=c2;
++	addx	c_1,%g0,c_1	!=
++
++	umul	a_2,b_0,t_1	!mul_add_c(a[2],b[0],c3,c1,c2);
++	addcc	c_3,t_1,c_3
++	rd	%y,t_2
++	addxcc	c_1,t_2,c_1	!=
++	addx	%g0,%g0,c_2
++	ld	bp(2),b_2
++	umul	a_1,b_1,t_1	!mul_add_c(a[1],b[1],c3,c1,c2);
++	addcc	c_3,t_1,c_3	!=
++	rd	%y,t_2
++	addxcc	c_1,t_2,c_1
++	ld	bp(3),b_3
++	addx	c_2,%g0,c_2	!=
++	umul	a_0,b_2,t_1	!mul_add_c(a[0],b[2],c3,c1,c2);
++	addcc	c_3,t_1,c_3
++	rd	%y,t_2
++	addxcc	c_1,t_2,c_1	!=
++	addx	c_2,%g0,c_2
++	st	c_3,rp(2)	!r[2]=c3;
++
++	umul	a_0,b_3,t_1	!mul_add_c(a[0],b[3],c1,c2,c3);
++	addcc	c_1,t_1,c_1	!=
++	rd	%y,t_2
++	addxcc	c_2,t_2,c_2
++	addx	%g0,%g0,c_3
++	umul	a_1,b_2,t_1	!=!mul_add_c(a[1],b[2],c1,c2,c3);
++	addcc	c_1,t_1,c_1
++	rd	%y,t_2
++	addxcc	c_2,t_2,c_2
++	addx	c_3,%g0,c_3	!=
++	ld	ap(3),a_3
++	umul	a_2,b_1,t_1	!mul_add_c(a[2],b[1],c1,c2,c3);
++	addcc	c_1,t_1,c_1
++	rd	%y,t_2		!=
++	addxcc	c_2,t_2,c_2
++	addx	c_3,%g0,c_3
++	ld	ap(4),a_4
++	umul	a_3,b_0,t_1	!mul_add_c(a[3],b[0],c1,c2,c3);!=
++	addcc	c_1,t_1,c_1
++	rd	%y,t_2
++	addxcc	c_2,t_2,c_2
++	addx	c_3,%g0,c_3	!=
++	st	c_1,rp(3)	!r[3]=c1;
++
++	umul	a_4,b_0,t_1	!mul_add_c(a[4],b[0],c2,c3,c1);
++	addcc	c_2,t_1,c_2
++	rd	%y,t_2		!=
++	addxcc	c_3,t_2,c_3
++	addx	%g0,%g0,c_1
++	umul	a_3,b_1,t_1	!mul_add_c(a[3],b[1],c2,c3,c1);
++	addcc	c_2,t_1,c_2	!=
++	rd	%y,t_2
++	addxcc	c_3,t_2,c_3
++	addx	c_1,%g0,c_1
++	umul	a_2,b_2,t_1	!=!mul_add_c(a[2],b[2],c2,c3,c1);
++	addcc	c_2,t_1,c_2
++	rd	%y,t_2
++	addxcc	c_3,t_2,c_3
++	addx	c_1,%g0,c_1	!=
++	ld	bp(4),b_4
++	umul	a_1,b_3,t_1	!mul_add_c(a[1],b[3],c2,c3,c1);
++	addcc	c_2,t_1,c_2
++	rd	%y,t_2		!=
++	addxcc	c_3,t_2,c_3
++	addx	c_1,%g0,c_1
++	ld	bp(5),b_5
++	umul	a_0,b_4,t_1	!=!mul_add_c(a[0],b[4],c2,c3,c1);
++	addcc	c_2,t_1,c_2
++	rd	%y,t_2
++	addxcc	c_3,t_2,c_3
++	addx	c_1,%g0,c_1	!=
++	st	c_2,rp(4)	!r[4]=c2;
++
++	umul	a_0,b_5,t_1	!mul_add_c(a[0],b[5],c3,c1,c2);
++	addcc	c_3,t_1,c_3
++	rd	%y,t_2		!=
++	addxcc	c_1,t_2,c_1
++	addx	%g0,%g0,c_2
++	umul	a_1,b_4,t_1	!mul_add_c(a[1],b[4],c3,c1,c2);
++	addcc	c_3,t_1,c_3	!=
++	rd	%y,t_2
++	addxcc	c_1,t_2,c_1
++	addx	c_2,%g0,c_2
++	umul	a_2,b_3,t_1	!=!mul_add_c(a[2],b[3],c3,c1,c2);
++	addcc	c_3,t_1,c_3
++	rd	%y,t_2
++	addxcc	c_1,t_2,c_1
++	addx	c_2,%g0,c_2	!=
++	umul	a_3,b_2,t_1	!mul_add_c(a[3],b[2],c3,c1,c2);
++	addcc	c_3,t_1,c_3
++	rd	%y,t_2
++	addxcc	c_1,t_2,c_1	!=
++	addx	c_2,%g0,c_2
++	ld	ap(5),a_5
++	umul	a_4,b_1,t_1	!mul_add_c(a[4],b[1],c3,c1,c2);
++	addcc	c_3,t_1,c_3	!=
++	rd	%y,t_2
++	addxcc	c_1,t_2,c_1
++	ld	ap(6),a_6
++	addx	c_2,%g0,c_2	!=
++	umul	a_5,b_0,t_1	!mul_add_c(a[5],b[0],c3,c1,c2);
++	addcc	c_3,t_1,c_3
++	rd	%y,t_2
++	addxcc	c_1,t_2,c_1	!=
++	addx	c_2,%g0,c_2
++	st	c_3,rp(5)	!r[5]=c3;
++
++	umul	a_6,b_0,t_1	!mul_add_c(a[6],b[0],c1,c2,c3);
++	addcc	c_1,t_1,c_1	!=
++	rd	%y,t_2
++	addxcc	c_2,t_2,c_2
++	addx	%g0,%g0,c_3
++	umul	a_5,b_1,t_1	!=!mul_add_c(a[5],b[1],c1,c2,c3);
++	addcc	c_1,t_1,c_1
++	rd	%y,t_2
++	addxcc	c_2,t_2,c_2
++	addx	c_3,%g0,c_3	!=
++	umul	a_4,b_2,t_1	!mul_add_c(a[4],b[2],c1,c2,c3);
++	addcc	c_1,t_1,c_1
++	rd	%y,t_2
++	addxcc	c_2,t_2,c_2	!=
++	addx	c_3,%g0,c_3
++	umul	a_3,b_3,t_1	!mul_add_c(a[3],b[3],c1,c2,c3);
++	addcc	c_1,t_1,c_1
++	rd	%y,t_2		!=
++	addxcc	c_2,t_2,c_2
++	addx	c_3,%g0,c_3
++	umul	a_2,b_4,t_1	!mul_add_c(a[2],b[4],c1,c2,c3);
++	addcc	c_1,t_1,c_1	!=
++	rd	%y,t_2
++	addxcc	c_2,t_2,c_2
++	ld	bp(6),b_6
++	addx	c_3,%g0,c_3	!=
++	umul	a_1,b_5,t_1	!mul_add_c(a[1],b[5],c1,c2,c3);
++	addcc	c_1,t_1,c_1
++	rd	%y,t_2
++	addxcc	c_2,t_2,c_2	!=
++	addx	c_3,%g0,c_3
++	ld	bp(7),b_7
++	umul	a_0,b_6,t_1	!mul_add_c(a[0],b[6],c1,c2,c3);
++	addcc	c_1,t_1,c_1	!=
++	rd	%y,t_2
++	addxcc	c_2,t_2,c_2
++	st	c_1,rp(6)	!r[6]=c1;
++	addx	c_3,%g0,c_3	!=
++
++	umul	a_0,b_7,t_1	!mul_add_c(a[0],b[7],c2,c3,c1);
++	addcc	c_2,t_1,c_2
++	rd	%y,t_2
++	addxcc	c_3,t_2,c_3	!=
++	addx	%g0,%g0,c_1
++	umul	a_1,b_6,t_1	!mul_add_c(a[1],b[6],c2,c3,c1);
++	addcc	c_2,t_1,c_2
++	rd	%y,t_2		!=
++	addxcc	c_3,t_2,c_3
++	addx	c_1,%g0,c_1
++	umul	a_2,b_5,t_1	!mul_add_c(a[2],b[5],c2,c3,c1);
++	addcc	c_2,t_1,c_2	!=
++	rd	%y,t_2
++	addxcc	c_3,t_2,c_3
++	addx	c_1,%g0,c_1
++	umul	a_3,b_4,t_1	!=!mul_add_c(a[3],b[4],c2,c3,c1);
++	addcc	c_2,t_1,c_2
++	rd	%y,t_2
++	addxcc	c_3,t_2,c_3
++	addx	c_1,%g0,c_1	!=
++	umul	a_4,b_3,t_1	!mul_add_c(a[4],b[3],c2,c3,c1);
++	addcc	c_2,t_1,c_2
++	rd	%y,t_2
++	addxcc	c_3,t_2,c_3	!=
++	addx	c_1,%g0,c_1
++	umul	a_5,b_2,t_1	!mul_add_c(a[5],b[2],c2,c3,c1);
++	addcc	c_2,t_1,c_2
++	rd	%y,t_2		!=
++	addxcc	c_3,t_2,c_3
++	addx	c_1,%g0,c_1
++	ld	ap(7),a_7
++	umul	a_6,b_1,t_1	!=!mul_add_c(a[6],b[1],c2,c3,c1);
++	addcc	c_2,t_1,c_2
++	rd	%y,t_2
++	addxcc	c_3,t_2,c_3
++	addx	c_1,%g0,c_1	!=
++	umul	a_7,b_0,t_1	!mul_add_c(a[7],b[0],c2,c3,c1);
++	addcc	c_2,t_1,c_2
++	rd	%y,t_2
++	addxcc	c_3,t_2,c_3	!=
++	addx	c_1,%g0,c_1
++	st	c_2,rp(7)	!r[7]=c2;
++
++	umul	a_7,b_1,t_1	!mul_add_c(a[7],b[1],c3,c1,c2);
++	addcc	c_3,t_1,c_3	!=
++	rd	%y,t_2
++	addxcc	c_1,t_2,c_1
++	addx	%g0,%g0,c_2
++	umul	a_6,b_2,t_1	!=!mul_add_c(a[6],b[2],c3,c1,c2);
++	addcc	c_3,t_1,c_3
++	rd	%y,t_2
++	addxcc	c_1,t_2,c_1
++	addx	c_2,%g0,c_2	!=
++	umul	a_5,b_3,t_1	!mul_add_c(a[5],b[3],c3,c1,c2);
++	addcc	c_3,t_1,c_3
++	rd	%y,t_2
++	addxcc	c_1,t_2,c_1	!=
++	addx	c_2,%g0,c_2
++	umul	a_4,b_4,t_1	!mul_add_c(a[4],b[4],c3,c1,c2);
++	addcc	c_3,t_1,c_3
++	rd	%y,t_2		!=
++	addxcc	c_1,t_2,c_1
++	addx	c_2,%g0,c_2
++	umul	a_3,b_5,t_1	!mul_add_c(a[3],b[5],c3,c1,c2);
++	addcc	c_3,t_1,c_3	!=
++	rd	%y,t_2
++	addxcc	c_1,t_2,c_1
++	addx	c_2,%g0,c_2
++	umul	a_2,b_6,t_1	!=!mul_add_c(a[2],b[6],c3,c1,c2);
++	addcc	c_3,t_1,c_3
++	rd	%y,t_2
++	addxcc	c_1,t_2,c_1
++	addx	c_2,%g0,c_2	!=
++	umul	a_1,b_7,t_1	!mul_add_c(a[1],b[7],c3,c1,c2);
++	addcc	c_3,t_1,c_3
++	rd	%y,t_2
++	addxcc	c_1,t_2,c_1	!
++	addx	c_2,%g0,c_2
++	st	c_3,rp(8)	!r[8]=c3;
++
++	umul	a_2,b_7,t_1	!mul_add_c(a[2],b[7],c1,c2,c3);
++	addcc	c_1,t_1,c_1	!=
++	rd	%y,t_2
++	addxcc	c_2,t_2,c_2
++	addx	%g0,%g0,c_3
++	umul	a_3,b_6,t_1	!=!mul_add_c(a[3],b[6],c1,c2,c3);
++	addcc	c_1,t_1,c_1
++	rd	%y,t_2
++	addxcc	c_2,t_2,c_2
++	addx	c_3,%g0,c_3	!=
++	umul	a_4,b_5,t_1	!mul_add_c(a[4],b[5],c1,c2,c3);
++	addcc	c_1,t_1,c_1
++	rd	%y,t_2
++	addxcc	c_2,t_2,c_2	!=
++	addx	c_3,%g0,c_3
++	umul	a_5,b_4,t_1	!mul_add_c(a[5],b[4],c1,c2,c3);
++	addcc	c_1,t_1,c_1
++	rd	%y,t_2		!=
++	addxcc	c_2,t_2,c_2
++	addx	c_3,%g0,c_3
++	umul	a_6,b_3,t_1	!mul_add_c(a[6],b[3],c1,c2,c3);
++	addcc	c_1,t_1,c_1	!=
++	rd	%y,t_2
++	addxcc	c_2,t_2,c_2
++	addx	c_3,%g0,c_3
++	umul	a_7,b_2,t_1	!=!mul_add_c(a[7],b[2],c1,c2,c3);
++	addcc	c_1,t_1,c_1
++	rd	%y,t_2
++	addxcc	c_2,t_2,c_2
++	addx	c_3,%g0,c_3	!=
++	st	c_1,rp(9)	!r[9]=c1;
++
++	umul	a_7,b_3,t_1	!mul_add_c(a[7],b[3],c2,c3,c1);
++	addcc	c_2,t_1,c_2
++	rd	%y,t_2		!=
++	addxcc	c_3,t_2,c_3
++	addx	%g0,%g0,c_1
++	umul	a_6,b_4,t_1	!mul_add_c(a[6],b[4],c2,c3,c1);
++	addcc	c_2,t_1,c_2	!=
++	rd	%y,t_2
++	addxcc	c_3,t_2,c_3
++	addx	c_1,%g0,c_1
++	umul	a_5,b_5,t_1	!=!mul_add_c(a[5],b[5],c2,c3,c1);
++	addcc	c_2,t_1,c_2
++	rd	%y,t_2
++	addxcc	c_3,t_2,c_3
++	addx	c_1,%g0,c_1	!=
++	umul	a_4,b_6,t_1	!mul_add_c(a[4],b[6],c2,c3,c1);
++	addcc	c_2,t_1,c_2
++	rd	%y,t_2
++	addxcc	c_3,t_2,c_3	!=
++	addx	c_1,%g0,c_1
++	umul	a_3,b_7,t_1	!mul_add_c(a[3],b[7],c2,c3,c1);
++	addcc	c_2,t_1,c_2
++	rd	%y,t_2		!=
++	addxcc	c_3,t_2,c_3
++	addx	c_1,%g0,c_1
++	st	c_2,rp(10)	!r[10]=c2;
++
++	umul	a_4,b_7,t_1	!=!mul_add_c(a[4],b[7],c3,c1,c2);
++	addcc	c_3,t_1,c_3
++	rd	%y,t_2
++	addxcc	c_1,t_2,c_1
++	addx	%g0,%g0,c_2	!=
++	umul	a_5,b_6,t_1	!mul_add_c(a[5],b[6],c3,c1,c2);
++	addcc	c_3,t_1,c_3
++	rd	%y,t_2
++	addxcc	c_1,t_2,c_1	!=
++	addx	c_2,%g0,c_2
++	umul	a_6,b_5,t_1	!mul_add_c(a[6],b[5],c3,c1,c2);
++	addcc	c_3,t_1,c_3
++	rd	%y,t_2		!=
++	addxcc	c_1,t_2,c_1
++	addx	c_2,%g0,c_2
++	umul	a_7,b_4,t_1	!mul_add_c(a[7],b[4],c3,c1,c2);
++	addcc	c_3,t_1,c_3	!=
++	rd	%y,t_2
++	addxcc	c_1,t_2,c_1
++	st	c_3,rp(11)	!r[11]=c3;
++	addx	c_2,%g0,c_2	!=
++
++	umul	a_7,b_5,t_1	!mul_add_c(a[7],b[5],c1,c2,c3);
++	addcc	c_1,t_1,c_1
++	rd	%y,t_2
++	addxcc	c_2,t_2,c_2	!=
++	addx	%g0,%g0,c_3
++	umul	a_6,b_6,t_1	!mul_add_c(a[6],b[6],c1,c2,c3);
++	addcc	c_1,t_1,c_1
++	rd	%y,t_2		!=
++	addxcc	c_2,t_2,c_2
++	addx	c_3,%g0,c_3
++	umul	a_5,b_7,t_1	!mul_add_c(a[5],b[7],c1,c2,c3);
++	addcc	c_1,t_1,c_1	!=
++	rd	%y,t_2
++	addxcc	c_2,t_2,c_2
++	st	c_1,rp(12)	!r[12]=c1;
++	addx	c_3,%g0,c_3	!=
++
++	umul	a_6,b_7,t_1	!mul_add_c(a[6],b[7],c2,c3,c1);
++	addcc	c_2,t_1,c_2
++	rd	%y,t_2
++	addxcc	c_3,t_2,c_3	!=
++	addx	%g0,%g0,c_1
++	umul	a_7,b_6,t_1	!mul_add_c(a[7],b[6],c2,c3,c1);
++	addcc	c_2,t_1,c_2
++	rd	%y,t_2		!=
++	addxcc	c_3,t_2,c_3
++	addx	c_1,%g0,c_1
++	st	c_2,rp(13)	!r[13]=c2;
++
++	umul	a_7,b_7,t_1	!=!mul_add_c(a[7],b[7],c3,c1,c2);
++	addcc	c_3,t_1,c_3
++	rd	%y,t_2
++	addxcc	c_1,t_2,c_1
++	nop			!=
++	st	c_3,rp(14)	!r[14]=c3;
++	st	c_1,rp(15)	!r[15]=c1;
++
++	ret
++	restore	%g0,%g0,%o0
++
++.type	bn_mul_comba8,#function
++.size	bn_mul_comba8,(.-bn_mul_comba8)
++
++.align	32
++
++.global bn_mul_comba4
++/*
++ * void bn_mul_comba4(r,a,b)
++ * BN_ULONG *r,*a,*b;
++ */
++bn_mul_comba4:
++	save	%sp,FRAME_SIZE,%sp
++	ld	ap(0),a_0
++	ld	bp(0),b_0
++	umul	a_0,b_0,c_1	!=!mul_add_c(a[0],b[0],c1,c2,c3);
++	ld	bp(1),b_1
++	rd	%y,c_2
++	st	c_1,rp(0)	!r[0]=c1;
++
++	umul	a_0,b_1,t_1	!=!mul_add_c(a[0],b[1],c2,c3,c1);
++	ld	ap(1),a_1
++	addcc	c_2,t_1,c_2
++	rd	%y,t_2		!=
++	addxcc	%g0,t_2,c_3
++	addx	%g0,%g0,c_1
++	ld	ap(2),a_2
++	umul	a_1,b_0,t_1	!=!mul_add_c(a[1],b[0],c2,c3,c1);
++	addcc	c_2,t_1,c_2
++	rd	%y,t_2
++	addxcc	c_3,t_2,c_3
++	addx	c_1,%g0,c_1	!=
++	st	c_2,rp(1)	!r[1]=c2;
++
++	umul	a_2,b_0,t_1	!mul_add_c(a[2],b[0],c3,c1,c2);
++	addcc	c_3,t_1,c_3
++	rd	%y,t_2		!=
++	addxcc	c_1,t_2,c_1
++	addx	%g0,%g0,c_2
++	ld	bp(2),b_2
++	umul	a_1,b_1,t_1	!=!mul_add_c(a[1],b[1],c3,c1,c2);
++	addcc	c_3,t_1,c_3
++	rd	%y,t_2
++	addxcc	c_1,t_2,c_1
++	addx	c_2,%g0,c_2	!=
++	ld	bp(3),b_3
++	umul	a_0,b_2,t_1	!mul_add_c(a[0],b[2],c3,c1,c2);
++	addcc	c_3,t_1,c_3
++	rd	%y,t_2		!=
++	addxcc	c_1,t_2,c_1
++	addx	c_2,%g0,c_2
++	st	c_3,rp(2)	!r[2]=c3;
++
++	umul	a_0,b_3,t_1	!=!mul_add_c(a[0],b[3],c1,c2,c3);
++	addcc	c_1,t_1,c_1
++	rd	%y,t_2
++	addxcc	c_2,t_2,c_2
++	addx	%g0,%g0,c_3	!=
++	umul	a_1,b_2,t_1	!mul_add_c(a[1],b[2],c1,c2,c3);
++	addcc	c_1,t_1,c_1
++	rd	%y,t_2
++	addxcc	c_2,t_2,c_2	!=
++	addx	c_3,%g0,c_3
++	ld	ap(3),a_3
++	umul	a_2,b_1,t_1	!mul_add_c(a[2],b[1],c1,c2,c3);
++	addcc	c_1,t_1,c_1	!=
++	rd	%y,t_2
++	addxcc	c_2,t_2,c_2
++	addx	c_3,%g0,c_3
++	umul	a_3,b_0,t_1	!=!mul_add_c(a[3],b[0],c1,c2,c3);
++	addcc	c_1,t_1,c_1
++	rd	%y,t_2
++	addxcc	c_2,t_2,c_2
++	addx	c_3,%g0,c_3	!=
++	st	c_1,rp(3)	!r[3]=c1;
++
++	umul	a_3,b_1,t_1	!mul_add_c(a[3],b[1],c2,c3,c1);
++	addcc	c_2,t_1,c_2
++	rd	%y,t_2		!=
++	addxcc	c_3,t_2,c_3
++	addx	%g0,%g0,c_1
++	umul	a_2,b_2,t_1	!mul_add_c(a[2],b[2],c2,c3,c1);
++	addcc	c_2,t_1,c_2	!=
++	rd	%y,t_2
++	addxcc	c_3,t_2,c_3
++	addx	c_1,%g0,c_1
++	umul	a_1,b_3,t_1	!=!mul_add_c(a[1],b[3],c2,c3,c1);
++	addcc	c_2,t_1,c_2
++	rd	%y,t_2
++	addxcc	c_3,t_2,c_3
++	addx	c_1,%g0,c_1	!=
++	st	c_2,rp(4)	!r[4]=c2;
++
++	umul	a_2,b_3,t_1	!mul_add_c(a[2],b[3],c3,c1,c2);
++	addcc	c_3,t_1,c_3
++	rd	%y,t_2		!=
++	addxcc	c_1,t_2,c_1
++	addx	%g0,%g0,c_2
++	umul	a_3,b_2,t_1	!mul_add_c(a[3],b[2],c3,c1,c2);
++	addcc	c_3,t_1,c_3	!=
++	rd	%y,t_2
++	addxcc	c_1,t_2,c_1
++	st	c_3,rp(5)	!r[5]=c3;
++	addx	c_2,%g0,c_2	!=
++
++	umul	a_3,b_3,t_1	!mul_add_c(a[3],b[3],c1,c2,c3);
++	addcc	c_1,t_1,c_1
++	rd	%y,t_2
++	addxcc	c_2,t_2,c_2	!=
++	st	c_1,rp(6)	!r[6]=c1;
++	st	c_2,rp(7)	!r[7]=c2;
++	
++	ret
++	restore	%g0,%g0,%o0
++
++.type	bn_mul_comba4,#function
++.size	bn_mul_comba4,(.-bn_mul_comba4)
++
++.align	32
++
++.global bn_sqr_comba8
++bn_sqr_comba8:
++	save	%sp,FRAME_SIZE,%sp
++	ld	ap(0),a_0
++	ld	ap(1),a_1
++	umul	a_0,a_0,c_1	!=!sqr_add_c(a,0,c1,c2,c3);
++	rd	%y,c_2
++	st	c_1,rp(0)	!r[0]=c1;
++
++	ld	ap(2),a_2
++	umul	a_0,a_1,t_1	!=!sqr_add_c2(a,1,0,c2,c3,c1);
++	addcc	c_2,t_1,c_2
++	rd	%y,t_2
++	addxcc	%g0,t_2,c_3
++	addx	%g0,%g0,c_1	!=
++	addcc	c_2,t_1,c_2
++	addxcc	c_3,t_2,c_3
++	st	c_2,rp(1)	!r[1]=c2;
++	addx	c_1,%g0,c_1	!=
++
++	umul	a_2,a_0,t_1	!sqr_add_c2(a,2,0,c3,c1,c2);
++	addcc	c_3,t_1,c_3
++	rd	%y,t_2
++	addxcc	c_1,t_2,c_1	!=
++	addx	%g0,%g0,c_2
++	addcc	c_3,t_1,c_3
++	addxcc	c_1,t_2,c_1
++	addx	c_2,%g0,c_2	!=
++	ld	ap(3),a_3
++	umul	a_1,a_1,t_1	!sqr_add_c(a,1,c3,c1,c2);
++	addcc	c_3,t_1,c_3
++	rd	%y,t_2		!=
++	addxcc	c_1,t_2,c_1
++	addx	c_2,%g0,c_2
++	st	c_3,rp(2)	!r[2]=c3;
++
++	umul	a_0,a_3,t_1	!=!sqr_add_c2(a,3,0,c1,c2,c3);
++	addcc	c_1,t_1,c_1
++	rd	%y,t_2
++	addxcc	c_2,t_2,c_2
++	addx	%g0,%g0,c_3	!=
++	addcc	c_1,t_1,c_1
++	addxcc	c_2,t_2,c_2
++	ld	ap(4),a_4
++	addx	c_3,%g0,c_3	!=
++	umul	a_1,a_2,t_1	!sqr_add_c2(a,2,1,c1,c2,c3);
++	addcc	c_1,t_1,c_1
++	rd	%y,t_2
++	addxcc	c_2,t_2,c_2	!=
++	addx	c_3,%g0,c_3
++	addcc	c_1,t_1,c_1
++	addxcc	c_2,t_2,c_2
++	addx	c_3,%g0,c_3	!=
++	st	c_1,rp(3)	!r[3]=c1;
++
++	umul	a_4,a_0,t_1	!sqr_add_c2(a,4,0,c2,c3,c1);
++	addcc	c_2,t_1,c_2
++	rd	%y,t_2		!=
++	addxcc	c_3,t_2,c_3
++	addx	%g0,%g0,c_1
++	addcc	c_2,t_1,c_2
++	addxcc	c_3,t_2,c_3	!=
++	addx	c_1,%g0,c_1
++	umul	a_3,a_1,t_1	!sqr_add_c2(a,3,1,c2,c3,c1);
++	addcc	c_2,t_1,c_2
++	rd	%y,t_2		!=
++	addxcc	c_3,t_2,c_3
++	addx	c_1,%g0,c_1
++	addcc	c_2,t_1,c_2
++	addxcc	c_3,t_2,c_3	!=
++	addx	c_1,%g0,c_1
++	ld	ap(5),a_5
++	umul	a_2,a_2,t_1	!sqr_add_c(a,2,c2,c3,c1);
++	addcc	c_2,t_1,c_2	!=
++	rd	%y,t_2
++	addxcc	c_3,t_2,c_3
++	st	c_2,rp(4)	!r[4]=c2;
++	addx	c_1,%g0,c_1	!=
++
++	umul	a_0,a_5,t_1	!sqr_add_c2(a,5,0,c3,c1,c2);
++	addcc	c_3,t_1,c_3
++	rd	%y,t_2
++	addxcc	c_1,t_2,c_1	!=
++	addx	%g0,%g0,c_2
++	addcc	c_3,t_1,c_3
++	addxcc	c_1,t_2,c_1
++	addx	c_2,%g0,c_2	!=
++	umul	a_1,a_4,t_1	!sqr_add_c2(a,4,1,c3,c1,c2);
++	addcc	c_3,t_1,c_3
++	rd	%y,t_2
++	addxcc	c_1,t_2,c_1	!=
++	addx	c_2,%g0,c_2
++	addcc	c_3,t_1,c_3
++	addxcc	c_1,t_2,c_1
++	addx	c_2,%g0,c_2	!=
++	ld	ap(6),a_6
++	umul	a_2,a_3,t_1	!sqr_add_c2(a,3,2,c3,c1,c2);
++	addcc	c_3,t_1,c_3
++	rd	%y,t_2		!=
++	addxcc	c_1,t_2,c_1
++	addx	c_2,%g0,c_2
++	addcc	c_3,t_1,c_3
++	addxcc	c_1,t_2,c_1	!=
++	addx	c_2,%g0,c_2
++	st	c_3,rp(5)	!r[5]=c3;
++
++	umul	a_6,a_0,t_1	!sqr_add_c2(a,6,0,c1,c2,c3);
++	addcc	c_1,t_1,c_1	!=
++	rd	%y,t_2
++	addxcc	c_2,t_2,c_2
++	addx	%g0,%g0,c_3
++	addcc	c_1,t_1,c_1	!=
++	addxcc	c_2,t_2,c_2
++	addx	c_3,%g0,c_3
++	umul	a_5,a_1,t_1	!sqr_add_c2(a,5,1,c1,c2,c3);
++	addcc	c_1,t_1,c_1	!=
++	rd	%y,t_2
++	addxcc	c_2,t_2,c_2
++	addx	c_3,%g0,c_3
++	addcc	c_1,t_1,c_1	!=
++	addxcc	c_2,t_2,c_2
++	addx	c_3,%g0,c_3
++	umul	a_4,a_2,t_1	!sqr_add_c2(a,4,2,c1,c2,c3);
++	addcc	c_1,t_1,c_1	!=
++	rd	%y,t_2
++	addxcc	c_2,t_2,c_2
++	addx	c_3,%g0,c_3
++	addcc	c_1,t_1,c_1	!=
++	addxcc	c_2,t_2,c_2
++	addx	c_3,%g0,c_3
++	ld	ap(7),a_7
++	umul	a_3,a_3,t_1	!=!sqr_add_c(a,3,c1,c2,c3);
++	addcc	c_1,t_1,c_1
++	rd	%y,t_2
++	addxcc	c_2,t_2,c_2
++	addx	c_3,%g0,c_3	!=
++	st	c_1,rp(6)	!r[6]=c1;
++
++	umul	a_0,a_7,t_1	!sqr_add_c2(a,7,0,c2,c3,c1);
++	addcc	c_2,t_1,c_2
++	rd	%y,t_2		!=
++	addxcc	c_3,t_2,c_3
++	addx	%g0,%g0,c_1
++	addcc	c_2,t_1,c_2
++	addxcc	c_3,t_2,c_3	!=
++	addx	c_1,%g0,c_1
++	umul	a_1,a_6,t_1	!sqr_add_c2(a,6,1,c2,c3,c1);
++	addcc	c_2,t_1,c_2
++	rd	%y,t_2		!=
++	addxcc	c_3,t_2,c_3
++	addx	c_1,%g0,c_1
++	addcc	c_2,t_1,c_2
++	addxcc	c_3,t_2,c_3	!=
++	addx	c_1,%g0,c_1
++	umul	a_2,a_5,t_1	!sqr_add_c2(a,5,2,c2,c3,c1);
++	addcc	c_2,t_1,c_2
++	rd	%y,t_2		!=
++	addxcc	c_3,t_2,c_3
++	addx	c_1,%g0,c_1
++	addcc	c_2,t_1,c_2
++	addxcc	c_3,t_2,c_3	!=
++	addx	c_1,%g0,c_1
++	umul	a_3,a_4,t_1	!sqr_add_c2(a,4,3,c2,c3,c1);
++	addcc	c_2,t_1,c_2
++	rd	%y,t_2		!=
++	addxcc	c_3,t_2,c_3
++	addx	c_1,%g0,c_1
++	addcc	c_2,t_1,c_2
++	addxcc	c_3,t_2,c_3	!=
++	addx	c_1,%g0,c_1
++	st	c_2,rp(7)	!r[7]=c2;
++
++	umul	a_7,a_1,t_1	!sqr_add_c2(a,7,1,c3,c1,c2);
++	addcc	c_3,t_1,c_3	!=
++	rd	%y,t_2
++	addxcc	c_1,t_2,c_1
++	addx	%g0,%g0,c_2
++	addcc	c_3,t_1,c_3	!=
++	addxcc	c_1,t_2,c_1
++	addx	c_2,%g0,c_2
++	umul	a_6,a_2,t_1	!sqr_add_c2(a,6,2,c3,c1,c2);
++	addcc	c_3,t_1,c_3	!=
++	rd	%y,t_2
++	addxcc	c_1,t_2,c_1
++	addx	c_2,%g0,c_2
++	addcc	c_3,t_1,c_3	!=
++	addxcc	c_1,t_2,c_1
++	addx	c_2,%g0,c_2
++	umul	a_5,a_3,t_1	!sqr_add_c2(a,5,3,c3,c1,c2);
++	addcc	c_3,t_1,c_3	!=
++	rd	%y,t_2
++	addxcc	c_1,t_2,c_1
++	addx	c_2,%g0,c_2
++	addcc	c_3,t_1,c_3	!=
++	addxcc	c_1,t_2,c_1
++	addx	c_2,%g0,c_2
++	umul	a_4,a_4,t_1	!sqr_add_c(a,4,c3,c1,c2);
++	addcc	c_3,t_1,c_3	!=
++	rd	%y,t_2
++	addxcc	c_1,t_2,c_1
++	st	c_3,rp(8)	!r[8]=c3;
++	addx	c_2,%g0,c_2	!=
++
++	umul	a_2,a_7,t_1	!sqr_add_c2(a,7,2,c1,c2,c3);
++	addcc	c_1,t_1,c_1
++	rd	%y,t_2
++	addxcc	c_2,t_2,c_2	!=
++	addx	%g0,%g0,c_3
++	addcc	c_1,t_1,c_1
++	addxcc	c_2,t_2,c_2
++	addx	c_3,%g0,c_3	!=
++	umul	a_3,a_6,t_1	!sqr_add_c2(a,6,3,c1,c2,c3);
++	addcc	c_1,t_1,c_1
++	rd	%y,t_2
++	addxcc	c_2,t_2,c_2	!=
++	addx	c_3,%g0,c_3
++	addcc	c_1,t_1,c_1
++	addxcc	c_2,t_2,c_2
++	addx	c_3,%g0,c_3	!=
++	umul	a_4,a_5,t_1	!sqr_add_c2(a,5,4,c1,c2,c3);
++	addcc	c_1,t_1,c_1
++	rd	%y,t_2
++	addxcc	c_2,t_2,c_2	!=
++	addx	c_3,%g0,c_3
++	addcc	c_1,t_1,c_1
++	addxcc	c_2,t_2,c_2
++	addx	c_3,%g0,c_3	!=
++	st	c_1,rp(9)	!r[9]=c1;
++
++	umul	a_7,a_3,t_1	!sqr_add_c2(a,7,3,c2,c3,c1);
++	addcc	c_2,t_1,c_2
++	rd	%y,t_2		!=
++	addxcc	c_3,t_2,c_3
++	addx	%g0,%g0,c_1
++	addcc	c_2,t_1,c_2
++	addxcc	c_3,t_2,c_3	!=
++	addx	c_1,%g0,c_1
++	umul	a_6,a_4,t_1	!sqr_add_c2(a,6,4,c2,c3,c1);
++	addcc	c_2,t_1,c_2
++	rd	%y,t_2		!=
++	addxcc	c_3,t_2,c_3
++	addx	c_1,%g0,c_1
++	addcc	c_2,t_1,c_2
++	addxcc	c_3,t_2,c_3	!=
++	addx	c_1,%g0,c_1
++	umul	a_5,a_5,t_1	!sqr_add_c(a,5,c2,c3,c1);
++	addcc	c_2,t_1,c_2
++	rd	%y,t_2		!=
++	addxcc	c_3,t_2,c_3
++	addx	c_1,%g0,c_1
++	st	c_2,rp(10)	!r[10]=c2;
++
++	umul	a_4,a_7,t_1	!=!sqr_add_c2(a,7,4,c3,c1,c2);
++	addcc	c_3,t_1,c_3
++	rd	%y,t_2
++	addxcc	c_1,t_2,c_1
++	addx	%g0,%g0,c_2	!=
++	addcc	c_3,t_1,c_3
++	addxcc	c_1,t_2,c_1
++	addx	c_2,%g0,c_2
++	umul	a_5,a_6,t_1	!=!sqr_add_c2(a,6,5,c3,c1,c2);
++	addcc	c_3,t_1,c_3
++	rd	%y,t_2
++	addxcc	c_1,t_2,c_1
++	addx	c_2,%g0,c_2	!=
++	addcc	c_3,t_1,c_3
++	addxcc	c_1,t_2,c_1
++	st	c_3,rp(11)	!r[11]=c3;
++	addx	c_2,%g0,c_2	!=
++
++	umul	a_7,a_5,t_1	!sqr_add_c2(a,7,5,c1,c2,c3);
++	addcc	c_1,t_1,c_1
++	rd	%y,t_2
++	addxcc	c_2,t_2,c_2	!=
++	addx	%g0,%g0,c_3
++	addcc	c_1,t_1,c_1
++	addxcc	c_2,t_2,c_2
++	addx	c_3,%g0,c_3	!=
++	umul	a_6,a_6,t_1	!sqr_add_c(a,6,c1,c2,c3);
++	addcc	c_1,t_1,c_1
++	rd	%y,t_2
++	addxcc	c_2,t_2,c_2	!=
++	addx	c_3,%g0,c_3
++	st	c_1,rp(12)	!r[12]=c1;
++
++	umul	a_6,a_7,t_1	!sqr_add_c2(a,7,6,c2,c3,c1);
++	addcc	c_2,t_1,c_2	!=
++	rd	%y,t_2
++	addxcc	c_3,t_2,c_3
++	addx	%g0,%g0,c_1
++	addcc	c_2,t_1,c_2	!=
++	addxcc	c_3,t_2,c_3
++	st	c_2,rp(13)	!r[13]=c2;
++	addx	c_1,%g0,c_1	!=
++
++	umul	a_7,a_7,t_1	!sqr_add_c(a,7,c3,c1,c2);
++	addcc	c_3,t_1,c_3
++	rd	%y,t_2
++	addxcc	c_1,t_2,c_1	!=
++	st	c_3,rp(14)	!r[14]=c3;
++	st	c_1,rp(15)	!r[15]=c1;
++
++	ret
++	restore	%g0,%g0,%o0
++
++.type	bn_sqr_comba8,#function
++.size	bn_sqr_comba8,(.-bn_sqr_comba8)
++
++.align	32
++
++.global bn_sqr_comba4
++/*
++ * void bn_sqr_comba4(r,a)
++ * BN_ULONG *r,*a;
++ */
++bn_sqr_comba4:
++	save	%sp,FRAME_SIZE,%sp
++	ld	ap(0),a_0
++	umul	a_0,a_0,c_1	!sqr_add_c(a,0,c1,c2,c3);
++	ld	ap(1),a_1	!=
++	rd	%y,c_2
++	st	c_1,rp(0)	!r[0]=c1;
++
++	ld	ap(2),a_2
++	umul	a_0,a_1,t_1	!=!sqr_add_c2(a,1,0,c2,c3,c1);
++	addcc	c_2,t_1,c_2
++	rd	%y,t_2
++	addxcc	%g0,t_2,c_3
++	addx	%g0,%g0,c_1	!=
++	addcc	c_2,t_1,c_2
++	addxcc	c_3,t_2,c_3
++	addx	c_1,%g0,c_1	!=
++	st	c_2,rp(1)	!r[1]=c2;
++
++	umul	a_2,a_0,t_1	!sqr_add_c2(a,2,0,c3,c1,c2);
++	addcc	c_3,t_1,c_3
++	rd	%y,t_2		!=
++	addxcc	c_1,t_2,c_1
++	addx	%g0,%g0,c_2
++	addcc	c_3,t_1,c_3
++	addxcc	c_1,t_2,c_1	!=
++	addx	c_2,%g0,c_2
++	ld	ap(3),a_3
++	umul	a_1,a_1,t_1	!sqr_add_c(a,1,c3,c1,c2);
++	addcc	c_3,t_1,c_3	!=
++	rd	%y,t_2
++	addxcc	c_1,t_2,c_1
++	st	c_3,rp(2)	!r[2]=c3;
++	addx	c_2,%g0,c_2	!=
++
++	umul	a_0,a_3,t_1	!sqr_add_c2(a,3,0,c1,c2,c3);
++	addcc	c_1,t_1,c_1
++	rd	%y,t_2
++	addxcc	c_2,t_2,c_2	!=
++	addx	%g0,%g0,c_3
++	addcc	c_1,t_1,c_1
++	addxcc	c_2,t_2,c_2
++	addx	c_3,%g0,c_3	!=
++	umul	a_1,a_2,t_1	!sqr_add_c2(a,2,1,c1,c2,c3);
++	addcc	c_1,t_1,c_1
++	rd	%y,t_2
++	addxcc	c_2,t_2,c_2	!=
++	addx	c_3,%g0,c_3
++	addcc	c_1,t_1,c_1
++	addxcc	c_2,t_2,c_2
++	addx	c_3,%g0,c_3	!=
++	st	c_1,rp(3)	!r[3]=c1;
++
++	umul	a_3,a_1,t_1	!sqr_add_c2(a,3,1,c2,c3,c1);
++	addcc	c_2,t_1,c_2
++	rd	%y,t_2		!=
++	addxcc	c_3,t_2,c_3
++	addx	%g0,%g0,c_1
++	addcc	c_2,t_1,c_2
++	addxcc	c_3,t_2,c_3	!=
++	addx	c_1,%g0,c_1
++	umul	a_2,a_2,t_1	!sqr_add_c(a,2,c2,c3,c1);
++	addcc	c_2,t_1,c_2
++	rd	%y,t_2		!=
++	addxcc	c_3,t_2,c_3
++	addx	c_1,%g0,c_1
++	st	c_2,rp(4)	!r[4]=c2;
++
++	umul	a_2,a_3,t_1	!=!sqr_add_c2(a,3,2,c3,c1,c2);
++	addcc	c_3,t_1,c_3
++	rd	%y,t_2
++	addxcc	c_1,t_2,c_1
++	addx	%g0,%g0,c_2	!=
++	addcc	c_3,t_1,c_3
++	addxcc	c_1,t_2,c_1
++	st	c_3,rp(5)	!r[5]=c3;
++	addx	c_2,%g0,c_2	!=
++
++	umul	a_3,a_3,t_1	!sqr_add_c(a,3,c1,c2,c3);
++	addcc	c_1,t_1,c_1
++	rd	%y,t_2
++	addxcc	c_2,t_2,c_2	!=
++	st	c_1,rp(6)	!r[6]=c1;
++	st	c_2,rp(7)	!r[7]=c2;
++	
++	ret
++	restore	%g0,%g0,%o0
++
++.type	bn_sqr_comba4,#function
++.size	bn_sqr_comba4,(.-bn_sqr_comba4)
++
++.align	32
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/bn/asm/sparcv8plus.S b/CryptoPkg/Library/OpensslLib/openssl/crypto/bn/asm/sparcv8plus.S
+new file mode 100644
+index 0000000..714a136
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/bn/asm/sparcv8plus.S
+@@ -0,0 +1,1562 @@
++.ident	"sparcv8plus.s, Version 1.4"
++.ident	"SPARC v9 ISA artwork by Andy Polyakov "
++
++/*
++ * ====================================================================
++ * Copyright 1999-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ * ====================================================================
++ */
++
++/*
++ * This is my modest contributon to OpenSSL project (see
++ * http://www.openssl.org/ for more information about it) and is
++ * a drop-in UltraSPARC ISA replacement for crypto/bn/bn_asm.c
++ * module. For updates see http://fy.chalmers.se/~appro/hpe/.
++ *
++ * Questions-n-answers.
++ *
++ * Q. How to compile?
++ * A. With SC4.x/SC5.x:
++ *
++ *	cc -xarch=v8plus -c bn_asm.sparc.v8plus.S -o bn_asm.o
++ *
++ *    and with gcc:
++ *
++ *	gcc -mcpu=ultrasparc -c bn_asm.sparc.v8plus.S -o bn_asm.o
++ *
++ *    or if above fails (it does if you have gas installed):
++ *
++ *	gcc -E bn_asm.sparc.v8plus.S | as -xarch=v8plus /dev/fd/0 -o bn_asm.o
++ *
++ *    Quick-n-dirty way to fuse the module into the library.
++ *    Provided that the library is already configured and built
++ *    (in 0.9.2 case with no-asm option):
++ *
++ *	# cd crypto/bn
++ *	# cp /some/place/bn_asm.sparc.v8plus.S .
++ *	# cc -xarch=v8plus -c bn_asm.sparc.v8plus.S -o bn_asm.o
++ *	# make
++ *	# cd ../..
++ *	# make; make test
++ *
++ *    Quick-n-dirty way to get rid of it:
++ *
++ *	# cd crypto/bn
++ *	# touch bn_asm.c
++ *	# make
++ *	# cd ../..
++ *	# make; make test
++ *
++ * Q. V8plus architecture? What kind of beast is that?
++ * A. Well, it's rather a programming model than an architecture...
++ *    It's actually v9-compliant, i.e. *any* UltraSPARC, CPU under
++ *    special conditions, namely when kernel doesn't preserve upper
++ *    32 bits of otherwise 64-bit registers during a context switch.
++ *
++ * Q. Why just UltraSPARC? What about SuperSPARC?
++ * A. Original release did target UltraSPARC only. Now SuperSPARC
++ *    version is provided along. Both version share bn_*comba[48]
++ *    implementations (see comment later in code for explanation).
++ *    But what's so special about this UltraSPARC implementation?
++ *    Why didn't I let compiler do the job? Trouble is that most of
++ *    available compilers (well, SC5.0 is the only exception) don't
++ *    attempt to take advantage of UltraSPARC's 64-bitness under
++ *    32-bit kernels even though it's perfectly possible (see next
++ *    question).
++ *
++ * Q. 64-bit registers under 32-bit kernels? Didn't you just say it
++ *    doesn't work?
++ * A. You can't address *all* registers as 64-bit wide:-( The catch is
++ *    that you actually may rely upon %o0-%o5 and %g1-%g4 being fully
++ *    preserved if you're in a leaf function, i.e. such never calling
++ *    any other functions. All functions in this module are leaf and
++ *    10 registers is a handful. And as a matter of fact none-"comba"
++ *    routines don't require even that much and I could even afford to
++ *    not allocate own stack frame for 'em:-)
++ *
++ * Q. What about 64-bit kernels?
++ * A. What about 'em? Just kidding:-) Pure 64-bit version is currently
++ *    under evaluation and development...
++ *
++ * Q. What about shared libraries?
++ * A. What about 'em? Kidding again:-) Code does *not* contain any
++ *    code position dependencies and it's safe to include it into
++ *    shared library as is.
++ *
++ * Q. How much faster does it go?
++ * A. Do you have a good benchmark? In either case below is what I
++ *    experience with crypto/bn/expspeed.c test program:
++ *
++ *	v8plus module on U10/300MHz against bn_asm.c compiled with:
++ *
++ *	cc-5.0 -xarch=v8plus -xO5 -xdepend	+7-12%
++ *	cc-4.2 -xarch=v8plus -xO5 -xdepend	+25-35%
++ *	egcs-1.1.2 -mcpu=ultrasparc -O3		+35-45%
++ *
++ *	v8 module on SS10/60MHz against bn_asm.c compiled with:
++ *
++ *	cc-5.0 -xarch=v8 -xO5 -xdepend		+7-10%
++ *	cc-4.2 -xarch=v8 -xO5 -xdepend		+10%
++ *	egcs-1.1.2 -mv8 -O3			+35-45%
++ *
++ *    As you can see it's damn hard to beat the new Sun C compiler
++ *    and it's in first place GNU C users who will appreciate this
++ *    assembler implementation:-)	
++ */
++
++/*
++ * Revision history.
++ *
++ * 1.0	- initial release;
++ * 1.1	- new loop unrolling model(*);
++ *	- some more fine tuning;
++ * 1.2	- made gas friendly;
++ *	- updates to documentation concerning v9;
++ *	- new performance comparison matrix;
++ * 1.3	- fixed problem with /usr/ccs/lib/cpp;
++ * 1.4	- native V9 bn_*_comba[48] implementation (15% more efficient)
++ *	  resulting in slight overall performance kick;
++ *	- some retunes;
++ *	- support for GNU as added;
++ *
++ * (*)	Originally unrolled loop looked like this:
++ *	    for (;;) {
++ *		op(p+0); if (--n==0) break;
++ *		op(p+1); if (--n==0) break;
++ *		op(p+2); if (--n==0) break;
++ *		op(p+3); if (--n==0) break;
++ *		p+=4;
++ *	    }
++ *	I unroll according to following:
++ *	    while (n&~3) {
++ *		op(p+0); op(p+1); op(p+2); op(p+3);
++ *		p+=4; n=-4;
++ *	    }
++ *	    if (n) {
++ *		op(p+0); if (--n==0) return;
++ *		op(p+2); if (--n==0) return;
++ *		op(p+3); return;
++ *	    }
++ */
++
++#ifdef OPENSSL_FIPSCANISTER
++#include 
++#endif
++
++#if defined(__SUNPRO_C) && defined(__sparcv9)
++  /* They've said -xarch=v9 at command line */
++  .register	%g2,#scratch
++  .register	%g3,#scratch
++# define	FRAME_SIZE	-192
++#elif defined(__GNUC__) && defined(__arch64__)
++  /* They've said -m64 at command line */
++  .register	%g2,#scratch
++  .register	%g3,#scratch
++# define	FRAME_SIZE	-192
++#else 
++# define	FRAME_SIZE	-96
++#endif 
++/*
++ * GNU assembler can't stand stuw:-(
++ */
++#define stuw st
++
++.section	".text",#alloc,#execinstr
++.file		"bn_asm.sparc.v8plus.S"
++
++.align	32
++
++.global bn_mul_add_words
++/*
++ * BN_ULONG bn_mul_add_words(rp,ap,num,w)
++ * BN_ULONG *rp,*ap;
++ * int num;
++ * BN_ULONG w;
++ */
++bn_mul_add_words:
++	sra	%o2,%g0,%o2	! signx %o2
++	brgz,a	%o2,.L_bn_mul_add_words_proceed
++	lduw	[%o1],%g2
++	retl
++	clr	%o0
++	nop
++	nop
++	nop
++
++.L_bn_mul_add_words_proceed:
++	srl	%o3,%g0,%o3	! clruw	%o3
++	andcc	%o2,-4,%g0
++	bz,pn	%icc,.L_bn_mul_add_words_tail
++	clr	%o5
++
++.L_bn_mul_add_words_loop:	! wow! 32 aligned!
++	lduw	[%o0],%g1
++	lduw	[%o1+4],%g3
++	mulx	%o3,%g2,%g2
++	add	%g1,%o5,%o4
++	nop
++	add	%o4,%g2,%o4
++	stuw	%o4,[%o0]
++	srlx	%o4,32,%o5
++
++	lduw	[%o0+4],%g1
++	lduw	[%o1+8],%g2
++	mulx	%o3,%g3,%g3
++	add	%g1,%o5,%o4
++	dec	4,%o2
++	add	%o4,%g3,%o4
++	stuw	%o4,[%o0+4]
++	srlx	%o4,32,%o5
++
++	lduw	[%o0+8],%g1
++	lduw	[%o1+12],%g3
++	mulx	%o3,%g2,%g2
++	add	%g1,%o5,%o4
++	inc	16,%o1
++	add	%o4,%g2,%o4
++	stuw	%o4,[%o0+8]
++	srlx	%o4,32,%o5
++
++	lduw	[%o0+12],%g1
++	mulx	%o3,%g3,%g3
++	add	%g1,%o5,%o4
++	inc	16,%o0
++	add	%o4,%g3,%o4
++	andcc	%o2,-4,%g0
++	stuw	%o4,[%o0-4]
++	srlx	%o4,32,%o5
++	bnz,a,pt	%icc,.L_bn_mul_add_words_loop
++	lduw	[%o1],%g2
++
++	brnz,a,pn	%o2,.L_bn_mul_add_words_tail
++	lduw	[%o1],%g2
++.L_bn_mul_add_words_return:
++	retl
++	mov	%o5,%o0
++
++.L_bn_mul_add_words_tail:
++	lduw	[%o0],%g1
++	mulx	%o3,%g2,%g2
++	add	%g1,%o5,%o4
++	dec	%o2
++	add	%o4,%g2,%o4
++	srlx	%o4,32,%o5
++	brz,pt	%o2,.L_bn_mul_add_words_return
++	stuw	%o4,[%o0]
++
++	lduw	[%o1+4],%g2
++	lduw	[%o0+4],%g1
++	mulx	%o3,%g2,%g2
++	add	%g1,%o5,%o4
++	dec	%o2
++	add	%o4,%g2,%o4
++	srlx	%o4,32,%o5
++	brz,pt	%o2,.L_bn_mul_add_words_return
++	stuw	%o4,[%o0+4]
++
++	lduw	[%o1+8],%g2
++	lduw	[%o0+8],%g1
++	mulx	%o3,%g2,%g2
++	add	%g1,%o5,%o4
++	add	%o4,%g2,%o4
++	stuw	%o4,[%o0+8]
++	retl
++	srlx	%o4,32,%o0
++
++.type	bn_mul_add_words,#function
++.size	bn_mul_add_words,(.-bn_mul_add_words)
++
++.align	32
++
++.global bn_mul_words
++/*
++ * BN_ULONG bn_mul_words(rp,ap,num,w)
++ * BN_ULONG *rp,*ap;
++ * int num;
++ * BN_ULONG w;
++ */
++bn_mul_words:
++	sra	%o2,%g0,%o2	! signx %o2
++	brgz,a	%o2,.L_bn_mul_words_proceeed
++	lduw	[%o1],%g2
++	retl
++	clr	%o0
++	nop
++	nop
++	nop
++
++.L_bn_mul_words_proceeed:
++	srl	%o3,%g0,%o3	! clruw	%o3
++	andcc	%o2,-4,%g0
++	bz,pn	%icc,.L_bn_mul_words_tail
++	clr	%o5
++
++.L_bn_mul_words_loop:		! wow! 32 aligned!
++	lduw	[%o1+4],%g3
++	mulx	%o3,%g2,%g2
++	add	%g2,%o5,%o4
++	nop
++	stuw	%o4,[%o0]
++	srlx	%o4,32,%o5
++
++	lduw	[%o1+8],%g2
++	mulx	%o3,%g3,%g3
++	add	%g3,%o5,%o4
++	dec	4,%o2
++	stuw	%o4,[%o0+4]
++	srlx	%o4,32,%o5
++
++	lduw	[%o1+12],%g3
++	mulx	%o3,%g2,%g2
++	add	%g2,%o5,%o4
++	inc	16,%o1
++	stuw	%o4,[%o0+8]
++	srlx	%o4,32,%o5
++
++	mulx	%o3,%g3,%g3
++	add	%g3,%o5,%o4
++	inc	16,%o0
++	stuw	%o4,[%o0-4]
++	srlx	%o4,32,%o5
++	andcc	%o2,-4,%g0
++	bnz,a,pt	%icc,.L_bn_mul_words_loop
++	lduw	[%o1],%g2
++	nop
++	nop
++
++	brnz,a,pn	%o2,.L_bn_mul_words_tail
++	lduw	[%o1],%g2
++.L_bn_mul_words_return:
++	retl
++	mov	%o5,%o0
++
++.L_bn_mul_words_tail:
++	mulx	%o3,%g2,%g2
++	add	%g2,%o5,%o4
++	dec	%o2
++	srlx	%o4,32,%o5
++	brz,pt	%o2,.L_bn_mul_words_return
++	stuw	%o4,[%o0]
++
++	lduw	[%o1+4],%g2
++	mulx	%o3,%g2,%g2
++	add	%g2,%o5,%o4
++	dec	%o2
++	srlx	%o4,32,%o5
++	brz,pt	%o2,.L_bn_mul_words_return
++	stuw	%o4,[%o0+4]
++
++	lduw	[%o1+8],%g2
++	mulx	%o3,%g2,%g2
++	add	%g2,%o5,%o4
++	stuw	%o4,[%o0+8]
++	retl
++	srlx	%o4,32,%o0
++
++.type	bn_mul_words,#function
++.size	bn_mul_words,(.-bn_mul_words)
++
++.align  32
++.global	bn_sqr_words
++/*
++ * void bn_sqr_words(r,a,n)
++ * BN_ULONG *r,*a;
++ * int n;
++ */
++bn_sqr_words:
++	sra	%o2,%g0,%o2	! signx %o2
++	brgz,a	%o2,.L_bn_sqr_words_proceeed
++	lduw	[%o1],%g2
++	retl
++	clr	%o0
++	nop
++	nop
++	nop
++
++.L_bn_sqr_words_proceeed:
++	andcc	%o2,-4,%g0
++	nop
++	bz,pn	%icc,.L_bn_sqr_words_tail
++	nop
++
++.L_bn_sqr_words_loop:		! wow! 32 aligned!
++	lduw	[%o1+4],%g3
++	mulx	%g2,%g2,%o4
++	stuw	%o4,[%o0]
++	srlx	%o4,32,%o5
++	stuw	%o5,[%o0+4]
++	nop
++
++	lduw	[%o1+8],%g2
++	mulx	%g3,%g3,%o4
++	dec	4,%o2
++	stuw	%o4,[%o0+8]
++	srlx	%o4,32,%o5
++	stuw	%o5,[%o0+12]
++
++	lduw	[%o1+12],%g3
++	mulx	%g2,%g2,%o4
++	srlx	%o4,32,%o5
++	stuw	%o4,[%o0+16]
++	inc	16,%o1
++	stuw	%o5,[%o0+20]
++
++	mulx	%g3,%g3,%o4
++	inc	32,%o0
++	stuw	%o4,[%o0-8]
++	srlx	%o4,32,%o5
++	andcc	%o2,-4,%g2
++	stuw	%o5,[%o0-4]
++	bnz,a,pt	%icc,.L_bn_sqr_words_loop
++	lduw	[%o1],%g2
++	nop
++
++	brnz,a,pn	%o2,.L_bn_sqr_words_tail
++	lduw	[%o1],%g2
++.L_bn_sqr_words_return:
++	retl
++	clr	%o0
++
++.L_bn_sqr_words_tail:
++	mulx	%g2,%g2,%o4
++	dec	%o2
++	stuw	%o4,[%o0]
++	srlx	%o4,32,%o5
++	brz,pt	%o2,.L_bn_sqr_words_return
++	stuw	%o5,[%o0+4]
++
++	lduw	[%o1+4],%g2
++	mulx	%g2,%g2,%o4
++	dec	%o2
++	stuw	%o4,[%o0+8]
++	srlx	%o4,32,%o5
++	brz,pt	%o2,.L_bn_sqr_words_return
++	stuw	%o5,[%o0+12]
++
++	lduw	[%o1+8],%g2
++	mulx	%g2,%g2,%o4
++	srlx	%o4,32,%o5
++	stuw	%o4,[%o0+16]
++	stuw	%o5,[%o0+20]
++	retl
++	clr	%o0
++
++.type	bn_sqr_words,#function
++.size	bn_sqr_words,(.-bn_sqr_words)
++
++.align	32
++.global bn_div_words
++/*
++ * BN_ULONG bn_div_words(h,l,d)
++ * BN_ULONG h,l,d;
++ */
++bn_div_words:
++	sllx	%o0,32,%o0
++	or	%o0,%o1,%o0
++	udivx	%o0,%o2,%o0
++	retl
++	srl	%o0,%g0,%o0	! clruw	%o0
++
++.type	bn_div_words,#function
++.size	bn_div_words,(.-bn_div_words)
++
++.align	32
++
++.global bn_add_words
++/*
++ * BN_ULONG bn_add_words(rp,ap,bp,n)
++ * BN_ULONG *rp,*ap,*bp;
++ * int n;
++ */
++bn_add_words:
++	sra	%o3,%g0,%o3	! signx %o3
++	brgz,a	%o3,.L_bn_add_words_proceed
++	lduw	[%o1],%o4
++	retl
++	clr	%o0
++
++.L_bn_add_words_proceed:
++	andcc	%o3,-4,%g0
++	bz,pn	%icc,.L_bn_add_words_tail
++	addcc	%g0,0,%g0	! clear carry flag
++
++.L_bn_add_words_loop:		! wow! 32 aligned!
++	dec	4,%o3
++	lduw	[%o2],%o5
++	lduw	[%o1+4],%g1
++	lduw	[%o2+4],%g2
++	lduw	[%o1+8],%g3
++	lduw	[%o2+8],%g4
++	addccc	%o5,%o4,%o5
++	stuw	%o5,[%o0]
++
++	lduw	[%o1+12],%o4
++	lduw	[%o2+12],%o5
++	inc	16,%o1
++	addccc	%g1,%g2,%g1
++	stuw	%g1,[%o0+4]
++	
++	inc	16,%o2
++	addccc	%g3,%g4,%g3
++	stuw	%g3,[%o0+8]
++
++	inc	16,%o0
++	addccc	%o5,%o4,%o5
++	stuw	%o5,[%o0-4]
++	and	%o3,-4,%g1
++	brnz,a,pt	%g1,.L_bn_add_words_loop
++	lduw	[%o1],%o4
++
++	brnz,a,pn	%o3,.L_bn_add_words_tail
++	lduw	[%o1],%o4
++.L_bn_add_words_return:
++	clr	%o0
++	retl
++	movcs	%icc,1,%o0
++	nop
++
++.L_bn_add_words_tail:
++	lduw	[%o2],%o5
++	dec	%o3
++	addccc	%o5,%o4,%o5
++	brz,pt	%o3,.L_bn_add_words_return
++	stuw	%o5,[%o0]
++
++	lduw	[%o1+4],%o4
++	lduw	[%o2+4],%o5
++	dec	%o3
++	addccc	%o5,%o4,%o5
++	brz,pt	%o3,.L_bn_add_words_return
++	stuw	%o5,[%o0+4]
++
++	lduw	[%o1+8],%o4
++	lduw	[%o2+8],%o5
++	addccc	%o5,%o4,%o5
++	stuw	%o5,[%o0+8]
++	clr	%o0
++	retl
++	movcs	%icc,1,%o0
++
++.type	bn_add_words,#function
++.size	bn_add_words,(.-bn_add_words)
++
++.global bn_sub_words
++/*
++ * BN_ULONG bn_sub_words(rp,ap,bp,n)
++ * BN_ULONG *rp,*ap,*bp;
++ * int n;
++ */
++bn_sub_words:
++	sra	%o3,%g0,%o3	! signx %o3
++	brgz,a	%o3,.L_bn_sub_words_proceed
++	lduw	[%o1],%o4
++	retl
++	clr	%o0
++
++.L_bn_sub_words_proceed:
++	andcc	%o3,-4,%g0
++	bz,pn	%icc,.L_bn_sub_words_tail
++	addcc	%g0,0,%g0	! clear carry flag
++
++.L_bn_sub_words_loop:		! wow! 32 aligned!
++	dec	4,%o3
++	lduw	[%o2],%o5
++	lduw	[%o1+4],%g1
++	lduw	[%o2+4],%g2
++	lduw	[%o1+8],%g3
++	lduw	[%o2+8],%g4
++	subccc	%o4,%o5,%o5
++	stuw	%o5,[%o0]
++
++	lduw	[%o1+12],%o4
++	lduw	[%o2+12],%o5
++	inc	16,%o1
++	subccc	%g1,%g2,%g2
++	stuw	%g2,[%o0+4]
++
++	inc	16,%o2
++	subccc	%g3,%g4,%g4
++	stuw	%g4,[%o0+8]
++
++	inc	16,%o0
++	subccc	%o4,%o5,%o5
++	stuw	%o5,[%o0-4]
++	and	%o3,-4,%g1
++	brnz,a,pt	%g1,.L_bn_sub_words_loop
++	lduw	[%o1],%o4
++
++	brnz,a,pn	%o3,.L_bn_sub_words_tail
++	lduw	[%o1],%o4
++.L_bn_sub_words_return:
++	clr	%o0
++	retl
++	movcs	%icc,1,%o0
++	nop
++
++.L_bn_sub_words_tail:		! wow! 32 aligned!
++	lduw	[%o2],%o5
++	dec	%o3
++	subccc	%o4,%o5,%o5
++	brz,pt	%o3,.L_bn_sub_words_return
++	stuw	%o5,[%o0]
++
++	lduw	[%o1+4],%o4
++	lduw	[%o2+4],%o5
++	dec	%o3
++	subccc	%o4,%o5,%o5
++	brz,pt	%o3,.L_bn_sub_words_return
++	stuw	%o5,[%o0+4]
++
++	lduw	[%o1+8],%o4
++	lduw	[%o2+8],%o5
++	subccc	%o4,%o5,%o5
++	stuw	%o5,[%o0+8]
++	clr	%o0
++	retl
++	movcs	%icc,1,%o0
++
++.type	bn_sub_words,#function
++.size	bn_sub_words,(.-bn_sub_words)
++
++/*
++ * Code below depends on the fact that upper parts of the %l0-%l7
++ * and %i0-%i7 are zeroed by kernel after context switch. In
++ * previous versions this comment stated that "the trouble is that
++ * it's not feasible to implement the mumbo-jumbo in less V9
++ * instructions:-(" which apparently isn't true thanks to
++ * 'bcs,a %xcc,.+8; inc %rd' pair. But the performance improvement
++ * results not from the shorter code, but from elimination of
++ * multicycle none-pairable 'rd %y,%rd' instructions.
++ *
++ *							Andy.
++ */
++
++/*
++ * Here is register usage map for *all* routines below.
++ */
++#define t_1	%o0
++#define	t_2	%o1
++#define c_12	%o2
++#define c_3	%o3
++
++#define ap(I)	[%i1+4*I]
++#define bp(I)	[%i2+4*I]
++#define rp(I)	[%i0+4*I]
++
++#define	a_0	%l0
++#define	a_1	%l1
++#define	a_2	%l2
++#define	a_3	%l3
++#define	a_4	%l4
++#define	a_5	%l5
++#define	a_6	%l6
++#define	a_7	%l7
++
++#define	b_0	%i3
++#define	b_1	%i4
++#define	b_2	%i5
++#define	b_3	%o4
++#define	b_4	%o5
++#define	b_5	%o7
++#define	b_6	%g1
++#define	b_7	%g4
++
++.align	32
++.global bn_mul_comba8
++/*
++ * void bn_mul_comba8(r,a,b)
++ * BN_ULONG *r,*a,*b;
++ */
++bn_mul_comba8:
++	save	%sp,FRAME_SIZE,%sp
++	mov	1,t_2
++	lduw	ap(0),a_0
++	sllx	t_2,32,t_2
++	lduw	bp(0),b_0	!=
++	lduw	bp(1),b_1
++	mulx	a_0,b_0,t_1	!mul_add_c(a[0],b[0],c1,c2,c3);
++	srlx	t_1,32,c_12
++	stuw	t_1,rp(0)	!=!r[0]=c1;
++
++	lduw	ap(1),a_1
++	mulx	a_0,b_1,t_1	!mul_add_c(a[0],b[1],c2,c3,c1);
++	addcc	c_12,t_1,c_12
++	clr	c_3		!=
++	bcs,a	%xcc,.+8
++	add	c_3,t_2,c_3
++	lduw	ap(2),a_2
++	mulx	a_1,b_0,t_1	!=!mul_add_c(a[1],b[0],c2,c3,c1);
++	addcc	c_12,t_1,t_1
++	bcs,a	%xcc,.+8
++	add	c_3,t_2,c_3
++	srlx	t_1,32,c_12	!=
++	stuw	t_1,rp(1)	!r[1]=c2;
++	or	c_12,c_3,c_12
++
++	mulx	a_2,b_0,t_1	!mul_add_c(a[2],b[0],c3,c1,c2);
++	addcc	c_12,t_1,c_12	!=
++	clr	c_3
++	bcs,a	%xcc,.+8
++	add	c_3,t_2,c_3
++	lduw	bp(2),b_2	!=
++	mulx	a_1,b_1,t_1	!mul_add_c(a[1],b[1],c3,c1,c2);
++	addcc	c_12,t_1,c_12
++	bcs,a	%xcc,.+8
++	add	c_3,t_2,c_3	!=
++	lduw	bp(3),b_3
++	mulx	a_0,b_2,t_1	!mul_add_c(a[0],b[2],c3,c1,c2);
++	addcc	c_12,t_1,t_1
++	bcs,a	%xcc,.+8	!=
++	add	c_3,t_2,c_3
++	srlx	t_1,32,c_12
++	stuw	t_1,rp(2)	!r[2]=c3;
++	or	c_12,c_3,c_12	!=
++
++	mulx	a_0,b_3,t_1	!mul_add_c(a[0],b[3],c1,c2,c3);
++	addcc	c_12,t_1,c_12
++	clr	c_3
++	bcs,a	%xcc,.+8	!=
++	add	c_3,t_2,c_3
++	mulx	a_1,b_2,t_1	!=!mul_add_c(a[1],b[2],c1,c2,c3);
++	addcc	c_12,t_1,c_12
++	bcs,a	%xcc,.+8	!=
++	add	c_3,t_2,c_3
++	lduw	ap(3),a_3
++	mulx	a_2,b_1,t_1	!mul_add_c(a[2],b[1],c1,c2,c3);
++	addcc	c_12,t_1,c_12	!=
++	bcs,a	%xcc,.+8
++	add	c_3,t_2,c_3
++	lduw	ap(4),a_4
++	mulx	a_3,b_0,t_1	!=!mul_add_c(a[3],b[0],c1,c2,c3);!=
++	addcc	c_12,t_1,t_1
++	bcs,a	%xcc,.+8
++	add	c_3,t_2,c_3
++	srlx	t_1,32,c_12	!=
++	stuw	t_1,rp(3)	!r[3]=c1;
++	or	c_12,c_3,c_12
++
++	mulx	a_4,b_0,t_1	!mul_add_c(a[4],b[0],c2,c3,c1);
++	addcc	c_12,t_1,c_12	!=
++	clr	c_3
++	bcs,a	%xcc,.+8
++	add	c_3,t_2,c_3
++	mulx	a_3,b_1,t_1	!=!mul_add_c(a[3],b[1],c2,c3,c1);
++	addcc	c_12,t_1,c_12
++	bcs,a	%xcc,.+8
++	add	c_3,t_2,c_3
++	mulx	a_2,b_2,t_1	!=!mul_add_c(a[2],b[2],c2,c3,c1);
++	addcc	c_12,t_1,c_12
++	bcs,a	%xcc,.+8
++	add	c_3,t_2,c_3
++	lduw	bp(4),b_4	!=
++	mulx	a_1,b_3,t_1	!mul_add_c(a[1],b[3],c2,c3,c1);
++	addcc	c_12,t_1,c_12
++	bcs,a	%xcc,.+8
++	add	c_3,t_2,c_3	!=
++	lduw	bp(5),b_5
++	mulx	a_0,b_4,t_1	!mul_add_c(a[0],b[4],c2,c3,c1);
++	addcc	c_12,t_1,t_1
++	bcs,a	%xcc,.+8	!=
++	add	c_3,t_2,c_3
++	srlx	t_1,32,c_12
++	stuw	t_1,rp(4)	!r[4]=c2;
++	or	c_12,c_3,c_12	!=
++
++	mulx	a_0,b_5,t_1	!mul_add_c(a[0],b[5],c3,c1,c2);
++	addcc	c_12,t_1,c_12
++	clr	c_3
++	bcs,a	%xcc,.+8	!=
++	add	c_3,t_2,c_3
++	mulx	a_1,b_4,t_1	!mul_add_c(a[1],b[4],c3,c1,c2);
++	addcc	c_12,t_1,c_12
++	bcs,a	%xcc,.+8	!=
++	add	c_3,t_2,c_3
++	mulx	a_2,b_3,t_1	!mul_add_c(a[2],b[3],c3,c1,c2);
++	addcc	c_12,t_1,c_12
++	bcs,a	%xcc,.+8	!=
++	add	c_3,t_2,c_3
++	mulx	a_3,b_2,t_1	!mul_add_c(a[3],b[2],c3,c1,c2);
++	addcc	c_12,t_1,c_12
++	bcs,a	%xcc,.+8	!=
++	add	c_3,t_2,c_3
++	lduw	ap(5),a_5
++	mulx	a_4,b_1,t_1	!mul_add_c(a[4],b[1],c3,c1,c2);
++	addcc	c_12,t_1,c_12	!=
++	bcs,a	%xcc,.+8
++	add	c_3,t_2,c_3
++	lduw	ap(6),a_6
++	mulx	a_5,b_0,t_1	!=!mul_add_c(a[5],b[0],c3,c1,c2);
++	addcc	c_12,t_1,t_1
++	bcs,a	%xcc,.+8
++	add	c_3,t_2,c_3
++	srlx	t_1,32,c_12	!=
++	stuw	t_1,rp(5)	!r[5]=c3;
++	or	c_12,c_3,c_12
++
++	mulx	a_6,b_0,t_1	!mul_add_c(a[6],b[0],c1,c2,c3);
++	addcc	c_12,t_1,c_12	!=
++	clr	c_3
++	bcs,a	%xcc,.+8
++	add	c_3,t_2,c_3
++	mulx	a_5,b_1,t_1	!=!mul_add_c(a[5],b[1],c1,c2,c3);
++	addcc	c_12,t_1,c_12
++	bcs,a	%xcc,.+8
++	add	c_3,t_2,c_3
++	mulx	a_4,b_2,t_1	!=!mul_add_c(a[4],b[2],c1,c2,c3);
++	addcc	c_12,t_1,c_12
++	bcs,a	%xcc,.+8
++	add	c_3,t_2,c_3
++	mulx	a_3,b_3,t_1	!=!mul_add_c(a[3],b[3],c1,c2,c3);
++	addcc	c_12,t_1,c_12
++	bcs,a	%xcc,.+8
++	add	c_3,t_2,c_3
++	mulx	a_2,b_4,t_1	!=!mul_add_c(a[2],b[4],c1,c2,c3);
++	addcc	c_12,t_1,c_12
++	bcs,a	%xcc,.+8
++	add	c_3,t_2,c_3
++	lduw	bp(6),b_6	!=
++	mulx	a_1,b_5,t_1	!mul_add_c(a[1],b[5],c1,c2,c3);
++	addcc	c_12,t_1,c_12
++	bcs,a	%xcc,.+8
++	add	c_3,t_2,c_3	!=
++	lduw	bp(7),b_7
++	mulx	a_0,b_6,t_1	!mul_add_c(a[0],b[6],c1,c2,c3);
++	addcc	c_12,t_1,t_1
++	bcs,a	%xcc,.+8	!=
++	add	c_3,t_2,c_3
++	srlx	t_1,32,c_12
++	stuw	t_1,rp(6)	!r[6]=c1;
++	or	c_12,c_3,c_12	!=
++
++	mulx	a_0,b_7,t_1	!mul_add_c(a[0],b[7],c2,c3,c1);
++	addcc	c_12,t_1,c_12
++	clr	c_3
++	bcs,a	%xcc,.+8	!=
++	add	c_3,t_2,c_3
++	mulx	a_1,b_6,t_1	!mul_add_c(a[1],b[6],c2,c3,c1);
++	addcc	c_12,t_1,c_12
++	bcs,a	%xcc,.+8	!=
++	add	c_3,t_2,c_3
++	mulx	a_2,b_5,t_1	!mul_add_c(a[2],b[5],c2,c3,c1);
++	addcc	c_12,t_1,c_12
++	bcs,a	%xcc,.+8	!=
++	add	c_3,t_2,c_3
++	mulx	a_3,b_4,t_1	!mul_add_c(a[3],b[4],c2,c3,c1);
++	addcc	c_12,t_1,c_12
++	bcs,a	%xcc,.+8	!=
++	add	c_3,t_2,c_3
++	mulx	a_4,b_3,t_1	!mul_add_c(a[4],b[3],c2,c3,c1);
++	addcc	c_12,t_1,c_12
++	bcs,a	%xcc,.+8	!=
++	add	c_3,t_2,c_3
++	mulx	a_5,b_2,t_1	!mul_add_c(a[5],b[2],c2,c3,c1);
++	addcc	c_12,t_1,c_12
++	bcs,a	%xcc,.+8	!=
++	add	c_3,t_2,c_3
++	lduw	ap(7),a_7
++	mulx	a_6,b_1,t_1	!=!mul_add_c(a[6],b[1],c2,c3,c1);
++	addcc	c_12,t_1,c_12
++	bcs,a	%xcc,.+8
++	add	c_3,t_2,c_3
++	mulx	a_7,b_0,t_1	!=!mul_add_c(a[7],b[0],c2,c3,c1);
++	addcc	c_12,t_1,t_1
++	bcs,a	%xcc,.+8
++	add	c_3,t_2,c_3
++	srlx	t_1,32,c_12	!=
++	stuw	t_1,rp(7)	!r[7]=c2;
++	or	c_12,c_3,c_12
++
++	mulx	a_7,b_1,t_1	!=!mul_add_c(a[7],b[1],c3,c1,c2);
++	addcc	c_12,t_1,c_12
++	clr	c_3
++	bcs,a	%xcc,.+8
++	add	c_3,t_2,c_3	!=
++	mulx	a_6,b_2,t_1	!mul_add_c(a[6],b[2],c3,c1,c2);
++	addcc	c_12,t_1,c_12
++	bcs,a	%xcc,.+8
++	add	c_3,t_2,c_3	!=
++	mulx	a_5,b_3,t_1	!mul_add_c(a[5],b[3],c3,c1,c2);
++	addcc	c_12,t_1,c_12
++	bcs,a	%xcc,.+8
++	add	c_3,t_2,c_3	!=
++	mulx	a_4,b_4,t_1	!mul_add_c(a[4],b[4],c3,c1,c2);
++	addcc	c_12,t_1,c_12
++	bcs,a	%xcc,.+8
++	add	c_3,t_2,c_3	!=
++	mulx	a_3,b_5,t_1	!mul_add_c(a[3],b[5],c3,c1,c2);
++	addcc	c_12,t_1,c_12
++	bcs,a	%xcc,.+8
++	add	c_3,t_2,c_3	!=
++	mulx	a_2,b_6,t_1	!mul_add_c(a[2],b[6],c3,c1,c2);
++	addcc	c_12,t_1,c_12
++	bcs,a	%xcc,.+8
++	add	c_3,t_2,c_3	!=
++	mulx	a_1,b_7,t_1	!mul_add_c(a[1],b[7],c3,c1,c2);
++	addcc	c_12,t_1,t_1
++	bcs,a	%xcc,.+8
++	add	c_3,t_2,c_3	!=
++	srlx	t_1,32,c_12
++	stuw	t_1,rp(8)	!r[8]=c3;
++	or	c_12,c_3,c_12
++
++	mulx	a_2,b_7,t_1	!=!mul_add_c(a[2],b[7],c1,c2,c3);
++	addcc	c_12,t_1,c_12
++	clr	c_3
++	bcs,a	%xcc,.+8
++	add	c_3,t_2,c_3	!=
++	mulx	a_3,b_6,t_1	!mul_add_c(a[3],b[6],c1,c2,c3);
++	addcc	c_12,t_1,c_12
++	bcs,a	%xcc,.+8	!=
++	add	c_3,t_2,c_3
++	mulx	a_4,b_5,t_1	!mul_add_c(a[4],b[5],c1,c2,c3);
++	addcc	c_12,t_1,c_12
++	bcs,a	%xcc,.+8	!=
++	add	c_3,t_2,c_3
++	mulx	a_5,b_4,t_1	!mul_add_c(a[5],b[4],c1,c2,c3);
++	addcc	c_12,t_1,c_12
++	bcs,a	%xcc,.+8	!=
++	add	c_3,t_2,c_3
++	mulx	a_6,b_3,t_1	!mul_add_c(a[6],b[3],c1,c2,c3);
++	addcc	c_12,t_1,c_12
++	bcs,a	%xcc,.+8	!=
++	add	c_3,t_2,c_3
++	mulx	a_7,b_2,t_1	!mul_add_c(a[7],b[2],c1,c2,c3);
++	addcc	c_12,t_1,t_1
++	bcs,a	%xcc,.+8	!=
++	add	c_3,t_2,c_3
++	srlx	t_1,32,c_12
++	stuw	t_1,rp(9)	!r[9]=c1;
++	or	c_12,c_3,c_12	!=
++
++	mulx	a_7,b_3,t_1	!mul_add_c(a[7],b[3],c2,c3,c1);
++	addcc	c_12,t_1,c_12
++	clr	c_3
++	bcs,a	%xcc,.+8	!=
++	add	c_3,t_2,c_3
++	mulx	a_6,b_4,t_1	!mul_add_c(a[6],b[4],c2,c3,c1);
++	addcc	c_12,t_1,c_12
++	bcs,a	%xcc,.+8	!=
++	add	c_3,t_2,c_3
++	mulx	a_5,b_5,t_1	!mul_add_c(a[5],b[5],c2,c3,c1);
++	addcc	c_12,t_1,c_12
++	bcs,a	%xcc,.+8	!=
++	add	c_3,t_2,c_3
++	mulx	a_4,b_6,t_1	!mul_add_c(a[4],b[6],c2,c3,c1);
++	addcc	c_12,t_1,c_12
++	bcs,a	%xcc,.+8	!=
++	add	c_3,t_2,c_3
++	mulx	a_3,b_7,t_1	!mul_add_c(a[3],b[7],c2,c3,c1);
++	addcc	c_12,t_1,t_1
++	bcs,a	%xcc,.+8	!=
++	add	c_3,t_2,c_3
++	srlx	t_1,32,c_12
++	stuw	t_1,rp(10)	!r[10]=c2;
++	or	c_12,c_3,c_12	!=
++
++	mulx	a_4,b_7,t_1	!mul_add_c(a[4],b[7],c3,c1,c2);
++	addcc	c_12,t_1,c_12
++	clr	c_3
++	bcs,a	%xcc,.+8	!=
++	add	c_3,t_2,c_3
++	mulx	a_5,b_6,t_1	!mul_add_c(a[5],b[6],c3,c1,c2);
++	addcc	c_12,t_1,c_12
++	bcs,a	%xcc,.+8	!=
++	add	c_3,t_2,c_3
++	mulx	a_6,b_5,t_1	!mul_add_c(a[6],b[5],c3,c1,c2);
++	addcc	c_12,t_1,c_12
++	bcs,a	%xcc,.+8	!=
++	add	c_3,t_2,c_3
++	mulx	a_7,b_4,t_1	!mul_add_c(a[7],b[4],c3,c1,c2);
++	addcc	c_12,t_1,t_1
++	bcs,a	%xcc,.+8	!=
++	add	c_3,t_2,c_3
++	srlx	t_1,32,c_12
++	stuw	t_1,rp(11)	!r[11]=c3;
++	or	c_12,c_3,c_12	!=
++
++	mulx	a_7,b_5,t_1	!mul_add_c(a[7],b[5],c1,c2,c3);
++	addcc	c_12,t_1,c_12
++	clr	c_3
++	bcs,a	%xcc,.+8	!=
++	add	c_3,t_2,c_3
++	mulx	a_6,b_6,t_1	!mul_add_c(a[6],b[6],c1,c2,c3);
++	addcc	c_12,t_1,c_12
++	bcs,a	%xcc,.+8	!=
++	add	c_3,t_2,c_3
++	mulx	a_5,b_7,t_1	!mul_add_c(a[5],b[7],c1,c2,c3);
++	addcc	c_12,t_1,t_1
++	bcs,a	%xcc,.+8	!=
++	add	c_3,t_2,c_3
++	srlx	t_1,32,c_12
++	stuw	t_1,rp(12)	!r[12]=c1;
++	or	c_12,c_3,c_12	!=
++
++	mulx	a_6,b_7,t_1	!mul_add_c(a[6],b[7],c2,c3,c1);
++	addcc	c_12,t_1,c_12
++	clr	c_3
++	bcs,a	%xcc,.+8	!=
++	add	c_3,t_2,c_3
++	mulx	a_7,b_6,t_1	!mul_add_c(a[7],b[6],c2,c3,c1);
++	addcc	c_12,t_1,t_1
++	bcs,a	%xcc,.+8	!=
++	add	c_3,t_2,c_3
++	srlx	t_1,32,c_12
++	st	t_1,rp(13)	!r[13]=c2;
++	or	c_12,c_3,c_12	!=
++
++	mulx	a_7,b_7,t_1	!mul_add_c(a[7],b[7],c3,c1,c2);
++	addcc	c_12,t_1,t_1
++	srlx	t_1,32,c_12	!=
++	stuw	t_1,rp(14)	!r[14]=c3;
++	stuw	c_12,rp(15)	!r[15]=c1;
++
++	ret
++	restore	%g0,%g0,%o0	!=
++
++.type	bn_mul_comba8,#function
++.size	bn_mul_comba8,(.-bn_mul_comba8)
++
++.align	32
++
++.global bn_mul_comba4
++/*
++ * void bn_mul_comba4(r,a,b)
++ * BN_ULONG *r,*a,*b;
++ */
++bn_mul_comba4:
++	save	%sp,FRAME_SIZE,%sp
++	lduw	ap(0),a_0
++	mov	1,t_2
++	lduw	bp(0),b_0
++	sllx	t_2,32,t_2	!=
++	lduw	bp(1),b_1
++	mulx	a_0,b_0,t_1	!mul_add_c(a[0],b[0],c1,c2,c3);
++	srlx	t_1,32,c_12
++	stuw	t_1,rp(0)	!=!r[0]=c1;
++
++	lduw	ap(1),a_1
++	mulx	a_0,b_1,t_1	!mul_add_c(a[0],b[1],c2,c3,c1);
++	addcc	c_12,t_1,c_12
++	clr	c_3		!=
++	bcs,a	%xcc,.+8
++	add	c_3,t_2,c_3
++	lduw	ap(2),a_2
++	mulx	a_1,b_0,t_1	!=!mul_add_c(a[1],b[0],c2,c3,c1);
++	addcc	c_12,t_1,t_1
++	bcs,a	%xcc,.+8
++	add	c_3,t_2,c_3
++	srlx	t_1,32,c_12	!=
++	stuw	t_1,rp(1)	!r[1]=c2;
++	or	c_12,c_3,c_12
++
++	mulx	a_2,b_0,t_1	!mul_add_c(a[2],b[0],c3,c1,c2);
++	addcc	c_12,t_1,c_12	!=
++	clr	c_3
++	bcs,a	%xcc,.+8
++	add	c_3,t_2,c_3
++	lduw	bp(2),b_2	!=
++	mulx	a_1,b_1,t_1	!mul_add_c(a[1],b[1],c3,c1,c2);
++	addcc	c_12,t_1,c_12
++	bcs,a	%xcc,.+8
++	add	c_3,t_2,c_3	!=
++	lduw	bp(3),b_3
++	mulx	a_0,b_2,t_1	!mul_add_c(a[0],b[2],c3,c1,c2);
++	addcc	c_12,t_1,t_1
++	bcs,a	%xcc,.+8	!=
++	add	c_3,t_2,c_3
++	srlx	t_1,32,c_12
++	stuw	t_1,rp(2)	!r[2]=c3;
++	or	c_12,c_3,c_12	!=
++
++	mulx	a_0,b_3,t_1	!mul_add_c(a[0],b[3],c1,c2,c3);
++	addcc	c_12,t_1,c_12
++	clr	c_3
++	bcs,a	%xcc,.+8	!=
++	add	c_3,t_2,c_3
++	mulx	a_1,b_2,t_1	!mul_add_c(a[1],b[2],c1,c2,c3);
++	addcc	c_12,t_1,c_12
++	bcs,a	%xcc,.+8	!=
++	add	c_3,t_2,c_3
++	lduw	ap(3),a_3
++	mulx	a_2,b_1,t_1	!mul_add_c(a[2],b[1],c1,c2,c3);
++	addcc	c_12,t_1,c_12	!=
++	bcs,a	%xcc,.+8
++	add	c_3,t_2,c_3
++	mulx	a_3,b_0,t_1	!mul_add_c(a[3],b[0],c1,c2,c3);!=
++	addcc	c_12,t_1,t_1	!=
++	bcs,a	%xcc,.+8
++	add	c_3,t_2,c_3
++	srlx	t_1,32,c_12
++	stuw	t_1,rp(3)	!=!r[3]=c1;
++	or	c_12,c_3,c_12
++
++	mulx	a_3,b_1,t_1	!mul_add_c(a[3],b[1],c2,c3,c1);
++	addcc	c_12,t_1,c_12
++	clr	c_3		!=
++	bcs,a	%xcc,.+8
++	add	c_3,t_2,c_3
++	mulx	a_2,b_2,t_1	!mul_add_c(a[2],b[2],c2,c3,c1);
++	addcc	c_12,t_1,c_12	!=
++	bcs,a	%xcc,.+8
++	add	c_3,t_2,c_3
++	mulx	a_1,b_3,t_1	!mul_add_c(a[1],b[3],c2,c3,c1);
++	addcc	c_12,t_1,t_1	!=
++	bcs,a	%xcc,.+8
++	add	c_3,t_2,c_3
++	srlx	t_1,32,c_12
++	stuw	t_1,rp(4)	!=!r[4]=c2;
++	or	c_12,c_3,c_12
++
++	mulx	a_2,b_3,t_1	!mul_add_c(a[2],b[3],c3,c1,c2);
++	addcc	c_12,t_1,c_12
++	clr	c_3		!=
++	bcs,a	%xcc,.+8
++	add	c_3,t_2,c_3
++	mulx	a_3,b_2,t_1	!mul_add_c(a[3],b[2],c3,c1,c2);
++	addcc	c_12,t_1,t_1	!=
++	bcs,a	%xcc,.+8
++	add	c_3,t_2,c_3
++	srlx	t_1,32,c_12
++	stuw	t_1,rp(5)	!=!r[5]=c3;
++	or	c_12,c_3,c_12
++
++	mulx	a_3,b_3,t_1	!mul_add_c(a[3],b[3],c1,c2,c3);
++	addcc	c_12,t_1,t_1
++	srlx	t_1,32,c_12	!=
++	stuw	t_1,rp(6)	!r[6]=c1;
++	stuw	c_12,rp(7)	!r[7]=c2;
++	
++	ret
++	restore	%g0,%g0,%o0
++
++.type	bn_mul_comba4,#function
++.size	bn_mul_comba4,(.-bn_mul_comba4)
++
++.align	32
++
++.global bn_sqr_comba8
++bn_sqr_comba8:
++	save	%sp,FRAME_SIZE,%sp
++	mov	1,t_2
++	lduw	ap(0),a_0
++	sllx	t_2,32,t_2
++	lduw	ap(1),a_1
++	mulx	a_0,a_0,t_1	!sqr_add_c(a,0,c1,c2,c3);
++	srlx	t_1,32,c_12
++	stuw	t_1,rp(0)	!r[0]=c1;
++
++	lduw	ap(2),a_2
++	mulx	a_0,a_1,t_1	!=!sqr_add_c2(a,1,0,c2,c3,c1);
++	addcc	c_12,t_1,c_12
++	clr	c_3
++	bcs,a	%xcc,.+8
++	add	c_3,t_2,c_3
++	addcc	c_12,t_1,t_1
++	bcs,a	%xcc,.+8
++	add	c_3,t_2,c_3
++	srlx	t_1,32,c_12
++	stuw	t_1,rp(1)	!r[1]=c2;
++	or	c_12,c_3,c_12
++
++	mulx	a_2,a_0,t_1	!sqr_add_c2(a,2,0,c3,c1,c2);
++	addcc	c_12,t_1,c_12
++	clr	c_3
++	bcs,a	%xcc,.+8
++	add	c_3,t_2,c_3
++	addcc	c_12,t_1,c_12
++	bcs,a	%xcc,.+8
++	add	c_3,t_2,c_3
++	lduw	ap(3),a_3
++	mulx	a_1,a_1,t_1	!sqr_add_c(a,1,c3,c1,c2);
++	addcc	c_12,t_1,t_1
++	bcs,a	%xcc,.+8
++	add	c_3,t_2,c_3
++	srlx	t_1,32,c_12
++	stuw	t_1,rp(2)	!r[2]=c3;
++	or	c_12,c_3,c_12
++
++	mulx	a_0,a_3,t_1	!sqr_add_c2(a,3,0,c1,c2,c3);
++	addcc	c_12,t_1,c_12
++	clr	c_3
++	bcs,a	%xcc,.+8
++	add	c_3,t_2,c_3
++	addcc	c_12,t_1,c_12
++	bcs,a	%xcc,.+8
++	add	c_3,t_2,c_3
++	lduw	ap(4),a_4
++	mulx	a_1,a_2,t_1	!sqr_add_c2(a,2,1,c1,c2,c3);
++	addcc	c_12,t_1,c_12
++	bcs,a	%xcc,.+8
++	add	c_3,t_2,c_3
++	addcc	c_12,t_1,t_1
++	bcs,a	%xcc,.+8
++	add	c_3,t_2,c_3
++	srlx	t_1,32,c_12
++	st	t_1,rp(3)	!r[3]=c1;
++	or	c_12,c_3,c_12
++
++	mulx	a_4,a_0,t_1	!sqr_add_c2(a,4,0,c2,c3,c1);
++	addcc	c_12,t_1,c_12
++	clr	c_3
++	bcs,a	%xcc,.+8
++	add	c_3,t_2,c_3
++	addcc	c_12,t_1,c_12
++	bcs,a	%xcc,.+8
++	add	c_3,t_2,c_3
++	mulx	a_3,a_1,t_1	!sqr_add_c2(a,3,1,c2,c3,c1);
++	addcc	c_12,t_1,c_12
++	bcs,a	%xcc,.+8
++	add	c_3,t_2,c_3
++	addcc	c_12,t_1,c_12
++	bcs,a	%xcc,.+8
++	add	c_3,t_2,c_3
++	lduw	ap(5),a_5
++	mulx	a_2,a_2,t_1	!sqr_add_c(a,2,c2,c3,c1);
++	addcc	c_12,t_1,t_1
++	bcs,a	%xcc,.+8
++	add	c_3,t_2,c_3
++	srlx	t_1,32,c_12
++	stuw	t_1,rp(4)	!r[4]=c2;
++	or	c_12,c_3,c_12
++
++	mulx	a_0,a_5,t_1	!sqr_add_c2(a,5,0,c3,c1,c2);
++	addcc	c_12,t_1,c_12
++	clr	c_3
++	bcs,a	%xcc,.+8
++	add	c_3,t_2,c_3
++	addcc	c_12,t_1,c_12
++	bcs,a	%xcc,.+8
++	add	c_3,t_2,c_3
++	mulx	a_1,a_4,t_1	!sqr_add_c2(a,4,1,c3,c1,c2);
++	addcc	c_12,t_1,c_12
++	bcs,a	%xcc,.+8
++	add	c_3,t_2,c_3
++	addcc	c_12,t_1,c_12
++	bcs,a	%xcc,.+8
++	add	c_3,t_2,c_3
++	lduw	ap(6),a_6
++	mulx	a_2,a_3,t_1	!sqr_add_c2(a,3,2,c3,c1,c2);
++	addcc	c_12,t_1,c_12
++	bcs,a	%xcc,.+8
++	add	c_3,t_2,c_3
++	addcc	c_12,t_1,t_1
++	bcs,a	%xcc,.+8
++	add	c_3,t_2,c_3
++	srlx	t_1,32,c_12
++	stuw	t_1,rp(5)	!r[5]=c3;
++	or	c_12,c_3,c_12
++
++	mulx	a_6,a_0,t_1	!sqr_add_c2(a,6,0,c1,c2,c3);
++	addcc	c_12,t_1,c_12
++	clr	c_3
++	bcs,a	%xcc,.+8
++	add	c_3,t_2,c_3
++	addcc	c_12,t_1,c_12
++	bcs,a	%xcc,.+8
++	add	c_3,t_2,c_3
++	mulx	a_5,a_1,t_1	!sqr_add_c2(a,5,1,c1,c2,c3);
++	addcc	c_12,t_1,c_12
++	bcs,a	%xcc,.+8
++	add	c_3,t_2,c_3
++	addcc	c_12,t_1,c_12
++	bcs,a	%xcc,.+8
++	add	c_3,t_2,c_3
++	mulx	a_4,a_2,t_1	!sqr_add_c2(a,4,2,c1,c2,c3);
++	addcc	c_12,t_1,c_12
++	bcs,a	%xcc,.+8
++	add	c_3,t_2,c_3
++	addcc	c_12,t_1,c_12
++	bcs,a	%xcc,.+8
++	add	c_3,t_2,c_3
++	lduw	ap(7),a_7
++	mulx	a_3,a_3,t_1	!=!sqr_add_c(a,3,c1,c2,c3);
++	addcc	c_12,t_1,t_1
++	bcs,a	%xcc,.+8
++	add	c_3,t_2,c_3
++	srlx	t_1,32,c_12
++	stuw	t_1,rp(6)	!r[6]=c1;
++	or	c_12,c_3,c_12
++
++	mulx	a_0,a_7,t_1	!sqr_add_c2(a,7,0,c2,c3,c1);
++	addcc	c_12,t_1,c_12
++	clr	c_3
++	bcs,a	%xcc,.+8
++	add	c_3,t_2,c_3
++	addcc	c_12,t_1,c_12
++	bcs,a	%xcc,.+8
++	add	c_3,t_2,c_3
++	mulx	a_1,a_6,t_1	!sqr_add_c2(a,6,1,c2,c3,c1);
++	addcc	c_12,t_1,c_12
++	bcs,a	%xcc,.+8
++	add	c_3,t_2,c_3
++	addcc	c_12,t_1,c_12
++	bcs,a	%xcc,.+8
++	add	c_3,t_2,c_3
++	mulx	a_2,a_5,t_1	!sqr_add_c2(a,5,2,c2,c3,c1);
++	addcc	c_12,t_1,c_12
++	bcs,a	%xcc,.+8
++	add	c_3,t_2,c_3
++	addcc	c_12,t_1,c_12
++	bcs,a	%xcc,.+8
++	add	c_3,t_2,c_3
++	mulx	a_3,a_4,t_1	!sqr_add_c2(a,4,3,c2,c3,c1);
++	addcc	c_12,t_1,c_12
++	bcs,a	%xcc,.+8
++	add	c_3,t_2,c_3
++	addcc	c_12,t_1,t_1
++	bcs,a	%xcc,.+8
++	add	c_3,t_2,c_3
++	srlx	t_1,32,c_12
++	stuw	t_1,rp(7)	!r[7]=c2;
++	or	c_12,c_3,c_12
++
++	mulx	a_7,a_1,t_1	!sqr_add_c2(a,7,1,c3,c1,c2);
++	addcc	c_12,t_1,c_12
++	clr	c_3
++	bcs,a	%xcc,.+8
++	add	c_3,t_2,c_3
++	addcc	c_12,t_1,c_12
++	bcs,a	%xcc,.+8
++	add	c_3,t_2,c_3
++	mulx	a_6,a_2,t_1	!sqr_add_c2(a,6,2,c3,c1,c2);
++	addcc	c_12,t_1,c_12
++	bcs,a	%xcc,.+8
++	add	c_3,t_2,c_3
++	addcc	c_12,t_1,c_12
++	bcs,a	%xcc,.+8
++	add	c_3,t_2,c_3
++	mulx	a_5,a_3,t_1	!sqr_add_c2(a,5,3,c3,c1,c2);
++	addcc	c_12,t_1,c_12
++	bcs,a	%xcc,.+8
++	add	c_3,t_2,c_3
++	addcc	c_12,t_1,c_12
++	bcs,a	%xcc,.+8
++	add	c_3,t_2,c_3
++	mulx	a_4,a_4,t_1	!sqr_add_c(a,4,c3,c1,c2);
++	addcc	c_12,t_1,t_1
++	bcs,a	%xcc,.+8
++	add	c_3,t_2,c_3
++	srlx	t_1,32,c_12
++	stuw	t_1,rp(8)	!r[8]=c3;
++	or	c_12,c_3,c_12
++
++	mulx	a_2,a_7,t_1	!sqr_add_c2(a,7,2,c1,c2,c3);
++	addcc	c_12,t_1,c_12
++	clr	c_3
++	bcs,a	%xcc,.+8
++	add	c_3,t_2,c_3
++	addcc	c_12,t_1,c_12
++	bcs,a	%xcc,.+8
++	add	c_3,t_2,c_3
++	mulx	a_3,a_6,t_1	!sqr_add_c2(a,6,3,c1,c2,c3);
++	addcc	c_12,t_1,c_12
++	bcs,a	%xcc,.+8
++	add	c_3,t_2,c_3
++	addcc	c_12,t_1,c_12
++	bcs,a	%xcc,.+8
++	add	c_3,t_2,c_3
++	mulx	a_4,a_5,t_1	!sqr_add_c2(a,5,4,c1,c2,c3);
++	addcc	c_12,t_1,c_12
++	bcs,a	%xcc,.+8
++	add	c_3,t_2,c_3
++	addcc	c_12,t_1,t_1
++	bcs,a	%xcc,.+8
++	add	c_3,t_2,c_3
++	srlx	t_1,32,c_12
++	stuw	t_1,rp(9)	!r[9]=c1;
++	or	c_12,c_3,c_12
++
++	mulx	a_7,a_3,t_1	!sqr_add_c2(a,7,3,c2,c3,c1);
++	addcc	c_12,t_1,c_12
++	clr	c_3
++	bcs,a	%xcc,.+8
++	add	c_3,t_2,c_3
++	addcc	c_12,t_1,c_12
++	bcs,a	%xcc,.+8
++	add	c_3,t_2,c_3
++	mulx	a_6,a_4,t_1	!sqr_add_c2(a,6,4,c2,c3,c1);
++	addcc	c_12,t_1,c_12
++	bcs,a	%xcc,.+8
++	add	c_3,t_2,c_3
++	addcc	c_12,t_1,c_12
++	bcs,a	%xcc,.+8
++	add	c_3,t_2,c_3
++	mulx	a_5,a_5,t_1	!sqr_add_c(a,5,c2,c3,c1);
++	addcc	c_12,t_1,t_1
++	bcs,a	%xcc,.+8
++	add	c_3,t_2,c_3
++	srlx	t_1,32,c_12
++	stuw	t_1,rp(10)	!r[10]=c2;
++	or	c_12,c_3,c_12
++
++	mulx	a_4,a_7,t_1	!sqr_add_c2(a,7,4,c3,c1,c2);
++	addcc	c_12,t_1,c_12
++	clr	c_3
++	bcs,a	%xcc,.+8
++	add	c_3,t_2,c_3
++	addcc	c_12,t_1,c_12
++	bcs,a	%xcc,.+8
++	add	c_3,t_2,c_3
++	mulx	a_5,a_6,t_1	!sqr_add_c2(a,6,5,c3,c1,c2);
++	addcc	c_12,t_1,c_12
++	bcs,a	%xcc,.+8
++	add	c_3,t_2,c_3
++	addcc	c_12,t_1,t_1
++	bcs,a	%xcc,.+8
++	add	c_3,t_2,c_3
++	srlx	t_1,32,c_12
++	stuw	t_1,rp(11)	!r[11]=c3;
++	or	c_12,c_3,c_12
++
++	mulx	a_7,a_5,t_1	!sqr_add_c2(a,7,5,c1,c2,c3);
++	addcc	c_12,t_1,c_12
++	clr	c_3
++	bcs,a	%xcc,.+8
++	add	c_3,t_2,c_3
++	addcc	c_12,t_1,c_12
++	bcs,a	%xcc,.+8
++	add	c_3,t_2,c_3
++	mulx	a_6,a_6,t_1	!sqr_add_c(a,6,c1,c2,c3);
++	addcc	c_12,t_1,t_1
++	bcs,a	%xcc,.+8
++	add	c_3,t_2,c_3
++	srlx	t_1,32,c_12
++	stuw	t_1,rp(12)	!r[12]=c1;
++	or	c_12,c_3,c_12
++
++	mulx	a_6,a_7,t_1	!sqr_add_c2(a,7,6,c2,c3,c1);
++	addcc	c_12,t_1,c_12
++	clr	c_3
++	bcs,a	%xcc,.+8
++	add	c_3,t_2,c_3
++	addcc	c_12,t_1,t_1
++	bcs,a	%xcc,.+8
++	add	c_3,t_2,c_3
++	srlx	t_1,32,c_12
++	stuw	t_1,rp(13)	!r[13]=c2;
++	or	c_12,c_3,c_12
++
++	mulx	a_7,a_7,t_1	!sqr_add_c(a,7,c3,c1,c2);
++	addcc	c_12,t_1,t_1
++	srlx	t_1,32,c_12
++	stuw	t_1,rp(14)	!r[14]=c3;
++	stuw	c_12,rp(15)	!r[15]=c1;
++
++	ret
++	restore	%g0,%g0,%o0
++
++.type	bn_sqr_comba8,#function
++.size	bn_sqr_comba8,(.-bn_sqr_comba8)
++
++.align	32
++
++.global bn_sqr_comba4
++/*
++ * void bn_sqr_comba4(r,a)
++ * BN_ULONG *r,*a;
++ */
++bn_sqr_comba4:
++	save	%sp,FRAME_SIZE,%sp
++	mov	1,t_2
++	lduw	ap(0),a_0
++	sllx	t_2,32,t_2
++	lduw	ap(1),a_1
++	mulx	a_0,a_0,t_1	!sqr_add_c(a,0,c1,c2,c3);
++	srlx	t_1,32,c_12
++	stuw	t_1,rp(0)	!r[0]=c1;
++
++	lduw	ap(2),a_2
++	mulx	a_0,a_1,t_1	!sqr_add_c2(a,1,0,c2,c3,c1);
++	addcc	c_12,t_1,c_12
++	clr	c_3
++	bcs,a	%xcc,.+8
++	add	c_3,t_2,c_3
++	addcc	c_12,t_1,t_1
++	bcs,a	%xcc,.+8
++	add	c_3,t_2,c_3
++	srlx	t_1,32,c_12
++	stuw	t_1,rp(1)	!r[1]=c2;
++	or	c_12,c_3,c_12
++
++	mulx	a_2,a_0,t_1	!sqr_add_c2(a,2,0,c3,c1,c2);
++	addcc	c_12,t_1,c_12
++	clr	c_3
++	bcs,a	%xcc,.+8
++	add	c_3,t_2,c_3
++	addcc	c_12,t_1,c_12
++	bcs,a	%xcc,.+8
++	add	c_3,t_2,c_3
++	lduw	ap(3),a_3
++	mulx	a_1,a_1,t_1	!sqr_add_c(a,1,c3,c1,c2);
++	addcc	c_12,t_1,t_1
++	bcs,a	%xcc,.+8
++	add	c_3,t_2,c_3
++	srlx	t_1,32,c_12
++	stuw	t_1,rp(2)	!r[2]=c3;
++	or	c_12,c_3,c_12
++
++	mulx	a_0,a_3,t_1	!sqr_add_c2(a,3,0,c1,c2,c3);
++	addcc	c_12,t_1,c_12
++	clr	c_3
++	bcs,a	%xcc,.+8
++	add	c_3,t_2,c_3
++	addcc	c_12,t_1,c_12
++	bcs,a	%xcc,.+8
++	add	c_3,t_2,c_3
++	mulx	a_1,a_2,t_1	!sqr_add_c2(a,2,1,c1,c2,c3);
++	addcc	c_12,t_1,c_12
++	bcs,a	%xcc,.+8
++	add	c_3,t_2,c_3
++	addcc	c_12,t_1,t_1
++	bcs,a	%xcc,.+8
++	add	c_3,t_2,c_3
++	srlx	t_1,32,c_12
++	stuw	t_1,rp(3)	!r[3]=c1;
++	or	c_12,c_3,c_12
++
++	mulx	a_3,a_1,t_1	!sqr_add_c2(a,3,1,c2,c3,c1);
++	addcc	c_12,t_1,c_12
++	clr	c_3
++	bcs,a	%xcc,.+8
++	add	c_3,t_2,c_3
++	addcc	c_12,t_1,c_12
++	bcs,a	%xcc,.+8
++	add	c_3,t_2,c_3
++	mulx	a_2,a_2,t_1	!sqr_add_c(a,2,c2,c3,c1);
++	addcc	c_12,t_1,t_1
++	bcs,a	%xcc,.+8
++	add	c_3,t_2,c_3
++	srlx	t_1,32,c_12
++	stuw	t_1,rp(4)	!r[4]=c2;
++	or	c_12,c_3,c_12
++
++	mulx	a_2,a_3,t_1	!sqr_add_c2(a,3,2,c3,c1,c2);
++	addcc	c_12,t_1,c_12
++	clr	c_3
++	bcs,a	%xcc,.+8
++	add	c_3,t_2,c_3
++	addcc	c_12,t_1,t_1
++	bcs,a	%xcc,.+8
++	add	c_3,t_2,c_3
++	srlx	t_1,32,c_12
++	stuw	t_1,rp(5)	!r[5]=c3;
++	or	c_12,c_3,c_12
++
++	mulx	a_3,a_3,t_1	!sqr_add_c(a,3,c1,c2,c3);
++	addcc	c_12,t_1,t_1
++	srlx	t_1,32,c_12
++	stuw	t_1,rp(6)	!r[6]=c1;
++	stuw	c_12,rp(7)	!r[7]=c2;
++	
++	ret
++	restore	%g0,%g0,%o0
++
++.type	bn_sqr_comba4,#function
++.size	bn_sqr_comba4,(.-bn_sqr_comba4)
++
++.align	32
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/bn/asm/sparcv9-gf2m.pl b/CryptoPkg/Library/OpensslLib/openssl/crypto/bn/asm/sparcv9-gf2m.pl
+new file mode 100644
+index 0000000..dcf11a8
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/bn/asm/sparcv9-gf2m.pl
+@@ -0,0 +1,200 @@
++#! /usr/bin/env perl
++# Copyright 2012-2016 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
++# in the file LICENSE in the source distribution or at
++# https://www.openssl.org/source/license.html
++
++#
++# ====================================================================
++# Written by Andy Polyakov  for the OpenSSL
++# project. The module is, however, dual licensed under OpenSSL and
++# CRYPTOGAMS licenses depending on where you obtain it. For further
++# details see http://www.openssl.org/~appro/cryptogams/.
++# ====================================================================
++#
++# October 2012
++#
++# The module implements bn_GF2m_mul_2x2 polynomial multiplication used
++# in bn_gf2m.c. It's kind of low-hanging mechanical port from C for
++# the time being... Except that it has two code paths: one suitable
++# for all SPARCv9 processors and one for VIS3-capable ones. Former
++# delivers ~25-45% more, more for longer keys, heaviest DH and DSA
++# verify operations on venerable UltraSPARC II. On T4 VIS3 code is
++# ~100-230% faster than gcc-generated code and ~35-90% faster than
++# the pure SPARCv9 code path.
++
++$output = pop;
++open STDOUT,">$output";
++
++$locals=16*8;
++
++$tab="%l0";
++
++@T=("%g2","%g3");
++@i=("%g4","%g5");
++
++($a1,$a2,$a4,$a8,$a12,$a48)=map("%o$_",(0..5));
++($lo,$hi,$b)=("%g1",$a8,"%o7"); $a=$lo;
++
++$code.=<<___;
++#include 
++
++#ifdef __arch64__
++.register	%g2,#scratch
++.register	%g3,#scratch
++#endif
++
++#ifdef __PIC__
++SPARC_PIC_THUNK(%g1)
++#endif
++
++.globl	bn_GF2m_mul_2x2
++.align	16
++bn_GF2m_mul_2x2:
++        SPARC_LOAD_ADDRESS_LEAF(OPENSSL_sparcv9cap_P,%g1,%g5)
++        ld	[%g1+0],%g1             	! OPENSSL_sparcv9cap_P[0]
++
++        andcc	%g1, SPARCV9_VIS3, %g0
++        bz,pn	%icc,.Lsoftware
++        nop
++
++	sllx	%o1, 32, %o1
++	sllx	%o3, 32, %o3
++	or	%o2, %o1, %o1
++	or	%o4, %o3, %o3
++	.word	0x95b262ab			! xmulx   %o1, %o3, %o2
++	.word	0x99b262cb			! xmulxhi %o1, %o3, %o4
++	srlx	%o2, 32, %o1			! 13 cycles later
++	st	%o2, [%o0+0]
++	st	%o1, [%o0+4]
++	srlx	%o4, 32, %o3
++	st	%o4, [%o0+8]
++	retl
++	st	%o3, [%o0+12]
++
++.align	16
++.Lsoftware:
++	save	%sp,-STACK_FRAME-$locals,%sp
++
++	sllx	%i1,32,$a
++	mov	-1,$a12
++	sllx	%i3,32,$b
++	or	%i2,$a,$a
++	srlx	$a12,1,$a48			! 0x7fff...
++	or	%i4,$b,$b
++	srlx	$a12,2,$a12			! 0x3fff...
++	add	%sp,STACK_BIAS+STACK_FRAME,$tab
++
++	sllx	$a,2,$a4
++	mov	$a,$a1
++	sllx	$a,1,$a2
++
++	srax	$a4,63,@i[1]			! broadcast 61st bit
++	and	$a48,$a4,$a4			! (a<<2)&0x7fff...
++	srlx	$a48,2,$a48
++	srax	$a2,63,@i[0]			! broadcast 62nd bit
++	and	$a12,$a2,$a2			! (a<<1)&0x3fff...
++	srax	$a1,63,$lo			! broadcast 63rd bit
++	and	$a48,$a1,$a1			! (a<<0)&0x1fff...
++
++	sllx	$a1,3,$a8
++	and	$b,$lo,$lo
++	and	$b,@i[0],@i[0]
++	and	$b,@i[1],@i[1]
++
++	stx	%g0,[$tab+0*8]			! tab[0]=0
++	xor	$a1,$a2,$a12
++	stx	$a1,[$tab+1*8]			! tab[1]=a1
++	stx	$a2,[$tab+2*8]			! tab[2]=a2
++	 xor	$a4,$a8,$a48
++	stx	$a12,[$tab+3*8]			! tab[3]=a1^a2
++	 xor	$a4,$a1,$a1
++
++	stx	$a4,[$tab+4*8]			! tab[4]=a4
++	xor	$a4,$a2,$a2
++	stx	$a1,[$tab+5*8]			! tab[5]=a1^a4
++	xor	$a4,$a12,$a12
++	stx	$a2,[$tab+6*8]			! tab[6]=a2^a4
++	 xor	$a48,$a1,$a1
++	stx	$a12,[$tab+7*8]			! tab[7]=a1^a2^a4
++	 xor	$a48,$a2,$a2
++
++	stx	$a8,[$tab+8*8]			! tab[8]=a8
++	xor	$a48,$a12,$a12
++	stx	$a1,[$tab+9*8]			! tab[9]=a1^a8
++	 xor	$a4,$a1,$a1
++	stx	$a2,[$tab+10*8]			! tab[10]=a2^a8
++	 xor	$a4,$a2,$a2
++	stx	$a12,[$tab+11*8]		! tab[11]=a1^a2^a8
++
++	xor	$a4,$a12,$a12
++	stx	$a48,[$tab+12*8]		! tab[12]=a4^a8
++	 srlx	$lo,1,$hi
++	stx	$a1,[$tab+13*8]			! tab[13]=a1^a4^a8
++	 sllx	$lo,63,$lo
++	stx	$a2,[$tab+14*8]			! tab[14]=a2^a4^a8
++	 srlx	@i[0],2,@T[0]
++	stx	$a12,[$tab+15*8]		! tab[15]=a1^a2^a4^a8
++
++	sllx	@i[0],62,$a1
++	 sllx	$b,3,@i[0]
++	srlx	@i[1],3,@T[1]
++	 and	@i[0],`0xf<<3`,@i[0]
++	sllx	@i[1],61,$a2
++	 ldx	[$tab+@i[0]],@i[0]
++	 srlx	$b,4-3,@i[1]
++	xor	@T[0],$hi,$hi
++	 and	@i[1],`0xf<<3`,@i[1]
++	xor	$a1,$lo,$lo
++	 ldx	[$tab+@i[1]],@i[1]
++	xor	@T[1],$hi,$hi
++
++	xor	@i[0],$lo,$lo
++	srlx	$b,8-3,@i[0]
++	 xor	$a2,$lo,$lo
++	and	@i[0],`0xf<<3`,@i[0]
++___
++for($n=1;$n<14;$n++) {
++$code.=<<___;
++	sllx	@i[1],`$n*4`,@T[0]
++	ldx	[$tab+@i[0]],@i[0]
++	srlx	@i[1],`64-$n*4`,@T[1]
++	xor	@T[0],$lo,$lo
++	srlx	$b,`($n+2)*4`-3,@i[1]
++	xor	@T[1],$hi,$hi
++	and	@i[1],`0xf<<3`,@i[1]
++___
++	push(@i,shift(@i)); push(@T,shift(@T));
++}
++$code.=<<___;
++	sllx	@i[1],`$n*4`,@T[0]
++	ldx	[$tab+@i[0]],@i[0]
++	srlx	@i[1],`64-$n*4`,@T[1]
++	xor	@T[0],$lo,$lo
++
++	sllx	@i[0],`($n+1)*4`,@T[0]
++	 xor	@T[1],$hi,$hi
++	srlx	@i[0],`64-($n+1)*4`,@T[1]
++	xor	@T[0],$lo,$lo
++	xor	@T[1],$hi,$hi
++
++	srlx	$lo,32,%i1
++	st	$lo,[%i0+0]
++	st	%i1,[%i0+4]
++	srlx	$hi,32,%i2
++	st	$hi,[%i0+8]
++	st	%i2,[%i0+12]
++
++	ret
++	restore
++.type	bn_GF2m_mul_2x2,#function
++.size	bn_GF2m_mul_2x2,.-bn_GF2m_mul_2x2
++.asciz	"GF(2^m) Multiplication for SPARCv9, CRYPTOGAMS by "
++.align	4
++___
++
++$code =~ s/\`([^\`]*)\`/eval($1)/gem;
++print $code;
++close STDOUT;
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/bn/asm/sparcv9-mont.pl b/CryptoPkg/Library/OpensslLib/openssl/crypto/bn/asm/sparcv9-mont.pl
+new file mode 100644
+index 0000000..c36ce36
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/bn/asm/sparcv9-mont.pl
+@@ -0,0 +1,616 @@
++#! /usr/bin/env perl
++# Copyright 2005-2016 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
++# in the file LICENSE in the source distribution or at
++# https://www.openssl.org/source/license.html
++
++
++# ====================================================================
++# Written by Andy Polyakov  for the OpenSSL
++# project. The module is, however, dual licensed under OpenSSL and
++# CRYPTOGAMS licenses depending on where you obtain it. For further
++# details see http://www.openssl.org/~appro/cryptogams/.
++# ====================================================================
++
++# December 2005
++#
++# Pure SPARCv9/8+ and IALU-only bn_mul_mont implementation. The reasons
++# for undertaken effort are multiple. First of all, UltraSPARC is not
++# the whole SPARCv9 universe and other VIS-free implementations deserve
++# optimized code as much. Secondly, newly introduced UltraSPARC T1,
++# a.k.a. Niagara, has shared FPU and concurrent FPU-intensive paths,
++# such as sparcv9a-mont, will simply sink it. Yes, T1 is equipped with
++# several integrated RSA/DSA accelerator circuits accessible through
++# kernel driver [only(*)], but having decent user-land software
++# implementation is important too. Finally, reasons like desire to
++# experiment with dedicated squaring procedure. Yes, this module
++# implements one, because it was easiest to draft it in SPARCv9
++# instructions...
++
++# (*)	Engine accessing the driver in question is on my TODO list.
++#	For reference, acceleator is estimated to give 6 to 10 times
++#	improvement on single-threaded RSA sign. It should be noted
++#	that 6-10x improvement coefficient does not actually mean
++#	something extraordinary in terms of absolute [single-threaded]
++#	performance, as SPARCv9 instruction set is by all means least
++#	suitable for high performance crypto among other 64 bit
++#	platforms. 6-10x factor simply places T1 in same performance
++#	domain as say AMD64 and IA-64. Improvement of RSA verify don't
++#	appear impressive at all, but it's the sign operation which is
++#	far more critical/interesting.
++
++# You might notice that inner loops are modulo-scheduled:-) This has
++# essentially negligible impact on UltraSPARC performance, it's
++# Fujitsu SPARC64 V users who should notice and hopefully appreciate
++# the advantage... Currently this module surpasses sparcv9a-mont.pl
++# by ~20% on UltraSPARC-III and later cores, but recall that sparcv9a
++# module still have hidden potential [see TODO list there], which is
++# estimated to be larger than 20%...
++
++$output = pop;
++open STDOUT,">$output";
++
++# int bn_mul_mont(
++$rp="%i0";	# BN_ULONG *rp,
++$ap="%i1";	# const BN_ULONG *ap,
++$bp="%i2";	# const BN_ULONG *bp,
++$np="%i3";	# const BN_ULONG *np,
++$n0="%i4";	# const BN_ULONG *n0,
++$num="%i5";	# int num);
++
++$frame="STACK_FRAME";
++$bias="STACK_BIAS";
++
++$car0="%o0";
++$car1="%o1";
++$car2="%o2";	# 1 bit
++$acc0="%o3";
++$acc1="%o4";
++$mask="%g1";	# 32 bits, what a waste...
++$tmp0="%g4";
++$tmp1="%g5";
++
++$i="%l0";
++$j="%l1";
++$mul0="%l2";
++$mul1="%l3";
++$tp="%l4";
++$apj="%l5";
++$npj="%l6";
++$tpj="%l7";
++
++$fname="bn_mul_mont_int";
++
++$code=<<___;
++#include "sparc_arch.h"
++
++.section	".text",#alloc,#execinstr
++
++.global	$fname
++.align	32
++$fname:
++	cmp	%o5,4			! 128 bits minimum
++	bge,pt	%icc,.Lenter
++	sethi	%hi(0xffffffff),$mask
++	retl
++	clr	%o0
++.align	32
++.Lenter:
++	save	%sp,-$frame,%sp
++	sll	$num,2,$num		! num*=4
++	or	$mask,%lo(0xffffffff),$mask
++	ld	[$n0],$n0
++	cmp	$ap,$bp
++	and	$num,$mask,$num
++	ld	[$bp],$mul0		! bp[0]
++	nop
++
++	add	%sp,$bias,%o7		! real top of stack
++	ld	[$ap],$car0		! ap[0] ! redundant in squaring context
++	sub	%o7,$num,%o7
++	ld	[$ap+4],$apj		! ap[1]
++	and	%o7,-1024,%o7
++	ld	[$np],$car1		! np[0]
++	sub	%o7,$bias,%sp		! alloca
++	ld	[$np+4],$npj		! np[1]
++	be,pt	SIZE_T_CC,.Lbn_sqr_mont
++	mov	12,$j
++
++	mulx	$car0,$mul0,$car0	! ap[0]*bp[0]
++	mulx	$apj,$mul0,$tmp0	!prologue! ap[1]*bp[0]
++	and	$car0,$mask,$acc0
++	add	%sp,$bias+$frame,$tp
++	ld	[$ap+8],$apj		!prologue!
++
++	mulx	$n0,$acc0,$mul1		! "t[0]"*n0
++	and	$mul1,$mask,$mul1
++
++	mulx	$car1,$mul1,$car1	! np[0]*"t[0]"*n0
++	mulx	$npj,$mul1,$acc1	!prologue! np[1]*"t[0]"*n0
++	srlx	$car0,32,$car0
++	add	$acc0,$car1,$car1
++	ld	[$np+8],$npj		!prologue!
++	srlx	$car1,32,$car1
++	mov	$tmp0,$acc0		!prologue!
++
++.L1st:
++	mulx	$apj,$mul0,$tmp0
++	mulx	$npj,$mul1,$tmp1
++	add	$acc0,$car0,$car0
++	ld	[$ap+$j],$apj		! ap[j]
++	and	$car0,$mask,$acc0
++	add	$acc1,$car1,$car1
++	ld	[$np+$j],$npj		! np[j]
++	srlx	$car0,32,$car0
++	add	$acc0,$car1,$car1
++	add	$j,4,$j			! j++
++	mov	$tmp0,$acc0
++	st	$car1,[$tp]
++	cmp	$j,$num
++	mov	$tmp1,$acc1
++	srlx	$car1,32,$car1
++	bl	%icc,.L1st
++	add	$tp,4,$tp		! tp++
++!.L1st
++
++	mulx	$apj,$mul0,$tmp0	!epilogue!
++	mulx	$npj,$mul1,$tmp1
++	add	$acc0,$car0,$car0
++	and	$car0,$mask,$acc0
++	add	$acc1,$car1,$car1
++	srlx	$car0,32,$car0
++	add	$acc0,$car1,$car1
++	st	$car1,[$tp]
++	srlx	$car1,32,$car1
++
++	add	$tmp0,$car0,$car0
++	and	$car0,$mask,$acc0
++	add	$tmp1,$car1,$car1
++	srlx	$car0,32,$car0
++	add	$acc0,$car1,$car1
++	st	$car1,[$tp+4]
++	srlx	$car1,32,$car1
++
++	add	$car0,$car1,$car1
++	st	$car1,[$tp+8]
++	srlx	$car1,32,$car2
++
++	mov	4,$i			! i++
++	ld	[$bp+4],$mul0		! bp[1]
++.Louter:
++	add	%sp,$bias+$frame,$tp
++	ld	[$ap],$car0		! ap[0]
++	ld	[$ap+4],$apj		! ap[1]
++	ld	[$np],$car1		! np[0]
++	ld	[$np+4],$npj		! np[1]
++	ld	[$tp],$tmp1		! tp[0]
++	ld	[$tp+4],$tpj		! tp[1]
++	mov	12,$j
++
++	mulx	$car0,$mul0,$car0
++	mulx	$apj,$mul0,$tmp0	!prologue!
++	add	$tmp1,$car0,$car0
++	ld	[$ap+8],$apj		!prologue!
++	and	$car0,$mask,$acc0
++
++	mulx	$n0,$acc0,$mul1
++	and	$mul1,$mask,$mul1
++
++	mulx	$car1,$mul1,$car1
++	mulx	$npj,$mul1,$acc1	!prologue!
++	srlx	$car0,32,$car0
++	add	$acc0,$car1,$car1
++	ld	[$np+8],$npj		!prologue!
++	srlx	$car1,32,$car1
++	mov	$tmp0,$acc0		!prologue!
++
++.Linner:
++	mulx	$apj,$mul0,$tmp0
++	mulx	$npj,$mul1,$tmp1
++	add	$tpj,$car0,$car0
++	ld	[$ap+$j],$apj		! ap[j]
++	add	$acc0,$car0,$car0
++	add	$acc1,$car1,$car1
++	ld	[$np+$j],$npj		! np[j]
++	and	$car0,$mask,$acc0
++	ld	[$tp+8],$tpj		! tp[j]
++	srlx	$car0,32,$car0
++	add	$acc0,$car1,$car1
++	add	$j,4,$j			! j++
++	mov	$tmp0,$acc0
++	st	$car1,[$tp]		! tp[j-1]
++	srlx	$car1,32,$car1
++	mov	$tmp1,$acc1
++	cmp	$j,$num
++	bl	%icc,.Linner
++	add	$tp,4,$tp		! tp++
++!.Linner
++
++	mulx	$apj,$mul0,$tmp0	!epilogue!
++	mulx	$npj,$mul1,$tmp1
++	add	$tpj,$car0,$car0
++	add	$acc0,$car0,$car0
++	ld	[$tp+8],$tpj		! tp[j]
++	and	$car0,$mask,$acc0
++	add	$acc1,$car1,$car1
++	srlx	$car0,32,$car0
++	add	$acc0,$car1,$car1
++	st	$car1,[$tp]		! tp[j-1]
++	srlx	$car1,32,$car1
++
++	add	$tpj,$car0,$car0
++	add	$tmp0,$car0,$car0
++	and	$car0,$mask,$acc0
++	add	$tmp1,$car1,$car1
++	add	$acc0,$car1,$car1
++	st	$car1,[$tp+4]		! tp[j-1]
++	srlx	$car0,32,$car0
++	add	$i,4,$i			! i++
++	srlx	$car1,32,$car1
++
++	add	$car0,$car1,$car1
++	cmp	$i,$num
++	add	$car2,$car1,$car1
++	st	$car1,[$tp+8]
++
++	srlx	$car1,32,$car2
++	bl,a	%icc,.Louter
++	ld	[$bp+$i],$mul0		! bp[i]
++!.Louter
++
++	add	$tp,12,$tp
++
++.Ltail:
++	add	$np,$num,$np
++	add	$rp,$num,$rp
++	mov	$tp,$ap
++	sub	%g0,$num,%o7		! k=-num
++	ba	.Lsub
++	subcc	%g0,%g0,%g0		! clear %icc.c
++.align	16
++.Lsub:
++	ld	[$tp+%o7],%o0
++	ld	[$np+%o7],%o1
++	subccc	%o0,%o1,%o1		! tp[j]-np[j]
++	add	$rp,%o7,$i
++	add	%o7,4,%o7
++	brnz	%o7,.Lsub
++	st	%o1,[$i]
++	subc	$car2,0,$car2		! handle upmost overflow bit
++	and	$tp,$car2,$ap
++	andn	$rp,$car2,$np
++	or	$ap,$np,$ap
++	sub	%g0,$num,%o7
++
++.Lcopy:
++	ld	[$ap+%o7],%o0		! copy or in-place refresh
++	st	%g0,[$tp+%o7]		! zap tp
++	st	%o0,[$rp+%o7]
++	add	%o7,4,%o7
++	brnz	%o7,.Lcopy
++	nop
++	mov	1,%i0
++	ret
++	restore
++___
++
++########
++######## .Lbn_sqr_mont gives up to 20% *overall* improvement over
++######## code without following dedicated squaring procedure.
++########
++$sbit="%i2";		# re-use $bp!
++
++$code.=<<___;
++.align	32
++.Lbn_sqr_mont:
++	mulx	$mul0,$mul0,$car0		! ap[0]*ap[0]
++	mulx	$apj,$mul0,$tmp0		!prologue!
++	and	$car0,$mask,$acc0
++	add	%sp,$bias+$frame,$tp
++	ld	[$ap+8],$apj			!prologue!
++
++	mulx	$n0,$acc0,$mul1			! "t[0]"*n0
++	srlx	$car0,32,$car0
++	and	$mul1,$mask,$mul1
++
++	mulx	$car1,$mul1,$car1		! np[0]*"t[0]"*n0
++	mulx	$npj,$mul1,$acc1		!prologue!
++	and	$car0,1,$sbit
++	ld	[$np+8],$npj			!prologue!
++	srlx	$car0,1,$car0
++	add	$acc0,$car1,$car1
++	srlx	$car1,32,$car1
++	mov	$tmp0,$acc0			!prologue!
++
++.Lsqr_1st:
++	mulx	$apj,$mul0,$tmp0
++	mulx	$npj,$mul1,$tmp1
++	add	$acc0,$car0,$car0		! ap[j]*a0+c0
++	add	$acc1,$car1,$car1
++	ld	[$ap+$j],$apj			! ap[j]
++	and	$car0,$mask,$acc0
++	ld	[$np+$j],$npj			! np[j]
++	srlx	$car0,32,$car0
++	add	$acc0,$acc0,$acc0
++	or	$sbit,$acc0,$acc0
++	mov	$tmp1,$acc1
++	srlx	$acc0,32,$sbit
++	add	$j,4,$j				! j++
++	and	$acc0,$mask,$acc0
++	cmp	$j,$num
++	add	$acc0,$car1,$car1
++	st	$car1,[$tp]
++	mov	$tmp0,$acc0
++	srlx	$car1,32,$car1
++	bl	%icc,.Lsqr_1st
++	add	$tp,4,$tp			! tp++
++!.Lsqr_1st
++
++	mulx	$apj,$mul0,$tmp0		! epilogue
++	mulx	$npj,$mul1,$tmp1
++	add	$acc0,$car0,$car0		! ap[j]*a0+c0
++	add	$acc1,$car1,$car1
++	and	$car0,$mask,$acc0
++	srlx	$car0,32,$car0
++	add	$acc0,$acc0,$acc0
++	or	$sbit,$acc0,$acc0
++	srlx	$acc0,32,$sbit
++	and	$acc0,$mask,$acc0
++	add	$acc0,$car1,$car1
++	st	$car1,[$tp]
++	srlx	$car1,32,$car1
++
++	add	$tmp0,$car0,$car0		! ap[j]*a0+c0
++	add	$tmp1,$car1,$car1
++	and	$car0,$mask,$acc0
++	srlx	$car0,32,$car0
++	add	$acc0,$acc0,$acc0
++	or	$sbit,$acc0,$acc0
++	srlx	$acc0,32,$sbit
++	and	$acc0,$mask,$acc0
++	add	$acc0,$car1,$car1
++	st	$car1,[$tp+4]
++	srlx	$car1,32,$car1
++
++	add	$car0,$car0,$car0
++	or	$sbit,$car0,$car0
++	add	$car0,$car1,$car1
++	st	$car1,[$tp+8]
++	srlx	$car1,32,$car2
++
++	ld	[%sp+$bias+$frame],$tmp0	! tp[0]
++	ld	[%sp+$bias+$frame+4],$tmp1	! tp[1]
++	ld	[%sp+$bias+$frame+8],$tpj	! tp[2]
++	ld	[$ap+4],$mul0			! ap[1]
++	ld	[$ap+8],$apj			! ap[2]
++	ld	[$np],$car1			! np[0]
++	ld	[$np+4],$npj			! np[1]
++	mulx	$n0,$tmp0,$mul1
++
++	mulx	$mul0,$mul0,$car0
++	and	$mul1,$mask,$mul1
++
++	mulx	$car1,$mul1,$car1
++	mulx	$npj,$mul1,$acc1
++	add	$tmp0,$car1,$car1
++	and	$car0,$mask,$acc0
++	ld	[$np+8],$npj			! np[2]
++	srlx	$car1,32,$car1
++	add	$tmp1,$car1,$car1
++	srlx	$car0,32,$car0
++	add	$acc0,$car1,$car1
++	and	$car0,1,$sbit
++	add	$acc1,$car1,$car1
++	srlx	$car0,1,$car0
++	mov	12,$j
++	st	$car1,[%sp+$bias+$frame]	! tp[0]=
++	srlx	$car1,32,$car1
++	add	%sp,$bias+$frame+4,$tp
++
++.Lsqr_2nd:
++	mulx	$apj,$mul0,$acc0
++	mulx	$npj,$mul1,$acc1
++	add	$acc0,$car0,$car0
++	add	$tpj,$car1,$car1
++	ld	[$ap+$j],$apj			! ap[j]
++	and	$car0,$mask,$acc0
++	ld	[$np+$j],$npj			! np[j]
++	srlx	$car0,32,$car0
++	add	$acc1,$car1,$car1
++	ld	[$tp+8],$tpj			! tp[j]
++	add	$acc0,$acc0,$acc0
++	add	$j,4,$j				! j++
++	or	$sbit,$acc0,$acc0
++	srlx	$acc0,32,$sbit
++	and	$acc0,$mask,$acc0
++	cmp	$j,$num
++	add	$acc0,$car1,$car1
++	st	$car1,[$tp]			! tp[j-1]
++	srlx	$car1,32,$car1
++	bl	%icc,.Lsqr_2nd
++	add	$tp,4,$tp			! tp++
++!.Lsqr_2nd
++
++	mulx	$apj,$mul0,$acc0
++	mulx	$npj,$mul1,$acc1
++	add	$acc0,$car0,$car0
++	add	$tpj,$car1,$car1
++	and	$car0,$mask,$acc0
++	srlx	$car0,32,$car0
++	add	$acc1,$car1,$car1
++	add	$acc0,$acc0,$acc0
++	or	$sbit,$acc0,$acc0
++	srlx	$acc0,32,$sbit
++	and	$acc0,$mask,$acc0
++	add	$acc0,$car1,$car1
++	st	$car1,[$tp]			! tp[j-1]
++	srlx	$car1,32,$car1
++
++	add	$car0,$car0,$car0
++	or	$sbit,$car0,$car0
++	add	$car0,$car1,$car1
++	add	$car2,$car1,$car1
++	st	$car1,[$tp+4]
++	srlx	$car1,32,$car2
++
++	ld	[%sp+$bias+$frame],$tmp1	! tp[0]
++	ld	[%sp+$bias+$frame+4],$tpj	! tp[1]
++	ld	[$ap+8],$mul0			! ap[2]
++	ld	[$np],$car1			! np[0]
++	ld	[$np+4],$npj			! np[1]
++	mulx	$n0,$tmp1,$mul1
++	and	$mul1,$mask,$mul1
++	mov	8,$i
++
++	mulx	$mul0,$mul0,$car0
++	mulx	$car1,$mul1,$car1
++	and	$car0,$mask,$acc0
++	add	$tmp1,$car1,$car1
++	srlx	$car0,32,$car0
++	add	%sp,$bias+$frame,$tp
++	srlx	$car1,32,$car1
++	and	$car0,1,$sbit
++	srlx	$car0,1,$car0
++	mov	4,$j
++
++.Lsqr_outer:
++.Lsqr_inner1:
++	mulx	$npj,$mul1,$acc1
++	add	$tpj,$car1,$car1
++	add	$j,4,$j
++	ld	[$tp+8],$tpj
++	cmp	$j,$i
++	add	$acc1,$car1,$car1
++	ld	[$np+$j],$npj
++	st	$car1,[$tp]
++	srlx	$car1,32,$car1
++	bl	%icc,.Lsqr_inner1
++	add	$tp,4,$tp
++!.Lsqr_inner1
++
++	add	$j,4,$j
++	ld	[$ap+$j],$apj			! ap[j]
++	mulx	$npj,$mul1,$acc1
++	add	$tpj,$car1,$car1
++	ld	[$np+$j],$npj			! np[j]
++	add	$acc0,$car1,$car1
++	ld	[$tp+8],$tpj			! tp[j]
++	add	$acc1,$car1,$car1
++	st	$car1,[$tp]
++	srlx	$car1,32,$car1
++
++	add	$j,4,$j
++	cmp	$j,$num
++	be,pn	%icc,.Lsqr_no_inner2
++	add	$tp,4,$tp
++
++.Lsqr_inner2:
++	mulx	$apj,$mul0,$acc0
++	mulx	$npj,$mul1,$acc1
++	add	$tpj,$car1,$car1
++	add	$acc0,$car0,$car0
++	ld	[$ap+$j],$apj			! ap[j]
++	and	$car0,$mask,$acc0
++	ld	[$np+$j],$npj			! np[j]
++	srlx	$car0,32,$car0
++	add	$acc0,$acc0,$acc0
++	ld	[$tp+8],$tpj			! tp[j]
++	or	$sbit,$acc0,$acc0
++	add	$j,4,$j				! j++
++	srlx	$acc0,32,$sbit
++	and	$acc0,$mask,$acc0
++	cmp	$j,$num
++	add	$acc0,$car1,$car1
++	add	$acc1,$car1,$car1
++	st	$car1,[$tp]			! tp[j-1]
++	srlx	$car1,32,$car1
++	bl	%icc,.Lsqr_inner2
++	add	$tp,4,$tp			! tp++
++
++.Lsqr_no_inner2:
++	mulx	$apj,$mul0,$acc0
++	mulx	$npj,$mul1,$acc1
++	add	$tpj,$car1,$car1
++	add	$acc0,$car0,$car0
++	and	$car0,$mask,$acc0
++	srlx	$car0,32,$car0
++	add	$acc0,$acc0,$acc0
++	or	$sbit,$acc0,$acc0
++	srlx	$acc0,32,$sbit
++	and	$acc0,$mask,$acc0
++	add	$acc0,$car1,$car1
++	add	$acc1,$car1,$car1
++	st	$car1,[$tp]			! tp[j-1]
++	srlx	$car1,32,$car1
++
++	add	$car0,$car0,$car0
++	or	$sbit,$car0,$car0
++	add	$car0,$car1,$car1
++	add	$car2,$car1,$car1
++	st	$car1,[$tp+4]
++	srlx	$car1,32,$car2
++
++	add	$i,4,$i				! i++
++	ld	[%sp+$bias+$frame],$tmp1	! tp[0]
++	ld	[%sp+$bias+$frame+4],$tpj	! tp[1]
++	ld	[$ap+$i],$mul0			! ap[j]
++	ld	[$np],$car1			! np[0]
++	ld	[$np+4],$npj			! np[1]
++	mulx	$n0,$tmp1,$mul1
++	and	$mul1,$mask,$mul1
++	add	$i,4,$tmp0
++
++	mulx	$mul0,$mul0,$car0
++	mulx	$car1,$mul1,$car1
++	and	$car0,$mask,$acc0
++	add	$tmp1,$car1,$car1
++	srlx	$car0,32,$car0
++	add	%sp,$bias+$frame,$tp
++	srlx	$car1,32,$car1
++	and	$car0,1,$sbit
++	srlx	$car0,1,$car0
++
++	cmp	$tmp0,$num			! i"
++.align	32
++___
++$code =~ s/\`([^\`]*)\`/eval($1)/gem;
++print $code;
++close STDOUT;
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/bn/asm/sparcv9a-mont.pl b/CryptoPkg/Library/OpensslLib/openssl/crypto/bn/asm/sparcv9a-mont.pl
+new file mode 100755
+index 0000000..50b6906
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/bn/asm/sparcv9a-mont.pl
+@@ -0,0 +1,887 @@
++#! /usr/bin/env perl
++# Copyright 2005-2016 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
++# in the file LICENSE in the source distribution or at
++# https://www.openssl.org/source/license.html
++
++
++# ====================================================================
++# Written by Andy Polyakov  for the OpenSSL
++# project. The module is, however, dual licensed under OpenSSL and
++# CRYPTOGAMS licenses depending on where you obtain it. For further
++# details see http://www.openssl.org/~appro/cryptogams/.
++# ====================================================================
++
++# October 2005
++#
++# "Teaser" Montgomery multiplication module for UltraSPARC. Why FPU?
++# Because unlike integer multiplier, which simply stalls whole CPU,
++# FPU is fully pipelined and can effectively emit 48 bit partial
++# product every cycle. Why not blended SPARC v9? One can argue that
++# making this module dependent on UltraSPARC VIS extension limits its
++# binary compatibility. Well yes, it does exclude SPARC64 prior-V(!)
++# implementations from compatibility matrix. But the rest, whole Sun
++# UltraSPARC family and brand new Fujitsu's SPARC64 V, all support
++# VIS extension instructions used in this module. This is considered
++# good enough to not care about HAL SPARC64 users [if any] who have
++# integer-only pure SPARCv9 module to "fall down" to.
++
++# USI&II cores currently exhibit uniform 2x improvement [over pre-
++# bn_mul_mont codebase] for all key lengths and benchmarks. On USIII
++# performance improves few percents for shorter keys and worsens few
++# percents for longer keys. This is because USIII integer multiplier
++# is >3x faster than USI&II one, which is harder to match [but see
++# TODO list below]. It should also be noted that SPARC64 V features
++# out-of-order execution, which *might* mean that integer multiplier
++# is pipelined, which in turn *might* be impossible to match... On
++# additional note, SPARC64 V implements FP Multiply-Add instruction,
++# which is perfectly usable in this context... In other words, as far
++# as Fujitsu SPARC64 V goes, talk to the author:-)
++
++# The implementation implies following "non-natural" limitations on
++# input arguments:
++# - num may not be less than 4;
++# - num has to be even;
++# Failure to meet either condition has no fatal effects, simply
++# doesn't give any performance gain.
++
++# TODO:
++# - modulo-schedule inner loop for better performance (on in-order
++#   execution core such as UltraSPARC this shall result in further
++#   noticeable(!) improvement);
++# - dedicated squaring procedure[?];
++
++######################################################################
++# November 2006
++#
++# Modulo-scheduled inner loops allow to interleave floating point and
++# integer instructions and minimize Read-After-Write penalties. This
++# results in *further* 20-50% performance improvement [depending on
++# key length, more for longer keys] on USI&II cores and 30-80% - on
++# USIII&IV.
++
++$output = pop;
++open STDOUT,">$output";
++
++$fname="bn_mul_mont_fpu";
++
++$frame="STACK_FRAME";
++$bias="STACK_BIAS";
++$locals=64;
++
++# In order to provide for 32-/64-bit ABI duality, I keep integers wider
++# than 32 bit in %g1-%g4 and %o0-%o5. %l0-%l7 and %i0-%i5 are used
++# exclusively for pointers, indexes and other small values...
++# int bn_mul_mont(
++$rp="%i0";	# BN_ULONG *rp,
++$ap="%i1";	# const BN_ULONG *ap,
++$bp="%i2";	# const BN_ULONG *bp,
++$np="%i3";	# const BN_ULONG *np,
++$n0="%i4";	# const BN_ULONG *n0,
++$num="%i5";	# int num);
++
++$tp="%l0";	# t[num]
++$ap_l="%l1";	# a[num],n[num] are smashed to 32-bit words and saved
++$ap_h="%l2";	# to these four vectors as double-precision FP values.
++$np_l="%l3";	# This way a bunch of fxtods are eliminated in second
++$np_h="%l4";	# loop and L1-cache aliasing is minimized...
++$i="%l5";
++$j="%l6";
++$mask="%l7";	# 16-bit mask, 0xffff
++
++$n0="%g4";	# reassigned(!) to "64-bit" register
++$carry="%i4";	# %i4 reused(!) for a carry bit
++
++# FP register naming chart
++#
++#     ..HILO
++#       dcba
++#   --------
++#        LOa
++#       LOb
++#      LOc
++#     LOd
++#      HIa
++#     HIb
++#    HIc
++#   HId
++#    ..a
++#   ..b
++$ba="%f0";    $bb="%f2";    $bc="%f4";    $bd="%f6";
++$na="%f8";    $nb="%f10";   $nc="%f12";   $nd="%f14";
++$alo="%f16";  $alo_="%f17"; $ahi="%f18";  $ahi_="%f19";
++$nlo="%f20";  $nlo_="%f21"; $nhi="%f22";  $nhi_="%f23";
++
++$dota="%f24"; $dotb="%f26";
++
++$aloa="%f32"; $alob="%f34"; $aloc="%f36"; $alod="%f38";
++$ahia="%f40"; $ahib="%f42"; $ahic="%f44"; $ahid="%f46";
++$nloa="%f48"; $nlob="%f50"; $nloc="%f52"; $nlod="%f54";
++$nhia="%f56"; $nhib="%f58"; $nhic="%f60"; $nhid="%f62";
++
++$ASI_FL16_P=0xD2;	# magic ASI value to engage 16-bit FP load
++
++$code=<<___;
++#include "sparc_arch.h"
++
++.section	".text",#alloc,#execinstr
++
++.global $fname
++.align  32
++$fname:
++	save	%sp,-$frame-$locals,%sp
++
++	cmp	$num,4
++	bl,a,pn %icc,.Lret
++	clr	%i0
++	andcc	$num,1,%g0		! $num has to be even...
++	bnz,a,pn %icc,.Lret
++	clr	%i0			! signal "unsupported input value"
++
++	srl	$num,1,$num
++	sethi	%hi(0xffff),$mask
++	ld	[%i4+0],$n0		! $n0 reassigned, remember?
++	or	$mask,%lo(0xffff),$mask
++	ld	[%i4+4],%o0
++	sllx	%o0,32,%o0
++	or	%o0,$n0,$n0		! $n0=n0[1].n0[0]
++
++	sll	$num,3,$num		! num*=8
++
++	add	%sp,$bias,%o0		! real top of stack
++	sll	$num,2,%o1
++	add	%o1,$num,%o1		! %o1=num*5
++	sub	%o0,%o1,%o0
++	and	%o0,-2048,%o0		! optimize TLB utilization
++	sub	%o0,$bias,%sp		! alloca(5*num*8)
++
++	rd	%asi,%o7		! save %asi
++	add	%sp,$bias+$frame+$locals,$tp
++	add	$tp,$num,$ap_l
++	add	$ap_l,$num,$ap_l	! [an]p_[lh] point at the vectors' ends !
++	add	$ap_l,$num,$ap_h
++	add	$ap_h,$num,$np_l
++	add	$np_l,$num,$np_h
++
++	wr	%g0,$ASI_FL16_P,%asi	! setup %asi for 16-bit FP loads
++
++	add	$rp,$num,$rp		! readjust input pointers to point
++	add	$ap,$num,$ap		! at the ends too...
++	add	$bp,$num,$bp
++	add	$np,$num,$np
++
++	stx	%o7,[%sp+$bias+$frame+48]	! save %asi
++
++	sub	%g0,$num,$i		! i=-num
++	sub	%g0,$num,$j		! j=-num
++
++	add	$ap,$j,%o3
++	add	$bp,$i,%o4
++
++	ld	[%o3+4],%g1		! bp[0]
++	ld	[%o3+0],%o0
++	ld	[%o4+4],%g5		! ap[0]
++	sllx	%g1,32,%g1
++	ld	[%o4+0],%o1
++	sllx	%g5,32,%g5
++	or	%g1,%o0,%o0
++	or	%g5,%o1,%o1
++
++	add	$np,$j,%o5
++
++	mulx	%o1,%o0,%o0		! ap[0]*bp[0]
++	mulx	$n0,%o0,%o0		! ap[0]*bp[0]*n0
++	stx	%o0,[%sp+$bias+$frame+0]
++
++	ld	[%o3+0],$alo_	! load a[j] as pair of 32-bit words
++	fzeros	$alo
++	ld	[%o3+4],$ahi_
++	fzeros	$ahi
++	ld	[%o5+0],$nlo_	! load n[j] as pair of 32-bit words
++	fzeros	$nlo
++	ld	[%o5+4],$nhi_
++	fzeros	$nhi
++
++	! transfer b[i] to FPU as 4x16-bit values
++	ldda	[%o4+2]%asi,$ba
++	fxtod	$alo,$alo
++	ldda	[%o4+0]%asi,$bb
++	fxtod	$ahi,$ahi
++	ldda	[%o4+6]%asi,$bc
++	fxtod	$nlo,$nlo
++	ldda	[%o4+4]%asi,$bd
++	fxtod	$nhi,$nhi
++
++	! transfer ap[0]*b[0]*n0 to FPU as 4x16-bit values
++	ldda	[%sp+$bias+$frame+6]%asi,$na
++	fxtod	$ba,$ba
++	ldda	[%sp+$bias+$frame+4]%asi,$nb
++	fxtod	$bb,$bb
++	ldda	[%sp+$bias+$frame+2]%asi,$nc
++	fxtod	$bc,$bc
++	ldda	[%sp+$bias+$frame+0]%asi,$nd
++	fxtod	$bd,$bd
++
++	std	$alo,[$ap_l+$j]		! save smashed ap[j] in double format
++	fxtod	$na,$na
++	std	$ahi,[$ap_h+$j]
++	fxtod	$nb,$nb
++	std	$nlo,[$np_l+$j]		! save smashed np[j] in double format
++	fxtod	$nc,$nc
++	std	$nhi,[$np_h+$j]
++	fxtod	$nd,$nd
++
++		fmuld	$alo,$ba,$aloa
++		fmuld	$nlo,$na,$nloa
++		fmuld	$alo,$bb,$alob
++		fmuld	$nlo,$nb,$nlob
++		fmuld	$alo,$bc,$aloc
++	faddd	$aloa,$nloa,$nloa
++		fmuld	$nlo,$nc,$nloc
++		fmuld	$alo,$bd,$alod
++	faddd	$alob,$nlob,$nlob
++		fmuld	$nlo,$nd,$nlod
++		fmuld	$ahi,$ba,$ahia
++	faddd	$aloc,$nloc,$nloc
++		fmuld	$nhi,$na,$nhia
++		fmuld	$ahi,$bb,$ahib
++	faddd	$alod,$nlod,$nlod
++		fmuld	$nhi,$nb,$nhib
++		fmuld	$ahi,$bc,$ahic
++	faddd	$ahia,$nhia,$nhia
++		fmuld	$nhi,$nc,$nhic
++		fmuld	$ahi,$bd,$ahid
++	faddd	$ahib,$nhib,$nhib
++		fmuld	$nhi,$nd,$nhid
++
++	faddd	$ahic,$nhic,$dota	! $nhic
++	faddd	$ahid,$nhid,$dotb	! $nhid
++
++	faddd	$nloc,$nhia,$nloc
++	faddd	$nlod,$nhib,$nlod
++
++	fdtox	$nloa,$nloa
++	fdtox	$nlob,$nlob
++	fdtox	$nloc,$nloc
++	fdtox	$nlod,$nlod
++
++	std	$nloa,[%sp+$bias+$frame+0]
++	add	$j,8,$j
++	std	$nlob,[%sp+$bias+$frame+8]
++	add	$ap,$j,%o4
++	std	$nloc,[%sp+$bias+$frame+16]
++	add	$np,$j,%o5
++	std	$nlod,[%sp+$bias+$frame+24]
++
++	ld	[%o4+0],$alo_	! load a[j] as pair of 32-bit words
++	fzeros	$alo
++	ld	[%o4+4],$ahi_
++	fzeros	$ahi
++	ld	[%o5+0],$nlo_	! load n[j] as pair of 32-bit words
++	fzeros	$nlo
++	ld	[%o5+4],$nhi_
++	fzeros	$nhi
++
++	fxtod	$alo,$alo
++	fxtod	$ahi,$ahi
++	fxtod	$nlo,$nlo
++	fxtod	$nhi,$nhi
++
++	ldx	[%sp+$bias+$frame+0],%o0
++		fmuld	$alo,$ba,$aloa
++	ldx	[%sp+$bias+$frame+8],%o1
++		fmuld	$nlo,$na,$nloa
++	ldx	[%sp+$bias+$frame+16],%o2
++		fmuld	$alo,$bb,$alob
++	ldx	[%sp+$bias+$frame+24],%o3
++		fmuld	$nlo,$nb,$nlob
++
++	srlx	%o0,16,%o7
++	std	$alo,[$ap_l+$j]		! save smashed ap[j] in double format
++		fmuld	$alo,$bc,$aloc
++	add	%o7,%o1,%o1
++	std	$ahi,[$ap_h+$j]
++		faddd	$aloa,$nloa,$nloa
++		fmuld	$nlo,$nc,$nloc
++	srlx	%o1,16,%o7
++	std	$nlo,[$np_l+$j]		! save smashed np[j] in double format
++		fmuld	$alo,$bd,$alod
++	add	%o7,%o2,%o2
++	std	$nhi,[$np_h+$j]
++		faddd	$alob,$nlob,$nlob
++		fmuld	$nlo,$nd,$nlod
++	srlx	%o2,16,%o7
++		fmuld	$ahi,$ba,$ahia
++	add	%o7,%o3,%o3		! %o3.%o2[0..15].%o1[0..15].%o0[0..15]
++		faddd	$aloc,$nloc,$nloc
++		fmuld	$nhi,$na,$nhia
++	!and	%o0,$mask,%o0
++	!and	%o1,$mask,%o1
++	!and	%o2,$mask,%o2
++	!sllx	%o1,16,%o1
++	!sllx	%o2,32,%o2
++	!sllx	%o3,48,%o7
++	!or	%o1,%o0,%o0
++	!or	%o2,%o0,%o0
++	!or	%o7,%o0,%o0		! 64-bit result
++	srlx	%o3,16,%g1		! 34-bit carry
++		fmuld	$ahi,$bb,$ahib
++
++	faddd	$alod,$nlod,$nlod
++		fmuld	$nhi,$nb,$nhib
++		fmuld	$ahi,$bc,$ahic
++	faddd	$ahia,$nhia,$nhia
++		fmuld	$nhi,$nc,$nhic
++		fmuld	$ahi,$bd,$ahid
++	faddd	$ahib,$nhib,$nhib
++		fmuld	$nhi,$nd,$nhid
++
++	faddd	$dota,$nloa,$nloa
++	faddd	$dotb,$nlob,$nlob
++	faddd	$ahic,$nhic,$dota	! $nhic
++	faddd	$ahid,$nhid,$dotb	! $nhid
++
++	faddd	$nloc,$nhia,$nloc
++	faddd	$nlod,$nhib,$nlod
++
++	fdtox	$nloa,$nloa
++	fdtox	$nlob,$nlob
++	fdtox	$nloc,$nloc
++	fdtox	$nlod,$nlod
++
++	std	$nloa,[%sp+$bias+$frame+0]
++	std	$nlob,[%sp+$bias+$frame+8]
++	addcc	$j,8,$j
++	std	$nloc,[%sp+$bias+$frame+16]
++	bz,pn	%icc,.L1stskip
++	std	$nlod,[%sp+$bias+$frame+24]
++
++.align	32			! incidentally already aligned !
++.L1st:
++	add	$ap,$j,%o4
++	add	$np,$j,%o5
++	ld	[%o4+0],$alo_	! load a[j] as pair of 32-bit words
++	fzeros	$alo
++	ld	[%o4+4],$ahi_
++	fzeros	$ahi
++	ld	[%o5+0],$nlo_	! load n[j] as pair of 32-bit words
++	fzeros	$nlo
++	ld	[%o5+4],$nhi_
++	fzeros	$nhi
++
++	fxtod	$alo,$alo
++	fxtod	$ahi,$ahi
++	fxtod	$nlo,$nlo
++	fxtod	$nhi,$nhi
++
++	ldx	[%sp+$bias+$frame+0],%o0
++		fmuld	$alo,$ba,$aloa
++	ldx	[%sp+$bias+$frame+8],%o1
++		fmuld	$nlo,$na,$nloa
++	ldx	[%sp+$bias+$frame+16],%o2
++		fmuld	$alo,$bb,$alob
++	ldx	[%sp+$bias+$frame+24],%o3
++		fmuld	$nlo,$nb,$nlob
++
++	srlx	%o0,16,%o7
++	std	$alo,[$ap_l+$j]		! save smashed ap[j] in double format
++		fmuld	$alo,$bc,$aloc
++	add	%o7,%o1,%o1
++	std	$ahi,[$ap_h+$j]
++		faddd	$aloa,$nloa,$nloa
++		fmuld	$nlo,$nc,$nloc
++	srlx	%o1,16,%o7
++	std	$nlo,[$np_l+$j]		! save smashed np[j] in double format
++		fmuld	$alo,$bd,$alod
++	add	%o7,%o2,%o2
++	std	$nhi,[$np_h+$j]
++		faddd	$alob,$nlob,$nlob
++		fmuld	$nlo,$nd,$nlod
++	srlx	%o2,16,%o7
++		fmuld	$ahi,$ba,$ahia
++	add	%o7,%o3,%o3		! %o3.%o2[0..15].%o1[0..15].%o0[0..15]
++	and	%o0,$mask,%o0
++		faddd	$aloc,$nloc,$nloc
++		fmuld	$nhi,$na,$nhia
++	and	%o1,$mask,%o1
++	and	%o2,$mask,%o2
++		fmuld	$ahi,$bb,$ahib
++	sllx	%o1,16,%o1
++		faddd	$alod,$nlod,$nlod
++		fmuld	$nhi,$nb,$nhib
++	sllx	%o2,32,%o2
++		fmuld	$ahi,$bc,$ahic
++	sllx	%o3,48,%o7
++	or	%o1,%o0,%o0
++		faddd	$ahia,$nhia,$nhia
++		fmuld	$nhi,$nc,$nhic
++	or	%o2,%o0,%o0
++		fmuld	$ahi,$bd,$ahid
++	or	%o7,%o0,%o0		! 64-bit result
++		faddd	$ahib,$nhib,$nhib
++		fmuld	$nhi,$nd,$nhid
++	addcc	%g1,%o0,%o0
++		faddd	$dota,$nloa,$nloa
++	srlx	%o3,16,%g1		! 34-bit carry
++		faddd	$dotb,$nlob,$nlob
++	bcs,a	%xcc,.+8
++	add	%g1,1,%g1
++
++	stx	%o0,[$tp]		! tp[j-1]=
++
++	faddd	$ahic,$nhic,$dota	! $nhic
++	faddd	$ahid,$nhid,$dotb	! $nhid
++
++	faddd	$nloc,$nhia,$nloc
++	faddd	$nlod,$nhib,$nlod
++
++	fdtox	$nloa,$nloa
++	fdtox	$nlob,$nlob
++	fdtox	$nloc,$nloc
++	fdtox	$nlod,$nlod
++
++	std	$nloa,[%sp+$bias+$frame+0]
++	std	$nlob,[%sp+$bias+$frame+8]
++	std	$nloc,[%sp+$bias+$frame+16]
++	std	$nlod,[%sp+$bias+$frame+24]
++
++	addcc	$j,8,$j
++	bnz,pt	%icc,.L1st
++	add	$tp,8,$tp
++
++.L1stskip:
++	fdtox	$dota,$dota
++	fdtox	$dotb,$dotb
++
++	ldx	[%sp+$bias+$frame+0],%o0
++	ldx	[%sp+$bias+$frame+8],%o1
++	ldx	[%sp+$bias+$frame+16],%o2
++	ldx	[%sp+$bias+$frame+24],%o3
++
++	srlx	%o0,16,%o7
++	std	$dota,[%sp+$bias+$frame+32]
++	add	%o7,%o1,%o1
++	std	$dotb,[%sp+$bias+$frame+40]
++	srlx	%o1,16,%o7
++	add	%o7,%o2,%o2
++	srlx	%o2,16,%o7
++	add	%o7,%o3,%o3		! %o3.%o2[0..15].%o1[0..15].%o0[0..15]
++	and	%o0,$mask,%o0
++	and	%o1,$mask,%o1
++	and	%o2,$mask,%o2
++	sllx	%o1,16,%o1
++	sllx	%o2,32,%o2
++	sllx	%o3,48,%o7
++	or	%o1,%o0,%o0
++	or	%o2,%o0,%o0
++	or	%o7,%o0,%o0		! 64-bit result
++	ldx	[%sp+$bias+$frame+32],%o4
++	addcc	%g1,%o0,%o0
++	ldx	[%sp+$bias+$frame+40],%o5
++	srlx	%o3,16,%g1		! 34-bit carry
++	bcs,a	%xcc,.+8
++	add	%g1,1,%g1
++
++	stx	%o0,[$tp]		! tp[j-1]=
++	add	$tp,8,$tp
++
++	srlx	%o4,16,%o7
++	add	%o7,%o5,%o5
++	and	%o4,$mask,%o4
++	sllx	%o5,16,%o7
++	or	%o7,%o4,%o4
++	addcc	%g1,%o4,%o4
++	srlx	%o5,48,%g1
++	bcs,a	%xcc,.+8
++	add	%g1,1,%g1
++
++	mov	%g1,$carry
++	stx	%o4,[$tp]		! tp[num-1]=
++
++	ba	.Louter
++	add	$i,8,$i
++.align	32
++.Louter:
++	sub	%g0,$num,$j		! j=-num
++	add	%sp,$bias+$frame+$locals,$tp
++
++	add	$ap,$j,%o3
++	add	$bp,$i,%o4
++
++	ld	[%o3+4],%g1		! bp[i]
++	ld	[%o3+0],%o0
++	ld	[%o4+4],%g5		! ap[0]
++	sllx	%g1,32,%g1
++	ld	[%o4+0],%o1
++	sllx	%g5,32,%g5
++	or	%g1,%o0,%o0
++	or	%g5,%o1,%o1
++
++	ldx	[$tp],%o2		! tp[0]
++	mulx	%o1,%o0,%o0
++	addcc	%o2,%o0,%o0
++	mulx	$n0,%o0,%o0		! (ap[0]*bp[i]+t[0])*n0
++	stx	%o0,[%sp+$bias+$frame+0]
++
++	! transfer b[i] to FPU as 4x16-bit values
++	ldda	[%o4+2]%asi,$ba
++	ldda	[%o4+0]%asi,$bb
++	ldda	[%o4+6]%asi,$bc
++	ldda	[%o4+4]%asi,$bd
++
++	! transfer (ap[0]*b[i]+t[0])*n0 to FPU as 4x16-bit values
++	ldda	[%sp+$bias+$frame+6]%asi,$na
++	fxtod	$ba,$ba
++	ldda	[%sp+$bias+$frame+4]%asi,$nb
++	fxtod	$bb,$bb
++	ldda	[%sp+$bias+$frame+2]%asi,$nc
++	fxtod	$bc,$bc
++	ldda	[%sp+$bias+$frame+0]%asi,$nd
++	fxtod	$bd,$bd
++	ldd	[$ap_l+$j],$alo		! load a[j] in double format
++	fxtod	$na,$na
++	ldd	[$ap_h+$j],$ahi
++	fxtod	$nb,$nb
++	ldd	[$np_l+$j],$nlo		! load n[j] in double format
++	fxtod	$nc,$nc
++	ldd	[$np_h+$j],$nhi
++	fxtod	$nd,$nd
++
++		fmuld	$alo,$ba,$aloa
++		fmuld	$nlo,$na,$nloa
++		fmuld	$alo,$bb,$alob
++		fmuld	$nlo,$nb,$nlob
++		fmuld	$alo,$bc,$aloc
++	faddd	$aloa,$nloa,$nloa
++		fmuld	$nlo,$nc,$nloc
++		fmuld	$alo,$bd,$alod
++	faddd	$alob,$nlob,$nlob
++		fmuld	$nlo,$nd,$nlod
++		fmuld	$ahi,$ba,$ahia
++	faddd	$aloc,$nloc,$nloc
++		fmuld	$nhi,$na,$nhia
++		fmuld	$ahi,$bb,$ahib
++	faddd	$alod,$nlod,$nlod
++		fmuld	$nhi,$nb,$nhib
++		fmuld	$ahi,$bc,$ahic
++	faddd	$ahia,$nhia,$nhia
++		fmuld	$nhi,$nc,$nhic
++		fmuld	$ahi,$bd,$ahid
++	faddd	$ahib,$nhib,$nhib
++		fmuld	$nhi,$nd,$nhid
++
++	faddd	$ahic,$nhic,$dota	! $nhic
++	faddd	$ahid,$nhid,$dotb	! $nhid
++
++	faddd	$nloc,$nhia,$nloc
++	faddd	$nlod,$nhib,$nlod
++
++	fdtox	$nloa,$nloa
++	fdtox	$nlob,$nlob
++	fdtox	$nloc,$nloc
++	fdtox	$nlod,$nlod
++
++	std	$nloa,[%sp+$bias+$frame+0]
++	std	$nlob,[%sp+$bias+$frame+8]
++	std	$nloc,[%sp+$bias+$frame+16]
++	add	$j,8,$j
++	std	$nlod,[%sp+$bias+$frame+24]
++
++	ldd	[$ap_l+$j],$alo		! load a[j] in double format
++	ldd	[$ap_h+$j],$ahi
++	ldd	[$np_l+$j],$nlo		! load n[j] in double format
++	ldd	[$np_h+$j],$nhi
++
++		fmuld	$alo,$ba,$aloa
++		fmuld	$nlo,$na,$nloa
++		fmuld	$alo,$bb,$alob
++		fmuld	$nlo,$nb,$nlob
++		fmuld	$alo,$bc,$aloc
++	ldx	[%sp+$bias+$frame+0],%o0
++		faddd	$aloa,$nloa,$nloa
++		fmuld	$nlo,$nc,$nloc
++	ldx	[%sp+$bias+$frame+8],%o1
++		fmuld	$alo,$bd,$alod
++	ldx	[%sp+$bias+$frame+16],%o2
++		faddd	$alob,$nlob,$nlob
++		fmuld	$nlo,$nd,$nlod
++	ldx	[%sp+$bias+$frame+24],%o3
++		fmuld	$ahi,$ba,$ahia
++
++	srlx	%o0,16,%o7
++		faddd	$aloc,$nloc,$nloc
++		fmuld	$nhi,$na,$nhia
++	add	%o7,%o1,%o1
++		fmuld	$ahi,$bb,$ahib
++	srlx	%o1,16,%o7
++		faddd	$alod,$nlod,$nlod
++		fmuld	$nhi,$nb,$nhib
++	add	%o7,%o2,%o2
++		fmuld	$ahi,$bc,$ahic
++	srlx	%o2,16,%o7
++		faddd	$ahia,$nhia,$nhia
++		fmuld	$nhi,$nc,$nhic
++	add	%o7,%o3,%o3		! %o3.%o2[0..15].%o1[0..15].%o0[0..15]
++	! why?
++	and	%o0,$mask,%o0
++		fmuld	$ahi,$bd,$ahid
++	and	%o1,$mask,%o1
++	and	%o2,$mask,%o2
++		faddd	$ahib,$nhib,$nhib
++		fmuld	$nhi,$nd,$nhid
++	sllx	%o1,16,%o1
++		faddd	$dota,$nloa,$nloa
++	sllx	%o2,32,%o2
++		faddd	$dotb,$nlob,$nlob
++	sllx	%o3,48,%o7
++	or	%o1,%o0,%o0
++		faddd	$ahic,$nhic,$dota	! $nhic
++	or	%o2,%o0,%o0
++		faddd	$ahid,$nhid,$dotb	! $nhid
++	or	%o7,%o0,%o0		! 64-bit result
++	ldx	[$tp],%o7
++		faddd	$nloc,$nhia,$nloc
++	addcc	%o7,%o0,%o0
++	! end-of-why?
++		faddd	$nlod,$nhib,$nlod
++	srlx	%o3,16,%g1		! 34-bit carry
++		fdtox	$nloa,$nloa
++	bcs,a	%xcc,.+8
++	add	%g1,1,%g1
++
++	fdtox	$nlob,$nlob
++	fdtox	$nloc,$nloc
++	fdtox	$nlod,$nlod
++
++	std	$nloa,[%sp+$bias+$frame+0]
++	std	$nlob,[%sp+$bias+$frame+8]
++	addcc	$j,8,$j
++	std	$nloc,[%sp+$bias+$frame+16]
++	bz,pn	%icc,.Linnerskip
++	std	$nlod,[%sp+$bias+$frame+24]
++
++	ba	.Linner
++	nop
++.align	32
++.Linner:
++	ldd	[$ap_l+$j],$alo		! load a[j] in double format
++	ldd	[$ap_h+$j],$ahi
++	ldd	[$np_l+$j],$nlo		! load n[j] in double format
++	ldd	[$np_h+$j],$nhi
++
++		fmuld	$alo,$ba,$aloa
++		fmuld	$nlo,$na,$nloa
++		fmuld	$alo,$bb,$alob
++		fmuld	$nlo,$nb,$nlob
++		fmuld	$alo,$bc,$aloc
++	ldx	[%sp+$bias+$frame+0],%o0
++		faddd	$aloa,$nloa,$nloa
++		fmuld	$nlo,$nc,$nloc
++	ldx	[%sp+$bias+$frame+8],%o1
++		fmuld	$alo,$bd,$alod
++	ldx	[%sp+$bias+$frame+16],%o2
++		faddd	$alob,$nlob,$nlob
++		fmuld	$nlo,$nd,$nlod
++	ldx	[%sp+$bias+$frame+24],%o3
++		fmuld	$ahi,$ba,$ahia
++
++	srlx	%o0,16,%o7
++		faddd	$aloc,$nloc,$nloc
++		fmuld	$nhi,$na,$nhia
++	add	%o7,%o1,%o1
++		fmuld	$ahi,$bb,$ahib
++	srlx	%o1,16,%o7
++		faddd	$alod,$nlod,$nlod
++		fmuld	$nhi,$nb,$nhib
++	add	%o7,%o2,%o2
++		fmuld	$ahi,$bc,$ahic
++	srlx	%o2,16,%o7
++		faddd	$ahia,$nhia,$nhia
++		fmuld	$nhi,$nc,$nhic
++	add	%o7,%o3,%o3		! %o3.%o2[0..15].%o1[0..15].%o0[0..15]
++	and	%o0,$mask,%o0
++		fmuld	$ahi,$bd,$ahid
++	and	%o1,$mask,%o1
++	and	%o2,$mask,%o2
++		faddd	$ahib,$nhib,$nhib
++		fmuld	$nhi,$nd,$nhid
++	sllx	%o1,16,%o1
++		faddd	$dota,$nloa,$nloa
++	sllx	%o2,32,%o2
++		faddd	$dotb,$nlob,$nlob
++	sllx	%o3,48,%o7
++	or	%o1,%o0,%o0
++		faddd	$ahic,$nhic,$dota	! $nhic
++	or	%o2,%o0,%o0
++		faddd	$ahid,$nhid,$dotb	! $nhid
++	or	%o7,%o0,%o0		! 64-bit result
++		faddd	$nloc,$nhia,$nloc
++	addcc	%g1,%o0,%o0
++	ldx	[$tp+8],%o7		! tp[j]
++		faddd	$nlod,$nhib,$nlod
++	srlx	%o3,16,%g1		! 34-bit carry
++		fdtox	$nloa,$nloa
++	bcs,a	%xcc,.+8
++	add	%g1,1,%g1
++		fdtox	$nlob,$nlob
++	addcc	%o7,%o0,%o0
++		fdtox	$nloc,$nloc
++	bcs,a	%xcc,.+8
++	add	%g1,1,%g1
++
++	stx	%o0,[$tp]		! tp[j-1]
++		fdtox	$nlod,$nlod
++
++	std	$nloa,[%sp+$bias+$frame+0]
++	std	$nlob,[%sp+$bias+$frame+8]
++	std	$nloc,[%sp+$bias+$frame+16]
++	addcc	$j,8,$j
++	std	$nlod,[%sp+$bias+$frame+24]
++	bnz,pt	%icc,.Linner
++	add	$tp,8,$tp
++
++.Linnerskip:
++	fdtox	$dota,$dota
++	fdtox	$dotb,$dotb
++
++	ldx	[%sp+$bias+$frame+0],%o0
++	ldx	[%sp+$bias+$frame+8],%o1
++	ldx	[%sp+$bias+$frame+16],%o2
++	ldx	[%sp+$bias+$frame+24],%o3
++
++	srlx	%o0,16,%o7
++	std	$dota,[%sp+$bias+$frame+32]
++	add	%o7,%o1,%o1
++	std	$dotb,[%sp+$bias+$frame+40]
++	srlx	%o1,16,%o7
++	add	%o7,%o2,%o2
++	srlx	%o2,16,%o7
++	add	%o7,%o3,%o3		! %o3.%o2[0..15].%o1[0..15].%o0[0..15]
++	and	%o0,$mask,%o0
++	and	%o1,$mask,%o1
++	and	%o2,$mask,%o2
++	sllx	%o1,16,%o1
++	sllx	%o2,32,%o2
++	sllx	%o3,48,%o7
++	or	%o1,%o0,%o0
++	or	%o2,%o0,%o0
++	ldx	[%sp+$bias+$frame+32],%o4
++	or	%o7,%o0,%o0		! 64-bit result
++	ldx	[%sp+$bias+$frame+40],%o5
++	addcc	%g1,%o0,%o0
++	ldx	[$tp+8],%o7		! tp[j]
++	srlx	%o3,16,%g1		! 34-bit carry
++	bcs,a	%xcc,.+8
++	add	%g1,1,%g1
++
++	addcc	%o7,%o0,%o0
++	bcs,a	%xcc,.+8
++	add	%g1,1,%g1
++
++	stx	%o0,[$tp]		! tp[j-1]
++	add	$tp,8,$tp
++
++	srlx	%o4,16,%o7
++	add	%o7,%o5,%o5
++	and	%o4,$mask,%o4
++	sllx	%o5,16,%o7
++	or	%o7,%o4,%o4
++	addcc	%g1,%o4,%o4
++	srlx	%o5,48,%g1
++	bcs,a	%xcc,.+8
++	add	%g1,1,%g1
++
++	addcc	$carry,%o4,%o4
++	stx	%o4,[$tp]		! tp[num-1]
++	mov	%g1,$carry
++	bcs,a	%xcc,.+8
++	add	$carry,1,$carry
++
++	addcc	$i,8,$i
++	bnz	%icc,.Louter
++	nop
++
++	add	$tp,8,$tp		! adjust tp to point at the end
++	orn	%g0,%g0,%g4
++	sub	%g0,$num,%o7		! n=-num
++	ba	.Lsub
++	subcc	%g0,%g0,%g0		! clear %icc.c
++
++.align	32
++.Lsub:
++	ldx	[$tp+%o7],%o0
++	add	$np,%o7,%g1
++	ld	[%g1+0],%o2
++	ld	[%g1+4],%o3
++	srlx	%o0,32,%o1
++	subccc	%o0,%o2,%o2
++	add	$rp,%o7,%g1
++	subccc	%o1,%o3,%o3
++	st	%o2,[%g1+0]
++	add	%o7,8,%o7
++	brnz,pt	%o7,.Lsub
++	st	%o3,[%g1+4]
++	subc	$carry,0,%g4
++	sub	%g0,$num,%o7		! n=-num
++	ba	.Lcopy
++	nop
++
++.align	32
++.Lcopy:
++	ldx	[$tp+%o7],%o0
++	add	$rp,%o7,%g1
++	ld	[%g1+0],%o2
++	ld	[%g1+4],%o3
++	stx	%g0,[$tp+%o7]
++	and	%o0,%g4,%o0
++	srlx	%o0,32,%o1
++	andn	%o2,%g4,%o2
++	andn	%o3,%g4,%o3
++	or	%o2,%o0,%o0
++	or	%o3,%o1,%o1
++	st	%o0,[%g1+0]
++	add	%o7,8,%o7
++	brnz,pt	%o7,.Lcopy
++	st	%o1,[%g1+4]
++	sub	%g0,$num,%o7		! n=-num
++
++.Lzap:
++	stx	%g0,[$ap_l+%o7]
++	stx	%g0,[$ap_h+%o7]
++	stx	%g0,[$np_l+%o7]
++	stx	%g0,[$np_h+%o7]
++	add	%o7,8,%o7
++	brnz,pt	%o7,.Lzap
++	nop
++
++	ldx	[%sp+$bias+$frame+48],%o7
++	wr	%g0,%o7,%asi		! restore %asi
++
++	mov	1,%i0
++.Lret:
++	ret
++	restore
++.type   $fname,#function
++.size	$fname,(.-$fname)
++.asciz	"Montgomery Multipltication for UltraSPARC, CRYPTOGAMS by "
++.align	32
++___
++
++$code =~ s/\`([^\`]*)\`/eval($1)/gem;
++
++# Below substitution makes it possible to compile without demanding
++# VIS extensions on command line, e.g. -xarch=v9 vs. -xarch=v9a. I
++# dare to do this, because VIS capability is detected at run-time now
++# and this routine is not called on CPU not capable to execute it. Do
++# note that fzeros is not the only VIS dependency! Another dependency
++# is implicit and is just _a_ numerical value loaded to %asi register,
++# which assembler can't recognize as VIS specific...
++$code =~ s/fzeros\s+%f([0-9]+)/
++	   sprintf(".word\t0x%x\t! fzeros %%f%d",0x81b00c20|($1<<25),$1)
++	  /gem;
++
++print $code;
++# flush
++close STDOUT;
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/bn/asm/via-mont.pl b/CryptoPkg/Library/OpensslLib/openssl/crypto/bn/asm/via-mont.pl
+new file mode 100644
+index 0000000..9f81bc8
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/bn/asm/via-mont.pl
+@@ -0,0 +1,254 @@
++#! /usr/bin/env perl
++# Copyright 2006-2016 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
++# in the file LICENSE in the source distribution or at
++# https://www.openssl.org/source/license.html
++
++#
++# ====================================================================
++# Written by Andy Polyakov  for the OpenSSL
++# project. The module is, however, dual licensed under OpenSSL and
++# CRYPTOGAMS licenses depending on where you obtain it. For further
++# details see http://www.openssl.org/~appro/cryptogams/.
++# ====================================================================
++#
++# Wrapper around 'rep montmul', VIA-specific instruction accessing
++# PadLock Montgomery Multiplier. The wrapper is designed as drop-in
++# replacement for OpenSSL bn_mul_mont [first implemented in 0.9.9].
++#
++# Below are interleaved outputs from 'openssl speed rsa dsa' for 4
++# different software configurations on 1.5GHz VIA Esther processor.
++# Lines marked with "software integer" denote performance of hand-
++# coded integer-only assembler found in OpenSSL 0.9.7. "Software SSE2"
++# refers to hand-coded SSE2 Montgomery multiplication procedure found
++# OpenSSL 0.9.9. "Hardware VIA SDK" refers to padlock_pmm routine from
++# Padlock SDK 2.0.1 available for download from VIA, which naturally
++# utilizes the magic 'repz montmul' instruction. And finally "hardware
++# this" refers to *this* implementation which also uses 'repz montmul'
++#
++#                   sign    verify    sign/s verify/s
++# rsa  512 bits 0.001720s 0.000140s    581.4   7149.7	software integer
++# rsa  512 bits 0.000690s 0.000086s   1450.3  11606.0	software SSE2
++# rsa  512 bits 0.006136s 0.000201s    163.0   4974.5	hardware VIA SDK
++# rsa  512 bits 0.000712s 0.000050s   1404.9  19858.5	hardware this
++#
++# rsa 1024 bits 0.008518s 0.000413s    117.4   2420.8	software integer
++# rsa 1024 bits 0.004275s 0.000277s    233.9   3609.7	software SSE2
++# rsa 1024 bits 0.012136s 0.000260s     82.4   3844.5	hardware VIA SDK
++# rsa 1024 bits 0.002522s 0.000116s    396.5   8650.9	hardware this
++#
++# rsa 2048 bits 0.050101s 0.001371s     20.0    729.6	software integer
++# rsa 2048 bits 0.030273s 0.001008s     33.0    991.9	software SSE2
++# rsa 2048 bits 0.030833s 0.000976s     32.4   1025.1	hardware VIA SDK
++# rsa 2048 bits 0.011879s 0.000342s     84.2   2921.7	hardware this
++#
++# rsa 4096 bits 0.327097s 0.004859s      3.1    205.8	software integer
++# rsa 4096 bits 0.229318s 0.003859s      4.4    259.2	software SSE2
++# rsa 4096 bits 0.233953s 0.003274s      4.3    305.4	hardware VIA SDK
++# rsa 4096 bits 0.070493s 0.001166s     14.2    857.6	hardware this
++#
++# dsa  512 bits 0.001342s 0.001651s    745.2    605.7	software integer
++# dsa  512 bits 0.000844s 0.000987s   1185.3   1013.1	software SSE2
++# dsa  512 bits 0.001902s 0.002247s    525.6    444.9	hardware VIA SDK
++# dsa  512 bits 0.000458s 0.000524s   2182.2   1909.1	hardware this
++#
++# dsa 1024 bits 0.003964s 0.004926s    252.3    203.0	software integer
++# dsa 1024 bits 0.002686s 0.003166s    372.3    315.8	software SSE2
++# dsa 1024 bits 0.002397s 0.002823s    417.1    354.3	hardware VIA SDK
++# dsa 1024 bits 0.000978s 0.001170s   1022.2    855.0	hardware this
++#
++# dsa 2048 bits 0.013280s 0.016518s     75.3     60.5	software integer
++# dsa 2048 bits 0.009911s 0.011522s    100.9     86.8	software SSE2
++# dsa 2048 bits 0.009542s 0.011763s    104.8     85.0	hardware VIA SDK
++# dsa 2048 bits 0.002884s 0.003352s    346.8    298.3	hardware this
++#
++# To give you some other reference point here is output for 2.4GHz P4
++# running hand-coded SSE2 bn_mul_mont found in 0.9.9, i.e. "software
++# SSE2" in above terms.
++#
++# rsa  512 bits 0.000407s 0.000047s   2454.2  21137.0
++# rsa 1024 bits 0.002426s 0.000141s    412.1   7100.0
++# rsa 2048 bits 0.015046s 0.000491s     66.5   2034.9
++# rsa 4096 bits 0.109770s 0.002379s      9.1    420.3
++# dsa  512 bits 0.000438s 0.000525s   2281.1   1904.1
++# dsa 1024 bits 0.001346s 0.001595s    742.7    627.0
++# dsa 2048 bits 0.004745s 0.005582s    210.7    179.1
++#
++# Conclusions: 
++# - VIA SDK leaves a *lot* of room for improvement (which this
++#   implementation successfully fills:-);
++# - 'rep montmul' gives up to >3x performance improvement depending on
++#   key length;
++# - in terms of absolute performance it delivers approximately as much
++#   as modern out-of-order 32-bit cores [again, for longer keys].
++
++$0 =~ m/(.*[\/\\])[^\/\\]+$/; $dir=$1;
++push(@INC,"${dir}","${dir}../../perlasm");
++require "x86asm.pl";
++
++$output = pop;
++open STDOUT,">$output";
++
++&asm_init($ARGV[0],"via-mont.pl");
++
++# int bn_mul_mont(BN_ULONG *rp, const BN_ULONG *ap, const BN_ULONG *bp, const BN_ULONG *np,const BN_ULONG *n0, int num);
++$func="bn_mul_mont_padlock";
++
++$pad=16*1;	# amount of reserved bytes on top of every vector
++
++# stack layout
++$mZeroPrime=&DWP(0,"esp");		# these are specified by VIA
++$A=&DWP(4,"esp");
++$B=&DWP(8,"esp");
++$T=&DWP(12,"esp");
++$M=&DWP(16,"esp");
++$scratch=&DWP(20,"esp");
++$rp=&DWP(24,"esp");			# these are mine
++$sp=&DWP(28,"esp");
++# &DWP(32,"esp")			# 32 byte scratch area
++# &DWP(64+(4*$num+$pad)*0,"esp")	# padded tp[num]
++# &DWP(64+(4*$num+$pad)*1,"esp")	# padded copy of ap[num]
++# &DWP(64+(4*$num+$pad)*2,"esp")	# padded copy of bp[num]
++# &DWP(64+(4*$num+$pad)*3,"esp")	# padded copy of np[num]
++# Note that SDK suggests to unconditionally allocate 2K per vector. This
++# has quite an impact on performance. It naturally depends on key length,
++# but to give an example 1024 bit private RSA key operations suffer >30%
++# penalty. I allocate only as much as actually required...
++
++&function_begin($func);
++	&xor	("eax","eax");
++	&mov	("ecx",&wparam(5));	# num
++	# meet VIA's limitations for num [note that the specification
++	# expresses them in bits, while we work with amount of 32-bit words]
++	&test	("ecx",3);
++	&jnz	(&label("leave"));	# num % 4 != 0
++	&cmp	("ecx",8);
++	&jb	(&label("leave"));	# num < 8
++	&cmp	("ecx",1024);
++	&ja	(&label("leave"));	# num > 1024
++
++	&pushf	();
++	&cld	();
++
++	&mov	("edi",&wparam(0));	# rp
++	&mov	("eax",&wparam(1));	# ap
++	&mov	("ebx",&wparam(2));	# bp
++	&mov	("edx",&wparam(3));	# np
++	&mov	("esi",&wparam(4));	# n0
++	&mov	("esi",&DWP(0,"esi"));	# *n0
++
++	&lea	("ecx",&DWP($pad,"","ecx",4));	# ecx becomes vector size in bytes
++	&lea	("ebp",&DWP(64,"","ecx",4));	# allocate 4 vectors + 64 bytes
++	&neg	("ebp");
++	&add	("ebp","esp");
++	&and	("ebp",-64);		# align to cache-line
++	&xchg	("ebp","esp");		# alloca
++
++	&mov	($rp,"edi");		# save rp
++	&mov	($sp,"ebp");		# save esp
++
++	&mov	($mZeroPrime,"esi");
++	&lea	("esi",&DWP(64,"esp"));	# tp
++	&mov	($T,"esi");
++	&lea	("edi",&DWP(32,"esp"));	# scratch area
++	&mov	($scratch,"edi");
++	&mov	("esi","eax");
++
++	&lea	("ebp",&DWP(-$pad,"ecx"));
++	&shr	("ebp",2);		# restore original num value in ebp
++
++	&xor	("eax","eax");
++
++	&mov	("ecx","ebp");
++	&lea	("ecx",&DWP((32+$pad)/4,"ecx"));# padded tp + scratch
++	&data_byte(0xf3,0xab);		# rep stosl, bzero
++
++	&mov	("ecx","ebp");
++	&lea	("edi",&DWP(64+$pad,"esp","ecx",4));# pointer to ap copy
++	&mov	($A,"edi");
++	&data_byte(0xf3,0xa5);		# rep movsl, memcpy
++	&mov	("ecx",$pad/4);
++	&data_byte(0xf3,0xab);		# rep stosl, bzero pad
++	# edi points at the end of padded ap copy...
++
++	&mov	("ecx","ebp");
++	&mov	("esi","ebx");
++	&mov	($B,"edi");
++	&data_byte(0xf3,0xa5);		# rep movsl, memcpy
++	&mov	("ecx",$pad/4);
++	&data_byte(0xf3,0xab);		# rep stosl, bzero pad
++	# edi points at the end of padded bp copy...
++
++	&mov	("ecx","ebp");
++	&mov	("esi","edx");
++	&mov	($M,"edi");
++	&data_byte(0xf3,0xa5);		# rep movsl, memcpy
++	&mov	("ecx",$pad/4);
++	&data_byte(0xf3,0xab);		# rep stosl, bzero pad
++	# edi points at the end of padded np copy...
++
++	# let magic happen...
++	&mov	("ecx","ebp");
++	&mov	("esi","esp");
++	&shl	("ecx",5);		# convert word counter to bit counter
++	&align	(4);
++	&data_byte(0xf3,0x0f,0xa6,0xc0);# rep montmul
++
++	&mov	("ecx","ebp");
++	&lea	("esi",&DWP(64,"esp"));		# tp
++	# edi still points at the end of padded np copy...
++	&neg	("ebp");
++	&lea	("ebp",&DWP(-$pad,"edi","ebp",4));	# so just "rewind"
++	&mov	("edi",$rp);			# restore rp
++	&xor	("edx","edx");			# i=0 and clear CF
++
++&set_label("sub",8);
++	&mov	("eax",&DWP(0,"esi","edx",4));
++	&sbb	("eax",&DWP(0,"ebp","edx",4));
++	&mov	(&DWP(0,"edi","edx",4),"eax");	# rp[i]=tp[i]-np[i]
++	&lea	("edx",&DWP(1,"edx"));		# i++
++	&loop	(&label("sub"));		# doesn't affect CF!
++
++	&mov	("eax",&DWP(0,"esi","edx",4));	# upmost overflow bit
++	&sbb	("eax",0);
++	&and	("esi","eax");
++	¬	("eax");
++	&mov	("ebp","edi");
++	&and	("ebp","eax");
++	&or	("esi","ebp");			# tp=carry?tp:rp
++
++	&mov	("ecx","edx");			# num
++	&xor	("edx","edx");			# i=0
++
++&set_label("copy",8);
++	&mov	("eax",&DWP(0,"esi","edx",4));
++	&mov	(&DWP(64,"esp","edx",4),"ecx");	# zap tp
++	&mov	(&DWP(0,"edi","edx",4),"eax");
++	&lea	("edx",&DWP(1,"edx"));		# i++
++	&loop	(&label("copy"));
++
++	&mov	("ebp",$sp);
++	&xor	("eax","eax");
++
++	&mov	("ecx",64/4);
++	&mov	("edi","esp");		# zap frame including scratch area
++	&data_byte(0xf3,0xab);		# rep stosl, bzero
++
++	# zap copies of ap, bp and np
++	&lea	("edi",&DWP(64+$pad,"esp","edx",4));# pointer to ap
++	&lea	("ecx",&DWP(3*$pad/4,"edx","edx",2));
++	&data_byte(0xf3,0xab);		# rep stosl, bzero
++
++	&mov	("esp","ebp");
++	&inc	("eax");		# signal "done"
++	&popf	();
++&set_label("leave");
++&function_end($func);
++
++&asciz("Padlock Montgomery Multiplication, CRYPTOGAMS by ");
++
++&asm_finish();
++
++close STDOUT;
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/bn/asm/vis3-mont.pl b/CryptoPkg/Library/OpensslLib/openssl/crypto/bn/asm/vis3-mont.pl
+new file mode 100644
+index 0000000..64dba44
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/bn/asm/vis3-mont.pl
+@@ -0,0 +1,384 @@
++#! /usr/bin/env perl
++# Copyright 2012-2016 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
++# in the file LICENSE in the source distribution or at
++# https://www.openssl.org/source/license.html
++
++
++# ====================================================================
++# Written by Andy Polyakov  for the OpenSSL
++# project. The module is, however, dual licensed under OpenSSL and
++# CRYPTOGAMS licenses depending on where you obtain it. For further
++# details see http://www.openssl.org/~appro/cryptogams/.
++# ====================================================================
++
++# October 2012.
++#
++# SPARCv9 VIS3 Montgomery multiplicaion procedure suitable for T3 and
++# onward. There are three new instructions used here: umulxhi,
++# addxc[cc] and initializing store. On T3 RSA private key operations
++# are 1.54/1.87/2.11/2.26 times faster for 512/1024/2048/4096-bit key
++# lengths. This is without dedicated squaring procedure. On T4
++# corresponding coefficients are 1.47/2.10/2.80/2.90x, which is mostly
++# for reference purposes, because T4 has dedicated Montgomery
++# multiplication and squaring *instructions* that deliver even more.
++
++$output = pop;
++open STDOUT,">$output";
++
++$frame = "STACK_FRAME";
++$bias = "STACK_BIAS";
++
++$code.=<<___;
++#include "sparc_arch.h"
++
++#ifdef	__arch64__
++.register	%g2,#scratch
++.register	%g3,#scratch
++#endif
++
++.section	".text",#alloc,#execinstr
++___
++
++($n0,$m0,$m1,$lo0,$hi0, $lo1,$hi1,$aj,$alo,$nj,$nlo,$tj)=
++	(map("%g$_",(1..5)),map("%o$_",(0..5,7)));
++
++# int bn_mul_mont(
++$rp="%o0";	# BN_ULONG *rp,
++$ap="%o1";	# const BN_ULONG *ap,
++$bp="%o2";	# const BN_ULONG *bp,
++$np="%o3";	# const BN_ULONG *np,
++$n0p="%o4";	# const BN_ULONG *n0,
++$num="%o5";	# int num);	# caller ensures that num is even
++				# and >=6
++$code.=<<___;
++.globl	bn_mul_mont_vis3
++.align	32
++bn_mul_mont_vis3:
++	add	%sp,	$bias,	%g4	! real top of stack
++	sll	$num,	2,	$num	! size in bytes
++	add	$num,	63,	%g5
++	andn	%g5,	63,	%g5	! buffer size rounded up to 64 bytes
++	add	%g5,	%g5,	%g1
++	add	%g5,	%g1,	%g1	! 3*buffer size
++	sub	%g4,	%g1,	%g1
++	andn	%g1,	63,	%g1	! align at 64 byte
++	sub	%g1,	$frame,	%g1	! new top of stack
++	sub	%g1,	%g4,	%g1
++
++	save	%sp,	%g1,	%sp
++___
++
++#	+-------------------------------+<-----	%sp
++#	.				.
++#	+-------------------------------+<-----	aligned at 64 bytes
++#	| __int64 tmp[0]		|
++#	+-------------------------------+
++#	.				.
++#	.				.
++#	+-------------------------------+<----- aligned at 64 bytes
++#	| __int64 ap[1..0]		|	converted ap[]
++#	+-------------------------------+
++#	| __int64 np[1..0]		|	converted np[]
++#	+-------------------------------+
++#	| __int64 ap[3..2]		|
++#	.				.
++#	.				.
++#	+-------------------------------+
++($rp,$ap,$bp,$np,$n0p,$num)=map("%i$_",(0..5));
++($t0,$t1,$t2,$t3,$cnt,$tp,$bufsz,$anp)=map("%l$_",(0..7));
++($ovf,$i)=($t0,$t1);
++$code.=<<___;
++	ld	[$n0p+0],	$t0	! pull n0[0..1] value
++	add	%sp, $bias+$frame, $tp
++	ld	[$n0p+4],	$t1
++	add	$tp,	%g5,	$anp
++	ld	[$bp+0],	$t2	! m0=bp[0]
++	sllx	$t1,	32,	$n0
++	ld	[$bp+4],	$t3
++	or	$t0,	$n0,	$n0
++	add	$bp,	8,	$bp
++
++	ld	[$ap+0],	$t0	! ap[0]
++	sllx	$t3,	32,	$m0
++	ld	[$ap+4],	$t1
++	or	$t2,	$m0,	$m0
++
++	ld	[$ap+8],	$t2	! ap[1]
++	sllx	$t1,	32,	$aj
++	ld	[$ap+12],	$t3
++	or	$t0,	$aj,	$aj
++	add	$ap,	16,	$ap
++	stx	$aj,	[$anp]		! converted ap[0]
++
++	mulx	$aj,	$m0,	$lo0	! ap[0]*bp[0]
++	umulxhi	$aj,	$m0,	$hi0
++
++	ld	[$np+0],	$t0	! np[0]
++	sllx	$t3,	32,	$aj
++	ld	[$np+4],	$t1
++	or	$t2,	$aj,	$aj
++
++	ld	[$np+8],	$t2	! np[1]
++	sllx	$t1,	32,	$nj
++	ld	[$np+12],	$t3
++	or	$t0, $nj,	$nj
++	add	$np,	16,	$np
++	stx	$nj,	[$anp+8]	! converted np[0]
++
++	mulx	$lo0,	$n0,	$m1	! "tp[0]"*n0
++	stx	$aj,	[$anp+16]	! converted ap[1]
++
++	mulx	$aj,	$m0,	$alo	! ap[1]*bp[0]
++	umulxhi	$aj,	$m0,	$aj	! ahi=aj
++
++	mulx	$nj,	$m1,	$lo1	! np[0]*m1
++	umulxhi	$nj,	$m1,	$hi1
++
++	sllx	$t3,	32,	$nj
++	or	$t2,	$nj,	$nj
++	stx	$nj,	[$anp+24]	! converted np[1]
++	add	$anp,	32,	$anp
++
++	addcc	$lo0,	$lo1,	$lo1
++	addxc	%g0,	$hi1,	$hi1
++
++	mulx	$nj,	$m1,	$nlo	! np[1]*m1
++	umulxhi	$nj,	$m1,	$nj	! nhi=nj
++
++	ba	.L1st
++	sub	$num,	24,	$cnt	! cnt=num-3
++
++.align	16
++.L1st:
++	ld	[$ap+0],	$t0	! ap[j]
++	addcc	$alo,	$hi0,	$lo0
++	ld	[$ap+4],	$t1
++	addxc	$aj,	%g0,	$hi0
++
++	sllx	$t1,	32,	$aj
++	add	$ap,	8,	$ap
++	or	$t0,	$aj,	$aj
++	stx	$aj,	[$anp]		! converted ap[j]
++
++	ld	[$np+0],	$t2	! np[j]
++	addcc	$nlo,	$hi1,	$lo1
++	ld	[$np+4],	$t3
++	addxc	$nj,	%g0,	$hi1	! nhi=nj
++
++	sllx	$t3,	32,	$nj
++	add	$np,	8,	$np
++	mulx	$aj,	$m0,	$alo	! ap[j]*bp[0]
++	or	$t2,	$nj,	$nj
++	umulxhi	$aj,	$m0,	$aj	! ahi=aj
++	stx	$nj,	[$anp+8]	! converted np[j]
++	add	$anp,	16,	$anp	! anp++
++
++	mulx	$nj,	$m1,	$nlo	! np[j]*m1
++	addcc	$lo0,	$lo1,	$lo1	! np[j]*m1+ap[j]*bp[0]
++	umulxhi	$nj,	$m1,	$nj	! nhi=nj
++	addxc	%g0,	$hi1,	$hi1
++	stx	$lo1,	[$tp]		! tp[j-1]
++	add	$tp,	8,	$tp	! tp++
++
++	brnz,pt	$cnt,	.L1st
++	sub	$cnt,	8,	$cnt	! j--
++!.L1st
++	addcc	$alo,	$hi0,	$lo0
++	addxc	$aj,	%g0,	$hi0	! ahi=aj
++
++	addcc	$nlo,	$hi1,	$lo1
++	addxc	$nj,	%g0,	$hi1
++	addcc	$lo0,	$lo1,	$lo1	! np[j]*m1+ap[j]*bp[0]
++	addxc	%g0,	$hi1,	$hi1
++	stx	$lo1,	[$tp]		! tp[j-1]
++	add	$tp,	8,	$tp
++
++	addcc	$hi0,	$hi1,	$hi1
++	addxc	%g0,	%g0,	$ovf	! upmost overflow bit
++	stx	$hi1,	[$tp]
++	add	$tp,	8,	$tp
++
++	ba	.Louter
++	sub	$num,	16,	$i	! i=num-2
++
++.align	16
++.Louter:
++	ld	[$bp+0],	$t2	! m0=bp[i]
++	ld	[$bp+4],	$t3
++
++	sub	$anp,	$num,	$anp	! rewind
++	sub	$tp,	$num,	$tp
++	sub	$anp,	$num,	$anp
++
++	add	$bp,	8,	$bp
++	sllx	$t3,	32,	$m0
++	ldx	[$anp+0],	$aj	! ap[0]
++	or	$t2,	$m0,	$m0
++	ldx	[$anp+8],	$nj	! np[0]
++
++	mulx	$aj,	$m0,	$lo0	! ap[0]*bp[i]
++	ldx	[$tp],		$tj	! tp[0]
++	umulxhi	$aj,	$m0,	$hi0
++	ldx	[$anp+16],	$aj	! ap[1]
++	addcc	$lo0,	$tj,	$lo0	! ap[0]*bp[i]+tp[0]
++	mulx	$aj,	$m0,	$alo	! ap[1]*bp[i]
++	addxc	%g0,	$hi0,	$hi0
++	mulx	$lo0,	$n0,	$m1	! tp[0]*n0
++	umulxhi	$aj,	$m0,	$aj	! ahi=aj
++	mulx	$nj,	$m1,	$lo1	! np[0]*m1
++	umulxhi	$nj,	$m1,	$hi1
++	ldx	[$anp+24],	$nj	! np[1]
++	add	$anp,	32,	$anp
++	addcc	$lo1,	$lo0,	$lo1
++	mulx	$nj,	$m1,	$nlo	! np[1]*m1
++	addxc	%g0,	$hi1,	$hi1
++	umulxhi	$nj,	$m1,	$nj	! nhi=nj
++
++	ba	.Linner
++	sub	$num,	24,	$cnt	! cnt=num-3
++.align	16
++.Linner:
++	addcc	$alo,	$hi0,	$lo0
++	ldx	[$tp+8],	$tj	! tp[j]
++	addxc	$aj,	%g0,	$hi0	! ahi=aj
++	ldx	[$anp+0],	$aj	! ap[j]
++	addcc	$nlo,	$hi1,	$lo1
++	mulx	$aj,	$m0,	$alo	! ap[j]*bp[i]
++	addxc	$nj,	%g0,	$hi1	! nhi=nj
++	ldx	[$anp+8],	$nj	! np[j]
++	add	$anp,	16,	$anp
++	umulxhi	$aj,	$m0,	$aj	! ahi=aj
++	addcc	$lo0,	$tj,	$lo0	! ap[j]*bp[i]+tp[j]
++	mulx	$nj,	$m1,	$nlo	! np[j]*m1
++	addxc	%g0,	$hi0,	$hi0
++	umulxhi	$nj,	$m1,	$nj	! nhi=nj
++	addcc	$lo1,	$lo0,	$lo1	! np[j]*m1+ap[j]*bp[i]+tp[j]
++	addxc	%g0,	$hi1,	$hi1
++	stx	$lo1,	[$tp]		! tp[j-1]
++	add	$tp,	8,	$tp
++	brnz,pt	$cnt,	.Linner
++	sub	$cnt,	8,	$cnt
++!.Linner
++	ldx	[$tp+8],	$tj	! tp[j]
++	addcc	$alo,	$hi0,	$lo0
++	addxc	$aj,	%g0,	$hi0	! ahi=aj
++	addcc	$lo0,	$tj,	$lo0	! ap[j]*bp[i]+tp[j]
++	addxc	%g0,	$hi0,	$hi0
++
++	addcc	$nlo,	$hi1,	$lo1
++	addxc	$nj,	%g0,	$hi1	! nhi=nj
++	addcc	$lo1,	$lo0,	$lo1	! np[j]*m1+ap[j]*bp[i]+tp[j]
++	addxc	%g0,	$hi1,	$hi1
++	stx	$lo1,	[$tp]		! tp[j-1]
++
++	subcc	%g0,	$ovf,	%g0	! move upmost overflow to CCR.xcc
++	addxccc	$hi1,	$hi0,	$hi1
++	addxc	%g0,	%g0,	$ovf
++	stx	$hi1,	[$tp+8]
++	add	$tp,	16,	$tp
++
++	brnz,pt	$i,	.Louter
++	sub	$i,	8,	$i
++
++	sub	$anp,	$num,	$anp	! rewind
++	sub	$tp,	$num,	$tp
++	sub	$anp,	$num,	$anp
++	ba	.Lsub
++	subcc	$num,	8,	$cnt	! cnt=num-1 and clear CCR.xcc
++
++.align	16
++.Lsub:
++	ldx	[$tp],		$tj
++	add	$tp,	8,	$tp
++	ldx	[$anp+8],	$nj
++	add	$anp,	16,	$anp
++	subccc	$tj,	$nj,	$t2	! tp[j]-np[j]
++	srlx	$tj,	32,	$tj
++	srlx	$nj,	32,	$nj
++	subccc	$tj,	$nj,	$t3
++	add	$rp,	8,	$rp
++	st	$t2,	[$rp-4]		! reverse order
++	st	$t3,	[$rp-8]
++	brnz,pt	$cnt,	.Lsub
++	sub	$cnt,	8,	$cnt
++
++	sub	$anp,	$num,	$anp	! rewind
++	sub	$tp,	$num,	$tp
++	sub	$anp,	$num,	$anp
++	sub	$rp,	$num,	$rp
++
++	subc	$ovf,	%g0,	$ovf	! handle upmost overflow bit
++	and	$tp,	$ovf,	$ap
++	andn	$rp,	$ovf,	$np
++	or	$np,	$ap,	$ap	! ap=borrow?tp:rp
++	ba	.Lcopy
++	sub	$num,	8,	$cnt
++
++.align	16
++.Lcopy:					! copy or in-place refresh
++	ld	[$ap+0],	$t2
++	ld	[$ap+4],	$t3
++	add	$ap,	8,	$ap
++	stx	%g0,	[$tp]		! zap
++	add	$tp,	8,	$tp
++	stx	%g0,	[$anp]		! zap
++	stx	%g0,	[$anp+8]
++	add	$anp,	16,	$anp
++	st	$t3,	[$rp+0]		! flip order
++	st	$t2,	[$rp+4]
++	add	$rp,	8,	$rp
++	brnz	$cnt,	.Lcopy
++	sub	$cnt,	8,	$cnt
++
++	mov	1,	%o0
++	ret
++	restore
++.type	bn_mul_mont_vis3, #function
++.size	bn_mul_mont_vis3, .-bn_mul_mont_vis3
++.asciz  "Montgomery Multiplication for SPARCv9 VIS3, CRYPTOGAMS by "
++.align	4
++___
++
++# Purpose of these subroutines is to explicitly encode VIS instructions,
++# so that one can compile the module without having to specify VIS
++# extensions on compiler command line, e.g. -xarch=v9 vs. -xarch=v9a.
++# Idea is to reserve for option to produce "universal" binary and let
++# programmer detect if current CPU is VIS capable at run-time.
++sub unvis3 {
++my ($mnemonic,$rs1,$rs2,$rd)=@_;
++my %bias = ( "g" => 0, "o" => 8, "l" => 16, "i" => 24 );
++my ($ref,$opf);
++my %visopf = (	"addxc"		=> 0x011,
++		"addxccc"	=> 0x013,
++		"umulxhi"	=> 0x016	);
++
++    $ref = "$mnemonic\t$rs1,$rs2,$rd";
++
++    if ($opf=$visopf{$mnemonic}) {
++	foreach ($rs1,$rs2,$rd) {
++	    return $ref if (!/%([goli])([0-9])/);
++	    $_=$bias{$1}+$2;
++	}
++
++	return	sprintf ".word\t0x%08x !%s",
++			0x81b00000|$rd<<25|$rs1<<14|$opf<<5|$rs2,
++			$ref;
++    } else {
++	return $ref;
++    }
++}
++
++foreach (split("\n",$code)) {
++	s/\`([^\`]*)\`/eval $1/ge;
++
++	s/\b(umulxhi|addxc[c]{0,2})\s+(%[goli][0-7]),\s*(%[goli][0-7]),\s*(%[goli][0-7])/
++		&unvis3($1,$2,$3,$4)
++	 /ge;
++
++	print $_,"\n";
++}
++
++close STDOUT;
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/bn/asm/x86-gf2m.pl b/CryptoPkg/Library/OpensslLib/openssl/crypto/bn/asm/x86-gf2m.pl
+new file mode 100644
+index 0000000..f464368
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/bn/asm/x86-gf2m.pl
+@@ -0,0 +1,325 @@
++#! /usr/bin/env perl
++# Copyright 2011-2016 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
++# in the file LICENSE in the source distribution or at
++# https://www.openssl.org/source/license.html
++
++#
++# ====================================================================
++# Written by Andy Polyakov  for the OpenSSL
++# project. The module is, however, dual licensed under OpenSSL and
++# CRYPTOGAMS licenses depending on where you obtain it. For further
++# details see http://www.openssl.org/~appro/cryptogams/.
++# ====================================================================
++#
++# May 2011
++#
++# The module implements bn_GF2m_mul_2x2 polynomial multiplication used
++# in bn_gf2m.c. It's kind of low-hanging mechanical port from C for
++# the time being... Except that it has three code paths: pure integer
++# code suitable for any x86 CPU, MMX code suitable for PIII and later
++# and PCLMULQDQ suitable for Westmere and later. Improvement varies
++# from one benchmark and µ-arch to another. Below are interval values
++# for 163- and 571-bit ECDH benchmarks relative to compiler-generated
++# code:
++#
++# PIII		16%-30%
++# P4		12%-12%
++# Opteron	18%-40%
++# Core2		19%-44%
++# Atom		38%-64%
++# Westmere	53%-121%(PCLMULQDQ)/20%-32%(MMX)
++# Sandy Bridge	72%-127%(PCLMULQDQ)/27%-23%(MMX)
++#
++# Note that above improvement coefficients are not coefficients for
++# bn_GF2m_mul_2x2 itself. For example 120% ECDH improvement is result
++# of bn_GF2m_mul_2x2 being >4x faster. As it gets faster, benchmark
++# is more and more dominated by other subroutines, most notably by
++# BN_GF2m_mod[_mul]_arr...
++
++$0 =~ m/(.*[\/\\])[^\/\\]+$/; $dir=$1;
++push(@INC,"${dir}","${dir}../../perlasm");
++require "x86asm.pl";
++
++$output = pop;
++open STDOUT,">$output";
++
++&asm_init($ARGV[0],$0,$x86only = $ARGV[$#ARGV] eq "386");
++
++$sse2=0;
++for (@ARGV) { $sse2=1 if (/-DOPENSSL_IA32_SSE2/); }
++
++&external_label("OPENSSL_ia32cap_P") if ($sse2);
++
++$a="eax";
++$b="ebx";
++($a1,$a2,$a4)=("ecx","edx","ebp");
++
++$R="mm0";
++@T=("mm1","mm2");
++($A,$B,$B30,$B31)=("mm2","mm3","mm4","mm5");
++@i=("esi","edi");
++
++					if (!$x86only) {
++&function_begin_B("_mul_1x1_mmx");
++	&sub	("esp",32+4);
++	 &mov	($a1,$a);
++	 &lea	($a2,&DWP(0,$a,$a));
++	 &and	($a1,0x3fffffff);
++	 &lea	($a4,&DWP(0,$a2,$a2));
++	 &mov	(&DWP(0*4,"esp"),0);
++	 &and	($a2,0x7fffffff);
++	&movd	($A,$a);
++	&movd	($B,$b);
++	 &mov	(&DWP(1*4,"esp"),$a1);	# a1
++	 &xor	($a1,$a2);		# a1^a2
++	&pxor	($B31,$B31);
++	&pxor	($B30,$B30);
++	 &mov	(&DWP(2*4,"esp"),$a2);	# a2
++	 &xor	($a2,$a4);		# a2^a4
++	 &mov	(&DWP(3*4,"esp"),$a1);	# a1^a2
++	&pcmpgtd($B31,$A);		# broadcast 31st bit
++	&paddd	($A,$A);		# $A<<=1
++	 &xor	($a1,$a2);		# a1^a4=a1^a2^a2^a4
++	 &mov	(&DWP(4*4,"esp"),$a4);	# a4
++	 &xor	($a4,$a2);		# a2=a4^a2^a4
++	&pand	($B31,$B);
++	&pcmpgtd($B30,$A);		# broadcast 30th bit
++	 &mov	(&DWP(5*4,"esp"),$a1);	# a1^a4
++	 &xor	($a4,$a1);		# a1^a2^a4
++	&psllq	($B31,31);
++	&pand	($B30,$B);
++	 &mov	(&DWP(6*4,"esp"),$a2);	# a2^a4
++	&mov	(@i[0],0x7);
++	 &mov	(&DWP(7*4,"esp"),$a4);	# a1^a2^a4
++	 &mov	($a4,@i[0]);
++	&and	(@i[0],$b);
++	&shr	($b,3);
++	&mov	(@i[1],$a4);
++	&psllq	($B30,30);
++	&and	(@i[1],$b);
++	&shr	($b,3);
++	&movd	($R,&DWP(0,"esp",@i[0],4));
++	&mov	(@i[0],$a4);
++	&and	(@i[0],$b);
++	&shr	($b,3);
++	for($n=1;$n<9;$n++) {
++		&movd	(@T[1],&DWP(0,"esp",@i[1],4));
++		&mov	(@i[1],$a4);
++		&psllq	(@T[1],3*$n);
++		&and	(@i[1],$b);
++		&shr	($b,3);
++		&pxor	($R,@T[1]);
++
++		push(@i,shift(@i)); push(@T,shift(@T));
++	}
++	&movd	(@T[1],&DWP(0,"esp",@i[1],4));
++	&pxor	($R,$B30);
++	&psllq	(@T[1],3*$n++);
++	&pxor	($R,@T[1]);
++
++	&movd	(@T[0],&DWP(0,"esp",@i[0],4));
++	&pxor	($R,$B31);
++	&psllq	(@T[0],3*$n);
++	&add	("esp",32+4);
++	&pxor	($R,@T[0]);
++	&ret	();
++&function_end_B("_mul_1x1_mmx");
++					}
++
++($lo,$hi)=("eax","edx");
++@T=("ecx","ebp");
++
++&function_begin_B("_mul_1x1_ialu");
++	&sub	("esp",32+4);
++	 &mov	($a1,$a);
++	 &lea	($a2,&DWP(0,$a,$a));
++	 &lea	($a4,&DWP(0,"",$a,4));
++	 &and	($a1,0x3fffffff);
++	&lea	(@i[1],&DWP(0,$lo,$lo));
++	&sar	($lo,31);		# broadcast 31st bit
++	 &mov	(&DWP(0*4,"esp"),0);
++	 &and	($a2,0x7fffffff);
++	 &mov	(&DWP(1*4,"esp"),$a1);	# a1
++	 &xor	($a1,$a2);		# a1^a2
++	 &mov	(&DWP(2*4,"esp"),$a2);	# a2
++	 &xor	($a2,$a4);		# a2^a4
++	 &mov	(&DWP(3*4,"esp"),$a1);	# a1^a2
++	 &xor	($a1,$a2);		# a1^a4=a1^a2^a2^a4
++	 &mov	(&DWP(4*4,"esp"),$a4);	# a4
++	 &xor	($a4,$a2);		# a2=a4^a2^a4
++	 &mov	(&DWP(5*4,"esp"),$a1);	# a1^a4
++	 &xor	($a4,$a1);		# a1^a2^a4
++	&sar	(@i[1],31);		# broardcast 30th bit
++	&and	($lo,$b);
++	 &mov	(&DWP(6*4,"esp"),$a2);	# a2^a4
++	&and	(@i[1],$b);
++	 &mov	(&DWP(7*4,"esp"),$a4);	# a1^a2^a4
++	&mov	($hi,$lo);
++	&shl	($lo,31);
++	&mov	(@T[0],@i[1]);
++	&shr	($hi,1);
++
++	 &mov	(@i[0],0x7);
++	&shl	(@i[1],30);
++	 &and	(@i[0],$b);
++	&shr	(@T[0],2);
++	&xor	($lo,@i[1]);
++
++	&shr	($b,3);
++	&mov	(@i[1],0x7);		# 5-byte instruction!?
++	&and	(@i[1],$b);
++	&shr	($b,3);
++	 &xor	($hi,@T[0]);
++	&xor	($lo,&DWP(0,"esp",@i[0],4));
++	&mov	(@i[0],0x7);
++	&and	(@i[0],$b);
++	&shr	($b,3);
++	for($n=1;$n<9;$n++) {
++		&mov	(@T[1],&DWP(0,"esp",@i[1],4));
++		&mov	(@i[1],0x7);
++		&mov	(@T[0],@T[1]);
++		&shl	(@T[1],3*$n);
++		&and	(@i[1],$b);
++		&shr	(@T[0],32-3*$n);
++		&xor	($lo,@T[1]);
++		&shr	($b,3);
++		&xor	($hi,@T[0]);
++
++		push(@i,shift(@i)); push(@T,shift(@T));
++	}
++	&mov	(@T[1],&DWP(0,"esp",@i[1],4));
++	&mov	(@T[0],@T[1]);
++	&shl	(@T[1],3*$n);
++	&mov	(@i[1],&DWP(0,"esp",@i[0],4));
++	&shr	(@T[0],32-3*$n);	$n++;
++	&mov	(@i[0],@i[1]);
++	&xor	($lo,@T[1]);
++	&shl	(@i[1],3*$n);
++	&xor	($hi,@T[0]);
++	&shr	(@i[0],32-3*$n);
++	&xor	($lo,@i[1]);
++	&xor	($hi,@i[0]);
++
++	&add	("esp",32+4);
++	&ret	();
++&function_end_B("_mul_1x1_ialu");
++
++# void bn_GF2m_mul_2x2(BN_ULONG *r, BN_ULONG a1, BN_ULONG a0, BN_ULONG b1, BN_ULONG b0);
++&function_begin_B("bn_GF2m_mul_2x2");
++if (!$x86only) {
++	&picmeup("edx","OPENSSL_ia32cap_P");
++	&mov	("eax",&DWP(0,"edx"));
++	&mov	("edx",&DWP(4,"edx"));
++	&test	("eax",1<<23);		# check MMX bit
++	&jz	(&label("ialu"));
++if ($sse2) {
++	&test	("eax",1<<24);		# check FXSR bit
++	&jz	(&label("mmx"));
++	&test	("edx",1<<1);		# check PCLMULQDQ bit
++	&jz	(&label("mmx"));
++
++	&movups		("xmm0",&QWP(8,"esp"));
++	&shufps		("xmm0","xmm0",0b10110001);
++	&pclmulqdq	("xmm0","xmm0",1);
++	&mov		("eax",&DWP(4,"esp"));
++	&movups		(&QWP(0,"eax"),"xmm0");
++	&ret	();
++
++&set_label("mmx",16);
++}
++	&push	("ebp");
++	&push	("ebx");
++	&push	("esi");
++	&push	("edi");
++	&mov	($a,&wparam(1));
++	&mov	($b,&wparam(3));
++	&call	("_mul_1x1_mmx");	# a1·b1
++	&movq	("mm7",$R);
++
++	&mov	($a,&wparam(2));
++	&mov	($b,&wparam(4));
++	&call	("_mul_1x1_mmx");	# a0·b0
++	&movq	("mm6",$R);
++
++	&mov	($a,&wparam(1));
++	&mov	($b,&wparam(3));
++	&xor	($a,&wparam(2));
++	&xor	($b,&wparam(4));
++	&call	("_mul_1x1_mmx");	# (a0+a1)·(b0+b1)
++	&pxor	($R,"mm7");
++	&mov	($a,&wparam(0));
++	&pxor	($R,"mm6");		# (a0+a1)·(b0+b1)-a1·b1-a0·b0
++
++	&movq	($A,$R);
++	&psllq	($R,32);
++	&pop	("edi");
++	&psrlq	($A,32);
++	&pop	("esi");
++	&pxor	($R,"mm6");
++	&pop	("ebx");
++	&pxor	($A,"mm7");
++	&movq	(&QWP(0,$a),$R);
++	&pop	("ebp");
++	&movq	(&QWP(8,$a),$A);
++	&emms	();
++	&ret	();
++&set_label("ialu",16);
++}
++	&push	("ebp");
++	&push	("ebx");
++	&push	("esi");
++	&push	("edi");
++	&stack_push(4+1);
++
++	&mov	($a,&wparam(1));
++	&mov	($b,&wparam(3));
++	&call	("_mul_1x1_ialu");	# a1·b1
++	&mov	(&DWP(8,"esp"),$lo);
++	&mov	(&DWP(12,"esp"),$hi);
++
++	&mov	($a,&wparam(2));
++	&mov	($b,&wparam(4));
++	&call	("_mul_1x1_ialu");	# a0·b0
++	&mov	(&DWP(0,"esp"),$lo);
++	&mov	(&DWP(4,"esp"),$hi);
++
++	&mov	($a,&wparam(1));
++	&mov	($b,&wparam(3));
++	&xor	($a,&wparam(2));
++	&xor	($b,&wparam(4));
++	&call	("_mul_1x1_ialu");	# (a0+a1)·(b0+b1)
++
++	&mov	("ebp",&wparam(0));
++		 @r=("ebx","ecx","edi","esi");
++	&mov	(@r[0],&DWP(0,"esp"));
++	&mov	(@r[1],&DWP(4,"esp"));
++	&mov	(@r[2],&DWP(8,"esp"));
++	&mov	(@r[3],&DWP(12,"esp"));
++
++	&xor	($lo,$hi);
++	&xor	($hi,@r[1]);
++	&xor	($lo,@r[0]);
++	&mov	(&DWP(0,"ebp"),@r[0]);
++	&xor	($hi,@r[2]);
++	&mov	(&DWP(12,"ebp"),@r[3]);
++	&xor	($lo,@r[3]);
++	&stack_pop(4+1);
++	&xor	($hi,@r[3]);
++	&pop	("edi");
++	&xor	($lo,$hi);
++	&pop	("esi");
++	&mov	(&DWP(8,"ebp"),$hi);
++	&pop	("ebx");
++	&mov	(&DWP(4,"ebp"),$lo);
++	&pop	("ebp");
++	&ret	();
++&function_end_B("bn_GF2m_mul_2x2");
++
++&asciz	("GF(2^m) Multiplication for x86, CRYPTOGAMS by ");
++
++&asm_finish();
++
++close STDOUT;
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/bn/asm/x86-mont.pl b/CryptoPkg/Library/OpensslLib/openssl/crypto/bn/asm/x86-mont.pl
+new file mode 100755
+index 0000000..6787503
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/bn/asm/x86-mont.pl
+@@ -0,0 +1,629 @@
++#! /usr/bin/env perl
++# Copyright 2005-2016 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
++# in the file LICENSE in the source distribution or at
++# https://www.openssl.org/source/license.html
++
++
++# ====================================================================
++# Written by Andy Polyakov  for the OpenSSL
++# project. The module is, however, dual licensed under OpenSSL and
++# CRYPTOGAMS licenses depending on where you obtain it. For further
++# details see http://www.openssl.org/~appro/cryptogams/.
++# ====================================================================
++
++# October 2005
++#
++# This is a "teaser" code, as it can be improved in several ways...
++# First of all non-SSE2 path should be implemented (yes, for now it
++# performs Montgomery multiplication/convolution only on SSE2-capable
++# CPUs such as P4, others fall down to original code). Then inner loop
++# can be unrolled and modulo-scheduled to improve ILP and possibly
++# moved to 128-bit XMM register bank (though it would require input
++# rearrangement and/or increase bus bandwidth utilization). Dedicated
++# squaring procedure should give further performance improvement...
++# Yet, for being draft, the code improves rsa512 *sign* benchmark by
++# 110%(!), rsa1024 one - by 70% and rsa4096 - by 20%:-)
++
++# December 2006
++#
++# Modulo-scheduling SSE2 loops results in further 15-20% improvement.
++# Integer-only code [being equipped with dedicated squaring procedure]
++# gives ~40% on rsa512 sign benchmark...
++
++$0 =~ m/(.*[\/\\])[^\/\\]+$/; $dir=$1;
++push(@INC,"${dir}","${dir}../../perlasm");
++require "x86asm.pl";
++
++$output = pop;
++open STDOUT,">$output";
++ 
++&asm_init($ARGV[0],$0);
++
++$sse2=0;
++for (@ARGV) { $sse2=1 if (/-DOPENSSL_IA32_SSE2/); }
++
++&external_label("OPENSSL_ia32cap_P") if ($sse2);
++
++&function_begin("bn_mul_mont");
++
++$i="edx";
++$j="ecx";
++$ap="esi";	$tp="esi";		# overlapping variables!!!
++$rp="edi";	$bp="edi";		# overlapping variables!!!
++$np="ebp";
++$num="ebx";
++
++$_num=&DWP(4*0,"esp");			# stack top layout
++$_rp=&DWP(4*1,"esp");
++$_ap=&DWP(4*2,"esp");
++$_bp=&DWP(4*3,"esp");
++$_np=&DWP(4*4,"esp");
++$_n0=&DWP(4*5,"esp");	$_n0q=&QWP(4*5,"esp");
++$_sp=&DWP(4*6,"esp");
++$_bpend=&DWP(4*7,"esp");
++$frame=32;				# size of above frame rounded up to 16n
++
++	&xor	("eax","eax");
++	&mov	("edi",&wparam(5));	# int num
++	&cmp	("edi",4);
++	&jl	(&label("just_leave"));
++
++	&lea	("esi",&wparam(0));	# put aside pointer to argument block
++	&lea	("edx",&wparam(1));	# load ap
++	&add	("edi",2);		# extra two words on top of tp
++	&neg	("edi");
++	&lea	("ebp",&DWP(-$frame,"esp","edi",4));	# future alloca($frame+4*(num+2))
++	&neg	("edi");
++
++	# minimize cache contention by arraning 2K window between stack
++	# pointer and ap argument [np is also position sensitive vector,
++	# but it's assumed to be near ap, as it's allocated at ~same
++	# time].
++	&mov	("eax","ebp");
++	&sub	("eax","edx");
++	&and	("eax",2047);
++	&sub	("ebp","eax");		# this aligns sp and ap modulo 2048
++
++	&xor	("edx","ebp");
++	&and	("edx",2048);
++	&xor	("edx",2048);
++	&sub	("ebp","edx");		# this splits them apart modulo 4096
++
++	&and	("ebp",-64);		# align to cache line
++
++	# An OS-agnostic version of __chkstk.
++	#
++	# Some OSes (Windows) insist on stack being "wired" to
++	# physical memory in strictly sequential manner, i.e. if stack
++	# allocation spans two pages, then reference to farmost one can
++	# be punishable by SEGV. But page walking can do good even on
++	# other OSes, because it guarantees that villain thread hits
++	# the guard page before it can make damage to innocent one...
++	&mov	("eax","esp");
++	&sub	("eax","ebp");
++	&and	("eax",-4096);
++	&mov	("edx","esp");		# saved stack pointer!
++	&lea	("esp",&DWP(0,"ebp","eax"));
++	&mov	("eax",&DWP(0,"esp"));
++	&cmp	("esp","ebp");
++	&ja	(&label("page_walk"));
++	&jmp	(&label("page_walk_done"));
++
++&set_label("page_walk",16);
++	&lea	("esp",&DWP(-4096,"esp"));
++	&mov	("eax",&DWP(0,"esp"));
++	&cmp	("esp","ebp");
++	&ja	(&label("page_walk"));
++&set_label("page_walk_done");
++
++	################################# load argument block...
++	&mov	("eax",&DWP(0*4,"esi"));# BN_ULONG *rp
++	&mov	("ebx",&DWP(1*4,"esi"));# const BN_ULONG *ap
++	&mov	("ecx",&DWP(2*4,"esi"));# const BN_ULONG *bp
++	&mov	("ebp",&DWP(3*4,"esi"));# const BN_ULONG *np
++	&mov	("esi",&DWP(4*4,"esi"));# const BN_ULONG *n0
++	#&mov	("edi",&DWP(5*4,"esi"));# int num
++
++	&mov	("esi",&DWP(0,"esi"));	# pull n0[0]
++	&mov	($_rp,"eax");		# ... save a copy of argument block
++	&mov	($_ap,"ebx");
++	&mov	($_bp,"ecx");
++	&mov	($_np,"ebp");
++	&mov	($_n0,"esi");
++	&lea	($num,&DWP(-3,"edi"));	# num=num-1 to assist modulo-scheduling
++	#&mov	($_num,$num);		# redundant as $num is not reused
++	&mov	($_sp,"edx");		# saved stack pointer!
++
++if($sse2) {
++$acc0="mm0";	# mmx register bank layout
++$acc1="mm1";
++$car0="mm2";
++$car1="mm3";
++$mul0="mm4";
++$mul1="mm5";
++$temp="mm6";
++$mask="mm7";
++
++	&picmeup("eax","OPENSSL_ia32cap_P");
++	&bt	(&DWP(0,"eax"),26);
++	&jnc	(&label("non_sse2"));
++
++	&mov	("eax",-1);
++	&movd	($mask,"eax");		# mask 32 lower bits
++
++	&mov	($ap,$_ap);		# load input pointers
++	&mov	($bp,$_bp);
++	&mov	($np,$_np);
++
++	&xor	($i,$i);		# i=0
++	&xor	($j,$j);		# j=0
++
++	&movd	($mul0,&DWP(0,$bp));		# bp[0]
++	&movd	($mul1,&DWP(0,$ap));		# ap[0]
++	&movd	($car1,&DWP(0,$np));		# np[0]
++
++	&pmuludq($mul1,$mul0);			# ap[0]*bp[0]
++	&movq	($car0,$mul1);
++	&movq	($acc0,$mul1);			# I wish movd worked for
++	&pand	($acc0,$mask);			# inter-register transfers
++
++	&pmuludq($mul1,$_n0q);			# *=n0
++
++	&pmuludq($car1,$mul1);			# "t[0]"*np[0]*n0
++	&paddq	($car1,$acc0);
++
++	&movd	($acc1,&DWP(4,$np));		# np[1]
++	&movd	($acc0,&DWP(4,$ap));		# ap[1]
++
++	&psrlq	($car0,32);
++	&psrlq	($car1,32);
++
++	&inc	($j);				# j++
++&set_label("1st",16);
++	&pmuludq($acc0,$mul0);			# ap[j]*bp[0]
++	&pmuludq($acc1,$mul1);			# np[j]*m1
++	&paddq	($car0,$acc0);			# +=c0
++	&paddq	($car1,$acc1);			# +=c1
++
++	&movq	($acc0,$car0);
++	&pand	($acc0,$mask);
++	&movd	($acc1,&DWP(4,$np,$j,4));	# np[j+1]
++	&paddq	($car1,$acc0);			# +=ap[j]*bp[0];
++	&movd	($acc0,&DWP(4,$ap,$j,4));	# ap[j+1]
++	&psrlq	($car0,32);
++	&movd	(&DWP($frame-4,"esp",$j,4),$car1);	# tp[j-1]=
++	&psrlq	($car1,32);
++
++	&lea	($j,&DWP(1,$j));
++	&cmp	($j,$num);
++	&jl	(&label("1st"));
++
++	&pmuludq($acc0,$mul0);			# ap[num-1]*bp[0]
++	&pmuludq($acc1,$mul1);			# np[num-1]*m1
++	&paddq	($car0,$acc0);			# +=c0
++	&paddq	($car1,$acc1);			# +=c1
++
++	&movq	($acc0,$car0);
++	&pand	($acc0,$mask);
++	&paddq	($car1,$acc0);			# +=ap[num-1]*bp[0];
++	&movd	(&DWP($frame-4,"esp",$j,4),$car1);	# tp[num-2]=
++
++	&psrlq	($car0,32);
++	&psrlq	($car1,32);
++
++	&paddq	($car1,$car0);
++	&movq	(&QWP($frame,"esp",$num,4),$car1);	# tp[num].tp[num-1]
++
++	&inc	($i);				# i++
++&set_label("outer");
++	&xor	($j,$j);			# j=0
++
++	&movd	($mul0,&DWP(0,$bp,$i,4));	# bp[i]
++	&movd	($mul1,&DWP(0,$ap));		# ap[0]
++	&movd	($temp,&DWP($frame,"esp"));	# tp[0]
++	&movd	($car1,&DWP(0,$np));		# np[0]
++	&pmuludq($mul1,$mul0);			# ap[0]*bp[i]
++
++	&paddq	($mul1,$temp);			# +=tp[0]
++	&movq	($acc0,$mul1);
++	&movq	($car0,$mul1);
++	&pand	($acc0,$mask);
++
++	&pmuludq($mul1,$_n0q);			# *=n0
++
++	&pmuludq($car1,$mul1);
++	&paddq	($car1,$acc0);
++
++	&movd	($temp,&DWP($frame+4,"esp"));	# tp[1]
++	&movd	($acc1,&DWP(4,$np));		# np[1]
++	&movd	($acc0,&DWP(4,$ap));		# ap[1]
++
++	&psrlq	($car0,32);
++	&psrlq	($car1,32);
++	&paddq	($car0,$temp);			# +=tp[1]
++
++	&inc	($j);				# j++
++	&dec	($num);
++&set_label("inner");
++	&pmuludq($acc0,$mul0);			# ap[j]*bp[i]
++	&pmuludq($acc1,$mul1);			# np[j]*m1
++	&paddq	($car0,$acc0);			# +=c0
++	&paddq	($car1,$acc1);			# +=c1
++
++	&movq	($acc0,$car0);
++	&movd	($temp,&DWP($frame+4,"esp",$j,4));# tp[j+1]
++	&pand	($acc0,$mask);
++	&movd	($acc1,&DWP(4,$np,$j,4));	# np[j+1]
++	&paddq	($car1,$acc0);			# +=ap[j]*bp[i]+tp[j]
++	&movd	($acc0,&DWP(4,$ap,$j,4));	# ap[j+1]
++	&psrlq	($car0,32);
++	&movd	(&DWP($frame-4,"esp",$j,4),$car1);# tp[j-1]=
++	&psrlq	($car1,32);
++	&paddq	($car0,$temp);			# +=tp[j+1]
++
++	&dec	($num);
++	&lea	($j,&DWP(1,$j));		# j++
++	&jnz	(&label("inner"));
++
++	&mov	($num,$j);
++	&pmuludq($acc0,$mul0);			# ap[num-1]*bp[i]
++	&pmuludq($acc1,$mul1);			# np[num-1]*m1
++	&paddq	($car0,$acc0);			# +=c0
++	&paddq	($car1,$acc1);			# +=c1
++
++	&movq	($acc0,$car0);
++	&pand	($acc0,$mask);
++	&paddq	($car1,$acc0);			# +=ap[num-1]*bp[i]+tp[num-1]
++	&movd	(&DWP($frame-4,"esp",$j,4),$car1);	# tp[num-2]=
++	&psrlq	($car0,32);
++	&psrlq	($car1,32);
++
++	&movd	($temp,&DWP($frame+4,"esp",$num,4));	# += tp[num]
++	&paddq	($car1,$car0);
++	&paddq	($car1,$temp);
++	&movq	(&QWP($frame,"esp",$num,4),$car1);	# tp[num].tp[num-1]
++
++	&lea	($i,&DWP(1,$i));		# i++
++	&cmp	($i,$num);
++	&jle	(&label("outer"));
++
++	&emms	();				# done with mmx bank
++	&jmp	(&label("common_tail"));
++
++&set_label("non_sse2",16);
++}
++
++if (0) {
++	&mov	("esp",$_sp);
++	&xor	("eax","eax");	# signal "not fast enough [yet]"
++	&jmp	(&label("just_leave"));
++	# While the below code provides competitive performance for
++	# all key lengths on modern Intel cores, it's still more
++	# than 10% slower for 4096-bit key elsewhere:-( "Competitive"
++	# means compared to the original integer-only assembler.
++	# 512-bit RSA sign is better by ~40%, but that's about all
++	# one can say about all CPUs...
++} else {
++$inp="esi";	# integer path uses these registers differently
++$word="edi";
++$carry="ebp";
++
++	&mov	($inp,$_ap);
++	&lea	($carry,&DWP(1,$num));
++	&mov	($word,$_bp);
++	&xor	($j,$j);				# j=0
++	&mov	("edx",$inp);
++	&and	($carry,1);				# see if num is even
++	&sub	("edx",$word);				# see if ap==bp
++	&lea	("eax",&DWP(4,$word,$num,4));		# &bp[num]
++	&or	($carry,"edx");
++	&mov	($word,&DWP(0,$word));			# bp[0]
++	&jz	(&label("bn_sqr_mont"));
++	&mov	($_bpend,"eax");
++	&mov	("eax",&DWP(0,$inp));
++	&xor	("edx","edx");
++
++&set_label("mull",16);
++	&mov	($carry,"edx");
++	&mul	($word);				# ap[j]*bp[0]
++	&add	($carry,"eax");
++	&lea	($j,&DWP(1,$j));
++	&adc	("edx",0);
++	&mov	("eax",&DWP(0,$inp,$j,4));		# ap[j+1]
++	&cmp	($j,$num);
++	&mov	(&DWP($frame-4,"esp",$j,4),$carry);	# tp[j]=
++	&jl	(&label("mull"));
++
++	&mov	($carry,"edx");
++	&mul	($word);				# ap[num-1]*bp[0]
++	 &mov	($word,$_n0);
++	&add	("eax",$carry);
++	 &mov	($inp,$_np);
++	&adc	("edx",0);
++	 &imul	($word,&DWP($frame,"esp"));		# n0*tp[0]
++
++	&mov	(&DWP($frame,"esp",$num,4),"eax");	# tp[num-1]=
++	&xor	($j,$j);
++	&mov	(&DWP($frame+4,"esp",$num,4),"edx");	# tp[num]=
++	&mov	(&DWP($frame+8,"esp",$num,4),$j);	# tp[num+1]=
++
++	&mov	("eax",&DWP(0,$inp));			# np[0]
++	&mul	($word);				# np[0]*m
++	&add	("eax",&DWP($frame,"esp"));		# +=tp[0]
++	&mov	("eax",&DWP(4,$inp));			# np[1]
++	&adc	("edx",0);
++	&inc	($j);
++
++	&jmp	(&label("2ndmadd"));
++
++&set_label("1stmadd",16);
++	&mov	($carry,"edx");
++	&mul	($word);				# ap[j]*bp[i]
++	&add	($carry,&DWP($frame,"esp",$j,4));	# +=tp[j]
++	&lea	($j,&DWP(1,$j));
++	&adc	("edx",0);
++	&add	($carry,"eax");
++	&mov	("eax",&DWP(0,$inp,$j,4));		# ap[j+1]
++	&adc	("edx",0);
++	&cmp	($j,$num);
++	&mov	(&DWP($frame-4,"esp",$j,4),$carry);	# tp[j]=
++	&jl	(&label("1stmadd"));
++
++	&mov	($carry,"edx");
++	&mul	($word);				# ap[num-1]*bp[i]
++	&add	("eax",&DWP($frame,"esp",$num,4));	# +=tp[num-1]
++	 &mov	($word,$_n0);
++	&adc	("edx",0);
++	 &mov	($inp,$_np);
++	&add	($carry,"eax");
++	&adc	("edx",0);
++	 &imul	($word,&DWP($frame,"esp"));		# n0*tp[0]
++
++	&xor	($j,$j);
++	&add	("edx",&DWP($frame+4,"esp",$num,4));	# carry+=tp[num]
++	&mov	(&DWP($frame,"esp",$num,4),$carry);	# tp[num-1]=
++	&adc	($j,0);
++	 &mov	("eax",&DWP(0,$inp));			# np[0]
++	&mov	(&DWP($frame+4,"esp",$num,4),"edx");	# tp[num]=
++	&mov	(&DWP($frame+8,"esp",$num,4),$j);	# tp[num+1]=
++
++	&mul	($word);				# np[0]*m
++	&add	("eax",&DWP($frame,"esp"));		# +=tp[0]
++	&mov	("eax",&DWP(4,$inp));			# np[1]
++	&adc	("edx",0);
++	&mov	($j,1);
++
++&set_label("2ndmadd",16);
++	&mov	($carry,"edx");
++	&mul	($word);				# np[j]*m
++	&add	($carry,&DWP($frame,"esp",$j,4));	# +=tp[j]
++	&lea	($j,&DWP(1,$j));
++	&adc	("edx",0);
++	&add	($carry,"eax");
++	&mov	("eax",&DWP(0,$inp,$j,4));		# np[j+1]
++	&adc	("edx",0);
++	&cmp	($j,$num);
++	&mov	(&DWP($frame-8,"esp",$j,4),$carry);	# tp[j-1]=
++	&jl	(&label("2ndmadd"));
++
++	&mov	($carry,"edx");
++	&mul	($word);				# np[j]*m
++	&add	($carry,&DWP($frame,"esp",$num,4));	# +=tp[num-1]
++	&adc	("edx",0);
++	&add	($carry,"eax");
++	&adc	("edx",0);
++	&mov	(&DWP($frame-4,"esp",$num,4),$carry);	# tp[num-2]=
++
++	&xor	("eax","eax");
++	 &mov	($j,$_bp);				# &bp[i]
++	&add	("edx",&DWP($frame+4,"esp",$num,4));	# carry+=tp[num]
++	&adc	("eax",&DWP($frame+8,"esp",$num,4));	# +=tp[num+1]
++	 &lea	($j,&DWP(4,$j));
++	&mov	(&DWP($frame,"esp",$num,4),"edx");	# tp[num-1]=
++	 &cmp	($j,$_bpend);
++	&mov	(&DWP($frame+4,"esp",$num,4),"eax");	# tp[num]=
++	&je	(&label("common_tail"));
++
++	&mov	($word,&DWP(0,$j));			# bp[i+1]
++	&mov	($inp,$_ap);
++	&mov	($_bp,$j);				# &bp[++i]
++	&xor	($j,$j);
++	&xor	("edx","edx");
++	&mov	("eax",&DWP(0,$inp));
++	&jmp	(&label("1stmadd"));
++
++&set_label("bn_sqr_mont",16);
++$sbit=$num;
++	&mov	($_num,$num);
++	&mov	($_bp,$j);				# i=0
++
++	&mov	("eax",$word);				# ap[0]
++	&mul	($word);				# ap[0]*ap[0]
++	&mov	(&DWP($frame,"esp"),"eax");		# tp[0]=
++	&mov	($sbit,"edx");
++	&shr	("edx",1);
++	&and	($sbit,1);
++	&inc	($j);
++&set_label("sqr",16);
++	&mov	("eax",&DWP(0,$inp,$j,4));		# ap[j]
++	&mov	($carry,"edx");
++	&mul	($word);				# ap[j]*ap[0]
++	&add	("eax",$carry);
++	&lea	($j,&DWP(1,$j));
++	&adc	("edx",0);
++	&lea	($carry,&DWP(0,$sbit,"eax",2));
++	&shr	("eax",31);
++	&cmp	($j,$_num);
++	&mov	($sbit,"eax");
++	&mov	(&DWP($frame-4,"esp",$j,4),$carry);	# tp[j]=
++	&jl	(&label("sqr"));
++
++	&mov	("eax",&DWP(0,$inp,$j,4));		# ap[num-1]
++	&mov	($carry,"edx");
++	&mul	($word);				# ap[num-1]*ap[0]
++	&add	("eax",$carry);
++	 &mov	($word,$_n0);
++	&adc	("edx",0);
++	 &mov	($inp,$_np);
++	&lea	($carry,&DWP(0,$sbit,"eax",2));
++	 &imul	($word,&DWP($frame,"esp"));		# n0*tp[0]
++	&shr	("eax",31);
++	&mov	(&DWP($frame,"esp",$j,4),$carry);	# tp[num-1]=
++
++	&lea	($carry,&DWP(0,"eax","edx",2));
++	 &mov	("eax",&DWP(0,$inp));			# np[0]
++	&shr	("edx",31);
++	&mov	(&DWP($frame+4,"esp",$j,4),$carry);	# tp[num]=
++	&mov	(&DWP($frame+8,"esp",$j,4),"edx");	# tp[num+1]=
++
++	&mul	($word);				# np[0]*m
++	&add	("eax",&DWP($frame,"esp"));		# +=tp[0]
++	&mov	($num,$j);
++	&adc	("edx",0);
++	&mov	("eax",&DWP(4,$inp));			# np[1]
++	&mov	($j,1);
++
++&set_label("3rdmadd",16);
++	&mov	($carry,"edx");
++	&mul	($word);				# np[j]*m
++	&add	($carry,&DWP($frame,"esp",$j,4));	# +=tp[j]
++	&adc	("edx",0);
++	&add	($carry,"eax");
++	&mov	("eax",&DWP(4,$inp,$j,4));		# np[j+1]
++	&adc	("edx",0);
++	&mov	(&DWP($frame-4,"esp",$j,4),$carry);	# tp[j-1]=
++
++	&mov	($carry,"edx");
++	&mul	($word);				# np[j+1]*m
++	&add	($carry,&DWP($frame+4,"esp",$j,4));	# +=tp[j+1]
++	&lea	($j,&DWP(2,$j));
++	&adc	("edx",0);
++	&add	($carry,"eax");
++	&mov	("eax",&DWP(0,$inp,$j,4));		# np[j+2]
++	&adc	("edx",0);
++	&cmp	($j,$num);
++	&mov	(&DWP($frame-8,"esp",$j,4),$carry);	# tp[j]=
++	&jl	(&label("3rdmadd"));
++
++	&mov	($carry,"edx");
++	&mul	($word);				# np[j]*m
++	&add	($carry,&DWP($frame,"esp",$num,4));	# +=tp[num-1]
++	&adc	("edx",0);
++	&add	($carry,"eax");
++	&adc	("edx",0);
++	&mov	(&DWP($frame-4,"esp",$num,4),$carry);	# tp[num-2]=
++
++	&mov	($j,$_bp);				# i
++	&xor	("eax","eax");
++	&mov	($inp,$_ap);
++	&add	("edx",&DWP($frame+4,"esp",$num,4));	# carry+=tp[num]
++	&adc	("eax",&DWP($frame+8,"esp",$num,4));	# +=tp[num+1]
++	&mov	(&DWP($frame,"esp",$num,4),"edx");	# tp[num-1]=
++	&cmp	($j,$num);
++	&mov	(&DWP($frame+4,"esp",$num,4),"eax");	# tp[num]=
++	&je	(&label("common_tail"));
++
++	&mov	($word,&DWP(4,$inp,$j,4));		# ap[i]
++	&lea	($j,&DWP(1,$j));
++	&mov	("eax",$word);
++	&mov	($_bp,$j);				# ++i
++	&mul	($word);				# ap[i]*ap[i]
++	&add	("eax",&DWP($frame,"esp",$j,4));	# +=tp[i]
++	&adc	("edx",0);
++	&mov	(&DWP($frame,"esp",$j,4),"eax");	# tp[i]=
++	&xor	($carry,$carry);
++	&cmp	($j,$num);
++	&lea	($j,&DWP(1,$j));
++	&je	(&label("sqrlast"));
++
++	&mov	($sbit,"edx");				# zaps $num
++	&shr	("edx",1);
++	&and	($sbit,1);
++&set_label("sqradd",16);
++	&mov	("eax",&DWP(0,$inp,$j,4));		# ap[j]
++	&mov	($carry,"edx");
++	&mul	($word);				# ap[j]*ap[i]
++	&add	("eax",$carry);
++	&lea	($carry,&DWP(0,"eax","eax"));
++	&adc	("edx",0);
++	&shr	("eax",31);
++	&add	($carry,&DWP($frame,"esp",$j,4));	# +=tp[j]
++	&lea	($j,&DWP(1,$j));
++	&adc	("eax",0);
++	&add	($carry,$sbit);
++	&adc	("eax",0);
++	&cmp	($j,$_num);
++	&mov	(&DWP($frame-4,"esp",$j,4),$carry);	# tp[j]=
++	&mov	($sbit,"eax");
++	&jle	(&label("sqradd"));
++
++	&mov	($carry,"edx");
++	&add	("edx","edx");
++	&shr	($carry,31);
++	&add	("edx",$sbit);
++	&adc	($carry,0);
++&set_label("sqrlast");
++	&mov	($word,$_n0);
++	&mov	($inp,$_np);
++	&imul	($word,&DWP($frame,"esp"));		# n0*tp[0]
++
++	&add	("edx",&DWP($frame,"esp",$j,4));	# +=tp[num]
++	&mov	("eax",&DWP(0,$inp));			# np[0]
++	&adc	($carry,0);
++	&mov	(&DWP($frame,"esp",$j,4),"edx");	# tp[num]=
++	&mov	(&DWP($frame+4,"esp",$j,4),$carry);	# tp[num+1]=
++
++	&mul	($word);				# np[0]*m
++	&add	("eax",&DWP($frame,"esp"));		# +=tp[0]
++	&lea	($num,&DWP(-1,$j));
++	&adc	("edx",0);
++	&mov	($j,1);
++	&mov	("eax",&DWP(4,$inp));			# np[1]
++
++	&jmp	(&label("3rdmadd"));
++}
++
++&set_label("common_tail",16);
++	&mov	($np,$_np);			# load modulus pointer
++	&mov	($rp,$_rp);			# load result pointer
++	&lea	($tp,&DWP($frame,"esp"));	# [$ap and $bp are zapped]
++
++	&mov	("eax",&DWP(0,$tp));		# tp[0]
++	&mov	($j,$num);			# j=num-1
++	&xor	($i,$i);			# i=0 and clear CF!
++
++&set_label("sub",16);
++	&sbb	("eax",&DWP(0,$np,$i,4));
++	&mov	(&DWP(0,$rp,$i,4),"eax");	# rp[i]=tp[i]-np[i]
++	&dec	($j);				# doesn't affect CF!
++	&mov	("eax",&DWP(4,$tp,$i,4));	# tp[i+1]
++	&lea	($i,&DWP(1,$i));		# i++
++	&jge	(&label("sub"));
++
++	&sbb	("eax",0);			# handle upmost overflow bit
++	&and	($tp,"eax");
++	¬	("eax");
++	&mov	($np,$rp);
++	&and	($np,"eax");
++	&or	($tp,$np);			# tp=carry?tp:rp
++
++&set_label("copy",16);				# copy or in-place refresh
++	&mov	("eax",&DWP(0,$tp,$num,4));
++	&mov	(&DWP(0,$rp,$num,4),"eax");	# rp[i]=tp[i]
++	&mov	(&DWP($frame,"esp",$num,4),$j);	# zap temporary vector
++	&dec	($num);
++	&jge	(&label("copy"));
++
++	&mov	("esp",$_sp);		# pull saved stack pointer
++	&mov	("eax",1);
++&set_label("just_leave");
++&function_end("bn_mul_mont");
++
++&asciz("Montgomery Multiplication for x86, CRYPTOGAMS by ");
++
++&asm_finish();
++
++close STDOUT;
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/bn/asm/x86.pl b/CryptoPkg/Library/OpensslLib/openssl/crypto/bn/asm/x86.pl
+new file mode 100644
+index 0000000..d57571d
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/bn/asm/x86.pl
+@@ -0,0 +1,38 @@
++#! /usr/bin/env perl
++# Copyright 1995-2016 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
++# in the file LICENSE in the source distribution or at
++# https://www.openssl.org/source/license.html
++
++push(@INC,"perlasm","../../perlasm");
++require "x86asm.pl";
++
++require("x86/mul_add.pl");
++require("x86/mul.pl");
++require("x86/sqr.pl");
++require("x86/div.pl");
++require("x86/add.pl");
++require("x86/sub.pl");
++require("x86/comba.pl");
++
++$output = pop;
++open STDOUT,">$output";
++
++&asm_init($ARGV[0],$0);
++
++&bn_mul_add_words("bn_mul_add_words");
++&bn_mul_words("bn_mul_words");
++&bn_sqr_words("bn_sqr_words");
++&bn_div_words("bn_div_words");
++&bn_add_words("bn_add_words");
++&bn_sub_words("bn_sub_words");
++&bn_mul_comba("bn_mul_comba8",8);
++&bn_mul_comba("bn_mul_comba4",4);
++&bn_sqr_comba("bn_sqr_comba8",8);
++&bn_sqr_comba("bn_sqr_comba4",4);
++
++&asm_finish();
++
++close STDOUT;
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/bn/asm/x86_64-gcc.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/bn/asm/x86_64-gcc.c
+new file mode 100644
+index 0000000..4f19abe
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/bn/asm/x86_64-gcc.c
+@@ -0,0 +1,647 @@
++/*
++ * Copyright 2002-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include "../bn_lcl.h"
++#if !(defined(__GNUC__) && __GNUC__>=2)
++# include "../bn_asm.c"         /* kind of dirty hack for Sun Studio */
++#else
++/*-
++ * x86_64 BIGNUM accelerator version 0.1, December 2002.
++ *
++ * Implemented by Andy Polyakov  for the OpenSSL
++ * project.
++ *
++ * Rights for redistribution and usage in source and binary forms are
++ * granted according to the OpenSSL license. Warranty of any kind is
++ * disclaimed.
++ *
++ * Q. Version 0.1? It doesn't sound like Andy, he used to assign real
++ *    versions, like 1.0...
++ * A. Well, that's because this code is basically a quick-n-dirty
++ *    proof-of-concept hack. As you can see it's implemented with
++ *    inline assembler, which means that you're bound to GCC and that
++ *    there might be enough room for further improvement.
++ *
++ * Q. Why inline assembler?
++ * A. x86_64 features own ABI which I'm not familiar with. This is
++ *    why I decided to let the compiler take care of subroutine
++ *    prologue/epilogue as well as register allocation. For reference.
++ *    Win64 implements different ABI for AMD64, different from Linux.
++ *
++ * Q. How much faster does it get?
++ * A. 'apps/openssl speed rsa dsa' output with no-asm:
++ *
++ *                        sign    verify    sign/s verify/s
++ *      rsa  512 bits   0.0006s   0.0001s   1683.8  18456.2
++ *      rsa 1024 bits   0.0028s   0.0002s    356.0   6407.0
++ *      rsa 2048 bits   0.0172s   0.0005s     58.0   1957.8
++ *      rsa 4096 bits   0.1155s   0.0018s      8.7    555.6
++ *                        sign    verify    sign/s verify/s
++ *      dsa  512 bits   0.0005s   0.0006s   2100.8   1768.3
++ *      dsa 1024 bits   0.0014s   0.0018s    692.3    559.2
++ *      dsa 2048 bits   0.0049s   0.0061s    204.7    165.0
++ *
++ *    'apps/openssl speed rsa dsa' output with this module:
++ *
++ *                        sign    verify    sign/s verify/s
++ *      rsa  512 bits   0.0004s   0.0000s   2767.1  33297.9
++ *      rsa 1024 bits   0.0012s   0.0001s    867.4  14674.7
++ *      rsa 2048 bits   0.0061s   0.0002s    164.0   5270.0
++ *      rsa 4096 bits   0.0384s   0.0006s     26.1   1650.8
++ *                        sign    verify    sign/s verify/s
++ *      dsa  512 bits   0.0002s   0.0003s   4442.2   3786.3
++ *      dsa 1024 bits   0.0005s   0.0007s   1835.1   1497.4
++ *      dsa 2048 bits   0.0016s   0.0020s    620.4    504.6
++ *
++ *    For the reference. IA-32 assembler implementation performs
++ *    very much like 64-bit code compiled with no-asm on the same
++ *    machine.
++ */
++
++# if defined(_WIN64) || !defined(__LP64__)
++#  define BN_ULONG unsigned long long
++# else
++#  define BN_ULONG unsigned long
++# endif
++
++# undef mul
++# undef mul_add
++
++/*-
++ * "m"(a), "+m"(r)      is the way to favor DirectPath µ-code;
++ * "g"(0)               let the compiler to decide where does it
++ *                      want to keep the value of zero;
++ */
++# define mul_add(r,a,word,carry) do {   \
++        register BN_ULONG high,low;     \
++        asm ("mulq %3"                  \
++                : "=a"(low),"=d"(high)  \
++                : "a"(word),"m"(a)      \
++                : "cc");                \
++        asm ("addq %2,%0; adcq %3,%1"   \
++                : "+r"(carry),"+d"(high)\
++                : "a"(low),"g"(0)       \
++                : "cc");                \
++        asm ("addq %2,%0; adcq %3,%1"   \
++                : "+m"(r),"+d"(high)    \
++                : "r"(carry),"g"(0)     \
++                : "cc");                \
++        carry=high;                     \
++        } while (0)
++
++# define mul(r,a,word,carry) do {       \
++        register BN_ULONG high,low;     \
++        asm ("mulq %3"                  \
++                : "=a"(low),"=d"(high)  \
++                : "a"(word),"g"(a)      \
++                : "cc");                \
++        asm ("addq %2,%0; adcq %3,%1"   \
++                : "+r"(carry),"+d"(high)\
++                : "a"(low),"g"(0)       \
++                : "cc");                \
++        (r)=carry, carry=high;          \
++        } while (0)
++# undef sqr
++# define sqr(r0,r1,a)                   \
++        asm ("mulq %2"                  \
++                : "=a"(r0),"=d"(r1)     \
++                : "a"(a)                \
++                : "cc");
++
++BN_ULONG bn_mul_add_words(BN_ULONG *rp, const BN_ULONG *ap, int num,
++                          BN_ULONG w)
++{
++    BN_ULONG c1 = 0;
++
++    if (num <= 0)
++        return (c1);
++
++    while (num & ~3) {
++        mul_add(rp[0], ap[0], w, c1);
++        mul_add(rp[1], ap[1], w, c1);
++        mul_add(rp[2], ap[2], w, c1);
++        mul_add(rp[3], ap[3], w, c1);
++        ap += 4;
++        rp += 4;
++        num -= 4;
++    }
++    if (num) {
++        mul_add(rp[0], ap[0], w, c1);
++        if (--num == 0)
++            return c1;
++        mul_add(rp[1], ap[1], w, c1);
++        if (--num == 0)
++            return c1;
++        mul_add(rp[2], ap[2], w, c1);
++        return c1;
++    }
++
++    return (c1);
++}
++
++BN_ULONG bn_mul_words(BN_ULONG *rp, const BN_ULONG *ap, int num, BN_ULONG w)
++{
++    BN_ULONG c1 = 0;
++
++    if (num <= 0)
++        return (c1);
++
++    while (num & ~3) {
++        mul(rp[0], ap[0], w, c1);
++        mul(rp[1], ap[1], w, c1);
++        mul(rp[2], ap[2], w, c1);
++        mul(rp[3], ap[3], w, c1);
++        ap += 4;
++        rp += 4;
++        num -= 4;
++    }
++    if (num) {
++        mul(rp[0], ap[0], w, c1);
++        if (--num == 0)
++            return c1;
++        mul(rp[1], ap[1], w, c1);
++        if (--num == 0)
++            return c1;
++        mul(rp[2], ap[2], w, c1);
++    }
++    return (c1);
++}
++
++void bn_sqr_words(BN_ULONG *r, const BN_ULONG *a, int n)
++{
++    if (n <= 0)
++        return;
++
++    while (n & ~3) {
++        sqr(r[0], r[1], a[0]);
++        sqr(r[2], r[3], a[1]);
++        sqr(r[4], r[5], a[2]);
++        sqr(r[6], r[7], a[3]);
++        a += 4;
++        r += 8;
++        n -= 4;
++    }
++    if (n) {
++        sqr(r[0], r[1], a[0]);
++        if (--n == 0)
++            return;
++        sqr(r[2], r[3], a[1]);
++        if (--n == 0)
++            return;
++        sqr(r[4], r[5], a[2]);
++    }
++}
++
++BN_ULONG bn_div_words(BN_ULONG h, BN_ULONG l, BN_ULONG d)
++{
++    BN_ULONG ret, waste;
++
++ asm("divq      %4":"=a"(ret), "=d"(waste)
++ :     "a"(l), "d"(h), "r"(d)
++ :     "cc");
++
++    return ret;
++}
++
++BN_ULONG bn_add_words(BN_ULONG *rp, const BN_ULONG *ap, const BN_ULONG *bp,
++                      int n)
++{
++    BN_ULONG ret;
++    size_t i = 0;
++
++    if (n <= 0)
++        return 0;
++
++    asm volatile ("       subq    %0,%0           \n" /* clear carry */
++                  "       jmp     1f              \n"
++                  ".p2align 4                     \n"
++                  "1:     movq    (%4,%2,8),%0    \n"
++                  "       adcq    (%5,%2,8),%0    \n"
++                  "       movq    %0,(%3,%2,8)    \n"
++                  "       lea     1(%2),%2        \n"
++                  "       loop    1b              \n"
++                  "       sbbq    %0,%0           \n":"=&r" (ret), "+c"(n),
++                  "+r"(i)
++                  :"r"(rp), "r"(ap), "r"(bp)
++                  :"cc", "memory");
++
++    return ret & 1;
++}
++
++# ifndef SIMICS
++BN_ULONG bn_sub_words(BN_ULONG *rp, const BN_ULONG *ap, const BN_ULONG *bp,
++                      int n)
++{
++    BN_ULONG ret;
++    size_t i = 0;
++
++    if (n <= 0)
++        return 0;
++
++    asm volatile ("       subq    %0,%0           \n" /* clear borrow */
++                  "       jmp     1f              \n"
++                  ".p2align 4                     \n"
++                  "1:     movq    (%4,%2,8),%0    \n"
++                  "       sbbq    (%5,%2,8),%0    \n"
++                  "       movq    %0,(%3,%2,8)    \n"
++                  "       lea     1(%2),%2        \n"
++                  "       loop    1b              \n"
++                  "       sbbq    %0,%0           \n":"=&r" (ret), "+c"(n),
++                  "+r"(i)
++                  :"r"(rp), "r"(ap), "r"(bp)
++                  :"cc", "memory");
++
++    return ret & 1;
++}
++# else
++/* Simics 1.4<7 has buggy sbbq:-( */
++#  define BN_MASK2 0xffffffffffffffffL
++BN_ULONG bn_sub_words(BN_ULONG *r, BN_ULONG *a, BN_ULONG *b, int n)
++{
++    BN_ULONG t1, t2;
++    int c = 0;
++
++    if (n <= 0)
++        return ((BN_ULONG)0);
++
++    for (;;) {
++        t1 = a[0];
++        t2 = b[0];
++        r[0] = (t1 - t2 - c) & BN_MASK2;
++        if (t1 != t2)
++            c = (t1 < t2);
++        if (--n <= 0)
++            break;
++
++        t1 = a[1];
++        t2 = b[1];
++        r[1] = (t1 - t2 - c) & BN_MASK2;
++        if (t1 != t2)
++            c = (t1 < t2);
++        if (--n <= 0)
++            break;
++
++        t1 = a[2];
++        t2 = b[2];
++        r[2] = (t1 - t2 - c) & BN_MASK2;
++        if (t1 != t2)
++            c = (t1 < t2);
++        if (--n <= 0)
++            break;
++
++        t1 = a[3];
++        t2 = b[3];
++        r[3] = (t1 - t2 - c) & BN_MASK2;
++        if (t1 != t2)
++            c = (t1 < t2);
++        if (--n <= 0)
++            break;
++
++        a += 4;
++        b += 4;
++        r += 4;
++    }
++    return (c);
++}
++# endif
++
++/* mul_add_c(a,b,c0,c1,c2)  -- c+=a*b for three word number c=(c2,c1,c0) */
++/* mul_add_c2(a,b,c0,c1,c2) -- c+=2*a*b for three word number c=(c2,c1,c0) */
++/* sqr_add_c(a,i,c0,c1,c2)  -- c+=a[i]^2 for three word number c=(c2,c1,c0) */
++/*
++ * sqr_add_c2(a,i,c0,c1,c2) -- c+=2*a[i]*a[j] for three word number
++ * c=(c2,c1,c0)
++ */
++
++/*
++ * Keep in mind that carrying into high part of multiplication result
++ * can not overflow, because it cannot be all-ones.
++ */
++# if 0
++/* original macros are kept for reference purposes */
++#  define mul_add_c(a,b,c0,c1,c2)       do {    \
++        BN_ULONG ta = (a), tb = (b);            \
++        BN_ULONG lo, hi;                        \
++        BN_UMULT_LOHI(lo,hi,ta,tb);             \
++        c0 += lo; hi += (c0 for the OpenSSL
++# project. The module is, however, dual licensed under OpenSSL and
++# CRYPTOGAMS licenses depending on where you obtain it. For further
++# details see http://www.openssl.org/~appro/cryptogams/.
++# ====================================================================
++#
++# May 2011
++#
++# The module implements bn_GF2m_mul_2x2 polynomial multiplication used
++# in bn_gf2m.c. It's kind of low-hanging mechanical port from C for
++# the time being... Except that it has two code paths: code suitable
++# for any x86_64 CPU and PCLMULQDQ one suitable for Westmere and
++# later. Improvement varies from one benchmark and µ-arch to another.
++# Vanilla code path is at most 20% faster than compiler-generated code
++# [not very impressive], while PCLMULQDQ - whole 85%-160% better on
++# 163- and 571-bit ECDH benchmarks on Intel CPUs. Keep in mind that
++# these coefficients are not ones for bn_GF2m_mul_2x2 itself, as not
++# all CPU time is burnt in it...
++
++$flavour = shift;
++$output  = shift;
++if ($flavour =~ /\./) { $output = $flavour; undef $flavour; }
++
++$win64=0; $win64=1 if ($flavour =~ /[nm]asm|mingw64/ || $output =~ /\.asm$/);
++
++$0 =~ m/(.*[\/\\])[^\/\\]+$/; $dir=$1;
++( $xlate="${dir}x86_64-xlate.pl" and -f $xlate ) or
++( $xlate="${dir}../../perlasm/x86_64-xlate.pl" and -f $xlate) or
++die "can't locate x86_64-xlate.pl";
++
++open OUT,"| \"$^X\" \"$xlate\" $flavour \"$output\"";
++*STDOUT=*OUT;
++
++($lo,$hi)=("%rax","%rdx");	$a=$lo;
++($i0,$i1)=("%rsi","%rdi");
++($t0,$t1)=("%rbx","%rcx");
++($b,$mask)=("%rbp","%r8");
++($a1,$a2,$a4,$a8,$a12,$a48)=map("%r$_",(9..15));
++($R,$Tx)=("%xmm0","%xmm1");
++
++$code.=<<___;
++.text
++
++.type	_mul_1x1,\@abi-omnipotent
++.align	16
++_mul_1x1:
++	sub	\$128+8,%rsp
++	mov	\$-1,$a1
++	lea	($a,$a),$i0
++	shr	\$3,$a1
++	lea	(,$a,4),$i1
++	and	$a,$a1			# a1=a&0x1fffffffffffffff
++	lea	(,$a,8),$a8
++	sar	\$63,$a			# broadcast 63rd bit
++	lea	($a1,$a1),$a2
++	sar	\$63,$i0		# broadcast 62nd bit
++	lea	(,$a1,4),$a4
++	and	$b,$a
++	sar	\$63,$i1		# boardcast 61st bit
++	mov	$a,$hi			# $a is $lo
++	shl	\$63,$lo
++	and	$b,$i0
++	shr	\$1,$hi
++	mov	$i0,$t1
++	shl	\$62,$i0
++	and	$b,$i1
++	shr	\$2,$t1
++	xor	$i0,$lo
++	mov	$i1,$t0
++	shl	\$61,$i1
++	xor	$t1,$hi
++	shr	\$3,$t0
++	xor	$i1,$lo
++	xor	$t0,$hi
++
++	mov	$a1,$a12
++	movq	\$0,0(%rsp)		# tab[0]=0
++	xor	$a2,$a12		# a1^a2
++	mov	$a1,8(%rsp)		# tab[1]=a1
++	 mov	$a4,$a48
++	mov	$a2,16(%rsp)		# tab[2]=a2
++	 xor	$a8,$a48		# a4^a8
++	mov	$a12,24(%rsp)		# tab[3]=a1^a2
++
++	xor	$a4,$a1
++	mov	$a4,32(%rsp)		# tab[4]=a4
++	xor	$a4,$a2
++	mov	$a1,40(%rsp)		# tab[5]=a1^a4
++	xor	$a4,$a12
++	mov	$a2,48(%rsp)		# tab[6]=a2^a4
++	 xor	$a48,$a1		# a1^a4^a4^a8=a1^a8
++	mov	$a12,56(%rsp)		# tab[7]=a1^a2^a4
++	 xor	$a48,$a2		# a2^a4^a4^a8=a1^a8
++
++	mov	$a8,64(%rsp)		# tab[8]=a8
++	xor	$a48,$a12		# a1^a2^a4^a4^a8=a1^a2^a8
++	mov	$a1,72(%rsp)		# tab[9]=a1^a8
++	 xor	$a4,$a1			# a1^a8^a4
++	mov	$a2,80(%rsp)		# tab[10]=a2^a8
++	 xor	$a4,$a2			# a2^a8^a4
++	mov	$a12,88(%rsp)		# tab[11]=a1^a2^a8
++
++	xor	$a4,$a12		# a1^a2^a8^a4
++	mov	$a48,96(%rsp)		# tab[12]=a4^a8
++	 mov	$mask,$i0
++	mov	$a1,104(%rsp)		# tab[13]=a1^a4^a8
++	 and	$b,$i0
++	mov	$a2,112(%rsp)		# tab[14]=a2^a4^a8
++	 shr	\$4,$b
++	mov	$a12,120(%rsp)		# tab[15]=a1^a2^a4^a8
++	 mov	$mask,$i1
++	 and	$b,$i1
++	 shr	\$4,$b
++
++	movq	(%rsp,$i0,8),$R		# half of calculations is done in SSE2
++	mov	$mask,$i0
++	and	$b,$i0
++	shr	\$4,$b
++___
++    for ($n=1;$n<8;$n++) {
++	$code.=<<___;
++	mov	(%rsp,$i1,8),$t1
++	mov	$mask,$i1
++	mov	$t1,$t0
++	shl	\$`8*$n-4`,$t1
++	and	$b,$i1
++	 movq	(%rsp,$i0,8),$Tx
++	shr	\$`64-(8*$n-4)`,$t0
++	xor	$t1,$lo
++	 pslldq	\$$n,$Tx
++	 mov	$mask,$i0
++	shr	\$4,$b
++	xor	$t0,$hi
++	 and	$b,$i0
++	 shr	\$4,$b
++	 pxor	$Tx,$R
++___
++    }
++$code.=<<___;
++	mov	(%rsp,$i1,8),$t1
++	mov	$t1,$t0
++	shl	\$`8*$n-4`,$t1
++	movq	$R,$i0
++	shr	\$`64-(8*$n-4)`,$t0
++	xor	$t1,$lo
++	psrldq	\$8,$R
++	xor	$t0,$hi
++	movq	$R,$i1
++	xor	$i0,$lo
++	xor	$i1,$hi
++
++	add	\$128+8,%rsp
++	ret
++.Lend_mul_1x1:
++.size	_mul_1x1,.-_mul_1x1
++___
++
++($rp,$a1,$a0,$b1,$b0) = $win64?	("%rcx","%rdx","%r8", "%r9","%r10") :	# Win64 order
++				("%rdi","%rsi","%rdx","%rcx","%r8");	# Unix order
++
++$code.=<<___;
++.extern	OPENSSL_ia32cap_P
++.globl	bn_GF2m_mul_2x2
++.type	bn_GF2m_mul_2x2,\@abi-omnipotent
++.align	16
++bn_GF2m_mul_2x2:
++	mov	OPENSSL_ia32cap_P(%rip),%rax
++	bt	\$33,%rax
++	jnc	.Lvanilla_mul_2x2
++
++	movq		$a1,%xmm0
++	movq		$b1,%xmm1
++	movq		$a0,%xmm2
++___
++$code.=<<___ if ($win64);
++	movq		40(%rsp),%xmm3
++___
++$code.=<<___ if (!$win64);
++	movq		$b0,%xmm3
++___
++$code.=<<___;
++	movdqa		%xmm0,%xmm4
++	movdqa		%xmm1,%xmm5
++	pclmulqdq	\$0,%xmm1,%xmm0	# a1·b1
++	pxor		%xmm2,%xmm4
++	pxor		%xmm3,%xmm5
++	pclmulqdq	\$0,%xmm3,%xmm2	# a0·b0
++	pclmulqdq	\$0,%xmm5,%xmm4	# (a0+a1)·(b0+b1)
++	xorps		%xmm0,%xmm4
++	xorps		%xmm2,%xmm4	# (a0+a1)·(b0+b1)-a0·b0-a1·b1
++	movdqa		%xmm4,%xmm5
++	pslldq		\$8,%xmm4
++	psrldq		\$8,%xmm5
++	pxor		%xmm4,%xmm2
++	pxor		%xmm5,%xmm0
++	movdqu		%xmm2,0($rp)
++	movdqu		%xmm0,16($rp)
++	ret
++
++.align	16
++.Lvanilla_mul_2x2:
++	lea	-8*17(%rsp),%rsp
++___
++$code.=<<___ if ($win64);
++	mov	`8*17+40`(%rsp),$b0
++	mov	%rdi,8*15(%rsp)
++	mov	%rsi,8*16(%rsp)
++___
++$code.=<<___;
++	mov	%r14,8*10(%rsp)
++	mov	%r13,8*11(%rsp)
++	mov	%r12,8*12(%rsp)
++	mov	%rbp,8*13(%rsp)
++	mov	%rbx,8*14(%rsp)
++.Lbody_mul_2x2:
++	mov	$rp,32(%rsp)		# save the arguments
++	mov	$a1,40(%rsp)
++	mov	$a0,48(%rsp)
++	mov	$b1,56(%rsp)
++	mov	$b0,64(%rsp)
++
++	mov	\$0xf,$mask
++	mov	$a1,$a
++	mov	$b1,$b
++	call	_mul_1x1		# a1·b1
++	mov	$lo,16(%rsp)
++	mov	$hi,24(%rsp)
++
++	mov	48(%rsp),$a
++	mov	64(%rsp),$b
++	call	_mul_1x1		# a0·b0
++	mov	$lo,0(%rsp)
++	mov	$hi,8(%rsp)
++
++	mov	40(%rsp),$a
++	mov	56(%rsp),$b
++	xor	48(%rsp),$a
++	xor	64(%rsp),$b
++	call	_mul_1x1		# (a0+a1)·(b0+b1)
++___
++	@r=("%rbx","%rcx","%rdi","%rsi");
++$code.=<<___;
++	mov	0(%rsp),@r[0]
++	mov	8(%rsp),@r[1]
++	mov	16(%rsp),@r[2]
++	mov	24(%rsp),@r[3]
++	mov	32(%rsp),%rbp
++
++	xor	$hi,$lo
++	xor	@r[1],$hi
++	xor	@r[0],$lo
++	mov	@r[0],0(%rbp)
++	xor	@r[2],$hi
++	mov	@r[3],24(%rbp)
++	xor	@r[3],$lo
++	xor	@r[3],$hi
++	xor	$hi,$lo
++	mov	$hi,16(%rbp)
++	mov	$lo,8(%rbp)
++
++	mov	8*10(%rsp),%r14
++	mov	8*11(%rsp),%r13
++	mov	8*12(%rsp),%r12
++	mov	8*13(%rsp),%rbp
++	mov	8*14(%rsp),%rbx
++___
++$code.=<<___ if ($win64);
++	mov	8*15(%rsp),%rdi
++	mov	8*16(%rsp),%rsi
++___
++$code.=<<___;
++	lea	8*17(%rsp),%rsp
++	ret
++.Lend_mul_2x2:
++.size	bn_GF2m_mul_2x2,.-bn_GF2m_mul_2x2
++.asciz	"GF(2^m) Multiplication for x86_64, CRYPTOGAMS by "
++.align	16
++___
++
++# EXCEPTION_DISPOSITION handler (EXCEPTION_RECORD *rec,ULONG64 frame,
++#               CONTEXT *context,DISPATCHER_CONTEXT *disp)
++if ($win64) {
++$rec="%rcx";
++$frame="%rdx";
++$context="%r8";
++$disp="%r9";
++
++$code.=<<___;
++.extern __imp_RtlVirtualUnwind
++
++.type	se_handler,\@abi-omnipotent
++.align	16
++se_handler:
++	push	%rsi
++	push	%rdi
++	push	%rbx
++	push	%rbp
++	push	%r12
++	push	%r13
++	push	%r14
++	push	%r15
++	pushfq
++	sub	\$64,%rsp
++
++	mov	152($context),%rax	# pull context->Rsp
++	mov	248($context),%rbx	# pull context->Rip
++
++	lea	.Lbody_mul_2x2(%rip),%r10
++	cmp	%r10,%rbx		# context->Rip<"prologue" label
++	jb	.Lin_prologue
++
++	mov	8*10(%rax),%r14		# mimic epilogue
++	mov	8*11(%rax),%r13
++	mov	8*12(%rax),%r12
++	mov	8*13(%rax),%rbp
++	mov	8*14(%rax),%rbx
++	mov	8*15(%rax),%rdi
++	mov	8*16(%rax),%rsi
++
++	mov	%rbx,144($context)	# restore context->Rbx
++	mov	%rbp,160($context)	# restore context->Rbp
++	mov	%rsi,168($context)	# restore context->Rsi
++	mov	%rdi,176($context)	# restore context->Rdi
++	mov	%r12,216($context)	# restore context->R12
++	mov	%r13,224($context)	# restore context->R13
++	mov	%r14,232($context)	# restore context->R14
++
++.Lin_prologue:
++	lea	8*17(%rax),%rax
++	mov	%rax,152($context)	# restore context->Rsp
++
++	mov	40($disp),%rdi		# disp->ContextRecord
++	mov	$context,%rsi		# context
++	mov	\$154,%ecx		# sizeof(CONTEXT)
++	.long	0xa548f3fc		# cld; rep movsq
++
++	mov	$disp,%rsi
++	xor	%rcx,%rcx		# arg1, UNW_FLAG_NHANDLER
++	mov	8(%rsi),%rdx		# arg2, disp->ImageBase
++	mov	0(%rsi),%r8		# arg3, disp->ControlPc
++	mov	16(%rsi),%r9		# arg4, disp->FunctionEntry
++	mov	40(%rsi),%r10		# disp->ContextRecord
++	lea	56(%rsi),%r11		# &disp->HandlerData
++	lea	24(%rsi),%r12		# &disp->EstablisherFrame
++	mov	%r10,32(%rsp)		# arg5
++	mov	%r11,40(%rsp)		# arg6
++	mov	%r12,48(%rsp)		# arg7
++	mov	%rcx,56(%rsp)		# arg8, (NULL)
++	call	*__imp_RtlVirtualUnwind(%rip)
++
++	mov	\$1,%eax		# ExceptionContinueSearch
++	add	\$64,%rsp
++	popfq
++	pop	%r15
++	pop	%r14
++	pop	%r13
++	pop	%r12
++	pop	%rbp
++	pop	%rbx
++	pop	%rdi
++	pop	%rsi
++	ret
++.size	se_handler,.-se_handler
++
++.section	.pdata
++.align	4
++	.rva	_mul_1x1
++	.rva	.Lend_mul_1x1
++	.rva	.LSEH_info_1x1
++
++	.rva	.Lvanilla_mul_2x2
++	.rva	.Lend_mul_2x2
++	.rva	.LSEH_info_2x2
++.section	.xdata
++.align	8
++.LSEH_info_1x1:
++	.byte	0x01,0x07,0x02,0x00
++	.byte	0x07,0x01,0x11,0x00	# sub rsp,128+8
++.LSEH_info_2x2:
++	.byte	9,0,0,0
++	.rva	se_handler
++___
++}
++
++$code =~ s/\`([^\`]*)\`/eval($1)/gem;
++print $code;
++close STDOUT;
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/bn/asm/x86_64-mont.pl b/CryptoPkg/Library/OpensslLib/openssl/crypto/bn/asm/x86_64-mont.pl
+new file mode 100755
+index 0000000..df4cca5
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/bn/asm/x86_64-mont.pl
+@@ -0,0 +1,1521 @@
++#! /usr/bin/env perl
++# Copyright 2005-2016 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
++# in the file LICENSE in the source distribution or at
++# https://www.openssl.org/source/license.html
++
++
++# ====================================================================
++# Written by Andy Polyakov  for the OpenSSL
++# project. The module is, however, dual licensed under OpenSSL and
++# CRYPTOGAMS licenses depending on where you obtain it. For further
++# details see http://www.openssl.org/~appro/cryptogams/.
++# ====================================================================
++
++# October 2005.
++#
++# Montgomery multiplication routine for x86_64. While it gives modest
++# 9% improvement of rsa4096 sign on Opteron, rsa512 sign runs more
++# than twice, >2x, as fast. Most common rsa1024 sign is improved by
++# respectful 50%. It remains to be seen if loop unrolling and
++# dedicated squaring routine can provide further improvement...
++
++# July 2011.
++#
++# Add dedicated squaring procedure. Performance improvement varies
++# from platform to platform, but in average it's ~5%/15%/25%/33%
++# for 512-/1024-/2048-/4096-bit RSA *sign* benchmarks respectively.
++
++# August 2011.
++#
++# Unroll and modulo-schedule inner loops in such manner that they
++# are "fallen through" for input lengths of 8, which is critical for
++# 1024-bit RSA *sign*. Average performance improvement in comparison
++# to *initial* version of this module from 2005 is ~0%/30%/40%/45%
++# for 512-/1024-/2048-/4096-bit RSA *sign* benchmarks respectively.
++
++# June 2013.
++#
++# Optimize reduction in squaring procedure and improve 1024+-bit RSA
++# sign performance by 10-16% on Intel Sandy Bridge and later
++# (virtually same on non-Intel processors).
++
++# August 2013.
++#
++# Add MULX/ADOX/ADCX code path.
++
++$flavour = shift;
++$output  = shift;
++if ($flavour =~ /\./) { $output = $flavour; undef $flavour; }
++
++$win64=0; $win64=1 if ($flavour =~ /[nm]asm|mingw64/ || $output =~ /\.asm$/);
++
++$0 =~ m/(.*[\/\\])[^\/\\]+$/; $dir=$1;
++( $xlate="${dir}x86_64-xlate.pl" and -f $xlate ) or
++( $xlate="${dir}../../perlasm/x86_64-xlate.pl" and -f $xlate) or
++die "can't locate x86_64-xlate.pl";
++
++open OUT,"| \"$^X\" \"$xlate\" $flavour \"$output\"";
++*STDOUT=*OUT;
++
++if (`$ENV{CC} -Wa,-v -c -o /dev/null -x assembler /dev/null 2>&1`
++		=~ /GNU assembler version ([2-9]\.[0-9]+)/) {
++	$addx = ($1>=2.23);
++}
++
++if (!$addx && $win64 && ($flavour =~ /nasm/ || $ENV{ASM} =~ /nasm/) &&
++	    `nasm -v 2>&1` =~ /NASM version ([2-9]\.[0-9]+)/) {
++	$addx = ($1>=2.10);
++}
++
++if (!$addx && $win64 && ($flavour =~ /masm/ || $ENV{ASM} =~ /ml64/) &&
++	    `ml64 2>&1` =~ /Version ([0-9]+)\./) {
++	$addx = ($1>=12);
++}
++
++if (!$addx && `$ENV{CC} -v 2>&1` =~ /((?:^clang|LLVM) version|.*based on LLVM) ([3-9])\.([0-9]+)/) {
++	my $ver = $2 + $3/100.0;	# 3.1->3.01, 3.10->3.10
++	$addx = ($ver>=3.03);
++}
++
++# int bn_mul_mont(
++$rp="%rdi";	# BN_ULONG *rp,
++$ap="%rsi";	# const BN_ULONG *ap,
++$bp="%rdx";	# const BN_ULONG *bp,
++$np="%rcx";	# const BN_ULONG *np,
++$n0="%r8";	# const BN_ULONG *n0,
++$num="%r9";	# int num);
++$lo0="%r10";
++$hi0="%r11";
++$hi1="%r13";
++$i="%r14";
++$j="%r15";
++$m0="%rbx";
++$m1="%rbp";
++
++$code=<<___;
++.text
++
++.extern	OPENSSL_ia32cap_P
++
++.globl	bn_mul_mont
++.type	bn_mul_mont,\@function,6
++.align	16
++bn_mul_mont:
++	mov	${num}d,${num}d
++	mov	%rsp,%rax
++	test	\$3,${num}d
++	jnz	.Lmul_enter
++	cmp	\$8,${num}d
++	jb	.Lmul_enter
++___
++$code.=<<___ if ($addx);
++	mov	OPENSSL_ia32cap_P+8(%rip),%r11d
++___
++$code.=<<___;
++	cmp	$ap,$bp
++	jne	.Lmul4x_enter
++	test	\$7,${num}d
++	jz	.Lsqr8x_enter
++	jmp	.Lmul4x_enter
++
++.align	16
++.Lmul_enter:
++	push	%rbx
++	push	%rbp
++	push	%r12
++	push	%r13
++	push	%r14
++	push	%r15
++
++	neg	$num
++	mov	%rsp,%r11
++	lea	-16(%rsp,$num,8),%r10	# future alloca(8*(num+2))
++	neg	$num			# restore $num
++	and	\$-1024,%r10		# minimize TLB usage
++
++	# An OS-agnostic version of __chkstk.
++	#
++	# Some OSes (Windows) insist on stack being "wired" to
++	# physical memory in strictly sequential manner, i.e. if stack
++	# allocation spans two pages, then reference to farmost one can
++	# be punishable by SEGV. But page walking can do good even on
++	# other OSes, because it guarantees that villain thread hits
++	# the guard page before it can make damage to innocent one...
++	sub	%r10,%r11
++	and	\$-4096,%r11
++	lea	(%r10,%r11),%rsp
++	mov	(%rsp),%r11
++	cmp	%r10,%rsp
++	ja	.Lmul_page_walk
++	jmp	.Lmul_page_walk_done
++
++.align	16
++.Lmul_page_walk:
++	lea	-4096(%rsp),%rsp
++	mov	(%rsp),%r11
++	cmp	%r10,%rsp
++	ja	.Lmul_page_walk
++.Lmul_page_walk_done:
++
++	mov	%rax,8(%rsp,$num,8)	# tp[num+1]=%rsp
++.Lmul_body:
++	mov	$bp,%r12		# reassign $bp
++___
++		$bp="%r12";
++$code.=<<___;
++	mov	($n0),$n0		# pull n0[0] value
++	mov	($bp),$m0		# m0=bp[0]
++	mov	($ap),%rax
++
++	xor	$i,$i			# i=0
++	xor	$j,$j			# j=0
++
++	mov	$n0,$m1
++	mulq	$m0			# ap[0]*bp[0]
++	mov	%rax,$lo0
++	mov	($np),%rax
++
++	imulq	$lo0,$m1		# "tp[0]"*n0
++	mov	%rdx,$hi0
++
++	mulq	$m1			# np[0]*m1
++	add	%rax,$lo0		# discarded
++	mov	8($ap),%rax
++	adc	\$0,%rdx
++	mov	%rdx,$hi1
++
++	lea	1($j),$j		# j++
++	jmp	.L1st_enter
++
++.align	16
++.L1st:
++	add	%rax,$hi1
++	mov	($ap,$j,8),%rax
++	adc	\$0,%rdx
++	add	$hi0,$hi1		# np[j]*m1+ap[j]*bp[0]
++	mov	$lo0,$hi0
++	adc	\$0,%rdx
++	mov	$hi1,-16(%rsp,$j,8)	# tp[j-1]
++	mov	%rdx,$hi1
++
++.L1st_enter:
++	mulq	$m0			# ap[j]*bp[0]
++	add	%rax,$hi0
++	mov	($np,$j,8),%rax
++	adc	\$0,%rdx
++	lea	1($j),$j		# j++
++	mov	%rdx,$lo0
++
++	mulq	$m1			# np[j]*m1
++	cmp	$num,$j
++	jne	.L1st
++
++	add	%rax,$hi1
++	mov	($ap),%rax		# ap[0]
++	adc	\$0,%rdx
++	add	$hi0,$hi1		# np[j]*m1+ap[j]*bp[0]
++	adc	\$0,%rdx
++	mov	$hi1,-16(%rsp,$j,8)	# tp[j-1]
++	mov	%rdx,$hi1
++	mov	$lo0,$hi0
++
++	xor	%rdx,%rdx
++	add	$hi0,$hi1
++	adc	\$0,%rdx
++	mov	$hi1,-8(%rsp,$num,8)
++	mov	%rdx,(%rsp,$num,8)	# store upmost overflow bit
++
++	lea	1($i),$i		# i++
++	jmp	.Louter
++.align	16
++.Louter:
++	mov	($bp,$i,8),$m0		# m0=bp[i]
++	xor	$j,$j			# j=0
++	mov	$n0,$m1
++	mov	(%rsp),$lo0
++	mulq	$m0			# ap[0]*bp[i]
++	add	%rax,$lo0		# ap[0]*bp[i]+tp[0]
++	mov	($np),%rax
++	adc	\$0,%rdx
++
++	imulq	$lo0,$m1		# tp[0]*n0
++	mov	%rdx,$hi0
++
++	mulq	$m1			# np[0]*m1
++	add	%rax,$lo0		# discarded
++	mov	8($ap),%rax
++	adc	\$0,%rdx
++	mov	8(%rsp),$lo0		# tp[1]
++	mov	%rdx,$hi1
++
++	lea	1($j),$j		# j++
++	jmp	.Linner_enter
++
++.align	16
++.Linner:
++	add	%rax,$hi1
++	mov	($ap,$j,8),%rax
++	adc	\$0,%rdx
++	add	$lo0,$hi1		# np[j]*m1+ap[j]*bp[i]+tp[j]
++	mov	(%rsp,$j,8),$lo0
++	adc	\$0,%rdx
++	mov	$hi1,-16(%rsp,$j,8)	# tp[j-1]
++	mov	%rdx,$hi1
++
++.Linner_enter:
++	mulq	$m0			# ap[j]*bp[i]
++	add	%rax,$hi0
++	mov	($np,$j,8),%rax
++	adc	\$0,%rdx
++	add	$hi0,$lo0		# ap[j]*bp[i]+tp[j]
++	mov	%rdx,$hi0
++	adc	\$0,$hi0
++	lea	1($j),$j		# j++
++
++	mulq	$m1			# np[j]*m1
++	cmp	$num,$j
++	jne	.Linner
++
++	add	%rax,$hi1
++	mov	($ap),%rax		# ap[0]
++	adc	\$0,%rdx
++	add	$lo0,$hi1		# np[j]*m1+ap[j]*bp[i]+tp[j]
++	mov	(%rsp,$j,8),$lo0
++	adc	\$0,%rdx
++	mov	$hi1,-16(%rsp,$j,8)	# tp[j-1]
++	mov	%rdx,$hi1
++
++	xor	%rdx,%rdx
++	add	$hi0,$hi1
++	adc	\$0,%rdx
++	add	$lo0,$hi1		# pull upmost overflow bit
++	adc	\$0,%rdx
++	mov	$hi1,-8(%rsp,$num,8)
++	mov	%rdx,(%rsp,$num,8)	# store upmost overflow bit
++
++	lea	1($i),$i		# i++
++	cmp	$num,$i
++	jb	.Louter
++
++	xor	$i,$i			# i=0 and clear CF!
++	mov	(%rsp),%rax		# tp[0]
++	lea	(%rsp),$ap		# borrow ap for tp
++	mov	$num,$j			# j=num
++	jmp	.Lsub
++.align	16
++.Lsub:	sbb	($np,$i,8),%rax
++	mov	%rax,($rp,$i,8)		# rp[i]=tp[i]-np[i]
++	mov	8($ap,$i,8),%rax	# tp[i+1]
++	lea	1($i),$i		# i++
++	dec	$j			# doesnn't affect CF!
++	jnz	.Lsub
++
++	sbb	\$0,%rax		# handle upmost overflow bit
++	xor	$i,$i
++	and	%rax,$ap
++	not	%rax
++	mov	$rp,$np
++	and	%rax,$np
++	mov	$num,$j			# j=num
++	or	$np,$ap			# ap=borrow?tp:rp
++.align	16
++.Lcopy:					# copy or in-place refresh
++	mov	($ap,$i,8),%rax
++	mov	$i,(%rsp,$i,8)		# zap temporary vector
++	mov	%rax,($rp,$i,8)		# rp[i]=tp[i]
++	lea	1($i),$i
++	sub	\$1,$j
++	jnz	.Lcopy
++
++	mov	8(%rsp,$num,8),%rsi	# restore %rsp
++	mov	\$1,%rax
++	mov	-48(%rsi),%r15
++	mov	-40(%rsi),%r14
++	mov	-32(%rsi),%r13
++	mov	-24(%rsi),%r12
++	mov	-16(%rsi),%rbp
++	mov	-8(%rsi),%rbx
++	lea	(%rsi),%rsp
++.Lmul_epilogue:
++	ret
++.size	bn_mul_mont,.-bn_mul_mont
++___
++{{{
++my @A=("%r10","%r11");
++my @N=("%r13","%rdi");
++$code.=<<___;
++.type	bn_mul4x_mont,\@function,6
++.align	16
++bn_mul4x_mont:
++	mov	${num}d,${num}d
++	mov	%rsp,%rax
++.Lmul4x_enter:
++___
++$code.=<<___ if ($addx);
++	and	\$0x80100,%r11d
++	cmp	\$0x80100,%r11d
++	je	.Lmulx4x_enter
++___
++$code.=<<___;
++	push	%rbx
++	push	%rbp
++	push	%r12
++	push	%r13
++	push	%r14
++	push	%r15
++
++	neg	$num
++	mov	%rsp,%r11
++	lea	-32(%rsp,$num,8),%r10	# future alloca(8*(num+4))
++	neg	$num			# restore
++	and	\$-1024,%r10		# minimize TLB usage
++
++	sub	%r10,%r11
++	and	\$-4096,%r11
++	lea	(%r10,%r11),%rsp
++	mov	(%rsp),%r11
++	cmp	%r10,%rsp
++	ja	.Lmul4x_page_walk
++	jmp	.Lmul4x_page_walk_done
++
++.Lmul4x_page_walk:
++	lea	-4096(%rsp),%rsp
++	mov	(%rsp),%r11
++	cmp	%r10,%rsp
++	ja	.Lmul4x_page_walk
++.Lmul4x_page_walk_done:
++
++	mov	%rax,8(%rsp,$num,8)	# tp[num+1]=%rsp
++.Lmul4x_body:
++	mov	$rp,16(%rsp,$num,8)	# tp[num+2]=$rp
++	mov	%rdx,%r12		# reassign $bp
++___
++		$bp="%r12";
++$code.=<<___;
++	mov	($n0),$n0		# pull n0[0] value
++	mov	($bp),$m0		# m0=bp[0]
++	mov	($ap),%rax
++
++	xor	$i,$i			# i=0
++	xor	$j,$j			# j=0
++
++	mov	$n0,$m1
++	mulq	$m0			# ap[0]*bp[0]
++	mov	%rax,$A[0]
++	mov	($np),%rax
++
++	imulq	$A[0],$m1		# "tp[0]"*n0
++	mov	%rdx,$A[1]
++
++	mulq	$m1			# np[0]*m1
++	add	%rax,$A[0]		# discarded
++	mov	8($ap),%rax
++	adc	\$0,%rdx
++	mov	%rdx,$N[1]
++
++	mulq	$m0
++	add	%rax,$A[1]
++	mov	8($np),%rax
++	adc	\$0,%rdx
++	mov	%rdx,$A[0]
++
++	mulq	$m1
++	add	%rax,$N[1]
++	mov	16($ap),%rax
++	adc	\$0,%rdx
++	add	$A[1],$N[1]
++	lea	4($j),$j		# j++
++	adc	\$0,%rdx
++	mov	$N[1],(%rsp)
++	mov	%rdx,$N[0]
++	jmp	.L1st4x
++.align	16
++.L1st4x:
++	mulq	$m0			# ap[j]*bp[0]
++	add	%rax,$A[0]
++	mov	-16($np,$j,8),%rax
++	adc	\$0,%rdx
++	mov	%rdx,$A[1]
++
++	mulq	$m1			# np[j]*m1
++	add	%rax,$N[0]
++	mov	-8($ap,$j,8),%rax
++	adc	\$0,%rdx
++	add	$A[0],$N[0]		# np[j]*m1+ap[j]*bp[0]
++	adc	\$0,%rdx
++	mov	$N[0],-24(%rsp,$j,8)	# tp[j-1]
++	mov	%rdx,$N[1]
++
++	mulq	$m0			# ap[j]*bp[0]
++	add	%rax,$A[1]
++	mov	-8($np,$j,8),%rax
++	adc	\$0,%rdx
++	mov	%rdx,$A[0]
++
++	mulq	$m1			# np[j]*m1
++	add	%rax,$N[1]
++	mov	($ap,$j,8),%rax
++	adc	\$0,%rdx
++	add	$A[1],$N[1]		# np[j]*m1+ap[j]*bp[0]
++	adc	\$0,%rdx
++	mov	$N[1],-16(%rsp,$j,8)	# tp[j-1]
++	mov	%rdx,$N[0]
++
++	mulq	$m0			# ap[j]*bp[0]
++	add	%rax,$A[0]
++	mov	($np,$j,8),%rax
++	adc	\$0,%rdx
++	mov	%rdx,$A[1]
++
++	mulq	$m1			# np[j]*m1
++	add	%rax,$N[0]
++	mov	8($ap,$j,8),%rax
++	adc	\$0,%rdx
++	add	$A[0],$N[0]		# np[j]*m1+ap[j]*bp[0]
++	adc	\$0,%rdx
++	mov	$N[0],-8(%rsp,$j,8)	# tp[j-1]
++	mov	%rdx,$N[1]
++
++	mulq	$m0			# ap[j]*bp[0]
++	add	%rax,$A[1]
++	mov	8($np,$j,8),%rax
++	adc	\$0,%rdx
++	lea	4($j),$j		# j++
++	mov	%rdx,$A[0]
++
++	mulq	$m1			# np[j]*m1
++	add	%rax,$N[1]
++	mov	-16($ap,$j,8),%rax
++	adc	\$0,%rdx
++	add	$A[1],$N[1]		# np[j]*m1+ap[j]*bp[0]
++	adc	\$0,%rdx
++	mov	$N[1],-32(%rsp,$j,8)	# tp[j-1]
++	mov	%rdx,$N[0]
++	cmp	$num,$j
++	jb	.L1st4x
++
++	mulq	$m0			# ap[j]*bp[0]
++	add	%rax,$A[0]
++	mov	-16($np,$j,8),%rax
++	adc	\$0,%rdx
++	mov	%rdx,$A[1]
++
++	mulq	$m1			# np[j]*m1
++	add	%rax,$N[0]
++	mov	-8($ap,$j,8),%rax
++	adc	\$0,%rdx
++	add	$A[0],$N[0]		# np[j]*m1+ap[j]*bp[0]
++	adc	\$0,%rdx
++	mov	$N[0],-24(%rsp,$j,8)	# tp[j-1]
++	mov	%rdx,$N[1]
++
++	mulq	$m0			# ap[j]*bp[0]
++	add	%rax,$A[1]
++	mov	-8($np,$j,8),%rax
++	adc	\$0,%rdx
++	mov	%rdx,$A[0]
++
++	mulq	$m1			# np[j]*m1
++	add	%rax,$N[1]
++	mov	($ap),%rax		# ap[0]
++	adc	\$0,%rdx
++	add	$A[1],$N[1]		# np[j]*m1+ap[j]*bp[0]
++	adc	\$0,%rdx
++	mov	$N[1],-16(%rsp,$j,8)	# tp[j-1]
++	mov	%rdx,$N[0]
++
++	xor	$N[1],$N[1]
++	add	$A[0],$N[0]
++	adc	\$0,$N[1]
++	mov	$N[0],-8(%rsp,$j,8)
++	mov	$N[1],(%rsp,$j,8)	# store upmost overflow bit
++
++	lea	1($i),$i		# i++
++.align	4
++.Louter4x:
++	mov	($bp,$i,8),$m0		# m0=bp[i]
++	xor	$j,$j			# j=0
++	mov	(%rsp),$A[0]
++	mov	$n0,$m1
++	mulq	$m0			# ap[0]*bp[i]
++	add	%rax,$A[0]		# ap[0]*bp[i]+tp[0]
++	mov	($np),%rax
++	adc	\$0,%rdx
++
++	imulq	$A[0],$m1		# tp[0]*n0
++	mov	%rdx,$A[1]
++
++	mulq	$m1			# np[0]*m1
++	add	%rax,$A[0]		# "$N[0]", discarded
++	mov	8($ap),%rax
++	adc	\$0,%rdx
++	mov	%rdx,$N[1]
++
++	mulq	$m0			# ap[j]*bp[i]
++	add	%rax,$A[1]
++	mov	8($np),%rax
++	adc	\$0,%rdx
++	add	8(%rsp),$A[1]		# +tp[1]
++	adc	\$0,%rdx
++	mov	%rdx,$A[0]
++
++	mulq	$m1			# np[j]*m1
++	add	%rax,$N[1]
++	mov	16($ap),%rax
++	adc	\$0,%rdx
++	add	$A[1],$N[1]		# np[j]*m1+ap[j]*bp[i]+tp[j]
++	lea	4($j),$j		# j+=2
++	adc	\$0,%rdx
++	mov	$N[1],(%rsp)		# tp[j-1]
++	mov	%rdx,$N[0]
++	jmp	.Linner4x
++.align	16
++.Linner4x:
++	mulq	$m0			# ap[j]*bp[i]
++	add	%rax,$A[0]
++	mov	-16($np,$j,8),%rax
++	adc	\$0,%rdx
++	add	-16(%rsp,$j,8),$A[0]	# ap[j]*bp[i]+tp[j]
++	adc	\$0,%rdx
++	mov	%rdx,$A[1]
++
++	mulq	$m1			# np[j]*m1
++	add	%rax,$N[0]
++	mov	-8($ap,$j,8),%rax
++	adc	\$0,%rdx
++	add	$A[0],$N[0]
++	adc	\$0,%rdx
++	mov	$N[0],-24(%rsp,$j,8)	# tp[j-1]
++	mov	%rdx,$N[1]
++
++	mulq	$m0			# ap[j]*bp[i]
++	add	%rax,$A[1]
++	mov	-8($np,$j,8),%rax
++	adc	\$0,%rdx
++	add	-8(%rsp,$j,8),$A[1]
++	adc	\$0,%rdx
++	mov	%rdx,$A[0]
++
++	mulq	$m1			# np[j]*m1
++	add	%rax,$N[1]
++	mov	($ap,$j,8),%rax
++	adc	\$0,%rdx
++	add	$A[1],$N[1]
++	adc	\$0,%rdx
++	mov	$N[1],-16(%rsp,$j,8)	# tp[j-1]
++	mov	%rdx,$N[0]
++
++	mulq	$m0			# ap[j]*bp[i]
++	add	%rax,$A[0]
++	mov	($np,$j,8),%rax
++	adc	\$0,%rdx
++	add	(%rsp,$j,8),$A[0]	# ap[j]*bp[i]+tp[j]
++	adc	\$0,%rdx
++	mov	%rdx,$A[1]
++
++	mulq	$m1			# np[j]*m1
++	add	%rax,$N[0]
++	mov	8($ap,$j,8),%rax
++	adc	\$0,%rdx
++	add	$A[0],$N[0]
++	adc	\$0,%rdx
++	mov	$N[0],-8(%rsp,$j,8)	# tp[j-1]
++	mov	%rdx,$N[1]
++
++	mulq	$m0			# ap[j]*bp[i]
++	add	%rax,$A[1]
++	mov	8($np,$j,8),%rax
++	adc	\$0,%rdx
++	add	8(%rsp,$j,8),$A[1]
++	adc	\$0,%rdx
++	lea	4($j),$j		# j++
++	mov	%rdx,$A[0]
++
++	mulq	$m1			# np[j]*m1
++	add	%rax,$N[1]
++	mov	-16($ap,$j,8),%rax
++	adc	\$0,%rdx
++	add	$A[1],$N[1]
++	adc	\$0,%rdx
++	mov	$N[1],-32(%rsp,$j,8)	# tp[j-1]
++	mov	%rdx,$N[0]
++	cmp	$num,$j
++	jb	.Linner4x
++
++	mulq	$m0			# ap[j]*bp[i]
++	add	%rax,$A[0]
++	mov	-16($np,$j,8),%rax
++	adc	\$0,%rdx
++	add	-16(%rsp,$j,8),$A[0]	# ap[j]*bp[i]+tp[j]
++	adc	\$0,%rdx
++	mov	%rdx,$A[1]
++
++	mulq	$m1			# np[j]*m1
++	add	%rax,$N[0]
++	mov	-8($ap,$j,8),%rax
++	adc	\$0,%rdx
++	add	$A[0],$N[0]
++	adc	\$0,%rdx
++	mov	$N[0],-24(%rsp,$j,8)	# tp[j-1]
++	mov	%rdx,$N[1]
++
++	mulq	$m0			# ap[j]*bp[i]
++	add	%rax,$A[1]
++	mov	-8($np,$j,8),%rax
++	adc	\$0,%rdx
++	add	-8(%rsp,$j,8),$A[1]
++	adc	\$0,%rdx
++	lea	1($i),$i		# i++
++	mov	%rdx,$A[0]
++
++	mulq	$m1			# np[j]*m1
++	add	%rax,$N[1]
++	mov	($ap),%rax		# ap[0]
++	adc	\$0,%rdx
++	add	$A[1],$N[1]
++	adc	\$0,%rdx
++	mov	$N[1],-16(%rsp,$j,8)	# tp[j-1]
++	mov	%rdx,$N[0]
++
++	xor	$N[1],$N[1]
++	add	$A[0],$N[0]
++	adc	\$0,$N[1]
++	add	(%rsp,$num,8),$N[0]	# pull upmost overflow bit
++	adc	\$0,$N[1]
++	mov	$N[0],-8(%rsp,$j,8)
++	mov	$N[1],(%rsp,$j,8)	# store upmost overflow bit
++
++	cmp	$num,$i
++	jb	.Louter4x
++___
++{
++my @ri=("%rax","%rdx",$m0,$m1);
++$code.=<<___;
++	mov	16(%rsp,$num,8),$rp	# restore $rp
++	mov	0(%rsp),@ri[0]		# tp[0]
++	pxor	%xmm0,%xmm0
++	mov	8(%rsp),@ri[1]		# tp[1]
++	shr	\$2,$num		# num/=4
++	lea	(%rsp),$ap		# borrow ap for tp
++	xor	$i,$i			# i=0 and clear CF!
++
++	sub	0($np),@ri[0]
++	mov	16($ap),@ri[2]		# tp[2]
++	mov	24($ap),@ri[3]		# tp[3]
++	sbb	8($np),@ri[1]
++	lea	-1($num),$j		# j=num/4-1
++	jmp	.Lsub4x
++.align	16
++.Lsub4x:
++	mov	@ri[0],0($rp,$i,8)	# rp[i]=tp[i]-np[i]
++	mov	@ri[1],8($rp,$i,8)	# rp[i]=tp[i]-np[i]
++	sbb	16($np,$i,8),@ri[2]
++	mov	32($ap,$i,8),@ri[0]	# tp[i+1]
++	mov	40($ap,$i,8),@ri[1]
++	sbb	24($np,$i,8),@ri[3]
++	mov	@ri[2],16($rp,$i,8)	# rp[i]=tp[i]-np[i]
++	mov	@ri[3],24($rp,$i,8)	# rp[i]=tp[i]-np[i]
++	sbb	32($np,$i,8),@ri[0]
++	mov	48($ap,$i,8),@ri[2]
++	mov	56($ap,$i,8),@ri[3]
++	sbb	40($np,$i,8),@ri[1]
++	lea	4($i),$i		# i++
++	dec	$j			# doesnn't affect CF!
++	jnz	.Lsub4x
++
++	mov	@ri[0],0($rp,$i,8)	# rp[i]=tp[i]-np[i]
++	mov	32($ap,$i,8),@ri[0]	# load overflow bit
++	sbb	16($np,$i,8),@ri[2]
++	mov	@ri[1],8($rp,$i,8)	# rp[i]=tp[i]-np[i]
++	sbb	24($np,$i,8),@ri[3]
++	mov	@ri[2],16($rp,$i,8)	# rp[i]=tp[i]-np[i]
++
++	sbb	\$0,@ri[0]		# handle upmost overflow bit
++	mov	@ri[3],24($rp,$i,8)	# rp[i]=tp[i]-np[i]
++	xor	$i,$i			# i=0
++	and	@ri[0],$ap
++	not	@ri[0]
++	mov	$rp,$np
++	and	@ri[0],$np
++	lea	-1($num),$j
++	or	$np,$ap			# ap=borrow?tp:rp
++
++	movdqu	($ap),%xmm1
++	movdqa	%xmm0,(%rsp)
++	movdqu	%xmm1,($rp)
++	jmp	.Lcopy4x
++.align	16
++.Lcopy4x:					# copy or in-place refresh
++	movdqu	16($ap,$i),%xmm2
++	movdqu	32($ap,$i),%xmm1
++	movdqa	%xmm0,16(%rsp,$i)
++	movdqu	%xmm2,16($rp,$i)
++	movdqa	%xmm0,32(%rsp,$i)
++	movdqu	%xmm1,32($rp,$i)
++	lea	32($i),$i
++	dec	$j
++	jnz	.Lcopy4x
++
++	shl	\$2,$num
++	movdqu	16($ap,$i),%xmm2
++	movdqa	%xmm0,16(%rsp,$i)
++	movdqu	%xmm2,16($rp,$i)
++___
++}
++$code.=<<___;
++	mov	8(%rsp,$num,8),%rsi	# restore %rsp
++	mov	\$1,%rax
++	mov	-48(%rsi),%r15
++	mov	-40(%rsi),%r14
++	mov	-32(%rsi),%r13
++	mov	-24(%rsi),%r12
++	mov	-16(%rsi),%rbp
++	mov	-8(%rsi),%rbx
++	lea	(%rsi),%rsp
++.Lmul4x_epilogue:
++	ret
++.size	bn_mul4x_mont,.-bn_mul4x_mont
++___
++}}}
++{{{
++######################################################################
++# void bn_sqr8x_mont(
++my $rptr="%rdi";	# const BN_ULONG *rptr,
++my $aptr="%rsi";	# const BN_ULONG *aptr,
++my $bptr="%rdx";	# not used
++my $nptr="%rcx";	# const BN_ULONG *nptr,
++my $n0  ="%r8";		# const BN_ULONG *n0);
++my $num ="%r9";		# int num, has to be divisible by 8
++
++my ($i,$j,$tptr)=("%rbp","%rcx",$rptr);
++my @A0=("%r10","%r11");
++my @A1=("%r12","%r13");
++my ($a0,$a1,$ai)=("%r14","%r15","%rbx");
++
++$code.=<<___	if ($addx);
++.extern	bn_sqrx8x_internal		# see x86_64-mont5 module
++___
++$code.=<<___;
++.extern	bn_sqr8x_internal		# see x86_64-mont5 module
++
++.type	bn_sqr8x_mont,\@function,6
++.align	32
++bn_sqr8x_mont:
++	mov	%rsp,%rax
++.Lsqr8x_enter:
++	push	%rbx
++	push	%rbp
++	push	%r12
++	push	%r13
++	push	%r14
++	push	%r15
++.Lsqr8x_prologue:
++
++	mov	${num}d,%r10d
++	shl	\$3,${num}d		# convert $num to bytes
++	shl	\$3+2,%r10		# 4*$num
++	neg	$num
++
++	##############################################################
++	# ensure that stack frame doesn't alias with $aptr modulo
++	# 4096. this is done to allow memory disambiguation logic
++	# do its job.
++	#
++	lea	-64(%rsp,$num,2),%r11
++	mov	%rsp,%rbp
++	mov	($n0),$n0		# *n0
++	sub	$aptr,%r11
++	and	\$4095,%r11
++	cmp	%r11,%r10
++	jb	.Lsqr8x_sp_alt
++	sub	%r11,%rbp		# align with $aptr
++	lea	-64(%rbp,$num,2),%rbp	# future alloca(frame+2*$num)
++	jmp	.Lsqr8x_sp_done
++
++.align	32
++.Lsqr8x_sp_alt:
++	lea	4096-64(,$num,2),%r10	# 4096-frame-2*$num
++	lea	-64(%rbp,$num,2),%rbp	# future alloca(frame+2*$num)
++	sub	%r10,%r11
++	mov	\$0,%r10
++	cmovc	%r10,%r11
++	sub	%r11,%rbp
++.Lsqr8x_sp_done:
++	and	\$-64,%rbp
++	mov	%rsp,%r11
++	sub	%rbp,%r11
++	and	\$-4096,%r11
++	lea	(%rbp,%r11),%rsp
++	mov	(%rsp),%r10
++	cmp	%rbp,%rsp
++	ja	.Lsqr8x_page_walk
++	jmp	.Lsqr8x_page_walk_done
++
++.align	16
++.Lsqr8x_page_walk:
++	lea	-4096(%rsp),%rsp
++	mov	(%rsp),%r10
++	cmp	%rbp,%rsp
++	ja	.Lsqr8x_page_walk
++.Lsqr8x_page_walk_done:
++
++	mov	$num,%r10
++	neg	$num
++
++	mov	$n0,  32(%rsp)
++	mov	%rax, 40(%rsp)		# save original %rsp
++.Lsqr8x_body:
++
++	movq	$nptr, %xmm2		# save pointer to modulus
++	pxor	%xmm0,%xmm0
++	movq	$rptr,%xmm1		# save $rptr
++	movq	%r10, %xmm3		# -$num
++___
++$code.=<<___ if ($addx);
++	mov	OPENSSL_ia32cap_P+8(%rip),%eax
++	and	\$0x80100,%eax
++	cmp	\$0x80100,%eax
++	jne	.Lsqr8x_nox
++
++	call	bn_sqrx8x_internal	# see x86_64-mont5 module
++					# %rax	top-most carry
++					# %rbp	nptr
++					# %rcx	-8*num
++					# %r8	end of tp[2*num]
++	lea	(%r8,%rcx),%rbx
++	mov	%rcx,$num
++	mov	%rcx,%rdx
++	movq	%xmm1,$rptr
++	sar	\$3+2,%rcx		# %cf=0
++	jmp	.Lsqr8x_sub
++
++.align	32
++.Lsqr8x_nox:
++___
++$code.=<<___;
++	call	bn_sqr8x_internal	# see x86_64-mont5 module
++					# %rax	top-most carry
++					# %rbp	nptr
++					# %r8	-8*num
++					# %rdi	end of tp[2*num]
++	lea	(%rdi,$num),%rbx
++	mov	$num,%rcx
++	mov	$num,%rdx
++	movq	%xmm1,$rptr
++	sar	\$3+2,%rcx		# %cf=0
++	jmp	.Lsqr8x_sub
++
++.align	32
++.Lsqr8x_sub:
++	mov	8*0(%rbx),%r12
++	mov	8*1(%rbx),%r13
++	mov	8*2(%rbx),%r14
++	mov	8*3(%rbx),%r15
++	lea	8*4(%rbx),%rbx
++	sbb	8*0(%rbp),%r12
++	sbb	8*1(%rbp),%r13
++	sbb	8*2(%rbp),%r14
++	sbb	8*3(%rbp),%r15
++	lea	8*4(%rbp),%rbp
++	mov	%r12,8*0($rptr)
++	mov	%r13,8*1($rptr)
++	mov	%r14,8*2($rptr)
++	mov	%r15,8*3($rptr)
++	lea	8*4($rptr),$rptr
++	inc	%rcx			# preserves %cf
++	jnz	.Lsqr8x_sub
++
++	sbb	\$0,%rax		# top-most carry
++	lea	(%rbx,$num),%rbx	# rewind
++	lea	($rptr,$num),$rptr	# rewind
++
++	movq	%rax,%xmm1
++	pxor	%xmm0,%xmm0
++	pshufd	\$0,%xmm1,%xmm1
++	mov	40(%rsp),%rsi		# restore %rsp
++	jmp	.Lsqr8x_cond_copy
++
++.align	32
++.Lsqr8x_cond_copy:
++	movdqa	16*0(%rbx),%xmm2
++	movdqa	16*1(%rbx),%xmm3
++	lea	16*2(%rbx),%rbx
++	movdqu	16*0($rptr),%xmm4
++	movdqu	16*1($rptr),%xmm5
++	lea	16*2($rptr),$rptr
++	movdqa	%xmm0,-16*2(%rbx)	# zero tp
++	movdqa	%xmm0,-16*1(%rbx)
++	movdqa	%xmm0,-16*2(%rbx,%rdx)
++	movdqa	%xmm0,-16*1(%rbx,%rdx)
++	pcmpeqd	%xmm1,%xmm0
++	pand	%xmm1,%xmm2
++	pand	%xmm1,%xmm3
++	pand	%xmm0,%xmm4
++	pand	%xmm0,%xmm5
++	pxor	%xmm0,%xmm0
++	por	%xmm2,%xmm4
++	por	%xmm3,%xmm5
++	movdqu	%xmm4,-16*2($rptr)
++	movdqu	%xmm5,-16*1($rptr)
++	add	\$32,$num
++	jnz	.Lsqr8x_cond_copy
++
++	mov	\$1,%rax
++	mov	-48(%rsi),%r15
++	mov	-40(%rsi),%r14
++	mov	-32(%rsi),%r13
++	mov	-24(%rsi),%r12
++	mov	-16(%rsi),%rbp
++	mov	-8(%rsi),%rbx
++	lea	(%rsi),%rsp
++.Lsqr8x_epilogue:
++	ret
++.size	bn_sqr8x_mont,.-bn_sqr8x_mont
++___
++}}}
++
++if ($addx) {{{
++my $bp="%rdx";	# original value
++
++$code.=<<___;
++.type	bn_mulx4x_mont,\@function,6
++.align	32
++bn_mulx4x_mont:
++	mov	%rsp,%rax
++.Lmulx4x_enter:
++	push	%rbx
++	push	%rbp
++	push	%r12
++	push	%r13
++	push	%r14
++	push	%r15
++.Lmulx4x_prologue:
++
++	shl	\$3,${num}d		# convert $num to bytes
++	xor	%r10,%r10
++	sub	$num,%r10		# -$num
++	mov	($n0),$n0		# *n0
++	lea	-72(%rsp,%r10),%rbp	# future alloca(frame+$num+8)
++	and	\$-128,%rbp
++	mov	%rsp,%r11
++	sub	%rbp,%r11
++	and	\$-4096,%r11
++	lea	(%rbp,%r11),%rsp
++	mov	(%rsp),%r10
++	cmp	%rbp,%rsp
++	ja	.Lmulx4x_page_walk
++	jmp	.Lmulx4x_page_walk_done
++
++.align	16
++.Lmulx4x_page_walk:
++	lea	-4096(%rsp),%rsp
++	mov	(%rsp),%r10
++	cmp	%rbp,%rsp
++	ja	.Lmulx4x_page_walk
++.Lmulx4x_page_walk_done:
++
++	lea	($bp,$num),%r10
++	##############################################################
++	# Stack layout
++	# +0	num
++	# +8	off-loaded &b[i]
++	# +16	end of b[num]
++	# +24	saved n0
++	# +32	saved rp
++	# +40	saved %rsp
++	# +48	inner counter
++	# +56
++	# +64	tmp[num+1]
++	#
++	mov	$num,0(%rsp)		# save $num
++	shr	\$5,$num
++	mov	%r10,16(%rsp)		# end of b[num]
++	sub	\$1,$num
++	mov	$n0, 24(%rsp)		# save *n0
++	mov	$rp, 32(%rsp)		# save $rp
++	mov	%rax,40(%rsp)		# save original %rsp
++	mov	$num,48(%rsp)		# inner counter
++	jmp	.Lmulx4x_body
++
++.align	32
++.Lmulx4x_body:
++___
++my ($aptr, $bptr, $nptr, $tptr, $mi,  $bi,  $zero, $num)=
++   ("%rsi","%rdi","%rcx","%rbx","%r8","%r9","%rbp","%rax");
++my $rptr=$bptr;
++$code.=<<___;
++	lea	8($bp),$bptr
++	mov	($bp),%rdx		# b[0], $bp==%rdx actually
++	lea	64+32(%rsp),$tptr
++	mov	%rdx,$bi
++
++	mulx	0*8($aptr),$mi,%rax	# a[0]*b[0]
++	mulx	1*8($aptr),%r11,%r14	# a[1]*b[0]
++	add	%rax,%r11
++	mov	$bptr,8(%rsp)		# off-load &b[i]
++	mulx	2*8($aptr),%r12,%r13	# ...
++	adc	%r14,%r12
++	adc	\$0,%r13
++
++	mov	$mi,$bptr		# borrow $bptr
++	imulq	24(%rsp),$mi		# "t[0]"*n0
++	xor	$zero,$zero		# cf=0, of=0
++
++	mulx	3*8($aptr),%rax,%r14
++	 mov	$mi,%rdx
++	lea	4*8($aptr),$aptr
++	adcx	%rax,%r13
++	adcx	$zero,%r14		# cf=0
++
++	mulx	0*8($nptr),%rax,%r10
++	adcx	%rax,$bptr		# discarded
++	adox	%r11,%r10
++	mulx	1*8($nptr),%rax,%r11
++	adcx	%rax,%r10
++	adox	%r12,%r11
++	.byte	0xc4,0x62,0xfb,0xf6,0xa1,0x10,0x00,0x00,0x00	# mulx	2*8($nptr),%rax,%r12
++	mov	48(%rsp),$bptr		# counter value
++	mov	%r10,-4*8($tptr)
++	adcx	%rax,%r11
++	adox	%r13,%r12
++	mulx	3*8($nptr),%rax,%r15
++	 mov	$bi,%rdx
++	mov	%r11,-3*8($tptr)
++	adcx	%rax,%r12
++	adox	$zero,%r15		# of=0
++	lea	4*8($nptr),$nptr
++	mov	%r12,-2*8($tptr)
++
++	jmp	.Lmulx4x_1st
++
++.align	32
++.Lmulx4x_1st:
++	adcx	$zero,%r15		# cf=0, modulo-scheduled
++	mulx	0*8($aptr),%r10,%rax	# a[4]*b[0]
++	adcx	%r14,%r10
++	mulx	1*8($aptr),%r11,%r14	# a[5]*b[0]
++	adcx	%rax,%r11
++	mulx	2*8($aptr),%r12,%rax	# ...
++	adcx	%r14,%r12
++	mulx	3*8($aptr),%r13,%r14
++	 .byte	0x67,0x67
++	 mov	$mi,%rdx
++	adcx	%rax,%r13
++	adcx	$zero,%r14		# cf=0
++	lea	4*8($aptr),$aptr
++	lea	4*8($tptr),$tptr
++
++	adox	%r15,%r10
++	mulx	0*8($nptr),%rax,%r15
++	adcx	%rax,%r10
++	adox	%r15,%r11
++	mulx	1*8($nptr),%rax,%r15
++	adcx	%rax,%r11
++	adox	%r15,%r12
++	mulx	2*8($nptr),%rax,%r15
++	mov	%r10,-5*8($tptr)
++	adcx	%rax,%r12
++	mov	%r11,-4*8($tptr)
++	adox	%r15,%r13
++	mulx	3*8($nptr),%rax,%r15
++	 mov	$bi,%rdx
++	mov	%r12,-3*8($tptr)
++	adcx	%rax,%r13
++	adox	$zero,%r15
++	lea	4*8($nptr),$nptr
++	mov	%r13,-2*8($tptr)
++
++	dec	$bptr			# of=0, pass cf
++	jnz	.Lmulx4x_1st
++
++	mov	0(%rsp),$num		# load num
++	mov	8(%rsp),$bptr		# re-load &b[i]
++	adc	$zero,%r15		# modulo-scheduled
++	add	%r15,%r14
++	sbb	%r15,%r15		# top-most carry
++	mov	%r14,-1*8($tptr)
++	jmp	.Lmulx4x_outer
++
++.align	32
++.Lmulx4x_outer:
++	mov	($bptr),%rdx		# b[i]
++	lea	8($bptr),$bptr		# b++
++	sub	$num,$aptr		# rewind $aptr
++	mov	%r15,($tptr)		# save top-most carry
++	lea	64+4*8(%rsp),$tptr
++	sub	$num,$nptr		# rewind $nptr
++
++	mulx	0*8($aptr),$mi,%r11	# a[0]*b[i]
++	xor	%ebp,%ebp		# xor	$zero,$zero	# cf=0, of=0
++	mov	%rdx,$bi
++	mulx	1*8($aptr),%r14,%r12	# a[1]*b[i]
++	adox	-4*8($tptr),$mi
++	adcx	%r14,%r11
++	mulx	2*8($aptr),%r15,%r13	# ...
++	adox	-3*8($tptr),%r11
++	adcx	%r15,%r12
++	adox	-2*8($tptr),%r12
++	adcx	$zero,%r13
++	adox	$zero,%r13
++
++	mov	$bptr,8(%rsp)		# off-load &b[i]
++	mov	$mi,%r15
++	imulq	24(%rsp),$mi		# "t[0]"*n0
++	xor	%ebp,%ebp		# xor	$zero,$zero	# cf=0, of=0
++
++	mulx	3*8($aptr),%rax,%r14
++	 mov	$mi,%rdx
++	adcx	%rax,%r13
++	adox	-1*8($tptr),%r13
++	adcx	$zero,%r14
++	lea	4*8($aptr),$aptr
++	adox	$zero,%r14
++
++	mulx	0*8($nptr),%rax,%r10
++	adcx	%rax,%r15		# discarded
++	adox	%r11,%r10
++	mulx	1*8($nptr),%rax,%r11
++	adcx	%rax,%r10
++	adox	%r12,%r11
++	mulx	2*8($nptr),%rax,%r12
++	mov	%r10,-4*8($tptr)
++	adcx	%rax,%r11
++	adox	%r13,%r12
++	mulx	3*8($nptr),%rax,%r15
++	 mov	$bi,%rdx
++	mov	%r11,-3*8($tptr)
++	lea	4*8($nptr),$nptr
++	adcx	%rax,%r12
++	adox	$zero,%r15		# of=0
++	mov	48(%rsp),$bptr		# counter value
++	mov	%r12,-2*8($tptr)
++
++	jmp	.Lmulx4x_inner
++
++.align	32
++.Lmulx4x_inner:
++	mulx	0*8($aptr),%r10,%rax	# a[4]*b[i]
++	adcx	$zero,%r15		# cf=0, modulo-scheduled
++	adox	%r14,%r10
++	mulx	1*8($aptr),%r11,%r14	# a[5]*b[i]
++	adcx	0*8($tptr),%r10
++	adox	%rax,%r11
++	mulx	2*8($aptr),%r12,%rax	# ...
++	adcx	1*8($tptr),%r11
++	adox	%r14,%r12
++	mulx	3*8($aptr),%r13,%r14
++	 mov	$mi,%rdx
++	adcx	2*8($tptr),%r12
++	adox	%rax,%r13
++	adcx	3*8($tptr),%r13
++	adox	$zero,%r14		# of=0
++	lea	4*8($aptr),$aptr
++	lea	4*8($tptr),$tptr
++	adcx	$zero,%r14		# cf=0
++
++	adox	%r15,%r10
++	mulx	0*8($nptr),%rax,%r15
++	adcx	%rax,%r10
++	adox	%r15,%r11
++	mulx	1*8($nptr),%rax,%r15
++	adcx	%rax,%r11
++	adox	%r15,%r12
++	mulx	2*8($nptr),%rax,%r15
++	mov	%r10,-5*8($tptr)
++	adcx	%rax,%r12
++	adox	%r15,%r13
++	mulx	3*8($nptr),%rax,%r15
++	 mov	$bi,%rdx
++	mov	%r11,-4*8($tptr)
++	mov	%r12,-3*8($tptr)
++	adcx	%rax,%r13
++	adox	$zero,%r15
++	lea	4*8($nptr),$nptr
++	mov	%r13,-2*8($tptr)
++
++	dec	$bptr			# of=0, pass cf
++	jnz	.Lmulx4x_inner
++
++	mov	0(%rsp),$num		# load num
++	mov	8(%rsp),$bptr		# re-load &b[i]
++	adc	$zero,%r15		# modulo-scheduled
++	sub	0*8($tptr),$zero	# pull top-most carry
++	adc	%r15,%r14
++	sbb	%r15,%r15		# top-most carry
++	mov	%r14,-1*8($tptr)
++
++	cmp	16(%rsp),$bptr
++	jne	.Lmulx4x_outer
++
++	lea	64(%rsp),$tptr
++	sub	$num,$nptr		# rewind $nptr
++	neg	%r15
++	mov	$num,%rdx
++	shr	\$3+2,$num		# %cf=0
++	mov	32(%rsp),$rptr		# restore rp
++	jmp	.Lmulx4x_sub
++
++.align	32
++.Lmulx4x_sub:
++	mov	8*0($tptr),%r11
++	mov	8*1($tptr),%r12
++	mov	8*2($tptr),%r13
++	mov	8*3($tptr),%r14
++	lea	8*4($tptr),$tptr
++	sbb	8*0($nptr),%r11
++	sbb	8*1($nptr),%r12
++	sbb	8*2($nptr),%r13
++	sbb	8*3($nptr),%r14
++	lea	8*4($nptr),$nptr
++	mov	%r11,8*0($rptr)
++	mov	%r12,8*1($rptr)
++	mov	%r13,8*2($rptr)
++	mov	%r14,8*3($rptr)
++	lea	8*4($rptr),$rptr
++	dec	$num			# preserves %cf
++	jnz	.Lmulx4x_sub
++
++	sbb	\$0,%r15		# top-most carry
++	lea	64(%rsp),$tptr
++	sub	%rdx,$rptr		# rewind
++
++	movq	%r15,%xmm1
++	pxor	%xmm0,%xmm0
++	pshufd	\$0,%xmm1,%xmm1
++	mov	40(%rsp),%rsi		# restore %rsp
++	jmp	.Lmulx4x_cond_copy
++
++.align	32
++.Lmulx4x_cond_copy:
++	movdqa	16*0($tptr),%xmm2
++	movdqa	16*1($tptr),%xmm3
++	lea	16*2($tptr),$tptr
++	movdqu	16*0($rptr),%xmm4
++	movdqu	16*1($rptr),%xmm5
++	lea	16*2($rptr),$rptr
++	movdqa	%xmm0,-16*2($tptr)	# zero tp
++	movdqa	%xmm0,-16*1($tptr)
++	pcmpeqd	%xmm1,%xmm0
++	pand	%xmm1,%xmm2
++	pand	%xmm1,%xmm3
++	pand	%xmm0,%xmm4
++	pand	%xmm0,%xmm5
++	pxor	%xmm0,%xmm0
++	por	%xmm2,%xmm4
++	por	%xmm3,%xmm5
++	movdqu	%xmm4,-16*2($rptr)
++	movdqu	%xmm5,-16*1($rptr)
++	sub	\$32,%rdx
++	jnz	.Lmulx4x_cond_copy
++
++	mov	%rdx,($tptr)
++
++	mov	\$1,%rax
++	mov	-48(%rsi),%r15
++	mov	-40(%rsi),%r14
++	mov	-32(%rsi),%r13
++	mov	-24(%rsi),%r12
++	mov	-16(%rsi),%rbp
++	mov	-8(%rsi),%rbx
++	lea	(%rsi),%rsp
++.Lmulx4x_epilogue:
++	ret
++.size	bn_mulx4x_mont,.-bn_mulx4x_mont
++___
++}}}
++$code.=<<___;
++.asciz	"Montgomery Multiplication for x86_64, CRYPTOGAMS by "
++.align	16
++___
++
++# EXCEPTION_DISPOSITION handler (EXCEPTION_RECORD *rec,ULONG64 frame,
++#		CONTEXT *context,DISPATCHER_CONTEXT *disp)
++if ($win64) {
++$rec="%rcx";
++$frame="%rdx";
++$context="%r8";
++$disp="%r9";
++
++$code.=<<___;
++.extern	__imp_RtlVirtualUnwind
++.type	mul_handler,\@abi-omnipotent
++.align	16
++mul_handler:
++	push	%rsi
++	push	%rdi
++	push	%rbx
++	push	%rbp
++	push	%r12
++	push	%r13
++	push	%r14
++	push	%r15
++	pushfq
++	sub	\$64,%rsp
++
++	mov	120($context),%rax	# pull context->Rax
++	mov	248($context),%rbx	# pull context->Rip
++
++	mov	8($disp),%rsi		# disp->ImageBase
++	mov	56($disp),%r11		# disp->HandlerData
++
++	mov	0(%r11),%r10d		# HandlerData[0]
++	lea	(%rsi,%r10),%r10	# end of prologue label
++	cmp	%r10,%rbx		# context->RipRsp
++
++	mov	4(%r11),%r10d		# HandlerData[1]
++	lea	(%rsi,%r10),%r10	# epilogue label
++	cmp	%r10,%rbx		# context->Rip>=epilogue label
++	jae	.Lcommon_seh_tail
++
++	mov	192($context),%r10	# pull $num
++	mov	8(%rax,%r10,8),%rax	# pull saved stack pointer
++
++	jmp	.Lcommon_pop_regs
++.size	mul_handler,.-mul_handler
++
++.type	sqr_handler,\@abi-omnipotent
++.align	16
++sqr_handler:
++	push	%rsi
++	push	%rdi
++	push	%rbx
++	push	%rbp
++	push	%r12
++	push	%r13
++	push	%r14
++	push	%r15
++	pushfq
++	sub	\$64,%rsp
++
++	mov	120($context),%rax	# pull context->Rax
++	mov	248($context),%rbx	# pull context->Rip
++
++	mov	8($disp),%rsi		# disp->ImageBase
++	mov	56($disp),%r11		# disp->HandlerData
++
++	mov	0(%r11),%r10d		# HandlerData[0]
++	lea	(%rsi,%r10),%r10	# end of prologue label
++	cmp	%r10,%rbx		# context->Rip<.Lsqr_body
++	jb	.Lcommon_seh_tail
++
++	mov	4(%r11),%r10d		# HandlerData[1]
++	lea	(%rsi,%r10),%r10	# body label
++	cmp	%r10,%rbx		# context->Rip>=.Lsqr_epilogue
++	jb	.Lcommon_pop_regs
++
++	mov	152($context),%rax	# pull context->Rsp
++
++	mov	8(%r11),%r10d		# HandlerData[2]
++	lea	(%rsi,%r10),%r10	# epilogue label
++	cmp	%r10,%rbx		# context->Rip>=.Lsqr_epilogue
++	jae	.Lcommon_seh_tail
++
++	mov	40(%rax),%rax		# pull saved stack pointer
++
++.Lcommon_pop_regs:
++	mov	-8(%rax),%rbx
++	mov	-16(%rax),%rbp
++	mov	-24(%rax),%r12
++	mov	-32(%rax),%r13
++	mov	-40(%rax),%r14
++	mov	-48(%rax),%r15
++	mov	%rbx,144($context)	# restore context->Rbx
++	mov	%rbp,160($context)	# restore context->Rbp
++	mov	%r12,216($context)	# restore context->R12
++	mov	%r13,224($context)	# restore context->R13
++	mov	%r14,232($context)	# restore context->R14
++	mov	%r15,240($context)	# restore context->R15
++
++.Lcommon_seh_tail:
++	mov	8(%rax),%rdi
++	mov	16(%rax),%rsi
++	mov	%rax,152($context)	# restore context->Rsp
++	mov	%rsi,168($context)	# restore context->Rsi
++	mov	%rdi,176($context)	# restore context->Rdi
++
++	mov	40($disp),%rdi		# disp->ContextRecord
++	mov	$context,%rsi		# context
++	mov	\$154,%ecx		# sizeof(CONTEXT)
++	.long	0xa548f3fc		# cld; rep movsq
++
++	mov	$disp,%rsi
++	xor	%rcx,%rcx		# arg1, UNW_FLAG_NHANDLER
++	mov	8(%rsi),%rdx		# arg2, disp->ImageBase
++	mov	0(%rsi),%r8		# arg3, disp->ControlPc
++	mov	16(%rsi),%r9		# arg4, disp->FunctionEntry
++	mov	40(%rsi),%r10		# disp->ContextRecord
++	lea	56(%rsi),%r11		# &disp->HandlerData
++	lea	24(%rsi),%r12		# &disp->EstablisherFrame
++	mov	%r10,32(%rsp)		# arg5
++	mov	%r11,40(%rsp)		# arg6
++	mov	%r12,48(%rsp)		# arg7
++	mov	%rcx,56(%rsp)		# arg8, (NULL)
++	call	*__imp_RtlVirtualUnwind(%rip)
++
++	mov	\$1,%eax		# ExceptionContinueSearch
++	add	\$64,%rsp
++	popfq
++	pop	%r15
++	pop	%r14
++	pop	%r13
++	pop	%r12
++	pop	%rbp
++	pop	%rbx
++	pop	%rdi
++	pop	%rsi
++	ret
++.size	sqr_handler,.-sqr_handler
++
++.section	.pdata
++.align	4
++	.rva	.LSEH_begin_bn_mul_mont
++	.rva	.LSEH_end_bn_mul_mont
++	.rva	.LSEH_info_bn_mul_mont
++
++	.rva	.LSEH_begin_bn_mul4x_mont
++	.rva	.LSEH_end_bn_mul4x_mont
++	.rva	.LSEH_info_bn_mul4x_mont
++
++	.rva	.LSEH_begin_bn_sqr8x_mont
++	.rva	.LSEH_end_bn_sqr8x_mont
++	.rva	.LSEH_info_bn_sqr8x_mont
++___
++$code.=<<___ if ($addx);
++	.rva	.LSEH_begin_bn_mulx4x_mont
++	.rva	.LSEH_end_bn_mulx4x_mont
++	.rva	.LSEH_info_bn_mulx4x_mont
++___
++$code.=<<___;
++.section	.xdata
++.align	8
++.LSEH_info_bn_mul_mont:
++	.byte	9,0,0,0
++	.rva	mul_handler
++	.rva	.Lmul_body,.Lmul_epilogue	# HandlerData[]
++.LSEH_info_bn_mul4x_mont:
++	.byte	9,0,0,0
++	.rva	mul_handler
++	.rva	.Lmul4x_body,.Lmul4x_epilogue	# HandlerData[]
++.LSEH_info_bn_sqr8x_mont:
++	.byte	9,0,0,0
++	.rva	sqr_handler
++	.rva	.Lsqr8x_prologue,.Lsqr8x_body,.Lsqr8x_epilogue		# HandlerData[]
++.align	8
++___
++$code.=<<___ if ($addx);
++.LSEH_info_bn_mulx4x_mont:
++	.byte	9,0,0,0
++	.rva	sqr_handler
++	.rva	.Lmulx4x_prologue,.Lmulx4x_body,.Lmulx4x_epilogue	# HandlerData[]
++.align	8
++___
++}
++
++print $code;
++close STDOUT;
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/bn/asm/x86_64-mont5.pl b/CryptoPkg/Library/OpensslLib/openssl/crypto/bn/asm/x86_64-mont5.pl
+new file mode 100755
+index 0000000..6807ab5
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/bn/asm/x86_64-mont5.pl
+@@ -0,0 +1,3827 @@
++#! /usr/bin/env perl
++# Copyright 2011-2016 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
++# in the file LICENSE in the source distribution or at
++# https://www.openssl.org/source/license.html
++
++
++# ====================================================================
++# Written by Andy Polyakov  for the OpenSSL
++# project. The module is, however, dual licensed under OpenSSL and
++# CRYPTOGAMS licenses depending on where you obtain it. For further
++# details see http://www.openssl.org/~appro/cryptogams/.
++# ====================================================================
++
++# August 2011.
++#
++# Companion to x86_64-mont.pl that optimizes cache-timing attack
++# countermeasures. The subroutines are produced by replacing bp[i]
++# references in their x86_64-mont.pl counterparts with cache-neutral
++# references to powers table computed in BN_mod_exp_mont_consttime.
++# In addition subroutine that scatters elements of the powers table
++# is implemented, so that scatter-/gathering can be tuned without
++# bn_exp.c modifications.
++
++# August 2013.
++#
++# Add MULX/AD*X code paths and additional interfaces to optimize for
++# branch prediction unit. For input lengths that are multiples of 8
++# the np argument is not just modulus value, but one interleaved
++# with 0. This is to optimize post-condition...
++
++$flavour = shift;
++$output  = shift;
++if ($flavour =~ /\./) { $output = $flavour; undef $flavour; }
++
++$win64=0; $win64=1 if ($flavour =~ /[nm]asm|mingw64/ || $output =~ /\.asm$/);
++
++$0 =~ m/(.*[\/\\])[^\/\\]+$/; $dir=$1;
++( $xlate="${dir}x86_64-xlate.pl" and -f $xlate ) or
++( $xlate="${dir}../../perlasm/x86_64-xlate.pl" and -f $xlate) or
++die "can't locate x86_64-xlate.pl";
++
++open OUT,"| \"$^X\" \"$xlate\" $flavour \"$output\"";
++*STDOUT=*OUT;
++
++if (`$ENV{CC} -Wa,-v -c -o /dev/null -x assembler /dev/null 2>&1`
++		=~ /GNU assembler version ([2-9]\.[0-9]+)/) {
++	$addx = ($1>=2.23);
++}
++
++if (!$addx && $win64 && ($flavour =~ /nasm/ || $ENV{ASM} =~ /nasm/) &&
++	    `nasm -v 2>&1` =~ /NASM version ([2-9]\.[0-9]+)/) {
++	$addx = ($1>=2.10);
++}
++
++if (!$addx && $win64 && ($flavour =~ /masm/ || $ENV{ASM} =~ /ml64/) &&
++	    `ml64 2>&1` =~ /Version ([0-9]+)\./) {
++	$addx = ($1>=12);
++}
++
++if (!$addx && `$ENV{CC} -v 2>&1` =~ /((?:^clang|LLVM) version|.*based on LLVM) ([3-9])\.([0-9]+)/) {
++	my $ver = $2 + $3/100.0;	# 3.1->3.01, 3.10->3.10
++	$addx = ($ver>=3.03);
++}
++
++# int bn_mul_mont_gather5(
++$rp="%rdi";	# BN_ULONG *rp,
++$ap="%rsi";	# const BN_ULONG *ap,
++$bp="%rdx";	# const BN_ULONG *bp,
++$np="%rcx";	# const BN_ULONG *np,
++$n0="%r8";	# const BN_ULONG *n0,
++$num="%r9";	# int num,
++		# int idx);	# 0 to 2^5-1, "index" in $bp holding
++				# pre-computed powers of a', interlaced
++				# in such manner that b[0] is $bp[idx],
++				# b[1] is [2^5+idx], etc.
++$lo0="%r10";
++$hi0="%r11";
++$hi1="%r13";
++$i="%r14";
++$j="%r15";
++$m0="%rbx";
++$m1="%rbp";
++
++$code=<<___;
++.text
++
++.extern	OPENSSL_ia32cap_P
++
++.globl	bn_mul_mont_gather5
++.type	bn_mul_mont_gather5,\@function,6
++.align	64
++bn_mul_mont_gather5:
++	mov	${num}d,${num}d
++	mov	%rsp,%rax
++	test	\$7,${num}d
++	jnz	.Lmul_enter
++___
++$code.=<<___ if ($addx);
++	mov	OPENSSL_ia32cap_P+8(%rip),%r11d
++___
++$code.=<<___;
++	jmp	.Lmul4x_enter
++
++.align	16
++.Lmul_enter:
++	movd	`($win64?56:8)`(%rsp),%xmm5	# load 7th argument
++	push	%rbx
++	push	%rbp
++	push	%r12
++	push	%r13
++	push	%r14
++	push	%r15
++
++	neg	$num
++	mov	%rsp,%r11
++	lea	-280(%rsp,$num,8),%r10	# future alloca(8*(num+2)+256+8)
++	neg	$num			# restore $num
++	and	\$-1024,%r10		# minimize TLB usage
++
++	# An OS-agnostic version of __chkstk.
++	#
++	# Some OSes (Windows) insist on stack being "wired" to
++	# physical memory in strictly sequential manner, i.e. if stack
++	# allocation spans two pages, then reference to farmost one can
++	# be punishable by SEGV. But page walking can do good even on
++	# other OSes, because it guarantees that villain thread hits
++	# the guard page before it can make damage to innocent one...
++	sub	%r10,%r11
++	and	\$-4096,%r11
++	lea	(%r10,%r11),%rsp
++	mov	(%rsp),%r11
++	cmp	%r10,%rsp
++	ja	.Lmul_page_walk
++	jmp	.Lmul_page_walk_done
++
++.Lmul_page_walk:
++	lea	-4096(%rsp),%rsp
++	mov	(%rsp),%r11
++	cmp	%r10,%rsp
++	ja	.Lmul_page_walk
++.Lmul_page_walk_done:
++
++	lea	.Linc(%rip),%r10
++	mov	%rax,8(%rsp,$num,8)	# tp[num+1]=%rsp
++.Lmul_body:
++
++	lea	128($bp),%r12		# reassign $bp (+size optimization)
++___
++		$bp="%r12";
++		$STRIDE=2**5*8;		# 5 is "window size"
++		$N=$STRIDE/4;		# should match cache line size
++$code.=<<___;
++	movdqa	0(%r10),%xmm0		# 00000001000000010000000000000000
++	movdqa	16(%r10),%xmm1		# 00000002000000020000000200000002
++	lea	24-112(%rsp,$num,8),%r10# place the mask after tp[num+3] (+ICache optimization)
++	and	\$-16,%r10
++
++	pshufd	\$0,%xmm5,%xmm5		# broadcast index
++	movdqa	%xmm1,%xmm4
++	movdqa	%xmm1,%xmm2
++___
++########################################################################
++# calculate mask by comparing 0..31 to index and save result to stack
++#
++$code.=<<___;
++	paddd	%xmm0,%xmm1
++	pcmpeqd	%xmm5,%xmm0		# compare to 1,0
++	.byte	0x67
++	movdqa	%xmm4,%xmm3
++___
++for($k=0;$k<$STRIDE/16-4;$k+=4) {
++$code.=<<___;
++	paddd	%xmm1,%xmm2
++	pcmpeqd	%xmm5,%xmm1		# compare to 3,2
++	movdqa	%xmm0,`16*($k+0)+112`(%r10)
++	movdqa	%xmm4,%xmm0
++
++	paddd	%xmm2,%xmm3
++	pcmpeqd	%xmm5,%xmm2		# compare to 5,4
++	movdqa	%xmm1,`16*($k+1)+112`(%r10)
++	movdqa	%xmm4,%xmm1
++
++	paddd	%xmm3,%xmm0
++	pcmpeqd	%xmm5,%xmm3		# compare to 7,6
++	movdqa	%xmm2,`16*($k+2)+112`(%r10)
++	movdqa	%xmm4,%xmm2
++
++	paddd	%xmm0,%xmm1
++	pcmpeqd	%xmm5,%xmm0
++	movdqa	%xmm3,`16*($k+3)+112`(%r10)
++	movdqa	%xmm4,%xmm3
++___
++}
++$code.=<<___;				# last iteration can be optimized
++	paddd	%xmm1,%xmm2
++	pcmpeqd	%xmm5,%xmm1
++	movdqa	%xmm0,`16*($k+0)+112`(%r10)
++
++	paddd	%xmm2,%xmm3
++	.byte	0x67
++	pcmpeqd	%xmm5,%xmm2
++	movdqa	%xmm1,`16*($k+1)+112`(%r10)
++
++	pcmpeqd	%xmm5,%xmm3
++	movdqa	%xmm2,`16*($k+2)+112`(%r10)
++	pand	`16*($k+0)-128`($bp),%xmm0	# while it's still in register
++
++	pand	`16*($k+1)-128`($bp),%xmm1
++	pand	`16*($k+2)-128`($bp),%xmm2
++	movdqa	%xmm3,`16*($k+3)+112`(%r10)
++	pand	`16*($k+3)-128`($bp),%xmm3
++	por	%xmm2,%xmm0
++	por	%xmm3,%xmm1
++___
++for($k=0;$k<$STRIDE/16-4;$k+=4) {
++$code.=<<___;
++	movdqa	`16*($k+0)-128`($bp),%xmm4
++	movdqa	`16*($k+1)-128`($bp),%xmm5
++	movdqa	`16*($k+2)-128`($bp),%xmm2
++	pand	`16*($k+0)+112`(%r10),%xmm4
++	movdqa	`16*($k+3)-128`($bp),%xmm3
++	pand	`16*($k+1)+112`(%r10),%xmm5
++	por	%xmm4,%xmm0
++	pand	`16*($k+2)+112`(%r10),%xmm2
++	por	%xmm5,%xmm1
++	pand	`16*($k+3)+112`(%r10),%xmm3
++	por	%xmm2,%xmm0
++	por	%xmm3,%xmm1
++___
++}
++$code.=<<___;
++	por	%xmm1,%xmm0
++	pshufd	\$0x4e,%xmm0,%xmm1
++	por	%xmm1,%xmm0
++	lea	$STRIDE($bp),$bp
++	movq	%xmm0,$m0		# m0=bp[0]
++
++	mov	($n0),$n0		# pull n0[0] value
++	mov	($ap),%rax
++
++	xor	$i,$i			# i=0
++	xor	$j,$j			# j=0
++
++	mov	$n0,$m1
++	mulq	$m0			# ap[0]*bp[0]
++	mov	%rax,$lo0
++	mov	($np),%rax
++
++	imulq	$lo0,$m1		# "tp[0]"*n0
++	mov	%rdx,$hi0
++
++	mulq	$m1			# np[0]*m1
++	add	%rax,$lo0		# discarded
++	mov	8($ap),%rax
++	adc	\$0,%rdx
++	mov	%rdx,$hi1
++
++	lea	1($j),$j		# j++
++	jmp	.L1st_enter
++
++.align	16
++.L1st:
++	add	%rax,$hi1
++	mov	($ap,$j,8),%rax
++	adc	\$0,%rdx
++	add	$hi0,$hi1		# np[j]*m1+ap[j]*bp[0]
++	mov	$lo0,$hi0
++	adc	\$0,%rdx
++	mov	$hi1,-16(%rsp,$j,8)	# tp[j-1]
++	mov	%rdx,$hi1
++
++.L1st_enter:
++	mulq	$m0			# ap[j]*bp[0]
++	add	%rax,$hi0
++	mov	($np,$j,8),%rax
++	adc	\$0,%rdx
++	lea	1($j),$j		# j++
++	mov	%rdx,$lo0
++
++	mulq	$m1			# np[j]*m1
++	cmp	$num,$j
++	jne	.L1st			# note that upon exit $j==$num, so
++					# they can be used interchangeably
++
++	add	%rax,$hi1
++	adc	\$0,%rdx
++	add	$hi0,$hi1		# np[j]*m1+ap[j]*bp[0]
++	adc	\$0,%rdx
++	mov	$hi1,-16(%rsp,$num,8)	# tp[num-1]
++	mov	%rdx,$hi1
++	mov	$lo0,$hi0
++
++	xor	%rdx,%rdx
++	add	$hi0,$hi1
++	adc	\$0,%rdx
++	mov	$hi1,-8(%rsp,$num,8)
++	mov	%rdx,(%rsp,$num,8)	# store upmost overflow bit
++
++	lea	1($i),$i		# i++
++	jmp	.Louter
++.align	16
++.Louter:
++	lea	24+128(%rsp,$num,8),%rdx	# where 256-byte mask is (+size optimization)
++	and	\$-16,%rdx
++	pxor	%xmm4,%xmm4
++	pxor	%xmm5,%xmm5
++___
++for($k=0;$k<$STRIDE/16;$k+=4) {
++$code.=<<___;
++	movdqa	`16*($k+0)-128`($bp),%xmm0
++	movdqa	`16*($k+1)-128`($bp),%xmm1
++	movdqa	`16*($k+2)-128`($bp),%xmm2
++	movdqa	`16*($k+3)-128`($bp),%xmm3
++	pand	`16*($k+0)-128`(%rdx),%xmm0
++	pand	`16*($k+1)-128`(%rdx),%xmm1
++	por	%xmm0,%xmm4
++	pand	`16*($k+2)-128`(%rdx),%xmm2
++	por	%xmm1,%xmm5
++	pand	`16*($k+3)-128`(%rdx),%xmm3
++	por	%xmm2,%xmm4
++	por	%xmm3,%xmm5
++___
++}
++$code.=<<___;
++	por	%xmm5,%xmm4
++	pshufd	\$0x4e,%xmm4,%xmm0
++	por	%xmm4,%xmm0
++	lea	$STRIDE($bp),$bp
++
++	mov	($ap),%rax		# ap[0]
++	movq	%xmm0,$m0		# m0=bp[i]
++
++	xor	$j,$j			# j=0
++	mov	$n0,$m1
++	mov	(%rsp),$lo0
++
++	mulq	$m0			# ap[0]*bp[i]
++	add	%rax,$lo0		# ap[0]*bp[i]+tp[0]
++	mov	($np),%rax
++	adc	\$0,%rdx
++
++	imulq	$lo0,$m1		# tp[0]*n0
++	mov	%rdx,$hi0
++
++	mulq	$m1			# np[0]*m1
++	add	%rax,$lo0		# discarded
++	mov	8($ap),%rax
++	adc	\$0,%rdx
++	mov	8(%rsp),$lo0		# tp[1]
++	mov	%rdx,$hi1
++
++	lea	1($j),$j		# j++
++	jmp	.Linner_enter
++
++.align	16
++.Linner:
++	add	%rax,$hi1
++	mov	($ap,$j,8),%rax
++	adc	\$0,%rdx
++	add	$lo0,$hi1		# np[j]*m1+ap[j]*bp[i]+tp[j]
++	mov	(%rsp,$j,8),$lo0
++	adc	\$0,%rdx
++	mov	$hi1,-16(%rsp,$j,8)	# tp[j-1]
++	mov	%rdx,$hi1
++
++.Linner_enter:
++	mulq	$m0			# ap[j]*bp[i]
++	add	%rax,$hi0
++	mov	($np,$j,8),%rax
++	adc	\$0,%rdx
++	add	$hi0,$lo0		# ap[j]*bp[i]+tp[j]
++	mov	%rdx,$hi0
++	adc	\$0,$hi0
++	lea	1($j),$j		# j++
++
++	mulq	$m1			# np[j]*m1
++	cmp	$num,$j
++	jne	.Linner			# note that upon exit $j==$num, so
++					# they can be used interchangeably
++	add	%rax,$hi1
++	adc	\$0,%rdx
++	add	$lo0,$hi1		# np[j]*m1+ap[j]*bp[i]+tp[j]
++	mov	(%rsp,$num,8),$lo0
++	adc	\$0,%rdx
++	mov	$hi1,-16(%rsp,$num,8)	# tp[num-1]
++	mov	%rdx,$hi1
++
++	xor	%rdx,%rdx
++	add	$hi0,$hi1
++	adc	\$0,%rdx
++	add	$lo0,$hi1		# pull upmost overflow bit
++	adc	\$0,%rdx
++	mov	$hi1,-8(%rsp,$num,8)
++	mov	%rdx,(%rsp,$num,8)	# store upmost overflow bit
++
++	lea	1($i),$i		# i++
++	cmp	$num,$i
++	jb	.Louter
++
++	xor	$i,$i			# i=0 and clear CF!
++	mov	(%rsp),%rax		# tp[0]
++	lea	(%rsp),$ap		# borrow ap for tp
++	mov	$num,$j			# j=num
++	jmp	.Lsub
++.align	16
++.Lsub:	sbb	($np,$i,8),%rax
++	mov	%rax,($rp,$i,8)		# rp[i]=tp[i]-np[i]
++	mov	8($ap,$i,8),%rax	# tp[i+1]
++	lea	1($i),$i		# i++
++	dec	$j			# doesnn't affect CF!
++	jnz	.Lsub
++
++	sbb	\$0,%rax		# handle upmost overflow bit
++	xor	$i,$i
++	and	%rax,$ap
++	not	%rax
++	mov	$rp,$np
++	and	%rax,$np
++	mov	$num,$j			# j=num
++	or	$np,$ap			# ap=borrow?tp:rp
++.align	16
++.Lcopy:					# copy or in-place refresh
++	mov	($ap,$i,8),%rax
++	mov	$i,(%rsp,$i,8)		# zap temporary vector
++	mov	%rax,($rp,$i,8)		# rp[i]=tp[i]
++	lea	1($i),$i
++	sub	\$1,$j
++	jnz	.Lcopy
++
++	mov	8(%rsp,$num,8),%rsi	# restore %rsp
++	mov	\$1,%rax
++
++	mov	-48(%rsi),%r15
++	mov	-40(%rsi),%r14
++	mov	-32(%rsi),%r13
++	mov	-24(%rsi),%r12
++	mov	-16(%rsi),%rbp
++	mov	-8(%rsi),%rbx
++	lea	(%rsi),%rsp
++.Lmul_epilogue:
++	ret
++.size	bn_mul_mont_gather5,.-bn_mul_mont_gather5
++___
++{{{
++my @A=("%r10","%r11");
++my @N=("%r13","%rdi");
++$code.=<<___;
++.type	bn_mul4x_mont_gather5,\@function,6
++.align	32
++bn_mul4x_mont_gather5:
++	.byte	0x67
++	mov	%rsp,%rax
++.Lmul4x_enter:
++___
++$code.=<<___ if ($addx);
++	and	\$0x80108,%r11d
++	cmp	\$0x80108,%r11d		# check for AD*X+BMI2+BMI1
++	je	.Lmulx4x_enter
++___
++$code.=<<___;
++	push	%rbx
++	push	%rbp
++	push	%r12
++	push	%r13
++	push	%r14
++	push	%r15
++.Lmul4x_prologue:
++
++	.byte	0x67
++	shl	\$3,${num}d		# convert $num to bytes
++	lea	($num,$num,2),%r10	# 3*$num in bytes
++	neg	$num			# -$num
++
++	##############################################################
++	# Ensure that stack frame doesn't alias with $rptr+3*$num
++	# modulo 4096, which covers ret[num], am[num] and n[num]
++	# (see bn_exp.c). This is done to allow memory disambiguation
++	# logic do its magic. [Extra [num] is allocated in order
++	# to align with bn_power5's frame, which is cleansed after
++	# completing exponentiation. Extra 256 bytes is for power mask
++	# calculated from 7th argument, the index.]
++	#
++	lea	-320(%rsp,$num,2),%r11
++	mov	%rsp,%rbp
++	sub	$rp,%r11
++	and	\$4095,%r11
++	cmp	%r11,%r10
++	jb	.Lmul4xsp_alt
++	sub	%r11,%rbp		# align with $rp
++	lea	-320(%rbp,$num,2),%rbp	# future alloca(frame+2*num*8+256)
++	jmp	.Lmul4xsp_done
++
++.align	32
++.Lmul4xsp_alt:
++	lea	4096-320(,$num,2),%r10
++	lea	-320(%rbp,$num,2),%rbp	# future alloca(frame+2*num*8+256)
++	sub	%r10,%r11
++	mov	\$0,%r10
++	cmovc	%r10,%r11
++	sub	%r11,%rbp
++.Lmul4xsp_done:
++	and	\$-64,%rbp
++	mov	%rsp,%r11
++	sub	%rbp,%r11
++	and	\$-4096,%r11
++	lea	(%rbp,%r11),%rsp
++	mov	(%rsp),%r10
++	cmp	%rbp,%rsp
++	ja	.Lmul4x_page_walk
++	jmp	.Lmul4x_page_walk_done
++
++.Lmul4x_page_walk:
++	lea	-4096(%rsp),%rsp
++	mov	(%rsp),%r10
++	cmp	%rbp,%rsp
++	ja	.Lmul4x_page_walk
++.Lmul4x_page_walk_done:
++
++	neg	$num
++
++	mov	%rax,40(%rsp)
++.Lmul4x_body:
++
++	call	mul4x_internal
++
++	mov	40(%rsp),%rsi		# restore %rsp
++	mov	\$1,%rax
++
++	mov	-48(%rsi),%r15
++	mov	-40(%rsi),%r14
++	mov	-32(%rsi),%r13
++	mov	-24(%rsi),%r12
++	mov	-16(%rsi),%rbp
++	mov	-8(%rsi),%rbx
++	lea	(%rsi),%rsp
++.Lmul4x_epilogue:
++	ret
++.size	bn_mul4x_mont_gather5,.-bn_mul4x_mont_gather5
++
++.type	mul4x_internal,\@abi-omnipotent
++.align	32
++mul4x_internal:
++	shl	\$5,$num		# $num was in bytes
++	movd	`($win64?56:8)`(%rax),%xmm5	# load 7th argument, index
++	lea	.Linc(%rip),%rax
++	lea	128(%rdx,$num),%r13	# end of powers table (+size optimization)
++	shr	\$5,$num		# restore $num
++___
++		$bp="%r12";
++		$STRIDE=2**5*8;		# 5 is "window size"
++		$N=$STRIDE/4;		# should match cache line size
++		$tp=$i;
++$code.=<<___;
++	movdqa	0(%rax),%xmm0		# 00000001000000010000000000000000
++	movdqa	16(%rax),%xmm1		# 00000002000000020000000200000002
++	lea	88-112(%rsp,$num),%r10	# place the mask after tp[num+1] (+ICache optimization)
++	lea	128(%rdx),$bp		# size optimization
++
++	pshufd	\$0,%xmm5,%xmm5		# broadcast index
++	movdqa	%xmm1,%xmm4
++	.byte	0x67,0x67
++	movdqa	%xmm1,%xmm2
++___
++########################################################################
++# calculate mask by comparing 0..31 to index and save result to stack
++#
++$code.=<<___;
++	paddd	%xmm0,%xmm1
++	pcmpeqd	%xmm5,%xmm0		# compare to 1,0
++	.byte	0x67
++	movdqa	%xmm4,%xmm3
++___
++for($i=0;$i<$STRIDE/16-4;$i+=4) {
++$code.=<<___;
++	paddd	%xmm1,%xmm2
++	pcmpeqd	%xmm5,%xmm1		# compare to 3,2
++	movdqa	%xmm0,`16*($i+0)+112`(%r10)
++	movdqa	%xmm4,%xmm0
++
++	paddd	%xmm2,%xmm3
++	pcmpeqd	%xmm5,%xmm2		# compare to 5,4
++	movdqa	%xmm1,`16*($i+1)+112`(%r10)
++	movdqa	%xmm4,%xmm1
++
++	paddd	%xmm3,%xmm0
++	pcmpeqd	%xmm5,%xmm3		# compare to 7,6
++	movdqa	%xmm2,`16*($i+2)+112`(%r10)
++	movdqa	%xmm4,%xmm2
++
++	paddd	%xmm0,%xmm1
++	pcmpeqd	%xmm5,%xmm0
++	movdqa	%xmm3,`16*($i+3)+112`(%r10)
++	movdqa	%xmm4,%xmm3
++___
++}
++$code.=<<___;				# last iteration can be optimized
++	paddd	%xmm1,%xmm2
++	pcmpeqd	%xmm5,%xmm1
++	movdqa	%xmm0,`16*($i+0)+112`(%r10)
++
++	paddd	%xmm2,%xmm3
++	.byte	0x67
++	pcmpeqd	%xmm5,%xmm2
++	movdqa	%xmm1,`16*($i+1)+112`(%r10)
++
++	pcmpeqd	%xmm5,%xmm3
++	movdqa	%xmm2,`16*($i+2)+112`(%r10)
++	pand	`16*($i+0)-128`($bp),%xmm0	# while it's still in register
++
++	pand	`16*($i+1)-128`($bp),%xmm1
++	pand	`16*($i+2)-128`($bp),%xmm2
++	movdqa	%xmm3,`16*($i+3)+112`(%r10)
++	pand	`16*($i+3)-128`($bp),%xmm3
++	por	%xmm2,%xmm0
++	por	%xmm3,%xmm1
++___
++for($i=0;$i<$STRIDE/16-4;$i+=4) {
++$code.=<<___;
++	movdqa	`16*($i+0)-128`($bp),%xmm4
++	movdqa	`16*($i+1)-128`($bp),%xmm5
++	movdqa	`16*($i+2)-128`($bp),%xmm2
++	pand	`16*($i+0)+112`(%r10),%xmm4
++	movdqa	`16*($i+3)-128`($bp),%xmm3
++	pand	`16*($i+1)+112`(%r10),%xmm5
++	por	%xmm4,%xmm0
++	pand	`16*($i+2)+112`(%r10),%xmm2
++	por	%xmm5,%xmm1
++	pand	`16*($i+3)+112`(%r10),%xmm3
++	por	%xmm2,%xmm0
++	por	%xmm3,%xmm1
++___
++}
++$code.=<<___;
++	por	%xmm1,%xmm0
++	pshufd	\$0x4e,%xmm0,%xmm1
++	por	%xmm1,%xmm0
++	lea	$STRIDE($bp),$bp
++	movq	%xmm0,$m0		# m0=bp[0]
++
++	mov	%r13,16+8(%rsp)		# save end of b[num]
++	mov	$rp, 56+8(%rsp)		# save $rp
++
++	mov	($n0),$n0		# pull n0[0] value
++	mov	($ap),%rax
++	lea	($ap,$num),$ap		# end of a[num]
++	neg	$num
++
++	mov	$n0,$m1
++	mulq	$m0			# ap[0]*bp[0]
++	mov	%rax,$A[0]
++	mov	($np),%rax
++
++	imulq	$A[0],$m1		# "tp[0]"*n0
++	lea	64+8(%rsp),$tp
++	mov	%rdx,$A[1]
++
++	mulq	$m1			# np[0]*m1
++	add	%rax,$A[0]		# discarded
++	mov	8($ap,$num),%rax
++	adc	\$0,%rdx
++	mov	%rdx,$N[1]
++
++	mulq	$m0
++	add	%rax,$A[1]
++	mov	8*1($np),%rax
++	adc	\$0,%rdx
++	mov	%rdx,$A[0]
++
++	mulq	$m1
++	add	%rax,$N[1]
++	mov	16($ap,$num),%rax
++	adc	\$0,%rdx
++	add	$A[1],$N[1]
++	lea	4*8($num),$j		# j=4
++	lea	8*4($np),$np
++	adc	\$0,%rdx
++	mov	$N[1],($tp)
++	mov	%rdx,$N[0]
++	jmp	.L1st4x
++
++.align	32
++.L1st4x:
++	mulq	$m0			# ap[j]*bp[0]
++	add	%rax,$A[0]
++	mov	-8*2($np),%rax
++	lea	32($tp),$tp
++	adc	\$0,%rdx
++	mov	%rdx,$A[1]
++
++	mulq	$m1			# np[j]*m1
++	add	%rax,$N[0]
++	mov	-8($ap,$j),%rax
++	adc	\$0,%rdx
++	add	$A[0],$N[0]		# np[j]*m1+ap[j]*bp[0]
++	adc	\$0,%rdx
++	mov	$N[0],-24($tp)		# tp[j-1]
++	mov	%rdx,$N[1]
++
++	mulq	$m0			# ap[j]*bp[0]
++	add	%rax,$A[1]
++	mov	-8*1($np),%rax
++	adc	\$0,%rdx
++	mov	%rdx,$A[0]
++
++	mulq	$m1			# np[j]*m1
++	add	%rax,$N[1]
++	mov	($ap,$j),%rax
++	adc	\$0,%rdx
++	add	$A[1],$N[1]		# np[j]*m1+ap[j]*bp[0]
++	adc	\$0,%rdx
++	mov	$N[1],-16($tp)		# tp[j-1]
++	mov	%rdx,$N[0]
++
++	mulq	$m0			# ap[j]*bp[0]
++	add	%rax,$A[0]
++	mov	8*0($np),%rax
++	adc	\$0,%rdx
++	mov	%rdx,$A[1]
++
++	mulq	$m1			# np[j]*m1
++	add	%rax,$N[0]
++	mov	8($ap,$j),%rax
++	adc	\$0,%rdx
++	add	$A[0],$N[0]		# np[j]*m1+ap[j]*bp[0]
++	adc	\$0,%rdx
++	mov	$N[0],-8($tp)		# tp[j-1]
++	mov	%rdx,$N[1]
++
++	mulq	$m0			# ap[j]*bp[0]
++	add	%rax,$A[1]
++	mov	8*1($np),%rax
++	adc	\$0,%rdx
++	mov	%rdx,$A[0]
++
++	mulq	$m1			# np[j]*m1
++	add	%rax,$N[1]
++	mov	16($ap,$j),%rax
++	adc	\$0,%rdx
++	add	$A[1],$N[1]		# np[j]*m1+ap[j]*bp[0]
++	lea	8*4($np),$np
++	adc	\$0,%rdx
++	mov	$N[1],($tp)		# tp[j-1]
++	mov	%rdx,$N[0]
++
++	add	\$32,$j			# j+=4
++	jnz	.L1st4x
++
++	mulq	$m0			# ap[j]*bp[0]
++	add	%rax,$A[0]
++	mov	-8*2($np),%rax
++	lea	32($tp),$tp
++	adc	\$0,%rdx
++	mov	%rdx,$A[1]
++
++	mulq	$m1			# np[j]*m1
++	add	%rax,$N[0]
++	mov	-8($ap),%rax
++	adc	\$0,%rdx
++	add	$A[0],$N[0]		# np[j]*m1+ap[j]*bp[0]
++	adc	\$0,%rdx
++	mov	$N[0],-24($tp)		# tp[j-1]
++	mov	%rdx,$N[1]
++
++	mulq	$m0			# ap[j]*bp[0]
++	add	%rax,$A[1]
++	mov	-8*1($np),%rax
++	adc	\$0,%rdx
++	mov	%rdx,$A[0]
++
++	mulq	$m1			# np[j]*m1
++	add	%rax,$N[1]
++	mov	($ap,$num),%rax		# ap[0]
++	adc	\$0,%rdx
++	add	$A[1],$N[1]		# np[j]*m1+ap[j]*bp[0]
++	adc	\$0,%rdx
++	mov	$N[1],-16($tp)		# tp[j-1]
++	mov	%rdx,$N[0]
++
++	lea	($np,$num),$np		# rewind $np
++
++	xor	$N[1],$N[1]
++	add	$A[0],$N[0]
++	adc	\$0,$N[1]
++	mov	$N[0],-8($tp)
++
++	jmp	.Louter4x
++
++.align	32
++.Louter4x:
++	lea	16+128($tp),%rdx	# where 256-byte mask is (+size optimization)
++	pxor	%xmm4,%xmm4
++	pxor	%xmm5,%xmm5
++___
++for($i=0;$i<$STRIDE/16;$i+=4) {
++$code.=<<___;
++	movdqa	`16*($i+0)-128`($bp),%xmm0
++	movdqa	`16*($i+1)-128`($bp),%xmm1
++	movdqa	`16*($i+2)-128`($bp),%xmm2
++	movdqa	`16*($i+3)-128`($bp),%xmm3
++	pand	`16*($i+0)-128`(%rdx),%xmm0
++	pand	`16*($i+1)-128`(%rdx),%xmm1
++	por	%xmm0,%xmm4
++	pand	`16*($i+2)-128`(%rdx),%xmm2
++	por	%xmm1,%xmm5
++	pand	`16*($i+3)-128`(%rdx),%xmm3
++	por	%xmm2,%xmm4
++	por	%xmm3,%xmm5
++___
++}
++$code.=<<___;
++	por	%xmm5,%xmm4
++	pshufd	\$0x4e,%xmm4,%xmm0
++	por	%xmm4,%xmm0
++	lea	$STRIDE($bp),$bp
++	movq	%xmm0,$m0		# m0=bp[i]
++
++	mov	($tp,$num),$A[0]
++	mov	$n0,$m1
++	mulq	$m0			# ap[0]*bp[i]
++	add	%rax,$A[0]		# ap[0]*bp[i]+tp[0]
++	mov	($np),%rax
++	adc	\$0,%rdx
++
++	imulq	$A[0],$m1		# tp[0]*n0
++	mov	%rdx,$A[1]
++	mov	$N[1],($tp)		# store upmost overflow bit
++
++	lea	($tp,$num),$tp		# rewind $tp
++
++	mulq	$m1			# np[0]*m1
++	add	%rax,$A[0]		# "$N[0]", discarded
++	mov	8($ap,$num),%rax
++	adc	\$0,%rdx
++	mov	%rdx,$N[1]
++
++	mulq	$m0			# ap[j]*bp[i]
++	add	%rax,$A[1]
++	mov	8*1($np),%rax
++	adc	\$0,%rdx
++	add	8($tp),$A[1]		# +tp[1]
++	adc	\$0,%rdx
++	mov	%rdx,$A[0]
++
++	mulq	$m1			# np[j]*m1
++	add	%rax,$N[1]
++	mov	16($ap,$num),%rax
++	adc	\$0,%rdx
++	add	$A[1],$N[1]		# np[j]*m1+ap[j]*bp[i]+tp[j]
++	lea	4*8($num),$j		# j=4
++	lea	8*4($np),$np
++	adc	\$0,%rdx
++	mov	%rdx,$N[0]
++	jmp	.Linner4x
++
++.align	32
++.Linner4x:
++	mulq	$m0			# ap[j]*bp[i]
++	add	%rax,$A[0]
++	mov	-8*2($np),%rax
++	adc	\$0,%rdx
++	add	16($tp),$A[0]		# ap[j]*bp[i]+tp[j]
++	lea	32($tp),$tp
++	adc	\$0,%rdx
++	mov	%rdx,$A[1]
++
++	mulq	$m1			# np[j]*m1
++	add	%rax,$N[0]
++	mov	-8($ap,$j),%rax
++	adc	\$0,%rdx
++	add	$A[0],$N[0]
++	adc	\$0,%rdx
++	mov	$N[1],-32($tp)		# tp[j-1]
++	mov	%rdx,$N[1]
++
++	mulq	$m0			# ap[j]*bp[i]
++	add	%rax,$A[1]
++	mov	-8*1($np),%rax
++	adc	\$0,%rdx
++	add	-8($tp),$A[1]
++	adc	\$0,%rdx
++	mov	%rdx,$A[0]
++
++	mulq	$m1			# np[j]*m1
++	add	%rax,$N[1]
++	mov	($ap,$j),%rax
++	adc	\$0,%rdx
++	add	$A[1],$N[1]
++	adc	\$0,%rdx
++	mov	$N[0],-24($tp)		# tp[j-1]
++	mov	%rdx,$N[0]
++
++	mulq	$m0			# ap[j]*bp[i]
++	add	%rax,$A[0]
++	mov	8*0($np),%rax
++	adc	\$0,%rdx
++	add	($tp),$A[0]		# ap[j]*bp[i]+tp[j]
++	adc	\$0,%rdx
++	mov	%rdx,$A[1]
++
++	mulq	$m1			# np[j]*m1
++	add	%rax,$N[0]
++	mov	8($ap,$j),%rax
++	adc	\$0,%rdx
++	add	$A[0],$N[0]
++	adc	\$0,%rdx
++	mov	$N[1],-16($tp)		# tp[j-1]
++	mov	%rdx,$N[1]
++
++	mulq	$m0			# ap[j]*bp[i]
++	add	%rax,$A[1]
++	mov	8*1($np),%rax
++	adc	\$0,%rdx
++	add	8($tp),$A[1]
++	adc	\$0,%rdx
++	mov	%rdx,$A[0]
++
++	mulq	$m1			# np[j]*m1
++	add	%rax,$N[1]
++	mov	16($ap,$j),%rax
++	adc	\$0,%rdx
++	add	$A[1],$N[1]
++	lea	8*4($np),$np
++	adc	\$0,%rdx
++	mov	$N[0],-8($tp)		# tp[j-1]
++	mov	%rdx,$N[0]
++
++	add	\$32,$j			# j+=4
++	jnz	.Linner4x
++
++	mulq	$m0			# ap[j]*bp[i]
++	add	%rax,$A[0]
++	mov	-8*2($np),%rax
++	adc	\$0,%rdx
++	add	16($tp),$A[0]		# ap[j]*bp[i]+tp[j]
++	lea	32($tp),$tp
++	adc	\$0,%rdx
++	mov	%rdx,$A[1]
++
++	mulq	$m1			# np[j]*m1
++	add	%rax,$N[0]
++	mov	-8($ap),%rax
++	adc	\$0,%rdx
++	add	$A[0],$N[0]
++	adc	\$0,%rdx
++	mov	$N[1],-32($tp)		# tp[j-1]
++	mov	%rdx,$N[1]
++
++	mulq	$m0			# ap[j]*bp[i]
++	add	%rax,$A[1]
++	mov	$m1,%rax
++	mov	-8*1($np),$m1
++	adc	\$0,%rdx
++	add	-8($tp),$A[1]
++	adc	\$0,%rdx
++	mov	%rdx,$A[0]
++
++	mulq	$m1			# np[j]*m1
++	add	%rax,$N[1]
++	mov	($ap,$num),%rax		# ap[0]
++	adc	\$0,%rdx
++	add	$A[1],$N[1]
++	adc	\$0,%rdx
++	mov	$N[0],-24($tp)		# tp[j-1]
++	mov	%rdx,$N[0]
++
++	mov	$N[1],-16($tp)		# tp[j-1]
++	lea	($np,$num),$np		# rewind $np
++
++	xor	$N[1],$N[1]
++	add	$A[0],$N[0]
++	adc	\$0,$N[1]
++	add	($tp),$N[0]		# pull upmost overflow bit
++	adc	\$0,$N[1]		# upmost overflow bit
++	mov	$N[0],-8($tp)
++
++	cmp	16+8(%rsp),$bp
++	jb	.Louter4x
++___
++if (1) {
++$code.=<<___;
++	xor	%rax,%rax
++	sub	$N[0],$m1		# compare top-most words
++	adc	$j,$j			# $j is zero
++	or	$j,$N[1]
++	sub	$N[1],%rax		# %rax=-$N[1]
++	lea	($tp,$num),%rbx		# tptr in .sqr4x_sub
++	mov	($np),%r12
++	lea	($np),%rbp		# nptr in .sqr4x_sub
++	mov	%r9,%rcx
++	sar	\$3+2,%rcx
++	mov	56+8(%rsp),%rdi		# rptr in .sqr4x_sub
++	dec	%r12			# so that after 'not' we get -n[0]
++	xor	%r10,%r10
++	mov	8*1(%rbp),%r13
++	mov	8*2(%rbp),%r14
++	mov	8*3(%rbp),%r15
++	jmp	.Lsqr4x_sub_entry
++___
++} else {
++my @ri=("%rax",$bp,$m0,$m1);
++my $rp="%rdx";
++$code.=<<___
++	xor	\$1,$N[1]
++	lea	($tp,$num),$tp		# rewind $tp
++	sar	\$5,$num		# cf=0
++	lea	($np,$N[1],8),$np
++	mov	56+8(%rsp),$rp		# restore $rp
++	jmp	.Lsub4x
++
++.align	32
++.Lsub4x:
++	.byte	0x66
++	mov	8*0($tp),@ri[0]
++	mov	8*1($tp),@ri[1]
++	.byte	0x66
++	sbb	16*0($np),@ri[0]
++	mov	8*2($tp),@ri[2]
++	sbb	16*1($np),@ri[1]
++	mov	3*8($tp),@ri[3]
++	lea	4*8($tp),$tp
++	sbb	16*2($np),@ri[2]
++	mov	@ri[0],8*0($rp)
++	sbb	16*3($np),@ri[3]
++	lea	16*4($np),$np
++	mov	@ri[1],8*1($rp)
++	mov	@ri[2],8*2($rp)
++	mov	@ri[3],8*3($rp)
++	lea	8*4($rp),$rp
++
++	inc	$num
++	jnz	.Lsub4x
++
++	ret
++___
++}
++$code.=<<___;
++.size	mul4x_internal,.-mul4x_internal
++___
++}}}
++{{{
++######################################################################
++# void bn_power5(
++my $rptr="%rdi";	# BN_ULONG *rptr,
++my $aptr="%rsi";	# const BN_ULONG *aptr,
++my $bptr="%rdx";	# const void *table,
++my $nptr="%rcx";	# const BN_ULONG *nptr,
++my $n0  ="%r8";		# const BN_ULONG *n0);
++my $num ="%r9";		# int num, has to be divisible by 8
++			# int pwr 
++
++my ($i,$j,$tptr)=("%rbp","%rcx",$rptr);
++my @A0=("%r10","%r11");
++my @A1=("%r12","%r13");
++my ($a0,$a1,$ai)=("%r14","%r15","%rbx");
++
++$code.=<<___;
++.globl	bn_power5
++.type	bn_power5,\@function,6
++.align	32
++bn_power5:
++	mov	%rsp,%rax
++___
++$code.=<<___ if ($addx);
++	mov	OPENSSL_ia32cap_P+8(%rip),%r11d
++	and	\$0x80108,%r11d
++	cmp	\$0x80108,%r11d		# check for AD*X+BMI2+BMI1
++	je	.Lpowerx5_enter
++___
++$code.=<<___;
++	push	%rbx
++	push	%rbp
++	push	%r12
++	push	%r13
++	push	%r14
++	push	%r15
++.Lpower5_prologue:
++
++	shl	\$3,${num}d		# convert $num to bytes
++	lea	($num,$num,2),%r10d	# 3*$num
++	neg	$num
++	mov	($n0),$n0		# *n0
++
++	##############################################################
++	# Ensure that stack frame doesn't alias with $rptr+3*$num
++	# modulo 4096, which covers ret[num], am[num] and n[num]
++	# (see bn_exp.c). This is done to allow memory disambiguation
++	# logic do its magic. [Extra 256 bytes is for power mask
++	# calculated from 7th argument, the index.]
++	#
++	lea	-320(%rsp,$num,2),%r11
++	mov	%rsp,%rbp
++	sub	$rptr,%r11
++	and	\$4095,%r11
++	cmp	%r11,%r10
++	jb	.Lpwr_sp_alt
++	sub	%r11,%rbp		# align with $aptr
++	lea	-320(%rbp,$num,2),%rbp	# future alloca(frame+2*num*8+256)
++	jmp	.Lpwr_sp_done
++
++.align	32
++.Lpwr_sp_alt:
++	lea	4096-320(,$num,2),%r10
++	lea	-320(%rbp,$num,2),%rbp	# future alloca(frame+2*num*8+256)
++	sub	%r10,%r11
++	mov	\$0,%r10
++	cmovc	%r10,%r11
++	sub	%r11,%rbp
++.Lpwr_sp_done:
++	and	\$-64,%rbp
++	mov	%rsp,%r11
++	sub	%rbp,%r11
++	and	\$-4096,%r11
++	lea	(%rbp,%r11),%rsp
++	mov	(%rsp),%r10
++	cmp	%rbp,%rsp
++	ja	.Lpwr_page_walk
++	jmp	.Lpwr_page_walk_done
++
++.Lpwr_page_walk:
++	lea	-4096(%rsp),%rsp
++	mov	(%rsp),%r10
++	cmp	%rbp,%rsp
++	ja	.Lpwr_page_walk
++.Lpwr_page_walk_done:
++
++	mov	$num,%r10	
++	neg	$num
++
++	##############################################################
++	# Stack layout
++	#
++	# +0	saved $num, used in reduction section
++	# +8	&t[2*$num], used in reduction section
++	# +32	saved *n0
++	# +40	saved %rsp
++	# +48	t[2*$num]
++	#
++	mov	$n0,  32(%rsp)
++	mov	%rax, 40(%rsp)		# save original %rsp
++.Lpower5_body:
++	movq	$rptr,%xmm1		# save $rptr, used in sqr8x
++	movq	$nptr,%xmm2		# save $nptr
++	movq	%r10, %xmm3		# -$num, used in sqr8x
++	movq	$bptr,%xmm4
++
++	call	__bn_sqr8x_internal
++	call	__bn_post4x_internal
++	call	__bn_sqr8x_internal
++	call	__bn_post4x_internal
++	call	__bn_sqr8x_internal
++	call	__bn_post4x_internal
++	call	__bn_sqr8x_internal
++	call	__bn_post4x_internal
++	call	__bn_sqr8x_internal
++	call	__bn_post4x_internal
++
++	movq	%xmm2,$nptr
++	movq	%xmm4,$bptr
++	mov	$aptr,$rptr
++	mov	40(%rsp),%rax
++	lea	32(%rsp),$n0
++
++	call	mul4x_internal
++
++	mov	40(%rsp),%rsi		# restore %rsp
++	mov	\$1,%rax
++	mov	-48(%rsi),%r15
++	mov	-40(%rsi),%r14
++	mov	-32(%rsi),%r13
++	mov	-24(%rsi),%r12
++	mov	-16(%rsi),%rbp
++	mov	-8(%rsi),%rbx
++	lea	(%rsi),%rsp
++.Lpower5_epilogue:
++	ret
++.size	bn_power5,.-bn_power5
++
++.globl	bn_sqr8x_internal
++.hidden	bn_sqr8x_internal
++.type	bn_sqr8x_internal,\@abi-omnipotent
++.align	32
++bn_sqr8x_internal:
++__bn_sqr8x_internal:
++	##############################################################
++	# Squaring part:
++	#
++	# a) multiply-n-add everything but a[i]*a[i];
++	# b) shift result of a) by 1 to the left and accumulate
++	#    a[i]*a[i] products;
++	#
++	##############################################################
++	#                                                     a[1]a[0]
++	#                                                 a[2]a[0]
++	#                                             a[3]a[0]
++	#                                             a[2]a[1]
++	#                                         a[4]a[0]
++	#                                         a[3]a[1]
++	#                                     a[5]a[0]
++	#                                     a[4]a[1]
++	#                                     a[3]a[2]
++	#                                 a[6]a[0]
++	#                                 a[5]a[1]
++	#                                 a[4]a[2]
++	#                             a[7]a[0]
++	#                             a[6]a[1]
++	#                             a[5]a[2]
++	#                             a[4]a[3]
++	#                         a[7]a[1]
++	#                         a[6]a[2]
++	#                         a[5]a[3]
++	#                     a[7]a[2]
++	#                     a[6]a[3]
++	#                     a[5]a[4]
++	#                 a[7]a[3]
++	#                 a[6]a[4]
++	#             a[7]a[4]
++	#             a[6]a[5]
++	#         a[7]a[5]
++	#     a[7]a[6]
++	#                                                     a[1]a[0]
++	#                                                 a[2]a[0]
++	#                                             a[3]a[0]
++	#                                         a[4]a[0]
++	#                                     a[5]a[0]
++	#                                 a[6]a[0]
++	#                             a[7]a[0]
++	#                                             a[2]a[1]
++	#                                         a[3]a[1]
++	#                                     a[4]a[1]
++	#                                 a[5]a[1]
++	#                             a[6]a[1]
++	#                         a[7]a[1]
++	#                                     a[3]a[2]
++	#                                 a[4]a[2]
++	#                             a[5]a[2]
++	#                         a[6]a[2]
++	#                     a[7]a[2]
++	#                             a[4]a[3]
++	#                         a[5]a[3]
++	#                     a[6]a[3]
++	#                 a[7]a[3]
++	#                     a[5]a[4]
++	#                 a[6]a[4]
++	#             a[7]a[4]
++	#             a[6]a[5]
++	#         a[7]a[5]
++	#     a[7]a[6]
++	#                                                         a[0]a[0]
++	#                                                 a[1]a[1]
++	#                                         a[2]a[2]
++	#                                 a[3]a[3]
++	#                         a[4]a[4]
++	#                 a[5]a[5]
++	#         a[6]a[6]
++	# a[7]a[7]
++
++	lea	32(%r10),$i		# $i=-($num-32)
++	lea	($aptr,$num),$aptr	# end of a[] buffer, ($aptr,$i)=&ap[2]
++
++	mov	$num,$j			# $j=$num
++
++					# comments apply to $num==8 case
++	mov	-32($aptr,$i),$a0	# a[0]
++	lea	48+8(%rsp,$num,2),$tptr	# end of tp[] buffer, &tp[2*$num]
++	mov	-24($aptr,$i),%rax	# a[1]
++	lea	-32($tptr,$i),$tptr	# end of tp[] window, &tp[2*$num-"$i"]
++	mov	-16($aptr,$i),$ai	# a[2]
++	mov	%rax,$a1
++
++	mul	$a0			# a[1]*a[0]
++	mov	%rax,$A0[0]		# a[1]*a[0]
++	 mov	$ai,%rax		# a[2]
++	mov	%rdx,$A0[1]
++	mov	$A0[0],-24($tptr,$i)	# t[1]
++
++	mul	$a0			# a[2]*a[0]
++	add	%rax,$A0[1]
++	 mov	$ai,%rax
++	adc	\$0,%rdx
++	mov	$A0[1],-16($tptr,$i)	# t[2]
++	mov	%rdx,$A0[0]
++
++
++	 mov	-8($aptr,$i),$ai	# a[3]
++	mul	$a1			# a[2]*a[1]
++	mov	%rax,$A1[0]		# a[2]*a[1]+t[3]
++	 mov	$ai,%rax
++	mov	%rdx,$A1[1]
++
++	 lea	($i),$j
++	mul	$a0			# a[3]*a[0]
++	add	%rax,$A0[0]		# a[3]*a[0]+a[2]*a[1]+t[3]
++	 mov	$ai,%rax
++	mov	%rdx,$A0[1]
++	adc	\$0,$A0[1]
++	add	$A1[0],$A0[0]
++	adc	\$0,$A0[1]
++	mov	$A0[0],-8($tptr,$j)	# t[3]
++	jmp	.Lsqr4x_1st
++
++.align	32
++.Lsqr4x_1st:
++	 mov	($aptr,$j),$ai		# a[4]
++	mul	$a1			# a[3]*a[1]
++	add	%rax,$A1[1]		# a[3]*a[1]+t[4]
++	 mov	$ai,%rax
++	mov	%rdx,$A1[0]
++	adc	\$0,$A1[0]
++
++	mul	$a0			# a[4]*a[0]
++	add	%rax,$A0[1]		# a[4]*a[0]+a[3]*a[1]+t[4]
++	 mov	$ai,%rax		# a[3]
++	 mov	8($aptr,$j),$ai		# a[5]
++	mov	%rdx,$A0[0]
++	adc	\$0,$A0[0]
++	add	$A1[1],$A0[1]
++	adc	\$0,$A0[0]
++
++
++	mul	$a1			# a[4]*a[3]
++	add	%rax,$A1[0]		# a[4]*a[3]+t[5]
++	 mov	$ai,%rax
++	 mov	$A0[1],($tptr,$j)	# t[4]
++	mov	%rdx,$A1[1]
++	adc	\$0,$A1[1]
++
++	mul	$a0			# a[5]*a[2]
++	add	%rax,$A0[0]		# a[5]*a[2]+a[4]*a[3]+t[5]
++	 mov	$ai,%rax
++	 mov	16($aptr,$j),$ai	# a[6]
++	mov	%rdx,$A0[1]
++	adc	\$0,$A0[1]
++	add	$A1[0],$A0[0]
++	adc	\$0,$A0[1]
++
++	mul	$a1			# a[5]*a[3]
++	add	%rax,$A1[1]		# a[5]*a[3]+t[6]
++	 mov	$ai,%rax
++	 mov	$A0[0],8($tptr,$j)	# t[5]
++	mov	%rdx,$A1[0]
++	adc	\$0,$A1[0]
++
++	mul	$a0			# a[6]*a[2]
++	add	%rax,$A0[1]		# a[6]*a[2]+a[5]*a[3]+t[6]
++	 mov	$ai,%rax		# a[3]
++	 mov	24($aptr,$j),$ai	# a[7]
++	mov	%rdx,$A0[0]
++	adc	\$0,$A0[0]
++	add	$A1[1],$A0[1]
++	adc	\$0,$A0[0]
++
++
++	mul	$a1			# a[6]*a[5]
++	add	%rax,$A1[0]		# a[6]*a[5]+t[7]
++	 mov	$ai,%rax
++	 mov	$A0[1],16($tptr,$j)	# t[6]
++	mov	%rdx,$A1[1]
++	adc	\$0,$A1[1]
++	 lea	32($j),$j
++
++	mul	$a0			# a[7]*a[4]
++	add	%rax,$A0[0]		# a[7]*a[4]+a[6]*a[5]+t[6]
++	 mov	$ai,%rax
++	mov	%rdx,$A0[1]
++	adc	\$0,$A0[1]
++	add	$A1[0],$A0[0]
++	adc	\$0,$A0[1]
++	mov	$A0[0],-8($tptr,$j)	# t[7]
++
++	cmp	\$0,$j
++	jne	.Lsqr4x_1st
++
++	mul	$a1			# a[7]*a[5]
++	add	%rax,$A1[1]
++	lea	16($i),$i
++	adc	\$0,%rdx
++	add	$A0[1],$A1[1]
++	adc	\$0,%rdx
++
++	mov	$A1[1],($tptr)		# t[8]
++	mov	%rdx,$A1[0]
++	mov	%rdx,8($tptr)		# t[9]
++	jmp	.Lsqr4x_outer
++
++.align	32
++.Lsqr4x_outer:				# comments apply to $num==6 case
++	mov	-32($aptr,$i),$a0	# a[0]
++	lea	48+8(%rsp,$num,2),$tptr	# end of tp[] buffer, &tp[2*$num]
++	mov	-24($aptr,$i),%rax	# a[1]
++	lea	-32($tptr,$i),$tptr	# end of tp[] window, &tp[2*$num-"$i"]
++	mov	-16($aptr,$i),$ai	# a[2]
++	mov	%rax,$a1
++
++	mul	$a0			# a[1]*a[0]
++	mov	-24($tptr,$i),$A0[0]	# t[1]
++	add	%rax,$A0[0]		# a[1]*a[0]+t[1]
++	 mov	$ai,%rax		# a[2]
++	adc	\$0,%rdx
++	mov	$A0[0],-24($tptr,$i)	# t[1]
++	mov	%rdx,$A0[1]
++
++	mul	$a0			# a[2]*a[0]
++	add	%rax,$A0[1]
++	 mov	$ai,%rax
++	adc	\$0,%rdx
++	add	-16($tptr,$i),$A0[1]	# a[2]*a[0]+t[2]
++	mov	%rdx,$A0[0]
++	adc	\$0,$A0[0]
++	mov	$A0[1],-16($tptr,$i)	# t[2]
++
++	xor	$A1[0],$A1[0]
++
++	 mov	-8($aptr,$i),$ai	# a[3]
++	mul	$a1			# a[2]*a[1]
++	add	%rax,$A1[0]		# a[2]*a[1]+t[3]
++	 mov	$ai,%rax
++	adc	\$0,%rdx
++	add	-8($tptr,$i),$A1[0]
++	mov	%rdx,$A1[1]
++	adc	\$0,$A1[1]
++
++	mul	$a0			# a[3]*a[0]
++	add	%rax,$A0[0]		# a[3]*a[0]+a[2]*a[1]+t[3]
++	 mov	$ai,%rax
++	adc	\$0,%rdx
++	add	$A1[0],$A0[0]
++	mov	%rdx,$A0[1]
++	adc	\$0,$A0[1]
++	mov	$A0[0],-8($tptr,$i)	# t[3]
++
++	lea	($i),$j
++	jmp	.Lsqr4x_inner
++
++.align	32
++.Lsqr4x_inner:
++	 mov	($aptr,$j),$ai		# a[4]
++	mul	$a1			# a[3]*a[1]
++	add	%rax,$A1[1]		# a[3]*a[1]+t[4]
++	 mov	$ai,%rax
++	mov	%rdx,$A1[0]
++	adc	\$0,$A1[0]
++	add	($tptr,$j),$A1[1]
++	adc	\$0,$A1[0]
++
++	.byte	0x67
++	mul	$a0			# a[4]*a[0]
++	add	%rax,$A0[1]		# a[4]*a[0]+a[3]*a[1]+t[4]
++	 mov	$ai,%rax		# a[3]
++	 mov	8($aptr,$j),$ai		# a[5]
++	mov	%rdx,$A0[0]
++	adc	\$0,$A0[0]
++	add	$A1[1],$A0[1]
++	adc	\$0,$A0[0]
++
++	mul	$a1			# a[4]*a[3]
++	add	%rax,$A1[0]		# a[4]*a[3]+t[5]
++	mov	$A0[1],($tptr,$j)	# t[4]
++	 mov	$ai,%rax
++	mov	%rdx,$A1[1]
++	adc	\$0,$A1[1]
++	add	8($tptr,$j),$A1[0]
++	lea	16($j),$j		# j++
++	adc	\$0,$A1[1]
++
++	mul	$a0			# a[5]*a[2]
++	add	%rax,$A0[0]		# a[5]*a[2]+a[4]*a[3]+t[5]
++	 mov	$ai,%rax
++	adc	\$0,%rdx
++	add	$A1[0],$A0[0]
++	mov	%rdx,$A0[1]
++	adc	\$0,$A0[1]
++	mov	$A0[0],-8($tptr,$j)	# t[5], "preloaded t[1]" below
++
++	cmp	\$0,$j
++	jne	.Lsqr4x_inner
++
++	.byte	0x67
++	mul	$a1			# a[5]*a[3]
++	add	%rax,$A1[1]
++	adc	\$0,%rdx
++	add	$A0[1],$A1[1]
++	adc	\$0,%rdx
++
++	mov	$A1[1],($tptr)		# t[6], "preloaded t[2]" below
++	mov	%rdx,$A1[0]
++	mov	%rdx,8($tptr)		# t[7], "preloaded t[3]" below
++
++	add	\$16,$i
++	jnz	.Lsqr4x_outer
++
++					# comments apply to $num==4 case
++	mov	-32($aptr),$a0		# a[0]
++	lea	48+8(%rsp,$num,2),$tptr	# end of tp[] buffer, &tp[2*$num]
++	mov	-24($aptr),%rax		# a[1]
++	lea	-32($tptr,$i),$tptr	# end of tp[] window, &tp[2*$num-"$i"]
++	mov	-16($aptr),$ai		# a[2]
++	mov	%rax,$a1
++
++	mul	$a0			# a[1]*a[0]
++	add	%rax,$A0[0]		# a[1]*a[0]+t[1], preloaded t[1]
++	 mov	$ai,%rax		# a[2]
++	mov	%rdx,$A0[1]
++	adc	\$0,$A0[1]
++
++	mul	$a0			# a[2]*a[0]
++	add	%rax,$A0[1]
++	 mov	$ai,%rax
++	 mov	$A0[0],-24($tptr)	# t[1]
++	mov	%rdx,$A0[0]
++	adc	\$0,$A0[0]
++	add	$A1[1],$A0[1]		# a[2]*a[0]+t[2], preloaded t[2]
++	 mov	-8($aptr),$ai		# a[3]
++	adc	\$0,$A0[0]
++
++	mul	$a1			# a[2]*a[1]
++	add	%rax,$A1[0]		# a[2]*a[1]+t[3], preloaded t[3]
++	 mov	$ai,%rax
++	 mov	$A0[1],-16($tptr)	# t[2]
++	mov	%rdx,$A1[1]
++	adc	\$0,$A1[1]
++
++	mul	$a0			# a[3]*a[0]
++	add	%rax,$A0[0]		# a[3]*a[0]+a[2]*a[1]+t[3]
++	 mov	$ai,%rax
++	mov	%rdx,$A0[1]
++	adc	\$0,$A0[1]
++	add	$A1[0],$A0[0]
++	adc	\$0,$A0[1]
++	mov	$A0[0],-8($tptr)	# t[3]
++
++	mul	$a1			# a[3]*a[1]
++	add	%rax,$A1[1]
++	 mov	-16($aptr),%rax		# a[2]
++	adc	\$0,%rdx
++	add	$A0[1],$A1[1]
++	adc	\$0,%rdx
++
++	mov	$A1[1],($tptr)		# t[4]
++	mov	%rdx,$A1[0]
++	mov	%rdx,8($tptr)		# t[5]
++
++	mul	$ai			# a[2]*a[3]
++___
++{
++my ($shift,$carry)=($a0,$a1);
++my @S=(@A1,$ai,$n0);
++$code.=<<___;
++	 add	\$16,$i
++	 xor	$shift,$shift
++	 sub	$num,$i			# $i=16-$num
++	 xor	$carry,$carry
++
++	add	$A1[0],%rax		# t[5]
++	adc	\$0,%rdx
++	mov	%rax,8($tptr)		# t[5]
++	mov	%rdx,16($tptr)		# t[6]
++	mov	$carry,24($tptr)	# t[7]
++
++	 mov	-16($aptr,$i),%rax	# a[0]
++	lea	48+8(%rsp),$tptr
++	 xor	$A0[0],$A0[0]		# t[0]
++	 mov	8($tptr),$A0[1]		# t[1]
++
++	lea	($shift,$A0[0],2),$S[0]	# t[2*i]<<1 | shift
++	shr	\$63,$A0[0]
++	lea	($j,$A0[1],2),$S[1]	# t[2*i+1]<<1 |
++	shr	\$63,$A0[1]
++	or	$A0[0],$S[1]		# | t[2*i]>>63
++	 mov	16($tptr),$A0[0]	# t[2*i+2]	# prefetch
++	mov	$A0[1],$shift		# shift=t[2*i+1]>>63
++	mul	%rax			# a[i]*a[i]
++	neg	$carry			# mov $carry,cf
++	 mov	24($tptr),$A0[1]	# t[2*i+2+1]	# prefetch
++	adc	%rax,$S[0]
++	 mov	-8($aptr,$i),%rax	# a[i+1]	# prefetch
++	mov	$S[0],($tptr)
++	adc	%rdx,$S[1]
++
++	lea	($shift,$A0[0],2),$S[2]	# t[2*i]<<1 | shift
++	 mov	$S[1],8($tptr)
++	 sbb	$carry,$carry		# mov cf,$carry
++	shr	\$63,$A0[0]
++	lea	($j,$A0[1],2),$S[3]	# t[2*i+1]<<1 |
++	shr	\$63,$A0[1]
++	or	$A0[0],$S[3]		# | t[2*i]>>63
++	 mov	32($tptr),$A0[0]	# t[2*i+2]	# prefetch
++	mov	$A0[1],$shift		# shift=t[2*i+1]>>63
++	mul	%rax			# a[i]*a[i]
++	neg	$carry			# mov $carry,cf
++	 mov	40($tptr),$A0[1]	# t[2*i+2+1]	# prefetch
++	adc	%rax,$S[2]
++	 mov	0($aptr,$i),%rax	# a[i+1]	# prefetch
++	mov	$S[2],16($tptr)
++	adc	%rdx,$S[3]
++	lea	16($i),$i
++	mov	$S[3],24($tptr)
++	sbb	$carry,$carry		# mov cf,$carry
++	lea	64($tptr),$tptr
++	jmp	.Lsqr4x_shift_n_add
++
++.align	32
++.Lsqr4x_shift_n_add:
++	lea	($shift,$A0[0],2),$S[0]	# t[2*i]<<1 | shift
++	shr	\$63,$A0[0]
++	lea	($j,$A0[1],2),$S[1]	# t[2*i+1]<<1 |
++	shr	\$63,$A0[1]
++	or	$A0[0],$S[1]		# | t[2*i]>>63
++	 mov	-16($tptr),$A0[0]	# t[2*i+2]	# prefetch
++	mov	$A0[1],$shift		# shift=t[2*i+1]>>63
++	mul	%rax			# a[i]*a[i]
++	neg	$carry			# mov $carry,cf
++	 mov	-8($tptr),$A0[1]	# t[2*i+2+1]	# prefetch
++	adc	%rax,$S[0]
++	 mov	-8($aptr,$i),%rax	# a[i+1]	# prefetch
++	mov	$S[0],-32($tptr)
++	adc	%rdx,$S[1]
++
++	lea	($shift,$A0[0],2),$S[2]	# t[2*i]<<1 | shift
++	 mov	$S[1],-24($tptr)
++	 sbb	$carry,$carry		# mov cf,$carry
++	shr	\$63,$A0[0]
++	lea	($j,$A0[1],2),$S[3]	# t[2*i+1]<<1 |
++	shr	\$63,$A0[1]
++	or	$A0[0],$S[3]		# | t[2*i]>>63
++	 mov	0($tptr),$A0[0]		# t[2*i+2]	# prefetch
++	mov	$A0[1],$shift		# shift=t[2*i+1]>>63
++	mul	%rax			# a[i]*a[i]
++	neg	$carry			# mov $carry,cf
++	 mov	8($tptr),$A0[1]		# t[2*i+2+1]	# prefetch
++	adc	%rax,$S[2]
++	 mov	0($aptr,$i),%rax	# a[i+1]	# prefetch
++	mov	$S[2],-16($tptr)
++	adc	%rdx,$S[3]
++
++	lea	($shift,$A0[0],2),$S[0]	# t[2*i]<<1 | shift
++	 mov	$S[3],-8($tptr)
++	 sbb	$carry,$carry		# mov cf,$carry
++	shr	\$63,$A0[0]
++	lea	($j,$A0[1],2),$S[1]	# t[2*i+1]<<1 |
++	shr	\$63,$A0[1]
++	or	$A0[0],$S[1]		# | t[2*i]>>63
++	 mov	16($tptr),$A0[0]	# t[2*i+2]	# prefetch
++	mov	$A0[1],$shift		# shift=t[2*i+1]>>63
++	mul	%rax			# a[i]*a[i]
++	neg	$carry			# mov $carry,cf
++	 mov	24($tptr),$A0[1]	# t[2*i+2+1]	# prefetch
++	adc	%rax,$S[0]
++	 mov	8($aptr,$i),%rax	# a[i+1]	# prefetch
++	mov	$S[0],0($tptr)
++	adc	%rdx,$S[1]
++
++	lea	($shift,$A0[0],2),$S[2]	# t[2*i]<<1 | shift
++	 mov	$S[1],8($tptr)
++	 sbb	$carry,$carry		# mov cf,$carry
++	shr	\$63,$A0[0]
++	lea	($j,$A0[1],2),$S[3]	# t[2*i+1]<<1 |
++	shr	\$63,$A0[1]
++	or	$A0[0],$S[3]		# | t[2*i]>>63
++	 mov	32($tptr),$A0[0]	# t[2*i+2]	# prefetch
++	mov	$A0[1],$shift		# shift=t[2*i+1]>>63
++	mul	%rax			# a[i]*a[i]
++	neg	$carry			# mov $carry,cf
++	 mov	40($tptr),$A0[1]	# t[2*i+2+1]	# prefetch
++	adc	%rax,$S[2]
++	 mov	16($aptr,$i),%rax	# a[i+1]	# prefetch
++	mov	$S[2],16($tptr)
++	adc	%rdx,$S[3]
++	mov	$S[3],24($tptr)
++	sbb	$carry,$carry		# mov cf,$carry
++	lea	64($tptr),$tptr
++	add	\$32,$i
++	jnz	.Lsqr4x_shift_n_add
++
++	lea	($shift,$A0[0],2),$S[0]	# t[2*i]<<1 | shift
++	.byte	0x67
++	shr	\$63,$A0[0]
++	lea	($j,$A0[1],2),$S[1]	# t[2*i+1]<<1 |
++	shr	\$63,$A0[1]
++	or	$A0[0],$S[1]		# | t[2*i]>>63
++	 mov	-16($tptr),$A0[0]	# t[2*i+2]	# prefetch
++	mov	$A0[1],$shift		# shift=t[2*i+1]>>63
++	mul	%rax			# a[i]*a[i]
++	neg	$carry			# mov $carry,cf
++	 mov	-8($tptr),$A0[1]	# t[2*i+2+1]	# prefetch
++	adc	%rax,$S[0]
++	 mov	-8($aptr),%rax		# a[i+1]	# prefetch
++	mov	$S[0],-32($tptr)
++	adc	%rdx,$S[1]
++
++	lea	($shift,$A0[0],2),$S[2]	# t[2*i]<<1|shift
++	 mov	$S[1],-24($tptr)
++	 sbb	$carry,$carry		# mov cf,$carry
++	shr	\$63,$A0[0]
++	lea	($j,$A0[1],2),$S[3]	# t[2*i+1]<<1 |
++	shr	\$63,$A0[1]
++	or	$A0[0],$S[3]		# | t[2*i]>>63
++	mul	%rax			# a[i]*a[i]
++	neg	$carry			# mov $carry,cf
++	adc	%rax,$S[2]
++	adc	%rdx,$S[3]
++	mov	$S[2],-16($tptr)
++	mov	$S[3],-8($tptr)
++___
++}
++######################################################################
++# Montgomery reduction part, "word-by-word" algorithm.
++#
++# This new path is inspired by multiple submissions from Intel, by
++# Shay Gueron, Vlad Krasnov, Erdinc Ozturk, James Guilford,
++# Vinodh Gopal...
++{
++my ($nptr,$tptr,$carry,$m0)=("%rbp","%rdi","%rsi","%rbx");
++
++$code.=<<___;
++	movq	%xmm2,$nptr
++__bn_sqr8x_reduction:
++	xor	%rax,%rax
++	lea	($nptr,$num),%rcx	# end of n[]
++	lea	48+8(%rsp,$num,2),%rdx	# end of t[] buffer
++	mov	%rcx,0+8(%rsp)
++	lea	48+8(%rsp,$num),$tptr	# end of initial t[] window
++	mov	%rdx,8+8(%rsp)
++	neg	$num
++	jmp	.L8x_reduction_loop
++
++.align	32
++.L8x_reduction_loop:
++	lea	($tptr,$num),$tptr	# start of current t[] window
++	.byte	0x66
++	mov	8*0($tptr),$m0
++	mov	8*1($tptr),%r9
++	mov	8*2($tptr),%r10
++	mov	8*3($tptr),%r11
++	mov	8*4($tptr),%r12
++	mov	8*5($tptr),%r13
++	mov	8*6($tptr),%r14
++	mov	8*7($tptr),%r15
++	mov	%rax,(%rdx)		# store top-most carry bit
++	lea	8*8($tptr),$tptr
++
++	.byte	0x67
++	mov	$m0,%r8
++	imulq	32+8(%rsp),$m0		# n0*a[0]
++	mov	8*0($nptr),%rax		# n[0]
++	mov	\$8,%ecx
++	jmp	.L8x_reduce
++
++.align	32
++.L8x_reduce:
++	mulq	$m0
++	 mov	8*1($nptr),%rax		# n[1]
++	neg	%r8
++	mov	%rdx,%r8
++	adc	\$0,%r8
++
++	mulq	$m0
++	add	%rax,%r9
++	 mov	8*2($nptr),%rax
++	adc	\$0,%rdx
++	add	%r9,%r8
++	 mov	$m0,48-8+8(%rsp,%rcx,8)	# put aside n0*a[i]
++	mov	%rdx,%r9
++	adc	\$0,%r9
++
++	mulq	$m0
++	add	%rax,%r10
++	 mov	8*3($nptr),%rax
++	adc	\$0,%rdx
++	add	%r10,%r9
++	 mov	32+8(%rsp),$carry	# pull n0, borrow $carry
++	mov	%rdx,%r10
++	adc	\$0,%r10
++
++	mulq	$m0
++	add	%rax,%r11
++	 mov	8*4($nptr),%rax
++	adc	\$0,%rdx
++	 imulq	%r8,$carry		# modulo-scheduled
++	add	%r11,%r10
++	mov	%rdx,%r11
++	adc	\$0,%r11
++
++	mulq	$m0
++	add	%rax,%r12
++	 mov	8*5($nptr),%rax
++	adc	\$0,%rdx
++	add	%r12,%r11
++	mov	%rdx,%r12
++	adc	\$0,%r12
++
++	mulq	$m0
++	add	%rax,%r13
++	 mov	8*6($nptr),%rax
++	adc	\$0,%rdx
++	add	%r13,%r12
++	mov	%rdx,%r13
++	adc	\$0,%r13
++
++	mulq	$m0
++	add	%rax,%r14
++	 mov	8*7($nptr),%rax
++	adc	\$0,%rdx
++	add	%r14,%r13
++	mov	%rdx,%r14
++	adc	\$0,%r14
++
++	mulq	$m0
++	 mov	$carry,$m0		# n0*a[i]
++	add	%rax,%r15
++	 mov	8*0($nptr),%rax		# n[0]
++	adc	\$0,%rdx
++	add	%r15,%r14
++	mov	%rdx,%r15
++	adc	\$0,%r15
++
++	dec	%ecx
++	jnz	.L8x_reduce
++
++	lea	8*8($nptr),$nptr
++	xor	%rax,%rax
++	mov	8+8(%rsp),%rdx		# pull end of t[]
++	cmp	0+8(%rsp),$nptr		# end of n[]?
++	jae	.L8x_no_tail
++
++	.byte	0x66
++	add	8*0($tptr),%r8
++	adc	8*1($tptr),%r9
++	adc	8*2($tptr),%r10
++	adc	8*3($tptr),%r11
++	adc	8*4($tptr),%r12
++	adc	8*5($tptr),%r13
++	adc	8*6($tptr),%r14
++	adc	8*7($tptr),%r15
++	sbb	$carry,$carry		# top carry
++
++	mov	48+56+8(%rsp),$m0	# pull n0*a[0]
++	mov	\$8,%ecx
++	mov	8*0($nptr),%rax
++	jmp	.L8x_tail
++
++.align	32
++.L8x_tail:
++	mulq	$m0
++	add	%rax,%r8
++	 mov	8*1($nptr),%rax
++	 mov	%r8,($tptr)		# save result
++	mov	%rdx,%r8
++	adc	\$0,%r8
++
++	mulq	$m0
++	add	%rax,%r9
++	 mov	8*2($nptr),%rax
++	adc	\$0,%rdx
++	add	%r9,%r8
++	 lea	8($tptr),$tptr		# $tptr++
++	mov	%rdx,%r9
++	adc	\$0,%r9
++
++	mulq	$m0
++	add	%rax,%r10
++	 mov	8*3($nptr),%rax
++	adc	\$0,%rdx
++	add	%r10,%r9
++	mov	%rdx,%r10
++	adc	\$0,%r10
++
++	mulq	$m0
++	add	%rax,%r11
++	 mov	8*4($nptr),%rax
++	adc	\$0,%rdx
++	add	%r11,%r10
++	mov	%rdx,%r11
++	adc	\$0,%r11
++
++	mulq	$m0
++	add	%rax,%r12
++	 mov	8*5($nptr),%rax
++	adc	\$0,%rdx
++	add	%r12,%r11
++	mov	%rdx,%r12
++	adc	\$0,%r12
++
++	mulq	$m0
++	add	%rax,%r13
++	 mov	8*6($nptr),%rax
++	adc	\$0,%rdx
++	add	%r13,%r12
++	mov	%rdx,%r13
++	adc	\$0,%r13
++
++	mulq	$m0
++	add	%rax,%r14
++	 mov	8*7($nptr),%rax
++	adc	\$0,%rdx
++	add	%r14,%r13
++	mov	%rdx,%r14
++	adc	\$0,%r14
++
++	mulq	$m0
++	 mov	48-16+8(%rsp,%rcx,8),$m0# pull n0*a[i]
++	add	%rax,%r15
++	adc	\$0,%rdx
++	add	%r15,%r14
++	 mov	8*0($nptr),%rax		# pull n[0]
++	mov	%rdx,%r15
++	adc	\$0,%r15
++
++	dec	%ecx
++	jnz	.L8x_tail
++
++	lea	8*8($nptr),$nptr
++	mov	8+8(%rsp),%rdx		# pull end of t[]
++	cmp	0+8(%rsp),$nptr		# end of n[]?
++	jae	.L8x_tail_done		# break out of loop
++
++	 mov	48+56+8(%rsp),$m0	# pull n0*a[0]
++	neg	$carry
++	 mov	8*0($nptr),%rax		# pull n[0]
++	adc	8*0($tptr),%r8
++	adc	8*1($tptr),%r9
++	adc	8*2($tptr),%r10
++	adc	8*3($tptr),%r11
++	adc	8*4($tptr),%r12
++	adc	8*5($tptr),%r13
++	adc	8*6($tptr),%r14
++	adc	8*7($tptr),%r15
++	sbb	$carry,$carry		# top carry
++
++	mov	\$8,%ecx
++	jmp	.L8x_tail
++
++.align	32
++.L8x_tail_done:
++	xor	%rax,%rax
++	add	(%rdx),%r8		# can this overflow?
++	adc	\$0,%r9
++	adc	\$0,%r10
++	adc	\$0,%r11
++	adc	\$0,%r12
++	adc	\$0,%r13
++	adc	\$0,%r14
++	adc	\$0,%r15
++	adc	\$0,%rax
++
++	neg	$carry
++.L8x_no_tail:
++	adc	8*0($tptr),%r8
++	adc	8*1($tptr),%r9
++	adc	8*2($tptr),%r10
++	adc	8*3($tptr),%r11
++	adc	8*4($tptr),%r12
++	adc	8*5($tptr),%r13
++	adc	8*6($tptr),%r14
++	adc	8*7($tptr),%r15
++	adc	\$0,%rax		# top-most carry
++	 mov	-8($nptr),%rcx		# np[num-1]
++	 xor	$carry,$carry
++
++	movq	%xmm2,$nptr		# restore $nptr
++
++	mov	%r8,8*0($tptr)		# store top 512 bits
++	mov	%r9,8*1($tptr)
++	 movq	%xmm3,$num		# $num is %r9, can't be moved upwards
++	mov	%r10,8*2($tptr)
++	mov	%r11,8*3($tptr)
++	mov	%r12,8*4($tptr)
++	mov	%r13,8*5($tptr)
++	mov	%r14,8*6($tptr)
++	mov	%r15,8*7($tptr)
++	lea	8*8($tptr),$tptr
++
++	cmp	%rdx,$tptr		# end of t[]?
++	jb	.L8x_reduction_loop
++	ret
++.size	bn_sqr8x_internal,.-bn_sqr8x_internal
++___
++}
++##############################################################
++# Post-condition, 4x unrolled
++#
++{
++my ($tptr,$nptr)=("%rbx","%rbp");
++$code.=<<___;
++.type	__bn_post4x_internal,\@abi-omnipotent
++.align	32
++__bn_post4x_internal:
++	mov	8*0($nptr),%r12
++	lea	(%rdi,$num),$tptr	# %rdi was $tptr above
++	mov	$num,%rcx
++	movq	%xmm1,$rptr		# restore $rptr
++	neg	%rax
++	movq	%xmm1,$aptr		# prepare for back-to-back call
++	sar	\$3+2,%rcx
++	dec	%r12			# so that after 'not' we get -n[0]
++	xor	%r10,%r10
++	mov	8*1($nptr),%r13
++	mov	8*2($nptr),%r14
++	mov	8*3($nptr),%r15
++	jmp	.Lsqr4x_sub_entry
++
++.align	16
++.Lsqr4x_sub:
++	mov	8*0($nptr),%r12
++	mov	8*1($nptr),%r13
++	mov	8*2($nptr),%r14
++	mov	8*3($nptr),%r15
++.Lsqr4x_sub_entry:
++	lea	8*4($nptr),$nptr
++	not	%r12
++	not	%r13
++	not	%r14
++	not	%r15
++	and	%rax,%r12
++	and	%rax,%r13
++	and	%rax,%r14
++	and	%rax,%r15
++
++	neg	%r10			# mov %r10,%cf
++	adc	8*0($tptr),%r12
++	adc	8*1($tptr),%r13
++	adc	8*2($tptr),%r14
++	adc	8*3($tptr),%r15
++	mov	%r12,8*0($rptr)
++	lea	8*4($tptr),$tptr
++	mov	%r13,8*1($rptr)
++	sbb	%r10,%r10		# mov %cf,%r10
++	mov	%r14,8*2($rptr)
++	mov	%r15,8*3($rptr)
++	lea	8*4($rptr),$rptr
++
++	inc	%rcx			# pass %cf
++	jnz	.Lsqr4x_sub
++
++	mov	$num,%r10		# prepare for back-to-back call
++	neg	$num			# restore $num	
++	ret
++.size	__bn_post4x_internal,.-__bn_post4x_internal
++___
++}
++{
++$code.=<<___;
++.globl	bn_from_montgomery
++.type	bn_from_montgomery,\@abi-omnipotent
++.align	32
++bn_from_montgomery:
++	testl	\$7,`($win64?"48(%rsp)":"%r9d")`
++	jz	bn_from_mont8x
++	xor	%eax,%eax
++	ret
++.size	bn_from_montgomery,.-bn_from_montgomery
++
++.type	bn_from_mont8x,\@function,6
++.align	32
++bn_from_mont8x:
++	.byte	0x67
++	mov	%rsp,%rax
++	push	%rbx
++	push	%rbp
++	push	%r12
++	push	%r13
++	push	%r14
++	push	%r15
++.Lfrom_prologue:
++
++	shl	\$3,${num}d		# convert $num to bytes
++	lea	($num,$num,2),%r10	# 3*$num in bytes
++	neg	$num
++	mov	($n0),$n0		# *n0
++
++	##############################################################
++	# Ensure that stack frame doesn't alias with $rptr+3*$num
++	# modulo 4096, which covers ret[num], am[num] and n[num]
++	# (see bn_exp.c). The stack is allocated to aligned with
++	# bn_power5's frame, and as bn_from_montgomery happens to be
++	# last operation, we use the opportunity to cleanse it.
++	#
++	lea	-320(%rsp,$num,2),%r11
++	mov	%rsp,%rbp
++	sub	$rptr,%r11
++	and	\$4095,%r11
++	cmp	%r11,%r10
++	jb	.Lfrom_sp_alt
++	sub	%r11,%rbp		# align with $aptr
++	lea	-320(%rbp,$num,2),%rbp	# future alloca(frame+2*$num*8+256)
++	jmp	.Lfrom_sp_done
++
++.align	32
++.Lfrom_sp_alt:
++	lea	4096-320(,$num,2),%r10
++	lea	-320(%rbp,$num,2),%rbp	# future alloca(frame+2*$num*8+256)
++	sub	%r10,%r11
++	mov	\$0,%r10
++	cmovc	%r10,%r11
++	sub	%r11,%rbp
++.Lfrom_sp_done:
++	and	\$-64,%rbp
++	mov	%rsp,%r11
++	sub	%rbp,%r11
++	and	\$-4096,%r11
++	lea	(%rbp,%r11),%rsp
++	mov	(%rsp),%r10
++	cmp	%rbp,%rsp
++	ja	.Lfrom_page_walk
++	jmp	.Lfrom_page_walk_done
++
++.Lfrom_page_walk:
++	lea	-4096(%rsp),%rsp
++	mov	(%rsp),%r10
++	cmp	%rbp,%rsp
++	ja	.Lfrom_page_walk
++.Lfrom_page_walk_done:
++
++	mov	$num,%r10
++	neg	$num
++
++	##############################################################
++	# Stack layout
++	#
++	# +0	saved $num, used in reduction section
++	# +8	&t[2*$num], used in reduction section
++	# +32	saved *n0
++	# +40	saved %rsp
++	# +48	t[2*$num]
++	#
++	mov	$n0,  32(%rsp)
++	mov	%rax, 40(%rsp)		# save original %rsp
++.Lfrom_body:
++	mov	$num,%r11
++	lea	48(%rsp),%rax
++	pxor	%xmm0,%xmm0
++	jmp	.Lmul_by_1
++
++.align	32
++.Lmul_by_1:
++	movdqu	($aptr),%xmm1
++	movdqu	16($aptr),%xmm2
++	movdqu	32($aptr),%xmm3
++	movdqa	%xmm0,(%rax,$num)
++	movdqu	48($aptr),%xmm4
++	movdqa	%xmm0,16(%rax,$num)
++	.byte	0x48,0x8d,0xb6,0x40,0x00,0x00,0x00	# lea	64($aptr),$aptr
++	movdqa	%xmm1,(%rax)
++	movdqa	%xmm0,32(%rax,$num)
++	movdqa	%xmm2,16(%rax)
++	movdqa	%xmm0,48(%rax,$num)
++	movdqa	%xmm3,32(%rax)
++	movdqa	%xmm4,48(%rax)
++	lea	64(%rax),%rax
++	sub	\$64,%r11
++	jnz	.Lmul_by_1
++
++	movq	$rptr,%xmm1
++	movq	$nptr,%xmm2
++	.byte	0x67
++	mov	$nptr,%rbp
++	movq	%r10, %xmm3		# -num
++___
++$code.=<<___ if ($addx);
++	mov	OPENSSL_ia32cap_P+8(%rip),%r11d
++	and	\$0x80108,%r11d
++	cmp	\$0x80108,%r11d		# check for AD*X+BMI2+BMI1
++	jne	.Lfrom_mont_nox
++
++	lea	(%rax,$num),$rptr
++	call	__bn_sqrx8x_reduction
++	call	__bn_postx4x_internal
++
++	pxor	%xmm0,%xmm0
++	lea	48(%rsp),%rax
++	mov	40(%rsp),%rsi		# restore %rsp
++	jmp	.Lfrom_mont_zero
++
++.align	32
++.Lfrom_mont_nox:
++___
++$code.=<<___;
++	call	__bn_sqr8x_reduction
++	call	__bn_post4x_internal
++
++	pxor	%xmm0,%xmm0
++	lea	48(%rsp),%rax
++	mov	40(%rsp),%rsi		# restore %rsp
++	jmp	.Lfrom_mont_zero
++
++.align	32
++.Lfrom_mont_zero:
++	movdqa	%xmm0,16*0(%rax)
++	movdqa	%xmm0,16*1(%rax)
++	movdqa	%xmm0,16*2(%rax)
++	movdqa	%xmm0,16*3(%rax)
++	lea	16*4(%rax),%rax
++	sub	\$32,$num
++	jnz	.Lfrom_mont_zero
++
++	mov	\$1,%rax
++	mov	-48(%rsi),%r15
++	mov	-40(%rsi),%r14
++	mov	-32(%rsi),%r13
++	mov	-24(%rsi),%r12
++	mov	-16(%rsi),%rbp
++	mov	-8(%rsi),%rbx
++	lea	(%rsi),%rsp
++.Lfrom_epilogue:
++	ret
++.size	bn_from_mont8x,.-bn_from_mont8x
++___
++}
++}}}
++
++if ($addx) {{{
++my $bp="%rdx";	# restore original value
++
++$code.=<<___;
++.type	bn_mulx4x_mont_gather5,\@function,6
++.align	32
++bn_mulx4x_mont_gather5:
++	mov	%rsp,%rax
++.Lmulx4x_enter:
++	push	%rbx
++	push	%rbp
++	push	%r12
++	push	%r13
++	push	%r14
++	push	%r15
++.Lmulx4x_prologue:
++
++	shl	\$3,${num}d		# convert $num to bytes
++	lea	($num,$num,2),%r10	# 3*$num in bytes
++	neg	$num			# -$num
++	mov	($n0),$n0		# *n0
++
++	##############################################################
++	# Ensure that stack frame doesn't alias with $rptr+3*$num
++	# modulo 4096, which covers ret[num], am[num] and n[num]
++	# (see bn_exp.c). This is done to allow memory disambiguation
++	# logic do its magic. [Extra [num] is allocated in order
++	# to align with bn_power5's frame, which is cleansed after
++	# completing exponentiation. Extra 256 bytes is for power mask
++	# calculated from 7th argument, the index.]
++	#
++	lea	-320(%rsp,$num,2),%r11
++	mov	%rsp,%rbp
++	sub	$rp,%r11
++	and	\$4095,%r11
++	cmp	%r11,%r10
++	jb	.Lmulx4xsp_alt
++	sub	%r11,%rbp		# align with $aptr
++	lea	-320(%rbp,$num,2),%rbp	# future alloca(frame+2*$num*8+256)
++	jmp	.Lmulx4xsp_done
++
++.Lmulx4xsp_alt:
++	lea	4096-320(,$num,2),%r10
++	lea	-320(%rbp,$num,2),%rbp	# future alloca(frame+2*$num*8+256)
++	sub	%r10,%r11
++	mov	\$0,%r10
++	cmovc	%r10,%r11
++	sub	%r11,%rbp
++.Lmulx4xsp_done:	
++	and	\$-64,%rbp		# ensure alignment
++	mov	%rsp,%r11
++	sub	%rbp,%r11
++	and	\$-4096,%r11
++	lea	(%rbp,%r11),%rsp
++	mov	(%rsp),%r10
++	cmp	%rbp,%rsp
++	ja	.Lmulx4x_page_walk
++	jmp	.Lmulx4x_page_walk_done
++
++.Lmulx4x_page_walk:
++	lea	-4096(%rsp),%rsp
++	mov	(%rsp),%r10
++	cmp	%rbp,%rsp
++	ja	.Lmulx4x_page_walk
++.Lmulx4x_page_walk_done:
++
++	##############################################################
++	# Stack layout
++	# +0	-num
++	# +8	off-loaded &b[i]
++	# +16	end of b[num]
++	# +24	inner counter
++	# +32	saved n0
++	# +40	saved %rsp
++	# +48
++	# +56	saved rp
++	# +64	tmp[num+1]
++	#
++	mov	$n0, 32(%rsp)		# save *n0
++	mov	%rax,40(%rsp)		# save original %rsp
++.Lmulx4x_body:
++	call	mulx4x_internal
++
++	mov	40(%rsp),%rsi		# restore %rsp
++	mov	\$1,%rax
++
++	mov	-48(%rsi),%r15
++	mov	-40(%rsi),%r14
++	mov	-32(%rsi),%r13
++	mov	-24(%rsi),%r12
++	mov	-16(%rsi),%rbp
++	mov	-8(%rsi),%rbx
++	lea	(%rsi),%rsp
++.Lmulx4x_epilogue:
++	ret
++.size	bn_mulx4x_mont_gather5,.-bn_mulx4x_mont_gather5
++
++.type	mulx4x_internal,\@abi-omnipotent
++.align	32
++mulx4x_internal:
++	mov	$num,8(%rsp)		# save -$num (it was in bytes)
++	mov	$num,%r10
++	neg	$num			# restore $num
++	shl	\$5,$num
++	neg	%r10			# restore $num
++	lea	128($bp,$num),%r13	# end of powers table (+size optimization)
++	shr	\$5+5,$num
++	movd	`($win64?56:8)`(%rax),%xmm5	# load 7th argument
++	sub	\$1,$num
++	lea	.Linc(%rip),%rax
++	mov	%r13,16+8(%rsp)		# end of b[num]
++	mov	$num,24+8(%rsp)		# inner counter
++	mov	$rp, 56+8(%rsp)		# save $rp
++___
++my ($aptr, $bptr, $nptr, $tptr, $mi,  $bi,  $zero, $num)=
++   ("%rsi","%rdi","%rcx","%rbx","%r8","%r9","%rbp","%rax");
++my $rptr=$bptr;
++my $STRIDE=2**5*8;		# 5 is "window size"
++my $N=$STRIDE/4;		# should match cache line size
++$code.=<<___;
++	movdqa	0(%rax),%xmm0		# 00000001000000010000000000000000
++	movdqa	16(%rax),%xmm1		# 00000002000000020000000200000002
++	lea	88-112(%rsp,%r10),%r10	# place the mask after tp[num+1] (+ICache optimizaton)
++	lea	128($bp),$bptr		# size optimization
++
++	pshufd	\$0,%xmm5,%xmm5		# broadcast index
++	movdqa	%xmm1,%xmm4
++	.byte	0x67
++	movdqa	%xmm1,%xmm2
++___
++########################################################################
++# calculate mask by comparing 0..31 to index and save result to stack
++#
++$code.=<<___;
++	.byte	0x67
++	paddd	%xmm0,%xmm1
++	pcmpeqd	%xmm5,%xmm0		# compare to 1,0
++	movdqa	%xmm4,%xmm3
++___
++for($i=0;$i<$STRIDE/16-4;$i+=4) {
++$code.=<<___;
++	paddd	%xmm1,%xmm2
++	pcmpeqd	%xmm5,%xmm1		# compare to 3,2
++	movdqa	%xmm0,`16*($i+0)+112`(%r10)
++	movdqa	%xmm4,%xmm0
++
++	paddd	%xmm2,%xmm3
++	pcmpeqd	%xmm5,%xmm2		# compare to 5,4
++	movdqa	%xmm1,`16*($i+1)+112`(%r10)
++	movdqa	%xmm4,%xmm1
++
++	paddd	%xmm3,%xmm0
++	pcmpeqd	%xmm5,%xmm3		# compare to 7,6
++	movdqa	%xmm2,`16*($i+2)+112`(%r10)
++	movdqa	%xmm4,%xmm2
++
++	paddd	%xmm0,%xmm1
++	pcmpeqd	%xmm5,%xmm0
++	movdqa	%xmm3,`16*($i+3)+112`(%r10)
++	movdqa	%xmm4,%xmm3
++___
++}
++$code.=<<___;				# last iteration can be optimized
++	.byte	0x67
++	paddd	%xmm1,%xmm2
++	pcmpeqd	%xmm5,%xmm1
++	movdqa	%xmm0,`16*($i+0)+112`(%r10)
++
++	paddd	%xmm2,%xmm3
++	pcmpeqd	%xmm5,%xmm2
++	movdqa	%xmm1,`16*($i+1)+112`(%r10)
++
++	pcmpeqd	%xmm5,%xmm3
++	movdqa	%xmm2,`16*($i+2)+112`(%r10)
++
++	pand	`16*($i+0)-128`($bptr),%xmm0	# while it's still in register
++	pand	`16*($i+1)-128`($bptr),%xmm1
++	pand	`16*($i+2)-128`($bptr),%xmm2
++	movdqa	%xmm3,`16*($i+3)+112`(%r10)
++	pand	`16*($i+3)-128`($bptr),%xmm3
++	por	%xmm2,%xmm0
++	por	%xmm3,%xmm1
++___
++for($i=0;$i<$STRIDE/16-4;$i+=4) {
++$code.=<<___;
++	movdqa	`16*($i+0)-128`($bptr),%xmm4
++	movdqa	`16*($i+1)-128`($bptr),%xmm5
++	movdqa	`16*($i+2)-128`($bptr),%xmm2
++	pand	`16*($i+0)+112`(%r10),%xmm4
++	movdqa	`16*($i+3)-128`($bptr),%xmm3
++	pand	`16*($i+1)+112`(%r10),%xmm5
++	por	%xmm4,%xmm0
++	pand	`16*($i+2)+112`(%r10),%xmm2
++	por	%xmm5,%xmm1
++	pand	`16*($i+3)+112`(%r10),%xmm3
++	por	%xmm2,%xmm0
++	por	%xmm3,%xmm1
++___
++}
++$code.=<<___;
++	pxor	%xmm1,%xmm0
++	pshufd	\$0x4e,%xmm0,%xmm1
++	por	%xmm1,%xmm0
++	lea	$STRIDE($bptr),$bptr
++	movq	%xmm0,%rdx		# bp[0]
++	lea	64+8*4+8(%rsp),$tptr
++
++	mov	%rdx,$bi
++	mulx	0*8($aptr),$mi,%rax	# a[0]*b[0]
++	mulx	1*8($aptr),%r11,%r12	# a[1]*b[0]
++	add	%rax,%r11
++	mulx	2*8($aptr),%rax,%r13	# ...
++	adc	%rax,%r12
++	adc	\$0,%r13
++	mulx	3*8($aptr),%rax,%r14
++
++	mov	$mi,%r15
++	imulq	32+8(%rsp),$mi		# "t[0]"*n0
++	xor	$zero,$zero		# cf=0, of=0
++	mov	$mi,%rdx
++
++	mov	$bptr,8+8(%rsp)		# off-load &b[i]
++
++	lea	4*8($aptr),$aptr
++	adcx	%rax,%r13
++	adcx	$zero,%r14		# cf=0
++
++	mulx	0*8($nptr),%rax,%r10
++	adcx	%rax,%r15		# discarded
++	adox	%r11,%r10
++	mulx	1*8($nptr),%rax,%r11
++	adcx	%rax,%r10
++	adox	%r12,%r11
++	mulx	2*8($nptr),%rax,%r12
++	mov	24+8(%rsp),$bptr	# counter value
++	mov	%r10,-8*4($tptr)
++	adcx	%rax,%r11
++	adox	%r13,%r12
++	mulx	3*8($nptr),%rax,%r15
++	 mov	$bi,%rdx
++	mov	%r11,-8*3($tptr)
++	adcx	%rax,%r12
++	adox	$zero,%r15		# of=0
++	lea	4*8($nptr),$nptr
++	mov	%r12,-8*2($tptr)
++	jmp	.Lmulx4x_1st
++
++.align	32
++.Lmulx4x_1st:
++	adcx	$zero,%r15		# cf=0, modulo-scheduled
++	mulx	0*8($aptr),%r10,%rax	# a[4]*b[0]
++	adcx	%r14,%r10
++	mulx	1*8($aptr),%r11,%r14	# a[5]*b[0]
++	adcx	%rax,%r11
++	mulx	2*8($aptr),%r12,%rax	# ...
++	adcx	%r14,%r12
++	mulx	3*8($aptr),%r13,%r14
++	 .byte	0x67,0x67
++	 mov	$mi,%rdx
++	adcx	%rax,%r13
++	adcx	$zero,%r14		# cf=0
++	lea	4*8($aptr),$aptr
++	lea	4*8($tptr),$tptr
++
++	adox	%r15,%r10
++	mulx	0*8($nptr),%rax,%r15
++	adcx	%rax,%r10
++	adox	%r15,%r11
++	mulx	1*8($nptr),%rax,%r15
++	adcx	%rax,%r11
++	adox	%r15,%r12
++	mulx	2*8($nptr),%rax,%r15
++	mov	%r10,-5*8($tptr)
++	adcx	%rax,%r12
++	mov	%r11,-4*8($tptr)
++	adox	%r15,%r13
++	mulx	3*8($nptr),%rax,%r15
++	 mov	$bi,%rdx
++	mov	%r12,-3*8($tptr)
++	adcx	%rax,%r13
++	adox	$zero,%r15
++	lea	4*8($nptr),$nptr
++	mov	%r13,-2*8($tptr)
++
++	dec	$bptr			# of=0, pass cf
++	jnz	.Lmulx4x_1st
++
++	mov	8(%rsp),$num		# load -num
++	adc	$zero,%r15		# modulo-scheduled
++	lea	($aptr,$num),$aptr	# rewind $aptr
++	add	%r15,%r14
++	mov	8+8(%rsp),$bptr		# re-load &b[i]
++	adc	$zero,$zero		# top-most carry
++	mov	%r14,-1*8($tptr)
++	jmp	.Lmulx4x_outer
++
++.align	32
++.Lmulx4x_outer:
++	lea	16-256($tptr),%r10	# where 256-byte mask is (+density control)
++	pxor	%xmm4,%xmm4
++	.byte	0x67,0x67
++	pxor	%xmm5,%xmm5
++___
++for($i=0;$i<$STRIDE/16;$i+=4) {
++$code.=<<___;
++	movdqa	`16*($i+0)-128`($bptr),%xmm0
++	movdqa	`16*($i+1)-128`($bptr),%xmm1
++	movdqa	`16*($i+2)-128`($bptr),%xmm2
++	pand	`16*($i+0)+256`(%r10),%xmm0
++	movdqa	`16*($i+3)-128`($bptr),%xmm3
++	pand	`16*($i+1)+256`(%r10),%xmm1
++	por	%xmm0,%xmm4
++	pand	`16*($i+2)+256`(%r10),%xmm2
++	por	%xmm1,%xmm5
++	pand	`16*($i+3)+256`(%r10),%xmm3
++	por	%xmm2,%xmm4
++	por	%xmm3,%xmm5
++___
++}
++$code.=<<___;
++	por	%xmm5,%xmm4
++	pshufd	\$0x4e,%xmm4,%xmm0
++	por	%xmm4,%xmm0
++	lea	$STRIDE($bptr),$bptr
++	movq	%xmm0,%rdx		# m0=bp[i]
++
++	mov	$zero,($tptr)		# save top-most carry
++	lea	4*8($tptr,$num),$tptr	# rewind $tptr
++	mulx	0*8($aptr),$mi,%r11	# a[0]*b[i]
++	xor	$zero,$zero		# cf=0, of=0
++	mov	%rdx,$bi
++	mulx	1*8($aptr),%r14,%r12	# a[1]*b[i]
++	adox	-4*8($tptr),$mi		# +t[0]
++	adcx	%r14,%r11
++	mulx	2*8($aptr),%r15,%r13	# ...
++	adox	-3*8($tptr),%r11
++	adcx	%r15,%r12
++	mulx	3*8($aptr),%rdx,%r14
++	adox	-2*8($tptr),%r12
++	adcx	%rdx,%r13
++	lea	($nptr,$num),$nptr	# rewind $nptr
++	lea	4*8($aptr),$aptr
++	adox	-1*8($tptr),%r13
++	adcx	$zero,%r14
++	adox	$zero,%r14
++
++	mov	$mi,%r15
++	imulq	32+8(%rsp),$mi		# "t[0]"*n0
++
++	mov	$mi,%rdx
++	xor	$zero,$zero		# cf=0, of=0
++	mov	$bptr,8+8(%rsp)		# off-load &b[i]
++
++	mulx	0*8($nptr),%rax,%r10
++	adcx	%rax,%r15		# discarded
++	adox	%r11,%r10
++	mulx	1*8($nptr),%rax,%r11
++	adcx	%rax,%r10
++	adox	%r12,%r11
++	mulx	2*8($nptr),%rax,%r12
++	adcx	%rax,%r11
++	adox	%r13,%r12
++	mulx	3*8($nptr),%rax,%r15
++	 mov	$bi,%rdx
++	mov	24+8(%rsp),$bptr	# counter value
++	mov	%r10,-8*4($tptr)
++	adcx	%rax,%r12
++	mov	%r11,-8*3($tptr)
++	adox	$zero,%r15		# of=0
++	mov	%r12,-8*2($tptr)
++	lea	4*8($nptr),$nptr
++	jmp	.Lmulx4x_inner
++
++.align	32
++.Lmulx4x_inner:
++	mulx	0*8($aptr),%r10,%rax	# a[4]*b[i]
++	adcx	$zero,%r15		# cf=0, modulo-scheduled
++	adox	%r14,%r10
++	mulx	1*8($aptr),%r11,%r14	# a[5]*b[i]
++	adcx	0*8($tptr),%r10
++	adox	%rax,%r11
++	mulx	2*8($aptr),%r12,%rax	# ...
++	adcx	1*8($tptr),%r11
++	adox	%r14,%r12
++	mulx	3*8($aptr),%r13,%r14
++	 mov	$mi,%rdx
++	adcx	2*8($tptr),%r12
++	adox	%rax,%r13
++	adcx	3*8($tptr),%r13
++	adox	$zero,%r14		# of=0
++	lea	4*8($aptr),$aptr
++	lea	4*8($tptr),$tptr
++	adcx	$zero,%r14		# cf=0
++
++	adox	%r15,%r10
++	mulx	0*8($nptr),%rax,%r15
++	adcx	%rax,%r10
++	adox	%r15,%r11
++	mulx	1*8($nptr),%rax,%r15
++	adcx	%rax,%r11
++	adox	%r15,%r12
++	mulx	2*8($nptr),%rax,%r15
++	mov	%r10,-5*8($tptr)
++	adcx	%rax,%r12
++	adox	%r15,%r13
++	mov	%r11,-4*8($tptr)
++	mulx	3*8($nptr),%rax,%r15
++	 mov	$bi,%rdx
++	lea	4*8($nptr),$nptr
++	mov	%r12,-3*8($tptr)
++	adcx	%rax,%r13
++	adox	$zero,%r15
++	mov	%r13,-2*8($tptr)
++
++	dec	$bptr			# of=0, pass cf
++	jnz	.Lmulx4x_inner
++
++	mov	0+8(%rsp),$num		# load -num
++	adc	$zero,%r15		# modulo-scheduled
++	sub	0*8($tptr),$bptr	# pull top-most carry to %cf
++	mov	8+8(%rsp),$bptr		# re-load &b[i]
++	mov	16+8(%rsp),%r10
++	adc	%r15,%r14
++	lea	($aptr,$num),$aptr	# rewind $aptr
++	adc	$zero,$zero		# top-most carry
++	mov	%r14,-1*8($tptr)
++
++	cmp	%r10,$bptr
++	jb	.Lmulx4x_outer
++
++	mov	-8($nptr),%r10
++	mov	$zero,%r8
++	mov	($nptr,$num),%r12
++	lea	($nptr,$num),%rbp	# rewind $nptr
++	mov	$num,%rcx
++	lea	($tptr,$num),%rdi	# rewind $tptr
++	xor	%eax,%eax
++	xor	%r15,%r15
++	sub	%r14,%r10		# compare top-most words
++	adc	%r15,%r15
++	or	%r15,%r8
++	sar	\$3+2,%rcx
++	sub	%r8,%rax		# %rax=-%r8
++	mov	56+8(%rsp),%rdx		# restore rp
++	dec	%r12			# so that after 'not' we get -n[0]
++	mov	8*1(%rbp),%r13
++	xor	%r8,%r8
++	mov	8*2(%rbp),%r14
++	mov	8*3(%rbp),%r15
++	jmp	.Lsqrx4x_sub_entry	# common post-condition
++.size	mulx4x_internal,.-mulx4x_internal
++___
++}{
++######################################################################
++# void bn_power5(
++my $rptr="%rdi";	# BN_ULONG *rptr,
++my $aptr="%rsi";	# const BN_ULONG *aptr,
++my $bptr="%rdx";	# const void *table,
++my $nptr="%rcx";	# const BN_ULONG *nptr,
++my $n0  ="%r8";		# const BN_ULONG *n0);
++my $num ="%r9";		# int num, has to be divisible by 8
++			# int pwr);
++
++my ($i,$j,$tptr)=("%rbp","%rcx",$rptr);
++my @A0=("%r10","%r11");
++my @A1=("%r12","%r13");
++my ($a0,$a1,$ai)=("%r14","%r15","%rbx");
++
++$code.=<<___;
++.type	bn_powerx5,\@function,6
++.align	32
++bn_powerx5:
++	mov	%rsp,%rax
++.Lpowerx5_enter:
++	push	%rbx
++	push	%rbp
++	push	%r12
++	push	%r13
++	push	%r14
++	push	%r15
++.Lpowerx5_prologue:
++
++	shl	\$3,${num}d		# convert $num to bytes
++	lea	($num,$num,2),%r10	# 3*$num in bytes
++	neg	$num
++	mov	($n0),$n0		# *n0
++
++	##############################################################
++	# Ensure that stack frame doesn't alias with $rptr+3*$num
++	# modulo 4096, which covers ret[num], am[num] and n[num]
++	# (see bn_exp.c). This is done to allow memory disambiguation
++	# logic do its magic. [Extra 256 bytes is for power mask
++	# calculated from 7th argument, the index.]
++	#
++	lea	-320(%rsp,$num,2),%r11
++	mov	%rsp,%rbp
++	sub	$rptr,%r11
++	and	\$4095,%r11
++	cmp	%r11,%r10
++	jb	.Lpwrx_sp_alt
++	sub	%r11,%rbp		# align with $aptr
++	lea	-320(%rbp,$num,2),%rbp	# future alloca(frame+2*$num*8+256)
++	jmp	.Lpwrx_sp_done
++
++.align	32
++.Lpwrx_sp_alt:
++	lea	4096-320(,$num,2),%r10
++	lea	-320(%rbp,$num,2),%rbp	# alloca(frame+2*$num*8+256)
++	sub	%r10,%r11
++	mov	\$0,%r10
++	cmovc	%r10,%r11
++	sub	%r11,%rbp
++.Lpwrx_sp_done:
++	and	\$-64,%rbp
++	mov	%rsp,%r11
++	sub	%rbp,%r11
++	and	\$-4096,%r11
++	lea	(%rbp,%r11),%rsp
++	mov	(%rsp),%r10
++	cmp	%rbp,%rsp
++	ja	.Lpwrx_page_walk
++	jmp	.Lpwrx_page_walk_done
++
++.Lpwrx_page_walk:
++	lea	-4096(%rsp),%rsp
++	mov	(%rsp),%r10
++	cmp	%rbp,%rsp
++	ja	.Lpwrx_page_walk
++.Lpwrx_page_walk_done:
++
++	mov	$num,%r10	
++	neg	$num
++
++	##############################################################
++	# Stack layout
++	#
++	# +0	saved $num, used in reduction section
++	# +8	&t[2*$num], used in reduction section
++	# +16	intermediate carry bit
++	# +24	top-most carry bit, used in reduction section
++	# +32	saved *n0
++	# +40	saved %rsp
++	# +48	t[2*$num]
++	#
++	pxor	%xmm0,%xmm0
++	movq	$rptr,%xmm1		# save $rptr
++	movq	$nptr,%xmm2		# save $nptr
++	movq	%r10, %xmm3		# -$num
++	movq	$bptr,%xmm4
++	mov	$n0,  32(%rsp)
++	mov	%rax, 40(%rsp)		# save original %rsp
++.Lpowerx5_body:
++
++	call	__bn_sqrx8x_internal
++	call	__bn_postx4x_internal
++	call	__bn_sqrx8x_internal
++	call	__bn_postx4x_internal
++	call	__bn_sqrx8x_internal
++	call	__bn_postx4x_internal
++	call	__bn_sqrx8x_internal
++	call	__bn_postx4x_internal
++	call	__bn_sqrx8x_internal
++	call	__bn_postx4x_internal
++
++	mov	%r10,$num		# -num
++	mov	$aptr,$rptr
++	movq	%xmm2,$nptr
++	movq	%xmm4,$bptr
++	mov	40(%rsp),%rax
++
++	call	mulx4x_internal
++
++	mov	40(%rsp),%rsi		# restore %rsp
++	mov	\$1,%rax
++
++	mov	-48(%rsi),%r15
++	mov	-40(%rsi),%r14
++	mov	-32(%rsi),%r13
++	mov	-24(%rsi),%r12
++	mov	-16(%rsi),%rbp
++	mov	-8(%rsi),%rbx
++	lea	(%rsi),%rsp
++.Lpowerx5_epilogue:
++	ret
++.size	bn_powerx5,.-bn_powerx5
++
++.globl	bn_sqrx8x_internal
++.hidden	bn_sqrx8x_internal
++.type	bn_sqrx8x_internal,\@abi-omnipotent
++.align	32
++bn_sqrx8x_internal:
++__bn_sqrx8x_internal:
++	##################################################################
++	# Squaring part:
++	#
++	# a) multiply-n-add everything but a[i]*a[i];
++	# b) shift result of a) by 1 to the left and accumulate
++	#    a[i]*a[i] products;
++	#
++	##################################################################
++	# a[7]a[7]a[6]a[6]a[5]a[5]a[4]a[4]a[3]a[3]a[2]a[2]a[1]a[1]a[0]a[0]
++	#                                                     a[1]a[0]
++	#                                                 a[2]a[0]
++	#                                             a[3]a[0]
++	#                                             a[2]a[1]
++	#                                         a[3]a[1]
++	#                                     a[3]a[2]
++	#
++	#                                         a[4]a[0]
++	#                                     a[5]a[0]
++	#                                 a[6]a[0]
++	#                             a[7]a[0]
++	#                                     a[4]a[1]
++	#                                 a[5]a[1]
++	#                             a[6]a[1]
++	#                         a[7]a[1]
++	#                                 a[4]a[2]
++	#                             a[5]a[2]
++	#                         a[6]a[2]
++	#                     a[7]a[2]
++	#                             a[4]a[3]
++	#                         a[5]a[3]
++	#                     a[6]a[3]
++	#                 a[7]a[3]
++	#
++	#                     a[5]a[4]
++	#                 a[6]a[4]
++	#             a[7]a[4]
++	#             a[6]a[5]
++	#         a[7]a[5]
++	#     a[7]a[6]
++	# a[7]a[7]a[6]a[6]a[5]a[5]a[4]a[4]a[3]a[3]a[2]a[2]a[1]a[1]a[0]a[0]
++___
++{
++my ($zero,$carry)=("%rbp","%rcx");
++my $aaptr=$zero;
++$code.=<<___;
++	lea	48+8(%rsp),$tptr
++	lea	($aptr,$num),$aaptr
++	mov	$num,0+8(%rsp)			# save $num
++	mov	$aaptr,8+8(%rsp)		# save end of $aptr
++	jmp	.Lsqr8x_zero_start
++
++.align	32
++.byte	0x66,0x66,0x66,0x2e,0x0f,0x1f,0x84,0x00,0x00,0x00,0x00,0x00
++.Lsqrx8x_zero:
++	.byte	0x3e
++	movdqa	%xmm0,0*8($tptr)
++	movdqa	%xmm0,2*8($tptr)
++	movdqa	%xmm0,4*8($tptr)
++	movdqa	%xmm0,6*8($tptr)
++.Lsqr8x_zero_start:			# aligned at 32
++	movdqa	%xmm0,8*8($tptr)
++	movdqa	%xmm0,10*8($tptr)
++	movdqa	%xmm0,12*8($tptr)
++	movdqa	%xmm0,14*8($tptr)
++	lea	16*8($tptr),$tptr
++	sub	\$64,$num
++	jnz	.Lsqrx8x_zero
++
++	mov	0*8($aptr),%rdx		# a[0], modulo-scheduled
++	#xor	%r9,%r9			# t[1], ex-$num, zero already
++	xor	%r10,%r10
++	xor	%r11,%r11
++	xor	%r12,%r12
++	xor	%r13,%r13
++	xor	%r14,%r14
++	xor	%r15,%r15
++	lea	48+8(%rsp),$tptr
++	xor	$zero,$zero		# cf=0, cf=0
++	jmp	.Lsqrx8x_outer_loop
++
++.align	32
++.Lsqrx8x_outer_loop:
++	mulx	1*8($aptr),%r8,%rax	# a[1]*a[0]
++	adcx	%r9,%r8			# a[1]*a[0]+=t[1]
++	adox	%rax,%r10
++	mulx	2*8($aptr),%r9,%rax	# a[2]*a[0]
++	adcx	%r10,%r9
++	adox	%rax,%r11
++	.byte	0xc4,0xe2,0xab,0xf6,0x86,0x18,0x00,0x00,0x00	# mulx	3*8($aptr),%r10,%rax	# ...
++	adcx	%r11,%r10
++	adox	%rax,%r12
++	.byte	0xc4,0xe2,0xa3,0xf6,0x86,0x20,0x00,0x00,0x00	# mulx	4*8($aptr),%r11,%rax
++	adcx	%r12,%r11
++	adox	%rax,%r13
++	mulx	5*8($aptr),%r12,%rax
++	adcx	%r13,%r12
++	adox	%rax,%r14
++	mulx	6*8($aptr),%r13,%rax
++	adcx	%r14,%r13
++	adox	%r15,%rax
++	mulx	7*8($aptr),%r14,%r15
++	 mov	1*8($aptr),%rdx		# a[1]
++	adcx	%rax,%r14
++	adox	$zero,%r15
++	adc	8*8($tptr),%r15
++	mov	%r8,1*8($tptr)		# t[1]
++	mov	%r9,2*8($tptr)		# t[2]
++	sbb	$carry,$carry		# mov %cf,$carry
++	xor	$zero,$zero		# cf=0, of=0
++
++
++	mulx	2*8($aptr),%r8,%rbx	# a[2]*a[1]
++	mulx	3*8($aptr),%r9,%rax	# a[3]*a[1]
++	adcx	%r10,%r8
++	adox	%rbx,%r9
++	mulx	4*8($aptr),%r10,%rbx	# ...
++	adcx	%r11,%r9
++	adox	%rax,%r10
++	.byte	0xc4,0xe2,0xa3,0xf6,0x86,0x28,0x00,0x00,0x00	# mulx	5*8($aptr),%r11,%rax
++	adcx	%r12,%r10
++	adox	%rbx,%r11
++	.byte	0xc4,0xe2,0x9b,0xf6,0x9e,0x30,0x00,0x00,0x00	# mulx	6*8($aptr),%r12,%rbx
++	adcx	%r13,%r11
++	adox	%r14,%r12
++	.byte	0xc4,0x62,0x93,0xf6,0xb6,0x38,0x00,0x00,0x00	# mulx	7*8($aptr),%r13,%r14
++	 mov	2*8($aptr),%rdx		# a[2]
++	adcx	%rax,%r12
++	adox	%rbx,%r13
++	adcx	%r15,%r13
++	adox	$zero,%r14		# of=0
++	adcx	$zero,%r14		# cf=0
++
++	mov	%r8,3*8($tptr)		# t[3]
++	mov	%r9,4*8($tptr)		# t[4]
++
++	mulx	3*8($aptr),%r8,%rbx	# a[3]*a[2]
++	mulx	4*8($aptr),%r9,%rax	# a[4]*a[2]
++	adcx	%r10,%r8
++	adox	%rbx,%r9
++	mulx	5*8($aptr),%r10,%rbx	# ...
++	adcx	%r11,%r9
++	adox	%rax,%r10
++	.byte	0xc4,0xe2,0xa3,0xf6,0x86,0x30,0x00,0x00,0x00	# mulx	6*8($aptr),%r11,%rax
++	adcx	%r12,%r10
++	adox	%r13,%r11
++	.byte	0xc4,0x62,0x9b,0xf6,0xae,0x38,0x00,0x00,0x00	# mulx	7*8($aptr),%r12,%r13
++	.byte	0x3e
++	 mov	3*8($aptr),%rdx		# a[3]
++	adcx	%rbx,%r11
++	adox	%rax,%r12
++	adcx	%r14,%r12
++	mov	%r8,5*8($tptr)		# t[5]
++	mov	%r9,6*8($tptr)		# t[6]
++	 mulx	4*8($aptr),%r8,%rax	# a[4]*a[3]
++	adox	$zero,%r13		# of=0
++	adcx	$zero,%r13		# cf=0
++
++	mulx	5*8($aptr),%r9,%rbx	# a[5]*a[3]
++	adcx	%r10,%r8
++	adox	%rax,%r9
++	mulx	6*8($aptr),%r10,%rax	# ...
++	adcx	%r11,%r9
++	adox	%r12,%r10
++	mulx	7*8($aptr),%r11,%r12
++	 mov	4*8($aptr),%rdx		# a[4]
++	 mov	5*8($aptr),%r14		# a[5]
++	adcx	%rbx,%r10
++	adox	%rax,%r11
++	 mov	6*8($aptr),%r15		# a[6]
++	adcx	%r13,%r11
++	adox	$zero,%r12		# of=0
++	adcx	$zero,%r12		# cf=0
++
++	mov	%r8,7*8($tptr)		# t[7]
++	mov	%r9,8*8($tptr)		# t[8]
++
++	mulx	%r14,%r9,%rax		# a[5]*a[4]
++	 mov	7*8($aptr),%r8		# a[7]
++	adcx	%r10,%r9
++	mulx	%r15,%r10,%rbx		# a[6]*a[4]
++	adox	%rax,%r10
++	adcx	%r11,%r10
++	mulx	%r8,%r11,%rax		# a[7]*a[4]
++	 mov	%r14,%rdx		# a[5]
++	adox	%rbx,%r11
++	adcx	%r12,%r11
++	#adox	$zero,%rax		# of=0
++	adcx	$zero,%rax		# cf=0
++
++	mulx	%r15,%r14,%rbx		# a[6]*a[5]
++	mulx	%r8,%r12,%r13		# a[7]*a[5]
++	 mov	%r15,%rdx		# a[6]
++	 lea	8*8($aptr),$aptr
++	adcx	%r14,%r11
++	adox	%rbx,%r12
++	adcx	%rax,%r12
++	adox	$zero,%r13
++
++	.byte	0x67,0x67
++	mulx	%r8,%r8,%r14		# a[7]*a[6]
++	adcx	%r8,%r13
++	adcx	$zero,%r14
++
++	cmp	8+8(%rsp),$aptr
++	je	.Lsqrx8x_outer_break
++
++	neg	$carry			# mov $carry,%cf
++	mov	\$-8,%rcx
++	mov	$zero,%r15
++	mov	8*8($tptr),%r8
++	adcx	9*8($tptr),%r9		# +=t[9]
++	adcx	10*8($tptr),%r10	# ...
++	adcx	11*8($tptr),%r11
++	adc	12*8($tptr),%r12
++	adc	13*8($tptr),%r13
++	adc	14*8($tptr),%r14
++	adc	15*8($tptr),%r15
++	lea	($aptr),$aaptr
++	lea	2*64($tptr),$tptr
++	sbb	%rax,%rax		# mov %cf,$carry
++
++	mov	-64($aptr),%rdx		# a[0]
++	mov	%rax,16+8(%rsp)		# offload $carry
++	mov	$tptr,24+8(%rsp)
++
++	#lea	8*8($tptr),$tptr	# see 2*8*8($tptr) above
++	xor	%eax,%eax		# cf=0, of=0
++	jmp	.Lsqrx8x_loop
++
++.align	32
++.Lsqrx8x_loop:
++	mov	%r8,%rbx
++	mulx	0*8($aaptr),%rax,%r8	# a[8]*a[i]
++	adcx	%rax,%rbx		# +=t[8]
++	adox	%r9,%r8
++
++	mulx	1*8($aaptr),%rax,%r9	# ...
++	adcx	%rax,%r8
++	adox	%r10,%r9
++
++	mulx	2*8($aaptr),%rax,%r10
++	adcx	%rax,%r9
++	adox	%r11,%r10
++
++	mulx	3*8($aaptr),%rax,%r11
++	adcx	%rax,%r10
++	adox	%r12,%r11
++
++	.byte	0xc4,0x62,0xfb,0xf6,0xa5,0x20,0x00,0x00,0x00	# mulx	4*8($aaptr),%rax,%r12
++	adcx	%rax,%r11
++	adox	%r13,%r12
++
++	mulx	5*8($aaptr),%rax,%r13
++	adcx	%rax,%r12
++	adox	%r14,%r13
++
++	mulx	6*8($aaptr),%rax,%r14
++	 mov	%rbx,($tptr,%rcx,8)	# store t[8+i]
++	 mov	\$0,%ebx
++	adcx	%rax,%r13
++	adox	%r15,%r14
++
++	.byte	0xc4,0x62,0xfb,0xf6,0xbd,0x38,0x00,0x00,0x00	# mulx	7*8($aaptr),%rax,%r15
++	 mov	8($aptr,%rcx,8),%rdx	# a[i]
++	adcx	%rax,%r14
++	adox	%rbx,%r15		# %rbx is 0, of=0
++	adcx	%rbx,%r15		# cf=0
++
++	.byte	0x67
++	inc	%rcx			# of=0
++	jnz	.Lsqrx8x_loop
++
++	lea	8*8($aaptr),$aaptr
++	mov	\$-8,%rcx
++	cmp	8+8(%rsp),$aaptr	# done?
++	je	.Lsqrx8x_break
++
++	sub	16+8(%rsp),%rbx		# mov 16(%rsp),%cf
++	.byte	0x66
++	mov	-64($aptr),%rdx
++	adcx	0*8($tptr),%r8
++	adcx	1*8($tptr),%r9
++	adc	2*8($tptr),%r10
++	adc	3*8($tptr),%r11
++	adc	4*8($tptr),%r12
++	adc	5*8($tptr),%r13
++	adc	6*8($tptr),%r14
++	adc	7*8($tptr),%r15
++	lea	8*8($tptr),$tptr
++	.byte	0x67
++	sbb	%rax,%rax		# mov %cf,%rax
++	xor	%ebx,%ebx		# cf=0, of=0
++	mov	%rax,16+8(%rsp)		# offload carry
++	jmp	.Lsqrx8x_loop
++
++.align	32
++.Lsqrx8x_break:
++	sub	16+8(%rsp),%r8		# consume last carry
++	mov	24+8(%rsp),$carry	# initial $tptr, borrow $carry
++	mov	0*8($aptr),%rdx		# a[8], modulo-scheduled
++	xor	%ebp,%ebp		# xor	$zero,$zero
++	mov	%r8,0*8($tptr)
++	cmp	$carry,$tptr		# cf=0, of=0
++	je	.Lsqrx8x_outer_loop
++
++	mov	%r9,1*8($tptr)
++	 mov	1*8($carry),%r9
++	mov	%r10,2*8($tptr)
++	 mov	2*8($carry),%r10
++	mov	%r11,3*8($tptr)
++	 mov	3*8($carry),%r11
++	mov	%r12,4*8($tptr)
++	 mov	4*8($carry),%r12
++	mov	%r13,5*8($tptr)
++	 mov	5*8($carry),%r13
++	mov	%r14,6*8($tptr)
++	 mov	6*8($carry),%r14
++	mov	%r15,7*8($tptr)
++	 mov	7*8($carry),%r15
++	mov	$carry,$tptr
++	jmp	.Lsqrx8x_outer_loop
++
++.align	32
++.Lsqrx8x_outer_break:
++	mov	%r9,9*8($tptr)		# t[9]
++	 movq	%xmm3,%rcx		# -$num
++	mov	%r10,10*8($tptr)	# ...
++	mov	%r11,11*8($tptr)
++	mov	%r12,12*8($tptr)
++	mov	%r13,13*8($tptr)
++	mov	%r14,14*8($tptr)
++___
++}{
++my $i="%rcx";
++$code.=<<___;
++	lea	48+8(%rsp),$tptr
++	mov	($aptr,$i),%rdx		# a[0]
++
++	mov	8($tptr),$A0[1]		# t[1]
++	xor	$A0[0],$A0[0]		# t[0], of=0, cf=0
++	mov	0+8(%rsp),$num		# restore $num
++	adox	$A0[1],$A0[1]
++	 mov	16($tptr),$A1[0]	# t[2]	# prefetch
++	 mov	24($tptr),$A1[1]	# t[3]	# prefetch
++	#jmp	.Lsqrx4x_shift_n_add	# happens to be aligned
++
++.align	32
++.Lsqrx4x_shift_n_add:
++	mulx	%rdx,%rax,%rbx
++	 adox	$A1[0],$A1[0]
++	adcx	$A0[0],%rax
++	 .byte	0x48,0x8b,0x94,0x0e,0x08,0x00,0x00,0x00	# mov	8($aptr,$i),%rdx	# a[i+1]	# prefetch
++	 .byte	0x4c,0x8b,0x97,0x20,0x00,0x00,0x00	# mov	32($tptr),$A0[0]	# t[2*i+4]	# prefetch
++	 adox	$A1[1],$A1[1]
++	adcx	$A0[1],%rbx
++	 mov	40($tptr),$A0[1]		# t[2*i+4+1]	# prefetch
++	mov	%rax,0($tptr)
++	mov	%rbx,8($tptr)
++
++	mulx	%rdx,%rax,%rbx
++	 adox	$A0[0],$A0[0]
++	adcx	$A1[0],%rax
++	 mov	16($aptr,$i),%rdx	# a[i+2]	# prefetch
++	 mov	48($tptr),$A1[0]	# t[2*i+6]	# prefetch
++	 adox	$A0[1],$A0[1]
++	adcx	$A1[1],%rbx
++	 mov	56($tptr),$A1[1]	# t[2*i+6+1]	# prefetch
++	mov	%rax,16($tptr)
++	mov	%rbx,24($tptr)
++
++	mulx	%rdx,%rax,%rbx
++	 adox	$A1[0],$A1[0]
++	adcx	$A0[0],%rax
++	 mov	24($aptr,$i),%rdx	# a[i+3]	# prefetch
++	 lea	32($i),$i
++	 mov	64($tptr),$A0[0]	# t[2*i+8]	# prefetch
++	 adox	$A1[1],$A1[1]
++	adcx	$A0[1],%rbx
++	 mov	72($tptr),$A0[1]	# t[2*i+8+1]	# prefetch
++	mov	%rax,32($tptr)
++	mov	%rbx,40($tptr)
++
++	mulx	%rdx,%rax,%rbx
++	 adox	$A0[0],$A0[0]
++	adcx	$A1[0],%rax
++	jrcxz	.Lsqrx4x_shift_n_add_break
++	 .byte	0x48,0x8b,0x94,0x0e,0x00,0x00,0x00,0x00	# mov	0($aptr,$i),%rdx	# a[i+4]	# prefetch
++	 adox	$A0[1],$A0[1]
++	adcx	$A1[1],%rbx
++	 mov	80($tptr),$A1[0]	# t[2*i+10]	# prefetch
++	 mov	88($tptr),$A1[1]	# t[2*i+10+1]	# prefetch
++	mov	%rax,48($tptr)
++	mov	%rbx,56($tptr)
++	lea	64($tptr),$tptr
++	nop
++	jmp	.Lsqrx4x_shift_n_add
++
++.align	32
++.Lsqrx4x_shift_n_add_break:
++	adcx	$A1[1],%rbx
++	mov	%rax,48($tptr)
++	mov	%rbx,56($tptr)
++	lea	64($tptr),$tptr		# end of t[] buffer
++___
++}
++######################################################################
++# Montgomery reduction part, "word-by-word" algorithm.
++#
++# This new path is inspired by multiple submissions from Intel, by
++# Shay Gueron, Vlad Krasnov, Erdinc Ozturk, James Guilford,
++# Vinodh Gopal...
++{
++my ($nptr,$carry,$m0)=("%rbp","%rsi","%rdx");
++
++$code.=<<___;
++	movq	%xmm2,$nptr
++__bn_sqrx8x_reduction:
++	xor	%eax,%eax		# initial top-most carry bit
++	mov	32+8(%rsp),%rbx		# n0
++	mov	48+8(%rsp),%rdx		# "%r8", 8*0($tptr)
++	lea	-8*8($nptr,$num),%rcx	# end of n[]
++	#lea	48+8(%rsp,$num,2),$tptr	# end of t[] buffer
++	mov	%rcx, 0+8(%rsp)		# save end of n[]
++	mov	$tptr,8+8(%rsp)		# save end of t[]
++
++	lea	48+8(%rsp),$tptr		# initial t[] window
++	jmp	.Lsqrx8x_reduction_loop
++
++.align	32
++.Lsqrx8x_reduction_loop:
++	mov	8*1($tptr),%r9
++	mov	8*2($tptr),%r10
++	mov	8*3($tptr),%r11
++	mov	8*4($tptr),%r12
++	mov	%rdx,%r8
++	imulq	%rbx,%rdx		# n0*a[i]
++	mov	8*5($tptr),%r13
++	mov	8*6($tptr),%r14
++	mov	8*7($tptr),%r15
++	mov	%rax,24+8(%rsp)		# store top-most carry bit
++
++	lea	8*8($tptr),$tptr
++	xor	$carry,$carry		# cf=0,of=0
++	mov	\$-8,%rcx
++	jmp	.Lsqrx8x_reduce
++
++.align	32
++.Lsqrx8x_reduce:
++	mov	%r8, %rbx
++	mulx	8*0($nptr),%rax,%r8	# n[0]
++	adcx	%rbx,%rax		# discarded
++	adox	%r9,%r8
++
++	mulx	8*1($nptr),%rbx,%r9	# n[1]
++	adcx	%rbx,%r8
++	adox	%r10,%r9
++
++	mulx	8*2($nptr),%rbx,%r10
++	adcx	%rbx,%r9
++	adox	%r11,%r10
++
++	mulx	8*3($nptr),%rbx,%r11
++	adcx	%rbx,%r10
++	adox	%r12,%r11
++
++	.byte	0xc4,0x62,0xe3,0xf6,0xa5,0x20,0x00,0x00,0x00	# mulx	8*4($nptr),%rbx,%r12
++	 mov	%rdx,%rax
++	 mov	%r8,%rdx
++	adcx	%rbx,%r11
++	adox	%r13,%r12
++
++	 mulx	32+8(%rsp),%rbx,%rdx	# %rdx discarded
++	 mov	%rax,%rdx
++	 mov	%rax,64+48+8(%rsp,%rcx,8)	# put aside n0*a[i]
++
++	mulx	8*5($nptr),%rax,%r13
++	adcx	%rax,%r12
++	adox	%r14,%r13
++
++	mulx	8*6($nptr),%rax,%r14
++	adcx	%rax,%r13
++	adox	%r15,%r14
++
++	mulx	8*7($nptr),%rax,%r15
++	 mov	%rbx,%rdx
++	adcx	%rax,%r14
++	adox	$carry,%r15		# $carry is 0
++	adcx	$carry,%r15		# cf=0
++
++	.byte	0x67,0x67,0x67
++	inc	%rcx			# of=0
++	jnz	.Lsqrx8x_reduce
++
++	mov	$carry,%rax		# xor	%rax,%rax
++	cmp	0+8(%rsp),$nptr		# end of n[]?
++	jae	.Lsqrx8x_no_tail
++
++	mov	48+8(%rsp),%rdx		# pull n0*a[0]
++	add	8*0($tptr),%r8
++	lea	8*8($nptr),$nptr
++	mov	\$-8,%rcx
++	adcx	8*1($tptr),%r9
++	adcx	8*2($tptr),%r10
++	adc	8*3($tptr),%r11
++	adc	8*4($tptr),%r12
++	adc	8*5($tptr),%r13
++	adc	8*6($tptr),%r14
++	adc	8*7($tptr),%r15
++	lea	8*8($tptr),$tptr
++	sbb	%rax,%rax		# top carry
++
++	xor	$carry,$carry		# of=0, cf=0
++	mov	%rax,16+8(%rsp)
++	jmp	.Lsqrx8x_tail
++
++.align	32
++.Lsqrx8x_tail:
++	mov	%r8,%rbx
++	mulx	8*0($nptr),%rax,%r8
++	adcx	%rax,%rbx
++	adox	%r9,%r8
++
++	mulx	8*1($nptr),%rax,%r9
++	adcx	%rax,%r8
++	adox	%r10,%r9
++
++	mulx	8*2($nptr),%rax,%r10
++	adcx	%rax,%r9
++	adox	%r11,%r10
++
++	mulx	8*3($nptr),%rax,%r11
++	adcx	%rax,%r10
++	adox	%r12,%r11
++
++	.byte	0xc4,0x62,0xfb,0xf6,0xa5,0x20,0x00,0x00,0x00	# mulx	8*4($nptr),%rax,%r12
++	adcx	%rax,%r11
++	adox	%r13,%r12
++
++	mulx	8*5($nptr),%rax,%r13
++	adcx	%rax,%r12
++	adox	%r14,%r13
++
++	mulx	8*6($nptr),%rax,%r14
++	adcx	%rax,%r13
++	adox	%r15,%r14
++
++	mulx	8*7($nptr),%rax,%r15
++	 mov	72+48+8(%rsp,%rcx,8),%rdx	# pull n0*a[i]
++	adcx	%rax,%r14
++	adox	$carry,%r15
++	 mov	%rbx,($tptr,%rcx,8)	# save result
++	 mov	%r8,%rbx
++	adcx	$carry,%r15		# cf=0
++
++	inc	%rcx			# of=0
++	jnz	.Lsqrx8x_tail
++
++	cmp	0+8(%rsp),$nptr		# end of n[]?
++	jae	.Lsqrx8x_tail_done	# break out of loop
++
++	sub	16+8(%rsp),$carry	# mov 16(%rsp),%cf
++	 mov	48+8(%rsp),%rdx		# pull n0*a[0]
++	 lea	8*8($nptr),$nptr
++	adc	8*0($tptr),%r8
++	adc	8*1($tptr),%r9
++	adc	8*2($tptr),%r10
++	adc	8*3($tptr),%r11
++	adc	8*4($tptr),%r12
++	adc	8*5($tptr),%r13
++	adc	8*6($tptr),%r14
++	adc	8*7($tptr),%r15
++	lea	8*8($tptr),$tptr
++	sbb	%rax,%rax
++	sub	\$8,%rcx		# mov	\$-8,%rcx
++
++	xor	$carry,$carry		# of=0, cf=0
++	mov	%rax,16+8(%rsp)
++	jmp	.Lsqrx8x_tail
++
++.align	32
++.Lsqrx8x_tail_done:
++	xor	%rax,%rax
++	add	24+8(%rsp),%r8		# can this overflow?
++	adc	\$0,%r9
++	adc	\$0,%r10
++	adc	\$0,%r11
++	adc	\$0,%r12
++	adc	\$0,%r13
++	adc	\$0,%r14
++	adc	\$0,%r15
++	adc	\$0,%rax
++
++	sub	16+8(%rsp),$carry	# mov 16(%rsp),%cf
++.Lsqrx8x_no_tail:			# %cf is 0 if jumped here
++	adc	8*0($tptr),%r8
++	 movq	%xmm3,%rcx
++	adc	8*1($tptr),%r9
++	 mov	8*7($nptr),$carry
++	 movq	%xmm2,$nptr		# restore $nptr
++	adc	8*2($tptr),%r10
++	adc	8*3($tptr),%r11
++	adc	8*4($tptr),%r12
++	adc	8*5($tptr),%r13
++	adc	8*6($tptr),%r14
++	adc	8*7($tptr),%r15
++	adc	\$0,%rax		# top-most carry
++
++	mov	32+8(%rsp),%rbx		# n0
++	mov	8*8($tptr,%rcx),%rdx	# modulo-scheduled "%r8"
++
++	mov	%r8,8*0($tptr)		# store top 512 bits
++	 lea	8*8($tptr),%r8		# borrow %r8
++	mov	%r9,8*1($tptr)
++	mov	%r10,8*2($tptr)
++	mov	%r11,8*3($tptr)
++	mov	%r12,8*4($tptr)
++	mov	%r13,8*5($tptr)
++	mov	%r14,8*6($tptr)
++	mov	%r15,8*7($tptr)
++
++	lea	8*8($tptr,%rcx),$tptr	# start of current t[] window
++	cmp	8+8(%rsp),%r8		# end of t[]?
++	jb	.Lsqrx8x_reduction_loop
++	ret
++.size	bn_sqrx8x_internal,.-bn_sqrx8x_internal
++___
++}
++##############################################################
++# Post-condition, 4x unrolled
++#
++{
++my ($rptr,$nptr)=("%rdx","%rbp");
++$code.=<<___;
++.align	32
++__bn_postx4x_internal:
++	mov	8*0($nptr),%r12
++	mov	%rcx,%r10		# -$num
++	mov	%rcx,%r9		# -$num
++	neg	%rax
++	sar	\$3+2,%rcx
++	#lea	48+8(%rsp,%r9),$tptr
++	movq	%xmm1,$rptr		# restore $rptr
++	movq	%xmm1,$aptr		# prepare for back-to-back call
++	dec	%r12			# so that after 'not' we get -n[0]
++	mov	8*1($nptr),%r13
++	xor	%r8,%r8
++	mov	8*2($nptr),%r14
++	mov	8*3($nptr),%r15
++	jmp	.Lsqrx4x_sub_entry
++
++.align	16
++.Lsqrx4x_sub:
++	mov	8*0($nptr),%r12
++	mov	8*1($nptr),%r13
++	mov	8*2($nptr),%r14
++	mov	8*3($nptr),%r15
++.Lsqrx4x_sub_entry:
++	andn	%rax,%r12,%r12
++	lea	8*4($nptr),$nptr
++	andn	%rax,%r13,%r13
++	andn	%rax,%r14,%r14
++	andn	%rax,%r15,%r15
++
++	neg	%r8			# mov %r8,%cf
++	adc	8*0($tptr),%r12
++	adc	8*1($tptr),%r13
++	adc	8*2($tptr),%r14
++	adc	8*3($tptr),%r15
++	mov	%r12,8*0($rptr)
++	lea	8*4($tptr),$tptr
++	mov	%r13,8*1($rptr)
++	sbb	%r8,%r8			# mov %cf,%r8
++	mov	%r14,8*2($rptr)
++	mov	%r15,8*3($rptr)
++	lea	8*4($rptr),$rptr
++
++	inc	%rcx
++	jnz	.Lsqrx4x_sub
++
++	neg	%r9			# restore $num
++
++	ret
++.size	__bn_postx4x_internal,.-__bn_postx4x_internal
++___
++}
++}}}
++{
++my ($inp,$num,$tbl,$idx)=$win64?("%rcx","%edx","%r8", "%r9d") : # Win64 order
++				("%rdi","%esi","%rdx","%ecx");  # Unix order
++my $out=$inp;
++my $STRIDE=2**5*8;
++my $N=$STRIDE/4;
++
++$code.=<<___;
++.globl	bn_get_bits5
++.type	bn_get_bits5,\@abi-omnipotent
++.align	16
++bn_get_bits5:
++	lea	0($inp),%r10
++	lea	1($inp),%r11
++	mov	$num,%ecx
++	shr	\$4,$num
++	and	\$15,%ecx
++	lea	-8(%ecx),%eax
++	cmp	\$11,%ecx
++	cmova	%r11,%r10
++	cmova	%eax,%ecx
++	movzw	(%r10,$num,2),%eax
++	shrl	%cl,%eax
++	and	\$31,%eax
++	ret
++.size	bn_get_bits5,.-bn_get_bits5
++
++.globl	bn_scatter5
++.type	bn_scatter5,\@abi-omnipotent
++.align	16
++bn_scatter5:
++	cmp	\$0, $num
++	jz	.Lscatter_epilogue
++	lea	($tbl,$idx,8),$tbl
++.Lscatter:
++	mov	($inp),%rax
++	lea	8($inp),$inp
++	mov	%rax,($tbl)
++	lea	32*8($tbl),$tbl
++	sub	\$1,$num
++	jnz	.Lscatter
++.Lscatter_epilogue:
++	ret
++.size	bn_scatter5,.-bn_scatter5
++
++.globl	bn_gather5
++.type	bn_gather5,\@abi-omnipotent
++.align	32
++bn_gather5:
++.LSEH_begin_bn_gather5:			# Win64 thing, but harmless in other cases
++	# I can't trust assembler to use specific encoding:-(
++	.byte	0x4c,0x8d,0x14,0x24			#lea    (%rsp),%r10
++	.byte	0x48,0x81,0xec,0x08,0x01,0x00,0x00	#sub	$0x108,%rsp
++	lea	.Linc(%rip),%rax
++	and	\$-16,%rsp		# shouldn't be formally required
++
++	movd	$idx,%xmm5
++	movdqa	0(%rax),%xmm0		# 00000001000000010000000000000000
++	movdqa	16(%rax),%xmm1		# 00000002000000020000000200000002
++	lea	128($tbl),%r11		# size optimization
++	lea	128(%rsp),%rax		# size optimization
++
++	pshufd	\$0,%xmm5,%xmm5		# broadcast $idx
++	movdqa	%xmm1,%xmm4
++	movdqa	%xmm1,%xmm2
++___
++########################################################################
++# calculate mask by comparing 0..31 to $idx and save result to stack
++#
++for($i=0;$i<$STRIDE/16;$i+=4) {
++$code.=<<___;
++	paddd	%xmm0,%xmm1
++	pcmpeqd	%xmm5,%xmm0		# compare to 1,0
++___
++$code.=<<___	if ($i);
++	movdqa	%xmm3,`16*($i-1)-128`(%rax)
++___
++$code.=<<___;
++	movdqa	%xmm4,%xmm3
++
++	paddd	%xmm1,%xmm2
++	pcmpeqd	%xmm5,%xmm1		# compare to 3,2
++	movdqa	%xmm0,`16*($i+0)-128`(%rax)
++	movdqa	%xmm4,%xmm0
++
++	paddd	%xmm2,%xmm3
++	pcmpeqd	%xmm5,%xmm2		# compare to 5,4
++	movdqa	%xmm1,`16*($i+1)-128`(%rax)
++	movdqa	%xmm4,%xmm1
++
++	paddd	%xmm3,%xmm0
++	pcmpeqd	%xmm5,%xmm3		# compare to 7,6
++	movdqa	%xmm2,`16*($i+2)-128`(%rax)
++	movdqa	%xmm4,%xmm2
++___
++}
++$code.=<<___;
++	movdqa	%xmm3,`16*($i-1)-128`(%rax)
++	jmp	.Lgather
++
++.align	32
++.Lgather:
++	pxor	%xmm4,%xmm4
++	pxor	%xmm5,%xmm5
++___
++for($i=0;$i<$STRIDE/16;$i+=4) {
++$code.=<<___;
++	movdqa	`16*($i+0)-128`(%r11),%xmm0
++	movdqa	`16*($i+1)-128`(%r11),%xmm1
++	movdqa	`16*($i+2)-128`(%r11),%xmm2
++	pand	`16*($i+0)-128`(%rax),%xmm0
++	movdqa	`16*($i+3)-128`(%r11),%xmm3
++	pand	`16*($i+1)-128`(%rax),%xmm1
++	por	%xmm0,%xmm4
++	pand	`16*($i+2)-128`(%rax),%xmm2
++	por	%xmm1,%xmm5
++	pand	`16*($i+3)-128`(%rax),%xmm3
++	por	%xmm2,%xmm4
++	por	%xmm3,%xmm5
++___
++}
++$code.=<<___;
++	por	%xmm5,%xmm4
++	lea	$STRIDE(%r11),%r11
++	pshufd	\$0x4e,%xmm4,%xmm0
++	por	%xmm4,%xmm0
++	movq	%xmm0,($out)		# m0=bp[0]
++	lea	8($out),$out
++	sub	\$1,$num
++	jnz	.Lgather
++
++	lea	(%r10),%rsp
++	ret
++.LSEH_end_bn_gather5:
++.size	bn_gather5,.-bn_gather5
++___
++}
++$code.=<<___;
++.align	64
++.Linc:
++	.long	0,0, 1,1
++	.long	2,2, 2,2
++.asciz	"Montgomery Multiplication with scatter/gather for x86_64, CRYPTOGAMS by "
++___
++
++# EXCEPTION_DISPOSITION handler (EXCEPTION_RECORD *rec,ULONG64 frame,
++#		CONTEXT *context,DISPATCHER_CONTEXT *disp)
++if ($win64) {
++$rec="%rcx";
++$frame="%rdx";
++$context="%r8";
++$disp="%r9";
++
++$code.=<<___;
++.extern	__imp_RtlVirtualUnwind
++.type	mul_handler,\@abi-omnipotent
++.align	16
++mul_handler:
++	push	%rsi
++	push	%rdi
++	push	%rbx
++	push	%rbp
++	push	%r12
++	push	%r13
++	push	%r14
++	push	%r15
++	pushfq
++	sub	\$64,%rsp
++
++	mov	120($context),%rax	# pull context->Rax
++	mov	248($context),%rbx	# pull context->Rip
++
++	mov	8($disp),%rsi		# disp->ImageBase
++	mov	56($disp),%r11		# disp->HandlerData
++
++	mov	0(%r11),%r10d		# HandlerData[0]
++	lea	(%rsi,%r10),%r10	# end of prologue label
++	cmp	%r10,%rbx		# context->RipRip>=epilogue label
++	jb	.Lcommon_pop_regs
++
++	mov	152($context),%rax	# pull context->Rsp
++
++	mov	8(%r11),%r10d		# HandlerData[2]
++	lea	(%rsi,%r10),%r10	# epilogue label
++	cmp	%r10,%rbx		# context->Rip>=epilogue label
++	jae	.Lcommon_seh_tail
++
++	lea	.Lmul_epilogue(%rip),%r10
++	cmp	%r10,%rbx
++	ja	.Lbody_40
++
++	mov	192($context),%r10	# pull $num
++	mov	8(%rax,%r10,8),%rax	# pull saved stack pointer
++
++	jmp	.Lcommon_pop_regs
++
++.Lbody_40:
++	mov	40(%rax),%rax		# pull saved stack pointer
++.Lcommon_pop_regs:
++	mov	-8(%rax),%rbx
++	mov	-16(%rax),%rbp
++	mov	-24(%rax),%r12
++	mov	-32(%rax),%r13
++	mov	-40(%rax),%r14
++	mov	-48(%rax),%r15
++	mov	%rbx,144($context)	# restore context->Rbx
++	mov	%rbp,160($context)	# restore context->Rbp
++	mov	%r12,216($context)	# restore context->R12
++	mov	%r13,224($context)	# restore context->R13
++	mov	%r14,232($context)	# restore context->R14
++	mov	%r15,240($context)	# restore context->R15
++
++.Lcommon_seh_tail:
++	mov	8(%rax),%rdi
++	mov	16(%rax),%rsi
++	mov	%rax,152($context)	# restore context->Rsp
++	mov	%rsi,168($context)	# restore context->Rsi
++	mov	%rdi,176($context)	# restore context->Rdi
++
++	mov	40($disp),%rdi		# disp->ContextRecord
++	mov	$context,%rsi		# context
++	mov	\$154,%ecx		# sizeof(CONTEXT)
++	.long	0xa548f3fc		# cld; rep movsq
++
++	mov	$disp,%rsi
++	xor	%rcx,%rcx		# arg1, UNW_FLAG_NHANDLER
++	mov	8(%rsi),%rdx		# arg2, disp->ImageBase
++	mov	0(%rsi),%r8		# arg3, disp->ControlPc
++	mov	16(%rsi),%r9		# arg4, disp->FunctionEntry
++	mov	40(%rsi),%r10		# disp->ContextRecord
++	lea	56(%rsi),%r11		# &disp->HandlerData
++	lea	24(%rsi),%r12		# &disp->EstablisherFrame
++	mov	%r10,32(%rsp)		# arg5
++	mov	%r11,40(%rsp)		# arg6
++	mov	%r12,48(%rsp)		# arg7
++	mov	%rcx,56(%rsp)		# arg8, (NULL)
++	call	*__imp_RtlVirtualUnwind(%rip)
++
++	mov	\$1,%eax		# ExceptionContinueSearch
++	add	\$64,%rsp
++	popfq
++	pop	%r15
++	pop	%r14
++	pop	%r13
++	pop	%r12
++	pop	%rbp
++	pop	%rbx
++	pop	%rdi
++	pop	%rsi
++	ret
++.size	mul_handler,.-mul_handler
++
++.section	.pdata
++.align	4
++	.rva	.LSEH_begin_bn_mul_mont_gather5
++	.rva	.LSEH_end_bn_mul_mont_gather5
++	.rva	.LSEH_info_bn_mul_mont_gather5
++
++	.rva	.LSEH_begin_bn_mul4x_mont_gather5
++	.rva	.LSEH_end_bn_mul4x_mont_gather5
++	.rva	.LSEH_info_bn_mul4x_mont_gather5
++
++	.rva	.LSEH_begin_bn_power5
++	.rva	.LSEH_end_bn_power5
++	.rva	.LSEH_info_bn_power5
++
++	.rva	.LSEH_begin_bn_from_mont8x
++	.rva	.LSEH_end_bn_from_mont8x
++	.rva	.LSEH_info_bn_from_mont8x
++___
++$code.=<<___ if ($addx);
++	.rva	.LSEH_begin_bn_mulx4x_mont_gather5
++	.rva	.LSEH_end_bn_mulx4x_mont_gather5
++	.rva	.LSEH_info_bn_mulx4x_mont_gather5
++
++	.rva	.LSEH_begin_bn_powerx5
++	.rva	.LSEH_end_bn_powerx5
++	.rva	.LSEH_info_bn_powerx5
++___
++$code.=<<___;
++	.rva	.LSEH_begin_bn_gather5
++	.rva	.LSEH_end_bn_gather5
++	.rva	.LSEH_info_bn_gather5
++
++.section	.xdata
++.align	8
++.LSEH_info_bn_mul_mont_gather5:
++	.byte	9,0,0,0
++	.rva	mul_handler
++	.rva	.Lmul_body,.Lmul_body,.Lmul_epilogue		# HandlerData[]
++.align	8
++.LSEH_info_bn_mul4x_mont_gather5:
++	.byte	9,0,0,0
++	.rva	mul_handler
++	.rva	.Lmul4x_prologue,.Lmul4x_body,.Lmul4x_epilogue		# HandlerData[]
++.align	8
++.LSEH_info_bn_power5:
++	.byte	9,0,0,0
++	.rva	mul_handler
++	.rva	.Lpower5_prologue,.Lpower5_body,.Lpower5_epilogue	# HandlerData[]
++.align	8
++.LSEH_info_bn_from_mont8x:
++	.byte	9,0,0,0
++	.rva	mul_handler
++	.rva	.Lfrom_prologue,.Lfrom_body,.Lfrom_epilogue		# HandlerData[]
++___
++$code.=<<___ if ($addx);
++.align	8
++.LSEH_info_bn_mulx4x_mont_gather5:
++	.byte	9,0,0,0
++	.rva	mul_handler
++	.rva	.Lmulx4x_prologue,.Lmulx4x_body,.Lmulx4x_epilogue	# HandlerData[]
++.align	8
++.LSEH_info_bn_powerx5:
++	.byte	9,0,0,0
++	.rva	mul_handler
++	.rva	.Lpowerx5_prologue,.Lpowerx5_body,.Lpowerx5_epilogue	# HandlerData[]
++___
++$code.=<<___;
++.align	8
++.LSEH_info_bn_gather5:
++	.byte	0x01,0x0b,0x03,0x0a
++	.byte	0x0b,0x01,0x21,0x00	# sub	rsp,0x108
++	.byte	0x04,0xa3,0x00,0x00	# lea	r10,(rsp)
++.align	8
++___
++}
++
++$code =~ s/\`([^\`]*)\`/eval($1)/gem;
++
++print $code;
++close STDOUT;
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/bn/bn_add.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/bn/bn_add.c
+new file mode 100644
+index 0000000..6479650
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/bn/bn_add.c
+@@ -0,0 +1,205 @@
++/*
++ * Copyright 1995-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include "internal/cryptlib.h"
++#include "bn_lcl.h"
++
++/* r can == a or b */
++int BN_add(BIGNUM *r, const BIGNUM *a, const BIGNUM *b)
++{
++    int a_neg = a->neg, ret;
++
++    bn_check_top(a);
++    bn_check_top(b);
++
++    /*-
++     *  a +  b      a+b
++     *  a + -b      a-b
++     * -a +  b      b-a
++     * -a + -b      -(a+b)
++     */
++    if (a_neg ^ b->neg) {
++        /* only one is negative */
++        if (a_neg) {
++            const BIGNUM *tmp;
++
++            tmp = a;
++            a = b;
++            b = tmp;
++        }
++
++        /* we are now a - b */
++
++        if (BN_ucmp(a, b) < 0) {
++            if (!BN_usub(r, b, a))
++                return 0;
++            r->neg = 1;
++        } else {
++            if (!BN_usub(r, a, b))
++                return 0;
++            r->neg = 0;
++        }
++        return 1;
++    }
++
++    ret = BN_uadd(r, a, b);
++    r->neg = a_neg;
++    bn_check_top(r);
++    return ret;
++}
++
++/* unsigned add of b to a */
++int BN_uadd(BIGNUM *r, const BIGNUM *a, const BIGNUM *b)
++{
++    int max, min, dif;
++    const BN_ULONG *ap, *bp;
++    BN_ULONG *rp, carry, t1, t2;
++
++    bn_check_top(a);
++    bn_check_top(b);
++
++    if (a->top < b->top) {
++        const BIGNUM *tmp;
++
++        tmp = a;
++        a = b;
++        b = tmp;
++    }
++    max = a->top;
++    min = b->top;
++    dif = max - min;
++
++    if (bn_wexpand(r, max + 1) == NULL)
++        return 0;
++
++    r->top = max;
++
++    ap = a->d;
++    bp = b->d;
++    rp = r->d;
++
++    carry = bn_add_words(rp, ap, bp, min);
++    rp += min;
++    ap += min;
++
++    while (dif) {
++        dif--;
++        t1 = *(ap++);
++        t2 = (t1 + carry) & BN_MASK2;
++        *(rp++) = t2;
++        carry &= (t2 == 0);
++    }
++    *rp = carry;
++    r->top += carry;
++
++    r->neg = 0;
++    bn_check_top(r);
++    return 1;
++}
++
++/* unsigned subtraction of b from a, a must be larger than b. */
++int BN_usub(BIGNUM *r, const BIGNUM *a, const BIGNUM *b)
++{
++    int max, min, dif;
++    BN_ULONG t1, t2, borrow, *rp;
++    const BN_ULONG *ap, *bp;
++
++    bn_check_top(a);
++    bn_check_top(b);
++
++    max = a->top;
++    min = b->top;
++    dif = max - min;
++
++    if (dif < 0) {              /* hmm... should not be happening */
++        BNerr(BN_F_BN_USUB, BN_R_ARG2_LT_ARG3);
++        return 0;
++    }
++
++    if (bn_wexpand(r, max) == NULL)
++        return 0;
++
++    ap = a->d;
++    bp = b->d;
++    rp = r->d;
++
++    borrow = bn_sub_words(rp, ap, bp, min);
++    ap += min;
++    rp += min;
++
++    while (dif) {
++        dif--;
++        t1 = *(ap++);
++        t2 = (t1 - borrow) & BN_MASK2;
++        *(rp++) = t2;
++        borrow &= (t1 == 0);
++    }
++
++    r->top = max;
++    r->neg = 0;
++    bn_correct_top(r);
++    return 1;
++}
++
++int BN_sub(BIGNUM *r, const BIGNUM *a, const BIGNUM *b)
++{
++    int max;
++    int add = 0, neg = 0;
++
++    bn_check_top(a);
++    bn_check_top(b);
++
++    /*-
++     *  a -  b      a-b
++     *  a - -b      a+b
++     * -a -  b      -(a+b)
++     * -a - -b      b-a
++     */
++    if (a->neg) {
++        if (b->neg) {
++            const BIGNUM *tmp;
++
++            tmp = a;
++            a = b;
++            b = tmp;
++        } else {
++            add = 1;
++            neg = 1;
++        }
++    } else {
++        if (b->neg) {
++            add = 1;
++            neg = 0;
++        }
++    }
++
++    if (add) {
++        if (!BN_uadd(r, a, b))
++            return 0;
++        r->neg = neg;
++        return 1;
++    }
++
++    /* We are actually doing a - b :-) */
++
++    max = (a->top > b->top) ? a->top : b->top;
++    if (bn_wexpand(r, max) == NULL)
++        return 0;
++    if (BN_ucmp(a, b) < 0) {
++        if (!BN_usub(r, b, a))
++            return 0;
++        r->neg = 1;
++    } else {
++        if (!BN_usub(r, a, b))
++            return 0;
++        r->neg = 0;
++    }
++    bn_check_top(r);
++    return 1;
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/bn/bn_asm.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/bn/bn_asm.c
+new file mode 100644
+index 0000000..39c6c21
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/bn/bn_asm.c
+@@ -0,0 +1,1039 @@
++/*
++ * Copyright 1995-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include 
++#include "internal/cryptlib.h"
++#include "bn_lcl.h"
++
++#if defined(BN_LLONG) || defined(BN_UMULT_HIGH)
++
++BN_ULONG bn_mul_add_words(BN_ULONG *rp, const BN_ULONG *ap, int num,
++                          BN_ULONG w)
++{
++    BN_ULONG c1 = 0;
++
++    assert(num >= 0);
++    if (num <= 0)
++        return (c1);
++
++# ifndef OPENSSL_SMALL_FOOTPRINT
++    while (num & ~3) {
++        mul_add(rp[0], ap[0], w, c1);
++        mul_add(rp[1], ap[1], w, c1);
++        mul_add(rp[2], ap[2], w, c1);
++        mul_add(rp[3], ap[3], w, c1);
++        ap += 4;
++        rp += 4;
++        num -= 4;
++    }
++# endif
++    while (num) {
++        mul_add(rp[0], ap[0], w, c1);
++        ap++;
++        rp++;
++        num--;
++    }
++
++    return (c1);
++}
++
++BN_ULONG bn_mul_words(BN_ULONG *rp, const BN_ULONG *ap, int num, BN_ULONG w)
++{
++    BN_ULONG c1 = 0;
++
++    assert(num >= 0);
++    if (num <= 0)
++        return (c1);
++
++# ifndef OPENSSL_SMALL_FOOTPRINT
++    while (num & ~3) {
++        mul(rp[0], ap[0], w, c1);
++        mul(rp[1], ap[1], w, c1);
++        mul(rp[2], ap[2], w, c1);
++        mul(rp[3], ap[3], w, c1);
++        ap += 4;
++        rp += 4;
++        num -= 4;
++    }
++# endif
++    while (num) {
++        mul(rp[0], ap[0], w, c1);
++        ap++;
++        rp++;
++        num--;
++    }
++    return (c1);
++}
++
++void bn_sqr_words(BN_ULONG *r, const BN_ULONG *a, int n)
++{
++    assert(n >= 0);
++    if (n <= 0)
++        return;
++
++# ifndef OPENSSL_SMALL_FOOTPRINT
++    while (n & ~3) {
++        sqr(r[0], r[1], a[0]);
++        sqr(r[2], r[3], a[1]);
++        sqr(r[4], r[5], a[2]);
++        sqr(r[6], r[7], a[3]);
++        a += 4;
++        r += 8;
++        n -= 4;
++    }
++# endif
++    while (n) {
++        sqr(r[0], r[1], a[0]);
++        a++;
++        r += 2;
++        n--;
++    }
++}
++
++#else                           /* !(defined(BN_LLONG) ||
++                                 * defined(BN_UMULT_HIGH)) */
++
++BN_ULONG bn_mul_add_words(BN_ULONG *rp, const BN_ULONG *ap, int num,
++                          BN_ULONG w)
++{
++    BN_ULONG c = 0;
++    BN_ULONG bl, bh;
++
++    assert(num >= 0);
++    if (num <= 0)
++        return ((BN_ULONG)0);
++
++    bl = LBITS(w);
++    bh = HBITS(w);
++
++# ifndef OPENSSL_SMALL_FOOTPRINT
++    while (num & ~3) {
++        mul_add(rp[0], ap[0], bl, bh, c);
++        mul_add(rp[1], ap[1], bl, bh, c);
++        mul_add(rp[2], ap[2], bl, bh, c);
++        mul_add(rp[3], ap[3], bl, bh, c);
++        ap += 4;
++        rp += 4;
++        num -= 4;
++    }
++# endif
++    while (num) {
++        mul_add(rp[0], ap[0], bl, bh, c);
++        ap++;
++        rp++;
++        num--;
++    }
++    return (c);
++}
++
++BN_ULONG bn_mul_words(BN_ULONG *rp, const BN_ULONG *ap, int num, BN_ULONG w)
++{
++    BN_ULONG carry = 0;
++    BN_ULONG bl, bh;
++
++    assert(num >= 0);
++    if (num <= 0)
++        return ((BN_ULONG)0);
++
++    bl = LBITS(w);
++    bh = HBITS(w);
++
++# ifndef OPENSSL_SMALL_FOOTPRINT
++    while (num & ~3) {
++        mul(rp[0], ap[0], bl, bh, carry);
++        mul(rp[1], ap[1], bl, bh, carry);
++        mul(rp[2], ap[2], bl, bh, carry);
++        mul(rp[3], ap[3], bl, bh, carry);
++        ap += 4;
++        rp += 4;
++        num -= 4;
++    }
++# endif
++    while (num) {
++        mul(rp[0], ap[0], bl, bh, carry);
++        ap++;
++        rp++;
++        num--;
++    }
++    return (carry);
++}
++
++void bn_sqr_words(BN_ULONG *r, const BN_ULONG *a, int n)
++{
++    assert(n >= 0);
++    if (n <= 0)
++        return;
++
++# ifndef OPENSSL_SMALL_FOOTPRINT
++    while (n & ~3) {
++        sqr64(r[0], r[1], a[0]);
++        sqr64(r[2], r[3], a[1]);
++        sqr64(r[4], r[5], a[2]);
++        sqr64(r[6], r[7], a[3]);
++        a += 4;
++        r += 8;
++        n -= 4;
++    }
++# endif
++    while (n) {
++        sqr64(r[0], r[1], a[0]);
++        a++;
++        r += 2;
++        n--;
++    }
++}
++
++#endif                          /* !(defined(BN_LLONG) ||
++                                 * defined(BN_UMULT_HIGH)) */
++
++#if defined(BN_LLONG) && defined(BN_DIV2W)
++
++BN_ULONG bn_div_words(BN_ULONG h, BN_ULONG l, BN_ULONG d)
++{
++    return ((BN_ULONG)(((((BN_ULLONG) h) << BN_BITS2) | l) / (BN_ULLONG) d));
++}
++
++#else
++
++/* Divide h,l by d and return the result. */
++/* I need to test this some more :-( */
++BN_ULONG bn_div_words(BN_ULONG h, BN_ULONG l, BN_ULONG d)
++{
++    BN_ULONG dh, dl, q, ret = 0, th, tl, t;
++    int i, count = 2;
++
++    if (d == 0)
++        return (BN_MASK2);
++
++    i = BN_num_bits_word(d);
++    assert((i == BN_BITS2) || (h <= (BN_ULONG)1 << i));
++
++    i = BN_BITS2 - i;
++    if (h >= d)
++        h -= d;
++
++    if (i) {
++        d <<= i;
++        h = (h << i) | (l >> (BN_BITS2 - i));
++        l <<= i;
++    }
++    dh = (d & BN_MASK2h) >> BN_BITS4;
++    dl = (d & BN_MASK2l);
++    for (;;) {
++        if ((h >> BN_BITS4) == dh)
++            q = BN_MASK2l;
++        else
++            q = h / dh;
++
++        th = q * dh;
++        tl = dl * q;
++        for (;;) {
++            t = h - th;
++            if ((t & BN_MASK2h) ||
++                ((tl) <= ((t << BN_BITS4) | ((l & BN_MASK2h) >> BN_BITS4))))
++                break;
++            q--;
++            th -= dh;
++            tl -= dl;
++        }
++        t = (tl >> BN_BITS4);
++        tl = (tl << BN_BITS4) & BN_MASK2h;
++        th += t;
++
++        if (l < tl)
++            th++;
++        l -= tl;
++        if (h < th) {
++            h += d;
++            q--;
++        }
++        h -= th;
++
++        if (--count == 0)
++            break;
++
++        ret = q << BN_BITS4;
++        h = ((h << BN_BITS4) | (l >> BN_BITS4)) & BN_MASK2;
++        l = (l & BN_MASK2l) << BN_BITS4;
++    }
++    ret |= q;
++    return (ret);
++}
++#endif                          /* !defined(BN_LLONG) && defined(BN_DIV2W) */
++
++#ifdef BN_LLONG
++BN_ULONG bn_add_words(BN_ULONG *r, const BN_ULONG *a, const BN_ULONG *b,
++                      int n)
++{
++    BN_ULLONG ll = 0;
++
++    assert(n >= 0);
++    if (n <= 0)
++        return ((BN_ULONG)0);
++
++# ifndef OPENSSL_SMALL_FOOTPRINT
++    while (n & ~3) {
++        ll += (BN_ULLONG) a[0] + b[0];
++        r[0] = (BN_ULONG)ll & BN_MASK2;
++        ll >>= BN_BITS2;
++        ll += (BN_ULLONG) a[1] + b[1];
++        r[1] = (BN_ULONG)ll & BN_MASK2;
++        ll >>= BN_BITS2;
++        ll += (BN_ULLONG) a[2] + b[2];
++        r[2] = (BN_ULONG)ll & BN_MASK2;
++        ll >>= BN_BITS2;
++        ll += (BN_ULLONG) a[3] + b[3];
++        r[3] = (BN_ULONG)ll & BN_MASK2;
++        ll >>= BN_BITS2;
++        a += 4;
++        b += 4;
++        r += 4;
++        n -= 4;
++    }
++# endif
++    while (n) {
++        ll += (BN_ULLONG) a[0] + b[0];
++        r[0] = (BN_ULONG)ll & BN_MASK2;
++        ll >>= BN_BITS2;
++        a++;
++        b++;
++        r++;
++        n--;
++    }
++    return ((BN_ULONG)ll);
++}
++#else                           /* !BN_LLONG */
++BN_ULONG bn_add_words(BN_ULONG *r, const BN_ULONG *a, const BN_ULONG *b,
++                      int n)
++{
++    BN_ULONG c, l, t;
++
++    assert(n >= 0);
++    if (n <= 0)
++        return ((BN_ULONG)0);
++
++    c = 0;
++# ifndef OPENSSL_SMALL_FOOTPRINT
++    while (n & ~3) {
++        t = a[0];
++        t = (t + c) & BN_MASK2;
++        c = (t < c);
++        l = (t + b[0]) & BN_MASK2;
++        c += (l < t);
++        r[0] = l;
++        t = a[1];
++        t = (t + c) & BN_MASK2;
++        c = (t < c);
++        l = (t + b[1]) & BN_MASK2;
++        c += (l < t);
++        r[1] = l;
++        t = a[2];
++        t = (t + c) & BN_MASK2;
++        c = (t < c);
++        l = (t + b[2]) & BN_MASK2;
++        c += (l < t);
++        r[2] = l;
++        t = a[3];
++        t = (t + c) & BN_MASK2;
++        c = (t < c);
++        l = (t + b[3]) & BN_MASK2;
++        c += (l < t);
++        r[3] = l;
++        a += 4;
++        b += 4;
++        r += 4;
++        n -= 4;
++    }
++# endif
++    while (n) {
++        t = a[0];
++        t = (t + c) & BN_MASK2;
++        c = (t < c);
++        l = (t + b[0]) & BN_MASK2;
++        c += (l < t);
++        r[0] = l;
++        a++;
++        b++;
++        r++;
++        n--;
++    }
++    return ((BN_ULONG)c);
++}
++#endif                          /* !BN_LLONG */
++
++BN_ULONG bn_sub_words(BN_ULONG *r, const BN_ULONG *a, const BN_ULONG *b,
++                      int n)
++{
++    BN_ULONG t1, t2;
++    int c = 0;
++
++    assert(n >= 0);
++    if (n <= 0)
++        return ((BN_ULONG)0);
++
++#ifndef OPENSSL_SMALL_FOOTPRINT
++    while (n & ~3) {
++        t1 = a[0];
++        t2 = b[0];
++        r[0] = (t1 - t2 - c) & BN_MASK2;
++        if (t1 != t2)
++            c = (t1 < t2);
++        t1 = a[1];
++        t2 = b[1];
++        r[1] = (t1 - t2 - c) & BN_MASK2;
++        if (t1 != t2)
++            c = (t1 < t2);
++        t1 = a[2];
++        t2 = b[2];
++        r[2] = (t1 - t2 - c) & BN_MASK2;
++        if (t1 != t2)
++            c = (t1 < t2);
++        t1 = a[3];
++        t2 = b[3];
++        r[3] = (t1 - t2 - c) & BN_MASK2;
++        if (t1 != t2)
++            c = (t1 < t2);
++        a += 4;
++        b += 4;
++        r += 4;
++        n -= 4;
++    }
++#endif
++    while (n) {
++        t1 = a[0];
++        t2 = b[0];
++        r[0] = (t1 - t2 - c) & BN_MASK2;
++        if (t1 != t2)
++            c = (t1 < t2);
++        a++;
++        b++;
++        r++;
++        n--;
++    }
++    return (c);
++}
++
++#if defined(BN_MUL_COMBA) && !defined(OPENSSL_SMALL_FOOTPRINT)
++
++# undef bn_mul_comba8
++# undef bn_mul_comba4
++# undef bn_sqr_comba8
++# undef bn_sqr_comba4
++
++/* mul_add_c(a,b,c0,c1,c2)  -- c+=a*b for three word number c=(c2,c1,c0) */
++/* mul_add_c2(a,b,c0,c1,c2) -- c+=2*a*b for three word number c=(c2,c1,c0) */
++/* sqr_add_c(a,i,c0,c1,c2)  -- c+=a[i]^2 for three word number c=(c2,c1,c0) */
++/*
++ * sqr_add_c2(a,i,c0,c1,c2) -- c+=2*a[i]*a[j] for three word number
++ * c=(c2,c1,c0)
++ */
++
++# ifdef BN_LLONG
++/*
++ * Keep in mind that additions to multiplication result can not
++ * overflow, because its high half cannot be all-ones.
++ */
++#  define mul_add_c(a,b,c0,c1,c2)       do {    \
++        BN_ULONG hi;                            \
++        BN_ULLONG t = (BN_ULLONG)(a)*(b);       \
++        t += c0;                /* no carry */  \
++        c0 = (BN_ULONG)Lw(t);                   \
++        hi = (BN_ULONG)Hw(t);                   \
++        c1 = (c1+hi)&BN_MASK2; if (c1
++/*
++ * This is essentially reference implementation, which may or may not
++ * result in performance improvement. E.g. on IA-32 this routine was
++ * observed to give 40% faster rsa1024 private key operations and 10%
++ * faster rsa4096 ones, while on AMD64 it improves rsa1024 sign only
++ * by 10% and *worsens* rsa4096 sign by 15%. Once again, it's a
++ * reference implementation, one to be used as starting point for
++ * platform-specific assembler. Mentioned numbers apply to compiler
++ * generated code compiled with and without -DOPENSSL_BN_ASM_MONT and
++ * can vary not only from platform to platform, but even for compiler
++ * versions. Assembler vs. assembler improvement coefficients can
++ * [and are known to] differ and are to be documented elsewhere.
++ */
++int bn_mul_mont(BN_ULONG *rp, const BN_ULONG *ap, const BN_ULONG *bp,
++                const BN_ULONG *np, const BN_ULONG *n0p, int num)
++{
++    BN_ULONG c0, c1, ml, *tp, n0;
++#   ifdef mul64
++    BN_ULONG mh;
++#   endif
++    volatile BN_ULONG *vp;
++    int i = 0, j;
++
++#   if 0                        /* template for platform-specific
++                                 * implementation */
++    if (ap == bp)
++        return bn_sqr_mont(rp, ap, np, n0p, num);
++#   endif
++    vp = tp = alloca((num + 2) * sizeof(BN_ULONG));
++
++    n0 = *n0p;
++
++    c0 = 0;
++    ml = bp[0];
++#   ifdef mul64
++    mh = HBITS(ml);
++    ml = LBITS(ml);
++    for (j = 0; j < num; ++j)
++        mul(tp[j], ap[j], ml, mh, c0);
++#   else
++    for (j = 0; j < num; ++j)
++        mul(tp[j], ap[j], ml, c0);
++#   endif
++
++    tp[num] = c0;
++    tp[num + 1] = 0;
++    goto enter;
++
++    for (i = 0; i < num; i++) {
++        c0 = 0;
++        ml = bp[i];
++#   ifdef mul64
++        mh = HBITS(ml);
++        ml = LBITS(ml);
++        for (j = 0; j < num; ++j)
++            mul_add(tp[j], ap[j], ml, mh, c0);
++#   else
++        for (j = 0; j < num; ++j)
++            mul_add(tp[j], ap[j], ml, c0);
++#   endif
++        c1 = (tp[num] + c0) & BN_MASK2;
++        tp[num] = c1;
++        tp[num + 1] = (c1 < c0 ? 1 : 0);
++ enter:
++        c1 = tp[0];
++        ml = (c1 * n0) & BN_MASK2;
++        c0 = 0;
++#   ifdef mul64
++        mh = HBITS(ml);
++        ml = LBITS(ml);
++        mul_add(c1, np[0], ml, mh, c0);
++#   else
++        mul_add(c1, ml, np[0], c0);
++#   endif
++        for (j = 1; j < num; j++) {
++            c1 = tp[j];
++#   ifdef mul64
++            mul_add(c1, np[j], ml, mh, c0);
++#   else
++            mul_add(c1, ml, np[j], c0);
++#   endif
++            tp[j - 1] = c1 & BN_MASK2;
++        }
++        c1 = (tp[num] + c0) & BN_MASK2;
++        tp[num - 1] = c1;
++        tp[num] = tp[num + 1] + (c1 < c0 ? 1 : 0);
++    }
++
++    if (tp[num] != 0 || tp[num - 1] >= np[num - 1]) {
++        c0 = bn_sub_words(rp, tp, np, num);
++        if (tp[num] != 0 || c0 == 0) {
++            for (i = 0; i < num + 2; i++)
++                vp[i] = 0;
++            return 1;
++        }
++    }
++    for (i = 0; i < num; i++)
++        rp[i] = tp[i], vp[i] = 0;
++    vp[num] = 0;
++    vp[num + 1] = 0;
++    return 1;
++}
++#  else
++/*
++ * Return value of 0 indicates that multiplication/convolution was not
++ * performed to signal the caller to fall down to alternative/original
++ * code-path.
++ */
++int bn_mul_mont(BN_ULONG *rp, const BN_ULONG *ap, const BN_ULONG *bp,
++                const BN_ULONG *np, const BN_ULONG *n0, int num)
++{
++    return 0;
++}
++#  endif                        /* OPENSSL_BN_ASM_MONT */
++# endif
++
++#else                           /* !BN_MUL_COMBA */
++
++/* hmm... is it faster just to do a multiply? */
++# undef bn_sqr_comba4
++# undef bn_sqr_comba8
++void bn_sqr_comba4(BN_ULONG *r, const BN_ULONG *a)
++{
++    BN_ULONG t[8];
++    bn_sqr_normal(r, a, 4, t);
++}
++
++void bn_sqr_comba8(BN_ULONG *r, const BN_ULONG *a)
++{
++    BN_ULONG t[16];
++    bn_sqr_normal(r, a, 8, t);
++}
++
++void bn_mul_comba4(BN_ULONG *r, BN_ULONG *a, BN_ULONG *b)
++{
++    r[4] = bn_mul_words(&(r[0]), a, 4, b[0]);
++    r[5] = bn_mul_add_words(&(r[1]), a, 4, b[1]);
++    r[6] = bn_mul_add_words(&(r[2]), a, 4, b[2]);
++    r[7] = bn_mul_add_words(&(r[3]), a, 4, b[3]);
++}
++
++void bn_mul_comba8(BN_ULONG *r, BN_ULONG *a, BN_ULONG *b)
++{
++    r[8] = bn_mul_words(&(r[0]), a, 8, b[0]);
++    r[9] = bn_mul_add_words(&(r[1]), a, 8, b[1]);
++    r[10] = bn_mul_add_words(&(r[2]), a, 8, b[2]);
++    r[11] = bn_mul_add_words(&(r[3]), a, 8, b[3]);
++    r[12] = bn_mul_add_words(&(r[4]), a, 8, b[4]);
++    r[13] = bn_mul_add_words(&(r[5]), a, 8, b[5]);
++    r[14] = bn_mul_add_words(&(r[6]), a, 8, b[6]);
++    r[15] = bn_mul_add_words(&(r[7]), a, 8, b[7]);
++}
++
++# ifdef OPENSSL_NO_ASM
++#  ifdef OPENSSL_BN_ASM_MONT
++#   include 
++int bn_mul_mont(BN_ULONG *rp, const BN_ULONG *ap, const BN_ULONG *bp,
++                const BN_ULONG *np, const BN_ULONG *n0p, int num)
++{
++    BN_ULONG c0, c1, *tp, n0 = *n0p;
++    volatile BN_ULONG *vp;
++    int i = 0, j;
++
++    vp = tp = alloca((num + 2) * sizeof(BN_ULONG));
++
++    for (i = 0; i <= num; i++)
++        tp[i] = 0;
++
++    for (i = 0; i < num; i++) {
++        c0 = bn_mul_add_words(tp, ap, num, bp[i]);
++        c1 = (tp[num] + c0) & BN_MASK2;
++        tp[num] = c1;
++        tp[num + 1] = (c1 < c0 ? 1 : 0);
++
++        c0 = bn_mul_add_words(tp, np, num, tp[0] * n0);
++        c1 = (tp[num] + c0) & BN_MASK2;
++        tp[num] = c1;
++        tp[num + 1] += (c1 < c0 ? 1 : 0);
++        for (j = 0; j <= num; j++)
++            tp[j] = tp[j + 1];
++    }
++
++    if (tp[num] != 0 || tp[num - 1] >= np[num - 1]) {
++        c0 = bn_sub_words(rp, tp, np, num);
++        if (tp[num] != 0 || c0 == 0) {
++            for (i = 0; i < num + 2; i++)
++                vp[i] = 0;
++            return 1;
++        }
++    }
++    for (i = 0; i < num; i++)
++        rp[i] = tp[i], vp[i] = 0;
++    vp[num] = 0;
++    vp[num + 1] = 0;
++    return 1;
++}
++#  else
++int bn_mul_mont(BN_ULONG *rp, const BN_ULONG *ap, const BN_ULONG *bp,
++                const BN_ULONG *np, const BN_ULONG *n0, int num)
++{
++    return 0;
++}
++#  endif                        /* OPENSSL_BN_ASM_MONT */
++# endif
++
++#endif                          /* !BN_MUL_COMBA */
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/bn/bn_blind.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/bn/bn_blind.c
+new file mode 100644
+index 0000000..24d1383
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/bn/bn_blind.c
+@@ -0,0 +1,289 @@
++/*
++ * Copyright 1998-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include "internal/cryptlib.h"
++#include "bn_lcl.h"
++
++#define BN_BLINDING_COUNTER     32
++
++struct bn_blinding_st {
++    BIGNUM *A;
++    BIGNUM *Ai;
++    BIGNUM *e;
++    BIGNUM *mod;                /* just a reference */
++    CRYPTO_THREAD_ID tid;
++    int counter;
++    unsigned long flags;
++    BN_MONT_CTX *m_ctx;
++    int (*bn_mod_exp) (BIGNUM *r, const BIGNUM *a, const BIGNUM *p,
++                       const BIGNUM *m, BN_CTX *ctx, BN_MONT_CTX *m_ctx);
++    CRYPTO_RWLOCK *lock;
++};
++
++BN_BLINDING *BN_BLINDING_new(const BIGNUM *A, const BIGNUM *Ai, BIGNUM *mod)
++{
++    BN_BLINDING *ret = NULL;
++
++    bn_check_top(mod);
++
++    if ((ret = OPENSSL_zalloc(sizeof(*ret))) == NULL) {
++        BNerr(BN_F_BN_BLINDING_NEW, ERR_R_MALLOC_FAILURE);
++        return NULL;
++    }
++
++    ret->lock = CRYPTO_THREAD_lock_new();
++    if (ret->lock == NULL) {
++        BNerr(BN_F_BN_BLINDING_NEW, ERR_R_MALLOC_FAILURE);
++        OPENSSL_free(ret);
++        return NULL;
++    }
++
++    BN_BLINDING_set_current_thread(ret);
++
++    if (A != NULL) {
++        if ((ret->A = BN_dup(A)) == NULL)
++            goto err;
++    }
++
++    if (Ai != NULL) {
++        if ((ret->Ai = BN_dup(Ai)) == NULL)
++            goto err;
++    }
++
++    /* save a copy of mod in the BN_BLINDING structure */
++    if ((ret->mod = BN_dup(mod)) == NULL)
++        goto err;
++
++    if (BN_get_flags(mod, BN_FLG_CONSTTIME) != 0)
++        BN_set_flags(ret->mod, BN_FLG_CONSTTIME);
++
++    /*
++     * Set the counter to the special value -1 to indicate that this is
++     * never-used fresh blinding that does not need updating before first
++     * use.
++     */
++    ret->counter = -1;
++
++    return ret;
++
++ err:
++    BN_BLINDING_free(ret);
++    return NULL;
++}
++
++void BN_BLINDING_free(BN_BLINDING *r)
++{
++    if (r == NULL)
++        return;
++
++    BN_free(r->A);
++    BN_free(r->Ai);
++    BN_free(r->e);
++    BN_free(r->mod);
++    CRYPTO_THREAD_lock_free(r->lock);
++    OPENSSL_free(r);
++}
++
++int BN_BLINDING_update(BN_BLINDING *b, BN_CTX *ctx)
++{
++    int ret = 0;
++
++    if ((b->A == NULL) || (b->Ai == NULL)) {
++        BNerr(BN_F_BN_BLINDING_UPDATE, BN_R_NOT_INITIALIZED);
++        goto err;
++    }
++
++    if (b->counter == -1)
++        b->counter = 0;
++
++    if (++b->counter == BN_BLINDING_COUNTER && b->e != NULL &&
++        !(b->flags & BN_BLINDING_NO_RECREATE)) {
++        /* re-create blinding parameters */
++        if (!BN_BLINDING_create_param(b, NULL, NULL, ctx, NULL, NULL))
++            goto err;
++    } else if (!(b->flags & BN_BLINDING_NO_UPDATE)) {
++        if (!BN_mod_mul(b->A, b->A, b->A, b->mod, ctx))
++            goto err;
++        if (!BN_mod_mul(b->Ai, b->Ai, b->Ai, b->mod, ctx))
++            goto err;
++    }
++
++    ret = 1;
++ err:
++    if (b->counter == BN_BLINDING_COUNTER)
++        b->counter = 0;
++    return (ret);
++}
++
++int BN_BLINDING_convert(BIGNUM *n, BN_BLINDING *b, BN_CTX *ctx)
++{
++    return BN_BLINDING_convert_ex(n, NULL, b, ctx);
++}
++
++int BN_BLINDING_convert_ex(BIGNUM *n, BIGNUM *r, BN_BLINDING *b, BN_CTX *ctx)
++{
++    int ret = 1;
++
++    bn_check_top(n);
++
++    if ((b->A == NULL) || (b->Ai == NULL)) {
++        BNerr(BN_F_BN_BLINDING_CONVERT_EX, BN_R_NOT_INITIALIZED);
++        return (0);
++    }
++
++    if (b->counter == -1)
++        /* Fresh blinding, doesn't need updating. */
++        b->counter = 0;
++    else if (!BN_BLINDING_update(b, ctx))
++        return (0);
++
++    if (r != NULL) {
++        if (!BN_copy(r, b->Ai))
++            ret = 0;
++    }
++
++    if (!BN_mod_mul(n, n, b->A, b->mod, ctx))
++        ret = 0;
++
++    return ret;
++}
++
++int BN_BLINDING_invert(BIGNUM *n, BN_BLINDING *b, BN_CTX *ctx)
++{
++    return BN_BLINDING_invert_ex(n, NULL, b, ctx);
++}
++
++int BN_BLINDING_invert_ex(BIGNUM *n, const BIGNUM *r, BN_BLINDING *b,
++                          BN_CTX *ctx)
++{
++    int ret;
++
++    bn_check_top(n);
++
++    if (r != NULL)
++        ret = BN_mod_mul(n, n, r, b->mod, ctx);
++    else {
++        if (b->Ai == NULL) {
++            BNerr(BN_F_BN_BLINDING_INVERT_EX, BN_R_NOT_INITIALIZED);
++            return (0);
++        }
++        ret = BN_mod_mul(n, n, b->Ai, b->mod, ctx);
++    }
++
++    bn_check_top(n);
++    return (ret);
++}
++
++int BN_BLINDING_is_current_thread(BN_BLINDING *b)
++{
++    return CRYPTO_THREAD_compare_id(CRYPTO_THREAD_get_current_id(), b->tid);
++}
++
++void BN_BLINDING_set_current_thread(BN_BLINDING *b)
++{
++    b->tid = CRYPTO_THREAD_get_current_id();
++}
++
++int BN_BLINDING_lock(BN_BLINDING *b)
++{
++    return CRYPTO_THREAD_write_lock(b->lock);
++}
++
++int BN_BLINDING_unlock(BN_BLINDING *b)
++{
++    return CRYPTO_THREAD_unlock(b->lock);
++}
++
++unsigned long BN_BLINDING_get_flags(const BN_BLINDING *b)
++{
++    return b->flags;
++}
++
++void BN_BLINDING_set_flags(BN_BLINDING *b, unsigned long flags)
++{
++    b->flags = flags;
++}
++
++BN_BLINDING *BN_BLINDING_create_param(BN_BLINDING *b,
++                                      const BIGNUM *e, BIGNUM *m, BN_CTX *ctx,
++                                      int (*bn_mod_exp) (BIGNUM *r,
++                                                         const BIGNUM *a,
++                                                         const BIGNUM *p,
++                                                         const BIGNUM *m,
++                                                         BN_CTX *ctx,
++                                                         BN_MONT_CTX *m_ctx),
++                                      BN_MONT_CTX *m_ctx)
++{
++    int retry_counter = 32;
++    BN_BLINDING *ret = NULL;
++
++    if (b == NULL)
++        ret = BN_BLINDING_new(NULL, NULL, m);
++    else
++        ret = b;
++
++    if (ret == NULL)
++        goto err;
++
++    if (ret->A == NULL && (ret->A = BN_new()) == NULL)
++        goto err;
++    if (ret->Ai == NULL && (ret->Ai = BN_new()) == NULL)
++        goto err;
++
++    if (e != NULL) {
++        BN_free(ret->e);
++        ret->e = BN_dup(e);
++    }
++    if (ret->e == NULL)
++        goto err;
++
++    if (bn_mod_exp != NULL)
++        ret->bn_mod_exp = bn_mod_exp;
++    if (m_ctx != NULL)
++        ret->m_ctx = m_ctx;
++
++    do {
++        int rv;
++        if (!BN_rand_range(ret->A, ret->mod))
++            goto err;
++        if (!int_bn_mod_inverse(ret->Ai, ret->A, ret->mod, ctx, &rv)) {
++            /*
++             * this should almost never happen for good RSA keys
++             */
++            if (rv) {
++                if (retry_counter-- == 0) {
++                    BNerr(BN_F_BN_BLINDING_CREATE_PARAM,
++                          BN_R_TOO_MANY_ITERATIONS);
++                    goto err;
++                }
++            } else
++                goto err;
++        } else
++            break;
++    } while (1);
++
++    if (ret->bn_mod_exp != NULL && ret->m_ctx != NULL) {
++        if (!ret->bn_mod_exp
++            (ret->A, ret->A, ret->e, ret->mod, ctx, ret->m_ctx))
++            goto err;
++    } else {
++        if (!BN_mod_exp(ret->A, ret->A, ret->e, ret->mod, ctx))
++            goto err;
++    }
++
++    return ret;
++ err:
++    if (b == NULL) {
++        BN_BLINDING_free(ret);
++        ret = NULL;
++    }
++
++    return ret;
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/bn/bn_const.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/bn/bn_const.c
+new file mode 100644
+index 0000000..39dd612
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/bn/bn_const.c
+@@ -0,0 +1,553 @@
++/*
++ * Copyright 2005-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++
++/*-
++ * "First Oakley Default Group" from RFC2409, section 6.1.
++ *
++ * The prime is: 2^768 - 2 ^704 - 1 + 2^64 * { [2^638 pi] + 149686 }
++ *
++ * RFC2409 specifies a generator of 2.
++ * RFC2412 specifies a generator of of 22.
++ */
++
++BIGNUM *BN_get_rfc2409_prime_768(BIGNUM *bn)
++{
++    static const unsigned char RFC2409_PRIME_768[] = {
++        0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
++        0xC9, 0x0F, 0xDA, 0xA2, 0x21, 0x68, 0xC2, 0x34,
++        0xC4, 0xC6, 0x62, 0x8B, 0x80, 0xDC, 0x1C, 0xD1,
++        0x29, 0x02, 0x4E, 0x08, 0x8A, 0x67, 0xCC, 0x74,
++        0x02, 0x0B, 0xBE, 0xA6, 0x3B, 0x13, 0x9B, 0x22,
++        0x51, 0x4A, 0x08, 0x79, 0x8E, 0x34, 0x04, 0xDD,
++        0xEF, 0x95, 0x19, 0xB3, 0xCD, 0x3A, 0x43, 0x1B,
++        0x30, 0x2B, 0x0A, 0x6D, 0xF2, 0x5F, 0x14, 0x37,
++        0x4F, 0xE1, 0x35, 0x6D, 0x6D, 0x51, 0xC2, 0x45,
++        0xE4, 0x85, 0xB5, 0x76, 0x62, 0x5E, 0x7E, 0xC6,
++        0xF4, 0x4C, 0x42, 0xE9, 0xA6, 0x3A, 0x36, 0x20,
++        0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
++    };
++    return BN_bin2bn(RFC2409_PRIME_768, sizeof(RFC2409_PRIME_768), bn);
++}
++
++/*-
++ * "Second Oakley Default Group" from RFC2409, section 6.2.
++ *
++ * The prime is: 2^1024 - 2^960 - 1 + 2^64 * { [2^894 pi] + 129093 }.
++ *
++ * RFC2409 specifies a generator of 2.
++ * RFC2412 specifies a generator of 22.
++ */
++
++BIGNUM *BN_get_rfc2409_prime_1024(BIGNUM *bn)
++{
++    static const unsigned char RFC2409_PRIME_1024[] = {
++        0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
++        0xC9, 0x0F, 0xDA, 0xA2, 0x21, 0x68, 0xC2, 0x34,
++        0xC4, 0xC6, 0x62, 0x8B, 0x80, 0xDC, 0x1C, 0xD1,
++        0x29, 0x02, 0x4E, 0x08, 0x8A, 0x67, 0xCC, 0x74,
++        0x02, 0x0B, 0xBE, 0xA6, 0x3B, 0x13, 0x9B, 0x22,
++        0x51, 0x4A, 0x08, 0x79, 0x8E, 0x34, 0x04, 0xDD,
++        0xEF, 0x95, 0x19, 0xB3, 0xCD, 0x3A, 0x43, 0x1B,
++        0x30, 0x2B, 0x0A, 0x6D, 0xF2, 0x5F, 0x14, 0x37,
++        0x4F, 0xE1, 0x35, 0x6D, 0x6D, 0x51, 0xC2, 0x45,
++        0xE4, 0x85, 0xB5, 0x76, 0x62, 0x5E, 0x7E, 0xC6,
++        0xF4, 0x4C, 0x42, 0xE9, 0xA6, 0x37, 0xED, 0x6B,
++        0x0B, 0xFF, 0x5C, 0xB6, 0xF4, 0x06, 0xB7, 0xED,
++        0xEE, 0x38, 0x6B, 0xFB, 0x5A, 0x89, 0x9F, 0xA5,
++        0xAE, 0x9F, 0x24, 0x11, 0x7C, 0x4B, 0x1F, 0xE6,
++        0x49, 0x28, 0x66, 0x51, 0xEC, 0xE6, 0x53, 0x81,
++        0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
++    };
++    return BN_bin2bn(RFC2409_PRIME_1024, sizeof(RFC2409_PRIME_1024), bn);
++}
++
++/*-
++ * "1536-bit MODP Group" from RFC3526, Section 2.
++ *
++ * The prime is: 2^1536 - 2^1472 - 1 + 2^64 * { [2^1406 pi] + 741804 }
++ *
++ * RFC3526 specifies a generator of 2.
++ * RFC2312 specifies a generator of 22.
++ */
++
++BIGNUM *BN_get_rfc3526_prime_1536(BIGNUM *bn)
++{
++    static const unsigned char RFC3526_PRIME_1536[] = {
++        0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
++        0xC9, 0x0F, 0xDA, 0xA2, 0x21, 0x68, 0xC2, 0x34,
++        0xC4, 0xC6, 0x62, 0x8B, 0x80, 0xDC, 0x1C, 0xD1,
++        0x29, 0x02, 0x4E, 0x08, 0x8A, 0x67, 0xCC, 0x74,
++        0x02, 0x0B, 0xBE, 0xA6, 0x3B, 0x13, 0x9B, 0x22,
++        0x51, 0x4A, 0x08, 0x79, 0x8E, 0x34, 0x04, 0xDD,
++        0xEF, 0x95, 0x19, 0xB3, 0xCD, 0x3A, 0x43, 0x1B,
++        0x30, 0x2B, 0x0A, 0x6D, 0xF2, 0x5F, 0x14, 0x37,
++        0x4F, 0xE1, 0x35, 0x6D, 0x6D, 0x51, 0xC2, 0x45,
++        0xE4, 0x85, 0xB5, 0x76, 0x62, 0x5E, 0x7E, 0xC6,
++        0xF4, 0x4C, 0x42, 0xE9, 0xA6, 0x37, 0xED, 0x6B,
++        0x0B, 0xFF, 0x5C, 0xB6, 0xF4, 0x06, 0xB7, 0xED,
++        0xEE, 0x38, 0x6B, 0xFB, 0x5A, 0x89, 0x9F, 0xA5,
++        0xAE, 0x9F, 0x24, 0x11, 0x7C, 0x4B, 0x1F, 0xE6,
++        0x49, 0x28, 0x66, 0x51, 0xEC, 0xE4, 0x5B, 0x3D,
++        0xC2, 0x00, 0x7C, 0xB8, 0xA1, 0x63, 0xBF, 0x05,
++        0x98, 0xDA, 0x48, 0x36, 0x1C, 0x55, 0xD3, 0x9A,
++        0x69, 0x16, 0x3F, 0xA8, 0xFD, 0x24, 0xCF, 0x5F,
++        0x83, 0x65, 0x5D, 0x23, 0xDC, 0xA3, 0xAD, 0x96,
++        0x1C, 0x62, 0xF3, 0x56, 0x20, 0x85, 0x52, 0xBB,
++        0x9E, 0xD5, 0x29, 0x07, 0x70, 0x96, 0x96, 0x6D,
++        0x67, 0x0C, 0x35, 0x4E, 0x4A, 0xBC, 0x98, 0x04,
++        0xF1, 0x74, 0x6C, 0x08, 0xCA, 0x23, 0x73, 0x27,
++        0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
++    };
++    return BN_bin2bn(RFC3526_PRIME_1536, sizeof(RFC3526_PRIME_1536), bn);
++}
++
++/*-
++ * "2048-bit MODP Group" from RFC3526, Section 3.
++ *
++ * The prime is: 2^2048 - 2^1984 - 1 + 2^64 * { [2^1918 pi] + 124476 }
++ *
++ * RFC3526 specifies a generator of 2.
++ */
++
++BIGNUM *BN_get_rfc3526_prime_2048(BIGNUM *bn)
++{
++    static const unsigned char RFC3526_PRIME_2048[] = {
++        0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
++        0xC9, 0x0F, 0xDA, 0xA2, 0x21, 0x68, 0xC2, 0x34,
++        0xC4, 0xC6, 0x62, 0x8B, 0x80, 0xDC, 0x1C, 0xD1,
++        0x29, 0x02, 0x4E, 0x08, 0x8A, 0x67, 0xCC, 0x74,
++        0x02, 0x0B, 0xBE, 0xA6, 0x3B, 0x13, 0x9B, 0x22,
++        0x51, 0x4A, 0x08, 0x79, 0x8E, 0x34, 0x04, 0xDD,
++        0xEF, 0x95, 0x19, 0xB3, 0xCD, 0x3A, 0x43, 0x1B,
++        0x30, 0x2B, 0x0A, 0x6D, 0xF2, 0x5F, 0x14, 0x37,
++        0x4F, 0xE1, 0x35, 0x6D, 0x6D, 0x51, 0xC2, 0x45,
++        0xE4, 0x85, 0xB5, 0x76, 0x62, 0x5E, 0x7E, 0xC6,
++        0xF4, 0x4C, 0x42, 0xE9, 0xA6, 0x37, 0xED, 0x6B,
++        0x0B, 0xFF, 0x5C, 0xB6, 0xF4, 0x06, 0xB7, 0xED,
++        0xEE, 0x38, 0x6B, 0xFB, 0x5A, 0x89, 0x9F, 0xA5,
++        0xAE, 0x9F, 0x24, 0x11, 0x7C, 0x4B, 0x1F, 0xE6,
++        0x49, 0x28, 0x66, 0x51, 0xEC, 0xE4, 0x5B, 0x3D,
++        0xC2, 0x00, 0x7C, 0xB8, 0xA1, 0x63, 0xBF, 0x05,
++        0x98, 0xDA, 0x48, 0x36, 0x1C, 0x55, 0xD3, 0x9A,
++        0x69, 0x16, 0x3F, 0xA8, 0xFD, 0x24, 0xCF, 0x5F,
++        0x83, 0x65, 0x5D, 0x23, 0xDC, 0xA3, 0xAD, 0x96,
++        0x1C, 0x62, 0xF3, 0x56, 0x20, 0x85, 0x52, 0xBB,
++        0x9E, 0xD5, 0x29, 0x07, 0x70, 0x96, 0x96, 0x6D,
++        0x67, 0x0C, 0x35, 0x4E, 0x4A, 0xBC, 0x98, 0x04,
++        0xF1, 0x74, 0x6C, 0x08, 0xCA, 0x18, 0x21, 0x7C,
++        0x32, 0x90, 0x5E, 0x46, 0x2E, 0x36, 0xCE, 0x3B,
++        0xE3, 0x9E, 0x77, 0x2C, 0x18, 0x0E, 0x86, 0x03,
++        0x9B, 0x27, 0x83, 0xA2, 0xEC, 0x07, 0xA2, 0x8F,
++        0xB5, 0xC5, 0x5D, 0xF0, 0x6F, 0x4C, 0x52, 0xC9,
++        0xDE, 0x2B, 0xCB, 0xF6, 0x95, 0x58, 0x17, 0x18,
++        0x39, 0x95, 0x49, 0x7C, 0xEA, 0x95, 0x6A, 0xE5,
++        0x15, 0xD2, 0x26, 0x18, 0x98, 0xFA, 0x05, 0x10,
++        0x15, 0x72, 0x8E, 0x5A, 0x8A, 0xAC, 0xAA, 0x68,
++        0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
++    };
++    return BN_bin2bn(RFC3526_PRIME_2048, sizeof(RFC3526_PRIME_2048), bn);
++}
++
++/*-
++ * "3072-bit MODP Group" from RFC3526, Section 4.
++ *
++ * The prime is: 2^3072 - 2^3008 - 1 + 2^64 * { [2^2942 pi] + 1690314 }
++ *
++ * RFC3526 specifies a generator of 2.
++ */
++
++BIGNUM *BN_get_rfc3526_prime_3072(BIGNUM *bn)
++{
++    static const unsigned char RFC3526_PRIME_3072[] = {
++        0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
++        0xC9, 0x0F, 0xDA, 0xA2, 0x21, 0x68, 0xC2, 0x34,
++        0xC4, 0xC6, 0x62, 0x8B, 0x80, 0xDC, 0x1C, 0xD1,
++        0x29, 0x02, 0x4E, 0x08, 0x8A, 0x67, 0xCC, 0x74,
++        0x02, 0x0B, 0xBE, 0xA6, 0x3B, 0x13, 0x9B, 0x22,
++        0x51, 0x4A, 0x08, 0x79, 0x8E, 0x34, 0x04, 0xDD,
++        0xEF, 0x95, 0x19, 0xB3, 0xCD, 0x3A, 0x43, 0x1B,
++        0x30, 0x2B, 0x0A, 0x6D, 0xF2, 0x5F, 0x14, 0x37,
++        0x4F, 0xE1, 0x35, 0x6D, 0x6D, 0x51, 0xC2, 0x45,
++        0xE4, 0x85, 0xB5, 0x76, 0x62, 0x5E, 0x7E, 0xC6,
++        0xF4, 0x4C, 0x42, 0xE9, 0xA6, 0x37, 0xED, 0x6B,
++        0x0B, 0xFF, 0x5C, 0xB6, 0xF4, 0x06, 0xB7, 0xED,
++        0xEE, 0x38, 0x6B, 0xFB, 0x5A, 0x89, 0x9F, 0xA5,
++        0xAE, 0x9F, 0x24, 0x11, 0x7C, 0x4B, 0x1F, 0xE6,
++        0x49, 0x28, 0x66, 0x51, 0xEC, 0xE4, 0x5B, 0x3D,
++        0xC2, 0x00, 0x7C, 0xB8, 0xA1, 0x63, 0xBF, 0x05,
++        0x98, 0xDA, 0x48, 0x36, 0x1C, 0x55, 0xD3, 0x9A,
++        0x69, 0x16, 0x3F, 0xA8, 0xFD, 0x24, 0xCF, 0x5F,
++        0x83, 0x65, 0x5D, 0x23, 0xDC, 0xA3, 0xAD, 0x96,
++        0x1C, 0x62, 0xF3, 0x56, 0x20, 0x85, 0x52, 0xBB,
++        0x9E, 0xD5, 0x29, 0x07, 0x70, 0x96, 0x96, 0x6D,
++        0x67, 0x0C, 0x35, 0x4E, 0x4A, 0xBC, 0x98, 0x04,
++        0xF1, 0x74, 0x6C, 0x08, 0xCA, 0x18, 0x21, 0x7C,
++        0x32, 0x90, 0x5E, 0x46, 0x2E, 0x36, 0xCE, 0x3B,
++        0xE3, 0x9E, 0x77, 0x2C, 0x18, 0x0E, 0x86, 0x03,
++        0x9B, 0x27, 0x83, 0xA2, 0xEC, 0x07, 0xA2, 0x8F,
++        0xB5, 0xC5, 0x5D, 0xF0, 0x6F, 0x4C, 0x52, 0xC9,
++        0xDE, 0x2B, 0xCB, 0xF6, 0x95, 0x58, 0x17, 0x18,
++        0x39, 0x95, 0x49, 0x7C, 0xEA, 0x95, 0x6A, 0xE5,
++        0x15, 0xD2, 0x26, 0x18, 0x98, 0xFA, 0x05, 0x10,
++        0x15, 0x72, 0x8E, 0x5A, 0x8A, 0xAA, 0xC4, 0x2D,
++        0xAD, 0x33, 0x17, 0x0D, 0x04, 0x50, 0x7A, 0x33,
++        0xA8, 0x55, 0x21, 0xAB, 0xDF, 0x1C, 0xBA, 0x64,
++        0xEC, 0xFB, 0x85, 0x04, 0x58, 0xDB, 0xEF, 0x0A,
++        0x8A, 0xEA, 0x71, 0x57, 0x5D, 0x06, 0x0C, 0x7D,
++        0xB3, 0x97, 0x0F, 0x85, 0xA6, 0xE1, 0xE4, 0xC7,
++        0xAB, 0xF5, 0xAE, 0x8C, 0xDB, 0x09, 0x33, 0xD7,
++        0x1E, 0x8C, 0x94, 0xE0, 0x4A, 0x25, 0x61, 0x9D,
++        0xCE, 0xE3, 0xD2, 0x26, 0x1A, 0xD2, 0xEE, 0x6B,
++        0xF1, 0x2F, 0xFA, 0x06, 0xD9, 0x8A, 0x08, 0x64,
++        0xD8, 0x76, 0x02, 0x73, 0x3E, 0xC8, 0x6A, 0x64,
++        0x52, 0x1F, 0x2B, 0x18, 0x17, 0x7B, 0x20, 0x0C,
++        0xBB, 0xE1, 0x17, 0x57, 0x7A, 0x61, 0x5D, 0x6C,
++        0x77, 0x09, 0x88, 0xC0, 0xBA, 0xD9, 0x46, 0xE2,
++        0x08, 0xE2, 0x4F, 0xA0, 0x74, 0xE5, 0xAB, 0x31,
++        0x43, 0xDB, 0x5B, 0xFC, 0xE0, 0xFD, 0x10, 0x8E,
++        0x4B, 0x82, 0xD1, 0x20, 0xA9, 0x3A, 0xD2, 0xCA,
++        0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
++    };
++    return BN_bin2bn(RFC3526_PRIME_3072, sizeof(RFC3526_PRIME_3072), bn);
++}
++
++/*-
++ * "4096-bit MODP Group" from RFC3526, Section 5.
++ *
++ * The prime is: 2^4096 - 2^4032 - 1 + 2^64 * { [2^3966 pi] + 240904 }
++ *
++ * RFC3526 specifies a generator of 2.
++ */
++
++BIGNUM *BN_get_rfc3526_prime_4096(BIGNUM *bn)
++{
++    static const unsigned char RFC3526_PRIME_4096[] = {
++        0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
++        0xC9, 0x0F, 0xDA, 0xA2, 0x21, 0x68, 0xC2, 0x34,
++        0xC4, 0xC6, 0x62, 0x8B, 0x80, 0xDC, 0x1C, 0xD1,
++        0x29, 0x02, 0x4E, 0x08, 0x8A, 0x67, 0xCC, 0x74,
++        0x02, 0x0B, 0xBE, 0xA6, 0x3B, 0x13, 0x9B, 0x22,
++        0x51, 0x4A, 0x08, 0x79, 0x8E, 0x34, 0x04, 0xDD,
++        0xEF, 0x95, 0x19, 0xB3, 0xCD, 0x3A, 0x43, 0x1B,
++        0x30, 0x2B, 0x0A, 0x6D, 0xF2, 0x5F, 0x14, 0x37,
++        0x4F, 0xE1, 0x35, 0x6D, 0x6D, 0x51, 0xC2, 0x45,
++        0xE4, 0x85, 0xB5, 0x76, 0x62, 0x5E, 0x7E, 0xC6,
++        0xF4, 0x4C, 0x42, 0xE9, 0xA6, 0x37, 0xED, 0x6B,
++        0x0B, 0xFF, 0x5C, 0xB6, 0xF4, 0x06, 0xB7, 0xED,
++        0xEE, 0x38, 0x6B, 0xFB, 0x5A, 0x89, 0x9F, 0xA5,
++        0xAE, 0x9F, 0x24, 0x11, 0x7C, 0x4B, 0x1F, 0xE6,
++        0x49, 0x28, 0x66, 0x51, 0xEC, 0xE4, 0x5B, 0x3D,
++        0xC2, 0x00, 0x7C, 0xB8, 0xA1, 0x63, 0xBF, 0x05,
++        0x98, 0xDA, 0x48, 0x36, 0x1C, 0x55, 0xD3, 0x9A,
++        0x69, 0x16, 0x3F, 0xA8, 0xFD, 0x24, 0xCF, 0x5F,
++        0x83, 0x65, 0x5D, 0x23, 0xDC, 0xA3, 0xAD, 0x96,
++        0x1C, 0x62, 0xF3, 0x56, 0x20, 0x85, 0x52, 0xBB,
++        0x9E, 0xD5, 0x29, 0x07, 0x70, 0x96, 0x96, 0x6D,
++        0x67, 0x0C, 0x35, 0x4E, 0x4A, 0xBC, 0x98, 0x04,
++        0xF1, 0x74, 0x6C, 0x08, 0xCA, 0x18, 0x21, 0x7C,
++        0x32, 0x90, 0x5E, 0x46, 0x2E, 0x36, 0xCE, 0x3B,
++        0xE3, 0x9E, 0x77, 0x2C, 0x18, 0x0E, 0x86, 0x03,
++        0x9B, 0x27, 0x83, 0xA2, 0xEC, 0x07, 0xA2, 0x8F,
++        0xB5, 0xC5, 0x5D, 0xF0, 0x6F, 0x4C, 0x52, 0xC9,
++        0xDE, 0x2B, 0xCB, 0xF6, 0x95, 0x58, 0x17, 0x18,
++        0x39, 0x95, 0x49, 0x7C, 0xEA, 0x95, 0x6A, 0xE5,
++        0x15, 0xD2, 0x26, 0x18, 0x98, 0xFA, 0x05, 0x10,
++        0x15, 0x72, 0x8E, 0x5A, 0x8A, 0xAA, 0xC4, 0x2D,
++        0xAD, 0x33, 0x17, 0x0D, 0x04, 0x50, 0x7A, 0x33,
++        0xA8, 0x55, 0x21, 0xAB, 0xDF, 0x1C, 0xBA, 0x64,
++        0xEC, 0xFB, 0x85, 0x04, 0x58, 0xDB, 0xEF, 0x0A,
++        0x8A, 0xEA, 0x71, 0x57, 0x5D, 0x06, 0x0C, 0x7D,
++        0xB3, 0x97, 0x0F, 0x85, 0xA6, 0xE1, 0xE4, 0xC7,
++        0xAB, 0xF5, 0xAE, 0x8C, 0xDB, 0x09, 0x33, 0xD7,
++        0x1E, 0x8C, 0x94, 0xE0, 0x4A, 0x25, 0x61, 0x9D,
++        0xCE, 0xE3, 0xD2, 0x26, 0x1A, 0xD2, 0xEE, 0x6B,
++        0xF1, 0x2F, 0xFA, 0x06, 0xD9, 0x8A, 0x08, 0x64,
++        0xD8, 0x76, 0x02, 0x73, 0x3E, 0xC8, 0x6A, 0x64,
++        0x52, 0x1F, 0x2B, 0x18, 0x17, 0x7B, 0x20, 0x0C,
++        0xBB, 0xE1, 0x17, 0x57, 0x7A, 0x61, 0x5D, 0x6C,
++        0x77, 0x09, 0x88, 0xC0, 0xBA, 0xD9, 0x46, 0xE2,
++        0x08, 0xE2, 0x4F, 0xA0, 0x74, 0xE5, 0xAB, 0x31,
++        0x43, 0xDB, 0x5B, 0xFC, 0xE0, 0xFD, 0x10, 0x8E,
++        0x4B, 0x82, 0xD1, 0x20, 0xA9, 0x21, 0x08, 0x01,
++        0x1A, 0x72, 0x3C, 0x12, 0xA7, 0x87, 0xE6, 0xD7,
++        0x88, 0x71, 0x9A, 0x10, 0xBD, 0xBA, 0x5B, 0x26,
++        0x99, 0xC3, 0x27, 0x18, 0x6A, 0xF4, 0xE2, 0x3C,
++        0x1A, 0x94, 0x68, 0x34, 0xB6, 0x15, 0x0B, 0xDA,
++        0x25, 0x83, 0xE9, 0xCA, 0x2A, 0xD4, 0x4C, 0xE8,
++        0xDB, 0xBB, 0xC2, 0xDB, 0x04, 0xDE, 0x8E, 0xF9,
++        0x2E, 0x8E, 0xFC, 0x14, 0x1F, 0xBE, 0xCA, 0xA6,
++        0x28, 0x7C, 0x59, 0x47, 0x4E, 0x6B, 0xC0, 0x5D,
++        0x99, 0xB2, 0x96, 0x4F, 0xA0, 0x90, 0xC3, 0xA2,
++        0x23, 0x3B, 0xA1, 0x86, 0x51, 0x5B, 0xE7, 0xED,
++        0x1F, 0x61, 0x29, 0x70, 0xCE, 0xE2, 0xD7, 0xAF,
++        0xB8, 0x1B, 0xDD, 0x76, 0x21, 0x70, 0x48, 0x1C,
++        0xD0, 0x06, 0x91, 0x27, 0xD5, 0xB0, 0x5A, 0xA9,
++        0x93, 0xB4, 0xEA, 0x98, 0x8D, 0x8F, 0xDD, 0xC1,
++        0x86, 0xFF, 0xB7, 0xDC, 0x90, 0xA6, 0xC0, 0x8F,
++        0x4D, 0xF4, 0x35, 0xC9, 0x34, 0x06, 0x31, 0x99,
++        0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
++    };
++    return BN_bin2bn(RFC3526_PRIME_4096, sizeof(RFC3526_PRIME_4096), bn);
++}
++
++/*-
++ * "6144-bit MODP Group" from RFC3526, Section 6.
++ *
++ * The prime is: 2^6144 - 2^6080 - 1 + 2^64 * { [2^6014 pi] + 929484 }
++ *
++ * RFC3526 specifies a generator of 2.
++ */
++
++BIGNUM *BN_get_rfc3526_prime_6144(BIGNUM *bn)
++{
++    static const unsigned char RFC3526_PRIME_6144[] = {
++        0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
++        0xC9, 0x0F, 0xDA, 0xA2, 0x21, 0x68, 0xC2, 0x34,
++        0xC4, 0xC6, 0x62, 0x8B, 0x80, 0xDC, 0x1C, 0xD1,
++        0x29, 0x02, 0x4E, 0x08, 0x8A, 0x67, 0xCC, 0x74,
++        0x02, 0x0B, 0xBE, 0xA6, 0x3B, 0x13, 0x9B, 0x22,
++        0x51, 0x4A, 0x08, 0x79, 0x8E, 0x34, 0x04, 0xDD,
++        0xEF, 0x95, 0x19, 0xB3, 0xCD, 0x3A, 0x43, 0x1B,
++        0x30, 0x2B, 0x0A, 0x6D, 0xF2, 0x5F, 0x14, 0x37,
++        0x4F, 0xE1, 0x35, 0x6D, 0x6D, 0x51, 0xC2, 0x45,
++        0xE4, 0x85, 0xB5, 0x76, 0x62, 0x5E, 0x7E, 0xC6,
++        0xF4, 0x4C, 0x42, 0xE9, 0xA6, 0x37, 0xED, 0x6B,
++        0x0B, 0xFF, 0x5C, 0xB6, 0xF4, 0x06, 0xB7, 0xED,
++        0xEE, 0x38, 0x6B, 0xFB, 0x5A, 0x89, 0x9F, 0xA5,
++        0xAE, 0x9F, 0x24, 0x11, 0x7C, 0x4B, 0x1F, 0xE6,
++        0x49, 0x28, 0x66, 0x51, 0xEC, 0xE4, 0x5B, 0x3D,
++        0xC2, 0x00, 0x7C, 0xB8, 0xA1, 0x63, 0xBF, 0x05,
++        0x98, 0xDA, 0x48, 0x36, 0x1C, 0x55, 0xD3, 0x9A,
++        0x69, 0x16, 0x3F, 0xA8, 0xFD, 0x24, 0xCF, 0x5F,
++        0x83, 0x65, 0x5D, 0x23, 0xDC, 0xA3, 0xAD, 0x96,
++        0x1C, 0x62, 0xF3, 0x56, 0x20, 0x85, 0x52, 0xBB,
++        0x9E, 0xD5, 0x29, 0x07, 0x70, 0x96, 0x96, 0x6D,
++        0x67, 0x0C, 0x35, 0x4E, 0x4A, 0xBC, 0x98, 0x04,
++        0xF1, 0x74, 0x6C, 0x08, 0xCA, 0x18, 0x21, 0x7C,
++        0x32, 0x90, 0x5E, 0x46, 0x2E, 0x36, 0xCE, 0x3B,
++        0xE3, 0x9E, 0x77, 0x2C, 0x18, 0x0E, 0x86, 0x03,
++        0x9B, 0x27, 0x83, 0xA2, 0xEC, 0x07, 0xA2, 0x8F,
++        0xB5, 0xC5, 0x5D, 0xF0, 0x6F, 0x4C, 0x52, 0xC9,
++        0xDE, 0x2B, 0xCB, 0xF6, 0x95, 0x58, 0x17, 0x18,
++        0x39, 0x95, 0x49, 0x7C, 0xEA, 0x95, 0x6A, 0xE5,
++        0x15, 0xD2, 0x26, 0x18, 0x98, 0xFA, 0x05, 0x10,
++        0x15, 0x72, 0x8E, 0x5A, 0x8A, 0xAA, 0xC4, 0x2D,
++        0xAD, 0x33, 0x17, 0x0D, 0x04, 0x50, 0x7A, 0x33,
++        0xA8, 0x55, 0x21, 0xAB, 0xDF, 0x1C, 0xBA, 0x64,
++        0xEC, 0xFB, 0x85, 0x04, 0x58, 0xDB, 0xEF, 0x0A,
++        0x8A, 0xEA, 0x71, 0x57, 0x5D, 0x06, 0x0C, 0x7D,
++        0xB3, 0x97, 0x0F, 0x85, 0xA6, 0xE1, 0xE4, 0xC7,
++        0xAB, 0xF5, 0xAE, 0x8C, 0xDB, 0x09, 0x33, 0xD7,
++        0x1E, 0x8C, 0x94, 0xE0, 0x4A, 0x25, 0x61, 0x9D,
++        0xCE, 0xE3, 0xD2, 0x26, 0x1A, 0xD2, 0xEE, 0x6B,
++        0xF1, 0x2F, 0xFA, 0x06, 0xD9, 0x8A, 0x08, 0x64,
++        0xD8, 0x76, 0x02, 0x73, 0x3E, 0xC8, 0x6A, 0x64,
++        0x52, 0x1F, 0x2B, 0x18, 0x17, 0x7B, 0x20, 0x0C,
++        0xBB, 0xE1, 0x17, 0x57, 0x7A, 0x61, 0x5D, 0x6C,
++        0x77, 0x09, 0x88, 0xC0, 0xBA, 0xD9, 0x46, 0xE2,
++        0x08, 0xE2, 0x4F, 0xA0, 0x74, 0xE5, 0xAB, 0x31,
++        0x43, 0xDB, 0x5B, 0xFC, 0xE0, 0xFD, 0x10, 0x8E,
++        0x4B, 0x82, 0xD1, 0x20, 0xA9, 0x21, 0x08, 0x01,
++        0x1A, 0x72, 0x3C, 0x12, 0xA7, 0x87, 0xE6, 0xD7,
++        0x88, 0x71, 0x9A, 0x10, 0xBD, 0xBA, 0x5B, 0x26,
++        0x99, 0xC3, 0x27, 0x18, 0x6A, 0xF4, 0xE2, 0x3C,
++        0x1A, 0x94, 0x68, 0x34, 0xB6, 0x15, 0x0B, 0xDA,
++        0x25, 0x83, 0xE9, 0xCA, 0x2A, 0xD4, 0x4C, 0xE8,
++        0xDB, 0xBB, 0xC2, 0xDB, 0x04, 0xDE, 0x8E, 0xF9,
++        0x2E, 0x8E, 0xFC, 0x14, 0x1F, 0xBE, 0xCA, 0xA6,
++        0x28, 0x7C, 0x59, 0x47, 0x4E, 0x6B, 0xC0, 0x5D,
++        0x99, 0xB2, 0x96, 0x4F, 0xA0, 0x90, 0xC3, 0xA2,
++        0x23, 0x3B, 0xA1, 0x86, 0x51, 0x5B, 0xE7, 0xED,
++        0x1F, 0x61, 0x29, 0x70, 0xCE, 0xE2, 0xD7, 0xAF,
++        0xB8, 0x1B, 0xDD, 0x76, 0x21, 0x70, 0x48, 0x1C,
++        0xD0, 0x06, 0x91, 0x27, 0xD5, 0xB0, 0x5A, 0xA9,
++        0x93, 0xB4, 0xEA, 0x98, 0x8D, 0x8F, 0xDD, 0xC1,
++        0x86, 0xFF, 0xB7, 0xDC, 0x90, 0xA6, 0xC0, 0x8F,
++        0x4D, 0xF4, 0x35, 0xC9, 0x34, 0x02, 0x84, 0x92,
++        0x36, 0xC3, 0xFA, 0xB4, 0xD2, 0x7C, 0x70, 0x26,
++        0xC1, 0xD4, 0xDC, 0xB2, 0x60, 0x26, 0x46, 0xDE,
++        0xC9, 0x75, 0x1E, 0x76, 0x3D, 0xBA, 0x37, 0xBD,
++        0xF8, 0xFF, 0x94, 0x06, 0xAD, 0x9E, 0x53, 0x0E,
++        0xE5, 0xDB, 0x38, 0x2F, 0x41, 0x30, 0x01, 0xAE,
++        0xB0, 0x6A, 0x53, 0xED, 0x90, 0x27, 0xD8, 0x31,
++        0x17, 0x97, 0x27, 0xB0, 0x86, 0x5A, 0x89, 0x18,
++        0xDA, 0x3E, 0xDB, 0xEB, 0xCF, 0x9B, 0x14, 0xED,
++        0x44, 0xCE, 0x6C, 0xBA, 0xCE, 0xD4, 0xBB, 0x1B,
++        0xDB, 0x7F, 0x14, 0x47, 0xE6, 0xCC, 0x25, 0x4B,
++        0x33, 0x20, 0x51, 0x51, 0x2B, 0xD7, 0xAF, 0x42,
++        0x6F, 0xB8, 0xF4, 0x01, 0x37, 0x8C, 0xD2, 0xBF,
++        0x59, 0x83, 0xCA, 0x01, 0xC6, 0x4B, 0x92, 0xEC,
++        0xF0, 0x32, 0xEA, 0x15, 0xD1, 0x72, 0x1D, 0x03,
++        0xF4, 0x82, 0xD7, 0xCE, 0x6E, 0x74, 0xFE, 0xF6,
++        0xD5, 0x5E, 0x70, 0x2F, 0x46, 0x98, 0x0C, 0x82,
++        0xB5, 0xA8, 0x40, 0x31, 0x90, 0x0B, 0x1C, 0x9E,
++        0x59, 0xE7, 0xC9, 0x7F, 0xBE, 0xC7, 0xE8, 0xF3,
++        0x23, 0xA9, 0x7A, 0x7E, 0x36, 0xCC, 0x88, 0xBE,
++        0x0F, 0x1D, 0x45, 0xB7, 0xFF, 0x58, 0x5A, 0xC5,
++        0x4B, 0xD4, 0x07, 0xB2, 0x2B, 0x41, 0x54, 0xAA,
++        0xCC, 0x8F, 0x6D, 0x7E, 0xBF, 0x48, 0xE1, 0xD8,
++        0x14, 0xCC, 0x5E, 0xD2, 0x0F, 0x80, 0x37, 0xE0,
++        0xA7, 0x97, 0x15, 0xEE, 0xF2, 0x9B, 0xE3, 0x28,
++        0x06, 0xA1, 0xD5, 0x8B, 0xB7, 0xC5, 0xDA, 0x76,
++        0xF5, 0x50, 0xAA, 0x3D, 0x8A, 0x1F, 0xBF, 0xF0,
++        0xEB, 0x19, 0xCC, 0xB1, 0xA3, 0x13, 0xD5, 0x5C,
++        0xDA, 0x56, 0xC9, 0xEC, 0x2E, 0xF2, 0x96, 0x32,
++        0x38, 0x7F, 0xE8, 0xD7, 0x6E, 0x3C, 0x04, 0x68,
++        0x04, 0x3E, 0x8F, 0x66, 0x3F, 0x48, 0x60, 0xEE,
++        0x12, 0xBF, 0x2D, 0x5B, 0x0B, 0x74, 0x74, 0xD6,
++        0xE6, 0x94, 0xF9, 0x1E, 0x6D, 0xCC, 0x40, 0x24,
++        0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
++    };
++    return BN_bin2bn(RFC3526_PRIME_6144, sizeof(RFC3526_PRIME_6144), bn);
++}
++
++/*-
++ * "8192-bit MODP Group" from RFC3526, Section 7.
++ *
++ * The prime is: 2^8192 - 2^8128 - 1 + 2^64 * { [2^8062 pi] + 4743158 }
++ *
++ * RFC3526 specifies a generator of 2.
++ */
++
++BIGNUM *BN_get_rfc3526_prime_8192(BIGNUM *bn)
++{
++    static const unsigned char RFC3526_PRIME_8192[] = {
++        0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
++        0xC9, 0x0F, 0xDA, 0xA2, 0x21, 0x68, 0xC2, 0x34,
++        0xC4, 0xC6, 0x62, 0x8B, 0x80, 0xDC, 0x1C, 0xD1,
++        0x29, 0x02, 0x4E, 0x08, 0x8A, 0x67, 0xCC, 0x74,
++        0x02, 0x0B, 0xBE, 0xA6, 0x3B, 0x13, 0x9B, 0x22,
++        0x51, 0x4A, 0x08, 0x79, 0x8E, 0x34, 0x04, 0xDD,
++        0xEF, 0x95, 0x19, 0xB3, 0xCD, 0x3A, 0x43, 0x1B,
++        0x30, 0x2B, 0x0A, 0x6D, 0xF2, 0x5F, 0x14, 0x37,
++        0x4F, 0xE1, 0x35, 0x6D, 0x6D, 0x51, 0xC2, 0x45,
++        0xE4, 0x85, 0xB5, 0x76, 0x62, 0x5E, 0x7E, 0xC6,
++        0xF4, 0x4C, 0x42, 0xE9, 0xA6, 0x37, 0xED, 0x6B,
++        0x0B, 0xFF, 0x5C, 0xB6, 0xF4, 0x06, 0xB7, 0xED,
++        0xEE, 0x38, 0x6B, 0xFB, 0x5A, 0x89, 0x9F, 0xA5,
++        0xAE, 0x9F, 0x24, 0x11, 0x7C, 0x4B, 0x1F, 0xE6,
++        0x49, 0x28, 0x66, 0x51, 0xEC, 0xE4, 0x5B, 0x3D,
++        0xC2, 0x00, 0x7C, 0xB8, 0xA1, 0x63, 0xBF, 0x05,
++        0x98, 0xDA, 0x48, 0x36, 0x1C, 0x55, 0xD3, 0x9A,
++        0x69, 0x16, 0x3F, 0xA8, 0xFD, 0x24, 0xCF, 0x5F,
++        0x83, 0x65, 0x5D, 0x23, 0xDC, 0xA3, 0xAD, 0x96,
++        0x1C, 0x62, 0xF3, 0x56, 0x20, 0x85, 0x52, 0xBB,
++        0x9E, 0xD5, 0x29, 0x07, 0x70, 0x96, 0x96, 0x6D,
++        0x67, 0x0C, 0x35, 0x4E, 0x4A, 0xBC, 0x98, 0x04,
++        0xF1, 0x74, 0x6C, 0x08, 0xCA, 0x18, 0x21, 0x7C,
++        0x32, 0x90, 0x5E, 0x46, 0x2E, 0x36, 0xCE, 0x3B,
++        0xE3, 0x9E, 0x77, 0x2C, 0x18, 0x0E, 0x86, 0x03,
++        0x9B, 0x27, 0x83, 0xA2, 0xEC, 0x07, 0xA2, 0x8F,
++        0xB5, 0xC5, 0x5D, 0xF0, 0x6F, 0x4C, 0x52, 0xC9,
++        0xDE, 0x2B, 0xCB, 0xF6, 0x95, 0x58, 0x17, 0x18,
++        0x39, 0x95, 0x49, 0x7C, 0xEA, 0x95, 0x6A, 0xE5,
++        0x15, 0xD2, 0x26, 0x18, 0x98, 0xFA, 0x05, 0x10,
++        0x15, 0x72, 0x8E, 0x5A, 0x8A, 0xAA, 0xC4, 0x2D,
++        0xAD, 0x33, 0x17, 0x0D, 0x04, 0x50, 0x7A, 0x33,
++        0xA8, 0x55, 0x21, 0xAB, 0xDF, 0x1C, 0xBA, 0x64,
++        0xEC, 0xFB, 0x85, 0x04, 0x58, 0xDB, 0xEF, 0x0A,
++        0x8A, 0xEA, 0x71, 0x57, 0x5D, 0x06, 0x0C, 0x7D,
++        0xB3, 0x97, 0x0F, 0x85, 0xA6, 0xE1, 0xE4, 0xC7,
++        0xAB, 0xF5, 0xAE, 0x8C, 0xDB, 0x09, 0x33, 0xD7,
++        0x1E, 0x8C, 0x94, 0xE0, 0x4A, 0x25, 0x61, 0x9D,
++        0xCE, 0xE3, 0xD2, 0x26, 0x1A, 0xD2, 0xEE, 0x6B,
++        0xF1, 0x2F, 0xFA, 0x06, 0xD9, 0x8A, 0x08, 0x64,
++        0xD8, 0x76, 0x02, 0x73, 0x3E, 0xC8, 0x6A, 0x64,
++        0x52, 0x1F, 0x2B, 0x18, 0x17, 0x7B, 0x20, 0x0C,
++        0xBB, 0xE1, 0x17, 0x57, 0x7A, 0x61, 0x5D, 0x6C,
++        0x77, 0x09, 0x88, 0xC0, 0xBA, 0xD9, 0x46, 0xE2,
++        0x08, 0xE2, 0x4F, 0xA0, 0x74, 0xE5, 0xAB, 0x31,
++        0x43, 0xDB, 0x5B, 0xFC, 0xE0, 0xFD, 0x10, 0x8E,
++        0x4B, 0x82, 0xD1, 0x20, 0xA9, 0x21, 0x08, 0x01,
++        0x1A, 0x72, 0x3C, 0x12, 0xA7, 0x87, 0xE6, 0xD7,
++        0x88, 0x71, 0x9A, 0x10, 0xBD, 0xBA, 0x5B, 0x26,
++        0x99, 0xC3, 0x27, 0x18, 0x6A, 0xF4, 0xE2, 0x3C,
++        0x1A, 0x94, 0x68, 0x34, 0xB6, 0x15, 0x0B, 0xDA,
++        0x25, 0x83, 0xE9, 0xCA, 0x2A, 0xD4, 0x4C, 0xE8,
++        0xDB, 0xBB, 0xC2, 0xDB, 0x04, 0xDE, 0x8E, 0xF9,
++        0x2E, 0x8E, 0xFC, 0x14, 0x1F, 0xBE, 0xCA, 0xA6,
++        0x28, 0x7C, 0x59, 0x47, 0x4E, 0x6B, 0xC0, 0x5D,
++        0x99, 0xB2, 0x96, 0x4F, 0xA0, 0x90, 0xC3, 0xA2,
++        0x23, 0x3B, 0xA1, 0x86, 0x51, 0x5B, 0xE7, 0xED,
++        0x1F, 0x61, 0x29, 0x70, 0xCE, 0xE2, 0xD7, 0xAF,
++        0xB8, 0x1B, 0xDD, 0x76, 0x21, 0x70, 0x48, 0x1C,
++        0xD0, 0x06, 0x91, 0x27, 0xD5, 0xB0, 0x5A, 0xA9,
++        0x93, 0xB4, 0xEA, 0x98, 0x8D, 0x8F, 0xDD, 0xC1,
++        0x86, 0xFF, 0xB7, 0xDC, 0x90, 0xA6, 0xC0, 0x8F,
++        0x4D, 0xF4, 0x35, 0xC9, 0x34, 0x02, 0x84, 0x92,
++        0x36, 0xC3, 0xFA, 0xB4, 0xD2, 0x7C, 0x70, 0x26,
++        0xC1, 0xD4, 0xDC, 0xB2, 0x60, 0x26, 0x46, 0xDE,
++        0xC9, 0x75, 0x1E, 0x76, 0x3D, 0xBA, 0x37, 0xBD,
++        0xF8, 0xFF, 0x94, 0x06, 0xAD, 0x9E, 0x53, 0x0E,
++        0xE5, 0xDB, 0x38, 0x2F, 0x41, 0x30, 0x01, 0xAE,
++        0xB0, 0x6A, 0x53, 0xED, 0x90, 0x27, 0xD8, 0x31,
++        0x17, 0x97, 0x27, 0xB0, 0x86, 0x5A, 0x89, 0x18,
++        0xDA, 0x3E, 0xDB, 0xEB, 0xCF, 0x9B, 0x14, 0xED,
++        0x44, 0xCE, 0x6C, 0xBA, 0xCE, 0xD4, 0xBB, 0x1B,
++        0xDB, 0x7F, 0x14, 0x47, 0xE6, 0xCC, 0x25, 0x4B,
++        0x33, 0x20, 0x51, 0x51, 0x2B, 0xD7, 0xAF, 0x42,
++        0x6F, 0xB8, 0xF4, 0x01, 0x37, 0x8C, 0xD2, 0xBF,
++        0x59, 0x83, 0xCA, 0x01, 0xC6, 0x4B, 0x92, 0xEC,
++        0xF0, 0x32, 0xEA, 0x15, 0xD1, 0x72, 0x1D, 0x03,
++        0xF4, 0x82, 0xD7, 0xCE, 0x6E, 0x74, 0xFE, 0xF6,
++        0xD5, 0x5E, 0x70, 0x2F, 0x46, 0x98, 0x0C, 0x82,
++        0xB5, 0xA8, 0x40, 0x31, 0x90, 0x0B, 0x1C, 0x9E,
++        0x59, 0xE7, 0xC9, 0x7F, 0xBE, 0xC7, 0xE8, 0xF3,
++        0x23, 0xA9, 0x7A, 0x7E, 0x36, 0xCC, 0x88, 0xBE,
++        0x0F, 0x1D, 0x45, 0xB7, 0xFF, 0x58, 0x5A, 0xC5,
++        0x4B, 0xD4, 0x07, 0xB2, 0x2B, 0x41, 0x54, 0xAA,
++        0xCC, 0x8F, 0x6D, 0x7E, 0xBF, 0x48, 0xE1, 0xD8,
++        0x14, 0xCC, 0x5E, 0xD2, 0x0F, 0x80, 0x37, 0xE0,
++        0xA7, 0x97, 0x15, 0xEE, 0xF2, 0x9B, 0xE3, 0x28,
++        0x06, 0xA1, 0xD5, 0x8B, 0xB7, 0xC5, 0xDA, 0x76,
++        0xF5, 0x50, 0xAA, 0x3D, 0x8A, 0x1F, 0xBF, 0xF0,
++        0xEB, 0x19, 0xCC, 0xB1, 0xA3, 0x13, 0xD5, 0x5C,
++        0xDA, 0x56, 0xC9, 0xEC, 0x2E, 0xF2, 0x96, 0x32,
++        0x38, 0x7F, 0xE8, 0xD7, 0x6E, 0x3C, 0x04, 0x68,
++        0x04, 0x3E, 0x8F, 0x66, 0x3F, 0x48, 0x60, 0xEE,
++        0x12, 0xBF, 0x2D, 0x5B, 0x0B, 0x74, 0x74, 0xD6,
++        0xE6, 0x94, 0xF9, 0x1E, 0x6D, 0xBE, 0x11, 0x59,
++        0x74, 0xA3, 0x92, 0x6F, 0x12, 0xFE, 0xE5, 0xE4,
++        0x38, 0x77, 0x7C, 0xB6, 0xA9, 0x32, 0xDF, 0x8C,
++        0xD8, 0xBE, 0xC4, 0xD0, 0x73, 0xB9, 0x31, 0xBA,
++        0x3B, 0xC8, 0x32, 0xB6, 0x8D, 0x9D, 0xD3, 0x00,
++        0x74, 0x1F, 0xA7, 0xBF, 0x8A, 0xFC, 0x47, 0xED,
++        0x25, 0x76, 0xF6, 0x93, 0x6B, 0xA4, 0x24, 0x66,
++        0x3A, 0xAB, 0x63, 0x9C, 0x5A, 0xE4, 0xF5, 0x68,
++        0x34, 0x23, 0xB4, 0x74, 0x2B, 0xF1, 0xC9, 0x78,
++        0x23, 0x8F, 0x16, 0xCB, 0xE3, 0x9D, 0x65, 0x2D,
++        0xE3, 0xFD, 0xB8, 0xBE, 0xFC, 0x84, 0x8A, 0xD9,
++        0x22, 0x22, 0x2E, 0x04, 0xA4, 0x03, 0x7C, 0x07,
++        0x13, 0xEB, 0x57, 0xA8, 0x1A, 0x23, 0xF0, 0xC7,
++        0x34, 0x73, 0xFC, 0x64, 0x6C, 0xEA, 0x30, 0x6B,
++        0x4B, 0xCB, 0xC8, 0x86, 0x2F, 0x83, 0x85, 0xDD,
++        0xFA, 0x9D, 0x4B, 0x7F, 0xA2, 0xC0, 0x87, 0xE8,
++        0x79, 0x68, 0x33, 0x03, 0xED, 0x5B, 0xDD, 0x3A,
++        0x06, 0x2B, 0x3C, 0xF5, 0xB3, 0xA2, 0x78, 0xA6,
++        0x6D, 0x2A, 0x13, 0xF8, 0x3F, 0x44, 0xF8, 0x2D,
++        0xDF, 0x31, 0x0E, 0xE0, 0x74, 0xAB, 0x6A, 0x36,
++        0x45, 0x97, 0xE8, 0x99, 0xA0, 0x25, 0x5D, 0xC1,
++        0x64, 0xF3, 0x1C, 0xC5, 0x08, 0x46, 0x85, 0x1D,
++        0xF9, 0xAB, 0x48, 0x19, 0x5D, 0xED, 0x7E, 0xA1,
++        0xB1, 0xD5, 0x10, 0xBD, 0x7E, 0xE7, 0x4D, 0x73,
++        0xFA, 0xF3, 0x6B, 0xC3, 0x1E, 0xCF, 0xA2, 0x68,
++        0x35, 0x90, 0x46, 0xF4, 0xEB, 0x87, 0x9F, 0x92,
++        0x40, 0x09, 0x43, 0x8B, 0x48, 0x1C, 0x6C, 0xD7,
++        0x88, 0x9A, 0x00, 0x2E, 0xD5, 0xEE, 0x38, 0x2B,
++        0xC9, 0x19, 0x0D, 0xA6, 0xFC, 0x02, 0x6E, 0x47,
++        0x95, 0x58, 0xE4, 0x47, 0x56, 0x77, 0xE9, 0xAA,
++        0x9E, 0x30, 0x50, 0xE2, 0x76, 0x56, 0x94, 0xDF,
++        0xC8, 0x1F, 0x56, 0xE8, 0x80, 0xB9, 0x6E, 0x71,
++        0x60, 0xC9, 0x80, 0xDD, 0x98, 0xED, 0xD3, 0xDF,
++        0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
++    };
++    return BN_bin2bn(RFC3526_PRIME_8192, sizeof(RFC3526_PRIME_8192), bn);
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/bn/bn_ctx.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/bn/bn_ctx.c
+new file mode 100644
+index 0000000..68c0468
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/bn/bn_ctx.c
+@@ -0,0 +1,353 @@
++/*
++ * Copyright 2000-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include "internal/cryptlib.h"
++#include "bn_lcl.h"
++
++/*-
++ * TODO list
++ *
++ * 1. Check a bunch of "(words+1)" type hacks in various bignum functions and
++ * check they can be safely removed.
++ *  - Check +1 and other ugliness in BN_from_montgomery()
++ *
++ * 2. Consider allowing a BN_new_ex() that, at least, lets you specify an
++ * appropriate 'block' size that will be honoured by bn_expand_internal() to
++ * prevent piddly little reallocations. OTOH, profiling bignum expansions in
++ * BN_CTX doesn't show this to be a big issue.
++ */
++
++/* How many bignums are in each "pool item"; */
++#define BN_CTX_POOL_SIZE        16
++/* The stack frame info is resizing, set a first-time expansion size; */
++#define BN_CTX_START_FRAMES     32
++
++/***********/
++/* BN_POOL */
++/***********/
++
++/* A bundle of bignums that can be linked with other bundles */
++typedef struct bignum_pool_item {
++    /* The bignum values */
++    BIGNUM vals[BN_CTX_POOL_SIZE];
++    /* Linked-list admin */
++    struct bignum_pool_item *prev, *next;
++} BN_POOL_ITEM;
++/* A linked-list of bignums grouped in bundles */
++typedef struct bignum_pool {
++    /* Linked-list admin */
++    BN_POOL_ITEM *head, *current, *tail;
++    /* Stack depth and allocation size */
++    unsigned used, size;
++} BN_POOL;
++static void BN_POOL_init(BN_POOL *);
++static void BN_POOL_finish(BN_POOL *);
++static BIGNUM *BN_POOL_get(BN_POOL *, int);
++static void BN_POOL_release(BN_POOL *, unsigned int);
++
++/************/
++/* BN_STACK */
++/************/
++
++/* A wrapper to manage the "stack frames" */
++typedef struct bignum_ctx_stack {
++    /* Array of indexes into the bignum stack */
++    unsigned int *indexes;
++    /* Number of stack frames, and the size of the allocated array */
++    unsigned int depth, size;
++} BN_STACK;
++static void BN_STACK_init(BN_STACK *);
++static void BN_STACK_finish(BN_STACK *);
++static int BN_STACK_push(BN_STACK *, unsigned int);
++static unsigned int BN_STACK_pop(BN_STACK *);
++
++/**********/
++/* BN_CTX */
++/**********/
++
++/* The opaque BN_CTX type */
++struct bignum_ctx {
++    /* The bignum bundles */
++    BN_POOL pool;
++    /* The "stack frames", if you will */
++    BN_STACK stack;
++    /* The number of bignums currently assigned */
++    unsigned int used;
++    /* Depth of stack overflow */
++    int err_stack;
++    /* Block "gets" until an "end" (compatibility behaviour) */
++    int too_many;
++    /* Flags. */
++    int flags;
++};
++
++/* Enable this to find BN_CTX bugs */
++#ifdef BN_CTX_DEBUG
++static const char *ctxdbg_cur = NULL;
++static void ctxdbg(BN_CTX *ctx)
++{
++    unsigned int bnidx = 0, fpidx = 0;
++    BN_POOL_ITEM *item = ctx->pool.head;
++    BN_STACK *stack = &ctx->stack;
++    fprintf(stderr, "(%16p): ", ctx);
++    while (bnidx < ctx->used) {
++        fprintf(stderr, "%03x ", item->vals[bnidx++ % BN_CTX_POOL_SIZE].dmax);
++        if (!(bnidx % BN_CTX_POOL_SIZE))
++            item = item->next;
++    }
++    fprintf(stderr, "\n");
++    bnidx = 0;
++    fprintf(stderr, "          : ");
++    while (fpidx < stack->depth) {
++        while (bnidx++ < stack->indexes[fpidx])
++            fprintf(stderr, "    ");
++        fprintf(stderr, "^^^ ");
++        bnidx++;
++        fpidx++;
++    }
++    fprintf(stderr, "\n");
++}
++
++# define CTXDBG_ENTRY(str, ctx)  do { \
++                                ctxdbg_cur = (str); \
++                                fprintf(stderr,"Starting %s\n", ctxdbg_cur); \
++                                ctxdbg(ctx); \
++                                } while(0)
++# define CTXDBG_EXIT(ctx)        do { \
++                                fprintf(stderr,"Ending %s\n", ctxdbg_cur); \
++                                ctxdbg(ctx); \
++                                } while(0)
++# define CTXDBG_RET(ctx,ret)
++#else
++# define CTXDBG_ENTRY(str, ctx)
++# define CTXDBG_EXIT(ctx)
++# define CTXDBG_RET(ctx,ret)
++#endif
++
++
++BN_CTX *BN_CTX_new(void)
++{
++    BN_CTX *ret;
++
++    if ((ret = OPENSSL_zalloc(sizeof(*ret))) == NULL) {
++        BNerr(BN_F_BN_CTX_NEW, ERR_R_MALLOC_FAILURE);
++        return NULL;
++    }
++    /* Initialise the structure */
++    BN_POOL_init(&ret->pool);
++    BN_STACK_init(&ret->stack);
++    return ret;
++}
++
++BN_CTX *BN_CTX_secure_new(void)
++{
++    BN_CTX *ret = BN_CTX_new();
++
++    if (ret != NULL)
++        ret->flags = BN_FLG_SECURE;
++    return ret;
++}
++
++void BN_CTX_free(BN_CTX *ctx)
++{
++    if (ctx == NULL)
++        return;
++#ifdef BN_CTX_DEBUG
++    {
++        BN_POOL_ITEM *pool = ctx->pool.head;
++        fprintf(stderr, "BN_CTX_free, stack-size=%d, pool-bignums=%d\n",
++                ctx->stack.size, ctx->pool.size);
++        fprintf(stderr, "dmaxs: ");
++        while (pool) {
++            unsigned loop = 0;
++            while (loop < BN_CTX_POOL_SIZE)
++                fprintf(stderr, "%02x ", pool->vals[loop++].dmax);
++            pool = pool->next;
++        }
++        fprintf(stderr, "\n");
++    }
++#endif
++    BN_STACK_finish(&ctx->stack);
++    BN_POOL_finish(&ctx->pool);
++    OPENSSL_free(ctx);
++}
++
++void BN_CTX_start(BN_CTX *ctx)
++{
++    CTXDBG_ENTRY("BN_CTX_start", ctx);
++    /* If we're already overflowing ... */
++    if (ctx->err_stack || ctx->too_many)
++        ctx->err_stack++;
++    /* (Try to) get a new frame pointer */
++    else if (!BN_STACK_push(&ctx->stack, ctx->used)) {
++        BNerr(BN_F_BN_CTX_START, BN_R_TOO_MANY_TEMPORARY_VARIABLES);
++        ctx->err_stack++;
++    }
++    CTXDBG_EXIT(ctx);
++}
++
++void BN_CTX_end(BN_CTX *ctx)
++{
++    CTXDBG_ENTRY("BN_CTX_end", ctx);
++    if (ctx->err_stack)
++        ctx->err_stack--;
++    else {
++        unsigned int fp = BN_STACK_pop(&ctx->stack);
++        /* Does this stack frame have anything to release? */
++        if (fp < ctx->used)
++            BN_POOL_release(&ctx->pool, ctx->used - fp);
++        ctx->used = fp;
++        /* Unjam "too_many" in case "get" had failed */
++        ctx->too_many = 0;
++    }
++    CTXDBG_EXIT(ctx);
++}
++
++BIGNUM *BN_CTX_get(BN_CTX *ctx)
++{
++    BIGNUM *ret;
++
++    CTXDBG_ENTRY("BN_CTX_get", ctx);
++    if (ctx->err_stack || ctx->too_many)
++        return NULL;
++    if ((ret = BN_POOL_get(&ctx->pool, ctx->flags)) == NULL) {
++        /*
++         * Setting too_many prevents repeated "get" attempts from cluttering
++         * the error stack.
++         */
++        ctx->too_many = 1;
++        BNerr(BN_F_BN_CTX_GET, BN_R_TOO_MANY_TEMPORARY_VARIABLES);
++        return NULL;
++    }
++    /* OK, make sure the returned bignum is "zero" */
++    BN_zero(ret);
++    ctx->used++;
++    CTXDBG_RET(ctx, ret);
++    return ret;
++}
++
++/************/
++/* BN_STACK */
++/************/
++
++static void BN_STACK_init(BN_STACK *st)
++{
++    st->indexes = NULL;
++    st->depth = st->size = 0;
++}
++
++static void BN_STACK_finish(BN_STACK *st)
++{
++    OPENSSL_free(st->indexes);
++    st->indexes = NULL;
++}
++
++
++static int BN_STACK_push(BN_STACK *st, unsigned int idx)
++{
++    if (st->depth == st->size) {
++        /* Need to expand */
++        unsigned int newsize =
++            st->size ? (st->size * 3 / 2) : BN_CTX_START_FRAMES;
++        unsigned int *newitems = OPENSSL_malloc(sizeof(*newitems) * newsize);
++        if (newitems == NULL)
++            return 0;
++        if (st->depth)
++            memcpy(newitems, st->indexes, sizeof(*newitems) * st->depth);
++        OPENSSL_free(st->indexes);
++        st->indexes = newitems;
++        st->size = newsize;
++    }
++    st->indexes[(st->depth)++] = idx;
++    return 1;
++}
++
++static unsigned int BN_STACK_pop(BN_STACK *st)
++{
++    return st->indexes[--(st->depth)];
++}
++
++/***********/
++/* BN_POOL */
++/***********/
++
++static void BN_POOL_init(BN_POOL *p)
++{
++    p->head = p->current = p->tail = NULL;
++    p->used = p->size = 0;
++}
++
++static void BN_POOL_finish(BN_POOL *p)
++{
++    unsigned int loop;
++    BIGNUM *bn;
++
++    while (p->head) {
++        for (loop = 0, bn = p->head->vals; loop++ < BN_CTX_POOL_SIZE; bn++)
++            if (bn->d)
++                BN_clear_free(bn);
++        p->current = p->head->next;
++        OPENSSL_free(p->head);
++        p->head = p->current;
++    }
++}
++
++
++static BIGNUM *BN_POOL_get(BN_POOL *p, int flag)
++{
++    BIGNUM *bn;
++    unsigned int loop;
++
++    /* Full; allocate a new pool item and link it in. */
++    if (p->used == p->size) {
++        BN_POOL_ITEM *item = OPENSSL_malloc(sizeof(*item));
++        if (item == NULL)
++            return NULL;
++        for (loop = 0, bn = item->vals; loop++ < BN_CTX_POOL_SIZE; bn++) {
++            bn_init(bn);
++            if ((flag & BN_FLG_SECURE) != 0)
++                BN_set_flags(bn, BN_FLG_SECURE);
++        }
++        item->prev = p->tail;
++        item->next = NULL;
++
++        if (p->head == NULL)
++            p->head = p->current = p->tail = item;
++        else {
++            p->tail->next = item;
++            p->tail = item;
++            p->current = item;
++        }
++        p->size += BN_CTX_POOL_SIZE;
++        p->used++;
++        /* Return the first bignum from the new pool */
++        return item->vals;
++    }
++
++    if (!p->used)
++        p->current = p->head;
++    else if ((p->used % BN_CTX_POOL_SIZE) == 0)
++        p->current = p->current->next;
++    return p->current->vals + ((p->used++) % BN_CTX_POOL_SIZE);
++}
++
++static void BN_POOL_release(BN_POOL *p, unsigned int num)
++{
++    unsigned int offset = (p->used - 1) % BN_CTX_POOL_SIZE;
++
++    p->used -= num;
++    while (num--) {
++        bn_check_top(p->current->vals + offset);
++        if (offset == 0) {
++            offset = BN_CTX_POOL_SIZE - 1;
++            p->current = p->current->prev;
++        } else
++            offset--;
++    }
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/bn/bn_depr.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/bn/bn_depr.c
+new file mode 100644
+index 0000000..7d89214
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/bn/bn_depr.c
+@@ -0,0 +1,68 @@
++/*
++ * Copyright 2002-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++/*
++ * Support for deprecated functions goes here - static linkage will only
++ * slurp this code if applications are using them directly.
++ */
++
++#include 
++#if OPENSSL_API_COMPAT >= 0x00908000L
++NON_EMPTY_TRANSLATION_UNIT
++#else
++
++# include 
++# include 
++# include "internal/cryptlib.h"
++# include "bn_lcl.h"
++
++BIGNUM *BN_generate_prime(BIGNUM *ret, int bits, int safe,
++                          const BIGNUM *add, const BIGNUM *rem,
++                          void (*callback) (int, int, void *), void *cb_arg)
++{
++    BN_GENCB cb;
++    BIGNUM *rnd = NULL;
++
++    BN_GENCB_set_old(&cb, callback, cb_arg);
++
++    if (ret == NULL) {
++        if ((rnd = BN_new()) == NULL)
++            goto err;
++    } else
++        rnd = ret;
++    if (!BN_generate_prime_ex(rnd, bits, safe, add, rem, &cb))
++        goto err;
++
++    /* we have a prime :-) */
++    return ret;
++ err:
++    BN_free(rnd);
++    return NULL;
++}
++
++int BN_is_prime(const BIGNUM *a, int checks,
++                void (*callback) (int, int, void *), BN_CTX *ctx_passed,
++                void *cb_arg)
++{
++    BN_GENCB cb;
++    BN_GENCB_set_old(&cb, callback, cb_arg);
++    return BN_is_prime_ex(a, checks, ctx_passed, &cb);
++}
++
++int BN_is_prime_fasttest(const BIGNUM *a, int checks,
++                         void (*callback) (int, int, void *),
++                         BN_CTX *ctx_passed, void *cb_arg,
++                         int do_trial_division)
++{
++    BN_GENCB cb;
++    BN_GENCB_set_old(&cb, callback, cb_arg);
++    return BN_is_prime_fasttest_ex(a, checks, ctx_passed,
++                                   do_trial_division, &cb);
++}
++#endif
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/bn/bn_dh.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/bn/bn_dh.c
+new file mode 100644
+index 0000000..17d0559
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/bn/bn_dh.c
+@@ -0,0 +1,220 @@
++/*
++ * Copyright 2014-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include "bn_lcl.h"
++#include "e_os.h"
++
++#ifndef OPENSSL_NO_DH
++#include 
++#include "internal/bn_dh.h"
++/* DH parameters from RFC5114 */
++
++# if BN_BITS2 == 64
++static const BN_ULONG dh1024_160_p[] = {
++    0xDF1FB2BC2E4A4371ULL, 0xE68CFDA76D4DA708ULL, 0x45BF37DF365C1A65ULL,
++    0xA151AF5F0DC8B4BDULL, 0xFAA31A4FF55BCCC0ULL, 0x4EFFD6FAE5644738ULL,
++    0x98488E9C219A7372ULL, 0xACCBDD7D90C4BD70ULL, 0x24975C3CD49B83BFULL,
++    0x13ECB4AEA9061123ULL, 0x9838EF1E2EE652C0ULL, 0x6073E28675A23D18ULL,
++    0x9A6A9DCA52D23B61ULL, 0x52C99FBCFB06A3C6ULL, 0xDE92DE5EAE5D54ECULL,
++    0xB10B8F96A080E01DULL
++};
++
++static const BN_ULONG dh1024_160_g[] = {
++    0x855E6EEB22B3B2E5ULL, 0x858F4DCEF97C2A24ULL, 0x2D779D5918D08BC8ULL,
++    0xD662A4D18E73AFA3ULL, 0x1DBF0A0169B6A28AULL, 0xA6A24C087A091F53ULL,
++    0x909D0D2263F80A76ULL, 0xD7FBD7D3B9A92EE1ULL, 0x5E91547F9E2749F4ULL,
++    0x160217B4B01B886AULL, 0x777E690F5504F213ULL, 0x266FEA1E5C41564BULL,
++    0xD6406CFF14266D31ULL, 0xF8104DD258AC507FULL, 0x6765A442EFB99905ULL,
++    0xA4D1CBD5C3FD3412ULL
++};
++
++static const BN_ULONG dh1024_160_q[] = {
++    0x64B7CB9D49462353ULL, 0x81A8DF278ABA4E7DULL, 0x00000000F518AA87ULL
++};
++
++static const BN_ULONG dh2048_224_p[] = {
++    0x0AC4DFFE0C10E64FULL, 0xCF9DE5384E71B81CULL, 0x7EF363E2FFA31F71ULL,
++    0xE3FB73C16B8E75B9ULL, 0xC9B53DCF4BA80A29ULL, 0x23F10B0E16E79763ULL,
++    0xC52172E413042E9BULL, 0xBE60E69CC928B2B9ULL, 0x80CD86A1B9E587E8ULL,
++    0x315D75E198C641A4ULL, 0xCDF93ACC44328387ULL, 0x15987D9ADC0A486DULL,
++    0x7310F7121FD5A074ULL, 0x278273C7DE31EFDCULL, 0x1602E714415D9330ULL,
++    0x81286130BC8985DBULL, 0xB3BF8A3170918836ULL, 0x6A00E0A0B9C49708ULL,
++    0xC6BA0B2C8BBC27BEULL, 0xC9F98D11ED34DBF6ULL, 0x7AD5B7D0B6C12207ULL,
++    0xD91E8FEF55B7394BULL, 0x9037C9EDEFDA4DF8ULL, 0x6D3F8152AD6AC212ULL,
++    0x1DE6B85A1274A0A6ULL, 0xEB3D688A309C180EULL, 0xAF9A3C407BA1DF15ULL,
++    0xE6FA141DF95A56DBULL, 0xB54B1597B61D0A75ULL, 0xA20D64E5683B9FD1ULL,
++    0xD660FAA79559C51FULL, 0xAD107E1E9123A9D0ULL
++};
++
++static const BN_ULONG dh2048_224_g[] = {
++    0x84B890D3191F2BFAULL, 0x81BC087F2A7065B3ULL, 0x19C418E1F6EC0179ULL,
++    0x7B5A0F1C71CFFF4CULL, 0xEDFE72FE9B6AA4BDULL, 0x81E1BCFE94B30269ULL,
++    0x566AFBB48D6C0191ULL, 0xB539CCE3409D13CDULL, 0x6AA21E7F5F2FF381ULL,
++    0xD9E263E4770589EFULL, 0x10E183EDD19963DDULL, 0xB70A8137150B8EEBULL,
++    0x051AE3D428C8F8ACULL, 0xBB77A86F0C1AB15BULL, 0x6E3025E316A330EFULL,
++    0x19529A45D6F83456ULL, 0xF180EB34118E98D1ULL, 0xB5F6C6B250717CBEULL,
++    0x09939D54DA7460CDULL, 0xE247150422EA1ED4ULL, 0xB8A762D0521BC98AULL,
++    0xF4D027275AC1348BULL, 0xC17669101999024AULL, 0xBE5E9001A8D66AD7ULL,
++    0xC57DB17C620A8652ULL, 0xAB739D7700C29F52ULL, 0xDD921F01A70C4AFAULL,
++    0xA6824A4E10B9A6F0ULL, 0x74866A08CFE4FFE3ULL, 0x6CDEBE7B89998CAFULL,
++    0x9DF30B5C8FFDAC50ULL, 0xAC4032EF4F2D9AE3ULL
++};
++
++static const BN_ULONG dh2048_224_q[] = {
++    0xBF389A99B36371EBULL, 0x1F80535A4738CEBCULL, 0xC58D93FE99717710ULL,
++    0x00000000801C0D34ULL
++};
++
++static const BN_ULONG dh2048_256_p[] = {
++    0xDB094AE91E1A1597ULL, 0x693877FAD7EF09CAULL, 0x6116D2276E11715FULL,
++    0xA4B54330C198AF12ULL, 0x75F26375D7014103ULL, 0xC3A3960A54E710C3ULL,
++    0xDED4010ABD0BE621ULL, 0xC0B857F689962856ULL, 0xB3CA3F7971506026ULL,
++    0x1CCACB83E6B486F6ULL, 0x67E144E514056425ULL, 0xF6A167B5A41825D9ULL,
++    0x3AD8347796524D8EULL, 0xF13C6D9A51BFA4ABULL, 0x2D52526735488A0EULL,
++    0xB63ACAE1CAA6B790ULL, 0x4FDB70C581B23F76ULL, 0xBC39A0BF12307F5CULL,
++    0xB941F54EB1E59BB8ULL, 0x6C5BFC11D45F9088ULL, 0x22E0B1EF4275BF7BULL,
++    0x91F9E6725B4758C0ULL, 0x5A8A9D306BCF67EDULL, 0x209E0C6497517ABDULL,
++    0x3BF4296D830E9A7CULL, 0x16C3D91134096FAAULL, 0xFAF7DF4561B2AA30ULL,
++    0xE00DF8F1D61957D4ULL, 0x5D2CEED4435E3B00ULL, 0x8CEEF608660DD0F2ULL,
++    0xFFBBD19C65195999ULL, 0x87A8E61DB4B6663CULL
++};
++
++static const BN_ULONG dh2048_256_g[] = {
++    0x664B4C0F6CC41659ULL, 0x5E2327CFEF98C582ULL, 0xD647D148D4795451ULL,
++    0x2F63078490F00EF8ULL, 0x184B523D1DB246C3ULL, 0xC7891428CDC67EB6ULL,
++    0x7FD028370DF92B52ULL, 0xB3353BBB64E0EC37ULL, 0xECD06E1557CD0915ULL,
++    0xB7D2BBD2DF016199ULL, 0xC8484B1E052588B9ULL, 0xDB2A3B7313D3FE14ULL,
++    0xD052B985D182EA0AULL, 0xA4BD1BFFE83B9C80ULL, 0xDFC967C1FB3F2E55ULL,
++    0xB5045AF2767164E1ULL, 0x1D14348F6F2F9193ULL, 0x64E67982428EBC83ULL,
++    0x8AC376D282D6ED38ULL, 0x777DE62AAAB8A862ULL, 0xDDF463E5E9EC144BULL,
++    0x0196F931C77A57F2ULL, 0xA55AE31341000A65ULL, 0x901228F8C28CBB18ULL,
++    0xBC3773BF7E8C6F62ULL, 0xBE3A6C1B0C6B47B1ULL, 0xFF4FED4AAC0BB555ULL,
++    0x10DBC15077BE463FULL, 0x07F4793A1A0BA125ULL, 0x4CA7B18F21EF2054ULL,
++    0x2E77506660EDBD48ULL, 0x3FB32C9B73134D0BULL
++};
++
++static const BN_ULONG dh2048_256_q[] = {
++    0xA308B0FE64F5FBD3ULL, 0x99B1A47D1EB3750BULL, 0xB447997640129DA2ULL,
++    0x8CF83642A709A097ULL
++};
++
++# elif BN_BITS2 == 32
++
++static const BN_ULONG dh1024_160_p[] = {
++    0x2E4A4371, 0xDF1FB2BC, 0x6D4DA708, 0xE68CFDA7, 0x365C1A65, 0x45BF37DF,
++    0x0DC8B4BD, 0xA151AF5F, 0xF55BCCC0, 0xFAA31A4F, 0xE5644738, 0x4EFFD6FA,
++    0x219A7372, 0x98488E9C, 0x90C4BD70, 0xACCBDD7D, 0xD49B83BF, 0x24975C3C,
++    0xA9061123, 0x13ECB4AE, 0x2EE652C0, 0x9838EF1E, 0x75A23D18, 0x6073E286,
++    0x52D23B61, 0x9A6A9DCA, 0xFB06A3C6, 0x52C99FBC, 0xAE5D54EC, 0xDE92DE5E,
++    0xA080E01D, 0xB10B8F96
++};
++
++static const BN_ULONG dh1024_160_g[] = {
++    0x22B3B2E5, 0x855E6EEB, 0xF97C2A24, 0x858F4DCE, 0x18D08BC8, 0x2D779D59,
++    0x8E73AFA3, 0xD662A4D1, 0x69B6A28A, 0x1DBF0A01, 0x7A091F53, 0xA6A24C08,
++    0x63F80A76, 0x909D0D22, 0xB9A92EE1, 0xD7FBD7D3, 0x9E2749F4, 0x5E91547F,
++    0xB01B886A, 0x160217B4, 0x5504F213, 0x777E690F, 0x5C41564B, 0x266FEA1E,
++    0x14266D31, 0xD6406CFF, 0x58AC507F, 0xF8104DD2, 0xEFB99905, 0x6765A442,
++    0xC3FD3412, 0xA4D1CBD5
++};
++
++static const BN_ULONG dh1024_160_q[] = {
++    0x49462353, 0x64B7CB9D, 0x8ABA4E7D, 0x81A8DF27, 0xF518AA87
++};
++
++static const BN_ULONG dh2048_224_p[] = {
++    0x0C10E64F, 0x0AC4DFFE, 0x4E71B81C, 0xCF9DE538, 0xFFA31F71, 0x7EF363E2,
++    0x6B8E75B9, 0xE3FB73C1, 0x4BA80A29, 0xC9B53DCF, 0x16E79763, 0x23F10B0E,
++    0x13042E9B, 0xC52172E4, 0xC928B2B9, 0xBE60E69C, 0xB9E587E8, 0x80CD86A1,
++    0x98C641A4, 0x315D75E1, 0x44328387, 0xCDF93ACC, 0xDC0A486D, 0x15987D9A,
++    0x1FD5A074, 0x7310F712, 0xDE31EFDC, 0x278273C7, 0x415D9330, 0x1602E714,
++    0xBC8985DB, 0x81286130, 0x70918836, 0xB3BF8A31, 0xB9C49708, 0x6A00E0A0,
++    0x8BBC27BE, 0xC6BA0B2C, 0xED34DBF6, 0xC9F98D11, 0xB6C12207, 0x7AD5B7D0,
++    0x55B7394B, 0xD91E8FEF, 0xEFDA4DF8, 0x9037C9ED, 0xAD6AC212, 0x6D3F8152,
++    0x1274A0A6, 0x1DE6B85A, 0x309C180E, 0xEB3D688A, 0x7BA1DF15, 0xAF9A3C40,
++    0xF95A56DB, 0xE6FA141D, 0xB61D0A75, 0xB54B1597, 0x683B9FD1, 0xA20D64E5,
++    0x9559C51F, 0xD660FAA7, 0x9123A9D0, 0xAD107E1E
++};
++
++static const BN_ULONG dh2048_224_g[] = {
++    0x191F2BFA, 0x84B890D3, 0x2A7065B3, 0x81BC087F, 0xF6EC0179, 0x19C418E1,
++    0x71CFFF4C, 0x7B5A0F1C, 0x9B6AA4BD, 0xEDFE72FE, 0x94B30269, 0x81E1BCFE,
++    0x8D6C0191, 0x566AFBB4, 0x409D13CD, 0xB539CCE3, 0x5F2FF381, 0x6AA21E7F,
++    0x770589EF, 0xD9E263E4, 0xD19963DD, 0x10E183ED, 0x150B8EEB, 0xB70A8137,
++    0x28C8F8AC, 0x051AE3D4, 0x0C1AB15B, 0xBB77A86F, 0x16A330EF, 0x6E3025E3,
++    0xD6F83456, 0x19529A45, 0x118E98D1, 0xF180EB34, 0x50717CBE, 0xB5F6C6B2,
++    0xDA7460CD, 0x09939D54, 0x22EA1ED4, 0xE2471504, 0x521BC98A, 0xB8A762D0,
++    0x5AC1348B, 0xF4D02727, 0x1999024A, 0xC1766910, 0xA8D66AD7, 0xBE5E9001,
++    0x620A8652, 0xC57DB17C, 0x00C29F52, 0xAB739D77, 0xA70C4AFA, 0xDD921F01,
++    0x10B9A6F0, 0xA6824A4E, 0xCFE4FFE3, 0x74866A08, 0x89998CAF, 0x6CDEBE7B,
++    0x8FFDAC50, 0x9DF30B5C, 0x4F2D9AE3, 0xAC4032EF
++};
++
++static const BN_ULONG dh2048_224_q[] = {
++    0xB36371EB, 0xBF389A99, 0x4738CEBC, 0x1F80535A, 0x99717710, 0xC58D93FE,
++    0x801C0D34
++};
++
++static const BN_ULONG dh2048_256_p[] = {
++    0x1E1A1597, 0xDB094AE9, 0xD7EF09CA, 0x693877FA, 0x6E11715F, 0x6116D227,
++    0xC198AF12, 0xA4B54330, 0xD7014103, 0x75F26375, 0x54E710C3, 0xC3A3960A,
++    0xBD0BE621, 0xDED4010A, 0x89962856, 0xC0B857F6, 0x71506026, 0xB3CA3F79,
++    0xE6B486F6, 0x1CCACB83, 0x14056425, 0x67E144E5, 0xA41825D9, 0xF6A167B5,
++    0x96524D8E, 0x3AD83477, 0x51BFA4AB, 0xF13C6D9A, 0x35488A0E, 0x2D525267,
++    0xCAA6B790, 0xB63ACAE1, 0x81B23F76, 0x4FDB70C5, 0x12307F5C, 0xBC39A0BF,
++    0xB1E59BB8, 0xB941F54E, 0xD45F9088, 0x6C5BFC11, 0x4275BF7B, 0x22E0B1EF,
++    0x5B4758C0, 0x91F9E672, 0x6BCF67ED, 0x5A8A9D30, 0x97517ABD, 0x209E0C64,
++    0x830E9A7C, 0x3BF4296D, 0x34096FAA, 0x16C3D911, 0x61B2AA30, 0xFAF7DF45,
++    0xD61957D4, 0xE00DF8F1, 0x435E3B00, 0x5D2CEED4, 0x660DD0F2, 0x8CEEF608,
++    0x65195999, 0xFFBBD19C, 0xB4B6663C, 0x87A8E61D
++};
++
++static const BN_ULONG dh2048_256_g[] = {
++    0x6CC41659, 0x664B4C0F, 0xEF98C582, 0x5E2327CF, 0xD4795451, 0xD647D148,
++    0x90F00EF8, 0x2F630784, 0x1DB246C3, 0x184B523D, 0xCDC67EB6, 0xC7891428,
++    0x0DF92B52, 0x7FD02837, 0x64E0EC37, 0xB3353BBB, 0x57CD0915, 0xECD06E15,
++    0xDF016199, 0xB7D2BBD2, 0x052588B9, 0xC8484B1E, 0x13D3FE14, 0xDB2A3B73,
++    0xD182EA0A, 0xD052B985, 0xE83B9C80, 0xA4BD1BFF, 0xFB3F2E55, 0xDFC967C1,
++    0x767164E1, 0xB5045AF2, 0x6F2F9193, 0x1D14348F, 0x428EBC83, 0x64E67982,
++    0x82D6ED38, 0x8AC376D2, 0xAAB8A862, 0x777DE62A, 0xE9EC144B, 0xDDF463E5,
++    0xC77A57F2, 0x0196F931, 0x41000A65, 0xA55AE313, 0xC28CBB18, 0x901228F8,
++    0x7E8C6F62, 0xBC3773BF, 0x0C6B47B1, 0xBE3A6C1B, 0xAC0BB555, 0xFF4FED4A,
++    0x77BE463F, 0x10DBC150, 0x1A0BA125, 0x07F4793A, 0x21EF2054, 0x4CA7B18F,
++    0x60EDBD48, 0x2E775066, 0x73134D0B, 0x3FB32C9B
++};
++
++static const BN_ULONG dh2048_256_q[] = {
++    0x64F5FBD3, 0xA308B0FE, 0x1EB3750B, 0x99B1A47D, 0x40129DA2, 0xB4479976,
++    0xA709A097, 0x8CF83642
++};
++
++# else
++#  error "unsupported BN_BITS2"
++# endif
++
++/* Macro to make a BIGNUM from static data */
++
++# define make_dh_bn(x) extern const BIGNUM _bignum_##x; \
++                       const BIGNUM _bignum_##x = { (BN_ULONG *) x, \
++                        OSSL_NELEM(x),\
++                        OSSL_NELEM(x),\
++                        0, BN_FLG_STATIC_DATA };
++
++
++make_dh_bn(dh1024_160_p)
++make_dh_bn(dh1024_160_g)
++make_dh_bn(dh1024_160_q)
++make_dh_bn(dh2048_224_p)
++make_dh_bn(dh2048_224_g)
++make_dh_bn(dh2048_224_q)
++make_dh_bn(dh2048_256_p)
++make_dh_bn(dh2048_256_g)
++make_dh_bn(dh2048_256_q)
++
++#endif
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/bn/bn_div.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/bn/bn_div.c
+new file mode 100644
+index 0000000..5e620b2
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/bn/bn_div.c
+@@ -0,0 +1,423 @@
++/*
++ * Copyright 1995-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include "internal/cryptlib.h"
++#include "bn_lcl.h"
++
++/* The old slow way */
++#if 0
++int BN_div(BIGNUM *dv, BIGNUM *rem, const BIGNUM *m, const BIGNUM *d,
++           BN_CTX *ctx)
++{
++    int i, nm, nd;
++    int ret = 0;
++    BIGNUM *D;
++
++    bn_check_top(m);
++    bn_check_top(d);
++    if (BN_is_zero(d)) {
++        BNerr(BN_F_BN_DIV, BN_R_DIV_BY_ZERO);
++        return (0);
++    }
++
++    if (BN_ucmp(m, d) < 0) {
++        if (rem != NULL) {
++            if (BN_copy(rem, m) == NULL)
++                return (0);
++        }
++        if (dv != NULL)
++            BN_zero(dv);
++        return (1);
++    }
++
++    BN_CTX_start(ctx);
++    D = BN_CTX_get(ctx);
++    if (dv == NULL)
++        dv = BN_CTX_get(ctx);
++    if (rem == NULL)
++        rem = BN_CTX_get(ctx);
++    if (D == NULL || dv == NULL || rem == NULL)
++        goto end;
++
++    nd = BN_num_bits(d);
++    nm = BN_num_bits(m);
++    if (BN_copy(D, d) == NULL)
++        goto end;
++    if (BN_copy(rem, m) == NULL)
++        goto end;
++
++    /*
++     * The next 2 are needed so we can do a dv->d[0]|=1 later since
++     * BN_lshift1 will only work once there is a value :-)
++     */
++    BN_zero(dv);
++    if (bn_wexpand(dv, 1) == NULL)
++        goto end;
++    dv->top = 1;
++
++    if (!BN_lshift(D, D, nm - nd))
++        goto end;
++    for (i = nm - nd; i >= 0; i--) {
++        if (!BN_lshift1(dv, dv))
++            goto end;
++        if (BN_ucmp(rem, D) >= 0) {
++            dv->d[0] |= 1;
++            if (!BN_usub(rem, rem, D))
++                goto end;
++        }
++/* CAN IMPROVE (and have now :=) */
++        if (!BN_rshift1(D, D))
++            goto end;
++    }
++    rem->neg = BN_is_zero(rem) ? 0 : m->neg;
++    dv->neg = m->neg ^ d->neg;
++    ret = 1;
++ end:
++    BN_CTX_end(ctx);
++    return (ret);
++}
++
++#else
++
++# if !defined(OPENSSL_NO_ASM) && !defined(OPENSSL_NO_INLINE_ASM) \
++    && !defined(PEDANTIC) && !defined(BN_DIV3W)
++#  if defined(__GNUC__) && __GNUC__>=2
++#   if defined(__i386) || defined (__i386__)
++   /*-
++    * There were two reasons for implementing this template:
++    * - GNU C generates a call to a function (__udivdi3 to be exact)
++    *   in reply to ((((BN_ULLONG)n0)<
++    */
++#    undef bn_div_words
++#    define bn_div_words(n0,n1,d0)                \
++        ({  asm volatile (                      \
++                "divl   %4"                     \
++                : "=a"(q), "=d"(rem)            \
++                : "a"(n1), "d"(n0), "r"(d0)     \
++                : "cc");                        \
++            q;                                  \
++        })
++#    define REMAINDER_IS_ALREADY_CALCULATED
++#   elif defined(__x86_64) && defined(SIXTY_FOUR_BIT_LONG)
++   /*
++    * Same story here, but it's 128-bit by 64-bit division. Wow!
++    *                                   
++    */
++#    undef bn_div_words
++#    define bn_div_words(n0,n1,d0)                \
++        ({  asm volatile (                      \
++                "divq   %4"                     \
++                : "=a"(q), "=d"(rem)            \
++                : "a"(n1), "d"(n0), "r"(d0)     \
++                : "cc");                        \
++            q;                                  \
++        })
++#    define REMAINDER_IS_ALREADY_CALCULATED
++#   endif                       /* __ */
++#  endif                        /* __GNUC__ */
++# endif                         /* OPENSSL_NO_ASM */
++
++/*-
++ * BN_div computes  dv := num / divisor, rounding towards
++ * zero, and sets up rm  such that  dv*divisor + rm = num  holds.
++ * Thus:
++ *     dv->neg == num->neg ^ divisor->neg  (unless the result is zero)
++ *     rm->neg == num->neg                 (unless the remainder is zero)
++ * If 'dv' or 'rm' is NULL, the respective value is not returned.
++ */
++int BN_div(BIGNUM *dv, BIGNUM *rm, const BIGNUM *num, const BIGNUM *divisor,
++           BN_CTX *ctx)
++{
++    int norm_shift, i, loop;
++    BIGNUM *tmp, wnum, *snum, *sdiv, *res;
++    BN_ULONG *resp, *wnump;
++    BN_ULONG d0, d1;
++    int num_n, div_n;
++    int no_branch = 0;
++
++    /*
++     * Invalid zero-padding would have particularly bad consequences so don't
++     * just rely on bn_check_top() here (bn_check_top() works only for
++     * BN_DEBUG builds)
++     */
++    if ((num->top > 0 && num->d[num->top - 1] == 0) ||
++        (divisor->top > 0 && divisor->d[divisor->top - 1] == 0)) {
++        BNerr(BN_F_BN_DIV, BN_R_NOT_INITIALIZED);
++        return 0;
++    }
++
++    bn_check_top(num);
++    bn_check_top(divisor);
++
++    if ((BN_get_flags(num, BN_FLG_CONSTTIME) != 0)
++        || (BN_get_flags(divisor, BN_FLG_CONSTTIME) != 0)) {
++        no_branch = 1;
++    }
++
++    bn_check_top(dv);
++    bn_check_top(rm);
++    /*- bn_check_top(num); *//*
++     * 'num' has been checked already
++     */
++    /*- bn_check_top(divisor); *//*
++     * 'divisor' has been checked already
++     */
++
++    if (BN_is_zero(divisor)) {
++        BNerr(BN_F_BN_DIV, BN_R_DIV_BY_ZERO);
++        return (0);
++    }
++
++    if (!no_branch && BN_ucmp(num, divisor) < 0) {
++        if (rm != NULL) {
++            if (BN_copy(rm, num) == NULL)
++                return (0);
++        }
++        if (dv != NULL)
++            BN_zero(dv);
++        return (1);
++    }
++
++    BN_CTX_start(ctx);
++    tmp = BN_CTX_get(ctx);
++    snum = BN_CTX_get(ctx);
++    sdiv = BN_CTX_get(ctx);
++    if (dv == NULL)
++        res = BN_CTX_get(ctx);
++    else
++        res = dv;
++    if (sdiv == NULL || res == NULL || tmp == NULL || snum == NULL)
++        goto err;
++
++    /* First we normalise the numbers */
++    norm_shift = BN_BITS2 - ((BN_num_bits(divisor)) % BN_BITS2);
++    if (!(BN_lshift(sdiv, divisor, norm_shift)))
++        goto err;
++    sdiv->neg = 0;
++    norm_shift += BN_BITS2;
++    if (!(BN_lshift(snum, num, norm_shift)))
++        goto err;
++    snum->neg = 0;
++
++    if (no_branch) {
++        /*
++         * Since we don't know whether snum is larger than sdiv, we pad snum
++         * with enough zeroes without changing its value.
++         */
++        if (snum->top <= sdiv->top + 1) {
++            if (bn_wexpand(snum, sdiv->top + 2) == NULL)
++                goto err;
++            for (i = snum->top; i < sdiv->top + 2; i++)
++                snum->d[i] = 0;
++            snum->top = sdiv->top + 2;
++        } else {
++            if (bn_wexpand(snum, snum->top + 1) == NULL)
++                goto err;
++            snum->d[snum->top] = 0;
++            snum->top++;
++        }
++    }
++
++    div_n = sdiv->top;
++    num_n = snum->top;
++    loop = num_n - div_n;
++    /*
++     * Lets setup a 'window' into snum This is the part that corresponds to
++     * the current 'area' being divided
++     */
++    wnum.neg = 0;
++    wnum.d = &(snum->d[loop]);
++    wnum.top = div_n;
++    /*
++     * only needed when BN_ucmp messes up the values between top and max
++     */
++    wnum.dmax = snum->dmax - loop; /* so we don't step out of bounds */
++
++    /* Get the top 2 words of sdiv */
++    /* div_n=sdiv->top; */
++    d0 = sdiv->d[div_n - 1];
++    d1 = (div_n == 1) ? 0 : sdiv->d[div_n - 2];
++
++    /* pointer to the 'top' of snum */
++    wnump = &(snum->d[num_n - 1]);
++
++    /* Setup to 'res' */
++    if (!bn_wexpand(res, (loop + 1)))
++        goto err;
++    res->neg = (num->neg ^ divisor->neg);
++    res->top = loop - no_branch;
++    resp = &(res->d[loop - 1]);
++
++    /* space for temp */
++    if (!bn_wexpand(tmp, (div_n + 1)))
++        goto err;
++
++    if (!no_branch) {
++        if (BN_ucmp(&wnum, sdiv) >= 0) {
++            /*
++             * If BN_DEBUG_RAND is defined BN_ucmp changes (via bn_pollute)
++             * the const bignum arguments => clean the values between top and
++             * max again
++             */
++            bn_clear_top2max(&wnum);
++            bn_sub_words(wnum.d, wnum.d, sdiv->d, div_n);
++            *resp = 1;
++        } else
++            res->top--;
++    }
++
++    /* Increase the resp pointer so that we never create an invalid pointer. */
++    resp++;
++
++    /*
++     * if res->top == 0 then clear the neg value otherwise decrease the resp
++     * pointer
++     */
++    if (res->top == 0)
++        res->neg = 0;
++    else
++        resp--;
++
++    for (i = 0; i < loop - 1; i++, wnump--) {
++        BN_ULONG q, l0;
++        /*
++         * the first part of the loop uses the top two words of snum and sdiv
++         * to calculate a BN_ULONG q such that | wnum - sdiv * q | < sdiv
++         */
++# if defined(BN_DIV3W) && !defined(OPENSSL_NO_ASM)
++        BN_ULONG bn_div_3_words(BN_ULONG *, BN_ULONG, BN_ULONG);
++        q = bn_div_3_words(wnump, d1, d0);
++# else
++        BN_ULONG n0, n1, rem = 0;
++
++        n0 = wnump[0];
++        n1 = wnump[-1];
++        if (n0 == d0)
++            q = BN_MASK2;
++        else {                  /* n0 < d0 */
++
++#  ifdef BN_LLONG
++            BN_ULLONG t2;
++
++#   if defined(BN_LLONG) && defined(BN_DIV2W) && !defined(bn_div_words)
++            q = (BN_ULONG)(((((BN_ULLONG) n0) << BN_BITS2) | n1) / d0);
++#   else
++            q = bn_div_words(n0, n1, d0);
++#   endif
++
++#   ifndef REMAINDER_IS_ALREADY_CALCULATED
++            /*
++             * rem doesn't have to be BN_ULLONG. The least we
++             * know it's less that d0, isn't it?
++             */
++            rem = (n1 - q * d0) & BN_MASK2;
++#   endif
++            t2 = (BN_ULLONG) d1 *q;
++
++            for (;;) {
++                if (t2 <= ((((BN_ULLONG) rem) << BN_BITS2) | wnump[-2]))
++                    break;
++                q--;
++                rem += d0;
++                if (rem < d0)
++                    break;      /* don't let rem overflow */
++                t2 -= d1;
++            }
++#  else                         /* !BN_LLONG */
++            BN_ULONG t2l, t2h;
++
++            q = bn_div_words(n0, n1, d0);
++#   ifndef REMAINDER_IS_ALREADY_CALCULATED
++            rem = (n1 - q * d0) & BN_MASK2;
++#   endif
++
++#   if defined(BN_UMULT_LOHI)
++            BN_UMULT_LOHI(t2l, t2h, d1, q);
++#   elif defined(BN_UMULT_HIGH)
++            t2l = d1 * q;
++            t2h = BN_UMULT_HIGH(d1, q);
++#   else
++            {
++                BN_ULONG ql, qh;
++                t2l = LBITS(d1);
++                t2h = HBITS(d1);
++                ql = LBITS(q);
++                qh = HBITS(q);
++                mul64(t2l, t2h, ql, qh); /* t2=(BN_ULLONG)d1*q; */
++            }
++#   endif
++
++            for (;;) {
++                if ((t2h < rem) || ((t2h == rem) && (t2l <= wnump[-2])))
++                    break;
++                q--;
++                rem += d0;
++                if (rem < d0)
++                    break;      /* don't let rem overflow */
++                if (t2l < d1)
++                    t2h--;
++                t2l -= d1;
++            }
++#  endif                        /* !BN_LLONG */
++        }
++# endif                         /* !BN_DIV3W */
++
++        l0 = bn_mul_words(tmp->d, sdiv->d, div_n, q);
++        tmp->d[div_n] = l0;
++        wnum.d--;
++        /*
++         * ingore top values of the bignums just sub the two BN_ULONG arrays
++         * with bn_sub_words
++         */
++        if (bn_sub_words(wnum.d, wnum.d, tmp->d, div_n + 1)) {
++            /*
++             * Note: As we have considered only the leading two BN_ULONGs in
++             * the calculation of q, sdiv * q might be greater than wnum (but
++             * then (q-1) * sdiv is less or equal than wnum)
++             */
++            q--;
++            if (bn_add_words(wnum.d, wnum.d, sdiv->d, div_n))
++                /*
++                 * we can't have an overflow here (assuming that q != 0, but
++                 * if q == 0 then tmp is zero anyway)
++                 */
++                (*wnump)++;
++        }
++        /* store part of the result */
++        resp--;
++        *resp = q;
++    }
++    bn_correct_top(snum);
++    if (rm != NULL) {
++        /*
++         * Keep a copy of the neg flag in num because if rm==num BN_rshift()
++         * will overwrite it.
++         */
++        int neg = num->neg;
++        BN_rshift(rm, snum, norm_shift);
++        if (!BN_is_zero(rm))
++            rm->neg = neg;
++        bn_check_top(rm);
++    }
++    if (no_branch)
++        bn_correct_top(res);
++    BN_CTX_end(ctx);
++    return (1);
++ err:
++    bn_check_top(rm);
++    BN_CTX_end(ctx);
++    return (0);
++}
++#endif
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/bn/bn_err.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/bn/bn_err.c
+new file mode 100644
+index 0000000..5fe9db9
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/bn/bn_err.c
+@@ -0,0 +1,107 @@
++/*
++ * Generated by util/mkerr.pl DO NOT EDIT
++ * Copyright 1995-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include 
++#include 
++
++/* BEGIN ERROR CODES */
++#ifndef OPENSSL_NO_ERR
++
++# define ERR_FUNC(func) ERR_PACK(ERR_LIB_BN,func,0)
++# define ERR_REASON(reason) ERR_PACK(ERR_LIB_BN,0,reason)
++
++static ERR_STRING_DATA BN_str_functs[] = {
++    {ERR_FUNC(BN_F_BNRAND), "bnrand"},
++    {ERR_FUNC(BN_F_BN_BLINDING_CONVERT_EX), "BN_BLINDING_convert_ex"},
++    {ERR_FUNC(BN_F_BN_BLINDING_CREATE_PARAM), "BN_BLINDING_create_param"},
++    {ERR_FUNC(BN_F_BN_BLINDING_INVERT_EX), "BN_BLINDING_invert_ex"},
++    {ERR_FUNC(BN_F_BN_BLINDING_NEW), "BN_BLINDING_new"},
++    {ERR_FUNC(BN_F_BN_BLINDING_UPDATE), "BN_BLINDING_update"},
++    {ERR_FUNC(BN_F_BN_BN2DEC), "BN_bn2dec"},
++    {ERR_FUNC(BN_F_BN_BN2HEX), "BN_bn2hex"},
++    {ERR_FUNC(BN_F_BN_COMPUTE_WNAF), "bn_compute_wNAF"},
++    {ERR_FUNC(BN_F_BN_CTX_GET), "BN_CTX_get"},
++    {ERR_FUNC(BN_F_BN_CTX_NEW), "BN_CTX_new"},
++    {ERR_FUNC(BN_F_BN_CTX_START), "BN_CTX_start"},
++    {ERR_FUNC(BN_F_BN_DIV), "BN_div"},
++    {ERR_FUNC(BN_F_BN_DIV_RECP), "BN_div_recp"},
++    {ERR_FUNC(BN_F_BN_EXP), "BN_exp"},
++    {ERR_FUNC(BN_F_BN_EXPAND_INTERNAL), "bn_expand_internal"},
++    {ERR_FUNC(BN_F_BN_GENCB_NEW), "BN_GENCB_new"},
++    {ERR_FUNC(BN_F_BN_GENERATE_DSA_NONCE), "BN_generate_dsa_nonce"},
++    {ERR_FUNC(BN_F_BN_GENERATE_PRIME_EX), "BN_generate_prime_ex"},
++    {ERR_FUNC(BN_F_BN_GF2M_MOD), "BN_GF2m_mod"},
++    {ERR_FUNC(BN_F_BN_GF2M_MOD_EXP), "BN_GF2m_mod_exp"},
++    {ERR_FUNC(BN_F_BN_GF2M_MOD_MUL), "BN_GF2m_mod_mul"},
++    {ERR_FUNC(BN_F_BN_GF2M_MOD_SOLVE_QUAD), "BN_GF2m_mod_solve_quad"},
++    {ERR_FUNC(BN_F_BN_GF2M_MOD_SOLVE_QUAD_ARR), "BN_GF2m_mod_solve_quad_arr"},
++    {ERR_FUNC(BN_F_BN_GF2M_MOD_SQR), "BN_GF2m_mod_sqr"},
++    {ERR_FUNC(BN_F_BN_GF2M_MOD_SQRT), "BN_GF2m_mod_sqrt"},
++    {ERR_FUNC(BN_F_BN_LSHIFT), "BN_lshift"},
++    {ERR_FUNC(BN_F_BN_MOD_EXP2_MONT), "BN_mod_exp2_mont"},
++    {ERR_FUNC(BN_F_BN_MOD_EXP_MONT), "BN_mod_exp_mont"},
++    {ERR_FUNC(BN_F_BN_MOD_EXP_MONT_CONSTTIME), "BN_mod_exp_mont_consttime"},
++    {ERR_FUNC(BN_F_BN_MOD_EXP_MONT_WORD), "BN_mod_exp_mont_word"},
++    {ERR_FUNC(BN_F_BN_MOD_EXP_RECP), "BN_mod_exp_recp"},
++    {ERR_FUNC(BN_F_BN_MOD_EXP_SIMPLE), "BN_mod_exp_simple"},
++    {ERR_FUNC(BN_F_BN_MOD_INVERSE), "BN_mod_inverse"},
++    {ERR_FUNC(BN_F_BN_MOD_INVERSE_NO_BRANCH), "BN_mod_inverse_no_branch"},
++    {ERR_FUNC(BN_F_BN_MOD_LSHIFT_QUICK), "BN_mod_lshift_quick"},
++    {ERR_FUNC(BN_F_BN_MOD_SQRT), "BN_mod_sqrt"},
++    {ERR_FUNC(BN_F_BN_MPI2BN), "BN_mpi2bn"},
++    {ERR_FUNC(BN_F_BN_NEW), "BN_new"},
++    {ERR_FUNC(BN_F_BN_RAND), "BN_rand"},
++    {ERR_FUNC(BN_F_BN_RAND_RANGE), "BN_rand_range"},
++    {ERR_FUNC(BN_F_BN_RSHIFT), "BN_rshift"},
++    {ERR_FUNC(BN_F_BN_SET_WORDS), "bn_set_words"},
++    {ERR_FUNC(BN_F_BN_USUB), "BN_usub"},
++    {0, NULL}
++};
++
++static ERR_STRING_DATA BN_str_reasons[] = {
++    {ERR_REASON(BN_R_ARG2_LT_ARG3), "arg2 lt arg3"},
++    {ERR_REASON(BN_R_BAD_RECIPROCAL), "bad reciprocal"},
++    {ERR_REASON(BN_R_BIGNUM_TOO_LONG), "bignum too long"},
++    {ERR_REASON(BN_R_BITS_TOO_SMALL), "bits too small"},
++    {ERR_REASON(BN_R_CALLED_WITH_EVEN_MODULUS), "called with even modulus"},
++    {ERR_REASON(BN_R_DIV_BY_ZERO), "div by zero"},
++    {ERR_REASON(BN_R_ENCODING_ERROR), "encoding error"},
++    {ERR_REASON(BN_R_EXPAND_ON_STATIC_BIGNUM_DATA),
++     "expand on static bignum data"},
++    {ERR_REASON(BN_R_INPUT_NOT_REDUCED), "input not reduced"},
++    {ERR_REASON(BN_R_INVALID_LENGTH), "invalid length"},
++    {ERR_REASON(BN_R_INVALID_RANGE), "invalid range"},
++    {ERR_REASON(BN_R_INVALID_SHIFT), "invalid shift"},
++    {ERR_REASON(BN_R_NOT_A_SQUARE), "not a square"},
++    {ERR_REASON(BN_R_NOT_INITIALIZED), "not initialized"},
++    {ERR_REASON(BN_R_NO_INVERSE), "no inverse"},
++    {ERR_REASON(BN_R_NO_SOLUTION), "no solution"},
++    {ERR_REASON(BN_R_PRIVATE_KEY_TOO_LARGE), "private key too large"},
++    {ERR_REASON(BN_R_P_IS_NOT_PRIME), "p is not prime"},
++    {ERR_REASON(BN_R_TOO_MANY_ITERATIONS), "too many iterations"},
++    {ERR_REASON(BN_R_TOO_MANY_TEMPORARY_VARIABLES),
++     "too many temporary variables"},
++    {0, NULL}
++};
++
++#endif
++
++int ERR_load_BN_strings(void)
++{
++#ifndef OPENSSL_NO_ERR
++
++    if (ERR_func_error_string(BN_str_functs[0].error) == NULL) {
++        ERR_load_strings(0, BN_str_functs);
++        ERR_load_strings(0, BN_str_reasons);
++    }
++#endif
++    return 1;
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/bn/bn_exp.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/bn/bn_exp.c
+new file mode 100644
+index 0000000..feeb764
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/bn/bn_exp.c
+@@ -0,0 +1,1362 @@
++/*
++ * Copyright 1995-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include "internal/cryptlib.h"
++#include "internal/constant_time_locl.h"
++#include "bn_lcl.h"
++
++#include 
++#ifdef _WIN32
++# include 
++# ifndef alloca
++#  define alloca _alloca
++# endif
++#elif defined(__GNUC__)
++# ifndef alloca
++#  define alloca(s) __builtin_alloca((s))
++# endif
++#elif defined(__sun)
++# include 
++#endif
++
++#include "rsaz_exp.h"
++
++#undef SPARC_T4_MONT
++#if defined(OPENSSL_BN_ASM_MONT) && (defined(__sparc__) || defined(__sparc))
++# include "sparc_arch.h"
++extern unsigned int OPENSSL_sparcv9cap_P[];
++# define SPARC_T4_MONT
++#endif
++
++/* maximum precomputation table size for *variable* sliding windows */
++#define TABLE_SIZE      32
++
++/* this one works - simple but works */
++int BN_exp(BIGNUM *r, const BIGNUM *a, const BIGNUM *p, BN_CTX *ctx)
++{
++    int i, bits, ret = 0;
++    BIGNUM *v, *rr;
++
++    if (BN_get_flags(p, BN_FLG_CONSTTIME) != 0) {
++        /* BN_FLG_CONSTTIME only supported by BN_mod_exp_mont() */
++        BNerr(BN_F_BN_EXP, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
++        return 0;
++    }
++
++    BN_CTX_start(ctx);
++    if ((r == a) || (r == p))
++        rr = BN_CTX_get(ctx);
++    else
++        rr = r;
++    v = BN_CTX_get(ctx);
++    if (rr == NULL || v == NULL)
++        goto err;
++
++    if (BN_copy(v, a) == NULL)
++        goto err;
++    bits = BN_num_bits(p);
++
++    if (BN_is_odd(p)) {
++        if (BN_copy(rr, a) == NULL)
++            goto err;
++    } else {
++        if (!BN_one(rr))
++            goto err;
++    }
++
++    for (i = 1; i < bits; i++) {
++        if (!BN_sqr(v, v, ctx))
++            goto err;
++        if (BN_is_bit_set(p, i)) {
++            if (!BN_mul(rr, rr, v, ctx))
++                goto err;
++        }
++    }
++    if (r != rr && BN_copy(r, rr) == NULL)
++        goto err;
++
++    ret = 1;
++ err:
++    BN_CTX_end(ctx);
++    bn_check_top(r);
++    return (ret);
++}
++
++int BN_mod_exp(BIGNUM *r, const BIGNUM *a, const BIGNUM *p, const BIGNUM *m,
++               BN_CTX *ctx)
++{
++    int ret;
++
++    bn_check_top(a);
++    bn_check_top(p);
++    bn_check_top(m);
++
++    /*-
++     * For even modulus  m = 2^k*m_odd, it might make sense to compute
++     * a^p mod m_odd  and  a^p mod 2^k  separately (with Montgomery
++     * exponentiation for the odd part), using appropriate exponent
++     * reductions, and combine the results using the CRT.
++     *
++     * For now, we use Montgomery only if the modulus is odd; otherwise,
++     * exponentiation using the reciprocal-based quick remaindering
++     * algorithm is used.
++     *
++     * (Timing obtained with expspeed.c [computations  a^p mod m
++     * where  a, p, m  are of the same length: 256, 512, 1024, 2048,
++     * 4096, 8192 bits], compared to the running time of the
++     * standard algorithm:
++     *
++     *   BN_mod_exp_mont   33 .. 40 %  [AMD K6-2, Linux, debug configuration]
++     *                     55 .. 77 %  [UltraSparc processor, but
++     *                                  debug-solaris-sparcv8-gcc conf.]
++     *
++     *   BN_mod_exp_recp   50 .. 70 %  [AMD K6-2, Linux, debug configuration]
++     *                     62 .. 118 % [UltraSparc, debug-solaris-sparcv8-gcc]
++     *
++     * On the Sparc, BN_mod_exp_recp was faster than BN_mod_exp_mont
++     * at 2048 and more bits, but at 512 and 1024 bits, it was
++     * slower even than the standard algorithm!
++     *
++     * "Real" timings [linux-elf, solaris-sparcv9-gcc configurations]
++     * should be obtained when the new Montgomery reduction code
++     * has been integrated into OpenSSL.)
++     */
++
++#define MONT_MUL_MOD
++#define MONT_EXP_WORD
++#define RECP_MUL_MOD
++
++#ifdef MONT_MUL_MOD
++    /*
++     * I have finally been able to take out this pre-condition of the top bit
++     * being set.  It was caused by an error in BN_div with negatives.  There
++     * was also another problem when for a^b%m a >= m.  eay 07-May-97
++     */
++    /* if ((m->d[m->top-1]&BN_TBIT) && BN_is_odd(m)) */
++
++    if (BN_is_odd(m)) {
++# ifdef MONT_EXP_WORD
++        if (a->top == 1 && !a->neg
++            && (BN_get_flags(p, BN_FLG_CONSTTIME) == 0)) {
++            BN_ULONG A = a->d[0];
++            ret = BN_mod_exp_mont_word(r, A, p, m, ctx, NULL);
++        } else
++# endif
++            ret = BN_mod_exp_mont(r, a, p, m, ctx, NULL);
++    } else
++#endif
++#ifdef RECP_MUL_MOD
++    {
++        ret = BN_mod_exp_recp(r, a, p, m, ctx);
++    }
++#else
++    {
++        ret = BN_mod_exp_simple(r, a, p, m, ctx);
++    }
++#endif
++
++    bn_check_top(r);
++    return (ret);
++}
++
++int BN_mod_exp_recp(BIGNUM *r, const BIGNUM *a, const BIGNUM *p,
++                    const BIGNUM *m, BN_CTX *ctx)
++{
++    int i, j, bits, ret = 0, wstart, wend, window, wvalue;
++    int start = 1;
++    BIGNUM *aa;
++    /* Table of variables obtained from 'ctx' */
++    BIGNUM *val[TABLE_SIZE];
++    BN_RECP_CTX recp;
++
++    if (BN_get_flags(p, BN_FLG_CONSTTIME) != 0) {
++        /* BN_FLG_CONSTTIME only supported by BN_mod_exp_mont() */
++        BNerr(BN_F_BN_MOD_EXP_RECP, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
++        return 0;
++    }
++
++    bits = BN_num_bits(p);
++    if (bits == 0) {
++        /* x**0 mod 1 is still zero. */
++        if (BN_is_one(m)) {
++            ret = 1;
++            BN_zero(r);
++        } else {
++            ret = BN_one(r);
++        }
++        return ret;
++    }
++
++    BN_CTX_start(ctx);
++    aa = BN_CTX_get(ctx);
++    val[0] = BN_CTX_get(ctx);
++    if (!aa || !val[0])
++        goto err;
++
++    BN_RECP_CTX_init(&recp);
++    if (m->neg) {
++        /* ignore sign of 'm' */
++        if (!BN_copy(aa, m))
++            goto err;
++        aa->neg = 0;
++        if (BN_RECP_CTX_set(&recp, aa, ctx) <= 0)
++            goto err;
++    } else {
++        if (BN_RECP_CTX_set(&recp, m, ctx) <= 0)
++            goto err;
++    }
++
++    if (!BN_nnmod(val[0], a, m, ctx))
++        goto err;               /* 1 */
++    if (BN_is_zero(val[0])) {
++        BN_zero(r);
++        ret = 1;
++        goto err;
++    }
++
++    window = BN_window_bits_for_exponent_size(bits);
++    if (window > 1) {
++        if (!BN_mod_mul_reciprocal(aa, val[0], val[0], &recp, ctx))
++            goto err;           /* 2 */
++        j = 1 << (window - 1);
++        for (i = 1; i < j; i++) {
++            if (((val[i] = BN_CTX_get(ctx)) == NULL) ||
++                !BN_mod_mul_reciprocal(val[i], val[i - 1], aa, &recp, ctx))
++                goto err;
++        }
++    }
++
++    start = 1;                  /* This is used to avoid multiplication etc
++                                 * when there is only the value '1' in the
++                                 * buffer. */
++    wvalue = 0;                 /* The 'value' of the window */
++    wstart = bits - 1;          /* The top bit of the window */
++    wend = 0;                   /* The bottom bit of the window */
++
++    if (!BN_one(r))
++        goto err;
++
++    for (;;) {
++        if (BN_is_bit_set(p, wstart) == 0) {
++            if (!start)
++                if (!BN_mod_mul_reciprocal(r, r, r, &recp, ctx))
++                    goto err;
++            if (wstart == 0)
++                break;
++            wstart--;
++            continue;
++        }
++        /*
++         * We now have wstart on a 'set' bit, we now need to work out how bit
++         * a window to do.  To do this we need to scan forward until the last
++         * set bit before the end of the window
++         */
++        j = wstart;
++        wvalue = 1;
++        wend = 0;
++        for (i = 1; i < window; i++) {
++            if (wstart - i < 0)
++                break;
++            if (BN_is_bit_set(p, wstart - i)) {
++                wvalue <<= (i - wend);
++                wvalue |= 1;
++                wend = i;
++            }
++        }
++
++        /* wend is the size of the current window */
++        j = wend + 1;
++        /* add the 'bytes above' */
++        if (!start)
++            for (i = 0; i < j; i++) {
++                if (!BN_mod_mul_reciprocal(r, r, r, &recp, ctx))
++                    goto err;
++            }
++
++        /* wvalue will be an odd number < 2^window */
++        if (!BN_mod_mul_reciprocal(r, r, val[wvalue >> 1], &recp, ctx))
++            goto err;
++
++        /* move the 'window' down further */
++        wstart -= wend + 1;
++        wvalue = 0;
++        start = 0;
++        if (wstart < 0)
++            break;
++    }
++    ret = 1;
++ err:
++    BN_CTX_end(ctx);
++    BN_RECP_CTX_free(&recp);
++    bn_check_top(r);
++    return (ret);
++}
++
++int BN_mod_exp_mont(BIGNUM *rr, const BIGNUM *a, const BIGNUM *p,
++                    const BIGNUM *m, BN_CTX *ctx, BN_MONT_CTX *in_mont)
++{
++    int i, j, bits, ret = 0, wstart, wend, window, wvalue;
++    int start = 1;
++    BIGNUM *d, *r;
++    const BIGNUM *aa;
++    /* Table of variables obtained from 'ctx' */
++    BIGNUM *val[TABLE_SIZE];
++    BN_MONT_CTX *mont = NULL;
++
++    if (BN_get_flags(p, BN_FLG_CONSTTIME) != 0) {
++        return BN_mod_exp_mont_consttime(rr, a, p, m, ctx, in_mont);
++    }
++
++    bn_check_top(a);
++    bn_check_top(p);
++    bn_check_top(m);
++
++    if (!BN_is_odd(m)) {
++        BNerr(BN_F_BN_MOD_EXP_MONT, BN_R_CALLED_WITH_EVEN_MODULUS);
++        return (0);
++    }
++    bits = BN_num_bits(p);
++    if (bits == 0) {
++        /* x**0 mod 1 is still zero. */
++        if (BN_is_one(m)) {
++            ret = 1;
++            BN_zero(rr);
++        } else {
++            ret = BN_one(rr);
++        }
++        return ret;
++    }
++
++    BN_CTX_start(ctx);
++    d = BN_CTX_get(ctx);
++    r = BN_CTX_get(ctx);
++    val[0] = BN_CTX_get(ctx);
++    if (!d || !r || !val[0])
++        goto err;
++
++    /*
++     * If this is not done, things will break in the montgomery part
++     */
++
++    if (in_mont != NULL)
++        mont = in_mont;
++    else {
++        if ((mont = BN_MONT_CTX_new()) == NULL)
++            goto err;
++        if (!BN_MONT_CTX_set(mont, m, ctx))
++            goto err;
++    }
++
++    if (a->neg || BN_ucmp(a, m) >= 0) {
++        if (!BN_nnmod(val[0], a, m, ctx))
++            goto err;
++        aa = val[0];
++    } else
++        aa = a;
++    if (BN_is_zero(aa)) {
++        BN_zero(rr);
++        ret = 1;
++        goto err;
++    }
++    if (!BN_to_montgomery(val[0], aa, mont, ctx))
++        goto err;               /* 1 */
++
++    window = BN_window_bits_for_exponent_size(bits);
++    if (window > 1) {
++        if (!BN_mod_mul_montgomery(d, val[0], val[0], mont, ctx))
++            goto err;           /* 2 */
++        j = 1 << (window - 1);
++        for (i = 1; i < j; i++) {
++            if (((val[i] = BN_CTX_get(ctx)) == NULL) ||
++                !BN_mod_mul_montgomery(val[i], val[i - 1], d, mont, ctx))
++                goto err;
++        }
++    }
++
++    start = 1;                  /* This is used to avoid multiplication etc
++                                 * when there is only the value '1' in the
++                                 * buffer. */
++    wvalue = 0;                 /* The 'value' of the window */
++    wstart = bits - 1;          /* The top bit of the window */
++    wend = 0;                   /* The bottom bit of the window */
++
++#if 1                           /* by Shay Gueron's suggestion */
++    j = m->top;                 /* borrow j */
++    if (m->d[j - 1] & (((BN_ULONG)1) << (BN_BITS2 - 1))) {
++        if (bn_wexpand(r, j) == NULL)
++            goto err;
++        /* 2^(top*BN_BITS2) - m */
++        r->d[0] = (0 - m->d[0]) & BN_MASK2;
++        for (i = 1; i < j; i++)
++            r->d[i] = (~m->d[i]) & BN_MASK2;
++        r->top = j;
++        /*
++         * Upper words will be zero if the corresponding words of 'm' were
++         * 0xfff[...], so decrement r->top accordingly.
++         */
++        bn_correct_top(r);
++    } else
++#endif
++    if (!BN_to_montgomery(r, BN_value_one(), mont, ctx))
++        goto err;
++    for (;;) {
++        if (BN_is_bit_set(p, wstart) == 0) {
++            if (!start) {
++                if (!BN_mod_mul_montgomery(r, r, r, mont, ctx))
++                    goto err;
++            }
++            if (wstart == 0)
++                break;
++            wstart--;
++            continue;
++        }
++        /*
++         * We now have wstart on a 'set' bit, we now need to work out how bit
++         * a window to do.  To do this we need to scan forward until the last
++         * set bit before the end of the window
++         */
++        j = wstart;
++        wvalue = 1;
++        wend = 0;
++        for (i = 1; i < window; i++) {
++            if (wstart - i < 0)
++                break;
++            if (BN_is_bit_set(p, wstart - i)) {
++                wvalue <<= (i - wend);
++                wvalue |= 1;
++                wend = i;
++            }
++        }
++
++        /* wend is the size of the current window */
++        j = wend + 1;
++        /* add the 'bytes above' */
++        if (!start)
++            for (i = 0; i < j; i++) {
++                if (!BN_mod_mul_montgomery(r, r, r, mont, ctx))
++                    goto err;
++            }
++
++        /* wvalue will be an odd number < 2^window */
++        if (!BN_mod_mul_montgomery(r, r, val[wvalue >> 1], mont, ctx))
++            goto err;
++
++        /* move the 'window' down further */
++        wstart -= wend + 1;
++        wvalue = 0;
++        start = 0;
++        if (wstart < 0)
++            break;
++    }
++#if defined(SPARC_T4_MONT)
++    if (OPENSSL_sparcv9cap_P[0] & (SPARCV9_VIS3 | SPARCV9_PREFER_FPU)) {
++        j = mont->N.top;        /* borrow j */
++        val[0]->d[0] = 1;       /* borrow val[0] */
++        for (i = 1; i < j; i++)
++            val[0]->d[i] = 0;
++        val[0]->top = j;
++        if (!BN_mod_mul_montgomery(rr, r, val[0], mont, ctx))
++            goto err;
++    } else
++#endif
++    if (!BN_from_montgomery(rr, r, mont, ctx))
++        goto err;
++    ret = 1;
++ err:
++    if (in_mont == NULL)
++        BN_MONT_CTX_free(mont);
++    BN_CTX_end(ctx);
++    bn_check_top(rr);
++    return (ret);
++}
++
++#if defined(SPARC_T4_MONT)
++static BN_ULONG bn_get_bits(const BIGNUM *a, int bitpos)
++{
++    BN_ULONG ret = 0;
++    int wordpos;
++
++    wordpos = bitpos / BN_BITS2;
++    bitpos %= BN_BITS2;
++    if (wordpos >= 0 && wordpos < a->top) {
++        ret = a->d[wordpos] & BN_MASK2;
++        if (bitpos) {
++            ret >>= bitpos;
++            if (++wordpos < a->top)
++                ret |= a->d[wordpos] << (BN_BITS2 - bitpos);
++        }
++    }
++
++    return ret & BN_MASK2;
++}
++#endif
++
++/*
++ * BN_mod_exp_mont_consttime() stores the precomputed powers in a specific
++ * layout so that accessing any of these table values shows the same access
++ * pattern as far as cache lines are concerned.  The following functions are
++ * used to transfer a BIGNUM from/to that table.
++ */
++
++static int MOD_EXP_CTIME_COPY_TO_PREBUF(const BIGNUM *b, int top,
++                                        unsigned char *buf, int idx,
++                                        int window)
++{
++    int i, j;
++    int width = 1 << window;
++    BN_ULONG *table = (BN_ULONG *)buf;
++
++    if (top > b->top)
++        top = b->top;           /* this works because 'buf' is explicitly
++                                 * zeroed */
++    for (i = 0, j = idx; i < top; i++, j += width) {
++        table[j] = b->d[i];
++    }
++
++    return 1;
++}
++
++static int MOD_EXP_CTIME_COPY_FROM_PREBUF(BIGNUM *b, int top,
++                                          unsigned char *buf, int idx,
++                                          int window)
++{
++    int i, j;
++    int width = 1 << window;
++    /*
++     * We declare table 'volatile' in order to discourage compiler
++     * from reordering loads from the table. Concern is that if
++     * reordered in specific manner loads might give away the
++     * information we are trying to conceal. Some would argue that
++     * compiler can reorder them anyway, but it can as well be
++     * argued that doing so would be violation of standard...
++     */
++    volatile BN_ULONG *table = (volatile BN_ULONG *)buf;
++
++    if (bn_wexpand(b, top) == NULL)
++        return 0;
++
++    if (window <= 3) {
++        for (i = 0; i < top; i++, table += width) {
++            BN_ULONG acc = 0;
++
++            for (j = 0; j < width; j++) {
++                acc |= table[j] &
++                       ((BN_ULONG)0 - (constant_time_eq_int(j,idx)&1));
++            }
++
++            b->d[i] = acc;
++        }
++    } else {
++        int xstride = 1 << (window - 2);
++        BN_ULONG y0, y1, y2, y3;
++
++        i = idx >> (window - 2);        /* equivalent of idx / xstride */
++        idx &= xstride - 1;             /* equivalent of idx % xstride */
++
++        y0 = (BN_ULONG)0 - (constant_time_eq_int(i,0)&1);
++        y1 = (BN_ULONG)0 - (constant_time_eq_int(i,1)&1);
++        y2 = (BN_ULONG)0 - (constant_time_eq_int(i,2)&1);
++        y3 = (BN_ULONG)0 - (constant_time_eq_int(i,3)&1);
++
++        for (i = 0; i < top; i++, table += width) {
++            BN_ULONG acc = 0;
++
++            for (j = 0; j < xstride; j++) {
++                acc |= ( (table[j + 0 * xstride] & y0) |
++                         (table[j + 1 * xstride] & y1) |
++                         (table[j + 2 * xstride] & y2) |
++                         (table[j + 3 * xstride] & y3) )
++                       & ((BN_ULONG)0 - (constant_time_eq_int(j,idx)&1));
++            }
++
++            b->d[i] = acc;
++        }
++    }
++
++    b->top = top;
++    bn_correct_top(b);
++    return 1;
++}
++
++/*
++ * Given a pointer value, compute the next address that is a cache line
++ * multiple.
++ */
++#define MOD_EXP_CTIME_ALIGN(x_) \
++        ((unsigned char*)(x_) + (MOD_EXP_CTIME_MIN_CACHE_LINE_WIDTH - (((size_t)(x_)) & (MOD_EXP_CTIME_MIN_CACHE_LINE_MASK))))
++
++/*
++ * This variant of BN_mod_exp_mont() uses fixed windows and the special
++ * precomputation memory layout to limit data-dependency to a minimum to
++ * protect secret exponents (cf. the hyper-threading timing attacks pointed
++ * out by Colin Percival,
++ * http://www.daemonology.net/hyperthreading-considered-harmful/)
++ */
++int BN_mod_exp_mont_consttime(BIGNUM *rr, const BIGNUM *a, const BIGNUM *p,
++                              const BIGNUM *m, BN_CTX *ctx,
++                              BN_MONT_CTX *in_mont)
++{
++    int i, bits, ret = 0, window, wvalue;
++    int top;
++    BN_MONT_CTX *mont = NULL;
++
++    int numPowers;
++    unsigned char *powerbufFree = NULL;
++    int powerbufLen = 0;
++    unsigned char *powerbuf = NULL;
++    BIGNUM tmp, am;
++#if defined(SPARC_T4_MONT)
++    unsigned int t4 = 0;
++#endif
++
++    bn_check_top(a);
++    bn_check_top(p);
++    bn_check_top(m);
++
++    if (!BN_is_odd(m)) {
++        BNerr(BN_F_BN_MOD_EXP_MONT_CONSTTIME, BN_R_CALLED_WITH_EVEN_MODULUS);
++        return (0);
++    }
++
++    top = m->top;
++
++    bits = BN_num_bits(p);
++    if (bits == 0) {
++        /* x**0 mod 1 is still zero. */
++        if (BN_is_one(m)) {
++            ret = 1;
++            BN_zero(rr);
++        } else {
++            ret = BN_one(rr);
++        }
++        return ret;
++    }
++
++    BN_CTX_start(ctx);
++
++    /*
++     * Allocate a montgomery context if it was not supplied by the caller. If
++     * this is not done, things will break in the montgomery part.
++     */
++    if (in_mont != NULL)
++        mont = in_mont;
++    else {
++        if ((mont = BN_MONT_CTX_new()) == NULL)
++            goto err;
++        if (!BN_MONT_CTX_set(mont, m, ctx))
++            goto err;
++    }
++
++#ifdef RSAZ_ENABLED
++    /*
++     * If the size of the operands allow it, perform the optimized
++     * RSAZ exponentiation. For further information see
++     * crypto/bn/rsaz_exp.c and accompanying assembly modules.
++     */
++    if ((16 == a->top) && (16 == p->top) && (BN_num_bits(m) == 1024)
++        && rsaz_avx2_eligible()) {
++        if (NULL == bn_wexpand(rr, 16))
++            goto err;
++        RSAZ_1024_mod_exp_avx2(rr->d, a->d, p->d, m->d, mont->RR.d,
++                               mont->n0[0]);
++        rr->top = 16;
++        rr->neg = 0;
++        bn_correct_top(rr);
++        ret = 1;
++        goto err;
++    } else if ((8 == a->top) && (8 == p->top) && (BN_num_bits(m) == 512)) {
++        if (NULL == bn_wexpand(rr, 8))
++            goto err;
++        RSAZ_512_mod_exp(rr->d, a->d, p->d, m->d, mont->n0[0], mont->RR.d);
++        rr->top = 8;
++        rr->neg = 0;
++        bn_correct_top(rr);
++        ret = 1;
++        goto err;
++    }
++#endif
++
++    /* Get the window size to use with size of p. */
++    window = BN_window_bits_for_ctime_exponent_size(bits);
++#if defined(SPARC_T4_MONT)
++    if (window >= 5 && (top & 15) == 0 && top <= 64 &&
++        (OPENSSL_sparcv9cap_P[1] & (CFR_MONTMUL | CFR_MONTSQR)) ==
++        (CFR_MONTMUL | CFR_MONTSQR) && (t4 = OPENSSL_sparcv9cap_P[0]))
++        window = 5;
++    else
++#endif
++#if defined(OPENSSL_BN_ASM_MONT5)
++    if (window >= 5) {
++        window = 5;             /* ~5% improvement for RSA2048 sign, and even
++                                 * for RSA4096 */
++        /* reserve space for mont->N.d[] copy */
++        powerbufLen += top * sizeof(mont->N.d[0]);
++    }
++#endif
++    (void)0;
++
++    /*
++     * Allocate a buffer large enough to hold all of the pre-computed powers
++     * of am, am itself and tmp.
++     */
++    numPowers = 1 << window;
++    powerbufLen += sizeof(m->d[0]) * (top * numPowers +
++                                      ((2 * top) >
++                                       numPowers ? (2 * top) : numPowers));
++#ifdef alloca
++    if (powerbufLen < 3072)
++        powerbufFree =
++            alloca(powerbufLen + MOD_EXP_CTIME_MIN_CACHE_LINE_WIDTH);
++    else
++#endif
++        if ((powerbufFree =
++             OPENSSL_malloc(powerbufLen + MOD_EXP_CTIME_MIN_CACHE_LINE_WIDTH))
++            == NULL)
++        goto err;
++
++    powerbuf = MOD_EXP_CTIME_ALIGN(powerbufFree);
++    memset(powerbuf, 0, powerbufLen);
++
++#ifdef alloca
++    if (powerbufLen < 3072)
++        powerbufFree = NULL;
++#endif
++
++    /* lay down tmp and am right after powers table */
++    tmp.d = (BN_ULONG *)(powerbuf + sizeof(m->d[0]) * top * numPowers);
++    am.d = tmp.d + top;
++    tmp.top = am.top = 0;
++    tmp.dmax = am.dmax = top;
++    tmp.neg = am.neg = 0;
++    tmp.flags = am.flags = BN_FLG_STATIC_DATA;
++
++    /* prepare a^0 in Montgomery domain */
++#if 1                           /* by Shay Gueron's suggestion */
++    if (m->d[top - 1] & (((BN_ULONG)1) << (BN_BITS2 - 1))) {
++        /* 2^(top*BN_BITS2) - m */
++        tmp.d[0] = (0 - m->d[0]) & BN_MASK2;
++        for (i = 1; i < top; i++)
++            tmp.d[i] = (~m->d[i]) & BN_MASK2;
++        tmp.top = top;
++    } else
++#endif
++    if (!BN_to_montgomery(&tmp, BN_value_one(), mont, ctx))
++        goto err;
++
++    /* prepare a^1 in Montgomery domain */
++    if (a->neg || BN_ucmp(a, m) >= 0) {
++        if (!BN_mod(&am, a, m, ctx))
++            goto err;
++        if (!BN_to_montgomery(&am, &am, mont, ctx))
++            goto err;
++    } else if (!BN_to_montgomery(&am, a, mont, ctx))
++        goto err;
++
++#if defined(SPARC_T4_MONT)
++    if (t4) {
++        typedef int (*bn_pwr5_mont_f) (BN_ULONG *tp, const BN_ULONG *np,
++                                       const BN_ULONG *n0, const void *table,
++                                       int power, int bits);
++        int bn_pwr5_mont_t4_8(BN_ULONG *tp, const BN_ULONG *np,
++                              const BN_ULONG *n0, const void *table,
++                              int power, int bits);
++        int bn_pwr5_mont_t4_16(BN_ULONG *tp, const BN_ULONG *np,
++                               const BN_ULONG *n0, const void *table,
++                               int power, int bits);
++        int bn_pwr5_mont_t4_24(BN_ULONG *tp, const BN_ULONG *np,
++                               const BN_ULONG *n0, const void *table,
++                               int power, int bits);
++        int bn_pwr5_mont_t4_32(BN_ULONG *tp, const BN_ULONG *np,
++                               const BN_ULONG *n0, const void *table,
++                               int power, int bits);
++        static const bn_pwr5_mont_f pwr5_funcs[4] = {
++            bn_pwr5_mont_t4_8, bn_pwr5_mont_t4_16,
++            bn_pwr5_mont_t4_24, bn_pwr5_mont_t4_32
++        };
++        bn_pwr5_mont_f pwr5_worker = pwr5_funcs[top / 16 - 1];
++
++        typedef int (*bn_mul_mont_f) (BN_ULONG *rp, const BN_ULONG *ap,
++                                      const void *bp, const BN_ULONG *np,
++                                      const BN_ULONG *n0);
++        int bn_mul_mont_t4_8(BN_ULONG *rp, const BN_ULONG *ap, const void *bp,
++                             const BN_ULONG *np, const BN_ULONG *n0);
++        int bn_mul_mont_t4_16(BN_ULONG *rp, const BN_ULONG *ap,
++                              const void *bp, const BN_ULONG *np,
++                              const BN_ULONG *n0);
++        int bn_mul_mont_t4_24(BN_ULONG *rp, const BN_ULONG *ap,
++                              const void *bp, const BN_ULONG *np,
++                              const BN_ULONG *n0);
++        int bn_mul_mont_t4_32(BN_ULONG *rp, const BN_ULONG *ap,
++                              const void *bp, const BN_ULONG *np,
++                              const BN_ULONG *n0);
++        static const bn_mul_mont_f mul_funcs[4] = {
++            bn_mul_mont_t4_8, bn_mul_mont_t4_16,
++            bn_mul_mont_t4_24, bn_mul_mont_t4_32
++        };
++        bn_mul_mont_f mul_worker = mul_funcs[top / 16 - 1];
++
++        void bn_mul_mont_vis3(BN_ULONG *rp, const BN_ULONG *ap,
++                              const void *bp, const BN_ULONG *np,
++                              const BN_ULONG *n0, int num);
++        void bn_mul_mont_t4(BN_ULONG *rp, const BN_ULONG *ap,
++                            const void *bp, const BN_ULONG *np,
++                            const BN_ULONG *n0, int num);
++        void bn_mul_mont_gather5_t4(BN_ULONG *rp, const BN_ULONG *ap,
++                                    const void *table, const BN_ULONG *np,
++                                    const BN_ULONG *n0, int num, int power);
++        void bn_flip_n_scatter5_t4(const BN_ULONG *inp, size_t num,
++                                   void *table, size_t power);
++        void bn_gather5_t4(BN_ULONG *out, size_t num,
++                           void *table, size_t power);
++        void bn_flip_t4(BN_ULONG *dst, BN_ULONG *src, size_t num);
++
++        BN_ULONG *np = mont->N.d, *n0 = mont->n0;
++        int stride = 5 * (6 - (top / 16 - 1)); /* multiple of 5, but less
++                                                * than 32 */
++
++        /*
++         * BN_to_montgomery can contaminate words above .top [in
++         * BN_DEBUG[_DEBUG] build]...
++         */
++        for (i = am.top; i < top; i++)
++            am.d[i] = 0;
++        for (i = tmp.top; i < top; i++)
++            tmp.d[i] = 0;
++
++        bn_flip_n_scatter5_t4(tmp.d, top, powerbuf, 0);
++        bn_flip_n_scatter5_t4(am.d, top, powerbuf, 1);
++        if (!(*mul_worker) (tmp.d, am.d, am.d, np, n0) &&
++            !(*mul_worker) (tmp.d, am.d, am.d, np, n0))
++            bn_mul_mont_vis3(tmp.d, am.d, am.d, np, n0, top);
++        bn_flip_n_scatter5_t4(tmp.d, top, powerbuf, 2);
++
++        for (i = 3; i < 32; i++) {
++            /* Calculate a^i = a^(i-1) * a */
++            if (!(*mul_worker) (tmp.d, tmp.d, am.d, np, n0) &&
++                !(*mul_worker) (tmp.d, tmp.d, am.d, np, n0))
++                bn_mul_mont_vis3(tmp.d, tmp.d, am.d, np, n0, top);
++            bn_flip_n_scatter5_t4(tmp.d, top, powerbuf, i);
++        }
++
++        /* switch to 64-bit domain */
++        np = alloca(top * sizeof(BN_ULONG));
++        top /= 2;
++        bn_flip_t4(np, mont->N.d, top);
++
++        bits--;
++        for (wvalue = 0, i = bits % 5; i >= 0; i--, bits--)
++            wvalue = (wvalue << 1) + BN_is_bit_set(p, bits);
++        bn_gather5_t4(tmp.d, top, powerbuf, wvalue);
++
++        /*
++         * Scan the exponent one window at a time starting from the most
++         * significant bits.
++         */
++        while (bits >= 0) {
++            if (bits < stride)
++                stride = bits + 1;
++            bits -= stride;
++            wvalue = bn_get_bits(p, bits + 1);
++
++            if ((*pwr5_worker) (tmp.d, np, n0, powerbuf, wvalue, stride))
++                continue;
++            /* retry once and fall back */
++            if ((*pwr5_worker) (tmp.d, np, n0, powerbuf, wvalue, stride))
++                continue;
++
++            bits += stride - 5;
++            wvalue >>= stride - 5;
++            wvalue &= 31;
++            bn_mul_mont_t4(tmp.d, tmp.d, tmp.d, np, n0, top);
++            bn_mul_mont_t4(tmp.d, tmp.d, tmp.d, np, n0, top);
++            bn_mul_mont_t4(tmp.d, tmp.d, tmp.d, np, n0, top);
++            bn_mul_mont_t4(tmp.d, tmp.d, tmp.d, np, n0, top);
++            bn_mul_mont_t4(tmp.d, tmp.d, tmp.d, np, n0, top);
++            bn_mul_mont_gather5_t4(tmp.d, tmp.d, powerbuf, np, n0, top,
++                                   wvalue);
++        }
++
++        bn_flip_t4(tmp.d, tmp.d, top);
++        top *= 2;
++        /* back to 32-bit domain */
++        tmp.top = top;
++        bn_correct_top(&tmp);
++        OPENSSL_cleanse(np, top * sizeof(BN_ULONG));
++    } else
++#endif
++#if defined(OPENSSL_BN_ASM_MONT5)
++    if (window == 5 && top > 1) {
++        /*
++         * This optimization uses ideas from http://eprint.iacr.org/2011/239,
++         * specifically optimization of cache-timing attack countermeasures
++         * and pre-computation optimization.
++         */
++
++        /*
++         * Dedicated window==4 case improves 512-bit RSA sign by ~15%, but as
++         * 512-bit RSA is hardly relevant, we omit it to spare size...
++         */
++        void bn_mul_mont_gather5(BN_ULONG *rp, const BN_ULONG *ap,
++                                 const void *table, const BN_ULONG *np,
++                                 const BN_ULONG *n0, int num, int power);
++        void bn_scatter5(const BN_ULONG *inp, size_t num,
++                         void *table, size_t power);
++        void bn_gather5(BN_ULONG *out, size_t num, void *table, size_t power);
++        void bn_power5(BN_ULONG *rp, const BN_ULONG *ap,
++                       const void *table, const BN_ULONG *np,
++                       const BN_ULONG *n0, int num, int power);
++        int bn_get_bits5(const BN_ULONG *ap, int off);
++        int bn_from_montgomery(BN_ULONG *rp, const BN_ULONG *ap,
++                               const BN_ULONG *not_used, const BN_ULONG *np,
++                               const BN_ULONG *n0, int num);
++
++        BN_ULONG *n0 = mont->n0, *np;
++
++        /*
++         * BN_to_montgomery can contaminate words above .top [in
++         * BN_DEBUG[_DEBUG] build]...
++         */
++        for (i = am.top; i < top; i++)
++            am.d[i] = 0;
++        for (i = tmp.top; i < top; i++)
++            tmp.d[i] = 0;
++
++        /*
++         * copy mont->N.d[] to improve cache locality
++         */
++        for (np = am.d + top, i = 0; i < top; i++)
++            np[i] = mont->N.d[i];
++
++        bn_scatter5(tmp.d, top, powerbuf, 0);
++        bn_scatter5(am.d, am.top, powerbuf, 1);
++        bn_mul_mont(tmp.d, am.d, am.d, np, n0, top);
++        bn_scatter5(tmp.d, top, powerbuf, 2);
++
++# if 0
++        for (i = 3; i < 32; i++) {
++            /* Calculate a^i = a^(i-1) * a */
++            bn_mul_mont_gather5(tmp.d, am.d, powerbuf, np, n0, top, i - 1);
++            bn_scatter5(tmp.d, top, powerbuf, i);
++        }
++# else
++        /* same as above, but uses squaring for 1/2 of operations */
++        for (i = 4; i < 32; i *= 2) {
++            bn_mul_mont(tmp.d, tmp.d, tmp.d, np, n0, top);
++            bn_scatter5(tmp.d, top, powerbuf, i);
++        }
++        for (i = 3; i < 8; i += 2) {
++            int j;
++            bn_mul_mont_gather5(tmp.d, am.d, powerbuf, np, n0, top, i - 1);
++            bn_scatter5(tmp.d, top, powerbuf, i);
++            for (j = 2 * i; j < 32; j *= 2) {
++                bn_mul_mont(tmp.d, tmp.d, tmp.d, np, n0, top);
++                bn_scatter5(tmp.d, top, powerbuf, j);
++            }
++        }
++        for (; i < 16; i += 2) {
++            bn_mul_mont_gather5(tmp.d, am.d, powerbuf, np, n0, top, i - 1);
++            bn_scatter5(tmp.d, top, powerbuf, i);
++            bn_mul_mont(tmp.d, tmp.d, tmp.d, np, n0, top);
++            bn_scatter5(tmp.d, top, powerbuf, 2 * i);
++        }
++        for (; i < 32; i += 2) {
++            bn_mul_mont_gather5(tmp.d, am.d, powerbuf, np, n0, top, i - 1);
++            bn_scatter5(tmp.d, top, powerbuf, i);
++        }
++# endif
++        bits--;
++        for (wvalue = 0, i = bits % 5; i >= 0; i--, bits--)
++            wvalue = (wvalue << 1) + BN_is_bit_set(p, bits);
++        bn_gather5(tmp.d, top, powerbuf, wvalue);
++
++        /*
++         * Scan the exponent one window at a time starting from the most
++         * significant bits.
++         */
++        if (top & 7)
++            while (bits >= 0) {
++                for (wvalue = 0, i = 0; i < 5; i++, bits--)
++                    wvalue = (wvalue << 1) + BN_is_bit_set(p, bits);
++
++                bn_mul_mont(tmp.d, tmp.d, tmp.d, np, n0, top);
++                bn_mul_mont(tmp.d, tmp.d, tmp.d, np, n0, top);
++                bn_mul_mont(tmp.d, tmp.d, tmp.d, np, n0, top);
++                bn_mul_mont(tmp.d, tmp.d, tmp.d, np, n0, top);
++                bn_mul_mont(tmp.d, tmp.d, tmp.d, np, n0, top);
++                bn_mul_mont_gather5(tmp.d, tmp.d, powerbuf, np, n0, top,
++                                    wvalue);
++        } else {
++            while (bits >= 0) {
++                wvalue = bn_get_bits5(p->d, bits - 4);
++                bits -= 5;
++                bn_power5(tmp.d, tmp.d, powerbuf, np, n0, top, wvalue);
++            }
++        }
++
++        ret = bn_from_montgomery(tmp.d, tmp.d, NULL, np, n0, top);
++        tmp.top = top;
++        bn_correct_top(&tmp);
++        if (ret) {
++            if (!BN_copy(rr, &tmp))
++                ret = 0;
++            goto err;           /* non-zero ret means it's not error */
++        }
++    } else
++#endif
++    {
++        if (!MOD_EXP_CTIME_COPY_TO_PREBUF(&tmp, top, powerbuf, 0, window))
++            goto err;
++        if (!MOD_EXP_CTIME_COPY_TO_PREBUF(&am, top, powerbuf, 1, window))
++            goto err;
++
++        /*
++         * If the window size is greater than 1, then calculate
++         * val[i=2..2^winsize-1]. Powers are computed as a*a^(i-1) (even
++         * powers could instead be computed as (a^(i/2))^2 to use the slight
++         * performance advantage of sqr over mul).
++         */
++        if (window > 1) {
++            if (!BN_mod_mul_montgomery(&tmp, &am, &am, mont, ctx))
++                goto err;
++            if (!MOD_EXP_CTIME_COPY_TO_PREBUF(&tmp, top, powerbuf, 2,
++                                              window))
++                goto err;
++            for (i = 3; i < numPowers; i++) {
++                /* Calculate a^i = a^(i-1) * a */
++                if (!BN_mod_mul_montgomery(&tmp, &am, &tmp, mont, ctx))
++                    goto err;
++                if (!MOD_EXP_CTIME_COPY_TO_PREBUF(&tmp, top, powerbuf, i,
++                                                  window))
++                    goto err;
++            }
++        }
++
++        bits--;
++        for (wvalue = 0, i = bits % window; i >= 0; i--, bits--)
++            wvalue = (wvalue << 1) + BN_is_bit_set(p, bits);
++        if (!MOD_EXP_CTIME_COPY_FROM_PREBUF(&tmp, top, powerbuf, wvalue,
++                                            window))
++            goto err;
++
++        /*
++         * Scan the exponent one window at a time starting from the most
++         * significant bits.
++         */
++        while (bits >= 0) {
++            wvalue = 0;         /* The 'value' of the window */
++
++            /* Scan the window, squaring the result as we go */
++            for (i = 0; i < window; i++, bits--) {
++                if (!BN_mod_mul_montgomery(&tmp, &tmp, &tmp, mont, ctx))
++                    goto err;
++                wvalue = (wvalue << 1) + BN_is_bit_set(p, bits);
++            }
++
++            /*
++             * Fetch the appropriate pre-computed value from the pre-buf
++             */
++            if (!MOD_EXP_CTIME_COPY_FROM_PREBUF(&am, top, powerbuf, wvalue,
++                                                window))
++                goto err;
++
++            /* Multiply the result into the intermediate result */
++            if (!BN_mod_mul_montgomery(&tmp, &tmp, &am, mont, ctx))
++                goto err;
++        }
++    }
++
++    /* Convert the final result from montgomery to standard format */
++#if defined(SPARC_T4_MONT)
++    if (OPENSSL_sparcv9cap_P[0] & (SPARCV9_VIS3 | SPARCV9_PREFER_FPU)) {
++        am.d[0] = 1;            /* borrow am */
++        for (i = 1; i < top; i++)
++            am.d[i] = 0;
++        if (!BN_mod_mul_montgomery(rr, &tmp, &am, mont, ctx))
++            goto err;
++    } else
++#endif
++    if (!BN_from_montgomery(rr, &tmp, mont, ctx))
++        goto err;
++    ret = 1;
++ err:
++    if (in_mont == NULL)
++        BN_MONT_CTX_free(mont);
++    if (powerbuf != NULL) {
++        OPENSSL_cleanse(powerbuf, powerbufLen);
++        OPENSSL_free(powerbufFree);
++    }
++    BN_CTX_end(ctx);
++    return (ret);
++}
++
++int BN_mod_exp_mont_word(BIGNUM *rr, BN_ULONG a, const BIGNUM *p,
++                         const BIGNUM *m, BN_CTX *ctx, BN_MONT_CTX *in_mont)
++{
++    BN_MONT_CTX *mont = NULL;
++    int b, bits, ret = 0;
++    int r_is_one;
++    BN_ULONG w, next_w;
++    BIGNUM *d, *r, *t;
++    BIGNUM *swap_tmp;
++#define BN_MOD_MUL_WORD(r, w, m) \
++                (BN_mul_word(r, (w)) && \
++                (/* BN_ucmp(r, (m)) < 0 ? 1 :*/  \
++                        (BN_mod(t, r, m, ctx) && (swap_tmp = r, r = t, t = swap_tmp, 1))))
++    /*
++     * BN_MOD_MUL_WORD is only used with 'w' large, so the BN_ucmp test is
++     * probably more overhead than always using BN_mod (which uses BN_copy if
++     * a similar test returns true).
++     */
++    /*
++     * We can use BN_mod and do not need BN_nnmod because our accumulator is
++     * never negative (the result of BN_mod does not depend on the sign of
++     * the modulus).
++     */
++#define BN_TO_MONTGOMERY_WORD(r, w, mont) \
++                (BN_set_word(r, (w)) && BN_to_montgomery(r, r, (mont), ctx))
++
++    if (BN_get_flags(p, BN_FLG_CONSTTIME) != 0) {
++        /* BN_FLG_CONSTTIME only supported by BN_mod_exp_mont() */
++        BNerr(BN_F_BN_MOD_EXP_MONT_WORD, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
++        return 0;
++    }
++
++    bn_check_top(p);
++    bn_check_top(m);
++
++    if (!BN_is_odd(m)) {
++        BNerr(BN_F_BN_MOD_EXP_MONT_WORD, BN_R_CALLED_WITH_EVEN_MODULUS);
++        return (0);
++    }
++    if (m->top == 1)
++        a %= m->d[0];           /* make sure that 'a' is reduced */
++
++    bits = BN_num_bits(p);
++    if (bits == 0) {
++        /* x**0 mod 1 is still zero. */
++        if (BN_is_one(m)) {
++            ret = 1;
++            BN_zero(rr);
++        } else {
++            ret = BN_one(rr);
++        }
++        return ret;
++    }
++    if (a == 0) {
++        BN_zero(rr);
++        ret = 1;
++        return ret;
++    }
++
++    BN_CTX_start(ctx);
++    d = BN_CTX_get(ctx);
++    r = BN_CTX_get(ctx);
++    t = BN_CTX_get(ctx);
++    if (d == NULL || r == NULL || t == NULL)
++        goto err;
++
++    if (in_mont != NULL)
++        mont = in_mont;
++    else {
++        if ((mont = BN_MONT_CTX_new()) == NULL)
++            goto err;
++        if (!BN_MONT_CTX_set(mont, m, ctx))
++            goto err;
++    }
++
++    r_is_one = 1;               /* except for Montgomery factor */
++
++    /* bits-1 >= 0 */
++
++    /* The result is accumulated in the product r*w. */
++    w = a;                      /* bit 'bits-1' of 'p' is always set */
++    for (b = bits - 2; b >= 0; b--) {
++        /* First, square r*w. */
++        next_w = w * w;
++        if ((next_w / w) != w) { /* overflow */
++            if (r_is_one) {
++                if (!BN_TO_MONTGOMERY_WORD(r, w, mont))
++                    goto err;
++                r_is_one = 0;
++            } else {
++                if (!BN_MOD_MUL_WORD(r, w, m))
++                    goto err;
++            }
++            next_w = 1;
++        }
++        w = next_w;
++        if (!r_is_one) {
++            if (!BN_mod_mul_montgomery(r, r, r, mont, ctx))
++                goto err;
++        }
++
++        /* Second, multiply r*w by 'a' if exponent bit is set. */
++        if (BN_is_bit_set(p, b)) {
++            next_w = w * a;
++            if ((next_w / a) != w) { /* overflow */
++                if (r_is_one) {
++                    if (!BN_TO_MONTGOMERY_WORD(r, w, mont))
++                        goto err;
++                    r_is_one = 0;
++                } else {
++                    if (!BN_MOD_MUL_WORD(r, w, m))
++                        goto err;
++                }
++                next_w = a;
++            }
++            w = next_w;
++        }
++    }
++
++    /* Finally, set r:=r*w. */
++    if (w != 1) {
++        if (r_is_one) {
++            if (!BN_TO_MONTGOMERY_WORD(r, w, mont))
++                goto err;
++            r_is_one = 0;
++        } else {
++            if (!BN_MOD_MUL_WORD(r, w, m))
++                goto err;
++        }
++    }
++
++    if (r_is_one) {             /* can happen only if a == 1 */
++        if (!BN_one(rr))
++            goto err;
++    } else {
++        if (!BN_from_montgomery(rr, r, mont, ctx))
++            goto err;
++    }
++    ret = 1;
++ err:
++    if (in_mont == NULL)
++        BN_MONT_CTX_free(mont);
++    BN_CTX_end(ctx);
++    bn_check_top(rr);
++    return (ret);
++}
++
++/* The old fallback, simple version :-) */
++int BN_mod_exp_simple(BIGNUM *r, const BIGNUM *a, const BIGNUM *p,
++                      const BIGNUM *m, BN_CTX *ctx)
++{
++    int i, j, bits, ret = 0, wstart, wend, window, wvalue;
++    int start = 1;
++    BIGNUM *d;
++    /* Table of variables obtained from 'ctx' */
++    BIGNUM *val[TABLE_SIZE];
++
++    if (BN_get_flags(p, BN_FLG_CONSTTIME) != 0) {
++        /* BN_FLG_CONSTTIME only supported by BN_mod_exp_mont() */
++        BNerr(BN_F_BN_MOD_EXP_SIMPLE, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
++        return 0;
++    }
++
++    bits = BN_num_bits(p);
++   if (bits == 0) {
++        /* x**0 mod 1 is still zero. */
++        if (BN_is_one(m)) {
++            ret = 1;
++            BN_zero(r);
++        } else {
++            ret = BN_one(r);
++        }
++        return ret;
++    }
++
++    BN_CTX_start(ctx);
++    d = BN_CTX_get(ctx);
++    val[0] = BN_CTX_get(ctx);
++    if (!d || !val[0])
++        goto err;
++
++    if (!BN_nnmod(val[0], a, m, ctx))
++        goto err;               /* 1 */
++    if (BN_is_zero(val[0])) {
++        BN_zero(r);
++        ret = 1;
++        goto err;
++    }
++
++    window = BN_window_bits_for_exponent_size(bits);
++    if (window > 1) {
++        if (!BN_mod_mul(d, val[0], val[0], m, ctx))
++            goto err;           /* 2 */
++        j = 1 << (window - 1);
++        for (i = 1; i < j; i++) {
++            if (((val[i] = BN_CTX_get(ctx)) == NULL) ||
++                !BN_mod_mul(val[i], val[i - 1], d, m, ctx))
++                goto err;
++        }
++    }
++
++    start = 1;                  /* This is used to avoid multiplication etc
++                                 * when there is only the value '1' in the
++                                 * buffer. */
++    wvalue = 0;                 /* The 'value' of the window */
++    wstart = bits - 1;          /* The top bit of the window */
++    wend = 0;                   /* The bottom bit of the window */
++
++    if (!BN_one(r))
++        goto err;
++
++    for (;;) {
++        if (BN_is_bit_set(p, wstart) == 0) {
++            if (!start)
++                if (!BN_mod_mul(r, r, r, m, ctx))
++                    goto err;
++            if (wstart == 0)
++                break;
++            wstart--;
++            continue;
++        }
++        /*
++         * We now have wstart on a 'set' bit, we now need to work out how bit
++         * a window to do.  To do this we need to scan forward until the last
++         * set bit before the end of the window
++         */
++        j = wstart;
++        wvalue = 1;
++        wend = 0;
++        for (i = 1; i < window; i++) {
++            if (wstart - i < 0)
++                break;
++            if (BN_is_bit_set(p, wstart - i)) {
++                wvalue <<= (i - wend);
++                wvalue |= 1;
++                wend = i;
++            }
++        }
++
++        /* wend is the size of the current window */
++        j = wend + 1;
++        /* add the 'bytes above' */
++        if (!start)
++            for (i = 0; i < j; i++) {
++                if (!BN_mod_mul(r, r, r, m, ctx))
++                    goto err;
++            }
++
++        /* wvalue will be an odd number < 2^window */
++        if (!BN_mod_mul(r, r, val[wvalue >> 1], m, ctx))
++            goto err;
++
++        /* move the 'window' down further */
++        wstart -= wend + 1;
++        wvalue = 0;
++        start = 0;
++        if (wstart < 0)
++            break;
++    }
++    ret = 1;
++ err:
++    BN_CTX_end(ctx);
++    bn_check_top(r);
++    return (ret);
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/bn/bn_exp2.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/bn/bn_exp2.c
+new file mode 100644
+index 0000000..5141c21
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/bn/bn_exp2.c
+@@ -0,0 +1,201 @@
++/*
++ * Copyright 1995-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include "internal/cryptlib.h"
++#include "bn_lcl.h"
++
++#define TABLE_SIZE      32
++
++int BN_mod_exp2_mont(BIGNUM *rr, const BIGNUM *a1, const BIGNUM *p1,
++                     const BIGNUM *a2, const BIGNUM *p2, const BIGNUM *m,
++                     BN_CTX *ctx, BN_MONT_CTX *in_mont)
++{
++    int i, j, bits, b, bits1, bits2, ret =
++        0, wpos1, wpos2, window1, window2, wvalue1, wvalue2;
++    int r_is_one = 1;
++    BIGNUM *d, *r;
++    const BIGNUM *a_mod_m;
++    /* Tables of variables obtained from 'ctx' */
++    BIGNUM *val1[TABLE_SIZE], *val2[TABLE_SIZE];
++    BN_MONT_CTX *mont = NULL;
++
++    bn_check_top(a1);
++    bn_check_top(p1);
++    bn_check_top(a2);
++    bn_check_top(p2);
++    bn_check_top(m);
++
++    if (!(m->d[0] & 1)) {
++        BNerr(BN_F_BN_MOD_EXP2_MONT, BN_R_CALLED_WITH_EVEN_MODULUS);
++        return (0);
++    }
++    bits1 = BN_num_bits(p1);
++    bits2 = BN_num_bits(p2);
++    if ((bits1 == 0) && (bits2 == 0)) {
++        ret = BN_one(rr);
++        return ret;
++    }
++
++    bits = (bits1 > bits2) ? bits1 : bits2;
++
++    BN_CTX_start(ctx);
++    d = BN_CTX_get(ctx);
++    r = BN_CTX_get(ctx);
++    val1[0] = BN_CTX_get(ctx);
++    val2[0] = BN_CTX_get(ctx);
++    if (!d || !r || !val1[0] || !val2[0])
++        goto err;
++
++    if (in_mont != NULL)
++        mont = in_mont;
++    else {
++        if ((mont = BN_MONT_CTX_new()) == NULL)
++            goto err;
++        if (!BN_MONT_CTX_set(mont, m, ctx))
++            goto err;
++    }
++
++    window1 = BN_window_bits_for_exponent_size(bits1);
++    window2 = BN_window_bits_for_exponent_size(bits2);
++
++    /*
++     * Build table for a1:   val1[i] := a1^(2*i + 1) mod m  for i = 0 .. 2^(window1-1)
++     */
++    if (a1->neg || BN_ucmp(a1, m) >= 0) {
++        if (!BN_mod(val1[0], a1, m, ctx))
++            goto err;
++        a_mod_m = val1[0];
++    } else
++        a_mod_m = a1;
++    if (BN_is_zero(a_mod_m)) {
++        BN_zero(rr);
++        ret = 1;
++        goto err;
++    }
++
++    if (!BN_to_montgomery(val1[0], a_mod_m, mont, ctx))
++        goto err;
++    if (window1 > 1) {
++        if (!BN_mod_mul_montgomery(d, val1[0], val1[0], mont, ctx))
++            goto err;
++
++        j = 1 << (window1 - 1);
++        for (i = 1; i < j; i++) {
++            if (((val1[i] = BN_CTX_get(ctx)) == NULL) ||
++                !BN_mod_mul_montgomery(val1[i], val1[i - 1], d, mont, ctx))
++                goto err;
++        }
++    }
++
++    /*
++     * Build table for a2:   val2[i] := a2^(2*i + 1) mod m  for i = 0 .. 2^(window2-1)
++     */
++    if (a2->neg || BN_ucmp(a2, m) >= 0) {
++        if (!BN_mod(val2[0], a2, m, ctx))
++            goto err;
++        a_mod_m = val2[0];
++    } else
++        a_mod_m = a2;
++    if (BN_is_zero(a_mod_m)) {
++        BN_zero(rr);
++        ret = 1;
++        goto err;
++    }
++    if (!BN_to_montgomery(val2[0], a_mod_m, mont, ctx))
++        goto err;
++    if (window2 > 1) {
++        if (!BN_mod_mul_montgomery(d, val2[0], val2[0], mont, ctx))
++            goto err;
++
++        j = 1 << (window2 - 1);
++        for (i = 1; i < j; i++) {
++            if (((val2[i] = BN_CTX_get(ctx)) == NULL) ||
++                !BN_mod_mul_montgomery(val2[i], val2[i - 1], d, mont, ctx))
++                goto err;
++        }
++    }
++
++    /* Now compute the power product, using independent windows. */
++    r_is_one = 1;
++    wvalue1 = 0;                /* The 'value' of the first window */
++    wvalue2 = 0;                /* The 'value' of the second window */
++    wpos1 = 0;                  /* If wvalue1 > 0, the bottom bit of the
++                                 * first window */
++    wpos2 = 0;                  /* If wvalue2 > 0, the bottom bit of the
++                                 * second window */
++
++    if (!BN_to_montgomery(r, BN_value_one(), mont, ctx))
++        goto err;
++    for (b = bits - 1; b >= 0; b--) {
++        if (!r_is_one) {
++            if (!BN_mod_mul_montgomery(r, r, r, mont, ctx))
++                goto err;
++        }
++
++        if (!wvalue1)
++            if (BN_is_bit_set(p1, b)) {
++                /*
++                 * consider bits b-window1+1 .. b for this window
++                 */
++                i = b - window1 + 1;
++                while (!BN_is_bit_set(p1, i)) /* works for i<0 */
++                    i++;
++                wpos1 = i;
++                wvalue1 = 1;
++                for (i = b - 1; i >= wpos1; i--) {
++                    wvalue1 <<= 1;
++                    if (BN_is_bit_set(p1, i))
++                        wvalue1++;
++                }
++            }
++
++        if (!wvalue2)
++            if (BN_is_bit_set(p2, b)) {
++                /*
++                 * consider bits b-window2+1 .. b for this window
++                 */
++                i = b - window2 + 1;
++                while (!BN_is_bit_set(p2, i))
++                    i++;
++                wpos2 = i;
++                wvalue2 = 1;
++                for (i = b - 1; i >= wpos2; i--) {
++                    wvalue2 <<= 1;
++                    if (BN_is_bit_set(p2, i))
++                        wvalue2++;
++                }
++            }
++
++        if (wvalue1 && b == wpos1) {
++            /* wvalue1 is odd and < 2^window1 */
++            if (!BN_mod_mul_montgomery(r, r, val1[wvalue1 >> 1], mont, ctx))
++                goto err;
++            wvalue1 = 0;
++            r_is_one = 0;
++        }
++
++        if (wvalue2 && b == wpos2) {
++            /* wvalue2 is odd and < 2^window2 */
++            if (!BN_mod_mul_montgomery(r, r, val2[wvalue2 >> 1], mont, ctx))
++                goto err;
++            wvalue2 = 0;
++            r_is_one = 0;
++        }
++    }
++    if (!BN_from_montgomery(rr, r, mont, ctx))
++        goto err;
++    ret = 1;
++ err:
++    if (in_mont == NULL)
++        BN_MONT_CTX_free(mont);
++    BN_CTX_end(ctx);
++    bn_check_top(rr);
++    return (ret);
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/bn/bn_gcd.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/bn/bn_gcd.c
+new file mode 100644
+index 0000000..e1aac13
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/bn/bn_gcd.c
+@@ -0,0 +1,620 @@
++/*
++ * Copyright 1995-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include "internal/cryptlib.h"
++#include "bn_lcl.h"
++
++static BIGNUM *euclid(BIGNUM *a, BIGNUM *b);
++
++int BN_gcd(BIGNUM *r, const BIGNUM *in_a, const BIGNUM *in_b, BN_CTX *ctx)
++{
++    BIGNUM *a, *b, *t;
++    int ret = 0;
++
++    bn_check_top(in_a);
++    bn_check_top(in_b);
++
++    BN_CTX_start(ctx);
++    a = BN_CTX_get(ctx);
++    b = BN_CTX_get(ctx);
++    if (a == NULL || b == NULL)
++        goto err;
++
++    if (BN_copy(a, in_a) == NULL)
++        goto err;
++    if (BN_copy(b, in_b) == NULL)
++        goto err;
++    a->neg = 0;
++    b->neg = 0;
++
++    if (BN_cmp(a, b) < 0) {
++        t = a;
++        a = b;
++        b = t;
++    }
++    t = euclid(a, b);
++    if (t == NULL)
++        goto err;
++
++    if (BN_copy(r, t) == NULL)
++        goto err;
++    ret = 1;
++ err:
++    BN_CTX_end(ctx);
++    bn_check_top(r);
++    return (ret);
++}
++
++static BIGNUM *euclid(BIGNUM *a, BIGNUM *b)
++{
++    BIGNUM *t;
++    int shifts = 0;
++
++    bn_check_top(a);
++    bn_check_top(b);
++
++    /* 0 <= b <= a */
++    while (!BN_is_zero(b)) {
++        /* 0 < b <= a */
++
++        if (BN_is_odd(a)) {
++            if (BN_is_odd(b)) {
++                if (!BN_sub(a, a, b))
++                    goto err;
++                if (!BN_rshift1(a, a))
++                    goto err;
++                if (BN_cmp(a, b) < 0) {
++                    t = a;
++                    a = b;
++                    b = t;
++                }
++            } else {            /* a odd - b even */
++
++                if (!BN_rshift1(b, b))
++                    goto err;
++                if (BN_cmp(a, b) < 0) {
++                    t = a;
++                    a = b;
++                    b = t;
++                }
++            }
++        } else {                /* a is even */
++
++            if (BN_is_odd(b)) {
++                if (!BN_rshift1(a, a))
++                    goto err;
++                if (BN_cmp(a, b) < 0) {
++                    t = a;
++                    a = b;
++                    b = t;
++                }
++            } else {            /* a even - b even */
++
++                if (!BN_rshift1(a, a))
++                    goto err;
++                if (!BN_rshift1(b, b))
++                    goto err;
++                shifts++;
++            }
++        }
++        /* 0 <= b <= a */
++    }
++
++    if (shifts) {
++        if (!BN_lshift(a, a, shifts))
++            goto err;
++    }
++    bn_check_top(a);
++    return (a);
++ err:
++    return (NULL);
++}
++
++/* solves ax == 1 (mod n) */
++static BIGNUM *BN_mod_inverse_no_branch(BIGNUM *in,
++                                        const BIGNUM *a, const BIGNUM *n,
++                                        BN_CTX *ctx);
++
++BIGNUM *BN_mod_inverse(BIGNUM *in,
++                       const BIGNUM *a, const BIGNUM *n, BN_CTX *ctx)
++{
++    BIGNUM *rv;
++    int noinv;
++    rv = int_bn_mod_inverse(in, a, n, ctx, &noinv);
++    if (noinv)
++        BNerr(BN_F_BN_MOD_INVERSE, BN_R_NO_INVERSE);
++    return rv;
++}
++
++BIGNUM *int_bn_mod_inverse(BIGNUM *in,
++                           const BIGNUM *a, const BIGNUM *n, BN_CTX *ctx,
++                           int *pnoinv)
++{
++    BIGNUM *A, *B, *X, *Y, *M, *D, *T, *R = NULL;
++    BIGNUM *ret = NULL;
++    int sign;
++
++    if (pnoinv)
++        *pnoinv = 0;
++
++    if ((BN_get_flags(a, BN_FLG_CONSTTIME) != 0)
++        || (BN_get_flags(n, BN_FLG_CONSTTIME) != 0)) {
++        return BN_mod_inverse_no_branch(in, a, n, ctx);
++    }
++
++    bn_check_top(a);
++    bn_check_top(n);
++
++    BN_CTX_start(ctx);
++    A = BN_CTX_get(ctx);
++    B = BN_CTX_get(ctx);
++    X = BN_CTX_get(ctx);
++    D = BN_CTX_get(ctx);
++    M = BN_CTX_get(ctx);
++    Y = BN_CTX_get(ctx);
++    T = BN_CTX_get(ctx);
++    if (T == NULL)
++        goto err;
++
++    if (in == NULL)
++        R = BN_new();
++    else
++        R = in;
++    if (R == NULL)
++        goto err;
++
++    BN_one(X);
++    BN_zero(Y);
++    if (BN_copy(B, a) == NULL)
++        goto err;
++    if (BN_copy(A, n) == NULL)
++        goto err;
++    A->neg = 0;
++    if (B->neg || (BN_ucmp(B, A) >= 0)) {
++        if (!BN_nnmod(B, B, A, ctx))
++            goto err;
++    }
++    sign = -1;
++    /*-
++     * From  B = a mod |n|,  A = |n|  it follows that
++     *
++     *      0 <= B < A,
++     *     -sign*X*a  ==  B   (mod |n|),
++     *      sign*Y*a  ==  A   (mod |n|).
++     */
++
++    if (BN_is_odd(n) && (BN_num_bits(n) <= 2048)) {
++        /*
++         * Binary inversion algorithm; requires odd modulus. This is faster
++         * than the general algorithm if the modulus is sufficiently small
++         * (about 400 .. 500 bits on 32-bit systems, but much more on 64-bit
++         * systems)
++         */
++        int shift;
++
++        while (!BN_is_zero(B)) {
++            /*-
++             *      0 < B < |n|,
++             *      0 < A <= |n|,
++             * (1) -sign*X*a  ==  B   (mod |n|),
++             * (2)  sign*Y*a  ==  A   (mod |n|)
++             */
++
++            /*
++             * Now divide B by the maximum possible power of two in the
++             * integers, and divide X by the same value mod |n|. When we're
++             * done, (1) still holds.
++             */
++            shift = 0;
++            while (!BN_is_bit_set(B, shift)) { /* note that 0 < B */
++                shift++;
++
++                if (BN_is_odd(X)) {
++                    if (!BN_uadd(X, X, n))
++                        goto err;
++                }
++                /*
++                 * now X is even, so we can easily divide it by two
++                 */
++                if (!BN_rshift1(X, X))
++                    goto err;
++            }
++            if (shift > 0) {
++                if (!BN_rshift(B, B, shift))
++                    goto err;
++            }
++
++            /*
++             * Same for A and Y.  Afterwards, (2) still holds.
++             */
++            shift = 0;
++            while (!BN_is_bit_set(A, shift)) { /* note that 0 < A */
++                shift++;
++
++                if (BN_is_odd(Y)) {
++                    if (!BN_uadd(Y, Y, n))
++                        goto err;
++                }
++                /* now Y is even */
++                if (!BN_rshift1(Y, Y))
++                    goto err;
++            }
++            if (shift > 0) {
++                if (!BN_rshift(A, A, shift))
++                    goto err;
++            }
++
++            /*-
++             * We still have (1) and (2).
++             * Both  A  and  B  are odd.
++             * The following computations ensure that
++             *
++             *     0 <= B < |n|,
++             *      0 < A < |n|,
++             * (1) -sign*X*a  ==  B   (mod |n|),
++             * (2)  sign*Y*a  ==  A   (mod |n|),
++             *
++             * and that either  A  or  B  is even in the next iteration.
++             */
++            if (BN_ucmp(B, A) >= 0) {
++                /* -sign*(X + Y)*a == B - A  (mod |n|) */
++                if (!BN_uadd(X, X, Y))
++                    goto err;
++                /*
++                 * NB: we could use BN_mod_add_quick(X, X, Y, n), but that
++                 * actually makes the algorithm slower
++                 */
++                if (!BN_usub(B, B, A))
++                    goto err;
++            } else {
++                /*  sign*(X + Y)*a == A - B  (mod |n|) */
++                if (!BN_uadd(Y, Y, X))
++                    goto err;
++                /*
++                 * as above, BN_mod_add_quick(Y, Y, X, n) would slow things
++                 * down
++                 */
++                if (!BN_usub(A, A, B))
++                    goto err;
++            }
++        }
++    } else {
++        /* general inversion algorithm */
++
++        while (!BN_is_zero(B)) {
++            BIGNUM *tmp;
++
++            /*-
++             *      0 < B < A,
++             * (*) -sign*X*a  ==  B   (mod |n|),
++             *      sign*Y*a  ==  A   (mod |n|)
++             */
++
++            /* (D, M) := (A/B, A%B) ... */
++            if (BN_num_bits(A) == BN_num_bits(B)) {
++                if (!BN_one(D))
++                    goto err;
++                if (!BN_sub(M, A, B))
++                    goto err;
++            } else if (BN_num_bits(A) == BN_num_bits(B) + 1) {
++                /* A/B is 1, 2, or 3 */
++                if (!BN_lshift1(T, B))
++                    goto err;
++                if (BN_ucmp(A, T) < 0) {
++                    /* A < 2*B, so D=1 */
++                    if (!BN_one(D))
++                        goto err;
++                    if (!BN_sub(M, A, B))
++                        goto err;
++                } else {
++                    /* A >= 2*B, so D=2 or D=3 */
++                    if (!BN_sub(M, A, T))
++                        goto err;
++                    if (!BN_add(D, T, B))
++                        goto err; /* use D (:= 3*B) as temp */
++                    if (BN_ucmp(A, D) < 0) {
++                        /* A < 3*B, so D=2 */
++                        if (!BN_set_word(D, 2))
++                            goto err;
++                        /*
++                         * M (= A - 2*B) already has the correct value
++                         */
++                    } else {
++                        /* only D=3 remains */
++                        if (!BN_set_word(D, 3))
++                            goto err;
++                        /*
++                         * currently M = A - 2*B, but we need M = A - 3*B
++                         */
++                        if (!BN_sub(M, M, B))
++                            goto err;
++                    }
++                }
++            } else {
++                if (!BN_div(D, M, A, B, ctx))
++                    goto err;
++            }
++
++            /*-
++             * Now
++             *      A = D*B + M;
++             * thus we have
++             * (**)  sign*Y*a  ==  D*B + M   (mod |n|).
++             */
++
++            tmp = A;            /* keep the BIGNUM object, the value does not
++                                 * matter */
++
++            /* (A, B) := (B, A mod B) ... */
++            A = B;
++            B = M;
++            /* ... so we have  0 <= B < A  again */
++
++            /*-
++             * Since the former  M  is now  B  and the former  B  is now  A,
++             * (**) translates into
++             *       sign*Y*a  ==  D*A + B    (mod |n|),
++             * i.e.
++             *       sign*Y*a - D*A  ==  B    (mod |n|).
++             * Similarly, (*) translates into
++             *      -sign*X*a  ==  A          (mod |n|).
++             *
++             * Thus,
++             *   sign*Y*a + D*sign*X*a  ==  B  (mod |n|),
++             * i.e.
++             *        sign*(Y + D*X)*a  ==  B  (mod |n|).
++             *
++             * So if we set  (X, Y, sign) := (Y + D*X, X, -sign), we arrive back at
++             *      -sign*X*a  ==  B   (mod |n|),
++             *       sign*Y*a  ==  A   (mod |n|).
++             * Note that  X  and  Y  stay non-negative all the time.
++             */
++
++            /*
++             * most of the time D is very small, so we can optimize tmp :=
++             * D*X+Y
++             */
++            if (BN_is_one(D)) {
++                if (!BN_add(tmp, X, Y))
++                    goto err;
++            } else {
++                if (BN_is_word(D, 2)) {
++                    if (!BN_lshift1(tmp, X))
++                        goto err;
++                } else if (BN_is_word(D, 4)) {
++                    if (!BN_lshift(tmp, X, 2))
++                        goto err;
++                } else if (D->top == 1) {
++                    if (!BN_copy(tmp, X))
++                        goto err;
++                    if (!BN_mul_word(tmp, D->d[0]))
++                        goto err;
++                } else {
++                    if (!BN_mul(tmp, D, X, ctx))
++                        goto err;
++                }
++                if (!BN_add(tmp, tmp, Y))
++                    goto err;
++            }
++
++            M = Y;              /* keep the BIGNUM object, the value does not
++                                 * matter */
++            Y = X;
++            X = tmp;
++            sign = -sign;
++        }
++    }
++
++    /*-
++     * The while loop (Euclid's algorithm) ends when
++     *      A == gcd(a,n);
++     * we have
++     *       sign*Y*a  ==  A  (mod |n|),
++     * where  Y  is non-negative.
++     */
++
++    if (sign < 0) {
++        if (!BN_sub(Y, n, Y))
++            goto err;
++    }
++    /* Now  Y*a  ==  A  (mod |n|).  */
++
++    if (BN_is_one(A)) {
++        /* Y*a == 1  (mod |n|) */
++        if (!Y->neg && BN_ucmp(Y, n) < 0) {
++            if (!BN_copy(R, Y))
++                goto err;
++        } else {
++            if (!BN_nnmod(R, Y, n, ctx))
++                goto err;
++        }
++    } else {
++        if (pnoinv)
++            *pnoinv = 1;
++        goto err;
++    }
++    ret = R;
++ err:
++    if ((ret == NULL) && (in == NULL))
++        BN_free(R);
++    BN_CTX_end(ctx);
++    bn_check_top(ret);
++    return (ret);
++}
++
++/*
++ * BN_mod_inverse_no_branch is a special version of BN_mod_inverse. It does
++ * not contain branches that may leak sensitive information.
++ */
++static BIGNUM *BN_mod_inverse_no_branch(BIGNUM *in,
++                                        const BIGNUM *a, const BIGNUM *n,
++                                        BN_CTX *ctx)
++{
++    BIGNUM *A, *B, *X, *Y, *M, *D, *T, *R = NULL;
++    BIGNUM *ret = NULL;
++    int sign;
++
++    bn_check_top(a);
++    bn_check_top(n);
++
++    BN_CTX_start(ctx);
++    A = BN_CTX_get(ctx);
++    B = BN_CTX_get(ctx);
++    X = BN_CTX_get(ctx);
++    D = BN_CTX_get(ctx);
++    M = BN_CTX_get(ctx);
++    Y = BN_CTX_get(ctx);
++    T = BN_CTX_get(ctx);
++    if (T == NULL)
++        goto err;
++
++    if (in == NULL)
++        R = BN_new();
++    else
++        R = in;
++    if (R == NULL)
++        goto err;
++
++    BN_one(X);
++    BN_zero(Y);
++    if (BN_copy(B, a) == NULL)
++        goto err;
++    if (BN_copy(A, n) == NULL)
++        goto err;
++    A->neg = 0;
++
++    if (B->neg || (BN_ucmp(B, A) >= 0)) {
++        /*
++         * Turn BN_FLG_CONSTTIME flag on, so that when BN_div is invoked,
++         * BN_div_no_branch will be called eventually.
++         */
++         {
++            BIGNUM local_B;
++            bn_init(&local_B);
++            BN_with_flags(&local_B, B, BN_FLG_CONSTTIME);
++            if (!BN_nnmod(B, &local_B, A, ctx))
++                goto err;
++            /* Ensure local_B goes out of scope before any further use of B */
++        }
++    }
++    sign = -1;
++    /*-
++     * From  B = a mod |n|,  A = |n|  it follows that
++     *
++     *      0 <= B < A,
++     *     -sign*X*a  ==  B   (mod |n|),
++     *      sign*Y*a  ==  A   (mod |n|).
++     */
++
++    while (!BN_is_zero(B)) {
++        BIGNUM *tmp;
++
++        /*-
++         *      0 < B < A,
++         * (*) -sign*X*a  ==  B   (mod |n|),
++         *      sign*Y*a  ==  A   (mod |n|)
++         */
++
++        /*
++         * Turn BN_FLG_CONSTTIME flag on, so that when BN_div is invoked,
++         * BN_div_no_branch will be called eventually.
++         */
++        {
++            BIGNUM local_A;
++            bn_init(&local_A);
++            BN_with_flags(&local_A, A, BN_FLG_CONSTTIME);
++
++            /* (D, M) := (A/B, A%B) ... */
++            if (!BN_div(D, M, &local_A, B, ctx))
++                goto err;
++            /* Ensure local_A goes out of scope before any further use of A */
++        }
++
++        /*-
++         * Now
++         *      A = D*B + M;
++         * thus we have
++         * (**)  sign*Y*a  ==  D*B + M   (mod |n|).
++         */
++
++        tmp = A;                /* keep the BIGNUM object, the value does not
++                                 * matter */
++
++        /* (A, B) := (B, A mod B) ... */
++        A = B;
++        B = M;
++        /* ... so we have  0 <= B < A  again */
++
++        /*-
++         * Since the former  M  is now  B  and the former  B  is now  A,
++         * (**) translates into
++         *       sign*Y*a  ==  D*A + B    (mod |n|),
++         * i.e.
++         *       sign*Y*a - D*A  ==  B    (mod |n|).
++         * Similarly, (*) translates into
++         *      -sign*X*a  ==  A          (mod |n|).
++         *
++         * Thus,
++         *   sign*Y*a + D*sign*X*a  ==  B  (mod |n|),
++         * i.e.
++         *        sign*(Y + D*X)*a  ==  B  (mod |n|).
++         *
++         * So if we set  (X, Y, sign) := (Y + D*X, X, -sign), we arrive back at
++         *      -sign*X*a  ==  B   (mod |n|),
++         *       sign*Y*a  ==  A   (mod |n|).
++         * Note that  X  and  Y  stay non-negative all the time.
++         */
++
++        if (!BN_mul(tmp, D, X, ctx))
++            goto err;
++        if (!BN_add(tmp, tmp, Y))
++            goto err;
++
++        M = Y;                  /* keep the BIGNUM object, the value does not
++                                 * matter */
++        Y = X;
++        X = tmp;
++        sign = -sign;
++    }
++
++    /*-
++     * The while loop (Euclid's algorithm) ends when
++     *      A == gcd(a,n);
++     * we have
++     *       sign*Y*a  ==  A  (mod |n|),
++     * where  Y  is non-negative.
++     */
++
++    if (sign < 0) {
++        if (!BN_sub(Y, n, Y))
++            goto err;
++    }
++    /* Now  Y*a  ==  A  (mod |n|).  */
++
++    if (BN_is_one(A)) {
++        /* Y*a == 1  (mod |n|) */
++        if (!Y->neg && BN_ucmp(Y, n) < 0) {
++            if (!BN_copy(R, Y))
++                goto err;
++        } else {
++            if (!BN_nnmod(R, Y, n, ctx))
++                goto err;
++        }
++    } else {
++        BNerr(BN_F_BN_MOD_INVERSE_NO_BRANCH, BN_R_NO_INVERSE);
++        goto err;
++    }
++    ret = R;
++ err:
++    if ((ret == NULL) && (in == NULL))
++        BN_free(R);
++    BN_CTX_end(ctx);
++    bn_check_top(ret);
++    return (ret);
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/bn/bn_gf2m.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/bn/bn_gf2m.c
+new file mode 100644
+index 0000000..e69de29
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/bn/bn_intern.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/bn/bn_intern.c
+new file mode 100644
+index 0000000..2c97064
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/bn/bn_intern.c
+@@ -0,0 +1,210 @@
++/*
++ * Copyright 2014-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include "internal/cryptlib.h"
++#include "bn_lcl.h"
++
++/*
++ * Determine the modified width-(w+1) Non-Adjacent Form (wNAF) of 'scalar'.
++ * This is an array  r[]  of values that are either zero or odd with an
++ * absolute value less than  2^w  satisfying
++ *     scalar = \sum_j r[j]*2^j
++ * where at most one of any  w+1  consecutive digits is non-zero
++ * with the exception that the most significant digit may be only
++ * w-1 zeros away from that next non-zero digit.
++ */
++signed char *bn_compute_wNAF(const BIGNUM *scalar, int w, size_t *ret_len)
++{
++    int window_val;
++    signed char *r = NULL;
++    int sign = 1;
++    int bit, next_bit, mask;
++    size_t len = 0, j;
++
++    if (BN_is_zero(scalar)) {
++        r = OPENSSL_malloc(1);
++        if (r == NULL) {
++            BNerr(BN_F_BN_COMPUTE_WNAF, ERR_R_MALLOC_FAILURE);
++            goto err;
++        }
++        r[0] = 0;
++        *ret_len = 1;
++        return r;
++    }
++
++    if (w <= 0 || w > 7) {      /* 'signed char' can represent integers with
++                                 * absolute values less than 2^7 */
++        BNerr(BN_F_BN_COMPUTE_WNAF, ERR_R_INTERNAL_ERROR);
++        goto err;
++    }
++    bit = 1 << w;               /* at most 128 */
++    next_bit = bit << 1;        /* at most 256 */
++    mask = next_bit - 1;        /* at most 255 */
++
++    if (BN_is_negative(scalar)) {
++        sign = -1;
++    }
++
++    if (scalar->d == NULL || scalar->top == 0) {
++        BNerr(BN_F_BN_COMPUTE_WNAF, ERR_R_INTERNAL_ERROR);
++        goto err;
++    }
++
++    len = BN_num_bits(scalar);
++    r = OPENSSL_malloc(len + 1); /*
++                                  * Modified wNAF may be one digit longer than binary representation
++                                  * (*ret_len will be set to the actual length, i.e. at most
++                                  * BN_num_bits(scalar) + 1)
++                                  */
++    if (r == NULL) {
++        BNerr(BN_F_BN_COMPUTE_WNAF, ERR_R_MALLOC_FAILURE);
++        goto err;
++    }
++    window_val = scalar->d[0] & mask;
++    j = 0;
++    while ((window_val != 0) || (j + w + 1 < len)) { /* if j+w+1 >= len,
++                                                      * window_val will not
++                                                      * increase */
++        int digit = 0;
++
++        /* 0 <= window_val <= 2^(w+1) */
++
++        if (window_val & 1) {
++            /* 0 < window_val < 2^(w+1) */
++
++            if (window_val & bit) {
++                digit = window_val - next_bit; /* -2^w < digit < 0 */
++
++#if 1                           /* modified wNAF */
++                if (j + w + 1 >= len) {
++                    /*
++                     * Special case for generating modified wNAFs:
++                     * no new bits will be added into window_val,
++                     * so using a positive digit here will decrease
++                     * the total length of the representation
++                     */
++
++                    digit = window_val & (mask >> 1); /* 0 < digit < 2^w */
++                }
++#endif
++            } else {
++                digit = window_val; /* 0 < digit < 2^w */
++            }
++
++            if (digit <= -bit || digit >= bit || !(digit & 1)) {
++                BNerr(BN_F_BN_COMPUTE_WNAF, ERR_R_INTERNAL_ERROR);
++                goto err;
++            }
++
++            window_val -= digit;
++
++            /*
++             * now window_val is 0 or 2^(w+1) in standard wNAF generation;
++             * for modified window NAFs, it may also be 2^w
++             */
++            if (window_val != 0 && window_val != next_bit
++                && window_val != bit) {
++                BNerr(BN_F_BN_COMPUTE_WNAF, ERR_R_INTERNAL_ERROR);
++                goto err;
++            }
++        }
++
++        r[j++] = sign * digit;
++
++        window_val >>= 1;
++        window_val += bit * BN_is_bit_set(scalar, j + w);
++
++        if (window_val > next_bit) {
++            BNerr(BN_F_BN_COMPUTE_WNAF, ERR_R_INTERNAL_ERROR);
++            goto err;
++        }
++    }
++
++    if (j > len + 1) {
++        BNerr(BN_F_BN_COMPUTE_WNAF, ERR_R_INTERNAL_ERROR);
++        goto err;
++    }
++    *ret_len = j;
++    return r;
++
++ err:
++    OPENSSL_free(r);
++    return NULL;
++}
++
++int bn_get_top(const BIGNUM *a)
++{
++    return a->top;
++}
++
++void bn_set_top(BIGNUM *a, int top)
++{
++    a->top = top;
++}
++
++int bn_get_dmax(const BIGNUM *a)
++{
++    return a->dmax;
++}
++
++void bn_set_all_zero(BIGNUM *a)
++{
++    int i;
++
++    for (i = a->top; i < a->dmax; i++)
++        a->d[i] = 0;
++}
++
++int bn_copy_words(BN_ULONG *out, const BIGNUM *in, int size)
++{
++    if (in->top > size)
++        return 0;
++
++    memset(out, 0, sizeof(*out) * size);
++    if (in->d != NULL)
++        memcpy(out, in->d, sizeof(*out) * in->top);
++    return 1;
++}
++
++BN_ULONG *bn_get_words(const BIGNUM *a)
++{
++    return a->d;
++}
++
++void bn_set_static_words(BIGNUM *a, BN_ULONG *words, int size)
++{
++    a->d = words;
++    a->dmax = a->top = size;
++    a->neg = 0;
++    a->flags |= BN_FLG_STATIC_DATA;
++    bn_correct_top(a);
++}
++
++int bn_set_words(BIGNUM *a, BN_ULONG *words, int num_words)
++{
++    if (bn_wexpand(a, num_words) == NULL) {
++        BNerr(BN_F_BN_SET_WORDS, ERR_R_MALLOC_FAILURE);
++        return 0;
++    }
++
++    memcpy(a->d, words, sizeof(BN_ULONG) * num_words);
++    a->top = num_words;
++    bn_correct_top(a);
++    return 1;
++}
++
++size_t bn_sizeof_BIGNUM(void)
++{
++    return sizeof(BIGNUM);
++}
++
++BIGNUM *bn_array_el(BIGNUM *base, int el)
++{
++    return &base[el];
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/bn/bn_kron.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/bn/bn_kron.c
+new file mode 100644
+index 0000000..b9bc6cc
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/bn/bn_kron.c
+@@ -0,0 +1,140 @@
++/*
++ * Copyright 2000-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include "internal/cryptlib.h"
++#include "bn_lcl.h"
++
++/* least significant word */
++#define BN_lsw(n) (((n)->top == 0) ? (BN_ULONG) 0 : (n)->d[0])
++
++/* Returns -2 for errors because both -1 and 0 are valid results. */
++int BN_kronecker(const BIGNUM *a, const BIGNUM *b, BN_CTX *ctx)
++{
++    int i;
++    int ret = -2;               /* avoid 'uninitialized' warning */
++    int err = 0;
++    BIGNUM *A, *B, *tmp;
++    /*-
++     * In 'tab', only odd-indexed entries are relevant:
++     * For any odd BIGNUM n,
++     *     tab[BN_lsw(n) & 7]
++     * is $(-1)^{(n^2-1)/8}$ (using TeX notation).
++     * Note that the sign of n does not matter.
++     */
++    static const int tab[8] = { 0, 1, 0, -1, 0, -1, 0, 1 };
++
++    bn_check_top(a);
++    bn_check_top(b);
++
++    BN_CTX_start(ctx);
++    A = BN_CTX_get(ctx);
++    B = BN_CTX_get(ctx);
++    if (B == NULL)
++        goto end;
++
++    err = !BN_copy(A, a);
++    if (err)
++        goto end;
++    err = !BN_copy(B, b);
++    if (err)
++        goto end;
++
++    /*
++     * Kronecker symbol, implemented according to Henri Cohen,
++     * "A Course in Computational Algebraic Number Theory"
++     * (algorithm 1.4.10).
++     */
++
++    /* Cohen's step 1: */
++
++    if (BN_is_zero(B)) {
++        ret = BN_abs_is_word(A, 1);
++        goto end;
++    }
++
++    /* Cohen's step 2: */
++
++    if (!BN_is_odd(A) && !BN_is_odd(B)) {
++        ret = 0;
++        goto end;
++    }
++
++    /* now  B  is non-zero */
++    i = 0;
++    while (!BN_is_bit_set(B, i))
++        i++;
++    err = !BN_rshift(B, B, i);
++    if (err)
++        goto end;
++    if (i & 1) {
++        /* i is odd */
++        /* (thus  B  was even, thus  A  must be odd!)  */
++
++        /* set 'ret' to $(-1)^{(A^2-1)/8}$ */
++        ret = tab[BN_lsw(A) & 7];
++    } else {
++        /* i is even */
++        ret = 1;
++    }
++
++    if (B->neg) {
++        B->neg = 0;
++        if (A->neg)
++            ret = -ret;
++    }
++
++    /*
++     * now B is positive and odd, so what remains to be done is to compute
++     * the Jacobi symbol (A/B) and multiply it by 'ret'
++     */
++
++    while (1) {
++        /* Cohen's step 3: */
++
++        /*  B  is positive and odd */
++
++        if (BN_is_zero(A)) {
++            ret = BN_is_one(B) ? ret : 0;
++            goto end;
++        }
++
++        /* now  A  is non-zero */
++        i = 0;
++        while (!BN_is_bit_set(A, i))
++            i++;
++        err = !BN_rshift(A, A, i);
++        if (err)
++            goto end;
++        if (i & 1) {
++            /* i is odd */
++            /* multiply 'ret' by  $(-1)^{(B^2-1)/8}$ */
++            ret = ret * tab[BN_lsw(B) & 7];
++        }
++
++        /* Cohen's step 4: */
++        /* multiply 'ret' by  $(-1)^{(A-1)(B-1)/4}$ */
++        if ((A->neg ? ~BN_lsw(A) : BN_lsw(A)) & BN_lsw(B) & 2)
++            ret = -ret;
++
++        /* (A, B) := (B mod |A|, |A|) */
++        err = !BN_nnmod(B, B, A, ctx);
++        if (err)
++            goto end;
++        tmp = A;
++        A = B;
++        B = tmp;
++        tmp->neg = 0;
++    }
++ end:
++    BN_CTX_end(ctx);
++    if (err)
++        return -2;
++    else
++        return ret;
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/bn/bn_lcl.h b/CryptoPkg/Library/OpensslLib/openssl/crypto/bn/bn_lcl.h
+new file mode 100644
+index 0000000..5fb3814
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/bn/bn_lcl.h
+@@ -0,0 +1,689 @@
++/*
++ * Copyright 1995-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#ifndef HEADER_BN_LCL_H
++# define HEADER_BN_LCL_H
++
++/*
++ * The EDK2 build doesn't use bn_conf.h; it sets THIRTY_TWO_BIT or
++ * SIXTY_FOUR_BIT in its own environment since it doesn't re-run our
++ * Configure script and needs to support both 32-bit and 64-bit.
++ */
++# include 
++
++# if !defined(OPENSSL_SYS_UEFI)
++#  include "internal/bn_conf.h"
++# endif
++
++# include "internal/bn_int.h"
++
++#ifdef  __cplusplus
++extern "C" {
++#endif
++
++/*
++ * These preprocessor symbols control various aspects of the bignum headers
++ * and library code. They're not defined by any "normal" configuration, as
++ * they are intended for development and testing purposes. NB: defining all
++ * three can be useful for debugging application code as well as openssl
++ * itself. BN_DEBUG - turn on various debugging alterations to the bignum
++ * code BN_DEBUG_RAND - uses random poisoning of unused words to trip up
++ * mismanagement of bignum internals. You must also define BN_DEBUG.
++ */
++/* #define BN_DEBUG */
++/* #define BN_DEBUG_RAND */
++
++# ifndef OPENSSL_SMALL_FOOTPRINT
++#  define BN_MUL_COMBA
++#  define BN_SQR_COMBA
++#  define BN_RECURSION
++# endif
++
++/*
++ * This next option uses the C libraries (2 word)/(1 word) function. If it is
++ * not defined, I use my C version (which is slower). The reason for this
++ * flag is that when the particular C compiler library routine is used, and
++ * the library is linked with a different compiler, the library is missing.
++ * This mostly happens when the library is built with gcc and then linked
++ * using normal cc.  This would be a common occurrence because gcc normally
++ * produces code that is 2 times faster than system compilers for the big
++ * number stuff. For machines with only one compiler (or shared libraries),
++ * this should be on.  Again this in only really a problem on machines using
++ * "long long's", are 32bit, and are not using my assembler code.
++ */
++# if defined(OPENSSL_SYS_MSDOS) || defined(OPENSSL_SYS_WINDOWS) || \
++    defined(OPENSSL_SYS_WIN32) || defined(linux)
++#  define BN_DIV2W
++# endif
++
++/*
++ * 64-bit processor with LP64 ABI
++ */
++# ifdef SIXTY_FOUR_BIT_LONG
++#  define BN_ULLONG       unsigned long long
++#  define BN_BITS4        32
++#  define BN_MASK2        (0xffffffffffffffffL)
++#  define BN_MASK2l       (0xffffffffL)
++#  define BN_MASK2h       (0xffffffff00000000L)
++#  define BN_MASK2h1      (0xffffffff80000000L)
++#  define BN_DEC_CONV     (10000000000000000000UL)
++#  define BN_DEC_NUM      19
++#  define BN_DEC_FMT1     "%lu"
++#  define BN_DEC_FMT2     "%019lu"
++# endif
++
++/*
++ * 64-bit processor other than LP64 ABI
++ */
++# ifdef SIXTY_FOUR_BIT
++#  undef BN_LLONG
++#  undef BN_ULLONG
++#  define BN_BITS4        32
++#  define BN_MASK2        (0xffffffffffffffffLL)
++#  define BN_MASK2l       (0xffffffffL)
++#  define BN_MASK2h       (0xffffffff00000000LL)
++#  define BN_MASK2h1      (0xffffffff80000000LL)
++#  define BN_DEC_CONV     (10000000000000000000ULL)
++#  define BN_DEC_NUM      19
++#  define BN_DEC_FMT1     "%llu"
++#  define BN_DEC_FMT2     "%019llu"
++# endif
++
++# ifdef THIRTY_TWO_BIT
++#  ifdef BN_LLONG
++#   if defined(_WIN32) && !defined(__GNUC__)
++#    define BN_ULLONG     unsigned __int64
++#   else
++#    define BN_ULLONG     unsigned long long
++#   endif
++#  endif
++#  define BN_BITS4        16
++#  define BN_MASK2        (0xffffffffL)
++#  define BN_MASK2l       (0xffff)
++#  define BN_MASK2h1      (0xffff8000L)
++#  define BN_MASK2h       (0xffff0000L)
++#  define BN_DEC_CONV     (1000000000L)
++#  define BN_DEC_NUM      9
++#  define BN_DEC_FMT1     "%u"
++#  define BN_DEC_FMT2     "%09u"
++# endif
++
++
++/*-
++ * Bignum consistency macros
++ * There is one "API" macro, bn_fix_top(), for stripping leading zeroes from
++ * bignum data after direct manipulations on the data. There is also an
++ * "internal" macro, bn_check_top(), for verifying that there are no leading
++ * zeroes. Unfortunately, some auditing is required due to the fact that
++ * bn_fix_top() has become an overabused duct-tape because bignum data is
++ * occasionally passed around in an inconsistent state. So the following
++ * changes have been made to sort this out;
++ * - bn_fix_top()s implementation has been moved to bn_correct_top()
++ * - if BN_DEBUG isn't defined, bn_fix_top() maps to bn_correct_top(), and
++ *   bn_check_top() is as before.
++ * - if BN_DEBUG *is* defined;
++ *   - bn_check_top() tries to pollute unused words even if the bignum 'top' is
++ *     consistent. (ed: only if BN_DEBUG_RAND is defined)
++ *   - bn_fix_top() maps to bn_check_top() rather than "fixing" anything.
++ * The idea is to have debug builds flag up inconsistent bignums when they
++ * occur. If that occurs in a bn_fix_top(), we examine the code in question; if
++ * the use of bn_fix_top() was appropriate (ie. it follows directly after code
++ * that manipulates the bignum) it is converted to bn_correct_top(), and if it
++ * was not appropriate, we convert it permanently to bn_check_top() and track
++ * down the cause of the bug. Eventually, no internal code should be using the
++ * bn_fix_top() macro. External applications and libraries should try this with
++ * their own code too, both in terms of building against the openssl headers
++ * with BN_DEBUG defined *and* linking with a version of OpenSSL built with it
++ * defined. This not only improves external code, it provides more test
++ * coverage for openssl's own code.
++ */
++
++# ifdef BN_DEBUG
++
++#  ifdef BN_DEBUG_RAND
++/* To avoid "make update" cvs wars due to BN_DEBUG, use some tricks */
++#   ifndef RAND_bytes
++int RAND_bytes(unsigned char *buf, int num);
++#    define BN_DEBUG_TRIX
++#   endif
++#   define bn_pollute(a) \
++        do { \
++            const BIGNUM *_bnum1 = (a); \
++            if (_bnum1->top < _bnum1->dmax) { \
++                unsigned char _tmp_char; \
++                /* We cast away const without the compiler knowing, any \
++                 * *genuinely* constant variables that aren't mutable \
++                 * wouldn't be constructed with top!=dmax. */ \
++                BN_ULONG *_not_const; \
++                memcpy(&_not_const, &_bnum1->d, sizeof(_not_const)); \
++                RAND_bytes(&_tmp_char, 1); /* Debug only - safe to ignore error return */\
++                memset(_not_const + _bnum1->top, _tmp_char, \
++                       sizeof(*_not_const) * (_bnum1->dmax - _bnum1->top)); \
++            } \
++        } while(0)
++#   ifdef BN_DEBUG_TRIX
++#    undef RAND_bytes
++#   endif
++#  else
++#   define bn_pollute(a)
++#  endif
++#  define bn_check_top(a) \
++        do { \
++                const BIGNUM *_bnum2 = (a); \
++                if (_bnum2 != NULL) { \
++                        OPENSSL_assert(((_bnum2->top == 0) && !_bnum2->neg) || \
++                                (_bnum2->top && (_bnum2->d[_bnum2->top - 1] != 0))); \
++                        bn_pollute(_bnum2); \
++                } \
++        } while(0)
++
++#  define bn_fix_top(a)           bn_check_top(a)
++
++#  define bn_check_size(bn, bits) bn_wcheck_size(bn, ((bits+BN_BITS2-1))/BN_BITS2)
++#  define bn_wcheck_size(bn, words) \
++        do { \
++                const BIGNUM *_bnum2 = (bn); \
++                OPENSSL_assert((words) <= (_bnum2)->dmax && \
++                        (words) >= (_bnum2)->top); \
++                /* avoid unused variable warning with NDEBUG */ \
++                (void)(_bnum2); \
++        } while(0)
++
++# else                          /* !BN_DEBUG */
++
++#  define bn_pollute(a)
++#  define bn_check_top(a)
++#  define bn_fix_top(a)           bn_correct_top(a)
++#  define bn_check_size(bn, bits)
++#  define bn_wcheck_size(bn, words)
++
++# endif
++
++BN_ULONG bn_mul_add_words(BN_ULONG *rp, const BN_ULONG *ap, int num,
++                          BN_ULONG w);
++BN_ULONG bn_mul_words(BN_ULONG *rp, const BN_ULONG *ap, int num, BN_ULONG w);
++void bn_sqr_words(BN_ULONG *rp, const BN_ULONG *ap, int num);
++BN_ULONG bn_div_words(BN_ULONG h, BN_ULONG l, BN_ULONG d);
++BN_ULONG bn_add_words(BN_ULONG *rp, const BN_ULONG *ap, const BN_ULONG *bp,
++                      int num);
++BN_ULONG bn_sub_words(BN_ULONG *rp, const BN_ULONG *ap, const BN_ULONG *bp,
++                      int num);
++
++struct bignum_st {
++    BN_ULONG *d;                /* Pointer to an array of 'BN_BITS2' bit
++                                 * chunks. */
++    int top;                    /* Index of last used d +1. */
++    /* The next are internal book keeping for bn_expand. */
++    int dmax;                   /* Size of the d array. */
++    int neg;                    /* one if the number is negative */
++    int flags;
++};
++
++/* Used for montgomery multiplication */
++struct bn_mont_ctx_st {
++    int ri;                     /* number of bits in R */
++    BIGNUM RR;                  /* used to convert to montgomery form */
++    BIGNUM N;                   /* The modulus */
++    BIGNUM Ni;                  /* R*(1/R mod N) - N*Ni = 1 (Ni is only
++                                 * stored for bignum algorithm) */
++    BN_ULONG n0[2];             /* least significant word(s) of Ni; (type
++                                 * changed with 0.9.9, was "BN_ULONG n0;"
++                                 * before) */
++    int flags;
++};
++
++/*
++ * Used for reciprocal division/mod functions It cannot be shared between
++ * threads
++ */
++struct bn_recp_ctx_st {
++    BIGNUM N;                   /* the divisor */
++    BIGNUM Nr;                  /* the reciprocal */
++    int num_bits;
++    int shift;
++    int flags;
++};
++
++/* Used for slow "generation" functions. */
++struct bn_gencb_st {
++    unsigned int ver;           /* To handle binary (in)compatibility */
++    void *arg;                  /* callback-specific data */
++    union {
++        /* if (ver==1) - handles old style callbacks */
++        void (*cb_1) (int, int, void *);
++        /* if (ver==2) - new callback style */
++        int (*cb_2) (int, int, BN_GENCB *);
++    } cb;
++};
++
++/*-
++ * BN_window_bits_for_exponent_size -- macro for sliding window mod_exp functions
++ *
++ *
++ * For window size 'w' (w >= 2) and a random 'b' bits exponent,
++ * the number of multiplications is a constant plus on average
++ *
++ *    2^(w-1) + (b-w)/(w+1);
++ *
++ * here  2^(w-1)  is for precomputing the table (we actually need
++ * entries only for windows that have the lowest bit set), and
++ * (b-w)/(w+1)  is an approximation for the expected number of
++ * w-bit windows, not counting the first one.
++ *
++ * Thus we should use
++ *
++ *    w >= 6  if        b > 671
++ *     w = 5  if  671 > b > 239
++ *     w = 4  if  239 > b >  79
++ *     w = 3  if   79 > b >  23
++ *    w <= 2  if   23 > b
++ *
++ * (with draws in between).  Very small exponents are often selected
++ * with low Hamming weight, so we use  w = 1  for b <= 23.
++ */
++# define BN_window_bits_for_exponent_size(b) \
++                ((b) > 671 ? 6 : \
++                 (b) > 239 ? 5 : \
++                 (b) >  79 ? 4 : \
++                 (b) >  23 ? 3 : 1)
++
++/*
++ * BN_mod_exp_mont_conttime is based on the assumption that the L1 data cache
++ * line width of the target processor is at least the following value.
++ */
++# define MOD_EXP_CTIME_MIN_CACHE_LINE_WIDTH      ( 64 )
++# define MOD_EXP_CTIME_MIN_CACHE_LINE_MASK       (MOD_EXP_CTIME_MIN_CACHE_LINE_WIDTH - 1)
++
++/*
++ * Window sizes optimized for fixed window size modular exponentiation
++ * algorithm (BN_mod_exp_mont_consttime). To achieve the security goals of
++ * BN_mode_exp_mont_consttime, the maximum size of the window must not exceed
++ * log_2(MOD_EXP_CTIME_MIN_CACHE_LINE_WIDTH). Window size thresholds are
++ * defined for cache line sizes of 32 and 64, cache line sizes where
++ * log_2(32)=5 and log_2(64)=6 respectively. A window size of 7 should only be
++ * used on processors that have a 128 byte or greater cache line size.
++ */
++# if MOD_EXP_CTIME_MIN_CACHE_LINE_WIDTH == 64
++
++#  define BN_window_bits_for_ctime_exponent_size(b) \
++                ((b) > 937 ? 6 : \
++                 (b) > 306 ? 5 : \
++                 (b) >  89 ? 4 : \
++                 (b) >  22 ? 3 : 1)
++#  define BN_MAX_WINDOW_BITS_FOR_CTIME_EXPONENT_SIZE    (6)
++
++# elif MOD_EXP_CTIME_MIN_CACHE_LINE_WIDTH == 32
++
++#  define BN_window_bits_for_ctime_exponent_size(b) \
++                ((b) > 306 ? 5 : \
++                 (b) >  89 ? 4 : \
++                 (b) >  22 ? 3 : 1)
++#  define BN_MAX_WINDOW_BITS_FOR_CTIME_EXPONENT_SIZE    (5)
++
++# endif
++
++/* Pentium pro 16,16,16,32,64 */
++/* Alpha       16,16,16,16.64 */
++# define BN_MULL_SIZE_NORMAL                     (16)/* 32 */
++# define BN_MUL_RECURSIVE_SIZE_NORMAL            (16)/* 32 less than */
++# define BN_SQR_RECURSIVE_SIZE_NORMAL            (16)/* 32 */
++# define BN_MUL_LOW_RECURSIVE_SIZE_NORMAL        (32)/* 32 */
++# define BN_MONT_CTX_SET_SIZE_WORD               (64)/* 32 */
++
++/*
++ * 2011-02-22 SMS. In various places, a size_t variable or a type cast to
++ * size_t was used to perform integer-only operations on pointers.  This
++ * failed on VMS with 64-bit pointers (CC /POINTER_SIZE = 64) because size_t
++ * is still only 32 bits.  What's needed in these cases is an integer type
++ * with the same size as a pointer, which size_t is not certain to be. The
++ * only fix here is VMS-specific.
++ */
++# if defined(OPENSSL_SYS_VMS)
++#  if __INITIAL_POINTER_SIZE == 64
++#   define PTR_SIZE_INT long long
++#  else                         /* __INITIAL_POINTER_SIZE == 64 */
++#   define PTR_SIZE_INT int
++#  endif                        /* __INITIAL_POINTER_SIZE == 64 [else] */
++# elif !defined(PTR_SIZE_INT)   /* defined(OPENSSL_SYS_VMS) */
++#  define PTR_SIZE_INT size_t
++# endif                         /* defined(OPENSSL_SYS_VMS) [else] */
++
++# if !defined(OPENSSL_NO_ASM) && !defined(OPENSSL_NO_INLINE_ASM) && !defined(PEDANTIC)
++/*
++ * BN_UMULT_HIGH section.
++ *
++ * No, I'm not trying to overwhelm you when stating that the
++ * product of N-bit numbers is 2*N bits wide:-) No, I don't expect
++ * you to be impressed when I say that if the compiler doesn't
++ * support 2*N integer type, then you have to replace every N*N
++ * multiplication with 4 (N/2)*(N/2) accompanied by some shifts
++ * and additions which unavoidably results in severe performance
++ * penalties. Of course provided that the hardware is capable of
++ * producing 2*N result... That's when you normally start
++ * considering assembler implementation. However! It should be
++ * pointed out that some CPUs (most notably Alpha, PowerPC and
++ * upcoming IA-64 family:-) provide *separate* instruction
++ * calculating the upper half of the product placing the result
++ * into a general purpose register. Now *if* the compiler supports
++ * inline assembler, then it's not impossible to implement the
++ * "bignum" routines (and have the compiler optimize 'em)
++ * exhibiting "native" performance in C. That's what BN_UMULT_HIGH
++ * macro is about:-)
++ *
++ *                                      
++ */
++#  if defined(__alpha) && (defined(SIXTY_FOUR_BIT_LONG) || defined(SIXTY_FOUR_BIT))
++#   if defined(__DECC)
++#    include 
++#    define BN_UMULT_HIGH(a,b)   (BN_ULONG)asm("umulh %a0,%a1,%v0",(a),(b))
++#   elif defined(__GNUC__) && __GNUC__>=2
++#    define BN_UMULT_HIGH(a,b)   ({      \
++        register BN_ULONG ret;          \
++        asm ("umulh     %1,%2,%0"       \
++             : "=r"(ret)                \
++             : "r"(a), "r"(b));         \
++        ret;                    })
++#   endif                       /* compiler */
++#  elif defined(_ARCH_PPC) && defined(__64BIT__) && defined(SIXTY_FOUR_BIT_LONG)
++#   if defined(__GNUC__) && __GNUC__>=2
++#    define BN_UMULT_HIGH(a,b)   ({      \
++        register BN_ULONG ret;          \
++        asm ("mulhdu    %0,%1,%2"       \
++             : "=r"(ret)                \
++             : "r"(a), "r"(b));         \
++        ret;                    })
++#   endif                       /* compiler */
++#  elif (defined(__x86_64) || defined(__x86_64__)) && \
++       (defined(SIXTY_FOUR_BIT_LONG) || defined(SIXTY_FOUR_BIT))
++#   if defined(__GNUC__) && __GNUC__>=2
++#    define BN_UMULT_HIGH(a,b)   ({      \
++        register BN_ULONG ret,discard;  \
++        asm ("mulq      %3"             \
++             : "=a"(discard),"=d"(ret)  \
++             : "a"(a), "g"(b)           \
++             : "cc");                   \
++        ret;                    })
++#    define BN_UMULT_LOHI(low,high,a,b)  \
++        asm ("mulq      %3"             \
++                : "=a"(low),"=d"(high)  \
++                : "a"(a),"g"(b)         \
++                : "cc");
++#   endif
++#  elif (defined(_M_AMD64) || defined(_M_X64)) && defined(SIXTY_FOUR_BIT)
++#   if defined(_MSC_VER) && _MSC_VER>=1400
++unsigned __int64 __umulh(unsigned __int64 a, unsigned __int64 b);
++unsigned __int64 _umul128(unsigned __int64 a, unsigned __int64 b,
++                          unsigned __int64 *h);
++#    pragma intrinsic(__umulh,_umul128)
++#    define BN_UMULT_HIGH(a,b)           __umulh((a),(b))
++#    define BN_UMULT_LOHI(low,high,a,b)  ((low)=_umul128((a),(b),&(high)))
++#   endif
++#  elif defined(__mips) && (defined(SIXTY_FOUR_BIT) || defined(SIXTY_FOUR_BIT_LONG))
++#   if defined(__GNUC__) && __GNUC__>=2
++#    if defined(__SIZEOF_INT128__) && __SIZEOF_INT128__==16
++      /* "h" constraint is not an option on R6 and was removed in 4.4 */
++#     define BN_UMULT_HIGH(a,b)          (((__uint128_t)(a)*(b))>>64)
++#     define BN_UMULT_LOHI(low,high,a,b) ({     \
++        __uint128_t ret=(__uint128_t)(a)*(b);   \
++        (high)=ret>>64; (low)=ret;       })
++#    else
++#     define BN_UMULT_HIGH(a,b) ({      \
++        register BN_ULONG ret;          \
++        asm ("dmultu    %1,%2"          \
++             : "=h"(ret)                \
++             : "r"(a), "r"(b) : "l");   \
++        ret;                    })
++#     define BN_UMULT_LOHI(low,high,a,b)\
++        asm ("dmultu    %2,%3"          \
++             : "=l"(low),"=h"(high)     \
++             : "r"(a), "r"(b));
++#    endif
++#   endif
++#  elif defined(__aarch64__) && defined(SIXTY_FOUR_BIT_LONG)
++#   if defined(__GNUC__) && __GNUC__>=2
++#    define BN_UMULT_HIGH(a,b)   ({      \
++        register BN_ULONG ret;          \
++        asm ("umulh     %0,%1,%2"       \
++             : "=r"(ret)                \
++             : "r"(a), "r"(b));         \
++        ret;                    })
++#   endif
++#  endif                        /* cpu */
++# endif                         /* OPENSSL_NO_ASM */
++
++/*************************************************************
++ * Using the long long type
++ */
++# define Lw(t)    (((BN_ULONG)(t))&BN_MASK2)
++# define Hw(t)    (((BN_ULONG)((t)>>BN_BITS2))&BN_MASK2)
++
++# ifdef BN_DEBUG_RAND
++#  define bn_clear_top2max(a) \
++        { \
++        int      ind = (a)->dmax - (a)->top; \
++        BN_ULONG *ftl = &(a)->d[(a)->top-1]; \
++        for (; ind != 0; ind--) \
++                *(++ftl) = 0x0; \
++        }
++# else
++#  define bn_clear_top2max(a)
++# endif
++
++# ifdef BN_LLONG
++#  define mul_add(r,a,w,c) { \
++        BN_ULLONG t; \
++        t=(BN_ULLONG)w * (a) + (r) + (c); \
++        (r)= Lw(t); \
++        (c)= Hw(t); \
++        }
++
++#  define mul(r,a,w,c) { \
++        BN_ULLONG t; \
++        t=(BN_ULLONG)w * (a) + (c); \
++        (r)= Lw(t); \
++        (c)= Hw(t); \
++        }
++
++#  define sqr(r0,r1,a) { \
++        BN_ULLONG t; \
++        t=(BN_ULLONG)(a)*(a); \
++        (r0)=Lw(t); \
++        (r1)=Hw(t); \
++        }
++
++# elif defined(BN_UMULT_LOHI)
++#  define mul_add(r,a,w,c) {              \
++        BN_ULONG high,low,ret,tmp=(a);  \
++        ret =  (r);                     \
++        BN_UMULT_LOHI(low,high,w,tmp);  \
++        ret += (c);                     \
++        (c) =  (ret<(c))?1:0;           \
++        (c) += high;                    \
++        ret += low;                     \
++        (c) += (ret>BN_BITS4)&BN_MASK2l)
++#  define L2HBITS(a)      (((a)<>BN_BITS2)&BN_MASKl)
++#  define LL2HBITS(a)     ((BN_ULLONG)((a)&BN_MASKl)<>(BN_BITS4-1); \
++        m =(m&BN_MASK2l)<<(BN_BITS4+1); \
++        l=(l+m)&BN_MASK2; if (l < m) h++; \
++        (lo)=l; \
++        (ho)=h; \
++        }
++
++#  define mul_add(r,a,bl,bh,c) { \
++        BN_ULONG l,h; \
++ \
++        h= (a); \
++        l=LBITS(h); \
++        h=HBITS(h); \
++        mul64(l,h,(bl),(bh)); \
++ \
++        /* non-multiply part */ \
++        l=(l+(c))&BN_MASK2; if (l < (c)) h++; \
++        (c)=(r); \
++        l=(l+(c))&BN_MASK2; if (l < (c)) h++; \
++        (c)=h&BN_MASK2; \
++        (r)=l; \
++        }
++
++#  define mul(r,a,bl,bh,c) { \
++        BN_ULONG l,h; \
++ \
++        h= (a); \
++        l=LBITS(h); \
++        h=HBITS(h); \
++        mul64(l,h,(bl),(bh)); \
++ \
++        /* non-multiply part */ \
++        l+=(c); if ((l&BN_MASK2) < (c)) h++; \
++        (c)=h&BN_MASK2; \
++        (r)=l&BN_MASK2; \
++        }
++# endif                         /* !BN_LLONG */
++
++void BN_RECP_CTX_init(BN_RECP_CTX *recp);
++void BN_MONT_CTX_init(BN_MONT_CTX *ctx);
++
++void bn_init(BIGNUM *a);
++void bn_mul_normal(BN_ULONG *r, BN_ULONG *a, int na, BN_ULONG *b, int nb);
++void bn_mul_comba8(BN_ULONG *r, BN_ULONG *a, BN_ULONG *b);
++void bn_mul_comba4(BN_ULONG *r, BN_ULONG *a, BN_ULONG *b);
++void bn_sqr_normal(BN_ULONG *r, const BN_ULONG *a, int n, BN_ULONG *tmp);
++void bn_sqr_comba8(BN_ULONG *r, const BN_ULONG *a);
++void bn_sqr_comba4(BN_ULONG *r, const BN_ULONG *a);
++int bn_cmp_words(const BN_ULONG *a, const BN_ULONG *b, int n);
++int bn_cmp_part_words(const BN_ULONG *a, const BN_ULONG *b, int cl, int dl);
++void bn_mul_recursive(BN_ULONG *r, BN_ULONG *a, BN_ULONG *b, int n2,
++                      int dna, int dnb, BN_ULONG *t);
++void bn_mul_part_recursive(BN_ULONG *r, BN_ULONG *a, BN_ULONG *b,
++                           int n, int tna, int tnb, BN_ULONG *t);
++void bn_sqr_recursive(BN_ULONG *r, const BN_ULONG *a, int n2, BN_ULONG *t);
++void bn_mul_low_normal(BN_ULONG *r, BN_ULONG *a, BN_ULONG *b, int n);
++void bn_mul_low_recursive(BN_ULONG *r, BN_ULONG *a, BN_ULONG *b, int n2,
++                          BN_ULONG *t);
++void bn_mul_high(BN_ULONG *r, BN_ULONG *a, BN_ULONG *b, BN_ULONG *l, int n2,
++                 BN_ULONG *t);
++BN_ULONG bn_add_part_words(BN_ULONG *r, const BN_ULONG *a, const BN_ULONG *b,
++                           int cl, int dl);
++BN_ULONG bn_sub_part_words(BN_ULONG *r, const BN_ULONG *a, const BN_ULONG *b,
++                           int cl, int dl);
++int bn_mul_mont(BN_ULONG *rp, const BN_ULONG *ap, const BN_ULONG *bp,
++                const BN_ULONG *np, const BN_ULONG *n0, int num);
++
++BIGNUM *int_bn_mod_inverse(BIGNUM *in,
++                           const BIGNUM *a, const BIGNUM *n, BN_CTX *ctx,
++                           int *noinv);
++
++int bn_probable_prime_dh(BIGNUM *rnd, int bits,
++                         const BIGNUM *add, const BIGNUM *rem, BN_CTX *ctx);
++int bn_probable_prime_dh_retry(BIGNUM *rnd, int bits, BN_CTX *ctx);
++int bn_probable_prime_dh_coprime(BIGNUM *rnd, int bits, BN_CTX *ctx);
++
++static ossl_inline BIGNUM *bn_expand(BIGNUM *a, int bits)
++{
++    if (bits > (INT_MAX - BN_BITS2 + 1))
++        return NULL;
++
++    if (((bits+BN_BITS2-1)/BN_BITS2) <= (a)->dmax)
++        return a;
++
++    return bn_expand2((a),(bits+BN_BITS2-1)/BN_BITS2);
++}
++
++#ifdef  __cplusplus
++}
++#endif
++
++#endif
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/bn/bn_lib.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/bn/bn_lib.c
+new file mode 100644
+index 0000000..17d34c3
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/bn/bn_lib.c
+@@ -0,0 +1,1037 @@
++/*
++ * Copyright 1995-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include 
++#include "internal/cryptlib.h"
++#include "bn_lcl.h"
++#include 
++
++/* This stuff appears to be completely unused, so is deprecated */
++#if OPENSSL_API_COMPAT < 0x00908000L
++/*-
++ * For a 32 bit machine
++ * 2 -   4 ==  128
++ * 3 -   8 ==  256
++ * 4 -  16 ==  512
++ * 5 -  32 == 1024
++ * 6 -  64 == 2048
++ * 7 - 128 == 4096
++ * 8 - 256 == 8192
++ */
++static int bn_limit_bits = 0;
++static int bn_limit_num = 8;    /* (1<= 0) {
++        if (mult > (int)(sizeof(int) * 8) - 1)
++            mult = sizeof(int) * 8 - 1;
++        bn_limit_bits = mult;
++        bn_limit_num = 1 << mult;
++    }
++    if (high >= 0) {
++        if (high > (int)(sizeof(int) * 8) - 1)
++            high = sizeof(int) * 8 - 1;
++        bn_limit_bits_high = high;
++        bn_limit_num_high = 1 << high;
++    }
++    if (low >= 0) {
++        if (low > (int)(sizeof(int) * 8) - 1)
++            low = sizeof(int) * 8 - 1;
++        bn_limit_bits_low = low;
++        bn_limit_num_low = 1 << low;
++    }
++    if (mont >= 0) {
++        if (mont > (int)(sizeof(int) * 8) - 1)
++            mont = sizeof(int) * 8 - 1;
++        bn_limit_bits_mont = mont;
++        bn_limit_num_mont = 1 << mont;
++    }
++}
++
++int BN_get_params(int which)
++{
++    if (which == 0)
++        return (bn_limit_bits);
++    else if (which == 1)
++        return (bn_limit_bits_high);
++    else if (which == 2)
++        return (bn_limit_bits_low);
++    else if (which == 3)
++        return (bn_limit_bits_mont);
++    else
++        return (0);
++}
++#endif
++
++const BIGNUM *BN_value_one(void)
++{
++    static const BN_ULONG data_one = 1L;
++    static const BIGNUM const_one =
++        { (BN_ULONG *)&data_one, 1, 1, 0, BN_FLG_STATIC_DATA };
++
++    return (&const_one);
++}
++
++int BN_num_bits_word(BN_ULONG l)
++{
++    static const unsigned char bits[256] = {
++        0, 1, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4,
++        5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
++        6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
++        6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
++        7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
++        7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
++        7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
++        7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
++        8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
++        8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
++        8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
++        8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
++        8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
++        8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
++        8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
++        8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
++    };
++
++#if defined(SIXTY_FOUR_BIT_LONG)
++    if (l & 0xffffffff00000000L) {
++        if (l & 0xffff000000000000L) {
++            if (l & 0xff00000000000000L) {
++                return (bits[(int)(l >> 56)] + 56);
++            } else
++                return (bits[(int)(l >> 48)] + 48);
++        } else {
++            if (l & 0x0000ff0000000000L) {
++                return (bits[(int)(l >> 40)] + 40);
++            } else
++                return (bits[(int)(l >> 32)] + 32);
++        }
++    } else
++#else
++# ifdef SIXTY_FOUR_BIT
++    if (l & 0xffffffff00000000LL) {
++        if (l & 0xffff000000000000LL) {
++            if (l & 0xff00000000000000LL) {
++                return (bits[(int)(l >> 56)] + 56);
++            } else
++                return (bits[(int)(l >> 48)] + 48);
++        } else {
++            if (l & 0x0000ff0000000000LL) {
++                return (bits[(int)(l >> 40)] + 40);
++            } else
++                return (bits[(int)(l >> 32)] + 32);
++        }
++    } else
++# endif
++#endif
++    {
++#if defined(THIRTY_TWO_BIT) || defined(SIXTY_FOUR_BIT) || defined(SIXTY_FOUR_BIT_LONG)
++        if (l & 0xffff0000L) {
++            if (l & 0xff000000L)
++                return (bits[(int)(l >> 24L)] + 24);
++            else
++                return (bits[(int)(l >> 16L)] + 16);
++        } else
++#endif
++        {
++#if defined(THIRTY_TWO_BIT) || defined(SIXTY_FOUR_BIT) || defined(SIXTY_FOUR_BIT_LONG)
++            if (l & 0xff00L)
++                return (bits[(int)(l >> 8)] + 8);
++            else
++#endif
++                return (bits[(int)(l)]);
++        }
++    }
++}
++
++int BN_num_bits(const BIGNUM *a)
++{
++    int i = a->top - 1;
++    bn_check_top(a);
++
++    if (BN_is_zero(a))
++        return 0;
++    return ((i * BN_BITS2) + BN_num_bits_word(a->d[i]));
++}
++
++static void bn_free_d(BIGNUM *a)
++{
++    if (BN_get_flags(a, BN_FLG_SECURE))
++        OPENSSL_secure_free(a->d);
++    else
++        OPENSSL_free(a->d);
++}
++
++
++void BN_clear_free(BIGNUM *a)
++{
++    int i;
++
++    if (a == NULL)
++        return;
++    bn_check_top(a);
++    if (a->d != NULL) {
++        OPENSSL_cleanse(a->d, a->dmax * sizeof(a->d[0]));
++        if (!BN_get_flags(a, BN_FLG_STATIC_DATA))
++            bn_free_d(a);
++    }
++    i = BN_get_flags(a, BN_FLG_MALLOCED);
++    OPENSSL_cleanse(a, sizeof(*a));
++    if (i)
++        OPENSSL_free(a);
++}
++
++void BN_free(BIGNUM *a)
++{
++    if (a == NULL)
++        return;
++    bn_check_top(a);
++    if (!BN_get_flags(a, BN_FLG_STATIC_DATA))
++        bn_free_d(a);
++    if (a->flags & BN_FLG_MALLOCED)
++        OPENSSL_free(a);
++    else {
++#if OPENSSL_API_COMPAT < 0x00908000L
++        a->flags |= BN_FLG_FREE;
++#endif
++        a->d = NULL;
++    }
++}
++
++void bn_init(BIGNUM *a)
++{
++    static BIGNUM nilbn;
++
++    *a = nilbn;
++    bn_check_top(a);
++}
++
++BIGNUM *BN_new(void)
++{
++    BIGNUM *ret;
++
++    if ((ret = OPENSSL_zalloc(sizeof(*ret))) == NULL) {
++        BNerr(BN_F_BN_NEW, ERR_R_MALLOC_FAILURE);
++        return (NULL);
++    }
++    ret->flags = BN_FLG_MALLOCED;
++    bn_check_top(ret);
++    return (ret);
++}
++
++ BIGNUM *BN_secure_new(void)
++ {
++     BIGNUM *ret = BN_new();
++     if (ret != NULL)
++         ret->flags |= BN_FLG_SECURE;
++     return (ret);
++ }
++
++/* This is used by bn_expand2() */
++/* The caller MUST check that words > b->dmax before calling this */
++static BN_ULONG *bn_expand_internal(const BIGNUM *b, int words)
++{
++    BN_ULONG *A, *a = NULL;
++    const BN_ULONG *B;
++    int i;
++
++    bn_check_top(b);
++
++    if (words > (INT_MAX / (4 * BN_BITS2))) {
++        BNerr(BN_F_BN_EXPAND_INTERNAL, BN_R_BIGNUM_TOO_LONG);
++        return NULL;
++    }
++    if (BN_get_flags(b, BN_FLG_STATIC_DATA)) {
++        BNerr(BN_F_BN_EXPAND_INTERNAL, BN_R_EXPAND_ON_STATIC_BIGNUM_DATA);
++        return (NULL);
++    }
++    if (BN_get_flags(b, BN_FLG_SECURE))
++        a = A = OPENSSL_secure_zalloc(words * sizeof(*a));
++    else
++        a = A = OPENSSL_zalloc(words * sizeof(*a));
++    if (A == NULL) {
++        BNerr(BN_F_BN_EXPAND_INTERNAL, ERR_R_MALLOC_FAILURE);
++        return (NULL);
++    }
++
++#if 1
++    B = b->d;
++    /* Check if the previous number needs to be copied */
++    if (B != NULL) {
++        for (i = b->top >> 2; i > 0; i--, A += 4, B += 4) {
++            /*
++             * The fact that the loop is unrolled
++             * 4-wise is a tribute to Intel. It's
++             * the one that doesn't have enough
++             * registers to accommodate more data.
++             * I'd unroll it 8-wise otherwise:-)
++             *
++             *              
++             */
++            BN_ULONG a0, a1, a2, a3;
++            a0 = B[0];
++            a1 = B[1];
++            a2 = B[2];
++            a3 = B[3];
++            A[0] = a0;
++            A[1] = a1;
++            A[2] = a2;
++            A[3] = a3;
++        }
++        switch (b->top & 3) {
++        case 3:
++            A[2] = B[2];
++        case 2:
++            A[1] = B[1];
++        case 1:
++            A[0] = B[0];
++        case 0:
++            /* Without the "case 0" some old optimizers got this wrong. */
++            ;
++        }
++    }
++#else
++    memset(A, 0, sizeof(*A) * words);
++    memcpy(A, b->d, sizeof(b->d[0]) * b->top);
++#endif
++
++    return (a);
++}
++
++/*
++ * This is an internal function that should not be used in applications. It
++ * ensures that 'b' has enough room for a 'words' word number and initialises
++ * any unused part of b->d with leading zeros. It is mostly used by the
++ * various BIGNUM routines. If there is an error, NULL is returned. If not,
++ * 'b' is returned.
++ */
++
++BIGNUM *bn_expand2(BIGNUM *b, int words)
++{
++    bn_check_top(b);
++
++    if (words > b->dmax) {
++        BN_ULONG *a = bn_expand_internal(b, words);
++        if (!a)
++            return NULL;
++        if (b->d) {
++            OPENSSL_cleanse(b->d, b->dmax * sizeof(b->d[0]));
++            bn_free_d(b);
++        }
++        b->d = a;
++        b->dmax = words;
++    }
++
++    bn_check_top(b);
++    return b;
++}
++
++BIGNUM *BN_dup(const BIGNUM *a)
++{
++    BIGNUM *t;
++
++    if (a == NULL)
++        return NULL;
++    bn_check_top(a);
++
++    t = BN_get_flags(a, BN_FLG_SECURE) ? BN_secure_new() : BN_new();
++    if (t == NULL)
++        return NULL;
++    if (!BN_copy(t, a)) {
++        BN_free(t);
++        return NULL;
++    }
++    bn_check_top(t);
++    return t;
++}
++
++BIGNUM *BN_copy(BIGNUM *a, const BIGNUM *b)
++{
++    int i;
++    BN_ULONG *A;
++    const BN_ULONG *B;
++
++    bn_check_top(b);
++
++    if (a == b)
++        return (a);
++    if (bn_wexpand(a, b->top) == NULL)
++        return (NULL);
++
++#if 1
++    A = a->d;
++    B = b->d;
++    for (i = b->top >> 2; i > 0; i--, A += 4, B += 4) {
++        BN_ULONG a0, a1, a2, a3;
++        a0 = B[0];
++        a1 = B[1];
++        a2 = B[2];
++        a3 = B[3];
++        A[0] = a0;
++        A[1] = a1;
++        A[2] = a2;
++        A[3] = a3;
++    }
++    /* ultrix cc workaround, see comments in bn_expand_internal */
++    switch (b->top & 3) {
++    case 3:
++        A[2] = B[2];
++    case 2:
++        A[1] = B[1];
++    case 1:
++        A[0] = B[0];
++    case 0:;
++    }
++#else
++    memcpy(a->d, b->d, sizeof(b->d[0]) * b->top);
++#endif
++
++    a->top = b->top;
++    a->neg = b->neg;
++    bn_check_top(a);
++    return (a);
++}
++
++void BN_swap(BIGNUM *a, BIGNUM *b)
++{
++    int flags_old_a, flags_old_b;
++    BN_ULONG *tmp_d;
++    int tmp_top, tmp_dmax, tmp_neg;
++
++    bn_check_top(a);
++    bn_check_top(b);
++
++    flags_old_a = a->flags;
++    flags_old_b = b->flags;
++
++    tmp_d = a->d;
++    tmp_top = a->top;
++    tmp_dmax = a->dmax;
++    tmp_neg = a->neg;
++
++    a->d = b->d;
++    a->top = b->top;
++    a->dmax = b->dmax;
++    a->neg = b->neg;
++
++    b->d = tmp_d;
++    b->top = tmp_top;
++    b->dmax = tmp_dmax;
++    b->neg = tmp_neg;
++
++    a->flags =
++        (flags_old_a & BN_FLG_MALLOCED) | (flags_old_b & BN_FLG_STATIC_DATA);
++    b->flags =
++        (flags_old_b & BN_FLG_MALLOCED) | (flags_old_a & BN_FLG_STATIC_DATA);
++    bn_check_top(a);
++    bn_check_top(b);
++}
++
++void BN_clear(BIGNUM *a)
++{
++    bn_check_top(a);
++    if (a->d != NULL)
++        OPENSSL_cleanse(a->d, sizeof(*a->d) * a->dmax);
++    a->top = 0;
++    a->neg = 0;
++}
++
++BN_ULONG BN_get_word(const BIGNUM *a)
++{
++    if (a->top > 1)
++        return BN_MASK2;
++    else if (a->top == 1)
++        return a->d[0];
++    /* a->top == 0 */
++    return 0;
++}
++
++int BN_set_word(BIGNUM *a, BN_ULONG w)
++{
++    bn_check_top(a);
++    if (bn_expand(a, (int)sizeof(BN_ULONG) * 8) == NULL)
++        return (0);
++    a->neg = 0;
++    a->d[0] = w;
++    a->top = (w ? 1 : 0);
++    bn_check_top(a);
++    return (1);
++}
++
++BIGNUM *BN_bin2bn(const unsigned char *s, int len, BIGNUM *ret)
++{
++    unsigned int i, m;
++    unsigned int n;
++    BN_ULONG l;
++    BIGNUM *bn = NULL;
++
++    if (ret == NULL)
++        ret = bn = BN_new();
++    if (ret == NULL)
++        return (NULL);
++    bn_check_top(ret);
++    /* Skip leading zero's. */
++    for ( ; len > 0 && *s == 0; s++, len--)
++        continue;
++    n = len;
++    if (n == 0) {
++        ret->top = 0;
++        return (ret);
++    }
++    i = ((n - 1) / BN_BYTES) + 1;
++    m = ((n - 1) % (BN_BYTES));
++    if (bn_wexpand(ret, (int)i) == NULL) {
++        BN_free(bn);
++        return NULL;
++    }
++    ret->top = i;
++    ret->neg = 0;
++    l = 0;
++    while (n--) {
++        l = (l << 8L) | *(s++);
++        if (m-- == 0) {
++            ret->d[--i] = l;
++            l = 0;
++            m = BN_BYTES - 1;
++        }
++    }
++    /*
++     * need to call this due to clear byte at top if avoiding having the top
++     * bit set (-ve number)
++     */
++    bn_correct_top(ret);
++    return (ret);
++}
++
++/* ignore negative */
++static int bn2binpad(const BIGNUM *a, unsigned char *to, int tolen)
++{
++    int i;
++    BN_ULONG l;
++
++    bn_check_top(a);
++    i = BN_num_bytes(a);
++    if (tolen == -1)
++        tolen = i;
++    else if (tolen < i)
++        return -1;
++    /* Add leading zeroes if necessary */
++    if (tolen > i) {
++        memset(to, 0, tolen - i);
++        to += tolen - i;
++    }
++    while (i--) {
++        l = a->d[i / BN_BYTES];
++        *(to++) = (unsigned char)(l >> (8 * (i % BN_BYTES))) & 0xff;
++    }
++    return tolen;
++}
++
++int BN_bn2binpad(const BIGNUM *a, unsigned char *to, int tolen)
++{
++    if (tolen < 0)
++        return -1;
++    return bn2binpad(a, to, tolen);
++}
++
++int BN_bn2bin(const BIGNUM *a, unsigned char *to)
++{
++    return bn2binpad(a, to, -1);
++}
++
++BIGNUM *BN_lebin2bn(const unsigned char *s, int len, BIGNUM *ret)
++{
++    unsigned int i, m;
++    unsigned int n;
++    BN_ULONG l;
++    BIGNUM *bn = NULL;
++
++    if (ret == NULL)
++        ret = bn = BN_new();
++    if (ret == NULL)
++        return (NULL);
++    bn_check_top(ret);
++    s += len;
++    /* Skip trailing zeroes. */
++    for ( ; len > 0 && s[-1] == 0; s--, len--)
++        continue;
++    n = len;
++    if (n == 0) {
++        ret->top = 0;
++        return ret;
++    }
++    i = ((n - 1) / BN_BYTES) + 1;
++    m = ((n - 1) % (BN_BYTES));
++    if (bn_wexpand(ret, (int)i) == NULL) {
++        BN_free(bn);
++        return NULL;
++    }
++    ret->top = i;
++    ret->neg = 0;
++    l = 0;
++    while (n--) {
++        s--;
++        l = (l << 8L) | *s;
++        if (m-- == 0) {
++            ret->d[--i] = l;
++            l = 0;
++            m = BN_BYTES - 1;
++        }
++    }
++    /*
++     * need to call this due to clear byte at top if avoiding having the top
++     * bit set (-ve number)
++     */
++    bn_correct_top(ret);
++    return ret;
++}
++
++int BN_bn2lebinpad(const BIGNUM *a, unsigned char *to, int tolen)
++{
++    int i;
++    BN_ULONG l;
++    bn_check_top(a);
++    i = BN_num_bytes(a);
++    if (tolen < i)
++        return -1;
++    /* Add trailing zeroes if necessary */
++    if (tolen > i)
++        memset(to + i, 0, tolen - i);
++    to += i;
++    while (i--) {
++        l = a->d[i / BN_BYTES];
++        to--;
++        *to = (unsigned char)(l >> (8 * (i % BN_BYTES))) & 0xff;
++    }
++    return tolen;
++}
++
++int BN_ucmp(const BIGNUM *a, const BIGNUM *b)
++{
++    int i;
++    BN_ULONG t1, t2, *ap, *bp;
++
++    bn_check_top(a);
++    bn_check_top(b);
++
++    i = a->top - b->top;
++    if (i != 0)
++        return (i);
++    ap = a->d;
++    bp = b->d;
++    for (i = a->top - 1; i >= 0; i--) {
++        t1 = ap[i];
++        t2 = bp[i];
++        if (t1 != t2)
++            return ((t1 > t2) ? 1 : -1);
++    }
++    return (0);
++}
++
++int BN_cmp(const BIGNUM *a, const BIGNUM *b)
++{
++    int i;
++    int gt, lt;
++    BN_ULONG t1, t2;
++
++    if ((a == NULL) || (b == NULL)) {
++        if (a != NULL)
++            return (-1);
++        else if (b != NULL)
++            return (1);
++        else
++            return (0);
++    }
++
++    bn_check_top(a);
++    bn_check_top(b);
++
++    if (a->neg != b->neg) {
++        if (a->neg)
++            return (-1);
++        else
++            return (1);
++    }
++    if (a->neg == 0) {
++        gt = 1;
++        lt = -1;
++    } else {
++        gt = -1;
++        lt = 1;
++    }
++
++    if (a->top > b->top)
++        return (gt);
++    if (a->top < b->top)
++        return (lt);
++    for (i = a->top - 1; i >= 0; i--) {
++        t1 = a->d[i];
++        t2 = b->d[i];
++        if (t1 > t2)
++            return (gt);
++        if (t1 < t2)
++            return (lt);
++    }
++    return (0);
++}
++
++int BN_set_bit(BIGNUM *a, int n)
++{
++    int i, j, k;
++
++    if (n < 0)
++        return 0;
++
++    i = n / BN_BITS2;
++    j = n % BN_BITS2;
++    if (a->top <= i) {
++        if (bn_wexpand(a, i + 1) == NULL)
++            return (0);
++        for (k = a->top; k < i + 1; k++)
++            a->d[k] = 0;
++        a->top = i + 1;
++    }
++
++    a->d[i] |= (((BN_ULONG)1) << j);
++    bn_check_top(a);
++    return (1);
++}
++
++int BN_clear_bit(BIGNUM *a, int n)
++{
++    int i, j;
++
++    bn_check_top(a);
++    if (n < 0)
++        return 0;
++
++    i = n / BN_BITS2;
++    j = n % BN_BITS2;
++    if (a->top <= i)
++        return (0);
++
++    a->d[i] &= (~(((BN_ULONG)1) << j));
++    bn_correct_top(a);
++    return (1);
++}
++
++int BN_is_bit_set(const BIGNUM *a, int n)
++{
++    int i, j;
++
++    bn_check_top(a);
++    if (n < 0)
++        return 0;
++    i = n / BN_BITS2;
++    j = n % BN_BITS2;
++    if (a->top <= i)
++        return 0;
++    return (int)(((a->d[i]) >> j) & ((BN_ULONG)1));
++}
++
++int BN_mask_bits(BIGNUM *a, int n)
++{
++    int b, w;
++
++    bn_check_top(a);
++    if (n < 0)
++        return 0;
++
++    w = n / BN_BITS2;
++    b = n % BN_BITS2;
++    if (w >= a->top)
++        return 0;
++    if (b == 0)
++        a->top = w;
++    else {
++        a->top = w + 1;
++        a->d[w] &= ~(BN_MASK2 << b);
++    }
++    bn_correct_top(a);
++    return (1);
++}
++
++void BN_set_negative(BIGNUM *a, int b)
++{
++    if (b && !BN_is_zero(a))
++        a->neg = 1;
++    else
++        a->neg = 0;
++}
++
++int bn_cmp_words(const BN_ULONG *a, const BN_ULONG *b, int n)
++{
++    int i;
++    BN_ULONG aa, bb;
++
++    aa = a[n - 1];
++    bb = b[n - 1];
++    if (aa != bb)
++        return ((aa > bb) ? 1 : -1);
++    for (i = n - 2; i >= 0; i--) {
++        aa = a[i];
++        bb = b[i];
++        if (aa != bb)
++            return ((aa > bb) ? 1 : -1);
++    }
++    return (0);
++}
++
++/*
++ * Here follows a specialised variants of bn_cmp_words().  It has the
++ * capability of performing the operation on arrays of different sizes. The
++ * sizes of those arrays is expressed through cl, which is the common length
++ * ( basically, min(len(a),len(b)) ), and dl, which is the delta between the
++ * two lengths, calculated as len(a)-len(b). All lengths are the number of
++ * BN_ULONGs...
++ */
++
++int bn_cmp_part_words(const BN_ULONG *a, const BN_ULONG *b, int cl, int dl)
++{
++    int n, i;
++    n = cl - 1;
++
++    if (dl < 0) {
++        for (i = dl; i < 0; i++) {
++            if (b[n - i] != 0)
++                return -1;      /* a < b */
++        }
++    }
++    if (dl > 0) {
++        for (i = dl; i > 0; i--) {
++            if (a[n + i] != 0)
++                return 1;       /* a > b */
++        }
++    }
++    return bn_cmp_words(a, b, cl);
++}
++
++/*
++ * Constant-time conditional swap of a and b.
++ * a and b are swapped if condition is not 0.  The code assumes that at most one bit of condition is set.
++ * nwords is the number of words to swap.  The code assumes that at least nwords are allocated in both a and b,
++ * and that no more than nwords are used by either a or b.
++ * a and b cannot be the same number
++ */
++void BN_consttime_swap(BN_ULONG condition, BIGNUM *a, BIGNUM *b, int nwords)
++{
++    BN_ULONG t;
++    int i;
++
++    bn_wcheck_size(a, nwords);
++    bn_wcheck_size(b, nwords);
++
++    assert(a != b);
++    assert((condition & (condition - 1)) == 0);
++    assert(sizeof(BN_ULONG) >= sizeof(int));
++
++    condition = ((condition - 1) >> (BN_BITS2 - 1)) - 1;
++
++    t = (a->top ^ b->top) & condition;
++    a->top ^= t;
++    b->top ^= t;
++
++#define BN_CONSTTIME_SWAP(ind) \
++        do { \
++                t = (a->d[ind] ^ b->d[ind]) & condition; \
++                a->d[ind] ^= t; \
++                b->d[ind] ^= t; \
++        } while (0)
++
++    switch (nwords) {
++    default:
++        for (i = 10; i < nwords; i++)
++            BN_CONSTTIME_SWAP(i);
++        /* Fallthrough */
++    case 10:
++        BN_CONSTTIME_SWAP(9);   /* Fallthrough */
++    case 9:
++        BN_CONSTTIME_SWAP(8);   /* Fallthrough */
++    case 8:
++        BN_CONSTTIME_SWAP(7);   /* Fallthrough */
++    case 7:
++        BN_CONSTTIME_SWAP(6);   /* Fallthrough */
++    case 6:
++        BN_CONSTTIME_SWAP(5);   /* Fallthrough */
++    case 5:
++        BN_CONSTTIME_SWAP(4);   /* Fallthrough */
++    case 4:
++        BN_CONSTTIME_SWAP(3);   /* Fallthrough */
++    case 3:
++        BN_CONSTTIME_SWAP(2);   /* Fallthrough */
++    case 2:
++        BN_CONSTTIME_SWAP(1);   /* Fallthrough */
++    case 1:
++        BN_CONSTTIME_SWAP(0);
++    }
++#undef BN_CONSTTIME_SWAP
++}
++
++/* Bits of security, see SP800-57 */
++
++int BN_security_bits(int L, int N)
++{
++    int secbits, bits;
++    if (L >= 15360)
++        secbits = 256;
++    else if (L >= 7690)
++        secbits = 192;
++    else if (L >= 3072)
++        secbits = 128;
++    else if (L >= 2048)
++        secbits = 112;
++    else if (L >= 1024)
++        secbits = 80;
++    else
++        return 0;
++    if (N == -1)
++        return secbits;
++    bits = N / 2;
++    if (bits < 80)
++        return 0;
++    return bits >= secbits ? secbits : bits;
++}
++
++void BN_zero_ex(BIGNUM *a)
++{
++    a->top = 0;
++    a->neg = 0;
++}
++
++int BN_abs_is_word(const BIGNUM *a, const BN_ULONG w)
++{
++    return ((a->top == 1) && (a->d[0] == w)) || ((w == 0) && (a->top == 0));
++}
++
++int BN_is_zero(const BIGNUM *a)
++{
++    return a->top == 0;
++}
++
++int BN_is_one(const BIGNUM *a)
++{
++    return BN_abs_is_word(a, 1) && !a->neg;
++}
++
++int BN_is_word(const BIGNUM *a, const BN_ULONG w)
++{
++    return BN_abs_is_word(a, w) && (!w || !a->neg);
++}
++
++int BN_is_odd(const BIGNUM *a)
++{
++    return (a->top > 0) && (a->d[0] & 1);
++}
++
++int BN_is_negative(const BIGNUM *a)
++{
++    return (a->neg != 0);
++}
++
++int BN_to_montgomery(BIGNUM *r, const BIGNUM *a, BN_MONT_CTX *mont,
++                     BN_CTX *ctx)
++{
++    return BN_mod_mul_montgomery(r, a, &(mont->RR), mont, ctx);
++}
++
++void BN_with_flags(BIGNUM *dest, const BIGNUM *b, int flags)
++{
++    dest->d = b->d;
++    dest->top = b->top;
++    dest->dmax = b->dmax;
++    dest->neg = b->neg;
++    dest->flags = ((dest->flags & BN_FLG_MALLOCED)
++                   | (b->flags & ~BN_FLG_MALLOCED)
++                   | BN_FLG_STATIC_DATA | flags);
++}
++
++BN_GENCB *BN_GENCB_new(void)
++{
++    BN_GENCB *ret;
++
++    if ((ret = OPENSSL_malloc(sizeof(*ret))) == NULL) {
++        BNerr(BN_F_BN_GENCB_NEW, ERR_R_MALLOC_FAILURE);
++        return (NULL);
++    }
++
++    return ret;
++}
++
++void BN_GENCB_free(BN_GENCB *cb)
++{
++    if (cb == NULL)
++        return;
++    OPENSSL_free(cb);
++}
++
++void BN_set_flags(BIGNUM *b, int n)
++{
++    b->flags |= n;
++}
++
++int BN_get_flags(const BIGNUM *b, int n)
++{
++    return b->flags & n;
++}
++
++/* Populate a BN_GENCB structure with an "old"-style callback */
++void BN_GENCB_set_old(BN_GENCB *gencb, void (*callback) (int, int, void *),
++                      void *cb_arg)
++{
++    BN_GENCB *tmp_gencb = gencb;
++    tmp_gencb->ver = 1;
++    tmp_gencb->arg = cb_arg;
++    tmp_gencb->cb.cb_1 = callback;
++}
++
++/* Populate a BN_GENCB structure with a "new"-style callback */
++void BN_GENCB_set(BN_GENCB *gencb, int (*callback) (int, int, BN_GENCB *),
++                  void *cb_arg)
++{
++    BN_GENCB *tmp_gencb = gencb;
++    tmp_gencb->ver = 2;
++    tmp_gencb->arg = cb_arg;
++    tmp_gencb->cb.cb_2 = callback;
++}
++
++void *BN_GENCB_get_arg(BN_GENCB *cb)
++{
++    return cb->arg;
++}
++
++BIGNUM *bn_wexpand(BIGNUM *a, int words)
++{
++    return (words <= a->dmax) ? a : bn_expand2(a, words);
++}
++
++void bn_correct_top(BIGNUM *a)
++{
++    BN_ULONG *ftl;
++    int tmp_top = a->top;
++
++    if (tmp_top > 0) {
++        for (ftl = &(a->d[tmp_top]); tmp_top > 0; tmp_top--) {
++            ftl--;
++            if (*ftl != 0)
++                break;
++        }
++        a->top = tmp_top;
++    }
++    if (a->top == 0)
++        a->neg = 0;
++    bn_pollute(a);
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/bn/bn_mod.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/bn/bn_mod.c
+new file mode 100644
+index 0000000..13b583f
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/bn/bn_mod.c
+@@ -0,0 +1,201 @@
++/*
++ * Copyright 1998-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include "internal/cryptlib.h"
++#include "bn_lcl.h"
++
++int BN_nnmod(BIGNUM *r, const BIGNUM *m, const BIGNUM *d, BN_CTX *ctx)
++{
++    /*
++     * like BN_mod, but returns non-negative remainder (i.e., 0 <= r < |d|
++     * always holds)
++     */
++
++    if (!(BN_mod(r, m, d, ctx)))
++        return 0;
++    if (!r->neg)
++        return 1;
++    /* now   -|d| < r < 0,  so we have to set  r := r + |d| */
++    return (d->neg ? BN_sub : BN_add) (r, r, d);
++}
++
++int BN_mod_add(BIGNUM *r, const BIGNUM *a, const BIGNUM *b, const BIGNUM *m,
++               BN_CTX *ctx)
++{
++    if (!BN_add(r, a, b))
++        return 0;
++    return BN_nnmod(r, r, m, ctx);
++}
++
++/*
++ * BN_mod_add variant that may be used if both a and b are non-negative and
++ * less than m
++ */
++int BN_mod_add_quick(BIGNUM *r, const BIGNUM *a, const BIGNUM *b,
++                     const BIGNUM *m)
++{
++    if (!BN_uadd(r, a, b))
++        return 0;
++    if (BN_ucmp(r, m) >= 0)
++        return BN_usub(r, r, m);
++    return 1;
++}
++
++int BN_mod_sub(BIGNUM *r, const BIGNUM *a, const BIGNUM *b, const BIGNUM *m,
++               BN_CTX *ctx)
++{
++    if (!BN_sub(r, a, b))
++        return 0;
++    return BN_nnmod(r, r, m, ctx);
++}
++
++/*
++ * BN_mod_sub variant that may be used if both a and b are non-negative and
++ * less than m
++ */
++int BN_mod_sub_quick(BIGNUM *r, const BIGNUM *a, const BIGNUM *b,
++                     const BIGNUM *m)
++{
++    if (!BN_sub(r, a, b))
++        return 0;
++    if (r->neg)
++        return BN_add(r, r, m);
++    return 1;
++}
++
++/* slow but works */
++int BN_mod_mul(BIGNUM *r, const BIGNUM *a, const BIGNUM *b, const BIGNUM *m,
++               BN_CTX *ctx)
++{
++    BIGNUM *t;
++    int ret = 0;
++
++    bn_check_top(a);
++    bn_check_top(b);
++    bn_check_top(m);
++
++    BN_CTX_start(ctx);
++    if ((t = BN_CTX_get(ctx)) == NULL)
++        goto err;
++    if (a == b) {
++        if (!BN_sqr(t, a, ctx))
++            goto err;
++    } else {
++        if (!BN_mul(t, a, b, ctx))
++            goto err;
++    }
++    if (!BN_nnmod(r, t, m, ctx))
++        goto err;
++    bn_check_top(r);
++    ret = 1;
++ err:
++    BN_CTX_end(ctx);
++    return (ret);
++}
++
++int BN_mod_sqr(BIGNUM *r, const BIGNUM *a, const BIGNUM *m, BN_CTX *ctx)
++{
++    if (!BN_sqr(r, a, ctx))
++        return 0;
++    /* r->neg == 0,  thus we don't need BN_nnmod */
++    return BN_mod(r, r, m, ctx);
++}
++
++int BN_mod_lshift1(BIGNUM *r, const BIGNUM *a, const BIGNUM *m, BN_CTX *ctx)
++{
++    if (!BN_lshift1(r, a))
++        return 0;
++    bn_check_top(r);
++    return BN_nnmod(r, r, m, ctx);
++}
++
++/*
++ * BN_mod_lshift1 variant that may be used if a is non-negative and less than
++ * m
++ */
++int BN_mod_lshift1_quick(BIGNUM *r, const BIGNUM *a, const BIGNUM *m)
++{
++    if (!BN_lshift1(r, a))
++        return 0;
++    bn_check_top(r);
++    if (BN_cmp(r, m) >= 0)
++        return BN_sub(r, r, m);
++    return 1;
++}
++
++int BN_mod_lshift(BIGNUM *r, const BIGNUM *a, int n, const BIGNUM *m,
++                  BN_CTX *ctx)
++{
++    BIGNUM *abs_m = NULL;
++    int ret;
++
++    if (!BN_nnmod(r, a, m, ctx))
++        return 0;
++
++    if (m->neg) {
++        abs_m = BN_dup(m);
++        if (abs_m == NULL)
++            return 0;
++        abs_m->neg = 0;
++    }
++
++    ret = BN_mod_lshift_quick(r, r, n, (abs_m ? abs_m : m));
++    bn_check_top(r);
++
++    BN_free(abs_m);
++    return ret;
++}
++
++/*
++ * BN_mod_lshift variant that may be used if a is non-negative and less than
++ * m
++ */
++int BN_mod_lshift_quick(BIGNUM *r, const BIGNUM *a, int n, const BIGNUM *m)
++{
++    if (r != a) {
++        if (BN_copy(r, a) == NULL)
++            return 0;
++    }
++
++    while (n > 0) {
++        int max_shift;
++
++        /* 0 < r < m */
++        max_shift = BN_num_bits(m) - BN_num_bits(r);
++        /* max_shift >= 0 */
++
++        if (max_shift < 0) {
++            BNerr(BN_F_BN_MOD_LSHIFT_QUICK, BN_R_INPUT_NOT_REDUCED);
++            return 0;
++        }
++
++        if (max_shift > n)
++            max_shift = n;
++
++        if (max_shift) {
++            if (!BN_lshift(r, r, max_shift))
++                return 0;
++            n -= max_shift;
++        } else {
++            if (!BN_lshift1(r, r))
++                return 0;
++            --n;
++        }
++
++        /* BN_num_bits(r) <= BN_num_bits(m) */
++
++        if (BN_cmp(r, m) >= 0) {
++            if (!BN_sub(r, r, m))
++                return 0;
++        }
++    }
++    bn_check_top(r);
++
++    return 1;
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/bn/bn_mont.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/bn/bn_mont.c
+new file mode 100644
+index 0000000..6d37279
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/bn/bn_mont.c
+@@ -0,0 +1,434 @@
++/*
++ * Copyright 1995-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++/*
++ * Details about Montgomery multiplication algorithms can be found at
++ * http://security.ece.orst.edu/publications.html, e.g.
++ * http://security.ece.orst.edu/koc/papers/j37acmon.pdf and
++ * sections 3.8 and 4.2 in http://security.ece.orst.edu/koc/papers/r01rsasw.pdf
++ */
++
++#include "internal/cryptlib.h"
++#include "bn_lcl.h"
++
++#define MONT_WORD               /* use the faster word-based algorithm */
++
++#ifdef MONT_WORD
++static int BN_from_montgomery_word(BIGNUM *ret, BIGNUM *r, BN_MONT_CTX *mont);
++#endif
++
++int BN_mod_mul_montgomery(BIGNUM *r, const BIGNUM *a, const BIGNUM *b,
++                          BN_MONT_CTX *mont, BN_CTX *ctx)
++{
++    BIGNUM *tmp;
++    int ret = 0;
++#if defined(OPENSSL_BN_ASM_MONT) && defined(MONT_WORD)
++    int num = mont->N.top;
++
++    if (num > 1 && a->top == num && b->top == num) {
++        if (bn_wexpand(r, num) == NULL)
++            return (0);
++        if (bn_mul_mont(r->d, a->d, b->d, mont->N.d, mont->n0, num)) {
++            r->neg = a->neg ^ b->neg;
++            r->top = num;
++            bn_correct_top(r);
++            return (1);
++        }
++    }
++#endif
++
++    BN_CTX_start(ctx);
++    tmp = BN_CTX_get(ctx);
++    if (tmp == NULL)
++        goto err;
++
++    bn_check_top(tmp);
++    if (a == b) {
++        if (!BN_sqr(tmp, a, ctx))
++            goto err;
++    } else {
++        if (!BN_mul(tmp, a, b, ctx))
++            goto err;
++    }
++    /* reduce from aRR to aR */
++#ifdef MONT_WORD
++    if (!BN_from_montgomery_word(r, tmp, mont))
++        goto err;
++#else
++    if (!BN_from_montgomery(r, tmp, mont, ctx))
++        goto err;
++#endif
++    bn_check_top(r);
++    ret = 1;
++ err:
++    BN_CTX_end(ctx);
++    return (ret);
++}
++
++#ifdef MONT_WORD
++static int BN_from_montgomery_word(BIGNUM *ret, BIGNUM *r, BN_MONT_CTX *mont)
++{
++    BIGNUM *n;
++    BN_ULONG *ap, *np, *rp, n0, v, carry;
++    int nl, max, i;
++
++    n = &(mont->N);
++    nl = n->top;
++    if (nl == 0) {
++        ret->top = 0;
++        return (1);
++    }
++
++    max = (2 * nl);             /* carry is stored separately */
++    if (bn_wexpand(r, max) == NULL)
++        return (0);
++
++    r->neg ^= n->neg;
++    np = n->d;
++    rp = r->d;
++
++    /* clear the top words of T */
++    i = max - r->top;
++    if (i)
++        memset(&rp[r->top], 0, sizeof(*rp) * i);
++
++    r->top = max;
++    n0 = mont->n0[0];
++
++    for (carry = 0, i = 0; i < nl; i++, rp++) {
++        v = bn_mul_add_words(rp, np, nl, (rp[0] * n0) & BN_MASK2);
++        v = (v + carry + rp[nl]) & BN_MASK2;
++        carry |= (v != rp[nl]);
++        carry &= (v <= rp[nl]);
++        rp[nl] = v;
++    }
++
++    if (bn_wexpand(ret, nl) == NULL)
++        return (0);
++    ret->top = nl;
++    ret->neg = r->neg;
++
++    rp = ret->d;
++    ap = &(r->d[nl]);
++
++# define BRANCH_FREE 1
++# if BRANCH_FREE
++    {
++        BN_ULONG *nrp;
++        size_t m;
++
++        v = bn_sub_words(rp, ap, np, nl) - carry;
++        /*
++         * if subtraction result is real, then trick unconditional memcpy
++         * below to perform in-place "refresh" instead of actual copy.
++         */
++        m = (0 - (size_t)v);
++        nrp =
++            (BN_ULONG *)(((PTR_SIZE_INT) rp & ~m) | ((PTR_SIZE_INT) ap & m));
++
++        for (i = 0, nl -= 4; i < nl; i += 4) {
++            BN_ULONG t1, t2, t3, t4;
++
++            t1 = nrp[i + 0];
++            t2 = nrp[i + 1];
++            t3 = nrp[i + 2];
++            ap[i + 0] = 0;
++            t4 = nrp[i + 3];
++            ap[i + 1] = 0;
++            rp[i + 0] = t1;
++            ap[i + 2] = 0;
++            rp[i + 1] = t2;
++            ap[i + 3] = 0;
++            rp[i + 2] = t3;
++            rp[i + 3] = t4;
++        }
++        for (nl += 4; i < nl; i++)
++            rp[i] = nrp[i], ap[i] = 0;
++    }
++# else
++    if (bn_sub_words(rp, ap, np, nl) - carry)
++        memcpy(rp, ap, nl * sizeof(BN_ULONG));
++# endif
++    bn_correct_top(r);
++    bn_correct_top(ret);
++    bn_check_top(ret);
++
++    return (1);
++}
++#endif                          /* MONT_WORD */
++
++int BN_from_montgomery(BIGNUM *ret, const BIGNUM *a, BN_MONT_CTX *mont,
++                       BN_CTX *ctx)
++{
++    int retn = 0;
++#ifdef MONT_WORD
++    BIGNUM *t;
++
++    BN_CTX_start(ctx);
++    if ((t = BN_CTX_get(ctx)) && BN_copy(t, a))
++        retn = BN_from_montgomery_word(ret, t, mont);
++    BN_CTX_end(ctx);
++#else                           /* !MONT_WORD */
++    BIGNUM *t1, *t2;
++
++    BN_CTX_start(ctx);
++    t1 = BN_CTX_get(ctx);
++    t2 = BN_CTX_get(ctx);
++    if (t1 == NULL || t2 == NULL)
++        goto err;
++
++    if (!BN_copy(t1, a))
++        goto err;
++    BN_mask_bits(t1, mont->ri);
++
++    if (!BN_mul(t2, t1, &mont->Ni, ctx))
++        goto err;
++    BN_mask_bits(t2, mont->ri);
++
++    if (!BN_mul(t1, t2, &mont->N, ctx))
++        goto err;
++    if (!BN_add(t2, a, t1))
++        goto err;
++    if (!BN_rshift(ret, t2, mont->ri))
++        goto err;
++
++    if (BN_ucmp(ret, &(mont->N)) >= 0) {
++        if (!BN_usub(ret, ret, &(mont->N)))
++            goto err;
++    }
++    retn = 1;
++    bn_check_top(ret);
++ err:
++    BN_CTX_end(ctx);
++#endif                          /* MONT_WORD */
++    return (retn);
++}
++
++BN_MONT_CTX *BN_MONT_CTX_new(void)
++{
++    BN_MONT_CTX *ret;
++
++    if ((ret = OPENSSL_malloc(sizeof(*ret))) == NULL)
++        return (NULL);
++
++    BN_MONT_CTX_init(ret);
++    ret->flags = BN_FLG_MALLOCED;
++    return (ret);
++}
++
++void BN_MONT_CTX_init(BN_MONT_CTX *ctx)
++{
++    ctx->ri = 0;
++    bn_init(&(ctx->RR));
++    bn_init(&(ctx->N));
++    bn_init(&(ctx->Ni));
++    ctx->n0[0] = ctx->n0[1] = 0;
++    ctx->flags = 0;
++}
++
++void BN_MONT_CTX_free(BN_MONT_CTX *mont)
++{
++    if (mont == NULL)
++        return;
++
++    BN_clear_free(&(mont->RR));
++    BN_clear_free(&(mont->N));
++    BN_clear_free(&(mont->Ni));
++    if (mont->flags & BN_FLG_MALLOCED)
++        OPENSSL_free(mont);
++}
++
++int BN_MONT_CTX_set(BN_MONT_CTX *mont, const BIGNUM *mod, BN_CTX *ctx)
++{
++    int ret = 0;
++    BIGNUM *Ri, *R;
++
++    if (BN_is_zero(mod))
++        return 0;
++
++    BN_CTX_start(ctx);
++    if ((Ri = BN_CTX_get(ctx)) == NULL)
++        goto err;
++    R = &(mont->RR);            /* grab RR as a temp */
++    if (!BN_copy(&(mont->N), mod))
++        goto err;               /* Set N */
++    mont->N.neg = 0;
++
++#ifdef MONT_WORD
++    {
++        BIGNUM tmod;
++        BN_ULONG buf[2];
++
++        bn_init(&tmod);
++        tmod.d = buf;
++        tmod.dmax = 2;
++        tmod.neg = 0;
++
++        mont->ri = (BN_num_bits(mod) + (BN_BITS2 - 1)) / BN_BITS2 * BN_BITS2;
++
++# if defined(OPENSSL_BN_ASM_MONT) && (BN_BITS2<=32)
++        /*
++         * Only certain BN_BITS2<=32 platforms actually make use of n0[1],
++         * and we could use the #else case (with a shorter R value) for the
++         * others.  However, currently only the assembler files do know which
++         * is which.
++         */
++
++        BN_zero(R);
++        if (!(BN_set_bit(R, 2 * BN_BITS2)))
++            goto err;
++
++        tmod.top = 0;
++        if ((buf[0] = mod->d[0]))
++            tmod.top = 1;
++        if ((buf[1] = mod->top > 1 ? mod->d[1] : 0))
++            tmod.top = 2;
++
++        if ((BN_mod_inverse(Ri, R, &tmod, ctx)) == NULL)
++            goto err;
++        if (!BN_lshift(Ri, Ri, 2 * BN_BITS2))
++            goto err;           /* R*Ri */
++        if (!BN_is_zero(Ri)) {
++            if (!BN_sub_word(Ri, 1))
++                goto err;
++        } else {                /* if N mod word size == 1 */
++
++            if (bn_expand(Ri, (int)sizeof(BN_ULONG) * 2) == NULL)
++                goto err;
++            /* Ri-- (mod double word size) */
++            Ri->neg = 0;
++            Ri->d[0] = BN_MASK2;
++            Ri->d[1] = BN_MASK2;
++            Ri->top = 2;
++        }
++        if (!BN_div(Ri, NULL, Ri, &tmod, ctx))
++            goto err;
++        /*
++         * Ni = (R*Ri-1)/N, keep only couple of least significant words:
++         */
++        mont->n0[0] = (Ri->top > 0) ? Ri->d[0] : 0;
++        mont->n0[1] = (Ri->top > 1) ? Ri->d[1] : 0;
++# else
++        BN_zero(R);
++        if (!(BN_set_bit(R, BN_BITS2)))
++            goto err;           /* R */
++
++        buf[0] = mod->d[0];     /* tmod = N mod word size */
++        buf[1] = 0;
++        tmod.top = buf[0] != 0 ? 1 : 0;
++        /* Ri = R^-1 mod N */
++        if ((BN_mod_inverse(Ri, R, &tmod, ctx)) == NULL)
++            goto err;
++        if (!BN_lshift(Ri, Ri, BN_BITS2))
++            goto err;           /* R*Ri */
++        if (!BN_is_zero(Ri)) {
++            if (!BN_sub_word(Ri, 1))
++                goto err;
++        } else {                /* if N mod word size == 1 */
++
++            if (!BN_set_word(Ri, BN_MASK2))
++                goto err;       /* Ri-- (mod word size) */
++        }
++        if (!BN_div(Ri, NULL, Ri, &tmod, ctx))
++            goto err;
++        /*
++         * Ni = (R*Ri-1)/N, keep only least significant word:
++         */
++        mont->n0[0] = (Ri->top > 0) ? Ri->d[0] : 0;
++        mont->n0[1] = 0;
++# endif
++    }
++#else                           /* !MONT_WORD */
++    {                           /* bignum version */
++        mont->ri = BN_num_bits(&mont->N);
++        BN_zero(R);
++        if (!BN_set_bit(R, mont->ri))
++            goto err;           /* R = 2^ri */
++        /* Ri = R^-1 mod N */
++        if ((BN_mod_inverse(Ri, R, &mont->N, ctx)) == NULL)
++            goto err;
++        if (!BN_lshift(Ri, Ri, mont->ri))
++            goto err;           /* R*Ri */
++        if (!BN_sub_word(Ri, 1))
++            goto err;
++        /*
++         * Ni = (R*Ri-1) / N
++         */
++        if (!BN_div(&(mont->Ni), NULL, Ri, &mont->N, ctx))
++            goto err;
++    }
++#endif
++
++    /* setup RR for conversions */
++    BN_zero(&(mont->RR));
++    if (!BN_set_bit(&(mont->RR), mont->ri * 2))
++        goto err;
++    if (!BN_mod(&(mont->RR), &(mont->RR), &(mont->N), ctx))
++        goto err;
++
++    ret = 1;
++ err:
++    BN_CTX_end(ctx);
++    return ret;
++}
++
++BN_MONT_CTX *BN_MONT_CTX_copy(BN_MONT_CTX *to, BN_MONT_CTX *from)
++{
++    if (to == from)
++        return (to);
++
++    if (!BN_copy(&(to->RR), &(from->RR)))
++        return NULL;
++    if (!BN_copy(&(to->N), &(from->N)))
++        return NULL;
++    if (!BN_copy(&(to->Ni), &(from->Ni)))
++        return NULL;
++    to->ri = from->ri;
++    to->n0[0] = from->n0[0];
++    to->n0[1] = from->n0[1];
++    return (to);
++}
++
++BN_MONT_CTX *BN_MONT_CTX_set_locked(BN_MONT_CTX **pmont, CRYPTO_RWLOCK *lock,
++                                    const BIGNUM *mod, BN_CTX *ctx)
++{
++    BN_MONT_CTX *ret;
++
++    CRYPTO_THREAD_read_lock(lock);
++    ret = *pmont;
++    CRYPTO_THREAD_unlock(lock);
++    if (ret)
++        return ret;
++
++    /*
++     * We don't want to serialise globally while doing our lazy-init math in
++     * BN_MONT_CTX_set. That punishes threads that are doing independent
++     * things. Instead, punish the case where more than one thread tries to
++     * lazy-init the same 'pmont', by having each do the lazy-init math work
++     * independently and only use the one from the thread that wins the race
++     * (the losers throw away the work they've done).
++     */
++    ret = BN_MONT_CTX_new();
++    if (ret == NULL)
++        return NULL;
++    if (!BN_MONT_CTX_set(ret, mod, ctx)) {
++        BN_MONT_CTX_free(ret);
++        return NULL;
++    }
++
++    /* The locked compare-and-set, after the local work is done. */
++    CRYPTO_THREAD_write_lock(lock);
++    if (*pmont) {
++        BN_MONT_CTX_free(ret);
++        ret = *pmont;
++    } else
++        *pmont = ret;
++    CRYPTO_THREAD_unlock(lock);
++    return ret;
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/bn/bn_mpi.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/bn/bn_mpi.c
+new file mode 100644
+index 0000000..043e21d
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/bn/bn_mpi.c
+@@ -0,0 +1,86 @@
++/*
++ * Copyright 1995-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include "internal/cryptlib.h"
++#include "bn_lcl.h"
++
++int BN_bn2mpi(const BIGNUM *a, unsigned char *d)
++{
++    int bits;
++    int num = 0;
++    int ext = 0;
++    long l;
++
++    bits = BN_num_bits(a);
++    num = (bits + 7) / 8;
++    if (bits > 0) {
++        ext = ((bits & 0x07) == 0);
++    }
++    if (d == NULL)
++        return (num + 4 + ext);
++
++    l = num + ext;
++    d[0] = (unsigned char)(l >> 24) & 0xff;
++    d[1] = (unsigned char)(l >> 16) & 0xff;
++    d[2] = (unsigned char)(l >> 8) & 0xff;
++    d[3] = (unsigned char)(l) & 0xff;
++    if (ext)
++        d[4] = 0;
++    num = BN_bn2bin(a, &(d[4 + ext]));
++    if (a->neg)
++        d[4] |= 0x80;
++    return (num + 4 + ext);
++}
++
++BIGNUM *BN_mpi2bn(const unsigned char *d, int n, BIGNUM *ain)
++{
++    long len;
++    int neg = 0;
++    BIGNUM *a = NULL;
++
++    if (n < 4) {
++        BNerr(BN_F_BN_MPI2BN, BN_R_INVALID_LENGTH);
++        return NULL;
++    }
++    len = ((long)d[0] << 24) | ((long)d[1] << 16) | ((int)d[2] << 8) | (int)
++        d[3];
++    if ((len + 4) != n) {
++        BNerr(BN_F_BN_MPI2BN, BN_R_ENCODING_ERROR);
++        return NULL;
++    }
++
++    if (ain == NULL)
++        a = BN_new();
++    else
++        a = ain;
++
++    if (a == NULL)
++        return NULL;
++
++    if (len == 0) {
++        a->neg = 0;
++        a->top = 0;
++        return a;
++    }
++    d += 4;
++    if ((*d) & 0x80)
++        neg = 1;
++    if (BN_bin2bn(d, (int)len, a) == NULL) {
++        if (ain == NULL)
++            BN_free(a);
++        return NULL;
++    }
++    a->neg = neg;
++    if (neg) {
++        BN_clear_bit(a, BN_num_bits(a) - 1);
++    }
++    bn_check_top(a);
++    return a;
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/bn/bn_mul.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/bn/bn_mul.c
+new file mode 100644
+index 0000000..4a0a950
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/bn/bn_mul.c
+@@ -0,0 +1,1045 @@
++/*
++ * Copyright 1995-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include "internal/cryptlib.h"
++#include "bn_lcl.h"
++
++#if defined(OPENSSL_NO_ASM) || !defined(OPENSSL_BN_ASM_PART_WORDS)
++/*
++ * Here follows specialised variants of bn_add_words() and bn_sub_words().
++ * They have the property performing operations on arrays of different sizes.
++ * The sizes of those arrays is expressed through cl, which is the common
++ * length ( basically, min(len(a),len(b)) ), and dl, which is the delta
++ * between the two lengths, calculated as len(a)-len(b). All lengths are the
++ * number of BN_ULONGs...  For the operations that require a result array as
++ * parameter, it must have the length cl+abs(dl). These functions should
++ * probably end up in bn_asm.c as soon as there are assembler counterparts
++ * for the systems that use assembler files.
++ */
++
++BN_ULONG bn_sub_part_words(BN_ULONG *r,
++                           const BN_ULONG *a, const BN_ULONG *b,
++                           int cl, int dl)
++{
++    BN_ULONG c, t;
++
++    assert(cl >= 0);
++    c = bn_sub_words(r, a, b, cl);
++
++    if (dl == 0)
++        return c;
++
++    r += cl;
++    a += cl;
++    b += cl;
++
++    if (dl < 0) {
++        for (;;) {
++            t = b[0];
++            r[0] = (0 - t - c) & BN_MASK2;
++            if (t != 0)
++                c = 1;
++            if (++dl >= 0)
++                break;
++
++            t = b[1];
++            r[1] = (0 - t - c) & BN_MASK2;
++            if (t != 0)
++                c = 1;
++            if (++dl >= 0)
++                break;
++
++            t = b[2];
++            r[2] = (0 - t - c) & BN_MASK2;
++            if (t != 0)
++                c = 1;
++            if (++dl >= 0)
++                break;
++
++            t = b[3];
++            r[3] = (0 - t - c) & BN_MASK2;
++            if (t != 0)
++                c = 1;
++            if (++dl >= 0)
++                break;
++
++            b += 4;
++            r += 4;
++        }
++    } else {
++        int save_dl = dl;
++        while (c) {
++            t = a[0];
++            r[0] = (t - c) & BN_MASK2;
++            if (t != 0)
++                c = 0;
++            if (--dl <= 0)
++                break;
++
++            t = a[1];
++            r[1] = (t - c) & BN_MASK2;
++            if (t != 0)
++                c = 0;
++            if (--dl <= 0)
++                break;
++
++            t = a[2];
++            r[2] = (t - c) & BN_MASK2;
++            if (t != 0)
++                c = 0;
++            if (--dl <= 0)
++                break;
++
++            t = a[3];
++            r[3] = (t - c) & BN_MASK2;
++            if (t != 0)
++                c = 0;
++            if (--dl <= 0)
++                break;
++
++            save_dl = dl;
++            a += 4;
++            r += 4;
++        }
++        if (dl > 0) {
++            if (save_dl > dl) {
++                switch (save_dl - dl) {
++                case 1:
++                    r[1] = a[1];
++                    if (--dl <= 0)
++                        break;
++                case 2:
++                    r[2] = a[2];
++                    if (--dl <= 0)
++                        break;
++                case 3:
++                    r[3] = a[3];
++                    if (--dl <= 0)
++                        break;
++                }
++                a += 4;
++                r += 4;
++            }
++        }
++        if (dl > 0) {
++            for (;;) {
++                r[0] = a[0];
++                if (--dl <= 0)
++                    break;
++                r[1] = a[1];
++                if (--dl <= 0)
++                    break;
++                r[2] = a[2];
++                if (--dl <= 0)
++                    break;
++                r[3] = a[3];
++                if (--dl <= 0)
++                    break;
++
++                a += 4;
++                r += 4;
++            }
++        }
++    }
++    return c;
++}
++#endif
++
++BN_ULONG bn_add_part_words(BN_ULONG *r,
++                           const BN_ULONG *a, const BN_ULONG *b,
++                           int cl, int dl)
++{
++    BN_ULONG c, l, t;
++
++    assert(cl >= 0);
++    c = bn_add_words(r, a, b, cl);
++
++    if (dl == 0)
++        return c;
++
++    r += cl;
++    a += cl;
++    b += cl;
++
++    if (dl < 0) {
++        int save_dl = dl;
++        while (c) {
++            l = (c + b[0]) & BN_MASK2;
++            c = (l < c);
++            r[0] = l;
++            if (++dl >= 0)
++                break;
++
++            l = (c + b[1]) & BN_MASK2;
++            c = (l < c);
++            r[1] = l;
++            if (++dl >= 0)
++                break;
++
++            l = (c + b[2]) & BN_MASK2;
++            c = (l < c);
++            r[2] = l;
++            if (++dl >= 0)
++                break;
++
++            l = (c + b[3]) & BN_MASK2;
++            c = (l < c);
++            r[3] = l;
++            if (++dl >= 0)
++                break;
++
++            save_dl = dl;
++            b += 4;
++            r += 4;
++        }
++        if (dl < 0) {
++            if (save_dl < dl) {
++                switch (dl - save_dl) {
++                case 1:
++                    r[1] = b[1];
++                    if (++dl >= 0)
++                        break;
++                case 2:
++                    r[2] = b[2];
++                    if (++dl >= 0)
++                        break;
++                case 3:
++                    r[3] = b[3];
++                    if (++dl >= 0)
++                        break;
++                }
++                b += 4;
++                r += 4;
++            }
++        }
++        if (dl < 0) {
++            for (;;) {
++                r[0] = b[0];
++                if (++dl >= 0)
++                    break;
++                r[1] = b[1];
++                if (++dl >= 0)
++                    break;
++                r[2] = b[2];
++                if (++dl >= 0)
++                    break;
++                r[3] = b[3];
++                if (++dl >= 0)
++                    break;
++
++                b += 4;
++                r += 4;
++            }
++        }
++    } else {
++        int save_dl = dl;
++        while (c) {
++            t = (a[0] + c) & BN_MASK2;
++            c = (t < c);
++            r[0] = t;
++            if (--dl <= 0)
++                break;
++
++            t = (a[1] + c) & BN_MASK2;
++            c = (t < c);
++            r[1] = t;
++            if (--dl <= 0)
++                break;
++
++            t = (a[2] + c) & BN_MASK2;
++            c = (t < c);
++            r[2] = t;
++            if (--dl <= 0)
++                break;
++
++            t = (a[3] + c) & BN_MASK2;
++            c = (t < c);
++            r[3] = t;
++            if (--dl <= 0)
++                break;
++
++            save_dl = dl;
++            a += 4;
++            r += 4;
++        }
++        if (dl > 0) {
++            if (save_dl > dl) {
++                switch (save_dl - dl) {
++                case 1:
++                    r[1] = a[1];
++                    if (--dl <= 0)
++                        break;
++                case 2:
++                    r[2] = a[2];
++                    if (--dl <= 0)
++                        break;
++                case 3:
++                    r[3] = a[3];
++                    if (--dl <= 0)
++                        break;
++                }
++                a += 4;
++                r += 4;
++            }
++        }
++        if (dl > 0) {
++            for (;;) {
++                r[0] = a[0];
++                if (--dl <= 0)
++                    break;
++                r[1] = a[1];
++                if (--dl <= 0)
++                    break;
++                r[2] = a[2];
++                if (--dl <= 0)
++                    break;
++                r[3] = a[3];
++                if (--dl <= 0)
++                    break;
++
++                a += 4;
++                r += 4;
++            }
++        }
++    }
++    return c;
++}
++
++#ifdef BN_RECURSION
++/*
++ * Karatsuba recursive multiplication algorithm (cf. Knuth, The Art of
++ * Computer Programming, Vol. 2)
++ */
++
++/*-
++ * r is 2*n2 words in size,
++ * a and b are both n2 words in size.
++ * n2 must be a power of 2.
++ * We multiply and return the result.
++ * t must be 2*n2 words in size
++ * We calculate
++ * a[0]*b[0]
++ * a[0]*b[0]+a[1]*b[1]+(a[0]-a[1])*(b[1]-b[0])
++ * a[1]*b[1]
++ */
++/* dnX may not be positive, but n2/2+dnX has to be */
++void bn_mul_recursive(BN_ULONG *r, BN_ULONG *a, BN_ULONG *b, int n2,
++                      int dna, int dnb, BN_ULONG *t)
++{
++    int n = n2 / 2, c1, c2;
++    int tna = n + dna, tnb = n + dnb;
++    unsigned int neg, zero;
++    BN_ULONG ln, lo, *p;
++
++# ifdef BN_MUL_COMBA
++#  if 0
++    if (n2 == 4) {
++        bn_mul_comba4(r, a, b);
++        return;
++    }
++#  endif
++    /*
++     * Only call bn_mul_comba 8 if n2 == 8 and the two arrays are complete
++     * [steve]
++     */
++    if (n2 == 8 && dna == 0 && dnb == 0) {
++        bn_mul_comba8(r, a, b);
++        return;
++    }
++# endif                         /* BN_MUL_COMBA */
++    /* Else do normal multiply */
++    if (n2 < BN_MUL_RECURSIVE_SIZE_NORMAL) {
++        bn_mul_normal(r, a, n2 + dna, b, n2 + dnb);
++        if ((dna + dnb) < 0)
++            memset(&r[2 * n2 + dna + dnb], 0,
++                   sizeof(BN_ULONG) * -(dna + dnb));
++        return;
++    }
++    /* r=(a[0]-a[1])*(b[1]-b[0]) */
++    c1 = bn_cmp_part_words(a, &(a[n]), tna, n - tna);
++    c2 = bn_cmp_part_words(&(b[n]), b, tnb, tnb - n);
++    zero = neg = 0;
++    switch (c1 * 3 + c2) {
++    case -4:
++        bn_sub_part_words(t, &(a[n]), a, tna, tna - n); /* - */
++        bn_sub_part_words(&(t[n]), b, &(b[n]), tnb, n - tnb); /* - */
++        break;
++    case -3:
++        zero = 1;
++        break;
++    case -2:
++        bn_sub_part_words(t, &(a[n]), a, tna, tna - n); /* - */
++        bn_sub_part_words(&(t[n]), &(b[n]), b, tnb, tnb - n); /* + */
++        neg = 1;
++        break;
++    case -1:
++    case 0:
++    case 1:
++        zero = 1;
++        break;
++    case 2:
++        bn_sub_part_words(t, a, &(a[n]), tna, n - tna); /* + */
++        bn_sub_part_words(&(t[n]), b, &(b[n]), tnb, n - tnb); /* - */
++        neg = 1;
++        break;
++    case 3:
++        zero = 1;
++        break;
++    case 4:
++        bn_sub_part_words(t, a, &(a[n]), tna, n - tna);
++        bn_sub_part_words(&(t[n]), &(b[n]), b, tnb, tnb - n);
++        break;
++    }
++
++# ifdef BN_MUL_COMBA
++    if (n == 4 && dna == 0 && dnb == 0) { /* XXX: bn_mul_comba4 could take
++                                           * extra args to do this well */
++        if (!zero)
++            bn_mul_comba4(&(t[n2]), t, &(t[n]));
++        else
++            memset(&t[n2], 0, sizeof(*t) * 8);
++
++        bn_mul_comba4(r, a, b);
++        bn_mul_comba4(&(r[n2]), &(a[n]), &(b[n]));
++    } else if (n == 8 && dna == 0 && dnb == 0) { /* XXX: bn_mul_comba8 could
++                                                  * take extra args to do
++                                                  * this well */
++        if (!zero)
++            bn_mul_comba8(&(t[n2]), t, &(t[n]));
++        else
++            memset(&t[n2], 0, sizeof(*t) * 16);
++
++        bn_mul_comba8(r, a, b);
++        bn_mul_comba8(&(r[n2]), &(a[n]), &(b[n]));
++    } else
++# endif                         /* BN_MUL_COMBA */
++    {
++        p = &(t[n2 * 2]);
++        if (!zero)
++            bn_mul_recursive(&(t[n2]), t, &(t[n]), n, 0, 0, p);
++        else
++            memset(&t[n2], 0, sizeof(*t) * n2);
++        bn_mul_recursive(r, a, b, n, 0, 0, p);
++        bn_mul_recursive(&(r[n2]), &(a[n]), &(b[n]), n, dna, dnb, p);
++    }
++
++    /*-
++     * t[32] holds (a[0]-a[1])*(b[1]-b[0]), c1 is the sign
++     * r[10] holds (a[0]*b[0])
++     * r[32] holds (b[1]*b[1])
++     */
++
++    c1 = (int)(bn_add_words(t, r, &(r[n2]), n2));
++
++    if (neg) {                  /* if t[32] is negative */
++        c1 -= (int)(bn_sub_words(&(t[n2]), t, &(t[n2]), n2));
++    } else {
++        /* Might have a carry */
++        c1 += (int)(bn_add_words(&(t[n2]), &(t[n2]), t, n2));
++    }
++
++    /*-
++     * t[32] holds (a[0]-a[1])*(b[1]-b[0])+(a[0]*b[0])+(a[1]*b[1])
++     * r[10] holds (a[0]*b[0])
++     * r[32] holds (b[1]*b[1])
++     * c1 holds the carry bits
++     */
++    c1 += (int)(bn_add_words(&(r[n]), &(r[n]), &(t[n2]), n2));
++    if (c1) {
++        p = &(r[n + n2]);
++        lo = *p;
++        ln = (lo + c1) & BN_MASK2;
++        *p = ln;
++
++        /*
++         * The overflow will stop before we over write words we should not
++         * overwrite
++         */
++        if (ln < (BN_ULONG)c1) {
++            do {
++                p++;
++                lo = *p;
++                ln = (lo + 1) & BN_MASK2;
++                *p = ln;
++            } while (ln == 0);
++        }
++    }
++}
++
++/*
++ * n+tn is the word length t needs to be n*4 is size, as does r
++ */
++/* tnX may not be negative but less than n */
++void bn_mul_part_recursive(BN_ULONG *r, BN_ULONG *a, BN_ULONG *b, int n,
++                           int tna, int tnb, BN_ULONG *t)
++{
++    int i, j, n2 = n * 2;
++    int c1, c2, neg;
++    BN_ULONG ln, lo, *p;
++
++    if (n < 8) {
++        bn_mul_normal(r, a, n + tna, b, n + tnb);
++        return;
++    }
++
++    /* r=(a[0]-a[1])*(b[1]-b[0]) */
++    c1 = bn_cmp_part_words(a, &(a[n]), tna, n - tna);
++    c2 = bn_cmp_part_words(&(b[n]), b, tnb, tnb - n);
++    neg = 0;
++    switch (c1 * 3 + c2) {
++    case -4:
++        bn_sub_part_words(t, &(a[n]), a, tna, tna - n); /* - */
++        bn_sub_part_words(&(t[n]), b, &(b[n]), tnb, n - tnb); /* - */
++        break;
++    case -3:
++        /* break; */
++    case -2:
++        bn_sub_part_words(t, &(a[n]), a, tna, tna - n); /* - */
++        bn_sub_part_words(&(t[n]), &(b[n]), b, tnb, tnb - n); /* + */
++        neg = 1;
++        break;
++    case -1:
++    case 0:
++    case 1:
++        /* break; */
++    case 2:
++        bn_sub_part_words(t, a, &(a[n]), tna, n - tna); /* + */
++        bn_sub_part_words(&(t[n]), b, &(b[n]), tnb, n - tnb); /* - */
++        neg = 1;
++        break;
++    case 3:
++        /* break; */
++    case 4:
++        bn_sub_part_words(t, a, &(a[n]), tna, n - tna);
++        bn_sub_part_words(&(t[n]), &(b[n]), b, tnb, tnb - n);
++        break;
++    }
++    /*
++     * The zero case isn't yet implemented here. The speedup would probably
++     * be negligible.
++     */
++# if 0
++    if (n == 4) {
++        bn_mul_comba4(&(t[n2]), t, &(t[n]));
++        bn_mul_comba4(r, a, b);
++        bn_mul_normal(&(r[n2]), &(a[n]), tn, &(b[n]), tn);
++        memset(&r[n2 + tn * 2], 0, sizeof(*r) * (n2 - tn * 2));
++    } else
++# endif
++    if (n == 8) {
++        bn_mul_comba8(&(t[n2]), t, &(t[n]));
++        bn_mul_comba8(r, a, b);
++        bn_mul_normal(&(r[n2]), &(a[n]), tna, &(b[n]), tnb);
++        memset(&r[n2 + tna + tnb], 0, sizeof(*r) * (n2 - tna - tnb));
++    } else {
++        p = &(t[n2 * 2]);
++        bn_mul_recursive(&(t[n2]), t, &(t[n]), n, 0, 0, p);
++        bn_mul_recursive(r, a, b, n, 0, 0, p);
++        i = n / 2;
++        /*
++         * If there is only a bottom half to the number, just do it
++         */
++        if (tna > tnb)
++            j = tna - i;
++        else
++            j = tnb - i;
++        if (j == 0) {
++            bn_mul_recursive(&(r[n2]), &(a[n]), &(b[n]),
++                             i, tna - i, tnb - i, p);
++            memset(&r[n2 + i * 2], 0, sizeof(*r) * (n2 - i * 2));
++        } else if (j > 0) {     /* eg, n == 16, i == 8 and tn == 11 */
++            bn_mul_part_recursive(&(r[n2]), &(a[n]), &(b[n]),
++                                  i, tna - i, tnb - i, p);
++            memset(&(r[n2 + tna + tnb]), 0,
++                   sizeof(BN_ULONG) * (n2 - tna - tnb));
++        } else {                /* (j < 0) eg, n == 16, i == 8 and tn == 5 */
++
++            memset(&r[n2], 0, sizeof(*r) * n2);
++            if (tna < BN_MUL_RECURSIVE_SIZE_NORMAL
++                && tnb < BN_MUL_RECURSIVE_SIZE_NORMAL) {
++                bn_mul_normal(&(r[n2]), &(a[n]), tna, &(b[n]), tnb);
++            } else {
++                for (;;) {
++                    i /= 2;
++                    /*
++                     * these simplified conditions work exclusively because
++                     * difference between tna and tnb is 1 or 0
++                     */
++                    if (i < tna || i < tnb) {
++                        bn_mul_part_recursive(&(r[n2]),
++                                              &(a[n]), &(b[n]),
++                                              i, tna - i, tnb - i, p);
++                        break;
++                    } else if (i == tna || i == tnb) {
++                        bn_mul_recursive(&(r[n2]),
++                                         &(a[n]), &(b[n]),
++                                         i, tna - i, tnb - i, p);
++                        break;
++                    }
++                }
++            }
++        }
++    }
++
++    /*-
++     * t[32] holds (a[0]-a[1])*(b[1]-b[0]), c1 is the sign
++     * r[10] holds (a[0]*b[0])
++     * r[32] holds (b[1]*b[1])
++     */
++
++    c1 = (int)(bn_add_words(t, r, &(r[n2]), n2));
++
++    if (neg) {                  /* if t[32] is negative */
++        c1 -= (int)(bn_sub_words(&(t[n2]), t, &(t[n2]), n2));
++    } else {
++        /* Might have a carry */
++        c1 += (int)(bn_add_words(&(t[n2]), &(t[n2]), t, n2));
++    }
++
++    /*-
++     * t[32] holds (a[0]-a[1])*(b[1]-b[0])+(a[0]*b[0])+(a[1]*b[1])
++     * r[10] holds (a[0]*b[0])
++     * r[32] holds (b[1]*b[1])
++     * c1 holds the carry bits
++     */
++    c1 += (int)(bn_add_words(&(r[n]), &(r[n]), &(t[n2]), n2));
++    if (c1) {
++        p = &(r[n + n2]);
++        lo = *p;
++        ln = (lo + c1) & BN_MASK2;
++        *p = ln;
++
++        /*
++         * The overflow will stop before we over write words we should not
++         * overwrite
++         */
++        if (ln < (BN_ULONG)c1) {
++            do {
++                p++;
++                lo = *p;
++                ln = (lo + 1) & BN_MASK2;
++                *p = ln;
++            } while (ln == 0);
++        }
++    }
++}
++
++/*-
++ * a and b must be the same size, which is n2.
++ * r needs to be n2 words and t needs to be n2*2
++ */
++void bn_mul_low_recursive(BN_ULONG *r, BN_ULONG *a, BN_ULONG *b, int n2,
++                          BN_ULONG *t)
++{
++    int n = n2 / 2;
++
++    bn_mul_recursive(r, a, b, n, 0, 0, &(t[0]));
++    if (n >= BN_MUL_LOW_RECURSIVE_SIZE_NORMAL) {
++        bn_mul_low_recursive(&(t[0]), &(a[0]), &(b[n]), n, &(t[n2]));
++        bn_add_words(&(r[n]), &(r[n]), &(t[0]), n);
++        bn_mul_low_recursive(&(t[0]), &(a[n]), &(b[0]), n, &(t[n2]));
++        bn_add_words(&(r[n]), &(r[n]), &(t[0]), n);
++    } else {
++        bn_mul_low_normal(&(t[0]), &(a[0]), &(b[n]), n);
++        bn_mul_low_normal(&(t[n]), &(a[n]), &(b[0]), n);
++        bn_add_words(&(r[n]), &(r[n]), &(t[0]), n);
++        bn_add_words(&(r[n]), &(r[n]), &(t[n]), n);
++    }
++}
++
++/*-
++ * a and b must be the same size, which is n2.
++ * r needs to be n2 words and t needs to be n2*2
++ * l is the low words of the output.
++ * t needs to be n2*3
++ */
++void bn_mul_high(BN_ULONG *r, BN_ULONG *a, BN_ULONG *b, BN_ULONG *l, int n2,
++                 BN_ULONG *t)
++{
++    int i, n;
++    int c1, c2;
++    int neg, oneg, zero;
++    BN_ULONG ll, lc, *lp, *mp;
++
++    n = n2 / 2;
++
++    /* Calculate (al-ah)*(bh-bl) */
++    neg = zero = 0;
++    c1 = bn_cmp_words(&(a[0]), &(a[n]), n);
++    c2 = bn_cmp_words(&(b[n]), &(b[0]), n);
++    switch (c1 * 3 + c2) {
++    case -4:
++        bn_sub_words(&(r[0]), &(a[n]), &(a[0]), n);
++        bn_sub_words(&(r[n]), &(b[0]), &(b[n]), n);
++        break;
++    case -3:
++        zero = 1;
++        break;
++    case -2:
++        bn_sub_words(&(r[0]), &(a[n]), &(a[0]), n);
++        bn_sub_words(&(r[n]), &(b[n]), &(b[0]), n);
++        neg = 1;
++        break;
++    case -1:
++    case 0:
++    case 1:
++        zero = 1;
++        break;
++    case 2:
++        bn_sub_words(&(r[0]), &(a[0]), &(a[n]), n);
++        bn_sub_words(&(r[n]), &(b[0]), &(b[n]), n);
++        neg = 1;
++        break;
++    case 3:
++        zero = 1;
++        break;
++    case 4:
++        bn_sub_words(&(r[0]), &(a[0]), &(a[n]), n);
++        bn_sub_words(&(r[n]), &(b[n]), &(b[0]), n);
++        break;
++    }
++
++    oneg = neg;
++    /* t[10] = (a[0]-a[1])*(b[1]-b[0]) */
++    /* r[10] = (a[1]*b[1]) */
++# ifdef BN_MUL_COMBA
++    if (n == 8) {
++        bn_mul_comba8(&(t[0]), &(r[0]), &(r[n]));
++        bn_mul_comba8(r, &(a[n]), &(b[n]));
++    } else
++# endif
++    {
++        bn_mul_recursive(&(t[0]), &(r[0]), &(r[n]), n, 0, 0, &(t[n2]));
++        bn_mul_recursive(r, &(a[n]), &(b[n]), n, 0, 0, &(t[n2]));
++    }
++
++    /*-
++     * s0 == low(al*bl)
++     * s1 == low(ah*bh)+low((al-ah)*(bh-bl))+low(al*bl)+high(al*bl)
++     * We know s0 and s1 so the only unknown is high(al*bl)
++     * high(al*bl) == s1 - low(ah*bh+s0+(al-ah)*(bh-bl))
++     * high(al*bl) == s1 - (r[0]+l[0]+t[0])
++     */
++    if (l != NULL) {
++        lp = &(t[n2 + n]);
++        bn_add_words(lp, &(r[0]), &(l[0]), n);
++    } else {
++        lp = &(r[0]);
++    }
++
++    if (neg)
++        neg = (int)(bn_sub_words(&(t[n2]), lp, &(t[0]), n));
++    else {
++        bn_add_words(&(t[n2]), lp, &(t[0]), n);
++        neg = 0;
++    }
++
++    if (l != NULL) {
++        bn_sub_words(&(t[n2 + n]), &(l[n]), &(t[n2]), n);
++    } else {
++        lp = &(t[n2 + n]);
++        mp = &(t[n2]);
++        for (i = 0; i < n; i++)
++            lp[i] = ((~mp[i]) + 1) & BN_MASK2;
++    }
++
++    /*-
++     * s[0] = low(al*bl)
++     * t[3] = high(al*bl)
++     * t[10] = (a[0]-a[1])*(b[1]-b[0]) neg is the sign
++     * r[10] = (a[1]*b[1])
++     */
++    /*-
++     * R[10] = al*bl
++     * R[21] = al*bl + ah*bh + (a[0]-a[1])*(b[1]-b[0])
++     * R[32] = ah*bh
++     */
++    /*-
++     * R[1]=t[3]+l[0]+r[0](+-)t[0] (have carry/borrow)
++     * R[2]=r[0]+t[3]+r[1](+-)t[1] (have carry/borrow)
++     * R[3]=r[1]+(carry/borrow)
++     */
++    if (l != NULL) {
++        lp = &(t[n2]);
++        c1 = (int)(bn_add_words(lp, &(t[n2 + n]), &(l[0]), n));
++    } else {
++        lp = &(t[n2 + n]);
++        c1 = 0;
++    }
++    c1 += (int)(bn_add_words(&(t[n2]), lp, &(r[0]), n));
++    if (oneg)
++        c1 -= (int)(bn_sub_words(&(t[n2]), &(t[n2]), &(t[0]), n));
++    else
++        c1 += (int)(bn_add_words(&(t[n2]), &(t[n2]), &(t[0]), n));
++
++    c2 = (int)(bn_add_words(&(r[0]), &(r[0]), &(t[n2 + n]), n));
++    c2 += (int)(bn_add_words(&(r[0]), &(r[0]), &(r[n]), n));
++    if (oneg)
++        c2 -= (int)(bn_sub_words(&(r[0]), &(r[0]), &(t[n]), n));
++    else
++        c2 += (int)(bn_add_words(&(r[0]), &(r[0]), &(t[n]), n));
++
++    if (c1 != 0) {              /* Add starting at r[0], could be +ve or -ve */
++        i = 0;
++        if (c1 > 0) {
++            lc = c1;
++            do {
++                ll = (r[i] + lc) & BN_MASK2;
++                r[i++] = ll;
++                lc = (lc > ll);
++            } while (lc);
++        } else {
++            lc = -c1;
++            do {
++                ll = r[i];
++                r[i++] = (ll - lc) & BN_MASK2;
++                lc = (lc > ll);
++            } while (lc);
++        }
++    }
++    if (c2 != 0) {              /* Add starting at r[1] */
++        i = n;
++        if (c2 > 0) {
++            lc = c2;
++            do {
++                ll = (r[i] + lc) & BN_MASK2;
++                r[i++] = ll;
++                lc = (lc > ll);
++            } while (lc);
++        } else {
++            lc = -c2;
++            do {
++                ll = r[i];
++                r[i++] = (ll - lc) & BN_MASK2;
++                lc = (lc > ll);
++            } while (lc);
++        }
++    }
++}
++#endif                          /* BN_RECURSION */
++
++int BN_mul(BIGNUM *r, const BIGNUM *a, const BIGNUM *b, BN_CTX *ctx)
++{
++    int ret = 0;
++    int top, al, bl;
++    BIGNUM *rr;
++#if defined(BN_MUL_COMBA) || defined(BN_RECURSION)
++    int i;
++#endif
++#ifdef BN_RECURSION
++    BIGNUM *t = NULL;
++    int j = 0, k;
++#endif
++
++    bn_check_top(a);
++    bn_check_top(b);
++    bn_check_top(r);
++
++    al = a->top;
++    bl = b->top;
++
++    if ((al == 0) || (bl == 0)) {
++        BN_zero(r);
++        return (1);
++    }
++    top = al + bl;
++
++    BN_CTX_start(ctx);
++    if ((r == a) || (r == b)) {
++        if ((rr = BN_CTX_get(ctx)) == NULL)
++            goto err;
++    } else
++        rr = r;
++
++#if defined(BN_MUL_COMBA) || defined(BN_RECURSION)
++    i = al - bl;
++#endif
++#ifdef BN_MUL_COMBA
++    if (i == 0) {
++# if 0
++        if (al == 4) {
++            if (bn_wexpand(rr, 8) == NULL)
++                goto err;
++            rr->top = 8;
++            bn_mul_comba4(rr->d, a->d, b->d);
++            goto end;
++        }
++# endif
++        if (al == 8) {
++            if (bn_wexpand(rr, 16) == NULL)
++                goto err;
++            rr->top = 16;
++            bn_mul_comba8(rr->d, a->d, b->d);
++            goto end;
++        }
++    }
++#endif                          /* BN_MUL_COMBA */
++#ifdef BN_RECURSION
++    if ((al >= BN_MULL_SIZE_NORMAL) && (bl >= BN_MULL_SIZE_NORMAL)) {
++        if (i >= -1 && i <= 1) {
++            /*
++             * Find out the power of two lower or equal to the longest of the
++             * two numbers
++             */
++            if (i >= 0) {
++                j = BN_num_bits_word((BN_ULONG)al);
++            }
++            if (i == -1) {
++                j = BN_num_bits_word((BN_ULONG)bl);
++            }
++            j = 1 << (j - 1);
++            assert(j <= al || j <= bl);
++            k = j + j;
++            t = BN_CTX_get(ctx);
++            if (t == NULL)
++                goto err;
++            if (al > j || bl > j) {
++                if (bn_wexpand(t, k * 4) == NULL)
++                    goto err;
++                if (bn_wexpand(rr, k * 4) == NULL)
++                    goto err;
++                bn_mul_part_recursive(rr->d, a->d, b->d,
++                                      j, al - j, bl - j, t->d);
++            } else {            /* al <= j || bl <= j */
++
++                if (bn_wexpand(t, k * 2) == NULL)
++                    goto err;
++                if (bn_wexpand(rr, k * 2) == NULL)
++                    goto err;
++                bn_mul_recursive(rr->d, a->d, b->d, j, al - j, bl - j, t->d);
++            }
++            rr->top = top;
++            goto end;
++        }
++# if 0
++        if (i == 1 && !BN_get_flags(b, BN_FLG_STATIC_DATA)) {
++            BIGNUM *tmp_bn = (BIGNUM *)b;
++            if (bn_wexpand(tmp_bn, al) == NULL)
++                goto err;
++            tmp_bn->d[bl] = 0;
++            bl++;
++            i--;
++        } else if (i == -1 && !BN_get_flags(a, BN_FLG_STATIC_DATA)) {
++            BIGNUM *tmp_bn = (BIGNUM *)a;
++            if (bn_wexpand(tmp_bn, bl) == NULL)
++                goto err;
++            tmp_bn->d[al] = 0;
++            al++;
++            i++;
++        }
++        if (i == 0) {
++            /* symmetric and > 4 */
++            /* 16 or larger */
++            j = BN_num_bits_word((BN_ULONG)al);
++            j = 1 << (j - 1);
++            k = j + j;
++            t = BN_CTX_get(ctx);
++            if (al == j) {      /* exact multiple */
++                if (bn_wexpand(t, k * 2) == NULL)
++                    goto err;
++                if (bn_wexpand(rr, k * 2) == NULL)
++                    goto err;
++                bn_mul_recursive(rr->d, a->d, b->d, al, t->d);
++            } else {
++                if (bn_wexpand(t, k * 4) == NULL)
++                    goto err;
++                if (bn_wexpand(rr, k * 4) == NULL)
++                    goto err;
++                bn_mul_part_recursive(rr->d, a->d, b->d, al - j, j, t->d);
++            }
++            rr->top = top;
++            goto end;
++        }
++# endif
++    }
++#endif                          /* BN_RECURSION */
++    if (bn_wexpand(rr, top) == NULL)
++        goto err;
++    rr->top = top;
++    bn_mul_normal(rr->d, a->d, al, b->d, bl);
++
++#if defined(BN_MUL_COMBA) || defined(BN_RECURSION)
++ end:
++#endif
++    rr->neg = a->neg ^ b->neg;
++    bn_correct_top(rr);
++    if (r != rr && BN_copy(r, rr) == NULL)
++        goto err;
++
++    ret = 1;
++ err:
++    bn_check_top(r);
++    BN_CTX_end(ctx);
++    return (ret);
++}
++
++void bn_mul_normal(BN_ULONG *r, BN_ULONG *a, int na, BN_ULONG *b, int nb)
++{
++    BN_ULONG *rr;
++
++    if (na < nb) {
++        int itmp;
++        BN_ULONG *ltmp;
++
++        itmp = na;
++        na = nb;
++        nb = itmp;
++        ltmp = a;
++        a = b;
++        b = ltmp;
++
++    }
++    rr = &(r[na]);
++    if (nb <= 0) {
++        (void)bn_mul_words(r, a, na, 0);
++        return;
++    } else
++        rr[0] = bn_mul_words(r, a, na, b[0]);
++
++    for (;;) {
++        if (--nb <= 0)
++            return;
++        rr[1] = bn_mul_add_words(&(r[1]), a, na, b[1]);
++        if (--nb <= 0)
++            return;
++        rr[2] = bn_mul_add_words(&(r[2]), a, na, b[2]);
++        if (--nb <= 0)
++            return;
++        rr[3] = bn_mul_add_words(&(r[3]), a, na, b[3]);
++        if (--nb <= 0)
++            return;
++        rr[4] = bn_mul_add_words(&(r[4]), a, na, b[4]);
++        rr += 4;
++        r += 4;
++        b += 4;
++    }
++}
++
++void bn_mul_low_normal(BN_ULONG *r, BN_ULONG *a, BN_ULONG *b, int n)
++{
++    bn_mul_words(r, a, n, b[0]);
++
++    for (;;) {
++        if (--n <= 0)
++            return;
++        bn_mul_add_words(&(r[1]), a, n, b[1]);
++        if (--n <= 0)
++            return;
++        bn_mul_add_words(&(r[2]), a, n, b[2]);
++        if (--n <= 0)
++            return;
++        bn_mul_add_words(&(r[3]), a, n, b[3]);
++        if (--n <= 0)
++            return;
++        bn_mul_add_words(&(r[4]), a, n, b[4]);
++        r += 4;
++        b += 4;
++    }
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/bn/bn_nist.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/bn/bn_nist.c
+new file mode 100644
+index 0000000..53598f9
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/bn/bn_nist.c
+@@ -0,0 +1,1239 @@
++/*
++ * Copyright 2002-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include "bn_lcl.h"
++#include "internal/cryptlib.h"
++
++#define BN_NIST_192_TOP (192+BN_BITS2-1)/BN_BITS2
++#define BN_NIST_224_TOP (224+BN_BITS2-1)/BN_BITS2
++#define BN_NIST_256_TOP (256+BN_BITS2-1)/BN_BITS2
++#define BN_NIST_384_TOP (384+BN_BITS2-1)/BN_BITS2
++#define BN_NIST_521_TOP (521+BN_BITS2-1)/BN_BITS2
++
++/* pre-computed tables are "carry-less" values of modulus*(i+1) */
++#if BN_BITS2 == 64
++static const BN_ULONG _nist_p_192[][BN_NIST_192_TOP] = {
++    {0xFFFFFFFFFFFFFFFFULL, 0xFFFFFFFFFFFFFFFEULL, 0xFFFFFFFFFFFFFFFFULL},
++    {0xFFFFFFFFFFFFFFFEULL, 0xFFFFFFFFFFFFFFFDULL, 0xFFFFFFFFFFFFFFFFULL},
++    {0xFFFFFFFFFFFFFFFDULL, 0xFFFFFFFFFFFFFFFCULL, 0xFFFFFFFFFFFFFFFFULL}
++};
++
++static const BN_ULONG _nist_p_192_sqr[] = {
++    0x0000000000000001ULL, 0x0000000000000002ULL, 0x0000000000000001ULL,
++    0xFFFFFFFFFFFFFFFEULL, 0xFFFFFFFFFFFFFFFDULL, 0xFFFFFFFFFFFFFFFFULL
++};
++
++static const BN_ULONG _nist_p_224[][BN_NIST_224_TOP] = {
++    {0x0000000000000001ULL, 0xFFFFFFFF00000000ULL,
++     0xFFFFFFFFFFFFFFFFULL, 0x00000000FFFFFFFFULL},
++    {0x0000000000000002ULL, 0xFFFFFFFE00000000ULL,
++     0xFFFFFFFFFFFFFFFFULL, 0x00000001FFFFFFFFULL} /* this one is
++                                                    * "carry-full" */
++};
++
++static const BN_ULONG _nist_p_224_sqr[] = {
++    0x0000000000000001ULL, 0xFFFFFFFE00000000ULL,
++    0xFFFFFFFFFFFFFFFFULL, 0x0000000200000000ULL,
++    0x0000000000000000ULL, 0xFFFFFFFFFFFFFFFEULL,
++    0xFFFFFFFFFFFFFFFFULL
++};
++
++static const BN_ULONG _nist_p_256[][BN_NIST_256_TOP] = {
++    {0xFFFFFFFFFFFFFFFFULL, 0x00000000FFFFFFFFULL,
++     0x0000000000000000ULL, 0xFFFFFFFF00000001ULL},
++    {0xFFFFFFFFFFFFFFFEULL, 0x00000001FFFFFFFFULL,
++     0x0000000000000000ULL, 0xFFFFFFFE00000002ULL},
++    {0xFFFFFFFFFFFFFFFDULL, 0x00000002FFFFFFFFULL,
++     0x0000000000000000ULL, 0xFFFFFFFD00000003ULL},
++    {0xFFFFFFFFFFFFFFFCULL, 0x00000003FFFFFFFFULL,
++     0x0000000000000000ULL, 0xFFFFFFFC00000004ULL},
++    {0xFFFFFFFFFFFFFFFBULL, 0x00000004FFFFFFFFULL,
++     0x0000000000000000ULL, 0xFFFFFFFB00000005ULL},
++};
++
++static const BN_ULONG _nist_p_256_sqr[] = {
++    0x0000000000000001ULL, 0xFFFFFFFE00000000ULL,
++    0xFFFFFFFFFFFFFFFFULL, 0x00000001FFFFFFFEULL,
++    0x00000001FFFFFFFEULL, 0x00000001FFFFFFFEULL,
++    0xFFFFFFFE00000001ULL, 0xFFFFFFFE00000002ULL
++};
++
++static const BN_ULONG _nist_p_384[][BN_NIST_384_TOP] = {
++    {0x00000000FFFFFFFFULL, 0xFFFFFFFF00000000ULL, 0xFFFFFFFFFFFFFFFEULL,
++     0xFFFFFFFFFFFFFFFFULL, 0xFFFFFFFFFFFFFFFFULL, 0xFFFFFFFFFFFFFFFFULL},
++    {0x00000001FFFFFFFEULL, 0xFFFFFFFE00000000ULL, 0xFFFFFFFFFFFFFFFDULL,
++     0xFFFFFFFFFFFFFFFFULL, 0xFFFFFFFFFFFFFFFFULL, 0xFFFFFFFFFFFFFFFFULL},
++    {0x00000002FFFFFFFDULL, 0xFFFFFFFD00000000ULL, 0xFFFFFFFFFFFFFFFCULL,
++     0xFFFFFFFFFFFFFFFFULL, 0xFFFFFFFFFFFFFFFFULL, 0xFFFFFFFFFFFFFFFFULL},
++    {0x00000003FFFFFFFCULL, 0xFFFFFFFC00000000ULL, 0xFFFFFFFFFFFFFFFBULL,
++     0xFFFFFFFFFFFFFFFFULL, 0xFFFFFFFFFFFFFFFFULL, 0xFFFFFFFFFFFFFFFFULL},
++    {0x00000004FFFFFFFBULL, 0xFFFFFFFB00000000ULL, 0xFFFFFFFFFFFFFFFAULL,
++     0xFFFFFFFFFFFFFFFFULL, 0xFFFFFFFFFFFFFFFFULL, 0xFFFFFFFFFFFFFFFFULL},
++};
++
++static const BN_ULONG _nist_p_384_sqr[] = {
++    0xFFFFFFFE00000001ULL, 0x0000000200000000ULL, 0xFFFFFFFE00000000ULL,
++    0x0000000200000000ULL, 0x0000000000000001ULL, 0x0000000000000000ULL,
++    0x00000001FFFFFFFEULL, 0xFFFFFFFE00000000ULL, 0xFFFFFFFFFFFFFFFDULL,
++    0xFFFFFFFFFFFFFFFFULL, 0xFFFFFFFFFFFFFFFFULL, 0xFFFFFFFFFFFFFFFFULL
++};
++
++static const BN_ULONG _nist_p_521[] =
++    { 0xFFFFFFFFFFFFFFFFULL, 0xFFFFFFFFFFFFFFFFULL,
++    0xFFFFFFFFFFFFFFFFULL, 0xFFFFFFFFFFFFFFFFULL,
++    0xFFFFFFFFFFFFFFFFULL, 0xFFFFFFFFFFFFFFFFULL,
++    0xFFFFFFFFFFFFFFFFULL, 0xFFFFFFFFFFFFFFFFULL,
++    0x00000000000001FFULL
++};
++
++static const BN_ULONG _nist_p_521_sqr[] = {
++    0x0000000000000001ULL, 0x0000000000000000ULL, 0x0000000000000000ULL,
++    0x0000000000000000ULL, 0x0000000000000000ULL, 0x0000000000000000ULL,
++    0x0000000000000000ULL, 0x0000000000000000ULL, 0xFFFFFFFFFFFFFC00ULL,
++    0xFFFFFFFFFFFFFFFFULL, 0xFFFFFFFFFFFFFFFFULL, 0xFFFFFFFFFFFFFFFFULL,
++    0xFFFFFFFFFFFFFFFFULL, 0xFFFFFFFFFFFFFFFFULL, 0xFFFFFFFFFFFFFFFFULL,
++    0xFFFFFFFFFFFFFFFFULL, 0x000000000003FFFFULL
++};
++#elif BN_BITS2 == 32
++static const BN_ULONG _nist_p_192[][BN_NIST_192_TOP] = {
++    {0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFE, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF},
++    {0xFFFFFFFE, 0xFFFFFFFF, 0xFFFFFFFD, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF},
++    {0xFFFFFFFD, 0xFFFFFFFF, 0xFFFFFFFC, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF}
++};
++
++static const BN_ULONG _nist_p_192_sqr[] = {
++    0x00000001, 0x00000000, 0x00000002, 0x00000000, 0x00000001, 0x00000000,
++    0xFFFFFFFE, 0xFFFFFFFF, 0xFFFFFFFD, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF
++};
++
++static const BN_ULONG _nist_p_224[][BN_NIST_224_TOP] = {
++    {0x00000001, 0x00000000, 0x00000000, 0xFFFFFFFF,
++     0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF},
++    {0x00000002, 0x00000000, 0x00000000, 0xFFFFFFFE,
++     0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF}
++};
++
++static const BN_ULONG _nist_p_224_sqr[] = {
++    0x00000001, 0x00000000, 0x00000000, 0xFFFFFFFE,
++    0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000002,
++    0x00000000, 0x00000000, 0xFFFFFFFE, 0xFFFFFFFF,
++    0xFFFFFFFF, 0xFFFFFFFF
++};
++
++static const BN_ULONG _nist_p_256[][BN_NIST_256_TOP] = {
++    {0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000,
++     0x00000000, 0x00000000, 0x00000001, 0xFFFFFFFF},
++    {0xFFFFFFFE, 0xFFFFFFFF, 0xFFFFFFFF, 0x00000001,
++     0x00000000, 0x00000000, 0x00000002, 0xFFFFFFFE},
++    {0xFFFFFFFD, 0xFFFFFFFF, 0xFFFFFFFF, 0x00000002,
++     0x00000000, 0x00000000, 0x00000003, 0xFFFFFFFD},
++    {0xFFFFFFFC, 0xFFFFFFFF, 0xFFFFFFFF, 0x00000003,
++     0x00000000, 0x00000000, 0x00000004, 0xFFFFFFFC},
++    {0xFFFFFFFB, 0xFFFFFFFF, 0xFFFFFFFF, 0x00000004,
++     0x00000000, 0x00000000, 0x00000005, 0xFFFFFFFB},
++};
++
++static const BN_ULONG _nist_p_256_sqr[] = {
++    0x00000001, 0x00000000, 0x00000000, 0xFFFFFFFE,
++    0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFE, 0x00000001,
++    0xFFFFFFFE, 0x00000001, 0xFFFFFFFE, 0x00000001,
++    0x00000001, 0xFFFFFFFE, 0x00000002, 0xFFFFFFFE
++};
++
++static const BN_ULONG _nist_p_384[][BN_NIST_384_TOP] = {
++    {0xFFFFFFFF, 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFE, 0xFFFFFFFF,
++     0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF},
++    {0xFFFFFFFE, 0x00000001, 0x00000000, 0xFFFFFFFE, 0xFFFFFFFD, 0xFFFFFFFF,
++     0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF},
++    {0xFFFFFFFD, 0x00000002, 0x00000000, 0xFFFFFFFD, 0xFFFFFFFC, 0xFFFFFFFF,
++     0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF},
++    {0xFFFFFFFC, 0x00000003, 0x00000000, 0xFFFFFFFC, 0xFFFFFFFB, 0xFFFFFFFF,
++     0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF},
++    {0xFFFFFFFB, 0x00000004, 0x00000000, 0xFFFFFFFB, 0xFFFFFFFA, 0xFFFFFFFF,
++     0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF},
++};
++
++static const BN_ULONG _nist_p_384_sqr[] = {
++    0x00000001, 0xFFFFFFFE, 0x00000000, 0x00000002, 0x00000000, 0xFFFFFFFE,
++    0x00000000, 0x00000002, 0x00000001, 0x00000000, 0x00000000, 0x00000000,
++    0xFFFFFFFE, 0x00000001, 0x00000000, 0xFFFFFFFE, 0xFFFFFFFD, 0xFFFFFFFF,
++    0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF
++};
++
++static const BN_ULONG _nist_p_521[] = { 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
++    0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
++    0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
++    0xFFFFFFFF, 0x000001FF
++};
++
++static const BN_ULONG _nist_p_521_sqr[] = {
++    0x00000001, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
++    0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
++    0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xFFFFFC00, 0xFFFFFFFF,
++    0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
++    0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
++    0xFFFFFFFF, 0xFFFFFFFF, 0x0003FFFF
++};
++#else
++# error "unsupported BN_BITS2"
++#endif
++
++static const BIGNUM _bignum_nist_p_192 = {
++    (BN_ULONG *)_nist_p_192[0],
++    BN_NIST_192_TOP,
++    BN_NIST_192_TOP,
++    0,
++    BN_FLG_STATIC_DATA
++};
++
++static const BIGNUM _bignum_nist_p_224 = {
++    (BN_ULONG *)_nist_p_224[0],
++    BN_NIST_224_TOP,
++    BN_NIST_224_TOP,
++    0,
++    BN_FLG_STATIC_DATA
++};
++
++static const BIGNUM _bignum_nist_p_256 = {
++    (BN_ULONG *)_nist_p_256[0],
++    BN_NIST_256_TOP,
++    BN_NIST_256_TOP,
++    0,
++    BN_FLG_STATIC_DATA
++};
++
++static const BIGNUM _bignum_nist_p_384 = {
++    (BN_ULONG *)_nist_p_384[0],
++    BN_NIST_384_TOP,
++    BN_NIST_384_TOP,
++    0,
++    BN_FLG_STATIC_DATA
++};
++
++static const BIGNUM _bignum_nist_p_521 = {
++    (BN_ULONG *)_nist_p_521,
++    BN_NIST_521_TOP,
++    BN_NIST_521_TOP,
++    0,
++    BN_FLG_STATIC_DATA
++};
++
++const BIGNUM *BN_get0_nist_prime_192(void)
++{
++    return &_bignum_nist_p_192;
++}
++
++const BIGNUM *BN_get0_nist_prime_224(void)
++{
++    return &_bignum_nist_p_224;
++}
++
++const BIGNUM *BN_get0_nist_prime_256(void)
++{
++    return &_bignum_nist_p_256;
++}
++
++const BIGNUM *BN_get0_nist_prime_384(void)
++{
++    return &_bignum_nist_p_384;
++}
++
++const BIGNUM *BN_get0_nist_prime_521(void)
++{
++    return &_bignum_nist_p_521;
++}
++
++static void nist_cp_bn_0(BN_ULONG *dst, const BN_ULONG *src, int top, int max)
++{
++    int i;
++
++#ifdef BN_DEBUG
++    OPENSSL_assert(top <= max);
++#endif
++    for (i = 0; i < top; i++)
++        dst[i] = src[i];
++    for (; i < max; i++)
++        dst[i] = 0;
++}
++
++static void nist_cp_bn(BN_ULONG *dst, const BN_ULONG *src, int top)
++{
++    int i;
++
++    for (i = 0; i < top; i++)
++        dst[i] = src[i];
++}
++
++#if BN_BITS2 == 64
++# define bn_cp_64(to, n, from, m)        (to)[n] = (m>=0)?((from)[m]):0;
++# define bn_64_set_0(to, n)              (to)[n] = (BN_ULONG)0;
++/*
++ * two following macros are implemented under assumption that they
++ * are called in a sequence with *ascending* n, i.e. as they are...
++ */
++# define bn_cp_32_naked(to, n, from, m)  (((n)&1)?(to[(n)/2]|=((m)&1)?(from[(m)/2]&BN_MASK2h):(from[(m)/2]<<32))\
++                                                :(to[(n)/2] =((m)&1)?(from[(m)/2]>>32):(from[(m)/2]&BN_MASK2l)))
++# define bn_32_set_0(to, n)              (((n)&1)?(to[(n)/2]&=BN_MASK2l):(to[(n)/2]=0));
++# define bn_cp_32(to,n,from,m)           ((m)>=0)?bn_cp_32_naked(to,n,from,m):bn_32_set_0(to,n)
++# if defined(L_ENDIAN)
++#  if defined(__arch64__)
++#   define NIST_INT64 long
++#  else
++#   define NIST_INT64 long long
++#  endif
++# endif
++#else
++# define bn_cp_64(to, n, from, m) \
++        { \
++        bn_cp_32(to, (n)*2, from, (m)*2); \
++        bn_cp_32(to, (n)*2+1, from, (m)*2+1); \
++        }
++# define bn_64_set_0(to, n) \
++        { \
++        bn_32_set_0(to, (n)*2); \
++        bn_32_set_0(to, (n)*2+1); \
++        }
++# define bn_cp_32(to, n, from, m)        (to)[n] = (m>=0)?((from)[m]):0;
++# define bn_32_set_0(to, n)              (to)[n] = (BN_ULONG)0;
++# if defined(_WIN32) && !defined(__GNUC__)
++#  define NIST_INT64 __int64
++# elif defined(BN_LLONG)
++#  define NIST_INT64 long long
++# endif
++#endif                          /* BN_BITS2 != 64 */
++
++#define nist_set_192(to, from, a1, a2, a3) \
++        { \
++        bn_cp_64(to, 0, from, (a3) - 3) \
++        bn_cp_64(to, 1, from, (a2) - 3) \
++        bn_cp_64(to, 2, from, (a1) - 3) \
++        }
++
++int BN_nist_mod_192(BIGNUM *r, const BIGNUM *a, const BIGNUM *field,
++                    BN_CTX *ctx)
++{
++    int top = a->top, i;
++    int carry;
++    register BN_ULONG *r_d, *a_d = a->d;
++    union {
++        BN_ULONG bn[BN_NIST_192_TOP];
++        unsigned int ui[BN_NIST_192_TOP * sizeof(BN_ULONG) /
++                        sizeof(unsigned int)];
++    } buf;
++    BN_ULONG c_d[BN_NIST_192_TOP], *res;
++    PTR_SIZE_INT mask;
++    static const BIGNUM _bignum_nist_p_192_sqr = {
++        (BN_ULONG *)_nist_p_192_sqr,
++        OSSL_NELEM(_nist_p_192_sqr),
++        OSSL_NELEM(_nist_p_192_sqr),
++        0, BN_FLG_STATIC_DATA
++    };
++
++    field = &_bignum_nist_p_192; /* just to make sure */
++
++    if (BN_is_negative(a) || BN_ucmp(a, &_bignum_nist_p_192_sqr) >= 0)
++        return BN_nnmod(r, a, field, ctx);
++
++    i = BN_ucmp(field, a);
++    if (i == 0) {
++        BN_zero(r);
++        return 1;
++    } else if (i > 0)
++        return (r == a) ? 1 : (BN_copy(r, a) != NULL);
++
++    if (r != a) {
++        if (!bn_wexpand(r, BN_NIST_192_TOP))
++            return 0;
++        r_d = r->d;
++        nist_cp_bn(r_d, a_d, BN_NIST_192_TOP);
++    } else
++        r_d = a_d;
++
++    nist_cp_bn_0(buf.bn, a_d + BN_NIST_192_TOP, top - BN_NIST_192_TOP,
++                 BN_NIST_192_TOP);
++
++#if defined(NIST_INT64)
++    {
++        NIST_INT64 acc;         /* accumulator */
++        unsigned int *rp = (unsigned int *)r_d;
++        const unsigned int *bp = (const unsigned int *)buf.ui;
++
++        acc = rp[0];
++        acc += bp[3 * 2 - 6];
++        acc += bp[5 * 2 - 6];
++        rp[0] = (unsigned int)acc;
++        acc >>= 32;
++
++        acc += rp[1];
++        acc += bp[3 * 2 - 5];
++        acc += bp[5 * 2 - 5];
++        rp[1] = (unsigned int)acc;
++        acc >>= 32;
++
++        acc += rp[2];
++        acc += bp[3 * 2 - 6];
++        acc += bp[4 * 2 - 6];
++        acc += bp[5 * 2 - 6];
++        rp[2] = (unsigned int)acc;
++        acc >>= 32;
++
++        acc += rp[3];
++        acc += bp[3 * 2 - 5];
++        acc += bp[4 * 2 - 5];
++        acc += bp[5 * 2 - 5];
++        rp[3] = (unsigned int)acc;
++        acc >>= 32;
++
++        acc += rp[4];
++        acc += bp[4 * 2 - 6];
++        acc += bp[5 * 2 - 6];
++        rp[4] = (unsigned int)acc;
++        acc >>= 32;
++
++        acc += rp[5];
++        acc += bp[4 * 2 - 5];
++        acc += bp[5 * 2 - 5];
++        rp[5] = (unsigned int)acc;
++
++        carry = (int)(acc >> 32);
++    }
++#else
++    {
++        BN_ULONG t_d[BN_NIST_192_TOP];
++
++        nist_set_192(t_d, buf.bn, 0, 3, 3);
++        carry = (int)bn_add_words(r_d, r_d, t_d, BN_NIST_192_TOP);
++        nist_set_192(t_d, buf.bn, 4, 4, 0);
++        carry += (int)bn_add_words(r_d, r_d, t_d, BN_NIST_192_TOP);
++        nist_set_192(t_d, buf.bn, 5, 5, 5)
++            carry += (int)bn_add_words(r_d, r_d, t_d, BN_NIST_192_TOP);
++    }
++#endif
++    if (carry > 0)
++        carry =
++            (int)bn_sub_words(r_d, r_d, _nist_p_192[carry - 1],
++                              BN_NIST_192_TOP);
++    else
++        carry = 1;
++
++    /*
++     * we need 'if (carry==0 || result>=modulus) result-=modulus;'
++     * as comparison implies subtraction, we can write
++     * 'tmp=result-modulus; if (!carry || !borrow) result=tmp;'
++     * this is what happens below, but without explicit if:-) a.
++     */
++    mask =
++        0 - (PTR_SIZE_INT) bn_sub_words(c_d, r_d, _nist_p_192[0],
++                                        BN_NIST_192_TOP);
++    mask &= 0 - (PTR_SIZE_INT) carry;
++    res = c_d;
++    res = (BN_ULONG *)
++        (((PTR_SIZE_INT) res & ~mask) | ((PTR_SIZE_INT) r_d & mask));
++    nist_cp_bn(r_d, res, BN_NIST_192_TOP);
++    r->top = BN_NIST_192_TOP;
++    bn_correct_top(r);
++
++    return 1;
++}
++
++typedef BN_ULONG (*bn_addsub_f) (BN_ULONG *, const BN_ULONG *,
++                                 const BN_ULONG *, int);
++
++#define nist_set_224(to, from, a1, a2, a3, a4, a5, a6, a7) \
++        { \
++        bn_cp_32(to, 0, from, (a7) - 7) \
++        bn_cp_32(to, 1, from, (a6) - 7) \
++        bn_cp_32(to, 2, from, (a5) - 7) \
++        bn_cp_32(to, 3, from, (a4) - 7) \
++        bn_cp_32(to, 4, from, (a3) - 7) \
++        bn_cp_32(to, 5, from, (a2) - 7) \
++        bn_cp_32(to, 6, from, (a1) - 7) \
++        }
++
++int BN_nist_mod_224(BIGNUM *r, const BIGNUM *a, const BIGNUM *field,
++                    BN_CTX *ctx)
++{
++    int top = a->top, i;
++    int carry;
++    BN_ULONG *r_d, *a_d = a->d;
++    union {
++        BN_ULONG bn[BN_NIST_224_TOP];
++        unsigned int ui[BN_NIST_224_TOP * sizeof(BN_ULONG) /
++                        sizeof(unsigned int)];
++    } buf;
++    BN_ULONG c_d[BN_NIST_224_TOP], *res;
++    PTR_SIZE_INT mask;
++    union {
++        bn_addsub_f f;
++        PTR_SIZE_INT p;
++    } u;
++    static const BIGNUM _bignum_nist_p_224_sqr = {
++        (BN_ULONG *)_nist_p_224_sqr,
++        OSSL_NELEM(_nist_p_224_sqr),
++        OSSL_NELEM(_nist_p_224_sqr),
++        0, BN_FLG_STATIC_DATA
++    };
++
++    field = &_bignum_nist_p_224; /* just to make sure */
++
++    if (BN_is_negative(a) || BN_ucmp(a, &_bignum_nist_p_224_sqr) >= 0)
++        return BN_nnmod(r, a, field, ctx);
++
++    i = BN_ucmp(field, a);
++    if (i == 0) {
++        BN_zero(r);
++        return 1;
++    } else if (i > 0)
++        return (r == a) ? 1 : (BN_copy(r, a) != NULL);
++
++    if (r != a) {
++        if (!bn_wexpand(r, BN_NIST_224_TOP))
++            return 0;
++        r_d = r->d;
++        nist_cp_bn(r_d, a_d, BN_NIST_224_TOP);
++    } else
++        r_d = a_d;
++
++#if BN_BITS2==64
++    /* copy upper 256 bits of 448 bit number ... */
++    nist_cp_bn_0(c_d, a_d + (BN_NIST_224_TOP - 1),
++                 top - (BN_NIST_224_TOP - 1), BN_NIST_224_TOP);
++    /* ... and right shift by 32 to obtain upper 224 bits */
++    nist_set_224(buf.bn, c_d, 14, 13, 12, 11, 10, 9, 8);
++    /* truncate lower part to 224 bits too */
++    r_d[BN_NIST_224_TOP - 1] &= BN_MASK2l;
++#else
++    nist_cp_bn_0(buf.bn, a_d + BN_NIST_224_TOP, top - BN_NIST_224_TOP,
++                 BN_NIST_224_TOP);
++#endif
++
++#if defined(NIST_INT64) && BN_BITS2!=64
++    {
++        NIST_INT64 acc;         /* accumulator */
++        unsigned int *rp = (unsigned int *)r_d;
++        const unsigned int *bp = (const unsigned int *)buf.ui;
++
++        acc = rp[0];
++        acc -= bp[7 - 7];
++        acc -= bp[11 - 7];
++        rp[0] = (unsigned int)acc;
++        acc >>= 32;
++
++        acc += rp[1];
++        acc -= bp[8 - 7];
++        acc -= bp[12 - 7];
++        rp[1] = (unsigned int)acc;
++        acc >>= 32;
++
++        acc += rp[2];
++        acc -= bp[9 - 7];
++        acc -= bp[13 - 7];
++        rp[2] = (unsigned int)acc;
++        acc >>= 32;
++
++        acc += rp[3];
++        acc += bp[7 - 7];
++        acc += bp[11 - 7];
++        acc -= bp[10 - 7];
++        rp[3] = (unsigned int)acc;
++        acc >>= 32;
++
++        acc += rp[4];
++        acc += bp[8 - 7];
++        acc += bp[12 - 7];
++        acc -= bp[11 - 7];
++        rp[4] = (unsigned int)acc;
++        acc >>= 32;
++
++        acc += rp[5];
++        acc += bp[9 - 7];
++        acc += bp[13 - 7];
++        acc -= bp[12 - 7];
++        rp[5] = (unsigned int)acc;
++        acc >>= 32;
++
++        acc += rp[6];
++        acc += bp[10 - 7];
++        acc -= bp[13 - 7];
++        rp[6] = (unsigned int)acc;
++
++        carry = (int)(acc >> 32);
++# if BN_BITS2==64
++        rp[7] = carry;
++# endif
++    }
++#else
++    {
++        BN_ULONG t_d[BN_NIST_224_TOP];
++
++        nist_set_224(t_d, buf.bn, 10, 9, 8, 7, 0, 0, 0);
++        carry = (int)bn_add_words(r_d, r_d, t_d, BN_NIST_224_TOP);
++        nist_set_224(t_d, buf.bn, 0, 13, 12, 11, 0, 0, 0);
++        carry += (int)bn_add_words(r_d, r_d, t_d, BN_NIST_224_TOP);
++        nist_set_224(t_d, buf.bn, 13, 12, 11, 10, 9, 8, 7);
++        carry -= (int)bn_sub_words(r_d, r_d, t_d, BN_NIST_224_TOP);
++        nist_set_224(t_d, buf.bn, 0, 0, 0, 0, 13, 12, 11);
++        carry -= (int)bn_sub_words(r_d, r_d, t_d, BN_NIST_224_TOP);
++
++# if BN_BITS2==64
++        carry = (int)(r_d[BN_NIST_224_TOP - 1] >> 32);
++# endif
++    }
++#endif
++    u.f = bn_sub_words;
++    if (carry > 0) {
++        carry =
++            (int)bn_sub_words(r_d, r_d, _nist_p_224[carry - 1],
++                              BN_NIST_224_TOP);
++#if BN_BITS2==64
++        carry = (int)(~(r_d[BN_NIST_224_TOP - 1] >> 32)) & 1;
++#endif
++    } else if (carry < 0) {
++        /*
++         * it's a bit more complicated logic in this case. if bn_add_words
++         * yields no carry, then result has to be adjusted by unconditionally
++         * *adding* the modulus. but if it does, then result has to be
++         * compared to the modulus and conditionally adjusted by
++         * *subtracting* the latter.
++         */
++        carry =
++            (int)bn_add_words(r_d, r_d, _nist_p_224[-carry - 1],
++                              BN_NIST_224_TOP);
++        mask = 0 - (PTR_SIZE_INT) carry;
++        u.p = ((PTR_SIZE_INT) bn_sub_words & mask) |
++            ((PTR_SIZE_INT) bn_add_words & ~mask);
++    } else
++        carry = 1;
++
++    /* otherwise it's effectively same as in BN_nist_mod_192... */
++    mask =
++        0 - (PTR_SIZE_INT) (*u.f) (c_d, r_d, _nist_p_224[0], BN_NIST_224_TOP);
++    mask &= 0 - (PTR_SIZE_INT) carry;
++    res = c_d;
++    res = (BN_ULONG *)(((PTR_SIZE_INT) res & ~mask) |
++                       ((PTR_SIZE_INT) r_d & mask));
++    nist_cp_bn(r_d, res, BN_NIST_224_TOP);
++    r->top = BN_NIST_224_TOP;
++    bn_correct_top(r);
++
++    return 1;
++}
++
++#define nist_set_256(to, from, a1, a2, a3, a4, a5, a6, a7, a8) \
++        { \
++        bn_cp_32(to, 0, from, (a8) - 8) \
++        bn_cp_32(to, 1, from, (a7) - 8) \
++        bn_cp_32(to, 2, from, (a6) - 8) \
++        bn_cp_32(to, 3, from, (a5) - 8) \
++        bn_cp_32(to, 4, from, (a4) - 8) \
++        bn_cp_32(to, 5, from, (a3) - 8) \
++        bn_cp_32(to, 6, from, (a2) - 8) \
++        bn_cp_32(to, 7, from, (a1) - 8) \
++        }
++
++int BN_nist_mod_256(BIGNUM *r, const BIGNUM *a, const BIGNUM *field,
++                    BN_CTX *ctx)
++{
++    int i, top = a->top;
++    int carry = 0;
++    register BN_ULONG *a_d = a->d, *r_d;
++    union {
++        BN_ULONG bn[BN_NIST_256_TOP];
++        unsigned int ui[BN_NIST_256_TOP * sizeof(BN_ULONG) /
++                        sizeof(unsigned int)];
++    } buf;
++    BN_ULONG c_d[BN_NIST_256_TOP], *res;
++    PTR_SIZE_INT mask;
++    union {
++        bn_addsub_f f;
++        PTR_SIZE_INT p;
++    } u;
++    static const BIGNUM _bignum_nist_p_256_sqr = {
++        (BN_ULONG *)_nist_p_256_sqr,
++        OSSL_NELEM(_nist_p_256_sqr),
++        OSSL_NELEM(_nist_p_256_sqr),
++        0, BN_FLG_STATIC_DATA
++    };
++
++    field = &_bignum_nist_p_256; /* just to make sure */
++
++    if (BN_is_negative(a) || BN_ucmp(a, &_bignum_nist_p_256_sqr) >= 0)
++        return BN_nnmod(r, a, field, ctx);
++
++    i = BN_ucmp(field, a);
++    if (i == 0) {
++        BN_zero(r);
++        return 1;
++    } else if (i > 0)
++        return (r == a) ? 1 : (BN_copy(r, a) != NULL);
++
++    if (r != a) {
++        if (!bn_wexpand(r, BN_NIST_256_TOP))
++            return 0;
++        r_d = r->d;
++        nist_cp_bn(r_d, a_d, BN_NIST_256_TOP);
++    } else
++        r_d = a_d;
++
++    nist_cp_bn_0(buf.bn, a_d + BN_NIST_256_TOP, top - BN_NIST_256_TOP,
++                 BN_NIST_256_TOP);
++
++#if defined(NIST_INT64)
++    {
++        NIST_INT64 acc;         /* accumulator */
++        unsigned int *rp = (unsigned int *)r_d;
++        const unsigned int *bp = (const unsigned int *)buf.ui;
++
++        acc = rp[0];
++        acc += bp[8 - 8];
++        acc += bp[9 - 8];
++        acc -= bp[11 - 8];
++        acc -= bp[12 - 8];
++        acc -= bp[13 - 8];
++        acc -= bp[14 - 8];
++        rp[0] = (unsigned int)acc;
++        acc >>= 32;
++
++        acc += rp[1];
++        acc += bp[9 - 8];
++        acc += bp[10 - 8];
++        acc -= bp[12 - 8];
++        acc -= bp[13 - 8];
++        acc -= bp[14 - 8];
++        acc -= bp[15 - 8];
++        rp[1] = (unsigned int)acc;
++        acc >>= 32;
++
++        acc += rp[2];
++        acc += bp[10 - 8];
++        acc += bp[11 - 8];
++        acc -= bp[13 - 8];
++        acc -= bp[14 - 8];
++        acc -= bp[15 - 8];
++        rp[2] = (unsigned int)acc;
++        acc >>= 32;
++
++        acc += rp[3];
++        acc += bp[11 - 8];
++        acc += bp[11 - 8];
++        acc += bp[12 - 8];
++        acc += bp[12 - 8];
++        acc += bp[13 - 8];
++        acc -= bp[15 - 8];
++        acc -= bp[8 - 8];
++        acc -= bp[9 - 8];
++        rp[3] = (unsigned int)acc;
++        acc >>= 32;
++
++        acc += rp[4];
++        acc += bp[12 - 8];
++        acc += bp[12 - 8];
++        acc += bp[13 - 8];
++        acc += bp[13 - 8];
++        acc += bp[14 - 8];
++        acc -= bp[9 - 8];
++        acc -= bp[10 - 8];
++        rp[4] = (unsigned int)acc;
++        acc >>= 32;
++
++        acc += rp[5];
++        acc += bp[13 - 8];
++        acc += bp[13 - 8];
++        acc += bp[14 - 8];
++        acc += bp[14 - 8];
++        acc += bp[15 - 8];
++        acc -= bp[10 - 8];
++        acc -= bp[11 - 8];
++        rp[5] = (unsigned int)acc;
++        acc >>= 32;
++
++        acc += rp[6];
++        acc += bp[14 - 8];
++        acc += bp[14 - 8];
++        acc += bp[15 - 8];
++        acc += bp[15 - 8];
++        acc += bp[14 - 8];
++        acc += bp[13 - 8];
++        acc -= bp[8 - 8];
++        acc -= bp[9 - 8];
++        rp[6] = (unsigned int)acc;
++        acc >>= 32;
++
++        acc += rp[7];
++        acc += bp[15 - 8];
++        acc += bp[15 - 8];
++        acc += bp[15 - 8];
++        acc += bp[8 - 8];
++        acc -= bp[10 - 8];
++        acc -= bp[11 - 8];
++        acc -= bp[12 - 8];
++        acc -= bp[13 - 8];
++        rp[7] = (unsigned int)acc;
++
++        carry = (int)(acc >> 32);
++    }
++#else
++    {
++        BN_ULONG t_d[BN_NIST_256_TOP];
++
++        /*
++         * S1
++         */
++        nist_set_256(t_d, buf.bn, 15, 14, 13, 12, 11, 0, 0, 0);
++        /*
++         * S2
++         */
++        nist_set_256(c_d, buf.bn, 0, 15, 14, 13, 12, 0, 0, 0);
++        carry = (int)bn_add_words(t_d, t_d, c_d, BN_NIST_256_TOP);
++        /* left shift */
++        {
++            register BN_ULONG *ap, t, c;
++            ap = t_d;
++            c = 0;
++            for (i = BN_NIST_256_TOP; i != 0; --i) {
++                t = *ap;
++                *(ap++) = ((t << 1) | c) & BN_MASK2;
++                c = (t & BN_TBIT) ? 1 : 0;
++            }
++            carry <<= 1;
++            carry |= c;
++        }
++        carry += (int)bn_add_words(r_d, r_d, t_d, BN_NIST_256_TOP);
++        /*
++         * S3
++         */
++        nist_set_256(t_d, buf.bn, 15, 14, 0, 0, 0, 10, 9, 8);
++        carry += (int)bn_add_words(r_d, r_d, t_d, BN_NIST_256_TOP);
++        /*
++         * S4
++         */
++        nist_set_256(t_d, buf.bn, 8, 13, 15, 14, 13, 11, 10, 9);
++        carry += (int)bn_add_words(r_d, r_d, t_d, BN_NIST_256_TOP);
++        /*
++         * D1
++         */
++        nist_set_256(t_d, buf.bn, 10, 8, 0, 0, 0, 13, 12, 11);
++        carry -= (int)bn_sub_words(r_d, r_d, t_d, BN_NIST_256_TOP);
++        /*
++         * D2
++         */
++        nist_set_256(t_d, buf.bn, 11, 9, 0, 0, 15, 14, 13, 12);
++        carry -= (int)bn_sub_words(r_d, r_d, t_d, BN_NIST_256_TOP);
++        /*
++         * D3
++         */
++        nist_set_256(t_d, buf.bn, 12, 0, 10, 9, 8, 15, 14, 13);
++        carry -= (int)bn_sub_words(r_d, r_d, t_d, BN_NIST_256_TOP);
++        /*
++         * D4
++         */
++        nist_set_256(t_d, buf.bn, 13, 0, 11, 10, 9, 0, 15, 14);
++        carry -= (int)bn_sub_words(r_d, r_d, t_d, BN_NIST_256_TOP);
++
++    }
++#endif
++    /* see BN_nist_mod_224 for explanation */
++    u.f = bn_sub_words;
++    if (carry > 0)
++        carry =
++            (int)bn_sub_words(r_d, r_d, _nist_p_256[carry - 1],
++                              BN_NIST_256_TOP);
++    else if (carry < 0) {
++        carry =
++            (int)bn_add_words(r_d, r_d, _nist_p_256[-carry - 1],
++                              BN_NIST_256_TOP);
++        mask = 0 - (PTR_SIZE_INT) carry;
++        u.p = ((PTR_SIZE_INT) bn_sub_words & mask) |
++            ((PTR_SIZE_INT) bn_add_words & ~mask);
++    } else
++        carry = 1;
++
++    mask =
++        0 - (PTR_SIZE_INT) (*u.f) (c_d, r_d, _nist_p_256[0], BN_NIST_256_TOP);
++    mask &= 0 - (PTR_SIZE_INT) carry;
++    res = c_d;
++    res = (BN_ULONG *)(((PTR_SIZE_INT) res & ~mask) |
++                       ((PTR_SIZE_INT) r_d & mask));
++    nist_cp_bn(r_d, res, BN_NIST_256_TOP);
++    r->top = BN_NIST_256_TOP;
++    bn_correct_top(r);
++
++    return 1;
++}
++
++#define nist_set_384(to,from,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12) \
++        { \
++        bn_cp_32(to, 0, from,  (a12) - 12) \
++        bn_cp_32(to, 1, from,  (a11) - 12) \
++        bn_cp_32(to, 2, from,  (a10) - 12) \
++        bn_cp_32(to, 3, from,  (a9) - 12)  \
++        bn_cp_32(to, 4, from,  (a8) - 12)  \
++        bn_cp_32(to, 5, from,  (a7) - 12)  \
++        bn_cp_32(to, 6, from,  (a6) - 12)  \
++        bn_cp_32(to, 7, from,  (a5) - 12)  \
++        bn_cp_32(to, 8, from,  (a4) - 12)  \
++        bn_cp_32(to, 9, from,  (a3) - 12)  \
++        bn_cp_32(to, 10, from, (a2) - 12)  \
++        bn_cp_32(to, 11, from, (a1) - 12)  \
++        }
++
++int BN_nist_mod_384(BIGNUM *r, const BIGNUM *a, const BIGNUM *field,
++                    BN_CTX *ctx)
++{
++    int i, top = a->top;
++    int carry = 0;
++    register BN_ULONG *r_d, *a_d = a->d;
++    union {
++        BN_ULONG bn[BN_NIST_384_TOP];
++        unsigned int ui[BN_NIST_384_TOP * sizeof(BN_ULONG) /
++                        sizeof(unsigned int)];
++    } buf;
++    BN_ULONG c_d[BN_NIST_384_TOP], *res;
++    PTR_SIZE_INT mask;
++    union {
++        bn_addsub_f f;
++        PTR_SIZE_INT p;
++    } u;
++    static const BIGNUM _bignum_nist_p_384_sqr = {
++        (BN_ULONG *)_nist_p_384_sqr,
++        OSSL_NELEM(_nist_p_384_sqr),
++        OSSL_NELEM(_nist_p_384_sqr),
++        0, BN_FLG_STATIC_DATA
++    };
++
++    field = &_bignum_nist_p_384; /* just to make sure */
++
++    if (BN_is_negative(a) || BN_ucmp(a, &_bignum_nist_p_384_sqr) >= 0)
++        return BN_nnmod(r, a, field, ctx);
++
++    i = BN_ucmp(field, a);
++    if (i == 0) {
++        BN_zero(r);
++        return 1;
++    } else if (i > 0)
++        return (r == a) ? 1 : (BN_copy(r, a) != NULL);
++
++    if (r != a) {
++        if (!bn_wexpand(r, BN_NIST_384_TOP))
++            return 0;
++        r_d = r->d;
++        nist_cp_bn(r_d, a_d, BN_NIST_384_TOP);
++    } else
++        r_d = a_d;
++
++    nist_cp_bn_0(buf.bn, a_d + BN_NIST_384_TOP, top - BN_NIST_384_TOP,
++                 BN_NIST_384_TOP);
++
++#if defined(NIST_INT64)
++    {
++        NIST_INT64 acc;         /* accumulator */
++        unsigned int *rp = (unsigned int *)r_d;
++        const unsigned int *bp = (const unsigned int *)buf.ui;
++
++        acc = rp[0];
++        acc += bp[12 - 12];
++        acc += bp[21 - 12];
++        acc += bp[20 - 12];
++        acc -= bp[23 - 12];
++        rp[0] = (unsigned int)acc;
++        acc >>= 32;
++
++        acc += rp[1];
++        acc += bp[13 - 12];
++        acc += bp[22 - 12];
++        acc += bp[23 - 12];
++        acc -= bp[12 - 12];
++        acc -= bp[20 - 12];
++        rp[1] = (unsigned int)acc;
++        acc >>= 32;
++
++        acc += rp[2];
++        acc += bp[14 - 12];
++        acc += bp[23 - 12];
++        acc -= bp[13 - 12];
++        acc -= bp[21 - 12];
++        rp[2] = (unsigned int)acc;
++        acc >>= 32;
++
++        acc += rp[3];
++        acc += bp[15 - 12];
++        acc += bp[12 - 12];
++        acc += bp[20 - 12];
++        acc += bp[21 - 12];
++        acc -= bp[14 - 12];
++        acc -= bp[22 - 12];
++        acc -= bp[23 - 12];
++        rp[3] = (unsigned int)acc;
++        acc >>= 32;
++
++        acc += rp[4];
++        acc += bp[21 - 12];
++        acc += bp[21 - 12];
++        acc += bp[16 - 12];
++        acc += bp[13 - 12];
++        acc += bp[12 - 12];
++        acc += bp[20 - 12];
++        acc += bp[22 - 12];
++        acc -= bp[15 - 12];
++        acc -= bp[23 - 12];
++        acc -= bp[23 - 12];
++        rp[4] = (unsigned int)acc;
++        acc >>= 32;
++
++        acc += rp[5];
++        acc += bp[22 - 12];
++        acc += bp[22 - 12];
++        acc += bp[17 - 12];
++        acc += bp[14 - 12];
++        acc += bp[13 - 12];
++        acc += bp[21 - 12];
++        acc += bp[23 - 12];
++        acc -= bp[16 - 12];
++        rp[5] = (unsigned int)acc;
++        acc >>= 32;
++
++        acc += rp[6];
++        acc += bp[23 - 12];
++        acc += bp[23 - 12];
++        acc += bp[18 - 12];
++        acc += bp[15 - 12];
++        acc += bp[14 - 12];
++        acc += bp[22 - 12];
++        acc -= bp[17 - 12];
++        rp[6] = (unsigned int)acc;
++        acc >>= 32;
++
++        acc += rp[7];
++        acc += bp[19 - 12];
++        acc += bp[16 - 12];
++        acc += bp[15 - 12];
++        acc += bp[23 - 12];
++        acc -= bp[18 - 12];
++        rp[7] = (unsigned int)acc;
++        acc >>= 32;
++
++        acc += rp[8];
++        acc += bp[20 - 12];
++        acc += bp[17 - 12];
++        acc += bp[16 - 12];
++        acc -= bp[19 - 12];
++        rp[8] = (unsigned int)acc;
++        acc >>= 32;
++
++        acc += rp[9];
++        acc += bp[21 - 12];
++        acc += bp[18 - 12];
++        acc += bp[17 - 12];
++        acc -= bp[20 - 12];
++        rp[9] = (unsigned int)acc;
++        acc >>= 32;
++
++        acc += rp[10];
++        acc += bp[22 - 12];
++        acc += bp[19 - 12];
++        acc += bp[18 - 12];
++        acc -= bp[21 - 12];
++        rp[10] = (unsigned int)acc;
++        acc >>= 32;
++
++        acc += rp[11];
++        acc += bp[23 - 12];
++        acc += bp[20 - 12];
++        acc += bp[19 - 12];
++        acc -= bp[22 - 12];
++        rp[11] = (unsigned int)acc;
++
++        carry = (int)(acc >> 32);
++    }
++#else
++    {
++        BN_ULONG t_d[BN_NIST_384_TOP];
++
++        /*
++         * S1
++         */
++        nist_set_256(t_d, buf.bn, 0, 0, 0, 0, 0, 23 - 4, 22 - 4, 21 - 4);
++        /* left shift */
++        {
++            register BN_ULONG *ap, t, c;
++            ap = t_d;
++            c = 0;
++            for (i = 3; i != 0; --i) {
++                t = *ap;
++                *(ap++) = ((t << 1) | c) & BN_MASK2;
++                c = (t & BN_TBIT) ? 1 : 0;
++            }
++            *ap = c;
++        }
++        carry =
++            (int)bn_add_words(r_d + (128 / BN_BITS2), r_d + (128 / BN_BITS2),
++                              t_d, BN_NIST_256_TOP);
++        /*
++         * S2
++         */
++        carry += (int)bn_add_words(r_d, r_d, buf.bn, BN_NIST_384_TOP);
++        /*
++         * S3
++         */
++        nist_set_384(t_d, buf.bn, 20, 19, 18, 17, 16, 15, 14, 13, 12, 23, 22,
++                     21);
++        carry += (int)bn_add_words(r_d, r_d, t_d, BN_NIST_384_TOP);
++        /*
++         * S4
++         */
++        nist_set_384(t_d, buf.bn, 19, 18, 17, 16, 15, 14, 13, 12, 20, 0, 23,
++                     0);
++        carry += (int)bn_add_words(r_d, r_d, t_d, BN_NIST_384_TOP);
++        /*
++         * S5
++         */
++        nist_set_384(t_d, buf.bn, 0, 0, 0, 0, 23, 22, 21, 20, 0, 0, 0, 0);
++        carry += (int)bn_add_words(r_d, r_d, t_d, BN_NIST_384_TOP);
++        /*
++         * S6
++         */
++        nist_set_384(t_d, buf.bn, 0, 0, 0, 0, 0, 0, 23, 22, 21, 0, 0, 20);
++        carry += (int)bn_add_words(r_d, r_d, t_d, BN_NIST_384_TOP);
++        /*
++         * D1
++         */
++        nist_set_384(t_d, buf.bn, 22, 21, 20, 19, 18, 17, 16, 15, 14, 13, 12,
++                     23);
++        carry -= (int)bn_sub_words(r_d, r_d, t_d, BN_NIST_384_TOP);
++        /*
++         * D2
++         */
++        nist_set_384(t_d, buf.bn, 0, 0, 0, 0, 0, 0, 0, 23, 22, 21, 20, 0);
++        carry -= (int)bn_sub_words(r_d, r_d, t_d, BN_NIST_384_TOP);
++        /*
++         * D3
++         */
++        nist_set_384(t_d, buf.bn, 0, 0, 0, 0, 0, 0, 0, 23, 23, 0, 0, 0);
++        carry -= (int)bn_sub_words(r_d, r_d, t_d, BN_NIST_384_TOP);
++
++    }
++#endif
++    /* see BN_nist_mod_224 for explanation */
++    u.f = bn_sub_words;
++    if (carry > 0)
++        carry =
++            (int)bn_sub_words(r_d, r_d, _nist_p_384[carry - 1],
++                              BN_NIST_384_TOP);
++    else if (carry < 0) {
++        carry =
++            (int)bn_add_words(r_d, r_d, _nist_p_384[-carry - 1],
++                              BN_NIST_384_TOP);
++        mask = 0 - (PTR_SIZE_INT) carry;
++        u.p = ((PTR_SIZE_INT) bn_sub_words & mask) |
++            ((PTR_SIZE_INT) bn_add_words & ~mask);
++    } else
++        carry = 1;
++
++    mask =
++        0 - (PTR_SIZE_INT) (*u.f) (c_d, r_d, _nist_p_384[0], BN_NIST_384_TOP);
++    mask &= 0 - (PTR_SIZE_INT) carry;
++    res = c_d;
++    res = (BN_ULONG *)(((PTR_SIZE_INT) res & ~mask) |
++                       ((PTR_SIZE_INT) r_d & mask));
++    nist_cp_bn(r_d, res, BN_NIST_384_TOP);
++    r->top = BN_NIST_384_TOP;
++    bn_correct_top(r);
++
++    return 1;
++}
++
++#define BN_NIST_521_RSHIFT      (521%BN_BITS2)
++#define BN_NIST_521_LSHIFT      (BN_BITS2-BN_NIST_521_RSHIFT)
++#define BN_NIST_521_TOP_MASK    ((BN_ULONG)BN_MASK2>>BN_NIST_521_LSHIFT)
++
++int BN_nist_mod_521(BIGNUM *r, const BIGNUM *a, const BIGNUM *field,
++                    BN_CTX *ctx)
++{
++    int top = a->top, i;
++    BN_ULONG *r_d, *a_d = a->d, t_d[BN_NIST_521_TOP], val, tmp, *res;
++    PTR_SIZE_INT mask;
++    static const BIGNUM _bignum_nist_p_521_sqr = {
++        (BN_ULONG *)_nist_p_521_sqr,
++        OSSL_NELEM(_nist_p_521_sqr),
++        OSSL_NELEM(_nist_p_521_sqr),
++        0, BN_FLG_STATIC_DATA
++    };
++
++    field = &_bignum_nist_p_521; /* just to make sure */
++
++    if (BN_is_negative(a) || BN_ucmp(a, &_bignum_nist_p_521_sqr) >= 0)
++        return BN_nnmod(r, a, field, ctx);
++
++    i = BN_ucmp(field, a);
++    if (i == 0) {
++        BN_zero(r);
++        return 1;
++    } else if (i > 0)
++        return (r == a) ? 1 : (BN_copy(r, a) != NULL);
++
++    if (r != a) {
++        if (!bn_wexpand(r, BN_NIST_521_TOP))
++            return 0;
++        r_d = r->d;
++        nist_cp_bn(r_d, a_d, BN_NIST_521_TOP);
++    } else
++        r_d = a_d;
++
++    /* upper 521 bits, copy ... */
++    nist_cp_bn_0(t_d, a_d + (BN_NIST_521_TOP - 1),
++                 top - (BN_NIST_521_TOP - 1), BN_NIST_521_TOP);
++    /* ... and right shift */
++    for (val = t_d[0], i = 0; i < BN_NIST_521_TOP - 1; i++) {
++#if 0
++        /*
++         * MSC ARM compiler [version 2013, presumably even earlier,
++         * much earlier] miscompiles this code, but not one in
++         * #else section. See RT#3541.
++         */
++        tmp = val >> BN_NIST_521_RSHIFT;
++        val = t_d[i + 1];
++        t_d[i] = (tmp | val << BN_NIST_521_LSHIFT) & BN_MASK2;
++#else
++        t_d[i] = (val >> BN_NIST_521_RSHIFT |
++                  (tmp = t_d[i + 1]) << BN_NIST_521_LSHIFT) & BN_MASK2;
++        val = tmp;
++#endif
++    }
++    t_d[i] = val >> BN_NIST_521_RSHIFT;
++    /* lower 521 bits */
++    r_d[i] &= BN_NIST_521_TOP_MASK;
++
++    bn_add_words(r_d, r_d, t_d, BN_NIST_521_TOP);
++    mask =
++        0 - (PTR_SIZE_INT) bn_sub_words(t_d, r_d, _nist_p_521,
++                                        BN_NIST_521_TOP);
++    res = t_d;
++    res = (BN_ULONG *)(((PTR_SIZE_INT) res & ~mask) |
++                       ((PTR_SIZE_INT) r_d & mask));
++    nist_cp_bn(r_d, res, BN_NIST_521_TOP);
++    r->top = BN_NIST_521_TOP;
++    bn_correct_top(r);
++
++    return 1;
++}
++
++int (*BN_nist_mod_func(const BIGNUM *p)) (BIGNUM *r, const BIGNUM *a,
++                                          const BIGNUM *field, BN_CTX *ctx) {
++    if (BN_ucmp(&_bignum_nist_p_192, p) == 0)
++        return BN_nist_mod_192;
++    if (BN_ucmp(&_bignum_nist_p_224, p) == 0)
++        return BN_nist_mod_224;
++    if (BN_ucmp(&_bignum_nist_p_256, p) == 0)
++        return BN_nist_mod_256;
++    if (BN_ucmp(&_bignum_nist_p_384, p) == 0)
++        return BN_nist_mod_384;
++    if (BN_ucmp(&_bignum_nist_p_521, p) == 0)
++        return BN_nist_mod_521;
++    return 0;
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/bn/bn_prime.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/bn/bn_prime.c
+new file mode 100644
+index 0000000..7103acf
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/bn/bn_prime.c
+@@ -0,0 +1,608 @@
++/*
++ * WARNING: do not edit!
++ * Generated by crypto/bn/bn_prime.pl
++ * Copyright 1995-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include 
++#include "internal/cryptlib.h"
++#include "bn_lcl.h"
++
++/*
++ * The quick sieve algorithm approach to weeding out primes is Philip
++ * Zimmermann's, as implemented in PGP.  I have had a read of his comments
++ * and implemented my own version.
++ */
++#include "bn_prime.h"
++
++static int witness(BIGNUM *w, const BIGNUM *a, const BIGNUM *a1,
++                   const BIGNUM *a1_odd, int k, BN_CTX *ctx,
++                   BN_MONT_CTX *mont);
++static int probable_prime(BIGNUM *rnd, int bits, prime_t *mods);
++static int probable_prime_dh_safe(BIGNUM *rnd, int bits,
++                                  const BIGNUM *add, const BIGNUM *rem,
++                                  BN_CTX *ctx);
++
++static const int prime_offsets[480] = {
++    13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83,
++    89, 97, 101, 103, 107, 109, 113, 127, 131, 137, 139, 149, 151, 157, 163,
++    167, 169, 173, 179, 181, 191, 193, 197, 199, 211, 221, 223, 227, 229,
++    233, 239, 241, 247, 251, 257, 263, 269, 271, 277, 281, 283, 289, 293,
++    299, 307, 311, 313, 317, 323, 331, 337, 347, 349, 353, 359, 361, 367,
++    373, 377, 379, 383, 389, 391, 397, 401, 403, 409, 419, 421, 431, 433,
++    437, 439, 443, 449, 457, 461, 463, 467, 479, 481, 487, 491, 493, 499,
++    503, 509, 521, 523, 527, 529, 533, 541, 547, 551, 557, 559, 563, 569,
++    571, 577, 587, 589, 593, 599, 601, 607, 611, 613, 617, 619, 629, 631,
++    641, 643, 647, 653, 659, 661, 667, 673, 677, 683, 689, 691, 697, 701,
++    703, 709, 713, 719, 727, 731, 733, 739, 743, 751, 757, 761, 767, 769,
++    773, 779, 787, 793, 797, 799, 809, 811, 817, 821, 823, 827, 829, 839,
++    841, 851, 853, 857, 859, 863, 871, 877, 881, 883, 887, 893, 899, 901,
++    907, 911, 919, 923, 929, 937, 941, 943, 947, 949, 953, 961, 967, 971,
++    977, 983, 989, 991, 997, 1003, 1007, 1009, 1013, 1019, 1021, 1027, 1031,
++    1033, 1037, 1039, 1049, 1051, 1061, 1063, 1069, 1073, 1079, 1081, 1087,
++    1091, 1093, 1097, 1103, 1109, 1117, 1121, 1123, 1129, 1139, 1147, 1151,
++    1153, 1157, 1159, 1163, 1171, 1181, 1187, 1189, 1193, 1201, 1207, 1213,
++    1217, 1219, 1223, 1229, 1231, 1237, 1241, 1247, 1249, 1259, 1261, 1271,
++    1273, 1277, 1279, 1283, 1289, 1291, 1297, 1301, 1303, 1307, 1313, 1319,
++    1321, 1327, 1333, 1339, 1343, 1349, 1357, 1361, 1363, 1367, 1369, 1373,
++    1381, 1387, 1391, 1399, 1403, 1409, 1411, 1417, 1423, 1427, 1429, 1433,
++    1439, 1447, 1451, 1453, 1457, 1459, 1469, 1471, 1481, 1483, 1487, 1489,
++    1493, 1499, 1501, 1511, 1513, 1517, 1523, 1531, 1537, 1541, 1543, 1549,
++    1553, 1559, 1567, 1571, 1577, 1579, 1583, 1591, 1597, 1601, 1607, 1609,
++    1613, 1619, 1621, 1627, 1633, 1637, 1643, 1649, 1651, 1657, 1663, 1667,
++    1669, 1679, 1681, 1691, 1693, 1697, 1699, 1703, 1709, 1711, 1717, 1721,
++    1723, 1733, 1739, 1741, 1747, 1751, 1753, 1759, 1763, 1769, 1777, 1781,
++    1783, 1787, 1789, 1801, 1807, 1811, 1817, 1819, 1823, 1829, 1831, 1843,
++    1847, 1849, 1853, 1861, 1867, 1871, 1873, 1877, 1879, 1889, 1891, 1901,
++    1907, 1909, 1913, 1919, 1921, 1927, 1931, 1933, 1937, 1943, 1949, 1951,
++    1957, 1961, 1963, 1973, 1979, 1987, 1993, 1997, 1999, 2003, 2011, 2017,
++    2021, 2027, 2029, 2033, 2039, 2041, 2047, 2053, 2059, 2063, 2069, 2071,
++    2077, 2081, 2083, 2087, 2089, 2099, 2111, 2113, 2117, 2119, 2129, 2131,
++    2137, 2141, 2143, 2147, 2153, 2159, 2161, 2171, 2173, 2179, 2183, 2197,
++    2201, 2203, 2207, 2209, 2213, 2221, 2227, 2231, 2237, 2239, 2243, 2249,
++    2251, 2257, 2263, 2267, 2269, 2273, 2279, 2281, 2287, 2291, 2293, 2297,
++    2309, 2311
++};
++
++static const int prime_offset_count = 480;
++static const int prime_multiplier = 2310;
++static const int prime_multiplier_bits = 11; /* 2^|prime_multiplier_bits| <=
++                                              * |prime_multiplier| */
++static const int first_prime_index = 5;
++
++int BN_GENCB_call(BN_GENCB *cb, int a, int b)
++{
++    /* No callback means continue */
++    if (!cb)
++        return 1;
++    switch (cb->ver) {
++    case 1:
++        /* Deprecated-style callbacks */
++        if (!cb->cb.cb_1)
++            return 1;
++        cb->cb.cb_1(a, b, cb->arg);
++        return 1;
++    case 2:
++        /* New-style callbacks */
++        return cb->cb.cb_2(a, b, cb);
++    default:
++        break;
++    }
++    /* Unrecognised callback type */
++    return 0;
++}
++
++int BN_generate_prime_ex(BIGNUM *ret, int bits, int safe,
++                         const BIGNUM *add, const BIGNUM *rem, BN_GENCB *cb)
++{
++    BIGNUM *t;
++    int found = 0;
++    int i, j, c1 = 0;
++    BN_CTX *ctx = NULL;
++    prime_t *mods = NULL;
++    int checks = BN_prime_checks_for_size(bits);
++
++    if (bits < 2) {
++        /* There are no prime numbers this small. */
++        BNerr(BN_F_BN_GENERATE_PRIME_EX, BN_R_BITS_TOO_SMALL);
++        return 0;
++    } else if (bits == 2 && safe) {
++        /* The smallest safe prime (7) is three bits. */
++        BNerr(BN_F_BN_GENERATE_PRIME_EX, BN_R_BITS_TOO_SMALL);
++        return 0;
++    }
++
++    mods = OPENSSL_zalloc(sizeof(*mods) * NUMPRIMES);
++    if (mods == NULL)
++        goto err;
++
++    ctx = BN_CTX_new();
++    if (ctx == NULL)
++        goto err;
++    BN_CTX_start(ctx);
++    t = BN_CTX_get(ctx);
++    if (!t)
++        goto err;
++ loop:
++    /* make a random number and set the top and bottom bits */
++    if (add == NULL) {
++        if (!probable_prime(ret, bits, mods))
++            goto err;
++    } else {
++        if (safe) {
++            if (!probable_prime_dh_safe(ret, bits, add, rem, ctx))
++                goto err;
++        } else {
++            if (!bn_probable_prime_dh(ret, bits, add, rem, ctx))
++                goto err;
++        }
++    }
++
++    if (!BN_GENCB_call(cb, 0, c1++))
++        /* aborted */
++        goto err;
++
++    if (!safe) {
++        i = BN_is_prime_fasttest_ex(ret, checks, ctx, 0, cb);
++        if (i == -1)
++            goto err;
++        if (i == 0)
++            goto loop;
++    } else {
++        /*
++         * for "safe prime" generation, check that (p-1)/2 is prime. Since a
++         * prime is odd, We just need to divide by 2
++         */
++        if (!BN_rshift1(t, ret))
++            goto err;
++
++        for (i = 0; i < checks; i++) {
++            j = BN_is_prime_fasttest_ex(ret, 1, ctx, 0, cb);
++            if (j == -1)
++                goto err;
++            if (j == 0)
++                goto loop;
++
++            j = BN_is_prime_fasttest_ex(t, 1, ctx, 0, cb);
++            if (j == -1)
++                goto err;
++            if (j == 0)
++                goto loop;
++
++            if (!BN_GENCB_call(cb, 2, c1 - 1))
++                goto err;
++            /* We have a safe prime test pass */
++        }
++    }
++    /* we have a prime :-) */
++    found = 1;
++ err:
++    OPENSSL_free(mods);
++    if (ctx != NULL)
++        BN_CTX_end(ctx);
++    BN_CTX_free(ctx);
++    bn_check_top(ret);
++    return found;
++}
++
++int BN_is_prime_ex(const BIGNUM *a, int checks, BN_CTX *ctx_passed,
++                   BN_GENCB *cb)
++{
++    return BN_is_prime_fasttest_ex(a, checks, ctx_passed, 0, cb);
++}
++
++int BN_is_prime_fasttest_ex(const BIGNUM *a, int checks, BN_CTX *ctx_passed,
++                            int do_trial_division, BN_GENCB *cb)
++{
++    int i, j, ret = -1;
++    int k;
++    BN_CTX *ctx = NULL;
++    BIGNUM *A1, *A1_odd, *check; /* taken from ctx */
++    BN_MONT_CTX *mont = NULL;
++    const BIGNUM *A = NULL;
++
++    if (BN_cmp(a, BN_value_one()) <= 0)
++        return 0;
++
++    if (checks == BN_prime_checks)
++        checks = BN_prime_checks_for_size(BN_num_bits(a));
++
++    /* first look for small factors */
++    if (!BN_is_odd(a))
++        /* a is even => a is prime if and only if a == 2 */
++        return BN_is_word(a, 2);
++    if (do_trial_division) {
++        for (i = 1; i < NUMPRIMES; i++) {
++            BN_ULONG mod = BN_mod_word(a, primes[i]);
++            if (mod == (BN_ULONG)-1)
++                goto err;
++            if (mod == 0)
++                return 0;
++        }
++        if (!BN_GENCB_call(cb, 1, -1))
++            goto err;
++    }
++
++    if (ctx_passed != NULL)
++        ctx = ctx_passed;
++    else if ((ctx = BN_CTX_new()) == NULL)
++        goto err;
++    BN_CTX_start(ctx);
++
++    /* A := abs(a) */
++    if (a->neg) {
++        BIGNUM *t;
++        if ((t = BN_CTX_get(ctx)) == NULL)
++            goto err;
++        if (BN_copy(t, a) == NULL)
++            goto err;
++        t->neg = 0;
++        A = t;
++    } else
++        A = a;
++    A1 = BN_CTX_get(ctx);
++    A1_odd = BN_CTX_get(ctx);
++    check = BN_CTX_get(ctx);
++    if (check == NULL)
++        goto err;
++
++    /* compute A1 := A - 1 */
++    if (!BN_copy(A1, A))
++        goto err;
++    if (!BN_sub_word(A1, 1))
++        goto err;
++    if (BN_is_zero(A1)) {
++        ret = 0;
++        goto err;
++    }
++
++    /* write  A1  as  A1_odd * 2^k */
++    k = 1;
++    while (!BN_is_bit_set(A1, k))
++        k++;
++    if (!BN_rshift(A1_odd, A1, k))
++        goto err;
++
++    /* Montgomery setup for computations mod A */
++    mont = BN_MONT_CTX_new();
++    if (mont == NULL)
++        goto err;
++    if (!BN_MONT_CTX_set(mont, A, ctx))
++        goto err;
++
++    for (i = 0; i < checks; i++) {
++        if (!BN_pseudo_rand_range(check, A1))
++            goto err;
++        if (!BN_add_word(check, 1))
++            goto err;
++        /* now 1 <= check < A */
++
++        j = witness(check, A, A1, A1_odd, k, ctx, mont);
++        if (j == -1)
++            goto err;
++        if (j) {
++            ret = 0;
++            goto err;
++        }
++        if (!BN_GENCB_call(cb, 1, i))
++            goto err;
++    }
++    ret = 1;
++ err:
++    if (ctx != NULL) {
++        BN_CTX_end(ctx);
++        if (ctx_passed == NULL)
++            BN_CTX_free(ctx);
++    }
++    BN_MONT_CTX_free(mont);
++
++    return (ret);
++}
++
++int bn_probable_prime_dh_retry(BIGNUM *rnd, int bits, BN_CTX *ctx)
++{
++    int i;
++    int ret = 0;
++
++ loop:
++    if (!BN_rand(rnd, bits, BN_RAND_TOP_ONE, BN_RAND_BOTTOM_ODD))
++        goto err;
++
++    /* we now have a random number 'rand' to test. */
++
++    for (i = 1; i < NUMPRIMES; i++) {
++        /* check that rnd is a prime */
++        BN_ULONG mod = BN_mod_word(rnd, (BN_ULONG)primes[i]);
++        if (mod == (BN_ULONG)-1)
++            goto err;
++        if (mod <= 1) {
++            goto loop;
++        }
++    }
++    ret = 1;
++
++ err:
++    bn_check_top(rnd);
++    return (ret);
++}
++
++int bn_probable_prime_dh_coprime(BIGNUM *rnd, int bits, BN_CTX *ctx)
++{
++    int i;
++    BIGNUM *offset_index;
++    BIGNUM *offset_count;
++    int ret = 0;
++
++    OPENSSL_assert(bits > prime_multiplier_bits);
++
++    BN_CTX_start(ctx);
++    if ((offset_index = BN_CTX_get(ctx)) == NULL)
++        goto err;
++    if ((offset_count = BN_CTX_get(ctx)) == NULL)
++        goto err;
++
++    if (!BN_add_word(offset_count, prime_offset_count))
++        goto err;
++
++ loop:
++    if (!BN_rand(rnd, bits - prime_multiplier_bits,
++                 BN_RAND_TOP_ONE, BN_RAND_BOTTOM_ODD))
++        goto err;
++    if (BN_is_bit_set(rnd, bits))
++        goto loop;
++    if (!BN_rand_range(offset_index, offset_count))
++        goto err;
++
++    if (!BN_mul_word(rnd, prime_multiplier)
++        || !BN_add_word(rnd, prime_offsets[BN_get_word(offset_index)]))
++        goto err;
++
++    /* we now have a random number 'rand' to test. */
++
++    /* skip coprimes */
++    for (i = first_prime_index; i < NUMPRIMES; i++) {
++        /* check that rnd is a prime */
++        BN_ULONG mod = BN_mod_word(rnd, (BN_ULONG)primes[i]);
++        if (mod == (BN_ULONG)-1)
++            goto err;
++        if (mod <= 1)
++            goto loop;
++    }
++    ret = 1;
++
++ err:
++    BN_CTX_end(ctx);
++    bn_check_top(rnd);
++    return ret;
++}
++
++static int witness(BIGNUM *w, const BIGNUM *a, const BIGNUM *a1,
++                   const BIGNUM *a1_odd, int k, BN_CTX *ctx,
++                   BN_MONT_CTX *mont)
++{
++    if (!BN_mod_exp_mont(w, w, a1_odd, a, ctx, mont)) /* w := w^a1_odd mod a */
++        return -1;
++    if (BN_is_one(w))
++        return 0;               /* probably prime */
++    if (BN_cmp(w, a1) == 0)
++        return 0;               /* w == -1 (mod a), 'a' is probably prime */
++    while (--k) {
++        if (!BN_mod_mul(w, w, w, a, ctx)) /* w := w^2 mod a */
++            return -1;
++        if (BN_is_one(w))
++            return 1;           /* 'a' is composite, otherwise a previous 'w'
++                                 * would have been == -1 (mod 'a') */
++        if (BN_cmp(w, a1) == 0)
++            return 0;           /* w == -1 (mod a), 'a' is probably prime */
++    }
++    /*
++     * If we get here, 'w' is the (a-1)/2-th power of the original 'w', and
++     * it is neither -1 nor +1 -- so 'a' cannot be prime
++     */
++    bn_check_top(w);
++    return 1;
++}
++
++static int probable_prime(BIGNUM *rnd, int bits, prime_t *mods)
++{
++    int i;
++    BN_ULONG delta;
++    BN_ULONG maxdelta = BN_MASK2 - primes[NUMPRIMES - 1];
++    char is_single_word = bits <= BN_BITS2;
++
++ again:
++    if (!BN_rand(rnd, bits, BN_RAND_TOP_TWO, BN_RAND_BOTTOM_ODD))
++        return (0);
++    /* we now have a random number 'rnd' to test. */
++    for (i = 1; i < NUMPRIMES; i++) {
++        BN_ULONG mod = BN_mod_word(rnd, (BN_ULONG)primes[i]);
++        if (mod == (BN_ULONG)-1)
++            return 0;
++        mods[i] = (prime_t) mod;
++    }
++    /*
++     * If bits is so small that it fits into a single word then we
++     * additionally don't want to exceed that many bits.
++     */
++    if (is_single_word) {
++        BN_ULONG size_limit;
++
++        if (bits == BN_BITS2) {
++            /*
++             * Shifting by this much has undefined behaviour so we do it a
++             * different way
++             */
++            size_limit = ~((BN_ULONG)0) - BN_get_word(rnd);
++        } else {
++            size_limit = (((BN_ULONG)1) << bits) - BN_get_word(rnd) - 1;
++        }
++        if (size_limit < maxdelta)
++            maxdelta = size_limit;
++    }
++    delta = 0;
++ loop:
++    if (is_single_word) {
++        BN_ULONG rnd_word = BN_get_word(rnd);
++
++        /*-
++         * In the case that the candidate prime is a single word then
++         * we check that:
++         *   1) It's greater than primes[i] because we shouldn't reject
++         *      3 as being a prime number because it's a multiple of
++         *      three.
++         *   2) That it's not a multiple of a known prime. We don't
++         *      check that rnd-1 is also coprime to all the known
++         *      primes because there aren't many small primes where
++         *      that's true.
++         */
++        for (i = 1; i < NUMPRIMES && primes[i] < rnd_word; i++) {
++            if ((mods[i] + delta) % primes[i] == 0) {
++                delta += 2;
++                if (delta > maxdelta)
++                    goto again;
++                goto loop;
++            }
++        }
++    } else {
++        for (i = 1; i < NUMPRIMES; i++) {
++            /*
++             * check that rnd is not a prime and also that gcd(rnd-1,primes)
++             * == 1 (except for 2)
++             */
++            if (((mods[i] + delta) % primes[i]) <= 1) {
++                delta += 2;
++                if (delta > maxdelta)
++                    goto again;
++                goto loop;
++            }
++        }
++    }
++    if (!BN_add_word(rnd, delta))
++        return (0);
++    if (BN_num_bits(rnd) != bits)
++        goto again;
++    bn_check_top(rnd);
++    return (1);
++}
++
++int bn_probable_prime_dh(BIGNUM *rnd, int bits,
++                         const BIGNUM *add, const BIGNUM *rem, BN_CTX *ctx)
++{
++    int i, ret = 0;
++    BIGNUM *t1;
++
++    BN_CTX_start(ctx);
++    if ((t1 = BN_CTX_get(ctx)) == NULL)
++        goto err;
++
++    if (!BN_rand(rnd, bits, BN_RAND_TOP_ONE, BN_RAND_BOTTOM_ODD))
++        goto err;
++
++    /* we need ((rnd-rem) % add) == 0 */
++
++    if (!BN_mod(t1, rnd, add, ctx))
++        goto err;
++    if (!BN_sub(rnd, rnd, t1))
++        goto err;
++    if (rem == NULL) {
++        if (!BN_add_word(rnd, 1))
++            goto err;
++    } else {
++        if (!BN_add(rnd, rnd, rem))
++            goto err;
++    }
++
++    /* we now have a random number 'rand' to test. */
++
++ loop:
++    for (i = 1; i < NUMPRIMES; i++) {
++        /* check that rnd is a prime */
++        BN_ULONG mod = BN_mod_word(rnd, (BN_ULONG)primes[i]);
++        if (mod == (BN_ULONG)-1)
++            goto err;
++        if (mod <= 1) {
++            if (!BN_add(rnd, rnd, add))
++                goto err;
++            goto loop;
++        }
++    }
++    ret = 1;
++
++ err:
++    BN_CTX_end(ctx);
++    bn_check_top(rnd);
++    return (ret);
++}
++
++static int probable_prime_dh_safe(BIGNUM *p, int bits, const BIGNUM *padd,
++                                  const BIGNUM *rem, BN_CTX *ctx)
++{
++    int i, ret = 0;
++    BIGNUM *t1, *qadd, *q;
++
++    bits--;
++    BN_CTX_start(ctx);
++    t1 = BN_CTX_get(ctx);
++    q = BN_CTX_get(ctx);
++    qadd = BN_CTX_get(ctx);
++    if (qadd == NULL)
++        goto err;
++
++    if (!BN_rshift1(qadd, padd))
++        goto err;
++
++    if (!BN_rand(q, bits, BN_RAND_TOP_ONE, BN_RAND_BOTTOM_ODD))
++        goto err;
++
++    /* we need ((rnd-rem) % add) == 0 */
++    if (!BN_mod(t1, q, qadd, ctx))
++        goto err;
++    if (!BN_sub(q, q, t1))
++        goto err;
++    if (rem == NULL) {
++        if (!BN_add_word(q, 1))
++            goto err;
++    } else {
++        if (!BN_rshift1(t1, rem))
++            goto err;
++        if (!BN_add(q, q, t1))
++            goto err;
++    }
++
++    /* we now have a random number 'rand' to test. */
++    if (!BN_lshift1(p, q))
++        goto err;
++    if (!BN_add_word(p, 1))
++        goto err;
++
++ loop:
++    for (i = 1; i < NUMPRIMES; i++) {
++        /* check that p and q are prime */
++        /*
++         * check that for p and q gcd(p-1,primes) == 1 (except for 2)
++         */
++        BN_ULONG pmod = BN_mod_word(p, (BN_ULONG)primes[i]);
++        BN_ULONG qmod = BN_mod_word(q, (BN_ULONG)primes[i]);
++        if (pmod == (BN_ULONG)-1 || qmod == (BN_ULONG)-1)
++            goto err;
++        if (pmod == 0 || qmod == 0) {
++            if (!BN_add(p, p, padd))
++                goto err;
++            if (!BN_add(q, q, qadd))
++                goto err;
++            goto loop;
++        }
++    }
++    ret = 1;
++
++ err:
++    BN_CTX_end(ctx);
++    bn_check_top(p);
++    return (ret);
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/bn/bn_prime.h b/CryptoPkg/Library/OpensslLib/openssl/crypto/bn/bn_prime.h
+new file mode 100644
+index 0000000..41440fa
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/bn/bn_prime.h
+@@ -0,0 +1,274 @@
++/*
++ * WARNING: do not edit!
++ * Generated by crypto/bn/bn_prime.pl
++ *
++ * Copyright 1998-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++typedef unsigned short prime_t;
++# define NUMPRIMES 2048
++
++static const prime_t primes[2048] = {
++
++       2,    3,    5,    7,   11,   13,   17,   19, 
++      23,   29,   31,   37,   41,   43,   47,   53, 
++      59,   61,   67,   71,   73,   79,   83,   89, 
++      97,  101,  103,  107,  109,  113,  127,  131, 
++     137,  139,  149,  151,  157,  163,  167,  173, 
++     179,  181,  191,  193,  197,  199,  211,  223, 
++     227,  229,  233,  239,  241,  251,  257,  263, 
++     269,  271,  277,  281,  283,  293,  307,  311, 
++     313,  317,  331,  337,  347,  349,  353,  359, 
++     367,  373,  379,  383,  389,  397,  401,  409, 
++     419,  421,  431,  433,  439,  443,  449,  457, 
++     461,  463,  467,  479,  487,  491,  499,  503, 
++     509,  521,  523,  541,  547,  557,  563,  569, 
++     571,  577,  587,  593,  599,  601,  607,  613, 
++     617,  619,  631,  641,  643,  647,  653,  659, 
++     661,  673,  677,  683,  691,  701,  709,  719, 
++     727,  733,  739,  743,  751,  757,  761,  769, 
++     773,  787,  797,  809,  811,  821,  823,  827, 
++     829,  839,  853,  857,  859,  863,  877,  881, 
++     883,  887,  907,  911,  919,  929,  937,  941, 
++     947,  953,  967,  971,  977,  983,  991,  997, 
++    1009, 1013, 1019, 1021, 1031, 1033, 1039, 1049, 
++    1051, 1061, 1063, 1069, 1087, 1091, 1093, 1097, 
++    1103, 1109, 1117, 1123, 1129, 1151, 1153, 1163, 
++    1171, 1181, 1187, 1193, 1201, 1213, 1217, 1223, 
++    1229, 1231, 1237, 1249, 1259, 1277, 1279, 1283, 
++    1289, 1291, 1297, 1301, 1303, 1307, 1319, 1321, 
++    1327, 1361, 1367, 1373, 1381, 1399, 1409, 1423, 
++    1427, 1429, 1433, 1439, 1447, 1451, 1453, 1459, 
++    1471, 1481, 1483, 1487, 1489, 1493, 1499, 1511, 
++    1523, 1531, 1543, 1549, 1553, 1559, 1567, 1571, 
++    1579, 1583, 1597, 1601, 1607, 1609, 1613, 1619, 
++    1621, 1627, 1637, 1657, 1663, 1667, 1669, 1693, 
++    1697, 1699, 1709, 1721, 1723, 1733, 1741, 1747, 
++    1753, 1759, 1777, 1783, 1787, 1789, 1801, 1811, 
++    1823, 1831, 1847, 1861, 1867, 1871, 1873, 1877, 
++    1879, 1889, 1901, 1907, 1913, 1931, 1933, 1949, 
++    1951, 1973, 1979, 1987, 1993, 1997, 1999, 2003, 
++    2011, 2017, 2027, 2029, 2039, 2053, 2063, 2069, 
++    2081, 2083, 2087, 2089, 2099, 2111, 2113, 2129, 
++    2131, 2137, 2141, 2143, 2153, 2161, 2179, 2203, 
++    2207, 2213, 2221, 2237, 2239, 2243, 2251, 2267, 
++    2269, 2273, 2281, 2287, 2293, 2297, 2309, 2311, 
++    2333, 2339, 2341, 2347, 2351, 2357, 2371, 2377, 
++    2381, 2383, 2389, 2393, 2399, 2411, 2417, 2423, 
++    2437, 2441, 2447, 2459, 2467, 2473, 2477, 2503, 
++    2521, 2531, 2539, 2543, 2549, 2551, 2557, 2579, 
++    2591, 2593, 2609, 2617, 2621, 2633, 2647, 2657, 
++    2659, 2663, 2671, 2677, 2683, 2687, 2689, 2693, 
++    2699, 2707, 2711, 2713, 2719, 2729, 2731, 2741, 
++    2749, 2753, 2767, 2777, 2789, 2791, 2797, 2801, 
++    2803, 2819, 2833, 2837, 2843, 2851, 2857, 2861, 
++    2879, 2887, 2897, 2903, 2909, 2917, 2927, 2939, 
++    2953, 2957, 2963, 2969, 2971, 2999, 3001, 3011, 
++    3019, 3023, 3037, 3041, 3049, 3061, 3067, 3079, 
++    3083, 3089, 3109, 3119, 3121, 3137, 3163, 3167, 
++    3169, 3181, 3187, 3191, 3203, 3209, 3217, 3221, 
++    3229, 3251, 3253, 3257, 3259, 3271, 3299, 3301, 
++    3307, 3313, 3319, 3323, 3329, 3331, 3343, 3347, 
++    3359, 3361, 3371, 3373, 3389, 3391, 3407, 3413, 
++    3433, 3449, 3457, 3461, 3463, 3467, 3469, 3491, 
++    3499, 3511, 3517, 3527, 3529, 3533, 3539, 3541, 
++    3547, 3557, 3559, 3571, 3581, 3583, 3593, 3607, 
++    3613, 3617, 3623, 3631, 3637, 3643, 3659, 3671, 
++    3673, 3677, 3691, 3697, 3701, 3709, 3719, 3727, 
++    3733, 3739, 3761, 3767, 3769, 3779, 3793, 3797, 
++    3803, 3821, 3823, 3833, 3847, 3851, 3853, 3863, 
++    3877, 3881, 3889, 3907, 3911, 3917, 3919, 3923, 
++    3929, 3931, 3943, 3947, 3967, 3989, 4001, 4003, 
++    4007, 4013, 4019, 4021, 4027, 4049, 4051, 4057, 
++    4073, 4079, 4091, 4093, 4099, 4111, 4127, 4129, 
++    4133, 4139, 4153, 4157, 4159, 4177, 4201, 4211, 
++    4217, 4219, 4229, 4231, 4241, 4243, 4253, 4259, 
++    4261, 4271, 4273, 4283, 4289, 4297, 4327, 4337, 
++    4339, 4349, 4357, 4363, 4373, 4391, 4397, 4409, 
++    4421, 4423, 4441, 4447, 4451, 4457, 4463, 4481, 
++    4483, 4493, 4507, 4513, 4517, 4519, 4523, 4547, 
++    4549, 4561, 4567, 4583, 4591, 4597, 4603, 4621, 
++    4637, 4639, 4643, 4649, 4651, 4657, 4663, 4673, 
++    4679, 4691, 4703, 4721, 4723, 4729, 4733, 4751, 
++    4759, 4783, 4787, 4789, 4793, 4799, 4801, 4813, 
++    4817, 4831, 4861, 4871, 4877, 4889, 4903, 4909, 
++    4919, 4931, 4933, 4937, 4943, 4951, 4957, 4967, 
++    4969, 4973, 4987, 4993, 4999, 5003, 5009, 5011, 
++    5021, 5023, 5039, 5051, 5059, 5077, 5081, 5087, 
++    5099, 5101, 5107, 5113, 5119, 5147, 5153, 5167, 
++    5171, 5179, 5189, 5197, 5209, 5227, 5231, 5233, 
++    5237, 5261, 5273, 5279, 5281, 5297, 5303, 5309, 
++    5323, 5333, 5347, 5351, 5381, 5387, 5393, 5399, 
++    5407, 5413, 5417, 5419, 5431, 5437, 5441, 5443, 
++    5449, 5471, 5477, 5479, 5483, 5501, 5503, 5507, 
++    5519, 5521, 5527, 5531, 5557, 5563, 5569, 5573, 
++    5581, 5591, 5623, 5639, 5641, 5647, 5651, 5653, 
++    5657, 5659, 5669, 5683, 5689, 5693, 5701, 5711, 
++    5717, 5737, 5741, 5743, 5749, 5779, 5783, 5791, 
++    5801, 5807, 5813, 5821, 5827, 5839, 5843, 5849, 
++    5851, 5857, 5861, 5867, 5869, 5879, 5881, 5897, 
++    5903, 5923, 5927, 5939, 5953, 5981, 5987, 6007, 
++    6011, 6029, 6037, 6043, 6047, 6053, 6067, 6073, 
++    6079, 6089, 6091, 6101, 6113, 6121, 6131, 6133, 
++    6143, 6151, 6163, 6173, 6197, 6199, 6203, 6211, 
++    6217, 6221, 6229, 6247, 6257, 6263, 6269, 6271, 
++    6277, 6287, 6299, 6301, 6311, 6317, 6323, 6329, 
++    6337, 6343, 6353, 6359, 6361, 6367, 6373, 6379, 
++    6389, 6397, 6421, 6427, 6449, 6451, 6469, 6473, 
++    6481, 6491, 6521, 6529, 6547, 6551, 6553, 6563, 
++    6569, 6571, 6577, 6581, 6599, 6607, 6619, 6637, 
++    6653, 6659, 6661, 6673, 6679, 6689, 6691, 6701, 
++    6703, 6709, 6719, 6733, 6737, 6761, 6763, 6779, 
++    6781, 6791, 6793, 6803, 6823, 6827, 6829, 6833, 
++    6841, 6857, 6863, 6869, 6871, 6883, 6899, 6907, 
++    6911, 6917, 6947, 6949, 6959, 6961, 6967, 6971, 
++    6977, 6983, 6991, 6997, 7001, 7013, 7019, 7027, 
++    7039, 7043, 7057, 7069, 7079, 7103, 7109, 7121, 
++    7127, 7129, 7151, 7159, 7177, 7187, 7193, 7207, 
++    7211, 7213, 7219, 7229, 7237, 7243, 7247, 7253, 
++    7283, 7297, 7307, 7309, 7321, 7331, 7333, 7349, 
++    7351, 7369, 7393, 7411, 7417, 7433, 7451, 7457, 
++    7459, 7477, 7481, 7487, 7489, 7499, 7507, 7517, 
++    7523, 7529, 7537, 7541, 7547, 7549, 7559, 7561, 
++    7573, 7577, 7583, 7589, 7591, 7603, 7607, 7621, 
++    7639, 7643, 7649, 7669, 7673, 7681, 7687, 7691, 
++    7699, 7703, 7717, 7723, 7727, 7741, 7753, 7757, 
++    7759, 7789, 7793, 7817, 7823, 7829, 7841, 7853, 
++    7867, 7873, 7877, 7879, 7883, 7901, 7907, 7919, 
++    7927, 7933, 7937, 7949, 7951, 7963, 7993, 8009, 
++    8011, 8017, 8039, 8053, 8059, 8069, 8081, 8087, 
++    8089, 8093, 8101, 8111, 8117, 8123, 8147, 8161, 
++    8167, 8171, 8179, 8191, 8209, 8219, 8221, 8231, 
++    8233, 8237, 8243, 8263, 8269, 8273, 8287, 8291, 
++    8293, 8297, 8311, 8317, 8329, 8353, 8363, 8369, 
++    8377, 8387, 8389, 8419, 8423, 8429, 8431, 8443, 
++    8447, 8461, 8467, 8501, 8513, 8521, 8527, 8537, 
++    8539, 8543, 8563, 8573, 8581, 8597, 8599, 8609, 
++    8623, 8627, 8629, 8641, 8647, 8663, 8669, 8677, 
++    8681, 8689, 8693, 8699, 8707, 8713, 8719, 8731, 
++    8737, 8741, 8747, 8753, 8761, 8779, 8783, 8803, 
++    8807, 8819, 8821, 8831, 8837, 8839, 8849, 8861, 
++    8863, 8867, 8887, 8893, 8923, 8929, 8933, 8941, 
++    8951, 8963, 8969, 8971, 8999, 9001, 9007, 9011, 
++    9013, 9029, 9041, 9043, 9049, 9059, 9067, 9091, 
++    9103, 9109, 9127, 9133, 9137, 9151, 9157, 9161, 
++    9173, 9181, 9187, 9199, 9203, 9209, 9221, 9227, 
++    9239, 9241, 9257, 9277, 9281, 9283, 9293, 9311, 
++    9319, 9323, 9337, 9341, 9343, 9349, 9371, 9377, 
++    9391, 9397, 9403, 9413, 9419, 9421, 9431, 9433, 
++    9437, 9439, 9461, 9463, 9467, 9473, 9479, 9491, 
++    9497, 9511, 9521, 9533, 9539, 9547, 9551, 9587, 
++    9601, 9613, 9619, 9623, 9629, 9631, 9643, 9649, 
++    9661, 9677, 9679, 9689, 9697, 9719, 9721, 9733, 
++    9739, 9743, 9749, 9767, 9769, 9781, 9787, 9791, 
++    9803, 9811, 9817, 9829, 9833, 9839, 9851, 9857, 
++    9859, 9871, 9883, 9887, 9901, 9907, 9923, 9929, 
++    9931, 9941, 9949, 9967, 9973, 10007, 10009, 10037, 
++    10039, 10061, 10067, 10069, 10079, 10091, 10093, 10099, 
++    10103, 10111, 10133, 10139, 10141, 10151, 10159, 10163, 
++    10169, 10177, 10181, 10193, 10211, 10223, 10243, 10247, 
++    10253, 10259, 10267, 10271, 10273, 10289, 10301, 10303, 
++    10313, 10321, 10331, 10333, 10337, 10343, 10357, 10369, 
++    10391, 10399, 10427, 10429, 10433, 10453, 10457, 10459, 
++    10463, 10477, 10487, 10499, 10501, 10513, 10529, 10531, 
++    10559, 10567, 10589, 10597, 10601, 10607, 10613, 10627, 
++    10631, 10639, 10651, 10657, 10663, 10667, 10687, 10691, 
++    10709, 10711, 10723, 10729, 10733, 10739, 10753, 10771, 
++    10781, 10789, 10799, 10831, 10837, 10847, 10853, 10859, 
++    10861, 10867, 10883, 10889, 10891, 10903, 10909, 10937, 
++    10939, 10949, 10957, 10973, 10979, 10987, 10993, 11003, 
++    11027, 11047, 11057, 11059, 11069, 11071, 11083, 11087, 
++    11093, 11113, 11117, 11119, 11131, 11149, 11159, 11161, 
++    11171, 11173, 11177, 11197, 11213, 11239, 11243, 11251, 
++    11257, 11261, 11273, 11279, 11287, 11299, 11311, 11317, 
++    11321, 11329, 11351, 11353, 11369, 11383, 11393, 11399, 
++    11411, 11423, 11437, 11443, 11447, 11467, 11471, 11483, 
++    11489, 11491, 11497, 11503, 11519, 11527, 11549, 11551, 
++    11579, 11587, 11593, 11597, 11617, 11621, 11633, 11657, 
++    11677, 11681, 11689, 11699, 11701, 11717, 11719, 11731, 
++    11743, 11777, 11779, 11783, 11789, 11801, 11807, 11813, 
++    11821, 11827, 11831, 11833, 11839, 11863, 11867, 11887, 
++    11897, 11903, 11909, 11923, 11927, 11933, 11939, 11941, 
++    11953, 11959, 11969, 11971, 11981, 11987, 12007, 12011, 
++    12037, 12041, 12043, 12049, 12071, 12073, 12097, 12101, 
++    12107, 12109, 12113, 12119, 12143, 12149, 12157, 12161, 
++    12163, 12197, 12203, 12211, 12227, 12239, 12241, 12251, 
++    12253, 12263, 12269, 12277, 12281, 12289, 12301, 12323, 
++    12329, 12343, 12347, 12373, 12377, 12379, 12391, 12401, 
++    12409, 12413, 12421, 12433, 12437, 12451, 12457, 12473, 
++    12479, 12487, 12491, 12497, 12503, 12511, 12517, 12527, 
++    12539, 12541, 12547, 12553, 12569, 12577, 12583, 12589, 
++    12601, 12611, 12613, 12619, 12637, 12641, 12647, 12653, 
++    12659, 12671, 12689, 12697, 12703, 12713, 12721, 12739, 
++    12743, 12757, 12763, 12781, 12791, 12799, 12809, 12821, 
++    12823, 12829, 12841, 12853, 12889, 12893, 12899, 12907, 
++    12911, 12917, 12919, 12923, 12941, 12953, 12959, 12967, 
++    12973, 12979, 12983, 13001, 13003, 13007, 13009, 13033, 
++    13037, 13043, 13049, 13063, 13093, 13099, 13103, 13109, 
++    13121, 13127, 13147, 13151, 13159, 13163, 13171, 13177, 
++    13183, 13187, 13217, 13219, 13229, 13241, 13249, 13259, 
++    13267, 13291, 13297, 13309, 13313, 13327, 13331, 13337, 
++    13339, 13367, 13381, 13397, 13399, 13411, 13417, 13421, 
++    13441, 13451, 13457, 13463, 13469, 13477, 13487, 13499, 
++    13513, 13523, 13537, 13553, 13567, 13577, 13591, 13597, 
++    13613, 13619, 13627, 13633, 13649, 13669, 13679, 13681, 
++    13687, 13691, 13693, 13697, 13709, 13711, 13721, 13723, 
++    13729, 13751, 13757, 13759, 13763, 13781, 13789, 13799, 
++    13807, 13829, 13831, 13841, 13859, 13873, 13877, 13879, 
++    13883, 13901, 13903, 13907, 13913, 13921, 13931, 13933, 
++    13963, 13967, 13997, 13999, 14009, 14011, 14029, 14033, 
++    14051, 14057, 14071, 14081, 14083, 14087, 14107, 14143, 
++    14149, 14153, 14159, 14173, 14177, 14197, 14207, 14221, 
++    14243, 14249, 14251, 14281, 14293, 14303, 14321, 14323, 
++    14327, 14341, 14347, 14369, 14387, 14389, 14401, 14407, 
++    14411, 14419, 14423, 14431, 14437, 14447, 14449, 14461, 
++    14479, 14489, 14503, 14519, 14533, 14537, 14543, 14549, 
++    14551, 14557, 14561, 14563, 14591, 14593, 14621, 14627, 
++    14629, 14633, 14639, 14653, 14657, 14669, 14683, 14699, 
++    14713, 14717, 14723, 14731, 14737, 14741, 14747, 14753, 
++    14759, 14767, 14771, 14779, 14783, 14797, 14813, 14821, 
++    14827, 14831, 14843, 14851, 14867, 14869, 14879, 14887, 
++    14891, 14897, 14923, 14929, 14939, 14947, 14951, 14957, 
++    14969, 14983, 15013, 15017, 15031, 15053, 15061, 15073, 
++    15077, 15083, 15091, 15101, 15107, 15121, 15131, 15137, 
++    15139, 15149, 15161, 15173, 15187, 15193, 15199, 15217, 
++    15227, 15233, 15241, 15259, 15263, 15269, 15271, 15277, 
++    15287, 15289, 15299, 15307, 15313, 15319, 15329, 15331, 
++    15349, 15359, 15361, 15373, 15377, 15383, 15391, 15401, 
++    15413, 15427, 15439, 15443, 15451, 15461, 15467, 15473, 
++    15493, 15497, 15511, 15527, 15541, 15551, 15559, 15569, 
++    15581, 15583, 15601, 15607, 15619, 15629, 15641, 15643, 
++    15647, 15649, 15661, 15667, 15671, 15679, 15683, 15727, 
++    15731, 15733, 15737, 15739, 15749, 15761, 15767, 15773, 
++    15787, 15791, 15797, 15803, 15809, 15817, 15823, 15859, 
++    15877, 15881, 15887, 15889, 15901, 15907, 15913, 15919, 
++    15923, 15937, 15959, 15971, 15973, 15991, 16001, 16007, 
++    16033, 16057, 16061, 16063, 16067, 16069, 16073, 16087, 
++    16091, 16097, 16103, 16111, 16127, 16139, 16141, 16183, 
++    16187, 16189, 16193, 16217, 16223, 16229, 16231, 16249, 
++    16253, 16267, 16273, 16301, 16319, 16333, 16339, 16349, 
++    16361, 16363, 16369, 16381, 16411, 16417, 16421, 16427, 
++    16433, 16447, 16451, 16453, 16477, 16481, 16487, 16493, 
++    16519, 16529, 16547, 16553, 16561, 16567, 16573, 16603, 
++    16607, 16619, 16631, 16633, 16649, 16651, 16657, 16661, 
++    16673, 16691, 16693, 16699, 16703, 16729, 16741, 16747, 
++    16759, 16763, 16787, 16811, 16823, 16829, 16831, 16843, 
++    16871, 16879, 16883, 16889, 16901, 16903, 16921, 16927, 
++    16931, 16937, 16943, 16963, 16979, 16981, 16987, 16993, 
++    17011, 17021, 17027, 17029, 17033, 17041, 17047, 17053, 
++    17077, 17093, 17099, 17107, 17117, 17123, 17137, 17159, 
++    17167, 17183, 17189, 17191, 17203, 17207, 17209, 17231, 
++    17239, 17257, 17291, 17293, 17299, 17317, 17321, 17327, 
++    17333, 17341, 17351, 17359, 17377, 17383, 17387, 17389, 
++    17393, 17401, 17417, 17419, 17431, 17443, 17449, 17467, 
++    17471, 17477, 17483, 17489, 17491, 17497, 17509, 17519, 
++    17539, 17551, 17569, 17573, 17579, 17581, 17597, 17599, 
++    17609, 17623, 17627, 17657, 17659, 17669, 17681, 17683, 
++    17707, 17713, 17729, 17737, 17747, 17749, 17761, 17783, 
++    17789, 17791, 17807, 17827, 17837, 17839, 17851, 17863, 
++};
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/bn/bn_prime.pl b/CryptoPkg/Library/OpensslLib/openssl/crypto/bn/bn_prime.pl
+new file mode 100644
+index 0000000..163d4a9
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/bn/bn_prime.pl
+@@ -0,0 +1,46 @@
++#! /usr/bin/env perl
++# Copyright 1998-2016 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
++# in the file LICENSE in the source distribution or at
++# https://www.openssl.org/source/license.html
++
++print <<"EOF";
++/*
++ * WARNING: do not edit!
++ * Generated by crypto/bn/bn_prime.pl
++ *
++ * Copyright 1998-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++EOF
++
++
++my $num = shift || 2048;
++my @primes = ( 2 );
++my $p = 1;
++loop: while ($#primes < $num-1) {
++    $p += 2;
++    my $s = int(sqrt($p));
++
++    for (my $i = 0; defined($primes[$i]) && $primes[$i] <= $s; $i++) {
++        next loop if ($p % $primes[$i]) == 0;
++    }
++    push(@primes, $p);
++}
++
++print "typedef unsigned short prime_t;\n";
++printf "# define NUMPRIMES %d\n\n", $num;
++
++printf "static const prime_t primes[%d] = {\n", $num;
++for (my $i = 0; $i <= $#primes; $i++) {
++    printf "\n    " if ($i % 8) == 0;
++    printf "%4d, ", $primes[$i];
++}
++print "\n};\n";
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/bn/bn_print.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/bn/bn_print.c
+new file mode 100644
+index 0000000..a16bde8
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/bn/bn_print.c
+@@ -0,0 +1,345 @@
++/*
++ * Copyright 1995-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include 
++#include 
++#include "internal/cryptlib.h"
++#include 
++#include "bn_lcl.h"
++
++static const char Hex[] = "0123456789ABCDEF";
++
++/* Must 'OPENSSL_free' the returned data */
++char *BN_bn2hex(const BIGNUM *a)
++{
++    int i, j, v, z = 0;
++    char *buf;
++    char *p;
++
++    if (BN_is_zero(a))
++        return OPENSSL_strdup("0");
++    buf = OPENSSL_malloc(a->top * BN_BYTES * 2 + 2);
++    if (buf == NULL) {
++        BNerr(BN_F_BN_BN2HEX, ERR_R_MALLOC_FAILURE);
++        goto err;
++    }
++    p = buf;
++    if (a->neg)
++        *(p++) = '-';
++    if (BN_is_zero(a))
++        *(p++) = '0';
++    for (i = a->top - 1; i >= 0; i--) {
++        for (j = BN_BITS2 - 8; j >= 0; j -= 8) {
++            /* strip leading zeros */
++            v = ((int)(a->d[i] >> (long)j)) & 0xff;
++            if (z || (v != 0)) {
++                *(p++) = Hex[v >> 4];
++                *(p++) = Hex[v & 0x0f];
++                z = 1;
++            }
++        }
++    }
++    *p = '\0';
++ err:
++    return (buf);
++}
++
++/* Must 'OPENSSL_free' the returned data */
++char *BN_bn2dec(const BIGNUM *a)
++{
++    int i = 0, num, ok = 0;
++    char *buf = NULL;
++    char *p;
++    BIGNUM *t = NULL;
++    BN_ULONG *bn_data = NULL, *lp;
++    int bn_data_num;
++
++    /*-
++     * get an upper bound for the length of the decimal integer
++     * num <= (BN_num_bits(a) + 1) * log(2)
++     *     <= 3 * BN_num_bits(a) * 0.101 + log(2) + 1     (rounding error)
++     *     <= 3 * BN_num_bits(a) / 10 + 3 * BN_num_bits / 1000 + 1 + 1
++     */
++    i = BN_num_bits(a) * 3;
++    num = (i / 10 + i / 1000 + 1) + 1;
++    bn_data_num = num / BN_DEC_NUM + 1;
++    bn_data = OPENSSL_malloc(bn_data_num * sizeof(BN_ULONG));
++    buf = OPENSSL_malloc(num + 3);
++    if ((buf == NULL) || (bn_data == NULL)) {
++        BNerr(BN_F_BN_BN2DEC, ERR_R_MALLOC_FAILURE);
++        goto err;
++    }
++    if ((t = BN_dup(a)) == NULL)
++        goto err;
++
++#define BUF_REMAIN (num+3 - (size_t)(p - buf))
++    p = buf;
++    lp = bn_data;
++    if (BN_is_zero(t)) {
++        *(p++) = '0';
++        *(p++) = '\0';
++    } else {
++        if (BN_is_negative(t))
++            *p++ = '-';
++
++        while (!BN_is_zero(t)) {
++            if (lp - bn_data >= bn_data_num)
++                goto err;
++            *lp = BN_div_word(t, BN_DEC_CONV);
++            if (*lp == (BN_ULONG)-1)
++                goto err;
++            lp++;
++        }
++        lp--;
++        /*
++         * We now have a series of blocks, BN_DEC_NUM chars in length, where
++         * the last one needs truncation. The blocks need to be reversed in
++         * order.
++         */
++        BIO_snprintf(p, BUF_REMAIN, BN_DEC_FMT1, *lp);
++        while (*p)
++            p++;
++        while (lp != bn_data) {
++            lp--;
++            BIO_snprintf(p, BUF_REMAIN, BN_DEC_FMT2, *lp);
++            while (*p)
++                p++;
++        }
++    }
++    ok = 1;
++ err:
++    OPENSSL_free(bn_data);
++    BN_free(t);
++    if (ok)
++        return buf;
++    OPENSSL_free(buf);
++    return NULL;
++}
++
++int BN_hex2bn(BIGNUM **bn, const char *a)
++{
++    BIGNUM *ret = NULL;
++    BN_ULONG l = 0;
++    int neg = 0, h, m, i, j, k, c;
++    int num;
++
++    if ((a == NULL) || (*a == '\0'))
++        return (0);
++
++    if (*a == '-') {
++        neg = 1;
++        a++;
++    }
++
++    for (i = 0; i <= (INT_MAX/4) && isxdigit((unsigned char)a[i]); i++)
++        continue;
++
++    if (i == 0 || i > INT_MAX/4)
++        goto err;
++
++    num = i + neg;
++    if (bn == NULL)
++        return (num);
++
++    /* a is the start of the hex digits, and it is 'i' long */
++    if (*bn == NULL) {
++        if ((ret = BN_new()) == NULL)
++            return (0);
++    } else {
++        ret = *bn;
++        BN_zero(ret);
++    }
++
++    /* i is the number of hex digits */
++    if (bn_expand(ret, i * 4) == NULL)
++        goto err;
++
++    j = i;                      /* least significant 'hex' */
++    m = 0;
++    h = 0;
++    while (j > 0) {
++        m = ((BN_BYTES * 2) <= j) ? (BN_BYTES * 2) : j;
++        l = 0;
++        for (;;) {
++            c = a[j - m];
++            k = OPENSSL_hexchar2int(c);
++            if (k < 0)
++                k = 0;          /* paranoia */
++            l = (l << 4) | k;
++
++            if (--m <= 0) {
++                ret->d[h++] = l;
++                break;
++            }
++        }
++        j -= (BN_BYTES * 2);
++    }
++    ret->top = h;
++    bn_correct_top(ret);
++
++    *bn = ret;
++    bn_check_top(ret);
++    /* Don't set the negative flag if it's zero. */
++    if (ret->top != 0)
++        ret->neg = neg;
++    return (num);
++ err:
++    if (*bn == NULL)
++        BN_free(ret);
++    return (0);
++}
++
++int BN_dec2bn(BIGNUM **bn, const char *a)
++{
++    BIGNUM *ret = NULL;
++    BN_ULONG l = 0;
++    int neg = 0, i, j;
++    int num;
++
++    if ((a == NULL) || (*a == '\0'))
++        return (0);
++    if (*a == '-') {
++        neg = 1;
++        a++;
++    }
++
++    for (i = 0; i <= (INT_MAX/4) && isdigit((unsigned char)a[i]); i++)
++        continue;
++
++    if (i == 0 || i > INT_MAX/4)
++        goto err;
++
++    num = i + neg;
++    if (bn == NULL)
++        return (num);
++
++    /*
++     * a is the start of the digits, and it is 'i' long. We chop it into
++     * BN_DEC_NUM digits at a time
++     */
++    if (*bn == NULL) {
++        if ((ret = BN_new()) == NULL)
++            return (0);
++    } else {
++        ret = *bn;
++        BN_zero(ret);
++    }
++
++    /* i is the number of digits, a bit of an over expand */
++    if (bn_expand(ret, i * 4) == NULL)
++        goto err;
++
++    j = BN_DEC_NUM - (i % BN_DEC_NUM);
++    if (j == BN_DEC_NUM)
++        j = 0;
++    l = 0;
++    while (--i >= 0) {
++        l *= 10;
++        l += *a - '0';
++        a++;
++        if (++j == BN_DEC_NUM) {
++            if (!BN_mul_word(ret, BN_DEC_CONV)
++                || !BN_add_word(ret, l))
++                goto err;
++            l = 0;
++            j = 0;
++        }
++    }
++
++    bn_correct_top(ret);
++    *bn = ret;
++    bn_check_top(ret);
++    /* Don't set the negative flag if it's zero. */
++    if (ret->top != 0)
++        ret->neg = neg;
++    return (num);
++ err:
++    if (*bn == NULL)
++        BN_free(ret);
++    return (0);
++}
++
++int BN_asc2bn(BIGNUM **bn, const char *a)
++{
++    const char *p = a;
++
++    if (*p == '-')
++        p++;
++
++    if (p[0] == '0' && (p[1] == 'X' || p[1] == 'x')) {
++        if (!BN_hex2bn(bn, p + 2))
++            return 0;
++    } else {
++        if (!BN_dec2bn(bn, p))
++            return 0;
++    }
++    /* Don't set the negative flag if it's zero. */
++    if (*a == '-' && (*bn)->top != 0)
++        (*bn)->neg = 1;
++    return 1;
++}
++
++# ifndef OPENSSL_NO_STDIO
++int BN_print_fp(FILE *fp, const BIGNUM *a)
++{
++    BIO *b;
++    int ret;
++
++    if ((b = BIO_new(BIO_s_file())) == NULL)
++        return (0);
++    BIO_set_fp(b, fp, BIO_NOCLOSE);
++    ret = BN_print(b, a);
++    BIO_free(b);
++    return (ret);
++}
++# endif
++
++int BN_print(BIO *bp, const BIGNUM *a)
++{
++    int i, j, v, z = 0;
++    int ret = 0;
++
++    if ((a->neg) && (BIO_write(bp, "-", 1) != 1))
++        goto end;
++    if (BN_is_zero(a) && (BIO_write(bp, "0", 1) != 1))
++        goto end;
++    for (i = a->top - 1; i >= 0; i--) {
++        for (j = BN_BITS2 - 4; j >= 0; j -= 4) {
++            /* strip leading zeros */
++            v = ((int)(a->d[i] >> (long)j)) & 0x0f;
++            if (z || (v != 0)) {
++                if (BIO_write(bp, &(Hex[v]), 1) != 1)
++                    goto end;
++                z = 1;
++            }
++        }
++    }
++    ret = 1;
++ end:
++    return (ret);
++}
++
++char *BN_options(void)
++{
++    static int init = 0;
++    static char data[16];
++
++    if (!init) {
++        init++;
++#ifdef BN_LLONG
++        BIO_snprintf(data, sizeof data, "bn(%d,%d)",
++                     (int)sizeof(BN_ULLONG) * 8, (int)sizeof(BN_ULONG) * 8);
++#else
++        BIO_snprintf(data, sizeof data, "bn(%d,%d)",
++                     (int)sizeof(BN_ULONG) * 8, (int)sizeof(BN_ULONG) * 8);
++#endif
++    }
++    return (data);
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/bn/bn_rand.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/bn/bn_rand.c
+new file mode 100644
+index 0000000..9ce4c5f
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/bn/bn_rand.c
+@@ -0,0 +1,258 @@
++/*
++ * Copyright 1995-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include 
++#include "internal/cryptlib.h"
++#include "bn_lcl.h"
++#include 
++#include 
++
++static int bnrand(int pseudorand, BIGNUM *rnd, int bits, int top, int bottom)
++{
++    unsigned char *buf = NULL;
++    int ret = 0, bit, bytes, mask;
++    time_t tim;
++
++    if (bits == 0) {
++        if (top != BN_RAND_TOP_ANY || bottom != BN_RAND_BOTTOM_ANY)
++            goto toosmall;
++        BN_zero(rnd);
++        return 1;
++    }
++    if (bits < 0 || (bits == 1 && top > 0))
++        goto toosmall;
++
++    bytes = (bits + 7) / 8;
++    bit = (bits - 1) % 8;
++    mask = 0xff << (bit + 1);
++
++    buf = OPENSSL_malloc(bytes);
++    if (buf == NULL) {
++        BNerr(BN_F_BNRAND, ERR_R_MALLOC_FAILURE);
++        goto err;
++    }
++
++    /* make a random number and set the top and bottom bits */
++    time(&tim);
++    RAND_add(&tim, sizeof(tim), 0.0);
++
++    if (RAND_bytes(buf, bytes) <= 0)
++        goto err;
++
++    if (pseudorand == 2) {
++        /*
++         * generate patterns that are more likely to trigger BN library bugs
++         */
++        int i;
++        unsigned char c;
++
++        for (i = 0; i < bytes; i++) {
++            if (RAND_bytes(&c, 1) <= 0)
++                goto err;
++            if (c >= 128 && i > 0)
++                buf[i] = buf[i - 1];
++            else if (c < 42)
++                buf[i] = 0;
++            else if (c < 84)
++                buf[i] = 255;
++        }
++    }
++
++    if (top >= 0) {
++        if (top) {
++            if (bit == 0) {
++                buf[0] = 1;
++                buf[1] |= 0x80;
++            } else {
++                buf[0] |= (3 << (bit - 1));
++            }
++        } else {
++            buf[0] |= (1 << bit);
++        }
++    }
++    buf[0] &= ~mask;
++    if (bottom)                 /* set bottom bit if requested */
++        buf[bytes - 1] |= 1;
++    if (!BN_bin2bn(buf, bytes, rnd))
++        goto err;
++    ret = 1;
++ err:
++    OPENSSL_clear_free(buf, bytes);
++    bn_check_top(rnd);
++    return (ret);
++
++toosmall:
++    BNerr(BN_F_BNRAND, BN_R_BITS_TOO_SMALL);
++    return 0;
++}
++
++int BN_rand(BIGNUM *rnd, int bits, int top, int bottom)
++{
++    return bnrand(0, rnd, bits, top, bottom);
++}
++
++int BN_pseudo_rand(BIGNUM *rnd, int bits, int top, int bottom)
++{
++    return bnrand(1, rnd, bits, top, bottom);
++}
++
++int BN_bntest_rand(BIGNUM *rnd, int bits, int top, int bottom)
++{
++    return bnrand(2, rnd, bits, top, bottom);
++}
++
++/* random number r:  0 <= r < range */
++static int bn_rand_range(int pseudo, BIGNUM *r, const BIGNUM *range)
++{
++    int (*bn_rand) (BIGNUM *, int, int, int) =
++        pseudo ? BN_pseudo_rand : BN_rand;
++    int n;
++    int count = 100;
++
++    if (range->neg || BN_is_zero(range)) {
++        BNerr(BN_F_BN_RAND_RANGE, BN_R_INVALID_RANGE);
++        return 0;
++    }
++
++    n = BN_num_bits(range);     /* n > 0 */
++
++    /* BN_is_bit_set(range, n - 1) always holds */
++
++    if (n == 1)
++        BN_zero(r);
++    else if (!BN_is_bit_set(range, n - 2) && !BN_is_bit_set(range, n - 3)) {
++        /*
++         * range = 100..._2, so 3*range (= 11..._2) is exactly one bit longer
++         * than range
++         */
++        do {
++            if (!bn_rand(r, n + 1, BN_RAND_TOP_ANY, BN_RAND_BOTTOM_ANY))
++                return 0;
++            /*
++             * If r < 3*range, use r := r MOD range (which is either r, r -
++             * range, or r - 2*range). Otherwise, iterate once more. Since
++             * 3*range = 11..._2, each iteration succeeds with probability >=
++             * .75.
++             */
++            if (BN_cmp(r, range) >= 0) {
++                if (!BN_sub(r, r, range))
++                    return 0;
++                if (BN_cmp(r, range) >= 0)
++                    if (!BN_sub(r, r, range))
++                        return 0;
++            }
++
++            if (!--count) {
++                BNerr(BN_F_BN_RAND_RANGE, BN_R_TOO_MANY_ITERATIONS);
++                return 0;
++            }
++
++        }
++        while (BN_cmp(r, range) >= 0);
++    } else {
++        do {
++            /* range = 11..._2  or  range = 101..._2 */
++            if (!bn_rand(r, n, BN_RAND_TOP_ANY, BN_RAND_BOTTOM_ANY))
++                return 0;
++
++            if (!--count) {
++                BNerr(BN_F_BN_RAND_RANGE, BN_R_TOO_MANY_ITERATIONS);
++                return 0;
++            }
++        }
++        while (BN_cmp(r, range) >= 0);
++    }
++
++    bn_check_top(r);
++    return 1;
++}
++
++int BN_rand_range(BIGNUM *r, const BIGNUM *range)
++{
++    return bn_rand_range(0, r, range);
++}
++
++int BN_pseudo_rand_range(BIGNUM *r, const BIGNUM *range)
++{
++    return bn_rand_range(1, r, range);
++}
++
++/*
++ * BN_generate_dsa_nonce generates a random number 0 <= out < range. Unlike
++ * BN_rand_range, it also includes the contents of |priv| and |message| in
++ * the generation so that an RNG failure isn't fatal as long as |priv|
++ * remains secret. This is intended for use in DSA and ECDSA where an RNG
++ * weakness leads directly to private key exposure unless this function is
++ * used.
++ */
++int BN_generate_dsa_nonce(BIGNUM *out, const BIGNUM *range,
++                          const BIGNUM *priv, const unsigned char *message,
++                          size_t message_len, BN_CTX *ctx)
++{
++    SHA512_CTX sha;
++    /*
++     * We use 512 bits of random data per iteration to ensure that we have at
++     * least |range| bits of randomness.
++     */
++    unsigned char random_bytes[64];
++    unsigned char digest[SHA512_DIGEST_LENGTH];
++    unsigned done, todo;
++    /* We generate |range|+8 bytes of random output. */
++    const unsigned num_k_bytes = BN_num_bytes(range) + 8;
++    unsigned char private_bytes[96];
++    unsigned char *k_bytes;
++    int ret = 0;
++
++    k_bytes = OPENSSL_malloc(num_k_bytes);
++    if (k_bytes == NULL)
++        goto err;
++
++    /* We copy |priv| into a local buffer to avoid exposing its length. */
++    todo = sizeof(priv->d[0]) * priv->top;
++    if (todo > sizeof(private_bytes)) {
++        /*
++         * No reasonable DSA or ECDSA key should have a private key this
++         * large and we don't handle this case in order to avoid leaking the
++         * length of the private key.
++         */
++        BNerr(BN_F_BN_GENERATE_DSA_NONCE, BN_R_PRIVATE_KEY_TOO_LARGE);
++        goto err;
++    }
++    memcpy(private_bytes, priv->d, todo);
++    memset(private_bytes + todo, 0, sizeof(private_bytes) - todo);
++
++    for (done = 0; done < num_k_bytes;) {
++        if (RAND_bytes(random_bytes, sizeof(random_bytes)) != 1)
++            goto err;
++        SHA512_Init(&sha);
++        SHA512_Update(&sha, &done, sizeof(done));
++        SHA512_Update(&sha, private_bytes, sizeof(private_bytes));
++        SHA512_Update(&sha, message, message_len);
++        SHA512_Update(&sha, random_bytes, sizeof(random_bytes));
++        SHA512_Final(digest, &sha);
++
++        todo = num_k_bytes - done;
++        if (todo > SHA512_DIGEST_LENGTH)
++            todo = SHA512_DIGEST_LENGTH;
++        memcpy(k_bytes + done, digest, todo);
++        done += todo;
++    }
++
++    if (!BN_bin2bn(k_bytes, num_k_bytes, out))
++        goto err;
++    if (BN_mod(out, out, range, ctx) != 1)
++        goto err;
++    ret = 1;
++
++ err:
++    OPENSSL_free(k_bytes);
++    OPENSSL_cleanse(private_bytes, sizeof(private_bytes));
++    return ret;
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/bn/bn_recp.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/bn/bn_recp.c
+new file mode 100644
+index 0000000..20585b9
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/bn/bn_recp.c
+@@ -0,0 +1,199 @@
++/*
++ * Copyright 1995-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include "internal/cryptlib.h"
++#include "bn_lcl.h"
++
++void BN_RECP_CTX_init(BN_RECP_CTX *recp)
++{
++    memset(recp, 0, sizeof(*recp));
++    bn_init(&(recp->N));
++    bn_init(&(recp->Nr));
++}
++
++BN_RECP_CTX *BN_RECP_CTX_new(void)
++{
++    BN_RECP_CTX *ret;
++
++    if ((ret = OPENSSL_zalloc(sizeof(*ret))) == NULL)
++        return (NULL);
++
++    bn_init(&(ret->N));
++    bn_init(&(ret->Nr));
++    ret->flags = BN_FLG_MALLOCED;
++    return (ret);
++}
++
++void BN_RECP_CTX_free(BN_RECP_CTX *recp)
++{
++    if (recp == NULL)
++        return;
++
++    BN_free(&(recp->N));
++    BN_free(&(recp->Nr));
++    if (recp->flags & BN_FLG_MALLOCED)
++        OPENSSL_free(recp);
++}
++
++int BN_RECP_CTX_set(BN_RECP_CTX *recp, const BIGNUM *d, BN_CTX *ctx)
++{
++    if (!BN_copy(&(recp->N), d))
++        return 0;
++    BN_zero(&(recp->Nr));
++    recp->num_bits = BN_num_bits(d);
++    recp->shift = 0;
++    return (1);
++}
++
++int BN_mod_mul_reciprocal(BIGNUM *r, const BIGNUM *x, const BIGNUM *y,
++                          BN_RECP_CTX *recp, BN_CTX *ctx)
++{
++    int ret = 0;
++    BIGNUM *a;
++    const BIGNUM *ca;
++
++    BN_CTX_start(ctx);
++    if ((a = BN_CTX_get(ctx)) == NULL)
++        goto err;
++    if (y != NULL) {
++        if (x == y) {
++            if (!BN_sqr(a, x, ctx))
++                goto err;
++        } else {
++            if (!BN_mul(a, x, y, ctx))
++                goto err;
++        }
++        ca = a;
++    } else
++        ca = x;                 /* Just do the mod */
++
++    ret = BN_div_recp(NULL, r, ca, recp, ctx);
++ err:
++    BN_CTX_end(ctx);
++    bn_check_top(r);
++    return (ret);
++}
++
++int BN_div_recp(BIGNUM *dv, BIGNUM *rem, const BIGNUM *m,
++                BN_RECP_CTX *recp, BN_CTX *ctx)
++{
++    int i, j, ret = 0;
++    BIGNUM *a, *b, *d, *r;
++
++    BN_CTX_start(ctx);
++    a = BN_CTX_get(ctx);
++    b = BN_CTX_get(ctx);
++    if (dv != NULL)
++        d = dv;
++    else
++        d = BN_CTX_get(ctx);
++    if (rem != NULL)
++        r = rem;
++    else
++        r = BN_CTX_get(ctx);
++    if (a == NULL || b == NULL || d == NULL || r == NULL)
++        goto err;
++
++    if (BN_ucmp(m, &(recp->N)) < 0) {
++        BN_zero(d);
++        if (!BN_copy(r, m)) {
++            BN_CTX_end(ctx);
++            return 0;
++        }
++        BN_CTX_end(ctx);
++        return (1);
++    }
++
++    /*
++     * We want the remainder Given input of ABCDEF / ab we need multiply
++     * ABCDEF by 3 digests of the reciprocal of ab
++     */
++
++    /* i := max(BN_num_bits(m), 2*BN_num_bits(N)) */
++    i = BN_num_bits(m);
++    j = recp->num_bits << 1;
++    if (j > i)
++        i = j;
++
++    /* Nr := round(2^i / N) */
++    if (i != recp->shift)
++        recp->shift = BN_reciprocal(&(recp->Nr), &(recp->N), i, ctx);
++    /* BN_reciprocal could have returned -1 for an error */
++    if (recp->shift == -1)
++        goto err;
++
++    /*-
++     * d := |round(round(m / 2^BN_num_bits(N)) * recp->Nr / 2^(i - BN_num_bits(N)))|
++     *    = |round(round(m / 2^BN_num_bits(N)) * round(2^i / N) / 2^(i - BN_num_bits(N)))|
++     *   <= |(m / 2^BN_num_bits(N)) * (2^i / N) * (2^BN_num_bits(N) / 2^i)|
++     *    = |m/N|
++     */
++    if (!BN_rshift(a, m, recp->num_bits))
++        goto err;
++    if (!BN_mul(b, a, &(recp->Nr), ctx))
++        goto err;
++    if (!BN_rshift(d, b, i - recp->num_bits))
++        goto err;
++    d->neg = 0;
++
++    if (!BN_mul(b, &(recp->N), d, ctx))
++        goto err;
++    if (!BN_usub(r, m, b))
++        goto err;
++    r->neg = 0;
++
++    j = 0;
++    while (BN_ucmp(r, &(recp->N)) >= 0) {
++        if (j++ > 2) {
++            BNerr(BN_F_BN_DIV_RECP, BN_R_BAD_RECIPROCAL);
++            goto err;
++        }
++        if (!BN_usub(r, r, &(recp->N)))
++            goto err;
++        if (!BN_add_word(d, 1))
++            goto err;
++    }
++
++    r->neg = BN_is_zero(r) ? 0 : m->neg;
++    d->neg = m->neg ^ recp->N.neg;
++    ret = 1;
++ err:
++    BN_CTX_end(ctx);
++    bn_check_top(dv);
++    bn_check_top(rem);
++    return (ret);
++}
++
++/*
++ * len is the expected size of the result We actually calculate with an extra
++ * word of precision, so we can do faster division if the remainder is not
++ * required.
++ */
++/* r := 2^len / m */
++int BN_reciprocal(BIGNUM *r, const BIGNUM *m, int len, BN_CTX *ctx)
++{
++    int ret = -1;
++    BIGNUM *t;
++
++    BN_CTX_start(ctx);
++    if ((t = BN_CTX_get(ctx)) == NULL)
++        goto err;
++
++    if (!BN_set_bit(t, len))
++        goto err;
++
++    if (!BN_div(r, NULL, t, m, ctx))
++        goto err;
++
++    ret = len;
++ err:
++    bn_check_top(r);
++    BN_CTX_end(ctx);
++    return (ret);
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/bn/bn_shift.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/bn/bn_shift.c
+new file mode 100644
+index 0000000..6a1eec8
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/bn/bn_shift.c
+@@ -0,0 +1,175 @@
++/*
++ * Copyright 1995-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include "internal/cryptlib.h"
++#include "bn_lcl.h"
++
++int BN_lshift1(BIGNUM *r, const BIGNUM *a)
++{
++    register BN_ULONG *ap, *rp, t, c;
++    int i;
++
++    bn_check_top(r);
++    bn_check_top(a);
++
++    if (r != a) {
++        r->neg = a->neg;
++        if (bn_wexpand(r, a->top + 1) == NULL)
++            return (0);
++        r->top = a->top;
++    } else {
++        if (bn_wexpand(r, a->top + 1) == NULL)
++            return (0);
++    }
++    ap = a->d;
++    rp = r->d;
++    c = 0;
++    for (i = 0; i < a->top; i++) {
++        t = *(ap++);
++        *(rp++) = ((t << 1) | c) & BN_MASK2;
++        c = (t & BN_TBIT) ? 1 : 0;
++    }
++    if (c) {
++        *rp = 1;
++        r->top++;
++    }
++    bn_check_top(r);
++    return (1);
++}
++
++int BN_rshift1(BIGNUM *r, const BIGNUM *a)
++{
++    BN_ULONG *ap, *rp, t, c;
++    int i, j;
++
++    bn_check_top(r);
++    bn_check_top(a);
++
++    if (BN_is_zero(a)) {
++        BN_zero(r);
++        return (1);
++    }
++    i = a->top;
++    ap = a->d;
++    j = i - (ap[i - 1] == 1);
++    if (a != r) {
++        if (bn_wexpand(r, j) == NULL)
++            return (0);
++        r->neg = a->neg;
++    }
++    rp = r->d;
++    t = ap[--i];
++    c = (t & 1) ? BN_TBIT : 0;
++    if (t >>= 1)
++        rp[i] = t;
++    while (i > 0) {
++        t = ap[--i];
++        rp[i] = ((t >> 1) & BN_MASK2) | c;
++        c = (t & 1) ? BN_TBIT : 0;
++    }
++    r->top = j;
++    if (!r->top)
++        r->neg = 0; /* don't allow negative zero */
++    bn_check_top(r);
++    return (1);
++}
++
++int BN_lshift(BIGNUM *r, const BIGNUM *a, int n)
++{
++    int i, nw, lb, rb;
++    BN_ULONG *t, *f;
++    BN_ULONG l;
++
++    bn_check_top(r);
++    bn_check_top(a);
++
++    if (n < 0) {
++        BNerr(BN_F_BN_LSHIFT, BN_R_INVALID_SHIFT);
++        return 0;
++    }
++
++    nw = n / BN_BITS2;
++    if (bn_wexpand(r, a->top + nw + 1) == NULL)
++        return (0);
++    r->neg = a->neg;
++    lb = n % BN_BITS2;
++    rb = BN_BITS2 - lb;
++    f = a->d;
++    t = r->d;
++    t[a->top + nw] = 0;
++    if (lb == 0)
++        for (i = a->top - 1; i >= 0; i--)
++            t[nw + i] = f[i];
++    else
++        for (i = a->top - 1; i >= 0; i--) {
++            l = f[i];
++            t[nw + i + 1] |= (l >> rb) & BN_MASK2;
++            t[nw + i] = (l << lb) & BN_MASK2;
++        }
++    memset(t, 0, sizeof(*t) * nw);
++    r->top = a->top + nw + 1;
++    bn_correct_top(r);
++    bn_check_top(r);
++    return (1);
++}
++
++int BN_rshift(BIGNUM *r, const BIGNUM *a, int n)
++{
++    int i, j, nw, lb, rb;
++    BN_ULONG *t, *f;
++    BN_ULONG l, tmp;
++
++    bn_check_top(r);
++    bn_check_top(a);
++
++    if (n < 0) {
++        BNerr(BN_F_BN_RSHIFT, BN_R_INVALID_SHIFT);
++        return 0;
++    }
++
++    nw = n / BN_BITS2;
++    rb = n % BN_BITS2;
++    lb = BN_BITS2 - rb;
++    if (nw >= a->top || a->top == 0) {
++        BN_zero(r);
++        return (1);
++    }
++    i = (BN_num_bits(a) - n + (BN_BITS2 - 1)) / BN_BITS2;
++    if (r != a) {
++        if (bn_wexpand(r, i) == NULL)
++            return (0);
++        r->neg = a->neg;
++    } else {
++        if (n == 0)
++            return 1;           /* or the copying loop will go berserk */
++    }
++
++    f = &(a->d[nw]);
++    t = r->d;
++    j = a->top - nw;
++    r->top = i;
++
++    if (rb == 0) {
++        for (i = j; i != 0; i--)
++            *(t++) = *(f++);
++    } else {
++        l = *(f++);
++        for (i = j - 1; i != 0; i--) {
++            tmp = (l >> rb) & BN_MASK2;
++            l = *(f++);
++            *(t++) = (tmp | (l << lb)) & BN_MASK2;
++        }
++        if ((l = (l >> rb) & BN_MASK2))
++            *(t) = l;
++    }
++    if (!r->top)
++        r->neg = 0; /* don't allow negative zero */
++    bn_check_top(r);
++    return (1);
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/bn/bn_sqr.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/bn/bn_sqr.c
+new file mode 100644
+index 0000000..44e7332
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/bn/bn_sqr.c
+@@ -0,0 +1,235 @@
++/*
++ * Copyright 1995-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include "internal/cryptlib.h"
++#include "bn_lcl.h"
++
++/* r must not be a */
++/*
++ * I've just gone over this and it is now %20 faster on x86 - eay - 27 Jun 96
++ */
++int BN_sqr(BIGNUM *r, const BIGNUM *a, BN_CTX *ctx)
++{
++    int max, al;
++    int ret = 0;
++    BIGNUM *tmp, *rr;
++
++    bn_check_top(a);
++
++    al = a->top;
++    if (al <= 0) {
++        r->top = 0;
++        r->neg = 0;
++        return 1;
++    }
++
++    BN_CTX_start(ctx);
++    rr = (a != r) ? r : BN_CTX_get(ctx);
++    tmp = BN_CTX_get(ctx);
++    if (!rr || !tmp)
++        goto err;
++
++    max = 2 * al;               /* Non-zero (from above) */
++    if (bn_wexpand(rr, max) == NULL)
++        goto err;
++
++    if (al == 4) {
++#ifndef BN_SQR_COMBA
++        BN_ULONG t[8];
++        bn_sqr_normal(rr->d, a->d, 4, t);
++#else
++        bn_sqr_comba4(rr->d, a->d);
++#endif
++    } else if (al == 8) {
++#ifndef BN_SQR_COMBA
++        BN_ULONG t[16];
++        bn_sqr_normal(rr->d, a->d, 8, t);
++#else
++        bn_sqr_comba8(rr->d, a->d);
++#endif
++    } else {
++#if defined(BN_RECURSION)
++        if (al < BN_SQR_RECURSIVE_SIZE_NORMAL) {
++            BN_ULONG t[BN_SQR_RECURSIVE_SIZE_NORMAL * 2];
++            bn_sqr_normal(rr->d, a->d, al, t);
++        } else {
++            int j, k;
++
++            j = BN_num_bits_word((BN_ULONG)al);
++            j = 1 << (j - 1);
++            k = j + j;
++            if (al == j) {
++                if (bn_wexpand(tmp, k * 2) == NULL)
++                    goto err;
++                bn_sqr_recursive(rr->d, a->d, al, tmp->d);
++            } else {
++                if (bn_wexpand(tmp, max) == NULL)
++                    goto err;
++                bn_sqr_normal(rr->d, a->d, al, tmp->d);
++            }
++        }
++#else
++        if (bn_wexpand(tmp, max) == NULL)
++            goto err;
++        bn_sqr_normal(rr->d, a->d, al, tmp->d);
++#endif
++    }
++
++    rr->neg = 0;
++    /*
++     * If the most-significant half of the top word of 'a' is zero, then the
++     * square of 'a' will max-1 words.
++     */
++    if (a->d[al - 1] == (a->d[al - 1] & BN_MASK2l))
++        rr->top = max - 1;
++    else
++        rr->top = max;
++    if (r != rr && BN_copy(r, rr) == NULL)
++        goto err;
++
++    ret = 1;
++ err:
++    bn_check_top(rr);
++    bn_check_top(tmp);
++    BN_CTX_end(ctx);
++    return (ret);
++}
++
++/* tmp must have 2*n words */
++void bn_sqr_normal(BN_ULONG *r, const BN_ULONG *a, int n, BN_ULONG *tmp)
++{
++    int i, j, max;
++    const BN_ULONG *ap;
++    BN_ULONG *rp;
++
++    max = n * 2;
++    ap = a;
++    rp = r;
++    rp[0] = rp[max - 1] = 0;
++    rp++;
++    j = n;
++
++    if (--j > 0) {
++        ap++;
++        rp[j] = bn_mul_words(rp, ap, j, ap[-1]);
++        rp += 2;
++    }
++
++    for (i = n - 2; i > 0; i--) {
++        j--;
++        ap++;
++        rp[j] = bn_mul_add_words(rp, ap, j, ap[-1]);
++        rp += 2;
++    }
++
++    bn_add_words(r, r, r, max);
++
++    /* There will not be a carry */
++
++    bn_sqr_words(tmp, a, n);
++
++    bn_add_words(r, r, tmp, max);
++}
++
++#ifdef BN_RECURSION
++/*-
++ * r is 2*n words in size,
++ * a and b are both n words in size.    (There's not actually a 'b' here ...)
++ * n must be a power of 2.
++ * We multiply and return the result.
++ * t must be 2*n words in size
++ * We calculate
++ * a[0]*b[0]
++ * a[0]*b[0]+a[1]*b[1]+(a[0]-a[1])*(b[1]-b[0])
++ * a[1]*b[1]
++ */
++void bn_sqr_recursive(BN_ULONG *r, const BN_ULONG *a, int n2, BN_ULONG *t)
++{
++    int n = n2 / 2;
++    int zero, c1;
++    BN_ULONG ln, lo, *p;
++
++    if (n2 == 4) {
++# ifndef BN_SQR_COMBA
++        bn_sqr_normal(r, a, 4, t);
++# else
++        bn_sqr_comba4(r, a);
++# endif
++        return;
++    } else if (n2 == 8) {
++# ifndef BN_SQR_COMBA
++        bn_sqr_normal(r, a, 8, t);
++# else
++        bn_sqr_comba8(r, a);
++# endif
++        return;
++    }
++    if (n2 < BN_SQR_RECURSIVE_SIZE_NORMAL) {
++        bn_sqr_normal(r, a, n2, t);
++        return;
++    }
++    /* r=(a[0]-a[1])*(a[1]-a[0]) */
++    c1 = bn_cmp_words(a, &(a[n]), n);
++    zero = 0;
++    if (c1 > 0)
++        bn_sub_words(t, a, &(a[n]), n);
++    else if (c1 < 0)
++        bn_sub_words(t, &(a[n]), a, n);
++    else
++        zero = 1;
++
++    /* The result will always be negative unless it is zero */
++    p = &(t[n2 * 2]);
++
++    if (!zero)
++        bn_sqr_recursive(&(t[n2]), t, n, p);
++    else
++        memset(&t[n2], 0, sizeof(*t) * n2);
++    bn_sqr_recursive(r, a, n, p);
++    bn_sqr_recursive(&(r[n2]), &(a[n]), n, p);
++
++    /*-
++     * t[32] holds (a[0]-a[1])*(a[1]-a[0]), it is negative or zero
++     * r[10] holds (a[0]*b[0])
++     * r[32] holds (b[1]*b[1])
++     */
++
++    c1 = (int)(bn_add_words(t, r, &(r[n2]), n2));
++
++    /* t[32] is negative */
++    c1 -= (int)(bn_sub_words(&(t[n2]), t, &(t[n2]), n2));
++
++    /*-
++     * t[32] holds (a[0]-a[1])*(a[1]-a[0])+(a[0]*a[0])+(a[1]*a[1])
++     * r[10] holds (a[0]*a[0])
++     * r[32] holds (a[1]*a[1])
++     * c1 holds the carry bits
++     */
++    c1 += (int)(bn_add_words(&(r[n]), &(r[n]), &(t[n2]), n2));
++    if (c1) {
++        p = &(r[n + n2]);
++        lo = *p;
++        ln = (lo + c1) & BN_MASK2;
++        *p = ln;
++
++        /*
++         * The overflow will stop before we over write words we should not
++         * overwrite
++         */
++        if (ln < (BN_ULONG)c1) {
++            do {
++                p++;
++                lo = *p;
++                ln = (lo + 1) & BN_MASK2;
++                *p = ln;
++            } while (ln == 0);
++        }
++    }
++}
++#endif
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/bn/bn_sqrt.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/bn/bn_sqrt.c
+new file mode 100644
+index 0000000..84376c7
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/bn/bn_sqrt.c
+@@ -0,0 +1,358 @@
++/*
++ * Copyright 2000-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include "internal/cryptlib.h"
++#include "bn_lcl.h"
++
++BIGNUM *BN_mod_sqrt(BIGNUM *in, const BIGNUM *a, const BIGNUM *p, BN_CTX *ctx)
++/*
++ * Returns 'ret' such that ret^2 == a (mod p), using the Tonelli/Shanks
++ * algorithm (cf. Henri Cohen, "A Course in Algebraic Computational Number
++ * Theory", algorithm 1.5.1). 'p' must be prime!
++ */
++{
++    BIGNUM *ret = in;
++    int err = 1;
++    int r;
++    BIGNUM *A, *b, *q, *t, *x, *y;
++    int e, i, j;
++
++    if (!BN_is_odd(p) || BN_abs_is_word(p, 1)) {
++        if (BN_abs_is_word(p, 2)) {
++            if (ret == NULL)
++                ret = BN_new();
++            if (ret == NULL)
++                goto end;
++            if (!BN_set_word(ret, BN_is_bit_set(a, 0))) {
++                if (ret != in)
++                    BN_free(ret);
++                return NULL;
++            }
++            bn_check_top(ret);
++            return ret;
++        }
++
++        BNerr(BN_F_BN_MOD_SQRT, BN_R_P_IS_NOT_PRIME);
++        return (NULL);
++    }
++
++    if (BN_is_zero(a) || BN_is_one(a)) {
++        if (ret == NULL)
++            ret = BN_new();
++        if (ret == NULL)
++            goto end;
++        if (!BN_set_word(ret, BN_is_one(a))) {
++            if (ret != in)
++                BN_free(ret);
++            return NULL;
++        }
++        bn_check_top(ret);
++        return ret;
++    }
++
++    BN_CTX_start(ctx);
++    A = BN_CTX_get(ctx);
++    b = BN_CTX_get(ctx);
++    q = BN_CTX_get(ctx);
++    t = BN_CTX_get(ctx);
++    x = BN_CTX_get(ctx);
++    y = BN_CTX_get(ctx);
++    if (y == NULL)
++        goto end;
++
++    if (ret == NULL)
++        ret = BN_new();
++    if (ret == NULL)
++        goto end;
++
++    /* A = a mod p */
++    if (!BN_nnmod(A, a, p, ctx))
++        goto end;
++
++    /* now write  |p| - 1  as  2^e*q  where  q  is odd */
++    e = 1;
++    while (!BN_is_bit_set(p, e))
++        e++;
++    /* we'll set  q  later (if needed) */
++
++    if (e == 1) {
++        /*-
++         * The easy case:  (|p|-1)/2  is odd, so 2 has an inverse
++         * modulo  (|p|-1)/2,  and square roots can be computed
++         * directly by modular exponentiation.
++         * We have
++         *     2 * (|p|+1)/4 == 1   (mod (|p|-1)/2),
++         * so we can use exponent  (|p|+1)/4,  i.e.  (|p|-3)/4 + 1.
++         */
++        if (!BN_rshift(q, p, 2))
++            goto end;
++        q->neg = 0;
++        if (!BN_add_word(q, 1))
++            goto end;
++        if (!BN_mod_exp(ret, A, q, p, ctx))
++            goto end;
++        err = 0;
++        goto vrfy;
++    }
++
++    if (e == 2) {
++        /*-
++         * |p| == 5  (mod 8)
++         *
++         * In this case  2  is always a non-square since
++         * Legendre(2,p) = (-1)^((p^2-1)/8)  for any odd prime.
++         * So if  a  really is a square, then  2*a  is a non-square.
++         * Thus for
++         *      b := (2*a)^((|p|-5)/8),
++         *      i := (2*a)*b^2
++         * we have
++         *     i^2 = (2*a)^((1 + (|p|-5)/4)*2)
++         *         = (2*a)^((p-1)/2)
++         *         = -1;
++         * so if we set
++         *      x := a*b*(i-1),
++         * then
++         *     x^2 = a^2 * b^2 * (i^2 - 2*i + 1)
++         *         = a^2 * b^2 * (-2*i)
++         *         = a*(-i)*(2*a*b^2)
++         *         = a*(-i)*i
++         *         = a.
++         *
++         * (This is due to A.O.L. Atkin,
++         * ,
++         * November 1992.)
++         */
++
++        /* t := 2*a */
++        if (!BN_mod_lshift1_quick(t, A, p))
++            goto end;
++
++        /* b := (2*a)^((|p|-5)/8) */
++        if (!BN_rshift(q, p, 3))
++            goto end;
++        q->neg = 0;
++        if (!BN_mod_exp(b, t, q, p, ctx))
++            goto end;
++
++        /* y := b^2 */
++        if (!BN_mod_sqr(y, b, p, ctx))
++            goto end;
++
++        /* t := (2*a)*b^2 - 1 */
++        if (!BN_mod_mul(t, t, y, p, ctx))
++            goto end;
++        if (!BN_sub_word(t, 1))
++            goto end;
++
++        /* x = a*b*t */
++        if (!BN_mod_mul(x, A, b, p, ctx))
++            goto end;
++        if (!BN_mod_mul(x, x, t, p, ctx))
++            goto end;
++
++        if (!BN_copy(ret, x))
++            goto end;
++        err = 0;
++        goto vrfy;
++    }
++
++    /*
++     * e > 2, so we really have to use the Tonelli/Shanks algorithm. First,
++     * find some y that is not a square.
++     */
++    if (!BN_copy(q, p))
++        goto end;               /* use 'q' as temp */
++    q->neg = 0;
++    i = 2;
++    do {
++        /*
++         * For efficiency, try small numbers first; if this fails, try random
++         * numbers.
++         */
++        if (i < 22) {
++            if (!BN_set_word(y, i))
++                goto end;
++        } else {
++            if (!BN_pseudo_rand(y, BN_num_bits(p), 0, 0))
++                goto end;
++            if (BN_ucmp(y, p) >= 0) {
++                if (!(p->neg ? BN_add : BN_sub) (y, y, p))
++                    goto end;
++            }
++            /* now 0 <= y < |p| */
++            if (BN_is_zero(y))
++                if (!BN_set_word(y, i))
++                    goto end;
++        }
++
++        r = BN_kronecker(y, q, ctx); /* here 'q' is |p| */
++        if (r < -1)
++            goto end;
++        if (r == 0) {
++            /* m divides p */
++            BNerr(BN_F_BN_MOD_SQRT, BN_R_P_IS_NOT_PRIME);
++            goto end;
++        }
++    }
++    while (r == 1 && ++i < 82);
++
++    if (r != -1) {
++        /*
++         * Many rounds and still no non-square -- this is more likely a bug
++         * than just bad luck. Even if p is not prime, we should have found
++         * some y such that r == -1.
++         */
++        BNerr(BN_F_BN_MOD_SQRT, BN_R_TOO_MANY_ITERATIONS);
++        goto end;
++    }
++
++    /* Here's our actual 'q': */
++    if (!BN_rshift(q, q, e))
++        goto end;
++
++    /*
++     * Now that we have some non-square, we can find an element of order 2^e
++     * by computing its q'th power.
++     */
++    if (!BN_mod_exp(y, y, q, p, ctx))
++        goto end;
++    if (BN_is_one(y)) {
++        BNerr(BN_F_BN_MOD_SQRT, BN_R_P_IS_NOT_PRIME);
++        goto end;
++    }
++
++    /*-
++     * Now we know that (if  p  is indeed prime) there is an integer
++     * k,  0 <= k < 2^e,  such that
++     *
++     *      a^q * y^k == 1   (mod p).
++     *
++     * As  a^q  is a square and  y  is not,  k  must be even.
++     * q+1  is even, too, so there is an element
++     *
++     *     X := a^((q+1)/2) * y^(k/2),
++     *
++     * and it satisfies
++     *
++     *     X^2 = a^q * a     * y^k
++     *         = a,
++     *
++     * so it is the square root that we are looking for.
++     */
++
++    /* t := (q-1)/2  (note that  q  is odd) */
++    if (!BN_rshift1(t, q))
++        goto end;
++
++    /* x := a^((q-1)/2) */
++    if (BN_is_zero(t)) {        /* special case: p = 2^e + 1 */
++        if (!BN_nnmod(t, A, p, ctx))
++            goto end;
++        if (BN_is_zero(t)) {
++            /* special case: a == 0  (mod p) */
++            BN_zero(ret);
++            err = 0;
++            goto end;
++        } else if (!BN_one(x))
++            goto end;
++    } else {
++        if (!BN_mod_exp(x, A, t, p, ctx))
++            goto end;
++        if (BN_is_zero(x)) {
++            /* special case: a == 0  (mod p) */
++            BN_zero(ret);
++            err = 0;
++            goto end;
++        }
++    }
++
++    /* b := a*x^2  (= a^q) */
++    if (!BN_mod_sqr(b, x, p, ctx))
++        goto end;
++    if (!BN_mod_mul(b, b, A, p, ctx))
++        goto end;
++
++    /* x := a*x    (= a^((q+1)/2)) */
++    if (!BN_mod_mul(x, x, A, p, ctx))
++        goto end;
++
++    while (1) {
++        /*-
++         * Now  b  is  a^q * y^k  for some even  k  (0 <= k < 2^E
++         * where  E  refers to the original value of  e,  which we
++         * don't keep in a variable),  and  x  is  a^((q+1)/2) * y^(k/2).
++         *
++         * We have  a*b = x^2,
++         *    y^2^(e-1) = -1,
++         *    b^2^(e-1) = 1.
++         */
++
++        if (BN_is_one(b)) {
++            if (!BN_copy(ret, x))
++                goto end;
++            err = 0;
++            goto vrfy;
++        }
++
++        /* find smallest  i  such that  b^(2^i) = 1 */
++        i = 1;
++        if (!BN_mod_sqr(t, b, p, ctx))
++            goto end;
++        while (!BN_is_one(t)) {
++            i++;
++            if (i == e) {
++                BNerr(BN_F_BN_MOD_SQRT, BN_R_NOT_A_SQUARE);
++                goto end;
++            }
++            if (!BN_mod_mul(t, t, t, p, ctx))
++                goto end;
++        }
++
++        /* t := y^2^(e - i - 1) */
++        if (!BN_copy(t, y))
++            goto end;
++        for (j = e - i - 1; j > 0; j--) {
++            if (!BN_mod_sqr(t, t, p, ctx))
++                goto end;
++        }
++        if (!BN_mod_mul(y, t, t, p, ctx))
++            goto end;
++        if (!BN_mod_mul(x, x, t, p, ctx))
++            goto end;
++        if (!BN_mod_mul(b, b, y, p, ctx))
++            goto end;
++        e = i;
++    }
++
++ vrfy:
++    if (!err) {
++        /*
++         * verify the result -- the input might have been not a square (test
++         * added in 0.9.8)
++         */
++
++        if (!BN_mod_sqr(x, ret, p, ctx))
++            err = 1;
++
++        if (!err && 0 != BN_cmp(x, A)) {
++            BNerr(BN_F_BN_MOD_SQRT, BN_R_NOT_A_SQUARE);
++            err = 1;
++        }
++    }
++
++ end:
++    if (err) {
++        if (ret != in)
++            BN_clear_free(ret);
++        ret = NULL;
++    }
++    BN_CTX_end(ctx);
++    bn_check_top(ret);
++    return ret;
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/bn/bn_srp.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/bn/bn_srp.c
+new file mode 100644
+index 0000000..58b1691
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/bn/bn_srp.c
+@@ -0,0 +1,545 @@
++/*
++ * Copyright 2014-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include "bn_lcl.h"
++#include "e_os.h"
++
++#ifndef OPENSSL_NO_SRP
++
++#include 
++#include 
++
++# if (BN_BYTES == 8)
++#  if (defined(_WIN32) || defined(_WIN64)) && !defined(__MINGW32__)
++#   define bn_pack4(a1,a2,a3,a4) ((a1##UI64<<48)|(a2##UI64<<32)|(a3##UI64<<16)|a4##UI64)
++#  elif defined(__arch64__)
++#   define bn_pack4(a1,a2,a3,a4) ((a1##UL<<48)|(a2##UL<<32)|(a3##UL<<16)|a4##UL)
++#  else
++#   define bn_pack4(a1,a2,a3,a4) ((a1##ULL<<48)|(a2##ULL<<32)|(a3##ULL<<16)|a4##ULL)
++#  endif
++# elif (BN_BYTES == 4)
++#  define bn_pack4(a1,a2,a3,a4)  ((a3##UL<<16)|a4##UL), ((a1##UL<<16)|a2##UL)
++# else
++#  error "unsupported BN_BYTES"
++# endif
++
++static const BN_ULONG bn_group_1024_value[] = {
++    bn_pack4(0x9FC6, 0x1D2F, 0xC0EB, 0x06E3),
++    bn_pack4(0xFD51, 0x38FE, 0x8376, 0x435B),
++    bn_pack4(0x2FD4, 0xCBF4, 0x976E, 0xAA9A),
++    bn_pack4(0x68ED, 0xBC3C, 0x0572, 0x6CC0),
++    bn_pack4(0xC529, 0xF566, 0x660E, 0x57EC),
++    bn_pack4(0x8255, 0x9B29, 0x7BCF, 0x1885),
++    bn_pack4(0xCE8E, 0xF4AD, 0x69B1, 0x5D49),
++    bn_pack4(0x5DC7, 0xD7B4, 0x6154, 0xD6B6),
++    bn_pack4(0x8E49, 0x5C1D, 0x6089, 0xDAD1),
++    bn_pack4(0xE0D5, 0xD8E2, 0x50B9, 0x8BE4),
++    bn_pack4(0x383B, 0x4813, 0xD692, 0xC6E0),
++    bn_pack4(0xD674, 0xDF74, 0x96EA, 0x81D3),
++    bn_pack4(0x9EA2, 0x314C, 0x9C25, 0x6576),
++    bn_pack4(0x6072, 0x6187, 0x75FF, 0x3C0B),
++    bn_pack4(0x9C33, 0xF80A, 0xFA8F, 0xC5E8),
++    bn_pack4(0xEEAF, 0x0AB9, 0xADB3, 0x8DD6)
++};
++
++const BIGNUM bn_group_1024 = {
++    (BN_ULONG *)bn_group_1024_value,
++    OSSL_NELEM(bn_group_1024_value),
++    OSSL_NELEM(bn_group_1024_value),
++    0,
++    BN_FLG_STATIC_DATA
++};
++
++static const BN_ULONG bn_group_1536_value[] = {
++    bn_pack4(0xCF76, 0xE3FE, 0xD135, 0xF9BB),
++    bn_pack4(0x1518, 0x0F93, 0x499A, 0x234D),
++    bn_pack4(0x8CE7, 0xA28C, 0x2442, 0xC6F3),
++    bn_pack4(0x5A02, 0x1FFF, 0x5E91, 0x479E),
++    bn_pack4(0x7F8A, 0x2FE9, 0xB8B5, 0x292E),
++    bn_pack4(0x837C, 0x264A, 0xE3A9, 0xBEB8),
++    bn_pack4(0xE442, 0x734A, 0xF7CC, 0xB7AE),
++    bn_pack4(0x6577, 0x2E43, 0x7D6C, 0x7F8C),
++    bn_pack4(0xDB2F, 0xD53D, 0x24B7, 0xC486),
++    bn_pack4(0x6EDF, 0x0195, 0x3934, 0x9627),
++    bn_pack4(0x158B, 0xFD3E, 0x2B9C, 0x8CF5),
++    bn_pack4(0x764E, 0x3F4B, 0x53DD, 0x9DA1),
++    bn_pack4(0x4754, 0x8381, 0xDBC5, 0xB1FC),
++    bn_pack4(0x9B60, 0x9E0B, 0xE3BA, 0xB63D),
++    bn_pack4(0x8134, 0xB1C8, 0xB979, 0x8914),
++    bn_pack4(0xDF02, 0x8A7C, 0xEC67, 0xF0D0),
++    bn_pack4(0x80B6, 0x55BB, 0x9A22, 0xE8DC),
++    bn_pack4(0x1558, 0x903B, 0xA0D0, 0xF843),
++    bn_pack4(0x51C6, 0xA94B, 0xE460, 0x7A29),
++    bn_pack4(0x5F4F, 0x5F55, 0x6E27, 0xCBDE),
++    bn_pack4(0xBEEE, 0xA961, 0x4B19, 0xCC4D),
++    bn_pack4(0xDBA5, 0x1DF4, 0x99AC, 0x4C80),
++    bn_pack4(0xB1F1, 0x2A86, 0x17A4, 0x7BBB),
++    bn_pack4(0x9DEF, 0x3CAF, 0xB939, 0x277A)
++};
++
++const BIGNUM bn_group_1536 = {
++    (BN_ULONG *)bn_group_1536_value,
++    OSSL_NELEM(bn_group_1536_value),
++    OSSL_NELEM(bn_group_1536_value),
++    0,
++    BN_FLG_STATIC_DATA
++};
++
++static const BN_ULONG bn_group_2048_value[] = {
++    bn_pack4(0x0FA7, 0x111F, 0x9E4A, 0xFF73),
++    bn_pack4(0x9B65, 0xE372, 0xFCD6, 0x8EF2),
++    bn_pack4(0x35DE, 0x236D, 0x525F, 0x5475),
++    bn_pack4(0x94B5, 0xC803, 0xD89F, 0x7AE4),
++    bn_pack4(0x71AE, 0x35F8, 0xE9DB, 0xFBB6),
++    bn_pack4(0x2A56, 0x98F3, 0xA8D0, 0xC382),
++    bn_pack4(0x9CCC, 0x041C, 0x7BC3, 0x08D8),
++    bn_pack4(0xAF87, 0x4E73, 0x03CE, 0x5329),
++    bn_pack4(0x6160, 0x2790, 0x04E5, 0x7AE6),
++    bn_pack4(0x032C, 0xFBDB, 0xF52F, 0xB378),
++    bn_pack4(0x5EA7, 0x7A27, 0x75D2, 0xECFA),
++    bn_pack4(0x5445, 0x23B5, 0x24B0, 0xD57D),
++    bn_pack4(0x5B9D, 0x32E6, 0x88F8, 0x7748),
++    bn_pack4(0xF1D2, 0xB907, 0x8717, 0x461A),
++    bn_pack4(0x76BD, 0x207A, 0x436C, 0x6481),
++    bn_pack4(0xCA97, 0xB43A, 0x23FB, 0x8016),
++    bn_pack4(0x1D28, 0x1E44, 0x6B14, 0x773B),
++    bn_pack4(0x7359, 0xD041, 0xD5C3, 0x3EA7),
++    bn_pack4(0xA80D, 0x740A, 0xDBF4, 0xFF74),
++    bn_pack4(0x55F9, 0x7993, 0xEC97, 0x5EEA),
++    bn_pack4(0x2918, 0xA996, 0x2F0B, 0x93B8),
++    bn_pack4(0x661A, 0x05FB, 0xD5FA, 0xAAE8),
++    bn_pack4(0xCF60, 0x9517, 0x9A16, 0x3AB3),
++    bn_pack4(0xE808, 0x3969, 0xEDB7, 0x67B0),
++    bn_pack4(0xCD7F, 0x48A9, 0xDA04, 0xFD50),
++    bn_pack4(0xD523, 0x12AB, 0x4B03, 0x310D),
++    bn_pack4(0x8193, 0xE075, 0x7767, 0xA13D),
++    bn_pack4(0xA373, 0x29CB, 0xB4A0, 0x99ED),
++    bn_pack4(0xFC31, 0x9294, 0x3DB5, 0x6050),
++    bn_pack4(0xAF72, 0xB665, 0x1987, 0xEE07),
++    bn_pack4(0xF166, 0xDE5E, 0x1389, 0x582F),
++    bn_pack4(0xAC6B, 0xDB41, 0x324A, 0x9A9B)
++};
++
++const BIGNUM bn_group_2048 = {
++    (BN_ULONG *)bn_group_2048_value,
++    OSSL_NELEM(bn_group_2048_value),
++    OSSL_NELEM(bn_group_2048_value),
++    0,
++    BN_FLG_STATIC_DATA
++};
++
++static const BN_ULONG bn_group_3072_value[] = {
++    bn_pack4(0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF),
++    bn_pack4(0x4B82, 0xD120, 0xA93A, 0xD2CA),
++    bn_pack4(0x43DB, 0x5BFC, 0xE0FD, 0x108E),
++    bn_pack4(0x08E2, 0x4FA0, 0x74E5, 0xAB31),
++    bn_pack4(0x7709, 0x88C0, 0xBAD9, 0x46E2),
++    bn_pack4(0xBBE1, 0x1757, 0x7A61, 0x5D6C),
++    bn_pack4(0x521F, 0x2B18, 0x177B, 0x200C),
++    bn_pack4(0xD876, 0x0273, 0x3EC8, 0x6A64),
++    bn_pack4(0xF12F, 0xFA06, 0xD98A, 0x0864),
++    bn_pack4(0xCEE3, 0xD226, 0x1AD2, 0xEE6B),
++    bn_pack4(0x1E8C, 0x94E0, 0x4A25, 0x619D),
++    bn_pack4(0xABF5, 0xAE8C, 0xDB09, 0x33D7),
++    bn_pack4(0xB397, 0x0F85, 0xA6E1, 0xE4C7),
++    bn_pack4(0x8AEA, 0x7157, 0x5D06, 0x0C7D),
++    bn_pack4(0xECFB, 0x8504, 0x58DB, 0xEF0A),
++    bn_pack4(0xA855, 0x21AB, 0xDF1C, 0xBA64),
++    bn_pack4(0xAD33, 0x170D, 0x0450, 0x7A33),
++    bn_pack4(0x1572, 0x8E5A, 0x8AAA, 0xC42D),
++    bn_pack4(0x15D2, 0x2618, 0x98FA, 0x0510),
++    bn_pack4(0x3995, 0x497C, 0xEA95, 0x6AE5),
++    bn_pack4(0xDE2B, 0xCBF6, 0x9558, 0x1718),
++    bn_pack4(0xB5C5, 0x5DF0, 0x6F4C, 0x52C9),
++    bn_pack4(0x9B27, 0x83A2, 0xEC07, 0xA28F),
++    bn_pack4(0xE39E, 0x772C, 0x180E, 0x8603),
++    bn_pack4(0x3290, 0x5E46, 0x2E36, 0xCE3B),
++    bn_pack4(0xF174, 0x6C08, 0xCA18, 0x217C),
++    bn_pack4(0x670C, 0x354E, 0x4ABC, 0x9804),
++    bn_pack4(0x9ED5, 0x2907, 0x7096, 0x966D),
++    bn_pack4(0x1C62, 0xF356, 0x2085, 0x52BB),
++    bn_pack4(0x8365, 0x5D23, 0xDCA3, 0xAD96),
++    bn_pack4(0x6916, 0x3FA8, 0xFD24, 0xCF5F),
++    bn_pack4(0x98DA, 0x4836, 0x1C55, 0xD39A),
++    bn_pack4(0xC200, 0x7CB8, 0xA163, 0xBF05),
++    bn_pack4(0x4928, 0x6651, 0xECE4, 0x5B3D),
++    bn_pack4(0xAE9F, 0x2411, 0x7C4B, 0x1FE6),
++    bn_pack4(0xEE38, 0x6BFB, 0x5A89, 0x9FA5),
++    bn_pack4(0x0BFF, 0x5CB6, 0xF406, 0xB7ED),
++    bn_pack4(0xF44C, 0x42E9, 0xA637, 0xED6B),
++    bn_pack4(0xE485, 0xB576, 0x625E, 0x7EC6),
++    bn_pack4(0x4FE1, 0x356D, 0x6D51, 0xC245),
++    bn_pack4(0x302B, 0x0A6D, 0xF25F, 0x1437),
++    bn_pack4(0xEF95, 0x19B3, 0xCD3A, 0x431B),
++    bn_pack4(0x514A, 0x0879, 0x8E34, 0x04DD),
++    bn_pack4(0x020B, 0xBEA6, 0x3B13, 0x9B22),
++    bn_pack4(0x2902, 0x4E08, 0x8A67, 0xCC74),
++    bn_pack4(0xC4C6, 0x628B, 0x80DC, 0x1CD1),
++    bn_pack4(0xC90F, 0xDAA2, 0x2168, 0xC234),
++    bn_pack4(0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF)
++};
++
++const BIGNUM bn_group_3072 = {
++    (BN_ULONG *)bn_group_3072_value,
++    OSSL_NELEM(bn_group_3072_value),
++    OSSL_NELEM(bn_group_3072_value),
++    0,
++    BN_FLG_STATIC_DATA
++};
++
++static const BN_ULONG bn_group_4096_value[] = {
++    bn_pack4(0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF),
++    bn_pack4(0x4DF4, 0x35C9, 0x3406, 0x3199),
++    bn_pack4(0x86FF, 0xB7DC, 0x90A6, 0xC08F),
++    bn_pack4(0x93B4, 0xEA98, 0x8D8F, 0xDDC1),
++    bn_pack4(0xD006, 0x9127, 0xD5B0, 0x5AA9),
++    bn_pack4(0xB81B, 0xDD76, 0x2170, 0x481C),
++    bn_pack4(0x1F61, 0x2970, 0xCEE2, 0xD7AF),
++    bn_pack4(0x233B, 0xA186, 0x515B, 0xE7ED),
++    bn_pack4(0x99B2, 0x964F, 0xA090, 0xC3A2),
++    bn_pack4(0x287C, 0x5947, 0x4E6B, 0xC05D),
++    bn_pack4(0x2E8E, 0xFC14, 0x1FBE, 0xCAA6),
++    bn_pack4(0xDBBB, 0xC2DB, 0x04DE, 0x8EF9),
++    bn_pack4(0x2583, 0xE9CA, 0x2AD4, 0x4CE8),
++    bn_pack4(0x1A94, 0x6834, 0xB615, 0x0BDA),
++    bn_pack4(0x99C3, 0x2718, 0x6AF4, 0xE23C),
++    bn_pack4(0x8871, 0x9A10, 0xBDBA, 0x5B26),
++    bn_pack4(0x1A72, 0x3C12, 0xA787, 0xE6D7),
++    bn_pack4(0x4B82, 0xD120, 0xA921, 0x0801),
++    bn_pack4(0x43DB, 0x5BFC, 0xE0FD, 0x108E),
++    bn_pack4(0x08E2, 0x4FA0, 0x74E5, 0xAB31),
++    bn_pack4(0x7709, 0x88C0, 0xBAD9, 0x46E2),
++    bn_pack4(0xBBE1, 0x1757, 0x7A61, 0x5D6C),
++    bn_pack4(0x521F, 0x2B18, 0x177B, 0x200C),
++    bn_pack4(0xD876, 0x0273, 0x3EC8, 0x6A64),
++    bn_pack4(0xF12F, 0xFA06, 0xD98A, 0x0864),
++    bn_pack4(0xCEE3, 0xD226, 0x1AD2, 0xEE6B),
++    bn_pack4(0x1E8C, 0x94E0, 0x4A25, 0x619D),
++    bn_pack4(0xABF5, 0xAE8C, 0xDB09, 0x33D7),
++    bn_pack4(0xB397, 0x0F85, 0xA6E1, 0xE4C7),
++    bn_pack4(0x8AEA, 0x7157, 0x5D06, 0x0C7D),
++    bn_pack4(0xECFB, 0x8504, 0x58DB, 0xEF0A),
++    bn_pack4(0xA855, 0x21AB, 0xDF1C, 0xBA64),
++    bn_pack4(0xAD33, 0x170D, 0x0450, 0x7A33),
++    bn_pack4(0x1572, 0x8E5A, 0x8AAA, 0xC42D),
++    bn_pack4(0x15D2, 0x2618, 0x98FA, 0x0510),
++    bn_pack4(0x3995, 0x497C, 0xEA95, 0x6AE5),
++    bn_pack4(0xDE2B, 0xCBF6, 0x9558, 0x1718),
++    bn_pack4(0xB5C5, 0x5DF0, 0x6F4C, 0x52C9),
++    bn_pack4(0x9B27, 0x83A2, 0xEC07, 0xA28F),
++    bn_pack4(0xE39E, 0x772C, 0x180E, 0x8603),
++    bn_pack4(0x3290, 0x5E46, 0x2E36, 0xCE3B),
++    bn_pack4(0xF174, 0x6C08, 0xCA18, 0x217C),
++    bn_pack4(0x670C, 0x354E, 0x4ABC, 0x9804),
++    bn_pack4(0x9ED5, 0x2907, 0x7096, 0x966D),
++    bn_pack4(0x1C62, 0xF356, 0x2085, 0x52BB),
++    bn_pack4(0x8365, 0x5D23, 0xDCA3, 0xAD96),
++    bn_pack4(0x6916, 0x3FA8, 0xFD24, 0xCF5F),
++    bn_pack4(0x98DA, 0x4836, 0x1C55, 0xD39A),
++    bn_pack4(0xC200, 0x7CB8, 0xA163, 0xBF05),
++    bn_pack4(0x4928, 0x6651, 0xECE4, 0x5B3D),
++    bn_pack4(0xAE9F, 0x2411, 0x7C4B, 0x1FE6),
++    bn_pack4(0xEE38, 0x6BFB, 0x5A89, 0x9FA5),
++    bn_pack4(0x0BFF, 0x5CB6, 0xF406, 0xB7ED),
++    bn_pack4(0xF44C, 0x42E9, 0xA637, 0xED6B),
++    bn_pack4(0xE485, 0xB576, 0x625E, 0x7EC6),
++    bn_pack4(0x4FE1, 0x356D, 0x6D51, 0xC245),
++    bn_pack4(0x302B, 0x0A6D, 0xF25F, 0x1437),
++    bn_pack4(0xEF95, 0x19B3, 0xCD3A, 0x431B),
++    bn_pack4(0x514A, 0x0879, 0x8E34, 0x04DD),
++    bn_pack4(0x020B, 0xBEA6, 0x3B13, 0x9B22),
++    bn_pack4(0x2902, 0x4E08, 0x8A67, 0xCC74),
++    bn_pack4(0xC4C6, 0x628B, 0x80DC, 0x1CD1),
++    bn_pack4(0xC90F, 0xDAA2, 0x2168, 0xC234),
++    bn_pack4(0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF)
++};
++
++const BIGNUM bn_group_4096 = {
++    (BN_ULONG *)bn_group_4096_value,
++    OSSL_NELEM(bn_group_4096_value),
++    OSSL_NELEM(bn_group_4096_value),
++    0,
++    BN_FLG_STATIC_DATA
++};
++
++static const BN_ULONG bn_group_6144_value[] = {
++    bn_pack4(0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF),
++    bn_pack4(0xE694, 0xF91E, 0x6DCC, 0x4024),
++    bn_pack4(0x12BF, 0x2D5B, 0x0B74, 0x74D6),
++    bn_pack4(0x043E, 0x8F66, 0x3F48, 0x60EE),
++    bn_pack4(0x387F, 0xE8D7, 0x6E3C, 0x0468),
++    bn_pack4(0xDA56, 0xC9EC, 0x2EF2, 0x9632),
++    bn_pack4(0xEB19, 0xCCB1, 0xA313, 0xD55C),
++    bn_pack4(0xF550, 0xAA3D, 0x8A1F, 0xBFF0),
++    bn_pack4(0x06A1, 0xD58B, 0xB7C5, 0xDA76),
++    bn_pack4(0xA797, 0x15EE, 0xF29B, 0xE328),
++    bn_pack4(0x14CC, 0x5ED2, 0x0F80, 0x37E0),
++    bn_pack4(0xCC8F, 0x6D7E, 0xBF48, 0xE1D8),
++    bn_pack4(0x4BD4, 0x07B2, 0x2B41, 0x54AA),
++    bn_pack4(0x0F1D, 0x45B7, 0xFF58, 0x5AC5),
++    bn_pack4(0x23A9, 0x7A7E, 0x36CC, 0x88BE),
++    bn_pack4(0x59E7, 0xC97F, 0xBEC7, 0xE8F3),
++    bn_pack4(0xB5A8, 0x4031, 0x900B, 0x1C9E),
++    bn_pack4(0xD55E, 0x702F, 0x4698, 0x0C82),
++    bn_pack4(0xF482, 0xD7CE, 0x6E74, 0xFEF6),
++    bn_pack4(0xF032, 0xEA15, 0xD172, 0x1D03),
++    bn_pack4(0x5983, 0xCA01, 0xC64B, 0x92EC),
++    bn_pack4(0x6FB8, 0xF401, 0x378C, 0xD2BF),
++    bn_pack4(0x3320, 0x5151, 0x2BD7, 0xAF42),
++    bn_pack4(0xDB7F, 0x1447, 0xE6CC, 0x254B),
++    bn_pack4(0x44CE, 0x6CBA, 0xCED4, 0xBB1B),
++    bn_pack4(0xDA3E, 0xDBEB, 0xCF9B, 0x14ED),
++    bn_pack4(0x1797, 0x27B0, 0x865A, 0x8918),
++    bn_pack4(0xB06A, 0x53ED, 0x9027, 0xD831),
++    bn_pack4(0xE5DB, 0x382F, 0x4130, 0x01AE),
++    bn_pack4(0xF8FF, 0x9406, 0xAD9E, 0x530E),
++    bn_pack4(0xC975, 0x1E76, 0x3DBA, 0x37BD),
++    bn_pack4(0xC1D4, 0xDCB2, 0x6026, 0x46DE),
++    bn_pack4(0x36C3, 0xFAB4, 0xD27C, 0x7026),
++    bn_pack4(0x4DF4, 0x35C9, 0x3402, 0x8492),
++    bn_pack4(0x86FF, 0xB7DC, 0x90A6, 0xC08F),
++    bn_pack4(0x93B4, 0xEA98, 0x8D8F, 0xDDC1),
++    bn_pack4(0xD006, 0x9127, 0xD5B0, 0x5AA9),
++    bn_pack4(0xB81B, 0xDD76, 0x2170, 0x481C),
++    bn_pack4(0x1F61, 0x2970, 0xCEE2, 0xD7AF),
++    bn_pack4(0x233B, 0xA186, 0x515B, 0xE7ED),
++    bn_pack4(0x99B2, 0x964F, 0xA090, 0xC3A2),
++    bn_pack4(0x287C, 0x5947, 0x4E6B, 0xC05D),
++    bn_pack4(0x2E8E, 0xFC14, 0x1FBE, 0xCAA6),
++    bn_pack4(0xDBBB, 0xC2DB, 0x04DE, 0x8EF9),
++    bn_pack4(0x2583, 0xE9CA, 0x2AD4, 0x4CE8),
++    bn_pack4(0x1A94, 0x6834, 0xB615, 0x0BDA),
++    bn_pack4(0x99C3, 0x2718, 0x6AF4, 0xE23C),
++    bn_pack4(0x8871, 0x9A10, 0xBDBA, 0x5B26),
++    bn_pack4(0x1A72, 0x3C12, 0xA787, 0xE6D7),
++    bn_pack4(0x4B82, 0xD120, 0xA921, 0x0801),
++    bn_pack4(0x43DB, 0x5BFC, 0xE0FD, 0x108E),
++    bn_pack4(0x08E2, 0x4FA0, 0x74E5, 0xAB31),
++    bn_pack4(0x7709, 0x88C0, 0xBAD9, 0x46E2),
++    bn_pack4(0xBBE1, 0x1757, 0x7A61, 0x5D6C),
++    bn_pack4(0x521F, 0x2B18, 0x177B, 0x200C),
++    bn_pack4(0xD876, 0x0273, 0x3EC8, 0x6A64),
++    bn_pack4(0xF12F, 0xFA06, 0xD98A, 0x0864),
++    bn_pack4(0xCEE3, 0xD226, 0x1AD2, 0xEE6B),
++    bn_pack4(0x1E8C, 0x94E0, 0x4A25, 0x619D),
++    bn_pack4(0xABF5, 0xAE8C, 0xDB09, 0x33D7),
++    bn_pack4(0xB397, 0x0F85, 0xA6E1, 0xE4C7),
++    bn_pack4(0x8AEA, 0x7157, 0x5D06, 0x0C7D),
++    bn_pack4(0xECFB, 0x8504, 0x58DB, 0xEF0A),
++    bn_pack4(0xA855, 0x21AB, 0xDF1C, 0xBA64),
++    bn_pack4(0xAD33, 0x170D, 0x0450, 0x7A33),
++    bn_pack4(0x1572, 0x8E5A, 0x8AAA, 0xC42D),
++    bn_pack4(0x15D2, 0x2618, 0x98FA, 0x0510),
++    bn_pack4(0x3995, 0x497C, 0xEA95, 0x6AE5),
++    bn_pack4(0xDE2B, 0xCBF6, 0x9558, 0x1718),
++    bn_pack4(0xB5C5, 0x5DF0, 0x6F4C, 0x52C9),
++    bn_pack4(0x9B27, 0x83A2, 0xEC07, 0xA28F),
++    bn_pack4(0xE39E, 0x772C, 0x180E, 0x8603),
++    bn_pack4(0x3290, 0x5E46, 0x2E36, 0xCE3B),
++    bn_pack4(0xF174, 0x6C08, 0xCA18, 0x217C),
++    bn_pack4(0x670C, 0x354E, 0x4ABC, 0x9804),
++    bn_pack4(0x9ED5, 0x2907, 0x7096, 0x966D),
++    bn_pack4(0x1C62, 0xF356, 0x2085, 0x52BB),
++    bn_pack4(0x8365, 0x5D23, 0xDCA3, 0xAD96),
++    bn_pack4(0x6916, 0x3FA8, 0xFD24, 0xCF5F),
++    bn_pack4(0x98DA, 0x4836, 0x1C55, 0xD39A),
++    bn_pack4(0xC200, 0x7CB8, 0xA163, 0xBF05),
++    bn_pack4(0x4928, 0x6651, 0xECE4, 0x5B3D),
++    bn_pack4(0xAE9F, 0x2411, 0x7C4B, 0x1FE6),
++    bn_pack4(0xEE38, 0x6BFB, 0x5A89, 0x9FA5),
++    bn_pack4(0x0BFF, 0x5CB6, 0xF406, 0xB7ED),
++    bn_pack4(0xF44C, 0x42E9, 0xA637, 0xED6B),
++    bn_pack4(0xE485, 0xB576, 0x625E, 0x7EC6),
++    bn_pack4(0x4FE1, 0x356D, 0x6D51, 0xC245),
++    bn_pack4(0x302B, 0x0A6D, 0xF25F, 0x1437),
++    bn_pack4(0xEF95, 0x19B3, 0xCD3A, 0x431B),
++    bn_pack4(0x514A, 0x0879, 0x8E34, 0x04DD),
++    bn_pack4(0x020B, 0xBEA6, 0x3B13, 0x9B22),
++    bn_pack4(0x2902, 0x4E08, 0x8A67, 0xCC74),
++    bn_pack4(0xC4C6, 0x628B, 0x80DC, 0x1CD1),
++    bn_pack4(0xC90F, 0xDAA2, 0x2168, 0xC234),
++    bn_pack4(0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF)
++};
++
++const BIGNUM bn_group_6144 = {
++    (BN_ULONG *)bn_group_6144_value,
++    OSSL_NELEM(bn_group_6144_value),
++    OSSL_NELEM(bn_group_6144_value),
++    0,
++    BN_FLG_STATIC_DATA
++};
++
++static const BN_ULONG bn_group_8192_value[] = {
++    bn_pack4(0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF),
++    bn_pack4(0x60C9, 0x80DD, 0x98ED, 0xD3DF),
++    bn_pack4(0xC81F, 0x56E8, 0x80B9, 0x6E71),
++    bn_pack4(0x9E30, 0x50E2, 0x7656, 0x94DF),
++    bn_pack4(0x9558, 0xE447, 0x5677, 0xE9AA),
++    bn_pack4(0xC919, 0x0DA6, 0xFC02, 0x6E47),
++    bn_pack4(0x889A, 0x002E, 0xD5EE, 0x382B),
++    bn_pack4(0x4009, 0x438B, 0x481C, 0x6CD7),
++    bn_pack4(0x3590, 0x46F4, 0xEB87, 0x9F92),
++    bn_pack4(0xFAF3, 0x6BC3, 0x1ECF, 0xA268),
++    bn_pack4(0xB1D5, 0x10BD, 0x7EE7, 0x4D73),
++    bn_pack4(0xF9AB, 0x4819, 0x5DED, 0x7EA1),
++    bn_pack4(0x64F3, 0x1CC5, 0x0846, 0x851D),
++    bn_pack4(0x4597, 0xE899, 0xA025, 0x5DC1),
++    bn_pack4(0xDF31, 0x0EE0, 0x74AB, 0x6A36),
++    bn_pack4(0x6D2A, 0x13F8, 0x3F44, 0xF82D),
++    bn_pack4(0x062B, 0x3CF5, 0xB3A2, 0x78A6),
++    bn_pack4(0x7968, 0x3303, 0xED5B, 0xDD3A),
++    bn_pack4(0xFA9D, 0x4B7F, 0xA2C0, 0x87E8),
++    bn_pack4(0x4BCB, 0xC886, 0x2F83, 0x85DD),
++    bn_pack4(0x3473, 0xFC64, 0x6CEA, 0x306B),
++    bn_pack4(0x13EB, 0x57A8, 0x1A23, 0xF0C7),
++    bn_pack4(0x2222, 0x2E04, 0xA403, 0x7C07),
++    bn_pack4(0xE3FD, 0xB8BE, 0xFC84, 0x8AD9),
++    bn_pack4(0x238F, 0x16CB, 0xE39D, 0x652D),
++    bn_pack4(0x3423, 0xB474, 0x2BF1, 0xC978),
++    bn_pack4(0x3AAB, 0x639C, 0x5AE4, 0xF568),
++    bn_pack4(0x2576, 0xF693, 0x6BA4, 0x2466),
++    bn_pack4(0x741F, 0xA7BF, 0x8AFC, 0x47ED),
++    bn_pack4(0x3BC8, 0x32B6, 0x8D9D, 0xD300),
++    bn_pack4(0xD8BE, 0xC4D0, 0x73B9, 0x31BA),
++    bn_pack4(0x3877, 0x7CB6, 0xA932, 0xDF8C),
++    bn_pack4(0x74A3, 0x926F, 0x12FE, 0xE5E4),
++    bn_pack4(0xE694, 0xF91E, 0x6DBE, 0x1159),
++    bn_pack4(0x12BF, 0x2D5B, 0x0B74, 0x74D6),
++    bn_pack4(0x043E, 0x8F66, 0x3F48, 0x60EE),
++    bn_pack4(0x387F, 0xE8D7, 0x6E3C, 0x0468),
++    bn_pack4(0xDA56, 0xC9EC, 0x2EF2, 0x9632),
++    bn_pack4(0xEB19, 0xCCB1, 0xA313, 0xD55C),
++    bn_pack4(0xF550, 0xAA3D, 0x8A1F, 0xBFF0),
++    bn_pack4(0x06A1, 0xD58B, 0xB7C5, 0xDA76),
++    bn_pack4(0xA797, 0x15EE, 0xF29B, 0xE328),
++    bn_pack4(0x14CC, 0x5ED2, 0x0F80, 0x37E0),
++    bn_pack4(0xCC8F, 0x6D7E, 0xBF48, 0xE1D8),
++    bn_pack4(0x4BD4, 0x07B2, 0x2B41, 0x54AA),
++    bn_pack4(0x0F1D, 0x45B7, 0xFF58, 0x5AC5),
++    bn_pack4(0x23A9, 0x7A7E, 0x36CC, 0x88BE),
++    bn_pack4(0x59E7, 0xC97F, 0xBEC7, 0xE8F3),
++    bn_pack4(0xB5A8, 0x4031, 0x900B, 0x1C9E),
++    bn_pack4(0xD55E, 0x702F, 0x4698, 0x0C82),
++    bn_pack4(0xF482, 0xD7CE, 0x6E74, 0xFEF6),
++    bn_pack4(0xF032, 0xEA15, 0xD172, 0x1D03),
++    bn_pack4(0x5983, 0xCA01, 0xC64B, 0x92EC),
++    bn_pack4(0x6FB8, 0xF401, 0x378C, 0xD2BF),
++    bn_pack4(0x3320, 0x5151, 0x2BD7, 0xAF42),
++    bn_pack4(0xDB7F, 0x1447, 0xE6CC, 0x254B),
++    bn_pack4(0x44CE, 0x6CBA, 0xCED4, 0xBB1B),
++    bn_pack4(0xDA3E, 0xDBEB, 0xCF9B, 0x14ED),
++    bn_pack4(0x1797, 0x27B0, 0x865A, 0x8918),
++    bn_pack4(0xB06A, 0x53ED, 0x9027, 0xD831),
++    bn_pack4(0xE5DB, 0x382F, 0x4130, 0x01AE),
++    bn_pack4(0xF8FF, 0x9406, 0xAD9E, 0x530E),
++    bn_pack4(0xC975, 0x1E76, 0x3DBA, 0x37BD),
++    bn_pack4(0xC1D4, 0xDCB2, 0x6026, 0x46DE),
++    bn_pack4(0x36C3, 0xFAB4, 0xD27C, 0x7026),
++    bn_pack4(0x4DF4, 0x35C9, 0x3402, 0x8492),
++    bn_pack4(0x86FF, 0xB7DC, 0x90A6, 0xC08F),
++    bn_pack4(0x93B4, 0xEA98, 0x8D8F, 0xDDC1),
++    bn_pack4(0xD006, 0x9127, 0xD5B0, 0x5AA9),
++    bn_pack4(0xB81B, 0xDD76, 0x2170, 0x481C),
++    bn_pack4(0x1F61, 0x2970, 0xCEE2, 0xD7AF),
++    bn_pack4(0x233B, 0xA186, 0x515B, 0xE7ED),
++    bn_pack4(0x99B2, 0x964F, 0xA090, 0xC3A2),
++    bn_pack4(0x287C, 0x5947, 0x4E6B, 0xC05D),
++    bn_pack4(0x2E8E, 0xFC14, 0x1FBE, 0xCAA6),
++    bn_pack4(0xDBBB, 0xC2DB, 0x04DE, 0x8EF9),
++    bn_pack4(0x2583, 0xE9CA, 0x2AD4, 0x4CE8),
++    bn_pack4(0x1A94, 0x6834, 0xB615, 0x0BDA),
++    bn_pack4(0x99C3, 0x2718, 0x6AF4, 0xE23C),
++    bn_pack4(0x8871, 0x9A10, 0xBDBA, 0x5B26),
++    bn_pack4(0x1A72, 0x3C12, 0xA787, 0xE6D7),
++    bn_pack4(0x4B82, 0xD120, 0xA921, 0x0801),
++    bn_pack4(0x43DB, 0x5BFC, 0xE0FD, 0x108E),
++    bn_pack4(0x08E2, 0x4FA0, 0x74E5, 0xAB31),
++    bn_pack4(0x7709, 0x88C0, 0xBAD9, 0x46E2),
++    bn_pack4(0xBBE1, 0x1757, 0x7A61, 0x5D6C),
++    bn_pack4(0x521F, 0x2B18, 0x177B, 0x200C),
++    bn_pack4(0xD876, 0x0273, 0x3EC8, 0x6A64),
++    bn_pack4(0xF12F, 0xFA06, 0xD98A, 0x0864),
++    bn_pack4(0xCEE3, 0xD226, 0x1AD2, 0xEE6B),
++    bn_pack4(0x1E8C, 0x94E0, 0x4A25, 0x619D),
++    bn_pack4(0xABF5, 0xAE8C, 0xDB09, 0x33D7),
++    bn_pack4(0xB397, 0x0F85, 0xA6E1, 0xE4C7),
++    bn_pack4(0x8AEA, 0x7157, 0x5D06, 0x0C7D),
++    bn_pack4(0xECFB, 0x8504, 0x58DB, 0xEF0A),
++    bn_pack4(0xA855, 0x21AB, 0xDF1C, 0xBA64),
++    bn_pack4(0xAD33, 0x170D, 0x0450, 0x7A33),
++    bn_pack4(0x1572, 0x8E5A, 0x8AAA, 0xC42D),
++    bn_pack4(0x15D2, 0x2618, 0x98FA, 0x0510),
++    bn_pack4(0x3995, 0x497C, 0xEA95, 0x6AE5),
++    bn_pack4(0xDE2B, 0xCBF6, 0x9558, 0x1718),
++    bn_pack4(0xB5C5, 0x5DF0, 0x6F4C, 0x52C9),
++    bn_pack4(0x9B27, 0x83A2, 0xEC07, 0xA28F),
++    bn_pack4(0xE39E, 0x772C, 0x180E, 0x8603),
++    bn_pack4(0x3290, 0x5E46, 0x2E36, 0xCE3B),
++    bn_pack4(0xF174, 0x6C08, 0xCA18, 0x217C),
++    bn_pack4(0x670C, 0x354E, 0x4ABC, 0x9804),
++    bn_pack4(0x9ED5, 0x2907, 0x7096, 0x966D),
++    bn_pack4(0x1C62, 0xF356, 0x2085, 0x52BB),
++    bn_pack4(0x8365, 0x5D23, 0xDCA3, 0xAD96),
++    bn_pack4(0x6916, 0x3FA8, 0xFD24, 0xCF5F),
++    bn_pack4(0x98DA, 0x4836, 0x1C55, 0xD39A),
++    bn_pack4(0xC200, 0x7CB8, 0xA163, 0xBF05),
++    bn_pack4(0x4928, 0x6651, 0xECE4, 0x5B3D),
++    bn_pack4(0xAE9F, 0x2411, 0x7C4B, 0x1FE6),
++    bn_pack4(0xEE38, 0x6BFB, 0x5A89, 0x9FA5),
++    bn_pack4(0x0BFF, 0x5CB6, 0xF406, 0xB7ED),
++    bn_pack4(0xF44C, 0x42E9, 0xA637, 0xED6B),
++    bn_pack4(0xE485, 0xB576, 0x625E, 0x7EC6),
++    bn_pack4(0x4FE1, 0x356D, 0x6D51, 0xC245),
++    bn_pack4(0x302B, 0x0A6D, 0xF25F, 0x1437),
++    bn_pack4(0xEF95, 0x19B3, 0xCD3A, 0x431B),
++    bn_pack4(0x514A, 0x0879, 0x8E34, 0x04DD),
++    bn_pack4(0x020B, 0xBEA6, 0x3B13, 0x9B22),
++    bn_pack4(0x2902, 0x4E08, 0x8A67, 0xCC74),
++    bn_pack4(0xC4C6, 0x628B, 0x80DC, 0x1CD1),
++    bn_pack4(0xC90F, 0xDAA2, 0x2168, 0xC234),
++    bn_pack4(0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF)
++};
++
++const BIGNUM bn_group_8192 = {
++    (BN_ULONG *)bn_group_8192_value,
++    OSSL_NELEM(bn_group_8192_value),
++    OSSL_NELEM(bn_group_8192_value),
++    0,
++    BN_FLG_STATIC_DATA
++};
++
++static const BN_ULONG bn_generator_19_value[] = { 19 };
++
++const BIGNUM bn_generator_19 = {
++    (BN_ULONG *)bn_generator_19_value,
++    1,
++    1,
++    0,
++    BN_FLG_STATIC_DATA
++};
++static const BN_ULONG bn_generator_5_value[] = { 5 };
++
++const BIGNUM bn_generator_5 = {
++    (BN_ULONG *)bn_generator_5_value,
++    1,
++    1,
++    0,
++    BN_FLG_STATIC_DATA
++};
++static const BN_ULONG bn_generator_2_value[] = { 2 };
++
++const BIGNUM bn_generator_2 = {
++    (BN_ULONG *)bn_generator_2_value,
++    1,
++    1,
++    0,
++    BN_FLG_STATIC_DATA
++};
++
++#endif
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/bn/bn_word.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/bn/bn_word.c
+new file mode 100644
+index 0000000..1af13a5
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/bn/bn_word.c
+@@ -0,0 +1,201 @@
++/*
++ * Copyright 1995-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include "internal/cryptlib.h"
++#include "bn_lcl.h"
++
++BN_ULONG BN_mod_word(const BIGNUM *a, BN_ULONG w)
++{
++#ifndef BN_LLONG
++    BN_ULONG ret = 0;
++#else
++    BN_ULLONG ret = 0;
++#endif
++    int i;
++
++    if (w == 0)
++        return (BN_ULONG)-1;
++
++#ifndef BN_LLONG
++    /*
++     * If |w| is too long and we don't have BN_ULLONG then we need to fall
++     * back to using BN_div_word
++     */
++    if (w > ((BN_ULONG)1 << BN_BITS4)) {
++        BIGNUM *tmp = BN_dup(a);
++        if (tmp == NULL)
++            return (BN_ULONG)-1;
++
++        ret = BN_div_word(tmp, w);
++        BN_free(tmp);
++
++        return ret;
++    }
++#endif
++
++    bn_check_top(a);
++    w &= BN_MASK2;
++    for (i = a->top - 1; i >= 0; i--) {
++#ifndef BN_LLONG
++        /*
++         * We can assume here that | w <= ((BN_ULONG)1 << BN_BITS4) | and so
++         * | ret < ((BN_ULONG)1 << BN_BITS4) | and therefore the shifts here are
++         * safe and will not overflow
++         */
++        ret = ((ret << BN_BITS4) | ((a->d[i] >> BN_BITS4) & BN_MASK2l)) % w;
++        ret = ((ret << BN_BITS4) | (a->d[i] & BN_MASK2l)) % w;
++#else
++        ret = (BN_ULLONG) (((ret << (BN_ULLONG) BN_BITS2) | a->d[i]) %
++                           (BN_ULLONG) w);
++#endif
++    }
++    return ((BN_ULONG)ret);
++}
++
++BN_ULONG BN_div_word(BIGNUM *a, BN_ULONG w)
++{
++    BN_ULONG ret = 0;
++    int i, j;
++
++    bn_check_top(a);
++    w &= BN_MASK2;
++
++    if (!w)
++        /* actually this an error (division by zero) */
++        return (BN_ULONG)-1;
++    if (a->top == 0)
++        return 0;
++
++    /* normalize input (so bn_div_words doesn't complain) */
++    j = BN_BITS2 - BN_num_bits_word(w);
++    w <<= j;
++    if (!BN_lshift(a, a, j))
++        return (BN_ULONG)-1;
++
++    for (i = a->top - 1; i >= 0; i--) {
++        BN_ULONG l, d;
++
++        l = a->d[i];
++        d = bn_div_words(ret, l, w);
++        ret = (l - ((d * w) & BN_MASK2)) & BN_MASK2;
++        a->d[i] = d;
++    }
++    if ((a->top > 0) && (a->d[a->top - 1] == 0))
++        a->top--;
++    ret >>= j;
++    if (!a->top)
++        a->neg = 0; /* don't allow negative zero */
++    bn_check_top(a);
++    return (ret);
++}
++
++int BN_add_word(BIGNUM *a, BN_ULONG w)
++{
++    BN_ULONG l;
++    int i;
++
++    bn_check_top(a);
++    w &= BN_MASK2;
++
++    /* degenerate case: w is zero */
++    if (!w)
++        return 1;
++    /* degenerate case: a is zero */
++    if (BN_is_zero(a))
++        return BN_set_word(a, w);
++    /* handle 'a' when negative */
++    if (a->neg) {
++        a->neg = 0;
++        i = BN_sub_word(a, w);
++        if (!BN_is_zero(a))
++            a->neg = !(a->neg);
++        return (i);
++    }
++    for (i = 0; w != 0 && i < a->top; i++) {
++        a->d[i] = l = (a->d[i] + w) & BN_MASK2;
++        w = (w > l) ? 1 : 0;
++    }
++    if (w && i == a->top) {
++        if (bn_wexpand(a, a->top + 1) == NULL)
++            return 0;
++        a->top++;
++        a->d[i] = w;
++    }
++    bn_check_top(a);
++    return (1);
++}
++
++int BN_sub_word(BIGNUM *a, BN_ULONG w)
++{
++    int i;
++
++    bn_check_top(a);
++    w &= BN_MASK2;
++
++    /* degenerate case: w is zero */
++    if (!w)
++        return 1;
++    /* degenerate case: a is zero */
++    if (BN_is_zero(a)) {
++        i = BN_set_word(a, w);
++        if (i != 0)
++            BN_set_negative(a, 1);
++        return i;
++    }
++    /* handle 'a' when negative */
++    if (a->neg) {
++        a->neg = 0;
++        i = BN_add_word(a, w);
++        a->neg = 1;
++        return (i);
++    }
++
++    if ((a->top == 1) && (a->d[0] < w)) {
++        a->d[0] = w - a->d[0];
++        a->neg = 1;
++        return (1);
++    }
++    i = 0;
++    for (;;) {
++        if (a->d[i] >= w) {
++            a->d[i] -= w;
++            break;
++        } else {
++            a->d[i] = (a->d[i] - w) & BN_MASK2;
++            i++;
++            w = 1;
++        }
++    }
++    if ((a->d[i] == 0) && (i == (a->top - 1)))
++        a->top--;
++    bn_check_top(a);
++    return (1);
++}
++
++int BN_mul_word(BIGNUM *a, BN_ULONG w)
++{
++    BN_ULONG ll;
++
++    bn_check_top(a);
++    w &= BN_MASK2;
++    if (a->top) {
++        if (w == 0)
++            BN_zero(a);
++        else {
++            ll = bn_mul_words(a->d, a->d, a->top, w);
++            if (ll) {
++                if (bn_wexpand(a, a->top + 1) == NULL)
++                    return (0);
++                a->d[a->top++] = ll;
++            }
++        }
++    }
++    bn_check_top(a);
++    return (1);
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/bn/bn_x931p.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/bn/bn_x931p.c
+new file mode 100644
+index 0000000..40734cb
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/bn/bn_x931p.c
+@@ -0,0 +1,238 @@
++/*
++ * Copyright 2011-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include 
++#include "bn_lcl.h"
++
++/* X9.31 routines for prime derivation */
++
++/*
++ * X9.31 prime derivation. This is used to generate the primes pi (p1, p2,
++ * q1, q2) from a parameter Xpi by checking successive odd integers.
++ */
++
++static int bn_x931_derive_pi(BIGNUM *pi, const BIGNUM *Xpi, BN_CTX *ctx,
++                             BN_GENCB *cb)
++{
++    int i = 0, is_prime;
++    if (!BN_copy(pi, Xpi))
++        return 0;
++    if (!BN_is_odd(pi) && !BN_add_word(pi, 1))
++        return 0;
++    for (;;) {
++        i++;
++        BN_GENCB_call(cb, 0, i);
++        /* NB 27 MR is specified in X9.31 */
++        is_prime = BN_is_prime_fasttest_ex(pi, 27, ctx, 1, cb);
++        if (is_prime < 0)
++            return 0;
++        if (is_prime)
++            break;
++        if (!BN_add_word(pi, 2))
++            return 0;
++    }
++    BN_GENCB_call(cb, 2, i);
++    return 1;
++}
++
++/*
++ * This is the main X9.31 prime derivation function. From parameters Xp1, Xp2
++ * and Xp derive the prime p. If the parameters p1 or p2 are not NULL they
++ * will be returned too: this is needed for testing.
++ */
++
++int BN_X931_derive_prime_ex(BIGNUM *p, BIGNUM *p1, BIGNUM *p2,
++                            const BIGNUM *Xp, const BIGNUM *Xp1,
++                            const BIGNUM *Xp2, const BIGNUM *e, BN_CTX *ctx,
++                            BN_GENCB *cb)
++{
++    int ret = 0;
++
++    BIGNUM *t, *p1p2, *pm1;
++
++    /* Only even e supported */
++    if (!BN_is_odd(e))
++        return 0;
++
++    BN_CTX_start(ctx);
++    if (!p1)
++        p1 = BN_CTX_get(ctx);
++
++    if (!p2)
++        p2 = BN_CTX_get(ctx);
++
++    t = BN_CTX_get(ctx);
++
++    p1p2 = BN_CTX_get(ctx);
++
++    pm1 = BN_CTX_get(ctx);
++
++    if (pm1 == NULL)
++        goto err;
++
++    if (!bn_x931_derive_pi(p1, Xp1, ctx, cb))
++        goto err;
++
++    if (!bn_x931_derive_pi(p2, Xp2, ctx, cb))
++        goto err;
++
++    if (!BN_mul(p1p2, p1, p2, ctx))
++        goto err;
++
++    /* First set p to value of Rp */
++
++    if (!BN_mod_inverse(p, p2, p1, ctx))
++        goto err;
++
++    if (!BN_mul(p, p, p2, ctx))
++        goto err;
++
++    if (!BN_mod_inverse(t, p1, p2, ctx))
++        goto err;
++
++    if (!BN_mul(t, t, p1, ctx))
++        goto err;
++
++    if (!BN_sub(p, p, t))
++        goto err;
++
++    if (p->neg && !BN_add(p, p, p1p2))
++        goto err;
++
++    /* p now equals Rp */
++
++    if (!BN_mod_sub(p, p, Xp, p1p2, ctx))
++        goto err;
++
++    if (!BN_add(p, p, Xp))
++        goto err;
++
++    /* p now equals Yp0 */
++
++    for (;;) {
++        int i = 1;
++        BN_GENCB_call(cb, 0, i++);
++        if (!BN_copy(pm1, p))
++            goto err;
++        if (!BN_sub_word(pm1, 1))
++            goto err;
++        if (!BN_gcd(t, pm1, e, ctx))
++            goto err;
++        if (BN_is_one(t)) {
++            /*
++             * X9.31 specifies 8 MR and 1 Lucas test or any prime test
++             * offering similar or better guarantees 50 MR is considerably
++             * better.
++             */
++            int r = BN_is_prime_fasttest_ex(p, 50, ctx, 1, cb);
++            if (r < 0)
++                goto err;
++            if (r)
++                break;
++        }
++        if (!BN_add(p, p, p1p2))
++            goto err;
++    }
++
++    BN_GENCB_call(cb, 3, 0);
++
++    ret = 1;
++
++ err:
++
++    BN_CTX_end(ctx);
++
++    return ret;
++}
++
++/*
++ * Generate pair of parameters Xp, Xq for X9.31 prime generation. Note: nbits
++ * parameter is sum of number of bits in both.
++ */
++
++int BN_X931_generate_Xpq(BIGNUM *Xp, BIGNUM *Xq, int nbits, BN_CTX *ctx)
++{
++    BIGNUM *t;
++    int i;
++    /*
++     * Number of bits for each prime is of the form 512+128s for s = 0, 1,
++     * ...
++     */
++    if ((nbits < 1024) || (nbits & 0xff))
++        return 0;
++    nbits >>= 1;
++    /*
++     * The random value Xp must be between sqrt(2) * 2^(nbits-1) and 2^nbits
++     * - 1. By setting the top two bits we ensure that the lower bound is
++     * exceeded.
++     */
++    if (!BN_rand(Xp, nbits, BN_RAND_TOP_TWO, BN_RAND_BOTTOM_ANY))
++        goto err;
++
++    BN_CTX_start(ctx);
++    t = BN_CTX_get(ctx);
++
++    for (i = 0; i < 1000; i++) {
++        if (!BN_rand(Xq, nbits, BN_RAND_TOP_TWO, BN_RAND_BOTTOM_ANY))
++            goto err;
++        /* Check that |Xp - Xq| > 2^(nbits - 100) */
++        BN_sub(t, Xp, Xq);
++        if (BN_num_bits(t) > (nbits - 100))
++            break;
++    }
++
++    BN_CTX_end(ctx);
++
++    if (i < 1000)
++        return 1;
++
++    return 0;
++
++ err:
++    BN_CTX_end(ctx);
++    return 0;
++}
++
++/*
++ * Generate primes using X9.31 algorithm. Of the values p, p1, p2, Xp1 and
++ * Xp2 only 'p' needs to be non-NULL. If any of the others are not NULL the
++ * relevant parameter will be stored in it. Due to the fact that |Xp - Xq| >
++ * 2^(nbits - 100) must be satisfied Xp and Xq are generated using the
++ * previous function and supplied as input.
++ */
++
++int BN_X931_generate_prime_ex(BIGNUM *p, BIGNUM *p1, BIGNUM *p2,
++                              BIGNUM *Xp1, BIGNUM *Xp2,
++                              const BIGNUM *Xp,
++                              const BIGNUM *e, BN_CTX *ctx, BN_GENCB *cb)
++{
++    int ret = 0;
++
++    BN_CTX_start(ctx);
++    if (!Xp1)
++        Xp1 = BN_CTX_get(ctx);
++    if (!Xp2)
++        Xp2 = BN_CTX_get(ctx);
++
++    if (!BN_rand(Xp1, 101, BN_RAND_TOP_ONE, BN_RAND_BOTTOM_ANY))
++        goto error;
++    if (!BN_rand(Xp2, 101, BN_RAND_TOP_ONE, BN_RAND_BOTTOM_ANY))
++        goto error;
++    if (!BN_X931_derive_prime_ex(p, p1, p2, Xp, Xp1, Xp2, e, ctx, cb))
++        goto error;
++
++    ret = 1;
++
++ error:
++    BN_CTX_end(ctx);
++
++    return ret;
++
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/bn/build.info b/CryptoPkg/Library/OpensslLib/openssl/crypto/bn/build.info
+new file mode 100644
+index 0000000..c608ecc
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/bn/build.info
+@@ -0,0 +1,84 @@
++LIBS=../../libcrypto
++SOURCE[../../libcrypto]=\
++        bn_add.c bn_div.c bn_exp.c bn_lib.c bn_ctx.c bn_mul.c bn_mod.c \
++        bn_print.c bn_rand.c bn_shift.c bn_word.c bn_blind.c \
++        bn_kron.c bn_sqrt.c bn_gcd.c bn_prime.c bn_err.c bn_sqr.c \
++        {- $target{bn_asm_src} -} \
++        bn_recp.c bn_mont.c bn_mpi.c bn_exp2.c bn_gf2m.c bn_nist.c \
++        bn_depr.c bn_const.c bn_x931p.c bn_intern.c bn_dh.c bn_srp.c
++INCLUDE[../../libcrypto]=../../crypto/include
++
++INCLUDE[bn_exp.o]=..
++
++GENERATE[bn-586.s]=asm/bn-586.pl \
++	$(PERLASM_SCHEME) $(CFLAGS) $(LIB_CFLAGS) $(PROCESSOR)
++DEPEND[bn-586.s]=../perlasm/x86asm.pl
++GENERATE[co-586.s]=asm/co-586.pl \
++	$(PERLASM_SCHEME) $(CFLAGS) $(LIB_CFLAGS) $(PROCESSOR)
++DEPEND[co-586.s]=../perlasm/x86asm.pl
++GENERATE[x86-mont.s]=asm/x86-mont.pl \
++	$(PERLASM_SCHEME) $(CFLAGS) $(LIB_CFLAGS) $(PROCESSOR)
++DEPEND[x86-mont.s]=../perlasm/x86asm.pl
++GENERATE[x86-gf2m.s]=asm/x86-gf2m.pl \
++	$(PERLASM_SCHEME) $(CFLAGS) $(LIB_CFLAGS) $(PROCESSOR)
++DEPEND[x86-gf2m.s]=../perlasm/x86asm.pl
++
++GENERATE[sparcv9a-mont.S]=asm/sparcv9a-mont.pl $(PERLASM_SCHEME)
++INCLUDE[sparcv9a-mont.o]=..
++GENERATE[sparcv9-mont.S]=asm/sparcv9-mont.pl $(PERLASM_SCHEME)
++INCLUDE[sparcv9-mont.o]=..
++GENERATE[vis3-mont.S]=asm/vis3-mont.pl $(PERLASM_SCHEME)
++INCLUDE[vis3-mont.o]=..
++GENERATE[sparct4-mont.S]=asm/sparct4-mont.pl $(PERLASM_SCHEME)
++INCLUDE[sparct4-mont.o]=..
++GENERATE[sparcv9-gf2m.S]=asm/sparcv9-gf2m.pl $(PERLASM_SCHEME)
++INCLUDE[sparcv9-gf2m.o]=..
++
++GENERATE[bn-mips.s]=asm/mips.pl $(PERLASM_SCHEME)
++GENERATE[mips-mont.s]=asm/mips-mont.pl $(PERLASM_SCHEME)
++
++GENERATE[s390x-mont.S]=asm/s390x-mont.pl $(PERLASM_SCHEME)
++GENERATE[s390x-gf2m.s]=asm/s390x-gf2m.pl $(PERLASM_SCHEME)
++
++GENERATE[x86_64-mont.s]=asm/x86_64-mont.pl $(PERLASM_SCHEME)
++GENERATE[x86_64-mont5.s]=asm/x86_64-mont5.pl $(PERLASM_SCHEME)
++GENERATE[x86_64-gf2m.s]=asm/x86_64-gf2m.pl $(PERLASM_SCHEME)
++GENERATE[rsaz-x86_64.s]=asm/rsaz-x86_64.pl $(PERLASM_SCHEME)
++GENERATE[rsaz-avx2.s]=asm/rsaz-avx2.pl $(PERLASM_SCHEME)
++
++GENERATE[bn-ia64.s]=asm/ia64.S
++GENERATE[ia64-mont.s]=asm/ia64-mont.pl $(CFLAGS) $(LIB_CFLAGS)
++
++GENERATE[parisc-mont.s]=asm/parisc-mont.pl $(PERLASM_SCHEME)
++
++# ppc - AIX, Linux, MacOS X...
++GENERATE[bn-ppc.s]=asm/ppc.pl $(PERLASM_SCHEME)
++GENERATE[ppc-mont.s]=asm/ppc-mont.pl $(PERLASM_SCHEME)
++GENERATE[ppc64-mont.s]=asm/ppc64-mont.pl $(PERLASM_SCHEME)
++
++GENERATE[alpha-mont.S]=asm/alpha-mont.pl $(PERLASM_SCHEME)
++
++GENERATE[armv4-mont.S]=asm/armv4-mont.pl $(PERLASM_SCHEME)
++INCLUDE[armv4-mont.o]=..
++GENERATE[armv4-gf2m.S]=asm/armv4-gf2m.pl $(PERLASM_SCHEME)
++INCLUDE[armv4-gf2m.o]=..
++GENERATE[armv8-mont.S]=asm/armv8-mont.pl $(PERLASM_SCHEME)
++
++OVERRIDES=bn-mips3.o pa-risc2W.o pa-risc2.c
++BEGINRAW[Makefile]
++##### BN assembler implementations
++
++{- $builddir -}/bn-mips3.o:	{- $sourcedir -}/asm/mips3.s
++	@if [ "$(CC)" = "gcc" ]; then \
++		ABI=`expr "$(CFLAGS)" : ".*-mabi=\([n3264]*\)"` && \
++		as -$$ABI -O -o $@ {- $sourcedir -}/asm/mips3.s; \
++	else	$(CC) -c $(CFLAGS) $(LIB_CFLAGS) -o $@ {- $sourcedir -}/asm/mips3.s; fi
++
++# GNU assembler fails to compile PA-RISC2 modules, insist on calling
++# vendor assembler...
++{- $builddir -}/pa-risc2W.o: {- $sourcedir -}/asm/pa-risc2W.s
++	CC="$(CC)" $(PERL) $(SRCDIR)/util/fipsas.pl $(SRCDIR) $< /usr/ccs/bin/as -o pa-risc2W.o {- $sourcedir -}/asm/pa-risc2W.s
++{- $builddir -}/pa-risc2.o: {- $sourcedir -}/asm/pa-risc2.s
++	CC="$(CC)" $(PERL) $(SRCDIR)/util/fipsas.pl $(SRCDIR) $< /usr/ccs/bin/as -o pa-risc2.o {- $sourcedir -}/asm/pa-risc2.s
++
++ENDRAW[Makefile]
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/bn/rsaz_exp.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/bn/rsaz_exp.c
+new file mode 100644
+index 0000000..1a70f6c
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/bn/rsaz_exp.c
+@@ -0,0 +1,352 @@
++/*
++ * Copyright 2013-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++/*****************************************************************************
++*                                                                            *
++*  Copyright (c) 2012, Intel Corporation                                     *
++*                                                                            *
++*  All rights reserved.                                                      *
++*                                                                            *
++*  Redistribution and use in source and binary forms, with or without        *
++*  modification, are permitted provided that the following conditions are    *
++*  met:                                                                      *
++*                                                                            *
++*  *  Redistributions of source code must retain the above copyright         *
++*     notice, this list of conditions and the following disclaimer.          *
++*                                                                            *
++*  *  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.                                                          *
++*                                                                            *
++*  *  Neither the name of the Intel Corporation nor the names of its         *
++*     contributors may be used to endorse or promote products derived from   *
++*     this software without specific prior written permission.               *
++*                                                                            *
++*                                                                            *
++*  THIS SOFTWARE IS PROVIDED BY INTEL CORPORATION ""AS IS"" AND ANY          *
++*  EXPRESS 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 INTEL CORPORATION OR            *
++*  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.              *
++*                                                                            *
++******************************************************************************
++* Developers and authors:                                                    *
++* Shay Gueron (1, 2), and Vlad Krasnov (1)                                   *
++* (1) Intel Corporation, Israel Development Center, Haifa, Israel            *
++* (2) University of Haifa, Israel                                            *
++*****************************************************************************/
++
++#include 
++#include "rsaz_exp.h"
++
++#ifndef RSAZ_ENABLED
++NON_EMPTY_TRANSLATION_UNIT
++#else
++
++/*
++ * See crypto/bn/asm/rsaz-avx2.pl for further details.
++ */
++void rsaz_1024_norm2red_avx2(void *red, const void *norm);
++void rsaz_1024_mul_avx2(void *ret, const void *a, const void *b,
++                        const void *n, BN_ULONG k);
++void rsaz_1024_sqr_avx2(void *ret, const void *a, const void *n, BN_ULONG k,
++                        int cnt);
++void rsaz_1024_scatter5_avx2(void *tbl, const void *val, int i);
++void rsaz_1024_gather5_avx2(void *val, const void *tbl, int i);
++void rsaz_1024_red2norm_avx2(void *norm, const void *red);
++
++#if defined(__GNUC__)
++# define ALIGN64        __attribute__((aligned(64)))
++#elif defined(_MSC_VER)
++# define ALIGN64        __declspec(align(64))
++#elif defined(__SUNPRO_C)
++# define ALIGN64
++# pragma align 64(one,two80)
++#else
++/* not fatal, might hurt performance a little */
++# define ALIGN64
++#endif
++
++ALIGN64 static const BN_ULONG one[40] = {
++    1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
++    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
++};
++
++ALIGN64 static const BN_ULONG two80[40] = {
++    0, 0, 1 << 22, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
++    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
++};
++
++void RSAZ_1024_mod_exp_avx2(BN_ULONG result_norm[16],
++                            const BN_ULONG base_norm[16],
++                            const BN_ULONG exponent[16],
++                            const BN_ULONG m_norm[16], const BN_ULONG RR[16],
++                            BN_ULONG k0)
++{
++    unsigned char storage[320 * 3 + 32 * 9 * 16 + 64]; /* 5.5KB */
++    unsigned char *p_str = storage + (64 - ((size_t)storage % 64));
++    unsigned char *a_inv, *m, *result;
++    unsigned char *table_s = p_str + 320 * 3;
++    unsigned char *R2 = table_s; /* borrow */
++    int index;
++    int wvalue;
++
++    if ((((size_t)p_str & 4095) + 320) >> 12) {
++        result = p_str;
++        a_inv = p_str + 320;
++        m = p_str + 320 * 2;    /* should not cross page */
++    } else {
++        m = p_str;              /* should not cross page */
++        result = p_str + 320;
++        a_inv = p_str + 320 * 2;
++    }
++
++    rsaz_1024_norm2red_avx2(m, m_norm);
++    rsaz_1024_norm2red_avx2(a_inv, base_norm);
++    rsaz_1024_norm2red_avx2(R2, RR);
++
++    rsaz_1024_mul_avx2(R2, R2, R2, m, k0);
++    rsaz_1024_mul_avx2(R2, R2, two80, m, k0);
++
++    /* table[0] = 1 */
++    rsaz_1024_mul_avx2(result, R2, one, m, k0);
++    /* table[1] = a_inv^1 */
++    rsaz_1024_mul_avx2(a_inv, a_inv, R2, m, k0);
++
++    rsaz_1024_scatter5_avx2(table_s, result, 0);
++    rsaz_1024_scatter5_avx2(table_s, a_inv, 1);
++
++    /* table[2] = a_inv^2 */
++    rsaz_1024_sqr_avx2(result, a_inv, m, k0, 1);
++    rsaz_1024_scatter5_avx2(table_s, result, 2);
++#if 0
++    /* this is almost 2x smaller and less than 1% slower */
++    for (index = 3; index < 32; index++) {
++        rsaz_1024_mul_avx2(result, result, a_inv, m, k0);
++        rsaz_1024_scatter5_avx2(table_s, result, index);
++    }
++#else
++    /* table[4] = a_inv^4 */
++    rsaz_1024_sqr_avx2(result, result, m, k0, 1);
++    rsaz_1024_scatter5_avx2(table_s, result, 4);
++    /* table[8] = a_inv^8 */
++    rsaz_1024_sqr_avx2(result, result, m, k0, 1);
++    rsaz_1024_scatter5_avx2(table_s, result, 8);
++    /* table[16] = a_inv^16 */
++    rsaz_1024_sqr_avx2(result, result, m, k0, 1);
++    rsaz_1024_scatter5_avx2(table_s, result, 16);
++    /* table[17] = a_inv^17 */
++    rsaz_1024_mul_avx2(result, result, a_inv, m, k0);
++    rsaz_1024_scatter5_avx2(table_s, result, 17);
++
++    /* table[3] */
++    rsaz_1024_gather5_avx2(result, table_s, 2);
++    rsaz_1024_mul_avx2(result, result, a_inv, m, k0);
++    rsaz_1024_scatter5_avx2(table_s, result, 3);
++    /* table[6] */
++    rsaz_1024_sqr_avx2(result, result, m, k0, 1);
++    rsaz_1024_scatter5_avx2(table_s, result, 6);
++    /* table[12] */
++    rsaz_1024_sqr_avx2(result, result, m, k0, 1);
++    rsaz_1024_scatter5_avx2(table_s, result, 12);
++    /* table[24] */
++    rsaz_1024_sqr_avx2(result, result, m, k0, 1);
++    rsaz_1024_scatter5_avx2(table_s, result, 24);
++    /* table[25] */
++    rsaz_1024_mul_avx2(result, result, a_inv, m, k0);
++    rsaz_1024_scatter5_avx2(table_s, result, 25);
++
++    /* table[5] */
++    rsaz_1024_gather5_avx2(result, table_s, 4);
++    rsaz_1024_mul_avx2(result, result, a_inv, m, k0);
++    rsaz_1024_scatter5_avx2(table_s, result, 5);
++    /* table[10] */
++    rsaz_1024_sqr_avx2(result, result, m, k0, 1);
++    rsaz_1024_scatter5_avx2(table_s, result, 10);
++    /* table[20] */
++    rsaz_1024_sqr_avx2(result, result, m, k0, 1);
++    rsaz_1024_scatter5_avx2(table_s, result, 20);
++    /* table[21] */
++    rsaz_1024_mul_avx2(result, result, a_inv, m, k0);
++    rsaz_1024_scatter5_avx2(table_s, result, 21);
++
++    /* table[7] */
++    rsaz_1024_gather5_avx2(result, table_s, 6);
++    rsaz_1024_mul_avx2(result, result, a_inv, m, k0);
++    rsaz_1024_scatter5_avx2(table_s, result, 7);
++    /* table[14] */
++    rsaz_1024_sqr_avx2(result, result, m, k0, 1);
++    rsaz_1024_scatter5_avx2(table_s, result, 14);
++    /* table[28] */
++    rsaz_1024_sqr_avx2(result, result, m, k0, 1);
++    rsaz_1024_scatter5_avx2(table_s, result, 28);
++    /* table[29] */
++    rsaz_1024_mul_avx2(result, result, a_inv, m, k0);
++    rsaz_1024_scatter5_avx2(table_s, result, 29);
++
++    /* table[9] */
++    rsaz_1024_gather5_avx2(result, table_s, 8);
++    rsaz_1024_mul_avx2(result, result, a_inv, m, k0);
++    rsaz_1024_scatter5_avx2(table_s, result, 9);
++    /* table[18] */
++    rsaz_1024_sqr_avx2(result, result, m, k0, 1);
++    rsaz_1024_scatter5_avx2(table_s, result, 18);
++    /* table[19] */
++    rsaz_1024_mul_avx2(result, result, a_inv, m, k0);
++    rsaz_1024_scatter5_avx2(table_s, result, 19);
++
++    /* table[11] */
++    rsaz_1024_gather5_avx2(result, table_s, 10);
++    rsaz_1024_mul_avx2(result, result, a_inv, m, k0);
++    rsaz_1024_scatter5_avx2(table_s, result, 11);
++    /* table[22] */
++    rsaz_1024_sqr_avx2(result, result, m, k0, 1);
++    rsaz_1024_scatter5_avx2(table_s, result, 22);
++    /* table[23] */
++    rsaz_1024_mul_avx2(result, result, a_inv, m, k0);
++    rsaz_1024_scatter5_avx2(table_s, result, 23);
++
++    /* table[13] */
++    rsaz_1024_gather5_avx2(result, table_s, 12);
++    rsaz_1024_mul_avx2(result, result, a_inv, m, k0);
++    rsaz_1024_scatter5_avx2(table_s, result, 13);
++    /* table[26] */
++    rsaz_1024_sqr_avx2(result, result, m, k0, 1);
++    rsaz_1024_scatter5_avx2(table_s, result, 26);
++    /* table[27] */
++    rsaz_1024_mul_avx2(result, result, a_inv, m, k0);
++    rsaz_1024_scatter5_avx2(table_s, result, 27);
++
++    /* table[15] */
++    rsaz_1024_gather5_avx2(result, table_s, 14);
++    rsaz_1024_mul_avx2(result, result, a_inv, m, k0);
++    rsaz_1024_scatter5_avx2(table_s, result, 15);
++    /* table[30] */
++    rsaz_1024_sqr_avx2(result, result, m, k0, 1);
++    rsaz_1024_scatter5_avx2(table_s, result, 30);
++    /* table[31] */
++    rsaz_1024_mul_avx2(result, result, a_inv, m, k0);
++    rsaz_1024_scatter5_avx2(table_s, result, 31);
++#endif
++
++    /* load first window */
++    p_str = (unsigned char *)exponent;
++    wvalue = p_str[127] >> 3;
++    rsaz_1024_gather5_avx2(result, table_s, wvalue);
++
++    index = 1014;
++
++    while (index > -1) {        /* loop for the remaining 127 windows */
++
++        rsaz_1024_sqr_avx2(result, result, m, k0, 5);
++
++        wvalue = (p_str[(index / 8) + 1] << 8) | p_str[index / 8];
++        wvalue = (wvalue >> (index % 8)) & 31;
++        index -= 5;
++
++        rsaz_1024_gather5_avx2(a_inv, table_s, wvalue); /* borrow a_inv */
++        rsaz_1024_mul_avx2(result, result, a_inv, m, k0);
++    }
++
++    /* square four times */
++    rsaz_1024_sqr_avx2(result, result, m, k0, 4);
++
++    wvalue = p_str[0] & 15;
++
++    rsaz_1024_gather5_avx2(a_inv, table_s, wvalue); /* borrow a_inv */
++    rsaz_1024_mul_avx2(result, result, a_inv, m, k0);
++
++    /* from Montgomery */
++    rsaz_1024_mul_avx2(result, result, one, m, k0);
++
++    rsaz_1024_red2norm_avx2(result_norm, result);
++
++    OPENSSL_cleanse(storage, sizeof(storage));
++}
++
++/*
++ * See crypto/bn/rsaz-x86_64.pl for further details.
++ */
++void rsaz_512_mul(void *ret, const void *a, const void *b, const void *n,
++                  BN_ULONG k);
++void rsaz_512_mul_scatter4(void *ret, const void *a, const void *n,
++                           BN_ULONG k, const void *tbl, unsigned int power);
++void rsaz_512_mul_gather4(void *ret, const void *a, const void *tbl,
++                          const void *n, BN_ULONG k, unsigned int power);
++void rsaz_512_mul_by_one(void *ret, const void *a, const void *n, BN_ULONG k);
++void rsaz_512_sqr(void *ret, const void *a, const void *n, BN_ULONG k,
++                  int cnt);
++void rsaz_512_scatter4(void *tbl, const BN_ULONG *val, int power);
++void rsaz_512_gather4(BN_ULONG *val, const void *tbl, int power);
++
++void RSAZ_512_mod_exp(BN_ULONG result[8],
++                      const BN_ULONG base[8], const BN_ULONG exponent[8],
++                      const BN_ULONG m[8], BN_ULONG k0, const BN_ULONG RR[8])
++{
++    unsigned char storage[16 * 8 * 8 + 64 * 2 + 64]; /* 1.2KB */
++    unsigned char *table = storage + (64 - ((size_t)storage % 64));
++    BN_ULONG *a_inv = (BN_ULONG *)(table + 16 * 8 * 8);
++    BN_ULONG *temp = (BN_ULONG *)(table + 16 * 8 * 8 + 8 * 8);
++    unsigned char *p_str = (unsigned char *)exponent;
++    int index;
++    unsigned int wvalue;
++
++    /* table[0] = 1_inv */
++    temp[0] = 0 - m[0];
++    temp[1] = ~m[1];
++    temp[2] = ~m[2];
++    temp[3] = ~m[3];
++    temp[4] = ~m[4];
++    temp[5] = ~m[5];
++    temp[6] = ~m[6];
++    temp[7] = ~m[7];
++    rsaz_512_scatter4(table, temp, 0);
++
++    /* table [1] = a_inv^1 */
++    rsaz_512_mul(a_inv, base, RR, m, k0);
++    rsaz_512_scatter4(table, a_inv, 1);
++
++    /* table [2] = a_inv^2 */
++    rsaz_512_sqr(temp, a_inv, m, k0, 1);
++    rsaz_512_scatter4(table, temp, 2);
++
++    for (index = 3; index < 16; index++)
++        rsaz_512_mul_scatter4(temp, a_inv, m, k0, table, index);
++
++    /* load first window */
++    wvalue = p_str[63];
++
++    rsaz_512_gather4(temp, table, wvalue >> 4);
++    rsaz_512_sqr(temp, temp, m, k0, 4);
++    rsaz_512_mul_gather4(temp, temp, table, m, k0, wvalue & 0xf);
++
++    for (index = 62; index >= 0; index--) {
++        wvalue = p_str[index];
++
++        rsaz_512_sqr(temp, temp, m, k0, 4);
++        rsaz_512_mul_gather4(temp, temp, table, m, k0, wvalue >> 4);
++
++        rsaz_512_sqr(temp, temp, m, k0, 4);
++        rsaz_512_mul_gather4(temp, temp, table, m, k0, wvalue & 0x0f);
++    }
++
++    /* from Montgomery */
++    rsaz_512_mul_by_one(result, temp, m, k0);
++
++    OPENSSL_cleanse(storage, sizeof(storage));
++}
++
++#endif
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/bn/rsaz_exp.h b/CryptoPkg/Library/OpensslLib/openssl/crypto/bn/rsaz_exp.h
+new file mode 100644
+index 0000000..9501cc8
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/bn/rsaz_exp.h
+@@ -0,0 +1,77 @@
++/*
++ * Copyright 2013-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++/*****************************************************************************
++*                                                                            *
++*  Copyright (c) 2012, Intel Corporation                                     *
++*                                                                            *
++*  All rights reserved.                                                      *
++*                                                                            *
++*  Redistribution and use in source and binary forms, with or without        *
++*  modification, are permitted provided that the following conditions are    *
++*  met:                                                                      *
++*                                                                            *
++*  *  Redistributions of source code must retain the above copyright         *
++*     notice, this list of conditions and the following disclaimer.          *
++*                                                                            *
++*  *  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.                                                          *
++*                                                                            *
++*  *  Neither the name of the Intel Corporation nor the names of its         *
++*     contributors may be used to endorse or promote products derived from   *
++*     this software without specific prior written permission.               *
++*                                                                            *
++*                                                                            *
++*  THIS SOFTWARE IS PROVIDED BY INTEL CORPORATION ""AS IS"" AND ANY          *
++*  EXPRESS 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 INTEL CORPORATION OR            *
++*  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.              *
++*                                                                            *
++******************************************************************************
++* Developers and authors:                                                    *
++* Shay Gueron (1, 2), and Vlad Krasnov (1)                                   *
++* (1) Intel Corporation, Israel Development Center, Haifa, Israel            *
++* (2) University of Haifa, Israel                                            *
++*****************************************************************************/
++
++#ifndef RSAZ_EXP_H
++# define RSAZ_EXP_H
++
++# undef RSAZ_ENABLED
++# if defined(OPENSSL_BN_ASM_MONT) && \
++        (defined(__x86_64) || defined(__x86_64__) || \
++         defined(_M_AMD64) || defined(_M_X64))
++#  define RSAZ_ENABLED
++
++#  include 
++
++void RSAZ_1024_mod_exp_avx2(BN_ULONG result[16],
++                            const BN_ULONG base_norm[16],
++                            const BN_ULONG exponent[16],
++                            const BN_ULONG m_norm[16], const BN_ULONG RR[16],
++                            BN_ULONG k0);
++int rsaz_avx2_eligible();
++
++void RSAZ_512_mod_exp(BN_ULONG result[8],
++                      const BN_ULONG base_norm[8], const BN_ULONG exponent[8],
++                      const BN_ULONG m_norm[8], BN_ULONG k0,
++                      const BN_ULONG RR[8]);
++
++# endif
++
++#endif
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/buffer/buf_err.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/buffer/buf_err.c
+new file mode 100644
+index 0000000..a6a2ab8
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/buffer/buf_err.c
+@@ -0,0 +1,44 @@
++/*
++ * Generated by util/mkerr.pl DO NOT EDIT
++ * Copyright 1995-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include 
++#include 
++
++/* BEGIN ERROR CODES */
++#ifndef OPENSSL_NO_ERR
++
++# define ERR_FUNC(func) ERR_PACK(ERR_LIB_BUF,func,0)
++# define ERR_REASON(reason) ERR_PACK(ERR_LIB_BUF,0,reason)
++
++static ERR_STRING_DATA BUF_str_functs[] = {
++    {ERR_FUNC(BUF_F_BUF_MEM_GROW), "BUF_MEM_grow"},
++    {ERR_FUNC(BUF_F_BUF_MEM_GROW_CLEAN), "BUF_MEM_grow_clean"},
++    {ERR_FUNC(BUF_F_BUF_MEM_NEW), "BUF_MEM_new"},
++    {0, NULL}
++};
++
++static ERR_STRING_DATA BUF_str_reasons[] = {
++    {0, NULL}
++};
++
++#endif
++
++int ERR_load_BUF_strings(void)
++{
++#ifndef OPENSSL_NO_ERR
++
++    if (ERR_func_error_string(BUF_str_functs[0].error) == NULL) {
++        ERR_load_strings(0, BUF_str_functs);
++        ERR_load_strings(0, BUF_str_reasons);
++    }
++#endif
++    return 1;
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/buffer/buffer.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/buffer/buffer.c
+new file mode 100644
+index 0000000..6b0bd4a
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/buffer/buffer.c
+@@ -0,0 +1,164 @@
++/*
++ * Copyright 1995-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include "internal/cryptlib.h"
++#include 
++
++/*
++ * LIMIT_BEFORE_EXPANSION is the maximum n such that (n+3)/3*4 < 2**31. That
++ * function is applied in several functions in this file and this limit
++ * ensures that the result fits in an int.
++ */
++#define LIMIT_BEFORE_EXPANSION 0x5ffffffc
++
++BUF_MEM *BUF_MEM_new_ex(unsigned long flags)
++{
++    BUF_MEM *ret;
++
++    ret = BUF_MEM_new();
++    if (ret != NULL)
++        ret->flags = flags;
++    return (ret);
++}
++
++BUF_MEM *BUF_MEM_new(void)
++{
++    BUF_MEM *ret;
++
++    ret = OPENSSL_zalloc(sizeof(*ret));
++    if (ret == NULL) {
++        BUFerr(BUF_F_BUF_MEM_NEW, ERR_R_MALLOC_FAILURE);
++        return (NULL);
++    }
++    return (ret);
++}
++
++void BUF_MEM_free(BUF_MEM *a)
++{
++    if (a == NULL)
++        return;
++
++    if (a->data != NULL) {
++        if (a->flags & BUF_MEM_FLAG_SECURE)
++            OPENSSL_secure_free(a->data);
++        else
++            OPENSSL_clear_free(a->data, a->max);
++    }
++    OPENSSL_free(a);
++}
++
++/* Allocate a block of secure memory; copy over old data if there
++ * was any, and then free it. */
++static char *sec_alloc_realloc(BUF_MEM *str, size_t len)
++{
++    char *ret;
++
++    ret = OPENSSL_secure_malloc(len);
++    if (str->data != NULL) {
++        if (ret != NULL)
++            memcpy(ret, str->data, str->length);
++        OPENSSL_secure_free(str->data);
++    }
++    return (ret);
++}
++
++size_t BUF_MEM_grow(BUF_MEM *str, size_t len)
++{
++    char *ret;
++    size_t n;
++
++    if (str->length >= len) {
++        str->length = len;
++        return (len);
++    }
++    if (str->max >= len) {
++        if (str->data != NULL)
++            memset(&str->data[str->length], 0, len - str->length);
++        str->length = len;
++        return (len);
++    }
++    /* This limit is sufficient to ensure (len+3)/3*4 < 2**31 */
++    if (len > LIMIT_BEFORE_EXPANSION) {
++        BUFerr(BUF_F_BUF_MEM_GROW, ERR_R_MALLOC_FAILURE);
++        return 0;
++    }
++    n = (len + 3) / 3 * 4;
++    if ((str->flags & BUF_MEM_FLAG_SECURE))
++        ret = sec_alloc_realloc(str, n);
++    else
++        ret = OPENSSL_realloc(str->data, n);
++    if (ret == NULL) {
++        BUFerr(BUF_F_BUF_MEM_GROW, ERR_R_MALLOC_FAILURE);
++        len = 0;
++    } else {
++        str->data = ret;
++        str->max = n;
++        memset(&str->data[str->length], 0, len - str->length);
++        str->length = len;
++    }
++    return (len);
++}
++
++size_t BUF_MEM_grow_clean(BUF_MEM *str, size_t len)
++{
++    char *ret;
++    size_t n;
++
++    if (str->length >= len) {
++        if (str->data != NULL)
++            memset(&str->data[len], 0, str->length - len);
++        str->length = len;
++        return (len);
++    }
++    if (str->max >= len) {
++        memset(&str->data[str->length], 0, len - str->length);
++        str->length = len;
++        return (len);
++    }
++    /* This limit is sufficient to ensure (len+3)/3*4 < 2**31 */
++    if (len > LIMIT_BEFORE_EXPANSION) {
++        BUFerr(BUF_F_BUF_MEM_GROW_CLEAN, ERR_R_MALLOC_FAILURE);
++        return 0;
++    }
++    n = (len + 3) / 3 * 4;
++    if ((str->flags & BUF_MEM_FLAG_SECURE))
++        ret = sec_alloc_realloc(str, n);
++    else
++        ret = OPENSSL_clear_realloc(str->data, str->max, n);
++    if (ret == NULL) {
++        BUFerr(BUF_F_BUF_MEM_GROW_CLEAN, ERR_R_MALLOC_FAILURE);
++        len = 0;
++    } else {
++        str->data = ret;
++        str->max = n;
++        memset(&str->data[str->length], 0, len - str->length);
++        str->length = len;
++    }
++    return (len);
++}
++
++void BUF_reverse(unsigned char *out, const unsigned char *in, size_t size)
++{
++    size_t i;
++    if (in) {
++        out += size - 1;
++        for (i = 0; i < size; i++)
++            *out-- = *in++;
++    } else {
++        unsigned char *q;
++        char c;
++        q = out + size - 1;
++        for (i = 0; i < size / 2; i++) {
++            c = *q;
++            *q-- = *out;
++            *out++ = c;
++        }
++    }
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/buffer/build.info b/CryptoPkg/Library/OpensslLib/openssl/crypto/buffer/build.info
+new file mode 100644
+index 0000000..54da1f9
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/buffer/build.info
+@@ -0,0 +1,2 @@
++LIBS=../../libcrypto
++SOURCE[../../libcrypto]=buffer.c buf_err.c
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/build.info b/CryptoPkg/Library/OpensslLib/openssl/crypto/build.info
+new file mode 100644
+index 0000000..916d24f
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/build.info
+@@ -0,0 +1,37 @@
++{- use File::Spec::Functions qw/catdir catfile/; -}
++LIBS=../libcrypto
++SOURCE[../libcrypto]=\
++        cryptlib.c mem.c mem_dbg.c cversion.c ex_data.c cpt_err.c \
++        ebcdic.c uid.c o_time.c o_str.c o_dir.c o_fopen.c \
++        threads_pthread.c threads_win.c threads_none.c \
++        o_init.c o_fips.c mem_sec.c init.c {- $target{cpuid_asm_src} -} \
++        {- $target{uplink_aux_src} -}
++EXTRA=  ../ms/uplink-x86.pl ../ms/uplink.c ../ms/applink.c \
++        x86cpuid.pl x86_64cpuid.pl ia64cpuid.S \
++        ppccpuid.pl pariscid.pl alphacpuid.pl arm64cpuid.pl armv4cpuid.pl
++
++DEPEND[cversion.o]=buildinf.h
++GENERATE[buildinf.h]=../util/mkbuildinf.pl "$(CC) $(CFLAGS_Q)" "$(PLATFORM)"
++DEPEND[buildinf.h]=../configdata.pm
++
++GENERATE[uplink-x86.s]=../ms/uplink-x86.pl $(PERLASM_SCHEME)
++GENERATE[uplink-x86_64.s]=../ms/uplink-x86_64.pl $(PERLASM_SCHEME)
++GENERATE[uplink-ia64.s]=../ms/uplink-ia64.pl $(PERLASM_SCHEME)
++
++GENERATE[x86cpuid.s]=x86cpuid.pl $(PERLASM_SCHEME) $(CFLAGS) $(LIB_CFLAGS) $(PROCESSOR)
++DEPEND[x86cpuid.s]=perlasm/x86asm.pl
++
++GENERATE[x86_64cpuid.s]=x86_64cpuid.pl $(PERLASM_SCHEME)
++
++GENERATE[ia64cpuid.s]=ia64cpuid.S
++GENERATE[ppccpuid.s]=ppccpuid.pl $(PERLASM_SCHEME)
++GENERATE[pariscid.s]=pariscid.pl $(PERLASM_SCHEME)
++GENERATE[alphacpuid.s]=alphacpuid.pl
++GENERATE[arm64cpuid.S]=arm64cpuid.pl $(PERLASM_SCHEME)
++INCLUDE[arm64cpuid.o]=.
++GENERATE[armv4cpuid.S]=armv4cpuid.pl $(PERLASM_SCHEME)
++INCLUDE[armv4cpuid.o]=.
++
++IF[{- $config{target} =~ /^(?:Cygwin|mingw|VC-)/ -}]
++  SHARED_SOURCE[../libcrypto]=dllmain.c
++ENDIF
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/c64xpluscpuid.pl b/CryptoPkg/Library/OpensslLib/openssl/crypto/c64xpluscpuid.pl
+new file mode 100644
+index 0000000..9efe120
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/c64xpluscpuid.pl
+@@ -0,0 +1,287 @@
++#! /usr/bin/env perl
++# Copyright 2012-2016 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
++# in the file LICENSE in the source distribution or at
++# https://www.openssl.org/source/license.html
++
++while (($output=shift) && ($output!~/\w[\w\-]*\.\w+$/)) {}
++open STDOUT,">$output";
++
++$code.=<<___;
++	.text
++
++	.if	.ASSEMBLER_VERSION<7000000
++	.asg	0,__TI_EABI__
++	.endif
++	.if	__TI_EABI__
++	.asg	OPENSSL_rdtsc,_OPENSSL_rdtsc
++	.asg	OPENSSL_cleanse,_OPENSSL_cleanse
++	.asg	CRYPTO_memcmp,_CRYPTO_memcmp
++	.asg	OPENSSL_atomic_add,_OPENSSL_atomic_add
++	.asg	OPENSSL_wipe_cpu,_OPENSSL_wipe_cpu
++	.asg	OPENSSL_instrument_bus,_OPENSSL_instrument_bus
++	.asg	OPENSSL_instrument_bus2,_OPENSSL_instrument_bus2
++	.endif
++
++	.asg	B3,RA
++
++	.global	_OPENSSL_rdtsc
++_OPENSSL_rdtsc:
++	.asmfunc
++	B	RA
++	MVC	TSCL,B0
++	MVC	TSCH,B1
++  [!B0]	MVC	B0,TSCL		; start TSC
++	MV	B0,A4
++	MV	B1,A5
++	.endasmfunc
++
++	.global	_OPENSSL_cleanse
++_OPENSSL_cleanse:
++	.asmfunc
++	ZERO	A3:A2
++||	ZERO	B2
++||	SHRU	B4,3,B0		; is length >= 8
++||	ADD	1,A4,B6
++  [!B0]	BNOP	RA
++||	ZERO	A1
++||	ZERO	B1
++   [B0]	MVC	B0,ILC
++||[!B0]	CMPLT	0,B4,A1
++||[!B0]	CMPLT	1,B4,B1
++   [A1]	STB	A2,*A4++[2]
++|| [B1] STB	B2,*B6++[2]
++||[!B0]	CMPLT	2,B4,A1
++||[!B0]	CMPLT	3,B4,B1
++   [A1]	STB	A2,*A4++[2]
++|| [B1] STB	B2,*B6++[2]
++||[!B0]	CMPLT	4,B4,A1
++||[!B0]	CMPLT	5,B4,B1
++   [A1]	STB	A2,*A4++[2]
++|| [B1] STB	B2,*B6++[2]
++||[!B0]	CMPLT	6,B4,A1
++   [A1]	STB	A2,*A4++[2]
++
++	SPLOOP	1
++	STNDW	A3:A2,*A4++
++||	SUB	B4,8,B4
++	SPKERNEL
++
++	MV	B4,B0		; remaining bytes
++||	ADD	1,A4,B6
++||	BNOP	RA
++   [B0]	CMPLT	0,B0,A1
++|| [B0]	CMPLT	1,B0,B1
++   [A1]	STB	A2,*A4++[2]
++|| [B1] STB	B2,*B6++[2]
++|| [B0]	CMPLT	2,B0,A1
++|| [B0]	CMPLT	3,B0,B1
++   [A1]	STB	A2,*A4++[2]
++|| [B1] STB	B2,*B6++[2]
++|| [B0]	CMPLT	4,B0,A1
++|| [B0]	CMPLT	5,B0,B1
++   [A1]	STB	A2,*A4++[2]
++|| [B1] STB	B2,*B6++[2]
++|| [B0]	CMPLT	6,B0,A1
++   [A1]	STB	A2,*A4++[2]
++	.endasmfunc
++
++	.global	_CRYPTO_memcmp
++_CRYPTO_memcmp:
++	.asmfunc
++	MV	A6,B0
++  [!B0]	BNOP	RA
++||[!B0]	ZERO	A4
++   [B0]	MVC	B0,ILC
++|| [B0]	ZERO	A0
++	NOP	4
++
++	SPLOOP	1
++	LDBU	*A4++,A1
++||	LDBU	*B4++,B1
++	NOP	4
++	XOR.L	B1,A1,A2
++	SPKERNEL 1,0
++||	OR.S	A2,A0,A0
++
++	BNOP	RA,3
++	ZERO.L	A4
++  [A0]	MVK	1,A4
++	.endasmfunc
++
++	.global	_OPENSSL_atomic_add
++_OPENSSL_atomic_add:
++	.asmfunc
++	MV	A4,B0
++atomic_add?:
++	LL	*B0,B5
++	NOP	4
++	ADD	B4,B5,B5
++	SL	B5,*B0
++	CMTL	*B0,B1
++	NOP	4
++  [!B1]	B	atomic_add?
++   [B1]	BNOP	RA,4
++	MV	B5,A4
++	.endasmfunc
++
++	.global	_OPENSSL_wipe_cpu
++_OPENSSL_wipe_cpu:
++	.asmfunc
++	ZERO	A0
++||	ZERO	B0
++||	ZERO	A1
++||	ZERO	B1
++	ZERO	A3:A2
++||	MVD	B0,B2
++||	ZERO	A4
++||	ZERO	B4
++||	ZERO	A5
++||	ZERO	B5
++||	BNOP	RA
++	ZERO	A7:A6
++||	ZERO	B7:B6
++||	ZERO	A8
++||	ZERO	B8
++||	ZERO	A9
++||	ZERO	B9
++	ZERO	A17:A16
++||	ZERO	B17:B16
++||	ZERO	A18
++||	ZERO	B18
++||	ZERO	A19
++||	ZERO	B19
++	ZERO	A21:A20
++||	ZERO	B21:B20
++||	ZERO	A22
++||	ZERO	B22
++||	ZERO	A23
++||	ZERO	B23
++	ZERO	A25:A24
++||	ZERO	B25:B24
++||	ZERO	A26
++||	ZERO	B26
++||	ZERO	A27
++||	ZERO	B27
++	ZERO	A29:A28
++||	ZERO	B29:B28
++||	ZERO	A30
++||	ZERO	B30
++||	ZERO	A31
++||	ZERO	B31
++	.endasmfunc
++
++CLFLUSH	.macro	CONTROL,ADDR,LEN
++	B	passthrough?
++||	STW	ADDR,*CONTROL[0]
++	STW	LEN,*CONTROL[1]
++spinlock?:
++	LDW	*CONTROL[1],A0
++	NOP	3
++passthrough?:
++	NOP
++  [A0]	BNOP	spinlock?,5
++	.endm
++
++	.global	_OPENSSL_instrument_bus
++_OPENSSL_instrument_bus:
++	.asmfunc
++	MV	B4,B0			; reassign sizeof(output)
++||	MV	A4,B4			; reassign output
++||	MVK	0x00004030,A3
++	MV	B0,A4			; return value
++||	MVK	1,A1
++||	MVKH	0x01840000,A3		; L1DWIBAR
++	MVC	TSCL,B8			; collect 1st tick
++||	MVK	0x00004010,A5
++	MV	B8,B9			; lasttick = tick
++||	MVK	0,B7			; lastdiff = 0
++||	MVKH	0x01840000,A5		; L2WIBAR
++	CLFLUSH	A3,B4,A1		; write-back and invalidate L1D line
++	CLFLUSH	A5,B4,A1		; write-back and invalidate L2 line
++	LL	*B4,B5
++	NOP	4
++	ADD	B7,B5,B5
++	SL	B5,*B4
++	CMTL	*B4,B1
++	NOP	4
++	STW	B5,*B4
++bus_loop1?:
++	MVC	TSCL,B8
++|| [B0]	SUB	B0,1,B0
++	SUB	B8,B9,B7		; lastdiff = tick - lasttick
++||	MV	B8,B9			; lasttick = tick
++	CLFLUSH	A3,B4,A1		; write-back and invalidate L1D line
++	CLFLUSH	A5,B4,A1		; write-back and invalidate L2 line
++	LL	*B4,B5
++	NOP	4
++	ADD	B7,B5,B5
++	SL	B5,*B4
++	CMTL	*B4,B1
++	STW	B5,*B4			; [!B1] is removed to flatten samples
++||	ADDK	4,B4
++|| [B0]	BNOP	bus_loop1?,5
++
++	BNOP	RA,5
++	.endasmfunc
++
++	.global	_OPENSSL_instrument_bus2
++_OPENSSL_instrument_bus2:
++	.asmfunc
++	MV	A6,B0			; reassign max
++||	MV	B4,A6			; reassing sizeof(output)
++||	MVK	0x00004030,A3
++	MV	A4,B4			; reassign output
++||	MVK	0,A4			; return value
++||	MVK	1,A1
++||	MVKH	0x01840000,A3		; L1DWIBAR
++
++	MVC	TSCL,B8			; collect 1st tick
++||	MVK	0x00004010,A5
++	MV	B8,B9			; lasttick = tick
++||	MVK	0,B7			; lastdiff = 0
++||	MVKH	0x01840000,A5		; L2WIBAR
++	CLFLUSH	A3,B4,A1		; write-back and invalidate L1D line
++	CLFLUSH	A5,B4,A1		; write-back and invalidate L2 line
++	LL	*B4,B5
++	NOP	4
++	ADD	B7,B5,B5
++	SL	B5,*B4
++	CMTL	*B4,B1
++	NOP	4
++	STW	B5,*B4
++
++	MVC	TSCL,B8			; collect 1st diff
++	SUB	B8,B9,B7		; lastdiff = tick - lasttick
++||	MV	B8,B9			; lasttick = tick
++||	SUB	B0,1,B0
++bus_loop2?:
++	CLFLUSH	A3,B4,A1		; write-back and invalidate L1D line
++	CLFLUSH	A5,B4,A1		; write-back and invalidate L2 line
++	LL	*B4,B5
++	NOP	4
++	ADD	B7,B5,B5
++	SL	B5,*B4
++	CMTL	*B4,B1
++	STW	B5,*B4			; [!B1] is removed to flatten samples
++||[!B0]	BNOP	bus_loop2_done?,2
++||	SUB	B0,1,B0
++	MVC	TSCL,B8
++	SUB	B8,B9,B8
++||	MV	B8,B9
++	CMPEQ	B8,B7,B2
++||	MV	B8,B7
++  [!B2]	ADDAW	B4,1,B4
++||[!B2]	ADDK	1,A4
++	CMPEQ	A4,A6,A2
++  [!A2]	BNOP	bus_loop2?,5
++
++bus_loop2_done?:
++	BNOP	RA,5
++	.endasmfunc
++___
++
++print $code;
++close STDOUT;
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/camellia/asm/cmll-x86.pl b/CryptoPkg/Library/OpensslLib/openssl/crypto/camellia/asm/cmll-x86.pl
+new file mode 100644
+index 0000000..59f9ed9
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/camellia/asm/cmll-x86.pl
+@@ -0,0 +1,1150 @@
++#! /usr/bin/env perl
++# Copyright 2008-2016 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
++# in the file LICENSE in the source distribution or at
++# https://www.openssl.org/source/license.html
++
++
++# ====================================================================
++# Copyright (c) 2008 Andy Polyakov 
++#
++# This module may be used under the terms of either the GNU General
++# Public License version 2 or later, the GNU Lesser General Public
++# License version 2.1 or later, the Mozilla Public License version
++# 1.1 or the BSD License. The exact terms of either license are
++# distributed along with this module. For further details see
++# http://www.openssl.org/~appro/camellia/.
++# ====================================================================
++
++# Performance in cycles per processed byte (less is better) in
++# 'openssl speed ...' benchmark:
++#
++#			AMD K8	Core2	PIII	P4
++# -evp camellia-128-ecb	21.5	22.8	27.0	28.9
++# + over gcc 3.4.6	+90/11% +70/10%	+53/4%	+160/64%
++# + over icc 8.0	+48/19% +21/15%	+21/17%	+55/37%
++#
++# camellia-128-cbc	17.3	21.1	23.9	25.9
++#
++# 128-bit key setup	196	280	256	240	cycles/key
++# + over gcc 3.4.6	+30/0%	+17/11%	+11/0%	+63/40%
++# + over icc 8.0	+18/3%	+10/0%	+10/3%	+21/10%
++#
++# Pairs of numbers in "+" rows represent performance improvement over
++# compiler generated position-independent code, PIC, and non-PIC
++# respectively. PIC results are of greater relevance, as this module
++# is position-independent, i.e. suitable for a shared library or PIE.
++# Position independence "costs" one register, which is why compilers
++# are so close with non-PIC results, they have an extra register to
++# spare. CBC results are better than ECB ones thanks to "zero-copy"
++# private _x86_* interface, and are ~30-40% better than with compiler
++# generated cmll_cbc.o, and reach ~80-90% of x86_64 performance on
++# same CPU (where applicable).
++
++$0 =~ m/(.*[\/\\])[^\/\\]+$/; $dir=$1;
++push(@INC,"${dir}","${dir}../../perlasm");
++require "x86asm.pl";
++
++$OPENSSL=1;
++
++$output = pop;
++open STDOUT,">$output";
++
++&asm_init($ARGV[0],"cmll-586.pl",$ARGV[$#ARGV] eq "386");
++
++@T=("eax","ebx","ecx","edx");
++$idx="esi";
++$key="edi";
++$Tbl="ebp";
++
++# stack frame layout in _x86_Camellia_* routines, frame is allocated
++# by caller
++$__ra=&DWP(0,"esp");	# return address
++$__s0=&DWP(4,"esp");	# s0 backing store
++$__s1=&DWP(8,"esp");	# s1 backing store
++$__s2=&DWP(12,"esp");	# s2 backing store
++$__s3=&DWP(16,"esp");	# s3 backing store
++$__end=&DWP(20,"esp");	# pointer to end/start of key schedule
++
++# stack frame layout in Camellia_[en|crypt] routines, which differs from
++# above by 4 and overlaps by pointer to end/start of key schedule
++$_end=&DWP(16,"esp");
++$_esp=&DWP(20,"esp");
++
++# const unsigned int Camellia_SBOX[4][256];
++# Well, sort of... Camellia_SBOX[0][] is interleaved with [1][],
++# and [2][] - with [3][]. This is done to optimize code size.
++$SBOX1_1110=0;		# Camellia_SBOX[0]
++$SBOX4_4404=4;		# Camellia_SBOX[1]
++$SBOX2_0222=2048;	# Camellia_SBOX[2]
++$SBOX3_3033=2052;	# Camellia_SBOX[3]
++&static_label("Camellia_SIGMA");
++&static_label("Camellia_SBOX");
++
++sub Camellia_Feistel {
++my $i=@_[0];
++my $seed=defined(@_[1])?@_[1]:0;
++my $scale=$seed<0?-8:8;
++my $frame=defined(@_[2])?@_[2]:0;
++my $j=($i&1)*2;
++my $t0=@T[($j)%4],$t1=@T[($j+1)%4],$t2=@T[($j+2)%4],$t3=@T[($j+3)%4];
++
++	&xor	($t0,$idx);				# t0^=key[0]
++	&xor	($t1,&DWP($seed+$i*$scale+4,$key));	# t1^=key[1]
++	&movz	($idx,&HB($t0));			# (t0>>8)&0xff
++	&mov	($t3,&DWP($SBOX3_3033,$Tbl,$idx,8));	# t3=SBOX3_3033[0]
++	&movz	($idx,&LB($t0));			# (t0>>0)&0xff
++	&xor	($t3,&DWP($SBOX4_4404,$Tbl,$idx,8));	# t3^=SBOX4_4404[0]
++	&shr	($t0,16);
++	&movz	($idx,&LB($t1));			# (t1>>0)&0xff
++	&mov	($t2,&DWP($SBOX1_1110,$Tbl,$idx,8));	# t2=SBOX1_1110[1]
++	&movz	($idx,&HB($t0));			# (t0>>24)&0xff
++	&xor	($t3,&DWP($SBOX1_1110,$Tbl,$idx,8));	# t3^=SBOX1_1110[0]
++	&movz	($idx,&HB($t1));			# (t1>>8)&0xff
++	&xor	($t2,&DWP($SBOX4_4404,$Tbl,$idx,8));	# t2^=SBOX4_4404[1]
++	&shr	($t1,16);
++	&movz	($t0,&LB($t0));				# (t0>>16)&0xff
++	&xor	($t3,&DWP($SBOX2_0222,$Tbl,$t0,8));	# t3^=SBOX2_0222[0]
++	&movz	($idx,&HB($t1));			# (t1>>24)&0xff
++	&mov	($t0,&DWP($frame+4*(($j+3)%4),"esp"));	# prefetch "s3"
++	&xor	($t2,$t3);				# t2^=t3
++	&rotr	($t3,8);				# t3=RightRotate(t3,8)
++	&xor	($t2,&DWP($SBOX2_0222,$Tbl,$idx,8));	# t2^=SBOX2_0222[1]
++	&movz	($idx,&LB($t1));			# (t1>>16)&0xff
++	&mov	($t1,&DWP($frame+4*(($j+2)%4),"esp"));	# prefetch "s2"
++	&xor	($t3,$t0);				# t3^=s3
++	&xor	($t2,&DWP($SBOX3_3033,$Tbl,$idx,8));	# t2^=SBOX3_3033[1]
++	&mov	($idx,&DWP($seed+($i+1)*$scale,$key));	# prefetch key[i+1]
++	&xor	($t3,$t2);				# t3^=t2
++	&mov	(&DWP($frame+4*(($j+3)%4),"esp"),$t3);	# s3=t3
++	&xor	($t2,$t1);				# t2^=s2
++	&mov	(&DWP($frame+4*(($j+2)%4),"esp"),$t2);	# s2=t2
++}
++
++# void Camellia_EncryptBlock_Rounds(
++#		int grandRounds,
++#		const Byte plaintext[],
++#		const KEY_TABLE_TYPE keyTable,
++#		Byte ciphertext[])
++&function_begin("Camellia_EncryptBlock_Rounds");
++	&mov	("eax",&wparam(0));	# load grandRounds
++	&mov	($idx,&wparam(1));	# load plaintext pointer
++	&mov	($key,&wparam(2));	# load key schedule pointer
++
++	&mov	("ebx","esp");
++	&sub	("esp",7*4);		# place for s[0-3],keyEnd,esp and ra
++	&and	("esp",-64);
++
++	# place stack frame just "above mod 1024" the key schedule
++	# this ensures that cache associativity of 2 suffices
++	&lea	("ecx",&DWP(-64-63,$key));
++	&sub	("ecx","esp");
++	&neg	("ecx");
++	&and	("ecx",0x3C0);	# modulo 1024, but aligned to cache-line
++	&sub	("esp","ecx");
++	&add	("esp",4);	# 4 is reserved for callee's return address
++
++	&shl	("eax",6);
++	&lea	("eax",&DWP(0,$key,"eax"));
++	&mov	($_esp,"ebx");	# save %esp
++	&mov	($_end,"eax");	# save keyEnd
++
++	&call	(&label("pic_point"));
++	&set_label("pic_point");
++	&blindpop($Tbl);
++	&lea	($Tbl,&DWP(&label("Camellia_SBOX")."-".&label("pic_point"),$Tbl));
++
++	&mov	(@T[0],&DWP(0,$idx));	# load plaintext
++	&mov	(@T[1],&DWP(4,$idx));
++	&mov	(@T[2],&DWP(8,$idx));
++	&bswap	(@T[0]);
++	&mov	(@T[3],&DWP(12,$idx));
++	&bswap	(@T[1]);
++	&bswap	(@T[2]);
++	&bswap	(@T[3]);
++
++	&call	("_x86_Camellia_encrypt");
++
++	&mov	("esp",$_esp);
++	&bswap	(@T[0]);
++	&mov	($idx,&wparam(3));	# load ciphertext pointer
++	&bswap	(@T[1]);
++	&bswap	(@T[2]);
++	&bswap	(@T[3]);
++	&mov	(&DWP(0,$idx),@T[0]);	# write ciphertext
++	&mov	(&DWP(4,$idx),@T[1]);
++	&mov	(&DWP(8,$idx),@T[2]);
++	&mov	(&DWP(12,$idx),@T[3]);
++&function_end("Camellia_EncryptBlock_Rounds");
++# V1.x API
++&function_begin_B("Camellia_EncryptBlock");
++	&mov	("eax",128);
++	&sub	("eax",&wparam(0));	# load keyBitLength
++	&mov	("eax",3);
++	&adc	("eax",0);		# keyBitLength==128?3:4
++	&mov	(&wparam(0),"eax");
++	&jmp	(&label("Camellia_EncryptBlock_Rounds"));
++&function_end_B("Camellia_EncryptBlock");
++
++if ($OPENSSL) {
++# void Camellia_encrypt(
++#		const unsigned char *in,
++#		unsigned char *out,
++#		const CAMELLIA_KEY *key)
++&function_begin("Camellia_encrypt");
++	&mov	($idx,&wparam(0));	# load plaintext pointer
++	&mov	($key,&wparam(2));	# load key schedule pointer
++
++	&mov	("ebx","esp");
++	&sub	("esp",7*4);		# place for s[0-3],keyEnd,esp and ra
++	&and	("esp",-64);
++	&mov	("eax",&DWP(272,$key));	# load grandRounds counter
++
++	# place stack frame just "above mod 1024" the key schedule
++	# this ensures that cache associativity of 2 suffices
++	&lea	("ecx",&DWP(-64-63,$key));
++	&sub	("ecx","esp");
++	&neg	("ecx");
++	&and	("ecx",0x3C0);	# modulo 1024, but aligned to cache-line
++	&sub	("esp","ecx");
++	&add	("esp",4);	# 4 is reserved for callee's return address
++
++	&shl	("eax",6);
++	&lea	("eax",&DWP(0,$key,"eax"));
++	&mov	($_esp,"ebx");	# save %esp
++	&mov	($_end,"eax");	# save keyEnd
++
++	&call	(&label("pic_point"));
++	&set_label("pic_point");
++	&blindpop($Tbl);
++	&lea	($Tbl,&DWP(&label("Camellia_SBOX")."-".&label("pic_point"),$Tbl));
++
++	&mov	(@T[0],&DWP(0,$idx));	# load plaintext
++	&mov	(@T[1],&DWP(4,$idx));
++	&mov	(@T[2],&DWP(8,$idx));
++	&bswap	(@T[0]);
++	&mov	(@T[3],&DWP(12,$idx));
++	&bswap	(@T[1]);
++	&bswap	(@T[2]);
++	&bswap	(@T[3]);
++
++	&call	("_x86_Camellia_encrypt");
++
++	&mov	("esp",$_esp);
++	&bswap	(@T[0]);
++	&mov	($idx,&wparam(1));	# load ciphertext pointer
++	&bswap	(@T[1]);
++	&bswap	(@T[2]);
++	&bswap	(@T[3]);
++	&mov	(&DWP(0,$idx),@T[0]);	# write ciphertext
++	&mov	(&DWP(4,$idx),@T[1]);
++	&mov	(&DWP(8,$idx),@T[2]);
++	&mov	(&DWP(12,$idx),@T[3]);
++&function_end("Camellia_encrypt");
++}
++
++&function_begin_B("_x86_Camellia_encrypt");
++	&xor	(@T[0],&DWP(0,$key));	# ^=key[0-3]
++	&xor	(@T[1],&DWP(4,$key));
++	&xor	(@T[2],&DWP(8,$key));
++	&xor	(@T[3],&DWP(12,$key));
++	&mov	($idx,&DWP(16,$key));	# prefetch key[4]
++
++	&mov	($__s0,@T[0]);		# save s[0-3]
++	&mov	($__s1,@T[1]);
++	&mov	($__s2,@T[2]);
++	&mov	($__s3,@T[3]);
++
++&set_label("loop",16);
++	for ($i=0;$i<6;$i++) { Camellia_Feistel($i,16,4); }
++
++	&add	($key,16*4);
++	&cmp	($key,$__end);
++	&je	(&label("done"));
++
++	# @T[0-1] are preloaded, $idx is preloaded with key[0]
++	&and	($idx,@T[0]);
++	 &mov	 (@T[3],$__s3);
++	&rotl	($idx,1);
++	 &mov	 (@T[2],@T[3]);
++	&xor	(@T[1],$idx);
++	 &or	 (@T[2],&DWP(12,$key));
++	&mov	($__s1,@T[1]);		# s1^=LeftRotate(s0&key[0],1);
++	 &xor	 (@T[2],$__s2);
++
++	&mov	($idx,&DWP(4,$key));
++	 &mov	 ($__s2,@T[2]);		# s2^=s3|key[3];
++	&or	($idx,@T[1]);
++	 &and	 (@T[2],&DWP(8,$key));
++	&xor	(@T[0],$idx);
++	 &rotl	 (@T[2],1);
++	&mov	($__s0,@T[0]);		# s0^=s1|key[1];
++	 &xor	 (@T[3],@T[2]);
++	&mov	($idx,&DWP(16,$key));		# prefetch key[4]
++	 &mov	 ($__s3,@T[3]);		# s3^=LeftRotate(s2&key[2],1);
++	&jmp	(&label("loop"));
++
++&set_label("done",8);
++	&mov	(@T[2],@T[0]);		# SwapHalf
++	&mov	(@T[3],@T[1]);
++	&mov	(@T[0],$__s2);
++	&mov	(@T[1],$__s3);
++	&xor	(@T[0],$idx);		# $idx is preloaded with key[0]
++	&xor	(@T[1],&DWP(4,$key));
++	&xor	(@T[2],&DWP(8,$key));
++	&xor	(@T[3],&DWP(12,$key));
++	&ret	();
++&function_end_B("_x86_Camellia_encrypt");
++
++# void Camellia_DecryptBlock_Rounds(
++#		int grandRounds,
++#		const Byte ciphertext[],
++#		const KEY_TABLE_TYPE keyTable,
++#		Byte plaintext[])
++&function_begin("Camellia_DecryptBlock_Rounds");
++	&mov	("eax",&wparam(0));	# load grandRounds
++	&mov	($idx,&wparam(1));	# load ciphertext pointer
++	&mov	($key,&wparam(2));	# load key schedule pointer
++
++	&mov	("ebx","esp");
++	&sub	("esp",7*4);		# place for s[0-3],keyEnd,esp and ra
++	&and	("esp",-64);
++
++	# place stack frame just "above mod 1024" the key schedule
++	# this ensures that cache associativity of 2 suffices
++	&lea	("ecx",&DWP(-64-63,$key));
++	&sub	("ecx","esp");
++	&neg	("ecx");
++	&and	("ecx",0x3C0);	# modulo 1024, but aligned to cache-line
++	&sub	("esp","ecx");
++	&add	("esp",4);	# 4 is reserved for callee's return address
++
++	&shl	("eax",6);
++	&mov	(&DWP(4*4,"esp"),$key);	# save keyStart
++	&lea	($key,&DWP(0,$key,"eax"));
++	&mov	(&DWP(5*4,"esp"),"ebx");# save %esp
++
++	&call	(&label("pic_point"));
++	&set_label("pic_point");
++	&blindpop($Tbl);
++	&lea	($Tbl,&DWP(&label("Camellia_SBOX")."-".&label("pic_point"),$Tbl));
++
++	&mov	(@T[0],&DWP(0,$idx));	# load ciphertext
++	&mov	(@T[1],&DWP(4,$idx));
++	&mov	(@T[2],&DWP(8,$idx));
++	&bswap	(@T[0]);
++	&mov	(@T[3],&DWP(12,$idx));
++	&bswap	(@T[1]);
++	&bswap	(@T[2]);
++	&bswap	(@T[3]);
++
++	&call	("_x86_Camellia_decrypt");
++
++	&mov	("esp",&DWP(5*4,"esp"));
++	&bswap	(@T[0]);
++	&mov	($idx,&wparam(3));	# load plaintext pointer
++	&bswap	(@T[1]);
++	&bswap	(@T[2]);
++	&bswap	(@T[3]);
++	&mov	(&DWP(0,$idx),@T[0]);	# write plaintext
++	&mov	(&DWP(4,$idx),@T[1]);
++	&mov	(&DWP(8,$idx),@T[2]);
++	&mov	(&DWP(12,$idx),@T[3]);
++&function_end("Camellia_DecryptBlock_Rounds");
++# V1.x API
++&function_begin_B("Camellia_DecryptBlock");
++	&mov	("eax",128);
++	&sub	("eax",&wparam(0));	# load keyBitLength
++	&mov	("eax",3);
++	&adc	("eax",0);		# keyBitLength==128?3:4
++	&mov	(&wparam(0),"eax");
++	&jmp	(&label("Camellia_DecryptBlock_Rounds"));
++&function_end_B("Camellia_DecryptBlock");
++
++if ($OPENSSL) {
++# void Camellia_decrypt(
++#		const unsigned char *in,
++#		unsigned char *out,
++#		const CAMELLIA_KEY *key)
++&function_begin("Camellia_decrypt");
++	&mov	($idx,&wparam(0));	# load ciphertext pointer
++	&mov	($key,&wparam(2));	# load key schedule pointer
++
++	&mov	("ebx","esp");
++	&sub	("esp",7*4);		# place for s[0-3],keyEnd,esp and ra
++	&and	("esp",-64);
++	&mov	("eax",&DWP(272,$key));	# load grandRounds counter
++
++	# place stack frame just "above mod 1024" the key schedule
++	# this ensures that cache associativity of 2 suffices
++	&lea	("ecx",&DWP(-64-63,$key));
++	&sub	("ecx","esp");
++	&neg	("ecx");
++	&and	("ecx",0x3C0);	# modulo 1024, but aligned to cache-line
++	&sub	("esp","ecx");
++	&add	("esp",4);	# 4 is reserved for callee's return address
++
++	&shl	("eax",6);
++	&mov	(&DWP(4*4,"esp"),$key);	# save keyStart
++	&lea	($key,&DWP(0,$key,"eax"));
++	&mov	(&DWP(5*4,"esp"),"ebx");# save %esp
++
++	&call	(&label("pic_point"));
++	&set_label("pic_point");
++	&blindpop($Tbl);
++	&lea	($Tbl,&DWP(&label("Camellia_SBOX")."-".&label("pic_point"),$Tbl));
++
++	&mov	(@T[0],&DWP(0,$idx));	# load ciphertext
++	&mov	(@T[1],&DWP(4,$idx));
++	&mov	(@T[2],&DWP(8,$idx));
++	&bswap	(@T[0]);
++	&mov	(@T[3],&DWP(12,$idx));
++	&bswap	(@T[1]);
++	&bswap	(@T[2]);
++	&bswap	(@T[3]);
++
++	&call	("_x86_Camellia_decrypt");
++
++	&mov	("esp",&DWP(5*4,"esp"));
++	&bswap	(@T[0]);
++	&mov	($idx,&wparam(1));	# load plaintext pointer
++	&bswap	(@T[1]);
++	&bswap	(@T[2]);
++	&bswap	(@T[3]);
++	&mov	(&DWP(0,$idx),@T[0]);	# write plaintext
++	&mov	(&DWP(4,$idx),@T[1]);
++	&mov	(&DWP(8,$idx),@T[2]);
++	&mov	(&DWP(12,$idx),@T[3]);
++&function_end("Camellia_decrypt");
++}
++
++&function_begin_B("_x86_Camellia_decrypt");
++	&xor	(@T[0],&DWP(0,$key));	# ^=key[0-3]
++	&xor	(@T[1],&DWP(4,$key));
++	&xor	(@T[2],&DWP(8,$key));
++	&xor	(@T[3],&DWP(12,$key));
++	&mov	($idx,&DWP(-8,$key));	# prefetch key[-2]
++
++	&mov	($__s0,@T[0]);		# save s[0-3]
++	&mov	($__s1,@T[1]);
++	&mov	($__s2,@T[2]);
++	&mov	($__s3,@T[3]);
++
++&set_label("loop",16);
++	for ($i=0;$i<6;$i++) { Camellia_Feistel($i,-8,4); }
++
++	&sub	($key,16*4);
++	&cmp	($key,$__end);
++	&je	(&label("done"));
++
++	# @T[0-1] are preloaded, $idx is preloaded with key[2]
++	&and	($idx,@T[0]);
++	 &mov	 (@T[3],$__s3);
++	&rotl	($idx,1);
++	 &mov	 (@T[2],@T[3]);
++	&xor	(@T[1],$idx);
++	 &or	 (@T[2],&DWP(4,$key));
++	&mov	($__s1,@T[1]);		# s1^=LeftRotate(s0&key[0],1);
++	 &xor	 (@T[2],$__s2);
++
++	&mov	($idx,&DWP(12,$key));
++	 &mov	 ($__s2,@T[2]);		# s2^=s3|key[3];
++	&or	($idx,@T[1]);
++	 &and	 (@T[2],&DWP(0,$key));
++	&xor	(@T[0],$idx);
++	 &rotl	 (@T[2],1);
++	&mov	($__s0,@T[0]);		# s0^=s1|key[1];
++	 &xor	 (@T[3],@T[2]);
++	&mov	($idx,&DWP(-8,$key));	# prefetch key[4]
++	 &mov	 ($__s3,@T[3]);		# s3^=LeftRotate(s2&key[2],1);
++	&jmp	(&label("loop"));
++
++&set_label("done",8);
++	&mov	(@T[2],@T[0]);		# SwapHalf
++	&mov	(@T[3],@T[1]);
++	&mov	(@T[0],$__s2);
++	&mov	(@T[1],$__s3);
++	&xor	(@T[2],$idx);		# $idx is preloaded with key[2]
++	&xor	(@T[3],&DWP(12,$key));
++	&xor	(@T[0],&DWP(0,$key));
++	&xor	(@T[1],&DWP(4,$key));
++	&ret	();
++&function_end_B("_x86_Camellia_decrypt");
++
++# shld is very slow on Intel P4 family. Even on AMD it limits
++# instruction decode rate [because it's VectorPath] and consequently
++# performance. PIII, PM and Core[2] seem to be the only ones which
++# execute this code ~7% faster...
++sub __rotl128 {
++  my ($i0,$i1,$i2,$i3,$rot,$rnd,@T)=@_;
++
++    $rnd *= 2;
++    if ($rot) {
++	&mov	($idx,$i0);
++	&shld	($i0,$i1,$rot);
++	&shld	($i1,$i2,$rot);
++	&shld	($i2,$i3,$rot);
++	&shld	($i3,$idx,$rot);
++    }
++    &mov	(&DWP(-128+4*$rnd++,$key),shift(@T))	if ($i0 eq @T[0]);
++    &mov	(&DWP(-128+4*$rnd++,$key),shift(@T))	if ($i1 eq @T[0]);
++    &mov	(&DWP(-128+4*$rnd++,$key),shift(@T))	if ($i2 eq @T[0]);
++    &mov	(&DWP(-128+4*$rnd++,$key),shift(@T))	if ($i3 eq @T[0]);
++}
++
++# ... Implementing 128-bit rotate without shld gives >3x performance
++# improvement on P4, only ~7% degradation on other Intel CPUs and
++# not worse performance on AMD. This is therefore preferred.
++sub _rotl128 {
++  my ($i0,$i1,$i2,$i3,$rot,$rnd,@T)=@_;
++
++    $rnd *= 2;
++    if ($rot) {
++	&mov	($Tbl,$i0);
++	&shl	($i0,$rot);
++	&mov	($idx,$i1);
++	&shr	($idx,32-$rot);
++	&shl	($i1,$rot);
++	&or	($i0,$idx);
++	&mov	($idx,$i2);
++	&shl	($i2,$rot);
++	&mov	(&DWP(-128+4*$rnd++,$key),shift(@T))	if ($i0 eq @T[0]);
++	&shr	($idx,32-$rot);
++	&or	($i1,$idx);
++	&shr	($Tbl,32-$rot);
++	&mov	($idx,$i3);
++	&shr	($idx,32-$rot);
++	&mov	(&DWP(-128+4*$rnd++,$key),shift(@T))	if ($i1 eq @T[0]);
++	&shl	($i3,$rot);
++	&or	($i2,$idx);
++	&or	($i3,$Tbl);
++	&mov	(&DWP(-128+4*$rnd++,$key),shift(@T))	if ($i2 eq @T[0]);
++	&mov	(&DWP(-128+4*$rnd++,$key),shift(@T))	if ($i3 eq @T[0]);
++    } else {
++	&mov	(&DWP(-128+4*$rnd++,$key),shift(@T))	if ($i0 eq @T[0]);
++	&mov	(&DWP(-128+4*$rnd++,$key),shift(@T))	if ($i1 eq @T[0]);
++	&mov	(&DWP(-128+4*$rnd++,$key),shift(@T))	if ($i2 eq @T[0]);
++	&mov	(&DWP(-128+4*$rnd++,$key),shift(@T))	if ($i3 eq @T[0]);
++    }
++}
++
++sub _saveround {
++my ($rnd,$key,@T)=@_;
++my $bias=int(@T[0])?shift(@T):0;
++
++	&mov	(&DWP($bias+$rnd*8+0,$key),@T[0]);
++	&mov	(&DWP($bias+$rnd*8+4,$key),@T[1])	if ($#T>=1);
++	&mov	(&DWP($bias+$rnd*8+8,$key),@T[2])	if ($#T>=2);
++	&mov	(&DWP($bias+$rnd*8+12,$key),@T[3])	if ($#T>=3);
++}
++
++sub _loadround {
++my ($rnd,$key,@T)=@_;
++my $bias=int(@T[0])?shift(@T):0;
++
++	&mov	(@T[0],&DWP($bias+$rnd*8+0,$key));
++	&mov	(@T[1],&DWP($bias+$rnd*8+4,$key))	if ($#T>=1);
++	&mov	(@T[2],&DWP($bias+$rnd*8+8,$key))	if ($#T>=2);
++	&mov	(@T[3],&DWP($bias+$rnd*8+12,$key))	if ($#T>=3);
++}
++
++# void Camellia_Ekeygen(
++#		const int keyBitLength,
++#		const Byte *rawKey,
++#		KEY_TABLE_TYPE keyTable)
++&function_begin("Camellia_Ekeygen");
++{ my $step=0;
++
++	&stack_push(4);				# place for s[0-3]
++
++	&mov	($Tbl,&wparam(0));		# load arguments
++	&mov	($idx,&wparam(1));
++	&mov	($key,&wparam(2));
++
++	&mov	(@T[0],&DWP(0,$idx));		# load 0-127 bits
++	&mov	(@T[1],&DWP(4,$idx));
++	&mov	(@T[2],&DWP(8,$idx));
++	&mov	(@T[3],&DWP(12,$idx));
++
++	&bswap	(@T[0]);
++	&bswap	(@T[1]);
++	&bswap	(@T[2]);
++	&bswap	(@T[3]);
++
++	&_saveround	(0,$key,@T);		# KL<<<0
++
++	&cmp	($Tbl,128);
++	&je	(&label("1st128"));
++
++	&mov	(@T[0],&DWP(16,$idx));		# load 128-191 bits
++	&mov	(@T[1],&DWP(20,$idx));
++	&cmp	($Tbl,192);
++	&je	(&label("1st192"));
++	&mov	(@T[2],&DWP(24,$idx));		# load 192-255 bits
++	&mov	(@T[3],&DWP(28,$idx));
++	&jmp	(&label("1st256"));
++&set_label("1st192",4);
++	&mov	(@T[2],@T[0]);
++	&mov	(@T[3],@T[1]);
++	¬	(@T[2]);
++	¬	(@T[3]);
++&set_label("1st256",4);
++	&bswap	(@T[0]);
++	&bswap	(@T[1]);
++	&bswap	(@T[2]);
++	&bswap	(@T[3]);
++
++	&_saveround	(4,$key,@T);		# temporary storage for KR!
++
++	&xor	(@T[0],&DWP(0*8+0,$key));	# KR^KL
++	&xor	(@T[1],&DWP(0*8+4,$key));
++	&xor	(@T[2],&DWP(1*8+0,$key));
++	&xor	(@T[3],&DWP(1*8+4,$key));
++
++&set_label("1st128",4);
++	&call	(&label("pic_point"));
++	&set_label("pic_point");
++	&blindpop($Tbl);
++	&lea	($Tbl,&DWP(&label("Camellia_SBOX")."-".&label("pic_point"),$Tbl));
++	&lea	($key,&DWP(&label("Camellia_SIGMA")."-".&label("Camellia_SBOX"),$Tbl));
++
++	&mov	($idx,&DWP($step*8,$key));	# prefetch SIGMA[0]
++	&mov	(&swtmp(0),@T[0]);		# save s[0-3]
++	&mov	(&swtmp(1),@T[1]);
++	&mov	(&swtmp(2),@T[2]);
++	&mov	(&swtmp(3),@T[3]);
++	&Camellia_Feistel($step++);
++	&Camellia_Feistel($step++);
++	&mov	(@T[2],&swtmp(2));
++	&mov	(@T[3],&swtmp(3));
++
++	&mov	($idx,&wparam(2));
++	&xor	(@T[0],&DWP(0*8+0,$idx));	# ^KL
++	&xor	(@T[1],&DWP(0*8+4,$idx));
++	&xor	(@T[2],&DWP(1*8+0,$idx));
++	&xor	(@T[3],&DWP(1*8+4,$idx));
++
++	&mov	($idx,&DWP($step*8,$key));	# prefetch SIGMA[4]
++	&mov	(&swtmp(0),@T[0]);		# save s[0-3]
++	&mov	(&swtmp(1),@T[1]);
++	&mov	(&swtmp(2),@T[2]);
++	&mov	(&swtmp(3),@T[3]);
++	&Camellia_Feistel($step++);
++	&Camellia_Feistel($step++);
++	&mov	(@T[2],&swtmp(2));
++	&mov	(@T[3],&swtmp(3));
++
++	&mov	($idx,&wparam(0));
++	&cmp	($idx,128);
++	&jne	(&label("2nd256"));
++
++	&mov	($key,&wparam(2));
++	&lea	($key,&DWP(128,$key));		# size optimization
++
++	####### process KA
++	&_saveround	(2,$key,-128,@T);	# KA<<<0
++	&_rotl128	(@T,15,6,@T);		# KA<<<15
++	&_rotl128	(@T,15,8,@T);		# KA<<<(15+15=30)
++	&_rotl128	(@T,15,12,@T[0],@T[1]);	# KA<<<(30+15=45)
++	&_rotl128	(@T,15,14,@T);		# KA<<<(45+15=60)
++	push		(@T,shift(@T));		# rotl128(@T,32);
++	&_rotl128	(@T,2,20,@T);		# KA<<<(60+32+2=94)
++	&_rotl128	(@T,17,24,@T);		# KA<<<(94+17=111)
++
++	####### process KL
++	&_loadround	(0,$key,-128,@T);	# load KL
++	&_rotl128	(@T,15,4,@T);		# KL<<<15
++	&_rotl128	(@T,30,10,@T);		# KL<<<(15+30=45)
++	&_rotl128	(@T,15,13,@T[2],@T[3]);	# KL<<<(45+15=60)
++	&_rotl128	(@T,17,16,@T);		# KL<<<(60+17=77)
++	&_rotl128	(@T,17,18,@T);		# KL<<<(77+17=94)
++	&_rotl128	(@T,17,22,@T);		# KL<<<(94+17=111)
++
++	while (@T[0] ne "eax")			# restore order
++	{   unshift	(@T,pop(@T));   }
++
++	&mov	("eax",3);			# 3 grandRounds
++	&jmp	(&label("done"));
++
++&set_label("2nd256",16);
++	&mov	($idx,&wparam(2));
++	&_saveround	(6,$idx,@T);		# temporary storage for KA!
++
++	&xor	(@T[0],&DWP(4*8+0,$idx));	# KA^KR
++	&xor	(@T[1],&DWP(4*8+4,$idx));
++	&xor	(@T[2],&DWP(5*8+0,$idx));
++	&xor	(@T[3],&DWP(5*8+4,$idx));
++
++	&mov	($idx,&DWP($step*8,$key));	# prefetch SIGMA[8]
++	&mov	(&swtmp(0),@T[0]);		# save s[0-3]
++	&mov	(&swtmp(1),@T[1]);
++	&mov	(&swtmp(2),@T[2]);
++	&mov	(&swtmp(3),@T[3]);
++	&Camellia_Feistel($step++);
++	&Camellia_Feistel($step++);
++	&mov	(@T[2],&swtmp(2));
++	&mov	(@T[3],&swtmp(3));
++
++	&mov	($key,&wparam(2));
++	&lea	($key,&DWP(128,$key));		# size optimization
++
++	####### process KB
++	&_saveround	(2,$key,-128,@T);	# KB<<<0
++	&_rotl128	(@T,30,10,@T);		# KB<<<30
++	&_rotl128	(@T,30,20,@T);		# KB<<<(30+30=60)
++	push		(@T,shift(@T));		# rotl128(@T,32);
++	&_rotl128	(@T,19,32,@T);		# KB<<<(60+32+19=111)
++
++	####### process KR
++	&_loadround	(4,$key,-128,@T);	# load KR
++	&_rotl128	(@T,15,4,@T);		# KR<<<15
++	&_rotl128	(@T,15,8,@T);		# KR<<<(15+15=30)
++	&_rotl128	(@T,30,18,@T);		# KR<<<(30+30=60)
++	push		(@T,shift(@T));		# rotl128(@T,32);
++	&_rotl128	(@T,2,26,@T);		# KR<<<(60+32+2=94)
++
++	####### process KA
++	&_loadround	(6,$key,-128,@T);	# load KA
++	&_rotl128	(@T,15,6,@T);		# KA<<<15
++	&_rotl128	(@T,30,14,@T);		# KA<<<(15+30=45)
++	push		(@T,shift(@T));		# rotl128(@T,32);
++	&_rotl128	(@T,0,24,@T);		# KA<<<(45+32+0=77)
++	&_rotl128	(@T,17,28,@T);		# KA<<<(77+17=94)
++
++	####### process KL
++	&_loadround	(0,$key,-128,@T);	# load KL
++	push		(@T,shift(@T));		# rotl128(@T,32);
++	&_rotl128	(@T,13,12,@T);		# KL<<<(32+13=45)
++	&_rotl128	(@T,15,16,@T);		# KL<<<(45+15=60)
++	&_rotl128	(@T,17,22,@T);		# KL<<<(60+17=77)
++	push		(@T,shift(@T));		# rotl128(@T,32);
++	&_rotl128	(@T,2,30,@T);		# KL<<<(77+32+2=111)
++
++	while (@T[0] ne "eax")			# restore order
++	{   unshift	(@T,pop(@T));   }
++
++	&mov	("eax",4);			# 4 grandRounds
++&set_label("done");
++	&lea	("edx",&DWP(272-128,$key));	# end of key schedule
++	&stack_pop(4);
++}
++&function_end("Camellia_Ekeygen");
++
++if ($OPENSSL) {
++# int Camellia_set_key (
++#		const unsigned char *userKey,
++#		int bits,
++#		CAMELLIA_KEY *key)
++&function_begin_B("Camellia_set_key");
++	&push	("ebx");
++	&mov	("ecx",&wparam(0));	# pull arguments
++	&mov	("ebx",&wparam(1));
++	&mov	("edx",&wparam(2));
++
++	&mov	("eax",-1);
++	&test	("ecx","ecx");
++	&jz	(&label("done"));	# userKey==NULL?
++	&test	("edx","edx");
++	&jz	(&label("done"));	# key==NULL?
++
++	&mov	("eax",-2);
++	&cmp	("ebx",256);
++	&je	(&label("arg_ok"));	# bits==256?
++	&cmp	("ebx",192);
++	&je	(&label("arg_ok"));	# bits==192?
++	&cmp	("ebx",128);
++	&jne	(&label("done"));	# bits!=128?
++&set_label("arg_ok",4);
++
++	&push	("edx");		# push arguments
++	&push	("ecx");
++	&push	("ebx");
++	&call	("Camellia_Ekeygen");
++	&stack_pop(3);
++
++	# eax holds grandRounds and edx points at where to put it
++	&mov	(&DWP(0,"edx"),"eax");
++	&xor	("eax","eax");
++&set_label("done",4);
++	&pop	("ebx");
++	&ret	();
++&function_end_B("Camellia_set_key");
++}
++
++@SBOX=(
++112,130, 44,236,179, 39,192,229,228,133, 87, 53,234, 12,174, 65,
++ 35,239,107,147, 69, 25,165, 33,237, 14, 79, 78, 29,101,146,189,
++134,184,175,143,124,235, 31,206, 62, 48,220, 95, 94,197, 11, 26,
++166,225, 57,202,213, 71, 93, 61,217,  1, 90,214, 81, 86,108, 77,
++139, 13,154,102,251,204,176, 45,116, 18, 43, 32,240,177,132,153,
++223, 76,203,194, 52,126,118,  5,109,183,169, 49,209, 23,  4,215,
++ 20, 88, 58, 97,222, 27, 17, 28, 50, 15,156, 22, 83, 24,242, 34,
++254, 68,207,178,195,181,122,145, 36,  8,232,168, 96,252,105, 80,
++170,208,160,125,161,137, 98,151, 84, 91, 30,149,224,255,100,210,
++ 16,196,  0, 72,163,247,117,219,138,  3,230,218,  9, 63,221,148,
++135, 92,131,  2,205, 74,144, 51,115,103,246,243,157,127,191,226,
++ 82,155,216, 38,200, 55,198, 59,129,150,111, 75, 19,190, 99, 46,
++233,121,167,140,159,110,188,142, 41,245,249,182, 47,253,180, 89,
++120,152,  6,106,231, 70,113,186,212, 37,171, 66,136,162,141,250,
++114,  7,185, 85,248,238,172, 10, 54, 73, 42,104, 60, 56,241,164,
++ 64, 40,211,123,187,201, 67,193, 21,227,173,244,119,199,128,158);
++
++sub S1110 { my $i=shift; $i=@SBOX[$i]; return $i<<24|$i<<16|$i<<8; }
++sub S4404 { my $i=shift; $i=($i<<1|$i>>7)&0xff; $i=@SBOX[$i]; return $i<<24|$i<<16|$i; }	
++sub S0222 { my $i=shift; $i=@SBOX[$i]; $i=($i<<1|$i>>7)&0xff; return $i<<16|$i<<8|$i; }	
++sub S3033 { my $i=shift; $i=@SBOX[$i]; $i=($i>>1|$i<<7)&0xff; return $i<<24|$i<<8|$i; }	
++
++&set_label("Camellia_SIGMA",64);
++&data_word(
++    0xa09e667f, 0x3bcc908b, 0xb67ae858, 0x4caa73b2,
++    0xc6ef372f, 0xe94f82be, 0x54ff53a5, 0xf1d36f1c,
++    0x10e527fa, 0xde682d1d, 0xb05688c2, 0xb3e6c1fd,
++    0,          0,          0,          0);
++&set_label("Camellia_SBOX",64);
++# tables are interleaved, remember?
++for ($i=0;$i<256;$i++) { &data_word(&S1110($i),&S4404($i)); }
++for ($i=0;$i<256;$i++) { &data_word(&S0222($i),&S3033($i)); }
++
++# void Camellia_cbc_encrypt (const void char *inp, unsigned char *out,
++#			size_t length, const CAMELLIA_KEY *key,
++#			unsigned char *ivp,const int enc);
++{
++# stack frame layout
++#             -4(%esp)		# return address	 0(%esp)
++#              0(%esp)		# s0			 4(%esp)
++#              4(%esp)		# s1			 8(%esp)
++#              8(%esp)		# s2			12(%esp)
++#             12(%esp)		# s3			16(%esp)
++#             16(%esp)		# end of key schedule	20(%esp)
++#             20(%esp)		# %esp backup
++my $_inp=&DWP(24,"esp");	#copy of wparam(0)
++my $_out=&DWP(28,"esp");	#copy of wparam(1)
++my $_len=&DWP(32,"esp");	#copy of wparam(2)
++my $_key=&DWP(36,"esp");	#copy of wparam(3)
++my $_ivp=&DWP(40,"esp");	#copy of wparam(4)
++my $ivec=&DWP(44,"esp");	#ivec[16]
++my $_tmp=&DWP(44,"esp");	#volatile variable [yes, aliases with ivec]
++my ($s0,$s1,$s2,$s3) = @T;
++
++&function_begin("Camellia_cbc_encrypt");
++	&mov	($s2 eq "ecx"? $s2 : "",&wparam(2));	# load len
++	&cmp	($s2,0);
++	&je	(&label("enc_out"));
++
++	&pushf	();
++	&cld	();
++
++	&mov	($s0,&wparam(0));	# load inp
++	&mov	($s1,&wparam(1));	# load out
++	#&mov	($s2,&wparam(2));	# load len
++	&mov	($s3,&wparam(3));	# load key
++	&mov	($Tbl,&wparam(4));	# load ivp
++
++	# allocate aligned stack frame...
++	&lea	($idx,&DWP(-64,"esp"));
++	&and	($idx,-64);
++
++	# place stack frame just "above mod 1024" the key schedule
++	# this ensures that cache associativity of 2 suffices
++	&lea	($key,&DWP(-64-63,$s3));
++	&sub	($key,$idx);
++	&neg	($key);
++	&and	($key,0x3C0);	# modulo 1024, but aligned to cache-line
++	&sub	($idx,$key);
++
++	&mov	($key,&wparam(5));	# load enc
++
++	&exch	("esp",$idx);
++	&add	("esp",4);		# reserve for return address!
++	&mov	($_esp,$idx);		# save %esp
++
++	&mov	($_inp,$s0);		# save copy of inp
++	&mov	($_out,$s1);		# save copy of out
++	&mov	($_len,$s2);		# save copy of len
++	&mov	($_key,$s3);		# save copy of key
++	&mov	($_ivp,$Tbl);		# save copy of ivp
++
++	&call   (&label("pic_point"));	# make it PIC!
++	&set_label("pic_point");
++	&blindpop($Tbl);
++	&lea    ($Tbl,&DWP(&label("Camellia_SBOX")."-".&label("pic_point"),$Tbl));
++
++	&mov	($idx,32);
++	&set_label("prefetch_sbox",4);
++		&mov	($s0,&DWP(0,$Tbl));
++		&mov	($s1,&DWP(32,$Tbl));
++		&mov	($s2,&DWP(64,$Tbl));
++		&mov	($s3,&DWP(96,$Tbl));
++		&lea	($Tbl,&DWP(128,$Tbl));
++		&dec	($idx);
++	&jnz	(&label("prefetch_sbox"));
++	&mov	($s0,$_key);
++	&sub	($Tbl,4096);
++	&mov	($idx,$_inp);
++	&mov	($s3,&DWP(272,$s0));		# load grandRounds
++
++	&cmp	($key,0);
++	&je	(&label("DECRYPT"));
++
++	&mov	($s2,$_len);
++	&mov	($key,$_ivp);
++	&shl	($s3,6);
++	&lea	($s3,&DWP(0,$s0,$s3));
++	&mov	($_end,$s3);
++
++	&test	($s2,0xFFFFFFF0);
++	&jz	(&label("enc_tail"));		# short input...
++
++	&mov	($s0,&DWP(0,$key));		# load iv
++	&mov	($s1,&DWP(4,$key));
++
++	&set_label("enc_loop",4);
++		&mov	($s2,&DWP(8,$key));
++		&mov	($s3,&DWP(12,$key));
++
++		&xor	($s0,&DWP(0,$idx));	# xor input data
++		&xor	($s1,&DWP(4,$idx));
++		&xor	($s2,&DWP(8,$idx));
++		&bswap	($s0);
++		&xor	($s3,&DWP(12,$idx));
++		&bswap	($s1);
++		&mov	($key,$_key);		# load key
++		&bswap	($s2);
++		&bswap	($s3);
++
++		&call	("_x86_Camellia_encrypt");
++
++		&mov	($idx,$_inp);		# load inp
++		&mov	($key,$_out);		# load out
++
++		&bswap	($s0);
++		&bswap	($s1);
++		&bswap	($s2);
++		&mov	(&DWP(0,$key),$s0);	# save output data
++		&bswap	($s3);
++		&mov	(&DWP(4,$key),$s1);
++		&mov	(&DWP(8,$key),$s2);
++		&mov	(&DWP(12,$key),$s3);
++
++		&mov	($s2,$_len);		# load len
++
++		&lea	($idx,&DWP(16,$idx));
++		&mov	($_inp,$idx);		# save inp
++
++		&lea	($s3,&DWP(16,$key));
++		&mov	($_out,$s3);		# save out
++
++		&sub	($s2,16);
++		&test	($s2,0xFFFFFFF0);
++		&mov	($_len,$s2);		# save len
++	&jnz	(&label("enc_loop"));
++	&test	($s2,15);
++	&jnz	(&label("enc_tail"));
++	&mov	($idx,$_ivp);		# load ivp
++	&mov	($s2,&DWP(8,$key));	# restore last dwords
++	&mov	($s3,&DWP(12,$key));
++	&mov	(&DWP(0,$idx),$s0);	# save ivec
++	&mov	(&DWP(4,$idx),$s1);
++	&mov	(&DWP(8,$idx),$s2);
++	&mov	(&DWP(12,$idx),$s3);
++
++	&mov	("esp",$_esp);
++	&popf	();
++    &set_label("enc_out");
++	&function_end_A();
++	&pushf	();			# kludge, never executed
++
++    &set_label("enc_tail",4);
++	&mov	($s0,$key eq "edi" ? $key : "");
++	&mov	($key,$_out);			# load out
++	&push	($s0);				# push ivp
++	&mov	($s1,16);
++	&sub	($s1,$s2);
++	&cmp	($key,$idx);			# compare with inp
++	&je	(&label("enc_in_place"));
++	&align	(4);
++	&data_word(0xA4F3F689);	# rep movsb	# copy input
++	&jmp	(&label("enc_skip_in_place"));
++    &set_label("enc_in_place");
++	&lea	($key,&DWP(0,$key,$s2));
++    &set_label("enc_skip_in_place");
++	&mov	($s2,$s1);
++	&xor	($s0,$s0);
++	&align	(4);
++	&data_word(0xAAF3F689);	# rep stosb	# zero tail
++	&pop	($key);				# pop ivp
++
++	&mov	($idx,$_out);			# output as input
++	&mov	($s0,&DWP(0,$key));
++	&mov	($s1,&DWP(4,$key));
++	&mov	($_len,16);			# len=16
++	&jmp	(&label("enc_loop"));		# one more spin...
++
++#----------------------------- DECRYPT -----------------------------#
++&set_label("DECRYPT",16);
++	&shl	($s3,6);
++	&lea	($s3,&DWP(0,$s0,$s3));
++	&mov	($_end,$s0);
++	&mov	($_key,$s3);
++
++	&cmp	($idx,$_out);
++	&je	(&label("dec_in_place"));	# in-place processing...
++
++	&mov	($key,$_ivp);			# load ivp
++	&mov	($_tmp,$key);
++
++	&set_label("dec_loop",4);
++		&mov	($s0,&DWP(0,$idx));	# read input
++		&mov	($s1,&DWP(4,$idx));
++		&mov	($s2,&DWP(8,$idx));
++		&bswap	($s0);
++		&mov	($s3,&DWP(12,$idx));
++		&bswap	($s1);
++		&mov	($key,$_key);		# load key
++		&bswap	($s2);
++		&bswap	($s3);
++
++		&call	("_x86_Camellia_decrypt");
++
++		&mov	($key,$_tmp);		# load ivp
++		&mov	($idx,$_len);		# load len
++
++		&bswap	($s0);
++		&bswap	($s1);
++		&bswap	($s2);
++		&xor	($s0,&DWP(0,$key));	# xor iv
++		&bswap	($s3);
++		&xor	($s1,&DWP(4,$key));
++		&xor	($s2,&DWP(8,$key));
++		&xor	($s3,&DWP(12,$key));
++
++		&sub	($idx,16);
++		&jc	(&label("dec_partial"));
++		&mov	($_len,$idx);		# save len
++		&mov	($idx,$_inp);		# load inp
++		&mov	($key,$_out);		# load out
++
++		&mov	(&DWP(0,$key),$s0);	# write output
++		&mov	(&DWP(4,$key),$s1);
++		&mov	(&DWP(8,$key),$s2);
++		&mov	(&DWP(12,$key),$s3);
++
++		&mov	($_tmp,$idx);		# save ivp
++		&lea	($idx,&DWP(16,$idx));
++		&mov	($_inp,$idx);		# save inp
++
++		&lea	($key,&DWP(16,$key));
++		&mov	($_out,$key);		# save out
++
++	&jnz	(&label("dec_loop"));
++	&mov	($key,$_tmp);		# load temp ivp
++    &set_label("dec_end");
++	&mov	($idx,$_ivp);		# load user ivp
++	&mov	($s0,&DWP(0,$key));	# load iv
++	&mov	($s1,&DWP(4,$key));
++	&mov	($s2,&DWP(8,$key));
++	&mov	($s3,&DWP(12,$key));
++	&mov	(&DWP(0,$idx),$s0);	# copy back to user
++	&mov	(&DWP(4,$idx),$s1);
++	&mov	(&DWP(8,$idx),$s2);
++	&mov	(&DWP(12,$idx),$s3);
++	&jmp	(&label("dec_out"));
++
++    &set_label("dec_partial",4);
++	&lea	($key,$ivec);
++	&mov	(&DWP(0,$key),$s0);	# dump output to stack
++	&mov	(&DWP(4,$key),$s1);
++	&mov	(&DWP(8,$key),$s2);
++	&mov	(&DWP(12,$key),$s3);
++	&lea	($s2 eq "ecx" ? $s2 : "",&DWP(16,$idx));
++	&mov	($idx eq "esi" ? $idx : "",$key);
++	&mov	($key eq "edi" ? $key : "",$_out);	# load out
++	&data_word(0xA4F3F689);	# rep movsb		# copy output
++	&mov	($key,$_inp);				# use inp as temp ivp
++	&jmp	(&label("dec_end"));
++
++    &set_label("dec_in_place",4);
++	&set_label("dec_in_place_loop");
++		&lea	($key,$ivec);
++		&mov	($s0,&DWP(0,$idx));	# read input
++		&mov	($s1,&DWP(4,$idx));
++		&mov	($s2,&DWP(8,$idx));
++		&mov	($s3,&DWP(12,$idx));
++
++		&mov	(&DWP(0,$key),$s0);	# copy to temp
++		&mov	(&DWP(4,$key),$s1);
++		&mov	(&DWP(8,$key),$s2);
++		&bswap	($s0);
++		&mov	(&DWP(12,$key),$s3);
++		&bswap	($s1);
++		&mov	($key,$_key);		# load key
++		&bswap	($s2);
++		&bswap	($s3);
++
++		&call	("_x86_Camellia_decrypt");
++
++		&mov	($key,$_ivp);		# load ivp
++		&mov	($idx,$_out);		# load out
++
++		&bswap	($s0);
++		&bswap	($s1);
++		&bswap	($s2);
++		&xor	($s0,&DWP(0,$key));	# xor iv
++		&bswap	($s3);
++		&xor	($s1,&DWP(4,$key));
++		&xor	($s2,&DWP(8,$key));
++		&xor	($s3,&DWP(12,$key));
++
++		&mov	(&DWP(0,$idx),$s0);	# write output
++		&mov	(&DWP(4,$idx),$s1);
++		&mov	(&DWP(8,$idx),$s2);
++		&mov	(&DWP(12,$idx),$s3);
++
++		&lea	($idx,&DWP(16,$idx));
++		&mov	($_out,$idx);		# save out
++
++		&lea	($idx,$ivec);
++		&mov	($s0,&DWP(0,$idx));	# read temp
++		&mov	($s1,&DWP(4,$idx));
++		&mov	($s2,&DWP(8,$idx));
++		&mov	($s3,&DWP(12,$idx));
++
++		&mov	(&DWP(0,$key),$s0);	# copy iv
++		&mov	(&DWP(4,$key),$s1);
++		&mov	(&DWP(8,$key),$s2);
++		&mov	(&DWP(12,$key),$s3);
++
++		&mov	($idx,$_inp);		# load inp
++
++		&lea	($idx,&DWP(16,$idx));
++		&mov	($_inp,$idx);		# save inp
++
++		&mov	($s2,$_len);		# load len
++		&sub	($s2,16);
++		&jc	(&label("dec_in_place_partial"));
++		&mov	($_len,$s2);		# save len
++	&jnz	(&label("dec_in_place_loop"));
++	&jmp	(&label("dec_out"));
++
++    &set_label("dec_in_place_partial",4);
++	# one can argue if this is actually required...
++	&mov	($key eq "edi" ? $key : "",$_out);
++	&lea	($idx eq "esi" ? $idx : "",$ivec);
++	&lea	($key,&DWP(0,$key,$s2));
++	&lea	($idx,&DWP(16,$idx,$s2));
++	&neg	($s2 eq "ecx" ? $s2 : "");
++	&data_word(0xA4F3F689);	# rep movsb	# restore tail
++
++    &set_label("dec_out",4);
++    &mov	("esp",$_esp);
++    &popf	();
++&function_end("Camellia_cbc_encrypt");
++}
++
++&asciz("Camellia for x86 by ");
++
++&asm_finish();
++
++close STDOUT;
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/camellia/asm/cmll-x86_64.pl b/CryptoPkg/Library/OpensslLib/openssl/crypto/camellia/asm/cmll-x86_64.pl
+new file mode 100644
+index 0000000..da5ad7b
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/camellia/asm/cmll-x86_64.pl
+@@ -0,0 +1,1088 @@
++#! /usr/bin/env perl
++# Copyright 2008-2016 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
++# in the file LICENSE in the source distribution or at
++# https://www.openssl.org/source/license.html
++
++
++# ====================================================================
++# Copyright (c) 2008 Andy Polyakov 
++#
++# This module may be used under the terms of either the GNU General
++# Public License version 2 or later, the GNU Lesser General Public
++# License version 2.1 or later, the Mozilla Public License version
++# 1.1 or the BSD License. The exact terms of either license are
++# distributed along with this module. For further details see
++# http://www.openssl.org/~appro/camellia/.
++# ====================================================================
++
++# Performance in cycles per processed byte (less is better) in
++# 'openssl speed ...' benchmark:
++#
++#			AMD64	Core2	EM64T
++# -evp camellia-128-ecb	16.7	21.0	22.7
++# + over gcc 3.4.6	+25%	+5%	0%
++#
++# camellia-128-cbc	15.7	20.4	21.1
++#
++# 128-bit key setup	128	216	205	cycles/key
++# + over gcc 3.4.6	+54%	+39%	+15%
++#
++# Numbers in "+" rows represent performance improvement over compiler
++# generated code. Key setup timings are impressive on AMD and Core2
++# thanks to 64-bit operations being covertly deployed. Improvement on
++# EM64T, pre-Core2 Intel x86_64 CPU, is not as impressive, because it
++# apparently emulates some of 64-bit operations in [32-bit] microcode.
++
++$flavour = shift;
++$output  = shift;
++if ($flavour =~ /\./) { $output = $flavour; undef $flavour; }
++
++$win64=0; $win64=1 if ($flavour =~ /[nm]asm|mingw64/ || $output =~ /\.asm$/);
++
++$0 =~ m/(.*[\/\\])[^\/\\]+$/; $dir=$1;
++( $xlate="${dir}x86_64-xlate.pl" and -f $xlate ) or
++( $xlate="${dir}../../perlasm/x86_64-xlate.pl" and -f $xlate) or
++die "can't locate x86_64-xlate.pl";
++
++open OUT,"| \"$^X\" \"$xlate\" $flavour \"$output\"";
++*STDOUT=*OUT;
++
++sub hi() { my $r=shift; $r =~ s/%[er]([a-d])x/%\1h/;    $r; }
++sub lo() { my $r=shift; $r =~ s/%[er]([a-d])x/%\1l/;
++                        $r =~ s/%[er]([sd]i)/%\1l/;
++                        $r =~ s/%(r[0-9]+)[d]?/%\1b/;   $r; }
++
++$t0="%eax";$t1="%ebx";$t2="%ecx";$t3="%edx";
++@S=("%r8d","%r9d","%r10d","%r11d");
++$i0="%esi";
++$i1="%edi";
++$Tbl="%rbp";	# size optimization
++$inp="%r12";
++$out="%r13";
++$key="%r14";
++$keyend="%r15";
++$arg0d=$win64?"%ecx":"%edi";
++
++# const unsigned int Camellia_SBOX[4][256];
++# Well, sort of... Camellia_SBOX[0][] is interleaved with [1][],
++# and [2][] - with [3][]. This is done to minimize code size.
++$SBOX1_1110=0;		# Camellia_SBOX[0]
++$SBOX4_4404=4;		# Camellia_SBOX[1]
++$SBOX2_0222=2048;	# Camellia_SBOX[2]
++$SBOX3_3033=2052;	# Camellia_SBOX[3]
++
++sub Camellia_Feistel {
++my $i=@_[0];
++my $seed=defined(@_[1])?@_[1]:0;
++my $scale=$seed<0?-8:8;
++my $j=($i&1)*2;
++my ($s0,$s1,$s2,$s3)=(@S[($j)%4],@S[($j+1)%4],@S[($j+2)%4],@S[($j+3)%4]);
++
++$code.=<<___;
++	xor	$s0,$t0				# t0^=key[0]
++	xor	$s1,$t1				# t1^=key[1]
++	movz	`&hi("$t0")`,$i0		# (t0>>8)&0xff
++	movz	`&lo("$t1")`,$i1		# (t1>>0)&0xff
++	mov	$SBOX3_3033($Tbl,$i0,8),$t3	# t3=SBOX3_3033[0]
++	mov	$SBOX1_1110($Tbl,$i1,8),$t2	# t2=SBOX1_1110[1]
++	movz	`&lo("$t0")`,$i0		# (t0>>0)&0xff
++	shr	\$16,$t0
++	movz	`&hi("$t1")`,$i1		# (t1>>8)&0xff
++	xor	$SBOX4_4404($Tbl,$i0,8),$t3	# t3^=SBOX4_4404[0]
++	shr	\$16,$t1
++	xor	$SBOX4_4404($Tbl,$i1,8),$t2	# t2^=SBOX4_4404[1]
++	movz	`&hi("$t0")`,$i0		# (t0>>24)&0xff
++	movz	`&lo("$t1")`,$i1		# (t1>>16)&0xff
++	xor	$SBOX1_1110($Tbl,$i0,8),$t3	# t3^=SBOX1_1110[0]
++	xor	$SBOX3_3033($Tbl,$i1,8),$t2	# t2^=SBOX3_3033[1]
++	movz	`&lo("$t0")`,$i0		# (t0>>16)&0xff
++	movz	`&hi("$t1")`,$i1		# (t1>>24)&0xff
++	xor	$SBOX2_0222($Tbl,$i0,8),$t3	# t3^=SBOX2_0222[0]
++	xor	$SBOX2_0222($Tbl,$i1,8),$t2	# t2^=SBOX2_0222[1]
++	mov	`$seed+($i+1)*$scale`($key),$t1	# prefetch key[i+1]
++	mov	`$seed+($i+1)*$scale+4`($key),$t0
++	xor	$t3,$t2				# t2^=t3
++	ror	\$8,$t3				# t3=RightRotate(t3,8)
++	xor	$t2,$s2
++	xor	$t2,$s3
++	xor	$t3,$s3
++___
++}
++
++# void Camellia_EncryptBlock_Rounds(
++#		int grandRounds,
++#		const Byte plaintext[],
++#		const KEY_TABLE_TYPE keyTable,
++#		Byte ciphertext[])
++$code=<<___;
++.text
++
++# V1.x API
++.globl	Camellia_EncryptBlock
++.type	Camellia_EncryptBlock,\@abi-omnipotent
++.align	16
++Camellia_EncryptBlock:
++	movl	\$128,%eax
++	subl	$arg0d,%eax
++	movl	\$3,$arg0d
++	adcl	\$0,$arg0d	# keyBitLength==128?3:4
++	jmp	.Lenc_rounds
++.size	Camellia_EncryptBlock,.-Camellia_EncryptBlock
++# V2
++.globl	Camellia_EncryptBlock_Rounds
++.type	Camellia_EncryptBlock_Rounds,\@function,4
++.align	16
++.Lenc_rounds:
++Camellia_EncryptBlock_Rounds:
++	push	%rbx
++	push	%rbp
++	push	%r13
++	push	%r14
++	push	%r15
++.Lenc_prologue:
++
++	#mov	%rsi,$inp		# put away arguments
++	mov	%rcx,$out
++	mov	%rdx,$key
++
++	shl	\$6,%edi		# process grandRounds
++	lea	.LCamellia_SBOX(%rip),$Tbl
++	lea	($key,%rdi),$keyend
++
++	mov	0(%rsi),@S[0]		# load plaintext
++	mov	4(%rsi),@S[1]
++	mov	8(%rsi),@S[2]
++	bswap	@S[0]
++	mov	12(%rsi),@S[3]
++	bswap	@S[1]
++	bswap	@S[2]
++	bswap	@S[3]
++
++	call	_x86_64_Camellia_encrypt
++
++	bswap	@S[0]
++	bswap	@S[1]
++	bswap	@S[2]
++	mov	@S[0],0($out)
++	bswap	@S[3]
++	mov	@S[1],4($out)
++	mov	@S[2],8($out)
++	mov	@S[3],12($out)
++
++	mov	0(%rsp),%r15
++	mov	8(%rsp),%r14
++	mov	16(%rsp),%r13
++	mov	24(%rsp),%rbp
++	mov	32(%rsp),%rbx
++	lea	40(%rsp),%rsp
++.Lenc_epilogue:
++	ret
++.size	Camellia_EncryptBlock_Rounds,.-Camellia_EncryptBlock_Rounds
++
++.type	_x86_64_Camellia_encrypt,\@abi-omnipotent
++.align	16
++_x86_64_Camellia_encrypt:
++	xor	0($key),@S[1]
++	xor	4($key),@S[0]		# ^=key[0-3]
++	xor	8($key),@S[3]
++	xor	12($key),@S[2]
++.align	16
++.Leloop:
++	mov	16($key),$t1		# prefetch key[4-5]
++	mov	20($key),$t0
++
++___
++	for ($i=0;$i<6;$i++) { Camellia_Feistel($i,16); }
++$code.=<<___;
++	lea	16*4($key),$key
++	cmp	$keyend,$key
++	mov	8($key),$t3		# prefetch key[2-3]
++	mov	12($key),$t2
++	je	.Ledone
++
++	and	@S[0],$t0
++	or	@S[3],$t3
++	rol	\$1,$t0
++	xor	$t3,@S[2]		# s2^=s3|key[3];
++	xor	$t0,@S[1]		# s1^=LeftRotate(s0&key[0],1);
++	and	@S[2],$t2
++	or	@S[1],$t1
++	rol	\$1,$t2
++	xor	$t1,@S[0]		# s0^=s1|key[1];
++	xor	$t2,@S[3]		# s3^=LeftRotate(s2&key[2],1);
++	jmp	.Leloop
++
++.align	16
++.Ledone:
++	xor	@S[2],$t0		# SwapHalf
++	xor	@S[3],$t1
++	xor	@S[0],$t2
++	xor	@S[1],$t3
++
++	mov	$t0,@S[0]
++	mov	$t1,@S[1]
++	mov	$t2,@S[2]
++	mov	$t3,@S[3]
++
++	.byte	0xf3,0xc3		# rep ret
++.size	_x86_64_Camellia_encrypt,.-_x86_64_Camellia_encrypt
++
++# V1.x API
++.globl	Camellia_DecryptBlock
++.type	Camellia_DecryptBlock,\@abi-omnipotent
++.align	16
++Camellia_DecryptBlock:
++	movl	\$128,%eax
++	subl	$arg0d,%eax
++	movl	\$3,$arg0d
++	adcl	\$0,$arg0d	# keyBitLength==128?3:4
++	jmp	.Ldec_rounds
++.size	Camellia_DecryptBlock,.-Camellia_DecryptBlock
++# V2
++.globl	Camellia_DecryptBlock_Rounds
++.type	Camellia_DecryptBlock_Rounds,\@function,4
++.align	16
++.Ldec_rounds:
++Camellia_DecryptBlock_Rounds:
++	push	%rbx
++	push	%rbp
++	push	%r13
++	push	%r14
++	push	%r15
++.Ldec_prologue:
++
++	#mov	%rsi,$inp		# put away arguments
++	mov	%rcx,$out
++	mov	%rdx,$keyend
++
++	shl	\$6,%edi		# process grandRounds
++	lea	.LCamellia_SBOX(%rip),$Tbl
++	lea	($keyend,%rdi),$key
++
++	mov	0(%rsi),@S[0]		# load plaintext
++	mov	4(%rsi),@S[1]
++	mov	8(%rsi),@S[2]
++	bswap	@S[0]
++	mov	12(%rsi),@S[3]
++	bswap	@S[1]
++	bswap	@S[2]
++	bswap	@S[3]
++
++	call	_x86_64_Camellia_decrypt
++
++	bswap	@S[0]
++	bswap	@S[1]
++	bswap	@S[2]
++	mov	@S[0],0($out)
++	bswap	@S[3]
++	mov	@S[1],4($out)
++	mov	@S[2],8($out)
++	mov	@S[3],12($out)
++
++	mov	0(%rsp),%r15
++	mov	8(%rsp),%r14
++	mov	16(%rsp),%r13
++	mov	24(%rsp),%rbp
++	mov	32(%rsp),%rbx
++	lea	40(%rsp),%rsp
++.Ldec_epilogue:
++	ret
++.size	Camellia_DecryptBlock_Rounds,.-Camellia_DecryptBlock_Rounds
++
++.type	_x86_64_Camellia_decrypt,\@abi-omnipotent
++.align	16
++_x86_64_Camellia_decrypt:
++	xor	0($key),@S[1]
++	xor	4($key),@S[0]		# ^=key[0-3]
++	xor	8($key),@S[3]
++	xor	12($key),@S[2]
++.align	16
++.Ldloop:
++	mov	-8($key),$t1		# prefetch key[4-5]
++	mov	-4($key),$t0
++
++___
++	for ($i=0;$i<6;$i++) { Camellia_Feistel($i,-8); }
++$code.=<<___;
++	lea	-16*4($key),$key
++	cmp	$keyend,$key
++	mov	0($key),$t3		# prefetch key[2-3]
++	mov	4($key),$t2
++	je	.Lddone
++
++	and	@S[0],$t0
++	or	@S[3],$t3
++	rol	\$1,$t0
++	xor	$t3,@S[2]		# s2^=s3|key[3];
++	xor	$t0,@S[1]		# s1^=LeftRotate(s0&key[0],1);
++	and	@S[2],$t2
++	or	@S[1],$t1
++	rol	\$1,$t2
++	xor	$t1,@S[0]		# s0^=s1|key[1];
++	xor	$t2,@S[3]		# s3^=LeftRotate(s2&key[2],1);
++
++	jmp	.Ldloop
++
++.align	16
++.Lddone:
++	xor	@S[2],$t2
++	xor	@S[3],$t3
++	xor	@S[0],$t0
++	xor	@S[1],$t1
++
++	mov	$t2,@S[0]		# SwapHalf
++	mov	$t3,@S[1]
++	mov	$t0,@S[2]
++	mov	$t1,@S[3]
++
++	.byte	0xf3,0xc3		# rep ret
++.size	_x86_64_Camellia_decrypt,.-_x86_64_Camellia_decrypt
++___
++
++sub _saveround {
++my ($rnd,$key,@T)=@_;
++my $bias=int(@T[0])?shift(@T):0;
++
++    if ($#T==3) {
++	$code.=<<___;
++	mov	@T[1],`$bias+$rnd*8+0`($key)
++	mov	@T[0],`$bias+$rnd*8+4`($key)
++	mov	@T[3],`$bias+$rnd*8+8`($key)
++	mov	@T[2],`$bias+$rnd*8+12`($key)
++___
++    } else {
++	$code.="	mov	@T[0],`$bias+$rnd*8+0`($key)\n";
++	$code.="	mov	@T[1],`$bias+$rnd*8+8`($key)\n"	if ($#T>=1);
++    }
++}
++
++sub _loadround {
++my ($rnd,$key,@T)=@_;
++my $bias=int(@T[0])?shift(@T):0;
++
++$code.="	mov	`$bias+$rnd*8+0`($key),@T[0]\n";
++$code.="	mov	`$bias+$rnd*8+8`($key),@T[1]\n"	if ($#T>=1);
++}
++
++# shld is very slow on Intel EM64T family. Even on AMD it limits
++# instruction decode rate [because it's VectorPath] and consequently
++# performance...
++sub __rotl128 {
++my ($i0,$i1,$rot)=@_;
++
++    if ($rot) {
++	$code.=<<___;
++	mov	$i0,%r11
++	shld	\$$rot,$i1,$i0
++	shld	\$$rot,%r11,$i1
++___
++    }
++}
++
++# ... Implementing 128-bit rotate without shld gives 80% better
++# performance EM64T, +15% on AMD64 and only ~7% degradation on
++# Core2. This is therefore preferred.
++sub _rotl128 {
++my ($i0,$i1,$rot)=@_;
++
++    if ($rot) {
++	$code.=<<___;
++	mov	$i0,%r11
++	shl	\$$rot,$i0
++	mov	$i1,%r9
++	shr	\$`64-$rot`,%r9
++	shr	\$`64-$rot`,%r11
++	or	%r9,$i0
++	shl	\$$rot,$i1
++	or	%r11,$i1
++___
++    }
++}
++
++{ my $step=0;
++
++$code.=<<___;
++.globl	Camellia_Ekeygen
++.type	Camellia_Ekeygen,\@function,3
++.align	16
++Camellia_Ekeygen:
++	push	%rbx
++	push	%rbp
++	push	%r13
++	push	%r14
++	push	%r15
++.Lkey_prologue:
++
++	mov	%edi,${keyend}d		# put away arguments, keyBitLength
++	mov	%rdx,$out		# keyTable
++
++	mov	0(%rsi),@S[0]		# load 0-127 bits
++	mov	4(%rsi),@S[1]
++	mov	8(%rsi),@S[2]
++	mov	12(%rsi),@S[3]
++
++	bswap	@S[0]
++	bswap	@S[1]
++	bswap	@S[2]
++	bswap	@S[3]
++___
++	&_saveround	(0,$out,@S);	# KL<<<0
++$code.=<<___;
++	cmp	\$128,$keyend		# check keyBitLength
++	je	.L1st128
++
++	mov	16(%rsi),@S[0]		# load 128-191 bits
++	mov	20(%rsi),@S[1]
++	cmp	\$192,$keyend
++	je	.L1st192
++	mov	24(%rsi),@S[2]		# load 192-255 bits
++	mov	28(%rsi),@S[3]
++	jmp	.L1st256
++.L1st192:
++	mov	@S[0],@S[2]
++	mov	@S[1],@S[3]
++	not	@S[2]
++	not	@S[3]
++.L1st256:
++	bswap	@S[0]
++	bswap	@S[1]
++	bswap	@S[2]
++	bswap	@S[3]
++___
++	&_saveround	(4,$out,@S);	# temp storage for KR!
++$code.=<<___;
++	xor	0($out),@S[1]		# KR^KL
++	xor	4($out),@S[0]
++	xor	8($out),@S[3]
++	xor	12($out),@S[2]
++
++.L1st128:
++	lea	.LCamellia_SIGMA(%rip),$key
++	lea	.LCamellia_SBOX(%rip),$Tbl
++
++	mov	0($key),$t1
++	mov	4($key),$t0
++___
++	&Camellia_Feistel($step++);
++	&Camellia_Feistel($step++);
++$code.=<<___;
++	xor	0($out),@S[1]		# ^KL
++	xor	4($out),@S[0]
++	xor	8($out),@S[3]
++	xor	12($out),@S[2]
++___
++	&Camellia_Feistel($step++);
++	&Camellia_Feistel($step++);
++$code.=<<___;
++	cmp	\$128,$keyend
++	jne	.L2nd256
++
++	lea	128($out),$out		# size optimization
++	shl	\$32,%r8		# @S[0]||
++	shl	\$32,%r10		# @S[2]||
++	or	%r9,%r8			# ||@S[1]
++	or	%r11,%r10		# ||@S[3]
++___
++	&_loadround	(0,$out,-128,"%rax","%rbx");	# KL
++	&_saveround	(2,$out,-128,"%r8","%r10");	# KA<<<0
++	&_rotl128	("%rax","%rbx",15);
++	&_saveround	(4,$out,-128,"%rax","%rbx");	# KL<<<15
++	&_rotl128	("%r8","%r10",15);
++	&_saveround	(6,$out,-128,"%r8","%r10");	# KA<<<15
++	&_rotl128	("%r8","%r10",15);		# 15+15=30
++	&_saveround	(8,$out,-128,"%r8","%r10");	# KA<<<30
++	&_rotl128	("%rax","%rbx",30);		# 15+30=45
++	&_saveround	(10,$out,-128,"%rax","%rbx");	# KL<<<45
++	&_rotl128	("%r8","%r10",15);		# 30+15=45
++	&_saveround	(12,$out,-128,"%r8");		# KA<<<45
++	&_rotl128	("%rax","%rbx",15);		# 45+15=60
++	&_saveround	(13,$out,-128,"%rbx");		# KL<<<60
++	&_rotl128	("%r8","%r10",15);		# 45+15=60
++	&_saveround	(14,$out,-128,"%r8","%r10");	# KA<<<60
++	&_rotl128	("%rax","%rbx",17);		# 60+17=77
++	&_saveround	(16,$out,-128,"%rax","%rbx");	# KL<<<77
++	&_rotl128	("%rax","%rbx",17);		# 77+17=94
++	&_saveround	(18,$out,-128,"%rax","%rbx");	# KL<<<94
++	&_rotl128	("%r8","%r10",34);		# 60+34=94
++	&_saveround	(20,$out,-128,"%r8","%r10");	# KA<<<94
++	&_rotl128	("%rax","%rbx",17);		# 94+17=111
++	&_saveround	(22,$out,-128,"%rax","%rbx");	# KL<<<111
++	&_rotl128	("%r8","%r10",17);		# 94+17=111
++	&_saveround	(24,$out,-128,"%r8","%r10");	# KA<<<111
++$code.=<<___;
++	mov	\$3,%eax
++	jmp	.Ldone
++.align	16
++.L2nd256:
++___
++	&_saveround	(6,$out,@S);	# temp storage for KA!
++$code.=<<___;
++	xor	`4*8+0`($out),@S[1]	# KA^KR
++	xor	`4*8+4`($out),@S[0]
++	xor	`5*8+0`($out),@S[3]
++	xor	`5*8+4`($out),@S[2]
++___
++	&Camellia_Feistel($step++);
++	&Camellia_Feistel($step++);
++
++	&_loadround	(0,$out,"%rax","%rbx");	# KL
++	&_loadround	(4,$out,"%rcx","%rdx");	# KR
++	&_loadround	(6,$out,"%r14","%r15");	# KA
++$code.=<<___;
++	lea	128($out),$out		# size optimization
++	shl	\$32,%r8		# @S[0]||
++	shl	\$32,%r10		# @S[2]||
++	or	%r9,%r8			# ||@S[1]
++	or	%r11,%r10		# ||@S[3]
++___
++	&_saveround	(2,$out,-128,"%r8","%r10");	# KB<<<0
++	&_rotl128	("%rcx","%rdx",15);
++	&_saveround	(4,$out,-128,"%rcx","%rdx");	# KR<<<15
++	&_rotl128	("%r14","%r15",15);
++	&_saveround	(6,$out,-128,"%r14","%r15");	# KA<<<15
++	&_rotl128	("%rcx","%rdx",15);		# 15+15=30
++	&_saveround	(8,$out,-128,"%rcx","%rdx");	# KR<<<30
++	&_rotl128	("%r8","%r10",30);
++	&_saveround	(10,$out,-128,"%r8","%r10");	# KB<<<30
++	&_rotl128	("%rax","%rbx",45);
++	&_saveround	(12,$out,-128,"%rax","%rbx");	# KL<<<45
++	&_rotl128	("%r14","%r15",30);		# 15+30=45
++	&_saveround	(14,$out,-128,"%r14","%r15");	# KA<<<45
++	&_rotl128	("%rax","%rbx",15);		# 45+15=60
++	&_saveround	(16,$out,-128,"%rax","%rbx");	# KL<<<60
++	&_rotl128	("%rcx","%rdx",30);		# 30+30=60
++	&_saveround	(18,$out,-128,"%rcx","%rdx");	# KR<<<60
++	&_rotl128	("%r8","%r10",30);		# 30+30=60
++	&_saveround	(20,$out,-128,"%r8","%r10");	# KB<<<60
++	&_rotl128	("%rax","%rbx",17);		# 60+17=77
++	&_saveround	(22,$out,-128,"%rax","%rbx");	# KL<<<77
++	&_rotl128	("%r14","%r15",32);		# 45+32=77
++	&_saveround	(24,$out,-128,"%r14","%r15");	# KA<<<77
++	&_rotl128	("%rcx","%rdx",34);		# 60+34=94
++	&_saveround	(26,$out,-128,"%rcx","%rdx");	# KR<<<94
++	&_rotl128	("%r14","%r15",17);		# 77+17=94
++	&_saveround	(28,$out,-128,"%r14","%r15");	# KA<<<77
++	&_rotl128	("%rax","%rbx",34);		# 77+34=111
++	&_saveround	(30,$out,-128,"%rax","%rbx");	# KL<<<111
++	&_rotl128	("%r8","%r10",51);		# 60+51=111
++	&_saveround	(32,$out,-128,"%r8","%r10");	# KB<<<111
++$code.=<<___;
++	mov	\$4,%eax
++.Ldone:
++	mov	0(%rsp),%r15
++	mov	8(%rsp),%r14
++	mov	16(%rsp),%r13
++	mov	24(%rsp),%rbp
++	mov	32(%rsp),%rbx
++	lea	40(%rsp),%rsp
++.Lkey_epilogue:
++	ret
++.size	Camellia_Ekeygen,.-Camellia_Ekeygen
++___
++}
++
++@SBOX=(
++112,130, 44,236,179, 39,192,229,228,133, 87, 53,234, 12,174, 65,
++ 35,239,107,147, 69, 25,165, 33,237, 14, 79, 78, 29,101,146,189,
++134,184,175,143,124,235, 31,206, 62, 48,220, 95, 94,197, 11, 26,
++166,225, 57,202,213, 71, 93, 61,217,  1, 90,214, 81, 86,108, 77,
++139, 13,154,102,251,204,176, 45,116, 18, 43, 32,240,177,132,153,
++223, 76,203,194, 52,126,118,  5,109,183,169, 49,209, 23,  4,215,
++ 20, 88, 58, 97,222, 27, 17, 28, 50, 15,156, 22, 83, 24,242, 34,
++254, 68,207,178,195,181,122,145, 36,  8,232,168, 96,252,105, 80,
++170,208,160,125,161,137, 98,151, 84, 91, 30,149,224,255,100,210,
++ 16,196,  0, 72,163,247,117,219,138,  3,230,218,  9, 63,221,148,
++135, 92,131,  2,205, 74,144, 51,115,103,246,243,157,127,191,226,
++ 82,155,216, 38,200, 55,198, 59,129,150,111, 75, 19,190, 99, 46,
++233,121,167,140,159,110,188,142, 41,245,249,182, 47,253,180, 89,
++120,152,  6,106,231, 70,113,186,212, 37,171, 66,136,162,141,250,
++114,  7,185, 85,248,238,172, 10, 54, 73, 42,104, 60, 56,241,164,
++ 64, 40,211,123,187,201, 67,193, 21,227,173,244,119,199,128,158);
++
++sub S1110 { my $i=shift; $i=@SBOX[$i]; $i=$i<<24|$i<<16|$i<<8; sprintf("0x%08x",$i); }
++sub S4404 { my $i=shift; $i=($i<<1|$i>>7)&0xff; $i=@SBOX[$i]; $i=$i<<24|$i<<16|$i; sprintf("0x%08x",$i); }
++sub S0222 { my $i=shift; $i=@SBOX[$i]; $i=($i<<1|$i>>7)&0xff; $i=$i<<16|$i<<8|$i; sprintf("0x%08x",$i); }
++sub S3033 { my $i=shift; $i=@SBOX[$i]; $i=($i>>1|$i<<7)&0xff; $i=$i<<24|$i<<8|$i; sprintf("0x%08x",$i); }
++
++$code.=<<___;
++.align	64
++.LCamellia_SIGMA:
++.long	0x3bcc908b, 0xa09e667f, 0x4caa73b2, 0xb67ae858
++.long	0xe94f82be, 0xc6ef372f, 0xf1d36f1c, 0x54ff53a5
++.long	0xde682d1d, 0x10e527fa, 0xb3e6c1fd, 0xb05688c2
++.long	0,          0,          0,          0
++.LCamellia_SBOX:
++___
++# tables are interleaved, remember?
++sub data_word { $code.=".long\t".join(',',@_)."\n"; }
++for ($i=0;$i<256;$i++) { &data_word(&S1110($i),&S4404($i)); }
++for ($i=0;$i<256;$i++) { &data_word(&S0222($i),&S3033($i)); }
++
++# void Camellia_cbc_encrypt (const void char *inp, unsigned char *out,
++#			size_t length, const CAMELLIA_KEY *key,
++#			unsigned char *ivp,const int enc);
++{
++$_key="0(%rsp)";
++$_end="8(%rsp)";	# inp+len&~15
++$_res="16(%rsp)";	# len&15
++$ivec="24(%rsp)";
++$_ivp="40(%rsp)";
++$_rsp="48(%rsp)";
++
++$code.=<<___;
++.globl	Camellia_cbc_encrypt
++.type	Camellia_cbc_encrypt,\@function,6
++.align	16
++Camellia_cbc_encrypt:
++	cmp	\$0,%rdx
++	je	.Lcbc_abort
++	push	%rbx
++	push	%rbp
++	push	%r12
++	push	%r13
++	push	%r14
++	push	%r15
++.Lcbc_prologue:
++
++	mov	%rsp,%rbp
++	sub	\$64,%rsp
++	and	\$-64,%rsp
++
++	# place stack frame just "above mod 1024" the key schedule,
++	# this ensures that cache associativity suffices
++	lea	-64-63(%rcx),%r10
++	sub	%rsp,%r10
++	neg	%r10
++	and	\$0x3C0,%r10
++	sub	%r10,%rsp
++	#add	\$8,%rsp		# 8 is reserved for callee's ra
++
++	mov	%rdi,$inp		# inp argument
++	mov	%rsi,$out		# out argument
++	mov	%r8,%rbx		# ivp argument
++	mov	%rcx,$key		# key argument
++	mov	272(%rcx),${keyend}d	# grandRounds
++
++	mov	%r8,$_ivp
++	mov	%rbp,$_rsp
++
++.Lcbc_body:
++	lea	.LCamellia_SBOX(%rip),$Tbl
++
++	mov	\$32,%ecx
++.align	4
++.Lcbc_prefetch_sbox:
++	mov	0($Tbl),%rax
++	mov	32($Tbl),%rsi
++	mov	64($Tbl),%rdi
++	mov	96($Tbl),%r11
++	lea	128($Tbl),$Tbl
++	loop	.Lcbc_prefetch_sbox
++	sub	\$4096,$Tbl
++	shl	\$6,$keyend
++	mov	%rdx,%rcx		# len argument
++	lea	($key,$keyend),$keyend
++
++	cmp	\$0,%r9d		# enc argument
++	je	.LCBC_DECRYPT
++
++	and	\$-16,%rdx
++	and	\$15,%rcx		# length residue
++	lea	($inp,%rdx),%rdx
++	mov	$key,$_key
++	mov	%rdx,$_end
++	mov	%rcx,$_res
++
++	cmp	$inp,%rdx
++	mov	0(%rbx),@S[0]		# load IV
++	mov	4(%rbx),@S[1]
++	mov	8(%rbx),@S[2]
++	mov	12(%rbx),@S[3]
++	je	.Lcbc_enc_tail
++	jmp	.Lcbc_eloop
++
++.align	16
++.Lcbc_eloop:
++	xor	0($inp),@S[0]
++	xor	4($inp),@S[1]
++	xor	8($inp),@S[2]
++	bswap	@S[0]
++	xor	12($inp),@S[3]
++	bswap	@S[1]
++	bswap	@S[2]
++	bswap	@S[3]
++
++	call	_x86_64_Camellia_encrypt
++
++	mov	$_key,$key		# "rewind" the key
++	bswap	@S[0]
++	mov	$_end,%rdx
++	bswap	@S[1]
++	mov	$_res,%rcx
++	bswap	@S[2]
++	mov	@S[0],0($out)
++	bswap	@S[3]
++	mov	@S[1],4($out)
++	mov	@S[2],8($out)
++	lea	16($inp),$inp
++	mov	@S[3],12($out)
++	cmp	%rdx,$inp
++	lea	16($out),$out
++	jne	.Lcbc_eloop
++
++	cmp	\$0,%rcx
++	jne	.Lcbc_enc_tail
++
++	mov	$_ivp,$out
++	mov	@S[0],0($out)		# write out IV residue
++	mov	@S[1],4($out)
++	mov	@S[2],8($out)
++	mov	@S[3],12($out)
++	jmp	.Lcbc_done
++
++.align	16
++.Lcbc_enc_tail:
++	xor	%rax,%rax
++	mov	%rax,0+$ivec
++	mov	%rax,8+$ivec
++	mov	%rax,$_res
++
++.Lcbc_enc_pushf:
++	pushfq
++	cld
++	mov	$inp,%rsi
++	lea	8+$ivec,%rdi
++	.long	0x9066A4F3		# rep movsb
++	popfq
++.Lcbc_enc_popf:
++
++	lea	$ivec,$inp
++	lea	16+$ivec,%rax
++	mov	%rax,$_end
++	jmp	.Lcbc_eloop		# one more time
++
++.align	16
++.LCBC_DECRYPT:
++	xchg	$key,$keyend
++	add	\$15,%rdx
++	and	\$15,%rcx		# length residue
++	and	\$-16,%rdx
++	mov	$key,$_key
++	lea	($inp,%rdx),%rdx
++	mov	%rdx,$_end
++	mov	%rcx,$_res
++
++	mov	(%rbx),%rax		# load IV
++	mov	8(%rbx),%rbx
++	jmp	.Lcbc_dloop
++.align	16
++.Lcbc_dloop:
++	mov	0($inp),@S[0]
++	mov	4($inp),@S[1]
++	mov	8($inp),@S[2]
++	bswap	@S[0]
++	mov	12($inp),@S[3]
++	bswap	@S[1]
++	mov	%rax,0+$ivec		# save IV to temporary storage
++	bswap	@S[2]
++	mov	%rbx,8+$ivec
++	bswap	@S[3]
++
++	call	_x86_64_Camellia_decrypt
++
++	mov	$_key,$key		# "rewind" the key
++	mov	$_end,%rdx
++	mov	$_res,%rcx
++
++	bswap	@S[0]
++	mov	($inp),%rax		# load IV for next iteration
++	bswap	@S[1]
++	mov	8($inp),%rbx
++	bswap	@S[2]
++	xor	0+$ivec,@S[0]
++	bswap	@S[3]
++	xor	4+$ivec,@S[1]
++	xor	8+$ivec,@S[2]
++	lea	16($inp),$inp
++	xor	12+$ivec,@S[3]
++	cmp	%rdx,$inp
++	je	.Lcbc_ddone
++
++	mov	@S[0],0($out)
++	mov	@S[1],4($out)
++	mov	@S[2],8($out)
++	mov	@S[3],12($out)
++
++	lea	16($out),$out
++	jmp	.Lcbc_dloop
++
++.align	16
++.Lcbc_ddone:
++	mov	$_ivp,%rdx
++	cmp	\$0,%rcx
++	jne	.Lcbc_dec_tail
++
++	mov	@S[0],0($out)
++	mov	@S[1],4($out)
++	mov	@S[2],8($out)
++	mov	@S[3],12($out)
++
++	mov	%rax,(%rdx)		# write out IV residue
++	mov	%rbx,8(%rdx)
++	jmp	.Lcbc_done
++.align	16
++.Lcbc_dec_tail:
++	mov	@S[0],0+$ivec
++	mov	@S[1],4+$ivec
++	mov	@S[2],8+$ivec
++	mov	@S[3],12+$ivec
++
++.Lcbc_dec_pushf:
++	pushfq
++	cld
++	lea	8+$ivec,%rsi
++	lea	($out),%rdi
++	.long	0x9066A4F3		# rep movsb
++	popfq
++.Lcbc_dec_popf:
++
++	mov	%rax,(%rdx)		# write out IV residue
++	mov	%rbx,8(%rdx)
++	jmp	.Lcbc_done
++
++.align	16
++.Lcbc_done:
++	mov	$_rsp,%rcx
++	mov	0(%rcx),%r15
++	mov	8(%rcx),%r14
++	mov	16(%rcx),%r13
++	mov	24(%rcx),%r12
++	mov	32(%rcx),%rbp
++	mov	40(%rcx),%rbx
++	lea	48(%rcx),%rsp
++.Lcbc_abort:
++	ret
++.size	Camellia_cbc_encrypt,.-Camellia_cbc_encrypt
++
++.asciz	"Camellia for x86_64 by "
++___
++}
++
++# EXCEPTION_DISPOSITION handler (EXCEPTION_RECORD *rec,ULONG64 frame,
++#		CONTEXT *context,DISPATCHER_CONTEXT *disp)
++if ($win64) {
++$rec="%rcx";
++$frame="%rdx";
++$context="%r8";
++$disp="%r9";
++
++$code.=<<___;
++.extern	__imp_RtlVirtualUnwind
++.type	common_se_handler,\@abi-omnipotent
++.align	16
++common_se_handler:
++	push	%rsi
++	push	%rdi
++	push	%rbx
++	push	%rbp
++	push	%r12
++	push	%r13
++	push	%r14
++	push	%r15
++	pushfq
++	lea	-64(%rsp),%rsp
++
++	mov	120($context),%rax	# pull context->Rax
++	mov	248($context),%rbx	# pull context->Rip
++
++	mov	8($disp),%rsi		# disp->ImageBase
++	mov	56($disp),%r11		# disp->HandlerData
++
++	mov	0(%r11),%r10d		# HandlerData[0]
++	lea	(%rsi,%r10),%r10	# prologue label
++	cmp	%r10,%rbx		# context->RipRsp
++
++	mov	4(%r11),%r10d		# HandlerData[1]
++	lea	(%rsi,%r10),%r10	# epilogue label
++	cmp	%r10,%rbx		# context->Rip>=epilogue label
++	jae	.Lin_prologue
++
++	lea	40(%rax),%rax
++	mov	-8(%rax),%rbx
++	mov	-16(%rax),%rbp
++	mov	-24(%rax),%r13
++	mov	-32(%rax),%r14
++	mov	-40(%rax),%r15
++	mov	%rbx,144($context)	# restore context->Rbx
++	mov	%rbp,160($context)	# restore context->Rbp
++	mov	%r13,224($context)	# restore context->R13
++	mov	%r14,232($context)	# restore context->R14
++	mov	%r15,240($context)	# restore context->R15
++
++.Lin_prologue:
++	mov	8(%rax),%rdi
++	mov	16(%rax),%rsi
++	mov	%rax,152($context)	# restore context->Rsp
++	mov	%rsi,168($context)	# restore context->Rsi
++	mov	%rdi,176($context)	# restore context->Rdi
++
++	jmp	.Lcommon_seh_exit
++.size	common_se_handler,.-common_se_handler
++
++.type	cbc_se_handler,\@abi-omnipotent
++.align	16
++cbc_se_handler:
++	push	%rsi
++	push	%rdi
++	push	%rbx
++	push	%rbp
++	push	%r12
++	push	%r13
++	push	%r14
++	push	%r15
++	pushfq
++	lea	-64(%rsp),%rsp
++
++	mov	120($context),%rax	# pull context->Rax
++	mov	248($context),%rbx	# pull context->Rip
++
++	lea	.Lcbc_prologue(%rip),%r10
++	cmp	%r10,%rbx		# context->Rip<.Lcbc_prologue
++	jb	.Lin_cbc_prologue
++
++	lea	.Lcbc_body(%rip),%r10
++	cmp	%r10,%rbx		# context->Rip<.Lcbc_body
++	jb	.Lin_cbc_frame_setup
++
++	mov	152($context),%rax	# pull context->Rsp
++
++	lea	.Lcbc_abort(%rip),%r10
++	cmp	%r10,%rbx		# context->Rip>=.Lcbc_abort
++	jae	.Lin_cbc_prologue
++
++	# handle pushf/popf in Camellia_cbc_encrypt
++	lea	.Lcbc_enc_pushf(%rip),%r10
++	cmp	%r10,%rbx		# context->Rip<=.Lcbc_enc_pushf
++	jbe	.Lin_cbc_no_flag
++	lea	8(%rax),%rax
++	lea	.Lcbc_enc_popf(%rip),%r10
++	cmp	%r10,%rbx		# context->Rip<.Lcbc_enc_popf
++	jb	.Lin_cbc_no_flag
++	lea	-8(%rax),%rax
++	lea	.Lcbc_dec_pushf(%rip),%r10
++	cmp	%r10,%rbx		# context->Rip<=.Lcbc_dec_pushf
++	jbe	.Lin_cbc_no_flag
++	lea	8(%rax),%rax
++	lea	.Lcbc_dec_popf(%rip),%r10
++	cmp	%r10,%rbx		# context->Rip<.Lcbc_dec_popf
++	jb	.Lin_cbc_no_flag
++	lea	-8(%rax),%rax
++
++.Lin_cbc_no_flag:
++	mov	48(%rax),%rax		# $_rsp
++	lea	48(%rax),%rax
++
++.Lin_cbc_frame_setup:
++	mov	-8(%rax),%rbx
++	mov	-16(%rax),%rbp
++	mov	-24(%rax),%r12
++	mov	-32(%rax),%r13
++	mov	-40(%rax),%r14
++	mov	-48(%rax),%r15
++	mov	%rbx,144($context)	# restore context->Rbx
++	mov	%rbp,160($context)	# restore context->Rbp
++	mov	%r12,216($context)	# restore context->R12
++	mov	%r13,224($context)	# restore context->R13
++	mov	%r14,232($context)	# restore context->R14
++	mov	%r15,240($context)	# restore context->R15
++
++.Lin_cbc_prologue:
++	mov	8(%rax),%rdi
++	mov	16(%rax),%rsi
++	mov	%rax,152($context)	# restore context->Rsp
++	mov	%rsi,168($context)	# restore context->Rsi
++	mov	%rdi,176($context)	# restore context->Rdi
++
++.align	4
++.Lcommon_seh_exit:
++
++	mov	40($disp),%rdi		# disp->ContextRecord
++	mov	$context,%rsi		# context
++	mov	\$`1232/8`,%ecx		# sizeof(CONTEXT)
++	.long	0xa548f3fc		# cld; rep movsq
++
++	mov	$disp,%rsi
++	xor	%rcx,%rcx		# arg1, UNW_FLAG_NHANDLER
++	mov	8(%rsi),%rdx		# arg2, disp->ImageBase
++	mov	0(%rsi),%r8		# arg3, disp->ControlPc
++	mov	16(%rsi),%r9		# arg4, disp->FunctionEntry
++	mov	40(%rsi),%r10		# disp->ContextRecord
++	lea	56(%rsi),%r11		# &disp->HandlerData
++	lea	24(%rsi),%r12		# &disp->EstablisherFrame
++	mov	%r10,32(%rsp)		# arg5
++	mov	%r11,40(%rsp)		# arg6
++	mov	%r12,48(%rsp)		# arg7
++	mov	%rcx,56(%rsp)		# arg8, (NULL)
++	call	*__imp_RtlVirtualUnwind(%rip)
++
++	mov	\$1,%eax		# ExceptionContinueSearch
++	lea	64(%rsp),%rsp
++	popfq
++	pop	%r15
++	pop	%r14
++	pop	%r13
++	pop	%r12
++	pop	%rbp
++	pop	%rbx
++	pop	%rdi
++	pop	%rsi
++	ret
++.size	cbc_se_handler,.-cbc_se_handler
++
++.section	.pdata
++.align	4
++	.rva	.LSEH_begin_Camellia_EncryptBlock_Rounds
++	.rva	.LSEH_end_Camellia_EncryptBlock_Rounds
++	.rva	.LSEH_info_Camellia_EncryptBlock_Rounds
++
++	.rva	.LSEH_begin_Camellia_DecryptBlock_Rounds
++	.rva	.LSEH_end_Camellia_DecryptBlock_Rounds
++	.rva	.LSEH_info_Camellia_DecryptBlock_Rounds
++
++	.rva	.LSEH_begin_Camellia_Ekeygen
++	.rva	.LSEH_end_Camellia_Ekeygen
++	.rva	.LSEH_info_Camellia_Ekeygen
++
++	.rva	.LSEH_begin_Camellia_cbc_encrypt
++	.rva	.LSEH_end_Camellia_cbc_encrypt
++	.rva	.LSEH_info_Camellia_cbc_encrypt
++
++.section	.xdata
++.align	8
++.LSEH_info_Camellia_EncryptBlock_Rounds:
++	.byte	9,0,0,0
++	.rva	common_se_handler
++	.rva	.Lenc_prologue,.Lenc_epilogue	# HandlerData[]
++.LSEH_info_Camellia_DecryptBlock_Rounds:
++	.byte	9,0,0,0
++	.rva	common_se_handler
++	.rva	.Ldec_prologue,.Ldec_epilogue	# HandlerData[]
++.LSEH_info_Camellia_Ekeygen:
++	.byte	9,0,0,0
++	.rva	common_se_handler
++	.rva	.Lkey_prologue,.Lkey_epilogue	# HandlerData[]
++.LSEH_info_Camellia_cbc_encrypt:
++	.byte	9,0,0,0
++	.rva	cbc_se_handler
++___
++}
++
++$code =~ s/\`([^\`]*)\`/eval $1/gem;
++print $code;
++close STDOUT;
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/camellia/asm/cmllt4-sparcv9.pl b/CryptoPkg/Library/OpensslLib/openssl/crypto/camellia/asm/cmllt4-sparcv9.pl
+new file mode 100644
+index 0000000..ffe4a7d
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/camellia/asm/cmllt4-sparcv9.pl
+@@ -0,0 +1,939 @@
++#! /usr/bin/env perl
++# Copyright 2012-2016 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
++# in the file LICENSE in the source distribution or at
++# https://www.openssl.org/source/license.html
++
++
++# ====================================================================
++# Written by David S. Miller  and Andy Polyakov
++# . The module is licensed under 2-clause BSD
++# license. October 2012. All rights reserved.
++# ====================================================================
++
++######################################################################
++# Camellia for SPARC T4.
++#
++# As with AES below results [for aligned data] are virtually identical
++# to critical path lenths for 3-cycle instruction latency:
++#
++#		128-bit key	192/256-
++# CBC encrypt	4.14/4.21(*)	5.46/5.52
++#			 (*) numbers after slash are for
++#			     misaligned data.
++#
++# As with Intel AES-NI, question is if it's possible to improve
++# performance of parallelizeable modes by interleaving round
++# instructions. In Camellia every instruction is dependent on
++# previous, which means that there is place for 2 additional ones
++# in between two dependent. Can we expect 3x performance improvement?
++# At least one can argue that it should be possible to break 2x
++# barrier... For some reason not even 2x appears to be possible:
++#
++#		128-bit key	192/256-
++# CBC decrypt	2.21/2.74	2.99/3.40
++# CTR		2.15/2.68(*)	2.93/3.34
++#			 (*) numbers after slash are for
++#			     misaligned data.
++#
++# This is for 2x interleave. But compared to 1x interleave CBC decrypt
++# improved by ... 0% for 128-bit key, and 11% for 192/256-bit one.
++# So that out-of-order execution logic can take non-interleaved code
++# to 1.87x, but can't take 2x interleaved one any further. There
++# surely is some explanation... As result 3x interleave was not even
++# attempted. Instead an effort was made to share specific modes
++# implementations with AES module (therefore sparct4_modes.pl).
++#
++# To anchor to something else, software C implementation processes
++# one byte in 38 cycles with 128-bit key on same processor.
++
++$0 =~ m/(.*[\/\\])[^\/\\]+$/; $dir=$1;
++push(@INC,"${dir}","${dir}../../perlasm");
++require "sparcv9_modes.pl";
++
++$output = pop;
++open STDOUT,">$output";
++
++$::evp=1;	# if $evp is set to 0, script generates module with
++# Camellia_[en|de]crypt, Camellia_set_key and Camellia_cbc_encrypt
++# entry points. These are fully compatible with openssl/camellia.h.
++
++######################################################################
++# single-round subroutines
++#
++{
++my ($inp,$out,$key,$rounds,$tmp,$mask)=map("%o$_",(0..5));
++
++$code=<<___;
++#include "sparc_arch.h"
++
++.text
++
++.globl	cmll_t4_encrypt
++.align	32
++cmll_t4_encrypt:
++	andcc		$inp, 7, %g1		! is input aligned?
++	andn		$inp, 7, $inp
++
++	ldx		[$key + 0], %g4
++	ldx		[$key + 8], %g5
++
++	ldx		[$inp + 0], %o4
++	bz,pt		%icc, 1f
++	ldx		[$inp + 8], %o5
++	ldx		[$inp + 16], $inp
++	sll		%g1, 3, %g1
++	sub		%g0, %g1, %o3
++	sllx		%o4, %g1, %o4
++	sllx		%o5, %g1, %g1
++	srlx		%o5, %o3, %o5
++	srlx		$inp, %o3, %o3
++	or		%o5, %o4, %o4
++	or		%o3, %g1, %o5
++1:
++	ld		[$key + 272], $rounds	! grandRounds, 3 or 4
++	ldd		[$key + 16], %f12
++	ldd		[$key + 24], %f14
++	xor		%g4, %o4, %o4
++	xor		%g5, %o5, %o5
++	ldd		[$key + 32], %f16
++	ldd		[$key + 40], %f18
++	movxtod		%o4, %f0
++	movxtod		%o5, %f2
++	ldd		[$key + 48], %f20
++	ldd		[$key + 56], %f22
++	sub		$rounds, 1, $rounds
++	ldd		[$key + 64], %f24
++	ldd		[$key + 72], %f26
++	add		$key, 80, $key
++
++.Lenc:
++	camellia_f	%f12, %f2, %f0, %f2
++	ldd		[$key + 0], %f12
++	sub		$rounds,1,$rounds
++	camellia_f	%f14, %f0, %f2, %f0
++	ldd		[$key + 8], %f14
++	camellia_f	%f16, %f2, %f0, %f2
++	ldd		[$key + 16], %f16
++	camellia_f	%f18, %f0, %f2, %f0
++	ldd		[$key + 24], %f18
++	camellia_f	%f20, %f2, %f0, %f2
++	ldd		[$key + 32], %f20
++	camellia_f	%f22, %f0, %f2, %f0
++	ldd		[$key + 40], %f22
++	camellia_fl	%f24, %f0, %f0
++	ldd		[$key + 48], %f24
++	camellia_fli	%f26, %f2, %f2
++	ldd		[$key + 56], %f26
++	brnz,pt		$rounds, .Lenc
++	add		$key, 64, $key
++
++	andcc		$out, 7, $tmp		! is output aligned?
++	camellia_f	%f12, %f2, %f0, %f2
++	camellia_f	%f14, %f0, %f2, %f0
++	camellia_f	%f16, %f2, %f0, %f2
++	camellia_f	%f18, %f0, %f2, %f0
++	camellia_f	%f20, %f2, %f0, %f4
++	camellia_f	%f22, %f0, %f4, %f2
++	fxor		%f24, %f4, %f0
++	fxor		%f26, %f2, %f2
++
++	bnz,pn		%icc, 2f
++	nop
++
++	std		%f0, [$out + 0]
++	retl
++	std		%f2, [$out + 8]
++
++2:	alignaddrl	$out, %g0, $out
++	mov		0xff, $mask
++	srl		$mask, $tmp, $mask
++
++	faligndata	%f0, %f0, %f4
++	faligndata	%f0, %f2, %f6
++	faligndata	%f2, %f2, %f8
++
++	stda		%f4, [$out + $mask]0xc0	! partial store
++	std		%f6, [$out + 8]
++	add		$out, 16, $out
++	orn		%g0, $mask, $mask
++	retl
++	stda		%f8, [$out + $mask]0xc0	! partial store
++.type	cmll_t4_encrypt,#function
++.size	cmll_t4_encrypt,.-cmll_t4_encrypt
++
++.globl	cmll_t4_decrypt
++.align	32
++cmll_t4_decrypt:
++	ld		[$key + 272], $rounds	! grandRounds, 3 or 4
++	andcc		$inp, 7, %g1		! is input aligned?
++	andn		$inp, 7, $inp
++
++	sll		$rounds, 6, $rounds
++	add		$rounds, $key, $key
++
++	ldx		[$inp + 0], %o4
++	bz,pt		%icc, 1f
++	ldx		[$inp + 8], %o5
++	ldx		[$inp + 16], $inp
++	sll		%g1, 3, %g1
++	sub		%g0, %g1, %g4
++	sllx		%o4, %g1, %o4
++	sllx		%o5, %g1, %g1
++	srlx		%o5, %g4, %o5
++	srlx		$inp, %g4, %g4
++	or		%o5, %o4, %o4
++	or		%g4, %g1, %o5
++1:
++	ldx		[$key + 0], %g4
++	ldx		[$key + 8], %g5
++	ldd		[$key - 8], %f12
++	ldd		[$key - 16], %f14
++	xor		%g4, %o4, %o4
++	xor		%g5, %o5, %o5
++	ldd		[$key - 24], %f16
++	ldd		[$key - 32], %f18
++	movxtod		%o4, %f0
++	movxtod		%o5, %f2
++	ldd		[$key - 40], %f20
++	ldd		[$key - 48], %f22
++	sub		$rounds, 64, $rounds
++	ldd		[$key - 56], %f24
++	ldd		[$key - 64], %f26
++	sub		$key, 64, $key
++
++.Ldec:
++	camellia_f	%f12, %f2, %f0, %f2
++	ldd		[$key - 8], %f12
++	sub		$rounds, 64, $rounds
++	camellia_f	%f14, %f0, %f2, %f0
++	ldd		[$key - 16], %f14
++	camellia_f	%f16, %f2, %f0, %f2
++	ldd		[$key - 24], %f16
++	camellia_f	%f18, %f0, %f2, %f0
++	ldd		[$key - 32], %f18
++	camellia_f	%f20, %f2, %f0, %f2
++	ldd		[$key - 40], %f20
++	camellia_f	%f22, %f0, %f2, %f0
++	ldd		[$key - 48], %f22
++	camellia_fl	%f24, %f0, %f0
++	ldd		[$key - 56], %f24
++	camellia_fli	%f26, %f2, %f2
++	ldd		[$key - 64], %f26
++	brnz,pt		$rounds, .Ldec
++	sub		$key, 64, $key
++
++	andcc		$out, 7, $tmp		! is output aligned?
++	camellia_f	%f12, %f2, %f0, %f2
++	camellia_f	%f14, %f0, %f2, %f0
++	camellia_f	%f16, %f2, %f0, %f2
++	camellia_f	%f18, %f0, %f2, %f0
++	camellia_f	%f20, %f2, %f0, %f4
++	camellia_f	%f22, %f0, %f4, %f2
++	fxor		%f26, %f4, %f0
++	fxor		%f24, %f2, %f2
++
++	bnz,pn		%icc, 2f
++	nop
++
++	std		%f0, [$out + 0]
++	retl
++	std		%f2, [$out + 8]
++
++2:	alignaddrl	$out, %g0, $out
++	mov		0xff, $mask
++	srl		$mask, $tmp, $mask
++
++	faligndata	%f0, %f0, %f4
++	faligndata	%f0, %f2, %f6
++	faligndata	%f2, %f2, %f8
++
++	stda		%f4, [$out + $mask]0xc0	! partial store
++	std		%f6, [$out + 8]
++	add		$out, 16, $out
++	orn		%g0, $mask, $mask
++	retl
++	stda		%f8, [$out + $mask]0xc0	! partial store
++.type	cmll_t4_decrypt,#function
++.size	cmll_t4_decrypt,.-cmll_t4_decrypt
++___
++}
++
++######################################################################
++# key setup subroutines
++#
++{
++sub ROTL128 {
++  my $rot = shift;
++
++	"srlx	%o4, 64-$rot, %g4\n\t".
++	"sllx	%o4, $rot, %o4\n\t".
++	"srlx	%o5, 64-$rot, %g5\n\t".
++	"sllx	%o5, $rot, %o5\n\t".
++	"or	%o4, %g5, %o4\n\t".
++	"or	%o5, %g4, %o5";
++}
++
++my ($inp,$bits,$out,$tmp)=map("%o$_",(0..5));
++$code.=<<___;
++.globl	cmll_t4_set_key
++.align	32
++cmll_t4_set_key:
++	and		$inp, 7, $tmp
++	alignaddr	$inp, %g0, $inp
++	cmp		$bits, 192
++	ldd		[$inp + 0], %f0
++	bl,pt		%icc,.L128
++	ldd		[$inp + 8], %f2
++
++	be,pt		%icc,.L192
++	ldd		[$inp + 16], %f4
++
++	brz,pt		$tmp, .L256aligned
++	ldd		[$inp + 24], %f6
++
++	ldd		[$inp + 32], %f8
++	faligndata	%f0, %f2, %f0
++	faligndata	%f2, %f4, %f2
++	faligndata	%f4, %f6, %f4
++	b		.L256aligned
++	faligndata	%f6, %f8, %f6
++
++.align	16
++.L192:
++	brz,a,pt	$tmp, .L256aligned
++	fnot2		%f4, %f6
++
++	ldd		[$inp + 24], %f6
++	nop
++	faligndata	%f0, %f2, %f0
++	faligndata	%f2, %f4, %f2
++	faligndata	%f4, %f6, %f4
++	fnot2		%f4, %f6
++
++.L256aligned:
++	std		%f0, [$out + 0]		! k[0, 1]
++	fsrc2		%f0, %f28
++	std		%f2, [$out + 8]		! k[2, 3]
++	fsrc2		%f2, %f30
++	fxor		%f4, %f0, %f0
++	b		.L128key
++	fxor		%f6, %f2, %f2
++
++.align	16
++.L128:
++	brz,pt		$tmp, .L128aligned
++	nop
++
++	ldd		[$inp + 16], %f4
++	nop
++	faligndata	%f0, %f2, %f0
++	faligndata	%f2, %f4, %f2
++
++.L128aligned:
++	std		%f0, [$out + 0]		! k[0, 1]
++	fsrc2		%f0, %f28
++	std		%f2, [$out + 8]		! k[2, 3]
++	fsrc2		%f2, %f30
++
++.L128key:
++	mov		%o7, %o5
++1:	call		.+8
++	add		%o7, SIGMA-1b, %o4
++	mov		%o5, %o7
++
++	ldd		[%o4 + 0], %f16
++	ldd		[%o4 + 8], %f18
++	ldd		[%o4 + 16], %f20
++	ldd		[%o4 + 24], %f22
++
++	camellia_f	%f16, %f2, %f0, %f2
++	camellia_f	%f18, %f0, %f2, %f0
++	fxor		%f28, %f0, %f0
++	fxor		%f30, %f2, %f2
++	camellia_f	%f20, %f2, %f0, %f2
++	camellia_f	%f22, %f0, %f2, %f0
++
++	bge,pn		%icc, .L256key
++	nop
++	std	%f0, [$out + 0x10]	! k[ 4,  5]
++	std	%f2, [$out + 0x18]	! k[ 6,  7]
++
++	movdtox	%f0, %o4
++	movdtox	%f2, %o5
++	`&ROTL128(15)`
++	stx	%o4, [$out + 0x30]	! k[12, 13]
++	stx	%o5, [$out + 0x38]	! k[14, 15]
++	`&ROTL128(15)`
++	stx	%o4, [$out + 0x40]	! k[16, 17]
++	stx	%o5, [$out + 0x48]	! k[18, 19]
++	`&ROTL128(15)`
++	stx	%o4, [$out + 0x60]	! k[24, 25]
++	`&ROTL128(15)`
++	stx	%o4, [$out + 0x70]	! k[28, 29]
++	stx	%o5, [$out + 0x78]	! k[30, 31]
++	`&ROTL128(34)`
++	stx	%o4, [$out + 0xa0]	! k[40, 41]
++	stx	%o5, [$out + 0xa8]	! k[42, 43]
++	`&ROTL128(17)`
++	stx	%o4, [$out + 0xc0]	! k[48, 49]
++	stx	%o5, [$out + 0xc8]	! k[50, 51]
++
++	movdtox	%f28, %o4		! k[ 0,  1]
++	movdtox	%f30, %o5		! k[ 2,  3]
++	`&ROTL128(15)`
++	stx	%o4, [$out + 0x20]	! k[ 8,  9]
++	stx	%o5, [$out + 0x28]	! k[10, 11]
++	`&ROTL128(30)`
++	stx	%o4, [$out + 0x50]	! k[20, 21]
++	stx	%o5, [$out + 0x58]	! k[22, 23]
++	`&ROTL128(15)`
++	stx	%o5, [$out + 0x68]	! k[26, 27]
++	`&ROTL128(17)`
++	stx	%o4, [$out + 0x80]	! k[32, 33]
++	stx	%o5, [$out + 0x88]	! k[34, 35]
++	`&ROTL128(17)`
++	stx	%o4, [$out + 0x90]	! k[36, 37]
++	stx	%o5, [$out + 0x98]	! k[38, 39]
++	`&ROTL128(17)`
++	stx	%o4, [$out + 0xb0]	! k[44, 45]
++	stx	%o5, [$out + 0xb8]	! k[46, 47]
++
++	mov		3, $tmp
++	st		$tmp, [$out + 0x110]
++	retl
++	xor		%o0, %o0, %o0
++
++.align	16
++.L256key:
++	ldd		[%o4 + 32], %f24
++	ldd		[%o4 + 40], %f26
++
++	std		%f0, [$out + 0x30]	! k[12, 13]
++	std		%f2, [$out + 0x38]	! k[14, 15]
++
++	fxor		%f4, %f0, %f0
++	fxor		%f6, %f2, %f2
++	camellia_f	%f24, %f2, %f0, %f2
++	camellia_f	%f26, %f0, %f2, %f0
++
++	std	%f0, [$out + 0x10]	! k[ 4,  5]
++	std	%f2, [$out + 0x18]	! k[ 6,  7]
++
++	movdtox	%f0, %o4
++	movdtox	%f2, %o5
++	`&ROTL128(30)`
++	stx	%o4, [$out + 0x50]	! k[20, 21]
++	stx	%o5, [$out + 0x58]	! k[22, 23]
++	`&ROTL128(30)`
++	stx	%o4, [$out + 0xa0]	! k[40, 41]
++	stx	%o5, [$out + 0xa8]	! k[42, 43]
++	`&ROTL128(51)`
++	stx	%o4, [$out + 0x100]	! k[64, 65]
++	stx	%o5, [$out + 0x108]	! k[66, 67]
++
++	movdtox	%f4, %o4		! k[ 8,  9]
++	movdtox	%f6, %o5		! k[10, 11]
++	`&ROTL128(15)`
++	stx	%o4, [$out + 0x20]	! k[ 8,  9]
++	stx	%o5, [$out + 0x28]	! k[10, 11]
++	`&ROTL128(15)`
++	stx	%o4, [$out + 0x40]	! k[16, 17]
++	stx	%o5, [$out + 0x48]	! k[18, 19]
++	`&ROTL128(30)`
++	stx	%o4, [$out + 0x90]	! k[36, 37]
++	stx	%o5, [$out + 0x98]	! k[38, 39]
++	`&ROTL128(34)`
++	stx	%o4, [$out + 0xd0]	! k[52, 53]
++	stx	%o5, [$out + 0xd8]	! k[54, 55]
++	ldx	[$out + 0x30], %o4	! k[12, 13]
++	ldx	[$out + 0x38], %o5	! k[14, 15]
++	`&ROTL128(15)`
++	stx	%o4, [$out + 0x30]	! k[12, 13]
++	stx	%o5, [$out + 0x38]	! k[14, 15]
++	`&ROTL128(30)`
++	stx	%o4, [$out + 0x70]	! k[28, 29]
++	stx	%o5, [$out + 0x78]	! k[30, 31]
++	srlx	%o4, 32, %g4
++	srlx	%o5, 32, %g5
++	st	%o4, [$out + 0xc0]	! k[48]
++	st	%g5, [$out + 0xc4]	! k[49]
++	st	%o5, [$out + 0xc8]	! k[50]
++	st	%g4, [$out + 0xcc]	! k[51]
++	`&ROTL128(49)`
++	stx	%o4, [$out + 0xe0]	! k[56, 57]
++	stx	%o5, [$out + 0xe8]	! k[58, 59]
++
++	movdtox	%f28, %o4		! k[ 0,  1]
++	movdtox	%f30, %o5		! k[ 2,  3]
++	`&ROTL128(45)`
++	stx	%o4, [$out + 0x60]	! k[24, 25]
++	stx	%o5, [$out + 0x68]	! k[26, 27]
++	`&ROTL128(15)`
++	stx	%o4, [$out + 0x80]	! k[32, 33]
++	stx	%o5, [$out + 0x88]	! k[34, 35]
++	`&ROTL128(17)`
++	stx	%o4, [$out + 0xb0]	! k[44, 45]
++	stx	%o5, [$out + 0xb8]	! k[46, 47]
++	`&ROTL128(34)`
++	stx	%o4, [$out + 0xf0]	! k[60, 61]
++	stx	%o5, [$out + 0xf8]	! k[62, 63]
++
++	mov		4, $tmp
++	st		$tmp, [$out + 0x110]
++	retl
++	xor		%o0, %o0, %o0
++.type	cmll_t4_set_key,#function
++.size	cmll_t4_set_key,.-cmll_t4_set_key
++.align	32
++SIGMA:
++	.long	0xa09e667f, 0x3bcc908b, 0xb67ae858, 0x4caa73b2
++	.long	0xc6ef372f, 0xe94f82be, 0x54ff53a5, 0xf1d36f1c
++	.long	0x10e527fa, 0xde682d1d, 0xb05688c2, 0xb3e6c1fd
++.type	SIGMA,#object
++.size	SIGMA,.-SIGMA
++.asciz	"Camellia for SPARC T4, David S. Miller, Andy Polyakov"
++___
++}
++
++{{{
++my ($inp,$out,$len,$key,$ivec,$enc)=map("%i$_",(0..5));
++my ($ileft,$iright,$ooff,$omask,$ivoff)=map("%l$_",(1..7));
++
++$code.=<<___;
++.align	32
++_cmll128_load_enckey:
++	ldx		[$key + 0], %g4
++	ldx		[$key + 8], %g5
++___
++for ($i=2; $i<26;$i++) {			# load key schedule
++    $code.=<<___;
++	ldd		[$key + `8*$i`], %f`12+2*$i`
++___
++}
++$code.=<<___;
++	retl
++	nop
++.type	_cmll128_load_enckey,#function
++.size	_cmll128_load_enckey,.-_cmll128_load_enckey
++_cmll256_load_enckey=_cmll128_load_enckey
++
++.align	32
++_cmll256_load_deckey:
++	ldd		[$key + 64], %f62
++	ldd		[$key + 72], %f60
++	b		.Load_deckey
++	add		$key, 64, $key
++_cmll128_load_deckey:
++	ldd		[$key + 0], %f60
++	ldd		[$key + 8], %f62
++.Load_deckey:
++___
++for ($i=2; $i<24;$i++) {			# load key schedule
++    $code.=<<___;
++	ldd		[$key + `8*$i`], %f`62-2*$i`
++___
++}
++$code.=<<___;
++	ldx		[$key + 192], %g4
++	retl
++	ldx		[$key + 200], %g5
++.type	_cmll256_load_deckey,#function
++.size	_cmll256_load_deckey,.-_cmll256_load_deckey
++
++.align	32
++_cmll128_encrypt_1x:
++___
++for ($i=0; $i<3; $i++) {
++    $code.=<<___;
++	camellia_f	%f`16+16*$i+0`, %f2, %f0, %f2
++	camellia_f	%f`16+16*$i+2`, %f0, %f2, %f0
++	camellia_f	%f`16+16*$i+4`, %f2, %f0, %f2
++	camellia_f	%f`16+16*$i+6`, %f0, %f2, %f0
++___
++$code.=<<___ if ($i<2);
++	camellia_f	%f`16+16*$i+8`, %f2, %f0, %f2
++	camellia_f	%f`16+16*$i+10`, %f0, %f2, %f0
++	camellia_fl	%f`16+16*$i+12`, %f0,      %f0
++	camellia_fli	%f`16+16*$i+14`, %f2,      %f2
++___
++}
++$code.=<<___;
++	camellia_f	%f56, %f2, %f0, %f4
++	camellia_f	%f58, %f0, %f4, %f2
++	fxor		%f60, %f4, %f0
++	retl
++	fxor		%f62, %f2, %f2
++.type	_cmll128_encrypt_1x,#function
++.size	_cmll128_encrypt_1x,.-_cmll128_encrypt_1x
++_cmll128_decrypt_1x=_cmll128_encrypt_1x
++
++.align	32
++_cmll128_encrypt_2x:
++___
++for ($i=0; $i<3; $i++) {
++    $code.=<<___;
++	camellia_f	%f`16+16*$i+0`, %f2, %f0, %f2
++	camellia_f	%f`16+16*$i+0`, %f6, %f4, %f6
++	camellia_f	%f`16+16*$i+2`, %f0, %f2, %f0
++	camellia_f	%f`16+16*$i+2`, %f4, %f6, %f4
++	camellia_f	%f`16+16*$i+4`, %f2, %f0, %f2
++	camellia_f	%f`16+16*$i+4`, %f6, %f4, %f6
++	camellia_f	%f`16+16*$i+6`, %f0, %f2, %f0
++	camellia_f	%f`16+16*$i+6`, %f4, %f6, %f4
++___
++$code.=<<___ if ($i<2);
++	camellia_f	%f`16+16*$i+8`, %f2, %f0, %f2
++	camellia_f	%f`16+16*$i+8`, %f6, %f4, %f6
++	camellia_f	%f`16+16*$i+10`, %f0, %f2, %f0
++	camellia_f	%f`16+16*$i+10`, %f4, %f6, %f4
++	camellia_fl	%f`16+16*$i+12`, %f0,      %f0
++	camellia_fl	%f`16+16*$i+12`, %f4,      %f4
++	camellia_fli	%f`16+16*$i+14`, %f2,      %f2
++	camellia_fli	%f`16+16*$i+14`, %f6,      %f6
++___
++}
++$code.=<<___;
++	camellia_f	%f56, %f2, %f0, %f8
++	camellia_f	%f56, %f6, %f4, %f10
++	camellia_f	%f58, %f0, %f8, %f2
++	camellia_f	%f58, %f4, %f10, %f6
++	fxor		%f60, %f8, %f0
++	fxor		%f60, %f10, %f4
++	fxor		%f62, %f2, %f2
++	retl
++	fxor		%f62, %f6, %f6
++.type	_cmll128_encrypt_2x,#function
++.size	_cmll128_encrypt_2x,.-_cmll128_encrypt_2x
++_cmll128_decrypt_2x=_cmll128_encrypt_2x
++
++.align	32
++_cmll256_encrypt_1x:
++	camellia_f	%f16, %f2, %f0, %f2
++	camellia_f	%f18, %f0, %f2, %f0
++	ldd		[$key + 208], %f16
++	ldd		[$key + 216], %f18
++	camellia_f	%f20, %f2, %f0, %f2
++	camellia_f	%f22, %f0, %f2, %f0
++	ldd		[$key + 224], %f20
++	ldd		[$key + 232], %f22
++	camellia_f	%f24, %f2, %f0, %f2
++	camellia_f	%f26, %f0, %f2, %f0
++	ldd		[$key + 240], %f24
++	ldd		[$key + 248], %f26
++	camellia_fl	%f28, %f0, %f0
++	camellia_fli	%f30, %f2, %f2
++	ldd		[$key + 256], %f28
++	ldd		[$key + 264], %f30
++___
++for ($i=1; $i<3; $i++) {
++    $code.=<<___;
++	camellia_f	%f`16+16*$i+0`, %f2, %f0, %f2
++	camellia_f	%f`16+16*$i+2`, %f0, %f2, %f0
++	camellia_f	%f`16+16*$i+4`, %f2, %f0, %f2
++	camellia_f	%f`16+16*$i+6`, %f0, %f2, %f0
++	camellia_f	%f`16+16*$i+8`, %f2, %f0, %f2
++	camellia_f	%f`16+16*$i+10`, %f0, %f2, %f0
++	camellia_fl	%f`16+16*$i+12`, %f0,      %f0
++	camellia_fli	%f`16+16*$i+14`, %f2,      %f2
++___
++}
++$code.=<<___;
++	camellia_f	%f16, %f2, %f0, %f2
++	camellia_f	%f18, %f0, %f2, %f0
++	ldd		[$key + 16], %f16
++	ldd		[$key + 24], %f18
++	camellia_f	%f20, %f2, %f0, %f2
++	camellia_f	%f22, %f0, %f2, %f0
++	ldd		[$key + 32], %f20
++	ldd		[$key + 40], %f22
++	camellia_f	%f24, %f2, %f0, %f4
++	camellia_f	%f26, %f0, %f4, %f2
++	ldd		[$key + 48], %f24
++	ldd		[$key + 56], %f26
++	fxor		%f28, %f4, %f0
++	fxor		%f30, %f2, %f2
++	ldd		[$key + 64], %f28
++	retl
++	ldd		[$key + 72], %f30
++.type	_cmll256_encrypt_1x,#function
++.size	_cmll256_encrypt_1x,.-_cmll256_encrypt_1x
++
++.align	32
++_cmll256_encrypt_2x:
++	camellia_f	%f16, %f2, %f0, %f2
++	camellia_f	%f16, %f6, %f4, %f6
++	camellia_f	%f18, %f0, %f2, %f0
++	camellia_f	%f18, %f4, %f6, %f4
++	ldd		[$key + 208], %f16
++	ldd		[$key + 216], %f18
++	camellia_f	%f20, %f2, %f0, %f2
++	camellia_f	%f20, %f6, %f4, %f6
++	camellia_f	%f22, %f0, %f2, %f0
++	camellia_f	%f22, %f4, %f6, %f4
++	ldd		[$key + 224], %f20
++	ldd		[$key + 232], %f22
++	camellia_f	%f24, %f2, %f0, %f2
++	camellia_f	%f24, %f6, %f4, %f6
++	camellia_f	%f26, %f0, %f2, %f0
++	camellia_f	%f26, %f4, %f6, %f4
++	ldd		[$key + 240], %f24
++	ldd		[$key + 248], %f26
++	camellia_fl	%f28, %f0, %f0
++	camellia_fl	%f28, %f4, %f4
++	camellia_fli	%f30, %f2, %f2
++	camellia_fli	%f30, %f6, %f6
++	ldd		[$key + 256], %f28
++	ldd		[$key + 264], %f30
++___
++for ($i=1; $i<3; $i++) {
++    $code.=<<___;
++	camellia_f	%f`16+16*$i+0`, %f2, %f0, %f2
++	camellia_f	%f`16+16*$i+0`, %f6, %f4, %f6
++	camellia_f	%f`16+16*$i+2`, %f0, %f2, %f0
++	camellia_f	%f`16+16*$i+2`, %f4, %f6, %f4
++	camellia_f	%f`16+16*$i+4`, %f2, %f0, %f2
++	camellia_f	%f`16+16*$i+4`, %f6, %f4, %f6
++	camellia_f	%f`16+16*$i+6`, %f0, %f2, %f0
++	camellia_f	%f`16+16*$i+6`, %f4, %f6, %f4
++	camellia_f	%f`16+16*$i+8`, %f2, %f0, %f2
++	camellia_f	%f`16+16*$i+8`, %f6, %f4, %f6
++	camellia_f	%f`16+16*$i+10`, %f0, %f2, %f0
++	camellia_f	%f`16+16*$i+10`, %f4, %f6, %f4
++	camellia_fl	%f`16+16*$i+12`, %f0,      %f0
++	camellia_fl	%f`16+16*$i+12`, %f4,      %f4
++	camellia_fli	%f`16+16*$i+14`, %f2,      %f2
++	camellia_fli	%f`16+16*$i+14`, %f6,      %f6
++___
++}
++$code.=<<___;
++	camellia_f	%f16, %f2, %f0, %f2
++	camellia_f	%f16, %f6, %f4, %f6
++	camellia_f	%f18, %f0, %f2, %f0
++	camellia_f	%f18, %f4, %f6, %f4
++	ldd		[$key + 16], %f16
++	ldd		[$key + 24], %f18
++	camellia_f	%f20, %f2, %f0, %f2
++	camellia_f	%f20, %f6, %f4, %f6
++	camellia_f	%f22, %f0, %f2, %f0
++	camellia_f	%f22, %f4, %f6, %f4
++	ldd		[$key + 32], %f20
++	ldd		[$key + 40], %f22
++	camellia_f	%f24, %f2, %f0, %f8
++	camellia_f	%f24, %f6, %f4, %f10
++	camellia_f	%f26, %f0, %f8, %f2
++	camellia_f	%f26, %f4, %f10, %f6
++	ldd		[$key + 48], %f24
++	ldd		[$key + 56], %f26
++	fxor		%f28, %f8, %f0
++	fxor		%f28, %f10, %f4
++	fxor		%f30, %f2, %f2
++	fxor		%f30, %f6, %f6
++	ldd		[$key + 64], %f28
++	retl
++	ldd		[$key + 72], %f30
++.type	_cmll256_encrypt_2x,#function
++.size	_cmll256_encrypt_2x,.-_cmll256_encrypt_2x
++
++.align	32
++_cmll256_decrypt_1x:
++	camellia_f	%f16, %f2, %f0, %f2
++	camellia_f	%f18, %f0, %f2, %f0
++	ldd		[$key - 8], %f16
++	ldd		[$key - 16], %f18
++	camellia_f	%f20, %f2, %f0, %f2
++	camellia_f	%f22, %f0, %f2, %f0
++	ldd		[$key - 24], %f20
++	ldd		[$key - 32], %f22
++	camellia_f	%f24, %f2, %f0, %f2
++	camellia_f	%f26, %f0, %f2, %f0
++	ldd		[$key - 40], %f24
++	ldd		[$key - 48], %f26
++	camellia_fl	%f28, %f0, %f0
++	camellia_fli	%f30, %f2, %f2
++	ldd		[$key - 56], %f28
++	ldd		[$key - 64], %f30
++___
++for ($i=1; $i<3; $i++) {
++    $code.=<<___;
++	camellia_f	%f`16+16*$i+0`, %f2, %f0, %f2
++	camellia_f	%f`16+16*$i+2`, %f0, %f2, %f0
++	camellia_f	%f`16+16*$i+4`, %f2, %f0, %f2
++	camellia_f	%f`16+16*$i+6`, %f0, %f2, %f0
++	camellia_f	%f`16+16*$i+8`, %f2, %f0, %f2
++	camellia_f	%f`16+16*$i+10`, %f0, %f2, %f0
++	camellia_fl	%f`16+16*$i+12`, %f0,      %f0
++	camellia_fli	%f`16+16*$i+14`, %f2,      %f2
++___
++}
++$code.=<<___;
++	camellia_f	%f16, %f2, %f0, %f2
++	camellia_f	%f18, %f0, %f2, %f0
++	ldd		[$key + 184], %f16
++	ldd		[$key + 176], %f18
++	camellia_f	%f20, %f2, %f0, %f2
++	camellia_f	%f22, %f0, %f2, %f0
++	ldd		[$key + 168], %f20
++	ldd		[$key + 160], %f22
++	camellia_f	%f24, %f2, %f0, %f4
++	camellia_f	%f26, %f0, %f4, %f2
++	ldd		[$key + 152], %f24
++	ldd		[$key + 144], %f26
++	fxor		%f30, %f4, %f0
++	fxor		%f28, %f2, %f2
++	ldd		[$key + 136], %f28
++	retl
++	ldd		[$key + 128], %f30
++.type	_cmll256_decrypt_1x,#function
++.size	_cmll256_decrypt_1x,.-_cmll256_decrypt_1x
++
++.align	32
++_cmll256_decrypt_2x:
++	camellia_f	%f16, %f2, %f0, %f2
++	camellia_f	%f16, %f6, %f4, %f6
++	camellia_f	%f18, %f0, %f2, %f0
++	camellia_f	%f18, %f4, %f6, %f4
++	ldd		[$key - 8], %f16
++	ldd		[$key - 16], %f18
++	camellia_f	%f20, %f2, %f0, %f2
++	camellia_f	%f20, %f6, %f4, %f6
++	camellia_f	%f22, %f0, %f2, %f0
++	camellia_f	%f22, %f4, %f6, %f4
++	ldd		[$key - 24], %f20
++	ldd		[$key - 32], %f22
++	camellia_f	%f24, %f2, %f0, %f2
++	camellia_f	%f24, %f6, %f4, %f6
++	camellia_f	%f26, %f0, %f2, %f0
++	camellia_f	%f26, %f4, %f6, %f4
++	ldd		[$key - 40], %f24
++	ldd		[$key - 48], %f26
++	camellia_fl	%f28, %f0, %f0
++	camellia_fl	%f28, %f4, %f4
++	camellia_fli	%f30, %f2, %f2
++	camellia_fli	%f30, %f6, %f6
++	ldd		[$key - 56], %f28
++	ldd		[$key - 64], %f30
++___
++for ($i=1; $i<3; $i++) {
++    $code.=<<___;
++	camellia_f	%f`16+16*$i+0`, %f2, %f0, %f2
++	camellia_f	%f`16+16*$i+0`, %f6, %f4, %f6
++	camellia_f	%f`16+16*$i+2`, %f0, %f2, %f0
++	camellia_f	%f`16+16*$i+2`, %f4, %f6, %f4
++	camellia_f	%f`16+16*$i+4`, %f2, %f0, %f2
++	camellia_f	%f`16+16*$i+4`, %f6, %f4, %f6
++	camellia_f	%f`16+16*$i+6`, %f0, %f2, %f0
++	camellia_f	%f`16+16*$i+6`, %f4, %f6, %f4
++	camellia_f	%f`16+16*$i+8`, %f2, %f0, %f2
++	camellia_f	%f`16+16*$i+8`, %f6, %f4, %f6
++	camellia_f	%f`16+16*$i+10`, %f0, %f2, %f0
++	camellia_f	%f`16+16*$i+10`, %f4, %f6, %f4
++	camellia_fl	%f`16+16*$i+12`, %f0,      %f0
++	camellia_fl	%f`16+16*$i+12`, %f4,      %f4
++	camellia_fli	%f`16+16*$i+14`, %f2,      %f2
++	camellia_fli	%f`16+16*$i+14`, %f6,      %f6
++___
++}
++$code.=<<___;
++	camellia_f	%f16, %f2, %f0, %f2
++	camellia_f	%f16, %f6, %f4, %f6
++	camellia_f	%f18, %f0, %f2, %f0
++	camellia_f	%f18, %f4, %f6, %f4
++	ldd		[$key + 184], %f16
++	ldd		[$key + 176], %f18
++	camellia_f	%f20, %f2, %f0, %f2
++	camellia_f	%f20, %f6, %f4, %f6
++	camellia_f	%f22, %f0, %f2, %f0
++	camellia_f	%f22, %f4, %f6, %f4
++	ldd		[$key + 168], %f20
++	ldd		[$key + 160], %f22
++	camellia_f	%f24, %f2, %f0, %f8
++	camellia_f	%f24, %f6, %f4, %f10
++	camellia_f	%f26, %f0, %f8, %f2
++	camellia_f	%f26, %f4, %f10, %f6
++	ldd		[$key + 152], %f24
++	ldd		[$key + 144], %f26
++	fxor		%f30, %f8, %f0
++	fxor		%f30, %f10, %f4
++	fxor		%f28, %f2, %f2
++	fxor		%f28, %f6, %f6
++	ldd		[$key + 136], %f28
++	retl
++	ldd		[$key + 128], %f30
++.type	_cmll256_decrypt_2x,#function
++.size	_cmll256_decrypt_2x,.-_cmll256_decrypt_2x
++___
++
++&alg_cbc_encrypt_implement("cmll",128);
++&alg_cbc_encrypt_implement("cmll",256);
++
++&alg_cbc_decrypt_implement("cmll",128);
++&alg_cbc_decrypt_implement("cmll",256);
++
++if ($::evp) {
++    &alg_ctr32_implement("cmll",128);
++    &alg_ctr32_implement("cmll",256);
++}
++}}}
++
++if (!$::evp) {
++$code.=<<___;
++.global	Camellia_encrypt
++Camellia_encrypt=cmll_t4_encrypt
++.global	Camellia_decrypt
++Camellia_decrypt=cmll_t4_decrypt
++.global	Camellia_set_key
++.align	32
++Camellia_set_key:
++	andcc		%o2, 7, %g0		! double-check alignment
++	bnz,a,pn	%icc, 1f
++	mov		-1, %o0
++	brz,a,pn	%o0, 1f
++	mov		-1, %o0
++	brz,a,pn	%o2, 1f
++	mov		-1, %o0
++	andncc		%o1, 0x1c0, %g0
++	bnz,a,pn	%icc, 1f
++	mov		-2, %o0
++	cmp		%o1, 128
++	bl,a,pn		%icc, 1f
++	mov		-2, %o0
++	b		cmll_t4_set_key
++	nop
++1:	retl
++	nop
++.type	Camellia_set_key,#function
++.size	Camellia_set_key,.-Camellia_set_key
++___
++
++my ($inp,$out,$len,$key,$ivec,$enc)=map("%o$_",(0..5));
++
++$code.=<<___;
++.globl	Camellia_cbc_encrypt
++.align	32
++Camellia_cbc_encrypt:
++	ld		[$key + 272], %g1
++	nop
++	brz		$enc, .Lcbc_decrypt
++	cmp		%g1, 3
++
++	be,pt		%icc, cmll128_t4_cbc_encrypt
++	nop
++	ba		cmll256_t4_cbc_encrypt
++	nop
++
++.Lcbc_decrypt:
++	be,pt		%icc, cmll128_t4_cbc_decrypt
++	nop
++	ba		cmll256_t4_cbc_decrypt
++	nop
++.type	Camellia_cbc_encrypt,#function
++.size	Camellia_cbc_encrypt,.-Camellia_cbc_encrypt
++___
++}
++
++&emit_assembler();
++
++close STDOUT;
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/camellia/build.info b/CryptoPkg/Library/OpensslLib/openssl/crypto/camellia/build.info
+new file mode 100644
+index 0000000..fd78272
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/camellia/build.info
+@@ -0,0 +1,11 @@
++LIBS=../../libcrypto
++SOURCE[../../libcrypto]=\
++        cmll_ecb.c cmll_ofb.c cmll_cfb.c cmll_ctr.c \
++        {- $target{cmll_asm_src} -}
++
++GENERATE[cmll-x86.s]=asm/cmll-x86.pl $(PERLASM_SCHEME) $(CFLAGS) $(LIB_CFLAGS) $(PROCESSOR)
++DEPEND[cmll-x86.s]=../perlasm/x86asm.pl
++GENERATE[cmll-x86_64.s]=asm/cmll-x86_64.pl $(PERLASM_SCHEME)
++GENERATE[cmllt4-sparcv9.S]=asm/cmllt4-sparcv9.pl $(PERLASM_SCHEME)
++INCLUDE[cmllt4-sparcv9.o]=..
++DEPEND[cmllt4-sparcv9.S]=../perlasm/sparcv9_modes.pl
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/camellia/camellia.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/camellia/camellia.c
+new file mode 100644
+index 0000000..6641a62
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/camellia/camellia.c
+@@ -0,0 +1,541 @@
++/*
++ * Copyright 2006-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++/* ====================================================================
++ * Copyright 2006 NTT (Nippon Telegraph and Telephone Corporation) .
++ * ALL RIGHTS RESERVED.
++ *
++ * Intellectual Property information for Camellia:
++ *     http://info.isl.ntt.co.jp/crypt/eng/info/chiteki.html
++ *
++ * News Release for Announcement of Camellia open source:
++ *     http://www.ntt.co.jp/news/news06e/0604/060413a.html
++ *
++ * The Camellia Code included herein is developed by
++ * NTT (Nippon Telegraph and Telephone Corporation), and is contributed
++ * to the OpenSSL project.
++ */
++
++/*
++ * Algorithm Specification
++ * http://info.isl.ntt.co.jp/crypt/eng/camellia/specifications.html
++ */
++
++/*
++ * This release balances code size and performance. In particular key
++ * schedule setup is fully unrolled, because doing so *significantly*
++ * reduces amount of instructions per setup round and code increase is
++ * justifiable. In block functions on the other hand only inner loops
++ * are unrolled, as full unroll gives only nominal performance boost,
++ * while code size grows 4 or 7 times. Also, unlike previous versions
++ * this one "encourages" compiler to keep intermediate variables in
++ * registers, which should give better "all round" results, in other
++ * words reasonable performance even with not so modern compilers.
++ */
++
++#include 
++#include "cmll_locl.h"
++#include 
++#include 
++
++/* 32-bit rotations */
++#if !defined(PEDANTIC) && !defined(OPENSSL_NO_ASM) && !defined(OPENSSL_NO_INLINE_ASM)
++# if defined(_MSC_VER) && (defined(_M_IX86) || defined(_M_AMD64) || defined(_M_X64))
++#  define RightRotate(x, s) _lrotr(x, s)
++#  define LeftRotate(x, s)  _lrotl(x, s)
++#  if _MSC_VER >= 1400
++#   define SWAP(x) _byteswap_ulong(x)
++#  else
++#   define SWAP(x) (_lrotl(x, 8) & 0x00ff00ff | _lrotr(x, 8) & 0xff00ff00)
++#  endif
++#  define GETU32(p)   SWAP(*((u32 *)(p)))
++#  define PUTU32(p,v) (*((u32 *)(p)) = SWAP((v)))
++# elif defined(__GNUC__) && __GNUC__>=2
++#  if defined(__i386) || defined(__x86_64)
++#   define RightRotate(x,s) ({u32 ret; asm ("rorl %1,%0":"=r"(ret):"I"(s),"0"(x):"cc"); ret; })
++#   define LeftRotate(x,s)  ({u32 ret; asm ("roll %1,%0":"=r"(ret):"I"(s),"0"(x):"cc"); ret; })
++#   if defined(B_ENDIAN)        /* stratus.com does it */
++#    define GETU32(p)   (*(u32 *)(p))
++#    define PUTU32(p,v) (*(u32 *)(p)=(v))
++#   else
++#    define GETU32(p)   ({u32 r=*(const u32 *)(p); asm("bswapl %0":"=r"(r):"0"(r)); r; })
++#    define PUTU32(p,v) ({u32 r=(v); asm("bswapl %0":"=r"(r):"0"(r)); *(u32 *)(p)=r; })
++#   endif
++#  elif defined(_ARCH_PPC) || defined(_ARCH_PPC64) || \
++        defined(__powerpc) || defined(__ppc__) || defined(__powerpc64__)
++#   define LeftRotate(x,s)  ({u32 ret; asm ("rlwinm %0,%1,%2,0,31":"=r"(ret):"r"(x),"I"(s)); ret; })
++#   define RightRotate(x,s) LeftRotate(x,(32-s))
++#  elif defined(__s390x__)
++#   define LeftRotate(x,s)  ({u32 ret; asm ("rll %0,%1,%2":"=r"(ret):"r"(x),"I"(s)); ret; })
++#   define RightRotate(x,s) LeftRotate(x,(32-s))
++#   define GETU32(p)   (*(u32 *)(p))
++#   define PUTU32(p,v) (*(u32 *)(p)=(v))
++#  endif
++# endif
++#endif
++
++#if !defined(RightRotate) && !defined(LeftRotate)
++# define RightRotate(x, s) ( ((x) >> (s)) + ((x) << (32 - s)) )
++# define LeftRotate(x, s)  ( ((x) << (s)) + ((x) >> (32 - s)) )
++#endif
++
++#if !defined(GETU32) && !defined(PUTU32)
++# define GETU32(p)   (((u32)(p)[0] << 24) ^ ((u32)(p)[1] << 16) ^ ((u32)(p)[2] <<  8) ^ ((u32)(p)[3]))
++# define PUTU32(p,v) ((p)[0] = (u8)((v) >> 24), (p)[1] = (u8)((v) >> 16), (p)[2] = (u8)((v) >>  8), (p)[3] = (u8)(v))
++#endif
++
++/* S-box data */
++#define SBOX1_1110 Camellia_SBOX[0]
++#define SBOX4_4404 Camellia_SBOX[1]
++#define SBOX2_0222 Camellia_SBOX[2]
++#define SBOX3_3033 Camellia_SBOX[3]
++static const u32 Camellia_SBOX[][256] = {
++    {0x70707000, 0x82828200, 0x2c2c2c00, 0xececec00, 0xb3b3b300, 0x27272700,
++     0xc0c0c000, 0xe5e5e500, 0xe4e4e400, 0x85858500, 0x57575700, 0x35353500,
++     0xeaeaea00, 0x0c0c0c00, 0xaeaeae00, 0x41414100, 0x23232300, 0xefefef00,
++     0x6b6b6b00, 0x93939300, 0x45454500, 0x19191900, 0xa5a5a500, 0x21212100,
++     0xededed00, 0x0e0e0e00, 0x4f4f4f00, 0x4e4e4e00, 0x1d1d1d00, 0x65656500,
++     0x92929200, 0xbdbdbd00, 0x86868600, 0xb8b8b800, 0xafafaf00, 0x8f8f8f00,
++     0x7c7c7c00, 0xebebeb00, 0x1f1f1f00, 0xcecece00, 0x3e3e3e00, 0x30303000,
++     0xdcdcdc00, 0x5f5f5f00, 0x5e5e5e00, 0xc5c5c500, 0x0b0b0b00, 0x1a1a1a00,
++     0xa6a6a600, 0xe1e1e100, 0x39393900, 0xcacaca00, 0xd5d5d500, 0x47474700,
++     0x5d5d5d00, 0x3d3d3d00, 0xd9d9d900, 0x01010100, 0x5a5a5a00, 0xd6d6d600,
++     0x51515100, 0x56565600, 0x6c6c6c00, 0x4d4d4d00, 0x8b8b8b00, 0x0d0d0d00,
++     0x9a9a9a00, 0x66666600, 0xfbfbfb00, 0xcccccc00, 0xb0b0b000, 0x2d2d2d00,
++     0x74747400, 0x12121200, 0x2b2b2b00, 0x20202000, 0xf0f0f000, 0xb1b1b100,
++     0x84848400, 0x99999900, 0xdfdfdf00, 0x4c4c4c00, 0xcbcbcb00, 0xc2c2c200,
++     0x34343400, 0x7e7e7e00, 0x76767600, 0x05050500, 0x6d6d6d00, 0xb7b7b700,
++     0xa9a9a900, 0x31313100, 0xd1d1d100, 0x17171700, 0x04040400, 0xd7d7d700,
++     0x14141400, 0x58585800, 0x3a3a3a00, 0x61616100, 0xdedede00, 0x1b1b1b00,
++     0x11111100, 0x1c1c1c00, 0x32323200, 0x0f0f0f00, 0x9c9c9c00, 0x16161600,
++     0x53535300, 0x18181800, 0xf2f2f200, 0x22222200, 0xfefefe00, 0x44444400,
++     0xcfcfcf00, 0xb2b2b200, 0xc3c3c300, 0xb5b5b500, 0x7a7a7a00, 0x91919100,
++     0x24242400, 0x08080800, 0xe8e8e800, 0xa8a8a800, 0x60606000, 0xfcfcfc00,
++     0x69696900, 0x50505000, 0xaaaaaa00, 0xd0d0d000, 0xa0a0a000, 0x7d7d7d00,
++     0xa1a1a100, 0x89898900, 0x62626200, 0x97979700, 0x54545400, 0x5b5b5b00,
++     0x1e1e1e00, 0x95959500, 0xe0e0e000, 0xffffff00, 0x64646400, 0xd2d2d200,
++     0x10101000, 0xc4c4c400, 0x00000000, 0x48484800, 0xa3a3a300, 0xf7f7f700,
++     0x75757500, 0xdbdbdb00, 0x8a8a8a00, 0x03030300, 0xe6e6e600, 0xdadada00,
++     0x09090900, 0x3f3f3f00, 0xdddddd00, 0x94949400, 0x87878700, 0x5c5c5c00,
++     0x83838300, 0x02020200, 0xcdcdcd00, 0x4a4a4a00, 0x90909000, 0x33333300,
++     0x73737300, 0x67676700, 0xf6f6f600, 0xf3f3f300, 0x9d9d9d00, 0x7f7f7f00,
++     0xbfbfbf00, 0xe2e2e200, 0x52525200, 0x9b9b9b00, 0xd8d8d800, 0x26262600,
++     0xc8c8c800, 0x37373700, 0xc6c6c600, 0x3b3b3b00, 0x81818100, 0x96969600,
++     0x6f6f6f00, 0x4b4b4b00, 0x13131300, 0xbebebe00, 0x63636300, 0x2e2e2e00,
++     0xe9e9e900, 0x79797900, 0xa7a7a700, 0x8c8c8c00, 0x9f9f9f00, 0x6e6e6e00,
++     0xbcbcbc00, 0x8e8e8e00, 0x29292900, 0xf5f5f500, 0xf9f9f900, 0xb6b6b600,
++     0x2f2f2f00, 0xfdfdfd00, 0xb4b4b400, 0x59595900, 0x78787800, 0x98989800,
++     0x06060600, 0x6a6a6a00, 0xe7e7e700, 0x46464600, 0x71717100, 0xbababa00,
++     0xd4d4d400, 0x25252500, 0xababab00, 0x42424200, 0x88888800, 0xa2a2a200,
++     0x8d8d8d00, 0xfafafa00, 0x72727200, 0x07070700, 0xb9b9b900, 0x55555500,
++     0xf8f8f800, 0xeeeeee00, 0xacacac00, 0x0a0a0a00, 0x36363600, 0x49494900,
++     0x2a2a2a00, 0x68686800, 0x3c3c3c00, 0x38383800, 0xf1f1f100, 0xa4a4a400,
++     0x40404000, 0x28282800, 0xd3d3d300, 0x7b7b7b00, 0xbbbbbb00, 0xc9c9c900,
++     0x43434300, 0xc1c1c100, 0x15151500, 0xe3e3e300, 0xadadad00, 0xf4f4f400,
++     0x77777700, 0xc7c7c700, 0x80808000, 0x9e9e9e00},
++    {0x70700070, 0x2c2c002c, 0xb3b300b3, 0xc0c000c0, 0xe4e400e4, 0x57570057,
++     0xeaea00ea, 0xaeae00ae, 0x23230023, 0x6b6b006b, 0x45450045, 0xa5a500a5,
++     0xeded00ed, 0x4f4f004f, 0x1d1d001d, 0x92920092, 0x86860086, 0xafaf00af,
++     0x7c7c007c, 0x1f1f001f, 0x3e3e003e, 0xdcdc00dc, 0x5e5e005e, 0x0b0b000b,
++     0xa6a600a6, 0x39390039, 0xd5d500d5, 0x5d5d005d, 0xd9d900d9, 0x5a5a005a,
++     0x51510051, 0x6c6c006c, 0x8b8b008b, 0x9a9a009a, 0xfbfb00fb, 0xb0b000b0,
++     0x74740074, 0x2b2b002b, 0xf0f000f0, 0x84840084, 0xdfdf00df, 0xcbcb00cb,
++     0x34340034, 0x76760076, 0x6d6d006d, 0xa9a900a9, 0xd1d100d1, 0x04040004,
++     0x14140014, 0x3a3a003a, 0xdede00de, 0x11110011, 0x32320032, 0x9c9c009c,
++     0x53530053, 0xf2f200f2, 0xfefe00fe, 0xcfcf00cf, 0xc3c300c3, 0x7a7a007a,
++     0x24240024, 0xe8e800e8, 0x60600060, 0x69690069, 0xaaaa00aa, 0xa0a000a0,
++     0xa1a100a1, 0x62620062, 0x54540054, 0x1e1e001e, 0xe0e000e0, 0x64640064,
++     0x10100010, 0x00000000, 0xa3a300a3, 0x75750075, 0x8a8a008a, 0xe6e600e6,
++     0x09090009, 0xdddd00dd, 0x87870087, 0x83830083, 0xcdcd00cd, 0x90900090,
++     0x73730073, 0xf6f600f6, 0x9d9d009d, 0xbfbf00bf, 0x52520052, 0xd8d800d8,
++     0xc8c800c8, 0xc6c600c6, 0x81810081, 0x6f6f006f, 0x13130013, 0x63630063,
++     0xe9e900e9, 0xa7a700a7, 0x9f9f009f, 0xbcbc00bc, 0x29290029, 0xf9f900f9,
++     0x2f2f002f, 0xb4b400b4, 0x78780078, 0x06060006, 0xe7e700e7, 0x71710071,
++     0xd4d400d4, 0xabab00ab, 0x88880088, 0x8d8d008d, 0x72720072, 0xb9b900b9,
++     0xf8f800f8, 0xacac00ac, 0x36360036, 0x2a2a002a, 0x3c3c003c, 0xf1f100f1,
++     0x40400040, 0xd3d300d3, 0xbbbb00bb, 0x43430043, 0x15150015, 0xadad00ad,
++     0x77770077, 0x80800080, 0x82820082, 0xecec00ec, 0x27270027, 0xe5e500e5,
++     0x85850085, 0x35350035, 0x0c0c000c, 0x41410041, 0xefef00ef, 0x93930093,
++     0x19190019, 0x21210021, 0x0e0e000e, 0x4e4e004e, 0x65650065, 0xbdbd00bd,
++     0xb8b800b8, 0x8f8f008f, 0xebeb00eb, 0xcece00ce, 0x30300030, 0x5f5f005f,
++     0xc5c500c5, 0x1a1a001a, 0xe1e100e1, 0xcaca00ca, 0x47470047, 0x3d3d003d,
++     0x01010001, 0xd6d600d6, 0x56560056, 0x4d4d004d, 0x0d0d000d, 0x66660066,
++     0xcccc00cc, 0x2d2d002d, 0x12120012, 0x20200020, 0xb1b100b1, 0x99990099,
++     0x4c4c004c, 0xc2c200c2, 0x7e7e007e, 0x05050005, 0xb7b700b7, 0x31310031,
++     0x17170017, 0xd7d700d7, 0x58580058, 0x61610061, 0x1b1b001b, 0x1c1c001c,
++     0x0f0f000f, 0x16160016, 0x18180018, 0x22220022, 0x44440044, 0xb2b200b2,
++     0xb5b500b5, 0x91910091, 0x08080008, 0xa8a800a8, 0xfcfc00fc, 0x50500050,
++     0xd0d000d0, 0x7d7d007d, 0x89890089, 0x97970097, 0x5b5b005b, 0x95950095,
++     0xffff00ff, 0xd2d200d2, 0xc4c400c4, 0x48480048, 0xf7f700f7, 0xdbdb00db,
++     0x03030003, 0xdada00da, 0x3f3f003f, 0x94940094, 0x5c5c005c, 0x02020002,
++     0x4a4a004a, 0x33330033, 0x67670067, 0xf3f300f3, 0x7f7f007f, 0xe2e200e2,
++     0x9b9b009b, 0x26260026, 0x37370037, 0x3b3b003b, 0x96960096, 0x4b4b004b,
++     0xbebe00be, 0x2e2e002e, 0x79790079, 0x8c8c008c, 0x6e6e006e, 0x8e8e008e,
++     0xf5f500f5, 0xb6b600b6, 0xfdfd00fd, 0x59590059, 0x98980098, 0x6a6a006a,
++     0x46460046, 0xbaba00ba, 0x25250025, 0x42420042, 0xa2a200a2, 0xfafa00fa,
++     0x07070007, 0x55550055, 0xeeee00ee, 0x0a0a000a, 0x49490049, 0x68680068,
++     0x38380038, 0xa4a400a4, 0x28280028, 0x7b7b007b, 0xc9c900c9, 0xc1c100c1,
++     0xe3e300e3, 0xf4f400f4, 0xc7c700c7, 0x9e9e009e},
++    {0x00e0e0e0, 0x00050505, 0x00585858, 0x00d9d9d9, 0x00676767, 0x004e4e4e,
++     0x00818181, 0x00cbcbcb, 0x00c9c9c9, 0x000b0b0b, 0x00aeaeae, 0x006a6a6a,
++     0x00d5d5d5, 0x00181818, 0x005d5d5d, 0x00828282, 0x00464646, 0x00dfdfdf,
++     0x00d6d6d6, 0x00272727, 0x008a8a8a, 0x00323232, 0x004b4b4b, 0x00424242,
++     0x00dbdbdb, 0x001c1c1c, 0x009e9e9e, 0x009c9c9c, 0x003a3a3a, 0x00cacaca,
++     0x00252525, 0x007b7b7b, 0x000d0d0d, 0x00717171, 0x005f5f5f, 0x001f1f1f,
++     0x00f8f8f8, 0x00d7d7d7, 0x003e3e3e, 0x009d9d9d, 0x007c7c7c, 0x00606060,
++     0x00b9b9b9, 0x00bebebe, 0x00bcbcbc, 0x008b8b8b, 0x00161616, 0x00343434,
++     0x004d4d4d, 0x00c3c3c3, 0x00727272, 0x00959595, 0x00ababab, 0x008e8e8e,
++     0x00bababa, 0x007a7a7a, 0x00b3b3b3, 0x00020202, 0x00b4b4b4, 0x00adadad,
++     0x00a2a2a2, 0x00acacac, 0x00d8d8d8, 0x009a9a9a, 0x00171717, 0x001a1a1a,
++     0x00353535, 0x00cccccc, 0x00f7f7f7, 0x00999999, 0x00616161, 0x005a5a5a,
++     0x00e8e8e8, 0x00242424, 0x00565656, 0x00404040, 0x00e1e1e1, 0x00636363,
++     0x00090909, 0x00333333, 0x00bfbfbf, 0x00989898, 0x00979797, 0x00858585,
++     0x00686868, 0x00fcfcfc, 0x00ececec, 0x000a0a0a, 0x00dadada, 0x006f6f6f,
++     0x00535353, 0x00626262, 0x00a3a3a3, 0x002e2e2e, 0x00080808, 0x00afafaf,
++     0x00282828, 0x00b0b0b0, 0x00747474, 0x00c2c2c2, 0x00bdbdbd, 0x00363636,
++     0x00222222, 0x00383838, 0x00646464, 0x001e1e1e, 0x00393939, 0x002c2c2c,
++     0x00a6a6a6, 0x00303030, 0x00e5e5e5, 0x00444444, 0x00fdfdfd, 0x00888888,
++     0x009f9f9f, 0x00656565, 0x00878787, 0x006b6b6b, 0x00f4f4f4, 0x00232323,
++     0x00484848, 0x00101010, 0x00d1d1d1, 0x00515151, 0x00c0c0c0, 0x00f9f9f9,
++     0x00d2d2d2, 0x00a0a0a0, 0x00555555, 0x00a1a1a1, 0x00414141, 0x00fafafa,
++     0x00434343, 0x00131313, 0x00c4c4c4, 0x002f2f2f, 0x00a8a8a8, 0x00b6b6b6,
++     0x003c3c3c, 0x002b2b2b, 0x00c1c1c1, 0x00ffffff, 0x00c8c8c8, 0x00a5a5a5,
++     0x00202020, 0x00898989, 0x00000000, 0x00909090, 0x00474747, 0x00efefef,
++     0x00eaeaea, 0x00b7b7b7, 0x00151515, 0x00060606, 0x00cdcdcd, 0x00b5b5b5,
++     0x00121212, 0x007e7e7e, 0x00bbbbbb, 0x00292929, 0x000f0f0f, 0x00b8b8b8,
++     0x00070707, 0x00040404, 0x009b9b9b, 0x00949494, 0x00212121, 0x00666666,
++     0x00e6e6e6, 0x00cecece, 0x00ededed, 0x00e7e7e7, 0x003b3b3b, 0x00fefefe,
++     0x007f7f7f, 0x00c5c5c5, 0x00a4a4a4, 0x00373737, 0x00b1b1b1, 0x004c4c4c,
++     0x00919191, 0x006e6e6e, 0x008d8d8d, 0x00767676, 0x00030303, 0x002d2d2d,
++     0x00dedede, 0x00969696, 0x00262626, 0x007d7d7d, 0x00c6c6c6, 0x005c5c5c,
++     0x00d3d3d3, 0x00f2f2f2, 0x004f4f4f, 0x00191919, 0x003f3f3f, 0x00dcdcdc,
++     0x00797979, 0x001d1d1d, 0x00525252, 0x00ebebeb, 0x00f3f3f3, 0x006d6d6d,
++     0x005e5e5e, 0x00fbfbfb, 0x00696969, 0x00b2b2b2, 0x00f0f0f0, 0x00313131,
++     0x000c0c0c, 0x00d4d4d4, 0x00cfcfcf, 0x008c8c8c, 0x00e2e2e2, 0x00757575,
++     0x00a9a9a9, 0x004a4a4a, 0x00575757, 0x00848484, 0x00111111, 0x00454545,
++     0x001b1b1b, 0x00f5f5f5, 0x00e4e4e4, 0x000e0e0e, 0x00737373, 0x00aaaaaa,
++     0x00f1f1f1, 0x00dddddd, 0x00595959, 0x00141414, 0x006c6c6c, 0x00929292,
++     0x00545454, 0x00d0d0d0, 0x00787878, 0x00707070, 0x00e3e3e3, 0x00494949,
++     0x00808080, 0x00505050, 0x00a7a7a7, 0x00f6f6f6, 0x00777777, 0x00939393,
++     0x00868686, 0x00838383, 0x002a2a2a, 0x00c7c7c7, 0x005b5b5b, 0x00e9e9e9,
++     0x00eeeeee, 0x008f8f8f, 0x00010101, 0x003d3d3d},
++    {0x38003838, 0x41004141, 0x16001616, 0x76007676, 0xd900d9d9, 0x93009393,
++     0x60006060, 0xf200f2f2, 0x72007272, 0xc200c2c2, 0xab00abab, 0x9a009a9a,
++     0x75007575, 0x06000606, 0x57005757, 0xa000a0a0, 0x91009191, 0xf700f7f7,
++     0xb500b5b5, 0xc900c9c9, 0xa200a2a2, 0x8c008c8c, 0xd200d2d2, 0x90009090,
++     0xf600f6f6, 0x07000707, 0xa700a7a7, 0x27002727, 0x8e008e8e, 0xb200b2b2,
++     0x49004949, 0xde00dede, 0x43004343, 0x5c005c5c, 0xd700d7d7, 0xc700c7c7,
++     0x3e003e3e, 0xf500f5f5, 0x8f008f8f, 0x67006767, 0x1f001f1f, 0x18001818,
++     0x6e006e6e, 0xaf00afaf, 0x2f002f2f, 0xe200e2e2, 0x85008585, 0x0d000d0d,
++     0x53005353, 0xf000f0f0, 0x9c009c9c, 0x65006565, 0xea00eaea, 0xa300a3a3,
++     0xae00aeae, 0x9e009e9e, 0xec00ecec, 0x80008080, 0x2d002d2d, 0x6b006b6b,
++     0xa800a8a8, 0x2b002b2b, 0x36003636, 0xa600a6a6, 0xc500c5c5, 0x86008686,
++     0x4d004d4d, 0x33003333, 0xfd00fdfd, 0x66006666, 0x58005858, 0x96009696,
++     0x3a003a3a, 0x09000909, 0x95009595, 0x10001010, 0x78007878, 0xd800d8d8,
++     0x42004242, 0xcc00cccc, 0xef00efef, 0x26002626, 0xe500e5e5, 0x61006161,
++     0x1a001a1a, 0x3f003f3f, 0x3b003b3b, 0x82008282, 0xb600b6b6, 0xdb00dbdb,
++     0xd400d4d4, 0x98009898, 0xe800e8e8, 0x8b008b8b, 0x02000202, 0xeb00ebeb,
++     0x0a000a0a, 0x2c002c2c, 0x1d001d1d, 0xb000b0b0, 0x6f006f6f, 0x8d008d8d,
++     0x88008888, 0x0e000e0e, 0x19001919, 0x87008787, 0x4e004e4e, 0x0b000b0b,
++     0xa900a9a9, 0x0c000c0c, 0x79007979, 0x11001111, 0x7f007f7f, 0x22002222,
++     0xe700e7e7, 0x59005959, 0xe100e1e1, 0xda00dada, 0x3d003d3d, 0xc800c8c8,
++     0x12001212, 0x04000404, 0x74007474, 0x54005454, 0x30003030, 0x7e007e7e,
++     0xb400b4b4, 0x28002828, 0x55005555, 0x68006868, 0x50005050, 0xbe00bebe,
++     0xd000d0d0, 0xc400c4c4, 0x31003131, 0xcb00cbcb, 0x2a002a2a, 0xad00adad,
++     0x0f000f0f, 0xca00caca, 0x70007070, 0xff00ffff, 0x32003232, 0x69006969,
++     0x08000808, 0x62006262, 0x00000000, 0x24002424, 0xd100d1d1, 0xfb00fbfb,
++     0xba00baba, 0xed00eded, 0x45004545, 0x81008181, 0x73007373, 0x6d006d6d,
++     0x84008484, 0x9f009f9f, 0xee00eeee, 0x4a004a4a, 0xc300c3c3, 0x2e002e2e,
++     0xc100c1c1, 0x01000101, 0xe600e6e6, 0x25002525, 0x48004848, 0x99009999,
++     0xb900b9b9, 0xb300b3b3, 0x7b007b7b, 0xf900f9f9, 0xce00cece, 0xbf00bfbf,
++     0xdf00dfdf, 0x71007171, 0x29002929, 0xcd00cdcd, 0x6c006c6c, 0x13001313,
++     0x64006464, 0x9b009b9b, 0x63006363, 0x9d009d9d, 0xc000c0c0, 0x4b004b4b,
++     0xb700b7b7, 0xa500a5a5, 0x89008989, 0x5f005f5f, 0xb100b1b1, 0x17001717,
++     0xf400f4f4, 0xbc00bcbc, 0xd300d3d3, 0x46004646, 0xcf00cfcf, 0x37003737,
++     0x5e005e5e, 0x47004747, 0x94009494, 0xfa00fafa, 0xfc00fcfc, 0x5b005b5b,
++     0x97009797, 0xfe00fefe, 0x5a005a5a, 0xac00acac, 0x3c003c3c, 0x4c004c4c,
++     0x03000303, 0x35003535, 0xf300f3f3, 0x23002323, 0xb800b8b8, 0x5d005d5d,
++     0x6a006a6a, 0x92009292, 0xd500d5d5, 0x21002121, 0x44004444, 0x51005151,
++     0xc600c6c6, 0x7d007d7d, 0x39003939, 0x83008383, 0xdc00dcdc, 0xaa00aaaa,
++     0x7c007c7c, 0x77007777, 0x56005656, 0x05000505, 0x1b001b1b, 0xa400a4a4,
++     0x15001515, 0x34003434, 0x1e001e1e, 0x1c001c1c, 0xf800f8f8, 0x52005252,
++     0x20002020, 0x14001414, 0xe900e9e9, 0xbd00bdbd, 0xdd00dddd, 0xe400e4e4,
++     0xa100a1a1, 0xe000e0e0, 0x8a008a8a, 0xf100f1f1, 0xd600d6d6, 0x7a007a7a,
++     0xbb00bbbb, 0xe300e3e3, 0x40004040, 0x4f004f4f}
++};
++
++/* Key generation constants */
++static const u32 SIGMA[] = {
++    0xa09e667f, 0x3bcc908b, 0xb67ae858, 0x4caa73b2, 0xc6ef372f, 0xe94f82be,
++    0x54ff53a5, 0xf1d36f1c, 0x10e527fa, 0xde682d1d, 0xb05688c2, 0xb3e6c1fd
++};
++
++/* The phi algorithm given in C.2.7 of the Camellia spec document. */
++/*
++ * This version does not attempt to minimize amount of temporary
++ * variables, but instead explicitly exposes algorithm's parallelism.
++ * It is therefore most appropriate for platforms with not less than
++ * ~16 registers. For platforms with less registers [well, x86 to be
++ * specific] assembler version should be/is provided anyway...
++ */
++#define Camellia_Feistel(_s0,_s1,_s2,_s3,_key) do {\
++        register u32 _t0,_t1,_t2,_t3;\
++\
++        _t0  = _s0 ^ (_key)[0];\
++        _t3  = SBOX4_4404[_t0&0xff];\
++        _t1  = _s1 ^ (_key)[1];\
++        _t3 ^= SBOX3_3033[(_t0 >> 8)&0xff];\
++        _t2  = SBOX1_1110[_t1&0xff];\
++        _t3 ^= SBOX2_0222[(_t0 >> 16)&0xff];\
++        _t2 ^= SBOX4_4404[(_t1 >> 8)&0xff];\
++        _t3 ^= SBOX1_1110[(_t0 >> 24)];\
++        _t2 ^= _t3;\
++        _t3  = RightRotate(_t3,8);\
++        _t2 ^= SBOX3_3033[(_t1 >> 16)&0xff];\
++        _s3 ^= _t3;\
++        _t2 ^= SBOX2_0222[(_t1 >> 24)];\
++        _s2 ^= _t2; \
++        _s3 ^= _t2;\
++} while(0)
++
++/*
++ * Note that n has to be less than 32. Rotations for larger amount
++ * of bits are achieved by "rotating" order of s-elements and
++ * adjusting n accordingly, e.g. RotLeft128(s1,s2,s3,s0,n-32).
++ */
++#define RotLeft128(_s0,_s1,_s2,_s3,_n) do {\
++        u32 _t0=_s0>>(32-_n);\
++        _s0 = (_s0<<_n) | (_s1>>(32-_n));\
++        _s1 = (_s1<<_n) | (_s2>>(32-_n));\
++        _s2 = (_s2<<_n) | (_s3>>(32-_n));\
++        _s3 = (_s3<<_n) | _t0;\
++} while (0)
++
++int Camellia_Ekeygen(int keyBitLength, const u8 *rawKey, KEY_TABLE_TYPE k)
++{
++    register u32 s0, s1, s2, s3;
++
++    k[0] = s0 = GETU32(rawKey);
++    k[1] = s1 = GETU32(rawKey + 4);
++    k[2] = s2 = GETU32(rawKey + 8);
++    k[3] = s3 = GETU32(rawKey + 12);
++
++    if (keyBitLength != 128) {
++        k[8] = s0 = GETU32(rawKey + 16);
++        k[9] = s1 = GETU32(rawKey + 20);
++        if (keyBitLength == 192) {
++            k[10] = s2 = ~s0;
++            k[11] = s3 = ~s1;
++        } else {
++            k[10] = s2 = GETU32(rawKey + 24);
++            k[11] = s3 = GETU32(rawKey + 28);
++        }
++        s0 ^= k[0], s1 ^= k[1], s2 ^= k[2], s3 ^= k[3];
++    }
++
++    /* Use the Feistel routine to scramble the key material */
++    Camellia_Feistel(s0, s1, s2, s3, SIGMA + 0);
++    Camellia_Feistel(s2, s3, s0, s1, SIGMA + 2);
++
++    s0 ^= k[0], s1 ^= k[1], s2 ^= k[2], s3 ^= k[3];
++    Camellia_Feistel(s0, s1, s2, s3, SIGMA + 4);
++    Camellia_Feistel(s2, s3, s0, s1, SIGMA + 6);
++
++    /* Fill the keyTable. Requires many block rotations. */
++    if (keyBitLength == 128) {
++        k[4] = s0, k[5] = s1, k[6] = s2, k[7] = s3;
++        RotLeft128(s0, s1, s2, s3, 15); /* KA <<< 15 */
++        k[12] = s0, k[13] = s1, k[14] = s2, k[15] = s3;
++        RotLeft128(s0, s1, s2, s3, 15); /* KA <<< 30 */
++        k[16] = s0, k[17] = s1, k[18] = s2, k[19] = s3;
++        RotLeft128(s0, s1, s2, s3, 15); /* KA <<< 45 */
++        k[24] = s0, k[25] = s1;
++        RotLeft128(s0, s1, s2, s3, 15); /* KA <<< 60 */
++        k[28] = s0, k[29] = s1, k[30] = s2, k[31] = s3;
++        RotLeft128(s1, s2, s3, s0, 2); /* KA <<< 94 */
++        k[40] = s1, k[41] = s2, k[42] = s3, k[43] = s0;
++        RotLeft128(s1, s2, s3, s0, 17); /* KA <<<111 */
++        k[48] = s1, k[49] = s2, k[50] = s3, k[51] = s0;
++
++        s0 = k[0], s1 = k[1], s2 = k[2], s3 = k[3];
++        RotLeft128(s0, s1, s2, s3, 15); /* KL <<< 15 */
++        k[8] = s0, k[9] = s1, k[10] = s2, k[11] = s3;
++        RotLeft128(s0, s1, s2, s3, 30); /* KL <<< 45 */
++        k[20] = s0, k[21] = s1, k[22] = s2, k[23] = s3;
++        RotLeft128(s0, s1, s2, s3, 15); /* KL <<< 60 */
++        k[26] = s2, k[27] = s3;
++        RotLeft128(s0, s1, s2, s3, 17); /* KL <<< 77 */
++        k[32] = s0, k[33] = s1, k[34] = s2, k[35] = s3;
++        RotLeft128(s0, s1, s2, s3, 17); /* KL <<< 94 */
++        k[36] = s0, k[37] = s1, k[38] = s2, k[39] = s3;
++        RotLeft128(s0, s1, s2, s3, 17); /* KL <<<111 */
++        k[44] = s0, k[45] = s1, k[46] = s2, k[47] = s3;
++
++        return 3;               /* grand rounds */
++    } else {
++        k[12] = s0, k[13] = s1, k[14] = s2, k[15] = s3;
++        s0 ^= k[8], s1 ^= k[9], s2 ^= k[10], s3 ^= k[11];
++        Camellia_Feistel(s0, s1, s2, s3, (SIGMA + 8));
++        Camellia_Feistel(s2, s3, s0, s1, (SIGMA + 10));
++
++        k[4] = s0, k[5] = s1, k[6] = s2, k[7] = s3;
++        RotLeft128(s0, s1, s2, s3, 30); /* KB <<< 30 */
++        k[20] = s0, k[21] = s1, k[22] = s2, k[23] = s3;
++        RotLeft128(s0, s1, s2, s3, 30); /* KB <<< 60 */
++        k[40] = s0, k[41] = s1, k[42] = s2, k[43] = s3;
++        RotLeft128(s1, s2, s3, s0, 19); /* KB <<<111 */
++        k[64] = s1, k[65] = s2, k[66] = s3, k[67] = s0;
++
++        s0 = k[8], s1 = k[9], s2 = k[10], s3 = k[11];
++        RotLeft128(s0, s1, s2, s3, 15); /* KR <<< 15 */
++        k[8] = s0, k[9] = s1, k[10] = s2, k[11] = s3;
++        RotLeft128(s0, s1, s2, s3, 15); /* KR <<< 30 */
++        k[16] = s0, k[17] = s1, k[18] = s2, k[19] = s3;
++        RotLeft128(s0, s1, s2, s3, 30); /* KR <<< 60 */
++        k[36] = s0, k[37] = s1, k[38] = s2, k[39] = s3;
++        RotLeft128(s1, s2, s3, s0, 2); /* KR <<< 94 */
++        k[52] = s1, k[53] = s2, k[54] = s3, k[55] = s0;
++
++        s0 = k[12], s1 = k[13], s2 = k[14], s3 = k[15];
++        RotLeft128(s0, s1, s2, s3, 15); /* KA <<< 15 */
++        k[12] = s0, k[13] = s1, k[14] = s2, k[15] = s3;
++        RotLeft128(s0, s1, s2, s3, 30); /* KA <<< 45 */
++        k[28] = s0, k[29] = s1, k[30] = s2, k[31] = s3;
++        /* KA <<< 77 */
++        k[48] = s1, k[49] = s2, k[50] = s3, k[51] = s0;
++        RotLeft128(s1, s2, s3, s0, 17); /* KA <<< 94 */
++        k[56] = s1, k[57] = s2, k[58] = s3, k[59] = s0;
++
++        s0 = k[0], s1 = k[1], s2 = k[2], s3 = k[3];
++        RotLeft128(s1, s2, s3, s0, 13); /* KL <<< 45 */
++        k[24] = s1, k[25] = s2, k[26] = s3, k[27] = s0;
++        RotLeft128(s1, s2, s3, s0, 15); /* KL <<< 60 */
++        k[32] = s1, k[33] = s2, k[34] = s3, k[35] = s0;
++        RotLeft128(s1, s2, s3, s0, 17); /* KL <<< 77 */
++        k[44] = s1, k[45] = s2, k[46] = s3, k[47] = s0;
++        RotLeft128(s2, s3, s0, s1, 2); /* KL <<<111 */
++        k[60] = s2, k[61] = s3, k[62] = s0, k[63] = s1;
++
++        return 4;               /* grand rounds */
++    }
++    /*
++     * It is possible to perform certain precalculations, which
++     * would spare few cycles in block procedure. It's not done,
++     * because it upsets the performance balance between key
++     * setup and block procedures, negatively affecting overall
++     * throughput in applications operating on short messages
++     * and volatile keys.
++     */
++}
++
++void Camellia_EncryptBlock_Rounds(int grandRounds, const u8 plaintext[],
++                                  const KEY_TABLE_TYPE keyTable,
++                                  u8 ciphertext[])
++{
++    register u32 s0, s1, s2, s3;
++    const u32 *k = keyTable, *kend = keyTable + grandRounds * 16;
++
++    s0 = GETU32(plaintext) ^ k[0];
++    s1 = GETU32(plaintext + 4) ^ k[1];
++    s2 = GETU32(plaintext + 8) ^ k[2];
++    s3 = GETU32(plaintext + 12) ^ k[3];
++    k += 4;
++
++    while (1) {
++        /* Camellia makes 6 Feistel rounds */
++        Camellia_Feistel(s0, s1, s2, s3, k + 0);
++        Camellia_Feistel(s2, s3, s0, s1, k + 2);
++        Camellia_Feistel(s0, s1, s2, s3, k + 4);
++        Camellia_Feistel(s2, s3, s0, s1, k + 6);
++        Camellia_Feistel(s0, s1, s2, s3, k + 8);
++        Camellia_Feistel(s2, s3, s0, s1, k + 10);
++        k += 12;
++
++        if (k == kend)
++            break;
++
++        /*
++         * This is the same function as the diffusion function D of the
++         * accompanying documentation. See section 3.2 for properties of the
++         * FLlayer function.
++         */
++        s1 ^= LeftRotate(s0 & k[0], 1);
++        s2 ^= s3 | k[3];
++        s0 ^= s1 | k[1];
++        s3 ^= LeftRotate(s2 & k[2], 1);
++        k += 4;
++    }
++
++    s2 ^= k[0], s3 ^= k[1], s0 ^= k[2], s1 ^= k[3];
++
++    PUTU32(ciphertext, s2);
++    PUTU32(ciphertext + 4, s3);
++    PUTU32(ciphertext + 8, s0);
++    PUTU32(ciphertext + 12, s1);
++}
++
++void Camellia_EncryptBlock(int keyBitLength, const u8 plaintext[],
++                           const KEY_TABLE_TYPE keyTable, u8 ciphertext[])
++{
++    Camellia_EncryptBlock_Rounds(keyBitLength == 128 ? 3 : 4,
++                                 plaintext, keyTable, ciphertext);
++}
++
++void Camellia_DecryptBlock_Rounds(int grandRounds, const u8 ciphertext[],
++                                  const KEY_TABLE_TYPE keyTable,
++                                  u8 plaintext[])
++{
++    u32 s0, s1, s2, s3;
++    const u32 *k = keyTable + grandRounds * 16, *kend = keyTable + 4;
++
++    s0 = GETU32(ciphertext) ^ k[0];
++    s1 = GETU32(ciphertext + 4) ^ k[1];
++    s2 = GETU32(ciphertext + 8) ^ k[2];
++    s3 = GETU32(ciphertext + 12) ^ k[3];
++
++    while (1) {
++        /* Camellia makes 6 Feistel rounds */
++        k -= 12;
++        Camellia_Feistel(s0, s1, s2, s3, k + 10);
++        Camellia_Feistel(s2, s3, s0, s1, k + 8);
++        Camellia_Feistel(s0, s1, s2, s3, k + 6);
++        Camellia_Feistel(s2, s3, s0, s1, k + 4);
++        Camellia_Feistel(s0, s1, s2, s3, k + 2);
++        Camellia_Feistel(s2, s3, s0, s1, k + 0);
++
++        if (k == kend)
++            break;
++
++        /*
++         * This is the same function as the diffusion function D of the
++         * accompanying documentation. See section 3.2 for properties of the
++         * FLlayer function.
++         */
++        k -= 4;
++        s1 ^= LeftRotate(s0 & k[2], 1);
++        s2 ^= s3 | k[1];
++        s0 ^= s1 | k[3];
++        s3 ^= LeftRotate(s2 & k[0], 1);
++    }
++
++    k -= 4;
++    s2 ^= k[0], s3 ^= k[1], s0 ^= k[2], s1 ^= k[3];
++
++    PUTU32(plaintext, s2);
++    PUTU32(plaintext + 4, s3);
++    PUTU32(plaintext + 8, s0);
++    PUTU32(plaintext + 12, s1);
++}
++
++void Camellia_DecryptBlock(int keyBitLength, const u8 plaintext[],
++                           const KEY_TABLE_TYPE keyTable, u8 ciphertext[])
++{
++    Camellia_DecryptBlock_Rounds(keyBitLength == 128 ? 3 : 4,
++                                 plaintext, keyTable, ciphertext);
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/camellia/cmll_cbc.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/camellia/cmll_cbc.c
+new file mode 100644
+index 0000000..b19171d
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/camellia/cmll_cbc.c
+@@ -0,0 +1,24 @@
++/*
++ * Copyright 2006-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include 
++
++void Camellia_cbc_encrypt(const unsigned char *in, unsigned char *out,
++                          size_t len, const CAMELLIA_KEY *key,
++                          unsigned char *ivec, const int enc)
++{
++
++    if (enc)
++        CRYPTO_cbc128_encrypt(in, out, len, key, ivec,
++                              (block128_f) Camellia_encrypt);
++    else
++        CRYPTO_cbc128_decrypt(in, out, len, key, ivec,
++                              (block128_f) Camellia_decrypt);
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/camellia/cmll_cfb.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/camellia/cmll_cfb.c
+new file mode 100644
+index 0000000..4f49ead
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/camellia/cmll_cfb.c
+@@ -0,0 +1,43 @@
++/*
++ * Copyright 2006-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include 
++
++/*
++ * The input and output encrypted as though 128bit cfb mode is being used.
++ * The extra state information to record how much of the 128bit block we have
++ * used is contained in *num;
++ */
++
++void Camellia_cfb128_encrypt(const unsigned char *in, unsigned char *out,
++                             size_t length, const CAMELLIA_KEY *key,
++                             unsigned char *ivec, int *num, const int enc)
++{
++
++    CRYPTO_cfb128_encrypt(in, out, length, key, ivec, num, enc,
++                          (block128_f) Camellia_encrypt);
++}
++
++/* N.B. This expects the input to be packed, MS bit first */
++void Camellia_cfb1_encrypt(const unsigned char *in, unsigned char *out,
++                           size_t length, const CAMELLIA_KEY *key,
++                           unsigned char *ivec, int *num, const int enc)
++{
++    CRYPTO_cfb128_1_encrypt(in, out, length, key, ivec, num, enc,
++                            (block128_f) Camellia_encrypt);
++}
++
++void Camellia_cfb8_encrypt(const unsigned char *in, unsigned char *out,
++                           size_t length, const CAMELLIA_KEY *key,
++                           unsigned char *ivec, int *num, const int enc)
++{
++    CRYPTO_cfb128_8_encrypt(in, out, length, key, ivec, num, enc,
++                            (block128_f) Camellia_encrypt);
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/camellia/cmll_ctr.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/camellia/cmll_ctr.c
+new file mode 100644
+index 0000000..161d1e1
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/camellia/cmll_ctr.c
+@@ -0,0 +1,22 @@
++/*
++ * Copyright 2006-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include 
++
++void Camellia_ctr128_encrypt(const unsigned char *in, unsigned char *out,
++                             size_t length, const CAMELLIA_KEY *key,
++                             unsigned char ivec[CAMELLIA_BLOCK_SIZE],
++                             unsigned char ecount_buf[CAMELLIA_BLOCK_SIZE],
++                             unsigned int *num)
++{
++
++    CRYPTO_ctr128_encrypt(in, out, length, key, ivec, ecount_buf, num,
++                          (block128_f) Camellia_encrypt);
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/camellia/cmll_ecb.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/camellia/cmll_ecb.c
+new file mode 100644
+index 0000000..d932f1b
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/camellia/cmll_ecb.c
+@@ -0,0 +1,20 @@
++/*
++ * Copyright 2006-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include "cmll_locl.h"
++
++void Camellia_ecb_encrypt(const unsigned char *in, unsigned char *out,
++                          const CAMELLIA_KEY *key, const int enc)
++{
++    if (CAMELLIA_ENCRYPT == enc)
++        Camellia_encrypt(in, out, key);
++    else
++        Camellia_decrypt(in, out, key);
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/camellia/cmll_locl.h b/CryptoPkg/Library/OpensslLib/openssl/crypto/camellia/cmll_locl.h
+new file mode 100644
+index 0000000..6403b39
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/camellia/cmll_locl.h
+@@ -0,0 +1,43 @@
++/*
++ * Copyright 2006-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++/* ====================================================================
++ * Copyright 2006 NTT (Nippon Telegraph and Telephone Corporation) .
++ * ALL RIGHTS RESERVED.
++ *
++ * Intellectual Property information for Camellia:
++ *     http://info.isl.ntt.co.jp/crypt/eng/info/chiteki.html
++ *
++ * News Release for Announcement of Camellia open source:
++ *     http://www.ntt.co.jp/news/news06e/0604/060413a.html
++ *
++ * The Camellia Code included herein is developed by
++ * NTT (Nippon Telegraph and Telephone Corporation), and is contributed
++ * to the OpenSSL project.
++ */
++
++#ifndef HEADER_CAMELLIA_LOCL_H
++# define HEADER_CAMELLIA_LOCL_H
++
++typedef unsigned int u32;
++typedef unsigned char u8;
++
++int Camellia_Ekeygen(int keyBitLength, const u8 *rawKey,
++                     KEY_TABLE_TYPE keyTable);
++void Camellia_EncryptBlock_Rounds(int grandRounds, const u8 plaintext[],
++                                  const KEY_TABLE_TYPE keyTable,
++                                  u8 ciphertext[]);
++void Camellia_DecryptBlock_Rounds(int grandRounds, const u8 ciphertext[],
++                                  const KEY_TABLE_TYPE keyTable,
++                                  u8 plaintext[]);
++void Camellia_EncryptBlock(int keyBitLength, const u8 plaintext[],
++                           const KEY_TABLE_TYPE keyTable, u8 ciphertext[]);
++void Camellia_DecryptBlock(int keyBitLength, const u8 ciphertext[],
++                           const KEY_TABLE_TYPE keyTable, u8 plaintext[]);
++#endif                          /* #ifndef HEADER_CAMELLIA_LOCL_H */
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/camellia/cmll_misc.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/camellia/cmll_misc.c
+new file mode 100644
+index 0000000..e5f014b
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/camellia/cmll_misc.c
+@@ -0,0 +1,35 @@
++/*
++ * Copyright 2006-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include 
++#include "cmll_locl.h"
++
++int Camellia_set_key(const unsigned char *userKey, const int bits,
++                     CAMELLIA_KEY *key)
++{
++    if (!userKey || !key)
++        return -1;
++    if (bits != 128 && bits != 192 && bits != 256)
++        return -2;
++    key->grand_rounds = Camellia_Ekeygen(bits, userKey, key->u.rd_key);
++    return 0;
++}
++
++void Camellia_encrypt(const unsigned char *in, unsigned char *out,
++                      const CAMELLIA_KEY *key)
++{
++    Camellia_EncryptBlock_Rounds(key->grand_rounds, in, key->u.rd_key, out);
++}
++
++void Camellia_decrypt(const unsigned char *in, unsigned char *out,
++                      const CAMELLIA_KEY *key)
++{
++    Camellia_DecryptBlock_Rounds(key->grand_rounds, in, key->u.rd_key, out);
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/camellia/cmll_ofb.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/camellia/cmll_ofb.c
+new file mode 100644
+index 0000000..b43c685
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/camellia/cmll_ofb.c
+@@ -0,0 +1,24 @@
++/*
++ * Copyright 2006-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include 
++
++/*
++ * The input and output encrypted as though 128bit ofb mode is being used.
++ * The extra state information to record how much of the 128bit block we have
++ * used is contained in *num;
++ */
++void Camellia_ofb128_encrypt(const unsigned char *in, unsigned char *out,
++                             size_t length, const CAMELLIA_KEY *key,
++                             unsigned char *ivec, int *num)
++{
++    CRYPTO_ofb128_encrypt(in, out, length, key, ivec, num,
++                          (block128_f) Camellia_encrypt);
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/cast/asm/cast-586.pl b/CryptoPkg/Library/OpensslLib/openssl/crypto/cast/asm/cast-586.pl
+new file mode 100644
+index 0000000..6beb9c5
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/cast/asm/cast-586.pl
+@@ -0,0 +1,192 @@
++#! /usr/bin/env perl
++# Copyright 1995-2016 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
++# in the file LICENSE in the source distribution or at
++# https://www.openssl.org/source/license.html
++
++
++# This flag makes the inner loop one cycle longer, but generates 
++# code that runs %30 faster on the pentium pro/II, 44% faster
++# of PIII, while only %7 slower on the pentium.
++# By default, this flag is on.
++$ppro=1;
++
++$0 =~ m/(.*[\/\\])[^\/\\]+$/; $dir=$1;
++push(@INC,"${dir}","${dir}../../perlasm");
++require "x86asm.pl";
++require "cbc.pl";
++
++$output=pop;
++open STDOUT,">$output";
++
++&asm_init($ARGV[0],"cast-586.pl",$ARGV[$#ARGV] eq "386");
++
++$CAST_ROUNDS=16;
++$L="edi";
++$R="esi";
++$K="ebp";
++$tmp1="ecx";
++$tmp2="ebx";
++$tmp3="eax";
++$tmp4="edx";
++$S1="CAST_S_table0";
++$S2="CAST_S_table1";
++$S3="CAST_S_table2";
++$S4="CAST_S_table3";
++
++@F1=("add","xor","sub");
++@F2=("xor","sub","add");
++@F3=("sub","add","xor");
++
++&CAST_encrypt("CAST_encrypt",1);
++&CAST_encrypt("CAST_decrypt",0);
++&cbc("CAST_cbc_encrypt","CAST_encrypt","CAST_decrypt",1,4,5,3,-1,-1);
++
++&asm_finish();
++
++close STDOUT;
++
++sub CAST_encrypt {
++    local($name,$enc)=@_;
++
++    local($win_ex)=<<"EOF";
++EXTERN	_CAST_S_table0:DWORD
++EXTERN	_CAST_S_table1:DWORD
++EXTERN	_CAST_S_table2:DWORD
++EXTERN	_CAST_S_table3:DWORD
++EOF
++    &main::external_label(
++			  "CAST_S_table0",
++			  "CAST_S_table1",
++			  "CAST_S_table2",
++			  "CAST_S_table3",
++			  );
++
++    &function_begin_B($name,$win_ex);
++
++    &comment("");
++
++    &push("ebp");
++    &push("ebx");
++    &mov($tmp2,&wparam(0));
++    &mov($K,&wparam(1));
++    &push("esi");
++    &push("edi");
++
++    &comment("Load the 2 words");
++    &mov($L,&DWP(0,$tmp2,"",0));
++    &mov($R,&DWP(4,$tmp2,"",0));
++
++    &comment('Get short key flag');
++    &mov($tmp3,&DWP(128,$K,"",0));
++    if($enc) {
++	&push($tmp3);
++    } else {
++	&or($tmp3,$tmp3);
++	&jnz(&label('cast_dec_skip'));
++    }
++
++    &xor($tmp3,	$tmp3);
++
++    # encrypting part
++
++    if ($enc) {
++	&E_CAST( 0,$S,$L,$R,$K,@F1,$tmp1,$tmp2,$tmp3,$tmp4);
++	&E_CAST( 1,$S,$R,$L,$K,@F2,$tmp1,$tmp2,$tmp3,$tmp4);
++	&E_CAST( 2,$S,$L,$R,$K,@F3,$tmp1,$tmp2,$tmp3,$tmp4);
++	&E_CAST( 3,$S,$R,$L,$K,@F1,$tmp1,$tmp2,$tmp3,$tmp4);
++	&E_CAST( 4,$S,$L,$R,$K,@F2,$tmp1,$tmp2,$tmp3,$tmp4);
++	&E_CAST( 5,$S,$R,$L,$K,@F3,$tmp1,$tmp2,$tmp3,$tmp4);
++	&E_CAST( 6,$S,$L,$R,$K,@F1,$tmp1,$tmp2,$tmp3,$tmp4);
++	&E_CAST( 7,$S,$R,$L,$K,@F2,$tmp1,$tmp2,$tmp3,$tmp4);
++	&E_CAST( 8,$S,$L,$R,$K,@F3,$tmp1,$tmp2,$tmp3,$tmp4);
++	&E_CAST( 9,$S,$R,$L,$K,@F1,$tmp1,$tmp2,$tmp3,$tmp4);
++	&E_CAST(10,$S,$L,$R,$K,@F2,$tmp1,$tmp2,$tmp3,$tmp4);
++	&E_CAST(11,$S,$R,$L,$K,@F3,$tmp1,$tmp2,$tmp3,$tmp4);
++	&comment('test short key flag');
++	&pop($tmp4);
++	&or($tmp4,$tmp4);
++	&jnz(&label('cast_enc_done'));
++	&E_CAST(12,$S,$L,$R,$K,@F1,$tmp1,$tmp2,$tmp3,$tmp4);
++	&E_CAST(13,$S,$R,$L,$K,@F2,$tmp1,$tmp2,$tmp3,$tmp4);
++	&E_CAST(14,$S,$L,$R,$K,@F3,$tmp1,$tmp2,$tmp3,$tmp4);
++	&E_CAST(15,$S,$R,$L,$K,@F1,$tmp1,$tmp2,$tmp3,$tmp4);
++    } else {
++	&E_CAST(15,$S,$L,$R,$K,@F1,$tmp1,$tmp2,$tmp3,$tmp4);
++	&E_CAST(14,$S,$R,$L,$K,@F3,$tmp1,$tmp2,$tmp3,$tmp4);
++	&E_CAST(13,$S,$L,$R,$K,@F2,$tmp1,$tmp2,$tmp3,$tmp4);
++	&E_CAST(12,$S,$R,$L,$K,@F1,$tmp1,$tmp2,$tmp3,$tmp4);
++	&set_label('cast_dec_skip');
++	&E_CAST(11,$S,$L,$R,$K,@F3,$tmp1,$tmp2,$tmp3,$tmp4);
++	&E_CAST(10,$S,$R,$L,$K,@F2,$tmp1,$tmp2,$tmp3,$tmp4);
++	&E_CAST( 9,$S,$L,$R,$K,@F1,$tmp1,$tmp2,$tmp3,$tmp4);
++	&E_CAST( 8,$S,$R,$L,$K,@F3,$tmp1,$tmp2,$tmp3,$tmp4);
++	&E_CAST( 7,$S,$L,$R,$K,@F2,$tmp1,$tmp2,$tmp3,$tmp4);
++	&E_CAST( 6,$S,$R,$L,$K,@F1,$tmp1,$tmp2,$tmp3,$tmp4);
++	&E_CAST( 5,$S,$L,$R,$K,@F3,$tmp1,$tmp2,$tmp3,$tmp4);
++	&E_CAST( 4,$S,$R,$L,$K,@F2,$tmp1,$tmp2,$tmp3,$tmp4);
++	&E_CAST( 3,$S,$L,$R,$K,@F1,$tmp1,$tmp2,$tmp3,$tmp4);
++	&E_CAST( 2,$S,$R,$L,$K,@F3,$tmp1,$tmp2,$tmp3,$tmp4);
++	&E_CAST( 1,$S,$L,$R,$K,@F2,$tmp1,$tmp2,$tmp3,$tmp4);
++	&E_CAST( 0,$S,$R,$L,$K,@F1,$tmp1,$tmp2,$tmp3,$tmp4);
++    }
++
++    &set_label('cast_enc_done') if $enc;
++# Why the nop? - Ben 17/1/99
++    &nop();
++    &mov($tmp3,&wparam(0));
++    &mov(&DWP(4,$tmp3,"",0),$L);
++    &mov(&DWP(0,$tmp3,"",0),$R);
++    &function_end($name);
++}
++
++sub E_CAST {
++    local($i,$S,$L,$R,$K,$OP1,$OP2,$OP3,$tmp1,$tmp2,$tmp3,$tmp4)=@_;
++    # Ri needs to have 16 pre added.
++
++    &comment("round $i");
++    &mov(	$tmp4,		&DWP($i*8,$K,"",1));
++
++    &mov(	$tmp1,		&DWP($i*8+4,$K,"",1));
++    &$OP1(	$tmp4,		$R);
++
++    &rotl(	$tmp4,		&LB($tmp1));
++
++    if ($ppro) {
++	&xor(	$tmp1,		$tmp1);
++	&mov(	$tmp2,		0xff);
++	
++	&movb(	&LB($tmp1),	&HB($tmp4));	# A
++	&and(	$tmp2,		$tmp4);
++
++	&shr(	$tmp4,		16); 		#
++	&xor(	$tmp3,		$tmp3);
++    } else {
++	&mov(	$tmp2,		$tmp4);		# B
++	&movb(	&LB($tmp1),	&HB($tmp4));	# A	# BAD BAD BAD
++	
++	&shr(	$tmp4,		16); 		#
++	&and(	$tmp2,		0xff);
++    }
++
++    &movb(	&LB($tmp3),	&HB($tmp4));	# C	# BAD BAD BAD
++    &and(	$tmp4,		0xff);		# D
++
++    &mov(	$tmp1,		&DWP($S1,"",$tmp1,4));
++    &mov(	$tmp2,		&DWP($S2,"",$tmp2,4));
++
++    &$OP2(	$tmp1,		$tmp2);
++    &mov(	$tmp2,		&DWP($S3,"",$tmp3,4));
++
++    &$OP3(	$tmp1,		$tmp2);
++    &mov(	$tmp2,		&DWP($S4,"",$tmp4,4));
++
++    &$OP1(	$tmp1,		$tmp2);
++    # XXX
++
++    &xor(	$L,		$tmp1);
++    # XXX
++}
++
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/cast/build.info b/CryptoPkg/Library/OpensslLib/openssl/crypto/cast/build.info
+new file mode 100644
+index 0000000..f6a25c9
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/cast/build.info
+@@ -0,0 +1,6 @@
++LIBS=../../libcrypto
++SOURCE[../../libcrypto]=\
++        c_skey.c c_ecb.c {- $target{cast_asm_src} -} c_cfb64.c c_ofb64.c
++
++GENERATE[cast-586.s]=asm/cast-586.pl $(PERLASM_SCHEME) $(CFLAGS) $(LIB_CFLAGS) $(PROCESSOR)
++DEPEND[cast-586.s]=../perlasm/x86asm.pl ../perlasm/cbc.pl
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/cast/c_cfb64.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/cast/c_cfb64.c
+new file mode 100644
+index 0000000..bd7cb2f
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/cast/c_cfb64.c
+@@ -0,0 +1,74 @@
++/*
++ * Copyright 1995-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include "cast_lcl.h"
++
++/*
++ * The input and output encrypted as though 64bit cfb mode is being used.
++ * The extra state information to record how much of the 64bit block we have
++ * used is contained in *num;
++ */
++
++void CAST_cfb64_encrypt(const unsigned char *in, unsigned char *out,
++                        long length, const CAST_KEY *schedule,
++                        unsigned char *ivec, int *num, int enc)
++{
++    register CAST_LONG v0, v1, t;
++    register int n = *num;
++    register long l = length;
++    CAST_LONG ti[2];
++    unsigned char *iv, c, cc;
++
++    iv = ivec;
++    if (enc) {
++        while (l--) {
++            if (n == 0) {
++                n2l(iv, v0);
++                ti[0] = v0;
++                n2l(iv, v1);
++                ti[1] = v1;
++                CAST_encrypt((CAST_LONG *)ti, schedule);
++                iv = ivec;
++                t = ti[0];
++                l2n(t, iv);
++                t = ti[1];
++                l2n(t, iv);
++                iv = ivec;
++            }
++            c = *(in++) ^ iv[n];
++            *(out++) = c;
++            iv[n] = c;
++            n = (n + 1) & 0x07;
++        }
++    } else {
++        while (l--) {
++            if (n == 0) {
++                n2l(iv, v0);
++                ti[0] = v0;
++                n2l(iv, v1);
++                ti[1] = v1;
++                CAST_encrypt((CAST_LONG *)ti, schedule);
++                iv = ivec;
++                t = ti[0];
++                l2n(t, iv);
++                t = ti[1];
++                l2n(t, iv);
++                iv = ivec;
++            }
++            cc = *(in++);
++            c = iv[n];
++            iv[n] = cc;
++            *(out++) = c ^ cc;
++            n = (n + 1) & 0x07;
++        }
++    }
++    v0 = v1 = ti[0] = ti[1] = t = c = cc = 0;
++    *num = n;
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/cast/c_ecb.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/cast/c_ecb.c
+new file mode 100644
+index 0000000..da41794
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/cast/c_ecb.c
+@@ -0,0 +1,32 @@
++/*
++ * Copyright 1995-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include "cast_lcl.h"
++#include 
++
++void CAST_ecb_encrypt(const unsigned char *in, unsigned char *out,
++                      const CAST_KEY *ks, int enc)
++{
++    CAST_LONG l, d[2];
++
++    n2l(in, l);
++    d[0] = l;
++    n2l(in, l);
++    d[1] = l;
++    if (enc)
++        CAST_encrypt(d, ks);
++    else
++        CAST_decrypt(d, ks);
++    l = d[0];
++    l2n(l, out);
++    l = d[1];
++    l2n(l, out);
++    l = d[0] = d[1] = 0;
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/cast/c_enc.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/cast/c_enc.c
+new file mode 100644
+index 0000000..9a85812
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/cast/c_enc.c
+@@ -0,0 +1,151 @@
++/*
++ * Copyright 1995-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include "cast_lcl.h"
++
++void CAST_encrypt(CAST_LONG *data, const CAST_KEY *key)
++{
++    register CAST_LONG l, r, t;
++    const register CAST_LONG *k;
++
++    k = &(key->data[0]);
++    l = data[0];
++    r = data[1];
++
++    E_CAST(0, k, l, r, +, ^, -);
++    E_CAST(1, k, r, l, ^, -, +);
++    E_CAST(2, k, l, r, -, +, ^);
++    E_CAST(3, k, r, l, +, ^, -);
++    E_CAST(4, k, l, r, ^, -, +);
++    E_CAST(5, k, r, l, -, +, ^);
++    E_CAST(6, k, l, r, +, ^, -);
++    E_CAST(7, k, r, l, ^, -, +);
++    E_CAST(8, k, l, r, -, +, ^);
++    E_CAST(9, k, r, l, +, ^, -);
++    E_CAST(10, k, l, r, ^, -, +);
++    E_CAST(11, k, r, l, -, +, ^);
++    if (!key->short_key) {
++        E_CAST(12, k, l, r, +, ^, -);
++        E_CAST(13, k, r, l, ^, -, +);
++        E_CAST(14, k, l, r, -, +, ^);
++        E_CAST(15, k, r, l, +, ^, -);
++    }
++
++    data[1] = l & 0xffffffffL;
++    data[0] = r & 0xffffffffL;
++}
++
++void CAST_decrypt(CAST_LONG *data, const CAST_KEY *key)
++{
++    register CAST_LONG l, r, t;
++    const register CAST_LONG *k;
++
++    k = &(key->data[0]);
++    l = data[0];
++    r = data[1];
++
++    if (!key->short_key) {
++        E_CAST(15, k, l, r, +, ^, -);
++        E_CAST(14, k, r, l, -, +, ^);
++        E_CAST(13, k, l, r, ^, -, +);
++        E_CAST(12, k, r, l, +, ^, -);
++    }
++    E_CAST(11, k, l, r, -, +, ^);
++    E_CAST(10, k, r, l, ^, -, +);
++    E_CAST(9, k, l, r, +, ^, -);
++    E_CAST(8, k, r, l, -, +, ^);
++    E_CAST(7, k, l, r, ^, -, +);
++    E_CAST(6, k, r, l, +, ^, -);
++    E_CAST(5, k, l, r, -, +, ^);
++    E_CAST(4, k, r, l, ^, -, +);
++    E_CAST(3, k, l, r, +, ^, -);
++    E_CAST(2, k, r, l, -, +, ^);
++    E_CAST(1, k, l, r, ^, -, +);
++    E_CAST(0, k, r, l, +, ^, -);
++
++    data[1] = l & 0xffffffffL;
++    data[0] = r & 0xffffffffL;
++}
++
++void CAST_cbc_encrypt(const unsigned char *in, unsigned char *out,
++                      long length, const CAST_KEY *ks, unsigned char *iv,
++                      int enc)
++{
++    register CAST_LONG tin0, tin1;
++    register CAST_LONG tout0, tout1, xor0, xor1;
++    register long l = length;
++    CAST_LONG tin[2];
++
++    if (enc) {
++        n2l(iv, tout0);
++        n2l(iv, tout1);
++        iv -= 8;
++        for (l -= 8; l >= 0; l -= 8) {
++            n2l(in, tin0);
++            n2l(in, tin1);
++            tin0 ^= tout0;
++            tin1 ^= tout1;
++            tin[0] = tin0;
++            tin[1] = tin1;
++            CAST_encrypt(tin, ks);
++            tout0 = tin[0];
++            tout1 = tin[1];
++            l2n(tout0, out);
++            l2n(tout1, out);
++        }
++        if (l != -8) {
++            n2ln(in, tin0, tin1, l + 8);
++            tin0 ^= tout0;
++            tin1 ^= tout1;
++            tin[0] = tin0;
++            tin[1] = tin1;
++            CAST_encrypt(tin, ks);
++            tout0 = tin[0];
++            tout1 = tin[1];
++            l2n(tout0, out);
++            l2n(tout1, out);
++        }
++        l2n(tout0, iv);
++        l2n(tout1, iv);
++    } else {
++        n2l(iv, xor0);
++        n2l(iv, xor1);
++        iv -= 8;
++        for (l -= 8; l >= 0; l -= 8) {
++            n2l(in, tin0);
++            n2l(in, tin1);
++            tin[0] = tin0;
++            tin[1] = tin1;
++            CAST_decrypt(tin, ks);
++            tout0 = tin[0] ^ xor0;
++            tout1 = tin[1] ^ xor1;
++            l2n(tout0, out);
++            l2n(tout1, out);
++            xor0 = tin0;
++            xor1 = tin1;
++        }
++        if (l != -8) {
++            n2l(in, tin0);
++            n2l(in, tin1);
++            tin[0] = tin0;
++            tin[1] = tin1;
++            CAST_decrypt(tin, ks);
++            tout0 = tin[0] ^ xor0;
++            tout1 = tin[1] ^ xor1;
++            l2nn(tout0, tout1, out, l + 8);
++            xor0 = tin0;
++            xor1 = tin1;
++        }
++        l2n(xor0, iv);
++        l2n(xor1, iv);
++    }
++    tin0 = tin1 = tout0 = tout1 = xor0 = xor1 = 0;
++    tin[0] = tin[1] = 0;
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/cast/c_ofb64.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/cast/c_ofb64.c
+new file mode 100644
+index 0000000..dffb074
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/cast/c_ofb64.c
+@@ -0,0 +1,61 @@
++/*
++ * Copyright 1995-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include "cast_lcl.h"
++
++/*
++ * The input and output encrypted as though 64bit ofb mode is being used.
++ * The extra state information to record how much of the 64bit block we have
++ * used is contained in *num;
++ */
++void CAST_ofb64_encrypt(const unsigned char *in, unsigned char *out,
++                        long length, const CAST_KEY *schedule,
++                        unsigned char *ivec, int *num)
++{
++    register CAST_LONG v0, v1, t;
++    register int n = *num;
++    register long l = length;
++    unsigned char d[8];
++    register char *dp;
++    CAST_LONG ti[2];
++    unsigned char *iv;
++    int save = 0;
++
++    iv = ivec;
++    n2l(iv, v0);
++    n2l(iv, v1);
++    ti[0] = v0;
++    ti[1] = v1;
++    dp = (char *)d;
++    l2n(v0, dp);
++    l2n(v1, dp);
++    while (l--) {
++        if (n == 0) {
++            CAST_encrypt((CAST_LONG *)ti, schedule);
++            dp = (char *)d;
++            t = ti[0];
++            l2n(t, dp);
++            t = ti[1];
++            l2n(t, dp);
++            save++;
++        }
++        *(out++) = *(in++) ^ d[n];
++        n = (n + 1) & 0x07;
++    }
++    if (save) {
++        v0 = ti[0];
++        v1 = ti[1];
++        iv = ivec;
++        l2n(v0, iv);
++        l2n(v1, iv);
++    }
++    t = v0 = v1 = ti[0] = ti[1] = 0;
++    *num = n;
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/cast/c_skey.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/cast/c_skey.c
+new file mode 100644
+index 0000000..962d2a6
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/cast/c_skey.c
+@@ -0,0 +1,118 @@
++/*
++ * Copyright 1995-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include "cast_lcl.h"
++#include "cast_s.h"
++
++#define CAST_exp(l,A,a,n) \
++        A[n/4]=l; \
++        a[n+3]=(l    )&0xff; \
++        a[n+2]=(l>> 8)&0xff; \
++        a[n+1]=(l>>16)&0xff; \
++        a[n+0]=(l>>24)&0xff;
++
++#define S4 CAST_S_table4
++#define S5 CAST_S_table5
++#define S6 CAST_S_table6
++#define S7 CAST_S_table7
++
++void CAST_set_key(CAST_KEY *key, int len, const unsigned char *data)
++{
++    CAST_LONG x[16];
++    CAST_LONG z[16];
++    CAST_LONG k[32];
++    CAST_LONG X[4], Z[4];
++    CAST_LONG l, *K;
++    int i;
++
++    for (i = 0; i < 16; i++)
++        x[i] = 0;
++    if (len > 16)
++        len = 16;
++    for (i = 0; i < len; i++)
++        x[i] = data[i];
++    if (len <= 10)
++        key->short_key = 1;
++    else
++        key->short_key = 0;
++
++    K = &k[0];
++    X[0] = ((x[0] << 24) | (x[1] << 16) | (x[2] << 8) | x[3]) & 0xffffffffL;
++    X[1] = ((x[4] << 24) | (x[5] << 16) | (x[6] << 8) | x[7]) & 0xffffffffL;
++    X[2] = ((x[8] << 24) | (x[9] << 16) | (x[10] << 8) | x[11]) & 0xffffffffL;
++    X[3] =
++        ((x[12] << 24) | (x[13] << 16) | (x[14] << 8) | x[15]) & 0xffffffffL;
++
++    for (;;) {
++        l = X[0] ^ S4[x[13]] ^ S5[x[15]] ^ S6[x[12]] ^ S7[x[14]] ^ S6[x[8]];
++        CAST_exp(l, Z, z, 0);
++        l = X[2] ^ S4[z[0]] ^ S5[z[2]] ^ S6[z[1]] ^ S7[z[3]] ^ S7[x[10]];
++        CAST_exp(l, Z, z, 4);
++        l = X[3] ^ S4[z[7]] ^ S5[z[6]] ^ S6[z[5]] ^ S7[z[4]] ^ S4[x[9]];
++        CAST_exp(l, Z, z, 8);
++        l = X[1] ^ S4[z[10]] ^ S5[z[9]] ^ S6[z[11]] ^ S7[z[8]] ^ S5[x[11]];
++        CAST_exp(l, Z, z, 12);
++
++        K[0] = S4[z[8]] ^ S5[z[9]] ^ S6[z[7]] ^ S7[z[6]] ^ S4[z[2]];
++        K[1] = S4[z[10]] ^ S5[z[11]] ^ S6[z[5]] ^ S7[z[4]] ^ S5[z[6]];
++        K[2] = S4[z[12]] ^ S5[z[13]] ^ S6[z[3]] ^ S7[z[2]] ^ S6[z[9]];
++        K[3] = S4[z[14]] ^ S5[z[15]] ^ S6[z[1]] ^ S7[z[0]] ^ S7[z[12]];
++
++        l = Z[2] ^ S4[z[5]] ^ S5[z[7]] ^ S6[z[4]] ^ S7[z[6]] ^ S6[z[0]];
++        CAST_exp(l, X, x, 0);
++        l = Z[0] ^ S4[x[0]] ^ S5[x[2]] ^ S6[x[1]] ^ S7[x[3]] ^ S7[z[2]];
++        CAST_exp(l, X, x, 4);
++        l = Z[1] ^ S4[x[7]] ^ S5[x[6]] ^ S6[x[5]] ^ S7[x[4]] ^ S4[z[1]];
++        CAST_exp(l, X, x, 8);
++        l = Z[3] ^ S4[x[10]] ^ S5[x[9]] ^ S6[x[11]] ^ S7[x[8]] ^ S5[z[3]];
++        CAST_exp(l, X, x, 12);
++
++        K[4] = S4[x[3]] ^ S5[x[2]] ^ S6[x[12]] ^ S7[x[13]] ^ S4[x[8]];
++        K[5] = S4[x[1]] ^ S5[x[0]] ^ S6[x[14]] ^ S7[x[15]] ^ S5[x[13]];
++        K[6] = S4[x[7]] ^ S5[x[6]] ^ S6[x[8]] ^ S7[x[9]] ^ S6[x[3]];
++        K[7] = S4[x[5]] ^ S5[x[4]] ^ S6[x[10]] ^ S7[x[11]] ^ S7[x[7]];
++
++        l = X[0] ^ S4[x[13]] ^ S5[x[15]] ^ S6[x[12]] ^ S7[x[14]] ^ S6[x[8]];
++        CAST_exp(l, Z, z, 0);
++        l = X[2] ^ S4[z[0]] ^ S5[z[2]] ^ S6[z[1]] ^ S7[z[3]] ^ S7[x[10]];
++        CAST_exp(l, Z, z, 4);
++        l = X[3] ^ S4[z[7]] ^ S5[z[6]] ^ S6[z[5]] ^ S7[z[4]] ^ S4[x[9]];
++        CAST_exp(l, Z, z, 8);
++        l = X[1] ^ S4[z[10]] ^ S5[z[9]] ^ S6[z[11]] ^ S7[z[8]] ^ S5[x[11]];
++        CAST_exp(l, Z, z, 12);
++
++        K[8] = S4[z[3]] ^ S5[z[2]] ^ S6[z[12]] ^ S7[z[13]] ^ S4[z[9]];
++        K[9] = S4[z[1]] ^ S5[z[0]] ^ S6[z[14]] ^ S7[z[15]] ^ S5[z[12]];
++        K[10] = S4[z[7]] ^ S5[z[6]] ^ S6[z[8]] ^ S7[z[9]] ^ S6[z[2]];
++        K[11] = S4[z[5]] ^ S5[z[4]] ^ S6[z[10]] ^ S7[z[11]] ^ S7[z[6]];
++
++        l = Z[2] ^ S4[z[5]] ^ S5[z[7]] ^ S6[z[4]] ^ S7[z[6]] ^ S6[z[0]];
++        CAST_exp(l, X, x, 0);
++        l = Z[0] ^ S4[x[0]] ^ S5[x[2]] ^ S6[x[1]] ^ S7[x[3]] ^ S7[z[2]];
++        CAST_exp(l, X, x, 4);
++        l = Z[1] ^ S4[x[7]] ^ S5[x[6]] ^ S6[x[5]] ^ S7[x[4]] ^ S4[z[1]];
++        CAST_exp(l, X, x, 8);
++        l = Z[3] ^ S4[x[10]] ^ S5[x[9]] ^ S6[x[11]] ^ S7[x[8]] ^ S5[z[3]];
++        CAST_exp(l, X, x, 12);
++
++        K[12] = S4[x[8]] ^ S5[x[9]] ^ S6[x[7]] ^ S7[x[6]] ^ S4[x[3]];
++        K[13] = S4[x[10]] ^ S5[x[11]] ^ S6[x[5]] ^ S7[x[4]] ^ S5[x[7]];
++        K[14] = S4[x[12]] ^ S5[x[13]] ^ S6[x[3]] ^ S7[x[2]] ^ S6[x[8]];
++        K[15] = S4[x[14]] ^ S5[x[15]] ^ S6[x[1]] ^ S7[x[0]] ^ S7[x[13]];
++        if (K != k)
++            break;
++        K += 16;
++    }
++
++    for (i = 0; i < 16; i++) {
++        key->data[i * 2] = k[i];
++        key->data[i * 2 + 1] = ((k[i + 16]) + 16) & 0x1f;
++    }
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/cast/cast_lcl.h b/CryptoPkg/Library/OpensslLib/openssl/crypto/cast/cast_lcl.h
+new file mode 100644
+index 0000000..504232a
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/cast/cast_lcl.h
+@@ -0,0 +1,176 @@
++/*
++ * Copyright 1995-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include "e_os.h"
++
++#ifdef OPENSSL_SYS_WIN32
++# include 
++#endif
++
++#undef c2l
++#define c2l(c,l)        (l =((unsigned long)(*((c)++)))    , \
++                         l|=((unsigned long)(*((c)++)))<< 8L, \
++                         l|=((unsigned long)(*((c)++)))<<16L, \
++                         l|=((unsigned long)(*((c)++)))<<24L)
++
++/* NOTE - c is not incremented as per c2l */
++#undef c2ln
++#define c2ln(c,l1,l2,n) { \
++                        c+=n; \
++                        l1=l2=0; \
++                        switch (n) { \
++                        case 8: l2 =((unsigned long)(*(--(c))))<<24L; \
++                        case 7: l2|=((unsigned long)(*(--(c))))<<16L; \
++                        case 6: l2|=((unsigned long)(*(--(c))))<< 8L; \
++                        case 5: l2|=((unsigned long)(*(--(c))));     \
++                        case 4: l1 =((unsigned long)(*(--(c))))<<24L; \
++                        case 3: l1|=((unsigned long)(*(--(c))))<<16L; \
++                        case 2: l1|=((unsigned long)(*(--(c))))<< 8L; \
++                        case 1: l1|=((unsigned long)(*(--(c))));     \
++                                } \
++                        }
++
++#undef l2c
++#define l2c(l,c)        (*((c)++)=(unsigned char)(((l)     )&0xff), \
++                         *((c)++)=(unsigned char)(((l)>> 8L)&0xff), \
++                         *((c)++)=(unsigned char)(((l)>>16L)&0xff), \
++                         *((c)++)=(unsigned char)(((l)>>24L)&0xff))
++
++/* NOTE - c is not incremented as per l2c */
++#undef l2cn
++#define l2cn(l1,l2,c,n) { \
++                        c+=n; \
++                        switch (n) { \
++                        case 8: *(--(c))=(unsigned char)(((l2)>>24L)&0xff); \
++                        case 7: *(--(c))=(unsigned char)(((l2)>>16L)&0xff); \
++                        case 6: *(--(c))=(unsigned char)(((l2)>> 8L)&0xff); \
++                        case 5: *(--(c))=(unsigned char)(((l2)     )&0xff); \
++                        case 4: *(--(c))=(unsigned char)(((l1)>>24L)&0xff); \
++                        case 3: *(--(c))=(unsigned char)(((l1)>>16L)&0xff); \
++                        case 2: *(--(c))=(unsigned char)(((l1)>> 8L)&0xff); \
++                        case 1: *(--(c))=(unsigned char)(((l1)     )&0xff); \
++                                } \
++                        }
++
++/* NOTE - c is not incremented as per n2l */
++#define n2ln(c,l1,l2,n) { \
++                        c+=n; \
++                        l1=l2=0; \
++                        switch (n) { \
++                        case 8: l2 =((unsigned long)(*(--(c))))    ; \
++                        case 7: l2|=((unsigned long)(*(--(c))))<< 8; \
++                        case 6: l2|=((unsigned long)(*(--(c))))<<16; \
++                        case 5: l2|=((unsigned long)(*(--(c))))<<24; \
++                        case 4: l1 =((unsigned long)(*(--(c))))    ; \
++                        case 3: l1|=((unsigned long)(*(--(c))))<< 8; \
++                        case 2: l1|=((unsigned long)(*(--(c))))<<16; \
++                        case 1: l1|=((unsigned long)(*(--(c))))<<24; \
++                                } \
++                        }
++
++/* NOTE - c is not incremented as per l2n */
++#define l2nn(l1,l2,c,n) { \
++                        c+=n; \
++                        switch (n) { \
++                        case 8: *(--(c))=(unsigned char)(((l2)    )&0xff); \
++                        case 7: *(--(c))=(unsigned char)(((l2)>> 8)&0xff); \
++                        case 6: *(--(c))=(unsigned char)(((l2)>>16)&0xff); \
++                        case 5: *(--(c))=(unsigned char)(((l2)>>24)&0xff); \
++                        case 4: *(--(c))=(unsigned char)(((l1)    )&0xff); \
++                        case 3: *(--(c))=(unsigned char)(((l1)>> 8)&0xff); \
++                        case 2: *(--(c))=(unsigned char)(((l1)>>16)&0xff); \
++                        case 1: *(--(c))=(unsigned char)(((l1)>>24)&0xff); \
++                                } \
++                        }
++
++#undef n2l
++#define n2l(c,l)        (l =((unsigned long)(*((c)++)))<<24L, \
++                         l|=((unsigned long)(*((c)++)))<<16L, \
++                         l|=((unsigned long)(*((c)++)))<< 8L, \
++                         l|=((unsigned long)(*((c)++))))
++
++#undef l2n
++#define l2n(l,c)        (*((c)++)=(unsigned char)(((l)>>24L)&0xff), \
++                         *((c)++)=(unsigned char)(((l)>>16L)&0xff), \
++                         *((c)++)=(unsigned char)(((l)>> 8L)&0xff), \
++                         *((c)++)=(unsigned char)(((l)     )&0xff))
++
++#if defined(OPENSSL_SYS_WIN32) && defined(_MSC_VER)
++# define ROTL(a,n)     (_lrotl(a,n))
++#else
++# define ROTL(a,n)     ((((a)<<(n))&0xffffffffL)|((a)>>((32-(n))&31)))
++#endif
++
++#define C_M    0x3fc
++#define C_0    22L
++#define C_1    14L
++#define C_2     6L
++#define C_3     2L              /* left shift */
++
++/* The rotate has an extra 16 added to it to help the x86 asm */
++#if defined(CAST_PTR)
++# define E_CAST(n,key,L,R,OP1,OP2,OP3) \
++        { \
++        int i; \
++        t=(key[n*2] OP1 R)&0xffffffffL; \
++        i=key[n*2+1]; \
++        t=ROTL(t,i); \
++        L^= (((((*(CAST_LONG *)((unsigned char *) \
++                        CAST_S_table0+((t>>C_2)&C_M)) OP2 \
++                *(CAST_LONG *)((unsigned char *) \
++                        CAST_S_table1+((t<>C_0)&C_M)))&0xffffffffL) OP1 \
++                *(CAST_LONG *)((unsigned char *) \
++                        CAST_S_table3+((t>>C_1)&C_M)))&0xffffffffL; \
++        }
++#elif defined(CAST_PTR2)
++# define E_CAST(n,key,L,R,OP1,OP2,OP3) \
++        { \
++        int i; \
++        CAST_LONG u,v,w; \
++        w=(key[n*2] OP1 R)&0xffffffffL; \
++        i=key[n*2+1]; \
++        w=ROTL(w,i); \
++        u=w>>C_2; \
++        v=w<>C_0; \
++        t=(t OP2 *(CAST_LONG *)((unsigned char *)CAST_S_table1+v))&0xffffffffL;\
++        v=w>>C_1; \
++        u&=C_M; \
++        v&=C_M; \
++        t=(t OP3 *(CAST_LONG *)((unsigned char *)CAST_S_table2+u)&0xffffffffL);\
++        t=(t OP1 *(CAST_LONG *)((unsigned char *)CAST_S_table3+v)&0xffffffffL);\
++        L^=(t&0xffffffff); \
++        }
++#else
++# define E_CAST(n,key,L,R,OP1,OP2,OP3) \
++        { \
++        CAST_LONG a,b,c,d; \
++        t=(key[n*2] OP1 R)&0xffffffff; \
++        t=ROTL(t,(key[n*2+1])); \
++        a=CAST_S_table0[(t>> 8)&0xff]; \
++        b=CAST_S_table1[(t    )&0xff]; \
++        c=CAST_S_table2[(t>>24)&0xff]; \
++        d=CAST_S_table3[(t>>16)&0xff]; \
++        L^=(((((a OP2 b)&0xffffffffL) OP3 c)&0xffffffffL) OP1 d)&0xffffffffL; \
++        }
++#endif
++
++extern const CAST_LONG CAST_S_table0[256];
++extern const CAST_LONG CAST_S_table1[256];
++extern const CAST_LONG CAST_S_table2[256];
++extern const CAST_LONG CAST_S_table3[256];
++extern const CAST_LONG CAST_S_table4[256];
++extern const CAST_LONG CAST_S_table5[256];
++extern const CAST_LONG CAST_S_table6[256];
++extern const CAST_LONG CAST_S_table7[256];
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/cast/cast_s.h b/CryptoPkg/Library/OpensslLib/openssl/crypto/cast/cast_s.h
+new file mode 100644
+index 0000000..d9fd6ac
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/cast/cast_s.h
+@@ -0,0 +1,544 @@
++/*
++ * Copyright 1995-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++OPENSSL_GLOBAL const CAST_LONG CAST_S_table0[256] = {
++    0x30fb40d4, 0x9fa0ff0b, 0x6beccd2f, 0x3f258c7a,
++    0x1e213f2f, 0x9c004dd3, 0x6003e540, 0xcf9fc949,
++    0xbfd4af27, 0x88bbbdb5, 0xe2034090, 0x98d09675,
++    0x6e63a0e0, 0x15c361d2, 0xc2e7661d, 0x22d4ff8e,
++    0x28683b6f, 0xc07fd059, 0xff2379c8, 0x775f50e2,
++    0x43c340d3, 0xdf2f8656, 0x887ca41a, 0xa2d2bd2d,
++    0xa1c9e0d6, 0x346c4819, 0x61b76d87, 0x22540f2f,
++    0x2abe32e1, 0xaa54166b, 0x22568e3a, 0xa2d341d0,
++    0x66db40c8, 0xa784392f, 0x004dff2f, 0x2db9d2de,
++    0x97943fac, 0x4a97c1d8, 0x527644b7, 0xb5f437a7,
++    0xb82cbaef, 0xd751d159, 0x6ff7f0ed, 0x5a097a1f,
++    0x827b68d0, 0x90ecf52e, 0x22b0c054, 0xbc8e5935,
++    0x4b6d2f7f, 0x50bb64a2, 0xd2664910, 0xbee5812d,
++    0xb7332290, 0xe93b159f, 0xb48ee411, 0x4bff345d,
++    0xfd45c240, 0xad31973f, 0xc4f6d02e, 0x55fc8165,
++    0xd5b1caad, 0xa1ac2dae, 0xa2d4b76d, 0xc19b0c50,
++    0x882240f2, 0x0c6e4f38, 0xa4e4bfd7, 0x4f5ba272,
++    0x564c1d2f, 0xc59c5319, 0xb949e354, 0xb04669fe,
++    0xb1b6ab8a, 0xc71358dd, 0x6385c545, 0x110f935d,
++    0x57538ad5, 0x6a390493, 0xe63d37e0, 0x2a54f6b3,
++    0x3a787d5f, 0x6276a0b5, 0x19a6fcdf, 0x7a42206a,
++    0x29f9d4d5, 0xf61b1891, 0xbb72275e, 0xaa508167,
++    0x38901091, 0xc6b505eb, 0x84c7cb8c, 0x2ad75a0f,
++    0x874a1427, 0xa2d1936b, 0x2ad286af, 0xaa56d291,
++    0xd7894360, 0x425c750d, 0x93b39e26, 0x187184c9,
++    0x6c00b32d, 0x73e2bb14, 0xa0bebc3c, 0x54623779,
++    0x64459eab, 0x3f328b82, 0x7718cf82, 0x59a2cea6,
++    0x04ee002e, 0x89fe78e6, 0x3fab0950, 0x325ff6c2,
++    0x81383f05, 0x6963c5c8, 0x76cb5ad6, 0xd49974c9,
++    0xca180dcf, 0x380782d5, 0xc7fa5cf6, 0x8ac31511,
++    0x35e79e13, 0x47da91d0, 0xf40f9086, 0xa7e2419e,
++    0x31366241, 0x051ef495, 0xaa573b04, 0x4a805d8d,
++    0x548300d0, 0x00322a3c, 0xbf64cddf, 0xba57a68e,
++    0x75c6372b, 0x50afd341, 0xa7c13275, 0x915a0bf5,
++    0x6b54bfab, 0x2b0b1426, 0xab4cc9d7, 0x449ccd82,
++    0xf7fbf265, 0xab85c5f3, 0x1b55db94, 0xaad4e324,
++    0xcfa4bd3f, 0x2deaa3e2, 0x9e204d02, 0xc8bd25ac,
++    0xeadf55b3, 0xd5bd9e98, 0xe31231b2, 0x2ad5ad6c,
++    0x954329de, 0xadbe4528, 0xd8710f69, 0xaa51c90f,
++    0xaa786bf6, 0x22513f1e, 0xaa51a79b, 0x2ad344cc,
++    0x7b5a41f0, 0xd37cfbad, 0x1b069505, 0x41ece491,
++    0xb4c332e6, 0x032268d4, 0xc9600acc, 0xce387e6d,
++    0xbf6bb16c, 0x6a70fb78, 0x0d03d9c9, 0xd4df39de,
++    0xe01063da, 0x4736f464, 0x5ad328d8, 0xb347cc96,
++    0x75bb0fc3, 0x98511bfb, 0x4ffbcc35, 0xb58bcf6a,
++    0xe11f0abc, 0xbfc5fe4a, 0xa70aec10, 0xac39570a,
++    0x3f04442f, 0x6188b153, 0xe0397a2e, 0x5727cb79,
++    0x9ceb418f, 0x1cacd68d, 0x2ad37c96, 0x0175cb9d,
++    0xc69dff09, 0xc75b65f0, 0xd9db40d8, 0xec0e7779,
++    0x4744ead4, 0xb11c3274, 0xdd24cb9e, 0x7e1c54bd,
++    0xf01144f9, 0xd2240eb1, 0x9675b3fd, 0xa3ac3755,
++    0xd47c27af, 0x51c85f4d, 0x56907596, 0xa5bb15e6,
++    0x580304f0, 0xca042cf1, 0x011a37ea, 0x8dbfaadb,
++    0x35ba3e4a, 0x3526ffa0, 0xc37b4d09, 0xbc306ed9,
++    0x98a52666, 0x5648f725, 0xff5e569d, 0x0ced63d0,
++    0x7c63b2cf, 0x700b45e1, 0xd5ea50f1, 0x85a92872,
++    0xaf1fbda7, 0xd4234870, 0xa7870bf3, 0x2d3b4d79,
++    0x42e04198, 0x0cd0ede7, 0x26470db8, 0xf881814c,
++    0x474d6ad7, 0x7c0c5e5c, 0xd1231959, 0x381b7298,
++    0xf5d2f4db, 0xab838653, 0x6e2f1e23, 0x83719c9e,
++    0xbd91e046, 0x9a56456e, 0xdc39200c, 0x20c8c571,
++    0x962bda1c, 0xe1e696ff, 0xb141ab08, 0x7cca89b9,
++    0x1a69e783, 0x02cc4843, 0xa2f7c579, 0x429ef47d,
++    0x427b169c, 0x5ac9f049, 0xdd8f0f00, 0x5c8165bf,
++};
++
++OPENSSL_GLOBAL const CAST_LONG CAST_S_table1[256] = {
++    0x1f201094, 0xef0ba75b, 0x69e3cf7e, 0x393f4380,
++    0xfe61cf7a, 0xeec5207a, 0x55889c94, 0x72fc0651,
++    0xada7ef79, 0x4e1d7235, 0xd55a63ce, 0xde0436ba,
++    0x99c430ef, 0x5f0c0794, 0x18dcdb7d, 0xa1d6eff3,
++    0xa0b52f7b, 0x59e83605, 0xee15b094, 0xe9ffd909,
++    0xdc440086, 0xef944459, 0xba83ccb3, 0xe0c3cdfb,
++    0xd1da4181, 0x3b092ab1, 0xf997f1c1, 0xa5e6cf7b,
++    0x01420ddb, 0xe4e7ef5b, 0x25a1ff41, 0xe180f806,
++    0x1fc41080, 0x179bee7a, 0xd37ac6a9, 0xfe5830a4,
++    0x98de8b7f, 0x77e83f4e, 0x79929269, 0x24fa9f7b,
++    0xe113c85b, 0xacc40083, 0xd7503525, 0xf7ea615f,
++    0x62143154, 0x0d554b63, 0x5d681121, 0xc866c359,
++    0x3d63cf73, 0xcee234c0, 0xd4d87e87, 0x5c672b21,
++    0x071f6181, 0x39f7627f, 0x361e3084, 0xe4eb573b,
++    0x602f64a4, 0xd63acd9c, 0x1bbc4635, 0x9e81032d,
++    0x2701f50c, 0x99847ab4, 0xa0e3df79, 0xba6cf38c,
++    0x10843094, 0x2537a95e, 0xf46f6ffe, 0xa1ff3b1f,
++    0x208cfb6a, 0x8f458c74, 0xd9e0a227, 0x4ec73a34,
++    0xfc884f69, 0x3e4de8df, 0xef0e0088, 0x3559648d,
++    0x8a45388c, 0x1d804366, 0x721d9bfd, 0xa58684bb,
++    0xe8256333, 0x844e8212, 0x128d8098, 0xfed33fb4,
++    0xce280ae1, 0x27e19ba5, 0xd5a6c252, 0xe49754bd,
++    0xc5d655dd, 0xeb667064, 0x77840b4d, 0xa1b6a801,
++    0x84db26a9, 0xe0b56714, 0x21f043b7, 0xe5d05860,
++    0x54f03084, 0x066ff472, 0xa31aa153, 0xdadc4755,
++    0xb5625dbf, 0x68561be6, 0x83ca6b94, 0x2d6ed23b,
++    0xeccf01db, 0xa6d3d0ba, 0xb6803d5c, 0xaf77a709,
++    0x33b4a34c, 0x397bc8d6, 0x5ee22b95, 0x5f0e5304,
++    0x81ed6f61, 0x20e74364, 0xb45e1378, 0xde18639b,
++    0x881ca122, 0xb96726d1, 0x8049a7e8, 0x22b7da7b,
++    0x5e552d25, 0x5272d237, 0x79d2951c, 0xc60d894c,
++    0x488cb402, 0x1ba4fe5b, 0xa4b09f6b, 0x1ca815cf,
++    0xa20c3005, 0x8871df63, 0xb9de2fcb, 0x0cc6c9e9,
++    0x0beeff53, 0xe3214517, 0xb4542835, 0x9f63293c,
++    0xee41e729, 0x6e1d2d7c, 0x50045286, 0x1e6685f3,
++    0xf33401c6, 0x30a22c95, 0x31a70850, 0x60930f13,
++    0x73f98417, 0xa1269859, 0xec645c44, 0x52c877a9,
++    0xcdff33a6, 0xa02b1741, 0x7cbad9a2, 0x2180036f,
++    0x50d99c08, 0xcb3f4861, 0xc26bd765, 0x64a3f6ab,
++    0x80342676, 0x25a75e7b, 0xe4e6d1fc, 0x20c710e6,
++    0xcdf0b680, 0x17844d3b, 0x31eef84d, 0x7e0824e4,
++    0x2ccb49eb, 0x846a3bae, 0x8ff77888, 0xee5d60f6,
++    0x7af75673, 0x2fdd5cdb, 0xa11631c1, 0x30f66f43,
++    0xb3faec54, 0x157fd7fa, 0xef8579cc, 0xd152de58,
++    0xdb2ffd5e, 0x8f32ce19, 0x306af97a, 0x02f03ef8,
++    0x99319ad5, 0xc242fa0f, 0xa7e3ebb0, 0xc68e4906,
++    0xb8da230c, 0x80823028, 0xdcdef3c8, 0xd35fb171,
++    0x088a1bc8, 0xbec0c560, 0x61a3c9e8, 0xbca8f54d,
++    0xc72feffa, 0x22822e99, 0x82c570b4, 0xd8d94e89,
++    0x8b1c34bc, 0x301e16e6, 0x273be979, 0xb0ffeaa6,
++    0x61d9b8c6, 0x00b24869, 0xb7ffce3f, 0x08dc283b,
++    0x43daf65a, 0xf7e19798, 0x7619b72f, 0x8f1c9ba4,
++    0xdc8637a0, 0x16a7d3b1, 0x9fc393b7, 0xa7136eeb,
++    0xc6bcc63e, 0x1a513742, 0xef6828bc, 0x520365d6,
++    0x2d6a77ab, 0x3527ed4b, 0x821fd216, 0x095c6e2e,
++    0xdb92f2fb, 0x5eea29cb, 0x145892f5, 0x91584f7f,
++    0x5483697b, 0x2667a8cc, 0x85196048, 0x8c4bacea,
++    0x833860d4, 0x0d23e0f9, 0x6c387e8a, 0x0ae6d249,
++    0xb284600c, 0xd835731d, 0xdcb1c647, 0xac4c56ea,
++    0x3ebd81b3, 0x230eabb0, 0x6438bc87, 0xf0b5b1fa,
++    0x8f5ea2b3, 0xfc184642, 0x0a036b7a, 0x4fb089bd,
++    0x649da589, 0xa345415e, 0x5c038323, 0x3e5d3bb9,
++    0x43d79572, 0x7e6dd07c, 0x06dfdf1e, 0x6c6cc4ef,
++    0x7160a539, 0x73bfbe70, 0x83877605, 0x4523ecf1,
++};
++
++OPENSSL_GLOBAL const CAST_LONG CAST_S_table2[256] = {
++    0x8defc240, 0x25fa5d9f, 0xeb903dbf, 0xe810c907,
++    0x47607fff, 0x369fe44b, 0x8c1fc644, 0xaececa90,
++    0xbeb1f9bf, 0xeefbcaea, 0xe8cf1950, 0x51df07ae,
++    0x920e8806, 0xf0ad0548, 0xe13c8d83, 0x927010d5,
++    0x11107d9f, 0x07647db9, 0xb2e3e4d4, 0x3d4f285e,
++    0xb9afa820, 0xfade82e0, 0xa067268b, 0x8272792e,
++    0x553fb2c0, 0x489ae22b, 0xd4ef9794, 0x125e3fbc,
++    0x21fffcee, 0x825b1bfd, 0x9255c5ed, 0x1257a240,
++    0x4e1a8302, 0xbae07fff, 0x528246e7, 0x8e57140e,
++    0x3373f7bf, 0x8c9f8188, 0xa6fc4ee8, 0xc982b5a5,
++    0xa8c01db7, 0x579fc264, 0x67094f31, 0xf2bd3f5f,
++    0x40fff7c1, 0x1fb78dfc, 0x8e6bd2c1, 0x437be59b,
++    0x99b03dbf, 0xb5dbc64b, 0x638dc0e6, 0x55819d99,
++    0xa197c81c, 0x4a012d6e, 0xc5884a28, 0xccc36f71,
++    0xb843c213, 0x6c0743f1, 0x8309893c, 0x0feddd5f,
++    0x2f7fe850, 0xd7c07f7e, 0x02507fbf, 0x5afb9a04,
++    0xa747d2d0, 0x1651192e, 0xaf70bf3e, 0x58c31380,
++    0x5f98302e, 0x727cc3c4, 0x0a0fb402, 0x0f7fef82,
++    0x8c96fdad, 0x5d2c2aae, 0x8ee99a49, 0x50da88b8,
++    0x8427f4a0, 0x1eac5790, 0x796fb449, 0x8252dc15,
++    0xefbd7d9b, 0xa672597d, 0xada840d8, 0x45f54504,
++    0xfa5d7403, 0xe83ec305, 0x4f91751a, 0x925669c2,
++    0x23efe941, 0xa903f12e, 0x60270df2, 0x0276e4b6,
++    0x94fd6574, 0x927985b2, 0x8276dbcb, 0x02778176,
++    0xf8af918d, 0x4e48f79e, 0x8f616ddf, 0xe29d840e,
++    0x842f7d83, 0x340ce5c8, 0x96bbb682, 0x93b4b148,
++    0xef303cab, 0x984faf28, 0x779faf9b, 0x92dc560d,
++    0x224d1e20, 0x8437aa88, 0x7d29dc96, 0x2756d3dc,
++    0x8b907cee, 0xb51fd240, 0xe7c07ce3, 0xe566b4a1,
++    0xc3e9615e, 0x3cf8209d, 0x6094d1e3, 0xcd9ca341,
++    0x5c76460e, 0x00ea983b, 0xd4d67881, 0xfd47572c,
++    0xf76cedd9, 0xbda8229c, 0x127dadaa, 0x438a074e,
++    0x1f97c090, 0x081bdb8a, 0x93a07ebe, 0xb938ca15,
++    0x97b03cff, 0x3dc2c0f8, 0x8d1ab2ec, 0x64380e51,
++    0x68cc7bfb, 0xd90f2788, 0x12490181, 0x5de5ffd4,
++    0xdd7ef86a, 0x76a2e214, 0xb9a40368, 0x925d958f,
++    0x4b39fffa, 0xba39aee9, 0xa4ffd30b, 0xfaf7933b,
++    0x6d498623, 0x193cbcfa, 0x27627545, 0x825cf47a,
++    0x61bd8ba0, 0xd11e42d1, 0xcead04f4, 0x127ea392,
++    0x10428db7, 0x8272a972, 0x9270c4a8, 0x127de50b,
++    0x285ba1c8, 0x3c62f44f, 0x35c0eaa5, 0xe805d231,
++    0x428929fb, 0xb4fcdf82, 0x4fb66a53, 0x0e7dc15b,
++    0x1f081fab, 0x108618ae, 0xfcfd086d, 0xf9ff2889,
++    0x694bcc11, 0x236a5cae, 0x12deca4d, 0x2c3f8cc5,
++    0xd2d02dfe, 0xf8ef5896, 0xe4cf52da, 0x95155b67,
++    0x494a488c, 0xb9b6a80c, 0x5c8f82bc, 0x89d36b45,
++    0x3a609437, 0xec00c9a9, 0x44715253, 0x0a874b49,
++    0xd773bc40, 0x7c34671c, 0x02717ef6, 0x4feb5536,
++    0xa2d02fff, 0xd2bf60c4, 0xd43f03c0, 0x50b4ef6d,
++    0x07478cd1, 0x006e1888, 0xa2e53f55, 0xb9e6d4bc,
++    0xa2048016, 0x97573833, 0xd7207d67, 0xde0f8f3d,
++    0x72f87b33, 0xabcc4f33, 0x7688c55d, 0x7b00a6b0,
++    0x947b0001, 0x570075d2, 0xf9bb88f8, 0x8942019e,
++    0x4264a5ff, 0x856302e0, 0x72dbd92b, 0xee971b69,
++    0x6ea22fde, 0x5f08ae2b, 0xaf7a616d, 0xe5c98767,
++    0xcf1febd2, 0x61efc8c2, 0xf1ac2571, 0xcc8239c2,
++    0x67214cb8, 0xb1e583d1, 0xb7dc3e62, 0x7f10bdce,
++    0xf90a5c38, 0x0ff0443d, 0x606e6dc6, 0x60543a49,
++    0x5727c148, 0x2be98a1d, 0x8ab41738, 0x20e1be24,
++    0xaf96da0f, 0x68458425, 0x99833be5, 0x600d457d,
++    0x282f9350, 0x8334b362, 0xd91d1120, 0x2b6d8da0,
++    0x642b1e31, 0x9c305a00, 0x52bce688, 0x1b03588a,
++    0xf7baefd5, 0x4142ed9c, 0xa4315c11, 0x83323ec5,
++    0xdfef4636, 0xa133c501, 0xe9d3531c, 0xee353783,
++};
++
++OPENSSL_GLOBAL const CAST_LONG CAST_S_table3[256] = {
++    0x9db30420, 0x1fb6e9de, 0xa7be7bef, 0xd273a298,
++    0x4a4f7bdb, 0x64ad8c57, 0x85510443, 0xfa020ed1,
++    0x7e287aff, 0xe60fb663, 0x095f35a1, 0x79ebf120,
++    0xfd059d43, 0x6497b7b1, 0xf3641f63, 0x241e4adf,
++    0x28147f5f, 0x4fa2b8cd, 0xc9430040, 0x0cc32220,
++    0xfdd30b30, 0xc0a5374f, 0x1d2d00d9, 0x24147b15,
++    0xee4d111a, 0x0fca5167, 0x71ff904c, 0x2d195ffe,
++    0x1a05645f, 0x0c13fefe, 0x081b08ca, 0x05170121,
++    0x80530100, 0xe83e5efe, 0xac9af4f8, 0x7fe72701,
++    0xd2b8ee5f, 0x06df4261, 0xbb9e9b8a, 0x7293ea25,
++    0xce84ffdf, 0xf5718801, 0x3dd64b04, 0xa26f263b,
++    0x7ed48400, 0x547eebe6, 0x446d4ca0, 0x6cf3d6f5,
++    0x2649abdf, 0xaea0c7f5, 0x36338cc1, 0x503f7e93,
++    0xd3772061, 0x11b638e1, 0x72500e03, 0xf80eb2bb,
++    0xabe0502e, 0xec8d77de, 0x57971e81, 0xe14f6746,
++    0xc9335400, 0x6920318f, 0x081dbb99, 0xffc304a5,
++    0x4d351805, 0x7f3d5ce3, 0xa6c866c6, 0x5d5bcca9,
++    0xdaec6fea, 0x9f926f91, 0x9f46222f, 0x3991467d,
++    0xa5bf6d8e, 0x1143c44f, 0x43958302, 0xd0214eeb,
++    0x022083b8, 0x3fb6180c, 0x18f8931e, 0x281658e6,
++    0x26486e3e, 0x8bd78a70, 0x7477e4c1, 0xb506e07c,
++    0xf32d0a25, 0x79098b02, 0xe4eabb81, 0x28123b23,
++    0x69dead38, 0x1574ca16, 0xdf871b62, 0x211c40b7,
++    0xa51a9ef9, 0x0014377b, 0x041e8ac8, 0x09114003,
++    0xbd59e4d2, 0xe3d156d5, 0x4fe876d5, 0x2f91a340,
++    0x557be8de, 0x00eae4a7, 0x0ce5c2ec, 0x4db4bba6,
++    0xe756bdff, 0xdd3369ac, 0xec17b035, 0x06572327,
++    0x99afc8b0, 0x56c8c391, 0x6b65811c, 0x5e146119,
++    0x6e85cb75, 0xbe07c002, 0xc2325577, 0x893ff4ec,
++    0x5bbfc92d, 0xd0ec3b25, 0xb7801ab7, 0x8d6d3b24,
++    0x20c763ef, 0xc366a5fc, 0x9c382880, 0x0ace3205,
++    0xaac9548a, 0xeca1d7c7, 0x041afa32, 0x1d16625a,
++    0x6701902c, 0x9b757a54, 0x31d477f7, 0x9126b031,
++    0x36cc6fdb, 0xc70b8b46, 0xd9e66a48, 0x56e55a79,
++    0x026a4ceb, 0x52437eff, 0x2f8f76b4, 0x0df980a5,
++    0x8674cde3, 0xedda04eb, 0x17a9be04, 0x2c18f4df,
++    0xb7747f9d, 0xab2af7b4, 0xefc34d20, 0x2e096b7c,
++    0x1741a254, 0xe5b6a035, 0x213d42f6, 0x2c1c7c26,
++    0x61c2f50f, 0x6552daf9, 0xd2c231f8, 0x25130f69,
++    0xd8167fa2, 0x0418f2c8, 0x001a96a6, 0x0d1526ab,
++    0x63315c21, 0x5e0a72ec, 0x49bafefd, 0x187908d9,
++    0x8d0dbd86, 0x311170a7, 0x3e9b640c, 0xcc3e10d7,
++    0xd5cad3b6, 0x0caec388, 0xf73001e1, 0x6c728aff,
++    0x71eae2a1, 0x1f9af36e, 0xcfcbd12f, 0xc1de8417,
++    0xac07be6b, 0xcb44a1d8, 0x8b9b0f56, 0x013988c3,
++    0xb1c52fca, 0xb4be31cd, 0xd8782806, 0x12a3a4e2,
++    0x6f7de532, 0x58fd7eb6, 0xd01ee900, 0x24adffc2,
++    0xf4990fc5, 0x9711aac5, 0x001d7b95, 0x82e5e7d2,
++    0x109873f6, 0x00613096, 0xc32d9521, 0xada121ff,
++    0x29908415, 0x7fbb977f, 0xaf9eb3db, 0x29c9ed2a,
++    0x5ce2a465, 0xa730f32c, 0xd0aa3fe8, 0x8a5cc091,
++    0xd49e2ce7, 0x0ce454a9, 0xd60acd86, 0x015f1919,
++    0x77079103, 0xdea03af6, 0x78a8565e, 0xdee356df,
++    0x21f05cbe, 0x8b75e387, 0xb3c50651, 0xb8a5c3ef,
++    0xd8eeb6d2, 0xe523be77, 0xc2154529, 0x2f69efdf,
++    0xafe67afb, 0xf470c4b2, 0xf3e0eb5b, 0xd6cc9876,
++    0x39e4460c, 0x1fda8538, 0x1987832f, 0xca007367,
++    0xa99144f8, 0x296b299e, 0x492fc295, 0x9266beab,
++    0xb5676e69, 0x9bd3ddda, 0xdf7e052f, 0xdb25701c,
++    0x1b5e51ee, 0xf65324e6, 0x6afce36c, 0x0316cc04,
++    0x8644213e, 0xb7dc59d0, 0x7965291f, 0xccd6fd43,
++    0x41823979, 0x932bcdf6, 0xb657c34d, 0x4edfd282,
++    0x7ae5290c, 0x3cb9536b, 0x851e20fe, 0x9833557e,
++    0x13ecf0b0, 0xd3ffb372, 0x3f85c5c1, 0x0aef7ed2,
++};
++
++OPENSSL_GLOBAL const CAST_LONG CAST_S_table4[256] = {
++    0x7ec90c04, 0x2c6e74b9, 0x9b0e66df, 0xa6337911,
++    0xb86a7fff, 0x1dd358f5, 0x44dd9d44, 0x1731167f,
++    0x08fbf1fa, 0xe7f511cc, 0xd2051b00, 0x735aba00,
++    0x2ab722d8, 0x386381cb, 0xacf6243a, 0x69befd7a,
++    0xe6a2e77f, 0xf0c720cd, 0xc4494816, 0xccf5c180,
++    0x38851640, 0x15b0a848, 0xe68b18cb, 0x4caadeff,
++    0x5f480a01, 0x0412b2aa, 0x259814fc, 0x41d0efe2,
++    0x4e40b48d, 0x248eb6fb, 0x8dba1cfe, 0x41a99b02,
++    0x1a550a04, 0xba8f65cb, 0x7251f4e7, 0x95a51725,
++    0xc106ecd7, 0x97a5980a, 0xc539b9aa, 0x4d79fe6a,
++    0xf2f3f763, 0x68af8040, 0xed0c9e56, 0x11b4958b,
++    0xe1eb5a88, 0x8709e6b0, 0xd7e07156, 0x4e29fea7,
++    0x6366e52d, 0x02d1c000, 0xc4ac8e05, 0x9377f571,
++    0x0c05372a, 0x578535f2, 0x2261be02, 0xd642a0c9,
++    0xdf13a280, 0x74b55bd2, 0x682199c0, 0xd421e5ec,
++    0x53fb3ce8, 0xc8adedb3, 0x28a87fc9, 0x3d959981,
++    0x5c1ff900, 0xfe38d399, 0x0c4eff0b, 0x062407ea,
++    0xaa2f4fb1, 0x4fb96976, 0x90c79505, 0xb0a8a774,
++    0xef55a1ff, 0xe59ca2c2, 0xa6b62d27, 0xe66a4263,
++    0xdf65001f, 0x0ec50966, 0xdfdd55bc, 0x29de0655,
++    0x911e739a, 0x17af8975, 0x32c7911c, 0x89f89468,
++    0x0d01e980, 0x524755f4, 0x03b63cc9, 0x0cc844b2,
++    0xbcf3f0aa, 0x87ac36e9, 0xe53a7426, 0x01b3d82b,
++    0x1a9e7449, 0x64ee2d7e, 0xcddbb1da, 0x01c94910,
++    0xb868bf80, 0x0d26f3fd, 0x9342ede7, 0x04a5c284,
++    0x636737b6, 0x50f5b616, 0xf24766e3, 0x8eca36c1,
++    0x136e05db, 0xfef18391, 0xfb887a37, 0xd6e7f7d4,
++    0xc7fb7dc9, 0x3063fcdf, 0xb6f589de, 0xec2941da,
++    0x26e46695, 0xb7566419, 0xf654efc5, 0xd08d58b7,
++    0x48925401, 0xc1bacb7f, 0xe5ff550f, 0xb6083049,
++    0x5bb5d0e8, 0x87d72e5a, 0xab6a6ee1, 0x223a66ce,
++    0xc62bf3cd, 0x9e0885f9, 0x68cb3e47, 0x086c010f,
++    0xa21de820, 0xd18b69de, 0xf3f65777, 0xfa02c3f6,
++    0x407edac3, 0xcbb3d550, 0x1793084d, 0xb0d70eba,
++    0x0ab378d5, 0xd951fb0c, 0xded7da56, 0x4124bbe4,
++    0x94ca0b56, 0x0f5755d1, 0xe0e1e56e, 0x6184b5be,
++    0x580a249f, 0x94f74bc0, 0xe327888e, 0x9f7b5561,
++    0xc3dc0280, 0x05687715, 0x646c6bd7, 0x44904db3,
++    0x66b4f0a3, 0xc0f1648a, 0x697ed5af, 0x49e92ff6,
++    0x309e374f, 0x2cb6356a, 0x85808573, 0x4991f840,
++    0x76f0ae02, 0x083be84d, 0x28421c9a, 0x44489406,
++    0x736e4cb8, 0xc1092910, 0x8bc95fc6, 0x7d869cf4,
++    0x134f616f, 0x2e77118d, 0xb31b2be1, 0xaa90b472,
++    0x3ca5d717, 0x7d161bba, 0x9cad9010, 0xaf462ba2,
++    0x9fe459d2, 0x45d34559, 0xd9f2da13, 0xdbc65487,
++    0xf3e4f94e, 0x176d486f, 0x097c13ea, 0x631da5c7,
++    0x445f7382, 0x175683f4, 0xcdc66a97, 0x70be0288,
++    0xb3cdcf72, 0x6e5dd2f3, 0x20936079, 0x459b80a5,
++    0xbe60e2db, 0xa9c23101, 0xeba5315c, 0x224e42f2,
++    0x1c5c1572, 0xf6721b2c, 0x1ad2fff3, 0x8c25404e,
++    0x324ed72f, 0x4067b7fd, 0x0523138e, 0x5ca3bc78,
++    0xdc0fd66e, 0x75922283, 0x784d6b17, 0x58ebb16e,
++    0x44094f85, 0x3f481d87, 0xfcfeae7b, 0x77b5ff76,
++    0x8c2302bf, 0xaaf47556, 0x5f46b02a, 0x2b092801,
++    0x3d38f5f7, 0x0ca81f36, 0x52af4a8a, 0x66d5e7c0,
++    0xdf3b0874, 0x95055110, 0x1b5ad7a8, 0xf61ed5ad,
++    0x6cf6e479, 0x20758184, 0xd0cefa65, 0x88f7be58,
++    0x4a046826, 0x0ff6f8f3, 0xa09c7f70, 0x5346aba0,
++    0x5ce96c28, 0xe176eda3, 0x6bac307f, 0x376829d2,
++    0x85360fa9, 0x17e3fe2a, 0x24b79767, 0xf5a96b20,
++    0xd6cd2595, 0x68ff1ebf, 0x7555442c, 0xf19f06be,
++    0xf9e0659a, 0xeeb9491d, 0x34010718, 0xbb30cab8,
++    0xe822fe15, 0x88570983, 0x750e6249, 0xda627e55,
++    0x5e76ffa8, 0xb1534546, 0x6d47de08, 0xefe9e7d4,
++};
++
++OPENSSL_GLOBAL const CAST_LONG CAST_S_table5[256] = {
++    0xf6fa8f9d, 0x2cac6ce1, 0x4ca34867, 0xe2337f7c,
++    0x95db08e7, 0x016843b4, 0xeced5cbc, 0x325553ac,
++    0xbf9f0960, 0xdfa1e2ed, 0x83f0579d, 0x63ed86b9,
++    0x1ab6a6b8, 0xde5ebe39, 0xf38ff732, 0x8989b138,
++    0x33f14961, 0xc01937bd, 0xf506c6da, 0xe4625e7e,
++    0xa308ea99, 0x4e23e33c, 0x79cbd7cc, 0x48a14367,
++    0xa3149619, 0xfec94bd5, 0xa114174a, 0xeaa01866,
++    0xa084db2d, 0x09a8486f, 0xa888614a, 0x2900af98,
++    0x01665991, 0xe1992863, 0xc8f30c60, 0x2e78ef3c,
++    0xd0d51932, 0xcf0fec14, 0xf7ca07d2, 0xd0a82072,
++    0xfd41197e, 0x9305a6b0, 0xe86be3da, 0x74bed3cd,
++    0x372da53c, 0x4c7f4448, 0xdab5d440, 0x6dba0ec3,
++    0x083919a7, 0x9fbaeed9, 0x49dbcfb0, 0x4e670c53,
++    0x5c3d9c01, 0x64bdb941, 0x2c0e636a, 0xba7dd9cd,
++    0xea6f7388, 0xe70bc762, 0x35f29adb, 0x5c4cdd8d,
++    0xf0d48d8c, 0xb88153e2, 0x08a19866, 0x1ae2eac8,
++    0x284caf89, 0xaa928223, 0x9334be53, 0x3b3a21bf,
++    0x16434be3, 0x9aea3906, 0xefe8c36e, 0xf890cdd9,
++    0x80226dae, 0xc340a4a3, 0xdf7e9c09, 0xa694a807,
++    0x5b7c5ecc, 0x221db3a6, 0x9a69a02f, 0x68818a54,
++    0xceb2296f, 0x53c0843a, 0xfe893655, 0x25bfe68a,
++    0xb4628abc, 0xcf222ebf, 0x25ac6f48, 0xa9a99387,
++    0x53bddb65, 0xe76ffbe7, 0xe967fd78, 0x0ba93563,
++    0x8e342bc1, 0xe8a11be9, 0x4980740d, 0xc8087dfc,
++    0x8de4bf99, 0xa11101a0, 0x7fd37975, 0xda5a26c0,
++    0xe81f994f, 0x9528cd89, 0xfd339fed, 0xb87834bf,
++    0x5f04456d, 0x22258698, 0xc9c4c83b, 0x2dc156be,
++    0x4f628daa, 0x57f55ec5, 0xe2220abe, 0xd2916ebf,
++    0x4ec75b95, 0x24f2c3c0, 0x42d15d99, 0xcd0d7fa0,
++    0x7b6e27ff, 0xa8dc8af0, 0x7345c106, 0xf41e232f,
++    0x35162386, 0xe6ea8926, 0x3333b094, 0x157ec6f2,
++    0x372b74af, 0x692573e4, 0xe9a9d848, 0xf3160289,
++    0x3a62ef1d, 0xa787e238, 0xf3a5f676, 0x74364853,
++    0x20951063, 0x4576698d, 0xb6fad407, 0x592af950,
++    0x36f73523, 0x4cfb6e87, 0x7da4cec0, 0x6c152daa,
++    0xcb0396a8, 0xc50dfe5d, 0xfcd707ab, 0x0921c42f,
++    0x89dff0bb, 0x5fe2be78, 0x448f4f33, 0x754613c9,
++    0x2b05d08d, 0x48b9d585, 0xdc049441, 0xc8098f9b,
++    0x7dede786, 0xc39a3373, 0x42410005, 0x6a091751,
++    0x0ef3c8a6, 0x890072d6, 0x28207682, 0xa9a9f7be,
++    0xbf32679d, 0xd45b5b75, 0xb353fd00, 0xcbb0e358,
++    0x830f220a, 0x1f8fb214, 0xd372cf08, 0xcc3c4a13,
++    0x8cf63166, 0x061c87be, 0x88c98f88, 0x6062e397,
++    0x47cf8e7a, 0xb6c85283, 0x3cc2acfb, 0x3fc06976,
++    0x4e8f0252, 0x64d8314d, 0xda3870e3, 0x1e665459,
++    0xc10908f0, 0x513021a5, 0x6c5b68b7, 0x822f8aa0,
++    0x3007cd3e, 0x74719eef, 0xdc872681, 0x073340d4,
++    0x7e432fd9, 0x0c5ec241, 0x8809286c, 0xf592d891,
++    0x08a930f6, 0x957ef305, 0xb7fbffbd, 0xc266e96f,
++    0x6fe4ac98, 0xb173ecc0, 0xbc60b42a, 0x953498da,
++    0xfba1ae12, 0x2d4bd736, 0x0f25faab, 0xa4f3fceb,
++    0xe2969123, 0x257f0c3d, 0x9348af49, 0x361400bc,
++    0xe8816f4a, 0x3814f200, 0xa3f94043, 0x9c7a54c2,
++    0xbc704f57, 0xda41e7f9, 0xc25ad33a, 0x54f4a084,
++    0xb17f5505, 0x59357cbe, 0xedbd15c8, 0x7f97c5ab,
++    0xba5ac7b5, 0xb6f6deaf, 0x3a479c3a, 0x5302da25,
++    0x653d7e6a, 0x54268d49, 0x51a477ea, 0x5017d55b,
++    0xd7d25d88, 0x44136c76, 0x0404a8c8, 0xb8e5a121,
++    0xb81a928a, 0x60ed5869, 0x97c55b96, 0xeaec991b,
++    0x29935913, 0x01fdb7f1, 0x088e8dfa, 0x9ab6f6f5,
++    0x3b4cbf9f, 0x4a5de3ab, 0xe6051d35, 0xa0e1d855,
++    0xd36b4cf1, 0xf544edeb, 0xb0e93524, 0xbebb8fbd,
++    0xa2d762cf, 0x49c92f54, 0x38b5f331, 0x7128a454,
++    0x48392905, 0xa65b1db8, 0x851c97bd, 0xd675cf2f,
++};
++
++OPENSSL_GLOBAL const CAST_LONG CAST_S_table6[256] = {
++    0x85e04019, 0x332bf567, 0x662dbfff, 0xcfc65693,
++    0x2a8d7f6f, 0xab9bc912, 0xde6008a1, 0x2028da1f,
++    0x0227bce7, 0x4d642916, 0x18fac300, 0x50f18b82,
++    0x2cb2cb11, 0xb232e75c, 0x4b3695f2, 0xb28707de,
++    0xa05fbcf6, 0xcd4181e9, 0xe150210c, 0xe24ef1bd,
++    0xb168c381, 0xfde4e789, 0x5c79b0d8, 0x1e8bfd43,
++    0x4d495001, 0x38be4341, 0x913cee1d, 0x92a79c3f,
++    0x089766be, 0xbaeeadf4, 0x1286becf, 0xb6eacb19,
++    0x2660c200, 0x7565bde4, 0x64241f7a, 0x8248dca9,
++    0xc3b3ad66, 0x28136086, 0x0bd8dfa8, 0x356d1cf2,
++    0x107789be, 0xb3b2e9ce, 0x0502aa8f, 0x0bc0351e,
++    0x166bf52a, 0xeb12ff82, 0xe3486911, 0xd34d7516,
++    0x4e7b3aff, 0x5f43671b, 0x9cf6e037, 0x4981ac83,
++    0x334266ce, 0x8c9341b7, 0xd0d854c0, 0xcb3a6c88,
++    0x47bc2829, 0x4725ba37, 0xa66ad22b, 0x7ad61f1e,
++    0x0c5cbafa, 0x4437f107, 0xb6e79962, 0x42d2d816,
++    0x0a961288, 0xe1a5c06e, 0x13749e67, 0x72fc081a,
++    0xb1d139f7, 0xf9583745, 0xcf19df58, 0xbec3f756,
++    0xc06eba30, 0x07211b24, 0x45c28829, 0xc95e317f,
++    0xbc8ec511, 0x38bc46e9, 0xc6e6fa14, 0xbae8584a,
++    0xad4ebc46, 0x468f508b, 0x7829435f, 0xf124183b,
++    0x821dba9f, 0xaff60ff4, 0xea2c4e6d, 0x16e39264,
++    0x92544a8b, 0x009b4fc3, 0xaba68ced, 0x9ac96f78,
++    0x06a5b79a, 0xb2856e6e, 0x1aec3ca9, 0xbe838688,
++    0x0e0804e9, 0x55f1be56, 0xe7e5363b, 0xb3a1f25d,
++    0xf7debb85, 0x61fe033c, 0x16746233, 0x3c034c28,
++    0xda6d0c74, 0x79aac56c, 0x3ce4e1ad, 0x51f0c802,
++    0x98f8f35a, 0x1626a49f, 0xeed82b29, 0x1d382fe3,
++    0x0c4fb99a, 0xbb325778, 0x3ec6d97b, 0x6e77a6a9,
++    0xcb658b5c, 0xd45230c7, 0x2bd1408b, 0x60c03eb7,
++    0xb9068d78, 0xa33754f4, 0xf430c87d, 0xc8a71302,
++    0xb96d8c32, 0xebd4e7be, 0xbe8b9d2d, 0x7979fb06,
++    0xe7225308, 0x8b75cf77, 0x11ef8da4, 0xe083c858,
++    0x8d6b786f, 0x5a6317a6, 0xfa5cf7a0, 0x5dda0033,
++    0xf28ebfb0, 0xf5b9c310, 0xa0eac280, 0x08b9767a,
++    0xa3d9d2b0, 0x79d34217, 0x021a718d, 0x9ac6336a,
++    0x2711fd60, 0x438050e3, 0x069908a8, 0x3d7fedc4,
++    0x826d2bef, 0x4eeb8476, 0x488dcf25, 0x36c9d566,
++    0x28e74e41, 0xc2610aca, 0x3d49a9cf, 0xbae3b9df,
++    0xb65f8de6, 0x92aeaf64, 0x3ac7d5e6, 0x9ea80509,
++    0xf22b017d, 0xa4173f70, 0xdd1e16c3, 0x15e0d7f9,
++    0x50b1b887, 0x2b9f4fd5, 0x625aba82, 0x6a017962,
++    0x2ec01b9c, 0x15488aa9, 0xd716e740, 0x40055a2c,
++    0x93d29a22, 0xe32dbf9a, 0x058745b9, 0x3453dc1e,
++    0xd699296e, 0x496cff6f, 0x1c9f4986, 0xdfe2ed07,
++    0xb87242d1, 0x19de7eae, 0x053e561a, 0x15ad6f8c,
++    0x66626c1c, 0x7154c24c, 0xea082b2a, 0x93eb2939,
++    0x17dcb0f0, 0x58d4f2ae, 0x9ea294fb, 0x52cf564c,
++    0x9883fe66, 0x2ec40581, 0x763953c3, 0x01d6692e,
++    0xd3a0c108, 0xa1e7160e, 0xe4f2dfa6, 0x693ed285,
++    0x74904698, 0x4c2b0edd, 0x4f757656, 0x5d393378,
++    0xa132234f, 0x3d321c5d, 0xc3f5e194, 0x4b269301,
++    0xc79f022f, 0x3c997e7e, 0x5e4f9504, 0x3ffafbbd,
++    0x76f7ad0e, 0x296693f4, 0x3d1fce6f, 0xc61e45be,
++    0xd3b5ab34, 0xf72bf9b7, 0x1b0434c0, 0x4e72b567,
++    0x5592a33d, 0xb5229301, 0xcfd2a87f, 0x60aeb767,
++    0x1814386b, 0x30bcc33d, 0x38a0c07d, 0xfd1606f2,
++    0xc363519b, 0x589dd390, 0x5479f8e6, 0x1cb8d647,
++    0x97fd61a9, 0xea7759f4, 0x2d57539d, 0x569a58cf,
++    0xe84e63ad, 0x462e1b78, 0x6580f87e, 0xf3817914,
++    0x91da55f4, 0x40a230f3, 0xd1988f35, 0xb6e318d2,
++    0x3ffa50bc, 0x3d40f021, 0xc3c0bdae, 0x4958c24c,
++    0x518f36b2, 0x84b1d370, 0x0fedce83, 0x878ddada,
++    0xf2a279c7, 0x94e01be8, 0x90716f4b, 0x954b8aa3,
++};
++
++OPENSSL_GLOBAL const CAST_LONG CAST_S_table7[256] = {
++    0xe216300d, 0xbbddfffc, 0xa7ebdabd, 0x35648095,
++    0x7789f8b7, 0xe6c1121b, 0x0e241600, 0x052ce8b5,
++    0x11a9cfb0, 0xe5952f11, 0xece7990a, 0x9386d174,
++    0x2a42931c, 0x76e38111, 0xb12def3a, 0x37ddddfc,
++    0xde9adeb1, 0x0a0cc32c, 0xbe197029, 0x84a00940,
++    0xbb243a0f, 0xb4d137cf, 0xb44e79f0, 0x049eedfd,
++    0x0b15a15d, 0x480d3168, 0x8bbbde5a, 0x669ded42,
++    0xc7ece831, 0x3f8f95e7, 0x72df191b, 0x7580330d,
++    0x94074251, 0x5c7dcdfa, 0xabbe6d63, 0xaa402164,
++    0xb301d40a, 0x02e7d1ca, 0x53571dae, 0x7a3182a2,
++    0x12a8ddec, 0xfdaa335d, 0x176f43e8, 0x71fb46d4,
++    0x38129022, 0xce949ad4, 0xb84769ad, 0x965bd862,
++    0x82f3d055, 0x66fb9767, 0x15b80b4e, 0x1d5b47a0,
++    0x4cfde06f, 0xc28ec4b8, 0x57e8726e, 0x647a78fc,
++    0x99865d44, 0x608bd593, 0x6c200e03, 0x39dc5ff6,
++    0x5d0b00a3, 0xae63aff2, 0x7e8bd632, 0x70108c0c,
++    0xbbd35049, 0x2998df04, 0x980cf42a, 0x9b6df491,
++    0x9e7edd53, 0x06918548, 0x58cb7e07, 0x3b74ef2e,
++    0x522fffb1, 0xd24708cc, 0x1c7e27cd, 0xa4eb215b,
++    0x3cf1d2e2, 0x19b47a38, 0x424f7618, 0x35856039,
++    0x9d17dee7, 0x27eb35e6, 0xc9aff67b, 0x36baf5b8,
++    0x09c467cd, 0xc18910b1, 0xe11dbf7b, 0x06cd1af8,
++    0x7170c608, 0x2d5e3354, 0xd4de495a, 0x64c6d006,
++    0xbcc0c62c, 0x3dd00db3, 0x708f8f34, 0x77d51b42,
++    0x264f620f, 0x24b8d2bf, 0x15c1b79e, 0x46a52564,
++    0xf8d7e54e, 0x3e378160, 0x7895cda5, 0x859c15a5,
++    0xe6459788, 0xc37bc75f, 0xdb07ba0c, 0x0676a3ab,
++    0x7f229b1e, 0x31842e7b, 0x24259fd7, 0xf8bef472,
++    0x835ffcb8, 0x6df4c1f2, 0x96f5b195, 0xfd0af0fc,
++    0xb0fe134c, 0xe2506d3d, 0x4f9b12ea, 0xf215f225,
++    0xa223736f, 0x9fb4c428, 0x25d04979, 0x34c713f8,
++    0xc4618187, 0xea7a6e98, 0x7cd16efc, 0x1436876c,
++    0xf1544107, 0xbedeee14, 0x56e9af27, 0xa04aa441,
++    0x3cf7c899, 0x92ecbae6, 0xdd67016d, 0x151682eb,
++    0xa842eedf, 0xfdba60b4, 0xf1907b75, 0x20e3030f,
++    0x24d8c29e, 0xe139673b, 0xefa63fb8, 0x71873054,
++    0xb6f2cf3b, 0x9f326442, 0xcb15a4cc, 0xb01a4504,
++    0xf1e47d8d, 0x844a1be5, 0xbae7dfdc, 0x42cbda70,
++    0xcd7dae0a, 0x57e85b7a, 0xd53f5af6, 0x20cf4d8c,
++    0xcea4d428, 0x79d130a4, 0x3486ebfb, 0x33d3cddc,
++    0x77853b53, 0x37effcb5, 0xc5068778, 0xe580b3e6,
++    0x4e68b8f4, 0xc5c8b37e, 0x0d809ea2, 0x398feb7c,
++    0x132a4f94, 0x43b7950e, 0x2fee7d1c, 0x223613bd,
++    0xdd06caa2, 0x37df932b, 0xc4248289, 0xacf3ebc3,
++    0x5715f6b7, 0xef3478dd, 0xf267616f, 0xc148cbe4,
++    0x9052815e, 0x5e410fab, 0xb48a2465, 0x2eda7fa4,
++    0xe87b40e4, 0xe98ea084, 0x5889e9e1, 0xefd390fc,
++    0xdd07d35b, 0xdb485694, 0x38d7e5b2, 0x57720101,
++    0x730edebc, 0x5b643113, 0x94917e4f, 0x503c2fba,
++    0x646f1282, 0x7523d24a, 0xe0779695, 0xf9c17a8f,
++    0x7a5b2121, 0xd187b896, 0x29263a4d, 0xba510cdf,
++    0x81f47c9f, 0xad1163ed, 0xea7b5965, 0x1a00726e,
++    0x11403092, 0x00da6d77, 0x4a0cdd61, 0xad1f4603,
++    0x605bdfb0, 0x9eedc364, 0x22ebe6a8, 0xcee7d28a,
++    0xa0e736a0, 0x5564a6b9, 0x10853209, 0xc7eb8f37,
++    0x2de705ca, 0x8951570f, 0xdf09822b, 0xbd691a6c,
++    0xaa12e4f2, 0x87451c0f, 0xe0f6a27a, 0x3ada4819,
++    0x4cf1764f, 0x0d771c2b, 0x67cdb156, 0x350d8384,
++    0x5938fa0f, 0x42399ef3, 0x36997b07, 0x0e84093d,
++    0x4aa93e61, 0x8360d87b, 0x1fa98b0c, 0x1149382c,
++    0xe97625a5, 0x0614d1b7, 0x0e25244b, 0x0c768347,
++    0x589e8d82, 0x0d2059d1, 0xa466bb1e, 0xf8da0a82,
++    0x04f19130, 0xba6e4ec0, 0x99265164, 0x1ee7230d,
++    0x50b2ad80, 0xeaee6801, 0x8db2a283, 0xea8bf59e,
++};
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/chacha/asm/chacha-armv4.pl b/CryptoPkg/Library/OpensslLib/openssl/crypto/chacha/asm/chacha-armv4.pl
+new file mode 100755
+index 0000000..b5e21e4
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/chacha/asm/chacha-armv4.pl
+@@ -0,0 +1,1158 @@
++#! /usr/bin/env perl
++# Copyright 2016 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
++# in the file LICENSE in the source distribution or at
++# https://www.openssl.org/source/license.html
++
++#
++# ====================================================================
++# Written by Andy Polyakov  for the OpenSSL
++# project. The module is, however, dual licensed under OpenSSL and
++# CRYPTOGAMS licenses depending on where you obtain it. For further
++# details see http://www.openssl.org/~appro/cryptogams/.
++# ====================================================================
++#
++# December 2014
++# 
++# ChaCha20 for ARMv4.
++#
++# Performance in cycles per byte out of large buffer.
++#
++#			IALU/gcc-4.4    1xNEON      3xNEON+1xIALU
++#
++# Cortex-A5		19.3(*)/+95%    21.8        14.1
++# Cortex-A8		10.5(*)/+160%   13.9        6.35
++# Cortex-A9		12.9(**)/+110%  14.3        6.50
++# Cortex-A15		11.0/+40%       16.0        5.00
++# Snapdragon S4		11.5/+125%      13.6        4.90
++#
++# (*)	most "favourable" result for aligned data on little-endian
++#	processor, result for misaligned data is 10-15% lower;
++# (**)	this result is a trade-off: it can be improved by 20%,
++#	but then Snapdragon S4 and Cortex-A8 results get
++#	20-25% worse;
++
++$flavour = shift;
++if ($flavour=~/\w[\w\-]*\.\w+$/) { $output=$flavour; undef $flavour; }
++else { while (($output=shift) && ($output!~/\w[\w\-]*\.\w+$/)) {} }
++
++if ($flavour && $flavour ne "void") {
++    $0 =~ m/(.*[\/\\])[^\/\\]+$/; $dir=$1;
++    ( $xlate="${dir}arm-xlate.pl" and -f $xlate ) or
++    ( $xlate="${dir}../../perlasm/arm-xlate.pl" and -f $xlate) or
++    die "can't locate arm-xlate.pl";
++
++    open STDOUT,"| \"$^X\" $xlate $flavour $output";
++} else {
++    open STDOUT,">$output";
++}
++
++sub AUTOLOAD()		# thunk [simplified] x86-style perlasm
++{ my $opcode = $AUTOLOAD; $opcode =~ s/.*:://; $opcode =~ s/_/\./;
++  my $arg = pop;
++    $arg = "#$arg" if ($arg*1 eq $arg);
++    $code .= "\t$opcode\t".join(',',@_,$arg)."\n";
++}
++
++my @x=map("r$_",(0..7,"x","x","x","x",12,"x",14,"x"));
++my @t=map("r$_",(8..11));
++
++sub ROUND {
++my ($a0,$b0,$c0,$d0)=@_;
++my ($a1,$b1,$c1,$d1)=map(($_&~3)+(($_+1)&3),($a0,$b0,$c0,$d0));
++my ($a2,$b2,$c2,$d2)=map(($_&~3)+(($_+1)&3),($a1,$b1,$c1,$d1));
++my ($a3,$b3,$c3,$d3)=map(($_&~3)+(($_+1)&3),($a2,$b2,$c2,$d2));
++my $odd = $d0&1;
++my ($xc,$xc_) = (@t[0..1]);
++my ($xd,$xd_) = $odd ? (@t[2],@x[$d1]) : (@x[$d0],@t[2]);
++my @ret;
++
++	# Consider order in which variables are addressed by their
++	# index:
++	#
++	#       a   b   c   d
++	#
++	#       0   4   8  12 < even round
++	#       1   5   9  13
++	#       2   6  10  14
++	#       3   7  11  15
++	#       0   5  10  15 < odd round
++	#       1   6  11  12
++	#       2   7   8  13
++	#       3   4   9  14
++	#
++	# 'a', 'b' are permanently allocated in registers, @x[0..7],
++	# while 'c's and pair of 'd's are maintained in memory. If
++	# you observe 'c' column, you'll notice that pair of 'c's is
++	# invariant between rounds. This means that we have to reload
++	# them once per round, in the middle. This is why you'll see
++	# bunch of 'c' stores and loads in the middle, but none in
++	# the beginning or end. If you observe 'd' column, you'll
++	# notice that 15 and 13 are reused in next pair of rounds.
++	# This is why these two are chosen for offloading to memory,
++	# to make loads count more.
++							push @ret,(
++	"&add	(@x[$a0],@x[$a0],@x[$b0])",
++	"&mov	($xd,$xd,'ror#16')",
++	 "&add	(@x[$a1],@x[$a1],@x[$b1])",
++	 "&mov	($xd_,$xd_,'ror#16')",
++	"&eor	($xd,$xd,@x[$a0],'ror#16')",
++	 "&eor	($xd_,$xd_,@x[$a1],'ror#16')",
++
++	"&add	($xc,$xc,$xd)",
++	"&mov	(@x[$b0],@x[$b0],'ror#20')",
++	 "&add	($xc_,$xc_,$xd_)",
++	 "&mov	(@x[$b1],@x[$b1],'ror#20')",
++	"&eor	(@x[$b0],@x[$b0],$xc,'ror#20')",
++	 "&eor	(@x[$b1],@x[$b1],$xc_,'ror#20')",
++
++	"&add	(@x[$a0],@x[$a0],@x[$b0])",
++	"&mov	($xd,$xd,'ror#24')",
++	 "&add	(@x[$a1],@x[$a1],@x[$b1])",
++	 "&mov	($xd_,$xd_,'ror#24')",
++	"&eor	($xd,$xd,@x[$a0],'ror#24')",
++	 "&eor	($xd_,$xd_,@x[$a1],'ror#24')",
++
++	"&add	($xc,$xc,$xd)",
++	"&mov	(@x[$b0],@x[$b0],'ror#25')"		);
++							push @ret,(
++	"&str	($xd,'[sp,#4*(16+$d0)]')",
++	"&ldr	($xd,'[sp,#4*(16+$d2)]')"		) if ($odd);
++							push @ret,(
++	 "&add	($xc_,$xc_,$xd_)",
++	 "&mov	(@x[$b1],@x[$b1],'ror#25')"		);
++							push @ret,(
++	 "&str	($xd_,'[sp,#4*(16+$d1)]')",
++	 "&ldr	($xd_,'[sp,#4*(16+$d3)]')"		) if (!$odd);
++							push @ret,(
++	"&eor	(@x[$b0],@x[$b0],$xc,'ror#25')",
++	 "&eor	(@x[$b1],@x[$b1],$xc_,'ror#25')"	);
++
++	$xd=@x[$d2]					if (!$odd);
++	$xd_=@x[$d3]					if ($odd);
++							push @ret,(
++	"&str	($xc,'[sp,#4*(16+$c0)]')",
++	"&ldr	($xc,'[sp,#4*(16+$c2)]')",
++	"&add	(@x[$a2],@x[$a2],@x[$b2])",
++	"&mov	($xd,$xd,'ror#16')",
++	 "&str	($xc_,'[sp,#4*(16+$c1)]')",
++	 "&ldr	($xc_,'[sp,#4*(16+$c3)]')",
++	 "&add	(@x[$a3],@x[$a3],@x[$b3])",
++	 "&mov	($xd_,$xd_,'ror#16')",
++	"&eor	($xd,$xd,@x[$a2],'ror#16')",
++	 "&eor	($xd_,$xd_,@x[$a3],'ror#16')",
++
++	"&add	($xc,$xc,$xd)",
++	"&mov	(@x[$b2],@x[$b2],'ror#20')",
++	 "&add	($xc_,$xc_,$xd_)",
++	 "&mov	(@x[$b3],@x[$b3],'ror#20')",
++	"&eor	(@x[$b2],@x[$b2],$xc,'ror#20')",
++	 "&eor	(@x[$b3],@x[$b3],$xc_,'ror#20')",
++
++	"&add	(@x[$a2],@x[$a2],@x[$b2])",
++	"&mov	($xd,$xd,'ror#24')",
++	 "&add	(@x[$a3],@x[$a3],@x[$b3])",
++	 "&mov	($xd_,$xd_,'ror#24')",
++	"&eor	($xd,$xd,@x[$a2],'ror#24')",
++	 "&eor	($xd_,$xd_,@x[$a3],'ror#24')",
++
++	"&add	($xc,$xc,$xd)",
++	"&mov	(@x[$b2],@x[$b2],'ror#25')",
++	 "&add	($xc_,$xc_,$xd_)",
++	 "&mov	(@x[$b3],@x[$b3],'ror#25')",
++	"&eor	(@x[$b2],@x[$b2],$xc,'ror#25')",
++	 "&eor	(@x[$b3],@x[$b3],$xc_,'ror#25')"	);
++
++	@ret;
++}
++
++$code.=<<___;
++#include "arm_arch.h"
++
++.text
++#if defined(__thumb2__)
++.syntax	unified
++.thumb
++#else
++.code	32
++#endif
++
++#if defined(__thumb2__) || defined(__clang__)
++#define ldrhsb	ldrbhs
++#endif
++
++.align	5
++.Lsigma:
++.long	0x61707865,0x3320646e,0x79622d32,0x6b206574	@ endian-neutral
++.Lone:
++.long	1,0,0,0
++#if __ARM_MAX_ARCH__>=7
++.LOPENSSL_armcap:
++.word   OPENSSL_armcap_P-.LChaCha20_ctr32
++#else
++.word	-1
++#endif
++
++.globl	ChaCha20_ctr32
++.type	ChaCha20_ctr32,%function
++.align	5
++ChaCha20_ctr32:
++.LChaCha20_ctr32:
++	ldr	r12,[sp,#0]		@ pull pointer to counter and nonce
++	stmdb	sp!,{r0-r2,r4-r11,lr}
++#if __ARM_ARCH__<7 && !defined(__thumb2__)
++	sub	r14,pc,#16		@ ChaCha20_ctr32
++#else
++	adr	r14,.LChaCha20_ctr32
++#endif
++	cmp	r2,#0			@ len==0?
++#ifdef	__thumb2__
++	itt	eq
++#endif
++	addeq	sp,sp,#4*3
++	beq	.Lno_data
++#if __ARM_MAX_ARCH__>=7
++	cmp	r2,#192			@ test len
++	bls	.Lshort
++	ldr	r4,[r14,#-32]
++	ldr	r4,[r14,r4]
++# ifdef	__APPLE__
++	ldr	r4,[r4]
++# endif
++	tst	r4,#ARMV7_NEON
++	bne	.LChaCha20_neon
++.Lshort:
++#endif
++	ldmia	r12,{r4-r7}		@ load counter and nonce
++	sub	sp,sp,#4*(16)		@ off-load area
++	sub	r14,r14,#64		@ .Lsigma
++	stmdb	sp!,{r4-r7}		@ copy counter and nonce
++	ldmia	r3,{r4-r11}		@ load key
++	ldmia	r14,{r0-r3}		@ load sigma
++	stmdb	sp!,{r4-r11}		@ copy key
++	stmdb	sp!,{r0-r3}		@ copy sigma
++	str	r10,[sp,#4*(16+10)]	@ off-load "@x[10]"
++	str	r11,[sp,#4*(16+11)]	@ off-load "@x[11]"
++	b	.Loop_outer_enter
++
++.align	4
++.Loop_outer:
++	ldmia	sp,{r0-r9}		@ load key material
++	str	@t[3],[sp,#4*(32+2)]	@ save len
++	str	r12,  [sp,#4*(32+1)]	@ save inp
++	str	r14,  [sp,#4*(32+0)]	@ save out
++.Loop_outer_enter:
++	ldr	@t[3], [sp,#4*(15)]
++	ldr	@x[12],[sp,#4*(12)]	@ modulo-scheduled load
++	ldr	@t[2], [sp,#4*(13)]
++	ldr	@x[14],[sp,#4*(14)]
++	str	@t[3], [sp,#4*(16+15)]
++	mov	@t[3],#10
++	b	.Loop
++
++.align	4
++.Loop:
++	subs	@t[3],@t[3],#1
++___
++	foreach (&ROUND(0, 4, 8,12)) { eval; }
++	foreach (&ROUND(0, 5,10,15)) { eval; }
++$code.=<<___;
++	bne	.Loop
++
++	ldr	@t[3],[sp,#4*(32+2)]	@ load len
++
++	str	@t[0], [sp,#4*(16+8)]	@ modulo-scheduled store
++	str	@t[1], [sp,#4*(16+9)]
++	str	@x[12],[sp,#4*(16+12)]
++	str	@t[2], [sp,#4*(16+13)]
++	str	@x[14],[sp,#4*(16+14)]
++
++	@ at this point we have first half of 512-bit result in
++	@ @x[0-7] and second half at sp+4*(16+8)
++
++	cmp	@t[3],#64		@ done yet?
++#ifdef	__thumb2__
++	itete	lo
++#endif
++	addlo	r12,sp,#4*(0)		@ shortcut or ...
++	ldrhs	r12,[sp,#4*(32+1)]	@ ... load inp
++	addlo	r14,sp,#4*(0)		@ shortcut or ...
++	ldrhs	r14,[sp,#4*(32+0)]	@ ... load out
++
++	ldr	@t[0],[sp,#4*(0)]	@ load key material
++	ldr	@t[1],[sp,#4*(1)]
++
++#if __ARM_ARCH__>=6 || !defined(__ARMEB__)
++# if __ARM_ARCH__<7
++	orr	@t[2],r12,r14
++	tst	@t[2],#3		@ are input and output aligned?
++	ldr	@t[2],[sp,#4*(2)]
++	bne	.Lunaligned
++	cmp	@t[3],#64		@ restore flags
++# else
++	ldr	@t[2],[sp,#4*(2)]
++# endif
++	ldr	@t[3],[sp,#4*(3)]
++
++	add	@x[0],@x[0],@t[0]	@ accumulate key material
++	add	@x[1],@x[1],@t[1]
++# ifdef	__thumb2__
++	itt	hs
++# endif
++	ldrhs	@t[0],[r12],#16		@ load input
++	ldrhs	@t[1],[r12,#-12]
++
++	add	@x[2],@x[2],@t[2]
++	add	@x[3],@x[3],@t[3]
++# ifdef	__thumb2__
++	itt	hs
++# endif
++	ldrhs	@t[2],[r12,#-8]
++	ldrhs	@t[3],[r12,#-4]
++# if __ARM_ARCH__>=6 && defined(__ARMEB__)
++	rev	@x[0],@x[0]
++	rev	@x[1],@x[1]
++	rev	@x[2],@x[2]
++	rev	@x[3],@x[3]
++# endif
++# ifdef	__thumb2__
++	itt	hs
++# endif
++	eorhs	@x[0],@x[0],@t[0]	@ xor with input
++	eorhs	@x[1],@x[1],@t[1]
++	 add	@t[0],sp,#4*(4)
++	str	@x[0],[r14],#16		@ store output
++# ifdef	__thumb2__
++	itt	hs
++# endif
++	eorhs	@x[2],@x[2],@t[2]
++	eorhs	@x[3],@x[3],@t[3]
++	 ldmia	@t[0],{@t[0]-@t[3]}	@ load key material
++	str	@x[1],[r14,#-12]
++	str	@x[2],[r14,#-8]
++	str	@x[3],[r14,#-4]
++
++	add	@x[4],@x[4],@t[0]	@ accumulate key material
++	add	@x[5],@x[5],@t[1]
++# ifdef	__thumb2__
++	itt	hs
++# endif
++	ldrhs	@t[0],[r12],#16		@ load input
++	ldrhs	@t[1],[r12,#-12]
++	add	@x[6],@x[6],@t[2]
++	add	@x[7],@x[7],@t[3]
++# ifdef	__thumb2__
++	itt	hs
++# endif
++	ldrhs	@t[2],[r12,#-8]
++	ldrhs	@t[3],[r12,#-4]
++# if __ARM_ARCH__>=6 && defined(__ARMEB__)
++	rev	@x[4],@x[4]
++	rev	@x[5],@x[5]
++	rev	@x[6],@x[6]
++	rev	@x[7],@x[7]
++# endif
++# ifdef	__thumb2__
++	itt	hs
++# endif
++	eorhs	@x[4],@x[4],@t[0]
++	eorhs	@x[5],@x[5],@t[1]
++	 add	@t[0],sp,#4*(8)
++	str	@x[4],[r14],#16		@ store output
++# ifdef	__thumb2__
++	itt	hs
++# endif
++	eorhs	@x[6],@x[6],@t[2]
++	eorhs	@x[7],@x[7],@t[3]
++	str	@x[5],[r14,#-12]
++	 ldmia	@t[0],{@t[0]-@t[3]}	@ load key material
++	str	@x[6],[r14,#-8]
++	 add	@x[0],sp,#4*(16+8)
++	str	@x[7],[r14,#-4]
++
++	ldmia	@x[0],{@x[0]-@x[7]}	@ load second half
++
++	add	@x[0],@x[0],@t[0]	@ accumulate key material
++	add	@x[1],@x[1],@t[1]
++# ifdef	__thumb2__
++	itt	hs
++# endif
++	ldrhs	@t[0],[r12],#16		@ load input
++	ldrhs	@t[1],[r12,#-12]
++# ifdef	__thumb2__
++	itt	hi
++# endif
++	 strhi	@t[2],[sp,#4*(16+10)]	@ copy "@x[10]" while at it
++	 strhi	@t[3],[sp,#4*(16+11)]	@ copy "@x[11]" while at it
++	add	@x[2],@x[2],@t[2]
++	add	@x[3],@x[3],@t[3]
++# ifdef	__thumb2__
++	itt	hs
++# endif
++	ldrhs	@t[2],[r12,#-8]
++	ldrhs	@t[3],[r12,#-4]
++# if __ARM_ARCH__>=6 && defined(__ARMEB__)
++	rev	@x[0],@x[0]
++	rev	@x[1],@x[1]
++	rev	@x[2],@x[2]
++	rev	@x[3],@x[3]
++# endif
++# ifdef	__thumb2__
++	itt	hs
++# endif
++	eorhs	@x[0],@x[0],@t[0]
++	eorhs	@x[1],@x[1],@t[1]
++	 add	@t[0],sp,#4*(12)
++	str	@x[0],[r14],#16		@ store output
++# ifdef	__thumb2__
++	itt	hs
++# endif
++	eorhs	@x[2],@x[2],@t[2]
++	eorhs	@x[3],@x[3],@t[3]
++	str	@x[1],[r14,#-12]
++	 ldmia	@t[0],{@t[0]-@t[3]}	@ load key material
++	str	@x[2],[r14,#-8]
++	str	@x[3],[r14,#-4]
++
++	add	@x[4],@x[4],@t[0]	@ accumulate key material
++	add	@x[5],@x[5],@t[1]
++# ifdef	__thumb2__
++	itt	hi
++# endif
++	 addhi	@t[0],@t[0],#1		@ next counter value
++	 strhi	@t[0],[sp,#4*(12)]	@ save next counter value
++# ifdef	__thumb2__
++	itt	hs
++# endif
++	ldrhs	@t[0],[r12],#16		@ load input
++	ldrhs	@t[1],[r12,#-12]
++	add	@x[6],@x[6],@t[2]
++	add	@x[7],@x[7],@t[3]
++# ifdef	__thumb2__
++	itt	hs
++# endif
++	ldrhs	@t[2],[r12,#-8]
++	ldrhs	@t[3],[r12,#-4]
++# if __ARM_ARCH__>=6 && defined(__ARMEB__)
++	rev	@x[4],@x[4]
++	rev	@x[5],@x[5]
++	rev	@x[6],@x[6]
++	rev	@x[7],@x[7]
++# endif
++# ifdef	__thumb2__
++	itt	hs
++# endif
++	eorhs	@x[4],@x[4],@t[0]
++	eorhs	@x[5],@x[5],@t[1]
++# ifdef	__thumb2__
++	 it	ne
++# endif
++	 ldrne	@t[0],[sp,#4*(32+2)]	@ re-load len
++# ifdef	__thumb2__
++	itt	hs
++# endif
++	eorhs	@x[6],@x[6],@t[2]
++	eorhs	@x[7],@x[7],@t[3]
++	str	@x[4],[r14],#16		@ store output
++	str	@x[5],[r14,#-12]
++# ifdef	__thumb2__
++	it	hs
++# endif
++	 subhs	@t[3],@t[0],#64		@ len-=64
++	str	@x[6],[r14,#-8]
++	str	@x[7],[r14,#-4]
++	bhi	.Loop_outer
++
++	beq	.Ldone
++# if __ARM_ARCH__<7
++	b	.Ltail
++
++.align	4
++.Lunaligned:				@ unaligned endian-neutral path
++	cmp	@t[3],#64		@ restore flags
++# endif
++#endif
++#if __ARM_ARCH__<7
++	ldr	@t[3],[sp,#4*(3)]
++___
++for ($i=0;$i<16;$i+=4) {
++my $j=$i&0x7;
++
++$code.=<<___	if ($i==4);
++	add	@x[0],sp,#4*(16+8)
++___
++$code.=<<___	if ($i==8);
++	ldmia	@x[0],{@x[0]-@x[7]}		@ load second half
++# ifdef	__thumb2__
++	itt	hi
++# endif
++	strhi	@t[2],[sp,#4*(16+10)]		@ copy "@x[10]"
++	strhi	@t[3],[sp,#4*(16+11)]		@ copy "@x[11]"
++___
++$code.=<<___;
++	add	@x[$j+0],@x[$j+0],@t[0]		@ accumulate key material
++___
++$code.=<<___	if ($i==12);
++# ifdef	__thumb2__
++	itt	hi
++# endif
++	addhi	@t[0],@t[0],#1			@ next counter value
++	strhi	@t[0],[sp,#4*(12)]		@ save next counter value
++___
++$code.=<<___;
++	add	@x[$j+1],@x[$j+1],@t[1]
++	add	@x[$j+2],@x[$j+2],@t[2]
++# ifdef	__thumb2__
++	itete	lo
++# endif
++	eorlo	@t[0],@t[0],@t[0]		@ zero or ...
++	ldrhsb	@t[0],[r12],#16			@ ... load input
++	eorlo	@t[1],@t[1],@t[1]
++	ldrhsb	@t[1],[r12,#-12]
++
++	add	@x[$j+3],@x[$j+3],@t[3]
++# ifdef	__thumb2__
++	itete	lo
++# endif
++	eorlo	@t[2],@t[2],@t[2]
++	ldrhsb	@t[2],[r12,#-8]
++	eorlo	@t[3],@t[3],@t[3]
++	ldrhsb	@t[3],[r12,#-4]
++
++	eor	@x[$j+0],@t[0],@x[$j+0]		@ xor with input (or zero)
++	eor	@x[$j+1],@t[1],@x[$j+1]
++# ifdef	__thumb2__
++	itt	hs
++# endif
++	ldrhsb	@t[0],[r12,#-15]		@ load more input
++	ldrhsb	@t[1],[r12,#-11]
++	eor	@x[$j+2],@t[2],@x[$j+2]
++	 strb	@x[$j+0],[r14],#16		@ store output
++	eor	@x[$j+3],@t[3],@x[$j+3]
++# ifdef	__thumb2__
++	itt	hs
++# endif
++	ldrhsb	@t[2],[r12,#-7]
++	ldrhsb	@t[3],[r12,#-3]
++	 strb	@x[$j+1],[r14,#-12]
++	eor	@x[$j+0],@t[0],@x[$j+0],lsr#8
++	 strb	@x[$j+2],[r14,#-8]
++	eor	@x[$j+1],@t[1],@x[$j+1],lsr#8
++# ifdef	__thumb2__
++	itt	hs
++# endif
++	ldrhsb	@t[0],[r12,#-14]		@ load more input
++	ldrhsb	@t[1],[r12,#-10]
++	 strb	@x[$j+3],[r14,#-4]
++	eor	@x[$j+2],@t[2],@x[$j+2],lsr#8
++	 strb	@x[$j+0],[r14,#-15]
++	eor	@x[$j+3],@t[3],@x[$j+3],lsr#8
++# ifdef	__thumb2__
++	itt	hs
++# endif
++	ldrhsb	@t[2],[r12,#-6]
++	ldrhsb	@t[3],[r12,#-2]
++	 strb	@x[$j+1],[r14,#-11]
++	eor	@x[$j+0],@t[0],@x[$j+0],lsr#8
++	 strb	@x[$j+2],[r14,#-7]
++	eor	@x[$j+1],@t[1],@x[$j+1],lsr#8
++# ifdef	__thumb2__
++	itt	hs
++# endif
++	ldrhsb	@t[0],[r12,#-13]		@ load more input
++	ldrhsb	@t[1],[r12,#-9]
++	 strb	@x[$j+3],[r14,#-3]
++	eor	@x[$j+2],@t[2],@x[$j+2],lsr#8
++	 strb	@x[$j+0],[r14,#-14]
++	eor	@x[$j+3],@t[3],@x[$j+3],lsr#8
++# ifdef	__thumb2__
++	itt	hs
++# endif
++	ldrhsb	@t[2],[r12,#-5]
++	ldrhsb	@t[3],[r12,#-1]
++	 strb	@x[$j+1],[r14,#-10]
++	 strb	@x[$j+2],[r14,#-6]
++	eor	@x[$j+0],@t[0],@x[$j+0],lsr#8
++	 strb	@x[$j+3],[r14,#-2]
++	eor	@x[$j+1],@t[1],@x[$j+1],lsr#8
++	 strb	@x[$j+0],[r14,#-13]
++	eor	@x[$j+2],@t[2],@x[$j+2],lsr#8
++	 strb	@x[$j+1],[r14,#-9]
++	eor	@x[$j+3],@t[3],@x[$j+3],lsr#8
++	 strb	@x[$j+2],[r14,#-5]
++	 strb	@x[$j+3],[r14,#-1]
++___
++$code.=<<___	if ($i<12);
++	add	@t[0],sp,#4*(4+$i)
++	ldmia	@t[0],{@t[0]-@t[3]}		@ load key material
++___
++}
++$code.=<<___;
++# ifdef	__thumb2__
++	it	ne
++# endif
++	ldrne	@t[0],[sp,#4*(32+2)]		@ re-load len
++# ifdef	__thumb2__
++	it	hs
++# endif
++	subhs	@t[3],@t[0],#64			@ len-=64
++	bhi	.Loop_outer
++
++	beq	.Ldone
++#endif
++
++.Ltail:
++	ldr	r12,[sp,#4*(32+1)]	@ load inp
++	add	@t[1],sp,#4*(0)
++	ldr	r14,[sp,#4*(32+0)]	@ load out
++
++.Loop_tail:
++	ldrb	@t[2],[@t[1]],#1	@ read buffer on stack
++	ldrb	@t[3],[r12],#1		@ read input
++	subs	@t[0],@t[0],#1
++	eor	@t[3],@t[3],@t[2]
++	strb	@t[3],[r14],#1		@ store output
++	bne	.Loop_tail
++
++.Ldone:
++	add	sp,sp,#4*(32+3)
++.Lno_data:
++	ldmia	sp!,{r4-r11,pc}
++.size	ChaCha20_ctr32,.-ChaCha20_ctr32
++___
++
++{{{
++my ($a0,$b0,$c0,$d0,$a1,$b1,$c1,$d1,$a2,$b2,$c2,$d2,$t0,$t1,$t2,$t3) =
++    map("q$_",(0..15));
++
++sub NEONROUND {
++my $odd = pop;
++my ($a,$b,$c,$d,$t)=@_;
++
++	(
++	"&vadd_i32	($a,$a,$b)",
++	"&veor		($d,$d,$a)",
++	"&vrev32_16	($d,$d)",	# vrot ($d,16)
++
++	"&vadd_i32	($c,$c,$d)",
++	"&veor		($t,$b,$c)",
++	"&vshr_u32	($b,$t,20)",
++	"&vsli_32	($b,$t,12)",
++
++	"&vadd_i32	($a,$a,$b)",
++	"&veor		($t,$d,$a)",
++	"&vshr_u32	($d,$t,24)",
++	"&vsli_32	($d,$t,8)",
++
++	"&vadd_i32	($c,$c,$d)",
++	"&veor		($t,$b,$c)",
++	"&vshr_u32	($b,$t,25)",
++	"&vsli_32	($b,$t,7)",
++
++	"&vext_8	($c,$c,$c,8)",
++	"&vext_8	($b,$b,$b,$odd?12:4)",
++	"&vext_8	($d,$d,$d,$odd?4:12)"
++	);
++}
++
++$code.=<<___;
++#if __ARM_MAX_ARCH__>=7
++.arch	armv7-a
++.fpu	neon
++
++.type	ChaCha20_neon,%function
++.align	5
++ChaCha20_neon:
++	ldr		r12,[sp,#0]		@ pull pointer to counter and nonce
++	stmdb		sp!,{r0-r2,r4-r11,lr}
++.LChaCha20_neon:
++	adr		r14,.Lsigma
++	vstmdb		sp!,{d8-d15}		@ ABI spec says so
++	stmdb		sp!,{r0-r3}
++
++	vld1.32		{$b0-$c0},[r3]		@ load key
++	ldmia		r3,{r4-r11}		@ load key
++
++	sub		sp,sp,#4*(16+16)
++	vld1.32		{$d0},[r12]		@ load counter and nonce
++	add		r12,sp,#4*8
++	ldmia		r14,{r0-r3}		@ load sigma
++	vld1.32		{$a0},[r14]!		@ load sigma
++	vld1.32		{$t0},[r14]		@ one
++	vst1.32		{$c0-$d0},[r12]		@ copy 1/2key|counter|nonce
++	vst1.32		{$a0-$b0},[sp]		@ copy sigma|1/2key
++
++	str		r10,[sp,#4*(16+10)]	@ off-load "@x[10]"
++	str		r11,[sp,#4*(16+11)]	@ off-load "@x[11]"
++	vshl.i32	$t1#lo,$t0#lo,#1	@ two
++	vstr		$t0#lo,[sp,#4*(16+0)]
++	vshl.i32	$t2#lo,$t0#lo,#2	@ four
++	vstr		$t1#lo,[sp,#4*(16+2)]
++	vmov		$a1,$a0
++	vstr		$t2#lo,[sp,#4*(16+4)]
++	vmov		$a2,$a0
++	vmov		$b1,$b0
++	vmov		$b2,$b0
++	b		.Loop_neon_enter
++
++.align	4
++.Loop_neon_outer:
++	ldmia		sp,{r0-r9}		@ load key material
++	cmp		@t[3],#64*2		@ if len<=64*2
++	bls		.Lbreak_neon		@ switch to integer-only
++	vmov		$a1,$a0
++	str		@t[3],[sp,#4*(32+2)]	@ save len
++	vmov		$a2,$a0
++	str		r12,  [sp,#4*(32+1)]	@ save inp
++	vmov		$b1,$b0
++	str		r14,  [sp,#4*(32+0)]	@ save out
++	vmov		$b2,$b0
++.Loop_neon_enter:
++	ldr		@t[3], [sp,#4*(15)]
++	vadd.i32	$d1,$d0,$t0		@ counter+1
++	ldr		@x[12],[sp,#4*(12)]	@ modulo-scheduled load
++	vmov		$c1,$c0
++	ldr		@t[2], [sp,#4*(13)]
++	vmov		$c2,$c0
++	ldr		@x[14],[sp,#4*(14)]
++	vadd.i32	$d2,$d1,$t0		@ counter+2
++	str		@t[3], [sp,#4*(16+15)]
++	mov		@t[3],#10
++	add		@x[12],@x[12],#3	@ counter+3 
++	b		.Loop_neon
++
++.align	4
++.Loop_neon:
++	subs		@t[3],@t[3],#1
++___
++	my @thread0=&NEONROUND($a0,$b0,$c0,$d0,$t0,0);
++	my @thread1=&NEONROUND($a1,$b1,$c1,$d1,$t1,0);
++	my @thread2=&NEONROUND($a2,$b2,$c2,$d2,$t2,0);
++	my @thread3=&ROUND(0,4,8,12);
++
++	foreach (@thread0) {
++		eval;			eval(shift(@thread3));
++		eval(shift(@thread1));	eval(shift(@thread3));
++		eval(shift(@thread2));	eval(shift(@thread3));
++	}
++
++	@thread0=&NEONROUND($a0,$b0,$c0,$d0,$t0,1);
++	@thread1=&NEONROUND($a1,$b1,$c1,$d1,$t1,1);
++	@thread2=&NEONROUND($a2,$b2,$c2,$d2,$t2,1);
++	@thread3=&ROUND(0,5,10,15);
++
++	foreach (@thread0) {
++		eval;			eval(shift(@thread3));
++		eval(shift(@thread1));	eval(shift(@thread3));
++		eval(shift(@thread2));	eval(shift(@thread3));
++	}
++$code.=<<___;
++	bne		.Loop_neon
++
++	add		@t[3],sp,#32
++	vld1.32		{$t0-$t1},[sp]		@ load key material
++	vld1.32		{$t2-$t3},[@t[3]]
++
++	ldr		@t[3],[sp,#4*(32+2)]	@ load len
++
++	str		@t[0], [sp,#4*(16+8)]	@ modulo-scheduled store
++	str		@t[1], [sp,#4*(16+9)]
++	str		@x[12],[sp,#4*(16+12)]
++	str		@t[2], [sp,#4*(16+13)]
++	str		@x[14],[sp,#4*(16+14)]
++
++	@ at this point we have first half of 512-bit result in
++	@ @x[0-7] and second half at sp+4*(16+8)
++
++	ldr		r12,[sp,#4*(32+1)]	@ load inp
++	ldr		r14,[sp,#4*(32+0)]	@ load out
++
++	vadd.i32	$a0,$a0,$t0		@ accumulate key material
++	vadd.i32	$a1,$a1,$t0
++	vadd.i32	$a2,$a2,$t0
++	vldr		$t0#lo,[sp,#4*(16+0)]	@ one
++
++	vadd.i32	$b0,$b0,$t1
++	vadd.i32	$b1,$b1,$t1
++	vadd.i32	$b2,$b2,$t1
++	vldr		$t1#lo,[sp,#4*(16+2)]	@ two
++
++	vadd.i32	$c0,$c0,$t2
++	vadd.i32	$c1,$c1,$t2
++	vadd.i32	$c2,$c2,$t2
++	vadd.i32	$d1#lo,$d1#lo,$t0#lo	@ counter+1
++	vadd.i32	$d2#lo,$d2#lo,$t1#lo	@ counter+2
++
++	vadd.i32	$d0,$d0,$t3
++	vadd.i32	$d1,$d1,$t3
++	vadd.i32	$d2,$d2,$t3
++
++	cmp		@t[3],#64*4
++	blo		.Ltail_neon
++
++	vld1.8		{$t0-$t1},[r12]!	@ load input
++	 mov		@t[3],sp
++	vld1.8		{$t2-$t3},[r12]!
++	veor		$a0,$a0,$t0		@ xor with input
++	veor		$b0,$b0,$t1
++	vld1.8		{$t0-$t1},[r12]!
++	veor		$c0,$c0,$t2
++	veor		$d0,$d0,$t3
++	vld1.8		{$t2-$t3},[r12]!
++
++	veor		$a1,$a1,$t0
++	 vst1.8		{$a0-$b0},[r14]!	@ store output
++	veor		$b1,$b1,$t1
++	vld1.8		{$t0-$t1},[r12]!
++	veor		$c1,$c1,$t2
++	 vst1.8		{$c0-$d0},[r14]!
++	veor		$d1,$d1,$t3
++	vld1.8		{$t2-$t3},[r12]!
++
++	veor		$a2,$a2,$t0
++	 vld1.32	{$a0-$b0},[@t[3]]!	@ load for next iteration
++	 veor		$t0#hi,$t0#hi,$t0#hi
++	 vldr		$t0#lo,[sp,#4*(16+4)]	@ four
++	veor		$b2,$b2,$t1
++	 vld1.32	{$c0-$d0},[@t[3]]
++	veor		$c2,$c2,$t2
++	 vst1.8		{$a1-$b1},[r14]!
++	veor		$d2,$d2,$t3
++	 vst1.8		{$c1-$d1},[r14]!
++
++	vadd.i32	$d0#lo,$d0#lo,$t0#lo	@ next counter value
++	vldr		$t0#lo,[sp,#4*(16+0)]	@ one
++
++	ldmia		sp,{@t[0]-@t[3]}	@ load key material
++	add		@x[0],@x[0],@t[0]	@ accumulate key material
++	ldr		@t[0],[r12],#16		@ load input
++	 vst1.8		{$a2-$b2},[r14]!
++	add		@x[1],@x[1],@t[1]
++	ldr		@t[1],[r12,#-12]
++	 vst1.8		{$c2-$d2},[r14]!
++	add		@x[2],@x[2],@t[2]
++	ldr		@t[2],[r12,#-8]
++	add		@x[3],@x[3],@t[3]
++	ldr		@t[3],[r12,#-4]
++# ifdef	__ARMEB__
++	rev		@x[0],@x[0]
++	rev		@x[1],@x[1]
++	rev		@x[2],@x[2]
++	rev		@x[3],@x[3]
++# endif
++	eor		@x[0],@x[0],@t[0]	@ xor with input
++	 add		@t[0],sp,#4*(4)
++	eor		@x[1],@x[1],@t[1]
++	str		@x[0],[r14],#16		@ store output
++	eor		@x[2],@x[2],@t[2]
++	str		@x[1],[r14,#-12]
++	eor		@x[3],@x[3],@t[3]
++	 ldmia		@t[0],{@t[0]-@t[3]}	@ load key material
++	str		@x[2],[r14,#-8]
++	str		@x[3],[r14,#-4]
++
++	add		@x[4],@x[4],@t[0]	@ accumulate key material
++	ldr		@t[0],[r12],#16		@ load input
++	add		@x[5],@x[5],@t[1]
++	ldr		@t[1],[r12,#-12]
++	add		@x[6],@x[6],@t[2]
++	ldr		@t[2],[r12,#-8]
++	add		@x[7],@x[7],@t[3]
++	ldr		@t[3],[r12,#-4]
++# ifdef	__ARMEB__
++	rev		@x[4],@x[4]
++	rev		@x[5],@x[5]
++	rev		@x[6],@x[6]
++	rev		@x[7],@x[7]
++# endif
++	eor		@x[4],@x[4],@t[0]
++	 add		@t[0],sp,#4*(8)
++	eor		@x[5],@x[5],@t[1]
++	str		@x[4],[r14],#16		@ store output
++	eor		@x[6],@x[6],@t[2]
++	str		@x[5],[r14,#-12]
++	eor		@x[7],@x[7],@t[3]
++	 ldmia		@t[0],{@t[0]-@t[3]}	@ load key material
++	str		@x[6],[r14,#-8]
++	 add		@x[0],sp,#4*(16+8)
++	str		@x[7],[r14,#-4]
++
++	ldmia		@x[0],{@x[0]-@x[7]}	@ load second half
++
++	add		@x[0],@x[0],@t[0]	@ accumulate key material
++	ldr		@t[0],[r12],#16		@ load input
++	add		@x[1],@x[1],@t[1]
++	ldr		@t[1],[r12,#-12]
++# ifdef	__thumb2__
++	it	hi
++# endif
++	 strhi		@t[2],[sp,#4*(16+10)]	@ copy "@x[10]" while at it
++	add		@x[2],@x[2],@t[2]
++	ldr		@t[2],[r12,#-8]
++# ifdef	__thumb2__
++	it	hi
++# endif
++	 strhi		@t[3],[sp,#4*(16+11)]	@ copy "@x[11]" while at it
++	add		@x[3],@x[3],@t[3]
++	ldr		@t[3],[r12,#-4]
++# ifdef	__ARMEB__
++	rev		@x[0],@x[0]
++	rev		@x[1],@x[1]
++	rev		@x[2],@x[2]
++	rev		@x[3],@x[3]
++# endif
++	eor		@x[0],@x[0],@t[0]
++	 add		@t[0],sp,#4*(12)
++	eor		@x[1],@x[1],@t[1]
++	str		@x[0],[r14],#16		@ store output
++	eor		@x[2],@x[2],@t[2]
++	str		@x[1],[r14,#-12]
++	eor		@x[3],@x[3],@t[3]
++	 ldmia		@t[0],{@t[0]-@t[3]}	@ load key material
++	str		@x[2],[r14,#-8]
++	str		@x[3],[r14,#-4]
++
++	add		@x[4],@x[4],@t[0]	@ accumulate key material
++	 add		@t[0],@t[0],#4		@ next counter value
++	add		@x[5],@x[5],@t[1]
++	 str		@t[0],[sp,#4*(12)]	@ save next counter value
++	ldr		@t[0],[r12],#16		@ load input
++	add		@x[6],@x[6],@t[2]
++	 add		@x[4],@x[4],#3		@ counter+3
++	ldr		@t[1],[r12,#-12]
++	add		@x[7],@x[7],@t[3]
++	ldr		@t[2],[r12,#-8]
++	ldr		@t[3],[r12,#-4]
++# ifdef	__ARMEB__
++	rev		@x[4],@x[4]
++	rev		@x[5],@x[5]
++	rev		@x[6],@x[6]
++	rev		@x[7],@x[7]
++# endif
++	eor		@x[4],@x[4],@t[0]
++# ifdef	__thumb2__
++	it	hi
++# endif
++	 ldrhi		@t[0],[sp,#4*(32+2)]	@ re-load len
++	eor		@x[5],@x[5],@t[1]
++	eor		@x[6],@x[6],@t[2]
++	str		@x[4],[r14],#16		@ store output
++	eor		@x[7],@x[7],@t[3]
++	str		@x[5],[r14,#-12]
++	 sub		@t[3],@t[0],#64*4	@ len-=64*4
++	str		@x[6],[r14,#-8]
++	str		@x[7],[r14,#-4]
++	bhi		.Loop_neon_outer
++
++	b		.Ldone_neon
++
++.align	4
++.Lbreak_neon:
++	@ harmonize NEON and integer-only stack frames: load data
++	@ from NEON frame, but save to integer-only one; distance
++	@ between the two is 4*(32+4+16-32)=4*(20).
++
++	str		@t[3], [sp,#4*(20+32+2)]	@ save len
++	 add		@t[3],sp,#4*(32+4)
++	str		r12,   [sp,#4*(20+32+1)]	@ save inp
++	str		r14,   [sp,#4*(20+32+0)]	@ save out
++
++	ldr		@x[12],[sp,#4*(16+10)]
++	ldr		@x[14],[sp,#4*(16+11)]
++	 vldmia		@t[3],{d8-d15}			@ fulfill ABI requirement
++	str		@x[12],[sp,#4*(20+16+10)]	@ copy "@x[10]"
++	str		@x[14],[sp,#4*(20+16+11)]	@ copy "@x[11]"
++
++	ldr		@t[3], [sp,#4*(15)]
++	ldr		@x[12],[sp,#4*(12)]		@ modulo-scheduled load
++	ldr		@t[2], [sp,#4*(13)]
++	ldr		@x[14],[sp,#4*(14)]
++	str		@t[3], [sp,#4*(20+16+15)]
++	add		@t[3],sp,#4*(20)
++	vst1.32		{$a0-$b0},[@t[3]]!		@ copy key
++	add		sp,sp,#4*(20)			@ switch frame
++	vst1.32		{$c0-$d0},[@t[3]]
++	mov		@t[3],#10
++	b		.Loop				@ go integer-only
++
++.align	4
++.Ltail_neon:
++	cmp		@t[3],#64*3
++	bhs		.L192_or_more_neon
++	cmp		@t[3],#64*2
++	bhs		.L128_or_more_neon
++	cmp		@t[3],#64*1
++	bhs		.L64_or_more_neon
++
++	add		@t[0],sp,#4*(8)
++	vst1.8		{$a0-$b0},[sp]
++	add		@t[2],sp,#4*(0)
++	vst1.8		{$c0-$d0},[@t[0]]
++	b		.Loop_tail_neon
++
++.align	4
++.L64_or_more_neon:
++	vld1.8		{$t0-$t1},[r12]!
++	vld1.8		{$t2-$t3},[r12]!
++	veor		$a0,$a0,$t0
++	veor		$b0,$b0,$t1
++	veor		$c0,$c0,$t2
++	veor		$d0,$d0,$t3
++	vst1.8		{$a0-$b0},[r14]!
++	vst1.8		{$c0-$d0},[r14]!
++
++	beq		.Ldone_neon
++
++	add		@t[0],sp,#4*(8)
++	vst1.8		{$a1-$b1},[sp]
++	add		@t[2],sp,#4*(0)
++	vst1.8		{$c1-$d1},[@t[0]]
++	sub		@t[3],@t[3],#64*1	@ len-=64*1
++	b		.Loop_tail_neon
++
++.align	4
++.L128_or_more_neon:
++	vld1.8		{$t0-$t1},[r12]!
++	vld1.8		{$t2-$t3},[r12]!
++	veor		$a0,$a0,$t0
++	veor		$b0,$b0,$t1
++	vld1.8		{$t0-$t1},[r12]!
++	veor		$c0,$c0,$t2
++	veor		$d0,$d0,$t3
++	vld1.8		{$t2-$t3},[r12]!
++
++	veor		$a1,$a1,$t0
++	veor		$b1,$b1,$t1
++	 vst1.8		{$a0-$b0},[r14]!
++	veor		$c1,$c1,$t2
++	 vst1.8		{$c0-$d0},[r14]!
++	veor		$d1,$d1,$t3
++	vst1.8		{$a1-$b1},[r14]!
++	vst1.8		{$c1-$d1},[r14]!
++
++	beq		.Ldone_neon
++
++	add		@t[0],sp,#4*(8)
++	vst1.8		{$a2-$b2},[sp]
++	add		@t[2],sp,#4*(0)
++	vst1.8		{$c2-$d2},[@t[0]]
++	sub		@t[3],@t[3],#64*2	@ len-=64*2
++	b		.Loop_tail_neon
++
++.align	4
++.L192_or_more_neon:
++	vld1.8		{$t0-$t1},[r12]!
++	vld1.8		{$t2-$t3},[r12]!
++	veor		$a0,$a0,$t0
++	veor		$b0,$b0,$t1
++	vld1.8		{$t0-$t1},[r12]!
++	veor		$c0,$c0,$t2
++	veor		$d0,$d0,$t3
++	vld1.8		{$t2-$t3},[r12]!
++
++	veor		$a1,$a1,$t0
++	veor		$b1,$b1,$t1
++	vld1.8		{$t0-$t1},[r12]!
++	veor		$c1,$c1,$t2
++	 vst1.8		{$a0-$b0},[r14]!
++	veor		$d1,$d1,$t3
++	vld1.8		{$t2-$t3},[r12]!
++
++	veor		$a2,$a2,$t0
++	 vst1.8		{$c0-$d0},[r14]!
++	veor		$b2,$b2,$t1
++	 vst1.8		{$a1-$b1},[r14]!
++	veor		$c2,$c2,$t2
++	 vst1.8		{$c1-$d1},[r14]!
++	veor		$d2,$d2,$t3
++	vst1.8		{$a2-$b2},[r14]!
++	vst1.8		{$c2-$d2},[r14]!
++
++	beq		.Ldone_neon
++
++	ldmia		sp,{@t[0]-@t[3]}	@ load key material
++	add		@x[0],@x[0],@t[0]	@ accumulate key material
++	 add		@t[0],sp,#4*(4)
++	add		@x[1],@x[1],@t[1]
++	add		@x[2],@x[2],@t[2]
++	add		@x[3],@x[3],@t[3]
++	 ldmia		@t[0],{@t[0]-@t[3]}	@ load key material
++
++	add		@x[4],@x[4],@t[0]	@ accumulate key material
++	 add		@t[0],sp,#4*(8)
++	add		@x[5],@x[5],@t[1]
++	add		@x[6],@x[6],@t[2]
++	add		@x[7],@x[7],@t[3]
++	 ldmia		@t[0],{@t[0]-@t[3]}	@ load key material
++# ifdef	__ARMEB__
++	rev		@x[0],@x[0]
++	rev		@x[1],@x[1]
++	rev		@x[2],@x[2]
++	rev		@x[3],@x[3]
++	rev		@x[4],@x[4]
++	rev		@x[5],@x[5]
++	rev		@x[6],@x[6]
++	rev		@x[7],@x[7]
++# endif
++	stmia		sp,{@x[0]-@x[7]}
++	 add		@x[0],sp,#4*(16+8)
++
++	ldmia		@x[0],{@x[0]-@x[7]}	@ load second half
++
++	add		@x[0],@x[0],@t[0]	@ accumulate key material
++	 add		@t[0],sp,#4*(12)
++	add		@x[1],@x[1],@t[1]
++	add		@x[2],@x[2],@t[2]
++	add		@x[3],@x[3],@t[3]
++	 ldmia		@t[0],{@t[0]-@t[3]}	@ load key material
++
++	add		@x[4],@x[4],@t[0]	@ accumulate key material
++	 add		@t[0],sp,#4*(8)
++	add		@x[5],@x[5],@t[1]
++	 add		@x[4],@x[4],#3		@ counter+3
++	add		@x[6],@x[6],@t[2]
++	add		@x[7],@x[7],@t[3]
++	 ldr		@t[3],[sp,#4*(32+2)]	@ re-load len
++# ifdef	__ARMEB__
++	rev		@x[0],@x[0]
++	rev		@x[1],@x[1]
++	rev		@x[2],@x[2]
++	rev		@x[3],@x[3]
++	rev		@x[4],@x[4]
++	rev		@x[5],@x[5]
++	rev		@x[6],@x[6]
++	rev		@x[7],@x[7]
++# endif
++	stmia		@t[0],{@x[0]-@x[7]}
++	 add		@t[2],sp,#4*(0)
++	 sub		@t[3],@t[3],#64*3	@ len-=64*3
++
++.Loop_tail_neon:
++	ldrb		@t[0],[@t[2]],#1	@ read buffer on stack
++	ldrb		@t[1],[r12],#1		@ read input
++	subs		@t[3],@t[3],#1
++	eor		@t[0],@t[0],@t[1]
++	strb		@t[0],[r14],#1		@ store output
++	bne		.Loop_tail_neon
++
++.Ldone_neon:
++	add		sp,sp,#4*(32+4)
++	vldmia		sp,{d8-d15}
++	add		sp,sp,#4*(16+3)
++	ldmia		sp!,{r4-r11,pc}
++.size	ChaCha20_neon,.-ChaCha20_neon
++.comm	OPENSSL_armcap_P,4,4
++#endif
++___
++}}}
++
++foreach (split("\n",$code)) {
++	s/\`([^\`]*)\`/eval $1/geo;
++
++	s/\bq([0-9]+)#(lo|hi)/sprintf "d%d",2*$1+($2 eq "hi")/geo;
++
++	print $_,"\n";
++}
++close STDOUT;
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/chacha/asm/chacha-armv8.pl b/CryptoPkg/Library/OpensslLib/openssl/crypto/chacha/asm/chacha-armv8.pl
+new file mode 100755
+index 0000000..f7e1074
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/chacha/asm/chacha-armv8.pl
+@@ -0,0 +1,1135 @@
++#! /usr/bin/env perl
++# Copyright 2016 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
++# in the file LICENSE in the source distribution or at
++# https://www.openssl.org/source/license.html
++
++#
++# ====================================================================
++# Written by Andy Polyakov  for the OpenSSL
++# project. The module is, however, dual licensed under OpenSSL and
++# CRYPTOGAMS licenses depending on where you obtain it. For further
++# details see http://www.openssl.org/~appro/cryptogams/.
++# ====================================================================
++#
++# June 2015
++# 
++# ChaCha20 for ARMv8.
++#
++# Performance in cycles per byte out of large buffer.
++#
++#			IALU/gcc-4.9    3xNEON+1xIALU	6xNEON+2xIALU
++#
++# Apple A7		5.50/+49%       3.33            1.70
++# Cortex-A53		8.40/+80%       4.72		4.72(*)
++# Cortex-A57		8.06/+43%       4.90            4.43(**)
++# Denver		4.50/+82%       2.63		2.67(*)
++# X-Gene		9.50/+46%       8.82		8.89(*)
++# Mongoose		8.00/+44%	3.64		3.25
++#
++# (*)	it's expected that doubling interleave factor doesn't help
++#	all processors, only those with higher NEON latency and
++#	higher instruction issue rate;
++# (**)	expected improvement was actually higher;
++
++$flavour=shift;
++$output=shift;
++
++$0 =~ m/(.*[\/\\])[^\/\\]+$/; $dir=$1;
++( $xlate="${dir}arm-xlate.pl" and -f $xlate ) or
++( $xlate="${dir}../../perlasm/arm-xlate.pl" and -f $xlate) or
++die "can't locate arm-xlate.pl";
++
++open OUT,"| \"$^X\" $xlate $flavour $output";
++*STDOUT=*OUT;
++
++sub AUTOLOAD()		# thunk [simplified] x86-style perlasm
++{ my $opcode = $AUTOLOAD; $opcode =~ s/.*:://; $opcode =~ s/_/\./;
++  my $arg = pop;
++    $arg = "#$arg" if ($arg*1 eq $arg);
++    $code .= "\t$opcode\t".join(',',@_,$arg)."\n";
++}
++
++my ($out,$inp,$len,$key,$ctr) = map("x$_",(0..4));
++
++my @x=map("x$_",(5..17,19..21));
++my @d=map("x$_",(22..28,30));
++
++sub ROUND {
++my ($a0,$b0,$c0,$d0)=@_;
++my ($a1,$b1,$c1,$d1)=map(($_&~3)+(($_+1)&3),($a0,$b0,$c0,$d0));
++my ($a2,$b2,$c2,$d2)=map(($_&~3)+(($_+1)&3),($a1,$b1,$c1,$d1));
++my ($a3,$b3,$c3,$d3)=map(($_&~3)+(($_+1)&3),($a2,$b2,$c2,$d2));
++
++    (
++	"&add_32	(@x[$a0],@x[$a0],@x[$b0])",
++	 "&add_32	(@x[$a1],@x[$a1],@x[$b1])",
++	  "&add_32	(@x[$a2],@x[$a2],@x[$b2])",
++	   "&add_32	(@x[$a3],@x[$a3],@x[$b3])",
++	"&eor_32	(@x[$d0],@x[$d0],@x[$a0])",
++	 "&eor_32	(@x[$d1],@x[$d1],@x[$a1])",
++	  "&eor_32	(@x[$d2],@x[$d2],@x[$a2])",
++	   "&eor_32	(@x[$d3],@x[$d3],@x[$a3])",
++	"&ror_32	(@x[$d0],@x[$d0],16)",
++	 "&ror_32	(@x[$d1],@x[$d1],16)",
++	  "&ror_32	(@x[$d2],@x[$d2],16)",
++	   "&ror_32	(@x[$d3],@x[$d3],16)",
++
++	"&add_32	(@x[$c0],@x[$c0],@x[$d0])",
++	 "&add_32	(@x[$c1],@x[$c1],@x[$d1])",
++	  "&add_32	(@x[$c2],@x[$c2],@x[$d2])",
++	   "&add_32	(@x[$c3],@x[$c3],@x[$d3])",
++	"&eor_32	(@x[$b0],@x[$b0],@x[$c0])",
++	 "&eor_32	(@x[$b1],@x[$b1],@x[$c1])",
++	  "&eor_32	(@x[$b2],@x[$b2],@x[$c2])",
++	   "&eor_32	(@x[$b3],@x[$b3],@x[$c3])",
++	"&ror_32	(@x[$b0],@x[$b0],20)",
++	 "&ror_32	(@x[$b1],@x[$b1],20)",
++	  "&ror_32	(@x[$b2],@x[$b2],20)",
++	   "&ror_32	(@x[$b3],@x[$b3],20)",
++
++	"&add_32	(@x[$a0],@x[$a0],@x[$b0])",
++	 "&add_32	(@x[$a1],@x[$a1],@x[$b1])",
++	  "&add_32	(@x[$a2],@x[$a2],@x[$b2])",
++	   "&add_32	(@x[$a3],@x[$a3],@x[$b3])",
++	"&eor_32	(@x[$d0],@x[$d0],@x[$a0])",
++	 "&eor_32	(@x[$d1],@x[$d1],@x[$a1])",
++	  "&eor_32	(@x[$d2],@x[$d2],@x[$a2])",
++	   "&eor_32	(@x[$d3],@x[$d3],@x[$a3])",
++	"&ror_32	(@x[$d0],@x[$d0],24)",
++	 "&ror_32	(@x[$d1],@x[$d1],24)",
++	  "&ror_32	(@x[$d2],@x[$d2],24)",
++	   "&ror_32	(@x[$d3],@x[$d3],24)",
++
++	"&add_32	(@x[$c0],@x[$c0],@x[$d0])",
++	 "&add_32	(@x[$c1],@x[$c1],@x[$d1])",
++	  "&add_32	(@x[$c2],@x[$c2],@x[$d2])",
++	   "&add_32	(@x[$c3],@x[$c3],@x[$d3])",
++	"&eor_32	(@x[$b0],@x[$b0],@x[$c0])",
++	 "&eor_32	(@x[$b1],@x[$b1],@x[$c1])",
++	  "&eor_32	(@x[$b2],@x[$b2],@x[$c2])",
++	   "&eor_32	(@x[$b3],@x[$b3],@x[$c3])",
++	"&ror_32	(@x[$b0],@x[$b0],25)",
++	 "&ror_32	(@x[$b1],@x[$b1],25)",
++	  "&ror_32	(@x[$b2],@x[$b2],25)",
++	   "&ror_32	(@x[$b3],@x[$b3],25)"
++    );
++}
++
++$code.=<<___;
++#include "arm_arch.h"
++
++.text
++
++.extern	OPENSSL_armcap_P
++
++.align	5
++.Lsigma:
++.quad	0x3320646e61707865,0x6b20657479622d32		// endian-neutral
++.Lone:
++.long	1,0,0,0
++.LOPENSSL_armcap_P:
++#ifdef	__ILP32__
++.long	OPENSSL_armcap_P-.
++#else
++.quad	OPENSSL_armcap_P-.
++#endif
++.asciz	"ChaCha20 for ARMv8, CRYPTOGAMS by "
++
++.globl	ChaCha20_ctr32
++.type	ChaCha20_ctr32,%function
++.align	5
++ChaCha20_ctr32:
++	cbz	$len,.Labort
++	adr	@x[0],.LOPENSSL_armcap_P
++	cmp	$len,#192
++	b.lo	.Lshort
++#ifdef	__ILP32__
++	ldrsw	@x[1],[@x[0]]
++#else
++	ldr	@x[1],[@x[0]]
++#endif
++	ldr	w17,[@x[1],@x[0]]
++	tst	w17,#ARMV7_NEON
++	b.ne	ChaCha20_neon
++
++.Lshort:
++	stp	x29,x30,[sp,#-96]!
++	add	x29,sp,#0
++
++	adr	@x[0],.Lsigma
++	stp	x19,x20,[sp,#16]
++	stp	x21,x22,[sp,#32]
++	stp	x23,x24,[sp,#48]
++	stp	x25,x26,[sp,#64]
++	stp	x27,x28,[sp,#80]
++	sub	sp,sp,#64
++
++	ldp	@d[0],@d[1],[@x[0]]		// load sigma
++	ldp	@d[2],@d[3],[$key]		// load key
++	ldp	@d[4],@d[5],[$key,#16]
++	ldp	@d[6],@d[7],[$ctr]		// load counter
++#ifdef	__ARMEB__
++	ror	@d[2],@d[2],#32
++	ror	@d[3],@d[3],#32
++	ror	@d[4],@d[4],#32
++	ror	@d[5],@d[5],#32
++	ror	@d[6],@d[6],#32
++	ror	@d[7],@d[7],#32
++#endif
++
++.Loop_outer:
++	mov.32	@x[0],@d[0]			// unpack key block
++	lsr	@x[1],@d[0],#32
++	mov.32	@x[2],@d[1]
++	lsr	@x[3],@d[1],#32
++	mov.32	@x[4],@d[2]
++	lsr	@x[5],@d[2],#32
++	mov.32	@x[6],@d[3]
++	lsr	@x[7],@d[3],#32
++	mov.32	@x[8],@d[4]
++	lsr	@x[9],@d[4],#32
++	mov.32	@x[10],@d[5]
++	lsr	@x[11],@d[5],#32
++	mov.32	@x[12],@d[6]
++	lsr	@x[13],@d[6],#32
++	mov.32	@x[14],@d[7]
++	lsr	@x[15],@d[7],#32
++
++	mov	$ctr,#10
++	subs	$len,$len,#64
++.Loop:
++	sub	$ctr,$ctr,#1	
++___
++	foreach (&ROUND(0, 4, 8,12)) { eval; }
++	foreach (&ROUND(0, 5,10,15)) { eval; }
++$code.=<<___;
++	cbnz	$ctr,.Loop
++
++	add.32	@x[0],@x[0],@d[0]		// accumulate key block
++	add	@x[1],@x[1],@d[0],lsr#32
++	add.32	@x[2],@x[2],@d[1]
++	add	@x[3],@x[3],@d[1],lsr#32
++	add.32	@x[4],@x[4],@d[2]
++	add	@x[5],@x[5],@d[2],lsr#32
++	add.32	@x[6],@x[6],@d[3]
++	add	@x[7],@x[7],@d[3],lsr#32
++	add.32	@x[8],@x[8],@d[4]
++	add	@x[9],@x[9],@d[4],lsr#32
++	add.32	@x[10],@x[10],@d[5]
++	add	@x[11],@x[11],@d[5],lsr#32
++	add.32	@x[12],@x[12],@d[6]
++	add	@x[13],@x[13],@d[6],lsr#32
++	add.32	@x[14],@x[14],@d[7]
++	add	@x[15],@x[15],@d[7],lsr#32
++
++	b.lo	.Ltail
++
++	add	@x[0],@x[0],@x[1],lsl#32	// pack
++	add	@x[2],@x[2],@x[3],lsl#32
++	ldp	@x[1],@x[3],[$inp,#0]		// load input
++	add	@x[4],@x[4],@x[5],lsl#32
++	add	@x[6],@x[6],@x[7],lsl#32
++	ldp	@x[5],@x[7],[$inp,#16]
++	add	@x[8],@x[8],@x[9],lsl#32
++	add	@x[10],@x[10],@x[11],lsl#32
++	ldp	@x[9],@x[11],[$inp,#32]
++	add	@x[12],@x[12],@x[13],lsl#32
++	add	@x[14],@x[14],@x[15],lsl#32
++	ldp	@x[13],@x[15],[$inp,#48]
++	add	$inp,$inp,#64
++#ifdef	__ARMEB__
++	rev	@x[0],@x[0]
++	rev	@x[2],@x[2]
++	rev	@x[4],@x[4]
++	rev	@x[6],@x[6]
++	rev	@x[8],@x[8]
++	rev	@x[10],@x[10]
++	rev	@x[12],@x[12]
++	rev	@x[14],@x[14]
++#endif
++	eor	@x[0],@x[0],@x[1]
++	eor	@x[2],@x[2],@x[3]
++	eor	@x[4],@x[4],@x[5]
++	eor	@x[6],@x[6],@x[7]
++	eor	@x[8],@x[8],@x[9]
++	eor	@x[10],@x[10],@x[11]
++	eor	@x[12],@x[12],@x[13]
++	eor	@x[14],@x[14],@x[15]
++
++	stp	@x[0],@x[2],[$out,#0]		// store output
++	 add	@d[6],@d[6],#1			// increment counter
++	stp	@x[4],@x[6],[$out,#16]
++	stp	@x[8],@x[10],[$out,#32]
++	stp	@x[12],@x[14],[$out,#48]
++	add	$out,$out,#64
++
++	b.hi	.Loop_outer
++
++	ldp	x19,x20,[x29,#16]
++	add	sp,sp,#64
++	ldp	x21,x22,[x29,#32]
++	ldp	x23,x24,[x29,#48]
++	ldp	x25,x26,[x29,#64]
++	ldp	x27,x28,[x29,#80]
++	ldp	x29,x30,[sp],#96
++.Labort:
++	ret
++
++.align	4
++.Ltail:
++	add	$len,$len,#64
++.Less_than_64:
++	sub	$out,$out,#1
++	add	$inp,$inp,$len
++	add	$out,$out,$len
++	add	$ctr,sp,$len
++	neg	$len,$len
++
++	add	@x[0],@x[0],@x[1],lsl#32	// pack
++	add	@x[2],@x[2],@x[3],lsl#32
++	add	@x[4],@x[4],@x[5],lsl#32
++	add	@x[6],@x[6],@x[7],lsl#32
++	add	@x[8],@x[8],@x[9],lsl#32
++	add	@x[10],@x[10],@x[11],lsl#32
++	add	@x[12],@x[12],@x[13],lsl#32
++	add	@x[14],@x[14],@x[15],lsl#32
++#ifdef	__ARMEB__
++	rev	@x[0],@x[0]
++	rev	@x[2],@x[2]
++	rev	@x[4],@x[4]
++	rev	@x[6],@x[6]
++	rev	@x[8],@x[8]
++	rev	@x[10],@x[10]
++	rev	@x[12],@x[12]
++	rev	@x[14],@x[14]
++#endif
++	stp	@x[0],@x[2],[sp,#0]
++	stp	@x[4],@x[6],[sp,#16]
++	stp	@x[8],@x[10],[sp,#32]
++	stp	@x[12],@x[14],[sp,#48]
++
++.Loop_tail:
++	ldrb	w10,[$inp,$len]
++	ldrb	w11,[$ctr,$len]
++	add	$len,$len,#1
++	eor	w10,w10,w11
++	strb	w10,[$out,$len]
++	cbnz	$len,.Loop_tail
++
++	stp	xzr,xzr,[sp,#0]
++	stp	xzr,xzr,[sp,#16]
++	stp	xzr,xzr,[sp,#32]
++	stp	xzr,xzr,[sp,#48]
++
++	ldp	x19,x20,[x29,#16]
++	add	sp,sp,#64
++	ldp	x21,x22,[x29,#32]
++	ldp	x23,x24,[x29,#48]
++	ldp	x25,x26,[x29,#64]
++	ldp	x27,x28,[x29,#80]
++	ldp	x29,x30,[sp],#96
++	ret
++.size	ChaCha20_ctr32,.-ChaCha20_ctr32
++___
++
++{{{
++my ($A0,$B0,$C0,$D0,$A1,$B1,$C1,$D1,$A2,$B2,$C2,$D2,$T0,$T1,$T2,$T3) =
++    map("v$_.4s",(0..7,16..23));
++my (@K)=map("v$_.4s",(24..30));
++my $ONE="v31.4s";
++
++sub NEONROUND {
++my $odd = pop;
++my ($a,$b,$c,$d,$t)=@_;
++
++	(
++	"&add		('$a','$a','$b')",
++	"&eor		('$d','$d','$a')",
++	"&rev32_16	('$d','$d')",		# vrot ($d,16)
++
++	"&add		('$c','$c','$d')",
++	"&eor		('$t','$b','$c')",
++	"&ushr		('$b','$t',20)",
++	"&sli		('$b','$t',12)",
++
++	"&add		('$a','$a','$b')",
++	"&eor		('$t','$d','$a')",
++	"&ushr		('$d','$t',24)",
++	"&sli		('$d','$t',8)",
++
++	"&add		('$c','$c','$d')",
++	"&eor		('$t','$b','$c')",
++	"&ushr		('$b','$t',25)",
++	"&sli		('$b','$t',7)",
++
++	"&ext		('$c','$c','$c',8)",
++	"&ext		('$d','$d','$d',$odd?4:12)",
++	"&ext		('$b','$b','$b',$odd?12:4)"
++	);
++}
++
++$code.=<<___;
++
++.type	ChaCha20_neon,%function
++.align	5
++ChaCha20_neon:
++	stp	x29,x30,[sp,#-96]!
++	add	x29,sp,#0
++
++	adr	@x[0],.Lsigma
++	stp	x19,x20,[sp,#16]
++	stp	x21,x22,[sp,#32]
++	stp	x23,x24,[sp,#48]
++	stp	x25,x26,[sp,#64]
++	stp	x27,x28,[sp,#80]
++	cmp	$len,#512
++	b.hs	.L512_or_more_neon
++
++	sub	sp,sp,#64
++
++	ldp	@d[0],@d[1],[@x[0]]		// load sigma
++	ld1	{@K[0]},[@x[0]],#16
++	ldp	@d[2],@d[3],[$key]		// load key
++	ldp	@d[4],@d[5],[$key,#16]
++	ld1	{@K[1],@K[2]},[$key]
++	ldp	@d[6],@d[7],[$ctr]		// load counter
++	ld1	{@K[3]},[$ctr]
++	ld1	{$ONE},[@x[0]]
++#ifdef	__ARMEB__
++	rev64	@K[0],@K[0]
++	ror	@d[2],@d[2],#32
++	ror	@d[3],@d[3],#32
++	ror	@d[4],@d[4],#32
++	ror	@d[5],@d[5],#32
++	ror	@d[6],@d[6],#32
++	ror	@d[7],@d[7],#32
++#endif
++	add	@K[3],@K[3],$ONE		// += 1
++	add	@K[4],@K[3],$ONE
++	add	@K[5],@K[4],$ONE
++	shl	$ONE,$ONE,#2			// 1 -> 4
++
++.Loop_outer_neon:
++	mov.32	@x[0],@d[0]			// unpack key block
++	lsr	@x[1],@d[0],#32
++	 mov	$A0,@K[0]
++	mov.32	@x[2],@d[1]
++	lsr	@x[3],@d[1],#32
++	 mov	$A1,@K[0]
++	mov.32	@x[4],@d[2]
++	lsr	@x[5],@d[2],#32
++	 mov	$A2,@K[0]
++	mov.32	@x[6],@d[3]
++	 mov	$B0,@K[1]
++	lsr	@x[7],@d[3],#32
++	 mov	$B1,@K[1]
++	mov.32	@x[8],@d[4]
++	 mov	$B2,@K[1]
++	lsr	@x[9],@d[4],#32
++	 mov	$D0,@K[3]
++	mov.32	@x[10],@d[5]
++	 mov	$D1,@K[4]
++	lsr	@x[11],@d[5],#32
++	 mov	$D2,@K[5]
++	mov.32	@x[12],@d[6]
++	 mov	$C0,@K[2]
++	lsr	@x[13],@d[6],#32
++	 mov	$C1,@K[2]
++	mov.32	@x[14],@d[7]
++	 mov	$C2,@K[2]
++	lsr	@x[15],@d[7],#32
++
++	mov	$ctr,#10
++	subs	$len,$len,#256
++.Loop_neon:
++	sub	$ctr,$ctr,#1
++___
++	my @thread0=&NEONROUND($A0,$B0,$C0,$D0,$T0,0);
++	my @thread1=&NEONROUND($A1,$B1,$C1,$D1,$T1,0);
++	my @thread2=&NEONROUND($A2,$B2,$C2,$D2,$T2,0);
++	my @thread3=&ROUND(0,4,8,12);
++
++	foreach (@thread0) {
++		eval;			eval(shift(@thread3));
++		eval(shift(@thread1));	eval(shift(@thread3));
++		eval(shift(@thread2));	eval(shift(@thread3));
++	}
++
++	@thread0=&NEONROUND($A0,$B0,$C0,$D0,$T0,1);
++	@thread1=&NEONROUND($A1,$B1,$C1,$D1,$T1,1);
++	@thread2=&NEONROUND($A2,$B2,$C2,$D2,$T2,1);
++	@thread3=&ROUND(0,5,10,15);
++
++	foreach (@thread0) {
++		eval;			eval(shift(@thread3));
++		eval(shift(@thread1));	eval(shift(@thread3));
++		eval(shift(@thread2));	eval(shift(@thread3));
++	}
++$code.=<<___;
++	cbnz	$ctr,.Loop_neon
++
++	add.32	@x[0],@x[0],@d[0]		// accumulate key block
++	 add	$A0,$A0,@K[0]
++	add	@x[1],@x[1],@d[0],lsr#32
++	 add	$A1,$A1,@K[0]
++	add.32	@x[2],@x[2],@d[1]
++	 add	$A2,$A2,@K[0]
++	add	@x[3],@x[3],@d[1],lsr#32
++	 add	$C0,$C0,@K[2]
++	add.32	@x[4],@x[4],@d[2]
++	 add	$C1,$C1,@K[2]
++	add	@x[5],@x[5],@d[2],lsr#32
++	 add	$C2,$C2,@K[2]
++	add.32	@x[6],@x[6],@d[3]
++	 add	$D0,$D0,@K[3]
++	add	@x[7],@x[7],@d[3],lsr#32
++	add.32	@x[8],@x[8],@d[4]
++	 add	$D1,$D1,@K[4]
++	add	@x[9],@x[9],@d[4],lsr#32
++	add.32	@x[10],@x[10],@d[5]
++	 add	$D2,$D2,@K[5]
++	add	@x[11],@x[11],@d[5],lsr#32
++	add.32	@x[12],@x[12],@d[6]
++	 add	$B0,$B0,@K[1]
++	add	@x[13],@x[13],@d[6],lsr#32
++	add.32	@x[14],@x[14],@d[7]
++	 add	$B1,$B1,@K[1]
++	add	@x[15],@x[15],@d[7],lsr#32
++	 add	$B2,$B2,@K[1]
++
++	b.lo	.Ltail_neon
++
++	add	@x[0],@x[0],@x[1],lsl#32	// pack
++	add	@x[2],@x[2],@x[3],lsl#32
++	ldp	@x[1],@x[3],[$inp,#0]		// load input
++	add	@x[4],@x[4],@x[5],lsl#32
++	add	@x[6],@x[6],@x[7],lsl#32
++	ldp	@x[5],@x[7],[$inp,#16]
++	add	@x[8],@x[8],@x[9],lsl#32
++	add	@x[10],@x[10],@x[11],lsl#32
++	ldp	@x[9],@x[11],[$inp,#32]
++	add	@x[12],@x[12],@x[13],lsl#32
++	add	@x[14],@x[14],@x[15],lsl#32
++	ldp	@x[13],@x[15],[$inp,#48]
++	add	$inp,$inp,#64
++#ifdef	__ARMEB__
++	rev	@x[0],@x[0]
++	rev	@x[2],@x[2]
++	rev	@x[4],@x[4]
++	rev	@x[6],@x[6]
++	rev	@x[8],@x[8]
++	rev	@x[10],@x[10]
++	rev	@x[12],@x[12]
++	rev	@x[14],@x[14]
++#endif
++	ld1.8	{$T0-$T3},[$inp],#64
++	eor	@x[0],@x[0],@x[1]
++	eor	@x[2],@x[2],@x[3]
++	eor	@x[4],@x[4],@x[5]
++	eor	@x[6],@x[6],@x[7]
++	eor	@x[8],@x[8],@x[9]
++	 eor	$A0,$A0,$T0
++	eor	@x[10],@x[10],@x[11]
++	 eor	$B0,$B0,$T1
++	eor	@x[12],@x[12],@x[13]
++	 eor	$C0,$C0,$T2
++	eor	@x[14],@x[14],@x[15]
++	 eor	$D0,$D0,$T3
++	 ld1.8	{$T0-$T3},[$inp],#64
++
++	stp	@x[0],@x[2],[$out,#0]		// store output
++	 add	@d[6],@d[6],#4			// increment counter
++	stp	@x[4],@x[6],[$out,#16]
++	 add	@K[3],@K[3],$ONE		// += 4
++	stp	@x[8],@x[10],[$out,#32]
++	 add	@K[4],@K[4],$ONE
++	stp	@x[12],@x[14],[$out,#48]
++	 add	@K[5],@K[5],$ONE
++	add	$out,$out,#64
++
++	st1.8	{$A0-$D0},[$out],#64
++	ld1.8	{$A0-$D0},[$inp],#64
++
++	eor	$A1,$A1,$T0
++	eor	$B1,$B1,$T1
++	eor	$C1,$C1,$T2
++	eor	$D1,$D1,$T3
++	st1.8	{$A1-$D1},[$out],#64
++
++	eor	$A2,$A2,$A0
++	eor	$B2,$B2,$B0
++	eor	$C2,$C2,$C0
++	eor	$D2,$D2,$D0
++	st1.8	{$A2-$D2},[$out],#64
++
++	b.hi	.Loop_outer_neon
++
++	ldp	x19,x20,[x29,#16]
++	add	sp,sp,#64
++	ldp	x21,x22,[x29,#32]
++	ldp	x23,x24,[x29,#48]
++	ldp	x25,x26,[x29,#64]
++	ldp	x27,x28,[x29,#80]
++	ldp	x29,x30,[sp],#96
++	ret
++
++.Ltail_neon:
++	add	$len,$len,#256
++	cmp	$len,#64
++	b.lo	.Less_than_64
++
++	add	@x[0],@x[0],@x[1],lsl#32	// pack
++	add	@x[2],@x[2],@x[3],lsl#32
++	ldp	@x[1],@x[3],[$inp,#0]		// load input
++	add	@x[4],@x[4],@x[5],lsl#32
++	add	@x[6],@x[6],@x[7],lsl#32
++	ldp	@x[5],@x[7],[$inp,#16]
++	add	@x[8],@x[8],@x[9],lsl#32
++	add	@x[10],@x[10],@x[11],lsl#32
++	ldp	@x[9],@x[11],[$inp,#32]
++	add	@x[12],@x[12],@x[13],lsl#32
++	add	@x[14],@x[14],@x[15],lsl#32
++	ldp	@x[13],@x[15],[$inp,#48]
++	add	$inp,$inp,#64
++#ifdef	__ARMEB__
++	rev	@x[0],@x[0]
++	rev	@x[2],@x[2]
++	rev	@x[4],@x[4]
++	rev	@x[6],@x[6]
++	rev	@x[8],@x[8]
++	rev	@x[10],@x[10]
++	rev	@x[12],@x[12]
++	rev	@x[14],@x[14]
++#endif
++	eor	@x[0],@x[0],@x[1]
++	eor	@x[2],@x[2],@x[3]
++	eor	@x[4],@x[4],@x[5]
++	eor	@x[6],@x[6],@x[7]
++	eor	@x[8],@x[8],@x[9]
++	eor	@x[10],@x[10],@x[11]
++	eor	@x[12],@x[12],@x[13]
++	eor	@x[14],@x[14],@x[15]
++
++	stp	@x[0],@x[2],[$out,#0]		// store output
++	 add	@d[6],@d[6],#4			// increment counter
++	stp	@x[4],@x[6],[$out,#16]
++	stp	@x[8],@x[10],[$out,#32]
++	stp	@x[12],@x[14],[$out,#48]
++	add	$out,$out,#64
++	b.eq	.Ldone_neon
++	sub	$len,$len,#64
++	cmp	$len,#64
++	b.lo	.Less_than_128
++
++	ld1.8	{$T0-$T3},[$inp],#64
++	eor	$A0,$A0,$T0
++	eor	$B0,$B0,$T1
++	eor	$C0,$C0,$T2
++	eor	$D0,$D0,$T3
++	st1.8	{$A0-$D0},[$out],#64
++	b.eq	.Ldone_neon
++	sub	$len,$len,#64
++	cmp	$len,#64
++	b.lo	.Less_than_192
++
++	ld1.8	{$T0-$T3},[$inp],#64
++	eor	$A1,$A1,$T0
++	eor	$B1,$B1,$T1
++	eor	$C1,$C1,$T2
++	eor	$D1,$D1,$T3
++	st1.8	{$A1-$D1},[$out],#64
++	b.eq	.Ldone_neon
++	sub	$len,$len,#64
++
++	st1.8	{$A2-$D2},[sp]
++	b	.Last_neon
++
++.Less_than_128:
++	st1.8	{$A0-$D0},[sp]
++	b	.Last_neon
++.Less_than_192:
++	st1.8	{$A1-$D1},[sp]
++	b	.Last_neon
++
++.align	4
++.Last_neon:
++	sub	$out,$out,#1
++	add	$inp,$inp,$len
++	add	$out,$out,$len
++	add	$ctr,sp,$len
++	neg	$len,$len
++
++.Loop_tail_neon:
++	ldrb	w10,[$inp,$len]
++	ldrb	w11,[$ctr,$len]
++	add	$len,$len,#1
++	eor	w10,w10,w11
++	strb	w10,[$out,$len]
++	cbnz	$len,.Loop_tail_neon
++
++	stp	xzr,xzr,[sp,#0]
++	stp	xzr,xzr,[sp,#16]
++	stp	xzr,xzr,[sp,#32]
++	stp	xzr,xzr,[sp,#48]
++
++.Ldone_neon:
++	ldp	x19,x20,[x29,#16]
++	add	sp,sp,#64
++	ldp	x21,x22,[x29,#32]
++	ldp	x23,x24,[x29,#48]
++	ldp	x25,x26,[x29,#64]
++	ldp	x27,x28,[x29,#80]
++	ldp	x29,x30,[sp],#96
++	ret
++.size	ChaCha20_neon,.-ChaCha20_neon
++___
++{
++my ($T0,$T1,$T2,$T3,$T4,$T5)=@K;
++my ($A0,$B0,$C0,$D0,$A1,$B1,$C1,$D1,$A2,$B2,$C2,$D2,
++    $A3,$B3,$C3,$D3,$A4,$B4,$C4,$D4,$A5,$B5,$C5,$D5) = map("v$_.4s",(0..23));
++
++$code.=<<___;
++.type	ChaCha20_512_neon,%function
++.align	5
++ChaCha20_512_neon:
++	stp	x29,x30,[sp,#-96]!
++	add	x29,sp,#0
++
++	adr	@x[0],.Lsigma
++	stp	x19,x20,[sp,#16]
++	stp	x21,x22,[sp,#32]
++	stp	x23,x24,[sp,#48]
++	stp	x25,x26,[sp,#64]
++	stp	x27,x28,[sp,#80]
++
++.L512_or_more_neon:
++	sub	sp,sp,#128+64
++
++	ldp	@d[0],@d[1],[@x[0]]		// load sigma
++	ld1	{@K[0]},[@x[0]],#16
++	ldp	@d[2],@d[3],[$key]		// load key
++	ldp	@d[4],@d[5],[$key,#16]
++	ld1	{@K[1],@K[2]},[$key]
++	ldp	@d[6],@d[7],[$ctr]		// load counter
++	ld1	{@K[3]},[$ctr]
++	ld1	{$ONE},[@x[0]]
++#ifdef	__ARMEB__
++	rev64	@K[0],@K[0]
++	ror	@d[2],@d[2],#32
++	ror	@d[3],@d[3],#32
++	ror	@d[4],@d[4],#32
++	ror	@d[5],@d[5],#32
++	ror	@d[6],@d[6],#32
++	ror	@d[7],@d[7],#32
++#endif
++	add	@K[3],@K[3],$ONE		// += 1
++	stp	@K[0],@K[1],[sp,#0]		// off-load key block, invariant part
++	add	@K[3],@K[3],$ONE		// not typo
++	str	@K[2],[sp,#32]
++	add	@K[4],@K[3],$ONE
++	add	@K[5],@K[4],$ONE
++	add	@K[6],@K[5],$ONE
++	shl	$ONE,$ONE,#2			// 1 -> 4
++
++	stp	d8,d9,[sp,#128+0]		// meet ABI requirements
++	stp	d10,d11,[sp,#128+16]
++	stp	d12,d13,[sp,#128+32]
++	stp	d14,d15,[sp,#128+48]
++
++	sub	$len,$len,#512			// not typo
++
++.Loop_outer_512_neon:
++	 mov	$A0,@K[0]
++	 mov	$A1,@K[0]
++	 mov	$A2,@K[0]
++	 mov	$A3,@K[0]
++	 mov	$A4,@K[0]
++	 mov	$A5,@K[0]
++	 mov	$B0,@K[1]
++	mov.32	@x[0],@d[0]			// unpack key block
++	 mov	$B1,@K[1]
++	lsr	@x[1],@d[0],#32
++	 mov	$B2,@K[1]
++	mov.32	@x[2],@d[1]
++	 mov	$B3,@K[1]
++	lsr	@x[3],@d[1],#32
++	 mov	$B4,@K[1]
++	mov.32	@x[4],@d[2]
++	 mov	$B5,@K[1]
++	lsr	@x[5],@d[2],#32
++	 mov	$D0,@K[3]
++	mov.32	@x[6],@d[3]
++	 mov	$D1,@K[4]
++	lsr	@x[7],@d[3],#32
++	 mov	$D2,@K[5]
++	mov.32	@x[8],@d[4]
++	 mov	$D3,@K[6]
++	lsr	@x[9],@d[4],#32
++	 mov	$C0,@K[2]
++	mov.32	@x[10],@d[5]
++	 mov	$C1,@K[2]
++	lsr	@x[11],@d[5],#32
++	 add	$D4,$D0,$ONE			// +4
++	mov.32	@x[12],@d[6]
++	 add	$D5,$D1,$ONE			// +4
++	lsr	@x[13],@d[6],#32
++	 mov	$C2,@K[2]
++	mov.32	@x[14],@d[7]
++	 mov	$C3,@K[2]
++	lsr	@x[15],@d[7],#32
++	 mov	$C4,@K[2]
++	 stp	@K[3],@K[4],[sp,#48]		// off-load key block, variable part
++	 mov	$C5,@K[2]
++	 str	@K[5],[sp,#80]
++
++	mov	$ctr,#5
++	subs	$len,$len,#512
++.Loop_upper_neon:
++	sub	$ctr,$ctr,#1
++___
++	my @thread0=&NEONROUND($A0,$B0,$C0,$D0,$T0,0);
++	my @thread1=&NEONROUND($A1,$B1,$C1,$D1,$T1,0);
++	my @thread2=&NEONROUND($A2,$B2,$C2,$D2,$T2,0);
++	my @thread3=&NEONROUND($A3,$B3,$C3,$D3,$T3,0);
++	my @thread4=&NEONROUND($A4,$B4,$C4,$D4,$T4,0);
++	my @thread5=&NEONROUND($A5,$B5,$C5,$D5,$T5,0);
++	my @thread67=(&ROUND(0,4,8,12),&ROUND(0,5,10,15));
++	my $diff = ($#thread0+1)*6 - $#thread67 - 1;
++	my $i = 0;
++
++	foreach (@thread0) {
++		eval;			eval(shift(@thread67));
++		eval(shift(@thread1));	eval(shift(@thread67));
++		eval(shift(@thread2));	eval(shift(@thread67));
++		eval(shift(@thread3));	eval(shift(@thread67));
++		eval(shift(@thread4));	eval(shift(@thread67));
++		eval(shift(@thread5));	eval(shift(@thread67));
++	}
++
++	@thread0=&NEONROUND($A0,$B0,$C0,$D0,$T0,1);
++	@thread1=&NEONROUND($A1,$B1,$C1,$D1,$T1,1);
++	@thread2=&NEONROUND($A2,$B2,$C2,$D2,$T2,1);
++	@thread3=&NEONROUND($A3,$B3,$C3,$D3,$T3,1);
++	@thread4=&NEONROUND($A4,$B4,$C4,$D4,$T4,1);
++	@thread5=&NEONROUND($A5,$B5,$C5,$D5,$T5,1);
++	@thread67=(&ROUND(0,4,8,12),&ROUND(0,5,10,15));
++
++	foreach (@thread0) {
++		eval;			eval(shift(@thread67));
++		eval(shift(@thread1));	eval(shift(@thread67));
++		eval(shift(@thread2));	eval(shift(@thread67));
++		eval(shift(@thread3));	eval(shift(@thread67));
++		eval(shift(@thread4));	eval(shift(@thread67));
++		eval(shift(@thread5));	eval(shift(@thread67));
++	}
++$code.=<<___;
++	cbnz	$ctr,.Loop_upper_neon
++
++	add.32	@x[0],@x[0],@d[0]		// accumulate key block
++	add	@x[1],@x[1],@d[0],lsr#32
++	add.32	@x[2],@x[2],@d[1]
++	add	@x[3],@x[3],@d[1],lsr#32
++	add.32	@x[4],@x[4],@d[2]
++	add	@x[5],@x[5],@d[2],lsr#32
++	add.32	@x[6],@x[6],@d[3]
++	add	@x[7],@x[7],@d[3],lsr#32
++	add.32	@x[8],@x[8],@d[4]
++	add	@x[9],@x[9],@d[4],lsr#32
++	add.32	@x[10],@x[10],@d[5]
++	add	@x[11],@x[11],@d[5],lsr#32
++	add.32	@x[12],@x[12],@d[6]
++	add	@x[13],@x[13],@d[6],lsr#32
++	add.32	@x[14],@x[14],@d[7]
++	add	@x[15],@x[15],@d[7],lsr#32
++
++	add	@x[0],@x[0],@x[1],lsl#32	// pack
++	add	@x[2],@x[2],@x[3],lsl#32
++	ldp	@x[1],@x[3],[$inp,#0]		// load input
++	add	@x[4],@x[4],@x[5],lsl#32
++	add	@x[6],@x[6],@x[7],lsl#32
++	ldp	@x[5],@x[7],[$inp,#16]
++	add	@x[8],@x[8],@x[9],lsl#32
++	add	@x[10],@x[10],@x[11],lsl#32
++	ldp	@x[9],@x[11],[$inp,#32]
++	add	@x[12],@x[12],@x[13],lsl#32
++	add	@x[14],@x[14],@x[15],lsl#32
++	ldp	@x[13],@x[15],[$inp,#48]
++	add	$inp,$inp,#64
++#ifdef	__ARMEB__
++	rev	@x[0],@x[0]
++	rev	@x[2],@x[2]
++	rev	@x[4],@x[4]
++	rev	@x[6],@x[6]
++	rev	@x[8],@x[8]
++	rev	@x[10],@x[10]
++	rev	@x[12],@x[12]
++	rev	@x[14],@x[14]
++#endif
++	eor	@x[0],@x[0],@x[1]
++	eor	@x[2],@x[2],@x[3]
++	eor	@x[4],@x[4],@x[5]
++	eor	@x[6],@x[6],@x[7]
++	eor	@x[8],@x[8],@x[9]
++	eor	@x[10],@x[10],@x[11]
++	eor	@x[12],@x[12],@x[13]
++	eor	@x[14],@x[14],@x[15]
++
++	 stp	@x[0],@x[2],[$out,#0]		// store output
++	 add	@d[6],@d[6],#1			// increment counter
++	mov.32	@x[0],@d[0]			// unpack key block
++	lsr	@x[1],@d[0],#32
++	 stp	@x[4],@x[6],[$out,#16]
++	mov.32	@x[2],@d[1]
++	lsr	@x[3],@d[1],#32
++	 stp	@x[8],@x[10],[$out,#32]
++	mov.32	@x[4],@d[2]
++	lsr	@x[5],@d[2],#32
++	 stp	@x[12],@x[14],[$out,#48]
++	 add	$out,$out,#64
++	mov.32	@x[6],@d[3]
++	lsr	@x[7],@d[3],#32
++	mov.32	@x[8],@d[4]
++	lsr	@x[9],@d[4],#32
++	mov.32	@x[10],@d[5]
++	lsr	@x[11],@d[5],#32
++	mov.32	@x[12],@d[6]
++	lsr	@x[13],@d[6],#32
++	mov.32	@x[14],@d[7]
++	lsr	@x[15],@d[7],#32
++
++	mov	$ctr,#5
++.Loop_lower_neon:
++	sub	$ctr,$ctr,#1
++___
++	@thread0=&NEONROUND($A0,$B0,$C0,$D0,$T0,0);
++	@thread1=&NEONROUND($A1,$B1,$C1,$D1,$T1,0);
++	@thread2=&NEONROUND($A2,$B2,$C2,$D2,$T2,0);
++	@thread3=&NEONROUND($A3,$B3,$C3,$D3,$T3,0);
++	@thread4=&NEONROUND($A4,$B4,$C4,$D4,$T4,0);
++	@thread5=&NEONROUND($A5,$B5,$C5,$D5,$T5,0);
++	@thread67=(&ROUND(0,4,8,12),&ROUND(0,5,10,15));
++
++	foreach (@thread0) {
++		eval;			eval(shift(@thread67));
++		eval(shift(@thread1));	eval(shift(@thread67));
++		eval(shift(@thread2));	eval(shift(@thread67));
++		eval(shift(@thread3));	eval(shift(@thread67));
++		eval(shift(@thread4));	eval(shift(@thread67));
++		eval(shift(@thread5));	eval(shift(@thread67));
++	}
++
++	@thread0=&NEONROUND($A0,$B0,$C0,$D0,$T0,1);
++	@thread1=&NEONROUND($A1,$B1,$C1,$D1,$T1,1);
++	@thread2=&NEONROUND($A2,$B2,$C2,$D2,$T2,1);
++	@thread3=&NEONROUND($A3,$B3,$C3,$D3,$T3,1);
++	@thread4=&NEONROUND($A4,$B4,$C4,$D4,$T4,1);
++	@thread5=&NEONROUND($A5,$B5,$C5,$D5,$T5,1);
++	@thread67=(&ROUND(0,4,8,12),&ROUND(0,5,10,15));
++
++	foreach (@thread0) {
++		eval;			eval(shift(@thread67));
++		eval(shift(@thread1));	eval(shift(@thread67));
++		eval(shift(@thread2));	eval(shift(@thread67));
++		eval(shift(@thread3));	eval(shift(@thread67));
++		eval(shift(@thread4));	eval(shift(@thread67));
++		eval(shift(@thread5));	eval(shift(@thread67));
++	}
++$code.=<<___;
++	cbnz	$ctr,.Loop_lower_neon
++
++	add.32	@x[0],@x[0],@d[0]		// accumulate key block
++	 ldp	@K[0],@K[1],[sp,#0]
++	add	@x[1],@x[1],@d[0],lsr#32
++	 ldp	@K[2],@K[3],[sp,#32]
++	add.32	@x[2],@x[2],@d[1]
++	 ldp	@K[4],@K[5],[sp,#64]
++	add	@x[3],@x[3],@d[1],lsr#32
++	 add	$A0,$A0,@K[0]
++	add.32	@x[4],@x[4],@d[2]
++	 add	$A1,$A1,@K[0]
++	add	@x[5],@x[5],@d[2],lsr#32
++	 add	$A2,$A2,@K[0]
++	add.32	@x[6],@x[6],@d[3]
++	 add	$A3,$A3,@K[0]
++	add	@x[7],@x[7],@d[3],lsr#32
++	 add	$A4,$A4,@K[0]
++	add.32	@x[8],@x[8],@d[4]
++	 add	$A5,$A5,@K[0]
++	add	@x[9],@x[9],@d[4],lsr#32
++	 add	$C0,$C0,@K[2]
++	add.32	@x[10],@x[10],@d[5]
++	 add	$C1,$C1,@K[2]
++	add	@x[11],@x[11],@d[5],lsr#32
++	 add	$C2,$C2,@K[2]
++	add.32	@x[12],@x[12],@d[6]
++	 add	$C3,$C3,@K[2]
++	add	@x[13],@x[13],@d[6],lsr#32
++	 add	$C4,$C4,@K[2]
++	add.32	@x[14],@x[14],@d[7]
++	 add	$C5,$C5,@K[2]
++	add	@x[15],@x[15],@d[7],lsr#32
++	 add	$D4,$D4,$ONE			// +4
++	add	@x[0],@x[0],@x[1],lsl#32	// pack
++	 add	$D5,$D5,$ONE			// +4
++	add	@x[2],@x[2],@x[3],lsl#32
++	 add	$D0,$D0,@K[3]
++	ldp	@x[1],@x[3],[$inp,#0]		// load input
++	 add	$D1,$D1,@K[4]
++	add	@x[4],@x[4],@x[5],lsl#32
++	 add	$D2,$D2,@K[5]
++	add	@x[6],@x[6],@x[7],lsl#32
++	 add	$D3,$D3,@K[6]
++	ldp	@x[5],@x[7],[$inp,#16]
++	 add	$D4,$D4,@K[3]
++	add	@x[8],@x[8],@x[9],lsl#32
++	 add	$D5,$D5,@K[4]
++	add	@x[10],@x[10],@x[11],lsl#32
++	 add	$B0,$B0,@K[1]
++	ldp	@x[9],@x[11],[$inp,#32]
++	 add	$B1,$B1,@K[1]
++	add	@x[12],@x[12],@x[13],lsl#32
++	 add	$B2,$B2,@K[1]
++	add	@x[14],@x[14],@x[15],lsl#32
++	 add	$B3,$B3,@K[1]
++	ldp	@x[13],@x[15],[$inp,#48]
++	 add	$B4,$B4,@K[1]
++	add	$inp,$inp,#64
++	 add	$B5,$B5,@K[1]
++
++#ifdef	__ARMEB__
++	rev	@x[0],@x[0]
++	rev	@x[2],@x[2]
++	rev	@x[4],@x[4]
++	rev	@x[6],@x[6]
++	rev	@x[8],@x[8]
++	rev	@x[10],@x[10]
++	rev	@x[12],@x[12]
++	rev	@x[14],@x[14]
++#endif
++	ld1.8	{$T0-$T3},[$inp],#64
++	eor	@x[0],@x[0],@x[1]
++	eor	@x[2],@x[2],@x[3]
++	eor	@x[4],@x[4],@x[5]
++	eor	@x[6],@x[6],@x[7]
++	eor	@x[8],@x[8],@x[9]
++	 eor	$A0,$A0,$T0
++	eor	@x[10],@x[10],@x[11]
++	 eor	$B0,$B0,$T1
++	eor	@x[12],@x[12],@x[13]
++	 eor	$C0,$C0,$T2
++	eor	@x[14],@x[14],@x[15]
++	 eor	$D0,$D0,$T3
++	 ld1.8	{$T0-$T3},[$inp],#64
++
++	stp	@x[0],@x[2],[$out,#0]		// store output
++	 add	@d[6],@d[6],#7			// increment counter
++	stp	@x[4],@x[6],[$out,#16]
++	stp	@x[8],@x[10],[$out,#32]
++	stp	@x[12],@x[14],[$out,#48]
++	add	$out,$out,#64
++	st1.8	{$A0-$D0},[$out],#64
++
++	ld1.8	{$A0-$D0},[$inp],#64
++	eor	$A1,$A1,$T0
++	eor	$B1,$B1,$T1
++	eor	$C1,$C1,$T2
++	eor	$D1,$D1,$T3
++	st1.8	{$A1-$D1},[$out],#64
++
++	ld1.8	{$A1-$D1},[$inp],#64
++	eor	$A2,$A2,$A0
++	 ldp	@K[0],@K[1],[sp,#0]
++	eor	$B2,$B2,$B0
++	 ldp	@K[2],@K[3],[sp,#32]
++	eor	$C2,$C2,$C0
++	eor	$D2,$D2,$D0
++	st1.8	{$A2-$D2},[$out],#64
++
++	ld1.8	{$A2-$D2},[$inp],#64
++	eor	$A3,$A3,$A1
++	eor	$B3,$B3,$B1
++	eor	$C3,$C3,$C1
++	eor	$D3,$D3,$D1
++	st1.8	{$A3-$D3},[$out],#64
++
++	ld1.8	{$A3-$D3},[$inp],#64
++	eor	$A4,$A4,$A2
++	eor	$B4,$B4,$B2
++	eor	$C4,$C4,$C2
++	eor	$D4,$D4,$D2
++	st1.8	{$A4-$D4},[$out],#64
++
++	shl	$A0,$ONE,#1			// 4 -> 8
++	eor	$A5,$A5,$A3
++	eor	$B5,$B5,$B3
++	eor	$C5,$C5,$C3
++	eor	$D5,$D5,$D3
++	st1.8	{$A5-$D5},[$out],#64
++
++	add	@K[3],@K[3],$A0			// += 8
++	add	@K[4],@K[4],$A0
++	add	@K[5],@K[5],$A0
++	add	@K[6],@K[6],$A0
++
++	b.hs	.Loop_outer_512_neon
++
++	adds	$len,$len,#512
++	ushr	$A0,$ONE,#2			// 4 -> 1
++
++	ldp	d8,d9,[sp,#128+0]		// meet ABI requirements
++	ldp	d10,d11,[sp,#128+16]
++	ldp	d12,d13,[sp,#128+32]
++	ldp	d14,d15,[sp,#128+48]
++
++	stp	@K[0],$ONE,[sp,#0]		// wipe off-load area
++	stp	@K[0],$ONE,[sp,#32]
++	stp	@K[0],$ONE,[sp,#64]
++
++	b.eq	.Ldone_512_neon
++
++	cmp	$len,#192
++	sub	@K[3],@K[3],$A0			// -= 1
++	sub	@K[4],@K[4],$A0
++	sub	@K[5],@K[5],$A0
++	add	sp,sp,#128
++	b.hs	.Loop_outer_neon
++
++	eor	@K[1],@K[1],@K[1]
++	eor	@K[2],@K[2],@K[2]
++	eor	@K[3],@K[3],@K[3]
++	eor	@K[4],@K[4],@K[4]
++	eor	@K[5],@K[5],@K[5]
++	eor	@K[6],@K[6],@K[6]
++	b	.Loop_outer
++
++.Ldone_512_neon:
++	ldp	x19,x20,[x29,#16]
++	add	sp,sp,#128+64
++	ldp	x21,x22,[x29,#32]
++	ldp	x23,x24,[x29,#48]
++	ldp	x25,x26,[x29,#64]
++	ldp	x27,x28,[x29,#80]
++	ldp	x29,x30,[sp],#96
++	ret
++.size	ChaCha20_512_neon,.-ChaCha20_512_neon
++___
++}
++}}}
++
++foreach (split("\n",$code)) {
++	s/\`([^\`]*)\`/eval $1/geo;
++
++	(s/\b([a-z]+)\.32\b/$1/ and (s/x([0-9]+)/w$1/g or 1))	or
++	(m/\b(eor|ext|mov)\b/ and (s/\.4s/\.16b/g or 1))	or
++	(s/\b((?:ld|st)1)\.8\b/$1/ and (s/\.4s/\.16b/g or 1))	or
++	(m/\b(ld|st)[rp]\b/ and (s/v([0-9]+)\.4s/q$1/g or 1))	or
++	(s/\brev32\.16\b/rev32/ and (s/\.4s/\.8h/g or 1));
++
++	#s/\bq([0-9]+)#(lo|hi)/sprintf "d%d",2*$1+($2 eq "hi")/geo;
++
++	print $_,"\n";
++}
++close STDOUT;	# flush
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/chacha/asm/chacha-c64xplus.pl b/CryptoPkg/Library/OpensslLib/openssl/crypto/chacha/asm/chacha-c64xplus.pl
+new file mode 100755
+index 0000000..bdb3804
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/chacha/asm/chacha-c64xplus.pl
+@@ -0,0 +1,926 @@
++#! /usr/bin/env perl
++# Copyright 2016 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
++# in the file LICENSE in the source distribution or at
++# https://www.openssl.org/source/license.html
++
++#
++# ====================================================================
++# Written by Andy Polyakov  for the OpenSSL
++# project. The module is, however, dual licensed under OpenSSL and
++# CRYPTOGAMS licenses depending on where you obtain it. For further
++# details see http://www.openssl.org/~appro/cryptogams/.
++# ====================================================================
++#
++# ChaCha20 for C64x+.
++#
++# October 2015
++#
++# Performance is 3.54 cycles per processed byte, which is ~4.3 times
++# faster than code generated by TI compiler. Compiler also disables
++# interrupts for some reason, thus making interrupt response time
++# dependent on input length. This module on the other hand is free
++# from such limiation.
++
++$output=pop;
++open STDOUT,">$output";
++
++($OUT,$INP,$LEN,$KEYB,$COUNTERA)=("A4","B4","A6","B6","A8");
++($KEYA,$COUNTERB,$STEP)=("A7","B7","A3");
++
++@X=  ("A16","B16","A17","B17","A18","B18","A19","B19",
++      "A20","B20","A21","B21","A22","B22","A23","B23");
++@Y=  ("A24","B24","A25","B25","A26","B26","A27","B27",
++      "A28","B28","A29","B29","A30","B30","A31","B31");
++@DAT=("A6", "A7", "B6", "B7", "A8", "A9", "B8", "B9",
++      "A10","A11","B10","B11","A12","A13","B12","B13");
++
++# yes, overlaps with @DAT, used only in 2x interleave code path...
++@K2x=("A6", "B6", "A7", "B7", "A8", "B8", "A9", "B9",
++      "A10","B10","A11","B11","A2", "B2", "A13","B13");
++
++$code.=<<___;
++	.text
++
++	.if	.ASSEMBLER_VERSION<7000000
++	.asg	0,__TI_EABI__
++	.endif
++	.if	__TI_EABI__
++	.asg	ChaCha20_ctr32,_ChaCha20_ctr32
++	.endif
++
++	.asg	B3,RA
++	.asg	A15,FP
++	.asg	B15,SP
++
++	.global	_ChaCha20_ctr32
++	.align	32
++_ChaCha20_ctr32:
++	.asmfunc	stack_usage(40+64)
++	MV	$LEN,A0			; reassign
++  [!A0]	BNOP	RA			; no data
++|| [A0]	STW	FP,*SP--(40+64)		; save frame pointer and alloca(40+64)
++|| [A0]	MV	SP,FP
++   [A0]	STDW	B13:B12,*SP[4+8]	; ABI says so
++|| [A0]	MV	$KEYB,$KEYA
++|| [A0]	MV	$COUNTERA,$COUNTERB
++   [A0]	STDW	B11:B10,*SP[3+8]
++|| [A0]	STDW	A13:A12,*FP[-3]
++   [A0]	STDW	A11:A10,*FP[-4]
++|| [A0]	MVK	128,$STEP		; 2 * input block size
++
++   [A0]	LDW	*${KEYA}[0],@Y[4]	; load key
++|| [A0]	LDW	*${KEYB}[1],@Y[5]
++|| [A0]	MVK	0x00007865,@Y[0]	; synthesize sigma
++|| [A0]	MVK	0x0000646e,@Y[1]
++   [A0]	LDW	*${KEYA}[2],@Y[6]
++|| [A0]	LDW	*${KEYB}[3],@Y[7]
++|| [A0]	MVKH	0x61700000,@Y[0]
++|| [A0]	MVKH	0x33200000,@Y[1]
++	LDW	*${KEYA}[4],@Y[8]
++||	LDW	*${KEYB}[5],@Y[9]
++||	MVK	0x00002d32,@Y[2]
++||	MVK	0x00006574,@Y[3]
++	LDW	*${KEYA}[6],@Y[10]
++||	LDW	*${KEYB}[7],@Y[11]
++||	MVKH	0x79620000,@Y[2]
++||	MVKH	0x6b200000,@Y[3]
++	LDW	*${COUNTERA}[0],@Y[12]	; load counter||nonce
++||	LDW	*${COUNTERB}[1],@Y[13]
++||	CMPLTU	A0,$STEP,A1		; is length < 2*blocks?
++	LDW	*${COUNTERA}[2],@Y[14]
++||	LDW	*${COUNTERB}[3],@Y[15]
++|| [A1]	BNOP	top1x?
++   [A1]	MVK	64,$STEP		; input block size
++||	MVK	10,B0			; inner loop counter
++
++	DMV	@Y[2],@Y[0],@X[2]:@X[0]	; copy block
++||	DMV	@Y[3],@Y[1],@X[3]:@X[1]
++||[!A1]	STDW	@Y[2]:@Y[0],*FP[-12]	; offload key material to stack
++||[!A1]	STDW	@Y[3]:@Y[1],*SP[2]
++	DMV	@Y[6],@Y[4],@X[6]:@X[4]
++||	DMV	@Y[7],@Y[5],@X[7]:@X[5]
++||[!A1]	STDW	@Y[6]:@Y[4],*FP[-10]
++||[!A1]	STDW	@Y[7]:@Y[5],*SP[4]
++	DMV	@Y[10],@Y[8],@X[10]:@X[8]
++||	DMV	@Y[11],@Y[9],@X[11]:@X[9]
++||[!A1]	STDW	@Y[10]:@Y[8],*FP[-8]
++||[!A1]	STDW	@Y[11]:@Y[9],*SP[6]
++	DMV	@Y[14],@Y[12],@X[14]:@X[12]
++||	DMV	@Y[15],@Y[13],@X[15]:@X[13]
++||[!A1]	MV	@Y[12],@K2x[12]		; counter
++||[!A1]	MV	@Y[13],@K2x[13]
++||[!A1]	STW	@Y[14],*FP[-6*2]
++||[!A1]	STW	@Y[15],*SP[8*2]
++___
++{	################################################################
++	# 2x interleave gives 50% performance improvement
++	#
++my ($a0,$a1,$a2,$a3) = (0..3);
++my ($b0,$b1,$b2,$b3) = (4..7);
++my ($c0,$c1,$c2,$c3) = (8..11);
++my ($d0,$d1,$d2,$d3) = (12..15);
++
++$code.=<<___;
++outer2x?:
++	ADD	@X[$b1],@X[$a1],@X[$a1]
++||	ADD	@X[$b2],@X[$a2],@X[$a2]
++||	ADD	@X[$b0],@X[$a0],@X[$a0]
++||	ADD	@X[$b3],@X[$a3],@X[$a3]
++||	 DMV	@Y[2],@Y[0],@K2x[2]:@K2x[0]
++||	 DMV	@Y[3],@Y[1],@K2x[3]:@K2x[1]
++	XOR	@X[$a1],@X[$d1],@X[$d1]
++||	XOR	@X[$a2],@X[$d2],@X[$d2]
++||	XOR	@X[$a0],@X[$d0],@X[$d0]
++||	XOR	@X[$a3],@X[$d3],@X[$d3]
++||	 DMV	@Y[6],@Y[4],@K2x[6]:@K2x[4]
++||	 DMV	@Y[7],@Y[5],@K2x[7]:@K2x[5]
++	SWAP2	@X[$d1],@X[$d1]		; rotate by 16
++||	SWAP2	@X[$d2],@X[$d2]
++||	SWAP2	@X[$d0],@X[$d0]
++||	SWAP2	@X[$d3],@X[$d3]
++
++	ADD	@X[$d1],@X[$c1],@X[$c1]
++||	ADD	@X[$d2],@X[$c2],@X[$c2]
++||	ADD	@X[$d0],@X[$c0],@X[$c0]
++||	ADD	@X[$d3],@X[$c3],@X[$c3]
++||	 DMV	@Y[10],@Y[8],@K2x[10]:@K2x[8]
++||	 DMV	@Y[11],@Y[9],@K2x[11]:@K2x[9]
++	XOR	@X[$c1],@X[$b1],@X[$b1]
++||	XOR	@X[$c2],@X[$b2],@X[$b2]
++||	XOR	@X[$c0],@X[$b0],@X[$b0]
++||	XOR	@X[$c3],@X[$b3],@X[$b3]
++||	 ADD	1,@Y[12],@Y[12]		; adjust counter for 2nd block
++	ROTL	@X[$b1],12,@X[$b1]
++||	ROTL	@X[$b2],12,@X[$b2]
++||	 MV	@Y[14],@K2x[14]
++||	 MV	@Y[15],@K2x[15]
++top2x?:
++	ROTL	@X[$b0],12,@X[$b0]
++||	ROTL	@X[$b3],12,@X[$b3]
++||	 ADD	@Y[$b1],@Y[$a1],@Y[$a1]
++||	 ADD	@Y[$b2],@Y[$a2],@Y[$a2]
++	 ADD	@Y[$b0],@Y[$a0],@Y[$a0]
++||	 ADD	@Y[$b3],@Y[$a3],@Y[$a3]
++
++||	ADD	@X[$b1],@X[$a1],@X[$a1]
++||	ADD	@X[$b2],@X[$a2],@X[$a2]
++||	 XOR	@Y[$a1],@Y[$d1],@Y[$d1]
++||	 XOR	@Y[$a2],@Y[$d2],@Y[$d2]
++	 XOR	@Y[$a0],@Y[$d0],@Y[$d0]
++||	 XOR	@Y[$a3],@Y[$d3],@Y[$d3]
++||	ADD	@X[$b0],@X[$a0],@X[$a0]
++||	ADD	@X[$b3],@X[$a3],@X[$a3]
++||	XOR	@X[$a1],@X[$d1],@X[$d1]
++||	XOR	@X[$a2],@X[$d2],@X[$d2]
++	XOR	@X[$a0],@X[$d0],@X[$d0]
++||	XOR	@X[$a3],@X[$d3],@X[$d3]
++||	ROTL	@X[$d1],8,@X[$d1]
++||	ROTL	@X[$d2],8,@X[$d2]
++||	 SWAP2	@Y[$d1],@Y[$d1]		; rotate by 16
++||	 SWAP2	@Y[$d2],@Y[$d2]
++||	 SWAP2	@Y[$d0],@Y[$d0]
++||	 SWAP2	@Y[$d3],@Y[$d3]
++	ROTL	@X[$d0],8,@X[$d0]
++||	ROTL	@X[$d3],8,@X[$d3]
++||	 ADD	@Y[$d1],@Y[$c1],@Y[$c1]
++||	 ADD	@Y[$d2],@Y[$c2],@Y[$c2]
++||	 ADD	@Y[$d0],@Y[$c0],@Y[$c0]
++||	 ADD	@Y[$d3],@Y[$c3],@Y[$c3]
++||	BNOP	middle2x1?		; protect from interrupt
++
++	ADD	@X[$d1],@X[$c1],@X[$c1]
++||	ADD	@X[$d2],@X[$c2],@X[$c2]
++||	 XOR	@Y[$c1],@Y[$b1],@Y[$b1]
++||	 XOR	@Y[$c2],@Y[$b2],@Y[$b2]
++||	 XOR	@Y[$c0],@Y[$b0],@Y[$b0]
++||	 XOR	@Y[$c3],@Y[$b3],@Y[$b3]
++	ADD	@X[$d0],@X[$c0],@X[$c0]
++||	ADD	@X[$d3],@X[$c3],@X[$c3]
++||	XOR	@X[$c1],@X[$b1],@X[$b1]
++||	XOR	@X[$c2],@X[$b2],@X[$b2]
++||	ROTL	@X[$d1],0,@X[$d2]	; moved to avoid cross-path stall
++||	ROTL	@X[$d2],0,@X[$d3]
++	XOR	@X[$c0],@X[$b0],@X[$b0]
++||	XOR	@X[$c3],@X[$b3],@X[$b3]
++||	MV	@X[$d0],@X[$d1]
++||	MV	@X[$d3],@X[$d0]
++||	 ROTL	@Y[$b1],12,@Y[$b1]
++||	 ROTL	@Y[$b2],12,@Y[$b2]
++	ROTL	@X[$b1],7,@X[$b0]	; avoided cross-path stall
++||	ROTL	@X[$b2],7,@X[$b1]
++	ROTL	@X[$b0],7,@X[$b3]
++||	ROTL	@X[$b3],7,@X[$b2]
++middle2x1?:
++
++	 ROTL	@Y[$b0],12,@Y[$b0]
++||	 ROTL	@Y[$b3],12,@Y[$b3]
++||	ADD	@X[$b0],@X[$a0],@X[$a0]
++||	ADD	@X[$b1],@X[$a1],@X[$a1]
++	ADD	@X[$b2],@X[$a2],@X[$a2]
++||	ADD	@X[$b3],@X[$a3],@X[$a3]
++
++||	 ADD	@Y[$b1],@Y[$a1],@Y[$a1]
++||	 ADD	@Y[$b2],@Y[$a2],@Y[$a2]
++||	XOR	@X[$a0],@X[$d0],@X[$d0]
++||	XOR	@X[$a1],@X[$d1],@X[$d1]
++	XOR	@X[$a2],@X[$d2],@X[$d2]
++||	XOR	@X[$a3],@X[$d3],@X[$d3]
++||	 ADD	@Y[$b0],@Y[$a0],@Y[$a0]
++||	 ADD	@Y[$b3],@Y[$a3],@Y[$a3]
++||	 XOR	@Y[$a1],@Y[$d1],@Y[$d1]
++||	 XOR	@Y[$a2],@Y[$d2],@Y[$d2]
++	 XOR	@Y[$a0],@Y[$d0],@Y[$d0]
++||	 XOR	@Y[$a3],@Y[$d3],@Y[$d3]
++||	 ROTL	@Y[$d1],8,@Y[$d1]
++||	 ROTL	@Y[$d2],8,@Y[$d2]
++||	SWAP2	@X[$d0],@X[$d0]		; rotate by 16
++||	SWAP2	@X[$d1],@X[$d1]
++||	SWAP2	@X[$d2],@X[$d2]
++||	SWAP2	@X[$d3],@X[$d3]
++	 ROTL	@Y[$d0],8,@Y[$d0]
++||	 ROTL	@Y[$d3],8,@Y[$d3]
++||	ADD	@X[$d0],@X[$c2],@X[$c2]
++||	ADD	@X[$d1],@X[$c3],@X[$c3]
++||	ADD	@X[$d2],@X[$c0],@X[$c0]
++||	ADD	@X[$d3],@X[$c1],@X[$c1]
++||	BNOP	middle2x2?		; protect from interrupt
++
++	 ADD	@Y[$d1],@Y[$c1],@Y[$c1]
++||	 ADD	@Y[$d2],@Y[$c2],@Y[$c2]
++||	XOR	@X[$c2],@X[$b0],@X[$b0]
++||	XOR	@X[$c3],@X[$b1],@X[$b1]
++||	XOR	@X[$c0],@X[$b2],@X[$b2]
++||	XOR	@X[$c1],@X[$b3],@X[$b3]
++	 ADD	@Y[$d0],@Y[$c0],@Y[$c0]
++||	 ADD	@Y[$d3],@Y[$c3],@Y[$c3]
++||	 XOR	@Y[$c1],@Y[$b1],@Y[$b1]
++||	 XOR	@Y[$c2],@Y[$b2],@Y[$b2]
++||	 ROTL	@Y[$d1],0,@Y[$d2]	; moved to avoid cross-path stall
++||	 ROTL	@Y[$d2],0,@Y[$d3]
++	 XOR	@Y[$c0],@Y[$b0],@Y[$b0]
++||	 XOR	@Y[$c3],@Y[$b3],@Y[$b3]
++||	 MV	@Y[$d0],@Y[$d1]
++||	 MV	@Y[$d3],@Y[$d0]
++||	ROTL	@X[$b0],12,@X[$b0]
++||	ROTL	@X[$b1],12,@X[$b1]
++	 ROTL	@Y[$b1],7,@Y[$b0]	; avoided cross-path stall
++||	 ROTL	@Y[$b2],7,@Y[$b1]
++	 ROTL	@Y[$b0],7,@Y[$b3]
++||	 ROTL	@Y[$b3],7,@Y[$b2]
++middle2x2?:
++
++	ROTL	@X[$b2],12,@X[$b2]
++||	ROTL	@X[$b3],12,@X[$b3]
++||	 ADD	@Y[$b0],@Y[$a0],@Y[$a0]
++||	 ADD	@Y[$b1],@Y[$a1],@Y[$a1]
++	 ADD	@Y[$b2],@Y[$a2],@Y[$a2]
++||	 ADD	@Y[$b3],@Y[$a3],@Y[$a3]
++
++||	ADD	@X[$b0],@X[$a0],@X[$a0]
++||	ADD	@X[$b1],@X[$a1],@X[$a1]
++||	 XOR	@Y[$a0],@Y[$d0],@Y[$d0]
++||	 XOR	@Y[$a1],@Y[$d1],@Y[$d1]
++	 XOR	@Y[$a2],@Y[$d2],@Y[$d2]
++||	 XOR	@Y[$a3],@Y[$d3],@Y[$d3]
++||	ADD	@X[$b2],@X[$a2],@X[$a2]
++||	ADD	@X[$b3],@X[$a3],@X[$a3]
++||	XOR	@X[$a0],@X[$d0],@X[$d0]
++||	XOR	@X[$a1],@X[$d1],@X[$d1]
++	XOR	@X[$a2],@X[$d2],@X[$d2]
++||	XOR	@X[$a3],@X[$d3],@X[$d3]
++||	ROTL	@X[$d0],8,@X[$d0]
++||	ROTL	@X[$d1],8,@X[$d1]
++||	 SWAP2	@Y[$d0],@Y[$d0]		; rotate by 16
++||	 SWAP2	@Y[$d1],@Y[$d1]
++||	 SWAP2	@Y[$d2],@Y[$d2]
++||	 SWAP2	@Y[$d3],@Y[$d3]
++	ROTL	@X[$d2],8,@X[$d2]
++||	ROTL	@X[$d3],8,@X[$d3]
++||	 ADD	@Y[$d0],@Y[$c2],@Y[$c2]
++||	 ADD	@Y[$d1],@Y[$c3],@Y[$c3]
++||	 ADD	@Y[$d2],@Y[$c0],@Y[$c0]
++||	 ADD	@Y[$d3],@Y[$c1],@Y[$c1]
++||	BNOP	bottom2x1?		; protect from interrupt
++
++	ADD	@X[$d0],@X[$c2],@X[$c2]
++||	ADD	@X[$d1],@X[$c3],@X[$c3]
++||	 XOR	@Y[$c2],@Y[$b0],@Y[$b0]
++||	 XOR	@Y[$c3],@Y[$b1],@Y[$b1]
++||	 XOR	@Y[$c0],@Y[$b2],@Y[$b2]
++||	 XOR	@Y[$c1],@Y[$b3],@Y[$b3]
++	ADD	@X[$d2],@X[$c0],@X[$c0]
++||	ADD	@X[$d3],@X[$c1],@X[$c1]
++||	XOR	@X[$c2],@X[$b0],@X[$b0]
++||	XOR	@X[$c3],@X[$b1],@X[$b1]
++||	ROTL	@X[$d0],0,@X[$d3]	; moved to avoid cross-path stall
++||	ROTL	@X[$d1],0,@X[$d0]
++	XOR	@X[$c0],@X[$b2],@X[$b2]
++||	XOR	@X[$c1],@X[$b3],@X[$b3]
++||	MV	@X[$d2],@X[$d1]
++||	MV	@X[$d3],@X[$d2]
++||	 ROTL	@Y[$b0],12,@Y[$b0]
++||	 ROTL	@Y[$b1],12,@Y[$b1]
++	ROTL	@X[$b0],7,@X[$b1]	; avoided cross-path stall
++||	ROTL	@X[$b1],7,@X[$b2]
++	ROTL	@X[$b2],7,@X[$b3]
++||	ROTL	@X[$b3],7,@X[$b0]
++|| [B0]	SUB	B0,1,B0			; decrement inner loop counter
++bottom2x1?:
++
++	 ROTL	@Y[$b2],12,@Y[$b2]
++||	 ROTL	@Y[$b3],12,@Y[$b3]
++|| [B0]	ADD	@X[$b1],@X[$a1],@X[$a1]	; modulo-scheduled
++|| [B0]	ADD	@X[$b2],@X[$a2],@X[$a2]
++   [B0]	ADD	@X[$b0],@X[$a0],@X[$a0]
++|| [B0]	ADD	@X[$b3],@X[$a3],@X[$a3]
++
++||	 ADD	@Y[$b0],@Y[$a0],@Y[$a0]
++||	 ADD	@Y[$b1],@Y[$a1],@Y[$a1]
++|| [B0]	XOR	@X[$a1],@X[$d1],@X[$d1]
++|| [B0]	XOR	@X[$a2],@X[$d2],@X[$d2]
++   [B0]	XOR	@X[$a0],@X[$d0],@X[$d0]
++|| [B0]	XOR	@X[$a3],@X[$d3],@X[$d3]
++||	 ADD	@Y[$b2],@Y[$a2],@Y[$a2]
++||	 ADD	@Y[$b3],@Y[$a3],@Y[$a3]
++||	 XOR	@Y[$a0],@Y[$d0],@Y[$d0]
++||	 XOR	@Y[$a1],@Y[$d1],@Y[$d1]
++	 XOR	@Y[$a2],@Y[$d2],@Y[$d2]
++||	 XOR	@Y[$a3],@Y[$d3],@Y[$d3]
++||	 ROTL	@Y[$d0],8,@Y[$d0]
++||	 ROTL	@Y[$d1],8,@Y[$d1]
++|| [B0]	SWAP2	@X[$d1],@X[$d1]		; rotate by 16
++|| [B0]	SWAP2	@X[$d2],@X[$d2]
++|| [B0]	SWAP2	@X[$d0],@X[$d0]
++|| [B0]	SWAP2	@X[$d3],@X[$d3]
++	 ROTL	@Y[$d2],8,@Y[$d2]
++||	 ROTL	@Y[$d3],8,@Y[$d3]
++|| [B0]	ADD	@X[$d1],@X[$c1],@X[$c1]
++|| [B0]	ADD	@X[$d2],@X[$c2],@X[$c2]
++|| [B0]	ADD	@X[$d0],@X[$c0],@X[$c0]
++|| [B0]	ADD	@X[$d3],@X[$c3],@X[$c3]
++|| [B0]	BNOP	top2x?			; even protects from interrupt
++
++	 ADD	@Y[$d0],@Y[$c2],@Y[$c2]
++||	 ADD	@Y[$d1],@Y[$c3],@Y[$c3]
++|| [B0]	XOR	@X[$c1],@X[$b1],@X[$b1]
++|| [B0]	XOR	@X[$c2],@X[$b2],@X[$b2]
++|| [B0]	XOR	@X[$c0],@X[$b0],@X[$b0]
++|| [B0]	XOR	@X[$c3],@X[$b3],@X[$b3]
++	 ADD	@Y[$d2],@Y[$c0],@Y[$c0]
++||	 ADD	@Y[$d3],@Y[$c1],@Y[$c1]
++||	 XOR	@Y[$c2],@Y[$b0],@Y[$b0]
++||	 XOR	@Y[$c3],@Y[$b1],@Y[$b1]
++||	 ROTL	@Y[$d0],0,@Y[$d3]	; moved to avoid cross-path stall
++||	 ROTL	@Y[$d1],0,@Y[$d0]
++	 XOR	@Y[$c0],@Y[$b2],@Y[$b2]
++||	 XOR	@Y[$c1],@Y[$b3],@Y[$b3]
++||	 MV	@Y[$d2],@Y[$d1]
++||	 MV	@Y[$d3],@Y[$d2]
++|| [B0]	ROTL	@X[$b1],12,@X[$b1]
++|| [B0]	ROTL	@X[$b2],12,@X[$b2]
++	 ROTL	@Y[$b0],7,@Y[$b1]	; avoided cross-path stall
++||	 ROTL	@Y[$b1],7,@Y[$b2]
++	 ROTL	@Y[$b2],7,@Y[$b3]
++||	 ROTL	@Y[$b3],7,@Y[$b0]
++bottom2x2?:
++___
++}
++
++$code.=<<___;
++	ADD	@K2x[0],@X[0],@X[0]	; accumulate key material
++||	ADD	@K2x[1],@X[1],@X[1]
++||	ADD	@K2x[2],@X[2],@X[2]
++||	ADD	@K2x[3],@X[3],@X[3]
++	 ADD	@K2x[0],@Y[0],@Y[0]
++||	 ADD	@K2x[1],@Y[1],@Y[1]
++||	 ADD	@K2x[2],@Y[2],@Y[2]
++||	 ADD	@K2x[3],@Y[3],@Y[3]
++||	LDNDW	*${INP}++[8],@DAT[1]:@DAT[0]
++	ADD	@K2x[4],@X[4],@X[4]
++||	ADD	@K2x[5],@X[5],@X[5]
++||	ADD	@K2x[6],@X[6],@X[6]
++||	ADD	@K2x[7],@X[7],@X[7]
++||	LDNDW	*${INP}[-7],@DAT[3]:@DAT[2]
++	 ADD	@K2x[4],@Y[4],@Y[4]
++||	 ADD	@K2x[5],@Y[5],@Y[5]
++||	 ADD	@K2x[6],@Y[6],@Y[6]
++||	 ADD	@K2x[7],@Y[7],@Y[7]
++||	LDNDW	*${INP}[-6],@DAT[5]:@DAT[4]
++	ADD	@K2x[8],@X[8],@X[8]
++||	ADD	@K2x[9],@X[9],@X[9]
++||	ADD	@K2x[10],@X[10],@X[10]
++||	ADD	@K2x[11],@X[11],@X[11]
++||	LDNDW	*${INP}[-5],@DAT[7]:@DAT[6]
++	 ADD	@K2x[8],@Y[8],@Y[8]
++||	 ADD	@K2x[9],@Y[9],@Y[9]
++||	 ADD	@K2x[10],@Y[10],@Y[10]
++||	 ADD	@K2x[11],@Y[11],@Y[11]
++||	LDNDW	*${INP}[-4],@DAT[9]:@DAT[8]
++	ADD	@K2x[12],@X[12],@X[12]
++||	ADD	@K2x[13],@X[13],@X[13]
++||	ADD	@K2x[14],@X[14],@X[14]
++||	ADD	@K2x[15],@X[15],@X[15]
++||	LDNDW	*${INP}[-3],@DAT[11]:@DAT[10]
++	 ADD	@K2x[12],@Y[12],@Y[12]
++||	 ADD	@K2x[13],@Y[13],@Y[13]
++||	 ADD	@K2x[14],@Y[14],@Y[14]
++||	 ADD	@K2x[15],@Y[15],@Y[15]
++||	LDNDW	*${INP}[-2],@DAT[13]:@DAT[12]
++	 ADD	1,@Y[12],@Y[12]		; adjust counter for 2nd block
++||	ADD	2,@K2x[12],@K2x[12]	; increment counter
++||	LDNDW	*${INP}[-1],@DAT[15]:@DAT[14]
++
++	.if	.BIG_ENDIAN
++	SWAP2	@X[0],@X[0]
++||	SWAP2	@X[1],@X[1]
++||	SWAP2	@X[2],@X[2]
++||	SWAP2	@X[3],@X[3]
++	SWAP2	@X[4],@X[4]
++||	SWAP2	@X[5],@X[5]
++||	SWAP2	@X[6],@X[6]
++||	SWAP2	@X[7],@X[7]
++	SWAP2	@X[8],@X[8]
++||	SWAP2	@X[9],@X[9]
++||	SWAP4	@X[0],@X[1]
++||	SWAP4	@X[1],@X[0]
++	SWAP2	@X[10],@X[10]
++||	SWAP2	@X[11],@X[11]
++||	SWAP4	@X[2],@X[3]
++||	SWAP4	@X[3],@X[2]
++	SWAP2	@X[12],@X[12]
++||	SWAP2	@X[13],@X[13]
++||	SWAP4	@X[4],@X[5]
++||	SWAP4	@X[5],@X[4]
++	SWAP2	@X[14],@X[14]
++||	SWAP2	@X[15],@X[15]
++||	SWAP4	@X[6],@X[7]
++||	SWAP4	@X[7],@X[6]
++	SWAP4	@X[8],@X[9]
++||	SWAP4	@X[9],@X[8]
++||	 SWAP2	@Y[0],@Y[0]
++||	 SWAP2	@Y[1],@Y[1]
++	SWAP4	@X[10],@X[11]
++||	SWAP4	@X[11],@X[10]
++||	 SWAP2	@Y[2],@Y[2]
++||	 SWAP2	@Y[3],@Y[3]
++	SWAP4	@X[12],@X[13]
++||	SWAP4	@X[13],@X[12]
++||	 SWAP2	@Y[4],@Y[4]
++||	 SWAP2	@Y[5],@Y[5]
++	SWAP4	@X[14],@X[15]
++||	SWAP4	@X[15],@X[14]
++||	 SWAP2	@Y[6],@Y[6]
++||	 SWAP2	@Y[7],@Y[7]
++	 SWAP2	@Y[8],@Y[8]
++||	 SWAP2	@Y[9],@Y[9]
++||	 SWAP4	@Y[0],@Y[1]
++||	 SWAP4	@Y[1],@Y[0]
++	 SWAP2	@Y[10],@Y[10]
++||	 SWAP2	@Y[11],@Y[11]
++||	 SWAP4	@Y[2],@Y[3]
++||	 SWAP4	@Y[3],@Y[2]
++	 SWAP2	@Y[12],@Y[12]
++||	 SWAP2	@Y[13],@Y[13]
++||	 SWAP4	@Y[4],@Y[5]
++||	 SWAP4	@Y[5],@Y[4]
++	 SWAP2	@Y[14],@Y[14]
++||	 SWAP2	@Y[15],@Y[15]
++||	 SWAP4	@Y[6],@Y[7]
++||	 SWAP4	@Y[7],@Y[6]
++	 SWAP4	@Y[8],@Y[9]
++||	 SWAP4	@Y[9],@Y[8]
++	 SWAP4	@Y[10],@Y[11]
++||	 SWAP4	@Y[11],@Y[10]
++	 SWAP4	@Y[12],@Y[13]
++||	 SWAP4	@Y[13],@Y[12]
++	 SWAP4	@Y[14],@Y[15]
++||	 SWAP4	@Y[15],@Y[14]
++	.endif
++
++	XOR	@DAT[0],@X[0],@X[0]	; xor 1st block
++||	XOR	@DAT[3],@X[3],@X[3]
++||	XOR	@DAT[2],@X[2],@X[1]
++||	XOR	@DAT[1],@X[1],@X[2]
++||	LDNDW	*${INP}++[8],@DAT[1]:@DAT[0]
++	XOR	@DAT[4],@X[4],@X[4]
++||	XOR	@DAT[7],@X[7],@X[7]
++||	LDNDW	*${INP}[-7],@DAT[3]:@DAT[2]
++	XOR	@DAT[6],@X[6],@X[5]
++||	XOR	@DAT[5],@X[5],@X[6]
++||	LDNDW	*${INP}[-6],@DAT[5]:@DAT[4]
++	XOR	@DAT[8],@X[8],@X[8]
++||	XOR	@DAT[11],@X[11],@X[11]
++||	LDNDW	*${INP}[-5],@DAT[7]:@DAT[6]
++	XOR	@DAT[10],@X[10],@X[9]
++||	XOR	@DAT[9],@X[9],@X[10]
++||	LDNDW	*${INP}[-4],@DAT[9]:@DAT[8]
++	XOR	@DAT[12],@X[12],@X[12]
++||	XOR	@DAT[15],@X[15],@X[15]
++||	LDNDW	*${INP}[-3],@DAT[11]:@DAT[10]
++	XOR	@DAT[14],@X[14],@X[13]
++||	XOR	@DAT[13],@X[13],@X[14]
++||	LDNDW	*${INP}[-2],@DAT[13]:@DAT[12]
++   [A0]	SUB	A0,$STEP,A0		; SUB	A0,128,A0
++||	LDNDW	*${INP}[-1],@DAT[15]:@DAT[14]
++
++	XOR	@Y[0],@DAT[0],@DAT[0]	; xor 2nd block
++||	XOR	@Y[1],@DAT[1],@DAT[1]
++||	STNDW	@X[2]:@X[0],*${OUT}++[8]
++	XOR	@Y[2],@DAT[2],@DAT[2]
++||	XOR	@Y[3],@DAT[3],@DAT[3]
++||	STNDW	@X[3]:@X[1],*${OUT}[-7]
++	XOR	@Y[4],@DAT[4],@DAT[4]
++|| [A0]	LDDW	*FP[-12],@X[2]:@X[0]	; re-load key material from stack
++|| [A0]	LDDW	*SP[2],  @X[3]:@X[1]
++	XOR	@Y[5],@DAT[5],@DAT[5]
++||	STNDW	@X[6]:@X[4],*${OUT}[-6]
++	XOR	@Y[6],@DAT[6],@DAT[6]
++||	XOR	@Y[7],@DAT[7],@DAT[7]
++||	STNDW	@X[7]:@X[5],*${OUT}[-5]
++	XOR	@Y[8],@DAT[8],@DAT[8]
++|| [A0]	LDDW	*FP[-10],@X[6]:@X[4]
++|| [A0]	LDDW	*SP[4],  @X[7]:@X[5]
++	XOR	@Y[9],@DAT[9],@DAT[9]
++||	STNDW	@X[10]:@X[8],*${OUT}[-4]
++	XOR	@Y[10],@DAT[10],@DAT[10]
++||	XOR	@Y[11],@DAT[11],@DAT[11]
++||	STNDW	@X[11]:@X[9],*${OUT}[-3]
++	XOR	@Y[12],@DAT[12],@DAT[12]
++|| [A0]	LDDW	*FP[-8], @X[10]:@X[8]
++|| [A0]	LDDW	*SP[6],  @X[11]:@X[9]
++	XOR	@Y[13],@DAT[13],@DAT[13]
++||	STNDW	@X[14]:@X[12],*${OUT}[-2]
++	XOR	@Y[14],@DAT[14],@DAT[14]
++||	XOR	@Y[15],@DAT[15],@DAT[15]
++||	STNDW	@X[15]:@X[13],*${OUT}[-1]
++
++   [A0]	MV	@K2x[12],@X[12]
++|| [A0]	MV	@K2x[13],@X[13]
++|| [A0]	LDW	*FP[-6*2], @X[14]
++|| [A0]	LDW	*SP[8*2],  @X[15]
++
++   [A0]	DMV	@X[2],@X[0],@Y[2]:@Y[0]	; duplicate key material
++||	STNDW	@DAT[1]:@DAT[0],*${OUT}++[8]
++   [A0]	DMV	@X[3],@X[1],@Y[3]:@Y[1]
++||	STNDW	@DAT[3]:@DAT[2],*${OUT}[-7]
++   [A0]	DMV	@X[6],@X[4],@Y[6]:@Y[4]
++||	STNDW	@DAT[5]:@DAT[4],*${OUT}[-6]
++||	CMPLTU	A0,$STEP,A1		; is remaining length < 2*blocks?
++||[!A0]	BNOP	epilogue?
++   [A0]	DMV	@X[7],@X[5],@Y[7]:@Y[5]
++||	STNDW	@DAT[7]:@DAT[6],*${OUT}[-5]
++||[!A1]	BNOP	outer2x?
++   [A0]	DMV	@X[10],@X[8],@Y[10]:@Y[8]
++||	STNDW	@DAT[9]:@DAT[8],*${OUT}[-4]
++   [A0]	DMV	@X[11],@X[9],@Y[11]:@Y[9]
++||	STNDW	@DAT[11]:@DAT[10],*${OUT}[-3]
++   [A0]	DMV	@X[14],@X[12],@Y[14]:@Y[12]
++||	STNDW	@DAT[13]:@DAT[12],*${OUT}[-2]
++   [A0]	DMV	@X[15],@X[13],@Y[15]:@Y[13]
++||	STNDW	@DAT[15]:@DAT[14],*${OUT}[-1]
++;;===== branch to epilogue? is taken here
++   [A1]	MVK	64,$STEP
++|| [A0]	MVK	10,B0			; inner loop counter
++;;===== branch to outer2x? is taken here
++___
++{
++my ($a0,$a1,$a2,$a3) = (0..3);
++my ($b0,$b1,$b2,$b3) = (4..7);
++my ($c0,$c1,$c2,$c3) = (8..11);
++my ($d0,$d1,$d2,$d3) = (12..15);
++
++$code.=<<___;
++top1x?:
++	ADD	@X[$b1],@X[$a1],@X[$a1]
++||	ADD	@X[$b2],@X[$a2],@X[$a2]
++	ADD	@X[$b0],@X[$a0],@X[$a0]
++||	ADD	@X[$b3],@X[$a3],@X[$a3]
++||	XOR	@X[$a1],@X[$d1],@X[$d1]
++||	XOR	@X[$a2],@X[$d2],@X[$d2]
++	XOR	@X[$a0],@X[$d0],@X[$d0]
++||	XOR	@X[$a3],@X[$d3],@X[$d3]
++||	SWAP2	@X[$d1],@X[$d1]		; rotate by 16
++||	SWAP2	@X[$d2],@X[$d2]
++	SWAP2	@X[$d0],@X[$d0]
++||	SWAP2	@X[$d3],@X[$d3]
++
++||	ADD	@X[$d1],@X[$c1],@X[$c1]
++||	ADD	@X[$d2],@X[$c2],@X[$c2]
++	ADD	@X[$d0],@X[$c0],@X[$c0]
++||	ADD	@X[$d3],@X[$c3],@X[$c3]
++||	XOR	@X[$c1],@X[$b1],@X[$b1]
++||	XOR	@X[$c2],@X[$b2],@X[$b2]
++	XOR	@X[$c0],@X[$b0],@X[$b0]
++||	XOR	@X[$c3],@X[$b3],@X[$b3]
++||	ROTL	@X[$b1],12,@X[$b1]
++||	ROTL	@X[$b2],12,@X[$b2]
++	ROTL	@X[$b0],12,@X[$b0]
++||	ROTL	@X[$b3],12,@X[$b3]
++
++	ADD	@X[$b1],@X[$a1],@X[$a1]
++||	ADD	@X[$b2],@X[$a2],@X[$a2]
++	ADD	@X[$b0],@X[$a0],@X[$a0]
++||	ADD	@X[$b3],@X[$a3],@X[$a3]
++||	XOR	@X[$a1],@X[$d1],@X[$d1]
++||	XOR	@X[$a2],@X[$d2],@X[$d2]
++	XOR	@X[$a0],@X[$d0],@X[$d0]
++||	XOR	@X[$a3],@X[$d3],@X[$d3]
++||	ROTL	@X[$d1],8,@X[$d1]
++||	ROTL	@X[$d2],8,@X[$d2]
++	ROTL	@X[$d0],8,@X[$d0]
++||	ROTL	@X[$d3],8,@X[$d3]
++||	BNOP	middle1x?		; protect from interrupt
++
++	ADD	@X[$d1],@X[$c1],@X[$c1]
++||	ADD	@X[$d2],@X[$c2],@X[$c2]
++	ADD	@X[$d0],@X[$c0],@X[$c0]
++||	ADD	@X[$d3],@X[$c3],@X[$c3]
++||	XOR	@X[$c1],@X[$b1],@X[$b1]
++||	XOR	@X[$c2],@X[$b2],@X[$b2]
++||	ROTL	@X[$d1],0,@X[$d2]	; moved to avoid cross-path stall
++||	ROTL	@X[$d2],0,@X[$d3]
++	XOR	@X[$c0],@X[$b0],@X[$b0]
++||	XOR	@X[$c3],@X[$b3],@X[$b3]
++||	ROTL	@X[$d0],0,@X[$d1]
++||	ROTL	@X[$d3],0,@X[$d0]
++	ROTL	@X[$b1],7,@X[$b0]	; avoided cross-path stall
++||	ROTL	@X[$b2],7,@X[$b1]
++	ROTL	@X[$b0],7,@X[$b3]
++||	ROTL	@X[$b3],7,@X[$b2]
++middle1x?:
++
++	ADD	@X[$b0],@X[$a0],@X[$a0]
++||	ADD	@X[$b1],@X[$a1],@X[$a1]
++	ADD	@X[$b2],@X[$a2],@X[$a2]
++||	ADD	@X[$b3],@X[$a3],@X[$a3]
++||	XOR	@X[$a0],@X[$d0],@X[$d0]
++||	XOR	@X[$a1],@X[$d1],@X[$d1]
++	XOR	@X[$a2],@X[$d2],@X[$d2]
++||	XOR	@X[$a3],@X[$d3],@X[$d3]
++||	SWAP2	@X[$d0],@X[$d0]		; rotate by 16
++||	SWAP2	@X[$d1],@X[$d1]
++	SWAP2	@X[$d2],@X[$d2]
++||	SWAP2	@X[$d3],@X[$d3]
++
++||	ADD	@X[$d0],@X[$c2],@X[$c2]
++||	ADD	@X[$d1],@X[$c3],@X[$c3]
++	ADD	@X[$d2],@X[$c0],@X[$c0]
++||	ADD	@X[$d3],@X[$c1],@X[$c1]
++||	XOR	@X[$c2],@X[$b0],@X[$b0]
++||	XOR	@X[$c3],@X[$b1],@X[$b1]
++	XOR	@X[$c0],@X[$b2],@X[$b2]
++||	XOR	@X[$c1],@X[$b3],@X[$b3]
++||	ROTL	@X[$b0],12,@X[$b0]
++||	ROTL	@X[$b1],12,@X[$b1]
++	ROTL	@X[$b2],12,@X[$b2]
++||	ROTL	@X[$b3],12,@X[$b3]
++
++	ADD	@X[$b0],@X[$a0],@X[$a0]
++||	ADD	@X[$b1],@X[$a1],@X[$a1]
++|| [B0]	SUB	B0,1,B0			; decrement inner loop counter
++	ADD	@X[$b2],@X[$a2],@X[$a2]
++||	ADD	@X[$b3],@X[$a3],@X[$a3]
++||	XOR	@X[$a0],@X[$d0],@X[$d0]
++||	XOR	@X[$a1],@X[$d1],@X[$d1]
++	XOR	@X[$a2],@X[$d2],@X[$d2]
++||	XOR	@X[$a3],@X[$d3],@X[$d3]
++||	ROTL	@X[$d0],8,@X[$d0]
++||	ROTL	@X[$d1],8,@X[$d1]
++	ROTL	@X[$d2],8,@X[$d2]
++||	ROTL	@X[$d3],8,@X[$d3]
++|| [B0]	BNOP	top1x?			; even protects from interrupt
++
++	ADD	@X[$d0],@X[$c2],@X[$c2]
++||	ADD	@X[$d1],@X[$c3],@X[$c3]
++	ADD	@X[$d2],@X[$c0],@X[$c0]
++||	ADD	@X[$d3],@X[$c1],@X[$c1]
++||	XOR	@X[$c2],@X[$b0],@X[$b0]
++||	XOR	@X[$c3],@X[$b1],@X[$b1]
++||	ROTL	@X[$d0],0,@X[$d3]	; moved to avoid cross-path stall
++||	ROTL	@X[$d1],0,@X[$d0]
++	XOR	@X[$c0],@X[$b2],@X[$b2]
++||	XOR	@X[$c1],@X[$b3],@X[$b3]
++||	ROTL	@X[$d2],0,@X[$d1]
++||	ROTL	@X[$d3],0,@X[$d2]
++	ROTL	@X[$b0],7,@X[$b1]	; avoided cross-path stall
++||	ROTL	@X[$b1],7,@X[$b2]
++	ROTL	@X[$b2],7,@X[$b3]
++||	ROTL	@X[$b3],7,@X[$b0]
++||[!B0]	CMPLTU	A0,$STEP,A1		; less than 64 bytes left?
++bottom1x?:
++___
++}
++
++$code.=<<___;
++	ADD	@Y[0],@X[0],@X[0]	; accumulate key material
++||	ADD	@Y[1],@X[1],@X[1]
++||	ADD	@Y[2],@X[2],@X[2]
++||	ADD	@Y[3],@X[3],@X[3]
++||[!A1]	LDNDW	*${INP}++[8],@DAT[1]:@DAT[0]
++|| [A1]	BNOP	tail?
++	ADD	@Y[4],@X[4],@X[4]
++||	ADD	@Y[5],@X[5],@X[5]
++||	ADD	@Y[6],@X[6],@X[6]
++||	ADD	@Y[7],@X[7],@X[7]
++||[!A1]	LDNDW	*${INP}[-7],@DAT[3]:@DAT[2]
++	ADD	@Y[8],@X[8],@X[8]
++||	ADD	@Y[9],@X[9],@X[9]
++||	ADD	@Y[10],@X[10],@X[10]
++||	ADD	@Y[11],@X[11],@X[11]
++||[!A1]	LDNDW	*${INP}[-6],@DAT[5]:@DAT[4]
++	ADD	@Y[12],@X[12],@X[12]
++||	ADD	@Y[13],@X[13],@X[13]
++||	ADD	@Y[14],@X[14],@X[14]
++||	ADD	@Y[15],@X[15],@X[15]
++||[!A1]	LDNDW	*${INP}[-5],@DAT[7]:@DAT[6]
++  [!A1]	LDNDW	*${INP}[-4],@DAT[9]:@DAT[8]
++  [!A1]	LDNDW	*${INP}[-3],@DAT[11]:@DAT[10]
++	LDNDW	*${INP}[-2],@DAT[13]:@DAT[12]
++	LDNDW	*${INP}[-1],@DAT[15]:@DAT[14]
++
++	.if	.BIG_ENDIAN
++	SWAP2	@X[0],@X[0]
++||	SWAP2	@X[1],@X[1]
++||	SWAP2	@X[2],@X[2]
++||	SWAP2	@X[3],@X[3]
++	SWAP2	@X[4],@X[4]
++||	SWAP2	@X[5],@X[5]
++||	SWAP2	@X[6],@X[6]
++||	SWAP2	@X[7],@X[7]
++	SWAP2	@X[8],@X[8]
++||	SWAP2	@X[9],@X[9]
++||	SWAP4	@X[0],@X[1]
++||	SWAP4	@X[1],@X[0]
++	SWAP2	@X[10],@X[10]
++||	SWAP2	@X[11],@X[11]
++||	SWAP4	@X[2],@X[3]
++||	SWAP4	@X[3],@X[2]
++	SWAP2	@X[12],@X[12]
++||	SWAP2	@X[13],@X[13]
++||	SWAP4	@X[4],@X[5]
++||	SWAP4	@X[5],@X[4]
++	SWAP2	@X[14],@X[14]
++||	SWAP2	@X[15],@X[15]
++||	SWAP4	@X[6],@X[7]
++||	SWAP4	@X[7],@X[6]
++	SWAP4	@X[8],@X[9]
++||	SWAP4	@X[9],@X[8]
++	SWAP4	@X[10],@X[11]
++||	SWAP4	@X[11],@X[10]
++	SWAP4	@X[12],@X[13]
++||	SWAP4	@X[13],@X[12]
++	SWAP4	@X[14],@X[15]
++||	SWAP4	@X[15],@X[14]
++	.else
++	NOP	1
++	.endif
++
++	XOR	@X[0],@DAT[0],@DAT[0]	; xor with input
++||	XOR	@X[1],@DAT[1],@DAT[1]
++||	XOR	@X[2],@DAT[2],@DAT[2]
++||	XOR	@X[3],@DAT[3],@DAT[3]
++|| [A0]	SUB	A0,$STEP,A0		; SUB	A0,64,A0
++	XOR	@X[4],@DAT[4],@DAT[4]
++||	XOR	@X[5],@DAT[5],@DAT[5]
++||	XOR	@X[6],@DAT[6],@DAT[6]
++||	XOR	@X[7],@DAT[7],@DAT[7]
++||	STNDW	@DAT[1]:@DAT[0],*${OUT}++[8]
++	XOR	@X[8],@DAT[8],@DAT[8]
++||	XOR	@X[9],@DAT[9],@DAT[9]
++||	XOR	@X[10],@DAT[10],@DAT[10]
++||	XOR	@X[11],@DAT[11],@DAT[11]
++||	STNDW	@DAT[3]:@DAT[2],*${OUT}[-7]
++	XOR	@X[12],@DAT[12],@DAT[12]
++||	XOR	@X[13],@DAT[13],@DAT[13]
++||	XOR	@X[14],@DAT[14],@DAT[14]
++||	XOR	@X[15],@DAT[15],@DAT[15]
++||	STNDW	@DAT[5]:@DAT[4],*${OUT}[-6]
++|| [A0]	BNOP	top1x?
++   [A0]	DMV	@Y[2],@Y[0],@X[2]:@X[0]	; duplicate key material
++|| [A0]	DMV	@Y[3],@Y[1],@X[3]:@X[1]
++||	STNDW	@DAT[7]:@DAT[6],*${OUT}[-5]
++   [A0]	DMV	@Y[6],@Y[4],@X[6]:@X[4]
++|| [A0]	DMV	@Y[7],@Y[5],@X[7]:@X[5]
++||	STNDW	@DAT[9]:@DAT[8],*${OUT}[-4]
++   [A0]	DMV	@Y[10],@Y[8],@X[10]:@X[8]
++|| [A0]	DMV	@Y[11],@Y[9],@X[11]:@X[9]
++|| [A0]	ADD	1,@Y[12],@Y[12]		; increment counter
++||	STNDW	@DAT[11]:@DAT[10],*${OUT}[-3]
++   [A0]	DMV	@Y[14],@Y[12],@X[14]:@X[12]
++|| [A0]	DMV	@Y[15],@Y[13],@X[15]:@X[13]
++||	STNDW	@DAT[13]:@DAT[12],*${OUT}[-2]
++   [A0]	MVK	10,B0			; inner loop counter
++||	STNDW	@DAT[15]:@DAT[14],*${OUT}[-1]
++;;===== branch to top1x? is taken here
++
++epilogue?:
++	LDDW	*FP[-4],A11:A10		; ABI says so
++	LDDW	*FP[-3],A13:A12
++||	LDDW	*SP[3+8],B11:B10
++	LDDW	*SP[4+8],B13:B12
++||	BNOP	RA
++	LDW	*++SP(40+64),FP		; restore frame pointer
++	NOP	4
++
++tail?:
++	LDBU	*${INP}++[1],B24	; load byte by byte
++||	SUB	A0,1,A0
++||	SUB	A0,1,B1
++  [!B1]	BNOP	epilogue?		; interrupts are disabled for whole time
++|| [A0] LDBU	*${INP}++[1],B24
++|| [A0]	SUB	A0,1,A0
++||	SUB	B1,1,B1
++  [!B1]	BNOP	epilogue?
++|| [A0] LDBU	*${INP}++[1],B24
++|| [A0]	SUB	A0,1,A0
++||	SUB	B1,1,B1
++  [!B1]	BNOP	epilogue?
++||	ROTL	@X[0],0,A24
++|| [A0] LDBU	*${INP}++[1],B24
++|| [A0]	SUB	A0,1,A0
++||	SUB	B1,1,B1
++  [!B1]	BNOP	epilogue?
++||	ROTL	@X[0],24,A24
++|| [A0] LDBU	*${INP}++[1],A24
++|| [A0]	SUB	A0,1,A0
++||	SUB	B1,1,B1
++  [!B1]	BNOP	epilogue?
++||	ROTL	@X[0],16,A24
++|| [A0] LDBU	*${INP}++[1],A24
++|| [A0]	SUB	A0,1,A0
++||	SUB	B1,1,B1
++||	XOR	A24,B24,B25
++	STB	B25,*${OUT}++[1]	; store byte by byte
++||[!B1]	BNOP	epilogue?
++||	ROTL	@X[0],8,A24
++|| [A0] LDBU	*${INP}++[1],A24
++|| [A0]	SUB	A0,1,A0
++||	SUB	B1,1,B1
++||	XOR	A24,B24,B25
++	STB	B25,*${OUT}++[1]
++___
++sub TAIL_STEP {
++my $Xi= shift;
++my $T = ($Xi=~/^B/?"B24":"A24");	# match @X[i] to avoid cross path
++my $D = $T; $D=~tr/AB/BA/;
++my $O = $D; $O=~s/24/25/;
++
++$code.=<<___;
++||[!B1]	BNOP	epilogue?
++||	ROTL	$Xi,0,$T
++|| [A0] LDBU	*${INP}++[1],$D
++|| [A0]	SUB	A0,1,A0
++||	SUB	B1,1,B1
++||	XOR	A24,B24,$O
++	STB	$O,*${OUT}++[1]
++||[!B1]	BNOP	epilogue?
++||	ROTL	$Xi,24,$T
++|| [A0] LDBU	*${INP}++[1],$T
++|| [A0]	SUB	A0,1,A0
++||	SUB	B1,1,B1
++||	XOR	A24,B24,$O
++	STB	$O,*${OUT}++[1]
++||[!B1]	BNOP	epilogue?
++||	ROTL	$Xi,16,$T
++|| [A0] LDBU	*${INP}++[1],$T
++|| [A0]	SUB	A0,1,A0
++||	SUB	B1,1,B1
++||	XOR	A24,B24,$O
++	STB	$O,*${OUT}++[1]
++||[!B1]	BNOP	epilogue?
++||	ROTL	$Xi,8,$T
++|| [A0] LDBU	*${INP}++[1],$T
++|| [A0]	SUB	A0,1,A0
++||	SUB	B1,1,B1
++||	XOR	A24,B24,$O
++	STB	$O,*${OUT}++[1]
++___
++}
++	foreach (1..14) { TAIL_STEP(@X[$_]); }
++$code.=<<___;
++||[!B1]	BNOP	epilogue?
++||	ROTL	@X[15],0,B24
++||	XOR	A24,B24,A25
++	STB	A25,*${OUT}++[1]
++||	ROTL	@X[15],24,B24
++||	XOR	A24,B24,A25
++	STB	A25,*${OUT}++[1]
++||	ROTL	@X[15],16,B24
++||	XOR	A24,B24,A25
++	STB	A25,*${OUT}++[1]
++||	XOR	A24,B24,A25
++	STB	A25,*${OUT}++[1]
++||	XOR	A24,B24,B25
++	STB	B25,*${OUT}++[1]
++	.endasmfunc
++
++	.sect	.const
++	.cstring "ChaCha20 for C64x+, CRYPTOGAMS by "
++	.align	4
++___
++
++print $code;
++close STDOUT;
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/chacha/asm/chacha-ppc.pl b/CryptoPkg/Library/OpensslLib/openssl/crypto/chacha/asm/chacha-ppc.pl
+new file mode 100755
+index 0000000..181decd
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/chacha/asm/chacha-ppc.pl
+@@ -0,0 +1,953 @@
++#! /usr/bin/env perl
++# Copyright 2016 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
++# in the file LICENSE in the source distribution or at
++# https://www.openssl.org/source/license.html
++
++#
++# ====================================================================
++# Written by Andy Polyakov  for the OpenSSL
++# project. The module is, however, dual licensed under OpenSSL and
++# CRYPTOGAMS licenses depending on where you obtain it. For further
++# details see http://www.openssl.org/~appro/cryptogams/.
++# ====================================================================
++#
++# October 2015
++# 
++# ChaCha20 for PowerPC/AltiVec.
++#
++# Performance in cycles per byte out of large buffer.
++#
++#			IALU/gcc-4.x    3xAltiVec+1xIALU
++#
++# Freescale e300	13.6/+115%	-
++# PPC74x0/G4e		6.81/+310%	4.66
++# PPC970/G5		9.29/+160%	4.60
++# POWER7		8.62/+61%	4.27
++# POWER8		8.70/+51%	3.96
++
++$flavour = shift;
++
++if ($flavour =~ /64/) {
++	$SIZE_T	=8;
++	$LRSAVE	=2*$SIZE_T;
++	$STU	="stdu";
++	$POP	="ld";
++	$PUSH	="std";
++	$UCMP	="cmpld";
++} elsif ($flavour =~ /32/) {
++	$SIZE_T	=4;
++	$LRSAVE	=$SIZE_T;
++	$STU	="stwu";
++	$POP	="lwz";
++	$PUSH	="stw";
++	$UCMP	="cmplw";
++} else { die "nonsense $flavour"; }
++
++$LITTLE_ENDIAN = ($flavour=~/le$/) ? 1 : 0;
++
++$0 =~ m/(.*[\/\\])[^\/\\]+$/; $dir=$1;
++( $xlate="${dir}ppc-xlate.pl" and -f $xlate ) or
++( $xlate="${dir}../../perlasm/ppc-xlate.pl" and -f $xlate) or
++die "can't locate ppc-xlate.pl";
++
++open STDOUT,"| $^X $xlate $flavour ".shift || die "can't call $xlate: $!";
++
++$LOCALS=6*$SIZE_T;
++$FRAME=$LOCALS+64+18*$SIZE_T;	# 64 is for local variables
++
++sub AUTOLOAD()		# thunk [simplified] x86-style perlasm
++{ my $opcode = $AUTOLOAD; $opcode =~ s/.*:://; $opcode =~ s/_/\./;
++    $code .= "\t$opcode\t".join(',',@_)."\n";
++}
++
++my $sp = "r1";
++
++my ($out,$inp,$len,$key,$ctr) = map("r$_",(3..7));
++
++my @x=map("r$_",(16..31));
++my @d=map("r$_",(11,12,14,15));
++my @t=map("r$_",(7..10));
++
++sub ROUND {
++my ($a0,$b0,$c0,$d0)=@_;
++my ($a1,$b1,$c1,$d1)=map(($_&~3)+(($_+1)&3),($a0,$b0,$c0,$d0));
++my ($a2,$b2,$c2,$d2)=map(($_&~3)+(($_+1)&3),($a1,$b1,$c1,$d1));
++my ($a3,$b3,$c3,$d3)=map(($_&~3)+(($_+1)&3),($a2,$b2,$c2,$d2));
++
++    (
++	"&add		(@x[$a0],@x[$a0],@x[$b0])",
++	 "&add		(@x[$a1],@x[$a1],@x[$b1])",
++	  "&add		(@x[$a2],@x[$a2],@x[$b2])",
++	   "&add	(@x[$a3],@x[$a3],@x[$b3])",
++	"&xor		(@x[$d0],@x[$d0],@x[$a0])",
++	 "&xor		(@x[$d1],@x[$d1],@x[$a1])",
++	  "&xor		(@x[$d2],@x[$d2],@x[$a2])",
++	   "&xor	(@x[$d3],@x[$d3],@x[$a3])",
++	"&rotlwi	(@x[$d0],@x[$d0],16)",
++	 "&rotlwi	(@x[$d1],@x[$d1],16)",
++	  "&rotlwi	(@x[$d2],@x[$d2],16)",
++	   "&rotlwi	(@x[$d3],@x[$d3],16)",
++
++	"&add		(@x[$c0],@x[$c0],@x[$d0])",
++	 "&add		(@x[$c1],@x[$c1],@x[$d1])",
++	  "&add		(@x[$c2],@x[$c2],@x[$d2])",
++	   "&add	(@x[$c3],@x[$c3],@x[$d3])",
++	"&xor		(@x[$b0],@x[$b0],@x[$c0])",
++	 "&xor		(@x[$b1],@x[$b1],@x[$c1])",
++	  "&xor		(@x[$b2],@x[$b2],@x[$c2])",
++	   "&xor	(@x[$b3],@x[$b3],@x[$c3])",
++	"&rotlwi	(@x[$b0],@x[$b0],12)",
++	 "&rotlwi	(@x[$b1],@x[$b1],12)",
++	  "&rotlwi	(@x[$b2],@x[$b2],12)",
++	   "&rotlwi	(@x[$b3],@x[$b3],12)",
++
++	"&add		(@x[$a0],@x[$a0],@x[$b0])",
++	 "&add		(@x[$a1],@x[$a1],@x[$b1])",
++	  "&add		(@x[$a2],@x[$a2],@x[$b2])",
++	   "&add	(@x[$a3],@x[$a3],@x[$b3])",
++	"&xor		(@x[$d0],@x[$d0],@x[$a0])",
++	 "&xor		(@x[$d1],@x[$d1],@x[$a1])",
++	  "&xor		(@x[$d2],@x[$d2],@x[$a2])",
++	   "&xor	(@x[$d3],@x[$d3],@x[$a3])",
++	"&rotlwi	(@x[$d0],@x[$d0],8)",
++	 "&rotlwi	(@x[$d1],@x[$d1],8)",
++	  "&rotlwi	(@x[$d2],@x[$d2],8)",
++	   "&rotlwi	(@x[$d3],@x[$d3],8)",
++
++	"&add		(@x[$c0],@x[$c0],@x[$d0])",
++	 "&add		(@x[$c1],@x[$c1],@x[$d1])",
++	  "&add		(@x[$c2],@x[$c2],@x[$d2])",
++	   "&add	(@x[$c3],@x[$c3],@x[$d3])",
++	"&xor		(@x[$b0],@x[$b0],@x[$c0])",
++	 "&xor		(@x[$b1],@x[$b1],@x[$c1])",
++	  "&xor		(@x[$b2],@x[$b2],@x[$c2])",
++	   "&xor	(@x[$b3],@x[$b3],@x[$c3])",
++	"&rotlwi	(@x[$b0],@x[$b0],7)",
++	 "&rotlwi	(@x[$b1],@x[$b1],7)",
++	  "&rotlwi	(@x[$b2],@x[$b2],7)",
++	   "&rotlwi	(@x[$b3],@x[$b3],7)"
++    );
++}
++
++$code.=<<___;
++.machine	"any"
++.text
++
++.globl	.ChaCha20_ctr32_int
++.align	5
++.ChaCha20_ctr32_int:
++__ChaCha20_ctr32_int:
++	${UCMP}i $len,0
++	beqlr-
++
++	$STU	$sp,-$FRAME($sp)
++	mflr	r0
++
++	$PUSH	r14,`$FRAME-$SIZE_T*18`($sp)
++	$PUSH	r15,`$FRAME-$SIZE_T*17`($sp)
++	$PUSH	r16,`$FRAME-$SIZE_T*16`($sp)
++	$PUSH	r17,`$FRAME-$SIZE_T*15`($sp)
++	$PUSH	r18,`$FRAME-$SIZE_T*14`($sp)
++	$PUSH	r19,`$FRAME-$SIZE_T*13`($sp)
++	$PUSH	r20,`$FRAME-$SIZE_T*12`($sp)
++	$PUSH	r21,`$FRAME-$SIZE_T*11`($sp)
++	$PUSH	r22,`$FRAME-$SIZE_T*10`($sp)
++	$PUSH	r23,`$FRAME-$SIZE_T*9`($sp)
++	$PUSH	r24,`$FRAME-$SIZE_T*8`($sp)
++	$PUSH	r25,`$FRAME-$SIZE_T*7`($sp)
++	$PUSH	r26,`$FRAME-$SIZE_T*6`($sp)
++	$PUSH	r27,`$FRAME-$SIZE_T*5`($sp)
++	$PUSH	r28,`$FRAME-$SIZE_T*4`($sp)
++	$PUSH	r29,`$FRAME-$SIZE_T*3`($sp)
++	$PUSH	r30,`$FRAME-$SIZE_T*2`($sp)
++	$PUSH	r31,`$FRAME-$SIZE_T*1`($sp)
++	$PUSH	r0,`$FRAME+$LRSAVE`($sp)
++
++	lwz	@d[0],0($ctr)			# load counter
++	lwz	@d[1],4($ctr)
++	lwz	@d[2],8($ctr)
++	lwz	@d[3],12($ctr)
++
++	bl	__ChaCha20_1x
++
++	$POP	r0,`$FRAME+$LRSAVE`($sp)
++	$POP	r14,`$FRAME-$SIZE_T*18`($sp)
++	$POP	r15,`$FRAME-$SIZE_T*17`($sp)
++	$POP	r16,`$FRAME-$SIZE_T*16`($sp)
++	$POP	r17,`$FRAME-$SIZE_T*15`($sp)
++	$POP	r18,`$FRAME-$SIZE_T*14`($sp)
++	$POP	r19,`$FRAME-$SIZE_T*13`($sp)
++	$POP	r20,`$FRAME-$SIZE_T*12`($sp)
++	$POP	r21,`$FRAME-$SIZE_T*11`($sp)
++	$POP	r22,`$FRAME-$SIZE_T*10`($sp)
++	$POP	r23,`$FRAME-$SIZE_T*9`($sp)
++	$POP	r24,`$FRAME-$SIZE_T*8`($sp)
++	$POP	r25,`$FRAME-$SIZE_T*7`($sp)
++	$POP	r26,`$FRAME-$SIZE_T*6`($sp)
++	$POP	r27,`$FRAME-$SIZE_T*5`($sp)
++	$POP	r28,`$FRAME-$SIZE_T*4`($sp)
++	$POP	r29,`$FRAME-$SIZE_T*3`($sp)
++	$POP	r30,`$FRAME-$SIZE_T*2`($sp)
++	$POP	r31,`$FRAME-$SIZE_T*1`($sp)
++	mtlr	r0
++	addi	$sp,$sp,$FRAME
++	blr
++	.long	0
++	.byte	0,12,4,1,0x80,18,5,0
++	.long	0
++.size	.ChaCha20_ctr32_int,.-.ChaCha20_ctr32_int
++
++.align	5
++__ChaCha20_1x:
++Loop_outer:
++	lis	@x[0],0x6170			# synthesize sigma
++	lis	@x[1],0x3320
++	lis	@x[2],0x7962
++	lis	@x[3],0x6b20
++	ori	@x[0],@x[0],0x7865
++	ori	@x[1],@x[1],0x646e
++	ori	@x[2],@x[2],0x2d32
++	ori	@x[3],@x[3],0x6574
++
++	li	r0,10				# inner loop counter
++	lwz	@x[4],0($key)			# load key
++	lwz	@x[5],4($key)
++	lwz	@x[6],8($key)
++	lwz	@x[7],12($key)
++	lwz	@x[8],16($key)
++	mr	@x[12],@d[0]			# copy counter
++	lwz	@x[9],20($key)
++	mr	@x[13],@d[1]
++	lwz	@x[10],24($key)
++	mr	@x[14],@d[2]
++	lwz	@x[11],28($key)
++	mr	@x[15],@d[3]
++
++	mr	@t[0],@x[4]
++	mr	@t[1],@x[5]
++	mr	@t[2],@x[6]
++	mr	@t[3],@x[7]
++
++	mtctr	r0
++Loop:
++___
++	foreach (&ROUND(0, 4, 8,12)) { eval; }
++	foreach (&ROUND(0, 5,10,15)) { eval; }
++$code.=<<___;
++	bdnz	Loop
++
++	subic	$len,$len,64			# $len-=64
++	addi	@x[0],@x[0],0x7865		# accumulate key block
++	addi	@x[1],@x[1],0x646e
++	addi	@x[2],@x[2],0x2d32
++	addi	@x[3],@x[3],0x6574
++	addis	@x[0],@x[0],0x6170
++	addis	@x[1],@x[1],0x3320
++	addis	@x[2],@x[2],0x7962
++	addis	@x[3],@x[3],0x6b20
++
++	subfe.	r0,r0,r0			# borrow?-1:0
++	add	@x[4],@x[4],@t[0]
++	lwz	@t[0],16($key)
++	add	@x[5],@x[5],@t[1]
++	lwz	@t[1],20($key)
++	add	@x[6],@x[6],@t[2]
++	lwz	@t[2],24($key)
++	add	@x[7],@x[7],@t[3]
++	lwz	@t[3],28($key)
++	add	@x[8],@x[8],@t[0]
++	add	@x[9],@x[9],@t[1]
++	add	@x[10],@x[10],@t[2]
++	add	@x[11],@x[11],@t[3]
++
++	add	@x[12],@x[12],@d[0]
++	add	@x[13],@x[13],@d[1]
++	add	@x[14],@x[14],@d[2]
++	add	@x[15],@x[15],@d[3]
++	addi	@d[0],@d[0],1			# increment counter
++___
++if (!$LITTLE_ENDIAN) { for($i=0;$i<16;$i++) {	# flip byte order
++$code.=<<___;
++	mr	@t[$i&3],@x[$i]
++	rotlwi	@x[$i],@x[$i],8
++	rlwimi	@x[$i],@t[$i&3],24,0,7
++	rlwimi	@x[$i],@t[$i&3],24,16,23
++___
++} }
++$code.=<<___;
++	bne	Ltail				# $len-=64 borrowed
++
++	lwz	@t[0],0($inp)			# load input, aligned or not
++	lwz	@t[1],4($inp)
++	${UCMP}i $len,0				# done already?
++	lwz	@t[2],8($inp)
++	lwz	@t[3],12($inp)
++	xor	@x[0],@x[0],@t[0]		# xor with input
++	lwz	@t[0],16($inp)
++	xor	@x[1],@x[1],@t[1]
++	lwz	@t[1],20($inp)
++	xor	@x[2],@x[2],@t[2]
++	lwz	@t[2],24($inp)
++	xor	@x[3],@x[3],@t[3]
++	lwz	@t[3],28($inp)
++	xor	@x[4],@x[4],@t[0]
++	lwz	@t[0],32($inp)
++	xor	@x[5],@x[5],@t[1]
++	lwz	@t[1],36($inp)
++	xor	@x[6],@x[6],@t[2]
++	lwz	@t[2],40($inp)
++	xor	@x[7],@x[7],@t[3]
++	lwz	@t[3],44($inp)
++	xor	@x[8],@x[8],@t[0]
++	lwz	@t[0],48($inp)
++	xor	@x[9],@x[9],@t[1]
++	lwz	@t[1],52($inp)
++	xor	@x[10],@x[10],@t[2]
++	lwz	@t[2],56($inp)
++	xor	@x[11],@x[11],@t[3]
++	lwz	@t[3],60($inp)
++	xor	@x[12],@x[12],@t[0]
++	stw	@x[0],0($out)			# store output, aligned or not
++	xor	@x[13],@x[13],@t[1]
++	stw	@x[1],4($out)
++	xor	@x[14],@x[14],@t[2]
++	stw	@x[2],8($out)
++	xor	@x[15],@x[15],@t[3]
++	stw	@x[3],12($out)
++	stw	@x[4],16($out)
++	stw	@x[5],20($out)
++	stw	@x[6],24($out)
++	stw	@x[7],28($out)
++	stw	@x[8],32($out)
++	stw	@x[9],36($out)
++	stw	@x[10],40($out)
++	stw	@x[11],44($out)
++	stw	@x[12],48($out)
++	stw	@x[13],52($out)
++	stw	@x[14],56($out)
++	addi	$inp,$inp,64
++	stw	@x[15],60($out)
++	addi	$out,$out,64
++
++	bne	Loop_outer
++
++	blr
++
++.align	4
++Ltail:
++	addi	$len,$len,64			# restore tail length
++	subi	$inp,$inp,1			# prepare for *++ptr
++	subi	$out,$out,1
++	addi	@t[0],$sp,$LOCALS-1
++	mtctr	$len
++
++	stw	@x[0],`$LOCALS+0`($sp)		# save whole block to stack
++	stw	@x[1],`$LOCALS+4`($sp)
++	stw	@x[2],`$LOCALS+8`($sp)
++	stw	@x[3],`$LOCALS+12`($sp)
++	stw	@x[4],`$LOCALS+16`($sp)
++	stw	@x[5],`$LOCALS+20`($sp)
++	stw	@x[6],`$LOCALS+24`($sp)
++	stw	@x[7],`$LOCALS+28`($sp)
++	stw	@x[8],`$LOCALS+32`($sp)
++	stw	@x[9],`$LOCALS+36`($sp)
++	stw	@x[10],`$LOCALS+40`($sp)
++	stw	@x[11],`$LOCALS+44`($sp)
++	stw	@x[12],`$LOCALS+48`($sp)
++	stw	@x[13],`$LOCALS+52`($sp)
++	stw	@x[14],`$LOCALS+56`($sp)
++	stw	@x[15],`$LOCALS+60`($sp)
++
++Loop_tail:					# byte-by-byte loop
++	lbzu	@d[0],1($inp)
++	lbzu	@x[0],1(@t[0])
++	xor	@d[1],@d[0],@x[0]
++	stbu	@d[1],1($out)
++	bdnz	Loop_tail
++
++	stw	$sp,`$LOCALS+0`($sp)		# wipe block on stack
++	stw	$sp,`$LOCALS+4`($sp)
++	stw	$sp,`$LOCALS+8`($sp)
++	stw	$sp,`$LOCALS+12`($sp)
++	stw	$sp,`$LOCALS+16`($sp)
++	stw	$sp,`$LOCALS+20`($sp)
++	stw	$sp,`$LOCALS+24`($sp)
++	stw	$sp,`$LOCALS+28`($sp)
++	stw	$sp,`$LOCALS+32`($sp)
++	stw	$sp,`$LOCALS+36`($sp)
++	stw	$sp,`$LOCALS+40`($sp)
++	stw	$sp,`$LOCALS+44`($sp)
++	stw	$sp,`$LOCALS+48`($sp)
++	stw	$sp,`$LOCALS+52`($sp)
++	stw	$sp,`$LOCALS+56`($sp)
++	stw	$sp,`$LOCALS+60`($sp)
++
++	blr
++	.long	0
++	.byte	0,12,0x14,0,0,0,0,0
++___
++
++{{{
++my ($A0,$B0,$C0,$D0,$A1,$B1,$C1,$D1,$A2,$B2,$C2,$D2,$T0,$T1,$T2) =
++    map("v$_",(0..14));
++my (@K)=map("v$_",(15..20));
++my ($FOUR,$sixteen,$twenty4,$twenty,$twelve,$twenty5,$seven) =
++    map("v$_",(21..27));
++my ($inpperm,$outperm,$outmask) = map("v$_",(28..30));
++my @D=("v31",$seven,$T0,$T1,$T2);
++
++my $FRAME=$LOCALS+64+13*16+18*$SIZE_T;	# 13*16 is for v20-v31 offload
++
++sub VMXROUND {
++my $odd = pop;
++my ($a,$b,$c,$d,$t)=@_;
++
++	(
++	"&vadduwm	('$a','$a','$b')",
++	"&vxor		('$d','$d','$a')",
++	"&vperm		('$d','$d','$d','$sixteen')",
++
++	"&vadduwm	('$c','$c','$d')",
++	"&vxor		('$t','$b','$c')",
++	"&vsrw		('$b','$t','$twenty')",
++	"&vslw		('$t','$t','$twelve')",
++	"&vor		('$b','$b','$t')",
++
++	"&vadduwm	('$a','$a','$b')",
++	"&vxor		('$d','$d','$a')",
++	"&vperm		('$d','$d','$d','$twenty4')",
++
++	"&vadduwm	('$c','$c','$d')",
++	"&vxor		('$t','$b','$c')",
++	"&vsrw		('$b','$t','$twenty5')",
++	"&vslw		('$t','$t','$seven')",
++	"&vor		('$b','$b','$t')",
++
++	"&vsldoi	('$c','$c','$c',8)",
++	"&vsldoi	('$b','$b','$b',$odd?4:12)",
++	"&vsldoi	('$d','$d','$d',$odd?12:4)"
++	);
++}
++
++$code.=<<___;
++
++.globl	.ChaCha20_ctr32_vmx
++.align	5
++.ChaCha20_ctr32_vmx:
++	${UCMP}i $len,256
++	blt	__ChaCha20_ctr32_int
++
++	$STU	$sp,-$FRAME($sp)
++	mflr	r0
++	li	r10,`15+$LOCALS+64`
++	li	r11,`31+$LOCALS+64`
++	mfspr	r12,256
++	stvx	v20,r10,$sp
++	addi	r10,r10,32
++	stvx	v21,r11,$sp
++	addi	r11,r11,32
++	stvx	v22,r10,$sp
++	addi	r10,r10,32
++	stvx	v23,r11,$sp
++	addi	r11,r11,32
++	stvx	v24,r10,$sp
++	addi	r10,r10,32
++	stvx	v25,r11,$sp
++	addi	r11,r11,32
++	stvx	v26,r10,$sp
++	addi	r10,r10,32
++	stvx	v27,r11,$sp
++	addi	r11,r11,32
++	stvx	v28,r10,$sp
++	addi	r10,r10,32
++	stvx	v29,r11,$sp
++	addi	r11,r11,32
++	stvx	v30,r10,$sp
++	stvx	v31,r11,$sp
++	stw	r12,`$FRAME-$SIZE_T*18-4`($sp)	# save vrsave
++	$PUSH	r14,`$FRAME-$SIZE_T*18`($sp)
++	$PUSH	r15,`$FRAME-$SIZE_T*17`($sp)
++	$PUSH	r16,`$FRAME-$SIZE_T*16`($sp)
++	$PUSH	r17,`$FRAME-$SIZE_T*15`($sp)
++	$PUSH	r18,`$FRAME-$SIZE_T*14`($sp)
++	$PUSH	r19,`$FRAME-$SIZE_T*13`($sp)
++	$PUSH	r20,`$FRAME-$SIZE_T*12`($sp)
++	$PUSH	r21,`$FRAME-$SIZE_T*11`($sp)
++	$PUSH	r22,`$FRAME-$SIZE_T*10`($sp)
++	$PUSH	r23,`$FRAME-$SIZE_T*9`($sp)
++	$PUSH	r24,`$FRAME-$SIZE_T*8`($sp)
++	$PUSH	r25,`$FRAME-$SIZE_T*7`($sp)
++	$PUSH	r26,`$FRAME-$SIZE_T*6`($sp)
++	$PUSH	r27,`$FRAME-$SIZE_T*5`($sp)
++	$PUSH	r28,`$FRAME-$SIZE_T*4`($sp)
++	$PUSH	r29,`$FRAME-$SIZE_T*3`($sp)
++	$PUSH	r30,`$FRAME-$SIZE_T*2`($sp)
++	$PUSH	r31,`$FRAME-$SIZE_T*1`($sp)
++	li	r12,-1
++	$PUSH	r0, `$FRAME+$LRSAVE`($sp)
++	mtspr	256,r12				# preserve all AltiVec registers
++
++	bl	Lconsts				# returns pointer Lsigma in r12
++	li	@x[0],16
++	li	@x[1],32
++	li	@x[2],48
++	li	@x[3],64
++	li	@x[4],31			# 31 is not a typo
++	li	@x[5],15			# nor is 15
++
++	lvx	@K[1],0,$key			# load key
++	?lvsr	$T0,0,$key			# prepare unaligned load
++	lvx	@K[2],@x[0],$key
++	lvx	@D[0],@x[4],$key
++
++	lvx	@K[3],0,$ctr			# load counter
++	?lvsr	$T1,0,$ctr			# prepare unaligned load
++	lvx	@D[1],@x[5],$ctr
++
++	lvx	@K[0],0,r12			# load constants
++	lvx	@K[5],@x[0],r12			# one
++	lvx	$FOUR,@x[1],r12
++	lvx	$sixteen,@x[2],r12
++	lvx	$twenty4,@x[3],r12
++
++	?vperm	@K[1],@K[2],@K[1],$T0		# align key
++	?vperm	@K[2],@D[0],@K[2],$T0
++	?vperm	@K[3],@D[1],@K[3],$T1		# align counter
++
++	lwz	@d[0],0($ctr)			# load counter to GPR
++	lwz	@d[1],4($ctr)
++	vadduwm	@K[3],@K[3],@K[5]		# adjust AltiVec counter
++	lwz	@d[2],8($ctr)
++	vadduwm	@K[4],@K[3],@K[5]
++	lwz	@d[3],12($ctr)
++	vadduwm	@K[5],@K[4],@K[5]
++
++	vspltisw $twenty,-12			# synthesize constants 
++	vspltisw $twelve,12
++	vspltisw $twenty5,-7
++	#vspltisw $seven,7			# synthesized in the loop
++
++	vxor	$T0,$T0,$T0			# 0x00..00
++	vspltisw $outmask,-1			# 0xff..ff
++	?lvsr	$inpperm,0,$inp			# prepare for unaligned load
++	?lvsl	$outperm,0,$out			# prepare for unaligned store
++	?vperm	$outmask,$outmask,$T0,$outperm
++
++	be?lvsl	$T0,0,@x[0]			# 0x00..0f
++	be?vspltisb $T1,3			# 0x03..03
++	be?vxor	$T0,$T0,$T1			# swap bytes within words
++	be?vxor	$outperm,$outperm,$T1
++	be?vperm $inpperm,$inpperm,$inpperm,$T0
++
++	b	Loop_outer_vmx
++
++.align	4
++Loop_outer_vmx:
++	lis	@x[0],0x6170			# synthesize sigma
++	lis	@x[1],0x3320
++	 vmr	$A0,@K[0]
++	lis	@x[2],0x7962
++	lis	@x[3],0x6b20
++	 vmr	$A1,@K[0]
++	ori	@x[0],@x[0],0x7865
++	ori	@x[1],@x[1],0x646e
++	 vmr	$A2,@K[0]
++	ori	@x[2],@x[2],0x2d32
++	ori	@x[3],@x[3],0x6574
++	 vmr	$B0,@K[1]
++
++	li	r0,10				# inner loop counter
++	lwz	@x[4],0($key)			# load key to GPR
++	 vmr	$B1,@K[1]
++	lwz	@x[5],4($key)
++	 vmr	$B2,@K[1]
++	lwz	@x[6],8($key)
++	 vmr	$C0,@K[2]
++	lwz	@x[7],12($key)
++	 vmr	$C1,@K[2]
++	lwz	@x[8],16($key)
++	 vmr	$C2,@K[2]
++	mr	@x[12],@d[0]			# copy GPR counter
++	lwz	@x[9],20($key)
++	 vmr	$D0,@K[3]
++	mr	@x[13],@d[1]
++	lwz	@x[10],24($key)
++	 vmr	$D1,@K[4]
++	mr	@x[14],@d[2]
++	lwz	@x[11],28($key)
++	 vmr	$D2,@K[5]
++	mr	@x[15],@d[3]
++
++	mr	@t[0],@x[4]
++	mr	@t[1],@x[5]
++	mr	@t[2],@x[6]
++	mr	@t[3],@x[7]
++	vspltisw $seven,7
++
++	mtctr	r0
++	nop
++Loop_vmx:
++___
++	my @thread0=&VMXROUND($A0,$B0,$C0,$D0,$T0,0);
++	my @thread1=&VMXROUND($A1,$B1,$C1,$D1,$T1,0);
++	my @thread2=&VMXROUND($A2,$B2,$C2,$D2,$T2,0);
++	my @thread3=&ROUND(0,4,8,12);
++
++	foreach (@thread0) {
++		eval;			eval(shift(@thread3));
++		eval(shift(@thread1));	eval(shift(@thread3));
++		eval(shift(@thread2));	eval(shift(@thread3));
++	}
++
++	@thread0=&VMXROUND($A0,$B0,$C0,$D0,$T0,1);
++	@thread1=&VMXROUND($A1,$B1,$C1,$D1,$T1,1);
++	@thread2=&VMXROUND($A2,$B2,$C2,$D2,$T2,1);
++	@thread3=&ROUND(0,5,10,15);
++
++	foreach (@thread0) {
++		eval;			eval(shift(@thread3));
++		eval(shift(@thread1));	eval(shift(@thread3));
++		eval(shift(@thread2));	eval(shift(@thread3));
++	}
++$code.=<<___;
++	bdnz	Loop_vmx
++
++	subi	$len,$len,256			# $len-=256
++	addi	@x[0],@x[0],0x7865		# accumulate key block
++	addi	@x[1],@x[1],0x646e
++	addi	@x[2],@x[2],0x2d32
++	addi	@x[3],@x[3],0x6574
++	addis	@x[0],@x[0],0x6170
++	addis	@x[1],@x[1],0x3320
++	addis	@x[2],@x[2],0x7962
++	addis	@x[3],@x[3],0x6b20
++	add	@x[4],@x[4],@t[0]
++	lwz	@t[0],16($key)
++	add	@x[5],@x[5],@t[1]
++	lwz	@t[1],20($key)
++	add	@x[6],@x[6],@t[2]
++	lwz	@t[2],24($key)
++	add	@x[7],@x[7],@t[3]
++	lwz	@t[3],28($key)
++	add	@x[8],@x[8],@t[0]
++	add	@x[9],@x[9],@t[1]
++	add	@x[10],@x[10],@t[2]
++	add	@x[11],@x[11],@t[3]
++	add	@x[12],@x[12],@d[0]
++	add	@x[13],@x[13],@d[1]
++	add	@x[14],@x[14],@d[2]
++	add	@x[15],@x[15],@d[3]
++
++	vadduwm	$A0,$A0,@K[0]			# accumulate key block
++	vadduwm	$A1,$A1,@K[0]
++	vadduwm	$A2,$A2,@K[0]
++	vadduwm	$B0,$B0,@K[1]
++	vadduwm	$B1,$B1,@K[1]
++	vadduwm	$B2,$B2,@K[1]
++	vadduwm	$C0,$C0,@K[2]
++	vadduwm	$C1,$C1,@K[2]
++	vadduwm	$C2,$C2,@K[2]
++	vadduwm	$D0,$D0,@K[3]
++	vadduwm	$D1,$D1,@K[4]
++	vadduwm	$D2,$D2,@K[5]
++
++	addi	@d[0],@d[0],4			# increment counter
++	vadduwm	@K[3],@K[3],$FOUR
++	vadduwm	@K[4],@K[4],$FOUR
++	vadduwm	@K[5],@K[5],$FOUR
++
++___
++if (!$LITTLE_ENDIAN) { for($i=0;$i<16;$i++) {	# flip byte order
++$code.=<<___;
++	mr	@t[$i&3],@x[$i]
++	rotlwi	@x[$i],@x[$i],8
++	rlwimi	@x[$i],@t[$i&3],24,0,7
++	rlwimi	@x[$i],@t[$i&3],24,16,23
++___
++} }
++$code.=<<___;
++	lwz	@t[0],0($inp)			# load input, aligned or not
++	lwz	@t[1],4($inp)
++	lwz	@t[2],8($inp)
++	lwz	@t[3],12($inp)
++	xor	@x[0],@x[0],@t[0]		# xor with input
++	lwz	@t[0],16($inp)
++	xor	@x[1],@x[1],@t[1]
++	lwz	@t[1],20($inp)
++	xor	@x[2],@x[2],@t[2]
++	lwz	@t[2],24($inp)
++	xor	@x[3],@x[3],@t[3]
++	lwz	@t[3],28($inp)
++	xor	@x[4],@x[4],@t[0]
++	lwz	@t[0],32($inp)
++	xor	@x[5],@x[5],@t[1]
++	lwz	@t[1],36($inp)
++	xor	@x[6],@x[6],@t[2]
++	lwz	@t[2],40($inp)
++	xor	@x[7],@x[7],@t[3]
++	lwz	@t[3],44($inp)
++	xor	@x[8],@x[8],@t[0]
++	lwz	@t[0],48($inp)
++	xor	@x[9],@x[9],@t[1]
++	lwz	@t[1],52($inp)
++	xor	@x[10],@x[10],@t[2]
++	lwz	@t[2],56($inp)
++	xor	@x[11],@x[11],@t[3]
++	lwz	@t[3],60($inp)
++	xor	@x[12],@x[12],@t[0]
++	stw	@x[0],0($out)			# store output, aligned or not
++	xor	@x[13],@x[13],@t[1]
++	stw	@x[1],4($out)
++	xor	@x[14],@x[14],@t[2]
++	stw	@x[2],8($out)
++	xor	@x[15],@x[15],@t[3]
++	stw	@x[3],12($out)
++	addi	$inp,$inp,64
++	stw	@x[4],16($out)
++	li	@t[0],16
++	stw	@x[5],20($out)
++	li	@t[1],32
++	stw	@x[6],24($out)
++	li	@t[2],48
++	stw	@x[7],28($out)
++	li	@t[3],64
++	stw	@x[8],32($out)
++	stw	@x[9],36($out)
++	stw	@x[10],40($out)
++	stw	@x[11],44($out)
++	stw	@x[12],48($out)
++	stw	@x[13],52($out)
++	stw	@x[14],56($out)
++	stw	@x[15],60($out)
++	addi	$out,$out,64
++
++	lvx	@D[0],0,$inp			# load input
++	lvx	@D[1],@t[0],$inp
++	lvx	@D[2],@t[1],$inp
++	lvx	@D[3],@t[2],$inp
++	lvx	@D[4],@t[3],$inp
++	addi	$inp,$inp,64
++
++	?vperm	@D[0],@D[1],@D[0],$inpperm	# align input
++	?vperm	@D[1],@D[2],@D[1],$inpperm
++	?vperm	@D[2],@D[3],@D[2],$inpperm
++	?vperm	@D[3],@D[4],@D[3],$inpperm
++	vxor	$A0,$A0,@D[0]			# xor with input
++	vxor	$B0,$B0,@D[1]
++	lvx	@D[1],@t[0],$inp		# keep loading input
++	vxor	$C0,$C0,@D[2]
++	lvx	@D[2],@t[1],$inp
++	vxor	$D0,$D0,@D[3]
++	lvx	@D[3],@t[2],$inp
++	lvx	@D[0],@t[3],$inp
++	addi	$inp,$inp,64
++	li	@t[3],63			# 63 is not a typo
++	vperm	$A0,$A0,$A0,$outperm		# pre-misalign output
++	vperm	$B0,$B0,$B0,$outperm
++	vperm	$C0,$C0,$C0,$outperm
++	vperm	$D0,$D0,$D0,$outperm
++
++	?vperm	@D[4],@D[1],@D[4],$inpperm	# align input
++	?vperm	@D[1],@D[2],@D[1],$inpperm
++	?vperm	@D[2],@D[3],@D[2],$inpperm
++	?vperm	@D[3],@D[0],@D[3],$inpperm
++	vxor	$A1,$A1,@D[4]
++	vxor	$B1,$B1,@D[1]
++	lvx	@D[1],@t[0],$inp		# keep loading input
++	vxor	$C1,$C1,@D[2]
++	lvx	@D[2],@t[1],$inp
++	vxor	$D1,$D1,@D[3]
++	lvx	@D[3],@t[2],$inp
++	lvx	@D[4],@t[3],$inp		# redundant in aligned case
++	addi	$inp,$inp,64
++	vperm	$A1,$A1,$A1,$outperm		# pre-misalign output
++	vperm	$B1,$B1,$B1,$outperm
++	vperm	$C1,$C1,$C1,$outperm
++	vperm	$D1,$D1,$D1,$outperm
++
++	?vperm	@D[0],@D[1],@D[0],$inpperm	# align input
++	?vperm	@D[1],@D[2],@D[1],$inpperm
++	?vperm	@D[2],@D[3],@D[2],$inpperm
++	?vperm	@D[3],@D[4],@D[3],$inpperm
++	vxor	$A2,$A2,@D[0]
++	vxor	$B2,$B2,@D[1]
++	vxor	$C2,$C2,@D[2]
++	vxor	$D2,$D2,@D[3]
++	vperm	$A2,$A2,$A2,$outperm		# pre-misalign output
++	vperm	$B2,$B2,$B2,$outperm
++	vperm	$C2,$C2,$C2,$outperm
++	vperm	$D2,$D2,$D2,$outperm
++
++	andi.	@x[1],$out,15			# is $out aligned?
++	mr	@x[0],$out
++
++	vsel	@D[0],$A0,$B0,$outmask		# collect pre-misaligned output
++	vsel	@D[1],$B0,$C0,$outmask
++	vsel	@D[2],$C0,$D0,$outmask
++	vsel	@D[3],$D0,$A1,$outmask
++	vsel	$B0,$A1,$B1,$outmask
++	vsel	$C0,$B1,$C1,$outmask
++	vsel	$D0,$C1,$D1,$outmask
++	vsel	$A1,$D1,$A2,$outmask
++	vsel	$B1,$A2,$B2,$outmask
++	vsel	$C1,$B2,$C2,$outmask
++	vsel	$D1,$C2,$D2,$outmask
++
++	#stvx	$A0,0,$out			# take it easy on the edges
++	stvx	@D[0],@t[0],$out		# store output
++	stvx	@D[1],@t[1],$out
++	stvx	@D[2],@t[2],$out
++	addi	$out,$out,64
++	stvx	@D[3],0,$out
++	stvx	$B0,@t[0],$out
++	stvx	$C0,@t[1],$out
++	stvx	$D0,@t[2],$out
++	addi	$out,$out,64
++	stvx	$A1,0,$out
++	stvx	$B1,@t[0],$out
++	stvx	$C1,@t[1],$out
++	stvx	$D1,@t[2],$out
++	addi	$out,$out,64
++
++	beq	Laligned_vmx
++
++	sub	@x[2],$out,@x[1]		# in misaligned case edges
++	li	@x[3],0				# are written byte-by-byte
++Lunaligned_tail_vmx:
++	stvebx	$D2,@x[3],@x[2]
++	addi	@x[3],@x[3],1
++	cmpw	@x[3],@x[1]
++	bne	Lunaligned_tail_vmx
++
++	sub	@x[2],@x[0],@x[1]
++Lunaligned_head_vmx:
++	stvebx	$A0,@x[1],@x[2]
++	cmpwi	@x[1],15
++	addi	@x[1],@x[1],1
++	bne	Lunaligned_head_vmx
++
++	${UCMP}i $len,255			# done with 256-byte blocks yet?
++	bgt	Loop_outer_vmx
++
++	b	Ldone_vmx
++
++.align	4
++Laligned_vmx:
++	stvx	$A0,0,@x[0]			# head hexaword was not stored
++
++	${UCMP}i $len,255			# done with 256-byte blocks yet?
++	bgt	Loop_outer_vmx
++	nop
++
++Ldone_vmx:
++	${UCMP}i $len,0				# done yet?
++	bnel	__ChaCha20_1x
++
++	lwz	r12,`$FRAME-$SIZE_T*18-4`($sp)	# pull vrsave
++	li	r10,`15+$LOCALS+64`
++	li	r11,`31+$LOCALS+64`
++	mtspr	256,r12				# restore vrsave
++	lvx	v20,r10,$sp
++	addi	r10,r10,32
++	lvx	v21,r11,$sp
++	addi	r11,r11,32
++	lvx	v22,r10,$sp
++	addi	r10,r10,32
++	lvx	v23,r11,$sp
++	addi	r11,r11,32
++	lvx	v24,r10,$sp
++	addi	r10,r10,32
++	lvx	v25,r11,$sp
++	addi	r11,r11,32
++	lvx	v26,r10,$sp
++	addi	r10,r10,32
++	lvx	v27,r11,$sp
++	addi	r11,r11,32
++	lvx	v28,r10,$sp
++	addi	r10,r10,32
++	lvx	v29,r11,$sp
++	addi	r11,r11,32
++	lvx	v30,r10,$sp
++	lvx	v31,r11,$sp
++	$POP	r0, `$FRAME+$LRSAVE`($sp)
++	$POP	r14,`$FRAME-$SIZE_T*18`($sp)
++	$POP	r15,`$FRAME-$SIZE_T*17`($sp)
++	$POP	r16,`$FRAME-$SIZE_T*16`($sp)
++	$POP	r17,`$FRAME-$SIZE_T*15`($sp)
++	$POP	r18,`$FRAME-$SIZE_T*14`($sp)
++	$POP	r19,`$FRAME-$SIZE_T*13`($sp)
++	$POP	r20,`$FRAME-$SIZE_T*12`($sp)
++	$POP	r21,`$FRAME-$SIZE_T*11`($sp)
++	$POP	r22,`$FRAME-$SIZE_T*10`($sp)
++	$POP	r23,`$FRAME-$SIZE_T*9`($sp)
++	$POP	r24,`$FRAME-$SIZE_T*8`($sp)
++	$POP	r25,`$FRAME-$SIZE_T*7`($sp)
++	$POP	r26,`$FRAME-$SIZE_T*6`($sp)
++	$POP	r27,`$FRAME-$SIZE_T*5`($sp)
++	$POP	r28,`$FRAME-$SIZE_T*4`($sp)
++	$POP	r29,`$FRAME-$SIZE_T*3`($sp)
++	$POP	r30,`$FRAME-$SIZE_T*2`($sp)
++	$POP	r31,`$FRAME-$SIZE_T*1`($sp)
++	mtlr	r0
++	addi	$sp,$sp,$FRAME
++	blr
++	.long	0
++	.byte	0,12,0x04,1,0x80,18,5,0
++	.long	0
++.size	.ChaCha20_ctr32_vmx,.-.ChaCha20_ctr32_vmx
++
++.align	5
++Lconsts:
++	mflr	r0
++	bcl	20,31,\$+4
++	mflr	r12	#vvvvv "distance between . and _vpaes_consts
++	addi	r12,r12,`64-8`
++	mtlr	r0
++	blr
++	.long	0
++	.byte	0,12,0x14,0,0,0,0,0
++	.space	`64-9*4`
++Lsigma:
++	.long   0x61707865,0x3320646e,0x79622d32,0x6b206574
++	.long	1,0,0,0
++	.long	4,0,0,0
++___
++$code.=<<___ 	if ($LITTLE_ENDIAN);
++	.long	0x0e0f0c0d,0x0a0b0809,0x06070405,0x02030001
++	.long	0x0d0e0f0c,0x090a0b08,0x05060704,0x01020300
++___
++$code.=<<___ 	if (!$LITTLE_ENDIAN);	# flipped words
++	.long	0x02030001,0x06070405,0x0a0b0809,0x0e0f0c0d
++	.long	0x01020300,0x05060704,0x090a0b08,0x0d0e0f0c
++___
++$code.=<<___;
++.asciz  "ChaCha20 for PowerPC/AltiVec, CRYPTOGAMS by "
++.align	2
++___
++}}}
++
++foreach (split("\n",$code)) {
++	s/\`([^\`]*)\`/eval $1/ge;
++
++	# instructions prefixed with '?' are endian-specific and need
++	# to be adjusted accordingly...
++	if ($flavour !~ /le$/) {	# big-endian
++	    s/be\?//		or
++	    s/le\?/#le#/	or
++	    s/\?lvsr/lvsl/	or
++	    s/\?lvsl/lvsr/	or
++	    s/\?(vperm\s+v[0-9]+,\s*)(v[0-9]+,\s*)(v[0-9]+,\s*)(v[0-9]+)/$1$3$2$4/ or
++	    s/(vsldoi\s+v[0-9]+,\s*)(v[0-9]+,)\s*(v[0-9]+,\s*)([0-9]+)/$1$3$2 16-$4/;
++	} else {			# little-endian
++	    s/le\?//		or
++	    s/be\?/#be#/	or
++	    s/\?([a-z]+)/$1/;
++	}
++
++	print $_,"\n";
++}
++
++close STDOUT;
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/chacha/asm/chacha-s390x.pl b/CryptoPkg/Library/OpensslLib/openssl/crypto/chacha/asm/chacha-s390x.pl
+new file mode 100755
+index 0000000..c315264
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/chacha/asm/chacha-s390x.pl
+@@ -0,0 +1,326 @@
++#! /usr/bin/env perl
++# Copyright 2016 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
++# in the file LICENSE in the source distribution or at
++# https://www.openssl.org/source/license.html
++
++#
++# ====================================================================
++# Written by Andy Polyakov  for the OpenSSL
++# project. The module is, however, dual licensed under OpenSSL and
++# CRYPTOGAMS licenses depending on where you obtain it. For further
++# details see http://www.openssl.org/~appro/cryptogams/.
++# ====================================================================
++#
++# December 2015
++#
++# ChaCha20 for s390x.
++#
++# 3 times faster than compiler-generated code.
++
++$flavour = shift;
++
++if ($flavour =~ /3[12]/) {
++	$SIZE_T=4;
++	$g="";
++} else {
++	$SIZE_T=8;
++	$g="g";
++}
++
++while (($output=shift) && ($output!~/\w[\w\-]*\.\w+$/)) {}
++open STDOUT,">$output";
++
++sub AUTOLOAD()		# thunk [simplified] x86-style perlasm
++{ my $opcode = $AUTOLOAD; $opcode =~ s/.*:://;
++    $code .= "\t$opcode\t".join(',',@_)."\n";
++}
++
++my $sp="%r15";
++
++my $stdframe=16*$SIZE_T+4*8;
++my $frame=$stdframe+4*20;
++
++my ($out,$inp,$len,$key,$counter)=map("%r$_",(2..6));
++
++my @x=map("%r$_",(0..7,"x","x","x","x",(10..13)));
++my @t=map("%r$_",(8,9));
++
++sub ROUND {
++my ($a0,$b0,$c0,$d0)=@_;
++my ($a1,$b1,$c1,$d1)=map(($_&~3)+(($_+1)&3),($a0,$b0,$c0,$d0));
++my ($a2,$b2,$c2,$d2)=map(($_&~3)+(($_+1)&3),($a1,$b1,$c1,$d1));
++my ($a3,$b3,$c3,$d3)=map(($_&~3)+(($_+1)&3),($a2,$b2,$c2,$d2));
++my ($xc,$xc_)=map("\"$_\"",@t);
++my @x=map("\"$_\"",@x);
++
++	# Consider order in which variables are addressed by their
++	# index:
++	#
++	#	a   b   c   d
++	#
++	#	0   4   8  12 < even round
++	#	1   5   9  13
++	#	2   6  10  14
++	#	3   7  11  15
++	#	0   5  10  15 < odd round
++	#	1   6  11  12
++	#	2   7   8  13
++	#	3   4   9  14
++	#
++	# 'a', 'b' and 'd's are permanently allocated in registers,
++	# @x[0..7,12..15], while 'c's are maintained in memory. If
++	# you observe 'c' column, you'll notice that pair of 'c's is
++	# invariant between rounds. This means that we have to reload
++	# them once per round, in the middle. This is why you'll see
++	# 'c' stores and loads in the middle, but none in the beginning
++	# or end.
++
++	(
++	"&alr	(@x[$a0],@x[$b0])",	# Q1
++	 "&alr	(@x[$a1],@x[$b1])",	# Q2
++	"&xr	(@x[$d0],@x[$a0])",
++	 "&xr	(@x[$d1],@x[$a1])",
++	"&rll	(@x[$d0],@x[$d0],16)",
++	 "&rll	(@x[$d1],@x[$d1],16)",
++
++	"&alr	($xc,@x[$d0])",
++	 "&alr	($xc_,@x[$d1])",
++	"&xr	(@x[$b0],$xc)",
++	 "&xr	(@x[$b1],$xc_)",
++	"&rll	(@x[$b0],@x[$b0],12)",
++	 "&rll	(@x[$b1],@x[$b1],12)",
++
++	"&alr	(@x[$a0],@x[$b0])",
++	 "&alr	(@x[$a1],@x[$b1])",
++	"&xr	(@x[$d0],@x[$a0])",
++	 "&xr	(@x[$d1],@x[$a1])",
++	"&rll	(@x[$d0],@x[$d0],8)",
++	 "&rll	(@x[$d1],@x[$d1],8)",
++
++	"&alr	($xc,@x[$d0])",
++	 "&alr	($xc_,@x[$d1])",
++	"&xr	(@x[$b0],$xc)",
++	 "&xr	(@x[$b1],$xc_)",
++	"&rll	(@x[$b0],@x[$b0],7)",
++	 "&rll	(@x[$b1],@x[$b1],7)",
++
++	"&stm	($xc,$xc_,'$stdframe+4*8+4*$c0($sp)')",	# reload pair of 'c's
++	"&lm	($xc,$xc_,'$stdframe+4*8+4*$c2($sp)')",
++
++	"&alr	(@x[$a2],@x[$b2])",	# Q3
++	 "&alr	(@x[$a3],@x[$b3])",	# Q4
++	"&xr	(@x[$d2],@x[$a2])",
++	 "&xr	(@x[$d3],@x[$a3])",
++	"&rll	(@x[$d2],@x[$d2],16)",
++	 "&rll	(@x[$d3],@x[$d3],16)",
++
++	"&alr	($xc,@x[$d2])",
++	 "&alr	($xc_,@x[$d3])",
++	"&xr	(@x[$b2],$xc)",
++	 "&xr	(@x[$b3],$xc_)",
++	"&rll	(@x[$b2],@x[$b2],12)",
++	 "&rll	(@x[$b3],@x[$b3],12)",
++
++	"&alr	(@x[$a2],@x[$b2])",
++	 "&alr	(@x[$a3],@x[$b3])",
++	"&xr	(@x[$d2],@x[$a2])",
++	 "&xr	(@x[$d3],@x[$a3])",
++	"&rll	(@x[$d2],@x[$d2],8)",
++	 "&rll	(@x[$d3],@x[$d3],8)",
++
++	"&alr	($xc,@x[$d2])",
++	 "&alr	($xc_,@x[$d3])",
++	"&xr	(@x[$b2],$xc)",
++	 "&xr	(@x[$b3],$xc_)",
++	"&rll	(@x[$b2],@x[$b2],7)",
++	 "&rll	(@x[$b3],@x[$b3],7)"
++	);
++}
++
++$code.=<<___;
++.text
++
++.globl	ChaCha20_ctr32
++.type	ChaCha20_ctr32,\@function
++.align	32
++ChaCha20_ctr32:
++	lt${g}r	$len,$len			# $len==0?
++	bzr	%r14
++	a${g}hi	$len,-64
++	l${g}hi	%r1,-$frame
++	stm${g}	%r6,%r15,`6*$SIZE_T`($sp)
++	sl${g}r	$out,$inp			# difference
++	la	$len,0($inp,$len)		# end of input minus 64
++	larl	%r7,.Lsigma
++	lgr	%r0,$sp
++	la	$sp,0(%r1,$sp)
++	st${g}	%r0,0($sp)
++
++	lmg	%r8,%r11,0($key)		# load key
++	lmg	%r12,%r13,0($counter)		# load counter
++	lmg	%r6,%r7,0(%r7)			# load sigma constant
++
++	la	%r14,0($inp)
++	st${g}	$out,$frame+3*$SIZE_T($sp)
++	st${g}	$len,$frame+4*$SIZE_T($sp)
++	stmg	%r6,%r13,$stdframe($sp)		# copy key schedule to stack
++	srlg	@x[12],%r12,32			# 32-bit counter value
++	j	.Loop_outer
++
++.align	16
++.Loop_outer:
++	lm	@x[0],@x[7],$stdframe+4*0($sp)		# load x[0]-x[7]
++	lm	@t[0],@t[1],$stdframe+4*10($sp)		# load x[10]-x[11]
++	lm	@x[13],@x[15],$stdframe+4*13($sp)	# load x[13]-x[15]
++	stm	@t[0],@t[1],$stdframe+4*8+4*10($sp)	# offload x[10]-x[11]
++	lm	@t[0],@t[1],$stdframe+4*8($sp)		# load x[8]-x[9]
++	st	@x[12],$stdframe+4*12($sp)		# save counter
++	st${g}	%r14,$frame+2*$SIZE_T($sp)		# save input pointer
++	lhi	%r14,10
++	j	.Loop
++
++.align	4
++.Loop:
++___
++	foreach (&ROUND(0, 4, 8,12)) { eval; }
++	foreach (&ROUND(0, 5,10,15)) { eval; }
++$code.=<<___;
++	brct	%r14,.Loop
++
++	l${g}	%r14,$frame+2*$SIZE_T($sp)		# pull input pointer
++	stm	@t[0],@t[1],$stdframe+4*8+4*8($sp)	# offload x[8]-x[9]
++	lm${g}	@t[0],@t[1],$frame+3*$SIZE_T($sp)
++
++	al	@x[0],$stdframe+4*0($sp)	# accumulate key schedule
++	al	@x[1],$stdframe+4*1($sp)
++	al	@x[2],$stdframe+4*2($sp)
++	al	@x[3],$stdframe+4*3($sp)
++	al	@x[4],$stdframe+4*4($sp)
++	al	@x[5],$stdframe+4*5($sp)
++	al	@x[6],$stdframe+4*6($sp)
++	al	@x[7],$stdframe+4*7($sp)
++	lrvr	@x[0],@x[0]
++	lrvr	@x[1],@x[1]
++	lrvr	@x[2],@x[2]
++	lrvr	@x[3],@x[3]
++	lrvr	@x[4],@x[4]
++	lrvr	@x[5],@x[5]
++	lrvr	@x[6],@x[6]
++	lrvr	@x[7],@x[7]
++	al	@x[12],$stdframe+4*12($sp)
++	al	@x[13],$stdframe+4*13($sp)
++	al	@x[14],$stdframe+4*14($sp)
++	al	@x[15],$stdframe+4*15($sp)
++	lrvr	@x[12],@x[12]
++	lrvr	@x[13],@x[13]
++	lrvr	@x[14],@x[14]
++	lrvr	@x[15],@x[15]
++
++	la	@t[0],0(@t[0],%r14)		# reconstruct output pointer
++	cl${g}r	%r14,@t[1]
++	jh	.Ltail
++
++	x	@x[0],4*0(%r14)			# xor with input
++	x	@x[1],4*1(%r14)
++	st	@x[0],4*0(@t[0])		# store output
++	x	@x[2],4*2(%r14)
++	st	@x[1],4*1(@t[0])
++	x	@x[3],4*3(%r14)
++	st	@x[2],4*2(@t[0])
++	x	@x[4],4*4(%r14)
++	st	@x[3],4*3(@t[0])
++	 lm	@x[0],@x[3],$stdframe+4*8+4*8($sp)	# load x[8]-x[11]
++	x	@x[5],4*5(%r14)
++	st	@x[4],4*4(@t[0])
++	x	@x[6],4*6(%r14)
++	 al	@x[0],$stdframe+4*8($sp)
++	st	@x[5],4*5(@t[0])
++	x	@x[7],4*7(%r14)
++	 al	@x[1],$stdframe+4*9($sp)
++	st	@x[6],4*6(@t[0])
++	x	@x[12],4*12(%r14)
++	 al	@x[2],$stdframe+4*10($sp)
++	st	@x[7],4*7(@t[0])
++	x	@x[13],4*13(%r14)
++	 al	@x[3],$stdframe+4*11($sp)
++	st	@x[12],4*12(@t[0])
++	x	@x[14],4*14(%r14)
++	st	@x[13],4*13(@t[0])
++	x	@x[15],4*15(%r14)
++	st	@x[14],4*14(@t[0])
++	 lrvr	@x[0],@x[0]
++	st	@x[15],4*15(@t[0])
++	 lrvr	@x[1],@x[1]
++	 lrvr	@x[2],@x[2]
++	 lrvr	@x[3],@x[3]
++	lhi	@x[12],1
++	 x	@x[0],4*8(%r14)
++	al	@x[12],$stdframe+4*12($sp)	# increment counter
++	 x	@x[1],4*9(%r14)
++	 st	@x[0],4*8(@t[0])
++	 x	@x[2],4*10(%r14)
++	 st	@x[1],4*9(@t[0])
++	 x	@x[3],4*11(%r14)
++	 st	@x[2],4*10(@t[0])
++	 st	@x[3],4*11(@t[0])
++
++	cl${g}r	%r14,@t[1]			# done yet?
++	la	%r14,64(%r14)
++	jl	.Loop_outer
++
++.Ldone:
++	xgr	%r0,%r0
++	xgr	%r1,%r1
++	xgr	%r2,%r2
++	xgr	%r3,%r3
++	stmg	%r0,%r3,$stdframe+4*4($sp)	# wipe key copy
++	stmg	%r0,%r3,$stdframe+4*12($sp)
++
++	lm${g}	%r6,%r15,`$frame+6*$SIZE_T`($sp)
++	br	%r14
++
++.align	16
++.Ltail:
++	la	@t[1],64($t[1])
++	stm	@x[0],@x[7],$stdframe+4*0($sp)
++	sl${g}r	@t[1],%r14
++	lm	@x[0],@x[3],$stdframe+4*8+4*8($sp)
++	l${g}hi	@x[6],0
++	stm	@x[12],@x[15],$stdframe+4*12($sp)
++	al	@x[0],$stdframe+4*8($sp)
++	al	@x[1],$stdframe+4*9($sp)
++	al	@x[2],$stdframe+4*10($sp)
++	al	@x[3],$stdframe+4*11($sp)
++	lrvr	@x[0],@x[0]
++	lrvr	@x[1],@x[1]
++	lrvr	@x[2],@x[2]
++	lrvr	@x[3],@x[3]
++	stm	@x[0],@x[3],$stdframe+4*8($sp)
++
++.Loop_tail:
++	llgc	@x[4],0(@x[6],%r14)
++	llgc	@x[5],$stdframe(@x[6],$sp)
++	xr	@x[5],@x[4]
++	stc	@x[5],0(@x[6],@t[0])
++	la	@x[6],1(@x[6])
++	brct	@t[1],.Loop_tail
++
++	j	.Ldone
++.size	ChaCha20_ctr32,.-ChaCha20_ctr32
++
++.align	32
++.Lsigma:
++.long	0x61707865,0x3320646e,0x79622d32,0x6b206574	# endian-neutral
++.asciz	"ChaCha20 for s390x, CRYPTOGAMS by "
++.align	4
++___
++
++foreach (split("\n",$code)) {
++	s/\`([^\`]*)\`/eval $1/ge;
++
++	print $_,"\n";
++}
++close STDOUT;
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/chacha/asm/chacha-x86.pl b/CryptoPkg/Library/OpensslLib/openssl/crypto/chacha/asm/chacha-x86.pl
+new file mode 100755
+index 0000000..61b3286
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/chacha/asm/chacha-x86.pl
+@@ -0,0 +1,1154 @@
++#! /usr/bin/env perl
++# Copyright 2016 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
++# in the file LICENSE in the source distribution or at
++# https://www.openssl.org/source/license.html
++
++#
++# ====================================================================
++# Written by Andy Polyakov  for the OpenSSL
++# project. The module is, however, dual licensed under OpenSSL and
++# CRYPTOGAMS licenses depending on where you obtain it. For further
++# details see http://www.openssl.org/~appro/cryptogams/.
++# ====================================================================
++#
++# January 2015
++#
++# ChaCha20 for x86.
++#
++# Performance in cycles per byte out of large buffer.
++#
++#		1xIALU/gcc	4xSSSE3
++# Pentium	17.5/+80%
++# PIII		14.2/+60%
++# P4		18.6/+84%
++# Core2		9.56/+89%	4.83
++# Westmere	9.50/+45%	3.35
++# Sandy Bridge	10.5/+47%	3.20
++# Haswell	8.15/+50%	2.83
++# Silvermont	17.4/+36%	8.35
++# Goldmont	13.4/+40%	4.36
++# Sledgehammer	10.2/+54%
++# Bulldozer	13.4/+50%	4.38(*)
++#
++# (*)	Bulldozer actually executes 4xXOP code path that delivers 3.55;
++
++$0 =~ m/(.*[\/\\])[^\/\\]+$/; $dir=$1;
++push(@INC,"${dir}","${dir}../../perlasm");
++require "x86asm.pl";
++
++$output=pop;
++open STDOUT,">$output";
++
++&asm_init($ARGV[0],"chacha-x86.pl",$ARGV[$#ARGV] eq "386");
++
++$xmm=$ymm=0;
++for (@ARGV) { $xmm=1 if (/-DOPENSSL_IA32_SSE2/); }
++
++$ymm=1 if ($xmm &&
++		`$ENV{CC} -Wa,-v -c -o /dev/null -x assembler /dev/null 2>&1`
++			=~ /GNU assembler version ([2-9]\.[0-9]+)/ &&
++		($gasver=$1)>=2.19);	# first version supporting AVX
++
++$ymm=1 if ($xmm && !$ymm && $ARGV[0] eq "win32n" &&
++		`nasm -v 2>&1` =~ /NASM version ([2-9]\.[0-9]+)/ &&
++		$1>=2.03);	# first version supporting AVX
++
++$ymm=1 if ($xmm && !$ymm && $ARGV[0] eq "win32" &&
++		`ml 2>&1` =~ /Version ([0-9]+)\./ &&
++		$1>=10);	# first version supporting AVX
++
++$ymm=1 if ($xmm && !$ymm &&
++		`$ENV{CC} -v 2>&1` =~ /(^clang version|based on LLVM) ([3-9]\.[0-9]+)/ &&
++		$2>=3.0);	# first version supporting AVX
++
++$a="eax";
++($b,$b_)=("ebx","ebp");
++($c,$c_)=("ecx","esi");
++($d,$d_)=("edx","edi");
++
++sub QUARTERROUND {
++my ($ai,$bi,$ci,$di,$i)=@_;
++my ($an,$bn,$cn,$dn)=map(($_&~3)+(($_+1)&3),($ai,$bi,$ci,$di));	# next
++my ($ap,$bp,$cp,$dp)=map(($_&~3)+(($_-1)&3),($ai,$bi,$ci,$di));	# previous
++
++	#       a   b   c   d
++	#
++	#       0   4   8  12 < even round
++	#       1   5   9  13
++	#       2   6  10  14
++	#       3   7  11  15
++	#       0   5  10  15 < odd round
++	#       1   6  11  12
++	#       2   7   8  13
++	#       3   4   9  14
++
++	if ($i==0) {
++            my $j=4;
++	    ($ap,$bp,$cp,$dp)=map(($_&~3)+(($_-$j--)&3),($ap,$bp,$cp,$dp));
++	} elsif ($i==3) {
++            my $j=0;
++	    ($an,$bn,$cn,$dn)=map(($_&~3)+(($_+$j++)&3),($an,$bn,$cn,$dn));
++	} elsif ($i==4) {
++            my $j=4;
++	    ($ap,$bp,$cp,$dp)=map(($_&~3)+(($_+$j--)&3),($ap,$bp,$cp,$dp));
++	} elsif ($i==7) {
++            my $j=0;
++	    ($an,$bn,$cn,$dn)=map(($_&~3)+(($_-$j++)&3),($an,$bn,$cn,$dn));
++	}
++
++	#&add	($a,$b);			# see elsewhere
++	&xor	($d,$a);
++	 &mov	(&DWP(4*$cp,"esp"),$c_)		if ($ai>0 && $ai<3);
++	&rol	($d,16);
++	 &mov	(&DWP(4*$bp,"esp"),$b_)		if ($i!=0);
++	&add	($c,$d);
++	 &mov	($c_,&DWP(4*$cn,"esp"))		if ($ai>0 && $ai<3);
++	&xor	($b,$c);
++	 &mov	($d_,&DWP(4*$dn,"esp"))		if ($di!=$dn);
++	&rol	($b,12);
++	 &mov	($b_,&DWP(4*$bn,"esp"))		if ($i<7);
++	 &mov	($b_,&DWP(128,"esp"))		if ($i==7);	# loop counter
++	&add	($a,$b);
++	&xor	($d,$a);
++	&mov	(&DWP(4*$ai,"esp"),$a);
++	&rol	($d,8);
++	&mov	($a,&DWP(4*$an,"esp"));
++	&add	($c,$d);
++	&mov	(&DWP(4*$di,"esp"),$d)		if ($di!=$dn);
++	&mov	($d_,$d)			if ($di==$dn);
++	&xor	($b,$c);
++	 &add	($a,$b_)			if ($i<7);	# elsewhere
++	&rol	($b,7);
++
++	($b,$b_)=($b_,$b);
++	($c,$c_)=($c_,$c);
++	($d,$d_)=($d_,$d);
++}
++
++&static_label("ssse3_shortcut");
++&static_label("xop_shortcut");
++&static_label("ssse3_data");
++&static_label("pic_point");
++
++&function_begin("ChaCha20_ctr32");
++	&xor	("eax","eax");
++	&cmp	("eax",&wparam(2));		# len==0?
++	&je	(&label("no_data"));
++if ($xmm) {
++	&call	(&label("pic_point"));
++&set_label("pic_point");
++	&blindpop("eax");
++	&picmeup("ebp","OPENSSL_ia32cap_P","eax",&label("pic_point"));
++	&test	(&DWP(0,"ebp"),1<<24);		# test FXSR bit
++	&jz	(&label("x86"));
++	&test	(&DWP(4,"ebp"),1<<9);		# test SSSE3 bit
++	&jz	(&label("x86"));
++	&jmp	(&label("ssse3_shortcut"));
++&set_label("x86");
++}
++	&mov	("esi",&wparam(3));		# key
++	&mov	("edi",&wparam(4));		# counter and nonce
++
++	&stack_push(33);
++
++	&mov	("eax",&DWP(4*0,"esi"));	# copy key
++	&mov	("ebx",&DWP(4*1,"esi"));
++	&mov	("ecx",&DWP(4*2,"esi"));
++	&mov	("edx",&DWP(4*3,"esi"));
++	&mov	(&DWP(64+4*4,"esp"),"eax");
++	&mov	(&DWP(64+4*5,"esp"),"ebx");
++	&mov	(&DWP(64+4*6,"esp"),"ecx");
++	&mov	(&DWP(64+4*7,"esp"),"edx");
++	&mov	("eax",&DWP(4*4,"esi"));
++	&mov	("ebx",&DWP(4*5,"esi"));
++	&mov	("ecx",&DWP(4*6,"esi"));
++	&mov	("edx",&DWP(4*7,"esi"));
++	&mov	(&DWP(64+4*8,"esp"),"eax");
++	&mov	(&DWP(64+4*9,"esp"),"ebx");
++	&mov	(&DWP(64+4*10,"esp"),"ecx");
++	&mov	(&DWP(64+4*11,"esp"),"edx");
++	&mov	("eax",&DWP(4*0,"edi"));	# copy counter and nonce
++	&mov	("ebx",&DWP(4*1,"edi"));
++	&mov	("ecx",&DWP(4*2,"edi"));
++	&mov	("edx",&DWP(4*3,"edi"));
++	&sub	("eax",1);
++	&mov	(&DWP(64+4*12,"esp"),"eax");
++	&mov	(&DWP(64+4*13,"esp"),"ebx");
++	&mov	(&DWP(64+4*14,"esp"),"ecx");
++	&mov	(&DWP(64+4*15,"esp"),"edx");
++	&jmp	(&label("entry"));
++
++&set_label("outer_loop",16);
++	&mov	(&wparam(1),$b);		# save input
++	&mov	(&wparam(0),$a);		# save output
++	&mov	(&wparam(2),$c);		# save len
++&set_label("entry");
++	&mov	($a,0x61707865);
++	&mov	(&DWP(4*1,"esp"),0x3320646e);
++	&mov	(&DWP(4*2,"esp"),0x79622d32);
++	&mov	(&DWP(4*3,"esp"),0x6b206574);
++
++	&mov	($b, &DWP(64+4*5,"esp"));	# copy key material
++	&mov	($b_,&DWP(64+4*6,"esp"));
++	&mov	($c, &DWP(64+4*10,"esp"));
++	&mov	($c_,&DWP(64+4*11,"esp"));
++	&mov	($d, &DWP(64+4*13,"esp"));
++	&mov	($d_,&DWP(64+4*14,"esp"));
++	&mov	(&DWP(4*5,"esp"),$b);
++	&mov	(&DWP(4*6,"esp"),$b_);
++	&mov	(&DWP(4*10,"esp"),$c);
++	&mov	(&DWP(4*11,"esp"),$c_);
++	&mov	(&DWP(4*13,"esp"),$d);
++	&mov	(&DWP(4*14,"esp"),$d_);
++
++	&mov	($b, &DWP(64+4*7,"esp"));
++	&mov	($d_,&DWP(64+4*15,"esp"));
++	&mov	($d, &DWP(64+4*12,"esp"));
++	&mov	($b_,&DWP(64+4*4,"esp"));
++	&mov	($c, &DWP(64+4*8,"esp"));
++	&mov	($c_,&DWP(64+4*9,"esp"));
++	&add	($d,1);				# counter value
++	&mov	(&DWP(4*7,"esp"),$b);
++	&mov	(&DWP(4*15,"esp"),$d_);
++	&mov	(&DWP(64+4*12,"esp"),$d);	# save counter value
++
++	&mov	($b,10);			# loop counter
++	&jmp	(&label("loop"));
++
++&set_label("loop",16);
++	&add	($a,$b_);			# elsewhere
++	&mov	(&DWP(128,"esp"),$b);		# save loop counter
++	&mov	($b,$b_);
++	&QUARTERROUND(0, 4, 8, 12, 0);
++	&QUARTERROUND(1, 5, 9, 13, 1);
++	&QUARTERROUND(2, 6,10, 14, 2);
++	&QUARTERROUND(3, 7,11, 15, 3);
++	&QUARTERROUND(0, 5,10, 15, 4);
++	&QUARTERROUND(1, 6,11, 12, 5);
++	&QUARTERROUND(2, 7, 8, 13, 6);
++	&QUARTERROUND(3, 4, 9, 14, 7);
++	&dec	($b);
++	&jnz	(&label("loop"));
++
++	&mov	($b,&wparam(2));		# load len
++
++	&add	($a,0x61707865);		# accumulate key material
++	&add	($b_,&DWP(64+4*4,"esp"));
++	&add	($c, &DWP(64+4*8,"esp"));
++	&add	($c_,&DWP(64+4*9,"esp"));
++
++	&cmp	($b,64);
++	&jb	(&label("tail"));
++
++	&mov	($b,&wparam(1));		# load input pointer
++	&add	($d, &DWP(64+4*12,"esp"));
++	&add	($d_,&DWP(64+4*14,"esp"));
++
++	&xor	($a, &DWP(4*0,$b));		# xor with input
++	&xor	($b_,&DWP(4*4,$b));
++	&mov	(&DWP(4*0,"esp"),$a);
++	&mov	($a,&wparam(0));		# load output pointer
++	&xor	($c, &DWP(4*8,$b));
++	&xor	($c_,&DWP(4*9,$b));
++	&xor	($d, &DWP(4*12,$b));
++	&xor	($d_,&DWP(4*14,$b));
++	&mov	(&DWP(4*4,$a),$b_);		# write output
++	&mov	(&DWP(4*8,$a),$c);
++	&mov	(&DWP(4*9,$a),$c_);
++	&mov	(&DWP(4*12,$a),$d);
++	&mov	(&DWP(4*14,$a),$d_);
++
++	&mov	($b_,&DWP(4*1,"esp"));
++	&mov	($c, &DWP(4*2,"esp"));
++	&mov	($c_,&DWP(4*3,"esp"));
++	&mov	($d, &DWP(4*5,"esp"));
++	&mov	($d_,&DWP(4*6,"esp"));
++	&add	($b_,0x3320646e);		# accumulate key material
++	&add	($c, 0x79622d32);
++	&add	($c_,0x6b206574);
++	&add	($d, &DWP(64+4*5,"esp"));
++	&add	($d_,&DWP(64+4*6,"esp"));
++	&xor	($b_,&DWP(4*1,$b));
++	&xor	($c, &DWP(4*2,$b));
++	&xor	($c_,&DWP(4*3,$b));
++	&xor	($d, &DWP(4*5,$b));
++	&xor	($d_,&DWP(4*6,$b));
++	&mov	(&DWP(4*1,$a),$b_);
++	&mov	(&DWP(4*2,$a),$c);
++	&mov	(&DWP(4*3,$a),$c_);
++	&mov	(&DWP(4*5,$a),$d);
++	&mov	(&DWP(4*6,$a),$d_);
++
++	&mov	($b_,&DWP(4*7,"esp"));
++	&mov	($c, &DWP(4*10,"esp"));
++	&mov	($c_,&DWP(4*11,"esp"));
++	&mov	($d, &DWP(4*13,"esp"));
++	&mov	($d_,&DWP(4*15,"esp"));
++	&add	($b_,&DWP(64+4*7,"esp"));
++	&add	($c, &DWP(64+4*10,"esp"));
++	&add	($c_,&DWP(64+4*11,"esp"));
++	&add	($d, &DWP(64+4*13,"esp"));
++	&add	($d_,&DWP(64+4*15,"esp"));
++	&xor	($b_,&DWP(4*7,$b));
++	&xor	($c, &DWP(4*10,$b));
++	&xor	($c_,&DWP(4*11,$b));
++	&xor	($d, &DWP(4*13,$b));
++	&xor	($d_,&DWP(4*15,$b));
++	&lea	($b,&DWP(4*16,$b));
++	&mov	(&DWP(4*7,$a),$b_);
++	&mov	($b_,&DWP(4*0,"esp"));
++	&mov	(&DWP(4*10,$a),$c);
++	&mov	($c,&wparam(2));		# len
++	&mov	(&DWP(4*11,$a),$c_);
++	&mov	(&DWP(4*13,$a),$d);
++	&mov	(&DWP(4*15,$a),$d_);
++	&mov	(&DWP(4*0,$a),$b_);
++	&lea	($a,&DWP(4*16,$a));
++	&sub	($c,64);
++	&jnz	(&label("outer_loop"));
++
++	&jmp	(&label("done"));
++
++&set_label("tail");
++	&add	($d, &DWP(64+4*12,"esp"));
++	&add	($d_,&DWP(64+4*14,"esp"));
++	&mov	(&DWP(4*0,"esp"),$a);
++	&mov	(&DWP(4*4,"esp"),$b_);
++	&mov	(&DWP(4*8,"esp"),$c);
++	&mov	(&DWP(4*9,"esp"),$c_);
++	&mov	(&DWP(4*12,"esp"),$d);
++	&mov	(&DWP(4*14,"esp"),$d_);
++
++	&mov	($b_,&DWP(4*1,"esp"));
++	&mov	($c, &DWP(4*2,"esp"));
++	&mov	($c_,&DWP(4*3,"esp"));
++	&mov	($d, &DWP(4*5,"esp"));
++	&mov	($d_,&DWP(4*6,"esp"));
++	&add	($b_,0x3320646e);		# accumulate key material
++	&add	($c, 0x79622d32);
++	&add	($c_,0x6b206574);
++	&add	($d, &DWP(64+4*5,"esp"));
++	&add	($d_,&DWP(64+4*6,"esp"));
++	&mov	(&DWP(4*1,"esp"),$b_);
++	&mov	(&DWP(4*2,"esp"),$c);
++	&mov	(&DWP(4*3,"esp"),$c_);
++	&mov	(&DWP(4*5,"esp"),$d);
++	&mov	(&DWP(4*6,"esp"),$d_);
++
++	&mov	($b_,&DWP(4*7,"esp"));
++	&mov	($c, &DWP(4*10,"esp"));
++	&mov	($c_,&DWP(4*11,"esp"));
++	&mov	($d, &DWP(4*13,"esp"));
++	&mov	($d_,&DWP(4*15,"esp"));
++	&add	($b_,&DWP(64+4*7,"esp"));
++	&add	($c, &DWP(64+4*10,"esp"));
++	&add	($c_,&DWP(64+4*11,"esp"));
++	&add	($d, &DWP(64+4*13,"esp"));
++	&add	($d_,&DWP(64+4*15,"esp"));
++	&mov	(&DWP(4*7,"esp"),$b_);
++	&mov	($b_,&wparam(1));		# load input
++	&mov	(&DWP(4*10,"esp"),$c);
++	&mov	($c,&wparam(0));		# load output
++	&mov	(&DWP(4*11,"esp"),$c_);
++	&xor	($c_,$c_);
++	&mov	(&DWP(4*13,"esp"),$d);
++	&mov	(&DWP(4*15,"esp"),$d_);
++
++	&xor	("eax","eax");
++	&xor	("edx","edx");
++&set_label("tail_loop");
++	&movb	("al",&BP(0,$c_,$b_));
++	&movb	("dl",&BP(0,"esp",$c_));
++	&lea	($c_,&DWP(1,$c_));
++	&xor	("al","dl");
++	&mov	(&BP(-1,$c,$c_),"al");
++	&dec	($b);
++	&jnz	(&label("tail_loop"));
++
++&set_label("done");
++	&stack_pop(33);
++&set_label("no_data");
++&function_end("ChaCha20_ctr32");
++
++if ($xmm) {
++my ($xa,$xa_,$xb,$xb_,$xc,$xc_,$xd,$xd_)=map("xmm$_",(0..7));
++my ($out,$inp,$len)=("edi","esi","ecx");
++
++sub QUARTERROUND_SSSE3 {
++my ($ai,$bi,$ci,$di,$i)=@_;
++my ($an,$bn,$cn,$dn)=map(($_&~3)+(($_+1)&3),($ai,$bi,$ci,$di));	# next
++my ($ap,$bp,$cp,$dp)=map(($_&~3)+(($_-1)&3),($ai,$bi,$ci,$di));	# previous
++
++	#       a   b   c   d
++	#
++	#       0   4   8  12 < even round
++	#       1   5   9  13
++	#       2   6  10  14
++	#       3   7  11  15
++	#       0   5  10  15 < odd round
++	#       1   6  11  12
++	#       2   7   8  13
++	#       3   4   9  14
++
++	if ($i==0) {
++            my $j=4;
++	    ($ap,$bp,$cp,$dp)=map(($_&~3)+(($_-$j--)&3),($ap,$bp,$cp,$dp));
++	} elsif ($i==3) {
++            my $j=0;
++	    ($an,$bn,$cn,$dn)=map(($_&~3)+(($_+$j++)&3),($an,$bn,$cn,$dn));
++	} elsif ($i==4) {
++            my $j=4;
++	    ($ap,$bp,$cp,$dp)=map(($_&~3)+(($_+$j--)&3),($ap,$bp,$cp,$dp));
++	} elsif ($i==7) {
++            my $j=0;
++	    ($an,$bn,$cn,$dn)=map(($_&~3)+(($_-$j++)&3),($an,$bn,$cn,$dn));
++	}
++
++	#&paddd	($xa,$xb);			# see elsewhere
++	#&pxor	($xd,$xa);			# see elsewhere
++	 &movdqa(&QWP(16*$cp-128,"ebx"),$xc_)	if ($ai>0 && $ai<3);
++	&pshufb	($xd,&QWP(0,"eax"));		# rot16
++	 &movdqa(&QWP(16*$bp-128,"ebx"),$xb_)	if ($i!=0);
++	&paddd	($xc,$xd);
++	 &movdqa($xc_,&QWP(16*$cn-128,"ebx"))	if ($ai>0 && $ai<3);
++	&pxor	($xb,$xc);
++	 &movdqa($xb_,&QWP(16*$bn-128,"ebx"))	if ($i<7);
++	&movdqa	($xa_,$xb);			# borrow as temporary
++	&pslld	($xb,12);
++	&psrld	($xa_,20);
++	&por	($xb,$xa_);
++	 &movdqa($xa_,&QWP(16*$an-128,"ebx"));
++	&paddd	($xa,$xb);
++	 &movdqa($xd_,&QWP(16*$dn-128,"ebx"))	if ($di!=$dn);
++	&pxor	($xd,$xa);
++	&movdqa	(&QWP(16*$ai-128,"ebx"),$xa);
++	&pshufb	($xd,&QWP(16,"eax"));		# rot8
++	&paddd	($xc,$xd);
++	&movdqa	(&QWP(16*$di-128,"ebx"),$xd)	if ($di!=$dn);
++	&movdqa	($xd_,$xd)			if ($di==$dn);
++	&pxor	($xb,$xc);
++	 &paddd	($xa_,$xb_)			if ($i<7);	# elsewhere
++	&movdqa	($xa,$xb);			# borrow as temporary
++	&pslld	($xb,7);
++	&psrld	($xa,25);
++	 &pxor	($xd_,$xa_)			if ($i<7);	# elsewhere
++	&por	($xb,$xa);
++
++	($xa,$xa_)=($xa_,$xa);
++	($xb,$xb_)=($xb_,$xb);
++	($xc,$xc_)=($xc_,$xc);
++	($xd,$xd_)=($xd_,$xd);
++}
++
++&function_begin("ChaCha20_ssse3");
++&set_label("ssse3_shortcut");
++if ($ymm) {
++	&test		(&DWP(4,"ebp"),1<<11);		# test XOP bit
++	&jnz		(&label("xop_shortcut"));
++}
++
++	&mov		($out,&wparam(0));
++	&mov		($inp,&wparam(1));
++	&mov		($len,&wparam(2));
++	&mov		("edx",&wparam(3));		# key
++	&mov		("ebx",&wparam(4));		# counter and nonce
++
++	&mov		("ebp","esp");
++	&stack_push	(131);
++	&and		("esp",-64);
++	&mov		(&DWP(512,"esp"),"ebp");
++
++	&lea		("eax",&DWP(&label("ssse3_data")."-".
++				    &label("pic_point"),"eax"));
++	&movdqu		("xmm3",&QWP(0,"ebx"));		# counter and nonce
++
++if (defined($gasver) && $gasver>=2.17) {		# even though we encode
++							# pshufb manually, we
++							# handle only register
++							# operands, while this
++							# segment uses memory
++							# operand...
++	&cmp		($len,64*4);
++	&jb		(&label("1x"));
++
++	&mov		(&DWP(512+4,"esp"),"edx");	# offload pointers
++	&mov		(&DWP(512+8,"esp"),"ebx");
++	&sub		($len,64*4);			# bias len
++	&lea		("ebp",&DWP(256+128,"esp"));	# size optimization
++
++	&movdqu		("xmm7",&QWP(0,"edx"));		# key
++	&pshufd		("xmm0","xmm3",0x00);
++	&pshufd		("xmm1","xmm3",0x55);
++	&pshufd		("xmm2","xmm3",0xaa);
++	&pshufd		("xmm3","xmm3",0xff);
++	 &paddd		("xmm0",&QWP(16*3,"eax"));	# fix counters
++	&pshufd		("xmm4","xmm7",0x00);
++	&pshufd		("xmm5","xmm7",0x55);
++	 &psubd		("xmm0",&QWP(16*4,"eax"));
++	&pshufd		("xmm6","xmm7",0xaa);
++	&pshufd		("xmm7","xmm7",0xff);
++	&movdqa		(&QWP(16*12-128,"ebp"),"xmm0");
++	&movdqa		(&QWP(16*13-128,"ebp"),"xmm1");
++	&movdqa		(&QWP(16*14-128,"ebp"),"xmm2");
++	&movdqa		(&QWP(16*15-128,"ebp"),"xmm3");
++	 &movdqu	("xmm3",&QWP(16,"edx"));	# key
++	&movdqa		(&QWP(16*4-128,"ebp"),"xmm4");
++	&movdqa		(&QWP(16*5-128,"ebp"),"xmm5");
++	&movdqa		(&QWP(16*6-128,"ebp"),"xmm6");
++	&movdqa		(&QWP(16*7-128,"ebp"),"xmm7");
++	 &movdqa	("xmm7",&QWP(16*2,"eax"));	# sigma
++	 &lea		("ebx",&DWP(128,"esp"));	# size optimization
++
++	&pshufd		("xmm0","xmm3",0x00);
++	&pshufd		("xmm1","xmm3",0x55);
++	&pshufd		("xmm2","xmm3",0xaa);
++	&pshufd		("xmm3","xmm3",0xff);
++	&pshufd		("xmm4","xmm7",0x00);
++	&pshufd		("xmm5","xmm7",0x55);
++	&pshufd		("xmm6","xmm7",0xaa);
++	&pshufd		("xmm7","xmm7",0xff);
++	&movdqa		(&QWP(16*8-128,"ebp"),"xmm0");
++	&movdqa		(&QWP(16*9-128,"ebp"),"xmm1");
++	&movdqa		(&QWP(16*10-128,"ebp"),"xmm2");
++	&movdqa		(&QWP(16*11-128,"ebp"),"xmm3");
++	&movdqa		(&QWP(16*0-128,"ebp"),"xmm4");
++	&movdqa		(&QWP(16*1-128,"ebp"),"xmm5");
++	&movdqa		(&QWP(16*2-128,"ebp"),"xmm6");
++	&movdqa		(&QWP(16*3-128,"ebp"),"xmm7");
++
++	&lea		($inp,&DWP(128,$inp));		# size optimization
++	&lea		($out,&DWP(128,$out));		# size optimization
++	&jmp		(&label("outer_loop"));
++
++&set_label("outer_loop",16);
++	#&movdqa	("xmm0",&QWP(16*0-128,"ebp"));	# copy key material
++	&movdqa		("xmm1",&QWP(16*1-128,"ebp"));
++	&movdqa		("xmm2",&QWP(16*2-128,"ebp"));
++	&movdqa		("xmm3",&QWP(16*3-128,"ebp"));
++	#&movdqa	("xmm4",&QWP(16*4-128,"ebp"));
++	&movdqa		("xmm5",&QWP(16*5-128,"ebp"));
++	&movdqa		("xmm6",&QWP(16*6-128,"ebp"));
++	&movdqa		("xmm7",&QWP(16*7-128,"ebp"));
++	#&movdqa	(&QWP(16*0-128,"ebx"),"xmm0");
++	&movdqa		(&QWP(16*1-128,"ebx"),"xmm1");
++	&movdqa		(&QWP(16*2-128,"ebx"),"xmm2");
++	&movdqa		(&QWP(16*3-128,"ebx"),"xmm3");
++	#&movdqa	(&QWP(16*4-128,"ebx"),"xmm4");
++	&movdqa		(&QWP(16*5-128,"ebx"),"xmm5");
++	&movdqa		(&QWP(16*6-128,"ebx"),"xmm6");
++	&movdqa		(&QWP(16*7-128,"ebx"),"xmm7");
++	#&movdqa	("xmm0",&QWP(16*8-128,"ebp"));
++	#&movdqa	("xmm1",&QWP(16*9-128,"ebp"));
++	&movdqa		("xmm2",&QWP(16*10-128,"ebp"));
++	&movdqa		("xmm3",&QWP(16*11-128,"ebp"));
++	&movdqa		("xmm4",&QWP(16*12-128,"ebp"));
++	&movdqa		("xmm5",&QWP(16*13-128,"ebp"));
++	&movdqa		("xmm6",&QWP(16*14-128,"ebp"));
++	&movdqa		("xmm7",&QWP(16*15-128,"ebp"));
++	&paddd		("xmm4",&QWP(16*4,"eax"));	# counter value
++	#&movdqa	(&QWP(16*8-128,"ebx"),"xmm0");
++	#&movdqa	(&QWP(16*9-128,"ebx"),"xmm1");
++	&movdqa		(&QWP(16*10-128,"ebx"),"xmm2");
++	&movdqa		(&QWP(16*11-128,"ebx"),"xmm3");
++	&movdqa		(&QWP(16*12-128,"ebx"),"xmm4");
++	&movdqa		(&QWP(16*13-128,"ebx"),"xmm5");
++	&movdqa		(&QWP(16*14-128,"ebx"),"xmm6");
++	&movdqa		(&QWP(16*15-128,"ebx"),"xmm7");
++	&movdqa		(&QWP(16*12-128,"ebp"),"xmm4");	# save counter value
++
++	&movdqa		($xa, &QWP(16*0-128,"ebp"));
++	&movdqa		($xd, "xmm4");
++	&movdqa		($xb_,&QWP(16*4-128,"ebp"));
++	&movdqa		($xc, &QWP(16*8-128,"ebp"));
++	&movdqa		($xc_,&QWP(16*9-128,"ebp"));
++
++	&mov		("edx",10);			# loop counter
++	&nop		();
++
++&set_label("loop",16);
++	&paddd		($xa,$xb_);			# elsewhere
++	&movdqa		($xb,$xb_);
++	&pxor		($xd,$xa);			# elsewhere
++	&QUARTERROUND_SSSE3(0, 4, 8, 12, 0);
++	&QUARTERROUND_SSSE3(1, 5, 9, 13, 1);
++	&QUARTERROUND_SSSE3(2, 6,10, 14, 2);
++	&QUARTERROUND_SSSE3(3, 7,11, 15, 3);
++	&QUARTERROUND_SSSE3(0, 5,10, 15, 4);
++	&QUARTERROUND_SSSE3(1, 6,11, 12, 5);
++	&QUARTERROUND_SSSE3(2, 7, 8, 13, 6);
++	&QUARTERROUND_SSSE3(3, 4, 9, 14, 7);
++	&dec		("edx");
++	&jnz		(&label("loop"));
++
++	&movdqa		(&QWP(16*4-128,"ebx"),$xb_);
++	&movdqa		(&QWP(16*8-128,"ebx"),$xc);
++	&movdqa		(&QWP(16*9-128,"ebx"),$xc_);
++	&movdqa		(&QWP(16*12-128,"ebx"),$xd);
++	&movdqa		(&QWP(16*14-128,"ebx"),$xd_);
++
++    my ($xa0,$xa1,$xa2,$xa3,$xt0,$xt1,$xt2,$xt3)=map("xmm$_",(0..7));
++
++	#&movdqa	($xa0,&QWP(16*0-128,"ebx"));	# it's there
++	&movdqa		($xa1,&QWP(16*1-128,"ebx"));
++	&movdqa		($xa2,&QWP(16*2-128,"ebx"));
++	&movdqa		($xa3,&QWP(16*3-128,"ebx"));
++
++    for($i=0;$i<256;$i+=64) {
++	&paddd		($xa0,&QWP($i+16*0-128,"ebp"));	# accumulate key material
++	&paddd		($xa1,&QWP($i+16*1-128,"ebp"));
++	&paddd		($xa2,&QWP($i+16*2-128,"ebp"));
++	&paddd		($xa3,&QWP($i+16*3-128,"ebp"));
++
++	&movdqa		($xt2,$xa0);		# "de-interlace" data
++	&punpckldq	($xa0,$xa1);
++	&movdqa		($xt3,$xa2);
++	&punpckldq	($xa2,$xa3);
++	&punpckhdq	($xt2,$xa1);
++	&punpckhdq	($xt3,$xa3);
++	&movdqa		($xa1,$xa0);
++	&punpcklqdq	($xa0,$xa2);		# "a0"
++	&movdqa		($xa3,$xt2);
++	&punpcklqdq	($xt2,$xt3);		# "a2"
++	&punpckhqdq	($xa1,$xa2);		# "a1"
++	&punpckhqdq	($xa3,$xt3);		# "a3"
++
++	#($xa2,$xt2)=($xt2,$xa2);
++
++	&movdqu		($xt0,&QWP(64*0-128,$inp));	# load input
++	&movdqu		($xt1,&QWP(64*1-128,$inp));
++	&movdqu		($xa2,&QWP(64*2-128,$inp));
++	&movdqu		($xt3,&QWP(64*3-128,$inp));
++	&lea		($inp,&QWP($i<192?16:(64*4-16*3),$inp));
++	&pxor		($xt0,$xa0);
++	&movdqa		($xa0,&QWP($i+16*4-128,"ebx"))	if ($i<192);
++	&pxor		($xt1,$xa1);
++	&movdqa		($xa1,&QWP($i+16*5-128,"ebx"))	if ($i<192);
++	&pxor		($xt2,$xa2);
++	&movdqa		($xa2,&QWP($i+16*6-128,"ebx"))	if ($i<192);
++	&pxor		($xt3,$xa3);
++	&movdqa		($xa3,&QWP($i+16*7-128,"ebx"))	if ($i<192);
++	&movdqu		(&QWP(64*0-128,$out),$xt0);	# store output
++	&movdqu		(&QWP(64*1-128,$out),$xt1);
++	&movdqu		(&QWP(64*2-128,$out),$xt2);
++	&movdqu		(&QWP(64*3-128,$out),$xt3);
++	&lea		($out,&QWP($i<192?16:(64*4-16*3),$out));
++    }
++	&sub		($len,64*4);
++	&jnc		(&label("outer_loop"));
++
++	&add		($len,64*4);
++	&jz		(&label("done"));
++
++	&mov		("ebx",&DWP(512+8,"esp"));	# restore pointers
++	&lea		($inp,&DWP(-128,$inp));
++	&mov		("edx",&DWP(512+4,"esp"));
++	&lea		($out,&DWP(-128,$out));
++
++	&movd		("xmm2",&DWP(16*12-128,"ebp"));	# counter value
++	&movdqu		("xmm3",&QWP(0,"ebx"));
++	&paddd		("xmm2",&QWP(16*6,"eax"));	# +four
++	&pand		("xmm3",&QWP(16*7,"eax"));
++	&por		("xmm3","xmm2");		# counter value
++}
++{
++my ($a,$b,$c,$d,$t,$t1,$rot16,$rot24)=map("xmm$_",(0..7));
++
++sub SSSE3ROUND {	# critical path is 20 "SIMD ticks" per round
++	&paddd		($a,$b);
++	&pxor		($d,$a);
++	&pshufb		($d,$rot16);
++
++	&paddd		($c,$d);
++	&pxor		($b,$c);
++	&movdqa		($t,$b);
++	&psrld		($b,20);
++	&pslld		($t,12);
++	&por		($b,$t);
++
++	&paddd		($a,$b);
++	&pxor		($d,$a);
++	&pshufb		($d,$rot24);
++
++	&paddd		($c,$d);
++	&pxor		($b,$c);
++	&movdqa		($t,$b);
++	&psrld		($b,25);
++	&pslld		($t,7);
++	&por		($b,$t);
++}
++
++&set_label("1x");
++	&movdqa		($a,&QWP(16*2,"eax"));		# sigma
++	&movdqu		($b,&QWP(0,"edx"));
++	&movdqu		($c,&QWP(16,"edx"));
++	#&movdqu	($d,&QWP(0,"ebx"));		# already loaded
++	&movdqa		($rot16,&QWP(0,"eax"));
++	&movdqa		($rot24,&QWP(16,"eax"));
++	&mov		(&DWP(16*3,"esp"),"ebp");
++
++	&movdqa		(&QWP(16*0,"esp"),$a);
++	&movdqa		(&QWP(16*1,"esp"),$b);
++	&movdqa		(&QWP(16*2,"esp"),$c);
++	&movdqa		(&QWP(16*3,"esp"),$d);
++	&mov		("edx",10);
++	&jmp		(&label("loop1x"));
++
++&set_label("outer1x",16);
++	&movdqa		($d,&QWP(16*5,"eax"));		# one
++	&movdqa		($a,&QWP(16*0,"esp"));
++	&movdqa		($b,&QWP(16*1,"esp"));
++	&movdqa		($c,&QWP(16*2,"esp"));
++	&paddd		($d,&QWP(16*3,"esp"));
++	&mov		("edx",10);
++	&movdqa		(&QWP(16*3,"esp"),$d);
++	&jmp		(&label("loop1x"));
++
++&set_label("loop1x",16);
++	&SSSE3ROUND();
++	&pshufd	($c,$c,0b01001110);
++	&pshufd	($b,$b,0b00111001);
++	&pshufd	($d,$d,0b10010011);
++	&nop	();
++
++	&SSSE3ROUND();
++	&pshufd	($c,$c,0b01001110);
++	&pshufd	($b,$b,0b10010011);
++	&pshufd	($d,$d,0b00111001);
++
++	&dec		("edx");
++	&jnz		(&label("loop1x"));
++
++	&paddd		($a,&QWP(16*0,"esp"));
++	&paddd		($b,&QWP(16*1,"esp"));
++	&paddd		($c,&QWP(16*2,"esp"));
++	&paddd		($d,&QWP(16*3,"esp"));
++
++	&cmp		($len,64);
++	&jb		(&label("tail"));
++
++	&movdqu		($t,&QWP(16*0,$inp));
++	&movdqu		($t1,&QWP(16*1,$inp));
++	&pxor		($a,$t);		# xor with input
++	&movdqu		($t,&QWP(16*2,$inp));
++	&pxor		($b,$t1);
++	&movdqu		($t1,&QWP(16*3,$inp));
++	&pxor		($c,$t);
++	&pxor		($d,$t1);
++	&lea		($inp,&DWP(16*4,$inp));	# inp+=64
++
++	&movdqu		(&QWP(16*0,$out),$a);	# write output
++	&movdqu		(&QWP(16*1,$out),$b);
++	&movdqu		(&QWP(16*2,$out),$c);
++	&movdqu		(&QWP(16*3,$out),$d);
++	&lea		($out,&DWP(16*4,$out));	# inp+=64
++
++	&sub		($len,64);
++	&jnz		(&label("outer1x"));
++
++	&jmp		(&label("done"));
++
++&set_label("tail");
++	&movdqa		(&QWP(16*0,"esp"),$a);
++	&movdqa		(&QWP(16*1,"esp"),$b);
++	&movdqa		(&QWP(16*2,"esp"),$c);
++	&movdqa		(&QWP(16*3,"esp"),$d);
++
++	&xor		("eax","eax");
++	&xor		("edx","edx");
++	&xor		("ebp","ebp");
++
++&set_label("tail_loop");
++	&movb		("al",&BP(0,"esp","ebp"));
++	&movb		("dl",&BP(0,$inp,"ebp"));
++	&lea		("ebp",&DWP(1,"ebp"));
++	&xor		("al","dl");
++	&movb		(&BP(-1,$out,"ebp"),"al");
++	&dec		($len);
++	&jnz		(&label("tail_loop"));
++}
++&set_label("done");
++	&mov		("esp",&DWP(512,"esp"));
++&function_end("ChaCha20_ssse3");
++
++&align	(64);
++&set_label("ssse3_data");
++&data_byte(0x2,0x3,0x0,0x1, 0x6,0x7,0x4,0x5, 0xa,0xb,0x8,0x9, 0xe,0xf,0xc,0xd);
++&data_byte(0x3,0x0,0x1,0x2, 0x7,0x4,0x5,0x6, 0xb,0x8,0x9,0xa, 0xf,0xc,0xd,0xe);
++&data_word(0x61707865,0x3320646e,0x79622d32,0x6b206574);
++&data_word(0,1,2,3);
++&data_word(4,4,4,4);
++&data_word(1,0,0,0);
++&data_word(4,0,0,0);
++&data_word(0,-1,-1,-1);
++&align	(64);
++}
++&asciz	("ChaCha20 for x86, CRYPTOGAMS by ");
++
++if ($ymm) {
++my ($xa,$xa_,$xb,$xb_,$xc,$xc_,$xd,$xd_)=map("xmm$_",(0..7));
++my ($out,$inp,$len)=("edi","esi","ecx");
++
++sub QUARTERROUND_XOP {
++my ($ai,$bi,$ci,$di,$i)=@_;
++my ($an,$bn,$cn,$dn)=map(($_&~3)+(($_+1)&3),($ai,$bi,$ci,$di));	# next
++my ($ap,$bp,$cp,$dp)=map(($_&~3)+(($_-1)&3),($ai,$bi,$ci,$di));	# previous
++
++	#       a   b   c   d
++	#
++	#       0   4   8  12 < even round
++	#       1   5   9  13
++	#       2   6  10  14
++	#       3   7  11  15
++	#       0   5  10  15 < odd round
++	#       1   6  11  12
++	#       2   7   8  13
++	#       3   4   9  14
++
++	if ($i==0) {
++            my $j=4;
++	    ($ap,$bp,$cp,$dp)=map(($_&~3)+(($_-$j--)&3),($ap,$bp,$cp,$dp));
++	} elsif ($i==3) {
++            my $j=0;
++	    ($an,$bn,$cn,$dn)=map(($_&~3)+(($_+$j++)&3),($an,$bn,$cn,$dn));
++	} elsif ($i==4) {
++            my $j=4;
++	    ($ap,$bp,$cp,$dp)=map(($_&~3)+(($_+$j--)&3),($ap,$bp,$cp,$dp));
++	} elsif ($i==7) {
++            my $j=0;
++	    ($an,$bn,$cn,$dn)=map(($_&~3)+(($_-$j++)&3),($an,$bn,$cn,$dn));
++	}
++
++	#&vpaddd	($xa,$xa,$xb);			# see elsewhere
++	#&vpxor		($xd,$xd,$xa);			# see elsewhere
++	 &vmovdqa	(&QWP(16*$cp-128,"ebx"),$xc_)	if ($ai>0 && $ai<3);
++	&vprotd		($xd,$xd,16);
++	 &vmovdqa	(&QWP(16*$bp-128,"ebx"),$xb_)	if ($i!=0);
++	&vpaddd		($xc,$xc,$xd);
++	 &vmovdqa	($xc_,&QWP(16*$cn-128,"ebx"))	if ($ai>0 && $ai<3);
++	&vpxor		($xb,$i!=0?$xb:$xb_,$xc);
++	 &vmovdqa	($xa_,&QWP(16*$an-128,"ebx"));
++	&vprotd		($xb,$xb,12);
++	 &vmovdqa	($xb_,&QWP(16*$bn-128,"ebx"))	if ($i<7);
++	&vpaddd		($xa,$xa,$xb);
++	 &vmovdqa	($xd_,&QWP(16*$dn-128,"ebx"))	if ($di!=$dn);
++	&vpxor		($xd,$xd,$xa);
++	 &vpaddd	($xa_,$xa_,$xb_)		if ($i<7);	# elsewhere
++	&vprotd		($xd,$xd,8);
++	&vmovdqa	(&QWP(16*$ai-128,"ebx"),$xa);
++	&vpaddd		($xc,$xc,$xd);
++	&vmovdqa	(&QWP(16*$di-128,"ebx"),$xd)	if ($di!=$dn);
++	&vpxor		($xb,$xb,$xc);
++	 &vpxor		($xd_,$di==$dn?$xd:$xd_,$xa_)	if ($i<7);	# elsewhere
++	&vprotd		($xb,$xb,7);
++
++	($xa,$xa_)=($xa_,$xa);
++	($xb,$xb_)=($xb_,$xb);
++	($xc,$xc_)=($xc_,$xc);
++	($xd,$xd_)=($xd_,$xd);
++}
++
++&function_begin("ChaCha20_xop");
++&set_label("xop_shortcut");
++	&mov		($out,&wparam(0));
++	&mov		($inp,&wparam(1));
++	&mov		($len,&wparam(2));
++	&mov		("edx",&wparam(3));		# key
++	&mov		("ebx",&wparam(4));		# counter and nonce
++	&vzeroupper	();
++
++	&mov		("ebp","esp");
++	&stack_push	(131);
++	&and		("esp",-64);
++	&mov		(&DWP(512,"esp"),"ebp");
++
++	&lea		("eax",&DWP(&label("ssse3_data")."-".
++				    &label("pic_point"),"eax"));
++	&vmovdqu	("xmm3",&QWP(0,"ebx"));		# counter and nonce
++
++	&cmp		($len,64*4);
++	&jb		(&label("1x"));
++
++	&mov		(&DWP(512+4,"esp"),"edx");	# offload pointers
++	&mov		(&DWP(512+8,"esp"),"ebx");
++	&sub		($len,64*4);			# bias len
++	&lea		("ebp",&DWP(256+128,"esp"));	# size optimization
++
++	&vmovdqu	("xmm7",&QWP(0,"edx"));		# key
++	&vpshufd	("xmm0","xmm3",0x00);
++	&vpshufd	("xmm1","xmm3",0x55);
++	&vpshufd	("xmm2","xmm3",0xaa);
++	&vpshufd	("xmm3","xmm3",0xff);
++	 &vpaddd	("xmm0","xmm0",&QWP(16*3,"eax"));	# fix counters
++	&vpshufd	("xmm4","xmm7",0x00);
++	&vpshufd	("xmm5","xmm7",0x55);
++	 &vpsubd	("xmm0","xmm0",&QWP(16*4,"eax"));
++	&vpshufd	("xmm6","xmm7",0xaa);
++	&vpshufd	("xmm7","xmm7",0xff);
++	&vmovdqa	(&QWP(16*12-128,"ebp"),"xmm0");
++	&vmovdqa	(&QWP(16*13-128,"ebp"),"xmm1");
++	&vmovdqa	(&QWP(16*14-128,"ebp"),"xmm2");
++	&vmovdqa	(&QWP(16*15-128,"ebp"),"xmm3");
++	 &vmovdqu	("xmm3",&QWP(16,"edx"));	# key
++	&vmovdqa	(&QWP(16*4-128,"ebp"),"xmm4");
++	&vmovdqa	(&QWP(16*5-128,"ebp"),"xmm5");
++	&vmovdqa	(&QWP(16*6-128,"ebp"),"xmm6");
++	&vmovdqa	(&QWP(16*7-128,"ebp"),"xmm7");
++	 &vmovdqa	("xmm7",&QWP(16*2,"eax"));	# sigma
++	 &lea		("ebx",&DWP(128,"esp"));	# size optimization
++
++	&vpshufd	("xmm0","xmm3",0x00);
++	&vpshufd	("xmm1","xmm3",0x55);
++	&vpshufd	("xmm2","xmm3",0xaa);
++	&vpshufd	("xmm3","xmm3",0xff);
++	&vpshufd	("xmm4","xmm7",0x00);
++	&vpshufd	("xmm5","xmm7",0x55);
++	&vpshufd	("xmm6","xmm7",0xaa);
++	&vpshufd	("xmm7","xmm7",0xff);
++	&vmovdqa	(&QWP(16*8-128,"ebp"),"xmm0");
++	&vmovdqa	(&QWP(16*9-128,"ebp"),"xmm1");
++	&vmovdqa	(&QWP(16*10-128,"ebp"),"xmm2");
++	&vmovdqa	(&QWP(16*11-128,"ebp"),"xmm3");
++	&vmovdqa	(&QWP(16*0-128,"ebp"),"xmm4");
++	&vmovdqa	(&QWP(16*1-128,"ebp"),"xmm5");
++	&vmovdqa	(&QWP(16*2-128,"ebp"),"xmm6");
++	&vmovdqa	(&QWP(16*3-128,"ebp"),"xmm7");
++
++	&lea		($inp,&DWP(128,$inp));		# size optimization
++	&lea		($out,&DWP(128,$out));		# size optimization
++	&jmp		(&label("outer_loop"));
++
++&set_label("outer_loop",32);
++	#&vmovdqa	("xmm0",&QWP(16*0-128,"ebp"));	# copy key material
++	&vmovdqa	("xmm1",&QWP(16*1-128,"ebp"));
++	&vmovdqa	("xmm2",&QWP(16*2-128,"ebp"));
++	&vmovdqa	("xmm3",&QWP(16*3-128,"ebp"));
++	#&vmovdqa	("xmm4",&QWP(16*4-128,"ebp"));
++	&vmovdqa	("xmm5",&QWP(16*5-128,"ebp"));
++	&vmovdqa	("xmm6",&QWP(16*6-128,"ebp"));
++	&vmovdqa	("xmm7",&QWP(16*7-128,"ebp"));
++	#&vmovdqa	(&QWP(16*0-128,"ebx"),"xmm0");
++	&vmovdqa	(&QWP(16*1-128,"ebx"),"xmm1");
++	&vmovdqa	(&QWP(16*2-128,"ebx"),"xmm2");
++	&vmovdqa	(&QWP(16*3-128,"ebx"),"xmm3");
++	#&vmovdqa	(&QWP(16*4-128,"ebx"),"xmm4");
++	&vmovdqa	(&QWP(16*5-128,"ebx"),"xmm5");
++	&vmovdqa	(&QWP(16*6-128,"ebx"),"xmm6");
++	&vmovdqa	(&QWP(16*7-128,"ebx"),"xmm7");
++	#&vmovdqa	("xmm0",&QWP(16*8-128,"ebp"));
++	#&vmovdqa	("xmm1",&QWP(16*9-128,"ebp"));
++	&vmovdqa	("xmm2",&QWP(16*10-128,"ebp"));
++	&vmovdqa	("xmm3",&QWP(16*11-128,"ebp"));
++	&vmovdqa	("xmm4",&QWP(16*12-128,"ebp"));
++	&vmovdqa	("xmm5",&QWP(16*13-128,"ebp"));
++	&vmovdqa	("xmm6",&QWP(16*14-128,"ebp"));
++	&vmovdqa	("xmm7",&QWP(16*15-128,"ebp"));
++	&vpaddd		("xmm4","xmm4",&QWP(16*4,"eax"));	# counter value
++	#&vmovdqa	(&QWP(16*8-128,"ebx"),"xmm0");
++	#&vmovdqa	(&QWP(16*9-128,"ebx"),"xmm1");
++	&vmovdqa	(&QWP(16*10-128,"ebx"),"xmm2");
++	&vmovdqa	(&QWP(16*11-128,"ebx"),"xmm3");
++	&vmovdqa	(&QWP(16*12-128,"ebx"),"xmm4");
++	&vmovdqa	(&QWP(16*13-128,"ebx"),"xmm5");
++	&vmovdqa	(&QWP(16*14-128,"ebx"),"xmm6");
++	&vmovdqa	(&QWP(16*15-128,"ebx"),"xmm7");
++	&vmovdqa	(&QWP(16*12-128,"ebp"),"xmm4");	# save counter value
++
++	&vmovdqa	($xa, &QWP(16*0-128,"ebp"));
++	&vmovdqa	($xd, "xmm4");
++	&vmovdqa	($xb_,&QWP(16*4-128,"ebp"));
++	&vmovdqa	($xc, &QWP(16*8-128,"ebp"));
++	&vmovdqa	($xc_,&QWP(16*9-128,"ebp"));
++
++	&mov		("edx",10);			# loop counter
++	&nop		();
++
++&set_label("loop",32);
++	&vpaddd		($xa,$xa,$xb_);			# elsewhere
++	&vpxor		($xd,$xd,$xa);			# elsewhere
++	&QUARTERROUND_XOP(0, 4, 8, 12, 0);
++	&QUARTERROUND_XOP(1, 5, 9, 13, 1);
++	&QUARTERROUND_XOP(2, 6,10, 14, 2);
++	&QUARTERROUND_XOP(3, 7,11, 15, 3);
++	&QUARTERROUND_XOP(0, 5,10, 15, 4);
++	&QUARTERROUND_XOP(1, 6,11, 12, 5);
++	&QUARTERROUND_XOP(2, 7, 8, 13, 6);
++	&QUARTERROUND_XOP(3, 4, 9, 14, 7);
++	&dec		("edx");
++	&jnz		(&label("loop"));
++
++	&vmovdqa	(&QWP(16*4-128,"ebx"),$xb_);
++	&vmovdqa	(&QWP(16*8-128,"ebx"),$xc);
++	&vmovdqa	(&QWP(16*9-128,"ebx"),$xc_);
++	&vmovdqa	(&QWP(16*12-128,"ebx"),$xd);
++	&vmovdqa	(&QWP(16*14-128,"ebx"),$xd_);
++
++    my ($xa0,$xa1,$xa2,$xa3,$xt0,$xt1,$xt2,$xt3)=map("xmm$_",(0..7));
++
++	#&vmovdqa	($xa0,&QWP(16*0-128,"ebx"));	# it's there
++	&vmovdqa	($xa1,&QWP(16*1-128,"ebx"));
++	&vmovdqa	($xa2,&QWP(16*2-128,"ebx"));
++	&vmovdqa	($xa3,&QWP(16*3-128,"ebx"));
++
++    for($i=0;$i<256;$i+=64) {
++	&vpaddd		($xa0,$xa0,&QWP($i+16*0-128,"ebp"));	# accumulate key material
++	&vpaddd		($xa1,$xa1,&QWP($i+16*1-128,"ebp"));
++	&vpaddd		($xa2,$xa2,&QWP($i+16*2-128,"ebp"));
++	&vpaddd		($xa3,$xa3,&QWP($i+16*3-128,"ebp"));
++
++	&vpunpckldq	($xt2,$xa0,$xa1);	# "de-interlace" data
++	&vpunpckldq	($xt3,$xa2,$xa3);
++	&vpunpckhdq	($xa0,$xa0,$xa1);
++	&vpunpckhdq	($xa2,$xa2,$xa3);
++	&vpunpcklqdq	($xa1,$xt2,$xt3);	# "a0"
++	&vpunpckhqdq	($xt2,$xt2,$xt3);	# "a1"
++	&vpunpcklqdq	($xt3,$xa0,$xa2);	# "a2"
++	&vpunpckhqdq	($xa3,$xa0,$xa2);	# "a3"
++
++	&vpxor		($xt0,$xa1,&QWP(64*0-128,$inp));
++	&vpxor		($xt1,$xt2,&QWP(64*1-128,$inp));
++	&vpxor		($xt2,$xt3,&QWP(64*2-128,$inp));
++	&vpxor		($xt3,$xa3,&QWP(64*3-128,$inp));
++	&lea		($inp,&QWP($i<192?16:(64*4-16*3),$inp));
++	&vmovdqa	($xa0,&QWP($i+16*4-128,"ebx"))	if ($i<192);
++	&vmovdqa	($xa1,&QWP($i+16*5-128,"ebx"))	if ($i<192);
++	&vmovdqa	($xa2,&QWP($i+16*6-128,"ebx"))	if ($i<192);
++	&vmovdqa	($xa3,&QWP($i+16*7-128,"ebx"))	if ($i<192);
++	&vmovdqu	(&QWP(64*0-128,$out),$xt0);	# store output
++	&vmovdqu	(&QWP(64*1-128,$out),$xt1);
++	&vmovdqu	(&QWP(64*2-128,$out),$xt2);
++	&vmovdqu	(&QWP(64*3-128,$out),$xt3);
++	&lea		($out,&QWP($i<192?16:(64*4-16*3),$out));
++    }
++	&sub		($len,64*4);
++	&jnc		(&label("outer_loop"));
++
++	&add		($len,64*4);
++	&jz		(&label("done"));
++
++	&mov		("ebx",&DWP(512+8,"esp"));	# restore pointers
++	&lea		($inp,&DWP(-128,$inp));
++	&mov		("edx",&DWP(512+4,"esp"));
++	&lea		($out,&DWP(-128,$out));
++
++	&vmovd		("xmm2",&DWP(16*12-128,"ebp"));	# counter value
++	&vmovdqu	("xmm3",&QWP(0,"ebx"));
++	&vpaddd		("xmm2","xmm2",&QWP(16*6,"eax"));# +four
++	&vpand		("xmm3","xmm3",&QWP(16*7,"eax"));
++	&vpor		("xmm3","xmm3","xmm2");		# counter value
++{
++my ($a,$b,$c,$d,$t,$t1,$rot16,$rot24)=map("xmm$_",(0..7));
++
++sub XOPROUND {
++	&vpaddd		($a,$a,$b);
++	&vpxor		($d,$d,$a);
++	&vprotd		($d,$d,16);
++
++	&vpaddd		($c,$c,$d);
++	&vpxor		($b,$b,$c);
++	&vprotd		($b,$b,12);
++
++	&vpaddd		($a,$a,$b);
++	&vpxor		($d,$d,$a);
++	&vprotd		($d,$d,8);
++
++	&vpaddd		($c,$c,$d);
++	&vpxor		($b,$b,$c);
++	&vprotd		($b,$b,7);
++}
++
++&set_label("1x");
++	&vmovdqa	($a,&QWP(16*2,"eax"));		# sigma
++	&vmovdqu	($b,&QWP(0,"edx"));
++	&vmovdqu	($c,&QWP(16,"edx"));
++	#&vmovdqu	($d,&QWP(0,"ebx"));		# already loaded
++	&vmovdqa	($rot16,&QWP(0,"eax"));
++	&vmovdqa	($rot24,&QWP(16,"eax"));
++	&mov		(&DWP(16*3,"esp"),"ebp");
++
++	&vmovdqa	(&QWP(16*0,"esp"),$a);
++	&vmovdqa	(&QWP(16*1,"esp"),$b);
++	&vmovdqa	(&QWP(16*2,"esp"),$c);
++	&vmovdqa	(&QWP(16*3,"esp"),$d);
++	&mov		("edx",10);
++	&jmp		(&label("loop1x"));
++
++&set_label("outer1x",16);
++	&vmovdqa	($d,&QWP(16*5,"eax"));		# one
++	&vmovdqa	($a,&QWP(16*0,"esp"));
++	&vmovdqa	($b,&QWP(16*1,"esp"));
++	&vmovdqa	($c,&QWP(16*2,"esp"));
++	&vpaddd		($d,$d,&QWP(16*3,"esp"));
++	&mov		("edx",10);
++	&vmovdqa	(&QWP(16*3,"esp"),$d);
++	&jmp		(&label("loop1x"));
++
++&set_label("loop1x",16);
++	&XOPROUND();
++	&vpshufd	($c,$c,0b01001110);
++	&vpshufd	($b,$b,0b00111001);
++	&vpshufd	($d,$d,0b10010011);
++
++	&XOPROUND();
++	&vpshufd	($c,$c,0b01001110);
++	&vpshufd	($b,$b,0b10010011);
++	&vpshufd	($d,$d,0b00111001);
++
++	&dec		("edx");
++	&jnz		(&label("loop1x"));
++
++	&vpaddd		($a,$a,&QWP(16*0,"esp"));
++	&vpaddd		($b,$b,&QWP(16*1,"esp"));
++	&vpaddd		($c,$c,&QWP(16*2,"esp"));
++	&vpaddd		($d,$d,&QWP(16*3,"esp"));
++
++	&cmp		($len,64);
++	&jb		(&label("tail"));
++
++	&vpxor		($a,$a,&QWP(16*0,$inp));	# xor with input
++	&vpxor		($b,$b,&QWP(16*1,$inp));
++	&vpxor		($c,$c,&QWP(16*2,$inp));
++	&vpxor		($d,$d,&QWP(16*3,$inp));
++	&lea		($inp,&DWP(16*4,$inp));		# inp+=64
++
++	&vmovdqu	(&QWP(16*0,$out),$a);		# write output
++	&vmovdqu	(&QWP(16*1,$out),$b);
++	&vmovdqu	(&QWP(16*2,$out),$c);
++	&vmovdqu	(&QWP(16*3,$out),$d);
++	&lea		($out,&DWP(16*4,$out));		# inp+=64
++
++	&sub		($len,64);
++	&jnz		(&label("outer1x"));
++
++	&jmp		(&label("done"));
++
++&set_label("tail");
++	&vmovdqa	(&QWP(16*0,"esp"),$a);
++	&vmovdqa	(&QWP(16*1,"esp"),$b);
++	&vmovdqa	(&QWP(16*2,"esp"),$c);
++	&vmovdqa	(&QWP(16*3,"esp"),$d);
++
++	&xor		("eax","eax");
++	&xor		("edx","edx");
++	&xor		("ebp","ebp");
++
++&set_label("tail_loop");
++	&movb		("al",&BP(0,"esp","ebp"));
++	&movb		("dl",&BP(0,$inp,"ebp"));
++	&lea		("ebp",&DWP(1,"ebp"));
++	&xor		("al","dl");
++	&movb		(&BP(-1,$out,"ebp"),"al");
++	&dec		($len);
++	&jnz		(&label("tail_loop"));
++}
++&set_label("done");
++	&vzeroupper	();
++	&mov		("esp",&DWP(512,"esp"));
++&function_end("ChaCha20_xop");
++}
++
++&asm_finish();
++
++close STDOUT;
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/chacha/asm/chacha-x86_64.pl b/CryptoPkg/Library/OpensslLib/openssl/crypto/chacha/asm/chacha-x86_64.pl
+new file mode 100755
+index 0000000..347dfcb
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/chacha/asm/chacha-x86_64.pl
+@@ -0,0 +1,2245 @@
++#! /usr/bin/env perl
++# Copyright 2016 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
++# in the file LICENSE in the source distribution or at
++# https://www.openssl.org/source/license.html
++
++#
++# ====================================================================
++# Written by Andy Polyakov  for the OpenSSL
++# project. The module is, however, dual licensed under OpenSSL and
++# CRYPTOGAMS licenses depending on where you obtain it. For further
++# details see http://www.openssl.org/~appro/cryptogams/.
++# ====================================================================
++#
++# November 2014
++#
++# ChaCha20 for x86_64.
++#
++# Performance in cycles per byte out of large buffer.
++#
++#		IALU/gcc 4.8(i)	1xSSSE3/SSE2	4xSSSE3	    8xAVX2
++#
++# P4		9.48/+99%	-/22.7(ii)	-
++# Core2		7.83/+55%	7.90/8.08	4.35
++# Westmere	7.19/+50%	5.60/6.70	3.00
++# Sandy Bridge	8.31/+42%	5.45/6.76	2.72
++# Ivy Bridge	6.71/+46%	5.40/6.49	2.41
++# Haswell	5.92/+43%	5.20/6.45	2.42	    1.23
++# Silvermont	12.0/+33%	7.75/7.40	7.03(iii)
++# Goldmont	10.6/+17%	5.10/-		3.28
++# Sledgehammer	7.28/+52%	-/14.2(ii)	-
++# Bulldozer	9.66/+28%	9.85/11.1	3.06(iv)
++# VIA Nano	10.5/+46%	6.72/8.60	6.05
++#
++# (i)	compared to older gcc 3.x one can observe >2x improvement on
++#	most platforms;
++# (ii)	as it can be seen, SSE2 performance is too low on legacy
++#	processors; NxSSE2 results are naturally better, but not
++#	impressively better than IALU ones, which is why you won't
++#	find SSE2 code below;
++# (iii)	this is not optimal result for Atom because of MSROM
++#	limitations, SSE2 can do better, but gain is considered too
++#	low to justify the [maintenance] effort;
++# (iv)	Bulldozer actually executes 4xXOP code path that delivers 2.20;
++
++$flavour = shift;
++$output  = shift;
++if ($flavour =~ /\./) { $output = $flavour; undef $flavour; }
++
++$win64=0; $win64=1 if ($flavour =~ /[nm]asm|mingw64/ || $output =~ /\.asm$/);
++
++$0 =~ m/(.*[\/\\])[^\/\\]+$/; $dir=$1;
++( $xlate="${dir}x86_64-xlate.pl" and -f $xlate ) or
++( $xlate="${dir}../../perlasm/x86_64-xlate.pl" and -f $xlate) or
++die "can't locate x86_64-xlate.pl";
++
++if (`$ENV{CC} -Wa,-v -c -o /dev/null -x assembler /dev/null 2>&1`
++		=~ /GNU assembler version ([2-9]\.[0-9]+)/) {
++	$avx = ($1>=2.19) + ($1>=2.22);
++}
++
++if (!$avx && $win64 && ($flavour =~ /nasm/ || $ENV{ASM} =~ /nasm/) &&
++	   `nasm -v 2>&1` =~ /NASM version ([2-9]\.[0-9]+)/) {
++	$avx = ($1>=2.09) + ($1>=2.10);
++}
++
++if (!$avx && $win64 && ($flavour =~ /masm/ || $ENV{ASM} =~ /ml64/) &&
++	   `ml64 2>&1` =~ /Version ([0-9]+)\./) {
++	$avx = ($1>=10) + ($1>=11);
++}
++
++if (!$avx && `$ENV{CC} -v 2>&1` =~ /((?:^clang|LLVM) version|.*based on LLVM) ([3-9]\.[0-9]+)/) {
++	$avx = ($2>=3.0) + ($2>3.0);
++}
++
++open OUT,"| \"$^X\" \"$xlate\" $flavour \"$output\"";
++*STDOUT=*OUT;
++
++# input parameter block
++($out,$inp,$len,$key,$counter)=("%rdi","%rsi","%rdx","%rcx","%r8");
++
++$code.=<<___;
++.text
++
++.extern OPENSSL_ia32cap_P
++
++.align	64
++.Lzero:
++.long	0,0,0,0
++.Lone:
++.long	1,0,0,0
++.Linc:
++.long	0,1,2,3
++.Lfour:
++.long	4,4,4,4
++.Lincy:
++.long	0,2,4,6,1,3,5,7
++.Leight:
++.long	8,8,8,8,8,8,8,8
++.Lrot16:
++.byte	0x2,0x3,0x0,0x1, 0x6,0x7,0x4,0x5, 0xa,0xb,0x8,0x9, 0xe,0xf,0xc,0xd
++.Lrot24:
++.byte	0x3,0x0,0x1,0x2, 0x7,0x4,0x5,0x6, 0xb,0x8,0x9,0xa, 0xf,0xc,0xd,0xe
++.Lsigma:
++.asciz	"expand 32-byte k"
++.asciz	"ChaCha20 for x86_64, CRYPTOGAMS by "
++___
++
++sub AUTOLOAD()          # thunk [simplified] 32-bit style perlasm
++{ my $opcode = $AUTOLOAD; $opcode =~ s/.*:://;
++  my $arg = pop;
++    $arg = "\$$arg" if ($arg*1 eq $arg);
++    $code .= "\t$opcode\t".join(',',$arg,reverse @_)."\n";
++}
++
++@x=("%eax","%ebx","%ecx","%edx",map("%r${_}d",(8..11)),
++    "%nox","%nox","%nox","%nox",map("%r${_}d",(12..15)));
++@t=("%esi","%edi");
++
++sub ROUND {			# critical path is 24 cycles per round
++my ($a0,$b0,$c0,$d0)=@_;
++my ($a1,$b1,$c1,$d1)=map(($_&~3)+(($_+1)&3),($a0,$b0,$c0,$d0));
++my ($a2,$b2,$c2,$d2)=map(($_&~3)+(($_+1)&3),($a1,$b1,$c1,$d1));
++my ($a3,$b3,$c3,$d3)=map(($_&~3)+(($_+1)&3),($a2,$b2,$c2,$d2));
++my ($xc,$xc_)=map("\"$_\"",@t);
++my @x=map("\"$_\"",@x);
++
++	# Consider order in which variables are addressed by their
++	# index:
++	#
++	#	a   b   c   d
++	#
++	#	0   4   8  12 < even round
++	#	1   5   9  13
++	#	2   6  10  14
++	#	3   7  11  15
++	#	0   5  10  15 < odd round
++	#	1   6  11  12
++	#	2   7   8  13
++	#	3   4   9  14
++	#
++	# 'a', 'b' and 'd's are permanently allocated in registers,
++	# @x[0..7,12..15], while 'c's are maintained in memory. If
++	# you observe 'c' column, you'll notice that pair of 'c's is
++	# invariant between rounds. This means that we have to reload
++	# them once per round, in the middle. This is why you'll see
++	# bunch of 'c' stores and loads in the middle, but none in
++	# the beginning or end.
++
++	# Normally instructions would be interleaved to favour in-order
++	# execution. Generally out-of-order cores manage it gracefully,
++	# but not this time for some reason. As in-order execution
++	# cores are dying breed, old Atom is the only one around,
++	# instructions are left uninterleaved. Besides, Atom is better
++	# off executing 1xSSSE3 code anyway...
++
++	(
++	"&add	(@x[$a0],@x[$b0])",	# Q1
++	"&xor	(@x[$d0],@x[$a0])",
++	"&rol	(@x[$d0],16)",
++	 "&add	(@x[$a1],@x[$b1])",	# Q2
++	 "&xor	(@x[$d1],@x[$a1])",
++	 "&rol	(@x[$d1],16)",
++
++	"&add	($xc,@x[$d0])",
++	"&xor	(@x[$b0],$xc)",
++	"&rol	(@x[$b0],12)",
++	 "&add	($xc_,@x[$d1])",
++	 "&xor	(@x[$b1],$xc_)",
++	 "&rol	(@x[$b1],12)",
++
++	"&add	(@x[$a0],@x[$b0])",
++	"&xor	(@x[$d0],@x[$a0])",
++	"&rol	(@x[$d0],8)",
++	 "&add	(@x[$a1],@x[$b1])",
++	 "&xor	(@x[$d1],@x[$a1])",
++	 "&rol	(@x[$d1],8)",
++
++	"&add	($xc,@x[$d0])",
++	"&xor	(@x[$b0],$xc)",
++	"&rol	(@x[$b0],7)",
++	 "&add	($xc_,@x[$d1])",
++	 "&xor	(@x[$b1],$xc_)",
++	 "&rol	(@x[$b1],7)",
++
++	"&mov	(\"4*$c0(%rsp)\",$xc)",	# reload pair of 'c's
++	 "&mov	(\"4*$c1(%rsp)\",$xc_)",
++	"&mov	($xc,\"4*$c2(%rsp)\")",
++	 "&mov	($xc_,\"4*$c3(%rsp)\")",
++
++	"&add	(@x[$a2],@x[$b2])",	# Q3
++	"&xor	(@x[$d2],@x[$a2])",
++	"&rol	(@x[$d2],16)",
++	 "&add	(@x[$a3],@x[$b3])",	# Q4
++	 "&xor	(@x[$d3],@x[$a3])",
++	 "&rol	(@x[$d3],16)",
++
++	"&add	($xc,@x[$d2])",
++	"&xor	(@x[$b2],$xc)",
++	"&rol	(@x[$b2],12)",
++	 "&add	($xc_,@x[$d3])",
++	 "&xor	(@x[$b3],$xc_)",
++	 "&rol	(@x[$b3],12)",
++
++	"&add	(@x[$a2],@x[$b2])",
++	"&xor	(@x[$d2],@x[$a2])",
++	"&rol	(@x[$d2],8)",
++	 "&add	(@x[$a3],@x[$b3])",
++	 "&xor	(@x[$d3],@x[$a3])",
++	 "&rol	(@x[$d3],8)",
++
++	"&add	($xc,@x[$d2])",
++	"&xor	(@x[$b2],$xc)",
++	"&rol	(@x[$b2],7)",
++	 "&add	($xc_,@x[$d3])",
++	 "&xor	(@x[$b3],$xc_)",
++	 "&rol	(@x[$b3],7)"
++	);
++}
++
++########################################################################
++# Generic code path that handles all lengths on pre-SSSE3 processors.
++$code.=<<___;
++.globl	ChaCha20_ctr32
++.type	ChaCha20_ctr32,\@function,5
++.align	64
++ChaCha20_ctr32:
++	cmp	\$0,$len
++	je	.Lno_data
++	mov	OPENSSL_ia32cap_P+4(%rip),%r10
++	test	\$`1<<(41-32)`,%r10d
++	jnz	.LChaCha20_ssse3
++
++	push	%rbx
++	push	%rbp
++	push	%r12
++	push	%r13
++	push	%r14
++	push	%r15
++	sub	\$64+24,%rsp
++
++	#movdqa	.Lsigma(%rip),%xmm0
++	movdqu	($key),%xmm1
++	movdqu	16($key),%xmm2
++	movdqu	($counter),%xmm3
++	movdqa	.Lone(%rip),%xmm4
++
++	#movdqa	%xmm0,4*0(%rsp)		# key[0]
++	movdqa	%xmm1,4*4(%rsp)		# key[1]
++	movdqa	%xmm2,4*8(%rsp)		# key[2]
++	movdqa	%xmm3,4*12(%rsp)	# key[3]
++	mov	$len,%rbp		# reassign $len
++	jmp	.Loop_outer
++
++.align	32
++.Loop_outer:
++	mov	\$0x61707865,@x[0]      # 'expa'
++	mov	\$0x3320646e,@x[1]      # 'nd 3'
++	mov	\$0x79622d32,@x[2]      # '2-by'
++	mov	\$0x6b206574,@x[3]      # 'te k'
++	mov	4*4(%rsp),@x[4]
++	mov	4*5(%rsp),@x[5]
++	mov	4*6(%rsp),@x[6]
++	mov	4*7(%rsp),@x[7]
++	movd	%xmm3,@x[12]
++	mov	4*13(%rsp),@x[13]
++	mov	4*14(%rsp),@x[14]
++	mov	4*15(%rsp),@x[15]
++
++	mov	%rbp,64+0(%rsp)		# save len
++	mov	\$10,%ebp
++	mov	$inp,64+8(%rsp)		# save inp
++	movq	%xmm2,%rsi		# "@x[8]"
++	mov	$out,64+16(%rsp)	# save out
++	mov	%rsi,%rdi
++	shr	\$32,%rdi		# "@x[9]"
++	jmp	.Loop
++
++.align	32
++.Loop:
++___
++	foreach (&ROUND (0, 4, 8,12)) { eval; }
++	foreach (&ROUND	(0, 5,10,15)) { eval; }
++	&dec	("%ebp");
++	&jnz	(".Loop");
++
++$code.=<<___;
++	mov	@t[1],4*9(%rsp)		# modulo-scheduled
++	mov	@t[0],4*8(%rsp)
++	mov	64(%rsp),%rbp		# load len
++	movdqa	%xmm2,%xmm1
++	mov	64+8(%rsp),$inp		# load inp
++	paddd	%xmm4,%xmm3		# increment counter
++	mov	64+16(%rsp),$out	# load out
++
++	add	\$0x61707865,@x[0]      # 'expa'
++	add	\$0x3320646e,@x[1]      # 'nd 3'
++	add	\$0x79622d32,@x[2]      # '2-by'
++	add	\$0x6b206574,@x[3]      # 'te k'
++	add	4*4(%rsp),@x[4]
++	add	4*5(%rsp),@x[5]
++	add	4*6(%rsp),@x[6]
++	add	4*7(%rsp),@x[7]
++	add	4*12(%rsp),@x[12]
++	add	4*13(%rsp),@x[13]
++	add	4*14(%rsp),@x[14]
++	add	4*15(%rsp),@x[15]
++	paddd	4*8(%rsp),%xmm1
++
++	cmp	\$64,%rbp
++	jb	.Ltail
++
++	xor	4*0($inp),@x[0]		# xor with input
++	xor	4*1($inp),@x[1]
++	xor	4*2($inp),@x[2]
++	xor	4*3($inp),@x[3]
++	xor	4*4($inp),@x[4]
++	xor	4*5($inp),@x[5]
++	xor	4*6($inp),@x[6]
++	xor	4*7($inp),@x[7]
++	movdqu	4*8($inp),%xmm0
++	xor	4*12($inp),@x[12]
++	xor	4*13($inp),@x[13]
++	xor	4*14($inp),@x[14]
++	xor	4*15($inp),@x[15]
++	lea	4*16($inp),$inp		# inp+=64
++	pxor	%xmm1,%xmm0
++
++	movdqa	%xmm2,4*8(%rsp)
++	movd	%xmm3,4*12(%rsp)
++
++	mov	@x[0],4*0($out)		# write output
++	mov	@x[1],4*1($out)
++	mov	@x[2],4*2($out)
++	mov	@x[3],4*3($out)
++	mov	@x[4],4*4($out)
++	mov	@x[5],4*5($out)
++	mov	@x[6],4*6($out)
++	mov	@x[7],4*7($out)
++	movdqu	%xmm0,4*8($out)
++	mov	@x[12],4*12($out)
++	mov	@x[13],4*13($out)
++	mov	@x[14],4*14($out)
++	mov	@x[15],4*15($out)
++	lea	4*16($out),$out		# out+=64
++
++	sub	\$64,%rbp
++	jnz	.Loop_outer
++
++	jmp	.Ldone
++
++.align	16
++.Ltail:
++	mov	@x[0],4*0(%rsp)
++	mov	@x[1],4*1(%rsp)
++	xor	%rbx,%rbx
++	mov	@x[2],4*2(%rsp)
++	mov	@x[3],4*3(%rsp)
++	mov	@x[4],4*4(%rsp)
++	mov	@x[5],4*5(%rsp)
++	mov	@x[6],4*6(%rsp)
++	mov	@x[7],4*7(%rsp)
++	movdqa	%xmm1,4*8(%rsp)
++	mov	@x[12],4*12(%rsp)
++	mov	@x[13],4*13(%rsp)
++	mov	@x[14],4*14(%rsp)
++	mov	@x[15],4*15(%rsp)
++
++.Loop_tail:
++	movzb	($inp,%rbx),%eax
++	movzb	(%rsp,%rbx),%edx
++	lea	1(%rbx),%rbx
++	xor	%edx,%eax
++	mov	%al,-1($out,%rbx)
++	dec	%rbp
++	jnz	.Loop_tail
++
++.Ldone:
++	add	\$64+24,%rsp
++	pop	%r15
++	pop	%r14
++	pop	%r13
++	pop	%r12
++	pop	%rbp
++	pop	%rbx
++.Lno_data:
++	ret
++.size	ChaCha20_ctr32,.-ChaCha20_ctr32
++___
++
++########################################################################
++# SSSE3 code path that handles shorter lengths
++{
++my ($a,$b,$c,$d,$t,$t1,$rot16,$rot24)=map("%xmm$_",(0..7));
++
++sub SSSE3ROUND {	# critical path is 20 "SIMD ticks" per round
++	&paddd	($a,$b);
++	&pxor	($d,$a);
++	&pshufb	($d,$rot16);
++
++	&paddd	($c,$d);
++	&pxor	($b,$c);
++	&movdqa	($t,$b);
++	&psrld	($b,20);
++	&pslld	($t,12);
++	&por	($b,$t);
++
++	&paddd	($a,$b);
++	&pxor	($d,$a);
++	&pshufb	($d,$rot24);
++
++	&paddd	($c,$d);
++	&pxor	($b,$c);
++	&movdqa	($t,$b);
++	&psrld	($b,25);
++	&pslld	($t,7);
++	&por	($b,$t);
++}
++
++my $xframe = $win64 ? 32+32+8 : 24;
++
++$code.=<<___;
++.type	ChaCha20_ssse3,\@function,5
++.align	32
++ChaCha20_ssse3:
++.LChaCha20_ssse3:
++___
++$code.=<<___	if ($avx);
++	test	\$`1<<(43-32)`,%r10d
++	jnz	.LChaCha20_4xop		# XOP is fastest even if we use 1/4
++___
++$code.=<<___;
++	cmp	\$128,$len		# we might throw away some data,
++	ja	.LChaCha20_4x		# but overall it won't be slower
++
++.Ldo_sse3_after_all:
++	push	%rbx
++	push	%rbp
++	push	%r12
++	push	%r13
++	push	%r14
++	push	%r15
++
++	sub	\$64+$xframe,%rsp
++___
++$code.=<<___	if ($win64);
++	movaps	%xmm6,64+32(%rsp)
++	movaps	%xmm7,64+48(%rsp)
++___
++$code.=<<___;
++	movdqa	.Lsigma(%rip),$a
++	movdqu	($key),$b
++	movdqu	16($key),$c
++	movdqu	($counter),$d
++	movdqa	.Lrot16(%rip),$rot16
++	movdqa	.Lrot24(%rip),$rot24
++
++	movdqa	$a,0x00(%rsp)
++	movdqa	$b,0x10(%rsp)
++	movdqa	$c,0x20(%rsp)
++	movdqa	$d,0x30(%rsp)
++	mov	\$10,%ebp
++	jmp	.Loop_ssse3
++
++.align	32
++.Loop_outer_ssse3:
++	movdqa	.Lone(%rip),$d
++	movdqa	0x00(%rsp),$a
++	movdqa	0x10(%rsp),$b
++	movdqa	0x20(%rsp),$c
++	paddd	0x30(%rsp),$d
++	mov	\$10,%ebp
++	movdqa	$d,0x30(%rsp)
++	jmp	.Loop_ssse3
++
++.align	32
++.Loop_ssse3:
++___
++	&SSSE3ROUND();
++	&pshufd	($c,$c,0b01001110);
++	&pshufd	($b,$b,0b00111001);
++	&pshufd	($d,$d,0b10010011);
++	&nop	();
++
++	&SSSE3ROUND();
++	&pshufd	($c,$c,0b01001110);
++	&pshufd	($b,$b,0b10010011);
++	&pshufd	($d,$d,0b00111001);
++
++	&dec	("%ebp");
++	&jnz	(".Loop_ssse3");
++
++$code.=<<___;
++	paddd	0x00(%rsp),$a
++	paddd	0x10(%rsp),$b
++	paddd	0x20(%rsp),$c
++	paddd	0x30(%rsp),$d
++
++	cmp	\$64,$len
++	jb	.Ltail_ssse3
++
++	movdqu	0x00($inp),$t
++	movdqu	0x10($inp),$t1
++	pxor	$t,$a			# xor with input
++	movdqu	0x20($inp),$t
++	pxor	$t1,$b
++	movdqu	0x30($inp),$t1
++	lea	0x40($inp),$inp		# inp+=64
++	pxor	$t,$c
++	pxor	$t1,$d
++
++	movdqu	$a,0x00($out)		# write output
++	movdqu	$b,0x10($out)
++	movdqu	$c,0x20($out)
++	movdqu	$d,0x30($out)
++	lea	0x40($out),$out		# out+=64
++
++	sub	\$64,$len
++	jnz	.Loop_outer_ssse3
++
++	jmp	.Ldone_ssse3
++
++.align	16
++.Ltail_ssse3:
++	movdqa	$a,0x00(%rsp)
++	movdqa	$b,0x10(%rsp)
++	movdqa	$c,0x20(%rsp)
++	movdqa	$d,0x30(%rsp)
++	xor	%rbx,%rbx
++
++.Loop_tail_ssse3:
++	movzb	($inp,%rbx),%eax
++	movzb	(%rsp,%rbx),%ecx
++	lea	1(%rbx),%rbx
++	xor	%ecx,%eax
++	mov	%al,-1($out,%rbx)
++	dec	$len
++	jnz	.Loop_tail_ssse3
++
++.Ldone_ssse3:
++___
++$code.=<<___	if ($win64);
++	movaps	64+32(%rsp),%xmm6
++	movaps	64+48(%rsp),%xmm7
++___
++$code.=<<___;
++	add	\$64+$xframe,%rsp
++	pop	%r15
++	pop	%r14
++	pop	%r13
++	pop	%r12
++	pop	%rbp
++	pop	%rbx
++	ret
++.size	ChaCha20_ssse3,.-ChaCha20_ssse3
++___
++}
++
++########################################################################
++# SSSE3 code path that handles longer messages.
++{
++# assign variables to favor Atom front-end
++my ($xd0,$xd1,$xd2,$xd3, $xt0,$xt1,$xt2,$xt3,
++    $xa0,$xa1,$xa2,$xa3, $xb0,$xb1,$xb2,$xb3)=map("%xmm$_",(0..15));
++my  @xx=($xa0,$xa1,$xa2,$xa3, $xb0,$xb1,$xb2,$xb3,
++	"%nox","%nox","%nox","%nox", $xd0,$xd1,$xd2,$xd3);
++
++sub SSSE3_lane_ROUND {
++my ($a0,$b0,$c0,$d0)=@_;
++my ($a1,$b1,$c1,$d1)=map(($_&~3)+(($_+1)&3),($a0,$b0,$c0,$d0));
++my ($a2,$b2,$c2,$d2)=map(($_&~3)+(($_+1)&3),($a1,$b1,$c1,$d1));
++my ($a3,$b3,$c3,$d3)=map(($_&~3)+(($_+1)&3),($a2,$b2,$c2,$d2));
++my ($xc,$xc_,$t0,$t1)=map("\"$_\"",$xt0,$xt1,$xt2,$xt3);
++my @x=map("\"$_\"",@xx);
++
++	# Consider order in which variables are addressed by their
++	# index:
++	#
++	#	a   b   c   d
++	#
++	#	0   4   8  12 < even round
++	#	1   5   9  13
++	#	2   6  10  14
++	#	3   7  11  15
++	#	0   5  10  15 < odd round
++	#	1   6  11  12
++	#	2   7   8  13
++	#	3   4   9  14
++	#
++	# 'a', 'b' and 'd's are permanently allocated in registers,
++	# @x[0..7,12..15], while 'c's are maintained in memory. If
++	# you observe 'c' column, you'll notice that pair of 'c's is
++	# invariant between rounds. This means that we have to reload
++	# them once per round, in the middle. This is why you'll see
++	# bunch of 'c' stores and loads in the middle, but none in
++	# the beginning or end.
++
++	(
++	"&paddd		(@x[$a0],@x[$b0])",	# Q1
++	 "&paddd	(@x[$a1],@x[$b1])",	# Q2
++	"&pxor		(@x[$d0],@x[$a0])",
++	 "&pxor		(@x[$d1],@x[$a1])",
++	"&pshufb	(@x[$d0],$t1)",
++	 "&pshufb	(@x[$d1],$t1)",
++
++	"&paddd		($xc,@x[$d0])",
++	 "&paddd	($xc_,@x[$d1])",
++	"&pxor		(@x[$b0],$xc)",
++	 "&pxor		(@x[$b1],$xc_)",
++	"&movdqa	($t0,@x[$b0])",
++	"&pslld		(@x[$b0],12)",
++	"&psrld		($t0,20)",
++	 "&movdqa	($t1,@x[$b1])",
++	 "&pslld	(@x[$b1],12)",
++	"&por		(@x[$b0],$t0)",
++	 "&psrld	($t1,20)",
++	"&movdqa	($t0,'(%r11)')",	# .Lrot24(%rip)
++	 "&por		(@x[$b1],$t1)",
++
++	"&paddd		(@x[$a0],@x[$b0])",
++	 "&paddd	(@x[$a1],@x[$b1])",
++	"&pxor		(@x[$d0],@x[$a0])",
++	 "&pxor		(@x[$d1],@x[$a1])",
++	"&pshufb	(@x[$d0],$t0)",
++	 "&pshufb	(@x[$d1],$t0)",
++
++	"&paddd		($xc,@x[$d0])",
++	 "&paddd	($xc_,@x[$d1])",
++	"&pxor		(@x[$b0],$xc)",
++	 "&pxor		(@x[$b1],$xc_)",
++	"&movdqa	($t1,@x[$b0])",
++	"&pslld		(@x[$b0],7)",
++	"&psrld		($t1,25)",
++	 "&movdqa	($t0,@x[$b1])",
++	 "&pslld	(@x[$b1],7)",
++	"&por		(@x[$b0],$t1)",
++	 "&psrld	($t0,25)",
++	"&movdqa	($t1,'(%r10)')",	# .Lrot16(%rip)
++	 "&por		(@x[$b1],$t0)",
++
++	"&movdqa	(\"`16*($c0-8)`(%rsp)\",$xc)",	# reload pair of 'c's
++	 "&movdqa	(\"`16*($c1-8)`(%rsp)\",$xc_)",
++	"&movdqa	($xc,\"`16*($c2-8)`(%rsp)\")",
++	 "&movdqa	($xc_,\"`16*($c3-8)`(%rsp)\")",
++
++	"&paddd		(@x[$a2],@x[$b2])",	# Q3
++	 "&paddd	(@x[$a3],@x[$b3])",	# Q4
++	"&pxor		(@x[$d2],@x[$a2])",
++	 "&pxor		(@x[$d3],@x[$a3])",
++	"&pshufb	(@x[$d2],$t1)",
++	 "&pshufb	(@x[$d3],$t1)",
++
++	"&paddd		($xc,@x[$d2])",
++	 "&paddd	($xc_,@x[$d3])",
++	"&pxor		(@x[$b2],$xc)",
++	 "&pxor		(@x[$b3],$xc_)",
++	"&movdqa	($t0,@x[$b2])",
++	"&pslld		(@x[$b2],12)",
++	"&psrld		($t0,20)",
++	 "&movdqa	($t1,@x[$b3])",
++	 "&pslld	(@x[$b3],12)",
++	"&por		(@x[$b2],$t0)",
++	 "&psrld	($t1,20)",
++	"&movdqa	($t0,'(%r11)')",	# .Lrot24(%rip)
++	 "&por		(@x[$b3],$t1)",
++
++	"&paddd		(@x[$a2],@x[$b2])",
++	 "&paddd	(@x[$a3],@x[$b3])",
++	"&pxor		(@x[$d2],@x[$a2])",
++	 "&pxor		(@x[$d3],@x[$a3])",
++	"&pshufb	(@x[$d2],$t0)",
++	 "&pshufb	(@x[$d3],$t0)",
++
++	"&paddd		($xc,@x[$d2])",
++	 "&paddd	($xc_,@x[$d3])",
++	"&pxor		(@x[$b2],$xc)",
++	 "&pxor		(@x[$b3],$xc_)",
++	"&movdqa	($t1,@x[$b2])",
++	"&pslld		(@x[$b2],7)",
++	"&psrld		($t1,25)",
++	 "&movdqa	($t0,@x[$b3])",
++	 "&pslld	(@x[$b3],7)",
++	"&por		(@x[$b2],$t1)",
++	 "&psrld	($t0,25)",
++	"&movdqa	($t1,'(%r10)')",	# .Lrot16(%rip)
++	 "&por		(@x[$b3],$t0)"
++	);
++}
++
++my $xframe = $win64 ? 0xa0 : 0;
++
++$code.=<<___;
++.type	ChaCha20_4x,\@function,5
++.align	32
++ChaCha20_4x:
++.LChaCha20_4x:
++	mov		%r10,%r11
++___
++$code.=<<___	if ($avx>1);
++	shr		\$32,%r10		# OPENSSL_ia32cap_P+8
++	test		\$`1<<5`,%r10		# test AVX2
++	jnz		.LChaCha20_8x
++___
++$code.=<<___;
++	cmp		\$192,$len
++	ja		.Lproceed4x
++
++	and		\$`1<<26|1<<22`,%r11	# isolate XSAVE+MOVBE
++	cmp		\$`1<<22`,%r11		# check for MOVBE without XSAVE
++	je		.Ldo_sse3_after_all	# to detect Atom
++
++.Lproceed4x:
++	lea		-0x78(%rsp),%r11
++	sub		\$0x148+$xframe,%rsp
++___
++	################ stack layout
++	# +0x00		SIMD equivalent of @x[8-12]
++	# ...
++	# +0x40		constant copy of key[0-2] smashed by lanes
++	# ...
++	# +0x100	SIMD counters (with nonce smashed by lanes)
++	# ...
++	# +0x140
++$code.=<<___	if ($win64);
++	movaps		%xmm6,-0x30(%r11)
++	movaps		%xmm7,-0x20(%r11)
++	movaps		%xmm8,-0x10(%r11)
++	movaps		%xmm9,0x00(%r11)
++	movaps		%xmm10,0x10(%r11)
++	movaps		%xmm11,0x20(%r11)
++	movaps		%xmm12,0x30(%r11)
++	movaps		%xmm13,0x40(%r11)
++	movaps		%xmm14,0x50(%r11)
++	movaps		%xmm15,0x60(%r11)
++___
++$code.=<<___;
++	movdqa		.Lsigma(%rip),$xa3	# key[0]
++	movdqu		($key),$xb3		# key[1]
++	movdqu		16($key),$xt3		# key[2]
++	movdqu		($counter),$xd3		# key[3]
++	lea		0x100(%rsp),%rcx	# size optimization
++	lea		.Lrot16(%rip),%r10
++	lea		.Lrot24(%rip),%r11
++
++	pshufd		\$0x00,$xa3,$xa0	# smash key by lanes...
++	pshufd		\$0x55,$xa3,$xa1
++	movdqa		$xa0,0x40(%rsp)		# ... and offload
++	pshufd		\$0xaa,$xa3,$xa2
++	movdqa		$xa1,0x50(%rsp)
++	pshufd		\$0xff,$xa3,$xa3
++	movdqa		$xa2,0x60(%rsp)
++	movdqa		$xa3,0x70(%rsp)
++
++	pshufd		\$0x00,$xb3,$xb0
++	pshufd		\$0x55,$xb3,$xb1
++	movdqa		$xb0,0x80-0x100(%rcx)
++	pshufd		\$0xaa,$xb3,$xb2
++	movdqa		$xb1,0x90-0x100(%rcx)
++	pshufd		\$0xff,$xb3,$xb3
++	movdqa		$xb2,0xa0-0x100(%rcx)
++	movdqa		$xb3,0xb0-0x100(%rcx)
++
++	pshufd		\$0x00,$xt3,$xt0	# "$xc0"
++	pshufd		\$0x55,$xt3,$xt1	# "$xc1"
++	movdqa		$xt0,0xc0-0x100(%rcx)
++	pshufd		\$0xaa,$xt3,$xt2	# "$xc2"
++	movdqa		$xt1,0xd0-0x100(%rcx)
++	pshufd		\$0xff,$xt3,$xt3	# "$xc3"
++	movdqa		$xt2,0xe0-0x100(%rcx)
++	movdqa		$xt3,0xf0-0x100(%rcx)
++
++	pshufd		\$0x00,$xd3,$xd0
++	pshufd		\$0x55,$xd3,$xd1
++	paddd		.Linc(%rip),$xd0	# don't save counters yet
++	pshufd		\$0xaa,$xd3,$xd2
++	movdqa		$xd1,0x110-0x100(%rcx)
++	pshufd		\$0xff,$xd3,$xd3
++	movdqa		$xd2,0x120-0x100(%rcx)
++	movdqa		$xd3,0x130-0x100(%rcx)
++
++	jmp		.Loop_enter4x
++
++.align	32
++.Loop_outer4x:
++	movdqa		0x40(%rsp),$xa0		# re-load smashed key
++	movdqa		0x50(%rsp),$xa1
++	movdqa		0x60(%rsp),$xa2
++	movdqa		0x70(%rsp),$xa3
++	movdqa		0x80-0x100(%rcx),$xb0
++	movdqa		0x90-0x100(%rcx),$xb1
++	movdqa		0xa0-0x100(%rcx),$xb2
++	movdqa		0xb0-0x100(%rcx),$xb3
++	movdqa		0xc0-0x100(%rcx),$xt0	# "$xc0"
++	movdqa		0xd0-0x100(%rcx),$xt1	# "$xc1"
++	movdqa		0xe0-0x100(%rcx),$xt2	# "$xc2"
++	movdqa		0xf0-0x100(%rcx),$xt3	# "$xc3"
++	movdqa		0x100-0x100(%rcx),$xd0
++	movdqa		0x110-0x100(%rcx),$xd1
++	movdqa		0x120-0x100(%rcx),$xd2
++	movdqa		0x130-0x100(%rcx),$xd3
++	paddd		.Lfour(%rip),$xd0	# next SIMD counters
++
++.Loop_enter4x:
++	movdqa		$xt2,0x20(%rsp)		# SIMD equivalent of "@x[10]"
++	movdqa		$xt3,0x30(%rsp)		# SIMD equivalent of "@x[11]"
++	movdqa		(%r10),$xt3		# .Lrot16(%rip)
++	mov		\$10,%eax
++	movdqa		$xd0,0x100-0x100(%rcx)	# save SIMD counters
++	jmp		.Loop4x
++
++.align	32
++.Loop4x:
++___
++	foreach (&SSSE3_lane_ROUND(0, 4, 8,12)) { eval; }
++	foreach (&SSSE3_lane_ROUND(0, 5,10,15)) { eval; }
++$code.=<<___;
++	dec		%eax
++	jnz		.Loop4x
++
++	paddd		0x40(%rsp),$xa0		# accumulate key material
++	paddd		0x50(%rsp),$xa1
++	paddd		0x60(%rsp),$xa2
++	paddd		0x70(%rsp),$xa3
++
++	movdqa		$xa0,$xt2		# "de-interlace" data
++	punpckldq	$xa1,$xa0
++	movdqa		$xa2,$xt3
++	punpckldq	$xa3,$xa2
++	punpckhdq	$xa1,$xt2
++	punpckhdq	$xa3,$xt3
++	movdqa		$xa0,$xa1
++	punpcklqdq	$xa2,$xa0		# "a0"
++	movdqa		$xt2,$xa3
++	punpcklqdq	$xt3,$xt2		# "a2"
++	punpckhqdq	$xa2,$xa1		# "a1"
++	punpckhqdq	$xt3,$xa3		# "a3"
++___
++	($xa2,$xt2)=($xt2,$xa2);
++$code.=<<___;
++	paddd		0x80-0x100(%rcx),$xb0
++	paddd		0x90-0x100(%rcx),$xb1
++	paddd		0xa0-0x100(%rcx),$xb2
++	paddd		0xb0-0x100(%rcx),$xb3
++
++	movdqa		$xa0,0x00(%rsp)		# offload $xaN
++	movdqa		$xa1,0x10(%rsp)
++	movdqa		0x20(%rsp),$xa0		# "xc2"
++	movdqa		0x30(%rsp),$xa1		# "xc3"
++
++	movdqa		$xb0,$xt2
++	punpckldq	$xb1,$xb0
++	movdqa		$xb2,$xt3
++	punpckldq	$xb3,$xb2
++	punpckhdq	$xb1,$xt2
++	punpckhdq	$xb3,$xt3
++	movdqa		$xb0,$xb1
++	punpcklqdq	$xb2,$xb0		# "b0"
++	movdqa		$xt2,$xb3
++	punpcklqdq	$xt3,$xt2		# "b2"
++	punpckhqdq	$xb2,$xb1		# "b1"
++	punpckhqdq	$xt3,$xb3		# "b3"
++___
++	($xb2,$xt2)=($xt2,$xb2);
++	my ($xc0,$xc1,$xc2,$xc3)=($xt0,$xt1,$xa0,$xa1);
++$code.=<<___;
++	paddd		0xc0-0x100(%rcx),$xc0
++	paddd		0xd0-0x100(%rcx),$xc1
++	paddd		0xe0-0x100(%rcx),$xc2
++	paddd		0xf0-0x100(%rcx),$xc3
++
++	movdqa		$xa2,0x20(%rsp)		# keep offloading $xaN
++	movdqa		$xa3,0x30(%rsp)
++
++	movdqa		$xc0,$xt2
++	punpckldq	$xc1,$xc0
++	movdqa		$xc2,$xt3
++	punpckldq	$xc3,$xc2
++	punpckhdq	$xc1,$xt2
++	punpckhdq	$xc3,$xt3
++	movdqa		$xc0,$xc1
++	punpcklqdq	$xc2,$xc0		# "c0"
++	movdqa		$xt2,$xc3
++	punpcklqdq	$xt3,$xt2		# "c2"
++	punpckhqdq	$xc2,$xc1		# "c1"
++	punpckhqdq	$xt3,$xc3		# "c3"
++___
++	($xc2,$xt2)=($xt2,$xc2);
++	($xt0,$xt1)=($xa2,$xa3);		# use $xaN as temporary
++$code.=<<___;
++	paddd		0x100-0x100(%rcx),$xd0
++	paddd		0x110-0x100(%rcx),$xd1
++	paddd		0x120-0x100(%rcx),$xd2
++	paddd		0x130-0x100(%rcx),$xd3
++
++	movdqa		$xd0,$xt2
++	punpckldq	$xd1,$xd0
++	movdqa		$xd2,$xt3
++	punpckldq	$xd3,$xd2
++	punpckhdq	$xd1,$xt2
++	punpckhdq	$xd3,$xt3
++	movdqa		$xd0,$xd1
++	punpcklqdq	$xd2,$xd0		# "d0"
++	movdqa		$xt2,$xd3
++	punpcklqdq	$xt3,$xt2		# "d2"
++	punpckhqdq	$xd2,$xd1		# "d1"
++	punpckhqdq	$xt3,$xd3		# "d3"
++___
++	($xd2,$xt2)=($xt2,$xd2);
++$code.=<<___;
++	cmp		\$64*4,$len
++	jb		.Ltail4x
++
++	movdqu		0x00($inp),$xt0		# xor with input
++	movdqu		0x10($inp),$xt1
++	movdqu		0x20($inp),$xt2
++	movdqu		0x30($inp),$xt3
++	pxor		0x00(%rsp),$xt0		# $xaN is offloaded, remember?
++	pxor		$xb0,$xt1
++	pxor		$xc0,$xt2
++	pxor		$xd0,$xt3
++
++	 movdqu		$xt0,0x00($out)
++	movdqu		0x40($inp),$xt0
++	 movdqu		$xt1,0x10($out)
++	movdqu		0x50($inp),$xt1
++	 movdqu		$xt2,0x20($out)
++	movdqu		0x60($inp),$xt2
++	 movdqu		$xt3,0x30($out)
++	movdqu		0x70($inp),$xt3
++	lea		0x80($inp),$inp		# size optimization
++	pxor		0x10(%rsp),$xt0
++	pxor		$xb1,$xt1
++	pxor		$xc1,$xt2
++	pxor		$xd1,$xt3
++
++	 movdqu		$xt0,0x40($out)
++	movdqu		0x00($inp),$xt0
++	 movdqu		$xt1,0x50($out)
++	movdqu		0x10($inp),$xt1
++	 movdqu		$xt2,0x60($out)
++	movdqu		0x20($inp),$xt2
++	 movdqu		$xt3,0x70($out)
++	 lea		0x80($out),$out		# size optimization
++	movdqu		0x30($inp),$xt3
++	pxor		0x20(%rsp),$xt0
++	pxor		$xb2,$xt1
++	pxor		$xc2,$xt2
++	pxor		$xd2,$xt3
++
++	 movdqu		$xt0,0x00($out)
++	movdqu		0x40($inp),$xt0
++	 movdqu		$xt1,0x10($out)
++	movdqu		0x50($inp),$xt1
++	 movdqu		$xt2,0x20($out)
++	movdqu		0x60($inp),$xt2
++	 movdqu		$xt3,0x30($out)
++	movdqu		0x70($inp),$xt3
++	lea		0x80($inp),$inp		# inp+=64*4
++	pxor		0x30(%rsp),$xt0
++	pxor		$xb3,$xt1
++	pxor		$xc3,$xt2
++	pxor		$xd3,$xt3
++	movdqu		$xt0,0x40($out)
++	movdqu		$xt1,0x50($out)
++	movdqu		$xt2,0x60($out)
++	movdqu		$xt3,0x70($out)
++	lea		0x80($out),$out		# out+=64*4
++
++	sub		\$64*4,$len
++	jnz		.Loop_outer4x
++
++	jmp		.Ldone4x
++
++.Ltail4x:
++	cmp		\$192,$len
++	jae		.L192_or_more4x
++	cmp		\$128,$len
++	jae		.L128_or_more4x
++	cmp		\$64,$len
++	jae		.L64_or_more4x
++
++	#movdqa		0x00(%rsp),$xt0		# $xaN is offloaded, remember?
++	xor		%r10,%r10
++	#movdqa		$xt0,0x00(%rsp)
++	movdqa		$xb0,0x10(%rsp)
++	movdqa		$xc0,0x20(%rsp)
++	movdqa		$xd0,0x30(%rsp)
++	jmp		.Loop_tail4x
++
++.align	32
++.L64_or_more4x:
++	movdqu		0x00($inp),$xt0		# xor with input
++	movdqu		0x10($inp),$xt1
++	movdqu		0x20($inp),$xt2
++	movdqu		0x30($inp),$xt3
++	pxor		0x00(%rsp),$xt0		# $xaxN is offloaded, remember?
++	pxor		$xb0,$xt1
++	pxor		$xc0,$xt2
++	pxor		$xd0,$xt3
++	movdqu		$xt0,0x00($out)
++	movdqu		$xt1,0x10($out)
++	movdqu		$xt2,0x20($out)
++	movdqu		$xt3,0x30($out)
++	je		.Ldone4x
++
++	movdqa		0x10(%rsp),$xt0		# $xaN is offloaded, remember?
++	lea		0x40($inp),$inp		# inp+=64*1
++	xor		%r10,%r10
++	movdqa		$xt0,0x00(%rsp)
++	movdqa		$xb1,0x10(%rsp)
++	lea		0x40($out),$out		# out+=64*1
++	movdqa		$xc1,0x20(%rsp)
++	sub		\$64,$len		# len-=64*1
++	movdqa		$xd1,0x30(%rsp)
++	jmp		.Loop_tail4x
++
++.align	32
++.L128_or_more4x:
++	movdqu		0x00($inp),$xt0		# xor with input
++	movdqu		0x10($inp),$xt1
++	movdqu		0x20($inp),$xt2
++	movdqu		0x30($inp),$xt3
++	pxor		0x00(%rsp),$xt0		# $xaN is offloaded, remember?
++	pxor		$xb0,$xt1
++	pxor		$xc0,$xt2
++	pxor		$xd0,$xt3
++
++	 movdqu		$xt0,0x00($out)
++	movdqu		0x40($inp),$xt0
++	 movdqu		$xt1,0x10($out)
++	movdqu		0x50($inp),$xt1
++	 movdqu		$xt2,0x20($out)
++	movdqu		0x60($inp),$xt2
++	 movdqu		$xt3,0x30($out)
++	movdqu		0x70($inp),$xt3
++	pxor		0x10(%rsp),$xt0
++	pxor		$xb1,$xt1
++	pxor		$xc1,$xt2
++	pxor		$xd1,$xt3
++	movdqu		$xt0,0x40($out)
++	movdqu		$xt1,0x50($out)
++	movdqu		$xt2,0x60($out)
++	movdqu		$xt3,0x70($out)
++	je		.Ldone4x
++
++	movdqa		0x20(%rsp),$xt0		# $xaN is offloaded, remember?
++	lea		0x80($inp),$inp		# inp+=64*2
++	xor		%r10,%r10
++	movdqa		$xt0,0x00(%rsp)
++	movdqa		$xb2,0x10(%rsp)
++	lea		0x80($out),$out		# out+=64*2
++	movdqa		$xc2,0x20(%rsp)
++	sub		\$128,$len		# len-=64*2
++	movdqa		$xd2,0x30(%rsp)
++	jmp		.Loop_tail4x
++
++.align	32
++.L192_or_more4x:
++	movdqu		0x00($inp),$xt0		# xor with input
++	movdqu		0x10($inp),$xt1
++	movdqu		0x20($inp),$xt2
++	movdqu		0x30($inp),$xt3
++	pxor		0x00(%rsp),$xt0		# $xaN is offloaded, remember?
++	pxor		$xb0,$xt1
++	pxor		$xc0,$xt2
++	pxor		$xd0,$xt3
++
++	 movdqu		$xt0,0x00($out)
++	movdqu		0x40($inp),$xt0
++	 movdqu		$xt1,0x10($out)
++	movdqu		0x50($inp),$xt1
++	 movdqu		$xt2,0x20($out)
++	movdqu		0x60($inp),$xt2
++	 movdqu		$xt3,0x30($out)
++	movdqu		0x70($inp),$xt3
++	lea		0x80($inp),$inp		# size optimization
++	pxor		0x10(%rsp),$xt0
++	pxor		$xb1,$xt1
++	pxor		$xc1,$xt2
++	pxor		$xd1,$xt3
++
++	 movdqu		$xt0,0x40($out)
++	movdqu		0x00($inp),$xt0
++	 movdqu		$xt1,0x50($out)
++	movdqu		0x10($inp),$xt1
++	 movdqu		$xt2,0x60($out)
++	movdqu		0x20($inp),$xt2
++	 movdqu		$xt3,0x70($out)
++	 lea		0x80($out),$out		# size optimization
++	movdqu		0x30($inp),$xt3
++	pxor		0x20(%rsp),$xt0
++	pxor		$xb2,$xt1
++	pxor		$xc2,$xt2
++	pxor		$xd2,$xt3
++	movdqu		$xt0,0x00($out)
++	movdqu		$xt1,0x10($out)
++	movdqu		$xt2,0x20($out)
++	movdqu		$xt3,0x30($out)
++	je		.Ldone4x
++
++	movdqa		0x30(%rsp),$xt0		# $xaN is offloaded, remember?
++	lea		0x40($inp),$inp		# inp+=64*3
++	xor		%r10,%r10
++	movdqa		$xt0,0x00(%rsp)
++	movdqa		$xb3,0x10(%rsp)
++	lea		0x40($out),$out		# out+=64*3
++	movdqa		$xc3,0x20(%rsp)
++	sub		\$192,$len		# len-=64*3
++	movdqa		$xd3,0x30(%rsp)
++
++.Loop_tail4x:
++	movzb		($inp,%r10),%eax
++	movzb		(%rsp,%r10),%ecx
++	lea		1(%r10),%r10
++	xor		%ecx,%eax
++	mov		%al,-1($out,%r10)
++	dec		$len
++	jnz		.Loop_tail4x
++
++.Ldone4x:
++___
++$code.=<<___	if ($win64);
++	lea		0x140+0x30(%rsp),%r11
++	movaps		-0x30(%r11),%xmm6
++	movaps		-0x20(%r11),%xmm7
++	movaps		-0x10(%r11),%xmm8
++	movaps		0x00(%r11),%xmm9
++	movaps		0x10(%r11),%xmm10
++	movaps		0x20(%r11),%xmm11
++	movaps		0x30(%r11),%xmm12
++	movaps		0x40(%r11),%xmm13
++	movaps		0x50(%r11),%xmm14
++	movaps		0x60(%r11),%xmm15
++___
++$code.=<<___;
++	add		\$0x148+$xframe,%rsp
++	ret
++.size	ChaCha20_4x,.-ChaCha20_4x
++___
++}
++
++########################################################################
++# XOP code path that handles all lengths.
++if ($avx) {
++# There is some "anomaly" observed depending on instructions' size or
++# alignment. If you look closely at below code you'll notice that
++# sometimes argument order varies. The order affects instruction
++# encoding by making it larger, and such fiddling gives 5% performance
++# improvement. This is on FX-4100...
++
++my ($xb0,$xb1,$xb2,$xb3, $xd0,$xd1,$xd2,$xd3,
++    $xa0,$xa1,$xa2,$xa3, $xt0,$xt1,$xt2,$xt3)=map("%xmm$_",(0..15));
++my  @xx=($xa0,$xa1,$xa2,$xa3, $xb0,$xb1,$xb2,$xb3,
++	 $xt0,$xt1,$xt2,$xt3, $xd0,$xd1,$xd2,$xd3);
++
++sub XOP_lane_ROUND {
++my ($a0,$b0,$c0,$d0)=@_;
++my ($a1,$b1,$c1,$d1)=map(($_&~3)+(($_+1)&3),($a0,$b0,$c0,$d0));
++my ($a2,$b2,$c2,$d2)=map(($_&~3)+(($_+1)&3),($a1,$b1,$c1,$d1));
++my ($a3,$b3,$c3,$d3)=map(($_&~3)+(($_+1)&3),($a2,$b2,$c2,$d2));
++my @x=map("\"$_\"",@xx);
++
++	(
++	"&vpaddd	(@x[$a0],@x[$a0],@x[$b0])",	# Q1
++	 "&vpaddd	(@x[$a1],@x[$a1],@x[$b1])",	# Q2
++	  "&vpaddd	(@x[$a2],@x[$a2],@x[$b2])",	# Q3
++	   "&vpaddd	(@x[$a3],@x[$a3],@x[$b3])",	# Q4
++	"&vpxor		(@x[$d0],@x[$a0],@x[$d0])",
++	 "&vpxor	(@x[$d1],@x[$a1],@x[$d1])",
++	  "&vpxor	(@x[$d2],@x[$a2],@x[$d2])",
++	   "&vpxor	(@x[$d3],@x[$a3],@x[$d3])",
++	"&vprotd	(@x[$d0],@x[$d0],16)",
++	 "&vprotd	(@x[$d1],@x[$d1],16)",
++	  "&vprotd	(@x[$d2],@x[$d2],16)",
++	   "&vprotd	(@x[$d3],@x[$d3],16)",
++
++	"&vpaddd	(@x[$c0],@x[$c0],@x[$d0])",
++	 "&vpaddd	(@x[$c1],@x[$c1],@x[$d1])",
++	  "&vpaddd	(@x[$c2],@x[$c2],@x[$d2])",
++	   "&vpaddd	(@x[$c3],@x[$c3],@x[$d3])",
++	"&vpxor		(@x[$b0],@x[$c0],@x[$b0])",
++	 "&vpxor	(@x[$b1],@x[$c1],@x[$b1])",
++	  "&vpxor	(@x[$b2],@x[$b2],@x[$c2])",	# flip
++	   "&vpxor	(@x[$b3],@x[$b3],@x[$c3])",	# flip
++	"&vprotd	(@x[$b0],@x[$b0],12)",
++	 "&vprotd	(@x[$b1],@x[$b1],12)",
++	  "&vprotd	(@x[$b2],@x[$b2],12)",
++	   "&vprotd	(@x[$b3],@x[$b3],12)",
++
++	"&vpaddd	(@x[$a0],@x[$b0],@x[$a0])",	# flip
++	 "&vpaddd	(@x[$a1],@x[$b1],@x[$a1])",	# flip
++	  "&vpaddd	(@x[$a2],@x[$a2],@x[$b2])",
++	   "&vpaddd	(@x[$a3],@x[$a3],@x[$b3])",
++	"&vpxor		(@x[$d0],@x[$a0],@x[$d0])",
++	 "&vpxor	(@x[$d1],@x[$a1],@x[$d1])",
++	  "&vpxor	(@x[$d2],@x[$a2],@x[$d2])",
++	   "&vpxor	(@x[$d3],@x[$a3],@x[$d3])",
++	"&vprotd	(@x[$d0],@x[$d0],8)",
++	 "&vprotd	(@x[$d1],@x[$d1],8)",
++	  "&vprotd	(@x[$d2],@x[$d2],8)",
++	   "&vprotd	(@x[$d3],@x[$d3],8)",
++
++	"&vpaddd	(@x[$c0],@x[$c0],@x[$d0])",
++	 "&vpaddd	(@x[$c1],@x[$c1],@x[$d1])",
++	  "&vpaddd	(@x[$c2],@x[$c2],@x[$d2])",
++	   "&vpaddd	(@x[$c3],@x[$c3],@x[$d3])",
++	"&vpxor		(@x[$b0],@x[$c0],@x[$b0])",
++	 "&vpxor	(@x[$b1],@x[$c1],@x[$b1])",
++	  "&vpxor	(@x[$b2],@x[$b2],@x[$c2])",	# flip
++	   "&vpxor	(@x[$b3],@x[$b3],@x[$c3])",	# flip
++	"&vprotd	(@x[$b0],@x[$b0],7)",
++	 "&vprotd	(@x[$b1],@x[$b1],7)",
++	  "&vprotd	(@x[$b2],@x[$b2],7)",
++	   "&vprotd	(@x[$b3],@x[$b3],7)"
++	);
++}
++
++my $xframe = $win64 ? 0xa0 : 0;
++
++$code.=<<___;
++.type	ChaCha20_4xop,\@function,5
++.align	32
++ChaCha20_4xop:
++.LChaCha20_4xop:
++	lea		-0x78(%rsp),%r11
++	sub		\$0x148+$xframe,%rsp
++___
++	################ stack layout
++	# +0x00		SIMD equivalent of @x[8-12]
++	# ...
++	# +0x40		constant copy of key[0-2] smashed by lanes
++	# ...
++	# +0x100	SIMD counters (with nonce smashed by lanes)
++	# ...
++	# +0x140
++$code.=<<___	if ($win64);
++	movaps		%xmm6,-0x30(%r11)
++	movaps		%xmm7,-0x20(%r11)
++	movaps		%xmm8,-0x10(%r11)
++	movaps		%xmm9,0x00(%r11)
++	movaps		%xmm10,0x10(%r11)
++	movaps		%xmm11,0x20(%r11)
++	movaps		%xmm12,0x30(%r11)
++	movaps		%xmm13,0x40(%r11)
++	movaps		%xmm14,0x50(%r11)
++	movaps		%xmm15,0x60(%r11)
++___
++$code.=<<___;
++	vzeroupper
++
++	vmovdqa		.Lsigma(%rip),$xa3	# key[0]
++	vmovdqu		($key),$xb3		# key[1]
++	vmovdqu		16($key),$xt3		# key[2]
++	vmovdqu		($counter),$xd3		# key[3]
++	lea		0x100(%rsp),%rcx	# size optimization
++
++	vpshufd		\$0x00,$xa3,$xa0	# smash key by lanes...
++	vpshufd		\$0x55,$xa3,$xa1
++	vmovdqa		$xa0,0x40(%rsp)		# ... and offload
++	vpshufd		\$0xaa,$xa3,$xa2
++	vmovdqa		$xa1,0x50(%rsp)
++	vpshufd		\$0xff,$xa3,$xa3
++	vmovdqa		$xa2,0x60(%rsp)
++	vmovdqa		$xa3,0x70(%rsp)
++
++	vpshufd		\$0x00,$xb3,$xb0
++	vpshufd		\$0x55,$xb3,$xb1
++	vmovdqa		$xb0,0x80-0x100(%rcx)
++	vpshufd		\$0xaa,$xb3,$xb2
++	vmovdqa		$xb1,0x90-0x100(%rcx)
++	vpshufd		\$0xff,$xb3,$xb3
++	vmovdqa		$xb2,0xa0-0x100(%rcx)
++	vmovdqa		$xb3,0xb0-0x100(%rcx)
++
++	vpshufd		\$0x00,$xt3,$xt0	# "$xc0"
++	vpshufd		\$0x55,$xt3,$xt1	# "$xc1"
++	vmovdqa		$xt0,0xc0-0x100(%rcx)
++	vpshufd		\$0xaa,$xt3,$xt2	# "$xc2"
++	vmovdqa		$xt1,0xd0-0x100(%rcx)
++	vpshufd		\$0xff,$xt3,$xt3	# "$xc3"
++	vmovdqa		$xt2,0xe0-0x100(%rcx)
++	vmovdqa		$xt3,0xf0-0x100(%rcx)
++
++	vpshufd		\$0x00,$xd3,$xd0
++	vpshufd		\$0x55,$xd3,$xd1
++	vpaddd		.Linc(%rip),$xd0,$xd0	# don't save counters yet
++	vpshufd		\$0xaa,$xd3,$xd2
++	vmovdqa		$xd1,0x110-0x100(%rcx)
++	vpshufd		\$0xff,$xd3,$xd3
++	vmovdqa		$xd2,0x120-0x100(%rcx)
++	vmovdqa		$xd3,0x130-0x100(%rcx)
++
++	jmp		.Loop_enter4xop
++
++.align	32
++.Loop_outer4xop:
++	vmovdqa		0x40(%rsp),$xa0		# re-load smashed key
++	vmovdqa		0x50(%rsp),$xa1
++	vmovdqa		0x60(%rsp),$xa2
++	vmovdqa		0x70(%rsp),$xa3
++	vmovdqa		0x80-0x100(%rcx),$xb0
++	vmovdqa		0x90-0x100(%rcx),$xb1
++	vmovdqa		0xa0-0x100(%rcx),$xb2
++	vmovdqa		0xb0-0x100(%rcx),$xb3
++	vmovdqa		0xc0-0x100(%rcx),$xt0	# "$xc0"
++	vmovdqa		0xd0-0x100(%rcx),$xt1	# "$xc1"
++	vmovdqa		0xe0-0x100(%rcx),$xt2	# "$xc2"
++	vmovdqa		0xf0-0x100(%rcx),$xt3	# "$xc3"
++	vmovdqa		0x100-0x100(%rcx),$xd0
++	vmovdqa		0x110-0x100(%rcx),$xd1
++	vmovdqa		0x120-0x100(%rcx),$xd2
++	vmovdqa		0x130-0x100(%rcx),$xd3
++	vpaddd		.Lfour(%rip),$xd0,$xd0	# next SIMD counters
++
++.Loop_enter4xop:
++	mov		\$10,%eax
++	vmovdqa		$xd0,0x100-0x100(%rcx)	# save SIMD counters
++	jmp		.Loop4xop
++
++.align	32
++.Loop4xop:
++___
++	foreach (&XOP_lane_ROUND(0, 4, 8,12)) { eval; }
++	foreach (&XOP_lane_ROUND(0, 5,10,15)) { eval; }
++$code.=<<___;
++	dec		%eax
++	jnz		.Loop4xop
++
++	vpaddd		0x40(%rsp),$xa0,$xa0	# accumulate key material
++	vpaddd		0x50(%rsp),$xa1,$xa1
++	vpaddd		0x60(%rsp),$xa2,$xa2
++	vpaddd		0x70(%rsp),$xa3,$xa3
++
++	vmovdqa		$xt2,0x20(%rsp)		# offload $xc2,3
++	vmovdqa		$xt3,0x30(%rsp)
++
++	vpunpckldq	$xa1,$xa0,$xt2		# "de-interlace" data
++	vpunpckldq	$xa3,$xa2,$xt3
++	vpunpckhdq	$xa1,$xa0,$xa0
++	vpunpckhdq	$xa3,$xa2,$xa2
++	vpunpcklqdq	$xt3,$xt2,$xa1		# "a0"
++	vpunpckhqdq	$xt3,$xt2,$xt2		# "a1"
++	vpunpcklqdq	$xa2,$xa0,$xa3		# "a2"
++	vpunpckhqdq	$xa2,$xa0,$xa0		# "a3"
++___
++        ($xa0,$xa1,$xa2,$xa3,$xt2)=($xa1,$xt2,$xa3,$xa0,$xa2);
++$code.=<<___;
++	vpaddd		0x80-0x100(%rcx),$xb0,$xb0
++	vpaddd		0x90-0x100(%rcx),$xb1,$xb1
++	vpaddd		0xa0-0x100(%rcx),$xb2,$xb2
++	vpaddd		0xb0-0x100(%rcx),$xb3,$xb3
++
++	vmovdqa		$xa0,0x00(%rsp)		# offload $xa0,1
++	vmovdqa		$xa1,0x10(%rsp)
++	vmovdqa		0x20(%rsp),$xa0		# "xc2"
++	vmovdqa		0x30(%rsp),$xa1		# "xc3"
++
++	vpunpckldq	$xb1,$xb0,$xt2
++	vpunpckldq	$xb3,$xb2,$xt3
++	vpunpckhdq	$xb1,$xb0,$xb0
++	vpunpckhdq	$xb3,$xb2,$xb2
++	vpunpcklqdq	$xt3,$xt2,$xb1		# "b0"
++	vpunpckhqdq	$xt3,$xt2,$xt2		# "b1"
++	vpunpcklqdq	$xb2,$xb0,$xb3		# "b2"
++	vpunpckhqdq	$xb2,$xb0,$xb0		# "b3"
++___
++	($xb0,$xb1,$xb2,$xb3,$xt2)=($xb1,$xt2,$xb3,$xb0,$xb2);
++	my ($xc0,$xc1,$xc2,$xc3)=($xt0,$xt1,$xa0,$xa1);
++$code.=<<___;
++	vpaddd		0xc0-0x100(%rcx),$xc0,$xc0
++	vpaddd		0xd0-0x100(%rcx),$xc1,$xc1
++	vpaddd		0xe0-0x100(%rcx),$xc2,$xc2
++	vpaddd		0xf0-0x100(%rcx),$xc3,$xc3
++
++	vpunpckldq	$xc1,$xc0,$xt2
++	vpunpckldq	$xc3,$xc2,$xt3
++	vpunpckhdq	$xc1,$xc0,$xc0
++	vpunpckhdq	$xc3,$xc2,$xc2
++	vpunpcklqdq	$xt3,$xt2,$xc1		# "c0"
++	vpunpckhqdq	$xt3,$xt2,$xt2		# "c1"
++	vpunpcklqdq	$xc2,$xc0,$xc3		# "c2"
++	vpunpckhqdq	$xc2,$xc0,$xc0		# "c3"
++___
++	($xc0,$xc1,$xc2,$xc3,$xt2)=($xc1,$xt2,$xc3,$xc0,$xc2);
++$code.=<<___;
++	vpaddd		0x100-0x100(%rcx),$xd0,$xd0
++	vpaddd		0x110-0x100(%rcx),$xd1,$xd1
++	vpaddd		0x120-0x100(%rcx),$xd2,$xd2
++	vpaddd		0x130-0x100(%rcx),$xd3,$xd3
++
++	vpunpckldq	$xd1,$xd0,$xt2
++	vpunpckldq	$xd3,$xd2,$xt3
++	vpunpckhdq	$xd1,$xd0,$xd0
++	vpunpckhdq	$xd3,$xd2,$xd2
++	vpunpcklqdq	$xt3,$xt2,$xd1		# "d0"
++	vpunpckhqdq	$xt3,$xt2,$xt2		# "d1"
++	vpunpcklqdq	$xd2,$xd0,$xd3		# "d2"
++	vpunpckhqdq	$xd2,$xd0,$xd0		# "d3"
++___
++	($xd0,$xd1,$xd2,$xd3,$xt2)=($xd1,$xt2,$xd3,$xd0,$xd2);
++	($xa0,$xa1)=($xt2,$xt3);
++$code.=<<___;
++	vmovdqa		0x00(%rsp),$xa0		# restore $xa0,1
++	vmovdqa		0x10(%rsp),$xa1
++
++	cmp		\$64*4,$len
++	jb		.Ltail4xop
++
++	vpxor		0x00($inp),$xa0,$xa0	# xor with input
++	vpxor		0x10($inp),$xb0,$xb0
++	vpxor		0x20($inp),$xc0,$xc0
++	vpxor		0x30($inp),$xd0,$xd0
++	vpxor		0x40($inp),$xa1,$xa1
++	vpxor		0x50($inp),$xb1,$xb1
++	vpxor		0x60($inp),$xc1,$xc1
++	vpxor		0x70($inp),$xd1,$xd1
++	lea		0x80($inp),$inp		# size optimization
++	vpxor		0x00($inp),$xa2,$xa2
++	vpxor		0x10($inp),$xb2,$xb2
++	vpxor		0x20($inp),$xc2,$xc2
++	vpxor		0x30($inp),$xd2,$xd2
++	vpxor		0x40($inp),$xa3,$xa3
++	vpxor		0x50($inp),$xb3,$xb3
++	vpxor		0x60($inp),$xc3,$xc3
++	vpxor		0x70($inp),$xd3,$xd3
++	lea		0x80($inp),$inp		# inp+=64*4
++
++	vmovdqu		$xa0,0x00($out)
++	vmovdqu		$xb0,0x10($out)
++	vmovdqu		$xc0,0x20($out)
++	vmovdqu		$xd0,0x30($out)
++	vmovdqu		$xa1,0x40($out)
++	vmovdqu		$xb1,0x50($out)
++	vmovdqu		$xc1,0x60($out)
++	vmovdqu		$xd1,0x70($out)
++	lea		0x80($out),$out		# size optimization
++	vmovdqu		$xa2,0x00($out)
++	vmovdqu		$xb2,0x10($out)
++	vmovdqu		$xc2,0x20($out)
++	vmovdqu		$xd2,0x30($out)
++	vmovdqu		$xa3,0x40($out)
++	vmovdqu		$xb3,0x50($out)
++	vmovdqu		$xc3,0x60($out)
++	vmovdqu		$xd3,0x70($out)
++	lea		0x80($out),$out		# out+=64*4
++
++	sub		\$64*4,$len
++	jnz		.Loop_outer4xop
++
++	jmp		.Ldone4xop
++
++.align	32
++.Ltail4xop:
++	cmp		\$192,$len
++	jae		.L192_or_more4xop
++	cmp		\$128,$len
++	jae		.L128_or_more4xop
++	cmp		\$64,$len
++	jae		.L64_or_more4xop
++
++	xor		%r10,%r10
++	vmovdqa		$xa0,0x00(%rsp)
++	vmovdqa		$xb0,0x10(%rsp)
++	vmovdqa		$xc0,0x20(%rsp)
++	vmovdqa		$xd0,0x30(%rsp)
++	jmp		.Loop_tail4xop
++
++.align	32
++.L64_or_more4xop:
++	vpxor		0x00($inp),$xa0,$xa0	# xor with input
++	vpxor		0x10($inp),$xb0,$xb0
++	vpxor		0x20($inp),$xc0,$xc0
++	vpxor		0x30($inp),$xd0,$xd0
++	vmovdqu		$xa0,0x00($out)
++	vmovdqu		$xb0,0x10($out)
++	vmovdqu		$xc0,0x20($out)
++	vmovdqu		$xd0,0x30($out)
++	je		.Ldone4xop
++
++	lea		0x40($inp),$inp		# inp+=64*1
++	vmovdqa		$xa1,0x00(%rsp)
++	xor		%r10,%r10
++	vmovdqa		$xb1,0x10(%rsp)
++	lea		0x40($out),$out		# out+=64*1
++	vmovdqa		$xc1,0x20(%rsp)
++	sub		\$64,$len		# len-=64*1
++	vmovdqa		$xd1,0x30(%rsp)
++	jmp		.Loop_tail4xop
++
++.align	32
++.L128_or_more4xop:
++	vpxor		0x00($inp),$xa0,$xa0	# xor with input
++	vpxor		0x10($inp),$xb0,$xb0
++	vpxor		0x20($inp),$xc0,$xc0
++	vpxor		0x30($inp),$xd0,$xd0
++	vpxor		0x40($inp),$xa1,$xa1
++	vpxor		0x50($inp),$xb1,$xb1
++	vpxor		0x60($inp),$xc1,$xc1
++	vpxor		0x70($inp),$xd1,$xd1
++
++	vmovdqu		$xa0,0x00($out)
++	vmovdqu		$xb0,0x10($out)
++	vmovdqu		$xc0,0x20($out)
++	vmovdqu		$xd0,0x30($out)
++	vmovdqu		$xa1,0x40($out)
++	vmovdqu		$xb1,0x50($out)
++	vmovdqu		$xc1,0x60($out)
++	vmovdqu		$xd1,0x70($out)
++	je		.Ldone4xop
++
++	lea		0x80($inp),$inp		# inp+=64*2
++	vmovdqa		$xa2,0x00(%rsp)
++	xor		%r10,%r10
++	vmovdqa		$xb2,0x10(%rsp)
++	lea		0x80($out),$out		# out+=64*2
++	vmovdqa		$xc2,0x20(%rsp)
++	sub		\$128,$len		# len-=64*2
++	vmovdqa		$xd2,0x30(%rsp)
++	jmp		.Loop_tail4xop
++
++.align	32
++.L192_or_more4xop:
++	vpxor		0x00($inp),$xa0,$xa0	# xor with input
++	vpxor		0x10($inp),$xb0,$xb0
++	vpxor		0x20($inp),$xc0,$xc0
++	vpxor		0x30($inp),$xd0,$xd0
++	vpxor		0x40($inp),$xa1,$xa1
++	vpxor		0x50($inp),$xb1,$xb1
++	vpxor		0x60($inp),$xc1,$xc1
++	vpxor		0x70($inp),$xd1,$xd1
++	lea		0x80($inp),$inp		# size optimization
++	vpxor		0x00($inp),$xa2,$xa2
++	vpxor		0x10($inp),$xb2,$xb2
++	vpxor		0x20($inp),$xc2,$xc2
++	vpxor		0x30($inp),$xd2,$xd2
++
++	vmovdqu		$xa0,0x00($out)
++	vmovdqu		$xb0,0x10($out)
++	vmovdqu		$xc0,0x20($out)
++	vmovdqu		$xd0,0x30($out)
++	vmovdqu		$xa1,0x40($out)
++	vmovdqu		$xb1,0x50($out)
++	vmovdqu		$xc1,0x60($out)
++	vmovdqu		$xd1,0x70($out)
++	lea		0x80($out),$out		# size optimization
++	vmovdqu		$xa2,0x00($out)
++	vmovdqu		$xb2,0x10($out)
++	vmovdqu		$xc2,0x20($out)
++	vmovdqu		$xd2,0x30($out)
++	je		.Ldone4xop
++
++	lea		0x40($inp),$inp		# inp+=64*3
++	vmovdqa		$xa3,0x00(%rsp)
++	xor		%r10,%r10
++	vmovdqa		$xb3,0x10(%rsp)
++	lea		0x40($out),$out		# out+=64*3
++	vmovdqa		$xc3,0x20(%rsp)
++	sub		\$192,$len		# len-=64*3
++	vmovdqa		$xd3,0x30(%rsp)
++
++.Loop_tail4xop:
++	movzb		($inp,%r10),%eax
++	movzb		(%rsp,%r10),%ecx
++	lea		1(%r10),%r10
++	xor		%ecx,%eax
++	mov		%al,-1($out,%r10)
++	dec		$len
++	jnz		.Loop_tail4xop
++
++.Ldone4xop:
++	vzeroupper
++___
++$code.=<<___	if ($win64);
++	lea		0x140+0x30(%rsp),%r11
++	movaps		-0x30(%r11),%xmm6
++	movaps		-0x20(%r11),%xmm7
++	movaps		-0x10(%r11),%xmm8
++	movaps		0x00(%r11),%xmm9
++	movaps		0x10(%r11),%xmm10
++	movaps		0x20(%r11),%xmm11
++	movaps		0x30(%r11),%xmm12
++	movaps		0x40(%r11),%xmm13
++	movaps		0x50(%r11),%xmm14
++	movaps		0x60(%r11),%xmm15
++___
++$code.=<<___;
++	add		\$0x148+$xframe,%rsp
++	ret
++.size	ChaCha20_4xop,.-ChaCha20_4xop
++___
++}
++
++########################################################################
++# AVX2 code path
++if ($avx>1) {
++my ($xb0,$xb1,$xb2,$xb3, $xd0,$xd1,$xd2,$xd3,
++    $xa0,$xa1,$xa2,$xa3, $xt0,$xt1,$xt2,$xt3)=map("%ymm$_",(0..15));
++my @xx=($xa0,$xa1,$xa2,$xa3, $xb0,$xb1,$xb2,$xb3,
++	"%nox","%nox","%nox","%nox", $xd0,$xd1,$xd2,$xd3);
++
++sub AVX2_lane_ROUND {
++my ($a0,$b0,$c0,$d0)=@_;
++my ($a1,$b1,$c1,$d1)=map(($_&~3)+(($_+1)&3),($a0,$b0,$c0,$d0));
++my ($a2,$b2,$c2,$d2)=map(($_&~3)+(($_+1)&3),($a1,$b1,$c1,$d1));
++my ($a3,$b3,$c3,$d3)=map(($_&~3)+(($_+1)&3),($a2,$b2,$c2,$d2));
++my ($xc,$xc_,$t0,$t1)=map("\"$_\"",$xt0,$xt1,$xt2,$xt3);
++my @x=map("\"$_\"",@xx);
++
++	# Consider order in which variables are addressed by their
++	# index:
++	#
++	#	a   b   c   d
++	#
++	#	0   4   8  12 < even round
++	#	1   5   9  13
++	#	2   6  10  14
++	#	3   7  11  15
++	#	0   5  10  15 < odd round
++	#	1   6  11  12
++	#	2   7   8  13
++	#	3   4   9  14
++	#
++	# 'a', 'b' and 'd's are permanently allocated in registers,
++	# @x[0..7,12..15], while 'c's are maintained in memory. If
++	# you observe 'c' column, you'll notice that pair of 'c's is
++	# invariant between rounds. This means that we have to reload
++	# them once per round, in the middle. This is why you'll see
++	# bunch of 'c' stores and loads in the middle, but none in
++	# the beginning or end.
++
++	(
++	"&vpaddd	(@x[$a0],@x[$a0],@x[$b0])",	# Q1
++	"&vpxor		(@x[$d0],@x[$a0],@x[$d0])",
++	"&vpshufb	(@x[$d0],@x[$d0],$t1)",
++	 "&vpaddd	(@x[$a1],@x[$a1],@x[$b1])",	# Q2
++	 "&vpxor	(@x[$d1],@x[$a1],@x[$d1])",
++	 "&vpshufb	(@x[$d1],@x[$d1],$t1)",
++
++	"&vpaddd	($xc,$xc,@x[$d0])",
++	"&vpxor		(@x[$b0],$xc,@x[$b0])",
++	"&vpslld	($t0,@x[$b0],12)",
++	"&vpsrld	(@x[$b0],@x[$b0],20)",
++	"&vpor		(@x[$b0],$t0,@x[$b0])",
++	"&vbroadcasti128($t0,'(%r11)')",		# .Lrot24(%rip)
++	 "&vpaddd	($xc_,$xc_,@x[$d1])",
++	 "&vpxor	(@x[$b1],$xc_,@x[$b1])",
++	 "&vpslld	($t1,@x[$b1],12)",
++	 "&vpsrld	(@x[$b1],@x[$b1],20)",
++	 "&vpor		(@x[$b1],$t1,@x[$b1])",
++
++	"&vpaddd	(@x[$a0],@x[$a0],@x[$b0])",
++	"&vpxor		(@x[$d0],@x[$a0],@x[$d0])",
++	"&vpshufb	(@x[$d0],@x[$d0],$t0)",
++	 "&vpaddd	(@x[$a1],@x[$a1],@x[$b1])",
++	 "&vpxor	(@x[$d1],@x[$a1],@x[$d1])",
++	 "&vpshufb	(@x[$d1],@x[$d1],$t0)",
++
++	"&vpaddd	($xc,$xc,@x[$d0])",
++	"&vpxor		(@x[$b0],$xc,@x[$b0])",
++	"&vpslld	($t1,@x[$b0],7)",
++	"&vpsrld	(@x[$b0],@x[$b0],25)",
++	"&vpor		(@x[$b0],$t1,@x[$b0])",
++	"&vbroadcasti128($t1,'(%r10)')",		# .Lrot16(%rip)
++	 "&vpaddd	($xc_,$xc_,@x[$d1])",
++	 "&vpxor	(@x[$b1],$xc_,@x[$b1])",
++	 "&vpslld	($t0,@x[$b1],7)",
++	 "&vpsrld	(@x[$b1],@x[$b1],25)",
++	 "&vpor		(@x[$b1],$t0,@x[$b1])",
++
++	"&vmovdqa	(\"`32*($c0-8)`(%rsp)\",$xc)",	# reload pair of 'c's
++	 "&vmovdqa	(\"`32*($c1-8)`(%rsp)\",$xc_)",
++	"&vmovdqa	($xc,\"`32*($c2-8)`(%rsp)\")",
++	 "&vmovdqa	($xc_,\"`32*($c3-8)`(%rsp)\")",
++
++	"&vpaddd	(@x[$a2],@x[$a2],@x[$b2])",	# Q3
++	"&vpxor		(@x[$d2],@x[$a2],@x[$d2])",
++	"&vpshufb	(@x[$d2],@x[$d2],$t1)",
++	 "&vpaddd	(@x[$a3],@x[$a3],@x[$b3])",	# Q4
++	 "&vpxor	(@x[$d3],@x[$a3],@x[$d3])",
++	 "&vpshufb	(@x[$d3],@x[$d3],$t1)",
++
++	"&vpaddd	($xc,$xc,@x[$d2])",
++	"&vpxor		(@x[$b2],$xc,@x[$b2])",
++	"&vpslld	($t0,@x[$b2],12)",
++	"&vpsrld	(@x[$b2],@x[$b2],20)",
++	"&vpor		(@x[$b2],$t0,@x[$b2])",
++	"&vbroadcasti128($t0,'(%r11)')",		# .Lrot24(%rip)
++	 "&vpaddd	($xc_,$xc_,@x[$d3])",
++	 "&vpxor	(@x[$b3],$xc_,@x[$b3])",
++	 "&vpslld	($t1,@x[$b3],12)",
++	 "&vpsrld	(@x[$b3],@x[$b3],20)",
++	 "&vpor		(@x[$b3],$t1,@x[$b3])",
++
++	"&vpaddd	(@x[$a2],@x[$a2],@x[$b2])",
++	"&vpxor		(@x[$d2],@x[$a2],@x[$d2])",
++	"&vpshufb	(@x[$d2],@x[$d2],$t0)",
++	 "&vpaddd	(@x[$a3],@x[$a3],@x[$b3])",
++	 "&vpxor	(@x[$d3],@x[$a3],@x[$d3])",
++	 "&vpshufb	(@x[$d3],@x[$d3],$t0)",
++
++	"&vpaddd	($xc,$xc,@x[$d2])",
++	"&vpxor		(@x[$b2],$xc,@x[$b2])",
++	"&vpslld	($t1,@x[$b2],7)",
++	"&vpsrld	(@x[$b2],@x[$b2],25)",
++	"&vpor		(@x[$b2],$t1,@x[$b2])",
++	"&vbroadcasti128($t1,'(%r10)')",		# .Lrot16(%rip)
++	 "&vpaddd	($xc_,$xc_,@x[$d3])",
++	 "&vpxor	(@x[$b3],$xc_,@x[$b3])",
++	 "&vpslld	($t0,@x[$b3],7)",
++	 "&vpsrld	(@x[$b3],@x[$b3],25)",
++	 "&vpor		(@x[$b3],$t0,@x[$b3])"
++	);
++}
++
++my $xframe = $win64 ? 0xb0 : 8;
++
++$code.=<<___;
++.type	ChaCha20_8x,\@function,5
++.align	32
++ChaCha20_8x:
++.LChaCha20_8x:
++	mov		%rsp,%r10
++	sub		\$0x280+$xframe,%rsp
++	and		\$-32,%rsp
++___
++$code.=<<___	if ($win64);
++	lea		0x290+0x30(%rsp),%r11
++	movaps		%xmm6,-0x30(%r11)
++	movaps		%xmm7,-0x20(%r11)
++	movaps		%xmm8,-0x10(%r11)
++	movaps		%xmm9,0x00(%r11)
++	movaps		%xmm10,0x10(%r11)
++	movaps		%xmm11,0x20(%r11)
++	movaps		%xmm12,0x30(%r11)
++	movaps		%xmm13,0x40(%r11)
++	movaps		%xmm14,0x50(%r11)
++	movaps		%xmm15,0x60(%r11)
++___
++$code.=<<___;
++	vzeroupper
++	mov		%r10,0x280(%rsp)
++
++	################ stack layout
++	# +0x00		SIMD equivalent of @x[8-12]
++	# ...
++	# +0x80		constant copy of key[0-2] smashed by lanes
++	# ...
++	# +0x200	SIMD counters (with nonce smashed by lanes)
++	# ...
++	# +0x280	saved %rsp
++
++	vbroadcasti128	.Lsigma(%rip),$xa3	# key[0]
++	vbroadcasti128	($key),$xb3		# key[1]
++	vbroadcasti128	16($key),$xt3		# key[2]
++	vbroadcasti128	($counter),$xd3		# key[3]
++	lea		0x100(%rsp),%rcx	# size optimization
++	lea		0x200(%rsp),%rax	# size optimization
++	lea		.Lrot16(%rip),%r10
++	lea		.Lrot24(%rip),%r11
++
++	vpshufd		\$0x00,$xa3,$xa0	# smash key by lanes...
++	vpshufd		\$0x55,$xa3,$xa1
++	vmovdqa		$xa0,0x80-0x100(%rcx)	# ... and offload
++	vpshufd		\$0xaa,$xa3,$xa2
++	vmovdqa		$xa1,0xa0-0x100(%rcx)
++	vpshufd		\$0xff,$xa3,$xa3
++	vmovdqa		$xa2,0xc0-0x100(%rcx)
++	vmovdqa		$xa3,0xe0-0x100(%rcx)
++
++	vpshufd		\$0x00,$xb3,$xb0
++	vpshufd		\$0x55,$xb3,$xb1
++	vmovdqa		$xb0,0x100-0x100(%rcx)
++	vpshufd		\$0xaa,$xb3,$xb2
++	vmovdqa		$xb1,0x120-0x100(%rcx)
++	vpshufd		\$0xff,$xb3,$xb3
++	vmovdqa		$xb2,0x140-0x100(%rcx)
++	vmovdqa		$xb3,0x160-0x100(%rcx)
++
++	vpshufd		\$0x00,$xt3,$xt0	# "xc0"
++	vpshufd		\$0x55,$xt3,$xt1	# "xc1"
++	vmovdqa		$xt0,0x180-0x200(%rax)
++	vpshufd		\$0xaa,$xt3,$xt2	# "xc2"
++	vmovdqa		$xt1,0x1a0-0x200(%rax)
++	vpshufd		\$0xff,$xt3,$xt3	# "xc3"
++	vmovdqa		$xt2,0x1c0-0x200(%rax)
++	vmovdqa		$xt3,0x1e0-0x200(%rax)
++
++	vpshufd		\$0x00,$xd3,$xd0
++	vpshufd		\$0x55,$xd3,$xd1
++	vpaddd		.Lincy(%rip),$xd0,$xd0	# don't save counters yet
++	vpshufd		\$0xaa,$xd3,$xd2
++	vmovdqa		$xd1,0x220-0x200(%rax)
++	vpshufd		\$0xff,$xd3,$xd3
++	vmovdqa		$xd2,0x240-0x200(%rax)
++	vmovdqa		$xd3,0x260-0x200(%rax)
++
++	jmp		.Loop_enter8x
++
++.align	32
++.Loop_outer8x:
++	vmovdqa		0x80-0x100(%rcx),$xa0	# re-load smashed key
++	vmovdqa		0xa0-0x100(%rcx),$xa1
++	vmovdqa		0xc0-0x100(%rcx),$xa2
++	vmovdqa		0xe0-0x100(%rcx),$xa3
++	vmovdqa		0x100-0x100(%rcx),$xb0
++	vmovdqa		0x120-0x100(%rcx),$xb1
++	vmovdqa		0x140-0x100(%rcx),$xb2
++	vmovdqa		0x160-0x100(%rcx),$xb3
++	vmovdqa		0x180-0x200(%rax),$xt0	# "xc0"
++	vmovdqa		0x1a0-0x200(%rax),$xt1	# "xc1"
++	vmovdqa		0x1c0-0x200(%rax),$xt2	# "xc2"
++	vmovdqa		0x1e0-0x200(%rax),$xt3	# "xc3"
++	vmovdqa		0x200-0x200(%rax),$xd0
++	vmovdqa		0x220-0x200(%rax),$xd1
++	vmovdqa		0x240-0x200(%rax),$xd2
++	vmovdqa		0x260-0x200(%rax),$xd3
++	vpaddd		.Leight(%rip),$xd0,$xd0	# next SIMD counters
++
++.Loop_enter8x:
++	vmovdqa		$xt2,0x40(%rsp)		# SIMD equivalent of "@x[10]"
++	vmovdqa		$xt3,0x60(%rsp)		# SIMD equivalent of "@x[11]"
++	vbroadcasti128	(%r10),$xt3
++	vmovdqa		$xd0,0x200-0x200(%rax)	# save SIMD counters
++	mov		\$10,%eax
++	jmp		.Loop8x
++
++.align	32
++.Loop8x:
++___
++	foreach (&AVX2_lane_ROUND(0, 4, 8,12)) { eval; }
++	foreach (&AVX2_lane_ROUND(0, 5,10,15)) { eval; }
++$code.=<<___;
++	dec		%eax
++	jnz		.Loop8x
++
++	lea		0x200(%rsp),%rax	# size optimization
++	vpaddd		0x80-0x100(%rcx),$xa0,$xa0	# accumulate key
++	vpaddd		0xa0-0x100(%rcx),$xa1,$xa1
++	vpaddd		0xc0-0x100(%rcx),$xa2,$xa2
++	vpaddd		0xe0-0x100(%rcx),$xa3,$xa3
++
++	vpunpckldq	$xa1,$xa0,$xt2		# "de-interlace" data
++	vpunpckldq	$xa3,$xa2,$xt3
++	vpunpckhdq	$xa1,$xa0,$xa0
++	vpunpckhdq	$xa3,$xa2,$xa2
++	vpunpcklqdq	$xt3,$xt2,$xa1		# "a0"
++	vpunpckhqdq	$xt3,$xt2,$xt2		# "a1"
++	vpunpcklqdq	$xa2,$xa0,$xa3		# "a2"
++	vpunpckhqdq	$xa2,$xa0,$xa0		# "a3"
++___
++	($xa0,$xa1,$xa2,$xa3,$xt2)=($xa1,$xt2,$xa3,$xa0,$xa2);
++$code.=<<___;
++	vpaddd		0x100-0x100(%rcx),$xb0,$xb0
++	vpaddd		0x120-0x100(%rcx),$xb1,$xb1
++	vpaddd		0x140-0x100(%rcx),$xb2,$xb2
++	vpaddd		0x160-0x100(%rcx),$xb3,$xb3
++
++	vpunpckldq	$xb1,$xb0,$xt2
++	vpunpckldq	$xb3,$xb2,$xt3
++	vpunpckhdq	$xb1,$xb0,$xb0
++	vpunpckhdq	$xb3,$xb2,$xb2
++	vpunpcklqdq	$xt3,$xt2,$xb1		# "b0"
++	vpunpckhqdq	$xt3,$xt2,$xt2		# "b1"
++	vpunpcklqdq	$xb2,$xb0,$xb3		# "b2"
++	vpunpckhqdq	$xb2,$xb0,$xb0		# "b3"
++___
++	($xb0,$xb1,$xb2,$xb3,$xt2)=($xb1,$xt2,$xb3,$xb0,$xb2);
++$code.=<<___;
++	vperm2i128	\$0x20,$xb0,$xa0,$xt3	# "de-interlace" further
++	vperm2i128	\$0x31,$xb0,$xa0,$xb0
++	vperm2i128	\$0x20,$xb1,$xa1,$xa0
++	vperm2i128	\$0x31,$xb1,$xa1,$xb1
++	vperm2i128	\$0x20,$xb2,$xa2,$xa1
++	vperm2i128	\$0x31,$xb2,$xa2,$xb2
++	vperm2i128	\$0x20,$xb3,$xa3,$xa2
++	vperm2i128	\$0x31,$xb3,$xa3,$xb3
++___
++	($xa0,$xa1,$xa2,$xa3,$xt3)=($xt3,$xa0,$xa1,$xa2,$xa3);
++	my ($xc0,$xc1,$xc2,$xc3)=($xt0,$xt1,$xa0,$xa1);
++$code.=<<___;
++	vmovdqa		$xa0,0x00(%rsp)		# offload $xaN
++	vmovdqa		$xa1,0x20(%rsp)
++	vmovdqa		0x40(%rsp),$xc2		# $xa0
++	vmovdqa		0x60(%rsp),$xc3		# $xa1
++
++	vpaddd		0x180-0x200(%rax),$xc0,$xc0
++	vpaddd		0x1a0-0x200(%rax),$xc1,$xc1
++	vpaddd		0x1c0-0x200(%rax),$xc2,$xc2
++	vpaddd		0x1e0-0x200(%rax),$xc3,$xc3
++
++	vpunpckldq	$xc1,$xc0,$xt2
++	vpunpckldq	$xc3,$xc2,$xt3
++	vpunpckhdq	$xc1,$xc0,$xc0
++	vpunpckhdq	$xc3,$xc2,$xc2
++	vpunpcklqdq	$xt3,$xt2,$xc1		# "c0"
++	vpunpckhqdq	$xt3,$xt2,$xt2		# "c1"
++	vpunpcklqdq	$xc2,$xc0,$xc3		# "c2"
++	vpunpckhqdq	$xc2,$xc0,$xc0		# "c3"
++___
++	($xc0,$xc1,$xc2,$xc3,$xt2)=($xc1,$xt2,$xc3,$xc0,$xc2);
++$code.=<<___;
++	vpaddd		0x200-0x200(%rax),$xd0,$xd0
++	vpaddd		0x220-0x200(%rax),$xd1,$xd1
++	vpaddd		0x240-0x200(%rax),$xd2,$xd2
++	vpaddd		0x260-0x200(%rax),$xd3,$xd3
++
++	vpunpckldq	$xd1,$xd0,$xt2
++	vpunpckldq	$xd3,$xd2,$xt3
++	vpunpckhdq	$xd1,$xd0,$xd0
++	vpunpckhdq	$xd3,$xd2,$xd2
++	vpunpcklqdq	$xt3,$xt2,$xd1		# "d0"
++	vpunpckhqdq	$xt3,$xt2,$xt2		# "d1"
++	vpunpcklqdq	$xd2,$xd0,$xd3		# "d2"
++	vpunpckhqdq	$xd2,$xd0,$xd0		# "d3"
++___
++	($xd0,$xd1,$xd2,$xd3,$xt2)=($xd1,$xt2,$xd3,$xd0,$xd2);
++$code.=<<___;
++	vperm2i128	\$0x20,$xd0,$xc0,$xt3	# "de-interlace" further
++	vperm2i128	\$0x31,$xd0,$xc0,$xd0
++	vperm2i128	\$0x20,$xd1,$xc1,$xc0
++	vperm2i128	\$0x31,$xd1,$xc1,$xd1
++	vperm2i128	\$0x20,$xd2,$xc2,$xc1
++	vperm2i128	\$0x31,$xd2,$xc2,$xd2
++	vperm2i128	\$0x20,$xd3,$xc3,$xc2
++	vperm2i128	\$0x31,$xd3,$xc3,$xd3
++___
++	($xc0,$xc1,$xc2,$xc3,$xt3)=($xt3,$xc0,$xc1,$xc2,$xc3);
++	($xb0,$xb1,$xb2,$xb3,$xc0,$xc1,$xc2,$xc3)=
++	($xc0,$xc1,$xc2,$xc3,$xb0,$xb1,$xb2,$xb3);
++	($xa0,$xa1)=($xt2,$xt3);
++$code.=<<___;
++	vmovdqa		0x00(%rsp),$xa0		# $xaN was offloaded, remember?
++	vmovdqa		0x20(%rsp),$xa1
++
++	cmp		\$64*8,$len
++	jb		.Ltail8x
++
++	vpxor		0x00($inp),$xa0,$xa0	# xor with input
++	vpxor		0x20($inp),$xb0,$xb0
++	vpxor		0x40($inp),$xc0,$xc0
++	vpxor		0x60($inp),$xd0,$xd0
++	lea		0x80($inp),$inp		# size optimization
++	vmovdqu		$xa0,0x00($out)
++	vmovdqu		$xb0,0x20($out)
++	vmovdqu		$xc0,0x40($out)
++	vmovdqu		$xd0,0x60($out)
++	lea		0x80($out),$out		# size optimization
++
++	vpxor		0x00($inp),$xa1,$xa1
++	vpxor		0x20($inp),$xb1,$xb1
++	vpxor		0x40($inp),$xc1,$xc1
++	vpxor		0x60($inp),$xd1,$xd1
++	lea		0x80($inp),$inp		# size optimization
++	vmovdqu		$xa1,0x00($out)
++	vmovdqu		$xb1,0x20($out)
++	vmovdqu		$xc1,0x40($out)
++	vmovdqu		$xd1,0x60($out)
++	lea		0x80($out),$out		# size optimization
++
++	vpxor		0x00($inp),$xa2,$xa2
++	vpxor		0x20($inp),$xb2,$xb2
++	vpxor		0x40($inp),$xc2,$xc2
++	vpxor		0x60($inp),$xd2,$xd2
++	lea		0x80($inp),$inp		# size optimization
++	vmovdqu		$xa2,0x00($out)
++	vmovdqu		$xb2,0x20($out)
++	vmovdqu		$xc2,0x40($out)
++	vmovdqu		$xd2,0x60($out)
++	lea		0x80($out),$out		# size optimization
++
++	vpxor		0x00($inp),$xa3,$xa3
++	vpxor		0x20($inp),$xb3,$xb3
++	vpxor		0x40($inp),$xc3,$xc3
++	vpxor		0x60($inp),$xd3,$xd3
++	lea		0x80($inp),$inp		# size optimization
++	vmovdqu		$xa3,0x00($out)
++	vmovdqu		$xb3,0x20($out)
++	vmovdqu		$xc3,0x40($out)
++	vmovdqu		$xd3,0x60($out)
++	lea		0x80($out),$out		# size optimization
++
++	sub		\$64*8,$len
++	jnz		.Loop_outer8x
++
++	jmp		.Ldone8x
++
++.Ltail8x:
++	cmp		\$448,$len
++	jae		.L448_or_more8x
++	cmp		\$384,$len
++	jae		.L384_or_more8x
++	cmp		\$320,$len
++	jae		.L320_or_more8x
++	cmp		\$256,$len
++	jae		.L256_or_more8x
++	cmp		\$192,$len
++	jae		.L192_or_more8x
++	cmp		\$128,$len
++	jae		.L128_or_more8x
++	cmp		\$64,$len
++	jae		.L64_or_more8x
++
++	xor		%r10,%r10
++	vmovdqa		$xa0,0x00(%rsp)
++	vmovdqa		$xb0,0x20(%rsp)
++	jmp		.Loop_tail8x
++
++.align	32
++.L64_or_more8x:
++	vpxor		0x00($inp),$xa0,$xa0	# xor with input
++	vpxor		0x20($inp),$xb0,$xb0
++	vmovdqu		$xa0,0x00($out)
++	vmovdqu		$xb0,0x20($out)
++	je		.Ldone8x
++
++	lea		0x40($inp),$inp		# inp+=64*1
++	xor		%r10,%r10
++	vmovdqa		$xc0,0x00(%rsp)
++	lea		0x40($out),$out		# out+=64*1
++	sub		\$64,$len		# len-=64*1
++	vmovdqa		$xd0,0x20(%rsp)
++	jmp		.Loop_tail8x
++
++.align	32
++.L128_or_more8x:
++	vpxor		0x00($inp),$xa0,$xa0	# xor with input
++	vpxor		0x20($inp),$xb0,$xb0
++	vpxor		0x40($inp),$xc0,$xc0
++	vpxor		0x60($inp),$xd0,$xd0
++	vmovdqu		$xa0,0x00($out)
++	vmovdqu		$xb0,0x20($out)
++	vmovdqu		$xc0,0x40($out)
++	vmovdqu		$xd0,0x60($out)
++	je		.Ldone8x
++
++	lea		0x80($inp),$inp		# inp+=64*2
++	xor		%r10,%r10
++	vmovdqa		$xa1,0x00(%rsp)
++	lea		0x80($out),$out		# out+=64*2
++	sub		\$128,$len		# len-=64*2
++	vmovdqa		$xb1,0x20(%rsp)
++	jmp		.Loop_tail8x
++
++.align	32
++.L192_or_more8x:
++	vpxor		0x00($inp),$xa0,$xa0	# xor with input
++	vpxor		0x20($inp),$xb0,$xb0
++	vpxor		0x40($inp),$xc0,$xc0
++	vpxor		0x60($inp),$xd0,$xd0
++	vpxor		0x80($inp),$xa1,$xa1
++	vpxor		0xa0($inp),$xb1,$xb1
++	vmovdqu		$xa0,0x00($out)
++	vmovdqu		$xb0,0x20($out)
++	vmovdqu		$xc0,0x40($out)
++	vmovdqu		$xd0,0x60($out)
++	vmovdqu		$xa1,0x80($out)
++	vmovdqu		$xb1,0xa0($out)
++	je		.Ldone8x
++
++	lea		0xc0($inp),$inp		# inp+=64*3
++	xor		%r10,%r10
++	vmovdqa		$xc1,0x00(%rsp)
++	lea		0xc0($out),$out		# out+=64*3
++	sub		\$192,$len		# len-=64*3
++	vmovdqa		$xd1,0x20(%rsp)
++	jmp		.Loop_tail8x
++
++.align	32
++.L256_or_more8x:
++	vpxor		0x00($inp),$xa0,$xa0	# xor with input
++	vpxor		0x20($inp),$xb0,$xb0
++	vpxor		0x40($inp),$xc0,$xc0
++	vpxor		0x60($inp),$xd0,$xd0
++	vpxor		0x80($inp),$xa1,$xa1
++	vpxor		0xa0($inp),$xb1,$xb1
++	vpxor		0xc0($inp),$xc1,$xc1
++	vpxor		0xe0($inp),$xd1,$xd1
++	vmovdqu		$xa0,0x00($out)
++	vmovdqu		$xb0,0x20($out)
++	vmovdqu		$xc0,0x40($out)
++	vmovdqu		$xd0,0x60($out)
++	vmovdqu		$xa1,0x80($out)
++	vmovdqu		$xb1,0xa0($out)
++	vmovdqu		$xc1,0xc0($out)
++	vmovdqu		$xd1,0xe0($out)
++	je		.Ldone8x
++
++	lea		0x100($inp),$inp	# inp+=64*4
++	xor		%r10,%r10
++	vmovdqa		$xa2,0x00(%rsp)
++	lea		0x100($out),$out	# out+=64*4
++	sub		\$256,$len		# len-=64*4
++	vmovdqa		$xb2,0x20(%rsp)
++	jmp		.Loop_tail8x
++
++.align	32
++.L320_or_more8x:
++	vpxor		0x00($inp),$xa0,$xa0	# xor with input
++	vpxor		0x20($inp),$xb0,$xb0
++	vpxor		0x40($inp),$xc0,$xc0
++	vpxor		0x60($inp),$xd0,$xd0
++	vpxor		0x80($inp),$xa1,$xa1
++	vpxor		0xa0($inp),$xb1,$xb1
++	vpxor		0xc0($inp),$xc1,$xc1
++	vpxor		0xe0($inp),$xd1,$xd1
++	vpxor		0x100($inp),$xa2,$xa2
++	vpxor		0x120($inp),$xb2,$xb2
++	vmovdqu		$xa0,0x00($out)
++	vmovdqu		$xb0,0x20($out)
++	vmovdqu		$xc0,0x40($out)
++	vmovdqu		$xd0,0x60($out)
++	vmovdqu		$xa1,0x80($out)
++	vmovdqu		$xb1,0xa0($out)
++	vmovdqu		$xc1,0xc0($out)
++	vmovdqu		$xd1,0xe0($out)
++	vmovdqu		$xa2,0x100($out)
++	vmovdqu		$xb2,0x120($out)
++	je		.Ldone8x
++
++	lea		0x140($inp),$inp	# inp+=64*5
++	xor		%r10,%r10
++	vmovdqa		$xc2,0x00(%rsp)
++	lea		0x140($out),$out	# out+=64*5
++	sub		\$320,$len		# len-=64*5
++	vmovdqa		$xd2,0x20(%rsp)
++	jmp		.Loop_tail8x
++
++.align	32
++.L384_or_more8x:
++	vpxor		0x00($inp),$xa0,$xa0	# xor with input
++	vpxor		0x20($inp),$xb0,$xb0
++	vpxor		0x40($inp),$xc0,$xc0
++	vpxor		0x60($inp),$xd0,$xd0
++	vpxor		0x80($inp),$xa1,$xa1
++	vpxor		0xa0($inp),$xb1,$xb1
++	vpxor		0xc0($inp),$xc1,$xc1
++	vpxor		0xe0($inp),$xd1,$xd1
++	vpxor		0x100($inp),$xa2,$xa2
++	vpxor		0x120($inp),$xb2,$xb2
++	vpxor		0x140($inp),$xc2,$xc2
++	vpxor		0x160($inp),$xd2,$xd2
++	vmovdqu		$xa0,0x00($out)
++	vmovdqu		$xb0,0x20($out)
++	vmovdqu		$xc0,0x40($out)
++	vmovdqu		$xd0,0x60($out)
++	vmovdqu		$xa1,0x80($out)
++	vmovdqu		$xb1,0xa0($out)
++	vmovdqu		$xc1,0xc0($out)
++	vmovdqu		$xd1,0xe0($out)
++	vmovdqu		$xa2,0x100($out)
++	vmovdqu		$xb2,0x120($out)
++	vmovdqu		$xc2,0x140($out)
++	vmovdqu		$xd2,0x160($out)
++	je		.Ldone8x
++
++	lea		0x180($inp),$inp	# inp+=64*6
++	xor		%r10,%r10
++	vmovdqa		$xa3,0x00(%rsp)
++	lea		0x180($out),$out	# out+=64*6
++	sub		\$384,$len		# len-=64*6
++	vmovdqa		$xb3,0x20(%rsp)
++	jmp		.Loop_tail8x
++
++.align	32
++.L448_or_more8x:
++	vpxor		0x00($inp),$xa0,$xa0	# xor with input
++	vpxor		0x20($inp),$xb0,$xb0
++	vpxor		0x40($inp),$xc0,$xc0
++	vpxor		0x60($inp),$xd0,$xd0
++	vpxor		0x80($inp),$xa1,$xa1
++	vpxor		0xa0($inp),$xb1,$xb1
++	vpxor		0xc0($inp),$xc1,$xc1
++	vpxor		0xe0($inp),$xd1,$xd1
++	vpxor		0x100($inp),$xa2,$xa2
++	vpxor		0x120($inp),$xb2,$xb2
++	vpxor		0x140($inp),$xc2,$xc2
++	vpxor		0x160($inp),$xd2,$xd2
++	vpxor		0x180($inp),$xa3,$xa3
++	vpxor		0x1a0($inp),$xb3,$xb3
++	vmovdqu		$xa0,0x00($out)
++	vmovdqu		$xb0,0x20($out)
++	vmovdqu		$xc0,0x40($out)
++	vmovdqu		$xd0,0x60($out)
++	vmovdqu		$xa1,0x80($out)
++	vmovdqu		$xb1,0xa0($out)
++	vmovdqu		$xc1,0xc0($out)
++	vmovdqu		$xd1,0xe0($out)
++	vmovdqu		$xa2,0x100($out)
++	vmovdqu		$xb2,0x120($out)
++	vmovdqu		$xc2,0x140($out)
++	vmovdqu		$xd2,0x160($out)
++	vmovdqu		$xa3,0x180($out)
++	vmovdqu		$xb3,0x1a0($out)
++	je		.Ldone8x
++
++	lea		0x1c0($inp),$inp	# inp+=64*7
++	xor		%r10,%r10
++	vmovdqa		$xc3,0x00(%rsp)
++	lea		0x1c0($out),$out	# out+=64*7
++	sub		\$448,$len		# len-=64*7
++	vmovdqa		$xd3,0x20(%rsp)
++
++.Loop_tail8x:
++	movzb		($inp,%r10),%eax
++	movzb		(%rsp,%r10),%ecx
++	lea		1(%r10),%r10
++	xor		%ecx,%eax
++	mov		%al,-1($out,%r10)
++	dec		$len
++	jnz		.Loop_tail8x
++
++.Ldone8x:
++	vzeroall
++___
++$code.=<<___	if ($win64);
++	lea		0x290+0x30(%rsp),%r11
++	movaps		-0x30(%r11),%xmm6
++	movaps		-0x20(%r11),%xmm7
++	movaps		-0x10(%r11),%xmm8
++	movaps		0x00(%r11),%xmm9
++	movaps		0x10(%r11),%xmm10
++	movaps		0x20(%r11),%xmm11
++	movaps		0x30(%r11),%xmm12
++	movaps		0x40(%r11),%xmm13
++	movaps		0x50(%r11),%xmm14
++	movaps		0x60(%r11),%xmm15
++___
++$code.=<<___;
++	mov		0x280(%rsp),%rsp
++	ret
++.size	ChaCha20_8x,.-ChaCha20_8x
++___
++}
++
++foreach (split("\n",$code)) {
++	s/\`([^\`]*)\`/eval $1/geo;
++
++	s/%x#%y/%x/go;
++
++	print $_,"\n";
++}
++
++close STDOUT;
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/chacha/build.info b/CryptoPkg/Library/OpensslLib/openssl/crypto/chacha/build.info
+new file mode 100644
+index 0000000..f99114c
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/chacha/build.info
+@@ -0,0 +1,17 @@
++LIBS=../../libcrypto
++SOURCE[../../libcrypto]={- $target{chacha_asm_src} -}
++
++GENERATE[chacha-x86.s]=asm/chacha-x86.pl $(PERLASM_SCHEME) $(CFLAGS) $(LIB_CFLAGS) $(PROCESSOR)
++GENERATE[chacha-x86_64.s]=asm/chacha-x86_64.pl $(PERLASM_SCHEME)
++GENERATE[chacha-ppc.s]=asm/chacha-ppc.pl $(PERLASM_SCHEME)
++GENERATE[chacha-armv4.S]=asm/chacha-armv4.pl $(PERLASM_SCHEME)
++INCLUDE[chacha-armv4.o]=..
++GENERATE[chacha-armv8.S]=asm/chacha-armv8.pl $(PERLASM_SCHEME)
++INCLUDE[chacha-armv8.o]=..
++
++BEGINRAW[Makefile(unix)]
++##### CHACHA assembler implementations
++
++{- $builddir -}/chacha-%.S:	{- $sourcedir -}/asm/chacha-%.pl
++	CC="$(CC)" $(PERL) $< $(PERLASM_SCHEME) $@
++ENDRAW[Makefile(unix)]
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/chacha/chacha_enc.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/chacha/chacha_enc.c
+new file mode 100644
+index 0000000..239f68a
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/chacha/chacha_enc.c
+@@ -0,0 +1,121 @@
++/*
++ * Copyright 2015-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++/* Adapted from the public domain code by D. Bernstein from SUPERCOP. */
++
++#include 
++
++#include "internal/chacha.h"
++
++typedef unsigned int u32;
++typedef unsigned char u8;
++typedef union {
++    u32 u[16];
++    u8 c[64];
++} chacha_buf;
++
++# define ROTATE(v, n) (((v) << (n)) | ((v) >> (32 - (n))))
++
++# define U32TO8_LITTLE(p, v) do { \
++                                (p)[0] = (u8)(v >>  0); \
++                                (p)[1] = (u8)(v >>  8); \
++                                (p)[2] = (u8)(v >> 16); \
++                                (p)[3] = (u8)(v >> 24); \
++                                } while(0)
++
++/* QUARTERROUND updates a, b, c, d with a ChaCha "quarter" round. */
++# define QUARTERROUND(a,b,c,d) ( \
++                x[a] += x[b], x[d] = ROTATE((x[d] ^ x[a]),16), \
++                x[c] += x[d], x[b] = ROTATE((x[b] ^ x[c]),12), \
++                x[a] += x[b], x[d] = ROTATE((x[d] ^ x[a]), 8), \
++                x[c] += x[d], x[b] = ROTATE((x[b] ^ x[c]), 7)  )
++
++/* chacha_core performs 20 rounds of ChaCha on the input words in
++ * |input| and writes the 64 output bytes to |output|. */
++static void chacha20_core(chacha_buf *output, const u32 input[16])
++{
++    u32 x[16];
++    int i;
++    const union {
++        long one;
++        char little;
++    } is_endian = { 1 };
++
++    memcpy(x, input, sizeof(x));
++
++    for (i = 20; i > 0; i -= 2) {
++        QUARTERROUND(0, 4, 8, 12);
++        QUARTERROUND(1, 5, 9, 13);
++        QUARTERROUND(2, 6, 10, 14);
++        QUARTERROUND(3, 7, 11, 15);
++        QUARTERROUND(0, 5, 10, 15);
++        QUARTERROUND(1, 6, 11, 12);
++        QUARTERROUND(2, 7, 8, 13);
++        QUARTERROUND(3, 4, 9, 14);
++    }
++
++    if (is_endian.little) {
++        for (i = 0; i < 16; ++i)
++            output->u[i] = x[i] + input[i];
++    } else {
++        for (i = 0; i < 16; ++i)
++            U32TO8_LITTLE(output->c + 4 * i, (x[i] + input[i]));
++    }
++}
++
++void ChaCha20_ctr32(unsigned char *out, const unsigned char *inp,
++                    size_t len, const unsigned int key[8],
++                    const unsigned int counter[4])
++{
++    u32 input[16];
++    chacha_buf buf;
++    size_t todo, i;
++
++    /* sigma constant "expand 32-byte k" in little-endian encoding */
++    input[0] = ((u32)'e') | ((u32)'x'<<8) | ((u32)'p'<<16) | ((u32)'a'<<24);
++    input[1] = ((u32)'n') | ((u32)'d'<<8) | ((u32)' '<<16) | ((u32)'3'<<24);
++    input[2] = ((u32)'2') | ((u32)'-'<<8) | ((u32)'b'<<16) | ((u32)'y'<<24);
++    input[3] = ((u32)'t') | ((u32)'e'<<8) | ((u32)' '<<16) | ((u32)'k'<<24);
++
++    input[4] = key[0];
++    input[5] = key[1];
++    input[6] = key[2];
++    input[7] = key[3];
++    input[8] = key[4];
++    input[9] = key[5];
++    input[10] = key[6];
++    input[11] = key[7];
++
++    input[12] = counter[0];
++    input[13] = counter[1];
++    input[14] = counter[2];
++    input[15] = counter[3];
++
++    while (len > 0) {
++        todo = sizeof(buf);
++        if (len < todo)
++            todo = len;
++
++        chacha20_core(&buf, input);
++
++        for (i = 0; i < todo; i++)
++            out[i] = inp[i] ^ buf.c[i];
++        out += todo;
++        inp += todo;
++        len -= todo;
++
++        /*
++         * Advance 32-bit counter. Note that as subroutine is so to
++         * say nonce-agnostic, this limited counter width doesn't
++         * prevent caller from implementing wider counter. It would
++         * simply take two calls split on counter overflow...
++         */
++        input[12]++;
++    }
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/cmac/build.info b/CryptoPkg/Library/OpensslLib/openssl/crypto/cmac/build.info
+new file mode 100644
+index 0000000..c8a4949
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/cmac/build.info
+@@ -0,0 +1,2 @@
++LIBS=../../libcrypto
++SOURCE[../../libcrypto]=cmac.c cm_ameth.c cm_pmeth.c
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/cmac/cm_ameth.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/cmac/cm_ameth.c
+new file mode 100644
+index 0000000..a58454a
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/cmac/cm_ameth.c
+@@ -0,0 +1,51 @@
++/*
++ * Copyright 2010-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include "internal/cryptlib.h"
++#include 
++#include 
++#include "internal/asn1_int.h"
++
++/*
++ * CMAC "ASN1" method. This is just here to indicate the maximum CMAC output
++ * length and to free up a CMAC key.
++ */
++
++static int cmac_size(const EVP_PKEY *pkey)
++{
++    return EVP_MAX_BLOCK_LENGTH;
++}
++
++static void cmac_key_free(EVP_PKEY *pkey)
++{
++    CMAC_CTX *cmctx = EVP_PKEY_get0(pkey);
++    CMAC_CTX_free(cmctx);
++}
++
++const EVP_PKEY_ASN1_METHOD cmac_asn1_meth = {
++    EVP_PKEY_CMAC,
++    EVP_PKEY_CMAC,
++    0,
++
++    "CMAC",
++    "OpenSSL CMAC method",
++
++    0, 0, 0, 0,
++
++    0, 0, 0,
++
++    cmac_size,
++    0, 0,
++    0, 0, 0, 0, 0, 0, 0,
++
++    cmac_key_free,
++    0,
++    0, 0
++};
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/cmac/cm_pmeth.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/cmac/cm_pmeth.c
+new file mode 100644
+index 0000000..10748f1
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/cmac/cm_pmeth.c
+@@ -0,0 +1,161 @@
++/*
++ * Copyright 2010-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include "internal/cryptlib.h"
++#include 
++#include 
++#include 
++#include 
++#include "internal/evp_int.h"
++
++/* The context structure and "key" is simply a CMAC_CTX */
++
++static int pkey_cmac_init(EVP_PKEY_CTX *ctx)
++{
++    ctx->data = CMAC_CTX_new();
++    if (ctx->data == NULL)
++        return 0;
++    ctx->keygen_info_count = 0;
++    return 1;
++}
++
++static int pkey_cmac_copy(EVP_PKEY_CTX *dst, EVP_PKEY_CTX *src)
++{
++    if (!pkey_cmac_init(dst))
++        return 0;
++    if (!CMAC_CTX_copy(dst->data, src->data))
++        return 0;
++    return 1;
++}
++
++static void pkey_cmac_cleanup(EVP_PKEY_CTX *ctx)
++{
++    CMAC_CTX_free(ctx->data);
++}
++
++static int pkey_cmac_keygen(EVP_PKEY_CTX *ctx, EVP_PKEY *pkey)
++{
++    CMAC_CTX *cmkey = CMAC_CTX_new();
++    CMAC_CTX *cmctx = ctx->data;
++    if (cmkey == NULL)
++        return 0;
++    if (!CMAC_CTX_copy(cmkey, cmctx)) {
++        CMAC_CTX_free(cmkey);
++        return 0;
++    }
++    EVP_PKEY_assign(pkey, EVP_PKEY_CMAC, cmkey);
++
++    return 1;
++}
++
++static int int_update(EVP_MD_CTX *ctx, const void *data, size_t count)
++{
++    if (!CMAC_Update(EVP_MD_CTX_pkey_ctx(ctx)->data, data, count))
++        return 0;
++    return 1;
++}
++
++static int cmac_signctx_init(EVP_PKEY_CTX *ctx, EVP_MD_CTX *mctx)
++{
++    EVP_MD_CTX_set_flags(mctx, EVP_MD_CTX_FLAG_NO_INIT);
++    EVP_MD_CTX_set_update_fn(mctx, int_update);
++    return 1;
++}
++
++static int cmac_signctx(EVP_PKEY_CTX *ctx, unsigned char *sig, size_t *siglen,
++                        EVP_MD_CTX *mctx)
++{
++    return CMAC_Final(ctx->data, sig, siglen);
++}
++
++static int pkey_cmac_ctrl(EVP_PKEY_CTX *ctx, int type, int p1, void *p2)
++{
++    CMAC_CTX *cmctx = ctx->data;
++    switch (type) {
++
++    case EVP_PKEY_CTRL_SET_MAC_KEY:
++        if (!p2 || p1 < 0)
++            return 0;
++        if (!CMAC_Init(cmctx, p2, p1, NULL, NULL))
++            return 0;
++        break;
++
++    case EVP_PKEY_CTRL_CIPHER:
++        if (!CMAC_Init(cmctx, NULL, 0, p2, ctx->engine))
++            return 0;
++        break;
++
++    case EVP_PKEY_CTRL_MD:
++        if (ctx->pkey && !CMAC_CTX_copy(ctx->data,
++                                        (CMAC_CTX *)ctx->pkey->pkey.ptr))
++            return 0;
++        if (!CMAC_Init(cmctx, NULL, 0, NULL, NULL))
++            return 0;
++        break;
++
++    default:
++        return -2;
++
++    }
++    return 1;
++}
++
++static int pkey_cmac_ctrl_str(EVP_PKEY_CTX *ctx,
++                              const char *type, const char *value)
++{
++    if (!value) {
++        return 0;
++    }
++    if (strcmp(type, "cipher") == 0) {
++        const EVP_CIPHER *c;
++        c = EVP_get_cipherbyname(value);
++        if (!c)
++            return 0;
++        return pkey_cmac_ctrl(ctx, EVP_PKEY_CTRL_CIPHER, -1, (void *)c);
++    }
++    if (strcmp(type, "key") == 0)
++        return EVP_PKEY_CTX_str2ctrl(ctx, EVP_PKEY_CTRL_SET_MAC_KEY, value);
++    if (strcmp(type, "hexkey") == 0)
++        return EVP_PKEY_CTX_hex2ctrl(ctx, EVP_PKEY_CTRL_SET_MAC_KEY, value);
++    return -2;
++}
++
++const EVP_PKEY_METHOD cmac_pkey_meth = {
++    EVP_PKEY_CMAC,
++    EVP_PKEY_FLAG_SIGCTX_CUSTOM,
++    pkey_cmac_init,
++    pkey_cmac_copy,
++    pkey_cmac_cleanup,
++
++    0, 0,
++
++    0,
++    pkey_cmac_keygen,
++
++    0, 0,
++
++    0, 0,
++
++    0, 0,
++
++    cmac_signctx_init,
++    cmac_signctx,
++
++    0, 0,
++
++    0, 0,
++
++    0, 0,
++
++    0, 0,
++
++    pkey_cmac_ctrl,
++    pkey_cmac_ctrl_str
++};
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/cmac/cmac.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/cmac/cmac.c
+new file mode 100644
+index 0000000..c4f13a0
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/cmac/cmac.c
+@@ -0,0 +1,223 @@
++/*
++ * Copyright 2010-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include 
++#include 
++#include "internal/cryptlib.h"
++#include 
++
++struct CMAC_CTX_st {
++    /* Cipher context to use */
++    EVP_CIPHER_CTX *cctx;
++    /* Keys k1 and k2 */
++    unsigned char k1[EVP_MAX_BLOCK_LENGTH];
++    unsigned char k2[EVP_MAX_BLOCK_LENGTH];
++    /* Temporary block */
++    unsigned char tbl[EVP_MAX_BLOCK_LENGTH];
++    /* Last (possibly partial) block */
++    unsigned char last_block[EVP_MAX_BLOCK_LENGTH];
++    /* Number of bytes in last block: -1 means context not initialised */
++    int nlast_block;
++};
++
++/* Make temporary keys K1 and K2 */
++
++static void make_kn(unsigned char *k1, const unsigned char *l, int bl)
++{
++    int i;
++    unsigned char c = l[0], carry = c >> 7, cnext;
++
++    /* Shift block to left, including carry */
++    for (i = 0; i < bl - 1; i++, c = cnext)
++        k1[i] = (c << 1) | ((cnext = l[i + 1]) >> 7);
++
++    /* If MSB set fixup with R */
++    k1[i] = (c << 1) ^ ((0 - carry) & (bl == 16 ? 0x87 : 0x1b));
++}
++
++CMAC_CTX *CMAC_CTX_new(void)
++{
++    CMAC_CTX *ctx;
++
++    ctx = OPENSSL_malloc(sizeof(*ctx));
++    if (ctx == NULL)
++        return NULL;
++    ctx->cctx = EVP_CIPHER_CTX_new();
++    if (ctx->cctx == NULL) {
++        OPENSSL_free(ctx);
++        return NULL;
++    }
++    ctx->nlast_block = -1;
++    return ctx;
++}
++
++void CMAC_CTX_cleanup(CMAC_CTX *ctx)
++{
++    EVP_CIPHER_CTX_free(ctx->cctx);
++    OPENSSL_cleanse(ctx->tbl, EVP_MAX_BLOCK_LENGTH);
++    OPENSSL_cleanse(ctx->k1, EVP_MAX_BLOCK_LENGTH);
++    OPENSSL_cleanse(ctx->k2, EVP_MAX_BLOCK_LENGTH);
++    OPENSSL_cleanse(ctx->last_block, EVP_MAX_BLOCK_LENGTH);
++    ctx->nlast_block = -1;
++}
++
++EVP_CIPHER_CTX *CMAC_CTX_get0_cipher_ctx(CMAC_CTX *ctx)
++{
++    return ctx->cctx;
++}
++
++void CMAC_CTX_free(CMAC_CTX *ctx)
++{
++    if (!ctx)
++        return;
++    CMAC_CTX_cleanup(ctx);
++    OPENSSL_free(ctx);
++}
++
++int CMAC_CTX_copy(CMAC_CTX *out, const CMAC_CTX *in)
++{
++    int bl;
++    if (in->nlast_block == -1)
++        return 0;
++    if (!EVP_CIPHER_CTX_copy(out->cctx, in->cctx))
++        return 0;
++    bl = EVP_CIPHER_CTX_block_size(in->cctx);
++    memcpy(out->k1, in->k1, bl);
++    memcpy(out->k2, in->k2, bl);
++    memcpy(out->tbl, in->tbl, bl);
++    memcpy(out->last_block, in->last_block, bl);
++    out->nlast_block = in->nlast_block;
++    return 1;
++}
++
++int CMAC_Init(CMAC_CTX *ctx, const void *key, size_t keylen,
++              const EVP_CIPHER *cipher, ENGINE *impl)
++{
++    static const unsigned char zero_iv[EVP_MAX_BLOCK_LENGTH] = { 0 };
++    /* All zeros means restart */
++    if (!key && !cipher && !impl && keylen == 0) {
++        /* Not initialised */
++        if (ctx->nlast_block == -1)
++            return 0;
++        if (!EVP_EncryptInit_ex(ctx->cctx, NULL, NULL, NULL, zero_iv))
++            return 0;
++        memset(ctx->tbl, 0, EVP_CIPHER_CTX_block_size(ctx->cctx));
++        ctx->nlast_block = 0;
++        return 1;
++    }
++    /* Initialise context */
++    if (cipher && !EVP_EncryptInit_ex(ctx->cctx, cipher, impl, NULL, NULL))
++        return 0;
++    /* Non-NULL key means initialisation complete */
++    if (key) {
++        int bl;
++        if (!EVP_CIPHER_CTX_cipher(ctx->cctx))
++            return 0;
++        if (!EVP_CIPHER_CTX_set_key_length(ctx->cctx, keylen))
++            return 0;
++        if (!EVP_EncryptInit_ex(ctx->cctx, NULL, NULL, key, zero_iv))
++            return 0;
++        bl = EVP_CIPHER_CTX_block_size(ctx->cctx);
++        if (!EVP_Cipher(ctx->cctx, ctx->tbl, zero_iv, bl))
++            return 0;
++        make_kn(ctx->k1, ctx->tbl, bl);
++        make_kn(ctx->k2, ctx->k1, bl);
++        OPENSSL_cleanse(ctx->tbl, bl);
++        /* Reset context again ready for first data block */
++        if (!EVP_EncryptInit_ex(ctx->cctx, NULL, NULL, NULL, zero_iv))
++            return 0;
++        /* Zero tbl so resume works */
++        memset(ctx->tbl, 0, bl);
++        ctx->nlast_block = 0;
++    }
++    return 1;
++}
++
++int CMAC_Update(CMAC_CTX *ctx, const void *in, size_t dlen)
++{
++    const unsigned char *data = in;
++    size_t bl;
++    if (ctx->nlast_block == -1)
++        return 0;
++    if (dlen == 0)
++        return 1;
++    bl = EVP_CIPHER_CTX_block_size(ctx->cctx);
++    /* Copy into partial block if we need to */
++    if (ctx->nlast_block > 0) {
++        size_t nleft;
++        nleft = bl - ctx->nlast_block;
++        if (dlen < nleft)
++            nleft = dlen;
++        memcpy(ctx->last_block + ctx->nlast_block, data, nleft);
++        dlen -= nleft;
++        ctx->nlast_block += nleft;
++        /* If no more to process return */
++        if (dlen == 0)
++            return 1;
++        data += nleft;
++        /* Else not final block so encrypt it */
++        if (!EVP_Cipher(ctx->cctx, ctx->tbl, ctx->last_block, bl))
++            return 0;
++    }
++    /* Encrypt all but one of the complete blocks left */
++    while (dlen > bl) {
++        if (!EVP_Cipher(ctx->cctx, ctx->tbl, data, bl))
++            return 0;
++        dlen -= bl;
++        data += bl;
++    }
++    /* Copy any data left to last block buffer */
++    memcpy(ctx->last_block, data, dlen);
++    ctx->nlast_block = dlen;
++    return 1;
++
++}
++
++int CMAC_Final(CMAC_CTX *ctx, unsigned char *out, size_t *poutlen)
++{
++    int i, bl, lb;
++    if (ctx->nlast_block == -1)
++        return 0;
++    bl = EVP_CIPHER_CTX_block_size(ctx->cctx);
++    *poutlen = (size_t)bl;
++    if (!out)
++        return 1;
++    lb = ctx->nlast_block;
++    /* Is last block complete? */
++    if (lb == bl) {
++        for (i = 0; i < bl; i++)
++            out[i] = ctx->last_block[i] ^ ctx->k1[i];
++    } else {
++        ctx->last_block[lb] = 0x80;
++        if (bl - lb > 1)
++            memset(ctx->last_block + lb + 1, 0, bl - lb - 1);
++        for (i = 0; i < bl; i++)
++            out[i] = ctx->last_block[i] ^ ctx->k2[i];
++    }
++    if (!EVP_Cipher(ctx->cctx, out, out, bl)) {
++        OPENSSL_cleanse(out, bl);
++        return 0;
++    }
++    return 1;
++}
++
++int CMAC_resume(CMAC_CTX *ctx)
++{
++    if (ctx->nlast_block == -1)
++        return 0;
++    /*
++     * The buffer "tbl" contains the last fully encrypted block which is the
++     * last IV (or all zeroes if no last encrypted block). The last block has
++     * not been modified since CMAC_final(). So reinitialising using the last
++     * decrypted block will allow CMAC to continue after calling
++     * CMAC_Final().
++     */
++    return EVP_EncryptInit_ex(ctx->cctx, NULL, NULL, NULL, ctx->tbl);
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/cms/build.info b/CryptoPkg/Library/OpensslLib/openssl/crypto/cms/build.info
+new file mode 100644
+index 0000000..cb67543
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/cms/build.info
+@@ -0,0 +1,5 @@
++LIBS=../../libcrypto
++SOURCE[../../libcrypto]= \
++        cms_lib.c cms_asn1.c cms_att.c cms_io.c cms_smime.c cms_err.c \
++        cms_sd.c cms_dd.c cms_cd.c cms_env.c cms_enc.c cms_ess.c \
++        cms_pwri.c cms_kari.c
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/cms/cms_asn1.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/cms/cms_asn1.c
+new file mode 100644
+index 0000000..81e9a53
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/cms/cms_asn1.c
+@@ -0,0 +1,402 @@
++/*
++ * Copyright 2008-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include 
++#include 
++#include 
++#include "cms_lcl.h"
++
++
++ASN1_SEQUENCE(CMS_IssuerAndSerialNumber) = {
++        ASN1_SIMPLE(CMS_IssuerAndSerialNumber, issuer, X509_NAME),
++        ASN1_SIMPLE(CMS_IssuerAndSerialNumber, serialNumber, ASN1_INTEGER)
++} ASN1_SEQUENCE_END(CMS_IssuerAndSerialNumber)
++
++ASN1_SEQUENCE(CMS_OtherCertificateFormat) = {
++        ASN1_SIMPLE(CMS_OtherCertificateFormat, otherCertFormat, ASN1_OBJECT),
++        ASN1_OPT(CMS_OtherCertificateFormat, otherCert, ASN1_ANY)
++} static_ASN1_SEQUENCE_END(CMS_OtherCertificateFormat)
++
++ASN1_CHOICE(CMS_CertificateChoices) = {
++        ASN1_SIMPLE(CMS_CertificateChoices, d.certificate, X509),
++        ASN1_IMP(CMS_CertificateChoices, d.extendedCertificate, ASN1_SEQUENCE, 0),
++        ASN1_IMP(CMS_CertificateChoices, d.v1AttrCert, ASN1_SEQUENCE, 1),
++        ASN1_IMP(CMS_CertificateChoices, d.v2AttrCert, ASN1_SEQUENCE, 2),
++        ASN1_IMP(CMS_CertificateChoices, d.other, CMS_OtherCertificateFormat, 3)
++} ASN1_CHOICE_END(CMS_CertificateChoices)
++
++ASN1_CHOICE(CMS_SignerIdentifier) = {
++        ASN1_SIMPLE(CMS_SignerIdentifier, d.issuerAndSerialNumber, CMS_IssuerAndSerialNumber),
++        ASN1_IMP(CMS_SignerIdentifier, d.subjectKeyIdentifier, ASN1_OCTET_STRING, 0)
++} static_ASN1_CHOICE_END(CMS_SignerIdentifier)
++
++ASN1_NDEF_SEQUENCE(CMS_EncapsulatedContentInfo) = {
++        ASN1_SIMPLE(CMS_EncapsulatedContentInfo, eContentType, ASN1_OBJECT),
++        ASN1_NDEF_EXP_OPT(CMS_EncapsulatedContentInfo, eContent, ASN1_OCTET_STRING_NDEF, 0)
++} static_ASN1_NDEF_SEQUENCE_END(CMS_EncapsulatedContentInfo)
++
++/* Minor tweak to operation: free up signer key, cert */
++static int cms_si_cb(int operation, ASN1_VALUE **pval, const ASN1_ITEM *it,
++                     void *exarg)
++{
++    if (operation == ASN1_OP_FREE_POST) {
++        CMS_SignerInfo *si = (CMS_SignerInfo *)*pval;
++        EVP_PKEY_free(si->pkey);
++        X509_free(si->signer);
++        EVP_MD_CTX_free(si->mctx);
++    }
++    return 1;
++}
++
++ASN1_SEQUENCE_cb(CMS_SignerInfo, cms_si_cb) = {
++        ASN1_SIMPLE(CMS_SignerInfo, version, LONG),
++        ASN1_SIMPLE(CMS_SignerInfo, sid, CMS_SignerIdentifier),
++        ASN1_SIMPLE(CMS_SignerInfo, digestAlgorithm, X509_ALGOR),
++        ASN1_IMP_SET_OF_OPT(CMS_SignerInfo, signedAttrs, X509_ATTRIBUTE, 0),
++        ASN1_SIMPLE(CMS_SignerInfo, signatureAlgorithm, X509_ALGOR),
++        ASN1_SIMPLE(CMS_SignerInfo, signature, ASN1_OCTET_STRING),
++        ASN1_IMP_SET_OF_OPT(CMS_SignerInfo, unsignedAttrs, X509_ATTRIBUTE, 1)
++} ASN1_SEQUENCE_END_cb(CMS_SignerInfo, CMS_SignerInfo)
++
++ASN1_SEQUENCE(CMS_OtherRevocationInfoFormat) = {
++        ASN1_SIMPLE(CMS_OtherRevocationInfoFormat, otherRevInfoFormat, ASN1_OBJECT),
++        ASN1_OPT(CMS_OtherRevocationInfoFormat, otherRevInfo, ASN1_ANY)
++} static_ASN1_SEQUENCE_END(CMS_OtherRevocationInfoFormat)
++
++ASN1_CHOICE(CMS_RevocationInfoChoice) = {
++        ASN1_SIMPLE(CMS_RevocationInfoChoice, d.crl, X509_CRL),
++        ASN1_IMP(CMS_RevocationInfoChoice, d.other, CMS_OtherRevocationInfoFormat, 1)
++} ASN1_CHOICE_END(CMS_RevocationInfoChoice)
++
++ASN1_NDEF_SEQUENCE(CMS_SignedData) = {
++        ASN1_SIMPLE(CMS_SignedData, version, LONG),
++        ASN1_SET_OF(CMS_SignedData, digestAlgorithms, X509_ALGOR),
++        ASN1_SIMPLE(CMS_SignedData, encapContentInfo, CMS_EncapsulatedContentInfo),
++        ASN1_IMP_SET_OF_OPT(CMS_SignedData, certificates, CMS_CertificateChoices, 0),
++        ASN1_IMP_SET_OF_OPT(CMS_SignedData, crls, CMS_RevocationInfoChoice, 1),
++        ASN1_SET_OF(CMS_SignedData, signerInfos, CMS_SignerInfo)
++} ASN1_NDEF_SEQUENCE_END(CMS_SignedData)
++
++ASN1_SEQUENCE(CMS_OriginatorInfo) = {
++        ASN1_IMP_SET_OF_OPT(CMS_OriginatorInfo, certificates, CMS_CertificateChoices, 0),
++        ASN1_IMP_SET_OF_OPT(CMS_OriginatorInfo, crls, CMS_RevocationInfoChoice, 1)
++} static_ASN1_SEQUENCE_END(CMS_OriginatorInfo)
++
++ASN1_NDEF_SEQUENCE(CMS_EncryptedContentInfo) = {
++        ASN1_SIMPLE(CMS_EncryptedContentInfo, contentType, ASN1_OBJECT),
++        ASN1_SIMPLE(CMS_EncryptedContentInfo, contentEncryptionAlgorithm, X509_ALGOR),
++        ASN1_IMP_OPT(CMS_EncryptedContentInfo, encryptedContent, ASN1_OCTET_STRING_NDEF, 0)
++} static_ASN1_NDEF_SEQUENCE_END(CMS_EncryptedContentInfo)
++
++ASN1_SEQUENCE(CMS_KeyTransRecipientInfo) = {
++        ASN1_SIMPLE(CMS_KeyTransRecipientInfo, version, LONG),
++        ASN1_SIMPLE(CMS_KeyTransRecipientInfo, rid, CMS_SignerIdentifier),
++        ASN1_SIMPLE(CMS_KeyTransRecipientInfo, keyEncryptionAlgorithm, X509_ALGOR),
++        ASN1_SIMPLE(CMS_KeyTransRecipientInfo, encryptedKey, ASN1_OCTET_STRING)
++} ASN1_SEQUENCE_END(CMS_KeyTransRecipientInfo)
++
++ASN1_SEQUENCE(CMS_OtherKeyAttribute) = {
++        ASN1_SIMPLE(CMS_OtherKeyAttribute, keyAttrId, ASN1_OBJECT),
++        ASN1_OPT(CMS_OtherKeyAttribute, keyAttr, ASN1_ANY)
++} ASN1_SEQUENCE_END(CMS_OtherKeyAttribute)
++
++ASN1_SEQUENCE(CMS_RecipientKeyIdentifier) = {
++        ASN1_SIMPLE(CMS_RecipientKeyIdentifier, subjectKeyIdentifier, ASN1_OCTET_STRING),
++        ASN1_OPT(CMS_RecipientKeyIdentifier, date, ASN1_GENERALIZEDTIME),
++        ASN1_OPT(CMS_RecipientKeyIdentifier, other, CMS_OtherKeyAttribute)
++} ASN1_SEQUENCE_END(CMS_RecipientKeyIdentifier)
++
++ASN1_CHOICE(CMS_KeyAgreeRecipientIdentifier) = {
++  ASN1_SIMPLE(CMS_KeyAgreeRecipientIdentifier, d.issuerAndSerialNumber, CMS_IssuerAndSerialNumber),
++  ASN1_IMP(CMS_KeyAgreeRecipientIdentifier, d.rKeyId, CMS_RecipientKeyIdentifier, 0)
++} static_ASN1_CHOICE_END(CMS_KeyAgreeRecipientIdentifier)
++
++static int cms_rek_cb(int operation, ASN1_VALUE **pval, const ASN1_ITEM *it,
++                      void *exarg)
++{
++    CMS_RecipientEncryptedKey *rek = (CMS_RecipientEncryptedKey *)*pval;
++    if (operation == ASN1_OP_FREE_POST) {
++        EVP_PKEY_free(rek->pkey);
++    }
++    return 1;
++}
++
++ASN1_SEQUENCE_cb(CMS_RecipientEncryptedKey, cms_rek_cb) = {
++        ASN1_SIMPLE(CMS_RecipientEncryptedKey, rid, CMS_KeyAgreeRecipientIdentifier),
++        ASN1_SIMPLE(CMS_RecipientEncryptedKey, encryptedKey, ASN1_OCTET_STRING)
++} ASN1_SEQUENCE_END_cb(CMS_RecipientEncryptedKey, CMS_RecipientEncryptedKey)
++
++ASN1_SEQUENCE(CMS_OriginatorPublicKey) = {
++  ASN1_SIMPLE(CMS_OriginatorPublicKey, algorithm, X509_ALGOR),
++  ASN1_SIMPLE(CMS_OriginatorPublicKey, publicKey, ASN1_BIT_STRING)
++} ASN1_SEQUENCE_END(CMS_OriginatorPublicKey)
++
++ASN1_CHOICE(CMS_OriginatorIdentifierOrKey) = {
++  ASN1_SIMPLE(CMS_OriginatorIdentifierOrKey, d.issuerAndSerialNumber, CMS_IssuerAndSerialNumber),
++  ASN1_IMP(CMS_OriginatorIdentifierOrKey, d.subjectKeyIdentifier, ASN1_OCTET_STRING, 0),
++  ASN1_IMP(CMS_OriginatorIdentifierOrKey, d.originatorKey, CMS_OriginatorPublicKey, 1)
++} static_ASN1_CHOICE_END(CMS_OriginatorIdentifierOrKey)
++
++static int cms_kari_cb(int operation, ASN1_VALUE **pval, const ASN1_ITEM *it,
++                       void *exarg)
++{
++    CMS_KeyAgreeRecipientInfo *kari = (CMS_KeyAgreeRecipientInfo *)*pval;
++    if (operation == ASN1_OP_NEW_POST) {
++        kari->ctx = EVP_CIPHER_CTX_new();
++        if (kari->ctx == NULL)
++            return 0;
++        EVP_CIPHER_CTX_set_flags(kari->ctx, EVP_CIPHER_CTX_FLAG_WRAP_ALLOW);
++        kari->pctx = NULL;
++    } else if (operation == ASN1_OP_FREE_POST) {
++        EVP_PKEY_CTX_free(kari->pctx);
++        EVP_CIPHER_CTX_free(kari->ctx);
++    }
++    return 1;
++}
++
++ASN1_SEQUENCE_cb(CMS_KeyAgreeRecipientInfo, cms_kari_cb) = {
++        ASN1_SIMPLE(CMS_KeyAgreeRecipientInfo, version, LONG),
++        ASN1_EXP(CMS_KeyAgreeRecipientInfo, originator, CMS_OriginatorIdentifierOrKey, 0),
++        ASN1_EXP_OPT(CMS_KeyAgreeRecipientInfo, ukm, ASN1_OCTET_STRING, 1),
++        ASN1_SIMPLE(CMS_KeyAgreeRecipientInfo, keyEncryptionAlgorithm, X509_ALGOR),
++        ASN1_SEQUENCE_OF(CMS_KeyAgreeRecipientInfo, recipientEncryptedKeys, CMS_RecipientEncryptedKey)
++} ASN1_SEQUENCE_END_cb(CMS_KeyAgreeRecipientInfo, CMS_KeyAgreeRecipientInfo)
++
++ASN1_SEQUENCE(CMS_KEKIdentifier) = {
++        ASN1_SIMPLE(CMS_KEKIdentifier, keyIdentifier, ASN1_OCTET_STRING),
++        ASN1_OPT(CMS_KEKIdentifier, date, ASN1_GENERALIZEDTIME),
++        ASN1_OPT(CMS_KEKIdentifier, other, CMS_OtherKeyAttribute)
++} static_ASN1_SEQUENCE_END(CMS_KEKIdentifier)
++
++ASN1_SEQUENCE(CMS_KEKRecipientInfo) = {
++        ASN1_SIMPLE(CMS_KEKRecipientInfo, version, LONG),
++        ASN1_SIMPLE(CMS_KEKRecipientInfo, kekid, CMS_KEKIdentifier),
++        ASN1_SIMPLE(CMS_KEKRecipientInfo, keyEncryptionAlgorithm, X509_ALGOR),
++        ASN1_SIMPLE(CMS_KEKRecipientInfo, encryptedKey, ASN1_OCTET_STRING)
++} ASN1_SEQUENCE_END(CMS_KEKRecipientInfo)
++
++ASN1_SEQUENCE(CMS_PasswordRecipientInfo) = {
++        ASN1_SIMPLE(CMS_PasswordRecipientInfo, version, LONG),
++        ASN1_IMP_OPT(CMS_PasswordRecipientInfo, keyDerivationAlgorithm, X509_ALGOR, 0),
++        ASN1_SIMPLE(CMS_PasswordRecipientInfo, keyEncryptionAlgorithm, X509_ALGOR),
++        ASN1_SIMPLE(CMS_PasswordRecipientInfo, encryptedKey, ASN1_OCTET_STRING)
++} ASN1_SEQUENCE_END(CMS_PasswordRecipientInfo)
++
++ASN1_SEQUENCE(CMS_OtherRecipientInfo) = {
++  ASN1_SIMPLE(CMS_OtherRecipientInfo, oriType, ASN1_OBJECT),
++  ASN1_OPT(CMS_OtherRecipientInfo, oriValue, ASN1_ANY)
++} static_ASN1_SEQUENCE_END(CMS_OtherRecipientInfo)
++
++/* Free up RecipientInfo additional data */
++static int cms_ri_cb(int operation, ASN1_VALUE **pval, const ASN1_ITEM *it,
++                     void *exarg)
++{
++    if (operation == ASN1_OP_FREE_PRE) {
++        CMS_RecipientInfo *ri = (CMS_RecipientInfo *)*pval;
++        if (ri->type == CMS_RECIPINFO_TRANS) {
++            CMS_KeyTransRecipientInfo *ktri = ri->d.ktri;
++            EVP_PKEY_free(ktri->pkey);
++            X509_free(ktri->recip);
++            EVP_PKEY_CTX_free(ktri->pctx);
++        } else if (ri->type == CMS_RECIPINFO_KEK) {
++            CMS_KEKRecipientInfo *kekri = ri->d.kekri;
++            OPENSSL_clear_free(kekri->key, kekri->keylen);
++        } else if (ri->type == CMS_RECIPINFO_PASS) {
++            CMS_PasswordRecipientInfo *pwri = ri->d.pwri;
++            OPENSSL_clear_free(pwri->pass, pwri->passlen);
++        }
++    }
++    return 1;
++}
++
++ASN1_CHOICE_cb(CMS_RecipientInfo, cms_ri_cb) = {
++        ASN1_SIMPLE(CMS_RecipientInfo, d.ktri, CMS_KeyTransRecipientInfo),
++        ASN1_IMP(CMS_RecipientInfo, d.kari, CMS_KeyAgreeRecipientInfo, 1),
++        ASN1_IMP(CMS_RecipientInfo, d.kekri, CMS_KEKRecipientInfo, 2),
++        ASN1_IMP(CMS_RecipientInfo, d.pwri, CMS_PasswordRecipientInfo, 3),
++        ASN1_IMP(CMS_RecipientInfo, d.ori, CMS_OtherRecipientInfo, 4)
++} ASN1_CHOICE_END_cb(CMS_RecipientInfo, CMS_RecipientInfo, type)
++
++ASN1_NDEF_SEQUENCE(CMS_EnvelopedData) = {
++        ASN1_SIMPLE(CMS_EnvelopedData, version, LONG),
++        ASN1_IMP_OPT(CMS_EnvelopedData, originatorInfo, CMS_OriginatorInfo, 0),
++        ASN1_SET_OF(CMS_EnvelopedData, recipientInfos, CMS_RecipientInfo),
++        ASN1_SIMPLE(CMS_EnvelopedData, encryptedContentInfo, CMS_EncryptedContentInfo),
++        ASN1_IMP_SET_OF_OPT(CMS_EnvelopedData, unprotectedAttrs, X509_ATTRIBUTE, 1)
++} ASN1_NDEF_SEQUENCE_END(CMS_EnvelopedData)
++
++ASN1_NDEF_SEQUENCE(CMS_DigestedData) = {
++        ASN1_SIMPLE(CMS_DigestedData, version, LONG),
++        ASN1_SIMPLE(CMS_DigestedData, digestAlgorithm, X509_ALGOR),
++        ASN1_SIMPLE(CMS_DigestedData, encapContentInfo, CMS_EncapsulatedContentInfo),
++        ASN1_SIMPLE(CMS_DigestedData, digest, ASN1_OCTET_STRING)
++} ASN1_NDEF_SEQUENCE_END(CMS_DigestedData)
++
++ASN1_NDEF_SEQUENCE(CMS_EncryptedData) = {
++        ASN1_SIMPLE(CMS_EncryptedData, version, LONG),
++        ASN1_SIMPLE(CMS_EncryptedData, encryptedContentInfo, CMS_EncryptedContentInfo),
++        ASN1_IMP_SET_OF_OPT(CMS_EncryptedData, unprotectedAttrs, X509_ATTRIBUTE, 1)
++} ASN1_NDEF_SEQUENCE_END(CMS_EncryptedData)
++
++ASN1_NDEF_SEQUENCE(CMS_AuthenticatedData) = {
++        ASN1_SIMPLE(CMS_AuthenticatedData, version, LONG),
++        ASN1_IMP_OPT(CMS_AuthenticatedData, originatorInfo, CMS_OriginatorInfo, 0),
++        ASN1_SET_OF(CMS_AuthenticatedData, recipientInfos, CMS_RecipientInfo),
++        ASN1_SIMPLE(CMS_AuthenticatedData, macAlgorithm, X509_ALGOR),
++        ASN1_IMP(CMS_AuthenticatedData, digestAlgorithm, X509_ALGOR, 1),
++        ASN1_SIMPLE(CMS_AuthenticatedData, encapContentInfo, CMS_EncapsulatedContentInfo),
++        ASN1_IMP_SET_OF_OPT(CMS_AuthenticatedData, authAttrs, X509_ALGOR, 2),
++        ASN1_SIMPLE(CMS_AuthenticatedData, mac, ASN1_OCTET_STRING),
++        ASN1_IMP_SET_OF_OPT(CMS_AuthenticatedData, unauthAttrs, X509_ALGOR, 3)
++} static_ASN1_NDEF_SEQUENCE_END(CMS_AuthenticatedData)
++
++ASN1_NDEF_SEQUENCE(CMS_CompressedData) = {
++        ASN1_SIMPLE(CMS_CompressedData, version, LONG),
++        ASN1_SIMPLE(CMS_CompressedData, compressionAlgorithm, X509_ALGOR),
++        ASN1_SIMPLE(CMS_CompressedData, encapContentInfo, CMS_EncapsulatedContentInfo),
++} ASN1_NDEF_SEQUENCE_END(CMS_CompressedData)
++
++/* This is the ANY DEFINED BY table for the top level ContentInfo structure */
++
++ASN1_ADB_TEMPLATE(cms_default) = ASN1_EXP(CMS_ContentInfo, d.other, ASN1_ANY, 0);
++
++ASN1_ADB(CMS_ContentInfo) = {
++        ADB_ENTRY(NID_pkcs7_data, ASN1_NDEF_EXP(CMS_ContentInfo, d.data, ASN1_OCTET_STRING_NDEF, 0)),
++        ADB_ENTRY(NID_pkcs7_signed, ASN1_NDEF_EXP(CMS_ContentInfo, d.signedData, CMS_SignedData, 0)),
++        ADB_ENTRY(NID_pkcs7_enveloped, ASN1_NDEF_EXP(CMS_ContentInfo, d.envelopedData, CMS_EnvelopedData, 0)),
++        ADB_ENTRY(NID_pkcs7_digest, ASN1_NDEF_EXP(CMS_ContentInfo, d.digestedData, CMS_DigestedData, 0)),
++        ADB_ENTRY(NID_pkcs7_encrypted, ASN1_NDEF_EXP(CMS_ContentInfo, d.encryptedData, CMS_EncryptedData, 0)),
++        ADB_ENTRY(NID_id_smime_ct_authData, ASN1_NDEF_EXP(CMS_ContentInfo, d.authenticatedData, CMS_AuthenticatedData, 0)),
++        ADB_ENTRY(NID_id_smime_ct_compressedData, ASN1_NDEF_EXP(CMS_ContentInfo, d.compressedData, CMS_CompressedData, 0)),
++} ASN1_ADB_END(CMS_ContentInfo, 0, contentType, 0, &cms_default_tt, NULL);
++
++/* CMS streaming support */
++static int cms_cb(int operation, ASN1_VALUE **pval, const ASN1_ITEM *it,
++                  void *exarg)
++{
++    ASN1_STREAM_ARG *sarg = exarg;
++    CMS_ContentInfo *cms = NULL;
++    if (pval)
++        cms = (CMS_ContentInfo *)*pval;
++    else
++        return 1;
++    switch (operation) {
++
++    case ASN1_OP_STREAM_PRE:
++        if (CMS_stream(&sarg->boundary, cms) <= 0)
++            return 0;
++    case ASN1_OP_DETACHED_PRE:
++        sarg->ndef_bio = CMS_dataInit(cms, sarg->out);
++        if (!sarg->ndef_bio)
++            return 0;
++        break;
++
++    case ASN1_OP_STREAM_POST:
++    case ASN1_OP_DETACHED_POST:
++        if (CMS_dataFinal(cms, sarg->ndef_bio) <= 0)
++            return 0;
++        break;
++
++    }
++    return 1;
++}
++
++ASN1_NDEF_SEQUENCE_cb(CMS_ContentInfo, cms_cb) = {
++        ASN1_SIMPLE(CMS_ContentInfo, contentType, ASN1_OBJECT),
++        ASN1_ADB_OBJECT(CMS_ContentInfo)
++} ASN1_NDEF_SEQUENCE_END_cb(CMS_ContentInfo, CMS_ContentInfo)
++
++/* Specials for signed attributes */
++
++/*
++ * When signing attributes we want to reorder them to match the sorted
++ * encoding.
++ */
++
++ASN1_ITEM_TEMPLATE(CMS_Attributes_Sign) =
++        ASN1_EX_TEMPLATE_TYPE(ASN1_TFLG_SET_ORDER, 0, CMS_ATTRIBUTES, X509_ATTRIBUTE)
++ASN1_ITEM_TEMPLATE_END(CMS_Attributes_Sign)
++
++/*
++ * When verifying attributes we need to use the received order. So we use
++ * SEQUENCE OF and tag it to SET OF
++ */
++
++ASN1_ITEM_TEMPLATE(CMS_Attributes_Verify) =
++        ASN1_EX_TEMPLATE_TYPE(ASN1_TFLG_SEQUENCE_OF | ASN1_TFLG_IMPTAG | ASN1_TFLG_UNIVERSAL,
++                                V_ASN1_SET, CMS_ATTRIBUTES, X509_ATTRIBUTE)
++ASN1_ITEM_TEMPLATE_END(CMS_Attributes_Verify)
++
++
++
++ASN1_CHOICE(CMS_ReceiptsFrom) = {
++  ASN1_IMP(CMS_ReceiptsFrom, d.allOrFirstTier, LONG, 0),
++  ASN1_IMP_SEQUENCE_OF(CMS_ReceiptsFrom, d.receiptList, GENERAL_NAMES, 1)
++} static_ASN1_CHOICE_END(CMS_ReceiptsFrom)
++
++ASN1_SEQUENCE(CMS_ReceiptRequest) = {
++  ASN1_SIMPLE(CMS_ReceiptRequest, signedContentIdentifier, ASN1_OCTET_STRING),
++  ASN1_SIMPLE(CMS_ReceiptRequest, receiptsFrom, CMS_ReceiptsFrom),
++  ASN1_SEQUENCE_OF(CMS_ReceiptRequest, receiptsTo, GENERAL_NAMES)
++} ASN1_SEQUENCE_END(CMS_ReceiptRequest)
++
++ASN1_SEQUENCE(CMS_Receipt) = {
++  ASN1_SIMPLE(CMS_Receipt, version, LONG),
++  ASN1_SIMPLE(CMS_Receipt, contentType, ASN1_OBJECT),
++  ASN1_SIMPLE(CMS_Receipt, signedContentIdentifier, ASN1_OCTET_STRING),
++  ASN1_SIMPLE(CMS_Receipt, originatorSignatureValue, ASN1_OCTET_STRING)
++} ASN1_SEQUENCE_END(CMS_Receipt)
++
++/*
++ * Utilities to encode the CMS_SharedInfo structure used during key
++ * derivation.
++ */
++
++typedef struct {
++    X509_ALGOR *keyInfo;
++    ASN1_OCTET_STRING *entityUInfo;
++    ASN1_OCTET_STRING *suppPubInfo;
++} CMS_SharedInfo;
++
++ASN1_SEQUENCE(CMS_SharedInfo) = {
++  ASN1_SIMPLE(CMS_SharedInfo, keyInfo, X509_ALGOR),
++  ASN1_EXP_OPT(CMS_SharedInfo, entityUInfo, ASN1_OCTET_STRING, 0),
++  ASN1_EXP_OPT(CMS_SharedInfo, suppPubInfo, ASN1_OCTET_STRING, 2),
++} static_ASN1_SEQUENCE_END(CMS_SharedInfo)
++
++int CMS_SharedInfo_encode(unsigned char **pder, X509_ALGOR *kekalg,
++                          ASN1_OCTET_STRING *ukm, int keylen)
++{
++    union {
++        CMS_SharedInfo *pecsi;
++        ASN1_VALUE *a;
++    } intsi = {
++        NULL
++    };
++
++    ASN1_OCTET_STRING oklen;
++    unsigned char kl[4];
++    CMS_SharedInfo ecsi;
++
++    keylen <<= 3;
++    kl[0] = (keylen >> 24) & 0xff;
++    kl[1] = (keylen >> 16) & 0xff;
++    kl[2] = (keylen >> 8) & 0xff;
++    kl[3] = keylen & 0xff;
++    oklen.length = 4;
++    oklen.data = kl;
++    oklen.type = V_ASN1_OCTET_STRING;
++    oklen.flags = 0;
++    ecsi.keyInfo = kekalg;
++    ecsi.entityUInfo = ukm;
++    ecsi.suppPubInfo = &oklen;
++    intsi.pecsi = &ecsi;
++    return ASN1_item_i2d(intsi.a, pder, ASN1_ITEM_rptr(CMS_SharedInfo));
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/cms/cms_att.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/cms/cms_att.c
+new file mode 100644
+index 0000000..664e649
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/cms/cms_att.c
+@@ -0,0 +1,152 @@
++/*
++ * Copyright 2008-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include 
++#include 
++#include 
++#include 
++#include "cms_lcl.h"
++
++/* CMS SignedData Attribute utilities */
++
++int CMS_signed_get_attr_count(const CMS_SignerInfo *si)
++{
++    return X509at_get_attr_count(si->signedAttrs);
++}
++
++int CMS_signed_get_attr_by_NID(const CMS_SignerInfo *si, int nid, int lastpos)
++{
++    return X509at_get_attr_by_NID(si->signedAttrs, nid, lastpos);
++}
++
++int CMS_signed_get_attr_by_OBJ(const CMS_SignerInfo *si, const ASN1_OBJECT *obj,
++                               int lastpos)
++{
++    return X509at_get_attr_by_OBJ(si->signedAttrs, obj, lastpos);
++}
++
++X509_ATTRIBUTE *CMS_signed_get_attr(const CMS_SignerInfo *si, int loc)
++{
++    return X509at_get_attr(si->signedAttrs, loc);
++}
++
++X509_ATTRIBUTE *CMS_signed_delete_attr(CMS_SignerInfo *si, int loc)
++{
++    return X509at_delete_attr(si->signedAttrs, loc);
++}
++
++int CMS_signed_add1_attr(CMS_SignerInfo *si, X509_ATTRIBUTE *attr)
++{
++    if (X509at_add1_attr(&si->signedAttrs, attr))
++        return 1;
++    return 0;
++}
++
++int CMS_signed_add1_attr_by_OBJ(CMS_SignerInfo *si,
++                                const ASN1_OBJECT *obj, int type,
++                                const void *bytes, int len)
++{
++    if (X509at_add1_attr_by_OBJ(&si->signedAttrs, obj, type, bytes, len))
++        return 1;
++    return 0;
++}
++
++int CMS_signed_add1_attr_by_NID(CMS_SignerInfo *si,
++                                int nid, int type, const void *bytes, int len)
++{
++    if (X509at_add1_attr_by_NID(&si->signedAttrs, nid, type, bytes, len))
++        return 1;
++    return 0;
++}
++
++int CMS_signed_add1_attr_by_txt(CMS_SignerInfo *si,
++                                const char *attrname, int type,
++                                const void *bytes, int len)
++{
++    if (X509at_add1_attr_by_txt(&si->signedAttrs, attrname, type, bytes, len))
++        return 1;
++    return 0;
++}
++
++void *CMS_signed_get0_data_by_OBJ(CMS_SignerInfo *si, const ASN1_OBJECT *oid,
++                                  int lastpos, int type)
++{
++    return X509at_get0_data_by_OBJ(si->signedAttrs, oid, lastpos, type);
++}
++
++int CMS_unsigned_get_attr_count(const CMS_SignerInfo *si)
++{
++    return X509at_get_attr_count(si->unsignedAttrs);
++}
++
++int CMS_unsigned_get_attr_by_NID(const CMS_SignerInfo *si, int nid,
++                                 int lastpos)
++{
++    return X509at_get_attr_by_NID(si->unsignedAttrs, nid, lastpos);
++}
++
++int CMS_unsigned_get_attr_by_OBJ(const CMS_SignerInfo *si,
++                                 const ASN1_OBJECT *obj, int lastpos)
++{
++    return X509at_get_attr_by_OBJ(si->unsignedAttrs, obj, lastpos);
++}
++
++X509_ATTRIBUTE *CMS_unsigned_get_attr(const CMS_SignerInfo *si, int loc)
++{
++    return X509at_get_attr(si->unsignedAttrs, loc);
++}
++
++X509_ATTRIBUTE *CMS_unsigned_delete_attr(CMS_SignerInfo *si, int loc)
++{
++    return X509at_delete_attr(si->unsignedAttrs, loc);
++}
++
++int CMS_unsigned_add1_attr(CMS_SignerInfo *si, X509_ATTRIBUTE *attr)
++{
++    if (X509at_add1_attr(&si->unsignedAttrs, attr))
++        return 1;
++    return 0;
++}
++
++int CMS_unsigned_add1_attr_by_OBJ(CMS_SignerInfo *si,
++                                  const ASN1_OBJECT *obj, int type,
++                                  const void *bytes, int len)
++{
++    if (X509at_add1_attr_by_OBJ(&si->unsignedAttrs, obj, type, bytes, len))
++        return 1;
++    return 0;
++}
++
++int CMS_unsigned_add1_attr_by_NID(CMS_SignerInfo *si,
++                                  int nid, int type,
++                                  const void *bytes, int len)
++{
++    if (X509at_add1_attr_by_NID(&si->unsignedAttrs, nid, type, bytes, len))
++        return 1;
++    return 0;
++}
++
++int CMS_unsigned_add1_attr_by_txt(CMS_SignerInfo *si,
++                                  const char *attrname, int type,
++                                  const void *bytes, int len)
++{
++    if (X509at_add1_attr_by_txt(&si->unsignedAttrs, attrname,
++                                type, bytes, len))
++        return 1;
++    return 0;
++}
++
++void *CMS_unsigned_get0_data_by_OBJ(CMS_SignerInfo *si, ASN1_OBJECT *oid,
++                                    int lastpos, int type)
++{
++    return X509at_get0_data_by_OBJ(si->unsignedAttrs, oid, lastpos, type);
++}
++
++/* Specific attribute cases */
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/cms/cms_cd.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/cms/cms_cd.c
+new file mode 100644
+index 0000000..f05e308
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/cms/cms_cd.c
+@@ -0,0 +1,82 @@
++/*
++ * Copyright 2008-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include "internal/cryptlib.h"
++#include 
++#include 
++#include 
++#include 
++#include 
++#include 
++#include 
++#include "cms_lcl.h"
++
++#ifdef ZLIB
++
++/* CMS CompressedData Utilities */
++
++CMS_ContentInfo *cms_CompressedData_create(int comp_nid)
++{
++    CMS_ContentInfo *cms;
++    CMS_CompressedData *cd;
++    /*
++     * Will need something cleverer if there is ever more than one
++     * compression algorithm or parameters have some meaning...
++     */
++    if (comp_nid != NID_zlib_compression) {
++        CMSerr(CMS_F_CMS_COMPRESSEDDATA_CREATE,
++               CMS_R_UNSUPPORTED_COMPRESSION_ALGORITHM);
++        return NULL;
++    }
++    cms = CMS_ContentInfo_new();
++    if (cms == NULL)
++        return NULL;
++
++    cd = M_ASN1_new_of(CMS_CompressedData);
++
++    if (cd == NULL)
++        goto err;
++
++    cms->contentType = OBJ_nid2obj(NID_id_smime_ct_compressedData);
++    cms->d.compressedData = cd;
++
++    cd->version = 0;
++
++    X509_ALGOR_set0(cd->compressionAlgorithm,
++                    OBJ_nid2obj(NID_zlib_compression), V_ASN1_UNDEF, NULL);
++
++    cd->encapContentInfo->eContentType = OBJ_nid2obj(NID_pkcs7_data);
++
++    return cms;
++
++ err:
++    CMS_ContentInfo_free(cms);
++    return NULL;
++}
++
++BIO *cms_CompressedData_init_bio(CMS_ContentInfo *cms)
++{
++    CMS_CompressedData *cd;
++    const ASN1_OBJECT *compoid;
++    if (OBJ_obj2nid(cms->contentType) != NID_id_smime_ct_compressedData) {
++        CMSerr(CMS_F_CMS_COMPRESSEDDATA_INIT_BIO,
++               CMS_R_CONTENT_TYPE_NOT_COMPRESSED_DATA);
++        return NULL;
++    }
++    cd = cms->d.compressedData;
++    X509_ALGOR_get0(&compoid, NULL, NULL, cd->compressionAlgorithm);
++    if (OBJ_obj2nid(compoid) != NID_zlib_compression) {
++        CMSerr(CMS_F_CMS_COMPRESSEDDATA_INIT_BIO,
++               CMS_R_UNSUPPORTED_COMPRESSION_ALGORITHM);
++        return NULL;
++    }
++    return BIO_new(BIO_f_zlib());
++}
++
++#endif
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/cms/cms_dd.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/cms/cms_dd.c
+new file mode 100644
+index 0000000..5da6802
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/cms/cms_dd.c
+@@ -0,0 +1,99 @@
++/*
++ * Copyright 2008-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include "internal/cryptlib.h"
++#include 
++#include 
++#include 
++#include 
++#include 
++#include "cms_lcl.h"
++
++/* CMS DigestedData Utilities */
++
++CMS_ContentInfo *cms_DigestedData_create(const EVP_MD *md)
++{
++    CMS_ContentInfo *cms;
++    CMS_DigestedData *dd;
++    cms = CMS_ContentInfo_new();
++    if (cms == NULL)
++        return NULL;
++
++    dd = M_ASN1_new_of(CMS_DigestedData);
++
++    if (dd == NULL)
++        goto err;
++
++    cms->contentType = OBJ_nid2obj(NID_pkcs7_digest);
++    cms->d.digestedData = dd;
++
++    dd->version = 0;
++    dd->encapContentInfo->eContentType = OBJ_nid2obj(NID_pkcs7_data);
++
++    X509_ALGOR_set_md(dd->digestAlgorithm, md);
++
++    return cms;
++
++ err:
++    CMS_ContentInfo_free(cms);
++    return NULL;
++}
++
++BIO *cms_DigestedData_init_bio(CMS_ContentInfo *cms)
++{
++    CMS_DigestedData *dd;
++    dd = cms->d.digestedData;
++    return cms_DigestAlgorithm_init_bio(dd->digestAlgorithm);
++}
++
++int cms_DigestedData_do_final(CMS_ContentInfo *cms, BIO *chain, int verify)
++{
++    EVP_MD_CTX *mctx = EVP_MD_CTX_new();
++    unsigned char md[EVP_MAX_MD_SIZE];
++    unsigned int mdlen;
++    int r = 0;
++    CMS_DigestedData *dd;
++
++    if (mctx == NULL) {
++        CMSerr(CMS_F_CMS_DIGESTEDDATA_DO_FINAL, ERR_R_MALLOC_FAILURE);
++        goto err;
++    }
++
++    dd = cms->d.digestedData;
++
++    if (!cms_DigestAlgorithm_find_ctx(mctx, chain, dd->digestAlgorithm))
++        goto err;
++
++    if (EVP_DigestFinal_ex(mctx, md, &mdlen) <= 0)
++        goto err;
++
++    if (verify) {
++        if (mdlen != (unsigned int)dd->digest->length) {
++            CMSerr(CMS_F_CMS_DIGESTEDDATA_DO_FINAL,
++                   CMS_R_MESSAGEDIGEST_WRONG_LENGTH);
++            goto err;
++        }
++
++        if (memcmp(md, dd->digest->data, mdlen))
++            CMSerr(CMS_F_CMS_DIGESTEDDATA_DO_FINAL,
++                   CMS_R_VERIFICATION_FAILURE);
++        else
++            r = 1;
++    } else {
++        if (!ASN1_STRING_set(dd->digest, md, mdlen))
++            goto err;
++        r = 1;
++    }
++
++ err:
++    EVP_MD_CTX_free(mctx);
++
++    return r;
++
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/cms/cms_enc.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/cms/cms_enc.c
+new file mode 100644
+index 0000000..ed91342
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/cms/cms_enc.c
+@@ -0,0 +1,212 @@
++/*
++ * Copyright 2008-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include "internal/cryptlib.h"
++#include 
++#include 
++#include 
++#include 
++#include 
++#include 
++#include "cms_lcl.h"
++
++/* CMS EncryptedData Utilities */
++
++/* Return BIO based on EncryptedContentInfo and key */
++
++BIO *cms_EncryptedContent_init_bio(CMS_EncryptedContentInfo *ec)
++{
++    BIO *b;
++    EVP_CIPHER_CTX *ctx;
++    const EVP_CIPHER *ciph;
++    X509_ALGOR *calg = ec->contentEncryptionAlgorithm;
++    unsigned char iv[EVP_MAX_IV_LENGTH], *piv = NULL;
++    unsigned char *tkey = NULL;
++    size_t tkeylen = 0;
++
++    int ok = 0;
++
++    int enc, keep_key = 0;
++
++    enc = ec->cipher ? 1 : 0;
++
++    b = BIO_new(BIO_f_cipher());
++    if (b == NULL) {
++        CMSerr(CMS_F_CMS_ENCRYPTEDCONTENT_INIT_BIO, ERR_R_MALLOC_FAILURE);
++        return NULL;
++    }
++
++    BIO_get_cipher_ctx(b, &ctx);
++
++    if (enc) {
++        ciph = ec->cipher;
++        /*
++         * If not keeping key set cipher to NULL so subsequent calls decrypt.
++         */
++        if (ec->key)
++            ec->cipher = NULL;
++    } else {
++        ciph = EVP_get_cipherbyobj(calg->algorithm);
++
++        if (!ciph) {
++            CMSerr(CMS_F_CMS_ENCRYPTEDCONTENT_INIT_BIO, CMS_R_UNKNOWN_CIPHER);
++            goto err;
++        }
++    }
++
++    if (EVP_CipherInit_ex(ctx, ciph, NULL, NULL, NULL, enc) <= 0) {
++        CMSerr(CMS_F_CMS_ENCRYPTEDCONTENT_INIT_BIO,
++               CMS_R_CIPHER_INITIALISATION_ERROR);
++        goto err;
++    }
++
++    if (enc) {
++        int ivlen;
++        calg->algorithm = OBJ_nid2obj(EVP_CIPHER_CTX_type(ctx));
++        /* Generate a random IV if we need one */
++        ivlen = EVP_CIPHER_CTX_iv_length(ctx);
++        if (ivlen > 0) {
++            if (RAND_bytes(iv, ivlen) <= 0)
++                goto err;
++            piv = iv;
++        }
++    } else if (EVP_CIPHER_asn1_to_param(ctx, calg->parameter) <= 0) {
++        CMSerr(CMS_F_CMS_ENCRYPTEDCONTENT_INIT_BIO,
++               CMS_R_CIPHER_PARAMETER_INITIALISATION_ERROR);
++        goto err;
++    }
++    tkeylen = EVP_CIPHER_CTX_key_length(ctx);
++    /* Generate random session key */
++    if (!enc || !ec->key) {
++        tkey = OPENSSL_malloc(tkeylen);
++        if (tkey == NULL) {
++            CMSerr(CMS_F_CMS_ENCRYPTEDCONTENT_INIT_BIO, ERR_R_MALLOC_FAILURE);
++            goto err;
++        }
++        if (EVP_CIPHER_CTX_rand_key(ctx, tkey) <= 0)
++            goto err;
++    }
++
++    if (!ec->key) {
++        ec->key = tkey;
++        ec->keylen = tkeylen;
++        tkey = NULL;
++        if (enc)
++            keep_key = 1;
++        else
++            ERR_clear_error();
++
++    }
++
++    if (ec->keylen != tkeylen) {
++        /* If necessary set key length */
++        if (EVP_CIPHER_CTX_set_key_length(ctx, ec->keylen) <= 0) {
++            /*
++             * Only reveal failure if debugging so we don't leak information
++             * which may be useful in MMA.
++             */
++            if (enc || ec->debug) {
++                CMSerr(CMS_F_CMS_ENCRYPTEDCONTENT_INIT_BIO,
++                       CMS_R_INVALID_KEY_LENGTH);
++                goto err;
++            } else {
++                /* Use random key */
++                OPENSSL_clear_free(ec->key, ec->keylen);
++                ec->key = tkey;
++                ec->keylen = tkeylen;
++                tkey = NULL;
++                ERR_clear_error();
++            }
++        }
++    }
++
++    if (EVP_CipherInit_ex(ctx, NULL, NULL, ec->key, piv, enc) <= 0) {
++        CMSerr(CMS_F_CMS_ENCRYPTEDCONTENT_INIT_BIO,
++               CMS_R_CIPHER_INITIALISATION_ERROR);
++        goto err;
++    }
++    if (enc) {
++        calg->parameter = ASN1_TYPE_new();
++        if (calg->parameter == NULL) {
++            CMSerr(CMS_F_CMS_ENCRYPTEDCONTENT_INIT_BIO, ERR_R_MALLOC_FAILURE);
++            goto err;
++        }
++        if (EVP_CIPHER_param_to_asn1(ctx, calg->parameter) <= 0) {
++            CMSerr(CMS_F_CMS_ENCRYPTEDCONTENT_INIT_BIO,
++                   CMS_R_CIPHER_PARAMETER_INITIALISATION_ERROR);
++            goto err;
++        }
++        /* If parameter type not set omit parameter */
++        if (calg->parameter->type == V_ASN1_UNDEF) {
++            ASN1_TYPE_free(calg->parameter);
++            calg->parameter = NULL;
++        }
++    }
++    ok = 1;
++
++ err:
++    if (!keep_key || !ok) {
++        OPENSSL_clear_free(ec->key, ec->keylen);
++        ec->key = NULL;
++    }
++    OPENSSL_clear_free(tkey, tkeylen);
++    if (ok)
++        return b;
++    BIO_free(b);
++    return NULL;
++}
++
++int cms_EncryptedContent_init(CMS_EncryptedContentInfo *ec,
++                              const EVP_CIPHER *cipher,
++                              const unsigned char *key, size_t keylen)
++{
++    ec->cipher = cipher;
++    if (key) {
++        ec->key = OPENSSL_malloc(keylen);
++        if (ec->key == NULL)
++            return 0;
++        memcpy(ec->key, key, keylen);
++    }
++    ec->keylen = keylen;
++    if (cipher)
++        ec->contentType = OBJ_nid2obj(NID_pkcs7_data);
++    return 1;
++}
++
++int CMS_EncryptedData_set1_key(CMS_ContentInfo *cms, const EVP_CIPHER *ciph,
++                               const unsigned char *key, size_t keylen)
++{
++    CMS_EncryptedContentInfo *ec;
++    if (!key || !keylen) {
++        CMSerr(CMS_F_CMS_ENCRYPTEDDATA_SET1_KEY, CMS_R_NO_KEY);
++        return 0;
++    }
++    if (ciph) {
++        cms->d.encryptedData = M_ASN1_new_of(CMS_EncryptedData);
++        if (!cms->d.encryptedData) {
++            CMSerr(CMS_F_CMS_ENCRYPTEDDATA_SET1_KEY, ERR_R_MALLOC_FAILURE);
++            return 0;
++        }
++        cms->contentType = OBJ_nid2obj(NID_pkcs7_encrypted);
++        cms->d.encryptedData->version = 0;
++    } else if (OBJ_obj2nid(cms->contentType) != NID_pkcs7_encrypted) {
++        CMSerr(CMS_F_CMS_ENCRYPTEDDATA_SET1_KEY, CMS_R_NOT_ENCRYPTED_DATA);
++        return 0;
++    }
++    ec = cms->d.encryptedData->encryptedContentInfo;
++    return cms_EncryptedContent_init(ec, ciph, key, keylen);
++}
++
++BIO *cms_EncryptedData_init_bio(CMS_ContentInfo *cms)
++{
++    CMS_EncryptedData *enc = cms->d.encryptedData;
++    if (enc->encryptedContentInfo->cipher && enc->unprotectedAttrs)
++        enc->version = 2;
++    return cms_EncryptedContent_init_bio(enc->encryptedContentInfo);
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/cms/cms_env.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/cms/cms_env.c
+new file mode 100644
+index 0000000..8d45943
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/cms/cms_env.c
+@@ -0,0 +1,902 @@
++/*
++ * Copyright 2008-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include "internal/cryptlib.h"
++#include 
++#include 
++#include 
++#include 
++#include 
++#include 
++#include "cms_lcl.h"
++#include "internal/asn1_int.h"
++#include "internal/evp_int.h"
++
++/* CMS EnvelopedData Utilities */
++
++CMS_EnvelopedData *cms_get0_enveloped(CMS_ContentInfo *cms)
++{
++    if (OBJ_obj2nid(cms->contentType) != NID_pkcs7_enveloped) {
++        CMSerr(CMS_F_CMS_GET0_ENVELOPED,
++               CMS_R_CONTENT_TYPE_NOT_ENVELOPED_DATA);
++        return NULL;
++    }
++    return cms->d.envelopedData;
++}
++
++static CMS_EnvelopedData *cms_enveloped_data_init(CMS_ContentInfo *cms)
++{
++    if (cms->d.other == NULL) {
++        cms->d.envelopedData = M_ASN1_new_of(CMS_EnvelopedData);
++        if (!cms->d.envelopedData) {
++            CMSerr(CMS_F_CMS_ENVELOPED_DATA_INIT, ERR_R_MALLOC_FAILURE);
++            return NULL;
++        }
++        cms->d.envelopedData->version = 0;
++        cms->d.envelopedData->encryptedContentInfo->contentType =
++            OBJ_nid2obj(NID_pkcs7_data);
++        ASN1_OBJECT_free(cms->contentType);
++        cms->contentType = OBJ_nid2obj(NID_pkcs7_enveloped);
++        return cms->d.envelopedData;
++    }
++    return cms_get0_enveloped(cms);
++}
++
++int cms_env_asn1_ctrl(CMS_RecipientInfo *ri, int cmd)
++{
++    EVP_PKEY *pkey;
++    int i;
++    if (ri->type == CMS_RECIPINFO_TRANS)
++        pkey = ri->d.ktri->pkey;
++    else if (ri->type == CMS_RECIPINFO_AGREE) {
++        EVP_PKEY_CTX *pctx = ri->d.kari->pctx;
++        if (!pctx)
++            return 0;
++        pkey = EVP_PKEY_CTX_get0_pkey(pctx);
++        if (!pkey)
++            return 0;
++    } else
++        return 0;
++    if (!pkey->ameth || !pkey->ameth->pkey_ctrl)
++        return 1;
++    i = pkey->ameth->pkey_ctrl(pkey, ASN1_PKEY_CTRL_CMS_ENVELOPE, cmd, ri);
++    if (i == -2) {
++        CMSerr(CMS_F_CMS_ENV_ASN1_CTRL,
++               CMS_R_NOT_SUPPORTED_FOR_THIS_KEY_TYPE);
++        return 0;
++    }
++    if (i <= 0) {
++        CMSerr(CMS_F_CMS_ENV_ASN1_CTRL, CMS_R_CTRL_FAILURE);
++        return 0;
++    }
++    return 1;
++}
++
++STACK_OF(CMS_RecipientInfo) *CMS_get0_RecipientInfos(CMS_ContentInfo *cms)
++{
++    CMS_EnvelopedData *env;
++    env = cms_get0_enveloped(cms);
++    if (!env)
++        return NULL;
++    return env->recipientInfos;
++}
++
++int CMS_RecipientInfo_type(CMS_RecipientInfo *ri)
++{
++    return ri->type;
++}
++
++EVP_PKEY_CTX *CMS_RecipientInfo_get0_pkey_ctx(CMS_RecipientInfo *ri)
++{
++    if (ri->type == CMS_RECIPINFO_TRANS)
++        return ri->d.ktri->pctx;
++    else if (ri->type == CMS_RECIPINFO_AGREE)
++        return ri->d.kari->pctx;
++    return NULL;
++}
++
++CMS_ContentInfo *CMS_EnvelopedData_create(const EVP_CIPHER *cipher)
++{
++    CMS_ContentInfo *cms;
++    CMS_EnvelopedData *env;
++    cms = CMS_ContentInfo_new();
++    if (cms == NULL)
++        goto merr;
++    env = cms_enveloped_data_init(cms);
++    if (env == NULL)
++        goto merr;
++    if (!cms_EncryptedContent_init(env->encryptedContentInfo,
++                                   cipher, NULL, 0))
++        goto merr;
++    return cms;
++ merr:
++    CMS_ContentInfo_free(cms);
++    CMSerr(CMS_F_CMS_ENVELOPEDDATA_CREATE, ERR_R_MALLOC_FAILURE);
++    return NULL;
++}
++
++/* Key Transport Recipient Info (KTRI) routines */
++
++/* Initialise a ktri based on passed certificate and key */
++
++static int cms_RecipientInfo_ktri_init(CMS_RecipientInfo *ri, X509 *recip,
++                                       EVP_PKEY *pk, unsigned int flags)
++{
++    CMS_KeyTransRecipientInfo *ktri;
++    int idtype;
++
++    ri->d.ktri = M_ASN1_new_of(CMS_KeyTransRecipientInfo);
++    if (!ri->d.ktri)
++        return 0;
++    ri->type = CMS_RECIPINFO_TRANS;
++
++    ktri = ri->d.ktri;
++
++    if (flags & CMS_USE_KEYID) {
++        ktri->version = 2;
++        idtype = CMS_RECIPINFO_KEYIDENTIFIER;
++    } else {
++        ktri->version = 0;
++        idtype = CMS_RECIPINFO_ISSUER_SERIAL;
++    }
++
++    /*
++     * Not a typo: RecipientIdentifier and SignerIdentifier are the same
++     * structure.
++     */
++
++    if (!cms_set1_SignerIdentifier(ktri->rid, recip, idtype))
++        return 0;
++
++    X509_up_ref(recip);
++    EVP_PKEY_up_ref(pk);
++
++    ktri->pkey = pk;
++    ktri->recip = recip;
++
++    if (flags & CMS_KEY_PARAM) {
++        ktri->pctx = EVP_PKEY_CTX_new(ktri->pkey, NULL);
++        if (ktri->pctx == NULL)
++            return 0;
++        if (EVP_PKEY_encrypt_init(ktri->pctx) <= 0)
++            return 0;
++    } else if (!cms_env_asn1_ctrl(ri, 0))
++        return 0;
++    return 1;
++}
++
++/*
++ * 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 *ri = NULL;
++    CMS_EnvelopedData *env;
++    EVP_PKEY *pk = NULL;
++    env = cms_get0_enveloped(cms);
++    if (!env)
++        goto err;
++
++    /* Initialize recipient info */
++    ri = M_ASN1_new_of(CMS_RecipientInfo);
++    if (!ri)
++        goto merr;
++
++    pk = X509_get0_pubkey(recip);
++    if (!pk) {
++        CMSerr(CMS_F_CMS_ADD1_RECIPIENT_CERT, CMS_R_ERROR_GETTING_PUBLIC_KEY);
++        goto err;
++    }
++
++    switch (cms_pkey_get_ri_type(pk)) {
++
++    case CMS_RECIPINFO_TRANS:
++        if (!cms_RecipientInfo_ktri_init(ri, recip, pk, flags))
++            goto err;
++        break;
++
++    case CMS_RECIPINFO_AGREE:
++        if (!cms_RecipientInfo_kari_init(ri, recip, pk, flags))
++            goto err;
++        break;
++
++    default:
++        CMSerr(CMS_F_CMS_ADD1_RECIPIENT_CERT,
++               CMS_R_NOT_SUPPORTED_FOR_THIS_KEY_TYPE);
++        goto err;
++
++    }
++
++    if (!sk_CMS_RecipientInfo_push(env->recipientInfos, ri))
++        goto merr;
++
++    return ri;
++
++ merr:
++    CMSerr(CMS_F_CMS_ADD1_RECIPIENT_CERT, ERR_R_MALLOC_FAILURE);
++ err:
++    M_ASN1_free_of(ri, CMS_RecipientInfo);
++    return NULL;
++
++}
++
++int CMS_RecipientInfo_ktri_get0_algs(CMS_RecipientInfo *ri,
++                                     EVP_PKEY **pk, X509 **recip,
++                                     X509_ALGOR **palg)
++{
++    CMS_KeyTransRecipientInfo *ktri;
++    if (ri->type != CMS_RECIPINFO_TRANS) {
++        CMSerr(CMS_F_CMS_RECIPIENTINFO_KTRI_GET0_ALGS,
++               CMS_R_NOT_KEY_TRANSPORT);
++        return 0;
++    }
++
++    ktri = ri->d.ktri;
++
++    if (pk)
++        *pk = ktri->pkey;
++    if (recip)
++        *recip = ktri->recip;
++    if (palg)
++        *palg = ktri->keyEncryptionAlgorithm;
++    return 1;
++}
++
++int CMS_RecipientInfo_ktri_get0_signer_id(CMS_RecipientInfo *ri,
++                                          ASN1_OCTET_STRING **keyid,
++                                          X509_NAME **issuer,
++                                          ASN1_INTEGER **sno)
++{
++    CMS_KeyTransRecipientInfo *ktri;
++    if (ri->type != CMS_RECIPINFO_TRANS) {
++        CMSerr(CMS_F_CMS_RECIPIENTINFO_KTRI_GET0_SIGNER_ID,
++               CMS_R_NOT_KEY_TRANSPORT);
++        return 0;
++    }
++    ktri = ri->d.ktri;
++
++    return cms_SignerIdentifier_get0_signer_id(ktri->rid, keyid, issuer, sno);
++}
++
++int CMS_RecipientInfo_ktri_cert_cmp(CMS_RecipientInfo *ri, X509 *cert)
++{
++    if (ri->type != CMS_RECIPINFO_TRANS) {
++        CMSerr(CMS_F_CMS_RECIPIENTINFO_KTRI_CERT_CMP,
++               CMS_R_NOT_KEY_TRANSPORT);
++        return -2;
++    }
++    return cms_SignerIdentifier_cert_cmp(ri->d.ktri->rid, cert);
++}
++
++int CMS_RecipientInfo_set0_pkey(CMS_RecipientInfo *ri, EVP_PKEY *pkey)
++{
++    if (ri->type != CMS_RECIPINFO_TRANS) {
++        CMSerr(CMS_F_CMS_RECIPIENTINFO_SET0_PKEY, CMS_R_NOT_KEY_TRANSPORT);
++        return 0;
++    }
++    ri->d.ktri->pkey = pkey;
++    return 1;
++}
++
++/* Encrypt content key in key transport recipient info */
++
++static int cms_RecipientInfo_ktri_encrypt(CMS_ContentInfo *cms,
++                                          CMS_RecipientInfo *ri)
++{
++    CMS_KeyTransRecipientInfo *ktri;
++    CMS_EncryptedContentInfo *ec;
++    EVP_PKEY_CTX *pctx;
++    unsigned char *ek = NULL;
++    size_t eklen;
++
++    int ret = 0;
++
++    if (ri->type != CMS_RECIPINFO_TRANS) {
++        CMSerr(CMS_F_CMS_RECIPIENTINFO_KTRI_ENCRYPT, CMS_R_NOT_KEY_TRANSPORT);
++        return 0;
++    }
++    ktri = ri->d.ktri;
++    ec = cms->d.envelopedData->encryptedContentInfo;
++
++    pctx = ktri->pctx;
++
++    if (pctx) {
++        if (!cms_env_asn1_ctrl(ri, 0))
++            goto err;
++    } else {
++        pctx = EVP_PKEY_CTX_new(ktri->pkey, NULL);
++        if (pctx == NULL)
++            return 0;
++
++        if (EVP_PKEY_encrypt_init(pctx) <= 0)
++            goto err;
++    }
++
++    if (EVP_PKEY_CTX_ctrl(pctx, -1, EVP_PKEY_OP_ENCRYPT,
++                          EVP_PKEY_CTRL_CMS_ENCRYPT, 0, ri) <= 0) {
++        CMSerr(CMS_F_CMS_RECIPIENTINFO_KTRI_ENCRYPT, CMS_R_CTRL_ERROR);
++        goto err;
++    }
++
++    if (EVP_PKEY_encrypt(pctx, NULL, &eklen, ec->key, ec->keylen) <= 0)
++        goto err;
++
++    ek = OPENSSL_malloc(eklen);
++
++    if (ek == NULL) {
++        CMSerr(CMS_F_CMS_RECIPIENTINFO_KTRI_ENCRYPT, ERR_R_MALLOC_FAILURE);
++        goto err;
++    }
++
++    if (EVP_PKEY_encrypt(pctx, ek, &eklen, ec->key, ec->keylen) <= 0)
++        goto err;
++
++    ASN1_STRING_set0(ktri->encryptedKey, ek, eklen);
++    ek = NULL;
++
++    ret = 1;
++
++ err:
++    EVP_PKEY_CTX_free(pctx);
++    ktri->pctx = NULL;
++    OPENSSL_free(ek);
++    return ret;
++
++}
++
++/* Decrypt content key from KTRI */
++
++static int cms_RecipientInfo_ktri_decrypt(CMS_ContentInfo *cms,
++                                          CMS_RecipientInfo *ri)
++{
++    CMS_KeyTransRecipientInfo *ktri = ri->d.ktri;
++    EVP_PKEY *pkey = ktri->pkey;
++    unsigned char *ek = NULL;
++    size_t eklen;
++    int ret = 0;
++    CMS_EncryptedContentInfo *ec;
++    ec = cms->d.envelopedData->encryptedContentInfo;
++
++    if (ktri->pkey == NULL) {
++        CMSerr(CMS_F_CMS_RECIPIENTINFO_KTRI_DECRYPT, CMS_R_NO_PRIVATE_KEY);
++        return 0;
++    }
++
++    ktri->pctx = EVP_PKEY_CTX_new(pkey, NULL);
++    if (ktri->pctx == NULL)
++        return 0;
++
++    if (EVP_PKEY_decrypt_init(ktri->pctx) <= 0)
++        goto err;
++
++    if (!cms_env_asn1_ctrl(ri, 1))
++        goto err;
++
++    if (EVP_PKEY_CTX_ctrl(ktri->pctx, -1, EVP_PKEY_OP_DECRYPT,
++                          EVP_PKEY_CTRL_CMS_DECRYPT, 0, ri) <= 0) {
++        CMSerr(CMS_F_CMS_RECIPIENTINFO_KTRI_DECRYPT, CMS_R_CTRL_ERROR);
++        goto err;
++    }
++
++    if (EVP_PKEY_decrypt(ktri->pctx, NULL, &eklen,
++                         ktri->encryptedKey->data,
++                         ktri->encryptedKey->length) <= 0)
++        goto err;
++
++    ek = OPENSSL_malloc(eklen);
++
++    if (ek == NULL) {
++        CMSerr(CMS_F_CMS_RECIPIENTINFO_KTRI_DECRYPT, ERR_R_MALLOC_FAILURE);
++        goto err;
++    }
++
++    if (EVP_PKEY_decrypt(ktri->pctx, ek, &eklen,
++                         ktri->encryptedKey->data,
++                         ktri->encryptedKey->length) <= 0) {
++        CMSerr(CMS_F_CMS_RECIPIENTINFO_KTRI_DECRYPT, CMS_R_CMS_LIB);
++        goto err;
++    }
++
++    ret = 1;
++
++    OPENSSL_clear_free(ec->key, ec->keylen);
++    ec->key = ek;
++    ec->keylen = eklen;
++
++ err:
++    EVP_PKEY_CTX_free(ktri->pctx);
++    ktri->pctx = NULL;
++    if (!ret)
++        OPENSSL_free(ek);
++
++    return ret;
++}
++
++/* Key Encrypted Key (KEK) RecipientInfo routines */
++
++int CMS_RecipientInfo_kekri_id_cmp(CMS_RecipientInfo *ri,
++                                   const unsigned char *id, size_t idlen)
++{
++    ASN1_OCTET_STRING tmp_os;
++    CMS_KEKRecipientInfo *kekri;
++    if (ri->type != CMS_RECIPINFO_KEK) {
++        CMSerr(CMS_F_CMS_RECIPIENTINFO_KEKRI_ID_CMP, CMS_R_NOT_KEK);
++        return -2;
++    }
++    kekri = ri->d.kekri;
++    tmp_os.type = V_ASN1_OCTET_STRING;
++    tmp_os.flags = 0;
++    tmp_os.data = (unsigned char *)id;
++    tmp_os.length = (int)idlen;
++    return ASN1_OCTET_STRING_cmp(&tmp_os, kekri->kekid->keyIdentifier);
++}
++
++/* For now hard code AES key wrap info */
++
++static size_t aes_wrap_keylen(int nid)
++{
++    switch (nid) {
++    case NID_id_aes128_wrap:
++        return 16;
++
++    case NID_id_aes192_wrap:
++        return 24;
++
++    case NID_id_aes256_wrap:
++        return 32;
++
++    default:
++        return 0;
++    }
++}
++
++CMS_RecipientInfo *CMS_add0_recipient_key(CMS_ContentInfo *cms, int nid,
++                                          unsigned char *key, size_t keylen,
++                                          unsigned char *id, size_t idlen,
++                                          ASN1_GENERALIZEDTIME *date,
++                                          ASN1_OBJECT *otherTypeId,
++                                          ASN1_TYPE *otherType)
++{
++    CMS_RecipientInfo *ri = NULL;
++    CMS_EnvelopedData *env;
++    CMS_KEKRecipientInfo *kekri;
++    env = cms_get0_enveloped(cms);
++    if (!env)
++        goto err;
++
++    if (nid == NID_undef) {
++        switch (keylen) {
++        case 16:
++            nid = NID_id_aes128_wrap;
++            break;
++
++        case 24:
++            nid = NID_id_aes192_wrap;
++            break;
++
++        case 32:
++            nid = NID_id_aes256_wrap;
++            break;
++
++        default:
++            CMSerr(CMS_F_CMS_ADD0_RECIPIENT_KEY, CMS_R_INVALID_KEY_LENGTH);
++            goto err;
++        }
++
++    } else {
++
++        size_t exp_keylen = aes_wrap_keylen(nid);
++
++        if (!exp_keylen) {
++            CMSerr(CMS_F_CMS_ADD0_RECIPIENT_KEY,
++                   CMS_R_UNSUPPORTED_KEK_ALGORITHM);
++            goto err;
++        }
++
++        if (keylen != exp_keylen) {
++            CMSerr(CMS_F_CMS_ADD0_RECIPIENT_KEY, CMS_R_INVALID_KEY_LENGTH);
++            goto err;
++        }
++
++    }
++
++    /* Initialize recipient info */
++    ri = M_ASN1_new_of(CMS_RecipientInfo);
++    if (!ri)
++        goto merr;
++
++    ri->d.kekri = M_ASN1_new_of(CMS_KEKRecipientInfo);
++    if (!ri->d.kekri)
++        goto merr;
++    ri->type = CMS_RECIPINFO_KEK;
++
++    kekri = ri->d.kekri;
++
++    if (otherTypeId) {
++        kekri->kekid->other = M_ASN1_new_of(CMS_OtherKeyAttribute);
++        if (kekri->kekid->other == NULL)
++            goto merr;
++    }
++
++    if (!sk_CMS_RecipientInfo_push(env->recipientInfos, ri))
++        goto merr;
++
++    /* After this point no calls can fail */
++
++    kekri->version = 4;
++
++    kekri->key = key;
++    kekri->keylen = keylen;
++
++    ASN1_STRING_set0(kekri->kekid->keyIdentifier, id, idlen);
++
++    kekri->kekid->date = date;
++
++    if (kekri->kekid->other) {
++        kekri->kekid->other->keyAttrId = otherTypeId;
++        kekri->kekid->other->keyAttr = otherType;
++    }
++
++    X509_ALGOR_set0(kekri->keyEncryptionAlgorithm,
++                    OBJ_nid2obj(nid), V_ASN1_UNDEF, NULL);
++
++    return ri;
++
++ merr:
++    CMSerr(CMS_F_CMS_ADD0_RECIPIENT_KEY, ERR_R_MALLOC_FAILURE);
++ err:
++    M_ASN1_free_of(ri, CMS_RecipientInfo);
++    return NULL;
++
++}
++
++int CMS_RecipientInfo_kekri_get0_id(CMS_RecipientInfo *ri,
++                                    X509_ALGOR **palg,
++                                    ASN1_OCTET_STRING **pid,
++                                    ASN1_GENERALIZEDTIME **pdate,
++                                    ASN1_OBJECT **potherid,
++                                    ASN1_TYPE **pothertype)
++{
++    CMS_KEKIdentifier *rkid;
++    if (ri->type != CMS_RECIPINFO_KEK) {
++        CMSerr(CMS_F_CMS_RECIPIENTINFO_KEKRI_GET0_ID, CMS_R_NOT_KEK);
++        return 0;
++    }
++    rkid = ri->d.kekri->kekid;
++    if (palg)
++        *palg = ri->d.kekri->keyEncryptionAlgorithm;
++    if (pid)
++        *pid = rkid->keyIdentifier;
++    if (pdate)
++        *pdate = rkid->date;
++    if (potherid) {
++        if (rkid->other)
++            *potherid = rkid->other->keyAttrId;
++        else
++            *potherid = NULL;
++    }
++    if (pothertype) {
++        if (rkid->other)
++            *pothertype = rkid->other->keyAttr;
++        else
++            *pothertype = NULL;
++    }
++    return 1;
++}
++
++int CMS_RecipientInfo_set0_key(CMS_RecipientInfo *ri,
++                               unsigned char *key, size_t keylen)
++{
++    CMS_KEKRecipientInfo *kekri;
++    if (ri->type != CMS_RECIPINFO_KEK) {
++        CMSerr(CMS_F_CMS_RECIPIENTINFO_SET0_KEY, CMS_R_NOT_KEK);
++        return 0;
++    }
++
++    kekri = ri->d.kekri;
++    kekri->key = key;
++    kekri->keylen = keylen;
++    return 1;
++}
++
++/* Encrypt content key in KEK recipient info */
++
++static int cms_RecipientInfo_kekri_encrypt(CMS_ContentInfo *cms,
++                                           CMS_RecipientInfo *ri)
++{
++    CMS_EncryptedContentInfo *ec;
++    CMS_KEKRecipientInfo *kekri;
++    AES_KEY actx;
++    unsigned char *wkey = NULL;
++    int wkeylen;
++    int r = 0;
++
++    ec = cms->d.envelopedData->encryptedContentInfo;
++
++    kekri = ri->d.kekri;
++
++    if (!kekri->key) {
++        CMSerr(CMS_F_CMS_RECIPIENTINFO_KEKRI_ENCRYPT, CMS_R_NO_KEY);
++        return 0;
++    }
++
++    if (AES_set_encrypt_key(kekri->key, kekri->keylen << 3, &actx)) {
++        CMSerr(CMS_F_CMS_RECIPIENTINFO_KEKRI_ENCRYPT,
++               CMS_R_ERROR_SETTING_KEY);
++        goto err;
++    }
++
++    wkey = OPENSSL_malloc(ec->keylen + 8);
++
++    if (wkey == NULL) {
++        CMSerr(CMS_F_CMS_RECIPIENTINFO_KEKRI_ENCRYPT, ERR_R_MALLOC_FAILURE);
++        goto err;
++    }
++
++    wkeylen = AES_wrap_key(&actx, NULL, wkey, ec->key, ec->keylen);
++
++    if (wkeylen <= 0) {
++        CMSerr(CMS_F_CMS_RECIPIENTINFO_KEKRI_ENCRYPT, CMS_R_WRAP_ERROR);
++        goto err;
++    }
++
++    ASN1_STRING_set0(kekri->encryptedKey, wkey, wkeylen);
++
++    r = 1;
++
++ err:
++
++    if (!r)
++        OPENSSL_free(wkey);
++    OPENSSL_cleanse(&actx, sizeof(actx));
++
++    return r;
++
++}
++
++/* Decrypt content key in KEK recipient info */
++
++static int cms_RecipientInfo_kekri_decrypt(CMS_ContentInfo *cms,
++                                           CMS_RecipientInfo *ri)
++{
++    CMS_EncryptedContentInfo *ec;
++    CMS_KEKRecipientInfo *kekri;
++    AES_KEY actx;
++    unsigned char *ukey = NULL;
++    int ukeylen;
++    int r = 0, wrap_nid;
++
++    ec = cms->d.envelopedData->encryptedContentInfo;
++
++    kekri = ri->d.kekri;
++
++    if (!kekri->key) {
++        CMSerr(CMS_F_CMS_RECIPIENTINFO_KEKRI_DECRYPT, CMS_R_NO_KEY);
++        return 0;
++    }
++
++    wrap_nid = OBJ_obj2nid(kekri->keyEncryptionAlgorithm->algorithm);
++    if (aes_wrap_keylen(wrap_nid) != kekri->keylen) {
++        CMSerr(CMS_F_CMS_RECIPIENTINFO_KEKRI_DECRYPT,
++               CMS_R_INVALID_KEY_LENGTH);
++        return 0;
++    }
++
++    /* If encrypted key length is invalid don't bother */
++
++    if (kekri->encryptedKey->length < 16) {
++        CMSerr(CMS_F_CMS_RECIPIENTINFO_KEKRI_DECRYPT,
++               CMS_R_INVALID_ENCRYPTED_KEY_LENGTH);
++        goto err;
++    }
++
++    if (AES_set_decrypt_key(kekri->key, kekri->keylen << 3, &actx)) {
++        CMSerr(CMS_F_CMS_RECIPIENTINFO_KEKRI_DECRYPT,
++               CMS_R_ERROR_SETTING_KEY);
++        goto err;
++    }
++
++    ukey = OPENSSL_malloc(kekri->encryptedKey->length - 8);
++
++    if (ukey == NULL) {
++        CMSerr(CMS_F_CMS_RECIPIENTINFO_KEKRI_DECRYPT, ERR_R_MALLOC_FAILURE);
++        goto err;
++    }
++
++    ukeylen = AES_unwrap_key(&actx, NULL, ukey,
++                             kekri->encryptedKey->data,
++                             kekri->encryptedKey->length);
++
++    if (ukeylen <= 0) {
++        CMSerr(CMS_F_CMS_RECIPIENTINFO_KEKRI_DECRYPT, CMS_R_UNWRAP_ERROR);
++        goto err;
++    }
++
++    ec->key = ukey;
++    ec->keylen = ukeylen;
++
++    r = 1;
++
++ err:
++
++    if (!r)
++        OPENSSL_free(ukey);
++    OPENSSL_cleanse(&actx, sizeof(actx));
++
++    return r;
++
++}
++
++int CMS_RecipientInfo_decrypt(CMS_ContentInfo *cms, CMS_RecipientInfo *ri)
++{
++    switch (ri->type) {
++    case CMS_RECIPINFO_TRANS:
++        return cms_RecipientInfo_ktri_decrypt(cms, ri);
++
++    case CMS_RECIPINFO_KEK:
++        return cms_RecipientInfo_kekri_decrypt(cms, ri);
++
++    case CMS_RECIPINFO_PASS:
++        return cms_RecipientInfo_pwri_crypt(cms, ri, 0);
++
++    default:
++        CMSerr(CMS_F_CMS_RECIPIENTINFO_DECRYPT,
++               CMS_R_UNSUPPORTED_RECPIENTINFO_TYPE);
++        return 0;
++    }
++}
++
++int CMS_RecipientInfo_encrypt(CMS_ContentInfo *cms, CMS_RecipientInfo *ri)
++{
++    switch (ri->type) {
++    case CMS_RECIPINFO_TRANS:
++        return cms_RecipientInfo_ktri_encrypt(cms, ri);
++
++    case CMS_RECIPINFO_AGREE:
++        return cms_RecipientInfo_kari_encrypt(cms, ri);
++
++    case CMS_RECIPINFO_KEK:
++        return cms_RecipientInfo_kekri_encrypt(cms, ri);
++
++    case CMS_RECIPINFO_PASS:
++        return cms_RecipientInfo_pwri_crypt(cms, ri, 1);
++
++    default:
++        CMSerr(CMS_F_CMS_RECIPIENTINFO_ENCRYPT,
++               CMS_R_UNSUPPORTED_RECIPIENT_TYPE);
++        return 0;
++    }
++}
++
++/* Check structures and fixup version numbers (if necessary) */
++
++static void cms_env_set_originfo_version(CMS_EnvelopedData *env)
++{
++    CMS_OriginatorInfo *org = env->originatorInfo;
++    int i;
++    if (org == NULL)
++        return;
++    for (i = 0; i < sk_CMS_CertificateChoices_num(org->certificates); i++) {
++        CMS_CertificateChoices *cch;
++        cch = sk_CMS_CertificateChoices_value(org->certificates, i);
++        if (cch->type == CMS_CERTCHOICE_OTHER) {
++            env->version = 4;
++            return;
++        } else if (cch->type == CMS_CERTCHOICE_V2ACERT) {
++            if (env->version < 3)
++                env->version = 3;
++        }
++    }
++
++    for (i = 0; i < sk_CMS_RevocationInfoChoice_num(org->crls); i++) {
++        CMS_RevocationInfoChoice *rch;
++        rch = sk_CMS_RevocationInfoChoice_value(org->crls, i);
++        if (rch->type == CMS_REVCHOICE_OTHER) {
++            env->version = 4;
++            return;
++        }
++    }
++}
++
++static void cms_env_set_version(CMS_EnvelopedData *env)
++{
++    int i;
++    CMS_RecipientInfo *ri;
++
++    /*
++     * Can't set version higher than 4 so if 4 or more already nothing to do.
++     */
++    if (env->version >= 4)
++        return;
++
++    cms_env_set_originfo_version(env);
++
++    if (env->version >= 3)
++        return;
++
++    for (i = 0; i < sk_CMS_RecipientInfo_num(env->recipientInfos); i++) {
++        ri = sk_CMS_RecipientInfo_value(env->recipientInfos, i);
++        if (ri->type == CMS_RECIPINFO_PASS || ri->type == CMS_RECIPINFO_OTHER) {
++            env->version = 3;
++            return;
++        } else if (ri->type != CMS_RECIPINFO_TRANS
++                   || ri->d.ktri->version != 0) {
++            env->version = 2;
++        }
++    }
++    if (env->originatorInfo || env->unprotectedAttrs)
++        env->version = 2;
++    if (env->version == 2)
++        return;
++    env->version = 0;
++}
++
++BIO *cms_EnvelopedData_init_bio(CMS_ContentInfo *cms)
++{
++    CMS_EncryptedContentInfo *ec;
++    STACK_OF(CMS_RecipientInfo) *rinfos;
++    CMS_RecipientInfo *ri;
++    int i, ok = 0;
++    BIO *ret;
++
++    /* Get BIO first to set up key */
++
++    ec = cms->d.envelopedData->encryptedContentInfo;
++    ret = cms_EncryptedContent_init_bio(ec);
++
++    /* If error or no cipher end of processing */
++
++    if (!ret || !ec->cipher)
++        return ret;
++
++    /* Now encrypt content key according to each RecipientInfo type */
++
++    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_INIT_BIO,
++                   CMS_R_ERROR_SETTING_RECIPIENTINFO);
++            goto err;
++        }
++    }
++    cms_env_set_version(cms->d.envelopedData);
++
++    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;
++
++}
++
++/*
++ * Get RecipientInfo type (if any) supported by a key (public or private). To
++ * retain compatibility with previous behaviour if the ctrl value isn't
++ * supported we assume key transport.
++ */
++int cms_pkey_get_ri_type(EVP_PKEY *pk)
++{
++    if (pk->ameth && pk->ameth->pkey_ctrl) {
++        int i, r;
++        i = pk->ameth->pkey_ctrl(pk, ASN1_PKEY_CTRL_CMS_RI_TYPE, 0, &r);
++        if (i > 0)
++            return r;
++    }
++    return CMS_RECIPINFO_TRANS;
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/cms/cms_err.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/cms/cms_err.c
+new file mode 100644
+index 0000000..c6df1b5
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/cms/cms_err.c
+@@ -0,0 +1,258 @@
++/*
++ * Generated by util/mkerr.pl DO NOT EDIT
++ * Copyright 1995-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include 
++#include 
++
++/* BEGIN ERROR CODES */
++#ifndef OPENSSL_NO_ERR
++
++# define ERR_FUNC(func) ERR_PACK(ERR_LIB_CMS,func,0)
++# define ERR_REASON(reason) ERR_PACK(ERR_LIB_CMS,0,reason)
++
++static ERR_STRING_DATA CMS_str_functs[] = {
++    {ERR_FUNC(CMS_F_CHECK_CONTENT), "check_content"},
++    {ERR_FUNC(CMS_F_CMS_ADD0_CERT), "CMS_add0_cert"},
++    {ERR_FUNC(CMS_F_CMS_ADD0_RECIPIENT_KEY), "CMS_add0_recipient_key"},
++    {ERR_FUNC(CMS_F_CMS_ADD0_RECIPIENT_PASSWORD),
++     "CMS_add0_recipient_password"},
++    {ERR_FUNC(CMS_F_CMS_ADD1_RECEIPTREQUEST), "CMS_add1_ReceiptRequest"},
++    {ERR_FUNC(CMS_F_CMS_ADD1_RECIPIENT_CERT), "CMS_add1_recipient_cert"},
++    {ERR_FUNC(CMS_F_CMS_ADD1_SIGNER), "CMS_add1_signer"},
++    {ERR_FUNC(CMS_F_CMS_ADD1_SIGNINGTIME), "cms_add1_signingTime"},
++    {ERR_FUNC(CMS_F_CMS_COMPRESS), "CMS_compress"},
++    {ERR_FUNC(CMS_F_CMS_COMPRESSEDDATA_CREATE), "cms_CompressedData_create"},
++    {ERR_FUNC(CMS_F_CMS_COMPRESSEDDATA_INIT_BIO),
++     "cms_CompressedData_init_bio"},
++    {ERR_FUNC(CMS_F_CMS_COPY_CONTENT), "cms_copy_content"},
++    {ERR_FUNC(CMS_F_CMS_COPY_MESSAGEDIGEST), "cms_copy_messageDigest"},
++    {ERR_FUNC(CMS_F_CMS_DATA), "CMS_data"},
++    {ERR_FUNC(CMS_F_CMS_DATAFINAL), "CMS_dataFinal"},
++    {ERR_FUNC(CMS_F_CMS_DATAINIT), "CMS_dataInit"},
++    {ERR_FUNC(CMS_F_CMS_DECRYPT), "CMS_decrypt"},
++    {ERR_FUNC(CMS_F_CMS_DECRYPT_SET1_KEY), "CMS_decrypt_set1_key"},
++    {ERR_FUNC(CMS_F_CMS_DECRYPT_SET1_PASSWORD), "CMS_decrypt_set1_password"},
++    {ERR_FUNC(CMS_F_CMS_DECRYPT_SET1_PKEY), "CMS_decrypt_set1_pkey"},
++    {ERR_FUNC(CMS_F_CMS_DIGESTALGORITHM_FIND_CTX),
++     "cms_DigestAlgorithm_find_ctx"},
++    {ERR_FUNC(CMS_F_CMS_DIGESTALGORITHM_INIT_BIO),
++     "cms_DigestAlgorithm_init_bio"},
++    {ERR_FUNC(CMS_F_CMS_DIGESTEDDATA_DO_FINAL), "cms_DigestedData_do_final"},
++    {ERR_FUNC(CMS_F_CMS_DIGEST_VERIFY), "CMS_digest_verify"},
++    {ERR_FUNC(CMS_F_CMS_ENCODE_RECEIPT), "cms_encode_Receipt"},
++    {ERR_FUNC(CMS_F_CMS_ENCRYPT), "CMS_encrypt"},
++    {ERR_FUNC(CMS_F_CMS_ENCRYPTEDCONTENT_INIT_BIO),
++     "cms_EncryptedContent_init_bio"},
++    {ERR_FUNC(CMS_F_CMS_ENCRYPTEDDATA_DECRYPT), "CMS_EncryptedData_decrypt"},
++    {ERR_FUNC(CMS_F_CMS_ENCRYPTEDDATA_ENCRYPT), "CMS_EncryptedData_encrypt"},
++    {ERR_FUNC(CMS_F_CMS_ENCRYPTEDDATA_SET1_KEY),
++     "CMS_EncryptedData_set1_key"},
++    {ERR_FUNC(CMS_F_CMS_ENVELOPEDDATA_CREATE), "CMS_EnvelopedData_create"},
++    {ERR_FUNC(CMS_F_CMS_ENVELOPEDDATA_INIT_BIO),
++     "cms_EnvelopedData_init_bio"},
++    {ERR_FUNC(CMS_F_CMS_ENVELOPED_DATA_INIT), "cms_enveloped_data_init"},
++    {ERR_FUNC(CMS_F_CMS_ENV_ASN1_CTRL), "cms_env_asn1_ctrl"},
++    {ERR_FUNC(CMS_F_CMS_FINAL), "CMS_final"},
++    {ERR_FUNC(CMS_F_CMS_GET0_CERTIFICATE_CHOICES),
++     "cms_get0_certificate_choices"},
++    {ERR_FUNC(CMS_F_CMS_GET0_CONTENT), "CMS_get0_content"},
++    {ERR_FUNC(CMS_F_CMS_GET0_ECONTENT_TYPE), "cms_get0_econtent_type"},
++    {ERR_FUNC(CMS_F_CMS_GET0_ENVELOPED), "cms_get0_enveloped"},
++    {ERR_FUNC(CMS_F_CMS_GET0_REVOCATION_CHOICES),
++     "cms_get0_revocation_choices"},
++    {ERR_FUNC(CMS_F_CMS_GET0_SIGNED), "cms_get0_signed"},
++    {ERR_FUNC(CMS_F_CMS_MSGSIGDIGEST_ADD1), "cms_msgSigDigest_add1"},
++    {ERR_FUNC(CMS_F_CMS_RECEIPTREQUEST_CREATE0),
++     "CMS_ReceiptRequest_create0"},
++    {ERR_FUNC(CMS_F_CMS_RECEIPT_VERIFY), "cms_Receipt_verify"},
++    {ERR_FUNC(CMS_F_CMS_RECIPIENTINFO_DECRYPT), "CMS_RecipientInfo_decrypt"},
++    {ERR_FUNC(CMS_F_CMS_RECIPIENTINFO_ENCRYPT), "CMS_RecipientInfo_encrypt"},
++    {ERR_FUNC(CMS_F_CMS_RECIPIENTINFO_KARI_ENCRYPT),
++     "cms_RecipientInfo_kari_encrypt"},
++    {ERR_FUNC(CMS_F_CMS_RECIPIENTINFO_KARI_GET0_ALG),
++     "CMS_RecipientInfo_kari_get0_alg"},
++    {ERR_FUNC(CMS_F_CMS_RECIPIENTINFO_KARI_GET0_ORIG_ID),
++     "CMS_RecipientInfo_kari_get0_orig_id"},
++    {ERR_FUNC(CMS_F_CMS_RECIPIENTINFO_KARI_GET0_REKS),
++     "CMS_RecipientInfo_kari_get0_reks"},
++    {ERR_FUNC(CMS_F_CMS_RECIPIENTINFO_KARI_ORIG_ID_CMP),
++     "CMS_RecipientInfo_kari_orig_id_cmp"},
++    {ERR_FUNC(CMS_F_CMS_RECIPIENTINFO_KEKRI_DECRYPT),
++     "cms_RecipientInfo_kekri_decrypt"},
++    {ERR_FUNC(CMS_F_CMS_RECIPIENTINFO_KEKRI_ENCRYPT),
++     "cms_RecipientInfo_kekri_encrypt"},
++    {ERR_FUNC(CMS_F_CMS_RECIPIENTINFO_KEKRI_GET0_ID),
++     "CMS_RecipientInfo_kekri_get0_id"},
++    {ERR_FUNC(CMS_F_CMS_RECIPIENTINFO_KEKRI_ID_CMP),
++     "CMS_RecipientInfo_kekri_id_cmp"},
++    {ERR_FUNC(CMS_F_CMS_RECIPIENTINFO_KTRI_CERT_CMP),
++     "CMS_RecipientInfo_ktri_cert_cmp"},
++    {ERR_FUNC(CMS_F_CMS_RECIPIENTINFO_KTRI_DECRYPT),
++     "cms_RecipientInfo_ktri_decrypt"},
++    {ERR_FUNC(CMS_F_CMS_RECIPIENTINFO_KTRI_ENCRYPT),
++     "cms_RecipientInfo_ktri_encrypt"},
++    {ERR_FUNC(CMS_F_CMS_RECIPIENTINFO_KTRI_GET0_ALGS),
++     "CMS_RecipientInfo_ktri_get0_algs"},
++    {ERR_FUNC(CMS_F_CMS_RECIPIENTINFO_KTRI_GET0_SIGNER_ID),
++     "CMS_RecipientInfo_ktri_get0_signer_id"},
++    {ERR_FUNC(CMS_F_CMS_RECIPIENTINFO_PWRI_CRYPT),
++     "cms_RecipientInfo_pwri_crypt"},
++    {ERR_FUNC(CMS_F_CMS_RECIPIENTINFO_SET0_KEY),
++     "CMS_RecipientInfo_set0_key"},
++    {ERR_FUNC(CMS_F_CMS_RECIPIENTINFO_SET0_PASSWORD),
++     "CMS_RecipientInfo_set0_password"},
++    {ERR_FUNC(CMS_F_CMS_RECIPIENTINFO_SET0_PKEY),
++     "CMS_RecipientInfo_set0_pkey"},
++    {ERR_FUNC(CMS_F_CMS_SD_ASN1_CTRL), "cms_sd_asn1_ctrl"},
++    {ERR_FUNC(CMS_F_CMS_SET1_IAS), "cms_set1_ias"},
++    {ERR_FUNC(CMS_F_CMS_SET1_KEYID), "cms_set1_keyid"},
++    {ERR_FUNC(CMS_F_CMS_SET1_SIGNERIDENTIFIER), "cms_set1_SignerIdentifier"},
++    {ERR_FUNC(CMS_F_CMS_SET_DETACHED), "CMS_set_detached"},
++    {ERR_FUNC(CMS_F_CMS_SIGN), "CMS_sign"},
++    {ERR_FUNC(CMS_F_CMS_SIGNED_DATA_INIT), "cms_signed_data_init"},
++    {ERR_FUNC(CMS_F_CMS_SIGNERINFO_CONTENT_SIGN),
++     "cms_SignerInfo_content_sign"},
++    {ERR_FUNC(CMS_F_CMS_SIGNERINFO_SIGN), "CMS_SignerInfo_sign"},
++    {ERR_FUNC(CMS_F_CMS_SIGNERINFO_VERIFY), "CMS_SignerInfo_verify"},
++    {ERR_FUNC(CMS_F_CMS_SIGNERINFO_VERIFY_CERT),
++     "cms_signerinfo_verify_cert"},
++    {ERR_FUNC(CMS_F_CMS_SIGNERINFO_VERIFY_CONTENT),
++     "CMS_SignerInfo_verify_content"},
++    {ERR_FUNC(CMS_F_CMS_SIGN_RECEIPT), "CMS_sign_receipt"},
++    {ERR_FUNC(CMS_F_CMS_STREAM), "CMS_stream"},
++    {ERR_FUNC(CMS_F_CMS_UNCOMPRESS), "CMS_uncompress"},
++    {ERR_FUNC(CMS_F_CMS_VERIFY), "CMS_verify"},
++    {0, NULL}
++};
++
++static ERR_STRING_DATA CMS_str_reasons[] = {
++    {ERR_REASON(CMS_R_ADD_SIGNER_ERROR), "add signer error"},
++    {ERR_REASON(CMS_R_CERTIFICATE_ALREADY_PRESENT),
++     "certificate already present"},
++    {ERR_REASON(CMS_R_CERTIFICATE_HAS_NO_KEYID), "certificate has no keyid"},
++    {ERR_REASON(CMS_R_CERTIFICATE_VERIFY_ERROR), "certificate verify error"},
++    {ERR_REASON(CMS_R_CIPHER_INITIALISATION_ERROR),
++     "cipher initialisation error"},
++    {ERR_REASON(CMS_R_CIPHER_PARAMETER_INITIALISATION_ERROR),
++     "cipher parameter initialisation error"},
++    {ERR_REASON(CMS_R_CMS_DATAFINAL_ERROR), "cms datafinal error"},
++    {ERR_REASON(CMS_R_CMS_LIB), "cms lib"},
++    {ERR_REASON(CMS_R_CONTENTIDENTIFIER_MISMATCH),
++     "contentidentifier mismatch"},
++    {ERR_REASON(CMS_R_CONTENT_NOT_FOUND), "content not found"},
++    {ERR_REASON(CMS_R_CONTENT_TYPE_MISMATCH), "content type mismatch"},
++    {ERR_REASON(CMS_R_CONTENT_TYPE_NOT_COMPRESSED_DATA),
++     "content type not compressed data"},
++    {ERR_REASON(CMS_R_CONTENT_TYPE_NOT_ENVELOPED_DATA),
++     "content type not enveloped data"},
++    {ERR_REASON(CMS_R_CONTENT_TYPE_NOT_SIGNED_DATA),
++     "content type not signed data"},
++    {ERR_REASON(CMS_R_CONTENT_VERIFY_ERROR), "content verify error"},
++    {ERR_REASON(CMS_R_CTRL_ERROR), "ctrl error"},
++    {ERR_REASON(CMS_R_CTRL_FAILURE), "ctrl failure"},
++    {ERR_REASON(CMS_R_DECRYPT_ERROR), "decrypt error"},
++    {ERR_REASON(CMS_R_ERROR_GETTING_PUBLIC_KEY), "error getting public key"},
++    {ERR_REASON(CMS_R_ERROR_READING_MESSAGEDIGEST_ATTRIBUTE),
++     "error reading messagedigest attribute"},
++    {ERR_REASON(CMS_R_ERROR_SETTING_KEY), "error setting key"},
++    {ERR_REASON(CMS_R_ERROR_SETTING_RECIPIENTINFO),
++     "error setting recipientinfo"},
++    {ERR_REASON(CMS_R_INVALID_ENCRYPTED_KEY_LENGTH),
++     "invalid encrypted key length"},
++    {ERR_REASON(CMS_R_INVALID_KEY_ENCRYPTION_PARAMETER),
++     "invalid key encryption parameter"},
++    {ERR_REASON(CMS_R_INVALID_KEY_LENGTH), "invalid key length"},
++    {ERR_REASON(CMS_R_MD_BIO_INIT_ERROR), "md bio init error"},
++    {ERR_REASON(CMS_R_MESSAGEDIGEST_ATTRIBUTE_WRONG_LENGTH),
++     "messagedigest attribute wrong length"},
++    {ERR_REASON(CMS_R_MESSAGEDIGEST_WRONG_LENGTH),
++     "messagedigest wrong length"},
++    {ERR_REASON(CMS_R_MSGSIGDIGEST_ERROR), "msgsigdigest error"},
++    {ERR_REASON(CMS_R_MSGSIGDIGEST_VERIFICATION_FAILURE),
++     "msgsigdigest verification failure"},
++    {ERR_REASON(CMS_R_MSGSIGDIGEST_WRONG_LENGTH),
++     "msgsigdigest wrong length"},
++    {ERR_REASON(CMS_R_NEED_ONE_SIGNER), "need one signer"},
++    {ERR_REASON(CMS_R_NOT_A_SIGNED_RECEIPT), "not a signed receipt"},
++    {ERR_REASON(CMS_R_NOT_ENCRYPTED_DATA), "not encrypted data"},
++    {ERR_REASON(CMS_R_NOT_KEK), "not kek"},
++    {ERR_REASON(CMS_R_NOT_KEY_AGREEMENT), "not key agreement"},
++    {ERR_REASON(CMS_R_NOT_KEY_TRANSPORT), "not key transport"},
++    {ERR_REASON(CMS_R_NOT_PWRI), "not pwri"},
++    {ERR_REASON(CMS_R_NOT_SUPPORTED_FOR_THIS_KEY_TYPE),
++     "not supported for this key type"},
++    {ERR_REASON(CMS_R_NO_CIPHER), "no cipher"},
++    {ERR_REASON(CMS_R_NO_CONTENT), "no content"},
++    {ERR_REASON(CMS_R_NO_CONTENT_TYPE), "no content type"},
++    {ERR_REASON(CMS_R_NO_DEFAULT_DIGEST), "no default digest"},
++    {ERR_REASON(CMS_R_NO_DIGEST_SET), "no digest set"},
++    {ERR_REASON(CMS_R_NO_KEY), "no key"},
++    {ERR_REASON(CMS_R_NO_KEY_OR_CERT), "no key or cert"},
++    {ERR_REASON(CMS_R_NO_MATCHING_DIGEST), "no matching digest"},
++    {ERR_REASON(CMS_R_NO_MATCHING_RECIPIENT), "no matching recipient"},
++    {ERR_REASON(CMS_R_NO_MATCHING_SIGNATURE), "no matching signature"},
++    {ERR_REASON(CMS_R_NO_MSGSIGDIGEST), "no msgsigdigest"},
++    {ERR_REASON(CMS_R_NO_PASSWORD), "no password"},
++    {ERR_REASON(CMS_R_NO_PRIVATE_KEY), "no private key"},
++    {ERR_REASON(CMS_R_NO_PUBLIC_KEY), "no public key"},
++    {ERR_REASON(CMS_R_NO_RECEIPT_REQUEST), "no receipt request"},
++    {ERR_REASON(CMS_R_NO_SIGNERS), "no signers"},
++    {ERR_REASON(CMS_R_PRIVATE_KEY_DOES_NOT_MATCH_CERTIFICATE),
++     "private key does not match certificate"},
++    {ERR_REASON(CMS_R_RECEIPT_DECODE_ERROR), "receipt decode error"},
++    {ERR_REASON(CMS_R_RECIPIENT_ERROR), "recipient error"},
++    {ERR_REASON(CMS_R_SIGNER_CERTIFICATE_NOT_FOUND),
++     "signer certificate not found"},
++    {ERR_REASON(CMS_R_SIGNFINAL_ERROR), "signfinal error"},
++    {ERR_REASON(CMS_R_SMIME_TEXT_ERROR), "smime text error"},
++    {ERR_REASON(CMS_R_STORE_INIT_ERROR), "store init error"},
++    {ERR_REASON(CMS_R_TYPE_NOT_COMPRESSED_DATA), "type not compressed data"},
++    {ERR_REASON(CMS_R_TYPE_NOT_DATA), "type not data"},
++    {ERR_REASON(CMS_R_TYPE_NOT_DIGESTED_DATA), "type not digested data"},
++    {ERR_REASON(CMS_R_TYPE_NOT_ENCRYPTED_DATA), "type not encrypted data"},
++    {ERR_REASON(CMS_R_TYPE_NOT_ENVELOPED_DATA), "type not enveloped data"},
++    {ERR_REASON(CMS_R_UNABLE_TO_FINALIZE_CONTEXT),
++     "unable to finalize context"},
++    {ERR_REASON(CMS_R_UNKNOWN_CIPHER), "unknown cipher"},
++    {ERR_REASON(CMS_R_UNKNOWN_DIGEST_ALGORIHM), "unknown digest algorihm"},
++    {ERR_REASON(CMS_R_UNKNOWN_ID), "unknown id"},
++    {ERR_REASON(CMS_R_UNSUPPORTED_COMPRESSION_ALGORITHM),
++     "unsupported compression algorithm"},
++    {ERR_REASON(CMS_R_UNSUPPORTED_CONTENT_TYPE), "unsupported content type"},
++    {ERR_REASON(CMS_R_UNSUPPORTED_KEK_ALGORITHM),
++     "unsupported kek algorithm"},
++    {ERR_REASON(CMS_R_UNSUPPORTED_KEY_ENCRYPTION_ALGORITHM),
++     "unsupported key encryption algorithm"},
++    {ERR_REASON(CMS_R_UNSUPPORTED_RECIPIENT_TYPE),
++     "unsupported recipient type"},
++    {ERR_REASON(CMS_R_UNSUPPORTED_RECPIENTINFO_TYPE),
++     "unsupported recpientinfo type"},
++    {ERR_REASON(CMS_R_UNSUPPORTED_TYPE), "unsupported type"},
++    {ERR_REASON(CMS_R_UNWRAP_ERROR), "unwrap error"},
++    {ERR_REASON(CMS_R_UNWRAP_FAILURE), "unwrap failure"},
++    {ERR_REASON(CMS_R_VERIFICATION_FAILURE), "verification failure"},
++    {ERR_REASON(CMS_R_WRAP_ERROR), "wrap error"},
++    {0, NULL}
++};
++
++#endif
++
++int ERR_load_CMS_strings(void)
++{
++#ifndef OPENSSL_NO_ERR
++
++    if (ERR_func_error_string(CMS_str_functs[0].error) == NULL) {
++        ERR_load_strings(0, CMS_str_functs);
++        ERR_load_strings(0, CMS_str_reasons);
++    }
++#endif
++    return 1;
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/cms/cms_ess.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/cms/cms_ess.c
+new file mode 100644
+index 0000000..4780231
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/cms/cms_ess.c
+@@ -0,0 +1,337 @@
++/*
++ * Copyright 2008-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include "internal/cryptlib.h"
++#include 
++#include 
++#include 
++#include 
++#include 
++#include 
++#include "cms_lcl.h"
++
++IMPLEMENT_ASN1_FUNCTIONS(CMS_ReceiptRequest)
++
++/* ESS services: for now just Signed Receipt related */
++
++int CMS_get1_ReceiptRequest(CMS_SignerInfo *si, CMS_ReceiptRequest **prr)
++{
++    ASN1_STRING *str;
++    CMS_ReceiptRequest *rr = NULL;
++    if (prr)
++        *prr = NULL;
++    str = CMS_signed_get0_data_by_OBJ(si,
++                                      OBJ_nid2obj
++                                      (NID_id_smime_aa_receiptRequest), -3,
++                                      V_ASN1_SEQUENCE);
++    if (!str)
++        return 0;
++
++    rr = ASN1_item_unpack(str, ASN1_ITEM_rptr(CMS_ReceiptRequest));
++    if (!rr)
++        return -1;
++    if (prr)
++        *prr = rr;
++    else
++        CMS_ReceiptRequest_free(rr);
++    return 1;
++}
++
++CMS_ReceiptRequest *CMS_ReceiptRequest_create0(unsigned char *id, int idlen,
++                                               int allorfirst,
++                                               STACK_OF(GENERAL_NAMES)
++                                               *receiptList, STACK_OF(GENERAL_NAMES)
++                                               *receiptsTo)
++{
++    CMS_ReceiptRequest *rr = NULL;
++
++    rr = CMS_ReceiptRequest_new();
++    if (rr == NULL)
++        goto merr;
++    if (id)
++        ASN1_STRING_set0(rr->signedContentIdentifier, id, idlen);
++    else {
++        if (!ASN1_STRING_set(rr->signedContentIdentifier, NULL, 32))
++            goto merr;
++        if (RAND_bytes(rr->signedContentIdentifier->data, 32) <= 0)
++            goto err;
++    }
++
++    sk_GENERAL_NAMES_pop_free(rr->receiptsTo, GENERAL_NAMES_free);
++    rr->receiptsTo = receiptsTo;
++
++    if (receiptList) {
++        rr->receiptsFrom->type = 1;
++        rr->receiptsFrom->d.receiptList = receiptList;
++    } else {
++        rr->receiptsFrom->type = 0;
++        rr->receiptsFrom->d.allOrFirstTier = allorfirst;
++    }
++
++    return rr;
++
++ merr:
++    CMSerr(CMS_F_CMS_RECEIPTREQUEST_CREATE0, ERR_R_MALLOC_FAILURE);
++
++ err:
++    CMS_ReceiptRequest_free(rr);
++    return NULL;
++
++}
++
++int CMS_add1_ReceiptRequest(CMS_SignerInfo *si, CMS_ReceiptRequest *rr)
++{
++    unsigned char *rrder = NULL;
++    int rrderlen, r = 0;
++
++    rrderlen = i2d_CMS_ReceiptRequest(rr, &rrder);
++    if (rrderlen < 0)
++        goto merr;
++
++    if (!CMS_signed_add1_attr_by_NID(si, NID_id_smime_aa_receiptRequest,
++                                     V_ASN1_SEQUENCE, rrder, rrderlen))
++        goto merr;
++
++    r = 1;
++
++ merr:
++    if (!r)
++        CMSerr(CMS_F_CMS_ADD1_RECEIPTREQUEST, ERR_R_MALLOC_FAILURE);
++
++    OPENSSL_free(rrder);
++
++    return r;
++
++}
++
++void CMS_ReceiptRequest_get0_values(CMS_ReceiptRequest *rr,
++                                    ASN1_STRING **pcid,
++                                    int *pallorfirst,
++                                    STACK_OF(GENERAL_NAMES) **plist,
++                                    STACK_OF(GENERAL_NAMES) **prto)
++{
++    if (pcid)
++        *pcid = rr->signedContentIdentifier;
++    if (rr->receiptsFrom->type == 0) {
++        if (pallorfirst)
++            *pallorfirst = (int)rr->receiptsFrom->d.allOrFirstTier;
++        if (plist)
++            *plist = NULL;
++    } else {
++        if (pallorfirst)
++            *pallorfirst = -1;
++        if (plist)
++            *plist = rr->receiptsFrom->d.receiptList;
++    }
++    if (prto)
++        *prto = rr->receiptsTo;
++}
++
++/* Digest a SignerInfo structure for msgSigDigest attribute processing */
++
++static int cms_msgSigDigest(CMS_SignerInfo *si,
++                            unsigned char *dig, unsigned int *diglen)
++{
++    const EVP_MD *md;
++    md = EVP_get_digestbyobj(si->digestAlgorithm->algorithm);
++    if (md == NULL)
++        return 0;
++    if (!ASN1_item_digest(ASN1_ITEM_rptr(CMS_Attributes_Verify), md,
++                          si->signedAttrs, dig, diglen))
++        return 0;
++    return 1;
++}
++
++/* Add a msgSigDigest attribute to a SignerInfo */
++
++int cms_msgSigDigest_add1(CMS_SignerInfo *dest, CMS_SignerInfo *src)
++{
++    unsigned char dig[EVP_MAX_MD_SIZE];
++    unsigned int diglen;
++    if (!cms_msgSigDigest(src, dig, &diglen)) {
++        CMSerr(CMS_F_CMS_MSGSIGDIGEST_ADD1, CMS_R_MSGSIGDIGEST_ERROR);
++        return 0;
++    }
++    if (!CMS_signed_add1_attr_by_NID(dest, NID_id_smime_aa_msgSigDigest,
++                                     V_ASN1_OCTET_STRING, dig, diglen)) {
++        CMSerr(CMS_F_CMS_MSGSIGDIGEST_ADD1, ERR_R_MALLOC_FAILURE);
++        return 0;
++    }
++    return 1;
++}
++
++/* Verify signed receipt after it has already passed normal CMS verify */
++
++int cms_Receipt_verify(CMS_ContentInfo *cms, CMS_ContentInfo *req_cms)
++{
++    int r = 0, i;
++    CMS_ReceiptRequest *rr = NULL;
++    CMS_Receipt *rct = NULL;
++    STACK_OF(CMS_SignerInfo) *sis, *osis;
++    CMS_SignerInfo *si, *osi = NULL;
++    ASN1_OCTET_STRING *msig, **pcont;
++    ASN1_OBJECT *octype;
++    unsigned char dig[EVP_MAX_MD_SIZE];
++    unsigned int diglen;
++
++    /* Get SignerInfos, also checks SignedData content type */
++    osis = CMS_get0_SignerInfos(req_cms);
++    sis = CMS_get0_SignerInfos(cms);
++    if (!osis || !sis)
++        goto err;
++
++    if (sk_CMS_SignerInfo_num(sis) != 1) {
++        CMSerr(CMS_F_CMS_RECEIPT_VERIFY, CMS_R_NEED_ONE_SIGNER);
++        goto err;
++    }
++
++    /* Check receipt content type */
++    if (OBJ_obj2nid(CMS_get0_eContentType(cms)) != NID_id_smime_ct_receipt) {
++        CMSerr(CMS_F_CMS_RECEIPT_VERIFY, CMS_R_NOT_A_SIGNED_RECEIPT);
++        goto err;
++    }
++
++    /* Extract and decode receipt content */
++    pcont = CMS_get0_content(cms);
++    if (!pcont || !*pcont) {
++        CMSerr(CMS_F_CMS_RECEIPT_VERIFY, CMS_R_NO_CONTENT);
++        goto err;
++    }
++
++    rct = ASN1_item_unpack(*pcont, ASN1_ITEM_rptr(CMS_Receipt));
++
++    if (!rct) {
++        CMSerr(CMS_F_CMS_RECEIPT_VERIFY, CMS_R_RECEIPT_DECODE_ERROR);
++        goto err;
++    }
++
++    /* Locate original request */
++
++    for (i = 0; i < sk_CMS_SignerInfo_num(osis); i++) {
++        osi = sk_CMS_SignerInfo_value(osis, i);
++        if (!ASN1_STRING_cmp(osi->signature, rct->originatorSignatureValue))
++            break;
++    }
++
++    if (i == sk_CMS_SignerInfo_num(osis)) {
++        CMSerr(CMS_F_CMS_RECEIPT_VERIFY, CMS_R_NO_MATCHING_SIGNATURE);
++        goto err;
++    }
++
++    si = sk_CMS_SignerInfo_value(sis, 0);
++
++    /* Get msgSigDigest value and compare */
++
++    msig = CMS_signed_get0_data_by_OBJ(si,
++                                       OBJ_nid2obj
++                                       (NID_id_smime_aa_msgSigDigest), -3,
++                                       V_ASN1_OCTET_STRING);
++
++    if (!msig) {
++        CMSerr(CMS_F_CMS_RECEIPT_VERIFY, CMS_R_NO_MSGSIGDIGEST);
++        goto err;
++    }
++
++    if (!cms_msgSigDigest(osi, dig, &diglen)) {
++        CMSerr(CMS_F_CMS_RECEIPT_VERIFY, CMS_R_MSGSIGDIGEST_ERROR);
++        goto err;
++    }
++
++    if (diglen != (unsigned int)msig->length) {
++        CMSerr(CMS_F_CMS_RECEIPT_VERIFY, CMS_R_MSGSIGDIGEST_WRONG_LENGTH);
++        goto err;
++    }
++
++    if (memcmp(dig, msig->data, diglen)) {
++        CMSerr(CMS_F_CMS_RECEIPT_VERIFY,
++               CMS_R_MSGSIGDIGEST_VERIFICATION_FAILURE);
++        goto err;
++    }
++
++    /* Compare content types */
++
++    octype = CMS_signed_get0_data_by_OBJ(osi,
++                                         OBJ_nid2obj(NID_pkcs9_contentType),
++                                         -3, V_ASN1_OBJECT);
++    if (!octype) {
++        CMSerr(CMS_F_CMS_RECEIPT_VERIFY, CMS_R_NO_CONTENT_TYPE);
++        goto err;
++    }
++
++    /* Compare details in receipt request */
++
++    if (OBJ_cmp(octype, rct->contentType)) {
++        CMSerr(CMS_F_CMS_RECEIPT_VERIFY, CMS_R_CONTENT_TYPE_MISMATCH);
++        goto err;
++    }
++
++    /* Get original receipt request details */
++
++    if (CMS_get1_ReceiptRequest(osi, &rr) <= 0) {
++        CMSerr(CMS_F_CMS_RECEIPT_VERIFY, CMS_R_NO_RECEIPT_REQUEST);
++        goto err;
++    }
++
++    if (ASN1_STRING_cmp(rr->signedContentIdentifier,
++                        rct->signedContentIdentifier)) {
++        CMSerr(CMS_F_CMS_RECEIPT_VERIFY, CMS_R_CONTENTIDENTIFIER_MISMATCH);
++        goto err;
++    }
++
++    r = 1;
++
++ err:
++    CMS_ReceiptRequest_free(rr);
++    M_ASN1_free_of(rct, CMS_Receipt);
++    return r;
++
++}
++
++/*
++ * Encode a Receipt into an OCTET STRING read for including into content of a
++ * SignedData ContentInfo.
++ */
++
++ASN1_OCTET_STRING *cms_encode_Receipt(CMS_SignerInfo *si)
++{
++    CMS_Receipt rct;
++    CMS_ReceiptRequest *rr = NULL;
++    ASN1_OBJECT *ctype;
++    ASN1_OCTET_STRING *os = NULL;
++
++    /* Get original receipt request */
++
++    /* Get original receipt request details */
++
++    if (CMS_get1_ReceiptRequest(si, &rr) <= 0) {
++        CMSerr(CMS_F_CMS_ENCODE_RECEIPT, CMS_R_NO_RECEIPT_REQUEST);
++        goto err;
++    }
++
++    /* Get original content type */
++
++    ctype = CMS_signed_get0_data_by_OBJ(si,
++                                        OBJ_nid2obj(NID_pkcs9_contentType),
++                                        -3, V_ASN1_OBJECT);
++    if (!ctype) {
++        CMSerr(CMS_F_CMS_ENCODE_RECEIPT, CMS_R_NO_CONTENT_TYPE);
++        goto err;
++    }
++
++    rct.version = 1;
++    rct.contentType = ctype;
++    rct.signedContentIdentifier = rr->signedContentIdentifier;
++    rct.originatorSignatureValue = si->signature;
++
++    os = ASN1_item_pack(&rct, ASN1_ITEM_rptr(CMS_Receipt), NULL);
++
++ err:
++    CMS_ReceiptRequest_free(rr);
++    return os;
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/cms/cms_io.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/cms/cms_io.c
+new file mode 100644
+index 0000000..d18f980
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/cms/cms_io.c
+@@ -0,0 +1,88 @@
++/*
++ * Copyright 2008-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include 
++#include 
++#include 
++#include 
++#include "cms_lcl.h"
++
++int CMS_stream(unsigned char ***boundary, CMS_ContentInfo *cms)
++{
++    ASN1_OCTET_STRING **pos;
++    pos = CMS_get0_content(cms);
++    if (pos == NULL)
++        return 0;
++    if (*pos == NULL)
++        *pos = ASN1_OCTET_STRING_new();
++    if (*pos != NULL) {
++        (*pos)->flags |= ASN1_STRING_FLAG_NDEF;
++        (*pos)->flags &= ~ASN1_STRING_FLAG_CONT;
++        *boundary = &(*pos)->data;
++        return 1;
++    }
++    CMSerr(CMS_F_CMS_STREAM, ERR_R_MALLOC_FAILURE);
++    return 0;
++}
++
++CMS_ContentInfo *d2i_CMS_bio(BIO *bp, CMS_ContentInfo **cms)
++{
++    return ASN1_item_d2i_bio(ASN1_ITEM_rptr(CMS_ContentInfo), bp, cms);
++}
++
++int i2d_CMS_bio(BIO *bp, CMS_ContentInfo *cms)
++{
++    return ASN1_item_i2d_bio(ASN1_ITEM_rptr(CMS_ContentInfo), bp, cms);
++}
++
++IMPLEMENT_PEM_rw_const(CMS, CMS_ContentInfo, PEM_STRING_CMS, CMS_ContentInfo)
++
++BIO *BIO_new_CMS(BIO *out, CMS_ContentInfo *cms)
++{
++    return BIO_new_NDEF(out, (ASN1_VALUE *)cms,
++                        ASN1_ITEM_rptr(CMS_ContentInfo));
++}
++
++/* CMS wrappers round generalised stream and MIME routines */
++
++int i2d_CMS_bio_stream(BIO *out, CMS_ContentInfo *cms, BIO *in, int flags)
++{
++    return i2d_ASN1_bio_stream(out, (ASN1_VALUE *)cms, in, flags,
++                               ASN1_ITEM_rptr(CMS_ContentInfo));
++}
++
++int PEM_write_bio_CMS_stream(BIO *out, CMS_ContentInfo *cms, BIO *in,
++                             int flags)
++{
++    return PEM_write_bio_ASN1_stream(out, (ASN1_VALUE *)cms, in, flags,
++                                     "CMS", ASN1_ITEM_rptr(CMS_ContentInfo));
++}
++
++int SMIME_write_CMS(BIO *bio, CMS_ContentInfo *cms, BIO *data, int flags)
++{
++    STACK_OF(X509_ALGOR) *mdalgs;
++    int ctype_nid = OBJ_obj2nid(cms->contentType);
++    int econt_nid = OBJ_obj2nid(CMS_get0_eContentType(cms));
++    if (ctype_nid == NID_pkcs7_signed)
++        mdalgs = cms->d.signedData->digestAlgorithms;
++    else
++        mdalgs = NULL;
++
++    return SMIME_write_ASN1(bio, (ASN1_VALUE *)cms, data, flags,
++                            ctype_nid, econt_nid, mdalgs,
++                            ASN1_ITEM_rptr(CMS_ContentInfo));
++}
++
++CMS_ContentInfo *SMIME_read_CMS(BIO *bio, BIO **bcont)
++{
++    return (CMS_ContentInfo *)SMIME_read_ASN1(bio, bcont,
++                                              ASN1_ITEM_rptr
++                                              (CMS_ContentInfo));
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/cms/cms_kari.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/cms/cms_kari.c
+new file mode 100644
+index 0000000..3bc46fe
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/cms/cms_kari.c
+@@ -0,0 +1,411 @@
++/*
++ * Copyright 2013-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include "internal/cryptlib.h"
++#include 
++#include 
++#include 
++#include 
++#include 
++#include 
++#include "cms_lcl.h"
++#include "internal/asn1_int.h"
++
++/* Key Agreement Recipient Info (KARI) routines */
++
++int CMS_RecipientInfo_kari_get0_alg(CMS_RecipientInfo *ri,
++                                    X509_ALGOR **palg,
++                                    ASN1_OCTET_STRING **pukm)
++{
++    if (ri->type != CMS_RECIPINFO_AGREE) {
++        CMSerr(CMS_F_CMS_RECIPIENTINFO_KARI_GET0_ALG,
++               CMS_R_NOT_KEY_AGREEMENT);
++        return 0;
++    }
++    if (palg)
++        *palg = ri->d.kari->keyEncryptionAlgorithm;
++    if (pukm)
++        *pukm = ri->d.kari->ukm;
++    return 1;
++}
++
++/* Retrieve recipient encrypted keys from a kari */
++
++STACK_OF(CMS_RecipientEncryptedKey)
++*CMS_RecipientInfo_kari_get0_reks(CMS_RecipientInfo *ri)
++{
++    if (ri->type != CMS_RECIPINFO_AGREE) {
++        CMSerr(CMS_F_CMS_RECIPIENTINFO_KARI_GET0_REKS,
++               CMS_R_NOT_KEY_AGREEMENT);
++        return NULL;
++    }
++    return ri->d.kari->recipientEncryptedKeys;
++}
++
++int CMS_RecipientInfo_kari_get0_orig_id(CMS_RecipientInfo *ri,
++                                        X509_ALGOR **pubalg,
++                                        ASN1_BIT_STRING **pubkey,
++                                        ASN1_OCTET_STRING **keyid,
++                                        X509_NAME **issuer,
++                                        ASN1_INTEGER **sno)
++{
++    CMS_OriginatorIdentifierOrKey *oik;
++    if (ri->type != CMS_RECIPINFO_AGREE) {
++        CMSerr(CMS_F_CMS_RECIPIENTINFO_KARI_GET0_ORIG_ID,
++               CMS_R_NOT_KEY_AGREEMENT);
++        return 0;
++    }
++    oik = ri->d.kari->originator;
++    if (issuer)
++        *issuer = NULL;
++    if (sno)
++        *sno = NULL;
++    if (keyid)
++        *keyid = NULL;
++    if (pubalg)
++        *pubalg = NULL;
++    if (pubkey)
++        *pubkey = NULL;
++    if (oik->type == CMS_OIK_ISSUER_SERIAL) {
++        if (issuer)
++            *issuer = oik->d.issuerAndSerialNumber->issuer;
++        if (sno)
++            *sno = oik->d.issuerAndSerialNumber->serialNumber;
++    } else if (oik->type == CMS_OIK_KEYIDENTIFIER) {
++        if (keyid)
++            *keyid = oik->d.subjectKeyIdentifier;
++    } else if (oik->type == CMS_OIK_PUBKEY) {
++        if (pubalg)
++            *pubalg = oik->d.originatorKey->algorithm;
++        if (pubkey)
++            *pubkey = oik->d.originatorKey->publicKey;
++    } else
++        return 0;
++    return 1;
++}
++
++int CMS_RecipientInfo_kari_orig_id_cmp(CMS_RecipientInfo *ri, X509 *cert)
++{
++    CMS_OriginatorIdentifierOrKey *oik;
++    if (ri->type != CMS_RECIPINFO_AGREE) {
++        CMSerr(CMS_F_CMS_RECIPIENTINFO_KARI_ORIG_ID_CMP,
++               CMS_R_NOT_KEY_AGREEMENT);
++        return -2;
++    }
++    oik = ri->d.kari->originator;
++    if (oik->type == CMS_OIK_ISSUER_SERIAL)
++        return cms_ias_cert_cmp(oik->d.issuerAndSerialNumber, cert);
++    else if (oik->type == CMS_OIK_KEYIDENTIFIER)
++        return cms_keyid_cert_cmp(oik->d.subjectKeyIdentifier, cert);
++    return -1;
++}
++
++int CMS_RecipientEncryptedKey_get0_id(CMS_RecipientEncryptedKey *rek,
++                                      ASN1_OCTET_STRING **keyid,
++                                      ASN1_GENERALIZEDTIME **tm,
++                                      CMS_OtherKeyAttribute **other,
++                                      X509_NAME **issuer, ASN1_INTEGER **sno)
++{
++    CMS_KeyAgreeRecipientIdentifier *rid = rek->rid;
++    if (rid->type == CMS_REK_ISSUER_SERIAL) {
++        if (issuer)
++            *issuer = rid->d.issuerAndSerialNumber->issuer;
++        if (sno)
++            *sno = rid->d.issuerAndSerialNumber->serialNumber;
++        if (keyid)
++            *keyid = NULL;
++        if (tm)
++            *tm = NULL;
++        if (other)
++            *other = NULL;
++    } else if (rid->type == CMS_REK_KEYIDENTIFIER) {
++        if (keyid)
++            *keyid = rid->d.rKeyId->subjectKeyIdentifier;
++        if (tm)
++            *tm = rid->d.rKeyId->date;
++        if (other)
++            *other = rid->d.rKeyId->other;
++        if (issuer)
++            *issuer = NULL;
++        if (sno)
++            *sno = NULL;
++    } else
++        return 0;
++    return 1;
++}
++
++int CMS_RecipientEncryptedKey_cert_cmp(CMS_RecipientEncryptedKey *rek,
++                                       X509 *cert)
++{
++    CMS_KeyAgreeRecipientIdentifier *rid = rek->rid;
++    if (rid->type == CMS_REK_ISSUER_SERIAL)
++        return cms_ias_cert_cmp(rid->d.issuerAndSerialNumber, cert);
++    else if (rid->type == CMS_REK_KEYIDENTIFIER)
++        return cms_keyid_cert_cmp(rid->d.rKeyId->subjectKeyIdentifier, cert);
++    else
++        return -1;
++}
++
++int CMS_RecipientInfo_kari_set0_pkey(CMS_RecipientInfo *ri, EVP_PKEY *pk)
++{
++    EVP_PKEY_CTX *pctx;
++    CMS_KeyAgreeRecipientInfo *kari = ri->d.kari;
++
++    EVP_PKEY_CTX_free(kari->pctx);
++    kari->pctx = NULL;
++    if (!pk)
++        return 1;
++    pctx = EVP_PKEY_CTX_new(pk, NULL);
++    if (!pctx || !EVP_PKEY_derive_init(pctx))
++        goto err;
++    kari->pctx = pctx;
++    return 1;
++ err:
++    EVP_PKEY_CTX_free(pctx);
++    return 0;
++}
++
++EVP_CIPHER_CTX *CMS_RecipientInfo_kari_get0_ctx(CMS_RecipientInfo *ri)
++{
++    if (ri->type == CMS_RECIPINFO_AGREE)
++        return ri->d.kari->ctx;
++    return NULL;
++}
++
++/*
++ * Derive KEK and decrypt/encrypt with it to produce either the original CEK
++ * or the encrypted CEK.
++ */
++
++static int cms_kek_cipher(unsigned char **pout, size_t *poutlen,
++                          const unsigned char *in, size_t inlen,
++                          CMS_KeyAgreeRecipientInfo *kari, int enc)
++{
++    /* Key encryption key */
++    unsigned char kek[EVP_MAX_KEY_LENGTH];
++    size_t keklen;
++    int rv = 0;
++    unsigned char *out = NULL;
++    int outlen;
++    keklen = EVP_CIPHER_CTX_key_length(kari->ctx);
++    if (keklen > EVP_MAX_KEY_LENGTH)
++        return 0;
++    /* Derive KEK */
++    if (EVP_PKEY_derive(kari->pctx, kek, &keklen) <= 0)
++        goto err;
++    /* Set KEK in context */
++    if (!EVP_CipherInit_ex(kari->ctx, NULL, NULL, kek, NULL, enc))
++        goto err;
++    /* obtain output length of ciphered key */
++    if (!EVP_CipherUpdate(kari->ctx, NULL, &outlen, in, inlen))
++        goto err;
++    out = OPENSSL_malloc(outlen);
++    if (out == NULL)
++        goto err;
++    if (!EVP_CipherUpdate(kari->ctx, out, &outlen, in, inlen))
++        goto err;
++    *pout = out;
++    *poutlen = (size_t)outlen;
++    rv = 1;
++
++ err:
++    OPENSSL_cleanse(kek, keklen);
++    if (!rv)
++        OPENSSL_free(out);
++    EVP_CIPHER_CTX_reset(kari->ctx);
++    /* FIXME: WHY IS kari->pctx freed here?  /RL */
++    EVP_PKEY_CTX_free(kari->pctx);
++    kari->pctx = NULL;
++    return rv;
++}
++
++int CMS_RecipientInfo_kari_decrypt(CMS_ContentInfo *cms,
++                                   CMS_RecipientInfo *ri,
++                                   CMS_RecipientEncryptedKey *rek)
++{
++    int rv = 0;
++    unsigned char *enckey = NULL, *cek = NULL;
++    size_t enckeylen;
++    size_t ceklen;
++    CMS_EncryptedContentInfo *ec;
++    enckeylen = rek->encryptedKey->length;
++    enckey = rek->encryptedKey->data;
++    /* Setup all parameters to derive KEK */
++    if (!cms_env_asn1_ctrl(ri, 1))
++        goto err;
++    /* Attempt to decrypt CEK */
++    if (!cms_kek_cipher(&cek, &ceklen, enckey, enckeylen, ri->d.kari, 0))
++        goto err;
++    ec = cms->d.envelopedData->encryptedContentInfo;
++    OPENSSL_clear_free(ec->key, ec->keylen);
++    ec->key = cek;
++    ec->keylen = ceklen;
++    cek = NULL;
++    rv = 1;
++ err:
++    OPENSSL_free(cek);
++    return rv;
++}
++
++/* Create ephemeral key and initialise context based on it */
++static int cms_kari_create_ephemeral_key(CMS_KeyAgreeRecipientInfo *kari,
++                                         EVP_PKEY *pk)
++{
++    EVP_PKEY_CTX *pctx = NULL;
++    EVP_PKEY *ekey = NULL;
++    int rv = 0;
++    pctx = EVP_PKEY_CTX_new(pk, NULL);
++    if (!pctx)
++        goto err;
++    if (EVP_PKEY_keygen_init(pctx) <= 0)
++        goto err;
++    if (EVP_PKEY_keygen(pctx, &ekey) <= 0)
++        goto err;
++    EVP_PKEY_CTX_free(pctx);
++    pctx = EVP_PKEY_CTX_new(ekey, 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);
++    EVP_PKEY_free(ekey);
++    return rv;
++}
++
++/* Initialise a ktri based on passed certificate and key */
++
++int cms_RecipientInfo_kari_init(CMS_RecipientInfo *ri, X509 *recip,
++                                EVP_PKEY *pk, unsigned int flags)
++{
++    CMS_KeyAgreeRecipientInfo *kari;
++    CMS_RecipientEncryptedKey *rek = NULL;
++
++    ri->d.kari = M_ASN1_new_of(CMS_KeyAgreeRecipientInfo);
++    if (!ri->d.kari)
++        return 0;
++    ri->type = CMS_RECIPINFO_AGREE;
++
++    kari = ri->d.kari;
++    kari->version = 3;
++
++    rek = M_ASN1_new_of(CMS_RecipientEncryptedKey);
++    if (!sk_CMS_RecipientEncryptedKey_push(kari->recipientEncryptedKeys, rek)) {
++        M_ASN1_free_of(rek, CMS_RecipientEncryptedKey);
++        return 0;
++    }
++
++    if (flags & CMS_USE_KEYID) {
++        rek->rid->type = CMS_REK_KEYIDENTIFIER;
++        rek->rid->d.rKeyId = M_ASN1_new_of(CMS_RecipientKeyIdentifier);
++        if (rek->rid->d.rKeyId == NULL)
++            return 0;
++        if (!cms_set1_keyid(&rek->rid->d.rKeyId->subjectKeyIdentifier, recip))
++            return 0;
++    } else {
++        rek->rid->type = CMS_REK_ISSUER_SERIAL;
++        if (!cms_set1_ias(&rek->rid->d.issuerAndSerialNumber, recip))
++            return 0;
++    }
++
++    /* Create ephemeral key */
++    if (!cms_kari_create_ephemeral_key(kari, pk))
++        return 0;
++
++    EVP_PKEY_up_ref(pk);
++    rek->pkey = pk;
++    return 1;
++}
++
++static int cms_wrap_init(CMS_KeyAgreeRecipientInfo *kari,
++                         const EVP_CIPHER *cipher)
++{
++    EVP_CIPHER_CTX *ctx = kari->ctx;
++    const EVP_CIPHER *kekcipher;
++    int keylen = EVP_CIPHER_key_length(cipher);
++    /* 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;
++    }
++    /*
++     * Pick a cipher based on content encryption cipher. If it is DES3 use
++     * DES3 wrap otherwise use AES wrap similar to key size.
++     */
++#ifndef OPENSSL_NO_DES
++    if (EVP_CIPHER_type(cipher) == NID_des_ede3_cbc)
++        kekcipher = EVP_des_ede3_wrap();
++    else
++#endif
++    if (keylen <= 16)
++        kekcipher = EVP_aes_128_wrap();
++    else if (keylen <= 24)
++        kekcipher = EVP_aes_192_wrap();
++    else
++        kekcipher = EVP_aes_256_wrap();
++    return EVP_EncryptInit_ex(ctx, kekcipher, NULL, NULL, NULL);
++}
++
++/* Encrypt content key in key agreement recipient info */
++
++int cms_RecipientInfo_kari_encrypt(CMS_ContentInfo *cms,
++                                   CMS_RecipientInfo *ri)
++{
++    CMS_KeyAgreeRecipientInfo *kari;
++    CMS_EncryptedContentInfo *ec;
++    CMS_RecipientEncryptedKey *rek;
++    STACK_OF(CMS_RecipientEncryptedKey) *reks;
++    int i;
++
++    if (ri->type != CMS_RECIPINFO_AGREE) {
++        CMSerr(CMS_F_CMS_RECIPIENTINFO_KARI_ENCRYPT, CMS_R_NOT_KEY_AGREEMENT);
++        return 0;
++    }
++    kari = ri->d.kari;
++    reks = kari->recipientEncryptedKeys;
++    ec = cms->d.envelopedData->encryptedContentInfo;
++    /* Initialise wrap algorithm parameters */
++    if (!cms_wrap_init(kari, ec->cipher))
++        return 0;
++    /*
++     * If no originator key set up initialise for ephemeral key the public key
++     * ASN1 structure will set the actual public key value.
++     */
++    if (kari->originator->type == -1) {
++        CMS_OriginatorIdentifierOrKey *oik = kari->originator;
++        oik->type = CMS_OIK_PUBKEY;
++        oik->d.originatorKey = M_ASN1_new_of(CMS_OriginatorPublicKey);
++        if (!oik->d.originatorKey)
++            return 0;
++    }
++    /* Initialise KDF algorithm */
++    if (!cms_env_asn1_ctrl(ri, 0))
++        return 0;
++    /* For each rek, derive KEK, encrypt CEK */
++    for (i = 0; i < sk_CMS_RecipientEncryptedKey_num(reks); i++) {
++        unsigned char *enckey;
++        size_t enckeylen;
++        rek = sk_CMS_RecipientEncryptedKey_value(reks, i);
++        if (EVP_PKEY_derive_set_peer(kari->pctx, rek->pkey) <= 0)
++            return 0;
++        if (!cms_kek_cipher(&enckey, &enckeylen, ec->key, ec->keylen,
++                            kari, 1))
++            return 0;
++        ASN1_STRING_set0(rek->encryptedKey, enckey, enckeylen);
++    }
++
++    return 1;
++
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/cms/cms_lcl.h b/CryptoPkg/Library/OpensslLib/openssl/crypto/cms/cms_lcl.h
+new file mode 100644
+index 0000000..d0c0e81
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/cms/cms_lcl.h
+@@ -0,0 +1,444 @@
++/*
++ * Copyright 2008-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#ifndef HEADER_CMS_LCL_H
++# define HEADER_CMS_LCL_H
++
++#ifdef __cplusplus
++extern "C" {
++#endif
++
++# include 
++
++/*
++ * Cryptographic message syntax (CMS) structures: taken from RFC3852
++ */
++
++/* Forward references */
++
++typedef struct CMS_IssuerAndSerialNumber_st CMS_IssuerAndSerialNumber;
++typedef struct CMS_EncapsulatedContentInfo_st CMS_EncapsulatedContentInfo;
++typedef struct CMS_SignerIdentifier_st CMS_SignerIdentifier;
++typedef struct CMS_SignedData_st CMS_SignedData;
++typedef struct CMS_OtherRevocationInfoFormat_st CMS_OtherRevocationInfoFormat;
++typedef struct CMS_OriginatorInfo_st CMS_OriginatorInfo;
++typedef struct CMS_EncryptedContentInfo_st CMS_EncryptedContentInfo;
++typedef struct CMS_EnvelopedData_st CMS_EnvelopedData;
++typedef struct CMS_DigestedData_st CMS_DigestedData;
++typedef struct CMS_EncryptedData_st CMS_EncryptedData;
++typedef struct CMS_AuthenticatedData_st CMS_AuthenticatedData;
++typedef struct CMS_CompressedData_st CMS_CompressedData;
++typedef struct CMS_OtherCertificateFormat_st CMS_OtherCertificateFormat;
++typedef struct CMS_KeyTransRecipientInfo_st CMS_KeyTransRecipientInfo;
++typedef struct CMS_OriginatorPublicKey_st CMS_OriginatorPublicKey;
++typedef struct CMS_OriginatorIdentifierOrKey_st CMS_OriginatorIdentifierOrKey;
++typedef struct CMS_KeyAgreeRecipientInfo_st CMS_KeyAgreeRecipientInfo;
++typedef struct CMS_RecipientKeyIdentifier_st CMS_RecipientKeyIdentifier;
++typedef struct CMS_KeyAgreeRecipientIdentifier_st
++    CMS_KeyAgreeRecipientIdentifier;
++typedef struct CMS_KEKIdentifier_st CMS_KEKIdentifier;
++typedef struct CMS_KEKRecipientInfo_st CMS_KEKRecipientInfo;
++typedef struct CMS_PasswordRecipientInfo_st CMS_PasswordRecipientInfo;
++typedef struct CMS_OtherRecipientInfo_st CMS_OtherRecipientInfo;
++typedef struct CMS_ReceiptsFrom_st CMS_ReceiptsFrom;
++
++struct CMS_ContentInfo_st {
++    ASN1_OBJECT *contentType;
++    union {
++        ASN1_OCTET_STRING *data;
++        CMS_SignedData *signedData;
++        CMS_EnvelopedData *envelopedData;
++        CMS_DigestedData *digestedData;
++        CMS_EncryptedData *encryptedData;
++        CMS_AuthenticatedData *authenticatedData;
++        CMS_CompressedData *compressedData;
++        ASN1_TYPE *other;
++        /* Other types ... */
++        void *otherData;
++    } d;
++};
++
++DEFINE_STACK_OF(CMS_CertificateChoices)
++
++struct CMS_SignedData_st {
++    long version;
++    STACK_OF(X509_ALGOR) *digestAlgorithms;
++    CMS_EncapsulatedContentInfo *encapContentInfo;
++    STACK_OF(CMS_CertificateChoices) *certificates;
++    STACK_OF(CMS_RevocationInfoChoice) *crls;
++    STACK_OF(CMS_SignerInfo) *signerInfos;
++};
++
++struct CMS_EncapsulatedContentInfo_st {
++    ASN1_OBJECT *eContentType;
++    ASN1_OCTET_STRING *eContent;
++    /* Set to 1 if incomplete structure only part set up */
++    int partial;
++};
++
++struct CMS_SignerInfo_st {
++    long version;
++    CMS_SignerIdentifier *sid;
++    X509_ALGOR *digestAlgorithm;
++    STACK_OF(X509_ATTRIBUTE) *signedAttrs;
++    X509_ALGOR *signatureAlgorithm;
++    ASN1_OCTET_STRING *signature;
++    STACK_OF(X509_ATTRIBUTE) *unsignedAttrs;
++    /* Signing certificate and key */
++    X509 *signer;
++    EVP_PKEY *pkey;
++    /* Digest and public key context for alternative parameters */
++    EVP_MD_CTX *mctx;
++    EVP_PKEY_CTX *pctx;
++};
++
++struct CMS_SignerIdentifier_st {
++    int type;
++    union {
++        CMS_IssuerAndSerialNumber *issuerAndSerialNumber;
++        ASN1_OCTET_STRING *subjectKeyIdentifier;
++    } d;
++};
++
++struct CMS_EnvelopedData_st {
++    long version;
++    CMS_OriginatorInfo *originatorInfo;
++    STACK_OF(CMS_RecipientInfo) *recipientInfos;
++    CMS_EncryptedContentInfo *encryptedContentInfo;
++    STACK_OF(X509_ATTRIBUTE) *unprotectedAttrs;
++};
++
++struct CMS_OriginatorInfo_st {
++    STACK_OF(CMS_CertificateChoices) *certificates;
++    STACK_OF(CMS_RevocationInfoChoice) *crls;
++};
++
++struct CMS_EncryptedContentInfo_st {
++    ASN1_OBJECT *contentType;
++    X509_ALGOR *contentEncryptionAlgorithm;
++    ASN1_OCTET_STRING *encryptedContent;
++    /* Content encryption algorithm and key */
++    const EVP_CIPHER *cipher;
++    unsigned char *key;
++    size_t keylen;
++    /* Set to 1 if we are debugging decrypt and don't fake keys for MMA */
++    int debug;
++};
++
++struct CMS_RecipientInfo_st {
++    int type;
++    union {
++        CMS_KeyTransRecipientInfo *ktri;
++        CMS_KeyAgreeRecipientInfo *kari;
++        CMS_KEKRecipientInfo *kekri;
++        CMS_PasswordRecipientInfo *pwri;
++        CMS_OtherRecipientInfo *ori;
++    } d;
++};
++
++typedef CMS_SignerIdentifier CMS_RecipientIdentifier;
++
++struct CMS_KeyTransRecipientInfo_st {
++    long version;
++    CMS_RecipientIdentifier *rid;
++    X509_ALGOR *keyEncryptionAlgorithm;
++    ASN1_OCTET_STRING *encryptedKey;
++    /* Recipient Key and cert */
++    X509 *recip;
++    EVP_PKEY *pkey;
++    /* Public key context for this operation */
++    EVP_PKEY_CTX *pctx;
++};
++
++struct CMS_KeyAgreeRecipientInfo_st {
++    long version;
++    CMS_OriginatorIdentifierOrKey *originator;
++    ASN1_OCTET_STRING *ukm;
++    X509_ALGOR *keyEncryptionAlgorithm;
++    STACK_OF(CMS_RecipientEncryptedKey) *recipientEncryptedKeys;
++    /* Public key context associated with current operation */
++    EVP_PKEY_CTX *pctx;
++    /* Cipher context for CEK wrapping */
++    EVP_CIPHER_CTX *ctx;
++};
++
++struct CMS_OriginatorIdentifierOrKey_st {
++    int type;
++    union {
++        CMS_IssuerAndSerialNumber *issuerAndSerialNumber;
++        ASN1_OCTET_STRING *subjectKeyIdentifier;
++        CMS_OriginatorPublicKey *originatorKey;
++    } d;
++};
++
++struct CMS_OriginatorPublicKey_st {
++    X509_ALGOR *algorithm;
++    ASN1_BIT_STRING *publicKey;
++};
++
++struct CMS_RecipientEncryptedKey_st {
++    CMS_KeyAgreeRecipientIdentifier *rid;
++    ASN1_OCTET_STRING *encryptedKey;
++    /* Public key associated with this recipient */
++    EVP_PKEY *pkey;
++};
++
++struct CMS_KeyAgreeRecipientIdentifier_st {
++    int type;
++    union {
++        CMS_IssuerAndSerialNumber *issuerAndSerialNumber;
++        CMS_RecipientKeyIdentifier *rKeyId;
++    } d;
++};
++
++struct CMS_RecipientKeyIdentifier_st {
++    ASN1_OCTET_STRING *subjectKeyIdentifier;
++    ASN1_GENERALIZEDTIME *date;
++    CMS_OtherKeyAttribute *other;
++};
++
++struct CMS_KEKRecipientInfo_st {
++    long version;
++    CMS_KEKIdentifier *kekid;
++    X509_ALGOR *keyEncryptionAlgorithm;
++    ASN1_OCTET_STRING *encryptedKey;
++    /* Extra info: symmetric key to use */
++    unsigned char *key;
++    size_t keylen;
++};
++
++struct CMS_KEKIdentifier_st {
++    ASN1_OCTET_STRING *keyIdentifier;
++    ASN1_GENERALIZEDTIME *date;
++    CMS_OtherKeyAttribute *other;
++};
++
++struct CMS_PasswordRecipientInfo_st {
++    long version;
++    X509_ALGOR *keyDerivationAlgorithm;
++    X509_ALGOR *keyEncryptionAlgorithm;
++    ASN1_OCTET_STRING *encryptedKey;
++    /* Extra info: password to use */
++    unsigned char *pass;
++    size_t passlen;
++};
++
++struct CMS_OtherRecipientInfo_st {
++    ASN1_OBJECT *oriType;
++    ASN1_TYPE *oriValue;
++};
++
++struct CMS_DigestedData_st {
++    long version;
++    X509_ALGOR *digestAlgorithm;
++    CMS_EncapsulatedContentInfo *encapContentInfo;
++    ASN1_OCTET_STRING *digest;
++};
++
++struct CMS_EncryptedData_st {
++    long version;
++    CMS_EncryptedContentInfo *encryptedContentInfo;
++    STACK_OF(X509_ATTRIBUTE) *unprotectedAttrs;
++};
++
++struct CMS_AuthenticatedData_st {
++    long version;
++    CMS_OriginatorInfo *originatorInfo;
++    STACK_OF(CMS_RecipientInfo) *recipientInfos;
++    X509_ALGOR *macAlgorithm;
++    X509_ALGOR *digestAlgorithm;
++    CMS_EncapsulatedContentInfo *encapContentInfo;
++    STACK_OF(X509_ATTRIBUTE) *authAttrs;
++    ASN1_OCTET_STRING *mac;
++    STACK_OF(X509_ATTRIBUTE) *unauthAttrs;
++};
++
++struct CMS_CompressedData_st {
++    long version;
++    X509_ALGOR *compressionAlgorithm;
++    STACK_OF(CMS_RecipientInfo) *recipientInfos;
++    CMS_EncapsulatedContentInfo *encapContentInfo;
++};
++
++struct CMS_RevocationInfoChoice_st {
++    int type;
++    union {
++        X509_CRL *crl;
++        CMS_OtherRevocationInfoFormat *other;
++    } d;
++};
++
++# define CMS_REVCHOICE_CRL               0
++# define CMS_REVCHOICE_OTHER             1
++
++struct CMS_OtherRevocationInfoFormat_st {
++    ASN1_OBJECT *otherRevInfoFormat;
++    ASN1_TYPE *otherRevInfo;
++};
++
++struct CMS_CertificateChoices {
++    int type;
++    union {
++        X509 *certificate;
++        ASN1_STRING *extendedCertificate; /* Obsolete */
++        ASN1_STRING *v1AttrCert; /* Left encoded for now */
++        ASN1_STRING *v2AttrCert; /* Left encoded for now */
++        CMS_OtherCertificateFormat *other;
++    } d;
++};
++
++# define CMS_CERTCHOICE_CERT             0
++# define CMS_CERTCHOICE_EXCERT           1
++# define CMS_CERTCHOICE_V1ACERT          2
++# define CMS_CERTCHOICE_V2ACERT          3
++# define CMS_CERTCHOICE_OTHER            4
++
++struct CMS_OtherCertificateFormat_st {
++    ASN1_OBJECT *otherCertFormat;
++    ASN1_TYPE *otherCert;
++};
++
++/*
++ * This is also defined in pkcs7.h but we duplicate it to allow the CMS code
++ * to be independent of PKCS#7
++ */
++
++struct CMS_IssuerAndSerialNumber_st {
++    X509_NAME *issuer;
++    ASN1_INTEGER *serialNumber;
++};
++
++struct CMS_OtherKeyAttribute_st {
++    ASN1_OBJECT *keyAttrId;
++    ASN1_TYPE *keyAttr;
++};
++
++/* ESS structures */
++
++# ifdef HEADER_X509V3_H
++
++struct CMS_ReceiptRequest_st {
++    ASN1_OCTET_STRING *signedContentIdentifier;
++    CMS_ReceiptsFrom *receiptsFrom;
++    STACK_OF(GENERAL_NAMES) *receiptsTo;
++};
++
++struct CMS_ReceiptsFrom_st {
++    int type;
++    union {
++        long allOrFirstTier;
++        STACK_OF(GENERAL_NAMES) *receiptList;
++    } d;
++};
++# endif
++
++struct CMS_Receipt_st {
++    long version;
++    ASN1_OBJECT *contentType;
++    ASN1_OCTET_STRING *signedContentIdentifier;
++    ASN1_OCTET_STRING *originatorSignatureValue;
++};
++
++DECLARE_ASN1_FUNCTIONS(CMS_ContentInfo)
++DECLARE_ASN1_ITEM(CMS_SignerInfo)
++DECLARE_ASN1_ITEM(CMS_IssuerAndSerialNumber)
++DECLARE_ASN1_ITEM(CMS_Attributes_Sign)
++DECLARE_ASN1_ITEM(CMS_Attributes_Verify)
++DECLARE_ASN1_ITEM(CMS_RecipientInfo)
++DECLARE_ASN1_ITEM(CMS_PasswordRecipientInfo)
++DECLARE_ASN1_ALLOC_FUNCTIONS(CMS_IssuerAndSerialNumber)
++
++# define CMS_SIGNERINFO_ISSUER_SERIAL    0
++# define CMS_SIGNERINFO_KEYIDENTIFIER    1
++
++# define CMS_RECIPINFO_ISSUER_SERIAL     0
++# define CMS_RECIPINFO_KEYIDENTIFIER     1
++
++# define CMS_REK_ISSUER_SERIAL           0
++# define CMS_REK_KEYIDENTIFIER           1
++
++# define CMS_OIK_ISSUER_SERIAL           0
++# define CMS_OIK_KEYIDENTIFIER           1
++# define CMS_OIK_PUBKEY                  2
++
++BIO *cms_content_bio(CMS_ContentInfo *cms);
++
++CMS_ContentInfo *cms_Data_create(void);
++
++CMS_ContentInfo *cms_DigestedData_create(const EVP_MD *md);
++BIO *cms_DigestedData_init_bio(CMS_ContentInfo *cms);
++int cms_DigestedData_do_final(CMS_ContentInfo *cms, BIO *chain, int verify);
++
++BIO *cms_SignedData_init_bio(CMS_ContentInfo *cms);
++int cms_SignedData_final(CMS_ContentInfo *cms, BIO *chain);
++int cms_set1_SignerIdentifier(CMS_SignerIdentifier *sid, X509 *cert,
++                              int type);
++int cms_SignerIdentifier_get0_signer_id(CMS_SignerIdentifier *sid,
++                                        ASN1_OCTET_STRING **keyid,
++                                        X509_NAME **issuer,
++                                        ASN1_INTEGER **sno);
++int cms_SignerIdentifier_cert_cmp(CMS_SignerIdentifier *sid, X509 *cert);
++
++CMS_ContentInfo *cms_CompressedData_create(int comp_nid);
++BIO *cms_CompressedData_init_bio(CMS_ContentInfo *cms);
++
++BIO *cms_DigestAlgorithm_init_bio(X509_ALGOR *digestAlgorithm);
++int cms_DigestAlgorithm_find_ctx(EVP_MD_CTX *mctx, BIO *chain,
++                                 X509_ALGOR *mdalg);
++
++int cms_ias_cert_cmp(CMS_IssuerAndSerialNumber *ias, X509 *cert);
++int cms_keyid_cert_cmp(ASN1_OCTET_STRING *keyid, X509 *cert);
++int cms_set1_ias(CMS_IssuerAndSerialNumber **pias, X509 *cert);
++int cms_set1_keyid(ASN1_OCTET_STRING **pkeyid, X509 *cert);
++
++BIO *cms_EncryptedContent_init_bio(CMS_EncryptedContentInfo *ec);
++BIO *cms_EncryptedData_init_bio(CMS_ContentInfo *cms);
++int cms_EncryptedContent_init(CMS_EncryptedContentInfo *ec,
++                              const EVP_CIPHER *cipher,
++                              const unsigned char *key, size_t keylen);
++
++int cms_Receipt_verify(CMS_ContentInfo *cms, CMS_ContentInfo *req_cms);
++int cms_msgSigDigest_add1(CMS_SignerInfo *dest, CMS_SignerInfo *src);
++ASN1_OCTET_STRING *cms_encode_Receipt(CMS_SignerInfo *si);
++
++BIO *cms_EnvelopedData_init_bio(CMS_ContentInfo *cms);
++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);
++/* KARI routines */
++int cms_RecipientInfo_kari_init(CMS_RecipientInfo *ri, X509 *recip,
++                                EVP_PKEY *pk, unsigned int flags);
++int cms_RecipientInfo_kari_encrypt(CMS_ContentInfo *cms,
++                                   CMS_RecipientInfo *ri);
++
++/* PWRI routines */
++int cms_RecipientInfo_pwri_crypt(CMS_ContentInfo *cms, CMS_RecipientInfo *ri,
++                                 int en_de);
++
++DECLARE_ASN1_ITEM(CMS_CertificateChoices)
++DECLARE_ASN1_ITEM(CMS_DigestedData)
++DECLARE_ASN1_ITEM(CMS_EncryptedData)
++DECLARE_ASN1_ITEM(CMS_EnvelopedData)
++DECLARE_ASN1_ITEM(CMS_KEKRecipientInfo)
++DECLARE_ASN1_ITEM(CMS_KeyAgreeRecipientInfo)
++DECLARE_ASN1_ITEM(CMS_KeyTransRecipientInfo)
++DECLARE_ASN1_ITEM(CMS_OriginatorPublicKey)
++DECLARE_ASN1_ITEM(CMS_OtherKeyAttribute)
++DECLARE_ASN1_ITEM(CMS_Receipt)
++DECLARE_ASN1_ITEM(CMS_ReceiptRequest)
++DECLARE_ASN1_ITEM(CMS_RecipientEncryptedKey)
++DECLARE_ASN1_ITEM(CMS_RecipientKeyIdentifier)
++DECLARE_ASN1_ITEM(CMS_RevocationInfoChoice)
++DECLARE_ASN1_ITEM(CMS_SignedData)
++DECLARE_ASN1_ITEM(CMS_CompressedData)
++
++#ifdef  __cplusplus
++}
++#endif
++#endif
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/cms/cms_lib.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/cms/cms_lib.c
+new file mode 100644
+index 0000000..7395684
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/cms/cms_lib.c
+@@ -0,0 +1,587 @@
++/*
++ * Copyright 2008-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include 
++#include 
++#include 
++#include 
++#include 
++#include 
++#include "cms_lcl.h"
++
++IMPLEMENT_ASN1_FUNCTIONS(CMS_ContentInfo)
++IMPLEMENT_ASN1_PRINT_FUNCTION(CMS_ContentInfo)
++
++const ASN1_OBJECT *CMS_get0_type(const CMS_ContentInfo *cms)
++{
++    return cms->contentType;
++}
++
++CMS_ContentInfo *cms_Data_create(void)
++{
++    CMS_ContentInfo *cms;
++    cms = CMS_ContentInfo_new();
++    if (cms != NULL) {
++        cms->contentType = OBJ_nid2obj(NID_pkcs7_data);
++        /* Never detached */
++        CMS_set_detached(cms, 0);
++    }
++    return cms;
++}
++
++BIO *cms_content_bio(CMS_ContentInfo *cms)
++{
++    ASN1_OCTET_STRING **pos = CMS_get0_content(cms);
++    if (!pos)
++        return NULL;
++    /* If content detached data goes nowhere: create NULL BIO */
++    if (!*pos)
++        return BIO_new(BIO_s_null());
++    /*
++     * If content not detached and created return memory BIO
++     */
++    if (!*pos || ((*pos)->flags == ASN1_STRING_FLAG_CONT))
++        return BIO_new(BIO_s_mem());
++    /* Else content was read in: return read only BIO for it */
++    return BIO_new_mem_buf((*pos)->data, (*pos)->length);
++}
++
++BIO *CMS_dataInit(CMS_ContentInfo *cms, BIO *icont)
++{
++    BIO *cmsbio, *cont;
++    if (icont)
++        cont = icont;
++    else
++        cont = cms_content_bio(cms);
++    if (!cont) {
++        CMSerr(CMS_F_CMS_DATAINIT, CMS_R_NO_CONTENT);
++        return NULL;
++    }
++    switch (OBJ_obj2nid(cms->contentType)) {
++
++    case NID_pkcs7_data:
++        return cont;
++
++    case NID_pkcs7_signed:
++        cmsbio = cms_SignedData_init_bio(cms);
++        break;
++
++    case NID_pkcs7_digest:
++        cmsbio = cms_DigestedData_init_bio(cms);
++        break;
++#ifdef ZLIB
++    case NID_id_smime_ct_compressedData:
++        cmsbio = cms_CompressedData_init_bio(cms);
++        break;
++#endif
++
++    case NID_pkcs7_encrypted:
++        cmsbio = cms_EncryptedData_init_bio(cms);
++        break;
++
++    case NID_pkcs7_enveloped:
++        cmsbio = cms_EnvelopedData_init_bio(cms);
++        break;
++
++    default:
++        CMSerr(CMS_F_CMS_DATAINIT, CMS_R_UNSUPPORTED_TYPE);
++        return NULL;
++    }
++
++    if (cmsbio)
++        return BIO_push(cmsbio, cont);
++
++    if (!icont)
++        BIO_free(cont);
++    return NULL;
++
++}
++
++int CMS_dataFinal(CMS_ContentInfo *cms, BIO *cmsbio)
++{
++    ASN1_OCTET_STRING **pos = CMS_get0_content(cms);
++    if (!pos)
++        return 0;
++    /* If embedded content find memory BIO and set content */
++    if (*pos && ((*pos)->flags & ASN1_STRING_FLAG_CONT)) {
++        BIO *mbio;
++        unsigned char *cont;
++        long contlen;
++        mbio = BIO_find_type(cmsbio, BIO_TYPE_MEM);
++        if (!mbio) {
++            CMSerr(CMS_F_CMS_DATAFINAL, CMS_R_CONTENT_NOT_FOUND);
++            return 0;
++        }
++        contlen = BIO_get_mem_data(mbio, &cont);
++        /* Set bio as read only so its content can't be clobbered */
++        BIO_set_flags(mbio, BIO_FLAGS_MEM_RDONLY);
++        BIO_set_mem_eof_return(mbio, 0);
++        ASN1_STRING_set0(*pos, cont, contlen);
++        (*pos)->flags &= ~ASN1_STRING_FLAG_CONT;
++    }
++
++    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_signed:
++        return cms_SignedData_final(cms, cmsbio);
++
++    case NID_pkcs7_digest:
++        return cms_DigestedData_do_final(cms, cmsbio, 0);
++
++    default:
++        CMSerr(CMS_F_CMS_DATAFINAL, CMS_R_UNSUPPORTED_TYPE);
++        return 0;
++    }
++}
++
++/*
++ * Return an OCTET STRING pointer to content. This allows it to be accessed
++ * or set later.
++ */
++
++ASN1_OCTET_STRING **CMS_get0_content(CMS_ContentInfo *cms)
++{
++    switch (OBJ_obj2nid(cms->contentType)) {
++
++    case NID_pkcs7_data:
++        return &cms->d.data;
++
++    case NID_pkcs7_signed:
++        return &cms->d.signedData->encapContentInfo->eContent;
++
++    case NID_pkcs7_enveloped:
++        return &cms->d.envelopedData->encryptedContentInfo->encryptedContent;
++
++    case NID_pkcs7_digest:
++        return &cms->d.digestedData->encapContentInfo->eContent;
++
++    case NID_pkcs7_encrypted:
++        return &cms->d.encryptedData->encryptedContentInfo->encryptedContent;
++
++    case NID_id_smime_ct_authData:
++        return &cms->d.authenticatedData->encapContentInfo->eContent;
++
++    case NID_id_smime_ct_compressedData:
++        return &cms->d.compressedData->encapContentInfo->eContent;
++
++    default:
++        if (cms->d.other->type == V_ASN1_OCTET_STRING)
++            return &cms->d.other->value.octet_string;
++        CMSerr(CMS_F_CMS_GET0_CONTENT, CMS_R_UNSUPPORTED_CONTENT_TYPE);
++        return NULL;
++
++    }
++}
++
++/*
++ * Return an ASN1_OBJECT pointer to content type. This allows it to be
++ * accessed or set later.
++ */
++
++static ASN1_OBJECT **cms_get0_econtent_type(CMS_ContentInfo *cms)
++{
++    switch (OBJ_obj2nid(cms->contentType)) {
++
++    case NID_pkcs7_signed:
++        return &cms->d.signedData->encapContentInfo->eContentType;
++
++    case NID_pkcs7_enveloped:
++        return &cms->d.envelopedData->encryptedContentInfo->contentType;
++
++    case NID_pkcs7_digest:
++        return &cms->d.digestedData->encapContentInfo->eContentType;
++
++    case NID_pkcs7_encrypted:
++        return &cms->d.encryptedData->encryptedContentInfo->contentType;
++
++    case NID_id_smime_ct_authData:
++        return &cms->d.authenticatedData->encapContentInfo->eContentType;
++
++    case NID_id_smime_ct_compressedData:
++        return &cms->d.compressedData->encapContentInfo->eContentType;
++
++    default:
++        CMSerr(CMS_F_CMS_GET0_ECONTENT_TYPE, CMS_R_UNSUPPORTED_CONTENT_TYPE);
++        return NULL;
++
++    }
++}
++
++const ASN1_OBJECT *CMS_get0_eContentType(CMS_ContentInfo *cms)
++{
++    ASN1_OBJECT **petype;
++    petype = cms_get0_econtent_type(cms);
++    if (petype)
++        return *petype;
++    return NULL;
++}
++
++int CMS_set1_eContentType(CMS_ContentInfo *cms, const ASN1_OBJECT *oid)
++{
++    ASN1_OBJECT **petype, *etype;
++    petype = cms_get0_econtent_type(cms);
++    if (!petype)
++        return 0;
++    if (!oid)
++        return 1;
++    etype = OBJ_dup(oid);
++    if (!etype)
++        return 0;
++    ASN1_OBJECT_free(*petype);
++    *petype = etype;
++    return 1;
++}
++
++int CMS_is_detached(CMS_ContentInfo *cms)
++{
++    ASN1_OCTET_STRING **pos;
++    pos = CMS_get0_content(cms);
++    if (!pos)
++        return -1;
++    if (*pos)
++        return 0;
++    return 1;
++}
++
++int CMS_set_detached(CMS_ContentInfo *cms, int detached)
++{
++    ASN1_OCTET_STRING **pos;
++    pos = CMS_get0_content(cms);
++    if (!pos)
++        return 0;
++    if (detached) {
++        ASN1_OCTET_STRING_free(*pos);
++        *pos = NULL;
++        return 1;
++    }
++    if (*pos == NULL)
++        *pos = ASN1_OCTET_STRING_new();
++    if (*pos != NULL) {
++        /*
++         * NB: special flag to show content is created and not read in.
++         */
++        (*pos)->flags |= ASN1_STRING_FLAG_CONT;
++        return 1;
++    }
++    CMSerr(CMS_F_CMS_SET_DETACHED, ERR_R_MALLOC_FAILURE);
++    return 0;
++}
++
++/* Create a digest BIO from an X509_ALGOR structure */
++
++BIO *cms_DigestAlgorithm_init_bio(X509_ALGOR *digestAlgorithm)
++{
++    BIO *mdbio = NULL;
++    const ASN1_OBJECT *digestoid;
++    const EVP_MD *digest;
++    X509_ALGOR_get0(&digestoid, NULL, NULL, digestAlgorithm);
++    digest = EVP_get_digestbyobj(digestoid);
++    if (!digest) {
++        CMSerr(CMS_F_CMS_DIGESTALGORITHM_INIT_BIO,
++               CMS_R_UNKNOWN_DIGEST_ALGORIHM);
++        goto err;
++    }
++    mdbio = BIO_new(BIO_f_md());
++    if (mdbio == NULL || !BIO_set_md(mdbio, digest)) {
++        CMSerr(CMS_F_CMS_DIGESTALGORITHM_INIT_BIO, CMS_R_MD_BIO_INIT_ERROR);
++        goto err;
++    }
++    return mdbio;
++ err:
++    BIO_free(mdbio);
++    return NULL;
++}
++
++/* Locate a message digest content from a BIO chain based on SignerInfo */
++
++int cms_DigestAlgorithm_find_ctx(EVP_MD_CTX *mctx, BIO *chain,
++                                 X509_ALGOR *mdalg)
++{
++    int nid;
++    const ASN1_OBJECT *mdoid;
++    X509_ALGOR_get0(&mdoid, NULL, NULL, mdalg);
++    nid = OBJ_obj2nid(mdoid);
++    /* Look for digest type to match signature */
++    for (;;) {
++        EVP_MD_CTX *mtmp;
++        chain = BIO_find_type(chain, BIO_TYPE_MD);
++        if (chain == NULL) {
++            CMSerr(CMS_F_CMS_DIGESTALGORITHM_FIND_CTX,
++                   CMS_R_NO_MATCHING_DIGEST);
++            return 0;
++        }
++        BIO_get_md_ctx(chain, &mtmp);
++        if (EVP_MD_CTX_type(mtmp) == nid
++            /*
++             * Workaround for broken implementations that use signature
++             * algorithm OID instead of digest.
++             */
++            || EVP_MD_pkey_type(EVP_MD_CTX_md(mtmp)) == nid)
++            return EVP_MD_CTX_copy_ex(mctx, mtmp);
++        chain = BIO_next(chain);
++    }
++}
++
++static STACK_OF(CMS_CertificateChoices)
++**cms_get0_certificate_choices(CMS_ContentInfo *cms)
++{
++    switch (OBJ_obj2nid(cms->contentType)) {
++
++    case NID_pkcs7_signed:
++        return &cms->d.signedData->certificates;
++
++    case NID_pkcs7_enveloped:
++        if (cms->d.envelopedData->originatorInfo == NULL)
++            return NULL;
++        return &cms->d.envelopedData->originatorInfo->certificates;
++
++    default:
++        CMSerr(CMS_F_CMS_GET0_CERTIFICATE_CHOICES,
++               CMS_R_UNSUPPORTED_CONTENT_TYPE);
++        return NULL;
++
++    }
++}
++
++CMS_CertificateChoices *CMS_add0_CertificateChoices(CMS_ContentInfo *cms)
++{
++    STACK_OF(CMS_CertificateChoices) **pcerts;
++    CMS_CertificateChoices *cch;
++    pcerts = cms_get0_certificate_choices(cms);
++    if (!pcerts)
++        return NULL;
++    if (!*pcerts)
++        *pcerts = sk_CMS_CertificateChoices_new_null();
++    if (!*pcerts)
++        return NULL;
++    cch = M_ASN1_new_of(CMS_CertificateChoices);
++    if (!cch)
++        return NULL;
++    if (!sk_CMS_CertificateChoices_push(*pcerts, cch)) {
++        M_ASN1_free_of(cch, CMS_CertificateChoices);
++        return NULL;
++    }
++    return cch;
++}
++
++int CMS_add0_cert(CMS_ContentInfo *cms, X509 *cert)
++{
++    CMS_CertificateChoices *cch;
++    STACK_OF(CMS_CertificateChoices) **pcerts;
++    int i;
++    pcerts = cms_get0_certificate_choices(cms);
++    if (!pcerts)
++        return 0;
++    for (i = 0; i < sk_CMS_CertificateChoices_num(*pcerts); i++) {
++        cch = sk_CMS_CertificateChoices_value(*pcerts, i);
++        if (cch->type == CMS_CERTCHOICE_CERT) {
++            if (!X509_cmp(cch->d.certificate, cert)) {
++                CMSerr(CMS_F_CMS_ADD0_CERT,
++                       CMS_R_CERTIFICATE_ALREADY_PRESENT);
++                return 0;
++            }
++        }
++    }
++    cch = CMS_add0_CertificateChoices(cms);
++    if (!cch)
++        return 0;
++    cch->type = CMS_CERTCHOICE_CERT;
++    cch->d.certificate = cert;
++    return 1;
++}
++
++int CMS_add1_cert(CMS_ContentInfo *cms, X509 *cert)
++{
++    int r;
++    r = CMS_add0_cert(cms, cert);
++    if (r > 0)
++        X509_up_ref(cert);
++    return r;
++}
++
++static STACK_OF(CMS_RevocationInfoChoice)
++**cms_get0_revocation_choices(CMS_ContentInfo *cms)
++{
++    switch (OBJ_obj2nid(cms->contentType)) {
++
++    case NID_pkcs7_signed:
++        return &cms->d.signedData->crls;
++
++    case NID_pkcs7_enveloped:
++        if (cms->d.envelopedData->originatorInfo == NULL)
++            return NULL;
++        return &cms->d.envelopedData->originatorInfo->crls;
++
++    default:
++        CMSerr(CMS_F_CMS_GET0_REVOCATION_CHOICES,
++               CMS_R_UNSUPPORTED_CONTENT_TYPE);
++        return NULL;
++
++    }
++}
++
++CMS_RevocationInfoChoice *CMS_add0_RevocationInfoChoice(CMS_ContentInfo *cms)
++{
++    STACK_OF(CMS_RevocationInfoChoice) **pcrls;
++    CMS_RevocationInfoChoice *rch;
++    pcrls = cms_get0_revocation_choices(cms);
++    if (!pcrls)
++        return NULL;
++    if (!*pcrls)
++        *pcrls = sk_CMS_RevocationInfoChoice_new_null();
++    if (!*pcrls)
++        return NULL;
++    rch = M_ASN1_new_of(CMS_RevocationInfoChoice);
++    if (!rch)
++        return NULL;
++    if (!sk_CMS_RevocationInfoChoice_push(*pcrls, rch)) {
++        M_ASN1_free_of(rch, CMS_RevocationInfoChoice);
++        return NULL;
++    }
++    return rch;
++}
++
++int CMS_add0_crl(CMS_ContentInfo *cms, X509_CRL *crl)
++{
++    CMS_RevocationInfoChoice *rch;
++    rch = CMS_add0_RevocationInfoChoice(cms);
++    if (!rch)
++        return 0;
++    rch->type = CMS_REVCHOICE_CRL;
++    rch->d.crl = crl;
++    return 1;
++}
++
++int CMS_add1_crl(CMS_ContentInfo *cms, X509_CRL *crl)
++{
++    int r;
++    r = CMS_add0_crl(cms, crl);
++    if (r > 0)
++        X509_CRL_up_ref(crl);
++    return r;
++}
++
++STACK_OF(X509) *CMS_get1_certs(CMS_ContentInfo *cms)
++{
++    STACK_OF(X509) *certs = NULL;
++    CMS_CertificateChoices *cch;
++    STACK_OF(CMS_CertificateChoices) **pcerts;
++    int i;
++    pcerts = cms_get0_certificate_choices(cms);
++    if (!pcerts)
++        return NULL;
++    for (i = 0; i < sk_CMS_CertificateChoices_num(*pcerts); i++) {
++        cch = sk_CMS_CertificateChoices_value(*pcerts, i);
++        if (cch->type == 0) {
++            if (!certs) {
++                certs = sk_X509_new_null();
++                if (!certs)
++                    return NULL;
++            }
++            if (!sk_X509_push(certs, cch->d.certificate)) {
++                sk_X509_pop_free(certs, X509_free);
++                return NULL;
++            }
++            X509_up_ref(cch->d.certificate);
++        }
++    }
++    return certs;
++
++}
++
++STACK_OF(X509_CRL) *CMS_get1_crls(CMS_ContentInfo *cms)
++{
++    STACK_OF(X509_CRL) *crls = NULL;
++    STACK_OF(CMS_RevocationInfoChoice) **pcrls;
++    CMS_RevocationInfoChoice *rch;
++    int i;
++    pcrls = cms_get0_revocation_choices(cms);
++    if (!pcrls)
++        return NULL;
++    for (i = 0; i < sk_CMS_RevocationInfoChoice_num(*pcrls); i++) {
++        rch = sk_CMS_RevocationInfoChoice_value(*pcrls, i);
++        if (rch->type == 0) {
++            if (!crls) {
++                crls = sk_X509_CRL_new_null();
++                if (!crls)
++                    return NULL;
++            }
++            if (!sk_X509_CRL_push(crls, rch->d.crl)) {
++                sk_X509_CRL_pop_free(crls, X509_CRL_free);
++                return NULL;
++            }
++            X509_CRL_up_ref(rch->d.crl);
++        }
++    }
++    return crls;
++}
++
++int cms_ias_cert_cmp(CMS_IssuerAndSerialNumber *ias, X509 *cert)
++{
++    int ret;
++    ret = X509_NAME_cmp(ias->issuer, X509_get_issuer_name(cert));
++    if (ret)
++        return ret;
++    return ASN1_INTEGER_cmp(ias->serialNumber, X509_get_serialNumber(cert));
++}
++
++int cms_keyid_cert_cmp(ASN1_OCTET_STRING *keyid, X509 *cert)
++{
++    const ASN1_OCTET_STRING *cert_keyid = X509_get0_subject_key_id(cert);
++
++    if (cert_keyid == NULL)
++        return -1;
++    return ASN1_OCTET_STRING_cmp(keyid, cert_keyid);
++}
++
++int cms_set1_ias(CMS_IssuerAndSerialNumber **pias, X509 *cert)
++{
++    CMS_IssuerAndSerialNumber *ias;
++    ias = M_ASN1_new_of(CMS_IssuerAndSerialNumber);
++    if (!ias)
++        goto err;
++    if (!X509_NAME_set(&ias->issuer, X509_get_issuer_name(cert)))
++        goto err;
++    if (!ASN1_STRING_copy(ias->serialNumber, X509_get_serialNumber(cert)))
++        goto err;
++    M_ASN1_free_of(*pias, CMS_IssuerAndSerialNumber);
++    *pias = ias;
++    return 1;
++ err:
++    M_ASN1_free_of(ias, CMS_IssuerAndSerialNumber);
++    CMSerr(CMS_F_CMS_SET1_IAS, ERR_R_MALLOC_FAILURE);
++    return 0;
++}
++
++int cms_set1_keyid(ASN1_OCTET_STRING **pkeyid, X509 *cert)
++{
++    ASN1_OCTET_STRING *keyid = NULL;
++    const ASN1_OCTET_STRING *cert_keyid;
++    cert_keyid = X509_get0_subject_key_id(cert);
++    if (cert_keyid == NULL) {
++        CMSerr(CMS_F_CMS_SET1_KEYID, CMS_R_CERTIFICATE_HAS_NO_KEYID);
++        return 0;
++    }
++    keyid = ASN1_STRING_dup(cert_keyid);
++    if (!keyid) {
++        CMSerr(CMS_F_CMS_SET1_KEYID, ERR_R_MALLOC_FAILURE);
++        return 0;
++    }
++    ASN1_OCTET_STRING_free(*pkeyid);
++    *pkeyid = keyid;
++    return 1;
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/cms/cms_pwri.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/cms/cms_pwri.c
+new file mode 100644
+index 0000000..0571bb8
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/cms/cms_pwri.c
+@@ -0,0 +1,392 @@
++/*
++ * Copyright 2009-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include "internal/cryptlib.h"
++#include 
++#include 
++#include 
++#include 
++#include 
++#include 
++#include 
++#include "cms_lcl.h"
++#include "internal/asn1_int.h"
++
++int CMS_RecipientInfo_set0_password(CMS_RecipientInfo *ri,
++                                    unsigned char *pass, ossl_ssize_t passlen)
++{
++    CMS_PasswordRecipientInfo *pwri;
++    if (ri->type != CMS_RECIPINFO_PASS) {
++        CMSerr(CMS_F_CMS_RECIPIENTINFO_SET0_PASSWORD, CMS_R_NOT_PWRI);
++        return 0;
++    }
++
++    pwri = ri->d.pwri;
++    pwri->pass = pass;
++    if (pass && passlen < 0)
++        passlen = strlen((char *)pass);
++    pwri->passlen = passlen;
++    return 1;
++}
++
++CMS_RecipientInfo *CMS_add0_recipient_password(CMS_ContentInfo *cms,
++                                               int iter, int wrap_nid,
++                                               int pbe_nid,
++                                               unsigned char *pass,
++                                               ossl_ssize_t passlen,
++                                               const EVP_CIPHER *kekciph)
++{
++    CMS_RecipientInfo *ri = NULL;
++    CMS_EnvelopedData *env;
++    CMS_PasswordRecipientInfo *pwri;
++    EVP_CIPHER_CTX *ctx = NULL;
++    X509_ALGOR *encalg = NULL;
++    unsigned char iv[EVP_MAX_IV_LENGTH];
++    int ivlen;
++
++    env = cms_get0_enveloped(cms);
++    if (!env)
++        return NULL;
++
++    if (wrap_nid <= 0)
++        wrap_nid = NID_id_alg_PWRI_KEK;
++
++    if (pbe_nid <= 0)
++        pbe_nid = NID_id_pbkdf2;
++
++    /* Get from enveloped data */
++    if (kekciph == NULL)
++        kekciph = env->encryptedContentInfo->cipher;
++
++    if (kekciph == NULL) {
++        CMSerr(CMS_F_CMS_ADD0_RECIPIENT_PASSWORD, CMS_R_NO_CIPHER);
++        return NULL;
++    }
++    if (wrap_nid != NID_id_alg_PWRI_KEK) {
++        CMSerr(CMS_F_CMS_ADD0_RECIPIENT_PASSWORD,
++               CMS_R_UNSUPPORTED_KEY_ENCRYPTION_ALGORITHM);
++        return NULL;
++    }
++
++    /* Setup algorithm identifier for cipher */
++    encalg = X509_ALGOR_new();
++    if (encalg == NULL) {
++        goto merr;
++    }
++    ctx = EVP_CIPHER_CTX_new();
++
++    if (EVP_EncryptInit_ex(ctx, kekciph, NULL, NULL, NULL) <= 0) {
++        CMSerr(CMS_F_CMS_ADD0_RECIPIENT_PASSWORD, ERR_R_EVP_LIB);
++        goto err;
++    }
++
++    ivlen = EVP_CIPHER_CTX_iv_length(ctx);
++
++    if (ivlen > 0) {
++        if (RAND_bytes(iv, ivlen) <= 0)
++            goto err;
++        if (EVP_EncryptInit_ex(ctx, NULL, NULL, NULL, iv) <= 0) {
++            CMSerr(CMS_F_CMS_ADD0_RECIPIENT_PASSWORD, ERR_R_EVP_LIB);
++            goto err;
++        }
++        encalg->parameter = ASN1_TYPE_new();
++        if (!encalg->parameter) {
++            CMSerr(CMS_F_CMS_ADD0_RECIPIENT_PASSWORD, ERR_R_MALLOC_FAILURE);
++            goto err;
++        }
++        if (EVP_CIPHER_param_to_asn1(ctx, encalg->parameter) <= 0) {
++            CMSerr(CMS_F_CMS_ADD0_RECIPIENT_PASSWORD,
++                   CMS_R_CIPHER_PARAMETER_INITIALISATION_ERROR);
++            goto err;
++        }
++    }
++
++    encalg->algorithm = OBJ_nid2obj(EVP_CIPHER_CTX_type(ctx));
++
++    EVP_CIPHER_CTX_free(ctx);
++    ctx = NULL;
++
++    /* Initialize recipient info */
++    ri = M_ASN1_new_of(CMS_RecipientInfo);
++    if (ri == NULL)
++        goto merr;
++
++    ri->d.pwri = M_ASN1_new_of(CMS_PasswordRecipientInfo);
++    if (ri->d.pwri == NULL)
++        goto merr;
++    ri->type = CMS_RECIPINFO_PASS;
++
++    pwri = ri->d.pwri;
++    /* Since this is overwritten, free up empty structure already there */
++    X509_ALGOR_free(pwri->keyEncryptionAlgorithm);
++    pwri->keyEncryptionAlgorithm = X509_ALGOR_new();
++    if (pwri->keyEncryptionAlgorithm == NULL)
++        goto merr;
++    pwri->keyEncryptionAlgorithm->algorithm = OBJ_nid2obj(wrap_nid);
++    pwri->keyEncryptionAlgorithm->parameter = ASN1_TYPE_new();
++    if (pwri->keyEncryptionAlgorithm->parameter == NULL)
++        goto merr;
++
++    if (!ASN1_item_pack(encalg, ASN1_ITEM_rptr(X509_ALGOR),
++                        &pwri->keyEncryptionAlgorithm->parameter->
++                        value.sequence))
++         goto merr;
++    pwri->keyEncryptionAlgorithm->parameter->type = V_ASN1_SEQUENCE;
++
++    X509_ALGOR_free(encalg);
++    encalg = NULL;
++
++    /* Setup PBE algorithm */
++
++    pwri->keyDerivationAlgorithm = PKCS5_pbkdf2_set(iter, NULL, 0, -1, -1);
++
++    if (!pwri->keyDerivationAlgorithm)
++        goto err;
++
++    CMS_RecipientInfo_set0_password(ri, pass, passlen);
++    pwri->version = 0;
++
++    if (!sk_CMS_RecipientInfo_push(env->recipientInfos, ri))
++        goto merr;
++
++    return ri;
++
++ merr:
++    CMSerr(CMS_F_CMS_ADD0_RECIPIENT_PASSWORD, ERR_R_MALLOC_FAILURE);
++ err:
++    EVP_CIPHER_CTX_free(ctx);
++    if (ri)
++        M_ASN1_free_of(ri, CMS_RecipientInfo);
++    X509_ALGOR_free(encalg);
++    return NULL;
++
++}
++
++/*
++ * This is an implementation of the key wrapping mechanism in RFC3211, at
++ * some point this should go into EVP.
++ */
++
++static int kek_unwrap_key(unsigned char *out, size_t *outlen,
++                          const unsigned char *in, size_t inlen,
++                          EVP_CIPHER_CTX *ctx)
++{
++    size_t blocklen = EVP_CIPHER_CTX_block_size(ctx);
++    unsigned char *tmp;
++    int outl, rv = 0;
++    if (inlen < 2 * blocklen) {
++        /* too small */
++        return 0;
++    }
++    if (inlen % blocklen) {
++        /* Invalid size */
++        return 0;
++    }
++    tmp = OPENSSL_malloc(inlen);
++    if (tmp == NULL)
++        return 0;
++    /* setup IV by decrypting last two blocks */
++    if (!EVP_DecryptUpdate(ctx, tmp + inlen - 2 * blocklen, &outl,
++                           in + inlen - 2 * blocklen, blocklen * 2)
++        /*
++         * Do a decrypt of last decrypted block to set IV to correct value
++         * output it to start of buffer so we don't corrupt decrypted block
++         * this works because buffer is at least two block lengths long.
++         */
++        || !EVP_DecryptUpdate(ctx, tmp, &outl,
++                              tmp + inlen - blocklen, blocklen)
++        /* Can now decrypt first n - 1 blocks */
++        || !EVP_DecryptUpdate(ctx, tmp, &outl, in, inlen - blocklen)
++
++        /* Reset IV to original value */
++        || !EVP_DecryptInit_ex(ctx, NULL, NULL, NULL, NULL)
++        /* Decrypt again */
++        || !EVP_DecryptUpdate(ctx, tmp, &outl, tmp, inlen))
++        goto err;
++    /* Check check bytes */
++    if (((tmp[1] ^ tmp[4]) & (tmp[2] ^ tmp[5]) & (tmp[3] ^ tmp[6])) != 0xff) {
++        /* Check byte failure */
++        goto err;
++    }
++    if (inlen < (size_t)(tmp[0] - 4)) {
++        /* Invalid length value */
++        goto err;
++    }
++    *outlen = (size_t)tmp[0];
++    memcpy(out, tmp + 4, *outlen);
++    rv = 1;
++ err:
++    OPENSSL_clear_free(tmp, inlen);
++    return rv;
++
++}
++
++static int kek_wrap_key(unsigned char *out, size_t *outlen,
++                        const unsigned char *in, size_t inlen,
++                        EVP_CIPHER_CTX *ctx)
++{
++    size_t blocklen = EVP_CIPHER_CTX_block_size(ctx);
++    size_t olen;
++    int dummy;
++    /*
++     * First decide length of output buffer: need header and round up to
++     * multiple of block length.
++     */
++    olen = (inlen + 4 + blocklen - 1) / blocklen;
++    olen *= blocklen;
++    if (olen < 2 * blocklen) {
++        /* Key too small */
++        return 0;
++    }
++    if (inlen > 0xFF) {
++        /* Key too large */
++        return 0;
++    }
++    if (out) {
++        /* Set header */
++        out[0] = (unsigned char)inlen;
++        out[1] = in[0] ^ 0xFF;
++        out[2] = in[1] ^ 0xFF;
++        out[3] = in[2] ^ 0xFF;
++        memcpy(out + 4, in, inlen);
++        /* Add random padding to end */
++        if (olen > inlen + 4
++            && RAND_bytes(out + 4 + inlen, olen - 4 - inlen) <= 0)
++            return 0;
++        /* Encrypt twice */
++        if (!EVP_EncryptUpdate(ctx, out, &dummy, out, olen)
++            || !EVP_EncryptUpdate(ctx, out, &dummy, out, olen))
++            return 0;
++    }
++
++    *outlen = olen;
++
++    return 1;
++}
++
++/* Encrypt/Decrypt content key in PWRI recipient info */
++
++int cms_RecipientInfo_pwri_crypt(CMS_ContentInfo *cms, CMS_RecipientInfo *ri,
++                                 int en_de)
++{
++    CMS_EncryptedContentInfo *ec;
++    CMS_PasswordRecipientInfo *pwri;
++    int r = 0;
++    X509_ALGOR *algtmp, *kekalg = NULL;
++    EVP_CIPHER_CTX *kekctx = NULL;
++    const EVP_CIPHER *kekcipher;
++    unsigned char *key = NULL;
++    size_t keylen;
++
++    ec = cms->d.envelopedData->encryptedContentInfo;
++
++    pwri = ri->d.pwri;
++
++    if (!pwri->pass) {
++        CMSerr(CMS_F_CMS_RECIPIENTINFO_PWRI_CRYPT, CMS_R_NO_PASSWORD);
++        return 0;
++    }
++    algtmp = pwri->keyEncryptionAlgorithm;
++
++    if (!algtmp || OBJ_obj2nid(algtmp->algorithm) != NID_id_alg_PWRI_KEK) {
++        CMSerr(CMS_F_CMS_RECIPIENTINFO_PWRI_CRYPT,
++               CMS_R_UNSUPPORTED_KEY_ENCRYPTION_ALGORITHM);
++        return 0;
++    }
++
++    kekalg = ASN1_TYPE_unpack_sequence(ASN1_ITEM_rptr(X509_ALGOR),
++                                       algtmp->parameter);
++
++    if (kekalg == NULL) {
++        CMSerr(CMS_F_CMS_RECIPIENTINFO_PWRI_CRYPT,
++               CMS_R_INVALID_KEY_ENCRYPTION_PARAMETER);
++        return 0;
++    }
++
++    kekcipher = EVP_get_cipherbyobj(kekalg->algorithm);
++
++    if (!kekcipher) {
++        CMSerr(CMS_F_CMS_RECIPIENTINFO_PWRI_CRYPT, CMS_R_UNKNOWN_CIPHER);
++        return 0;
++    }
++
++    kekctx = EVP_CIPHER_CTX_new();
++    if (kekctx == NULL) {
++        CMSerr(CMS_F_CMS_RECIPIENTINFO_PWRI_CRYPT, ERR_R_MALLOC_FAILURE);
++        return 0;
++    }
++    /* Fixup cipher based on AlgorithmIdentifier to set IV etc */
++    if (!EVP_CipherInit_ex(kekctx, kekcipher, NULL, NULL, NULL, en_de))
++        goto err;
++    EVP_CIPHER_CTX_set_padding(kekctx, 0);
++    if (EVP_CIPHER_asn1_to_param(kekctx, kekalg->parameter) < 0) {
++        CMSerr(CMS_F_CMS_RECIPIENTINFO_PWRI_CRYPT,
++               CMS_R_CIPHER_PARAMETER_INITIALISATION_ERROR);
++        goto err;
++    }
++
++    algtmp = pwri->keyDerivationAlgorithm;
++
++    /* Finish password based key derivation to setup key in "ctx" */
++
++    if (EVP_PBE_CipherInit(algtmp->algorithm,
++                           (char *)pwri->pass, pwri->passlen,
++                           algtmp->parameter, kekctx, en_de) < 0) {
++        CMSerr(CMS_F_CMS_RECIPIENTINFO_PWRI_CRYPT, ERR_R_EVP_LIB);
++        goto err;
++    }
++
++    /* Finally wrap/unwrap the key */
++
++    if (en_de) {
++
++        if (!kek_wrap_key(NULL, &keylen, ec->key, ec->keylen, kekctx))
++            goto err;
++
++        key = OPENSSL_malloc(keylen);
++
++        if (key == NULL)
++            goto err;
++
++        if (!kek_wrap_key(key, &keylen, ec->key, ec->keylen, kekctx))
++            goto err;
++        pwri->encryptedKey->data = key;
++        pwri->encryptedKey->length = keylen;
++    } else {
++        key = OPENSSL_malloc(pwri->encryptedKey->length);
++
++        if (key == NULL) {
++            CMSerr(CMS_F_CMS_RECIPIENTINFO_PWRI_CRYPT, ERR_R_MALLOC_FAILURE);
++            goto err;
++        }
++        if (!kek_unwrap_key(key, &keylen,
++                            pwri->encryptedKey->data,
++                            pwri->encryptedKey->length, kekctx)) {
++            CMSerr(CMS_F_CMS_RECIPIENTINFO_PWRI_CRYPT, CMS_R_UNWRAP_FAILURE);
++            goto err;
++        }
++
++        ec->key = key;
++        ec->keylen = keylen;
++
++    }
++
++    r = 1;
++
++ err:
++
++    EVP_CIPHER_CTX_free(kekctx);
++
++    if (!r)
++        OPENSSL_free(key);
++    X509_ALGOR_free(kekalg);
++
++    return r;
++
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/cms/cms_sd.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/cms/cms_sd.c
+new file mode 100644
+index 0000000..76c1f53
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/cms/cms_sd.c
+@@ -0,0 +1,923 @@
++/*
++ * Copyright 2008-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include "internal/cryptlib.h"
++#include 
++#include 
++#include 
++#include 
++#include 
++#include 
++#include "cms_lcl.h"
++#include "internal/asn1_int.h"
++#include "internal/evp_int.h"
++
++/* CMS SignedData Utilities */
++
++static CMS_SignedData *cms_get0_signed(CMS_ContentInfo *cms)
++{
++    if (OBJ_obj2nid(cms->contentType) != NID_pkcs7_signed) {
++        CMSerr(CMS_F_CMS_GET0_SIGNED, CMS_R_CONTENT_TYPE_NOT_SIGNED_DATA);
++        return NULL;
++    }
++    return cms->d.signedData;
++}
++
++static CMS_SignedData *cms_signed_data_init(CMS_ContentInfo *cms)
++{
++    if (cms->d.other == NULL) {
++        cms->d.signedData = M_ASN1_new_of(CMS_SignedData);
++        if (!cms->d.signedData) {
++            CMSerr(CMS_F_CMS_SIGNED_DATA_INIT, ERR_R_MALLOC_FAILURE);
++            return NULL;
++        }
++        cms->d.signedData->version = 1;
++        cms->d.signedData->encapContentInfo->eContentType =
++            OBJ_nid2obj(NID_pkcs7_data);
++        cms->d.signedData->encapContentInfo->partial = 1;
++        ASN1_OBJECT_free(cms->contentType);
++        cms->contentType = OBJ_nid2obj(NID_pkcs7_signed);
++        return cms->d.signedData;
++    }
++    return cms_get0_signed(cms);
++}
++
++/* Just initialise SignedData e.g. for certs only structure */
++
++int CMS_SignedData_init(CMS_ContentInfo *cms)
++{
++    if (cms_signed_data_init(cms))
++        return 1;
++    else
++        return 0;
++}
++
++/* Check structures and fixup version numbers (if necessary) */
++
++static void cms_sd_set_version(CMS_SignedData *sd)
++{
++    int i;
++    CMS_CertificateChoices *cch;
++    CMS_RevocationInfoChoice *rch;
++    CMS_SignerInfo *si;
++
++    for (i = 0; i < sk_CMS_CertificateChoices_num(sd->certificates); i++) {
++        cch = sk_CMS_CertificateChoices_value(sd->certificates, i);
++        if (cch->type == CMS_CERTCHOICE_OTHER) {
++            if (sd->version < 5)
++                sd->version = 5;
++        } else if (cch->type == CMS_CERTCHOICE_V2ACERT) {
++            if (sd->version < 4)
++                sd->version = 4;
++        } else if (cch->type == CMS_CERTCHOICE_V1ACERT) {
++            if (sd->version < 3)
++                sd->version = 3;
++        }
++    }
++
++    for (i = 0; i < sk_CMS_RevocationInfoChoice_num(sd->crls); i++) {
++        rch = sk_CMS_RevocationInfoChoice_value(sd->crls, i);
++        if (rch->type == CMS_REVCHOICE_OTHER) {
++            if (sd->version < 5)
++                sd->version = 5;
++        }
++    }
++
++    if ((OBJ_obj2nid(sd->encapContentInfo->eContentType) != NID_pkcs7_data)
++        && (sd->version < 3))
++        sd->version = 3;
++
++    for (i = 0; i < sk_CMS_SignerInfo_num(sd->signerInfos); i++) {
++        si = sk_CMS_SignerInfo_value(sd->signerInfos, i);
++        if (si->sid->type == CMS_SIGNERINFO_KEYIDENTIFIER) {
++            if (si->version < 3)
++                si->version = 3;
++            if (sd->version < 3)
++                sd->version = 3;
++        } else if (si->version < 1)
++            si->version = 1;
++    }
++
++    if (sd->version < 1)
++        sd->version = 1;
++
++}
++
++/* Copy an existing messageDigest value */
++
++static int cms_copy_messageDigest(CMS_ContentInfo *cms, CMS_SignerInfo *si)
++{
++    STACK_OF(CMS_SignerInfo) *sinfos;
++    CMS_SignerInfo *sitmp;
++    int i;
++    sinfos = CMS_get0_SignerInfos(cms);
++    for (i = 0; i < sk_CMS_SignerInfo_num(sinfos); i++) {
++        ASN1_OCTET_STRING *messageDigest;
++        sitmp = sk_CMS_SignerInfo_value(sinfos, i);
++        if (sitmp == si)
++            continue;
++        if (CMS_signed_get_attr_count(sitmp) < 0)
++            continue;
++        if (OBJ_cmp(si->digestAlgorithm->algorithm,
++                    sitmp->digestAlgorithm->algorithm))
++            continue;
++        messageDigest = CMS_signed_get0_data_by_OBJ(sitmp,
++                                                    OBJ_nid2obj
++                                                    (NID_pkcs9_messageDigest),
++                                                    -3, V_ASN1_OCTET_STRING);
++        if (!messageDigest) {
++            CMSerr(CMS_F_CMS_COPY_MESSAGEDIGEST,
++                   CMS_R_ERROR_READING_MESSAGEDIGEST_ATTRIBUTE);
++            return 0;
++        }
++
++        if (CMS_signed_add1_attr_by_NID(si, NID_pkcs9_messageDigest,
++                                        V_ASN1_OCTET_STRING,
++                                        messageDigest, -1))
++            return 1;
++        else
++            return 0;
++    }
++    CMSerr(CMS_F_CMS_COPY_MESSAGEDIGEST, CMS_R_NO_MATCHING_DIGEST);
++    return 0;
++}
++
++int cms_set1_SignerIdentifier(CMS_SignerIdentifier *sid, X509 *cert, int type)
++{
++    switch (type) {
++    case CMS_SIGNERINFO_ISSUER_SERIAL:
++        if (!cms_set1_ias(&sid->d.issuerAndSerialNumber, cert))
++            return 0;
++        break;
++
++    case CMS_SIGNERINFO_KEYIDENTIFIER:
++        if (!cms_set1_keyid(&sid->d.subjectKeyIdentifier, cert))
++            return 0;
++        break;
++
++    default:
++        CMSerr(CMS_F_CMS_SET1_SIGNERIDENTIFIER, CMS_R_UNKNOWN_ID);
++        return 0;
++    }
++
++    sid->type = type;
++
++    return 1;
++}
++
++int cms_SignerIdentifier_get0_signer_id(CMS_SignerIdentifier *sid,
++                                        ASN1_OCTET_STRING **keyid,
++                                        X509_NAME **issuer,
++                                        ASN1_INTEGER **sno)
++{
++    if (sid->type == CMS_SIGNERINFO_ISSUER_SERIAL) {
++        if (issuer)
++            *issuer = sid->d.issuerAndSerialNumber->issuer;
++        if (sno)
++            *sno = sid->d.issuerAndSerialNumber->serialNumber;
++    } else if (sid->type == CMS_SIGNERINFO_KEYIDENTIFIER) {
++        if (keyid)
++            *keyid = sid->d.subjectKeyIdentifier;
++    } else
++        return 0;
++    return 1;
++}
++
++int cms_SignerIdentifier_cert_cmp(CMS_SignerIdentifier *sid, X509 *cert)
++{
++    if (sid->type == CMS_SIGNERINFO_ISSUER_SERIAL)
++        return cms_ias_cert_cmp(sid->d.issuerAndSerialNumber, cert);
++    else if (sid->type == CMS_SIGNERINFO_KEYIDENTIFIER)
++        return cms_keyid_cert_cmp(sid->d.subjectKeyIdentifier, cert);
++    else
++        return -1;
++}
++
++static int cms_sd_asn1_ctrl(CMS_SignerInfo *si, int cmd)
++{
++    EVP_PKEY *pkey = si->pkey;
++    int i;
++    if (!pkey->ameth || !pkey->ameth->pkey_ctrl)
++        return 1;
++    i = pkey->ameth->pkey_ctrl(pkey, ASN1_PKEY_CTRL_CMS_SIGN, cmd, si);
++    if (i == -2) {
++        CMSerr(CMS_F_CMS_SD_ASN1_CTRL, CMS_R_NOT_SUPPORTED_FOR_THIS_KEY_TYPE);
++        return 0;
++    }
++    if (i <= 0) {
++        CMSerr(CMS_F_CMS_SD_ASN1_CTRL, CMS_R_CTRL_FAILURE);
++        return 0;
++    }
++    return 1;
++}
++
++CMS_SignerInfo *CMS_add1_signer(CMS_ContentInfo *cms,
++                                X509 *signer, EVP_PKEY *pk, const EVP_MD *md,
++                                unsigned int flags)
++{
++    CMS_SignedData *sd;
++    CMS_SignerInfo *si = NULL;
++    X509_ALGOR *alg;
++    int i, type;
++    if (!X509_check_private_key(signer, pk)) {
++        CMSerr(CMS_F_CMS_ADD1_SIGNER,
++               CMS_R_PRIVATE_KEY_DOES_NOT_MATCH_CERTIFICATE);
++        return NULL;
++    }
++    sd = cms_signed_data_init(cms);
++    if (!sd)
++        goto err;
++    si = M_ASN1_new_of(CMS_SignerInfo);
++    if (!si)
++        goto merr;
++    /* Call for side-effect of computing hash and caching extensions */
++    X509_check_purpose(signer, -1, -1);
++
++    X509_up_ref(signer);
++    EVP_PKEY_up_ref(pk);
++
++    si->pkey = pk;
++    si->signer = signer;
++    si->mctx = EVP_MD_CTX_new();
++    si->pctx = NULL;
++
++    if (si->mctx == NULL) {
++        CMSerr(CMS_F_CMS_ADD1_SIGNER, ERR_R_MALLOC_FAILURE);
++        goto err;
++    }
++
++    if (flags & CMS_USE_KEYID) {
++        si->version = 3;
++        if (sd->version < 3)
++            sd->version = 3;
++        type = CMS_SIGNERINFO_KEYIDENTIFIER;
++    } else {
++        type = CMS_SIGNERINFO_ISSUER_SERIAL;
++        si->version = 1;
++    }
++
++    if (!cms_set1_SignerIdentifier(si->sid, signer, type))
++        goto err;
++
++    if (md == NULL) {
++        int def_nid;
++        if (EVP_PKEY_get_default_digest_nid(pk, &def_nid) <= 0)
++            goto err;
++        md = EVP_get_digestbynid(def_nid);
++        if (md == NULL) {
++            CMSerr(CMS_F_CMS_ADD1_SIGNER, CMS_R_NO_DEFAULT_DIGEST);
++            goto err;
++        }
++    }
++
++    if (!md) {
++        CMSerr(CMS_F_CMS_ADD1_SIGNER, CMS_R_NO_DIGEST_SET);
++        goto err;
++    }
++
++    X509_ALGOR_set_md(si->digestAlgorithm, md);
++
++    /* See if digest is present in digestAlgorithms */
++    for (i = 0; i < sk_X509_ALGOR_num(sd->digestAlgorithms); i++) {
++        const ASN1_OBJECT *aoid;
++        alg = sk_X509_ALGOR_value(sd->digestAlgorithms, i);
++        X509_ALGOR_get0(&aoid, NULL, NULL, alg);
++        if (OBJ_obj2nid(aoid) == EVP_MD_type(md))
++            break;
++    }
++
++    if (i == sk_X509_ALGOR_num(sd->digestAlgorithms)) {
++        alg = X509_ALGOR_new();
++        if (alg == NULL)
++            goto merr;
++        X509_ALGOR_set_md(alg, md);
++        if (!sk_X509_ALGOR_push(sd->digestAlgorithms, alg)) {
++            X509_ALGOR_free(alg);
++            goto merr;
++        }
++    }
++
++    if (!(flags & CMS_KEY_PARAM) && !cms_sd_asn1_ctrl(si, 0))
++        goto err;
++    if (!(flags & CMS_NOATTR)) {
++        /*
++         * Initialize signed attributes structure so other attributes
++         * such as signing time etc are added later even if we add none here.
++         */
++        if (!si->signedAttrs) {
++            si->signedAttrs = sk_X509_ATTRIBUTE_new_null();
++            if (!si->signedAttrs)
++                goto merr;
++        }
++
++        if (!(flags & CMS_NOSMIMECAP)) {
++            STACK_OF(X509_ALGOR) *smcap = NULL;
++            i = CMS_add_standard_smimecap(&smcap);
++            if (i)
++                i = CMS_add_smimecap(si, smcap);
++            sk_X509_ALGOR_pop_free(smcap, X509_ALGOR_free);
++            if (!i)
++                goto merr;
++        }
++        if (flags & CMS_REUSE_DIGEST) {
++            if (!cms_copy_messageDigest(cms, si))
++                goto err;
++            if (!(flags & (CMS_PARTIAL | CMS_KEY_PARAM)) &&
++                !CMS_SignerInfo_sign(si))
++                goto err;
++        }
++    }
++
++    if (!(flags & CMS_NOCERTS)) {
++        /* NB ignore -1 return for duplicate cert */
++        if (!CMS_add1_cert(cms, signer))
++            goto merr;
++    }
++
++    if (flags & CMS_KEY_PARAM) {
++        if (flags & CMS_NOATTR) {
++            si->pctx = EVP_PKEY_CTX_new(si->pkey, NULL);
++            if (si->pctx == NULL)
++                goto err;
++            if (EVP_PKEY_sign_init(si->pctx) <= 0)
++                goto err;
++            if (EVP_PKEY_CTX_set_signature_md(si->pctx, md) <= 0)
++                goto err;
++        } else if (EVP_DigestSignInit(si->mctx, &si->pctx, md, NULL, pk) <=
++                   0)
++            goto err;
++    }
++
++    if (!sd->signerInfos)
++        sd->signerInfos = sk_CMS_SignerInfo_new_null();
++    if (!sd->signerInfos || !sk_CMS_SignerInfo_push(sd->signerInfos, si))
++        goto merr;
++
++    return si;
++
++ merr:
++    CMSerr(CMS_F_CMS_ADD1_SIGNER, ERR_R_MALLOC_FAILURE);
++ err:
++    M_ASN1_free_of(si, CMS_SignerInfo);
++    return NULL;
++
++}
++
++static int cms_add1_signingTime(CMS_SignerInfo *si, ASN1_TIME *t)
++{
++    ASN1_TIME *tt;
++    int r = 0;
++    if (t)
++        tt = t;
++    else
++        tt = X509_gmtime_adj(NULL, 0);
++
++    if (!tt)
++        goto merr;
++
++    if (CMS_signed_add1_attr_by_NID(si, NID_pkcs9_signingTime,
++                                    tt->type, tt, -1) <= 0)
++        goto merr;
++
++    r = 1;
++
++ merr:
++
++    if (!t)
++        ASN1_TIME_free(tt);
++
++    if (!r)
++        CMSerr(CMS_F_CMS_ADD1_SIGNINGTIME, ERR_R_MALLOC_FAILURE);
++
++    return r;
++
++}
++
++EVP_PKEY_CTX *CMS_SignerInfo_get0_pkey_ctx(CMS_SignerInfo *si)
++{
++    return si->pctx;
++}
++
++EVP_MD_CTX *CMS_SignerInfo_get0_md_ctx(CMS_SignerInfo *si)
++{
++    return si->mctx;
++}
++
++STACK_OF(CMS_SignerInfo) *CMS_get0_SignerInfos(CMS_ContentInfo *cms)
++{
++    CMS_SignedData *sd;
++    sd = cms_get0_signed(cms);
++    if (!sd)
++        return NULL;
++    return sd->signerInfos;
++}
++
++STACK_OF(X509) *CMS_get0_signers(CMS_ContentInfo *cms)
++{
++    STACK_OF(X509) *signers = NULL;
++    STACK_OF(CMS_SignerInfo) *sinfos;
++    CMS_SignerInfo *si;
++    int i;
++    sinfos = CMS_get0_SignerInfos(cms);
++    for (i = 0; i < sk_CMS_SignerInfo_num(sinfos); i++) {
++        si = sk_CMS_SignerInfo_value(sinfos, i);
++        if (si->signer) {
++            if (!signers) {
++                signers = sk_X509_new_null();
++                if (!signers)
++                    return NULL;
++            }
++            if (!sk_X509_push(signers, si->signer)) {
++                sk_X509_free(signers);
++                return NULL;
++            }
++        }
++    }
++    return signers;
++}
++
++void CMS_SignerInfo_set1_signer_cert(CMS_SignerInfo *si, X509 *signer)
++{
++    if (signer) {
++        X509_up_ref(signer);
++        EVP_PKEY_free(si->pkey);
++        si->pkey = X509_get_pubkey(signer);
++    }
++    X509_free(si->signer);
++    si->signer = signer;
++}
++
++int CMS_SignerInfo_get0_signer_id(CMS_SignerInfo *si,
++                                  ASN1_OCTET_STRING **keyid,
++                                  X509_NAME **issuer, ASN1_INTEGER **sno)
++{
++    return cms_SignerIdentifier_get0_signer_id(si->sid, keyid, issuer, sno);
++}
++
++int CMS_SignerInfo_cert_cmp(CMS_SignerInfo *si, X509 *cert)
++{
++    return cms_SignerIdentifier_cert_cmp(si->sid, cert);
++}
++
++int CMS_set1_signers_certs(CMS_ContentInfo *cms, STACK_OF(X509) *scerts,
++                           unsigned int flags)
++{
++    CMS_SignedData *sd;
++    CMS_SignerInfo *si;
++    CMS_CertificateChoices *cch;
++    STACK_OF(CMS_CertificateChoices) *certs;
++    X509 *x;
++    int i, j;
++    int ret = 0;
++    sd = cms_get0_signed(cms);
++    if (!sd)
++        return -1;
++    certs = sd->certificates;
++    for (i = 0; i < sk_CMS_SignerInfo_num(sd->signerInfos); i++) {
++        si = sk_CMS_SignerInfo_value(sd->signerInfos, i);
++        if (si->signer)
++            continue;
++
++        for (j = 0; j < sk_X509_num(scerts); j++) {
++            x = sk_X509_value(scerts, j);
++            if (CMS_SignerInfo_cert_cmp(si, x) == 0) {
++                CMS_SignerInfo_set1_signer_cert(si, x);
++                ret++;
++                break;
++            }
++        }
++
++        if (si->signer || (flags & CMS_NOINTERN))
++            continue;
++
++        for (j = 0; j < sk_CMS_CertificateChoices_num(certs); j++) {
++            cch = sk_CMS_CertificateChoices_value(certs, j);
++            if (cch->type != 0)
++                continue;
++            x = cch->d.certificate;
++            if (CMS_SignerInfo_cert_cmp(si, x) == 0) {
++                CMS_SignerInfo_set1_signer_cert(si, x);
++                ret++;
++                break;
++            }
++        }
++    }
++    return ret;
++}
++
++void CMS_SignerInfo_get0_algs(CMS_SignerInfo *si, EVP_PKEY **pk,
++                              X509 **signer, X509_ALGOR **pdig,
++                              X509_ALGOR **psig)
++{
++    if (pk)
++        *pk = si->pkey;
++    if (signer)
++        *signer = si->signer;
++    if (pdig)
++        *pdig = si->digestAlgorithm;
++    if (psig)
++        *psig = si->signatureAlgorithm;
++}
++
++ASN1_OCTET_STRING *CMS_SignerInfo_get0_signature(CMS_SignerInfo *si)
++{
++    return si->signature;
++}
++
++static int cms_SignerInfo_content_sign(CMS_ContentInfo *cms,
++                                       CMS_SignerInfo *si, BIO *chain)
++{
++    EVP_MD_CTX *mctx = EVP_MD_CTX_new();
++    int r = 0;
++    EVP_PKEY_CTX *pctx = NULL;
++
++    if (mctx == NULL) {
++        CMSerr(CMS_F_CMS_SIGNERINFO_CONTENT_SIGN, ERR_R_MALLOC_FAILURE);
++        return 0;
++    }
++
++    if (!si->pkey) {
++        CMSerr(CMS_F_CMS_SIGNERINFO_CONTENT_SIGN, CMS_R_NO_PRIVATE_KEY);
++        goto err;
++    }
++
++    if (!cms_DigestAlgorithm_find_ctx(mctx, chain, si->digestAlgorithm))
++        goto err;
++    /* Set SignerInfo algorithm details if we used custom parameter */
++    if (si->pctx && !cms_sd_asn1_ctrl(si, 0))
++        goto err;
++
++    /*
++     * If any signed attributes calculate and add messageDigest attribute
++     */
++
++    if (CMS_signed_get_attr_count(si) >= 0) {
++        ASN1_OBJECT *ctype =
++            cms->d.signedData->encapContentInfo->eContentType;
++        unsigned char md[EVP_MAX_MD_SIZE];
++        unsigned int mdlen;
++        if (!EVP_DigestFinal_ex(mctx, md, &mdlen))
++            goto err;
++        if (!CMS_signed_add1_attr_by_NID(si, NID_pkcs9_messageDigest,
++                                         V_ASN1_OCTET_STRING, md, mdlen))
++            goto err;
++        /* Copy content type across */
++        if (CMS_signed_add1_attr_by_NID(si, NID_pkcs9_contentType,
++                                        V_ASN1_OBJECT, ctype, -1) <= 0)
++            goto err;
++        if (!CMS_SignerInfo_sign(si))
++            goto err;
++    } else if (si->pctx) {
++        unsigned char *sig;
++        size_t siglen;
++        unsigned char md[EVP_MAX_MD_SIZE];
++        unsigned int mdlen;
++        pctx = si->pctx;
++        if (!EVP_DigestFinal_ex(mctx, md, &mdlen))
++            goto err;
++        siglen = EVP_PKEY_size(si->pkey);
++        sig = OPENSSL_malloc(siglen);
++        if (sig == NULL) {
++            CMSerr(CMS_F_CMS_SIGNERINFO_CONTENT_SIGN, ERR_R_MALLOC_FAILURE);
++            goto err;
++        }
++        if (EVP_PKEY_sign(pctx, sig, &siglen, md, mdlen) <= 0) {
++            OPENSSL_free(sig);
++            goto err;
++        }
++        ASN1_STRING_set0(si->signature, sig, siglen);
++    } else {
++        unsigned char *sig;
++        unsigned int siglen;
++        sig = OPENSSL_malloc(EVP_PKEY_size(si->pkey));
++        if (sig == NULL) {
++            CMSerr(CMS_F_CMS_SIGNERINFO_CONTENT_SIGN, ERR_R_MALLOC_FAILURE);
++            goto err;
++        }
++        if (!EVP_SignFinal(mctx, sig, &siglen, si->pkey)) {
++            CMSerr(CMS_F_CMS_SIGNERINFO_CONTENT_SIGN, CMS_R_SIGNFINAL_ERROR);
++            OPENSSL_free(sig);
++            goto err;
++        }
++        ASN1_STRING_set0(si->signature, sig, siglen);
++    }
++
++    r = 1;
++
++ err:
++    EVP_MD_CTX_free(mctx);
++    EVP_PKEY_CTX_free(pctx);
++    return r;
++
++}
++
++int cms_SignedData_final(CMS_ContentInfo *cms, BIO *chain)
++{
++    STACK_OF(CMS_SignerInfo) *sinfos;
++    CMS_SignerInfo *si;
++    int i;
++    sinfos = CMS_get0_SignerInfos(cms);
++    for (i = 0; i < sk_CMS_SignerInfo_num(sinfos); i++) {
++        si = sk_CMS_SignerInfo_value(sinfos, i);
++        if (!cms_SignerInfo_content_sign(cms, si, chain))
++            return 0;
++    }
++    cms->d.signedData->encapContentInfo->partial = 0;
++    return 1;
++}
++
++int CMS_SignerInfo_sign(CMS_SignerInfo *si)
++{
++    EVP_MD_CTX *mctx = si->mctx;
++    EVP_PKEY_CTX *pctx;
++    unsigned char *abuf = NULL;
++    int alen;
++    size_t siglen;
++    const EVP_MD *md = NULL;
++
++    md = EVP_get_digestbyobj(si->digestAlgorithm->algorithm);
++    if (md == NULL)
++        return 0;
++
++    if (CMS_signed_get_attr_by_NID(si, NID_pkcs9_signingTime, -1) < 0) {
++        if (!cms_add1_signingTime(si, NULL))
++            goto err;
++    }
++
++    if (si->pctx)
++        pctx = si->pctx;
++    else {
++        EVP_MD_CTX_reset(mctx);
++        if (EVP_DigestSignInit(mctx, &pctx, md, NULL, si->pkey) <= 0)
++            goto err;
++    }
++
++    if (EVP_PKEY_CTX_ctrl(pctx, -1, EVP_PKEY_OP_SIGN,
++                          EVP_PKEY_CTRL_CMS_SIGN, 0, si) <= 0) {
++        CMSerr(CMS_F_CMS_SIGNERINFO_SIGN, CMS_R_CTRL_ERROR);
++        goto err;
++    }
++
++    alen = ASN1_item_i2d((ASN1_VALUE *)si->signedAttrs, &abuf,
++                         ASN1_ITEM_rptr(CMS_Attributes_Sign));
++    if (!abuf)
++        goto err;
++    if (EVP_DigestSignUpdate(mctx, abuf, alen) <= 0)
++        goto err;
++    if (EVP_DigestSignFinal(mctx, NULL, &siglen) <= 0)
++        goto err;
++    OPENSSL_free(abuf);
++    abuf = OPENSSL_malloc(siglen);
++    if (abuf == NULL)
++        goto err;
++    if (EVP_DigestSignFinal(mctx, abuf, &siglen) <= 0)
++        goto err;
++
++    if (EVP_PKEY_CTX_ctrl(pctx, -1, EVP_PKEY_OP_SIGN,
++                          EVP_PKEY_CTRL_CMS_SIGN, 1, si) <= 0) {
++        CMSerr(CMS_F_CMS_SIGNERINFO_SIGN, CMS_R_CTRL_ERROR);
++        goto err;
++    }
++
++    EVP_MD_CTX_reset(mctx);
++
++    ASN1_STRING_set0(si->signature, abuf, siglen);
++
++    return 1;
++
++ err:
++    OPENSSL_free(abuf);
++    EVP_MD_CTX_reset(mctx);
++    return 0;
++
++}
++
++int CMS_SignerInfo_verify(CMS_SignerInfo *si)
++{
++    EVP_MD_CTX *mctx = NULL;
++    unsigned char *abuf = NULL;
++    int alen, r = -1;
++    const EVP_MD *md = NULL;
++
++    if (!si->pkey) {
++        CMSerr(CMS_F_CMS_SIGNERINFO_VERIFY, CMS_R_NO_PUBLIC_KEY);
++        return -1;
++    }
++
++    md = EVP_get_digestbyobj(si->digestAlgorithm->algorithm);
++    if (md == NULL)
++        return -1;
++    if (si->mctx == NULL)
++        si->mctx = EVP_MD_CTX_new();
++    mctx = si->mctx;
++    if (EVP_DigestVerifyInit(mctx, &si->pctx, md, NULL, si->pkey) <= 0)
++        goto err;
++
++    if (!cms_sd_asn1_ctrl(si, 1))
++        goto err;
++
++    alen = ASN1_item_i2d((ASN1_VALUE *)si->signedAttrs, &abuf,
++                         ASN1_ITEM_rptr(CMS_Attributes_Verify));
++    if (!abuf)
++        goto err;
++    r = EVP_DigestVerifyUpdate(mctx, abuf, alen);
++    OPENSSL_free(abuf);
++    if (r <= 0) {
++        r = -1;
++        goto err;
++    }
++    r = EVP_DigestVerifyFinal(mctx,
++                              si->signature->data, si->signature->length);
++    if (r <= 0)
++        CMSerr(CMS_F_CMS_SIGNERINFO_VERIFY, CMS_R_VERIFICATION_FAILURE);
++ err:
++    EVP_MD_CTX_reset(mctx);
++    return r;
++}
++
++/* Create a chain of digest BIOs from a CMS ContentInfo */
++
++BIO *cms_SignedData_init_bio(CMS_ContentInfo *cms)
++{
++    int i;
++    CMS_SignedData *sd;
++    BIO *chain = NULL;
++    sd = cms_get0_signed(cms);
++    if (!sd)
++        return NULL;
++    if (cms->d.signedData->encapContentInfo->partial)
++        cms_sd_set_version(sd);
++    for (i = 0; i < sk_X509_ALGOR_num(sd->digestAlgorithms); i++) {
++        X509_ALGOR *digestAlgorithm;
++        BIO *mdbio;
++        digestAlgorithm = sk_X509_ALGOR_value(sd->digestAlgorithms, i);
++        mdbio = cms_DigestAlgorithm_init_bio(digestAlgorithm);
++        if (!mdbio)
++            goto err;
++        if (chain)
++            BIO_push(chain, mdbio);
++        else
++            chain = mdbio;
++    }
++    return chain;
++ err:
++    BIO_free_all(chain);
++    return NULL;
++}
++
++int CMS_SignerInfo_verify_content(CMS_SignerInfo *si, BIO *chain)
++{
++    ASN1_OCTET_STRING *os = NULL;
++    EVP_MD_CTX *mctx = EVP_MD_CTX_new();
++    EVP_PKEY_CTX *pkctx = NULL;
++    int r = -1;
++    unsigned char mval[EVP_MAX_MD_SIZE];
++    unsigned int mlen;
++
++    if (mctx == NULL) {
++        CMSerr(CMS_F_CMS_SIGNERINFO_VERIFY_CONTENT, ERR_R_MALLOC_FAILURE);
++        goto err;
++    }
++    /* If we have any signed attributes look for messageDigest value */
++    if (CMS_signed_get_attr_count(si) >= 0) {
++        os = CMS_signed_get0_data_by_OBJ(si,
++                                         OBJ_nid2obj(NID_pkcs9_messageDigest),
++                                         -3, V_ASN1_OCTET_STRING);
++        if (!os) {
++            CMSerr(CMS_F_CMS_SIGNERINFO_VERIFY_CONTENT,
++                   CMS_R_ERROR_READING_MESSAGEDIGEST_ATTRIBUTE);
++            goto err;
++        }
++    }
++
++    if (!cms_DigestAlgorithm_find_ctx(mctx, chain, si->digestAlgorithm))
++        goto err;
++
++    if (EVP_DigestFinal_ex(mctx, mval, &mlen) <= 0) {
++        CMSerr(CMS_F_CMS_SIGNERINFO_VERIFY_CONTENT,
++               CMS_R_UNABLE_TO_FINALIZE_CONTEXT);
++        goto err;
++    }
++
++    /* If messageDigest found compare it */
++
++    if (os) {
++        if (mlen != (unsigned int)os->length) {
++            CMSerr(CMS_F_CMS_SIGNERINFO_VERIFY_CONTENT,
++                   CMS_R_MESSAGEDIGEST_ATTRIBUTE_WRONG_LENGTH);
++            goto err;
++        }
++
++        if (memcmp(mval, os->data, mlen)) {
++            CMSerr(CMS_F_CMS_SIGNERINFO_VERIFY_CONTENT,
++                   CMS_R_VERIFICATION_FAILURE);
++            r = 0;
++        } else
++            r = 1;
++    } else {
++        const EVP_MD *md = EVP_MD_CTX_md(mctx);
++        pkctx = EVP_PKEY_CTX_new(si->pkey, NULL);
++        if (pkctx == NULL)
++            goto err;
++        if (EVP_PKEY_verify_init(pkctx) <= 0)
++            goto err;
++        if (EVP_PKEY_CTX_set_signature_md(pkctx, md) <= 0)
++            goto err;
++        si->pctx = pkctx;
++        if (!cms_sd_asn1_ctrl(si, 1))
++            goto err;
++        r = EVP_PKEY_verify(pkctx, si->signature->data,
++                            si->signature->length, mval, mlen);
++        if (r <= 0) {
++            CMSerr(CMS_F_CMS_SIGNERINFO_VERIFY_CONTENT,
++                   CMS_R_VERIFICATION_FAILURE);
++            r = 0;
++        }
++    }
++
++ err:
++    EVP_PKEY_CTX_free(pkctx);
++    EVP_MD_CTX_free(mctx);
++    return r;
++
++}
++
++int CMS_add_smimecap(CMS_SignerInfo *si, STACK_OF(X509_ALGOR) *algs)
++{
++    unsigned char *smder = NULL;
++    int smderlen, r;
++    smderlen = i2d_X509_ALGORS(algs, &smder);
++    if (smderlen <= 0)
++        return 0;
++    r = CMS_signed_add1_attr_by_NID(si, NID_SMIMECapabilities,
++                                    V_ASN1_SEQUENCE, smder, smderlen);
++    OPENSSL_free(smder);
++    return r;
++}
++
++int CMS_add_simple_smimecap(STACK_OF(X509_ALGOR) **algs,
++                            int algnid, int keysize)
++{
++    X509_ALGOR *alg;
++    ASN1_INTEGER *key = NULL;
++    if (keysize > 0) {
++        key = ASN1_INTEGER_new();
++        if (key == NULL || !ASN1_INTEGER_set(key, keysize))
++            return 0;
++    }
++    alg = X509_ALGOR_new();
++    if (alg == NULL) {
++        ASN1_INTEGER_free(key);
++        return 0;
++    }
++
++    X509_ALGOR_set0(alg, OBJ_nid2obj(algnid),
++                    key ? V_ASN1_INTEGER : V_ASN1_UNDEF, key);
++    if (*algs == NULL)
++        *algs = sk_X509_ALGOR_new_null();
++    if (*algs == NULL || !sk_X509_ALGOR_push(*algs, alg)) {
++        X509_ALGOR_free(alg);
++        return 0;
++    }
++    return 1;
++}
++
++/* Check to see if a cipher exists and if so add S/MIME capabilities */
++
++static int cms_add_cipher_smcap(STACK_OF(X509_ALGOR) **sk, int nid, int arg)
++{
++    if (EVP_get_cipherbynid(nid))
++        return CMS_add_simple_smimecap(sk, nid, arg);
++    return 1;
++}
++
++static int cms_add_digest_smcap(STACK_OF(X509_ALGOR) **sk, int nid, int arg)
++{
++    if (EVP_get_digestbynid(nid))
++        return CMS_add_simple_smimecap(sk, nid, arg);
++    return 1;
++}
++
++int CMS_add_standard_smimecap(STACK_OF(X509_ALGOR) **smcap)
++{
++    if (!cms_add_cipher_smcap(smcap, NID_aes_256_cbc, -1)
++        || !cms_add_digest_smcap(smcap, NID_id_GostR3411_2012_256, -1)
++        || !cms_add_digest_smcap(smcap, NID_id_GostR3411_2012_512, -1)
++        || !cms_add_digest_smcap(smcap, NID_id_GostR3411_94, -1)
++        || !cms_add_cipher_smcap(smcap, NID_id_Gost28147_89, -1)
++        || !cms_add_cipher_smcap(smcap, NID_aes_192_cbc, -1)
++        || !cms_add_cipher_smcap(smcap, NID_aes_128_cbc, -1)
++        || !cms_add_cipher_smcap(smcap, NID_des_ede3_cbc, -1)
++        || !cms_add_cipher_smcap(smcap, NID_rc2_cbc, 128)
++        || !cms_add_cipher_smcap(smcap, NID_rc2_cbc, 64)
++        || !cms_add_cipher_smcap(smcap, NID_des_cbc, -1)
++        || !cms_add_cipher_smcap(smcap, NID_rc2_cbc, 40))
++        return 0;
++    return 1;
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/cms/cms_smime.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/cms/cms_smime.c
+new file mode 100644
+index 0000000..dbf7dd3
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/cms/cms_smime.c
+@@ -0,0 +1,844 @@
++/*
++ * Copyright 2008-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include "internal/cryptlib.h"
++#include 
++#include 
++#include 
++#include 
++#include 
++#include "cms_lcl.h"
++#include "internal/asn1_int.h"
++
++static BIO *cms_get_text_bio(BIO *out, unsigned int flags)
++{
++    BIO *rbio;
++    if (out == NULL)
++        rbio = BIO_new(BIO_s_null());
++    else if (flags & CMS_TEXT) {
++        rbio = BIO_new(BIO_s_mem());
++        BIO_set_mem_eof_return(rbio, 0);
++    } else
++        rbio = out;
++    return rbio;
++}
++
++static int cms_copy_content(BIO *out, BIO *in, unsigned int flags)
++{
++    unsigned char buf[4096];
++    int r = 0, i;
++    BIO *tmpout;
++
++    tmpout = cms_get_text_bio(out, flags);
++
++    if (tmpout == NULL) {
++        CMSerr(CMS_F_CMS_COPY_CONTENT, ERR_R_MALLOC_FAILURE);
++        goto err;
++    }
++
++    /* Read all content through chain to process digest, decrypt etc */
++    for (;;) {
++        i = BIO_read(in, buf, sizeof(buf));
++        if (i <= 0) {
++            if (BIO_method_type(in) == BIO_TYPE_CIPHER) {
++                if (!BIO_get_cipher_status(in))
++                    goto err;
++            }
++            if (i < 0)
++                goto err;
++            break;
++        }
++
++        if (tmpout && (BIO_write(tmpout, buf, i) != i))
++            goto err;
++    }
++
++    if (flags & CMS_TEXT) {
++        if (!SMIME_text(tmpout, out)) {
++            CMSerr(CMS_F_CMS_COPY_CONTENT, CMS_R_SMIME_TEXT_ERROR);
++            goto err;
++        }
++    }
++
++    r = 1;
++
++ err:
++    if (tmpout != out)
++        BIO_free(tmpout);
++    return r;
++
++}
++
++static int check_content(CMS_ContentInfo *cms)
++{
++    ASN1_OCTET_STRING **pos = CMS_get0_content(cms);
++    if (!pos || !*pos) {
++        CMSerr(CMS_F_CHECK_CONTENT, CMS_R_NO_CONTENT);
++        return 0;
++    }
++    return 1;
++}
++
++static void do_free_upto(BIO *f, BIO *upto)
++{
++    if (upto) {
++        BIO *tbio;
++        do {
++            tbio = BIO_pop(f);
++            BIO_free(f);
++            f = tbio;
++        }
++        while (f && f != upto);
++    } else
++        BIO_free_all(f);
++}
++
++int CMS_data(CMS_ContentInfo *cms, BIO *out, unsigned int flags)
++{
++    BIO *cont;
++    int r;
++    if (OBJ_obj2nid(CMS_get0_type(cms)) != NID_pkcs7_data) {
++        CMSerr(CMS_F_CMS_DATA, CMS_R_TYPE_NOT_DATA);
++        return 0;
++    }
++    cont = CMS_dataInit(cms, NULL);
++    if (!cont)
++        return 0;
++    r = cms_copy_content(out, cont, flags);
++    BIO_free_all(cont);
++    return r;
++}
++
++CMS_ContentInfo *CMS_data_create(BIO *in, unsigned int flags)
++{
++    CMS_ContentInfo *cms;
++    cms = cms_Data_create();
++    if (!cms)
++        return NULL;
++
++    if ((flags & CMS_STREAM) || CMS_final(cms, in, NULL, flags))
++        return cms;
++
++    CMS_ContentInfo_free(cms);
++
++    return NULL;
++}
++
++int CMS_digest_verify(CMS_ContentInfo *cms, BIO *dcont, BIO *out,
++                      unsigned int flags)
++{
++    BIO *cont;
++    int r;
++    if (OBJ_obj2nid(CMS_get0_type(cms)) != NID_pkcs7_digest) {
++        CMSerr(CMS_F_CMS_DIGEST_VERIFY, CMS_R_TYPE_NOT_DIGESTED_DATA);
++        return 0;
++    }
++
++    if (!dcont && !check_content(cms))
++        return 0;
++
++    cont = CMS_dataInit(cms, dcont);
++    if (!cont)
++        return 0;
++    r = cms_copy_content(out, cont, flags);
++    if (r)
++        r = cms_DigestedData_do_final(cms, cont, 1);
++    do_free_upto(cont, dcont);
++    return r;
++}
++
++CMS_ContentInfo *CMS_digest_create(BIO *in, const EVP_MD *md,
++                                   unsigned int flags)
++{
++    CMS_ContentInfo *cms;
++    if (!md)
++        md = EVP_sha1();
++    cms = cms_DigestedData_create(md);
++    if (!cms)
++        return NULL;
++
++    if (!(flags & CMS_DETACHED))
++        CMS_set_detached(cms, 0);
++
++    if ((flags & CMS_STREAM) || CMS_final(cms, in, NULL, flags))
++        return cms;
++
++    CMS_ContentInfo_free(cms);
++    return NULL;
++}
++
++int CMS_EncryptedData_decrypt(CMS_ContentInfo *cms,
++                              const unsigned char *key, size_t keylen,
++                              BIO *dcont, BIO *out, unsigned int flags)
++{
++    BIO *cont;
++    int r;
++    if (OBJ_obj2nid(CMS_get0_type(cms)) != NID_pkcs7_encrypted) {
++        CMSerr(CMS_F_CMS_ENCRYPTEDDATA_DECRYPT,
++               CMS_R_TYPE_NOT_ENCRYPTED_DATA);
++        return 0;
++    }
++
++    if (!dcont && !check_content(cms))
++        return 0;
++
++    if (CMS_EncryptedData_set1_key(cms, NULL, key, keylen) <= 0)
++        return 0;
++    cont = CMS_dataInit(cms, dcont);
++    if (!cont)
++        return 0;
++    r = cms_copy_content(out, cont, flags);
++    do_free_upto(cont, dcont);
++    return r;
++}
++
++CMS_ContentInfo *CMS_EncryptedData_encrypt(BIO *in, const EVP_CIPHER *cipher,
++                                           const unsigned char *key,
++                                           size_t keylen, unsigned int flags)
++{
++    CMS_ContentInfo *cms;
++    if (!cipher) {
++        CMSerr(CMS_F_CMS_ENCRYPTEDDATA_ENCRYPT, CMS_R_NO_CIPHER);
++        return NULL;
++    }
++    cms = CMS_ContentInfo_new();
++    if (cms == NULL)
++        return NULL;
++    if (!CMS_EncryptedData_set1_key(cms, cipher, key, keylen))
++        return NULL;
++
++    if (!(flags & CMS_DETACHED))
++        CMS_set_detached(cms, 0);
++
++    if ((flags & (CMS_STREAM | CMS_PARTIAL))
++        || CMS_final(cms, in, NULL, flags))
++        return cms;
++
++    CMS_ContentInfo_free(cms);
++    return NULL;
++}
++
++static int cms_signerinfo_verify_cert(CMS_SignerInfo *si,
++                                      X509_STORE *store,
++                                      STACK_OF(X509) *certs,
++                                      STACK_OF(X509_CRL) *crls)
++{
++    X509_STORE_CTX *ctx = X509_STORE_CTX_new();
++    X509 *signer;
++    int i, j, r = 0;
++
++    if (ctx == NULL) {
++        CMSerr(CMS_F_CMS_SIGNERINFO_VERIFY_CERT, ERR_R_MALLOC_FAILURE);
++        goto err;
++    }
++    CMS_SignerInfo_get0_algs(si, NULL, &signer, NULL, NULL);
++    if (!X509_STORE_CTX_init(ctx, store, signer, certs)) {
++        CMSerr(CMS_F_CMS_SIGNERINFO_VERIFY_CERT, CMS_R_STORE_INIT_ERROR);
++        goto err;
++    }
++    X509_STORE_CTX_set_default(ctx, "smime_sign");
++    if (crls)
++        X509_STORE_CTX_set0_crls(ctx, crls);
++
++    i = X509_verify_cert(ctx);
++    if (i <= 0) {
++        j = X509_STORE_CTX_get_error(ctx);
++        CMSerr(CMS_F_CMS_SIGNERINFO_VERIFY_CERT,
++               CMS_R_CERTIFICATE_VERIFY_ERROR);
++        ERR_add_error_data(2, "Verify error:",
++                           X509_verify_cert_error_string(j));
++        goto err;
++    }
++    r = 1;
++ err:
++    X509_STORE_CTX_free(ctx);
++    return r;
++
++}
++
++int CMS_verify(CMS_ContentInfo *cms, STACK_OF(X509) *certs,
++               X509_STORE *store, BIO *dcont, BIO *out, unsigned int flags)
++{
++    CMS_SignerInfo *si;
++    STACK_OF(CMS_SignerInfo) *sinfos;
++    STACK_OF(X509) *cms_certs = NULL;
++    STACK_OF(X509_CRL) *crls = NULL;
++    X509 *signer;
++    int i, scount = 0, ret = 0;
++    BIO *cmsbio = NULL, *tmpin = NULL, *tmpout = NULL;
++
++    if (!dcont && !check_content(cms))
++        return 0;
++    if (dcont && !(flags & CMS_BINARY)) {
++        const ASN1_OBJECT *coid = CMS_get0_eContentType(cms);
++        if (OBJ_obj2nid(coid) == NID_id_ct_asciiTextWithCRLF)
++            flags |= CMS_ASCIICRLF;
++    }
++
++    /* Attempt to find all signer certificates */
++
++    sinfos = CMS_get0_SignerInfos(cms);
++
++    if (sk_CMS_SignerInfo_num(sinfos) <= 0) {
++        CMSerr(CMS_F_CMS_VERIFY, CMS_R_NO_SIGNERS);
++        goto err;
++    }
++
++    for (i = 0; i < sk_CMS_SignerInfo_num(sinfos); i++) {
++        si = sk_CMS_SignerInfo_value(sinfos, i);
++        CMS_SignerInfo_get0_algs(si, NULL, &signer, NULL, NULL);
++        if (signer)
++            scount++;
++    }
++
++    if (scount != sk_CMS_SignerInfo_num(sinfos))
++        scount += CMS_set1_signers_certs(cms, certs, flags);
++
++    if (scount != sk_CMS_SignerInfo_num(sinfos)) {
++        CMSerr(CMS_F_CMS_VERIFY, CMS_R_SIGNER_CERTIFICATE_NOT_FOUND);
++        goto err;
++    }
++
++    /* Attempt to verify all signers certs */
++
++    if (!(flags & CMS_NO_SIGNER_CERT_VERIFY)) {
++        cms_certs = CMS_get1_certs(cms);
++        if (!(flags & CMS_NOCRL))
++            crls = CMS_get1_crls(cms);
++        for (i = 0; i < sk_CMS_SignerInfo_num(sinfos); i++) {
++            si = sk_CMS_SignerInfo_value(sinfos, i);
++            if (!cms_signerinfo_verify_cert(si, store, cms_certs, crls))
++                goto err;
++        }
++    }
++
++    /* Attempt to verify all SignerInfo signed attribute signatures */
++
++    if (!(flags & CMS_NO_ATTR_VERIFY)) {
++        for (i = 0; i < sk_CMS_SignerInfo_num(sinfos); i++) {
++            si = sk_CMS_SignerInfo_value(sinfos, i);
++            if (CMS_signed_get_attr_count(si) < 0)
++                continue;
++            if (CMS_SignerInfo_verify(si) <= 0)
++                goto err;
++        }
++    }
++
++    /*
++     * Performance optimization: if the content is a memory BIO then store
++     * its contents in a temporary read only memory BIO. This avoids
++     * potentially large numbers of slow copies of data which will occur when
++     * reading from a read write memory BIO when signatures are calculated.
++     */
++
++    if (dcont && (BIO_method_type(dcont) == BIO_TYPE_MEM)) {
++        char *ptr;
++        long len;
++        len = BIO_get_mem_data(dcont, &ptr);
++        tmpin = BIO_new_mem_buf(ptr, len);
++        if (tmpin == NULL) {
++            CMSerr(CMS_F_CMS_VERIFY, ERR_R_MALLOC_FAILURE);
++            goto err2;
++        }
++    } else
++        tmpin = dcont;
++    /*
++     * If not binary mode and detached generate digests by *writing* through
++     * the BIO. That makes it possible to canonicalise the input.
++     */
++    if (!(flags & SMIME_BINARY) && dcont) {
++        /*
++         * Create output BIO so we can either handle text or to ensure
++         * included content doesn't override detached content.
++         */
++        tmpout = cms_get_text_bio(out, flags);
++        if (!tmpout) {
++            CMSerr(CMS_F_CMS_VERIFY, ERR_R_MALLOC_FAILURE);
++            goto err;
++        }
++        cmsbio = CMS_dataInit(cms, tmpout);
++        if (!cmsbio)
++            goto err;
++        /*
++         * Don't use SMIME_TEXT for verify: it adds headers and we want to
++         * remove them.
++         */
++        SMIME_crlf_copy(dcont, cmsbio, flags & ~SMIME_TEXT);
++
++        if (flags & CMS_TEXT) {
++            if (!SMIME_text(tmpout, out)) {
++                CMSerr(CMS_F_CMS_VERIFY, CMS_R_SMIME_TEXT_ERROR);
++                goto err;
++            }
++        }
++    } else {
++        cmsbio = CMS_dataInit(cms, tmpin);
++        if (!cmsbio)
++            goto err;
++
++        if (!cms_copy_content(out, cmsbio, flags))
++            goto err;
++
++    }
++    if (!(flags & CMS_NO_CONTENT_VERIFY)) {
++        for (i = 0; i < sk_CMS_SignerInfo_num(sinfos); i++) {
++            si = sk_CMS_SignerInfo_value(sinfos, i);
++            if (CMS_SignerInfo_verify_content(si, cmsbio) <= 0) {
++                CMSerr(CMS_F_CMS_VERIFY, CMS_R_CONTENT_VERIFY_ERROR);
++                goto err;
++            }
++        }
++    }
++
++    ret = 1;
++
++ err:
++    if (!(flags & SMIME_BINARY) && dcont) {
++        do_free_upto(cmsbio, tmpout);
++        if (tmpin != dcont)
++            BIO_free(tmpin);
++    } else {
++        if (dcont && (tmpin == dcont))
++            do_free_upto(cmsbio, dcont);
++        else
++            BIO_free_all(cmsbio);
++    }
++
++    if (out != tmpout)
++        BIO_free_all(tmpout);
++
++ err2:
++    sk_X509_pop_free(cms_certs, X509_free);
++    sk_X509_CRL_pop_free(crls, X509_CRL_free);
++
++    return ret;
++}
++
++int CMS_verify_receipt(CMS_ContentInfo *rcms, CMS_ContentInfo *ocms,
++                       STACK_OF(X509) *certs,
++                       X509_STORE *store, unsigned int flags)
++{
++    int r;
++    flags &= ~(CMS_DETACHED | CMS_TEXT);
++    r = CMS_verify(rcms, certs, store, NULL, NULL, flags);
++    if (r <= 0)
++        return r;
++    return cms_Receipt_verify(rcms, ocms);
++}
++
++CMS_ContentInfo *CMS_sign(X509 *signcert, EVP_PKEY *pkey,
++                          STACK_OF(X509) *certs, BIO *data,
++                          unsigned int flags)
++{
++    CMS_ContentInfo *cms;
++    int i;
++
++    cms = CMS_ContentInfo_new();
++    if (cms == NULL || !CMS_SignedData_init(cms))
++        goto merr;
++    if (flags & CMS_ASCIICRLF
++        && !CMS_set1_eContentType(cms,
++                                  OBJ_nid2obj(NID_id_ct_asciiTextWithCRLF)))
++        goto err;
++
++    if (pkey && !CMS_add1_signer(cms, signcert, pkey, NULL, flags)) {
++        CMSerr(CMS_F_CMS_SIGN, CMS_R_ADD_SIGNER_ERROR);
++        goto err;
++    }
++
++    for (i = 0; i < sk_X509_num(certs); i++) {
++        X509 *x = sk_X509_value(certs, i);
++        if (!CMS_add1_cert(cms, x))
++            goto merr;
++    }
++
++    if (!(flags & CMS_DETACHED))
++        CMS_set_detached(cms, 0);
++
++    if ((flags & (CMS_STREAM | CMS_PARTIAL))
++        || CMS_final(cms, data, NULL, flags))
++        return cms;
++    else
++        goto err;
++
++ merr:
++    CMSerr(CMS_F_CMS_SIGN, ERR_R_MALLOC_FAILURE);
++
++ err:
++    CMS_ContentInfo_free(cms);
++    return NULL;
++}
++
++CMS_ContentInfo *CMS_sign_receipt(CMS_SignerInfo *si,
++                                  X509 *signcert, EVP_PKEY *pkey,
++                                  STACK_OF(X509) *certs, unsigned int flags)
++{
++    CMS_SignerInfo *rct_si;
++    CMS_ContentInfo *cms = NULL;
++    ASN1_OCTET_STRING **pos, *os;
++    BIO *rct_cont = NULL;
++    int r = 0;
++
++    flags &= ~(CMS_STREAM | CMS_TEXT);
++    /* Not really detached but avoids content being allocated */
++    flags |= CMS_PARTIAL | CMS_BINARY | CMS_DETACHED;
++    if (!pkey || !signcert) {
++        CMSerr(CMS_F_CMS_SIGN_RECEIPT, CMS_R_NO_KEY_OR_CERT);
++        return NULL;
++    }
++
++    /* Initialize signed data */
++
++    cms = CMS_sign(NULL, NULL, certs, NULL, flags);
++    if (!cms)
++        goto err;
++
++    /* Set inner content type to signed receipt */
++    if (!CMS_set1_eContentType(cms, OBJ_nid2obj(NID_id_smime_ct_receipt)))
++        goto err;
++
++    rct_si = CMS_add1_signer(cms, signcert, pkey, NULL, flags);
++    if (!rct_si) {
++        CMSerr(CMS_F_CMS_SIGN_RECEIPT, CMS_R_ADD_SIGNER_ERROR);
++        goto err;
++    }
++
++    os = cms_encode_Receipt(si);
++
++    if (!os)
++        goto err;
++
++    /* Set content to digest */
++    rct_cont = BIO_new_mem_buf(os->data, os->length);
++    if (!rct_cont)
++        goto err;
++
++    /* Add msgSigDigest attribute */
++
++    if (!cms_msgSigDigest_add1(rct_si, si))
++        goto err;
++
++    /* Finalize structure */
++    if (!CMS_final(cms, rct_cont, NULL, flags))
++        goto err;
++
++    /* Set embedded content */
++    pos = CMS_get0_content(cms);
++    *pos = os;
++
++    r = 1;
++
++ err:
++    BIO_free(rct_cont);
++    if (r)
++        return cms;
++    CMS_ContentInfo_free(cms);
++    return NULL;
++
++}
++
++CMS_ContentInfo *CMS_encrypt(STACK_OF(X509) *certs, BIO *data,
++                             const EVP_CIPHER *cipher, unsigned int flags)
++{
++    CMS_ContentInfo *cms;
++    int i;
++    X509 *recip;
++    cms = CMS_EnvelopedData_create(cipher);
++    if (!cms)
++        goto merr;
++    for (i = 0; i < sk_X509_num(certs); i++) {
++        recip = sk_X509_value(certs, i);
++        if (!CMS_add1_recipient_cert(cms, recip, flags)) {
++            CMSerr(CMS_F_CMS_ENCRYPT, CMS_R_RECIPIENT_ERROR);
++            goto err;
++        }
++    }
++
++    if (!(flags & CMS_DETACHED))
++        CMS_set_detached(cms, 0);
++
++    if ((flags & (CMS_STREAM | CMS_PARTIAL))
++        || CMS_final(cms, data, NULL, flags))
++        return cms;
++    else
++        goto err;
++
++ merr:
++    CMSerr(CMS_F_CMS_ENCRYPT, ERR_R_MALLOC_FAILURE);
++ err:
++    CMS_ContentInfo_free(cms);
++    return NULL;
++}
++
++static int cms_kari_set1_pkey(CMS_ContentInfo *cms, CMS_RecipientInfo *ri,
++                              EVP_PKEY *pk, X509 *cert)
++{
++    int i;
++    STACK_OF(CMS_RecipientEncryptedKey) *reks;
++    CMS_RecipientEncryptedKey *rek;
++    reks = CMS_RecipientInfo_kari_get0_reks(ri);
++    if (!cert)
++        return 0;
++    for (i = 0; i < sk_CMS_RecipientEncryptedKey_num(reks); i++) {
++        int rv;
++        rek = sk_CMS_RecipientEncryptedKey_value(reks, i);
++        if (CMS_RecipientEncryptedKey_cert_cmp(rek, cert))
++            continue;
++        CMS_RecipientInfo_kari_set0_pkey(ri, pk);
++        rv = CMS_RecipientInfo_kari_decrypt(cms, ri, rek);
++        CMS_RecipientInfo_kari_set0_pkey(ri, NULL);
++        if (rv > 0)
++            return 1;
++        return -1;
++    }
++    return 0;
++}
++
++int CMS_decrypt_set1_pkey(CMS_ContentInfo *cms, EVP_PKEY *pk, X509 *cert)
++{
++    STACK_OF(CMS_RecipientInfo) *ris;
++    CMS_RecipientInfo *ri;
++    int i, r, 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;
++    }
++
++    for (i = 0; i < sk_CMS_RecipientInfo_num(ris); i++) {
++        ri = sk_CMS_RecipientInfo_value(ris, i);
++        if (CMS_RecipientInfo_type(ri) != ri_type)
++            continue;
++        match_ri = 1;
++        if (ri_type == CMS_RECIPINFO_AGREE) {
++            r = cms_kari_set1_pkey(cms, ri, pk, cert);
++            if (r > 0)
++                return 1;
++            if (r < 0)
++                return 0;
++        }
++        /*
++         * If we have a cert try matching RecipientInfo otherwise try them
++         * all.
++         */
++        else if (!cert || !CMS_RecipientInfo_ktri_cert_cmp(ri, cert)) {
++            CMS_RecipientInfo_set0_pkey(ri, pk);
++            r = CMS_RecipientInfo_decrypt(cms, ri);
++            CMS_RecipientInfo_set0_pkey(ri, NULL);
++            if (cert) {
++                /*
++                 * If not debugging clear any error and return success to
++                 * avoid leaking of information useful to MMA
++                 */
++                if (!debug) {
++                    ERR_clear_error();
++                    return 1;
++                }
++                if (r > 0)
++                    return 1;
++                CMSerr(CMS_F_CMS_DECRYPT_SET1_PKEY, CMS_R_DECRYPT_ERROR);
++                return 0;
++            }
++            /*
++             * If no cert and not debugging don't leave loop after first
++             * successful decrypt. Always attempt to decrypt all recipients
++             * to avoid leaking timing of a successful decrypt.
++             */
++            else if (r > 0 && debug)
++                return 1;
++        }
++    }
++    /* If no cert and not debugging always return success */
++    if (match_ri && !cert && !debug) {
++        ERR_clear_error();
++        return 1;
++    }
++
++    CMSerr(CMS_F_CMS_DECRYPT_SET1_PKEY, CMS_R_NO_MATCHING_RECIPIENT);
++    return 0;
++
++}
++
++int CMS_decrypt_set1_key(CMS_ContentInfo *cms,
++                         unsigned char *key, size_t keylen,
++                         const unsigned char *id, size_t idlen)
++{
++    STACK_OF(CMS_RecipientInfo) *ris;
++    CMS_RecipientInfo *ri;
++    int i, r;
++    ris = CMS_get0_RecipientInfos(cms);
++    for (i = 0; i < sk_CMS_RecipientInfo_num(ris); i++) {
++        ri = sk_CMS_RecipientInfo_value(ris, i);
++        if (CMS_RecipientInfo_type(ri) != CMS_RECIPINFO_KEK)
++            continue;
++
++        /*
++         * If we have an id try matching RecipientInfo otherwise try them
++         * all.
++         */
++        if (!id || (CMS_RecipientInfo_kekri_id_cmp(ri, id, idlen) == 0)) {
++            CMS_RecipientInfo_set0_key(ri, key, keylen);
++            r = CMS_RecipientInfo_decrypt(cms, ri);
++            CMS_RecipientInfo_set0_key(ri, NULL, 0);
++            if (r > 0)
++                return 1;
++            if (id) {
++                CMSerr(CMS_F_CMS_DECRYPT_SET1_KEY, CMS_R_DECRYPT_ERROR);
++                return 0;
++            }
++            ERR_clear_error();
++        }
++    }
++
++    CMSerr(CMS_F_CMS_DECRYPT_SET1_KEY, CMS_R_NO_MATCHING_RECIPIENT);
++    return 0;
++
++}
++
++int CMS_decrypt_set1_password(CMS_ContentInfo *cms,
++                              unsigned char *pass, ossl_ssize_t passlen)
++{
++    STACK_OF(CMS_RecipientInfo) *ris;
++    CMS_RecipientInfo *ri;
++    int i, r;
++    ris = CMS_get0_RecipientInfos(cms);
++    for (i = 0; i < sk_CMS_RecipientInfo_num(ris); i++) {
++        ri = sk_CMS_RecipientInfo_value(ris, i);
++        if (CMS_RecipientInfo_type(ri) != CMS_RECIPINFO_PASS)
++            continue;
++        CMS_RecipientInfo_set0_password(ri, pass, passlen);
++        r = CMS_RecipientInfo_decrypt(cms, ri);
++        CMS_RecipientInfo_set0_password(ri, NULL, 0);
++        if (r > 0)
++            return 1;
++    }
++
++    CMSerr(CMS_F_CMS_DECRYPT_SET1_PASSWORD, CMS_R_NO_MATCHING_RECIPIENT);
++    return 0;
++
++}
++
++int CMS_decrypt(CMS_ContentInfo *cms, EVP_PKEY *pk, X509 *cert,
++                BIO *dcont, BIO *out, unsigned int flags)
++{
++    int r;
++    BIO *cont;
++    if (OBJ_obj2nid(CMS_get0_type(cms)) != NID_pkcs7_enveloped) {
++        CMSerr(CMS_F_CMS_DECRYPT, CMS_R_TYPE_NOT_ENVELOPED_DATA);
++        return 0;
++    }
++    if (!dcont && !check_content(cms))
++        return 0;
++    if (flags & CMS_DEBUG_DECRYPT)
++        cms->d.envelopedData->encryptedContentInfo->debug = 1;
++    else
++        cms->d.envelopedData->encryptedContentInfo->debug = 0;
++    if (!pk && !cert && !dcont && !out)
++        return 1;
++    if (pk && !CMS_decrypt_set1_pkey(cms, pk, cert))
++        return 0;
++    cont = CMS_dataInit(cms, dcont);
++    if (!cont)
++        return 0;
++    r = cms_copy_content(out, cont, flags);
++    do_free_upto(cont, dcont);
++    return r;
++}
++
++int CMS_final(CMS_ContentInfo *cms, BIO *data, BIO *dcont, unsigned int flags)
++{
++    BIO *cmsbio;
++    int ret = 0;
++
++    if ((cmsbio = CMS_dataInit(cms, dcont)) == NULL) {
++        CMSerr(CMS_F_CMS_FINAL, CMS_R_CMS_LIB);
++        return 0;
++    }
++
++    SMIME_crlf_copy(data, cmsbio, flags);
++
++    (void)BIO_flush(cmsbio);
++
++    if (!CMS_dataFinal(cms, cmsbio)) {
++        CMSerr(CMS_F_CMS_FINAL, CMS_R_CMS_DATAFINAL_ERROR);
++        goto err;
++    }
++
++    ret = 1;
++
++ err:
++    do_free_upto(cmsbio, dcont);
++
++    return ret;
++
++}
++
++#ifdef ZLIB
++
++int CMS_uncompress(CMS_ContentInfo *cms, BIO *dcont, BIO *out,
++                   unsigned int flags)
++{
++    BIO *cont;
++    int r;
++    if (OBJ_obj2nid(CMS_get0_type(cms)) != NID_id_smime_ct_compressedData) {
++        CMSerr(CMS_F_CMS_UNCOMPRESS, CMS_R_TYPE_NOT_COMPRESSED_DATA);
++        return 0;
++    }
++
++    if (!dcont && !check_content(cms))
++        return 0;
++
++    cont = CMS_dataInit(cms, dcont);
++    if (!cont)
++        return 0;
++    r = cms_copy_content(out, cont, flags);
++    do_free_upto(cont, dcont);
++    return r;
++}
++
++CMS_ContentInfo *CMS_compress(BIO *in, int comp_nid, unsigned int flags)
++{
++    CMS_ContentInfo *cms;
++    if (comp_nid <= 0)
++        comp_nid = NID_zlib_compression;
++    cms = cms_CompressedData_create(comp_nid);
++    if (!cms)
++        return NULL;
++
++    if (!(flags & CMS_DETACHED))
++        CMS_set_detached(cms, 0);
++
++    if ((flags & CMS_STREAM) || CMS_final(cms, in, NULL, flags))
++        return cms;
++
++    CMS_ContentInfo_free(cms);
++    return NULL;
++}
++
++#else
++
++int CMS_uncompress(CMS_ContentInfo *cms, BIO *dcont, BIO *out,
++                   unsigned int flags)
++{
++    CMSerr(CMS_F_CMS_UNCOMPRESS, CMS_R_UNSUPPORTED_COMPRESSION_ALGORITHM);
++    return 0;
++}
++
++CMS_ContentInfo *CMS_compress(BIO *in, int comp_nid, unsigned int flags)
++{
++    CMSerr(CMS_F_CMS_COMPRESS, CMS_R_UNSUPPORTED_COMPRESSION_ALGORITHM);
++    return NULL;
++}
++
++#endif
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/comp/build.info b/CryptoPkg/Library/OpensslLib/openssl/crypto/comp/build.info
+new file mode 100644
+index 0000000..65df46a
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/comp/build.info
+@@ -0,0 +1,4 @@
++LIBS=../../libcrypto
++SOURCE[../../libcrypto]= \
++        comp_lib.c comp_err.c \
++        c_zlib.c
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/comp/c_zlib.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/comp/c_zlib.c
+new file mode 100644
+index 0000000..2f38c2e
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/comp/c_zlib.c
+@@ -0,0 +1,615 @@
++/*
++ * Copyright 1998-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include 
++#include 
++#include 
++#include "internal/comp.h"
++#include 
++#include "internal/cryptlib_int.h"
++#include "internal/bio.h"
++#include "comp_lcl.h"
++
++COMP_METHOD *COMP_zlib(void);
++
++static COMP_METHOD zlib_method_nozlib = {
++    NID_undef,
++    "(undef)",
++    NULL,
++    NULL,
++    NULL,
++    NULL,
++};
++
++#ifndef ZLIB
++# undef ZLIB_SHARED
++#else
++
++# include 
++
++static int zlib_stateful_init(COMP_CTX *ctx);
++static void zlib_stateful_finish(COMP_CTX *ctx);
++static int zlib_stateful_compress_block(COMP_CTX *ctx, unsigned char *out,
++                                        unsigned int olen, unsigned char *in,
++                                        unsigned int ilen);
++static int zlib_stateful_expand_block(COMP_CTX *ctx, unsigned char *out,
++                                      unsigned int olen, unsigned char *in,
++                                      unsigned int ilen);
++
++/* memory allocations functions for zlib initialisation */
++static void *zlib_zalloc(void *opaque, unsigned int no, unsigned int size)
++{
++    void *p;
++
++    p = OPENSSL_zalloc(no * size);
++    return p;
++}
++
++static void zlib_zfree(void *opaque, void *address)
++{
++    OPENSSL_free(address);
++}
++
++
++static COMP_METHOD zlib_stateful_method = {
++    NID_zlib_compression,
++    LN_zlib_compression,
++    zlib_stateful_init,
++    zlib_stateful_finish,
++    zlib_stateful_compress_block,
++    zlib_stateful_expand_block
++};
++
++/*
++ * When OpenSSL is built on Windows, we do not want to require that
++ * the ZLIB.DLL be available in order for the OpenSSL DLLs to
++ * work.  Therefore, all ZLIB routines are loaded at run time
++ * and we do not link to a .LIB file when ZLIB_SHARED is set.
++ */
++# if defined(OPENSSL_SYS_WINDOWS) || defined(OPENSSL_SYS_WIN32)
++#  include 
++# endif                         /* !(OPENSSL_SYS_WINDOWS ||
++                                 * OPENSSL_SYS_WIN32) */
++
++# ifdef ZLIB_SHARED
++#  include "internal/dso.h"
++
++/* Function pointers */
++typedef int (*compress_ft) (Bytef *dest, uLongf * destLen,
++                            const Bytef *source, uLong sourceLen);
++typedef int (*inflateEnd_ft) (z_streamp strm);
++typedef int (*inflate_ft) (z_streamp strm, int flush);
++typedef int (*inflateInit__ft) (z_streamp strm,
++                                const char *version, int stream_size);
++typedef int (*deflateEnd_ft) (z_streamp strm);
++typedef int (*deflate_ft) (z_streamp strm, int flush);
++typedef int (*deflateInit__ft) (z_streamp strm, int level,
++                                const char *version, int stream_size);
++typedef const char *(*zError__ft) (int err);
++static compress_ft p_compress = NULL;
++static inflateEnd_ft p_inflateEnd = NULL;
++static inflate_ft p_inflate = NULL;
++static inflateInit__ft p_inflateInit_ = NULL;
++static deflateEnd_ft p_deflateEnd = NULL;
++static deflate_ft p_deflate = NULL;
++static deflateInit__ft p_deflateInit_ = NULL;
++static zError__ft p_zError = NULL;
++
++static int zlib_loaded = 0;     /* only attempt to init func pts once */
++static DSO *zlib_dso = NULL;
++
++#  define compress                p_compress
++#  define inflateEnd              p_inflateEnd
++#  define inflate                 p_inflate
++#  define inflateInit_            p_inflateInit_
++#  define deflateEnd              p_deflateEnd
++#  define deflate                 p_deflate
++#  define deflateInit_            p_deflateInit_
++#  define zError                  p_zError
++# endif                         /* ZLIB_SHARED */
++
++struct zlib_state {
++    z_stream istream;
++    z_stream ostream;
++};
++
++static int zlib_stateful_init(COMP_CTX *ctx)
++{
++    int err;
++    struct zlib_state *state = OPENSSL_zalloc(sizeof(*state));
++
++    if (state == NULL)
++        goto err;
++
++    state->istream.zalloc = zlib_zalloc;
++    state->istream.zfree = zlib_zfree;
++    state->istream.opaque = Z_NULL;
++    state->istream.next_in = Z_NULL;
++    state->istream.next_out = Z_NULL;
++    err = inflateInit_(&state->istream, ZLIB_VERSION, sizeof(z_stream));
++    if (err != Z_OK)
++        goto err;
++
++    state->ostream.zalloc = zlib_zalloc;
++    state->ostream.zfree = zlib_zfree;
++    state->ostream.opaque = Z_NULL;
++    state->ostream.next_in = Z_NULL;
++    state->ostream.next_out = Z_NULL;
++    err = deflateInit_(&state->ostream, Z_DEFAULT_COMPRESSION,
++                       ZLIB_VERSION, sizeof(z_stream));
++    if (err != Z_OK)
++        goto err;
++
++    ctx->data = state;
++    return 1;
++ err:
++    OPENSSL_free(state);
++    return 0;
++}
++
++static void zlib_stateful_finish(COMP_CTX *ctx)
++{
++    struct zlib_state *state = ctx->data;
++    inflateEnd(&state->istream);
++    deflateEnd(&state->ostream);
++    OPENSSL_free(state);
++}
++
++static int zlib_stateful_compress_block(COMP_CTX *ctx, unsigned char *out,
++                                        unsigned int olen, unsigned char *in,
++                                        unsigned int ilen)
++{
++    int err = Z_OK;
++    struct zlib_state *state = ctx->data;
++
++    if (state == NULL)
++        return -1;
++
++    state->ostream.next_in = in;
++    state->ostream.avail_in = ilen;
++    state->ostream.next_out = out;
++    state->ostream.avail_out = olen;
++    if (ilen > 0)
++        err = deflate(&state->ostream, Z_SYNC_FLUSH);
++    if (err != Z_OK)
++        return -1;
++    return olen - state->ostream.avail_out;
++}
++
++static int zlib_stateful_expand_block(COMP_CTX *ctx, unsigned char *out,
++                                      unsigned int olen, unsigned char *in,
++                                      unsigned int ilen)
++{
++    int err = Z_OK;
++    struct zlib_state *state = ctx->data;
++
++    if (state == NULL)
++        return 0;
++
++    state->istream.next_in = in;
++    state->istream.avail_in = ilen;
++    state->istream.next_out = out;
++    state->istream.avail_out = olen;
++    if (ilen > 0)
++        err = inflate(&state->istream, Z_SYNC_FLUSH);
++    if (err != Z_OK)
++        return -1;
++    return olen - state->istream.avail_out;
++}
++
++#endif
++
++COMP_METHOD *COMP_zlib(void)
++{
++    COMP_METHOD *meth = &zlib_method_nozlib;
++
++#ifdef ZLIB_SHARED
++    /* LIBZ may be externally defined, and we should respect that value */
++# ifndef LIBZ
++#  if defined(OPENSSL_SYS_WINDOWS) || defined(OPENSSL_SYS_WIN32)
++#   define LIBZ "ZLIB1"
++#  elif defined(OPENSSL_SYS_VMS)
++#   define LIBZ "LIBZ"
++#  else
++#   define LIBZ "z"
++#  endif
++# endif
++
++    if (!zlib_loaded) {
++        zlib_dso = DSO_load(NULL, LIBZ, NULL, 0);
++        if (zlib_dso != NULL) {
++            p_compress = (compress_ft) DSO_bind_func(zlib_dso, "compress");
++            p_inflateEnd
++                = (inflateEnd_ft) DSO_bind_func(zlib_dso, "inflateEnd");
++            p_inflate = (inflate_ft) DSO_bind_func(zlib_dso, "inflate");
++            p_inflateInit_
++                = (inflateInit__ft) DSO_bind_func(zlib_dso, "inflateInit_");
++            p_deflateEnd
++                = (deflateEnd_ft) DSO_bind_func(zlib_dso, "deflateEnd");
++            p_deflate = (deflate_ft) DSO_bind_func(zlib_dso, "deflate");
++            p_deflateInit_
++                = (deflateInit__ft) DSO_bind_func(zlib_dso, "deflateInit_");
++            p_zError = (zError__ft) DSO_bind_func(zlib_dso, "zError");
++
++            if (p_compress && p_inflateEnd && p_inflate
++                && p_inflateInit_ && p_deflateEnd
++                && p_deflate && p_deflateInit_ && p_zError)
++                zlib_loaded++;
++
++            if (!OPENSSL_init_crypto(OPENSSL_INIT_ZLIB, NULL)) {
++                comp_zlib_cleanup_int();
++                return meth;
++            }
++            if (zlib_loaded)
++                meth = &zlib_stateful_method;
++        }
++    }
++#endif
++#if defined(ZLIB)
++    meth = &zlib_stateful_method;
++#endif
++
++    return (meth);
++}
++
++void comp_zlib_cleanup_int(void)
++{
++#ifdef ZLIB_SHARED
++    if (zlib_dso != NULL)
++        DSO_free(zlib_dso);
++    zlib_dso = NULL;
++#endif
++}
++
++#ifdef ZLIB
++
++/* Zlib based compression/decompression filter BIO */
++
++typedef struct {
++    unsigned char *ibuf;        /* Input buffer */
++    int ibufsize;               /* Buffer size */
++    z_stream zin;               /* Input decompress context */
++    unsigned char *obuf;        /* Output buffer */
++    int obufsize;               /* Output buffer size */
++    unsigned char *optr;        /* Position in output buffer */
++    int ocount;                 /* Amount of data in output buffer */
++    int odone;                  /* deflate EOF */
++    int comp_level;             /* Compression level to use */
++    z_stream zout;              /* Output compression context */
++} BIO_ZLIB_CTX;
++
++# define ZLIB_DEFAULT_BUFSIZE 1024
++
++static int bio_zlib_new(BIO *bi);
++static int bio_zlib_free(BIO *bi);
++static int bio_zlib_read(BIO *b, char *out, int outl);
++static int bio_zlib_write(BIO *b, const char *in, int inl);
++static long bio_zlib_ctrl(BIO *b, int cmd, long num, void *ptr);
++static long bio_zlib_callback_ctrl(BIO *b, int cmd, bio_info_cb *fp);
++
++static const BIO_METHOD bio_meth_zlib = {
++    BIO_TYPE_COMP,
++    "zlib",
++    bio_zlib_write,
++    bio_zlib_read,
++    NULL,
++    NULL,
++    bio_zlib_ctrl,
++    bio_zlib_new,
++    bio_zlib_free,
++    bio_zlib_callback_ctrl
++};
++
++const BIO_METHOD *BIO_f_zlib(void)
++{
++    return &bio_meth_zlib;
++}
++
++static int bio_zlib_new(BIO *bi)
++{
++    BIO_ZLIB_CTX *ctx;
++# ifdef ZLIB_SHARED
++    (void)COMP_zlib();
++    if (!zlib_loaded) {
++        COMPerr(COMP_F_BIO_ZLIB_NEW, COMP_R_ZLIB_NOT_SUPPORTED);
++        return 0;
++    }
++# endif
++    ctx = OPENSSL_zalloc(sizeof(*ctx));
++    if (ctx == NULL) {
++        COMPerr(COMP_F_BIO_ZLIB_NEW, ERR_R_MALLOC_FAILURE);
++        return 0;
++    }
++    ctx->ibufsize = ZLIB_DEFAULT_BUFSIZE;
++    ctx->obufsize = ZLIB_DEFAULT_BUFSIZE;
++    ctx->zin.zalloc = Z_NULL;
++    ctx->zin.zfree = Z_NULL;
++    ctx->zout.zalloc = Z_NULL;
++    ctx->zout.zfree = Z_NULL;
++    ctx->comp_level = Z_DEFAULT_COMPRESSION;
++    BIO_set_init(bi, 1);
++    BIO_set_data(bi, ctx);
++
++    return 1;
++}
++
++static int bio_zlib_free(BIO *bi)
++{
++    BIO_ZLIB_CTX *ctx;
++    if (!bi)
++        return 0;
++    ctx = BIO_get_data(bi);
++    if (ctx->ibuf) {
++        /* Destroy decompress context */
++        inflateEnd(&ctx->zin);
++        OPENSSL_free(ctx->ibuf);
++    }
++    if (ctx->obuf) {
++        /* Destroy compress context */
++        deflateEnd(&ctx->zout);
++        OPENSSL_free(ctx->obuf);
++    }
++    OPENSSL_free(ctx);
++    BIO_set_data(bi, NULL);
++    BIO_set_init(bi, 0);
++
++    return 1;
++}
++
++static int bio_zlib_read(BIO *b, char *out, int outl)
++{
++    BIO_ZLIB_CTX *ctx;
++    int ret;
++    z_stream *zin;
++    BIO *next = BIO_next(b);
++
++    if (!out || !outl)
++        return 0;
++    ctx = BIO_get_data(b);
++    zin = &ctx->zin;
++    BIO_clear_retry_flags(b);
++    if (!ctx->ibuf) {
++        ctx->ibuf = OPENSSL_malloc(ctx->ibufsize);
++        if (ctx->ibuf == NULL) {
++            COMPerr(COMP_F_BIO_ZLIB_READ, ERR_R_MALLOC_FAILURE);
++            return 0;
++        }
++        inflateInit(zin);
++        zin->next_in = ctx->ibuf;
++        zin->avail_in = 0;
++    }
++
++    /* Copy output data directly to supplied buffer */
++    zin->next_out = (unsigned char *)out;
++    zin->avail_out = (unsigned int)outl;
++    for (;;) {
++        /* Decompress while data available */
++        while (zin->avail_in) {
++            ret = inflate(zin, 0);
++            if ((ret != Z_OK) && (ret != Z_STREAM_END)) {
++                COMPerr(COMP_F_BIO_ZLIB_READ, COMP_R_ZLIB_INFLATE_ERROR);
++                ERR_add_error_data(2, "zlib error:", zError(ret));
++                return 0;
++            }
++            /* If EOF or we've read everything then return */
++            if ((ret == Z_STREAM_END) || !zin->avail_out)
++                return outl - zin->avail_out;
++        }
++
++        /*
++         * No data in input buffer try to read some in, if an error then
++         * return the total data read.
++         */
++        ret = BIO_read(next, ctx->ibuf, ctx->ibufsize);
++        if (ret <= 0) {
++            /* Total data read */
++            int tot = outl - zin->avail_out;
++            BIO_copy_next_retry(b);
++            if (ret < 0)
++                return (tot > 0) ? tot : ret;
++            return tot;
++        }
++        zin->avail_in = ret;
++        zin->next_in = ctx->ibuf;
++    }
++}
++
++static int bio_zlib_write(BIO *b, const char *in, int inl)
++{
++    BIO_ZLIB_CTX *ctx;
++    int ret;
++    z_stream *zout;
++    BIO *next = BIO_next(b);
++
++    if (!in || !inl)
++        return 0;
++    ctx = BIO_get_data(b);
++    if (ctx->odone)
++        return 0;
++    zout = &ctx->zout;
++    BIO_clear_retry_flags(b);
++    if (!ctx->obuf) {
++        ctx->obuf = OPENSSL_malloc(ctx->obufsize);
++        /* Need error here */
++        if (ctx->obuf == NULL) {
++            COMPerr(COMP_F_BIO_ZLIB_WRITE, ERR_R_MALLOC_FAILURE);
++            return 0;
++        }
++        ctx->optr = ctx->obuf;
++        ctx->ocount = 0;
++        deflateInit(zout, ctx->comp_level);
++        zout->next_out = ctx->obuf;
++        zout->avail_out = ctx->obufsize;
++    }
++    /* Obtain input data directly from supplied buffer */
++    zout->next_in = (void *)in;
++    zout->avail_in = inl;
++    for (;;) {
++        /* If data in output buffer write it first */
++        while (ctx->ocount) {
++            ret = BIO_write(next, ctx->optr, ctx->ocount);
++            if (ret <= 0) {
++                /* Total data written */
++                int tot = inl - zout->avail_in;
++                BIO_copy_next_retry(b);
++                if (ret < 0)
++                    return (tot > 0) ? tot : ret;
++                return tot;
++            }
++            ctx->optr += ret;
++            ctx->ocount -= ret;
++        }
++
++        /* Have we consumed all supplied data? */
++        if (!zout->avail_in)
++            return inl;
++
++        /* Compress some more */
++
++        /* Reset buffer */
++        ctx->optr = ctx->obuf;
++        zout->next_out = ctx->obuf;
++        zout->avail_out = ctx->obufsize;
++        /* Compress some more */
++        ret = deflate(zout, 0);
++        if (ret != Z_OK) {
++            COMPerr(COMP_F_BIO_ZLIB_WRITE, COMP_R_ZLIB_DEFLATE_ERROR);
++            ERR_add_error_data(2, "zlib error:", zError(ret));
++            return 0;
++        }
++        ctx->ocount = ctx->obufsize - zout->avail_out;
++    }
++}
++
++static int bio_zlib_flush(BIO *b)
++{
++    BIO_ZLIB_CTX *ctx;
++    int ret;
++    z_stream *zout;
++    BIO *next = BIO_next(b);
++
++    ctx = BIO_get_data(b);
++    /* If no data written or already flush show success */
++    if (!ctx->obuf || (ctx->odone && !ctx->ocount))
++        return 1;
++    zout = &ctx->zout;
++    BIO_clear_retry_flags(b);
++    /* No more input data */
++    zout->next_in = NULL;
++    zout->avail_in = 0;
++    for (;;) {
++        /* If data in output buffer write it first */
++        while (ctx->ocount) {
++            ret = BIO_write(next, ctx->optr, ctx->ocount);
++            if (ret <= 0) {
++                BIO_copy_next_retry(b);
++                return ret;
++            }
++            ctx->optr += ret;
++            ctx->ocount -= ret;
++        }
++        if (ctx->odone)
++            return 1;
++
++        /* Compress some more */
++
++        /* Reset buffer */
++        ctx->optr = ctx->obuf;
++        zout->next_out = ctx->obuf;
++        zout->avail_out = ctx->obufsize;
++        /* Compress some more */
++        ret = deflate(zout, Z_FINISH);
++        if (ret == Z_STREAM_END)
++            ctx->odone = 1;
++        else if (ret != Z_OK) {
++            COMPerr(COMP_F_BIO_ZLIB_FLUSH, COMP_R_ZLIB_DEFLATE_ERROR);
++            ERR_add_error_data(2, "zlib error:", zError(ret));
++            return 0;
++        }
++        ctx->ocount = ctx->obufsize - zout->avail_out;
++    }
++}
++
++static long bio_zlib_ctrl(BIO *b, int cmd, long num, void *ptr)
++{
++    BIO_ZLIB_CTX *ctx;
++    int ret, *ip;
++    int ibs, obs;
++    BIO *next = BIO_next(b);
++
++    if (next == NULL)
++        return 0;
++    ctx = BIO_get_data(b);
++    switch (cmd) {
++
++    case BIO_CTRL_RESET:
++        ctx->ocount = 0;
++        ctx->odone = 0;
++        ret = 1;
++        break;
++
++    case BIO_CTRL_FLUSH:
++        ret = bio_zlib_flush(b);
++        if (ret > 0)
++            ret = BIO_flush(next);
++        break;
++
++    case BIO_C_SET_BUFF_SIZE:
++        ibs = -1;
++        obs = -1;
++        if (ptr != NULL) {
++            ip = ptr;
++            if (*ip == 0)
++                ibs = (int)num;
++            else
++                obs = (int)num;
++        } else {
++            ibs = (int)num;
++            obs = ibs;
++        }
++
++        if (ibs != -1) {
++            OPENSSL_free(ctx->ibuf);
++            ctx->ibuf = NULL;
++            ctx->ibufsize = ibs;
++        }
++
++        if (obs != -1) {
++            OPENSSL_free(ctx->obuf);
++            ctx->obuf = NULL;
++            ctx->obufsize = obs;
++        }
++        ret = 1;
++        break;
++
++    case BIO_C_DO_STATE_MACHINE:
++        BIO_clear_retry_flags(b);
++        ret = BIO_ctrl(next, cmd, num, ptr);
++        BIO_copy_next_retry(b);
++        break;
++
++    default:
++        ret = BIO_ctrl(next, cmd, num, ptr);
++        break;
++
++    }
++
++    return ret;
++}
++
++static long bio_zlib_callback_ctrl(BIO *b, int cmd, bio_info_cb *fp)
++{
++    BIO *next = BIO_next(b);
++    if (next == NULL)
++        return 0;
++    return BIO_callback_ctrl(next, cmd, fp);
++}
++
++#endif
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/comp/comp_err.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/comp/comp_err.c
+new file mode 100644
+index 0000000..8e2e695
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/comp/comp_err.c
+@@ -0,0 +1,48 @@
++/*
++ * Generated by util/mkerr.pl DO NOT EDIT
++ * Copyright 1995-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include 
++#include 
++
++/* BEGIN ERROR CODES */
++#ifndef OPENSSL_NO_ERR
++
++# define ERR_FUNC(func) ERR_PACK(ERR_LIB_COMP,func,0)
++# define ERR_REASON(reason) ERR_PACK(ERR_LIB_COMP,0,reason)
++
++static ERR_STRING_DATA COMP_str_functs[] = {
++    {ERR_FUNC(COMP_F_BIO_ZLIB_FLUSH), "bio_zlib_flush"},
++    {ERR_FUNC(COMP_F_BIO_ZLIB_NEW), "bio_zlib_new"},
++    {ERR_FUNC(COMP_F_BIO_ZLIB_READ), "bio_zlib_read"},
++    {ERR_FUNC(COMP_F_BIO_ZLIB_WRITE), "bio_zlib_write"},
++    {0, NULL}
++};
++
++static ERR_STRING_DATA COMP_str_reasons[] = {
++    {ERR_REASON(COMP_R_ZLIB_DEFLATE_ERROR), "zlib deflate error"},
++    {ERR_REASON(COMP_R_ZLIB_INFLATE_ERROR), "zlib inflate error"},
++    {ERR_REASON(COMP_R_ZLIB_NOT_SUPPORTED), "zlib not supported"},
++    {0, NULL}
++};
++
++#endif
++
++int ERR_load_COMP_strings(void)
++{
++#ifndef OPENSSL_NO_ERR
++
++    if (ERR_func_error_string(COMP_str_functs[0].error) == NULL) {
++        ERR_load_strings(0, COMP_str_functs);
++        ERR_load_strings(0, COMP_str_reasons);
++    }
++#endif
++    return 1;
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/comp/comp_lcl.h b/CryptoPkg/Library/OpensslLib/openssl/crypto/comp/comp_lcl.h
+new file mode 100644
+index 0000000..aa45fca
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/comp/comp_lcl.h
+@@ -0,0 +1,30 @@
++/*
++ * Copyright 2015-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++struct comp_method_st {
++    int type;                   /* NID for compression library */
++    const char *name;           /* A text string to identify the library */
++    int (*init) (COMP_CTX *ctx);
++    void (*finish) (COMP_CTX *ctx);
++    int (*compress) (COMP_CTX *ctx,
++                     unsigned char *out, unsigned int olen,
++                     unsigned char *in, unsigned int ilen);
++    int (*expand) (COMP_CTX *ctx,
++                   unsigned char *out, unsigned int olen,
++                   unsigned char *in, unsigned int ilen);
++};
++
++struct comp_ctx_st {
++    struct comp_method_st *meth;
++    unsigned long compress_in;
++    unsigned long compress_out;
++    unsigned long expand_in;
++    unsigned long expand_out;
++    void* data;
++};
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/comp/comp_lib.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/comp/comp_lib.c
+new file mode 100644
+index 0000000..32afd0d
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/comp/comp_lib.c
+@@ -0,0 +1,91 @@
++/*
++ * Copyright 1998-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include 
++#include 
++#include 
++#include 
++#include "comp_lcl.h"
++
++COMP_CTX *COMP_CTX_new(COMP_METHOD *meth)
++{
++    COMP_CTX *ret;
++
++    if ((ret = OPENSSL_zalloc(sizeof(*ret))) == NULL)
++        return (NULL);
++    ret->meth = meth;
++    if ((ret->meth->init != NULL) && !ret->meth->init(ret)) {
++        OPENSSL_free(ret);
++        ret = NULL;
++    }
++    return (ret);
++}
++
++const COMP_METHOD *COMP_CTX_get_method(const COMP_CTX *ctx)
++{
++    return ctx->meth;
++}
++
++int COMP_get_type(const COMP_METHOD *meth)
++{
++    return meth->type;
++}
++
++const char *COMP_get_name(const COMP_METHOD *meth)
++{
++    return meth->name;
++}
++
++void COMP_CTX_free(COMP_CTX *ctx)
++{
++    if (ctx == NULL)
++        return;
++
++    if (ctx->meth->finish != NULL)
++        ctx->meth->finish(ctx);
++
++    OPENSSL_free(ctx);
++}
++
++int COMP_compress_block(COMP_CTX *ctx, unsigned char *out, int olen,
++                        unsigned char *in, int ilen)
++{
++    int ret;
++    if (ctx->meth->compress == NULL) {
++        return (-1);
++    }
++    ret = ctx->meth->compress(ctx, out, olen, in, ilen);
++    if (ret > 0) {
++        ctx->compress_in += ilen;
++        ctx->compress_out += ret;
++    }
++    return (ret);
++}
++
++int COMP_expand_block(COMP_CTX *ctx, unsigned char *out, int olen,
++                      unsigned char *in, int ilen)
++{
++    int ret;
++
++    if (ctx->meth->expand == NULL) {
++        return (-1);
++    }
++    ret = ctx->meth->expand(ctx, out, olen, in, ilen);
++    if (ret > 0) {
++        ctx->expand_in += ilen;
++        ctx->expand_out += ret;
++    }
++    return (ret);
++}
++
++int COMP_CTX_get_type(const COMP_CTX* comp)
++{
++    return comp->meth ? comp->meth->type : NID_undef;
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/conf/build.info b/CryptoPkg/Library/OpensslLib/openssl/crypto/conf/build.info
+new file mode 100644
+index 0000000..4438eb4
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/conf/build.info
+@@ -0,0 +1,4 @@
++LIBS=../../libcrypto
++SOURCE[../../libcrypto]= \
++        conf_err.c conf_lib.c conf_api.c conf_def.c conf_mod.c \
++        conf_mall.c conf_sap.c
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/conf/conf_api.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/conf/conf_api.c
+new file mode 100644
+index 0000000..5535416
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/conf/conf_api.c
+@@ -0,0 +1,214 @@
++/*
++ * Copyright 1995-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++/* Part of the code in here was originally in conf.c, which is now removed */
++
++#include 
++#include 
++#include 
++#include 
++#include "e_os.h"
++
++static void value_free_hash(const CONF_VALUE *a, LHASH_OF(CONF_VALUE) *conf);
++static void value_free_stack_doall(CONF_VALUE *a);
++
++/* Up until OpenSSL 0.9.5a, this was get_section */
++CONF_VALUE *_CONF_get_section(const CONF *conf, const char *section)
++{
++    CONF_VALUE *v, vv;
++
++    if ((conf == NULL) || (section == NULL))
++        return (NULL);
++    vv.name = NULL;
++    vv.section = (char *)section;
++    v = lh_CONF_VALUE_retrieve(conf->data, &vv);
++    return (v);
++}
++
++/* Up until OpenSSL 0.9.5a, this was CONF_get_section */
++STACK_OF(CONF_VALUE) *_CONF_get_section_values(const CONF *conf,
++                                               const char *section)
++{
++    CONF_VALUE *v;
++
++    v = _CONF_get_section(conf, section);
++    if (v != NULL)
++        return ((STACK_OF(CONF_VALUE) *)v->value);
++    else
++        return (NULL);
++}
++
++int _CONF_add_string(CONF *conf, CONF_VALUE *section, CONF_VALUE *value)
++{
++    CONF_VALUE *v = NULL;
++    STACK_OF(CONF_VALUE) *ts;
++
++    ts = (STACK_OF(CONF_VALUE) *)section->value;
++
++    value->section = section->section;
++    if (!sk_CONF_VALUE_push(ts, value)) {
++        return 0;
++    }
++
++    v = lh_CONF_VALUE_insert(conf->data, value);
++    if (v != NULL) {
++        (void)sk_CONF_VALUE_delete_ptr(ts, v);
++        OPENSSL_free(v->name);
++        OPENSSL_free(v->value);
++        OPENSSL_free(v);
++    }
++    return 1;
++}
++
++char *_CONF_get_string(const CONF *conf, const char *section,
++                       const char *name)
++{
++    CONF_VALUE *v, vv;
++    char *p;
++
++    if (name == NULL)
++        return (NULL);
++    if (conf != NULL) {
++        if (section != NULL) {
++            vv.name = (char *)name;
++            vv.section = (char *)section;
++            v = lh_CONF_VALUE_retrieve(conf->data, &vv);
++            if (v != NULL)
++                return (v->value);
++            if (strcmp(section, "ENV") == 0) {
++                p = getenv(name);
++                if (p != NULL)
++                    return (p);
++            }
++        }
++        vv.section = "default";
++        vv.name = (char *)name;
++        v = lh_CONF_VALUE_retrieve(conf->data, &vv);
++        if (v != NULL)
++            return (v->value);
++        else
++            return (NULL);
++    } else
++        return (getenv(name));
++}
++
++static unsigned long conf_value_hash(const CONF_VALUE *v)
++{
++    return (OPENSSL_LH_strhash(v->section) << 2) ^ OPENSSL_LH_strhash(v->name);
++}
++
++static int conf_value_cmp(const CONF_VALUE *a, const CONF_VALUE *b)
++{
++    int i;
++
++    if (a->section != b->section) {
++        i = strcmp(a->section, b->section);
++        if (i)
++            return (i);
++    }
++
++    if ((a->name != NULL) && (b->name != NULL)) {
++        i = strcmp(a->name, b->name);
++        return (i);
++    } else if (a->name == b->name)
++        return (0);
++    else
++        return ((a->name == NULL) ? -1 : 1);
++}
++
++int _CONF_new_data(CONF *conf)
++{
++    if (conf == NULL) {
++        return 0;
++    }
++    if (conf->data == NULL) {
++        conf->data = lh_CONF_VALUE_new(conf_value_hash, conf_value_cmp);
++        if (conf->data == NULL)
++            return 0;
++    }
++    return 1;
++}
++
++typedef LHASH_OF(CONF_VALUE) LH_CONF_VALUE;
++
++IMPLEMENT_LHASH_DOALL_ARG_CONST(CONF_VALUE, LH_CONF_VALUE);
++
++void _CONF_free_data(CONF *conf)
++{
++    if (conf == NULL || conf->data == NULL)
++        return;
++
++    /* evil thing to make sure the 'OPENSSL_free()' works as expected */
++    lh_CONF_VALUE_set_down_load(conf->data, 0);
++    lh_CONF_VALUE_doall_LH_CONF_VALUE(conf->data, value_free_hash, conf->data);
++
++    /*
++     * We now have only 'section' entries in the hash table. Due to problems
++     * with
++     */
++
++    lh_CONF_VALUE_doall(conf->data, value_free_stack_doall);
++    lh_CONF_VALUE_free(conf->data);
++}
++
++static void value_free_hash(const CONF_VALUE *a, LHASH_OF(CONF_VALUE) *conf)
++{
++    if (a->name != NULL)
++        (void)lh_CONF_VALUE_delete(conf, a);
++}
++
++static void value_free_stack_doall(CONF_VALUE *a)
++{
++    CONF_VALUE *vv;
++    STACK_OF(CONF_VALUE) *sk;
++    int i;
++
++    if (a->name != NULL)
++        return;
++
++    sk = (STACK_OF(CONF_VALUE) *)a->value;
++    for (i = sk_CONF_VALUE_num(sk) - 1; i >= 0; i--) {
++        vv = sk_CONF_VALUE_value(sk, i);
++        OPENSSL_free(vv->value);
++        OPENSSL_free(vv->name);
++        OPENSSL_free(vv);
++    }
++    sk_CONF_VALUE_free(sk);
++    OPENSSL_free(a->section);
++    OPENSSL_free(a);
++}
++
++/* Up until OpenSSL 0.9.5a, this was new_section */
++CONF_VALUE *_CONF_new_section(CONF *conf, const char *section)
++{
++    STACK_OF(CONF_VALUE) *sk = NULL;
++    int i;
++    CONF_VALUE *v = NULL, *vv;
++
++    if ((sk = sk_CONF_VALUE_new_null()) == NULL)
++        goto err;
++    if ((v = OPENSSL_malloc(sizeof(*v))) == NULL)
++        goto err;
++    i = strlen(section) + 1;
++    if ((v->section = OPENSSL_malloc(i)) == NULL)
++        goto err;
++
++    memcpy(v->section, section, i);
++    v->name = NULL;
++    v->value = (char *)sk;
++
++    vv = lh_CONF_VALUE_insert(conf->data, v);
++    OPENSSL_assert(vv == NULL);
++    return v;
++
++ err:
++    sk_CONF_VALUE_free(sk);
++    OPENSSL_free(v);
++    return NULL;
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/conf/conf_def.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/conf/conf_def.c
+new file mode 100644
+index 0000000..8861b3a
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/conf/conf_def.c
+@@ -0,0 +1,630 @@
++/*
++ * Copyright 1995-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++/* Part of the code in here was originally in conf.c, which is now removed */
++
++#include 
++#include 
++#include "internal/cryptlib.h"
++#include 
++#include 
++#include 
++#include 
++#include "conf_def.h"
++#include 
++#include 
++
++static char *eat_ws(CONF *conf, char *p);
++static char *eat_alpha_numeric(CONF *conf, char *p);
++static void clear_comments(CONF *conf, char *p);
++static int str_copy(CONF *conf, char *section, char **to, char *from);
++static char *scan_quote(CONF *conf, char *p);
++static char *scan_dquote(CONF *conf, char *p);
++#define scan_esc(conf,p)        (((IS_EOF((conf),(p)[1]))?((p)+1):((p)+2)))
++
++static CONF *def_create(CONF_METHOD *meth);
++static int def_init_default(CONF *conf);
++static int def_init_WIN32(CONF *conf);
++static int def_destroy(CONF *conf);
++static int def_destroy_data(CONF *conf);
++static int def_load(CONF *conf, const char *name, long *eline);
++static int def_load_bio(CONF *conf, BIO *bp, long *eline);
++static int def_dump(const CONF *conf, BIO *bp);
++static int def_is_number(const CONF *conf, char c);
++static int def_to_int(const CONF *conf, char c);
++
++static CONF_METHOD default_method = {
++    "OpenSSL default",
++    def_create,
++    def_init_default,
++    def_destroy,
++    def_destroy_data,
++    def_load_bio,
++    def_dump,
++    def_is_number,
++    def_to_int,
++    def_load
++};
++
++static CONF_METHOD WIN32_method = {
++    "WIN32",
++    def_create,
++    def_init_WIN32,
++    def_destroy,
++    def_destroy_data,
++    def_load_bio,
++    def_dump,
++    def_is_number,
++    def_to_int,
++    def_load
++};
++
++CONF_METHOD *NCONF_default()
++{
++    return &default_method;
++}
++
++CONF_METHOD *NCONF_WIN32()
++{
++    return &WIN32_method;
++}
++
++static CONF *def_create(CONF_METHOD *meth)
++{
++    CONF *ret;
++
++    ret = OPENSSL_malloc(sizeof(*ret));
++    if (ret != NULL)
++        if (meth->init(ret) == 0) {
++            OPENSSL_free(ret);
++            ret = NULL;
++        }
++    return ret;
++}
++
++static int def_init_default(CONF *conf)
++{
++    if (conf == NULL)
++        return 0;
++
++    conf->meth = &default_method;
++    conf->meth_data = (void *)CONF_type_default;
++    conf->data = NULL;
++
++    return 1;
++}
++
++static int def_init_WIN32(CONF *conf)
++{
++    if (conf == NULL)
++        return 0;
++
++    conf->meth = &WIN32_method;
++    conf->meth_data = (void *)CONF_type_win32;
++    conf->data = NULL;
++
++    return 1;
++}
++
++static int def_destroy(CONF *conf)
++{
++    if (def_destroy_data(conf)) {
++        OPENSSL_free(conf);
++        return 1;
++    }
++    return 0;
++}
++
++static int def_destroy_data(CONF *conf)
++{
++    if (conf == NULL)
++        return 0;
++    _CONF_free_data(conf);
++    return 1;
++}
++
++static int def_load(CONF *conf, const char *name, long *line)
++{
++    int ret;
++    BIO *in = NULL;
++
++#ifdef OPENSSL_SYS_VMS
++    in = BIO_new_file(name, "r");
++#else
++    in = BIO_new_file(name, "rb");
++#endif
++    if (in == NULL) {
++        if (ERR_GET_REASON(ERR_peek_last_error()) == BIO_R_NO_SUCH_FILE)
++            CONFerr(CONF_F_DEF_LOAD, CONF_R_NO_SUCH_FILE);
++        else
++            CONFerr(CONF_F_DEF_LOAD, ERR_R_SYS_LIB);
++        return 0;
++    }
++
++    ret = def_load_bio(conf, in, line);
++    BIO_free(in);
++
++    return ret;
++}
++
++static int def_load_bio(CONF *conf, BIO *in, long *line)
++{
++/* The macro BUFSIZE conflicts with a system macro in VxWorks */
++#define CONFBUFSIZE     512
++    int bufnum = 0, i, ii;
++    BUF_MEM *buff = NULL;
++    char *s, *p, *end;
++    int again;
++    long eline = 0;
++    char btmp[DECIMAL_SIZE(eline) + 1];
++    CONF_VALUE *v = NULL, *tv;
++    CONF_VALUE *sv = NULL;
++    char *section = NULL, *buf;
++    char *start, *psection, *pname;
++    void *h = (void *)(conf->data);
++
++    if ((buff = BUF_MEM_new()) == NULL) {
++        CONFerr(CONF_F_DEF_LOAD_BIO, ERR_R_BUF_LIB);
++        goto err;
++    }
++
++    section = OPENSSL_strdup("default");
++    if (section == NULL) {
++        CONFerr(CONF_F_DEF_LOAD_BIO, ERR_R_MALLOC_FAILURE);
++        goto err;
++    }
++
++    if (_CONF_new_data(conf) == 0) {
++        CONFerr(CONF_F_DEF_LOAD_BIO, ERR_R_MALLOC_FAILURE);
++        goto err;
++    }
++
++    sv = _CONF_new_section(conf, section);
++    if (sv == NULL) {
++        CONFerr(CONF_F_DEF_LOAD_BIO, CONF_R_UNABLE_TO_CREATE_NEW_SECTION);
++        goto err;
++    }
++
++    bufnum = 0;
++    again = 0;
++    for (;;) {
++        if (!BUF_MEM_grow(buff, bufnum + CONFBUFSIZE)) {
++            CONFerr(CONF_F_DEF_LOAD_BIO, ERR_R_BUF_LIB);
++            goto err;
++        }
++        p = &(buff->data[bufnum]);
++        *p = '\0';
++        BIO_gets(in, p, CONFBUFSIZE - 1);
++        p[CONFBUFSIZE - 1] = '\0';
++        ii = i = strlen(p);
++        if (i == 0 && !again)
++            break;
++        again = 0;
++        while (i > 0) {
++            if ((p[i - 1] != '\r') && (p[i - 1] != '\n'))
++                break;
++            else
++                i--;
++        }
++        /*
++         * we removed some trailing stuff so there is a new line on the end.
++         */
++        if (ii && i == ii)
++            again = 1;          /* long line */
++        else {
++            p[i] = '\0';
++            eline++;            /* another input line */
++        }
++
++        /* we now have a line with trailing \r\n removed */
++
++        /* i is the number of bytes */
++        bufnum += i;
++
++        v = NULL;
++        /* check for line continuation */
++        if (bufnum >= 1) {
++            /*
++             * If we have bytes and the last char '\\' and second last char
++             * is not '\\'
++             */
++            p = &(buff->data[bufnum - 1]);
++            if (IS_ESC(conf, p[0]) && ((bufnum <= 1) || !IS_ESC(conf, p[-1]))) {
++                bufnum--;
++                again = 1;
++            }
++        }
++        if (again)
++            continue;
++        bufnum = 0;
++        buf = buff->data;
++
++        clear_comments(conf, buf);
++        s = eat_ws(conf, buf);
++        if (IS_EOF(conf, *s))
++            continue;           /* blank line */
++        if (*s == '[') {
++            char *ss;
++
++            s++;
++            start = eat_ws(conf, s);
++            ss = start;
++ again:
++            end = eat_alpha_numeric(conf, ss);
++            p = eat_ws(conf, end);
++            if (*p != ']') {
++                if (*p != '\0' && ss != p) {
++                    ss = p;
++                    goto again;
++                }
++                CONFerr(CONF_F_DEF_LOAD_BIO,
++                        CONF_R_MISSING_CLOSE_SQUARE_BRACKET);
++                goto err;
++            }
++            *end = '\0';
++            if (!str_copy(conf, NULL, §ion, start))
++                goto err;
++            if ((sv = _CONF_get_section(conf, section)) == NULL)
++                sv = _CONF_new_section(conf, section);
++            if (sv == NULL) {
++                CONFerr(CONF_F_DEF_LOAD_BIO,
++                        CONF_R_UNABLE_TO_CREATE_NEW_SECTION);
++                goto err;
++            }
++            continue;
++        } else {
++            pname = s;
++            psection = NULL;
++            end = eat_alpha_numeric(conf, s);
++            if ((end[0] == ':') && (end[1] == ':')) {
++                *end = '\0';
++                end += 2;
++                psection = pname;
++                pname = end;
++                end = eat_alpha_numeric(conf, end);
++            }
++            p = eat_ws(conf, end);
++            if (*p != '=') {
++                CONFerr(CONF_F_DEF_LOAD_BIO, CONF_R_MISSING_EQUAL_SIGN);
++                goto err;
++            }
++            *end = '\0';
++            p++;
++            start = eat_ws(conf, p);
++            while (!IS_EOF(conf, *p))
++                p++;
++            p--;
++            while ((p != start) && (IS_WS(conf, *p)))
++                p--;
++            p++;
++            *p = '\0';
++
++            if ((v = OPENSSL_malloc(sizeof(*v))) == NULL) {
++                CONFerr(CONF_F_DEF_LOAD_BIO, ERR_R_MALLOC_FAILURE);
++                goto err;
++            }
++            if (psection == NULL)
++                psection = section;
++            v->name = OPENSSL_malloc(strlen(pname) + 1);
++            v->value = NULL;
++            if (v->name == NULL) {
++                CONFerr(CONF_F_DEF_LOAD_BIO, ERR_R_MALLOC_FAILURE);
++                goto err;
++            }
++            OPENSSL_strlcpy(v->name, pname, strlen(pname) + 1);
++            if (!str_copy(conf, psection, &(v->value), start))
++                goto err;
++
++            if (strcmp(psection, section) != 0) {
++                if ((tv = _CONF_get_section(conf, psection))
++                    == NULL)
++                    tv = _CONF_new_section(conf, psection);
++                if (tv == NULL) {
++                    CONFerr(CONF_F_DEF_LOAD_BIO,
++                            CONF_R_UNABLE_TO_CREATE_NEW_SECTION);
++                    goto err;
++                }
++            } else
++                tv = sv;
++            if (_CONF_add_string(conf, tv, v) == 0) {
++                CONFerr(CONF_F_DEF_LOAD_BIO, ERR_R_MALLOC_FAILURE);
++                goto err;
++            }
++            v = NULL;
++        }
++    }
++    BUF_MEM_free(buff);
++    OPENSSL_free(section);
++    return (1);
++ err:
++    BUF_MEM_free(buff);
++    OPENSSL_free(section);
++    if (line != NULL)
++        *line = eline;
++    BIO_snprintf(btmp, sizeof btmp, "%ld", eline);
++    ERR_add_error_data(2, "line ", btmp);
++    if (h != conf->data) {
++        CONF_free(conf->data);
++        conf->data = NULL;
++    }
++    if (v != NULL) {
++        OPENSSL_free(v->name);
++        OPENSSL_free(v->value);
++        OPENSSL_free(v);
++    }
++    return (0);
++}
++
++static void clear_comments(CONF *conf, char *p)
++{
++    for (;;) {
++        if (IS_FCOMMENT(conf, *p)) {
++            *p = '\0';
++            return;
++        }
++        if (!IS_WS(conf, *p)) {
++            break;
++        }
++        p++;
++    }
++
++    for (;;) {
++        if (IS_COMMENT(conf, *p)) {
++            *p = '\0';
++            return;
++        }
++        if (IS_DQUOTE(conf, *p)) {
++            p = scan_dquote(conf, p);
++            continue;
++        }
++        if (IS_QUOTE(conf, *p)) {
++            p = scan_quote(conf, p);
++            continue;
++        }
++        if (IS_ESC(conf, *p)) {
++            p = scan_esc(conf, p);
++            continue;
++        }
++        if (IS_EOF(conf, *p))
++            return;
++        else
++            p++;
++    }
++}
++
++static int str_copy(CONF *conf, char *section, char **pto, char *from)
++{
++    int q, r, rr = 0, to = 0, len = 0;
++    char *s, *e, *rp, *p, *rrp, *np, *cp, v;
++    BUF_MEM *buf;
++
++    if ((buf = BUF_MEM_new()) == NULL)
++        return (0);
++
++    len = strlen(from) + 1;
++    if (!BUF_MEM_grow(buf, len))
++        goto err;
++
++    for (;;) {
++        if (IS_QUOTE(conf, *from)) {
++            q = *from;
++            from++;
++            while (!IS_EOF(conf, *from) && (*from != q)) {
++                if (IS_ESC(conf, *from)) {
++                    from++;
++                    if (IS_EOF(conf, *from))
++                        break;
++                }
++                buf->data[to++] = *(from++);
++            }
++            if (*from == q)
++                from++;
++        } else if (IS_DQUOTE(conf, *from)) {
++            q = *from;
++            from++;
++            while (!IS_EOF(conf, *from)) {
++                if (*from == q) {
++                    if (*(from + 1) == q) {
++                        from++;
++                    } else {
++                        break;
++                    }
++                }
++                buf->data[to++] = *(from++);
++            }
++            if (*from == q)
++                from++;
++        } else if (IS_ESC(conf, *from)) {
++            from++;
++            v = *(from++);
++            if (IS_EOF(conf, v))
++                break;
++            else if (v == 'r')
++                v = '\r';
++            else if (v == 'n')
++                v = '\n';
++            else if (v == 'b')
++                v = '\b';
++            else if (v == 't')
++                v = '\t';
++            buf->data[to++] = v;
++        } else if (IS_EOF(conf, *from))
++            break;
++        else if (*from == '$') {
++            /* try to expand it */
++            rrp = NULL;
++            s = &(from[1]);
++            if (*s == '{')
++                q = '}';
++            else if (*s == '(')
++                q = ')';
++            else
++                q = 0;
++
++            if (q)
++                s++;
++            cp = section;
++            e = np = s;
++            while (IS_ALPHA_NUMERIC(conf, *e))
++                e++;
++            if ((e[0] == ':') && (e[1] == ':')) {
++                cp = np;
++                rrp = e;
++                rr = *e;
++                *rrp = '\0';
++                e += 2;
++                np = e;
++                while (IS_ALPHA_NUMERIC(conf, *e))
++                    e++;
++            }
++            r = *e;
++            *e = '\0';
++            rp = e;
++            if (q) {
++                if (r != q) {
++                    CONFerr(CONF_F_STR_COPY, CONF_R_NO_CLOSE_BRACE);
++                    goto err;
++                }
++                e++;
++            }
++            /*-
++             * So at this point we have
++             * np which is the start of the name string which is
++             *   '\0' terminated.
++             * cp which is the start of the section string which is
++             *   '\0' terminated.
++             * e is the 'next point after'.
++             * r and rr are the chars replaced by the '\0'
++             * rp and rrp is where 'r' and 'rr' came from.
++             */
++            p = _CONF_get_string(conf, cp, np);
++            if (rrp != NULL)
++                *rrp = rr;
++            *rp = r;
++            if (p == NULL) {
++                CONFerr(CONF_F_STR_COPY, CONF_R_VARIABLE_HAS_NO_VALUE);
++                goto err;
++            }
++            if (!BUF_MEM_grow_clean(buf,
++                        (strlen(p) + buf->length - (e - from)))) {
++                CONFerr(CONF_F_STR_COPY, ERR_R_MALLOC_FAILURE);
++                goto err;
++            }
++            while (*p)
++                buf->data[to++] = *(p++);
++
++            /*
++             * Since we change the pointer 'from', we also have to change the
++             * perceived length of the string it points at.  /RL
++             */
++            len -= e - from;
++            from = e;
++
++            /*
++             * In case there were no braces or parenthesis around the
++             * variable reference, we have to put back the character that was
++             * replaced with a '\0'.  /RL
++             */
++            *rp = r;
++        } else
++            buf->data[to++] = *(from++);
++    }
++    buf->data[to] = '\0';
++    OPENSSL_free(*pto);
++    *pto = buf->data;
++    OPENSSL_free(buf);
++    return (1);
++ err:
++    BUF_MEM_free(buf);
++    return (0);
++}
++
++static char *eat_ws(CONF *conf, char *p)
++{
++    while (IS_WS(conf, *p) && (!IS_EOF(conf, *p)))
++        p++;
++    return (p);
++}
++
++static char *eat_alpha_numeric(CONF *conf, char *p)
++{
++    for (;;) {
++        if (IS_ESC(conf, *p)) {
++            p = scan_esc(conf, p);
++            continue;
++        }
++        if (!IS_ALPHA_NUMERIC_PUNCT(conf, *p))
++            return (p);
++        p++;
++    }
++}
++
++static char *scan_quote(CONF *conf, char *p)
++{
++    int q = *p;
++
++    p++;
++    while (!(IS_EOF(conf, *p)) && (*p != q)) {
++        if (IS_ESC(conf, *p)) {
++            p++;
++            if (IS_EOF(conf, *p))
++                return (p);
++        }
++        p++;
++    }
++    if (*p == q)
++        p++;
++    return (p);
++}
++
++static char *scan_dquote(CONF *conf, char *p)
++{
++    int q = *p;
++
++    p++;
++    while (!(IS_EOF(conf, *p))) {
++        if (*p == q) {
++            if (*(p + 1) == q) {
++                p++;
++            } else {
++                break;
++            }
++        }
++        p++;
++    }
++    if (*p == q)
++        p++;
++    return (p);
++}
++
++static void dump_value_doall_arg(const CONF_VALUE *a, BIO *out)
++{
++    if (a->name)
++        BIO_printf(out, "[%s] %s=%s\n", a->section, a->name, a->value);
++    else
++        BIO_printf(out, "[[%s]]\n", a->section);
++}
++
++IMPLEMENT_LHASH_DOALL_ARG_CONST(CONF_VALUE, BIO);
++
++static int def_dump(const CONF *conf, BIO *out)
++{
++    lh_CONF_VALUE_doall_BIO(conf->data, dump_value_doall_arg, out);
++    return 1;
++}
++
++static int def_is_number(const CONF *conf, char c)
++{
++    return IS_NUMBER(conf, c);
++}
++
++static int def_to_int(const CONF *conf, char c)
++{
++    return c - '0';
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/conf/conf_def.h b/CryptoPkg/Library/OpensslLib/openssl/crypto/conf/conf_def.h
+new file mode 100644
+index 0000000..da4767e
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/conf/conf_def.h
+@@ -0,0 +1,129 @@
++/*
++ * WARNING: do not edit!
++ * Generated by crypto/conf/keysets.pl
++ *
++ * Copyright 1995-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#define CONF_NUMBER             1
++#define CONF_UPPER              2
++#define CONF_LOWER              4
++#define CONF_UNDER              256
++#define CONF_PUNCTUATION        512
++#define CONF_WS                 16
++#define CONF_ESC                32
++#define CONF_QUOTE              64
++#define CONF_DQUOTE             1024
++#define CONF_COMMENT            128
++#define CONF_FCOMMENT           2048
++#define CONF_EOF                8
++#define CONF_HIGHBIT            4096
++#define CONF_ALPHA              (CONF_UPPER|CONF_LOWER)
++#define CONF_ALPHA_NUMERIC      (CONF_ALPHA|CONF_NUMBER|CONF_UNDER)
++#define CONF_ALPHA_NUMERIC_PUNCT (CONF_ALPHA|CONF_NUMBER|CONF_UNDER| \
++                                        CONF_PUNCTUATION)
++
++#define KEYTYPES(c)             ((const unsigned short *)((c)->meth_data))
++#ifndef CHARSET_EBCDIC
++# define IS_COMMENT(c,a)         (KEYTYPES(c)[(a)&0xff]&CONF_COMMENT)
++# define IS_FCOMMENT(c,a)        (KEYTYPES(c)[(a)&0xff]&CONF_FCOMMENT)
++# define IS_EOF(c,a)             (KEYTYPES(c)[(a)&0xff]&CONF_EOF)
++# define IS_ESC(c,a)             (KEYTYPES(c)[(a)&0xff]&CONF_ESC)
++# define IS_NUMBER(c,a)          (KEYTYPES(c)[(a)&0xff]&CONF_NUMBER)
++# define IS_WS(c,a)              (KEYTYPES(c)[(a)&0xff]&CONF_WS)
++# define IS_ALPHA_NUMERIC(c,a)   (KEYTYPES(c)[(a)&0xff]&CONF_ALPHA_NUMERIC)
++# define IS_ALPHA_NUMERIC_PUNCT(c,a) \
++                                (KEYTYPES(c)[(a)&0xff]&CONF_ALPHA_NUMERIC_PUNCT)
++# define IS_QUOTE(c,a)           (KEYTYPES(c)[(a)&0xff]&CONF_QUOTE)
++# define IS_DQUOTE(c,a)          (KEYTYPES(c)[(a)&0xff]&CONF_DQUOTE)
++# define IS_HIGHBIT(c,a)         (KEYTYPES(c)[(a)&0xff]&CONF_HIGHBIT)
++
++#else                           /* CHARSET_EBCDIC */
++
++# define IS_COMMENT(c,a)         (KEYTYPES(c)[os_toascii[a & 0xff]]&CONF_COMMENT)
++# define IS_FCOMMENT(c,a)        (KEYTYPES(c)[os_toascii[a & 0xff]]&CONF_FCOMMENT)
++# define IS_EOF(c,a)             (KEYTYPES(c)[os_toascii[a & 0xff]]&CONF_EOF)
++# define IS_ESC(c,a)             (KEYTYPES(c)[os_toascii[a & 0xff]]&CONF_ESC)
++# define IS_NUMBER(c,a)          (KEYTYPES(c)[os_toascii[a & 0xff]]&CONF_NUMBER)
++# define IS_WS(c,a)              (KEYTYPES(c)[os_toascii[a & 0xff]]&CONF_WS)
++# define IS_ALPHA_NUMERIC(c,a)   (KEYTYPES(c)[os_toascii[a & 0xff]]&CONF_ALPHA_NUMERIC)
++# define IS_ALPHA_NUMERIC_PUNCT(c,a) \
++                                (KEYTYPES(c)[os_toascii[a & 0xff]]&CONF_ALPHA_NUMERIC_PUNCT)
++# define IS_QUOTE(c,a)           (KEYTYPES(c)[os_toascii[a & 0xff]]&CONF_QUOTE)
++# define IS_DQUOTE(c,a)          (KEYTYPES(c)[os_toascii[a & 0xff]]&CONF_DQUOTE)
++# define IS_HIGHBIT(c,a)         (KEYTYPES(c)[os_toascii[a & 0xff]]&CONF_HIGHBIT)
++#endif                          /* CHARSET_EBCDIC */
++
++static const unsigned short CONF_type_default[256] = {
++    0x0008, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
++    0x0000, 0x0010, 0x0010, 0x0000, 0x0000, 0x0010, 0x0000, 0x0000,
++    0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
++    0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
++    0x0010, 0x0200, 0x0040, 0x0080, 0x0000, 0x0200, 0x0200, 0x0040,
++    0x0000, 0x0000, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
++    0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001,
++    0x0001, 0x0001, 0x0000, 0x0200, 0x0000, 0x0000, 0x0000, 0x0200,
++    0x0200, 0x0002, 0x0002, 0x0002, 0x0002, 0x0002, 0x0002, 0x0002,
++    0x0002, 0x0002, 0x0002, 0x0002, 0x0002, 0x0002, 0x0002, 0x0002,
++    0x0002, 0x0002, 0x0002, 0x0002, 0x0002, 0x0002, 0x0002, 0x0002,
++    0x0002, 0x0002, 0x0002, 0x0000, 0x0020, 0x0000, 0x0200, 0x0100,
++    0x0040, 0x0004, 0x0004, 0x0004, 0x0004, 0x0004, 0x0004, 0x0004,
++    0x0004, 0x0004, 0x0004, 0x0004, 0x0004, 0x0004, 0x0004, 0x0004,
++    0x0004, 0x0004, 0x0004, 0x0004, 0x0004, 0x0004, 0x0004, 0x0004,
++    0x0004, 0x0004, 0x0004, 0x0000, 0x0200, 0x0000, 0x0200, 0x0000,
++    0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000,
++    0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000,
++    0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000,
++    0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000,
++    0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000,
++    0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000,
++    0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000,
++    0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000,
++    0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000,
++    0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000,
++    0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000,
++    0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000,
++    0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000,
++    0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000,
++    0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000,
++    0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000,
++};
++
++static const unsigned short CONF_type_win32[256] = {
++    0x0008, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
++    0x0000, 0x0010, 0x0010, 0x0000, 0x0000, 0x0010, 0x0000, 0x0000,
++    0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
++    0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
++    0x0010, 0x0200, 0x0400, 0x0000, 0x0000, 0x0200, 0x0200, 0x0000,
++    0x0000, 0x0000, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
++    0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001,
++    0x0001, 0x0001, 0x0000, 0x0A00, 0x0000, 0x0000, 0x0000, 0x0200,
++    0x0200, 0x0002, 0x0002, 0x0002, 0x0002, 0x0002, 0x0002, 0x0002,
++    0x0002, 0x0002, 0x0002, 0x0002, 0x0002, 0x0002, 0x0002, 0x0002,
++    0x0002, 0x0002, 0x0002, 0x0002, 0x0002, 0x0002, 0x0002, 0x0002,
++    0x0002, 0x0002, 0x0002, 0x0000, 0x0000, 0x0000, 0x0200, 0x0100,
++    0x0000, 0x0004, 0x0004, 0x0004, 0x0004, 0x0004, 0x0004, 0x0004,
++    0x0004, 0x0004, 0x0004, 0x0004, 0x0004, 0x0004, 0x0004, 0x0004,
++    0x0004, 0x0004, 0x0004, 0x0004, 0x0004, 0x0004, 0x0004, 0x0004,
++    0x0004, 0x0004, 0x0004, 0x0000, 0x0200, 0x0000, 0x0200, 0x0000,
++    0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000,
++    0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000,
++    0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000,
++    0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000,
++    0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000,
++    0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000,
++    0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000,
++    0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000,
++    0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000,
++    0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000,
++    0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000,
++    0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000,
++    0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000,
++    0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000,
++    0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000,
++    0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000,
++};
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/conf/conf_err.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/conf/conf_err.c
+new file mode 100644
+index 0000000..b583c05
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/conf/conf_err.c
+@@ -0,0 +1,79 @@
++/*
++ * Generated by util/mkerr.pl DO NOT EDIT
++ * Copyright 1995-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include 
++#include 
++
++/* BEGIN ERROR CODES */
++#ifndef OPENSSL_NO_ERR
++
++# define ERR_FUNC(func) ERR_PACK(ERR_LIB_CONF,func,0)
++# define ERR_REASON(reason) ERR_PACK(ERR_LIB_CONF,0,reason)
++
++static ERR_STRING_DATA CONF_str_functs[] = {
++    {ERR_FUNC(CONF_F_CONF_DUMP_FP), "CONF_dump_fp"},
++    {ERR_FUNC(CONF_F_CONF_LOAD), "CONF_load"},
++    {ERR_FUNC(CONF_F_CONF_LOAD_FP), "CONF_load_fp"},
++    {ERR_FUNC(CONF_F_CONF_PARSE_LIST), "CONF_parse_list"},
++    {ERR_FUNC(CONF_F_DEF_LOAD), "def_load"},
++    {ERR_FUNC(CONF_F_DEF_LOAD_BIO), "def_load_bio"},
++    {ERR_FUNC(CONF_F_MODULE_INIT), "module_init"},
++    {ERR_FUNC(CONF_F_MODULE_LOAD_DSO), "module_load_dso"},
++    {ERR_FUNC(CONF_F_MODULE_RUN), "module_run"},
++    {ERR_FUNC(CONF_F_NCONF_DUMP_BIO), "NCONF_dump_bio"},
++    {ERR_FUNC(CONF_F_NCONF_DUMP_FP), "NCONF_dump_fp"},
++    {ERR_FUNC(CONF_F_NCONF_GET_NUMBER_E), "NCONF_get_number_e"},
++    {ERR_FUNC(CONF_F_NCONF_GET_SECTION), "NCONF_get_section"},
++    {ERR_FUNC(CONF_F_NCONF_GET_STRING), "NCONF_get_string"},
++    {ERR_FUNC(CONF_F_NCONF_LOAD), "NCONF_load"},
++    {ERR_FUNC(CONF_F_NCONF_LOAD_BIO), "NCONF_load_bio"},
++    {ERR_FUNC(CONF_F_NCONF_LOAD_FP), "NCONF_load_fp"},
++    {ERR_FUNC(CONF_F_NCONF_NEW), "NCONF_new"},
++    {ERR_FUNC(CONF_F_STR_COPY), "str_copy"},
++    {0, NULL}
++};
++
++static ERR_STRING_DATA CONF_str_reasons[] = {
++    {ERR_REASON(CONF_R_ERROR_LOADING_DSO), "error loading dso"},
++    {ERR_REASON(CONF_R_LIST_CANNOT_BE_NULL), "list cannot be null"},
++    {ERR_REASON(CONF_R_MISSING_CLOSE_SQUARE_BRACKET),
++     "missing close square bracket"},
++    {ERR_REASON(CONF_R_MISSING_EQUAL_SIGN), "missing equal sign"},
++    {ERR_REASON(CONF_R_MISSING_INIT_FUNCTION), "missing init function"},
++    {ERR_REASON(CONF_R_MODULE_INITIALIZATION_ERROR),
++     "module initialization error"},
++    {ERR_REASON(CONF_R_NO_CLOSE_BRACE), "no close brace"},
++    {ERR_REASON(CONF_R_NO_CONF), "no conf"},
++    {ERR_REASON(CONF_R_NO_CONF_OR_ENVIRONMENT_VARIABLE),
++     "no conf or environment variable"},
++    {ERR_REASON(CONF_R_NO_SECTION), "no section"},
++    {ERR_REASON(CONF_R_NO_SUCH_FILE), "no such file"},
++    {ERR_REASON(CONF_R_NO_VALUE), "no value"},
++    {ERR_REASON(CONF_R_UNABLE_TO_CREATE_NEW_SECTION),
++     "unable to create new section"},
++    {ERR_REASON(CONF_R_UNKNOWN_MODULE_NAME), "unknown module name"},
++    {ERR_REASON(CONF_R_VARIABLE_HAS_NO_VALUE), "variable has no value"},
++    {0, NULL}
++};
++
++#endif
++
++int ERR_load_CONF_strings(void)
++{
++#ifndef OPENSSL_NO_ERR
++
++    if (ERR_func_error_string(CONF_str_functs[0].error) == NULL) {
++        ERR_load_strings(0, CONF_str_functs);
++        ERR_load_strings(0, CONF_str_reasons);
++    }
++#endif
++    return 1;
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/conf/conf_lib.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/conf/conf_lib.c
+new file mode 100644
+index 0000000..3532114
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/conf/conf_lib.c
+@@ -0,0 +1,365 @@
++/*
++ * Copyright 2000-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include 
++#include 
++#include 
++#include 
++#include 
++#include 
++#include 
++#include "e_os.h"
++
++static CONF_METHOD *default_CONF_method = NULL;
++
++/* Init a 'CONF' structure from an old LHASH */
++
++void CONF_set_nconf(CONF *conf, LHASH_OF(CONF_VALUE) *hash)
++{
++    if (default_CONF_method == NULL)
++        default_CONF_method = NCONF_default();
++
++    default_CONF_method->init(conf);
++    conf->data = hash;
++}
++
++/*
++ * The following section contains the "CONF classic" functions, rewritten in
++ * terms of the new CONF interface.
++ */
++
++int CONF_set_default_method(CONF_METHOD *meth)
++{
++    default_CONF_method = meth;
++    return 1;
++}
++
++LHASH_OF(CONF_VALUE) *CONF_load(LHASH_OF(CONF_VALUE) *conf, const char *file,
++                                long *eline)
++{
++    LHASH_OF(CONF_VALUE) *ltmp;
++    BIO *in = NULL;
++
++#ifdef OPENSSL_SYS_VMS
++    in = BIO_new_file(file, "r");
++#else
++    in = BIO_new_file(file, "rb");
++#endif
++    if (in == NULL) {
++        CONFerr(CONF_F_CONF_LOAD, ERR_R_SYS_LIB);
++        return NULL;
++    }
++
++    ltmp = CONF_load_bio(conf, in, eline);
++    BIO_free(in);
++
++    return ltmp;
++}
++
++#ifndef OPENSSL_NO_STDIO
++LHASH_OF(CONF_VALUE) *CONF_load_fp(LHASH_OF(CONF_VALUE) *conf, FILE *fp,
++                                   long *eline)
++{
++    BIO *btmp;
++    LHASH_OF(CONF_VALUE) *ltmp;
++    if ((btmp = BIO_new_fp(fp, BIO_NOCLOSE)) == NULL) {
++        CONFerr(CONF_F_CONF_LOAD_FP, ERR_R_BUF_LIB);
++        return NULL;
++    }
++    ltmp = CONF_load_bio(conf, btmp, eline);
++    BIO_free(btmp);
++    return ltmp;
++}
++#endif
++
++LHASH_OF(CONF_VALUE) *CONF_load_bio(LHASH_OF(CONF_VALUE) *conf, BIO *bp,
++                                    long *eline)
++{
++    CONF ctmp;
++    int ret;
++
++    CONF_set_nconf(&ctmp, conf);
++
++    ret = NCONF_load_bio(&ctmp, bp, eline);
++    if (ret)
++        return ctmp.data;
++    return NULL;
++}
++
++STACK_OF(CONF_VALUE) *CONF_get_section(LHASH_OF(CONF_VALUE) *conf,
++                                       const char *section)
++{
++    if (conf == NULL) {
++        return NULL;
++    } else {
++        CONF ctmp;
++        CONF_set_nconf(&ctmp, conf);
++        return NCONF_get_section(&ctmp, section);
++    }
++}
++
++char *CONF_get_string(LHASH_OF(CONF_VALUE) *conf, const char *group,
++                      const char *name)
++{
++    if (conf == NULL) {
++        return NCONF_get_string(NULL, group, name);
++    } else {
++        CONF ctmp;
++        CONF_set_nconf(&ctmp, conf);
++        return NCONF_get_string(&ctmp, group, name);
++    }
++}
++
++long CONF_get_number(LHASH_OF(CONF_VALUE) *conf, const char *group,
++                     const char *name)
++{
++    int status;
++    long result = 0;
++
++    if (conf == NULL) {
++        status = NCONF_get_number_e(NULL, group, name, &result);
++    } else {
++        CONF ctmp;
++        CONF_set_nconf(&ctmp, conf);
++        status = NCONF_get_number_e(&ctmp, group, name, &result);
++    }
++
++    if (status == 0) {
++        /* This function does not believe in errors... */
++        ERR_clear_error();
++    }
++    return result;
++}
++
++void CONF_free(LHASH_OF(CONF_VALUE) *conf)
++{
++    CONF ctmp;
++    CONF_set_nconf(&ctmp, conf);
++    NCONF_free_data(&ctmp);
++}
++
++#ifndef OPENSSL_NO_STDIO
++int CONF_dump_fp(LHASH_OF(CONF_VALUE) *conf, FILE *out)
++{
++    BIO *btmp;
++    int ret;
++
++    if ((btmp = BIO_new_fp(out, BIO_NOCLOSE)) == NULL) {
++        CONFerr(CONF_F_CONF_DUMP_FP, ERR_R_BUF_LIB);
++        return 0;
++    }
++    ret = CONF_dump_bio(conf, btmp);
++    BIO_free(btmp);
++    return ret;
++}
++#endif
++
++int CONF_dump_bio(LHASH_OF(CONF_VALUE) *conf, BIO *out)
++{
++    CONF ctmp;
++    CONF_set_nconf(&ctmp, conf);
++    return NCONF_dump_bio(&ctmp, out);
++}
++
++/*
++ * The following section contains the "New CONF" functions.  They are
++ * completely centralised around a new CONF structure that may contain
++ * basically anything, but at least a method pointer and a table of data.
++ * These functions are also written in terms of the bridge functions used by
++ * the "CONF classic" functions, for consistency.
++ */
++
++CONF *NCONF_new(CONF_METHOD *meth)
++{
++    CONF *ret;
++
++    if (meth == NULL)
++        meth = NCONF_default();
++
++    ret = meth->create(meth);
++    if (ret == NULL) {
++        CONFerr(CONF_F_NCONF_NEW, ERR_R_MALLOC_FAILURE);
++        return (NULL);
++    }
++
++    return ret;
++}
++
++void NCONF_free(CONF *conf)
++{
++    if (conf == NULL)
++        return;
++    conf->meth->destroy(conf);
++}
++
++void NCONF_free_data(CONF *conf)
++{
++    if (conf == NULL)
++        return;
++    conf->meth->destroy_data(conf);
++}
++
++int NCONF_load(CONF *conf, const char *file, long *eline)
++{
++    if (conf == NULL) {
++        CONFerr(CONF_F_NCONF_LOAD, CONF_R_NO_CONF);
++        return 0;
++    }
++
++    return conf->meth->load(conf, file, eline);
++}
++
++#ifndef OPENSSL_NO_STDIO
++int NCONF_load_fp(CONF *conf, FILE *fp, long *eline)
++{
++    BIO *btmp;
++    int ret;
++    if ((btmp = BIO_new_fp(fp, BIO_NOCLOSE)) == NULL) {
++        CONFerr(CONF_F_NCONF_LOAD_FP, ERR_R_BUF_LIB);
++        return 0;
++    }
++    ret = NCONF_load_bio(conf, btmp, eline);
++    BIO_free(btmp);
++    return ret;
++}
++#endif
++
++int NCONF_load_bio(CONF *conf, BIO *bp, long *eline)
++{
++    if (conf == NULL) {
++        CONFerr(CONF_F_NCONF_LOAD_BIO, CONF_R_NO_CONF);
++        return 0;
++    }
++
++    return conf->meth->load_bio(conf, bp, eline);
++}
++
++STACK_OF(CONF_VALUE) *NCONF_get_section(const CONF *conf, const char *section)
++{
++    if (conf == NULL) {
++        CONFerr(CONF_F_NCONF_GET_SECTION, CONF_R_NO_CONF);
++        return NULL;
++    }
++
++    if (section == NULL) {
++        CONFerr(CONF_F_NCONF_GET_SECTION, CONF_R_NO_SECTION);
++        return NULL;
++    }
++
++    return _CONF_get_section_values(conf, section);
++}
++
++char *NCONF_get_string(const CONF *conf, const char *group, const char *name)
++{
++    char *s = _CONF_get_string(conf, group, name);
++
++    /*
++     * Since we may get a value from an environment variable even if conf is
++     * NULL, let's check the value first
++     */
++    if (s)
++        return s;
++
++    if (conf == NULL) {
++        CONFerr(CONF_F_NCONF_GET_STRING,
++                CONF_R_NO_CONF_OR_ENVIRONMENT_VARIABLE);
++        return NULL;
++    }
++    CONFerr(CONF_F_NCONF_GET_STRING, CONF_R_NO_VALUE);
++    ERR_add_error_data(4, "group=", group, " name=", name);
++    return NULL;
++}
++
++int NCONF_get_number_e(const CONF *conf, const char *group, const char *name,
++                       long *result)
++{
++    char *str;
++
++    if (result == NULL) {
++        CONFerr(CONF_F_NCONF_GET_NUMBER_E, ERR_R_PASSED_NULL_PARAMETER);
++        return 0;
++    }
++
++    str = NCONF_get_string(conf, group, name);
++
++    if (str == NULL)
++        return 0;
++
++    for (*result = 0; conf->meth->is_number(conf, *str);) {
++        *result = (*result) * 10 + conf->meth->to_int(conf, *str);
++        str++;
++    }
++
++    return 1;
++}
++
++#ifndef OPENSSL_NO_STDIO
++int NCONF_dump_fp(const CONF *conf, FILE *out)
++{
++    BIO *btmp;
++    int ret;
++    if ((btmp = BIO_new_fp(out, BIO_NOCLOSE)) == NULL) {
++        CONFerr(CONF_F_NCONF_DUMP_FP, ERR_R_BUF_LIB);
++        return 0;
++    }
++    ret = NCONF_dump_bio(conf, btmp);
++    BIO_free(btmp);
++    return ret;
++}
++#endif
++
++int NCONF_dump_bio(const CONF *conf, BIO *out)
++{
++    if (conf == NULL) {
++        CONFerr(CONF_F_NCONF_DUMP_BIO, CONF_R_NO_CONF);
++        return 0;
++    }
++
++    return conf->meth->dump(conf, out);
++}
++
++/*
++ * These routines call the C malloc/free, to avoid intermixing with
++ * OpenSSL function pointers before the library is initialized.
++ */
++OPENSSL_INIT_SETTINGS *OPENSSL_INIT_new(void)
++{
++    OPENSSL_INIT_SETTINGS *ret = malloc(sizeof(*ret));
++
++    if (ret != NULL)
++        memset(ret, 0, sizeof(*ret));
++    return ret;
++}
++
++
++#ifndef OPENSSL_NO_STDIO
++int OPENSSL_INIT_set_config_appname(OPENSSL_INIT_SETTINGS *settings,
++                                    const char *appname)
++{
++    char *newappname = NULL;
++
++    if (appname != NULL) {
++        newappname = strdup(appname);
++        if (newappname == NULL)
++            return 0;
++    }
++
++    free(settings->appname);
++    settings->appname = newappname;
++
++    return 1;
++}
++#endif
++
++void OPENSSL_INIT_free(OPENSSL_INIT_SETTINGS *settings)
++{
++    free(settings->appname);
++    free(settings);
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/conf/conf_mall.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/conf/conf_mall.c
+new file mode 100644
+index 0000000..4e7a434
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/conf/conf_mall.c
+@@ -0,0 +1,29 @@
++/*
++ * Copyright 2002-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include 
++#include "internal/cryptlib.h"
++#include 
++#include 
++#include 
++#include 
++
++/* Load all OpenSSL builtin modules */
++
++void OPENSSL_load_builtin_modules(void)
++{
++    /* Add builtin modules here */
++    ASN1_add_oid_module();
++    ASN1_add_stable_module();
++#ifndef OPENSSL_NO_ENGINE
++    ENGINE_add_conf_module();
++#endif
++    EVP_add_alg_module();
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/conf/conf_mod.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/conf/conf_mod.c
+new file mode 100644
+index 0000000..31f838e
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/conf/conf_mod.c
+@@ -0,0 +1,549 @@
++/*
++ * Copyright 2002-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include 
++#include 
++#include "internal/cryptlib.h"
++#include "internal/conf.h"
++#include "internal/dso.h"
++#include 
++
++#define DSO_mod_init_name "OPENSSL_init"
++#define DSO_mod_finish_name "OPENSSL_finish"
++
++/*
++ * This structure contains a data about supported modules. entries in this
++ * table correspond to either dynamic or static modules.
++ */
++
++struct conf_module_st {
++    /* DSO of this module or NULL if static */
++    DSO *dso;
++    /* Name of the module */
++    char *name;
++    /* Init function */
++    conf_init_func *init;
++    /* Finish function */
++    conf_finish_func *finish;
++    /* Number of successfully initialized modules */
++    int links;
++    void *usr_data;
++};
++
++/*
++ * This structure contains information about modules that have been
++ * successfully initialized. There may be more than one entry for a given
++ * module.
++ */
++
++struct conf_imodule_st {
++    CONF_MODULE *pmod;
++    char *name;
++    char *value;
++    unsigned long flags;
++    void *usr_data;
++};
++
++static STACK_OF(CONF_MODULE) *supported_modules = NULL;
++static STACK_OF(CONF_IMODULE) *initialized_modules = NULL;
++
++static void module_free(CONF_MODULE *md);
++static void module_finish(CONF_IMODULE *imod);
++static int module_run(const CONF *cnf, const char *name, const char *value,
++                      unsigned long flags);
++static CONF_MODULE *module_add(DSO *dso, const char *name,
++                               conf_init_func *ifunc,
++                               conf_finish_func *ffunc);
++static CONF_MODULE *module_find(const char *name);
++static int module_init(CONF_MODULE *pmod, const char *name, const char *value,
++                       const CONF *cnf);
++static CONF_MODULE *module_load_dso(const CONF *cnf, const char *name,
++                                    const char *value);
++
++/* Main function: load modules from a CONF structure */
++
++int CONF_modules_load(const CONF *cnf, const char *appname,
++                      unsigned long flags)
++{
++    STACK_OF(CONF_VALUE) *values;
++    CONF_VALUE *vl;
++    char *vsection = NULL;
++
++    int ret, i;
++
++    if (!cnf)
++        return 1;
++
++    if (appname)
++        vsection = NCONF_get_string(cnf, NULL, appname);
++
++    if (!appname || (!vsection && (flags & CONF_MFLAGS_DEFAULT_SECTION)))
++        vsection = NCONF_get_string(cnf, NULL, "openssl_conf");
++
++    if (!vsection) {
++        ERR_clear_error();
++        return 1;
++    }
++
++    values = NCONF_get_section(cnf, vsection);
++
++    if (!values)
++        return 0;
++
++    for (i = 0; i < sk_CONF_VALUE_num(values); i++) {
++        vl = sk_CONF_VALUE_value(values, i);
++        ret = module_run(cnf, vl->name, vl->value, flags);
++        if (ret <= 0)
++            if (!(flags & CONF_MFLAGS_IGNORE_ERRORS))
++                return ret;
++    }
++
++    return 1;
++
++}
++
++int CONF_modules_load_file(const char *filename, const char *appname,
++                           unsigned long flags)
++{
++    char *file = NULL;
++    CONF *conf = NULL;
++    int ret = 0;
++    conf = NCONF_new(NULL);
++    if (conf == NULL)
++        goto err;
++
++    if (filename == NULL) {
++        file = CONF_get1_default_config_file();
++        if (!file)
++            goto err;
++    } else
++        file = (char *)filename;
++
++    if (NCONF_load(conf, file, NULL) <= 0) {
++        if ((flags & CONF_MFLAGS_IGNORE_MISSING_FILE) &&
++            (ERR_GET_REASON(ERR_peek_last_error()) == CONF_R_NO_SUCH_FILE)) {
++            ERR_clear_error();
++            ret = 1;
++        }
++        goto err;
++    }
++
++    ret = CONF_modules_load(conf, appname, flags);
++
++ err:
++    if (filename == NULL)
++        OPENSSL_free(file);
++    NCONF_free(conf);
++
++    return ret;
++}
++
++static int module_run(const CONF *cnf, const char *name, const char *value,
++                      unsigned long flags)
++{
++    CONF_MODULE *md;
++    int ret;
++
++    md = module_find(name);
++
++    /* Module not found: try to load DSO */
++    if (!md && !(flags & CONF_MFLAGS_NO_DSO))
++        md = module_load_dso(cnf, name, value);
++
++    if (!md) {
++        if (!(flags & CONF_MFLAGS_SILENT)) {
++            CONFerr(CONF_F_MODULE_RUN, CONF_R_UNKNOWN_MODULE_NAME);
++            ERR_add_error_data(2, "module=", name);
++        }
++        return -1;
++    }
++
++    ret = module_init(md, name, value, cnf);
++
++    if (ret <= 0) {
++        if (!(flags & CONF_MFLAGS_SILENT)) {
++            char rcode[DECIMAL_SIZE(ret) + 1];
++            CONFerr(CONF_F_MODULE_RUN, CONF_R_MODULE_INITIALIZATION_ERROR);
++            BIO_snprintf(rcode, sizeof rcode, "%-8d", ret);
++            ERR_add_error_data(6, "module=", name, ", value=", value,
++                               ", retcode=", rcode);
++        }
++    }
++
++    return ret;
++}
++
++/* Load a module from a DSO */
++static CONF_MODULE *module_load_dso(const CONF *cnf,
++                                    const char *name, const char *value)
++{
++    DSO *dso = NULL;
++    conf_init_func *ifunc;
++    conf_finish_func *ffunc;
++    const char *path = NULL;
++    int errcode = 0;
++    CONF_MODULE *md;
++    /* Look for alternative path in module section */
++    path = NCONF_get_string(cnf, value, "path");
++    if (!path) {
++        ERR_clear_error();
++        path = name;
++    }
++    dso = DSO_load(NULL, path, NULL, 0);
++    if (!dso) {
++        errcode = CONF_R_ERROR_LOADING_DSO;
++        goto err;
++    }
++    ifunc = (conf_init_func *)DSO_bind_func(dso, DSO_mod_init_name);
++    if (!ifunc) {
++        errcode = CONF_R_MISSING_INIT_FUNCTION;
++        goto err;
++    }
++    ffunc = (conf_finish_func *)DSO_bind_func(dso, DSO_mod_finish_name);
++    /* All OK, add module */
++    md = module_add(dso, name, ifunc, ffunc);
++
++    if (!md)
++        goto err;
++
++    return md;
++
++ err:
++    DSO_free(dso);
++    CONFerr(CONF_F_MODULE_LOAD_DSO, errcode);
++    ERR_add_error_data(4, "module=", name, ", path=", path);
++    return NULL;
++}
++
++/* add module to list */
++static CONF_MODULE *module_add(DSO *dso, const char *name,
++                               conf_init_func *ifunc, conf_finish_func *ffunc)
++{
++    CONF_MODULE *tmod = NULL;
++    if (supported_modules == NULL)
++        supported_modules = sk_CONF_MODULE_new_null();
++    if (supported_modules == NULL)
++        return NULL;
++    tmod = OPENSSL_zalloc(sizeof(*tmod));
++    if (tmod == NULL)
++        return NULL;
++
++    tmod->dso = dso;
++    tmod->name = OPENSSL_strdup(name);
++    tmod->init = ifunc;
++    tmod->finish = ffunc;
++    if (tmod->name == NULL) {
++        OPENSSL_free(tmod);
++        return NULL;
++    }
++
++    if (!sk_CONF_MODULE_push(supported_modules, tmod)) {
++        OPENSSL_free(tmod->name);
++        OPENSSL_free(tmod);
++        return NULL;
++    }
++
++    return tmod;
++}
++
++/*
++ * Find a module from the list. We allow module names of the form
++ * modname.XXXX to just search for modname to allow the same module to be
++ * initialized more than once.
++ */
++
++static CONF_MODULE *module_find(const char *name)
++{
++    CONF_MODULE *tmod;
++    int i, nchar;
++    char *p;
++    p = strrchr(name, '.');
++
++    if (p)
++        nchar = p - name;
++    else
++        nchar = strlen(name);
++
++    for (i = 0; i < sk_CONF_MODULE_num(supported_modules); i++) {
++        tmod = sk_CONF_MODULE_value(supported_modules, i);
++        if (strncmp(tmod->name, name, nchar) == 0)
++            return tmod;
++    }
++
++    return NULL;
++
++}
++
++/* initialize a module */
++static int module_init(CONF_MODULE *pmod, const char *name, const char *value,
++                       const CONF *cnf)
++{
++    int ret = 1;
++    int init_called = 0;
++    CONF_IMODULE *imod = NULL;
++
++    /* Otherwise add initialized module to list */
++    imod = OPENSSL_malloc(sizeof(*imod));
++    if (imod == NULL)
++        goto err;
++
++    imod->pmod = pmod;
++    imod->name = OPENSSL_strdup(name);
++    imod->value = OPENSSL_strdup(value);
++    imod->usr_data = NULL;
++
++    if (!imod->name || !imod->value)
++        goto memerr;
++
++    /* Try to initialize module */
++    if (pmod->init) {
++        ret = pmod->init(imod, cnf);
++        init_called = 1;
++        /* Error occurred, exit */
++        if (ret <= 0)
++            goto err;
++    }
++
++    if (initialized_modules == NULL) {
++        initialized_modules = sk_CONF_IMODULE_new_null();
++        if (!initialized_modules) {
++            CONFerr(CONF_F_MODULE_INIT, ERR_R_MALLOC_FAILURE);
++            goto err;
++        }
++    }
++
++    if (!sk_CONF_IMODULE_push(initialized_modules, imod)) {
++        CONFerr(CONF_F_MODULE_INIT, ERR_R_MALLOC_FAILURE);
++        goto err;
++    }
++
++    pmod->links++;
++
++    return ret;
++
++ err:
++
++    /* We've started the module so we'd better finish it */
++    if (pmod->finish && init_called)
++        pmod->finish(imod);
++
++ memerr:
++    if (imod) {
++        OPENSSL_free(imod->name);
++        OPENSSL_free(imod->value);
++        OPENSSL_free(imod);
++    }
++
++    return -1;
++
++}
++
++/*
++ * Unload any dynamic modules that have a link count of zero: i.e. have no
++ * active initialized modules. If 'all' is set then all modules are unloaded
++ * including static ones.
++ */
++
++void CONF_modules_unload(int all)
++{
++    int i;
++    CONF_MODULE *md;
++    CONF_modules_finish();
++    /* unload modules in reverse order */
++    for (i = sk_CONF_MODULE_num(supported_modules) - 1; i >= 0; i--) {
++        md = sk_CONF_MODULE_value(supported_modules, i);
++        /* If static or in use and 'all' not set ignore it */
++        if (((md->links > 0) || !md->dso) && !all)
++            continue;
++        /* Since we're working in reverse this is OK */
++        (void)sk_CONF_MODULE_delete(supported_modules, i);
++        module_free(md);
++    }
++    if (sk_CONF_MODULE_num(supported_modules) == 0) {
++        sk_CONF_MODULE_free(supported_modules);
++        supported_modules = NULL;
++    }
++}
++
++/* unload a single module */
++static void module_free(CONF_MODULE *md)
++{
++    DSO_free(md->dso);
++    OPENSSL_free(md->name);
++    OPENSSL_free(md);
++}
++
++/* finish and free up all modules instances */
++
++void CONF_modules_finish(void)
++{
++    CONF_IMODULE *imod;
++    while (sk_CONF_IMODULE_num(initialized_modules) > 0) {
++        imod = sk_CONF_IMODULE_pop(initialized_modules);
++        module_finish(imod);
++    }
++    sk_CONF_IMODULE_free(initialized_modules);
++    initialized_modules = NULL;
++}
++
++/* finish a module instance */
++
++static void module_finish(CONF_IMODULE *imod)
++{
++    if (!imod)
++        return;
++    if (imod->pmod->finish)
++        imod->pmod->finish(imod);
++    imod->pmod->links--;
++    OPENSSL_free(imod->name);
++    OPENSSL_free(imod->value);
++    OPENSSL_free(imod);
++}
++
++/* Add a static module to OpenSSL */
++
++int CONF_module_add(const char *name, conf_init_func *ifunc,
++                    conf_finish_func *ffunc)
++{
++    if (module_add(NULL, name, ifunc, ffunc))
++        return 1;
++    else
++        return 0;
++}
++
++void conf_modules_free_int(void)
++{
++    CONF_modules_finish();
++    CONF_modules_unload(1);
++}
++
++/* Utility functions */
++
++const char *CONF_imodule_get_name(const CONF_IMODULE *md)
++{
++    return md->name;
++}
++
++const char *CONF_imodule_get_value(const CONF_IMODULE *md)
++{
++    return md->value;
++}
++
++void *CONF_imodule_get_usr_data(const CONF_IMODULE *md)
++{
++    return md->usr_data;
++}
++
++void CONF_imodule_set_usr_data(CONF_IMODULE *md, void *usr_data)
++{
++    md->usr_data = usr_data;
++}
++
++CONF_MODULE *CONF_imodule_get_module(const CONF_IMODULE *md)
++{
++    return md->pmod;
++}
++
++unsigned long CONF_imodule_get_flags(const CONF_IMODULE *md)
++{
++    return md->flags;
++}
++
++void CONF_imodule_set_flags(CONF_IMODULE *md, unsigned long flags)
++{
++    md->flags = flags;
++}
++
++void *CONF_module_get_usr_data(CONF_MODULE *pmod)
++{
++    return pmod->usr_data;
++}
++
++void CONF_module_set_usr_data(CONF_MODULE *pmod, void *usr_data)
++{
++    pmod->usr_data = usr_data;
++}
++
++/* Return default config file name */
++
++char *CONF_get1_default_config_file(void)
++{
++    char *file;
++    int len;
++
++    file = getenv("OPENSSL_CONF");
++    if (file)
++        return OPENSSL_strdup(file);
++
++    len = strlen(X509_get_default_cert_area());
++#ifndef OPENSSL_SYS_VMS
++    len++;
++#endif
++    len += strlen(OPENSSL_CONF);
++
++    file = OPENSSL_malloc(len + 1);
++
++    if (file == NULL)
++        return NULL;
++    OPENSSL_strlcpy(file, X509_get_default_cert_area(), len + 1);
++#ifndef OPENSSL_SYS_VMS
++    OPENSSL_strlcat(file, "/", len + 1);
++#endif
++    OPENSSL_strlcat(file, OPENSSL_CONF, len + 1);
++
++    return file;
++}
++
++/*
++ * This function takes a list separated by 'sep' and calls the callback
++ * function giving the start and length of each member optionally stripping
++ * leading and trailing whitespace. This can be used to parse comma separated
++ * lists for example.
++ */
++
++int CONF_parse_list(const char *list_, int sep, int nospc,
++                    int (*list_cb) (const char *elem, int len, void *usr),
++                    void *arg)
++{
++    int ret;
++    const char *lstart, *tmpend, *p;
++
++    if (list_ == NULL) {
++        CONFerr(CONF_F_CONF_PARSE_LIST, CONF_R_LIST_CANNOT_BE_NULL);
++        return 0;
++    }
++
++    lstart = list_;
++    for (;;) {
++        if (nospc) {
++            while (*lstart && isspace((unsigned char)*lstart))
++                lstart++;
++        }
++        p = strchr(lstart, sep);
++        if (p == lstart || !*lstart)
++            ret = list_cb(NULL, 0, arg);
++        else {
++            if (p)
++                tmpend = p - 1;
++            else
++                tmpend = lstart + strlen(lstart) - 1;
++            if (nospc) {
++                while (isspace((unsigned char)*tmpend))
++                    tmpend--;
++            }
++            ret = list_cb(lstart, tmpend - lstart + 1, arg);
++        }
++        if (ret <= 0)
++            return ret;
++        if (p == NULL)
++            return 1;
++        lstart = p + 1;
++    }
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/conf/conf_sap.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/conf/conf_sap.c
+new file mode 100644
+index 0000000..bed95ab
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/conf/conf_sap.c
+@@ -0,0 +1,60 @@
++/*
++ * Copyright 2002-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include 
++#include "internal/cryptlib.h"
++#include 
++#include 
++#include 
++#include 
++
++/*
++ * This is the automatic configuration loader: it is called automatically by
++ * OpenSSL when any of a number of standard initialisation functions are
++ * called, unless this is overridden by calling OPENSSL_no_config()
++ */
++
++static int openssl_configured = 0;
++
++#if OPENSSL_API_COMPAT < 0x10100000L
++void OPENSSL_config(const char *appname)
++{
++    OPENSSL_INIT_SETTINGS settings;
++
++    memset(&settings, 0, sizeof(settings));
++    if (appname != NULL)
++        settings.appname = strdup(appname);
++    OPENSSL_init_crypto(OPENSSL_INIT_LOAD_CONFIG, &settings);
++}
++#endif
++
++void openssl_config_int(const char *appname)
++{
++    if (openssl_configured)
++        return;
++
++    OPENSSL_load_builtin_modules();
++#ifndef OPENSSL_NO_ENGINE
++    /* Need to load ENGINEs */
++    ENGINE_load_builtin_engines();
++#endif
++    ERR_clear_error();
++#ifndef OPENSSL_SYS_UEFI
++    CONF_modules_load_file(NULL, appname,
++                               CONF_MFLAGS_DEFAULT_SECTION |
++                               CONF_MFLAGS_IGNORE_MISSING_FILE);
++#endif
++    openssl_configured = 1;
++}
++
++void openssl_no_config_int(void)
++{
++    openssl_configured = 1;
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/conf/keysets.pl b/CryptoPkg/Library/OpensslLib/openssl/crypto/conf/keysets.pl
+new file mode 100644
+index 0000000..5af08ae
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/conf/keysets.pl
+@@ -0,0 +1,141 @@
++#! /usr/bin/env perl
++# Copyright 1995-2016 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
++# in the file LICENSE in the source distribution or at
++# https://www.openssl.org/source/license.html
++
++$NUMBER=0x01;
++$UPPER=0x02;
++$LOWER=0x04;
++$UNDER=0x100;
++$PUNCTUATION=0x200;
++$WS=0x10;
++$ESC=0x20;
++$QUOTE=0x40;
++$DQUOTE=0x400;
++$COMMENT=0x80;
++$FCOMMENT=0x800;
++$EOF=0x08;
++$HIGHBIT=0x1000;
++
++foreach (0 .. 255)
++	{
++	$v=0;
++	$c=sprintf("%c",$_);
++	$v|=$NUMBER	if ($c =~ /[0-9]/);
++	$v|=$UPPER	if ($c =~ /[A-Z]/);
++	$v|=$LOWER	if ($c =~ /[a-z]/);
++	$v|=$UNDER	if ($c =~ /_/);
++	$v|=$PUNCTUATION if ($c =~ /[!\.%&\*\+,\/;\?\@\^\~\|-]/);
++	$v|=$WS		if ($c =~ /[ \t\r\n]/);
++	$v|=$ESC	if ($c =~ /\\/);
++	$v|=$QUOTE	if ($c =~ /['`"]/); # for emacs: "`'}/)
++	$v|=$COMMENT	if ($c =~ /\#/);
++	$v|=$EOF	if ($c =~ /\0/);
++	$v|=$HIGHBIT	if ($c =~/[\x80-\xff]/);
++
++	push(@V_def,$v);
++	}
++
++foreach (0 .. 255)
++	{
++	$v=0;
++	$c=sprintf("%c",$_);
++	$v|=$NUMBER	if ($c =~ /[0-9]/);
++	$v|=$UPPER	if ($c =~ /[A-Z]/);
++	$v|=$LOWER	if ($c =~ /[a-z]/);
++	$v|=$UNDER	if ($c =~ /_/);
++	$v|=$PUNCTUATION if ($c =~ /[!\.%&\*\+,\/;\?\@\^\~\|-]/);
++	$v|=$WS		if ($c =~ /[ \t\r\n]/);
++	$v|=$DQUOTE	if ($c =~ /["]/); # for emacs: "}/)
++	$v|=$FCOMMENT	if ($c =~ /;/);
++	$v|=$EOF	if ($c =~ /\0/);
++	$v|=$HIGHBIT	if ($c =~/[\x80-\xff]/);
++
++	push(@V_w32,$v);
++	}
++
++print <<"EOF";
++/*
++ * WARNING: do not edit!
++ * Generated by crypto/conf/keysets.pl
++ *
++ * Copyright 1995-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#define CONF_NUMBER             $NUMBER
++#define CONF_UPPER              $UPPER
++#define CONF_LOWER              $LOWER
++#define CONF_UNDER              $UNDER
++#define CONF_PUNCTUATION        $PUNCTUATION
++#define CONF_WS                 $WS
++#define CONF_ESC                $ESC
++#define CONF_QUOTE              $QUOTE
++#define CONF_DQUOTE             $DQUOTE
++#define CONF_COMMENT            $COMMENT
++#define CONF_FCOMMENT           $FCOMMENT
++#define CONF_EOF                $EOF
++#define CONF_HIGHBIT            $HIGHBIT
++#define CONF_ALPHA              (CONF_UPPER|CONF_LOWER)
++#define CONF_ALPHA_NUMERIC      (CONF_ALPHA|CONF_NUMBER|CONF_UNDER)
++#define CONF_ALPHA_NUMERIC_PUNCT (CONF_ALPHA|CONF_NUMBER|CONF_UNDER| \\
++                                        CONF_PUNCTUATION)
++
++#define KEYTYPES(c)             ((const unsigned short *)((c)->meth_data))
++#ifndef CHARSET_EBCDIC
++# define IS_COMMENT(c,a)         (KEYTYPES(c)[(a)&0xff]&CONF_COMMENT)
++# define IS_FCOMMENT(c,a)        (KEYTYPES(c)[(a)&0xff]&CONF_FCOMMENT)
++# define IS_EOF(c,a)             (KEYTYPES(c)[(a)&0xff]&CONF_EOF)
++# define IS_ESC(c,a)             (KEYTYPES(c)[(a)&0xff]&CONF_ESC)
++# define IS_NUMBER(c,a)          (KEYTYPES(c)[(a)&0xff]&CONF_NUMBER)
++# define IS_WS(c,a)              (KEYTYPES(c)[(a)&0xff]&CONF_WS)
++# define IS_ALPHA_NUMERIC(c,a)   (KEYTYPES(c)[(a)&0xff]&CONF_ALPHA_NUMERIC)
++# define IS_ALPHA_NUMERIC_PUNCT(c,a) \\
++                                (KEYTYPES(c)[(a)&0xff]&CONF_ALPHA_NUMERIC_PUNCT)
++# define IS_QUOTE(c,a)           (KEYTYPES(c)[(a)&0xff]&CONF_QUOTE)
++# define IS_DQUOTE(c,a)          (KEYTYPES(c)[(a)&0xff]&CONF_DQUOTE)
++# define IS_HIGHBIT(c,a)         (KEYTYPES(c)[(a)&0xff]&CONF_HIGHBIT)
++
++#else                           /* CHARSET_EBCDIC */
++
++# define IS_COMMENT(c,a)         (KEYTYPES(c)[os_toascii[a & 0xff]]&CONF_COMMENT)
++# define IS_FCOMMENT(c,a)        (KEYTYPES(c)[os_toascii[a & 0xff]]&CONF_FCOMMENT)
++# define IS_EOF(c,a)             (KEYTYPES(c)[os_toascii[a & 0xff]]&CONF_EOF)
++# define IS_ESC(c,a)             (KEYTYPES(c)[os_toascii[a & 0xff]]&CONF_ESC)
++# define IS_NUMBER(c,a)          (KEYTYPES(c)[os_toascii[a & 0xff]]&CONF_NUMBER)
++# define IS_WS(c,a)              (KEYTYPES(c)[os_toascii[a & 0xff]]&CONF_WS)
++# define IS_ALPHA_NUMERIC(c,a)   (KEYTYPES(c)[os_toascii[a & 0xff]]&CONF_ALPHA_NUMERIC)
++# define IS_ALPHA_NUMERIC_PUNCT(c,a) \\
++                                (KEYTYPES(c)[os_toascii[a & 0xff]]&CONF_ALPHA_NUMERIC_PUNCT)
++# define IS_QUOTE(c,a)           (KEYTYPES(c)[os_toascii[a & 0xff]]&CONF_QUOTE)
++# define IS_DQUOTE(c,a)          (KEYTYPES(c)[os_toascii[a & 0xff]]&CONF_DQUOTE)
++# define IS_HIGHBIT(c,a)         (KEYTYPES(c)[os_toascii[a & 0xff]]&CONF_HIGHBIT)
++#endif                          /* CHARSET_EBCDIC */
++
++EOF
++
++print "static const unsigned short CONF_type_default[256] = {";
++
++for ($i=0; $i<256; $i++)
++	{
++	print "\n   " if ($i % 8) == 0;
++	printf " 0x%04X,",$V_def[$i];
++	}
++
++print "\n};\n\n";
++
++print "static const unsigned short CONF_type_win32[256] = {";
++
++for ($i=0; $i<256; $i++)
++	{
++	print "\n   " if ($i % 8) == 0;
++	printf " 0x%04X,",$V_w32[$i];
++	}
++
++print "\n};\n";
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/cpt_err.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/cpt_err.c
+new file mode 100644
+index 0000000..c28dcf1
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/cpt_err.c
+@@ -0,0 +1,55 @@
++/*
++ * Generated by util/mkerr.pl DO NOT EDIT
++ * Copyright 1995-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include 
++#include 
++
++/* BEGIN ERROR CODES */
++#ifndef OPENSSL_NO_ERR
++
++# define ERR_FUNC(func) ERR_PACK(ERR_LIB_CRYPTO,func,0)
++# define ERR_REASON(reason) ERR_PACK(ERR_LIB_CRYPTO,0,reason)
++
++static ERR_STRING_DATA CRYPTO_str_functs[] = {
++    {ERR_FUNC(CRYPTO_F_CRYPTO_DUP_EX_DATA), "CRYPTO_dup_ex_data"},
++    {ERR_FUNC(CRYPTO_F_CRYPTO_FREE_EX_DATA), "CRYPTO_free_ex_data"},
++    {ERR_FUNC(CRYPTO_F_CRYPTO_GET_EX_NEW_INDEX), "CRYPTO_get_ex_new_index"},
++    {ERR_FUNC(CRYPTO_F_CRYPTO_MEMDUP), "CRYPTO_memdup"},
++    {ERR_FUNC(CRYPTO_F_CRYPTO_NEW_EX_DATA), "CRYPTO_new_ex_data"},
++    {ERR_FUNC(CRYPTO_F_CRYPTO_SET_EX_DATA), "CRYPTO_set_ex_data"},
++    {ERR_FUNC(CRYPTO_F_FIPS_MODE_SET), "FIPS_mode_set"},
++    {ERR_FUNC(CRYPTO_F_GET_AND_LOCK), "get_and_lock"},
++    {ERR_FUNC(CRYPTO_F_OPENSSL_BUF2HEXSTR), "OPENSSL_buf2hexstr"},
++    {ERR_FUNC(CRYPTO_F_OPENSSL_HEXSTR2BUF), "OPENSSL_hexstr2buf"},
++    {ERR_FUNC(CRYPTO_F_OPENSSL_INIT_CRYPTO), "OPENSSL_init_crypto"},
++    {0, NULL}
++};
++
++static ERR_STRING_DATA CRYPTO_str_reasons[] = {
++    {ERR_REASON(CRYPTO_R_FIPS_MODE_NOT_SUPPORTED), "fips mode not supported"},
++    {ERR_REASON(CRYPTO_R_ILLEGAL_HEX_DIGIT), "illegal hex digit"},
++    {ERR_REASON(CRYPTO_R_ODD_NUMBER_OF_DIGITS), "odd number of digits"},
++    {0, NULL}
++};
++
++#endif
++
++int ERR_load_CRYPTO_strings(void)
++{
++#ifndef OPENSSL_NO_ERR
++
++    if (ERR_func_error_string(CRYPTO_str_functs[0].error) == NULL) {
++        ERR_load_strings(0, CRYPTO_str_functs);
++        ERR_load_strings(0, CRYPTO_str_reasons);
++    }
++#endif
++    return 1;
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/cryptlib.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/cryptlib.c
+new file mode 100644
+index 0000000..01b8ce5
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/cryptlib.c
+@@ -0,0 +1,341 @@
++/*
++ * Copyright 1998-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++/* ====================================================================
++ * Copyright 2002 Sun Microsystems, Inc. ALL RIGHTS RESERVED.
++ * ECDH support in OpenSSL originally developed by
++ * SUN MICROSYSTEMS, INC., and contributed to the OpenSSL project.
++ */
++
++#include "internal/cryptlib_int.h"
++#include 
++
++#if     defined(__i386)   || defined(__i386__)   || defined(_M_IX86) || \
++        defined(__x86_64) || defined(__x86_64__) || \
++        defined(_M_AMD64) || defined(_M_X64)
++
++extern unsigned int OPENSSL_ia32cap_P[4];
++
++# if defined(OPENSSL_CPUID_OBJ) && !defined(OPENSSL_NO_ASM) && !defined(I386_ONLY)
++#include 
++#  define OPENSSL_CPUID_SETUP
++typedef uint64_t IA32CAP;
++void OPENSSL_cpuid_setup(void)
++{
++    static int trigger = 0;
++    IA32CAP OPENSSL_ia32_cpuid(unsigned int *);
++    IA32CAP vec;
++    char *env;
++
++    if (trigger)
++        return;
++
++    trigger = 1;
++    if ((env = getenv("OPENSSL_ia32cap"))) {
++        int off = (env[0] == '~') ? 1 : 0;
++#  if defined(_WIN32)
++        if (!sscanf(env + off, "%I64i", &vec))
++            vec = strtoul(env + off, NULL, 0);
++#  else
++        if (!sscanf(env + off, "%lli", (long long *)&vec))
++            vec = strtoul(env + off, NULL, 0);
++#  endif
++        if (off)
++            vec = OPENSSL_ia32_cpuid(OPENSSL_ia32cap_P) & ~vec;
++        else if (env[0] == ':')
++            vec = OPENSSL_ia32_cpuid(OPENSSL_ia32cap_P);
++
++        OPENSSL_ia32cap_P[2] = 0;
++        if ((env = strchr(env, ':'))) {
++            unsigned int vecx;
++            env++;
++            off = (env[0] == '~') ? 1 : 0;
++            vecx = strtoul(env + off, NULL, 0);
++            if (off)
++                OPENSSL_ia32cap_P[2] &= ~vecx;
++            else
++                OPENSSL_ia32cap_P[2] = vecx;
++        }
++    } else
++        vec = OPENSSL_ia32_cpuid(OPENSSL_ia32cap_P);
++
++    /*
++     * |(1<<10) sets a reserved bit to signal that variable
++     * was initialized already... This is to avoid interference
++     * with cpuid snippets in ELF .init segment.
++     */
++    OPENSSL_ia32cap_P[0] = (unsigned int)vec | (1 << 10);
++    OPENSSL_ia32cap_P[1] = (unsigned int)(vec >> 32);
++}
++# else
++unsigned int OPENSSL_ia32cap_P[4];
++# endif
++#endif
++int OPENSSL_NONPIC_relocated = 0;
++#if !defined(OPENSSL_CPUID_SETUP) && !defined(OPENSSL_CPUID_OBJ)
++void OPENSSL_cpuid_setup(void)
++{
++}
++#endif
++
++#if defined(_WIN32) && !defined(__CYGWIN__)
++# include 
++# include 
++# ifdef __WATCOMC__
++#  if defined(_UNICODE) || defined(__UNICODE__)
++#   define _vsntprintf _vsnwprintf
++#  else
++#   define _vsntprintf _vsnprintf
++#  endif
++# endif
++# ifdef _MSC_VER
++#  define alloca _alloca
++# endif
++
++# if defined(_WIN32_WINNT) && _WIN32_WINNT>=0x0333
++int OPENSSL_isservice(void)
++{
++    HWINSTA h;
++    DWORD len;
++    WCHAR *name;
++    static union {
++        void *p;
++        FARPROC f;
++    } _OPENSSL_isservice = {
++        NULL
++    };
++
++    if (_OPENSSL_isservice.p == NULL) {
++        HANDLE mod = GetModuleHandle(NULL);
++        if (mod != NULL)
++            _OPENSSL_isservice.f = GetProcAddress(mod, "_OPENSSL_isservice");
++        if (_OPENSSL_isservice.p == NULL)
++            _OPENSSL_isservice.p = (void *)-1;
++    }
++
++    if (_OPENSSL_isservice.p != (void *)-1)
++        return (*_OPENSSL_isservice.f) ();
++
++    h = GetProcessWindowStation();
++    if (h == NULL)
++        return -1;
++
++    if (GetUserObjectInformationW(h, UOI_NAME, NULL, 0, &len) ||
++        GetLastError() != ERROR_INSUFFICIENT_BUFFER)
++        return -1;
++
++    if (len > 512)
++        return -1;              /* paranoia */
++    len++, len &= ~1;           /* paranoia */
++    name = (WCHAR *)alloca(len + sizeof(WCHAR));
++    if (!GetUserObjectInformationW(h, UOI_NAME, name, len, &len))
++        return -1;
++
++    len++, len &= ~1;           /* paranoia */
++    name[len / sizeof(WCHAR)] = L'\0'; /* paranoia */
++#  if 1
++    /*
++     * This doesn't cover "interactive" services [working with real
++     * WinSta0's] nor programs started non-interactively by Task Scheduler
++     * [those are working with SAWinSta].
++     */
++    if (wcsstr(name, L"Service-0x"))
++        return 1;
++#  else
++    /* This covers all non-interactive programs such as services. */
++    if (!wcsstr(name, L"WinSta0"))
++        return 1;
++#  endif
++    else
++        return 0;
++}
++# else
++int OPENSSL_isservice(void)
++{
++    return 0;
++}
++# endif
++
++void OPENSSL_showfatal(const char *fmta, ...)
++{
++    va_list ap;
++    TCHAR buf[256];
++    const TCHAR *fmt;
++# ifdef STD_ERROR_HANDLE        /* what a dirty trick! */
++    HANDLE h;
++
++    if ((h = GetStdHandle(STD_ERROR_HANDLE)) != NULL &&
++        GetFileType(h) != FILE_TYPE_UNKNOWN) {
++        /* must be console application */
++        int len;
++        DWORD out;
++
++        va_start(ap, fmta);
++        len = _vsnprintf((char *)buf, sizeof(buf), fmta, ap);
++        WriteFile(h, buf, len < 0 ? sizeof(buf) : (DWORD) len, &out, NULL);
++        va_end(ap);
++        return;
++    }
++# endif
++
++    if (sizeof(TCHAR) == sizeof(char))
++        fmt = (const TCHAR *)fmta;
++    else
++        do {
++            int keepgoing;
++            size_t len_0 = strlen(fmta) + 1, i;
++            WCHAR *fmtw;
++
++            fmtw = (WCHAR *)alloca(len_0 * sizeof(WCHAR));
++            if (fmtw == NULL) {
++                fmt = (const TCHAR *)L"no stack?";
++                break;
++            }
++            if (!MultiByteToWideChar(CP_ACP, 0, fmta, len_0, fmtw, len_0))
++                for (i = 0; i < len_0; i++)
++                    fmtw[i] = (WCHAR)fmta[i];
++            for (i = 0; i < len_0; i++) {
++                if (fmtw[i] == L'%')
++                    do {
++                        keepgoing = 0;
++                        switch (fmtw[i + 1]) {
++                        case L'0':
++                        case L'1':
++                        case L'2':
++                        case L'3':
++                        case L'4':
++                        case L'5':
++                        case L'6':
++                        case L'7':
++                        case L'8':
++                        case L'9':
++                        case L'.':
++                        case L'*':
++                        case L'-':
++                            i++;
++                            keepgoing = 1;
++                            break;
++                        case L's':
++                            fmtw[i + 1] = L'S';
++                            break;
++                        case L'S':
++                            fmtw[i + 1] = L's';
++                            break;
++                        case L'c':
++                            fmtw[i + 1] = L'C';
++                            break;
++                        case L'C':
++                            fmtw[i + 1] = L'c';
++                            break;
++                        }
++                    } while (keepgoing);
++            }
++            fmt = (const TCHAR *)fmtw;
++        } while (0);
++
++    va_start(ap, fmta);
++    _vsntprintf(buf, OSSL_NELEM(buf) - 1, fmt, ap);
++    buf[OSSL_NELEM(buf) - 1] = _T('\0');
++    va_end(ap);
++
++# if defined(_WIN32_WINNT) && _WIN32_WINNT>=0x0333
++    /* this -------------v--- guards NT-specific calls */
++    if (check_winnt() && OPENSSL_isservice() > 0) {
++        HANDLE hEventLog = RegisterEventSource(NULL, _T("OpenSSL"));
++
++        if (hEventLog != NULL) {
++            const TCHAR *pmsg = buf;
++
++            if (!ReportEvent(hEventLog, EVENTLOG_ERROR_TYPE, 0, 0, NULL,
++                             1, 0, &pmsg, NULL)) {
++#if defined(DEBUG)
++                /*
++                 * We are in a situation where we tried to report a critical
++                 * error and this failed for some reason. As a last resort,
++                 * in debug builds, send output to the debugger or any other
++                 * tool like DebugView which can monitor the output.
++                 */
++                OutputDebugString(pmsg);
++#endif
++            }
++
++            (void)DeregisterEventSource(hEventLog);
++        }
++    } else
++# endif
++        MessageBox(NULL, buf, _T("OpenSSL: FATAL"), MB_OK | MB_ICONERROR);
++}
++#else
++void OPENSSL_showfatal(const char *fmta, ...)
++{
++#ifndef OPENSSL_NO_STDIO
++    va_list ap;
++
++    va_start(ap, fmta);
++    vfprintf(stderr, fmta, ap);
++    va_end(ap);
++#endif
++}
++
++int OPENSSL_isservice(void)
++{
++    return 0;
++}
++#endif
++
++void OPENSSL_die(const char *message, const char *file, int line)
++{
++    OPENSSL_showfatal("%s:%d: OpenSSL internal error: %s\n",
++                      file, line, message);
++#if !defined(_WIN32) || defined(__CYGWIN__)
++    abort();
++#else
++    /*
++     * Win32 abort() customarily shows a dialog, but we just did that...
++     */
++# if !defined(_WIN32_WCE)
++    raise(SIGABRT);
++# endif
++    _exit(3);
++#endif
++}
++
++#if !defined(OPENSSL_CPUID_OBJ)
++/* volatile unsigned char* pointers are there because
++ * 1. Accessing a variable declared volatile via a pointer
++ *    that lacks a volatile qualifier causes undefined behavior.
++ * 2. When the variable itself is not volatile the compiler is
++ *    not required to keep all those reads and can convert
++ *    this into canonical memcmp() which doesn't read the whole block.
++ * Pointers to volatile resolve the first problem fully. The second
++ * problem cannot be resolved in any Standard-compliant way but this
++ * works the problem around. Compilers typically react to
++ * pointers to volatile by preserving the reads and writes through them.
++ * The latter is not required by the Standard if the memory pointed to
++ * is not volatile.
++ * Pointers themselves are volatile in the function signature to work
++ * around a subtle bug in gcc 4.6+ which causes writes through
++ * pointers to volatile to not be emitted in some rare,
++ * never needed in real life, pieces of code.
++ */
++int CRYPTO_memcmp(const volatile void * volatile in_a,
++                  const volatile void * volatile in_b,
++                  size_t len)
++{
++    size_t i;
++    const volatile unsigned char *a = in_a;
++    const volatile unsigned char *b = in_b;
++    unsigned char x = 0;
++
++    for (i = 0; i < len; i++)
++        x |= a[i] ^ b[i];
++
++    return x;
++}
++#endif
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/ct/build.info b/CryptoPkg/Library/OpensslLib/openssl/crypto/ct/build.info
+new file mode 100644
+index 0000000..3ca0e31
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/ct/build.info
+@@ -0,0 +1,3 @@
++LIBS=../../libcrypto
++SOURCE[../../libcrypto]= ct_b64.c ct_err.c ct_log.c ct_oct.c ct_policy.c \
++                         ct_prn.c ct_sct.c ct_sct_ctx.c ct_vfy.c ct_x509v3.c
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/ct/ct_b64.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/ct/ct_b64.c
+new file mode 100644
+index 0000000..f0bf3af
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/ct/ct_b64.c
+@@ -0,0 +1,164 @@
++/*
++ * Copyright 2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include 
++
++#include 
++#include 
++#include 
++
++#include "ct_locl.h"
++
++/*
++ * Decodes the base64 string |in| into |out|.
++ * A new string will be malloc'd and assigned to |out|. This will be owned by
++ * the caller. Do not provide a pre-allocated string in |out|.
++ */
++static int ct_base64_decode(const char *in, unsigned char **out)
++{
++    size_t inlen = strlen(in);
++    int outlen;
++    unsigned char *outbuf = NULL;
++
++    if (inlen == 0) {
++        *out = NULL;
++        return 0;
++    }
++
++    outlen = (inlen / 4) * 3;
++    outbuf = OPENSSL_malloc(outlen);
++    if (outbuf == NULL) {
++        CTerr(CT_F_CT_BASE64_DECODE, ERR_R_MALLOC_FAILURE);
++        goto err;
++    }
++
++    outlen = EVP_DecodeBlock(outbuf, (unsigned char *)in, inlen);
++    if (outlen < 0) {
++        CTerr(CT_F_CT_BASE64_DECODE, CT_R_BASE64_DECODE_ERROR);
++        goto err;
++    }
++
++    /* Subtract padding bytes from |outlen| */
++    while (in[--inlen] == '=') {
++        --outlen;
++    }
++
++    *out = outbuf;
++    return outlen;
++err:
++    OPENSSL_free(outbuf);
++    return -1;
++}
++
++SCT *SCT_new_from_base64(unsigned char version, const char *logid_base64,
++                         ct_log_entry_type_t entry_type, uint64_t timestamp,
++                         const char *extensions_base64,
++                         const char *signature_base64)
++{
++    SCT *sct = SCT_new();
++    unsigned char *dec = NULL;
++    const unsigned char* p = NULL;
++    int declen;
++
++    if (sct == NULL) {
++        CTerr(CT_F_SCT_NEW_FROM_BASE64, ERR_R_MALLOC_FAILURE);
++        return NULL;
++    }
++
++    /*
++     * RFC6962 section 4.1 says we "MUST NOT expect this to be 0", but we
++     * can only construct SCT versions that have been defined.
++     */
++    if (!SCT_set_version(sct, version)) {
++        CTerr(CT_F_SCT_NEW_FROM_BASE64, CT_R_SCT_UNSUPPORTED_VERSION);
++        goto err;
++    }
++
++    declen = ct_base64_decode(logid_base64, &dec);
++    if (declen < 0) {
++        CTerr(CT_F_SCT_NEW_FROM_BASE64, X509_R_BASE64_DECODE_ERROR);
++        goto err;
++    }
++    if (!SCT_set0_log_id(sct, dec, declen))
++        goto err;
++    dec = NULL;
++
++    declen = ct_base64_decode(extensions_base64, &dec);
++    if (declen < 0) {
++        CTerr(CT_F_SCT_NEW_FROM_BASE64, X509_R_BASE64_DECODE_ERROR);
++        goto err;
++    }
++    SCT_set0_extensions(sct, dec, declen);
++    dec = NULL;
++
++    declen = ct_base64_decode(signature_base64, &dec);
++    if (declen < 0) {
++        CTerr(CT_F_SCT_NEW_FROM_BASE64, X509_R_BASE64_DECODE_ERROR);
++        goto err;
++    }
++
++    p = dec;
++    if (o2i_SCT_signature(sct, &p, declen) <= 0)
++        goto err;
++    OPENSSL_free(dec);
++    dec = NULL;
++
++    SCT_set_timestamp(sct, timestamp);
++
++    if (!SCT_set_log_entry_type(sct, entry_type))
++        goto err;
++
++    return sct;
++
++ err:
++    OPENSSL_free(dec);
++    SCT_free(sct);
++    return NULL;
++}
++
++/*
++ * Allocate, build and returns a new |ct_log| from input |pkey_base64|
++ * It returns 1 on success,
++ * 0 on decoding failure, or invalid parameter if any
++ * -1 on internal (malloc) failure
++ */
++int CTLOG_new_from_base64(CTLOG **ct_log, const char *pkey_base64, const char *name)
++{
++    unsigned char *pkey_der = NULL;
++    int pkey_der_len = ct_base64_decode(pkey_base64, &pkey_der);
++    const unsigned char *p;
++    EVP_PKEY *pkey = NULL;
++
++    if (ct_log == NULL) {
++        CTerr(CT_F_CTLOG_NEW_FROM_BASE64, ERR_R_PASSED_INVALID_ARGUMENT);
++        return 0;
++    }
++
++    if (pkey_der_len <= 0) {
++        CTerr(CT_F_CTLOG_NEW_FROM_BASE64, CT_R_LOG_CONF_INVALID_KEY);
++        return 0;
++    }
++
++    p = pkey_der;
++    pkey = d2i_PUBKEY(NULL, &p, pkey_der_len);
++    OPENSSL_free(pkey_der);
++    if (pkey == NULL) {
++        CTerr(CT_F_CTLOG_NEW_FROM_BASE64, CT_R_LOG_CONF_INVALID_KEY);
++        return 0;
++    }
++
++    *ct_log = CTLOG_new(pkey, name);
++    if (*ct_log == NULL) {
++        EVP_PKEY_free(pkey);
++        return 0;
++    }
++
++    return 1;
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/ct/ct_err.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/ct/ct_err.c
+new file mode 100644
+index 0000000..fe0778b
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/ct/ct_err.c
+@@ -0,0 +1,87 @@
++/*
++ * Generated by util/mkerr.pl DO NOT EDIT
++ * Copyright 1995-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include 
++#include 
++
++/* BEGIN ERROR CODES */
++#ifndef OPENSSL_NO_ERR
++
++# define ERR_FUNC(func) ERR_PACK(ERR_LIB_CT,func,0)
++# define ERR_REASON(reason) ERR_PACK(ERR_LIB_CT,0,reason)
++
++static ERR_STRING_DATA CT_str_functs[] = {
++    {ERR_FUNC(CT_F_CTLOG_NEW), "CTLOG_new"},
++    {ERR_FUNC(CT_F_CTLOG_NEW_FROM_BASE64), "CTLOG_new_from_base64"},
++    {ERR_FUNC(CT_F_CTLOG_NEW_FROM_CONF), "ctlog_new_from_conf"},
++    {ERR_FUNC(CT_F_CTLOG_STORE_LOAD_CTX_NEW), "ctlog_store_load_ctx_new"},
++    {ERR_FUNC(CT_F_CTLOG_STORE_LOAD_FILE), "CTLOG_STORE_load_file"},
++    {ERR_FUNC(CT_F_CTLOG_STORE_LOAD_LOG), "ctlog_store_load_log"},
++    {ERR_FUNC(CT_F_CTLOG_STORE_NEW), "CTLOG_STORE_new"},
++    {ERR_FUNC(CT_F_CT_BASE64_DECODE), "ct_base64_decode"},
++    {ERR_FUNC(CT_F_CT_POLICY_EVAL_CTX_NEW), "CT_POLICY_EVAL_CTX_new"},
++    {ERR_FUNC(CT_F_CT_V1_LOG_ID_FROM_PKEY), "ct_v1_log_id_from_pkey"},
++    {ERR_FUNC(CT_F_I2O_SCT), "i2o_SCT"},
++    {ERR_FUNC(CT_F_I2O_SCT_LIST), "i2o_SCT_LIST"},
++    {ERR_FUNC(CT_F_I2O_SCT_SIGNATURE), "i2o_SCT_signature"},
++    {ERR_FUNC(CT_F_O2I_SCT), "o2i_SCT"},
++    {ERR_FUNC(CT_F_O2I_SCT_LIST), "o2i_SCT_LIST"},
++    {ERR_FUNC(CT_F_O2I_SCT_SIGNATURE), "o2i_SCT_signature"},
++    {ERR_FUNC(CT_F_SCT_CTX_NEW), "SCT_CTX_new"},
++    {ERR_FUNC(CT_F_SCT_CTX_VERIFY), "SCT_CTX_verify"},
++    {ERR_FUNC(CT_F_SCT_NEW), "SCT_new"},
++    {ERR_FUNC(CT_F_SCT_NEW_FROM_BASE64), "SCT_new_from_base64"},
++    {ERR_FUNC(CT_F_SCT_SET0_LOG_ID), "SCT_set0_log_id"},
++    {ERR_FUNC(CT_F_SCT_SET1_EXTENSIONS), "SCT_set1_extensions"},
++    {ERR_FUNC(CT_F_SCT_SET1_LOG_ID), "SCT_set1_log_id"},
++    {ERR_FUNC(CT_F_SCT_SET1_SIGNATURE), "SCT_set1_signature"},
++    {ERR_FUNC(CT_F_SCT_SET_LOG_ENTRY_TYPE), "SCT_set_log_entry_type"},
++    {ERR_FUNC(CT_F_SCT_SET_SIGNATURE_NID), "SCT_set_signature_nid"},
++    {ERR_FUNC(CT_F_SCT_SET_VERSION), "SCT_set_version"},
++    {0, NULL}
++};
++
++static ERR_STRING_DATA CT_str_reasons[] = {
++    {ERR_REASON(CT_R_BASE64_DECODE_ERROR), "base64 decode error"},
++    {ERR_REASON(CT_R_INVALID_LOG_ID_LENGTH), "invalid log id length"},
++    {ERR_REASON(CT_R_LOG_CONF_INVALID), "log conf invalid"},
++    {ERR_REASON(CT_R_LOG_CONF_INVALID_KEY), "log conf invalid key"},
++    {ERR_REASON(CT_R_LOG_CONF_MISSING_DESCRIPTION),
++     "log conf missing description"},
++    {ERR_REASON(CT_R_LOG_CONF_MISSING_KEY), "log conf missing key"},
++    {ERR_REASON(CT_R_LOG_KEY_INVALID), "log key invalid"},
++    {ERR_REASON(CT_R_SCT_FUTURE_TIMESTAMP), "sct future timestamp"},
++    {ERR_REASON(CT_R_SCT_INVALID), "sct invalid"},
++    {ERR_REASON(CT_R_SCT_INVALID_SIGNATURE), "sct invalid signature"},
++    {ERR_REASON(CT_R_SCT_LIST_INVALID), "sct list invalid"},
++    {ERR_REASON(CT_R_SCT_LOG_ID_MISMATCH), "sct log id mismatch"},
++    {ERR_REASON(CT_R_SCT_NOT_SET), "sct not set"},
++    {ERR_REASON(CT_R_SCT_UNSUPPORTED_VERSION), "sct unsupported version"},
++    {ERR_REASON(CT_R_UNRECOGNIZED_SIGNATURE_NID),
++     "unrecognized signature nid"},
++    {ERR_REASON(CT_R_UNSUPPORTED_ENTRY_TYPE), "unsupported entry type"},
++    {ERR_REASON(CT_R_UNSUPPORTED_VERSION), "unsupported version"},
++    {0, NULL}
++};
++
++#endif
++
++int ERR_load_CT_strings(void)
++{
++#ifndef OPENSSL_NO_ERR
++
++    if (ERR_func_error_string(CT_str_functs[0].error) == NULL) {
++        ERR_load_strings(0, CT_str_functs);
++        ERR_load_strings(0, CT_str_reasons);
++    }
++#endif
++    return 1;
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/ct/ct_locl.h b/CryptoPkg/Library/OpensslLib/openssl/crypto/ct/ct_locl.h
+new file mode 100644
+index 0000000..9f983c9
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/ct/ct_locl.h
+@@ -0,0 +1,216 @@
++/*
++ * Copyright 2015-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include 
++#include 
++#include 
++#include 
++#include 
++
++/*
++ * From RFC6962: opaque SerializedSCT<1..2^16-1>; struct { SerializedSCT
++ * sct_list <1..2^16-1>; } SignedCertificateTimestampList;
++ */
++# define MAX_SCT_SIZE            65535
++# define MAX_SCT_LIST_SIZE       MAX_SCT_SIZE
++
++/*
++ * Macros to read and write integers in network-byte order.
++ */
++
++#define n2s(c,s)        ((s=(((unsigned int)((c)[0]))<< 8)| \
++                            (((unsigned int)((c)[1]))    )),c+=2)
++
++#define s2n(s,c)        ((c[0]=(unsigned char)(((s)>> 8)&0xff), \
++                          c[1]=(unsigned char)(((s)    )&0xff)),c+=2)
++
++#define l2n3(l,c)       ((c[0]=(unsigned char)(((l)>>16)&0xff), \
++                          c[1]=(unsigned char)(((l)>> 8)&0xff), \
++                          c[2]=(unsigned char)(((l)    )&0xff)),c+=3)
++
++#define n2l8(c,l)       (l =((uint64_t)(*((c)++)))<<56, \
++                         l|=((uint64_t)(*((c)++)))<<48, \
++                         l|=((uint64_t)(*((c)++)))<<40, \
++                         l|=((uint64_t)(*((c)++)))<<32, \
++                         l|=((uint64_t)(*((c)++)))<<24, \
++                         l|=((uint64_t)(*((c)++)))<<16, \
++                         l|=((uint64_t)(*((c)++)))<< 8, \
++                         l|=((uint64_t)(*((c)++))))
++
++#define l2n8(l,c)       (*((c)++)=(unsigned char)(((l)>>56)&0xff), \
++                         *((c)++)=(unsigned char)(((l)>>48)&0xff), \
++                         *((c)++)=(unsigned char)(((l)>>40)&0xff), \
++                         *((c)++)=(unsigned char)(((l)>>32)&0xff), \
++                         *((c)++)=(unsigned char)(((l)>>24)&0xff), \
++                         *((c)++)=(unsigned char)(((l)>>16)&0xff), \
++                         *((c)++)=(unsigned char)(((l)>> 8)&0xff), \
++                         *((c)++)=(unsigned char)(((l)    )&0xff))
++
++/* Signed Certificate Timestamp */
++struct sct_st {
++    sct_version_t version;
++    /* If version is not SCT_VERSION_V1, this contains the encoded SCT */
++    unsigned char *sct;
++    size_t sct_len;
++    /* If version is SCT_VERSION_V1, fields below contain components of the SCT */
++    unsigned char *log_id;
++    size_t log_id_len;
++    /*
++    * Note, we cannot distinguish between an unset timestamp, and one
++    * that is set to 0.  However since CT didn't exist in 1970, no real
++    * SCT should ever be set as such.
++    */
++    uint64_t timestamp;
++    unsigned char *ext;
++    size_t ext_len;
++    unsigned char hash_alg;
++    unsigned char sig_alg;
++    unsigned char *sig;
++    size_t sig_len;
++    /* Log entry type */
++    ct_log_entry_type_t entry_type;
++    /* Where this SCT was found, e.g. certificate, OCSP response, etc. */
++    sct_source_t source;
++    /* The result of the last attempt to validate this SCT. */
++    sct_validation_status_t validation_status;
++};
++
++/* Miscellaneous data that is useful when verifying an SCT  */
++struct sct_ctx_st {
++    /* Public key */
++    EVP_PKEY *pkey;
++    /* Hash of public key */
++    unsigned char *pkeyhash;
++    size_t pkeyhashlen;
++    /* For pre-certificate: issuer public key hash */
++    unsigned char *ihash;
++    size_t ihashlen;
++    /* certificate encoding */
++    unsigned char *certder;
++    size_t certderlen;
++    /* pre-certificate encoding */
++    unsigned char *preder;
++    size_t prederlen;
++    /* milliseconds since epoch (to check that the SCT isn't from the future) */
++    uint64_t epoch_time_in_ms;
++};
++
++/* Context when evaluating whether a Certificate Transparency policy is met */
++struct ct_policy_eval_ctx_st {
++    X509 *cert;
++    X509 *issuer;
++    CTLOG_STORE *log_store;
++    /* milliseconds since epoch (to check that SCTs aren't from the future) */
++    uint64_t epoch_time_in_ms;
++};
++
++/*
++ * Creates a new context for verifying an SCT.
++ */
++SCT_CTX *SCT_CTX_new(void);
++/*
++ * Deletes an SCT verification context.
++ */
++void SCT_CTX_free(SCT_CTX *sctx);
++
++/*
++ * Sets the certificate that the SCT was created for.
++ * If *cert does not have a poison extension, presigner must be NULL.
++ * If *cert does not have a poison extension, it may have a single SCT
++ * (NID_ct_precert_scts) extension.
++ * If either *cert or *presigner have an AKID (NID_authority_key_identifier)
++ * extension, both must have one.
++ * Returns 1 on success, 0 on failure.
++ */
++__owur int SCT_CTX_set1_cert(SCT_CTX *sctx, X509 *cert, X509 *presigner);
++
++/*
++ * Sets the issuer of the certificate that the SCT was created for.
++ * This is just a convenience method to save extracting the public key and
++ * calling SCT_CTX_set1_issuer_pubkey().
++ * Issuer must not be NULL.
++ * Returns 1 on success, 0 on failure.
++ */
++__owur int SCT_CTX_set1_issuer(SCT_CTX *sctx, const X509 *issuer);
++
++/*
++ * Sets the public key of the issuer of the certificate that the SCT was created
++ * for.
++ * The public key must not be NULL.
++ * Returns 1 on success, 0 on failure.
++ */
++__owur int SCT_CTX_set1_issuer_pubkey(SCT_CTX *sctx, X509_PUBKEY *pubkey);
++
++/*
++ * Sets the public key of the CT log that the SCT is from.
++ * Returns 1 on success, 0 on failure.
++ */
++__owur int SCT_CTX_set1_pubkey(SCT_CTX *sctx, X509_PUBKEY *pubkey);
++
++/*
++ * Sets the time to evaluate the SCT against, in milliseconds since the Unix
++ * epoch. If the SCT's timestamp is after this time, it will be interpreted as
++ * having been issued in the future. RFC6962 states that "TLS clients MUST
++ * reject SCTs whose timestamp is in the future", so an SCT will not validate
++ * in this case.
++ */
++void SCT_CTX_set_time(SCT_CTX *sctx, uint64_t time_in_ms);
++
++/*
++ * Verifies an SCT with the given context.
++ * Returns 1 if the SCT verifies successfully; any other value indicates
++ * failure. See EVP_DigestVerifyFinal() for the meaning of those values.
++ */
++__owur int SCT_CTX_verify(const SCT_CTX *sctx, const SCT *sct);
++
++/*
++ * Does this SCT have the minimum fields populated to be usable?
++ * Returns 1 if so, 0 otherwise.
++ */
++__owur int SCT_is_complete(const SCT *sct);
++
++/*
++ * Does this SCT have the signature-related fields populated?
++ * Returns 1 if so, 0 otherwise.
++ * This checks that the signature and hash algorithms are set to supported
++ * values and that the signature field is set.
++ */
++__owur int SCT_signature_is_complete(const SCT *sct);
++
++/*
++ * TODO(RJPercival): Create an SCT_signature struct and make i2o_SCT_signature
++ * and o2i_SCT_signature conform to the i2d/d2i conventions.
++ */
++
++/*
++* Serialize (to TLS format) an |sct| signature and write it to |out|.
++* If |out| is null, no signature will be output but the length will be returned.
++* If |out| points to a null pointer, a string will be allocated to hold the
++* TLS-format signature. It is the responsibility of the caller to free it.
++* If |out| points to an allocated string, the signature will be written to it.
++* The length of the signature in TLS format will be returned.
++*/
++__owur int i2o_SCT_signature(const SCT *sct, unsigned char **out);
++
++/*
++* Parses an SCT signature in TLS format and populates the |sct| with it.
++* |in| should be a pointer to a string containing the TLS-format signature.
++* |in| will be advanced to the end of the signature if parsing succeeds.
++* |len| should be the length of the signature in |in|.
++* Returns the number of bytes parsed, or a negative integer if an error occurs.
++* If an error occurs, the SCT's signature NID may be updated whilst the
++* signature field itself remains unset.
++*/
++__owur int o2i_SCT_signature(SCT *sct, const unsigned char **in, size_t len);
++
++/*
++ * Handlers for Certificate Transparency X509v3/OCSP extensions
++ */
++extern const X509V3_EXT_METHOD v3_ct_scts[3];
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/ct/ct_log.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/ct/ct_log.c
+new file mode 100644
+index 0000000..6db4c3e
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/ct/ct_log.c
+@@ -0,0 +1,304 @@
++/*
++ * Copyright 2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include 
++
++#include 
++#include 
++#include 
++#include 
++#include 
++
++#include "internal/cryptlib.h"
++
++/*
++ * Information about a CT log server.
++ */
++struct ctlog_st {
++    char *name;
++    uint8_t log_id[CT_V1_HASHLEN];
++    EVP_PKEY *public_key;
++};
++
++/*
++ * A store for multiple CTLOG instances.
++ * It takes ownership of any CTLOG instances added to it.
++ */
++struct ctlog_store_st {
++    STACK_OF(CTLOG) *logs;
++};
++
++/* The context when loading a CT log list from a CONF file. */
++typedef struct ctlog_store_load_ctx_st {
++    CTLOG_STORE *log_store;
++    CONF *conf;
++    size_t invalid_log_entries;
++} CTLOG_STORE_LOAD_CTX;
++
++/*
++ * Creates an empty context for loading a CT log store.
++ * It should be populated before use.
++ */
++static CTLOG_STORE_LOAD_CTX *ctlog_store_load_ctx_new();
++
++/*
++ * Deletes a CT log store load context.
++ * Does not delete any of the fields.
++ */
++static void ctlog_store_load_ctx_free(CTLOG_STORE_LOAD_CTX* ctx);
++
++static CTLOG_STORE_LOAD_CTX *ctlog_store_load_ctx_new()
++{
++    CTLOG_STORE_LOAD_CTX *ctx = OPENSSL_zalloc(sizeof(*ctx));
++
++    if (ctx == NULL)
++        CTerr(CT_F_CTLOG_STORE_LOAD_CTX_NEW, ERR_R_MALLOC_FAILURE);
++
++    return ctx;
++}
++
++static void ctlog_store_load_ctx_free(CTLOG_STORE_LOAD_CTX* ctx)
++{
++    OPENSSL_free(ctx);
++}
++
++/* Converts a log's public key into a SHA256 log ID */
++static int ct_v1_log_id_from_pkey(EVP_PKEY *pkey,
++                                  unsigned char log_id[CT_V1_HASHLEN])
++{
++    int ret = 0;
++    unsigned char *pkey_der = NULL;
++    int pkey_der_len = i2d_PUBKEY(pkey, &pkey_der);
++
++    if (pkey_der_len <= 0) {
++        CTerr(CT_F_CT_V1_LOG_ID_FROM_PKEY, CT_R_LOG_KEY_INVALID);
++        goto err;
++    }
++
++    SHA256(pkey_der, pkey_der_len, log_id);
++    ret = 1;
++err:
++    OPENSSL_free(pkey_der);
++    return ret;
++}
++
++CTLOG_STORE *CTLOG_STORE_new(void)
++{
++    CTLOG_STORE *ret = OPENSSL_zalloc(sizeof(*ret));
++
++    if (ret == NULL) {
++        CTerr(CT_F_CTLOG_STORE_NEW, ERR_R_MALLOC_FAILURE);
++        return NULL;
++    }
++
++    ret->logs = sk_CTLOG_new_null();
++    if (ret->logs == NULL)
++        goto err;
++
++    return ret;
++err:
++    OPENSSL_free(ret);
++    return NULL;
++}
++
++void CTLOG_STORE_free(CTLOG_STORE *store)
++{
++    if (store != NULL) {
++        sk_CTLOG_pop_free(store->logs, CTLOG_free);
++        OPENSSL_free(store);
++    }
++}
++
++static int ctlog_new_from_conf(CTLOG **ct_log, const CONF *conf, const char *section)
++{
++    const char *description = NCONF_get_string(conf, section, "description");
++    char *pkey_base64;
++
++    if (description == NULL) {
++        CTerr(CT_F_CTLOG_NEW_FROM_CONF, CT_R_LOG_CONF_MISSING_DESCRIPTION);
++        return 0;
++    }
++
++    pkey_base64 = NCONF_get_string(conf, section, "key");
++    if (pkey_base64 == NULL) {
++        CTerr(CT_F_CTLOG_NEW_FROM_CONF, CT_R_LOG_CONF_MISSING_KEY);
++        return 0;
++    }
++
++    return CTLOG_new_from_base64(ct_log, pkey_base64, description);
++}
++
++int CTLOG_STORE_load_default_file(CTLOG_STORE *store)
++{
++    const char *fpath = getenv(CTLOG_FILE_EVP);
++
++    if (fpath == NULL)
++      fpath = CTLOG_FILE;
++
++    return CTLOG_STORE_load_file(store, fpath);
++}
++
++/*
++ * Called by CONF_parse_list, which stops if this returns <= 0,
++ * Otherwise, one bad log entry would stop loading of any of
++ * the following log entries.
++ * It may stop parsing and returns -1 on any internal (malloc) error.
++ */
++static int ctlog_store_load_log(const char *log_name, int log_name_len,
++                                void *arg)
++{
++    CTLOG_STORE_LOAD_CTX *load_ctx = arg;
++    CTLOG *ct_log = NULL;
++    /* log_name may not be null-terminated, so fix that before using it */
++    char *tmp;
++    int ret = 0;
++
++    /* log_name will be NULL for empty list entries */
++    if (log_name == NULL)
++        return 1;
++
++    tmp = OPENSSL_strndup(log_name, log_name_len);
++    if (tmp == NULL)
++        goto mem_err;
++
++    ret = ctlog_new_from_conf(&ct_log, load_ctx->conf, tmp);
++    OPENSSL_free(tmp);
++
++    if (ret < 0) {
++        /* Propagate any internal error */
++        return ret;
++    }
++    if (ret == 0) {
++        /* If we can't load this log, record that fact and skip it */
++        ++load_ctx->invalid_log_entries;
++        return 1;
++    }
++
++    if (!sk_CTLOG_push(load_ctx->log_store->logs, ct_log)) {
++        goto mem_err;
++    }
++    return 1;
++
++mem_err:
++    CTLOG_free(ct_log);
++    CTerr(CT_F_CTLOG_STORE_LOAD_LOG, ERR_R_MALLOC_FAILURE);
++    return -1;
++}
++
++int CTLOG_STORE_load_file(CTLOG_STORE *store, const char *file)
++{
++    int ret = 0;
++    char *enabled_logs;
++    CTLOG_STORE_LOAD_CTX* load_ctx = ctlog_store_load_ctx_new();
++
++    load_ctx->log_store = store;
++    load_ctx->conf = NCONF_new(NULL);
++    if (load_ctx->conf == NULL)
++        goto end;
++
++    if (NCONF_load(load_ctx->conf, file, NULL) <= 0) {
++        CTerr(CT_F_CTLOG_STORE_LOAD_FILE, CT_R_LOG_CONF_INVALID);
++        goto end;
++    }
++
++    enabled_logs = NCONF_get_string(load_ctx->conf, NULL, "enabled_logs");
++    if (enabled_logs == NULL) {
++        CTerr(CT_F_CTLOG_STORE_LOAD_FILE, CT_R_LOG_CONF_INVALID);
++        goto end;
++    }
++
++    if (!CONF_parse_list(enabled_logs, ',', 1, ctlog_store_load_log, load_ctx) ||
++        load_ctx->invalid_log_entries > 0) {
++        CTerr(CT_F_CTLOG_STORE_LOAD_FILE, CT_R_LOG_CONF_INVALID);
++        goto end;
++    }
++
++    ret = 1;
++end:
++    NCONF_free(load_ctx->conf);
++    ctlog_store_load_ctx_free(load_ctx);
++    return ret;
++}
++
++/*
++ * Initialize a new CTLOG object.
++ * Takes ownership of the public key.
++ * Copies the name.
++ */
++CTLOG *CTLOG_new(EVP_PKEY *public_key, const char *name)
++{
++    CTLOG *ret = OPENSSL_zalloc(sizeof(*ret));
++
++    if (ret == NULL) {
++        CTerr(CT_F_CTLOG_NEW, ERR_R_MALLOC_FAILURE);
++        return NULL;
++    }
++
++    ret->name = OPENSSL_strdup(name);
++    if (ret->name == NULL) {
++        CTerr(CT_F_CTLOG_NEW, ERR_R_MALLOC_FAILURE);
++        goto err;
++    }
++
++    if (ct_v1_log_id_from_pkey(public_key, ret->log_id) != 1)
++        goto err;
++
++    ret->public_key = public_key;
++    return ret;
++err:
++    CTLOG_free(ret);
++    return NULL;
++}
++
++/* Frees CT log and associated structures */
++void CTLOG_free(CTLOG *log)
++{
++    if (log != NULL) {
++        OPENSSL_free(log->name);
++        EVP_PKEY_free(log->public_key);
++        OPENSSL_free(log);
++    }
++}
++
++const char *CTLOG_get0_name(const CTLOG *log)
++{
++    return log->name;
++}
++
++void CTLOG_get0_log_id(const CTLOG *log, const uint8_t **log_id,
++                       size_t *log_id_len)
++{
++    *log_id = log->log_id;
++    *log_id_len = CT_V1_HASHLEN;
++}
++
++EVP_PKEY *CTLOG_get0_public_key(const CTLOG *log)
++{
++    return log->public_key;
++}
++
++/*
++ * Given a log ID, finds the matching log.
++ * Returns NULL if no match found.
++ */
++const CTLOG *CTLOG_STORE_get0_log_by_id(const CTLOG_STORE *store,
++                                        const uint8_t *log_id,
++                                        size_t log_id_len)
++{
++    int i;
++
++    for (i = 0; i < sk_CTLOG_num(store->logs); ++i) {
++        const CTLOG *log = sk_CTLOG_value(store->logs, i);
++        if (memcmp(log->log_id, log_id, log_id_len) == 0)
++            return log;
++    }
++
++    return NULL;
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/ct/ct_oct.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/ct/ct_oct.c
+new file mode 100644
+index 0000000..0dd691c
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/ct/ct_oct.c
+@@ -0,0 +1,407 @@
++/*
++ * Copyright 2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#ifdef OPENSSL_NO_CT
++# error "CT is disabled"
++#endif
++
++#include 
++#include 
++
++#include 
++#include 
++#include 
++#include 
++
++#include "ct_locl.h"
++
++int o2i_SCT_signature(SCT *sct, const unsigned char **in, size_t len)
++{
++    size_t siglen;
++    size_t len_remaining = len;
++    const unsigned char *p;
++
++    if (sct->version != SCT_VERSION_V1) {
++        CTerr(CT_F_O2I_SCT_SIGNATURE, CT_R_UNSUPPORTED_VERSION);
++        return -1;
++    }
++    /*
++     * digitally-signed struct header: (1 byte) Hash algorithm (1 byte)
++     * Signature algorithm (2 bytes + ?) Signature
++     *
++     * This explicitly rejects empty signatures: they're invalid for
++     * all supported algorithms.
++     */
++    if (len <= 4) {
++        CTerr(CT_F_O2I_SCT_SIGNATURE, CT_R_SCT_INVALID_SIGNATURE);
++        return -1;
++    }
++
++    p = *in;
++    /* Get hash and signature algorithm */
++    sct->hash_alg = *p++;
++    sct->sig_alg = *p++;
++    if (SCT_get_signature_nid(sct) == NID_undef) {
++        CTerr(CT_F_O2I_SCT_SIGNATURE, CT_R_SCT_INVALID_SIGNATURE);
++        return -1;
++    }
++    /* Retrieve signature and check it is consistent with the buffer length */
++    n2s(p, siglen);
++    len_remaining -= (p - *in);
++    if (siglen > len_remaining) {
++        CTerr(CT_F_O2I_SCT_SIGNATURE, CT_R_SCT_INVALID_SIGNATURE);
++        return -1;
++    }
++
++    if (SCT_set1_signature(sct, p, siglen) != 1)
++        return -1;
++    len_remaining -= siglen;
++    *in = p + siglen;
++
++    return len - len_remaining;
++}
++
++SCT *o2i_SCT(SCT **psct, const unsigned char **in, size_t len)
++{
++    SCT *sct = NULL;
++    const unsigned char *p;
++
++    if (len == 0 || len > MAX_SCT_SIZE) {
++        CTerr(CT_F_O2I_SCT, CT_R_SCT_INVALID);
++        goto err;
++    }
++
++    if ((sct = SCT_new()) == NULL)
++        goto err;
++
++    p = *in;
++
++    sct->version = *p;
++    if (sct->version == SCT_VERSION_V1) {
++        int sig_len;
++        size_t len2;
++        /*-
++         * Fixed-length header:
++         *   struct {
++         *     Version sct_version;     (1 byte)
++         *     log_id id;               (32 bytes)
++         *     uint64 timestamp;        (8 bytes)
++         *     CtExtensions extensions; (2 bytes + ?)
++         *   }
++         */
++        if (len < 43) {
++            CTerr(CT_F_O2I_SCT, CT_R_SCT_INVALID);
++            goto err;
++        }
++        len -= 43;
++        p++;
++        sct->log_id = BUF_memdup(p, CT_V1_HASHLEN);
++        if (sct->log_id == NULL)
++            goto err;
++        sct->log_id_len = CT_V1_HASHLEN;
++        p += CT_V1_HASHLEN;
++
++        n2l8(p, sct->timestamp);
++
++        n2s(p, len2);
++        if (len < len2) {
++            CTerr(CT_F_O2I_SCT, CT_R_SCT_INVALID);
++            goto err;
++        }
++        if (len2 > 0) {
++            sct->ext = BUF_memdup(p, len2);
++            if (sct->ext == NULL)
++                goto err;
++        }
++        sct->ext_len = len2;
++        p += len2;
++        len -= len2;
++
++        sig_len = o2i_SCT_signature(sct, &p, len);
++        if (sig_len <= 0) {
++            CTerr(CT_F_O2I_SCT, CT_R_SCT_INVALID);
++            goto err;
++        }
++        len -= sig_len;
++        *in = p + len;
++    } else {
++        /* If not V1 just cache encoding */
++        sct->sct = BUF_memdup(p, len);
++        if (sct->sct == NULL)
++            goto err;
++        sct->sct_len = len;
++        *in = p + len;
++    }
++
++    if (psct != NULL) {
++        SCT_free(*psct);
++        *psct = sct;
++    }
++
++    return sct;
++err:
++    SCT_free(sct);
++    return NULL;
++}
++
++int i2o_SCT_signature(const SCT *sct, unsigned char **out)
++{
++    size_t len;
++    unsigned char *p = NULL, *pstart = NULL;
++
++    if (!SCT_signature_is_complete(sct)) {
++        CTerr(CT_F_I2O_SCT_SIGNATURE, CT_R_SCT_INVALID_SIGNATURE);
++        goto err;
++    }
++
++    if (sct->version != SCT_VERSION_V1) {
++        CTerr(CT_F_I2O_SCT_SIGNATURE, CT_R_UNSUPPORTED_VERSION);
++        goto err;
++    }
++
++    /*
++    * (1 byte) Hash algorithm
++    * (1 byte) Signature algorithm
++    * (2 bytes + ?) Signature
++    */
++    len = 4 + sct->sig_len;
++
++    if (out != NULL) {
++        if (*out != NULL) {
++            p = *out;
++            *out += len;
++        } else {
++            pstart = p = OPENSSL_malloc(len);
++            if (p == NULL) {
++                CTerr(CT_F_I2O_SCT_SIGNATURE, ERR_R_MALLOC_FAILURE);
++                goto err;
++            }
++            *out = p;
++        }
++
++        *p++ = sct->hash_alg;
++        *p++ = sct->sig_alg;
++        s2n(sct->sig_len, p);
++        memcpy(p, sct->sig, sct->sig_len);
++    }
++
++    return len;
++err:
++    OPENSSL_free(pstart);
++    return -1;
++}
++
++int i2o_SCT(const SCT *sct, unsigned char **out)
++{
++    size_t len;
++    unsigned char *p = NULL, *pstart = NULL;
++
++    if (!SCT_is_complete(sct)) {
++        CTerr(CT_F_I2O_SCT, CT_R_SCT_NOT_SET);
++        goto err;
++    }
++    /*
++     * Fixed-length header: struct { (1 byte) Version sct_version; (32 bytes)
++     * log_id id; (8 bytes) uint64 timestamp; (2 bytes + ?) CtExtensions
++     * extensions; (1 byte) Hash algorithm (1 byte) Signature algorithm (2
++     * bytes + ?) Signature
++     */
++    if (sct->version == SCT_VERSION_V1)
++        len = 43 + sct->ext_len + 4 + sct->sig_len;
++    else
++        len = sct->sct_len;
++
++    if (out == NULL)
++        return len;
++
++    if (*out != NULL) {
++        p = *out;
++        *out += len;
++    } else {
++        pstart = p = OPENSSL_malloc(len);
++        if (p == NULL) {
++            CTerr(CT_F_I2O_SCT, ERR_R_MALLOC_FAILURE);
++            goto err;
++        }
++        *out = p;
++    }
++
++    if (sct->version == SCT_VERSION_V1) {
++        *p++ = sct->version;
++        memcpy(p, sct->log_id, CT_V1_HASHLEN);
++        p += CT_V1_HASHLEN;
++        l2n8(sct->timestamp, p);
++        s2n(sct->ext_len, p);
++        if (sct->ext_len > 0) {
++            memcpy(p, sct->ext, sct->ext_len);
++            p += sct->ext_len;
++        }
++        if (i2o_SCT_signature(sct, &p) <= 0)
++            goto err;
++    } else {
++        memcpy(p, sct->sct, len);
++    }
++
++    return len;
++err:
++    OPENSSL_free(pstart);
++    return -1;
++}
++
++STACK_OF(SCT) *o2i_SCT_LIST(STACK_OF(SCT) **a, const unsigned char **pp,
++                            size_t len)
++{
++    STACK_OF(SCT) *sk = NULL;
++    size_t list_len, sct_len;
++
++    if (len < 2 || len > MAX_SCT_LIST_SIZE) {
++        CTerr(CT_F_O2I_SCT_LIST, CT_R_SCT_LIST_INVALID);
++        return NULL;
++    }
++
++    n2s(*pp, list_len);
++    if (list_len != len - 2) {
++        CTerr(CT_F_O2I_SCT_LIST, CT_R_SCT_LIST_INVALID);
++        return NULL;
++    }
++
++    if (a == NULL || *a == NULL) {
++        sk = sk_SCT_new_null();
++        if (sk == NULL)
++            return NULL;
++    } else {
++        SCT *sct;
++
++        /* Use the given stack, but empty it first. */
++        sk = *a;
++        while ((sct = sk_SCT_pop(sk)) != NULL)
++            SCT_free(sct);
++    }
++
++    while (list_len > 0) {
++        SCT *sct;
++
++        if (list_len < 2) {
++            CTerr(CT_F_O2I_SCT_LIST, CT_R_SCT_LIST_INVALID);
++            goto err;
++        }
++        n2s(*pp, sct_len);
++        list_len -= 2;
++
++        if (sct_len == 0 || sct_len > list_len) {
++            CTerr(CT_F_O2I_SCT_LIST, CT_R_SCT_LIST_INVALID);
++            goto err;
++        }
++        list_len -= sct_len;
++
++        if ((sct = o2i_SCT(NULL, pp, sct_len)) == NULL)
++            goto err;
++        if (!sk_SCT_push(sk, sct)) {
++            SCT_free(sct);
++            goto err;
++        }
++    }
++
++    if (a != NULL && *a == NULL)
++        *a = sk;
++    return sk;
++
++ err:
++    if (a == NULL || *a == NULL)
++        SCT_LIST_free(sk);
++    return NULL;
++}
++
++int i2o_SCT_LIST(const STACK_OF(SCT) *a, unsigned char **pp)
++{
++    int len, sct_len, i, is_pp_new = 0;
++    size_t len2;
++    unsigned char *p = NULL, *p2;
++
++    if (pp != NULL) {
++        if (*pp == NULL) {
++            if ((len = i2o_SCT_LIST(a, NULL)) == -1) {
++                CTerr(CT_F_I2O_SCT_LIST, CT_R_SCT_LIST_INVALID);
++                return -1;
++            }
++            if ((*pp = OPENSSL_malloc(len)) == NULL) {
++                CTerr(CT_F_I2O_SCT_LIST, ERR_R_MALLOC_FAILURE);
++                return -1;
++            }
++            is_pp_new = 1;
++        }
++        p = *pp + 2;
++    }
++
++    len2 = 2;
++    for (i = 0; i < sk_SCT_num(a); i++) {
++        if (pp != NULL) {
++            p2 = p;
++            p += 2;
++            if ((sct_len = i2o_SCT(sk_SCT_value(a, i), &p)) == -1)
++                goto err;
++            s2n(sct_len, p2);
++        } else {
++          if ((sct_len = i2o_SCT(sk_SCT_value(a, i), NULL)) == -1)
++              goto err;
++        }
++        len2 += 2 + sct_len;
++    }
++
++    if (len2 > MAX_SCT_LIST_SIZE)
++        goto err;
++
++    if (pp != NULL) {
++        p = *pp;
++        s2n(len2 - 2, p);
++        if (!is_pp_new)
++            *pp += len2;
++    }
++    return len2;
++
++ err:
++    if (is_pp_new) {
++        OPENSSL_free(*pp);
++        *pp = NULL;
++    }
++    return -1;
++}
++
++STACK_OF(SCT) *d2i_SCT_LIST(STACK_OF(SCT) **a, const unsigned char **pp,
++                            long len)
++{
++    ASN1_OCTET_STRING *oct = NULL;
++    STACK_OF(SCT) *sk = NULL;
++    const unsigned char *p;
++
++    p = *pp;
++    if (d2i_ASN1_OCTET_STRING(&oct, &p, len) == NULL)
++        return NULL;
++
++    p = oct->data;
++    if ((sk = o2i_SCT_LIST(a, &p, oct->length)) != NULL)
++        *pp += len;
++
++    ASN1_OCTET_STRING_free(oct);
++    return sk;
++}
++
++int i2d_SCT_LIST(const STACK_OF(SCT) *a, unsigned char **out)
++{
++    ASN1_OCTET_STRING oct;
++    int len;
++
++    oct.data = NULL;
++    if ((oct.length = i2o_SCT_LIST(a, &oct.data)) == -1)
++        return -1;
++
++    len = i2d_ASN1_OCTET_STRING(&oct, out);
++    OPENSSL_free(oct.data);
++    return len;
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/ct/ct_policy.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/ct/ct_policy.c
+new file mode 100644
+index 0000000..0d7b346
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/ct/ct_policy.c
+@@ -0,0 +1,98 @@
++/*
++ * Copyright 2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#ifdef OPENSSL_NO_CT
++# error "CT is disabled"
++#endif
++
++#include 
++#include 
++#include 
++
++#include "ct_locl.h"
++
++/*
++ * Number of seconds in the future that an SCT timestamp can be, by default,
++ * without being considered invalid. This is added to time() when setting a
++ * default value for CT_POLICY_EVAL_CTX.epoch_time_in_ms.
++ * It can be overridden by calling CT_POLICY_EVAL_CTX_set_time().
++ */
++static const time_t SCT_CLOCK_DRIFT_TOLERANCE = 300;
++
++CT_POLICY_EVAL_CTX *CT_POLICY_EVAL_CTX_new(void)
++{
++    CT_POLICY_EVAL_CTX *ctx = OPENSSL_zalloc(sizeof(CT_POLICY_EVAL_CTX));
++
++    if (ctx == NULL) {
++        CTerr(CT_F_CT_POLICY_EVAL_CTX_NEW, ERR_R_MALLOC_FAILURE);
++        return NULL;
++    }
++
++    /* time(NULL) shouldn't ever fail, so don't bother checking for -1. */
++    ctx->epoch_time_in_ms = (uint64_t)(time(NULL) + SCT_CLOCK_DRIFT_TOLERANCE) *
++            1000;
++
++    return ctx;
++}
++
++void CT_POLICY_EVAL_CTX_free(CT_POLICY_EVAL_CTX *ctx)
++{
++    if (ctx == NULL)
++        return;
++    X509_free(ctx->cert);
++    X509_free(ctx->issuer);
++    OPENSSL_free(ctx);
++}
++
++int CT_POLICY_EVAL_CTX_set1_cert(CT_POLICY_EVAL_CTX *ctx, X509 *cert)
++{
++    if (!X509_up_ref(cert))
++        return 0;
++    ctx->cert = cert;
++    return 1;
++}
++
++int CT_POLICY_EVAL_CTX_set1_issuer(CT_POLICY_EVAL_CTX *ctx, X509 *issuer)
++{
++    if (!X509_up_ref(issuer))
++        return 0;
++    ctx->issuer = issuer;
++    return 1;
++}
++
++void CT_POLICY_EVAL_CTX_set_shared_CTLOG_STORE(CT_POLICY_EVAL_CTX *ctx,
++                                               CTLOG_STORE *log_store)
++{
++    ctx->log_store = log_store;
++}
++
++void CT_POLICY_EVAL_CTX_set_time(CT_POLICY_EVAL_CTX *ctx, uint64_t time_in_ms)
++{
++    ctx->epoch_time_in_ms = time_in_ms;
++}
++
++X509* CT_POLICY_EVAL_CTX_get0_cert(const CT_POLICY_EVAL_CTX *ctx)
++{
++    return ctx->cert;
++}
++
++X509* CT_POLICY_EVAL_CTX_get0_issuer(const CT_POLICY_EVAL_CTX *ctx)
++{
++    return ctx->issuer;
++}
++
++const CTLOG_STORE *CT_POLICY_EVAL_CTX_get0_log_store(const CT_POLICY_EVAL_CTX *ctx)
++{
++    return ctx->log_store;
++}
++
++uint64_t CT_POLICY_EVAL_CTX_get_time(const CT_POLICY_EVAL_CTX *ctx)
++{
++    return ctx->epoch_time_in_ms;
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/ct/ct_prn.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/ct/ct_prn.c
+new file mode 100644
+index 0000000..376e045
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/ct/ct_prn.c
+@@ -0,0 +1,127 @@
++/*
++ * Copyright 2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#ifdef OPENSSL_NO_CT
++# error "CT is disabled"
++#endif
++
++#include 
++#include 
++
++#include "ct_locl.h"
++
++static void SCT_signature_algorithms_print(const SCT *sct, BIO *out)
++{
++    int nid = SCT_get_signature_nid(sct);
++
++    if (nid == NID_undef)
++        BIO_printf(out, "%02X%02X", sct->hash_alg, sct->sig_alg);
++    else
++        BIO_printf(out, "%s", OBJ_nid2ln(nid));
++}
++
++static void timestamp_print(uint64_t timestamp, BIO *out)
++{
++    ASN1_GENERALIZEDTIME *gen = ASN1_GENERALIZEDTIME_new();
++    char genstr[20];
++
++    if (gen == NULL)
++        return;
++    ASN1_GENERALIZEDTIME_adj(gen, (time_t)0,
++                             (int)(timestamp / 86400000),
++                             (timestamp % 86400000) / 1000);
++    /*
++     * Note GeneralizedTime from ASN1_GENERALIZETIME_adj is always 15
++     * characters long with a final Z. Update it with fractional seconds.
++     */
++    BIO_snprintf(genstr, sizeof(genstr), "%.14s.%03dZ",
++                 ASN1_STRING_get0_data(gen), (unsigned int)(timestamp % 1000));
++    if (ASN1_GENERALIZEDTIME_set_string(gen, genstr))
++        ASN1_GENERALIZEDTIME_print(out, gen);
++    ASN1_GENERALIZEDTIME_free(gen);
++}
++
++const char *SCT_validation_status_string(const SCT *sct)
++{
++
++    switch (SCT_get_validation_status(sct)) {
++    case SCT_VALIDATION_STATUS_NOT_SET:
++        return "not set";
++    case SCT_VALIDATION_STATUS_UNKNOWN_VERSION:
++        return "unknown version";
++    case SCT_VALIDATION_STATUS_UNKNOWN_LOG:
++        return "unknown log";
++    case SCT_VALIDATION_STATUS_UNVERIFIED:
++        return "unverified";
++    case SCT_VALIDATION_STATUS_INVALID:
++        return "invalid";
++    case SCT_VALIDATION_STATUS_VALID:
++        return "valid";
++    }
++    return "unknown status";
++}
++
++void SCT_print(const SCT *sct, BIO *out, int indent,
++               const CTLOG_STORE *log_store)
++{
++    const CTLOG *log = NULL;
++
++    if (log_store != NULL) {
++        log = CTLOG_STORE_get0_log_by_id(log_store, sct->log_id,
++                                         sct->log_id_len);
++    }
++
++    BIO_printf(out, "%*sSigned Certificate Timestamp:", indent, "");
++    BIO_printf(out, "\n%*sVersion   : ", indent + 4, "");
++
++    if (sct->version != SCT_VERSION_V1) {
++        BIO_printf(out, "unknown\n%*s", indent + 16, "");
++        BIO_hex_string(out, indent + 16, 16, sct->sct, sct->sct_len);
++        return;
++    }
++
++    BIO_printf(out, "v1 (0x0)");
++
++    if (log != NULL) {
++        BIO_printf(out, "\n%*sLog       : %s", indent + 4, "",
++                   CTLOG_get0_name(log));
++    }
++
++    BIO_printf(out, "\n%*sLog ID    : ", indent + 4, "");
++    BIO_hex_string(out, indent + 16, 16, sct->log_id, sct->log_id_len);
++
++    BIO_printf(out, "\n%*sTimestamp : ", indent + 4, "");
++    timestamp_print(sct->timestamp, out);
++
++    BIO_printf(out, "\n%*sExtensions: ", indent + 4, "");
++    if (sct->ext_len == 0)
++        BIO_printf(out, "none");
++    else
++        BIO_hex_string(out, indent + 16, 16, sct->ext, sct->ext_len);
++
++    BIO_printf(out, "\n%*sSignature : ", indent + 4, "");
++    SCT_signature_algorithms_print(sct, out);
++    BIO_printf(out, "\n%*s            ", indent + 4, "");
++    BIO_hex_string(out, indent + 16, 16, sct->sig, sct->sig_len);
++}
++
++void SCT_LIST_print(const STACK_OF(SCT) *sct_list, BIO *out, int indent,
++                    const char *separator, const CTLOG_STORE *log_store)
++{
++    int sct_count = sk_SCT_num(sct_list);
++    int i;
++
++    for (i = 0; i < sct_count; ++i) {
++        SCT *sct = sk_SCT_value(sct_list, i);
++
++        SCT_print(sct, out, indent, log_store);
++        if (i < sk_SCT_num(sct_list) - 1)
++            BIO_printf(out, "%s", separator);
++    }
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/ct/ct_sct.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/ct/ct_sct.c
+new file mode 100644
+index 0000000..cd2cf60
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/ct/ct_sct.c
+@@ -0,0 +1,393 @@
++/*
++ * Copyright 2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#ifdef OPENSSL_NO_CT
++# error "CT disabled"
++#endif
++
++#include 
++#include 
++#include 
++#include 
++#include 
++
++#include "ct_locl.h"
++
++SCT *SCT_new(void)
++{
++    SCT *sct = OPENSSL_zalloc(sizeof(*sct));
++
++    if (sct == NULL) {
++        CTerr(CT_F_SCT_NEW, ERR_R_MALLOC_FAILURE);
++        return NULL;
++    }
++
++    sct->entry_type = CT_LOG_ENTRY_TYPE_NOT_SET;
++    sct->version = SCT_VERSION_NOT_SET;
++    return sct;
++}
++
++void SCT_free(SCT *sct)
++{
++    if (sct == NULL)
++        return;
++
++    OPENSSL_free(sct->log_id);
++    OPENSSL_free(sct->ext);
++    OPENSSL_free(sct->sig);
++    OPENSSL_free(sct->sct);
++    OPENSSL_free(sct);
++}
++
++void SCT_LIST_free(STACK_OF(SCT) *a)
++{
++    sk_SCT_pop_free(a, SCT_free);
++}
++
++int SCT_set_version(SCT *sct, sct_version_t version)
++{
++    if (version != SCT_VERSION_V1) {
++        CTerr(CT_F_SCT_SET_VERSION, CT_R_UNSUPPORTED_VERSION);
++        return 0;
++    }
++    sct->version = version;
++    sct->validation_status = SCT_VALIDATION_STATUS_NOT_SET;
++    return 1;
++}
++
++int SCT_set_log_entry_type(SCT *sct, ct_log_entry_type_t entry_type)
++{
++    sct->validation_status = SCT_VALIDATION_STATUS_NOT_SET;
++
++    switch (entry_type) {
++    case CT_LOG_ENTRY_TYPE_X509:
++    case CT_LOG_ENTRY_TYPE_PRECERT:
++        sct->entry_type = entry_type;
++        return 1;
++    default:
++        CTerr(CT_F_SCT_SET_LOG_ENTRY_TYPE, CT_R_UNSUPPORTED_ENTRY_TYPE);
++        return 0;
++    }
++}
++
++int SCT_set0_log_id(SCT *sct, unsigned char *log_id, size_t log_id_len)
++{
++    if (sct->version == SCT_VERSION_V1 && log_id_len != CT_V1_HASHLEN) {
++        CTerr(CT_F_SCT_SET0_LOG_ID, CT_R_INVALID_LOG_ID_LENGTH);
++        return 0;
++    }
++
++    OPENSSL_free(sct->log_id);
++    sct->log_id = log_id;
++    sct->log_id_len = log_id_len;
++    sct->validation_status = SCT_VALIDATION_STATUS_NOT_SET;
++    return 1;
++}
++
++int SCT_set1_log_id(SCT *sct, const unsigned char *log_id, size_t log_id_len)
++{
++    if (sct->version == SCT_VERSION_V1 && log_id_len != CT_V1_HASHLEN) {
++        CTerr(CT_F_SCT_SET1_LOG_ID, CT_R_INVALID_LOG_ID_LENGTH);
++        return 0;
++    }
++
++    OPENSSL_free(sct->log_id);
++    sct->log_id = NULL;
++    sct->log_id_len = 0;
++    sct->validation_status = SCT_VALIDATION_STATUS_NOT_SET;
++
++    if (log_id != NULL && log_id_len > 0) {
++        sct->log_id = OPENSSL_memdup(log_id, log_id_len);
++        if (sct->log_id == NULL) {
++            CTerr(CT_F_SCT_SET1_LOG_ID, ERR_R_MALLOC_FAILURE);
++            return 0;
++        }
++        sct->log_id_len = log_id_len;
++    }
++    return 1;
++}
++
++
++void SCT_set_timestamp(SCT *sct, uint64_t timestamp)
++{
++    sct->timestamp = timestamp;
++    sct->validation_status = SCT_VALIDATION_STATUS_NOT_SET;
++}
++
++int SCT_set_signature_nid(SCT *sct, int nid)
++{
++    switch (nid) {
++    case NID_sha256WithRSAEncryption:
++        sct->hash_alg = TLSEXT_hash_sha256;
++        sct->sig_alg = TLSEXT_signature_rsa;
++        sct->validation_status = SCT_VALIDATION_STATUS_NOT_SET;
++        return 1;
++    case NID_ecdsa_with_SHA256:
++        sct->hash_alg = TLSEXT_hash_sha256;
++        sct->sig_alg = TLSEXT_signature_ecdsa;
++        sct->validation_status = SCT_VALIDATION_STATUS_NOT_SET;
++        return 1;
++    default:
++        CTerr(CT_F_SCT_SET_SIGNATURE_NID, CT_R_UNRECOGNIZED_SIGNATURE_NID);
++        return 0;
++    }
++}
++
++void SCT_set0_extensions(SCT *sct, unsigned char *ext, size_t ext_len)
++{
++    OPENSSL_free(sct->ext);
++    sct->ext = ext;
++    sct->ext_len = ext_len;
++    sct->validation_status = SCT_VALIDATION_STATUS_NOT_SET;
++}
++
++int SCT_set1_extensions(SCT *sct, const unsigned char *ext, size_t ext_len)
++{
++    OPENSSL_free(sct->ext);
++    sct->ext = NULL;
++    sct->ext_len = 0;
++    sct->validation_status = SCT_VALIDATION_STATUS_NOT_SET;
++
++    if (ext != NULL && ext_len > 0) {
++        sct->ext = OPENSSL_memdup(ext, ext_len);
++        if (sct->ext == NULL) {
++            CTerr(CT_F_SCT_SET1_EXTENSIONS, ERR_R_MALLOC_FAILURE);
++            return 0;
++        }
++        sct->ext_len = ext_len;
++    }
++    return 1;
++}
++
++void SCT_set0_signature(SCT *sct, unsigned char *sig, size_t sig_len)
++{
++    OPENSSL_free(sct->sig);
++    sct->sig = sig;
++    sct->sig_len = sig_len;
++    sct->validation_status = SCT_VALIDATION_STATUS_NOT_SET;
++}
++
++int SCT_set1_signature(SCT *sct, const unsigned char *sig, size_t sig_len)
++{
++    OPENSSL_free(sct->sig);
++    sct->sig = NULL;
++    sct->sig_len = 0;
++    sct->validation_status = SCT_VALIDATION_STATUS_NOT_SET;
++
++    if (sig != NULL && sig_len > 0) {
++        sct->sig = OPENSSL_memdup(sig, sig_len);
++        if (sct->sig == NULL) {
++            CTerr(CT_F_SCT_SET1_SIGNATURE, ERR_R_MALLOC_FAILURE);
++            return 0;
++        }
++        sct->sig_len = sig_len;
++    }
++    return 1;
++}
++
++sct_version_t SCT_get_version(const SCT *sct)
++{
++    return sct->version;
++}
++
++ct_log_entry_type_t SCT_get_log_entry_type(const SCT *sct)
++{
++    return sct->entry_type;
++}
++
++size_t SCT_get0_log_id(const SCT *sct, unsigned char **log_id)
++{
++    *log_id = sct->log_id;
++    return sct->log_id_len;
++}
++
++uint64_t SCT_get_timestamp(const SCT *sct)
++{
++    return sct->timestamp;
++}
++
++int SCT_get_signature_nid(const SCT *sct)
++{
++    if (sct->version == SCT_VERSION_V1) {
++        if (sct->hash_alg == TLSEXT_hash_sha256) {
++            switch (sct->sig_alg) {
++            case TLSEXT_signature_ecdsa:
++                return NID_ecdsa_with_SHA256;
++            case TLSEXT_signature_rsa:
++                return NID_sha256WithRSAEncryption;
++            default:
++                return NID_undef;
++            }
++        }
++    }
++    return NID_undef;
++}
++
++size_t SCT_get0_extensions(const SCT *sct, unsigned char **ext)
++{
++    *ext = sct->ext;
++    return sct->ext_len;
++}
++
++size_t SCT_get0_signature(const SCT *sct, unsigned char **sig)
++{
++    *sig = sct->sig;
++    return sct->sig_len;
++}
++
++int SCT_is_complete(const SCT *sct)
++{
++    switch (sct->version) {
++    case SCT_VERSION_NOT_SET:
++        return 0;
++    case SCT_VERSION_V1:
++        return sct->log_id != NULL && SCT_signature_is_complete(sct);
++    default:
++        return sct->sct != NULL; /* Just need cached encoding */
++    }
++}
++
++int SCT_signature_is_complete(const SCT *sct)
++{
++    return SCT_get_signature_nid(sct) != NID_undef &&
++        sct->sig != NULL && sct->sig_len > 0;
++}
++
++sct_source_t SCT_get_source(const SCT *sct)
++{
++    return sct->source;
++}
++
++int SCT_set_source(SCT *sct, sct_source_t source)
++{
++    sct->source = source;
++    sct->validation_status = SCT_VALIDATION_STATUS_NOT_SET;
++    switch (source) {
++    case SCT_SOURCE_TLS_EXTENSION:
++    case SCT_SOURCE_OCSP_STAPLED_RESPONSE:
++        return SCT_set_log_entry_type(sct, CT_LOG_ENTRY_TYPE_X509);
++    case SCT_SOURCE_X509V3_EXTENSION:
++        return SCT_set_log_entry_type(sct, CT_LOG_ENTRY_TYPE_PRECERT);
++    default: /* if we aren't sure, leave the log entry type alone */
++        return 1;
++    }
++}
++
++sct_validation_status_t SCT_get_validation_status(const SCT *sct)
++{
++    return sct->validation_status;
++}
++
++int SCT_validate(SCT *sct, const CT_POLICY_EVAL_CTX *ctx)
++{
++    int is_sct_valid = -1;
++    SCT_CTX *sctx = NULL;
++    X509_PUBKEY *pub = NULL, *log_pkey = NULL;
++    const CTLOG *log;
++
++    /*
++     * With an unrecognized SCT version we don't know what such an SCT means,
++     * let alone validate one.  So we return validation failure (0).
++     */
++    if (sct->version != SCT_VERSION_V1) {
++        sct->validation_status = SCT_VALIDATION_STATUS_UNKNOWN_VERSION;
++        return 0;
++    }
++
++    log = CTLOG_STORE_get0_log_by_id(ctx->log_store,
++                                     sct->log_id, sct->log_id_len);
++
++    /* Similarly, an SCT from an unknown log also cannot be validated. */
++    if (log == NULL) {
++        sct->validation_status = SCT_VALIDATION_STATUS_UNKNOWN_LOG;
++        return 0;
++    }
++
++    sctx = SCT_CTX_new();
++    if (sctx == NULL)
++        goto err;
++
++    if (X509_PUBKEY_set(&log_pkey, CTLOG_get0_public_key(log)) != 1)
++        goto err;
++    if (SCT_CTX_set1_pubkey(sctx, log_pkey) != 1)
++        goto err;
++
++    if (SCT_get_log_entry_type(sct) == CT_LOG_ENTRY_TYPE_PRECERT) {
++        EVP_PKEY *issuer_pkey;
++
++        if (ctx->issuer == NULL) {
++            sct->validation_status = SCT_VALIDATION_STATUS_UNVERIFIED;
++            goto end;
++        }
++
++        issuer_pkey = X509_get0_pubkey(ctx->issuer);
++
++        if (X509_PUBKEY_set(&pub, issuer_pkey) != 1)
++            goto err;
++        if (SCT_CTX_set1_issuer_pubkey(sctx, pub) != 1)
++            goto err;
++    }
++
++    SCT_CTX_set_time(sctx, ctx->epoch_time_in_ms);
++
++    /*
++     * XXX: Potential for optimization.  This repeats some idempotent heavy
++     * lifting on the certificate for each candidate SCT, and appears to not
++     * use any information in the SCT itself, only the certificate is
++     * processed.  So it may make more sense to to do this just once, perhaps
++     * associated with the shared (by all SCTs) policy eval ctx.
++     *
++     * XXX: Failure here is global (SCT independent) and represents either an
++     * issue with the certificate (e.g. duplicate extensions) or an out of
++     * memory condition.  When the certificate is incompatible with CT, we just
++     * mark the SCTs invalid, rather than report a failure to determine the
++     * validation status.  That way, callbacks that want to do "soft" SCT
++     * processing will not abort handshakes with false positive internal
++     * errors.  Since the function does not distinguish between certificate
++     * issues (peer's fault) and internal problems (out fault) the safe thing
++     * to do is to report a validation failure and let the callback or
++     * application decide what to do.
++     */
++    if (SCT_CTX_set1_cert(sctx, ctx->cert, NULL) != 1)
++        sct->validation_status = SCT_VALIDATION_STATUS_UNVERIFIED;
++    else
++        sct->validation_status = SCT_CTX_verify(sctx, sct) == 1 ?
++            SCT_VALIDATION_STATUS_VALID : SCT_VALIDATION_STATUS_INVALID;
++
++end:
++    is_sct_valid = sct->validation_status == SCT_VALIDATION_STATUS_VALID;
++err:
++    X509_PUBKEY_free(pub);
++    X509_PUBKEY_free(log_pkey);
++    SCT_CTX_free(sctx);
++
++    return is_sct_valid;
++}
++
++int SCT_LIST_validate(const STACK_OF(SCT) *scts, CT_POLICY_EVAL_CTX *ctx)
++{
++    int are_scts_valid = 1;
++    int sct_count = scts != NULL ? sk_SCT_num(scts) : 0;
++    int i;
++
++    for (i = 0; i < sct_count; ++i) {
++        int is_sct_valid = -1;
++        SCT *sct = sk_SCT_value(scts, i);
++
++        if (sct == NULL)
++            continue;
++
++        is_sct_valid = SCT_validate(sct, ctx);
++        if (is_sct_valid < 0)
++            return is_sct_valid;
++        are_scts_valid &= is_sct_valid;
++    }
++
++    return are_scts_valid;
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/ct/ct_sct_ctx.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/ct/ct_sct_ctx.c
+new file mode 100644
+index 0000000..75a5027
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/ct/ct_sct_ctx.c
+@@ -0,0 +1,263 @@
++/*
++ * Copyright 2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#ifdef OPENSSL_NO_CT
++# error "CT is disabled"
++#endif
++
++#include 
++#include 
++
++#include 
++#include 
++#include 
++
++#include "ct_locl.h"
++
++SCT_CTX *SCT_CTX_new(void)
++{
++    SCT_CTX *sctx = OPENSSL_zalloc(sizeof(*sctx));
++
++    if (sctx == NULL)
++        CTerr(CT_F_SCT_CTX_NEW, ERR_R_MALLOC_FAILURE);
++
++    return sctx;
++}
++
++void SCT_CTX_free(SCT_CTX *sctx)
++{
++    if (sctx == NULL)
++        return;
++    EVP_PKEY_free(sctx->pkey);
++    OPENSSL_free(sctx->pkeyhash);
++    OPENSSL_free(sctx->ihash);
++    OPENSSL_free(sctx->certder);
++    OPENSSL_free(sctx->preder);
++    OPENSSL_free(sctx);
++}
++
++/*
++ * Finds the index of the first extension with the given NID in cert.
++ * If there is more than one extension with that NID, *is_duplicated is set to
++ * 1, otherwise 0 (unless it is NULL).
++ */
++static int ct_x509_get_ext(X509 *cert, int nid, int *is_duplicated)
++{
++    int ret = X509_get_ext_by_NID(cert, nid, -1);
++
++    if (is_duplicated != NULL)
++        *is_duplicated = ret >= 0 && X509_get_ext_by_NID(cert, nid, ret) >= 0;
++
++    return ret;
++}
++
++/*
++ * Modifies a certificate by deleting extensions and copying the issuer and
++ * AKID from the presigner certificate, if necessary.
++ * Returns 1 on success, 0 otherwise.
++ */
++__owur static int ct_x509_cert_fixup(X509 *cert, X509 *presigner)
++{
++    int preidx, certidx;
++    int pre_akid_ext_is_dup, cert_akid_ext_is_dup;
++
++    if (presigner == NULL)
++        return 1;
++
++    preidx = ct_x509_get_ext(presigner, NID_authority_key_identifier,
++                             &pre_akid_ext_is_dup);
++    certidx = ct_x509_get_ext(cert, NID_authority_key_identifier,
++                              &cert_akid_ext_is_dup);
++
++    /* An error occurred whilst searching for the extension */
++    if (preidx < -1 || certidx < -1)
++        return 0;
++    /* Invalid certificate if they contain duplicate extensions */
++    if (pre_akid_ext_is_dup || cert_akid_ext_is_dup)
++        return 0;
++    /* AKID must be present in both certificate or absent in both */
++    if (preidx >= 0 && certidx == -1)
++        return 0;
++    if (preidx == -1 && certidx >= 0)
++        return 0;
++    /* Copy issuer name */
++    if (!X509_set_issuer_name(cert, X509_get_issuer_name(presigner)))
++        return 0;
++    if (preidx != -1) {
++        /* Retrieve and copy AKID encoding */
++        X509_EXTENSION *preext = X509_get_ext(presigner, preidx);
++        X509_EXTENSION *certext = X509_get_ext(cert, certidx);
++        ASN1_OCTET_STRING *preextdata;
++
++        /* Should never happen */
++        if (preext == NULL || certext == NULL)
++            return 0;
++        preextdata = X509_EXTENSION_get_data(preext);
++        if (preextdata == NULL ||
++            !X509_EXTENSION_set_data(certext, preextdata))
++            return 0;
++    }
++    return 1;
++}
++
++int SCT_CTX_set1_cert(SCT_CTX *sctx, X509 *cert, X509 *presigner)
++{
++    unsigned char *certder = NULL, *preder = NULL;
++    X509 *pretmp = NULL;
++    int certderlen = 0, prederlen = 0;
++    int idx = -1;
++    int poison_ext_is_dup, sct_ext_is_dup;
++    int poison_idx = ct_x509_get_ext(cert, NID_ct_precert_poison, &poison_ext_is_dup);
++
++    /* Duplicate poison extensions are present - error */
++    if (poison_ext_is_dup)
++        goto err;
++
++    /* If *cert doesn't have a poison extension, it isn't a precert */
++    if (poison_idx == -1) {
++        /* cert isn't a precert, so we shouldn't have a presigner */
++        if (presigner != NULL)
++            goto err;
++
++        certderlen = i2d_X509(cert, &certder);
++        if (certderlen < 0)
++            goto err;
++    }
++
++    /* See if cert has a precert SCTs extension */
++    idx = ct_x509_get_ext(cert, NID_ct_precert_scts, &sct_ext_is_dup);
++    /* Duplicate SCT extensions are present - error */
++    if (sct_ext_is_dup)
++        goto err;
++
++    if (idx >= 0 && poison_idx >= 0) {
++        /*
++         * cert can't both contain SCTs (i.e. have an SCT extension) and be a
++         * precert (i.e. have a poison extension).
++         */
++        goto err;
++    }
++
++    if (idx == -1) {
++        idx = poison_idx;
++    }
++
++    /*
++     * If either a poison or SCT extension is present, remove it before encoding
++     * cert. This, along with ct_x509_cert_fixup(), gets a TBSCertificate (see
++     * RFC5280) from cert, which is what the CT log signed when it produced the
++     * SCT.
++     */
++    if (idx >= 0) {
++        X509_EXTENSION *ext;
++
++        /* Take a copy of certificate so we don't modify passed version */
++        pretmp = X509_dup(cert);
++        if (pretmp == NULL)
++            goto err;
++
++        ext = X509_delete_ext(pretmp, idx);
++        X509_EXTENSION_free(ext);
++
++        if (!ct_x509_cert_fixup(pretmp, presigner))
++            goto err;
++
++        prederlen = i2d_re_X509_tbs(pretmp, &preder);
++        if (prederlen <= 0)
++            goto err;
++    }
++
++    X509_free(pretmp);
++
++    OPENSSL_free(sctx->certder);
++    sctx->certder = certder;
++    sctx->certderlen = certderlen;
++
++    OPENSSL_free(sctx->preder);
++    sctx->preder = preder;
++    sctx->prederlen = prederlen;
++
++    return 1;
++err:
++    OPENSSL_free(certder);
++    OPENSSL_free(preder);
++    X509_free(pretmp);
++    return 0;
++}
++
++__owur static int ct_public_key_hash(X509_PUBKEY *pkey, unsigned char **hash,
++                                     size_t *hash_len)
++{
++    int ret = 0;
++    unsigned char *md = NULL, *der = NULL;
++    int der_len;
++    unsigned int md_len;
++
++    /* Reuse buffer if possible */
++    if (*hash != NULL && *hash_len >= SHA256_DIGEST_LENGTH) {
++        md = *hash;
++    } else {
++        md = OPENSSL_malloc(SHA256_DIGEST_LENGTH);
++        if (md == NULL)
++            goto err;
++    }
++
++    /* Calculate key hash */
++    der_len = i2d_X509_PUBKEY(pkey, &der);
++    if (der_len <= 0)
++        goto err;
++
++    if (!EVP_Digest(der, der_len, md, &md_len, EVP_sha256(), NULL))
++        goto err;
++
++    if (md != *hash) {
++        OPENSSL_free(*hash);
++        *hash = md;
++        *hash_len = SHA256_DIGEST_LENGTH;
++    }
++
++    md = NULL;
++    ret = 1;
++ err:
++    OPENSSL_free(md);
++    OPENSSL_free(der);
++    return ret;
++}
++
++int SCT_CTX_set1_issuer(SCT_CTX *sctx, const X509 *issuer)
++{
++    return SCT_CTX_set1_issuer_pubkey(sctx, X509_get_X509_PUBKEY(issuer));
++}
++
++int SCT_CTX_set1_issuer_pubkey(SCT_CTX *sctx, X509_PUBKEY *pubkey)
++{
++    return ct_public_key_hash(pubkey, &sctx->ihash, &sctx->ihashlen);
++}
++
++int SCT_CTX_set1_pubkey(SCT_CTX *sctx, X509_PUBKEY *pubkey)
++{
++    EVP_PKEY *pkey = X509_PUBKEY_get(pubkey);
++
++    if (pkey == NULL)
++        return 0;
++
++    if (!ct_public_key_hash(pubkey, &sctx->pkeyhash, &sctx->pkeyhashlen)) {
++        EVP_PKEY_free(pkey);
++        return 0;
++    }
++
++    EVP_PKEY_free(sctx->pkey);
++    sctx->pkey = pkey;
++    return 1;
++}
++
++void SCT_CTX_set_time(SCT_CTX *sctx, uint64_t time_in_ms)
++{
++    sctx->epoch_time_in_ms = time_in_ms;
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/ct/ct_vfy.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/ct/ct_vfy.c
+new file mode 100644
+index 0000000..cabcf57
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/ct/ct_vfy.c
+@@ -0,0 +1,140 @@
++/*
++ * Copyright 2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++
++#include 
++#include 
++#include 
++#include 
++
++#include "ct_locl.h"
++
++typedef enum sct_signature_type_t {
++    SIGNATURE_TYPE_NOT_SET = -1,
++    SIGNATURE_TYPE_CERT_TIMESTAMP,
++    SIGNATURE_TYPE_TREE_HASH
++} SCT_SIGNATURE_TYPE;
++
++/*
++ * Update encoding for SCT signature verification/generation to supplied
++ * EVP_MD_CTX.
++ */
++static int sct_ctx_update(EVP_MD_CTX *ctx, const SCT_CTX *sctx, const SCT *sct)
++{
++    unsigned char tmpbuf[12];
++    unsigned char *p, *der;
++    size_t derlen;
++    /*+
++     * digitally-signed struct {
++     *   (1 byte) Version sct_version;
++     *   (1 byte) SignatureType signature_type = certificate_timestamp;
++     *   (8 bytes) uint64 timestamp;
++     *   (2 bytes) LogEntryType entry_type;
++     *   (? bytes) select(entry_type) {
++     *     case x509_entry: ASN.1Cert;
++     *     case precert_entry: PreCert;
++     *   } signed_entry;
++     *   (2 bytes + sct->ext_len) CtExtensions extensions;
++     * }
++     */
++    if (sct->entry_type == CT_LOG_ENTRY_TYPE_NOT_SET)
++        return 0;
++    if (sct->entry_type == CT_LOG_ENTRY_TYPE_PRECERT && sctx->ihash == NULL)
++        return 0;
++
++    p = tmpbuf;
++    *p++ = sct->version;
++    *p++ = SIGNATURE_TYPE_CERT_TIMESTAMP;
++    l2n8(sct->timestamp, p);
++    s2n(sct->entry_type, p);
++
++    if (!EVP_DigestUpdate(ctx, tmpbuf, p - tmpbuf))
++        return 0;
++
++    if (sct->entry_type == CT_LOG_ENTRY_TYPE_X509) {
++        der = sctx->certder;
++        derlen = sctx->certderlen;
++    } else {
++        if (!EVP_DigestUpdate(ctx, sctx->ihash, sctx->ihashlen))
++            return 0;
++        der = sctx->preder;
++        derlen = sctx->prederlen;
++    }
++
++    /* If no encoding available, fatal error */
++    if (der == NULL)
++        return 0;
++
++    /* Include length first */
++    p = tmpbuf;
++    l2n3(derlen, p);
++
++    if (!EVP_DigestUpdate(ctx, tmpbuf, 3))
++        return 0;
++    if (!EVP_DigestUpdate(ctx, der, derlen))
++        return 0;
++
++    /* Add any extensions */
++    p = tmpbuf;
++    s2n(sct->ext_len, p);
++    if (!EVP_DigestUpdate(ctx, tmpbuf, 2))
++        return 0;
++
++    if (sct->ext_len && !EVP_DigestUpdate(ctx, sct->ext, sct->ext_len))
++        return 0;
++
++    return 1;
++}
++
++int SCT_CTX_verify(const SCT_CTX *sctx, const SCT *sct)
++{
++    EVP_MD_CTX *ctx = NULL;
++    int ret = 0;
++
++    if (!SCT_is_complete(sct) || sctx->pkey == NULL ||
++        sct->entry_type == CT_LOG_ENTRY_TYPE_NOT_SET ||
++        (sct->entry_type == CT_LOG_ENTRY_TYPE_PRECERT && sctx->ihash == NULL)) {
++        CTerr(CT_F_SCT_CTX_VERIFY, CT_R_SCT_NOT_SET);
++        return 0;
++    }
++    if (sct->version != SCT_VERSION_V1) {
++        CTerr(CT_F_SCT_CTX_VERIFY, CT_R_SCT_UNSUPPORTED_VERSION);
++        return 0;
++    }
++    if (sct->log_id_len != sctx->pkeyhashlen ||
++        memcmp(sct->log_id, sctx->pkeyhash, sctx->pkeyhashlen) != 0) {
++        CTerr(CT_F_SCT_CTX_VERIFY, CT_R_SCT_LOG_ID_MISMATCH);
++        return 0;
++    }
++    if (sct->timestamp > sctx->epoch_time_in_ms) {
++        CTerr(CT_F_SCT_CTX_VERIFY, CT_R_SCT_FUTURE_TIMESTAMP);
++        return 0;
++    }
++
++    ctx = EVP_MD_CTX_new();
++    if (ctx == NULL)
++        goto end;
++
++    if (!EVP_DigestVerifyInit(ctx, NULL, EVP_sha256(), NULL, sctx->pkey))
++        goto end;
++
++    if (!sct_ctx_update(ctx, sctx, sct))
++        goto end;
++
++    /* Verify signature */
++    ret = EVP_DigestVerifyFinal(ctx, sct->sig, sct->sig_len);
++    /* If ret < 0 some other error: fall through without setting error */
++    if (ret == 0)
++        CTerr(CT_F_SCT_CTX_VERIFY, CT_R_SCT_INVALID_SIGNATURE);
++
++end:
++    EVP_MD_CTX_free(ctx);
++    return ret;
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/ct/ct_x509v3.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/ct/ct_x509v3.c
+new file mode 100644
+index 0000000..805ada0
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/ct/ct_x509v3.c
+@@ -0,0 +1,60 @@
++/*
++ * Copyright 2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#ifdef OPENSSL_NO_CT
++# error "CT is disabled"
++#endif
++
++#include "ct_locl.h"
++
++static char *i2s_poison(const X509V3_EXT_METHOD *method, void *val)
++{
++    return OPENSSL_strdup("NULL");
++}
++
++static void *s2i_poison(const X509V3_EXT_METHOD *method, X509V3_CTX *ctx, const char *str)
++{
++   return ASN1_NULL_new();
++}
++
++static int i2r_SCT_LIST(X509V3_EXT_METHOD *method, STACK_OF(SCT) *sct_list,
++                 BIO *out, int indent)
++{
++    SCT_LIST_print(sct_list, out, indent, "\n", NULL);
++    return 1;
++}
++
++/* Handlers for X509v3/OCSP Certificate Transparency extensions */
++const X509V3_EXT_METHOD v3_ct_scts[3] = {
++    /* X509v3 extension in certificates that contains SCTs */
++    { NID_ct_precert_scts, 0, NULL,
++    NULL, (X509V3_EXT_FREE)SCT_LIST_free,
++    (X509V3_EXT_D2I)d2i_SCT_LIST, (X509V3_EXT_I2D)i2d_SCT_LIST,
++    NULL, NULL,
++    NULL, NULL,
++    (X509V3_EXT_I2R)i2r_SCT_LIST, NULL,
++    NULL },
++
++    /* X509v3 extension to mark a certificate as a pre-certificate */
++    { NID_ct_precert_poison, 0, ASN1_ITEM_ref(ASN1_NULL),
++    NULL, NULL, NULL, NULL,
++    i2s_poison, s2i_poison,
++    NULL, NULL,
++    NULL, NULL,
++    NULL },
++
++    /* OCSP extension that contains SCTs */
++    { NID_ct_cert_scts, 0, NULL,
++    0, (X509V3_EXT_FREE)SCT_LIST_free,
++    (X509V3_EXT_D2I)d2i_SCT_LIST, (X509V3_EXT_I2D)i2d_SCT_LIST,
++    NULL, NULL,
++    NULL, NULL,
++    (X509V3_EXT_I2R)i2r_SCT_LIST, NULL,
++    NULL },
++};
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/cversion.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/cversion.c
+new file mode 100644
+index 0000000..96d8a5b
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/cversion.c
+@@ -0,0 +1,65 @@
++/*
++ * Copyright 1995-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include "internal/cryptlib.h"
++
++#ifndef NO_WINDOWS_BRAINDEATH
++# include "buildinf.h"
++#endif
++
++unsigned long OpenSSL_version_num(void)
++{
++    return OPENSSL_VERSION_NUMBER;
++}
++
++const char *OpenSSL_version(int t)
++{
++    if (t == OPENSSL_VERSION)
++        return OPENSSL_VERSION_TEXT;
++    if (t == OPENSSL_BUILT_ON) {
++#ifdef DATE
++# ifdef OPENSSL_USE_BUILD_DATE
++        return (DATE);
++# else
++        return ("built on: reproducible build, date unspecified");
++# endif
++#else
++        return ("built on: date not available");
++#endif
++    }
++    if (t == OPENSSL_CFLAGS) {
++#ifdef CFLAGS
++        return (CFLAGS);
++#else
++        return ("compiler: information not available");
++#endif
++    }
++    if (t == OPENSSL_PLATFORM) {
++#ifdef PLATFORM
++        return (PLATFORM);
++#else
++        return ("platform: information not available");
++#endif
++    }
++    if (t == OPENSSL_DIR) {
++#ifdef OPENSSLDIR
++        return "OPENSSLDIR: \"" OPENSSLDIR "\"";
++#else
++        return "OPENSSLDIR: N/A";
++#endif
++    }
++    if (t == OPENSSL_ENGINES_DIR) {
++#ifdef ENGINESDIR
++        return "ENGINESDIR: \"" ENGINESDIR "\"";
++#else
++        return "ENGINESDIR: N/A";
++#endif
++    }
++    return ("not available");
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/des/asm/crypt586.pl b/CryptoPkg/Library/OpensslLib/openssl/crypto/des/asm/crypt586.pl
+new file mode 100644
+index 0000000..d5911a1
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/des/asm/crypt586.pl
+@@ -0,0 +1,217 @@
++#! /usr/bin/env perl
++# Copyright 1995-2016 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
++# in the file LICENSE in the source distribution or at
++# https://www.openssl.org/source/license.html
++
++# The inner loop instruction sequence and the IP/FP modifications are from
++# Svend Olaf Mikkelsen 
++
++$0 =~ m/(.*[\/\\])[^\/\\]+$/; $dir=$1;
++push(@INC,"${dir}","${dir}../../perlasm");
++require "x86asm.pl";
++
++$output=pop;
++open STDOUT,">$output";
++
++&asm_init($ARGV[0],"crypt586.pl");
++
++$L="edi";
++$R="esi";
++
++&external_label("DES_SPtrans");
++&fcrypt_body("fcrypt_body");
++&asm_finish();
++
++close STDOUT;
++
++sub fcrypt_body
++	{
++	local($name,$do_ip)=@_;
++
++	&function_begin($name);
++
++	&comment("");
++	&comment("Load the 2 words");
++	$trans="ebp";
++
++	&xor(	$L,	$L);
++	&xor(	$R,	$R);
++
++	# PIC-ification:-)
++	&picmeup("edx","DES_SPtrans");
++	#if ($cpp)	{ &picmeup("edx","DES_SPtrans");   }
++	#else		{ &lea("edx",&DWP("DES_SPtrans")); }
++	&push("edx");	# becomes &swtmp(1)
++	#
++	&mov($trans,&wparam(1)); # reloaded with DES_SPtrans in D_ENCRYPT
++
++	&push(&DWC(25)); # add a variable
++
++	&set_label("start");
++	for ($i=0; $i<16; $i+=2)
++		{
++		&comment("");
++		&comment("Round $i");
++		&D_ENCRYPT($i,$L,$R,$i*2,$trans,"eax","ebx","ecx","edx");
++
++		&comment("");
++		&comment("Round ".sprintf("%d",$i+1));
++		&D_ENCRYPT($i+1,$R,$L,($i+1)*2,$trans,"eax","ebx","ecx","edx");
++		}
++	 &mov("ebx",	&swtmp(0));
++	&mov("eax",	$L);
++	 &dec("ebx");
++	&mov($L,	$R);
++	 &mov($R,	"eax");
++	&mov(&swtmp(0),	"ebx");
++	 &jnz(&label("start"));
++
++	&comment("");
++	&comment("FP");
++	&mov("edx",&wparam(0));
++
++	&FP_new($R,$L,"eax",3);
++	&mov(&DWP(0,"edx","",0),"eax");
++	&mov(&DWP(4,"edx","",0),$L);
++
++	&add("esp",8);	# remove variables
++
++	&function_end($name);
++	}
++
++sub D_ENCRYPT
++	{
++	local($r,$L,$R,$S,$trans,$u,$tmp1,$tmp2,$t)=@_;
++
++	&mov(	$u,		&wparam(2));			# 2
++	&mov(	$t,		$R);
++	&shr(	$t,		16);				# 1
++	&mov(	$tmp2,		&wparam(3));			# 2
++	&xor(	$t,		$R);				# 1
++
++	&and(	$u,		$t);				# 2
++	&and(	$t,		$tmp2);				# 2
++
++	&mov(	$tmp1,		$u);
++	&shl(	$tmp1,		16); 				# 1
++	&mov(	$tmp2,		$t);
++	&shl(	$tmp2,		16); 				# 1
++	&xor(	$u,		$tmp1);				# 2
++	&xor(	$t,		$tmp2);				# 2
++	&mov(	$tmp1,		&DWP(&n2a($S*4),$trans,"",0));	# 2
++	&xor(	$u,		$tmp1);
++	&mov(	$tmp2,		&DWP(&n2a(($S+1)*4),$trans,"",0));	# 2
++	&xor(	$u,		$R);
++	&xor(	$t,		$R);
++	&xor(	$t,		$tmp2);
++
++	&and(	$u,		"0xfcfcfcfc"	);		# 2
++	&xor(	$tmp1,		$tmp1);				# 1
++	&and(	$t,		"0xcfcfcfcf"	);		# 2
++	&xor(	$tmp2,		$tmp2);	
++	&movb(	&LB($tmp1),	&LB($u)	);
++	&movb(	&LB($tmp2),	&HB($u)	);
++	&rotr(	$t,		4		);
++	&mov(	$trans,		&swtmp(1));
++	&xor(	$L,		&DWP("     ",$trans,$tmp1,0));
++	&movb(	&LB($tmp1),	&LB($t)	);
++	&xor(	$L,		&DWP("0x200",$trans,$tmp2,0));
++	&movb(	&LB($tmp2),	&HB($t)	);
++	&shr(	$u,		16);
++	&xor(	$L,		&DWP("0x100",$trans,$tmp1,0));
++	&movb(	&LB($tmp1),	&HB($u)	);
++	&shr(	$t,		16);
++	&xor(	$L,		&DWP("0x300",$trans,$tmp2,0));
++	&movb(	&LB($tmp2),	&HB($t)	);
++	&and(	$u,		"0xff"	);
++	&and(	$t,		"0xff"	);
++	&mov(	$tmp1,		&DWP("0x600",$trans,$tmp1,0));
++	&xor(	$L,		$tmp1);
++	&mov(	$tmp1,		&DWP("0x700",$trans,$tmp2,0));
++	&xor(	$L,		$tmp1);
++	&mov(	$tmp1,		&DWP("0x400",$trans,$u,0));
++	&xor(	$L,		$tmp1);
++	&mov(	$tmp1,		&DWP("0x500",$trans,$t,0));
++	&xor(	$L,		$tmp1);
++	&mov(	$trans,		&wparam(1));
++	}
++
++sub n2a
++	{
++	sprintf("%d",$_[0]);
++	}
++
++# now has a side affect of rotating $a by $shift
++sub R_PERM_OP
++	{
++	local($a,$b,$tt,$shift,$mask,$last)=@_;
++
++	&rotl(	$a,		$shift		) if ($shift != 0);
++	&mov(	$tt,		$a		);
++	&xor(	$a,		$b		);
++	&and(	$a,		$mask		);
++	if ($notlast eq $b)
++		{
++		&xor(	$b,		$a		);
++		&xor(	$tt,		$a		);
++		}
++	else
++		{
++		&xor(	$tt,		$a		);
++		&xor(	$b,		$a		);
++		}
++	&comment("");
++	}
++
++sub IP_new
++	{
++	local($l,$r,$tt,$lr)=@_;
++
++	&R_PERM_OP($l,$r,$tt, 4,"0xf0f0f0f0",$l);
++	&R_PERM_OP($r,$tt,$l,20,"0xfff0000f",$l);
++	&R_PERM_OP($l,$tt,$r,14,"0x33333333",$r);
++	&R_PERM_OP($tt,$r,$l,22,"0x03fc03fc",$r);
++	&R_PERM_OP($l,$r,$tt, 9,"0xaaaaaaaa",$r);
++	
++	if ($lr != 3)
++		{
++		if (($lr-3) < 0)
++			{ &rotr($tt,	3-$lr); }
++		else	{ &rotl($tt,	$lr-3); }
++		}
++	if ($lr != 2)
++		{
++		if (($lr-2) < 0)
++			{ &rotr($r,	2-$lr); }
++		else	{ &rotl($r,	$lr-2); }
++		}
++	}
++
++sub FP_new
++	{
++	local($l,$r,$tt,$lr)=@_;
++
++	if ($lr != 2)
++		{
++		if (($lr-2) < 0)
++			{ &rotl($r,	2-$lr); }
++		else	{ &rotr($r,	$lr-2); }
++		}
++	if ($lr != 3)
++		{
++		if (($lr-3) < 0)
++			{ &rotl($l,	3-$lr); }
++		else	{ &rotr($l,	$lr-3); }
++		}
++
++	&R_PERM_OP($l,$r,$tt, 0,"0xaaaaaaaa",$r);
++	&R_PERM_OP($tt,$r,$l,23,"0x03fc03fc",$r);
++	&R_PERM_OP($l,$r,$tt,10,"0x33333333",$l);
++	&R_PERM_OP($r,$tt,$l,18,"0xfff0000f",$l);
++	&R_PERM_OP($l,$tt,$r,12,"0xf0f0f0f0",$r);
++	&rotr($tt	, 4);
++	}
++
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/des/asm/des-586.pl b/CryptoPkg/Library/OpensslLib/openssl/crypto/des/asm/des-586.pl
+new file mode 100644
+index 0000000..3d7c7f1
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/des/asm/des-586.pl
+@@ -0,0 +1,465 @@
++#! /usr/bin/env perl
++# Copyright 1995-2016 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
++# in the file LICENSE in the source distribution or at
++# https://www.openssl.org/source/license.html
++
++# The inner loop instruction sequence and the IP/FP modifications are from
++# Svend Olaf Mikkelsen 
++
++$0 =~ m/(.*[\/\\])[^\/\\]+$/; $dir=$1;
++push(@INC,"${dir}","${dir}../../perlasm");
++require "x86asm.pl";
++require "cbc.pl";
++require "desboth.pl";
++
++# base code is in microsft
++# op dest, source
++# format.
++#
++
++$output=pop;
++open STDOUT,">$output";
++
++&asm_init($ARGV[0],"des-586.pl");
++
++$L="edi";
++$R="esi";
++$trans="ebp";
++$small_footprint=1 if (grep(/\-DOPENSSL_SMALL_FOOTPRINT/,@ARGV));
++# one can discuss setting this variable to 1 unconditionally, as
++# the folded loop is only 3% slower than unrolled, but >7 times smaller
++
++&public_label("DES_SPtrans");
++&static_label("des_sptrans");
++
++&DES_encrypt_internal();
++&DES_decrypt_internal();
++&DES_encrypt("DES_encrypt1",1);
++&DES_encrypt("DES_encrypt2",0);
++&DES_encrypt3("DES_encrypt3",1);
++&DES_encrypt3("DES_decrypt3",0);
++&cbc("DES_ncbc_encrypt","DES_encrypt1","DES_encrypt1",0,4,5,3,5,-1);
++&cbc("DES_ede3_cbc_encrypt","DES_encrypt3","DES_decrypt3",0,6,7,3,4,5);
++&DES_SPtrans();
++
++&asm_finish();
++
++close STDOUT;
++
++sub DES_encrypt_internal()
++	{
++	&function_begin_B("_x86_DES_encrypt");
++
++	if ($small_footprint)
++	    {
++	    &lea("edx",&DWP(128,"ecx"));
++	    &push("edx");
++	    &push("ecx");
++	    &set_label("eloop");
++		&D_ENCRYPT(0,$L,$R,0,$trans,"eax","ebx","ecx","edx",&swtmp(0));
++		&comment("");
++		&D_ENCRYPT(1,$R,$L,2,$trans,"eax","ebx","ecx","edx",&swtmp(0));
++		&comment("");
++		&add("ecx",16);
++		&cmp("ecx",&swtmp(1));
++		&mov(&swtmp(0),"ecx");
++		&jb(&label("eloop"));
++	    &add("esp",8);
++	    }
++	else
++	    {
++	    &push("ecx");
++	    for ($i=0; $i<16; $i+=2)
++		{
++		&comment("Round $i");
++		&D_ENCRYPT($i,$L,$R,$i*2,$trans,"eax","ebx","ecx","edx",&swtmp(0));
++		&comment("Round ".sprintf("%d",$i+1));
++		&D_ENCRYPT($i+1,$R,$L,($i+1)*2,$trans,"eax","ebx","ecx","edx",&swtmp(0));
++		}
++	    &add("esp",4);
++	}
++	&ret();
++
++	&function_end_B("_x86_DES_encrypt");
++	}
++	
++sub DES_decrypt_internal()
++	{
++	&function_begin_B("_x86_DES_decrypt");
++
++	if ($small_footprint)
++	    {
++	    &push("ecx");
++	    &lea("ecx",&DWP(128,"ecx"));
++	    &push("ecx");
++	    &set_label("dloop");
++		&D_ENCRYPT(0,$L,$R,-2,$trans,"eax","ebx","ecx","edx",&swtmp(0));
++		&comment("");
++		&D_ENCRYPT(1,$R,$L,-4,$trans,"eax","ebx","ecx","edx",&swtmp(0));
++		&comment("");
++		&sub("ecx",16);
++		&cmp("ecx",&swtmp(1));
++		&mov(&swtmp(0),"ecx");
++		&ja(&label("dloop"));
++	    &add("esp",8);
++	    }
++	else
++	    {
++	    &push("ecx");
++	    for ($i=15; $i>0; $i-=2)
++		{
++		&comment("Round $i");
++		&D_ENCRYPT(15-$i,$L,$R,$i*2,$trans,"eax","ebx","ecx","edx",&swtmp(0));
++		&comment("Round ".sprintf("%d",$i-1));
++		&D_ENCRYPT(15-$i+1,$R,$L,($i-1)*2,$trans,"eax","ebx","ecx","edx",&swtmp(0));
++		}
++	    &add("esp",4);
++	    }
++	&ret();
++
++	&function_end_B("_x86_DES_decrypt");
++	}
++	
++sub DES_encrypt
++	{
++	local($name,$do_ip)=@_;
++
++	&function_begin_B($name);
++
++	&push("esi");
++	&push("edi");
++
++	&comment("");
++	&comment("Load the 2 words");
++
++	if ($do_ip)
++		{
++		&mov($R,&wparam(0));
++		 &xor(	"ecx",		"ecx"		);
++
++		&push("ebx");
++		&push("ebp");
++
++		&mov("eax",&DWP(0,$R,"",0));
++		 &mov("ebx",&wparam(2));	# get encrypt flag
++		&mov($L,&DWP(4,$R,"",0));
++		&comment("");
++		&comment("IP");
++		&IP_new("eax",$L,$R,3);
++		}
++	else
++		{
++		&mov("eax",&wparam(0));
++		 &xor(	"ecx",		"ecx"		);
++
++		&push("ebx");
++		&push("ebp");
++
++		&mov($R,&DWP(0,"eax","",0));
++		 &mov("ebx",&wparam(2));	# get encrypt flag
++		&rotl($R,3);
++		&mov($L,&DWP(4,"eax","",0));
++		&rotl($L,3);
++		}
++
++	# PIC-ification:-)
++	&call	(&label("pic_point"));
++	&set_label("pic_point");
++	&blindpop($trans);
++	&lea	($trans,&DWP(&label("des_sptrans")."-".&label("pic_point"),$trans));
++
++	&mov(	"ecx",	&wparam(1)	);
++
++	&cmp("ebx","0");
++	&je(&label("decrypt"));
++	&call("_x86_DES_encrypt");
++	&jmp(&label("done"));
++	&set_label("decrypt");
++	&call("_x86_DES_decrypt");
++	&set_label("done");
++
++	if ($do_ip)
++		{
++		&comment("");
++		&comment("FP");
++		&mov("edx",&wparam(0));
++		&FP_new($L,$R,"eax",3);
++
++		&mov(&DWP(0,"edx","",0),"eax");
++		&mov(&DWP(4,"edx","",0),$R);
++		}
++	else
++		{
++		&comment("");
++		&comment("Fixup");
++		&rotr($L,3);		# r
++		 &mov("eax",&wparam(0));
++		&rotr($R,3);		# l
++		 &mov(&DWP(0,"eax","",0),$L);
++		 &mov(&DWP(4,"eax","",0),$R);
++		}
++
++	&pop("ebp");
++	&pop("ebx");
++	&pop("edi");
++	&pop("esi");
++	&ret();
++
++	&function_end_B($name);
++	}
++
++sub D_ENCRYPT
++	{
++	local($r,$L,$R,$S,$trans,$u,$tmp1,$tmp2,$t,$wp1)=@_;
++
++	 &mov(	$u,		&DWP(&n2a($S*4),$tmp2,"",0));
++	&xor(	$tmp1,		$tmp1);
++	 &mov(	$t,		&DWP(&n2a(($S+1)*4),$tmp2,"",0));
++	&xor(	$u,		$R);
++	&xor(	$tmp2,		$tmp2);
++	 &xor(	$t,		$R);
++	&and(	$u,		"0xfcfcfcfc"	);
++	 &and(	$t,		"0xcfcfcfcf"	);
++	&movb(	&LB($tmp1),	&LB($u)	);
++	 &movb(	&LB($tmp2),	&HB($u)	);
++	&rotr(	$t,		4		);
++	&xor(	$L,		&DWP("     ",$trans,$tmp1,0));
++	 &movb(	&LB($tmp1),	&LB($t)	);
++	 &xor(	$L,		&DWP("0x200",$trans,$tmp2,0));
++	 &movb(	&LB($tmp2),	&HB($t)	);
++	&shr(	$u,		16);
++	 &xor(	$L,		&DWP("0x100",$trans,$tmp1,0));
++	 &movb(	&LB($tmp1),	&HB($u)	);
++	&shr(	$t,		16);
++	 &xor(	$L,		&DWP("0x300",$trans,$tmp2,0));
++	&movb(	&LB($tmp2),	&HB($t)	);
++	 &and(	$u,		"0xff"	);
++	&and(	$t,		"0xff"	);
++	 &xor(	$L,		&DWP("0x600",$trans,$tmp1,0));
++	 &xor(	$L,		&DWP("0x700",$trans,$tmp2,0));
++	&mov(	$tmp2,		$wp1	);
++	 &xor(	$L,		&DWP("0x400",$trans,$u,0));
++	 &xor(	$L,		&DWP("0x500",$trans,$t,0));
++	}
++
++sub n2a
++	{
++	sprintf("%d",$_[0]);
++	}
++
++# now has a side affect of rotating $a by $shift
++sub R_PERM_OP
++	{
++	local($a,$b,$tt,$shift,$mask,$last)=@_;
++
++	&rotl(	$a,		$shift		) if ($shift != 0);
++	&mov(	$tt,		$a		);
++	&xor(	$a,		$b		);
++	&and(	$a,		$mask		);
++	# This can never succeed, and besides it is difficult to see what the
++	# idea was - Ben 13 Feb 99
++	if (!$last eq $b)
++		{
++		&xor(	$b,		$a		);
++		&xor(	$tt,		$a		);
++		}
++	else
++		{
++		&xor(	$tt,		$a		);
++		&xor(	$b,		$a		);
++		}
++	&comment("");
++	}
++
++sub IP_new
++	{
++	local($l,$r,$tt,$lr)=@_;
++
++	&R_PERM_OP($l,$r,$tt, 4,"0xf0f0f0f0",$l);
++	&R_PERM_OP($r,$tt,$l,20,"0xfff0000f",$l);
++	&R_PERM_OP($l,$tt,$r,14,"0x33333333",$r);
++	&R_PERM_OP($tt,$r,$l,22,"0x03fc03fc",$r);
++	&R_PERM_OP($l,$r,$tt, 9,"0xaaaaaaaa",$r);
++	
++	if ($lr != 3)
++		{
++		if (($lr-3) < 0)
++			{ &rotr($tt,	3-$lr); }
++		else	{ &rotl($tt,	$lr-3); }
++		}
++	if ($lr != 2)
++		{
++		if (($lr-2) < 0)
++			{ &rotr($r,	2-$lr); }
++		else	{ &rotl($r,	$lr-2); }
++		}
++	}
++
++sub FP_new
++	{
++	local($l,$r,$tt,$lr)=@_;
++
++	if ($lr != 2)
++		{
++		if (($lr-2) < 0)
++			{ &rotl($r,	2-$lr); }
++		else	{ &rotr($r,	$lr-2); }
++		}
++	if ($lr != 3)
++		{
++		if (($lr-3) < 0)
++			{ &rotl($l,	3-$lr); }
++		else	{ &rotr($l,	$lr-3); }
++		}
++
++	&R_PERM_OP($l,$r,$tt, 0,"0xaaaaaaaa",$r);
++	&R_PERM_OP($tt,$r,$l,23,"0x03fc03fc",$r);
++	&R_PERM_OP($l,$r,$tt,10,"0x33333333",$l);
++	&R_PERM_OP($r,$tt,$l,18,"0xfff0000f",$l);
++	&R_PERM_OP($l,$tt,$r,12,"0xf0f0f0f0",$r);
++	&rotr($tt	, 4);
++	}
++
++sub DES_SPtrans
++	{
++	&set_label("DES_SPtrans",64);
++	&set_label("des_sptrans");
++	&data_word(0x02080800, 0x00080000, 0x02000002, 0x02080802);
++	&data_word(0x02000000, 0x00080802, 0x00080002, 0x02000002);
++	&data_word(0x00080802, 0x02080800, 0x02080000, 0x00000802);
++	&data_word(0x02000802, 0x02000000, 0x00000000, 0x00080002);
++	&data_word(0x00080000, 0x00000002, 0x02000800, 0x00080800);
++	&data_word(0x02080802, 0x02080000, 0x00000802, 0x02000800);
++	&data_word(0x00000002, 0x00000800, 0x00080800, 0x02080002);
++	&data_word(0x00000800, 0x02000802, 0x02080002, 0x00000000);
++	&data_word(0x00000000, 0x02080802, 0x02000800, 0x00080002);
++	&data_word(0x02080800, 0x00080000, 0x00000802, 0x02000800);
++	&data_word(0x02080002, 0x00000800, 0x00080800, 0x02000002);
++	&data_word(0x00080802, 0x00000002, 0x02000002, 0x02080000);
++	&data_word(0x02080802, 0x00080800, 0x02080000, 0x02000802);
++	&data_word(0x02000000, 0x00000802, 0x00080002, 0x00000000);
++	&data_word(0x00080000, 0x02000000, 0x02000802, 0x02080800);
++	&data_word(0x00000002, 0x02080002, 0x00000800, 0x00080802);
++	# nibble 1
++	&data_word(0x40108010, 0x00000000, 0x00108000, 0x40100000);
++	&data_word(0x40000010, 0x00008010, 0x40008000, 0x00108000);
++	&data_word(0x00008000, 0x40100010, 0x00000010, 0x40008000);
++	&data_word(0x00100010, 0x40108000, 0x40100000, 0x00000010);
++	&data_word(0x00100000, 0x40008010, 0x40100010, 0x00008000);
++	&data_word(0x00108010, 0x40000000, 0x00000000, 0x00100010);
++	&data_word(0x40008010, 0x00108010, 0x40108000, 0x40000010);
++	&data_word(0x40000000, 0x00100000, 0x00008010, 0x40108010);
++	&data_word(0x00100010, 0x40108000, 0x40008000, 0x00108010);
++	&data_word(0x40108010, 0x00100010, 0x40000010, 0x00000000);
++	&data_word(0x40000000, 0x00008010, 0x00100000, 0x40100010);
++	&data_word(0x00008000, 0x40000000, 0x00108010, 0x40008010);
++	&data_word(0x40108000, 0x00008000, 0x00000000, 0x40000010);
++	&data_word(0x00000010, 0x40108010, 0x00108000, 0x40100000);
++	&data_word(0x40100010, 0x00100000, 0x00008010, 0x40008000);
++	&data_word(0x40008010, 0x00000010, 0x40100000, 0x00108000);
++	# nibble 2
++	&data_word(0x04000001, 0x04040100, 0x00000100, 0x04000101);
++	&data_word(0x00040001, 0x04000000, 0x04000101, 0x00040100);
++	&data_word(0x04000100, 0x00040000, 0x04040000, 0x00000001);
++	&data_word(0x04040101, 0x00000101, 0x00000001, 0x04040001);
++	&data_word(0x00000000, 0x00040001, 0x04040100, 0x00000100);
++	&data_word(0x00000101, 0x04040101, 0x00040000, 0x04000001);
++	&data_word(0x04040001, 0x04000100, 0x00040101, 0x04040000);
++	&data_word(0x00040100, 0x00000000, 0x04000000, 0x00040101);
++	&data_word(0x04040100, 0x00000100, 0x00000001, 0x00040000);
++	&data_word(0x00000101, 0x00040001, 0x04040000, 0x04000101);
++	&data_word(0x00000000, 0x04040100, 0x00040100, 0x04040001);
++	&data_word(0x00040001, 0x04000000, 0x04040101, 0x00000001);
++	&data_word(0x00040101, 0x04000001, 0x04000000, 0x04040101);
++	&data_word(0x00040000, 0x04000100, 0x04000101, 0x00040100);
++	&data_word(0x04000100, 0x00000000, 0x04040001, 0x00000101);
++	&data_word(0x04000001, 0x00040101, 0x00000100, 0x04040000);
++	# nibble 3
++	&data_word(0x00401008, 0x10001000, 0x00000008, 0x10401008);
++	&data_word(0x00000000, 0x10400000, 0x10001008, 0x00400008);
++	&data_word(0x10401000, 0x10000008, 0x10000000, 0x00001008);
++	&data_word(0x10000008, 0x00401008, 0x00400000, 0x10000000);
++	&data_word(0x10400008, 0x00401000, 0x00001000, 0x00000008);
++	&data_word(0x00401000, 0x10001008, 0x10400000, 0x00001000);
++	&data_word(0x00001008, 0x00000000, 0x00400008, 0x10401000);
++	&data_word(0x10001000, 0x10400008, 0x10401008, 0x00400000);
++	&data_word(0x10400008, 0x00001008, 0x00400000, 0x10000008);
++	&data_word(0x00401000, 0x10001000, 0x00000008, 0x10400000);
++	&data_word(0x10001008, 0x00000000, 0x00001000, 0x00400008);
++	&data_word(0x00000000, 0x10400008, 0x10401000, 0x00001000);
++	&data_word(0x10000000, 0x10401008, 0x00401008, 0x00400000);
++	&data_word(0x10401008, 0x00000008, 0x10001000, 0x00401008);
++	&data_word(0x00400008, 0x00401000, 0x10400000, 0x10001008);
++	&data_word(0x00001008, 0x10000000, 0x10000008, 0x10401000);
++	# nibble 4
++	&data_word(0x08000000, 0x00010000, 0x00000400, 0x08010420);
++	&data_word(0x08010020, 0x08000400, 0x00010420, 0x08010000);
++	&data_word(0x00010000, 0x00000020, 0x08000020, 0x00010400);
++	&data_word(0x08000420, 0x08010020, 0x08010400, 0x00000000);
++	&data_word(0x00010400, 0x08000000, 0x00010020, 0x00000420);
++	&data_word(0x08000400, 0x00010420, 0x00000000, 0x08000020);
++	&data_word(0x00000020, 0x08000420, 0x08010420, 0x00010020);
++	&data_word(0x08010000, 0x00000400, 0x00000420, 0x08010400);
++	&data_word(0x08010400, 0x08000420, 0x00010020, 0x08010000);
++	&data_word(0x00010000, 0x00000020, 0x08000020, 0x08000400);
++	&data_word(0x08000000, 0x00010400, 0x08010420, 0x00000000);
++	&data_word(0x00010420, 0x08000000, 0x00000400, 0x00010020);
++	&data_word(0x08000420, 0x00000400, 0x00000000, 0x08010420);
++	&data_word(0x08010020, 0x08010400, 0x00000420, 0x00010000);
++	&data_word(0x00010400, 0x08010020, 0x08000400, 0x00000420);
++	&data_word(0x00000020, 0x00010420, 0x08010000, 0x08000020);
++	# nibble 5
++	&data_word(0x80000040, 0x00200040, 0x00000000, 0x80202000);
++	&data_word(0x00200040, 0x00002000, 0x80002040, 0x00200000);
++	&data_word(0x00002040, 0x80202040, 0x00202000, 0x80000000);
++	&data_word(0x80002000, 0x80000040, 0x80200000, 0x00202040);
++	&data_word(0x00200000, 0x80002040, 0x80200040, 0x00000000);
++	&data_word(0x00002000, 0x00000040, 0x80202000, 0x80200040);
++	&data_word(0x80202040, 0x80200000, 0x80000000, 0x00002040);
++	&data_word(0x00000040, 0x00202000, 0x00202040, 0x80002000);
++	&data_word(0x00002040, 0x80000000, 0x80002000, 0x00202040);
++	&data_word(0x80202000, 0x00200040, 0x00000000, 0x80002000);
++	&data_word(0x80000000, 0x00002000, 0x80200040, 0x00200000);
++	&data_word(0x00200040, 0x80202040, 0x00202000, 0x00000040);
++	&data_word(0x80202040, 0x00202000, 0x00200000, 0x80002040);
++	&data_word(0x80000040, 0x80200000, 0x00202040, 0x00000000);
++	&data_word(0x00002000, 0x80000040, 0x80002040, 0x80202000);
++	&data_word(0x80200000, 0x00002040, 0x00000040, 0x80200040);
++	# nibble 6
++	&data_word(0x00004000, 0x00000200, 0x01000200, 0x01000004);
++	&data_word(0x01004204, 0x00004004, 0x00004200, 0x00000000);
++	&data_word(0x01000000, 0x01000204, 0x00000204, 0x01004000);
++	&data_word(0x00000004, 0x01004200, 0x01004000, 0x00000204);
++	&data_word(0x01000204, 0x00004000, 0x00004004, 0x01004204);
++	&data_word(0x00000000, 0x01000200, 0x01000004, 0x00004200);
++	&data_word(0x01004004, 0x00004204, 0x01004200, 0x00000004);
++	&data_word(0x00004204, 0x01004004, 0x00000200, 0x01000000);
++	&data_word(0x00004204, 0x01004000, 0x01004004, 0x00000204);
++	&data_word(0x00004000, 0x00000200, 0x01000000, 0x01004004);
++	&data_word(0x01000204, 0x00004204, 0x00004200, 0x00000000);
++	&data_word(0x00000200, 0x01000004, 0x00000004, 0x01000200);
++	&data_word(0x00000000, 0x01000204, 0x01000200, 0x00004200);
++	&data_word(0x00000204, 0x00004000, 0x01004204, 0x01000000);
++	&data_word(0x01004200, 0x00000004, 0x00004004, 0x01004204);
++	&data_word(0x01000004, 0x01004200, 0x01004000, 0x00004004);
++	# nibble 7
++	&data_word(0x20800080, 0x20820000, 0x00020080, 0x00000000);
++	&data_word(0x20020000, 0x00800080, 0x20800000, 0x20820080);
++	&data_word(0x00000080, 0x20000000, 0x00820000, 0x00020080);
++	&data_word(0x00820080, 0x20020080, 0x20000080, 0x20800000);
++	&data_word(0x00020000, 0x00820080, 0x00800080, 0x20020000);
++	&data_word(0x20820080, 0x20000080, 0x00000000, 0x00820000);
++	&data_word(0x20000000, 0x00800000, 0x20020080, 0x20800080);
++	&data_word(0x00800000, 0x00020000, 0x20820000, 0x00000080);
++	&data_word(0x00800000, 0x00020000, 0x20000080, 0x20820080);
++	&data_word(0x00020080, 0x20000000, 0x00000000, 0x00820000);
++	&data_word(0x20800080, 0x20020080, 0x20020000, 0x00800080);
++	&data_word(0x20820000, 0x00000080, 0x00800080, 0x20020000);
++	&data_word(0x20820080, 0x00800000, 0x20800000, 0x20000080);
++	&data_word(0x00820000, 0x00020080, 0x20020080, 0x20800000);
++	&data_word(0x00000080, 0x20820000, 0x00820080, 0x00000000);
++	&data_word(0x20000000, 0x20800080, 0x00020000, 0x00820080);
++	}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/des/asm/des_enc.m4 b/CryptoPkg/Library/OpensslLib/openssl/crypto/des/asm/des_enc.m4
+new file mode 100644
+index 0000000..2d794d3
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/des/asm/des_enc.m4
+@@ -0,0 +1,1972 @@
++! Copyright 2000-2016 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
++! in the file LICENSE in the source distribution or at
++! https://www.openssl.org/source/license.html
++!
++!  To expand the m4 macros: m4 -B 8192 des_enc.m4 > des_enc.S
++!
++!  Global registers 1 to 5 are used. This is the same as done by the
++!  cc compiler. The UltraSPARC load/store little endian feature is used.
++!
++!  Instruction grouping often refers to one CPU cycle.
++!
++!  Assemble through gcc: gcc -c -mcpu=ultrasparc -o des_enc.o des_enc.S
++!
++!  Assemble through cc:  cc -c -xarch=v8plusa -o des_enc.o des_enc.S
++!
++!  Performance improvement according to './apps/openssl speed des'
++!
++!	32-bit build:
++!		23%  faster than cc-5.2 -xarch=v8plus -xO5
++!		115% faster than gcc-3.2.1 -m32 -mcpu=ultrasparc -O5
++!	64-bit build:
++!		50%  faster than cc-5.2 -xarch=v9 -xO5
++!		100% faster than gcc-3.2.1 -m64 -mcpu=ultrasparc -O5
++!
++
++.ident "des_enc.m4 2.1"
++.file  "des_enc-sparc.S"
++
++#include 
++
++#ifdef OPENSSL_FIPSCANISTER
++#include 
++#endif
++
++#if defined(__SUNPRO_C) && defined(__sparcv9)
++# define ABI64  /* They've said -xarch=v9 at command line */
++#elif defined(__GNUC__) && defined(__arch64__)
++# define ABI64  /* They've said -m64 at command line */
++#endif
++
++#ifdef ABI64
++  .register	%g2,#scratch
++  .register	%g3,#scratch
++# define	FRAME	-192
++# define	BIAS	2047
++# define	LDPTR	ldx
++# define	STPTR	stx
++# define	ARG0	128
++# define	ARGSZ	8
++#else
++# define	FRAME	-96
++# define	BIAS	0
++# define	LDPTR	ld
++# define	STPTR	st
++# define	ARG0	68
++# define	ARGSZ	4
++#endif
++
++#define LOOPS 7
++
++#define global0 %g0
++#define global1 %g1
++#define global2 %g2
++#define global3 %g3
++#define global4 %g4
++#define global5 %g5
++
++#define local0 %l0
++#define local1 %l1
++#define local2 %l2
++#define local3 %l3
++#define local4 %l4
++#define local5 %l5
++#define local7 %l6
++#define local6 %l7
++
++#define in0 %i0
++#define in1 %i1
++#define in2 %i2
++#define in3 %i3
++#define in4 %i4
++#define in5 %i5
++#define in6 %i6
++#define in7 %i7
++
++#define out0 %o0
++#define out1 %o1
++#define out2 %o2
++#define out3 %o3
++#define out4 %o4
++#define out5 %o5
++#define out6 %o6
++#define out7 %o7
++
++#define stub stb
++
++changequote({,})
++
++
++! Macro definitions:
++
++
++! {ip_macro}
++!
++! The logic used in initial and final permutations is the same as in
++! the C code. The permutations are done with a clever shift, xor, and
++! technique.
++!
++! The macro also loads address sbox 1 to 5 to global 1 to 5, address
++! sbox 6 to local6, and addres sbox 8 to out3.
++!
++! Rotates the halfs 3 left to bring the sbox bits in convenient positions.
++!
++! Loads key first round from address in parameter 5 to out0, out1.
++!
++! After the the original LibDES initial permutation, the resulting left
++! is in the variable initially used for right and vice versa. The macro
++! implements the possibility to keep the halfs in the original registers.
++!
++! parameter 1  left
++! parameter 2  right
++! parameter 3  result left (modify in first round)
++! parameter 4  result right (use in first round)
++! parameter 5  key address
++! parameter 6  1/2 for include encryption/decryption
++! parameter 7  1 for move in1 to in3
++! parameter 8  1 for move in3 to in4, 2 for move in4 to in3
++! parameter 9  1 for load ks3 and ks2 to in4 and in3
++
++define(ip_macro, {
++
++! {ip_macro}
++! $1 $2 $4 $3 $5 $6 $7 $8 $9
++
++	ld	[out2+256], local1
++	srl	$2, 4, local4
++
++	xor	local4, $1, local4
++	ifelse($7,1,{mov in1, in3},{nop})
++
++	ld	[out2+260], local2
++	and	local4, local1, local4
++	ifelse($8,1,{mov in3, in4},{})
++	ifelse($8,2,{mov in4, in3},{})
++
++	ld	[out2+280], out4          ! loop counter
++	sll	local4, 4, local1
++	xor	$1, local4, $1
++
++	ld	[out2+264], local3
++	srl	$1, 16, local4
++	xor	$2, local1, $2
++
++	ifelse($9,1,{LDPTR	KS3, in4},{})
++	xor	local4, $2, local4
++	nop	!sethi	%hi(DES_SPtrans), global1 ! sbox addr
++
++	ifelse($9,1,{LDPTR	KS2, in3},{})
++	and	local4, local2, local4
++	nop	!or	global1, %lo(DES_SPtrans), global1   ! sbox addr
++
++	sll	local4, 16, local1
++	xor	$2, local4, $2
++
++	srl	$2, 2, local4
++	xor	$1, local1, $1
++
++	sethi	%hi(16711680), local5
++	xor	local4, $1, local4
++
++	and	local4, local3, local4
++	or	local5, 255, local5
++
++	sll	local4, 2, local2
++	xor	$1, local4, $1
++
++	srl	$1, 8, local4
++	xor	$2, local2, $2
++
++	xor	local4, $2, local4
++	add	global1, 768, global4
++
++	and	local4, local5, local4
++	add	global1, 1024, global5
++
++	ld	[out2+272], local7
++	sll	local4, 8, local1
++	xor	$2, local4, $2
++
++	srl	$2, 1, local4
++	xor	$1, local1, $1
++
++	ld	[$5], out0                ! key 7531
++	xor	local4, $1, local4
++	add	global1, 256, global2
++
++	ld	[$5+4], out1              ! key 8642
++	and	local4, local7, local4
++	add	global1, 512, global3
++
++	sll	local4, 1, local1
++	xor	$1, local4, $1
++
++	sll	$1, 3, local3
++	xor	$2, local1, $2
++
++	sll	$2, 3, local2
++	add	global1, 1280, local6     ! address sbox 8
++
++	srl	$1, 29, local4
++	add	global1, 1792, out3       ! address sbox 8
++
++	srl	$2, 29, local1
++	or	local4, local3, $4
++
++	or	local2, local1, $3
++
++	ifelse($6, 1, {
++
++		ld	[out2+284], local5     ! 0x0000FC00 used in the rounds
++		or	local2, local1, $3
++		xor	$4, out0, local1
++
++		call .des_enc.1
++		and	local1, 252, local1
++
++	},{})
++
++	ifelse($6, 2, {
++
++		ld	[out2+284], local5     ! 0x0000FC00 used in the rounds
++		or	local2, local1, $3
++		xor	$4, out0, local1
++
++		call .des_dec.1
++		and	local1, 252, local1
++
++	},{})
++})
++
++
++! {rounds_macro}
++!
++! The logic used in the DES rounds is the same as in the C code,
++! except that calculations for sbox 1 and sbox 5 begin before
++! the previous round is finished.
++!
++! In each round one half (work) is modified based on key and the
++! other half (use).
++!
++! In this version we do two rounds in a loop repeated 7 times
++! and two rounds separately.
++!
++! One half has the bits for the sboxes in the following positions:
++!
++!	777777xx555555xx333333xx111111xx
++!
++!	88xx666666xx444444xx222222xx8888
++!
++! The bits for each sbox are xor-ed with the key bits for that box.
++! The above xx bits are cleared, and the result used for lookup in
++! the sbox table. Each sbox entry contains the 4 output bits permuted
++! into 32 bits according to the P permutation.
++!
++! In the description of DES, left and right are switched after
++! each round, except after last round. In this code the original
++! left and right are kept in the same register in all rounds, meaning
++! that after the 16 rounds the result for right is in the register
++! originally used for left.
++!
++! parameter 1  first work (left in first round)
++! parameter 2  first use (right in first round)
++! parameter 3  enc/dec  1/-1
++! parameter 4  loop label
++! parameter 5  key address register
++! parameter 6  optional address for key next encryption/decryption
++! parameter 7  not empty for include retl
++!
++! also compares in2 to 8
++
++define(rounds_macro, {
++
++! {rounds_macro}
++! $1 $2 $3 $4 $5 $6 $7 $8 $9
++
++	xor	$2, out0, local1
++
++	ld	[out2+284], local5        ! 0x0000FC00
++	ba	$4
++	and	local1, 252, local1
++
++	.align 32
++
++$4:
++	! local6 is address sbox 6
++	! out3   is address sbox 8
++	! out4   is loop counter
++
++	ld	[global1+local1], local1
++	xor	$2, out1, out1            ! 8642
++	xor	$2, out0, out0            ! 7531
++	! fmovs	%f0, %f0                  ! fxor used for alignment
++
++	srl	out1, 4, local0           ! rotate 4 right
++	and	out0, local5, local3      ! 3
++	! fmovs	%f0, %f0
++
++	ld	[$5+$3*8], local7         ! key 7531 next round
++	srl	local3, 8, local3         ! 3
++	and	local0, 252, local2       ! 2
++	! fmovs	%f0, %f0
++
++	ld	[global3+local3],local3   ! 3
++	sll	out1, 28, out1            ! rotate
++	xor	$1, local1, $1            ! 1 finished, local1 now sbox 7
++
++	ld	[global2+local2], local2  ! 2 
++	srl	out0, 24, local1          ! 7
++	or	out1, local0, out1        ! rotate
++
++	ldub	[out2+local1], local1     ! 7 (and 0xFC)
++	srl	out1, 24, local0          ! 8
++	and	out1, local5, local4      ! 4
++
++	ldub	[out2+local0], local0     ! 8 (and 0xFC)
++	srl	local4, 8, local4         ! 4
++	xor	$1, local2, $1            ! 2 finished local2 now sbox 6
++
++	ld	[global4+local4],local4   ! 4
++	srl	out1, 16, local2          ! 6
++	xor	$1, local3, $1            ! 3 finished local3 now sbox 5
++
++	ld	[out3+local0],local0      ! 8
++	and	local2, 252, local2       ! 6
++	add	global1, 1536, local5     ! address sbox 7
++
++	ld	[local6+local2], local2   ! 6
++	srl	out0, 16, local3          ! 5
++	xor	$1, local4, $1            ! 4 finished
++
++	ld	[local5+local1],local1    ! 7
++	and	local3, 252, local3       ! 5
++	xor	$1, local0, $1            ! 8 finished
++
++	ld	[global5+local3],local3   ! 5
++	xor	$1, local2, $1            ! 6 finished
++	subcc	out4, 1, out4
++
++	ld	[$5+$3*8+4], out0         ! key 8642 next round
++	xor	$1, local7, local2        ! sbox 5 next round
++	xor	$1, local1, $1            ! 7 finished
++
++	srl	local2, 16, local2        ! sbox 5 next round
++	xor	$1, local3, $1            ! 5 finished
++
++	ld	[$5+$3*16+4], out1        ! key 8642 next round again
++	and	local2, 252, local2       ! sbox5 next round
++! next round
++	xor	$1, local7, local7        ! 7531
++
++	ld	[global5+local2], local2  ! 5
++	srl	local7, 24, local3        ! 7
++	xor	$1, out0, out0            ! 8642
++
++	ldub	[out2+local3], local3     ! 7 (and 0xFC)
++	srl	out0, 4, local0           ! rotate 4 right
++	and	local7, 252, local1       ! 1
++
++	sll	out0, 28, out0            ! rotate
++	xor	$2, local2, $2            ! 5 finished local2 used
++
++	srl	local0, 8, local4         ! 4
++	and	local0, 252, local2       ! 2
++	ld	[local5+local3], local3   ! 7
++
++	srl	local0, 16, local5        ! 6
++	or	out0, local0, out0        ! rotate
++	ld	[global2+local2], local2  ! 2
++
++	srl	out0, 24, local0
++	ld	[$5+$3*16], out0          ! key 7531 next round
++	and	local4, 252, local4	  ! 4
++
++	and	local5, 252, local5       ! 6
++	ld	[global4+local4], local4  ! 4
++	xor	$2, local3, $2            ! 7 finished local3 used
++
++	and	local0, 252, local0       ! 8
++	ld	[local6+local5], local5   ! 6
++	xor	$2, local2, $2            ! 2 finished local2 now sbox 3
++
++	srl	local7, 8, local2         ! 3 start
++	ld	[out3+local0], local0     ! 8
++	xor	$2, local4, $2            ! 4 finished
++
++	and	local2, 252, local2       ! 3
++	ld	[global1+local1], local1  ! 1
++	xor	$2, local5, $2            ! 6 finished local5 used
++
++	ld	[global3+local2], local2  ! 3
++	xor	$2, local0, $2            ! 8 finished
++	add	$5, $3*16, $5             ! enc add 8, dec add -8 to key pointer
++
++	ld	[out2+284], local5        ! 0x0000FC00
++	xor	$2, out0, local4          ! sbox 1 next round
++	xor	$2, local1, $2            ! 1 finished
++
++	xor	$2, local2, $2            ! 3 finished
++	bne	$4
++	and	local4, 252, local1       ! sbox 1 next round
++
++! two rounds more:
++
++	ld	[global1+local1], local1
++	xor	$2, out1, out1
++	xor	$2, out0, out0
++
++	srl	out1, 4, local0           ! rotate
++	and	out0, local5, local3
++
++	ld	[$5+$3*8], local7         ! key 7531
++	srl	local3, 8, local3
++	and	local0, 252, local2
++
++	ld	[global3+local3],local3
++	sll	out1, 28, out1            ! rotate
++	xor	$1, local1, $1            ! 1 finished, local1 now sbox 7
++
++	ld	[global2+local2], local2
++	srl	out0, 24, local1
++	or	out1, local0, out1        ! rotate
++
++	ldub	[out2+local1], local1
++	srl	out1, 24, local0
++	and	out1, local5, local4
++
++	ldub	[out2+local0], local0
++	srl	local4, 8, local4
++	xor	$1, local2, $1            ! 2 finished local2 now sbox 6
++
++	ld	[global4+local4],local4
++	srl	out1, 16, local2
++	xor	$1, local3, $1            ! 3 finished local3 now sbox 5
++
++	ld	[out3+local0],local0
++	and	local2, 252, local2
++	add	global1, 1536, local5     ! address sbox 7
++
++	ld	[local6+local2], local2
++	srl	out0, 16, local3
++	xor	$1, local4, $1            ! 4 finished
++
++	ld	[local5+local1],local1
++	and	local3, 252, local3
++	xor	$1, local0, $1
++
++	ld	[global5+local3],local3
++	xor	$1, local2, $1            ! 6 finished
++	cmp	in2, 8
++
++	ifelse($6,{}, {}, {ld	[out2+280], out4})  ! loop counter
++	xor	$1, local7, local2        ! sbox 5 next round
++	xor	$1, local1, $1            ! 7 finished
++
++	ld	[$5+$3*8+4], out0
++	srl	local2, 16, local2        ! sbox 5 next round
++	xor	$1, local3, $1            ! 5 finished
++
++	and	local2, 252, local2
++! next round (two rounds more)
++	xor	$1, local7, local7        ! 7531
++
++	ld	[global5+local2], local2
++	srl	local7, 24, local3
++	xor	$1, out0, out0            ! 8642
++
++	ldub	[out2+local3], local3
++	srl	out0, 4, local0           ! rotate
++	and	local7, 252, local1
++
++	sll	out0, 28, out0            ! rotate
++	xor	$2, local2, $2            ! 5 finished local2 used
++
++	srl	local0, 8, local4
++	and	local0, 252, local2
++	ld	[local5+local3], local3
++
++	srl	local0, 16, local5
++	or	out0, local0, out0        ! rotate
++	ld	[global2+local2], local2
++
++	srl	out0, 24, local0
++	ifelse($6,{}, {}, {ld	[$6], out0})   ! key next encryption/decryption
++	and	local4, 252, local4
++
++	and	local5, 252, local5
++	ld	[global4+local4], local4
++	xor	$2, local3, $2            ! 7 finished local3 used
++
++	and	local0, 252, local0
++	ld	[local6+local5], local5
++	xor	$2, local2, $2            ! 2 finished local2 now sbox 3
++
++	srl	local7, 8, local2         ! 3 start
++	ld	[out3+local0], local0
++	xor	$2, local4, $2
++
++	and	local2, 252, local2
++	ld	[global1+local1], local1
++	xor	$2, local5, $2            ! 6 finished local5 used
++
++	ld	[global3+local2], local2
++	srl	$1, 3, local3
++	xor	$2, local0, $2
++
++	ifelse($6,{}, {}, {ld	[$6+4], out1}) ! key next encryption/decryption
++	sll	$1, 29, local4
++	xor	$2, local1, $2
++
++	ifelse($7,{}, {}, {retl})
++	xor	$2, local2, $2
++})
++
++
++! {fp_macro}
++!
++!  parameter 1   right (original left)
++!  parameter 2   left (original right)
++!  parameter 3   1 for optional store to [in0]
++!  parameter 4   1 for load input/output address to local5/7
++!
++!  The final permutation logic switches the halfes, meaning that
++!  left and right ends up the the registers originally used.
++
++define(fp_macro, {
++
++! {fp_macro}
++! $1 $2 $3 $4 $5 $6 $7 $8 $9
++
++	! initially undo the rotate 3 left done after initial permutation
++	! original left is received shifted 3 right and 29 left in local3/4
++
++	sll	$2, 29, local1
++	or	local3, local4, $1
++
++	srl	$2, 3, $2
++	sethi	%hi(0x55555555), local2
++
++	or	$2, local1, $2
++	or	local2, %lo(0x55555555), local2
++
++	srl	$2, 1, local3
++	sethi	%hi(0x00ff00ff), local1
++	xor	local3, $1, local3
++	or	local1, %lo(0x00ff00ff), local1
++	and	local3, local2, local3
++	sethi	%hi(0x33333333), local4
++	sll	local3, 1, local2
++
++	xor	$1, local3, $1
++
++	srl	$1, 8, local3
++	xor	$2, local2, $2
++	xor	local3, $2, local3
++	or	local4, %lo(0x33333333), local4
++	and	local3, local1, local3
++	sethi	%hi(0x0000ffff), local1
++	sll	local3, 8, local2
++
++	xor	$2, local3, $2
++
++	srl	$2, 2, local3
++	xor	$1, local2, $1
++	xor	local3, $1, local3
++	or	local1, %lo(0x0000ffff), local1
++	and	local3, local4, local3
++	sethi	%hi(0x0f0f0f0f), local4
++	sll	local3, 2, local2
++
++	ifelse($4,1, {LDPTR INPUT, local5})
++	xor	$1, local3, $1
++
++	ifelse($4,1, {LDPTR OUTPUT, local7})
++	srl	$1, 16, local3
++	xor	$2, local2, $2
++	xor	local3, $2, local3
++	or	local4, %lo(0x0f0f0f0f), local4
++	and	local3, local1, local3
++	sll	local3, 16, local2
++
++	xor	$2, local3, local1
++
++	srl	local1, 4, local3
++	xor	$1, local2, $1
++	xor	local3, $1, local3
++	and	local3, local4, local3
++	sll	local3, 4, local2
++
++	xor	$1, local3, $1
++
++	! optional store:
++
++	ifelse($3,1, {st $1, [in0]})
++
++	xor	local1, local2, $2
++
++	ifelse($3,1, {st $2, [in0+4]})
++
++})
++
++
++! {fp_ip_macro}
++!
++! Does initial permutation for next block mixed with
++! final permutation for current block.
++!
++! parameter 1   original left
++! parameter 2   original right
++! parameter 3   left ip
++! parameter 4   right ip
++! parameter 5   1: load ks1/ks2 to in3/in4, add 120 to in4
++!                2: mov in4 to in3
++!
++! also adds -8 to length in2 and loads loop counter to out4
++
++define(fp_ip_macro, {
++
++! {fp_ip_macro}
++! $1 $2 $3 $4 $5 $6 $7 $8 $9
++
++	define({temp1},{out4})
++	define({temp2},{local3})
++
++	define({ip1},{local1})
++	define({ip2},{local2})
++	define({ip4},{local4})
++	define({ip5},{local5})
++
++	! $1 in local3, local4
++
++	ld	[out2+256], ip1
++	sll	out5, 29, temp1
++	or	local3, local4, $1
++
++	srl	out5, 3, $2
++	ifelse($5,2,{mov in4, in3})
++
++	ld	[out2+272], ip5
++	srl	$4, 4, local0
++	or	$2, temp1, $2
++
++	srl	$2, 1, temp1
++	xor	temp1, $1, temp1
++
++	and	temp1, ip5, temp1
++	xor	local0, $3, local0
++
++	sll	temp1, 1, temp2
++	xor	$1, temp1, $1
++
++	and	local0, ip1, local0
++	add	in2, -8, in2
++
++	sll	local0, 4, local7
++	xor	$3, local0, $3
++
++	ld	[out2+268], ip4
++	srl	$1, 8, temp1
++	xor	$2, temp2, $2
++	ld	[out2+260], ip2
++	srl	$3, 16, local0
++	xor	$4, local7, $4
++	xor	temp1, $2, temp1
++	xor	local0, $4, local0
++	and	temp1, ip4, temp1
++	and	local0, ip2, local0
++	sll	temp1, 8, temp2
++	xor	$2, temp1, $2
++	sll	local0, 16, local7
++	xor	$4, local0, $4
++
++	srl	$2, 2, temp1
++	xor	$1, temp2, $1
++
++	ld	[out2+264], temp2         ! ip3
++	srl	$4, 2, local0
++	xor	$3, local7, $3
++	xor	temp1, $1, temp1
++	xor	local0, $3, local0
++	and	temp1, temp2, temp1
++	and	local0, temp2, local0
++	sll	temp1, 2, temp2
++	xor	$1, temp1, $1
++	sll	local0, 2, local7
++	xor	$3, local0, $3
++
++	srl	$1, 16, temp1
++	xor	$2, temp2, $2
++	srl	$3, 8, local0
++	xor	$4, local7, $4
++	xor	temp1, $2, temp1
++	xor	local0, $4, local0
++	and	temp1, ip2, temp1
++	and	local0, ip4, local0
++	sll	temp1, 16, temp2
++	xor	$2, temp1, local4
++	sll	local0, 8, local7
++	xor	$4, local0, $4
++
++	srl	$4, 1, local0
++	xor	$3, local7, $3
++
++	srl	local4, 4, temp1
++	xor	local0, $3, local0
++
++	xor	$1, temp2, $1
++	and	local0, ip5, local0
++
++	sll	local0, 1, local7
++	xor	temp1, $1, temp1
++
++	xor	$3, local0, $3
++	xor	$4, local7, $4
++
++	sll	$3, 3, local5
++	and	temp1, ip1, temp1
++
++	sll	temp1, 4, temp2
++	xor	$1, temp1, $1
++
++	ifelse($5,1,{LDPTR	KS2, in4})
++	sll	$4, 3, local2
++	xor	local4, temp2, $2
++
++	! reload since used as temporar:
++
++	ld	[out2+280], out4          ! loop counter
++
++	srl	$3, 29, local0
++	ifelse($5,1,{add in4, 120, in4})
++
++	ifelse($5,1,{LDPTR	KS1, in3})
++	srl	$4, 29, local7
++
++	or	local0, local5, $4
++	or	local2, local7, $3
++
++})
++
++
++
++! {load_little_endian}
++!
++! parameter 1  address
++! parameter 2  destination left
++! parameter 3  destination right
++! parameter 4  temporar
++! parameter 5  label
++
++define(load_little_endian, {
++
++! {load_little_endian}
++! $1 $2 $3 $4 $5 $6 $7 $8 $9
++
++	! first in memory to rightmost in register
++
++$5:
++	ldub	[$1+3], $2
++
++	ldub	[$1+2], $4
++	sll	$2, 8, $2
++	or	$2, $4, $2
++
++	ldub	[$1+1], $4
++	sll	$2, 8, $2
++	or	$2, $4, $2
++
++	ldub	[$1+0], $4
++	sll	$2, 8, $2
++	or	$2, $4, $2
++
++
++	ldub	[$1+3+4], $3
++
++	ldub	[$1+2+4], $4
++	sll	$3, 8, $3
++	or	$3, $4, $3
++
++	ldub	[$1+1+4], $4
++	sll	$3, 8, $3
++	or	$3, $4, $3
++
++	ldub	[$1+0+4], $4
++	sll	$3, 8, $3
++	or	$3, $4, $3
++$5a:
++
++})
++
++
++! {load_little_endian_inc}
++!
++! parameter 1  address
++! parameter 2  destination left
++! parameter 3  destination right
++! parameter 4  temporar
++! parameter 4  label
++!
++! adds 8 to address
++
++define(load_little_endian_inc, {
++
++! {load_little_endian_inc}
++! $1 $2 $3 $4 $5 $6 $7 $8 $9
++
++	! first in memory to rightmost in register
++
++$5:
++	ldub	[$1+3], $2
++
++	ldub	[$1+2], $4
++	sll	$2, 8, $2
++	or	$2, $4, $2
++
++	ldub	[$1+1], $4
++	sll	$2, 8, $2
++	or	$2, $4, $2
++
++	ldub	[$1+0], $4
++	sll	$2, 8, $2
++	or	$2, $4, $2
++
++	ldub	[$1+3+4], $3
++	add	$1, 8, $1
++
++	ldub	[$1+2+4-8], $4
++	sll	$3, 8, $3
++	or	$3, $4, $3
++
++	ldub	[$1+1+4-8], $4
++	sll	$3, 8, $3
++	or	$3, $4, $3
++
++	ldub	[$1+0+4-8], $4
++	sll	$3, 8, $3
++	or	$3, $4, $3
++$5a:
++
++})
++
++
++! {load_n_bytes}
++!
++! Loads 1 to 7 bytes little endian
++! Remaining bytes are zeroed.
++!
++! parameter 1  address
++! parameter 2  length
++! parameter 3  destination register left
++! parameter 4  destination register right
++! parameter 5  temp
++! parameter 6  temp2
++! parameter 7  label
++! parameter 8  return label
++
++define(load_n_bytes, {
++
++! {load_n_bytes}
++! $1 $2 $5 $6 $7 $8 $7 $8 $9
++
++$7.0:	call	.+8
++	sll	$2, 2, $6
++
++	add	%o7,$7.jmp.table-$7.0,$5
++
++	add	$5, $6, $5
++	mov	0, $4
++
++	ld	[$5], $5
++
++	jmp	%o7+$5
++	mov	0, $3
++
++$7.7:
++	ldub	[$1+6], $5
++	sll	$5, 16, $5
++	or	$3, $5, $3
++$7.6:
++	ldub	[$1+5], $5
++	sll	$5, 8, $5
++	or	$3, $5, $3
++$7.5:
++	ldub	[$1+4], $5
++	or	$3, $5, $3
++$7.4:
++	ldub	[$1+3], $5
++	sll	$5, 24, $5
++	or	$4, $5, $4
++$7.3:
++	ldub	[$1+2], $5
++	sll	$5, 16, $5
++	or	$4, $5, $4
++$7.2:
++	ldub	[$1+1], $5
++	sll	$5, 8, $5
++	or	$4, $5, $4
++$7.1:
++	ldub	[$1+0], $5
++	ba	$8
++	or	$4, $5, $4
++
++	.align 4
++
++$7.jmp.table:
++	.word	0
++	.word	$7.1-$7.0
++	.word	$7.2-$7.0
++	.word	$7.3-$7.0
++	.word	$7.4-$7.0
++	.word	$7.5-$7.0
++	.word	$7.6-$7.0
++	.word	$7.7-$7.0
++})
++
++
++! {store_little_endian}
++!
++! parameter 1  address
++! parameter 2  source left
++! parameter 3  source right
++! parameter 4  temporar
++
++define(store_little_endian, {
++
++! {store_little_endian}
++! $1 $2 $3 $4 $5 $6 $7 $8 $9
++
++	! rightmost in register to first in memory
++
++$5:
++	and	$2, 255, $4
++	stub	$4, [$1+0]
++
++	srl	$2, 8, $4
++	and	$4, 255, $4
++	stub	$4, [$1+1]
++
++	srl	$2, 16, $4
++	and	$4, 255, $4
++	stub	$4, [$1+2]
++
++	srl	$2, 24, $4
++	stub	$4, [$1+3]
++
++
++	and	$3, 255, $4
++	stub	$4, [$1+0+4]
++
++	srl	$3, 8, $4
++	and	$4, 255, $4
++	stub	$4, [$1+1+4]
++
++	srl	$3, 16, $4
++	and	$4, 255, $4
++	stub	$4, [$1+2+4]
++
++	srl	$3, 24, $4
++	stub	$4, [$1+3+4]
++
++$5a:
++
++})
++
++
++! {store_n_bytes}
++!
++! Stores 1 to 7 bytes little endian
++!
++! parameter 1  address
++! parameter 2  length
++! parameter 3  source register left
++! parameter 4  source register right
++! parameter 5  temp
++! parameter 6  temp2
++! parameter 7  label
++! parameter 8  return label
++
++define(store_n_bytes, {
++
++! {store_n_bytes}
++! $1 $2 $5 $6 $7 $8 $7 $8 $9
++
++$7.0:	call	.+8
++	sll	$2, 2, $6
++
++	add	%o7,$7.jmp.table-$7.0,$5
++
++	add	$5, $6, $5
++
++	ld	[$5], $5
++
++	jmp	%o7+$5
++	nop
++
++$7.7:
++	srl	$3, 16, $5
++	and	$5, 0xff, $5
++	stub	$5, [$1+6]
++$7.6:
++	srl	$3, 8, $5
++	and	$5, 0xff, $5
++	stub	$5, [$1+5]
++$7.5:
++	and	$3, 0xff, $5
++	stub	$5, [$1+4]
++$7.4:
++	srl	$4, 24, $5
++	stub	$5, [$1+3]
++$7.3:
++	srl	$4, 16, $5
++	and	$5, 0xff, $5
++	stub	$5, [$1+2]
++$7.2:
++	srl	$4, 8, $5
++	and	$5, 0xff, $5
++	stub	$5, [$1+1]
++$7.1:
++	and	$4, 0xff, $5
++
++
++	ba	$8
++	stub	$5, [$1]
++
++	.align 4
++
++$7.jmp.table:
++
++	.word	0
++	.word	$7.1-$7.0
++	.word	$7.2-$7.0
++	.word	$7.3-$7.0
++	.word	$7.4-$7.0
++	.word	$7.5-$7.0
++	.word	$7.6-$7.0
++	.word	$7.7-$7.0
++})
++
++
++define(testvalue,{1})
++
++define(register_init, {
++
++! For test purposes:
++
++	sethi	%hi(testvalue), local0
++	or	local0, %lo(testvalue), local0
++
++	ifelse($1,{},{}, {mov	local0, $1})
++	ifelse($2,{},{}, {mov	local0, $2})
++	ifelse($3,{},{}, {mov	local0, $3})
++	ifelse($4,{},{}, {mov	local0, $4})
++	ifelse($5,{},{}, {mov	local0, $5})
++	ifelse($6,{},{}, {mov	local0, $6})
++	ifelse($7,{},{}, {mov	local0, $7})
++	ifelse($8,{},{}, {mov	local0, $8})
++
++	mov	local0, local1
++	mov	local0, local2
++	mov	local0, local3
++	mov	local0, local4
++	mov	local0, local5
++	mov	local0, local7
++	mov	local0, local6
++	mov	local0, out0
++	mov	local0, out1
++	mov	local0, out2
++	mov	local0, out3
++	mov	local0, out4
++	mov	local0, out5
++	mov	local0, global1
++	mov	local0, global2
++	mov	local0, global3
++	mov	local0, global4
++	mov	local0, global5
++
++})
++
++.section	".text"
++
++	.align 32
++
++.des_enc:
++
++	! key address in3
++	! loads key next encryption/decryption first round from [in4]
++
++	rounds_macro(in5, out5, 1, .des_enc.1, in3, in4, retl)
++
++
++	.align 32
++
++.des_dec:
++
++	! implemented with out5 as first parameter to avoid
++	! register exchange in ede modes
++
++	! key address in4
++	! loads key next encryption/decryption first round from [in3]
++
++	rounds_macro(out5, in5, -1, .des_dec.1, in4, in3, retl)
++
++
++
++! void DES_encrypt1(data, ks, enc)
++! *******************************
++
++	.align 32
++	.global DES_encrypt1
++	.type	 DES_encrypt1,#function
++
++DES_encrypt1:
++
++	save	%sp, FRAME, %sp
++
++	sethi	%hi(.PIC.DES_SPtrans-1f),global1
++	or	global1,%lo(.PIC.DES_SPtrans-1f),global1
++1:	call	.+8
++	add	%o7,global1,global1
++	sub	global1,.PIC.DES_SPtrans-.des_and,out2
++
++	ld	[in0], in5                ! left
++	cmp	in2, 0                    ! enc
++
++	be	.encrypt.dec
++	ld	[in0+4], out5             ! right
++
++	! parameter 6  1/2 for include encryption/decryption
++	! parameter 7  1 for move in1 to in3
++	! parameter 8  1 for move in3 to in4, 2 for move in4 to in3
++
++	ip_macro(in5, out5, in5, out5, in3, 0, 1, 1)
++
++	rounds_macro(in5, out5, 1, .des_encrypt1.1, in3, in4) ! in4 not used
++
++	fp_macro(in5, out5, 1)            ! 1 for store to [in0]
++
++	ret
++	restore
++
++.encrypt.dec:
++
++	add	in1, 120, in3             ! use last subkey for first round
++
++	! parameter 6  1/2 for include encryption/decryption
++	! parameter 7  1 for move in1 to in3
++	! parameter 8  1 for move in3 to in4, 2 for move in4 to in3
++
++	ip_macro(in5, out5, out5, in5, in4, 2, 0, 1) ! include dec,  ks in4
++
++	fp_macro(out5, in5, 1)            ! 1 for store to [in0]
++
++	ret
++	restore
++
++.DES_encrypt1.end:
++	.size	 DES_encrypt1,.DES_encrypt1.end-DES_encrypt1
++
++
++! void DES_encrypt2(data, ks, enc)
++!*********************************
++
++	! encrypts/decrypts without initial/final permutation
++
++	.align 32
++	.global DES_encrypt2
++	.type	 DES_encrypt2,#function
++
++DES_encrypt2:
++
++	save	%sp, FRAME, %sp
++
++	sethi	%hi(.PIC.DES_SPtrans-1f),global1
++	or	global1,%lo(.PIC.DES_SPtrans-1f),global1
++1:	call	.+8
++	add	%o7,global1,global1
++	sub	global1,.PIC.DES_SPtrans-.des_and,out2
++
++	! Set sbox address 1 to 6 and rotate halfs 3 left
++	! Errors caught by destest? Yes. Still? *NO*
++
++	!sethi	%hi(DES_SPtrans), global1 ! address sbox 1
++
++	!or	global1, %lo(DES_SPtrans), global1  ! sbox 1
++
++	add	global1, 256, global2     ! sbox 2
++	add	global1, 512, global3     ! sbox 3
++
++	ld	[in0], out5               ! right
++	add	global1, 768, global4     ! sbox 4
++	add	global1, 1024, global5    ! sbox 5
++
++	ld	[in0+4], in5              ! left
++	add	global1, 1280, local6     ! sbox 6
++	add	global1, 1792, out3       ! sbox 8
++
++	! rotate
++
++	sll	in5, 3, local5
++	mov	in1, in3                  ! key address to in3
++
++	sll	out5, 3, local7
++	srl	in5, 29, in5
++
++	srl	out5, 29, out5
++	add	in5, local5, in5
++
++	add	out5, local7, out5
++	cmp	in2, 0
++
++	! we use our own stackframe
++
++	be	.encrypt2.dec
++	STPTR	in0, [%sp+BIAS+ARG0+0*ARGSZ]
++
++	ld	[in3], out0               ! key 7531 first round
++	mov	LOOPS, out4               ! loop counter
++
++	ld	[in3+4], out1             ! key 8642 first round
++	sethi	%hi(0x0000FC00), local5
++
++	call .des_enc
++	mov	in3, in4
++
++	! rotate
++	sll	in5, 29, in0
++	srl	in5, 3, in5
++	sll	out5, 29, in1
++	add	in5, in0, in5
++	srl	out5, 3, out5
++	LDPTR	[%sp+BIAS+ARG0+0*ARGSZ], in0
++	add	out5, in1, out5
++	st	in5, [in0]
++	st	out5, [in0+4]
++
++	ret
++	restore
++
++
++.encrypt2.dec:
++
++	add in3, 120, in4
++
++	ld	[in4], out0               ! key 7531 first round
++	mov	LOOPS, out4               ! loop counter
++
++	ld	[in4+4], out1             ! key 8642 first round
++	sethi	%hi(0x0000FC00), local5
++
++	mov	in5, local1               ! left expected in out5
++	mov	out5, in5
++
++	call .des_dec
++	mov	local1, out5
++
++.encrypt2.finish:
++
++	! rotate
++	sll	in5, 29, in0
++	srl	in5, 3, in5
++	sll	out5, 29, in1
++	add	in5, in0, in5
++	srl	out5, 3, out5
++	LDPTR	[%sp+BIAS+ARG0+0*ARGSZ], in0
++	add	out5, in1, out5
++	st	out5, [in0]
++	st	in5, [in0+4]
++
++	ret
++	restore
++
++.DES_encrypt2.end:
++	.size	 DES_encrypt2, .DES_encrypt2.end-DES_encrypt2
++
++
++! void DES_encrypt3(data, ks1, ks2, ks3)
++! **************************************
++
++	.align 32
++	.global DES_encrypt3
++	.type	 DES_encrypt3,#function
++
++DES_encrypt3:
++
++	save	%sp, FRAME, %sp
++	
++	sethi	%hi(.PIC.DES_SPtrans-1f),global1
++	or	global1,%lo(.PIC.DES_SPtrans-1f),global1
++1:	call	.+8
++	add	%o7,global1,global1
++	sub	global1,.PIC.DES_SPtrans-.des_and,out2
++
++	ld	[in0], in5                ! left
++	add	in2, 120, in4             ! ks2
++
++	ld	[in0+4], out5             ! right
++	mov	in3, in2                  ! save ks3
++
++	! parameter 6  1/2 for include encryption/decryption
++	! parameter 7  1 for mov in1 to in3
++	! parameter 8  1 for mov in3 to in4
++	! parameter 9  1 for load ks3 and ks2 to in4 and in3
++
++	ip_macro(in5, out5, in5, out5, in3, 1, 1, 0, 0)
++
++	call	.des_dec
++	mov	in2, in3                  ! preload ks3
++
++	call	.des_enc
++	nop
++
++	fp_macro(in5, out5, 1)
++
++	ret
++	restore
++
++.DES_encrypt3.end:
++	.size	 DES_encrypt3,.DES_encrypt3.end-DES_encrypt3
++
++
++! void DES_decrypt3(data, ks1, ks2, ks3)
++! **************************************
++
++	.align 32
++	.global DES_decrypt3
++	.type	 DES_decrypt3,#function
++
++DES_decrypt3:
++
++	save	%sp, FRAME, %sp
++	
++	sethi	%hi(.PIC.DES_SPtrans-1f),global1
++	or	global1,%lo(.PIC.DES_SPtrans-1f),global1
++1:	call	.+8
++	add	%o7,global1,global1
++	sub	global1,.PIC.DES_SPtrans-.des_and,out2
++
++	ld	[in0], in5                ! left
++	add	in3, 120, in4             ! ks3
++
++	ld	[in0+4], out5             ! right
++	mov	in2, in3                  ! ks2
++
++	! parameter 6  1/2 for include encryption/decryption
++	! parameter 7  1 for mov in1 to in3
++	! parameter 8  1 for mov in3 to in4
++	! parameter 9  1 for load ks3 and ks2 to in4 and in3
++
++	ip_macro(in5, out5, out5, in5, in4, 2, 0, 0, 0)
++
++	call	.des_enc
++	add	in1, 120, in4             ! preload ks1
++
++	call	.des_dec
++	nop
++
++	fp_macro(out5, in5, 1)
++
++	ret
++	restore
++
++.DES_decrypt3.end:
++	.size	 DES_decrypt3,.DES_decrypt3.end-DES_decrypt3
++
++! void DES_ncbc_encrypt(input, output, length, schedule, ivec, enc)
++! *****************************************************************
++
++
++	.align 32
++	.global DES_ncbc_encrypt
++	.type	 DES_ncbc_encrypt,#function
++
++DES_ncbc_encrypt:
++
++	save	%sp, FRAME, %sp
++	
++	define({INPUT},  { [%sp+BIAS+ARG0+0*ARGSZ] })
++	define({OUTPUT}, { [%sp+BIAS+ARG0+1*ARGSZ] })
++	define({IVEC},   { [%sp+BIAS+ARG0+4*ARGSZ] })
++
++	sethi	%hi(.PIC.DES_SPtrans-1f),global1
++	or	global1,%lo(.PIC.DES_SPtrans-1f),global1
++1:	call	.+8
++	add	%o7,global1,global1
++	sub	global1,.PIC.DES_SPtrans-.des_and,out2
++
++	cmp	in5, 0                    ! enc   
++
++	be	.ncbc.dec
++	STPTR	in4, IVEC
++
++	! addr  left  right  temp  label
++	load_little_endian(in4, in5, out5, local3, .LLE1)  ! iv
++
++	addcc	in2, -8, in2              ! bytes missing when first block done
++
++	bl	.ncbc.enc.seven.or.less
++	mov	in3, in4                  ! schedule
++
++.ncbc.enc.next.block:
++
++	load_little_endian(in0, out4, global4, local3, .LLE2)  ! block
++
++.ncbc.enc.next.block_1:
++
++	xor	in5, out4, in5            ! iv xor
++	xor	out5, global4, out5       ! iv xor
++
++	! parameter 8  1 for move in3 to in4, 2 for move in4 to in3
++	ip_macro(in5, out5, in5, out5, in3, 0, 0, 2)
++
++.ncbc.enc.next.block_2:
++
++!//	call .des_enc                     ! compares in2 to 8
++!	rounds inlined for alignment purposes
++
++	add	global1, 768, global4     ! address sbox 4 since register used below
++
++	rounds_macro(in5, out5, 1, .ncbc.enc.1, in3, in4) ! include encryption  ks in3
++
++	bl	.ncbc.enc.next.block_fp
++	add	in0, 8, in0               ! input address
++
++	! If 8 or more bytes are to be encrypted after this block,
++	! we combine final permutation for this block with initial
++	! permutation for next block. Load next block:
++
++	load_little_endian(in0, global3, global4, local5, .LLE12)
++
++	!  parameter 1   original left
++	!  parameter 2   original right
++	!  parameter 3   left ip
++	!  parameter 4   right ip
++	!  parameter 5   1: load ks1/ks2 to in3/in4, add 120 to in4
++	!                2: mov in4 to in3
++	!
++	! also adds -8 to length in2 and loads loop counter to out4
++
++	fp_ip_macro(out0, out1, global3, global4, 2)
++
++	store_little_endian(in1, out0, out1, local3, .SLE10)  ! block
++
++	ld	[in3], out0               ! key 7531 first round next block
++	mov 	in5, local1
++	xor	global3, out5, in5        ! iv xor next block
++
++	ld	[in3+4], out1             ! key 8642
++	add	global1, 512, global3     ! address sbox 3 since register used
++	xor	global4, local1, out5     ! iv xor next block
++
++	ba	.ncbc.enc.next.block_2
++	add	in1, 8, in1               ! output address
++
++.ncbc.enc.next.block_fp:
++
++	fp_macro(in5, out5)
++
++	store_little_endian(in1, in5, out5, local3, .SLE1)  ! block
++
++	addcc   in2, -8, in2              ! bytes missing when next block done
++
++	bpos	.ncbc.enc.next.block
++	add	in1, 8, in1
++
++.ncbc.enc.seven.or.less:
++
++	cmp	in2, -8
++
++	ble	.ncbc.enc.finish
++	nop
++
++	add	in2, 8, local1            ! bytes to load
++
++	! addr, length, dest left, dest right, temp, temp2, label, ret label
++	load_n_bytes(in0, local1, global4, out4, local2, local3, .LNB1, .ncbc.enc.next.block_1)
++
++	! Loads 1 to 7 bytes little endian to global4, out4
++
++
++.ncbc.enc.finish:
++
++	LDPTR	IVEC, local4
++	store_little_endian(local4, in5, out5, local5, .SLE2)  ! ivec
++
++	ret
++	restore
++
++
++.ncbc.dec:
++
++	STPTR	in0, INPUT
++	cmp	in2, 0                    ! length
++	add	in3, 120, in3
++
++	LDPTR	IVEC, local7              ! ivec
++	ble	.ncbc.dec.finish
++	mov	in3, in4                  ! schedule
++
++	STPTR	in1, OUTPUT
++	mov	in0, local5               ! input
++
++	load_little_endian(local7, in0, in1, local3, .LLE3)   ! ivec
++
++.ncbc.dec.next.block:
++
++	load_little_endian(local5, in5, out5, local3, .LLE4)  ! block
++
++	! parameter 6  1/2 for include encryption/decryption
++	! parameter 7  1 for mov in1 to in3
++	! parameter 8  1 for mov in3 to in4
++
++	ip_macro(in5, out5, out5, in5, in4, 2, 0, 1) ! include decryprion  ks in4
++
++	fp_macro(out5, in5, 0, 1) ! 1 for input and output address to local5/7
++
++	! in2 is bytes left to be stored
++	! in2 is compared to 8 in the rounds
++
++	xor	out5, in0, out4           ! iv xor
++	bl	.ncbc.dec.seven.or.less
++	xor	in5, in1, global4         ! iv xor
++
++	! Load ivec next block now, since input and output address might be the same.
++
++	load_little_endian_inc(local5, in0, in1, local3, .LLE5)  ! iv
++
++	store_little_endian(local7, out4, global4, local3, .SLE3)
++
++	STPTR	local5, INPUT
++	add	local7, 8, local7
++	addcc   in2, -8, in2
++
++	bg	.ncbc.dec.next.block
++	STPTR	local7, OUTPUT
++
++
++.ncbc.dec.store.iv:
++
++	LDPTR	IVEC, local4              ! ivec
++	store_little_endian(local4, in0, in1, local5, .SLE4)
++
++.ncbc.dec.finish:
++
++	ret
++	restore
++
++.ncbc.dec.seven.or.less:
++
++	load_little_endian_inc(local5, in0, in1, local3, .LLE13)     ! ivec
++
++	store_n_bytes(local7, in2, global4, out4, local3, local4, .SNB1, .ncbc.dec.store.iv)
++
++
++.DES_ncbc_encrypt.end:
++	.size	 DES_ncbc_encrypt, .DES_ncbc_encrypt.end-DES_ncbc_encrypt
++
++
++! void DES_ede3_cbc_encrypt(input, output, lenght, ks1, ks2, ks3, ivec, enc)
++! **************************************************************************
++
++
++	.align 32
++	.global DES_ede3_cbc_encrypt
++	.type	 DES_ede3_cbc_encrypt,#function
++
++DES_ede3_cbc_encrypt:
++
++	save	%sp, FRAME, %sp
++
++	define({KS1}, { [%sp+BIAS+ARG0+3*ARGSZ] })
++	define({KS2}, { [%sp+BIAS+ARG0+4*ARGSZ] })
++	define({KS3}, { [%sp+BIAS+ARG0+5*ARGSZ] })
++
++	sethi	%hi(.PIC.DES_SPtrans-1f),global1
++	or	global1,%lo(.PIC.DES_SPtrans-1f),global1
++1:	call	.+8
++	add	%o7,global1,global1
++	sub	global1,.PIC.DES_SPtrans-.des_and,out2
++
++	LDPTR	[%fp+BIAS+ARG0+7*ARGSZ], local3          ! enc
++	LDPTR	[%fp+BIAS+ARG0+6*ARGSZ], local4          ! ivec
++	cmp	local3, 0                 ! enc
++
++	be	.ede3.dec
++	STPTR	in4, KS2
++
++	STPTR	in5, KS3
++
++	load_little_endian(local4, in5, out5, local3, .LLE6)  ! ivec
++
++	addcc	in2, -8, in2              ! bytes missing after next block
++
++	bl	.ede3.enc.seven.or.less
++	STPTR	in3, KS1
++
++.ede3.enc.next.block:
++
++	load_little_endian(in0, out4, global4, local3, .LLE7)
++
++.ede3.enc.next.block_1:
++
++	LDPTR	KS2, in4
++	xor	in5, out4, in5            ! iv xor
++	xor	out5, global4, out5       ! iv xor
++
++	LDPTR	KS1, in3
++	add	in4, 120, in4             ! for decryption we use last subkey first
++	nop
++
++	ip_macro(in5, out5, in5, out5, in3)
++
++.ede3.enc.next.block_2:
++
++	call .des_enc                     ! ks1 in3
++	nop
++
++	call .des_dec                     ! ks2 in4
++	LDPTR	KS3, in3
++
++	call .des_enc                     ! ks3 in3  compares in2 to 8
++	nop
++
++	bl	.ede3.enc.next.block_fp
++	add	in0, 8, in0
++
++	! If 8 or more bytes are to be encrypted after this block,
++	! we combine final permutation for this block with initial
++	! permutation for next block. Load next block:
++
++	load_little_endian(in0, global3, global4, local5, .LLE11)
++
++	!  parameter 1   original left
++	!  parameter 2   original right
++	!  parameter 3   left ip
++	!  parameter 4   right ip
++	!  parameter 5   1: load ks1/ks2 to in3/in4, add 120 to in4
++	!                2: mov in4 to in3
++	!
++	! also adds -8 to length in2 and loads loop counter to out4
++
++	fp_ip_macro(out0, out1, global3, global4, 1)
++
++	store_little_endian(in1, out0, out1, local3, .SLE9)  ! block
++
++	mov 	in5, local1
++	xor	global3, out5, in5        ! iv xor next block
++
++	ld	[in3], out0               ! key 7531
++	add	global1, 512, global3     ! address sbox 3
++	xor	global4, local1, out5     ! iv xor next block
++
++	ld	[in3+4], out1             ! key 8642
++	add	global1, 768, global4     ! address sbox 4
++	ba	.ede3.enc.next.block_2
++	add	in1, 8, in1
++
++.ede3.enc.next.block_fp:
++
++	fp_macro(in5, out5)
++
++	store_little_endian(in1, in5, out5, local3, .SLE5)  ! block
++
++	addcc   in2, -8, in2              ! bytes missing when next block done
++
++	bpos	.ede3.enc.next.block
++	add	in1, 8, in1
++
++.ede3.enc.seven.or.less:
++
++	cmp	in2, -8
++
++	ble	.ede3.enc.finish
++	nop
++
++	add	in2, 8, local1            ! bytes to load
++
++	! addr, length, dest left, dest right, temp, temp2, label, ret label
++	load_n_bytes(in0, local1, global4, out4, local2, local3, .LNB2, .ede3.enc.next.block_1)
++
++.ede3.enc.finish:
++
++	LDPTR	[%fp+BIAS+ARG0+6*ARGSZ], local4          ! ivec
++	store_little_endian(local4, in5, out5, local5, .SLE6)  ! ivec
++
++	ret
++	restore
++
++.ede3.dec:
++
++	STPTR	in0, INPUT
++	add	in5, 120, in5
++
++	STPTR	in1, OUTPUT
++	mov	in0, local5
++	add	in3, 120, in3
++
++	STPTR	in3, KS1
++	cmp	in2, 0
++
++	ble	.ede3.dec.finish
++	STPTR	in5, KS3
++
++	LDPTR	[%fp+BIAS+ARG0+6*ARGSZ], local7          ! iv
++	load_little_endian(local7, in0, in1, local3, .LLE8)
++
++.ede3.dec.next.block:
++
++	load_little_endian(local5, in5, out5, local3, .LLE9)
++
++	! parameter 6  1/2 for include encryption/decryption
++	! parameter 7  1 for mov in1 to in3
++	! parameter 8  1 for mov in3 to in4
++	! parameter 9  1 for load ks3 and ks2 to in4 and in3
++
++	ip_macro(in5, out5, out5, in5, in4, 2, 0, 0, 1) ! inc .des_dec ks3 in4
++
++	call .des_enc                     ! ks2 in3
++	LDPTR	KS1, in4
++
++	call .des_dec                     ! ks1 in4
++	nop
++
++	fp_macro(out5, in5, 0, 1)   ! 1 for input and output address local5/7
++
++	! in2 is bytes left to be stored
++	! in2 is compared to 8 in the rounds
++
++	xor	out5, in0, out4
++	bl	.ede3.dec.seven.or.less
++	xor	in5, in1, global4
++
++	load_little_endian_inc(local5, in0, in1, local3, .LLE10)   ! iv next block
++
++	store_little_endian(local7, out4, global4, local3, .SLE7)  ! block
++
++	STPTR	local5, INPUT
++	addcc   in2, -8, in2
++	add	local7, 8, local7
++
++	bg	.ede3.dec.next.block
++	STPTR	local7, OUTPUT
++
++.ede3.dec.store.iv:
++
++	LDPTR	[%fp+BIAS+ARG0+6*ARGSZ], local4          ! ivec
++	store_little_endian(local4, in0, in1, local5, .SLE8)  ! ivec
++
++.ede3.dec.finish:
++
++	ret
++	restore
++
++.ede3.dec.seven.or.less:
++
++	load_little_endian_inc(local5, in0, in1, local3, .LLE14)     ! iv
++
++	store_n_bytes(local7, in2, global4, out4, local3, local4, .SNB2, .ede3.dec.store.iv)
++
++
++.DES_ede3_cbc_encrypt.end:
++	.size	 DES_ede3_cbc_encrypt,.DES_ede3_cbc_encrypt.end-DES_ede3_cbc_encrypt
++
++	.align	256
++	.type	 .des_and,#object
++	.size	 .des_and,284
++
++.des_and:
++
++! This table is used for AND 0xFC when it is known that register
++! bits 8-31 are zero. Makes it possible to do three arithmetic
++! operations in one cycle.
++
++	.byte  0, 0, 0, 0, 4, 4, 4, 4
++	.byte  8, 8, 8, 8, 12, 12, 12, 12
++	.byte  16, 16, 16, 16, 20, 20, 20, 20
++	.byte  24, 24, 24, 24, 28, 28, 28, 28
++	.byte  32, 32, 32, 32, 36, 36, 36, 36
++	.byte  40, 40, 40, 40, 44, 44, 44, 44
++	.byte  48, 48, 48, 48, 52, 52, 52, 52
++	.byte  56, 56, 56, 56, 60, 60, 60, 60
++	.byte  64, 64, 64, 64, 68, 68, 68, 68
++	.byte  72, 72, 72, 72, 76, 76, 76, 76
++	.byte  80, 80, 80, 80, 84, 84, 84, 84
++	.byte  88, 88, 88, 88, 92, 92, 92, 92
++	.byte  96, 96, 96, 96, 100, 100, 100, 100
++	.byte  104, 104, 104, 104, 108, 108, 108, 108
++	.byte  112, 112, 112, 112, 116, 116, 116, 116
++	.byte  120, 120, 120, 120, 124, 124, 124, 124
++	.byte  128, 128, 128, 128, 132, 132, 132, 132
++	.byte  136, 136, 136, 136, 140, 140, 140, 140
++	.byte  144, 144, 144, 144, 148, 148, 148, 148
++	.byte  152, 152, 152, 152, 156, 156, 156, 156
++	.byte  160, 160, 160, 160, 164, 164, 164, 164
++	.byte  168, 168, 168, 168, 172, 172, 172, 172
++	.byte  176, 176, 176, 176, 180, 180, 180, 180
++	.byte  184, 184, 184, 184, 188, 188, 188, 188
++	.byte  192, 192, 192, 192, 196, 196, 196, 196
++	.byte  200, 200, 200, 200, 204, 204, 204, 204
++	.byte  208, 208, 208, 208, 212, 212, 212, 212
++	.byte  216, 216, 216, 216, 220, 220, 220, 220
++	.byte  224, 224, 224, 224, 228, 228, 228, 228
++	.byte  232, 232, 232, 232, 236, 236, 236, 236
++	.byte  240, 240, 240, 240, 244, 244, 244, 244
++	.byte  248, 248, 248, 248, 252, 252, 252, 252
++
++	! 5 numbers for initil/final permutation
++
++	.word   0x0f0f0f0f                ! offset 256
++	.word	0x0000ffff                ! 260
++	.word	0x33333333                ! 264
++	.word	0x00ff00ff                ! 268
++	.word	0x55555555                ! 272
++
++	.word	0                         ! 276
++	.word	LOOPS                     ! 280
++	.word	0x0000FC00                ! 284
++
++	.global	DES_SPtrans
++	.type	DES_SPtrans,#object
++	.size	DES_SPtrans,2048
++.align	64
++DES_SPtrans:
++.PIC.DES_SPtrans:
++	! nibble 0
++	.word	0x02080800, 0x00080000, 0x02000002, 0x02080802
++	.word	0x02000000, 0x00080802, 0x00080002, 0x02000002
++	.word	0x00080802, 0x02080800, 0x02080000, 0x00000802
++	.word	0x02000802, 0x02000000, 0x00000000, 0x00080002
++	.word	0x00080000, 0x00000002, 0x02000800, 0x00080800
++	.word	0x02080802, 0x02080000, 0x00000802, 0x02000800
++	.word	0x00000002, 0x00000800, 0x00080800, 0x02080002
++	.word	0x00000800, 0x02000802, 0x02080002, 0x00000000
++	.word	0x00000000, 0x02080802, 0x02000800, 0x00080002
++	.word	0x02080800, 0x00080000, 0x00000802, 0x02000800
++	.word	0x02080002, 0x00000800, 0x00080800, 0x02000002
++	.word	0x00080802, 0x00000002, 0x02000002, 0x02080000
++	.word	0x02080802, 0x00080800, 0x02080000, 0x02000802
++	.word	0x02000000, 0x00000802, 0x00080002, 0x00000000
++	.word	0x00080000, 0x02000000, 0x02000802, 0x02080800
++	.word	0x00000002, 0x02080002, 0x00000800, 0x00080802
++	! nibble 1
++	.word	0x40108010, 0x00000000, 0x00108000, 0x40100000
++	.word	0x40000010, 0x00008010, 0x40008000, 0x00108000
++	.word	0x00008000, 0x40100010, 0x00000010, 0x40008000
++	.word	0x00100010, 0x40108000, 0x40100000, 0x00000010
++	.word	0x00100000, 0x40008010, 0x40100010, 0x00008000
++	.word	0x00108010, 0x40000000, 0x00000000, 0x00100010
++	.word	0x40008010, 0x00108010, 0x40108000, 0x40000010
++	.word	0x40000000, 0x00100000, 0x00008010, 0x40108010
++	.word	0x00100010, 0x40108000, 0x40008000, 0x00108010
++	.word	0x40108010, 0x00100010, 0x40000010, 0x00000000
++	.word	0x40000000, 0x00008010, 0x00100000, 0x40100010
++	.word	0x00008000, 0x40000000, 0x00108010, 0x40008010
++	.word	0x40108000, 0x00008000, 0x00000000, 0x40000010
++	.word	0x00000010, 0x40108010, 0x00108000, 0x40100000
++	.word	0x40100010, 0x00100000, 0x00008010, 0x40008000
++	.word	0x40008010, 0x00000010, 0x40100000, 0x00108000
++	! nibble 2
++	.word	0x04000001, 0x04040100, 0x00000100, 0x04000101
++	.word	0x00040001, 0x04000000, 0x04000101, 0x00040100
++	.word	0x04000100, 0x00040000, 0x04040000, 0x00000001
++	.word	0x04040101, 0x00000101, 0x00000001, 0x04040001
++	.word	0x00000000, 0x00040001, 0x04040100, 0x00000100
++	.word	0x00000101, 0x04040101, 0x00040000, 0x04000001
++	.word	0x04040001, 0x04000100, 0x00040101, 0x04040000
++	.word	0x00040100, 0x00000000, 0x04000000, 0x00040101
++	.word	0x04040100, 0x00000100, 0x00000001, 0x00040000
++	.word	0x00000101, 0x00040001, 0x04040000, 0x04000101
++	.word	0x00000000, 0x04040100, 0x00040100, 0x04040001
++	.word	0x00040001, 0x04000000, 0x04040101, 0x00000001
++	.word	0x00040101, 0x04000001, 0x04000000, 0x04040101
++	.word	0x00040000, 0x04000100, 0x04000101, 0x00040100
++	.word	0x04000100, 0x00000000, 0x04040001, 0x00000101
++	.word	0x04000001, 0x00040101, 0x00000100, 0x04040000
++	! nibble 3
++	.word	0x00401008, 0x10001000, 0x00000008, 0x10401008
++	.word	0x00000000, 0x10400000, 0x10001008, 0x00400008
++	.word	0x10401000, 0x10000008, 0x10000000, 0x00001008
++	.word	0x10000008, 0x00401008, 0x00400000, 0x10000000
++	.word	0x10400008, 0x00401000, 0x00001000, 0x00000008
++	.word	0x00401000, 0x10001008, 0x10400000, 0x00001000
++	.word	0x00001008, 0x00000000, 0x00400008, 0x10401000
++	.word	0x10001000, 0x10400008, 0x10401008, 0x00400000
++	.word	0x10400008, 0x00001008, 0x00400000, 0x10000008
++	.word	0x00401000, 0x10001000, 0x00000008, 0x10400000
++	.word	0x10001008, 0x00000000, 0x00001000, 0x00400008
++	.word	0x00000000, 0x10400008, 0x10401000, 0x00001000
++	.word	0x10000000, 0x10401008, 0x00401008, 0x00400000
++	.word	0x10401008, 0x00000008, 0x10001000, 0x00401008
++	.word	0x00400008, 0x00401000, 0x10400000, 0x10001008
++	.word	0x00001008, 0x10000000, 0x10000008, 0x10401000
++	! nibble 4
++	.word	0x08000000, 0x00010000, 0x00000400, 0x08010420
++	.word	0x08010020, 0x08000400, 0x00010420, 0x08010000
++	.word	0x00010000, 0x00000020, 0x08000020, 0x00010400
++	.word	0x08000420, 0x08010020, 0x08010400, 0x00000000
++	.word	0x00010400, 0x08000000, 0x00010020, 0x00000420
++	.word	0x08000400, 0x00010420, 0x00000000, 0x08000020
++	.word	0x00000020, 0x08000420, 0x08010420, 0x00010020
++	.word	0x08010000, 0x00000400, 0x00000420, 0x08010400
++	.word	0x08010400, 0x08000420, 0x00010020, 0x08010000
++	.word	0x00010000, 0x00000020, 0x08000020, 0x08000400
++	.word	0x08000000, 0x00010400, 0x08010420, 0x00000000
++	.word	0x00010420, 0x08000000, 0x00000400, 0x00010020
++	.word	0x08000420, 0x00000400, 0x00000000, 0x08010420
++	.word	0x08010020, 0x08010400, 0x00000420, 0x00010000
++	.word	0x00010400, 0x08010020, 0x08000400, 0x00000420
++	.word	0x00000020, 0x00010420, 0x08010000, 0x08000020
++	! nibble 5
++	.word	0x80000040, 0x00200040, 0x00000000, 0x80202000
++	.word	0x00200040, 0x00002000, 0x80002040, 0x00200000
++	.word	0x00002040, 0x80202040, 0x00202000, 0x80000000
++	.word	0x80002000, 0x80000040, 0x80200000, 0x00202040
++	.word	0x00200000, 0x80002040, 0x80200040, 0x00000000
++	.word	0x00002000, 0x00000040, 0x80202000, 0x80200040
++	.word	0x80202040, 0x80200000, 0x80000000, 0x00002040
++	.word	0x00000040, 0x00202000, 0x00202040, 0x80002000
++	.word	0x00002040, 0x80000000, 0x80002000, 0x00202040
++	.word	0x80202000, 0x00200040, 0x00000000, 0x80002000
++	.word	0x80000000, 0x00002000, 0x80200040, 0x00200000
++	.word	0x00200040, 0x80202040, 0x00202000, 0x00000040
++	.word	0x80202040, 0x00202000, 0x00200000, 0x80002040
++	.word	0x80000040, 0x80200000, 0x00202040, 0x00000000
++	.word	0x00002000, 0x80000040, 0x80002040, 0x80202000
++	.word	0x80200000, 0x00002040, 0x00000040, 0x80200040
++	! nibble 6
++	.word	0x00004000, 0x00000200, 0x01000200, 0x01000004
++	.word	0x01004204, 0x00004004, 0x00004200, 0x00000000
++	.word	0x01000000, 0x01000204, 0x00000204, 0x01004000
++	.word	0x00000004, 0x01004200, 0x01004000, 0x00000204
++	.word	0x01000204, 0x00004000, 0x00004004, 0x01004204
++	.word	0x00000000, 0x01000200, 0x01000004, 0x00004200
++	.word	0x01004004, 0x00004204, 0x01004200, 0x00000004
++	.word	0x00004204, 0x01004004, 0x00000200, 0x01000000
++	.word	0x00004204, 0x01004000, 0x01004004, 0x00000204
++	.word	0x00004000, 0x00000200, 0x01000000, 0x01004004
++	.word	0x01000204, 0x00004204, 0x00004200, 0x00000000
++	.word	0x00000200, 0x01000004, 0x00000004, 0x01000200
++	.word	0x00000000, 0x01000204, 0x01000200, 0x00004200
++	.word	0x00000204, 0x00004000, 0x01004204, 0x01000000
++	.word	0x01004200, 0x00000004, 0x00004004, 0x01004204
++	.word	0x01000004, 0x01004200, 0x01004000, 0x00004004
++	! nibble 7
++	.word	0x20800080, 0x20820000, 0x00020080, 0x00000000
++	.word	0x20020000, 0x00800080, 0x20800000, 0x20820080
++	.word	0x00000080, 0x20000000, 0x00820000, 0x00020080
++	.word	0x00820080, 0x20020080, 0x20000080, 0x20800000
++	.word	0x00020000, 0x00820080, 0x00800080, 0x20020000
++	.word	0x20820080, 0x20000080, 0x00000000, 0x00820000
++	.word	0x20000000, 0x00800000, 0x20020080, 0x20800080
++	.word	0x00800000, 0x00020000, 0x20820000, 0x00000080
++	.word	0x00800000, 0x00020000, 0x20000080, 0x20820080
++	.word	0x00020080, 0x20000000, 0x00000000, 0x00820000
++	.word	0x20800080, 0x20020080, 0x20020000, 0x00800080
++	.word	0x20820000, 0x00000080, 0x00800080, 0x20020000
++	.word	0x20820080, 0x00800000, 0x20800000, 0x20000080
++	.word	0x00820000, 0x00020080, 0x20020080, 0x20800000
++	.word	0x00000080, 0x20820000, 0x00820080, 0x00000000
++	.word	0x20000000, 0x20800080, 0x00020000, 0x00820080
++
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/des/asm/desboth.pl b/CryptoPkg/Library/OpensslLib/openssl/crypto/des/asm/desboth.pl
+new file mode 100644
+index 0000000..76759fb
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/des/asm/desboth.pl
+@@ -0,0 +1,86 @@
++#! /usr/bin/env perl
++# Copyright 1995-2016 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
++# in the file LICENSE in the source distribution or at
++# https://www.openssl.org/source/license.html
++
++
++$L="edi";
++$R="esi";
++
++sub DES_encrypt3
++	{
++	local($name,$enc)=@_;
++
++	&function_begin_B($name,"");
++	&push("ebx");
++	&mov("ebx",&wparam(0));
++
++	&push("ebp");
++	&push("esi");
++
++	&push("edi");
++
++	&comment("");
++	&comment("Load the data words");
++	&mov($L,&DWP(0,"ebx","",0));
++	&mov($R,&DWP(4,"ebx","",0));
++	&stack_push(3);
++
++	&comment("");
++	&comment("IP");
++	&IP_new($L,$R,"edx",0);
++
++	# put them back
++	
++	if ($enc)
++		{
++		&mov(&DWP(4,"ebx","",0),$R);
++		 &mov("eax",&wparam(1));
++		&mov(&DWP(0,"ebx","",0),"edx");
++		 &mov("edi",&wparam(2));
++		 &mov("esi",&wparam(3));
++		}
++	else
++		{
++		&mov(&DWP(4,"ebx","",0),$R);
++		 &mov("esi",&wparam(1));
++		&mov(&DWP(0,"ebx","",0),"edx");
++		 &mov("edi",&wparam(2));
++		 &mov("eax",&wparam(3));
++		}
++	&mov(&swtmp(2),	(DWC(($enc)?"1":"0")));
++	&mov(&swtmp(1),	"eax");
++	&mov(&swtmp(0),	"ebx");
++	&call("DES_encrypt2");
++	&mov(&swtmp(2),	(DWC(($enc)?"0":"1")));
++	&mov(&swtmp(1),	"edi");
++	&mov(&swtmp(0),	"ebx");
++	&call("DES_encrypt2");
++	&mov(&swtmp(2),	(DWC(($enc)?"1":"0")));
++	&mov(&swtmp(1),	"esi");
++	&mov(&swtmp(0),	"ebx");
++	&call("DES_encrypt2");
++
++	&stack_pop(3);
++	&mov($L,&DWP(0,"ebx","",0));
++	&mov($R,&DWP(4,"ebx","",0));
++
++	&comment("");
++	&comment("FP");
++	&FP_new($L,$R,"eax",0);
++
++	&mov(&DWP(0,"ebx","",0),"eax");
++	&mov(&DWP(4,"ebx","",0),$R);
++
++	&pop("edi");
++	&pop("esi");
++	&pop("ebp");
++	&pop("ebx");
++	&ret();
++	&function_end_B($name);
++	}
++
++
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/des/asm/dest4-sparcv9.pl b/CryptoPkg/Library/OpensslLib/openssl/crypto/des/asm/dest4-sparcv9.pl
+new file mode 100644
+index 0000000..4a6e29f
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/des/asm/dest4-sparcv9.pl
+@@ -0,0 +1,627 @@
++#! /usr/bin/env perl
++# Copyright 2013-2016 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
++# in the file LICENSE in the source distribution or at
++# https://www.openssl.org/source/license.html
++
++
++# ====================================================================
++# Written by David S. Miller  and Andy Polyakov
++# . The module is licensed under 2-clause BSD
++# license. March 2013. All rights reserved.
++# ====================================================================
++
++######################################################################
++# DES for SPARC T4.
++#
++# As with other hardware-assisted ciphers CBC encrypt results [for
++# aligned data] are virtually identical to critical path lengths:
++#
++#		DES		Triple-DES
++# CBC encrypt	4.14/4.15(*)	11.7/11.7
++# CBC decrypt	1.77/4.11(**)	6.42/7.47
++#
++#			 (*)	numbers after slash are for
++#				misaligned data;
++#			 (**)	this is result for largest
++#				block size, unlike all other
++#				cases smaller blocks results
++#				are better[?];
++
++$0 =~ m/(.*[\/\\])[^\/\\]+$/; $dir=$1;
++push(@INC,"${dir}","${dir}../../perlasm");
++require "sparcv9_modes.pl";
++
++$output=pop;
++open STDOUT,">$output";
++
++$code.=<<___;
++#include "sparc_arch.h"
++
++#ifdef	__arch64__
++.register       %g2,#scratch
++.register       %g3,#scratch
++#endif
++
++.text
++___
++
++{ my ($inp,$out)=("%o0","%o1");
++
++$code.=<<___;
++.align	32
++.globl	des_t4_key_expand
++.type	des_t4_key_expand,#function
++des_t4_key_expand:
++	andcc		$inp, 0x7, %g0
++	alignaddr	$inp, %g0, $inp
++	bz,pt		%icc, 1f
++	ldd		[$inp + 0x00], %f0
++	ldd		[$inp + 0x08], %f2
++	faligndata	%f0, %f2, %f0
++1:	des_kexpand	%f0, 0, %f0
++	des_kexpand	%f0, 1, %f2
++	std		%f0, [$out + 0x00]
++	des_kexpand	%f2, 3, %f6
++	std		%f2, [$out + 0x08]
++	des_kexpand	%f2, 2, %f4
++	des_kexpand	%f6, 3, %f10
++	std		%f6, [$out + 0x18]
++	des_kexpand	%f6, 2, %f8
++	std		%f4, [$out + 0x10]
++	des_kexpand	%f10, 3, %f14
++	std		%f10, [$out + 0x28]
++	des_kexpand	%f10, 2, %f12
++	std		%f8, [$out + 0x20]
++	des_kexpand	%f14, 1, %f16
++	std		%f14, [$out + 0x38]
++	des_kexpand	%f16, 3, %f20
++	std		%f12, [$out + 0x30]
++	des_kexpand	%f16, 2, %f18
++	std		%f16, [$out + 0x40]
++	des_kexpand	%f20, 3, %f24
++	std		%f20, [$out + 0x50]
++	des_kexpand	%f20, 2, %f22
++	std		%f18, [$out + 0x48]
++	des_kexpand	%f24, 3, %f28
++	std		%f24, [$out + 0x60]
++	des_kexpand	%f24, 2, %f26
++	std		%f22, [$out + 0x58]
++	des_kexpand	%f28, 1, %f30
++	std		%f28, [$out + 0x70]
++	std		%f26, [$out + 0x68]
++	retl
++	std		%f30, [$out + 0x78]
++.size	des_t4_key_expand,.-des_t4_key_expand
++___
++}
++{ my ($inp,$out,$len,$key,$ivec) = map("%o$_",(0..4));
++  my ($ileft,$iright,$omask) = map("%g$_",(1..3));
++
++$code.=<<___;
++.globl	des_t4_cbc_encrypt
++.align	32
++des_t4_cbc_encrypt:
++	cmp		$len, 0
++	be,pn		$::size_t_cc, .Lcbc_abort
++	srln		$len, 0, $len		! needed on v8+, "nop" on v9
++	ld		[$ivec + 0], %f0	! load ivec
++	ld		[$ivec + 4], %f1
++
++	and		$inp, 7, $ileft
++	andn		$inp, 7, $inp
++	sll		$ileft, 3, $ileft
++	mov		0xff, $omask
++	prefetch	[$inp], 20
++	prefetch	[$inp + 63], 20
++	sub		%g0, $ileft, $iright
++	and		$out, 7, %g4
++	alignaddrl	$out, %g0, $out
++	srl		$omask, %g4, $omask
++	srlx		$len, 3, $len
++	movrz		%g4, 0, $omask
++	prefetch	[$out], 22
++
++	ldd		[$key + 0x00], %f4	! load key schedule
++	ldd		[$key + 0x08], %f6
++	ldd		[$key + 0x10], %f8
++	ldd		[$key + 0x18], %f10
++	ldd		[$key + 0x20], %f12
++	ldd		[$key + 0x28], %f14
++	ldd		[$key + 0x30], %f16
++	ldd		[$key + 0x38], %f18
++	ldd		[$key + 0x40], %f20
++	ldd		[$key + 0x48], %f22
++	ldd		[$key + 0x50], %f24
++	ldd		[$key + 0x58], %f26
++	ldd		[$key + 0x60], %f28
++	ldd		[$key + 0x68], %f30
++	ldd		[$key + 0x70], %f32
++	ldd		[$key + 0x78], %f34
++
++.Ldes_cbc_enc_loop:
++	ldx		[$inp + 0], %g4
++	brz,pt		$ileft, 4f
++	nop
++
++	ldx		[$inp + 8], %g5
++	sllx		%g4, $ileft, %g4
++	srlx		%g5, $iright, %g5
++	or		%g5, %g4, %g4
++4:
++	movxtod		%g4, %f2
++	prefetch	[$inp + 8+63], 20
++	add		$inp, 8, $inp
++	fxor		%f2, %f0, %f0		! ^= ivec
++	prefetch	[$out + 63], 22
++
++	des_ip		%f0, %f0
++	des_round	%f4, %f6, %f0, %f0
++	des_round	%f8, %f10, %f0, %f0
++	des_round	%f12, %f14, %f0, %f0
++	des_round	%f16, %f18, %f0, %f0
++	des_round	%f20, %f22, %f0, %f0
++	des_round	%f24, %f26, %f0, %f0
++	des_round	%f28, %f30, %f0, %f0
++	des_round	%f32, %f34, %f0, %f0
++	des_iip		%f0, %f0
++
++	brnz,pn		$omask, 2f
++	sub		$len, 1, $len
++
++	std		%f0, [$out + 0]
++	brnz,pt		$len, .Ldes_cbc_enc_loop
++	add		$out, 8, $out
++
++	st		%f0, [$ivec + 0]	! write out ivec
++	retl
++	st		%f1, [$ivec + 4]
++.Lcbc_abort:
++	retl
++	nop
++
++.align	16
++2:	ldxa		[$inp]0x82, %g4		! avoid read-after-write hazard
++						! and ~4x deterioration
++						! in inp==out case
++	faligndata	%f0, %f0, %f2		! handle unaligned output
++
++	stda		%f2, [$out + $omask]0xc0	! partial store
++	add		$out, 8, $out
++	orn		%g0, $omask, $omask
++	stda		%f2, [$out + $omask]0xc0	! partial store
++
++	brnz,pt		$len, .Ldes_cbc_enc_loop+4
++	orn		%g0, $omask, $omask
++
++	st		%f0, [$ivec + 0]	! write out ivec
++	retl
++	st		%f1, [$ivec + 4]
++.type	des_t4_cbc_encrypt,#function
++.size	des_t4_cbc_encrypt,.-des_t4_cbc_encrypt
++
++.globl	des_t4_cbc_decrypt
++.align	32
++des_t4_cbc_decrypt:
++	cmp		$len, 0
++	be,pn		$::size_t_cc, .Lcbc_abort
++	srln		$len, 0, $len		! needed on v8+, "nop" on v9
++	ld		[$ivec + 0], %f2	! load ivec
++	ld		[$ivec + 4], %f3
++
++	and		$inp, 7, $ileft
++	andn		$inp, 7, $inp
++	sll		$ileft, 3, $ileft
++	mov		0xff, $omask
++	prefetch	[$inp], 20
++	prefetch	[$inp + 63], 20
++	sub		%g0, $ileft, $iright
++	and		$out, 7, %g4
++	alignaddrl	$out, %g0, $out
++	srl		$omask, %g4, $omask
++	srlx		$len, 3, $len
++	movrz		%g4, 0, $omask
++	prefetch	[$out], 22
++
++	ldd		[$key + 0x78], %f4	! load key schedule
++	ldd		[$key + 0x70], %f6
++	ldd		[$key + 0x68], %f8
++	ldd		[$key + 0x60], %f10
++	ldd		[$key + 0x58], %f12
++	ldd		[$key + 0x50], %f14
++	ldd		[$key + 0x48], %f16
++	ldd		[$key + 0x40], %f18
++	ldd		[$key + 0x38], %f20
++	ldd		[$key + 0x30], %f22
++	ldd		[$key + 0x28], %f24
++	ldd		[$key + 0x20], %f26
++	ldd		[$key + 0x18], %f28
++	ldd		[$key + 0x10], %f30
++	ldd		[$key + 0x08], %f32
++	ldd		[$key + 0x00], %f34
++
++.Ldes_cbc_dec_loop:
++	ldx		[$inp + 0], %g4
++	brz,pt		$ileft, 4f
++	nop
++
++	ldx		[$inp + 8], %g5
++	sllx		%g4, $ileft, %g4
++	srlx		%g5, $iright, %g5
++	or		%g5, %g4, %g4
++4:
++	movxtod		%g4, %f0
++	prefetch	[$inp + 8+63], 20
++	add		$inp, 8, $inp
++	prefetch	[$out + 63], 22
++
++	des_ip		%f0, %f0
++	des_round	%f4, %f6, %f0, %f0
++	des_round	%f8, %f10, %f0, %f0
++	des_round	%f12, %f14, %f0, %f0
++	des_round	%f16, %f18, %f0, %f0
++	des_round	%f20, %f22, %f0, %f0
++	des_round	%f24, %f26, %f0, %f0
++	des_round	%f28, %f30, %f0, %f0
++	des_round	%f32, %f34, %f0, %f0
++	des_iip		%f0, %f0
++
++	fxor		%f2, %f0, %f0		! ^= ivec
++	movxtod		%g4, %f2
++
++	brnz,pn		$omask, 2f
++	sub		$len, 1, $len
++
++	std		%f0, [$out + 0]
++	brnz,pt		$len, .Ldes_cbc_dec_loop
++	add		$out, 8, $out
++
++	st		%f2, [$ivec + 0]	! write out ivec
++	retl
++	st		%f3, [$ivec + 4]
++
++.align	16
++2:	ldxa		[$inp]0x82, %g4		! avoid read-after-write hazard
++						! and ~4x deterioration
++						! in inp==out case
++	faligndata	%f0, %f0, %f0		! handle unaligned output
++
++	stda		%f0, [$out + $omask]0xc0	! partial store
++	add		$out, 8, $out
++	orn		%g0, $omask, $omask
++	stda		%f0, [$out + $omask]0xc0	! partial store
++
++	brnz,pt		$len, .Ldes_cbc_dec_loop+4
++	orn		%g0, $omask, $omask
++
++	st		%f2, [$ivec + 0]	! write out ivec
++	retl
++	st		%f3, [$ivec + 4]
++.type	des_t4_cbc_decrypt,#function
++.size	des_t4_cbc_decrypt,.-des_t4_cbc_decrypt
++___
++
++# One might wonder why does one have back-to-back des_iip/des_ip
++# pairs between EDE passes. Indeed, aren't they inverse of each other?
++# They almost are. Outcome of the pair is 32-bit words being swapped
++# in target register. Consider pair of des_iip/des_ip as a way to
++# perform the due swap, it's actually fastest way in this case.
++
++$code.=<<___;
++.globl	des_t4_ede3_cbc_encrypt
++.align	32
++des_t4_ede3_cbc_encrypt:
++	cmp		$len, 0
++	be,pn		$::size_t_cc, .Lcbc_abort
++	srln		$len, 0, $len		! needed on v8+, "nop" on v9
++	ld		[$ivec + 0], %f0	! load ivec
++	ld		[$ivec + 4], %f1
++
++	and		$inp, 7, $ileft
++	andn		$inp, 7, $inp
++	sll		$ileft, 3, $ileft
++	mov		0xff, $omask
++	prefetch	[$inp], 20
++	prefetch	[$inp + 63], 20
++	sub		%g0, $ileft, $iright
++	and		$out, 7, %g4
++	alignaddrl	$out, %g0, $out
++	srl		$omask, %g4, $omask
++	srlx		$len, 3, $len
++	movrz		%g4, 0, $omask
++	prefetch	[$out], 22
++
++	ldd		[$key + 0x00], %f4	! load key schedule
++	ldd		[$key + 0x08], %f6
++	ldd		[$key + 0x10], %f8
++	ldd		[$key + 0x18], %f10
++	ldd		[$key + 0x20], %f12
++	ldd		[$key + 0x28], %f14
++	ldd		[$key + 0x30], %f16
++	ldd		[$key + 0x38], %f18
++	ldd		[$key + 0x40], %f20
++	ldd		[$key + 0x48], %f22
++	ldd		[$key + 0x50], %f24
++	ldd		[$key + 0x58], %f26
++	ldd		[$key + 0x60], %f28
++	ldd		[$key + 0x68], %f30
++	ldd		[$key + 0x70], %f32
++	ldd		[$key + 0x78], %f34
++
++.Ldes_ede3_cbc_enc_loop:
++	ldx		[$inp + 0], %g4
++	brz,pt		$ileft, 4f
++	nop
++
++	ldx		[$inp + 8], %g5
++	sllx		%g4, $ileft, %g4
++	srlx		%g5, $iright, %g5
++	or		%g5, %g4, %g4
++4:
++	movxtod		%g4, %f2
++	prefetch	[$inp + 8+63], 20
++	add		$inp, 8, $inp
++	fxor		%f2, %f0, %f0		! ^= ivec
++	prefetch	[$out + 63], 22
++
++	des_ip		%f0, %f0
++	des_round	%f4, %f6, %f0, %f0
++	des_round	%f8, %f10, %f0, %f0
++	des_round	%f12, %f14, %f0, %f0
++	des_round	%f16, %f18, %f0, %f0
++	ldd		[$key + 0x100-0x08], %f36
++	ldd		[$key + 0x100-0x10], %f38
++	des_round	%f20, %f22, %f0, %f0
++	ldd		[$key + 0x100-0x18], %f40
++	ldd		[$key + 0x100-0x20], %f42
++	des_round	%f24, %f26, %f0, %f0
++	ldd		[$key + 0x100-0x28], %f44
++	ldd		[$key + 0x100-0x30], %f46
++	des_round	%f28, %f30, %f0, %f0
++	ldd		[$key + 0x100-0x38], %f48
++	ldd		[$key + 0x100-0x40], %f50
++	des_round	%f32, %f34, %f0, %f0
++	ldd		[$key + 0x100-0x48], %f52
++	ldd		[$key + 0x100-0x50], %f54
++	des_iip		%f0, %f0
++
++	ldd		[$key + 0x100-0x58], %f56
++	ldd		[$key + 0x100-0x60], %f58
++	des_ip		%f0, %f0
++	ldd		[$key + 0x100-0x68], %f60
++	ldd		[$key + 0x100-0x70], %f62
++	des_round	%f36, %f38, %f0, %f0
++	ldd		[$key + 0x100-0x78], %f36
++	ldd		[$key + 0x100-0x80], %f38
++	des_round	%f40, %f42, %f0, %f0
++	des_round	%f44, %f46, %f0, %f0
++	des_round	%f48, %f50, %f0, %f0
++	ldd		[$key + 0x100+0x00], %f40
++	ldd		[$key + 0x100+0x08], %f42
++	des_round	%f52, %f54, %f0, %f0
++	ldd		[$key + 0x100+0x10], %f44
++	ldd		[$key + 0x100+0x18], %f46
++	des_round	%f56, %f58, %f0, %f0
++	ldd		[$key + 0x100+0x20], %f48
++	ldd		[$key + 0x100+0x28], %f50
++	des_round	%f60, %f62, %f0, %f0
++	ldd		[$key + 0x100+0x30], %f52
++	ldd		[$key + 0x100+0x38], %f54
++	des_round	%f36, %f38, %f0, %f0
++	ldd		[$key + 0x100+0x40], %f56
++	ldd		[$key + 0x100+0x48], %f58
++	des_iip		%f0, %f0
++
++	ldd		[$key + 0x100+0x50], %f60
++	ldd		[$key + 0x100+0x58], %f62
++	des_ip		%f0, %f0
++	ldd		[$key + 0x100+0x60], %f36
++	ldd		[$key + 0x100+0x68], %f38
++	des_round	%f40, %f42, %f0, %f0
++	ldd		[$key + 0x100+0x70], %f40
++	ldd		[$key + 0x100+0x78], %f42
++	des_round	%f44, %f46, %f0, %f0
++	des_round	%f48, %f50, %f0, %f0
++	des_round	%f52, %f54, %f0, %f0
++	des_round	%f56, %f58, %f0, %f0
++	des_round	%f60, %f62, %f0, %f0
++	des_round	%f36, %f38, %f0, %f0
++	des_round	%f40, %f42, %f0, %f0
++	des_iip		%f0, %f0
++
++	brnz,pn		$omask, 2f
++	sub		$len, 1, $len
++
++	std		%f0, [$out + 0]
++	brnz,pt		$len, .Ldes_ede3_cbc_enc_loop
++	add		$out, 8, $out
++
++	st		%f0, [$ivec + 0]	! write out ivec
++	retl
++	st		%f1, [$ivec + 4]
++
++.align	16
++2:	ldxa		[$inp]0x82, %g4		! avoid read-after-write hazard
++						! and ~2x deterioration
++						! in inp==out case
++	faligndata	%f0, %f0, %f2		! handle unaligned output
++
++	stda		%f2, [$out + $omask]0xc0	! partial store
++	add		$out, 8, $out
++	orn		%g0, $omask, $omask
++	stda		%f2, [$out + $omask]0xc0	! partial store
++
++	brnz,pt		$len, .Ldes_ede3_cbc_enc_loop+4
++	orn		%g0, $omask, $omask
++
++	st		%f0, [$ivec + 0]	! write out ivec
++	retl
++	st		%f1, [$ivec + 4]
++.type	des_t4_ede3_cbc_encrypt,#function
++.size	des_t4_ede3_cbc_encrypt,.-des_t4_ede3_cbc_encrypt
++
++.globl	des_t4_ede3_cbc_decrypt
++.align	32
++des_t4_ede3_cbc_decrypt:
++	cmp		$len, 0
++	be,pn		$::size_t_cc, .Lcbc_abort
++	srln		$len, 0, $len		! needed on v8+, "nop" on v9
++	ld		[$ivec + 0], %f2	! load ivec
++	ld		[$ivec + 4], %f3
++
++	and		$inp, 7, $ileft
++	andn		$inp, 7, $inp
++	sll		$ileft, 3, $ileft
++	mov		0xff, $omask
++	prefetch	[$inp], 20
++	prefetch	[$inp + 63], 20
++	sub		%g0, $ileft, $iright
++	and		$out, 7, %g4
++	alignaddrl	$out, %g0, $out
++	srl		$omask, %g4, $omask
++	srlx		$len, 3, $len
++	movrz		%g4, 0, $omask
++	prefetch	[$out], 22
++
++	ldd		[$key + 0x100+0x78], %f4	! load key schedule
++	ldd		[$key + 0x100+0x70], %f6
++	ldd		[$key + 0x100+0x68], %f8
++	ldd		[$key + 0x100+0x60], %f10
++	ldd		[$key + 0x100+0x58], %f12
++	ldd		[$key + 0x100+0x50], %f14
++	ldd		[$key + 0x100+0x48], %f16
++	ldd		[$key + 0x100+0x40], %f18
++	ldd		[$key + 0x100+0x38], %f20
++	ldd		[$key + 0x100+0x30], %f22
++	ldd		[$key + 0x100+0x28], %f24
++	ldd		[$key + 0x100+0x20], %f26
++	ldd		[$key + 0x100+0x18], %f28
++	ldd		[$key + 0x100+0x10], %f30
++	ldd		[$key + 0x100+0x08], %f32
++	ldd		[$key + 0x100+0x00], %f34
++
++.Ldes_ede3_cbc_dec_loop:
++	ldx		[$inp + 0], %g4
++	brz,pt		$ileft, 4f
++	nop
++
++	ldx		[$inp + 8], %g5
++	sllx		%g4, $ileft, %g4
++	srlx		%g5, $iright, %g5
++	or		%g5, %g4, %g4
++4:
++	movxtod		%g4, %f0
++	prefetch	[$inp + 8+63], 20
++	add		$inp, 8, $inp
++	prefetch	[$out + 63], 22
++
++	des_ip		%f0, %f0
++	des_round	%f4, %f6, %f0, %f0
++	des_round	%f8, %f10, %f0, %f0
++	des_round	%f12, %f14, %f0, %f0
++	des_round	%f16, %f18, %f0, %f0
++	ldd		[$key + 0x80+0x00], %f36
++	ldd		[$key + 0x80+0x08], %f38
++	des_round	%f20, %f22, %f0, %f0
++	ldd		[$key + 0x80+0x10], %f40
++	ldd		[$key + 0x80+0x18], %f42
++	des_round	%f24, %f26, %f0, %f0
++	ldd		[$key + 0x80+0x20], %f44
++	ldd		[$key + 0x80+0x28], %f46
++	des_round	%f28, %f30, %f0, %f0
++	ldd		[$key + 0x80+0x30], %f48
++	ldd		[$key + 0x80+0x38], %f50
++	des_round	%f32, %f34, %f0, %f0
++	ldd		[$key + 0x80+0x40], %f52
++	ldd		[$key + 0x80+0x48], %f54
++	des_iip		%f0, %f0
++
++	ldd		[$key + 0x80+0x50], %f56
++	ldd		[$key + 0x80+0x58], %f58
++	des_ip		%f0, %f0
++	ldd		[$key + 0x80+0x60], %f60
++	ldd		[$key + 0x80+0x68], %f62
++	des_round	%f36, %f38, %f0, %f0
++	ldd		[$key + 0x80+0x70], %f36
++	ldd		[$key + 0x80+0x78], %f38
++	des_round	%f40, %f42, %f0, %f0
++	des_round	%f44, %f46, %f0, %f0
++	des_round	%f48, %f50, %f0, %f0
++	ldd		[$key + 0x80-0x08], %f40
++	ldd		[$key + 0x80-0x10], %f42
++	des_round	%f52, %f54, %f0, %f0
++	ldd		[$key + 0x80-0x18], %f44
++	ldd		[$key + 0x80-0x20], %f46
++	des_round	%f56, %f58, %f0, %f0
++	ldd		[$key + 0x80-0x28], %f48
++	ldd		[$key + 0x80-0x30], %f50
++	des_round	%f60, %f62, %f0, %f0
++	ldd		[$key + 0x80-0x38], %f52
++	ldd		[$key + 0x80-0x40], %f54
++	des_round	%f36, %f38, %f0, %f0
++	ldd		[$key + 0x80-0x48], %f56
++	ldd		[$key + 0x80-0x50], %f58
++	des_iip		%f0, %f0
++
++	ldd		[$key + 0x80-0x58], %f60
++	ldd		[$key + 0x80-0x60], %f62
++	des_ip		%f0, %f0
++	ldd		[$key + 0x80-0x68], %f36
++	ldd		[$key + 0x80-0x70], %f38
++	des_round	%f40, %f42, %f0, %f0
++	ldd		[$key + 0x80-0x78], %f40
++	ldd		[$key + 0x80-0x80], %f42
++	des_round	%f44, %f46, %f0, %f0
++	des_round	%f48, %f50, %f0, %f0
++	des_round	%f52, %f54, %f0, %f0
++	des_round	%f56, %f58, %f0, %f0
++	des_round	%f60, %f62, %f0, %f0
++	des_round	%f36, %f38, %f0, %f0
++	des_round	%f40, %f42, %f0, %f0
++	des_iip		%f0, %f0
++
++	fxor		%f2, %f0, %f0		! ^= ivec
++	movxtod		%g4, %f2
++
++	brnz,pn		$omask, 2f
++	sub		$len, 1, $len
++
++	std		%f0, [$out + 0]
++	brnz,pt		$len, .Ldes_ede3_cbc_dec_loop
++	add		$out, 8, $out
++
++	st		%f2, [$ivec + 0]	! write out ivec
++	retl
++	st		%f3, [$ivec + 4]
++
++.align	16
++2:	ldxa		[$inp]0x82, %g4		! avoid read-after-write hazard
++						! and ~3x deterioration
++						! in inp==out case
++	faligndata	%f0, %f0, %f0		! handle unaligned output
++
++	stda		%f0, [$out + $omask]0xc0	! partial store
++	add		$out, 8, $out
++	orn		%g0, $omask, $omask
++	stda		%f0, [$out + $omask]0xc0	! partial store
++
++	brnz,pt		$len, .Ldes_ede3_cbc_dec_loop+4
++	orn		%g0, $omask, $omask
++
++	st		%f2, [$ivec + 0]	! write out ivec
++	retl
++	st		%f3, [$ivec + 4]
++.type	des_t4_ede3_cbc_decrypt,#function
++.size	des_t4_ede3_cbc_decrypt,.-des_t4_ede3_cbc_decrypt
++___
++}
++$code.=<<___;
++.asciz  "DES for SPARC T4, David S. Miller, Andy Polyakov"
++.align  4
++___
++
++&emit_assembler();
++
++close STDOUT;
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/des/build.info b/CryptoPkg/Library/OpensslLib/openssl/crypto/des/build.info
+new file mode 100644
+index 0000000..c0306cf
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/des/build.info
+@@ -0,0 +1,17 @@
++LIBS=../../libcrypto
++SOURCE[../../libcrypto]=\
++        set_key.c  ecb_enc.c  cbc_enc.c \
++        ecb3_enc.c cfb64enc.c cfb64ede.c cfb_enc.c \
++        ofb64ede.c ofb64enc.c ofb_enc.c \
++        str2key.c  pcbc_enc.c qud_cksm.c rand_key.c \
++        {- $target{des_asm_src} -} \
++        fcrypt.c xcbc_enc.c rpc_enc.c  cbc_cksm.c
++
++GENERATE[des_enc-sparc.S]=asm/des_enc.m4
++GENERATE[dest4-sparcv9.S]=asm/dest4-sparcv9.pl $(PERLASM_SCHEME)
++INCLUDE[dest4-sparcv9.o]=..
++
++GENERATE[des-586.s]=asm/des-586.pl $(PERLASM_SCHEME) $(CFLAGS) $(LIB_CFLAGS)
++DEPEND[des-586.s]=../perlasm/x86asm.pl ../perlasm/cbc.pl
++GENERATE[crypt586.s]=asm/crypt586.pl $(PERLASM_SCHEME) $(CFLAGS) $(LIB_CFLAGS)
++DEPEND[crypt586.s]=../perlasm/x86asm.pl ../perlasm/cbc.pl
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/des/cbc_cksm.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/des/cbc_cksm.c
+new file mode 100644
+index 0000000..a7bf068
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/des/cbc_cksm.c
+@@ -0,0 +1,54 @@
++/*
++ * Copyright 1995-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include "des_locl.h"
++
++DES_LONG DES_cbc_cksum(const unsigned char *in, DES_cblock *output,
++                       long length, DES_key_schedule *schedule,
++                       const_DES_cblock *ivec)
++{
++    register DES_LONG tout0, tout1, tin0, tin1;
++    register long l = length;
++    DES_LONG tin[2];
++    unsigned char *out = &(*output)[0];
++    const unsigned char *iv = &(*ivec)[0];
++
++    c2l(iv, tout0);
++    c2l(iv, tout1);
++    for (; l > 0; l -= 8) {
++        if (l >= 8) {
++            c2l(in, tin0);
++            c2l(in, tin1);
++        } else
++            c2ln(in, tin0, tin1, l);
++
++        tin0 ^= tout0;
++        tin[0] = tin0;
++        tin1 ^= tout1;
++        tin[1] = tin1;
++        DES_encrypt1((DES_LONG *)tin, schedule, DES_ENCRYPT);
++        /* fix 15/10/91 eay - thanks to keithr@sco.COM */
++        tout0 = tin[0];
++        tout1 = tin[1];
++    }
++    if (out != NULL) {
++        l2c(tout0, out);
++        l2c(tout1, out);
++    }
++    tout0 = tin0 = tin1 = tin[0] = tin[1] = 0;
++    /*
++     * Transform the data in tout1 so that it will match the return value
++     * that the MIT Kerberos mit_des_cbc_cksum API returns.
++     */
++    tout1 = ((tout1 >> 24L) & 0x000000FF)
++        | ((tout1 >> 8L) & 0x0000FF00)
++        | ((tout1 << 8L) & 0x00FF0000)
++        | ((tout1 << 24L) & 0xFF000000);
++    return (tout1);
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/des/cbc_enc.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/des/cbc_enc.c
+new file mode 100644
+index 0000000..92e773f
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/des/cbc_enc.c
+@@ -0,0 +1,12 @@
++/*
++ * Copyright 1995-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#define CBC_ENC_C__DONT_UPDATE_IV
++
++#include "ncbc_enc.c"           /* des_cbc_encrypt */
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/des/cfb64ede.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/des/cfb64ede.c
+new file mode 100644
+index 0000000..5edb979
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/des/cfb64ede.c
+@@ -0,0 +1,190 @@
++/*
++ * Copyright 1995-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include "des_locl.h"
++#include "e_os.h"
++
++/*
++ * The input and output encrypted as though 64bit cfb mode is being used.
++ * The extra state information to record how much of the 64bit block we have
++ * used is contained in *num;
++ */
++
++void DES_ede3_cfb64_encrypt(const unsigned char *in, unsigned char *out,
++                            long length, DES_key_schedule *ks1,
++                            DES_key_schedule *ks2, DES_key_schedule *ks3,
++                            DES_cblock *ivec, int *num, int enc)
++{
++    register DES_LONG v0, v1;
++    register long l = length;
++    register int n = *num;
++    DES_LONG ti[2];
++    unsigned char *iv, c, cc;
++
++    iv = &(*ivec)[0];
++    if (enc) {
++        while (l--) {
++            if (n == 0) {
++                c2l(iv, v0);
++                c2l(iv, v1);
++
++                ti[0] = v0;
++                ti[1] = v1;
++                DES_encrypt3(ti, ks1, ks2, ks3);
++                v0 = ti[0];
++                v1 = ti[1];
++
++                iv = &(*ivec)[0];
++                l2c(v0, iv);
++                l2c(v1, iv);
++                iv = &(*ivec)[0];
++            }
++            c = *(in++) ^ iv[n];
++            *(out++) = c;
++            iv[n] = c;
++            n = (n + 1) & 0x07;
++        }
++    } else {
++        while (l--) {
++            if (n == 0) {
++                c2l(iv, v0);
++                c2l(iv, v1);
++
++                ti[0] = v0;
++                ti[1] = v1;
++                DES_encrypt3(ti, ks1, ks2, ks3);
++                v0 = ti[0];
++                v1 = ti[1];
++
++                iv = &(*ivec)[0];
++                l2c(v0, iv);
++                l2c(v1, iv);
++                iv = &(*ivec)[0];
++            }
++            cc = *(in++);
++            c = iv[n];
++            iv[n] = cc;
++            *(out++) = c ^ cc;
++            n = (n + 1) & 0x07;
++        }
++    }
++    v0 = v1 = ti[0] = ti[1] = c = cc = 0;
++    *num = n;
++}
++
++/*
++ * This is compatible with the single key CFB-r for DES, even thought that's
++ * not what EVP needs.
++ */
++
++void DES_ede3_cfb_encrypt(const unsigned char *in, unsigned char *out,
++                          int numbits, long length, DES_key_schedule *ks1,
++                          DES_key_schedule *ks2, DES_key_schedule *ks3,
++                          DES_cblock *ivec, int enc)
++{
++    register DES_LONG d0, d1, v0, v1;
++    register unsigned long l = length, n = ((unsigned int)numbits + 7) / 8;
++    register int num = numbits, i;
++    DES_LONG ti[2];
++    unsigned char *iv;
++    unsigned char ovec[16];
++
++    if (num > 64)
++        return;
++    iv = &(*ivec)[0];
++    c2l(iv, v0);
++    c2l(iv, v1);
++    if (enc) {
++        while (l >= n) {
++            l -= n;
++            ti[0] = v0;
++            ti[1] = v1;
++            DES_encrypt3(ti, ks1, ks2, ks3);
++            c2ln(in, d0, d1, n);
++            in += n;
++            d0 ^= ti[0];
++            d1 ^= ti[1];
++            l2cn(d0, d1, out, n);
++            out += n;
++            /*
++             * 30-08-94 - eay - changed because l>>32 and l<<32 are bad under
++             * gcc :-(
++             */
++            if (num == 32) {
++                v0 = v1;
++                v1 = d0;
++            } else if (num == 64) {
++                v0 = d0;
++                v1 = d1;
++            } else {
++                iv = &ovec[0];
++                l2c(v0, iv);
++                l2c(v1, iv);
++                l2c(d0, iv);
++                l2c(d1, iv);
++                /* shift ovec left most of the bits... */
++                memmove(ovec, ovec + num / 8, 8 + (num % 8 ? 1 : 0));
++                /* now the remaining bits */
++                if (num % 8 != 0)
++                    for (i = 0; i < 8; ++i) {
++                        ovec[i] <<= num % 8;
++                        ovec[i] |= ovec[i + 1] >> (8 - num % 8);
++                    }
++                iv = &ovec[0];
++                c2l(iv, v0);
++                c2l(iv, v1);
++            }
++        }
++    } else {
++        while (l >= n) {
++            l -= n;
++            ti[0] = v0;
++            ti[1] = v1;
++            DES_encrypt3(ti, ks1, ks2, ks3);
++            c2ln(in, d0, d1, n);
++            in += n;
++            /*
++             * 30-08-94 - eay - changed because l>>32 and l<<32 are bad under
++             * gcc :-(
++             */
++            if (num == 32) {
++                v0 = v1;
++                v1 = d0;
++            } else if (num == 64) {
++                v0 = d0;
++                v1 = d1;
++            } else {
++                iv = &ovec[0];
++                l2c(v0, iv);
++                l2c(v1, iv);
++                l2c(d0, iv);
++                l2c(d1, iv);
++                /* shift ovec left most of the bits... */
++                memmove(ovec, ovec + num / 8, 8 + (num % 8 ? 1 : 0));
++                /* now the remaining bits */
++                if (num % 8 != 0)
++                    for (i = 0; i < 8; ++i) {
++                        ovec[i] <<= num % 8;
++                        ovec[i] |= ovec[i + 1] >> (8 - num % 8);
++                    }
++                iv = &ovec[0];
++                c2l(iv, v0);
++                c2l(iv, v1);
++            }
++            d0 ^= ti[0];
++            d1 ^= ti[1];
++            l2cn(d0, d1, out, n);
++            out += n;
++        }
++    }
++    iv = &(*ivec)[0];
++    l2c(v0, iv);
++    l2c(v1, iv);
++    v0 = v1 = d0 = d1 = ti[0] = ti[1] = 0;
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/des/cfb64enc.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/des/cfb64enc.c
+new file mode 100644
+index 0000000..96de51b
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/des/cfb64enc.c
+@@ -0,0 +1,73 @@
++/*
++ * Copyright 1995-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include "des_locl.h"
++
++/*
++ * The input and output encrypted as though 64bit cfb mode is being used.
++ * The extra state information to record how much of the 64bit block we have
++ * used is contained in *num;
++ */
++
++void DES_cfb64_encrypt(const unsigned char *in, unsigned char *out,
++                       long length, DES_key_schedule *schedule,
++                       DES_cblock *ivec, int *num, int enc)
++{
++    register DES_LONG v0, v1;
++    register long l = length;
++    register int n = *num;
++    DES_LONG ti[2];
++    unsigned char *iv, c, cc;
++
++    iv = &(*ivec)[0];
++    if (enc) {
++        while (l--) {
++            if (n == 0) {
++                c2l(iv, v0);
++                ti[0] = v0;
++                c2l(iv, v1);
++                ti[1] = v1;
++                DES_encrypt1(ti, schedule, DES_ENCRYPT);
++                iv = &(*ivec)[0];
++                v0 = ti[0];
++                l2c(v0, iv);
++                v0 = ti[1];
++                l2c(v0, iv);
++                iv = &(*ivec)[0];
++            }
++            c = *(in++) ^ iv[n];
++            *(out++) = c;
++            iv[n] = c;
++            n = (n + 1) & 0x07;
++        }
++    } else {
++        while (l--) {
++            if (n == 0) {
++                c2l(iv, v0);
++                ti[0] = v0;
++                c2l(iv, v1);
++                ti[1] = v1;
++                DES_encrypt1(ti, schedule, DES_ENCRYPT);
++                iv = &(*ivec)[0];
++                v0 = ti[0];
++                l2c(v0, iv);
++                v0 = ti[1];
++                l2c(v0, iv);
++                iv = &(*ivec)[0];
++            }
++            cc = *(in++);
++            c = iv[n];
++            iv[n] = cc;
++            *(out++) = c ^ cc;
++            n = (n + 1) & 0x07;
++        }
++    }
++    v0 = v1 = ti[0] = ti[1] = c = cc = 0;
++    *num = n;
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/des/cfb_enc.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/des/cfb_enc.c
+new file mode 100644
+index 0000000..6c428ba
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/des/cfb_enc.c
+@@ -0,0 +1,150 @@
++/*
++ * Copyright 1995-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include "e_os.h"
++#include "des_locl.h"
++#include 
++
++/*
++ * The input and output are loaded in multiples of 8 bits. What this means is
++ * that if you hame numbits=12 and length=2 the first 12 bits will be
++ * retrieved from the first byte and half the second.  The second 12 bits
++ * will come from the 3rd and half the 4th byte.
++ */
++/*
++ * Until Aug 1 2003 this function did not correctly implement CFB-r, so it
++ * will not be compatible with any encryption prior to that date. Ben.
++ */
++void DES_cfb_encrypt(const unsigned char *in, unsigned char *out, int numbits,
++                     long length, DES_key_schedule *schedule,
++                     DES_cblock *ivec, int enc)
++{
++    register DES_LONG d0, d1, v0, v1;
++    register unsigned long l = length;
++    register int num = numbits / 8, n = (numbits + 7) / 8, i, rem =
++        numbits % 8;
++    DES_LONG ti[2];
++    unsigned char *iv;
++#ifndef L_ENDIAN
++    unsigned char ovec[16];
++#else
++    unsigned int sh[4];
++    unsigned char *ovec = (unsigned char *)sh;
++
++    /* I kind of count that compiler optimizes away this assertioni, */
++    assert(sizeof(sh[0]) == 4); /* as this holds true for all, */
++    /* but 16-bit platforms...      */
++
++#endif
++
++    if (numbits <= 0 || numbits > 64)
++        return;
++    iv = &(*ivec)[0];
++    c2l(iv, v0);
++    c2l(iv, v1);
++    if (enc) {
++        while (l >= (unsigned long)n) {
++            l -= n;
++            ti[0] = v0;
++            ti[1] = v1;
++            DES_encrypt1((DES_LONG *)ti, schedule, DES_ENCRYPT);
++            c2ln(in, d0, d1, n);
++            in += n;
++            d0 ^= ti[0];
++            d1 ^= ti[1];
++            l2cn(d0, d1, out, n);
++            out += n;
++            /*
++             * 30-08-94 - eay - changed because l>>32 and l<<32 are bad under
++             * gcc :-(
++             */
++            if (numbits == 32) {
++                v0 = v1;
++                v1 = d0;
++            } else if (numbits == 64) {
++                v0 = d0;
++                v1 = d1;
++            } else {
++#ifndef L_ENDIAN
++                iv = &ovec[0];
++                l2c(v0, iv);
++                l2c(v1, iv);
++                l2c(d0, iv);
++                l2c(d1, iv);
++#else
++                sh[0] = v0, sh[1] = v1, sh[2] = d0, sh[3] = d1;
++#endif
++                if (rem == 0)
++                    memmove(ovec, ovec + num, 8);
++                else
++                    for (i = 0; i < 8; ++i)
++                        ovec[i] = ovec[i + num] << rem |
++                            ovec[i + num + 1] >> (8 - rem);
++#ifdef L_ENDIAN
++                v0 = sh[0], v1 = sh[1];
++#else
++                iv = &ovec[0];
++                c2l(iv, v0);
++                c2l(iv, v1);
++#endif
++            }
++        }
++    } else {
++        while (l >= (unsigned long)n) {
++            l -= n;
++            ti[0] = v0;
++            ti[1] = v1;
++            DES_encrypt1((DES_LONG *)ti, schedule, DES_ENCRYPT);
++            c2ln(in, d0, d1, n);
++            in += n;
++            /*
++             * 30-08-94 - eay - changed because l>>32 and l<<32 are bad under
++             * gcc :-(
++             */
++            if (numbits == 32) {
++                v0 = v1;
++                v1 = d0;
++            } else if (numbits == 64) {
++                v0 = d0;
++                v1 = d1;
++            } else {
++#ifndef L_ENDIAN
++                iv = &ovec[0];
++                l2c(v0, iv);
++                l2c(v1, iv);
++                l2c(d0, iv);
++                l2c(d1, iv);
++#else
++                sh[0] = v0, sh[1] = v1, sh[2] = d0, sh[3] = d1;
++#endif
++                if (rem == 0)
++                    memmove(ovec, ovec + num, 8);
++                else
++                    for (i = 0; i < 8; ++i)
++                        ovec[i] = ovec[i + num] << rem |
++                            ovec[i + num + 1] >> (8 - rem);
++#ifdef L_ENDIAN
++                v0 = sh[0], v1 = sh[1];
++#else
++                iv = &ovec[0];
++                c2l(iv, v0);
++                c2l(iv, v1);
++#endif
++            }
++            d0 ^= ti[0];
++            d1 ^= ti[1];
++            l2cn(d0, d1, out, n);
++            out += n;
++        }
++    }
++    iv = &(*ivec)[0];
++    l2c(v0, iv);
++    l2c(v1, iv);
++    v0 = v1 = d0 = d1 = ti[0] = ti[1] = 0;
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/des/des_enc.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/des/des_enc.c
+new file mode 100644
+index 0000000..600f6df
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/des/des_enc.c
+@@ -0,0 +1,301 @@
++/*
++ * Copyright 1995-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include "des_locl.h"
++#include "spr.h"
++
++void DES_encrypt1(DES_LONG *data, DES_key_schedule *ks, int enc)
++{
++    register DES_LONG l, r, t, u;
++    register DES_LONG *s;
++
++    r = data[0];
++    l = data[1];
++
++    IP(r, l);
++    /*
++     * Things have been modified so that the initial rotate is done outside
++     * the loop.  This required the DES_SPtrans values in sp.h to be rotated
++     * 1 bit to the right. One perl script later and things have a 5% speed
++     * up on a sparc2. Thanks to Richard Outerbridge
++     * <71755.204@CompuServe.COM> for pointing this out.
++     */
++    /* clear the top bits on machines with 8byte longs */
++    /* shift left by 2 */
++    r = ROTATE(r, 29) & 0xffffffffL;
++    l = ROTATE(l, 29) & 0xffffffffL;
++
++    s = ks->ks->deslong;
++    /*
++     * I don't know if it is worth the effort of loop unrolling the inner
++     * loop
++     */
++    if (enc) {
++        D_ENCRYPT(l, r, 0);     /* 1 */
++        D_ENCRYPT(r, l, 2);     /* 2 */
++        D_ENCRYPT(l, r, 4);     /* 3 */
++        D_ENCRYPT(r, l, 6);     /* 4 */
++        D_ENCRYPT(l, r, 8);     /* 5 */
++        D_ENCRYPT(r, l, 10);    /* 6 */
++        D_ENCRYPT(l, r, 12);    /* 7 */
++        D_ENCRYPT(r, l, 14);    /* 8 */
++        D_ENCRYPT(l, r, 16);    /* 9 */
++        D_ENCRYPT(r, l, 18);    /* 10 */
++        D_ENCRYPT(l, r, 20);    /* 11 */
++        D_ENCRYPT(r, l, 22);    /* 12 */
++        D_ENCRYPT(l, r, 24);    /* 13 */
++        D_ENCRYPT(r, l, 26);    /* 14 */
++        D_ENCRYPT(l, r, 28);    /* 15 */
++        D_ENCRYPT(r, l, 30);    /* 16 */
++    } else {
++        D_ENCRYPT(l, r, 30);    /* 16 */
++        D_ENCRYPT(r, l, 28);    /* 15 */
++        D_ENCRYPT(l, r, 26);    /* 14 */
++        D_ENCRYPT(r, l, 24);    /* 13 */
++        D_ENCRYPT(l, r, 22);    /* 12 */
++        D_ENCRYPT(r, l, 20);    /* 11 */
++        D_ENCRYPT(l, r, 18);    /* 10 */
++        D_ENCRYPT(r, l, 16);    /* 9 */
++        D_ENCRYPT(l, r, 14);    /* 8 */
++        D_ENCRYPT(r, l, 12);    /* 7 */
++        D_ENCRYPT(l, r, 10);    /* 6 */
++        D_ENCRYPT(r, l, 8);     /* 5 */
++        D_ENCRYPT(l, r, 6);     /* 4 */
++        D_ENCRYPT(r, l, 4);     /* 3 */
++        D_ENCRYPT(l, r, 2);     /* 2 */
++        D_ENCRYPT(r, l, 0);     /* 1 */
++    }
++
++    /* rotate and clear the top bits on machines with 8byte longs */
++    l = ROTATE(l, 3) & 0xffffffffL;
++    r = ROTATE(r, 3) & 0xffffffffL;
++
++    FP(r, l);
++    data[0] = l;
++    data[1] = r;
++    l = r = t = u = 0;
++}
++
++void DES_encrypt2(DES_LONG *data, DES_key_schedule *ks, int enc)
++{
++    register DES_LONG l, r, t, u;
++    register DES_LONG *s;
++
++    r = data[0];
++    l = data[1];
++
++    /*
++     * Things have been modified so that the initial rotate is done outside
++     * the loop.  This required the DES_SPtrans values in sp.h to be rotated
++     * 1 bit to the right. One perl script later and things have a 5% speed
++     * up on a sparc2. Thanks to Richard Outerbridge
++     * <71755.204@CompuServe.COM> for pointing this out.
++     */
++    /* clear the top bits on machines with 8byte longs */
++    r = ROTATE(r, 29) & 0xffffffffL;
++    l = ROTATE(l, 29) & 0xffffffffL;
++
++    s = ks->ks->deslong;
++    /*
++     * I don't know if it is worth the effort of loop unrolling the inner
++     * loop
++     */
++    if (enc) {
++        D_ENCRYPT(l, r, 0);     /* 1 */
++        D_ENCRYPT(r, l, 2);     /* 2 */
++        D_ENCRYPT(l, r, 4);     /* 3 */
++        D_ENCRYPT(r, l, 6);     /* 4 */
++        D_ENCRYPT(l, r, 8);     /* 5 */
++        D_ENCRYPT(r, l, 10);    /* 6 */
++        D_ENCRYPT(l, r, 12);    /* 7 */
++        D_ENCRYPT(r, l, 14);    /* 8 */
++        D_ENCRYPT(l, r, 16);    /* 9 */
++        D_ENCRYPT(r, l, 18);    /* 10 */
++        D_ENCRYPT(l, r, 20);    /* 11 */
++        D_ENCRYPT(r, l, 22);    /* 12 */
++        D_ENCRYPT(l, r, 24);    /* 13 */
++        D_ENCRYPT(r, l, 26);    /* 14 */
++        D_ENCRYPT(l, r, 28);    /* 15 */
++        D_ENCRYPT(r, l, 30);    /* 16 */
++    } else {
++        D_ENCRYPT(l, r, 30);    /* 16 */
++        D_ENCRYPT(r, l, 28);    /* 15 */
++        D_ENCRYPT(l, r, 26);    /* 14 */
++        D_ENCRYPT(r, l, 24);    /* 13 */
++        D_ENCRYPT(l, r, 22);    /* 12 */
++        D_ENCRYPT(r, l, 20);    /* 11 */
++        D_ENCRYPT(l, r, 18);    /* 10 */
++        D_ENCRYPT(r, l, 16);    /* 9 */
++        D_ENCRYPT(l, r, 14);    /* 8 */
++        D_ENCRYPT(r, l, 12);    /* 7 */
++        D_ENCRYPT(l, r, 10);    /* 6 */
++        D_ENCRYPT(r, l, 8);     /* 5 */
++        D_ENCRYPT(l, r, 6);     /* 4 */
++        D_ENCRYPT(r, l, 4);     /* 3 */
++        D_ENCRYPT(l, r, 2);     /* 2 */
++        D_ENCRYPT(r, l, 0);     /* 1 */
++    }
++    /* rotate and clear the top bits on machines with 8byte longs */
++    data[0] = ROTATE(l, 3) & 0xffffffffL;
++    data[1] = ROTATE(r, 3) & 0xffffffffL;
++    l = r = t = u = 0;
++}
++
++void DES_encrypt3(DES_LONG *data, DES_key_schedule *ks1,
++                  DES_key_schedule *ks2, DES_key_schedule *ks3)
++{
++    register DES_LONG l, r;
++
++    l = data[0];
++    r = data[1];
++    IP(l, r);
++    data[0] = l;
++    data[1] = r;
++    DES_encrypt2((DES_LONG *)data, ks1, DES_ENCRYPT);
++    DES_encrypt2((DES_LONG *)data, ks2, DES_DECRYPT);
++    DES_encrypt2((DES_LONG *)data, ks3, DES_ENCRYPT);
++    l = data[0];
++    r = data[1];
++    FP(r, l);
++    data[0] = l;
++    data[1] = r;
++}
++
++void DES_decrypt3(DES_LONG *data, DES_key_schedule *ks1,
++                  DES_key_schedule *ks2, DES_key_schedule *ks3)
++{
++    register DES_LONG l, r;
++
++    l = data[0];
++    r = data[1];
++    IP(l, r);
++    data[0] = l;
++    data[1] = r;
++    DES_encrypt2((DES_LONG *)data, ks3, DES_DECRYPT);
++    DES_encrypt2((DES_LONG *)data, ks2, DES_ENCRYPT);
++    DES_encrypt2((DES_LONG *)data, ks1, DES_DECRYPT);
++    l = data[0];
++    r = data[1];
++    FP(r, l);
++    data[0] = l;
++    data[1] = r;
++}
++
++#ifndef DES_DEFAULT_OPTIONS
++
++# undef CBC_ENC_C__DONT_UPDATE_IV
++# include "ncbc_enc.c"          /* DES_ncbc_encrypt */
++
++void DES_ede3_cbc_encrypt(const unsigned char *input, unsigned char *output,
++                          long length, DES_key_schedule *ks1,
++                          DES_key_schedule *ks2, DES_key_schedule *ks3,
++                          DES_cblock *ivec, int enc)
++{
++    register DES_LONG tin0, tin1;
++    register DES_LONG tout0, tout1, xor0, xor1;
++    register const unsigned char *in;
++    unsigned char *out;
++    register long l = length;
++    DES_LONG tin[2];
++    unsigned char *iv;
++
++    in = input;
++    out = output;
++    iv = &(*ivec)[0];
++
++    if (enc) {
++        c2l(iv, tout0);
++        c2l(iv, tout1);
++        for (l -= 8; l >= 0; l -= 8) {
++            c2l(in, tin0);
++            c2l(in, tin1);
++            tin0 ^= tout0;
++            tin1 ^= tout1;
++
++            tin[0] = tin0;
++            tin[1] = tin1;
++            DES_encrypt3((DES_LONG *)tin, ks1, ks2, ks3);
++            tout0 = tin[0];
++            tout1 = tin[1];
++
++            l2c(tout0, out);
++            l2c(tout1, out);
++        }
++        if (l != -8) {
++            c2ln(in, tin0, tin1, l + 8);
++            tin0 ^= tout0;
++            tin1 ^= tout1;
++
++            tin[0] = tin0;
++            tin[1] = tin1;
++            DES_encrypt3((DES_LONG *)tin, ks1, ks2, ks3);
++            tout0 = tin[0];
++            tout1 = tin[1];
++
++            l2c(tout0, out);
++            l2c(tout1, out);
++        }
++        iv = &(*ivec)[0];
++        l2c(tout0, iv);
++        l2c(tout1, iv);
++    } else {
++        register DES_LONG t0, t1;
++
++        c2l(iv, xor0);
++        c2l(iv, xor1);
++        for (l -= 8; l >= 0; l -= 8) {
++            c2l(in, tin0);
++            c2l(in, tin1);
++
++            t0 = tin0;
++            t1 = tin1;
++
++            tin[0] = tin0;
++            tin[1] = tin1;
++            DES_decrypt3((DES_LONG *)tin, ks1, ks2, ks3);
++            tout0 = tin[0];
++            tout1 = tin[1];
++
++            tout0 ^= xor0;
++            tout1 ^= xor1;
++            l2c(tout0, out);
++            l2c(tout1, out);
++            xor0 = t0;
++            xor1 = t1;
++        }
++        if (l != -8) {
++            c2l(in, tin0);
++            c2l(in, tin1);
++
++            t0 = tin0;
++            t1 = tin1;
++
++            tin[0] = tin0;
++            tin[1] = tin1;
++            DES_decrypt3((DES_LONG *)tin, ks1, ks2, ks3);
++            tout0 = tin[0];
++            tout1 = tin[1];
++
++            tout0 ^= xor0;
++            tout1 ^= xor1;
++            l2cn(tout0, tout1, out, l + 8);
++            xor0 = t0;
++            xor1 = t1;
++        }
++
++        iv = &(*ivec)[0];
++        l2c(xor0, iv);
++        l2c(xor1, iv);
++    }
++    tin0 = tin1 = tout0 = tout1 = xor0 = xor1 = 0;
++    tin[0] = tin[1] = 0;
++}
++
++#endif                          /* DES_DEFAULT_OPTIONS */
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/des/des_locl.h b/CryptoPkg/Library/OpensslLib/openssl/crypto/des/des_locl.h
+new file mode 100644
+index 0000000..53881d4
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/des/des_locl.h
+@@ -0,0 +1,217 @@
++/*
++ * Copyright 1995-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#ifndef HEADER_DES_LOCL_H
++# define HEADER_DES_LOCL_H
++
++# include 
++
++# include 
++# include 
++# include 
++
++# include 
++
++# ifdef OPENSSL_BUILD_SHLIBCRYPTO
++#  undef OPENSSL_EXTERN
++#  define OPENSSL_EXTERN OPENSSL_EXPORT
++# endif
++
++# define ITERATIONS 16
++# define HALF_ITERATIONS 8
++
++/* used in des_read and des_write */
++# define MAXWRITE        (1024*16)
++# define BSIZE           (MAXWRITE+4)
++
++# define c2l(c,l)        (l =((DES_LONG)(*((c)++)))    , \
++                         l|=((DES_LONG)(*((c)++)))<< 8L, \
++                         l|=((DES_LONG)(*((c)++)))<<16L, \
++                         l|=((DES_LONG)(*((c)++)))<<24L)
++
++/* NOTE - c is not incremented as per c2l */
++# define c2ln(c,l1,l2,n) { \
++                        c+=n; \
++                        l1=l2=0; \
++                        switch (n) { \
++                        case 8: l2 =((DES_LONG)(*(--(c))))<<24L; \
++                        case 7: l2|=((DES_LONG)(*(--(c))))<<16L; \
++                        case 6: l2|=((DES_LONG)(*(--(c))))<< 8L; \
++                        case 5: l2|=((DES_LONG)(*(--(c))));     \
++                        case 4: l1 =((DES_LONG)(*(--(c))))<<24L; \
++                        case 3: l1|=((DES_LONG)(*(--(c))))<<16L; \
++                        case 2: l1|=((DES_LONG)(*(--(c))))<< 8L; \
++                        case 1: l1|=((DES_LONG)(*(--(c))));     \
++                                } \
++                        }
++
++# define l2c(l,c)        (*((c)++)=(unsigned char)(((l)     )&0xff), \
++                         *((c)++)=(unsigned char)(((l)>> 8L)&0xff), \
++                         *((c)++)=(unsigned char)(((l)>>16L)&0xff), \
++                         *((c)++)=(unsigned char)(((l)>>24L)&0xff))
++
++/*
++ * replacements for htonl and ntohl since I have no idea what to do when
++ * faced with machines with 8 byte longs.
++ */
++# define HDRSIZE 4
++
++# define n2l(c,l)        (l =((DES_LONG)(*((c)++)))<<24L, \
++                         l|=((DES_LONG)(*((c)++)))<<16L, \
++                         l|=((DES_LONG)(*((c)++)))<< 8L, \
++                         l|=((DES_LONG)(*((c)++))))
++
++# define l2n(l,c)        (*((c)++)=(unsigned char)(((l)>>24L)&0xff), \
++                         *((c)++)=(unsigned char)(((l)>>16L)&0xff), \
++                         *((c)++)=(unsigned char)(((l)>> 8L)&0xff), \
++                         *((c)++)=(unsigned char)(((l)     )&0xff))
++
++/* NOTE - c is not incremented as per l2c */
++# define l2cn(l1,l2,c,n) { \
++                        c+=n; \
++                        switch (n) { \
++                        case 8: *(--(c))=(unsigned char)(((l2)>>24L)&0xff); \
++                        case 7: *(--(c))=(unsigned char)(((l2)>>16L)&0xff); \
++                        case 6: *(--(c))=(unsigned char)(((l2)>> 8L)&0xff); \
++                        case 5: *(--(c))=(unsigned char)(((l2)     )&0xff); \
++                        case 4: *(--(c))=(unsigned char)(((l1)>>24L)&0xff); \
++                        case 3: *(--(c))=(unsigned char)(((l1)>>16L)&0xff); \
++                        case 2: *(--(c))=(unsigned char)(((l1)>> 8L)&0xff); \
++                        case 1: *(--(c))=(unsigned char)(((l1)     )&0xff); \
++                                } \
++                        }
++
++# if (defined(OPENSSL_SYS_WIN32) && defined(_MSC_VER))
++#  define ROTATE(a,n)     (_lrotr(a,n))
++# elif defined(__ICC)
++#  define ROTATE(a,n)     (_rotr(a,n))
++# elif defined(__GNUC__) && __GNUC__>=2 && !defined(__STRICT_ANSI__) && !defined(OPENSSL_NO_ASM) && !defined(OPENSSL_NO_INLINE_ASM) && !defined(PEDANTIC)
++#  if defined(__i386) || defined(__i386__) || defined(__x86_64) || defined(__x86_64__)
++#   define ROTATE(a,n)   ({ register unsigned int ret;   \
++                                asm ("rorl %1,%0"       \
++                                        : "=r"(ret)     \
++                                        : "I"(n),"0"(a) \
++                                        : "cc");        \
++                           ret;                         \
++                        })
++#  endif
++# endif
++# ifndef ROTATE
++#  define ROTATE(a,n)     (((a)>>(n))+((a)<<(32-(n))))
++# endif
++
++/*
++ * Don't worry about the LOAD_DATA() stuff, that is used by fcrypt() to add
++ * it's little bit to the front
++ */
++
++# ifdef DES_FCRYPT
++
++#  define LOAD_DATA_tmp(R,S,u,t,E0,E1) \
++        { DES_LONG tmp; LOAD_DATA(R,S,u,t,E0,E1,tmp); }
++
++#  define LOAD_DATA(R,S,u,t,E0,E1,tmp) \
++        t=R^(R>>16L); \
++        u=t&E0; t&=E1; \
++        tmp=(u<<16); u^=R^s[S  ]; u^=tmp; \
++        tmp=(t<<16); t^=R^s[S+1]; t^=tmp
++# else
++#  define LOAD_DATA_tmp(a,b,c,d,e,f) LOAD_DATA(a,b,c,d,e,f,g)
++#  define LOAD_DATA(R,S,u,t,E0,E1,tmp) \
++        u=R^s[S  ]; \
++        t=R^s[S+1]
++# endif
++
++/*
++ * It recently occurred to me that 0^0^0^0^0^0^0 == 0, so there is no reason
++ * to not xor all the sub items together.  This potentially saves a register
++ * since things can be xored directly into L
++ */
++
++# define D_ENCRYPT(LL,R,S) { \
++        LOAD_DATA_tmp(R,S,u,t,E0,E1); \
++        t=ROTATE(t,4); \
++        LL^= \
++            DES_SPtrans[0][(u>> 2L)&0x3f]^ \
++            DES_SPtrans[2][(u>>10L)&0x3f]^ \
++            DES_SPtrans[4][(u>>18L)&0x3f]^ \
++            DES_SPtrans[6][(u>>26L)&0x3f]^ \
++            DES_SPtrans[1][(t>> 2L)&0x3f]^ \
++            DES_SPtrans[3][(t>>10L)&0x3f]^ \
++            DES_SPtrans[5][(t>>18L)&0x3f]^ \
++            DES_SPtrans[7][(t>>26L)&0x3f]; }
++
++        /*-
++         * IP and FP
++         * The problem is more of a geometric problem that random bit fiddling.
++         0  1  2  3  4  5  6  7      62 54 46 38 30 22 14  6
++         8  9 10 11 12 13 14 15      60 52 44 36 28 20 12  4
++        16 17 18 19 20 21 22 23      58 50 42 34 26 18 10  2
++        24 25 26 27 28 29 30 31  to  56 48 40 32 24 16  8  0
++
++        32 33 34 35 36 37 38 39      63 55 47 39 31 23 15  7
++        40 41 42 43 44 45 46 47      61 53 45 37 29 21 13  5
++        48 49 50 51 52 53 54 55      59 51 43 35 27 19 11  3
++        56 57 58 59 60 61 62 63      57 49 41 33 25 17  9  1
++
++        The output has been subject to swaps of the form
++        0 1 -> 3 1 but the odd and even bits have been put into
++        2 3    2 0
++        different words.  The main trick is to remember that
++        t=((l>>size)^r)&(mask);
++        r^=t;
++        l^=(t<>(n))^(b))&(m)),\
++        (b)^=(t),\
++        (a)^=((t)<<(n)))
++
++# define IP(l,r) \
++        { \
++        register DES_LONG tt; \
++        PERM_OP(r,l,tt, 4,0x0f0f0f0fL); \
++        PERM_OP(l,r,tt,16,0x0000ffffL); \
++        PERM_OP(r,l,tt, 2,0x33333333L); \
++        PERM_OP(l,r,tt, 8,0x00ff00ffL); \
++        PERM_OP(r,l,tt, 1,0x55555555L); \
++        }
++
++# define FP(l,r) \
++        { \
++        register DES_LONG tt; \
++        PERM_OP(l,r,tt, 1,0x55555555L); \
++        PERM_OP(r,l,tt, 8,0x00ff00ffL); \
++        PERM_OP(l,r,tt, 2,0x33333333L); \
++        PERM_OP(r,l,tt,16,0x0000ffffL); \
++        PERM_OP(l,r,tt, 4,0x0f0f0f0fL); \
++        }
++
++extern const DES_LONG DES_SPtrans[8][64];
++
++void fcrypt_body(DES_LONG *out, DES_key_schedule *ks,
++                 DES_LONG Eswap0, DES_LONG Eswap1);
++
++#endif
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/des/ecb3_enc.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/des/ecb3_enc.c
+new file mode 100644
+index 0000000..6ac89d4
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/des/ecb3_enc.c
+@@ -0,0 +1,33 @@
++/*
++ * Copyright 1995-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include "des_locl.h"
++
++void DES_ecb3_encrypt(const_DES_cblock *input, DES_cblock *output,
++                      DES_key_schedule *ks1, DES_key_schedule *ks2,
++                      DES_key_schedule *ks3, int enc)
++{
++    register DES_LONG l0, l1;
++    DES_LONG ll[2];
++    const unsigned char *in = &(*input)[0];
++    unsigned char *out = &(*output)[0];
++
++    c2l(in, l0);
++    c2l(in, l1);
++    ll[0] = l0;
++    ll[1] = l1;
++    if (enc)
++        DES_encrypt3(ll, ks1, ks2, ks3);
++    else
++        DES_decrypt3(ll, ks1, ks2, ks3);
++    l0 = ll[0];
++    l1 = ll[1];
++    l2c(l0, out);
++    l2c(l1, out);
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/des/ecb_enc.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/des/ecb_enc.c
+new file mode 100644
+index 0000000..bd130c6
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/des/ecb_enc.c
+@@ -0,0 +1,51 @@
++/*
++ * Copyright 1995-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include "des_locl.h"
++#include 
++#include 
++
++
++const char *DES_options(void)
++{
++    static int init = 1;
++    static char buf[32];
++
++    if (init) {
++        const char *size;
++
++        if (sizeof(DES_LONG) != sizeof(long))
++            size = "int";
++        else
++            size = "long";
++        BIO_snprintf(buf, sizeof buf, "des(%s)", size);
++        init = 0;
++    }
++    return (buf);
++}
++
++void DES_ecb_encrypt(const_DES_cblock *input, DES_cblock *output,
++                     DES_key_schedule *ks, int enc)
++{
++    register DES_LONG l;
++    DES_LONG ll[2];
++    const unsigned char *in = &(*input)[0];
++    unsigned char *out = &(*output)[0];
++
++    c2l(in, l);
++    ll[0] = l;
++    c2l(in, l);
++    ll[1] = l;
++    DES_encrypt1(ll, ks, enc);
++    l = ll[0];
++    l2c(l, out);
++    l = ll[1];
++    l2c(l, out);
++    l = ll[0] = ll[1] = 0;
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/des/fcrypt.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/des/fcrypt.c
+new file mode 100644
+index 0000000..5215ad3
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/des/fcrypt.c
+@@ -0,0 +1,149 @@
++/*
++ * Copyright 1998-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++/* NOCW */
++#include 
++#ifdef _OSD_POSIX
++# ifndef CHARSET_EBCDIC
++#  define CHARSET_EBCDIC 1
++# endif
++#endif
++#ifdef CHARSET_EBCDIC
++# include 
++#endif
++
++#include 
++#include "des_locl.h"
++
++/*
++ * Added more values to handle illegal salt values the way normal crypt()
++ * implementations do.  The patch was sent by Bjorn Gronvall 
++ */
++static unsigned const char con_salt[128] = {
++    0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, 0xD8, 0xD9,
++    0xDA, 0xDB, 0xDC, 0xDD, 0xDE, 0xDF, 0xE0, 0xE1,
++    0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7, 0xE8, 0xE9,
++    0xEA, 0xEB, 0xEC, 0xED, 0xEE, 0xEF, 0xF0, 0xF1,
++    0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, 0xF8, 0xF9,
++    0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xFF, 0x00, 0x01,
++    0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09,
++    0x0A, 0x0B, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A,
++    0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12,
++    0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A,
++    0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x20, 0x21, 0x22,
++    0x23, 0x24, 0x25, 0x20, 0x21, 0x22, 0x23, 0x24,
++    0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C,
++    0x2D, 0x2E, 0x2F, 0x30, 0x31, 0x32, 0x33, 0x34,
++    0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, 0x3C,
++    0x3D, 0x3E, 0x3F, 0x40, 0x41, 0x42, 0x43, 0x44,
++};
++
++static unsigned const char cov_2char[64] = {
++    0x2E, 0x2F, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35,
++    0x36, 0x37, 0x38, 0x39, 0x41, 0x42, 0x43, 0x44,
++    0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x4B, 0x4C,
++    0x4D, 0x4E, 0x4F, 0x50, 0x51, 0x52, 0x53, 0x54,
++    0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x61, 0x62,
++    0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6A,
++    0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 0x70, 0x71, 0x72,
++    0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A
++};
++
++char *DES_crypt(const char *buf, const char *salt)
++{
++    static char buff[14];
++
++#ifndef CHARSET_EBCDIC
++    return (DES_fcrypt(buf, salt, buff));
++#else
++    char e_salt[2 + 1];
++    char e_buf[32 + 1];         /* replace 32 by 8 ? */
++    char *ret;
++
++    if (salt[0] == '\0' || salt[1] == '\0')
++        return NULL;
++
++    /* Copy salt, convert to ASCII. */
++    e_salt[0] = salt[0];
++    e_salt[1] = salt[1];
++    e_salt[2] = '\0';
++    ebcdic2ascii(e_salt, e_salt, sizeof(e_salt));
++
++    /* Convert password to ASCII. */
++    OPENSSL_strlcpy(e_buf, buf, sizeof(e_buf));
++    ebcdic2ascii(e_buf, e_buf, sizeof e_buf);
++
++    /* Encrypt it (from/to ASCII); if it worked, convert back. */
++    ret = DES_fcrypt(e_buf, e_salt, buff);
++    if (ret != NULL)
++        ascii2ebcdic(ret, ret, strlen(ret));
++
++    return ret;
++#endif
++}
++
++char *DES_fcrypt(const char *buf, const char *salt, char *ret)
++{
++    unsigned int i, j, x, y;
++    DES_LONG Eswap0, Eswap1;
++    DES_LONG out[2], ll;
++    DES_cblock key;
++    DES_key_schedule ks;
++    unsigned char bb[9];
++    unsigned char *b = bb;
++    unsigned char c, u;
++
++    x = ret[0] = salt[0];
++    if (x == 0 || x >= sizeof(con_salt))
++        return NULL;
++    Eswap0 = con_salt[x] << 2;
++    x = ret[1] = salt[1];
++    if (x == 0 || x >= sizeof(con_salt))
++        return NULL;
++    Eswap1 = con_salt[x] << 6;
++
++    /*
++     * EAY r=strlen(buf); r=(r+7)/8;
++     */
++    for (i = 0; i < 8; i++) {
++        c = *(buf++);
++        if (!c)
++            break;
++        key[i] = (c << 1);
++    }
++    for (; i < 8; i++)
++        key[i] = 0;
++
++    DES_set_key_unchecked(&key, &ks);
++    fcrypt_body(&(out[0]), &ks, Eswap0, Eswap1);
++
++    ll = out[0];
++    l2c(ll, b);
++    ll = out[1];
++    l2c(ll, b);
++    y = 0;
++    u = 0x80;
++    bb[8] = 0;
++    for (i = 2; i < 13; i++) {
++        c = 0;
++        for (j = 0; j < 6; j++) {
++            c <<= 1;
++            if (bb[y] & u)
++                c |= 1;
++            u >>= 1;
++            if (!u) {
++                y++;
++                u = 0x80;
++            }
++        }
++        ret[i] = cov_2char[c];
++    }
++    ret[13] = '\0';
++    return (ret);
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/des/fcrypt_b.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/des/fcrypt_b.c
+new file mode 100644
+index 0000000..fe2369a
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/des/fcrypt_b.c
+@@ -0,0 +1,72 @@
++/*
++ * Copyright 1995-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++
++#define DES_FCRYPT
++#include "des_locl.h"
++#undef DES_FCRYPT
++
++#undef PERM_OP
++#define PERM_OP(a,b,t,n,m) ((t)=((((a)>>(n))^(b))&(m)),\
++        (b)^=(t),\
++        (a)^=((t)<<(n)))
++
++#undef HPERM_OP
++#define HPERM_OP(a,t,n,m) ((t)=((((a)<<(16-(n)))^(a))&(m)),\
++        (a)=(a)^(t)^(t>>(16-(n))))\
++
++void fcrypt_body(DES_LONG *out, DES_key_schedule *ks, DES_LONG Eswap0,
++                 DES_LONG Eswap1)
++{
++    register DES_LONG l, r, t, u;
++    register DES_LONG *s;
++    register int j;
++    register DES_LONG E0, E1;
++
++    l = 0;
++    r = 0;
++
++    s = (DES_LONG *)ks;
++    E0 = Eswap0;
++    E1 = Eswap1;
++
++    for (j = 0; j < 25; j++) {
++        D_ENCRYPT(l, r, 0);     /* 1 */
++        D_ENCRYPT(r, l, 2);     /* 2 */
++        D_ENCRYPT(l, r, 4);     /* 3 */
++        D_ENCRYPT(r, l, 6);     /* 4 */
++        D_ENCRYPT(l, r, 8);     /* 5 */
++        D_ENCRYPT(r, l, 10);    /* 6 */
++        D_ENCRYPT(l, r, 12);    /* 7 */
++        D_ENCRYPT(r, l, 14);    /* 8 */
++        D_ENCRYPT(l, r, 16);    /* 9 */
++        D_ENCRYPT(r, l, 18);    /* 10 */
++        D_ENCRYPT(l, r, 20);    /* 11 */
++        D_ENCRYPT(r, l, 22);    /* 12 */
++        D_ENCRYPT(l, r, 24);    /* 13 */
++        D_ENCRYPT(r, l, 26);    /* 14 */
++        D_ENCRYPT(l, r, 28);    /* 15 */
++        D_ENCRYPT(r, l, 30);    /* 16 */
++        t = l;
++        l = r;
++        r = t;
++    }
++    l = ROTATE(l, 3) & 0xffffffffL;
++    r = ROTATE(r, 3) & 0xffffffffL;
++
++    PERM_OP(l, r, t,  1, 0x55555555L);
++    PERM_OP(r, l, t,  8, 0x00ff00ffL);
++    PERM_OP(l, r, t,  2, 0x33333333L);
++    PERM_OP(r, l, t, 16, 0x0000ffffL);
++    PERM_OP(l, r, t,  4, 0x0f0f0f0fL);
++
++    out[0] = r;
++    out[1] = l;
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/des/ncbc_enc.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/des/ncbc_enc.c
+new file mode 100644
+index 0000000..244f15c
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/des/ncbc_enc.c
+@@ -0,0 +1,106 @@
++/*
++ * Copyright 1998-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++/*-
++ * #included by:
++ *    cbc_enc.c  (DES_cbc_encrypt)
++ *    des_enc.c  (DES_ncbc_encrypt)
++ */
++
++#include "des_locl.h"
++
++#ifdef CBC_ENC_C__DONT_UPDATE_IV
++void DES_cbc_encrypt(const unsigned char *in, unsigned char *out, long length,
++                     DES_key_schedule *_schedule, DES_cblock *ivec, int enc)
++#else
++void DES_ncbc_encrypt(const unsigned char *in, unsigned char *out,
++                      long length, DES_key_schedule *_schedule,
++                      DES_cblock *ivec, int enc)
++#endif
++{
++    register DES_LONG tin0, tin1;
++    register DES_LONG tout0, tout1, xor0, xor1;
++    register long l = length;
++    DES_LONG tin[2];
++    unsigned char *iv;
++
++    iv = &(*ivec)[0];
++
++    if (enc) {
++        c2l(iv, tout0);
++        c2l(iv, tout1);
++        for (l -= 8; l >= 0; l -= 8) {
++            c2l(in, tin0);
++            c2l(in, tin1);
++            tin0 ^= tout0;
++            tin[0] = tin0;
++            tin1 ^= tout1;
++            tin[1] = tin1;
++            DES_encrypt1((DES_LONG *)tin, _schedule, DES_ENCRYPT);
++            tout0 = tin[0];
++            l2c(tout0, out);
++            tout1 = tin[1];
++            l2c(tout1, out);
++        }
++        if (l != -8) {
++            c2ln(in, tin0, tin1, l + 8);
++            tin0 ^= tout0;
++            tin[0] = tin0;
++            tin1 ^= tout1;
++            tin[1] = tin1;
++            DES_encrypt1((DES_LONG *)tin, _schedule, DES_ENCRYPT);
++            tout0 = tin[0];
++            l2c(tout0, out);
++            tout1 = tin[1];
++            l2c(tout1, out);
++        }
++#ifndef CBC_ENC_C__DONT_UPDATE_IV
++        iv = &(*ivec)[0];
++        l2c(tout0, iv);
++        l2c(tout1, iv);
++#endif
++    } else {
++        c2l(iv, xor0);
++        c2l(iv, xor1);
++        for (l -= 8; l >= 0; l -= 8) {
++            c2l(in, tin0);
++            tin[0] = tin0;
++            c2l(in, tin1);
++            tin[1] = tin1;
++            DES_encrypt1((DES_LONG *)tin, _schedule, DES_DECRYPT);
++            tout0 = tin[0] ^ xor0;
++            tout1 = tin[1] ^ xor1;
++            l2c(tout0, out);
++            l2c(tout1, out);
++            xor0 = tin0;
++            xor1 = tin1;
++        }
++        if (l != -8) {
++            c2l(in, tin0);
++            tin[0] = tin0;
++            c2l(in, tin1);
++            tin[1] = tin1;
++            DES_encrypt1((DES_LONG *)tin, _schedule, DES_DECRYPT);
++            tout0 = tin[0] ^ xor0;
++            tout1 = tin[1] ^ xor1;
++            l2cn(tout0, tout1, out, l + 8);
++#ifndef CBC_ENC_C__DONT_UPDATE_IV
++            xor0 = tin0;
++            xor1 = tin1;
++#endif
++        }
++#ifndef CBC_ENC_C__DONT_UPDATE_IV
++        iv = &(*ivec)[0];
++        l2c(xor0, iv);
++        l2c(xor1, iv);
++#endif
++    }
++    tin0 = tin1 = tout0 = tout1 = xor0 = xor1 = 0;
++    tin[0] = tin[1] = 0;
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/des/ofb64ede.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/des/ofb64ede.c
+new file mode 100644
+index 0000000..a551a07
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/des/ofb64ede.c
+@@ -0,0 +1,62 @@
++/*
++ * Copyright 1995-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include "des_locl.h"
++
++/*
++ * The input and output encrypted as though 64bit ofb mode is being used.
++ * The extra state information to record how much of the 64bit block we have
++ * used is contained in *num;
++ */
++void DES_ede3_ofb64_encrypt(register const unsigned char *in,
++                            register unsigned char *out, long length,
++                            DES_key_schedule *k1, DES_key_schedule *k2,
++                            DES_key_schedule *k3, DES_cblock *ivec, int *num)
++{
++    register DES_LONG v0, v1;
++    register int n = *num;
++    register long l = length;
++    DES_cblock d;
++    register char *dp;
++    DES_LONG ti[2];
++    unsigned char *iv;
++    int save = 0;
++
++    iv = &(*ivec)[0];
++    c2l(iv, v0);
++    c2l(iv, v1);
++    ti[0] = v0;
++    ti[1] = v1;
++    dp = (char *)d;
++    l2c(v0, dp);
++    l2c(v1, dp);
++    while (l--) {
++        if (n == 0) {
++            /* ti[0]=v0; */
++            /* ti[1]=v1; */
++            DES_encrypt3(ti, k1, k2, k3);
++            v0 = ti[0];
++            v1 = ti[1];
++
++            dp = (char *)d;
++            l2c(v0, dp);
++            l2c(v1, dp);
++            save++;
++        }
++        *(out++) = *(in++) ^ d[n];
++        n = (n + 1) & 0x07;
++    }
++    if (save) {
++        iv = &(*ivec)[0];
++        l2c(v0, iv);
++        l2c(v1, iv);
++    }
++    v0 = v1 = ti[0] = ti[1] = 0;
++    *num = n;
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/des/ofb64enc.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/des/ofb64enc.c
+new file mode 100644
+index 0000000..30976c8
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/des/ofb64enc.c
+@@ -0,0 +1,60 @@
++/*
++ * Copyright 1995-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include "des_locl.h"
++
++/*
++ * The input and output encrypted as though 64bit ofb mode is being used.
++ * The extra state information to record how much of the 64bit block we have
++ * used is contained in *num;
++ */
++void DES_ofb64_encrypt(register const unsigned char *in,
++                       register unsigned char *out, long length,
++                       DES_key_schedule *schedule, DES_cblock *ivec, int *num)
++{
++    register DES_LONG v0, v1, t;
++    register int n = *num;
++    register long l = length;
++    DES_cblock d;
++    register unsigned char *dp;
++    DES_LONG ti[2];
++    unsigned char *iv;
++    int save = 0;
++
++    iv = &(*ivec)[0];
++    c2l(iv, v0);
++    c2l(iv, v1);
++    ti[0] = v0;
++    ti[1] = v1;
++    dp = d;
++    l2c(v0, dp);
++    l2c(v1, dp);
++    while (l--) {
++        if (n == 0) {
++            DES_encrypt1(ti, schedule, DES_ENCRYPT);
++            dp = d;
++            t = ti[0];
++            l2c(t, dp);
++            t = ti[1];
++            l2c(t, dp);
++            save++;
++        }
++        *(out++) = *(in++) ^ d[n];
++        n = (n + 1) & 0x07;
++    }
++    if (save) {
++        v0 = ti[0];
++        v1 = ti[1];
++        iv = &(*ivec)[0];
++        l2c(v0, iv);
++        l2c(v1, iv);
++    }
++    t = v0 = v1 = ti[0] = ti[1] = 0;
++    *num = n;
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/des/ofb_enc.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/des/ofb_enc.c
+new file mode 100644
+index 0000000..65a9b86
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/des/ofb_enc.c
+@@ -0,0 +1,82 @@
++/*
++ * Copyright 1995-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include "des_locl.h"
++
++/*
++ * The input and output are loaded in multiples of 8 bits. What this means is
++ * that if you have numbits=12 and length=2 the first 12 bits will be
++ * retrieved from the first byte and half the second.  The second 12 bits
++ * will come from the 3rd and half the 4th byte.
++ */
++void DES_ofb_encrypt(const unsigned char *in, unsigned char *out, int numbits,
++                     long length, DES_key_schedule *schedule,
++                     DES_cblock *ivec)
++{
++    register DES_LONG d0, d1, vv0, vv1, v0, v1, n = (numbits + 7) / 8;
++    register DES_LONG mask0, mask1;
++    register long l = length;
++    register int num = numbits;
++    DES_LONG ti[2];
++    unsigned char *iv;
++
++    if (num > 64)
++        return;
++    if (num > 32) {
++        mask0 = 0xffffffffL;
++        if (num >= 64)
++            mask1 = mask0;
++        else
++            mask1 = (1L << (num - 32)) - 1;
++    } else {
++        if (num == 32)
++            mask0 = 0xffffffffL;
++        else
++            mask0 = (1L << num) - 1;
++        mask1 = 0x00000000L;
++    }
++
++    iv = &(*ivec)[0];
++    c2l(iv, v0);
++    c2l(iv, v1);
++    ti[0] = v0;
++    ti[1] = v1;
++    while (l-- > 0) {
++        ti[0] = v0;
++        ti[1] = v1;
++        DES_encrypt1((DES_LONG *)ti, schedule, DES_ENCRYPT);
++        vv0 = ti[0];
++        vv1 = ti[1];
++        c2ln(in, d0, d1, n);
++        in += n;
++        d0 = (d0 ^ vv0) & mask0;
++        d1 = (d1 ^ vv1) & mask1;
++        l2cn(d0, d1, out, n);
++        out += n;
++
++        if (num == 32) {
++            v0 = v1;
++            v1 = vv0;
++        } else if (num == 64) {
++            v0 = vv0;
++            v1 = vv1;
++        } else if (num > 32) {  /* && num != 64 */
++            v0 = ((v1 >> (num - 32)) | (vv0 << (64 - num))) & 0xffffffffL;
++            v1 = ((vv0 >> (num - 32)) | (vv1 << (64 - num))) & 0xffffffffL;
++        } else {                /* num < 32 */
++
++            v0 = ((v0 >> num) | (v1 << (32 - num))) & 0xffffffffL;
++            v1 = ((v1 >> num) | (vv0 << (32 - num))) & 0xffffffffL;
++        }
++    }
++    iv = &(*ivec)[0];
++    l2c(v0, iv);
++    l2c(v1, iv);
++    v0 = v1 = d0 = d1 = ti[0] = ti[1] = vv0 = vv1 = 0;
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/des/pcbc_enc.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/des/pcbc_enc.c
+new file mode 100644
+index 0000000..0fa058f
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/des/pcbc_enc.c
+@@ -0,0 +1,66 @@
++/*
++ * Copyright 1995-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include "des_locl.h"
++
++void DES_pcbc_encrypt(const unsigned char *input, unsigned char *output,
++                      long length, DES_key_schedule *schedule,
++                      DES_cblock *ivec, int enc)
++{
++    register DES_LONG sin0, sin1, xor0, xor1, tout0, tout1;
++    DES_LONG tin[2];
++    const unsigned char *in;
++    unsigned char *out, *iv;
++
++    in = input;
++    out = output;
++    iv = &(*ivec)[0];
++
++    if (enc) {
++        c2l(iv, xor0);
++        c2l(iv, xor1);
++        for (; length > 0; length -= 8) {
++            if (length >= 8) {
++                c2l(in, sin0);
++                c2l(in, sin1);
++            } else
++                c2ln(in, sin0, sin1, length);
++            tin[0] = sin0 ^ xor0;
++            tin[1] = sin1 ^ xor1;
++            DES_encrypt1((DES_LONG *)tin, schedule, DES_ENCRYPT);
++            tout0 = tin[0];
++            tout1 = tin[1];
++            xor0 = sin0 ^ tout0;
++            xor1 = sin1 ^ tout1;
++            l2c(tout0, out);
++            l2c(tout1, out);
++        }
++    } else {
++        c2l(iv, xor0);
++        c2l(iv, xor1);
++        for (; length > 0; length -= 8) {
++            c2l(in, sin0);
++            c2l(in, sin1);
++            tin[0] = sin0;
++            tin[1] = sin1;
++            DES_encrypt1((DES_LONG *)tin, schedule, DES_DECRYPT);
++            tout0 = tin[0] ^ xor0;
++            tout1 = tin[1] ^ xor1;
++            if (length >= 8) {
++                l2c(tout0, out);
++                l2c(tout1, out);
++            } else
++                l2cn(tout0, tout1, out, length);
++            xor0 = tout0 ^ sin0;
++            xor1 = tout1 ^ sin1;
++        }
++    }
++    tin[0] = tin[1] = 0;
++    sin0 = sin1 = xor0 = xor1 = tout0 = tout1 = 0;
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/des/qud_cksm.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/des/qud_cksm.c
+new file mode 100644
+index 0000000..8710cec
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/des/qud_cksm.c
+@@ -0,0 +1,77 @@
++/*
++ * Copyright 1995-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++/*
++ * From "Message Authentication" R.R. Jueneman, S.M. Matyas, C.H. Meyer IEEE
++ * Communications Magazine Sept 1985 Vol. 23 No. 9 p 29-40 This module in
++ * only based on the code in this paper and is almost definitely not the same
++ * as the MIT implementation.
++ */
++#include "des_locl.h"
++
++/* bug fix for dos - 7/6/91 - Larry hughes@logos.ucs.indiana.edu */
++#define Q_B0(a) (((DES_LONG)(a)))
++#define Q_B1(a) (((DES_LONG)(a))<<8)
++#define Q_B2(a) (((DES_LONG)(a))<<16)
++#define Q_B3(a) (((DES_LONG)(a))<<24)
++
++/* used to scramble things a bit */
++/* Got the value MIT uses via brute force :-) 2/10/90 eay */
++#define NOISE   ((DES_LONG)83653421L)
++
++DES_LONG DES_quad_cksum(const unsigned char *input, DES_cblock output[],
++                        long length, int out_count, DES_cblock *seed)
++{
++    DES_LONG z0, z1, t0, t1;
++    int i;
++    long l;
++    const unsigned char *cp;
++    DES_LONG *lp;
++
++    if (out_count < 1)
++        out_count = 1;
++    lp = (DES_LONG *)&(output[0])[0];
++
++    z0 = Q_B0((*seed)[0]) | Q_B1((*seed)[1]) | Q_B2((*seed)[2]) |
++        Q_B3((*seed)[3]);
++    z1 = Q_B0((*seed)[4]) | Q_B1((*seed)[5]) | Q_B2((*seed)[6]) |
++        Q_B3((*seed)[7]);
++
++    for (i = 0; ((i < 4) && (i < out_count)); i++) {
++        cp = input;
++        l = length;
++        while (l > 0) {
++            if (l > 1) {
++                t0 = (DES_LONG)(*(cp++));
++                t0 |= (DES_LONG)Q_B1(*(cp++));
++                l--;
++            } else
++                t0 = (DES_LONG)(*(cp++));
++            l--;
++            /* add */
++            t0 += z0;
++            t0 &= 0xffffffffL;
++            t1 = z1;
++            /* square, well sort of square */
++            z0 = ((((t0 * t0) & 0xffffffffL) + ((t1 * t1) & 0xffffffffL))
++                  & 0xffffffffL) % 0x7fffffffL;
++            z1 = ((t0 * ((t1 + NOISE) & 0xffffffffL)) & 0xffffffffL) %
++                0x7fffffffL;
++        }
++        if (lp != NULL) {
++            /*
++             * The MIT library assumes that the checksum is composed of
++             * 2*out_count 32 bit ints
++             */
++            *lp++ = z0;
++            *lp++ = z1;
++        }
++    }
++    return (z0);
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/des/rand_key.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/des/rand_key.c
+new file mode 100644
+index 0000000..61e4f9d
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/des/rand_key.c
+@@ -0,0 +1,21 @@
++/*
++ * Copyright 1998-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include 
++
++int DES_random_key(DES_cblock *ret)
++{
++    do {
++        if (RAND_bytes((unsigned char *)ret, sizeof(DES_cblock)) != 1)
++            return (0);
++    } while (DES_is_weak_key(ret));
++    DES_set_odd_parity(ret);
++    return (1);
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/des/rpc_des.h b/CryptoPkg/Library/OpensslLib/openssl/crypto/des/rpc_des.h
+new file mode 100644
+index 0000000..fe59e22
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/des/rpc_des.h
+@@ -0,0 +1,76 @@
++/*
++ * Copyright 1995-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++/*  @(#)des.h   2.2 88/08/10 4.0 RPCSRC; from 2.7 88/02/08 SMI  */
++/*-
++ * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
++ * unrestricted use provided that this legend is included on all tape
++ * media and as a part of the software program in whole or part.  Users
++ * may copy or modify Sun RPC without charge, but are not authorized
++ * to license or distribute it to anyone else except as part of a product or
++ * program developed by the user.
++ *
++ * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
++ * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
++ * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
++ *
++ * Sun RPC is provided with no support and without any obligation on the
++ * part of Sun Microsystems, Inc. to assist in its use, correction,
++ * modification or enhancement.
++ *
++ * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
++ * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
++ * OR ANY PART THEREOF.
++ *
++ * In no event will Sun Microsystems, Inc. be liable for any lost revenue
++ * or profits or other special, indirect and consequential damages, even if
++ * Sun has been advised of the possibility of such damages.
++ *
++ * Sun Microsystems, Inc.
++ * 2550 Garcia Avenue
++ * Mountain View, California  94043
++ */
++/*
++ * Generic DES driver interface
++ * Keep this file hardware independent!
++ * Copyright (c) 1986 by Sun Microsystems, Inc.
++ */
++
++#define DES_MAXLEN      65536   /* maximum # of bytes to encrypt */
++#define DES_QUICKLEN    16      /* maximum # of bytes to encrypt quickly */
++
++enum desdir { ENCRYPT, DECRYPT };
++enum desmode { CBC, ECB };
++
++/*
++ * parameters to ioctl call
++ */
++struct desparams {
++    unsigned char des_key[8];   /* key (with low bit parity) */
++    enum desdir des_dir;        /* direction */
++    enum desmode des_mode;      /* mode */
++    unsigned char des_ivec[8];  /* input vector */
++    unsigned des_len;           /* number of bytes to crypt */
++    union {
++        unsigned char UDES_data[DES_QUICKLEN];
++        unsigned char *UDES_buf;
++    } UDES;
++#define des_data UDES.UDES_data /* direct data here if quick */
++#define des_buf  UDES.UDES_buf  /* otherwise, pointer to data */
++};
++
++/*
++ * Encrypt an arbitrary sized buffer
++ */
++#define DESIOCBLOCK     _IOWR('d', 6, struct desparams)
++
++/*
++ * Encrypt of small amount of data, quickly
++ */
++#define DESIOCQUICK     _IOWR('d', 7, struct desparams)
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/des/rpc_enc.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/des/rpc_enc.c
+new file mode 100644
+index 0000000..bfa8511
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/des/rpc_enc.c
+@@ -0,0 +1,30 @@
++/*
++ * Copyright 1995-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include "rpc_des.h"
++#include "des_locl.h"
++
++int _des_crypt(char *buf, int len, struct desparams *desp);
++int _des_crypt(char *buf, int len, struct desparams *desp)
++{
++    DES_key_schedule ks;
++    int enc;
++
++    DES_set_key_unchecked(&desp->des_key, &ks);
++    enc = (desp->des_dir == ENCRYPT) ? DES_ENCRYPT : DES_DECRYPT;
++
++    if (desp->des_mode == CBC)
++        DES_ecb_encrypt((const_DES_cblock *)desp->UDES.UDES_buf,
++                        (DES_cblock *)desp->UDES.UDES_buf, &ks, enc);
++    else {
++        DES_ncbc_encrypt(desp->UDES.UDES_buf, desp->UDES.UDES_buf,
++                         len, &ks, &desp->des_ivec, enc);
++    }
++    return (1);
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/des/set_key.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/des/set_key.c
+new file mode 100644
+index 0000000..795d954
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/des/set_key.c
+@@ -0,0 +1,389 @@
++/*
++ * Copyright 1995-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++/*-
++ * set_key.c v 1.4 eay 24/9/91
++ * 1.4 Speed up by 400% :-)
++ * 1.3 added register declarations.
++ * 1.2 unrolled make_key_sched a bit more
++ * 1.1 added norm_expand_bits
++ * 1.0 First working version
++ */
++#include 
++#include "des_locl.h"
++
++OPENSSL_IMPLEMENT_GLOBAL(int, DES_check_key, 0)
++                                                    /*
++                                                     * defaults to false
++                                                     */
++static const unsigned char odd_parity[256] = {
++    1, 1, 2, 2, 4, 4, 7, 7, 8, 8, 11, 11, 13, 13, 14, 14,
++    16, 16, 19, 19, 21, 21, 22, 22, 25, 25, 26, 26, 28, 28, 31, 31,
++    32, 32, 35, 35, 37, 37, 38, 38, 41, 41, 42, 42, 44, 44, 47, 47,
++    49, 49, 50, 50, 52, 52, 55, 55, 56, 56, 59, 59, 61, 61, 62, 62,
++    64, 64, 67, 67, 69, 69, 70, 70, 73, 73, 74, 74, 76, 76, 79, 79,
++    81, 81, 82, 82, 84, 84, 87, 87, 88, 88, 91, 91, 93, 93, 94, 94,
++    97, 97, 98, 98, 100, 100, 103, 103, 104, 104, 107, 107, 109, 109, 110,
++    110,
++    112, 112, 115, 115, 117, 117, 118, 118, 121, 121, 122, 122, 124, 124, 127,
++    127,
++    128, 128, 131, 131, 133, 133, 134, 134, 137, 137, 138, 138, 140, 140, 143,
++    143,
++    145, 145, 146, 146, 148, 148, 151, 151, 152, 152, 155, 155, 157, 157, 158,
++    158,
++    161, 161, 162, 162, 164, 164, 167, 167, 168, 168, 171, 171, 173, 173, 174,
++    174,
++    176, 176, 179, 179, 181, 181, 182, 182, 185, 185, 186, 186, 188, 188, 191,
++    191,
++    193, 193, 194, 194, 196, 196, 199, 199, 200, 200, 203, 203, 205, 205, 206,
++    206,
++    208, 208, 211, 211, 213, 213, 214, 214, 217, 217, 218, 218, 220, 220, 223,
++    223,
++    224, 224, 227, 227, 229, 229, 230, 230, 233, 233, 234, 234, 236, 236, 239,
++    239,
++    241, 241, 242, 242, 244, 244, 247, 247, 248, 248, 251, 251, 253, 253, 254,
++    254
++};
++
++void DES_set_odd_parity(DES_cblock *key)
++{
++    unsigned int i;
++
++    for (i = 0; i < DES_KEY_SZ; i++)
++        (*key)[i] = odd_parity[(*key)[i]];
++}
++
++int DES_check_key_parity(const_DES_cblock *key)
++{
++    unsigned int i;
++
++    for (i = 0; i < DES_KEY_SZ; i++) {
++        if ((*key)[i] != odd_parity[(*key)[i]])
++            return (0);
++    }
++    return (1);
++}
++
++/*-
++ * Weak and semi weak keys as taken from
++ * %A D.W. Davies
++ * %A W.L. Price
++ * %T Security for Computer Networks
++ * %I John Wiley & Sons
++ * %D 1984
++ * Many thanks to smb@ulysses.att.com (Steven Bellovin) for the reference
++ * (and actual cblock values).
++ */
++#define NUM_WEAK_KEY    16
++static const DES_cblock weak_keys[NUM_WEAK_KEY] = {
++    /* weak keys */
++    {0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01},
++    {0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE},
++    {0x1F, 0x1F, 0x1F, 0x1F, 0x0E, 0x0E, 0x0E, 0x0E},
++    {0xE0, 0xE0, 0xE0, 0xE0, 0xF1, 0xF1, 0xF1, 0xF1},
++    /* semi-weak keys */
++    {0x01, 0xFE, 0x01, 0xFE, 0x01, 0xFE, 0x01, 0xFE},
++    {0xFE, 0x01, 0xFE, 0x01, 0xFE, 0x01, 0xFE, 0x01},
++    {0x1F, 0xE0, 0x1F, 0xE0, 0x0E, 0xF1, 0x0E, 0xF1},
++    {0xE0, 0x1F, 0xE0, 0x1F, 0xF1, 0x0E, 0xF1, 0x0E},
++    {0x01, 0xE0, 0x01, 0xE0, 0x01, 0xF1, 0x01, 0xF1},
++    {0xE0, 0x01, 0xE0, 0x01, 0xF1, 0x01, 0xF1, 0x01},
++    {0x1F, 0xFE, 0x1F, 0xFE, 0x0E, 0xFE, 0x0E, 0xFE},
++    {0xFE, 0x1F, 0xFE, 0x1F, 0xFE, 0x0E, 0xFE, 0x0E},
++    {0x01, 0x1F, 0x01, 0x1F, 0x01, 0x0E, 0x01, 0x0E},
++    {0x1F, 0x01, 0x1F, 0x01, 0x0E, 0x01, 0x0E, 0x01},
++    {0xE0, 0xFE, 0xE0, 0xFE, 0xF1, 0xFE, 0xF1, 0xFE},
++    {0xFE, 0xE0, 0xFE, 0xE0, 0xFE, 0xF1, 0xFE, 0xF1}
++};
++
++int DES_is_weak_key(const_DES_cblock *key)
++{
++    int i;
++
++    for (i = 0; i < NUM_WEAK_KEY; i++)
++        /*
++         * Added == 0 to comparison, I obviously don't run this section very
++         * often :-(, thanks to engineering@MorningStar.Com for the fix eay
++         * 93/06/29 Another problem, I was comparing only the first 4 bytes,
++         * 97/03/18
++         */
++        if (memcmp(weak_keys[i], key, sizeof(DES_cblock)) == 0)
++            return (1);
++    return (0);
++}
++
++/*-
++ * NOW DEFINED IN des_local.h
++ * See ecb_encrypt.c for a pseudo description of these macros.
++ * #define PERM_OP(a,b,t,n,m) ((t)=((((a)>>(n))^(b))&(m)),\
++ *      (b)^=(t),\
++ *      (a)=((a)^((t)<<(n))))
++ */
++
++#define HPERM_OP(a,t,n,m) ((t)=((((a)<<(16-(n)))^(a))&(m)),\
++        (a)=(a)^(t)^(t>>(16-(n))))
++
++static const DES_LONG des_skb[8][64] = {
++    {
++     /* for C bits (numbered as per FIPS 46) 1 2 3 4 5 6 */
++     0x00000000L, 0x00000010L, 0x20000000L, 0x20000010L,
++     0x00010000L, 0x00010010L, 0x20010000L, 0x20010010L,
++     0x00000800L, 0x00000810L, 0x20000800L, 0x20000810L,
++     0x00010800L, 0x00010810L, 0x20010800L, 0x20010810L,
++     0x00000020L, 0x00000030L, 0x20000020L, 0x20000030L,
++     0x00010020L, 0x00010030L, 0x20010020L, 0x20010030L,
++     0x00000820L, 0x00000830L, 0x20000820L, 0x20000830L,
++     0x00010820L, 0x00010830L, 0x20010820L, 0x20010830L,
++     0x00080000L, 0x00080010L, 0x20080000L, 0x20080010L,
++     0x00090000L, 0x00090010L, 0x20090000L, 0x20090010L,
++     0x00080800L, 0x00080810L, 0x20080800L, 0x20080810L,
++     0x00090800L, 0x00090810L, 0x20090800L, 0x20090810L,
++     0x00080020L, 0x00080030L, 0x20080020L, 0x20080030L,
++     0x00090020L, 0x00090030L, 0x20090020L, 0x20090030L,
++     0x00080820L, 0x00080830L, 0x20080820L, 0x20080830L,
++     0x00090820L, 0x00090830L, 0x20090820L, 0x20090830L,
++     },
++    {
++     /* for C bits (numbered as per FIPS 46) 7 8 10 11 12 13 */
++     0x00000000L, 0x02000000L, 0x00002000L, 0x02002000L,
++     0x00200000L, 0x02200000L, 0x00202000L, 0x02202000L,
++     0x00000004L, 0x02000004L, 0x00002004L, 0x02002004L,
++     0x00200004L, 0x02200004L, 0x00202004L, 0x02202004L,
++     0x00000400L, 0x02000400L, 0x00002400L, 0x02002400L,
++     0x00200400L, 0x02200400L, 0x00202400L, 0x02202400L,
++     0x00000404L, 0x02000404L, 0x00002404L, 0x02002404L,
++     0x00200404L, 0x02200404L, 0x00202404L, 0x02202404L,
++     0x10000000L, 0x12000000L, 0x10002000L, 0x12002000L,
++     0x10200000L, 0x12200000L, 0x10202000L, 0x12202000L,
++     0x10000004L, 0x12000004L, 0x10002004L, 0x12002004L,
++     0x10200004L, 0x12200004L, 0x10202004L, 0x12202004L,
++     0x10000400L, 0x12000400L, 0x10002400L, 0x12002400L,
++     0x10200400L, 0x12200400L, 0x10202400L, 0x12202400L,
++     0x10000404L, 0x12000404L, 0x10002404L, 0x12002404L,
++     0x10200404L, 0x12200404L, 0x10202404L, 0x12202404L,
++     },
++    {
++     /* for C bits (numbered as per FIPS 46) 14 15 16 17 19 20 */
++     0x00000000L, 0x00000001L, 0x00040000L, 0x00040001L,
++     0x01000000L, 0x01000001L, 0x01040000L, 0x01040001L,
++     0x00000002L, 0x00000003L, 0x00040002L, 0x00040003L,
++     0x01000002L, 0x01000003L, 0x01040002L, 0x01040003L,
++     0x00000200L, 0x00000201L, 0x00040200L, 0x00040201L,
++     0x01000200L, 0x01000201L, 0x01040200L, 0x01040201L,
++     0x00000202L, 0x00000203L, 0x00040202L, 0x00040203L,
++     0x01000202L, 0x01000203L, 0x01040202L, 0x01040203L,
++     0x08000000L, 0x08000001L, 0x08040000L, 0x08040001L,
++     0x09000000L, 0x09000001L, 0x09040000L, 0x09040001L,
++     0x08000002L, 0x08000003L, 0x08040002L, 0x08040003L,
++     0x09000002L, 0x09000003L, 0x09040002L, 0x09040003L,
++     0x08000200L, 0x08000201L, 0x08040200L, 0x08040201L,
++     0x09000200L, 0x09000201L, 0x09040200L, 0x09040201L,
++     0x08000202L, 0x08000203L, 0x08040202L, 0x08040203L,
++     0x09000202L, 0x09000203L, 0x09040202L, 0x09040203L,
++     },
++    {
++     /* for C bits (numbered as per FIPS 46) 21 23 24 26 27 28 */
++     0x00000000L, 0x00100000L, 0x00000100L, 0x00100100L,
++     0x00000008L, 0x00100008L, 0x00000108L, 0x00100108L,
++     0x00001000L, 0x00101000L, 0x00001100L, 0x00101100L,
++     0x00001008L, 0x00101008L, 0x00001108L, 0x00101108L,
++     0x04000000L, 0x04100000L, 0x04000100L, 0x04100100L,
++     0x04000008L, 0x04100008L, 0x04000108L, 0x04100108L,
++     0x04001000L, 0x04101000L, 0x04001100L, 0x04101100L,
++     0x04001008L, 0x04101008L, 0x04001108L, 0x04101108L,
++     0x00020000L, 0x00120000L, 0x00020100L, 0x00120100L,
++     0x00020008L, 0x00120008L, 0x00020108L, 0x00120108L,
++     0x00021000L, 0x00121000L, 0x00021100L, 0x00121100L,
++     0x00021008L, 0x00121008L, 0x00021108L, 0x00121108L,
++     0x04020000L, 0x04120000L, 0x04020100L, 0x04120100L,
++     0x04020008L, 0x04120008L, 0x04020108L, 0x04120108L,
++     0x04021000L, 0x04121000L, 0x04021100L, 0x04121100L,
++     0x04021008L, 0x04121008L, 0x04021108L, 0x04121108L,
++     },
++    {
++     /* for D bits (numbered as per FIPS 46) 1 2 3 4 5 6 */
++     0x00000000L, 0x10000000L, 0x00010000L, 0x10010000L,
++     0x00000004L, 0x10000004L, 0x00010004L, 0x10010004L,
++     0x20000000L, 0x30000000L, 0x20010000L, 0x30010000L,
++     0x20000004L, 0x30000004L, 0x20010004L, 0x30010004L,
++     0x00100000L, 0x10100000L, 0x00110000L, 0x10110000L,
++     0x00100004L, 0x10100004L, 0x00110004L, 0x10110004L,
++     0x20100000L, 0x30100000L, 0x20110000L, 0x30110000L,
++     0x20100004L, 0x30100004L, 0x20110004L, 0x30110004L,
++     0x00001000L, 0x10001000L, 0x00011000L, 0x10011000L,
++     0x00001004L, 0x10001004L, 0x00011004L, 0x10011004L,
++     0x20001000L, 0x30001000L, 0x20011000L, 0x30011000L,
++     0x20001004L, 0x30001004L, 0x20011004L, 0x30011004L,
++     0x00101000L, 0x10101000L, 0x00111000L, 0x10111000L,
++     0x00101004L, 0x10101004L, 0x00111004L, 0x10111004L,
++     0x20101000L, 0x30101000L, 0x20111000L, 0x30111000L,
++     0x20101004L, 0x30101004L, 0x20111004L, 0x30111004L,
++     },
++    {
++     /* for D bits (numbered as per FIPS 46) 8 9 11 12 13 14 */
++     0x00000000L, 0x08000000L, 0x00000008L, 0x08000008L,
++     0x00000400L, 0x08000400L, 0x00000408L, 0x08000408L,
++     0x00020000L, 0x08020000L, 0x00020008L, 0x08020008L,
++     0x00020400L, 0x08020400L, 0x00020408L, 0x08020408L,
++     0x00000001L, 0x08000001L, 0x00000009L, 0x08000009L,
++     0x00000401L, 0x08000401L, 0x00000409L, 0x08000409L,
++     0x00020001L, 0x08020001L, 0x00020009L, 0x08020009L,
++     0x00020401L, 0x08020401L, 0x00020409L, 0x08020409L,
++     0x02000000L, 0x0A000000L, 0x02000008L, 0x0A000008L,
++     0x02000400L, 0x0A000400L, 0x02000408L, 0x0A000408L,
++     0x02020000L, 0x0A020000L, 0x02020008L, 0x0A020008L,
++     0x02020400L, 0x0A020400L, 0x02020408L, 0x0A020408L,
++     0x02000001L, 0x0A000001L, 0x02000009L, 0x0A000009L,
++     0x02000401L, 0x0A000401L, 0x02000409L, 0x0A000409L,
++     0x02020001L, 0x0A020001L, 0x02020009L, 0x0A020009L,
++     0x02020401L, 0x0A020401L, 0x02020409L, 0x0A020409L,
++     },
++    {
++     /* for D bits (numbered as per FIPS 46) 16 17 18 19 20 21 */
++     0x00000000L, 0x00000100L, 0x00080000L, 0x00080100L,
++     0x01000000L, 0x01000100L, 0x01080000L, 0x01080100L,
++     0x00000010L, 0x00000110L, 0x00080010L, 0x00080110L,
++     0x01000010L, 0x01000110L, 0x01080010L, 0x01080110L,
++     0x00200000L, 0x00200100L, 0x00280000L, 0x00280100L,
++     0x01200000L, 0x01200100L, 0x01280000L, 0x01280100L,
++     0x00200010L, 0x00200110L, 0x00280010L, 0x00280110L,
++     0x01200010L, 0x01200110L, 0x01280010L, 0x01280110L,
++     0x00000200L, 0x00000300L, 0x00080200L, 0x00080300L,
++     0x01000200L, 0x01000300L, 0x01080200L, 0x01080300L,
++     0x00000210L, 0x00000310L, 0x00080210L, 0x00080310L,
++     0x01000210L, 0x01000310L, 0x01080210L, 0x01080310L,
++     0x00200200L, 0x00200300L, 0x00280200L, 0x00280300L,
++     0x01200200L, 0x01200300L, 0x01280200L, 0x01280300L,
++     0x00200210L, 0x00200310L, 0x00280210L, 0x00280310L,
++     0x01200210L, 0x01200310L, 0x01280210L, 0x01280310L,
++     },
++    {
++     /* for D bits (numbered as per FIPS 46) 22 23 24 25 27 28 */
++     0x00000000L, 0x04000000L, 0x00040000L, 0x04040000L,
++     0x00000002L, 0x04000002L, 0x00040002L, 0x04040002L,
++     0x00002000L, 0x04002000L, 0x00042000L, 0x04042000L,
++     0x00002002L, 0x04002002L, 0x00042002L, 0x04042002L,
++     0x00000020L, 0x04000020L, 0x00040020L, 0x04040020L,
++     0x00000022L, 0x04000022L, 0x00040022L, 0x04040022L,
++     0x00002020L, 0x04002020L, 0x00042020L, 0x04042020L,
++     0x00002022L, 0x04002022L, 0x00042022L, 0x04042022L,
++     0x00000800L, 0x04000800L, 0x00040800L, 0x04040800L,
++     0x00000802L, 0x04000802L, 0x00040802L, 0x04040802L,
++     0x00002800L, 0x04002800L, 0x00042800L, 0x04042800L,
++     0x00002802L, 0x04002802L, 0x00042802L, 0x04042802L,
++     0x00000820L, 0x04000820L, 0x00040820L, 0x04040820L,
++     0x00000822L, 0x04000822L, 0x00040822L, 0x04040822L,
++     0x00002820L, 0x04002820L, 0x00042820L, 0x04042820L,
++     0x00002822L, 0x04002822L, 0x00042822L, 0x04042822L,
++     }
++};
++
++int DES_set_key(const_DES_cblock *key, DES_key_schedule *schedule)
++{
++    if (DES_check_key) {
++        return DES_set_key_checked(key, schedule);
++    } else {
++        DES_set_key_unchecked(key, schedule);
++        return 0;
++    }
++}
++
++/*-
++ * return 0 if key parity is odd (correct),
++ * return -1 if key parity error,
++ * return -2 if illegal weak key.
++ */
++int DES_set_key_checked(const_DES_cblock *key, DES_key_schedule *schedule)
++{
++    if (!DES_check_key_parity(key))
++        return (-1);
++    if (DES_is_weak_key(key))
++        return (-2);
++    DES_set_key_unchecked(key, schedule);
++    return 0;
++}
++
++void DES_set_key_unchecked(const_DES_cblock *key, DES_key_schedule *schedule)
++{
++    static const int shifts2[16] =
++        { 0, 0, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 0 };
++    register DES_LONG c, d, t, s, t2;
++    register const unsigned char *in;
++    register DES_LONG *k;
++    register int i;
++
++#ifdef OPENBSD_DEV_CRYPTO
++    memcpy(schedule->key, key, sizeof schedule->key);
++    schedule->session = NULL;
++#endif
++    k = &schedule->ks->deslong[0];
++    in = &(*key)[0];
++
++    c2l(in, c);
++    c2l(in, d);
++
++    /*
++     * do PC1 in 47 simple operations :-) Thanks to John Fletcher
++     * (john_fletcher@lccmail.ocf.llnl.gov) for the inspiration. :-)
++     */
++    PERM_OP(d, c, t, 4, 0x0f0f0f0fL);
++    HPERM_OP(c, t, -2, 0xcccc0000L);
++    HPERM_OP(d, t, -2, 0xcccc0000L);
++    PERM_OP(d, c, t, 1, 0x55555555L);
++    PERM_OP(c, d, t, 8, 0x00ff00ffL);
++    PERM_OP(d, c, t, 1, 0x55555555L);
++    d = (((d & 0x000000ffL) << 16L) | (d & 0x0000ff00L) |
++         ((d & 0x00ff0000L) >> 16L) | ((c & 0xf0000000L) >> 4L));
++    c &= 0x0fffffffL;
++
++    for (i = 0; i < ITERATIONS; i++) {
++        if (shifts2[i]) {
++            c = ((c >> 2L) | (c << 26L));
++            d = ((d >> 2L) | (d << 26L));
++        } else {
++            c = ((c >> 1L) | (c << 27L));
++            d = ((d >> 1L) | (d << 27L));
++        }
++        c &= 0x0fffffffL;
++        d &= 0x0fffffffL;
++        /*
++         * could be a few less shifts but I am to lazy at this point in time
++         * to investigate
++         */
++        s = des_skb[0][(c) & 0x3f] |
++            des_skb[1][((c >> 6L) & 0x03) | ((c >> 7L) & 0x3c)] |
++            des_skb[2][((c >> 13L) & 0x0f) | ((c >> 14L) & 0x30)] |
++            des_skb[3][((c >> 20L) & 0x01) | ((c >> 21L) & 0x06) |
++                       ((c >> 22L) & 0x38)];
++        t = des_skb[4][(d) & 0x3f] |
++            des_skb[5][((d >> 7L) & 0x03) | ((d >> 8L) & 0x3c)] |
++            des_skb[6][(d >> 15L) & 0x3f] |
++            des_skb[7][((d >> 21L) & 0x0f) | ((d >> 22L) & 0x30)];
++
++        /* table contained 0213 4657 */
++        t2 = ((t << 16L) | (s & 0x0000ffffL)) & 0xffffffffL;
++        *(k++) = ROTATE(t2, 30) & 0xffffffffL;
++
++        t2 = ((s >> 16L) | (t & 0xffff0000L));
++        *(k++) = ROTATE(t2, 26) & 0xffffffffL;
++    }
++}
++
++int DES_key_sched(const_DES_cblock *key, DES_key_schedule *schedule)
++{
++    return (DES_set_key(key, schedule));
++}
++
++/*-
++#undef des_fixup_key_parity
++void des_fixup_key_parity(des_cblock *key)
++        {
++        des_set_odd_parity(key);
++        }
++*/
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/des/spr.h b/CryptoPkg/Library/OpensslLib/openssl/crypto/des/spr.h
+new file mode 100644
+index 0000000..42adfbf
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/des/spr.h
+@@ -0,0 +1,163 @@
++/*
++ * Copyright 1995-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++OPENSSL_GLOBAL const DES_LONG DES_SPtrans[8][64] = {
++    {
++        /* nibble 0 */
++        0x02080800L, 0x00080000L, 0x02000002L, 0x02080802L,
++        0x02000000L, 0x00080802L, 0x00080002L, 0x02000002L,
++        0x00080802L, 0x02080800L, 0x02080000L, 0x00000802L,
++        0x02000802L, 0x02000000L, 0x00000000L, 0x00080002L,
++        0x00080000L, 0x00000002L, 0x02000800L, 0x00080800L,
++        0x02080802L, 0x02080000L, 0x00000802L, 0x02000800L,
++        0x00000002L, 0x00000800L, 0x00080800L, 0x02080002L,
++        0x00000800L, 0x02000802L, 0x02080002L, 0x00000000L,
++        0x00000000L, 0x02080802L, 0x02000800L, 0x00080002L,
++        0x02080800L, 0x00080000L, 0x00000802L, 0x02000800L,
++        0x02080002L, 0x00000800L, 0x00080800L, 0x02000002L,
++        0x00080802L, 0x00000002L, 0x02000002L, 0x02080000L,
++        0x02080802L, 0x00080800L, 0x02080000L, 0x02000802L,
++        0x02000000L, 0x00000802L, 0x00080002L, 0x00000000L,
++        0x00080000L, 0x02000000L, 0x02000802L, 0x02080800L,
++        0x00000002L, 0x02080002L, 0x00000800L, 0x00080802L,
++    },
++    {
++        /* nibble 1 */
++        0x40108010L, 0x00000000L, 0x00108000L, 0x40100000L,
++        0x40000010L, 0x00008010L, 0x40008000L, 0x00108000L,
++        0x00008000L, 0x40100010L, 0x00000010L, 0x40008000L,
++        0x00100010L, 0x40108000L, 0x40100000L, 0x00000010L,
++        0x00100000L, 0x40008010L, 0x40100010L, 0x00008000L,
++        0x00108010L, 0x40000000L, 0x00000000L, 0x00100010L,
++        0x40008010L, 0x00108010L, 0x40108000L, 0x40000010L,
++        0x40000000L, 0x00100000L, 0x00008010L, 0x40108010L,
++        0x00100010L, 0x40108000L, 0x40008000L, 0x00108010L,
++        0x40108010L, 0x00100010L, 0x40000010L, 0x00000000L,
++        0x40000000L, 0x00008010L, 0x00100000L, 0x40100010L,
++        0x00008000L, 0x40000000L, 0x00108010L, 0x40008010L,
++        0x40108000L, 0x00008000L, 0x00000000L, 0x40000010L,
++        0x00000010L, 0x40108010L, 0x00108000L, 0x40100000L,
++        0x40100010L, 0x00100000L, 0x00008010L, 0x40008000L,
++        0x40008010L, 0x00000010L, 0x40100000L, 0x00108000L,
++    },
++    {
++        /* nibble 2 */
++        0x04000001L, 0x04040100L, 0x00000100L, 0x04000101L,
++        0x00040001L, 0x04000000L, 0x04000101L, 0x00040100L,
++        0x04000100L, 0x00040000L, 0x04040000L, 0x00000001L,
++        0x04040101L, 0x00000101L, 0x00000001L, 0x04040001L,
++        0x00000000L, 0x00040001L, 0x04040100L, 0x00000100L,
++        0x00000101L, 0x04040101L, 0x00040000L, 0x04000001L,
++        0x04040001L, 0x04000100L, 0x00040101L, 0x04040000L,
++        0x00040100L, 0x00000000L, 0x04000000L, 0x00040101L,
++        0x04040100L, 0x00000100L, 0x00000001L, 0x00040000L,
++        0x00000101L, 0x00040001L, 0x04040000L, 0x04000101L,
++        0x00000000L, 0x04040100L, 0x00040100L, 0x04040001L,
++        0x00040001L, 0x04000000L, 0x04040101L, 0x00000001L,
++        0x00040101L, 0x04000001L, 0x04000000L, 0x04040101L,
++        0x00040000L, 0x04000100L, 0x04000101L, 0x00040100L,
++        0x04000100L, 0x00000000L, 0x04040001L, 0x00000101L,
++        0x04000001L, 0x00040101L, 0x00000100L, 0x04040000L,
++    },
++    {
++        /* nibble 3 */
++        0x00401008L, 0x10001000L, 0x00000008L, 0x10401008L,
++        0x00000000L, 0x10400000L, 0x10001008L, 0x00400008L,
++        0x10401000L, 0x10000008L, 0x10000000L, 0x00001008L,
++        0x10000008L, 0x00401008L, 0x00400000L, 0x10000000L,
++        0x10400008L, 0x00401000L, 0x00001000L, 0x00000008L,
++        0x00401000L, 0x10001008L, 0x10400000L, 0x00001000L,
++        0x00001008L, 0x00000000L, 0x00400008L, 0x10401000L,
++        0x10001000L, 0x10400008L, 0x10401008L, 0x00400000L,
++        0x10400008L, 0x00001008L, 0x00400000L, 0x10000008L,
++        0x00401000L, 0x10001000L, 0x00000008L, 0x10400000L,
++        0x10001008L, 0x00000000L, 0x00001000L, 0x00400008L,
++        0x00000000L, 0x10400008L, 0x10401000L, 0x00001000L,
++        0x10000000L, 0x10401008L, 0x00401008L, 0x00400000L,
++        0x10401008L, 0x00000008L, 0x10001000L, 0x00401008L,
++        0x00400008L, 0x00401000L, 0x10400000L, 0x10001008L,
++        0x00001008L, 0x10000000L, 0x10000008L, 0x10401000L,
++    },
++    {
++        /* nibble 4 */
++        0x08000000L, 0x00010000L, 0x00000400L, 0x08010420L,
++        0x08010020L, 0x08000400L, 0x00010420L, 0x08010000L,
++        0x00010000L, 0x00000020L, 0x08000020L, 0x00010400L,
++        0x08000420L, 0x08010020L, 0x08010400L, 0x00000000L,
++        0x00010400L, 0x08000000L, 0x00010020L, 0x00000420L,
++        0x08000400L, 0x00010420L, 0x00000000L, 0x08000020L,
++        0x00000020L, 0x08000420L, 0x08010420L, 0x00010020L,
++        0x08010000L, 0x00000400L, 0x00000420L, 0x08010400L,
++        0x08010400L, 0x08000420L, 0x00010020L, 0x08010000L,
++        0x00010000L, 0x00000020L, 0x08000020L, 0x08000400L,
++        0x08000000L, 0x00010400L, 0x08010420L, 0x00000000L,
++        0x00010420L, 0x08000000L, 0x00000400L, 0x00010020L,
++        0x08000420L, 0x00000400L, 0x00000000L, 0x08010420L,
++        0x08010020L, 0x08010400L, 0x00000420L, 0x00010000L,
++        0x00010400L, 0x08010020L, 0x08000400L, 0x00000420L,
++        0x00000020L, 0x00010420L, 0x08010000L, 0x08000020L,
++    },
++    {
++        /* nibble 5 */
++        0x80000040L, 0x00200040L, 0x00000000L, 0x80202000L,
++        0x00200040L, 0x00002000L, 0x80002040L, 0x00200000L,
++        0x00002040L, 0x80202040L, 0x00202000L, 0x80000000L,
++        0x80002000L, 0x80000040L, 0x80200000L, 0x00202040L,
++        0x00200000L, 0x80002040L, 0x80200040L, 0x00000000L,
++        0x00002000L, 0x00000040L, 0x80202000L, 0x80200040L,
++        0x80202040L, 0x80200000L, 0x80000000L, 0x00002040L,
++        0x00000040L, 0x00202000L, 0x00202040L, 0x80002000L,
++        0x00002040L, 0x80000000L, 0x80002000L, 0x00202040L,
++        0x80202000L, 0x00200040L, 0x00000000L, 0x80002000L,
++        0x80000000L, 0x00002000L, 0x80200040L, 0x00200000L,
++        0x00200040L, 0x80202040L, 0x00202000L, 0x00000040L,
++        0x80202040L, 0x00202000L, 0x00200000L, 0x80002040L,
++        0x80000040L, 0x80200000L, 0x00202040L, 0x00000000L,
++        0x00002000L, 0x80000040L, 0x80002040L, 0x80202000L,
++        0x80200000L, 0x00002040L, 0x00000040L, 0x80200040L,
++    },
++    {
++        /* nibble 6 */
++        0x00004000L, 0x00000200L, 0x01000200L, 0x01000004L,
++        0x01004204L, 0x00004004L, 0x00004200L, 0x00000000L,
++        0x01000000L, 0x01000204L, 0x00000204L, 0x01004000L,
++        0x00000004L, 0x01004200L, 0x01004000L, 0x00000204L,
++        0x01000204L, 0x00004000L, 0x00004004L, 0x01004204L,
++        0x00000000L, 0x01000200L, 0x01000004L, 0x00004200L,
++        0x01004004L, 0x00004204L, 0x01004200L, 0x00000004L,
++        0x00004204L, 0x01004004L, 0x00000200L, 0x01000000L,
++        0x00004204L, 0x01004000L, 0x01004004L, 0x00000204L,
++        0x00004000L, 0x00000200L, 0x01000000L, 0x01004004L,
++        0x01000204L, 0x00004204L, 0x00004200L, 0x00000000L,
++        0x00000200L, 0x01000004L, 0x00000004L, 0x01000200L,
++        0x00000000L, 0x01000204L, 0x01000200L, 0x00004200L,
++        0x00000204L, 0x00004000L, 0x01004204L, 0x01000000L,
++        0x01004200L, 0x00000004L, 0x00004004L, 0x01004204L,
++        0x01000004L, 0x01004200L, 0x01004000L, 0x00004004L,
++    },
++    {
++        /* nibble 7 */
++        0x20800080L, 0x20820000L, 0x00020080L, 0x00000000L,
++        0x20020000L, 0x00800080L, 0x20800000L, 0x20820080L,
++        0x00000080L, 0x20000000L, 0x00820000L, 0x00020080L,
++        0x00820080L, 0x20020080L, 0x20000080L, 0x20800000L,
++        0x00020000L, 0x00820080L, 0x00800080L, 0x20020000L,
++        0x20820080L, 0x20000080L, 0x00000000L, 0x00820000L,
++        0x20000000L, 0x00800000L, 0x20020080L, 0x20800080L,
++        0x00800000L, 0x00020000L, 0x20820000L, 0x00000080L,
++        0x00800000L, 0x00020000L, 0x20000080L, 0x20820080L,
++        0x00020080L, 0x20000000L, 0x00000000L, 0x00820000L,
++        0x20800080L, 0x20020080L, 0x20020000L, 0x00800080L,
++        0x20820000L, 0x00000080L, 0x00800080L, 0x20020000L,
++        0x20820080L, 0x00800000L, 0x20800000L, 0x20000080L,
++        0x00820000L, 0x00020080L, 0x20020080L, 0x20800000L,
++        0x00000080L, 0x20820000L, 0x00820080L, 0x00000000L,
++        0x20000000L, 0x20800080L, 0x00020000L, 0x00820080L,
++    }
++};
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/des/str2key.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/des/str2key.c
+new file mode 100644
+index 0000000..78998a1
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/des/str2key.c
+@@ -0,0 +1,97 @@
++/*
++ * Copyright 1995-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include "des_locl.h"
++
++void DES_string_to_key(const char *str, DES_cblock *key)
++{
++    DES_key_schedule ks;
++    int i, length;
++
++    memset(key, 0, 8);
++    length = strlen(str);
++#ifdef OLD_STR_TO_KEY
++    for (i = 0; i < length; i++)
++        (*key)[i % 8] ^= (str[i] << 1);
++#else                           /* MIT COMPATIBLE */
++    for (i = 0; i < length; i++) {
++        register unsigned char j = str[i];
++
++        if ((i % 16) < 8)
++            (*key)[i % 8] ^= (j << 1);
++        else {
++            /* Reverse the bit order 05/05/92 eay */
++            j = ((j << 4) & 0xf0) | ((j >> 4) & 0x0f);
++            j = ((j << 2) & 0xcc) | ((j >> 2) & 0x33);
++            j = ((j << 1) & 0xaa) | ((j >> 1) & 0x55);
++            (*key)[7 - (i % 8)] ^= j;
++        }
++    }
++#endif
++    DES_set_odd_parity(key);
++    DES_set_key_unchecked(key, &ks);
++    DES_cbc_cksum((const unsigned char *)str, key, length, &ks, key);
++    OPENSSL_cleanse(&ks, sizeof(ks));
++    DES_set_odd_parity(key);
++}
++
++void DES_string_to_2keys(const char *str, DES_cblock *key1, DES_cblock *key2)
++{
++    DES_key_schedule ks;
++    int i, length;
++
++    memset(key1, 0, 8);
++    memset(key2, 0, 8);
++    length = strlen(str);
++#ifdef OLD_STR_TO_KEY
++    if (length <= 8) {
++        for (i = 0; i < length; i++) {
++            (*key2)[i] = (*key1)[i] = (str[i] << 1);
++        }
++    } else {
++        for (i = 0; i < length; i++) {
++            if ((i / 8) & 1)
++                (*key2)[i % 8] ^= (str[i] << 1);
++            else
++                (*key1)[i % 8] ^= (str[i] << 1);
++        }
++    }
++#else                           /* MIT COMPATIBLE */
++    for (i = 0; i < length; i++) {
++        register unsigned char j = str[i];
++
++        if ((i % 32) < 16) {
++            if ((i % 16) < 8)
++                (*key1)[i % 8] ^= (j << 1);
++            else
++                (*key2)[i % 8] ^= (j << 1);
++        } else {
++            j = ((j << 4) & 0xf0) | ((j >> 4) & 0x0f);
++            j = ((j << 2) & 0xcc) | ((j >> 2) & 0x33);
++            j = ((j << 1) & 0xaa) | ((j >> 1) & 0x55);
++            if ((i % 16) < 8)
++                (*key1)[7 - (i % 8)] ^= j;
++            else
++                (*key2)[7 - (i % 8)] ^= j;
++        }
++    }
++    if (length <= 8)
++        memcpy(key2, key1, 8);
++#endif
++    DES_set_odd_parity(key1);
++    DES_set_odd_parity(key2);
++    DES_set_key_unchecked(key1, &ks);
++    DES_cbc_cksum((const unsigned char *)str, key1, length, &ks, key1);
++    DES_set_key_unchecked(key2, &ks);
++    DES_cbc_cksum((const unsigned char *)str, key2, length, &ks, key2);
++    OPENSSL_cleanse(&ks, sizeof(ks));
++    DES_set_odd_parity(key1);
++    DES_set_odd_parity(key2);
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/des/xcbc_enc.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/des/xcbc_enc.c
+new file mode 100644
+index 0000000..c4e455d
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/des/xcbc_enc.c
+@@ -0,0 +1,103 @@
++/*
++ * Copyright 1995-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include "des_locl.h"
++
++/* RSA's DESX */
++
++void DES_xcbc_encrypt(const unsigned char *in, unsigned char *out,
++                      long length, DES_key_schedule *schedule,
++                      DES_cblock *ivec, const_DES_cblock *inw,
++                      const_DES_cblock *outw, int enc)
++{
++    register DES_LONG tin0, tin1;
++    register DES_LONG tout0, tout1, xor0, xor1;
++    register DES_LONG inW0, inW1, outW0, outW1;
++    register const unsigned char *in2;
++    register long l = length;
++    DES_LONG tin[2];
++    unsigned char *iv;
++
++    in2 = &(*inw)[0];
++    c2l(in2, inW0);
++    c2l(in2, inW1);
++    in2 = &(*outw)[0];
++    c2l(in2, outW0);
++    c2l(in2, outW1);
++
++    iv = &(*ivec)[0];
++
++    if (enc) {
++        c2l(iv, tout0);
++        c2l(iv, tout1);
++        for (l -= 8; l >= 0; l -= 8) {
++            c2l(in, tin0);
++            c2l(in, tin1);
++            tin0 ^= tout0 ^ inW0;
++            tin[0] = tin0;
++            tin1 ^= tout1 ^ inW1;
++            tin[1] = tin1;
++            DES_encrypt1(tin, schedule, DES_ENCRYPT);
++            tout0 = tin[0] ^ outW0;
++            l2c(tout0, out);
++            tout1 = tin[1] ^ outW1;
++            l2c(tout1, out);
++        }
++        if (l != -8) {
++            c2ln(in, tin0, tin1, l + 8);
++            tin0 ^= tout0 ^ inW0;
++            tin[0] = tin0;
++            tin1 ^= tout1 ^ inW1;
++            tin[1] = tin1;
++            DES_encrypt1(tin, schedule, DES_ENCRYPT);
++            tout0 = tin[0] ^ outW0;
++            l2c(tout0, out);
++            tout1 = tin[1] ^ outW1;
++            l2c(tout1, out);
++        }
++        iv = &(*ivec)[0];
++        l2c(tout0, iv);
++        l2c(tout1, iv);
++    } else {
++        c2l(iv, xor0);
++        c2l(iv, xor1);
++        for (l -= 8; l > 0; l -= 8) {
++            c2l(in, tin0);
++            tin[0] = tin0 ^ outW0;
++            c2l(in, tin1);
++            tin[1] = tin1 ^ outW1;
++            DES_encrypt1(tin, schedule, DES_DECRYPT);
++            tout0 = tin[0] ^ xor0 ^ inW0;
++            tout1 = tin[1] ^ xor1 ^ inW1;
++            l2c(tout0, out);
++            l2c(tout1, out);
++            xor0 = tin0;
++            xor1 = tin1;
++        }
++        if (l != -8) {
++            c2l(in, tin0);
++            tin[0] = tin0 ^ outW0;
++            c2l(in, tin1);
++            tin[1] = tin1 ^ outW1;
++            DES_encrypt1(tin, schedule, DES_DECRYPT);
++            tout0 = tin[0] ^ xor0 ^ inW0;
++            tout1 = tin[1] ^ xor1 ^ inW1;
++            l2cn(tout0, tout1, out, l + 8);
++            xor0 = tin0;
++            xor1 = tin1;
++        }
++
++        iv = &(*ivec)[0];
++        l2c(xor0, iv);
++        l2c(xor1, iv);
++    }
++    tin0 = tin1 = tout0 = tout1 = xor0 = xor1 = 0;
++    inW0 = inW1 = outW0 = outW1 = 0;
++    tin[0] = tin[1] = 0;
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/dh/build.info b/CryptoPkg/Library/OpensslLib/openssl/crypto/dh/build.info
+new file mode 100644
+index 0000000..dba9306
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/dh/build.info
+@@ -0,0 +1,4 @@
++LIBS=../../libcrypto
++SOURCE[../../libcrypto]=\
++        dh_asn1.c dh_gen.c dh_key.c dh_lib.c dh_check.c dh_err.c dh_depr.c \
++        dh_ameth.c dh_pmeth.c dh_prn.c dh_rfc5114.c dh_kdf.c dh_meth.c
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/dh/dh1024.pem b/CryptoPkg/Library/OpensslLib/openssl/crypto/dh/dh1024.pem
+new file mode 100644
+index 0000000..81d43f6
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/dh/dh1024.pem
+@@ -0,0 +1,5 @@
++-----BEGIN DH PARAMETERS-----
++MIGHAoGBAJf2QmHKtQXdKCjhPx1ottPb0PMTBH9A6FbaWMsTuKG/K3g6TG1Z1fkq
++/Gz/PWk/eLI9TzFgqVAuPvr3q14a1aZeVUMTgo2oO5/y2UHe6VaJ+trqCTat3xlx
++/mNbIK9HA2RgPC3gWfVLZQrY+gz3ASHHR5nXWHEyvpuZm7m3h+irAgEC
++-----END DH PARAMETERS-----
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/dh/dh192.pem b/CryptoPkg/Library/OpensslLib/openssl/crypto/dh/dh192.pem
+new file mode 100644
+index 0000000..521c072
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/dh/dh192.pem
+@@ -0,0 +1,3 @@
++-----BEGIN DH PARAMETERS-----
++MB4CGQDUoLoCULb9LsYm5+/WN992xxbiLQlEuIsCAQM=
++-----END DH PARAMETERS-----
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/dh/dh2048.pem b/CryptoPkg/Library/OpensslLib/openssl/crypto/dh/dh2048.pem
+new file mode 100644
+index 0000000..295460f
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/dh/dh2048.pem
+@@ -0,0 +1,16 @@
++-----BEGIN DH PARAMETERS-----
++MIIBCAKCAQEA7ZKJNYJFVcs7+6J2WmkEYb8h86tT0s0h2v94GRFS8Q7B4lW9aG9o
++AFO5Imov5Jo0H2XMWTKKvbHbSe3fpxJmw/0hBHAY8H/W91hRGXKCeyKpNBgdL8sh
++z22SrkO2qCnHJ6PLAMXy5fsKpFmFor2tRfCzrfnggTXu2YOzzK7q62bmqVdmufEo
++pT8igNcLpvZxk5uBDvhakObMym9mX3rAEBoe8PwttggMYiiw7NuJKO4MqD1llGkW
++aVM8U2ATsCun1IKHrRxynkE1/MJ86VHeYYX8GZt2YA8z+GuzylIOKcMH6JAWzMwA
++Gbatw6QwizOhr9iMjZ0B26TE3X8LvW84wwIBAg==
++-----END DH PARAMETERS-----
++-----BEGIN DH PARAMETERS-----
++MIIBCAKCAQEArtA3w73zP6Lu3EOQtwogiXt3AXXpuS6yD4BhzNS1pZFyPHk0/an5
++8ydEkPhQZHKDW+BZJxxPLANaTudWo2YT8TgtvUdN6KSgMiEi6McwqDw+SADuvW+F
++SKUYFxG6VFIxyEP6xBdf+vhJxEDbRG2EYsHDRRtJ76gp9cSKTHusf2R+4AAVGqnt
++gRAbNqtcOar/7FSj+Pl8G3v0Bty0LcCSpbqgYlnv6z+rErQmmC6PPvSz97TDMCok
++yKpCE9hFA1zkqK3TH4FmFvGeIaXJUIBZf4mArWuBTjWFW3nmhESRUn1VK3K3x42N
++a5k6c2+EhrMFiLjxuH6JZoqL0/E93FF9SwIBAg==
++-----END DH PARAMETERS-----
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/dh/dh4096.pem b/CryptoPkg/Library/OpensslLib/openssl/crypto/dh/dh4096.pem
+new file mode 100644
+index 0000000..390943a
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/dh/dh4096.pem
+@@ -0,0 +1,14 @@
++-----BEGIN DH PARAMETERS-----
++MIICCAKCAgEA/urRnb6vkPYc/KEGXWnbCIOaKitq7ySIq9dTH7s+Ri59zs77zty7
++vfVlSe6VFTBWgYjD2XKUFmtqq6CqXMhVX5ElUDoYDpAyTH85xqNFLzFC7nKrff/H
++TFKNttp22cZE9V0IPpzedPfnQkE7aUdmF9JnDyv21Z/818O93u1B4r0szdnmEvEF
++bKuIxEHX+bp0ZR7RqE1AeifXGJX3d6tsd2PMAObxwwsv55RGkn50vHO4QxtTARr1
++rRUV5j3B3oPMgC7Offxx+98Xn45B1/G0Prp11anDsR1PGwtaCYipqsvMwQUSJtyE
++EOQWk+yFkeMe4vWv367eEi0Sd/wnC+TSXBE3pYvpYerJ8n1MceI5GQTdarJ77OW9
++bGTHmxRsLSCM1jpLdPja5jjb4siAa6EHc4qN9c/iFKS3PQPJEnX7pXKBRs5f7AF3
++W3RIGt+G9IVNZfXaS7Z/iCpgzgvKCs0VeqN38QsJGtC1aIkwOeyjPNy2G6jJ4yqH
++ovXYt/0mc00vCWeSNS1wren0pR2EiLxX0ypjjgsU1mk/Z3b/+zVf7fZSIB+nDLjb
++NPtUlJCVGnAeBK1J1nG3TQicqowOXoM6ISkdaXj5GPJdXHab2+S7cqhKGv5qC7rR
++jT6sx7RUr0CNTxzLI7muV2/a4tGmj0PSdXQdsZ7tw7gbXlaWT1+MM2MCAQI=
++-----END DH PARAMETERS-----
++
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/dh/dh512.pem b/CryptoPkg/Library/OpensslLib/openssl/crypto/dh/dh512.pem
+new file mode 100644
+index 0000000..0a4d863
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/dh/dh512.pem
+@@ -0,0 +1,4 @@
++-----BEGIN DH PARAMETERS-----
++MEYCQQDaWDwW2YUiidDkr3VvTMqS3UvlM7gE+w/tlO+cikQD7VdGUNNpmdsp13Yn
++a6LT1BLiGPTdHghM9tgAPnxHdOgzAgEC
++-----END DH PARAMETERS-----
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/dh/dh_ameth.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/dh/dh_ameth.c
+new file mode 100644
+index 0000000..cd77867
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/dh/dh_ameth.c
+@@ -0,0 +1,870 @@
++/*
++ * Copyright 2006-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include "internal/cryptlib.h"
++#include 
++#include 
++#include "dh_locl.h"
++#include 
++#include "internal/asn1_int.h"
++#include "internal/evp_int.h"
++#include 
++
++/*
++ * i2d/d2i like DH parameter functions which use the appropriate routine for
++ * PKCS#3 DH or X9.42 DH.
++ */
++
++static DH *d2i_dhp(const EVP_PKEY *pkey, const unsigned char **pp,
++                   long length)
++{
++    if (pkey->ameth == &dhx_asn1_meth)
++        return d2i_DHxparams(NULL, pp, length);
++    return d2i_DHparams(NULL, pp, length);
++}
++
++static int i2d_dhp(const EVP_PKEY *pkey, const DH *a, unsigned char **pp)
++{
++    if (pkey->ameth == &dhx_asn1_meth)
++        return i2d_DHxparams(a, pp);
++    return i2d_DHparams(a, pp);
++}
++
++static void int_dh_free(EVP_PKEY *pkey)
++{
++    DH_free(pkey->pkey.dh);
++}
++
++static int dh_pub_decode(EVP_PKEY *pkey, X509_PUBKEY *pubkey)
++{
++    const unsigned char *p, *pm;
++    int pklen, pmlen;
++    int ptype;
++    const void *pval;
++    const ASN1_STRING *pstr;
++    X509_ALGOR *palg;
++    ASN1_INTEGER *public_key = NULL;
++
++    DH *dh = NULL;
++
++    if (!X509_PUBKEY_get0_param(NULL, &p, &pklen, &palg, pubkey))
++        return 0;
++    X509_ALGOR_get0(NULL, &ptype, &pval, palg);
++
++    if (ptype != V_ASN1_SEQUENCE) {
++        DHerr(DH_F_DH_PUB_DECODE, DH_R_PARAMETER_ENCODING_ERROR);
++        goto err;
++    }
++
++    pstr = pval;
++    pm = pstr->data;
++    pmlen = pstr->length;
++
++    if ((dh = d2i_dhp(pkey, &pm, pmlen)) == NULL) {
++        DHerr(DH_F_DH_PUB_DECODE, DH_R_DECODE_ERROR);
++        goto err;
++    }
++
++    if ((public_key = d2i_ASN1_INTEGER(NULL, &p, pklen)) == NULL) {
++        DHerr(DH_F_DH_PUB_DECODE, DH_R_DECODE_ERROR);
++        goto err;
++    }
++
++    /* We have parameters now set public key */
++    if ((dh->pub_key = ASN1_INTEGER_to_BN(public_key, NULL)) == NULL) {
++        DHerr(DH_F_DH_PUB_DECODE, DH_R_BN_DECODE_ERROR);
++        goto err;
++    }
++
++    ASN1_INTEGER_free(public_key);
++    EVP_PKEY_assign(pkey, pkey->ameth->pkey_id, dh);
++    return 1;
++
++ err:
++    ASN1_INTEGER_free(public_key);
++    DH_free(dh);
++    return 0;
++
++}
++
++static int dh_pub_encode(X509_PUBKEY *pk, const EVP_PKEY *pkey)
++{
++    DH *dh;
++    int ptype;
++    unsigned char *penc = NULL;
++    int penclen;
++    ASN1_STRING *str;
++    ASN1_INTEGER *pub_key = NULL;
++
++    dh = pkey->pkey.dh;
++
++    str = ASN1_STRING_new();
++    if (str == NULL) {
++        DHerr(DH_F_DH_PUB_ENCODE, ERR_R_MALLOC_FAILURE);
++        goto err;
++    }
++    str->length = i2d_dhp(pkey, dh, &str->data);
++    if (str->length <= 0) {
++        DHerr(DH_F_DH_PUB_ENCODE, ERR_R_MALLOC_FAILURE);
++        goto err;
++    }
++    ptype = V_ASN1_SEQUENCE;
++
++    pub_key = BN_to_ASN1_INTEGER(dh->pub_key, NULL);
++    if (!pub_key)
++        goto err;
++
++    penclen = i2d_ASN1_INTEGER(pub_key, &penc);
++
++    ASN1_INTEGER_free(pub_key);
++
++    if (penclen <= 0) {
++        DHerr(DH_F_DH_PUB_ENCODE, ERR_R_MALLOC_FAILURE);
++        goto err;
++    }
++
++    if (X509_PUBKEY_set0_param(pk, OBJ_nid2obj(pkey->ameth->pkey_id),
++                               ptype, str, penc, penclen))
++        return 1;
++
++ err:
++    OPENSSL_free(penc);
++    ASN1_STRING_free(str);
++
++    return 0;
++}
++
++/*
++ * PKCS#8 DH is defined in PKCS#11 of all places. It is similar to DH in that
++ * the AlgorithmIdentifier contains the parameters, the private key is
++ * explicitly included and the pubkey must be recalculated.
++ */
++
++static int dh_priv_decode(EVP_PKEY *pkey, const PKCS8_PRIV_KEY_INFO *p8)
++{
++    const unsigned char *p, *pm;
++    int pklen, pmlen;
++    int ptype;
++    const void *pval;
++    const ASN1_STRING *pstr;
++    const X509_ALGOR *palg;
++    ASN1_INTEGER *privkey = NULL;
++
++    DH *dh = NULL;
++
++    if (!PKCS8_pkey_get0(NULL, &p, &pklen, &palg, p8))
++        return 0;
++
++    X509_ALGOR_get0(NULL, &ptype, &pval, palg);
++
++    if (ptype != V_ASN1_SEQUENCE)
++        goto decerr;
++    if ((privkey = d2i_ASN1_INTEGER(NULL, &p, pklen)) == NULL)
++        goto decerr;
++
++    pstr = pval;
++    pm = pstr->data;
++    pmlen = pstr->length;
++    if ((dh = d2i_dhp(pkey, &pm, pmlen)) == NULL)
++        goto decerr;
++
++    /* We have parameters now set private key */
++    if ((dh->priv_key = BN_secure_new()) == NULL
++        || !ASN1_INTEGER_to_BN(privkey, dh->priv_key)) {
++        DHerr(DH_F_DH_PRIV_DECODE, DH_R_BN_ERROR);
++        goto dherr;
++    }
++    /* Calculate public key */
++    if (!DH_generate_key(dh))
++        goto dherr;
++
++    EVP_PKEY_assign(pkey, pkey->ameth->pkey_id, dh);
++
++    ASN1_STRING_clear_free(privkey);
++
++    return 1;
++
++ decerr:
++    DHerr(DH_F_DH_PRIV_DECODE, EVP_R_DECODE_ERROR);
++ dherr:
++    DH_free(dh);
++    ASN1_STRING_clear_free(privkey);
++    return 0;
++}
++
++static int dh_priv_encode(PKCS8_PRIV_KEY_INFO *p8, const EVP_PKEY *pkey)
++{
++    ASN1_STRING *params = NULL;
++    ASN1_INTEGER *prkey = NULL;
++    unsigned char *dp = NULL;
++    int dplen;
++
++    params = ASN1_STRING_new();
++
++    if (params == NULL) {
++        DHerr(DH_F_DH_PRIV_ENCODE, ERR_R_MALLOC_FAILURE);
++        goto err;
++    }
++
++    params->length = i2d_dhp(pkey, pkey->pkey.dh, ¶ms->data);
++    if (params->length <= 0) {
++        DHerr(DH_F_DH_PRIV_ENCODE, ERR_R_MALLOC_FAILURE);
++        goto err;
++    }
++    params->type = V_ASN1_SEQUENCE;
++
++    /* Get private key into integer */
++    prkey = BN_to_ASN1_INTEGER(pkey->pkey.dh->priv_key, NULL);
++
++    if (!prkey) {
++        DHerr(DH_F_DH_PRIV_ENCODE, DH_R_BN_ERROR);
++        goto err;
++    }
++
++    dplen = i2d_ASN1_INTEGER(prkey, &dp);
++
++    ASN1_STRING_clear_free(prkey);
++    prkey = NULL;
++
++    if (!PKCS8_pkey_set0(p8, OBJ_nid2obj(pkey->ameth->pkey_id), 0,
++                         V_ASN1_SEQUENCE, params, dp, dplen))
++        goto err;
++
++    return 1;
++
++ err:
++    OPENSSL_free(dp);
++    ASN1_STRING_free(params);
++    ASN1_STRING_clear_free(prkey);
++    return 0;
++}
++
++static int dh_param_decode(EVP_PKEY *pkey,
++                           const unsigned char **pder, int derlen)
++{
++    DH *dh;
++
++    if ((dh = d2i_dhp(pkey, pder, derlen)) == NULL) {
++        DHerr(DH_F_DH_PARAM_DECODE, ERR_R_DH_LIB);
++        return 0;
++    }
++    EVP_PKEY_assign(pkey, pkey->ameth->pkey_id, dh);
++    return 1;
++}
++
++static int dh_param_encode(const EVP_PKEY *pkey, unsigned char **pder)
++{
++    return i2d_dhp(pkey, pkey->pkey.dh, pder);
++}
++
++static int do_dh_print(BIO *bp, const DH *x, int indent, int ptype)
++{
++    int reason = ERR_R_BUF_LIB;
++    const char *ktype = NULL;
++    BIGNUM *priv_key, *pub_key;
++
++    if (ptype == 2)
++        priv_key = x->priv_key;
++    else
++        priv_key = NULL;
++
++    if (ptype > 0)
++        pub_key = x->pub_key;
++    else
++        pub_key = NULL;
++
++    if (x->p == NULL || (ptype == 2 && priv_key == NULL)
++            || (ptype > 0 && pub_key == NULL)) {
++        reason = ERR_R_PASSED_NULL_PARAMETER;
++        goto err;
++    }
++
++    if (ptype == 2)
++        ktype = "DH Private-Key";
++    else if (ptype == 1)
++        ktype = "DH Public-Key";
++    else
++        ktype = "DH Parameters";
++
++    BIO_indent(bp, indent, 128);
++    if (BIO_printf(bp, "%s: (%d bit)\n", ktype, BN_num_bits(x->p)) <= 0)
++        goto err;
++    indent += 4;
++
++    if (!ASN1_bn_print(bp, "private-key:", priv_key, NULL, indent))
++        goto err;
++    if (!ASN1_bn_print(bp, "public-key:", pub_key, NULL, indent))
++        goto err;
++
++    if (!ASN1_bn_print(bp, "prime:", x->p, NULL, indent))
++        goto err;
++    if (!ASN1_bn_print(bp, "generator:", x->g, NULL, indent))
++        goto err;
++    if (x->q && !ASN1_bn_print(bp, "subgroup order:", x->q, NULL, indent))
++        goto err;
++    if (x->j && !ASN1_bn_print(bp, "subgroup factor:", x->j, NULL, indent))
++        goto err;
++    if (x->seed) {
++        int i;
++        BIO_indent(bp, indent, 128);
++        BIO_puts(bp, "seed:");
++        for (i = 0; i < x->seedlen; i++) {
++            if ((i % 15) == 0) {
++                if (BIO_puts(bp, "\n") <= 0
++                    || !BIO_indent(bp, indent + 4, 128))
++                    goto err;
++            }
++            if (BIO_printf(bp, "%02x%s", x->seed[i],
++                           ((i + 1) == x->seedlen) ? "" : ":") <= 0)
++                goto err;
++        }
++        if (BIO_write(bp, "\n", 1) <= 0)
++            return (0);
++    }
++    if (x->counter && !ASN1_bn_print(bp, "counter:", x->counter, NULL, indent))
++        goto err;
++    if (x->length != 0) {
++        BIO_indent(bp, indent, 128);
++        if (BIO_printf(bp, "recommended-private-length: %d bits\n",
++                       (int)x->length) <= 0)
++            goto err;
++    }
++
++    return 1;
++
++ err:
++    DHerr(DH_F_DO_DH_PRINT, reason);
++    return 0;
++}
++
++static int int_dh_size(const EVP_PKEY *pkey)
++{
++    return (DH_size(pkey->pkey.dh));
++}
++
++static int dh_bits(const EVP_PKEY *pkey)
++{
++    return BN_num_bits(pkey->pkey.dh->p);
++}
++
++static int dh_security_bits(const EVP_PKEY *pkey)
++{
++    return DH_security_bits(pkey->pkey.dh);
++}
++
++static int dh_cmp_parameters(const EVP_PKEY *a, const EVP_PKEY *b)
++{
++    if (BN_cmp(a->pkey.dh->p, b->pkey.dh->p) ||
++        BN_cmp(a->pkey.dh->g, b->pkey.dh->g))
++        return 0;
++    else if (a->ameth == &dhx_asn1_meth) {
++        if (BN_cmp(a->pkey.dh->q, b->pkey.dh->q))
++            return 0;
++    }
++    return 1;
++}
++
++static int int_dh_bn_cpy(BIGNUM **dst, const BIGNUM *src)
++{
++    BIGNUM *a;
++    if (src) {
++        a = BN_dup(src);
++        if (!a)
++            return 0;
++    } else
++        a = NULL;
++    BN_free(*dst);
++    *dst = a;
++    return 1;
++}
++
++static int int_dh_param_copy(DH *to, const DH *from, int is_x942)
++{
++    if (is_x942 == -1)
++        is_x942 = ! !from->q;
++    if (!int_dh_bn_cpy(&to->p, from->p))
++        return 0;
++    if (!int_dh_bn_cpy(&to->g, from->g))
++        return 0;
++    if (is_x942) {
++        if (!int_dh_bn_cpy(&to->q, from->q))
++            return 0;
++        if (!int_dh_bn_cpy(&to->j, from->j))
++            return 0;
++        OPENSSL_free(to->seed);
++        to->seed = NULL;
++        to->seedlen = 0;
++        if (from->seed) {
++            to->seed = OPENSSL_memdup(from->seed, from->seedlen);
++            if (!to->seed)
++                return 0;
++            to->seedlen = from->seedlen;
++        }
++    } else
++        to->length = from->length;
++    return 1;
++}
++
++DH *DHparams_dup(DH *dh)
++{
++    DH *ret;
++    ret = DH_new();
++    if (ret == NULL)
++        return NULL;
++    if (!int_dh_param_copy(ret, dh, -1)) {
++        DH_free(ret);
++        return NULL;
++    }
++    return ret;
++}
++
++static int dh_copy_parameters(EVP_PKEY *to, const EVP_PKEY *from)
++{
++    if (to->pkey.dh == NULL) {
++        to->pkey.dh = DH_new();
++        if (to->pkey.dh == NULL)
++            return 0;
++    }
++    return int_dh_param_copy(to->pkey.dh, from->pkey.dh,
++                             from->ameth == &dhx_asn1_meth);
++}
++
++static int dh_missing_parameters(const EVP_PKEY *a)
++{
++    if (a->pkey.dh == NULL || a->pkey.dh->p == NULL || a->pkey.dh->g == NULL)
++        return 1;
++    return 0;
++}
++
++static int dh_pub_cmp(const EVP_PKEY *a, const EVP_PKEY *b)
++{
++    if (dh_cmp_parameters(a, b) == 0)
++        return 0;
++    if (BN_cmp(b->pkey.dh->pub_key, a->pkey.dh->pub_key) != 0)
++        return 0;
++    else
++        return 1;
++}
++
++static int dh_param_print(BIO *bp, const EVP_PKEY *pkey, int indent,
++                          ASN1_PCTX *ctx)
++{
++    return do_dh_print(bp, pkey->pkey.dh, indent, 0);
++}
++
++static int dh_public_print(BIO *bp, const EVP_PKEY *pkey, int indent,
++                           ASN1_PCTX *ctx)
++{
++    return do_dh_print(bp, pkey->pkey.dh, indent, 1);
++}
++
++static int dh_private_print(BIO *bp, const EVP_PKEY *pkey, int indent,
++                            ASN1_PCTX *ctx)
++{
++    return do_dh_print(bp, pkey->pkey.dh, indent, 2);
++}
++
++int DHparams_print(BIO *bp, const DH *x)
++{
++    return do_dh_print(bp, x, 4, 0);
++}
++
++#ifndef OPENSSL_NO_CMS
++static int dh_cms_decrypt(CMS_RecipientInfo *ri);
++static int dh_cms_encrypt(CMS_RecipientInfo *ri);
++#endif
++
++static int dh_pkey_ctrl(EVP_PKEY *pkey, int op, long arg1, void *arg2)
++{
++    switch (op) {
++#ifndef OPENSSL_NO_CMS
++
++    case ASN1_PKEY_CTRL_CMS_ENVELOPE:
++        if (arg1 == 1)
++            return dh_cms_decrypt(arg2);
++        else if (arg1 == 0)
++            return dh_cms_encrypt(arg2);
++        return -2;
++
++    case ASN1_PKEY_CTRL_CMS_RI_TYPE:
++        *(int *)arg2 = CMS_RECIPINFO_AGREE;
++        return 1;
++#endif
++    default:
++        return -2;
++    }
++
++}
++
++const EVP_PKEY_ASN1_METHOD dh_asn1_meth = {
++    EVP_PKEY_DH,
++    EVP_PKEY_DH,
++    0,
++
++    "DH",
++    "OpenSSL PKCS#3 DH method",
++
++    dh_pub_decode,
++    dh_pub_encode,
++    dh_pub_cmp,
++    dh_public_print,
++
++    dh_priv_decode,
++    dh_priv_encode,
++    dh_private_print,
++
++    int_dh_size,
++    dh_bits,
++    dh_security_bits,
++
++    dh_param_decode,
++    dh_param_encode,
++    dh_missing_parameters,
++    dh_copy_parameters,
++    dh_cmp_parameters,
++    dh_param_print,
++    0,
++
++    int_dh_free,
++    0
++};
++
++const EVP_PKEY_ASN1_METHOD dhx_asn1_meth = {
++    EVP_PKEY_DHX,
++    EVP_PKEY_DHX,
++    0,
++
++    "X9.42 DH",
++    "OpenSSL X9.42 DH method",
++
++    dh_pub_decode,
++    dh_pub_encode,
++    dh_pub_cmp,
++    dh_public_print,
++
++    dh_priv_decode,
++    dh_priv_encode,
++    dh_private_print,
++
++    int_dh_size,
++    dh_bits,
++    dh_security_bits,
++
++    dh_param_decode,
++    dh_param_encode,
++    dh_missing_parameters,
++    dh_copy_parameters,
++    dh_cmp_parameters,
++    dh_param_print,
++    0,
++
++    int_dh_free,
++    dh_pkey_ctrl
++};
++
++#ifndef OPENSSL_NO_CMS
++
++static int dh_cms_set_peerkey(EVP_PKEY_CTX *pctx,
++                              X509_ALGOR *alg, ASN1_BIT_STRING *pubkey)
++{
++    const ASN1_OBJECT *aoid;
++    int atype;
++    const void *aval;
++    ASN1_INTEGER *public_key = NULL;
++    int rv = 0;
++    EVP_PKEY *pkpeer = NULL, *pk = NULL;
++    DH *dhpeer = NULL;
++    const unsigned char *p;
++    int plen;
++
++    X509_ALGOR_get0(&aoid, &atype, &aval, alg);
++    if (OBJ_obj2nid(aoid) != NID_dhpublicnumber)
++        goto err;
++    /* Only absent parameters allowed in RFC XXXX */
++    if (atype != V_ASN1_UNDEF && atype == V_ASN1_NULL)
++        goto err;
++
++    pk = EVP_PKEY_CTX_get0_pkey(pctx);
++    if (!pk)
++        goto err;
++    if (pk->type != EVP_PKEY_DHX)
++        goto err;
++    /* Get parameters from parent key */
++    dhpeer = DHparams_dup(pk->pkey.dh);
++    /* We have parameters now set public key */
++    plen = ASN1_STRING_length(pubkey);
++    p = ASN1_STRING_get0_data(pubkey);
++    if (!p || !plen)
++        goto err;
++
++    if ((public_key = d2i_ASN1_INTEGER(NULL, &p, plen)) == NULL) {
++        DHerr(DH_F_DH_CMS_SET_PEERKEY, DH_R_DECODE_ERROR);
++        goto err;
++    }
++
++    /* We have parameters now set public key */
++    if ((dhpeer->pub_key = ASN1_INTEGER_to_BN(public_key, NULL)) == NULL) {
++        DHerr(DH_F_DH_CMS_SET_PEERKEY, DH_R_BN_DECODE_ERROR);
++        goto err;
++    }
++
++    pkpeer = EVP_PKEY_new();
++    if (pkpeer == NULL)
++        goto err;
++    EVP_PKEY_assign(pkpeer, pk->ameth->pkey_id, dhpeer);
++    dhpeer = NULL;
++    if (EVP_PKEY_derive_set_peer(pctx, pkpeer) > 0)
++        rv = 1;
++ err:
++    ASN1_INTEGER_free(public_key);
++    EVP_PKEY_free(pkpeer);
++    DH_free(dhpeer);
++    return rv;
++}
++
++static int dh_cms_set_shared_info(EVP_PKEY_CTX *pctx, CMS_RecipientInfo *ri)
++{
++    int rv = 0;
++
++    X509_ALGOR *alg, *kekalg = NULL;
++    ASN1_OCTET_STRING *ukm;
++    const unsigned char *p;
++    unsigned char *dukm = NULL;
++    size_t dukmlen = 0;
++    int keylen, plen;
++    const EVP_CIPHER *kekcipher;
++    EVP_CIPHER_CTX *kekctx;
++
++    if (!CMS_RecipientInfo_kari_get0_alg(ri, &alg, &ukm))
++        goto err;
++
++    /*
++     * For DH we only have one OID permissible. If ever any more get defined
++     * we will need something cleverer.
++     */
++    if (OBJ_obj2nid(alg->algorithm) != NID_id_smime_alg_ESDH) {
++        DHerr(DH_F_DH_CMS_SET_SHARED_INFO, DH_R_KDF_PARAMETER_ERROR);
++        goto err;
++    }
++
++    if (EVP_PKEY_CTX_set_dh_kdf_type(pctx, EVP_PKEY_DH_KDF_X9_42) <= 0)
++        goto err;
++
++    if (EVP_PKEY_CTX_set_dh_kdf_md(pctx, EVP_sha1()) <= 0)
++        goto err;
++
++    if (alg->parameter->type != V_ASN1_SEQUENCE)
++        goto err;
++
++    p = alg->parameter->value.sequence->data;
++    plen = alg->parameter->value.sequence->length;
++    kekalg = d2i_X509_ALGOR(NULL, &p, plen);
++    if (!kekalg)
++        goto err;
++    kekctx = CMS_RecipientInfo_kari_get0_ctx(ri);
++    if (!kekctx)
++        goto err;
++    kekcipher = EVP_get_cipherbyobj(kekalg->algorithm);
++    if (!kekcipher || EVP_CIPHER_mode(kekcipher) != EVP_CIPH_WRAP_MODE)
++        goto err;
++    if (!EVP_EncryptInit_ex(kekctx, kekcipher, NULL, NULL, NULL))
++        goto err;
++    if (EVP_CIPHER_asn1_to_param(kekctx, kekalg->parameter) <= 0)
++        goto err;
++
++    keylen = EVP_CIPHER_CTX_key_length(kekctx);
++    if (EVP_PKEY_CTX_set_dh_kdf_outlen(pctx, keylen) <= 0)
++        goto err;
++    /* Use OBJ_nid2obj to ensure we use built in OID that isn't freed */
++    if (EVP_PKEY_CTX_set0_dh_kdf_oid(pctx,
++                                     OBJ_nid2obj(EVP_CIPHER_type(kekcipher)))
++        <= 0)
++        goto err;
++
++    if (ukm) {
++        dukmlen = ASN1_STRING_length(ukm);
++        dukm = OPENSSL_memdup(ASN1_STRING_get0_data(ukm), dukmlen);
++        if (!dukm)
++            goto err;
++    }
++
++    if (EVP_PKEY_CTX_set0_dh_kdf_ukm(pctx, dukm, dukmlen) <= 0)
++        goto err;
++    dukm = NULL;
++
++    rv = 1;
++ err:
++    X509_ALGOR_free(kekalg);
++    OPENSSL_free(dukm);
++    return rv;
++}
++
++static int dh_cms_decrypt(CMS_RecipientInfo *ri)
++{
++    EVP_PKEY_CTX *pctx;
++    pctx = CMS_RecipientInfo_get0_pkey_ctx(ri);
++    if (!pctx)
++        return 0;
++    /* See if we need to set peer key */
++    if (!EVP_PKEY_CTX_get0_peerkey(pctx)) {
++        X509_ALGOR *alg;
++        ASN1_BIT_STRING *pubkey;
++        if (!CMS_RecipientInfo_kari_get0_orig_id(ri, &alg, &pubkey,
++                                                 NULL, NULL, NULL))
++            return 0;
++        if (!alg || !pubkey)
++            return 0;
++        if (!dh_cms_set_peerkey(pctx, alg, pubkey)) {
++            DHerr(DH_F_DH_CMS_DECRYPT, DH_R_PEER_KEY_ERROR);
++            return 0;
++        }
++    }
++    /* Set DH derivation parameters and initialise unwrap context */
++    if (!dh_cms_set_shared_info(pctx, ri)) {
++        DHerr(DH_F_DH_CMS_DECRYPT, DH_R_SHARED_INFO_ERROR);
++        return 0;
++    }
++    return 1;
++}
++
++static int dh_cms_encrypt(CMS_RecipientInfo *ri)
++{
++    EVP_PKEY_CTX *pctx;
++    EVP_PKEY *pkey;
++    EVP_CIPHER_CTX *ctx;
++    int keylen;
++    X509_ALGOR *talg, *wrap_alg = NULL;
++    const ASN1_OBJECT *aoid;
++    ASN1_BIT_STRING *pubkey;
++    ASN1_STRING *wrap_str;
++    ASN1_OCTET_STRING *ukm;
++    unsigned char *penc = NULL, *dukm = NULL;
++    int penclen;
++    size_t dukmlen = 0;
++    int rv = 0;
++    int kdf_type, wrap_nid;
++    const EVP_MD *kdf_md;
++    pctx = CMS_RecipientInfo_get0_pkey_ctx(ri);
++    if (!pctx)
++        return 0;
++    /* Get ephemeral key */
++    pkey = EVP_PKEY_CTX_get0_pkey(pctx);
++    if (!CMS_RecipientInfo_kari_get0_orig_id(ri, &talg, &pubkey,
++                                             NULL, NULL, NULL))
++        goto err;
++    X509_ALGOR_get0(&aoid, NULL, NULL, talg);
++    /* Is everything uninitialised? */
++    if (aoid == OBJ_nid2obj(NID_undef)) {
++        ASN1_INTEGER *pubk = BN_to_ASN1_INTEGER(pkey->pkey.dh->pub_key, NULL);
++        if (!pubk)
++            goto err;
++        /* Set the key */
++
++        penclen = i2d_ASN1_INTEGER(pubk, &penc);
++        ASN1_INTEGER_free(pubk);
++        if (penclen <= 0)
++            goto err;
++        ASN1_STRING_set0(pubkey, penc, penclen);
++        pubkey->flags &= ~(ASN1_STRING_FLAG_BITS_LEFT | 0x07);
++        pubkey->flags |= ASN1_STRING_FLAG_BITS_LEFT;
++
++        penc = NULL;
++        X509_ALGOR_set0(talg, OBJ_nid2obj(NID_dhpublicnumber),
++                        V_ASN1_UNDEF, NULL);
++    }
++
++    /* See if custom parameters set */
++    kdf_type = EVP_PKEY_CTX_get_dh_kdf_type(pctx);
++    if (kdf_type <= 0)
++        goto err;
++    if (!EVP_PKEY_CTX_get_dh_kdf_md(pctx, &kdf_md))
++        goto err;
++
++    if (kdf_type == EVP_PKEY_DH_KDF_NONE) {
++        kdf_type = EVP_PKEY_DH_KDF_X9_42;
++        if (EVP_PKEY_CTX_set_dh_kdf_type(pctx, kdf_type) <= 0)
++            goto err;
++    } else if (kdf_type != EVP_PKEY_DH_KDF_X9_42)
++        /* Unknown KDF */
++        goto err;
++    if (kdf_md == NULL) {
++        /* Only SHA1 supported */
++        kdf_md = EVP_sha1();
++        if (EVP_PKEY_CTX_set_dh_kdf_md(pctx, kdf_md) <= 0)
++            goto err;
++    } else if (EVP_MD_type(kdf_md) != NID_sha1)
++        /* Unsupported digest */
++        goto err;
++
++    if (!CMS_RecipientInfo_kari_get0_alg(ri, &talg, &ukm))
++        goto err;
++
++    /* Get wrap NID */
++    ctx = CMS_RecipientInfo_kari_get0_ctx(ri);
++    wrap_nid = EVP_CIPHER_CTX_type(ctx);
++    if (EVP_PKEY_CTX_set0_dh_kdf_oid(pctx, OBJ_nid2obj(wrap_nid)) <= 0)
++        goto err;
++    keylen = EVP_CIPHER_CTX_key_length(ctx);
++
++    /* Package wrap algorithm in an AlgorithmIdentifier */
++
++    wrap_alg = X509_ALGOR_new();
++    if (wrap_alg == NULL)
++        goto err;
++    wrap_alg->algorithm = OBJ_nid2obj(wrap_nid);
++    wrap_alg->parameter = ASN1_TYPE_new();
++    if (wrap_alg->parameter == NULL)
++        goto err;
++    if (EVP_CIPHER_param_to_asn1(ctx, wrap_alg->parameter) <= 0)
++        goto err;
++    if (ASN1_TYPE_get(wrap_alg->parameter) == NID_undef) {
++        ASN1_TYPE_free(wrap_alg->parameter);
++        wrap_alg->parameter = NULL;
++    }
++
++    if (EVP_PKEY_CTX_set_dh_kdf_outlen(pctx, keylen) <= 0)
++        goto err;
++
++    if (ukm) {
++        dukmlen = ASN1_STRING_length(ukm);
++        dukm = OPENSSL_memdup(ASN1_STRING_get0_data(ukm), dukmlen);
++        if (!dukm)
++            goto err;
++    }
++
++    if (EVP_PKEY_CTX_set0_dh_kdf_ukm(pctx, dukm, dukmlen) <= 0)
++        goto err;
++    dukm = NULL;
++
++    /*
++     * Now need to wrap encoding of wrap AlgorithmIdentifier into parameter
++     * of another AlgorithmIdentifier.
++     */
++    penc = NULL;
++    penclen = i2d_X509_ALGOR(wrap_alg, &penc);
++    if (!penc || !penclen)
++        goto err;
++    wrap_str = ASN1_STRING_new();
++    if (wrap_str == NULL)
++        goto err;
++    ASN1_STRING_set0(wrap_str, penc, penclen);
++    penc = NULL;
++    X509_ALGOR_set0(talg, OBJ_nid2obj(NID_id_smime_alg_ESDH),
++                    V_ASN1_SEQUENCE, wrap_str);
++
++    rv = 1;
++
++ err:
++    OPENSSL_free(penc);
++    X509_ALGOR_free(wrap_alg);
++    return rv;
++}
++
++#endif
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/dh/dh_asn1.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/dh/dh_asn1.c
+new file mode 100644
+index 0000000..7c72fd6
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/dh/dh_asn1.c
+@@ -0,0 +1,138 @@
++/*
++ * Copyright 2000-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include "internal/cryptlib.h"
++#include 
++#include "dh_locl.h"
++#include 
++#include 
++
++/* Override the default free and new methods */
++static int dh_cb(int operation, ASN1_VALUE **pval, const ASN1_ITEM *it,
++                 void *exarg)
++{
++    if (operation == ASN1_OP_NEW_PRE) {
++        *pval = (ASN1_VALUE *)DH_new();
++        if (*pval != NULL)
++            return 2;
++        return 0;
++    } else if (operation == ASN1_OP_FREE_PRE) {
++        DH_free((DH *)*pval);
++        *pval = NULL;
++        return 2;
++    }
++    return 1;
++}
++
++ASN1_SEQUENCE_cb(DHparams, dh_cb) = {
++        ASN1_SIMPLE(DH, p, BIGNUM),
++        ASN1_SIMPLE(DH, g, BIGNUM),
++        ASN1_OPT(DH, length, ZLONG),
++} ASN1_SEQUENCE_END_cb(DH, DHparams)
++
++IMPLEMENT_ASN1_ENCODE_FUNCTIONS_const_fname(DH, DHparams, DHparams)
++
++/*
++ * Internal only structures for handling X9.42 DH: this gets translated to or
++ * from a DH structure straight away.
++ */
++
++typedef struct {
++    ASN1_BIT_STRING *seed;
++    BIGNUM *counter;
++} int_dhvparams;
++
++typedef struct {
++    BIGNUM *p;
++    BIGNUM *q;
++    BIGNUM *g;
++    BIGNUM *j;
++    int_dhvparams *vparams;
++} int_dhx942_dh;
++
++ASN1_SEQUENCE(DHvparams) = {
++        ASN1_SIMPLE(int_dhvparams, seed, ASN1_BIT_STRING),
++        ASN1_SIMPLE(int_dhvparams, counter, BIGNUM)
++} static_ASN1_SEQUENCE_END_name(int_dhvparams, DHvparams)
++
++ASN1_SEQUENCE(DHxparams) = {
++        ASN1_SIMPLE(int_dhx942_dh, p, BIGNUM),
++        ASN1_SIMPLE(int_dhx942_dh, g, BIGNUM),
++        ASN1_SIMPLE(int_dhx942_dh, q, BIGNUM),
++        ASN1_OPT(int_dhx942_dh, j, BIGNUM),
++        ASN1_OPT(int_dhx942_dh, vparams, DHvparams),
++} static_ASN1_SEQUENCE_END_name(int_dhx942_dh, DHxparams)
++
++int_dhx942_dh *d2i_int_dhx(int_dhx942_dh **a,
++                           const unsigned char **pp, long length);
++int i2d_int_dhx(const int_dhx942_dh *a, unsigned char **pp);
++
++IMPLEMENT_ASN1_ENCODE_FUNCTIONS_const_fname(int_dhx942_dh, DHxparams, int_dhx)
++
++/* Application public function: read in X9.42 DH parameters into DH structure */
++
++DH *d2i_DHxparams(DH **a, const unsigned char **pp, long length)
++{
++    int_dhx942_dh *dhx = NULL;
++    DH *dh = NULL;
++    dh = DH_new();
++    if (dh == NULL)
++        return NULL;
++    dhx = d2i_int_dhx(NULL, pp, length);
++    if (dhx == NULL) {
++        DH_free(dh);
++        return NULL;
++    }
++
++    if (a) {
++        DH_free(*a);
++        *a = dh;
++    }
++
++    dh->p = dhx->p;
++    dh->q = dhx->q;
++    dh->g = dhx->g;
++    dh->j = dhx->j;
++
++    if (dhx->vparams) {
++        dh->seed = dhx->vparams->seed->data;
++        dh->seedlen = dhx->vparams->seed->length;
++        dh->counter = dhx->vparams->counter;
++        dhx->vparams->seed->data = NULL;
++        ASN1_BIT_STRING_free(dhx->vparams->seed);
++        OPENSSL_free(dhx->vparams);
++        dhx->vparams = NULL;
++    }
++
++    OPENSSL_free(dhx);
++    return dh;
++}
++
++int i2d_DHxparams(const DH *dh, unsigned char **pp)
++{
++    int_dhx942_dh dhx;
++    int_dhvparams dhv;
++    ASN1_BIT_STRING bs;
++    dhx.p = dh->p;
++    dhx.g = dh->g;
++    dhx.q = dh->q;
++    dhx.j = dh->j;
++    if (dh->counter && dh->seed && dh->seedlen > 0) {
++        bs.flags = ASN1_STRING_FLAG_BITS_LEFT;
++        bs.data = dh->seed;
++        bs.length = dh->seedlen;
++        dhv.seed = &bs;
++        dhv.counter = dh->counter;
++        dhx.vparams = &dhv;
++    } else
++        dhx.vparams = NULL;
++
++    return i2d_int_dhx(&dhx, pp);
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/dh/dh_check.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/dh/dh_check.c
+new file mode 100644
+index 0000000..3b0fa59
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/dh/dh_check.c
+@@ -0,0 +1,183 @@
++/*
++ * Copyright 1995-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include "internal/cryptlib.h"
++#include 
++#include "dh_locl.h"
++
++/*-
++ * Check that p and g are suitable enough
++ *
++ * p is odd
++ * 1 < g < p - 1
++ */
++
++int DH_check_params(const DH *dh, int *ret)
++{
++    int ok = 0;
++    BIGNUM *tmp = NULL;
++    BN_CTX *ctx = NULL;
++
++    *ret = 0;
++    ctx = BN_CTX_new();
++    if (ctx == NULL)
++        goto err;
++    BN_CTX_start(ctx);
++    tmp = BN_CTX_get(ctx);
++    if (tmp == NULL)
++        goto err;
++
++    if (!BN_is_odd(dh->p))
++        *ret |= DH_CHECK_P_NOT_PRIME;
++    if (BN_is_negative(dh->g) || BN_is_zero(dh->g) || BN_is_one(dh->g))
++        *ret |= DH_NOT_SUITABLE_GENERATOR;
++    if (BN_copy(tmp, dh->p) == NULL || !BN_sub_word(tmp, 1))
++        goto err;
++    if (BN_cmp(dh->g, tmp) >= 0)
++        *ret |= DH_NOT_SUITABLE_GENERATOR;
++
++    ok = 1;
++ err:
++    if (ctx != NULL) {
++        BN_CTX_end(ctx);
++        BN_CTX_free(ctx);
++    }
++    return (ok);
++}
++
++/*-
++ * Check that p is a safe prime and
++ * if g is 2, 3 or 5, check that it is a suitable generator
++ * where
++ * for 2, p mod 24 == 11
++ * for 3, p mod 12 == 5
++ * for 5, p mod 10 == 3 or 7
++ * should hold.
++ */
++
++int DH_check(const DH *dh, int *ret)
++{
++    int ok = 0, r;
++    BN_CTX *ctx = NULL;
++    BN_ULONG l;
++    BIGNUM *t1 = NULL, *t2 = NULL;
++
++    *ret = 0;
++    ctx = BN_CTX_new();
++    if (ctx == NULL)
++        goto err;
++    BN_CTX_start(ctx);
++    t1 = BN_CTX_get(ctx);
++    if (t1 == NULL)
++        goto err;
++    t2 = BN_CTX_get(ctx);
++    if (t2 == NULL)
++        goto err;
++
++    if (dh->q) {
++        if (BN_cmp(dh->g, BN_value_one()) <= 0)
++            *ret |= DH_NOT_SUITABLE_GENERATOR;
++        else if (BN_cmp(dh->g, dh->p) >= 0)
++            *ret |= DH_NOT_SUITABLE_GENERATOR;
++        else {
++            /* Check g^q == 1 mod p */
++            if (!BN_mod_exp(t1, dh->g, dh->q, dh->p, ctx))
++                goto err;
++            if (!BN_is_one(t1))
++                *ret |= DH_NOT_SUITABLE_GENERATOR;
++        }
++        r = BN_is_prime_ex(dh->q, BN_prime_checks, ctx, NULL);
++        if (r < 0)
++            goto err;
++        if (!r)
++            *ret |= DH_CHECK_Q_NOT_PRIME;
++        /* Check p == 1 mod q  i.e. q divides p - 1 */
++        if (!BN_div(t1, t2, dh->p, dh->q, ctx))
++            goto err;
++        if (!BN_is_one(t2))
++            *ret |= DH_CHECK_INVALID_Q_VALUE;
++        if (dh->j && BN_cmp(dh->j, t1))
++            *ret |= DH_CHECK_INVALID_J_VALUE;
++
++    } else if (BN_is_word(dh->g, DH_GENERATOR_2)) {
++        l = BN_mod_word(dh->p, 24);
++        if (l == (BN_ULONG)-1)
++            goto err;
++        if (l != 11)
++            *ret |= DH_NOT_SUITABLE_GENERATOR;
++    } else if (BN_is_word(dh->g, DH_GENERATOR_5)) {
++        l = BN_mod_word(dh->p, 10);
++        if (l == (BN_ULONG)-1)
++            goto err;
++        if ((l != 3) && (l != 7))
++            *ret |= DH_NOT_SUITABLE_GENERATOR;
++    } else
++        *ret |= DH_UNABLE_TO_CHECK_GENERATOR;
++
++    r = BN_is_prime_ex(dh->p, BN_prime_checks, ctx, NULL);
++    if (r < 0)
++        goto err;
++    if (!r)
++        *ret |= DH_CHECK_P_NOT_PRIME;
++    else if (!dh->q) {
++        if (!BN_rshift1(t1, dh->p))
++            goto err;
++        r = BN_is_prime_ex(t1, BN_prime_checks, ctx, NULL);
++        if (r < 0)
++            goto err;
++	if (!r)
++            *ret |= DH_CHECK_P_NOT_SAFE_PRIME;
++    }
++    ok = 1;
++ err:
++    if (ctx != NULL) {
++        BN_CTX_end(ctx);
++        BN_CTX_free(ctx);
++    }
++    return (ok);
++}
++
++int DH_check_pub_key(const DH *dh, const BIGNUM *pub_key, int *ret)
++{
++    int ok = 0;
++    BIGNUM *tmp = NULL;
++    BN_CTX *ctx = NULL;
++
++    *ret = 0;
++    ctx = BN_CTX_new();
++    if (ctx == NULL)
++        goto err;
++    BN_CTX_start(ctx);
++    tmp = BN_CTX_get(ctx);
++    if (tmp == NULL || !BN_set_word(tmp, 1))
++        goto err;
++    if (BN_cmp(pub_key, tmp) <= 0)
++        *ret |= DH_CHECK_PUBKEY_TOO_SMALL;
++    if (BN_copy(tmp, dh->p) == NULL || !BN_sub_word(tmp, 1))
++        goto err;
++    if (BN_cmp(pub_key, tmp) >= 0)
++        *ret |= DH_CHECK_PUBKEY_TOO_LARGE;
++
++    if (dh->q != NULL) {
++        /* Check pub_key^q == 1 mod p */
++        if (!BN_mod_exp(tmp, pub_key, dh->q, dh->p, ctx))
++            goto err;
++        if (!BN_is_one(tmp))
++            *ret |= DH_CHECK_PUBKEY_INVALID;
++    }
++
++    ok = 1;
++ err:
++    if (ctx != NULL) {
++        BN_CTX_end(ctx);
++        BN_CTX_free(ctx);
++    }
++    return (ok);
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/dh/dh_depr.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/dh/dh_depr.c
+new file mode 100644
+index 0000000..f8ed1b7
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/dh/dh_depr.c
+@@ -0,0 +1,46 @@
++/*
++ * Copyright 2002-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++/* This file contains deprecated functions as wrappers to the new ones */
++
++#include 
++#if OPENSSL_API_COMPAT >= 0x00908000L
++NON_EMPTY_TRANSLATION_UNIT
++#else
++
++# include 
++# include "internal/cryptlib.h"
++# include 
++# include 
++
++DH *DH_generate_parameters(int prime_len, int generator,
++                           void (*callback) (int, int, void *), void *cb_arg)
++{
++    BN_GENCB *cb;
++    DH *ret = NULL;
++
++    if ((ret = DH_new()) == NULL)
++        return NULL;
++    cb = BN_GENCB_new();
++    if (cb == NULL) {
++        DH_free(ret);
++        return NULL;
++    }
++
++    BN_GENCB_set_old(cb, callback, cb_arg);
++
++    if (DH_generate_parameters_ex(ret, prime_len, generator, cb)) {
++        BN_GENCB_free(cb);
++        return ret;
++    }
++    BN_GENCB_free(cb);
++    DH_free(ret);
++    return NULL;
++}
++#endif
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/dh/dh_err.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/dh/dh_err.c
+new file mode 100644
+index 0000000..4e21f28
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/dh/dh_err.c
+@@ -0,0 +1,73 @@
++/*
++ * Generated by util/mkerr.pl DO NOT EDIT
++ * Copyright 1995-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include 
++#include 
++
++/* BEGIN ERROR CODES */
++#ifndef OPENSSL_NO_ERR
++
++# define ERR_FUNC(func) ERR_PACK(ERR_LIB_DH,func,0)
++# define ERR_REASON(reason) ERR_PACK(ERR_LIB_DH,0,reason)
++
++static ERR_STRING_DATA DH_str_functs[] = {
++    {ERR_FUNC(DH_F_COMPUTE_KEY), "compute_key"},
++    {ERR_FUNC(DH_F_DHPARAMS_PRINT_FP), "DHparams_print_fp"},
++    {ERR_FUNC(DH_F_DH_BUILTIN_GENPARAMS), "dh_builtin_genparams"},
++    {ERR_FUNC(DH_F_DH_CMS_DECRYPT), "dh_cms_decrypt"},
++    {ERR_FUNC(DH_F_DH_CMS_SET_PEERKEY), "dh_cms_set_peerkey"},
++    {ERR_FUNC(DH_F_DH_CMS_SET_SHARED_INFO), "dh_cms_set_shared_info"},
++    {ERR_FUNC(DH_F_DH_METH_DUP), "DH_meth_dup"},
++    {ERR_FUNC(DH_F_DH_METH_NEW), "DH_meth_new"},
++    {ERR_FUNC(DH_F_DH_METH_SET1_NAME), "DH_meth_set1_name"},
++    {ERR_FUNC(DH_F_DH_NEW_METHOD), "DH_new_method"},
++    {ERR_FUNC(DH_F_DH_PARAM_DECODE), "dh_param_decode"},
++    {ERR_FUNC(DH_F_DH_PRIV_DECODE), "dh_priv_decode"},
++    {ERR_FUNC(DH_F_DH_PRIV_ENCODE), "dh_priv_encode"},
++    {ERR_FUNC(DH_F_DH_PUB_DECODE), "dh_pub_decode"},
++    {ERR_FUNC(DH_F_DH_PUB_ENCODE), "dh_pub_encode"},
++    {ERR_FUNC(DH_F_DO_DH_PRINT), "do_dh_print"},
++    {ERR_FUNC(DH_F_GENERATE_KEY), "generate_key"},
++    {ERR_FUNC(DH_F_PKEY_DH_DERIVE), "pkey_dh_derive"},
++    {ERR_FUNC(DH_F_PKEY_DH_KEYGEN), "pkey_dh_keygen"},
++    {0, NULL}
++};
++
++static ERR_STRING_DATA DH_str_reasons[] = {
++    {ERR_REASON(DH_R_BAD_GENERATOR), "bad generator"},
++    {ERR_REASON(DH_R_BN_DECODE_ERROR), "bn decode error"},
++    {ERR_REASON(DH_R_BN_ERROR), "bn error"},
++    {ERR_REASON(DH_R_DECODE_ERROR), "decode error"},
++    {ERR_REASON(DH_R_INVALID_PUBKEY), "invalid public key"},
++    {ERR_REASON(DH_R_KDF_PARAMETER_ERROR), "kdf parameter error"},
++    {ERR_REASON(DH_R_KEYS_NOT_SET), "keys not set"},
++    {ERR_REASON(DH_R_MODULUS_TOO_LARGE), "modulus too large"},
++    {ERR_REASON(DH_R_NO_PARAMETERS_SET), "no parameters set"},
++    {ERR_REASON(DH_R_NO_PRIVATE_VALUE), "no private value"},
++    {ERR_REASON(DH_R_PARAMETER_ENCODING_ERROR), "parameter encoding error"},
++    {ERR_REASON(DH_R_PEER_KEY_ERROR), "peer key error"},
++    {ERR_REASON(DH_R_SHARED_INFO_ERROR), "shared info error"},
++    {0, NULL}
++};
++
++#endif
++
++int ERR_load_DH_strings(void)
++{
++#ifndef OPENSSL_NO_ERR
++
++    if (ERR_func_error_string(DH_str_functs[0].error) == NULL) {
++        ERR_load_strings(0, DH_str_functs);
++        ERR_load_strings(0, DH_str_reasons);
++    }
++#endif
++    return 1;
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/dh/dh_gen.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/dh/dh_gen.c
+new file mode 100644
+index 0000000..27ecb98
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/dh/dh_gen.c
+@@ -0,0 +1,130 @@
++/*
++ * Copyright 1995-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++/*
++ * NB: These functions have been upgraded - the previous prototypes are in
++ * dh_depr.c as wrappers to these ones.  - Geoff
++ */
++
++#include 
++#include "internal/cryptlib.h"
++#include 
++#include "dh_locl.h"
++
++static int dh_builtin_genparams(DH *ret, int prime_len, int generator,
++                                BN_GENCB *cb);
++
++int DH_generate_parameters_ex(DH *ret, int prime_len, int generator,
++                              BN_GENCB *cb)
++{
++    if (ret->meth->generate_params)
++        return ret->meth->generate_params(ret, prime_len, generator, cb);
++    return dh_builtin_genparams(ret, prime_len, generator, cb);
++}
++
++/*-
++ * We generate DH parameters as follows
++ * find a prime q which is prime_len/2 bits long.
++ * p=(2*q)+1 or (p-1)/2 = q
++ * For this case, g is a generator if
++ * g^((p-1)/q) mod p != 1 for values of q which are the factors of p-1.
++ * Since the factors of p-1 are q and 2, we just need to check
++ * g^2 mod p != 1 and g^q mod p != 1.
++ *
++ * Having said all that,
++ * there is another special case method for the generators 2, 3 and 5.
++ * for 2, p mod 24 == 11
++ * for 3, p mod 12 == 5  <<<<< does not work for safe primes.
++ * for 5, p mod 10 == 3 or 7
++ *
++ * Thanks to Phil Karn  for the pointers about the
++ * special generators and for answering some of my questions.
++ *
++ * I've implemented the second simple method :-).
++ * Since DH should be using a safe prime (both p and q are prime),
++ * this generator function can take a very very long time to run.
++ */
++/*
++ * Actually there is no reason to insist that 'generator' be a generator.
++ * It's just as OK (and in some sense better) to use a generator of the
++ * order-q subgroup.
++ */
++static int dh_builtin_genparams(DH *ret, int prime_len, int generator,
++                                BN_GENCB *cb)
++{
++    BIGNUM *t1, *t2;
++    int g, ok = -1;
++    BN_CTX *ctx = NULL;
++
++    ctx = BN_CTX_new();
++    if (ctx == NULL)
++        goto err;
++    BN_CTX_start(ctx);
++    t1 = BN_CTX_get(ctx);
++    t2 = BN_CTX_get(ctx);
++    if (t1 == NULL || t2 == NULL)
++        goto err;
++
++    /* Make sure 'ret' has the necessary elements */
++    if (!ret->p && ((ret->p = BN_new()) == NULL))
++        goto err;
++    if (!ret->g && ((ret->g = BN_new()) == NULL))
++        goto err;
++
++    if (generator <= 1) {
++        DHerr(DH_F_DH_BUILTIN_GENPARAMS, DH_R_BAD_GENERATOR);
++        goto err;
++    }
++    if (generator == DH_GENERATOR_2) {
++        if (!BN_set_word(t1, 24))
++            goto err;
++        if (!BN_set_word(t2, 11))
++            goto err;
++        g = 2;
++    } else if (generator == DH_GENERATOR_5) {
++        if (!BN_set_word(t1, 10))
++            goto err;
++        if (!BN_set_word(t2, 3))
++            goto err;
++        /*
++         * BN_set_word(t3,7); just have to miss out on these ones :-(
++         */
++        g = 5;
++    } else {
++        /*
++         * in the general case, don't worry if 'generator' is a generator or
++         * not: since we are using safe primes, it will generate either an
++         * order-q or an order-2q group, which both is OK
++         */
++        if (!BN_set_word(t1, 2))
++            goto err;
++        if (!BN_set_word(t2, 1))
++            goto err;
++        g = generator;
++    }
++
++    if (!BN_generate_prime_ex(ret->p, prime_len, 1, t1, t2, cb))
++        goto err;
++    if (!BN_GENCB_call(cb, 3, 0))
++        goto err;
++    if (!BN_set_word(ret->g, g))
++        goto err;
++    ok = 1;
++ err:
++    if (ok == -1) {
++        DHerr(DH_F_DH_BUILTIN_GENPARAMS, ERR_R_BN_LIB);
++        ok = 0;
++    }
++
++    if (ctx != NULL) {
++        BN_CTX_end(ctx);
++        BN_CTX_free(ctx);
++    }
++    return ok;
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/dh/dh_kdf.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/dh/dh_kdf.c
+new file mode 100644
+index 0000000..2782eee
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/dh/dh_kdf.c
+@@ -0,0 +1,150 @@
++/*
++ * Copyright 2013-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++
++#ifndef OPENSSL_NO_CMS
++#include 
++#include 
++#include 
++#include 
++#include 
++
++
++/* Key derivation from X9.42/RFC2631 */
++/* Uses CMS functions, hence the #ifdef wrapper. */
++
++#define DH_KDF_MAX      (1L << 30)
++
++/* Skip past an ASN1 structure: for OBJECT skip content octets too */
++
++static int skip_asn1(unsigned char **pp, long *plen, int exptag)
++{
++    const unsigned char *q = *pp;
++    int i, tag, xclass;
++    long tmplen;
++    i = ASN1_get_object(&q, &tmplen, &tag, &xclass, *plen);
++    if (i & 0x80)
++        return 0;
++    if (tag != exptag || xclass != V_ASN1_UNIVERSAL)
++        return 0;
++    if (tag == V_ASN1_OBJECT)
++        q += tmplen;
++    *plen -= q - *pp;
++    *pp = (unsigned char *)q;
++    return 1;
++}
++
++/*
++ * Encode the DH shared info structure, return an offset to the counter value
++ * so we can update the structure without reencoding it.
++ */
++
++static int dh_sharedinfo_encode(unsigned char **pder, unsigned char **pctr,
++                                ASN1_OBJECT *key_oid, size_t outlen,
++                                const unsigned char *ukm, size_t ukmlen)
++{
++    unsigned char *p;
++    int derlen;
++    long tlen;
++    /* "magic" value to check offset is sane */
++    static unsigned char ctr[4] = { 0xF3, 0x17, 0x22, 0x53 };
++    X509_ALGOR atmp;
++    ASN1_OCTET_STRING ctr_oct, ukm_oct, *pukm_oct;
++    ASN1_TYPE ctr_atype;
++    if (ukmlen > DH_KDF_MAX || outlen > DH_KDF_MAX)
++        return 0;
++    ctr_oct.data = ctr;
++    ctr_oct.length = 4;
++    ctr_oct.flags = 0;
++    ctr_oct.type = V_ASN1_OCTET_STRING;
++    ctr_atype.type = V_ASN1_OCTET_STRING;
++    ctr_atype.value.octet_string = &ctr_oct;
++    atmp.algorithm = key_oid;
++    atmp.parameter = &ctr_atype;
++    if (ukm) {
++        ukm_oct.type = V_ASN1_OCTET_STRING;
++        ukm_oct.flags = 0;
++        ukm_oct.data = (unsigned char *)ukm;
++        ukm_oct.length = ukmlen;
++        pukm_oct = &ukm_oct;
++    } else
++        pukm_oct = NULL;
++    derlen = CMS_SharedInfo_encode(pder, &atmp, pukm_oct, outlen);
++    if (derlen <= 0)
++        return 0;
++    p = *pder;
++    tlen = derlen;
++    if (!skip_asn1(&p, &tlen, V_ASN1_SEQUENCE))
++        return 0;
++    if (!skip_asn1(&p, &tlen, V_ASN1_SEQUENCE))
++        return 0;
++    if (!skip_asn1(&p, &tlen, V_ASN1_OBJECT))
++        return 0;
++    if (!skip_asn1(&p, &tlen, V_ASN1_OCTET_STRING))
++        return 0;
++    if (CRYPTO_memcmp(p, ctr, 4))
++        return 0;
++    *pctr = p;
++    return derlen;
++}
++
++int DH_KDF_X9_42(unsigned char *out, size_t outlen,
++                 const unsigned char *Z, size_t Zlen,
++                 ASN1_OBJECT *key_oid,
++                 const unsigned char *ukm, size_t ukmlen, const EVP_MD *md)
++{
++    EVP_MD_CTX *mctx = NULL;
++    int rv = 0;
++    unsigned int i;
++    size_t mdlen;
++    unsigned char *der = NULL, *ctr;
++    int derlen;
++    if (Zlen > DH_KDF_MAX)
++        return 0;
++    mctx = EVP_MD_CTX_new();
++    if (mctx == NULL)
++        return 0;
++    mdlen = EVP_MD_size(md);
++    derlen = dh_sharedinfo_encode(&der, &ctr, key_oid, outlen, ukm, ukmlen);
++    if (derlen == 0)
++        goto err;
++    for (i = 1;; i++) {
++        unsigned char mtmp[EVP_MAX_MD_SIZE];
++        if (!EVP_DigestInit_ex(mctx, md, NULL)
++            || !EVP_DigestUpdate(mctx, Z, Zlen))
++            goto err;
++        ctr[3] = i & 0xFF;
++        ctr[2] = (i >> 8) & 0xFF;
++        ctr[1] = (i >> 16) & 0xFF;
++        ctr[0] = (i >> 24) & 0xFF;
++        if (!EVP_DigestUpdate(mctx, der, derlen))
++            goto err;
++        if (outlen >= mdlen) {
++            if (!EVP_DigestFinal(mctx, out, NULL))
++                goto err;
++            outlen -= mdlen;
++            if (outlen == 0)
++                break;
++            out += mdlen;
++        } else {
++            if (!EVP_DigestFinal(mctx, mtmp, NULL))
++                goto err;
++            memcpy(out, mtmp, outlen);
++            OPENSSL_cleanse(mtmp, mdlen);
++            break;
++        }
++    }
++    rv = 1;
++ err:
++    OPENSSL_free(der);
++    EVP_MD_CTX_free(mctx);
++    return rv;
++}
++#endif
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/dh/dh_key.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/dh/dh_key.c
+new file mode 100644
+index 0000000..204e5a7
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/dh/dh_key.c
+@@ -0,0 +1,215 @@
++/*
++ * Copyright 1995-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include "internal/cryptlib.h"
++#include "dh_locl.h"
++#include "internal/bn_int.h"
++
++static int generate_key(DH *dh);
++static int compute_key(unsigned char *key, const BIGNUM *pub_key, DH *dh);
++static int dh_bn_mod_exp(const DH *dh, BIGNUM *r,
++                         const BIGNUM *a, const BIGNUM *p,
++                         const BIGNUM *m, BN_CTX *ctx, BN_MONT_CTX *m_ctx);
++static int dh_init(DH *dh);
++static int dh_finish(DH *dh);
++
++int DH_generate_key(DH *dh)
++{
++    return dh->meth->generate_key(dh);
++}
++
++int DH_compute_key(unsigned char *key, const BIGNUM *pub_key, DH *dh)
++{
++    return dh->meth->compute_key(key, pub_key, dh);
++}
++
++int DH_compute_key_padded(unsigned char *key, const BIGNUM *pub_key, DH *dh)
++{
++    int rv, pad;
++    rv = dh->meth->compute_key(key, pub_key, dh);
++    if (rv <= 0)
++        return rv;
++    pad = BN_num_bytes(dh->p) - rv;
++    if (pad > 0) {
++        memmove(key + pad, key, rv);
++        memset(key, 0, pad);
++    }
++    return rv + pad;
++}
++
++static DH_METHOD dh_ossl = {
++    "OpenSSL DH Method",
++    generate_key,
++    compute_key,
++    dh_bn_mod_exp,
++    dh_init,
++    dh_finish,
++    DH_FLAG_FIPS_METHOD,
++    NULL,
++    NULL
++};
++
++const DH_METHOD *DH_OpenSSL(void)
++{
++    return &dh_ossl;
++}
++
++static int generate_key(DH *dh)
++{
++    int ok = 0;
++    int generate_new_key = 0;
++    unsigned l;
++    BN_CTX *ctx;
++    BN_MONT_CTX *mont = NULL;
++    BIGNUM *pub_key = NULL, *priv_key = NULL;
++
++    ctx = BN_CTX_new();
++    if (ctx == NULL)
++        goto err;
++
++    if (dh->priv_key == NULL) {
++        priv_key = BN_secure_new();
++        if (priv_key == NULL)
++            goto err;
++        generate_new_key = 1;
++    } else
++        priv_key = dh->priv_key;
++
++    if (dh->pub_key == NULL) {
++        pub_key = BN_new();
++        if (pub_key == NULL)
++            goto err;
++    } else
++        pub_key = dh->pub_key;
++
++    if (dh->flags & DH_FLAG_CACHE_MONT_P) {
++        mont = BN_MONT_CTX_set_locked(&dh->method_mont_p,
++                                      dh->lock, dh->p, ctx);
++        if (!mont)
++            goto err;
++    }
++
++    if (generate_new_key) {
++        if (dh->q) {
++            do {
++                if (!BN_rand_range(priv_key, dh->q))
++                    goto err;
++            }
++            while (BN_is_zero(priv_key) || BN_is_one(priv_key));
++        } else {
++            /* secret exponent length */
++            l = dh->length ? dh->length : BN_num_bits(dh->p) - 1;
++            if (!BN_rand(priv_key, l, BN_RAND_TOP_ONE, BN_RAND_BOTTOM_ANY))
++                goto err;
++        }
++    }
++
++    {
++        BIGNUM *prk = BN_new();
++
++        if (prk == NULL)
++            goto err;
++        BN_with_flags(prk, priv_key, BN_FLG_CONSTTIME);
++
++        if (!dh->meth->bn_mod_exp(dh, pub_key, dh->g, prk, dh->p, ctx, mont)) {
++            BN_free(prk);
++            goto err;
++        }
++        /* We MUST free prk before any further use of priv_key */
++        BN_free(prk);
++    }
++
++    dh->pub_key = pub_key;
++    dh->priv_key = priv_key;
++    ok = 1;
++ err:
++    if (ok != 1)
++        DHerr(DH_F_GENERATE_KEY, ERR_R_BN_LIB);
++
++    if (pub_key != dh->pub_key)
++        BN_free(pub_key);
++    if (priv_key != dh->priv_key)
++        BN_free(priv_key);
++    BN_CTX_free(ctx);
++    return (ok);
++}
++
++static int compute_key(unsigned char *key, const BIGNUM *pub_key, DH *dh)
++{
++    BN_CTX *ctx = NULL;
++    BN_MONT_CTX *mont = NULL;
++    BIGNUM *tmp;
++    int ret = -1;
++    int check_result;
++
++    if (BN_num_bits(dh->p) > OPENSSL_DH_MAX_MODULUS_BITS) {
++        DHerr(DH_F_COMPUTE_KEY, DH_R_MODULUS_TOO_LARGE);
++        goto err;
++    }
++
++    ctx = BN_CTX_new();
++    if (ctx == NULL)
++        goto err;
++    BN_CTX_start(ctx);
++    tmp = BN_CTX_get(ctx);
++    if (tmp == NULL)
++        goto err;
++
++    if (dh->priv_key == NULL) {
++        DHerr(DH_F_COMPUTE_KEY, DH_R_NO_PRIVATE_VALUE);
++        goto err;
++    }
++
++    if (dh->flags & DH_FLAG_CACHE_MONT_P) {
++        mont = BN_MONT_CTX_set_locked(&dh->method_mont_p,
++                                      dh->lock, dh->p, ctx);
++        BN_set_flags(dh->priv_key, BN_FLG_CONSTTIME);
++        if (!mont)
++            goto err;
++    }
++
++    if (!DH_check_pub_key(dh, pub_key, &check_result) || check_result) {
++        DHerr(DH_F_COMPUTE_KEY, DH_R_INVALID_PUBKEY);
++        goto err;
++    }
++
++    if (!dh->
++        meth->bn_mod_exp(dh, tmp, pub_key, dh->priv_key, dh->p, ctx, mont)) {
++        DHerr(DH_F_COMPUTE_KEY, ERR_R_BN_LIB);
++        goto err;
++    }
++
++    ret = BN_bn2bin(tmp, key);
++ err:
++    if (ctx != NULL) {
++        BN_CTX_end(ctx);
++        BN_CTX_free(ctx);
++    }
++    return (ret);
++}
++
++static int dh_bn_mod_exp(const DH *dh, BIGNUM *r,
++                         const BIGNUM *a, const BIGNUM *p,
++                         const BIGNUM *m, BN_CTX *ctx, BN_MONT_CTX *m_ctx)
++{
++    return BN_mod_exp_mont(r, a, p, m, ctx, m_ctx);
++}
++
++static int dh_init(DH *dh)
++{
++    dh->flags |= DH_FLAG_CACHE_MONT_P;
++    return (1);
++}
++
++static int dh_finish(DH *dh)
++{
++    BN_MONT_CTX_free(dh->method_mont_p);
++    return (1);
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/dh/dh_lib.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/dh/dh_lib.c
+new file mode 100644
+index 0000000..adf1771
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/dh/dh_lib.c
+@@ -0,0 +1,284 @@
++/*
++ * Copyright 1995-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include "internal/cryptlib.h"
++#include 
++#include "dh_locl.h"
++#include 
++
++static const DH_METHOD *default_DH_method = NULL;
++
++void DH_set_default_method(const DH_METHOD *meth)
++{
++    default_DH_method = meth;
++}
++
++const DH_METHOD *DH_get_default_method(void)
++{
++    if (!default_DH_method)
++        default_DH_method = DH_OpenSSL();
++    return default_DH_method;
++}
++
++int DH_set_method(DH *dh, const DH_METHOD *meth)
++{
++    /*
++     * NB: The caller is specifically setting a method, so it's not up to us
++     * to deal with which ENGINE it comes from.
++     */
++    const DH_METHOD *mtmp;
++    mtmp = dh->meth;
++    if (mtmp->finish)
++        mtmp->finish(dh);
++#ifndef OPENSSL_NO_ENGINE
++    ENGINE_finish(dh->engine);
++    dh->engine = NULL;
++#endif
++    dh->meth = meth;
++    if (meth->init)
++        meth->init(dh);
++    return 1;
++}
++
++DH *DH_new(void)
++{
++    return DH_new_method(NULL);
++}
++
++DH *DH_new_method(ENGINE *engine)
++{
++    DH *ret = OPENSSL_zalloc(sizeof(*ret));
++
++    if (ret == NULL) {
++        DHerr(DH_F_DH_NEW_METHOD, ERR_R_MALLOC_FAILURE);
++        return NULL;
++    }
++
++    ret->references = 1;
++    ret->lock = CRYPTO_THREAD_lock_new();
++    if (ret->lock == NULL) {
++        DHerr(DH_F_DH_NEW_METHOD, ERR_R_MALLOC_FAILURE);
++        OPENSSL_free(ret);
++        return NULL;
++    }
++
++    ret->meth = DH_get_default_method();
++#ifndef OPENSSL_NO_ENGINE
++    ret->flags = ret->meth->flags;  /* early default init */
++    if (engine) {
++        if (!ENGINE_init(engine)) {
++            DHerr(DH_F_DH_NEW_METHOD, ERR_R_ENGINE_LIB);
++            goto err;
++        }
++        ret->engine = engine;
++    } else
++        ret->engine = ENGINE_get_default_DH();
++    if (ret->engine) {
++        ret->meth = ENGINE_get_DH(ret->engine);
++        if (ret->meth == NULL) {
++            DHerr(DH_F_DH_NEW_METHOD, ERR_R_ENGINE_LIB);
++            goto err;
++        }
++    }
++#endif
++
++    ret->flags = ret->meth->flags;
++
++    if (!CRYPTO_new_ex_data(CRYPTO_EX_INDEX_DH, ret, &ret->ex_data))
++        goto err;
++
++    if ((ret->meth->init != NULL) && !ret->meth->init(ret)) {
++        DHerr(DH_F_DH_NEW_METHOD, ERR_R_INIT_FAIL);
++err:
++        DH_free(ret);
++        ret = NULL;
++    }
++
++    return ret;
++}
++
++void DH_free(DH *r)
++{
++    int i;
++
++    if (r == NULL)
++        return;
++
++    CRYPTO_atomic_add(&r->references, -1, &i, r->lock);
++    REF_PRINT_COUNT("DH", r);
++    if (i > 0)
++        return;
++    REF_ASSERT_ISNT(i < 0);
++
++    if (r->meth->finish)
++        r->meth->finish(r);
++#ifndef OPENSSL_NO_ENGINE
++    ENGINE_finish(r->engine);
++#endif
++
++    CRYPTO_free_ex_data(CRYPTO_EX_INDEX_DH, r, &r->ex_data);
++
++    CRYPTO_THREAD_lock_free(r->lock);
++
++    BN_clear_free(r->p);
++    BN_clear_free(r->g);
++    BN_clear_free(r->q);
++    BN_clear_free(r->j);
++    OPENSSL_free(r->seed);
++    BN_clear_free(r->counter);
++    BN_clear_free(r->pub_key);
++    BN_clear_free(r->priv_key);
++    OPENSSL_free(r);
++}
++
++int DH_up_ref(DH *r)
++{
++    int i;
++
++    if (CRYPTO_atomic_add(&r->references, 1, &i, r->lock) <= 0)
++        return 0;
++
++    REF_PRINT_COUNT("DH", r);
++    REF_ASSERT_ISNT(i < 2);
++    return ((i > 1) ? 1 : 0);
++}
++
++int DH_set_ex_data(DH *d, int idx, void *arg)
++{
++    return (CRYPTO_set_ex_data(&d->ex_data, idx, arg));
++}
++
++void *DH_get_ex_data(DH *d, int idx)
++{
++    return (CRYPTO_get_ex_data(&d->ex_data, idx));
++}
++
++int DH_bits(const DH *dh)
++{
++    return BN_num_bits(dh->p);
++}
++
++int DH_size(const DH *dh)
++{
++    return (BN_num_bytes(dh->p));
++}
++
++int DH_security_bits(const DH *dh)
++{
++    int N;
++    if (dh->q)
++        N = BN_num_bits(dh->q);
++    else if (dh->length)
++        N = dh->length;
++    else
++        N = -1;
++    return BN_security_bits(BN_num_bits(dh->p), N);
++}
++
++
++void DH_get0_pqg(const DH *dh,
++                 const BIGNUM **p, const BIGNUM **q, const BIGNUM **g)
++{
++    if (p != NULL)
++        *p = dh->p;
++    if (q != NULL)
++        *q = dh->q;
++    if (g != NULL)
++        *g = dh->g;
++}
++
++int DH_set0_pqg(DH *dh, BIGNUM *p, BIGNUM *q, BIGNUM *g)
++{
++    /* If the fields p and g in d are NULL, the corresponding input
++     * parameters MUST be non-NULL.  q may remain NULL.
++     */
++    if ((dh->p == NULL && p == NULL)
++        || (dh->g == NULL && g == NULL))
++        return 0;
++
++    if (p != NULL) {
++        BN_free(dh->p);
++        dh->p = p;
++    }
++    if (q != NULL) {
++        BN_free(dh->q);
++        dh->q = q;
++    }
++    if (g != NULL) {
++        BN_free(dh->g);
++        dh->g = g;
++    }
++
++    if (q != NULL) {
++        dh->length = BN_num_bits(q);
++    }
++
++    return 1;
++}
++
++long DH_get_length(const DH *dh)
++{
++    return dh->length;
++}
++
++int DH_set_length(DH *dh, long length)
++{
++    dh->length = length;
++    return 1;
++}
++
++void DH_get0_key(const DH *dh, const BIGNUM **pub_key, const BIGNUM **priv_key)
++{
++    if (pub_key != NULL)
++        *pub_key = dh->pub_key;
++    if (priv_key != NULL)
++        *priv_key = dh->priv_key;
++}
++
++int DH_set0_key(DH *dh, BIGNUM *pub_key, BIGNUM *priv_key)
++{
++    /* If the field pub_key in dh is NULL, the corresponding input
++     * parameters MUST be non-NULL.  The priv_key field may
++     * be left NULL.
++     */
++    if (dh->pub_key == NULL && pub_key == NULL)
++        return 0;
++
++    if (pub_key != NULL) {
++        BN_free(dh->pub_key);
++        dh->pub_key = pub_key;
++    }
++    if (priv_key != NULL) {
++        BN_free(dh->priv_key);
++        dh->priv_key = priv_key;
++    }
++
++    return 1;
++}
++
++void DH_clear_flags(DH *dh, int flags)
++{
++    dh->flags &= ~flags;
++}
++
++int DH_test_flags(const DH *dh, int flags)
++{
++    return dh->flags & flags;
++}
++
++void DH_set_flags(DH *dh, int flags)
++{
++    dh->flags |= flags;
++}
++
++ENGINE *DH_get0_engine(DH *dh)
++{
++    return dh->engine;
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/dh/dh_locl.h b/CryptoPkg/Library/OpensslLib/openssl/crypto/dh/dh_locl.h
+new file mode 100644
+index 0000000..19301c3
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/dh/dh_locl.h
+@@ -0,0 +1,56 @@
++/*
++ * Copyright 2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++
++struct dh_st {
++    /*
++     * This first argument is used to pick up errors when a DH is passed
++     * instead of a EVP_PKEY
++     */
++    int pad;
++    int version;
++    BIGNUM *p;
++    BIGNUM *g;
++    long length;                /* optional */
++    BIGNUM *pub_key;            /* g^x % p */
++    BIGNUM *priv_key;           /* x */
++    int flags;
++    BN_MONT_CTX *method_mont_p;
++    /* Place holders if we want to do X9.42 DH */
++    BIGNUM *q;
++    BIGNUM *j;
++    unsigned char *seed;
++    int seedlen;
++    BIGNUM *counter;
++    int references;
++    CRYPTO_EX_DATA ex_data;
++    const DH_METHOD *meth;
++    ENGINE *engine;
++    CRYPTO_RWLOCK *lock;
++};
++
++struct dh_method {
++    char *name;
++    /* Methods here */
++    int (*generate_key) (DH *dh);
++    int (*compute_key) (unsigned char *key, const BIGNUM *pub_key, DH *dh);
++
++    /* Can be null */
++    int (*bn_mod_exp) (const DH *dh, BIGNUM *r, const BIGNUM *a,
++                       const BIGNUM *p, const BIGNUM *m, BN_CTX *ctx,
++                       BN_MONT_CTX *m_ctx);
++    int (*init) (DH *dh);
++    int (*finish) (DH *dh);
++    int flags;
++    char *app_data;
++    /* If this is non-NULL, it will be used to generate parameters */
++    int (*generate_params) (DH *dh, int prime_len, int generator,
++                            BN_GENCB *cb);
++};
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/dh/dh_meth.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/dh/dh_meth.c
+new file mode 100644
+index 0000000..ce6114c
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/dh/dh_meth.c
+@@ -0,0 +1,173 @@
++/*
++ * Copyright 2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include "dh_locl.h"
++#include 
++#include 
++
++DH_METHOD *DH_meth_new(const char *name, int flags)
++{
++    DH_METHOD *dhm = OPENSSL_zalloc(sizeof(*dhm));
++
++    if (dhm != NULL) {
++        dhm->flags = flags;
++
++        dhm->name = OPENSSL_strdup(name);
++        if (dhm->name != NULL)
++            return dhm;
++
++        OPENSSL_free(dhm);
++    }
++
++    DHerr(DH_F_DH_METH_NEW, ERR_R_MALLOC_FAILURE);
++    return NULL;
++}
++
++void DH_meth_free(DH_METHOD *dhm)
++{
++    if (dhm != NULL) {
++        OPENSSL_free(dhm->name);
++        OPENSSL_free(dhm);
++    }
++}
++
++DH_METHOD *DH_meth_dup(const DH_METHOD *dhm)
++{
++    DH_METHOD *ret = OPENSSL_malloc(sizeof(*ret));
++
++    if (ret != NULL) {
++        memcpy(ret, dhm, sizeof(*dhm));
++
++        ret->name = OPENSSL_strdup(dhm->name);
++        if (ret->name != NULL)
++            return ret;
++
++        OPENSSL_free(ret);
++    }
++
++    DHerr(DH_F_DH_METH_DUP, ERR_R_MALLOC_FAILURE);
++    return NULL;
++}
++
++const char *DH_meth_get0_name(const DH_METHOD *dhm)
++{
++    return dhm->name;
++}
++
++int DH_meth_set1_name(DH_METHOD *dhm, const char *name)
++{
++    char *tmpname = OPENSSL_strdup(name);
++
++    if (tmpname == NULL) {
++        DHerr(DH_F_DH_METH_SET1_NAME, ERR_R_MALLOC_FAILURE);
++        return 0;
++    }
++
++    OPENSSL_free(dhm->name);
++    dhm->name = tmpname;
++
++    return 1;
++}
++
++int DH_meth_get_flags(DH_METHOD *dhm)
++{
++    return dhm->flags;
++}
++
++int DH_meth_set_flags(DH_METHOD *dhm, int flags)
++{
++    dhm->flags = flags;
++    return 1;
++}
++
++void *DH_meth_get0_app_data(const DH_METHOD *dhm)
++{
++    return dhm->app_data;
++}
++
++int DH_meth_set0_app_data(DH_METHOD *dhm, void *app_data)
++{
++    dhm->app_data = app_data;
++    return 1;
++}
++
++int (*DH_meth_get_generate_key(const DH_METHOD *dhm)) (DH *)
++{
++    return dhm->generate_key;
++}
++
++int DH_meth_set_generate_key(DH_METHOD *dhm, int (*generate_key) (DH *))
++{
++    dhm->generate_key = generate_key;
++    return 1;
++}
++
++int (*DH_meth_get_compute_key(const DH_METHOD *dhm))
++        (unsigned char *key, const BIGNUM *pub_key, DH *dh)
++{
++    return dhm->compute_key;
++}
++
++int DH_meth_set_compute_key(DH_METHOD *dhm,
++        int (*compute_key) (unsigned char *key, const BIGNUM *pub_key, DH *dh))
++{
++    dhm->compute_key = compute_key;
++    return 1;
++}
++
++
++int (*DH_meth_get_bn_mod_exp(const DH_METHOD *dhm))
++    (const DH *, BIGNUM *, const BIGNUM *, const BIGNUM *, const BIGNUM *,
++     BN_CTX *, BN_MONT_CTX *)
++{
++    return dhm->bn_mod_exp;
++}
++
++int DH_meth_set_bn_mod_exp(DH_METHOD *dhm,
++    int (*bn_mod_exp) (const DH *, BIGNUM *, const BIGNUM *, const BIGNUM *,
++                       const BIGNUM *, BN_CTX *, BN_MONT_CTX *))
++{
++    dhm->bn_mod_exp = bn_mod_exp;
++    return 1;
++}
++
++int (*DH_meth_get_init(const DH_METHOD *dhm))(DH *)
++{
++    return dhm->init;
++}
++
++int DH_meth_set_init(DH_METHOD *dhm, int (*init)(DH *))
++{
++    dhm->init = init;
++    return 1;
++}
++
++int (*DH_meth_get_finish(const DH_METHOD *dhm)) (DH *)
++{
++    return dhm->finish;
++}
++
++int DH_meth_set_finish(DH_METHOD *dhm, int (*finish) (DH *))
++{
++    dhm->finish = finish;
++    return 1;
++}
++
++int (*DH_meth_get_generate_params(const DH_METHOD *dhm))
++        (DH *, int, int, BN_GENCB *)
++{
++    return dhm->generate_params;
++}
++
++int DH_meth_set_generate_params(DH_METHOD *dhm,
++        int (*generate_params) (DH *, int, int, BN_GENCB *))
++{
++    dhm->generate_params = generate_params;
++    return 1;
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/dh/dh_pmeth.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/dh/dh_pmeth.c
+new file mode 100644
+index 0000000..c3e03c7
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/dh/dh_pmeth.c
+@@ -0,0 +1,501 @@
++/*
++ * Copyright 2006-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include "internal/cryptlib.h"
++#include 
++#include 
++#include 
++#include "dh_locl.h"
++#include 
++#include 
++#include 
++#include "internal/evp_int.h"
++
++/* DH pkey context structure */
++
++typedef struct {
++    /* Parameter gen parameters */
++    int prime_len;
++    int generator;
++    int use_dsa;
++    int subprime_len;
++    /* message digest used for parameter generation */
++    const EVP_MD *md;
++    int rfc5114_param;
++    /* Keygen callback info */
++    int gentmp[2];
++    /* KDF (if any) to use for DH */
++    char kdf_type;
++    /* OID to use for KDF */
++    ASN1_OBJECT *kdf_oid;
++    /* Message digest to use for key derivation */
++    const EVP_MD *kdf_md;
++    /* User key material */
++    unsigned char *kdf_ukm;
++    size_t kdf_ukmlen;
++    /* KDF output length */
++    size_t kdf_outlen;
++} DH_PKEY_CTX;
++
++static int pkey_dh_init(EVP_PKEY_CTX *ctx)
++{
++    DH_PKEY_CTX *dctx;
++
++    dctx = OPENSSL_zalloc(sizeof(*dctx));
++    if (dctx == NULL)
++        return 0;
++    dctx->prime_len = 1024;
++    dctx->subprime_len = -1;
++    dctx->generator = 2;
++    dctx->kdf_type = EVP_PKEY_DH_KDF_NONE;
++
++    ctx->data = dctx;
++    ctx->keygen_info = dctx->gentmp;
++    ctx->keygen_info_count = 2;
++
++    return 1;
++}
++
++static void pkey_dh_cleanup(EVP_PKEY_CTX *ctx)
++{
++    DH_PKEY_CTX *dctx = ctx->data;
++    if (dctx != NULL) {
++        OPENSSL_free(dctx->kdf_ukm);
++        ASN1_OBJECT_free(dctx->kdf_oid);
++        OPENSSL_free(dctx);
++    }
++}
++
++
++static int pkey_dh_copy(EVP_PKEY_CTX *dst, EVP_PKEY_CTX *src)
++{
++    DH_PKEY_CTX *dctx, *sctx;
++    if (!pkey_dh_init(dst))
++        return 0;
++    sctx = src->data;
++    dctx = dst->data;
++    dctx->prime_len = sctx->prime_len;
++    dctx->subprime_len = sctx->subprime_len;
++    dctx->generator = sctx->generator;
++    dctx->use_dsa = sctx->use_dsa;
++    dctx->md = sctx->md;
++    dctx->rfc5114_param = sctx->rfc5114_param;
++
++    dctx->kdf_type = sctx->kdf_type;
++    dctx->kdf_oid = OBJ_dup(sctx->kdf_oid);
++    if (dctx->kdf_oid == NULL)
++        return 0;
++    dctx->kdf_md = sctx->kdf_md;
++    if (sctx->kdf_ukm != NULL) {
++        dctx->kdf_ukm = OPENSSL_memdup(sctx->kdf_ukm, sctx->kdf_ukmlen);
++        if (dctx->kdf_ukm == NULL)
++          return 0;
++        dctx->kdf_ukmlen = sctx->kdf_ukmlen;
++    }
++    dctx->kdf_outlen = sctx->kdf_outlen;
++    return 1;
++}
++
++static int pkey_dh_ctrl(EVP_PKEY_CTX *ctx, int type, int p1, void *p2)
++{
++    DH_PKEY_CTX *dctx = ctx->data;
++    switch (type) {
++    case EVP_PKEY_CTRL_DH_PARAMGEN_PRIME_LEN:
++        if (p1 < 256)
++            return -2;
++        dctx->prime_len = p1;
++        return 1;
++
++    case EVP_PKEY_CTRL_DH_PARAMGEN_SUBPRIME_LEN:
++        if (dctx->use_dsa == 0)
++            return -2;
++        dctx->subprime_len = p1;
++        return 1;
++
++    case EVP_PKEY_CTRL_DH_PARAMGEN_GENERATOR:
++        if (dctx->use_dsa)
++            return -2;
++        dctx->generator = p1;
++        return 1;
++
++    case EVP_PKEY_CTRL_DH_PARAMGEN_TYPE:
++#ifdef OPENSSL_NO_DSA
++        if (p1 != 0)
++            return -2;
++#else
++        if (p1 < 0 || p1 > 2)
++            return -2;
++#endif
++        dctx->use_dsa = p1;
++        return 1;
++
++    case EVP_PKEY_CTRL_DH_RFC5114:
++        if (p1 < 1 || p1 > 3)
++            return -2;
++        dctx->rfc5114_param = p1;
++        return 1;
++
++    case EVP_PKEY_CTRL_PEER_KEY:
++        /* Default behaviour is OK */
++        return 1;
++
++    case EVP_PKEY_CTRL_DH_KDF_TYPE:
++        if (p1 == -2)
++            return dctx->kdf_type;
++#ifdef OPENSSL_NO_CMS
++        if (p1 != EVP_PKEY_DH_KDF_NONE)
++#else
++        if (p1 != EVP_PKEY_DH_KDF_NONE && p1 != EVP_PKEY_DH_KDF_X9_42)
++#endif
++            return -2;
++        dctx->kdf_type = p1;
++        return 1;
++
++    case EVP_PKEY_CTRL_DH_KDF_MD:
++        dctx->kdf_md = p2;
++        return 1;
++
++    case EVP_PKEY_CTRL_GET_DH_KDF_MD:
++        *(const EVP_MD **)p2 = dctx->kdf_md;
++        return 1;
++
++    case EVP_PKEY_CTRL_DH_KDF_OUTLEN:
++        if (p1 <= 0)
++            return -2;
++        dctx->kdf_outlen = (size_t)p1;
++        return 1;
++
++    case EVP_PKEY_CTRL_GET_DH_KDF_OUTLEN:
++        *(int *)p2 = dctx->kdf_outlen;
++        return 1;
++
++    case EVP_PKEY_CTRL_DH_KDF_UKM:
++        OPENSSL_free(dctx->kdf_ukm);
++        dctx->kdf_ukm = p2;
++        if (p2)
++            dctx->kdf_ukmlen = p1;
++        else
++            dctx->kdf_ukmlen = 0;
++        return 1;
++
++    case EVP_PKEY_CTRL_GET_DH_KDF_UKM:
++        *(unsigned char **)p2 = dctx->kdf_ukm;
++        return dctx->kdf_ukmlen;
++
++    case EVP_PKEY_CTRL_DH_KDF_OID:
++        ASN1_OBJECT_free(dctx->kdf_oid);
++        dctx->kdf_oid = p2;
++        return 1;
++
++    case EVP_PKEY_CTRL_GET_DH_KDF_OID:
++        *(ASN1_OBJECT **)p2 = dctx->kdf_oid;
++        return 1;
++
++    default:
++        return -2;
++
++    }
++}
++
++static int pkey_dh_ctrl_str(EVP_PKEY_CTX *ctx,
++                            const char *type, const char *value)
++{
++    if (strcmp(type, "dh_paramgen_prime_len") == 0) {
++        int len;
++        len = atoi(value);
++        return EVP_PKEY_CTX_set_dh_paramgen_prime_len(ctx, len);
++    }
++    if (strcmp(type, "dh_rfc5114") == 0) {
++        DH_PKEY_CTX *dctx = ctx->data;
++        int len;
++        len = atoi(value);
++        if (len < 0 || len > 3)
++            return -2;
++        dctx->rfc5114_param = len;
++        return 1;
++    }
++    if (strcmp(type, "dh_paramgen_generator") == 0) {
++        int len;
++        len = atoi(value);
++        return EVP_PKEY_CTX_set_dh_paramgen_generator(ctx, len);
++    }
++    if (strcmp(type, "dh_paramgen_subprime_len") == 0) {
++        int len;
++        len = atoi(value);
++        return EVP_PKEY_CTX_set_dh_paramgen_subprime_len(ctx, len);
++    }
++    if (strcmp(type, "dh_paramgen_type") == 0) {
++        int typ;
++        typ = atoi(value);
++        return EVP_PKEY_CTX_set_dh_paramgen_type(ctx, typ);
++    }
++    return -2;
++}
++
++#ifndef OPENSSL_NO_DSA
++
++extern int dsa_builtin_paramgen(DSA *ret, size_t bits, size_t qbits,
++                                const EVP_MD *evpmd,
++                                const unsigned char *seed_in, size_t seed_len,
++                                unsigned char *seed_out, int *counter_ret,
++                                unsigned long *h_ret, BN_GENCB *cb);
++
++extern int dsa_builtin_paramgen2(DSA *ret, size_t L, size_t N,
++                                 const EVP_MD *evpmd,
++                                 const unsigned char *seed_in,
++                                 size_t seed_len, int idx,
++                                 unsigned char *seed_out, int *counter_ret,
++                                 unsigned long *h_ret, BN_GENCB *cb);
++
++static DSA *dsa_dh_generate(DH_PKEY_CTX *dctx, BN_GENCB *pcb)
++{
++    DSA *ret;
++    int rv = 0;
++    int prime_len = dctx->prime_len;
++    int subprime_len = dctx->subprime_len;
++    const EVP_MD *md = dctx->md;
++    if (dctx->use_dsa > 2)
++        return NULL;
++    ret = DSA_new();
++    if (ret == NULL)
++        return NULL;
++    if (subprime_len == -1) {
++        if (prime_len >= 2048)
++            subprime_len = 256;
++        else
++            subprime_len = 160;
++    }
++    if (md == NULL) {
++        if (prime_len >= 2048)
++            md = EVP_sha256();
++        else
++            md = EVP_sha1();
++    }
++    if (dctx->use_dsa == 1)
++        rv = dsa_builtin_paramgen(ret, prime_len, subprime_len, md,
++                                  NULL, 0, NULL, NULL, NULL, pcb);
++    else if (dctx->use_dsa == 2)
++        rv = dsa_builtin_paramgen2(ret, prime_len, subprime_len, md,
++                                   NULL, 0, -1, NULL, NULL, NULL, pcb);
++    if (rv <= 0) {
++        DSA_free(ret);
++        return NULL;
++    }
++    return ret;
++}
++
++#endif
++
++static int pkey_dh_paramgen(EVP_PKEY_CTX *ctx, EVP_PKEY *pkey)
++{
++    DH *dh = NULL;
++    DH_PKEY_CTX *dctx = ctx->data;
++    BN_GENCB *pcb;
++    int ret;
++    if (dctx->rfc5114_param) {
++        switch (dctx->rfc5114_param) {
++        case 1:
++            dh = DH_get_1024_160();
++            break;
++
++        case 2:
++            dh = DH_get_2048_224();
++            break;
++
++        case 3:
++            dh = DH_get_2048_256();
++            break;
++
++        default:
++            return -2;
++        }
++        EVP_PKEY_assign(pkey, EVP_PKEY_DHX, dh);
++        return 1;
++    }
++
++    if (ctx->pkey_gencb) {
++        pcb = BN_GENCB_new();
++        if (pcb == NULL)
++            return 0;
++        evp_pkey_set_cb_translate(pcb, ctx);
++    } else
++        pcb = NULL;
++#ifndef OPENSSL_NO_DSA
++    if (dctx->use_dsa) {
++        DSA *dsa_dh;
++        dsa_dh = dsa_dh_generate(dctx, pcb);
++        BN_GENCB_free(pcb);
++        if (dsa_dh == NULL)
++            return 0;
++        dh = DSA_dup_DH(dsa_dh);
++        DSA_free(dsa_dh);
++        if (!dh)
++            return 0;
++        EVP_PKEY_assign(pkey, EVP_PKEY_DHX, dh);
++        return 1;
++    }
++#endif
++    dh = DH_new();
++    if (dh == NULL) {
++        BN_GENCB_free(pcb);
++        return 0;
++    }
++    ret = DH_generate_parameters_ex(dh,
++                                    dctx->prime_len, dctx->generator, pcb);
++    BN_GENCB_free(pcb);
++    if (ret)
++        EVP_PKEY_assign_DH(pkey, dh);
++    else
++        DH_free(dh);
++    return ret;
++}
++
++static int pkey_dh_keygen(EVP_PKEY_CTX *ctx, EVP_PKEY *pkey)
++{
++    DH *dh = NULL;
++    if (ctx->pkey == NULL) {
++        DHerr(DH_F_PKEY_DH_KEYGEN, DH_R_NO_PARAMETERS_SET);
++        return 0;
++    }
++    dh = DH_new();
++    if (dh == NULL)
++        return 0;
++    EVP_PKEY_assign(pkey, ctx->pmeth->pkey_id, dh);
++    /* Note: if error return, pkey is freed by parent routine */
++    if (!EVP_PKEY_copy_parameters(pkey, ctx->pkey))
++        return 0;
++    return DH_generate_key(pkey->pkey.dh);
++}
++
++static int pkey_dh_derive(EVP_PKEY_CTX *ctx, unsigned char *key,
++                          size_t *keylen)
++{
++    int ret;
++    DH *dh;
++    DH_PKEY_CTX *dctx = ctx->data;
++    BIGNUM *dhpub;
++    if (!ctx->pkey || !ctx->peerkey) {
++        DHerr(DH_F_PKEY_DH_DERIVE, DH_R_KEYS_NOT_SET);
++        return 0;
++    }
++    dh = ctx->pkey->pkey.dh;
++    dhpub = ctx->peerkey->pkey.dh->pub_key;
++    if (dctx->kdf_type == EVP_PKEY_DH_KDF_NONE) {
++        if (key == NULL) {
++            *keylen = DH_size(dh);
++            return 1;
++        }
++        ret = DH_compute_key(key, dhpub, dh);
++        if (ret < 0)
++            return ret;
++        *keylen = ret;
++        return 1;
++    }
++#ifndef OPENSSL_NO_CMS
++    else if (dctx->kdf_type == EVP_PKEY_DH_KDF_X9_42) {
++
++        unsigned char *Z = NULL;
++        size_t Zlen = 0;
++        if (!dctx->kdf_outlen || !dctx->kdf_oid)
++            return 0;
++        if (key == NULL) {
++            *keylen = dctx->kdf_outlen;
++            return 1;
++        }
++        if (*keylen != dctx->kdf_outlen)
++            return 0;
++        ret = 0;
++        Zlen = DH_size(dh);
++        Z = OPENSSL_malloc(Zlen);
++        if (Z == NULL) {
++            goto err;
++        }
++        if (DH_compute_key_padded(Z, dhpub, dh) <= 0)
++            goto err;
++        if (!DH_KDF_X9_42(key, *keylen, Z, Zlen, dctx->kdf_oid,
++                          dctx->kdf_ukm, dctx->kdf_ukmlen, dctx->kdf_md))
++            goto err;
++        *keylen = dctx->kdf_outlen;
++        ret = 1;
++ err:
++        OPENSSL_clear_free(Z, Zlen);
++        return ret;
++    }
++#endif
++    return 0;
++}
++
++const EVP_PKEY_METHOD dh_pkey_meth = {
++    EVP_PKEY_DH,
++    0,
++    pkey_dh_init,
++    pkey_dh_copy,
++    pkey_dh_cleanup,
++
++    0,
++    pkey_dh_paramgen,
++
++    0,
++    pkey_dh_keygen,
++
++    0,
++    0,
++
++    0,
++    0,
++
++    0, 0,
++
++    0, 0, 0, 0,
++
++    0, 0,
++
++    0, 0,
++
++    0,
++    pkey_dh_derive,
++
++    pkey_dh_ctrl,
++    pkey_dh_ctrl_str
++};
++
++const EVP_PKEY_METHOD dhx_pkey_meth = {
++    EVP_PKEY_DHX,
++    0,
++    pkey_dh_init,
++    pkey_dh_copy,
++    pkey_dh_cleanup,
++
++    0,
++    pkey_dh_paramgen,
++
++    0,
++    pkey_dh_keygen,
++
++    0,
++    0,
++
++    0,
++    0,
++
++    0, 0,
++
++    0, 0, 0, 0,
++
++    0, 0,
++
++    0, 0,
++
++    0,
++    pkey_dh_derive,
++
++    pkey_dh_ctrl,
++    pkey_dh_ctrl_str
++};
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/dh/dh_prn.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/dh/dh_prn.c
+new file mode 100644
+index 0000000..283fb0f
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/dh/dh_prn.c
+@@ -0,0 +1,30 @@
++/*
++ * Copyright 1995-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include "internal/cryptlib.h"
++#include 
++#include 
++
++#ifndef OPENSSL_NO_STDIO
++int DHparams_print_fp(FILE *fp, const DH *x)
++{
++    BIO *b;
++    int ret;
++
++    if ((b = BIO_new(BIO_s_file())) == NULL) {
++        DHerr(DH_F_DHPARAMS_PRINT_FP, ERR_R_BUF_LIB);
++        return (0);
++    }
++    BIO_set_fp(b, fp, BIO_NOCLOSE);
++    ret = DHparams_print(b, x);
++    BIO_free(b);
++    return (ret);
++}
++#endif
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/dh/dh_rfc5114.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/dh/dh_rfc5114.c
+new file mode 100644
+index 0000000..c4a2195
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/dh/dh_rfc5114.c
+@@ -0,0 +1,41 @@
++/*
++ * Copyright 2011-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include "internal/cryptlib.h"
++#include "dh_locl.h"
++#include 
++#include "internal/bn_dh.h"
++
++/*
++ * Macro to make a DH structure from BIGNUM data. NB: although just copying
++ * the BIGNUM static pointers would be more efficient, we can't do that
++ * because they get wiped using BN_clear_free() when DH_free() is called.
++ */
++
++#define make_dh(x) \
++DH *DH_get_##x(void) \
++{ \
++    DH *dh = DH_new(); \
++\
++    if (dh == NULL) \
++        return NULL; \
++    dh->p = BN_dup(&_bignum_dh##x##_p); \
++    dh->g = BN_dup(&_bignum_dh##x##_g); \
++    dh->q = BN_dup(&_bignum_dh##x##_q); \
++    if (dh->p == NULL || dh->q == NULL || dh->g == NULL) {\
++        DH_free(dh); \
++        return NULL; \
++    } \
++    return dh; \
++}
++
++make_dh(1024_160)
++make_dh(2048_224)
++make_dh(2048_256)
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/dllmain.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/dllmain.c
+new file mode 100644
+index 0000000..91904aa
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/dllmain.c
+@@ -0,0 +1,60 @@
++/*
++ * Copyright 2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include "internal/cryptlib_int.h"
++
++#if defined(_WIN32) || defined(__CYGWIN__)
++# ifdef __CYGWIN__
++/* pick DLL_[PROCESS|THREAD]_[ATTACH|DETACH] definitions */
++#  include 
++/*
++ * this has side-effect of _WIN32 getting defined, which otherwise is
++ * mutually exclusive with __CYGWIN__...
++ */
++# endif
++
++/*
++ * All we really need to do is remove the 'error' state when a thread
++ * detaches
++ */
++
++BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved);
++BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
++{
++    switch (fdwReason) {
++    case DLL_PROCESS_ATTACH:
++        OPENSSL_cpuid_setup();
++# if defined(_WIN32_WINNT)
++        {
++            IMAGE_DOS_HEADER *dos_header = (IMAGE_DOS_HEADER *) hinstDLL;
++            IMAGE_NT_HEADERS *nt_headers;
++
++            if (dos_header->e_magic == IMAGE_DOS_SIGNATURE) {
++                nt_headers = (IMAGE_NT_HEADERS *) ((char *)dos_header
++                                                   + dos_header->e_lfanew);
++                if (nt_headers->Signature == IMAGE_NT_SIGNATURE &&
++                    hinstDLL !=
++                    (HINSTANCE) (nt_headers->OptionalHeader.ImageBase))
++                    OPENSSL_NONPIC_relocated = 1;
++            }
++        }
++# endif
++        break;
++    case DLL_THREAD_ATTACH:
++        break;
++    case DLL_THREAD_DETACH:
++        OPENSSL_thread_stop();
++        break;
++    case DLL_PROCESS_DETACH:
++        break;
++    }
++    return (TRUE);
++}
++#endif
++
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/dsa/build.info b/CryptoPkg/Library/OpensslLib/openssl/crypto/dsa/build.info
+new file mode 100644
+index 0000000..2e75985
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/dsa/build.info
+@@ -0,0 +1,5 @@
++LIBS=../../libcrypto
++SOURCE[../../libcrypto]=\
++        dsa_gen.c dsa_key.c dsa_lib.c dsa_asn1.c dsa_vrf.c dsa_sign.c \
++        dsa_err.c dsa_ossl.c dsa_depr.c dsa_ameth.c dsa_pmeth.c dsa_prn.c \
++        dsa_meth.c
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/dsa/dsa_ameth.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/dsa/dsa_ameth.c
+new file mode 100644
+index 0000000..7c0428d
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/dsa/dsa_ameth.c
+@@ -0,0 +1,567 @@
++/*
++ * Copyright 2006-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include "internal/cryptlib.h"
++#include 
++#include 
++#include "dsa_locl.h"
++#include 
++#include 
++#include "internal/asn1_int.h"
++#include "internal/evp_int.h"
++
++static int dsa_pub_decode(EVP_PKEY *pkey, X509_PUBKEY *pubkey)
++{
++    const unsigned char *p, *pm;
++    int pklen, pmlen;
++    int ptype;
++    const void *pval;
++    const ASN1_STRING *pstr;
++    X509_ALGOR *palg;
++    ASN1_INTEGER *public_key = NULL;
++
++    DSA *dsa = NULL;
++
++    if (!X509_PUBKEY_get0_param(NULL, &p, &pklen, &palg, pubkey))
++        return 0;
++    X509_ALGOR_get0(NULL, &ptype, &pval, palg);
++
++    if (ptype == V_ASN1_SEQUENCE) {
++        pstr = pval;
++        pm = pstr->data;
++        pmlen = pstr->length;
++
++        if ((dsa = d2i_DSAparams(NULL, &pm, pmlen)) == NULL) {
++            DSAerr(DSA_F_DSA_PUB_DECODE, DSA_R_DECODE_ERROR);
++            goto err;
++        }
++
++    } else if ((ptype == V_ASN1_NULL) || (ptype == V_ASN1_UNDEF)) {
++        if ((dsa = DSA_new()) == NULL) {
++            DSAerr(DSA_F_DSA_PUB_DECODE, ERR_R_MALLOC_FAILURE);
++            goto err;
++        }
++    } else {
++        DSAerr(DSA_F_DSA_PUB_DECODE, DSA_R_PARAMETER_ENCODING_ERROR);
++        goto err;
++    }
++
++    if ((public_key = d2i_ASN1_INTEGER(NULL, &p, pklen)) == NULL) {
++        DSAerr(DSA_F_DSA_PUB_DECODE, DSA_R_DECODE_ERROR);
++        goto err;
++    }
++
++    if ((dsa->pub_key = ASN1_INTEGER_to_BN(public_key, NULL)) == NULL) {
++        DSAerr(DSA_F_DSA_PUB_DECODE, DSA_R_BN_DECODE_ERROR);
++        goto err;
++    }
++
++    ASN1_INTEGER_free(public_key);
++    EVP_PKEY_assign_DSA(pkey, dsa);
++    return 1;
++
++ err:
++    ASN1_INTEGER_free(public_key);
++    DSA_free(dsa);
++    return 0;
++
++}
++
++static int dsa_pub_encode(X509_PUBKEY *pk, const EVP_PKEY *pkey)
++{
++    DSA *dsa;
++    int ptype;
++    unsigned char *penc = NULL;
++    int penclen;
++    ASN1_STRING *str = NULL;
++    ASN1_INTEGER *pubint = NULL;
++
++    dsa = pkey->pkey.dsa;
++    if (pkey->save_parameters && dsa->p && dsa->q && dsa->g) {
++        str = ASN1_STRING_new();
++        if (str == NULL) {
++            DSAerr(DSA_F_DSA_PUB_ENCODE, ERR_R_MALLOC_FAILURE);
++            goto err;
++        }
++        str->length = i2d_DSAparams(dsa, &str->data);
++        if (str->length <= 0) {
++            DSAerr(DSA_F_DSA_PUB_ENCODE, ERR_R_MALLOC_FAILURE);
++            goto err;
++        }
++        ptype = V_ASN1_SEQUENCE;
++    } else
++        ptype = V_ASN1_UNDEF;
++
++    pubint = BN_to_ASN1_INTEGER(dsa->pub_key, NULL);
++
++    if (pubint == NULL) {
++        DSAerr(DSA_F_DSA_PUB_ENCODE, ERR_R_MALLOC_FAILURE);
++        goto err;
++    }
++
++    penclen = i2d_ASN1_INTEGER(pubint, &penc);
++    ASN1_INTEGER_free(pubint);
++
++    if (penclen <= 0) {
++        DSAerr(DSA_F_DSA_PUB_ENCODE, ERR_R_MALLOC_FAILURE);
++        goto err;
++    }
++
++    if (X509_PUBKEY_set0_param(pk, OBJ_nid2obj(EVP_PKEY_DSA),
++                               ptype, str, penc, penclen))
++        return 1;
++
++ err:
++    OPENSSL_free(penc);
++    ASN1_STRING_free(str);
++
++    return 0;
++}
++
++/*
++ * In PKCS#8 DSA: you just get a private key integer and parameters in the
++ * AlgorithmIdentifier the pubkey must be recalculated.
++ */
++
++static int dsa_priv_decode(EVP_PKEY *pkey, const PKCS8_PRIV_KEY_INFO *p8)
++{
++    const unsigned char *p, *pm;
++    int pklen, pmlen;
++    int ptype;
++    const void *pval;
++    const ASN1_STRING *pstr;
++    const X509_ALGOR *palg;
++    ASN1_INTEGER *privkey = NULL;
++    BN_CTX *ctx = NULL;
++
++    DSA *dsa = NULL;
++
++    int ret = 0;
++
++    if (!PKCS8_pkey_get0(NULL, &p, &pklen, &palg, p8))
++        return 0;
++    X509_ALGOR_get0(NULL, &ptype, &pval, palg);
++
++    if ((privkey = d2i_ASN1_INTEGER(NULL, &p, pklen)) == NULL)
++        goto decerr;
++    if (privkey->type == V_ASN1_NEG_INTEGER || ptype != V_ASN1_SEQUENCE)
++        goto decerr;
++
++    pstr = pval;
++    pm = pstr->data;
++    pmlen = pstr->length;
++    if ((dsa = d2i_DSAparams(NULL, &pm, pmlen)) == NULL)
++        goto decerr;
++    /* We have parameters now set private key */
++    if ((dsa->priv_key = BN_secure_new()) == NULL
++        || !ASN1_INTEGER_to_BN(privkey, dsa->priv_key)) {
++        DSAerr(DSA_F_DSA_PRIV_DECODE, DSA_R_BN_ERROR);
++        goto dsaerr;
++    }
++    /* Calculate public key */
++    if ((dsa->pub_key = BN_new()) == NULL) {
++        DSAerr(DSA_F_DSA_PRIV_DECODE, ERR_R_MALLOC_FAILURE);
++        goto dsaerr;
++    }
++    if ((ctx = BN_CTX_new()) == NULL) {
++        DSAerr(DSA_F_DSA_PRIV_DECODE, ERR_R_MALLOC_FAILURE);
++        goto dsaerr;
++    }
++
++    if (!BN_mod_exp(dsa->pub_key, dsa->g, dsa->priv_key, dsa->p, ctx)) {
++        DSAerr(DSA_F_DSA_PRIV_DECODE, DSA_R_BN_ERROR);
++        goto dsaerr;
++    }
++
++    EVP_PKEY_assign_DSA(pkey, dsa);
++
++    ret = 1;
++    goto done;
++
++ decerr:
++    DSAerr(DSA_F_DSA_PRIV_DECODE, DSA_R_DECODE_ERROR);
++ dsaerr:
++    DSA_free(dsa);
++ done:
++    BN_CTX_free(ctx);
++    ASN1_STRING_clear_free(privkey);
++    return ret;
++}
++
++static int dsa_priv_encode(PKCS8_PRIV_KEY_INFO *p8, const EVP_PKEY *pkey)
++{
++    ASN1_STRING *params = NULL;
++    ASN1_INTEGER *prkey = NULL;
++    unsigned char *dp = NULL;
++    int dplen;
++
++    if (!pkey->pkey.dsa || !pkey->pkey.dsa->priv_key) {
++        DSAerr(DSA_F_DSA_PRIV_ENCODE, DSA_R_MISSING_PARAMETERS);
++        goto err;
++    }
++
++    params = ASN1_STRING_new();
++
++    if (params == NULL) {
++        DSAerr(DSA_F_DSA_PRIV_ENCODE, ERR_R_MALLOC_FAILURE);
++        goto err;
++    }
++
++    params->length = i2d_DSAparams(pkey->pkey.dsa, ¶ms->data);
++    if (params->length <= 0) {
++        DSAerr(DSA_F_DSA_PRIV_ENCODE, ERR_R_MALLOC_FAILURE);
++        goto err;
++    }
++    params->type = V_ASN1_SEQUENCE;
++
++    /* Get private key into integer */
++    prkey = BN_to_ASN1_INTEGER(pkey->pkey.dsa->priv_key, NULL);
++
++    if (!prkey) {
++        DSAerr(DSA_F_DSA_PRIV_ENCODE, DSA_R_BN_ERROR);
++        goto err;
++    }
++
++    dplen = i2d_ASN1_INTEGER(prkey, &dp);
++
++    ASN1_STRING_clear_free(prkey);
++    prkey = NULL;
++
++    if (!PKCS8_pkey_set0(p8, OBJ_nid2obj(NID_dsa), 0,
++                         V_ASN1_SEQUENCE, params, dp, dplen))
++        goto err;
++
++    return 1;
++
++ err:
++    OPENSSL_free(dp);
++    ASN1_STRING_free(params);
++    ASN1_STRING_clear_free(prkey);
++    return 0;
++}
++
++static int int_dsa_size(const EVP_PKEY *pkey)
++{
++    return (DSA_size(pkey->pkey.dsa));
++}
++
++static int dsa_bits(const EVP_PKEY *pkey)
++{
++    return DSA_bits(pkey->pkey.dsa);
++}
++
++static int dsa_security_bits(const EVP_PKEY *pkey)
++{
++    return DSA_security_bits(pkey->pkey.dsa);
++}
++
++static int dsa_missing_parameters(const EVP_PKEY *pkey)
++{
++    DSA *dsa;
++    dsa = pkey->pkey.dsa;
++    if (dsa == NULL || dsa->p == NULL || dsa->q == NULL || dsa->g == NULL)
++        return 1;
++    return 0;
++}
++
++static int dsa_copy_parameters(EVP_PKEY *to, const EVP_PKEY *from)
++{
++    BIGNUM *a;
++
++    if (to->pkey.dsa == NULL) {
++        to->pkey.dsa = DSA_new();
++        if (to->pkey.dsa == NULL)
++            return 0;
++    }
++
++    if ((a = BN_dup(from->pkey.dsa->p)) == NULL)
++        return 0;
++    BN_free(to->pkey.dsa->p);
++    to->pkey.dsa->p = a;
++
++    if ((a = BN_dup(from->pkey.dsa->q)) == NULL)
++        return 0;
++    BN_free(to->pkey.dsa->q);
++    to->pkey.dsa->q = a;
++
++    if ((a = BN_dup(from->pkey.dsa->g)) == NULL)
++        return 0;
++    BN_free(to->pkey.dsa->g);
++    to->pkey.dsa->g = a;
++    return 1;
++}
++
++static int dsa_cmp_parameters(const EVP_PKEY *a, const EVP_PKEY *b)
++{
++    if (BN_cmp(a->pkey.dsa->p, b->pkey.dsa->p) ||
++        BN_cmp(a->pkey.dsa->q, b->pkey.dsa->q) ||
++        BN_cmp(a->pkey.dsa->g, b->pkey.dsa->g))
++        return 0;
++    else
++        return 1;
++}
++
++static int dsa_pub_cmp(const EVP_PKEY *a, const EVP_PKEY *b)
++{
++    if (BN_cmp(b->pkey.dsa->pub_key, a->pkey.dsa->pub_key) != 0)
++        return 0;
++    else
++        return 1;
++}
++
++static void int_dsa_free(EVP_PKEY *pkey)
++{
++    DSA_free(pkey->pkey.dsa);
++}
++
++static int do_dsa_print(BIO *bp, const DSA *x, int off, int ptype)
++{
++    int ret = 0;
++    const char *ktype = NULL;
++    const BIGNUM *priv_key, *pub_key;
++
++    if (ptype == 2)
++        priv_key = x->priv_key;
++    else
++        priv_key = NULL;
++
++    if (ptype > 0)
++        pub_key = x->pub_key;
++    else
++        pub_key = NULL;
++
++    if (ptype == 2)
++        ktype = "Private-Key";
++    else if (ptype == 1)
++        ktype = "Public-Key";
++    else
++        ktype = "DSA-Parameters";
++
++    if (priv_key) {
++        if (!BIO_indent(bp, off, 128))
++            goto err;
++        if (BIO_printf(bp, "%s: (%d bit)\n", ktype, BN_num_bits(x->p))
++            <= 0)
++            goto err;
++    }
++
++    if (!ASN1_bn_print(bp, "priv:", priv_key, NULL, off))
++        goto err;
++    if (!ASN1_bn_print(bp, "pub: ", pub_key, NULL, off))
++        goto err;
++    if (!ASN1_bn_print(bp, "P:   ", x->p, NULL, off))
++        goto err;
++    if (!ASN1_bn_print(bp, "Q:   ", x->q, NULL, off))
++        goto err;
++    if (!ASN1_bn_print(bp, "G:   ", x->g, NULL, off))
++        goto err;
++    ret = 1;
++ err:
++    return (ret);
++}
++
++static int dsa_param_decode(EVP_PKEY *pkey,
++                            const unsigned char **pder, int derlen)
++{
++    DSA *dsa;
++
++    if ((dsa = d2i_DSAparams(NULL, pder, derlen)) == NULL) {
++        DSAerr(DSA_F_DSA_PARAM_DECODE, ERR_R_DSA_LIB);
++        return 0;
++    }
++    EVP_PKEY_assign_DSA(pkey, dsa);
++    return 1;
++}
++
++static int dsa_param_encode(const EVP_PKEY *pkey, unsigned char **pder)
++{
++    return i2d_DSAparams(pkey->pkey.dsa, pder);
++}
++
++static int dsa_param_print(BIO *bp, const EVP_PKEY *pkey, int indent,
++                           ASN1_PCTX *ctx)
++{
++    return do_dsa_print(bp, pkey->pkey.dsa, indent, 0);
++}
++
++static int dsa_pub_print(BIO *bp, const EVP_PKEY *pkey, int indent,
++                         ASN1_PCTX *ctx)
++{
++    return do_dsa_print(bp, pkey->pkey.dsa, indent, 1);
++}
++
++static int dsa_priv_print(BIO *bp, const EVP_PKEY *pkey, int indent,
++                          ASN1_PCTX *ctx)
++{
++    return do_dsa_print(bp, pkey->pkey.dsa, indent, 2);
++}
++
++static int old_dsa_priv_decode(EVP_PKEY *pkey,
++                               const unsigned char **pder, int derlen)
++{
++    DSA *dsa;
++
++    if ((dsa = d2i_DSAPrivateKey(NULL, pder, derlen)) == NULL) {
++        DSAerr(DSA_F_OLD_DSA_PRIV_DECODE, ERR_R_DSA_LIB);
++        return 0;
++    }
++    EVP_PKEY_assign_DSA(pkey, dsa);
++    return 1;
++}
++
++static int old_dsa_priv_encode(const EVP_PKEY *pkey, unsigned char **pder)
++{
++    return i2d_DSAPrivateKey(pkey->pkey.dsa, pder);
++}
++
++static int dsa_sig_print(BIO *bp, const X509_ALGOR *sigalg,
++                         const ASN1_STRING *sig, int indent, ASN1_PCTX *pctx)
++{
++    DSA_SIG *dsa_sig;
++    const unsigned char *p;
++
++    if (!sig) {
++        if (BIO_puts(bp, "\n") <= 0)
++            return 0;
++        else
++            return 1;
++    }
++    p = sig->data;
++    dsa_sig = d2i_DSA_SIG(NULL, &p, sig->length);
++    if (dsa_sig) {
++        int rv = 0;
++        const BIGNUM *r, *s;
++
++        DSA_SIG_get0(dsa_sig, &r, &s);
++
++        if (BIO_write(bp, "\n", 1) != 1)
++            goto err;
++
++        if (!ASN1_bn_print(bp, "r:   ", r, NULL, indent))
++            goto err;
++        if (!ASN1_bn_print(bp, "s:   ", s, NULL, indent))
++            goto err;
++        rv = 1;
++ err:
++        DSA_SIG_free(dsa_sig);
++        return rv;
++    }
++    return X509_signature_dump(bp, sig, indent);
++}
++
++static int dsa_pkey_ctrl(EVP_PKEY *pkey, int op, long arg1, void *arg2)
++{
++    switch (op) {
++    case ASN1_PKEY_CTRL_PKCS7_SIGN:
++        if (arg1 == 0) {
++            int snid, hnid;
++            X509_ALGOR *alg1, *alg2;
++            PKCS7_SIGNER_INFO_get0_algs(arg2, NULL, &alg1, &alg2);
++            if (alg1 == NULL || alg1->algorithm == NULL)
++                return -1;
++            hnid = OBJ_obj2nid(alg1->algorithm);
++            if (hnid == NID_undef)
++                return -1;
++            if (!OBJ_find_sigid_by_algs(&snid, hnid, EVP_PKEY_id(pkey)))
++                return -1;
++            X509_ALGOR_set0(alg2, OBJ_nid2obj(snid), V_ASN1_UNDEF, 0);
++        }
++        return 1;
++#ifndef OPENSSL_NO_CMS
++    case ASN1_PKEY_CTRL_CMS_SIGN:
++        if (arg1 == 0) {
++            int snid, hnid;
++            X509_ALGOR *alg1, *alg2;
++            CMS_SignerInfo_get0_algs(arg2, NULL, NULL, &alg1, &alg2);
++            if (alg1 == NULL || alg1->algorithm == NULL)
++                return -1;
++            hnid = OBJ_obj2nid(alg1->algorithm);
++            if (hnid == NID_undef)
++                return -1;
++            if (!OBJ_find_sigid_by_algs(&snid, hnid, EVP_PKEY_id(pkey)))
++                return -1;
++            X509_ALGOR_set0(alg2, OBJ_nid2obj(snid), V_ASN1_UNDEF, 0);
++        }
++        return 1;
++
++    case ASN1_PKEY_CTRL_CMS_RI_TYPE:
++        *(int *)arg2 = CMS_RECIPINFO_NONE;
++        return 1;
++#endif
++
++    case ASN1_PKEY_CTRL_DEFAULT_MD_NID:
++        *(int *)arg2 = NID_sha256;
++        return 2;
++
++    default:
++        return -2;
++
++    }
++
++}
++
++/* NB these are sorted in pkey_id order, lowest first */
++
++const EVP_PKEY_ASN1_METHOD dsa_asn1_meths[5] = {
++
++    {
++     EVP_PKEY_DSA2,
++     EVP_PKEY_DSA,
++     ASN1_PKEY_ALIAS},
++
++    {
++     EVP_PKEY_DSA1,
++     EVP_PKEY_DSA,
++     ASN1_PKEY_ALIAS},
++
++    {
++     EVP_PKEY_DSA4,
++     EVP_PKEY_DSA,
++     ASN1_PKEY_ALIAS},
++
++    {
++     EVP_PKEY_DSA3,
++     EVP_PKEY_DSA,
++     ASN1_PKEY_ALIAS},
++
++    {
++     EVP_PKEY_DSA,
++     EVP_PKEY_DSA,
++     0,
++
++     "DSA",
++     "OpenSSL DSA method",
++
++     dsa_pub_decode,
++     dsa_pub_encode,
++     dsa_pub_cmp,
++     dsa_pub_print,
++
++     dsa_priv_decode,
++     dsa_priv_encode,
++     dsa_priv_print,
++
++     int_dsa_size,
++     dsa_bits,
++     dsa_security_bits,
++
++     dsa_param_decode,
++     dsa_param_encode,
++     dsa_missing_parameters,
++     dsa_copy_parameters,
++     dsa_cmp_parameters,
++     dsa_param_print,
++     dsa_sig_print,
++
++     int_dsa_free,
++     dsa_pkey_ctrl,
++     old_dsa_priv_decode,
++     old_dsa_priv_encode}
++};
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/dsa/dsa_asn1.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/dsa/dsa_asn1.c
+new file mode 100644
+index 0000000..551c107
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/dsa/dsa_asn1.c
+@@ -0,0 +1,155 @@
++/*
++ * Copyright 1999-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include "internal/cryptlib.h"
++#include "dsa_locl.h"
++#include 
++#include 
++#include 
++
++ASN1_SEQUENCE(DSA_SIG) = {
++        ASN1_SIMPLE(DSA_SIG, r, CBIGNUM),
++        ASN1_SIMPLE(DSA_SIG, s, CBIGNUM)
++} static_ASN1_SEQUENCE_END(DSA_SIG)
++
++IMPLEMENT_ASN1_ENCODE_FUNCTIONS_const_fname(DSA_SIG, DSA_SIG, DSA_SIG)
++
++DSA_SIG *DSA_SIG_new(void)
++{
++    DSA_SIG *sig = OPENSSL_zalloc(sizeof(*sig));
++    if (sig == NULL)
++        DSAerr(DSA_F_DSA_SIG_NEW, ERR_R_MALLOC_FAILURE);
++    return sig;
++}
++
++void DSA_SIG_free(DSA_SIG *sig)
++{
++    if (sig == NULL)
++        return;
++    BN_clear_free(sig->r);
++    BN_clear_free(sig->s);
++    OPENSSL_free(sig);
++}
++
++void DSA_SIG_get0(const DSA_SIG *sig, const BIGNUM **pr, const BIGNUM **ps)
++{
++    if (pr != NULL)
++        *pr = sig->r;
++    if (ps != NULL)
++        *ps = sig->s;
++}
++
++int DSA_SIG_set0(DSA_SIG *sig, BIGNUM *r, BIGNUM *s)
++{
++    if (r == NULL || s == NULL)
++        return 0;
++    BN_clear_free(sig->r);
++    BN_clear_free(sig->s);
++    sig->r = r;
++    sig->s = s;
++    return 1;
++}
++
++/* Override the default free and new methods */
++static int dsa_cb(int operation, ASN1_VALUE **pval, const ASN1_ITEM *it,
++                  void *exarg)
++{
++    if (operation == ASN1_OP_NEW_PRE) {
++        *pval = (ASN1_VALUE *)DSA_new();
++        if (*pval != NULL)
++            return 2;
++        return 0;
++    } else if (operation == ASN1_OP_FREE_PRE) {
++        DSA_free((DSA *)*pval);
++        *pval = NULL;
++        return 2;
++    }
++    return 1;
++}
++
++ASN1_SEQUENCE_cb(DSAPrivateKey, dsa_cb) = {
++        ASN1_SIMPLE(DSA, version, LONG),
++        ASN1_SIMPLE(DSA, p, BIGNUM),
++        ASN1_SIMPLE(DSA, q, BIGNUM),
++        ASN1_SIMPLE(DSA, g, BIGNUM),
++        ASN1_SIMPLE(DSA, pub_key, BIGNUM),
++        ASN1_SIMPLE(DSA, priv_key, CBIGNUM)
++} static_ASN1_SEQUENCE_END_cb(DSA, DSAPrivateKey)
++
++IMPLEMENT_ASN1_ENCODE_FUNCTIONS_const_fname(DSA, DSAPrivateKey, DSAPrivateKey)
++
++ASN1_SEQUENCE_cb(DSAparams, dsa_cb) = {
++        ASN1_SIMPLE(DSA, p, BIGNUM),
++        ASN1_SIMPLE(DSA, q, BIGNUM),
++        ASN1_SIMPLE(DSA, g, BIGNUM),
++} static_ASN1_SEQUENCE_END_cb(DSA, DSAparams)
++
++IMPLEMENT_ASN1_ENCODE_FUNCTIONS_const_fname(DSA, DSAparams, DSAparams)
++
++ASN1_SEQUENCE_cb(DSAPublicKey, dsa_cb) = {
++        ASN1_SIMPLE(DSA, pub_key, BIGNUM),
++        ASN1_SIMPLE(DSA, p, BIGNUM),
++        ASN1_SIMPLE(DSA, q, BIGNUM),
++        ASN1_SIMPLE(DSA, g, BIGNUM)
++} static_ASN1_SEQUENCE_END_cb(DSA, DSAPublicKey)
++
++IMPLEMENT_ASN1_ENCODE_FUNCTIONS_const_fname(DSA, DSAPublicKey, DSAPublicKey)
++
++DSA *DSAparams_dup(DSA *dsa)
++{
++    return ASN1_item_dup(ASN1_ITEM_rptr(DSAparams), dsa);
++}
++
++int DSA_sign(int type, const unsigned char *dgst, int dlen,
++             unsigned char *sig, unsigned int *siglen, DSA *dsa)
++{
++    DSA_SIG *s;
++    RAND_seed(dgst, dlen);
++    s = DSA_do_sign(dgst, dlen, dsa);
++    if (s == NULL) {
++        *siglen = 0;
++        return (0);
++    }
++    *siglen = i2d_DSA_SIG(s, &sig);
++    DSA_SIG_free(s);
++    return (1);
++}
++
++/* data has already been hashed (probably with SHA or SHA-1). */
++/*-
++ * returns
++ *      1: correct signature
++ *      0: incorrect signature
++ *     -1: error
++ */
++int DSA_verify(int type, const unsigned char *dgst, int dgst_len,
++               const unsigned char *sigbuf, int siglen, DSA *dsa)
++{
++    DSA_SIG *s;
++    const unsigned char *p = sigbuf;
++    unsigned char *der = NULL;
++    int derlen = -1;
++    int ret = -1;
++
++    s = DSA_SIG_new();
++    if (s == NULL)
++        return (ret);
++    if (d2i_DSA_SIG(&s, &p, siglen) == NULL)
++        goto err;
++    /* Ensure signature uses DER and doesn't have trailing garbage */
++    derlen = i2d_DSA_SIG(s, &der);
++    if (derlen != siglen || memcmp(sigbuf, der, derlen))
++        goto err;
++    ret = DSA_do_verify(dgst, dgst_len, s, dsa);
++ err:
++    OPENSSL_clear_free(der, derlen);
++    DSA_SIG_free(s);
++    return (ret);
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/dsa/dsa_depr.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/dsa/dsa_depr.c
+new file mode 100644
+index 0000000..f51aea7
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/dsa/dsa_depr.c
+@@ -0,0 +1,62 @@
++/*
++ * Copyright 2002-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++/*
++ * This file contains deprecated function(s) that are now wrappers to the new
++ * version(s).
++ */
++
++/*
++ * Parameter generation follows the updated Appendix 2.2 for FIPS PUB 186,
++ * also Appendix 2.2 of FIPS PUB 186-1 (i.e. use SHA as defined in FIPS PUB
++ * 180-1)
++ */
++#define xxxHASH    EVP_sha1()
++
++#include 
++#if OPENSSL_API_COMPAT >= 0x00908000L
++NON_EMPTY_TRANSLATION_UNIT
++#else
++
++# include 
++# include 
++# include "internal/cryptlib.h"
++# include 
++# include 
++# include 
++# include 
++
++DSA *DSA_generate_parameters(int bits,
++                             unsigned char *seed_in, int seed_len,
++                             int *counter_ret, unsigned long *h_ret,
++                             void (*callback) (int, int, void *),
++                             void *cb_arg)
++{
++    BN_GENCB *cb;
++    DSA *ret;
++
++    if ((ret = DSA_new()) == NULL)
++        return NULL;
++    cb = BN_GENCB_new();
++    if (cb == NULL)
++        goto err;
++
++    BN_GENCB_set_old(cb, callback, cb_arg);
++
++    if (DSA_generate_parameters_ex(ret, bits, seed_in, seed_len,
++                                   counter_ret, h_ret, cb)) {
++        BN_GENCB_free(cb);
++        return ret;
++    }
++    BN_GENCB_free(cb);
++err:
++    DSA_free(ret);
++    return NULL;
++}
++#endif
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/dsa/dsa_err.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/dsa/dsa_err.c
+new file mode 100644
+index 0000000..b8f0af4
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/dsa/dsa_err.c
+@@ -0,0 +1,76 @@
++/*
++ * Generated by util/mkerr.pl DO NOT EDIT
++ * Copyright 1995-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include 
++#include 
++
++/* BEGIN ERROR CODES */
++#ifndef OPENSSL_NO_ERR
++
++# define ERR_FUNC(func) ERR_PACK(ERR_LIB_DSA,func,0)
++# define ERR_REASON(reason) ERR_PACK(ERR_LIB_DSA,0,reason)
++
++static ERR_STRING_DATA DSA_str_functs[] = {
++    {ERR_FUNC(DSA_F_DSAPARAMS_PRINT), "DSAparams_print"},
++    {ERR_FUNC(DSA_F_DSAPARAMS_PRINT_FP), "DSAparams_print_fp"},
++    {ERR_FUNC(DSA_F_DSA_BUILTIN_PARAMGEN), "dsa_builtin_paramgen"},
++    {ERR_FUNC(DSA_F_DSA_BUILTIN_PARAMGEN2), "dsa_builtin_paramgen2"},
++    {ERR_FUNC(DSA_F_DSA_DO_SIGN), "DSA_do_sign"},
++    {ERR_FUNC(DSA_F_DSA_DO_VERIFY), "DSA_do_verify"},
++    {ERR_FUNC(DSA_F_DSA_METH_DUP), "DSA_meth_dup"},
++    {ERR_FUNC(DSA_F_DSA_METH_NEW), "DSA_meth_new"},
++    {ERR_FUNC(DSA_F_DSA_METH_SET1_NAME), "DSA_meth_set1_name"},
++    {ERR_FUNC(DSA_F_DSA_NEW_METHOD), "DSA_new_method"},
++    {ERR_FUNC(DSA_F_DSA_PARAM_DECODE), "dsa_param_decode"},
++    {ERR_FUNC(DSA_F_DSA_PRINT_FP), "DSA_print_fp"},
++    {ERR_FUNC(DSA_F_DSA_PRIV_DECODE), "dsa_priv_decode"},
++    {ERR_FUNC(DSA_F_DSA_PRIV_ENCODE), "dsa_priv_encode"},
++    {ERR_FUNC(DSA_F_DSA_PUB_DECODE), "dsa_pub_decode"},
++    {ERR_FUNC(DSA_F_DSA_PUB_ENCODE), "dsa_pub_encode"},
++    {ERR_FUNC(DSA_F_DSA_SIGN), "DSA_sign"},
++    {ERR_FUNC(DSA_F_DSA_SIGN_SETUP), "DSA_sign_setup"},
++    {ERR_FUNC(DSA_F_DSA_SIG_NEW), "DSA_SIG_new"},
++    {ERR_FUNC(DSA_F_OLD_DSA_PRIV_DECODE), "old_dsa_priv_decode"},
++    {ERR_FUNC(DSA_F_PKEY_DSA_CTRL), "pkey_dsa_ctrl"},
++    {ERR_FUNC(DSA_F_PKEY_DSA_KEYGEN), "pkey_dsa_keygen"},
++    {0, NULL}
++};
++
++static ERR_STRING_DATA DSA_str_reasons[] = {
++    {ERR_REASON(DSA_R_BAD_Q_VALUE), "bad q value"},
++    {ERR_REASON(DSA_R_BN_DECODE_ERROR), "bn decode error"},
++    {ERR_REASON(DSA_R_BN_ERROR), "bn error"},
++    {ERR_REASON(DSA_R_DECODE_ERROR), "decode error"},
++    {ERR_REASON(DSA_R_INVALID_DIGEST_TYPE), "invalid digest type"},
++    {ERR_REASON(DSA_R_INVALID_PARAMETERS), "invalid parameters"},
++    {ERR_REASON(DSA_R_MISSING_PARAMETERS), "missing parameters"},
++    {ERR_REASON(DSA_R_MODULUS_TOO_LARGE), "modulus too large"},
++    {ERR_REASON(DSA_R_NO_PARAMETERS_SET), "no parameters set"},
++    {ERR_REASON(DSA_R_PARAMETER_ENCODING_ERROR), "parameter encoding error"},
++    {ERR_REASON(DSA_R_Q_NOT_PRIME), "q not prime"},
++    {ERR_REASON(DSA_R_SEED_LEN_SMALL),
++     "seed_len is less than the length of q"},
++    {0, NULL}
++};
++
++#endif
++
++int ERR_load_DSA_strings(void)
++{
++#ifndef OPENSSL_NO_ERR
++
++    if (ERR_func_error_string(DSA_str_functs[0].error) == NULL) {
++        ERR_load_strings(0, DSA_str_functs);
++        ERR_load_strings(0, DSA_str_reasons);
++    }
++#endif
++    return 1;
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/dsa/dsa_gen.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/dsa/dsa_gen.c
+new file mode 100644
+index 0000000..3efeab8
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/dsa/dsa_gen.c
+@@ -0,0 +1,601 @@
++/*
++ * Copyright 1995-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++/*
++ * Parameter generation follows the updated Appendix 2.2 for FIPS PUB 186,
++ * also Appendix 2.2 of FIPS PUB 186-1 (i.e. use SHA as defined in FIPS PUB
++ * 180-1)
++ */
++#define xxxHASH    EVP_sha1()
++
++#include 
++#include 
++#include "internal/cryptlib.h"
++#include 
++#include 
++#include 
++#include 
++#include "dsa_locl.h"
++
++int DSA_generate_parameters_ex(DSA *ret, int bits,
++                               const unsigned char *seed_in, int seed_len,
++                               int *counter_ret, unsigned long *h_ret,
++                               BN_GENCB *cb)
++{
++    if (ret->meth->dsa_paramgen)
++        return ret->meth->dsa_paramgen(ret, bits, seed_in, seed_len,
++                                       counter_ret, h_ret, cb);
++    else {
++        const EVP_MD *evpmd = bits >= 2048 ? EVP_sha256() : EVP_sha1();
++        size_t qbits = EVP_MD_size(evpmd) * 8;
++
++        return dsa_builtin_paramgen(ret, bits, qbits, evpmd,
++                                    seed_in, seed_len, NULL, counter_ret,
++                                    h_ret, cb);
++    }
++}
++
++int dsa_builtin_paramgen(DSA *ret, size_t bits, size_t qbits,
++                         const EVP_MD *evpmd, const unsigned char *seed_in,
++                         size_t seed_len, unsigned char *seed_out,
++                         int *counter_ret, unsigned long *h_ret, BN_GENCB *cb)
++{
++    int ok = 0;
++    unsigned char seed[SHA256_DIGEST_LENGTH];
++    unsigned char md[SHA256_DIGEST_LENGTH];
++    unsigned char buf[SHA256_DIGEST_LENGTH], buf2[SHA256_DIGEST_LENGTH];
++    BIGNUM *r0, *W, *X, *c, *test;
++    BIGNUM *g = NULL, *q = NULL, *p = NULL;
++    BN_MONT_CTX *mont = NULL;
++    int i, k, n = 0, m = 0, qsize = qbits >> 3;
++    int counter = 0;
++    int r = 0;
++    BN_CTX *ctx = NULL;
++    unsigned int h = 2;
++
++    if (qsize != SHA_DIGEST_LENGTH && qsize != SHA224_DIGEST_LENGTH &&
++        qsize != SHA256_DIGEST_LENGTH)
++        /* invalid q size */
++        return 0;
++
++    if (evpmd == NULL)
++        /* use SHA1 as default */
++        evpmd = EVP_sha1();
++
++    if (bits < 512)
++        bits = 512;
++
++    bits = (bits + 63) / 64 * 64;
++
++    if (seed_in != NULL) {
++        if (seed_len < (size_t)qsize) {
++            DSAerr(DSA_F_DSA_BUILTIN_PARAMGEN, DSA_R_SEED_LEN_SMALL);
++            return 0;
++        }
++        if (seed_len > (size_t)qsize) {
++            /* Only consume as much seed as is expected. */
++            seed_len = qsize;
++        }
++        memcpy(seed, seed_in, seed_len);
++    }
++
++    if ((mont = BN_MONT_CTX_new()) == NULL)
++        goto err;
++
++    if ((ctx = BN_CTX_new()) == NULL)
++        goto err;
++
++    BN_CTX_start(ctx);
++
++    r0 = BN_CTX_get(ctx);
++    g = BN_CTX_get(ctx);
++    W = BN_CTX_get(ctx);
++    q = BN_CTX_get(ctx);
++    X = BN_CTX_get(ctx);
++    c = BN_CTX_get(ctx);
++    p = BN_CTX_get(ctx);
++    test = BN_CTX_get(ctx);
++
++    if (test == NULL)
++        goto err;
++
++    if (!BN_lshift(test, BN_value_one(), bits - 1))
++        goto err;
++
++    for (;;) {
++        for (;;) {              /* find q */
++            int use_random_seed = (seed_in == NULL);
++
++            /* step 1 */
++            if (!BN_GENCB_call(cb, 0, m++))
++                goto err;
++
++            if (use_random_seed) {
++                if (RAND_bytes(seed, qsize) <= 0)
++                    goto err;
++            } else {
++                /* If we come back through, use random seed next time. */
++                seed_in = NULL;
++            }
++            memcpy(buf, seed, qsize);
++            memcpy(buf2, seed, qsize);
++            /* precompute "SEED + 1" for step 7: */
++            for (i = qsize - 1; i >= 0; i--) {
++                buf[i]++;
++                if (buf[i] != 0)
++                    break;
++            }
++
++            /* step 2 */
++            if (!EVP_Digest(seed, qsize, md, NULL, evpmd, NULL))
++                goto err;
++            if (!EVP_Digest(buf, qsize, buf2, NULL, evpmd, NULL))
++                goto err;
++            for (i = 0; i < qsize; i++)
++                md[i] ^= buf2[i];
++
++            /* step 3 */
++            md[0] |= 0x80;
++            md[qsize - 1] |= 0x01;
++            if (!BN_bin2bn(md, qsize, q))
++                goto err;
++
++            /* step 4 */
++            r = BN_is_prime_fasttest_ex(q, DSS_prime_checks, ctx,
++                                        use_random_seed, cb);
++            if (r > 0)
++                break;
++            if (r != 0)
++                goto err;
++
++            /* do a callback call */
++            /* step 5 */
++        }
++
++        if (!BN_GENCB_call(cb, 2, 0))
++            goto err;
++        if (!BN_GENCB_call(cb, 3, 0))
++            goto err;
++
++        /* step 6 */
++        counter = 0;
++        /* "offset = 2" */
++
++        n = (bits - 1) / 160;
++
++        for (;;) {
++            if ((counter != 0) && !BN_GENCB_call(cb, 0, counter))
++                goto err;
++
++            /* step 7 */
++            BN_zero(W);
++            /* now 'buf' contains "SEED + offset - 1" */
++            for (k = 0; k <= n; k++) {
++                /*
++                 * obtain "SEED + offset + k" by incrementing:
++                 */
++                for (i = qsize - 1; i >= 0; i--) {
++                    buf[i]++;
++                    if (buf[i] != 0)
++                        break;
++                }
++
++                if (!EVP_Digest(buf, qsize, md, NULL, evpmd, NULL))
++                    goto err;
++
++                /* step 8 */
++                if (!BN_bin2bn(md, qsize, r0))
++                    goto err;
++                if (!BN_lshift(r0, r0, (qsize << 3) * k))
++                    goto err;
++                if (!BN_add(W, W, r0))
++                    goto err;
++            }
++
++            /* more of step 8 */
++            if (!BN_mask_bits(W, bits - 1))
++                goto err;
++            if (!BN_copy(X, W))
++                goto err;
++            if (!BN_add(X, X, test))
++                goto err;
++
++            /* step 9 */
++            if (!BN_lshift1(r0, q))
++                goto err;
++            if (!BN_mod(c, X, r0, ctx))
++                goto err;
++            if (!BN_sub(r0, c, BN_value_one()))
++                goto err;
++            if (!BN_sub(p, X, r0))
++                goto err;
++
++            /* step 10 */
++            if (BN_cmp(p, test) >= 0) {
++                /* step 11 */
++                r = BN_is_prime_fasttest_ex(p, DSS_prime_checks, ctx, 1, cb);
++                if (r > 0)
++                    goto end;   /* found it */
++                if (r != 0)
++                    goto err;
++            }
++
++            /* step 13 */
++            counter++;
++            /* "offset = offset + n + 1" */
++
++            /* step 14 */
++            if (counter >= 4096)
++                break;
++        }
++    }
++ end:
++    if (!BN_GENCB_call(cb, 2, 1))
++        goto err;
++
++    /* We now need to generate g */
++    /* Set r0=(p-1)/q */
++    if (!BN_sub(test, p, BN_value_one()))
++        goto err;
++    if (!BN_div(r0, NULL, test, q, ctx))
++        goto err;
++
++    if (!BN_set_word(test, h))
++        goto err;
++    if (!BN_MONT_CTX_set(mont, p, ctx))
++        goto err;
++
++    for (;;) {
++        /* g=test^r0%p */
++        if (!BN_mod_exp_mont(g, test, r0, p, ctx, mont))
++            goto err;
++        if (!BN_is_one(g))
++            break;
++        if (!BN_add(test, test, BN_value_one()))
++            goto err;
++        h++;
++    }
++
++    if (!BN_GENCB_call(cb, 3, 1))
++        goto err;
++
++    ok = 1;
++ err:
++    if (ok) {
++        BN_free(ret->p);
++        BN_free(ret->q);
++        BN_free(ret->g);
++        ret->p = BN_dup(p);
++        ret->q = BN_dup(q);
++        ret->g = BN_dup(g);
++        if (ret->p == NULL || ret->q == NULL || ret->g == NULL) {
++            ok = 0;
++            goto err;
++        }
++        if (counter_ret != NULL)
++            *counter_ret = counter;
++        if (h_ret != NULL)
++            *h_ret = h;
++        if (seed_out)
++            memcpy(seed_out, seed, qsize);
++    }
++    if (ctx)
++        BN_CTX_end(ctx);
++    BN_CTX_free(ctx);
++    BN_MONT_CTX_free(mont);
++    return ok;
++}
++
++/*
++ * This is a parameter generation algorithm for the DSA2 algorithm as
++ * described in FIPS 186-3.
++ */
++
++int dsa_builtin_paramgen2(DSA *ret, size_t L, size_t N,
++                          const EVP_MD *evpmd, const unsigned char *seed_in,
++                          size_t seed_len, int idx, unsigned char *seed_out,
++                          int *counter_ret, unsigned long *h_ret,
++                          BN_GENCB *cb)
++{
++    int ok = -1;
++    unsigned char *seed = NULL, *seed_tmp = NULL;
++    unsigned char md[EVP_MAX_MD_SIZE];
++    int mdsize;
++    BIGNUM *r0, *W, *X, *c, *test;
++    BIGNUM *g = NULL, *q = NULL, *p = NULL;
++    BN_MONT_CTX *mont = NULL;
++    int i, k, n = 0, m = 0, qsize = N >> 3;
++    int counter = 0;
++    int r = 0;
++    BN_CTX *ctx = NULL;
++    EVP_MD_CTX *mctx = EVP_MD_CTX_new();
++    unsigned int h = 2;
++
++    if (mctx == NULL)
++        goto err;
++
++    if (evpmd == NULL) {
++        if (N == 160)
++            evpmd = EVP_sha1();
++        else if (N == 224)
++            evpmd = EVP_sha224();
++        else
++            evpmd = EVP_sha256();
++    }
++
++    mdsize = EVP_MD_size(evpmd);
++    /* If unverifiable g generation only don't need seed */
++    if (!ret->p || !ret->q || idx >= 0) {
++        if (seed_len == 0)
++            seed_len = mdsize;
++
++        seed = OPENSSL_malloc(seed_len);
++
++        if (seed_out)
++            seed_tmp = seed_out;
++        else
++            seed_tmp = OPENSSL_malloc(seed_len);
++
++        if (seed == NULL || seed_tmp == NULL)
++            goto err;
++
++        if (seed_in)
++            memcpy(seed, seed_in, seed_len);
++
++    }
++
++    if ((ctx = BN_CTX_new()) == NULL)
++        goto err;
++
++    if ((mont = BN_MONT_CTX_new()) == NULL)
++        goto err;
++
++    BN_CTX_start(ctx);
++    r0 = BN_CTX_get(ctx);
++    g = BN_CTX_get(ctx);
++    W = BN_CTX_get(ctx);
++    X = BN_CTX_get(ctx);
++    c = BN_CTX_get(ctx);
++    test = BN_CTX_get(ctx);
++    if (test == NULL)
++        goto err;
++
++    /* if p, q already supplied generate g only */
++    if (ret->p && ret->q) {
++        p = ret->p;
++        q = ret->q;
++        if (idx >= 0)
++            memcpy(seed_tmp, seed, seed_len);
++        goto g_only;
++    } else {
++        p = BN_CTX_get(ctx);
++        q = BN_CTX_get(ctx);
++    }
++
++    if (!BN_lshift(test, BN_value_one(), L - 1))
++        goto err;
++    for (;;) {
++        for (;;) {              /* find q */
++            unsigned char *pmd;
++            /* step 1 */
++            if (!BN_GENCB_call(cb, 0, m++))
++                goto err;
++
++            if (!seed_in) {
++                if (RAND_bytes(seed, seed_len) <= 0)
++                    goto err;
++            }
++            /* step 2 */
++            if (!EVP_Digest(seed, seed_len, md, NULL, evpmd, NULL))
++                goto err;
++            /* Take least significant bits of md */
++            if (mdsize > qsize)
++                pmd = md + mdsize - qsize;
++            else
++                pmd = md;
++
++            if (mdsize < qsize)
++                memset(md + mdsize, 0, qsize - mdsize);
++
++            /* step 3 */
++            pmd[0] |= 0x80;
++            pmd[qsize - 1] |= 0x01;
++            if (!BN_bin2bn(pmd, qsize, q))
++                goto err;
++
++            /* step 4 */
++            r = BN_is_prime_fasttest_ex(q, DSS_prime_checks, ctx,
++                                        seed_in ? 1 : 0, cb);
++            if (r > 0)
++                break;
++            if (r != 0)
++                goto err;
++            /* Provided seed didn't produce a prime: error */
++            if (seed_in) {
++                ok = 0;
++                DSAerr(DSA_F_DSA_BUILTIN_PARAMGEN2, DSA_R_Q_NOT_PRIME);
++                goto err;
++            }
++
++            /* do a callback call */
++            /* step 5 */
++        }
++        /* Copy seed to seed_out before we mess with it */
++        if (seed_out)
++            memcpy(seed_out, seed, seed_len);
++
++        if (!BN_GENCB_call(cb, 2, 0))
++            goto err;
++        if (!BN_GENCB_call(cb, 3, 0))
++            goto err;
++
++        /* step 6 */
++        counter = 0;
++        /* "offset = 1" */
++
++        n = (L - 1) / (mdsize << 3);
++
++        for (;;) {
++            if ((counter != 0) && !BN_GENCB_call(cb, 0, counter))
++                goto err;
++
++            /* step 7 */
++            BN_zero(W);
++            /* now 'buf' contains "SEED + offset - 1" */
++            for (k = 0; k <= n; k++) {
++                /*
++                 * obtain "SEED + offset + k" by incrementing:
++                 */
++                for (i = seed_len - 1; i >= 0; i--) {
++                    seed[i]++;
++                    if (seed[i] != 0)
++                        break;
++                }
++
++                if (!EVP_Digest(seed, seed_len, md, NULL, evpmd, NULL))
++                    goto err;
++
++                /* step 8 */
++                if (!BN_bin2bn(md, mdsize, r0))
++                    goto err;
++                if (!BN_lshift(r0, r0, (mdsize << 3) * k))
++                    goto err;
++                if (!BN_add(W, W, r0))
++                    goto err;
++            }
++
++            /* more of step 8 */
++            if (!BN_mask_bits(W, L - 1))
++                goto err;
++            if (!BN_copy(X, W))
++                goto err;
++            if (!BN_add(X, X, test))
++                goto err;
++
++            /* step 9 */
++            if (!BN_lshift1(r0, q))
++                goto err;
++            if (!BN_mod(c, X, r0, ctx))
++                goto err;
++            if (!BN_sub(r0, c, BN_value_one()))
++                goto err;
++            if (!BN_sub(p, X, r0))
++                goto err;
++
++            /* step 10 */
++            if (BN_cmp(p, test) >= 0) {
++                /* step 11 */
++                r = BN_is_prime_fasttest_ex(p, DSS_prime_checks, ctx, 1, cb);
++                if (r > 0)
++                    goto end;   /* found it */
++                if (r != 0)
++                    goto err;
++            }
++
++            /* step 13 */
++            counter++;
++            /* "offset = offset + n + 1" */
++
++            /* step 14 */
++            if (counter >= (int)(4 * L))
++                break;
++        }
++        if (seed_in) {
++            ok = 0;
++            DSAerr(DSA_F_DSA_BUILTIN_PARAMGEN2, DSA_R_INVALID_PARAMETERS);
++            goto err;
++        }
++    }
++ end:
++    if (!BN_GENCB_call(cb, 2, 1))
++        goto err;
++
++ g_only:
++
++    /* We now need to generate g */
++    /* Set r0=(p-1)/q */
++    if (!BN_sub(test, p, BN_value_one()))
++        goto err;
++    if (!BN_div(r0, NULL, test, q, ctx))
++        goto err;
++
++    if (idx < 0) {
++        if (!BN_set_word(test, h))
++            goto err;
++    } else
++        h = 1;
++    if (!BN_MONT_CTX_set(mont, p, ctx))
++        goto err;
++
++    for (;;) {
++        static const unsigned char ggen[4] = { 0x67, 0x67, 0x65, 0x6e };
++        if (idx >= 0) {
++            md[0] = idx & 0xff;
++            md[1] = (h >> 8) & 0xff;
++            md[2] = h & 0xff;
++            if (!EVP_DigestInit_ex(mctx, evpmd, NULL))
++                goto err;
++            if (!EVP_DigestUpdate(mctx, seed_tmp, seed_len))
++                goto err;
++            if (!EVP_DigestUpdate(mctx, ggen, sizeof(ggen)))
++                goto err;
++            if (!EVP_DigestUpdate(mctx, md, 3))
++                goto err;
++            if (!EVP_DigestFinal_ex(mctx, md, NULL))
++                goto err;
++            if (!BN_bin2bn(md, mdsize, test))
++                goto err;
++        }
++        /* g=test^r0%p */
++        if (!BN_mod_exp_mont(g, test, r0, p, ctx, mont))
++            goto err;
++        if (!BN_is_one(g))
++            break;
++        if (idx < 0 && !BN_add(test, test, BN_value_one()))
++            goto err;
++        h++;
++        if (idx >= 0 && h > 0xffff)
++            goto err;
++    }
++
++    if (!BN_GENCB_call(cb, 3, 1))
++        goto err;
++
++    ok = 1;
++ err:
++    if (ok == 1) {
++        if (p != ret->p) {
++            BN_free(ret->p);
++            ret->p = BN_dup(p);
++        }
++        if (q != ret->q) {
++            BN_free(ret->q);
++            ret->q = BN_dup(q);
++        }
++        BN_free(ret->g);
++        ret->g = BN_dup(g);
++        if (ret->p == NULL || ret->q == NULL || ret->g == NULL) {
++            ok = -1;
++            goto err;
++        }
++        if (counter_ret != NULL)
++            *counter_ret = counter;
++        if (h_ret != NULL)
++            *h_ret = h;
++    }
++    OPENSSL_free(seed);
++    if (seed_out != seed_tmp)
++        OPENSSL_free(seed_tmp);
++    if (ctx)
++        BN_CTX_end(ctx);
++    BN_CTX_free(ctx);
++    BN_MONT_CTX_free(mont);
++    EVP_MD_CTX_free(mctx);
++    return ok;
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/dsa/dsa_key.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/dsa/dsa_key.c
+new file mode 100644
+index 0000000..31442b1
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/dsa/dsa_key.c
+@@ -0,0 +1,77 @@
++/*
++ * Copyright 1995-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include 
++#include "internal/cryptlib.h"
++#include 
++#include "dsa_locl.h"
++
++static int dsa_builtin_keygen(DSA *dsa);
++
++int DSA_generate_key(DSA *dsa)
++{
++    if (dsa->meth->dsa_keygen)
++        return dsa->meth->dsa_keygen(dsa);
++    return dsa_builtin_keygen(dsa);
++}
++
++static int dsa_builtin_keygen(DSA *dsa)
++{
++    int ok = 0;
++    BN_CTX *ctx = NULL;
++    BIGNUM *pub_key = NULL, *priv_key = NULL;
++
++    if ((ctx = BN_CTX_new()) == NULL)
++        goto err;
++
++    if (dsa->priv_key == NULL) {
++        if ((priv_key = BN_secure_new()) == NULL)
++            goto err;
++    } else
++        priv_key = dsa->priv_key;
++
++    do
++        if (!BN_rand_range(priv_key, dsa->q))
++            goto err;
++    while (BN_is_zero(priv_key)) ;
++
++    if (dsa->pub_key == NULL) {
++        if ((pub_key = BN_new()) == NULL)
++            goto err;
++    } else
++        pub_key = dsa->pub_key;
++
++    {
++        BIGNUM *prk = BN_new();
++
++        if (prk == NULL)
++            goto err;
++        BN_with_flags(prk, priv_key, BN_FLG_CONSTTIME);
++
++        if (!BN_mod_exp(pub_key, dsa->g, prk, dsa->p, ctx)) {
++            BN_free(prk);
++            goto err;
++        }
++        /* We MUST free prk before any further use of priv_key */
++        BN_free(prk);
++    }
++
++    dsa->priv_key = priv_key;
++    dsa->pub_key = pub_key;
++    ok = 1;
++
++ err:
++    if (pub_key != dsa->pub_key)
++        BN_free(pub_key);
++    if (priv_key != dsa->priv_key)
++        BN_free(priv_key);
++    BN_CTX_free(ctx);
++    return (ok);
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/dsa/dsa_lib.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/dsa/dsa_lib.c
+new file mode 100644
+index 0000000..42324c7
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/dsa/dsa_lib.c
+@@ -0,0 +1,346 @@
++/*
++ * Copyright 1995-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++/* Original version from Steven Schoch  */
++
++#include 
++#include "internal/cryptlib.h"
++#include 
++#include "dsa_locl.h"
++#include 
++#include 
++#include 
++
++static const DSA_METHOD *default_DSA_method = NULL;
++
++void DSA_set_default_method(const DSA_METHOD *meth)
++{
++    default_DSA_method = meth;
++}
++
++const DSA_METHOD *DSA_get_default_method(void)
++{
++    if (!default_DSA_method)
++        default_DSA_method = DSA_OpenSSL();
++    return default_DSA_method;
++}
++
++DSA *DSA_new(void)
++{
++    return DSA_new_method(NULL);
++}
++
++int DSA_set_method(DSA *dsa, const DSA_METHOD *meth)
++{
++    /*
++     * NB: The caller is specifically setting a method, so it's not up to us
++     * to deal with which ENGINE it comes from.
++     */
++    const DSA_METHOD *mtmp;
++    mtmp = dsa->meth;
++    if (mtmp->finish)
++        mtmp->finish(dsa);
++#ifndef OPENSSL_NO_ENGINE
++    ENGINE_finish(dsa->engine);
++    dsa->engine = NULL;
++#endif
++    dsa->meth = meth;
++    if (meth->init)
++        meth->init(dsa);
++    return 1;
++}
++
++const DSA_METHOD *DSA_get_method(DSA *d)
++{
++    return d->meth;
++}
++
++DSA *DSA_new_method(ENGINE *engine)
++{
++    DSA *ret = OPENSSL_zalloc(sizeof(*ret));
++
++    if (ret == NULL) {
++        DSAerr(DSA_F_DSA_NEW_METHOD, ERR_R_MALLOC_FAILURE);
++        return NULL;
++    }
++
++    ret->references = 1;
++    ret->lock = CRYPTO_THREAD_lock_new();
++    if (ret->lock == NULL) {
++        DSAerr(DSA_F_DSA_NEW_METHOD, ERR_R_MALLOC_FAILURE);
++        OPENSSL_free(ret);
++        return NULL;
++    }
++
++    ret->meth = DSA_get_default_method();
++#ifndef OPENSSL_NO_ENGINE
++    ret->flags = ret->meth->flags & ~DSA_FLAG_NON_FIPS_ALLOW; /* early default init */
++    if (engine) {
++        if (!ENGINE_init(engine)) {
++            DSAerr(DSA_F_DSA_NEW_METHOD, ERR_R_ENGINE_LIB);
++            goto err;
++        }
++        ret->engine = engine;
++    } else
++        ret->engine = ENGINE_get_default_DSA();
++    if (ret->engine) {
++        ret->meth = ENGINE_get_DSA(ret->engine);
++        if (ret->meth == NULL) {
++            DSAerr(DSA_F_DSA_NEW_METHOD, ERR_R_ENGINE_LIB);
++            goto err;
++        }
++    }
++#endif
++
++    ret->flags = ret->meth->flags & ~DSA_FLAG_NON_FIPS_ALLOW;
++
++    if (!CRYPTO_new_ex_data(CRYPTO_EX_INDEX_DSA, ret, &ret->ex_data))
++        goto err;
++
++    if ((ret->meth->init != NULL) && !ret->meth->init(ret)) {
++        DSAerr(DSA_F_DSA_NEW_METHOD, ERR_R_INIT_FAIL);
++err:
++        DSA_free(ret);
++        ret = NULL;
++    }
++
++    return ret;
++}
++
++void DSA_free(DSA *r)
++{
++    int i;
++
++    if (r == NULL)
++        return;
++
++    CRYPTO_atomic_add(&r->references, -1, &i, r->lock);
++    REF_PRINT_COUNT("DSA", r);
++    if (i > 0)
++        return;
++    REF_ASSERT_ISNT(i < 0);
++
++    if (r->meth->finish)
++        r->meth->finish(r);
++#ifndef OPENSSL_NO_ENGINE
++    ENGINE_finish(r->engine);
++#endif
++
++    CRYPTO_free_ex_data(CRYPTO_EX_INDEX_DSA, r, &r->ex_data);
++
++    CRYPTO_THREAD_lock_free(r->lock);
++
++    BN_clear_free(r->p);
++    BN_clear_free(r->q);
++    BN_clear_free(r->g);
++    BN_clear_free(r->pub_key);
++    BN_clear_free(r->priv_key);
++    OPENSSL_free(r);
++}
++
++int DSA_up_ref(DSA *r)
++{
++    int i;
++
++    if (CRYPTO_atomic_add(&r->references, 1, &i, r->lock) <= 0)
++        return 0;
++
++    REF_PRINT_COUNT("DSA", r);
++    REF_ASSERT_ISNT(i < 2);
++    return ((i > 1) ? 1 : 0);
++}
++
++int DSA_size(const DSA *r)
++{
++    int ret, i;
++    ASN1_INTEGER bs;
++    unsigned char buf[4];       /* 4 bytes looks really small. However,
++                                 * i2d_ASN1_INTEGER() will not look beyond
++                                 * the first byte, as long as the second
++                                 * parameter is NULL. */
++
++    i = BN_num_bits(r->q);
++    bs.length = (i + 7) / 8;
++    bs.data = buf;
++    bs.type = V_ASN1_INTEGER;
++    /* If the top bit is set the asn1 encoding is 1 larger. */
++    buf[0] = 0xff;
++
++    i = i2d_ASN1_INTEGER(&bs, NULL);
++    i += i;                     /* r and s */
++    ret = ASN1_object_size(1, i, V_ASN1_SEQUENCE);
++    return (ret);
++}
++
++int DSA_set_ex_data(DSA *d, int idx, void *arg)
++{
++    return (CRYPTO_set_ex_data(&d->ex_data, idx, arg));
++}
++
++void *DSA_get_ex_data(DSA *d, int idx)
++{
++    return (CRYPTO_get_ex_data(&d->ex_data, idx));
++}
++
++int DSA_security_bits(const DSA *d)
++{
++    if (d->p && d->q)
++        return BN_security_bits(BN_num_bits(d->p), BN_num_bits(d->q));
++    return -1;
++}
++
++#ifndef OPENSSL_NO_DH
++DH *DSA_dup_DH(const DSA *r)
++{
++    /*
++     * DSA has p, q, g, optional pub_key, optional priv_key. DH has p,
++     * optional length, g, optional pub_key, optional priv_key, optional q.
++     */
++
++    DH *ret = NULL;
++    BIGNUM *p = NULL, *q = NULL, *g = NULL, *pub_key = NULL, *priv_key = NULL;
++
++    if (r == NULL)
++        goto err;
++    ret = DH_new();
++    if (ret == NULL)
++        goto err;
++    if (r->p != NULL || r->g != NULL || r->q != NULL) {
++        if (r->p == NULL || r->g == NULL || r->q == NULL) {
++            /* Shouldn't happen */
++            goto err;
++        }
++        p = BN_dup(r->p);
++        g = BN_dup(r->g);
++        q = BN_dup(r->q);
++        if (p == NULL || g == NULL || q == NULL || !DH_set0_pqg(ret, p, q, g))
++            goto err;
++        p = g = q = NULL;
++    }
++
++    if (r->pub_key != NULL) {
++        pub_key = BN_dup(r->pub_key);
++        if (pub_key == NULL)
++            goto err;
++        if (r->priv_key != NULL) {
++            priv_key = BN_dup(r->priv_key);
++            if (priv_key == NULL)
++                goto err;
++        }
++        if (!DH_set0_key(ret, pub_key, priv_key))
++            goto err;
++    } else if (r->priv_key != NULL) {
++        /* Shouldn't happen */
++        goto err;
++    }
++
++    return ret;
++
++ err:
++    BN_free(p);
++    BN_free(g);
++    BN_free(q);
++    BN_free(pub_key);
++    BN_free(priv_key);
++    DH_free(ret);
++    return NULL;
++}
++#endif
++
++void DSA_get0_pqg(const DSA *d,
++                  const BIGNUM **p, const BIGNUM **q, const BIGNUM **g)
++{
++    if (p != NULL)
++        *p = d->p;
++    if (q != NULL)
++        *q = d->q;
++    if (g != NULL)
++        *g = d->g;
++}
++
++int DSA_set0_pqg(DSA *d, BIGNUM *p, BIGNUM *q, BIGNUM *g)
++{
++    /* If the fields p, q and g in d are NULL, the corresponding input
++     * parameters MUST be non-NULL.
++     */
++    if ((d->p == NULL && p == NULL)
++        || (d->q == NULL && q == NULL)
++        || (d->g == NULL && g == NULL))
++        return 0;
++
++    if (p != NULL) {
++        BN_free(d->p);
++        d->p = p;
++    }
++    if (q != NULL) {
++        BN_free(d->q);
++        d->q = q;
++    }
++    if (g != NULL) {
++        BN_free(d->g);
++        d->g = g;
++    }
++
++    return 1;
++}
++
++void DSA_get0_key(const DSA *d,
++                  const BIGNUM **pub_key, const BIGNUM **priv_key)
++{
++    if (pub_key != NULL)
++        *pub_key = d->pub_key;
++    if (priv_key != NULL)
++        *priv_key = d->priv_key;
++}
++
++int DSA_set0_key(DSA *d, BIGNUM *pub_key, BIGNUM *priv_key)
++{
++    /* If the field pub_key in d is NULL, the corresponding input
++     * parameters MUST be non-NULL.  The priv_key field may
++     * be left NULL.
++     */
++    if (d->pub_key == NULL && pub_key == NULL)
++        return 0;
++
++    if (pub_key != NULL) {
++        BN_free(d->pub_key);
++        d->pub_key = pub_key;
++    }
++    if (priv_key != NULL) {
++        BN_free(d->priv_key);
++        d->priv_key = priv_key;
++    }
++
++    return 1;
++}
++
++void DSA_clear_flags(DSA *d, int flags)
++{
++    d->flags &= ~flags;
++}
++
++int DSA_test_flags(const DSA *d, int flags)
++{
++    return d->flags & flags;
++}
++
++void DSA_set_flags(DSA *d, int flags)
++{
++    d->flags |= flags;
++}
++
++ENGINE *DSA_get0_engine(DSA *d)
++{
++    return d->engine;
++}
++
++int DSA_bits(const DSA *dsa)
++{
++    return BN_num_bits(dsa->p);
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/dsa/dsa_locl.h b/CryptoPkg/Library/OpensslLib/openssl/crypto/dsa/dsa_locl.h
+new file mode 100644
+index 0000000..9021fce
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/dsa/dsa_locl.h
+@@ -0,0 +1,76 @@
++/*
++ * Copyright 2007-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++
++struct dsa_st {
++    /*
++     * This first variable is used to pick up errors where a DSA is passed
++     * instead of of a EVP_PKEY
++     */
++    int pad;
++    long version;
++    BIGNUM *p;
++    BIGNUM *q;                  /* == 20 */
++    BIGNUM *g;
++    BIGNUM *pub_key;            /* y public key */
++    BIGNUM *priv_key;           /* x private key */
++    int flags;
++    /* Normally used to cache montgomery values */
++    BN_MONT_CTX *method_mont_p;
++    int references;
++    CRYPTO_EX_DATA ex_data;
++    const DSA_METHOD *meth;
++    /* functional reference if 'meth' is ENGINE-provided */
++    ENGINE *engine;
++    CRYPTO_RWLOCK *lock;
++};
++
++struct DSA_SIG_st {
++    BIGNUM *r;
++    BIGNUM *s;
++};
++
++struct dsa_method {
++    char *name;
++    DSA_SIG *(*dsa_do_sign) (const unsigned char *dgst, int dlen, DSA *dsa);
++    int (*dsa_sign_setup) (DSA *dsa, BN_CTX *ctx_in, BIGNUM **kinvp,
++                           BIGNUM **rp);
++    int (*dsa_do_verify) (const unsigned char *dgst, int dgst_len,
++                          DSA_SIG *sig, DSA *dsa);
++    int (*dsa_mod_exp) (DSA *dsa, BIGNUM *rr, const BIGNUM *a1,
++                        const BIGNUM *p1, const BIGNUM *a2, const BIGNUM *p2,
++                        const BIGNUM *m, BN_CTX *ctx, BN_MONT_CTX *in_mont);
++    /* Can be null */
++    int (*bn_mod_exp) (DSA *dsa, BIGNUM *r, const BIGNUM *a, const BIGNUM *p,
++                       const BIGNUM *m, BN_CTX *ctx, BN_MONT_CTX *m_ctx);
++    int (*init) (DSA *dsa);
++    int (*finish) (DSA *dsa);
++    int flags;
++    void *app_data;
++    /* If this is non-NULL, it is used to generate DSA parameters */
++    int (*dsa_paramgen) (DSA *dsa, int bits,
++                         const unsigned char *seed, int seed_len,
++                         int *counter_ret, unsigned long *h_ret,
++                         BN_GENCB *cb);
++    /* If this is non-NULL, it is used to generate DSA keys */
++    int (*dsa_keygen) (DSA *dsa);
++};
++
++int dsa_builtin_paramgen(DSA *ret, size_t bits, size_t qbits,
++                         const EVP_MD *evpmd, const unsigned char *seed_in,
++                         size_t seed_len, unsigned char *seed_out,
++                         int *counter_ret, unsigned long *h_ret,
++                         BN_GENCB *cb);
++
++int dsa_builtin_paramgen2(DSA *ret, size_t L, size_t N,
++                          const EVP_MD *evpmd, const unsigned char *seed_in,
++                          size_t seed_len, int idx, unsigned char *seed_out,
++                          int *counter_ret, unsigned long *h_ret,
++                          BN_GENCB *cb);
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/dsa/dsa_meth.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/dsa/dsa_meth.c
+new file mode 100644
+index 0000000..f0188f2
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/dsa/dsa_meth.c
+@@ -0,0 +1,224 @@
++/*
++ * Copyright 2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++/*
++ * Licensed under the OpenSSL licenses, (the "License");
++ * you may not use this file except in compliance with the License.
++ * You may obtain a copy of the License at
++ * https://www.openssl.org/source/license.html
++ * or in the file LICENSE in the source distribution.
++ */
++
++#include "dsa_locl.h"
++#include 
++#include 
++
++DSA_METHOD *DSA_meth_new(const char *name, int flags)
++{
++    DSA_METHOD *dsam = OPENSSL_zalloc(sizeof(*dsam));
++
++    if (dsam != NULL) {
++        dsam->flags = flags;
++
++        dsam->name = OPENSSL_strdup(name);
++        if (dsam->name != NULL)
++            return dsam;
++
++        OPENSSL_free(dsam);
++    }
++
++    DSAerr(DSA_F_DSA_METH_NEW, ERR_R_MALLOC_FAILURE);
++    return NULL;
++}
++
++void DSA_meth_free(DSA_METHOD *dsam)
++{
++    if (dsam != NULL) {
++        OPENSSL_free(dsam->name);
++        OPENSSL_free(dsam);
++    }
++}
++
++DSA_METHOD *DSA_meth_dup(const DSA_METHOD *dsam)
++{
++    DSA_METHOD *ret = OPENSSL_malloc(sizeof(*ret));
++
++    if (ret != NULL) {
++        memcpy(ret, dsam, sizeof(*dsam));
++
++        ret->name = OPENSSL_strdup(dsam->name);
++        if (ret->name != NULL)
++            return ret;
++
++        OPENSSL_free(ret);
++    }
++
++    DSAerr(DSA_F_DSA_METH_DUP, ERR_R_MALLOC_FAILURE);
++    return NULL;
++}
++
++const char *DSA_meth_get0_name(const DSA_METHOD *dsam)
++{
++    return dsam->name;
++}
++
++int DSA_meth_set1_name(DSA_METHOD *dsam, const char *name)
++{
++    char *tmpname = OPENSSL_strdup(name);
++
++    if (tmpname == NULL) {
++        DSAerr(DSA_F_DSA_METH_SET1_NAME, ERR_R_MALLOC_FAILURE);
++        return 0;
++    }
++
++    OPENSSL_free(dsam->name);
++    dsam->name = tmpname;
++
++    return 1;
++}
++
++int DSA_meth_get_flags(DSA_METHOD *dsam)
++{
++    return dsam->flags;
++}
++
++int DSA_meth_set_flags(DSA_METHOD *dsam, int flags)
++{
++    dsam->flags = flags;
++    return 1;
++}
++
++void *DSA_meth_get0_app_data(const DSA_METHOD *dsam)
++{
++    return dsam->app_data;
++}
++
++int DSA_meth_set0_app_data(DSA_METHOD *dsam, void *app_data)
++{
++    dsam->app_data = app_data;
++    return 1;
++}
++
++DSA_SIG *(*DSA_meth_get_sign(const DSA_METHOD *dsam))
++        (const unsigned char *, int, DSA *)
++{
++    return dsam->dsa_do_sign;
++}
++
++int DSA_meth_set_sign(DSA_METHOD *dsam,
++                       DSA_SIG *(*sign) (const unsigned char *, int, DSA *))
++{
++    dsam->dsa_do_sign = sign;
++    return 1;
++}
++
++int (*DSA_meth_get_sign_setup(const DSA_METHOD *dsam))
++        (DSA *, BN_CTX *, BIGNUM **, BIGNUM **)
++{
++    return dsam->dsa_sign_setup;
++}
++
++int DSA_meth_set_sign_setup(DSA_METHOD *dsam,
++        int (*sign_setup) (DSA *, BN_CTX *, BIGNUM **, BIGNUM **))
++{
++    dsam->dsa_sign_setup = sign_setup;
++    return 1;
++}
++
++int (*DSA_meth_get_verify(const DSA_METHOD *dsam))
++        (const unsigned char *, int , DSA_SIG *, DSA *)
++{
++    return dsam->dsa_do_verify;
++}
++
++int DSA_meth_set_verify(DSA_METHOD *dsam,
++    int (*verify) (const unsigned char *, int, DSA_SIG *, DSA *))
++{
++    dsam->dsa_do_verify = verify;
++    return 1;
++}
++
++int (*DSA_meth_get_mod_exp(const DSA_METHOD *dsam))
++        (DSA *, BIGNUM *, const BIGNUM *, const BIGNUM *, const BIGNUM *,
++         const BIGNUM *, const BIGNUM *, BN_CTX *, BN_MONT_CTX *)
++{
++    return dsam->dsa_mod_exp;
++}
++
++int DSA_meth_set_mod_exp(DSA_METHOD *dsam,
++    int (*mod_exp) (DSA *, BIGNUM *, const BIGNUM *, const BIGNUM *,
++                    const BIGNUM *, const BIGNUM *, const BIGNUM *, BN_CTX *,
++                    BN_MONT_CTX *))
++{
++    dsam->dsa_mod_exp = mod_exp;
++    return 1;
++}
++
++int (*DSA_meth_get_bn_mod_exp(const DSA_METHOD *dsam))
++    (DSA *, BIGNUM *, const BIGNUM *, const BIGNUM *, const BIGNUM *, BN_CTX *,
++     BN_MONT_CTX *)
++{
++    return dsam->bn_mod_exp;
++}
++
++int DSA_meth_set_bn_mod_exp(DSA_METHOD *dsam,
++    int (*bn_mod_exp) (DSA *, BIGNUM *, const BIGNUM *, const BIGNUM *,
++                       const BIGNUM *, BN_CTX *, BN_MONT_CTX *))
++{
++    dsam->bn_mod_exp = bn_mod_exp;
++    return 1;
++}
++
++int (*DSA_meth_get_init(const DSA_METHOD *dsam))(DSA *)
++{
++    return dsam->init;
++}
++
++int DSA_meth_set_init(DSA_METHOD *dsam, int (*init)(DSA *))
++{
++    dsam->init = init;
++    return 1;
++}
++
++int (*DSA_meth_get_finish(const DSA_METHOD *dsam)) (DSA *)
++{
++    return dsam->finish;
++}
++
++int DSA_meth_set_finish(DSA_METHOD *dsam, int (*finish) (DSA *))
++{
++    dsam->finish = finish;
++    return 1;
++}
++
++int (*DSA_meth_get_paramgen(const DSA_METHOD *dsam))
++        (DSA *, int, const unsigned char *, int, int *, unsigned long *,
++         BN_GENCB *)
++{
++    return dsam->dsa_paramgen;
++}
++
++int DSA_meth_set_paramgen(DSA_METHOD *dsam,
++        int (*paramgen) (DSA *, int, const unsigned char *, int, int *,
++                         unsigned long *, BN_GENCB *))
++{
++    dsam->dsa_paramgen = paramgen;
++    return 1;
++}
++
++int (*DSA_meth_get_keygen(const DSA_METHOD *dsam)) (DSA *)
++{
++    return dsam->dsa_keygen;
++}
++
++int DSA_meth_set_keygen(DSA_METHOD *dsam, int (*keygen) (DSA *))
++{
++    dsam->dsa_keygen = keygen;
++    return 1;
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/dsa/dsa_ossl.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/dsa/dsa_ossl.c
+new file mode 100644
+index 0000000..f9f6a13
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/dsa/dsa_ossl.c
+@@ -0,0 +1,338 @@
++/*
++ * Copyright 1995-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++/* Original version from Steven Schoch  */
++
++#include 
++#include "internal/cryptlib.h"
++#include 
++#include 
++#include "dsa_locl.h"
++#include 
++
++static DSA_SIG *dsa_do_sign(const unsigned char *dgst, int dlen, DSA *dsa);
++static int dsa_sign_setup_no_digest(DSA *dsa, BN_CTX *ctx_in, BIGNUM **kinvp,
++                                    BIGNUM **rp);
++static int dsa_sign_setup(DSA *dsa, BN_CTX *ctx_in, BIGNUM **kinvp,
++                          BIGNUM **rp, const unsigned char *dgst, int dlen);
++static int dsa_do_verify(const unsigned char *dgst, int dgst_len,
++                         DSA_SIG *sig, DSA *dsa);
++static int dsa_init(DSA *dsa);
++static int dsa_finish(DSA *dsa);
++
++static DSA_METHOD openssl_dsa_meth = {
++    "OpenSSL DSA method",
++    dsa_do_sign,
++    dsa_sign_setup_no_digest,
++    dsa_do_verify,
++    NULL,                       /* dsa_mod_exp, */
++    NULL,                       /* dsa_bn_mod_exp, */
++    dsa_init,
++    dsa_finish,
++    DSA_FLAG_FIPS_METHOD,
++    NULL,
++    NULL,
++    NULL
++};
++
++const DSA_METHOD *DSA_OpenSSL(void)
++{
++    return &openssl_dsa_meth;
++}
++
++static DSA_SIG *dsa_do_sign(const unsigned char *dgst, int dlen, DSA *dsa)
++{
++    BIGNUM *kinv = NULL;
++    BIGNUM *m;
++    BIGNUM *xr;
++    BN_CTX *ctx = NULL;
++    int reason = ERR_R_BN_LIB;
++    DSA_SIG *ret = NULL;
++    int rv = 0;
++
++    m = BN_new();
++    xr = BN_new();
++    if (m == NULL || xr == NULL)
++        goto err;
++
++    if (!dsa->p || !dsa->q || !dsa->g) {
++        reason = DSA_R_MISSING_PARAMETERS;
++        goto err;
++    }
++
++    ret = DSA_SIG_new();
++    if (ret == NULL)
++        goto err;
++    ret->r = BN_new();
++    ret->s = BN_new();
++    if (ret->r == NULL || ret->s == NULL)
++        goto err;
++
++    ctx = BN_CTX_new();
++    if (ctx == NULL)
++        goto err;
++ redo:
++    if (!dsa_sign_setup(dsa, ctx, &kinv, &ret->r, dgst, dlen))
++        goto err;
++
++    if (dlen > BN_num_bytes(dsa->q))
++        /*
++         * if the digest length is greater than the size of q use the
++         * BN_num_bits(dsa->q) leftmost bits of the digest, see fips 186-3,
++         * 4.2
++         */
++        dlen = BN_num_bytes(dsa->q);
++    if (BN_bin2bn(dgst, dlen, m) == NULL)
++        goto err;
++
++    /* Compute  s = inv(k) (m + xr) mod q */
++    if (!BN_mod_mul(xr, dsa->priv_key, ret->r, dsa->q, ctx))
++        goto err;               /* s = xr */
++    if (!BN_add(ret->s, xr, m))
++        goto err;               /* s = m + xr */
++    if (BN_cmp(ret->s, dsa->q) > 0)
++        if (!BN_sub(ret->s, ret->s, dsa->q))
++            goto err;
++    if (!BN_mod_mul(ret->s, ret->s, kinv, dsa->q, ctx))
++        goto err;
++
++    /*
++     * Redo if r or s is zero as required by FIPS 186-3: this is very
++     * unlikely.
++     */
++    if (BN_is_zero(ret->r) || BN_is_zero(ret->s))
++        goto redo;
++
++    rv = 1;
++
++ err:
++    if (rv == 0) {
++        DSAerr(DSA_F_DSA_DO_SIGN, reason);
++        DSA_SIG_free(ret);
++        ret = NULL;
++    }
++    BN_CTX_free(ctx);
++    BN_clear_free(m);
++    BN_clear_free(xr);
++    BN_clear_free(kinv);
++    return ret;
++}
++
++static int dsa_sign_setup_no_digest(DSA *dsa, BN_CTX *ctx_in,
++                                    BIGNUM **kinvp, BIGNUM **rp)
++{
++    return dsa_sign_setup(dsa, ctx_in, kinvp, rp, NULL, 0);
++}
++
++static int dsa_sign_setup(DSA *dsa, BN_CTX *ctx_in,
++                          BIGNUM **kinvp, BIGNUM **rp,
++                          const unsigned char *dgst, int dlen)
++{
++    BN_CTX *ctx = NULL;
++    BIGNUM *k, *kinv = NULL, *r = *rp;
++    int ret = 0;
++
++    if (!dsa->p || !dsa->q || !dsa->g) {
++        DSAerr(DSA_F_DSA_SIGN_SETUP, DSA_R_MISSING_PARAMETERS);
++        return 0;
++    }
++
++    k = BN_new();
++    if (k == NULL)
++        goto err;
++
++    if (ctx_in == NULL) {
++        if ((ctx = BN_CTX_new()) == NULL)
++            goto err;
++    } else
++        ctx = ctx_in;
++
++    /* Get random k */
++    do {
++        if (dgst != NULL) {
++            /*
++             * We calculate k from SHA512(private_key + H(message) + random).
++             * This protects the private key from a weak PRNG.
++             */
++            if (!BN_generate_dsa_nonce(k, dsa->q, dsa->priv_key, dgst,
++                                       dlen, ctx))
++                goto err;
++        } else if (!BN_rand_range(k, dsa->q))
++            goto err;
++    } while (BN_is_zero(k));
++
++    BN_set_flags(k, BN_FLG_CONSTTIME);
++
++    if (dsa->flags & DSA_FLAG_CACHE_MONT_P) {
++        if (!BN_MONT_CTX_set_locked(&dsa->method_mont_p,
++                                    dsa->lock, dsa->p, ctx))
++            goto err;
++    }
++
++    /* Compute r = (g^k mod p) mod q */
++
++    /*
++     * We do not want timing information to leak the length of k, so we
++     * compute g^k using an equivalent exponent of fixed length. (This
++     * is a kludge that we need because the BN_mod_exp_mont() does not
++     * let us specify the desired timing behaviour.)
++     */
++
++    if (!BN_add(k, k, dsa->q))
++        goto err;
++    if (BN_num_bits(k) <= BN_num_bits(dsa->q)) {
++        if (!BN_add(k, k, dsa->q))
++            goto err;
++    }
++
++    if ((dsa)->meth->bn_mod_exp != NULL) {
++            if (!dsa->meth->bn_mod_exp(dsa, r, dsa->g, k, dsa->p, ctx,
++                                       dsa->method_mont_p))
++                goto err;
++    } else {
++            if (!BN_mod_exp_mont(r, dsa->g, k, dsa->p, ctx, dsa->method_mont_p))
++                goto err;
++    }
++
++    if (!BN_mod(r, r, dsa->q, ctx))
++        goto err;
++
++    /* Compute  part of 's = inv(k) (m + xr) mod q' */
++    if ((kinv = BN_mod_inverse(NULL, k, dsa->q, ctx)) == NULL)
++        goto err;
++
++    BN_clear_free(*kinvp);
++    *kinvp = kinv;
++    kinv = NULL;
++    ret = 1;
++ err:
++    if (!ret)
++        DSAerr(DSA_F_DSA_SIGN_SETUP, ERR_R_BN_LIB);
++    if (ctx != ctx_in)
++        BN_CTX_free(ctx);
++    BN_clear_free(k);
++    return ret;
++}
++
++static int dsa_do_verify(const unsigned char *dgst, int dgst_len,
++                         DSA_SIG *sig, DSA *dsa)
++{
++    BN_CTX *ctx;
++    BIGNUM *u1, *u2, *t1;
++    BN_MONT_CTX *mont = NULL;
++    const BIGNUM *r, *s;
++    int ret = -1, i;
++    if (!dsa->p || !dsa->q || !dsa->g) {
++        DSAerr(DSA_F_DSA_DO_VERIFY, DSA_R_MISSING_PARAMETERS);
++        return -1;
++    }
++
++    i = BN_num_bits(dsa->q);
++    /* fips 186-3 allows only different sizes for q */
++    if (i != 160 && i != 224 && i != 256) {
++        DSAerr(DSA_F_DSA_DO_VERIFY, DSA_R_BAD_Q_VALUE);
++        return -1;
++    }
++
++    if (BN_num_bits(dsa->p) > OPENSSL_DSA_MAX_MODULUS_BITS) {
++        DSAerr(DSA_F_DSA_DO_VERIFY, DSA_R_MODULUS_TOO_LARGE);
++        return -1;
++    }
++    u1 = BN_new();
++    u2 = BN_new();
++    t1 = BN_new();
++    ctx = BN_CTX_new();
++    if (u1 == NULL || u2 == NULL || t1 == NULL || ctx == NULL)
++        goto err;
++
++    DSA_SIG_get0(sig, &r, &s);
++
++    if (BN_is_zero(r) || BN_is_negative(r) ||
++        BN_ucmp(r, dsa->q) >= 0) {
++        ret = 0;
++        goto err;
++    }
++    if (BN_is_zero(s) || BN_is_negative(s) ||
++        BN_ucmp(s, dsa->q) >= 0) {
++        ret = 0;
++        goto err;
++    }
++
++    /*
++     * Calculate W = inv(S) mod Q save W in u2
++     */
++    if ((BN_mod_inverse(u2, s, dsa->q, ctx)) == NULL)
++        goto err;
++
++    /* save M in u1 */
++    if (dgst_len > (i >> 3))
++        /*
++         * if the digest length is greater than the size of q use the
++         * BN_num_bits(dsa->q) leftmost bits of the digest, see fips 186-3,
++         * 4.2
++         */
++        dgst_len = (i >> 3);
++    if (BN_bin2bn(dgst, dgst_len, u1) == NULL)
++        goto err;
++
++    /* u1 = M * w mod q */
++    if (!BN_mod_mul(u1, u1, u2, dsa->q, ctx))
++        goto err;
++
++    /* u2 = r * w mod q */
++    if (!BN_mod_mul(u2, r, u2, dsa->q, ctx))
++        goto err;
++
++    if (dsa->flags & DSA_FLAG_CACHE_MONT_P) {
++        mont = BN_MONT_CTX_set_locked(&dsa->method_mont_p,
++                                      dsa->lock, dsa->p, ctx);
++        if (!mont)
++            goto err;
++    }
++
++    if (dsa->meth->dsa_mod_exp != NULL) {
++        if (!dsa->meth->dsa_mod_exp(dsa, t1, dsa->g, u1, dsa->pub_key, u2,
++                                    dsa->p, ctx, mont))
++            goto err;
++    } else {
++        if (!BN_mod_exp2_mont(t1, dsa->g, u1, dsa->pub_key, u2, dsa->p, ctx,
++                              mont))
++            goto err;
++    }
++
++    /* let u1 = u1 mod q */
++    if (!BN_mod(u1, t1, dsa->q, ctx))
++        goto err;
++
++    /*
++     * V is now in u1.  If the signature is correct, it will be equal to R.
++     */
++    ret = (BN_ucmp(u1, r) == 0);
++
++ err:
++    if (ret < 0)
++        DSAerr(DSA_F_DSA_DO_VERIFY, ERR_R_BN_LIB);
++    BN_CTX_free(ctx);
++    BN_free(u1);
++    BN_free(u2);
++    BN_free(t1);
++    return (ret);
++}
++
++static int dsa_init(DSA *dsa)
++{
++    dsa->flags |= DSA_FLAG_CACHE_MONT_P;
++    return (1);
++}
++
++static int dsa_finish(DSA *dsa)
++{
++    BN_MONT_CTX_free(dsa->method_mont_p);
++    return (1);
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/dsa/dsa_pmeth.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/dsa/dsa_pmeth.c
+new file mode 100644
+index 0000000..95f088a
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/dsa/dsa_pmeth.c
+@@ -0,0 +1,273 @@
++/*
++ * Copyright 2006-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include "internal/cryptlib.h"
++#include 
++#include 
++#include 
++#include 
++#include "internal/evp_int.h"
++#include "dsa_locl.h"
++
++/* DSA pkey context structure */
++
++typedef struct {
++    /* Parameter gen parameters */
++    int nbits;                  /* size of p in bits (default: 1024) */
++    int qbits;                  /* size of q in bits (default: 160) */
++    const EVP_MD *pmd;          /* MD for parameter generation */
++    /* Keygen callback info */
++    int gentmp[2];
++    /* message digest */
++    const EVP_MD *md;           /* MD for the signature */
++} DSA_PKEY_CTX;
++
++static int pkey_dsa_init(EVP_PKEY_CTX *ctx)
++{
++    DSA_PKEY_CTX *dctx;
++    dctx = OPENSSL_malloc(sizeof(*dctx));
++    if (dctx == NULL)
++        return 0;
++    dctx->nbits = 1024;
++    dctx->qbits = 160;
++    dctx->pmd = NULL;
++    dctx->md = NULL;
++
++    ctx->data = dctx;
++    ctx->keygen_info = dctx->gentmp;
++    ctx->keygen_info_count = 2;
++
++    return 1;
++}
++
++static int pkey_dsa_copy(EVP_PKEY_CTX *dst, EVP_PKEY_CTX *src)
++{
++    DSA_PKEY_CTX *dctx, *sctx;
++    if (!pkey_dsa_init(dst))
++        return 0;
++    sctx = src->data;
++    dctx = dst->data;
++    dctx->nbits = sctx->nbits;
++    dctx->qbits = sctx->qbits;
++    dctx->pmd = sctx->pmd;
++    dctx->md = sctx->md;
++    return 1;
++}
++
++static void pkey_dsa_cleanup(EVP_PKEY_CTX *ctx)
++{
++    DSA_PKEY_CTX *dctx = ctx->data;
++    OPENSSL_free(dctx);
++}
++
++static int pkey_dsa_sign(EVP_PKEY_CTX *ctx, unsigned char *sig,
++                         size_t *siglen, const unsigned char *tbs,
++                         size_t tbslen)
++{
++    int ret;
++    unsigned int sltmp;
++    DSA_PKEY_CTX *dctx = ctx->data;
++    DSA *dsa = ctx->pkey->pkey.dsa;
++
++    if (dctx->md) {
++        if (tbslen != (size_t)EVP_MD_size(dctx->md))
++            return 0;
++    } else {
++        if (tbslen != SHA_DIGEST_LENGTH)
++            return 0;
++    }
++
++    ret = DSA_sign(0, tbs, tbslen, sig, &sltmp, dsa);
++
++    if (ret <= 0)
++        return ret;
++    *siglen = sltmp;
++    return 1;
++}
++
++static int pkey_dsa_verify(EVP_PKEY_CTX *ctx,
++                           const unsigned char *sig, size_t siglen,
++                           const unsigned char *tbs, size_t tbslen)
++{
++    int ret;
++    DSA_PKEY_CTX *dctx = ctx->data;
++    DSA *dsa = ctx->pkey->pkey.dsa;
++
++    if (dctx->md) {
++        if (tbslen != (size_t)EVP_MD_size(dctx->md))
++            return 0;
++    } else {
++        if (tbslen != SHA_DIGEST_LENGTH)
++            return 0;
++    }
++
++    ret = DSA_verify(0, tbs, tbslen, sig, siglen, dsa);
++
++    return ret;
++}
++
++static int pkey_dsa_ctrl(EVP_PKEY_CTX *ctx, int type, int p1, void *p2)
++{
++    DSA_PKEY_CTX *dctx = ctx->data;
++    switch (type) {
++    case EVP_PKEY_CTRL_DSA_PARAMGEN_BITS:
++        if (p1 < 256)
++            return -2;
++        dctx->nbits = p1;
++        return 1;
++
++    case EVP_PKEY_CTRL_DSA_PARAMGEN_Q_BITS:
++        if (p1 != 160 && p1 != 224 && p1 && p1 != 256)
++            return -2;
++        dctx->qbits = p1;
++        return 1;
++
++    case EVP_PKEY_CTRL_DSA_PARAMGEN_MD:
++        if (EVP_MD_type((const EVP_MD *)p2) != NID_sha1 &&
++            EVP_MD_type((const EVP_MD *)p2) != NID_sha224 &&
++            EVP_MD_type((const EVP_MD *)p2) != NID_sha256) {
++            DSAerr(DSA_F_PKEY_DSA_CTRL, DSA_R_INVALID_DIGEST_TYPE);
++            return 0;
++        }
++        dctx->pmd = p2;
++        return 1;
++
++    case EVP_PKEY_CTRL_MD:
++        if (EVP_MD_type((const EVP_MD *)p2) != NID_sha1 &&
++            EVP_MD_type((const EVP_MD *)p2) != NID_dsa &&
++            EVP_MD_type((const EVP_MD *)p2) != NID_dsaWithSHA &&
++            EVP_MD_type((const EVP_MD *)p2) != NID_sha224 &&
++            EVP_MD_type((const EVP_MD *)p2) != NID_sha256 &&
++            EVP_MD_type((const EVP_MD *)p2) != NID_sha384 &&
++            EVP_MD_type((const EVP_MD *)p2) != NID_sha512) {
++            DSAerr(DSA_F_PKEY_DSA_CTRL, DSA_R_INVALID_DIGEST_TYPE);
++            return 0;
++        }
++        dctx->md = p2;
++        return 1;
++
++    case EVP_PKEY_CTRL_GET_MD:
++        *(const EVP_MD **)p2 = dctx->md;
++        return 1;
++
++    case EVP_PKEY_CTRL_DIGESTINIT:
++    case EVP_PKEY_CTRL_PKCS7_SIGN:
++    case EVP_PKEY_CTRL_CMS_SIGN:
++        return 1;
++
++    case EVP_PKEY_CTRL_PEER_KEY:
++        DSAerr(DSA_F_PKEY_DSA_CTRL,
++               EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE);
++        return -2;
++    default:
++        return -2;
++
++    }
++}
++
++static int pkey_dsa_ctrl_str(EVP_PKEY_CTX *ctx,
++                             const char *type, const char *value)
++{
++    if (strcmp(type, "dsa_paramgen_bits") == 0) {
++        int nbits;
++        nbits = atoi(value);
++        return EVP_PKEY_CTX_set_dsa_paramgen_bits(ctx, nbits);
++    }
++    if (strcmp(type, "dsa_paramgen_q_bits") == 0) {
++        int qbits = atoi(value);
++        return EVP_PKEY_CTX_ctrl(ctx, EVP_PKEY_DSA, EVP_PKEY_OP_PARAMGEN,
++                                 EVP_PKEY_CTRL_DSA_PARAMGEN_Q_BITS, qbits,
++                                 NULL);
++    }
++    if (strcmp(type, "dsa_paramgen_md") == 0) {
++        return EVP_PKEY_CTX_ctrl(ctx, EVP_PKEY_DSA, EVP_PKEY_OP_PARAMGEN,
++                                 EVP_PKEY_CTRL_DSA_PARAMGEN_MD, 0,
++                                 (void *)EVP_get_digestbyname(value));
++    }
++    return -2;
++}
++
++static int pkey_dsa_paramgen(EVP_PKEY_CTX *ctx, EVP_PKEY *pkey)
++{
++    DSA *dsa = NULL;
++    DSA_PKEY_CTX *dctx = ctx->data;
++    BN_GENCB *pcb;
++    int ret;
++    if (ctx->pkey_gencb) {
++        pcb = BN_GENCB_new();
++        if (pcb == NULL)
++            return 0;
++        evp_pkey_set_cb_translate(pcb, ctx);
++    } else
++        pcb = NULL;
++    dsa = DSA_new();
++    if (dsa == NULL) {
++        BN_GENCB_free(pcb);
++        return 0;
++    }
++    ret = dsa_builtin_paramgen(dsa, dctx->nbits, dctx->qbits, dctx->pmd,
++                               NULL, 0, NULL, NULL, NULL, pcb);
++    BN_GENCB_free(pcb);
++    if (ret)
++        EVP_PKEY_assign_DSA(pkey, dsa);
++    else
++        DSA_free(dsa);
++    return ret;
++}
++
++static int pkey_dsa_keygen(EVP_PKEY_CTX *ctx, EVP_PKEY *pkey)
++{
++    DSA *dsa = NULL;
++    if (ctx->pkey == NULL) {
++        DSAerr(DSA_F_PKEY_DSA_KEYGEN, DSA_R_NO_PARAMETERS_SET);
++        return 0;
++    }
++    dsa = DSA_new();
++    if (dsa == NULL)
++        return 0;
++    EVP_PKEY_assign_DSA(pkey, dsa);
++    /* Note: if error return, pkey is freed by parent routine */
++    if (!EVP_PKEY_copy_parameters(pkey, ctx->pkey))
++        return 0;
++    return DSA_generate_key(pkey->pkey.dsa);
++}
++
++const EVP_PKEY_METHOD dsa_pkey_meth = {
++    EVP_PKEY_DSA,
++    EVP_PKEY_FLAG_AUTOARGLEN,
++    pkey_dsa_init,
++    pkey_dsa_copy,
++    pkey_dsa_cleanup,
++
++    0,
++    pkey_dsa_paramgen,
++
++    0,
++    pkey_dsa_keygen,
++
++    0,
++    pkey_dsa_sign,
++
++    0,
++    pkey_dsa_verify,
++
++    0, 0,
++
++    0, 0, 0, 0,
++
++    0, 0,
++
++    0, 0,
++
++    0, 0,
++
++    pkey_dsa_ctrl,
++    pkey_dsa_ctrl_str
++};
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/dsa/dsa_prn.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/dsa/dsa_prn.c
+new file mode 100644
+index 0000000..f3c20ea
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/dsa/dsa_prn.c
+@@ -0,0 +1,69 @@
++/*
++ * Copyright 2006-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include "internal/cryptlib.h"
++#include 
++#include 
++
++#ifndef OPENSSL_NO_STDIO
++int DSA_print_fp(FILE *fp, const DSA *x, int off)
++{
++    BIO *b;
++    int ret;
++
++    if ((b = BIO_new(BIO_s_file())) == NULL) {
++        DSAerr(DSA_F_DSA_PRINT_FP, ERR_R_BUF_LIB);
++        return (0);
++    }
++    BIO_set_fp(b, fp, BIO_NOCLOSE);
++    ret = DSA_print(b, x, off);
++    BIO_free(b);
++    return (ret);
++}
++
++int DSAparams_print_fp(FILE *fp, const DSA *x)
++{
++    BIO *b;
++    int ret;
++
++    if ((b = BIO_new(BIO_s_file())) == NULL) {
++        DSAerr(DSA_F_DSAPARAMS_PRINT_FP, ERR_R_BUF_LIB);
++        return (0);
++    }
++    BIO_set_fp(b, fp, BIO_NOCLOSE);
++    ret = DSAparams_print(b, x);
++    BIO_free(b);
++    return (ret);
++}
++#endif
++
++int DSA_print(BIO *bp, const DSA *x, int off)
++{
++    EVP_PKEY *pk;
++    int ret;
++    pk = EVP_PKEY_new();
++    if (pk == NULL || !EVP_PKEY_set1_DSA(pk, (DSA *)x))
++        return 0;
++    ret = EVP_PKEY_print_private(bp, pk, off, NULL);
++    EVP_PKEY_free(pk);
++    return ret;
++}
++
++int DSAparams_print(BIO *bp, const DSA *x)
++{
++    EVP_PKEY *pk;
++    int ret;
++    pk = EVP_PKEY_new();
++    if (pk == NULL || !EVP_PKEY_set1_DSA(pk, (DSA *)x))
++        return 0;
++    ret = EVP_PKEY_print_params(bp, pk, 4, NULL);
++    EVP_PKEY_free(pk);
++    return ret;
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/dsa/dsa_sign.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/dsa/dsa_sign.c
+new file mode 100644
+index 0000000..2e29d40
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/dsa/dsa_sign.c
+@@ -0,0 +1,24 @@
++/*
++ * Copyright 1995-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++/* Original version from Steven Schoch  */
++
++#include "internal/cryptlib.h"
++#include "dsa_locl.h"
++#include 
++
++DSA_SIG *DSA_do_sign(const unsigned char *dgst, int dlen, DSA *dsa)
++{
++    return dsa->meth->dsa_do_sign(dgst, dlen, dsa);
++}
++
++int DSA_sign_setup(DSA *dsa, BN_CTX *ctx_in, BIGNUM **kinvp, BIGNUM **rp)
++{
++    return dsa->meth->dsa_sign_setup(dsa, ctx_in, kinvp, rp);
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/dsa/dsa_vrf.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/dsa/dsa_vrf.c
+new file mode 100644
+index 0000000..a84d521
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/dsa/dsa_vrf.c
+@@ -0,0 +1,19 @@
++/*
++ * Copyright 1995-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++/* Original version from Steven Schoch  */
++
++#include "internal/cryptlib.h"
++#include "dsa_locl.h"
++
++int DSA_do_verify(const unsigned char *dgst, int dgst_len, DSA_SIG *sig,
++                  DSA *dsa)
++{
++    return dsa->meth->dsa_do_verify(dgst, dgst_len, sig, dsa);
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/dso/build.info b/CryptoPkg/Library/OpensslLib/openssl/crypto/dso/build.info
+new file mode 100644
+index 0000000..82b592d
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/dso/build.info
+@@ -0,0 +1,4 @@
++LIBS=../../libcrypto
++SOURCE[../../libcrypto]=\
++        dso_dl.c dso_dlfcn.c dso_err.c dso_lib.c \
++        dso_openssl.c dso_win32.c dso_vms.c
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/dso/dso_dl.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/dso/dso_dl.c
+new file mode 100644
+index 0000000..d80bf56
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/dso/dso_dl.c
+@@ -0,0 +1,279 @@
++/*
++ * Copyright 2000-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include "dso_locl.h"
++
++#ifdef DSO_DL
++
++# include 
++
++/* Part of the hack in "dl_load" ... */
++# define DSO_MAX_TRANSLATED_SIZE 256
++
++static int dl_load(DSO *dso);
++static int dl_unload(DSO *dso);
++static DSO_FUNC_TYPE dl_bind_func(DSO *dso, const char *symname);
++static char *dl_name_converter(DSO *dso, const char *filename);
++static char *dl_merger(DSO *dso, const char *filespec1,
++                       const char *filespec2);
++static int dl_pathbyaddr(void *addr, char *path, int sz);
++static void *dl_globallookup(const char *name);
++
++static DSO_METHOD dso_meth_dl = {
++    "OpenSSL 'dl' shared library method",
++    dl_load,
++    dl_unload,
++    dl_bind_func,
++    NULL,                       /* ctrl */
++    dl_name_converter,
++    dl_merger,
++    NULL,                       /* init */
++    NULL,                       /* finish */
++    dl_pathbyaddr,
++    dl_globallookup
++};
++
++DSO_METHOD *DSO_METHOD_openssl(void)
++{
++    return &dso_meth_dl;
++}
++
++/*
++ * For this DSO_METHOD, our meth_data STACK will contain; (i) the handle
++ * (shl_t) returned from shl_load(). NB: I checked on HPUX11 and shl_t is
++ * itself a pointer type so the cast is safe.
++ */
++
++static int dl_load(DSO *dso)
++{
++    shl_t ptr = NULL;
++    /*
++     * We don't do any fancy retries or anything, just take the method's (or
++     * DSO's if it has the callback set) best translation of the
++     * platform-independent filename and try once with that.
++     */
++    char *filename = DSO_convert_filename(dso, NULL);
++
++    if (filename == NULL) {
++        DSOerr(DSO_F_DL_LOAD, DSO_R_NO_FILENAME);
++        goto err;
++    }
++    ptr = shl_load(filename, BIND_IMMEDIATE |
++                   (dso->flags & DSO_FLAG_NO_NAME_TRANSLATION ? 0 :
++                    DYNAMIC_PATH), 0L);
++    if (ptr == NULL) {
++        char errbuf[160];
++        DSOerr(DSO_F_DL_LOAD, DSO_R_LOAD_FAILED);
++        if (openssl_strerror_r(errno, errbuf, sizeof(errbuf)))
++            ERR_add_error_data(4, "filename(", filename, "): ", errbuf);
++        goto err;
++    }
++    if (!sk_push(dso->meth_data, (char *)ptr)) {
++        DSOerr(DSO_F_DL_LOAD, DSO_R_STACK_ERROR);
++        goto err;
++    }
++    /*
++     * Success, stick the converted filename we've loaded under into the DSO
++     * (it also serves as the indicator that we are currently loaded).
++     */
++    dso->loaded_filename = filename;
++    return (1);
++ err:
++    /* Cleanup! */
++    OPENSSL_free(filename);
++    if (ptr != NULL)
++        shl_unload(ptr);
++    return (0);
++}
++
++static int dl_unload(DSO *dso)
++{
++    shl_t ptr;
++    if (dso == NULL) {
++        DSOerr(DSO_F_DL_UNLOAD, ERR_R_PASSED_NULL_PARAMETER);
++        return (0);
++    }
++    if (sk_num(dso->meth_data) < 1)
++        return (1);
++    /* Is this statement legal? */
++    ptr = (shl_t) sk_pop(dso->meth_data);
++    if (ptr == NULL) {
++        DSOerr(DSO_F_DL_UNLOAD, DSO_R_NULL_HANDLE);
++        /*
++         * Should push the value back onto the stack in case of a retry.
++         */
++        sk_push(dso->meth_data, (char *)ptr);
++        return (0);
++    }
++    shl_unload(ptr);
++    return (1);
++}
++
++static DSO_FUNC_TYPE dl_bind_func(DSO *dso, const char *symname)
++{
++    shl_t ptr;
++    void *sym;
++
++    if ((dso == NULL) || (symname == NULL)) {
++        DSOerr(DSO_F_DL_BIND_FUNC, ERR_R_PASSED_NULL_PARAMETER);
++        return (NULL);
++    }
++    if (sk_num(dso->meth_data) < 1) {
++        DSOerr(DSO_F_DL_BIND_FUNC, DSO_R_STACK_ERROR);
++        return (NULL);
++    }
++    ptr = (shl_t) sk_value(dso->meth_data, sk_num(dso->meth_data) - 1);
++    if (ptr == NULL) {
++        DSOerr(DSO_F_DL_BIND_FUNC, DSO_R_NULL_HANDLE);
++        return (NULL);
++    }
++    if (shl_findsym(&ptr, symname, TYPE_UNDEFINED, &sym) < 0) {
++        char errbuf[160];
++        DSOerr(DSO_F_DL_BIND_FUNC, DSO_R_SYM_FAILURE);
++        if (openssl_strerror_r(errno, errbuf, sizeof(errbuf)))
++            ERR_add_error_data(4, "symname(", symname, "): ", errbuf);
++        return (NULL);
++    }
++    return ((DSO_FUNC_TYPE)sym);
++}
++
++static char *dl_merger(DSO *dso, const char *filespec1, const char *filespec2)
++{
++    char *merged;
++
++    if (!filespec1 && !filespec2) {
++        DSOerr(DSO_F_DL_MERGER, ERR_R_PASSED_NULL_PARAMETER);
++        return (NULL);
++    }
++    /*
++     * If the first file specification is a rooted path, it rules. same goes
++     * if the second file specification is missing.
++     */
++    if (!filespec2 || filespec1[0] == '/') {
++        merged = OPENSSL_strdup(filespec1);
++        if (merged == NULL) {
++            DSOerr(DSO_F_DL_MERGER, ERR_R_MALLOC_FAILURE);
++            return (NULL);
++        }
++    }
++    /*
++     * If the first file specification is missing, the second one rules.
++     */
++    else if (!filespec1) {
++        merged = OPENSSL_strdup(filespec2);
++        if (merged == NULL) {
++            DSOerr(DSO_F_DL_MERGER, ERR_R_MALLOC_FAILURE);
++            return (NULL);
++        }
++    } else
++        /*
++         * This part isn't as trivial as it looks.  It assumes that the
++         * second file specification really is a directory, and makes no
++         * checks whatsoever.  Therefore, the result becomes the
++         * concatenation of filespec2 followed by a slash followed by
++         * filespec1.
++         */
++    {
++        int spec2len, len;
++
++        spec2len = (filespec2 ? strlen(filespec2) : 0);
++        len = spec2len + (filespec1 ? strlen(filespec1) : 0);
++
++        if (spec2len && filespec2[spec2len - 1] == '/') {
++            spec2len--;
++            len--;
++        }
++        merged = OPENSSL_malloc(len + 2);
++        if (merged == NULL) {
++            DSOerr(DSO_F_DL_MERGER, ERR_R_MALLOC_FAILURE);
++            return (NULL);
++        }
++        strcpy(merged, filespec2);
++        merged[spec2len] = '/';
++        strcpy(&merged[spec2len + 1], filespec1);
++    }
++    return (merged);
++}
++
++/*
++ * This function is identical to the one in dso_dlfcn.c, but as it is highly
++ * unlikely that both the "dl" *and* "dlfcn" variants are being compiled at
++ * the same time, there's no great duplicating the code. Figuring out an
++ * elegant way to share one copy of the code would be more difficult and
++ * would not leave the implementations independent.
++ */
++static char *dl_name_converter(DSO *dso, const char *filename)
++{
++    char *translated;
++    int len, rsize, transform;
++
++    len = strlen(filename);
++    rsize = len + 1;
++    transform = (strstr(filename, "/") == NULL);
++    {
++        /* We will convert this to "%s.s?" or "lib%s.s?" */
++        rsize += strlen(DSO_EXTENSION); /* The length of ".s?" */
++        if ((DSO_flags(dso) & DSO_FLAG_NAME_TRANSLATION_EXT_ONLY) == 0)
++            rsize += 3;         /* The length of "lib" */
++    }
++    translated = OPENSSL_malloc(rsize);
++    if (translated == NULL) {
++        DSOerr(DSO_F_DL_NAME_CONVERTER, DSO_R_NAME_TRANSLATION_FAILED);
++        return (NULL);
++    }
++    if (transform) {
++        if ((DSO_flags(dso) & DSO_FLAG_NAME_TRANSLATION_EXT_ONLY) == 0)
++            sprintf(translated, "lib%s%s", filename, DSO_EXTENSION);
++        else
++            sprintf(translated, "%s%s", filename, DSO_EXTENSION);
++    } else
++        sprintf(translated, "%s", filename);
++    return (translated);
++}
++
++static int dl_pathbyaddr(void *addr, char *path, int sz)
++{
++    struct shl_descriptor inf;
++    int i, len;
++
++    if (addr == NULL) {
++        union {
++            int (*f) (void *, char *, int);
++            void *p;
++        } t = {
++            dl_pathbyaddr
++        };
++        addr = t.p;
++    }
++
++    for (i = -1; shl_get_r(i, &inf) == 0; i++) {
++        if (((size_t)addr >= inf.tstart && (size_t)addr < inf.tend) ||
++            ((size_t)addr >= inf.dstart && (size_t)addr < inf.dend)) {
++            len = (int)strlen(inf.filename);
++            if (sz <= 0)
++                return len + 1;
++            if (len >= sz)
++                len = sz - 1;
++            memcpy(path, inf.filename, len);
++            path[len++] = 0;
++            return len;
++        }
++    }
++
++    return -1;
++}
++
++static void *dl_globallookup(const char *name)
++{
++    void *ret;
++    shl_t h = NULL;
++
++    return shl_findsym(&h, name, TYPE_UNDEFINED, &ret) ? NULL : ret;
++}
++#endif                          /* DSO_DL */
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/dso/dso_dlfcn.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/dso/dso_dlfcn.c
+new file mode 100644
+index 0000000..a4b0cdd
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/dso/dso_dlfcn.c
+@@ -0,0 +1,354 @@
++/*
++ * Copyright 2000-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++/*
++ * We need to do this early, because stdio.h includes the header files that
++ * handle _GNU_SOURCE and other similar macros.  Defining it later is simply
++ * too late, because those headers are protected from re- inclusion.
++ */
++#ifndef _GNU_SOURCE
++# define _GNU_SOURCE            /* make sure dladdr is declared */
++#endif
++
++#include "dso_locl.h"
++
++#ifdef DSO_DLFCN
++
++# ifdef HAVE_DLFCN_H
++#  ifdef __osf__
++#   define __EXTENSIONS__
++#  endif
++#  include 
++#  define HAVE_DLINFO 1
++#  if defined(_AIX) || defined(__CYGWIN__) || \
++     defined(__SCO_VERSION__) || defined(_SCO_ELF) || \
++     (defined(__osf__) && !defined(RTLD_NEXT))     || \
++     (defined(__OpenBSD__) && !defined(RTLD_SELF)) || \
++        defined(__ANDROID__)
++#   undef HAVE_DLINFO
++#  endif
++# endif
++
++/* Part of the hack in "dlfcn_load" ... */
++# define DSO_MAX_TRANSLATED_SIZE 256
++
++static int dlfcn_load(DSO *dso);
++static int dlfcn_unload(DSO *dso);
++static DSO_FUNC_TYPE dlfcn_bind_func(DSO *dso, const char *symname);
++static char *dlfcn_name_converter(DSO *dso, const char *filename);
++static char *dlfcn_merger(DSO *dso, const char *filespec1,
++                          const char *filespec2);
++static int dlfcn_pathbyaddr(void *addr, char *path, int sz);
++static void *dlfcn_globallookup(const char *name);
++
++static DSO_METHOD dso_meth_dlfcn = {
++    "OpenSSL 'dlfcn' shared library method",
++    dlfcn_load,
++    dlfcn_unload,
++    dlfcn_bind_func,
++    NULL,                       /* ctrl */
++    dlfcn_name_converter,
++    dlfcn_merger,
++    NULL,                       /* init */
++    NULL,                       /* finish */
++    dlfcn_pathbyaddr,
++    dlfcn_globallookup
++};
++
++DSO_METHOD *DSO_METHOD_openssl(void)
++{
++    return &dso_meth_dlfcn;
++}
++
++/*
++ * Prior to using the dlopen() function, we should decide on the flag we
++ * send. There's a few different ways of doing this and it's a messy
++ * venn-diagram to match up which platforms support what. So as we don't have
++ * autoconf yet, I'm implementing a hack that could be hacked further
++ * relatively easily to deal with cases as we find them. Initially this is to
++ * cope with OpenBSD.
++ */
++# if defined(__OpenBSD__) || defined(__NetBSD__)
++#  ifdef DL_LAZY
++#   define DLOPEN_FLAG DL_LAZY
++#  else
++#   ifdef RTLD_NOW
++#    define DLOPEN_FLAG RTLD_NOW
++#   else
++#    define DLOPEN_FLAG 0
++#   endif
++#  endif
++# else
++#  define DLOPEN_FLAG RTLD_NOW  /* Hope this works everywhere else */
++# endif
++
++/*
++ * For this DSO_METHOD, our meth_data STACK will contain; (i) the handle
++ * (void*) returned from dlopen().
++ */
++
++static int dlfcn_load(DSO *dso)
++{
++    void *ptr = NULL;
++    /* See applicable comments in dso_dl.c */
++    char *filename = DSO_convert_filename(dso, NULL);
++    int flags = DLOPEN_FLAG;
++
++    if (filename == NULL) {
++        DSOerr(DSO_F_DLFCN_LOAD, DSO_R_NO_FILENAME);
++        goto err;
++    }
++# ifdef RTLD_GLOBAL
++    if (dso->flags & DSO_FLAG_GLOBAL_SYMBOLS)
++        flags |= RTLD_GLOBAL;
++# endif
++    ptr = dlopen(filename, flags);
++    if (ptr == NULL) {
++        DSOerr(DSO_F_DLFCN_LOAD, DSO_R_LOAD_FAILED);
++        ERR_add_error_data(4, "filename(", filename, "): ", dlerror());
++        goto err;
++    }
++    if (!sk_void_push(dso->meth_data, (char *)ptr)) {
++        DSOerr(DSO_F_DLFCN_LOAD, DSO_R_STACK_ERROR);
++        goto err;
++    }
++    /* Success */
++    dso->loaded_filename = filename;
++    return (1);
++ err:
++    /* Cleanup! */
++    OPENSSL_free(filename);
++    if (ptr != NULL)
++        dlclose(ptr);
++    return (0);
++}
++
++static int dlfcn_unload(DSO *dso)
++{
++    void *ptr;
++    if (dso == NULL) {
++        DSOerr(DSO_F_DLFCN_UNLOAD, ERR_R_PASSED_NULL_PARAMETER);
++        return (0);
++    }
++    if (sk_void_num(dso->meth_data) < 1)
++        return (1);
++    ptr = sk_void_pop(dso->meth_data);
++    if (ptr == NULL) {
++        DSOerr(DSO_F_DLFCN_UNLOAD, DSO_R_NULL_HANDLE);
++        /*
++         * Should push the value back onto the stack in case of a retry.
++         */
++        sk_void_push(dso->meth_data, ptr);
++        return (0);
++    }
++    /* For now I'm not aware of any errors associated with dlclose() */
++    dlclose(ptr);
++    return (1);
++}
++
++static DSO_FUNC_TYPE dlfcn_bind_func(DSO *dso, const char *symname)
++{
++    void *ptr;
++    union {
++        DSO_FUNC_TYPE sym;
++        void *dlret;
++    } u;
++
++    if ((dso == NULL) || (symname == NULL)) {
++        DSOerr(DSO_F_DLFCN_BIND_FUNC, ERR_R_PASSED_NULL_PARAMETER);
++        return (NULL);
++    }
++    if (sk_void_num(dso->meth_data) < 1) {
++        DSOerr(DSO_F_DLFCN_BIND_FUNC, DSO_R_STACK_ERROR);
++        return (NULL);
++    }
++    ptr = sk_void_value(dso->meth_data, sk_void_num(dso->meth_data) - 1);
++    if (ptr == NULL) {
++        DSOerr(DSO_F_DLFCN_BIND_FUNC, DSO_R_NULL_HANDLE);
++        return (NULL);
++    }
++    u.dlret = dlsym(ptr, symname);
++    if (u.dlret == NULL) {
++        DSOerr(DSO_F_DLFCN_BIND_FUNC, DSO_R_SYM_FAILURE);
++        ERR_add_error_data(4, "symname(", symname, "): ", dlerror());
++        return (NULL);
++    }
++    return u.sym;
++}
++
++static char *dlfcn_merger(DSO *dso, const char *filespec1,
++                          const char *filespec2)
++{
++    char *merged;
++
++    if (!filespec1 && !filespec2) {
++        DSOerr(DSO_F_DLFCN_MERGER, ERR_R_PASSED_NULL_PARAMETER);
++        return (NULL);
++    }
++    /*
++     * If the first file specification is a rooted path, it rules. same goes
++     * if the second file specification is missing.
++     */
++    if (!filespec2 || (filespec1 != NULL && filespec1[0] == '/')) {
++        merged = OPENSSL_strdup(filespec1);
++        if (merged == NULL) {
++            DSOerr(DSO_F_DLFCN_MERGER, ERR_R_MALLOC_FAILURE);
++            return (NULL);
++        }
++    }
++    /*
++     * If the first file specification is missing, the second one rules.
++     */
++    else if (!filespec1) {
++        merged = OPENSSL_strdup(filespec2);
++        if (merged == NULL) {
++            DSOerr(DSO_F_DLFCN_MERGER, ERR_R_MALLOC_FAILURE);
++            return (NULL);
++        }
++    } else {
++        /*
++         * This part isn't as trivial as it looks.  It assumes that the
++         * second file specification really is a directory, and makes no
++         * checks whatsoever.  Therefore, the result becomes the
++         * concatenation of filespec2 followed by a slash followed by
++         * filespec1.
++         */
++        int spec2len, len;
++
++        spec2len = strlen(filespec2);
++        len = spec2len + strlen(filespec1);
++
++        if (spec2len && filespec2[spec2len - 1] == '/') {
++            spec2len--;
++            len--;
++        }
++        merged = OPENSSL_malloc(len + 2);
++        if (merged == NULL) {
++            DSOerr(DSO_F_DLFCN_MERGER, ERR_R_MALLOC_FAILURE);
++            return (NULL);
++        }
++        strcpy(merged, filespec2);
++        merged[spec2len] = '/';
++        strcpy(&merged[spec2len + 1], filespec1);
++    }
++    return (merged);
++}
++
++static char *dlfcn_name_converter(DSO *dso, const char *filename)
++{
++    char *translated;
++    int len, rsize, transform;
++
++    len = strlen(filename);
++    rsize = len + 1;
++    transform = (strstr(filename, "/") == NULL);
++    if (transform) {
++        /* We will convert this to "%s.so" or "lib%s.so" etc */
++        rsize += strlen(DSO_EXTENSION);    /* The length of ".so" */
++        if ((DSO_flags(dso) & DSO_FLAG_NAME_TRANSLATION_EXT_ONLY) == 0)
++            rsize += 3;         /* The length of "lib" */
++    }
++    translated = OPENSSL_malloc(rsize);
++    if (translated == NULL) {
++        DSOerr(DSO_F_DLFCN_NAME_CONVERTER, DSO_R_NAME_TRANSLATION_FAILED);
++        return (NULL);
++    }
++    if (transform) {
++        if ((DSO_flags(dso) & DSO_FLAG_NAME_TRANSLATION_EXT_ONLY) == 0)
++            sprintf(translated, "lib%s" DSO_EXTENSION, filename);
++        else
++            sprintf(translated, "%s" DSO_EXTENSION, filename);
++    } else
++        sprintf(translated, "%s", filename);
++    return (translated);
++}
++
++# ifdef __sgi
++/*-
++This is a quote from IRIX manual for dladdr(3c):
++
++      does not contain a prototype for dladdr or definition of
++     Dl_info.  The #include   in the SYNOPSIS line is traditional,
++     but contains no dladdr prototype and no IRIX library contains an
++     implementation.  Write your own declaration based on the code below.
++
++     The following code is dependent on internal interfaces that are not
++     part of the IRIX compatibility guarantee; however, there is no future
++     intention to change this interface, so on a practical level, the code
++     below is safe to use on IRIX.
++*/
++#  include 
++#  ifndef _RLD_INTERFACE_DLFCN_H_DLADDR
++#   define _RLD_INTERFACE_DLFCN_H_DLADDR
++typedef struct Dl_info {
++    const char *dli_fname;
++    void *dli_fbase;
++    const char *dli_sname;
++    void *dli_saddr;
++    int dli_version;
++    int dli_reserved1;
++    long dli_reserved[4];
++} Dl_info;
++#  else
++typedef struct Dl_info Dl_info;
++#  endif
++#  define _RLD_DLADDR             14
++
++static int dladdr(void *address, Dl_info *dl)
++{
++    void *v;
++    v = _rld_new_interface(_RLD_DLADDR, address, dl);
++    return (int)v;
++}
++# endif                         /* __sgi */
++
++static int dlfcn_pathbyaddr(void *addr, char *path, int sz)
++{
++# ifdef HAVE_DLINFO
++    Dl_info dli;
++    int len;
++
++    if (addr == NULL) {
++        union {
++            int (*f) (void *, char *, int);
++            void *p;
++        } t = {
++            dlfcn_pathbyaddr
++        };
++        addr = t.p;
++    }
++
++    if (dladdr(addr, &dli)) {
++        len = (int)strlen(dli.dli_fname);
++        if (sz <= 0)
++            return len + 1;
++        if (len >= sz)
++            len = sz - 1;
++        memcpy(path, dli.dli_fname, len);
++        path[len++] = 0;
++        return len;
++    }
++
++    ERR_add_error_data(2, "dlfcn_pathbyaddr(): ", dlerror());
++# endif
++    return -1;
++}
++
++static void *dlfcn_globallookup(const char *name)
++{
++    void *ret = NULL, *handle = dlopen(NULL, RTLD_LAZY);
++
++    if (handle) {
++        ret = dlsym(handle, name);
++        dlclose(handle);
++    }
++
++    return ret;
++}
++#endif                          /* DSO_DLFCN */
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/dso/dso_err.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/dso/dso_err.c
+new file mode 100644
+index 0000000..07588d5
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/dso/dso_err.c
+@@ -0,0 +1,93 @@
++/*
++ * Generated by util/mkerr.pl DO NOT EDIT
++ * Copyright 1995-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include 
++#include "internal/dso.h"
++
++/* BEGIN ERROR CODES */
++#ifndef OPENSSL_NO_ERR
++
++# define ERR_FUNC(func) ERR_PACK(ERR_LIB_DSO,func,0)
++# define ERR_REASON(reason) ERR_PACK(ERR_LIB_DSO,0,reason)
++
++static ERR_STRING_DATA DSO_str_functs[] = {
++    {ERR_FUNC(DSO_F_DLFCN_BIND_FUNC), "dlfcn_bind_func"},
++    {ERR_FUNC(DSO_F_DLFCN_LOAD), "dlfcn_load"},
++    {ERR_FUNC(DSO_F_DLFCN_MERGER), "dlfcn_merger"},
++    {ERR_FUNC(DSO_F_DLFCN_NAME_CONVERTER), "dlfcn_name_converter"},
++    {ERR_FUNC(DSO_F_DLFCN_UNLOAD), "dlfcn_unload"},
++    {ERR_FUNC(DSO_F_DL_BIND_FUNC), "dl_bind_func"},
++    {ERR_FUNC(DSO_F_DL_LOAD), "dl_load"},
++    {ERR_FUNC(DSO_F_DL_MERGER), "dl_merger"},
++    {ERR_FUNC(DSO_F_DL_NAME_CONVERTER), "dl_name_converter"},
++    {ERR_FUNC(DSO_F_DL_UNLOAD), "dl_unload"},
++    {ERR_FUNC(DSO_F_DSO_BIND_FUNC), "DSO_bind_func"},
++    {ERR_FUNC(DSO_F_DSO_CONVERT_FILENAME), "DSO_convert_filename"},
++    {ERR_FUNC(DSO_F_DSO_CTRL), "DSO_ctrl"},
++    {ERR_FUNC(DSO_F_DSO_FREE), "DSO_free"},
++    {ERR_FUNC(DSO_F_DSO_GET_FILENAME), "DSO_get_filename"},
++    {ERR_FUNC(DSO_F_DSO_GLOBAL_LOOKUP), "DSO_global_lookup"},
++    {ERR_FUNC(DSO_F_DSO_LOAD), "DSO_load"},
++    {ERR_FUNC(DSO_F_DSO_MERGE), "DSO_merge"},
++    {ERR_FUNC(DSO_F_DSO_NEW_METHOD), "DSO_new_method"},
++    {ERR_FUNC(DSO_F_DSO_PATHBYADDR), "DSO_pathbyaddr"},
++    {ERR_FUNC(DSO_F_DSO_SET_FILENAME), "DSO_set_filename"},
++    {ERR_FUNC(DSO_F_DSO_UP_REF), "DSO_up_ref"},
++    {ERR_FUNC(DSO_F_VMS_BIND_SYM), "vms_bind_sym"},
++    {ERR_FUNC(DSO_F_VMS_LOAD), "vms_load"},
++    {ERR_FUNC(DSO_F_VMS_MERGER), "vms_merger"},
++    {ERR_FUNC(DSO_F_VMS_UNLOAD), "vms_unload"},
++    {ERR_FUNC(DSO_F_WIN32_BIND_FUNC), "win32_bind_func"},
++    {ERR_FUNC(DSO_F_WIN32_GLOBALLOOKUP), "win32_globallookup"},
++    {ERR_FUNC(DSO_F_WIN32_JOINER), "win32_joiner"},
++    {ERR_FUNC(DSO_F_WIN32_LOAD), "win32_load"},
++    {ERR_FUNC(DSO_F_WIN32_MERGER), "win32_merger"},
++    {ERR_FUNC(DSO_F_WIN32_NAME_CONVERTER), "win32_name_converter"},
++    {ERR_FUNC(DSO_F_WIN32_PATHBYADDR), "win32_pathbyaddr"},
++    {ERR_FUNC(DSO_F_WIN32_SPLITTER), "win32_splitter"},
++    {ERR_FUNC(DSO_F_WIN32_UNLOAD), "win32_unload"},
++    {0, NULL}
++};
++
++static ERR_STRING_DATA DSO_str_reasons[] = {
++    {ERR_REASON(DSO_R_CTRL_FAILED), "control command failed"},
++    {ERR_REASON(DSO_R_DSO_ALREADY_LOADED), "dso already loaded"},
++    {ERR_REASON(DSO_R_EMPTY_FILE_STRUCTURE), "empty file structure"},
++    {ERR_REASON(DSO_R_FAILURE), "failure"},
++    {ERR_REASON(DSO_R_FILENAME_TOO_BIG), "filename too big"},
++    {ERR_REASON(DSO_R_FINISH_FAILED), "cleanup method function failed"},
++    {ERR_REASON(DSO_R_INCORRECT_FILE_SYNTAX), "incorrect file syntax"},
++    {ERR_REASON(DSO_R_LOAD_FAILED), "could not load the shared library"},
++    {ERR_REASON(DSO_R_NAME_TRANSLATION_FAILED), "name translation failed"},
++    {ERR_REASON(DSO_R_NO_FILENAME), "no filename"},
++    {ERR_REASON(DSO_R_NULL_HANDLE), "a null shared library handle was used"},
++    {ERR_REASON(DSO_R_SET_FILENAME_FAILED), "set filename failed"},
++    {ERR_REASON(DSO_R_STACK_ERROR), "the meth_data stack is corrupt"},
++    {ERR_REASON(DSO_R_SYM_FAILURE),
++     "could not bind to the requested symbol name"},
++    {ERR_REASON(DSO_R_UNLOAD_FAILED), "could not unload the shared library"},
++    {ERR_REASON(DSO_R_UNSUPPORTED), "functionality not supported"},
++    {0, NULL}
++};
++
++#endif
++
++int ERR_load_DSO_strings(void)
++{
++#ifndef OPENSSL_NO_ERR
++
++    if (ERR_func_error_string(DSO_str_functs[0].error) == NULL) {
++        ERR_load_strings(0, DSO_str_functs);
++        ERR_load_strings(0, DSO_str_reasons);
++    }
++#endif
++    return 1;
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/dso/dso_lib.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/dso/dso_lib.c
+new file mode 100644
+index 0000000..f58237d
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/dso/dso_lib.c
+@@ -0,0 +1,349 @@
++/*
++ * Copyright 2000-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include "dso_locl.h"
++
++static DSO_METHOD *default_DSO_meth = NULL;
++
++static DSO *DSO_new_method(DSO_METHOD *meth)
++{
++    DSO *ret;
++
++    if (default_DSO_meth == NULL) {
++        /*
++         * We default to DSO_METH_openssl() which in turn defaults to
++         * stealing the "best available" method. Will fallback to
++         * DSO_METH_null() in the worst case.
++         */
++        default_DSO_meth = DSO_METHOD_openssl();
++    }
++    ret = OPENSSL_zalloc(sizeof(*ret));
++    if (ret == NULL) {
++        DSOerr(DSO_F_DSO_NEW_METHOD, ERR_R_MALLOC_FAILURE);
++        return (NULL);
++    }
++    ret->meth_data = sk_void_new_null();
++    if (ret->meth_data == NULL) {
++        /* sk_new doesn't generate any errors so we do */
++        DSOerr(DSO_F_DSO_NEW_METHOD, ERR_R_MALLOC_FAILURE);
++        OPENSSL_free(ret);
++        return (NULL);
++    }
++    ret->meth = default_DSO_meth;
++    ret->references = 1;
++    ret->lock = CRYPTO_THREAD_lock_new();
++    if (ret->lock == NULL) {
++        DSOerr(DSO_F_DSO_NEW_METHOD, ERR_R_MALLOC_FAILURE);
++        sk_void_free(ret->meth_data);
++        OPENSSL_free(ret);
++        return NULL;
++    }
++
++    if ((ret->meth->init != NULL) && !ret->meth->init(ret)) {
++        DSO_free(ret);
++        ret = NULL;
++    }
++
++    return ret;
++}
++
++DSO *DSO_new(void)
++{
++    return DSO_new_method(NULL);
++}
++
++int DSO_free(DSO *dso)
++{
++    int i;
++
++    if (dso == NULL)
++        return (1);
++
++    if (CRYPTO_atomic_add(&dso->references, -1, &i, dso->lock) <= 0)
++        return 0;
++
++    REF_PRINT_COUNT("DSO", dso);
++    if (i > 0)
++        return 1;
++    REF_ASSERT_ISNT(i < 0);
++
++    if ((dso->flags & DSO_FLAG_NO_UNLOAD_ON_FREE) == 0) {
++        if ((dso->meth->dso_unload != NULL) && !dso->meth->dso_unload(dso)) {
++            DSOerr(DSO_F_DSO_FREE, DSO_R_UNLOAD_FAILED);
++            return 0;
++        }
++    }
++
++    if ((dso->meth->finish != NULL) && !dso->meth->finish(dso)) {
++        DSOerr(DSO_F_DSO_FREE, DSO_R_FINISH_FAILED);
++        return 0;
++    }
++
++    sk_void_free(dso->meth_data);
++    OPENSSL_free(dso->filename);
++    OPENSSL_free(dso->loaded_filename);
++    CRYPTO_THREAD_lock_free(dso->lock);
++    OPENSSL_free(dso);
++    return 1;
++}
++
++int DSO_flags(DSO *dso)
++{
++    return ((dso == NULL) ? 0 : dso->flags);
++}
++
++int DSO_up_ref(DSO *dso)
++{
++    int i;
++
++    if (dso == NULL) {
++        DSOerr(DSO_F_DSO_UP_REF, ERR_R_PASSED_NULL_PARAMETER);
++        return 0;
++    }
++
++    if (CRYPTO_atomic_add(&dso->references, 1, &i, dso->lock) <= 0)
++        return 0;
++
++    REF_PRINT_COUNT("DSO", r);
++    REF_ASSERT_ISNT(i < 2);
++    return ((i > 1) ? 1 : 0);
++}
++
++DSO *DSO_load(DSO *dso, const char *filename, DSO_METHOD *meth, int flags)
++{
++    DSO *ret;
++    int allocated = 0;
++
++    if (dso == NULL) {
++        ret = DSO_new_method(meth);
++        if (ret == NULL) {
++            DSOerr(DSO_F_DSO_LOAD, ERR_R_MALLOC_FAILURE);
++            goto err;
++        }
++        allocated = 1;
++        /* Pass the provided flags to the new DSO object */
++        if (DSO_ctrl(ret, DSO_CTRL_SET_FLAGS, flags, NULL) < 0) {
++            DSOerr(DSO_F_DSO_LOAD, DSO_R_CTRL_FAILED);
++            goto err;
++        }
++    } else
++        ret = dso;
++    /* Don't load if we're currently already loaded */
++    if (ret->filename != NULL) {
++        DSOerr(DSO_F_DSO_LOAD, DSO_R_DSO_ALREADY_LOADED);
++        goto err;
++    }
++    /*
++     * filename can only be NULL if we were passed a dso that already has one
++     * set.
++     */
++    if (filename != NULL)
++        if (!DSO_set_filename(ret, filename)) {
++            DSOerr(DSO_F_DSO_LOAD, DSO_R_SET_FILENAME_FAILED);
++            goto err;
++        }
++    filename = ret->filename;
++    if (filename == NULL) {
++        DSOerr(DSO_F_DSO_LOAD, DSO_R_NO_FILENAME);
++        goto err;
++    }
++    if (ret->meth->dso_load == NULL) {
++        DSOerr(DSO_F_DSO_LOAD, DSO_R_UNSUPPORTED);
++        goto err;
++    }
++    if (!ret->meth->dso_load(ret)) {
++        DSOerr(DSO_F_DSO_LOAD, DSO_R_LOAD_FAILED);
++        goto err;
++    }
++    /* Load succeeded */
++    return (ret);
++ err:
++    if (allocated)
++        DSO_free(ret);
++    return (NULL);
++}
++
++DSO_FUNC_TYPE DSO_bind_func(DSO *dso, const char *symname)
++{
++    DSO_FUNC_TYPE ret = NULL;
++
++    if ((dso == NULL) || (symname == NULL)) {
++        DSOerr(DSO_F_DSO_BIND_FUNC, ERR_R_PASSED_NULL_PARAMETER);
++        return (NULL);
++    }
++    if (dso->meth->dso_bind_func == NULL) {
++        DSOerr(DSO_F_DSO_BIND_FUNC, DSO_R_UNSUPPORTED);
++        return (NULL);
++    }
++    if ((ret = dso->meth->dso_bind_func(dso, symname)) == NULL) {
++        DSOerr(DSO_F_DSO_BIND_FUNC, DSO_R_SYM_FAILURE);
++        return (NULL);
++    }
++    /* Success */
++    return (ret);
++}
++
++/*
++ * I don't really like these *_ctrl functions very much to be perfectly
++ * honest. For one thing, I think I have to return a negative value for any
++ * error because possible DSO_ctrl() commands may return values such as
++ * "size"s that can legitimately be zero (making the standard
++ * "if (DSO_cmd(...))" form that works almost everywhere else fail at odd
++ * times. I'd prefer "output" values to be passed by reference and the return
++ * value as success/failure like usual ... but we conform when we must... :-)
++ */
++long DSO_ctrl(DSO *dso, int cmd, long larg, void *parg)
++{
++    if (dso == NULL) {
++        DSOerr(DSO_F_DSO_CTRL, ERR_R_PASSED_NULL_PARAMETER);
++        return (-1);
++    }
++    /*
++     * We should intercept certain generic commands and only pass control to
++     * the method-specific ctrl() function if it's something we don't handle.
++     */
++    switch (cmd) {
++    case DSO_CTRL_GET_FLAGS:
++        return dso->flags;
++    case DSO_CTRL_SET_FLAGS:
++        dso->flags = (int)larg;
++        return (0);
++    case DSO_CTRL_OR_FLAGS:
++        dso->flags |= (int)larg;
++        return (0);
++    default:
++        break;
++    }
++    if ((dso->meth == NULL) || (dso->meth->dso_ctrl == NULL)) {
++        DSOerr(DSO_F_DSO_CTRL, DSO_R_UNSUPPORTED);
++        return (-1);
++    }
++    return (dso->meth->dso_ctrl(dso, cmd, larg, parg));
++}
++
++const char *DSO_get_filename(DSO *dso)
++{
++    if (dso == NULL) {
++        DSOerr(DSO_F_DSO_GET_FILENAME, ERR_R_PASSED_NULL_PARAMETER);
++        return (NULL);
++    }
++    return (dso->filename);
++}
++
++int DSO_set_filename(DSO *dso, const char *filename)
++{
++    char *copied;
++
++    if ((dso == NULL) || (filename == NULL)) {
++        DSOerr(DSO_F_DSO_SET_FILENAME, ERR_R_PASSED_NULL_PARAMETER);
++        return (0);
++    }
++    if (dso->loaded_filename) {
++        DSOerr(DSO_F_DSO_SET_FILENAME, DSO_R_DSO_ALREADY_LOADED);
++        return (0);
++    }
++    /* We'll duplicate filename */
++    copied = OPENSSL_strdup(filename);
++    if (copied == NULL) {
++        DSOerr(DSO_F_DSO_SET_FILENAME, ERR_R_MALLOC_FAILURE);
++        return (0);
++    }
++    OPENSSL_free(dso->filename);
++    dso->filename = copied;
++    return (1);
++}
++
++char *DSO_merge(DSO *dso, const char *filespec1, const char *filespec2)
++{
++    char *result = NULL;
++
++    if (dso == NULL || filespec1 == NULL) {
++        DSOerr(DSO_F_DSO_MERGE, ERR_R_PASSED_NULL_PARAMETER);
++        return (NULL);
++    }
++    if ((dso->flags & DSO_FLAG_NO_NAME_TRANSLATION) == 0) {
++        if (dso->merger != NULL)
++            result = dso->merger(dso, filespec1, filespec2);
++        else if (dso->meth->dso_merger != NULL)
++            result = dso->meth->dso_merger(dso, filespec1, filespec2);
++    }
++    return (result);
++}
++
++char *DSO_convert_filename(DSO *dso, const char *filename)
++{
++    char *result = NULL;
++
++    if (dso == NULL) {
++        DSOerr(DSO_F_DSO_CONVERT_FILENAME, ERR_R_PASSED_NULL_PARAMETER);
++        return (NULL);
++    }
++    if (filename == NULL)
++        filename = dso->filename;
++    if (filename == NULL) {
++        DSOerr(DSO_F_DSO_CONVERT_FILENAME, DSO_R_NO_FILENAME);
++        return (NULL);
++    }
++    if ((dso->flags & DSO_FLAG_NO_NAME_TRANSLATION) == 0) {
++        if (dso->name_converter != NULL)
++            result = dso->name_converter(dso, filename);
++        else if (dso->meth->dso_name_converter != NULL)
++            result = dso->meth->dso_name_converter(dso, filename);
++    }
++    if (result == NULL) {
++        result = OPENSSL_strdup(filename);
++        if (result == NULL) {
++            DSOerr(DSO_F_DSO_CONVERT_FILENAME, ERR_R_MALLOC_FAILURE);
++            return (NULL);
++        }
++    }
++    return (result);
++}
++
++int DSO_pathbyaddr(void *addr, char *path, int sz)
++{
++    DSO_METHOD *meth = default_DSO_meth;
++    if (meth == NULL)
++        meth = DSO_METHOD_openssl();
++    if (meth->pathbyaddr == NULL) {
++        DSOerr(DSO_F_DSO_PATHBYADDR, DSO_R_UNSUPPORTED);
++        return -1;
++    }
++    return (*meth->pathbyaddr) (addr, path, sz);
++}
++
++DSO *DSO_dsobyaddr(void *addr, int flags)
++{
++    DSO *ret = NULL;
++    char *filename = NULL;
++    int len = DSO_pathbyaddr(addr, NULL, 0);
++
++    if (len < 0)
++        return NULL;
++
++    filename = OPENSSL_malloc(len);
++    if (filename != NULL
++            && DSO_pathbyaddr(addr, filename, len) == len)
++        ret = DSO_load(NULL, filename, NULL, flags);
++
++    OPENSSL_free(filename);
++    return ret;
++}
++
++void *DSO_global_lookup(const char *name)
++{
++    DSO_METHOD *meth = default_DSO_meth;
++    if (meth == NULL)
++        meth = DSO_METHOD_openssl();
++    if (meth->globallookup == NULL) {
++        DSOerr(DSO_F_DSO_GLOBAL_LOOKUP, DSO_R_UNSUPPORTED);
++        return NULL;
++    }
++    return (*meth->globallookup) (name);
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/dso/dso_locl.h b/CryptoPkg/Library/OpensslLib/openssl/crypto/dso/dso_locl.h
+new file mode 100644
+index 0000000..fbfad05
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/dso/dso_locl.h
+@@ -0,0 +1,106 @@
++/*
++ * Copyright 2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include "internal/cryptlib.h"
++#include "internal/dso.h"
++#include "internal/dso_conf.h"
++
++/**********************************************************************/
++/* The low-level handle type used to refer to a loaded shared library */
++
++struct dso_st {
++    DSO_METHOD *meth;
++    /*
++     * Standard dlopen uses a (void *). Win32 uses a HANDLE. VMS doesn't use
++     * anything but will need to cache the filename for use in the dso_bind
++     * handler. All in all, let each method control its own destiny.
++     * "Handles" and such go in a STACK.
++     */
++    STACK_OF(void) *meth_data;
++    int references;
++    int flags;
++    /*
++     * For use by applications etc ... use this for your bits'n'pieces, don't
++     * touch meth_data!
++     */
++    CRYPTO_EX_DATA ex_data;
++    /*
++     * If this callback function pointer is set to non-NULL, then it will be
++     * used in DSO_load() in place of meth->dso_name_converter. NB: This
++     * should normally set using DSO_set_name_converter().
++     */
++    DSO_NAME_CONVERTER_FUNC name_converter;
++    /*
++     * If this callback function pointer is set to non-NULL, then it will be
++     * used in DSO_load() in place of meth->dso_merger. NB: This should
++     * normally set using DSO_set_merger().
++     */
++    DSO_MERGER_FUNC merger;
++    /*
++     * This is populated with (a copy of) the platform-independent filename
++     * used for this DSO.
++     */
++    char *filename;
++    /*
++     * This is populated with (a copy of) the translated filename by which
++     * the DSO was actually loaded. It is NULL iff the DSO is not currently
++     * loaded. NB: This is here because the filename translation process may
++     * involve a callback being invoked more than once not only to convert to
++     * a platform-specific form, but also to try different filenames in the
++     * process of trying to perform a load. As such, this variable can be
++     * used to indicate (a) whether this DSO structure corresponds to a
++     * loaded library or not, and (b) the filename with which it was actually
++     * loaded.
++     */
++    char *loaded_filename;
++    CRYPTO_RWLOCK *lock;
++};
++
++struct dso_meth_st {
++    const char *name;
++    /*
++     * Loads a shared library, NB: new DSO_METHODs must ensure that a
++     * successful load populates the loaded_filename field, and likewise a
++     * successful unload OPENSSL_frees and NULLs it out.
++     */
++    int (*dso_load) (DSO *dso);
++    /* Unloads a shared library */
++    int (*dso_unload) (DSO *dso);
++    /*
++     * Binds a function - assumes a return type of DSO_FUNC_TYPE. This should
++     * be cast to the real function prototype by the caller. Platforms that
++     * don't have compatible representations for different prototypes (this
++     * is possible within ANSI C) are highly unlikely to have shared
++     * libraries at all, let alone a DSO_METHOD implemented for them.
++     */
++    DSO_FUNC_TYPE (*dso_bind_func) (DSO *dso, const char *symname);
++    /*
++     * The generic (yuck) "ctrl()" function. NB: Negative return values
++     * (rather than zero) indicate errors.
++     */
++    long (*dso_ctrl) (DSO *dso, int cmd, long larg, void *parg);
++    /*
++     * The default DSO_METHOD-specific function for converting filenames to a
++     * canonical native form.
++     */
++    DSO_NAME_CONVERTER_FUNC dso_name_converter;
++    /*
++     * The default DSO_METHOD-specific function for converting filenames to a
++     * canonical native form.
++     */
++    DSO_MERGER_FUNC dso_merger;
++    /* [De]Initialisation handlers. */
++    int (*init) (DSO *dso);
++    int (*finish) (DSO *dso);
++    /* Return pathname of the module containing location */
++    int (*pathbyaddr) (void *addr, char *path, int sz);
++    /* Perform global symbol lookup, i.e. among *all* modules */
++    void *(*globallookup) (const char *symname);
++};
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/dso/dso_openssl.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/dso/dso_openssl.c
+new file mode 100644
+index 0000000..6626331
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/dso/dso_openssl.c
+@@ -0,0 +1,22 @@
++/*
++ * Copyright 2000-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include "dso_locl.h"
++
++#if !defined(DSO_VMS) && !defined(DSO_DLCFN) && !defined(DSO_DL) && !defined(DSO_WIN32) && !defined(DSO_DLFCN)
++
++static DSO_METHOD dso_meth_null = {
++    "NULL shared library method"
++};
++
++DSO_METHOD *DSO_METHOD_openssl(void)
++{
++    return &dso_meth_null;
++}
++#endif
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/dso/dso_vms.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/dso/dso_vms.c
+new file mode 100644
+index 0000000..b9a98dd
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/dso/dso_vms.c
+@@ -0,0 +1,468 @@
++/*
++ * Copyright 2000-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include "dso_locl.h"
++
++#ifdef OPENSSL_SYS_VMS
++
++# pragma message disable DOLLARID
++# include 
++# include 
++# include 
++# include 
++# include 
++# include 
++# include 
++# include "../vms_rms.h"
++
++/* Some compiler options may mask the declaration of "_malloc32". */
++# if __INITIAL_POINTER_SIZE && defined _ANSI_C_SOURCE
++#  if __INITIAL_POINTER_SIZE == 64
++#   pragma pointer_size save
++#   pragma pointer_size 32
++void *_malloc32(__size_t);
++#   pragma pointer_size restore
++#  endif                        /* __INITIAL_POINTER_SIZE == 64 */
++# endif                         /* __INITIAL_POINTER_SIZE && defined
++                                 * _ANSI_C_SOURCE */
++
++# pragma message disable DOLLARID
++
++static int vms_load(DSO *dso);
++static int vms_unload(DSO *dso);
++static DSO_FUNC_TYPE vms_bind_func(DSO *dso, const char *symname);
++static char *vms_name_converter(DSO *dso, const char *filename);
++static char *vms_merger(DSO *dso, const char *filespec1,
++                        const char *filespec2);
++
++static DSO_METHOD dso_meth_vms = {
++    "OpenSSL 'VMS' shared library method",
++    vms_load,
++    NULL,                       /* unload */
++    vms_bind_func,
++    NULL,                       /* ctrl */
++    vms_name_converter,
++    vms_merger,
++    NULL,                       /* init */
++    NULL,                       /* finish */
++    NULL,                       /* pathbyaddr */
++    NULL                        /* globallookup */
++};
++
++/*
++ * On VMS, the only "handle" is the file name.  LIB$FIND_IMAGE_SYMBOL depends
++ * on the reference to the file name being the same for all calls regarding
++ * one shared image, so we'll just store it in an instance of the following
++ * structure and put a pointer to that instance in the meth_data stack.
++ */
++typedef struct dso_internal_st {
++    /*
++     * This should contain the name only, no directory, no extension, nothing
++     * but a name.
++     */
++    struct dsc$descriptor_s filename_dsc;
++    char filename[NAMX_MAXRSS + 1];
++    /*
++     * This contains whatever is not in filename, if needed. Normally not
++     * defined.
++     */
++    struct dsc$descriptor_s imagename_dsc;
++    char imagename[NAMX_MAXRSS + 1];
++} DSO_VMS_INTERNAL;
++
++DSO_METHOD *DSO_METHOD_openssl(void)
++{
++    return &dso_meth_vms;
++}
++
++static int vms_load(DSO *dso)
++{
++    void *ptr = NULL;
++    /* See applicable comments in dso_dl.c */
++    char *filename = DSO_convert_filename(dso, NULL);
++
++/* Ensure 32-bit pointer for "p", and appropriate malloc() function. */
++# if __INITIAL_POINTER_SIZE == 64
++#  define DSO_MALLOC _malloc32
++#  pragma pointer_size save
++#  pragma pointer_size 32
++# else                          /* __INITIAL_POINTER_SIZE == 64 */
++#  define DSO_MALLOC OPENSSL_malloc
++# endif                         /* __INITIAL_POINTER_SIZE == 64 [else] */
++
++    DSO_VMS_INTERNAL *p = NULL;
++
++# if __INITIAL_POINTER_SIZE == 64
++#  pragma pointer_size restore
++# endif                         /* __INITIAL_POINTER_SIZE == 64 */
++
++    const char *sp1, *sp2;      /* Search result */
++    const char *ext = NULL;     /* possible extension to add */
++
++    if (filename == NULL) {
++        DSOerr(DSO_F_VMS_LOAD, DSO_R_NO_FILENAME);
++        goto err;
++    }
++
++    /*-
++     * A file specification may look like this:
++     *
++     *      node::dev:[dir-spec]name.type;ver
++     *
++     * or (for compatibility with TOPS-20):
++     *
++     *      node::dev:name.type;ver
++     *
++     * and the dir-spec uses '.' as separator.  Also, a dir-spec
++     * may consist of several parts, with mixed use of [] and <>:
++     *
++     *      [dir1.]
++     *
++     * We need to split the file specification into the name and
++     * the rest (both before and after the name itself).
++     */
++    /*
++     * Start with trying to find the end of a dir-spec, and save the position
++     * of the byte after in sp1
++     */
++    sp1 = strrchr(filename, ']');
++    sp2 = strrchr(filename, '>');
++    if (sp1 == NULL)
++        sp1 = sp2;
++    if (sp2 != NULL && sp2 > sp1)
++        sp1 = sp2;
++    if (sp1 == NULL)
++        sp1 = strrchr(filename, ':');
++    if (sp1 == NULL)
++        sp1 = filename;
++    else
++        sp1++;                  /* The byte after the found character */
++    /* Now, let's see if there's a type, and save the position in sp2 */
++    sp2 = strchr(sp1, '.');
++    /*
++     * If there is a period and the next character is a semi-colon,
++     * we need to add an extension
++     */
++    if (sp2 != NULL && sp2[1] == ';')
++        ext = ".EXE";
++    /*
++     * If we found it, that's where we'll cut.  Otherwise, look for a version
++     * number and save the position in sp2
++     */
++    if (sp2 == NULL) {
++        sp2 = strchr(sp1, ';');
++        ext = ".EXE";
++    }
++    /*
++     * If there was still nothing to find, set sp2 to point at the end of the
++     * string
++     */
++    if (sp2 == NULL)
++        sp2 = sp1 + strlen(sp1);
++
++    /* Check that we won't get buffer overflows */
++    if (sp2 - sp1 > FILENAME_MAX
++        || (sp1 - filename) + strlen(sp2) > FILENAME_MAX) {
++        DSOerr(DSO_F_VMS_LOAD, DSO_R_FILENAME_TOO_BIG);
++        goto err;
++    }
++
++    p = DSO_MALLOC(sizeof(*p));
++    if (p == NULL) {
++        DSOerr(DSO_F_VMS_LOAD, ERR_R_MALLOC_FAILURE);
++        goto err;
++    }
++
++    strncpy(p->filename, sp1, sp2 - sp1);
++    p->filename[sp2 - sp1] = '\0';
++
++    strncpy(p->imagename, filename, sp1 - filename);
++    p->imagename[sp1 - filename] = '\0';
++    if (ext) {
++        strcat(p->imagename, ext);
++        if (*sp2 == '.')
++            sp2++;
++    }
++    strcat(p->imagename, sp2);
++
++    p->filename_dsc.dsc$w_length = strlen(p->filename);
++    p->filename_dsc.dsc$b_dtype = DSC$K_DTYPE_T;
++    p->filename_dsc.dsc$b_class = DSC$K_CLASS_S;
++    p->filename_dsc.dsc$a_pointer = p->filename;
++    p->imagename_dsc.dsc$w_length = strlen(p->imagename);
++    p->imagename_dsc.dsc$b_dtype = DSC$K_DTYPE_T;
++    p->imagename_dsc.dsc$b_class = DSC$K_CLASS_S;
++    p->imagename_dsc.dsc$a_pointer = p->imagename;
++
++    if (!sk_void_push(dso->meth_data, (char *)p)) {
++        DSOerr(DSO_F_VMS_LOAD, DSO_R_STACK_ERROR);
++        goto err;
++    }
++
++    /* Success (for now, we lie.  We actually do not know...) */
++    dso->loaded_filename = filename;
++    return (1);
++ err:
++    /* Cleanup! */
++    OPENSSL_free(p);
++    OPENSSL_free(filename);
++    return (0);
++}
++
++/*
++ * Note that this doesn't actually unload the shared image, as there is no
++ * such thing in VMS.  Next time it get loaded again, a new copy will
++ * actually be loaded.
++ */
++static int vms_unload(DSO *dso)
++{
++    DSO_VMS_INTERNAL *p;
++    if (dso == NULL) {
++        DSOerr(DSO_F_VMS_UNLOAD, ERR_R_PASSED_NULL_PARAMETER);
++        return (0);
++    }
++    if (sk_void_num(dso->meth_data) < 1)
++        return (1);
++    p = (DSO_VMS_INTERNAL *)sk_void_pop(dso->meth_data);
++    if (p == NULL) {
++        DSOerr(DSO_F_VMS_UNLOAD, DSO_R_NULL_HANDLE);
++        return (0);
++    }
++    /* Cleanup */
++    OPENSSL_free(p);
++    return (1);
++}
++
++/*
++ * We must do this in a separate function because of the way the exception
++ * handler works (it makes this function return
++ */
++static int do_find_symbol(DSO_VMS_INTERNAL *ptr,
++                          struct dsc$descriptor_s *symname_dsc, void **sym,
++                          unsigned long flags)
++{
++    /*
++     * Make sure that signals are caught and returned instead of aborting the
++     * program.  The exception handler gets unestablished automatically on
++     * return from this function.
++     */
++    lib$establish(lib$sig_to_ret);
++
++    if (ptr->imagename_dsc.dsc$w_length)
++        return lib$find_image_symbol(&ptr->filename_dsc,
++                                     symname_dsc, sym,
++                                     &ptr->imagename_dsc, flags);
++    else
++        return lib$find_image_symbol(&ptr->filename_dsc,
++                                     symname_dsc, sym, 0, flags);
++}
++
++void vms_bind_sym(DSO *dso, const char *symname, void **sym)
++{
++    DSO_VMS_INTERNAL *ptr;
++    int status;
++# ifdef LIB$M_FIS_MIXEDCASE
++    int flags = LIB$M_FIS_MIXEDCASE;
++# else
++    int flags = (1 << 4);
++# endif
++    struct dsc$descriptor_s symname_dsc;
++
++/* Arrange 32-bit pointer to (copied) string storage, if needed. */
++# if __INITIAL_POINTER_SIZE == 64
++#  define SYMNAME symname_32p
++#  pragma pointer_size save
++#  pragma pointer_size 32
++    char *symname_32p;
++#  pragma pointer_size restore
++    char symname_32[NAMX_MAXRSS + 1];
++# else                          /* __INITIAL_POINTER_SIZE == 64 */
++#  define SYMNAME ((char *) symname)
++# endif                         /* __INITIAL_POINTER_SIZE == 64 [else] */
++
++    *sym = NULL;
++
++    if ((dso == NULL) || (symname == NULL)) {
++        DSOerr(DSO_F_VMS_BIND_SYM, ERR_R_PASSED_NULL_PARAMETER);
++        return;
++    }
++# if __INITIAL_POINTER_SIZE == 64
++    /* Copy the symbol name to storage with a 32-bit pointer. */
++    symname_32p = symname_32;
++    strcpy(symname_32p, symname);
++# endif                         /* __INITIAL_POINTER_SIZE == 64 [else] */
++
++    symname_dsc.dsc$w_length = strlen(SYMNAME);
++    symname_dsc.dsc$b_dtype = DSC$K_DTYPE_T;
++    symname_dsc.dsc$b_class = DSC$K_CLASS_S;
++    symname_dsc.dsc$a_pointer = SYMNAME;
++
++    if (sk_void_num(dso->meth_data) < 1) {
++        DSOerr(DSO_F_VMS_BIND_SYM, DSO_R_STACK_ERROR);
++        return;
++    }
++    ptr = (DSO_VMS_INTERNAL *)sk_void_value(dso->meth_data,
++                                            sk_void_num(dso->meth_data) - 1);
++    if (ptr == NULL) {
++        DSOerr(DSO_F_VMS_BIND_SYM, DSO_R_NULL_HANDLE);
++        return;
++    }
++
++    if (dso->flags & DSO_FLAG_UPCASE_SYMBOL)
++        flags = 0;
++
++    status = do_find_symbol(ptr, &symname_dsc, sym, flags);
++
++    if (!$VMS_STATUS_SUCCESS(status)) {
++        unsigned short length;
++        char errstring[257];
++        struct dsc$descriptor_s errstring_dsc;
++
++        errstring_dsc.dsc$w_length = sizeof(errstring);
++        errstring_dsc.dsc$b_dtype = DSC$K_DTYPE_T;
++        errstring_dsc.dsc$b_class = DSC$K_CLASS_S;
++        errstring_dsc.dsc$a_pointer = errstring;
++
++        *sym = NULL;
++
++        status = sys$getmsg(status, &length, &errstring_dsc, 1, 0);
++
++        if (!$VMS_STATUS_SUCCESS(status))
++            lib$signal(status); /* This is really bad.  Abort! */
++        else {
++            errstring[length] = '\0';
++
++            DSOerr(DSO_F_VMS_BIND_SYM, DSO_R_SYM_FAILURE);
++            if (ptr->imagename_dsc.dsc$w_length)
++                ERR_add_error_data(9,
++                                   "Symbol ", symname,
++                                   " in ", ptr->filename,
++                                   " (", ptr->imagename, ")",
++                                   ": ", errstring);
++            else
++                ERR_add_error_data(6,
++                                   "Symbol ", symname,
++                                   " in ", ptr->filename, ": ", errstring);
++        }
++        return;
++    }
++    return;
++}
++
++static DSO_FUNC_TYPE vms_bind_func(DSO *dso, const char *symname)
++{
++    DSO_FUNC_TYPE sym = 0;
++    vms_bind_sym(dso, symname, (void **)&sym);
++    return sym;
++}
++
++static char *vms_merger(DSO *dso, const char *filespec1,
++                        const char *filespec2)
++{
++    int status;
++    int filespec1len, filespec2len;
++    struct FAB fab;
++    struct NAMX_STRUCT nam;
++    char esa[NAMX_MAXRSS + 1];
++    char *merged;
++
++/* Arrange 32-bit pointer to (copied) string storage, if needed. */
++# if __INITIAL_POINTER_SIZE == 64
++#  define FILESPEC1 filespec1_32p;
++#  define FILESPEC2 filespec2_32p;
++#  pragma pointer_size save
++#  pragma pointer_size 32
++    char *filespec1_32p;
++    char *filespec2_32p;
++#  pragma pointer_size restore
++    char filespec1_32[NAMX_MAXRSS + 1];
++    char filespec2_32[NAMX_MAXRSS + 1];
++# else                          /* __INITIAL_POINTER_SIZE == 64 */
++#  define FILESPEC1 ((char *) filespec1)
++#  define FILESPEC2 ((char *) filespec2)
++# endif                         /* __INITIAL_POINTER_SIZE == 64 [else] */
++
++    if (!filespec1)
++        filespec1 = "";
++    if (!filespec2)
++        filespec2 = "";
++    filespec1len = strlen(filespec1);
++    filespec2len = strlen(filespec2);
++
++# if __INITIAL_POINTER_SIZE == 64
++    /* Copy the file names to storage with a 32-bit pointer. */
++    filespec1_32p = filespec1_32;
++    filespec2_32p = filespec2_32;
++    strcpy(filespec1_32p, filespec1);
++    strcpy(filespec2_32p, filespec2);
++# endif                         /* __INITIAL_POINTER_SIZE == 64 [else] */
++
++    fab = cc$rms_fab;
++    nam = CC_RMS_NAMX;
++
++    FAB_OR_NAML(fab, nam).FAB_OR_NAML_FNA = FILESPEC1;
++    FAB_OR_NAML(fab, nam).FAB_OR_NAML_FNS = filespec1len;
++    FAB_OR_NAML(fab, nam).FAB_OR_NAML_DNA = FILESPEC2;
++    FAB_OR_NAML(fab, nam).FAB_OR_NAML_DNS = filespec2len;
++    NAMX_DNA_FNA_SET(fab)
++
++        nam.NAMX_ESA = esa;
++    nam.NAMX_ESS = NAMX_MAXRSS;
++    nam.NAMX_NOP = NAM$M_SYNCHK | NAM$M_PWD;
++    SET_NAMX_NO_SHORT_UPCASE(nam);
++
++    fab.FAB_NAMX = &nam;
++
++    status = sys$parse(&fab, 0, 0);
++
++    if (!$VMS_STATUS_SUCCESS(status)) {
++        unsigned short length;
++        char errstring[257];
++        struct dsc$descriptor_s errstring_dsc;
++
++        errstring_dsc.dsc$w_length = sizeof(errstring);
++        errstring_dsc.dsc$b_dtype = DSC$K_DTYPE_T;
++        errstring_dsc.dsc$b_class = DSC$K_CLASS_S;
++        errstring_dsc.dsc$a_pointer = errstring;
++
++        status = sys$getmsg(status, &length, &errstring_dsc, 1, 0);
++
++        if (!$VMS_STATUS_SUCCESS(status))
++            lib$signal(status); /* This is really bad.  Abort! */
++        else {
++            errstring[length] = '\0';
++
++            DSOerr(DSO_F_VMS_MERGER, DSO_R_FAILURE);
++            ERR_add_error_data(7,
++                               "filespec \"", filespec1, "\", ",
++                               "defaults \"", filespec2, "\": ", errstring);
++        }
++        return (NULL);
++    }
++
++    merged = OPENSSL_malloc(nam.NAMX_ESL + 1);
++    if (merged == NULL)
++        goto malloc_err;
++    strncpy(merged, nam.NAMX_ESA, nam.NAMX_ESL);
++    merged[nam.NAMX_ESL] = '\0';
++    return (merged);
++ malloc_err:
++    DSOerr(DSO_F_VMS_MERGER, ERR_R_MALLOC_FAILURE);
++}
++
++static char *vms_name_converter(DSO *dso, const char *filename)
++{
++    int len = strlen(filename);
++    char *not_translated = OPENSSL_malloc(len + 1);
++    if (not_translated != NULL)
++        strcpy(not_translated, filename);
++    return (not_translated);
++}
++
++#endif                          /* OPENSSL_SYS_VMS */
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/dso/dso_win32.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/dso/dso_win32.c
+new file mode 100644
+index 0000000..4a4c34a
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/dso/dso_win32.c
+@@ -0,0 +1,573 @@
++/*
++ * Copyright 2000-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include "dso_locl.h"
++
++#if defined(DSO_WIN32)
++
++# ifdef _WIN32_WCE
++#  if _WIN32_WCE < 300
++static FARPROC GetProcAddressA(HMODULE hModule, LPCSTR lpProcName)
++{
++    WCHAR lpProcNameW[64];
++    int i;
++
++    for (i = 0; lpProcName[i] && i < 64; i++)
++        lpProcNameW[i] = (WCHAR)lpProcName[i];
++    if (i == 64)
++        return NULL;
++    lpProcNameW[i] = 0;
++
++    return GetProcAddressW(hModule, lpProcNameW);
++}
++#  endif
++#  undef GetProcAddress
++#  define GetProcAddress GetProcAddressA
++
++static HINSTANCE LoadLibraryA(LPCSTR lpLibFileName)
++{
++    WCHAR *fnamw;
++    size_t len_0 = strlen(lpLibFileName) + 1, i;
++
++#  ifdef _MSC_VER
++    fnamw = (WCHAR *)_alloca(len_0 * sizeof(WCHAR));
++#  else
++    fnamw = (WCHAR *)alloca(len_0 * sizeof(WCHAR));
++#  endif
++    if (fnamw == NULL) {
++        SetLastError(ERROR_NOT_ENOUGH_MEMORY);
++        return NULL;
++    }
++#  if defined(_WIN32_WCE) && _WIN32_WCE>=101
++    if (!MultiByteToWideChar(CP_ACP, 0, lpLibFileName, len_0, fnamw, len_0))
++#  endif
++        for (i = 0; i < len_0; i++)
++            fnamw[i] = (WCHAR)lpLibFileName[i];
++
++    return LoadLibraryW(fnamw);
++}
++# endif
++
++/* Part of the hack in "win32_load" ... */
++# define DSO_MAX_TRANSLATED_SIZE 256
++
++static int win32_load(DSO *dso);
++static int win32_unload(DSO *dso);
++static DSO_FUNC_TYPE win32_bind_func(DSO *dso, const char *symname);
++static char *win32_name_converter(DSO *dso, const char *filename);
++static char *win32_merger(DSO *dso, const char *filespec1,
++                          const char *filespec2);
++static void *win32_globallookup(const char *name);
++
++static const char *openssl_strnchr(const char *string, int c, size_t len);
++
++static DSO_METHOD dso_meth_win32 = {
++    "OpenSSL 'win32' shared library method",
++    win32_load,
++    win32_unload,
++    win32_bind_func,
++    NULL,                       /* ctrl */
++    win32_name_converter,
++    win32_merger,
++    NULL,                       /* init */
++    NULL,                       /* finish */
++    NULL,                       /* pathbyaddr */
++    win32_globallookup
++};
++
++DSO_METHOD *DSO_METHOD_openssl(void)
++{
++    return &dso_meth_win32;
++}
++
++/*
++ * For this DSO_METHOD, our meth_data STACK will contain; (i) a pointer to
++ * the handle (HINSTANCE) returned from LoadLibrary(), and copied.
++ */
++
++static int win32_load(DSO *dso)
++{
++    HINSTANCE h = NULL, *p = NULL;
++    /* See applicable comments from dso_dl.c */
++    char *filename = DSO_convert_filename(dso, NULL);
++
++    if (filename == NULL) {
++        DSOerr(DSO_F_WIN32_LOAD, DSO_R_NO_FILENAME);
++        goto err;
++    }
++    h = LoadLibraryA(filename);
++    if (h == NULL) {
++        DSOerr(DSO_F_WIN32_LOAD, DSO_R_LOAD_FAILED);
++        ERR_add_error_data(3, "filename(", filename, ")");
++        goto err;
++    }
++    p = OPENSSL_malloc(sizeof(*p));
++    if (p == NULL) {
++        DSOerr(DSO_F_WIN32_LOAD, ERR_R_MALLOC_FAILURE);
++        goto err;
++    }
++    *p = h;
++    if (!sk_void_push(dso->meth_data, p)) {
++        DSOerr(DSO_F_WIN32_LOAD, DSO_R_STACK_ERROR);
++        goto err;
++    }
++    /* Success */
++    dso->loaded_filename = filename;
++    return (1);
++ err:
++    /* Cleanup ! */
++    OPENSSL_free(filename);
++    OPENSSL_free(p);
++    if (h != NULL)
++        FreeLibrary(h);
++    return (0);
++}
++
++static int win32_unload(DSO *dso)
++{
++    HINSTANCE *p;
++    if (dso == NULL) {
++        DSOerr(DSO_F_WIN32_UNLOAD, ERR_R_PASSED_NULL_PARAMETER);
++        return (0);
++    }
++    if (sk_void_num(dso->meth_data) < 1)
++        return (1);
++    p = sk_void_pop(dso->meth_data);
++    if (p == NULL) {
++        DSOerr(DSO_F_WIN32_UNLOAD, DSO_R_NULL_HANDLE);
++        return (0);
++    }
++    if (!FreeLibrary(*p)) {
++        DSOerr(DSO_F_WIN32_UNLOAD, DSO_R_UNLOAD_FAILED);
++        /*
++         * We should push the value back onto the stack in case of a retry.
++         */
++        sk_void_push(dso->meth_data, p);
++        return (0);
++    }
++    /* Cleanup */
++    OPENSSL_free(p);
++    return (1);
++}
++
++static DSO_FUNC_TYPE win32_bind_func(DSO *dso, const char *symname)
++{
++    HINSTANCE *ptr;
++    union {
++        void *p;
++        FARPROC f;
++    } sym;
++
++    if ((dso == NULL) || (symname == NULL)) {
++        DSOerr(DSO_F_WIN32_BIND_FUNC, ERR_R_PASSED_NULL_PARAMETER);
++        return (NULL);
++    }
++    if (sk_void_num(dso->meth_data) < 1) {
++        DSOerr(DSO_F_WIN32_BIND_FUNC, DSO_R_STACK_ERROR);
++        return (NULL);
++    }
++    ptr = sk_void_value(dso->meth_data, sk_void_num(dso->meth_data) - 1);
++    if (ptr == NULL) {
++        DSOerr(DSO_F_WIN32_BIND_FUNC, DSO_R_NULL_HANDLE);
++        return (NULL);
++    }
++    sym.f = GetProcAddress(*ptr, symname);
++    if (sym.p == NULL) {
++        DSOerr(DSO_F_WIN32_BIND_FUNC, DSO_R_SYM_FAILURE);
++        ERR_add_error_data(3, "symname(", symname, ")");
++        return (NULL);
++    }
++    return ((DSO_FUNC_TYPE)sym.f);
++}
++
++struct file_st {
++    const char *node;
++    int nodelen;
++    const char *device;
++    int devicelen;
++    const char *predir;
++    int predirlen;
++    const char *dir;
++    int dirlen;
++    const char *file;
++    int filelen;
++};
++
++static struct file_st *win32_splitter(DSO *dso, const char *filename,
++                                      int assume_last_is_dir)
++{
++    struct file_st *result = NULL;
++    enum { IN_NODE, IN_DEVICE, IN_FILE } position;
++    const char *start = filename;
++    char last;
++
++    if (!filename) {
++        DSOerr(DSO_F_WIN32_SPLITTER, DSO_R_NO_FILENAME);
++        /*
++         * goto err;
++         */
++        return (NULL);
++    }
++
++    result = OPENSSL_zalloc(sizeof(*result));
++    if (result == NULL) {
++        DSOerr(DSO_F_WIN32_SPLITTER, ERR_R_MALLOC_FAILURE);
++        return (NULL);
++    }
++
++    position = IN_DEVICE;
++
++    if ((filename[0] == '\\' && filename[1] == '\\')
++        || (filename[0] == '/' && filename[1] == '/')) {
++        position = IN_NODE;
++        filename += 2;
++        start = filename;
++        result->node = start;
++    }
++
++    do {
++        last = filename[0];
++        switch (last) {
++        case ':':
++            if (position != IN_DEVICE) {
++                DSOerr(DSO_F_WIN32_SPLITTER, DSO_R_INCORRECT_FILE_SYNTAX);
++                /*
++                 * goto err;
++                 */
++                OPENSSL_free(result);
++                return (NULL);
++            }
++            result->device = start;
++            result->devicelen = (int)(filename - start);
++            position = IN_FILE;
++            start = ++filename;
++            result->dir = start;
++            break;
++        case '\\':
++        case '/':
++            if (position == IN_NODE) {
++                result->nodelen = (int)(filename - start);
++                position = IN_FILE;
++                start = ++filename;
++                result->dir = start;
++            } else if (position == IN_DEVICE) {
++                position = IN_FILE;
++                filename++;
++                result->dir = start;
++                result->dirlen = (int)(filename - start);
++                start = filename;
++            } else {
++                filename++;
++                result->dirlen += (int)(filename - start);
++                start = filename;
++            }
++            break;
++        case '\0':
++            if (position == IN_NODE) {
++                result->nodelen = (int)(filename - start);
++            } else {
++                if (filename - start > 0) {
++                    if (assume_last_is_dir) {
++                        if (position == IN_DEVICE) {
++                            result->dir = start;
++                            result->dirlen = 0;
++                        }
++                        result->dirlen += (int)(filename - start);
++                    } else {
++                        result->file = start;
++                        result->filelen = (int)(filename - start);
++                    }
++                }
++            }
++            break;
++        default:
++            filename++;
++            break;
++        }
++    }
++    while (last);
++
++    if (!result->nodelen)
++        result->node = NULL;
++    if (!result->devicelen)
++        result->device = NULL;
++    if (!result->dirlen)
++        result->dir = NULL;
++    if (!result->filelen)
++        result->file = NULL;
++
++    return (result);
++}
++
++static char *win32_joiner(DSO *dso, const struct file_st *file_split)
++{
++    int len = 0, offset = 0;
++    char *result = NULL;
++    const char *start;
++
++    if (!file_split) {
++        DSOerr(DSO_F_WIN32_JOINER, ERR_R_PASSED_NULL_PARAMETER);
++        return (NULL);
++    }
++    if (file_split->node) {
++        len += 2 + file_split->nodelen; /* 2 for starting \\ */
++        if (file_split->predir || file_split->dir || file_split->file)
++            len++;              /* 1 for ending \ */
++    } else if (file_split->device) {
++        len += file_split->devicelen + 1; /* 1 for ending : */
++    }
++    len += file_split->predirlen;
++    if (file_split->predir && (file_split->dir || file_split->file)) {
++        len++;                  /* 1 for ending \ */
++    }
++    len += file_split->dirlen;
++    if (file_split->dir && file_split->file) {
++        len++;                  /* 1 for ending \ */
++    }
++    len += file_split->filelen;
++
++    if (!len) {
++        DSOerr(DSO_F_WIN32_JOINER, DSO_R_EMPTY_FILE_STRUCTURE);
++        return (NULL);
++    }
++
++    result = OPENSSL_malloc(len + 1);
++    if (result == NULL) {
++        DSOerr(DSO_F_WIN32_JOINER, ERR_R_MALLOC_FAILURE);
++        return (NULL);
++    }
++
++    if (file_split->node) {
++        strcpy(&result[offset], "\\\\");
++        offset += 2;
++        strncpy(&result[offset], file_split->node, file_split->nodelen);
++        offset += file_split->nodelen;
++        if (file_split->predir || file_split->dir || file_split->file) {
++            result[offset] = '\\';
++            offset++;
++        }
++    } else if (file_split->device) {
++        strncpy(&result[offset], file_split->device, file_split->devicelen);
++        offset += file_split->devicelen;
++        result[offset] = ':';
++        offset++;
++    }
++    start = file_split->predir;
++    while (file_split->predirlen > (start - file_split->predir)) {
++        const char *end = openssl_strnchr(start, '/',
++                                          file_split->predirlen - (start -
++                                                                   file_split->predir));
++        if (!end)
++            end = start
++                + file_split->predirlen - (start - file_split->predir);
++        strncpy(&result[offset], start, end - start);
++        offset += (int)(end - start);
++        result[offset] = '\\';
++        offset++;
++        start = end + 1;
++    }
++    start = file_split->dir;
++    while (file_split->dirlen > (start - file_split->dir)) {
++        const char *end = openssl_strnchr(start, '/',
++                                          file_split->dirlen - (start -
++                                                                file_split->dir));
++        if (!end)
++            end = start + file_split->dirlen - (start - file_split->dir);
++        strncpy(&result[offset], start, end - start);
++        offset += (int)(end - start);
++        result[offset] = '\\';
++        offset++;
++        start = end + 1;
++    }
++    strncpy(&result[offset], file_split->file, file_split->filelen);
++    offset += file_split->filelen;
++    result[offset] = '\0';
++    return (result);
++}
++
++static char *win32_merger(DSO *dso, const char *filespec1,
++                          const char *filespec2)
++{
++    char *merged = NULL;
++    struct file_st *filespec1_split = NULL;
++    struct file_st *filespec2_split = NULL;
++
++    if (!filespec1 && !filespec2) {
++        DSOerr(DSO_F_WIN32_MERGER, ERR_R_PASSED_NULL_PARAMETER);
++        return (NULL);
++    }
++    if (!filespec2) {
++        merged = OPENSSL_malloc(strlen(filespec1) + 1);
++        if (merged == NULL) {
++            DSOerr(DSO_F_WIN32_MERGER, ERR_R_MALLOC_FAILURE);
++            return (NULL);
++        }
++        strcpy(merged, filespec1);
++    } else if (!filespec1) {
++        merged = OPENSSL_malloc(strlen(filespec2) + 1);
++        if (merged == NULL) {
++            DSOerr(DSO_F_WIN32_MERGER, ERR_R_MALLOC_FAILURE);
++            return (NULL);
++        }
++        strcpy(merged, filespec2);
++    } else {
++        filespec1_split = win32_splitter(dso, filespec1, 0);
++        if (!filespec1_split) {
++            DSOerr(DSO_F_WIN32_MERGER, ERR_R_MALLOC_FAILURE);
++            return (NULL);
++        }
++        filespec2_split = win32_splitter(dso, filespec2, 1);
++        if (!filespec2_split) {
++            DSOerr(DSO_F_WIN32_MERGER, ERR_R_MALLOC_FAILURE);
++            OPENSSL_free(filespec1_split);
++            return (NULL);
++        }
++
++        /* Fill in into filespec1_split */
++        if (!filespec1_split->node && !filespec1_split->device) {
++            filespec1_split->node = filespec2_split->node;
++            filespec1_split->nodelen = filespec2_split->nodelen;
++            filespec1_split->device = filespec2_split->device;
++            filespec1_split->devicelen = filespec2_split->devicelen;
++        }
++        if (!filespec1_split->dir) {
++            filespec1_split->dir = filespec2_split->dir;
++            filespec1_split->dirlen = filespec2_split->dirlen;
++        } else if (filespec1_split->dir[0] != '\\'
++                   && filespec1_split->dir[0] != '/') {
++            filespec1_split->predir = filespec2_split->dir;
++            filespec1_split->predirlen = filespec2_split->dirlen;
++        }
++        if (!filespec1_split->file) {
++            filespec1_split->file = filespec2_split->file;
++            filespec1_split->filelen = filespec2_split->filelen;
++        }
++
++        merged = win32_joiner(dso, filespec1_split);
++    }
++    OPENSSL_free(filespec1_split);
++    OPENSSL_free(filespec2_split);
++    return (merged);
++}
++
++static char *win32_name_converter(DSO *dso, const char *filename)
++{
++    char *translated;
++    int len, transform;
++
++    len = strlen(filename);
++    transform = ((strstr(filename, "/") == NULL) &&
++                 (strstr(filename, "\\") == NULL) &&
++                 (strstr(filename, ":") == NULL));
++    if (transform)
++        /* We will convert this to "%s.dll" */
++        translated = OPENSSL_malloc(len + 5);
++    else
++        /* We will simply duplicate filename */
++        translated = OPENSSL_malloc(len + 1);
++    if (translated == NULL) {
++        DSOerr(DSO_F_WIN32_NAME_CONVERTER, DSO_R_NAME_TRANSLATION_FAILED);
++        return (NULL);
++    }
++    if (transform)
++        sprintf(translated, "%s.dll", filename);
++    else
++        sprintf(translated, "%s", filename);
++    return (translated);
++}
++
++static const char *openssl_strnchr(const char *string, int c, size_t len)
++{
++    size_t i;
++    const char *p;
++    for (i = 0, p = string; i < len && *p; i++, p++) {
++        if (*p == c)
++            return p;
++    }
++    return NULL;
++}
++
++# include 
++# ifdef _WIN32_WCE
++#  define DLLNAME "TOOLHELP.DLL"
++# else
++#  ifdef MODULEENTRY32
++#   undef MODULEENTRY32         /* unmask the ASCII version! */
++#  endif
++#  define DLLNAME "KERNEL32.DLL"
++# endif
++
++typedef HANDLE(WINAPI *CREATETOOLHELP32SNAPSHOT) (DWORD, DWORD);
++typedef BOOL(WINAPI *CLOSETOOLHELP32SNAPSHOT) (HANDLE);
++typedef BOOL(WINAPI *MODULE32) (HANDLE, MODULEENTRY32 *);
++
++static void *win32_globallookup(const char *name)
++{
++    HMODULE dll;
++    HANDLE hModuleSnap = INVALID_HANDLE_VALUE;
++    MODULEENTRY32 me32;
++    CREATETOOLHELP32SNAPSHOT create_snap;
++    CLOSETOOLHELP32SNAPSHOT close_snap;
++    MODULE32 module_first, module_next;
++    union {
++        void *p;
++        FARPROC f;
++    } ret = { NULL };
++
++    dll = LoadLibrary(TEXT(DLLNAME));
++    if (dll == NULL) {
++        DSOerr(DSO_F_WIN32_GLOBALLOOKUP, DSO_R_UNSUPPORTED);
++        return NULL;
++    }
++
++    create_snap = (CREATETOOLHELP32SNAPSHOT)
++        GetProcAddress(dll, "CreateToolhelp32Snapshot");
++    if (create_snap == NULL) {
++        FreeLibrary(dll);
++        DSOerr(DSO_F_WIN32_GLOBALLOOKUP, DSO_R_UNSUPPORTED);
++        return NULL;
++    }
++    /* We take the rest for granted... */
++# ifdef _WIN32_WCE
++    close_snap = (CLOSETOOLHELP32SNAPSHOT)
++        GetProcAddress(dll, "CloseToolhelp32Snapshot");
++# else
++    close_snap = (CLOSETOOLHELP32SNAPSHOT) CloseHandle;
++# endif
++    module_first = (MODULE32) GetProcAddress(dll, "Module32First");
++    module_next = (MODULE32) GetProcAddress(dll, "Module32Next");
++
++    hModuleSnap = (*create_snap) (TH32CS_SNAPMODULE, 0);
++    if (hModuleSnap == INVALID_HANDLE_VALUE) {
++        FreeLibrary(dll);
++        DSOerr(DSO_F_WIN32_GLOBALLOOKUP, DSO_R_UNSUPPORTED);
++        return NULL;
++    }
++
++    me32.dwSize = sizeof(me32);
++
++    if (!(*module_first) (hModuleSnap, &me32)) {
++        (*close_snap) (hModuleSnap);
++        FreeLibrary(dll);
++        return NULL;
++    }
++
++    do {
++        if ((ret.f = GetProcAddress(me32.hModule, name))) {
++            (*close_snap) (hModuleSnap);
++            FreeLibrary(dll);
++            return ret.p;
++        }
++    } while ((*module_next) (hModuleSnap, &me32));
++
++    (*close_snap) (hModuleSnap);
++    FreeLibrary(dll);
++    return NULL;
++}
++#endif                          /* DSO_WIN32 */
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/ebcdic.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/ebcdic.c
+new file mode 100644
+index 0000000..6871953
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/ebcdic.c
+@@ -0,0 +1,366 @@
++/*
++ * Copyright 2000-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++# include 
++#ifndef CHARSET_EBCDIC
++NON_EMPTY_TRANSLATION_UNIT
++#else
++
++# include 
++
++/*-
++ *      Initial Port for  Apache-1.3     by 
++ *      Adapted for       OpenSSL-0.9.4  by 
++ */
++
++# ifdef CHARSET_EBCDIC_TEST
++/*
++ * Here we're looking to test the EBCDIC code on an ASCII system so we don't do
++ * any translation in these tables at all.
++ */
++
++/* The ebcdic-to-ascii table: */
++const unsigned char os_toascii[256] = {
++    0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
++    0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
++    0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
++    0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
++    0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
++    0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
++    0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
++    0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
++    0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
++    0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f,
++    0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57,
++    0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f,
++    0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
++    0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
++    0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77,
++    0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f,
++    0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
++    0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
++    0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
++    0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f,
++    0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,
++    0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf,
++    0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7,
++    0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf,
++    0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7,
++    0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf,
++    0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7,
++    0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf,
++    0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7,
++    0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef,
++    0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7,
++    0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff
++};
++
++/* The ascii-to-ebcdic table: */
++const unsigned char os_toebcdic[256] = {
++    0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
++    0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
++    0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
++    0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
++    0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
++    0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
++    0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
++    0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
++    0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
++    0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f,
++    0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57,
++    0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f,
++    0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
++    0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
++    0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77,
++    0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f,
++    0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
++    0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
++    0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
++    0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f,
++    0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,
++    0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf,
++    0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7,
++    0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf,
++    0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7,
++    0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf,
++    0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7,
++    0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf,
++    0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7,
++    0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef,
++    0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7,
++    0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff
++};
++
++# elif defined(_OSD_POSIX)
++/*
++ * "BS2000 OSD" is a POSIX subsystem on a main frame. It is made by Siemens
++ * AG, Germany, for their BS2000 mainframe machines. Within the POSIX
++ * subsystem, the same character set was chosen as in "native BS2000", namely
++ * EBCDIC. (EDF04)
++ *
++ * The name "ASCII" in these routines is misleading: actually, conversion is
++ * not between EBCDIC and ASCII, but EBCDIC(EDF04) and ISO-8859.1; that means
++ * that (western european) national characters are preserved.
++ *
++ * This table is identical to the one used by rsh/rcp/ftp and other POSIX
++ * tools.
++ */
++
++/* Here's the bijective ebcdic-to-ascii table: */
++const unsigned char os_toascii[256] = {
++    /*
++     * 00
++     */ 0x00, 0x01, 0x02, 0x03, 0x85, 0x09, 0x86, 0x7f,
++    0x87, 0x8d, 0x8e, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* ................ */
++    /*
++     * 10
++     */ 0x10, 0x11, 0x12, 0x13, 0x8f, 0x0a, 0x08, 0x97,
++    0x18, 0x19, 0x9c, 0x9d, 0x1c, 0x1d, 0x1e, 0x1f, /* ................ */
++    /*
++     * 20
++     */ 0x80, 0x81, 0x82, 0x83, 0x84, 0x92, 0x17, 0x1b,
++    0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x05, 0x06, 0x07, /* ................ */
++    /*
++     * 30
++     */ 0x90, 0x91, 0x16, 0x93, 0x94, 0x95, 0x96, 0x04,
++    0x98, 0x99, 0x9a, 0x9b, 0x14, 0x15, 0x9e, 0x1a, /* ................ */
++    /*
++     * 40
++     */ 0x20, 0xa0, 0xe2, 0xe4, 0xe0, 0xe1, 0xe3, 0xe5,
++    0xe7, 0xf1, 0x60, 0x2e, 0x3c, 0x28, 0x2b, 0x7c, /* .........`.<(+| */
++    /*
++     * 50
++     */ 0x26, 0xe9, 0xea, 0xeb, 0xe8, 0xed, 0xee, 0xef,
++    0xec, 0xdf, 0x21, 0x24, 0x2a, 0x29, 0x3b, 0x9f, /* &.........!$*);. */
++    /*
++     * 60
++     */ 0x2d, 0x2f, 0xc2, 0xc4, 0xc0, 0xc1, 0xc3, 0xc5,
++    0xc7, 0xd1, 0x5e, 0x2c, 0x25, 0x5f, 0x3e, 0x3f,    /*-/........^,%_>?*/
++    /*
++     * 70
++     */ 0xf8, 0xc9, 0xca, 0xcb, 0xc8, 0xcd, 0xce, 0xcf,
++    0xcc, 0xa8, 0x3a, 0x23, 0x40, 0x27, 0x3d, 0x22, /* ..........:#@'=" */
++    /*
++     * 80
++     */ 0xd8, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
++    0x68, 0x69, 0xab, 0xbb, 0xf0, 0xfd, 0xfe, 0xb1, /* .abcdefghi...... */
++    /*
++     * 90
++     */ 0xb0, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, 0x70,
++    0x71, 0x72, 0xaa, 0xba, 0xe6, 0xb8, 0xc6, 0xa4, /* .jklmnopqr...... */
++    /*
++     * a0
++     */ 0xb5, 0xaf, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78,
++    0x79, 0x7a, 0xa1, 0xbf, 0xd0, 0xdd, 0xde, 0xae, /* ..stuvwxyz...... */
++    /*
++     * b0
++     */ 0xa2, 0xa3, 0xa5, 0xb7, 0xa9, 0xa7, 0xb6, 0xbc,
++    0xbd, 0xbe, 0xac, 0x5b, 0x5c, 0x5d, 0xb4, 0xd7, /* ...........[\].. */
++    /*
++     * c0
++     */ 0xf9, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
++    0x48, 0x49, 0xad, 0xf4, 0xf6, 0xf2, 0xf3, 0xf5, /* .ABCDEFGHI...... */
++    /*
++     * d0
++     */ 0xa6, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, 0x50,
++    0x51, 0x52, 0xb9, 0xfb, 0xfc, 0xdb, 0xfa, 0xff, /* .JKLMNOPQR...... */
++    /*
++     * e0
++     */ 0xd9, 0xf7, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58,
++    0x59, 0x5a, 0xb2, 0xd4, 0xd6, 0xd2, 0xd3, 0xd5, /* ..STUVWXYZ...... */
++    /*
++     * f0
++     */ 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
++    0x38, 0x39, 0xb3, 0x7b, 0xdc, 0x7d, 0xda, 0x7e /* 0123456789.{.}.~ */
++};
++
++/* The ascii-to-ebcdic table: */
++const unsigned char os_toebcdic[256] = {
++    /*
++     * 00
++     */ 0x00, 0x01, 0x02, 0x03, 0x37, 0x2d, 0x2e, 0x2f,
++    0x16, 0x05, 0x15, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* ................ */
++    /*
++     * 10
++     */ 0x10, 0x11, 0x12, 0x13, 0x3c, 0x3d, 0x32, 0x26,
++    0x18, 0x19, 0x3f, 0x27, 0x1c, 0x1d, 0x1e, 0x1f, /* ................ */
++    /*
++     * 20
++     */ 0x40, 0x5a, 0x7f, 0x7b, 0x5b, 0x6c, 0x50, 0x7d,
++    0x4d, 0x5d, 0x5c, 0x4e, 0x6b, 0x60, 0x4b, 0x61, /* !"#$%&'()*+,-./ */
++    /*
++     * 30
++     */ 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7,
++    0xf8, 0xf9, 0x7a, 0x5e, 0x4c, 0x7e, 0x6e, 0x6f, /* 0123456789:;<=>? */
++    /*
++     * 40
++     */ 0x7c, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7,
++    0xc8, 0xc9, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, /* @ABCDEFGHIJKLMNO */
++    /*
++     * 50
++     */ 0xd7, 0xd8, 0xd9, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6,
++    0xe7, 0xe8, 0xe9, 0xbb, 0xbc, 0xbd, 0x6a, 0x6d, /* PQRSTUVWXYZ[\]^_ */
++    /*
++     * 60
++     */ 0x4a, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
++    0x88, 0x89, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, /* `abcdefghijklmno */
++    /*
++     * 70
++     */ 0x97, 0x98, 0x99, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6,
++    0xa7, 0xa8, 0xa9, 0xfb, 0x4f, 0xfd, 0xff, 0x07, /* pqrstuvwxyz{|}~. */
++    /*
++     * 80
++     */ 0x20, 0x21, 0x22, 0x23, 0x24, 0x04, 0x06, 0x08,
++    0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x09, 0x0a, 0x14, /* ................ */
++    /*
++     * 90
++     */ 0x30, 0x31, 0x25, 0x33, 0x34, 0x35, 0x36, 0x17,
++    0x38, 0x39, 0x3a, 0x3b, 0x1a, 0x1b, 0x3e, 0x5f, /* ................ */
++    /*
++     * a0
++     */ 0x41, 0xaa, 0xb0, 0xb1, 0x9f, 0xb2, 0xd0, 0xb5,
++    0x79, 0xb4, 0x9a, 0x8a, 0xba, 0xca, 0xaf, 0xa1, /* ................ */
++    /*
++     * b0
++     */ 0x90, 0x8f, 0xea, 0xfa, 0xbe, 0xa0, 0xb6, 0xb3,
++    0x9d, 0xda, 0x9b, 0x8b, 0xb7, 0xb8, 0xb9, 0xab, /* ................ */
++    /*
++     * c0
++     */ 0x64, 0x65, 0x62, 0x66, 0x63, 0x67, 0x9e, 0x68,
++    0x74, 0x71, 0x72, 0x73, 0x78, 0x75, 0x76, 0x77, /* ................ */
++    /*
++     * d0
++     */ 0xac, 0x69, 0xed, 0xee, 0xeb, 0xef, 0xec, 0xbf,
++    0x80, 0xe0, 0xfe, 0xdd, 0xfc, 0xad, 0xae, 0x59, /* ................ */
++    /*
++     * e0
++     */ 0x44, 0x45, 0x42, 0x46, 0x43, 0x47, 0x9c, 0x48,
++    0x54, 0x51, 0x52, 0x53, 0x58, 0x55, 0x56, 0x57, /* ................ */
++    /*
++     * f0
++     */ 0x8c, 0x49, 0xcd, 0xce, 0xcb, 0xcf, 0xcc, 0xe1,
++    0x70, 0xc0, 0xde, 0xdb, 0xdc, 0x8d, 0x8e, 0xdf /* ................ */
++};
++
++# else /*_OSD_POSIX*/
++
++/*
++ * This code does basic character mapping for IBM's TPF and OS/390 operating
++ * systems. It is a modified version of the BS2000 table.
++ *
++ * Bijective EBCDIC (character set IBM-1047) to US-ASCII table: This table is
++ * bijective - there are no ambiguous or duplicate characters.
++ */
++const unsigned char os_toascii[256] = {
++    0x00, 0x01, 0x02, 0x03, 0x85, 0x09, 0x86, 0x7f, /* 00-0f: */
++    0x87, 0x8d, 0x8e, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* ................ */
++    0x10, 0x11, 0x12, 0x13, 0x8f, 0x0a, 0x08, 0x97, /* 10-1f: */
++    0x18, 0x19, 0x9c, 0x9d, 0x1c, 0x1d, 0x1e, 0x1f, /* ................ */
++    0x80, 0x81, 0x82, 0x83, 0x84, 0x92, 0x17, 0x1b, /* 20-2f: */
++    0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x05, 0x06, 0x07, /* ................ */
++    0x90, 0x91, 0x16, 0x93, 0x94, 0x95, 0x96, 0x04, /* 30-3f: */
++    0x98, 0x99, 0x9a, 0x9b, 0x14, 0x15, 0x9e, 0x1a, /* ................ */
++    0x20, 0xa0, 0xe2, 0xe4, 0xe0, 0xe1, 0xe3, 0xe5, /* 40-4f: */
++    0xe7, 0xf1, 0xa2, 0x2e, 0x3c, 0x28, 0x2b, 0x7c, /* ...........<(+| */
++    0x26, 0xe9, 0xea, 0xeb, 0xe8, 0xed, 0xee, 0xef, /* 50-5f: */
++    0xec, 0xdf, 0x21, 0x24, 0x2a, 0x29, 0x3b, 0x5e, /* &.........!$*);^ */
++    0x2d, 0x2f, 0xc2, 0xc4, 0xc0, 0xc1, 0xc3, 0xc5, /* 60-6f: */
++    0xc7, 0xd1, 0xa6, 0x2c, 0x25, 0x5f, 0x3e, 0x3f, /* -/.........,%_>? */
++    0xf8, 0xc9, 0xca, 0xcb, 0xc8, 0xcd, 0xce, 0xcf, /* 70-7f: */
++    0xcc, 0x60, 0x3a, 0x23, 0x40, 0x27, 0x3d, 0x22, /* .........`:#@'=" */
++    0xd8, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, /* 80-8f: */
++    0x68, 0x69, 0xab, 0xbb, 0xf0, 0xfd, 0xfe, 0xb1, /* .abcdefghi...... */
++    0xb0, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, 0x70, /* 90-9f: */
++    0x71, 0x72, 0xaa, 0xba, 0xe6, 0xb8, 0xc6, 0xa4, /* .jklmnopqr...... */
++    0xb5, 0x7e, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, /* a0-af: */
++    0x79, 0x7a, 0xa1, 0xbf, 0xd0, 0x5b, 0xde, 0xae, /* .~stuvwxyz...[.. */
++    0xac, 0xa3, 0xa5, 0xb7, 0xa9, 0xa7, 0xb6, 0xbc, /* b0-bf: */
++    0xbd, 0xbe, 0xdd, 0xa8, 0xaf, 0x5d, 0xb4, 0xd7, /* .............].. */
++    0x7b, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* c0-cf: */
++    0x48, 0x49, 0xad, 0xf4, 0xf6, 0xf2, 0xf3, 0xf5, /* {ABCDEFGHI...... */
++    0x7d, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, 0x50, /* d0-df: */
++    0x51, 0x52, 0xb9, 0xfb, 0xfc, 0xf9, 0xfa, 0xff, /* }JKLMNOPQR...... */
++    0x5c, 0xf7, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, /* e0-ef: */
++    0x59, 0x5a, 0xb2, 0xd4, 0xd6, 0xd2, 0xd3, 0xd5, /* \.STUVWXYZ...... */
++    0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, /* f0-ff: */
++    0x38, 0x39, 0xb3, 0xdb, 0xdc, 0xd9, 0xda, 0x9f /* 0123456789...... */
++};
++
++/*
++ * The US-ASCII to EBCDIC (character set IBM-1047) table: This table is
++ * bijective (no ambiguous or duplicate characters)
++ */
++const unsigned char os_toebcdic[256] = {
++    0x00, 0x01, 0x02, 0x03, 0x37, 0x2d, 0x2e, 0x2f, /* 00-0f: */
++    0x16, 0x05, 0x15, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* ................ */
++    0x10, 0x11, 0x12, 0x13, 0x3c, 0x3d, 0x32, 0x26, /* 10-1f: */
++    0x18, 0x19, 0x3f, 0x27, 0x1c, 0x1d, 0x1e, 0x1f, /* ................ */
++    0x40, 0x5a, 0x7f, 0x7b, 0x5b, 0x6c, 0x50, 0x7d, /* 20-2f: */
++    0x4d, 0x5d, 0x5c, 0x4e, 0x6b, 0x60, 0x4b, 0x61, /* !"#$%&'()*+,-./ */
++    0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, /* 30-3f: */
++    0xf8, 0xf9, 0x7a, 0x5e, 0x4c, 0x7e, 0x6e, 0x6f, /* 0123456789:;<=>? */
++    0x7c, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, /* 40-4f: */
++    0xc8, 0xc9, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, /* @ABCDEFGHIJKLMNO */
++    0xd7, 0xd8, 0xd9, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, /* 50-5f: */
++    0xe7, 0xe8, 0xe9, 0xad, 0xe0, 0xbd, 0x5f, 0x6d, /* PQRSTUVWXYZ[\]^_ */
++    0x79, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, /* 60-6f: */
++    0x88, 0x89, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, /* `abcdefghijklmno */
++    0x97, 0x98, 0x99, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, /* 70-7f: */
++    0xa7, 0xa8, 0xa9, 0xc0, 0x4f, 0xd0, 0xa1, 0x07, /* pqrstuvwxyz{|}~. */
++    0x20, 0x21, 0x22, 0x23, 0x24, 0x04, 0x06, 0x08, /* 80-8f: */
++    0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x09, 0x0a, 0x14, /* ................ */
++    0x30, 0x31, 0x25, 0x33, 0x34, 0x35, 0x36, 0x17, /* 90-9f: */
++    0x38, 0x39, 0x3a, 0x3b, 0x1a, 0x1b, 0x3e, 0xff, /* ................ */
++    0x41, 0xaa, 0x4a, 0xb1, 0x9f, 0xb2, 0x6a, 0xb5, /* a0-af: */
++    0xbb, 0xb4, 0x9a, 0x8a, 0xb0, 0xca, 0xaf, 0xbc, /* ................ */
++    0x90, 0x8f, 0xea, 0xfa, 0xbe, 0xa0, 0xb6, 0xb3, /* b0-bf: */
++    0x9d, 0xda, 0x9b, 0x8b, 0xb7, 0xb8, 0xb9, 0xab, /* ................ */
++    0x64, 0x65, 0x62, 0x66, 0x63, 0x67, 0x9e, 0x68, /* c0-cf: */
++    0x74, 0x71, 0x72, 0x73, 0x78, 0x75, 0x76, 0x77, /* ................ */
++    0xac, 0x69, 0xed, 0xee, 0xeb, 0xef, 0xec, 0xbf, /* d0-df: */
++    0x80, 0xfd, 0xfe, 0xfb, 0xfc, 0xba, 0xae, 0x59, /* ................ */
++    0x44, 0x45, 0x42, 0x46, 0x43, 0x47, 0x9c, 0x48, /* e0-ef: */
++    0x54, 0x51, 0x52, 0x53, 0x58, 0x55, 0x56, 0x57, /* ................ */
++    0x8c, 0x49, 0xcd, 0xce, 0xcb, 0xcf, 0xcc, 0xe1, /* f0-ff: */
++    0x70, 0xdd, 0xde, 0xdb, 0xdc, 0x8d, 0x8e, 0xdf /* ................ */
++};
++# endif/*_OSD_POSIX*/
++
++/*
++ * Translate a memory block from EBCDIC (host charset) to ASCII (net charset)
++ * dest and srce may be identical, or separate memory blocks, but should not
++ * overlap. These functions intentionally have an interface compatible to
++ * memcpy(3).
++ */
++
++void *ebcdic2ascii(void *dest, const void *srce, size_t count)
++{
++    unsigned char *udest = dest;
++    const unsigned char *usrce = srce;
++
++    while (count-- != 0) {
++        *udest++ = os_toascii[*usrce++];
++    }
++
++    return dest;
++}
++
++void *ascii2ebcdic(void *dest, const void *srce, size_t count)
++{
++    unsigned char *udest = dest;
++    const unsigned char *usrce = srce;
++
++    while (count-- != 0) {
++        *udest++ = os_toebcdic[*usrce++];
++    }
++
++    return dest;
++}
++
++#endif
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/ec/asm/ecp_nistz256-armv4.pl b/CryptoPkg/Library/OpensslLib/openssl/crypto/ec/asm/ecp_nistz256-armv4.pl
+new file mode 100755
+index 0000000..2314b75
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/ec/asm/ecp_nistz256-armv4.pl
+@@ -0,0 +1,1865 @@
++#! /usr/bin/env perl
++# Copyright 2015-2016 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
++# in the file LICENSE in the source distribution or at
++# https://www.openssl.org/source/license.html
++
++
++# ====================================================================
++# Written by Andy Polyakov  for the OpenSSL
++# project. The module is, however, dual licensed under OpenSSL and
++# CRYPTOGAMS licenses depending on where you obtain it. For further
++# details see http://www.openssl.org/~appro/cryptogams/.
++# ====================================================================
++#
++# ECP_NISTZ256 module for ARMv4.
++#
++# October 2014.
++#
++# Original ECP_NISTZ256 submission targeting x86_64 is detailed in
++# http://eprint.iacr.org/2013/816. In the process of adaptation
++# original .c module was made 32-bit savvy in order to make this
++# implementation possible.
++#
++#			with/without -DECP_NISTZ256_ASM
++# Cortex-A8		+53-170%
++# Cortex-A9		+76-205%
++# Cortex-A15		+100-316%
++# Snapdragon S4		+66-187%
++#
++# Ranges denote minimum and maximum improvement coefficients depending
++# on benchmark. Lower coefficients are for ECDSA sign, server-side
++# operation. Keep in mind that +200% means 3x improvement.
++
++$flavour = shift;
++if ($flavour=~/\w[\w\-]*\.\w+$/) { $output=$flavour; undef $flavour; }
++else { while (($output=shift) && ($output!~/\w[\w\-]*\.\w+$/)) {} }
++
++if ($flavour && $flavour ne "void") {
++    $0 =~ m/(.*[\/\\])[^\/\\]+$/; $dir=$1;
++    ( $xlate="${dir}arm-xlate.pl" and -f $xlate ) or
++    ( $xlate="${dir}../../perlasm/arm-xlate.pl" and -f $xlate) or
++    die "can't locate arm-xlate.pl";
++
++    open STDOUT,"| \"$^X\" $xlate $flavour $output";
++} else {
++    open STDOUT,">$output";
++}
++
++$code.=<<___;
++#include "arm_arch.h"
++
++.text
++#if defined(__thumb2__)
++.syntax	unified
++.thumb
++#else
++.code	32
++#endif
++___
++########################################################################
++# Convert ecp_nistz256_table.c to layout expected by ecp_nistz_gather_w7
++#
++$0 =~ m/(.*[\/\\])[^\/\\]+$/; $dir=$1;
++open TABLE,") {
++	s/TOBN\(\s*(0x[0-9a-f]+),\s*(0x[0-9a-f]+)\s*\)/push @arr,hex($2),hex($1)/geo;
++}
++close TABLE;
++
++# See ecp_nistz256_table.c for explanation for why it's 64*16*37.
++# 64*16*37-1 is because $#arr returns last valid index or @arr, not
++# amount of elements.
++die "insane number of elements" if ($#arr != 64*16*37-1);
++
++$code.=<<___;
++.globl	ecp_nistz256_precomputed
++.type	ecp_nistz256_precomputed,%object
++.align	12
++ecp_nistz256_precomputed:
++___
++########################################################################
++# this conversion smashes P256_POINT_AFFINE by individual bytes with
++# 64 byte interval, similar to
++#	1111222233334444
++#	1234123412341234
++for(1..37) {
++	@tbl = splice(@arr,0,64*16);
++	for($i=0;$i<64;$i++) {
++		undef @line;
++		for($j=0;$j<64;$j++) {
++			push @line,(@tbl[$j*16+$i/4]>>(($i%4)*8))&0xff;
++		}
++		$code.=".byte\t";
++		$code.=join(',',map { sprintf "0x%02x",$_} @line);
++		$code.="\n";
++	}
++}
++$code.=<<___;
++.size	ecp_nistz256_precomputed,.-ecp_nistz256_precomputed
++.align	5
++.LRR:	@ 2^512 mod P precomputed for NIST P256 polynomial
++.long	0x00000003, 0x00000000, 0xffffffff, 0xfffffffb
++.long	0xfffffffe, 0xffffffff, 0xfffffffd, 0x00000004
++.Lone:
++.long	1,0,0,0,0,0,0,0
++.asciz	"ECP_NISTZ256 for ARMv4, CRYPTOGAMS by "
++.align	6
++___
++
++########################################################################
++# common register layout, note that $t2 is link register, so that if
++# internal subroutine uses $t2, then it has to offload lr...
++
++($r_ptr,$a_ptr,$b_ptr,$ff,$a0,$a1,$a2,$a3,$a4,$a5,$a6,$a7,$t1,$t2)=
++		map("r$_",(0..12,14));
++($t0,$t3)=($ff,$a_ptr);
++
++$code.=<<___;
++@ void	ecp_nistz256_to_mont(BN_ULONG r0[8],const BN_ULONG r1[8]);
++.globl	ecp_nistz256_to_mont
++.type	ecp_nistz256_to_mont,%function
++ecp_nistz256_to_mont:
++	adr	$b_ptr,.LRR
++	b	.Lecp_nistz256_mul_mont
++.size	ecp_nistz256_to_mont,.-ecp_nistz256_to_mont
++
++@ void	ecp_nistz256_from_mont(BN_ULONG r0[8],const BN_ULONG r1[8]);
++.globl	ecp_nistz256_from_mont
++.type	ecp_nistz256_from_mont,%function
++ecp_nistz256_from_mont:
++	adr	$b_ptr,.Lone
++	b	.Lecp_nistz256_mul_mont
++.size	ecp_nistz256_from_mont,.-ecp_nistz256_from_mont
++
++@ void	ecp_nistz256_mul_by_2(BN_ULONG r0[8],const BN_ULONG r1[8]);
++.globl	ecp_nistz256_mul_by_2
++.type	ecp_nistz256_mul_by_2,%function
++.align	4
++ecp_nistz256_mul_by_2:
++	stmdb	sp!,{r4-r12,lr}
++	bl	__ecp_nistz256_mul_by_2
++#if __ARM_ARCH__>=5 || !defined(__thumb__)
++	ldmia	sp!,{r4-r12,pc}
++#else
++	ldmia	sp!,{r4-r12,lr}
++	bx	lr			@ interoperable with Thumb ISA:-)
++#endif
++.size	ecp_nistz256_mul_by_2,.-ecp_nistz256_mul_by_2
++
++.type	__ecp_nistz256_mul_by_2,%function
++.align	4
++__ecp_nistz256_mul_by_2:
++	ldr	$a0,[$a_ptr,#0]
++	ldr	$a1,[$a_ptr,#4]
++	ldr	$a2,[$a_ptr,#8]
++	adds	$a0,$a0,$a0		@ a[0:7]+=a[0:7], i.e. add with itself
++	ldr	$a3,[$a_ptr,#12]
++	adcs	$a1,$a1,$a1
++	ldr	$a4,[$a_ptr,#16]
++	adcs	$a2,$a2,$a2
++	ldr	$a5,[$a_ptr,#20]
++	adcs	$a3,$a3,$a3
++	ldr	$a6,[$a_ptr,#24]
++	adcs	$a4,$a4,$a4
++	ldr	$a7,[$a_ptr,#28]
++	adcs	$a5,$a5,$a5
++	adcs	$a6,$a6,$a6
++	mov	$ff,#0
++	adcs	$a7,$a7,$a7
++	adc	$ff,$ff,#0
++
++	b	.Lreduce_by_sub
++.size	__ecp_nistz256_mul_by_2,.-__ecp_nistz256_mul_by_2
++
++@ void	ecp_nistz256_add(BN_ULONG r0[8],const BN_ULONG r1[8],
++@					const BN_ULONG r2[8]);
++.globl	ecp_nistz256_add
++.type	ecp_nistz256_add,%function
++.align	4
++ecp_nistz256_add:
++	stmdb	sp!,{r4-r12,lr}
++	bl	__ecp_nistz256_add
++#if __ARM_ARCH__>=5 || !defined(__thumb__)
++	ldmia	sp!,{r4-r12,pc}
++#else
++	ldmia	sp!,{r4-r12,lr}
++	bx	lr			@ interoperable with Thumb ISA:-)
++#endif
++.size	ecp_nistz256_add,.-ecp_nistz256_add
++
++.type	__ecp_nistz256_add,%function
++.align	4
++__ecp_nistz256_add:
++	str	lr,[sp,#-4]!		@ push lr
++
++	ldr	$a0,[$a_ptr,#0]
++	ldr	$a1,[$a_ptr,#4]
++	ldr	$a2,[$a_ptr,#8]
++	ldr	$a3,[$a_ptr,#12]
++	ldr	$a4,[$a_ptr,#16]
++	 ldr	$t0,[$b_ptr,#0]
++	ldr	$a5,[$a_ptr,#20]
++	 ldr	$t1,[$b_ptr,#4]
++	ldr	$a6,[$a_ptr,#24]
++	 ldr	$t2,[$b_ptr,#8]
++	ldr	$a7,[$a_ptr,#28]
++	 ldr	$t3,[$b_ptr,#12]
++	adds	$a0,$a0,$t0
++	 ldr	$t0,[$b_ptr,#16]
++	adcs	$a1,$a1,$t1
++	 ldr	$t1,[$b_ptr,#20]
++	adcs	$a2,$a2,$t2
++	 ldr	$t2,[$b_ptr,#24]
++	adcs	$a3,$a3,$t3
++	 ldr	$t3,[$b_ptr,#28]
++	adcs	$a4,$a4,$t0
++	adcs	$a5,$a5,$t1
++	adcs	$a6,$a6,$t2
++	mov	$ff,#0
++	adcs	$a7,$a7,$t3
++	adc	$ff,$ff,#0
++	ldr	lr,[sp],#4		@ pop lr
++
++.Lreduce_by_sub:
++
++	@ if a+b >= modulus, subtract modulus.
++	@
++	@ But since comparison implies subtraction, we subtract
++	@ modulus and then add it back if subraction borrowed.
++
++	subs	$a0,$a0,#-1
++	sbcs	$a1,$a1,#-1
++	sbcs	$a2,$a2,#-1
++	sbcs	$a3,$a3,#0
++	sbcs	$a4,$a4,#0
++	sbcs	$a5,$a5,#0
++	sbcs	$a6,$a6,#1
++	sbcs	$a7,$a7,#-1
++	sbc	$ff,$ff,#0
++
++	@ Note that because mod has special form, i.e. consists of
++	@ 0xffffffff, 1 and 0s, we can conditionally synthesize it by
++	@ using value of borrow as a whole or extracting single bit.
++	@ Follow $ff register...
++
++	adds	$a0,$a0,$ff		@ add synthesized modulus
++	adcs	$a1,$a1,$ff
++	str	$a0,[$r_ptr,#0]
++	adcs	$a2,$a2,$ff
++	str	$a1,[$r_ptr,#4]
++	adcs	$a3,$a3,#0
++	str	$a2,[$r_ptr,#8]
++	adcs	$a4,$a4,#0
++	str	$a3,[$r_ptr,#12]
++	adcs	$a5,$a5,#0
++	str	$a4,[$r_ptr,#16]
++	adcs	$a6,$a6,$ff,lsr#31
++	str	$a5,[$r_ptr,#20]
++	adcs	$a7,$a7,$ff
++	str	$a6,[$r_ptr,#24]
++	str	$a7,[$r_ptr,#28]
++
++	mov	pc,lr
++.size	__ecp_nistz256_add,.-__ecp_nistz256_add
++
++@ void	ecp_nistz256_mul_by_3(BN_ULONG r0[8],const BN_ULONG r1[8]);
++.globl	ecp_nistz256_mul_by_3
++.type	ecp_nistz256_mul_by_3,%function
++.align	4
++ecp_nistz256_mul_by_3:
++	stmdb	sp!,{r4-r12,lr}
++	bl	__ecp_nistz256_mul_by_3
++#if __ARM_ARCH__>=5 || !defined(__thumb__)
++	ldmia	sp!,{r4-r12,pc}
++#else
++	ldmia	sp!,{r4-r12,lr}
++	bx	lr			@ interoperable with Thumb ISA:-)
++#endif
++.size	ecp_nistz256_mul_by_3,.-ecp_nistz256_mul_by_3
++
++.type	__ecp_nistz256_mul_by_3,%function
++.align	4
++__ecp_nistz256_mul_by_3:
++	str	lr,[sp,#-4]!		@ push lr
++
++	@ As multiplication by 3 is performed as 2*n+n, below are inline
++	@ copies of __ecp_nistz256_mul_by_2 and __ecp_nistz256_add, see
++	@ corresponding subroutines for details.
++
++	ldr	$a0,[$a_ptr,#0]
++	ldr	$a1,[$a_ptr,#4]
++	ldr	$a2,[$a_ptr,#8]
++	adds	$a0,$a0,$a0		@ a[0:7]+=a[0:7]
++	ldr	$a3,[$a_ptr,#12]
++	adcs	$a1,$a1,$a1
++	ldr	$a4,[$a_ptr,#16]
++	adcs	$a2,$a2,$a2
++	ldr	$a5,[$a_ptr,#20]
++	adcs	$a3,$a3,$a3
++	ldr	$a6,[$a_ptr,#24]
++	adcs	$a4,$a4,$a4
++	ldr	$a7,[$a_ptr,#28]
++	adcs	$a5,$a5,$a5
++	adcs	$a6,$a6,$a6
++	mov	$ff,#0
++	adcs	$a7,$a7,$a7
++	adc	$ff,$ff,#0
++
++	subs	$a0,$a0,#-1		@ .Lreduce_by_sub but without stores
++	sbcs	$a1,$a1,#-1
++	sbcs	$a2,$a2,#-1
++	sbcs	$a3,$a3,#0
++	sbcs	$a4,$a4,#0
++	sbcs	$a5,$a5,#0
++	sbcs	$a6,$a6,#1
++	sbcs	$a7,$a7,#-1
++	sbc	$ff,$ff,#0
++
++	adds	$a0,$a0,$ff		@ add synthesized modulus
++	adcs	$a1,$a1,$ff
++	adcs	$a2,$a2,$ff
++	adcs	$a3,$a3,#0
++	adcs	$a4,$a4,#0
++	 ldr	$b_ptr,[$a_ptr,#0]
++	adcs	$a5,$a5,#0
++	 ldr	$t1,[$a_ptr,#4]
++	adcs	$a6,$a6,$ff,lsr#31
++	 ldr	$t2,[$a_ptr,#8]
++	adc	$a7,$a7,$ff
++
++	ldr	$t0,[$a_ptr,#12]
++	adds	$a0,$a0,$b_ptr		@ 2*a[0:7]+=a[0:7]
++	ldr	$b_ptr,[$a_ptr,#16]
++	adcs	$a1,$a1,$t1
++	ldr	$t1,[$a_ptr,#20]
++	adcs	$a2,$a2,$t2
++	ldr	$t2,[$a_ptr,#24]
++	adcs	$a3,$a3,$t0
++	ldr	$t3,[$a_ptr,#28]
++	adcs	$a4,$a4,$b_ptr
++	adcs	$a5,$a5,$t1
++	adcs	$a6,$a6,$t2
++	mov	$ff,#0
++	adcs	$a7,$a7,$t3
++	adc	$ff,$ff,#0
++	ldr	lr,[sp],#4		@ pop lr
++
++	b	.Lreduce_by_sub
++.size	ecp_nistz256_mul_by_3,.-ecp_nistz256_mul_by_3
++
++@ void	ecp_nistz256_div_by_2(BN_ULONG r0[8],const BN_ULONG r1[8]);
++.globl	ecp_nistz256_div_by_2
++.type	ecp_nistz256_div_by_2,%function
++.align	4
++ecp_nistz256_div_by_2:
++	stmdb	sp!,{r4-r12,lr}
++	bl	__ecp_nistz256_div_by_2
++#if __ARM_ARCH__>=5 || !defined(__thumb__)
++	ldmia	sp!,{r4-r12,pc}
++#else
++	ldmia	sp!,{r4-r12,lr}
++	bx	lr			@ interoperable with Thumb ISA:-)
++#endif
++.size	ecp_nistz256_div_by_2,.-ecp_nistz256_div_by_2
++
++.type	__ecp_nistz256_div_by_2,%function
++.align	4
++__ecp_nistz256_div_by_2:
++	@ ret = (a is odd ? a+mod : a) >> 1
++
++	ldr	$a0,[$a_ptr,#0]
++	ldr	$a1,[$a_ptr,#4]
++	ldr	$a2,[$a_ptr,#8]
++	mov	$ff,$a0,lsl#31		@ place least significant bit to most
++					@ significant position, now arithmetic
++					@ right shift by 31 will produce -1 or
++					@ 0, while logical right shift 1 or 0,
++					@ this is how modulus is conditionally
++					@ synthesized in this case...
++	ldr	$a3,[$a_ptr,#12]
++	adds	$a0,$a0,$ff,asr#31
++	ldr	$a4,[$a_ptr,#16]
++	adcs	$a1,$a1,$ff,asr#31
++	ldr	$a5,[$a_ptr,#20]
++	adcs	$a2,$a2,$ff,asr#31
++	ldr	$a6,[$a_ptr,#24]
++	adcs	$a3,$a3,#0
++	ldr	$a7,[$a_ptr,#28]
++	adcs	$a4,$a4,#0
++	 mov	$a0,$a0,lsr#1		@ a[0:7]>>=1, we can start early
++					@ because it doesn't affect flags
++	adcs	$a5,$a5,#0
++	 orr	$a0,$a0,$a1,lsl#31
++	adcs	$a6,$a6,$ff,lsr#31
++	mov	$b_ptr,#0
++	adcs	$a7,$a7,$ff,asr#31
++	 mov	$a1,$a1,lsr#1
++	adc	$b_ptr,$b_ptr,#0	@ top-most carry bit from addition
++
++	orr	$a1,$a1,$a2,lsl#31
++	mov	$a2,$a2,lsr#1
++	str	$a0,[$r_ptr,#0]
++	orr	$a2,$a2,$a3,lsl#31
++	mov	$a3,$a3,lsr#1
++	str	$a1,[$r_ptr,#4]
++	orr	$a3,$a3,$a4,lsl#31
++	mov	$a4,$a4,lsr#1
++	str	$a2,[$r_ptr,#8]
++	orr	$a4,$a4,$a5,lsl#31
++	mov	$a5,$a5,lsr#1
++	str	$a3,[$r_ptr,#12]
++	orr	$a5,$a5,$a6,lsl#31
++	mov	$a6,$a6,lsr#1
++	str	$a4,[$r_ptr,#16]
++	orr	$a6,$a6,$a7,lsl#31
++	mov	$a7,$a7,lsr#1
++	str	$a5,[$r_ptr,#20]
++	orr	$a7,$a7,$b_ptr,lsl#31	@ don't forget the top-most carry bit
++	str	$a6,[$r_ptr,#24]
++	str	$a7,[$r_ptr,#28]
++
++	mov	pc,lr
++.size	__ecp_nistz256_div_by_2,.-__ecp_nistz256_div_by_2
++
++@ void	ecp_nistz256_sub(BN_ULONG r0[8],const BN_ULONG r1[8],
++@				        const BN_ULONG r2[8]);
++.globl	ecp_nistz256_sub
++.type	ecp_nistz256_sub,%function
++.align	4
++ecp_nistz256_sub:
++	stmdb	sp!,{r4-r12,lr}
++	bl	__ecp_nistz256_sub
++#if __ARM_ARCH__>=5 || !defined(__thumb__)
++	ldmia	sp!,{r4-r12,pc}
++#else
++	ldmia	sp!,{r4-r12,lr}
++	bx	lr			@ interoperable with Thumb ISA:-)
++#endif
++.size	ecp_nistz256_sub,.-ecp_nistz256_sub
++
++.type	__ecp_nistz256_sub,%function
++.align	4
++__ecp_nistz256_sub:
++	str	lr,[sp,#-4]!		@ push lr
++
++	ldr	$a0,[$a_ptr,#0]
++	ldr	$a1,[$a_ptr,#4]
++	ldr	$a2,[$a_ptr,#8]
++	ldr	$a3,[$a_ptr,#12]
++	ldr	$a4,[$a_ptr,#16]
++	 ldr	$t0,[$b_ptr,#0]
++	ldr	$a5,[$a_ptr,#20]
++	 ldr	$t1,[$b_ptr,#4]
++	ldr	$a6,[$a_ptr,#24]
++	 ldr	$t2,[$b_ptr,#8]
++	ldr	$a7,[$a_ptr,#28]
++	 ldr	$t3,[$b_ptr,#12]
++	subs	$a0,$a0,$t0
++	 ldr	$t0,[$b_ptr,#16]
++	sbcs	$a1,$a1,$t1
++	 ldr	$t1,[$b_ptr,#20]
++	sbcs	$a2,$a2,$t2
++	 ldr	$t2,[$b_ptr,#24]
++	sbcs	$a3,$a3,$t3
++	 ldr	$t3,[$b_ptr,#28]
++	sbcs	$a4,$a4,$t0
++	sbcs	$a5,$a5,$t1
++	sbcs	$a6,$a6,$t2
++	sbcs	$a7,$a7,$t3
++	sbc	$ff,$ff,$ff		@ broadcast borrow bit
++	ldr	lr,[sp],#4		@ pop lr
++
++.Lreduce_by_add:
++
++	@ if a-b borrows, add modulus.
++	@
++	@ Note that because mod has special form, i.e. consists of
++	@ 0xffffffff, 1 and 0s, we can conditionally synthesize it by
++	@ broadcasting borrow bit to a register, $ff, and using it as
++	@ a whole or extracting single bit.
++
++	adds	$a0,$a0,$ff		@ add synthesized modulus
++	adcs	$a1,$a1,$ff
++	str	$a0,[$r_ptr,#0]
++	adcs	$a2,$a2,$ff
++	str	$a1,[$r_ptr,#4]
++	adcs	$a3,$a3,#0
++	str	$a2,[$r_ptr,#8]
++	adcs	$a4,$a4,#0
++	str	$a3,[$r_ptr,#12]
++	adcs	$a5,$a5,#0
++	str	$a4,[$r_ptr,#16]
++	adcs	$a6,$a6,$ff,lsr#31
++	str	$a5,[$r_ptr,#20]
++	adcs	$a7,$a7,$ff
++	str	$a6,[$r_ptr,#24]
++	str	$a7,[$r_ptr,#28]
++
++	mov	pc,lr
++.size	__ecp_nistz256_sub,.-__ecp_nistz256_sub
++
++@ void	ecp_nistz256_neg(BN_ULONG r0[8],const BN_ULONG r1[8]);
++.globl	ecp_nistz256_neg
++.type	ecp_nistz256_neg,%function
++.align	4
++ecp_nistz256_neg:
++	stmdb	sp!,{r4-r12,lr}
++	bl	__ecp_nistz256_neg
++#if __ARM_ARCH__>=5 || !defined(__thumb__)
++	ldmia	sp!,{r4-r12,pc}
++#else
++	ldmia	sp!,{r4-r12,lr}
++	bx	lr			@ interoperable with Thumb ISA:-)
++#endif
++.size	ecp_nistz256_neg,.-ecp_nistz256_neg
++
++.type	__ecp_nistz256_neg,%function
++.align	4
++__ecp_nistz256_neg:
++	ldr	$a0,[$a_ptr,#0]
++	eor	$ff,$ff,$ff
++	ldr	$a1,[$a_ptr,#4]
++	ldr	$a2,[$a_ptr,#8]
++	subs	$a0,$ff,$a0
++	ldr	$a3,[$a_ptr,#12]
++	sbcs	$a1,$ff,$a1
++	ldr	$a4,[$a_ptr,#16]
++	sbcs	$a2,$ff,$a2
++	ldr	$a5,[$a_ptr,#20]
++	sbcs	$a3,$ff,$a3
++	ldr	$a6,[$a_ptr,#24]
++	sbcs	$a4,$ff,$a4
++	ldr	$a7,[$a_ptr,#28]
++	sbcs	$a5,$ff,$a5
++	sbcs	$a6,$ff,$a6
++	sbcs	$a7,$ff,$a7
++	sbc	$ff,$ff,$ff
++
++	b	.Lreduce_by_add
++.size	__ecp_nistz256_neg,.-__ecp_nistz256_neg
++___
++{
++my @acc=map("r$_",(3..11));
++my ($t0,$t1,$bj,$t2,$t3)=map("r$_",(0,1,2,12,14));
++
++$code.=<<___;
++@ void	ecp_nistz256_sqr_mont(BN_ULONG r0[8],const BN_ULONG r1[8]);
++.globl	ecp_nistz256_sqr_mont
++.type	ecp_nistz256_sqr_mont,%function
++.align	4
++ecp_nistz256_sqr_mont:
++	mov	$b_ptr,$a_ptr
++	b	.Lecp_nistz256_mul_mont
++.size	ecp_nistz256_sqr_mont,.-ecp_nistz256_sqr_mont
++
++@ void	ecp_nistz256_mul_mont(BN_ULONG r0[8],const BN_ULONG r1[8],
++@					     const BN_ULONG r2[8]);
++.globl	ecp_nistz256_mul_mont
++.type	ecp_nistz256_mul_mont,%function
++.align	4
++ecp_nistz256_mul_mont:
++.Lecp_nistz256_mul_mont:
++	stmdb	sp!,{r4-r12,lr}
++	bl	__ecp_nistz256_mul_mont
++#if __ARM_ARCH__>=5 || !defined(__thumb__)
++	ldmia	sp!,{r4-r12,pc}
++#else
++	ldmia	sp!,{r4-r12,lr}
++	bx	lr			@ interoperable with Thumb ISA:-)
++#endif
++.size	ecp_nistz256_mul_mont,.-ecp_nistz256_mul_mont
++
++.type	__ecp_nistz256_mul_mont,%function
++.align	4
++__ecp_nistz256_mul_mont:
++	stmdb	sp!,{r0-r2,lr}			@ make a copy of arguments too
++
++	ldr	$bj,[$b_ptr,#0]			@ b[0]
++	ldmia	$a_ptr,{@acc[1]-@acc[8]}
++
++	umull	@acc[0],$t3,@acc[1],$bj		@ r[0]=a[0]*b[0]
++	stmdb	sp!,{$acc[1]-@acc[8]}		@ copy a[0-7] to stack, so
++						@ that it can be addressed
++						@ without spending register
++						@ on address
++	umull	@acc[1],$t0,@acc[2],$bj		@ r[1]=a[1]*b[0]
++	umull	@acc[2],$t1,@acc[3],$bj
++	adds	@acc[1],@acc[1],$t3		@ accumulate high part of mult
++	umull	@acc[3],$t2,@acc[4],$bj
++	adcs	@acc[2],@acc[2],$t0
++	umull	@acc[4],$t3,@acc[5],$bj
++	adcs	@acc[3],@acc[3],$t1
++	umull	@acc[5],$t0,@acc[6],$bj
++	adcs	@acc[4],@acc[4],$t2
++	umull	@acc[6],$t1,@acc[7],$bj
++	adcs	@acc[5],@acc[5],$t3
++	umull	@acc[7],$t2,@acc[8],$bj
++	adcs	@acc[6],@acc[6],$t0
++	adcs	@acc[7],@acc[7],$t1
++	eor	$t3,$t3,$t3			@ first overflow bit is zero
++	adc	@acc[8],$t2,#0
++___
++for(my $i=1;$i<8;$i++) {
++my $t4=@acc[0];
++
++	# Reduction iteration is normally performed by accumulating
++	# result of multiplication of modulus by "magic" digit [and
++	# omitting least significant word, which is guaranteed to
++	# be 0], but thanks to special form of modulus and "magic"
++	# digit being equal to least significant word, it can be
++	# performed with additions and subtractions alone. Indeed:
++	#
++	#        ffff.0001.0000.0000.0000.ffff.ffff.ffff
++	# *                                         abcd
++	# + xxxx.xxxx.xxxx.xxxx.xxxx.xxxx.xxxx.xxxx.abcd
++	#
++	# Now observing that ff..ff*x = (2^n-1)*x = 2^n*x-x, we
++	# rewrite above as:
++	#
++	#   xxxx.xxxx.xxxx.xxxx.xxxx.xxxx.xxxx.xxxx.abcd
++	# + abcd.0000.abcd.0000.0000.abcd.0000.0000.0000
++	# -      abcd.0000.0000.0000.0000.0000.0000.abcd
++	#
++	# or marking redundant operations:
++	#
++	#   xxxx.xxxx.xxxx.xxxx.xxxx.xxxx.xxxx.xxxx.----
++	# + abcd.0000.abcd.0000.0000.abcd.----.----.----
++	# -      abcd.----.----.----.----.----.----.----
++
++$code.=<<___;
++	@ multiplication-less reduction $i
++	adds	@acc[3],@acc[3],@acc[0]		@ r[3]+=r[0]
++	 ldr	$bj,[sp,#40]			@ restore b_ptr
++	adcs	@acc[4],@acc[4],#0		@ r[4]+=0
++	adcs	@acc[5],@acc[5],#0		@ r[5]+=0
++	adcs	@acc[6],@acc[6],@acc[0]		@ r[6]+=r[0]
++	 ldr	$t1,[sp,#0]			@ load a[0]
++	adcs	@acc[7],@acc[7],#0		@ r[7]+=0
++	 ldr	$bj,[$bj,#4*$i]			@ load b[i]
++	adcs	@acc[8],@acc[8],@acc[0]		@ r[8]+=r[0]
++	 eor	$t0,$t0,$t0
++	adc	$t3,$t3,#0			@ overflow bit
++	subs	@acc[7],@acc[7],@acc[0]		@ r[7]-=r[0]
++	 ldr	$t2,[sp,#4]			@ a[1]
++	sbcs	@acc[8],@acc[8],#0		@ r[8]-=0
++	 umlal	@acc[1],$t0,$t1,$bj		@ "r[0]"+=a[0]*b[i]
++	 eor	$t1,$t1,$t1
++	sbc	@acc[0],$t3,#0			@ overflow bit, keep in mind
++						@ that netto result is
++						@ addition of a value which
++						@ makes underflow impossible
++
++	ldr	$t3,[sp,#8]			@ a[2]
++	umlal	@acc[2],$t1,$t2,$bj		@ "r[1]"+=a[1]*b[i]
++	 str	@acc[0],[sp,#36]		@ temporarily offload overflow
++	eor	$t2,$t2,$t2
++	ldr	$t4,[sp,#12]			@ a[3], $t4 is alias @acc[0]
++	umlal	@acc[3],$t2,$t3,$bj		@ "r[2]"+=a[2]*b[i]
++	eor	$t3,$t3,$t3
++	adds	@acc[2],@acc[2],$t0		@ accumulate high part of mult
++	ldr	$t0,[sp,#16]			@ a[4]
++	umlal	@acc[4],$t3,$t4,$bj		@ "r[3]"+=a[3]*b[i]
++	eor	$t4,$t4,$t4
++	adcs	@acc[3],@acc[3],$t1
++	ldr	$t1,[sp,#20]			@ a[5]
++	umlal	@acc[5],$t4,$t0,$bj		@ "r[4]"+=a[4]*b[i]
++	eor	$t0,$t0,$t0
++	adcs	@acc[4],@acc[4],$t2
++	ldr	$t2,[sp,#24]			@ a[6]
++	umlal	@acc[6],$t0,$t1,$bj		@ "r[5]"+=a[5]*b[i]
++	eor	$t1,$t1,$t1
++	adcs	@acc[5],@acc[5],$t3
++	ldr	$t3,[sp,#28]			@ a[7]
++	umlal	@acc[7],$t1,$t2,$bj		@ "r[6]"+=a[6]*b[i]
++	eor	$t2,$t2,$t2
++	adcs	@acc[6],@acc[6],$t4
++	 ldr	@acc[0],[sp,#36]		@ restore overflow bit
++	umlal	@acc[8],$t2,$t3,$bj		@ "r[7]"+=a[7]*b[i]
++	eor	$t3,$t3,$t3
++	adcs	@acc[7],@acc[7],$t0
++	adcs	@acc[8],@acc[8],$t1
++	adcs	@acc[0],$acc[0],$t2
++	adc	$t3,$t3,#0			@ new overflow bit
++___
++	push(@acc,shift(@acc));			# rotate registers, so that
++						# "r[i]" becomes r[i]
++}
++$code.=<<___;
++	@ last multiplication-less reduction
++	adds	@acc[3],@acc[3],@acc[0]
++	ldr	$r_ptr,[sp,#32]			@ restore r_ptr
++	adcs	@acc[4],@acc[4],#0
++	adcs	@acc[5],@acc[5],#0
++	adcs	@acc[6],@acc[6],@acc[0]
++	adcs	@acc[7],@acc[7],#0
++	adcs	@acc[8],@acc[8],@acc[0]
++	adc	$t3,$t3,#0
++	subs	@acc[7],@acc[7],@acc[0]
++	sbcs	@acc[8],@acc[8],#0
++	sbc	@acc[0],$t3,#0			@ overflow bit
++
++	@ Final step is "if result > mod, subtract mod", but we do it
++	@ "other way around", namely subtract modulus from result
++	@ and if it borrowed, add modulus back.
++
++	adds	@acc[1],@acc[1],#1		@ subs	@acc[1],@acc[1],#-1
++	adcs	@acc[2],@acc[2],#0		@ sbcs	@acc[2],@acc[2],#-1
++	adcs	@acc[3],@acc[3],#0		@ sbcs	@acc[3],@acc[3],#-1
++	sbcs	@acc[4],@acc[4],#0
++	sbcs	@acc[5],@acc[5],#0
++	sbcs	@acc[6],@acc[6],#0
++	sbcs	@acc[7],@acc[7],#1
++	adcs	@acc[8],@acc[8],#0		@ sbcs	@acc[8],@acc[8],#-1
++	ldr	lr,[sp,#44]			@ restore lr
++	sbc	@acc[0],@acc[0],#0		@ broadcast borrow bit
++	add	sp,sp,#48
++
++	@ Note that because mod has special form, i.e. consists of
++	@ 0xffffffff, 1 and 0s, we can conditionally synthesize it by
++	@ broadcasting borrow bit to a register, @acc[0], and using it as
++	@ a whole or extracting single bit.
++
++	adds	@acc[1],@acc[1],@acc[0]		@ add modulus or zero
++	adcs	@acc[2],@acc[2],@acc[0]
++	str	@acc[1],[$r_ptr,#0]
++	adcs	@acc[3],@acc[3],@acc[0]
++	str	@acc[2],[$r_ptr,#4]
++	adcs	@acc[4],@acc[4],#0
++	str	@acc[3],[$r_ptr,#8]
++	adcs	@acc[5],@acc[5],#0
++	str	@acc[4],[$r_ptr,#12]
++	adcs	@acc[6],@acc[6],#0
++	str	@acc[5],[$r_ptr,#16]
++	adcs	@acc[7],@acc[7],@acc[0],lsr#31
++	str	@acc[6],[$r_ptr,#20]
++	adc	@acc[8],@acc[8],@acc[0]
++	str	@acc[7],[$r_ptr,#24]
++	str	@acc[8],[$r_ptr,#28]
++
++	mov	pc,lr
++.size	__ecp_nistz256_mul_mont,.-__ecp_nistz256_mul_mont
++___
++}
++
++{
++my ($out,$inp,$index,$mask)=map("r$_",(0..3));
++$code.=<<___;
++@ void	ecp_nistz256_scatter_w5(void *r0,const P256_POINT *r1,
++@					 int r2);
++.globl	ecp_nistz256_scatter_w5
++.type	ecp_nistz256_scatter_w5,%function
++.align	5
++ecp_nistz256_scatter_w5:
++	stmdb	sp!,{r4-r11}
++
++	add	$out,$out,$index,lsl#2
++
++	ldmia	$inp!,{r4-r11}		@ X
++	str	r4,[$out,#64*0-4]
++	str	r5,[$out,#64*1-4]
++	str	r6,[$out,#64*2-4]
++	str	r7,[$out,#64*3-4]
++	str	r8,[$out,#64*4-4]
++	str	r9,[$out,#64*5-4]
++	str	r10,[$out,#64*6-4]
++	str	r11,[$out,#64*7-4]
++	add	$out,$out,#64*8
++
++	ldmia	$inp!,{r4-r11}		@ Y
++	str	r4,[$out,#64*0-4]
++	str	r5,[$out,#64*1-4]
++	str	r6,[$out,#64*2-4]
++	str	r7,[$out,#64*3-4]
++	str	r8,[$out,#64*4-4]
++	str	r9,[$out,#64*5-4]
++	str	r10,[$out,#64*6-4]
++	str	r11,[$out,#64*7-4]
++	add	$out,$out,#64*8
++
++	ldmia	$inp,{r4-r11}		@ Z
++	str	r4,[$out,#64*0-4]
++	str	r5,[$out,#64*1-4]
++	str	r6,[$out,#64*2-4]
++	str	r7,[$out,#64*3-4]
++	str	r8,[$out,#64*4-4]
++	str	r9,[$out,#64*5-4]
++	str	r10,[$out,#64*6-4]
++	str	r11,[$out,#64*7-4]
++
++	ldmia	sp!,{r4-r11}
++#if __ARM_ARCH__>=5 || defined(__thumb__)
++	bx	lr
++#else
++	mov	pc,lr
++#endif
++.size	ecp_nistz256_scatter_w5,.-ecp_nistz256_scatter_w5
++
++@ void	ecp_nistz256_gather_w5(P256_POINT *r0,const void *r1,
++@					      int r2);
++.globl	ecp_nistz256_gather_w5
++.type	ecp_nistz256_gather_w5,%function
++.align	5
++ecp_nistz256_gather_w5:
++	stmdb	sp!,{r4-r11}
++
++	cmp	$index,#0
++	mov	$mask,#0
++#ifdef	__thumb2__
++	itt	ne
++#endif
++	subne	$index,$index,#1
++	movne	$mask,#-1
++	add	$inp,$inp,$index,lsl#2
++
++	ldr	r4,[$inp,#64*0]
++	ldr	r5,[$inp,#64*1]
++	ldr	r6,[$inp,#64*2]
++	and	r4,r4,$mask
++	ldr	r7,[$inp,#64*3]
++	and	r5,r5,$mask
++	ldr	r8,[$inp,#64*4]
++	and	r6,r6,$mask
++	ldr	r9,[$inp,#64*5]
++	and	r7,r7,$mask
++	ldr	r10,[$inp,#64*6]
++	and	r8,r8,$mask
++	ldr	r11,[$inp,#64*7]
++	add	$inp,$inp,#64*8
++	and	r9,r9,$mask
++	and	r10,r10,$mask
++	and	r11,r11,$mask
++	stmia	$out!,{r4-r11}	@ X
++
++	ldr	r4,[$inp,#64*0]
++	ldr	r5,[$inp,#64*1]
++	ldr	r6,[$inp,#64*2]
++	and	r4,r4,$mask
++	ldr	r7,[$inp,#64*3]
++	and	r5,r5,$mask
++	ldr	r8,[$inp,#64*4]
++	and	r6,r6,$mask
++	ldr	r9,[$inp,#64*5]
++	and	r7,r7,$mask
++	ldr	r10,[$inp,#64*6]
++	and	r8,r8,$mask
++	ldr	r11,[$inp,#64*7]
++	add	$inp,$inp,#64*8
++	and	r9,r9,$mask
++	and	r10,r10,$mask
++	and	r11,r11,$mask
++	stmia	$out!,{r4-r11}	@ Y
++
++	ldr	r4,[$inp,#64*0]
++	ldr	r5,[$inp,#64*1]
++	ldr	r6,[$inp,#64*2]
++	and	r4,r4,$mask
++	ldr	r7,[$inp,#64*3]
++	and	r5,r5,$mask
++	ldr	r8,[$inp,#64*4]
++	and	r6,r6,$mask
++	ldr	r9,[$inp,#64*5]
++	and	r7,r7,$mask
++	ldr	r10,[$inp,#64*6]
++	and	r8,r8,$mask
++	ldr	r11,[$inp,#64*7]
++	and	r9,r9,$mask
++	and	r10,r10,$mask
++	and	r11,r11,$mask
++	stmia	$out,{r4-r11}		@ Z
++
++	ldmia	sp!,{r4-r11}
++#if __ARM_ARCH__>=5 || defined(__thumb__)
++	bx	lr
++#else
++	mov	pc,lr
++#endif
++.size	ecp_nistz256_gather_w5,.-ecp_nistz256_gather_w5
++
++@ void	ecp_nistz256_scatter_w7(void *r0,const P256_POINT_AFFINE *r1,
++@					 int r2);
++.globl	ecp_nistz256_scatter_w7
++.type	ecp_nistz256_scatter_w7,%function
++.align	5
++ecp_nistz256_scatter_w7:
++	add	$out,$out,$index
++	mov	$index,#64/4
++.Loop_scatter_w7:
++	ldr	$mask,[$inp],#4
++	subs	$index,$index,#1
++	strb	$mask,[$out,#64*0-1]
++	mov	$mask,$mask,lsr#8
++	strb	$mask,[$out,#64*1-1]
++	mov	$mask,$mask,lsr#8
++	strb	$mask,[$out,#64*2-1]
++	mov	$mask,$mask,lsr#8
++	strb	$mask,[$out,#64*3-1]
++	add	$out,$out,#64*4
++	bne	.Loop_scatter_w7
++
++#if __ARM_ARCH__>=5 || defined(__thumb__)
++	bx	lr
++#else
++	mov	pc,lr
++#endif
++.size	ecp_nistz256_scatter_w7,.-ecp_nistz256_scatter_w7
++
++@ void	ecp_nistz256_gather_w7(P256_POINT_AFFINE *r0,const void *r1,
++@						     int r2);
++.globl	ecp_nistz256_gather_w7
++.type	ecp_nistz256_gather_w7,%function
++.align	5
++ecp_nistz256_gather_w7:
++	stmdb	sp!,{r4-r7}
++
++	cmp	$index,#0
++	mov	$mask,#0
++#ifdef	__thumb2__
++	itt	ne
++#endif
++	subne	$index,$index,#1
++	movne	$mask,#-1
++	add	$inp,$inp,$index
++	mov	$index,#64/4
++	nop
++.Loop_gather_w7:
++	ldrb	r4,[$inp,#64*0]
++	subs	$index,$index,#1
++	ldrb	r5,[$inp,#64*1]
++	ldrb	r6,[$inp,#64*2]
++	ldrb	r7,[$inp,#64*3]
++	add	$inp,$inp,#64*4
++	orr	r4,r4,r5,lsl#8
++	orr	r4,r4,r6,lsl#16
++	orr	r4,r4,r7,lsl#24
++	and	r4,r4,$mask
++	str	r4,[$out],#4
++	bne	.Loop_gather_w7
++
++	ldmia	sp!,{r4-r7}
++#if __ARM_ARCH__>=5 || defined(__thumb__)
++	bx	lr
++#else
++	mov	pc,lr
++#endif
++.size	ecp_nistz256_gather_w7,.-ecp_nistz256_gather_w7
++___
++}
++if (0) {
++# In comparison to integer-only equivalent of below subroutine:
++#
++# Cortex-A8	+10%
++# Cortex-A9	-10%
++# Snapdragon S4	+5%
++#
++# As not all time is spent in multiplication, overall impact is deemed
++# too low to care about.
++
++my ($A0,$A1,$A2,$A3,$Bi,$zero,$temp)=map("d$_",(0..7));
++my $mask="q4";
++my $mult="q5";
++my @AxB=map("q$_",(8..15));
++
++my ($rptr,$aptr,$bptr,$toutptr)=map("r$_",(0..3));
++
++$code.=<<___;
++#if __ARM_ARCH__>=7
++.fpu	neon
++
++.globl	ecp_nistz256_mul_mont_neon
++.type	ecp_nistz256_mul_mont_neon,%function
++.align	5
++ecp_nistz256_mul_mont_neon:
++	mov	ip,sp
++	stmdb	sp!,{r4-r9}
++	vstmdb	sp!,{q4-q5}		@ ABI specification says so
++
++	sub		$toutptr,sp,#40
++	vld1.32		{${Bi}[0]},[$bptr,:32]!
++	veor		$zero,$zero,$zero
++	vld1.32		{$A0-$A3}, [$aptr]		@ can't specify :32 :-(
++	vzip.16		$Bi,$zero
++	mov		sp,$toutptr			@ alloca
++	vmov.i64	$mask,#0xffff
++
++	vmull.u32	@AxB[0],$Bi,${A0}[0]
++	vmull.u32	@AxB[1],$Bi,${A0}[1]
++	vmull.u32	@AxB[2],$Bi,${A1}[0]
++	vmull.u32	@AxB[3],$Bi,${A1}[1]
++	 vshr.u64	$temp,@AxB[0]#lo,#16
++	vmull.u32	@AxB[4],$Bi,${A2}[0]
++	 vadd.u64	@AxB[0]#hi,@AxB[0]#hi,$temp
++	vmull.u32	@AxB[5],$Bi,${A2}[1]
++	 vshr.u64	$temp,@AxB[0]#hi,#16		@ upper 32 bits of a[0]*b[0]
++	vmull.u32	@AxB[6],$Bi,${A3}[0]
++	 vand.u64	@AxB[0],@AxB[0],$mask		@ lower 32 bits of a[0]*b[0]
++	vmull.u32	@AxB[7],$Bi,${A3}[1]
++___
++for($i=1;$i<8;$i++) {
++$code.=<<___;
++	 vld1.32	{${Bi}[0]},[$bptr,:32]!
++	 veor		$zero,$zero,$zero
++	vadd.u64	@AxB[1]#lo,@AxB[1]#lo,$temp	@ reduction
++	vshl.u64	$mult,@AxB[0],#32
++	vadd.u64	@AxB[3],@AxB[3],@AxB[0]
++	vsub.u64	$mult,$mult,@AxB[0]
++	 vzip.16	$Bi,$zero
++	vadd.u64	@AxB[6],@AxB[6],@AxB[0]
++	vadd.u64	@AxB[7],@AxB[7],$mult
++___
++	push(@AxB,shift(@AxB));
++$code.=<<___;
++	vmlal.u32	@AxB[0],$Bi,${A0}[0]
++	vmlal.u32	@AxB[1],$Bi,${A0}[1]
++	vmlal.u32	@AxB[2],$Bi,${A1}[0]
++	vmlal.u32	@AxB[3],$Bi,${A1}[1]
++	 vshr.u64	$temp,@AxB[0]#lo,#16
++	vmlal.u32	@AxB[4],$Bi,${A2}[0]
++	 vadd.u64	@AxB[0]#hi,@AxB[0]#hi,$temp
++	vmlal.u32	@AxB[5],$Bi,${A2}[1]
++	 vshr.u64	$temp,@AxB[0]#hi,#16		@ upper 33 bits of a[0]*b[i]+t[0]
++	vmlal.u32	@AxB[6],$Bi,${A3}[0]
++	 vand.u64	@AxB[0],@AxB[0],$mask		@ lower 32 bits of a[0]*b[0]
++	vmull.u32	@AxB[7],$Bi,${A3}[1]
++___
++}
++$code.=<<___;
++	vadd.u64	@AxB[1]#lo,@AxB[1]#lo,$temp	@ last reduction
++	vshl.u64	$mult,@AxB[0],#32
++	vadd.u64	@AxB[3],@AxB[3],@AxB[0]
++	vsub.u64	$mult,$mult,@AxB[0]
++	vadd.u64	@AxB[6],@AxB[6],@AxB[0]
++	vadd.u64	@AxB[7],@AxB[7],$mult
++
++	vshr.u64	$temp,@AxB[1]#lo,#16		@ convert
++	vadd.u64	@AxB[1]#hi,@AxB[1]#hi,$temp
++	vshr.u64	$temp,@AxB[1]#hi,#16
++	vzip.16		@AxB[1]#lo,@AxB[1]#hi
++___
++foreach (2..7) {
++$code.=<<___;
++	vadd.u64	@AxB[$_]#lo,@AxB[$_]#lo,$temp
++	vst1.32		{@AxB[$_-1]#lo[0]},[$toutptr,:32]!
++	vshr.u64	$temp,@AxB[$_]#lo,#16
++	vadd.u64	@AxB[$_]#hi,@AxB[$_]#hi,$temp
++	vshr.u64	$temp,@AxB[$_]#hi,#16
++	vzip.16		@AxB[$_]#lo,@AxB[$_]#hi
++___
++}
++$code.=<<___;
++	vst1.32		{@AxB[7]#lo[0]},[$toutptr,:32]!
++	vst1.32		{$temp},[$toutptr]		@ upper 33 bits
++
++	ldr	r1,[sp,#0]
++	ldr	r2,[sp,#4]
++	ldr	r3,[sp,#8]
++	subs	r1,r1,#-1
++	ldr	r4,[sp,#12]
++	sbcs	r2,r2,#-1
++	ldr	r5,[sp,#16]
++	sbcs	r3,r3,#-1
++	ldr	r6,[sp,#20]
++	sbcs	r4,r4,#0
++	ldr	r7,[sp,#24]
++	sbcs	r5,r5,#0
++	ldr	r8,[sp,#28]
++	sbcs	r6,r6,#0
++	ldr	r9,[sp,#32]				@ top-most bit
++	sbcs	r7,r7,#1
++	sub	sp,ip,#40+16
++	sbcs	r8,r8,#-1
++	sbc	r9,r9,#0
++        vldmia  sp!,{q4-q5}
++
++	adds	r1,r1,r9
++	adcs	r2,r2,r9
++	str	r1,[$rptr,#0]
++	adcs	r3,r3,r9
++	str	r2,[$rptr,#4]
++	adcs	r4,r4,#0
++	str	r3,[$rptr,#8]
++	adcs	r5,r5,#0
++	str	r4,[$rptr,#12]
++	adcs	r6,r6,#0
++	str	r5,[$rptr,#16]
++	adcs	r7,r7,r9,lsr#31
++	str	r6,[$rptr,#20]
++	adcs	r8,r8,r9
++	str	r7,[$rptr,#24]
++	str	r8,[$rptr,#28]
++
++        ldmia   sp!,{r4-r9}
++	bx	lr
++.size	ecp_nistz256_mul_mont_neon,.-ecp_nistz256_mul_mont_neon
++#endif
++___
++}
++
++{{{
++########################################################################
++# Below $aN assignment matches order in which 256-bit result appears in
++# register bank at return from __ecp_nistz256_mul_mont, so that we can
++# skip over reloading it from memory. This means that below functions
++# use custom calling sequence accepting 256-bit input in registers,
++# output pointer in r0, $r_ptr, and optional pointer in r2, $b_ptr.
++#
++# See their "normal" counterparts for insights on calculations.
++
++my ($a0,$a1,$a2,$a3,$a4,$a5,$a6,$a7,
++    $t0,$t1,$t2,$t3)=map("r$_",(11,3..10,12,14,1));
++my $ff=$b_ptr;
++
++$code.=<<___;
++.type	__ecp_nistz256_sub_from,%function
++.align	5
++__ecp_nistz256_sub_from:
++	str	lr,[sp,#-4]!		@ push lr
++
++	 ldr	$t0,[$b_ptr,#0]
++	 ldr	$t1,[$b_ptr,#4]
++	 ldr	$t2,[$b_ptr,#8]
++	 ldr	$t3,[$b_ptr,#12]
++	subs	$a0,$a0,$t0
++	 ldr	$t0,[$b_ptr,#16]
++	sbcs	$a1,$a1,$t1
++	 ldr	$t1,[$b_ptr,#20]
++	sbcs	$a2,$a2,$t2
++	 ldr	$t2,[$b_ptr,#24]
++	sbcs	$a3,$a3,$t3
++	 ldr	$t3,[$b_ptr,#28]
++	sbcs	$a4,$a4,$t0
++	sbcs	$a5,$a5,$t1
++	sbcs	$a6,$a6,$t2
++	sbcs	$a7,$a7,$t3
++	sbc	$ff,$ff,$ff		@ broadcast borrow bit
++	ldr	lr,[sp],#4		@ pop lr
++
++	adds	$a0,$a0,$ff		@ add synthesized modulus
++	adcs	$a1,$a1,$ff
++	str	$a0,[$r_ptr,#0]
++	adcs	$a2,$a2,$ff
++	str	$a1,[$r_ptr,#4]
++	adcs	$a3,$a3,#0
++	str	$a2,[$r_ptr,#8]
++	adcs	$a4,$a4,#0
++	str	$a3,[$r_ptr,#12]
++	adcs	$a5,$a5,#0
++	str	$a4,[$r_ptr,#16]
++	adcs	$a6,$a6,$ff,lsr#31
++	str	$a5,[$r_ptr,#20]
++	adcs	$a7,$a7,$ff
++	str	$a6,[$r_ptr,#24]
++	str	$a7,[$r_ptr,#28]
++
++	mov	pc,lr
++.size	__ecp_nistz256_sub_from,.-__ecp_nistz256_sub_from
++
++.type	__ecp_nistz256_sub_morf,%function
++.align	5
++__ecp_nistz256_sub_morf:
++	str	lr,[sp,#-4]!		@ push lr
++
++	 ldr	$t0,[$b_ptr,#0]
++	 ldr	$t1,[$b_ptr,#4]
++	 ldr	$t2,[$b_ptr,#8]
++	 ldr	$t3,[$b_ptr,#12]
++	subs	$a0,$t0,$a0
++	 ldr	$t0,[$b_ptr,#16]
++	sbcs	$a1,$t1,$a1
++	 ldr	$t1,[$b_ptr,#20]
++	sbcs	$a2,$t2,$a2
++	 ldr	$t2,[$b_ptr,#24]
++	sbcs	$a3,$t3,$a3
++	 ldr	$t3,[$b_ptr,#28]
++	sbcs	$a4,$t0,$a4
++	sbcs	$a5,$t1,$a5
++	sbcs	$a6,$t2,$a6
++	sbcs	$a7,$t3,$a7
++	sbc	$ff,$ff,$ff		@ broadcast borrow bit
++	ldr	lr,[sp],#4		@ pop lr
++
++	adds	$a0,$a0,$ff		@ add synthesized modulus
++	adcs	$a1,$a1,$ff
++	str	$a0,[$r_ptr,#0]
++	adcs	$a2,$a2,$ff
++	str	$a1,[$r_ptr,#4]
++	adcs	$a3,$a3,#0
++	str	$a2,[$r_ptr,#8]
++	adcs	$a4,$a4,#0
++	str	$a3,[$r_ptr,#12]
++	adcs	$a5,$a5,#0
++	str	$a4,[$r_ptr,#16]
++	adcs	$a6,$a6,$ff,lsr#31
++	str	$a5,[$r_ptr,#20]
++	adcs	$a7,$a7,$ff
++	str	$a6,[$r_ptr,#24]
++	str	$a7,[$r_ptr,#28]
++
++	mov	pc,lr
++.size	__ecp_nistz256_sub_morf,.-__ecp_nistz256_sub_morf
++
++.type	__ecp_nistz256_add_self,%function
++.align	4
++__ecp_nistz256_add_self:
++	adds	$a0,$a0,$a0		@ a[0:7]+=a[0:7]
++	adcs	$a1,$a1,$a1
++	adcs	$a2,$a2,$a2
++	adcs	$a3,$a3,$a3
++	adcs	$a4,$a4,$a4
++	adcs	$a5,$a5,$a5
++	adcs	$a6,$a6,$a6
++	mov	$ff,#0
++	adcs	$a7,$a7,$a7
++	adc	$ff,$ff,#0
++
++	@ if a+b >= modulus, subtract modulus.
++	@
++	@ But since comparison implies subtraction, we subtract
++	@ modulus and then add it back if subraction borrowed.
++
++	subs	$a0,$a0,#-1
++	sbcs	$a1,$a1,#-1
++	sbcs	$a2,$a2,#-1
++	sbcs	$a3,$a3,#0
++	sbcs	$a4,$a4,#0
++	sbcs	$a5,$a5,#0
++	sbcs	$a6,$a6,#1
++	sbcs	$a7,$a7,#-1
++	sbc	$ff,$ff,#0
++
++	@ Note that because mod has special form, i.e. consists of
++	@ 0xffffffff, 1 and 0s, we can conditionally synthesize it by
++	@ using value of borrow as a whole or extracting single bit.
++	@ Follow $ff register...
++
++	adds	$a0,$a0,$ff		@ add synthesized modulus
++	adcs	$a1,$a1,$ff
++	str	$a0,[$r_ptr,#0]
++	adcs	$a2,$a2,$ff
++	str	$a1,[$r_ptr,#4]
++	adcs	$a3,$a3,#0
++	str	$a2,[$r_ptr,#8]
++	adcs	$a4,$a4,#0
++	str	$a3,[$r_ptr,#12]
++	adcs	$a5,$a5,#0
++	str	$a4,[$r_ptr,#16]
++	adcs	$a6,$a6,$ff,lsr#31
++	str	$a5,[$r_ptr,#20]
++	adcs	$a7,$a7,$ff
++	str	$a6,[$r_ptr,#24]
++	str	$a7,[$r_ptr,#28]
++
++	mov	pc,lr
++.size	__ecp_nistz256_add_self,.-__ecp_nistz256_add_self
++
++___
++
++########################################################################
++# following subroutines are "literal" implementation of those found in
++# ecp_nistz256.c
++#
++########################################################################
++# void ecp_nistz256_point_double(P256_POINT *out,const P256_POINT *inp);
++#
++{
++my ($S,$M,$Zsqr,$in_x,$tmp0)=map(32*$_,(0..4));
++# above map() describes stack layout with 5 temporary
++# 256-bit vectors on top. Then note that we push
++# starting from r0, which means that we have copy of
++# input arguments just below these temporary vectors.
++
++$code.=<<___;
++.globl	ecp_nistz256_point_double
++.type	ecp_nistz256_point_double,%function
++.align	5
++ecp_nistz256_point_double:
++	stmdb	sp!,{r0-r12,lr}		@ push from r0, unusual, but intentional
++	sub	sp,sp,#32*5
++
++.Lpoint_double_shortcut:
++	add	r3,sp,#$in_x
++	ldmia	$a_ptr!,{r4-r11}	@ copy in_x
++	stmia	r3,{r4-r11}
++
++	add	$r_ptr,sp,#$S
++	bl	__ecp_nistz256_mul_by_2	@ p256_mul_by_2(S, in_y);
++
++	add	$b_ptr,$a_ptr,#32
++	add	$a_ptr,$a_ptr,#32
++	add	$r_ptr,sp,#$Zsqr
++	bl	__ecp_nistz256_mul_mont	@ p256_sqr_mont(Zsqr, in_z);
++
++	add	$a_ptr,sp,#$S
++	add	$b_ptr,sp,#$S
++	add	$r_ptr,sp,#$S
++	bl	__ecp_nistz256_mul_mont	@ p256_sqr_mont(S, S);
++
++	ldr	$b_ptr,[sp,#32*5+4]
++	add	$a_ptr,$b_ptr,#32
++	add	$b_ptr,$b_ptr,#64
++	add	$r_ptr,sp,#$tmp0
++	bl	__ecp_nistz256_mul_mont	@ p256_mul_mont(tmp0, in_z, in_y);
++
++	ldr	$r_ptr,[sp,#32*5]
++	add	$r_ptr,$r_ptr,#64
++	bl	__ecp_nistz256_add_self	@ p256_mul_by_2(res_z, tmp0);
++
++	add	$a_ptr,sp,#$in_x
++	add	$b_ptr,sp,#$Zsqr
++	add	$r_ptr,sp,#$M
++	bl	__ecp_nistz256_add	@ p256_add(M, in_x, Zsqr);
++
++	add	$a_ptr,sp,#$in_x
++	add	$b_ptr,sp,#$Zsqr
++	add	$r_ptr,sp,#$Zsqr
++	bl	__ecp_nistz256_sub	@ p256_sub(Zsqr, in_x, Zsqr);
++
++	add	$a_ptr,sp,#$S
++	add	$b_ptr,sp,#$S
++	add	$r_ptr,sp,#$tmp0
++	bl	__ecp_nistz256_mul_mont	@ p256_sqr_mont(tmp0, S);
++
++	add	$a_ptr,sp,#$Zsqr
++	add	$b_ptr,sp,#$M
++	add	$r_ptr,sp,#$M
++	bl	__ecp_nistz256_mul_mont	@ p256_mul_mont(M, M, Zsqr);
++
++	ldr	$r_ptr,[sp,#32*5]
++	add	$a_ptr,sp,#$tmp0
++	add	$r_ptr,$r_ptr,#32
++	bl	__ecp_nistz256_div_by_2	@ p256_div_by_2(res_y, tmp0);
++
++	add	$a_ptr,sp,#$M
++	add	$r_ptr,sp,#$M
++	bl	__ecp_nistz256_mul_by_3	@ p256_mul_by_3(M, M);
++
++	add	$a_ptr,sp,#$in_x
++	add	$b_ptr,sp,#$S
++	add	$r_ptr,sp,#$S
++	bl	__ecp_nistz256_mul_mont	@ p256_mul_mont(S, S, in_x);
++
++	add	$r_ptr,sp,#$tmp0
++	bl	__ecp_nistz256_add_self	@ p256_mul_by_2(tmp0, S);
++
++	ldr	$r_ptr,[sp,#32*5]
++	add	$a_ptr,sp,#$M
++	add	$b_ptr,sp,#$M
++	bl	__ecp_nistz256_mul_mont	@ p256_sqr_mont(res_x, M);
++
++	add	$b_ptr,sp,#$tmp0
++	bl	__ecp_nistz256_sub_from	@ p256_sub(res_x, res_x, tmp0);
++
++	add	$b_ptr,sp,#$S
++	add	$r_ptr,sp,#$S
++	bl	__ecp_nistz256_sub_morf	@ p256_sub(S, S, res_x);
++
++	add	$a_ptr,sp,#$M
++	add	$b_ptr,sp,#$S
++	bl	__ecp_nistz256_mul_mont	@ p256_mul_mont(S, S, M);
++
++	ldr	$r_ptr,[sp,#32*5]
++	add	$b_ptr,$r_ptr,#32
++	add	$r_ptr,$r_ptr,#32
++	bl	__ecp_nistz256_sub_from	@ p256_sub(res_y, S, res_y);
++
++	add	sp,sp,#32*5+16		@ +16 means "skip even over saved r0-r3"
++#if __ARM_ARCH__>=5 || !defined(__thumb__)
++	ldmia	sp!,{r4-r12,pc}
++#else
++	ldmia	sp!,{r4-r12,lr}
++	bx	lr			@ interoperable with Thumb ISA:-)
++#endif
++.size	ecp_nistz256_point_double,.-ecp_nistz256_point_double
++___
++}
++
++########################################################################
++# void ecp_nistz256_point_add(P256_POINT *out,const P256_POINT *in1,
++#			      const P256_POINT *in2);
++{
++my ($res_x,$res_y,$res_z,
++    $in1_x,$in1_y,$in1_z,
++    $in2_x,$in2_y,$in2_z,
++    $H,$Hsqr,$R,$Rsqr,$Hcub,
++    $U1,$U2,$S1,$S2)=map(32*$_,(0..17));
++my ($Z1sqr, $Z2sqr) = ($Hsqr, $Rsqr);
++# above map() describes stack layout with 18 temporary
++# 256-bit vectors on top. Then note that we push
++# starting from r0, which means that we have copy of
++# input arguments just below these temporary vectors.
++# We use three of them for !in1infty, !in2intfy and
++# result of check for zero.
++
++$code.=<<___;
++.globl	ecp_nistz256_point_add
++.type	ecp_nistz256_point_add,%function
++.align	5
++ecp_nistz256_point_add:
++	stmdb	sp!,{r0-r12,lr}		@ push from r0, unusual, but intentional
++	sub	sp,sp,#32*18+16
++
++	ldmia	$b_ptr!,{r4-r11}	@ copy in2_x
++	add	r3,sp,#$in2_x
++	stmia	r3!,{r4-r11}
++	ldmia	$b_ptr!,{r4-r11}	@ copy in2_y
++	stmia	r3!,{r4-r11}
++	ldmia	$b_ptr,{r4-r11}		@ copy in2_z
++	orr	r12,r4,r5
++	orr	r12,r12,r6
++	orr	r12,r12,r7
++	orr	r12,r12,r8
++	orr	r12,r12,r9
++	orr	r12,r12,r10
++	orr	r12,r12,r11
++	cmp	r12,#0
++#ifdef	__thumb2__
++	it	ne
++#endif
++	movne	r12,#-1
++	stmia	r3,{r4-r11}
++	str	r12,[sp,#32*18+8]	@ !in2infty
++
++	ldmia	$a_ptr!,{r4-r11}	@ copy in1_x
++	add	r3,sp,#$in1_x
++	stmia	r3!,{r4-r11}
++	ldmia	$a_ptr!,{r4-r11}	@ copy in1_y
++	stmia	r3!,{r4-r11}
++	ldmia	$a_ptr,{r4-r11}		@ copy in1_z
++	orr	r12,r4,r5
++	orr	r12,r12,r6
++	orr	r12,r12,r7
++	orr	r12,r12,r8
++	orr	r12,r12,r9
++	orr	r12,r12,r10
++	orr	r12,r12,r11
++	cmp	r12,#0
++#ifdef	__thumb2__
++	it	ne
++#endif
++	movne	r12,#-1
++	stmia	r3,{r4-r11}
++	str	r12,[sp,#32*18+4]	@ !in1infty
++
++	add	$a_ptr,sp,#$in2_z
++	add	$b_ptr,sp,#$in2_z
++	add	$r_ptr,sp,#$Z2sqr
++	bl	__ecp_nistz256_mul_mont	@ p256_sqr_mont(Z2sqr, in2_z);
++
++	add	$a_ptr,sp,#$in1_z
++	add	$b_ptr,sp,#$in1_z
++	add	$r_ptr,sp,#$Z1sqr
++	bl	__ecp_nistz256_mul_mont	@ p256_sqr_mont(Z1sqr, in1_z);
++
++	add	$a_ptr,sp,#$in2_z
++	add	$b_ptr,sp,#$Z2sqr
++	add	$r_ptr,sp,#$S1
++	bl	__ecp_nistz256_mul_mont	@ p256_mul_mont(S1, Z2sqr, in2_z);
++
++	add	$a_ptr,sp,#$in1_z
++	add	$b_ptr,sp,#$Z1sqr
++	add	$r_ptr,sp,#$S2
++	bl	__ecp_nistz256_mul_mont	@ p256_mul_mont(S2, Z1sqr, in1_z);
++
++	add	$a_ptr,sp,#$in1_y
++	add	$b_ptr,sp,#$S1
++	add	$r_ptr,sp,#$S1
++	bl	__ecp_nistz256_mul_mont	@ p256_mul_mont(S1, S1, in1_y);
++
++	add	$a_ptr,sp,#$in2_y
++	add	$b_ptr,sp,#$S2
++	add	$r_ptr,sp,#$S2
++	bl	__ecp_nistz256_mul_mont	@ p256_mul_mont(S2, S2, in2_y);
++
++	add	$b_ptr,sp,#$S1
++	add	$r_ptr,sp,#$R
++	bl	__ecp_nistz256_sub_from	@ p256_sub(R, S2, S1);
++
++	orr	$a0,$a0,$a1		@ see if result is zero
++	orr	$a2,$a2,$a3
++	orr	$a4,$a4,$a5
++	orr	$a0,$a0,$a2
++	orr	$a4,$a4,$a6
++	orr	$a0,$a0,$a7
++	 add	$a_ptr,sp,#$in1_x
++	orr	$a0,$a0,$a4
++	 add	$b_ptr,sp,#$Z2sqr
++	str	$a0,[sp,#32*18+12]
++
++	add	$r_ptr,sp,#$U1
++	bl	__ecp_nistz256_mul_mont	@ p256_mul_mont(U1, in1_x, Z2sqr);
++
++	add	$a_ptr,sp,#$in2_x
++	add	$b_ptr,sp,#$Z1sqr
++	add	$r_ptr,sp,#$U2
++	bl	__ecp_nistz256_mul_mont	@ p256_mul_mont(U2, in2_x, Z1sqr);
++
++	add	$b_ptr,sp,#$U1
++	add	$r_ptr,sp,#$H
++	bl	__ecp_nistz256_sub_from	@ p256_sub(H, U2, U1);
++
++	orr	$a0,$a0,$a1		@ see if result is zero
++	orr	$a2,$a2,$a3
++	orr	$a4,$a4,$a5
++	orr	$a0,$a0,$a2
++	orr	$a4,$a4,$a6
++	orr	$a0,$a0,$a7
++	orrs	$a0,$a0,$a4
++
++	bne	.Ladd_proceed		@ is_equal(U1,U2)?
++
++	ldr	$t0,[sp,#32*18+4]
++	ldr	$t1,[sp,#32*18+8]
++	ldr	$t2,[sp,#32*18+12]
++	tst	$t0,$t1
++	beq	.Ladd_proceed		@ (in1infty || in2infty)?
++	tst	$t2,$t2
++	beq	.Ladd_double		@ is_equal(S1,S2)?
++
++	ldr	$r_ptr,[sp,#32*18+16]
++	eor	r4,r4,r4
++	eor	r5,r5,r5
++	eor	r6,r6,r6
++	eor	r7,r7,r7
++	eor	r8,r8,r8
++	eor	r9,r9,r9
++	eor	r10,r10,r10
++	eor	r11,r11,r11
++	stmia	$r_ptr!,{r4-r11}
++	stmia	$r_ptr!,{r4-r11}
++	stmia	$r_ptr!,{r4-r11}
++	b	.Ladd_done
++
++.align	4
++.Ladd_double:
++	ldr	$a_ptr,[sp,#32*18+20]
++	add	sp,sp,#32*(18-5)+16	@ difference in frame sizes
++	b	.Lpoint_double_shortcut
++
++.align	4
++.Ladd_proceed:
++	add	$a_ptr,sp,#$R
++	add	$b_ptr,sp,#$R
++	add	$r_ptr,sp,#$Rsqr
++	bl	__ecp_nistz256_mul_mont	@ p256_sqr_mont(Rsqr, R);
++
++	add	$a_ptr,sp,#$H
++	add	$b_ptr,sp,#$in1_z
++	add	$r_ptr,sp,#$res_z
++	bl	__ecp_nistz256_mul_mont	@ p256_mul_mont(res_z, H, in1_z);
++
++	add	$a_ptr,sp,#$H
++	add	$b_ptr,sp,#$H
++	add	$r_ptr,sp,#$Hsqr
++	bl	__ecp_nistz256_mul_mont	@ p256_sqr_mont(Hsqr, H);
++
++	add	$a_ptr,sp,#$in2_z
++	add	$b_ptr,sp,#$res_z
++	add	$r_ptr,sp,#$res_z
++	bl	__ecp_nistz256_mul_mont	@ p256_mul_mont(res_z, res_z, in2_z);
++
++	add	$a_ptr,sp,#$H
++	add	$b_ptr,sp,#$Hsqr
++	add	$r_ptr,sp,#$Hcub
++	bl	__ecp_nistz256_mul_mont	@ p256_mul_mont(Hcub, Hsqr, H);
++
++	add	$a_ptr,sp,#$Hsqr
++	add	$b_ptr,sp,#$U1
++	add	$r_ptr,sp,#$U2
++	bl	__ecp_nistz256_mul_mont	@ p256_mul_mont(U2, U1, Hsqr);
++
++	add	$r_ptr,sp,#$Hsqr
++	bl	__ecp_nistz256_add_self	@ p256_mul_by_2(Hsqr, U2);
++
++	add	$b_ptr,sp,#$Rsqr
++	add	$r_ptr,sp,#$res_x
++	bl	__ecp_nistz256_sub_morf	@ p256_sub(res_x, Rsqr, Hsqr);
++
++	add	$b_ptr,sp,#$Hcub
++	bl	__ecp_nistz256_sub_from	@  p256_sub(res_x, res_x, Hcub);
++
++	add	$b_ptr,sp,#$U2
++	add	$r_ptr,sp,#$res_y
++	bl	__ecp_nistz256_sub_morf	@ p256_sub(res_y, U2, res_x);
++
++	add	$a_ptr,sp,#$Hcub
++	add	$b_ptr,sp,#$S1
++	add	$r_ptr,sp,#$S2
++	bl	__ecp_nistz256_mul_mont	@ p256_mul_mont(S2, S1, Hcub);
++
++	add	$a_ptr,sp,#$R
++	add	$b_ptr,sp,#$res_y
++	add	$r_ptr,sp,#$res_y
++	bl	__ecp_nistz256_mul_mont	@ p256_mul_mont(res_y, res_y, R);
++
++	add	$b_ptr,sp,#$S2
++	bl	__ecp_nistz256_sub_from	@ p256_sub(res_y, res_y, S2);
++
++	ldr	r11,[sp,#32*18+4]	@ !in1intfy
++	ldr	r12,[sp,#32*18+8]	@ !in2intfy
++	add	r1,sp,#$res_x
++	add	r2,sp,#$in2_x
++	and	r10,r11,r12
++	mvn	r11,r11
++	add	r3,sp,#$in1_x
++	and	r11,r11,r12
++	mvn	r12,r12
++	ldr	$r_ptr,[sp,#32*18+16]
++___
++for($i=0;$i<96;$i+=8) {			# conditional moves
++$code.=<<___;
++	ldmia	r1!,{r4-r5}		@ res_x
++	ldmia	r2!,{r6-r7}		@ in2_x
++	ldmia	r3!,{r8-r9}		@ in1_x
++	and	r4,r4,r10
++	and	r5,r5,r10
++	and	r6,r6,r11
++	and	r7,r7,r11
++	and	r8,r8,r12
++	and	r9,r9,r12
++	orr	r4,r4,r6
++	orr	r5,r5,r7
++	orr	r4,r4,r8
++	orr	r5,r5,r9
++	stmia	$r_ptr!,{r4-r5}
++___
++}
++$code.=<<___;
++.Ladd_done:
++	add	sp,sp,#32*18+16+16	@ +16 means "skip even over saved r0-r3"
++#if __ARM_ARCH__>=5 || defined(__thumb__)
++	ldmia	sp!,{r4-r12,pc}
++#else
++	ldmia	sp!,{r4-r12,lr}
++	bx	lr			@ interoperable with Thumb ISA:-)
++#endif
++.size	ecp_nistz256_point_add,.-ecp_nistz256_point_add
++___
++}
++
++########################################################################
++# void ecp_nistz256_point_add_affine(P256_POINT *out,const P256_POINT *in1,
++#				     const P256_POINT_AFFINE *in2);
++{
++my ($res_x,$res_y,$res_z,
++    $in1_x,$in1_y,$in1_z,
++    $in2_x,$in2_y,
++    $U2,$S2,$H,$R,$Hsqr,$Hcub,$Rsqr)=map(32*$_,(0..14));
++my $Z1sqr = $S2;
++# above map() describes stack layout with 18 temporary
++# 256-bit vectors on top. Then note that we push
++# starting from r0, which means that we have copy of
++# input arguments just below these temporary vectors.
++# We use two of them for !in1infty, !in2intfy.
++
++my @ONE_mont=(1,0,0,-1,-1,-1,-2,0);
++
++$code.=<<___;
++.globl	ecp_nistz256_point_add_affine
++.type	ecp_nistz256_point_add_affine,%function
++.align	5
++ecp_nistz256_point_add_affine:
++	stmdb	sp!,{r0-r12,lr}		@ push from r0, unusual, but intentional
++	sub	sp,sp,#32*15
++
++	ldmia	$a_ptr!,{r4-r11}	@ copy in1_x
++	add	r3,sp,#$in1_x
++	stmia	r3!,{r4-r11}
++	ldmia	$a_ptr!,{r4-r11}	@ copy in1_y
++	stmia	r3!,{r4-r11}
++	ldmia	$a_ptr,{r4-r11}		@ copy in1_z
++	orr	r12,r4,r5
++	orr	r12,r12,r6
++	orr	r12,r12,r7
++	orr	r12,r12,r8
++	orr	r12,r12,r9
++	orr	r12,r12,r10
++	orr	r12,r12,r11
++	cmp	r12,#0
++#ifdef	__thumb2__
++	it	ne
++#endif
++	movne	r12,#-1
++	stmia	r3,{r4-r11}
++	str	r12,[sp,#32*15+4]	@ !in1infty
++
++	ldmia	$b_ptr!,{r4-r11}	@ copy in2_x
++	add	r3,sp,#$in2_x
++	orr	r12,r4,r5
++	orr	r12,r12,r6
++	orr	r12,r12,r7
++	orr	r12,r12,r8
++	orr	r12,r12,r9
++	orr	r12,r12,r10
++	orr	r12,r12,r11
++	stmia	r3!,{r4-r11}
++	ldmia	$b_ptr!,{r4-r11}	@ copy in2_y
++	orr	r12,r12,r4
++	orr	r12,r12,r5
++	orr	r12,r12,r6
++	orr	r12,r12,r7
++	orr	r12,r12,r8
++	orr	r12,r12,r9
++	orr	r12,r12,r10
++	orr	r12,r12,r11
++	stmia	r3!,{r4-r11}
++	cmp	r12,#0
++#ifdef	__thumb2__
++	it	ne
++#endif
++	movne	r12,#-1
++	str	r12,[sp,#32*15+8]	@ !in2infty
++
++	add	$a_ptr,sp,#$in1_z
++	add	$b_ptr,sp,#$in1_z
++	add	$r_ptr,sp,#$Z1sqr
++	bl	__ecp_nistz256_mul_mont	@ p256_sqr_mont(Z1sqr, in1_z);
++
++	add	$a_ptr,sp,#$Z1sqr
++	add	$b_ptr,sp,#$in2_x
++	add	$r_ptr,sp,#$U2
++	bl	__ecp_nistz256_mul_mont	@ p256_mul_mont(U2, Z1sqr, in2_x);
++
++	add	$b_ptr,sp,#$in1_x
++	add	$r_ptr,sp,#$H
++	bl	__ecp_nistz256_sub_from	@ p256_sub(H, U2, in1_x);
++
++	add	$a_ptr,sp,#$Z1sqr
++	add	$b_ptr,sp,#$in1_z
++	add	$r_ptr,sp,#$S2
++	bl	__ecp_nistz256_mul_mont	@ p256_mul_mont(S2, Z1sqr, in1_z);
++
++	add	$a_ptr,sp,#$H
++	add	$b_ptr,sp,#$in1_z
++	add	$r_ptr,sp,#$res_z
++	bl	__ecp_nistz256_mul_mont	@ p256_mul_mont(res_z, H, in1_z);
++
++	add	$a_ptr,sp,#$in2_y
++	add	$b_ptr,sp,#$S2
++	add	$r_ptr,sp,#$S2
++	bl	__ecp_nistz256_mul_mont	@ p256_mul_mont(S2, S2, in2_y);
++
++	add	$b_ptr,sp,#$in1_y
++	add	$r_ptr,sp,#$R
++	bl	__ecp_nistz256_sub_from	@ p256_sub(R, S2, in1_y);
++
++	add	$a_ptr,sp,#$H
++	add	$b_ptr,sp,#$H
++	add	$r_ptr,sp,#$Hsqr
++	bl	__ecp_nistz256_mul_mont	@ p256_sqr_mont(Hsqr, H);
++
++	add	$a_ptr,sp,#$R
++	add	$b_ptr,sp,#$R
++	add	$r_ptr,sp,#$Rsqr
++	bl	__ecp_nistz256_mul_mont	@ p256_sqr_mont(Rsqr, R);
++
++	add	$a_ptr,sp,#$H
++	add	$b_ptr,sp,#$Hsqr
++	add	$r_ptr,sp,#$Hcub
++	bl	__ecp_nistz256_mul_mont	@ p256_mul_mont(Hcub, Hsqr, H);
++
++	add	$a_ptr,sp,#$Hsqr
++	add	$b_ptr,sp,#$in1_x
++	add	$r_ptr,sp,#$U2
++	bl	__ecp_nistz256_mul_mont	@ p256_mul_mont(U2, in1_x, Hsqr);
++
++	add	$r_ptr,sp,#$Hsqr
++	bl	__ecp_nistz256_add_self	@ p256_mul_by_2(Hsqr, U2);
++
++	add	$b_ptr,sp,#$Rsqr
++	add	$r_ptr,sp,#$res_x
++	bl	__ecp_nistz256_sub_morf	@ p256_sub(res_x, Rsqr, Hsqr);
++
++	add	$b_ptr,sp,#$Hcub
++	bl	__ecp_nistz256_sub_from	@  p256_sub(res_x, res_x, Hcub);
++
++	add	$b_ptr,sp,#$U2
++	add	$r_ptr,sp,#$res_y
++	bl	__ecp_nistz256_sub_morf	@ p256_sub(res_y, U2, res_x);
++
++	add	$a_ptr,sp,#$Hcub
++	add	$b_ptr,sp,#$in1_y
++	add	$r_ptr,sp,#$S2
++	bl	__ecp_nistz256_mul_mont	@ p256_mul_mont(S2, in1_y, Hcub);
++
++	add	$a_ptr,sp,#$R
++	add	$b_ptr,sp,#$res_y
++	add	$r_ptr,sp,#$res_y
++	bl	__ecp_nistz256_mul_mont	@ p256_mul_mont(res_y, res_y, R);
++
++	add	$b_ptr,sp,#$S2
++	bl	__ecp_nistz256_sub_from	@ p256_sub(res_y, res_y, S2);
++
++	ldr	r11,[sp,#32*15+4]	@ !in1intfy
++	ldr	r12,[sp,#32*15+8]	@ !in2intfy
++	add	r1,sp,#$res_x
++	add	r2,sp,#$in2_x
++	and	r10,r11,r12
++	mvn	r11,r11
++	add	r3,sp,#$in1_x
++	and	r11,r11,r12
++	mvn	r12,r12
++	ldr	$r_ptr,[sp,#32*15]
++___
++for($i=0;$i<64;$i+=8) {			# conditional moves
++$code.=<<___;
++	ldmia	r1!,{r4-r5}		@ res_x
++	ldmia	r2!,{r6-r7}		@ in2_x
++	ldmia	r3!,{r8-r9}		@ in1_x
++	and	r4,r4,r10
++	and	r5,r5,r10
++	and	r6,r6,r11
++	and	r7,r7,r11
++	and	r8,r8,r12
++	and	r9,r9,r12
++	orr	r4,r4,r6
++	orr	r5,r5,r7
++	orr	r4,r4,r8
++	orr	r5,r5,r9
++	stmia	$r_ptr!,{r4-r5}
++___
++}
++for(;$i<96;$i+=8) {
++my $j=($i-64)/4;
++$code.=<<___;
++	ldmia	r1!,{r4-r5}		@ res_z
++	ldmia	r3!,{r8-r9}		@ in1_z
++	and	r4,r4,r10
++	and	r5,r5,r10
++	and	r6,r11,#@ONE_mont[$j]
++	and	r7,r11,#@ONE_mont[$j+1]
++	and	r8,r8,r12
++	and	r9,r9,r12
++	orr	r4,r4,r6
++	orr	r5,r5,r7
++	orr	r4,r4,r8
++	orr	r5,r5,r9
++	stmia	$r_ptr!,{r4-r5}
++___
++}
++$code.=<<___;
++	add	sp,sp,#32*15+16		@ +16 means "skip even over saved r0-r3"
++#if __ARM_ARCH__>=5 || !defined(__thumb__)
++	ldmia	sp!,{r4-r12,pc}
++#else
++	ldmia	sp!,{r4-r12,lr}
++	bx	lr			@ interoperable with Thumb ISA:-)
++#endif
++.size	ecp_nistz256_point_add_affine,.-ecp_nistz256_point_add_affine
++___
++}					}}}
++
++foreach (split("\n",$code)) {
++	s/\`([^\`]*)\`/eval $1/geo;
++
++	s/\bq([0-9]+)#(lo|hi)/sprintf "d%d",2*$1+($2 eq "hi")/geo;
++
++	print $_,"\n";
++}
++close STDOUT;	# enforce flush
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/ec/asm/ecp_nistz256-armv8.pl b/CryptoPkg/Library/OpensslLib/openssl/crypto/ec/asm/ecp_nistz256-armv8.pl
+new file mode 100644
+index 0000000..cdc9161
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/ec/asm/ecp_nistz256-armv8.pl
+@@ -0,0 +1,1558 @@
++#! /usr/bin/env perl
++# Copyright 2015-2016 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
++# in the file LICENSE in the source distribution or at
++# https://www.openssl.org/source/license.html
++
++
++# ====================================================================
++# Written by Andy Polyakov  for the OpenSSL
++# project. The module is, however, dual licensed under OpenSSL and
++# CRYPTOGAMS licenses depending on where you obtain it. For further
++# details see http://www.openssl.org/~appro/cryptogams/.
++# ====================================================================
++#
++# ECP_NISTZ256 module for ARMv8.
++#
++# February 2015.
++#
++# Original ECP_NISTZ256 submission targeting x86_64 is detailed in
++# http://eprint.iacr.org/2013/816.
++#
++#			with/without -DECP_NISTZ256_ASM
++# Apple A7		+120-360%
++# Cortex-A53		+120-400%
++# Cortex-A57		+120-350%
++# X-Gene		+200-330%
++# Denver		+140-400%
++#
++# Ranges denote minimum and maximum improvement coefficients depending
++# on benchmark. Lower coefficients are for ECDSA sign, server-side
++# operation. Keep in mind that +400% means 5x improvement.
++
++$flavour = shift;
++while (($output=shift) && ($output!~/\w[\w\-]*\.\w+$/)) {}
++
++$0 =~ m/(.*[\/\\])[^\/\\]+$/; $dir=$1;
++( $xlate="${dir}arm-xlate.pl" and -f $xlate ) or
++( $xlate="${dir}../../perlasm/arm-xlate.pl" and -f $xlate) or
++die "can't locate arm-xlate.pl";
++
++open OUT,"| \"$^X\" $xlate $flavour $output";
++*STDOUT=*OUT;
++
++{
++my ($rp,$ap,$bp,$bi,$a0,$a1,$a2,$a3,$t0,$t1,$t2,$t3,$poly1,$poly3,
++    $acc0,$acc1,$acc2,$acc3,$acc4,$acc5) =
++    map("x$_",(0..17,19,20));
++
++my ($acc6,$acc7)=($ap,$bp);	# used in __ecp_nistz256_sqr_mont
++
++$code.=<<___;
++#include "arm_arch.h"
++
++.text
++___
++########################################################################
++# Convert ecp_nistz256_table.c to layout expected by ecp_nistz_gather_w7
++#
++$0 =~ m/(.*[\/\\])[^\/\\]+$/; $dir=$1;
++open TABLE,") {
++	s/TOBN\(\s*(0x[0-9a-f]+),\s*(0x[0-9a-f]+)\s*\)/push @arr,hex($2),hex($1)/geo;
++}
++close TABLE;
++
++# See ecp_nistz256_table.c for explanation for why it's 64*16*37.
++# 64*16*37-1 is because $#arr returns last valid index or @arr, not
++# amount of elements.
++die "insane number of elements" if ($#arr != 64*16*37-1);
++
++$code.=<<___;
++.globl	ecp_nistz256_precomputed
++.type	ecp_nistz256_precomputed,%object
++.align	12
++ecp_nistz256_precomputed:
++___
++########################################################################
++# this conversion smashes P256_POINT_AFFINE by individual bytes with
++# 64 byte interval, similar to
++#	1111222233334444
++#	1234123412341234
++for(1..37) {
++	@tbl = splice(@arr,0,64*16);
++	for($i=0;$i<64;$i++) {
++		undef @line;
++		for($j=0;$j<64;$j++) {
++			push @line,(@tbl[$j*16+$i/4]>>(($i%4)*8))&0xff;
++		}
++		$code.=".byte\t";
++		$code.=join(',',map { sprintf "0x%02x",$_} @line);
++		$code.="\n";
++	}
++}
++$code.=<<___;
++.size	ecp_nistz256_precomputed,.-ecp_nistz256_precomputed
++.align	5
++.Lpoly:
++.quad	0xffffffffffffffff,0x00000000ffffffff,0x0000000000000000,0xffffffff00000001
++.LRR:	// 2^512 mod P precomputed for NIST P256 polynomial
++.quad	0x0000000000000003,0xfffffffbffffffff,0xfffffffffffffffe,0x00000004fffffffd
++.Lone_mont:
++.quad	0x0000000000000001,0xffffffff00000000,0xffffffffffffffff,0x00000000fffffffe
++.Lone:
++.quad	1,0,0,0
++.asciz	"ECP_NISTZ256 for ARMv8, CRYPTOGAMS by "
++
++// void	ecp_nistz256_to_mont(BN_ULONG x0[4],const BN_ULONG x1[4]);
++.globl	ecp_nistz256_to_mont
++.type	ecp_nistz256_to_mont,%function
++.align	6
++ecp_nistz256_to_mont:
++	stp	x29,x30,[sp,#-32]!
++	add	x29,sp,#0
++	stp	x19,x20,[sp,#16]
++
++	ldr	$bi,.LRR		// bp[0]
++	ldp	$a0,$a1,[$ap]
++	ldp	$a2,$a3,[$ap,#16]
++	ldr	$poly1,.Lpoly+8
++	ldr	$poly3,.Lpoly+24
++	adr	$bp,.LRR		// &bp[0]
++
++	bl	__ecp_nistz256_mul_mont
++
++	ldp	x19,x20,[sp,#16]
++	ldp	x29,x30,[sp],#32
++	ret
++.size	ecp_nistz256_to_mont,.-ecp_nistz256_to_mont
++
++// void	ecp_nistz256_from_mont(BN_ULONG x0[4],const BN_ULONG x1[4]);
++.globl	ecp_nistz256_from_mont
++.type	ecp_nistz256_from_mont,%function
++.align	4
++ecp_nistz256_from_mont:
++	stp	x29,x30,[sp,#-32]!
++	add	x29,sp,#0
++	stp	x19,x20,[sp,#16]
++
++	mov	$bi,#1			// bp[0]
++	ldp	$a0,$a1,[$ap]
++	ldp	$a2,$a3,[$ap,#16]
++	ldr	$poly1,.Lpoly+8
++	ldr	$poly3,.Lpoly+24
++	adr	$bp,.Lone		// &bp[0]
++
++	bl	__ecp_nistz256_mul_mont
++
++	ldp	x19,x20,[sp,#16]
++	ldp	x29,x30,[sp],#32
++	ret
++.size	ecp_nistz256_from_mont,.-ecp_nistz256_from_mont
++
++// void	ecp_nistz256_mul_mont(BN_ULONG x0[4],const BN_ULONG x1[4],
++//					     const BN_ULONG x2[4]);
++.globl	ecp_nistz256_mul_mont
++.type	ecp_nistz256_mul_mont,%function
++.align	4
++ecp_nistz256_mul_mont:
++	stp	x29,x30,[sp,#-32]!
++	add	x29,sp,#0
++	stp	x19,x20,[sp,#16]
++
++	ldr	$bi,[$bp]		// bp[0]
++	ldp	$a0,$a1,[$ap]
++	ldp	$a2,$a3,[$ap,#16]
++	ldr	$poly1,.Lpoly+8
++	ldr	$poly3,.Lpoly+24
++
++	bl	__ecp_nistz256_mul_mont
++
++	ldp	x19,x20,[sp,#16]
++	ldp	x29,x30,[sp],#32
++	ret
++.size	ecp_nistz256_mul_mont,.-ecp_nistz256_mul_mont
++
++// void	ecp_nistz256_sqr_mont(BN_ULONG x0[4],const BN_ULONG x1[4]);
++.globl	ecp_nistz256_sqr_mont
++.type	ecp_nistz256_sqr_mont,%function
++.align	4
++ecp_nistz256_sqr_mont:
++	stp	x29,x30,[sp,#-32]!
++	add	x29,sp,#0
++	stp	x19,x20,[sp,#16]
++
++	ldp	$a0,$a1,[$ap]
++	ldp	$a2,$a3,[$ap,#16]
++	ldr	$poly1,.Lpoly+8
++	ldr	$poly3,.Lpoly+24
++
++	bl	__ecp_nistz256_sqr_mont
++
++	ldp	x19,x20,[sp,#16]
++	ldp	x29,x30,[sp],#32
++	ret
++.size	ecp_nistz256_sqr_mont,.-ecp_nistz256_sqr_mont
++
++// void	ecp_nistz256_add(BN_ULONG x0[4],const BN_ULONG x1[4],
++//					const BN_ULONG x2[4]);
++.globl	ecp_nistz256_add
++.type	ecp_nistz256_add,%function
++.align	4
++ecp_nistz256_add:
++	stp	x29,x30,[sp,#-16]!
++	add	x29,sp,#0
++
++	ldp	$acc0,$acc1,[$ap]
++	ldp	$t0,$t1,[$bp]
++	ldp	$acc2,$acc3,[$ap,#16]
++	ldp	$t2,$t3,[$bp,#16]
++	ldr	$poly1,.Lpoly+8
++	ldr	$poly3,.Lpoly+24
++
++	bl	__ecp_nistz256_add
++
++	ldp	x29,x30,[sp],#16
++	ret
++.size	ecp_nistz256_add,.-ecp_nistz256_add
++
++// void	ecp_nistz256_div_by_2(BN_ULONG x0[4],const BN_ULONG x1[4]);
++.globl	ecp_nistz256_div_by_2
++.type	ecp_nistz256_div_by_2,%function
++.align	4
++ecp_nistz256_div_by_2:
++	stp	x29,x30,[sp,#-16]!
++	add	x29,sp,#0
++
++	ldp	$acc0,$acc1,[$ap]
++	ldp	$acc2,$acc3,[$ap,#16]
++	ldr	$poly1,.Lpoly+8
++	ldr	$poly3,.Lpoly+24
++
++	bl	__ecp_nistz256_div_by_2
++
++	ldp	x29,x30,[sp],#16
++	ret
++.size	ecp_nistz256_div_by_2,.-ecp_nistz256_div_by_2
++
++// void	ecp_nistz256_mul_by_2(BN_ULONG x0[4],const BN_ULONG x1[4]);
++.globl	ecp_nistz256_mul_by_2
++.type	ecp_nistz256_mul_by_2,%function
++.align	4
++ecp_nistz256_mul_by_2:
++	stp	x29,x30,[sp,#-16]!
++	add	x29,sp,#0
++
++	ldp	$acc0,$acc1,[$ap]
++	ldp	$acc2,$acc3,[$ap,#16]
++	ldr	$poly1,.Lpoly+8
++	ldr	$poly3,.Lpoly+24
++	mov	$t0,$acc0
++	mov	$t1,$acc1
++	mov	$t2,$acc2
++	mov	$t3,$acc3
++
++	bl	__ecp_nistz256_add	// ret = a+a	// 2*a
++
++	ldp	x29,x30,[sp],#16
++	ret
++.size	ecp_nistz256_mul_by_2,.-ecp_nistz256_mul_by_2
++
++// void	ecp_nistz256_mul_by_3(BN_ULONG x0[4],const BN_ULONG x1[4]);
++.globl	ecp_nistz256_mul_by_3
++.type	ecp_nistz256_mul_by_3,%function
++.align	4
++ecp_nistz256_mul_by_3:
++	stp	x29,x30,[sp,#-16]!
++	add	x29,sp,#0
++
++	ldp	$acc0,$acc1,[$ap]
++	ldp	$acc2,$acc3,[$ap,#16]
++	ldr	$poly1,.Lpoly+8
++	ldr	$poly3,.Lpoly+24
++	mov	$t0,$acc0
++	mov	$t1,$acc1
++	mov	$t2,$acc2
++	mov	$t3,$acc3
++	mov	$a0,$acc0
++	mov	$a1,$acc1
++	mov	$a2,$acc2
++	mov	$a3,$acc3
++
++	bl	__ecp_nistz256_add	// ret = a+a	// 2*a
++
++	mov	$t0,$a0
++	mov	$t1,$a1
++	mov	$t2,$a2
++	mov	$t3,$a3
++
++	bl	__ecp_nistz256_add	// ret += a	// 2*a+a=3*a
++
++	ldp	x29,x30,[sp],#16
++	ret
++.size	ecp_nistz256_mul_by_3,.-ecp_nistz256_mul_by_3
++
++// void	ecp_nistz256_sub(BN_ULONG x0[4],const BN_ULONG x1[4],
++//				        const BN_ULONG x2[4]);
++.globl	ecp_nistz256_sub
++.type	ecp_nistz256_sub,%function
++.align	4
++ecp_nistz256_sub:
++	stp	x29,x30,[sp,#-16]!
++	add	x29,sp,#0
++
++	ldp	$acc0,$acc1,[$ap]
++	ldp	$acc2,$acc3,[$ap,#16]
++	ldr	$poly1,.Lpoly+8
++	ldr	$poly3,.Lpoly+24
++
++	bl	__ecp_nistz256_sub_from
++
++	ldp	x29,x30,[sp],#16
++	ret
++.size	ecp_nistz256_sub,.-ecp_nistz256_sub
++
++// void	ecp_nistz256_neg(BN_ULONG x0[4],const BN_ULONG x1[4]);
++.globl	ecp_nistz256_neg
++.type	ecp_nistz256_neg,%function
++.align	4
++ecp_nistz256_neg:
++	stp	x29,x30,[sp,#-16]!
++	add	x29,sp,#0
++
++	mov	$bp,$ap
++	mov	$acc0,xzr		// a = 0
++	mov	$acc1,xzr
++	mov	$acc2,xzr
++	mov	$acc3,xzr
++	ldr	$poly1,.Lpoly+8
++	ldr	$poly3,.Lpoly+24
++
++	bl	__ecp_nistz256_sub_from
++
++	ldp	x29,x30,[sp],#16
++	ret
++.size	ecp_nistz256_neg,.-ecp_nistz256_neg
++
++// note that __ecp_nistz256_mul_mont expects a[0-3] input pre-loaded
++// to $a0-$a3 and b[0] - to $bi
++.type	__ecp_nistz256_mul_mont,%function
++.align	4
++__ecp_nistz256_mul_mont:
++	mul	$acc0,$a0,$bi		// a[0]*b[0]
++	umulh	$t0,$a0,$bi
++
++	mul	$acc1,$a1,$bi		// a[1]*b[0]
++	umulh	$t1,$a1,$bi
++
++	mul	$acc2,$a2,$bi		// a[2]*b[0]
++	umulh	$t2,$a2,$bi
++
++	mul	$acc3,$a3,$bi		// a[3]*b[0]
++	umulh	$t3,$a3,$bi
++	ldr	$bi,[$bp,#8]		// b[1]
++
++	adds	$acc1,$acc1,$t0		// accumulate high parts of multiplication
++	 lsl	$t0,$acc0,#32
++	adcs	$acc2,$acc2,$t1
++	 lsr	$t1,$acc0,#32
++	adcs	$acc3,$acc3,$t2
++	adc	$acc4,xzr,$t3
++	mov	$acc5,xzr
++___
++for($i=1;$i<4;$i++) {
++        # Reduction iteration is normally performed by accumulating
++        # result of multiplication of modulus by "magic" digit [and
++        # omitting least significant word, which is guaranteed to
++        # be 0], but thanks to special form of modulus and "magic"
++        # digit being equal to least significant word, it can be
++        # performed with additions and subtractions alone. Indeed:
++        #
++        #            ffff0001.00000000.0000ffff.ffffffff
++        # *                                     abcdefgh
++        # + xxxxxxxx.xxxxxxxx.xxxxxxxx.xxxxxxxx.abcdefgh
++        #
++        # Now observing that ff..ff*x = (2^n-1)*x = 2^n*x-x, we
++        # rewrite above as:
++        #
++        #   xxxxxxxx.xxxxxxxx.xxxxxxxx.xxxxxxxx.abcdefgh
++        # + abcdefgh.abcdefgh.0000abcd.efgh0000.00000000
++        # - 0000abcd.efgh0000.00000000.00000000.abcdefgh
++        #
++        # or marking redundant operations:
++        #
++        #   xxxxxxxx.xxxxxxxx.xxxxxxxx.xxxxxxxx.--------
++        # + abcdefgh.abcdefgh.0000abcd.efgh0000.--------
++        # - 0000abcd.efgh0000.--------.--------.--------
++
++$code.=<<___;
++	subs	$t2,$acc0,$t0		// "*0xffff0001"
++	sbc	$t3,$acc0,$t1
++	adds	$acc0,$acc1,$t0		// +=acc[0]<<96 and omit acc[0]
++	 mul	$t0,$a0,$bi		// lo(a[0]*b[i])
++	adcs	$acc1,$acc2,$t1
++	 mul	$t1,$a1,$bi		// lo(a[1]*b[i])
++	adcs	$acc2,$acc3,$t2		// +=acc[0]*0xffff0001
++	 mul	$t2,$a2,$bi		// lo(a[2]*b[i])
++	adcs	$acc3,$acc4,$t3
++	 mul	$t3,$a3,$bi		// lo(a[3]*b[i])
++	adc	$acc4,$acc5,xzr
++
++	adds	$acc0,$acc0,$t0		// accumulate low parts of multiplication
++	 umulh	$t0,$a0,$bi		// hi(a[0]*b[i])
++	adcs	$acc1,$acc1,$t1
++	 umulh	$t1,$a1,$bi		// hi(a[1]*b[i])
++	adcs	$acc2,$acc2,$t2
++	 umulh	$t2,$a2,$bi		// hi(a[2]*b[i])
++	adcs	$acc3,$acc3,$t3
++	 umulh	$t3,$a3,$bi		// hi(a[3]*b[i])
++	adc	$acc4,$acc4,xzr
++___
++$code.=<<___	if ($i<3);
++	ldr	$bi,[$bp,#8*($i+1)]	// b[$i+1]
++___
++$code.=<<___;
++	adds	$acc1,$acc1,$t0		// accumulate high parts of multiplication
++	 lsl	$t0,$acc0,#32
++	adcs	$acc2,$acc2,$t1
++	 lsr	$t1,$acc0,#32
++	adcs	$acc3,$acc3,$t2
++	adcs	$acc4,$acc4,$t3
++	adc	$acc5,xzr,xzr
++___
++}
++$code.=<<___;
++	// last reduction
++	subs	$t2,$acc0,$t0		// "*0xffff0001"
++	sbc	$t3,$acc0,$t1
++	adds	$acc0,$acc1,$t0		// +=acc[0]<<96 and omit acc[0]
++	adcs	$acc1,$acc2,$t1
++	adcs	$acc2,$acc3,$t2		// +=acc[0]*0xffff0001
++	adcs	$acc3,$acc4,$t3
++	adc	$acc4,$acc5,xzr
++
++	adds	$t0,$acc0,#1		// subs	$t0,$acc0,#-1 // tmp = ret-modulus
++	sbcs	$t1,$acc1,$poly1
++	sbcs	$t2,$acc2,xzr
++	sbcs	$t3,$acc3,$poly3
++	sbcs	xzr,$acc4,xzr		// did it borrow?
++
++	csel	$acc0,$acc0,$t0,lo	// ret = borrow ? ret : ret-modulus
++	csel	$acc1,$acc1,$t1,lo
++	csel	$acc2,$acc2,$t2,lo
++	stp	$acc0,$acc1,[$rp]
++	csel	$acc3,$acc3,$t3,lo
++	stp	$acc2,$acc3,[$rp,#16]
++
++	ret
++.size	__ecp_nistz256_mul_mont,.-__ecp_nistz256_mul_mont
++
++// note that __ecp_nistz256_sqr_mont expects a[0-3] input pre-loaded
++// to $a0-$a3
++.type	__ecp_nistz256_sqr_mont,%function
++.align	4
++__ecp_nistz256_sqr_mont:
++	//  |  |  |  |  |  |a1*a0|  |
++	//  |  |  |  |  |a2*a0|  |  |
++	//  |  |a3*a2|a3*a0|  |  |  |
++	//  |  |  |  |a2*a1|  |  |  |
++	//  |  |  |a3*a1|  |  |  |  |
++	// *|  |  |  |  |  |  |  | 2|
++	// +|a3*a3|a2*a2|a1*a1|a0*a0|
++	//  |--+--+--+--+--+--+--+--|
++	//  |A7|A6|A5|A4|A3|A2|A1|A0|, where Ax is $accx, i.e. follow $accx
++	//
++	//  "can't overflow" below mark carrying into high part of
++	//  multiplication result, which can't overflow, because it
++	//  can never be all ones.
++
++	mul	$acc1,$a1,$a0		// a[1]*a[0]
++	umulh	$t1,$a1,$a0
++	mul	$acc2,$a2,$a0		// a[2]*a[0]
++	umulh	$t2,$a2,$a0
++	mul	$acc3,$a3,$a0		// a[3]*a[0]
++	umulh	$acc4,$a3,$a0
++
++	adds	$acc2,$acc2,$t1		// accumulate high parts of multiplication
++	 mul	$t0,$a2,$a1		// a[2]*a[1]
++	 umulh	$t1,$a2,$a1
++	adcs	$acc3,$acc3,$t2
++	 mul	$t2,$a3,$a1		// a[3]*a[1]
++	 umulh	$t3,$a3,$a1
++	adc	$acc4,$acc4,xzr		// can't overflow
++
++	mul	$acc5,$a3,$a2		// a[3]*a[2]
++	umulh	$acc6,$a3,$a2
++
++	adds	$t1,$t1,$t2		// accumulate high parts of multiplication
++	 mul	$acc0,$a0,$a0		// a[0]*a[0]
++	adc	$t2,$t3,xzr		// can't overflow
++
++	adds	$acc3,$acc3,$t0		// accumulate low parts of multiplication
++	 umulh	$a0,$a0,$a0
++	adcs	$acc4,$acc4,$t1
++	 mul	$t1,$a1,$a1		// a[1]*a[1]
++	adcs	$acc5,$acc5,$t2
++	 umulh	$a1,$a1,$a1
++	adc	$acc6,$acc6,xzr		// can't overflow
++
++	adds	$acc1,$acc1,$acc1	// acc[1-6]*=2
++	 mul	$t2,$a2,$a2		// a[2]*a[2]
++	adcs	$acc2,$acc2,$acc2
++	 umulh	$a2,$a2,$a2
++	adcs	$acc3,$acc3,$acc3
++	 mul	$t3,$a3,$a3		// a[3]*a[3]
++	adcs	$acc4,$acc4,$acc4
++	 umulh	$a3,$a3,$a3
++	adcs	$acc5,$acc5,$acc5
++	adcs	$acc6,$acc6,$acc6
++	adc	$acc7,xzr,xzr
++
++	adds	$acc1,$acc1,$a0		// +a[i]*a[i]
++	adcs	$acc2,$acc2,$t1
++	adcs	$acc3,$acc3,$a1
++	adcs	$acc4,$acc4,$t2
++	adcs	$acc5,$acc5,$a2
++	 lsl	$t0,$acc0,#32
++	adcs	$acc6,$acc6,$t3
++	 lsr	$t1,$acc0,#32
++	adc	$acc7,$acc7,$a3
++___
++for($i=0;$i<3;$i++) {			# reductions, see commentary in
++					# multiplication for details
++$code.=<<___;
++	subs	$t2,$acc0,$t0		// "*0xffff0001"
++	sbc	$t3,$acc0,$t1
++	adds	$acc0,$acc1,$t0		// +=acc[0]<<96 and omit acc[0]
++	adcs	$acc1,$acc2,$t1
++	 lsl	$t0,$acc0,#32
++	adcs	$acc2,$acc3,$t2		// +=acc[0]*0xffff0001
++	 lsr	$t1,$acc0,#32
++	adc	$acc3,$t3,xzr		// can't overflow
++___
++}
++$code.=<<___;
++	subs	$t2,$acc0,$t0		// "*0xffff0001"
++	sbc	$t3,$acc0,$t1
++	adds	$acc0,$acc1,$t0		// +=acc[0]<<96 and omit acc[0]
++	adcs	$acc1,$acc2,$t1
++	adcs	$acc2,$acc3,$t2		// +=acc[0]*0xffff0001
++	adc	$acc3,$t3,xzr		// can't overflow
++
++	adds	$acc0,$acc0,$acc4	// accumulate upper half
++	adcs	$acc1,$acc1,$acc5
++	adcs	$acc2,$acc2,$acc6
++	adcs	$acc3,$acc3,$acc7
++	adc	$acc4,xzr,xzr
++
++	adds	$t0,$acc0,#1		// subs	$t0,$acc0,#-1 // tmp = ret-modulus
++	sbcs	$t1,$acc1,$poly1
++	sbcs	$t2,$acc2,xzr
++	sbcs	$t3,$acc3,$poly3
++	sbcs	xzr,$acc4,xzr		// did it borrow?
++
++	csel	$acc0,$acc0,$t0,lo	// ret = borrow ? ret : ret-modulus
++	csel	$acc1,$acc1,$t1,lo
++	csel	$acc2,$acc2,$t2,lo
++	stp	$acc0,$acc1,[$rp]
++	csel	$acc3,$acc3,$t3,lo
++	stp	$acc2,$acc3,[$rp,#16]
++
++	ret
++.size	__ecp_nistz256_sqr_mont,.-__ecp_nistz256_sqr_mont
++
++// Note that __ecp_nistz256_add expects both input vectors pre-loaded to
++// $a0-$a3 and $t0-$t3. This is done because it's used in multiple
++// contexts, e.g. in multiplication by 2 and 3...
++.type	__ecp_nistz256_add,%function
++.align	4
++__ecp_nistz256_add:
++	adds	$acc0,$acc0,$t0		// ret = a+b
++	adcs	$acc1,$acc1,$t1
++	adcs	$acc2,$acc2,$t2
++	adcs	$acc3,$acc3,$t3
++	adc	$ap,xzr,xzr		// zap $ap
++
++	adds	$t0,$acc0,#1		// subs	$t0,$a0,#-1 // tmp = ret-modulus
++	sbcs	$t1,$acc1,$poly1
++	sbcs	$t2,$acc2,xzr
++	sbcs	$t3,$acc3,$poly3
++	sbcs	xzr,$ap,xzr		// did subtraction borrow?
++
++	csel	$acc0,$acc0,$t0,lo	// ret = borrow ? ret : ret-modulus
++	csel	$acc1,$acc1,$t1,lo
++	csel	$acc2,$acc2,$t2,lo
++	stp	$acc0,$acc1,[$rp]
++	csel	$acc3,$acc3,$t3,lo
++	stp	$acc2,$acc3,[$rp,#16]
++
++	ret
++.size	__ecp_nistz256_add,.-__ecp_nistz256_add
++
++.type	__ecp_nistz256_sub_from,%function
++.align	4
++__ecp_nistz256_sub_from:
++	ldp	$t0,$t1,[$bp]
++	ldp	$t2,$t3,[$bp,#16]
++	subs	$acc0,$acc0,$t0		// ret = a-b
++	sbcs	$acc1,$acc1,$t1
++	sbcs	$acc2,$acc2,$t2
++	sbcs	$acc3,$acc3,$t3
++	sbc	$ap,xzr,xzr		// zap $ap
++
++	subs	$t0,$acc0,#1		// adds	$t0,$a0,#-1 // tmp = ret+modulus
++	adcs	$t1,$acc1,$poly1
++	adcs	$t2,$acc2,xzr
++	adc	$t3,$acc3,$poly3
++	cmp	$ap,xzr			// did subtraction borrow?
++
++	csel	$acc0,$acc0,$t0,eq	// ret = borrow ? ret+modulus : ret
++	csel	$acc1,$acc1,$t1,eq
++	csel	$acc2,$acc2,$t2,eq
++	stp	$acc0,$acc1,[$rp]
++	csel	$acc3,$acc3,$t3,eq
++	stp	$acc2,$acc3,[$rp,#16]
++
++	ret
++.size	__ecp_nistz256_sub_from,.-__ecp_nistz256_sub_from
++
++.type	__ecp_nistz256_sub_morf,%function
++.align	4
++__ecp_nistz256_sub_morf:
++	ldp	$t0,$t1,[$bp]
++	ldp	$t2,$t3,[$bp,#16]
++	subs	$acc0,$t0,$acc0		// ret = b-a
++	sbcs	$acc1,$t1,$acc1
++	sbcs	$acc2,$t2,$acc2
++	sbcs	$acc3,$t3,$acc3
++	sbc	$ap,xzr,xzr		// zap $ap
++
++	subs	$t0,$acc0,#1		// adds	$t0,$a0,#-1 // tmp = ret+modulus
++	adcs	$t1,$acc1,$poly1
++	adcs	$t2,$acc2,xzr
++	adc	$t3,$acc3,$poly3
++	cmp	$ap,xzr			// did subtraction borrow?
++
++	csel	$acc0,$acc0,$t0,eq	// ret = borrow ? ret+modulus : ret
++	csel	$acc1,$acc1,$t1,eq
++	csel	$acc2,$acc2,$t2,eq
++	stp	$acc0,$acc1,[$rp]
++	csel	$acc3,$acc3,$t3,eq
++	stp	$acc2,$acc3,[$rp,#16]
++
++	ret
++.size	__ecp_nistz256_sub_morf,.-__ecp_nistz256_sub_morf
++
++.type	__ecp_nistz256_div_by_2,%function
++.align	4
++__ecp_nistz256_div_by_2:
++	subs	$t0,$acc0,#1		// adds	$t0,$a0,#-1 // tmp = a+modulus
++	adcs	$t1,$acc1,$poly1
++	adcs	$t2,$acc2,xzr
++	adcs	$t3,$acc3,$poly3
++	adc	$ap,xzr,xzr		// zap $ap
++	tst	$acc0,#1		// is a even?
++
++	csel	$acc0,$acc0,$t0,eq	// ret = even ? a : a+modulus 
++	csel	$acc1,$acc1,$t1,eq
++	csel	$acc2,$acc2,$t2,eq
++	csel	$acc3,$acc3,$t3,eq
++	csel	$ap,xzr,$ap,eq
++
++	lsr	$acc0,$acc0,#1		// ret >>= 1
++	orr	$acc0,$acc0,$acc1,lsl#63
++	lsr	$acc1,$acc1,#1
++	orr	$acc1,$acc1,$acc2,lsl#63
++	lsr	$acc2,$acc2,#1
++	orr	$acc2,$acc2,$acc3,lsl#63
++	lsr	$acc3,$acc3,#1
++	stp	$acc0,$acc1,[$rp]
++	orr	$acc3,$acc3,$ap,lsl#63
++	stp	$acc2,$acc3,[$rp,#16]
++
++	ret
++.size	__ecp_nistz256_div_by_2,.-__ecp_nistz256_div_by_2
++___
++########################################################################
++# following subroutines are "literal" implementation of those found in
++# ecp_nistz256.c
++#
++########################################################################
++# void ecp_nistz256_point_double(P256_POINT *out,const P256_POINT *inp);
++#
++{
++my ($S,$M,$Zsqr,$tmp0)=map(32*$_,(0..3));
++# above map() describes stack layout with 4 temporary
++# 256-bit vectors on top.
++my ($rp_real,$ap_real) = map("x$_",(21,22));
++
++$code.=<<___;
++.globl	ecp_nistz256_point_double
++.type	ecp_nistz256_point_double,%function
++.align	5
++ecp_nistz256_point_double:
++	stp	x29,x30,[sp,#-80]!
++	add	x29,sp,#0
++	stp	x19,x20,[sp,#16]
++	stp	x21,x22,[sp,#32]
++	sub	sp,sp,#32*4
++
++.Ldouble_shortcut:
++	ldp	$acc0,$acc1,[$ap,#32]
++	 mov	$rp_real,$rp
++	ldp	$acc2,$acc3,[$ap,#48]
++	 mov	$ap_real,$ap
++	 ldr	$poly1,.Lpoly+8
++	mov	$t0,$acc0
++	 ldr	$poly3,.Lpoly+24
++	mov	$t1,$acc1
++	 ldp	$a0,$a1,[$ap_real,#64]	// forward load for p256_sqr_mont
++	mov	$t2,$acc2
++	mov	$t3,$acc3
++	 ldp	$a2,$a3,[$ap_real,#64+16]
++	add	$rp,sp,#$S
++	bl	__ecp_nistz256_add	// p256_mul_by_2(S, in_y);
++
++	add	$rp,sp,#$Zsqr
++	bl	__ecp_nistz256_sqr_mont	// p256_sqr_mont(Zsqr, in_z);
++
++	ldp	$t0,$t1,[$ap_real]
++	ldp	$t2,$t3,[$ap_real,#16]
++	mov	$a0,$acc0		// put Zsqr aside for p256_sub
++	mov	$a1,$acc1
++	mov	$a2,$acc2
++	mov	$a3,$acc3
++	add	$rp,sp,#$M
++	bl	__ecp_nistz256_add	// p256_add(M, Zsqr, in_x);
++
++	add	$bp,$ap_real,#0
++	mov	$acc0,$a0		// restore Zsqr
++	mov	$acc1,$a1
++	 ldp	$a0,$a1,[sp,#$S]	// forward load for p256_sqr_mont
++	mov	$acc2,$a2
++	mov	$acc3,$a3
++	 ldp	$a2,$a3,[sp,#$S+16]
++	add	$rp,sp,#$Zsqr
++	bl	__ecp_nistz256_sub_morf	// p256_sub(Zsqr, in_x, Zsqr);
++
++	add	$rp,sp,#$S
++	bl	__ecp_nistz256_sqr_mont	// p256_sqr_mont(S, S);
++
++	ldr	$bi,[$ap_real,#32]
++	ldp	$a0,$a1,[$ap_real,#64]
++	ldp	$a2,$a3,[$ap_real,#64+16]
++	add	$bp,$ap_real,#32
++	add	$rp,sp,#$tmp0
++	bl	__ecp_nistz256_mul_mont	// p256_mul_mont(tmp0, in_z, in_y);
++
++	mov	$t0,$acc0
++	mov	$t1,$acc1
++	 ldp	$a0,$a1,[sp,#$S]	// forward load for p256_sqr_mont
++	mov	$t2,$acc2
++	mov	$t3,$acc3
++	 ldp	$a2,$a3,[sp,#$S+16]
++	add	$rp,$rp_real,#64
++	bl	__ecp_nistz256_add	// p256_mul_by_2(res_z, tmp0);
++
++	add	$rp,sp,#$tmp0
++	bl	__ecp_nistz256_sqr_mont	// p256_sqr_mont(tmp0, S);
++
++	 ldr	$bi,[sp,#$Zsqr]		// forward load for p256_mul_mont
++	 ldp	$a0,$a1,[sp,#$M]
++	 ldp	$a2,$a3,[sp,#$M+16]
++	add	$rp,$rp_real,#32
++	bl	__ecp_nistz256_div_by_2	// p256_div_by_2(res_y, tmp0);
++
++	add	$bp,sp,#$Zsqr
++	add	$rp,sp,#$M
++	bl	__ecp_nistz256_mul_mont	// p256_mul_mont(M, M, Zsqr);
++
++	mov	$t0,$acc0		// duplicate M
++	mov	$t1,$acc1
++	mov	$t2,$acc2
++	mov	$t3,$acc3
++	mov	$a0,$acc0		// put M aside
++	mov	$a1,$acc1
++	mov	$a2,$acc2
++	mov	$a3,$acc3
++	add	$rp,sp,#$M
++	bl	__ecp_nistz256_add
++	mov	$t0,$a0			// restore M
++	mov	$t1,$a1
++	 ldr	$bi,[$ap_real]		// forward load for p256_mul_mont
++	mov	$t2,$a2
++	 ldp	$a0,$a1,[sp,#$S]
++	mov	$t3,$a3
++	 ldp	$a2,$a3,[sp,#$S+16]
++	bl	__ecp_nistz256_add	// p256_mul_by_3(M, M);
++
++	add	$bp,$ap_real,#0
++	add	$rp,sp,#$S
++	bl	__ecp_nistz256_mul_mont	// p256_mul_mont(S, S, in_x);
++
++	mov	$t0,$acc0
++	mov	$t1,$acc1
++	 ldp	$a0,$a1,[sp,#$M]	// forward load for p256_sqr_mont
++	mov	$t2,$acc2
++	mov	$t3,$acc3
++	 ldp	$a2,$a3,[sp,#$M+16]
++	add	$rp,sp,#$tmp0
++	bl	__ecp_nistz256_add	// p256_mul_by_2(tmp0, S);
++
++	add	$rp,$rp_real,#0
++	bl	__ecp_nistz256_sqr_mont	// p256_sqr_mont(res_x, M);
++
++	add	$bp,sp,#$tmp0
++	bl	__ecp_nistz256_sub_from	// p256_sub(res_x, res_x, tmp0);
++
++	add	$bp,sp,#$S
++	add	$rp,sp,#$S
++	bl	__ecp_nistz256_sub_morf	// p256_sub(S, S, res_x);
++
++	ldr	$bi,[sp,#$M]
++	mov	$a0,$acc0		// copy S
++	mov	$a1,$acc1
++	mov	$a2,$acc2
++	mov	$a3,$acc3
++	add	$bp,sp,#$M
++	bl	__ecp_nistz256_mul_mont	// p256_mul_mont(S, S, M);
++
++	add	$bp,$rp_real,#32
++	add	$rp,$rp_real,#32
++	bl	__ecp_nistz256_sub_from	// p256_sub(res_y, S, res_y);
++
++	add	sp,x29,#0		// destroy frame
++	ldp	x19,x20,[x29,#16]
++	ldp	x21,x22,[x29,#32]
++	ldp	x29,x30,[sp],#80
++	ret
++.size	ecp_nistz256_point_double,.-ecp_nistz256_point_double
++___
++}
++
++########################################################################
++# void ecp_nistz256_point_add(P256_POINT *out,const P256_POINT *in1,
++#			      const P256_POINT *in2);
++{
++my ($res_x,$res_y,$res_z,
++    $H,$Hsqr,$R,$Rsqr,$Hcub,
++    $U1,$U2,$S1,$S2)=map(32*$_,(0..11));
++my ($Z1sqr, $Z2sqr) = ($Hsqr, $Rsqr);
++# above map() describes stack layout with 12 temporary
++# 256-bit vectors on top.
++my ($rp_real,$ap_real,$bp_real,$in1infty,$in2infty,$temp)=map("x$_",(21..26));
++
++$code.=<<___;
++.globl	ecp_nistz256_point_add
++.type	ecp_nistz256_point_add,%function
++.align	5
++ecp_nistz256_point_add:
++	stp	x29,x30,[sp,#-80]!
++	add	x29,sp,#0
++	stp	x19,x20,[sp,#16]
++	stp	x21,x22,[sp,#32]
++	stp	x23,x24,[sp,#48]
++	stp	x25,x26,[sp,#64]
++	sub	sp,sp,#32*12
++
++	ldp	$a0,$a1,[$bp,#64]	// in2_z
++	ldp	$a2,$a3,[$bp,#64+16]
++	 mov	$rp_real,$rp
++	 mov	$ap_real,$ap
++	 mov	$bp_real,$bp
++	 ldr	$poly1,.Lpoly+8
++	 ldr	$poly3,.Lpoly+24
++	orr	$t0,$a0,$a1
++	orr	$t2,$a2,$a3
++	orr	$in2infty,$t0,$t2
++	cmp	$in2infty,#0
++	csetm	$in2infty,ne		// !in2infty
++	add	$rp,sp,#$Z2sqr
++	bl	__ecp_nistz256_sqr_mont	// p256_sqr_mont(Z2sqr, in2_z);
++
++	ldp	$a0,$a1,[$ap_real,#64]	// in1_z
++	ldp	$a2,$a3,[$ap_real,#64+16]
++	orr	$t0,$a0,$a1
++	orr	$t2,$a2,$a3
++	orr	$in1infty,$t0,$t2
++	cmp	$in1infty,#0
++	csetm	$in1infty,ne		// !in1infty
++	add	$rp,sp,#$Z1sqr
++	bl	__ecp_nistz256_sqr_mont	// p256_sqr_mont(Z1sqr, in1_z);
++
++	ldr	$bi,[$bp_real,#64]
++	ldp	$a0,$a1,[sp,#$Z2sqr]
++	ldp	$a2,$a3,[sp,#$Z2sqr+16]
++	add	$bp,$bp_real,#64
++	add	$rp,sp,#$S1
++	bl	__ecp_nistz256_mul_mont	// p256_mul_mont(S1, Z2sqr, in2_z);
++
++	ldr	$bi,[$ap_real,#64]
++	ldp	$a0,$a1,[sp,#$Z1sqr]
++	ldp	$a2,$a3,[sp,#$Z1sqr+16]
++	add	$bp,$ap_real,#64
++	add	$rp,sp,#$S2
++	bl	__ecp_nistz256_mul_mont	// p256_mul_mont(S2, Z1sqr, in1_z);
++
++	ldr	$bi,[$ap_real,#32]
++	ldp	$a0,$a1,[sp,#$S1]
++	ldp	$a2,$a3,[sp,#$S1+16]
++	add	$bp,$ap_real,#32
++	add	$rp,sp,#$S1
++	bl	__ecp_nistz256_mul_mont	// p256_mul_mont(S1, S1, in1_y);
++
++	ldr	$bi,[$bp_real,#32]
++	ldp	$a0,$a1,[sp,#$S2]
++	ldp	$a2,$a3,[sp,#$S2+16]
++	add	$bp,$bp_real,#32
++	add	$rp,sp,#$S2
++	bl	__ecp_nistz256_mul_mont	// p256_mul_mont(S2, S2, in2_y);
++
++	add	$bp,sp,#$S1
++	 ldr	$bi,[sp,#$Z2sqr]	// forward load for p256_mul_mont
++	 ldp	$a0,$a1,[$ap_real]
++	 ldp	$a2,$a3,[$ap_real,#16]
++	add	$rp,sp,#$R
++	bl	__ecp_nistz256_sub_from	// p256_sub(R, S2, S1);
++
++	orr	$acc0,$acc0,$acc1	// see if result is zero
++	orr	$acc2,$acc2,$acc3
++	orr	$temp,$acc0,$acc2
++
++	add	$bp,sp,#$Z2sqr
++	add	$rp,sp,#$U1
++	bl	__ecp_nistz256_mul_mont	// p256_mul_mont(U1, in1_x, Z2sqr);
++
++	ldr	$bi,[sp,#$Z1sqr]
++	ldp	$a0,$a1,[$bp_real]
++	ldp	$a2,$a3,[$bp_real,#16]
++	add	$bp,sp,#$Z1sqr
++	add	$rp,sp,#$U2
++	bl	__ecp_nistz256_mul_mont	// p256_mul_mont(U2, in2_x, Z1sqr);
++
++	add	$bp,sp,#$U1
++	 ldp	$a0,$a1,[sp,#$R]	// forward load for p256_sqr_mont
++	 ldp	$a2,$a3,[sp,#$R+16]
++	add	$rp,sp,#$H
++	bl	__ecp_nistz256_sub_from	// p256_sub(H, U2, U1);
++
++	orr	$acc0,$acc0,$acc1	// see if result is zero
++	orr	$acc2,$acc2,$acc3
++	orr	$acc0,$acc0,$acc2
++	tst	$acc0,$acc0
++	b.ne	.Ladd_proceed		// is_equal(U1,U2)?
++
++	tst	$in1infty,$in2infty
++	b.eq	.Ladd_proceed		// (in1infty || in2infty)?
++
++	tst	$temp,$temp
++	b.eq	.Ladd_double		// is_equal(S1,S2)?
++
++	eor	$a0,$a0,$a0
++	eor	$a1,$a1,$a1
++	stp	$a0,$a1,[$rp_real]
++	stp	$a0,$a1,[$rp_real,#16]
++	stp	$a0,$a1,[$rp_real,#32]
++	stp	$a0,$a1,[$rp_real,#48]
++	stp	$a0,$a1,[$rp_real,#64]
++	stp	$a0,$a1,[$rp_real,#80]
++	b	.Ladd_done
++
++.align	4
++.Ladd_double:
++	mov	$ap,$ap_real
++	mov	$rp,$rp_real
++	ldp	x23,x24,[x29,#48]
++	ldp	x25,x26,[x29,#64]
++	add	sp,sp,#32*(12-4)	// difference in stack frames
++	b	.Ldouble_shortcut
++
++.align	4
++.Ladd_proceed:
++	add	$rp,sp,#$Rsqr
++	bl	__ecp_nistz256_sqr_mont	// p256_sqr_mont(Rsqr, R);
++
++	ldr	$bi,[$ap_real,#64]
++	ldp	$a0,$a1,[sp,#$H]
++	ldp	$a2,$a3,[sp,#$H+16]
++	add	$bp,$ap_real,#64
++	add	$rp,sp,#$res_z
++	bl	__ecp_nistz256_mul_mont	// p256_mul_mont(res_z, H, in1_z);
++
++	ldp	$a0,$a1,[sp,#$H]
++	ldp	$a2,$a3,[sp,#$H+16]
++	add	$rp,sp,#$Hsqr
++	bl	__ecp_nistz256_sqr_mont	// p256_sqr_mont(Hsqr, H);
++
++	ldr	$bi,[$bp_real,#64]
++	ldp	$a0,$a1,[sp,#$res_z]
++	ldp	$a2,$a3,[sp,#$res_z+16]
++	add	$bp,$bp_real,#64
++	add	$rp,sp,#$res_z
++	bl	__ecp_nistz256_mul_mont	// p256_mul_mont(res_z, res_z, in2_z);
++
++	ldr	$bi,[sp,#$H]
++	ldp	$a0,$a1,[sp,#$Hsqr]
++	ldp	$a2,$a3,[sp,#$Hsqr+16]
++	add	$bp,sp,#$H
++	add	$rp,sp,#$Hcub
++	bl	__ecp_nistz256_mul_mont	// p256_mul_mont(Hcub, Hsqr, H);
++
++	ldr	$bi,[sp,#$Hsqr]
++	ldp	$a0,$a1,[sp,#$U1]
++	ldp	$a2,$a3,[sp,#$U1+16]
++	add	$bp,sp,#$Hsqr
++	add	$rp,sp,#$U2
++	bl	__ecp_nistz256_mul_mont	// p256_mul_mont(U2, U1, Hsqr);
++
++	mov	$t0,$acc0
++	mov	$t1,$acc1
++	mov	$t2,$acc2
++	mov	$t3,$acc3
++	add	$rp,sp,#$Hsqr
++	bl	__ecp_nistz256_add	// p256_mul_by_2(Hsqr, U2);
++
++	add	$bp,sp,#$Rsqr
++	add	$rp,sp,#$res_x
++	bl	__ecp_nistz256_sub_morf	// p256_sub(res_x, Rsqr, Hsqr);
++
++	add	$bp,sp,#$Hcub
++	bl	__ecp_nistz256_sub_from	//  p256_sub(res_x, res_x, Hcub);
++
++	add	$bp,sp,#$U2
++	 ldr	$bi,[sp,#$Hcub]		// forward load for p256_mul_mont
++	 ldp	$a0,$a1,[sp,#$S1]
++	 ldp	$a2,$a3,[sp,#$S1+16]
++	add	$rp,sp,#$res_y
++	bl	__ecp_nistz256_sub_morf	// p256_sub(res_y, U2, res_x);
++
++	add	$bp,sp,#$Hcub
++	add	$rp,sp,#$S2
++	bl	__ecp_nistz256_mul_mont	// p256_mul_mont(S2, S1, Hcub);
++
++	ldr	$bi,[sp,#$R]
++	ldp	$a0,$a1,[sp,#$res_y]
++	ldp	$a2,$a3,[sp,#$res_y+16]
++	add	$bp,sp,#$R
++	add	$rp,sp,#$res_y
++	bl	__ecp_nistz256_mul_mont	// p256_mul_mont(res_y, res_y, R);
++
++	add	$bp,sp,#$S2
++	bl	__ecp_nistz256_sub_from	// p256_sub(res_y, res_y, S2);
++
++	ldp	$a0,$a1,[sp,#$res_x]		// res
++	ldp	$a2,$a3,[sp,#$res_x+16]
++	ldp	$t0,$t1,[$bp_real]		// in2
++	ldp	$t2,$t3,[$bp_real,#16]
++___
++for($i=0;$i<64;$i+=32) {		# conditional moves
++$code.=<<___;
++	ldp	$acc0,$acc1,[$ap_real,#$i]	// in1
++	cmp	$in1infty,#0			// !$in1intfy, remember?
++	ldp	$acc2,$acc3,[$ap_real,#$i+16]
++	csel	$t0,$a0,$t0,ne
++	csel	$t1,$a1,$t1,ne
++	ldp	$a0,$a1,[sp,#$res_x+$i+32]	// res
++	csel	$t2,$a2,$t2,ne
++	csel	$t3,$a3,$t3,ne
++	cmp	$in2infty,#0			// !$in2intfy, remember?
++	ldp	$a2,$a3,[sp,#$res_x+$i+48]
++	csel	$acc0,$t0,$acc0,ne
++	csel	$acc1,$t1,$acc1,ne
++	ldp	$t0,$t1,[$bp_real,#$i+32]	// in2
++	csel	$acc2,$t2,$acc2,ne
++	csel	$acc3,$t3,$acc3,ne
++	ldp	$t2,$t3,[$bp_real,#$i+48]
++	stp	$acc0,$acc1,[$rp_real,#$i]
++	stp	$acc2,$acc3,[$rp_real,#$i+16]
++___
++}
++$code.=<<___;
++	ldp	$acc0,$acc1,[$ap_real,#$i]	// in1
++	cmp	$in1infty,#0			// !$in1intfy, remember?
++	ldp	$acc2,$acc3,[$ap_real,#$i+16]
++	csel	$t0,$a0,$t0,ne
++	csel	$t1,$a1,$t1,ne
++	csel	$t2,$a2,$t2,ne
++	csel	$t3,$a3,$t3,ne
++	cmp	$in2infty,#0			// !$in2intfy, remember?
++	csel	$acc0,$t0,$acc0,ne
++	csel	$acc1,$t1,$acc1,ne
++	csel	$acc2,$t2,$acc2,ne
++	csel	$acc3,$t3,$acc3,ne
++	stp	$acc0,$acc1,[$rp_real,#$i]
++	stp	$acc2,$acc3,[$rp_real,#$i+16]
++
++.Ladd_done:
++	add	sp,x29,#0	// destroy frame
++	ldp	x19,x20,[x29,#16]
++	ldp	x21,x22,[x29,#32]
++	ldp	x23,x24,[x29,#48]
++	ldp	x25,x26,[x29,#64]
++	ldp	x29,x30,[sp],#80
++	ret
++.size	ecp_nistz256_point_add,.-ecp_nistz256_point_add
++___
++}
++
++########################################################################
++# void ecp_nistz256_point_add_affine(P256_POINT *out,const P256_POINT *in1,
++#				     const P256_POINT_AFFINE *in2);
++{
++my ($res_x,$res_y,$res_z,
++    $U2,$S2,$H,$R,$Hsqr,$Hcub,$Rsqr)=map(32*$_,(0..9));
++my $Z1sqr = $S2;
++# above map() describes stack layout with 10 temporary
++# 256-bit vectors on top.
++my ($rp_real,$ap_real,$bp_real,$in1infty,$in2infty,$temp)=map("x$_",(21..26));
++
++$code.=<<___;
++.globl	ecp_nistz256_point_add_affine
++.type	ecp_nistz256_point_add_affine,%function
++.align	5
++ecp_nistz256_point_add_affine:
++	stp	x29,x30,[sp,#-80]!
++	add	x29,sp,#0
++	stp	x19,x20,[sp,#16]
++	stp	x21,x22,[sp,#32]
++	stp	x23,x24,[sp,#48]
++	stp	x25,x26,[sp,#64]
++	sub	sp,sp,#32*10
++
++	mov	$rp_real,$rp
++	mov	$ap_real,$ap
++	mov	$bp_real,$bp
++	ldr	$poly1,.Lpoly+8
++	ldr	$poly3,.Lpoly+24
++
++	ldp	$a0,$a1,[$ap,#64]	// in1_z
++	ldp	$a2,$a3,[$ap,#64+16]
++	orr	$t0,$a0,$a1
++	orr	$t2,$a2,$a3
++	orr	$in1infty,$t0,$t2
++	cmp	$in1infty,#0
++	csetm	$in1infty,ne		// !in1infty
++
++	ldp	$acc0,$acc1,[$bp]	// in2_x
++	ldp	$acc2,$acc3,[$bp,#16]
++	ldp	$t0,$t1,[$bp,#32]	// in2_y
++	ldp	$t2,$t3,[$bp,#48]
++	orr	$acc0,$acc0,$acc1
++	orr	$acc2,$acc2,$acc3
++	orr	$t0,$t0,$t1
++	orr	$t2,$t2,$t3
++	orr	$acc0,$acc0,$acc2
++	orr	$t0,$t0,$t2
++	orr	$in2infty,$acc0,$t0
++	cmp	$in2infty,#0
++	csetm	$in2infty,ne		// !in2infty
++
++	add	$rp,sp,#$Z1sqr
++	bl	__ecp_nistz256_sqr_mont	// p256_sqr_mont(Z1sqr, in1_z);
++
++	mov	$a0,$acc0
++	mov	$a1,$acc1
++	mov	$a2,$acc2
++	mov	$a3,$acc3
++	ldr	$bi,[$bp_real]
++	add	$bp,$bp_real,#0
++	add	$rp,sp,#$U2
++	bl	__ecp_nistz256_mul_mont	// p256_mul_mont(U2, Z1sqr, in2_x);
++
++	add	$bp,$ap_real,#0
++	 ldr	$bi,[$ap_real,#64]	// forward load for p256_mul_mont
++	 ldp	$a0,$a1,[sp,#$Z1sqr]
++	 ldp	$a2,$a3,[sp,#$Z1sqr+16]
++	add	$rp,sp,#$H
++	bl	__ecp_nistz256_sub_from	// p256_sub(H, U2, in1_x);
++
++	add	$bp,$ap_real,#64
++	add	$rp,sp,#$S2
++	bl	__ecp_nistz256_mul_mont	// p256_mul_mont(S2, Z1sqr, in1_z);
++
++	ldr	$bi,[$ap_real,#64]
++	ldp	$a0,$a1,[sp,#$H]
++	ldp	$a2,$a3,[sp,#$H+16]
++	add	$bp,$ap_real,#64
++	add	$rp,sp,#$res_z
++	bl	__ecp_nistz256_mul_mont	// p256_mul_mont(res_z, H, in1_z);
++
++	ldr	$bi,[$bp_real,#32]
++	ldp	$a0,$a1,[sp,#$S2]
++	ldp	$a2,$a3,[sp,#$S2+16]
++	add	$bp,$bp_real,#32
++	add	$rp,sp,#$S2
++	bl	__ecp_nistz256_mul_mont	// p256_mul_mont(S2, S2, in2_y);
++
++	add	$bp,$ap_real,#32
++	 ldp	$a0,$a1,[sp,#$H]	// forward load for p256_sqr_mont
++	 ldp	$a2,$a3,[sp,#$H+16]
++	add	$rp,sp,#$R
++	bl	__ecp_nistz256_sub_from	// p256_sub(R, S2, in1_y);
++
++	add	$rp,sp,#$Hsqr
++	bl	__ecp_nistz256_sqr_mont	// p256_sqr_mont(Hsqr, H);
++
++	ldp	$a0,$a1,[sp,#$R]
++	ldp	$a2,$a3,[sp,#$R+16]
++	add	$rp,sp,#$Rsqr
++	bl	__ecp_nistz256_sqr_mont	// p256_sqr_mont(Rsqr, R);
++
++	ldr	$bi,[sp,#$H]
++	ldp	$a0,$a1,[sp,#$Hsqr]
++	ldp	$a2,$a3,[sp,#$Hsqr+16]
++	add	$bp,sp,#$H
++	add	$rp,sp,#$Hcub
++	bl	__ecp_nistz256_mul_mont	// p256_mul_mont(Hcub, Hsqr, H);
++
++	ldr	$bi,[$ap_real]
++	ldp	$a0,$a1,[sp,#$Hsqr]
++	ldp	$a2,$a3,[sp,#$Hsqr+16]
++	add	$bp,$ap_real,#0
++	add	$rp,sp,#$U2
++	bl	__ecp_nistz256_mul_mont	// p256_mul_mont(U2, in1_x, Hsqr);
++
++	mov	$t0,$acc0
++	mov	$t1,$acc1
++	mov	$t2,$acc2
++	mov	$t3,$acc3
++	add	$rp,sp,#$Hsqr
++	bl	__ecp_nistz256_add	// p256_mul_by_2(Hsqr, U2);
++
++	add	$bp,sp,#$Rsqr
++	add	$rp,sp,#$res_x
++	bl	__ecp_nistz256_sub_morf	// p256_sub(res_x, Rsqr, Hsqr);
++
++	add	$bp,sp,#$Hcub
++	bl	__ecp_nistz256_sub_from	//  p256_sub(res_x, res_x, Hcub);
++
++	add	$bp,sp,#$U2
++	 ldr	$bi,[$ap_real,#32]	// forward load for p256_mul_mont
++	 ldp	$a0,$a1,[sp,#$Hcub]
++	 ldp	$a2,$a3,[sp,#$Hcub+16]
++	add	$rp,sp,#$res_y
++	bl	__ecp_nistz256_sub_morf	// p256_sub(res_y, U2, res_x);
++
++	add	$bp,$ap_real,#32
++	add	$rp,sp,#$S2
++	bl	__ecp_nistz256_mul_mont	// p256_mul_mont(S2, in1_y, Hcub);
++
++	ldr	$bi,[sp,#$R]
++	ldp	$a0,$a1,[sp,#$res_y]
++	ldp	$a2,$a3,[sp,#$res_y+16]
++	add	$bp,sp,#$R
++	add	$rp,sp,#$res_y
++	bl	__ecp_nistz256_mul_mont	// p256_mul_mont(res_y, res_y, R);
++
++	add	$bp,sp,#$S2
++	bl	__ecp_nistz256_sub_from	// p256_sub(res_y, res_y, S2);
++
++	ldp	$a0,$a1,[sp,#$res_x]		// res
++	ldp	$a2,$a3,[sp,#$res_x+16]
++	ldp	$t0,$t1,[$bp_real]		// in2
++	ldp	$t2,$t3,[$bp_real,#16]
++___
++for($i=0;$i<64;$i+=32) {		# conditional moves
++$code.=<<___;
++	ldp	$acc0,$acc1,[$ap_real,#$i]	// in1
++	cmp	$in1infty,#0			// !$in1intfy, remember?
++	ldp	$acc2,$acc3,[$ap_real,#$i+16]
++	csel	$t0,$a0,$t0,ne
++	csel	$t1,$a1,$t1,ne
++	ldp	$a0,$a1,[sp,#$res_x+$i+32]	// res
++	csel	$t2,$a2,$t2,ne
++	csel	$t3,$a3,$t3,ne
++	cmp	$in2infty,#0			// !$in2intfy, remember?
++	ldp	$a2,$a3,[sp,#$res_x+$i+48]
++	csel	$acc0,$t0,$acc0,ne
++	csel	$acc1,$t1,$acc1,ne
++	ldp	$t0,$t1,[$bp_real,#$i+32]	// in2
++	csel	$acc2,$t2,$acc2,ne
++	csel	$acc3,$t3,$acc3,ne
++	ldp	$t2,$t3,[$bp_real,#$i+48]
++	stp	$acc0,$acc1,[$rp_real,#$i]
++	stp	$acc2,$acc3,[$rp_real,#$i+16]
++___
++$code.=<<___	if ($i == 0);
++	adr	$bp_real,.Lone_mont-64
++___
++}
++$code.=<<___;
++	ldp	$acc0,$acc1,[$ap_real,#$i]	// in1
++	cmp	$in1infty,#0			// !$in1intfy, remember?
++	ldp	$acc2,$acc3,[$ap_real,#$i+16]
++	csel	$t0,$a0,$t0,ne
++	csel	$t1,$a1,$t1,ne
++	csel	$t2,$a2,$t2,ne
++	csel	$t3,$a3,$t3,ne
++	cmp	$in2infty,#0			// !$in2intfy, remember?
++	csel	$acc0,$t0,$acc0,ne
++	csel	$acc1,$t1,$acc1,ne
++	csel	$acc2,$t2,$acc2,ne
++	csel	$acc3,$t3,$acc3,ne
++	stp	$acc0,$acc1,[$rp_real,#$i]
++	stp	$acc2,$acc3,[$rp_real,#$i+16]
++
++	add	sp,x29,#0		// destroy frame
++	ldp	x19,x20,[x29,#16]
++	ldp	x21,x22,[x29,#32]
++	ldp	x23,x24,[x29,#48]
++	ldp	x25,x26,[x29,#64]
++	ldp	x29,x30,[sp],#80
++	ret
++.size	ecp_nistz256_point_add_affine,.-ecp_nistz256_point_add_affine
++___
++}	}
++
++########################################################################
++# scatter-gather subroutines
++{
++my ($out,$inp,$index,$mask)=map("x$_",(0..3));
++$code.=<<___;
++// void	ecp_nistz256_scatter_w5(void *x0,const P256_POINT *x1,
++//					 int x2);
++.globl	ecp_nistz256_scatter_w5
++.type	ecp_nistz256_scatter_w5,%function
++.align	4
++ecp_nistz256_scatter_w5:
++	stp	x29,x30,[sp,#-16]!
++	add	x29,sp,#0
++
++	add	$out,$out,$index,lsl#2
++
++	ldp	x4,x5,[$inp]		// X
++	ldp	x6,x7,[$inp,#16]
++	str	w4,[$out,#64*0-4]
++	lsr	x4,x4,#32
++	str	w5,[$out,#64*1-4]
++	lsr	x5,x5,#32
++	str	w6,[$out,#64*2-4]
++	lsr	x6,x6,#32
++	str	w7,[$out,#64*3-4]
++	lsr	x7,x7,#32
++	str	w4,[$out,#64*4-4]
++	str	w5,[$out,#64*5-4]
++	str	w6,[$out,#64*6-4]
++	str	w7,[$out,#64*7-4]
++	add	$out,$out,#64*8
++
++	ldp	x4,x5,[$inp,#32]	// Y
++	ldp	x6,x7,[$inp,#48]
++	str	w4,[$out,#64*0-4]
++	lsr	x4,x4,#32
++	str	w5,[$out,#64*1-4]
++	lsr	x5,x5,#32
++	str	w6,[$out,#64*2-4]
++	lsr	x6,x6,#32
++	str	w7,[$out,#64*3-4]
++	lsr	x7,x7,#32
++	str	w4,[$out,#64*4-4]
++	str	w5,[$out,#64*5-4]
++	str	w6,[$out,#64*6-4]
++	str	w7,[$out,#64*7-4]
++	add	$out,$out,#64*8
++
++	ldp	x4,x5,[$inp,#64]	// Z
++	ldp	x6,x7,[$inp,#80]
++	str	w4,[$out,#64*0-4]
++	lsr	x4,x4,#32
++	str	w5,[$out,#64*1-4]
++	lsr	x5,x5,#32
++	str	w6,[$out,#64*2-4]
++	lsr	x6,x6,#32
++	str	w7,[$out,#64*3-4]
++	lsr	x7,x7,#32
++	str	w4,[$out,#64*4-4]
++	str	w5,[$out,#64*5-4]
++	str	w6,[$out,#64*6-4]
++	str	w7,[$out,#64*7-4]
++
++	ldr	x29,[sp],#16
++	ret
++.size	ecp_nistz256_scatter_w5,.-ecp_nistz256_scatter_w5
++
++// void	ecp_nistz256_gather_w5(P256_POINT *x0,const void *x1,
++//					      int x2);
++.globl	ecp_nistz256_gather_w5
++.type	ecp_nistz256_gather_w5,%function
++.align	4
++ecp_nistz256_gather_w5:
++	stp	x29,x30,[sp,#-16]!
++	add	x29,sp,#0
++
++	cmp	$index,xzr
++	csetm	x3,ne
++	add	$index,$index,x3
++	add	$inp,$inp,$index,lsl#2
++
++	ldr	w4,[$inp,#64*0]
++	ldr	w5,[$inp,#64*1]
++	ldr	w6,[$inp,#64*2]
++	ldr	w7,[$inp,#64*3]
++	ldr	w8,[$inp,#64*4]
++	ldr	w9,[$inp,#64*5]
++	ldr	w10,[$inp,#64*6]
++	ldr	w11,[$inp,#64*7]
++	add	$inp,$inp,#64*8
++	orr	x4,x4,x8,lsl#32
++	orr	x5,x5,x9,lsl#32
++	orr	x6,x6,x10,lsl#32
++	orr	x7,x7,x11,lsl#32
++	csel	x4,x4,xzr,ne
++	csel	x5,x5,xzr,ne
++	csel	x6,x6,xzr,ne
++	csel	x7,x7,xzr,ne
++	stp	x4,x5,[$out]		// X
++	stp	x6,x7,[$out,#16]
++
++	ldr	w4,[$inp,#64*0]
++	ldr	w5,[$inp,#64*1]
++	ldr	w6,[$inp,#64*2]
++	ldr	w7,[$inp,#64*3]
++	ldr	w8,[$inp,#64*4]
++	ldr	w9,[$inp,#64*5]
++	ldr	w10,[$inp,#64*6]
++	ldr	w11,[$inp,#64*7]
++	add	$inp,$inp,#64*8
++	orr	x4,x4,x8,lsl#32
++	orr	x5,x5,x9,lsl#32
++	orr	x6,x6,x10,lsl#32
++	orr	x7,x7,x11,lsl#32
++	csel	x4,x4,xzr,ne
++	csel	x5,x5,xzr,ne
++	csel	x6,x6,xzr,ne
++	csel	x7,x7,xzr,ne
++	stp	x4,x5,[$out,#32]	// Y
++	stp	x6,x7,[$out,#48]
++
++	ldr	w4,[$inp,#64*0]
++	ldr	w5,[$inp,#64*1]
++	ldr	w6,[$inp,#64*2]
++	ldr	w7,[$inp,#64*3]
++	ldr	w8,[$inp,#64*4]
++	ldr	w9,[$inp,#64*5]
++	ldr	w10,[$inp,#64*6]
++	ldr	w11,[$inp,#64*7]
++	orr	x4,x4,x8,lsl#32
++	orr	x5,x5,x9,lsl#32
++	orr	x6,x6,x10,lsl#32
++	orr	x7,x7,x11,lsl#32
++	csel	x4,x4,xzr,ne
++	csel	x5,x5,xzr,ne
++	csel	x6,x6,xzr,ne
++	csel	x7,x7,xzr,ne
++	stp	x4,x5,[$out,#64]	// Z
++	stp	x6,x7,[$out,#80]
++
++	ldr	x29,[sp],#16
++	ret
++.size	ecp_nistz256_gather_w5,.-ecp_nistz256_gather_w5
++
++// void	ecp_nistz256_scatter_w7(void *x0,const P256_POINT_AFFINE *x1,
++//					 int x2);
++.globl	ecp_nistz256_scatter_w7
++.type	ecp_nistz256_scatter_w7,%function
++.align	4
++ecp_nistz256_scatter_w7:
++	stp	x29,x30,[sp,#-16]!
++	add	x29,sp,#0
++
++	add	$out,$out,$index
++	mov	$index,#64/8
++.Loop_scatter_w7:
++	ldr	x3,[$inp],#8
++	subs	$index,$index,#1
++	prfm	pstl1strm,[$out,#4096+64*0]
++	prfm	pstl1strm,[$out,#4096+64*1]
++	prfm	pstl1strm,[$out,#4096+64*2]
++	prfm	pstl1strm,[$out,#4096+64*3]
++	prfm	pstl1strm,[$out,#4096+64*4]
++	prfm	pstl1strm,[$out,#4096+64*5]
++	prfm	pstl1strm,[$out,#4096+64*6]
++	prfm	pstl1strm,[$out,#4096+64*7]
++	strb	w3,[$out,#64*0-1]
++	lsr	x3,x3,#8
++	strb	w3,[$out,#64*1-1]
++	lsr	x3,x3,#8
++	strb	w3,[$out,#64*2-1]
++	lsr	x3,x3,#8
++	strb	w3,[$out,#64*3-1]
++	lsr	x3,x3,#8
++	strb	w3,[$out,#64*4-1]
++	lsr	x3,x3,#8
++	strb	w3,[$out,#64*5-1]
++	lsr	x3,x3,#8
++	strb	w3,[$out,#64*6-1]
++	lsr	x3,x3,#8
++	strb	w3,[$out,#64*7-1]
++	add	$out,$out,#64*8
++	b.ne	.Loop_scatter_w7
++
++	ldr	x29,[sp],#16
++	ret
++.size	ecp_nistz256_scatter_w7,.-ecp_nistz256_scatter_w7
++
++// void	ecp_nistz256_gather_w7(P256_POINT_AFFINE *x0,const void *x1,
++//						     int x2);
++.globl	ecp_nistz256_gather_w7
++.type	ecp_nistz256_gather_w7,%function
++.align	4
++ecp_nistz256_gather_w7:
++	stp	x29,x30,[sp,#-16]!
++	add	x29,sp,#0
++
++	cmp	$index,xzr
++	csetm	x3,ne
++	add	$index,$index,x3
++	add	$inp,$inp,$index
++	mov	$index,#64/8
++	nop
++.Loop_gather_w7:
++	ldrb	w4,[$inp,#64*0]
++	prfm	pldl1strm,[$inp,#4096+64*0]
++	subs	$index,$index,#1
++	ldrb	w5,[$inp,#64*1]
++	prfm	pldl1strm,[$inp,#4096+64*1]
++	ldrb	w6,[$inp,#64*2]
++	prfm	pldl1strm,[$inp,#4096+64*2]
++	ldrb	w7,[$inp,#64*3]
++	prfm	pldl1strm,[$inp,#4096+64*3]
++	ldrb	w8,[$inp,#64*4]
++	prfm	pldl1strm,[$inp,#4096+64*4]
++	ldrb	w9,[$inp,#64*5]
++	prfm	pldl1strm,[$inp,#4096+64*5]
++	ldrb	w10,[$inp,#64*6]
++	prfm	pldl1strm,[$inp,#4096+64*6]
++	ldrb	w11,[$inp,#64*7]
++	prfm	pldl1strm,[$inp,#4096+64*7]
++	add	$inp,$inp,#64*8
++	orr	x4,x4,x5,lsl#8
++	orr	x6,x6,x7,lsl#8
++	orr	x8,x8,x9,lsl#8
++	orr	x4,x4,x6,lsl#16
++	orr	x10,x10,x11,lsl#8
++	orr	x4,x4,x8,lsl#32
++	orr	x4,x4,x10,lsl#48
++	and	x4,x4,x3
++	str	x4,[$out],#8
++	b.ne	.Loop_gather_w7
++
++	ldr	x29,[sp],#16
++	ret
++.size	ecp_nistz256_gather_w7,.-ecp_nistz256_gather_w7
++___
++}
++
++foreach (split("\n",$code)) {
++	s/\`([^\`]*)\`/eval $1/ge;
++
++	print $_,"\n";
++}
++close STDOUT;	# enforce flush
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/ec/asm/ecp_nistz256-avx2.pl b/CryptoPkg/Library/OpensslLib/openssl/crypto/ec/asm/ecp_nistz256-avx2.pl
+new file mode 100755
+index 0000000..3bdd2cf
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/ec/asm/ecp_nistz256-avx2.pl
+@@ -0,0 +1,2100 @@
++#! /usr/bin/env perl
++# Copyright 2014-2016 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
++# in the file LICENSE in the source distribution or at
++# https://www.openssl.org/source/license.html
++
++
++##############################################################################
++#                                                                            #
++# Copyright 2014 Intel Corporation                                           #
++#                                                                            #
++# Licensed under the Apache License, Version 2.0 (the "License");            #
++# you may not use this file except in compliance with the License.           #
++# You may obtain a copy of the License at                                    #
++#                                                                            #
++#    http://www.apache.org/licenses/LICENSE-2.0                              #
++#                                                                            #
++# Unless required by applicable law or agreed to in writing, software        #
++# distributed under the License is distributed on an "AS IS" BASIS,          #
++# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   #
++# See the License for the specific language governing permissions and        #
++# limitations under the License.                                             #
++#                                                                            #
++##############################################################################
++#                                                                            #
++#  Developers and authors:                                                   #
++#  Shay Gueron (1, 2), and Vlad Krasnov (1)                                  #
++#  (1) Intel Corporation, Israel Development Center                          #
++#  (2) University of Haifa                                                   #
++#  Reference:                                                                #
++#  S.Gueron and V.Krasnov, "Fast Prime Field Elliptic Curve Cryptography with#
++#                           256 Bit Primes"                                  #
++#                                                                            #
++##############################################################################
++
++$flavour = shift;
++$output  = shift;
++if ($flavour =~ /\./) { $output = $flavour; undef $flavour; }
++
++$win64=0; $win64=1 if ($flavour =~ /[nm]asm|mingw64/ || $output =~ /\.asm$/);
++
++$0 =~ m/(.*[\/\\])[^\/\\]+$/; $dir=$1;
++( $xlate="${dir}x86_64-xlate.pl" and -f $xlate ) or
++( $xlate="${dir}../../perlasm/x86_64-xlate.pl" and -f $xlate) or
++die "can't locate x86_64-xlate.pl";
++
++open OUT,"| \"$^X\" $xlate $flavour $output";
++*STDOUT=*OUT;
++
++if (`$ENV{CC} -Wa,-v -c -o /dev/null -x assembler /dev/null 2>&1`
++		=~ /GNU assembler version ([2-9]\.[0-9]+)/) {
++	$avx = ($1>=2.19) + ($1>=2.22);
++	$addx = ($1>=2.23);
++}
++
++if (!$addx && $win64 && ($flavour =~ /nasm/ || $ENV{ASM} =~ /nasm/) &&
++	    `nasm -v 2>&1` =~ /NASM version ([2-9]\.[0-9]+)/) {
++	$avx = ($1>=2.09) + ($1>=2.10);
++	$addx = ($1>=2.10);
++}
++
++if (!$addx && $win64 && ($flavour =~ /masm/ || $ENV{ASM} =~ /ml64/) &&
++	    `ml64 2>&1` =~ /Version ([0-9]+)\./) {
++	$avx = ($1>=10) + ($1>=11);
++	$addx = ($1>=12);
++}
++
++if (!$addx && `$ENV{CC} -v 2>&1` =~ /(^clang version|based on LLVM) ([3-9])\.([0-9]+)/) {
++	my $ver = $2 + $3/100.0;	# 3.1->3.01, 3.10->3.10
++	$avx = ($ver>=3.0) + ($ver>=3.01);
++	$addx = ($ver>=3.03);
++}
++
++if ($avx>=2) {{
++$digit_size = "\$29";
++$n_digits = "\$9";
++
++$code.=<<___;
++.text
++
++.align 64
++.LAVX2_AND_MASK:
++.LAVX2_POLY:
++.quad 0x1fffffff, 0x1fffffff, 0x1fffffff, 0x1fffffff
++.quad 0x1fffffff, 0x1fffffff, 0x1fffffff, 0x1fffffff
++.quad 0x1fffffff, 0x1fffffff, 0x1fffffff, 0x1fffffff
++.quad 0x000001ff, 0x000001ff, 0x000001ff, 0x000001ff
++.quad 0x00000000, 0x00000000, 0x00000000, 0x00000000
++.quad 0x00000000, 0x00000000, 0x00000000, 0x00000000
++.quad 0x00040000, 0x00040000, 0x00040000, 0x00040000
++.quad 0x1fe00000, 0x1fe00000, 0x1fe00000, 0x1fe00000
++.quad 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff
++
++.LAVX2_POLY_x2:
++.quad 0x7FFFFFFC, 0x7FFFFFFC, 0x7FFFFFFC, 0x7FFFFFFC
++.quad 0x7FFFFFFC, 0x7FFFFFFC, 0x7FFFFFFC, 0x7FFFFFFC
++.quad 0x7FFFFFFC, 0x7FFFFFFC, 0x7FFFFFFC, 0x7FFFFFFC
++.quad 0x400007FC, 0x400007FC, 0x400007FC, 0x400007FC
++.quad 0x3FFFFFFE, 0x3FFFFFFE, 0x3FFFFFFE, 0x3FFFFFFE
++.quad 0x3FFFFFFE, 0x3FFFFFFE, 0x3FFFFFFE, 0x3FFFFFFE
++.quad 0x400FFFFE, 0x400FFFFE, 0x400FFFFE, 0x400FFFFE
++.quad 0x7F7FFFFE, 0x7F7FFFFE, 0x7F7FFFFE, 0x7F7FFFFE
++.quad 0x03FFFFFC, 0x03FFFFFC, 0x03FFFFFC, 0x03FFFFFC
++
++.LAVX2_POLY_x8:
++.quad 0xFFFFFFF8, 0xFFFFFFF8, 0xFFFFFFF8, 0xFFFFFFF8
++.quad 0xFFFFFFF8, 0xFFFFFFF8, 0xFFFFFFF8, 0xFFFFFFF8
++.quad 0xFFFFFFF8, 0xFFFFFFF8, 0xFFFFFFF8, 0xFFFFFFF8
++.quad 0x80000FF8, 0x80000FF8, 0x80000FF8, 0x80000FF8
++.quad 0x7FFFFFFC, 0x7FFFFFFC, 0x7FFFFFFC, 0x7FFFFFFC
++.quad 0x7FFFFFFC, 0x7FFFFFFC, 0x7FFFFFFC, 0x7FFFFFFC
++.quad 0x801FFFFC, 0x801FFFFC, 0x801FFFFC, 0x801FFFFC
++.quad 0xFEFFFFFC, 0xFEFFFFFC, 0xFEFFFFFC, 0xFEFFFFFC
++.quad 0x07FFFFF8, 0x07FFFFF8, 0x07FFFFF8, 0x07FFFFF8
++
++.LONE:
++.quad 0x00000020, 0x00000020, 0x00000020, 0x00000020
++.quad 0x00000000, 0x00000000, 0x00000000, 0x00000000
++.quad 0x00000000, 0x00000000, 0x00000000, 0x00000000
++.quad 0x1fffc000, 0x1fffc000, 0x1fffc000, 0x1fffc000
++.quad 0x1fffffff, 0x1fffffff, 0x1fffffff, 0x1fffffff
++.quad 0x1fffffff, 0x1fffffff, 0x1fffffff, 0x1fffffff
++.quad 0x1f7fffff, 0x1f7fffff, 0x1f7fffff, 0x1f7fffff
++.quad 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x03ffffff
++.quad 0x00000000, 0x00000000, 0x00000000, 0x00000000
++
++# RR = 2^266 mod p in AVX2 format, to transform from the native OpenSSL
++# Montgomery form (*2^256) to our format (*2^261)
++
++.LTO_MONT_AVX2:
++.quad 0x00000400, 0x00000400, 0x00000400, 0x00000400
++.quad 0x00000000, 0x00000000, 0x00000000, 0x00000000
++.quad 0x00000000, 0x00000000, 0x00000000, 0x00000000
++.quad 0x1ff80000, 0x1ff80000, 0x1ff80000, 0x1ff80000
++.quad 0x1fffffff, 0x1fffffff, 0x1fffffff, 0x1fffffff
++.quad 0x1fffffff, 0x1fffffff, 0x1fffffff, 0x1fffffff
++.quad 0x0fffffff, 0x0fffffff, 0x0fffffff, 0x0fffffff
++.quad 0x1fffffff, 0x1fffffff, 0x1fffffff, 0x1fffffff
++.quad 0x00000003, 0x00000003, 0x00000003, 0x00000003
++
++.LFROM_MONT_AVX2:
++.quad 0x00000001, 0x00000001, 0x00000001, 0x00000001
++.quad 0x00000000, 0x00000000, 0x00000000, 0x00000000
++.quad 0x00000000, 0x00000000, 0x00000000, 0x00000000
++.quad 0x1ffffe00, 0x1ffffe00, 0x1ffffe00, 0x1ffffe00
++.quad 0x1fffffff, 0x1fffffff, 0x1fffffff, 0x1fffffff
++.quad 0x1fffffff, 0x1fffffff, 0x1fffffff, 0x1fffffff
++.quad 0x1ffbffff, 0x1ffbffff, 0x1ffbffff, 0x1ffbffff
++.quad 0x001fffff, 0x001fffff, 0x001fffff, 0x001fffff
++.quad 0x00000000, 0x00000000, 0x00000000, 0x00000000
++
++.LIntOne:
++.long 1,1,1,1,1,1,1,1
++___
++
++{
++# This function receives a pointer to an array of four affine points
++# (X, Y, <1>) and rearanges the data for AVX2 execution, while
++# converting it to 2^29 radix redundant form
++
++my ($X0,$X1,$X2,$X3, $Y0,$Y1,$Y2,$Y3,
++    $T0,$T1,$T2,$T3, $T4,$T5,$T6,$T7)=map("%ymm$_",(0..15));
++
++$code.=<<___;
++.globl	ecp_nistz256_avx2_transpose_convert
++.type	ecp_nistz256_avx2_transpose_convert,\@function,2
++.align 64
++ecp_nistz256_avx2_transpose_convert:
++	vzeroupper
++___
++$code.=<<___	if ($win64);
++	lea	-8-16*10(%rsp), %rsp
++	vmovaps	%xmm6, -8-16*10(%rax)
++	vmovaps	%xmm7, -8-16*9(%rax)
++	vmovaps	%xmm8, -8-16*8(%rax)
++	vmovaps	%xmm9, -8-16*7(%rax)
++	vmovaps	%xmm10, -8-16*6(%rax)
++	vmovaps	%xmm11, -8-16*5(%rax)
++	vmovaps	%xmm12, -8-16*4(%rax)
++	vmovaps	%xmm13, -8-16*3(%rax)
++	vmovaps	%xmm14, -8-16*2(%rax)
++	vmovaps	%xmm15, -8-16*1(%rax)
++___
++$code.=<<___;
++	# Load the data
++	vmovdqa		32*0(%rsi), $X0
++	lea		112(%rsi), %rax		# size optimization
++	vmovdqa		32*1(%rsi), $Y0
++	lea		.LAVX2_AND_MASK(%rip), %rdx
++	vmovdqa		32*2(%rsi), $X1
++	vmovdqa		32*3(%rsi), $Y1
++	vmovdqa		32*4-112(%rax), $X2
++	vmovdqa		32*5-112(%rax), $Y2
++	vmovdqa		32*6-112(%rax), $X3
++	vmovdqa		32*7-112(%rax), $Y3
++
++	# Transpose X and Y independently
++	vpunpcklqdq	$X1, $X0, $T0		# T0 = [B2 A2 B0 A0]
++	vpunpcklqdq	$X3, $X2, $T1		# T1 = [D2 C2 D0 C0]
++	vpunpckhqdq	$X1, $X0, $T2		# T2 = [B3 A3 B1 A1]
++	vpunpckhqdq	$X3, $X2, $T3		# T3 = [D3 C3 D1 C1]
++
++	vpunpcklqdq	$Y1, $Y0, $T4
++	vpunpcklqdq	$Y3, $Y2, $T5
++	vpunpckhqdq	$Y1, $Y0, $T6
++	vpunpckhqdq	$Y3, $Y2, $T7
++
++	vperm2i128	\$0x20, $T1, $T0, $X0	# X0 = [D0 C0 B0 A0]
++	vperm2i128	\$0x20, $T3, $T2, $X1	# X1 = [D1 C1 B1 A1]
++	vperm2i128	\$0x31, $T1, $T0, $X2	# X2 = [D2 C2 B2 A2]
++	vperm2i128	\$0x31, $T3, $T2, $X3	# X3 = [D3 C3 B3 A3]
++
++	vperm2i128	\$0x20, $T5, $T4, $Y0
++	vperm2i128	\$0x20, $T7, $T6, $Y1
++	vperm2i128	\$0x31, $T5, $T4, $Y2
++	vperm2i128	\$0x31, $T7, $T6, $Y3
++	vmovdqa		(%rdx), $T7
++
++	vpand		(%rdx), $X0, $T0	# out[0] = in[0] & mask;
++	vpsrlq		\$29, $X0, $X0
++	vpand		$T7, $X0, $T1		# out[1] = (in[0] >> shift) & mask;
++	vpsrlq		\$29, $X0, $X0
++	vpsllq		\$6, $X1, $T2
++	vpxor		$X0, $T2, $T2
++	vpand		$T7, $T2, $T2		# out[2] = ((in[0] >> (shift*2)) ^ (in[1] << (64-shift*2))) & mask;
++	vpsrlq		\$23, $X1, $X1
++	vpand		$T7, $X1, $T3		# out[3] = (in[1] >> ((shift*3)%64)) & mask;
++	vpsrlq		\$29, $X1, $X1
++	vpsllq		\$12, $X2, $T4
++	vpxor		$X1, $T4, $T4
++	vpand		$T7, $T4, $T4		# out[4] = ((in[1] >> ((shift*4)%64)) ^ (in[2] << (64*2-shift*4))) & mask;
++	vpsrlq		\$17, $X2, $X2
++	vpand		$T7, $X2, $T5		# out[5] = (in[2] >> ((shift*5)%64)) & mask;
++	vpsrlq		\$29, $X2, $X2
++	vpsllq		\$18, $X3, $T6
++	vpxor		$X2, $T6, $T6
++	vpand		$T7, $T6, $T6		# out[6] = ((in[2] >> ((shift*6)%64)) ^ (in[3] << (64*3-shift*6))) & mask;
++	vpsrlq		\$11, $X3, $X3
++	 vmovdqa	$T0, 32*0(%rdi)
++	 lea		112(%rdi), %rax		# size optimization
++	vpand		$T7, $X3, $T0		# out[7] = (in[3] >> ((shift*7)%64)) & mask;
++	vpsrlq		\$29, $X3, $X3		# out[8] = (in[3] >> ((shift*8)%64)) & mask;
++
++	vmovdqa		$T1, 32*1(%rdi)
++	vmovdqa		$T2, 32*2(%rdi)
++	vmovdqa		$T3, 32*3(%rdi)
++	vmovdqa		$T4, 32*4-112(%rax)
++	vmovdqa		$T5, 32*5-112(%rax)
++	vmovdqa		$T6, 32*6-112(%rax)
++	vmovdqa		$T0, 32*7-112(%rax)
++	vmovdqa		$X3, 32*8-112(%rax)
++	lea		448(%rdi), %rax		# size optimization
++
++	vpand		$T7, $Y0, $T0		# out[0] = in[0] & mask;
++	vpsrlq		\$29, $Y0, $Y0
++	vpand		$T7, $Y0, $T1		# out[1] = (in[0] >> shift) & mask;
++	vpsrlq		\$29, $Y0, $Y0
++	vpsllq		\$6, $Y1, $T2
++	vpxor		$Y0, $T2, $T2
++	vpand		$T7, $T2, $T2		# out[2] = ((in[0] >> (shift*2)) ^ (in[1] << (64-shift*2))) & mask;
++	vpsrlq		\$23, $Y1, $Y1
++	vpand		$T7, $Y1, $T3		# out[3] = (in[1] >> ((shift*3)%64)) & mask;
++	vpsrlq		\$29, $Y1, $Y1
++	vpsllq		\$12, $Y2, $T4
++	vpxor		$Y1, $T4, $T4
++	vpand		$T7, $T4, $T4		# out[4] = ((in[1] >> ((shift*4)%64)) ^ (in[2] << (64*2-shift*4))) & mask;
++	vpsrlq		\$17, $Y2, $Y2
++	vpand		$T7, $Y2, $T5		# out[5] = (in[2] >> ((shift*5)%64)) & mask;
++	vpsrlq		\$29, $Y2, $Y2
++	vpsllq		\$18, $Y3, $T6
++	vpxor		$Y2, $T6, $T6
++	vpand		$T7, $T6, $T6		# out[6] = ((in[2] >> ((shift*6)%64)) ^ (in[3] << (64*3-shift*6))) & mask;
++	vpsrlq		\$11, $Y3, $Y3
++	 vmovdqa	$T0, 32*9-448(%rax)
++	vpand		$T7, $Y3, $T0		# out[7] = (in[3] >> ((shift*7)%64)) & mask;
++	vpsrlq		\$29, $Y3, $Y3		# out[8] = (in[3] >> ((shift*8)%64)) & mask;
++
++	vmovdqa		$T1, 32*10-448(%rax)
++	vmovdqa		$T2, 32*11-448(%rax)
++	vmovdqa		$T3, 32*12-448(%rax)
++	vmovdqa		$T4, 32*13-448(%rax)
++	vmovdqa		$T5, 32*14-448(%rax)
++	vmovdqa		$T6, 32*15-448(%rax)
++	vmovdqa		$T0, 32*16-448(%rax)
++	vmovdqa		$Y3, 32*17-448(%rax)
++
++	vzeroupper
++___
++$code.=<<___	if ($win64);
++	movaps	16*0(%rsp), %xmm6
++	movaps	16*1(%rsp), %xmm7
++	movaps	16*2(%rsp), %xmm8
++	movaps	16*3(%rsp), %xmm9
++	movaps	16*4(%rsp), %xmm10
++	movaps	16*5(%rsp), %xmm11
++	movaps	16*6(%rsp), %xmm12
++	movaps	16*7(%rsp), %xmm13
++	movaps	16*8(%rsp), %xmm14
++	movaps	16*9(%rsp), %xmm15
++	lea	8+16*10(%rsp), %rsp
++___
++$code.=<<___;
++	ret
++.size	ecp_nistz256_avx2_transpose_convert,.-ecp_nistz256_avx2_transpose_convert
++___
++}
++{
++################################################################################
++# This function receives a pointer to an array of four AVX2 formatted points
++# (X, Y, Z) convert the data to normal representation, and rearanges the data
++
++my ($D0,$D1,$D2,$D3, $D4,$D5,$D6,$D7, $D8)=map("%ymm$_",(0..8));
++my ($T0,$T1,$T2,$T3, $T4,$T5,$T6)=map("%ymm$_",(9..15));
++
++$code.=<<___;
++
++.globl	ecp_nistz256_avx2_convert_transpose_back
++.type	ecp_nistz256_avx2_convert_transpose_back,\@function,2
++.align	32
++ecp_nistz256_avx2_convert_transpose_back:
++	vzeroupper
++___
++$code.=<<___	if ($win64);
++	lea	-8-16*10(%rsp), %rsp
++	vmovaps	%xmm6, -8-16*10(%rax)
++	vmovaps	%xmm7, -8-16*9(%rax)
++	vmovaps	%xmm8, -8-16*8(%rax)
++	vmovaps	%xmm9, -8-16*7(%rax)
++	vmovaps	%xmm10, -8-16*6(%rax)
++	vmovaps	%xmm11, -8-16*5(%rax)
++	vmovaps	%xmm12, -8-16*4(%rax)
++	vmovaps	%xmm13, -8-16*3(%rax)
++	vmovaps	%xmm14, -8-16*2(%rax)
++	vmovaps	%xmm15, -8-16*1(%rax)
++___
++$code.=<<___;
++	mov	\$3, %ecx
++
++.Lconv_loop:
++	vmovdqa		32*0(%rsi), $D0
++	lea		160(%rsi), %rax		# size optimization
++	vmovdqa		32*1(%rsi), $D1
++	vmovdqa		32*2(%rsi), $D2
++	vmovdqa		32*3(%rsi), $D3
++	vmovdqa		32*4-160(%rax), $D4
++	vmovdqa		32*5-160(%rax), $D5
++	vmovdqa		32*6-160(%rax), $D6
++	vmovdqa		32*7-160(%rax), $D7
++	vmovdqa		32*8-160(%rax), $D8
++
++	vpsllq		\$29, $D1, $D1
++	vpsllq		\$58, $D2, $T0
++	vpaddq		$D1, $D0, $D0
++	vpaddq		$T0, $D0, $D0		# out[0] = (in[0]) ^ (in[1] << shift*1) ^ (in[2] << shift*2);
++
++	vpsrlq		\$6, $D2, $D2
++	vpsllq		\$23, $D3, $D3
++	vpsllq		\$52, $D4, $T1
++	vpaddq		$D2, $D3, $D3
++	vpaddq		$D3, $T1, $D1		# out[1] = (in[2] >> (64*1-shift*2)) ^ (in[3] << shift*3%64) ^ (in[4] << shift*4%64);
++
++	vpsrlq		\$12, $D4, $D4
++	vpsllq		\$17, $D5, $D5
++	vpsllq		\$46, $D6, $T2
++	vpaddq		$D4, $D5, $D5
++	vpaddq		$D5, $T2, $D2		# out[2] = (in[4] >> (64*2-shift*4)) ^ (in[5] << shift*5%64) ^ (in[6] << shift*6%64);
++
++	vpsrlq		\$18, $D6, $D6
++	vpsllq		\$11, $D7, $D7
++	vpsllq		\$40, $D8, $T3
++	vpaddq		$D6, $D7, $D7
++	vpaddq		$D7, $T3, $D3		# out[3] = (in[6] >> (64*3-shift*6)) ^ (in[7] << shift*7%64) ^ (in[8] << shift*8%64);
++
++	vpunpcklqdq	$D1, $D0, $T0		# T0 = [B2 A2 B0 A0]
++	vpunpcklqdq	$D3, $D2, $T1		# T1 = [D2 C2 D0 C0]
++	vpunpckhqdq	$D1, $D0, $T2		# T2 = [B3 A3 B1 A1]
++	vpunpckhqdq	$D3, $D2, $T3		# T3 = [D3 C3 D1 C1]
++
++	vperm2i128	\$0x20, $T1, $T0, $D0	# X0 = [D0 C0 B0 A0]
++	vperm2i128	\$0x20, $T3, $T2, $D1	# X1 = [D1 C1 B1 A1]
++	vperm2i128	\$0x31, $T1, $T0, $D2	# X2 = [D2 C2 B2 A2]
++	vperm2i128	\$0x31, $T3, $T2, $D3	# X3 = [D3 C3 B3 A3]
++
++	vmovdqa		$D0, 32*0(%rdi)
++	vmovdqa		$D1, 32*3(%rdi)
++	vmovdqa		$D2, 32*6(%rdi)
++	vmovdqa		$D3, 32*9(%rdi)
++
++	lea		32*9(%rsi), %rsi
++	lea		32*1(%rdi), %rdi
++
++	dec	%ecx
++	jnz	.Lconv_loop
++
++	vzeroupper
++___
++$code.=<<___	if ($win64);
++	movaps	16*0(%rsp), %xmm6
++	movaps	16*1(%rsp), %xmm7
++	movaps	16*2(%rsp), %xmm8
++	movaps	16*3(%rsp), %xmm9
++	movaps	16*4(%rsp), %xmm10
++	movaps	16*5(%rsp), %xmm11
++	movaps	16*6(%rsp), %xmm12
++	movaps	16*7(%rsp), %xmm13
++	movaps	16*8(%rsp), %xmm14
++	movaps	16*9(%rsp), %xmm15
++	lea	8+16*10(%rsp), %rsp
++___
++$code.=<<___;
++	ret
++.size	ecp_nistz256_avx2_convert_transpose_back,.-ecp_nistz256_avx2_convert_transpose_back
++___
++}
++{
++my ($r_ptr,$a_ptr,$b_ptr,$itr)=("%rdi","%rsi","%rdx","%ecx");
++my ($ACC0,$ACC1,$ACC2,$ACC3,$ACC4,$ACC5,$ACC6,$ACC7,$ACC8)=map("%ymm$_",(0..8));
++my ($B,$Y,$T0,$AND_MASK,$OVERFLOW)=map("%ymm$_",(9..13));
++
++sub NORMALIZE {
++my $ret=<<___;
++	vpsrlq		$digit_size, $ACC0, $T0
++	vpand		$AND_MASK, $ACC0, $ACC0
++	vpaddq		$T0, $ACC1, $ACC1
++
++	vpsrlq		$digit_size, $ACC1, $T0
++	vpand		$AND_MASK, $ACC1, $ACC1
++	vpaddq		$T0, $ACC2, $ACC2
++
++	vpsrlq		$digit_size, $ACC2, $T0
++	vpand		$AND_MASK, $ACC2, $ACC2
++	vpaddq		$T0, $ACC3, $ACC3
++
++	vpsrlq		$digit_size, $ACC3, $T0
++	vpand		$AND_MASK, $ACC3, $ACC3
++	vpaddq		$T0, $ACC4, $ACC4
++
++	vpsrlq		$digit_size, $ACC4, $T0
++	vpand		$AND_MASK, $ACC4, $ACC4
++	vpaddq		$T0, $ACC5, $ACC5
++
++	vpsrlq		$digit_size, $ACC5, $T0
++	vpand		$AND_MASK, $ACC5, $ACC5
++	vpaddq		$T0, $ACC6, $ACC6
++
++	vpsrlq		$digit_size, $ACC6, $T0
++	vpand		$AND_MASK, $ACC6, $ACC6
++	vpaddq		$T0, $ACC7, $ACC7
++
++	vpsrlq		$digit_size, $ACC7, $T0
++	vpand		$AND_MASK, $ACC7, $ACC7
++	vpaddq		$T0, $ACC8, $ACC8
++	#vpand		$AND_MASK, $ACC8, $ACC8
++___
++    $ret;
++}
++
++sub STORE {
++my $ret=<<___;
++	vmovdqa		$ACC0, 32*0(%rdi)
++	lea		160(%rdi), %rax		# size optimization
++	vmovdqa		$ACC1, 32*1(%rdi)
++	vmovdqa		$ACC2, 32*2(%rdi)
++	vmovdqa		$ACC3, 32*3(%rdi)
++	vmovdqa		$ACC4, 32*4-160(%rax)
++	vmovdqa		$ACC5, 32*5-160(%rax)
++	vmovdqa		$ACC6, 32*6-160(%rax)
++	vmovdqa		$ACC7, 32*7-160(%rax)
++	vmovdqa		$ACC8, 32*8-160(%rax)
++___
++    $ret;
++}
++
++$code.=<<___;
++.type	avx2_normalize,\@abi-omnipotent
++.align	32
++avx2_normalize:
++	vpsrlq		$digit_size, $ACC0, $T0
++	vpand		$AND_MASK, $ACC0, $ACC0
++	vpaddq		$T0, $ACC1, $ACC1
++
++	vpsrlq		$digit_size, $ACC1, $T0
++	vpand		$AND_MASK, $ACC1, $ACC1
++	vpaddq		$T0, $ACC2, $ACC2
++
++	vpsrlq		$digit_size, $ACC2, $T0
++	vpand		$AND_MASK, $ACC2, $ACC2
++	vpaddq		$T0, $ACC3, $ACC3
++
++	vpsrlq		$digit_size, $ACC3, $T0
++	vpand		$AND_MASK, $ACC3, $ACC3
++	vpaddq		$T0, $ACC4, $ACC4
++
++	vpsrlq		$digit_size, $ACC4, $T0
++	vpand		$AND_MASK, $ACC4, $ACC4
++	vpaddq		$T0, $ACC5, $ACC5
++
++	vpsrlq		$digit_size, $ACC5, $T0
++	vpand		$AND_MASK, $ACC5, $ACC5
++	vpaddq		$T0, $ACC6, $ACC6
++
++	vpsrlq		$digit_size, $ACC6, $T0
++	vpand		$AND_MASK, $ACC6, $ACC6
++	vpaddq		$T0, $ACC7, $ACC7
++
++	vpsrlq		$digit_size, $ACC7, $T0
++	vpand		$AND_MASK, $ACC7, $ACC7
++	vpaddq		$T0, $ACC8, $ACC8
++	#vpand		$AND_MASK, $ACC8, $ACC8
++
++	ret
++.size	avx2_normalize,.-avx2_normalize
++
++.type	avx2_normalize_n_store,\@abi-omnipotent
++.align	32
++avx2_normalize_n_store:
++	vpsrlq		$digit_size, $ACC0, $T0
++	vpand		$AND_MASK, $ACC0, $ACC0
++	vpaddq		$T0, $ACC1, $ACC1
++
++	vpsrlq		$digit_size, $ACC1, $T0
++	vpand		$AND_MASK, $ACC1, $ACC1
++	 vmovdqa	$ACC0, 32*0(%rdi)
++	 lea		160(%rdi), %rax		# size optimization
++	vpaddq		$T0, $ACC2, $ACC2
++
++	vpsrlq		$digit_size, $ACC2, $T0
++	vpand		$AND_MASK, $ACC2, $ACC2
++	 vmovdqa	$ACC1, 32*1(%rdi)
++	vpaddq		$T0, $ACC3, $ACC3
++
++	vpsrlq		$digit_size, $ACC3, $T0
++	vpand		$AND_MASK, $ACC3, $ACC3
++	 vmovdqa	$ACC2, 32*2(%rdi)
++	vpaddq		$T0, $ACC4, $ACC4
++
++	vpsrlq		$digit_size, $ACC4, $T0
++	vpand		$AND_MASK, $ACC4, $ACC4
++	 vmovdqa	$ACC3, 32*3(%rdi)
++	vpaddq		$T0, $ACC5, $ACC5
++
++	vpsrlq		$digit_size, $ACC5, $T0
++	vpand		$AND_MASK, $ACC5, $ACC5
++	 vmovdqa	$ACC4, 32*4-160(%rax)
++	vpaddq		$T0, $ACC6, $ACC6
++
++	vpsrlq		$digit_size, $ACC6, $T0
++	vpand		$AND_MASK, $ACC6, $ACC6
++	 vmovdqa	$ACC5, 32*5-160(%rax)
++	vpaddq		$T0, $ACC7, $ACC7
++
++	vpsrlq		$digit_size, $ACC7, $T0
++	vpand		$AND_MASK, $ACC7, $ACC7
++	 vmovdqa	$ACC6, 32*6-160(%rax)
++	vpaddq		$T0, $ACC8, $ACC8
++	#vpand		$AND_MASK, $ACC8, $ACC8
++	 vmovdqa	$ACC7, 32*7-160(%rax)
++	 vmovdqa	$ACC8, 32*8-160(%rax)
++
++	ret
++.size	avx2_normalize_n_store,.-avx2_normalize_n_store
++
++################################################################################
++# void avx2_mul_x4(void* RESULTx4, void *Ax4, void *Bx4);
++.type	avx2_mul_x4,\@abi-omnipotent
++.align	32
++avx2_mul_x4:
++	lea	.LAVX2_POLY(%rip), %rax
++
++	vpxor	$ACC0, $ACC0, $ACC0
++	vpxor	$ACC1, $ACC1, $ACC1
++	vpxor	$ACC2, $ACC2, $ACC2
++	vpxor	$ACC3, $ACC3, $ACC3
++	vpxor	$ACC4, $ACC4, $ACC4
++	vpxor	$ACC5, $ACC5, $ACC5
++	vpxor	$ACC6, $ACC6, $ACC6
++	vpxor	$ACC7, $ACC7, $ACC7
++
++	vmovdqa	32*7(%rax), %ymm14
++	vmovdqa	32*8(%rax), %ymm15
++
++	mov	$n_digits, $itr
++	lea	-512($a_ptr), $a_ptr	# strategic bias to control u-op density
++	jmp	.Lavx2_mul_x4_loop
++
++.align	32
++.Lavx2_mul_x4_loop:
++	vmovdqa		32*0($b_ptr), $B
++	lea		32*1($b_ptr), $b_ptr
++
++	vpmuludq	32*0+512($a_ptr), $B, $T0
++	vpmuludq	32*1+512($a_ptr), $B, $OVERFLOW	# borrow $OVERFLOW
++	vpaddq		$T0, $ACC0, $ACC0
++	vpmuludq	32*2+512($a_ptr), $B, $T0
++	vpaddq		$OVERFLOW, $ACC1, $ACC1
++	 vpand		$AND_MASK, $ACC0, $Y
++	vpmuludq	32*3+512($a_ptr), $B, $OVERFLOW
++	vpaddq		$T0, $ACC2, $ACC2
++	vpmuludq	32*4+512($a_ptr), $B, $T0
++	vpaddq		$OVERFLOW, $ACC3, $ACC3
++	vpmuludq	32*5+512($a_ptr), $B, $OVERFLOW
++	vpaddq		$T0, $ACC4, $ACC4
++	vpmuludq	32*6+512($a_ptr), $B, $T0
++	vpaddq		$OVERFLOW, $ACC5, $ACC5
++	vpmuludq	32*7+512($a_ptr), $B, $OVERFLOW
++	vpaddq		$T0, $ACC6, $ACC6
++
++	# Skip some multiplications, optimizing for the constant poly
++	vpmuludq	$AND_MASK, $Y, $T0
++	 vpaddq		$OVERFLOW, $ACC7, $ACC7
++	 vpmuludq	32*8+512($a_ptr), $B, $ACC8
++	vpaddq		$T0, $ACC0, $OVERFLOW
++	vpaddq		$T0, $ACC1, $ACC0
++	vpsrlq		$digit_size, $OVERFLOW, $OVERFLOW
++	vpaddq		$T0, $ACC2, $ACC1
++	vpmuludq	32*3(%rax), $Y, $T0
++	vpaddq		$OVERFLOW, $ACC0, $ACC0
++	vpaddq		$T0, $ACC3, $ACC2
++	.byte		0x67
++	vmovdqa		$ACC4, $ACC3
++	vpsllq		\$18, $Y, $OVERFLOW
++	.byte		0x67
++	vmovdqa		$ACC5, $ACC4
++	vpmuludq	%ymm14, $Y, $T0
++	vpaddq		$OVERFLOW, $ACC6, $ACC5
++	vpmuludq	%ymm15, $Y, $OVERFLOW
++	vpaddq		$T0, $ACC7, $ACC6
++	vpaddq		$OVERFLOW, $ACC8, $ACC7
++
++	dec	$itr
++	jnz	.Lavx2_mul_x4_loop
++
++	vpxor	$ACC8, $ACC8, $ACC8
++
++	ret
++.size	avx2_mul_x4,.-avx2_mul_x4
++
++# Function optimized for the constant 1
++################################################################################
++# void avx2_mul_by1_x4(void* RESULTx4, void *Ax4);
++.type	avx2_mul_by1_x4,\@abi-omnipotent
++.align	32
++avx2_mul_by1_x4:
++	lea	.LAVX2_POLY(%rip), %rax
++
++	vpxor	$ACC0, $ACC0, $ACC0
++	vpxor	$ACC1, $ACC1, $ACC1
++	vpxor	$ACC2, $ACC2, $ACC2
++	vpxor	$ACC3, $ACC3, $ACC3
++	vpxor	$ACC4, $ACC4, $ACC4
++	vpxor	$ACC5, $ACC5, $ACC5
++	vpxor	$ACC6, $ACC6, $ACC6
++	vpxor	$ACC7, $ACC7, $ACC7
++	vpxor	$ACC8, $ACC8, $ACC8
++
++	vmovdqa	32*3+.LONE(%rip), %ymm14
++	vmovdqa	32*7+.LONE(%rip), %ymm15
++
++	mov	$n_digits, $itr
++	jmp	.Lavx2_mul_by1_x4_loop
++
++.align	32
++.Lavx2_mul_by1_x4_loop:
++	vmovdqa		32*0($a_ptr), $B
++	.byte		0x48,0x8d,0xb6,0x20,0,0,0	# lea	32*1($a_ptr), $a_ptr
++
++	vpsllq		\$5, $B, $OVERFLOW
++	vpmuludq	%ymm14, $B, $T0
++	vpaddq		$OVERFLOW, $ACC0, $ACC0
++	vpaddq		$T0, $ACC3, $ACC3
++	.byte		0x67
++	vpmuludq	$AND_MASK, $B, $T0
++	vpand		$AND_MASK, $ACC0, $Y
++	vpaddq		$T0, $ACC4, $ACC4
++	vpaddq		$T0, $ACC5, $ACC5
++	vpaddq		$T0, $ACC6, $ACC6
++	vpsllq		\$23, $B, $T0
++
++	.byte		0x67,0x67
++	vpmuludq	%ymm15, $B, $OVERFLOW
++	vpsubq		$T0, $ACC6, $ACC6
++
++	vpmuludq	$AND_MASK, $Y, $T0
++	vpaddq		$OVERFLOW, $ACC7, $ACC7
++	vpaddq		$T0, $ACC0, $OVERFLOW
++	vpaddq		$T0, $ACC1, $ACC0
++	.byte		0x67,0x67
++	vpsrlq		$digit_size, $OVERFLOW, $OVERFLOW
++	vpaddq		$T0, $ACC2, $ACC1
++	vpmuludq	32*3(%rax), $Y, $T0
++	vpaddq		$OVERFLOW, $ACC0, $ACC0
++	vpaddq		$T0, $ACC3, $ACC2
++	vmovdqa		$ACC4, $ACC3
++	vpsllq		\$18, $Y, $OVERFLOW
++	vmovdqa		$ACC5, $ACC4
++	vpmuludq	32*7(%rax), $Y, $T0
++	vpaddq		$OVERFLOW, $ACC6, $ACC5
++	vpaddq		$T0, $ACC7, $ACC6
++	vpmuludq	32*8(%rax), $Y, $ACC7
++
++	dec	$itr
++	jnz	.Lavx2_mul_by1_x4_loop
++
++	ret
++.size	avx2_mul_by1_x4,.-avx2_mul_by1_x4
++
++################################################################################
++# void avx2_sqr_x4(void* RESULTx4, void *Ax4, void *Bx4);
++.type	avx2_sqr_x4,\@abi-omnipotent
++.align	32
++avx2_sqr_x4:
++	lea		.LAVX2_POLY(%rip), %rax
++
++	vmovdqa		32*7(%rax), %ymm14
++	vmovdqa		32*8(%rax), %ymm15
++
++	vmovdqa		32*0($a_ptr), $B
++	vmovdqa		32*1($a_ptr), $ACC1
++	vmovdqa		32*2($a_ptr), $ACC2
++	vmovdqa		32*3($a_ptr), $ACC3
++	vmovdqa		32*4($a_ptr), $ACC4
++	vmovdqa		32*5($a_ptr), $ACC5
++	vmovdqa		32*6($a_ptr), $ACC6
++	vmovdqa		32*7($a_ptr), $ACC7
++	vpaddq		$ACC1, $ACC1, $ACC1	# 2*$ACC0..7
++	vmovdqa		32*8($a_ptr), $ACC8
++	vpaddq		$ACC2, $ACC2, $ACC2
++	vmovdqa		$ACC1, 32*0(%rcx)
++	vpaddq		$ACC3, $ACC3, $ACC3
++	vmovdqa		$ACC2, 32*1(%rcx)
++	vpaddq		$ACC4, $ACC4, $ACC4
++	vmovdqa		$ACC3, 32*2(%rcx)
++	vpaddq		$ACC5, $ACC5, $ACC5
++	vmovdqa		$ACC4, 32*3(%rcx)
++	vpaddq		$ACC6, $ACC6, $ACC6
++	vmovdqa		$ACC5, 32*4(%rcx)
++	vpaddq		$ACC7, $ACC7, $ACC7
++	vmovdqa		$ACC6, 32*5(%rcx)
++	vpaddq		$ACC8, $ACC8, $ACC8
++	vmovdqa		$ACC7, 32*6(%rcx)
++	vmovdqa		$ACC8, 32*7(%rcx)
++
++	#itr		1
++	vpmuludq	$B, $B, $ACC0
++	vpmuludq	$B, $ACC1, $ACC1
++	 vpand		$AND_MASK, $ACC0, $Y
++	vpmuludq	$B, $ACC2, $ACC2
++	vpmuludq	$B, $ACC3, $ACC3
++	vpmuludq	$B, $ACC4, $ACC4
++	vpmuludq	$B, $ACC5, $ACC5
++	vpmuludq	$B, $ACC6, $ACC6
++	 vpmuludq	$AND_MASK, $Y, $T0
++	vpmuludq	$B, $ACC7, $ACC7
++	vpmuludq	$B, $ACC8, $ACC8
++	 vmovdqa	32*1($a_ptr), $B
++
++	vpaddq		$T0, $ACC0, $OVERFLOW
++	vpaddq		$T0, $ACC1, $ACC0
++	vpsrlq		$digit_size, $OVERFLOW, $OVERFLOW
++	vpaddq		$T0, $ACC2, $ACC1
++	vpmuludq	32*3(%rax), $Y, $T0
++	vpaddq		$OVERFLOW, $ACC0, $ACC0
++	vpaddq		$T0, $ACC3, $ACC2
++	vmovdqa		$ACC4, $ACC3
++	vpsllq		\$18, $Y, $T0
++	vmovdqa		$ACC5, $ACC4
++	vpmuludq	%ymm14, $Y, $OVERFLOW
++	vpaddq		$T0, $ACC6, $ACC5
++	vpmuludq	%ymm15, $Y, $T0
++	vpaddq		$OVERFLOW, $ACC7, $ACC6
++	vpaddq		$T0, $ACC8, $ACC7
++
++	#itr		2
++	vpmuludq	$B, $B, $OVERFLOW
++	 vpand		$AND_MASK, $ACC0, $Y
++	vpmuludq	32*1(%rcx), $B, $T0
++	vpaddq		$OVERFLOW, $ACC1, $ACC1
++	vpmuludq	32*2(%rcx), $B, $OVERFLOW
++	vpaddq		$T0, $ACC2, $ACC2
++	vpmuludq	32*3(%rcx), $B, $T0
++	vpaddq		$OVERFLOW, $ACC3, $ACC3
++	vpmuludq	32*4(%rcx), $B, $OVERFLOW
++	vpaddq		$T0, $ACC4, $ACC4
++	vpmuludq	32*5(%rcx), $B, $T0
++	vpaddq		$OVERFLOW, $ACC5, $ACC5
++	vpmuludq	32*6(%rcx), $B, $OVERFLOW
++	vpaddq		$T0, $ACC6, $ACC6
++
++	vpmuludq	$AND_MASK, $Y, $T0
++	 vpaddq		$OVERFLOW, $ACC7, $ACC7
++	 vpmuludq	32*7(%rcx), $B, $ACC8
++	 vmovdqa	32*2($a_ptr), $B
++	vpaddq		$T0, $ACC0, $OVERFLOW
++	vpaddq		$T0, $ACC1, $ACC0
++	vpsrlq		$digit_size, $OVERFLOW, $OVERFLOW
++	vpaddq		$T0, $ACC2, $ACC1
++	vpmuludq	32*3(%rax), $Y, $T0
++	vpaddq		$OVERFLOW, $ACC0, $ACC0
++	vpaddq		$T0, $ACC3, $ACC2
++	vmovdqa		$ACC4, $ACC3
++	vpsllq		\$18, $Y, $T0
++	vmovdqa		$ACC5, $ACC4
++	vpmuludq	%ymm14, $Y, $OVERFLOW
++	vpaddq		$T0, $ACC6, $ACC5
++	vpmuludq	%ymm15, $Y, $T0
++	vpaddq		$OVERFLOW, $ACC7, $ACC6
++	vpaddq		$T0, $ACC8, $ACC7
++
++	#itr		3
++	vpmuludq	$B, $B, $T0
++	 vpand		$AND_MASK, $ACC0, $Y
++	vpmuludq	32*2(%rcx), $B, $OVERFLOW
++	vpaddq		$T0, $ACC2, $ACC2
++	vpmuludq	32*3(%rcx), $B, $T0
++	vpaddq		$OVERFLOW, $ACC3, $ACC3
++	vpmuludq	32*4(%rcx), $B, $OVERFLOW
++	vpaddq		$T0, $ACC4, $ACC4
++	vpmuludq	32*5(%rcx), $B, $T0
++	vpaddq		$OVERFLOW, $ACC5, $ACC5
++	vpmuludq	32*6(%rcx), $B, $OVERFLOW
++	vpaddq		$T0, $ACC6, $ACC6
++
++	vpmuludq	$AND_MASK, $Y, $T0
++	 vpaddq		$OVERFLOW, $ACC7, $ACC7
++	 vpmuludq	32*7(%rcx), $B, $ACC8
++	 vmovdqa	32*3($a_ptr), $B
++	vpaddq		$T0, $ACC0, $OVERFLOW
++	vpaddq		$T0, $ACC1, $ACC0
++	vpsrlq		$digit_size, $OVERFLOW, $OVERFLOW
++	vpaddq		$T0, $ACC2, $ACC1
++	vpmuludq	32*3(%rax), $Y, $T0
++	vpaddq		$OVERFLOW, $ACC0, $ACC0
++	vpaddq		$T0, $ACC3, $ACC2
++	vmovdqa		$ACC4, $ACC3
++	vpsllq		\$18, $Y, $T0
++	vmovdqa		$ACC5, $ACC4
++	vpmuludq	%ymm14, $Y, $OVERFLOW
++	vpaddq		$T0, $ACC6, $ACC5
++	vpmuludq	%ymm15, $Y, $T0
++	 vpand		$AND_MASK, $ACC0, $Y
++	vpaddq		$OVERFLOW, $ACC7, $ACC6
++	vpaddq		$T0, $ACC8, $ACC7
++
++	#itr		4
++	vpmuludq	$B, $B, $OVERFLOW
++	vpmuludq	32*3(%rcx), $B, $T0
++	vpaddq		$OVERFLOW, $ACC3, $ACC3
++	vpmuludq	32*4(%rcx), $B, $OVERFLOW
++	vpaddq		$T0, $ACC4, $ACC4
++	vpmuludq	32*5(%rcx), $B, $T0
++	vpaddq		$OVERFLOW, $ACC5, $ACC5
++	vpmuludq	32*6(%rcx), $B, $OVERFLOW
++	vpaddq		$T0, $ACC6, $ACC6
++
++	vpmuludq	$AND_MASK, $Y, $T0
++	 vpaddq		$OVERFLOW, $ACC7, $ACC7
++	 vpmuludq	32*7(%rcx), $B, $ACC8
++	 vmovdqa	32*4($a_ptr), $B
++	vpaddq		$T0, $ACC0, $OVERFLOW
++	vpaddq		$T0, $ACC1, $ACC0
++	vpsrlq		$digit_size, $OVERFLOW, $OVERFLOW
++	vpaddq		$T0, $ACC2, $ACC1
++	vpmuludq	32*3(%rax), $Y, $T0
++	vpaddq		$OVERFLOW, $ACC0, $ACC0
++	vpaddq		$T0, $ACC3, $ACC2
++	vmovdqa		$ACC4, $ACC3
++	vpsllq		\$18, $Y, $T0
++	vmovdqa		$ACC5, $ACC4
++	vpmuludq	%ymm14, $Y, $OVERFLOW
++	vpaddq		$T0, $ACC6, $ACC5
++	vpmuludq	%ymm15, $Y, $T0
++	 vpand		$AND_MASK, $ACC0, $Y
++	vpaddq		$OVERFLOW, $ACC7, $ACC6
++	vpaddq		$T0, $ACC8, $ACC7
++
++	#itr		5
++	vpmuludq	$B, $B, $T0
++	vpmuludq	32*4(%rcx), $B, $OVERFLOW
++	vpaddq		$T0, $ACC4, $ACC4
++	vpmuludq	32*5(%rcx), $B, $T0
++	vpaddq		$OVERFLOW, $ACC5, $ACC5
++	vpmuludq	32*6(%rcx), $B, $OVERFLOW
++	vpaddq		$T0, $ACC6, $ACC6
++
++	vpmuludq	$AND_MASK, $Y, $T0
++	 vpaddq		$OVERFLOW, $ACC7, $ACC7
++	 vpmuludq	32*7(%rcx), $B, $ACC8
++	 vmovdqa	32*5($a_ptr), $B
++	vpaddq		$T0, $ACC0, $OVERFLOW
++	vpsrlq		$digit_size, $OVERFLOW, $OVERFLOW
++	vpaddq		$T0, $ACC1, $ACC0
++	vpaddq		$T0, $ACC2, $ACC1
++	vpmuludq	32*3+.LAVX2_POLY(%rip), $Y, $T0
++	vpaddq		$OVERFLOW, $ACC0, $ACC0
++	vpaddq		$T0, $ACC3, $ACC2
++	vmovdqa		$ACC4, $ACC3
++	vpsllq		\$18, $Y, $T0
++	vmovdqa		$ACC5, $ACC4
++	vpmuludq	%ymm14, $Y, $OVERFLOW
++	vpaddq		$T0, $ACC6, $ACC5
++	vpmuludq	%ymm15, $Y, $T0
++	 vpand		$AND_MASK, $ACC0, $Y
++	vpaddq		$OVERFLOW, $ACC7, $ACC6
++	vpaddq		$T0, $ACC8, $ACC7
++
++	#itr		6
++	vpmuludq	$B, $B, $OVERFLOW
++	vpmuludq	32*5(%rcx), $B, $T0
++	vpaddq		$OVERFLOW, $ACC5, $ACC5
++	vpmuludq	32*6(%rcx), $B, $OVERFLOW
++	vpaddq		$T0, $ACC6, $ACC6
++
++	vpmuludq	$AND_MASK, $Y, $T0
++	 vpaddq		$OVERFLOW, $ACC7, $ACC7
++	 vpmuludq	32*7(%rcx), $B, $ACC8
++	 vmovdqa	32*6($a_ptr), $B
++	vpaddq		$T0, $ACC0, $OVERFLOW
++	vpaddq		$T0, $ACC1, $ACC0
++	vpsrlq		$digit_size, $OVERFLOW, $OVERFLOW
++	vpaddq		$T0, $ACC2, $ACC1
++	vpmuludq	32*3(%rax), $Y, $T0
++	vpaddq		$OVERFLOW, $ACC0, $ACC0
++	vpaddq		$T0, $ACC3, $ACC2
++	vmovdqa		$ACC4, $ACC3
++	vpsllq		\$18, $Y, $T0
++	vmovdqa		$ACC5, $ACC4
++	vpmuludq	%ymm14, $Y, $OVERFLOW
++	vpaddq		$T0, $ACC6, $ACC5
++	vpmuludq	%ymm15, $Y, $T0
++	 vpand		$AND_MASK, $ACC0, $Y
++	vpaddq		$OVERFLOW, $ACC7, $ACC6
++	vpaddq		$T0, $ACC8, $ACC7
++
++	#itr		7
++	vpmuludq	$B, $B, $T0
++	vpmuludq	32*6(%rcx), $B, $OVERFLOW
++	vpaddq		$T0, $ACC6, $ACC6
++
++	vpmuludq	$AND_MASK, $Y, $T0
++	 vpaddq		$OVERFLOW, $ACC7, $ACC7
++	 vpmuludq	32*7(%rcx), $B, $ACC8
++	 vmovdqa	32*7($a_ptr), $B
++	vpaddq		$T0, $ACC0, $OVERFLOW
++	vpsrlq		$digit_size, $OVERFLOW, $OVERFLOW
++	vpaddq		$T0, $ACC1, $ACC0
++	vpaddq		$T0, $ACC2, $ACC1
++	vpmuludq	32*3(%rax), $Y, $T0
++	vpaddq		$OVERFLOW, $ACC0, $ACC0
++	vpaddq		$T0, $ACC3, $ACC2
++	vmovdqa		$ACC4, $ACC3
++	vpsllq		\$18, $Y, $T0
++	vmovdqa		$ACC5, $ACC4
++	vpmuludq	%ymm14, $Y, $OVERFLOW
++	vpaddq		$T0, $ACC6, $ACC5
++	vpmuludq	%ymm15, $Y, $T0
++	 vpand		$AND_MASK, $ACC0, $Y
++	vpaddq		$OVERFLOW, $ACC7, $ACC6
++	vpaddq		$T0, $ACC8, $ACC7
++
++	#itr		8
++	vpmuludq	$B, $B, $OVERFLOW
++
++	vpmuludq	$AND_MASK, $Y, $T0
++	 vpaddq		$OVERFLOW, $ACC7, $ACC7
++	 vpmuludq	32*7(%rcx), $B, $ACC8
++	 vmovdqa	32*8($a_ptr), $B
++	vpaddq		$T0, $ACC0, $OVERFLOW
++	vpsrlq		$digit_size, $OVERFLOW, $OVERFLOW
++	vpaddq		$T0, $ACC1, $ACC0
++	vpaddq		$T0, $ACC2, $ACC1
++	vpmuludq	32*3(%rax), $Y, $T0
++	vpaddq		$OVERFLOW, $ACC0, $ACC0
++	vpaddq		$T0, $ACC3, $ACC2
++	vmovdqa		$ACC4, $ACC3
++	vpsllq		\$18, $Y, $T0
++	vmovdqa		$ACC5, $ACC4
++	vpmuludq	%ymm14, $Y, $OVERFLOW
++	vpaddq		$T0, $ACC6, $ACC5
++	vpmuludq	%ymm15, $Y, $T0
++	 vpand		$AND_MASK, $ACC0, $Y
++	vpaddq		$OVERFLOW, $ACC7, $ACC6
++	vpaddq		$T0, $ACC8, $ACC7
++
++	#itr		9
++	vpmuludq	$B, $B, $ACC8
++
++	vpmuludq	$AND_MASK, $Y, $T0
++	vpaddq		$T0, $ACC0, $OVERFLOW
++	vpsrlq		$digit_size, $OVERFLOW, $OVERFLOW
++	vpaddq		$T0, $ACC1, $ACC0
++	vpaddq		$T0, $ACC2, $ACC1
++	vpmuludq	32*3(%rax), $Y, $T0
++	vpaddq		$OVERFLOW, $ACC0, $ACC0
++	vpaddq		$T0, $ACC3, $ACC2
++	vmovdqa		$ACC4, $ACC3
++	vpsllq		\$18, $Y, $T0
++	vmovdqa		$ACC5, $ACC4
++	vpmuludq	%ymm14, $Y, $OVERFLOW
++	vpaddq		$T0, $ACC6, $ACC5
++	vpmuludq	%ymm15, $Y, $T0
++	vpaddq		$OVERFLOW, $ACC7, $ACC6
++	vpaddq		$T0, $ACC8, $ACC7
++
++	vpxor		$ACC8, $ACC8, $ACC8
++
++	ret
++.size	avx2_sqr_x4,.-avx2_sqr_x4
++
++################################################################################
++# void avx2_sub_x4(void* RESULTx4, void *Ax4, void *Bx4);
++.type	avx2_sub_x4,\@abi-omnipotent
++.align	32
++avx2_sub_x4:
++	vmovdqa	32*0($a_ptr), $ACC0
++	lea	160($a_ptr), $a_ptr
++	lea	.LAVX2_POLY_x8+128(%rip), %rax
++	lea	128($b_ptr), $b_ptr
++	vmovdqa	32*1-160($a_ptr), $ACC1
++	vmovdqa	32*2-160($a_ptr), $ACC2
++	vmovdqa	32*3-160($a_ptr), $ACC3
++	vmovdqa	32*4-160($a_ptr), $ACC4
++	vmovdqa	32*5-160($a_ptr), $ACC5
++	vmovdqa	32*6-160($a_ptr), $ACC6
++	vmovdqa	32*7-160($a_ptr), $ACC7
++	vmovdqa	32*8-160($a_ptr), $ACC8
++
++	vpaddq	32*0-128(%rax), $ACC0, $ACC0
++	vpaddq	32*1-128(%rax), $ACC1, $ACC1
++	vpaddq	32*2-128(%rax), $ACC2, $ACC2
++	vpaddq	32*3-128(%rax), $ACC3, $ACC3
++	vpaddq	32*4-128(%rax), $ACC4, $ACC4
++	vpaddq	32*5-128(%rax), $ACC5, $ACC5
++	vpaddq	32*6-128(%rax), $ACC6, $ACC6
++	vpaddq	32*7-128(%rax), $ACC7, $ACC7
++	vpaddq	32*8-128(%rax), $ACC8, $ACC8
++
++	vpsubq	32*0-128($b_ptr), $ACC0, $ACC0
++	vpsubq	32*1-128($b_ptr), $ACC1, $ACC1
++	vpsubq	32*2-128($b_ptr), $ACC2, $ACC2
++	vpsubq	32*3-128($b_ptr), $ACC3, $ACC3
++	vpsubq	32*4-128($b_ptr), $ACC4, $ACC4
++	vpsubq	32*5-128($b_ptr), $ACC5, $ACC5
++	vpsubq	32*6-128($b_ptr), $ACC6, $ACC6
++	vpsubq	32*7-128($b_ptr), $ACC7, $ACC7
++	vpsubq	32*8-128($b_ptr), $ACC8, $ACC8
++
++	ret
++.size	avx2_sub_x4,.-avx2_sub_x4
++
++.type	avx2_select_n_store,\@abi-omnipotent
++.align	32
++avx2_select_n_store:
++	vmovdqa	`8+32*9*8`(%rsp), $Y
++	vpor	`8+32*9*8+32`(%rsp), $Y, $Y
++
++	vpandn	$ACC0, $Y, $ACC0
++	vpandn	$ACC1, $Y, $ACC1
++	vpandn	$ACC2, $Y, $ACC2
++	vpandn	$ACC3, $Y, $ACC3
++	vpandn	$ACC4, $Y, $ACC4
++	vpandn	$ACC5, $Y, $ACC5
++	vpandn	$ACC6, $Y, $ACC6
++	vmovdqa	`8+32*9*8+32`(%rsp), $B
++	vpandn	$ACC7, $Y, $ACC7
++	vpandn	`8+32*9*8`(%rsp), $B, $B
++	vpandn	$ACC8, $Y, $ACC8
++
++	vpand	32*0(%rsi), $B, $T0
++	lea	160(%rsi), %rax
++	vpand	32*1(%rsi), $B, $Y
++	vpxor	$T0, $ACC0, $ACC0
++	vpand	32*2(%rsi), $B, $T0
++	vpxor	$Y, $ACC1, $ACC1
++	vpand	32*3(%rsi), $B, $Y
++	vpxor	$T0, $ACC2, $ACC2
++	vpand	32*4-160(%rax), $B, $T0
++	vpxor	$Y, $ACC3, $ACC3
++	vpand	32*5-160(%rax), $B, $Y
++	vpxor	$T0, $ACC4, $ACC4
++	vpand	32*6-160(%rax), $B, $T0
++	vpxor	$Y, $ACC5, $ACC5
++	vpand	32*7-160(%rax), $B, $Y
++	vpxor	$T0, $ACC6, $ACC6
++	vpand	32*8-160(%rax), $B, $T0
++	vmovdqa	`8+32*9*8+32`(%rsp), $B
++	vpxor	$Y, $ACC7, $ACC7
++
++	vpand	32*0(%rdx), $B, $Y
++	lea	160(%rdx), %rax
++	vpxor	$T0, $ACC8, $ACC8
++	vpand	32*1(%rdx), $B, $T0
++	vpxor	$Y, $ACC0, $ACC0
++	vpand	32*2(%rdx), $B, $Y
++	vpxor	$T0, $ACC1, $ACC1
++	vpand	32*3(%rdx), $B, $T0
++	vpxor	$Y, $ACC2, $ACC2
++	vpand	32*4-160(%rax), $B, $Y
++	vpxor	$T0, $ACC3, $ACC3
++	vpand	32*5-160(%rax), $B, $T0
++	vpxor	$Y, $ACC4, $ACC4
++	vpand	32*6-160(%rax), $B, $Y
++	vpxor	$T0, $ACC5, $ACC5
++	vpand	32*7-160(%rax), $B, $T0
++	vpxor	$Y, $ACC6, $ACC6
++	vpand	32*8-160(%rax), $B, $Y
++	vpxor	$T0, $ACC7, $ACC7
++	vpxor	$Y, $ACC8, $ACC8
++	`&STORE`
++
++	ret
++.size	avx2_select_n_store,.-avx2_select_n_store
++___
++$code.=<<___	if (0);				# inlined
++################################################################################
++# void avx2_mul_by2_x4(void* RESULTx4, void *Ax4);
++.type	avx2_mul_by2_x4,\@abi-omnipotent
++.align	32
++avx2_mul_by2_x4:
++	vmovdqa	32*0($a_ptr), $ACC0
++	lea	160($a_ptr), %rax
++	vmovdqa	32*1($a_ptr), $ACC1
++	vmovdqa	32*2($a_ptr), $ACC2
++	vmovdqa	32*3($a_ptr), $ACC3
++	vmovdqa	32*4-160(%rax), $ACC4
++	vmovdqa	32*5-160(%rax), $ACC5
++	vmovdqa	32*6-160(%rax), $ACC6
++	vmovdqa	32*7-160(%rax), $ACC7
++	vmovdqa	32*8-160(%rax), $ACC8
++
++	vpaddq	$ACC0, $ACC0, $ACC0
++	vpaddq	$ACC1, $ACC1, $ACC1
++	vpaddq	$ACC2, $ACC2, $ACC2
++	vpaddq	$ACC3, $ACC3, $ACC3
++	vpaddq	$ACC4, $ACC4, $ACC4
++	vpaddq	$ACC5, $ACC5, $ACC5
++	vpaddq	$ACC6, $ACC6, $ACC6
++	vpaddq	$ACC7, $ACC7, $ACC7
++	vpaddq	$ACC8, $ACC8, $ACC8
++
++	ret
++.size	avx2_mul_by2_x4,.-avx2_mul_by2_x4
++___
++my ($r_ptr_in,$a_ptr_in,$b_ptr_in)=("%rdi","%rsi","%rdx");
++my ($r_ptr,$a_ptr,$b_ptr)=("%r8","%r9","%r10");
++
++$code.=<<___;
++################################################################################
++# void ecp_nistz256_avx2_point_add_affine_x4(void* RESULTx4, void *Ax4, void *Bx4);
++.globl	ecp_nistz256_avx2_point_add_affine_x4
++.type	ecp_nistz256_avx2_point_add_affine_x4,\@function,3
++.align	32
++ecp_nistz256_avx2_point_add_affine_x4:
++	mov	%rsp, %rax
++	push    %rbp
++	vzeroupper
++___
++$code.=<<___	if ($win64);
++	lea	-16*10(%rsp), %rsp
++	vmovaps	%xmm6, -8-16*10(%rax)
++	vmovaps	%xmm7, -8-16*9(%rax)
++	vmovaps	%xmm8, -8-16*8(%rax)
++	vmovaps	%xmm9, -8-16*7(%rax)
++	vmovaps	%xmm10, -8-16*6(%rax)
++	vmovaps	%xmm11, -8-16*5(%rax)
++	vmovaps	%xmm12, -8-16*4(%rax)
++	vmovaps	%xmm13, -8-16*3(%rax)
++	vmovaps	%xmm14, -8-16*2(%rax)
++	vmovaps	%xmm15, -8-16*1(%rax)
++___
++$code.=<<___;
++	lea	-8(%rax), %rbp
++
++# Result + 32*0 = Result.X
++# Result + 32*9 = Result.Y
++# Result + 32*18 = Result.Z
++
++# A + 32*0 = A.X
++# A + 32*9 = A.Y
++# A + 32*18 = A.Z
++
++# B + 32*0 = B.X
++# B + 32*9 = B.Y
++
++	sub	\$`32*9*8+32*2+32*8`, %rsp
++	and	\$-64, %rsp
++
++	mov	$r_ptr_in, $r_ptr
++	mov	$a_ptr_in, $a_ptr
++	mov	$b_ptr_in, $b_ptr
++
++	vmovdqa	32*0($a_ptr_in), %ymm0
++	vmovdqa	.LAVX2_AND_MASK(%rip), $AND_MASK
++	vpxor	%ymm1, %ymm1, %ymm1
++	lea	256($a_ptr_in), %rax		# size optimization
++	vpor	32*1($a_ptr_in), %ymm0, %ymm0
++	vpor	32*2($a_ptr_in), %ymm0, %ymm0
++	vpor	32*3($a_ptr_in), %ymm0, %ymm0
++	vpor	32*4-256(%rax), %ymm0, %ymm0
++	lea	256(%rax), %rcx			# size optimization
++	vpor	32*5-256(%rax), %ymm0, %ymm0
++	vpor	32*6-256(%rax), %ymm0, %ymm0
++	vpor	32*7-256(%rax), %ymm0, %ymm0
++	vpor	32*8-256(%rax), %ymm0, %ymm0
++	vpor	32*9-256(%rax), %ymm0, %ymm0
++	vpor	32*10-256(%rax), %ymm0, %ymm0
++	vpor	32*11-256(%rax), %ymm0, %ymm0
++	vpor	32*12-512(%rcx), %ymm0, %ymm0
++	vpor	32*13-512(%rcx), %ymm0, %ymm0
++	vpor	32*14-512(%rcx), %ymm0, %ymm0
++	vpor	32*15-512(%rcx), %ymm0, %ymm0
++	vpor	32*16-512(%rcx), %ymm0, %ymm0
++	vpor	32*17-512(%rcx), %ymm0, %ymm0
++	vpcmpeqq %ymm1, %ymm0, %ymm0
++	vmovdqa	%ymm0, `32*9*8`(%rsp)
++
++	vpxor	%ymm1, %ymm1, %ymm1
++	vmovdqa	32*0($b_ptr), %ymm0
++	lea	256($b_ptr), %rax		# size optimization
++	vpor	32*1($b_ptr), %ymm0, %ymm0
++	vpor	32*2($b_ptr), %ymm0, %ymm0
++	vpor	32*3($b_ptr), %ymm0, %ymm0
++	vpor	32*4-256(%rax), %ymm0, %ymm0
++	lea	256(%rax), %rcx			# size optimization
++	vpor	32*5-256(%rax), %ymm0, %ymm0
++	vpor	32*6-256(%rax), %ymm0, %ymm0
++	vpor	32*7-256(%rax), %ymm0, %ymm0
++	vpor	32*8-256(%rax), %ymm0, %ymm0
++	vpor	32*9-256(%rax), %ymm0, %ymm0
++	vpor	32*10-256(%rax), %ymm0, %ymm0
++	vpor	32*11-256(%rax), %ymm0, %ymm0
++	vpor	32*12-512(%rcx), %ymm0, %ymm0
++	vpor	32*13-512(%rcx), %ymm0, %ymm0
++	vpor	32*14-512(%rcx), %ymm0, %ymm0
++	vpor	32*15-512(%rcx), %ymm0, %ymm0
++	vpor	32*16-512(%rcx), %ymm0, %ymm0
++	vpor	32*17-512(%rcx), %ymm0, %ymm0
++	vpcmpeqq %ymm1, %ymm0, %ymm0
++	vmovdqa	%ymm0, `32*9*8+32`(%rsp)
++
++	#	Z1^2 = Z1*Z1
++	lea	`32*9*2`($a_ptr), %rsi
++	lea	`32*9*2`(%rsp), %rdi
++	lea	`32*9*8+32*2`(%rsp), %rcx	# temporary vector
++	call	avx2_sqr_x4
++	call	avx2_normalize_n_store
++
++	#	U2 = X2*Z1^2
++	lea	`32*9*0`($b_ptr), %rsi
++	lea	`32*9*2`(%rsp), %rdx
++	lea	`32*9*0`(%rsp), %rdi
++	call	avx2_mul_x4
++	#call	avx2_normalize
++	`&STORE`
++
++	#	S2 = Z1*Z1^2 = Z1^3
++	lea	`32*9*2`($a_ptr), %rsi
++	lea	`32*9*2`(%rsp), %rdx
++	lea	`32*9*1`(%rsp), %rdi
++	call	avx2_mul_x4
++	call	avx2_normalize_n_store
++
++	#	S2 = S2*Y2 = Y2*Z1^3
++	lea	`32*9*1`($b_ptr), %rsi
++	lea	`32*9*1`(%rsp), %rdx
++	lea	`32*9*1`(%rsp), %rdi
++	call	avx2_mul_x4
++	call	avx2_normalize_n_store
++
++	#	H = U2 - U1 = U2 - X1
++	lea	`32*9*0`(%rsp), %rsi
++	lea	`32*9*0`($a_ptr), %rdx
++	lea	`32*9*3`(%rsp), %rdi
++	call	avx2_sub_x4
++	call	avx2_normalize_n_store
++
++	#	R = S2 - S1 = S2 - Y1
++	lea	`32*9*1`(%rsp), %rsi
++	lea	`32*9*1`($a_ptr), %rdx
++	lea	`32*9*4`(%rsp), %rdi
++	call	avx2_sub_x4
++	call	avx2_normalize_n_store
++
++	#	Z3 = H*Z1*Z2
++	lea	`32*9*3`(%rsp), %rsi
++	lea	`32*9*2`($a_ptr), %rdx
++	lea	`32*9*2`($r_ptr), %rdi
++	call	avx2_mul_x4
++	call	avx2_normalize
++
++	lea	.LONE(%rip), %rsi
++	lea	`32*9*2`($a_ptr), %rdx
++	call	avx2_select_n_store
++
++	#	R^2 = R^2
++	lea	`32*9*4`(%rsp), %rsi
++	lea	`32*9*6`(%rsp), %rdi
++	lea	`32*9*8+32*2`(%rsp), %rcx	# temporary vector
++	call	avx2_sqr_x4
++	call	avx2_normalize_n_store
++
++	#	H^2 = H^2
++	lea	`32*9*3`(%rsp), %rsi
++	lea	`32*9*5`(%rsp), %rdi
++	call	avx2_sqr_x4
++	call	avx2_normalize_n_store
++
++	#	H^3 = H^2*H
++	lea	`32*9*3`(%rsp), %rsi
++	lea	`32*9*5`(%rsp), %rdx
++	lea	`32*9*7`(%rsp), %rdi
++	call	avx2_mul_x4
++	call	avx2_normalize_n_store
++
++	#	U2 = U1*H^2
++	lea	`32*9*0`($a_ptr), %rsi
++	lea	`32*9*5`(%rsp), %rdx
++	lea	`32*9*0`(%rsp), %rdi
++	call	avx2_mul_x4
++	#call	avx2_normalize
++	`&STORE`
++
++	#	Hsqr = U2*2
++	#lea	32*9*0(%rsp), %rsi
++	#lea	32*9*5(%rsp), %rdi
++	#call	avx2_mul_by2_x4
++
++	vpaddq	$ACC0, $ACC0, $ACC0	# inlined avx2_mul_by2_x4
++	lea	`32*9*5`(%rsp), %rdi
++	vpaddq	$ACC1, $ACC1, $ACC1
++	vpaddq	$ACC2, $ACC2, $ACC2
++	vpaddq	$ACC3, $ACC3, $ACC3
++	vpaddq	$ACC4, $ACC4, $ACC4
++	vpaddq	$ACC5, $ACC5, $ACC5
++	vpaddq	$ACC6, $ACC6, $ACC6
++	vpaddq	$ACC7, $ACC7, $ACC7
++	vpaddq	$ACC8, $ACC8, $ACC8
++	call	avx2_normalize_n_store
++
++	#	X3 = R^2 - H^3
++	#lea	32*9*6(%rsp), %rsi
++	#lea	32*9*7(%rsp), %rdx
++	#lea	32*9*5(%rsp), %rcx
++	#lea	32*9*0($r_ptr), %rdi
++	#call	avx2_sub_x4
++	#NORMALIZE
++	#STORE
++
++	#	X3 = X3 - U2*2
++	#lea	32*9*0($r_ptr), %rsi
++	#lea	32*9*0($r_ptr), %rdi
++	#call	avx2_sub_x4
++	#NORMALIZE
++	#STORE
++
++	lea	`32*9*6+128`(%rsp), %rsi
++	lea	.LAVX2_POLY_x2+128(%rip), %rax
++	lea	`32*9*7+128`(%rsp), %rdx
++	lea	`32*9*5+128`(%rsp), %rcx
++	lea	`32*9*0`($r_ptr), %rdi
++
++	vmovdqa	32*0-128(%rsi), $ACC0
++	vmovdqa	32*1-128(%rsi), $ACC1
++	vmovdqa	32*2-128(%rsi), $ACC2
++	vmovdqa	32*3-128(%rsi), $ACC3
++	vmovdqa	32*4-128(%rsi), $ACC4
++	vmovdqa	32*5-128(%rsi), $ACC5
++	vmovdqa	32*6-128(%rsi), $ACC6
++	vmovdqa	32*7-128(%rsi), $ACC7
++	vmovdqa	32*8-128(%rsi), $ACC8
++
++	vpaddq	32*0-128(%rax), $ACC0, $ACC0
++	vpaddq	32*1-128(%rax), $ACC1, $ACC1
++	vpaddq	32*2-128(%rax), $ACC2, $ACC2
++	vpaddq	32*3-128(%rax), $ACC3, $ACC3
++	vpaddq	32*4-128(%rax), $ACC4, $ACC4
++	vpaddq	32*5-128(%rax), $ACC5, $ACC5
++	vpaddq	32*6-128(%rax), $ACC6, $ACC6
++	vpaddq	32*7-128(%rax), $ACC7, $ACC7
++	vpaddq	32*8-128(%rax), $ACC8, $ACC8
++
++	vpsubq	32*0-128(%rdx), $ACC0, $ACC0
++	vpsubq	32*1-128(%rdx), $ACC1, $ACC1
++	vpsubq	32*2-128(%rdx), $ACC2, $ACC2
++	vpsubq	32*3-128(%rdx), $ACC3, $ACC3
++	vpsubq	32*4-128(%rdx), $ACC4, $ACC4
++	vpsubq	32*5-128(%rdx), $ACC5, $ACC5
++	vpsubq	32*6-128(%rdx), $ACC6, $ACC6
++	vpsubq	32*7-128(%rdx), $ACC7, $ACC7
++	vpsubq	32*8-128(%rdx), $ACC8, $ACC8
++
++	vpsubq	32*0-128(%rcx), $ACC0, $ACC0
++	vpsubq	32*1-128(%rcx), $ACC1, $ACC1
++	vpsubq	32*2-128(%rcx), $ACC2, $ACC2
++	vpsubq	32*3-128(%rcx), $ACC3, $ACC3
++	vpsubq	32*4-128(%rcx), $ACC4, $ACC4
++	vpsubq	32*5-128(%rcx), $ACC5, $ACC5
++	vpsubq	32*6-128(%rcx), $ACC6, $ACC6
++	vpsubq	32*7-128(%rcx), $ACC7, $ACC7
++	vpsubq	32*8-128(%rcx), $ACC8, $ACC8
++	call	avx2_normalize
++
++	lea	32*0($b_ptr), %rsi
++	lea	32*0($a_ptr), %rdx
++	call	avx2_select_n_store
++
++	#	H = U2 - X3
++	lea	`32*9*0`(%rsp), %rsi
++	lea	`32*9*0`($r_ptr), %rdx
++	lea	`32*9*3`(%rsp), %rdi
++	call	avx2_sub_x4
++	call	avx2_normalize_n_store
++
++	#
++	lea	`32*9*3`(%rsp), %rsi
++	lea	`32*9*4`(%rsp), %rdx
++	lea	`32*9*3`(%rsp), %rdi
++	call	avx2_mul_x4
++	call	avx2_normalize_n_store
++
++	#
++	lea	`32*9*7`(%rsp), %rsi
++	lea	`32*9*1`($a_ptr), %rdx
++	lea	`32*9*1`(%rsp), %rdi
++	call	avx2_mul_x4
++	call	avx2_normalize_n_store
++
++	#
++	lea	`32*9*3`(%rsp), %rsi
++	lea	`32*9*1`(%rsp), %rdx
++	lea	`32*9*1`($r_ptr), %rdi
++	call	avx2_sub_x4
++	call	avx2_normalize
++
++	lea	32*9($b_ptr), %rsi
++	lea	32*9($a_ptr), %rdx
++	call	avx2_select_n_store
++
++	#lea	32*9*0($r_ptr), %rsi
++	#lea	32*9*0($r_ptr), %rdi
++	#call	avx2_mul_by1_x4
++	#NORMALIZE
++	#STORE
++
++	lea	`32*9*1`($r_ptr), %rsi
++	lea	`32*9*1`($r_ptr), %rdi
++	call	avx2_mul_by1_x4
++	call	avx2_normalize_n_store
++
++	vzeroupper
++___
++$code.=<<___	if ($win64);
++	movaps	%xmm6, -16*10(%rbp)
++	movaps	%xmm7, -16*9(%rbp)
++	movaps	%xmm8, -16*8(%rbp)
++	movaps	%xmm9, -16*7(%rbp)
++	movaps	%xmm10, -16*6(%rbp)
++	movaps	%xmm11, -16*5(%rbp)
++	movaps	%xmm12, -16*4(%rbp)
++	movaps	%xmm13, -16*3(%rbp)
++	movaps	%xmm14, -16*2(%rbp)
++	movaps	%xmm15, -16*1(%rbp)
++___
++$code.=<<___;
++	mov	%rbp, %rsp
++	pop	%rbp
++	ret
++.size	ecp_nistz256_avx2_point_add_affine_x4,.-ecp_nistz256_avx2_point_add_affine_x4
++
++################################################################################
++# void ecp_nistz256_avx2_point_add_affines_x4(void* RESULTx4, void *Ax4, void *Bx4);
++.globl	ecp_nistz256_avx2_point_add_affines_x4
++.type	ecp_nistz256_avx2_point_add_affines_x4,\@function,3
++.align	32
++ecp_nistz256_avx2_point_add_affines_x4:
++	mov	%rsp, %rax
++	push    %rbp
++	vzeroupper
++___
++$code.=<<___	if ($win64);
++	lea	-16*10(%rsp), %rsp
++	vmovaps	%xmm6, -8-16*10(%rax)
++	vmovaps	%xmm7, -8-16*9(%rax)
++	vmovaps	%xmm8, -8-16*8(%rax)
++	vmovaps	%xmm9, -8-16*7(%rax)
++	vmovaps	%xmm10, -8-16*6(%rax)
++	vmovaps	%xmm11, -8-16*5(%rax)
++	vmovaps	%xmm12, -8-16*4(%rax)
++	vmovaps	%xmm13, -8-16*3(%rax)
++	vmovaps	%xmm14, -8-16*2(%rax)
++	vmovaps	%xmm15, -8-16*1(%rax)
++___
++$code.=<<___;
++	lea	-8(%rax), %rbp
++
++# Result + 32*0 = Result.X
++# Result + 32*9 = Result.Y
++# Result + 32*18 = Result.Z
++
++# A + 32*0 = A.X
++# A + 32*9 = A.Y
++
++# B + 32*0 = B.X
++# B + 32*9 = B.Y
++
++	sub	\$`32*9*8+32*2+32*8`, %rsp
++	and	\$-64, %rsp
++
++	mov	$r_ptr_in, $r_ptr
++	mov	$a_ptr_in, $a_ptr
++	mov	$b_ptr_in, $b_ptr
++
++	vmovdqa	32*0($a_ptr_in), %ymm0
++	vmovdqa	.LAVX2_AND_MASK(%rip), $AND_MASK
++	vpxor	%ymm1, %ymm1, %ymm1
++	lea	256($a_ptr_in), %rax		# size optimization
++	vpor	32*1($a_ptr_in), %ymm0, %ymm0
++	vpor	32*2($a_ptr_in), %ymm0, %ymm0
++	vpor	32*3($a_ptr_in), %ymm0, %ymm0
++	vpor	32*4-256(%rax), %ymm0, %ymm0
++	lea	256(%rax), %rcx			# size optimization
++	vpor	32*5-256(%rax), %ymm0, %ymm0
++	vpor	32*6-256(%rax), %ymm0, %ymm0
++	vpor	32*7-256(%rax), %ymm0, %ymm0
++	vpor	32*8-256(%rax), %ymm0, %ymm0
++	vpor	32*9-256(%rax), %ymm0, %ymm0
++	vpor	32*10-256(%rax), %ymm0, %ymm0
++	vpor	32*11-256(%rax), %ymm0, %ymm0
++	vpor	32*12-512(%rcx), %ymm0, %ymm0
++	vpor	32*13-512(%rcx), %ymm0, %ymm0
++	vpor	32*14-512(%rcx), %ymm0, %ymm0
++	vpor	32*15-512(%rcx), %ymm0, %ymm0
++	vpor	32*16-512(%rcx), %ymm0, %ymm0
++	vpor	32*17-512(%rcx), %ymm0, %ymm0
++	vpcmpeqq %ymm1, %ymm0, %ymm0
++	vmovdqa	%ymm0, `32*9*8`(%rsp)
++
++	vpxor	%ymm1, %ymm1, %ymm1
++	vmovdqa	32*0($b_ptr), %ymm0
++	lea	256($b_ptr), %rax		# size optimization
++	vpor	32*1($b_ptr), %ymm0, %ymm0
++	vpor	32*2($b_ptr), %ymm0, %ymm0
++	vpor	32*3($b_ptr), %ymm0, %ymm0
++	vpor	32*4-256(%rax), %ymm0, %ymm0
++	lea	256(%rax), %rcx			# size optimization
++	vpor	32*5-256(%rax), %ymm0, %ymm0
++	vpor	32*6-256(%rax), %ymm0, %ymm0
++	vpor	32*7-256(%rax), %ymm0, %ymm0
++	vpor	32*8-256(%rax), %ymm0, %ymm0
++	vpor	32*9-256(%rax), %ymm0, %ymm0
++	vpor	32*10-256(%rax), %ymm0, %ymm0
++	vpor	32*11-256(%rax), %ymm0, %ymm0
++	vpor	32*12-512(%rcx), %ymm0, %ymm0
++	vpor	32*13-512(%rcx), %ymm0, %ymm0
++	vpor	32*14-512(%rcx), %ymm0, %ymm0
++	vpor	32*15-512(%rcx), %ymm0, %ymm0
++	vpor	32*16-512(%rcx), %ymm0, %ymm0
++	vpor	32*17-512(%rcx), %ymm0, %ymm0
++	vpcmpeqq %ymm1, %ymm0, %ymm0
++	vmovdqa	%ymm0, `32*9*8+32`(%rsp)
++
++	#	H = U2 - U1 = X2 - X1
++	lea	`32*9*0`($b_ptr), %rsi
++	lea	`32*9*0`($a_ptr), %rdx
++	lea	`32*9*3`(%rsp), %rdi
++	call	avx2_sub_x4
++	call	avx2_normalize_n_store
++
++	#	R = S2 - S1 = Y2 - Y1
++	lea	`32*9*1`($b_ptr), %rsi
++	lea	`32*9*1`($a_ptr), %rdx
++	lea	`32*9*4`(%rsp), %rdi
++	call	avx2_sub_x4
++	call	avx2_normalize_n_store
++
++	#	Z3 = H*Z1*Z2 = H
++	lea	`32*9*3`(%rsp), %rsi
++	lea	`32*9*2`($r_ptr), %rdi
++	call	avx2_mul_by1_x4
++	call	avx2_normalize
++
++	vmovdqa	`32*9*8`(%rsp), $B
++	vpor	`32*9*8+32`(%rsp), $B, $B
++
++	vpandn	$ACC0, $B, $ACC0
++	lea	.LONE+128(%rip), %rax
++	vpandn	$ACC1, $B, $ACC1
++	vpandn	$ACC2, $B, $ACC2
++	vpandn	$ACC3, $B, $ACC3
++	vpandn	$ACC4, $B, $ACC4
++	vpandn	$ACC5, $B, $ACC5
++	vpandn	$ACC6, $B, $ACC6
++	vpandn	$ACC7, $B, $ACC7
++
++	vpand	32*0-128(%rax), $B, $T0
++	 vpandn	$ACC8, $B, $ACC8
++	vpand	32*1-128(%rax), $B, $Y
++	vpxor	$T0, $ACC0, $ACC0
++	vpand	32*2-128(%rax), $B, $T0
++	vpxor	$Y, $ACC1, $ACC1
++	vpand	32*3-128(%rax), $B, $Y
++	vpxor	$T0, $ACC2, $ACC2
++	vpand	32*4-128(%rax), $B, $T0
++	vpxor	$Y, $ACC3, $ACC3
++	vpand	32*5-128(%rax), $B, $Y
++	vpxor	$T0, $ACC4, $ACC4
++	vpand	32*6-128(%rax), $B, $T0
++	vpxor	$Y, $ACC5, $ACC5
++	vpand	32*7-128(%rax), $B, $Y
++	vpxor	$T0, $ACC6, $ACC6
++	vpand	32*8-128(%rax), $B, $T0
++	vpxor	$Y, $ACC7, $ACC7
++	vpxor	$T0, $ACC8, $ACC8
++	`&STORE`
++
++	#	R^2 = R^2
++	lea	`32*9*4`(%rsp), %rsi
++	lea	`32*9*6`(%rsp), %rdi
++	lea	`32*9*8+32*2`(%rsp), %rcx	# temporary vector
++	call	avx2_sqr_x4
++	call	avx2_normalize_n_store
++
++	#	H^2 = H^2
++	lea	`32*9*3`(%rsp), %rsi
++	lea	`32*9*5`(%rsp), %rdi
++	call	avx2_sqr_x4
++	call	avx2_normalize_n_store
++
++	#	H^3 = H^2*H
++	lea	`32*9*3`(%rsp), %rsi
++	lea	`32*9*5`(%rsp), %rdx
++	lea	`32*9*7`(%rsp), %rdi
++	call	avx2_mul_x4
++	call	avx2_normalize_n_store
++
++	#	U2 = U1*H^2
++	lea	`32*9*0`($a_ptr), %rsi
++	lea	`32*9*5`(%rsp), %rdx
++	lea	`32*9*0`(%rsp), %rdi
++	call	avx2_mul_x4
++	#call	avx2_normalize
++	`&STORE`
++
++	#	Hsqr = U2*2
++	#lea	32*9*0(%rsp), %rsi
++	#lea	32*9*5(%rsp), %rdi
++	#call	avx2_mul_by2_x4
++
++	vpaddq	$ACC0, $ACC0, $ACC0	# inlined avx2_mul_by2_x4
++	lea	`32*9*5`(%rsp), %rdi
++	vpaddq	$ACC1, $ACC1, $ACC1
++	vpaddq	$ACC2, $ACC2, $ACC2
++	vpaddq	$ACC3, $ACC3, $ACC3
++	vpaddq	$ACC4, $ACC4, $ACC4
++	vpaddq	$ACC5, $ACC5, $ACC5
++	vpaddq	$ACC6, $ACC6, $ACC6
++	vpaddq	$ACC7, $ACC7, $ACC7
++	vpaddq	$ACC8, $ACC8, $ACC8
++	call	avx2_normalize_n_store
++
++	#	X3 = R^2 - H^3
++	#lea	32*9*6(%rsp), %rsi
++	#lea	32*9*7(%rsp), %rdx
++	#lea	32*9*5(%rsp), %rcx
++	#lea	32*9*0($r_ptr), %rdi
++	#call	avx2_sub_x4
++	#NORMALIZE
++	#STORE
++
++	#	X3 = X3 - U2*2
++	#lea	32*9*0($r_ptr), %rsi
++	#lea	32*9*0($r_ptr), %rdi
++	#call	avx2_sub_x4
++	#NORMALIZE
++	#STORE
++
++	lea	`32*9*6+128`(%rsp), %rsi
++	lea	.LAVX2_POLY_x2+128(%rip), %rax
++	lea	`32*9*7+128`(%rsp), %rdx
++	lea	`32*9*5+128`(%rsp), %rcx
++	lea	`32*9*0`($r_ptr), %rdi
++
++	vmovdqa	32*0-128(%rsi), $ACC0
++	vmovdqa	32*1-128(%rsi), $ACC1
++	vmovdqa	32*2-128(%rsi), $ACC2
++	vmovdqa	32*3-128(%rsi), $ACC3
++	vmovdqa	32*4-128(%rsi), $ACC4
++	vmovdqa	32*5-128(%rsi), $ACC5
++	vmovdqa	32*6-128(%rsi), $ACC6
++	vmovdqa	32*7-128(%rsi), $ACC7
++	vmovdqa	32*8-128(%rsi), $ACC8
++
++	vpaddq	32*0-128(%rax), $ACC0, $ACC0
++	vpaddq	32*1-128(%rax), $ACC1, $ACC1
++	vpaddq	32*2-128(%rax), $ACC2, $ACC2
++	vpaddq	32*3-128(%rax), $ACC3, $ACC3
++	vpaddq	32*4-128(%rax), $ACC4, $ACC4
++	vpaddq	32*5-128(%rax), $ACC5, $ACC5
++	vpaddq	32*6-128(%rax), $ACC6, $ACC6
++	vpaddq	32*7-128(%rax), $ACC7, $ACC7
++	vpaddq	32*8-128(%rax), $ACC8, $ACC8
++
++	vpsubq	32*0-128(%rdx), $ACC0, $ACC0
++	vpsubq	32*1-128(%rdx), $ACC1, $ACC1
++	vpsubq	32*2-128(%rdx), $ACC2, $ACC2
++	vpsubq	32*3-128(%rdx), $ACC3, $ACC3
++	vpsubq	32*4-128(%rdx), $ACC4, $ACC4
++	vpsubq	32*5-128(%rdx), $ACC5, $ACC5
++	vpsubq	32*6-128(%rdx), $ACC6, $ACC6
++	vpsubq	32*7-128(%rdx), $ACC7, $ACC7
++	vpsubq	32*8-128(%rdx), $ACC8, $ACC8
++
++	vpsubq	32*0-128(%rcx), $ACC0, $ACC0
++	vpsubq	32*1-128(%rcx), $ACC1, $ACC1
++	vpsubq	32*2-128(%rcx), $ACC2, $ACC2
++	vpsubq	32*3-128(%rcx), $ACC3, $ACC3
++	vpsubq	32*4-128(%rcx), $ACC4, $ACC4
++	vpsubq	32*5-128(%rcx), $ACC5, $ACC5
++	vpsubq	32*6-128(%rcx), $ACC6, $ACC6
++	vpsubq	32*7-128(%rcx), $ACC7, $ACC7
++	vpsubq	32*8-128(%rcx), $ACC8, $ACC8
++	call	avx2_normalize
++
++	lea	32*0($b_ptr), %rsi
++	lea	32*0($a_ptr), %rdx
++	call	avx2_select_n_store
++
++	#	H = U2 - X3
++	lea	`32*9*0`(%rsp), %rsi
++	lea	`32*9*0`($r_ptr), %rdx
++	lea	`32*9*3`(%rsp), %rdi
++	call	avx2_sub_x4
++	call	avx2_normalize_n_store
++
++	#	H = H*R
++	lea	`32*9*3`(%rsp), %rsi
++	lea	`32*9*4`(%rsp), %rdx
++	lea	`32*9*3`(%rsp), %rdi
++	call	avx2_mul_x4
++	call	avx2_normalize_n_store
++
++	#	S2 = S1 * H^3
++	lea	`32*9*7`(%rsp), %rsi
++	lea	`32*9*1`($a_ptr), %rdx
++	lea	`32*9*1`(%rsp), %rdi
++	call	avx2_mul_x4
++	call	avx2_normalize_n_store
++
++	#
++	lea	`32*9*3`(%rsp), %rsi
++	lea	`32*9*1`(%rsp), %rdx
++	lea	`32*9*1`($r_ptr), %rdi
++	call	avx2_sub_x4
++	call	avx2_normalize
++
++	lea	32*9($b_ptr), %rsi
++	lea	32*9($a_ptr), %rdx
++	call	avx2_select_n_store
++
++	#lea	32*9*0($r_ptr), %rsi
++	#lea	32*9*0($r_ptr), %rdi
++	#call	avx2_mul_by1_x4
++	#NORMALIZE
++	#STORE
++
++	lea	`32*9*1`($r_ptr), %rsi
++	lea	`32*9*1`($r_ptr), %rdi
++	call	avx2_mul_by1_x4
++	call	avx2_normalize_n_store
++
++	vzeroupper
++___
++$code.=<<___	if ($win64);
++	movaps	%xmm6, -16*10(%rbp)
++	movaps	%xmm7, -16*9(%rbp)
++	movaps	%xmm8, -16*8(%rbp)
++	movaps	%xmm9, -16*7(%rbp)
++	movaps	%xmm10, -16*6(%rbp)
++	movaps	%xmm11, -16*5(%rbp)
++	movaps	%xmm12, -16*4(%rbp)
++	movaps	%xmm13, -16*3(%rbp)
++	movaps	%xmm14, -16*2(%rbp)
++	movaps	%xmm15, -16*1(%rbp)
++___
++$code.=<<___;
++	mov	%rbp, %rsp
++	pop	%rbp
++	ret
++.size	ecp_nistz256_avx2_point_add_affines_x4,.-ecp_nistz256_avx2_point_add_affines_x4
++
++################################################################################
++# void ecp_nistz256_avx2_to_mont(void* RESULTx4, void *Ax4);
++.globl	ecp_nistz256_avx2_to_mont
++.type	ecp_nistz256_avx2_to_mont,\@function,2
++.align	32
++ecp_nistz256_avx2_to_mont:
++	vzeroupper
++___
++$code.=<<___	if ($win64);
++	lea	-8-16*10(%rsp), %rsp
++	vmovaps	%xmm6, -8-16*10(%rax)
++	vmovaps	%xmm7, -8-16*9(%rax)
++	vmovaps	%xmm8, -8-16*8(%rax)
++	vmovaps	%xmm9, -8-16*7(%rax)
++	vmovaps	%xmm10, -8-16*6(%rax)
++	vmovaps	%xmm11, -8-16*5(%rax)
++	vmovaps	%xmm12, -8-16*4(%rax)
++	vmovaps	%xmm13, -8-16*3(%rax)
++	vmovaps	%xmm14, -8-16*2(%rax)
++	vmovaps	%xmm15, -8-16*1(%rax)
++___
++$code.=<<___;
++	vmovdqa	.LAVX2_AND_MASK(%rip), $AND_MASK
++	lea	.LTO_MONT_AVX2(%rip), %rdx
++	call	avx2_mul_x4
++	call	avx2_normalize_n_store
++
++	vzeroupper
++___
++$code.=<<___	if ($win64);
++	movaps	16*0(%rsp), %xmm6
++	movaps	16*1(%rsp), %xmm7
++	movaps	16*2(%rsp), %xmm8
++	movaps	16*3(%rsp), %xmm9
++	movaps	16*4(%rsp), %xmm10
++	movaps	16*5(%rsp), %xmm11
++	movaps	16*6(%rsp), %xmm12
++	movaps	16*7(%rsp), %xmm13
++	movaps	16*8(%rsp), %xmm14
++	movaps	16*9(%rsp), %xmm15
++	lea	8+16*10(%rsp), %rsp
++___
++$code.=<<___;
++	ret
++.size	ecp_nistz256_avx2_to_mont,.-ecp_nistz256_avx2_to_mont
++
++################################################################################
++# void ecp_nistz256_avx2_from_mont(void* RESULTx4, void *Ax4);
++.globl	ecp_nistz256_avx2_from_mont
++.type	ecp_nistz256_avx2_from_mont,\@function,2
++.align	32
++ecp_nistz256_avx2_from_mont:
++	vzeroupper
++___
++$code.=<<___	if ($win64);
++	lea	-8-16*10(%rsp), %rsp
++	vmovaps	%xmm6, -8-16*10(%rax)
++	vmovaps	%xmm7, -8-16*9(%rax)
++	vmovaps	%xmm8, -8-16*8(%rax)
++	vmovaps	%xmm9, -8-16*7(%rax)
++	vmovaps	%xmm10, -8-16*6(%rax)
++	vmovaps	%xmm11, -8-16*5(%rax)
++	vmovaps	%xmm12, -8-16*4(%rax)
++	vmovaps	%xmm13, -8-16*3(%rax)
++	vmovaps	%xmm14, -8-16*2(%rax)
++	vmovaps	%xmm15, -8-16*1(%rax)
++___
++$code.=<<___;
++	vmovdqa	.LAVX2_AND_MASK(%rip), $AND_MASK
++	lea	.LFROM_MONT_AVX2(%rip), %rdx
++	call	avx2_mul_x4
++	call	avx2_normalize_n_store
++
++	vzeroupper
++___
++$code.=<<___	if ($win64);
++	movaps	16*0(%rsp), %xmm6
++	movaps	16*1(%rsp), %xmm7
++	movaps	16*2(%rsp), %xmm8
++	movaps	16*3(%rsp), %xmm9
++	movaps	16*4(%rsp), %xmm10
++	movaps	16*5(%rsp), %xmm11
++	movaps	16*6(%rsp), %xmm12
++	movaps	16*7(%rsp), %xmm13
++	movaps	16*8(%rsp), %xmm14
++	movaps	16*9(%rsp), %xmm15
++	lea	8+16*10(%rsp), %rsp
++___
++$code.=<<___;
++	ret
++.size	ecp_nistz256_avx2_from_mont,.-ecp_nistz256_avx2_from_mont
++
++################################################################################
++# void ecp_nistz256_avx2_set1(void* RESULTx4);
++.globl	ecp_nistz256_avx2_set1
++.type	ecp_nistz256_avx2_set1,\@function,1
++.align	32
++ecp_nistz256_avx2_set1:
++	lea	.LONE+128(%rip), %rax
++	lea	128(%rdi), %rdi
++	vzeroupper
++	vmovdqa	32*0-128(%rax), %ymm0
++	vmovdqa	32*1-128(%rax), %ymm1
++	vmovdqa	32*2-128(%rax), %ymm2
++	vmovdqa	32*3-128(%rax), %ymm3
++	vmovdqa	32*4-128(%rax), %ymm4
++	vmovdqa	32*5-128(%rax), %ymm5
++	vmovdqa	%ymm0, 32*0-128(%rdi)
++	vmovdqa	32*6-128(%rax), %ymm0
++	vmovdqa	%ymm1, 32*1-128(%rdi)
++	vmovdqa	32*7-128(%rax), %ymm1
++	vmovdqa	%ymm2, 32*2-128(%rdi)
++	vmovdqa	32*8-128(%rax), %ymm2
++	vmovdqa	%ymm3, 32*3-128(%rdi)
++	vmovdqa	%ymm4, 32*4-128(%rdi)
++	vmovdqa	%ymm5, 32*5-128(%rdi)
++	vmovdqa	%ymm0, 32*6-128(%rdi)
++	vmovdqa	%ymm1, 32*7-128(%rdi)
++	vmovdqa	%ymm2, 32*8-128(%rdi)
++
++	vzeroupper
++	ret
++.size	ecp_nistz256_avx2_set1,.-ecp_nistz256_avx2_set1
++___
++}
++{
++################################################################################
++# void ecp_nistz256_avx2_multi_gather_w7(void* RESULT, void *in,
++#			    int index0, int index1, int index2, int index3);
++################################################################################
++
++my ($val,$in_t,$index0,$index1,$index2,$index3)=("%rdi","%rsi","%edx","%ecx","%r8d","%r9d");
++my ($INDEX0,$INDEX1,$INDEX2,$INDEX3)=map("%ymm$_",(0..3));
++my ($R0a,$R0b,$R1a,$R1b,$R2a,$R2b,$R3a,$R3b)=map("%ymm$_",(4..11));
++my ($M0,$T0,$T1,$TMP0)=map("%ymm$_",(12..15));
++
++$code.=<<___;
++.globl	ecp_nistz256_avx2_multi_gather_w7
++.type	ecp_nistz256_avx2_multi_gather_w7,\@function,6
++.align	32
++ecp_nistz256_avx2_multi_gather_w7:
++	vzeroupper
++___
++$code.=<<___	if ($win64);
++	lea	-8-16*10(%rsp), %rsp
++	vmovaps	%xmm6, -8-16*10(%rax)
++	vmovaps	%xmm7, -8-16*9(%rax)
++	vmovaps	%xmm8, -8-16*8(%rax)
++	vmovaps	%xmm9, -8-16*7(%rax)
++	vmovaps	%xmm10, -8-16*6(%rax)
++	vmovaps	%xmm11, -8-16*5(%rax)
++	vmovaps	%xmm12, -8-16*4(%rax)
++	vmovaps	%xmm13, -8-16*3(%rax)
++	vmovaps	%xmm14, -8-16*2(%rax)
++	vmovaps	%xmm15, -8-16*1(%rax)
++___
++$code.=<<___;
++	lea	.LIntOne(%rip), %rax
++
++	vmovd	$index0, %xmm0
++	vmovd	$index1, %xmm1
++	vmovd	$index2, %xmm2
++	vmovd	$index3, %xmm3
++
++	vpxor	$R0a, $R0a, $R0a
++	vpxor	$R0b, $R0b, $R0b
++	vpxor	$R1a, $R1a, $R1a
++	vpxor	$R1b, $R1b, $R1b
++	vpxor	$R2a, $R2a, $R2a
++	vpxor	$R2b, $R2b, $R2b
++	vpxor	$R3a, $R3a, $R3a
++	vpxor	$R3b, $R3b, $R3b
++	vmovdqa	(%rax), $M0
++
++	vpermd	$INDEX0, $R0a, $INDEX0
++	vpermd	$INDEX1, $R0a, $INDEX1
++	vpermd	$INDEX2, $R0a, $INDEX2
++	vpermd	$INDEX3, $R0a, $INDEX3
++
++	mov	\$64, %ecx
++	lea	112($val), $val		# size optimization
++	jmp	.Lmulti_select_loop_avx2
++
++# INDEX=0, corresponds to the point at infty (0,0)
++.align	32
++.Lmulti_select_loop_avx2:
++	vpcmpeqd	$INDEX0, $M0, $TMP0
++
++	vmovdqa		`32*0+32*64*2*0`($in_t), $T0
++	vmovdqa		`32*1+32*64*2*0`($in_t), $T1
++	vpand		$TMP0, $T0, $T0
++	vpand		$TMP0, $T1, $T1
++	vpxor		$T0, $R0a, $R0a
++	vpxor		$T1, $R0b, $R0b
++
++	vpcmpeqd	$INDEX1, $M0, $TMP0
++
++	vmovdqa		`32*0+32*64*2*1`($in_t), $T0
++	vmovdqa		`32*1+32*64*2*1`($in_t), $T1
++	vpand		$TMP0, $T0, $T0
++	vpand		$TMP0, $T1, $T1
++	vpxor		$T0, $R1a, $R1a
++	vpxor		$T1, $R1b, $R1b
++
++	vpcmpeqd	$INDEX2, $M0, $TMP0
++
++	vmovdqa		`32*0+32*64*2*2`($in_t), $T0
++	vmovdqa		`32*1+32*64*2*2`($in_t), $T1
++	vpand		$TMP0, $T0, $T0
++	vpand		$TMP0, $T1, $T1
++	vpxor		$T0, $R2a, $R2a
++	vpxor		$T1, $R2b, $R2b
++
++	vpcmpeqd	$INDEX3, $M0, $TMP0
++
++	vmovdqa		`32*0+32*64*2*3`($in_t), $T0
++	vmovdqa		`32*1+32*64*2*3`($in_t), $T1
++	vpand		$TMP0, $T0, $T0
++	vpand		$TMP0, $T1, $T1
++	vpxor		$T0, $R3a, $R3a
++	vpxor		$T1, $R3b, $R3b
++
++	vpaddd		(%rax), $M0, $M0	# increment
++	lea		32*2($in_t), $in_t
++
++        dec	%ecx
++	jnz	.Lmulti_select_loop_avx2
++
++	vmovdqu	$R0a, 32*0-112($val)
++	vmovdqu	$R0b, 32*1-112($val)
++	vmovdqu	$R1a, 32*2-112($val)
++	vmovdqu	$R1b, 32*3-112($val)
++	vmovdqu	$R2a, 32*4-112($val)
++	vmovdqu	$R2b, 32*5-112($val)
++	vmovdqu	$R3a, 32*6-112($val)
++	vmovdqu	$R3b, 32*7-112($val)
++
++	vzeroupper
++___
++$code.=<<___	if ($win64);
++	movaps	16*0(%rsp), %xmm6
++	movaps	16*1(%rsp), %xmm7
++	movaps	16*2(%rsp), %xmm8
++	movaps	16*3(%rsp), %xmm9
++	movaps	16*4(%rsp), %xmm10
++	movaps	16*5(%rsp), %xmm11
++	movaps	16*6(%rsp), %xmm12
++	movaps	16*7(%rsp), %xmm13
++	movaps	16*8(%rsp), %xmm14
++	movaps	16*9(%rsp), %xmm15
++	lea	8+16*10(%rsp), %rsp
++___
++$code.=<<___;
++	ret
++.size	ecp_nistz256_avx2_multi_gather_w7,.-ecp_nistz256_avx2_multi_gather_w7
++
++.extern	OPENSSL_ia32cap_P
++.globl	ecp_nistz_avx2_eligible
++.type	ecp_nistz_avx2_eligible,\@abi-omnipotent
++.align	32
++ecp_nistz_avx2_eligible:
++	mov	OPENSSL_ia32cap_P+8(%rip),%eax
++	shr	\$5,%eax
++	and	\$1,%eax
++	ret
++.size	ecp_nistz_avx2_eligible,.-ecp_nistz_avx2_eligible
++___
++}
++}} else {{	# assembler is too old
++$code.=<<___;
++.text
++
++.globl	ecp_nistz256_avx2_transpose_convert
++.globl	ecp_nistz256_avx2_convert_transpose_back
++.globl	ecp_nistz256_avx2_point_add_affine_x4
++.globl	ecp_nistz256_avx2_point_add_affines_x4
++.globl	ecp_nistz256_avx2_to_mont
++.globl	ecp_nistz256_avx2_from_mont
++.globl	ecp_nistz256_avx2_set1
++.globl	ecp_nistz256_avx2_multi_gather_w7
++.type	ecp_nistz256_avx2_multi_gather_w7,\@abi-omnipotent
++ecp_nistz256_avx2_transpose_convert:
++ecp_nistz256_avx2_convert_transpose_back:
++ecp_nistz256_avx2_point_add_affine_x4:
++ecp_nistz256_avx2_point_add_affines_x4:
++ecp_nistz256_avx2_to_mont:
++ecp_nistz256_avx2_from_mont:
++ecp_nistz256_avx2_set1:
++ecp_nistz256_avx2_multi_gather_w7:
++	.byte	0x0f,0x0b	# ud2
++	ret
++.size	ecp_nistz256_avx2_multi_gather_w7,.-ecp_nistz256_avx2_multi_gather_w7
++
++.globl	ecp_nistz_avx2_eligible
++.type	ecp_nistz_avx2_eligible,\@abi-omnipotent
++ecp_nistz_avx2_eligible:
++	xor	%eax,%eax
++	ret
++.size	ecp_nistz_avx2_eligible,.-ecp_nistz_avx2_eligible
++___
++}}
++
++foreach (split("\n",$code)) {
++	s/\`([^\`]*)\`/eval($1)/geo;
++
++	print $_,"\n";
++}
++
++close STDOUT;
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/ec/asm/ecp_nistz256-sparcv9.pl b/CryptoPkg/Library/OpensslLib/openssl/crypto/ec/asm/ecp_nistz256-sparcv9.pl
+new file mode 100755
+index 0000000..97201cb
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/ec/asm/ecp_nistz256-sparcv9.pl
+@@ -0,0 +1,3061 @@
++#! /usr/bin/env perl
++# Copyright 2015-2016 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
++# in the file LICENSE in the source distribution or at
++# https://www.openssl.org/source/license.html
++
++
++# ====================================================================
++# Written by Andy Polyakov  for the OpenSSL
++# project. The module is, however, dual licensed under OpenSSL and
++# CRYPTOGAMS licenses depending on where you obtain it. For further
++# details see http://www.openssl.org/~appro/cryptogams/.
++# ====================================================================
++#
++# ECP_NISTZ256 module for SPARCv9.
++#
++# February 2015.
++#
++# Original ECP_NISTZ256 submission targeting x86_64 is detailed in
++# http://eprint.iacr.org/2013/816. In the process of adaptation
++# original .c module was made 32-bit savvy in order to make this
++# implementation possible.
++#
++#			with/without -DECP_NISTZ256_ASM
++# UltraSPARC III	+12-18%
++# SPARC T4		+99-550% (+66-150% on 32-bit Solaris)
++#
++# Ranges denote minimum and maximum improvement coefficients depending
++# on benchmark. Lower coefficients are for ECDSA sign, server-side
++# operation. Keep in mind that +200% means 3x improvement.
++
++$output = pop;
++open STDOUT,">$output";
++
++$code.=<<___;
++#include "sparc_arch.h"
++
++#define LOCALS	(STACK_BIAS+STACK_FRAME)
++#ifdef	__arch64__
++.register	%g2,#scratch
++.register	%g3,#scratch
++# define STACK64_FRAME	STACK_FRAME
++# define LOCALS64	LOCALS
++#else
++# define STACK64_FRAME	(2047+192)
++# define LOCALS64	STACK64_FRAME
++#endif
++
++.section	".text",#alloc,#execinstr
++___
++########################################################################
++# Convert ecp_nistz256_table.c to layout expected by ecp_nistz_gather_w7
++#
++$0 =~ m/(.*[\/\\])[^\/\\]+$/; $dir=$1;
++open TABLE,") {
++	s/TOBN\(\s*(0x[0-9a-f]+),\s*(0x[0-9a-f]+)\s*\)/push @arr,hex($2),hex($1)/geo;
++}
++close TABLE;
++
++# See ecp_nistz256_table.c for explanation for why it's 64*16*37.
++# 64*16*37-1 is because $#arr returns last valid index or @arr, not
++# amount of elements.
++die "insane number of elements" if ($#arr != 64*16*37-1);
++
++$code.=<<___;
++.globl	ecp_nistz256_precomputed
++.align	4096
++ecp_nistz256_precomputed:
++___
++########################################################################
++# this conversion smashes P256_POINT_AFFINE by individual bytes with
++# 64 byte interval, similar to
++#	1111222233334444
++#	1234123412341234
++for(1..37) {
++	@tbl = splice(@arr,0,64*16);
++	for($i=0;$i<64;$i++) {
++		undef @line;
++		for($j=0;$j<64;$j++) {
++			push @line,(@tbl[$j*16+$i/4]>>(($i%4)*8))&0xff;
++		}
++		$code.=".byte\t";
++		$code.=join(',',map { sprintf "0x%02x",$_} @line);
++		$code.="\n";
++	}
++}
++
++{{{
++my ($rp,$ap,$bp)=map("%i$_",(0..2));
++my @acc=map("%l$_",(0..7));
++my ($t0,$t1,$t2,$t3,$t4,$t5,$t6,$t7)=(map("%o$_",(0..5)),"%g4","%g5");
++my ($bi,$a0,$mask,$carry)=(map("%i$_",(3..5)),"%g1");
++my ($rp_real,$ap_real)=("%g2","%g3");
++
++$code.=<<___;
++.type	ecp_nistz256_precomputed,#object
++.size	ecp_nistz256_precomputed,.-ecp_nistz256_precomputed
++.align	64
++.LRR:	! 2^512 mod P precomputed for NIST P256 polynomial
++.long	0x00000003, 0x00000000, 0xffffffff, 0xfffffffb
++.long	0xfffffffe, 0xffffffff, 0xfffffffd, 0x00000004
++.Lone:
++.long	1,0,0,0,0,0,0,0
++.asciz	"ECP_NISTZ256 for SPARCv9, CRYPTOGAMS by "
++
++! void	ecp_nistz256_to_mont(BN_ULONG %i0[8],const BN_ULONG %i1[8]);
++.globl	ecp_nistz256_to_mont
++.align	64
++ecp_nistz256_to_mont:
++	save	%sp,-STACK_FRAME,%sp
++	nop
++1:	call	.+8
++	add	%o7,.LRR-1b,$bp
++	call	__ecp_nistz256_mul_mont
++	nop
++	ret
++	restore
++.type	ecp_nistz256_to_mont,#function
++.size	ecp_nistz256_to_mont,.-ecp_nistz256_to_mont
++
++! void	ecp_nistz256_from_mont(BN_ULONG %i0[8],const BN_ULONG %i1[8]);
++.globl	ecp_nistz256_from_mont
++.align	32
++ecp_nistz256_from_mont:
++	save	%sp,-STACK_FRAME,%sp
++	nop
++1:	call	.+8
++	add	%o7,.Lone-1b,$bp
++	call	__ecp_nistz256_mul_mont
++	nop
++	ret
++	restore
++.type	ecp_nistz256_from_mont,#function
++.size	ecp_nistz256_from_mont,.-ecp_nistz256_from_mont
++
++! void	ecp_nistz256_mul_mont(BN_ULONG %i0[8],const BN_ULONG %i1[8],
++!					      const BN_ULONG %i2[8]);
++.globl	ecp_nistz256_mul_mont
++.align	32
++ecp_nistz256_mul_mont:
++	save	%sp,-STACK_FRAME,%sp
++	nop
++	call	__ecp_nistz256_mul_mont
++	nop
++	ret
++	restore
++.type	ecp_nistz256_mul_mont,#function
++.size	ecp_nistz256_mul_mont,.-ecp_nistz256_mul_mont
++
++! void	ecp_nistz256_sqr_mont(BN_ULONG %i0[8],const BN_ULONG %i2[8]);
++.globl	ecp_nistz256_sqr_mont
++.align	32
++ecp_nistz256_sqr_mont:
++	save	%sp,-STACK_FRAME,%sp
++	mov	$ap,$bp
++	call	__ecp_nistz256_mul_mont
++	nop
++	ret
++	restore
++.type	ecp_nistz256_sqr_mont,#function
++.size	ecp_nistz256_sqr_mont,.-ecp_nistz256_sqr_mont
++___
++
++########################################################################
++# Special thing to keep in mind is that $t0-$t7 hold 64-bit values,
++# while all others are meant to keep 32. "Meant to" means that additions
++# to @acc[0-7] do "contaminate" upper bits, but they are cleared before
++# they can affect outcome (follow 'and' with $mask). Also keep in mind
++# that addition with carry is addition with 32-bit carry, even though
++# CPU is 64-bit. [Addition with 64-bit carry was introduced in T3, see
++# below for VIS3 code paths.]
++
++$code.=<<___;
++.align	32
++__ecp_nistz256_mul_mont:
++	ld	[$bp+0],$bi		! b[0]
++	mov	-1,$mask
++	ld	[$ap+0],$a0
++	srl	$mask,0,$mask		! 0xffffffff
++	ld	[$ap+4],$t1
++	ld	[$ap+8],$t2
++	ld	[$ap+12],$t3
++	ld	[$ap+16],$t4
++	ld	[$ap+20],$t5
++	ld	[$ap+24],$t6
++	ld	[$ap+28],$t7
++	mulx	$a0,$bi,$t0		! a[0-7]*b[0], 64-bit results
++	mulx	$t1,$bi,$t1
++	mulx	$t2,$bi,$t2
++	mulx	$t3,$bi,$t3
++	mulx	$t4,$bi,$t4
++	mulx	$t5,$bi,$t5
++	mulx	$t6,$bi,$t6
++	mulx	$t7,$bi,$t7
++	srlx	$t0,32,@acc[1]		! extract high parts
++	srlx	$t1,32,@acc[2]
++	srlx	$t2,32,@acc[3]
++	srlx	$t3,32,@acc[4]
++	srlx	$t4,32,@acc[5]
++	srlx	$t5,32,@acc[6]
++	srlx	$t6,32,@acc[7]
++	srlx	$t7,32,@acc[0]		! "@acc[8]"
++	mov	0,$carry
++___
++for($i=1;$i<8;$i++) {
++$code.=<<___;
++	addcc	@acc[1],$t1,@acc[1]	! accumulate high parts
++	ld	[$bp+4*$i],$bi		! b[$i]
++	ld	[$ap+4],$t1		! re-load a[1-7]
++	addccc	@acc[2],$t2,@acc[2]
++	addccc	@acc[3],$t3,@acc[3]
++	ld	[$ap+8],$t2
++	ld	[$ap+12],$t3
++	addccc	@acc[4],$t4,@acc[4]
++	addccc	@acc[5],$t5,@acc[5]
++	ld	[$ap+16],$t4
++	ld	[$ap+20],$t5
++	addccc	@acc[6],$t6,@acc[6]
++	addccc	@acc[7],$t7,@acc[7]
++	ld	[$ap+24],$t6
++	ld	[$ap+28],$t7
++	addccc	@acc[0],$carry,@acc[0]	! "@acc[8]"
++	addc	%g0,%g0,$carry
++___
++	# Reduction iteration is normally performed by accumulating
++	# result of multiplication of modulus by "magic" digit [and
++	# omitting least significant word, which is guaranteed to
++	# be 0], but thanks to special form of modulus and "magic"
++	# digit being equal to least significant word, it can be
++	# performed with additions and subtractions alone. Indeed:
++	#
++	#        ffff.0001.0000.0000.0000.ffff.ffff.ffff
++	# *                                         abcd
++	# + xxxx.xxxx.xxxx.xxxx.xxxx.xxxx.xxxx.xxxx.abcd
++	#
++	# Now observing that ff..ff*x = (2^n-1)*x = 2^n*x-x, we
++	# rewrite above as:
++	#
++	#   xxxx.xxxx.xxxx.xxxx.xxxx.xxxx.xxxx.xxxx.abcd
++	# + abcd.0000.abcd.0000.0000.abcd.0000.0000.0000
++	# -      abcd.0000.0000.0000.0000.0000.0000.abcd
++	#
++	# or marking redundant operations:
++	#
++	#   xxxx.xxxx.xxxx.xxxx.xxxx.xxxx.xxxx.xxxx.----
++	# + abcd.0000.abcd.0000.0000.abcd.----.----.----
++	# -      abcd.----.----.----.----.----.----.----
++
++$code.=<<___;
++	! multiplication-less reduction
++	addcc	@acc[3],$t0,@acc[3]	! r[3]+=r[0]
++	addccc	@acc[4],%g0,@acc[4]	! r[4]+=0
++	 and	@acc[1],$mask,@acc[1]
++	 and	@acc[2],$mask,@acc[2]
++	addccc	@acc[5],%g0,@acc[5]	! r[5]+=0
++	addccc	@acc[6],$t0,@acc[6]	! r[6]+=r[0]
++	 and	@acc[3],$mask,@acc[3]
++	 and	@acc[4],$mask,@acc[4]
++	addccc	@acc[7],%g0,@acc[7]	! r[7]+=0
++	addccc	@acc[0],$t0,@acc[0]	! r[8]+=r[0]	"@acc[8]"
++	 and	@acc[5],$mask,@acc[5]
++	 and	@acc[6],$mask,@acc[6]
++	addc	$carry,%g0,$carry	! top-most carry
++	subcc	@acc[7],$t0,@acc[7]	! r[7]-=r[0]
++	subccc	@acc[0],%g0,@acc[0]	! r[8]-=0	"@acc[8]"
++	subc	$carry,%g0,$carry	! top-most carry
++	 and	@acc[7],$mask,@acc[7]
++	 and	@acc[0],$mask,@acc[0]	! "@acc[8]"
++___
++	push(@acc,shift(@acc));		# rotate registers to "omit" acc[0]
++$code.=<<___;
++	mulx	$a0,$bi,$t0		! a[0-7]*b[$i], 64-bit results
++	mulx	$t1,$bi,$t1
++	mulx	$t2,$bi,$t2
++	mulx	$t3,$bi,$t3
++	mulx	$t4,$bi,$t4
++	mulx	$t5,$bi,$t5
++	mulx	$t6,$bi,$t6
++	mulx	$t7,$bi,$t7
++	add	@acc[0],$t0,$t0		! accumulate low parts, can't overflow
++	add	@acc[1],$t1,$t1
++	srlx	$t0,32,@acc[1]		! extract high parts
++	add	@acc[2],$t2,$t2
++	srlx	$t1,32,@acc[2]
++	add	@acc[3],$t3,$t3
++	srlx	$t2,32,@acc[3]
++	add	@acc[4],$t4,$t4
++	srlx	$t3,32,@acc[4]
++	add	@acc[5],$t5,$t5
++	srlx	$t4,32,@acc[5]
++	add	@acc[6],$t6,$t6
++	srlx	$t5,32,@acc[6]
++	add	@acc[7],$t7,$t7
++	srlx	$t6,32,@acc[7]
++	srlx	$t7,32,@acc[0]		! "@acc[8]"
++___
++}
++$code.=<<___;
++	addcc	@acc[1],$t1,@acc[1]	! accumulate high parts
++	addccc	@acc[2],$t2,@acc[2]
++	addccc	@acc[3],$t3,@acc[3]
++	addccc	@acc[4],$t4,@acc[4]
++	addccc	@acc[5],$t5,@acc[5]
++	addccc	@acc[6],$t6,@acc[6]
++	addccc	@acc[7],$t7,@acc[7]
++	addccc	@acc[0],$carry,@acc[0]	! "@acc[8]"
++	addc	%g0,%g0,$carry
++
++	addcc	@acc[3],$t0,@acc[3]	! multiplication-less reduction
++	addccc	@acc[4],%g0,@acc[4]
++	addccc	@acc[5],%g0,@acc[5]
++	addccc	@acc[6],$t0,@acc[6]
++	addccc	@acc[7],%g0,@acc[7]
++	addccc	@acc[0],$t0,@acc[0]	! "@acc[8]"
++	addc	$carry,%g0,$carry
++	subcc	@acc[7],$t0,@acc[7]
++	subccc	@acc[0],%g0,@acc[0]	! "@acc[8]"
++	subc	$carry,%g0,$carry	! top-most carry
++___
++	push(@acc,shift(@acc));		# rotate registers to omit acc[0]
++$code.=<<___;
++	! Final step is "if result > mod, subtract mod", but we do it
++	! "other way around", namely subtract modulus from result
++	! and if it borrowed, add modulus back.
++
++	subcc	@acc[0],-1,@acc[0]	! subtract modulus
++	subccc	@acc[1],-1,@acc[1]
++	subccc	@acc[2],-1,@acc[2]
++	subccc	@acc[3],0,@acc[3]
++	subccc	@acc[4],0,@acc[4]
++	subccc	@acc[5],0,@acc[5]
++	subccc	@acc[6],1,@acc[6]
++	subccc	@acc[7],-1,@acc[7]
++	subc	$carry,0,$carry		! broadcast borrow bit
++
++	! Note that because mod has special form, i.e. consists of
++	! 0xffffffff, 1 and 0s, we can conditionally synthesize it by
++	! using value of broadcasted borrow and the borrow bit itself.
++	! To minimize dependency chain we first broadcast and then
++	! extract the bit by negating (follow $bi).
++
++	addcc	@acc[0],$carry,@acc[0]	! add modulus or zero
++	addccc	@acc[1],$carry,@acc[1]
++	neg	$carry,$bi
++	st	@acc[0],[$rp]
++	addccc	@acc[2],$carry,@acc[2]
++	st	@acc[1],[$rp+4]
++	addccc	@acc[3],0,@acc[3]
++	st	@acc[2],[$rp+8]
++	addccc	@acc[4],0,@acc[4]
++	st	@acc[3],[$rp+12]
++	addccc	@acc[5],0,@acc[5]
++	st	@acc[4],[$rp+16]
++	addccc	@acc[6],$bi,@acc[6]
++	st	@acc[5],[$rp+20]
++	addc	@acc[7],$carry,@acc[7]
++	st	@acc[6],[$rp+24]
++	retl
++	st	@acc[7],[$rp+28]
++.type	__ecp_nistz256_mul_mont,#function
++.size	__ecp_nistz256_mul_mont,.-__ecp_nistz256_mul_mont
++
++! void	ecp_nistz256_add(BN_ULONG %i0[8],const BN_ULONG %i1[8],
++!					 const BN_ULONG %i2[8]);
++.globl	ecp_nistz256_add
++.align	32
++ecp_nistz256_add:
++	save	%sp,-STACK_FRAME,%sp
++	ld	[$ap],@acc[0]
++	ld	[$ap+4],@acc[1]
++	ld	[$ap+8],@acc[2]
++	ld	[$ap+12],@acc[3]
++	ld	[$ap+16],@acc[4]
++	ld	[$ap+20],@acc[5]
++	ld	[$ap+24],@acc[6]
++	call	__ecp_nistz256_add
++	ld	[$ap+28],@acc[7]
++	ret
++	restore
++.type	ecp_nistz256_add,#function
++.size	ecp_nistz256_add,.-ecp_nistz256_add
++
++.align	32
++__ecp_nistz256_add:
++	ld	[$bp+0],$t0		! b[0]
++	ld	[$bp+4],$t1
++	ld	[$bp+8],$t2
++	ld	[$bp+12],$t3
++	addcc	@acc[0],$t0,@acc[0]
++	ld	[$bp+16],$t4
++	ld	[$bp+20],$t5
++	addccc	@acc[1],$t1,@acc[1]
++	ld	[$bp+24],$t6
++	ld	[$bp+28],$t7
++	addccc	@acc[2],$t2,@acc[2]
++	addccc	@acc[3],$t3,@acc[3]
++	addccc	@acc[4],$t4,@acc[4]
++	addccc	@acc[5],$t5,@acc[5]
++	addccc	@acc[6],$t6,@acc[6]
++	addccc	@acc[7],$t7,@acc[7]
++	addc	%g0,%g0,$carry
++
++.Lreduce_by_sub:
++
++	! if a+b >= modulus, subtract modulus.
++	!
++	! But since comparison implies subtraction, we subtract
++	! modulus and then add it back if subraction borrowed.
++
++	subcc	@acc[0],-1,@acc[0]
++	subccc	@acc[1],-1,@acc[1]
++	subccc	@acc[2],-1,@acc[2]
++	subccc	@acc[3], 0,@acc[3]
++	subccc	@acc[4], 0,@acc[4]
++	subccc	@acc[5], 0,@acc[5]
++	subccc	@acc[6], 1,@acc[6]
++	subccc	@acc[7],-1,@acc[7]
++	subc	$carry,0,$carry
++
++	! Note that because mod has special form, i.e. consists of
++	! 0xffffffff, 1 and 0s, we can conditionally synthesize it by
++	! using value of borrow and its negative.
++
++	addcc	@acc[0],$carry,@acc[0]	! add synthesized modulus
++	addccc	@acc[1],$carry,@acc[1]
++	neg	$carry,$bi
++	st	@acc[0],[$rp]
++	addccc	@acc[2],$carry,@acc[2]
++	st	@acc[1],[$rp+4]
++	addccc	@acc[3],0,@acc[3]
++	st	@acc[2],[$rp+8]
++	addccc	@acc[4],0,@acc[4]
++	st	@acc[3],[$rp+12]
++	addccc	@acc[5],0,@acc[5]
++	st	@acc[4],[$rp+16]
++	addccc	@acc[6],$bi,@acc[6]
++	st	@acc[5],[$rp+20]
++	addc	@acc[7],$carry,@acc[7]
++	st	@acc[6],[$rp+24]
++	retl
++	st	@acc[7],[$rp+28]
++.type	__ecp_nistz256_add,#function
++.size	__ecp_nistz256_add,.-__ecp_nistz256_add
++
++! void	ecp_nistz256_mul_by_2(BN_ULONG %i0[8],const BN_ULONG %i1[8]);
++.globl	ecp_nistz256_mul_by_2
++.align	32
++ecp_nistz256_mul_by_2:
++	save	%sp,-STACK_FRAME,%sp
++	ld	[$ap],@acc[0]
++	ld	[$ap+4],@acc[1]
++	ld	[$ap+8],@acc[2]
++	ld	[$ap+12],@acc[3]
++	ld	[$ap+16],@acc[4]
++	ld	[$ap+20],@acc[5]
++	ld	[$ap+24],@acc[6]
++	call	__ecp_nistz256_mul_by_2
++	ld	[$ap+28],@acc[7]
++	ret
++	restore
++.type	ecp_nistz256_mul_by_2,#function
++.size	ecp_nistz256_mul_by_2,.-ecp_nistz256_mul_by_2
++
++.align	32
++__ecp_nistz256_mul_by_2:
++	addcc	@acc[0],@acc[0],@acc[0]	! a+a=2*a
++	addccc	@acc[1],@acc[1],@acc[1]
++	addccc	@acc[2],@acc[2],@acc[2]
++	addccc	@acc[3],@acc[3],@acc[3]
++	addccc	@acc[4],@acc[4],@acc[4]
++	addccc	@acc[5],@acc[5],@acc[5]
++	addccc	@acc[6],@acc[6],@acc[6]
++	addccc	@acc[7],@acc[7],@acc[7]
++	b	.Lreduce_by_sub
++	addc	%g0,%g0,$carry
++.type	__ecp_nistz256_mul_by_2,#function
++.size	__ecp_nistz256_mul_by_2,.-__ecp_nistz256_mul_by_2
++
++! void	ecp_nistz256_mul_by_3(BN_ULONG %i0[8],const BN_ULONG %i1[8]);
++.globl	ecp_nistz256_mul_by_3
++.align	32
++ecp_nistz256_mul_by_3:
++	save	%sp,-STACK_FRAME,%sp
++	ld	[$ap],@acc[0]
++	ld	[$ap+4],@acc[1]
++	ld	[$ap+8],@acc[2]
++	ld	[$ap+12],@acc[3]
++	ld	[$ap+16],@acc[4]
++	ld	[$ap+20],@acc[5]
++	ld	[$ap+24],@acc[6]
++	call	__ecp_nistz256_mul_by_3
++	ld	[$ap+28],@acc[7]
++	ret
++	restore
++.type	ecp_nistz256_mul_by_3,#function
++.size	ecp_nistz256_mul_by_3,.-ecp_nistz256_mul_by_3
++
++.align	32
++__ecp_nistz256_mul_by_3:
++	addcc	@acc[0],@acc[0],$t0	! a+a=2*a
++	addccc	@acc[1],@acc[1],$t1
++	addccc	@acc[2],@acc[2],$t2
++	addccc	@acc[3],@acc[3],$t3
++	addccc	@acc[4],@acc[4],$t4
++	addccc	@acc[5],@acc[5],$t5
++	addccc	@acc[6],@acc[6],$t6
++	addccc	@acc[7],@acc[7],$t7
++	addc	%g0,%g0,$carry
++
++	subcc	$t0,-1,$t0		! .Lreduce_by_sub but without stores
++	subccc	$t1,-1,$t1
++	subccc	$t2,-1,$t2
++	subccc	$t3, 0,$t3
++	subccc	$t4, 0,$t4
++	subccc	$t5, 0,$t5
++	subccc	$t6, 1,$t6
++	subccc	$t7,-1,$t7
++	subc	$carry,0,$carry
++
++	addcc	$t0,$carry,$t0		! add synthesized modulus
++	addccc	$t1,$carry,$t1
++	neg	$carry,$bi
++	addccc	$t2,$carry,$t2
++	addccc	$t3,0,$t3
++	addccc	$t4,0,$t4
++	addccc	$t5,0,$t5
++	addccc	$t6,$bi,$t6
++	addc	$t7,$carry,$t7
++
++	addcc	$t0,@acc[0],@acc[0]	! 2*a+a=3*a
++	addccc	$t1,@acc[1],@acc[1]
++	addccc	$t2,@acc[2],@acc[2]
++	addccc	$t3,@acc[3],@acc[3]
++	addccc	$t4,@acc[4],@acc[4]
++	addccc	$t5,@acc[5],@acc[5]
++	addccc	$t6,@acc[6],@acc[6]
++	addccc	$t7,@acc[7],@acc[7]
++	b	.Lreduce_by_sub
++	addc	%g0,%g0,$carry
++.type	__ecp_nistz256_mul_by_3,#function
++.size	__ecp_nistz256_mul_by_3,.-__ecp_nistz256_mul_by_3
++
++! void	ecp_nistz256_sub(BN_ULONG %i0[8],const BN_ULONG %i1[8],
++!				         const BN_ULONG %i2[8]);
++.globl	ecp_nistz256_sub
++.align	32
++ecp_nistz256_sub:
++	save	%sp,-STACK_FRAME,%sp
++	ld	[$ap],@acc[0]
++	ld	[$ap+4],@acc[1]
++	ld	[$ap+8],@acc[2]
++	ld	[$ap+12],@acc[3]
++	ld	[$ap+16],@acc[4]
++	ld	[$ap+20],@acc[5]
++	ld	[$ap+24],@acc[6]
++	call	__ecp_nistz256_sub_from
++	ld	[$ap+28],@acc[7]
++	ret
++	restore
++.type	ecp_nistz256_sub,#function
++.size	ecp_nistz256_sub,.-ecp_nistz256_sub
++
++! void	ecp_nistz256_neg(BN_ULONG %i0[8],const BN_ULONG %i1[8]);
++.globl	ecp_nistz256_neg
++.align	32
++ecp_nistz256_neg:
++	save	%sp,-STACK_FRAME,%sp
++	mov	$ap,$bp
++	mov	0,@acc[0]
++	mov	0,@acc[1]
++	mov	0,@acc[2]
++	mov	0,@acc[3]
++	mov	0,@acc[4]
++	mov	0,@acc[5]
++	mov	0,@acc[6]
++	call	__ecp_nistz256_sub_from
++	mov	0,@acc[7]
++	ret
++	restore
++.type	ecp_nistz256_neg,#function
++.size	ecp_nistz256_neg,.-ecp_nistz256_neg
++
++.align	32
++__ecp_nistz256_sub_from:
++	ld	[$bp+0],$t0		! b[0]
++	ld	[$bp+4],$t1
++	ld	[$bp+8],$t2
++	ld	[$bp+12],$t3
++	subcc	@acc[0],$t0,@acc[0]
++	ld	[$bp+16],$t4
++	ld	[$bp+20],$t5
++	subccc	@acc[1],$t1,@acc[1]
++	subccc	@acc[2],$t2,@acc[2]
++	ld	[$bp+24],$t6
++	ld	[$bp+28],$t7
++	subccc	@acc[3],$t3,@acc[3]
++	subccc	@acc[4],$t4,@acc[4]
++	subccc	@acc[5],$t5,@acc[5]
++	subccc	@acc[6],$t6,@acc[6]
++	subccc	@acc[7],$t7,@acc[7]
++	subc	%g0,%g0,$carry		! broadcast borrow bit
++
++.Lreduce_by_add:
++
++	! if a-b borrows, add modulus.
++	!
++	! Note that because mod has special form, i.e. consists of
++	! 0xffffffff, 1 and 0s, we can conditionally synthesize it by
++	! using value of broadcasted borrow and the borrow bit itself.
++	! To minimize dependency chain we first broadcast and then
++	! extract the bit by negating (follow $bi).
++
++	addcc	@acc[0],$carry,@acc[0]	! add synthesized modulus
++	addccc	@acc[1],$carry,@acc[1]
++	neg	$carry,$bi
++	st	@acc[0],[$rp]
++	addccc	@acc[2],$carry,@acc[2]
++	st	@acc[1],[$rp+4]
++	addccc	@acc[3],0,@acc[3]
++	st	@acc[2],[$rp+8]
++	addccc	@acc[4],0,@acc[4]
++	st	@acc[3],[$rp+12]
++	addccc	@acc[5],0,@acc[5]
++	st	@acc[4],[$rp+16]
++	addccc	@acc[6],$bi,@acc[6]
++	st	@acc[5],[$rp+20]
++	addc	@acc[7],$carry,@acc[7]
++	st	@acc[6],[$rp+24]
++	retl
++	st	@acc[7],[$rp+28]
++.type	__ecp_nistz256_sub_from,#function
++.size	__ecp_nistz256_sub_from,.-__ecp_nistz256_sub_from
++
++.align	32
++__ecp_nistz256_sub_morf:
++	ld	[$bp+0],$t0		! b[0]
++	ld	[$bp+4],$t1
++	ld	[$bp+8],$t2
++	ld	[$bp+12],$t3
++	subcc	$t0,@acc[0],@acc[0]
++	ld	[$bp+16],$t4
++	ld	[$bp+20],$t5
++	subccc	$t1,@acc[1],@acc[1]
++	subccc	$t2,@acc[2],@acc[2]
++	ld	[$bp+24],$t6
++	ld	[$bp+28],$t7
++	subccc	$t3,@acc[3],@acc[3]
++	subccc	$t4,@acc[4],@acc[4]
++	subccc	$t5,@acc[5],@acc[5]
++	subccc	$t6,@acc[6],@acc[6]
++	subccc	$t7,@acc[7],@acc[7]
++	b	.Lreduce_by_add
++	subc	%g0,%g0,$carry		! broadcast borrow bit
++.type	__ecp_nistz256_sub_morf,#function
++.size	__ecp_nistz256_sub_morf,.-__ecp_nistz256_sub_morf
++
++! void	ecp_nistz256_div_by_2(BN_ULONG %i0[8],const BN_ULONG %i1[8]);
++.globl	ecp_nistz256_div_by_2
++.align	32
++ecp_nistz256_div_by_2:
++	save	%sp,-STACK_FRAME,%sp
++	ld	[$ap],@acc[0]
++	ld	[$ap+4],@acc[1]
++	ld	[$ap+8],@acc[2]
++	ld	[$ap+12],@acc[3]
++	ld	[$ap+16],@acc[4]
++	ld	[$ap+20],@acc[5]
++	ld	[$ap+24],@acc[6]
++	call	__ecp_nistz256_div_by_2
++	ld	[$ap+28],@acc[7]
++	ret
++	restore
++.type	ecp_nistz256_div_by_2,#function
++.size	ecp_nistz256_div_by_2,.-ecp_nistz256_div_by_2
++
++.align	32
++__ecp_nistz256_div_by_2:
++	! ret = (a is odd ? a+mod : a) >> 1
++
++	and	@acc[0],1,$bi
++	neg	$bi,$carry
++	addcc	@acc[0],$carry,@acc[0]
++	addccc	@acc[1],$carry,@acc[1]
++	addccc	@acc[2],$carry,@acc[2]
++	addccc	@acc[3],0,@acc[3]
++	addccc	@acc[4],0,@acc[4]
++	addccc	@acc[5],0,@acc[5]
++	addccc	@acc[6],$bi,@acc[6]
++	addccc	@acc[7],$carry,@acc[7]
++	addc	%g0,%g0,$carry
++
++	! ret >>= 1
++
++	srl	@acc[0],1,@acc[0]
++	sll	@acc[1],31,$t0
++	srl	@acc[1],1,@acc[1]
++	or	@acc[0],$t0,@acc[0]
++	sll	@acc[2],31,$t1
++	srl	@acc[2],1,@acc[2]
++	or	@acc[1],$t1,@acc[1]
++	sll	@acc[3],31,$t2
++	st	@acc[0],[$rp]
++	srl	@acc[3],1,@acc[3]
++	or	@acc[2],$t2,@acc[2]
++	sll	@acc[4],31,$t3
++	st	@acc[1],[$rp+4]
++	srl	@acc[4],1,@acc[4]
++	or	@acc[3],$t3,@acc[3]
++	sll	@acc[5],31,$t4
++	st	@acc[2],[$rp+8]
++	srl	@acc[5],1,@acc[5]
++	or	@acc[4],$t4,@acc[4]
++	sll	@acc[6],31,$t5
++	st	@acc[3],[$rp+12]
++	srl	@acc[6],1,@acc[6]
++	or	@acc[5],$t5,@acc[5]
++	sll	@acc[7],31,$t6
++	st	@acc[4],[$rp+16]
++	srl	@acc[7],1,@acc[7]
++	or	@acc[6],$t6,@acc[6]
++	sll	$carry,31,$t7
++	st	@acc[5],[$rp+20]
++	or	@acc[7],$t7,@acc[7]
++	st	@acc[6],[$rp+24]
++	retl
++	st	@acc[7],[$rp+28]
++.type	__ecp_nistz256_div_by_2,#function
++.size	__ecp_nistz256_div_by_2,.-__ecp_nistz256_div_by_2
++___
++
++########################################################################
++# following subroutines are "literal" implementation of those found in
++# ecp_nistz256.c
++#
++########################################################################
++# void ecp_nistz256_point_double(P256_POINT *out,const P256_POINT *inp);
++#
++{
++my ($S,$M,$Zsqr,$tmp0)=map(32*$_,(0..3));
++# above map() describes stack layout with 4 temporary
++# 256-bit vectors on top.
++
++$code.=<<___;
++#ifdef __PIC__
++SPARC_PIC_THUNK(%g1)
++#endif
++
++.globl	ecp_nistz256_point_double
++.align	32
++ecp_nistz256_point_double:
++	SPARC_LOAD_ADDRESS_LEAF(OPENSSL_sparcv9cap_P,%g1,%g5)
++	ld	[%g1],%g1		! OPENSSL_sparcv9cap_P[0]
++	and	%g1,(SPARCV9_VIS3|SPARCV9_64BIT_STACK),%g1
++	cmp	%g1,(SPARCV9_VIS3|SPARCV9_64BIT_STACK)
++	be	ecp_nistz256_point_double_vis3
++	nop
++
++	save	%sp,-STACK_FRAME-32*4,%sp
++
++	mov	$rp,$rp_real
++	mov	$ap,$ap_real
++
++.Lpoint_double_shortcut:
++	ld	[$ap+32],@acc[0]
++	ld	[$ap+32+4],@acc[1]
++	ld	[$ap+32+8],@acc[2]
++	ld	[$ap+32+12],@acc[3]
++	ld	[$ap+32+16],@acc[4]
++	ld	[$ap+32+20],@acc[5]
++	ld	[$ap+32+24],@acc[6]
++	ld	[$ap+32+28],@acc[7]
++	call	__ecp_nistz256_mul_by_2	! p256_mul_by_2(S, in_y);
++	add	%sp,LOCALS+$S,$rp
++
++	add	$ap_real,64,$bp
++	add	$ap_real,64,$ap
++	call	__ecp_nistz256_mul_mont	! p256_sqr_mont(Zsqr, in_z);
++	add	%sp,LOCALS+$Zsqr,$rp
++
++	add	$ap_real,0,$bp
++	call	__ecp_nistz256_add	! p256_add(M, Zsqr, in_x);
++	add	%sp,LOCALS+$M,$rp
++
++	add	%sp,LOCALS+$S,$bp
++	add	%sp,LOCALS+$S,$ap
++	call	__ecp_nistz256_mul_mont	! p256_sqr_mont(S, S);
++	add	%sp,LOCALS+$S,$rp
++
++	ld	[$ap_real],@acc[0]
++	add	%sp,LOCALS+$Zsqr,$bp
++	ld	[$ap_real+4],@acc[1]
++	ld	[$ap_real+8],@acc[2]
++	ld	[$ap_real+12],@acc[3]
++	ld	[$ap_real+16],@acc[4]
++	ld	[$ap_real+20],@acc[5]
++	ld	[$ap_real+24],@acc[6]
++	ld	[$ap_real+28],@acc[7]
++	call	__ecp_nistz256_sub_from	! p256_sub(Zsqr, in_x, Zsqr);
++	add	%sp,LOCALS+$Zsqr,$rp
++
++	add	$ap_real,32,$bp
++	add	$ap_real,64,$ap
++	call	__ecp_nistz256_mul_mont	! p256_mul_mont(tmp0, in_z, in_y);
++	add	%sp,LOCALS+$tmp0,$rp
++
++	call	__ecp_nistz256_mul_by_2	! p256_mul_by_2(res_z, tmp0);
++	add	$rp_real,64,$rp
++
++	add	%sp,LOCALS+$Zsqr,$bp
++	add	%sp,LOCALS+$M,$ap
++	call	__ecp_nistz256_mul_mont	! p256_mul_mont(M, M, Zsqr);
++	add	%sp,LOCALS+$M,$rp
++
++	call	__ecp_nistz256_mul_by_3	! p256_mul_by_3(M, M);
++	add	%sp,LOCALS+$M,$rp
++
++	add	%sp,LOCALS+$S,$bp
++	add	%sp,LOCALS+$S,$ap
++	call	__ecp_nistz256_mul_mont	! p256_sqr_mont(tmp0, S);
++	add	%sp,LOCALS+$tmp0,$rp
++
++	call	__ecp_nistz256_div_by_2	! p256_div_by_2(res_y, tmp0);
++	add	$rp_real,32,$rp
++
++	add	$ap_real,0,$bp
++	add	%sp,LOCALS+$S,$ap
++	call	__ecp_nistz256_mul_mont	! p256_mul_mont(S, S, in_x);
++	add	%sp,LOCALS+$S,$rp
++
++	call	__ecp_nistz256_mul_by_2	! p256_mul_by_2(tmp0, S);
++	add	%sp,LOCALS+$tmp0,$rp
++
++	add	%sp,LOCALS+$M,$bp
++	add	%sp,LOCALS+$M,$ap
++	call	__ecp_nistz256_mul_mont	! p256_sqr_mont(res_x, M);
++	add	$rp_real,0,$rp
++
++	add	%sp,LOCALS+$tmp0,$bp
++	call	__ecp_nistz256_sub_from	! p256_sub(res_x, res_x, tmp0);
++	add	$rp_real,0,$rp
++
++	add	%sp,LOCALS+$S,$bp
++	call	__ecp_nistz256_sub_morf	! p256_sub(S, S, res_x);
++	add	%sp,LOCALS+$S,$rp
++
++	add	%sp,LOCALS+$M,$bp
++	add	%sp,LOCALS+$S,$ap
++	call	__ecp_nistz256_mul_mont	! p256_mul_mont(S, S, M);
++	add	%sp,LOCALS+$S,$rp
++
++	add	$rp_real,32,$bp
++	call	__ecp_nistz256_sub_from	! p256_sub(res_y, S, res_y);
++	add	$rp_real,32,$rp
++
++	ret
++	restore
++.type	ecp_nistz256_point_double,#function
++.size	ecp_nistz256_point_double,.-ecp_nistz256_point_double
++___
++}
++
++########################################################################
++# void ecp_nistz256_point_add(P256_POINT *out,const P256_POINT *in1,
++#			      const P256_POINT *in2);
++{
++my ($res_x,$res_y,$res_z,
++    $H,$Hsqr,$R,$Rsqr,$Hcub,
++    $U1,$U2,$S1,$S2)=map(32*$_,(0..11));
++my ($Z1sqr, $Z2sqr) = ($Hsqr, $Rsqr);
++
++# above map() describes stack layout with 12 temporary
++# 256-bit vectors on top. Then we reserve some space for
++# !in1infty, !in2infty, result of check for zero and return pointer.
++
++my $bp_real=$rp_real;
++
++$code.=<<___;
++.globl	ecp_nistz256_point_add
++.align	32
++ecp_nistz256_point_add:
++	SPARC_LOAD_ADDRESS_LEAF(OPENSSL_sparcv9cap_P,%g1,%g5)
++	ld	[%g1],%g1		! OPENSSL_sparcv9cap_P[0]
++	and	%g1,(SPARCV9_VIS3|SPARCV9_64BIT_STACK),%g1
++	cmp	%g1,(SPARCV9_VIS3|SPARCV9_64BIT_STACK)
++	be	ecp_nistz256_point_add_vis3
++	nop
++
++	save	%sp,-STACK_FRAME-32*12-32,%sp
++
++	stx	$rp,[%fp+STACK_BIAS-8]	! off-load $rp
++	mov	$ap,$ap_real
++	mov	$bp,$bp_real
++
++	ld	[$bp+64],$t0		! in2_z
++	ld	[$bp+64+4],$t1
++	ld	[$bp+64+8],$t2
++	ld	[$bp+64+12],$t3
++	ld	[$bp+64+16],$t4
++	ld	[$bp+64+20],$t5
++	ld	[$bp+64+24],$t6
++	ld	[$bp+64+28],$t7
++	or	$t1,$t0,$t0
++	or	$t3,$t2,$t2
++	or	$t5,$t4,$t4
++	or	$t7,$t6,$t6
++	or	$t2,$t0,$t0
++	or	$t6,$t4,$t4
++	or	$t4,$t0,$t0		! !in2infty
++	movrnz	$t0,-1,$t0
++	st	$t0,[%fp+STACK_BIAS-12]
++
++	ld	[$ap+64],$t0		! in1_z
++	ld	[$ap+64+4],$t1
++	ld	[$ap+64+8],$t2
++	ld	[$ap+64+12],$t3
++	ld	[$ap+64+16],$t4
++	ld	[$ap+64+20],$t5
++	ld	[$ap+64+24],$t6
++	ld	[$ap+64+28],$t7
++	or	$t1,$t0,$t0
++	or	$t3,$t2,$t2
++	or	$t5,$t4,$t4
++	or	$t7,$t6,$t6
++	or	$t2,$t0,$t0
++	or	$t6,$t4,$t4
++	or	$t4,$t0,$t0		! !in1infty
++	movrnz	$t0,-1,$t0
++	st	$t0,[%fp+STACK_BIAS-16]
++
++	add	$bp_real,64,$bp
++	add	$bp_real,64,$ap
++	call	__ecp_nistz256_mul_mont	! p256_sqr_mont(Z2sqr, in2_z);
++	add	%sp,LOCALS+$Z2sqr,$rp
++
++	add	$ap_real,64,$bp
++	add	$ap_real,64,$ap
++	call	__ecp_nistz256_mul_mont	! p256_sqr_mont(Z1sqr, in1_z);
++	add	%sp,LOCALS+$Z1sqr,$rp
++
++	add	$bp_real,64,$bp
++	add	%sp,LOCALS+$Z2sqr,$ap
++	call	__ecp_nistz256_mul_mont	! p256_mul_mont(S1, Z2sqr, in2_z);
++	add	%sp,LOCALS+$S1,$rp
++
++	add	$ap_real,64,$bp
++	add	%sp,LOCALS+$Z1sqr,$ap
++	call	__ecp_nistz256_mul_mont	! p256_mul_mont(S2, Z1sqr, in1_z);
++	add	%sp,LOCALS+$S2,$rp
++
++	add	$ap_real,32,$bp
++	add	%sp,LOCALS+$S1,$ap
++	call	__ecp_nistz256_mul_mont	! p256_mul_mont(S1, S1, in1_y);
++	add	%sp,LOCALS+$S1,$rp
++
++	add	$bp_real,32,$bp
++	add	%sp,LOCALS+$S2,$ap
++	call	__ecp_nistz256_mul_mont	! p256_mul_mont(S2, S2, in2_y);
++	add	%sp,LOCALS+$S2,$rp
++
++	add	%sp,LOCALS+$S1,$bp
++	call	__ecp_nistz256_sub_from	! p256_sub(R, S2, S1);
++	add	%sp,LOCALS+$R,$rp
++
++	or	@acc[1],@acc[0],@acc[0]	! see if result is zero
++	or	@acc[3],@acc[2],@acc[2]
++	or	@acc[5],@acc[4],@acc[4]
++	or	@acc[7],@acc[6],@acc[6]
++	or	@acc[2],@acc[0],@acc[0]
++	or	@acc[6],@acc[4],@acc[4]
++	or	@acc[4],@acc[0],@acc[0]
++	st	@acc[0],[%fp+STACK_BIAS-20]
++
++	add	$ap_real,0,$bp
++	add	%sp,LOCALS+$Z2sqr,$ap
++	call	__ecp_nistz256_mul_mont	! p256_mul_mont(U1, in1_x, Z2sqr);
++	add	%sp,LOCALS+$U1,$rp
++
++	add	$bp_real,0,$bp
++	add	%sp,LOCALS+$Z1sqr,$ap
++	call	__ecp_nistz256_mul_mont	! p256_mul_mont(U2, in2_x, Z1sqr);
++	add	%sp,LOCALS+$U2,$rp
++
++	add	%sp,LOCALS+$U1,$bp
++	call	__ecp_nistz256_sub_from	! p256_sub(H, U2, U1);
++	add	%sp,LOCALS+$H,$rp
++
++	or	@acc[1],@acc[0],@acc[0]	! see if result is zero
++	or	@acc[3],@acc[2],@acc[2]
++	or	@acc[5],@acc[4],@acc[4]
++	or	@acc[7],@acc[6],@acc[6]
++	or	@acc[2],@acc[0],@acc[0]
++	or	@acc[6],@acc[4],@acc[4]
++	orcc	@acc[4],@acc[0],@acc[0]
++
++	bne,pt	%icc,.Ladd_proceed	! is_equal(U1,U2)?
++	nop
++
++	ld	[%fp+STACK_BIAS-12],$t0
++	ld	[%fp+STACK_BIAS-16],$t1
++	ld	[%fp+STACK_BIAS-20],$t2
++	andcc	$t0,$t1,%g0
++	be,pt	%icc,.Ladd_proceed	! (in1infty || in2infty)?
++	nop
++	andcc	$t2,$t2,%g0
++	be,pt	%icc,.Ladd_double	! is_equal(S1,S2)?
++	nop
++
++	ldx	[%fp+STACK_BIAS-8],$rp
++	st	%g0,[$rp]
++	st	%g0,[$rp+4]
++	st	%g0,[$rp+8]
++	st	%g0,[$rp+12]
++	st	%g0,[$rp+16]
++	st	%g0,[$rp+20]
++	st	%g0,[$rp+24]
++	st	%g0,[$rp+28]
++	st	%g0,[$rp+32]
++	st	%g0,[$rp+32+4]
++	st	%g0,[$rp+32+8]
++	st	%g0,[$rp+32+12]
++	st	%g0,[$rp+32+16]
++	st	%g0,[$rp+32+20]
++	st	%g0,[$rp+32+24]
++	st	%g0,[$rp+32+28]
++	st	%g0,[$rp+64]
++	st	%g0,[$rp+64+4]
++	st	%g0,[$rp+64+8]
++	st	%g0,[$rp+64+12]
++	st	%g0,[$rp+64+16]
++	st	%g0,[$rp+64+20]
++	st	%g0,[$rp+64+24]
++	st	%g0,[$rp+64+28]
++	b	.Ladd_done
++	nop
++
++.align	16
++.Ladd_double:
++	ldx	[%fp+STACK_BIAS-8],$rp_real
++	mov	$ap_real,$ap
++	b	.Lpoint_double_shortcut
++	add	%sp,32*(12-4)+32,%sp	! difference in frame sizes
++
++.align	16
++.Ladd_proceed:
++	add	%sp,LOCALS+$R,$bp
++	add	%sp,LOCALS+$R,$ap
++	call	__ecp_nistz256_mul_mont	! p256_sqr_mont(Rsqr, R);
++	add	%sp,LOCALS+$Rsqr,$rp
++
++	add	$ap_real,64,$bp
++	add	%sp,LOCALS+$H,$ap
++	call	__ecp_nistz256_mul_mont	! p256_mul_mont(res_z, H, in1_z);
++	add	%sp,LOCALS+$res_z,$rp
++
++	add	%sp,LOCALS+$H,$bp
++	add	%sp,LOCALS+$H,$ap
++	call	__ecp_nistz256_mul_mont	! p256_sqr_mont(Hsqr, H);
++	add	%sp,LOCALS+$Hsqr,$rp
++
++	add	$bp_real,64,$bp
++	add	%sp,LOCALS+$res_z,$ap
++	call	__ecp_nistz256_mul_mont	! p256_mul_mont(res_z, res_z, in2_z);
++	add	%sp,LOCALS+$res_z,$rp
++
++	add	%sp,LOCALS+$H,$bp
++	add	%sp,LOCALS+$Hsqr,$ap
++	call	__ecp_nistz256_mul_mont	! p256_mul_mont(Hcub, Hsqr, H);
++	add	%sp,LOCALS+$Hcub,$rp
++
++	add	%sp,LOCALS+$U1,$bp
++	add	%sp,LOCALS+$Hsqr,$ap
++	call	__ecp_nistz256_mul_mont	! p256_mul_mont(U2, U1, Hsqr);
++	add	%sp,LOCALS+$U2,$rp
++
++	call	__ecp_nistz256_mul_by_2	! p256_mul_by_2(Hsqr, U2);
++	add	%sp,LOCALS+$Hsqr,$rp
++
++	add	%sp,LOCALS+$Rsqr,$bp
++	call	__ecp_nistz256_sub_morf	! p256_sub(res_x, Rsqr, Hsqr);
++	add	%sp,LOCALS+$res_x,$rp
++
++	add	%sp,LOCALS+$Hcub,$bp
++	call	__ecp_nistz256_sub_from	!  p256_sub(res_x, res_x, Hcub);
++	add	%sp,LOCALS+$res_x,$rp
++
++	add	%sp,LOCALS+$U2,$bp
++	call	__ecp_nistz256_sub_morf	! p256_sub(res_y, U2, res_x);
++	add	%sp,LOCALS+$res_y,$rp
++
++	add	%sp,LOCALS+$Hcub,$bp
++	add	%sp,LOCALS+$S1,$ap
++	call	__ecp_nistz256_mul_mont	! p256_mul_mont(S2, S1, Hcub);
++	add	%sp,LOCALS+$S2,$rp
++
++	add	%sp,LOCALS+$R,$bp
++	add	%sp,LOCALS+$res_y,$ap
++	call	__ecp_nistz256_mul_mont	! p256_mul_mont(res_y, res_y, R);
++	add	%sp,LOCALS+$res_y,$rp
++
++	add	%sp,LOCALS+$S2,$bp
++	call	__ecp_nistz256_sub_from	! p256_sub(res_y, res_y, S2);
++	add	%sp,LOCALS+$res_y,$rp
++
++	ld	[%fp+STACK_BIAS-16],$t1	! !in1infty
++	ld	[%fp+STACK_BIAS-12],$t2	! !in2infty
++	ldx	[%fp+STACK_BIAS-8],$rp
++___
++for($i=0;$i<96;$i+=8) {			# conditional moves
++$code.=<<___;
++	ld	[%sp+LOCALS+$i],@acc[0]		! res
++	ld	[%sp+LOCALS+$i+4],@acc[1]
++	ld	[$bp_real+$i],@acc[2]		! in2
++	ld	[$bp_real+$i+4],@acc[3]
++	ld	[$ap_real+$i],@acc[4]		! in1
++	ld	[$ap_real+$i+4],@acc[5]
++	movrz	$t1,@acc[2],@acc[0]
++	movrz	$t1,@acc[3],@acc[1]
++	movrz	$t2,@acc[4],@acc[0]
++	movrz	$t2,@acc[5],@acc[1]
++	st	@acc[0],[$rp+$i]
++	st	@acc[1],[$rp+$i+4]
++___
++}
++$code.=<<___;
++.Ladd_done:
++	ret
++	restore
++.type	ecp_nistz256_point_add,#function
++.size	ecp_nistz256_point_add,.-ecp_nistz256_point_add
++___
++}
++
++########################################################################
++# void ecp_nistz256_point_add_affine(P256_POINT *out,const P256_POINT *in1,
++#				     const P256_POINT_AFFINE *in2);
++{
++my ($res_x,$res_y,$res_z,
++    $U2,$S2,$H,$R,$Hsqr,$Hcub,$Rsqr)=map(32*$_,(0..9));
++my $Z1sqr = $S2;
++# above map() describes stack layout with 10 temporary
++# 256-bit vectors on top. Then we reserve some space for
++# !in1infty, !in2infty, result of check for zero and return pointer.
++
++my @ONE_mont=(1,0,0,-1,-1,-1,-2,0);
++my $bp_real=$rp_real;
++
++$code.=<<___;
++.globl	ecp_nistz256_point_add_affine
++.align	32
++ecp_nistz256_point_add_affine:
++	SPARC_LOAD_ADDRESS_LEAF(OPENSSL_sparcv9cap_P,%g1,%g5)
++	ld	[%g1],%g1		! OPENSSL_sparcv9cap_P[0]
++	and	%g1,(SPARCV9_VIS3|SPARCV9_64BIT_STACK),%g1
++	cmp	%g1,(SPARCV9_VIS3|SPARCV9_64BIT_STACK)
++	be	ecp_nistz256_point_add_affine_vis3
++	nop
++
++	save	%sp,-STACK_FRAME-32*10-32,%sp
++
++	stx	$rp,[%fp+STACK_BIAS-8]	! off-load $rp
++	mov	$ap,$ap_real
++	mov	$bp,$bp_real
++
++	ld	[$ap+64],$t0		! in1_z
++	ld	[$ap+64+4],$t1
++	ld	[$ap+64+8],$t2
++	ld	[$ap+64+12],$t3
++	ld	[$ap+64+16],$t4
++	ld	[$ap+64+20],$t5
++	ld	[$ap+64+24],$t6
++	ld	[$ap+64+28],$t7
++	or	$t1,$t0,$t0
++	or	$t3,$t2,$t2
++	or	$t5,$t4,$t4
++	or	$t7,$t6,$t6
++	or	$t2,$t0,$t0
++	or	$t6,$t4,$t4
++	or	$t4,$t0,$t0		! !in1infty
++	movrnz	$t0,-1,$t0
++	st	$t0,[%fp+STACK_BIAS-16]
++
++	ld	[$bp],@acc[0]		! in2_x
++	ld	[$bp+4],@acc[1]
++	ld	[$bp+8],@acc[2]
++	ld	[$bp+12],@acc[3]
++	ld	[$bp+16],@acc[4]
++	ld	[$bp+20],@acc[5]
++	ld	[$bp+24],@acc[6]
++	ld	[$bp+28],@acc[7]
++	ld	[$bp+32],$t0		! in2_y
++	ld	[$bp+32+4],$t1
++	ld	[$bp+32+8],$t2
++	ld	[$bp+32+12],$t3
++	ld	[$bp+32+16],$t4
++	ld	[$bp+32+20],$t5
++	ld	[$bp+32+24],$t6
++	ld	[$bp+32+28],$t7
++	or	@acc[1],@acc[0],@acc[0]
++	or	@acc[3],@acc[2],@acc[2]
++	or	@acc[5],@acc[4],@acc[4]
++	or	@acc[7],@acc[6],@acc[6]
++	or	@acc[2],@acc[0],@acc[0]
++	or	@acc[6],@acc[4],@acc[4]
++	or	@acc[4],@acc[0],@acc[0]
++	or	$t1,$t0,$t0
++	or	$t3,$t2,$t2
++	or	$t5,$t4,$t4
++	or	$t7,$t6,$t6
++	or	$t2,$t0,$t0
++	or	$t6,$t4,$t4
++	or	$t4,$t0,$t0
++	or	@acc[0],$t0,$t0		! !in2infty
++	movrnz	$t0,-1,$t0
++	st	$t0,[%fp+STACK_BIAS-12]
++
++	add	$ap_real,64,$bp
++	add	$ap_real,64,$ap
++	call	__ecp_nistz256_mul_mont	! p256_sqr_mont(Z1sqr, in1_z);
++	add	%sp,LOCALS+$Z1sqr,$rp
++
++	add	$bp_real,0,$bp
++	add	%sp,LOCALS+$Z1sqr,$ap
++	call	__ecp_nistz256_mul_mont	! p256_mul_mont(U2, Z1sqr, in2_x);
++	add	%sp,LOCALS+$U2,$rp
++
++	add	$ap_real,0,$bp
++	call	__ecp_nistz256_sub_from	! p256_sub(H, U2, in1_x);
++	add	%sp,LOCALS+$H,$rp
++
++	add	$ap_real,64,$bp
++	add	%sp,LOCALS+$Z1sqr,$ap
++	call	__ecp_nistz256_mul_mont	! p256_mul_mont(S2, Z1sqr, in1_z);
++	add	%sp,LOCALS+$S2,$rp
++
++	add	$ap_real,64,$bp
++	add	%sp,LOCALS+$H,$ap
++	call	__ecp_nistz256_mul_mont	! p256_mul_mont(res_z, H, in1_z);
++	add	%sp,LOCALS+$res_z,$rp
++
++	add	$bp_real,32,$bp
++	add	%sp,LOCALS+$S2,$ap
++	call	__ecp_nistz256_mul_mont	! p256_mul_mont(S2, S2, in2_y);
++	add	%sp,LOCALS+$S2,$rp
++
++	add	$ap_real,32,$bp
++	call	__ecp_nistz256_sub_from	! p256_sub(R, S2, in1_y);
++	add	%sp,LOCALS+$R,$rp
++
++	add	%sp,LOCALS+$H,$bp
++	add	%sp,LOCALS+$H,$ap
++	call	__ecp_nistz256_mul_mont	! p256_sqr_mont(Hsqr, H);
++	add	%sp,LOCALS+$Hsqr,$rp
++
++	add	%sp,LOCALS+$R,$bp
++	add	%sp,LOCALS+$R,$ap
++	call	__ecp_nistz256_mul_mont	! p256_sqr_mont(Rsqr, R);
++	add	%sp,LOCALS+$Rsqr,$rp
++
++	add	%sp,LOCALS+$H,$bp
++	add	%sp,LOCALS+$Hsqr,$ap
++	call	__ecp_nistz256_mul_mont	! p256_mul_mont(Hcub, Hsqr, H);
++	add	%sp,LOCALS+$Hcub,$rp
++
++	add	$ap_real,0,$bp
++	add	%sp,LOCALS+$Hsqr,$ap
++	call	__ecp_nistz256_mul_mont	! p256_mul_mont(U2, in1_x, Hsqr);
++	add	%sp,LOCALS+$U2,$rp
++
++	call	__ecp_nistz256_mul_by_2	! p256_mul_by_2(Hsqr, U2);
++	add	%sp,LOCALS+$Hsqr,$rp
++
++	add	%sp,LOCALS+$Rsqr,$bp
++	call	__ecp_nistz256_sub_morf	! p256_sub(res_x, Rsqr, Hsqr);
++	add	%sp,LOCALS+$res_x,$rp
++
++	add	%sp,LOCALS+$Hcub,$bp
++	call	__ecp_nistz256_sub_from	!  p256_sub(res_x, res_x, Hcub);
++	add	%sp,LOCALS+$res_x,$rp
++
++	add	%sp,LOCALS+$U2,$bp
++	call	__ecp_nistz256_sub_morf	! p256_sub(res_y, U2, res_x);
++	add	%sp,LOCALS+$res_y,$rp
++
++	add	$ap_real,32,$bp
++	add	%sp,LOCALS+$Hcub,$ap
++	call	__ecp_nistz256_mul_mont	! p256_mul_mont(S2, in1_y, Hcub);
++	add	%sp,LOCALS+$S2,$rp
++
++	add	%sp,LOCALS+$R,$bp
++	add	%sp,LOCALS+$res_y,$ap
++	call	__ecp_nistz256_mul_mont	! p256_mul_mont(res_y, res_y, R);
++	add	%sp,LOCALS+$res_y,$rp
++
++	add	%sp,LOCALS+$S2,$bp
++	call	__ecp_nistz256_sub_from	! p256_sub(res_y, res_y, S2);
++	add	%sp,LOCALS+$res_y,$rp
++
++	ld	[%fp+STACK_BIAS-16],$t1	! !in1infty
++	ld	[%fp+STACK_BIAS-12],$t2	! !in2infty
++	ldx	[%fp+STACK_BIAS-8],$rp
++___
++for($i=0;$i<64;$i+=8) {			# conditional moves
++$code.=<<___;
++	ld	[%sp+LOCALS+$i],@acc[0]		! res
++	ld	[%sp+LOCALS+$i+4],@acc[1]
++	ld	[$bp_real+$i],@acc[2]		! in2
++	ld	[$bp_real+$i+4],@acc[3]
++	ld	[$ap_real+$i],@acc[4]		! in1
++	ld	[$ap_real+$i+4],@acc[5]
++	movrz	$t1,@acc[2],@acc[0]
++	movrz	$t1,@acc[3],@acc[1]
++	movrz	$t2,@acc[4],@acc[0]
++	movrz	$t2,@acc[5],@acc[1]
++	st	@acc[0],[$rp+$i]
++	st	@acc[1],[$rp+$i+4]
++___
++}
++for(;$i<96;$i+=8) {
++my $j=($i-64)/4;
++$code.=<<___;
++	ld	[%sp+LOCALS+$i],@acc[0]		! res
++	ld	[%sp+LOCALS+$i+4],@acc[1]
++	ld	[$ap_real+$i],@acc[4]		! in1
++	ld	[$ap_real+$i+4],@acc[5]
++	movrz	$t1,@ONE_mont[$j],@acc[0]
++	movrz	$t1,@ONE_mont[$j+1],@acc[1]
++	movrz	$t2,@acc[4],@acc[0]
++	movrz	$t2,@acc[5],@acc[1]
++	st	@acc[0],[$rp+$i]
++	st	@acc[1],[$rp+$i+4]
++___
++}
++$code.=<<___;
++	ret
++	restore
++.type	ecp_nistz256_point_add_affine,#function
++.size	ecp_nistz256_point_add_affine,.-ecp_nistz256_point_add_affine
++___
++}								}}}
++{{{
++my ($out,$inp,$index)=map("%i$_",(0..2));
++my $mask="%o0";
++
++$code.=<<___;
++! void	ecp_nistz256_scatter_w5(void *%i0,const P256_POINT *%i1,
++!					  int %i2);
++.globl	ecp_nistz256_scatter_w5
++.align	32
++ecp_nistz256_scatter_w5:
++	save	%sp,-STACK_FRAME,%sp
++
++	sll	$index,2,$index
++	add	$out,$index,$out
++
++	ld	[$inp],%l0		! X
++	ld	[$inp+4],%l1
++	ld	[$inp+8],%l2
++	ld	[$inp+12],%l3
++	ld	[$inp+16],%l4
++	ld	[$inp+20],%l5
++	ld	[$inp+24],%l6
++	ld	[$inp+28],%l7
++	add	$inp,32,$inp
++	st	%l0,[$out+64*0-4]
++	st	%l1,[$out+64*1-4]
++	st	%l2,[$out+64*2-4]
++	st	%l3,[$out+64*3-4]
++	st	%l4,[$out+64*4-4]
++	st	%l5,[$out+64*5-4]
++	st	%l6,[$out+64*6-4]
++	st	%l7,[$out+64*7-4]
++	add	$out,64*8,$out
++
++	ld	[$inp],%l0		! Y
++	ld	[$inp+4],%l1
++	ld	[$inp+8],%l2
++	ld	[$inp+12],%l3
++	ld	[$inp+16],%l4
++	ld	[$inp+20],%l5
++	ld	[$inp+24],%l6
++	ld	[$inp+28],%l7
++	add	$inp,32,$inp
++	st	%l0,[$out+64*0-4]
++	st	%l1,[$out+64*1-4]
++	st	%l2,[$out+64*2-4]
++	st	%l3,[$out+64*3-4]
++	st	%l4,[$out+64*4-4]
++	st	%l5,[$out+64*5-4]
++	st	%l6,[$out+64*6-4]
++	st	%l7,[$out+64*7-4]
++	add	$out,64*8,$out
++
++	ld	[$inp],%l0		! Z
++	ld	[$inp+4],%l1
++	ld	[$inp+8],%l2
++	ld	[$inp+12],%l3
++	ld	[$inp+16],%l4
++	ld	[$inp+20],%l5
++	ld	[$inp+24],%l6
++	ld	[$inp+28],%l7
++	st	%l0,[$out+64*0-4]
++	st	%l1,[$out+64*1-4]
++	st	%l2,[$out+64*2-4]
++	st	%l3,[$out+64*3-4]
++	st	%l4,[$out+64*4-4]
++	st	%l5,[$out+64*5-4]
++	st	%l6,[$out+64*6-4]
++	st	%l7,[$out+64*7-4]
++
++	ret
++	restore
++.type	ecp_nistz256_scatter_w5,#function
++.size	ecp_nistz256_scatter_w5,.-ecp_nistz256_scatter_w5
++
++! void	ecp_nistz256_gather_w5(P256_POINT *%i0,const void *%i1,
++!					       int %i2);
++.globl	ecp_nistz256_gather_w5
++.align	32
++ecp_nistz256_gather_w5:
++	save	%sp,-STACK_FRAME,%sp
++
++	neg	$index,$mask
++	srax	$mask,63,$mask
++
++	add	$index,$mask,$index
++	sll	$index,2,$index
++	add	$inp,$index,$inp
++
++	ld	[$inp+64*0],%l0
++	ld	[$inp+64*1],%l1
++	ld	[$inp+64*2],%l2
++	ld	[$inp+64*3],%l3
++	ld	[$inp+64*4],%l4
++	ld	[$inp+64*5],%l5
++	ld	[$inp+64*6],%l6
++	ld	[$inp+64*7],%l7
++	add	$inp,64*8,$inp
++	and	%l0,$mask,%l0
++	and	%l1,$mask,%l1
++	st	%l0,[$out]		! X
++	and	%l2,$mask,%l2
++	st	%l1,[$out+4]
++	and	%l3,$mask,%l3
++	st	%l2,[$out+8]
++	and	%l4,$mask,%l4
++	st	%l3,[$out+12]
++	and	%l5,$mask,%l5
++	st	%l4,[$out+16]
++	and	%l6,$mask,%l6
++	st	%l5,[$out+20]
++	and	%l7,$mask,%l7
++	st	%l6,[$out+24]
++	st	%l7,[$out+28]
++	add	$out,32,$out
++
++	ld	[$inp+64*0],%l0
++	ld	[$inp+64*1],%l1
++	ld	[$inp+64*2],%l2
++	ld	[$inp+64*3],%l3
++	ld	[$inp+64*4],%l4
++	ld	[$inp+64*5],%l5
++	ld	[$inp+64*6],%l6
++	ld	[$inp+64*7],%l7
++	add	$inp,64*8,$inp
++	and	%l0,$mask,%l0
++	and	%l1,$mask,%l1
++	st	%l0,[$out]		! Y
++	and	%l2,$mask,%l2
++	st	%l1,[$out+4]
++	and	%l3,$mask,%l3
++	st	%l2,[$out+8]
++	and	%l4,$mask,%l4
++	st	%l3,[$out+12]
++	and	%l5,$mask,%l5
++	st	%l4,[$out+16]
++	and	%l6,$mask,%l6
++	st	%l5,[$out+20]
++	and	%l7,$mask,%l7
++	st	%l6,[$out+24]
++	st	%l7,[$out+28]
++	add	$out,32,$out
++
++	ld	[$inp+64*0],%l0
++	ld	[$inp+64*1],%l1
++	ld	[$inp+64*2],%l2
++	ld	[$inp+64*3],%l3
++	ld	[$inp+64*4],%l4
++	ld	[$inp+64*5],%l5
++	ld	[$inp+64*6],%l6
++	ld	[$inp+64*7],%l7
++	and	%l0,$mask,%l0
++	and	%l1,$mask,%l1
++	st	%l0,[$out]		! Z
++	and	%l2,$mask,%l2
++	st	%l1,[$out+4]
++	and	%l3,$mask,%l3
++	st	%l2,[$out+8]
++	and	%l4,$mask,%l4
++	st	%l3,[$out+12]
++	and	%l5,$mask,%l5
++	st	%l4,[$out+16]
++	and	%l6,$mask,%l6
++	st	%l5,[$out+20]
++	and	%l7,$mask,%l7
++	st	%l6,[$out+24]
++	st	%l7,[$out+28]
++
++	ret
++	restore
++.type	ecp_nistz256_gather_w5,#function
++.size	ecp_nistz256_gather_w5,.-ecp_nistz256_gather_w5
++
++! void	ecp_nistz256_scatter_w7(void *%i0,const P256_POINT_AFFINE *%i1,
++!					  int %i2);
++.globl	ecp_nistz256_scatter_w7
++.align	32
++ecp_nistz256_scatter_w7:
++	save	%sp,-STACK_FRAME,%sp
++	nop
++	add	$out,$index,$out
++	mov	64/4,$index
++.Loop_scatter_w7:
++	ld	[$inp],%l0
++	add	$inp,4,$inp
++	subcc	$index,1,$index
++	stb	%l0,[$out+64*0-1]
++	srl	%l0,8,%l1
++	stb	%l1,[$out+64*1-1]
++	srl	%l0,16,%l2
++	stb	%l2,[$out+64*2-1]
++	srl	%l0,24,%l3
++	stb	%l3,[$out+64*3-1]
++	bne	.Loop_scatter_w7
++	add	$out,64*4,$out
++
++	ret
++	restore
++.type	ecp_nistz256_scatter_w7,#function
++.size	ecp_nistz256_scatter_w7,.-ecp_nistz256_scatter_w7
++
++! void	ecp_nistz256_gather_w7(P256_POINT_AFFINE *%i0,const void *%i1,
++!						      int %i2);
++.globl	ecp_nistz256_gather_w7
++.align	32
++ecp_nistz256_gather_w7:
++	save	%sp,-STACK_FRAME,%sp
++
++	neg	$index,$mask
++	srax	$mask,63,$mask
++
++	add	$index,$mask,$index
++	add	$inp,$index,$inp
++	mov	64/4,$index
++
++.Loop_gather_w7:
++	ldub	[$inp+64*0],%l0
++	prefetch [$inp+3840+64*0],1
++	subcc	$index,1,$index
++	ldub	[$inp+64*1],%l1
++	prefetch [$inp+3840+64*1],1
++	ldub	[$inp+64*2],%l2
++	prefetch [$inp+3840+64*2],1
++	ldub	[$inp+64*3],%l3
++	prefetch [$inp+3840+64*3],1
++	add	$inp,64*4,$inp
++	sll	%l1,8,%l1
++	sll	%l2,16,%l2
++	or	%l0,%l1,%l0
++	sll	%l3,24,%l3
++	or	%l0,%l2,%l0
++	or	%l0,%l3,%l0
++	and	%l0,$mask,%l0
++	st	%l0,[$out]
++	bne	.Loop_gather_w7
++	add	$out,4,$out
++
++	ret
++	restore
++.type	ecp_nistz256_gather_w7,#function
++.size	ecp_nistz256_gather_w7,.-ecp_nistz256_gather_w7
++___
++}}}
++{{{
++########################################################################
++# Following subroutines are VIS3 counterparts of those above that
++# implement ones found in ecp_nistz256.c. Key difference is that they
++# use 128-bit muliplication and addition with 64-bit carry, and in order
++# to do that they perform conversion from uin32_t[8] to uint64_t[4] upon
++# entry and vice versa on return.
++#
++my ($rp,$ap,$bp)=map("%i$_",(0..2));
++my ($t0,$t1,$t2,$t3,$a0,$a1,$a2,$a3)=map("%l$_",(0..7));
++my ($acc0,$acc1,$acc2,$acc3,$acc4,$acc5)=map("%o$_",(0..5));
++my ($bi,$poly1,$poly3,$minus1)=(map("%i$_",(3..5)),"%g1");
++my ($rp_real,$ap_real)=("%g2","%g3");
++my ($acc6,$acc7)=($bp,$bi);	# used in squaring
++
++$code.=<<___;
++.align	32
++__ecp_nistz256_mul_by_2_vis3:
++	addcc	$acc0,$acc0,$acc0
++	addxccc	$acc1,$acc1,$acc1
++	addxccc	$acc2,$acc2,$acc2
++	addxccc	$acc3,$acc3,$acc3
++	b	.Lreduce_by_sub_vis3
++	addxc	%g0,%g0,$acc4		! did it carry?
++.type	__ecp_nistz256_mul_by_2_vis3,#function
++.size	__ecp_nistz256_mul_by_2_vis3,.-__ecp_nistz256_mul_by_2_vis3
++
++.align	32
++__ecp_nistz256_add_vis3:
++	ldx	[$bp+0],$t0
++	ldx	[$bp+8],$t1
++	ldx	[$bp+16],$t2
++	ldx	[$bp+24],$t3
++
++__ecp_nistz256_add_noload_vis3:
++
++	addcc	$t0,$acc0,$acc0
++	addxccc	$t1,$acc1,$acc1
++	addxccc	$t2,$acc2,$acc2
++	addxccc	$t3,$acc3,$acc3
++	addxc	%g0,%g0,$acc4		! did it carry?
++
++.Lreduce_by_sub_vis3:
++
++	addcc	$acc0,1,$t0		! add -modulus, i.e. subtract
++	addxccc	$acc1,$poly1,$t1
++	addxccc	$acc2,$minus1,$t2
++	addxccc	$acc3,$poly3,$t3
++	addxc	$acc4,$minus1,$acc4
++
++	movrz	$acc4,$t0,$acc0		! ret = borrow ? ret : ret-modulus
++	movrz	$acc4,$t1,$acc1
++	stx	$acc0,[$rp]
++	movrz	$acc4,$t2,$acc2
++	stx	$acc1,[$rp+8]
++	movrz	$acc4,$t3,$acc3
++	stx	$acc2,[$rp+16]
++	retl
++	stx	$acc3,[$rp+24]
++.type	__ecp_nistz256_add_vis3,#function
++.size	__ecp_nistz256_add_vis3,.-__ecp_nistz256_add_vis3
++
++! Trouble with subtraction is that there is no subtraction with 64-bit
++! borrow, only with 32-bit one. For this reason we "decompose" 64-bit
++! $acc0-$acc3 to 32-bit values and pick b[4] in 32-bit pieces. But
++! recall that SPARC is big-endian, which is why you'll observe that
++! b[4] is accessed as 4-0-12-8-20-16-28-24. And prior reduction we
++! "collect" result back to 64-bit $acc0-$acc3.
++.align	32
++__ecp_nistz256_sub_from_vis3:
++	ld	[$bp+4],$t0
++	ld	[$bp+0],$t1
++	ld	[$bp+12],$t2
++	ld	[$bp+8],$t3
++
++	srlx	$acc0,32,$acc4
++	not	$poly1,$poly1
++	srlx	$acc1,32,$acc5
++	subcc	$acc0,$t0,$acc0
++	ld	[$bp+20],$t0
++	subccc	$acc4,$t1,$acc4
++	ld	[$bp+16],$t1
++	subccc	$acc1,$t2,$acc1
++	ld	[$bp+28],$t2
++	and	$acc0,$poly1,$acc0
++	subccc	$acc5,$t3,$acc5
++	ld	[$bp+24],$t3
++	sllx	$acc4,32,$acc4
++	and	$acc1,$poly1,$acc1
++	sllx	$acc5,32,$acc5
++	or	$acc0,$acc4,$acc0
++	srlx	$acc2,32,$acc4
++	or	$acc1,$acc5,$acc1
++	srlx	$acc3,32,$acc5
++	subccc	$acc2,$t0,$acc2
++	subccc	$acc4,$t1,$acc4
++	subccc	$acc3,$t2,$acc3
++	and	$acc2,$poly1,$acc2
++	subccc	$acc5,$t3,$acc5
++	sllx	$acc4,32,$acc4
++	and	$acc3,$poly1,$acc3
++	sllx	$acc5,32,$acc5
++	or	$acc2,$acc4,$acc2
++	subc	%g0,%g0,$acc4		! did it borrow?
++	b	.Lreduce_by_add_vis3
++	or	$acc3,$acc5,$acc3
++.type	__ecp_nistz256_sub_from_vis3,#function
++.size	__ecp_nistz256_sub_from_vis3,.-__ecp_nistz256_sub_from_vis3
++
++.align	32
++__ecp_nistz256_sub_morf_vis3:
++	ld	[$bp+4],$t0
++	ld	[$bp+0],$t1
++	ld	[$bp+12],$t2
++	ld	[$bp+8],$t3
++
++	srlx	$acc0,32,$acc4
++	not	$poly1,$poly1
++	srlx	$acc1,32,$acc5
++	subcc	$t0,$acc0,$acc0
++	ld	[$bp+20],$t0
++	subccc	$t1,$acc4,$acc4
++	ld	[$bp+16],$t1
++	subccc	$t2,$acc1,$acc1
++	ld	[$bp+28],$t2
++	and	$acc0,$poly1,$acc0
++	subccc	$t3,$acc5,$acc5
++	ld	[$bp+24],$t3
++	sllx	$acc4,32,$acc4
++	and	$acc1,$poly1,$acc1
++	sllx	$acc5,32,$acc5
++	or	$acc0,$acc4,$acc0
++	srlx	$acc2,32,$acc4
++	or	$acc1,$acc5,$acc1
++	srlx	$acc3,32,$acc5
++	subccc	$t0,$acc2,$acc2
++	subccc	$t1,$acc4,$acc4
++	subccc	$t2,$acc3,$acc3
++	and	$acc2,$poly1,$acc2
++	subccc	$t3,$acc5,$acc5
++	sllx	$acc4,32,$acc4
++	and	$acc3,$poly1,$acc3
++	sllx	$acc5,32,$acc5
++	or	$acc2,$acc4,$acc2
++	subc	%g0,%g0,$acc4		! did it borrow?
++	or	$acc3,$acc5,$acc3
++
++.Lreduce_by_add_vis3:
++
++	addcc	$acc0,-1,$t0		! add modulus
++	not	$poly3,$t3
++	addxccc	$acc1,$poly1,$t1
++	not	$poly1,$poly1		! restore $poly1
++	addxccc	$acc2,%g0,$t2
++	addxc	$acc3,$t3,$t3
++
++	movrnz	$acc4,$t0,$acc0		! if a-b borrowed, ret = ret+mod
++	movrnz	$acc4,$t1,$acc1
++	stx	$acc0,[$rp]
++	movrnz	$acc4,$t2,$acc2
++	stx	$acc1,[$rp+8]
++	movrnz	$acc4,$t3,$acc3
++	stx	$acc2,[$rp+16]
++	retl
++	stx	$acc3,[$rp+24]
++.type	__ecp_nistz256_sub_morf_vis3,#function
++.size	__ecp_nistz256_sub_morf_vis3,.-__ecp_nistz256_sub_morf_vis3
++
++.align	32
++__ecp_nistz256_div_by_2_vis3:
++	! ret = (a is odd ? a+mod : a) >> 1
++
++	not	$poly1,$t1
++	not	$poly3,$t3
++	and	$acc0,1,$acc5
++	addcc	$acc0,-1,$t0		! add modulus
++	addxccc	$acc1,$t1,$t1
++	addxccc	$acc2,%g0,$t2
++	addxccc	$acc3,$t3,$t3
++	addxc	%g0,%g0,$acc4		! carry bit
++
++	movrnz	$acc5,$t0,$acc0
++	movrnz	$acc5,$t1,$acc1
++	movrnz	$acc5,$t2,$acc2
++	movrnz	$acc5,$t3,$acc3
++	movrz	$acc5,%g0,$acc4
++
++	! ret >>= 1
++
++	srlx	$acc0,1,$acc0
++	sllx	$acc1,63,$t0
++	srlx	$acc1,1,$acc1
++	or	$acc0,$t0,$acc0
++	sllx	$acc2,63,$t1
++	srlx	$acc2,1,$acc2
++	or	$acc1,$t1,$acc1
++	sllx	$acc3,63,$t2
++	stx	$acc0,[$rp]
++	srlx	$acc3,1,$acc3
++	or	$acc2,$t2,$acc2
++	sllx	$acc4,63,$t3		! don't forget carry bit
++	stx	$acc1,[$rp+8]
++	or	$acc3,$t3,$acc3
++	stx	$acc2,[$rp+16]
++	retl
++	stx	$acc3,[$rp+24]
++.type	__ecp_nistz256_div_by_2_vis3,#function
++.size	__ecp_nistz256_div_by_2_vis3,.-__ecp_nistz256_div_by_2_vis3
++
++! compared to __ecp_nistz256_mul_mont it's almost 4x smaller and
++! 4x faster [on T4]...
++.align	32
++__ecp_nistz256_mul_mont_vis3:
++	mulx	$a0,$bi,$acc0
++	not	$poly3,$poly3		! 0xFFFFFFFF00000001
++	umulxhi	$a0,$bi,$t0
++	mulx	$a1,$bi,$acc1
++	umulxhi	$a1,$bi,$t1
++	mulx	$a2,$bi,$acc2
++	umulxhi	$a2,$bi,$t2
++	mulx	$a3,$bi,$acc3
++	umulxhi	$a3,$bi,$t3
++	ldx	[$bp+8],$bi		! b[1]
++
++	addcc	$acc1,$t0,$acc1		! accumulate high parts of multiplication
++	 sllx	$acc0,32,$t0
++	addxccc	$acc2,$t1,$acc2
++	 srlx	$acc0,32,$t1
++	addxccc	$acc3,$t2,$acc3
++	addxc	%g0,$t3,$acc4
++	mov	0,$acc5
++___
++for($i=1;$i<4;$i++) {
++	# Reduction iteration is normally performed by accumulating
++	# result of multiplication of modulus by "magic" digit [and
++	# omitting least significant word, which is guaranteed to
++	# be 0], but thanks to special form of modulus and "magic"
++	# digit being equal to least significant word, it can be
++	# performed with additions and subtractions alone. Indeed:
++	#
++	#            ffff0001.00000000.0000ffff.ffffffff
++	# *                                     abcdefgh
++	# + xxxxxxxx.xxxxxxxx.xxxxxxxx.xxxxxxxx.abcdefgh
++	#
++	# Now observing that ff..ff*x = (2^n-1)*x = 2^n*x-x, we
++	# rewrite above as:
++	#
++	#   xxxxxxxx.xxxxxxxx.xxxxxxxx.xxxxxxxx.abcdefgh
++	# + abcdefgh.abcdefgh.0000abcd.efgh0000.00000000
++	# - 0000abcd.efgh0000.00000000.00000000.abcdefgh
++	#
++	# or marking redundant operations:
++	#
++	#   xxxxxxxx.xxxxxxxx.xxxxxxxx.xxxxxxxx.--------
++	# + abcdefgh.abcdefgh.0000abcd.efgh0000.--------
++	# - 0000abcd.efgh0000.--------.--------.--------
++	#   ^^^^^^^^ but this word is calculated with umulxhi, because
++	#            there is no subtract with 64-bit borrow:-(
++
++$code.=<<___;
++	sub	$acc0,$t0,$t2		! acc0*0xFFFFFFFF00000001, low part
++	umulxhi	$acc0,$poly3,$t3	! acc0*0xFFFFFFFF00000001, high part
++	addcc	$acc1,$t0,$acc0		! +=acc[0]<<96 and omit acc[0]
++	mulx	$a0,$bi,$t0
++	addxccc	$acc2,$t1,$acc1
++	mulx	$a1,$bi,$t1
++	addxccc	$acc3,$t2,$acc2		! +=acc[0]*0xFFFFFFFF00000001
++	mulx	$a2,$bi,$t2
++	addxccc	$acc4,$t3,$acc3
++	mulx	$a3,$bi,$t3
++	addxc	$acc5,%g0,$acc4
++
++	addcc	$acc0,$t0,$acc0		! accumulate low parts of multiplication
++	umulxhi	$a0,$bi,$t0
++	addxccc	$acc1,$t1,$acc1
++	umulxhi	$a1,$bi,$t1
++	addxccc	$acc2,$t2,$acc2
++	umulxhi	$a2,$bi,$t2
++	addxccc	$acc3,$t3,$acc3
++	umulxhi	$a3,$bi,$t3
++	addxc	$acc4,%g0,$acc4
++___
++$code.=<<___	if ($i<3);
++	ldx	[$bp+8*($i+1)],$bi	! bp[$i+1]
++___
++$code.=<<___;
++	addcc	$acc1,$t0,$acc1		! accumulate high parts of multiplication 
++	 sllx	$acc0,32,$t0
++	addxccc	$acc2,$t1,$acc2
++	 srlx	$acc0,32,$t1
++	addxccc	$acc3,$t2,$acc3
++	addxccc	$acc4,$t3,$acc4
++	addxc	%g0,%g0,$acc5
++___
++}
++$code.=<<___;
++	sub	$acc0,$t0,$t2		! acc0*0xFFFFFFFF00000001, low part
++	umulxhi	$acc0,$poly3,$t3	! acc0*0xFFFFFFFF00000001, high part
++	addcc	$acc1,$t0,$acc0		! +=acc[0]<<96 and omit acc[0]
++	addxccc	$acc2,$t1,$acc1
++	addxccc	$acc3,$t2,$acc2		! +=acc[0]*0xFFFFFFFF00000001
++	addxccc	$acc4,$t3,$acc3
++	b	.Lmul_final_vis3	! see below
++	addxc	$acc5,%g0,$acc4
++.type	__ecp_nistz256_mul_mont_vis3,#function
++.size	__ecp_nistz256_mul_mont_vis3,.-__ecp_nistz256_mul_mont_vis3
++
++! compared to above __ecp_nistz256_mul_mont_vis3 it's 21% less
++! instructions, but only 14% faster [on T4]...
++.align	32
++__ecp_nistz256_sqr_mont_vis3:
++	!  |  |  |  |  |  |a1*a0|  |
++	!  |  |  |  |  |a2*a0|  |  |
++	!  |  |a3*a2|a3*a0|  |  |  |
++	!  |  |  |  |a2*a1|  |  |  |
++	!  |  |  |a3*a1|  |  |  |  |
++	! *|  |  |  |  |  |  |  | 2|
++	! +|a3*a3|a2*a2|a1*a1|a0*a0|
++	!  |--+--+--+--+--+--+--+--|
++	!  |A7|A6|A5|A4|A3|A2|A1|A0|, where Ax is $accx, i.e. follow $accx
++	!
++	!  "can't overflow" below mark carrying into high part of
++	!  multiplication result, which can't overflow, because it
++	!  can never be all ones.
++
++	mulx	$a1,$a0,$acc1		! a[1]*a[0]
++	umulxhi	$a1,$a0,$t1
++	mulx	$a2,$a0,$acc2		! a[2]*a[0]
++	umulxhi	$a2,$a0,$t2
++	mulx	$a3,$a0,$acc3		! a[3]*a[0]
++	umulxhi	$a3,$a0,$acc4
++
++	addcc	$acc2,$t1,$acc2		! accumulate high parts of multiplication
++	mulx	$a2,$a1,$t0		! a[2]*a[1]
++	umulxhi	$a2,$a1,$t1
++	addxccc	$acc3,$t2,$acc3
++	mulx	$a3,$a1,$t2		! a[3]*a[1]
++	umulxhi	$a3,$a1,$t3
++	addxc	$acc4,%g0,$acc4		! can't overflow
++
++	mulx	$a3,$a2,$acc5		! a[3]*a[2]
++	not	$poly3,$poly3		! 0xFFFFFFFF00000001
++	umulxhi	$a3,$a2,$acc6
++
++	addcc	$t2,$t1,$t1		! accumulate high parts of multiplication
++	mulx	$a0,$a0,$acc0		! a[0]*a[0]
++	addxc	$t3,%g0,$t2		! can't overflow
++
++	addcc	$acc3,$t0,$acc3		! accumulate low parts of multiplication
++	umulxhi	$a0,$a0,$a0
++	addxccc	$acc4,$t1,$acc4
++	mulx	$a1,$a1,$t1		! a[1]*a[1]
++	addxccc	$acc5,$t2,$acc5
++	umulxhi	$a1,$a1,$a1
++	addxc	$acc6,%g0,$acc6		! can't overflow
++
++	addcc	$acc1,$acc1,$acc1	! acc[1-6]*=2
++	mulx	$a2,$a2,$t2		! a[2]*a[2]
++	addxccc	$acc2,$acc2,$acc2
++	umulxhi	$a2,$a2,$a2
++	addxccc	$acc3,$acc3,$acc3
++	mulx	$a3,$a3,$t3		! a[3]*a[3]
++	addxccc	$acc4,$acc4,$acc4
++	umulxhi	$a3,$a3,$a3
++	addxccc	$acc5,$acc5,$acc5
++	addxccc	$acc6,$acc6,$acc6
++	addxc	%g0,%g0,$acc7
++
++	addcc	$acc1,$a0,$acc1		! +a[i]*a[i]
++	addxccc	$acc2,$t1,$acc2
++	addxccc	$acc3,$a1,$acc3
++	addxccc	$acc4,$t2,$acc4
++	 sllx	$acc0,32,$t0
++	addxccc	$acc5,$a2,$acc5
++	 srlx	$acc0,32,$t1
++	addxccc	$acc6,$t3,$acc6
++	 sub	$acc0,$t0,$t2		! acc0*0xFFFFFFFF00000001, low part
++	addxc	$acc7,$a3,$acc7
++___
++for($i=0;$i<3;$i++) {			# reductions, see commentary
++					# in multiplication for details
++$code.=<<___;
++	umulxhi	$acc0,$poly3,$t3	! acc0*0xFFFFFFFF00000001, high part
++	addcc	$acc1,$t0,$acc0		! +=acc[0]<<96 and omit acc[0]
++	 sllx	$acc0,32,$t0
++	addxccc	$acc2,$t1,$acc1
++	 srlx	$acc0,32,$t1
++	addxccc	$acc3,$t2,$acc2		! +=acc[0]*0xFFFFFFFF00000001
++	 sub	$acc0,$t0,$t2		! acc0*0xFFFFFFFF00000001, low part
++	addxc	%g0,$t3,$acc3		! cant't overflow
++___
++}
++$code.=<<___;
++	umulxhi	$acc0,$poly3,$t3	! acc0*0xFFFFFFFF00000001, high part
++	addcc	$acc1,$t0,$acc0		! +=acc[0]<<96 and omit acc[0]
++	addxccc	$acc2,$t1,$acc1
++	addxccc	$acc3,$t2,$acc2		! +=acc[0]*0xFFFFFFFF00000001
++	addxc	%g0,$t3,$acc3		! can't overflow
++
++	addcc	$acc0,$acc4,$acc0	! accumulate upper half
++	addxccc	$acc1,$acc5,$acc1
++	addxccc	$acc2,$acc6,$acc2
++	addxccc	$acc3,$acc7,$acc3
++	addxc	%g0,%g0,$acc4
++
++.Lmul_final_vis3:
++
++	! Final step is "if result > mod, subtract mod", but as comparison
++	! means subtraction, we do the subtraction and then copy outcome
++	! if it didn't borrow. But note that as we [have to] replace
++	! subtraction with addition with negative, carry/borrow logic is
++	! inverse.
++
++	addcc	$acc0,1,$t0		! add -modulus, i.e. subtract
++	not	$poly3,$poly3		! restore 0x00000000FFFFFFFE
++	addxccc	$acc1,$poly1,$t1
++	addxccc	$acc2,$minus1,$t2
++	addxccc	$acc3,$poly3,$t3
++	addxccc	$acc4,$minus1,%g0	! did it carry?
++
++	movcs	%xcc,$t0,$acc0
++	movcs	%xcc,$t1,$acc1
++	stx	$acc0,[$rp]
++	movcs	%xcc,$t2,$acc2
++	stx	$acc1,[$rp+8]
++	movcs	%xcc,$t3,$acc3
++	stx	$acc2,[$rp+16]
++	retl
++	stx	$acc3,[$rp+24]
++.type	__ecp_nistz256_sqr_mont_vis3,#function
++.size	__ecp_nistz256_sqr_mont_vis3,.-__ecp_nistz256_sqr_mont_vis3
++___
++
++########################################################################
++# void ecp_nistz256_point_double(P256_POINT *out,const P256_POINT *inp);
++#
++{
++my ($res_x,$res_y,$res_z,
++    $in_x,$in_y,$in_z,
++    $S,$M,$Zsqr,$tmp0)=map(32*$_,(0..9));
++# above map() describes stack layout with 10 temporary
++# 256-bit vectors on top.
++
++$code.=<<___;
++.align	32
++ecp_nistz256_point_double_vis3:
++	save	%sp,-STACK64_FRAME-32*10,%sp
++
++	mov	$rp,$rp_real
++.Ldouble_shortcut_vis3:
++	mov	-1,$minus1
++	mov	-2,$poly3
++	sllx	$minus1,32,$poly1		! 0xFFFFFFFF00000000
++	srl	$poly3,0,$poly3			! 0x00000000FFFFFFFE
++
++	! convert input to uint64_t[4]
++	ld	[$ap],$a0			! in_x
++	ld	[$ap+4],$t0
++	ld	[$ap+8],$a1
++	ld	[$ap+12],$t1
++	ld	[$ap+16],$a2
++	ld	[$ap+20],$t2
++	ld	[$ap+24],$a3
++	ld	[$ap+28],$t3
++	sllx	$t0,32,$t0
++	sllx	$t1,32,$t1
++	ld	[$ap+32],$acc0			! in_y
++	or	$a0,$t0,$a0
++	ld	[$ap+32+4],$t0
++	sllx	$t2,32,$t2
++	ld	[$ap+32+8],$acc1
++	or	$a1,$t1,$a1
++	ld	[$ap+32+12],$t1
++	sllx	$t3,32,$t3
++	ld	[$ap+32+16],$acc2
++	or	$a2,$t2,$a2
++	ld	[$ap+32+20],$t2
++	or	$a3,$t3,$a3
++	ld	[$ap+32+24],$acc3
++	sllx	$t0,32,$t0
++	ld	[$ap+32+28],$t3
++	sllx	$t1,32,$t1
++	stx	$a0,[%sp+LOCALS64+$in_x]
++	sllx	$t2,32,$t2
++	stx	$a1,[%sp+LOCALS64+$in_x+8]
++	sllx	$t3,32,$t3
++	stx	$a2,[%sp+LOCALS64+$in_x+16]
++	or	$acc0,$t0,$acc0
++	stx	$a3,[%sp+LOCALS64+$in_x+24]
++	or	$acc1,$t1,$acc1
++	stx	$acc0,[%sp+LOCALS64+$in_y]
++	or	$acc2,$t2,$acc2
++	stx	$acc1,[%sp+LOCALS64+$in_y+8]
++	or	$acc3,$t3,$acc3
++	stx	$acc2,[%sp+LOCALS64+$in_y+16]
++	stx	$acc3,[%sp+LOCALS64+$in_y+24]
++
++	ld	[$ap+64],$a0			! in_z
++	ld	[$ap+64+4],$t0
++	ld	[$ap+64+8],$a1
++	ld	[$ap+64+12],$t1
++	ld	[$ap+64+16],$a2
++	ld	[$ap+64+20],$t2
++	ld	[$ap+64+24],$a3
++	ld	[$ap+64+28],$t3
++	sllx	$t0,32,$t0
++	sllx	$t1,32,$t1
++	or	$a0,$t0,$a0
++	sllx	$t2,32,$t2
++	or	$a1,$t1,$a1
++	sllx	$t3,32,$t3
++	or	$a2,$t2,$a2
++	or	$a3,$t3,$a3
++	sllx	$t0,32,$t0
++	sllx	$t1,32,$t1
++	stx	$a0,[%sp+LOCALS64+$in_z]
++	sllx	$t2,32,$t2
++	stx	$a1,[%sp+LOCALS64+$in_z+8]
++	sllx	$t3,32,$t3
++	stx	$a2,[%sp+LOCALS64+$in_z+16]
++	stx	$a3,[%sp+LOCALS64+$in_z+24]
++
++	! in_y is still in $acc0-$acc3
++	call	__ecp_nistz256_mul_by_2_vis3	! p256_mul_by_2(S, in_y);
++	add	%sp,LOCALS64+$S,$rp
++
++	! in_z is still in $a0-$a3
++	call	__ecp_nistz256_sqr_mont_vis3	! p256_sqr_mont(Zsqr, in_z);
++	add	%sp,LOCALS64+$Zsqr,$rp
++
++	mov	$acc0,$a0			! put Zsqr aside
++	mov	$acc1,$a1
++	mov	$acc2,$a2
++	mov	$acc3,$a3
++
++	add	%sp,LOCALS64+$in_x,$bp
++	call	__ecp_nistz256_add_vis3		! p256_add(M, Zsqr, in_x);
++	add	%sp,LOCALS64+$M,$rp
++
++	mov	$a0,$acc0			! restore Zsqr
++	ldx	[%sp+LOCALS64+$S],$a0		! forward load
++	mov	$a1,$acc1
++	ldx	[%sp+LOCALS64+$S+8],$a1
++	mov	$a2,$acc2
++	ldx	[%sp+LOCALS64+$S+16],$a2
++	mov	$a3,$acc3
++	ldx	[%sp+LOCALS64+$S+24],$a3
++
++	add	%sp,LOCALS64+$in_x,$bp
++	call	__ecp_nistz256_sub_morf_vis3	! p256_sub(Zsqr, in_x, Zsqr);
++	add	%sp,LOCALS64+$Zsqr,$rp
++
++	call	__ecp_nistz256_sqr_mont_vis3	! p256_sqr_mont(S, S);
++	add	%sp,LOCALS64+$S,$rp
++
++	ldx	[%sp+LOCALS64+$in_z],$bi
++	ldx	[%sp+LOCALS64+$in_y],$a0
++	ldx	[%sp+LOCALS64+$in_y+8],$a1
++	ldx	[%sp+LOCALS64+$in_y+16],$a2
++	ldx	[%sp+LOCALS64+$in_y+24],$a3
++	add	%sp,LOCALS64+$in_z,$bp
++	call	__ecp_nistz256_mul_mont_vis3	! p256_mul_mont(tmp0, in_z, in_y);
++	add	%sp,LOCALS64+$tmp0,$rp
++
++	ldx	[%sp+LOCALS64+$M],$bi		! forward load
++	ldx	[%sp+LOCALS64+$Zsqr],$a0
++	ldx	[%sp+LOCALS64+$Zsqr+8],$a1
++	ldx	[%sp+LOCALS64+$Zsqr+16],$a2
++	ldx	[%sp+LOCALS64+$Zsqr+24],$a3
++
++	call	__ecp_nistz256_mul_by_2_vis3	! p256_mul_by_2(res_z, tmp0);
++	add	%sp,LOCALS64+$res_z,$rp
++
++	add	%sp,LOCALS64+$M,$bp
++	call	__ecp_nistz256_mul_mont_vis3	! p256_mul_mont(M, M, Zsqr);
++	add	%sp,LOCALS64+$M,$rp
++
++	mov	$acc0,$a0			! put aside M
++	mov	$acc1,$a1
++	mov	$acc2,$a2
++	mov	$acc3,$a3
++	call	__ecp_nistz256_mul_by_2_vis3
++	add	%sp,LOCALS64+$M,$rp
++	mov	$a0,$t0				! copy M
++	ldx	[%sp+LOCALS64+$S],$a0		! forward load
++	mov	$a1,$t1
++	ldx	[%sp+LOCALS64+$S+8],$a1
++	mov	$a2,$t2
++	ldx	[%sp+LOCALS64+$S+16],$a2
++	mov	$a3,$t3
++	ldx	[%sp+LOCALS64+$S+24],$a3
++	call	__ecp_nistz256_add_noload_vis3	! p256_mul_by_3(M, M);
++	add	%sp,LOCALS64+$M,$rp
++
++	call	__ecp_nistz256_sqr_mont_vis3	! p256_sqr_mont(tmp0, S);
++	add	%sp,LOCALS64+$tmp0,$rp
++
++	ldx	[%sp+LOCALS64+$S],$bi		! forward load
++	ldx	[%sp+LOCALS64+$in_x],$a0
++	ldx	[%sp+LOCALS64+$in_x+8],$a1
++	ldx	[%sp+LOCALS64+$in_x+16],$a2
++	ldx	[%sp+LOCALS64+$in_x+24],$a3
++
++	call	__ecp_nistz256_div_by_2_vis3	! p256_div_by_2(res_y, tmp0);
++	add	%sp,LOCALS64+$res_y,$rp
++
++	add	%sp,LOCALS64+$S,$bp
++	call	__ecp_nistz256_mul_mont_vis3	! p256_mul_mont(S, S, in_x);
++	add	%sp,LOCALS64+$S,$rp
++
++	ldx	[%sp+LOCALS64+$M],$a0		! forward load
++	ldx	[%sp+LOCALS64+$M+8],$a1
++	ldx	[%sp+LOCALS64+$M+16],$a2
++	ldx	[%sp+LOCALS64+$M+24],$a3
++
++	call	__ecp_nistz256_mul_by_2_vis3	! p256_mul_by_2(tmp0, S);
++	add	%sp,LOCALS64+$tmp0,$rp
++
++	call	__ecp_nistz256_sqr_mont_vis3	! p256_sqr_mont(res_x, M);
++	add	%sp,LOCALS64+$res_x,$rp
++
++	add	%sp,LOCALS64+$tmp0,$bp
++	call	__ecp_nistz256_sub_from_vis3	! p256_sub(res_x, res_x, tmp0);
++	add	%sp,LOCALS64+$res_x,$rp
++
++	ldx	[%sp+LOCALS64+$M],$a0		! forward load
++	ldx	[%sp+LOCALS64+$M+8],$a1
++	ldx	[%sp+LOCALS64+$M+16],$a2
++	ldx	[%sp+LOCALS64+$M+24],$a3
++
++	add	%sp,LOCALS64+$S,$bp
++	call	__ecp_nistz256_sub_morf_vis3	! p256_sub(S, S, res_x);
++	add	%sp,LOCALS64+$S,$rp
++
++	mov	$acc0,$bi
++	call	__ecp_nistz256_mul_mont_vis3	! p256_mul_mont(S, S, M);
++	add	%sp,LOCALS64+$S,$rp
++
++	ldx	[%sp+LOCALS64+$res_x],$a0	! forward load
++	ldx	[%sp+LOCALS64+$res_x+8],$a1
++	ldx	[%sp+LOCALS64+$res_x+16],$a2
++	ldx	[%sp+LOCALS64+$res_x+24],$a3
++
++	add	%sp,LOCALS64+$res_y,$bp
++	call	__ecp_nistz256_sub_from_vis3	! p256_sub(res_y, S, res_y);
++	add	%sp,LOCALS64+$res_y,$bp
++
++	! convert output to uint_32[8]
++	srlx	$a0,32,$t0
++	srlx	$a1,32,$t1
++	st	$a0,[$rp_real]			! res_x
++	srlx	$a2,32,$t2
++	st	$t0,[$rp_real+4]
++	srlx	$a3,32,$t3
++	st	$a1,[$rp_real+8]
++	st	$t1,[$rp_real+12]
++	st	$a2,[$rp_real+16]
++	st	$t2,[$rp_real+20]
++	st	$a3,[$rp_real+24]
++	st	$t3,[$rp_real+28]
++
++	ldx	[%sp+LOCALS64+$res_z],$a0	! forward load
++	srlx	$acc0,32,$t0
++	ldx	[%sp+LOCALS64+$res_z+8],$a1
++	srlx	$acc1,32,$t1
++	ldx	[%sp+LOCALS64+$res_z+16],$a2
++	srlx	$acc2,32,$t2
++	ldx	[%sp+LOCALS64+$res_z+24],$a3
++	srlx	$acc3,32,$t3
++	st	$acc0,[$rp_real+32]		! res_y
++	st	$t0,  [$rp_real+32+4]
++	st	$acc1,[$rp_real+32+8]
++	st	$t1,  [$rp_real+32+12]
++	st	$acc2,[$rp_real+32+16]
++	st	$t2,  [$rp_real+32+20]
++	st	$acc3,[$rp_real+32+24]
++	st	$t3,  [$rp_real+32+28]
++
++	srlx	$a0,32,$t0
++	srlx	$a1,32,$t1
++	st	$a0,[$rp_real+64]		! res_z
++	srlx	$a2,32,$t2
++	st	$t0,[$rp_real+64+4]
++	srlx	$a3,32,$t3
++	st	$a1,[$rp_real+64+8]
++	st	$t1,[$rp_real+64+12]
++	st	$a2,[$rp_real+64+16]
++	st	$t2,[$rp_real+64+20]
++	st	$a3,[$rp_real+64+24]
++	st	$t3,[$rp_real+64+28]
++
++	ret
++	restore
++.type	ecp_nistz256_point_double_vis3,#function
++.size	ecp_nistz256_point_double_vis3,.-ecp_nistz256_point_double_vis3
++___
++}
++########################################################################
++# void ecp_nistz256_point_add(P256_POINT *out,const P256_POINT *in1,
++#			      const P256_POINT *in2);
++{
++my ($res_x,$res_y,$res_z,
++    $in1_x,$in1_y,$in1_z,
++    $in2_x,$in2_y,$in2_z,
++    $H,$Hsqr,$R,$Rsqr,$Hcub,
++    $U1,$U2,$S1,$S2)=map(32*$_,(0..17));
++my ($Z1sqr, $Z2sqr) = ($Hsqr, $Rsqr);
++
++# above map() describes stack layout with 18 temporary
++# 256-bit vectors on top. Then we reserve some space for
++# !in1infty, !in2infty and result of check for zero.
++
++$code.=<<___;
++.globl	ecp_nistz256_point_add_vis3
++.align	32
++ecp_nistz256_point_add_vis3:
++	save	%sp,-STACK64_FRAME-32*18-32,%sp
++
++	mov	$rp,$rp_real
++	mov	-1,$minus1
++	mov	-2,$poly3
++	sllx	$minus1,32,$poly1		! 0xFFFFFFFF00000000
++	srl	$poly3,0,$poly3			! 0x00000000FFFFFFFE
++
++	! convert input to uint64_t[4]
++	ld	[$bp],$a0			! in2_x
++	ld	[$bp+4],$t0
++	ld	[$bp+8],$a1
++	ld	[$bp+12],$t1
++	ld	[$bp+16],$a2
++	ld	[$bp+20],$t2
++	ld	[$bp+24],$a3
++	ld	[$bp+28],$t3
++	sllx	$t0,32,$t0
++	sllx	$t1,32,$t1
++	ld	[$bp+32],$acc0			! in2_y
++	or	$a0,$t0,$a0
++	ld	[$bp+32+4],$t0
++	sllx	$t2,32,$t2
++	ld	[$bp+32+8],$acc1
++	or	$a1,$t1,$a1
++	ld	[$bp+32+12],$t1
++	sllx	$t3,32,$t3
++	ld	[$bp+32+16],$acc2
++	or	$a2,$t2,$a2
++	ld	[$bp+32+20],$t2
++	or	$a3,$t3,$a3
++	ld	[$bp+32+24],$acc3
++	sllx	$t0,32,$t0
++	ld	[$bp+32+28],$t3
++	sllx	$t1,32,$t1
++	stx	$a0,[%sp+LOCALS64+$in2_x]
++	sllx	$t2,32,$t2
++	stx	$a1,[%sp+LOCALS64+$in2_x+8]
++	sllx	$t3,32,$t3
++	stx	$a2,[%sp+LOCALS64+$in2_x+16]
++	or	$acc0,$t0,$acc0
++	stx	$a3,[%sp+LOCALS64+$in2_x+24]
++	or	$acc1,$t1,$acc1
++	stx	$acc0,[%sp+LOCALS64+$in2_y]
++	or	$acc2,$t2,$acc2
++	stx	$acc1,[%sp+LOCALS64+$in2_y+8]
++	or	$acc3,$t3,$acc3
++	stx	$acc2,[%sp+LOCALS64+$in2_y+16]
++	stx	$acc3,[%sp+LOCALS64+$in2_y+24]
++
++	ld	[$bp+64],$acc0			! in2_z
++	ld	[$bp+64+4],$t0
++	ld	[$bp+64+8],$acc1
++	ld	[$bp+64+12],$t1
++	ld	[$bp+64+16],$acc2
++	ld	[$bp+64+20],$t2
++	ld	[$bp+64+24],$acc3
++	ld	[$bp+64+28],$t3
++	sllx	$t0,32,$t0
++	sllx	$t1,32,$t1
++	ld	[$ap],$a0			! in1_x
++	or	$acc0,$t0,$acc0
++	ld	[$ap+4],$t0
++	sllx	$t2,32,$t2
++	ld	[$ap+8],$a1
++	or	$acc1,$t1,$acc1
++	ld	[$ap+12],$t1
++	sllx	$t3,32,$t3
++	ld	[$ap+16],$a2
++	or	$acc2,$t2,$acc2
++	ld	[$ap+20],$t2
++	or	$acc3,$t3,$acc3
++	ld	[$ap+24],$a3
++	sllx	$t0,32,$t0
++	ld	[$ap+28],$t3
++	sllx	$t1,32,$t1
++	stx	$acc0,[%sp+LOCALS64+$in2_z]
++	sllx	$t2,32,$t2
++	stx	$acc1,[%sp+LOCALS64+$in2_z+8]
++	sllx	$t3,32,$t3
++	stx	$acc2,[%sp+LOCALS64+$in2_z+16]
++	stx	$acc3,[%sp+LOCALS64+$in2_z+24]
++
++	or	$acc1,$acc0,$acc0
++	or	$acc3,$acc2,$acc2
++	or	$acc2,$acc0,$acc0
++	movrnz	$acc0,-1,$acc0			! !in2infty
++	stx	$acc0,[%fp+STACK_BIAS-8]
++
++	or	$a0,$t0,$a0
++	ld	[$ap+32],$acc0			! in1_y
++	or	$a1,$t1,$a1
++	ld	[$ap+32+4],$t0
++	or	$a2,$t2,$a2
++	ld	[$ap+32+8],$acc1
++	or	$a3,$t3,$a3
++	ld	[$ap+32+12],$t1
++	ld	[$ap+32+16],$acc2
++	ld	[$ap+32+20],$t2
++	ld	[$ap+32+24],$acc3
++	sllx	$t0,32,$t0
++	ld	[$ap+32+28],$t3
++	sllx	$t1,32,$t1
++	stx	$a0,[%sp+LOCALS64+$in1_x]
++	sllx	$t2,32,$t2
++	stx	$a1,[%sp+LOCALS64+$in1_x+8]
++	sllx	$t3,32,$t3
++	stx	$a2,[%sp+LOCALS64+$in1_x+16]
++	or	$acc0,$t0,$acc0
++	stx	$a3,[%sp+LOCALS64+$in1_x+24]
++	or	$acc1,$t1,$acc1
++	stx	$acc0,[%sp+LOCALS64+$in1_y]
++	or	$acc2,$t2,$acc2
++	stx	$acc1,[%sp+LOCALS64+$in1_y+8]
++	or	$acc3,$t3,$acc3
++	stx	$acc2,[%sp+LOCALS64+$in1_y+16]
++	stx	$acc3,[%sp+LOCALS64+$in1_y+24]
++
++	ldx	[%sp+LOCALS64+$in2_z],$a0	! forward load
++	ldx	[%sp+LOCALS64+$in2_z+8],$a1
++	ldx	[%sp+LOCALS64+$in2_z+16],$a2
++	ldx	[%sp+LOCALS64+$in2_z+24],$a3
++
++	ld	[$ap+64],$acc0			! in1_z
++	ld	[$ap+64+4],$t0
++	ld	[$ap+64+8],$acc1
++	ld	[$ap+64+12],$t1
++	ld	[$ap+64+16],$acc2
++	ld	[$ap+64+20],$t2
++	ld	[$ap+64+24],$acc3
++	ld	[$ap+64+28],$t3
++	sllx	$t0,32,$t0
++	sllx	$t1,32,$t1
++	or	$acc0,$t0,$acc0
++	sllx	$t2,32,$t2
++	or	$acc1,$t1,$acc1
++	sllx	$t3,32,$t3
++	stx	$acc0,[%sp+LOCALS64+$in1_z]
++	or	$acc2,$t2,$acc2
++	stx	$acc1,[%sp+LOCALS64+$in1_z+8]
++	or	$acc3,$t3,$acc3
++	stx	$acc2,[%sp+LOCALS64+$in1_z+16]
++	stx	$acc3,[%sp+LOCALS64+$in1_z+24]
++
++	or	$acc1,$acc0,$acc0
++	or	$acc3,$acc2,$acc2
++	or	$acc2,$acc0,$acc0
++	movrnz	$acc0,-1,$acc0			! !in1infty
++	stx	$acc0,[%fp+STACK_BIAS-16]
++
++	call	__ecp_nistz256_sqr_mont_vis3	! p256_sqr_mont(Z2sqr, in2_z);
++	add	%sp,LOCALS64+$Z2sqr,$rp
++
++	ldx	[%sp+LOCALS64+$in1_z],$a0
++	ldx	[%sp+LOCALS64+$in1_z+8],$a1
++	ldx	[%sp+LOCALS64+$in1_z+16],$a2
++	ldx	[%sp+LOCALS64+$in1_z+24],$a3
++	call	__ecp_nistz256_sqr_mont_vis3	! p256_sqr_mont(Z1sqr, in1_z);
++	add	%sp,LOCALS64+$Z1sqr,$rp
++
++	ldx	[%sp+LOCALS64+$Z2sqr],$bi
++	ldx	[%sp+LOCALS64+$in2_z],$a0
++	ldx	[%sp+LOCALS64+$in2_z+8],$a1
++	ldx	[%sp+LOCALS64+$in2_z+16],$a2
++	ldx	[%sp+LOCALS64+$in2_z+24],$a3
++	add	%sp,LOCALS64+$Z2sqr,$bp
++	call	__ecp_nistz256_mul_mont_vis3	! p256_mul_mont(S1, Z2sqr, in2_z);
++	add	%sp,LOCALS64+$S1,$rp
++
++	ldx	[%sp+LOCALS64+$Z1sqr],$bi
++	ldx	[%sp+LOCALS64+$in1_z],$a0
++	ldx	[%sp+LOCALS64+$in1_z+8],$a1
++	ldx	[%sp+LOCALS64+$in1_z+16],$a2
++	ldx	[%sp+LOCALS64+$in1_z+24],$a3
++	add	%sp,LOCALS64+$Z1sqr,$bp
++	call	__ecp_nistz256_mul_mont_vis3	! p256_mul_mont(S2, Z1sqr, in1_z);
++	add	%sp,LOCALS64+$S2,$rp
++
++	ldx	[%sp+LOCALS64+$S1],$bi
++	ldx	[%sp+LOCALS64+$in1_y],$a0
++	ldx	[%sp+LOCALS64+$in1_y+8],$a1
++	ldx	[%sp+LOCALS64+$in1_y+16],$a2
++	ldx	[%sp+LOCALS64+$in1_y+24],$a3
++	add	%sp,LOCALS64+$S1,$bp
++	call	__ecp_nistz256_mul_mont_vis3	! p256_mul_mont(S1, S1, in1_y);
++	add	%sp,LOCALS64+$S1,$rp
++
++	ldx	[%sp+LOCALS64+$S2],$bi
++	ldx	[%sp+LOCALS64+$in2_y],$a0
++	ldx	[%sp+LOCALS64+$in2_y+8],$a1
++	ldx	[%sp+LOCALS64+$in2_y+16],$a2
++	ldx	[%sp+LOCALS64+$in2_y+24],$a3
++	add	%sp,LOCALS64+$S2,$bp
++	call	__ecp_nistz256_mul_mont_vis3	! p256_mul_mont(S2, S2, in2_y);
++	add	%sp,LOCALS64+$S2,$rp
++
++	ldx	[%sp+LOCALS64+$Z2sqr],$bi	! forward load
++	ldx	[%sp+LOCALS64+$in1_x],$a0
++	ldx	[%sp+LOCALS64+$in1_x+8],$a1
++	ldx	[%sp+LOCALS64+$in1_x+16],$a2
++	ldx	[%sp+LOCALS64+$in1_x+24],$a3
++
++	add	%sp,LOCALS64+$S1,$bp
++	call	__ecp_nistz256_sub_from_vis3	! p256_sub(R, S2, S1);
++	add	%sp,LOCALS64+$R,$rp
++
++	or	$acc1,$acc0,$acc0		! see if result is zero
++	or	$acc3,$acc2,$acc2
++	or	$acc2,$acc0,$acc0
++	stx	$acc0,[%fp+STACK_BIAS-24]
++
++	add	%sp,LOCALS64+$Z2sqr,$bp
++	call	__ecp_nistz256_mul_mont_vis3	! p256_mul_mont(U1, in1_x, Z2sqr);
++	add	%sp,LOCALS64+$U1,$rp
++
++	ldx	[%sp+LOCALS64+$Z1sqr],$bi
++	ldx	[%sp+LOCALS64+$in2_x],$a0
++	ldx	[%sp+LOCALS64+$in2_x+8],$a1
++	ldx	[%sp+LOCALS64+$in2_x+16],$a2
++	ldx	[%sp+LOCALS64+$in2_x+24],$a3
++	add	%sp,LOCALS64+$Z1sqr,$bp
++	call	__ecp_nistz256_mul_mont_vis3	! p256_mul_mont(U2, in2_x, Z1sqr);
++	add	%sp,LOCALS64+$U2,$rp
++
++	ldx	[%sp+LOCALS64+$R],$a0		! forward load
++	ldx	[%sp+LOCALS64+$R+8],$a1
++	ldx	[%sp+LOCALS64+$R+16],$a2
++	ldx	[%sp+LOCALS64+$R+24],$a3
++
++	add	%sp,LOCALS64+$U1,$bp
++	call	__ecp_nistz256_sub_from_vis3	! p256_sub(H, U2, U1);
++	add	%sp,LOCALS64+$H,$rp
++
++	or	$acc1,$acc0,$acc0		! see if result is zero
++	or	$acc3,$acc2,$acc2
++	orcc	$acc2,$acc0,$acc0
++
++	bne,pt	%xcc,.Ladd_proceed_vis3		! is_equal(U1,U2)?
++	nop
++
++	ldx	[%fp+STACK_BIAS-8],$t0
++	ldx	[%fp+STACK_BIAS-16],$t1
++	ldx	[%fp+STACK_BIAS-24],$t2
++	andcc	$t0,$t1,%g0
++	be,pt	%xcc,.Ladd_proceed_vis3		! (in1infty || in2infty)?
++	nop
++	andcc	$t2,$t2,%g0
++	be,a,pt	%xcc,.Ldouble_shortcut_vis3	! is_equal(S1,S2)?
++	add	%sp,32*(12-10)+32,%sp		! difference in frame sizes
++
++	st	%g0,[$rp_real]
++	st	%g0,[$rp_real+4]
++	st	%g0,[$rp_real+8]
++	st	%g0,[$rp_real+12]
++	st	%g0,[$rp_real+16]
++	st	%g0,[$rp_real+20]
++	st	%g0,[$rp_real+24]
++	st	%g0,[$rp_real+28]
++	st	%g0,[$rp_real+32]
++	st	%g0,[$rp_real+32+4]
++	st	%g0,[$rp_real+32+8]
++	st	%g0,[$rp_real+32+12]
++	st	%g0,[$rp_real+32+16]
++	st	%g0,[$rp_real+32+20]
++	st	%g0,[$rp_real+32+24]
++	st	%g0,[$rp_real+32+28]
++	st	%g0,[$rp_real+64]
++	st	%g0,[$rp_real+64+4]
++	st	%g0,[$rp_real+64+8]
++	st	%g0,[$rp_real+64+12]
++	st	%g0,[$rp_real+64+16]
++	st	%g0,[$rp_real+64+20]
++	st	%g0,[$rp_real+64+24]
++	st	%g0,[$rp_real+64+28]
++	b	.Ladd_done_vis3
++	nop
++
++.align	16
++.Ladd_proceed_vis3:
++	call	__ecp_nistz256_sqr_mont_vis3	! p256_sqr_mont(Rsqr, R);
++	add	%sp,LOCALS64+$Rsqr,$rp
++
++	ldx	[%sp+LOCALS64+$H],$bi
++	ldx	[%sp+LOCALS64+$in1_z],$a0
++	ldx	[%sp+LOCALS64+$in1_z+8],$a1
++	ldx	[%sp+LOCALS64+$in1_z+16],$a2
++	ldx	[%sp+LOCALS64+$in1_z+24],$a3
++	add	%sp,LOCALS64+$H,$bp
++	call	__ecp_nistz256_mul_mont_vis3	! p256_mul_mont(res_z, H, in1_z);
++	add	%sp,LOCALS64+$res_z,$rp
++
++	ldx	[%sp+LOCALS64+$H],$a0
++	ldx	[%sp+LOCALS64+$H+8],$a1
++	ldx	[%sp+LOCALS64+$H+16],$a2
++	ldx	[%sp+LOCALS64+$H+24],$a3
++	call	__ecp_nistz256_sqr_mont_vis3	! p256_sqr_mont(Hsqr, H);
++	add	%sp,LOCALS64+$Hsqr,$rp
++
++	ldx	[%sp+LOCALS64+$res_z],$bi
++	ldx	[%sp+LOCALS64+$in2_z],$a0
++	ldx	[%sp+LOCALS64+$in2_z+8],$a1
++	ldx	[%sp+LOCALS64+$in2_z+16],$a2
++	ldx	[%sp+LOCALS64+$in2_z+24],$a3
++	add	%sp,LOCALS64+$res_z,$bp
++	call	__ecp_nistz256_mul_mont_vis3	! p256_mul_mont(res_z, res_z, in2_z);
++	add	%sp,LOCALS64+$res_z,$rp
++
++	ldx	[%sp+LOCALS64+$H],$bi
++	ldx	[%sp+LOCALS64+$Hsqr],$a0
++	ldx	[%sp+LOCALS64+$Hsqr+8],$a1
++	ldx	[%sp+LOCALS64+$Hsqr+16],$a2
++	ldx	[%sp+LOCALS64+$Hsqr+24],$a3
++	add	%sp,LOCALS64+$H,$bp
++	call	__ecp_nistz256_mul_mont_vis3	! p256_mul_mont(Hcub, Hsqr, H);
++	add	%sp,LOCALS64+$Hcub,$rp
++
++	ldx	[%sp+LOCALS64+$U1],$bi
++	ldx	[%sp+LOCALS64+$Hsqr],$a0
++	ldx	[%sp+LOCALS64+$Hsqr+8],$a1
++	ldx	[%sp+LOCALS64+$Hsqr+16],$a2
++	ldx	[%sp+LOCALS64+$Hsqr+24],$a3
++	add	%sp,LOCALS64+$U1,$bp
++	call	__ecp_nistz256_mul_mont_vis3	! p256_mul_mont(U2, U1, Hsqr);
++	add	%sp,LOCALS64+$U2,$rp
++
++	call	__ecp_nistz256_mul_by_2_vis3	! p256_mul_by_2(Hsqr, U2);
++	add	%sp,LOCALS64+$Hsqr,$rp
++
++	add	%sp,LOCALS64+$Rsqr,$bp
++	call	__ecp_nistz256_sub_morf_vis3	! p256_sub(res_x, Rsqr, Hsqr);
++	add	%sp,LOCALS64+$res_x,$rp
++
++	add	%sp,LOCALS64+$Hcub,$bp
++	call	__ecp_nistz256_sub_from_vis3	!  p256_sub(res_x, res_x, Hcub);
++	add	%sp,LOCALS64+$res_x,$rp
++
++	ldx	[%sp+LOCALS64+$S1],$bi		! forward load
++	ldx	[%sp+LOCALS64+$Hcub],$a0
++	ldx	[%sp+LOCALS64+$Hcub+8],$a1
++	ldx	[%sp+LOCALS64+$Hcub+16],$a2
++	ldx	[%sp+LOCALS64+$Hcub+24],$a3
++
++	add	%sp,LOCALS64+$U2,$bp
++	call	__ecp_nistz256_sub_morf_vis3	! p256_sub(res_y, U2, res_x);
++	add	%sp,LOCALS64+$res_y,$rp
++
++	add	%sp,LOCALS64+$S1,$bp
++	call	__ecp_nistz256_mul_mont_vis3	! p256_mul_mont(S2, S1, Hcub);
++	add	%sp,LOCALS64+$S2,$rp
++
++	ldx	[%sp+LOCALS64+$R],$bi
++	ldx	[%sp+LOCALS64+$res_y],$a0
++	ldx	[%sp+LOCALS64+$res_y+8],$a1
++	ldx	[%sp+LOCALS64+$res_y+16],$a2
++	ldx	[%sp+LOCALS64+$res_y+24],$a3
++	add	%sp,LOCALS64+$R,$bp
++	call	__ecp_nistz256_mul_mont_vis3	! p256_mul_mont(res_y, res_y, R);
++	add	%sp,LOCALS64+$res_y,$rp
++
++	add	%sp,LOCALS64+$S2,$bp
++	call	__ecp_nistz256_sub_from_vis3	! p256_sub(res_y, res_y, S2);
++	add	%sp,LOCALS64+$res_y,$rp
++
++	ldx	[%fp+STACK_BIAS-16],$t1		! !in1infty
++	ldx	[%fp+STACK_BIAS-8],$t2		! !in2infty
++___
++for($i=0;$i<96;$i+=16) {			# conditional moves
++$code.=<<___;
++	ldx	[%sp+LOCALS64+$res_x+$i],$acc0	! res
++	ldx	[%sp+LOCALS64+$res_x+$i+8],$acc1
++	ldx	[%sp+LOCALS64+$in2_x+$i],$acc2	! in2
++	ldx	[%sp+LOCALS64+$in2_x+$i+8],$acc3
++	ldx	[%sp+LOCALS64+$in1_x+$i],$acc4	! in1
++	ldx	[%sp+LOCALS64+$in1_x+$i+8],$acc5
++	movrz	$t1,$acc2,$acc0
++	movrz	$t1,$acc3,$acc1
++	movrz	$t2,$acc4,$acc0
++	movrz	$t2,$acc5,$acc1
++	srlx	$acc0,32,$acc2
++	srlx	$acc1,32,$acc3
++	st	$acc0,[$rp_real+$i]
++	st	$acc2,[$rp_real+$i+4]
++	st	$acc1,[$rp_real+$i+8]
++	st	$acc3,[$rp_real+$i+12]
++___
++}
++$code.=<<___;
++.Ladd_done_vis3:
++	ret
++	restore
++.type	ecp_nistz256_point_add_vis3,#function
++.size	ecp_nistz256_point_add_vis3,.-ecp_nistz256_point_add_vis3
++___
++}
++########################################################################
++# void ecp_nistz256_point_add_affine(P256_POINT *out,const P256_POINT *in1,
++#				     const P256_POINT_AFFINE *in2);
++{
++my ($res_x,$res_y,$res_z,
++    $in1_x,$in1_y,$in1_z,
++    $in2_x,$in2_y,
++    $U2,$S2,$H,$R,$Hsqr,$Hcub,$Rsqr)=map(32*$_,(0..14));
++my $Z1sqr = $S2;
++# above map() describes stack layout with 15 temporary
++# 256-bit vectors on top. Then we reserve some space for
++# !in1infty and !in2infty.
++
++$code.=<<___;
++.align	32
++ecp_nistz256_point_add_affine_vis3:
++	save	%sp,-STACK64_FRAME-32*15-32,%sp
++
++	mov	$rp,$rp_real
++	mov	-1,$minus1
++	mov	-2,$poly3
++	sllx	$minus1,32,$poly1		! 0xFFFFFFFF00000000
++	srl	$poly3,0,$poly3			! 0x00000000FFFFFFFE
++
++	! convert input to uint64_t[4]
++	ld	[$bp],$a0			! in2_x
++	ld	[$bp+4],$t0
++	ld	[$bp+8],$a1
++	ld	[$bp+12],$t1
++	ld	[$bp+16],$a2
++	ld	[$bp+20],$t2
++	ld	[$bp+24],$a3
++	ld	[$bp+28],$t3
++	sllx	$t0,32,$t0
++	sllx	$t1,32,$t1
++	ld	[$bp+32],$acc0			! in2_y
++	or	$a0,$t0,$a0
++	ld	[$bp+32+4],$t0
++	sllx	$t2,32,$t2
++	ld	[$bp+32+8],$acc1
++	or	$a1,$t1,$a1
++	ld	[$bp+32+12],$t1
++	sllx	$t3,32,$t3
++	ld	[$bp+32+16],$acc2
++	or	$a2,$t2,$a2
++	ld	[$bp+32+20],$t2
++	or	$a3,$t3,$a3
++	ld	[$bp+32+24],$acc3
++	sllx	$t0,32,$t0
++	ld	[$bp+32+28],$t3
++	sllx	$t1,32,$t1
++	stx	$a0,[%sp+LOCALS64+$in2_x]
++	sllx	$t2,32,$t2
++	stx	$a1,[%sp+LOCALS64+$in2_x+8]
++	sllx	$t3,32,$t3
++	stx	$a2,[%sp+LOCALS64+$in2_x+16]
++	or	$acc0,$t0,$acc0
++	stx	$a3,[%sp+LOCALS64+$in2_x+24]
++	or	$acc1,$t1,$acc1
++	stx	$acc0,[%sp+LOCALS64+$in2_y]
++	or	$acc2,$t2,$acc2
++	stx	$acc1,[%sp+LOCALS64+$in2_y+8]
++	or	$acc3,$t3,$acc3
++	stx	$acc2,[%sp+LOCALS64+$in2_y+16]
++	stx	$acc3,[%sp+LOCALS64+$in2_y+24]
++
++	or	$a1,$a0,$a0
++	or	$a3,$a2,$a2
++	or	$acc1,$acc0,$acc0
++	or	$acc3,$acc2,$acc2
++	or	$a2,$a0,$a0
++	or	$acc2,$acc0,$acc0
++	or	$acc0,$a0,$a0
++	movrnz	$a0,-1,$a0			! !in2infty
++	stx	$a0,[%fp+STACK_BIAS-8]
++
++	ld	[$ap],$a0			! in1_x
++	ld	[$ap+4],$t0
++	ld	[$ap+8],$a1
++	ld	[$ap+12],$t1
++	ld	[$ap+16],$a2
++	ld	[$ap+20],$t2
++	ld	[$ap+24],$a3
++	ld	[$ap+28],$t3
++	sllx	$t0,32,$t0
++	sllx	$t1,32,$t1
++	ld	[$ap+32],$acc0			! in1_y
++	or	$a0,$t0,$a0
++	ld	[$ap+32+4],$t0
++	sllx	$t2,32,$t2
++	ld	[$ap+32+8],$acc1
++	or	$a1,$t1,$a1
++	ld	[$ap+32+12],$t1
++	sllx	$t3,32,$t3
++	ld	[$ap+32+16],$acc2
++	or	$a2,$t2,$a2
++	ld	[$ap+32+20],$t2
++	or	$a3,$t3,$a3
++	ld	[$ap+32+24],$acc3
++	sllx	$t0,32,$t0
++	ld	[$ap+32+28],$t3
++	sllx	$t1,32,$t1
++	stx	$a0,[%sp+LOCALS64+$in1_x]
++	sllx	$t2,32,$t2
++	stx	$a1,[%sp+LOCALS64+$in1_x+8]
++	sllx	$t3,32,$t3
++	stx	$a2,[%sp+LOCALS64+$in1_x+16]
++	or	$acc0,$t0,$acc0
++	stx	$a3,[%sp+LOCALS64+$in1_x+24]
++	or	$acc1,$t1,$acc1
++	stx	$acc0,[%sp+LOCALS64+$in1_y]
++	or	$acc2,$t2,$acc2
++	stx	$acc1,[%sp+LOCALS64+$in1_y+8]
++	or	$acc3,$t3,$acc3
++	stx	$acc2,[%sp+LOCALS64+$in1_y+16]
++	stx	$acc3,[%sp+LOCALS64+$in1_y+24]
++
++	ld	[$ap+64],$a0			! in1_z
++	ld	[$ap+64+4],$t0
++	ld	[$ap+64+8],$a1
++	ld	[$ap+64+12],$t1
++	ld	[$ap+64+16],$a2
++	ld	[$ap+64+20],$t2
++	ld	[$ap+64+24],$a3
++	ld	[$ap+64+28],$t3
++	sllx	$t0,32,$t0
++	sllx	$t1,32,$t1
++	or	$a0,$t0,$a0
++	sllx	$t2,32,$t2
++	or	$a1,$t1,$a1
++	sllx	$t3,32,$t3
++	stx	$a0,[%sp+LOCALS64+$in1_z]
++	or	$a2,$t2,$a2
++	stx	$a1,[%sp+LOCALS64+$in1_z+8]
++	or	$a3,$t3,$a3
++	stx	$a2,[%sp+LOCALS64+$in1_z+16]
++	stx	$a3,[%sp+LOCALS64+$in1_z+24]
++
++	or	$a1,$a0,$t0
++	or	$a3,$a2,$t2
++	or	$t2,$t0,$t0
++	movrnz	$t0,-1,$t0			! !in1infty
++	stx	$t0,[%fp+STACK_BIAS-16]
++
++	call	__ecp_nistz256_sqr_mont_vis3	! p256_sqr_mont(Z1sqr, in1_z);
++	add	%sp,LOCALS64+$Z1sqr,$rp
++
++	ldx	[%sp+LOCALS64+$in2_x],$bi
++	mov	$acc0,$a0
++	mov	$acc1,$a1
++	mov	$acc2,$a2
++	mov	$acc3,$a3
++	add	%sp,LOCALS64+$in2_x,$bp
++	call	__ecp_nistz256_mul_mont_vis3	! p256_mul_mont(U2, Z1sqr, in2_x);
++	add	%sp,LOCALS64+$U2,$rp
++
++	ldx	[%sp+LOCALS64+$Z1sqr],$bi	! forward load
++	ldx	[%sp+LOCALS64+$in1_z],$a0
++	ldx	[%sp+LOCALS64+$in1_z+8],$a1
++	ldx	[%sp+LOCALS64+$in1_z+16],$a2
++	ldx	[%sp+LOCALS64+$in1_z+24],$a3
++
++	add	%sp,LOCALS64+$in1_x,$bp
++	call	__ecp_nistz256_sub_from_vis3	! p256_sub(H, U2, in1_x);
++	add	%sp,LOCALS64+$H,$rp
++
++	add	%sp,LOCALS64+$Z1sqr,$bp
++	call	__ecp_nistz256_mul_mont_vis3	! p256_mul_mont(S2, Z1sqr, in1_z);
++	add	%sp,LOCALS64+$S2,$rp
++
++	ldx	[%sp+LOCALS64+$H],$bi
++	ldx	[%sp+LOCALS64+$in1_z],$a0
++	ldx	[%sp+LOCALS64+$in1_z+8],$a1
++	ldx	[%sp+LOCALS64+$in1_z+16],$a2
++	ldx	[%sp+LOCALS64+$in1_z+24],$a3
++	add	%sp,LOCALS64+$H,$bp
++	call	__ecp_nistz256_mul_mont_vis3	! p256_mul_mont(res_z, H, in1_z);
++	add	%sp,LOCALS64+$res_z,$rp
++
++	ldx	[%sp+LOCALS64+$S2],$bi
++	ldx	[%sp+LOCALS64+$in2_y],$a0
++	ldx	[%sp+LOCALS64+$in2_y+8],$a1
++	ldx	[%sp+LOCALS64+$in2_y+16],$a2
++	ldx	[%sp+LOCALS64+$in2_y+24],$a3
++	add	%sp,LOCALS64+$S2,$bp
++	call	__ecp_nistz256_mul_mont_vis3	! p256_mul_mont(S2, S2, in2_y);
++	add	%sp,LOCALS64+$S2,$rp
++
++	ldx	[%sp+LOCALS64+$H],$a0		! forward load
++	ldx	[%sp+LOCALS64+$H+8],$a1
++	ldx	[%sp+LOCALS64+$H+16],$a2
++	ldx	[%sp+LOCALS64+$H+24],$a3
++
++	add	%sp,LOCALS64+$in1_y,$bp
++	call	__ecp_nistz256_sub_from_vis3	! p256_sub(R, S2, in1_y);
++	add	%sp,LOCALS64+$R,$rp
++
++	call	__ecp_nistz256_sqr_mont_vis3	! p256_sqr_mont(Hsqr, H);
++	add	%sp,LOCALS64+$Hsqr,$rp
++
++	ldx	[%sp+LOCALS64+$R],$a0
++	ldx	[%sp+LOCALS64+$R+8],$a1
++	ldx	[%sp+LOCALS64+$R+16],$a2
++	ldx	[%sp+LOCALS64+$R+24],$a3
++	call	__ecp_nistz256_sqr_mont_vis3	! p256_sqr_mont(Rsqr, R);
++	add	%sp,LOCALS64+$Rsqr,$rp
++
++	ldx	[%sp+LOCALS64+$H],$bi
++	ldx	[%sp+LOCALS64+$Hsqr],$a0
++	ldx	[%sp+LOCALS64+$Hsqr+8],$a1
++	ldx	[%sp+LOCALS64+$Hsqr+16],$a2
++	ldx	[%sp+LOCALS64+$Hsqr+24],$a3
++	add	%sp,LOCALS64+$H,$bp
++	call	__ecp_nistz256_mul_mont_vis3	! p256_mul_mont(Hcub, Hsqr, H);
++	add	%sp,LOCALS64+$Hcub,$rp
++
++	ldx	[%sp+LOCALS64+$Hsqr],$bi
++	ldx	[%sp+LOCALS64+$in1_x],$a0
++	ldx	[%sp+LOCALS64+$in1_x+8],$a1
++	ldx	[%sp+LOCALS64+$in1_x+16],$a2
++	ldx	[%sp+LOCALS64+$in1_x+24],$a3
++	add	%sp,LOCALS64+$Hsqr,$bp
++	call	__ecp_nistz256_mul_mont_vis3	! p256_mul_mont(U2, in1_x, Hsqr);
++	add	%sp,LOCALS64+$U2,$rp
++
++	call	__ecp_nistz256_mul_by_2_vis3	! p256_mul_by_2(Hsqr, U2);
++	add	%sp,LOCALS64+$Hsqr,$rp
++
++	add	%sp,LOCALS64+$Rsqr,$bp
++	call	__ecp_nistz256_sub_morf_vis3	! p256_sub(res_x, Rsqr, Hsqr);
++	add	%sp,LOCALS64+$res_x,$rp
++
++	add	%sp,LOCALS64+$Hcub,$bp
++	call	__ecp_nistz256_sub_from_vis3	!  p256_sub(res_x, res_x, Hcub);
++	add	%sp,LOCALS64+$res_x,$rp
++
++	ldx	[%sp+LOCALS64+$Hcub],$bi	! forward load
++	ldx	[%sp+LOCALS64+$in1_y],$a0
++	ldx	[%sp+LOCALS64+$in1_y+8],$a1
++	ldx	[%sp+LOCALS64+$in1_y+16],$a2
++	ldx	[%sp+LOCALS64+$in1_y+24],$a3
++
++	add	%sp,LOCALS64+$U2,$bp
++	call	__ecp_nistz256_sub_morf_vis3	! p256_sub(res_y, U2, res_x);
++	add	%sp,LOCALS64+$res_y,$rp
++
++	add	%sp,LOCALS64+$Hcub,$bp
++	call	__ecp_nistz256_mul_mont_vis3	! p256_mul_mont(S2, in1_y, Hcub);
++	add	%sp,LOCALS64+$S2,$rp
++
++	ldx	[%sp+LOCALS64+$R],$bi
++	ldx	[%sp+LOCALS64+$res_y],$a0
++	ldx	[%sp+LOCALS64+$res_y+8],$a1
++	ldx	[%sp+LOCALS64+$res_y+16],$a2
++	ldx	[%sp+LOCALS64+$res_y+24],$a3
++	add	%sp,LOCALS64+$R,$bp
++	call	__ecp_nistz256_mul_mont_vis3	! p256_mul_mont(res_y, res_y, R);
++	add	%sp,LOCALS64+$res_y,$rp
++
++	add	%sp,LOCALS64+$S2,$bp
++	call	__ecp_nistz256_sub_from_vis3	! p256_sub(res_y, res_y, S2);
++	add	%sp,LOCALS64+$res_y,$rp
++
++	ldx	[%fp+STACK_BIAS-16],$t1		! !in1infty
++	ldx	[%fp+STACK_BIAS-8],$t2		! !in2infty
++1:	call	.+8
++	add	%o7,.Lone_mont_vis3-1b,$bp
++___
++for($i=0;$i<64;$i+=16) {			# conditional moves
++$code.=<<___;
++	ldx	[%sp+LOCALS64+$res_x+$i],$acc0	! res
++	ldx	[%sp+LOCALS64+$res_x+$i+8],$acc1
++	ldx	[%sp+LOCALS64+$in2_x+$i],$acc2	! in2
++	ldx	[%sp+LOCALS64+$in2_x+$i+8],$acc3
++	ldx	[%sp+LOCALS64+$in1_x+$i],$acc4	! in1
++	ldx	[%sp+LOCALS64+$in1_x+$i+8],$acc5
++	movrz	$t1,$acc2,$acc0
++	movrz	$t1,$acc3,$acc1
++	movrz	$t2,$acc4,$acc0
++	movrz	$t2,$acc5,$acc1
++	srlx	$acc0,32,$acc2
++	srlx	$acc1,32,$acc3
++	st	$acc0,[$rp_real+$i]
++	st	$acc2,[$rp_real+$i+4]
++	st	$acc1,[$rp_real+$i+8]
++	st	$acc3,[$rp_real+$i+12]
++___
++}
++for(;$i<96;$i+=16) {
++$code.=<<___;
++	ldx	[%sp+LOCALS64+$res_x+$i],$acc0	! res
++	ldx	[%sp+LOCALS64+$res_x+$i+8],$acc1
++	ldx	[$bp+$i-64],$acc2		! "in2"
++	ldx	[$bp+$i-64+8],$acc3
++	ldx	[%sp+LOCALS64+$in1_x+$i],$acc4	! in1
++	ldx	[%sp+LOCALS64+$in1_x+$i+8],$acc5
++	movrz	$t1,$acc2,$acc0
++	movrz	$t1,$acc3,$acc1
++	movrz	$t2,$acc4,$acc0
++	movrz	$t2,$acc5,$acc1
++	srlx	$acc0,32,$acc2
++	srlx	$acc1,32,$acc3
++	st	$acc0,[$rp_real+$i]
++	st	$acc2,[$rp_real+$i+4]
++	st	$acc1,[$rp_real+$i+8]
++	st	$acc3,[$rp_real+$i+12]
++___
++}
++$code.=<<___;
++	ret
++	restore
++.type	ecp_nistz256_point_add_affine_vis3,#function
++.size	ecp_nistz256_point_add_affine_vis3,.-ecp_nistz256_point_add_affine_vis3
++.align	64
++.Lone_mont_vis3:
++.long	0x00000000,0x00000001, 0xffffffff,0x00000000
++.long	0xffffffff,0xffffffff, 0x00000000,0xfffffffe
++.align	64
++___
++}								}}}
++
++# Purpose of these subroutines is to explicitly encode VIS instructions,
++# so that one can compile the module without having to specify VIS
++# extensions on compiler command line, e.g. -xarch=v9 vs. -xarch=v9a.
++# Idea is to reserve for option to produce "universal" binary and let
++# programmer detect if current CPU is VIS capable at run-time.
++sub unvis3 {
++my ($mnemonic,$rs1,$rs2,$rd)=@_;
++my %bias = ( "g" => 0, "o" => 8, "l" => 16, "i" => 24 );
++my ($ref,$opf);
++my %visopf = (	"addxc"		=> 0x011,
++		"addxccc"	=> 0x013,
++		"umulxhi"	=> 0x016	);
++
++    $ref = "$mnemonic\t$rs1,$rs2,$rd";
++
++    if ($opf=$visopf{$mnemonic}) {
++	foreach ($rs1,$rs2,$rd) {
++	    return $ref if (!/%([goli])([0-9])/);
++	    $_=$bias{$1}+$2;
++	}
++
++	return	sprintf ".word\t0x%08x !%s",
++			0x81b00000|$rd<<25|$rs1<<14|$opf<<5|$rs2,
++			$ref;
++    } else {
++	return $ref;
++    }
++}
++
++foreach (split("\n",$code)) {
++	s/\`([^\`]*)\`/eval $1/ge;
++
++	s/\b(umulxhi|addxc[c]{0,2})\s+(%[goli][0-7]),\s*(%[goli][0-7]),\s*(%[goli][0-7])/
++		&unvis3($1,$2,$3,$4)
++	 /ge;
++
++	print $_,"\n";
++}
++
++close STDOUT;
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/ec/asm/ecp_nistz256-x86.pl b/CryptoPkg/Library/OpensslLib/openssl/crypto/ec/asm/ecp_nistz256-x86.pl
+new file mode 100755
+index 0000000..1d9e006
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/ec/asm/ecp_nistz256-x86.pl
+@@ -0,0 +1,1866 @@
++#! /usr/bin/env perl
++# Copyright 2015-2016 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
++# in the file LICENSE in the source distribution or at
++# https://www.openssl.org/source/license.html
++
++
++# ====================================================================
++# Written by Andy Polyakov  for the OpenSSL
++# project. The module is, however, dual licensed under OpenSSL and
++# CRYPTOGAMS licenses depending on where you obtain it. For further
++# details see http://www.openssl.org/~appro/cryptogams/.
++# ====================================================================
++#
++# ECP_NISTZ256 module for x86/SSE2.
++#
++# October 2014.
++#
++# Original ECP_NISTZ256 submission targeting x86_64 is detailed in
++# http://eprint.iacr.org/2013/816. In the process of adaptation
++# original .c module was made 32-bit savvy in order to make this
++# implementation possible.
++#
++#		with/without -DECP_NISTZ256_ASM
++# Pentium	+66-163%
++# PIII		+72-172%
++# P4		+65-132%
++# Core2		+90-215%
++# Sandy Bridge	+105-265% (contemporary i[57]-* are all close to this)
++# Atom		+65-155%
++# Opteron	+54-110%
++# Bulldozer	+99-240%
++# VIA Nano	+93-290%
++#
++# Ranges denote minimum and maximum improvement coefficients depending
++# on benchmark. Lower coefficients are for ECDSA sign, server-side
++# operation. Keep in mind that +200% means 3x improvement.
++
++$0 =~ m/(.*[\/\\])[^\/\\]+$/; $dir=$1;
++push(@INC,"${dir}","${dir}../../perlasm");
++require "x86asm.pl";
++
++$output=pop;
++open STDOUT,">$output";
++
++&asm_init($ARGV[0],"ecp_nistz256-x86.pl",$ARGV[$#ARGV] eq "386");
++
++$sse2=0;
++for (@ARGV) { $sse2=1 if (/-DOPENSSL_IA32_SSE2/); }
++
++&external_label("OPENSSL_ia32cap_P") if ($sse2);
++
++
++########################################################################
++# Convert ecp_nistz256_table.c to layout expected by ecp_nistz_gather_w7
++#
++open TABLE,") {
++	s/TOBN\(\s*(0x[0-9a-f]+),\s*(0x[0-9a-f]+)\s*\)/push @arr,hex($2),hex($1)/geo;
++}
++close TABLE;
++
++# See ecp_nistz256_table.c for explanation for why it's 64*16*37.
++# 64*16*37-1 is because $#arr returns last valid index or @arr, not
++# amount of elements.
++die "insane number of elements" if ($#arr != 64*16*37-1);
++
++&public_label("ecp_nistz256_precomputed");
++&align(4096);
++&set_label("ecp_nistz256_precomputed");
++
++########################################################################
++# this conversion smashes P256_POINT_AFFINE by individual bytes with
++# 64 byte interval, similar to
++#	1111222233334444
++#	1234123412341234
++for(1..37) {
++	@tbl = splice(@arr,0,64*16);
++	for($i=0;$i<64;$i++) {
++		undef @line;
++		for($j=0;$j<64;$j++) {
++			push @line,(@tbl[$j*16+$i/4]>>(($i%4)*8))&0xff;
++		}
++		&data_byte(join(',',map { sprintf "0x%02x",$_} @line));
++	}
++}
++
++########################################################################
++# Keep in mind that constants are stored least to most significant word
++&static_label("RR");
++&set_label("RR",64);
++&data_word(3,0,-1,-5,-2,-1,-3,4);	# 2^512 mod P-256
++
++&static_label("ONE_mont");
++&set_label("ONE_mont");
++&data_word(1,0,0,-1,-1,-1,-2,0);
++
++&static_label("ONE");
++&set_label("ONE");
++&data_word(1,0,0,0,0,0,0,0);
++&asciz("ECP_NISZ256 for x86/SSE2, CRYPTOGAMS by ");
++&align(64);
++
++########################################################################
++# void ecp_nistz256_mul_by_2(BN_ULONG edi[8],const BN_ULONG esi[8]);
++&function_begin("ecp_nistz256_mul_by_2");
++	&mov	("esi",&wparam(1));
++	&mov	("edi",&wparam(0));
++	&mov	("ebp","esi");
++########################################################################
++# common pattern for internal functions is that %edi is result pointer,
++# %esi and %ebp are input ones, %ebp being optional. %edi is preserved.
++	&call	("_ecp_nistz256_add");
++&function_end("ecp_nistz256_mul_by_2");
++
++########################################################################
++# void ecp_nistz256_mul_by_3(BN_ULONG edi[8],const BN_ULONG esi[8]);
++&function_begin("ecp_nistz256_mul_by_3");
++	&mov	("esi",&wparam(1));
++					# multiplication by 3 is performed
++					# as 2*n+n, but we can't use output
++					# to store 2*n, because if output
++					# pointer equals to input, then
++					# we'll get 2*n+2*n.
++	&stack_push(8);			# therefore we need to allocate
++					# 256-bit intermediate buffer.
++	&mov	("edi","esp");
++	&mov	("ebp","esi");
++	&call	("_ecp_nistz256_add");
++	&lea	("esi",&DWP(0,"edi"));
++	&mov	("ebp",&wparam(1));
++	&mov	("edi",&wparam(0));
++	&call	("_ecp_nistz256_add");
++	&stack_pop(8);
++&function_end("ecp_nistz256_mul_by_3");
++
++########################################################################
++# void ecp_nistz256_div_by_2(BN_ULONG edi[8],const BN_ULONG esi[8]);
++&function_begin("ecp_nistz256_div_by_2");
++	&mov	("esi",&wparam(1));
++	&mov	("edi",&wparam(0));
++	&call	("_ecp_nistz256_div_by_2");
++&function_end("ecp_nistz256_div_by_2");
++
++&function_begin_B("_ecp_nistz256_div_by_2");
++	# tmp = a is odd ? a+mod : a
++	#
++	# note that because mod has special form, i.e. consists of
++	# 0xffffffff, 1 and 0s, we can conditionally synthesize it by
++	# assigning least significant bit of input to one register,
++	# %ebp, and its negative to another, %edx.
++
++	&mov	("ebp",&DWP(0,"esi"));
++	&xor	("edx","edx");
++	&mov	("ebx",&DWP(4,"esi"));
++	&mov	("eax","ebp");
++	&and	("ebp",1);
++	&mov	("ecx",&DWP(8,"esi"));
++	&sub	("edx","ebp");
++
++	&add	("eax","edx");
++	&adc	("ebx","edx");
++	&mov	(&DWP(0,"edi"),"eax");
++	&adc	("ecx","edx");
++	&mov	(&DWP(4,"edi"),"ebx");
++	&mov	(&DWP(8,"edi"),"ecx");
++
++	&mov	("eax",&DWP(12,"esi"));
++	&mov	("ebx",&DWP(16,"esi"));
++	&adc	("eax",0);
++	&mov	("ecx",&DWP(20,"esi"));
++	&adc	("ebx",0);
++	&mov	(&DWP(12,"edi"),"eax");
++	&adc	("ecx",0);
++	&mov	(&DWP(16,"edi"),"ebx");
++	&mov	(&DWP(20,"edi"),"ecx");
++
++	&mov	("eax",&DWP(24,"esi"));
++	&mov	("ebx",&DWP(28,"esi"));
++	&adc	("eax","ebp");
++	&adc	("ebx","edx");
++	&mov	(&DWP(24,"edi"),"eax");
++	&sbb	("esi","esi");			# broadcast carry bit
++	&mov	(&DWP(28,"edi"),"ebx");
++
++	# ret = tmp >> 1
++
++	&mov	("eax",&DWP(0,"edi"));
++	&mov	("ebx",&DWP(4,"edi"));
++	&mov	("ecx",&DWP(8,"edi"));
++	&mov	("edx",&DWP(12,"edi"));
++
++	&shr	("eax",1);
++	&mov	("ebp","ebx");
++	&shl	("ebx",31);
++	&or	("eax","ebx");
++
++	&shr	("ebp",1);
++	&mov	("ebx","ecx");
++	&shl	("ecx",31);
++	&mov	(&DWP(0,"edi"),"eax");
++	&or	("ebp","ecx");
++	&mov	("eax",&DWP(16,"edi"));
++
++	&shr	("ebx",1);
++	&mov	("ecx","edx");
++	&shl	("edx",31);
++	&mov	(&DWP(4,"edi"),"ebp");
++	&or	("ebx","edx");
++	&mov	("ebp",&DWP(20,"edi"));
++
++	&shr	("ecx",1);
++	&mov	("edx","eax");
++	&shl	("eax",31);
++	&mov	(&DWP(8,"edi"),"ebx");
++	&or	("ecx","eax");
++	&mov	("ebx",&DWP(24,"edi"));
++
++	&shr	("edx",1);
++	&mov	("eax","ebp");
++	&shl	("ebp",31);
++	&mov	(&DWP(12,"edi"),"ecx");
++	&or	("edx","ebp");
++	&mov	("ecx",&DWP(28,"edi"));
++
++	&shr	("eax",1);
++	&mov	("ebp","ebx");
++	&shl	("ebx",31);
++	&mov	(&DWP(16,"edi"),"edx");
++	&or	("eax","ebx");
++
++	&shr	("ebp",1);
++	&mov	("ebx","ecx");
++	&shl	("ecx",31);
++	&mov	(&DWP(20,"edi"),"eax");
++	&or	("ebp","ecx");
++
++	&shr	("ebx",1);
++	&shl	("esi",31);
++	&mov	(&DWP(24,"edi"),"ebp");
++	&or	("ebx","esi");			# handle top-most carry bit
++	&mov	(&DWP(28,"edi"),"ebx");
++
++	&ret	();
++&function_end_B("_ecp_nistz256_div_by_2");
++
++########################################################################
++# void ecp_nistz256_add(BN_ULONG edi[8],const BN_ULONG esi[8],
++#					const BN_ULONG ebp[8]);
++&function_begin("ecp_nistz256_add");
++	&mov	("esi",&wparam(1));
++	&mov	("ebp",&wparam(2));
++	&mov	("edi",&wparam(0));
++	&call	("_ecp_nistz256_add");
++&function_end("ecp_nistz256_add");
++
++&function_begin_B("_ecp_nistz256_add");
++	&mov	("eax",&DWP(0,"esi"));
++	&mov	("ebx",&DWP(4,"esi"));
++	&mov	("ecx",&DWP(8,"esi"));
++	&add	("eax",&DWP(0,"ebp"));
++	&mov	("edx",&DWP(12,"esi"));
++	&adc	("ebx",&DWP(4,"ebp"));
++	&mov	(&DWP(0,"edi"),"eax");
++	&adc	("ecx",&DWP(8,"ebp"));
++	&mov	(&DWP(4,"edi"),"ebx");
++	&adc	("edx",&DWP(12,"ebp"));
++	&mov	(&DWP(8,"edi"),"ecx");
++	&mov	(&DWP(12,"edi"),"edx");
++
++	&mov	("eax",&DWP(16,"esi"));
++	&mov	("ebx",&DWP(20,"esi"));
++	&mov	("ecx",&DWP(24,"esi"));
++	&adc	("eax",&DWP(16,"ebp"));
++	&mov	("edx",&DWP(28,"esi"));
++	&adc	("ebx",&DWP(20,"ebp"));
++	&mov	(&DWP(16,"edi"),"eax");
++	&adc	("ecx",&DWP(24,"ebp"));
++	&mov	(&DWP(20,"edi"),"ebx");
++	&mov	("esi",0);
++	&adc	("edx",&DWP(28,"ebp"));
++	&mov	(&DWP(24,"edi"),"ecx");
++	&adc	("esi",0);
++	&mov	(&DWP(28,"edi"),"edx");
++
++	# if a+b >= modulus, subtract modulus.
++	#
++	# But since comparison implies subtraction, we subtract modulus
++	# to see if it borrows, and then subtract it for real if
++	# subtraction didn't borrow.
++
++	&mov	("eax",&DWP(0,"edi"));
++	&mov	("ebx",&DWP(4,"edi"));
++	&mov	("ecx",&DWP(8,"edi"));
++	&sub	("eax",-1);
++	&mov	("edx",&DWP(12,"edi"));
++	&sbb	("ebx",-1);
++	&mov	("eax",&DWP(16,"edi"));
++	&sbb	("ecx",-1);
++	&mov	("ebx",&DWP(20,"edi"));
++	&sbb	("edx",0);
++	&mov	("ecx",&DWP(24,"edi"));
++	&sbb	("eax",0);
++	&mov	("edx",&DWP(28,"edi"));
++	&sbb	("ebx",0);
++	&sbb	("ecx",1);
++	&sbb	("edx",-1);
++	&sbb	("esi",0);
++
++	# Note that because mod has special form, i.e. consists of
++	# 0xffffffff, 1 and 0s, we can conditionally synthesize it by
++	# by using borrow.
++
++	¬	("esi");
++	&mov	("eax",&DWP(0,"edi"));
++	&mov	("ebp","esi");
++	&mov	("ebx",&DWP(4,"edi"));
++	&shr	("ebp",31);
++	&mov	("ecx",&DWP(8,"edi"));
++	&sub	("eax","esi");
++	&mov	("edx",&DWP(12,"edi"));
++	&sbb	("ebx","esi");
++	&mov	(&DWP(0,"edi"),"eax");
++	&sbb	("ecx","esi");
++	&mov	(&DWP(4,"edi"),"ebx");
++	&sbb	("edx",0);
++	&mov	(&DWP(8,"edi"),"ecx");
++	&mov	(&DWP(12,"edi"),"edx");
++
++	&mov	("eax",&DWP(16,"edi"));
++	&mov	("ebx",&DWP(20,"edi"));
++	&mov	("ecx",&DWP(24,"edi"));
++	&sbb	("eax",0);
++	&mov	("edx",&DWP(28,"edi"));
++	&sbb	("ebx",0);
++	&mov	(&DWP(16,"edi"),"eax");
++	&sbb	("ecx","ebp");
++	&mov	(&DWP(20,"edi"),"ebx");
++	&sbb	("edx","esi");
++	&mov	(&DWP(24,"edi"),"ecx");
++	&mov	(&DWP(28,"edi"),"edx");
++
++	&ret	();
++&function_end_B("_ecp_nistz256_add");
++
++########################################################################
++# void ecp_nistz256_sub(BN_ULONG edi[8],const BN_ULONG esi[8],
++#					const BN_ULONG ebp[8]);
++&function_begin("ecp_nistz256_sub");
++	&mov	("esi",&wparam(1));
++	&mov	("ebp",&wparam(2));
++	&mov	("edi",&wparam(0));
++	&call	("_ecp_nistz256_sub");
++&function_end("ecp_nistz256_sub");
++
++&function_begin_B("_ecp_nistz256_sub");
++	&mov	("eax",&DWP(0,"esi"));
++	&mov	("ebx",&DWP(4,"esi"));
++	&mov	("ecx",&DWP(8,"esi"));
++	&sub	("eax",&DWP(0,"ebp"));
++	&mov	("edx",&DWP(12,"esi"));
++	&sbb	("ebx",&DWP(4,"ebp"));
++	&mov	(&DWP(0,"edi"),"eax");
++	&sbb	("ecx",&DWP(8,"ebp"));
++	&mov	(&DWP(4,"edi"),"ebx");
++	&sbb	("edx",&DWP(12,"ebp"));
++	&mov	(&DWP(8,"edi"),"ecx");
++	&mov	(&DWP(12,"edi"),"edx");
++
++	&mov	("eax",&DWP(16,"esi"));
++	&mov	("ebx",&DWP(20,"esi"));
++	&mov	("ecx",&DWP(24,"esi"));
++	&sbb	("eax",&DWP(16,"ebp"));
++	&mov	("edx",&DWP(28,"esi"));
++	&sbb	("ebx",&DWP(20,"ebp"));
++	&sbb	("ecx",&DWP(24,"ebp"));
++	&mov	(&DWP(16,"edi"),"eax");
++	&sbb	("edx",&DWP(28,"ebp"));
++	&mov	(&DWP(20,"edi"),"ebx");
++	&sbb	("esi","esi");			# broadcast borrow bit
++	&mov	(&DWP(24,"edi"),"ecx");
++	&mov	(&DWP(28,"edi"),"edx");
++
++	# if a-b borrows, add modulus.
++	#
++	# Note that because mod has special form, i.e. consists of
++	# 0xffffffff, 1 and 0s, we can conditionally synthesize it by
++	# assigning borrow bit to one register, %ebp, and its negative
++	# to another, %esi. But we started by calculating %esi...
++
++	&mov	("eax",&DWP(0,"edi"));
++	&mov	("ebp","esi");
++	&mov	("ebx",&DWP(4,"edi"));
++	&shr	("ebp",31);
++	&mov	("ecx",&DWP(8,"edi"));
++	&add	("eax","esi");
++	&mov	("edx",&DWP(12,"edi"));
++	&adc	("ebx","esi");
++	&mov	(&DWP(0,"edi"),"eax");
++	&adc	("ecx","esi");
++	&mov	(&DWP(4,"edi"),"ebx");
++	&adc	("edx",0);
++	&mov	(&DWP(8,"edi"),"ecx");
++	&mov	(&DWP(12,"edi"),"edx");
++
++	&mov	("eax",&DWP(16,"edi"));
++	&mov	("ebx",&DWP(20,"edi"));
++	&mov	("ecx",&DWP(24,"edi"));
++	&adc	("eax",0);
++	&mov	("edx",&DWP(28,"edi"));
++	&adc	("ebx",0);
++	&mov	(&DWP(16,"edi"),"eax");
++	&adc	("ecx","ebp");
++	&mov	(&DWP(20,"edi"),"ebx");
++	&adc	("edx","esi");
++	&mov	(&DWP(24,"edi"),"ecx");
++	&mov	(&DWP(28,"edi"),"edx");
++
++	&ret	();
++&function_end_B("_ecp_nistz256_sub");
++
++########################################################################
++# void ecp_nistz256_neg(BN_ULONG edi[8],const BN_ULONG esi[8]);
++&function_begin("ecp_nistz256_neg");
++	&mov	("ebp",&wparam(1));
++	&mov	("edi",&wparam(0));
++
++	&xor	("eax","eax");
++	&stack_push(8);
++	&mov	(&DWP(0,"esp"),"eax");
++	&mov	("esi","esp");
++	&mov	(&DWP(4,"esp"),"eax");
++	&mov	(&DWP(8,"esp"),"eax");
++	&mov	(&DWP(12,"esp"),"eax");
++	&mov	(&DWP(16,"esp"),"eax");
++	&mov	(&DWP(20,"esp"),"eax");
++	&mov	(&DWP(24,"esp"),"eax");
++	&mov	(&DWP(28,"esp"),"eax");
++	
++	&call	("_ecp_nistz256_sub");
++
++	&stack_pop(8);
++&function_end("ecp_nistz256_neg");
++
++&function_begin_B("_picup_eax");
++	&mov	("eax",&DWP(0,"esp"));
++	&ret	();
++&function_end_B("_picup_eax");
++
++########################################################################
++# void ecp_nistz256_to_mont(BN_ULONG edi[8],const BN_ULONG esi[8]);
++&function_begin("ecp_nistz256_to_mont");
++	&mov	("esi",&wparam(1));
++	&call	("_picup_eax");
++    &set_label("pic");
++	&lea	("ebp",&DWP(&label("RR")."-".&label("pic"),"eax"));
++						if ($sse2) {
++	&picmeup("eax","OPENSSL_ia32cap_P","eax",&label("pic"));
++	&mov	("eax",&DWP(0,"eax"));		}
++	&mov	("edi",&wparam(0));
++	&call	("_ecp_nistz256_mul_mont");
++&function_end("ecp_nistz256_to_mont");
++
++########################################################################
++# void ecp_nistz256_from_mont(BN_ULONG edi[8],const BN_ULONG esi[8]);
++&function_begin("ecp_nistz256_from_mont");
++	&mov	("esi",&wparam(1));
++	&call	("_picup_eax");
++    &set_label("pic");
++	&lea	("ebp",&DWP(&label("ONE")."-".&label("pic"),"eax"));
++						if ($sse2) {
++	&picmeup("eax","OPENSSL_ia32cap_P","eax",&label("pic"));
++	&mov	("eax",&DWP(0,"eax"));		}
++	&mov	("edi",&wparam(0));
++	&call	("_ecp_nistz256_mul_mont");
++&function_end("ecp_nistz256_from_mont");
++
++########################################################################
++# void ecp_nistz256_mul_mont(BN_ULONG edi[8],const BN_ULONG esi[8],
++#					     const BN_ULONG ebp[8]);
++&function_begin("ecp_nistz256_mul_mont");
++	&mov	("esi",&wparam(1));
++	&mov	("ebp",&wparam(2));
++						if ($sse2) {
++	&call	("_picup_eax");
++    &set_label("pic");
++	&picmeup("eax","OPENSSL_ia32cap_P","eax",&label("pic"));
++	&mov	("eax",&DWP(0,"eax"));		}
++	&mov	("edi",&wparam(0));
++	&call	("_ecp_nistz256_mul_mont");
++&function_end("ecp_nistz256_mul_mont");
++
++########################################################################
++# void ecp_nistz256_sqr_mont(BN_ULONG edi[8],const BN_ULONG esi[8]);
++&function_begin("ecp_nistz256_sqr_mont");
++	&mov	("esi",&wparam(1));
++						if ($sse2) {
++	&call	("_picup_eax");
++    &set_label("pic");
++	&picmeup("eax","OPENSSL_ia32cap_P","eax",&label("pic"));
++	&mov	("eax",&DWP(0,"eax"));		}
++	&mov	("edi",&wparam(0));
++	&mov	("ebp","esi");
++	&call	("_ecp_nistz256_mul_mont");
++&function_end("ecp_nistz256_sqr_mont");
++
++&function_begin_B("_ecp_nistz256_mul_mont");
++						if ($sse2) {
++	&and	("eax",1<<24|1<<26);
++	&cmp	("eax",1<<24|1<<26);		# see if XMM+SSE2 is on
++	&jne	(&label("mul_mont_ialu"));
++
++	########################################
++	# SSE2 code path featuring 32x16-bit
++	# multiplications is ~2x faster than
++	# IALU counterpart (except on Atom)...
++	########################################
++	# stack layout:
++	# +------------------------------------+< %esp
++	# | 7 16-byte temporary XMM words,     |
++	# | "sliding" toward lower address     |
++	# .                                    .
++	# +------------------------------------+
++	# | unused XMM word                    |
++	# +------------------------------------+< +128,%ebx
++	# | 8 16-byte XMM words holding copies |
++	# | of a[i]<<64|a[i]                   |
++	# .                                    .
++	# .                                    .
++	# +------------------------------------+< +256
++	&mov	("edx","esp");
++	&sub	("esp",0x100);
++
++	&movd	("xmm7",&DWP(0,"ebp"));		# b[0] -> 0000.00xy
++	&lea	("ebp",&DWP(4,"ebp"));
++	&pcmpeqd("xmm6","xmm6");
++	&psrlq	("xmm6",48);			# compose 0xffff<<64|0xffff
++
++	&pshuflw("xmm7","xmm7",0b11011100);	# 0000.00xy -> 0000.0x0y
++	&and	("esp",-64);
++	&pshufd	("xmm7","xmm7",0b11011100);	# 0000.0x0y -> 000x.000y
++	&lea	("ebx",&DWP(0x80,"esp"));
++
++	&movd	("xmm0",&DWP(4*0,"esi"));	# a[0] -> 0000.00xy
++	&pshufd	("xmm0","xmm0",0b11001100);	# 0000.00xy -> 00xy.00xy
++	&movd	("xmm1",&DWP(4*1,"esi"));	# a[1] -> ...
++	&movdqa	(&QWP(0x00,"ebx"),"xmm0");	# offload converted a[0]
++	&pmuludq("xmm0","xmm7");		# a[0]*b[0]
++
++	&movd	("xmm2",&DWP(4*2,"esi"));
++	&pshufd	("xmm1","xmm1",0b11001100);
++	&movdqa	(&QWP(0x10,"ebx"),"xmm1");
++	&pmuludq("xmm1","xmm7");		# a[1]*b[0]
++
++	 &movq	("xmm4","xmm0");		# clear upper 64 bits
++	 &pslldq("xmm4",6);
++	 &paddq	("xmm4","xmm0");
++	 &movdqa("xmm5","xmm4");
++	 &psrldq("xmm4",10);			# upper 32 bits of a[0]*b[0]
++	 &pand	("xmm5","xmm6");		# lower 32 bits of a[0]*b[0]
++
++	# Upper half of a[0]*b[i] is carried into next multiplication
++	# iteration, while lower one "participates" in actual reduction.
++	# Normally latter is done by accumulating result of multiplication
++	# of modulus by "magic" digit, but thanks to special form of modulus
++	# and "magic" digit it can be performed only with additions and
++	# subtractions (see note in IALU section below). Note that we are
++	# not bothered with carry bits, they are accumulated in "flatten"
++	# phase after all multiplications and reductions.
++
++	&movd	("xmm3",&DWP(4*3,"esi"));
++	&pshufd	("xmm2","xmm2",0b11001100);
++	&movdqa	(&QWP(0x20,"ebx"),"xmm2");
++	&pmuludq("xmm2","xmm7");		# a[2]*b[0]
++	 &paddq	("xmm1","xmm4");		# a[1]*b[0]+hw(a[0]*b[0]), carry
++	&movdqa	(&QWP(0x00,"esp"),"xmm1");	# t[0]
++
++	&movd	("xmm0",&DWP(4*4,"esi"));
++	&pshufd	("xmm3","xmm3",0b11001100);
++	&movdqa	(&QWP(0x30,"ebx"),"xmm3");
++	&pmuludq("xmm3","xmm7");		# a[3]*b[0]
++	&movdqa	(&QWP(0x10,"esp"),"xmm2");
++
++	&movd	("xmm1",&DWP(4*5,"esi"));
++	&pshufd	("xmm0","xmm0",0b11001100);
++	&movdqa	(&QWP(0x40,"ebx"),"xmm0");
++	&pmuludq("xmm0","xmm7");		# a[4]*b[0]
++	 &paddq	("xmm3","xmm5");		# a[3]*b[0]+lw(a[0]*b[0]), reduction step
++	&movdqa	(&QWP(0x20,"esp"),"xmm3");
++
++	&movd	("xmm2",&DWP(4*6,"esi"));
++	&pshufd	("xmm1","xmm1",0b11001100);
++	&movdqa	(&QWP(0x50,"ebx"),"xmm1");
++	&pmuludq("xmm1","xmm7");		# a[5]*b[0]
++	&movdqa	(&QWP(0x30,"esp"),"xmm0");
++	 &pshufd("xmm4","xmm5",0b10110001);	# xmm4 = xmm5<<32, reduction step
++
++	&movd	("xmm3",&DWP(4*7,"esi"));
++	&pshufd	("xmm2","xmm2",0b11001100);
++	&movdqa	(&QWP(0x60,"ebx"),"xmm2");
++	&pmuludq("xmm2","xmm7");		# a[6]*b[0]
++	&movdqa	(&QWP(0x40,"esp"),"xmm1");
++	 &psubq	("xmm4","xmm5");		# xmm4 = xmm5*0xffffffff, reduction step
++
++	&movd	("xmm0",&DWP(0,"ebp"));		# b[1] -> 0000.00xy
++	&pshufd	("xmm3","xmm3",0b11001100);
++	&movdqa	(&QWP(0x70,"ebx"),"xmm3");
++	&pmuludq("xmm3","xmm7");		# a[7]*b[0]
++
++	&pshuflw("xmm7","xmm0",0b11011100);	# 0000.00xy -> 0000.0x0y
++	&movdqa	("xmm0",&QWP(0x00,"ebx"));	# pre-load converted a[0]
++	&pshufd	("xmm7","xmm7",0b11011100);	# 0000.0x0y -> 000x.000y
++
++	&mov	("ecx",6);
++	&lea	("ebp",&DWP(4,"ebp"));
++	&jmp	(&label("madd_sse2"));
++
++&set_label("madd_sse2",16);
++	 &paddq	("xmm2","xmm5");		# a[6]*b[i-1]+lw(a[0]*b[i-1]), reduction step [modulo-scheduled]
++	 &paddq	("xmm3","xmm4");		# a[7]*b[i-1]+lw(a[0]*b[i-1])*0xffffffff, reduction step [modulo-scheduled]
++	&movdqa	("xmm1",&QWP(0x10,"ebx"));
++	&pmuludq("xmm0","xmm7");		# a[0]*b[i]
++	 &movdqa(&QWP(0x50,"esp"),"xmm2");
++
++	&movdqa	("xmm2",&QWP(0x20,"ebx"));
++	&pmuludq("xmm1","xmm7");		# a[1]*b[i]
++	 &movdqa(&QWP(0x60,"esp"),"xmm3");
++	&paddq	("xmm0",&QWP(0x00,"esp"));
++
++	&movdqa	("xmm3",&QWP(0x30,"ebx"));
++	&pmuludq("xmm2","xmm7");		# a[2]*b[i]
++	 &movq	("xmm4","xmm0");		# clear upper 64 bits
++	 &pslldq("xmm4",6);
++	&paddq	("xmm1",&QWP(0x10,"esp"));
++	 &paddq	("xmm4","xmm0");
++	 &movdqa("xmm5","xmm4");
++	 &psrldq("xmm4",10);			# upper 33 bits of a[0]*b[i]+t[0]
++
++	&movdqa	("xmm0",&QWP(0x40,"ebx"));
++	&pmuludq("xmm3","xmm7");		# a[3]*b[i]
++	 &paddq	("xmm1","xmm4");		# a[1]*b[i]+hw(a[0]*b[i]), carry
++	&paddq	("xmm2",&QWP(0x20,"esp"));
++	&movdqa	(&QWP(0x00,"esp"),"xmm1");
++
++	&movdqa	("xmm1",&QWP(0x50,"ebx"));
++	&pmuludq("xmm0","xmm7");		# a[4]*b[i]
++	&paddq	("xmm3",&QWP(0x30,"esp"));
++	&movdqa	(&QWP(0x10,"esp"),"xmm2");
++	 &pand	("xmm5","xmm6");		# lower 32 bits of a[0]*b[i]
++
++	&movdqa	("xmm2",&QWP(0x60,"ebx"));
++	&pmuludq("xmm1","xmm7");		# a[5]*b[i]
++	 &paddq	("xmm3","xmm5");		# a[3]*b[i]+lw(a[0]*b[i]), reduction step
++	&paddq	("xmm0",&QWP(0x40,"esp"));
++	&movdqa	(&QWP(0x20,"esp"),"xmm3");
++	 &pshufd("xmm4","xmm5",0b10110001);	# xmm4 = xmm5<<32, reduction step
++
++	&movdqa	("xmm3","xmm7");
++	&pmuludq("xmm2","xmm7");		# a[6]*b[i]
++	 &movd	("xmm7",&DWP(0,"ebp"));		# b[i++] -> 0000.00xy
++	 &lea	("ebp",&DWP(4,"ebp"));
++	&paddq	("xmm1",&QWP(0x50,"esp"));
++	 &psubq	("xmm4","xmm5");		# xmm4 = xmm5*0xffffffff, reduction step
++	&movdqa	(&QWP(0x30,"esp"),"xmm0");
++	 &pshuflw("xmm7","xmm7",0b11011100);	# 0000.00xy -> 0000.0x0y
++
++	&pmuludq("xmm3",&QWP(0x70,"ebx"));	# a[7]*b[i]
++	 &pshufd("xmm7","xmm7",0b11011100);	# 0000.0x0y -> 000x.000y
++	 &movdqa("xmm0",&QWP(0x00,"ebx"));	# pre-load converted a[0]
++	&movdqa	(&QWP(0x40,"esp"),"xmm1");
++	&paddq	("xmm2",&QWP(0x60,"esp"));
++
++	&dec	("ecx");
++	&jnz	(&label("madd_sse2"));
++
++	 &paddq	("xmm2","xmm5");		# a[6]*b[6]+lw(a[0]*b[6]), reduction step [modulo-scheduled]
++	 &paddq	("xmm3","xmm4");		# a[7]*b[6]+lw(a[0]*b[6])*0xffffffff, reduction step [modulo-scheduled]
++	&movdqa	("xmm1",&QWP(0x10,"ebx"));
++	&pmuludq("xmm0","xmm7");		# a[0]*b[7]
++	 &movdqa(&QWP(0x50,"esp"),"xmm2");
++
++	&movdqa	("xmm2",&QWP(0x20,"ebx"));
++	&pmuludq("xmm1","xmm7");		# a[1]*b[7]
++	 &movdqa(&QWP(0x60,"esp"),"xmm3");
++	&paddq	("xmm0",&QWP(0x00,"esp"));
++
++	&movdqa	("xmm3",&QWP(0x30,"ebx"));
++	&pmuludq("xmm2","xmm7");		# a[2]*b[7]
++	 &movq	("xmm4","xmm0");		# clear upper 64 bits
++	 &pslldq("xmm4",6);
++	&paddq	("xmm1",&QWP(0x10,"esp"));
++	 &paddq	("xmm4","xmm0");
++	 &movdqa("xmm5","xmm4");
++	 &psrldq("xmm4",10);			# upper 33 bits of a[0]*b[i]+t[0]
++
++	&movdqa	("xmm0",&QWP(0x40,"ebx"));
++	&pmuludq("xmm3","xmm7");		# a[3]*b[7]
++	 &paddq	("xmm1","xmm4");		# a[1]*b[7]+hw(a[0]*b[7]), carry
++	&paddq	("xmm2",&QWP(0x20,"esp"));
++	&movdqa	(&QWP(0x00,"esp"),"xmm1");
++
++	&movdqa	("xmm1",&QWP(0x50,"ebx"));
++	&pmuludq("xmm0","xmm7");		# a[4]*b[7]
++	&paddq	("xmm3",&QWP(0x30,"esp"));
++	&movdqa	(&QWP(0x10,"esp"),"xmm2");
++	 &pand	("xmm5","xmm6");		# lower 32 bits of a[0]*b[i]
++
++	&movdqa	("xmm2",&QWP(0x60,"ebx"));
++	&pmuludq("xmm1","xmm7");		# a[5]*b[7]
++	 &paddq	("xmm3","xmm5");		# reduction step
++	&paddq	("xmm0",&QWP(0x40,"esp"));
++	&movdqa	(&QWP(0x20,"esp"),"xmm3");
++	 &pshufd("xmm4","xmm5",0b10110001);	# xmm4 = xmm5<<32, reduction step
++
++	&movdqa	("xmm3",&QWP(0x70,"ebx"));
++	&pmuludq("xmm2","xmm7");		# a[6]*b[7]
++	&paddq	("xmm1",&QWP(0x50,"esp"));
++	 &psubq	("xmm4","xmm5");		# xmm4 = xmm5*0xffffffff, reduction step
++	&movdqa	(&QWP(0x30,"esp"),"xmm0");
++
++	&pmuludq("xmm3","xmm7");		# a[7]*b[7]
++	&pcmpeqd("xmm7","xmm7");
++	&movdqa	("xmm0",&QWP(0x00,"esp"));
++	&pslldq	("xmm7",8);
++	&movdqa	(&QWP(0x40,"esp"),"xmm1");
++	&paddq	("xmm2",&QWP(0x60,"esp"));
++
++	 &paddq	("xmm2","xmm5");		# a[6]*b[7]+lw(a[0]*b[7]), reduction step
++	 &paddq	("xmm3","xmm4");		# a[6]*b[7]+lw(a[0]*b[7])*0xffffffff, reduction step
++	 &movdqa(&QWP(0x50,"esp"),"xmm2");
++	 &movdqa(&QWP(0x60,"esp"),"xmm3");
++
++	&movdqa	("xmm1",&QWP(0x10,"esp"));
++	&movdqa	("xmm2",&QWP(0x20,"esp"));
++	&movdqa	("xmm3",&QWP(0x30,"esp"));
++
++	&movq	("xmm4","xmm0");		# "flatten"
++	&pand	("xmm0","xmm7");
++	&xor	("ebp","ebp");
++	&pslldq	("xmm4",6);
++	 &movq	("xmm5","xmm1");
++	&paddq	("xmm0","xmm4");
++	 &pand	("xmm1","xmm7");
++	&psrldq	("xmm0",6);
++	&movd	("eax","xmm0");
++	&psrldq	("xmm0",4);
++
++	&paddq	("xmm5","xmm0");
++	&movdqa	("xmm0",&QWP(0x40,"esp"));
++	&sub	("eax",-1);			# start subtracting modulus,
++						# this is used to determine
++						# if result is larger/smaller
++						# than modulus (see below)
++	&pslldq	("xmm5",6);
++	 &movq	("xmm4","xmm2");
++	&paddq	("xmm1","xmm5");
++	 &pand	("xmm2","xmm7");
++	&psrldq	("xmm1",6);
++	&mov	(&DWP(4*0,"edi"),"eax");
++	&movd	("eax","xmm1");
++	&psrldq	("xmm1",4);
++
++	&paddq	("xmm4","xmm1");
++	&movdqa	("xmm1",&QWP(0x50,"esp"));
++	&sbb	("eax",-1);
++	&pslldq	("xmm4",6);
++	 &movq	("xmm5","xmm3");
++	&paddq	("xmm2","xmm4");
++	 &pand	("xmm3","xmm7");
++	&psrldq	("xmm2",6);
++	&mov	(&DWP(4*1,"edi"),"eax");
++	&movd	("eax","xmm2");
++	&psrldq	("xmm2",4);
++
++	&paddq	("xmm5","xmm2");
++	&movdqa	("xmm2",&QWP(0x60,"esp"));
++	&sbb	("eax",-1);
++	&pslldq	("xmm5",6);
++	 &movq	("xmm4","xmm0");
++	&paddq	("xmm3","xmm5");
++	 &pand	("xmm0","xmm7");
++	&psrldq	("xmm3",6);
++	&mov	(&DWP(4*2,"edi"),"eax");
++	&movd	("eax","xmm3");
++	&psrldq	("xmm3",4);
++
++	&paddq	("xmm4","xmm3");
++	&sbb	("eax",0);
++	&pslldq	("xmm4",6);
++	 &movq	("xmm5","xmm1");
++	&paddq	("xmm0","xmm4");
++	 &pand	("xmm1","xmm7");
++	&psrldq	("xmm0",6);
++	&mov	(&DWP(4*3,"edi"),"eax");
++	&movd	("eax","xmm0");
++	&psrldq	("xmm0",4);
++
++	&paddq	("xmm5","xmm0");
++	&sbb	("eax",0);
++	&pslldq	("xmm5",6);
++	 &movq	("xmm4","xmm2");
++	&paddq	("xmm1","xmm5");
++	 &pand	("xmm2","xmm7");
++	&psrldq	("xmm1",6);
++	&movd	("ebx","xmm1");
++	&psrldq	("xmm1",4);
++	&mov	("esp","edx");
++
++	&paddq	("xmm4","xmm1");
++	&pslldq	("xmm4",6);
++	&paddq	("xmm2","xmm4");
++	&psrldq	("xmm2",6);
++	&movd	("ecx","xmm2");
++	&psrldq	("xmm2",4);
++	&sbb	("ebx",0);
++	&movd	("edx","xmm2");
++	&pextrw	("esi","xmm2",2);		# top-most overflow bit
++	&sbb	("ecx",1);
++	&sbb	("edx",-1);
++	&sbb	("esi",0);			# borrow from subtraction
++
++	# Final step is "if result > mod, subtract mod", and at this point
++	# we have result - mod written to output buffer, as well as borrow
++	# bit from this subtraction, and if borrow bit is set, we add
++	# modulus back.
++	#
++	# Note that because mod has special form, i.e. consists of
++	# 0xffffffff, 1 and 0s, we can conditionally synthesize it by
++	# assigning borrow bit to one register, %ebp, and its negative
++	# to another, %esi. But we started by calculating %esi...
++
++	&sub	("ebp","esi");
++	&add	(&DWP(4*0,"edi"),"esi");	# add modulus or zero
++	&adc	(&DWP(4*1,"edi"),"esi");
++	&adc	(&DWP(4*2,"edi"),"esi");
++	&adc	(&DWP(4*3,"edi"),0);
++	&adc	("eax",0);
++	&adc	("ebx",0);
++	&mov	(&DWP(4*4,"edi"),"eax");
++	&adc	("ecx","ebp");
++	&mov	(&DWP(4*5,"edi"),"ebx");
++	&adc	("edx","esi");
++	&mov	(&DWP(4*6,"edi"),"ecx");
++	&mov	(&DWP(4*7,"edi"),"edx");
++
++	&ret	();
++
++&set_label("mul_mont_ialu",16);			}
++
++	########################################
++	# IALU code path suitable for all CPUs.
++	########################################
++	# stack layout:
++	# +------------------------------------+< %esp
++	# | 8 32-bit temporary words, accessed |
++	# | as circular buffer                 |
++	# .                                    .
++	# .                                    .
++	# +------------------------------------+< +32
++	# | offloaded destination pointer      |
++	# +------------------------------------+
++	# | unused                             |
++	# +------------------------------------+< +40
++	&sub	("esp",10*4);
++
++	&mov	("eax",&DWP(0*4,"esi"));		# a[0]
++	&mov	("ebx",&DWP(0*4,"ebp"));		# b[0]
++	&mov	(&DWP(8*4,"esp"),"edi");		# off-load dst ptr
++
++	&mul	("ebx");				# a[0]*b[0]
++	&mov	(&DWP(0*4,"esp"),"eax");		# t[0]
++	&mov	("eax",&DWP(1*4,"esi"));
++	&mov	("ecx","edx")
++
++	&mul	("ebx");				# a[1]*b[0]
++	&add	("ecx","eax");
++	&mov	("eax",&DWP(2*4,"esi"));
++	&adc	("edx",0);
++	&mov	(&DWP(1*4,"esp"),"ecx");		# t[1]
++	&mov	("ecx","edx");
++
++	&mul	("ebx");				# a[2]*b[0]
++	&add	("ecx","eax");
++	&mov	("eax",&DWP(3*4,"esi"));
++	&adc	("edx",0);
++	&mov	(&DWP(2*4,"esp"),"ecx");		# t[2]
++	&mov	("ecx","edx");
++
++	&mul	("ebx");				# a[3]*b[0]
++	&add	("ecx","eax");
++	&mov	("eax",&DWP(4*4,"esi"));
++	&adc	("edx",0);
++	&mov	(&DWP(3*4,"esp"),"ecx");		# t[3]
++	&mov	("ecx","edx");
++
++	&mul	("ebx");				# a[4]*b[0]
++	&add	("ecx","eax");
++	&mov	("eax",&DWP(5*4,"esi"));
++	&adc	("edx",0);
++	&mov	(&DWP(4*4,"esp"),"ecx");		# t[4]
++	&mov	("ecx","edx");
++
++	&mul	("ebx");				# a[5]*b[0]
++	&add	("ecx","eax");
++	&mov	("eax",&DWP(6*4,"esi"));
++	&adc	("edx",0);
++	&mov	(&DWP(5*4,"esp"),"ecx");		# t[5]
++	&mov	("ecx","edx");
++
++	&mul	("ebx");				# a[6]*b[0]
++	&add	("ecx","eax");
++	&mov	("eax",&DWP(7*4,"esi"));
++	&adc	("edx",0);
++	&mov	(&DWP(6*4,"esp"),"ecx");		# t[6]
++	&mov	("ecx","edx");
++
++	&xor	("edi","edi");				# initial top-most carry
++	&mul	("ebx");				# a[7]*b[0]
++	&add	("ecx","eax");				# t[7]
++	&mov	("eax",&DWP(0*4,"esp"));		# t[0]
++	&adc	("edx",0);				# t[8]
++
++for ($i=0;$i<7;$i++) {
++	my $j=$i+1;
++
++	# Reduction iteration is normally performed by accumulating
++	# result of multiplication of modulus by "magic" digit [and
++	# omitting least significant word, which is guaranteed to
++	# be 0], but thanks to special form of modulus and "magic"
++	# digit being equal to least significant word, it can be
++	# performed with additions and subtractions alone. Indeed:
++	#
++	#        ffff.0001.0000.0000.0000.ffff.ffff.ffff
++	# *                                         abcd
++	# + xxxx.xxxx.xxxx.xxxx.xxxx.xxxx.xxxx.xxxx.abcd
++	#
++	# Now observing that ff..ff*x = (2^n-1)*x = 2^n*x-x, we
++	# rewrite above as:
++	#
++	#   xxxx.xxxx.xxxx.xxxx.xxxx.xxxx.xxxx.xxxx.abcd
++	# + abcd.0000.abcd.0000.0000.abcd.0000.0000.0000
++	# -      abcd.0000.0000.0000.0000.0000.0000.abcd
++	#
++	# or marking redundant operations:
++	#
++	#   xxxx.xxxx.xxxx.xxxx.xxxx.xxxx.xxxx.xxxx.----
++	# + abcd.0000.abcd.0000.0000.abcd.----.----.----
++	# -      abcd.----.----.----.----.----.----.----
++
++	&add	(&DWP((($i+3)%8)*4,"esp"),"eax");	# t[3]+=t[0]
++	&adc	(&DWP((($i+4)%8)*4,"esp"),0);		# t[4]+=0
++	&adc	(&DWP((($i+5)%8)*4,"esp"),0);		# t[5]+=0
++	&adc	(&DWP((($i+6)%8)*4,"esp"),"eax");	# t[6]+=t[0]
++	&adc	("ecx",0);				# t[7]+=0
++	&adc	("edx","eax");				# t[8]+=t[0]
++	&adc	("edi",0);				# top-most carry
++	 &mov	("ebx",&DWP($j*4,"ebp"));		# b[i]
++	&sub	("ecx","eax");				# t[7]-=t[0]
++	 &mov	("eax",&DWP(0*4,"esi"));		# a[0]
++	&sbb	("edx",0);				# t[8]-=0
++	&mov	(&DWP((($i+7)%8)*4,"esp"),"ecx");
++	&sbb	("edi",0);				# top-most carry,
++							# keep in mind that
++							# netto result is
++							# *addition* of value
++							# with (abcd<<32)-abcd
++							# on top, so that
++							# underflow is
++							# impossible, because
++							# (abcd<<32)-abcd
++							# doesn't underflow
++	&mov	(&DWP((($i+8)%8)*4,"esp"),"edx");
++
++	&mul	("ebx");				# a[0]*b[i]
++	&add	("eax",&DWP((($j+0)%8)*4,"esp"));
++	&adc	("edx",0);
++	&mov	(&DWP((($j+0)%8)*4,"esp"),"eax");
++	&mov	("eax",&DWP(1*4,"esi"));
++	&mov	("ecx","edx")
++
++	&mul	("ebx");				# a[1]*b[i]
++	&add	("ecx",&DWP((($j+1)%8)*4,"esp"));
++	&adc	("edx",0);
++	&add	("ecx","eax");
++	&adc	("edx",0);
++	&mov	("eax",&DWP(2*4,"esi"));
++	&mov	(&DWP((($j+1)%8)*4,"esp"),"ecx");
++	&mov	("ecx","edx");
++
++	&mul	("ebx");				# a[2]*b[i]
++	&add	("ecx",&DWP((($j+2)%8)*4,"esp"));
++	&adc	("edx",0);
++	&add	("ecx","eax");
++	&adc	("edx",0);
++	&mov	("eax",&DWP(3*4,"esi"));
++	&mov	(&DWP((($j+2)%8)*4,"esp"),"ecx");
++	&mov	("ecx","edx");
++
++	&mul	("ebx");				# a[3]*b[i]
++	&add	("ecx",&DWP((($j+3)%8)*4,"esp"));
++	&adc	("edx",0);
++	&add	("ecx","eax");
++	&adc	("edx",0);
++	&mov	("eax",&DWP(4*4,"esi"));
++	&mov	(&DWP((($j+3)%8)*4,"esp"),"ecx");
++	&mov	("ecx","edx");
++
++	&mul	("ebx");				# a[4]*b[i]
++	&add	("ecx",&DWP((($j+4)%8)*4,"esp"));
++	&adc	("edx",0);
++	&add	("ecx","eax");
++	&adc	("edx",0);
++	&mov	("eax",&DWP(5*4,"esi"));
++	&mov	(&DWP((($j+4)%8)*4,"esp"),"ecx");
++	&mov	("ecx","edx");
++
++	&mul	("ebx");				# a[5]*b[i]
++	&add	("ecx",&DWP((($j+5)%8)*4,"esp"));
++	&adc	("edx",0);
++	&add	("ecx","eax");
++	&adc	("edx",0);
++	&mov	("eax",&DWP(6*4,"esi"));
++	&mov	(&DWP((($j+5)%8)*4,"esp"),"ecx");
++	&mov	("ecx","edx");
++
++	&mul	("ebx");				# a[6]*b[i]
++	&add	("ecx",&DWP((($j+6)%8)*4,"esp"));
++	&adc	("edx",0);
++	&add	("ecx","eax");
++	&adc	("edx",0);
++	&mov	("eax",&DWP(7*4,"esi"));
++	&mov	(&DWP((($j+6)%8)*4,"esp"),"ecx");
++	&mov	("ecx","edx");
++
++	&mul	("ebx");				# a[7]*b[i]
++	&add	("ecx",&DWP((($j+7)%8)*4,"esp"));
++	&adc	("edx",0);
++	&add	("ecx","eax");				# t[7]
++	&mov	("eax",&DWP((($j+0)%8)*4,"esp"));	# t[0]
++	&adc	("edx","edi");				# t[8]
++	&mov	("edi",0);
++	&adc	("edi",0);				# top-most carry
++}
++	&mov	("ebp",&DWP(8*4,"esp"));		# restore dst ptr
++	&xor	("esi","esi");
++	my $j=$i+1;
++
++	# last multiplication-less reduction
++	&add	(&DWP((($i+3)%8)*4,"esp"),"eax");	# t[3]+=t[0]
++	&adc	(&DWP((($i+4)%8)*4,"esp"),0);		# t[4]+=0
++	&adc	(&DWP((($i+5)%8)*4,"esp"),0);		# t[5]+=0
++	&adc	(&DWP((($i+6)%8)*4,"esp"),"eax");	# t[6]+=t[0]
++	&adc	("ecx",0);				# t[7]+=0
++	&adc	("edx","eax");				# t[8]+=t[0]
++	&adc	("edi",0);				# top-most carry
++	 &mov	("ebx",&DWP((($j+1)%8)*4,"esp"));
++	&sub	("ecx","eax");				# t[7]-=t[0]
++	 &mov	("eax",&DWP((($j+0)%8)*4,"esp"));
++	&sbb	("edx",0);				# t[8]-=0
++	&mov	(&DWP((($i+7)%8)*4,"esp"),"ecx");
++	&sbb	("edi",0);				# top-most carry
++	&mov	(&DWP((($i+8)%8)*4,"esp"),"edx");
++
++	# Final step is "if result > mod, subtract mod", but we do it
++	# "other way around", namely write result - mod to output buffer
++	# and if subtraction borrowed, add modulus back.
++
++	&mov	("ecx",&DWP((($j+2)%8)*4,"esp"));
++	&sub	("eax",-1);
++	&mov	("edx",&DWP((($j+3)%8)*4,"esp"));
++	&sbb	("ebx",-1);
++	&mov	(&DWP(0*4,"ebp"),"eax");
++	&sbb	("ecx",-1);
++	&mov	(&DWP(1*4,"ebp"),"ebx");
++	&sbb	("edx",0);
++	&mov	(&DWP(2*4,"ebp"),"ecx");
++	&mov	(&DWP(3*4,"ebp"),"edx");
++
++	&mov	("eax",&DWP((($j+4)%8)*4,"esp"));
++	&mov	("ebx",&DWP((($j+5)%8)*4,"esp"));
++	&mov	("ecx",&DWP((($j+6)%8)*4,"esp"));
++	&sbb	("eax",0);
++	&mov	("edx",&DWP((($j+7)%8)*4,"esp"));
++	&sbb	("ebx",0);
++	&sbb	("ecx",1);
++	&sbb	("edx",-1);
++	&sbb	("edi",0);
++
++	# Note that because mod has special form, i.e. consists of
++	# 0xffffffff, 1 and 0s, we can conditionally synthesize it by
++	# assigning borrow bit to one register, %ebp, and its negative
++	# to another, %esi. But we started by calculating %esi...
++
++	&sub	("esi","edi");
++	&add	(&DWP(0*4,"ebp"),"edi");		# add modulus or zero
++	&adc	(&DWP(1*4,"ebp"),"edi");
++	&adc	(&DWP(2*4,"ebp"),"edi");
++	&adc	(&DWP(3*4,"ebp"),0);
++	&adc	("eax",0);
++	&adc	("ebx",0);
++	&mov	(&DWP(4*4,"ebp"),"eax");
++	&adc	("ecx","esi");
++	&mov	(&DWP(5*4,"ebp"),"ebx");
++	&adc	("edx","edi");
++	&mov	(&DWP(6*4,"ebp"),"ecx");
++	&mov	("edi","ebp");				# fulfill contract
++	&mov	(&DWP(7*4,"ebp"),"edx");
++
++	&add	("esp",10*4);
++	&ret	();
++&function_end_B("_ecp_nistz256_mul_mont");
++
++########################################################################
++# void ecp_nistz256_scatter_w5(void *edi,const P256_POINT *esi,
++#					 int ebp);
++&function_begin("ecp_nistz256_scatter_w5");
++	&mov	("edi",&wparam(0));
++	&mov	("esi",&wparam(1));
++	&mov	("ebp",&wparam(2));
++
++	&lea	("edi",&DWP(128-4,"edi","ebp",4));
++	&mov	("ebp",96/16);
++&set_label("scatter_w5_loop");
++	&mov	("eax",&DWP(0,"esi"));
++	&mov	("ebx",&DWP(4,"esi"));
++	&mov	("ecx",&DWP(8,"esi"));
++	&mov	("edx",&DWP(12,"esi"));
++	&lea	("esi",&DWP(16,"esi"));
++	&mov	(&DWP(64*0-128,"edi"),"eax");
++	&mov	(&DWP(64*1-128,"edi"),"ebx");
++	&mov	(&DWP(64*2-128,"edi"),"ecx");
++	&mov	(&DWP(64*3-128,"edi"),"edx");
++	&lea	("edi",&DWP(64*4,"edi"));
++	&dec	("ebp");
++	&jnz	(&label("scatter_w5_loop"));
++&function_end("ecp_nistz256_scatter_w5");
++
++########################################################################
++# void ecp_nistz256_gather_w5(P256_POINT *edi,const void *esi,
++#					      int ebp);
++&function_begin("ecp_nistz256_gather_w5");
++	&mov	("esi",&wparam(1));
++	&mov	("ebp",&wparam(2));
++
++	&lea	("esi",&DWP(0,"esi","ebp",4));
++	&neg	("ebp");
++	&sar	("ebp",31);
++	&mov	("edi",&wparam(0));
++	&lea	("esi",&DWP(0,"esi","ebp",4));
++
++    for($i=0;$i<24;$i+=4) {
++	&mov	("eax",&DWP(64*($i+0),"esi"));
++	&mov	("ebx",&DWP(64*($i+1),"esi"));
++	&mov	("ecx",&DWP(64*($i+2),"esi"));
++	&mov	("edx",&DWP(64*($i+3),"esi"));
++	&and	("eax","ebp");
++	&and	("ebx","ebp");
++	&and	("ecx","ebp");
++	&and	("edx","ebp");
++	&mov	(&DWP(4*($i+0),"edi"),"eax");
++	&mov	(&DWP(4*($i+1),"edi"),"ebx");
++	&mov	(&DWP(4*($i+2),"edi"),"ecx");
++	&mov	(&DWP(4*($i+3),"edi"),"edx");
++    }
++&function_end("ecp_nistz256_gather_w5");
++
++########################################################################
++# void ecp_nistz256_scatter_w7(void *edi,const P256_POINT_AFFINE *esi,
++#					 int ebp);
++&function_begin("ecp_nistz256_scatter_w7");
++	&mov	("edi",&wparam(0));
++	&mov	("esi",&wparam(1));
++	&mov	("ebp",&wparam(2));
++
++	&lea	("edi",&DWP(-1,"edi","ebp"));
++	&mov	("ebp",64/4);
++&set_label("scatter_w7_loop");
++	&mov	("eax",&DWP(0,"esi"));
++	&lea	("esi",&DWP(4,"esi"));
++	&mov	(&BP(64*0,"edi"),"al");
++	&mov	(&BP(64*1,"edi"),"ah");
++	&shr	("eax",16);
++	&mov	(&BP(64*2,"edi"),"al");
++	&mov	(&BP(64*3,"edi"),"ah");
++	&lea	("edi",&DWP(64*4,"edi"));
++	&dec	("ebp");
++	&jnz	(&label("scatter_w7_loop"));
++&function_end("ecp_nistz256_scatter_w7");
++
++########################################################################
++# void ecp_nistz256_gather_w7(P256_POINT_AFFINE *edi,const void *esi,
++#						     int ebp);
++&function_begin("ecp_nistz256_gather_w7");
++	&mov	("esi",&wparam(1));
++	&mov	("ebp",&wparam(2));
++
++	&add	("esi","ebp");
++	&neg	("ebp"),
++	&sar	("ebp",31);
++	&mov	("edi",&wparam(0));
++	&lea	("esi",&DWP(0,"esi","ebp"));
++
++    for($i=0;$i<64;$i+=4) {
++	&movz	("eax",&BP(64*($i+0),"esi"));
++	&movz	("ebx",&BP(64*($i+1),"esi"));
++	&movz	("ecx",&BP(64*($i+2),"esi"));
++	&and	("eax","ebp");
++	&movz	("edx",&BP(64*($i+3),"esi"));
++	&and	("ebx","ebp");
++	&mov	(&BP($i+0,"edi"),"al");
++	&and	("ecx","ebp");
++	&mov	(&BP($i+1,"edi"),"bl");
++	&and	("edx","ebp");
++	&mov	(&BP($i+2,"edi"),"cl");
++	&mov	(&BP($i+3,"edi"),"dl");
++    }
++&function_end("ecp_nistz256_gather_w7");
++
++########################################################################
++# following subroutines are "literal" implementation of those found in
++# ecp_nistz256.c
++#
++########################################################################
++# void ecp_nistz256_point_double(P256_POINT *out,const P256_POINT *inp);
++#
++&static_label("point_double_shortcut");
++&function_begin("ecp_nistz256_point_double");
++{   my ($S,$M,$Zsqr,$in_x,$tmp0)=map(32*$_,(0..4));
++
++	&mov	("esi",&wparam(1));
++
++	# above map() describes stack layout with 5 temporary
++	# 256-bit vectors on top, then we take extra word for
++	# OPENSSL_ia32cap_P copy.
++	&stack_push(8*5+1);
++						if ($sse2) {
++	&call	("_picup_eax");
++    &set_label("pic");
++	&picmeup("edx","OPENSSL_ia32cap_P","eax",&label("pic"));
++	&mov	("ebp",&DWP(0,"edx"));		}
++
++&set_label("point_double_shortcut");
++	&mov	("eax",&DWP(0,"esi"));		# copy in_x
++	&mov	("ebx",&DWP(4,"esi"));
++	&mov	("ecx",&DWP(8,"esi"));
++	&mov	("edx",&DWP(12,"esi"));
++	&mov	(&DWP($in_x+0,"esp"),"eax");
++	&mov	(&DWP($in_x+4,"esp"),"ebx");
++	&mov	(&DWP($in_x+8,"esp"),"ecx");
++	&mov	(&DWP($in_x+12,"esp"),"edx");
++	&mov	("eax",&DWP(16,"esi"));
++	&mov	("ebx",&DWP(20,"esi"));
++	&mov	("ecx",&DWP(24,"esi"));
++	&mov	("edx",&DWP(28,"esi"));
++	&mov	(&DWP($in_x+16,"esp"),"eax");
++	&mov	(&DWP($in_x+20,"esp"),"ebx");
++	&mov	(&DWP($in_x+24,"esp"),"ecx");
++	&mov	(&DWP($in_x+28,"esp"),"edx");
++	&mov	(&DWP(32*5,"esp"),"ebp");	# OPENSSL_ia32cap_P copy
++
++	&lea	("ebp",&DWP(32,"esi"));
++	&lea	("esi",&DWP(32,"esi"));
++	&lea	("edi",&DWP($S,"esp"));
++	&call	("_ecp_nistz256_add");		# p256_mul_by_2(S, in_y);
++
++	&mov	("eax",&DWP(32*5,"esp"));	# OPENSSL_ia32cap_P copy
++	&mov	("esi",64);
++	&add	("esi",&wparam(1));
++	&lea	("edi",&DWP($Zsqr,"esp"));
++	&mov	("ebp","esi");
++	&call	("_ecp_nistz256_mul_mont");	# p256_sqr_mont(Zsqr, in_z);
++
++	&mov	("eax",&DWP(32*5,"esp"));	# OPENSSL_ia32cap_P copy
++	&lea	("esi",&DWP($S,"esp"));
++	&lea	("ebp",&DWP($S,"esp"));
++	&lea	("edi",&DWP($S,"esp"));
++	&call	("_ecp_nistz256_mul_mont");	# p256_sqr_mont(S, S);
++
++	&mov	("eax",&DWP(32*5,"esp"));	# OPENSSL_ia32cap_P copy
++	&mov	("ebp",&wparam(1));
++	&lea	("esi",&DWP(32,"ebp"));
++	&lea	("ebp",&DWP(64,"ebp"));
++	&lea	("edi",&DWP($tmp0,"esp"));
++	&call	("_ecp_nistz256_mul_mont");	# p256_mul_mont(tmp0, in_z, in_y);
++
++	&lea	("esi",&DWP($in_x,"esp"));
++	&lea	("ebp",&DWP($Zsqr,"esp"));
++	&lea	("edi",&DWP($M,"esp"));
++	&call	("_ecp_nistz256_add");		# p256_add(M, in_x, Zsqr);
++
++	&mov	("edi",64);
++	&lea	("esi",&DWP($tmp0,"esp"));
++	&lea	("ebp",&DWP($tmp0,"esp"));
++	&add	("edi",&wparam(0));
++	&call	("_ecp_nistz256_add");		# p256_mul_by_2(res_z, tmp0);
++
++	&lea	("esi",&DWP($in_x,"esp"));
++	&lea	("ebp",&DWP($Zsqr,"esp"));
++	&lea	("edi",&DWP($Zsqr,"esp"));
++	&call	("_ecp_nistz256_sub");		# p256_sub(Zsqr, in_x, Zsqr);
++
++	&mov	("eax",&DWP(32*5,"esp"));	# OPENSSL_ia32cap_P copy
++	&lea	("esi",&DWP($S,"esp"));
++	&lea	("ebp",&DWP($S,"esp"));
++	&lea	("edi",&DWP($tmp0,"esp"));
++	&call	("_ecp_nistz256_mul_mont");	# p256_sqr_mont(tmp0, S);
++
++	&mov	("eax",&DWP(32*5,"esp"));	# OPENSSL_ia32cap_P copy
++	&lea	("esi",&DWP($M,"esp"));
++	&lea	("ebp",&DWP($Zsqr,"esp"));
++	&lea	("edi",&DWP($M,"esp"));
++	&call	("_ecp_nistz256_mul_mont");	# p256_mul_mont(M, M, Zsqr);
++
++	&mov	("edi",32);
++	&lea	("esi",&DWP($tmp0,"esp"));
++	&add	("edi",&wparam(0));
++	&call	("_ecp_nistz256_div_by_2");	# p256_div_by_2(res_y, tmp0);
++
++	&lea	("esi",&DWP($M,"esp"));
++	&lea	("ebp",&DWP($M,"esp"));
++	&lea	("edi",&DWP($tmp0,"esp"));
++	&call	("_ecp_nistz256_add");		# 1/2 p256_mul_by_3(M, M);
++
++	&mov	("eax",&DWP(32*5,"esp"));	# OPENSSL_ia32cap_P copy
++	&lea	("esi",&DWP($in_x,"esp"));
++	&lea	("ebp",&DWP($S,"esp"));
++	&lea	("edi",&DWP($S,"esp"));
++	&call	("_ecp_nistz256_mul_mont");	# p256_mul_mont(S, S, in_x);
++
++	&lea	("esi",&DWP($tmp0,"esp"));
++	&lea	("ebp",&DWP($M,"esp"));
++	&lea	("edi",&DWP($M,"esp"));
++	&call	("_ecp_nistz256_add");		# 2/2 p256_mul_by_3(M, M);
++
++	&lea	("esi",&DWP($S,"esp"));
++	&lea	("ebp",&DWP($S,"esp"));
++	&lea	("edi",&DWP($tmp0,"esp"));
++	&call	("_ecp_nistz256_add");		# p256_mul_by_2(tmp0, S);
++
++	&mov	("eax",&DWP(32*5,"esp"));	# OPENSSL_ia32cap_P copy
++	&lea	("esi",&DWP($M,"esp"));
++	&lea	("ebp",&DWP($M,"esp"));
++	&mov	("edi",&wparam(0));
++	&call	("_ecp_nistz256_mul_mont");	# p256_sqr_mont(res_x, M);
++
++	&mov	("esi","edi");			# %edi is still res_x here
++	&lea	("ebp",&DWP($tmp0,"esp"));
++	&call	("_ecp_nistz256_sub");		# p256_sub(res_x, res_x, tmp0);
++
++	&lea	("esi",&DWP($S,"esp"));
++	&mov	("ebp","edi");			# %edi is still res_x
++	&lea	("edi",&DWP($S,"esp"));
++	&call	("_ecp_nistz256_sub");		# p256_sub(S, S, res_x);
++
++	&mov	("eax",&DWP(32*5,"esp"));	# OPENSSL_ia32cap_P copy
++	&mov	("esi","edi");			# %edi is still &S
++	&lea	("ebp",&DWP($M,"esp"));
++	&call	("_ecp_nistz256_mul_mont");	# p256_mul_mont(S, S, M);
++
++	&mov	("ebp",32);
++	&lea	("esi",&DWP($S,"esp"));
++	&add	("ebp",&wparam(0));
++	&mov	("edi","ebp");
++	&call	("_ecp_nistz256_sub");		# p256_sub(res_y, S, res_y);
++
++	&stack_pop(8*5+1);
++} &function_end("ecp_nistz256_point_double");
++
++########################################################################
++# void ecp_nistz256_point_add(P256_POINT *out,const P256_POINT *in1,
++#					      const P256_POINT *in2);
++&function_begin("ecp_nistz256_point_add");
++{   my ($res_x,$res_y,$res_z,
++	$in1_x,$in1_y,$in1_z,
++	$in2_x,$in2_y,$in2_z,
++	$H,$Hsqr,$R,$Rsqr,$Hcub,
++	$U1,$U2,$S1,$S2)=map(32*$_,(0..17));
++    my ($Z1sqr, $Z2sqr) = ($Hsqr, $Rsqr);
++
++	&mov	("esi",&wparam(2));
++
++	# above map() describes stack layout with 18 temporary
++	# 256-bit vectors on top, then we take extra words for
++	# !in1infty, !in2infty, result of check for zero and
++	# OPENSSL_ia32cap_P copy. [one unused word for padding]
++	&stack_push(8*18+5);
++						if ($sse2) {
++	&call	("_picup_eax");
++    &set_label("pic");
++	&picmeup("edx","OPENSSL_ia32cap_P","eax",&label("pic"));
++	&mov	("ebp",&DWP(0,"edx"));		}
++
++	&lea	("edi",&DWP($in2_x,"esp"));
++    for($i=0;$i<96;$i+=16) {
++	&mov	("eax",&DWP($i+0,"esi"));	# copy in2
++	&mov	("ebx",&DWP($i+4,"esi"));
++	&mov	("ecx",&DWP($i+8,"esi"));
++	&mov	("edx",&DWP($i+12,"esi"));
++	&mov	(&DWP($i+0,"edi"),"eax");
++	&mov	(&DWP(32*18+12,"esp"),"ebp")	if ($i==0);
++	&mov	("ebp","eax")			if ($i==64);
++	&or	("ebp","eax")			if ($i>64);
++	&mov	(&DWP($i+4,"edi"),"ebx");
++	&or	("ebp","ebx")			if ($i>=64);
++	&mov	(&DWP($i+8,"edi"),"ecx");
++	&or	("ebp","ecx")			if ($i>=64);
++	&mov	(&DWP($i+12,"edi"),"edx");
++	&or	("ebp","edx")			if ($i>=64);
++    }
++	&xor	("eax","eax");
++	&mov	("esi",&wparam(1));
++	&sub	("eax","ebp");
++	&or	("ebp","eax");
++	&sar	("ebp",31);
++	&mov	(&DWP(32*18+4,"esp"),"ebp");	# !in2infty
++
++	&lea	("edi",&DWP($in1_x,"esp"));
++    for($i=0;$i<96;$i+=16) {
++	&mov	("eax",&DWP($i+0,"esi"));	# copy in1
++	&mov	("ebx",&DWP($i+4,"esi"));
++	&mov	("ecx",&DWP($i+8,"esi"));
++	&mov	("edx",&DWP($i+12,"esi"));
++	&mov	(&DWP($i+0,"edi"),"eax");
++	&mov	("ebp","eax")			if ($i==64);
++	&or	("ebp","eax")			if ($i>64);
++	&mov	(&DWP($i+4,"edi"),"ebx");
++	&or	("ebp","ebx")			if ($i>=64);
++	&mov	(&DWP($i+8,"edi"),"ecx");
++	&or	("ebp","ecx")			if ($i>=64);
++	&mov	(&DWP($i+12,"edi"),"edx");
++	&or	("ebp","edx")			if ($i>=64);
++    }
++	&xor	("eax","eax");
++	&sub	("eax","ebp");
++	&or	("ebp","eax");
++	&sar	("ebp",31);
++	&mov	(&DWP(32*18+0,"esp"),"ebp");	# !in1infty
++
++	&mov	("eax",&DWP(32*18+12,"esp"));	# OPENSSL_ia32cap_P copy
++	&lea	("esi",&DWP($in2_z,"esp"));
++	&lea	("ebp",&DWP($in2_z,"esp"));
++	&lea	("edi",&DWP($Z2sqr,"esp"));
++	&call	("_ecp_nistz256_mul_mont");	# p256_sqr_mont(Z2sqr, in2_z);
++
++	&mov	("eax",&DWP(32*18+12,"esp"));	# OPENSSL_ia32cap_P copy
++	&lea	("esi",&DWP($in1_z,"esp"));
++	&lea	("ebp",&DWP($in1_z,"esp"));
++	&lea	("edi",&DWP($Z1sqr,"esp"));
++	&call	("_ecp_nistz256_mul_mont");	# p256_sqr_mont(Z1sqr, in1_z);
++
++	&mov	("eax",&DWP(32*18+12,"esp"));	# OPENSSL_ia32cap_P copy
++	&lea	("esi",&DWP($Z2sqr,"esp"));
++	&lea	("ebp",&DWP($in2_z,"esp"));
++	&lea	("edi",&DWP($S1,"esp"));
++	&call	("_ecp_nistz256_mul_mont");	# p256_mul_mont(S1, Z2sqr, in2_z);
++
++	&mov	("eax",&DWP(32*18+12,"esp"));	# OPENSSL_ia32cap_P copy
++	&lea	("esi",&DWP($Z1sqr,"esp"));
++	&lea	("ebp",&DWP($in1_z,"esp"));
++	&lea	("edi",&DWP($S2,"esp"));
++	&call	("_ecp_nistz256_mul_mont");	# p256_mul_mont(S2, Z1sqr, in1_z);
++
++	&mov	("eax",&DWP(32*18+12,"esp"));	# OPENSSL_ia32cap_P copy
++	&lea	("esi",&DWP($in1_y,"esp"));
++	&lea	("ebp",&DWP($S1,"esp"));
++	&lea	("edi",&DWP($S1,"esp"));
++	&call	("_ecp_nistz256_mul_mont");	# p256_mul_mont(S1, S1, in1_y);
++
++	&mov	("eax",&DWP(32*18+12,"esp"));	# OPENSSL_ia32cap_P copy
++	&lea	("esi",&DWP($in2_y,"esp"));
++	&lea	("ebp",&DWP($S2,"esp"));
++	&lea	("edi",&DWP($S2,"esp"));
++	&call	("_ecp_nistz256_mul_mont");	# p256_mul_mont(S2, S2, in2_y);
++
++	&lea	("esi",&DWP($S2,"esp"));
++	&lea	("ebp",&DWP($S1,"esp"));
++	&lea	("edi",&DWP($R,"esp"));
++	&call	("_ecp_nistz256_sub");		# p256_sub(R, S2, S1);
++
++	&or	("ebx","eax");			# see if result is zero
++	&mov	("eax",&DWP(32*18+12,"esp"));	# OPENSSL_ia32cap_P copy
++	&or	("ebx","ecx");
++	&or	("ebx","edx");
++	&or	("ebx",&DWP(0,"edi"));
++	&or	("ebx",&DWP(4,"edi"));
++	 &lea	("esi",&DWP($in1_x,"esp"));
++	&or	("ebx",&DWP(8,"edi"));
++	 &lea	("ebp",&DWP($Z2sqr,"esp"));
++	&or	("ebx",&DWP(12,"edi"));
++	 &lea	("edi",&DWP($U1,"esp"));
++	&mov	(&DWP(32*18+8,"esp"),"ebx");
++
++	&call	("_ecp_nistz256_mul_mont");	# p256_mul_mont(U1, in1_x, Z2sqr);
++
++	&mov	("eax",&DWP(32*18+12,"esp"));	# OPENSSL_ia32cap_P copy
++	&lea	("esi",&DWP($in2_x,"esp"));
++	&lea	("ebp",&DWP($Z1sqr,"esp"));
++	&lea	("edi",&DWP($U2,"esp"));
++	&call	("_ecp_nistz256_mul_mont");	# p256_mul_mont(U2, in2_x, Z1sqr);
++
++	&lea	("esi",&DWP($U2,"esp"));
++	&lea	("ebp",&DWP($U1,"esp"));
++	&lea	("edi",&DWP($H,"esp"));
++	&call	("_ecp_nistz256_sub");		# p256_sub(H, U2, U1);
++
++	&or	("eax","ebx");			# see if result is zero
++	&or	("eax","ecx");
++	&or	("eax","edx");
++	&or	("eax",&DWP(0,"edi"));
++	&or	("eax",&DWP(4,"edi"));
++	&or	("eax",&DWP(8,"edi"));
++	&or	("eax",&DWP(12,"edi"));
++
++	&data_byte(0x3e);			# predict taken
++	&jnz	(&label("add_proceed"));	# is_equal(U1,U2)?
++
++	&mov	("eax",&DWP(32*18+0,"esp"));
++	&and	("eax",&DWP(32*18+4,"esp"));
++	&mov	("ebx",&DWP(32*18+8,"esp"));
++	&jz	(&label("add_proceed"));	# (in1infty || in2infty)?
++	&test	("ebx","ebx");
++	&jz	(&label("add_double"));		# is_equal(S1,S2)?
++
++	&mov	("edi",&wparam(0));
++	&xor	("eax","eax");
++	&mov	("ecx",96/4);
++	&data_byte(0xfc,0xf3,0xab);		# cld; stosd
++	&jmp	(&label("add_done"));
++
++&set_label("add_double",16);
++	&mov	("esi",&wparam(1));
++	&mov	("ebp",&DWP(32*18+12,"esp"));	# OPENSSL_ia32cap_P copy
++	&add	("esp",4*((8*18+5)-(8*5+1)));	# difference in frame sizes
++	&jmp	(&label("point_double_shortcut"));
++
++&set_label("add_proceed",16);
++	&mov	("eax",&DWP(32*18+12,"esp"));	# OPENSSL_ia32cap_P copy
++	&lea	("esi",&DWP($R,"esp"));
++	&lea	("ebp",&DWP($R,"esp"));
++	&lea	("edi",&DWP($Rsqr,"esp"));
++	&call	("_ecp_nistz256_mul_mont");	# p256_sqr_mont(Rsqr, R);
++
++	&mov	("eax",&DWP(32*18+12,"esp"));	# OPENSSL_ia32cap_P copy
++	&lea	("esi",&DWP($H,"esp"));
++	&lea	("ebp",&DWP($in1_z,"esp"));
++	&lea	("edi",&DWP($res_z,"esp"));
++	&call	("_ecp_nistz256_mul_mont");	# p256_mul_mont(res_z, H, in1_z);
++
++	&mov	("eax",&DWP(32*18+12,"esp"));	# OPENSSL_ia32cap_P copy
++	&lea	("esi",&DWP($H,"esp"));
++	&lea	("ebp",&DWP($H,"esp"));
++	&lea	("edi",&DWP($Hsqr,"esp"));
++	&call	("_ecp_nistz256_mul_mont");	# p256_sqr_mont(Hsqr, H);
++
++	&mov	("eax",&DWP(32*18+12,"esp"));	# OPENSSL_ia32cap_P copy
++	&lea	("esi",&DWP($in2_z,"esp"));
++	&lea	("ebp",&DWP($res_z,"esp"));
++	&lea	("edi",&DWP($res_z,"esp"));
++	&call	("_ecp_nistz256_mul_mont");	# p256_mul_mont(res_z, res_z, in2_z);
++
++	&mov	("eax",&DWP(32*18+12,"esp"));	# OPENSSL_ia32cap_P copy
++	&lea	("esi",&DWP($Hsqr,"esp"));
++	&lea	("ebp",&DWP($U1,"esp"));
++	&lea	("edi",&DWP($U2,"esp"));
++	&call	("_ecp_nistz256_mul_mont");	# p256_mul_mont(U2, U1, Hsqr);
++
++	&mov	("eax",&DWP(32*18+12,"esp"));	# OPENSSL_ia32cap_P copy
++	&lea	("esi",&DWP($H,"esp"));
++	&lea	("ebp",&DWP($Hsqr,"esp"));
++	&lea	("edi",&DWP($Hcub,"esp"));
++	&call	("_ecp_nistz256_mul_mont");	# p256_mul_mont(Hcub, Hsqr, H);
++
++	&lea	("esi",&DWP($U2,"esp"));
++	&lea	("ebp",&DWP($U2,"esp"));
++	&lea	("edi",&DWP($Hsqr,"esp"));
++	&call	("_ecp_nistz256_add");		# p256_mul_by_2(Hsqr, U2);
++
++	&lea	("esi",&DWP($Rsqr,"esp"));
++	&lea	("ebp",&DWP($Hsqr,"esp"));
++	&lea	("edi",&DWP($res_x,"esp"));
++	&call	("_ecp_nistz256_sub");		# p256_sub(res_x, Rsqr, Hsqr);
++
++	&lea	("esi",&DWP($res_x,"esp"));
++	&lea	("ebp",&DWP($Hcub,"esp"));
++	&lea	("edi",&DWP($res_x,"esp"));
++	&call	("_ecp_nistz256_sub");		# p256_sub(res_x, res_x, Hcub);
++
++	&lea	("esi",&DWP($U2,"esp"));
++	&lea	("ebp",&DWP($res_x,"esp"));
++	&lea	("edi",&DWP($res_y,"esp"));
++	&call	("_ecp_nistz256_sub");		# p256_sub(res_y, U2, res_x);
++
++	&mov	("eax",&DWP(32*18+12,"esp"));	# OPENSSL_ia32cap_P copy
++	&lea	("esi",&DWP($Hcub,"esp"));
++	&lea	("ebp",&DWP($S1,"esp"));
++	&lea	("edi",&DWP($S2,"esp"));
++	&call	("_ecp_nistz256_mul_mont");	# p256_mul_mont(S2, S1, Hcub);
++
++	&mov	("eax",&DWP(32*18+12,"esp"));	# OPENSSL_ia32cap_P copy
++	&lea	("esi",&DWP($R,"esp"));
++	&lea	("ebp",&DWP($res_y,"esp"));
++	&lea	("edi",&DWP($res_y,"esp"));
++	&call	("_ecp_nistz256_mul_mont");	# p256_mul_mont(res_y, R, res_y);
++
++	&lea	("esi",&DWP($res_y,"esp"));
++	&lea	("ebp",&DWP($S2,"esp"));
++	&lea	("edi",&DWP($res_y,"esp"));
++	&call	("_ecp_nistz256_sub");		# p256_sub(res_y, res_y, S2);
++
++	&mov	("ebp",&DWP(32*18+0,"esp"));	# !in1infty
++	&mov	("esi",&DWP(32*18+4,"esp"));	# !in2infty
++	&mov	("edi",&wparam(0));
++	&mov	("edx","ebp");
++	¬	("ebp");
++	&and	("edx","esi");
++	&and	("ebp","esi");
++	¬	("esi");
++
++	########################################
++	# conditional moves
++    for($i=64;$i<96;$i+=4) {
++	&mov	("eax","edx");
++	&and	("eax",&DWP($res_x+$i,"esp"));
++	&mov	("ebx","ebp");
++	&and	("ebx",&DWP($in2_x+$i,"esp"));
++	&mov	("ecx","esi");
++	&and	("ecx",&DWP($in1_x+$i,"esp"));
++	&or	("eax","ebx");
++	&or	("eax","ecx");
++	&mov	(&DWP($i,"edi"),"eax");
++    }
++    for($i=0;$i<64;$i+=4) {
++	&mov	("eax","edx");
++	&and	("eax",&DWP($res_x+$i,"esp"));
++	&mov	("ebx","ebp");
++	&and	("ebx",&DWP($in2_x+$i,"esp"));
++	&mov	("ecx","esi");
++	&and	("ecx",&DWP($in1_x+$i,"esp"));
++	&or	("eax","ebx");
++	&or	("eax","ecx");
++	&mov	(&DWP($i,"edi"),"eax");
++    }
++    &set_label("add_done");
++	&stack_pop(8*18+5);
++} &function_end("ecp_nistz256_point_add");
++
++########################################################################
++# void ecp_nistz256_point_add_affine(P256_POINT *out,
++#				     const P256_POINT *in1,
++#				     const P256_POINT_AFFINE *in2);
++&function_begin("ecp_nistz256_point_add_affine");
++{
++    my ($res_x,$res_y,$res_z,
++	$in1_x,$in1_y,$in1_z,
++	$in2_x,$in2_y,
++	$U2,$S2,$H,$R,$Hsqr,$Hcub,$Rsqr)=map(32*$_,(0..14));
++    my $Z1sqr = $S2;
++    my @ONE_mont=(1,0,0,-1,-1,-1,-2,0);
++
++	&mov	("esi",&wparam(1));
++
++	# above map() describes stack layout with 15 temporary
++	# 256-bit vectors on top, then we take extra words for
++	# !in1infty, !in2infty, and OPENSSL_ia32cap_P copy.
++	&stack_push(8*15+3);
++						if ($sse2) {
++	&call	("_picup_eax");
++    &set_label("pic");
++	&picmeup("edx","OPENSSL_ia32cap_P","eax",&label("pic"));
++	&mov	("ebp",&DWP(0,"edx"));		}
++
++	&lea	("edi",&DWP($in1_x,"esp"));
++    for($i=0;$i<96;$i+=16) {
++	&mov	("eax",&DWP($i+0,"esi"));	# copy in1
++	&mov	("ebx",&DWP($i+4,"esi"));
++	&mov	("ecx",&DWP($i+8,"esi"));
++	&mov	("edx",&DWP($i+12,"esi"));
++	&mov	(&DWP($i+0,"edi"),"eax");
++	&mov	(&DWP(32*15+8,"esp"),"ebp")	if ($i==0);
++	&mov	("ebp","eax")			if ($i==64);
++	&or	("ebp","eax")			if ($i>64);
++	&mov	(&DWP($i+4,"edi"),"ebx");
++	&or	("ebp","ebx")			if ($i>=64);
++	&mov	(&DWP($i+8,"edi"),"ecx");
++	&or	("ebp","ecx")			if ($i>=64);
++	&mov	(&DWP($i+12,"edi"),"edx");
++	&or	("ebp","edx")			if ($i>=64);
++    }
++	&xor	("eax","eax");
++	&mov	("esi",&wparam(2));
++	&sub	("eax","ebp");
++	&or	("ebp","eax");
++	&sar	("ebp",31);
++	&mov	(&DWP(32*15+0,"esp"),"ebp");	# !in1infty
++
++	&lea	("edi",&DWP($in2_x,"esp"));
++    for($i=0;$i<64;$i+=16) {
++	&mov	("eax",&DWP($i+0,"esi"));	# copy in2
++	&mov	("ebx",&DWP($i+4,"esi"));
++	&mov	("ecx",&DWP($i+8,"esi"));
++	&mov	("edx",&DWP($i+12,"esi"));
++	&mov	(&DWP($i+0,"edi"),"eax");
++	&mov	("ebp","eax")			if ($i==0);
++	&or	("ebp","eax")			if ($i!=0);
++	&mov	(&DWP($i+4,"edi"),"ebx");
++	&or	("ebp","ebx");
++	&mov	(&DWP($i+8,"edi"),"ecx");
++	&or	("ebp","ecx");
++	&mov	(&DWP($i+12,"edi"),"edx");
++	&or	("ebp","edx");
++    }
++	&xor	("ebx","ebx");
++	&mov	("eax",&DWP(32*15+8,"esp"));	# OPENSSL_ia32cap_P copy
++	&sub	("ebx","ebp");
++	 &lea	("esi",&DWP($in1_z,"esp"));
++	&or	("ebx","ebp");
++	 &lea	("ebp",&DWP($in1_z,"esp"));
++	&sar	("ebx",31);
++	 &lea	("edi",&DWP($Z1sqr,"esp"));
++	&mov	(&DWP(32*15+4,"esp"),"ebx");	# !in2infty
++
++	&call	("_ecp_nistz256_mul_mont");	# p256_sqr_mont(Z1sqr, in1_z);
++
++	&mov	("eax",&DWP(32*15+8,"esp"));	# OPENSSL_ia32cap_P copy
++	&lea	("esi",&DWP($in2_x,"esp"));
++	&mov	("ebp","edi");			# %esi is stull &Z1sqr
++	&lea	("edi",&DWP($U2,"esp"));
++	&call	("_ecp_nistz256_mul_mont");	# p256_mul_mont(U2, Z1sqr, in2_x);
++
++	&mov	("eax",&DWP(32*15+8,"esp"));	# OPENSSL_ia32cap_P copy
++	&lea	("esi",&DWP($in1_z,"esp"));
++	&lea	("ebp",&DWP($Z1sqr,"esp"));
++	&lea	("edi",&DWP($S2,"esp"));
++	&call	("_ecp_nistz256_mul_mont");	# p256_mul_mont(S2, Z1sqr, in1_z);
++
++	&lea	("esi",&DWP($U2,"esp"));
++	&lea	("ebp",&DWP($in1_x,"esp"));
++	&lea	("edi",&DWP($H,"esp"));
++	&call	("_ecp_nistz256_sub");		# p256_sub(H, U2, in1_x);
++
++	&mov	("eax",&DWP(32*15+8,"esp"));	# OPENSSL_ia32cap_P copy
++	&lea	("esi",&DWP($in2_y,"esp"));
++	&lea	("ebp",&DWP($S2,"esp"));
++	&lea	("edi",&DWP($S2,"esp"));
++	&call	("_ecp_nistz256_mul_mont");	# p256_mul_mont(S2, S2, in2_y);
++
++	&mov	("eax",&DWP(32*15+8,"esp"));	# OPENSSL_ia32cap_P copy
++	&lea	("esi",&DWP($in1_z,"esp"));
++	&lea	("ebp",&DWP($H,"esp"));
++	&lea	("edi",&DWP($res_z,"esp"));
++	&call	("_ecp_nistz256_mul_mont");	# p256_mul_mont(res_z, H, in1_z);
++
++	&lea	("esi",&DWP($S2,"esp"));
++	&lea	("ebp",&DWP($in1_y,"esp"));
++	&lea	("edi",&DWP($R,"esp"));
++	&call	("_ecp_nistz256_sub");		# p256_sub(R, S2, in1_y);
++
++	&mov	("eax",&DWP(32*15+8,"esp"));	# OPENSSL_ia32cap_P copy
++	&lea	("esi",&DWP($H,"esp"));
++	&lea	("ebp",&DWP($H,"esp"));
++	&lea	("edi",&DWP($Hsqr,"esp"));
++	&call	("_ecp_nistz256_mul_mont");	# p256_sqr_mont(Hsqr, H);
++
++	&mov	("eax",&DWP(32*15+8,"esp"));	# OPENSSL_ia32cap_P copy
++	&lea	("esi",&DWP($R,"esp"));
++	&lea	("ebp",&DWP($R,"esp"));
++	&lea	("edi",&DWP($Rsqr,"esp"));
++	&call	("_ecp_nistz256_mul_mont");	# p256_sqr_mont(Rsqr, R);
++
++	&mov	("eax",&DWP(32*15+8,"esp"));	# OPENSSL_ia32cap_P copy
++	&lea	("esi",&DWP($in1_x,"esp"));
++	&lea	("ebp",&DWP($Hsqr,"esp"));
++	&lea	("edi",&DWP($U2,"esp"));
++	&call	("_ecp_nistz256_mul_mont");	# p256_mul_mont(U2, in1_x, Hsqr);
++
++	&mov	("eax",&DWP(32*15+8,"esp"));	# OPENSSL_ia32cap_P copy
++	&lea	("esi",&DWP($H,"esp"));
++	&lea	("ebp",&DWP($Hsqr,"esp"));
++	&lea	("edi",&DWP($Hcub,"esp"));
++	&call	("_ecp_nistz256_mul_mont");	# p256_mul_mont(Hcub, Hsqr, H);
++
++	&lea	("esi",&DWP($U2,"esp"));
++	&lea	("ebp",&DWP($U2,"esp"));
++	&lea	("edi",&DWP($Hsqr,"esp"));
++	&call	("_ecp_nistz256_add");		# p256_mul_by_2(Hsqr, U2);
++
++	&lea	("esi",&DWP($Rsqr,"esp"));
++	&lea	("ebp",&DWP($Hsqr,"esp"));
++	&lea	("edi",&DWP($res_x,"esp"));
++	&call	("_ecp_nistz256_sub");		# p256_sub(res_x, Rsqr, Hsqr);
++
++	&lea	("esi",&DWP($res_x,"esp"));
++	&lea	("ebp",&DWP($Hcub,"esp"));
++	&lea	("edi",&DWP($res_x,"esp"));
++	&call	("_ecp_nistz256_sub");		# p256_sub(res_x, res_x, Hcub);
++
++	&lea	("esi",&DWP($U2,"esp"));
++	&lea	("ebp",&DWP($res_x,"esp"));
++	&lea	("edi",&DWP($res_y,"esp"));
++	&call	("_ecp_nistz256_sub");		# p256_sub(res_y, U2, res_x);
++
++	&mov	("eax",&DWP(32*15+8,"esp"));	# OPENSSL_ia32cap_P copy
++	&lea	("esi",&DWP($Hcub,"esp"));
++	&lea	("ebp",&DWP($in1_y,"esp"));
++	&lea	("edi",&DWP($S2,"esp"));
++	&call	("_ecp_nistz256_mul_mont");	# p256_mul_mont(S2, Hcub, in1_y);
++
++	&mov	("eax",&DWP(32*15+8,"esp"));	# OPENSSL_ia32cap_P copy
++	&lea	("esi",&DWP($R,"esp"));
++	&lea	("ebp",&DWP($res_y,"esp"));
++	&lea	("edi",&DWP($res_y,"esp"));
++	&call	("_ecp_nistz256_mul_mont");	# p256_mul_mont(res_y, res_y, R);
++
++	&lea	("esi",&DWP($res_y,"esp"));
++	&lea	("ebp",&DWP($S2,"esp"));
++	&lea	("edi",&DWP($res_y,"esp"));
++	&call	("_ecp_nistz256_sub");		# p256_sub(res_y, res_y, S2);
++
++	&mov	("ebp",&DWP(32*15+0,"esp"));	# !in1infty
++	&mov	("esi",&DWP(32*15+4,"esp"));	# !in2infty
++	&mov	("edi",&wparam(0));
++	&mov	("edx","ebp");
++	¬	("ebp");
++	&and	("edx","esi");
++	&and	("ebp","esi");
++	¬	("esi");
++
++	########################################
++	# conditional moves
++    for($i=64;$i<96;$i+=4) {
++	my $one=@ONE_mont[($i-64)/4];
++
++	&mov	("eax","edx");
++	&and	("eax",&DWP($res_x+$i,"esp"));
++	&mov	("ebx","ebp")			if ($one && $one!=-1);
++	&and	("ebx",$one)			if ($one && $one!=-1);
++	&mov	("ecx","esi");
++	&and	("ecx",&DWP($in1_x+$i,"esp"));
++	&or	("eax",$one==-1?"ebp":"ebx")	if ($one);
++	&or	("eax","ecx");
++	&mov	(&DWP($i,"edi"),"eax");
++    }
++    for($i=0;$i<64;$i+=4) {
++	&mov	("eax","edx");
++	&and	("eax",&DWP($res_x+$i,"esp"));
++	&mov	("ebx","ebp");
++	&and	("ebx",&DWP($in2_x+$i,"esp"));
++	&mov	("ecx","esi");
++	&and	("ecx",&DWP($in1_x+$i,"esp"));
++	&or	("eax","ebx");
++	&or	("eax","ecx");
++	&mov	(&DWP($i,"edi"),"eax");
++    }
++	&stack_pop(8*15+3);
++} &function_end("ecp_nistz256_point_add_affine");
++
++&asm_finish();
++
++close STDOUT;
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/ec/asm/ecp_nistz256-x86_64.pl b/CryptoPkg/Library/OpensslLib/openssl/crypto/ec/asm/ecp_nistz256-x86_64.pl
+new file mode 100755
+index 0000000..16b6639
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/ec/asm/ecp_nistz256-x86_64.pl
+@@ -0,0 +1,3087 @@
++#! /usr/bin/env perl
++# Copyright 2014-2016 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
++# in the file LICENSE in the source distribution or at
++# https://www.openssl.org/source/license.html
++
++
++##############################################################################
++#                                                                            #
++# Copyright 2014 Intel Corporation                                           #
++#                                                                            #
++# Licensed under the Apache License, Version 2.0 (the "License");            #
++# you may not use this file except in compliance with the License.           #
++# You may obtain a copy of the License at                                    #
++#                                                                            #
++#    http://www.apache.org/licenses/LICENSE-2.0                              #
++#                                                                            #
++# Unless required by applicable law or agreed to in writing, software        #
++# distributed under the License is distributed on an "AS IS" BASIS,          #
++# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   #
++# See the License for the specific language governing permissions and        #
++# limitations under the License.                                             #
++#                                                                            #
++##############################################################################
++#                                                                            #
++#  Developers and authors:                                                   #
++#  Shay Gueron (1, 2), and Vlad Krasnov (1)                                  #
++#  (1) Intel Corporation, Israel Development Center                          #
++#  (2) University of Haifa                                                   #
++#  Reference:                                                                #
++#  S.Gueron and V.Krasnov, "Fast Prime Field Elliptic Curve Cryptography with#
++#                           256 Bit Primes"                                  #
++#                                                                            #
++##############################################################################
++
++# Further optimization by :
++#
++#		this/original	with/without -DECP_NISTZ256_ASM(*)
++# Opteron	+12-49%		+110-150%
++# Bulldozer	+14-45%		+175-210%
++# P4		+18-46%		n/a :-(
++# Westmere	+12-34%		+80-87%
++# Sandy Bridge	+9-35%		+110-120%
++# Ivy Bridge	+9-35%		+110-125%
++# Haswell	+8-37%		+140-160%
++# Broadwell	+18-58%		+145-210%
++# Atom		+15-50%		+130-180%
++# VIA Nano	+43-160%	+300-480%
++#
++# (*)	"without -DECP_NISTZ256_ASM" refers to build with
++#	"enable-ec_nistp_64_gcc_128";
++#
++# Ranges denote minimum and maximum improvement coefficients depending
++# on benchmark. Lower coefficients are for ECDSA sign, relatively fastest
++# server-side operation. Keep in mind that +100% means 2x improvement.
++
++$flavour = shift;
++$output  = shift;
++if ($flavour =~ /\./) { $output = $flavour; undef $flavour; }
++
++$win64=0; $win64=1 if ($flavour =~ /[nm]asm|mingw64/ || $output =~ /\.asm$/);
++
++$0 =~ m/(.*[\/\\])[^\/\\]+$/; $dir=$1;
++( $xlate="${dir}x86_64-xlate.pl" and -f $xlate ) or
++( $xlate="${dir}../../perlasm/x86_64-xlate.pl" and -f $xlate) or
++die "can't locate x86_64-xlate.pl";
++
++open OUT,"| \"$^X\" \"$xlate\" $flavour \"$output\"";
++*STDOUT=*OUT;
++
++if (`$ENV{CC} -Wa,-v -c -o /dev/null -x assembler /dev/null 2>&1`
++		=~ /GNU assembler version ([2-9]\.[0-9]+)/) {
++	$avx = ($1>=2.19) + ($1>=2.22);
++	$addx = ($1>=2.23);
++}
++
++if (!$addx && $win64 && ($flavour =~ /nasm/ || $ENV{ASM} =~ /nasm/) &&
++	    `nasm -v 2>&1` =~ /NASM version ([2-9]\.[0-9]+)/) {
++	$avx = ($1>=2.09) + ($1>=2.10);
++	$addx = ($1>=2.10);
++}
++
++if (!$addx && $win64 && ($flavour =~ /masm/ || $ENV{ASM} =~ /ml64/) &&
++	    `ml64 2>&1` =~ /Version ([0-9]+)\./) {
++	$avx = ($1>=10) + ($1>=11);
++	$addx = ($1>=12);
++}
++
++if (!$addx && `$ENV{CC} -v 2>&1` =~ /((?:^clang|LLVM) version|.*based on LLVM) ([3-9])\.([0-9]+)/) {
++	my $ver = $2 + $3/100.0;	# 3.1->3.01, 3.10->3.10
++	$avx = ($ver>=3.0) + ($ver>=3.01);
++	$addx = ($ver>=3.03);
++}
++
++$code.=<<___;
++.text
++.extern	OPENSSL_ia32cap_P
++
++# The polynomial
++.align 64
++.Lpoly:
++.quad 0xffffffffffffffff, 0x00000000ffffffff, 0x0000000000000000, 0xffffffff00000001
++
++# 2^512 mod P precomputed for NIST P256 polynomial
++.LRR:
++.quad 0x0000000000000003, 0xfffffffbffffffff, 0xfffffffffffffffe, 0x00000004fffffffd
++
++.LOne:
++.long 1,1,1,1,1,1,1,1
++.LTwo:
++.long 2,2,2,2,2,2,2,2
++.LThree:
++.long 3,3,3,3,3,3,3,3
++.LONE_mont:
++.quad 0x0000000000000001, 0xffffffff00000000, 0xffffffffffffffff, 0x00000000fffffffe
++___
++
++{
++################################################################################
++# void ecp_nistz256_mul_by_2(uint64_t res[4], uint64_t a[4]);
++
++my ($a0,$a1,$a2,$a3)=map("%r$_",(8..11));
++my ($t0,$t1,$t2,$t3,$t4)=("%rax","%rdx","%rcx","%r12","%r13");
++my ($r_ptr,$a_ptr,$b_ptr)=("%rdi","%rsi","%rdx");
++
++$code.=<<___;
++
++.globl	ecp_nistz256_mul_by_2
++.type	ecp_nistz256_mul_by_2,\@function,2
++.align	64
++ecp_nistz256_mul_by_2:
++	push	%r12
++	push	%r13
++
++	mov	8*0($a_ptr), $a0
++	xor	$t4,$t4
++	mov	8*1($a_ptr), $a1
++	add	$a0, $a0		# a0:a3+a0:a3
++	mov	8*2($a_ptr), $a2
++	adc	$a1, $a1
++	mov	8*3($a_ptr), $a3
++	lea	.Lpoly(%rip), $a_ptr
++	 mov	$a0, $t0
++	adc	$a2, $a2
++	adc	$a3, $a3
++	 mov	$a1, $t1
++	adc	\$0, $t4
++
++	sub	8*0($a_ptr), $a0
++	 mov	$a2, $t2
++	sbb	8*1($a_ptr), $a1
++	sbb	8*2($a_ptr), $a2
++	 mov	$a3, $t3
++	sbb	8*3($a_ptr), $a3
++	sbb	\$0, $t4
++
++	cmovc	$t0, $a0
++	cmovc	$t1, $a1
++	mov	$a0, 8*0($r_ptr)
++	cmovc	$t2, $a2
++	mov	$a1, 8*1($r_ptr)
++	cmovc	$t3, $a3
++	mov	$a2, 8*2($r_ptr)
++	mov	$a3, 8*3($r_ptr)
++
++	pop	%r13
++	pop	%r12
++	ret
++.size	ecp_nistz256_mul_by_2,.-ecp_nistz256_mul_by_2
++
++################################################################################
++# void ecp_nistz256_div_by_2(uint64_t res[4], uint64_t a[4]);
++.globl	ecp_nistz256_div_by_2
++.type	ecp_nistz256_div_by_2,\@function,2
++.align	32
++ecp_nistz256_div_by_2:
++	push	%r12
++	push	%r13
++
++	mov	8*0($a_ptr), $a0
++	mov	8*1($a_ptr), $a1
++	mov	8*2($a_ptr), $a2
++	 mov	$a0, $t0
++	mov	8*3($a_ptr), $a3
++	lea	.Lpoly(%rip), $a_ptr
++
++	 mov	$a1, $t1
++	xor	$t4, $t4
++	add	8*0($a_ptr), $a0
++	 mov	$a2, $t2
++	adc	8*1($a_ptr), $a1
++	adc	8*2($a_ptr), $a2
++	 mov	$a3, $t3
++	adc	8*3($a_ptr), $a3
++	adc	\$0, $t4
++	xor	$a_ptr, $a_ptr		# borrow $a_ptr
++	test	\$1, $t0
++
++	cmovz	$t0, $a0
++	cmovz	$t1, $a1
++	cmovz	$t2, $a2
++	cmovz	$t3, $a3
++	cmovz	$a_ptr, $t4
++
++	mov	$a1, $t0		# a0:a3>>1
++	shr	\$1, $a0
++	shl	\$63, $t0
++	mov	$a2, $t1
++	shr	\$1, $a1
++	or	$t0, $a0
++	shl	\$63, $t1
++	mov	$a3, $t2
++	shr	\$1, $a2
++	or	$t1, $a1
++	shl	\$63, $t2
++	shr	\$1, $a3
++	shl	\$63, $t4
++	or	$t2, $a2
++	or	$t4, $a3
++
++	mov	$a0, 8*0($r_ptr)
++	mov	$a1, 8*1($r_ptr)
++	mov	$a2, 8*2($r_ptr)
++	mov	$a3, 8*3($r_ptr)
++
++	pop	%r13
++	pop	%r12
++	ret
++.size	ecp_nistz256_div_by_2,.-ecp_nistz256_div_by_2
++
++################################################################################
++# void ecp_nistz256_mul_by_3(uint64_t res[4], uint64_t a[4]);
++.globl	ecp_nistz256_mul_by_3
++.type	ecp_nistz256_mul_by_3,\@function,2
++.align	32
++ecp_nistz256_mul_by_3:
++	push	%r12
++	push	%r13
++
++	mov	8*0($a_ptr), $a0
++	xor	$t4, $t4
++	mov	8*1($a_ptr), $a1
++	add	$a0, $a0		# a0:a3+a0:a3
++	mov	8*2($a_ptr), $a2
++	adc	$a1, $a1
++	mov	8*3($a_ptr), $a3
++	 mov	$a0, $t0
++	adc	$a2, $a2
++	adc	$a3, $a3
++	 mov	$a1, $t1
++	adc	\$0, $t4
++
++	sub	\$-1, $a0
++	 mov	$a2, $t2
++	sbb	.Lpoly+8*1(%rip), $a1
++	sbb	\$0, $a2
++	 mov	$a3, $t3
++	sbb	.Lpoly+8*3(%rip), $a3
++	sbb	\$0, $t4
++
++	cmovc	$t0, $a0
++	cmovc	$t1, $a1
++	cmovc	$t2, $a2
++	cmovc	$t3, $a3
++
++	xor	$t4, $t4
++	add	8*0($a_ptr), $a0	# a0:a3+=a_ptr[0:3]
++	adc	8*1($a_ptr), $a1
++	 mov	$a0, $t0
++	adc	8*2($a_ptr), $a2
++	adc	8*3($a_ptr), $a3
++	 mov	$a1, $t1
++	adc	\$0, $t4
++
++	sub	\$-1, $a0
++	 mov	$a2, $t2
++	sbb	.Lpoly+8*1(%rip), $a1
++	sbb	\$0, $a2
++	 mov	$a3, $t3
++	sbb	.Lpoly+8*3(%rip), $a3
++	sbb	\$0, $t4
++
++	cmovc	$t0, $a0
++	cmovc	$t1, $a1
++	mov	$a0, 8*0($r_ptr)
++	cmovc	$t2, $a2
++	mov	$a1, 8*1($r_ptr)
++	cmovc	$t3, $a3
++	mov	$a2, 8*2($r_ptr)
++	mov	$a3, 8*3($r_ptr)
++
++	pop %r13
++	pop %r12
++	ret
++.size	ecp_nistz256_mul_by_3,.-ecp_nistz256_mul_by_3
++
++################################################################################
++# void ecp_nistz256_add(uint64_t res[4], uint64_t a[4], uint64_t b[4]);
++.globl	ecp_nistz256_add
++.type	ecp_nistz256_add,\@function,3
++.align	32
++ecp_nistz256_add:
++	push	%r12
++	push	%r13
++
++	mov	8*0($a_ptr), $a0
++	xor	$t4, $t4
++	mov	8*1($a_ptr), $a1
++	mov	8*2($a_ptr), $a2
++	mov	8*3($a_ptr), $a3
++	lea	.Lpoly(%rip), $a_ptr
++
++	add	8*0($b_ptr), $a0
++	adc	8*1($b_ptr), $a1
++	 mov	$a0, $t0
++	adc	8*2($b_ptr), $a2
++	adc	8*3($b_ptr), $a3
++	 mov	$a1, $t1
++	adc	\$0, $t4
++
++	sub	8*0($a_ptr), $a0
++	 mov	$a2, $t2
++	sbb	8*1($a_ptr), $a1
++	sbb	8*2($a_ptr), $a2
++	 mov	$a3, $t3
++	sbb	8*3($a_ptr), $a3
++	sbb	\$0, $t4
++
++	cmovc	$t0, $a0
++	cmovc	$t1, $a1
++	mov	$a0, 8*0($r_ptr)
++	cmovc	$t2, $a2
++	mov	$a1, 8*1($r_ptr)
++	cmovc	$t3, $a3
++	mov	$a2, 8*2($r_ptr)
++	mov	$a3, 8*3($r_ptr)
++
++	pop %r13
++	pop %r12
++	ret
++.size	ecp_nistz256_add,.-ecp_nistz256_add
++
++################################################################################
++# void ecp_nistz256_sub(uint64_t res[4], uint64_t a[4], uint64_t b[4]);
++.globl	ecp_nistz256_sub
++.type	ecp_nistz256_sub,\@function,3
++.align	32
++ecp_nistz256_sub:
++	push	%r12
++	push	%r13
++
++	mov	8*0($a_ptr), $a0
++	xor	$t4, $t4
++	mov	8*1($a_ptr), $a1
++	mov	8*2($a_ptr), $a2
++	mov	8*3($a_ptr), $a3
++	lea	.Lpoly(%rip), $a_ptr
++
++	sub	8*0($b_ptr), $a0
++	sbb	8*1($b_ptr), $a1
++	 mov	$a0, $t0
++	sbb	8*2($b_ptr), $a2
++	sbb	8*3($b_ptr), $a3
++	 mov	$a1, $t1
++	sbb	\$0, $t4
++
++	add	8*0($a_ptr), $a0
++	 mov	$a2, $t2
++	adc	8*1($a_ptr), $a1
++	adc	8*2($a_ptr), $a2
++	 mov	$a3, $t3
++	adc	8*3($a_ptr), $a3
++	test	$t4, $t4
++
++	cmovz	$t0, $a0
++	cmovz	$t1, $a1
++	mov	$a0, 8*0($r_ptr)
++	cmovz	$t2, $a2
++	mov	$a1, 8*1($r_ptr)
++	cmovz	$t3, $a3
++	mov	$a2, 8*2($r_ptr)
++	mov	$a3, 8*3($r_ptr)
++
++	pop %r13
++	pop %r12
++	ret
++.size	ecp_nistz256_sub,.-ecp_nistz256_sub
++
++################################################################################
++# void ecp_nistz256_neg(uint64_t res[4], uint64_t a[4]);
++.globl	ecp_nistz256_neg
++.type	ecp_nistz256_neg,\@function,2
++.align	32
++ecp_nistz256_neg:
++	push	%r12
++	push	%r13
++
++	xor	$a0, $a0
++	xor	$a1, $a1
++	xor	$a2, $a2
++	xor	$a3, $a3
++	xor	$t4, $t4
++
++	sub	8*0($a_ptr), $a0
++	sbb	8*1($a_ptr), $a1
++	sbb	8*2($a_ptr), $a2
++	 mov	$a0, $t0
++	sbb	8*3($a_ptr), $a3
++	lea	.Lpoly(%rip), $a_ptr
++	 mov	$a1, $t1
++	sbb	\$0, $t4
++
++	add	8*0($a_ptr), $a0
++	 mov	$a2, $t2
++	adc	8*1($a_ptr), $a1
++	adc	8*2($a_ptr), $a2
++	 mov	$a3, $t3
++	adc	8*3($a_ptr), $a3
++	test	$t4, $t4
++
++	cmovz	$t0, $a0
++	cmovz	$t1, $a1
++	mov	$a0, 8*0($r_ptr)
++	cmovz	$t2, $a2
++	mov	$a1, 8*1($r_ptr)
++	cmovz	$t3, $a3
++	mov	$a2, 8*2($r_ptr)
++	mov	$a3, 8*3($r_ptr)
++
++	pop %r13
++	pop %r12
++	ret
++.size	ecp_nistz256_neg,.-ecp_nistz256_neg
++___
++}
++{
++my ($r_ptr,$a_ptr,$b_org,$b_ptr)=("%rdi","%rsi","%rdx","%rbx");
++my ($acc0,$acc1,$acc2,$acc3,$acc4,$acc5,$acc6,$acc7)=map("%r$_",(8..15));
++my ($t0,$t1,$t2,$t3,$t4)=("%rcx","%rbp","%rbx","%rdx","%rax");
++my ($poly1,$poly3)=($acc6,$acc7);
++
++$code.=<<___;
++################################################################################
++# void ecp_nistz256_to_mont(
++#   uint64_t res[4],
++#   uint64_t in[4]);
++.globl	ecp_nistz256_to_mont
++.type	ecp_nistz256_to_mont,\@function,2
++.align	32
++ecp_nistz256_to_mont:
++___
++$code.=<<___	if ($addx);
++	mov	\$0x80100, %ecx
++	and	OPENSSL_ia32cap_P+8(%rip), %ecx
++___
++$code.=<<___;
++	lea	.LRR(%rip), $b_org
++	jmp	.Lmul_mont
++.size	ecp_nistz256_to_mont,.-ecp_nistz256_to_mont
++
++################################################################################
++# void ecp_nistz256_mul_mont(
++#   uint64_t res[4],
++#   uint64_t a[4],
++#   uint64_t b[4]);
++
++.globl	ecp_nistz256_mul_mont
++.type	ecp_nistz256_mul_mont,\@function,3
++.align	32
++ecp_nistz256_mul_mont:
++___
++$code.=<<___	if ($addx);
++	mov	\$0x80100, %ecx
++	and	OPENSSL_ia32cap_P+8(%rip), %ecx
++___
++$code.=<<___;
++.Lmul_mont:
++	push	%rbp
++	push	%rbx
++	push	%r12
++	push	%r13
++	push	%r14
++	push	%r15
++___
++$code.=<<___	if ($addx);
++	cmp	\$0x80100, %ecx
++	je	.Lmul_montx
++___
++$code.=<<___;
++	mov	$b_org, $b_ptr
++	mov	8*0($b_org), %rax
++	mov	8*0($a_ptr), $acc1
++	mov	8*1($a_ptr), $acc2
++	mov	8*2($a_ptr), $acc3
++	mov	8*3($a_ptr), $acc4
++
++	call	__ecp_nistz256_mul_montq
++___
++$code.=<<___	if ($addx);
++	jmp	.Lmul_mont_done
++
++.align	32
++.Lmul_montx:
++	mov	$b_org, $b_ptr
++	mov	8*0($b_org), %rdx
++	mov	8*0($a_ptr), $acc1
++	mov	8*1($a_ptr), $acc2
++	mov	8*2($a_ptr), $acc3
++	mov	8*3($a_ptr), $acc4
++	lea	-128($a_ptr), $a_ptr	# control u-op density
++
++	call	__ecp_nistz256_mul_montx
++___
++$code.=<<___;
++.Lmul_mont_done:
++	pop	%r15
++	pop	%r14
++	pop	%r13
++	pop	%r12
++	pop	%rbx
++	pop	%rbp
++	ret
++.size	ecp_nistz256_mul_mont,.-ecp_nistz256_mul_mont
++
++.type	__ecp_nistz256_mul_montq,\@abi-omnipotent
++.align	32
++__ecp_nistz256_mul_montq:
++	########################################################################
++	# Multiply a by b[0]
++	mov	%rax, $t1
++	mulq	$acc1
++	mov	.Lpoly+8*1(%rip),$poly1
++	mov	%rax, $acc0
++	mov	$t1, %rax
++	mov	%rdx, $acc1
++
++	mulq	$acc2
++	mov	.Lpoly+8*3(%rip),$poly3
++	add	%rax, $acc1
++	mov	$t1, %rax
++	adc	\$0, %rdx
++	mov	%rdx, $acc2
++
++	mulq	$acc3
++	add	%rax, $acc2
++	mov	$t1, %rax
++	adc	\$0, %rdx
++	mov	%rdx, $acc3
++
++	mulq	$acc4
++	add	%rax, $acc3
++	 mov	$acc0, %rax
++	adc	\$0, %rdx
++	xor	$acc5, $acc5
++	mov	%rdx, $acc4
++
++	########################################################################
++	# First reduction step
++	# Basically now we want to multiply acc[0] by p256,
++	# and add the result to the acc.
++	# Due to the special form of p256 we do some optimizations
++	#
++	# acc[0] x p256[0..1] = acc[0] x 2^96 - acc[0]
++	# then we add acc[0] and get acc[0] x 2^96
++
++	mov	$acc0, $t1
++	shl	\$32, $acc0
++	mulq	$poly3
++	shr	\$32, $t1
++	add	$acc0, $acc1		# +=acc[0]<<96
++	adc	$t1, $acc2
++	adc	%rax, $acc3
++	 mov	8*1($b_ptr), %rax
++	adc	%rdx, $acc4
++	adc	\$0, $acc5
++	xor	$acc0, $acc0
++
++	########################################################################
++	# Multiply by b[1]
++	mov	%rax, $t1
++	mulq	8*0($a_ptr)
++	add	%rax, $acc1
++	mov	$t1, %rax
++	adc	\$0, %rdx
++	mov	%rdx, $t0
++
++	mulq	8*1($a_ptr)
++	add	$t0, $acc2
++	adc	\$0, %rdx
++	add	%rax, $acc2
++	mov	$t1, %rax
++	adc	\$0, %rdx
++	mov	%rdx, $t0
++
++	mulq	8*2($a_ptr)
++	add	$t0, $acc3
++	adc	\$0, %rdx
++	add	%rax, $acc3
++	mov	$t1, %rax
++	adc	\$0, %rdx
++	mov	%rdx, $t0
++
++	mulq	8*3($a_ptr)
++	add	$t0, $acc4
++	adc	\$0, %rdx
++	add	%rax, $acc4
++	 mov	$acc1, %rax
++	adc	%rdx, $acc5
++	adc	\$0, $acc0
++
++	########################################################################
++	# Second reduction step	
++	mov	$acc1, $t1
++	shl	\$32, $acc1
++	mulq	$poly3
++	shr	\$32, $t1
++	add	$acc1, $acc2
++	adc	$t1, $acc3
++	adc	%rax, $acc4
++	 mov	8*2($b_ptr), %rax
++	adc	%rdx, $acc5
++	adc	\$0, $acc0
++	xor	$acc1, $acc1
++
++	########################################################################
++	# Multiply by b[2]
++	mov	%rax, $t1
++	mulq	8*0($a_ptr)
++	add	%rax, $acc2
++	mov	$t1, %rax
++	adc	\$0, %rdx
++	mov	%rdx, $t0
++
++	mulq	8*1($a_ptr)
++	add	$t0, $acc3
++	adc	\$0, %rdx
++	add	%rax, $acc3
++	mov	$t1, %rax
++	adc	\$0, %rdx
++	mov	%rdx, $t0
++
++	mulq	8*2($a_ptr)
++	add	$t0, $acc4
++	adc	\$0, %rdx
++	add	%rax, $acc4
++	mov	$t1, %rax
++	adc	\$0, %rdx
++	mov	%rdx, $t0
++
++	mulq	8*3($a_ptr)
++	add	$t0, $acc5
++	adc	\$0, %rdx
++	add	%rax, $acc5
++	 mov	$acc2, %rax
++	adc	%rdx, $acc0
++	adc	\$0, $acc1
++
++	########################################################################
++	# Third reduction step	
++	mov	$acc2, $t1
++	shl	\$32, $acc2
++	mulq	$poly3
++	shr	\$32, $t1
++	add	$acc2, $acc3
++	adc	$t1, $acc4
++	adc	%rax, $acc5
++	 mov	8*3($b_ptr), %rax
++	adc	%rdx, $acc0
++	adc	\$0, $acc1
++	xor	$acc2, $acc2
++
++	########################################################################
++	# Multiply by b[3]
++	mov	%rax, $t1
++	mulq	8*0($a_ptr)
++	add	%rax, $acc3
++	mov	$t1, %rax
++	adc	\$0, %rdx
++	mov	%rdx, $t0
++
++	mulq	8*1($a_ptr)
++	add	$t0, $acc4
++	adc	\$0, %rdx
++	add	%rax, $acc4
++	mov	$t1, %rax
++	adc	\$0, %rdx
++	mov	%rdx, $t0
++
++	mulq	8*2($a_ptr)
++	add	$t0, $acc5
++	adc	\$0, %rdx
++	add	%rax, $acc5
++	mov	$t1, %rax
++	adc	\$0, %rdx
++	mov	%rdx, $t0
++
++	mulq	8*3($a_ptr)
++	add	$t0, $acc0
++	adc	\$0, %rdx
++	add	%rax, $acc0
++	 mov	$acc3, %rax
++	adc	%rdx, $acc1
++	adc	\$0, $acc2
++
++	########################################################################
++	# Final reduction step	
++	mov	$acc3, $t1
++	shl	\$32, $acc3
++	mulq	$poly3
++	shr	\$32, $t1
++	add	$acc3, $acc4
++	adc	$t1, $acc5
++	 mov	$acc4, $t0
++	adc	%rax, $acc0
++	adc	%rdx, $acc1
++	 mov	$acc5, $t1
++	adc	\$0, $acc2
++
++	########################################################################	
++	# Branch-less conditional subtraction of P
++	sub	\$-1, $acc4		# .Lpoly[0]
++	 mov	$acc0, $t2
++	sbb	$poly1, $acc5		# .Lpoly[1]
++	sbb	\$0, $acc0		# .Lpoly[2]
++	 mov	$acc1, $t3
++	sbb	$poly3, $acc1		# .Lpoly[3]
++	sbb	\$0, $acc2
++
++	cmovc	$t0, $acc4
++	cmovc	$t1, $acc5
++	mov	$acc4, 8*0($r_ptr)
++	cmovc	$t2, $acc0
++	mov	$acc5, 8*1($r_ptr)
++	cmovc	$t3, $acc1
++	mov	$acc0, 8*2($r_ptr)
++	mov	$acc1, 8*3($r_ptr)
++
++	ret
++.size	__ecp_nistz256_mul_montq,.-__ecp_nistz256_mul_montq
++
++################################################################################
++# void ecp_nistz256_sqr_mont(
++#   uint64_t res[4],
++#   uint64_t a[4]);
++
++# we optimize the square according to S.Gueron and V.Krasnov,
++# "Speeding up Big-Number Squaring"
++.globl	ecp_nistz256_sqr_mont
++.type	ecp_nistz256_sqr_mont,\@function,2
++.align	32
++ecp_nistz256_sqr_mont:
++___
++$code.=<<___	if ($addx);
++	mov	\$0x80100, %ecx
++	and	OPENSSL_ia32cap_P+8(%rip), %ecx
++___
++$code.=<<___;
++	push	%rbp
++	push	%rbx
++	push	%r12
++	push	%r13
++	push	%r14
++	push	%r15
++___
++$code.=<<___	if ($addx);
++	cmp	\$0x80100, %ecx
++	je	.Lsqr_montx
++___
++$code.=<<___;
++	mov	8*0($a_ptr), %rax
++	mov	8*1($a_ptr), $acc6
++	mov	8*2($a_ptr), $acc7
++	mov	8*3($a_ptr), $acc0
++
++	call	__ecp_nistz256_sqr_montq
++___
++$code.=<<___	if ($addx);
++	jmp	.Lsqr_mont_done
++
++.align	32
++.Lsqr_montx:
++	mov	8*0($a_ptr), %rdx
++	mov	8*1($a_ptr), $acc6
++	mov	8*2($a_ptr), $acc7
++	mov	8*3($a_ptr), $acc0
++	lea	-128($a_ptr), $a_ptr	# control u-op density
++
++	call	__ecp_nistz256_sqr_montx
++___
++$code.=<<___;
++.Lsqr_mont_done:
++	pop	%r15
++	pop	%r14
++	pop	%r13
++	pop	%r12
++	pop	%rbx
++	pop	%rbp
++	ret
++.size	ecp_nistz256_sqr_mont,.-ecp_nistz256_sqr_mont
++
++.type	__ecp_nistz256_sqr_montq,\@abi-omnipotent
++.align	32
++__ecp_nistz256_sqr_montq:
++	mov	%rax, $acc5
++	mulq	$acc6			# a[1]*a[0]
++	mov	%rax, $acc1
++	mov	$acc7, %rax
++	mov	%rdx, $acc2
++
++	mulq	$acc5			# a[0]*a[2]
++	add	%rax, $acc2
++	mov	$acc0, %rax
++	adc	\$0, %rdx
++	mov	%rdx, $acc3
++
++	mulq	$acc5			# a[0]*a[3]
++	add	%rax, $acc3
++	 mov	$acc7, %rax
++	adc	\$0, %rdx
++	mov	%rdx, $acc4
++
++	#################################
++	mulq	$acc6			# a[1]*a[2]
++	add	%rax, $acc3
++	mov	$acc0, %rax
++	adc	\$0, %rdx
++	mov	%rdx, $t1
++
++	mulq	$acc6			# a[1]*a[3]
++	add	%rax, $acc4
++	 mov	$acc0, %rax
++	adc	\$0, %rdx
++	add	$t1, $acc4
++	mov	%rdx, $acc5
++	adc	\$0, $acc5
++
++	#################################
++	mulq	$acc7			# a[2]*a[3]
++	xor	$acc7, $acc7
++	add	%rax, $acc5
++	 mov	8*0($a_ptr), %rax
++	mov	%rdx, $acc6
++	adc	\$0, $acc6
++
++	add	$acc1, $acc1		# acc1:6<<1
++	adc	$acc2, $acc2
++	adc	$acc3, $acc3
++	adc	$acc4, $acc4
++	adc	$acc5, $acc5
++	adc	$acc6, $acc6
++	adc	\$0, $acc7
++
++	mulq	%rax
++	mov	%rax, $acc0
++	mov	8*1($a_ptr), %rax
++	mov	%rdx, $t0
++
++	mulq	%rax
++	add	$t0, $acc1
++	adc	%rax, $acc2
++	mov	8*2($a_ptr), %rax
++	adc	\$0, %rdx
++	mov	%rdx, $t0
++
++	mulq	%rax
++	add	$t0, $acc3
++	adc	%rax, $acc4
++	mov	8*3($a_ptr), %rax
++	adc	\$0, %rdx
++	mov	%rdx, $t0
++
++	mulq	%rax
++	add	$t0, $acc5
++	adc	%rax, $acc6
++	 mov	$acc0, %rax
++	adc	%rdx, $acc7
++
++	mov	.Lpoly+8*1(%rip), $a_ptr
++	mov	.Lpoly+8*3(%rip), $t1
++
++	##########################################
++	# Now the reduction
++	# First iteration
++	mov	$acc0, $t0
++	shl	\$32, $acc0
++	mulq	$t1
++	shr	\$32, $t0
++	add	$acc0, $acc1		# +=acc[0]<<96
++	adc	$t0, $acc2
++	adc	%rax, $acc3
++	 mov	$acc1, %rax
++	adc	\$0, %rdx
++
++	##########################################
++	# Second iteration
++	mov	$acc1, $t0
++	shl	\$32, $acc1
++	mov	%rdx, $acc0
++	mulq	$t1
++	shr	\$32, $t0
++	add	$acc1, $acc2
++	adc	$t0, $acc3
++	adc	%rax, $acc0
++	 mov	$acc2, %rax
++	adc	\$0, %rdx
++
++	##########################################
++	# Third iteration
++	mov	$acc2, $t0
++	shl	\$32, $acc2
++	mov	%rdx, $acc1
++	mulq	$t1
++	shr	\$32, $t0
++	add	$acc2, $acc3
++	adc	$t0, $acc0
++	adc	%rax, $acc1
++	 mov	$acc3, %rax
++	adc	\$0, %rdx
++
++	###########################################
++	# Last iteration
++	mov	$acc3, $t0
++	shl	\$32, $acc3
++	mov	%rdx, $acc2
++	mulq	$t1
++	shr	\$32, $t0
++	add	$acc3, $acc0
++	adc	$t0, $acc1
++	adc	%rax, $acc2
++	adc	\$0, %rdx
++	xor	$acc3, $acc3
++
++	############################################
++	# Add the rest of the acc
++	add	$acc0, $acc4
++	adc	$acc1, $acc5
++	 mov	$acc4, $acc0
++	adc	$acc2, $acc6
++	adc	%rdx, $acc7
++	 mov	$acc5, $acc1
++	adc	\$0, $acc3
++
++	sub	\$-1, $acc4		# .Lpoly[0]
++	 mov	$acc6, $acc2
++	sbb	$a_ptr, $acc5		# .Lpoly[1]
++	sbb	\$0, $acc6		# .Lpoly[2]
++	 mov	$acc7, $t0
++	sbb	$t1, $acc7		# .Lpoly[3]
++	sbb	\$0, $acc3
++
++	cmovc	$acc0, $acc4
++	cmovc	$acc1, $acc5
++	mov	$acc4, 8*0($r_ptr)
++	cmovc	$acc2, $acc6
++	mov	$acc5, 8*1($r_ptr)
++	cmovc	$t0, $acc7
++	mov	$acc6, 8*2($r_ptr)
++	mov	$acc7, 8*3($r_ptr)
++
++	ret
++.size	__ecp_nistz256_sqr_montq,.-__ecp_nistz256_sqr_montq
++___
++
++if ($addx) {
++$code.=<<___;
++.type	__ecp_nistz256_mul_montx,\@abi-omnipotent
++.align	32
++__ecp_nistz256_mul_montx:
++	########################################################################
++	# Multiply by b[0]
++	mulx	$acc1, $acc0, $acc1
++	mulx	$acc2, $t0, $acc2
++	mov	\$32, $poly1
++	xor	$acc5, $acc5		# cf=0
++	mulx	$acc3, $t1, $acc3
++	mov	.Lpoly+8*3(%rip), $poly3
++	adc	$t0, $acc1
++	mulx	$acc4, $t0, $acc4
++	 mov	$acc0, %rdx
++	adc	$t1, $acc2
++	 shlx	$poly1,$acc0,$t1
++	adc	$t0, $acc3
++	 shrx	$poly1,$acc0,$t0
++	adc	\$0, $acc4
++
++	########################################################################
++	# First reduction step
++	add	$t1, $acc1
++	adc	$t0, $acc2
++
++	mulx	$poly3, $t0, $t1
++	 mov	8*1($b_ptr), %rdx
++	adc	$t0, $acc3
++	adc	$t1, $acc4
++	adc	\$0, $acc5
++	xor	$acc0, $acc0		# $acc0=0,cf=0,of=0
++
++	########################################################################
++	# Multiply by b[1]
++	mulx	8*0+128($a_ptr), $t0, $t1
++	adcx	$t0, $acc1
++	adox	$t1, $acc2
++
++	mulx	8*1+128($a_ptr), $t0, $t1
++	adcx	$t0, $acc2
++	adox	$t1, $acc3
++
++	mulx	8*2+128($a_ptr), $t0, $t1
++	adcx	$t0, $acc3
++	adox	$t1, $acc4
++
++	mulx	8*3+128($a_ptr), $t0, $t1
++	 mov	$acc1, %rdx
++	adcx	$t0, $acc4
++	 shlx	$poly1, $acc1, $t0
++	adox	$t1, $acc5
++	 shrx	$poly1, $acc1, $t1
++
++	adcx	$acc0, $acc5
++	adox	$acc0, $acc0
++	adc	\$0, $acc0
++
++	########################################################################
++	# Second reduction step
++	add	$t0, $acc2
++	adc	$t1, $acc3
++
++	mulx	$poly3, $t0, $t1
++	 mov	8*2($b_ptr), %rdx
++	adc	$t0, $acc4
++	adc	$t1, $acc5
++	adc	\$0, $acc0
++	xor	$acc1 ,$acc1		# $acc1=0,cf=0,of=0
++
++	########################################################################
++	# Multiply by b[2]
++	mulx	8*0+128($a_ptr), $t0, $t1
++	adcx	$t0, $acc2
++	adox	$t1, $acc3
++
++	mulx	8*1+128($a_ptr), $t0, $t1
++	adcx	$t0, $acc3
++	adox	$t1, $acc4
++
++	mulx	8*2+128($a_ptr), $t0, $t1
++	adcx	$t0, $acc4
++	adox	$t1, $acc5
++
++	mulx	8*3+128($a_ptr), $t0, $t1
++	 mov	$acc2, %rdx
++	adcx	$t0, $acc5
++	 shlx	$poly1, $acc2, $t0
++	adox	$t1, $acc0
++	 shrx	$poly1, $acc2, $t1
++
++	adcx	$acc1, $acc0
++	adox	$acc1, $acc1
++	adc	\$0, $acc1
++
++	########################################################################
++	# Third reduction step
++	add	$t0, $acc3
++	adc	$t1, $acc4
++
++	mulx	$poly3, $t0, $t1
++	 mov	8*3($b_ptr), %rdx
++	adc	$t0, $acc5
++	adc	$t1, $acc0
++	adc	\$0, $acc1
++	xor	$acc2, $acc2		# $acc2=0,cf=0,of=0
++
++	########################################################################
++	# Multiply by b[3]
++	mulx	8*0+128($a_ptr), $t0, $t1
++	adcx	$t0, $acc3
++	adox	$t1, $acc4
++
++	mulx	8*1+128($a_ptr), $t0, $t1
++	adcx	$t0, $acc4
++	adox	$t1, $acc5
++
++	mulx	8*2+128($a_ptr), $t0, $t1
++	adcx	$t0, $acc5
++	adox	$t1, $acc0
++
++	mulx	8*3+128($a_ptr), $t0, $t1
++	 mov	$acc3, %rdx
++	adcx	$t0, $acc0
++	 shlx	$poly1, $acc3, $t0
++	adox	$t1, $acc1
++	 shrx	$poly1, $acc3, $t1
++
++	adcx	$acc2, $acc1
++	adox	$acc2, $acc2
++	adc	\$0, $acc2
++
++	########################################################################
++	# Fourth reduction step
++	add	$t0, $acc4
++	adc	$t1, $acc5
++
++	mulx	$poly3, $t0, $t1
++	 mov	$acc4, $t2
++	mov	.Lpoly+8*1(%rip), $poly1
++	adc	$t0, $acc0
++	 mov	$acc5, $t3
++	adc	$t1, $acc1
++	adc	\$0, $acc2
++
++	########################################################################
++	# Branch-less conditional subtraction of P
++	xor	%eax, %eax
++	 mov	$acc0, $t0
++	sbb	\$-1, $acc4		# .Lpoly[0]
++	sbb	$poly1, $acc5		# .Lpoly[1]
++	sbb	\$0, $acc0		# .Lpoly[2]
++	 mov	$acc1, $t1
++	sbb	$poly3, $acc1		# .Lpoly[3]
++	sbb	\$0, $acc2
++
++	cmovc	$t2, $acc4
++	cmovc	$t3, $acc5
++	mov	$acc4, 8*0($r_ptr)
++	cmovc	$t0, $acc0
++	mov	$acc5, 8*1($r_ptr)
++	cmovc	$t1, $acc1
++	mov	$acc0, 8*2($r_ptr)
++	mov	$acc1, 8*3($r_ptr)
++
++	ret
++.size	__ecp_nistz256_mul_montx,.-__ecp_nistz256_mul_montx
++
++.type	__ecp_nistz256_sqr_montx,\@abi-omnipotent
++.align	32
++__ecp_nistz256_sqr_montx:
++	mulx	$acc6, $acc1, $acc2	# a[0]*a[1]
++	mulx	$acc7, $t0, $acc3	# a[0]*a[2]
++	xor	%eax, %eax
++	adc	$t0, $acc2
++	mulx	$acc0, $t1, $acc4	# a[0]*a[3]
++	 mov	$acc6, %rdx
++	adc	$t1, $acc3
++	adc	\$0, $acc4
++	xor	$acc5, $acc5		# $acc5=0,cf=0,of=0
++
++	#################################
++	mulx	$acc7, $t0, $t1		# a[1]*a[2]
++	adcx	$t0, $acc3
++	adox	$t1, $acc4
++
++	mulx	$acc0, $t0, $t1		# a[1]*a[3]
++	 mov	$acc7, %rdx
++	adcx	$t0, $acc4
++	adox	$t1, $acc5
++	adc	\$0, $acc5
++
++	#################################
++	mulx	$acc0, $t0, $acc6	# a[2]*a[3]
++	 mov	8*0+128($a_ptr), %rdx
++	xor	$acc7, $acc7		# $acc7=0,cf=0,of=0
++	 adcx	$acc1, $acc1		# acc1:6<<1
++	adox	$t0, $acc5
++	 adcx	$acc2, $acc2
++	adox	$acc7, $acc6		# of=0
++
++	mulx	%rdx, $acc0, $t1
++	mov	8*1+128($a_ptr), %rdx
++	 adcx	$acc3, $acc3
++	adox	$t1, $acc1
++	 adcx	$acc4, $acc4
++	mulx	%rdx, $t0, $t4
++	mov	8*2+128($a_ptr), %rdx
++	 adcx	$acc5, $acc5
++	adox	$t0, $acc2
++	 adcx	$acc6, $acc6
++	.byte	0x67
++	mulx	%rdx, $t0, $t1
++	mov	8*3+128($a_ptr), %rdx
++	adox	$t4, $acc3
++	 adcx	$acc7, $acc7
++	adox	$t0, $acc4
++	 mov	\$32, $a_ptr
++	adox	$t1, $acc5
++	.byte	0x67,0x67
++	mulx	%rdx, $t0, $t4
++	 mov	$acc0, %rdx
++	adox	$t0, $acc6
++	 shlx	$a_ptr, $acc0, $t0
++	adox	$t4, $acc7
++	 shrx	$a_ptr, $acc0, $t4
++	 mov	.Lpoly+8*3(%rip), $t1
++
++	# reduction step 1
++	add	$t0, $acc1
++	adc	$t4, $acc2
++
++	mulx	$t1, $t0, $acc0
++	 mov	$acc1, %rdx
++	adc	$t0, $acc3
++	 shlx	$a_ptr, $acc1, $t0
++	adc	\$0, $acc0
++	 shrx	$a_ptr, $acc1, $t4
++
++	# reduction step 2
++	add	$t0, $acc2
++	adc	$t4, $acc3
++
++	mulx	$t1, $t0, $acc1
++	 mov	$acc2, %rdx
++	adc	$t0, $acc0
++	 shlx	$a_ptr, $acc2, $t0
++	adc	\$0, $acc1
++	 shrx	$a_ptr, $acc2, $t4
++
++	# reduction step 3
++	add	$t0, $acc3
++	adc	$t4, $acc0
++
++	mulx	$t1, $t0, $acc2
++	 mov	$acc3, %rdx
++	adc	$t0, $acc1
++	 shlx	$a_ptr, $acc3, $t0
++	adc	\$0, $acc2
++	 shrx	$a_ptr, $acc3, $t4
++
++	# reduction step 4
++	add	$t0, $acc0
++	adc	$t4, $acc1
++
++	mulx	$t1, $t0, $acc3
++	adc	$t0, $acc2
++	adc	\$0, $acc3
++
++	xor	$t3, $t3		# cf=0
++	adc	$acc0, $acc4		# accumulate upper half
++	 mov	.Lpoly+8*1(%rip), $a_ptr
++	adc	$acc1, $acc5
++	 mov	$acc4, $acc0
++	adc	$acc2, $acc6
++	adc	$acc3, $acc7
++	 mov	$acc5, $acc1
++	adc	\$0, $t3
++
++	xor	%eax, %eax		# cf=0
++	sbb	\$-1, $acc4		# .Lpoly[0]
++	 mov	$acc6, $acc2
++	sbb	$a_ptr, $acc5		# .Lpoly[1]
++	sbb	\$0, $acc6		# .Lpoly[2]
++	 mov	$acc7, $acc3
++	sbb	$t1, $acc7		# .Lpoly[3]
++	sbb	\$0, $t3
++
++	cmovc	$acc0, $acc4
++	cmovc	$acc1, $acc5
++	mov	$acc4, 8*0($r_ptr)
++	cmovc	$acc2, $acc6
++	mov	$acc5, 8*1($r_ptr)
++	cmovc	$acc3, $acc7
++	mov	$acc6, 8*2($r_ptr)
++	mov	$acc7, 8*3($r_ptr)
++
++	ret
++.size	__ecp_nistz256_sqr_montx,.-__ecp_nistz256_sqr_montx
++___
++}
++}
++{
++my ($r_ptr,$in_ptr)=("%rdi","%rsi");
++my ($acc0,$acc1,$acc2,$acc3)=map("%r$_",(8..11));
++my ($t0,$t1,$t2)=("%rcx","%r12","%r13");
++
++$code.=<<___;
++################################################################################
++# void ecp_nistz256_from_mont(
++#   uint64_t res[4],
++#   uint64_t in[4]);
++# This one performs Montgomery multiplication by 1, so we only need the reduction
++
++.globl	ecp_nistz256_from_mont
++.type	ecp_nistz256_from_mont,\@function,2
++.align	32
++ecp_nistz256_from_mont:
++	push	%r12
++	push	%r13
++
++	mov	8*0($in_ptr), %rax
++	mov	.Lpoly+8*3(%rip), $t2
++	mov	8*1($in_ptr), $acc1
++	mov	8*2($in_ptr), $acc2
++	mov	8*3($in_ptr), $acc3
++	mov	%rax, $acc0
++	mov	.Lpoly+8*1(%rip), $t1
++
++	#########################################
++	# First iteration
++	mov	%rax, $t0
++	shl	\$32, $acc0
++	mulq	$t2
++	shr	\$32, $t0
++	add	$acc0, $acc1
++	adc	$t0, $acc2
++	adc	%rax, $acc3
++	 mov	$acc1, %rax
++	adc	\$0, %rdx
++
++	#########################################
++	# Second iteration
++	mov	$acc1, $t0
++	shl	\$32, $acc1
++	mov	%rdx, $acc0
++	mulq	$t2
++	shr	\$32, $t0
++	add	$acc1, $acc2
++	adc	$t0, $acc3
++	adc	%rax, $acc0
++	 mov	$acc2, %rax
++	adc	\$0, %rdx
++
++	##########################################
++	# Third iteration
++	mov	$acc2, $t0
++	shl	\$32, $acc2
++	mov	%rdx, $acc1
++	mulq	$t2
++	shr	\$32, $t0
++	add	$acc2, $acc3
++	adc	$t0, $acc0
++	adc	%rax, $acc1
++	 mov	$acc3, %rax
++	adc	\$0, %rdx
++
++	###########################################
++	# Last iteration
++	mov	$acc3, $t0
++	shl	\$32, $acc3
++	mov	%rdx, $acc2
++	mulq	$t2
++	shr	\$32, $t0
++	add	$acc3, $acc0
++	adc	$t0, $acc1
++	 mov	$acc0, $t0
++	adc	%rax, $acc2
++	 mov	$acc1, $in_ptr
++	adc	\$0, %rdx
++
++	###########################################
++	# Branch-less conditional subtraction
++	sub	\$-1, $acc0
++	 mov	$acc2, %rax
++	sbb	$t1, $acc1
++	sbb	\$0, $acc2
++	 mov	%rdx, $acc3
++	sbb	$t2, %rdx
++	sbb	$t2, $t2
++
++	cmovnz	$t0, $acc0
++	cmovnz	$in_ptr, $acc1
++	mov	$acc0, 8*0($r_ptr)
++	cmovnz	%rax, $acc2
++	mov	$acc1, 8*1($r_ptr)
++	cmovz	%rdx, $acc3
++	mov	$acc2, 8*2($r_ptr)
++	mov	$acc3, 8*3($r_ptr)
++
++	pop	%r13
++	pop	%r12
++	ret
++.size	ecp_nistz256_from_mont,.-ecp_nistz256_from_mont
++___
++}
++{
++my ($val,$in_t,$index)=$win64?("%rcx","%rdx","%r8d"):("%rdi","%rsi","%edx");
++my ($ONE,$INDEX,$Ra,$Rb,$Rc,$Rd,$Re,$Rf)=map("%xmm$_",(0..7));
++my ($M0,$T0a,$T0b,$T0c,$T0d,$T0e,$T0f,$TMP0)=map("%xmm$_",(8..15));
++my ($M1,$T2a,$T2b,$TMP2,$M2,$T2a,$T2b,$TMP2)=map("%xmm$_",(8..15));
++
++$code.=<<___;
++################################################################################
++# void ecp_nistz256_scatter_w5(uint64_t *val, uint64_t *in_t, int index);
++.globl	ecp_nistz256_scatter_w5
++.type	ecp_nistz256_scatter_w5,\@abi-omnipotent
++.align	32
++ecp_nistz256_scatter_w5:
++	lea	-3($index,$index,2), $index
++	movdqa	0x00($in_t), %xmm0
++	shl	\$5, $index
++	movdqa	0x10($in_t), %xmm1
++	movdqa	0x20($in_t), %xmm2
++	movdqa	0x30($in_t), %xmm3
++	movdqa	0x40($in_t), %xmm4
++	movdqa	0x50($in_t), %xmm5
++	movdqa	%xmm0, 0x00($val,$index)
++	movdqa	%xmm1, 0x10($val,$index)
++	movdqa	%xmm2, 0x20($val,$index)
++	movdqa	%xmm3, 0x30($val,$index)
++	movdqa	%xmm4, 0x40($val,$index)
++	movdqa	%xmm5, 0x50($val,$index)
++
++	ret
++.size	ecp_nistz256_scatter_w5,.-ecp_nistz256_scatter_w5
++
++################################################################################
++# void ecp_nistz256_gather_w5(uint64_t *val, uint64_t *in_t, int index);
++.globl	ecp_nistz256_gather_w5
++.type	ecp_nistz256_gather_w5,\@abi-omnipotent
++.align	32
++ecp_nistz256_gather_w5:
++___
++$code.=<<___	if ($avx>1);
++	mov	OPENSSL_ia32cap_P+8(%rip), %eax
++	test	\$`1<<5`, %eax
++	jnz	.Lavx2_gather_w5
++___
++$code.=<<___	if ($win64);
++	lea	-0x88(%rsp), %rax
++.LSEH_begin_ecp_nistz256_gather_w5:
++	.byte	0x48,0x8d,0x60,0xe0		#lea	-0x20(%rax), %rsp
++	.byte	0x0f,0x29,0x70,0xe0		#movaps	%xmm6, -0x20(%rax)
++	.byte	0x0f,0x29,0x78,0xf0		#movaps	%xmm7, -0x10(%rax)
++	.byte	0x44,0x0f,0x29,0x00		#movaps	%xmm8, 0(%rax)
++	.byte	0x44,0x0f,0x29,0x48,0x10	#movaps	%xmm9, 0x10(%rax)
++	.byte	0x44,0x0f,0x29,0x50,0x20	#movaps	%xmm10, 0x20(%rax)
++	.byte	0x44,0x0f,0x29,0x58,0x30	#movaps	%xmm11, 0x30(%rax)
++	.byte	0x44,0x0f,0x29,0x60,0x40	#movaps	%xmm12, 0x40(%rax)
++	.byte	0x44,0x0f,0x29,0x68,0x50	#movaps	%xmm13, 0x50(%rax)
++	.byte	0x44,0x0f,0x29,0x70,0x60	#movaps	%xmm14, 0x60(%rax)
++	.byte	0x44,0x0f,0x29,0x78,0x70	#movaps	%xmm15, 0x70(%rax)
++___
++$code.=<<___;
++	movdqa	.LOne(%rip), $ONE
++	movd	$index, $INDEX
++
++	pxor	$Ra, $Ra
++	pxor	$Rb, $Rb
++	pxor	$Rc, $Rc
++	pxor	$Rd, $Rd
++	pxor	$Re, $Re
++	pxor	$Rf, $Rf
++
++	movdqa	$ONE, $M0
++	pshufd	\$0, $INDEX, $INDEX
++
++	mov	\$16, %rax
++.Lselect_loop_sse_w5:
++
++	movdqa	$M0, $TMP0
++	paddd	$ONE, $M0
++	pcmpeqd $INDEX, $TMP0
++
++	movdqa	16*0($in_t), $T0a
++	movdqa	16*1($in_t), $T0b
++	movdqa	16*2($in_t), $T0c
++	movdqa	16*3($in_t), $T0d
++	movdqa	16*4($in_t), $T0e
++	movdqa	16*5($in_t), $T0f
++	lea 16*6($in_t), $in_t
++
++	pand	$TMP0, $T0a
++	pand	$TMP0, $T0b
++	por	$T0a, $Ra
++	pand	$TMP0, $T0c
++	por	$T0b, $Rb
++	pand	$TMP0, $T0d
++	por	$T0c, $Rc
++	pand	$TMP0, $T0e
++	por	$T0d, $Rd
++	pand	$TMP0, $T0f
++	por	$T0e, $Re
++	por	$T0f, $Rf
++
++	dec	%rax
++	jnz	.Lselect_loop_sse_w5
++
++	movdqu	$Ra, 16*0($val)
++	movdqu	$Rb, 16*1($val)
++	movdqu	$Rc, 16*2($val)
++	movdqu	$Rd, 16*3($val)
++	movdqu	$Re, 16*4($val)
++	movdqu	$Rf, 16*5($val)
++___
++$code.=<<___	if ($win64);
++	movaps	(%rsp), %xmm6
++	movaps	0x10(%rsp), %xmm7
++	movaps	0x20(%rsp), %xmm8
++	movaps	0x30(%rsp), %xmm9
++	movaps	0x40(%rsp), %xmm10
++	movaps	0x50(%rsp), %xmm11
++	movaps	0x60(%rsp), %xmm12
++	movaps	0x70(%rsp), %xmm13
++	movaps	0x80(%rsp), %xmm14
++	movaps	0x90(%rsp), %xmm15
++	lea	0xa8(%rsp), %rsp
++.LSEH_end_ecp_nistz256_gather_w5:
++___
++$code.=<<___;
++	ret
++.size	ecp_nistz256_gather_w5,.-ecp_nistz256_gather_w5
++
++################################################################################
++# void ecp_nistz256_scatter_w7(uint64_t *val, uint64_t *in_t, int index);
++.globl	ecp_nistz256_scatter_w7
++.type	ecp_nistz256_scatter_w7,\@abi-omnipotent
++.align	32
++ecp_nistz256_scatter_w7:
++	movdqu	0x00($in_t), %xmm0
++	shl	\$6, $index
++	movdqu	0x10($in_t), %xmm1
++	movdqu	0x20($in_t), %xmm2
++	movdqu	0x30($in_t), %xmm3
++	movdqa	%xmm0, 0x00($val,$index)
++	movdqa	%xmm1, 0x10($val,$index)
++	movdqa	%xmm2, 0x20($val,$index)
++	movdqa	%xmm3, 0x30($val,$index)
++
++	ret
++.size	ecp_nistz256_scatter_w7,.-ecp_nistz256_scatter_w7
++
++################################################################################
++# void ecp_nistz256_gather_w7(uint64_t *val, uint64_t *in_t, int index);
++.globl	ecp_nistz256_gather_w7
++.type	ecp_nistz256_gather_w7,\@abi-omnipotent
++.align	32
++ecp_nistz256_gather_w7:
++___
++$code.=<<___	if ($avx>1);
++	mov	OPENSSL_ia32cap_P+8(%rip), %eax
++	test	\$`1<<5`, %eax
++	jnz	.Lavx2_gather_w7
++___
++$code.=<<___	if ($win64);
++	lea	-0x88(%rsp), %rax
++.LSEH_begin_ecp_nistz256_gather_w7:
++	.byte	0x48,0x8d,0x60,0xe0		#lea	-0x20(%rax), %rsp
++	.byte	0x0f,0x29,0x70,0xe0		#movaps	%xmm6, -0x20(%rax)
++	.byte	0x0f,0x29,0x78,0xf0		#movaps	%xmm7, -0x10(%rax)
++	.byte	0x44,0x0f,0x29,0x00		#movaps	%xmm8, 0(%rax)
++	.byte	0x44,0x0f,0x29,0x48,0x10	#movaps	%xmm9, 0x10(%rax)
++	.byte	0x44,0x0f,0x29,0x50,0x20	#movaps	%xmm10, 0x20(%rax)
++	.byte	0x44,0x0f,0x29,0x58,0x30	#movaps	%xmm11, 0x30(%rax)
++	.byte	0x44,0x0f,0x29,0x60,0x40	#movaps	%xmm12, 0x40(%rax)
++	.byte	0x44,0x0f,0x29,0x68,0x50	#movaps	%xmm13, 0x50(%rax)
++	.byte	0x44,0x0f,0x29,0x70,0x60	#movaps	%xmm14, 0x60(%rax)
++	.byte	0x44,0x0f,0x29,0x78,0x70	#movaps	%xmm15, 0x70(%rax)
++___
++$code.=<<___;
++	movdqa	.LOne(%rip), $M0
++	movd	$index, $INDEX
++
++	pxor	$Ra, $Ra
++	pxor	$Rb, $Rb
++	pxor	$Rc, $Rc
++	pxor	$Rd, $Rd
++
++	movdqa	$M0, $ONE
++	pshufd	\$0, $INDEX, $INDEX
++	mov	\$64, %rax
++
++.Lselect_loop_sse_w7:
++	movdqa	$M0, $TMP0
++	paddd	$ONE, $M0
++	movdqa	16*0($in_t), $T0a
++	movdqa	16*1($in_t), $T0b
++	pcmpeqd	$INDEX, $TMP0
++	movdqa	16*2($in_t), $T0c
++	movdqa	16*3($in_t), $T0d
++	lea	16*4($in_t), $in_t
++
++	pand	$TMP0, $T0a
++	pand	$TMP0, $T0b
++	por	$T0a, $Ra
++	pand	$TMP0, $T0c
++	por	$T0b, $Rb
++	pand	$TMP0, $T0d
++	por	$T0c, $Rc
++	prefetcht0	255($in_t)
++	por	$T0d, $Rd
++
++	dec	%rax
++	jnz	.Lselect_loop_sse_w7
++
++	movdqu	$Ra, 16*0($val)
++	movdqu	$Rb, 16*1($val)
++	movdqu	$Rc, 16*2($val)
++	movdqu	$Rd, 16*3($val)
++___
++$code.=<<___	if ($win64);
++	movaps	(%rsp), %xmm6
++	movaps	0x10(%rsp), %xmm7
++	movaps	0x20(%rsp), %xmm8
++	movaps	0x30(%rsp), %xmm9
++	movaps	0x40(%rsp), %xmm10
++	movaps	0x50(%rsp), %xmm11
++	movaps	0x60(%rsp), %xmm12
++	movaps	0x70(%rsp), %xmm13
++	movaps	0x80(%rsp), %xmm14
++	movaps	0x90(%rsp), %xmm15
++	lea	0xa8(%rsp), %rsp
++.LSEH_end_ecp_nistz256_gather_w7:
++___
++$code.=<<___;
++	ret
++.size	ecp_nistz256_gather_w7,.-ecp_nistz256_gather_w7
++___
++}
++if ($avx>1) {
++my ($val,$in_t,$index)=$win64?("%rcx","%rdx","%r8d"):("%rdi","%rsi","%edx");
++my ($TWO,$INDEX,$Ra,$Rb,$Rc)=map("%ymm$_",(0..4));
++my ($M0,$T0a,$T0b,$T0c,$TMP0)=map("%ymm$_",(5..9));
++my ($M1,$T1a,$T1b,$T1c,$TMP1)=map("%ymm$_",(10..14));
++
++$code.=<<___;
++################################################################################
++# void ecp_nistz256_avx2_gather_w5(uint64_t *val, uint64_t *in_t, int index);
++.type	ecp_nistz256_avx2_gather_w5,\@abi-omnipotent
++.align	32
++ecp_nistz256_avx2_gather_w5:
++.Lavx2_gather_w5:
++	vzeroupper
++___
++$code.=<<___	if ($win64);
++	lea	-0x88(%rsp), %rax
++.LSEH_begin_ecp_nistz256_avx2_gather_w5:
++	.byte	0x48,0x8d,0x60,0xe0		#lea	-0x20(%rax), %rsp
++	.byte	0xc5,0xf8,0x29,0x70,0xe0	#vmovaps %xmm6, -0x20(%rax)
++	.byte	0xc5,0xf8,0x29,0x78,0xf0	#vmovaps %xmm7, -0x10(%rax)
++	.byte	0xc5,0x78,0x29,0x40,0x00	#vmovaps %xmm8, 8(%rax)
++	.byte	0xc5,0x78,0x29,0x48,0x10	#vmovaps %xmm9, 0x10(%rax)
++	.byte	0xc5,0x78,0x29,0x50,0x20	#vmovaps %xmm10, 0x20(%rax)
++	.byte	0xc5,0x78,0x29,0x58,0x30	#vmovaps %xmm11, 0x30(%rax)
++	.byte	0xc5,0x78,0x29,0x60,0x40	#vmovaps %xmm12, 0x40(%rax)
++	.byte	0xc5,0x78,0x29,0x68,0x50	#vmovaps %xmm13, 0x50(%rax)
++	.byte	0xc5,0x78,0x29,0x70,0x60	#vmovaps %xmm14, 0x60(%rax)
++	.byte	0xc5,0x78,0x29,0x78,0x70	#vmovaps %xmm15, 0x70(%rax)
++___
++$code.=<<___;
++	vmovdqa	.LTwo(%rip), $TWO
++
++	vpxor	$Ra, $Ra, $Ra
++	vpxor	$Rb, $Rb, $Rb
++	vpxor	$Rc, $Rc, $Rc
++
++	vmovdqa .LOne(%rip), $M0
++	vmovdqa .LTwo(%rip), $M1
++
++	vmovd	$index, %xmm1
++	vpermd	$INDEX, $Ra, $INDEX
++
++	mov	\$8, %rax
++.Lselect_loop_avx2_w5:
++
++	vmovdqa	32*0($in_t), $T0a
++	vmovdqa	32*1($in_t), $T0b
++	vmovdqa	32*2($in_t), $T0c
++
++	vmovdqa	32*3($in_t), $T1a
++	vmovdqa	32*4($in_t), $T1b
++	vmovdqa	32*5($in_t), $T1c
++
++	vpcmpeqd	$INDEX, $M0, $TMP0
++	vpcmpeqd	$INDEX, $M1, $TMP1
++
++	vpaddd	$TWO, $M0, $M0
++	vpaddd	$TWO, $M1, $M1
++	lea	32*6($in_t), $in_t
++
++	vpand	$TMP0, $T0a, $T0a
++	vpand	$TMP0, $T0b, $T0b
++	vpand	$TMP0, $T0c, $T0c
++	vpand	$TMP1, $T1a, $T1a
++	vpand	$TMP1, $T1b, $T1b
++	vpand	$TMP1, $T1c, $T1c
++
++	vpxor	$T0a, $Ra, $Ra
++	vpxor	$T0b, $Rb, $Rb
++	vpxor	$T0c, $Rc, $Rc
++	vpxor	$T1a, $Ra, $Ra
++	vpxor	$T1b, $Rb, $Rb
++	vpxor	$T1c, $Rc, $Rc
++
++	dec %rax
++	jnz .Lselect_loop_avx2_w5
++
++	vmovdqu $Ra, 32*0($val)
++	vmovdqu $Rb, 32*1($val)
++	vmovdqu $Rc, 32*2($val)
++	vzeroupper
++___
++$code.=<<___	if ($win64);
++	movaps	(%rsp), %xmm6
++	movaps	0x10(%rsp), %xmm7
++	movaps	0x20(%rsp), %xmm8
++	movaps	0x30(%rsp), %xmm9
++	movaps	0x40(%rsp), %xmm10
++	movaps	0x50(%rsp), %xmm11
++	movaps	0x60(%rsp), %xmm12
++	movaps	0x70(%rsp), %xmm13
++	movaps	0x80(%rsp), %xmm14
++	movaps	0x90(%rsp), %xmm15
++	lea	0xa8(%rsp), %rsp
++.LSEH_end_ecp_nistz256_avx2_gather_w5:
++___
++$code.=<<___;
++	ret
++.size	ecp_nistz256_avx2_gather_w5,.-ecp_nistz256_avx2_gather_w5
++___
++}
++if ($avx>1) {
++my ($val,$in_t,$index)=$win64?("%rcx","%rdx","%r8d"):("%rdi","%rsi","%edx");
++my ($THREE,$INDEX,$Ra,$Rb)=map("%ymm$_",(0..3));
++my ($M0,$T0a,$T0b,$TMP0)=map("%ymm$_",(4..7));
++my ($M1,$T1a,$T1b,$TMP1)=map("%ymm$_",(8..11));
++my ($M2,$T2a,$T2b,$TMP2)=map("%ymm$_",(12..15));
++
++$code.=<<___;
++
++################################################################################
++# void ecp_nistz256_avx2_gather_w7(uint64_t *val, uint64_t *in_t, int index);
++.globl	ecp_nistz256_avx2_gather_w7
++.type	ecp_nistz256_avx2_gather_w7,\@abi-omnipotent
++.align	32
++ecp_nistz256_avx2_gather_w7:
++.Lavx2_gather_w7:
++	vzeroupper
++___
++$code.=<<___	if ($win64);
++	lea	-0x88(%rsp), %rax
++.LSEH_begin_ecp_nistz256_avx2_gather_w7:
++	.byte	0x48,0x8d,0x60,0xe0		#lea	-0x20(%rax), %rsp
++	.byte	0xc5,0xf8,0x29,0x70,0xe0	#vmovaps %xmm6, -0x20(%rax)
++	.byte	0xc5,0xf8,0x29,0x78,0xf0	#vmovaps %xmm7, -0x10(%rax)
++	.byte	0xc5,0x78,0x29,0x40,0x00	#vmovaps %xmm8, 8(%rax)
++	.byte	0xc5,0x78,0x29,0x48,0x10	#vmovaps %xmm9, 0x10(%rax)
++	.byte	0xc5,0x78,0x29,0x50,0x20	#vmovaps %xmm10, 0x20(%rax)
++	.byte	0xc5,0x78,0x29,0x58,0x30	#vmovaps %xmm11, 0x30(%rax)
++	.byte	0xc5,0x78,0x29,0x60,0x40	#vmovaps %xmm12, 0x40(%rax)
++	.byte	0xc5,0x78,0x29,0x68,0x50	#vmovaps %xmm13, 0x50(%rax)
++	.byte	0xc5,0x78,0x29,0x70,0x60	#vmovaps %xmm14, 0x60(%rax)
++	.byte	0xc5,0x78,0x29,0x78,0x70	#vmovaps %xmm15, 0x70(%rax)
++___
++$code.=<<___;
++	vmovdqa	.LThree(%rip), $THREE
++
++	vpxor	$Ra, $Ra, $Ra
++	vpxor	$Rb, $Rb, $Rb
++
++	vmovdqa .LOne(%rip), $M0
++	vmovdqa .LTwo(%rip), $M1
++	vmovdqa .LThree(%rip), $M2
++
++	vmovd	$index, %xmm1
++	vpermd	$INDEX, $Ra, $INDEX
++	# Skip index = 0, because it is implicitly the point at infinity
++
++	mov	\$21, %rax
++.Lselect_loop_avx2_w7:
++
++	vmovdqa	32*0($in_t), $T0a
++	vmovdqa	32*1($in_t), $T0b
++
++	vmovdqa	32*2($in_t), $T1a
++	vmovdqa	32*3($in_t), $T1b
++
++	vmovdqa	32*4($in_t), $T2a
++	vmovdqa	32*5($in_t), $T2b
++
++	vpcmpeqd	$INDEX, $M0, $TMP0
++	vpcmpeqd	$INDEX, $M1, $TMP1
++	vpcmpeqd	$INDEX, $M2, $TMP2
++
++	vpaddd	$THREE, $M0, $M0
++	vpaddd	$THREE, $M1, $M1
++	vpaddd	$THREE, $M2, $M2
++	lea	32*6($in_t), $in_t
++
++	vpand	$TMP0, $T0a, $T0a
++	vpand	$TMP0, $T0b, $T0b
++	vpand	$TMP1, $T1a, $T1a
++	vpand	$TMP1, $T1b, $T1b
++	vpand	$TMP2, $T2a, $T2a
++	vpand	$TMP2, $T2b, $T2b
++
++	vpxor	$T0a, $Ra, $Ra
++	vpxor	$T0b, $Rb, $Rb
++	vpxor	$T1a, $Ra, $Ra
++	vpxor	$T1b, $Rb, $Rb
++	vpxor	$T2a, $Ra, $Ra
++	vpxor	$T2b, $Rb, $Rb
++
++	dec %rax
++	jnz .Lselect_loop_avx2_w7
++
++
++	vmovdqa	32*0($in_t), $T0a
++	vmovdqa	32*1($in_t), $T0b
++
++	vpcmpeqd	$INDEX, $M0, $TMP0
++
++	vpand	$TMP0, $T0a, $T0a
++	vpand	$TMP0, $T0b, $T0b
++
++	vpxor	$T0a, $Ra, $Ra
++	vpxor	$T0b, $Rb, $Rb
++
++	vmovdqu $Ra, 32*0($val)
++	vmovdqu $Rb, 32*1($val)
++	vzeroupper
++___
++$code.=<<___	if ($win64);
++	movaps	(%rsp), %xmm6
++	movaps	0x10(%rsp), %xmm7
++	movaps	0x20(%rsp), %xmm8
++	movaps	0x30(%rsp), %xmm9
++	movaps	0x40(%rsp), %xmm10
++	movaps	0x50(%rsp), %xmm11
++	movaps	0x60(%rsp), %xmm12
++	movaps	0x70(%rsp), %xmm13
++	movaps	0x80(%rsp), %xmm14
++	movaps	0x90(%rsp), %xmm15
++	lea	0xa8(%rsp), %rsp
++.LSEH_end_ecp_nistz256_avx2_gather_w7:
++___
++$code.=<<___;
++	ret
++.size	ecp_nistz256_avx2_gather_w7,.-ecp_nistz256_avx2_gather_w7
++___
++} else {
++$code.=<<___;
++.globl	ecp_nistz256_avx2_gather_w7
++.type	ecp_nistz256_avx2_gather_w7,\@function,3
++.align	32
++ecp_nistz256_avx2_gather_w7:
++	.byte	0x0f,0x0b	# ud2
++	ret
++.size	ecp_nistz256_avx2_gather_w7,.-ecp_nistz256_avx2_gather_w7
++___
++}
++{{{
++########################################################################
++# This block implements higher level point_double, point_add and
++# point_add_affine. The key to performance in this case is to allow
++# out-of-order execution logic to overlap computations from next step
++# with tail processing from current step. By using tailored calling
++# sequence we minimize inter-step overhead to give processor better
++# shot at overlapping operations...
++#
++# You will notice that input data is copied to stack. Trouble is that
++# there are no registers to spare for holding original pointers and
++# reloading them, pointers, would create undesired dependencies on
++# effective addresses calculation paths. In other words it's too done
++# to favour out-of-order execution logic.
++#						
++
++my ($r_ptr,$a_ptr,$b_org,$b_ptr)=("%rdi","%rsi","%rdx","%rbx");
++my ($acc0,$acc1,$acc2,$acc3,$acc4,$acc5,$acc6,$acc7)=map("%r$_",(8..15));
++my ($t0,$t1,$t2,$t3,$t4)=("%rax","%rbp","%rcx",$acc4,$acc4);
++my ($poly1,$poly3)=($acc6,$acc7);
++
++sub load_for_mul () {
++my ($a,$b,$src0) = @_;
++my $bias = $src0 eq "%rax" ? 0 : -128;
++
++"	mov	$b, $src0
++	lea	$b, $b_ptr
++	mov	8*0+$a, $acc1
++	mov	8*1+$a, $acc2
++	lea	$bias+$a, $a_ptr
++	mov	8*2+$a, $acc3
++	mov	8*3+$a, $acc4"
++}
++
++sub load_for_sqr () {
++my ($a,$src0) = @_;
++my $bias = $src0 eq "%rax" ? 0 : -128;
++
++"	mov	8*0+$a, $src0
++	mov	8*1+$a, $acc6
++	lea	$bias+$a, $a_ptr
++	mov	8*2+$a, $acc7
++	mov	8*3+$a, $acc0"
++}
++
++									{
++########################################################################
++# operate in 4-5-0-1 "name space" that matches multiplication output
++#
++my ($a0,$a1,$a2,$a3,$t3,$t4)=($acc4,$acc5,$acc0,$acc1,$acc2,$acc3);
++
++$code.=<<___;
++.type	__ecp_nistz256_add_toq,\@abi-omnipotent
++.align	32
++__ecp_nistz256_add_toq:
++	xor	$t4,$t4
++	add	8*0($b_ptr), $a0
++	adc	8*1($b_ptr), $a1
++	 mov	$a0, $t0
++	adc	8*2($b_ptr), $a2
++	adc	8*3($b_ptr), $a3
++	 mov	$a1, $t1
++	adc	\$0, $t4
++
++	sub	\$-1, $a0
++	 mov	$a2, $t2
++	sbb	$poly1, $a1
++	sbb	\$0, $a2
++	 mov	$a3, $t3
++	sbb	$poly3, $a3
++	sbb	\$0, $t4
++
++	cmovc	$t0, $a0
++	cmovc	$t1, $a1
++	mov	$a0, 8*0($r_ptr)
++	cmovc	$t2, $a2
++	mov	$a1, 8*1($r_ptr)
++	cmovc	$t3, $a3
++	mov	$a2, 8*2($r_ptr)
++	mov	$a3, 8*3($r_ptr)
++
++	ret
++.size	__ecp_nistz256_add_toq,.-__ecp_nistz256_add_toq
++
++.type	__ecp_nistz256_sub_fromq,\@abi-omnipotent
++.align	32
++__ecp_nistz256_sub_fromq:
++	sub	8*0($b_ptr), $a0
++	sbb	8*1($b_ptr), $a1
++	 mov	$a0, $t0
++	sbb	8*2($b_ptr), $a2
++	sbb	8*3($b_ptr), $a3
++	 mov	$a1, $t1
++	sbb	$t4, $t4
++
++	add	\$-1, $a0
++	 mov	$a2, $t2
++	adc	$poly1, $a1
++	adc	\$0, $a2
++	 mov	$a3, $t3
++	adc	$poly3, $a3
++	test	$t4, $t4
++
++	cmovz	$t0, $a0
++	cmovz	$t1, $a1
++	mov	$a0, 8*0($r_ptr)
++	cmovz	$t2, $a2
++	mov	$a1, 8*1($r_ptr)
++	cmovz	$t3, $a3
++	mov	$a2, 8*2($r_ptr)
++	mov	$a3, 8*3($r_ptr)
++
++	ret
++.size	__ecp_nistz256_sub_fromq,.-__ecp_nistz256_sub_fromq
++
++.type	__ecp_nistz256_subq,\@abi-omnipotent
++.align	32
++__ecp_nistz256_subq:
++	sub	$a0, $t0
++	sbb	$a1, $t1
++	 mov	$t0, $a0
++	sbb	$a2, $t2
++	sbb	$a3, $t3
++	 mov	$t1, $a1
++	sbb	$t4, $t4
++
++	add	\$-1, $t0
++	 mov	$t2, $a2
++	adc	$poly1, $t1
++	adc	\$0, $t2
++	 mov	$t3, $a3
++	adc	$poly3, $t3
++	test	$t4, $t4
++
++	cmovnz	$t0, $a0
++	cmovnz	$t1, $a1
++	cmovnz	$t2, $a2
++	cmovnz	$t3, $a3
++
++	ret
++.size	__ecp_nistz256_subq,.-__ecp_nistz256_subq
++
++.type	__ecp_nistz256_mul_by_2q,\@abi-omnipotent
++.align	32
++__ecp_nistz256_mul_by_2q:
++	xor	$t4, $t4
++	add	$a0, $a0		# a0:a3+a0:a3
++	adc	$a1, $a1
++	 mov	$a0, $t0
++	adc	$a2, $a2
++	adc	$a3, $a3
++	 mov	$a1, $t1
++	adc	\$0, $t4
++
++	sub	\$-1, $a0
++	 mov	$a2, $t2
++	sbb	$poly1, $a1
++	sbb	\$0, $a2
++	 mov	$a3, $t3
++	sbb	$poly3, $a3
++	sbb	\$0, $t4
++
++	cmovc	$t0, $a0
++	cmovc	$t1, $a1
++	mov	$a0, 8*0($r_ptr)
++	cmovc	$t2, $a2
++	mov	$a1, 8*1($r_ptr)
++	cmovc	$t3, $a3
++	mov	$a2, 8*2($r_ptr)
++	mov	$a3, 8*3($r_ptr)
++
++	ret
++.size	__ecp_nistz256_mul_by_2q,.-__ecp_nistz256_mul_by_2q
++___
++									}
++sub gen_double () {
++    my $x = shift;
++    my ($src0,$sfx,$bias);
++    my ($S,$M,$Zsqr,$in_x,$tmp0)=map(32*$_,(0..4));
++
++    if ($x ne "x") {
++	$src0 = "%rax";
++	$sfx  = "";
++	$bias = 0;
++
++$code.=<<___;
++.globl	ecp_nistz256_point_double
++.type	ecp_nistz256_point_double,\@function,2
++.align	32
++ecp_nistz256_point_double:
++___
++$code.=<<___	if ($addx);
++	mov	\$0x80100, %ecx
++	and	OPENSSL_ia32cap_P+8(%rip), %ecx
++	cmp	\$0x80100, %ecx
++	je	.Lpoint_doublex
++___
++    } else {
++	$src0 = "%rdx";
++	$sfx  = "x";
++	$bias = 128;
++
++$code.=<<___;
++.type	ecp_nistz256_point_doublex,\@function,2
++.align	32
++ecp_nistz256_point_doublex:
++.Lpoint_doublex:
++___
++    }
++$code.=<<___;
++	push	%rbp
++	push	%rbx
++	push	%r12
++	push	%r13
++	push	%r14
++	push	%r15
++	sub	\$32*5+8, %rsp
++
++.Lpoint_double_shortcut$x:
++	movdqu	0x00($a_ptr), %xmm0		# copy	*(P256_POINT *)$a_ptr.x
++	mov	$a_ptr, $b_ptr			# backup copy
++	movdqu	0x10($a_ptr), %xmm1
++	 mov	0x20+8*0($a_ptr), $acc4		# load in_y in "5-4-0-1" order
++	 mov	0x20+8*1($a_ptr), $acc5
++	 mov	0x20+8*2($a_ptr), $acc0
++	 mov	0x20+8*3($a_ptr), $acc1
++	 mov	.Lpoly+8*1(%rip), $poly1
++	 mov	.Lpoly+8*3(%rip), $poly3
++	movdqa	%xmm0, $in_x(%rsp)
++	movdqa	%xmm1, $in_x+0x10(%rsp)
++	lea	0x20($r_ptr), $acc2
++	lea	0x40($r_ptr), $acc3
++	movq	$r_ptr, %xmm0
++	movq	$acc2, %xmm1
++	movq	$acc3, %xmm2
++
++	lea	$S(%rsp), $r_ptr
++	call	__ecp_nistz256_mul_by_2$x	# p256_mul_by_2(S, in_y);
++
++	mov	0x40+8*0($a_ptr), $src0
++	mov	0x40+8*1($a_ptr), $acc6
++	mov	0x40+8*2($a_ptr), $acc7
++	mov	0x40+8*3($a_ptr), $acc0
++	lea	0x40-$bias($a_ptr), $a_ptr
++	lea	$Zsqr(%rsp), $r_ptr
++	call	__ecp_nistz256_sqr_mont$x	# p256_sqr_mont(Zsqr, in_z);
++
++	`&load_for_sqr("$S(%rsp)", "$src0")`
++	lea	$S(%rsp), $r_ptr
++	call	__ecp_nistz256_sqr_mont$x	# p256_sqr_mont(S, S);
++
++	mov	0x20($b_ptr), $src0		# $b_ptr is still valid
++	mov	0x40+8*0($b_ptr), $acc1
++	mov	0x40+8*1($b_ptr), $acc2
++	mov	0x40+8*2($b_ptr), $acc3
++	mov	0x40+8*3($b_ptr), $acc4
++	lea	0x40-$bias($b_ptr), $a_ptr
++	lea	0x20($b_ptr), $b_ptr
++	movq	%xmm2, $r_ptr
++	call	__ecp_nistz256_mul_mont$x	# p256_mul_mont(res_z, in_z, in_y);
++	call	__ecp_nistz256_mul_by_2$x	# p256_mul_by_2(res_z, res_z);
++
++	mov	$in_x+8*0(%rsp), $acc4		# "5-4-0-1" order
++	mov	$in_x+8*1(%rsp), $acc5
++	lea	$Zsqr(%rsp), $b_ptr
++	mov	$in_x+8*2(%rsp), $acc0
++	mov	$in_x+8*3(%rsp), $acc1
++	lea	$M(%rsp), $r_ptr
++	call	__ecp_nistz256_add_to$x		# p256_add(M, in_x, Zsqr);
++
++	mov	$in_x+8*0(%rsp), $acc4		# "5-4-0-1" order
++	mov	$in_x+8*1(%rsp), $acc5
++	lea	$Zsqr(%rsp), $b_ptr
++	mov	$in_x+8*2(%rsp), $acc0
++	mov	$in_x+8*3(%rsp), $acc1
++	lea	$Zsqr(%rsp), $r_ptr
++	call	__ecp_nistz256_sub_from$x	# p256_sub(Zsqr, in_x, Zsqr);
++
++	`&load_for_sqr("$S(%rsp)", "$src0")`
++	movq	%xmm1, $r_ptr
++	call	__ecp_nistz256_sqr_mont$x	# p256_sqr_mont(res_y, S);
++___
++{	
++######## ecp_nistz256_div_by_2(res_y, res_y); ##########################
++# operate in 4-5-6-7 "name space" that matches squaring output
++#
++my ($poly1,$poly3)=($a_ptr,$t1);
++my ($a0,$a1,$a2,$a3,$t3,$t4,$t1)=($acc4,$acc5,$acc6,$acc7,$acc0,$acc1,$acc2);
++
++$code.=<<___;
++	xor	$t4, $t4
++	mov	$a0, $t0
++	add	\$-1, $a0
++	mov	$a1, $t1
++	adc	$poly1, $a1
++	mov	$a2, $t2
++	adc	\$0, $a2
++	mov	$a3, $t3
++	adc	$poly3, $a3
++	adc	\$0, $t4
++	xor	$a_ptr, $a_ptr		# borrow $a_ptr
++	test	\$1, $t0
++
++	cmovz	$t0, $a0
++	cmovz	$t1, $a1
++	cmovz	$t2, $a2
++	cmovz	$t3, $a3
++	cmovz	$a_ptr, $t4
++
++	mov	$a1, $t0		# a0:a3>>1
++	shr	\$1, $a0
++	shl	\$63, $t0
++	mov	$a2, $t1
++	shr	\$1, $a1
++	or	$t0, $a0
++	shl	\$63, $t1
++	mov	$a3, $t2
++	shr	\$1, $a2
++	or	$t1, $a1
++	shl	\$63, $t2
++	mov	$a0, 8*0($r_ptr)
++	shr	\$1, $a3
++	mov	$a1, 8*1($r_ptr)
++	shl	\$63, $t4
++	or	$t2, $a2
++	or	$t4, $a3
++	mov	$a2, 8*2($r_ptr)
++	mov	$a3, 8*3($r_ptr)
++___
++}
++$code.=<<___;
++	`&load_for_mul("$M(%rsp)", "$Zsqr(%rsp)", "$src0")`
++	lea	$M(%rsp), $r_ptr
++	call	__ecp_nistz256_mul_mont$x	# p256_mul_mont(M, M, Zsqr);
++
++	lea	$tmp0(%rsp), $r_ptr
++	call	__ecp_nistz256_mul_by_2$x
++
++	lea	$M(%rsp), $b_ptr
++	lea	$M(%rsp), $r_ptr
++	call	__ecp_nistz256_add_to$x		# p256_mul_by_3(M, M);
++
++	`&load_for_mul("$S(%rsp)", "$in_x(%rsp)", "$src0")`
++	lea	$S(%rsp), $r_ptr
++	call	__ecp_nistz256_mul_mont$x	# p256_mul_mont(S, S, in_x);
++
++	lea	$tmp0(%rsp), $r_ptr
++	call	__ecp_nistz256_mul_by_2$x	# p256_mul_by_2(tmp0, S);
++
++	`&load_for_sqr("$M(%rsp)", "$src0")`
++	movq	%xmm0, $r_ptr
++	call	__ecp_nistz256_sqr_mont$x	# p256_sqr_mont(res_x, M);
++
++	lea	$tmp0(%rsp), $b_ptr
++	mov	$acc6, $acc0			# harmonize sqr output and sub input
++	mov	$acc7, $acc1
++	mov	$a_ptr, $poly1
++	mov	$t1, $poly3
++	call	__ecp_nistz256_sub_from$x	# p256_sub(res_x, res_x, tmp0);
++
++	mov	$S+8*0(%rsp), $t0
++	mov	$S+8*1(%rsp), $t1
++	mov	$S+8*2(%rsp), $t2
++	mov	$S+8*3(%rsp), $acc2		# "4-5-0-1" order
++	lea	$S(%rsp), $r_ptr
++	call	__ecp_nistz256_sub$x		# p256_sub(S, S, res_x);
++
++	mov	$M(%rsp), $src0
++	lea	$M(%rsp), $b_ptr
++	mov	$acc4, $acc6			# harmonize sub output and mul input
++	xor	%ecx, %ecx
++	mov	$acc4, $S+8*0(%rsp)		# have to save:-(	
++	mov	$acc5, $acc2
++	mov	$acc5, $S+8*1(%rsp)
++	cmovz	$acc0, $acc3
++	mov	$acc0, $S+8*2(%rsp)
++	lea	$S-$bias(%rsp), $a_ptr
++	cmovz	$acc1, $acc4
++	mov	$acc1, $S+8*3(%rsp)
++	mov	$acc6, $acc1
++	lea	$S(%rsp), $r_ptr
++	call	__ecp_nistz256_mul_mont$x	# p256_mul_mont(S, S, M);
++
++	movq	%xmm1, $b_ptr
++	movq	%xmm1, $r_ptr
++	call	__ecp_nistz256_sub_from$x	# p256_sub(res_y, S, res_y);
++
++	add	\$32*5+8, %rsp
++	pop	%r15
++	pop	%r14
++	pop	%r13
++	pop	%r12
++	pop	%rbx
++	pop	%rbp
++	ret
++.size	ecp_nistz256_point_double$sfx,.-ecp_nistz256_point_double$sfx
++___
++}
++&gen_double("q");
++
++sub gen_add () {
++    my $x = shift;
++    my ($src0,$sfx,$bias);
++    my ($H,$Hsqr,$R,$Rsqr,$Hcub,
++	$U1,$U2,$S1,$S2,
++	$res_x,$res_y,$res_z,
++	$in1_x,$in1_y,$in1_z,
++	$in2_x,$in2_y,$in2_z)=map(32*$_,(0..17));
++    my ($Z1sqr, $Z2sqr) = ($Hsqr, $Rsqr);
++
++    if ($x ne "x") {
++	$src0 = "%rax";
++	$sfx  = "";
++	$bias = 0;
++
++$code.=<<___;
++.globl	ecp_nistz256_point_add
++.type	ecp_nistz256_point_add,\@function,3
++.align	32
++ecp_nistz256_point_add:
++___
++$code.=<<___	if ($addx);
++	mov	\$0x80100, %ecx
++	and	OPENSSL_ia32cap_P+8(%rip), %ecx
++	cmp	\$0x80100, %ecx
++	je	.Lpoint_addx
++___
++    } else {
++	$src0 = "%rdx";
++	$sfx  = "x";
++	$bias = 128;
++
++$code.=<<___;
++.type	ecp_nistz256_point_addx,\@function,3
++.align	32
++ecp_nistz256_point_addx:
++.Lpoint_addx:
++___
++    }
++$code.=<<___;
++	push	%rbp
++	push	%rbx
++	push	%r12
++	push	%r13
++	push	%r14
++	push	%r15
++	sub	\$32*18+8, %rsp
++
++	movdqu	0x00($a_ptr), %xmm0		# copy	*(P256_POINT *)$a_ptr
++	movdqu	0x10($a_ptr), %xmm1
++	movdqu	0x20($a_ptr), %xmm2
++	movdqu	0x30($a_ptr), %xmm3
++	movdqu	0x40($a_ptr), %xmm4
++	movdqu	0x50($a_ptr), %xmm5
++	mov	$a_ptr, $b_ptr			# reassign
++	mov	$b_org, $a_ptr			# reassign
++	movdqa	%xmm0, $in1_x(%rsp)
++	movdqa	%xmm1, $in1_x+0x10(%rsp)
++	movdqa	%xmm2, $in1_y(%rsp)
++	movdqa	%xmm3, $in1_y+0x10(%rsp)
++	movdqa	%xmm4, $in1_z(%rsp)
++	movdqa	%xmm5, $in1_z+0x10(%rsp)
++	por	%xmm4, %xmm5
++
++	movdqu	0x00($a_ptr), %xmm0		# copy	*(P256_POINT *)$b_ptr
++	 pshufd	\$0xb1, %xmm5, %xmm3
++	movdqu	0x10($a_ptr), %xmm1
++	movdqu	0x20($a_ptr), %xmm2
++	 por	%xmm3, %xmm5
++	movdqu	0x30($a_ptr), %xmm3
++	 mov	0x40+8*0($a_ptr), $src0		# load original in2_z
++	 mov	0x40+8*1($a_ptr), $acc6
++	 mov	0x40+8*2($a_ptr), $acc7
++	 mov	0x40+8*3($a_ptr), $acc0
++	movdqa	%xmm0, $in2_x(%rsp)
++	 pshufd	\$0x1e, %xmm5, %xmm4
++	movdqa	%xmm1, $in2_x+0x10(%rsp)
++	movdqu	0x40($a_ptr),%xmm0		# in2_z again
++	movdqu	0x50($a_ptr),%xmm1
++	movdqa	%xmm2, $in2_y(%rsp)
++	movdqa	%xmm3, $in2_y+0x10(%rsp)
++	 por	%xmm4, %xmm5
++	 pxor	%xmm4, %xmm4
++	por	%xmm0, %xmm1
++	 movq	$r_ptr, %xmm0			# save $r_ptr
++
++	lea	0x40-$bias($a_ptr), $a_ptr	# $a_ptr is still valid
++	 mov	$src0, $in2_z+8*0(%rsp)		# make in2_z copy
++	 mov	$acc6, $in2_z+8*1(%rsp)
++	 mov	$acc7, $in2_z+8*2(%rsp)
++	 mov	$acc0, $in2_z+8*3(%rsp)
++	lea	$Z2sqr(%rsp), $r_ptr		# Z2^2
++	call	__ecp_nistz256_sqr_mont$x	# p256_sqr_mont(Z2sqr, in2_z);
++
++	pcmpeqd	%xmm4, %xmm5
++	pshufd	\$0xb1, %xmm1, %xmm4
++	por	%xmm1, %xmm4
++	pshufd	\$0, %xmm5, %xmm5		# in1infty
++	pshufd	\$0x1e, %xmm4, %xmm3
++	por	%xmm3, %xmm4
++	pxor	%xmm3, %xmm3
++	pcmpeqd	%xmm3, %xmm4
++	pshufd	\$0, %xmm4, %xmm4		# in2infty
++	 mov	0x40+8*0($b_ptr), $src0		# load original in1_z
++	 mov	0x40+8*1($b_ptr), $acc6
++	 mov	0x40+8*2($b_ptr), $acc7
++	 mov	0x40+8*3($b_ptr), $acc0
++	movq	$b_ptr, %xmm1
++
++	lea	0x40-$bias($b_ptr), $a_ptr
++	lea	$Z1sqr(%rsp), $r_ptr		# Z1^2
++	call	__ecp_nistz256_sqr_mont$x	# p256_sqr_mont(Z1sqr, in1_z);
++
++	`&load_for_mul("$Z2sqr(%rsp)", "$in2_z(%rsp)", "$src0")`
++	lea	$S1(%rsp), $r_ptr		# S1 = Z2^3
++	call	__ecp_nistz256_mul_mont$x	# p256_mul_mont(S1, Z2sqr, in2_z);
++
++	`&load_for_mul("$Z1sqr(%rsp)", "$in1_z(%rsp)", "$src0")`
++	lea	$S2(%rsp), $r_ptr		# S2 = Z1^3
++	call	__ecp_nistz256_mul_mont$x	# p256_mul_mont(S2, Z1sqr, in1_z);
++
++	`&load_for_mul("$S1(%rsp)", "$in1_y(%rsp)", "$src0")`
++	lea	$S1(%rsp), $r_ptr		# S1 = Y1*Z2^3
++	call	__ecp_nistz256_mul_mont$x	# p256_mul_mont(S1, S1, in1_y);
++
++	`&load_for_mul("$S2(%rsp)", "$in2_y(%rsp)", "$src0")`
++	lea	$S2(%rsp), $r_ptr		# S2 = Y2*Z1^3
++	call	__ecp_nistz256_mul_mont$x	# p256_mul_mont(S2, S2, in2_y);
++
++	lea	$S1(%rsp), $b_ptr
++	lea	$R(%rsp), $r_ptr		# R = S2 - S1
++	call	__ecp_nistz256_sub_from$x	# p256_sub(R, S2, S1);
++
++	or	$acc5, $acc4			# see if result is zero
++	movdqa	%xmm4, %xmm2
++	or	$acc0, $acc4
++	or	$acc1, $acc4
++	por	%xmm5, %xmm2			# in1infty || in2infty
++	movq	$acc4, %xmm3
++
++	`&load_for_mul("$Z2sqr(%rsp)", "$in1_x(%rsp)", "$src0")`
++	lea	$U1(%rsp), $r_ptr		# U1 = X1*Z2^2
++	call	__ecp_nistz256_mul_mont$x	# p256_mul_mont(U1, in1_x, Z2sqr);
++
++	`&load_for_mul("$Z1sqr(%rsp)", "$in2_x(%rsp)", "$src0")`
++	lea	$U2(%rsp), $r_ptr		# U2 = X2*Z1^2
++	call	__ecp_nistz256_mul_mont$x	# p256_mul_mont(U2, in2_x, Z1sqr);
++
++	lea	$U1(%rsp), $b_ptr
++	lea	$H(%rsp), $r_ptr		# H = U2 - U1
++	call	__ecp_nistz256_sub_from$x	# p256_sub(H, U2, U1);
++
++	or	$acc5, $acc4			# see if result is zero
++	or	$acc0, $acc4
++	or	$acc1, $acc4
++
++	.byte	0x3e				# predict taken
++	jnz	.Ladd_proceed$x			# is_equal(U1,U2)?
++	movq	%xmm2, $acc0
++	movq	%xmm3, $acc1
++	test	$acc0, $acc0
++	jnz	.Ladd_proceed$x			# (in1infty || in2infty)?
++	test	$acc1, $acc1
++	jz	.Ladd_double$x			# is_equal(S1,S2)?
++
++	movq	%xmm0, $r_ptr			# restore $r_ptr
++	pxor	%xmm0, %xmm0
++	movdqu	%xmm0, 0x00($r_ptr)
++	movdqu	%xmm0, 0x10($r_ptr)
++	movdqu	%xmm0, 0x20($r_ptr)
++	movdqu	%xmm0, 0x30($r_ptr)
++	movdqu	%xmm0, 0x40($r_ptr)
++	movdqu	%xmm0, 0x50($r_ptr)
++	jmp	.Ladd_done$x
++
++.align	32
++.Ladd_double$x:
++	movq	%xmm1, $a_ptr			# restore $a_ptr
++	movq	%xmm0, $r_ptr			# restore $r_ptr
++	add	\$`32*(18-5)`, %rsp		# difference in frame sizes
++	jmp	.Lpoint_double_shortcut$x
++
++.align	32
++.Ladd_proceed$x:
++	`&load_for_sqr("$R(%rsp)", "$src0")`
++	lea	$Rsqr(%rsp), $r_ptr		# R^2
++	call	__ecp_nistz256_sqr_mont$x	# p256_sqr_mont(Rsqr, R);
++
++	`&load_for_mul("$H(%rsp)", "$in1_z(%rsp)", "$src0")`
++	lea	$res_z(%rsp), $r_ptr		# Z3 = H*Z1*Z2
++	call	__ecp_nistz256_mul_mont$x	# p256_mul_mont(res_z, H, in1_z);
++
++	`&load_for_sqr("$H(%rsp)", "$src0")`
++	lea	$Hsqr(%rsp), $r_ptr		# H^2
++	call	__ecp_nistz256_sqr_mont$x	# p256_sqr_mont(Hsqr, H);
++
++	`&load_for_mul("$res_z(%rsp)", "$in2_z(%rsp)", "$src0")`
++	lea	$res_z(%rsp), $r_ptr		# Z3 = H*Z1*Z2
++	call	__ecp_nistz256_mul_mont$x	# p256_mul_mont(res_z, res_z, in2_z);
++
++	`&load_for_mul("$Hsqr(%rsp)", "$H(%rsp)", "$src0")`
++	lea	$Hcub(%rsp), $r_ptr		# H^3
++	call	__ecp_nistz256_mul_mont$x	# p256_mul_mont(Hcub, Hsqr, H);
++
++	`&load_for_mul("$Hsqr(%rsp)", "$U1(%rsp)", "$src0")`
++	lea	$U2(%rsp), $r_ptr		# U1*H^2
++	call	__ecp_nistz256_mul_mont$x	# p256_mul_mont(U2, U1, Hsqr);
++___
++{
++#######################################################################
++# operate in 4-5-0-1 "name space" that matches multiplication output
++#
++my ($acc0,$acc1,$acc2,$acc3,$t3,$t4)=($acc4,$acc5,$acc0,$acc1,$acc2,$acc3);
++my ($poly1, $poly3)=($acc6,$acc7);
++
++$code.=<<___;
++	#lea	$U2(%rsp), $a_ptr
++	#lea	$Hsqr(%rsp), $r_ptr	# 2*U1*H^2
++	#call	__ecp_nistz256_mul_by_2	# ecp_nistz256_mul_by_2(Hsqr, U2);
++
++	xor	$t4, $t4
++	add	$acc0, $acc0		# a0:a3+a0:a3
++	lea	$Rsqr(%rsp), $a_ptr
++	adc	$acc1, $acc1
++	 mov	$acc0, $t0
++	adc	$acc2, $acc2
++	adc	$acc3, $acc3
++	 mov	$acc1, $t1
++	adc	\$0, $t4
++
++	sub	\$-1, $acc0
++	 mov	$acc2, $t2
++	sbb	$poly1, $acc1
++	sbb	\$0, $acc2
++	 mov	$acc3, $t3
++	sbb	$poly3, $acc3
++	sbb	\$0, $t4
++
++	cmovc	$t0, $acc0
++	mov	8*0($a_ptr), $t0
++	cmovc	$t1, $acc1
++	mov	8*1($a_ptr), $t1
++	cmovc	$t2, $acc2
++	mov	8*2($a_ptr), $t2
++	cmovc	$t3, $acc3
++	mov	8*3($a_ptr), $t3
++
++	call	__ecp_nistz256_sub$x		# p256_sub(res_x, Rsqr, Hsqr);
++
++	lea	$Hcub(%rsp), $b_ptr
++	lea	$res_x(%rsp), $r_ptr
++	call	__ecp_nistz256_sub_from$x	# p256_sub(res_x, res_x, Hcub);
++
++	mov	$U2+8*0(%rsp), $t0
++	mov	$U2+8*1(%rsp), $t1
++	mov	$U2+8*2(%rsp), $t2
++	mov	$U2+8*3(%rsp), $t3
++	lea	$res_y(%rsp), $r_ptr
++
++	call	__ecp_nistz256_sub$x		# p256_sub(res_y, U2, res_x);
++
++	mov	$acc0, 8*0($r_ptr)		# save the result, as
++	mov	$acc1, 8*1($r_ptr)		# __ecp_nistz256_sub doesn't
++	mov	$acc2, 8*2($r_ptr)
++	mov	$acc3, 8*3($r_ptr)
++___
++}
++$code.=<<___;
++	`&load_for_mul("$S1(%rsp)", "$Hcub(%rsp)", "$src0")`
++	lea	$S2(%rsp), $r_ptr
++	call	__ecp_nistz256_mul_mont$x	# p256_mul_mont(S2, S1, Hcub);
++
++	`&load_for_mul("$R(%rsp)", "$res_y(%rsp)", "$src0")`
++	lea	$res_y(%rsp), $r_ptr
++	call	__ecp_nistz256_mul_mont$x	# p256_mul_mont(res_y, R, res_y);
++
++	lea	$S2(%rsp), $b_ptr
++	lea	$res_y(%rsp), $r_ptr
++	call	__ecp_nistz256_sub_from$x	# p256_sub(res_y, res_y, S2);
++
++	movq	%xmm0, $r_ptr		# restore $r_ptr
++
++	movdqa	%xmm5, %xmm0		# copy_conditional(res_z, in2_z, in1infty);
++	movdqa	%xmm5, %xmm1
++	pandn	$res_z(%rsp), %xmm0
++	movdqa	%xmm5, %xmm2
++	pandn	$res_z+0x10(%rsp), %xmm1
++	movdqa	%xmm5, %xmm3
++	pand	$in2_z(%rsp), %xmm2
++	pand	$in2_z+0x10(%rsp), %xmm3
++	por	%xmm0, %xmm2
++	por	%xmm1, %xmm3
++
++	movdqa	%xmm4, %xmm0		# copy_conditional(res_z, in1_z, in2infty);
++	movdqa	%xmm4, %xmm1
++	pandn	%xmm2, %xmm0
++	movdqa	%xmm4, %xmm2
++	pandn	%xmm3, %xmm1
++	movdqa	%xmm4, %xmm3
++	pand	$in1_z(%rsp), %xmm2
++	pand	$in1_z+0x10(%rsp), %xmm3
++	por	%xmm0, %xmm2
++	por	%xmm1, %xmm3
++	movdqu	%xmm2, 0x40($r_ptr)
++	movdqu	%xmm3, 0x50($r_ptr)
++
++	movdqa	%xmm5, %xmm0		# copy_conditional(res_x, in2_x, in1infty);
++	movdqa	%xmm5, %xmm1
++	pandn	$res_x(%rsp), %xmm0
++	movdqa	%xmm5, %xmm2
++	pandn	$res_x+0x10(%rsp), %xmm1
++	movdqa	%xmm5, %xmm3
++	pand	$in2_x(%rsp), %xmm2
++	pand	$in2_x+0x10(%rsp), %xmm3
++	por	%xmm0, %xmm2
++	por	%xmm1, %xmm3
++
++	movdqa	%xmm4, %xmm0		# copy_conditional(res_x, in1_x, in2infty);
++	movdqa	%xmm4, %xmm1
++	pandn	%xmm2, %xmm0
++	movdqa	%xmm4, %xmm2
++	pandn	%xmm3, %xmm1
++	movdqa	%xmm4, %xmm3
++	pand	$in1_x(%rsp), %xmm2
++	pand	$in1_x+0x10(%rsp), %xmm3
++	por	%xmm0, %xmm2
++	por	%xmm1, %xmm3
++	movdqu	%xmm2, 0x00($r_ptr)
++	movdqu	%xmm3, 0x10($r_ptr)
++
++	movdqa	%xmm5, %xmm0		# copy_conditional(res_y, in2_y, in1infty);
++	movdqa	%xmm5, %xmm1
++	pandn	$res_y(%rsp), %xmm0
++	movdqa	%xmm5, %xmm2
++	pandn	$res_y+0x10(%rsp), %xmm1
++	movdqa	%xmm5, %xmm3
++	pand	$in2_y(%rsp), %xmm2
++	pand	$in2_y+0x10(%rsp), %xmm3
++	por	%xmm0, %xmm2
++	por	%xmm1, %xmm3
++
++	movdqa	%xmm4, %xmm0		# copy_conditional(res_y, in1_y, in2infty);
++	movdqa	%xmm4, %xmm1
++	pandn	%xmm2, %xmm0
++	movdqa	%xmm4, %xmm2
++	pandn	%xmm3, %xmm1
++	movdqa	%xmm4, %xmm3
++	pand	$in1_y(%rsp), %xmm2
++	pand	$in1_y+0x10(%rsp), %xmm3
++	por	%xmm0, %xmm2
++	por	%xmm1, %xmm3
++	movdqu	%xmm2, 0x20($r_ptr)
++	movdqu	%xmm3, 0x30($r_ptr)
++
++.Ladd_done$x:
++	add	\$32*18+8, %rsp
++	pop	%r15
++	pop	%r14
++	pop	%r13
++	pop	%r12
++	pop	%rbx
++	pop	%rbp
++	ret
++.size	ecp_nistz256_point_add$sfx,.-ecp_nistz256_point_add$sfx
++___
++}
++&gen_add("q");
++
++sub gen_add_affine () {
++    my $x = shift;
++    my ($src0,$sfx,$bias);
++    my ($U2,$S2,$H,$R,$Hsqr,$Hcub,$Rsqr,
++	$res_x,$res_y,$res_z,
++	$in1_x,$in1_y,$in1_z,
++	$in2_x,$in2_y)=map(32*$_,(0..14));
++    my $Z1sqr = $S2;
++
++    if ($x ne "x") {
++	$src0 = "%rax";
++	$sfx  = "";
++	$bias = 0;
++
++$code.=<<___;
++.globl	ecp_nistz256_point_add_affine
++.type	ecp_nistz256_point_add_affine,\@function,3
++.align	32
++ecp_nistz256_point_add_affine:
++___
++$code.=<<___	if ($addx);
++	mov	\$0x80100, %ecx
++	and	OPENSSL_ia32cap_P+8(%rip), %ecx
++	cmp	\$0x80100, %ecx
++	je	.Lpoint_add_affinex
++___
++    } else {
++	$src0 = "%rdx";
++	$sfx  = "x";
++	$bias = 128;
++
++$code.=<<___;
++.type	ecp_nistz256_point_add_affinex,\@function,3
++.align	32
++ecp_nistz256_point_add_affinex:
++.Lpoint_add_affinex:
++___
++    }
++$code.=<<___;
++	push	%rbp
++	push	%rbx
++	push	%r12
++	push	%r13
++	push	%r14
++	push	%r15
++	sub	\$32*15+8, %rsp
++
++	movdqu	0x00($a_ptr), %xmm0	# copy	*(P256_POINT *)$a_ptr
++	mov	$b_org, $b_ptr		# reassign
++	movdqu	0x10($a_ptr), %xmm1
++	movdqu	0x20($a_ptr), %xmm2
++	movdqu	0x30($a_ptr), %xmm3
++	movdqu	0x40($a_ptr), %xmm4
++	movdqu	0x50($a_ptr), %xmm5
++	 mov	0x40+8*0($a_ptr), $src0	# load original in1_z
++	 mov	0x40+8*1($a_ptr), $acc6
++	 mov	0x40+8*2($a_ptr), $acc7
++	 mov	0x40+8*3($a_ptr), $acc0
++	movdqa	%xmm0, $in1_x(%rsp)
++	movdqa	%xmm1, $in1_x+0x10(%rsp)
++	movdqa	%xmm2, $in1_y(%rsp)
++	movdqa	%xmm3, $in1_y+0x10(%rsp)
++	movdqa	%xmm4, $in1_z(%rsp)
++	movdqa	%xmm5, $in1_z+0x10(%rsp)
++	por	%xmm4, %xmm5
++
++	movdqu	0x00($b_ptr), %xmm0	# copy	*(P256_POINT_AFFINE *)$b_ptr
++	 pshufd	\$0xb1, %xmm5, %xmm3
++	movdqu	0x10($b_ptr), %xmm1
++	movdqu	0x20($b_ptr), %xmm2
++	 por	%xmm3, %xmm5
++	movdqu	0x30($b_ptr), %xmm3
++	movdqa	%xmm0, $in2_x(%rsp)
++	 pshufd	\$0x1e, %xmm5, %xmm4
++	movdqa	%xmm1, $in2_x+0x10(%rsp)
++	por	%xmm0, %xmm1
++	 movq	$r_ptr, %xmm0		# save $r_ptr
++	movdqa	%xmm2, $in2_y(%rsp)
++	movdqa	%xmm3, $in2_y+0x10(%rsp)
++	por	%xmm2, %xmm3
++	 por	%xmm4, %xmm5
++	 pxor	%xmm4, %xmm4
++	por	%xmm1, %xmm3
++
++	lea	0x40-$bias($a_ptr), $a_ptr	# $a_ptr is still valid
++	lea	$Z1sqr(%rsp), $r_ptr		# Z1^2
++	call	__ecp_nistz256_sqr_mont$x	# p256_sqr_mont(Z1sqr, in1_z);
++
++	pcmpeqd	%xmm4, %xmm5
++	pshufd	\$0xb1, %xmm3, %xmm4
++	 mov	0x00($b_ptr), $src0		# $b_ptr is still valid
++	 #lea	0x00($b_ptr), $b_ptr
++	 mov	$acc4, $acc1			# harmonize sqr output and mul input
++	por	%xmm3, %xmm4
++	pshufd	\$0, %xmm5, %xmm5		# in1infty
++	pshufd	\$0x1e, %xmm4, %xmm3
++	 mov	$acc5, $acc2
++	por	%xmm3, %xmm4
++	pxor	%xmm3, %xmm3
++	 mov	$acc6, $acc3
++	pcmpeqd	%xmm3, %xmm4
++	pshufd	\$0, %xmm4, %xmm4		# in2infty
++
++	lea	$Z1sqr-$bias(%rsp), $a_ptr
++	mov	$acc7, $acc4
++	lea	$U2(%rsp), $r_ptr		# U2 = X2*Z1^2
++	call	__ecp_nistz256_mul_mont$x	# p256_mul_mont(U2, Z1sqr, in2_x);
++
++	lea	$in1_x(%rsp), $b_ptr
++	lea	$H(%rsp), $r_ptr		# H = U2 - U1
++	call	__ecp_nistz256_sub_from$x	# p256_sub(H, U2, in1_x);
++
++	`&load_for_mul("$Z1sqr(%rsp)", "$in1_z(%rsp)", "$src0")`
++	lea	$S2(%rsp), $r_ptr		# S2 = Z1^3
++	call	__ecp_nistz256_mul_mont$x	# p256_mul_mont(S2, Z1sqr, in1_z);
++
++	`&load_for_mul("$H(%rsp)", "$in1_z(%rsp)", "$src0")`
++	lea	$res_z(%rsp), $r_ptr		# Z3 = H*Z1*Z2
++	call	__ecp_nistz256_mul_mont$x	# p256_mul_mont(res_z, H, in1_z);
++
++	`&load_for_mul("$S2(%rsp)", "$in2_y(%rsp)", "$src0")`
++	lea	$S2(%rsp), $r_ptr		# S2 = Y2*Z1^3
++	call	__ecp_nistz256_mul_mont$x	# p256_mul_mont(S2, S2, in2_y);
++
++	lea	$in1_y(%rsp), $b_ptr
++	lea	$R(%rsp), $r_ptr		# R = S2 - S1
++	call	__ecp_nistz256_sub_from$x	# p256_sub(R, S2, in1_y);
++
++	`&load_for_sqr("$H(%rsp)", "$src0")`
++	lea	$Hsqr(%rsp), $r_ptr		# H^2
++	call	__ecp_nistz256_sqr_mont$x	# p256_sqr_mont(Hsqr, H);
++
++	`&load_for_sqr("$R(%rsp)", "$src0")`
++	lea	$Rsqr(%rsp), $r_ptr		# R^2
++	call	__ecp_nistz256_sqr_mont$x	# p256_sqr_mont(Rsqr, R);
++
++	`&load_for_mul("$H(%rsp)", "$Hsqr(%rsp)", "$src0")`
++	lea	$Hcub(%rsp), $r_ptr		# H^3
++	call	__ecp_nistz256_mul_mont$x	# p256_mul_mont(Hcub, Hsqr, H);
++
++	`&load_for_mul("$Hsqr(%rsp)", "$in1_x(%rsp)", "$src0")`
++	lea	$U2(%rsp), $r_ptr		# U1*H^2
++	call	__ecp_nistz256_mul_mont$x	# p256_mul_mont(U2, in1_x, Hsqr);
++___
++{
++#######################################################################
++# operate in 4-5-0-1 "name space" that matches multiplication output
++#
++my ($acc0,$acc1,$acc2,$acc3,$t3,$t4)=($acc4,$acc5,$acc0,$acc1,$acc2,$acc3);
++my ($poly1, $poly3)=($acc6,$acc7);
++
++$code.=<<___;
++	#lea	$U2(%rsp), $a_ptr
++	#lea	$Hsqr(%rsp), $r_ptr	# 2*U1*H^2
++	#call	__ecp_nistz256_mul_by_2	# ecp_nistz256_mul_by_2(Hsqr, U2);
++
++	xor	$t4, $t4
++	add	$acc0, $acc0		# a0:a3+a0:a3
++	lea	$Rsqr(%rsp), $a_ptr
++	adc	$acc1, $acc1
++	 mov	$acc0, $t0
++	adc	$acc2, $acc2
++	adc	$acc3, $acc3
++	 mov	$acc1, $t1
++	adc	\$0, $t4
++
++	sub	\$-1, $acc0
++	 mov	$acc2, $t2
++	sbb	$poly1, $acc1
++	sbb	\$0, $acc2
++	 mov	$acc3, $t3
++	sbb	$poly3, $acc3
++	sbb	\$0, $t4
++
++	cmovc	$t0, $acc0
++	mov	8*0($a_ptr), $t0
++	cmovc	$t1, $acc1
++	mov	8*1($a_ptr), $t1
++	cmovc	$t2, $acc2
++	mov	8*2($a_ptr), $t2
++	cmovc	$t3, $acc3
++	mov	8*3($a_ptr), $t3
++
++	call	__ecp_nistz256_sub$x		# p256_sub(res_x, Rsqr, Hsqr);
++
++	lea	$Hcub(%rsp), $b_ptr
++	lea	$res_x(%rsp), $r_ptr
++	call	__ecp_nistz256_sub_from$x	# p256_sub(res_x, res_x, Hcub);
++
++	mov	$U2+8*0(%rsp), $t0
++	mov	$U2+8*1(%rsp), $t1
++	mov	$U2+8*2(%rsp), $t2
++	mov	$U2+8*3(%rsp), $t3
++	lea	$H(%rsp), $r_ptr
++
++	call	__ecp_nistz256_sub$x		# p256_sub(H, U2, res_x);
++
++	mov	$acc0, 8*0($r_ptr)		# save the result, as
++	mov	$acc1, 8*1($r_ptr)		# __ecp_nistz256_sub doesn't
++	mov	$acc2, 8*2($r_ptr)
++	mov	$acc3, 8*3($r_ptr)
++___
++}
++$code.=<<___;
++	`&load_for_mul("$Hcub(%rsp)", "$in1_y(%rsp)", "$src0")`
++	lea	$S2(%rsp), $r_ptr
++	call	__ecp_nistz256_mul_mont$x	# p256_mul_mont(S2, Hcub, in1_y);
++
++	`&load_for_mul("$H(%rsp)", "$R(%rsp)", "$src0")`
++	lea	$H(%rsp), $r_ptr
++	call	__ecp_nistz256_mul_mont$x	# p256_mul_mont(H, H, R);
++
++	lea	$S2(%rsp), $b_ptr
++	lea	$res_y(%rsp), $r_ptr
++	call	__ecp_nistz256_sub_from$x	# p256_sub(res_y, H, S2);
++
++	movq	%xmm0, $r_ptr		# restore $r_ptr
++
++	movdqa	%xmm5, %xmm0		# copy_conditional(res_z, ONE, in1infty);
++	movdqa	%xmm5, %xmm1
++	pandn	$res_z(%rsp), %xmm0
++	movdqa	%xmm5, %xmm2
++	pandn	$res_z+0x10(%rsp), %xmm1
++	movdqa	%xmm5, %xmm3
++	pand	.LONE_mont(%rip), %xmm2
++	pand	.LONE_mont+0x10(%rip), %xmm3
++	por	%xmm0, %xmm2
++	por	%xmm1, %xmm3
++
++	movdqa	%xmm4, %xmm0		# copy_conditional(res_z, in1_z, in2infty);
++	movdqa	%xmm4, %xmm1
++	pandn	%xmm2, %xmm0
++	movdqa	%xmm4, %xmm2
++	pandn	%xmm3, %xmm1
++	movdqa	%xmm4, %xmm3
++	pand	$in1_z(%rsp), %xmm2
++	pand	$in1_z+0x10(%rsp), %xmm3
++	por	%xmm0, %xmm2
++	por	%xmm1, %xmm3
++	movdqu	%xmm2, 0x40($r_ptr)
++	movdqu	%xmm3, 0x50($r_ptr)
++
++	movdqa	%xmm5, %xmm0		# copy_conditional(res_x, in2_x, in1infty);
++	movdqa	%xmm5, %xmm1
++	pandn	$res_x(%rsp), %xmm0
++	movdqa	%xmm5, %xmm2
++	pandn	$res_x+0x10(%rsp), %xmm1
++	movdqa	%xmm5, %xmm3
++	pand	$in2_x(%rsp), %xmm2
++	pand	$in2_x+0x10(%rsp), %xmm3
++	por	%xmm0, %xmm2
++	por	%xmm1, %xmm3
++
++	movdqa	%xmm4, %xmm0		# copy_conditional(res_x, in1_x, in2infty);
++	movdqa	%xmm4, %xmm1
++	pandn	%xmm2, %xmm0
++	movdqa	%xmm4, %xmm2
++	pandn	%xmm3, %xmm1
++	movdqa	%xmm4, %xmm3
++	pand	$in1_x(%rsp), %xmm2
++	pand	$in1_x+0x10(%rsp), %xmm3
++	por	%xmm0, %xmm2
++	por	%xmm1, %xmm3
++	movdqu	%xmm2, 0x00($r_ptr)
++	movdqu	%xmm3, 0x10($r_ptr)
++
++	movdqa	%xmm5, %xmm0		# copy_conditional(res_y, in2_y, in1infty);
++	movdqa	%xmm5, %xmm1
++	pandn	$res_y(%rsp), %xmm0
++	movdqa	%xmm5, %xmm2
++	pandn	$res_y+0x10(%rsp), %xmm1
++	movdqa	%xmm5, %xmm3
++	pand	$in2_y(%rsp), %xmm2
++	pand	$in2_y+0x10(%rsp), %xmm3
++	por	%xmm0, %xmm2
++	por	%xmm1, %xmm3
++
++	movdqa	%xmm4, %xmm0		# copy_conditional(res_y, in1_y, in2infty);
++	movdqa	%xmm4, %xmm1
++	pandn	%xmm2, %xmm0
++	movdqa	%xmm4, %xmm2
++	pandn	%xmm3, %xmm1
++	movdqa	%xmm4, %xmm3
++	pand	$in1_y(%rsp), %xmm2
++	pand	$in1_y+0x10(%rsp), %xmm3
++	por	%xmm0, %xmm2
++	por	%xmm1, %xmm3
++	movdqu	%xmm2, 0x20($r_ptr)
++	movdqu	%xmm3, 0x30($r_ptr)
++
++	add	\$32*15+8, %rsp
++	pop	%r15
++	pop	%r14
++	pop	%r13
++	pop	%r12
++	pop	%rbx
++	pop	%rbp
++	ret
++.size	ecp_nistz256_point_add_affine$sfx,.-ecp_nistz256_point_add_affine$sfx
++___
++}
++&gen_add_affine("q");
++
++########################################################################
++# AD*X magic
++#
++if ($addx) {								{
++########################################################################
++# operate in 4-5-0-1 "name space" that matches multiplication output
++#
++my ($a0,$a1,$a2,$a3,$t3,$t4)=($acc4,$acc5,$acc0,$acc1,$acc2,$acc3);
++
++$code.=<<___;
++.type	__ecp_nistz256_add_tox,\@abi-omnipotent
++.align	32
++__ecp_nistz256_add_tox:
++	xor	$t4, $t4
++	adc	8*0($b_ptr), $a0
++	adc	8*1($b_ptr), $a1
++	 mov	$a0, $t0
++	adc	8*2($b_ptr), $a2
++	adc	8*3($b_ptr), $a3
++	 mov	$a1, $t1
++	adc	\$0, $t4
++
++	xor	$t3, $t3
++	sbb	\$-1, $a0
++	 mov	$a2, $t2
++	sbb	$poly1, $a1
++	sbb	\$0, $a2
++	 mov	$a3, $t3
++	sbb	$poly3, $a3
++	sbb	\$0, $t4
++
++	cmovc	$t0, $a0
++	cmovc	$t1, $a1
++	mov	$a0, 8*0($r_ptr)
++	cmovc	$t2, $a2
++	mov	$a1, 8*1($r_ptr)
++	cmovc	$t3, $a3
++	mov	$a2, 8*2($r_ptr)
++	mov	$a3, 8*3($r_ptr)
++
++	ret
++.size	__ecp_nistz256_add_tox,.-__ecp_nistz256_add_tox
++
++.type	__ecp_nistz256_sub_fromx,\@abi-omnipotent
++.align	32
++__ecp_nistz256_sub_fromx:
++	xor	$t4, $t4
++	sbb	8*0($b_ptr), $a0
++	sbb	8*1($b_ptr), $a1
++	 mov	$a0, $t0
++	sbb	8*2($b_ptr), $a2
++	sbb	8*3($b_ptr), $a3
++	 mov	$a1, $t1
++	sbb	\$0, $t4
++
++	xor	$t3, $t3
++	adc	\$-1, $a0
++	 mov	$a2, $t2
++	adc	$poly1, $a1
++	adc	\$0, $a2
++	 mov	$a3, $t3
++	adc	$poly3, $a3
++
++	bt	\$0, $t4
++	cmovnc	$t0, $a0
++	cmovnc	$t1, $a1
++	mov	$a0, 8*0($r_ptr)
++	cmovnc	$t2, $a2
++	mov	$a1, 8*1($r_ptr)
++	cmovnc	$t3, $a3
++	mov	$a2, 8*2($r_ptr)
++	mov	$a3, 8*3($r_ptr)
++
++	ret
++.size	__ecp_nistz256_sub_fromx,.-__ecp_nistz256_sub_fromx
++
++.type	__ecp_nistz256_subx,\@abi-omnipotent
++.align	32
++__ecp_nistz256_subx:
++	xor	$t4, $t4
++	sbb	$a0, $t0
++	sbb	$a1, $t1
++	 mov	$t0, $a0
++	sbb	$a2, $t2
++	sbb	$a3, $t3
++	 mov	$t1, $a1
++	sbb	\$0, $t4
++
++	xor	$a3 ,$a3
++	adc	\$-1, $t0
++	 mov	$t2, $a2
++	adc	$poly1, $t1
++	adc	\$0, $t2
++	 mov	$t3, $a3
++	adc	$poly3, $t3
++
++	bt	\$0, $t4
++	cmovc	$t0, $a0
++	cmovc	$t1, $a1
++	cmovc	$t2, $a2
++	cmovc	$t3, $a3
++
++	ret
++.size	__ecp_nistz256_subx,.-__ecp_nistz256_subx
++
++.type	__ecp_nistz256_mul_by_2x,\@abi-omnipotent
++.align	32
++__ecp_nistz256_mul_by_2x:
++	xor	$t4, $t4
++	adc	$a0, $a0		# a0:a3+a0:a3
++	adc	$a1, $a1
++	 mov	$a0, $t0
++	adc	$a2, $a2
++	adc	$a3, $a3
++	 mov	$a1, $t1
++	adc	\$0, $t4
++
++	xor	$t3, $t3
++	sbb	\$-1, $a0
++	 mov	$a2, $t2
++	sbb	$poly1, $a1
++	sbb	\$0, $a2
++	 mov	$a3, $t3
++	sbb	$poly3, $a3
++	sbb	\$0, $t4
++
++	cmovc	$t0, $a0
++	cmovc	$t1, $a1
++	mov	$a0, 8*0($r_ptr)
++	cmovc	$t2, $a2
++	mov	$a1, 8*1($r_ptr)
++	cmovc	$t3, $a3
++	mov	$a2, 8*2($r_ptr)
++	mov	$a3, 8*3($r_ptr)
++
++	ret
++.size	__ecp_nistz256_mul_by_2x,.-__ecp_nistz256_mul_by_2x
++___
++									}
++&gen_double("x");
++&gen_add("x");
++&gen_add_affine("x");
++}
++}}}
++
++########################################################################
++# Convert ecp_nistz256_table.c to layout expected by ecp_nistz_gather_w7
++#
++open TABLE,") {
++	s/TOBN\(\s*(0x[0-9a-f]+),\s*(0x[0-9a-f]+)\s*\)/push @arr,hex($2),hex($1)/geo;
++}
++close TABLE;
++
++die "insane number of elements" if ($#arr != 64*16*37-1);
++
++print <<___;
++.text
++.globl	ecp_nistz256_precomputed
++.type	ecp_nistz256_precomputed,\@object
++.align	4096
++ecp_nistz256_precomputed:
++___
++while (@line=splice(@arr,0,16)) {
++	print ".long\t",join(',',map { sprintf "0x%08x",$_} @line),"\n";
++}
++print <<___;
++.size	ecp_nistz256_precomputed,.-ecp_nistz256_precomputed
++___
++
++$code =~ s/\`([^\`]*)\`/eval $1/gem;
++print $code;
++close STDOUT;
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/ec/build.info b/CryptoPkg/Library/OpensslLib/openssl/crypto/ec/build.info
+new file mode 100644
+index 0000000..970c292
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/ec/build.info
+@@ -0,0 +1,28 @@
++LIBS=../../libcrypto
++SOURCE[../../libcrypto]=\
++        ec_lib.c ecp_smpl.c ecp_mont.c ecp_nist.c ec_cvt.c ec_mult.c \
++        ec_err.c ec_curve.c ec_check.c ec_print.c ec_asn1.c ec_key.c \
++        ec2_smpl.c ec2_mult.c ec_ameth.c ec_pmeth.c eck_prn.c \
++        ecp_nistp224.c ecp_nistp256.c ecp_nistp521.c ecp_nistputil.c \
++        ecp_oct.c ec2_oct.c ec_oct.c ec_kmeth.c ecdh_ossl.c ecdh_kdf.c \
++        ecdsa_ossl.c ecdsa_sign.c ecdsa_vrf.c curve25519.c ecx_meth.c \
++        {- $target{ec_asm_src} -}
++
++GENERATE[ecp_nistz256-x86.s]=asm/ecp_nistz256-x86.pl $(PERLASM_SCHEME) $(CFLAGS) $(LIB_CFLAGS) $(PROCESSOR)
++
++GENERATE[ecp_nistz256-x86_64.s]=asm/ecp_nistz256-x86_64.pl $(PERLASM_SCHEME)
++
++GENERATE[ecp_nistz256-avx2.s]=asm/ecp_nistz256-avx2.pl $(PERLASM_SCHEME)
++
++GENERATE[ecp_nistz256-sparcv9.S]=asm/ecp_nistz256-sparcv9.pl $(PERLASM_SCHEME)
++INCLUDE[ecp_nistz256-sparcv9.o]=..
++
++GENERATE[ecp_nistz256-armv4.S]=asm/ecp_nistz256-armv4.pl $(PERLASM_SCHEME)
++INCLUDE[ecp_nistz256-armv4.o]=..
++GENERATE[ecp_nistz256-armv8.S]=asm/ecp_nistz256-armv8.pl $(PERLASM_SCHEME)
++INCLUDE[ecp_nistz256-armv8.o]=..
++
++BEGINRAW[Makefile]
++{- $builddir -}/ecp_nistz256-%.S:	{- $sourcedir -}/asm/ecp_nistz256-%.pl
++	CC="$(CC)" $(PERL) $< $(PERLASM_SCHEME) $@
++ENDRAW[Makefile]
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/ec/curve25519.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/ec/curve25519.c
+new file mode 100644
+index 0000000..e535823
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/ec/curve25519.c
+@@ -0,0 +1,3394 @@
++/*
++ * Copyright 2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++/* This code is mostly taken from the ref10 version of Ed25519 in SUPERCOP
++ * 20141124 (http://bench.cr.yp.to/supercop.html).
++ *
++ * The field functions are shared by Ed25519 and X25519 where possible. */
++
++#include 
++#include "ec_lcl.h"
++
++
++/* fe means field element. Here the field is \Z/(2^255-19). An element t,
++ * entries t[0]...t[9], represents the integer t[0]+2^26 t[1]+2^51 t[2]+2^77
++ * t[3]+2^102 t[4]+...+2^230 t[9]. Bounds on each t[i] vary depending on
++ * context.  */
++typedef int32_t fe[10];
++
++static const int64_t kBottom25Bits = 0x1ffffffLL;
++static const int64_t kBottom26Bits = 0x3ffffffLL;
++static const int64_t kTop39Bits = 0xfffffffffe000000LL;
++static const int64_t kTop38Bits = 0xfffffffffc000000LL;
++
++static uint64_t load_3(const uint8_t *in) {
++  uint64_t result;
++  result = (uint64_t)in[0];
++  result |= ((uint64_t)in[1]) << 8;
++  result |= ((uint64_t)in[2]) << 16;
++  return result;
++}
++
++static uint64_t load_4(const uint8_t *in) {
++  uint64_t result;
++  result = (uint64_t)in[0];
++  result |= ((uint64_t)in[1]) << 8;
++  result |= ((uint64_t)in[2]) << 16;
++  result |= ((uint64_t)in[3]) << 24;
++  return result;
++}
++
++static void fe_frombytes(fe h, const uint8_t *s) {
++  /* Ignores top bit of h. */
++  int64_t h0 = load_4(s);
++  int64_t h1 = load_3(s + 4) << 6;
++  int64_t h2 = load_3(s + 7) << 5;
++  int64_t h3 = load_3(s + 10) << 3;
++  int64_t h4 = load_3(s + 13) << 2;
++  int64_t h5 = load_4(s + 16);
++  int64_t h6 = load_3(s + 20) << 7;
++  int64_t h7 = load_3(s + 23) << 5;
++  int64_t h8 = load_3(s + 26) << 4;
++  int64_t h9 = (load_3(s + 29) & 8388607) << 2;
++  int64_t carry0;
++  int64_t carry1;
++  int64_t carry2;
++  int64_t carry3;
++  int64_t carry4;
++  int64_t carry5;
++  int64_t carry6;
++  int64_t carry7;
++  int64_t carry8;
++  int64_t carry9;
++
++  carry9 = h9 + (1 << 24); h0 += (carry9 >> 25) * 19; h9 -= carry9 & kTop39Bits;
++  carry1 = h1 + (1 << 24); h2 += carry1 >> 25; h1 -= carry1 & kTop39Bits;
++  carry3 = h3 + (1 << 24); h4 += carry3 >> 25; h3 -= carry3 & kTop39Bits;
++  carry5 = h5 + (1 << 24); h6 += carry5 >> 25; h5 -= carry5 & kTop39Bits;
++  carry7 = h7 + (1 << 24); h8 += carry7 >> 25; h7 -= carry7 & kTop39Bits;
++
++  carry0 = h0 + (1 << 25); h1 += carry0 >> 26; h0 -= carry0 & kTop38Bits;
++  carry2 = h2 + (1 << 25); h3 += carry2 >> 26; h2 -= carry2 & kTop38Bits;
++  carry4 = h4 + (1 << 25); h5 += carry4 >> 26; h4 -= carry4 & kTop38Bits;
++  carry6 = h6 + (1 << 25); h7 += carry6 >> 26; h6 -= carry6 & kTop38Bits;
++  carry8 = h8 + (1 << 25); h9 += carry8 >> 26; h8 -= carry8 & kTop38Bits;
++
++  h[0] = h0;
++  h[1] = h1;
++  h[2] = h2;
++  h[3] = h3;
++  h[4] = h4;
++  h[5] = h5;
++  h[6] = h6;
++  h[7] = h7;
++  h[8] = h8;
++  h[9] = h9;
++}
++
++/* Preconditions:
++ *  |h| bounded by 1.1*2^26,1.1*2^25,1.1*2^26,1.1*2^25,etc.
++ *
++ * Write p=2^255-19; q=floor(h/p).
++ * Basic claim: q = floor(2^(-255)(h + 19 2^(-25)h9 + 2^(-1))).
++ *
++ * Proof:
++ *   Have |h|<=p so |q|<=1 so |19^2 2^(-255) q|<1/4.
++ *   Also have |h-2^230 h9|<2^231 so |19 2^(-255)(h-2^230 h9)|<1/4.
++ *
++ *   Write y=2^(-1)-19^2 2^(-255)q-19 2^(-255)(h-2^230 h9).
++ *   Then 0> 25;
++  q = (h0 + q) >> 26;
++  q = (h1 + q) >> 25;
++  q = (h2 + q) >> 26;
++  q = (h3 + q) >> 25;
++  q = (h4 + q) >> 26;
++  q = (h5 + q) >> 25;
++  q = (h6 + q) >> 26;
++  q = (h7 + q) >> 25;
++  q = (h8 + q) >> 26;
++  q = (h9 + q) >> 25;
++
++  /* Goal: Output h-(2^255-19)q, which is between 0 and 2^255-20. */
++  h0 += 19 * q;
++  /* Goal: Output h-2^255 q, which is between 0 and 2^255-20. */
++
++  h1 += h0 >> 26; h0 &= kBottom26Bits;
++  h2 += h1 >> 25; h1 &= kBottom25Bits;
++  h3 += h2 >> 26; h2 &= kBottom26Bits;
++  h4 += h3 >> 25; h3 &= kBottom25Bits;
++  h5 += h4 >> 26; h4 &= kBottom26Bits;
++  h6 += h5 >> 25; h5 &= kBottom25Bits;
++  h7 += h6 >> 26; h6 &= kBottom26Bits;
++  h8 += h7 >> 25; h7 &= kBottom25Bits;
++  h9 += h8 >> 26; h8 &= kBottom26Bits;
++                  h9 &= kBottom25Bits;
++                  /* h10 = carry9 */
++
++  /* Goal: Output h0+...+2^255 h10-2^255 q, which is between 0 and 2^255-20.
++   * Have h0+...+2^230 h9 between 0 and 2^255-1;
++   * evidently 2^255 h10-2^255 q = 0.
++   * Goal: Output h0+...+2^230 h9.  */
++
++  s[0] = h0 >> 0;
++  s[1] = h0 >> 8;
++  s[2] = h0 >> 16;
++  s[3] = (h0 >> 24) | ((uint32_t)(h1) << 2);
++  s[4] = h1 >> 6;
++  s[5] = h1 >> 14;
++  s[6] = (h1 >> 22) | ((uint32_t)(h2) << 3);
++  s[7] = h2 >> 5;
++  s[8] = h2 >> 13;
++  s[9] = (h2 >> 21) | ((uint32_t)(h3) << 5);
++  s[10] = h3 >> 3;
++  s[11] = h3 >> 11;
++  s[12] = (h3 >> 19) | ((uint32_t)(h4) << 6);
++  s[13] = h4 >> 2;
++  s[14] = h4 >> 10;
++  s[15] = h4 >> 18;
++  s[16] = h5 >> 0;
++  s[17] = h5 >> 8;
++  s[18] = h5 >> 16;
++  s[19] = (h5 >> 24) | ((uint32_t)(h6) << 1);
++  s[20] = h6 >> 7;
++  s[21] = h6 >> 15;
++  s[22] = (h6 >> 23) | ((uint32_t)(h7) << 3);
++  s[23] = h7 >> 5;
++  s[24] = h7 >> 13;
++  s[25] = (h7 >> 21) | ((uint32_t)(h8) << 4);
++  s[26] = h8 >> 4;
++  s[27] = h8 >> 12;
++  s[28] = (h8 >> 20) | ((uint32_t)(h9) << 6);
++  s[29] = h9 >> 2;
++  s[30] = h9 >> 10;
++  s[31] = h9 >> 18;
++}
++
++/* h = f */
++static void fe_copy(fe h, const fe f) {
++  memmove(h, f, sizeof(int32_t) * 10);
++}
++
++/* h = 0 */
++static void fe_0(fe h) { memset(h, 0, sizeof(int32_t) * 10); }
++
++/* h = 1 */
++static void fe_1(fe h) {
++  memset(h, 0, sizeof(int32_t) * 10);
++  h[0] = 1;
++}
++
++/* h = f + g
++ * Can overlap h with f or g.
++ *
++ * Preconditions:
++ *    |f| bounded by 1.1*2^25,1.1*2^24,1.1*2^25,1.1*2^24,etc.
++ *    |g| bounded by 1.1*2^25,1.1*2^24,1.1*2^25,1.1*2^24,etc.
++ *
++ * Postconditions:
++ *    |h| bounded by 1.1*2^26,1.1*2^25,1.1*2^26,1.1*2^25,etc. */
++static void fe_add(fe h, const fe f, const fe g) {
++  unsigned i;
++  for (i = 0; i < 10; i++) {
++    h[i] = f[i] + g[i];
++  }
++}
++
++/* h = f - g
++ * Can overlap h with f or g.
++ *
++ * Preconditions:
++ *    |f| bounded by 1.1*2^25,1.1*2^24,1.1*2^25,1.1*2^24,etc.
++ *    |g| bounded by 1.1*2^25,1.1*2^24,1.1*2^25,1.1*2^24,etc.
++ *
++ * Postconditions:
++ *    |h| bounded by 1.1*2^26,1.1*2^25,1.1*2^26,1.1*2^25,etc. */
++static void fe_sub(fe h, const fe f, const fe g) {
++  unsigned i;
++  for (i = 0; i < 10; i++) {
++    h[i] = f[i] - g[i];
++  }
++}
++
++/* h = f * g
++ * Can overlap h with f or g.
++ *
++ * Preconditions:
++ *    |f| bounded by 1.65*2^26,1.65*2^25,1.65*2^26,1.65*2^25,etc.
++ *    |g| bounded by 1.65*2^26,1.65*2^25,1.65*2^26,1.65*2^25,etc.
++ *
++ * Postconditions:
++ *    |h| bounded by 1.01*2^25,1.01*2^24,1.01*2^25,1.01*2^24,etc.
++ *
++ * Notes on implementation strategy:
++ *
++ * Using schoolbook multiplication.
++ * Karatsuba would save a little in some cost models.
++ *
++ * Most multiplications by 2 and 19 are 32-bit precomputations;
++ * cheaper than 64-bit postcomputations.
++ *
++ * There is one remaining multiplication by 19 in the carry chain;
++ * one *19 precomputation can be merged into this,
++ * but the resulting data flow is considerably less clean.
++ *
++ * There are 12 carries below.
++ * 10 of them are 2-way parallelizable and vectorizable.
++ * Can get away with 11 carries, but then data flow is much deeper.
++ *
++ * With tighter constraints on inputs can squeeze carries into int32. */
++static void fe_mul(fe h, const fe f, const fe g) {
++  int32_t f0 = f[0];
++  int32_t f1 = f[1];
++  int32_t f2 = f[2];
++  int32_t f3 = f[3];
++  int32_t f4 = f[4];
++  int32_t f5 = f[5];
++  int32_t f6 = f[6];
++  int32_t f7 = f[7];
++  int32_t f8 = f[8];
++  int32_t f9 = f[9];
++  int32_t g0 = g[0];
++  int32_t g1 = g[1];
++  int32_t g2 = g[2];
++  int32_t g3 = g[3];
++  int32_t g4 = g[4];
++  int32_t g5 = g[5];
++  int32_t g6 = g[6];
++  int32_t g7 = g[7];
++  int32_t g8 = g[8];
++  int32_t g9 = g[9];
++  int32_t g1_19 = 19 * g1; /* 1.959375*2^29 */
++  int32_t g2_19 = 19 * g2; /* 1.959375*2^30; still ok */
++  int32_t g3_19 = 19 * g3;
++  int32_t g4_19 = 19 * g4;
++  int32_t g5_19 = 19 * g5;
++  int32_t g6_19 = 19 * g6;
++  int32_t g7_19 = 19 * g7;
++  int32_t g8_19 = 19 * g8;
++  int32_t g9_19 = 19 * g9;
++  int32_t f1_2 = 2 * f1;
++  int32_t f3_2 = 2 * f3;
++  int32_t f5_2 = 2 * f5;
++  int32_t f7_2 = 2 * f7;
++  int32_t f9_2 = 2 * f9;
++  int64_t f0g0    = f0   * (int64_t) g0;
++  int64_t f0g1    = f0   * (int64_t) g1;
++  int64_t f0g2    = f0   * (int64_t) g2;
++  int64_t f0g3    = f0   * (int64_t) g3;
++  int64_t f0g4    = f0   * (int64_t) g4;
++  int64_t f0g5    = f0   * (int64_t) g5;
++  int64_t f0g6    = f0   * (int64_t) g6;
++  int64_t f0g7    = f0   * (int64_t) g7;
++  int64_t f0g8    = f0   * (int64_t) g8;
++  int64_t f0g9    = f0   * (int64_t) g9;
++  int64_t f1g0    = f1   * (int64_t) g0;
++  int64_t f1g1_2  = f1_2 * (int64_t) g1;
++  int64_t f1g2    = f1   * (int64_t) g2;
++  int64_t f1g3_2  = f1_2 * (int64_t) g3;
++  int64_t f1g4    = f1   * (int64_t) g4;
++  int64_t f1g5_2  = f1_2 * (int64_t) g5;
++  int64_t f1g6    = f1   * (int64_t) g6;
++  int64_t f1g7_2  = f1_2 * (int64_t) g7;
++  int64_t f1g8    = f1   * (int64_t) g8;
++  int64_t f1g9_38 = f1_2 * (int64_t) g9_19;
++  int64_t f2g0    = f2   * (int64_t) g0;
++  int64_t f2g1    = f2   * (int64_t) g1;
++  int64_t f2g2    = f2   * (int64_t) g2;
++  int64_t f2g3    = f2   * (int64_t) g3;
++  int64_t f2g4    = f2   * (int64_t) g4;
++  int64_t f2g5    = f2   * (int64_t) g5;
++  int64_t f2g6    = f2   * (int64_t) g6;
++  int64_t f2g7    = f2   * (int64_t) g7;
++  int64_t f2g8_19 = f2   * (int64_t) g8_19;
++  int64_t f2g9_19 = f2   * (int64_t) g9_19;
++  int64_t f3g0    = f3   * (int64_t) g0;
++  int64_t f3g1_2  = f3_2 * (int64_t) g1;
++  int64_t f3g2    = f3   * (int64_t) g2;
++  int64_t f3g3_2  = f3_2 * (int64_t) g3;
++  int64_t f3g4    = f3   * (int64_t) g4;
++  int64_t f3g5_2  = f3_2 * (int64_t) g5;
++  int64_t f3g6    = f3   * (int64_t) g6;
++  int64_t f3g7_38 = f3_2 * (int64_t) g7_19;
++  int64_t f3g8_19 = f3   * (int64_t) g8_19;
++  int64_t f3g9_38 = f3_2 * (int64_t) g9_19;
++  int64_t f4g0    = f4   * (int64_t) g0;
++  int64_t f4g1    = f4   * (int64_t) g1;
++  int64_t f4g2    = f4   * (int64_t) g2;
++  int64_t f4g3    = f4   * (int64_t) g3;
++  int64_t f4g4    = f4   * (int64_t) g4;
++  int64_t f4g5    = f4   * (int64_t) g5;
++  int64_t f4g6_19 = f4   * (int64_t) g6_19;
++  int64_t f4g7_19 = f4   * (int64_t) g7_19;
++  int64_t f4g8_19 = f4   * (int64_t) g8_19;
++  int64_t f4g9_19 = f4   * (int64_t) g9_19;
++  int64_t f5g0    = f5   * (int64_t) g0;
++  int64_t f5g1_2  = f5_2 * (int64_t) g1;
++  int64_t f5g2    = f5   * (int64_t) g2;
++  int64_t f5g3_2  = f5_2 * (int64_t) g3;
++  int64_t f5g4    = f5   * (int64_t) g4;
++  int64_t f5g5_38 = f5_2 * (int64_t) g5_19;
++  int64_t f5g6_19 = f5   * (int64_t) g6_19;
++  int64_t f5g7_38 = f5_2 * (int64_t) g7_19;
++  int64_t f5g8_19 = f5   * (int64_t) g8_19;
++  int64_t f5g9_38 = f5_2 * (int64_t) g9_19;
++  int64_t f6g0    = f6   * (int64_t) g0;
++  int64_t f6g1    = f6   * (int64_t) g1;
++  int64_t f6g2    = f6   * (int64_t) g2;
++  int64_t f6g3    = f6   * (int64_t) g3;
++  int64_t f6g4_19 = f6   * (int64_t) g4_19;
++  int64_t f6g5_19 = f6   * (int64_t) g5_19;
++  int64_t f6g6_19 = f6   * (int64_t) g6_19;
++  int64_t f6g7_19 = f6   * (int64_t) g7_19;
++  int64_t f6g8_19 = f6   * (int64_t) g8_19;
++  int64_t f6g9_19 = f6   * (int64_t) g9_19;
++  int64_t f7g0    = f7   * (int64_t) g0;
++  int64_t f7g1_2  = f7_2 * (int64_t) g1;
++  int64_t f7g2    = f7   * (int64_t) g2;
++  int64_t f7g3_38 = f7_2 * (int64_t) g3_19;
++  int64_t f7g4_19 = f7   * (int64_t) g4_19;
++  int64_t f7g5_38 = f7_2 * (int64_t) g5_19;
++  int64_t f7g6_19 = f7   * (int64_t) g6_19;
++  int64_t f7g7_38 = f7_2 * (int64_t) g7_19;
++  int64_t f7g8_19 = f7   * (int64_t) g8_19;
++  int64_t f7g9_38 = f7_2 * (int64_t) g9_19;
++  int64_t f8g0    = f8   * (int64_t) g0;
++  int64_t f8g1    = f8   * (int64_t) g1;
++  int64_t f8g2_19 = f8   * (int64_t) g2_19;
++  int64_t f8g3_19 = f8   * (int64_t) g3_19;
++  int64_t f8g4_19 = f8   * (int64_t) g4_19;
++  int64_t f8g5_19 = f8   * (int64_t) g5_19;
++  int64_t f8g6_19 = f8   * (int64_t) g6_19;
++  int64_t f8g7_19 = f8   * (int64_t) g7_19;
++  int64_t f8g8_19 = f8   * (int64_t) g8_19;
++  int64_t f8g9_19 = f8   * (int64_t) g9_19;
++  int64_t f9g0    = f9   * (int64_t) g0;
++  int64_t f9g1_38 = f9_2 * (int64_t) g1_19;
++  int64_t f9g2_19 = f9   * (int64_t) g2_19;
++  int64_t f9g3_38 = f9_2 * (int64_t) g3_19;
++  int64_t f9g4_19 = f9   * (int64_t) g4_19;
++  int64_t f9g5_38 = f9_2 * (int64_t) g5_19;
++  int64_t f9g6_19 = f9   * (int64_t) g6_19;
++  int64_t f9g7_38 = f9_2 * (int64_t) g7_19;
++  int64_t f9g8_19 = f9   * (int64_t) g8_19;
++  int64_t f9g9_38 = f9_2 * (int64_t) g9_19;
++  int64_t h0 = f0g0+f1g9_38+f2g8_19+f3g7_38+f4g6_19+f5g5_38+f6g4_19+f7g3_38+f8g2_19+f9g1_38;
++  int64_t h1 = f0g1+f1g0   +f2g9_19+f3g8_19+f4g7_19+f5g6_19+f6g5_19+f7g4_19+f8g3_19+f9g2_19;
++  int64_t h2 = f0g2+f1g1_2 +f2g0   +f3g9_38+f4g8_19+f5g7_38+f6g6_19+f7g5_38+f8g4_19+f9g3_38;
++  int64_t h3 = f0g3+f1g2   +f2g1   +f3g0   +f4g9_19+f5g8_19+f6g7_19+f7g6_19+f8g5_19+f9g4_19;
++  int64_t h4 = f0g4+f1g3_2 +f2g2   +f3g1_2 +f4g0   +f5g9_38+f6g8_19+f7g7_38+f8g6_19+f9g5_38;
++  int64_t h5 = f0g5+f1g4   +f2g3   +f3g2   +f4g1   +f5g0   +f6g9_19+f7g8_19+f8g7_19+f9g6_19;
++  int64_t h6 = f0g6+f1g5_2 +f2g4   +f3g3_2 +f4g2   +f5g1_2 +f6g0   +f7g9_38+f8g8_19+f9g7_38;
++  int64_t h7 = f0g7+f1g6   +f2g5   +f3g4   +f4g3   +f5g2   +f6g1   +f7g0   +f8g9_19+f9g8_19;
++  int64_t h8 = f0g8+f1g7_2 +f2g6   +f3g5_2 +f4g4   +f5g3_2 +f6g2   +f7g1_2 +f8g0   +f9g9_38;
++  int64_t h9 = f0g9+f1g8   +f2g7   +f3g6   +f4g5   +f5g4   +f6g3   +f7g2   +f8g1   +f9g0   ;
++  int64_t carry0;
++  int64_t carry1;
++  int64_t carry2;
++  int64_t carry3;
++  int64_t carry4;
++  int64_t carry5;
++  int64_t carry6;
++  int64_t carry7;
++  int64_t carry8;
++  int64_t carry9;
++
++  /* |h0| <= (1.65*1.65*2^52*(1+19+19+19+19)+1.65*1.65*2^50*(38+38+38+38+38))
++   *   i.e. |h0| <= 1.4*2^60; narrower ranges for h2, h4, h6, h8
++   * |h1| <= (1.65*1.65*2^51*(1+1+19+19+19+19+19+19+19+19))
++   *   i.e. |h1| <= 1.7*2^59; narrower ranges for h3, h5, h7, h9 */
++
++  carry0 = h0 + (1 << 25); h1 += carry0 >> 26; h0 -= carry0 & kTop38Bits;
++  carry4 = h4 + (1 << 25); h5 += carry4 >> 26; h4 -= carry4 & kTop38Bits;
++  /* |h0| <= 2^25 */
++  /* |h4| <= 2^25 */
++  /* |h1| <= 1.71*2^59 */
++  /* |h5| <= 1.71*2^59 */
++
++  carry1 = h1 + (1 << 24); h2 += carry1 >> 25; h1 -= carry1 & kTop39Bits;
++  carry5 = h5 + (1 << 24); h6 += carry5 >> 25; h5 -= carry5 & kTop39Bits;
++  /* |h1| <= 2^24; from now on fits into int32 */
++  /* |h5| <= 2^24; from now on fits into int32 */
++  /* |h2| <= 1.41*2^60 */
++  /* |h6| <= 1.41*2^60 */
++
++  carry2 = h2 + (1 << 25); h3 += carry2 >> 26; h2 -= carry2 & kTop38Bits;
++  carry6 = h6 + (1 << 25); h7 += carry6 >> 26; h6 -= carry6 & kTop38Bits;
++  /* |h2| <= 2^25; from now on fits into int32 unchanged */
++  /* |h6| <= 2^25; from now on fits into int32 unchanged */
++  /* |h3| <= 1.71*2^59 */
++  /* |h7| <= 1.71*2^59 */
++
++  carry3 = h3 + (1 << 24); h4 += carry3 >> 25; h3 -= carry3 & kTop39Bits;
++  carry7 = h7 + (1 << 24); h8 += carry7 >> 25; h7 -= carry7 & kTop39Bits;
++  /* |h3| <= 2^24; from now on fits into int32 unchanged */
++  /* |h7| <= 2^24; from now on fits into int32 unchanged */
++  /* |h4| <= 1.72*2^34 */
++  /* |h8| <= 1.41*2^60 */
++
++  carry4 = h4 + (1 << 25); h5 += carry4 >> 26; h4 -= carry4 & kTop38Bits;
++  carry8 = h8 + (1 << 25); h9 += carry8 >> 26; h8 -= carry8 & kTop38Bits;
++  /* |h4| <= 2^25; from now on fits into int32 unchanged */
++  /* |h8| <= 2^25; from now on fits into int32 unchanged */
++  /* |h5| <= 1.01*2^24 */
++  /* |h9| <= 1.71*2^59 */
++
++  carry9 = h9 + (1 << 24); h0 += (carry9 >> 25) * 19; h9 -= carry9 & kTop39Bits;
++  /* |h9| <= 2^24; from now on fits into int32 unchanged */
++  /* |h0| <= 1.1*2^39 */
++
++  carry0 = h0 + (1 << 25); h1 += carry0 >> 26; h0 -= carry0 & kTop38Bits;
++  /* |h0| <= 2^25; from now on fits into int32 unchanged */
++  /* |h1| <= 1.01*2^24 */
++
++  h[0] = h0;
++  h[1] = h1;
++  h[2] = h2;
++  h[3] = h3;
++  h[4] = h4;
++  h[5] = h5;
++  h[6] = h6;
++  h[7] = h7;
++  h[8] = h8;
++  h[9] = h9;
++}
++
++/* h = f * f
++ * Can overlap h with f.
++ *
++ * Preconditions:
++ *    |f| bounded by 1.65*2^26,1.65*2^25,1.65*2^26,1.65*2^25,etc.
++ *
++ * Postconditions:
++ *    |h| bounded by 1.01*2^25,1.01*2^24,1.01*2^25,1.01*2^24,etc.
++ *
++ * See fe_mul.c for discussion of implementation strategy. */
++static void fe_sq(fe h, const fe f) {
++  int32_t f0 = f[0];
++  int32_t f1 = f[1];
++  int32_t f2 = f[2];
++  int32_t f3 = f[3];
++  int32_t f4 = f[4];
++  int32_t f5 = f[5];
++  int32_t f6 = f[6];
++  int32_t f7 = f[7];
++  int32_t f8 = f[8];
++  int32_t f9 = f[9];
++  int32_t f0_2 = 2 * f0;
++  int32_t f1_2 = 2 * f1;
++  int32_t f2_2 = 2 * f2;
++  int32_t f3_2 = 2 * f3;
++  int32_t f4_2 = 2 * f4;
++  int32_t f5_2 = 2 * f5;
++  int32_t f6_2 = 2 * f6;
++  int32_t f7_2 = 2 * f7;
++  int32_t f5_38 = 38 * f5; /* 1.959375*2^30 */
++  int32_t f6_19 = 19 * f6; /* 1.959375*2^30 */
++  int32_t f7_38 = 38 * f7; /* 1.959375*2^30 */
++  int32_t f8_19 = 19 * f8; /* 1.959375*2^30 */
++  int32_t f9_38 = 38 * f9; /* 1.959375*2^30 */
++  int64_t f0f0    = f0   * (int64_t) f0;
++  int64_t f0f1_2  = f0_2 * (int64_t) f1;
++  int64_t f0f2_2  = f0_2 * (int64_t) f2;
++  int64_t f0f3_2  = f0_2 * (int64_t) f3;
++  int64_t f0f4_2  = f0_2 * (int64_t) f4;
++  int64_t f0f5_2  = f0_2 * (int64_t) f5;
++  int64_t f0f6_2  = f0_2 * (int64_t) f6;
++  int64_t f0f7_2  = f0_2 * (int64_t) f7;
++  int64_t f0f8_2  = f0_2 * (int64_t) f8;
++  int64_t f0f9_2  = f0_2 * (int64_t) f9;
++  int64_t f1f1_2  = f1_2 * (int64_t) f1;
++  int64_t f1f2_2  = f1_2 * (int64_t) f2;
++  int64_t f1f3_4  = f1_2 * (int64_t) f3_2;
++  int64_t f1f4_2  = f1_2 * (int64_t) f4;
++  int64_t f1f5_4  = f1_2 * (int64_t) f5_2;
++  int64_t f1f6_2  = f1_2 * (int64_t) f6;
++  int64_t f1f7_4  = f1_2 * (int64_t) f7_2;
++  int64_t f1f8_2  = f1_2 * (int64_t) f8;
++  int64_t f1f9_76 = f1_2 * (int64_t) f9_38;
++  int64_t f2f2    = f2   * (int64_t) f2;
++  int64_t f2f3_2  = f2_2 * (int64_t) f3;
++  int64_t f2f4_2  = f2_2 * (int64_t) f4;
++  int64_t f2f5_2  = f2_2 * (int64_t) f5;
++  int64_t f2f6_2  = f2_2 * (int64_t) f6;
++  int64_t f2f7_2  = f2_2 * (int64_t) f7;
++  int64_t f2f8_38 = f2_2 * (int64_t) f8_19;
++  int64_t f2f9_38 = f2   * (int64_t) f9_38;
++  int64_t f3f3_2  = f3_2 * (int64_t) f3;
++  int64_t f3f4_2  = f3_2 * (int64_t) f4;
++  int64_t f3f5_4  = f3_2 * (int64_t) f5_2;
++  int64_t f3f6_2  = f3_2 * (int64_t) f6;
++  int64_t f3f7_76 = f3_2 * (int64_t) f7_38;
++  int64_t f3f8_38 = f3_2 * (int64_t) f8_19;
++  int64_t f3f9_76 = f3_2 * (int64_t) f9_38;
++  int64_t f4f4    = f4   * (int64_t) f4;
++  int64_t f4f5_2  = f4_2 * (int64_t) f5;
++  int64_t f4f6_38 = f4_2 * (int64_t) f6_19;
++  int64_t f4f7_38 = f4   * (int64_t) f7_38;
++  int64_t f4f8_38 = f4_2 * (int64_t) f8_19;
++  int64_t f4f9_38 = f4   * (int64_t) f9_38;
++  int64_t f5f5_38 = f5   * (int64_t) f5_38;
++  int64_t f5f6_38 = f5_2 * (int64_t) f6_19;
++  int64_t f5f7_76 = f5_2 * (int64_t) f7_38;
++  int64_t f5f8_38 = f5_2 * (int64_t) f8_19;
++  int64_t f5f9_76 = f5_2 * (int64_t) f9_38;
++  int64_t f6f6_19 = f6   * (int64_t) f6_19;
++  int64_t f6f7_38 = f6   * (int64_t) f7_38;
++  int64_t f6f8_38 = f6_2 * (int64_t) f8_19;
++  int64_t f6f9_38 = f6   * (int64_t) f9_38;
++  int64_t f7f7_38 = f7   * (int64_t) f7_38;
++  int64_t f7f8_38 = f7_2 * (int64_t) f8_19;
++  int64_t f7f9_76 = f7_2 * (int64_t) f9_38;
++  int64_t f8f8_19 = f8   * (int64_t) f8_19;
++  int64_t f8f9_38 = f8   * (int64_t) f9_38;
++  int64_t f9f9_38 = f9   * (int64_t) f9_38;
++  int64_t h0 = f0f0  +f1f9_76+f2f8_38+f3f7_76+f4f6_38+f5f5_38;
++  int64_t h1 = f0f1_2+f2f9_38+f3f8_38+f4f7_38+f5f6_38;
++  int64_t h2 = f0f2_2+f1f1_2 +f3f9_76+f4f8_38+f5f7_76+f6f6_19;
++  int64_t h3 = f0f3_2+f1f2_2 +f4f9_38+f5f8_38+f6f7_38;
++  int64_t h4 = f0f4_2+f1f3_4 +f2f2   +f5f9_76+f6f8_38+f7f7_38;
++  int64_t h5 = f0f5_2+f1f4_2 +f2f3_2 +f6f9_38+f7f8_38;
++  int64_t h6 = f0f6_2+f1f5_4 +f2f4_2 +f3f3_2 +f7f9_76+f8f8_19;
++  int64_t h7 = f0f7_2+f1f6_2 +f2f5_2 +f3f4_2 +f8f9_38;
++  int64_t h8 = f0f8_2+f1f7_4 +f2f6_2 +f3f5_4 +f4f4   +f9f9_38;
++  int64_t h9 = f0f9_2+f1f8_2 +f2f7_2 +f3f6_2 +f4f5_2;
++  int64_t carry0;
++  int64_t carry1;
++  int64_t carry2;
++  int64_t carry3;
++  int64_t carry4;
++  int64_t carry5;
++  int64_t carry6;
++  int64_t carry7;
++  int64_t carry8;
++  int64_t carry9;
++
++  carry0 = h0 + (1 << 25); h1 += carry0 >> 26; h0 -= carry0 & kTop38Bits;
++  carry4 = h4 + (1 << 25); h5 += carry4 >> 26; h4 -= carry4 & kTop38Bits;
++
++  carry1 = h1 + (1 << 24); h2 += carry1 >> 25; h1 -= carry1 & kTop39Bits;
++  carry5 = h5 + (1 << 24); h6 += carry5 >> 25; h5 -= carry5 & kTop39Bits;
++
++  carry2 = h2 + (1 << 25); h3 += carry2 >> 26; h2 -= carry2 & kTop38Bits;
++  carry6 = h6 + (1 << 25); h7 += carry6 >> 26; h6 -= carry6 & kTop38Bits;
++
++  carry3 = h3 + (1 << 24); h4 += carry3 >> 25; h3 -= carry3 & kTop39Bits;
++  carry7 = h7 + (1 << 24); h8 += carry7 >> 25; h7 -= carry7 & kTop39Bits;
++
++  carry4 = h4 + (1 << 25); h5 += carry4 >> 26; h4 -= carry4 & kTop38Bits;
++  carry8 = h8 + (1 << 25); h9 += carry8 >> 26; h8 -= carry8 & kTop38Bits;
++
++  carry9 = h9 + (1 << 24); h0 += (carry9 >> 25) * 19; h9 -= carry9 & kTop39Bits;
++
++  carry0 = h0 + (1 << 25); h1 += carry0 >> 26; h0 -= carry0 & kTop38Bits;
++
++  h[0] = h0;
++  h[1] = h1;
++  h[2] = h2;
++  h[3] = h3;
++  h[4] = h4;
++  h[5] = h5;
++  h[6] = h6;
++  h[7] = h7;
++  h[8] = h8;
++  h[9] = h9;
++}
++
++static void fe_invert(fe out, const fe z) {
++  fe t0;
++  fe t1;
++  fe t2;
++  fe t3;
++  int i;
++
++  /*
++   * Compute z ** -1 = z ** (2 ** 255 - 19 - 2) with the exponent as
++   * 2 ** 255 - 21 = (2 ** 5) * (2 ** 250 - 1) + 11.
++   */
++
++  /* t0 = z ** 2 */
++  fe_sq(t0, z);
++
++  /* t1 = t0 ** (2 ** 2) = z ** 8 */
++  fe_sq(t1, t0);
++  fe_sq(t1, t1);
++
++  /* t1 = z * t1 = z ** 9 */
++  fe_mul(t1, z, t1);
++  /* t0 = t0 * t1 = z ** 11 -- stash t0 away for the end. */
++  fe_mul(t0, t0, t1);
++
++  /* t2 = t0 ** 2 = z ** 22 */
++  fe_sq(t2, t0);
++
++  /* t1 = t1 * t2 = z ** (2 ** 5 - 1) */
++  fe_mul(t1, t1, t2);
++
++  /* t2 = t1 ** (2 ** 5) = z ** ((2 ** 5) * (2 ** 5 - 1)) */
++  fe_sq(t2, t1);
++  for (i = 1; i < 5; ++i) {
++    fe_sq(t2, t2);
++  }
++
++  /* t1 = t1 * t2 = z ** ((2 ** 5 + 1) * (2 ** 5 - 1)) = z ** (2 ** 10 - 1) */
++  fe_mul(t1, t2, t1);
++
++  /* Continuing similarly... */
++
++  /* t2 = z ** (2 ** 20 - 1) */
++  fe_sq(t2, t1);
++  for (i = 1; i < 10; ++i) {
++    fe_sq(t2, t2);
++  }
++  fe_mul(t2, t2, t1);
++
++  /* t2 = z ** (2 ** 40 - 1) */
++  fe_sq(t3, t2);
++  for (i = 1; i < 20; ++i) {
++    fe_sq(t3, t3);
++  }
++  fe_mul(t2, t3, t2);
++
++  /* t2 = z ** (2 ** 10) * (2 ** 40 - 1) */
++  for (i = 0; i < 10; ++i) {
++    fe_sq(t2, t2);
++  }
++  /* t1 = z ** (2 ** 50 - 1) */
++  fe_mul(t1, t2, t1);
++
++  /* t2 = z ** (2 ** 100 - 1) */
++  fe_sq(t2, t1);
++  for (i = 1; i < 50; ++i) {
++    fe_sq(t2, t2);
++  }
++  fe_mul(t2, t2, t1);
++
++  /* t2 = z ** (2 ** 200 - 1) */
++  fe_sq(t3, t2);
++  for (i = 1; i < 100; ++i) {
++    fe_sq(t3, t3);
++  }
++  fe_mul(t2, t3, t2);
++
++  /* t2 = z ** ((2 ** 50) * (2 ** 200 - 1) */
++  fe_sq(t2, t2);
++  for (i = 1; i < 50; ++i) {
++    fe_sq(t2, t2);
++  }
++
++  /* t1 = z ** (2 ** 250 - 1) */
++  fe_mul(t1, t2, t1);
++
++  /* t1 = z ** ((2 ** 5) * (2 ** 250 - 1)) */
++  fe_sq(t1, t1);
++  for (i = 1; i < 5; ++i) {
++    fe_sq(t1, t1);
++  }
++
++  /* Recall t0 = z ** 11; out = z ** (2 ** 255 - 21) */
++  fe_mul(out, t1, t0);
++}
++
++/* h = -f
++ *
++ * Preconditions:
++ *    |f| bounded by 1.1*2^25,1.1*2^24,1.1*2^25,1.1*2^24,etc.
++ *
++ * Postconditions:
++ *    |h| bounded by 1.1*2^25,1.1*2^24,1.1*2^25,1.1*2^24,etc. */
++static void fe_neg(fe h, const fe f) {
++  unsigned i;
++  for (i = 0; i < 10; i++) {
++    h[i] = -f[i];
++  }
++}
++
++/* Replace (f,g) with (g,g) if b == 1;
++ * replace (f,g) with (f,g) if b == 0.
++ *
++ * Preconditions: b in {0,1}. */
++static void fe_cmov(fe f, const fe g, unsigned b) {
++  size_t i;
++  b = 0-b;
++  for (i = 0; i < 10; i++) {
++    int32_t x = f[i] ^ g[i];
++    x &= b;
++    f[i] ^= x;
++  }
++}
++
++/* h = 2 * f * f
++ * Can overlap h with f.
++ *
++ * Preconditions:
++ *    |f| bounded by 1.65*2^26,1.65*2^25,1.65*2^26,1.65*2^25,etc.
++ *
++ * Postconditions:
++ *    |h| bounded by 1.01*2^25,1.01*2^24,1.01*2^25,1.01*2^24,etc.
++ *
++ * See fe_mul.c for discussion of implementation strategy. */
++static void fe_sq2(fe h, const fe f) {
++  int32_t f0 = f[0];
++  int32_t f1 = f[1];
++  int32_t f2 = f[2];
++  int32_t f3 = f[3];
++  int32_t f4 = f[4];
++  int32_t f5 = f[5];
++  int32_t f6 = f[6];
++  int32_t f7 = f[7];
++  int32_t f8 = f[8];
++  int32_t f9 = f[9];
++  int32_t f0_2 = 2 * f0;
++  int32_t f1_2 = 2 * f1;
++  int32_t f2_2 = 2 * f2;
++  int32_t f3_2 = 2 * f3;
++  int32_t f4_2 = 2 * f4;
++  int32_t f5_2 = 2 * f5;
++  int32_t f6_2 = 2 * f6;
++  int32_t f7_2 = 2 * f7;
++  int32_t f5_38 = 38 * f5; /* 1.959375*2^30 */
++  int32_t f6_19 = 19 * f6; /* 1.959375*2^30 */
++  int32_t f7_38 = 38 * f7; /* 1.959375*2^30 */
++  int32_t f8_19 = 19 * f8; /* 1.959375*2^30 */
++  int32_t f9_38 = 38 * f9; /* 1.959375*2^30 */
++  int64_t f0f0    = f0   * (int64_t) f0;
++  int64_t f0f1_2  = f0_2 * (int64_t) f1;
++  int64_t f0f2_2  = f0_2 * (int64_t) f2;
++  int64_t f0f3_2  = f0_2 * (int64_t) f3;
++  int64_t f0f4_2  = f0_2 * (int64_t) f4;
++  int64_t f0f5_2  = f0_2 * (int64_t) f5;
++  int64_t f0f6_2  = f0_2 * (int64_t) f6;
++  int64_t f0f7_2  = f0_2 * (int64_t) f7;
++  int64_t f0f8_2  = f0_2 * (int64_t) f8;
++  int64_t f0f9_2  = f0_2 * (int64_t) f9;
++  int64_t f1f1_2  = f1_2 * (int64_t) f1;
++  int64_t f1f2_2  = f1_2 * (int64_t) f2;
++  int64_t f1f3_4  = f1_2 * (int64_t) f3_2;
++  int64_t f1f4_2  = f1_2 * (int64_t) f4;
++  int64_t f1f5_4  = f1_2 * (int64_t) f5_2;
++  int64_t f1f6_2  = f1_2 * (int64_t) f6;
++  int64_t f1f7_4  = f1_2 * (int64_t) f7_2;
++  int64_t f1f8_2  = f1_2 * (int64_t) f8;
++  int64_t f1f9_76 = f1_2 * (int64_t) f9_38;
++  int64_t f2f2    = f2   * (int64_t) f2;
++  int64_t f2f3_2  = f2_2 * (int64_t) f3;
++  int64_t f2f4_2  = f2_2 * (int64_t) f4;
++  int64_t f2f5_2  = f2_2 * (int64_t) f5;
++  int64_t f2f6_2  = f2_2 * (int64_t) f6;
++  int64_t f2f7_2  = f2_2 * (int64_t) f7;
++  int64_t f2f8_38 = f2_2 * (int64_t) f8_19;
++  int64_t f2f9_38 = f2   * (int64_t) f9_38;
++  int64_t f3f3_2  = f3_2 * (int64_t) f3;
++  int64_t f3f4_2  = f3_2 * (int64_t) f4;
++  int64_t f3f5_4  = f3_2 * (int64_t) f5_2;
++  int64_t f3f6_2  = f3_2 * (int64_t) f6;
++  int64_t f3f7_76 = f3_2 * (int64_t) f7_38;
++  int64_t f3f8_38 = f3_2 * (int64_t) f8_19;
++  int64_t f3f9_76 = f3_2 * (int64_t) f9_38;
++  int64_t f4f4    = f4   * (int64_t) f4;
++  int64_t f4f5_2  = f4_2 * (int64_t) f5;
++  int64_t f4f6_38 = f4_2 * (int64_t) f6_19;
++  int64_t f4f7_38 = f4   * (int64_t) f7_38;
++  int64_t f4f8_38 = f4_2 * (int64_t) f8_19;
++  int64_t f4f9_38 = f4   * (int64_t) f9_38;
++  int64_t f5f5_38 = f5   * (int64_t) f5_38;
++  int64_t f5f6_38 = f5_2 * (int64_t) f6_19;
++  int64_t f5f7_76 = f5_2 * (int64_t) f7_38;
++  int64_t f5f8_38 = f5_2 * (int64_t) f8_19;
++  int64_t f5f9_76 = f5_2 * (int64_t) f9_38;
++  int64_t f6f6_19 = f6   * (int64_t) f6_19;
++  int64_t f6f7_38 = f6   * (int64_t) f7_38;
++  int64_t f6f8_38 = f6_2 * (int64_t) f8_19;
++  int64_t f6f9_38 = f6   * (int64_t) f9_38;
++  int64_t f7f7_38 = f7   * (int64_t) f7_38;
++  int64_t f7f8_38 = f7_2 * (int64_t) f8_19;
++  int64_t f7f9_76 = f7_2 * (int64_t) f9_38;
++  int64_t f8f8_19 = f8   * (int64_t) f8_19;
++  int64_t f8f9_38 = f8   * (int64_t) f9_38;
++  int64_t f9f9_38 = f9   * (int64_t) f9_38;
++  int64_t h0 = f0f0  +f1f9_76+f2f8_38+f3f7_76+f4f6_38+f5f5_38;
++  int64_t h1 = f0f1_2+f2f9_38+f3f8_38+f4f7_38+f5f6_38;
++  int64_t h2 = f0f2_2+f1f1_2 +f3f9_76+f4f8_38+f5f7_76+f6f6_19;
++  int64_t h3 = f0f3_2+f1f2_2 +f4f9_38+f5f8_38+f6f7_38;
++  int64_t h4 = f0f4_2+f1f3_4 +f2f2   +f5f9_76+f6f8_38+f7f7_38;
++  int64_t h5 = f0f5_2+f1f4_2 +f2f3_2 +f6f9_38+f7f8_38;
++  int64_t h6 = f0f6_2+f1f5_4 +f2f4_2 +f3f3_2 +f7f9_76+f8f8_19;
++  int64_t h7 = f0f7_2+f1f6_2 +f2f5_2 +f3f4_2 +f8f9_38;
++  int64_t h8 = f0f8_2+f1f7_4 +f2f6_2 +f3f5_4 +f4f4   +f9f9_38;
++  int64_t h9 = f0f9_2+f1f8_2 +f2f7_2 +f3f6_2 +f4f5_2;
++  int64_t carry0;
++  int64_t carry1;
++  int64_t carry2;
++  int64_t carry3;
++  int64_t carry4;
++  int64_t carry5;
++  int64_t carry6;
++  int64_t carry7;
++  int64_t carry8;
++  int64_t carry9;
++
++  h0 += h0;
++  h1 += h1;
++  h2 += h2;
++  h3 += h3;
++  h4 += h4;
++  h5 += h5;
++  h6 += h6;
++  h7 += h7;
++  h8 += h8;
++  h9 += h9;
++
++  carry0 = h0 + (1 << 25); h1 += carry0 >> 26; h0 -= carry0 & kTop38Bits;
++  carry4 = h4 + (1 << 25); h5 += carry4 >> 26; h4 -= carry4 & kTop38Bits;
++
++  carry1 = h1 + (1 << 24); h2 += carry1 >> 25; h1 -= carry1 & kTop39Bits;
++  carry5 = h5 + (1 << 24); h6 += carry5 >> 25; h5 -= carry5 & kTop39Bits;
++
++  carry2 = h2 + (1 << 25); h3 += carry2 >> 26; h2 -= carry2 & kTop38Bits;
++  carry6 = h6 + (1 << 25); h7 += carry6 >> 26; h6 -= carry6 & kTop38Bits;
++
++  carry3 = h3 + (1 << 24); h4 += carry3 >> 25; h3 -= carry3 & kTop39Bits;
++  carry7 = h7 + (1 << 24); h8 += carry7 >> 25; h7 -= carry7 & kTop39Bits;
++
++  carry4 = h4 + (1 << 25); h5 += carry4 >> 26; h4 -= carry4 & kTop38Bits;
++  carry8 = h8 + (1 << 25); h9 += carry8 >> 26; h8 -= carry8 & kTop38Bits;
++
++  carry9 = h9 + (1 << 24); h0 += (carry9 >> 25) * 19; h9 -= carry9 & kTop39Bits;
++
++  carry0 = h0 + (1 << 25); h1 += carry0 >> 26; h0 -= carry0 & kTop38Bits;
++
++  h[0] = h0;
++  h[1] = h1;
++  h[2] = h2;
++  h[3] = h3;
++  h[4] = h4;
++  h[5] = h5;
++  h[6] = h6;
++  h[7] = h7;
++  h[8] = h8;
++  h[9] = h9;
++}
++
++/* ge means group element.
++
++ * Here the group is the set of pairs (x,y) of field elements (see fe.h)
++ * satisfying -x^2 + y^2 = 1 + d x^2y^2
++ * where d = -121665/121666.
++ *
++ * Representations:
++ *   ge_p2 (projective): (X:Y:Z) satisfying x=X/Z, y=Y/Z
++ *   ge_p3 (extended): (X:Y:Z:T) satisfying x=X/Z, y=Y/Z, XY=ZT
++ *   ge_p1p1 (completed): ((X:Z),(Y:T)) satisfying x=X/Z, y=Y/T
++ *   ge_precomp (Duif): (y+x,y-x,2dxy) */
++
++typedef struct {
++  fe X;
++  fe Y;
++  fe Z;
++} ge_p2;
++
++typedef struct {
++  fe X;
++  fe Y;
++  fe Z;
++  fe T;
++} ge_p3;
++
++typedef struct {
++  fe X;
++  fe Y;
++  fe Z;
++  fe T;
++} ge_p1p1;
++
++typedef struct {
++  fe yplusx;
++  fe yminusx;
++  fe xy2d;
++} ge_precomp;
++
++typedef struct {
++  fe YplusX;
++  fe YminusX;
++  fe Z;
++  fe T2d;
++} ge_cached;
++
++static void ge_p3_0(ge_p3 *h) {
++  fe_0(h->X);
++  fe_1(h->Y);
++  fe_1(h->Z);
++  fe_0(h->T);
++}
++
++static void ge_precomp_0(ge_precomp *h) {
++  fe_1(h->yplusx);
++  fe_1(h->yminusx);
++  fe_0(h->xy2d);
++}
++
++/* r = p */
++static void ge_p3_to_p2(ge_p2 *r, const ge_p3 *p) {
++  fe_copy(r->X, p->X);
++  fe_copy(r->Y, p->Y);
++  fe_copy(r->Z, p->Z);
++}
++
++/* r = p */
++static void ge_p1p1_to_p2(ge_p2 *r, const ge_p1p1 *p) {
++  fe_mul(r->X, p->X, p->T);
++  fe_mul(r->Y, p->Y, p->Z);
++  fe_mul(r->Z, p->Z, p->T);
++}
++
++/* r = p */
++static void ge_p1p1_to_p3(ge_p3 *r, const ge_p1p1 *p) {
++  fe_mul(r->X, p->X, p->T);
++  fe_mul(r->Y, p->Y, p->Z);
++  fe_mul(r->Z, p->Z, p->T);
++  fe_mul(r->T, p->X, p->Y);
++}
++
++/* r = 2 * p */
++static void ge_p2_dbl(ge_p1p1 *r, const ge_p2 *p) {
++  fe t0;
++
++  fe_sq(r->X, p->X);
++  fe_sq(r->Z, p->Y);
++  fe_sq2(r->T, p->Z);
++  fe_add(r->Y, p->X, p->Y);
++  fe_sq(t0, r->Y);
++  fe_add(r->Y, r->Z, r->X);
++  fe_sub(r->Z, r->Z, r->X);
++  fe_sub(r->X, t0, r->Y);
++  fe_sub(r->T, r->T, r->Z);
++}
++
++/* r = 2 * p */
++static void ge_p3_dbl(ge_p1p1 *r, const ge_p3 *p) {
++  ge_p2 q;
++  ge_p3_to_p2(&q, p);
++  ge_p2_dbl(r, &q);
++}
++
++/* r = p + q */
++static void ge_madd(ge_p1p1 *r, const ge_p3 *p, const ge_precomp *q) {
++  fe t0;
++
++  fe_add(r->X, p->Y, p->X);
++  fe_sub(r->Y, p->Y, p->X);
++  fe_mul(r->Z, r->X, q->yplusx);
++  fe_mul(r->Y, r->Y, q->yminusx);
++  fe_mul(r->T, q->xy2d, p->T);
++  fe_add(t0, p->Z, p->Z);
++  fe_sub(r->X, r->Z, r->Y);
++  fe_add(r->Y, r->Z, r->Y);
++  fe_add(r->Z, t0, r->T);
++  fe_sub(r->T, t0, r->T);
++}
++
++static uint8_t equal(signed char b, signed char c) {
++  uint8_t ub = b;
++  uint8_t uc = c;
++  uint8_t x = ub ^ uc; /* 0: yes; 1..255: no */
++  uint32_t y = x;      /* 0: yes; 1..255: no */
++  y -= 1;              /* 4294967295: yes; 0..254: no */
++  y >>= 31;            /* 1: yes; 0: no */
++  return y;
++}
++
++static void cmov(ge_precomp *t, const ge_precomp *u, uint8_t b) {
++  fe_cmov(t->yplusx, u->yplusx, b);
++  fe_cmov(t->yminusx, u->yminusx, b);
++  fe_cmov(t->xy2d, u->xy2d, b);
++}
++
++/* k25519Precomp[i][j] = (j+1)*256^i*B */
++static const ge_precomp k25519Precomp[32][8] = {
++    {
++        {
++            {25967493, -14356035, 29566456, 3660896, -12694345, 4014787,
++             27544626, -11754271, -6079156, 2047605},
++            {-12545711, 934262, -2722910, 3049990, -727428, 9406986, 12720692,
++             5043384, 19500929, -15469378},
++            {-8738181, 4489570, 9688441, -14785194, 10184609, -12363380,
++             29287919, 11864899, -24514362, -4438546},
++        },
++        {
++            {-12815894, -12976347, -21581243, 11784320, -25355658, -2750717,
++             -11717903, -3814571, -358445, -10211303},
++            {-21703237, 6903825, 27185491, 6451973, -29577724, -9554005,
++             -15616551, 11189268, -26829678, -5319081},
++            {26966642, 11152617, 32442495, 15396054, 14353839, -12752335,
++             -3128826, -9541118, -15472047, -4166697},
++        },
++        {
++            {15636291, -9688557, 24204773, -7912398, 616977, -16685262,
++             27787600, -14772189, 28944400, -1550024},
++            {16568933, 4717097, -11556148, -1102322, 15682896, -11807043,
++             16354577, -11775962, 7689662, 11199574},
++            {30464156, -5976125, -11779434, -15670865, 23220365, 15915852,
++             7512774, 10017326, -17749093, -9920357},
++        },
++        {
++            {-17036878, 13921892, 10945806, -6033431, 27105052, -16084379,
++             -28926210, 15006023, 3284568, -6276540},
++            {23599295, -8306047, -11193664, -7687416, 13236774, 10506355,
++             7464579, 9656445, 13059162, 10374397},
++            {7798556, 16710257, 3033922, 2874086, 28997861, 2835604, 32406664,
++             -3839045, -641708, -101325},
++        },
++        {
++            {10861363, 11473154, 27284546, 1981175, -30064349, 12577861,
++             32867885, 14515107, -15438304, 10819380},
++            {4708026, 6336745, 20377586, 9066809, -11272109, 6594696, -25653668,
++             12483688, -12668491, 5581306},
++            {19563160, 16186464, -29386857, 4097519, 10237984, -4348115,
++             28542350, 13850243, -23678021, -15815942},
++        },
++        {
++            {-15371964, -12862754, 32573250, 4720197, -26436522, 5875511,
++             -19188627, -15224819, -9818940, -12085777},
++            {-8549212, 109983, 15149363, 2178705, 22900618, 4543417, 3044240,
++             -15689887, 1762328, 14866737},
++            {-18199695, -15951423, -10473290, 1707278, -17185920, 3916101,
++             -28236412, 3959421, 27914454, 4383652},
++        },
++        {
++            {5153746, 9909285, 1723747, -2777874, 30523605, 5516873, 19480852,
++             5230134, -23952439, -15175766},
++            {-30269007, -3463509, 7665486, 10083793, 28475525, 1649722,
++             20654025, 16520125, 30598449, 7715701},
++            {28881845, 14381568, 9657904, 3680757, -20181635, 7843316,
++             -31400660, 1370708, 29794553, -1409300},
++        },
++        {
++            {14499471, -2729599, -33191113, -4254652, 28494862, 14271267,
++             30290735, 10876454, -33154098, 2381726},
++            {-7195431, -2655363, -14730155, 462251, -27724326, 3941372,
++             -6236617, 3696005, -32300832, 15351955},
++            {27431194, 8222322, 16448760, -3907995, -18707002, 11938355,
++             -32961401, -2970515, 29551813, 10109425},
++        },
++    },
++    {
++        {
++            {-13657040, -13155431, -31283750, 11777098, 21447386, 6519384,
++             -2378284, -1627556, 10092783, -4764171},
++            {27939166, 14210322, 4677035, 16277044, -22964462, -12398139,
++             -32508754, 12005538, -17810127, 12803510},
++            {17228999, -15661624, -1233527, 300140, -1224870, -11714777,
++             30364213, -9038194, 18016357, 4397660},
++        },
++        {
++            {-10958843, -7690207, 4776341, -14954238, 27850028, -15602212,
++             -26619106, 14544525, -17477504, 982639},
++            {29253598, 15796703, -2863982, -9908884, 10057023, 3163536, 7332899,
++             -4120128, -21047696, 9934963},
++            {5793303, 16271923, -24131614, -10116404, 29188560, 1206517,
++             -14747930, 4559895, -30123922, -10897950},
++        },
++        {
++            {-27643952, -11493006, 16282657, -11036493, 28414021, -15012264,
++             24191034, 4541697, -13338309, 5500568},
++            {12650548, -1497113, 9052871, 11355358, -17680037, -8400164,
++             -17430592, 12264343, 10874051, 13524335},
++            {25556948, -3045990, 714651, 2510400, 23394682, -10415330, 33119038,
++             5080568, -22528059, 5376628},
++        },
++        {
++            {-26088264, -4011052, -17013699, -3537628, -6726793, 1920897,
++             -22321305, -9447443, 4535768, 1569007},
++            {-2255422, 14606630, -21692440, -8039818, 28430649, 8775819,
++             -30494562, 3044290, 31848280, 12543772},
++            {-22028579, 2943893, -31857513, 6777306, 13784462, -4292203,
++             -27377195, -2062731, 7718482, 14474653},
++        },
++        {
++            {2385315, 2454213, -22631320, 46603, -4437935, -15680415, 656965,
++             -7236665, 24316168, -5253567},
++            {13741529, 10911568, -33233417, -8603737, -20177830, -1033297,
++             33040651, -13424532, -20729456, 8321686},
++            {21060490, -2212744, 15712757, -4336099, 1639040, 10656336,
++             23845965, -11874838, -9984458, 608372},
++        },
++        {
++            {-13672732, -15087586, -10889693, -7557059, -6036909, 11305547,
++             1123968, -6780577, 27229399, 23887},
++            {-23244140, -294205, -11744728, 14712571, -29465699, -2029617,
++             12797024, -6440308, -1633405, 16678954},
++            {-29500620, 4770662, -16054387, 14001338, 7830047, 9564805,
++             -1508144, -4795045, -17169265, 4904953},
++        },
++        {
++            {24059557, 14617003, 19037157, -15039908, 19766093, -14906429,
++             5169211, 16191880, 2128236, -4326833},
++            {-16981152, 4124966, -8540610, -10653797, 30336522, -14105247,
++             -29806336, 916033, -6882542, -2986532},
++            {-22630907, 12419372, -7134229, -7473371, -16478904, 16739175,
++             285431, 2763829, 15736322, 4143876},
++        },
++        {
++            {2379352, 11839345, -4110402, -5988665, 11274298, 794957, 212801,
++             -14594663, 23527084, -16458268},
++            {33431127, -11130478, -17838966, -15626900, 8909499, 8376530,
++             -32625340, 4087881, -15188911, -14416214},
++            {1767683, 7197987, -13205226, -2022635, -13091350, 448826, 5799055,
++             4357868, -4774191, -16323038},
++        },
++    },
++    {
++        {
++            {6721966, 13833823, -23523388, -1551314, 26354293, -11863321,
++             23365147, -3949732, 7390890, 2759800},
++            {4409041, 2052381, 23373853, 10530217, 7676779, -12885954, 21302353,
++             -4264057, 1244380, -12919645},
++            {-4421239, 7169619, 4982368, -2957590, 30256825, -2777540, 14086413,
++             9208236, 15886429, 16489664},
++        },
++        {
++            {1996075, 10375649, 14346367, 13311202, -6874135, -16438411,
++             -13693198, 398369, -30606455, -712933},
++            {-25307465, 9795880, -2777414, 14878809, -33531835, 14780363,
++             13348553, 12076947, -30836462, 5113182},
++            {-17770784, 11797796, 31950843, 13929123, -25888302, 12288344,
++             -30341101, -7336386, 13847711, 5387222},
++        },
++        {
++            {-18582163, -3416217, 17824843, -2340966, 22744343, -10442611,
++             8763061, 3617786, -19600662, 10370991},
++            {20246567, -14369378, 22358229, -543712, 18507283, -10413996,
++             14554437, -8746092, 32232924, 16763880},
++            {9648505, 10094563, 26416693, 14745928, -30374318, -6472621,
++             11094161, 15689506, 3140038, -16510092},
++        },
++        {
++            {-16160072, 5472695, 31895588, 4744994, 8823515, 10365685,
++             -27224800, 9448613, -28774454, 366295},
++            {19153450, 11523972, -11096490, -6503142, -24647631, 5420647,
++             28344573, 8041113, 719605, 11671788},
++            {8678025, 2694440, -6808014, 2517372, 4964326, 11152271, -15432916,
++             -15266516, 27000813, -10195553},
++        },
++        {
++            {-15157904, 7134312, 8639287, -2814877, -7235688, 10421742, 564065,
++             5336097, 6750977, -14521026},
++            {11836410, -3979488, 26297894, 16080799, 23455045, 15735944,
++             1695823, -8819122, 8169720, 16220347},
++            {-18115838, 8653647, 17578566, -6092619, -8025777, -16012763,
++             -11144307, -2627664, -5990708, -14166033},
++        },
++        {
++            {-23308498, -10968312, 15213228, -10081214, -30853605, -11050004,
++             27884329, 2847284, 2655861, 1738395},
++            {-27537433, -14253021, -25336301, -8002780, -9370762, 8129821,
++             21651608, -3239336, -19087449, -11005278},
++            {1533110, 3437855, 23735889, 459276, 29970501, 11335377, 26030092,
++             5821408, 10478196, 8544890},
++        },
++        {
++            {32173121, -16129311, 24896207, 3921497, 22579056, -3410854,
++             19270449, 12217473, 17789017, -3395995},
++            {-30552961, -2228401, -15578829, -10147201, 13243889, 517024,
++             15479401, -3853233, 30460520, 1052596},
++            {-11614875, 13323618, 32618793, 8175907, -15230173, 12596687,
++             27491595, -4612359, 3179268, -9478891},
++        },
++        {
++            {31947069, -14366651, -4640583, -15339921, -15125977, -6039709,
++             -14756777, -16411740, 19072640, -9511060},
++            {11685058, 11822410, 3158003, -13952594, 33402194, -4165066,
++             5977896, -5215017, 473099, 5040608},
++            {-20290863, 8198642, -27410132, 11602123, 1290375, -2799760,
++             28326862, 1721092, -19558642, -3131606},
++        },
++    },
++    {
++        {
++            {7881532, 10687937, 7578723, 7738378, -18951012, -2553952, 21820786,
++             8076149, -27868496, 11538389},
++            {-19935666, 3899861, 18283497, -6801568, -15728660, -11249211,
++             8754525, 7446702, -5676054, 5797016},
++            {-11295600, -3793569, -15782110, -7964573, 12708869, -8456199,
++             2014099, -9050574, -2369172, -5877341},
++        },
++        {
++            {-22472376, -11568741, -27682020, 1146375, 18956691, 16640559,
++             1192730, -3714199, 15123619, 10811505},
++            {14352098, -3419715, -18942044, 10822655, 32750596, 4699007, -70363,
++             15776356, -28886779, -11974553},
++            {-28241164, -8072475, -4978962, -5315317, 29416931, 1847569,
++             -20654173, -16484855, 4714547, -9600655},
++        },
++        {
++            {15200332, 8368572, 19679101, 15970074, -31872674, 1959451,
++             24611599, -4543832, -11745876, 12340220},
++            {12876937, -10480056, 33134381, 6590940, -6307776, 14872440,
++             9613953, 8241152, 15370987, 9608631},
++            {-4143277, -12014408, 8446281, -391603, 4407738, 13629032, -7724868,
++             15866074, -28210621, -8814099},
++        },
++        {
++            {26660628, -15677655, 8393734, 358047, -7401291, 992988, -23904233,
++             858697, 20571223, 8420556},
++            {14620715, 13067227, -15447274, 8264467, 14106269, 15080814,
++             33531827, 12516406, -21574435, -12476749},
++            {236881, 10476226, 57258, -14677024, 6472998, 2466984, 17258519,
++             7256740, 8791136, 15069930},
++        },
++        {
++            {1276410, -9371918, 22949635, -16322807, -23493039, -5702186,
++             14711875, 4874229, -30663140, -2331391},
++            {5855666, 4990204, -13711848, 7294284, -7804282, 1924647, -1423175,
++             -7912378, -33069337, 9234253},
++            {20590503, -9018988, 31529744, -7352666, -2706834, 10650548,
++             31559055, -11609587, 18979186, 13396066},
++        },
++        {
++            {24474287, 4968103, 22267082, 4407354, 24063882, -8325180,
++             -18816887, 13594782, 33514650, 7021958},
++            {-11566906, -6565505, -21365085, 15928892, -26158305, 4315421,
++             -25948728, -3916677, -21480480, 12868082},
++            {-28635013, 13504661, 19988037, -2132761, 21078225, 6443208,
++             -21446107, 2244500, -12455797, -8089383},
++        },
++        {
++            {-30595528, 13793479, -5852820, 319136, -25723172, -6263899,
++             33086546, 8957937, -15233648, 5540521},
++            {-11630176, -11503902, -8119500, -7643073, 2620056, 1022908,
++             -23710744, -1568984, -16128528, -14962807},
++            {23152971, 775386, 27395463, 14006635, -9701118, 4649512, 1689819,
++             892185, -11513277, -15205948},
++        },
++        {
++            {9770129, 9586738, 26496094, 4324120, 1556511, -3550024, 27453819,
++             4763127, -19179614, 5867134},
++            {-32765025, 1927590, 31726409, -4753295, 23962434, -16019500,
++             27846559, 5931263, -29749703, -16108455},
++            {27461885, -2977536, 22380810, 1815854, -23033753, -3031938,
++             7283490, -15148073, -19526700, 7734629},
++        },
++    },
++    {
++        {
++            {-8010264, -9590817, -11120403, 6196038, 29344158, -13430885,
++             7585295, -3176626, 18549497, 15302069},
++            {-32658337, -6171222, -7672793, -11051681, 6258878, 13504381,
++             10458790, -6418461, -8872242, 8424746},
++            {24687205, 8613276, -30667046, -3233545, 1863892, -1830544,
++             19206234, 7134917, -11284482, -828919},
++        },
++        {
++            {11334899, -9218022, 8025293, 12707519, 17523892, -10476071,
++             10243738, -14685461, -5066034, 16498837},
++            {8911542, 6887158, -9584260, -6958590, 11145641, -9543680, 17303925,
++             -14124238, 6536641, 10543906},
++            {-28946384, 15479763, -17466835, 568876, -1497683, 11223454,
++             -2669190, -16625574, -27235709, 8876771},
++        },
++        {
++            {-25742899, -12566864, -15649966, -846607, -33026686, -796288,
++             -33481822, 15824474, -604426, -9039817},
++            {10330056, 70051, 7957388, -9002667, 9764902, 15609756, 27698697,
++             -4890037, 1657394, 3084098},
++            {10477963, -7470260, 12119566, -13250805, 29016247, -5365589,
++             31280319, 14396151, -30233575, 15272409},
++        },
++        {
++            {-12288309, 3169463, 28813183, 16658753, 25116432, -5630466,
++             -25173957, -12636138, -25014757, 1950504},
++            {-26180358, 9489187, 11053416, -14746161, -31053720, 5825630,
++             -8384306, -8767532, 15341279, 8373727},
++            {28685821, 7759505, -14378516, -12002860, -31971820, 4079242,
++             298136, -10232602, -2878207, 15190420},
++        },
++        {
++            {-32932876, 13806336, -14337485, -15794431, -24004620, 10940928,
++             8669718, 2742393, -26033313, -6875003},
++            {-1580388, -11729417, -25979658, -11445023, -17411874, -10912854,
++             9291594, -16247779, -12154742, 6048605},
++            {-30305315, 14843444, 1539301, 11864366, 20201677, 1900163,
++             13934231, 5128323, 11213262, 9168384},
++        },
++        {
++            {-26280513, 11007847, 19408960, -940758, -18592965, -4328580,
++             -5088060, -11105150, 20470157, -16398701},
++            {-23136053, 9282192, 14855179, -15390078, -7362815, -14408560,
++             -22783952, 14461608, 14042978, 5230683},
++            {29969567, -2741594, -16711867, -8552442, 9175486, -2468974,
++             21556951, 3506042, -5933891, -12449708},
++        },
++        {
++            {-3144746, 8744661, 19704003, 4581278, -20430686, 6830683,
++             -21284170, 8971513, -28539189, 15326563},
++            {-19464629, 10110288, -17262528, -3503892, -23500387, 1355669,
++             -15523050, 15300988, -20514118, 9168260},
++            {-5353335, 4488613, -23803248, 16314347, 7780487, -15638939,
++             -28948358, 9601605, 33087103, -9011387},
++        },
++        {
++            {-19443170, -15512900, -20797467, -12445323, -29824447, 10229461,
++             -27444329, -15000531, -5996870, 15664672},
++            {23294591, -16632613, -22650781, -8470978, 27844204, 11461195,
++             13099750, -2460356, 18151676, 13417686},
++            {-24722913, -4176517, -31150679, 5988919, -26858785, 6685065,
++             1661597, -12551441, 15271676, -15452665},
++        },
++    },
++    {
++        {
++            {11433042, -13228665, 8239631, -5279517, -1985436, -725718,
++             -18698764, 2167544, -6921301, -13440182},
++            {-31436171, 15575146, 30436815, 12192228, -22463353, 9395379,
++             -9917708, -8638997, 12215110, 12028277},
++            {14098400, 6555944, 23007258, 5757252, -15427832, -12950502,
++             30123440, 4617780, -16900089, -655628},
++        },
++        {
++            {-4026201, -15240835, 11893168, 13718664, -14809462, 1847385,
++             -15819999, 10154009, 23973261, -12684474},
++            {-26531820, -3695990, -1908898, 2534301, -31870557, -16550355,
++             18341390, -11419951, 32013174, -10103539},
++            {-25479301, 10876443, -11771086, -14625140, -12369567, 1838104,
++             21911214, 6354752, 4425632, -837822},
++        },
++        {
++            {-10433389, -14612966, 22229858, -3091047, -13191166, 776729,
++             -17415375, -12020462, 4725005, 14044970},
++            {19268650, -7304421, 1555349, 8692754, -21474059, -9910664, 6347390,
++             -1411784, -19522291, -16109756},
++            {-24864089, 12986008, -10898878, -5558584, -11312371, -148526,
++             19541418, 8180106, 9282262, 10282508},
++        },
++        {
++            {-26205082, 4428547, -8661196, -13194263, 4098402, -14165257,
++             15522535, 8372215, 5542595, -10702683},
++            {-10562541, 14895633, 26814552, -16673850, -17480754, -2489360,
++             -2781891, 6993761, -18093885, 10114655},
++            {-20107055, -929418, 31422704, 10427861, -7110749, 6150669,
++             -29091755, -11529146, 25953725, -106158},
++        },
++        {
++            {-4234397, -8039292, -9119125, 3046000, 2101609, -12607294,
++             19390020, 6094296, -3315279, 12831125},
++            {-15998678, 7578152, 5310217, 14408357, -33548620, -224739,
++             31575954, 6326196, 7381791, -2421839},
++            {-20902779, 3296811, 24736065, -16328389, 18374254, 7318640,
++             6295303, 8082724, -15362489, 12339664},
++        },
++        {
++            {27724736, 2291157, 6088201, -14184798, 1792727, 5857634, 13848414,
++             15768922, 25091167, 14856294},
++            {-18866652, 8331043, 24373479, 8541013, -701998, -9269457, 12927300,
++             -12695493, -22182473, -9012899},
++            {-11423429, -5421590, 11632845, 3405020, 30536730, -11674039,
++             -27260765, 13866390, 30146206, 9142070},
++        },
++        {
++            {3924129, -15307516, -13817122, -10054960, 12291820, -668366,
++             -27702774, 9326384, -8237858, 4171294},
++            {-15921940, 16037937, 6713787, 16606682, -21612135, 2790944,
++             26396185, 3731949, 345228, -5462949},
++            {-21327538, 13448259, 25284571, 1143661, 20614966, -8849387,
++             2031539, -12391231, -16253183, -13582083},
++        },
++        {
++            {31016211, -16722429, 26371392, -14451233, -5027349, 14854137,
++             17477601, 3842657, 28012650, -16405420},
++            {-5075835, 9368966, -8562079, -4600902, -15249953, 6970560,
++             -9189873, 16292057, -8867157, 3507940},
++            {29439664, 3537914, 23333589, 6997794, -17555561, -11018068,
++             -15209202, -15051267, -9164929, 6580396},
++        },
++    },
++    {
++        {
++            {-12185861, -7679788, 16438269, 10826160, -8696817, -6235611,
++             17860444, -9273846, -2095802, 9304567},
++            {20714564, -4336911, 29088195, 7406487, 11426967, -5095705,
++             14792667, -14608617, 5289421, -477127},
++            {-16665533, -10650790, -6160345, -13305760, 9192020, -1802462,
++             17271490, 12349094, 26939669, -3752294},
++        },
++        {
++            {-12889898, 9373458, 31595848, 16374215, 21471720, 13221525,
++             -27283495, -12348559, -3698806, 117887},
++            {22263325, -6560050, 3984570, -11174646, -15114008, -566785,
++             28311253, 5358056, -23319780, 541964},
++            {16259219, 3261970, 2309254, -15534474, -16885711, -4581916,
++             24134070, -16705829, -13337066, -13552195},
++        },
++        {
++            {9378160, -13140186, -22845982, -12745264, 28198281, -7244098,
++             -2399684, -717351, 690426, 14876244},
++            {24977353, -314384, -8223969, -13465086, 28432343, -1176353,
++             -13068804, -12297348, -22380984, 6618999},
++            {-1538174, 11685646, 12944378, 13682314, -24389511, -14413193,
++             8044829, -13817328, 32239829, -5652762},
++        },
++        {
++            {-18603066, 4762990, -926250, 8885304, -28412480, -3187315, 9781647,
++             -10350059, 32779359, 5095274},
++            {-33008130, -5214506, -32264887, -3685216, 9460461, -9327423,
++             -24601656, 14506724, 21639561, -2630236},
++            {-16400943, -13112215, 25239338, 15531969, 3987758, -4499318,
++             -1289502, -6863535, 17874574, 558605},
++        },
++        {
++            {-13600129, 10240081, 9171883, 16131053, -20869254, 9599700,
++             33499487, 5080151, 2085892, 5119761},
++            {-22205145, -2519528, -16381601, 414691, -25019550, 2170430,
++             30634760, -8363614, -31999993, -5759884},
++            {-6845704, 15791202, 8550074, -1312654, 29928809, -12092256,
++             27534430, -7192145, -22351378, 12961482},
++        },
++        {
++            {-24492060, -9570771, 10368194, 11582341, -23397293, -2245287,
++             16533930, 8206996, -30194652, -5159638},
++            {-11121496, -3382234, 2307366, 6362031, -135455, 8868177, -16835630,
++             7031275, 7589640, 8945490},
++            {-32152748, 8917967, 6661220, -11677616, -1192060, -15793393,
++             7251489, -11182180, 24099109, -14456170},
++        },
++        {
++            {5019558, -7907470, 4244127, -14714356, -26933272, 6453165,
++             -19118182, -13289025, -6231896, -10280736},
++            {10853594, 10721687, 26480089, 5861829, -22995819, 1972175,
++             -1866647, -10557898, -3363451, -6441124},
++            {-17002408, 5906790, 221599, -6563147, 7828208, -13248918, 24362661,
++             -2008168, -13866408, 7421392},
++        },
++        {
++            {8139927, -6546497, 32257646, -5890546, 30375719, 1886181,
++             -21175108, 15441252, 28826358, -4123029},
++            {6267086, 9695052, 7709135, -16603597, -32869068, -1886135,
++             14795160, -7840124, 13746021, -1742048},
++            {28584902, 7787108, -6732942, -15050729, 22846041, -7571236,
++             -3181936, -363524, 4771362, -8419958},
++        },
++    },
++    {
++        {
++            {24949256, 6376279, -27466481, -8174608, -18646154, -9930606,
++             33543569, -12141695, 3569627, 11342593},
++            {26514989, 4740088, 27912651, 3697550, 19331575, -11472339, 6809886,
++             4608608, 7325975, -14801071},
++            {-11618399, -14554430, -24321212, 7655128, -1369274, 5214312,
++             -27400540, 10258390, -17646694, -8186692},
++        },
++        {
++            {11431204, 15823007, 26570245, 14329124, 18029990, 4796082,
++             -31446179, 15580664, 9280358, -3973687},
++            {-160783, -10326257, -22855316, -4304997, -20861367, -13621002,
++             -32810901, -11181622, -15545091, 4387441},
++            {-20799378, 12194512, 3937617, -5805892, -27154820, 9340370,
++             -24513992, 8548137, 20617071, -7482001},
++        },
++        {
++            {-938825, -3930586, -8714311, 16124718, 24603125, -6225393,
++             -13775352, -11875822, 24345683, 10325460},
++            {-19855277, -1568885, -22202708, 8714034, 14007766, 6928528,
++             16318175, -1010689, 4766743, 3552007},
++            {-21751364, -16730916, 1351763, -803421, -4009670, 3950935, 3217514,
++             14481909, 10988822, -3994762},
++        },
++        {
++            {15564307, -14311570, 3101243, 5684148, 30446780, -8051356,
++             12677127, -6505343, -8295852, 13296005},
++            {-9442290, 6624296, -30298964, -11913677, -4670981, -2057379,
++             31521204, 9614054, -30000824, 12074674},
++            {4771191, -135239, 14290749, -13089852, 27992298, 14998318,
++             -1413936, -1556716, 29832613, -16391035},
++        },
++        {
++            {7064884, -7541174, -19161962, -5067537, -18891269, -2912736,
++             25825242, 5293297, -27122660, 13101590},
++            {-2298563, 2439670, -7466610, 1719965, -27267541, -16328445,
++             32512469, -5317593, -30356070, -4190957},
++            {-30006540, 10162316, -33180176, 3981723, -16482138, -13070044,
++             14413974, 9515896, 19568978, 9628812},
++        },
++        {
++            {33053803, 199357, 15894591, 1583059, 27380243, -4580435, -17838894,
++             -6106839, -6291786, 3437740},
++            {-18978877, 3884493, 19469877, 12726490, 15913552, 13614290,
++             -22961733, 70104, 7463304, 4176122},
++            {-27124001, 10659917, 11482427, -16070381, 12771467, -6635117,
++             -32719404, -5322751, 24216882, 5944158},
++        },
++        {
++            {8894125, 7450974, -2664149, -9765752, -28080517, -12389115,
++             19345746, 14680796, 11632993, 5847885},
++            {26942781, -2315317, 9129564, -4906607, 26024105, 11769399,
++             -11518837, 6367194, -9727230, 4782140},
++            {19916461, -4828410, -22910704, -11414391, 25606324, -5972441,
++             33253853, 8220911, 6358847, -1873857},
++        },
++        {
++            {801428, -2081702, 16569428, 11065167, 29875704, 96627, 7908388,
++             -4480480, -13538503, 1387155},
++            {19646058, 5720633, -11416706, 12814209, 11607948, 12749789,
++             14147075, 15156355, -21866831, 11835260},
++            {19299512, 1155910, 28703737, 14890794, 2925026, 7269399, 26121523,
++             15467869, -26560550, 5052483},
++        },
++    },
++    {
++        {
++            {-3017432, 10058206, 1980837, 3964243, 22160966, 12322533, -6431123,
++             -12618185, 12228557, -7003677},
++            {32944382, 14922211, -22844894, 5188528, 21913450, -8719943,
++             4001465, 13238564, -6114803, 8653815},
++            {22865569, -4652735, 27603668, -12545395, 14348958, 8234005,
++             24808405, 5719875, 28483275, 2841751},
++        },
++        {
++            {-16420968, -1113305, -327719, -12107856, 21886282, -15552774,
++             -1887966, -315658, 19932058, -12739203},
++            {-11656086, 10087521, -8864888, -5536143, -19278573, -3055912,
++             3999228, 13239134, -4777469, -13910208},
++            {1382174, -11694719, 17266790, 9194690, -13324356, 9720081,
++             20403944, 11284705, -14013818, 3093230},
++        },
++        {
++            {16650921, -11037932, -1064178, 1570629, -8329746, 7352753, -302424,
++             16271225, -24049421, -6691850},
++            {-21911077, -5927941, -4611316, -5560156, -31744103, -10785293,
++             24123614, 15193618, -21652117, -16739389},
++            {-9935934, -4289447, -25279823, 4372842, 2087473, 10399484,
++             31870908, 14690798, 17361620, 11864968},
++        },
++        {
++            {-11307610, 6210372, 13206574, 5806320, -29017692, -13967200,
++             -12331205, -7486601, -25578460, -16240689},
++            {14668462, -12270235, 26039039, 15305210, 25515617, 4542480,
++             10453892, 6577524, 9145645, -6443880},
++            {5974874, 3053895, -9433049, -10385191, -31865124, 3225009,
++             -7972642, 3936128, -5652273, -3050304},
++        },
++        {
++            {30625386, -4729400, -25555961, -12792866, -20484575, 7695099,
++             17097188, -16303496, -27999779, 1803632},
++            {-3553091, 9865099, -5228566, 4272701, -5673832, -16689700,
++             14911344, 12196514, -21405489, 7047412},
++            {20093277, 9920966, -11138194, -5343857, 13161587, 12044805,
++             -32856851, 4124601, -32343828, -10257566},
++        },
++        {
++            {-20788824, 14084654, -13531713, 7842147, 19119038, -13822605,
++             4752377, -8714640, -21679658, 2288038},
++            {-26819236, -3283715, 29965059, 3039786, -14473765, 2540457,
++             29457502, 14625692, -24819617, 12570232},
++            {-1063558, -11551823, 16920318, 12494842, 1278292, -5869109,
++             -21159943, -3498680, -11974704, 4724943},
++        },
++        {
++            {17960970, -11775534, -4140968, -9702530, -8876562, -1410617,
++             -12907383, -8659932, -29576300, 1903856},
++            {23134274, -14279132, -10681997, -1611936, 20684485, 15770816,
++             -12989750, 3190296, 26955097, 14109738},
++            {15308788, 5320727, -30113809, -14318877, 22902008, 7767164,
++             29425325, -11277562, 31960942, 11934971},
++        },
++        {
++            {-27395711, 8435796, 4109644, 12222639, -24627868, 14818669,
++             20638173, 4875028, 10491392, 1379718},
++            {-13159415, 9197841, 3875503, -8936108, -1383712, -5879801,
++             33518459, 16176658, 21432314, 12180697},
++            {-11787308, 11500838, 13787581, -13832590, -22430679, 10140205,
++             1465425, 12689540, -10301319, -13872883},
++        },
++    },
++    {
++        {
++            {5414091, -15386041, -21007664, 9643570, 12834970, 1186149,
++             -2622916, -1342231, 26128231, 6032912},
++            {-26337395, -13766162, 32496025, -13653919, 17847801, -12669156,
++             3604025, 8316894, -25875034, -10437358},
++            {3296484, 6223048, 24680646, -12246460, -23052020, 5903205,
++             -8862297, -4639164, 12376617, 3188849},
++        },
++        {
++            {29190488, -14659046, 27549113, -1183516, 3520066, -10697301,
++             32049515, -7309113, -16109234, -9852307},
++            {-14744486, -9309156, 735818, -598978, -20407687, -5057904,
++             25246078, -15795669, 18640741, -960977},
++            {-6928835, -16430795, 10361374, 5642961, 4910474, 12345252,
++             -31638386, -494430, 10530747, 1053335},
++        },
++        {
++            {-29265967, -14186805, -13538216, -12117373, -19457059, -10655384,
++             -31462369, -2948985, 24018831, 15026644},
++            {-22592535, -3145277, -2289276, 5953843, -13440189, 9425631,
++             25310643, 13003497, -2314791, -15145616},
++            {-27419985, -603321, -8043984, -1669117, -26092265, 13987819,
++             -27297622, 187899, -23166419, -2531735},
++        },
++        {
++            {-21744398, -13810475, 1844840, 5021428, -10434399, -15911473,
++             9716667, 16266922, -5070217, 726099},
++            {29370922, -6053998, 7334071, -15342259, 9385287, 2247707,
++             -13661962, -4839461, 30007388, -15823341},
++            {-936379, 16086691, 23751945, -543318, -1167538, -5189036, 9137109,
++             730663, 9835848, 4555336},
++        },
++        {
++            {-23376435, 1410446, -22253753, -12899614, 30867635, 15826977,
++             17693930, 544696, -11985298, 12422646},
++            {31117226, -12215734, -13502838, 6561947, -9876867, -12757670,
++             -5118685, -4096706, 29120153, 13924425},
++            {-17400879, -14233209, 19675799, -2734756, -11006962, -5858820,
++             -9383939, -11317700, 7240931, -237388},
++        },
++        {
++            {-31361739, -11346780, -15007447, -5856218, -22453340, -12152771,
++             1222336, 4389483, 3293637, -15551743},
++            {-16684801, -14444245, 11038544, 11054958, -13801175, -3338533,
++             -24319580, 7733547, 12796905, -6335822},
++            {-8759414, -10817836, -25418864, 10783769, -30615557, -9746811,
++             -28253339, 3647836, 3222231, -11160462},
++        },
++        {
++            {18606113, 1693100, -25448386, -15170272, 4112353, 10045021,
++             23603893, -2048234, -7550776, 2484985},
++            {9255317, -3131197, -12156162, -1004256, 13098013, -9214866,
++             16377220, -2102812, -19802075, -3034702},
++            {-22729289, 7496160, -5742199, 11329249, 19991973, -3347502,
++             -31718148, 9936966, -30097688, -10618797},
++        },
++        {
++            {21878590, -5001297, 4338336, 13643897, -3036865, 13160960,
++             19708896, 5415497, -7360503, -4109293},
++            {27736861, 10103576, 12500508, 8502413, -3413016, -9633558,
++             10436918, -1550276, -23659143, -8132100},
++            {19492550, -12104365, -29681976, -852630, -3208171, 12403437,
++             30066266, 8367329, 13243957, 8709688},
++        },
++    },
++    {
++        {
++            {12015105, 2801261, 28198131, 10151021, 24818120, -4743133,
++             -11194191, -5645734, 5150968, 7274186},
++            {2831366, -12492146, 1478975, 6122054, 23825128, -12733586,
++             31097299, 6083058, 31021603, -9793610},
++            {-2529932, -2229646, 445613, 10720828, -13849527, -11505937,
++             -23507731, 16354465, 15067285, -14147707},
++        },
++        {
++            {7840942, 14037873, -33364863, 15934016, -728213, -3642706,
++             21403988, 1057586, -19379462, -12403220},
++            {915865, -16469274, 15608285, -8789130, -24357026, 6060030,
++             -17371319, 8410997, -7220461, 16527025},
++            {32922597, -556987, 20336074, -16184568, 10903705, -5384487,
++             16957574, 52992, 23834301, 6588044},
++        },
++        {
++            {32752030, 11232950, 3381995, -8714866, 22652988, -10744103,
++             17159699, 16689107, -20314580, -1305992},
++            {-4689649, 9166776, -25710296, -10847306, 11576752, 12733943,
++             7924251, -2752281, 1976123, -7249027},
++            {21251222, 16309901, -2983015, -6783122, 30810597, 12967303, 156041,
++             -3371252, 12331345, -8237197},
++        },
++        {
++            {8651614, -4477032, -16085636, -4996994, 13002507, 2950805,
++             29054427, -5106970, 10008136, -4667901},
++            {31486080, 15114593, -14261250, 12951354, 14369431, -7387845,
++             16347321, -13662089, 8684155, -10532952},
++            {19443825, 11385320, 24468943, -9659068, -23919258, 2187569,
++             -26263207, -6086921, 31316348, 14219878},
++        },
++        {
++            {-28594490, 1193785, 32245219, 11392485, 31092169, 15722801,
++             27146014, 6992409, 29126555, 9207390},
++            {32382935, 1110093, 18477781, 11028262, -27411763, -7548111,
++             -4980517, 10843782, -7957600, -14435730},
++            {2814918, 7836403, 27519878, -7868156, -20894015, -11553689,
++             -21494559, 8550130, 28346258, 1994730},
++        },
++        {
++            {-19578299, 8085545, -14000519, -3948622, 2785838, -16231307,
++             -19516951, 7174894, 22628102, 8115180},
++            {-30405132, 955511, -11133838, -15078069, -32447087, -13278079,
++             -25651578, 3317160, -9943017, 930272},
++            {-15303681, -6833769, 28856490, 1357446, 23421993, 1057177,
++             24091212, -1388970, -22765376, -10650715},
++        },
++        {
++            {-22751231, -5303997, -12907607, -12768866, -15811511, -7797053,
++             -14839018, -16554220, -1867018, 8398970},
++            {-31969310, 2106403, -4736360, 1362501, 12813763, 16200670,
++             22981545, -6291273, 18009408, -15772772},
++            {-17220923, -9545221, -27784654, 14166835, 29815394, 7444469,
++             29551787, -3727419, 19288549, 1325865},
++        },
++        {
++            {15100157, -15835752, -23923978, -1005098, -26450192, 15509408,
++             12376730, -3479146, 33166107, -8042750},
++            {20909231, 13023121, -9209752, 16251778, -5778415, -8094914,
++             12412151, 10018715, 2213263, -13878373},
++            {32529814, -11074689, 30361439, -16689753, -9135940, 1513226,
++             22922121, 6382134, -5766928, 8371348},
++        },
++    },
++    {
++        {
++            {9923462, 11271500, 12616794, 3544722, -29998368, -1721626,
++             12891687, -8193132, -26442943, 10486144},
++            {-22597207, -7012665, 8587003, -8257861, 4084309, -12970062, 361726,
++             2610596, -23921530, -11455195},
++            {5408411, -1136691, -4969122, 10561668, 24145918, 14240566,
++             31319731, -4235541, 19985175, -3436086},
++        },
++        {
++            {-13994457, 16616821, 14549246, 3341099, 32155958, 13648976,
++             -17577068, 8849297, 65030, 8370684},
++            {-8320926, -12049626, 31204563, 5839400, -20627288, -1057277,
++             -19442942, 6922164, 12743482, -9800518},
++            {-2361371, 12678785, 28815050, 4759974, -23893047, 4884717,
++             23783145, 11038569, 18800704, 255233},
++        },
++        {
++            {-5269658, -1773886, 13957886, 7990715, 23132995, 728773, 13393847,
++             9066957, 19258688, -14753793},
++            {-2936654, -10827535, -10432089, 14516793, -3640786, 4372541,
++             -31934921, 2209390, -1524053, 2055794},
++            {580882, 16705327, 5468415, -2683018, -30926419, -14696000,
++             -7203346, -8994389, -30021019, 7394435},
++        },
++        {
++            {23838809, 1822728, -15738443, 15242727, 8318092, -3733104,
++             -21672180, -3492205, -4821741, 14799921},
++            {13345610, 9759151, 3371034, -16137791, 16353039, 8577942, 31129804,
++             13496856, -9056018, 7402518},
++            {2286874, -4435931, -20042458, -2008336, -13696227, 5038122,
++             11006906, -15760352, 8205061, 1607563},
++        },
++        {
++            {14414086, -8002132, 3331830, -3208217, 22249151, -5594188,
++             18364661, -2906958, 30019587, -9029278},
++            {-27688051, 1585953, -10775053, 931069, -29120221, -11002319,
++             -14410829, 12029093, 9944378, 8024},
++            {4368715, -3709630, 29874200, -15022983, -20230386, -11410704,
++             -16114594, -999085, -8142388, 5640030},
++        },
++        {
++            {10299610, 13746483, 11661824, 16234854, 7630238, 5998374, 9809887,
++             -16694564, 15219798, -14327783},
++            {27425505, -5719081, 3055006, 10660664, 23458024, 595578, -15398605,
++             -1173195, -18342183, 9742717},
++            {6744077, 2427284, 26042789, 2720740, -847906, 1118974, 32324614,
++             7406442, 12420155, 1994844},
++        },
++        {
++            {14012521, -5024720, -18384453, -9578469, -26485342, -3936439,
++             -13033478, -10909803, 24319929, -6446333},
++            {16412690, -4507367, 10772641, 15929391, -17068788, -4658621,
++             10555945, -10484049, -30102368, -4739048},
++            {22397382, -7767684, -9293161, -12792868, 17166287, -9755136,
++             -27333065, 6199366, 21880021, -12250760},
++        },
++        {
++            {-4283307, 5368523, -31117018, 8163389, -30323063, 3209128,
++             16557151, 8890729, 8840445, 4957760},
++            {-15447727, 709327, -6919446, -10870178, -29777922, 6522332,
++             -21720181, 12130072, -14796503, 5005757},
++            {-2114751, -14308128, 23019042, 15765735, -25269683, 6002752,
++             10183197, -13239326, -16395286, -2176112},
++        },
++    },
++    {
++        {
++            {-19025756, 1632005, 13466291, -7995100, -23640451, 16573537,
++             -32013908, -3057104, 22208662, 2000468},
++            {3065073, -1412761, -25598674, -361432, -17683065, -5703415,
++             -8164212, 11248527, -3691214, -7414184},
++            {10379208, -6045554, 8877319, 1473647, -29291284, -12507580,
++             16690915, 2553332, -3132688, 16400289},
++        },
++        {
++            {15716668, 1254266, -18472690, 7446274, -8448918, 6344164,
++             -22097271, -7285580, 26894937, 9132066},
++            {24158887, 12938817, 11085297, -8177598, -28063478, -4457083,
++             -30576463, 64452, -6817084, -2692882},
++            {13488534, 7794716, 22236231, 5989356, 25426474, -12578208, 2350710,
++             -3418511, -4688006, 2364226},
++        },
++        {
++            {16335052, 9132434, 25640582, 6678888, 1725628, 8517937, -11807024,
++             -11697457, 15445875, -7798101},
++            {29004207, -7867081, 28661402, -640412, -12794003, -7943086,
++             31863255, -4135540, -278050, -15759279},
++            {-6122061, -14866665, -28614905, 14569919, -10857999, -3591829,
++             10343412, -6976290, -29828287, -10815811},
++        },
++        {
++            {27081650, 3463984, 14099042, -4517604, 1616303, -6205604, 29542636,
++             15372179, 17293797, 960709},
++            {20263915, 11434237, -5765435, 11236810, 13505955, -10857102,
++             -16111345, 6493122, -19384511, 7639714},
++            {-2830798, -14839232, 25403038, -8215196, -8317012, -16173699,
++             18006287, -16043750, 29994677, -15808121},
++        },
++        {
++            {9769828, 5202651, -24157398, -13631392, -28051003, -11561624,
++             -24613141, -13860782, -31184575, 709464},
++            {12286395, 13076066, -21775189, -1176622, -25003198, 4057652,
++             -32018128, -8890874, 16102007, 13205847},
++            {13733362, 5599946, 10557076, 3195751, -5557991, 8536970, -25540170,
++             8525972, 10151379, 10394400},
++        },
++        {
++            {4024660, -16137551, 22436262, 12276534, -9099015, -2686099,
++             19698229, 11743039, -33302334, 8934414},
++            {-15879800, -4525240, -8580747, -2934061, 14634845, -698278,
++             -9449077, 3137094, -11536886, 11721158},
++            {17555939, -5013938, 8268606, 2331751, -22738815, 9761013, 9319229,
++             8835153, -9205489, -1280045},
++        },
++        {
++            {-461409, -7830014, 20614118, 16688288, -7514766, -4807119,
++             22300304, 505429, 6108462, -6183415},
++            {-5070281, 12367917, -30663534, 3234473, 32617080, -8422642,
++             29880583, -13483331, -26898490, -7867459},
++            {-31975283, 5726539, 26934134, 10237677, -3173717, -605053,
++             24199304, 3795095, 7592688, -14992079},
++        },
++        {
++            {21594432, -14964228, 17466408, -4077222, 32537084, 2739898,
++             6407723, 12018833, -28256052, 4298412},
++            {-20650503, -11961496, -27236275, 570498, 3767144, -1717540,
++             13891942, -1569194, 13717174, 10805743},
++            {-14676630, -15644296, 15287174, 11927123, 24177847, -8175568,
++             -796431, 14860609, -26938930, -5863836},
++        },
++    },
++    {
++        {
++            {12962541, 5311799, -10060768, 11658280, 18855286, -7954201,
++             13286263, -12808704, -4381056, 9882022},
++            {18512079, 11319350, -20123124, 15090309, 18818594, 5271736,
++             -22727904, 3666879, -23967430, -3299429},
++            {-6789020, -3146043, 16192429, 13241070, 15898607, -14206114,
++             -10084880, -6661110, -2403099, 5276065},
++        },
++        {
++            {30169808, -5317648, 26306206, -11750859, 27814964, 7069267,
++             7152851, 3684982, 1449224, 13082861},
++            {10342826, 3098505, 2119311, 193222, 25702612, 12233820, 23697382,
++             15056736, -21016438, -8202000},
++            {-33150110, 3261608, 22745853, 7948688, 19370557, -15177665,
++             -26171976, 6482814, -10300080, -11060101},
++        },
++        {
++            {32869458, -5408545, 25609743, 15678670, -10687769, -15471071,
++             26112421, 2521008, -22664288, 6904815},
++            {29506923, 4457497, 3377935, -9796444, -30510046, 12935080, 1561737,
++             3841096, -29003639, -6657642},
++            {10340844, -6630377, -18656632, -2278430, 12621151, -13339055,
++             30878497, -11824370, -25584551, 5181966},
++        },
++        {
++            {25940115, -12658025, 17324188, -10307374, -8671468, 15029094,
++             24396252, -16450922, -2322852, -12388574},
++            {-21765684, 9916823, -1300409, 4079498, -1028346, 11909559, 1782390,
++             12641087, 20603771, -6561742},
++            {-18882287, -11673380, 24849422, 11501709, 13161720, -4768874,
++             1925523, 11914390, 4662781, 7820689},
++        },
++        {
++            {12241050, -425982, 8132691, 9393934, 32846760, -1599620, 29749456,
++             12172924, 16136752, 15264020},
++            {-10349955, -14680563, -8211979, 2330220, -17662549, -14545780,
++             10658213, 6671822, 19012087, 3772772},
++            {3753511, -3421066, 10617074, 2028709, 14841030, -6721664, 28718732,
++             -15762884, 20527771, 12988982},
++        },
++        {
++            {-14822485, -5797269, -3707987, 12689773, -898983, -10914866,
++             -24183046, -10564943, 3299665, -12424953},
++            {-16777703, -15253301, -9642417, 4978983, 3308785, 8755439, 6943197,
++             6461331, -25583147, 8991218},
++            {-17226263, 1816362, -1673288, -6086439, 31783888, -8175991,
++             -32948145, 7417950, -30242287, 1507265},
++        },
++        {
++            {29692663, 6829891, -10498800, 4334896, 20945975, -11906496,
++             -28887608, 8209391, 14606362, -10647073},
++            {-3481570, 8707081, 32188102, 5672294, 22096700, 1711240, -33020695,
++             9761487, 4170404, -2085325},
++            {-11587470, 14855945, -4127778, -1531857, -26649089, 15084046,
++             22186522, 16002000, -14276837, -8400798},
++        },
++        {
++            {-4811456, 13761029, -31703877, -2483919, -3312471, 7869047,
++             -7113572, -9620092, 13240845, 10965870},
++            {-7742563, -8256762, -14768334, -13656260, -23232383, 12387166,
++             4498947, 14147411, 29514390, 4302863},
++            {-13413405, -12407859, 20757302, -13801832, 14785143, 8976368,
++             -5061276, -2144373, 17846988, -13971927},
++        },
++    },
++    {
++        {
++            {-2244452, -754728, -4597030, -1066309, -6247172, 1455299,
++             -21647728, -9214789, -5222701, 12650267},
++            {-9906797, -16070310, 21134160, 12198166, -27064575, 708126, 387813,
++             13770293, -19134326, 10958663},
++            {22470984, 12369526, 23446014, -5441109, -21520802, -9698723,
++             -11772496, -11574455, -25083830, 4271862},
++        },
++        {
++            {-25169565, -10053642, -19909332, 15361595, -5984358, 2159192,
++             75375, -4278529, -32526221, 8469673},
++            {15854970, 4148314, -8893890, 7259002, 11666551, 13824734,
++             -30531198, 2697372, 24154791, -9460943},
++            {15446137, -15806644, 29759747, 14019369, 30811221, -9610191,
++             -31582008, 12840104, 24913809, 9815020},
++        },
++        {
++            {-4709286, -5614269, -31841498, -12288893, -14443537, 10799414,
++             -9103676, 13438769, 18735128, 9466238},
++            {11933045, 9281483, 5081055, -5183824, -2628162, -4905629, -7727821,
++             -10896103, -22728655, 16199064},
++            {14576810, 379472, -26786533, -8317236, -29426508, -10812974,
++             -102766, 1876699, 30801119, 2164795},
++        },
++        {
++            {15995086, 3199873, 13672555, 13712240, -19378835, -4647646,
++             -13081610, -15496269, -13492807, 1268052},
++            {-10290614, -3659039, -3286592, 10948818, 23037027, 3794475,
++             -3470338, -12600221, -17055369, 3565904},
++            {29210088, -9419337, -5919792, -4952785, 10834811, -13327726,
++             -16512102, -10820713, -27162222, -14030531},
++        },
++        {
++            {-13161890, 15508588, 16663704, -8156150, -28349942, 9019123,
++             -29183421, -3769423, 2244111, -14001979},
++            {-5152875, -3800936, -9306475, -6071583, 16243069, 14684434,
++             -25673088, -16180800, 13491506, 4641841},
++            {10813417, 643330, -19188515, -728916, 30292062, -16600078,
++             27548447, -7721242, 14476989, -12767431},
++        },
++        {
++            {10292079, 9984945, 6481436, 8279905, -7251514, 7032743, 27282937,
++             -1644259, -27912810, 12651324},
++            {-31185513, -813383, 22271204, 11835308, 10201545, 15351028,
++             17099662, 3988035, 21721536, -3148940},
++            {10202177, -6545839, -31373232, -9574638, -32150642, -8119683,
++             -12906320, 3852694, 13216206, 14842320},
++        },
++        {
++            {-15815640, -10601066, -6538952, -7258995, -6984659, -6581778,
++             -31500847, 13765824, -27434397, 9900184},
++            {14465505, -13833331, -32133984, -14738873, -27443187, 12990492,
++             33046193, 15796406, -7051866, -8040114},
++            {30924417, -8279620, 6359016, -12816335, 16508377, 9071735,
++             -25488601, 15413635, 9524356, -7018878},
++        },
++        {
++            {12274201, -13175547, 32627641, -1785326, 6736625, 13267305,
++             5237659, -5109483, 15663516, 4035784},
++            {-2951309, 8903985, 17349946, 601635, -16432815, -4612556,
++             -13732739, -15889334, -22258478, 4659091},
++            {-16916263, -4952973, -30393711, -15158821, 20774812, 15897498,
++             5736189, 15026997, -2178256, -13455585},
++        },
++    },
++    {
++        {
++            {-8858980, -2219056, 28571666, -10155518, -474467, -10105698,
++             -3801496, 278095, 23440562, -290208},
++            {10226241, -5928702, 15139956, 120818, -14867693, 5218603, 32937275,
++             11551483, -16571960, -7442864},
++            {17932739, -12437276, -24039557, 10749060, 11316803, 7535897,
++             22503767, 5561594, -3646624, 3898661},
++        },
++        {
++            {7749907, -969567, -16339731, -16464, -25018111, 15122143, -1573531,
++             7152530, 21831162, 1245233},
++            {26958459, -14658026, 4314586, 8346991, -5677764, 11960072,
++             -32589295, -620035, -30402091, -16716212},
++            {-12165896, 9166947, 33491384, 13673479, 29787085, 13096535,
++             6280834, 14587357, -22338025, 13987525},
++        },
++        {
++            {-24349909, 7778775, 21116000, 15572597, -4833266, -5357778,
++             -4300898, -5124639, -7469781, -2858068},
++            {9681908, -6737123, -31951644, 13591838, -6883821, 386950, 31622781,
++             6439245, -14581012, 4091397},
++            {-8426427, 1470727, -28109679, -1596990, 3978627, -5123623,
++             -19622683, 12092163, 29077877, -14741988},
++        },
++        {
++            {5269168, -6859726, -13230211, -8020715, 25932563, 1763552,
++             -5606110, -5505881, -20017847, 2357889},
++            {32264008, -15407652, -5387735, -1160093, -2091322, -3946900,
++             23104804, -12869908, 5727338, 189038},
++            {14609123, -8954470, -6000566, -16622781, -14577387, -7743898,
++             -26745169, 10942115, -25888931, -14884697},
++        },
++        {
++            {20513500, 5557931, -15604613, 7829531, 26413943, -2019404,
++             -21378968, 7471781, 13913677, -5137875},
++            {-25574376, 11967826, 29233242, 12948236, -6754465, 4713227,
++             -8940970, 14059180, 12878652, 8511905},
++            {-25656801, 3393631, -2955415, -7075526, -2250709, 9366908,
++             -30223418, 6812974, 5568676, -3127656},
++        },
++        {
++            {11630004, 12144454, 2116339, 13606037, 27378885, 15676917,
++             -17408753, -13504373, -14395196, 8070818},
++            {27117696, -10007378, -31282771, -5570088, 1127282, 12772488,
++             -29845906, 10483306, -11552749, -1028714},
++            {10637467, -5688064, 5674781, 1072708, -26343588, -6982302,
++             -1683975, 9177853, -27493162, 15431203},
++        },
++        {
++            {20525145, 10892566, -12742472, 12779443, -29493034, 16150075,
++             -28240519, 14943142, -15056790, -7935931},
++            {-30024462, 5626926, -551567, -9981087, 753598, 11981191, 25244767,
++             -3239766, -3356550, 9594024},
++            {-23752644, 2636870, -5163910, -10103818, 585134, 7877383, 11345683,
++             -6492290, 13352335, -10977084},
++        },
++        {
++            {-1931799, -5407458, 3304649, -12884869, 17015806, -4877091,
++             -29783850, -7752482, -13215537, -319204},
++            {20239939, 6607058, 6203985, 3483793, -18386976, -779229, -20723742,
++             15077870, -22750759, 14523817},
++            {27406042, -6041657, 27423596, -4497394, 4996214, 10002360,
++             -28842031, -4545494, -30172742, -4805667},
++        },
++    },
++    {
++        {
++            {11374242, 12660715, 17861383, -12540833, 10935568, 1099227,
++             -13886076, -9091740, -27727044, 11358504},
++            {-12730809, 10311867, 1510375, 10778093, -2119455, -9145702,
++             32676003, 11149336, -26123651, 4985768},
++            {-19096303, 341147, -6197485, -239033, 15756973, -8796662, -983043,
++             13794114, -19414307, -15621255},
++        },
++        {
++            {6490081, 11940286, 25495923, -7726360, 8668373, -8751316, 3367603,
++             6970005, -1691065, -9004790},
++            {1656497, 13457317, 15370807, 6364910, 13605745, 8362338, -19174622,
++             -5475723, -16796596, -5031438},
++            {-22273315, -13524424, -64685, -4334223, -18605636, -10921968,
++             -20571065, -7007978, -99853, -10237333},
++        },
++        {
++            {17747465, 10039260, 19368299, -4050591, -20630635, -16041286,
++             31992683, -15857976, -29260363, -5511971},
++            {31932027, -4986141, -19612382, 16366580, 22023614, 88450, 11371999,
++             -3744247, 4882242, -10626905},
++            {29796507, 37186, 19818052, 10115756, -11829032, 3352736, 18551198,
++             3272828, -5190932, -4162409},
++        },
++        {
++            {12501286, 4044383, -8612957, -13392385, -32430052, 5136599,
++             -19230378, -3529697, 330070, -3659409},
++            {6384877, 2899513, 17807477, 7663917, -2358888, 12363165, 25366522,
++             -8573892, -271295, 12071499},
++            {-8365515, -4042521, 25133448, -4517355, -6211027, 2265927,
++             -32769618, 1936675, -5159697, 3829363},
++        },
++        {
++            {28425966, -5835433, -577090, -4697198, -14217555, 6870930, 7921550,
++             -6567787, 26333140, 14267664},
++            {-11067219, 11871231, 27385719, -10559544, -4585914, -11189312,
++             10004786, -8709488, -21761224, 8930324},
++            {-21197785, -16396035, 25654216, -1725397, 12282012, 11008919,
++             1541940, 4757911, -26491501, -16408940},
++        },
++        {
++            {13537262, -7759490, -20604840, 10961927, -5922820, -13218065,
++             -13156584, 6217254, -15943699, 13814990},
++            {-17422573, 15157790, 18705543, 29619, 24409717, -260476, 27361681,
++             9257833, -1956526, -1776914},
++            {-25045300, -10191966, 15366585, 15166509, -13105086, 8423556,
++             -29171540, 12361135, -18685978, 4578290},
++        },
++        {
++            {24579768, 3711570, 1342322, -11180126, -27005135, 14124956,
++             -22544529, 14074919, 21964432, 8235257},
++            {-6528613, -2411497, 9442966, -5925588, 12025640, -1487420,
++             -2981514, -1669206, 13006806, 2355433},
++            {-16304899, -13605259, -6632427, -5142349, 16974359, -10911083,
++             27202044, 1719366, 1141648, -12796236},
++        },
++        {
++            {-12863944, -13219986, -8318266, -11018091, -6810145, -4843894,
++             13475066, -3133972, 32674895, 13715045},
++            {11423335, -5468059, 32344216, 8962751, 24989809, 9241752,
++             -13265253, 16086212, -28740881, -15642093},
++            {-1409668, 12530728, -6368726, 10847387, 19531186, -14132160,
++             -11709148, 7791794, -27245943, 4383347},
++        },
++    },
++    {
++        {
++            {-28970898, 5271447, -1266009, -9736989, -12455236, 16732599,
++             -4862407, -4906449, 27193557, 6245191},
++            {-15193956, 5362278, -1783893, 2695834, 4960227, 12840725, 23061898,
++             3260492, 22510453, 8577507},
++            {-12632451, 11257346, -32692994, 13548177, -721004, 10879011,
++             31168030, 13952092, -29571492, -3635906},
++        },
++        {
++            {3877321, -9572739, 32416692, 5405324, -11004407, -13656635,
++             3759769, 11935320, 5611860, 8164018},
++            {-16275802, 14667797, 15906460, 12155291, -22111149, -9039718,
++             32003002, -8832289, 5773085, -8422109},
++            {-23788118, -8254300, 1950875, 8937633, 18686727, 16459170, -905725,
++             12376320, 31632953, 190926},
++        },
++        {
++            {-24593607, -16138885, -8423991, 13378746, 14162407, 6901328,
++             -8288749, 4508564, -25341555, -3627528},
++            {8884438, -5884009, 6023974, 10104341, -6881569, -4941533, 18722941,
++             -14786005, -1672488, 827625},
++            {-32720583, -16289296, -32503547, 7101210, 13354605, 2659080,
++             -1800575, -14108036, -24878478, 1541286},
++        },
++        {
++            {2901347, -1117687, 3880376, -10059388, -17620940, -3612781,
++             -21802117, -3567481, 20456845, -1885033},
++            {27019610, 12299467, -13658288, -1603234, -12861660, -4861471,
++             -19540150, -5016058, 29439641, 15138866},
++            {21536104, -6626420, -32447818, -10690208, -22408077, 5175814,
++             -5420040, -16361163, 7779328, 109896},
++        },
++        {
++            {30279744, 14648750, -8044871, 6425558, 13639621, -743509, 28698390,
++             12180118, 23177719, -554075},
++            {26572847, 3405927, -31701700, 12890905, -19265668, 5335866,
++             -6493768, 2378492, 4439158, -13279347},
++            {-22716706, 3489070, -9225266, -332753, 18875722, -1140095,
++             14819434, -12731527, -17717757, -5461437},
++        },
++        {
++            {-5056483, 16566551, 15953661, 3767752, -10436499, 15627060,
++             -820954, 2177225, 8550082, -15114165},
++            {-18473302, 16596775, -381660, 15663611, 22860960, 15585581,
++             -27844109, -3582739, -23260460, -8428588},
++            {-32480551, 15707275, -8205912, -5652081, 29464558, 2713815,
++             -22725137, 15860482, -21902570, 1494193},
++        },
++        {
++            {-19562091, -14087393, -25583872, -9299552, 13127842, 759709,
++             21923482, 16529112, 8742704, 12967017},
++            {-28464899, 1553205, 32536856, -10473729, -24691605, -406174,
++             -8914625, -2933896, -29903758, 15553883},
++            {21877909, 3230008, 9881174, 10539357, -4797115, 2841332, 11543572,
++             14513274, 19375923, -12647961},
++        },
++        {
++            {8832269, -14495485, 13253511, 5137575, 5037871, 4078777, 24880818,
++             -6222716, 2862653, 9455043},
++            {29306751, 5123106, 20245049, -14149889, 9592566, 8447059, -2077124,
++             -2990080, 15511449, 4789663},
++            {-20679756, 7004547, 8824831, -9434977, -4045704, -3750736,
++             -5754762, 108893, 23513200, 16652362},
++        },
++    },
++    {
++        {
++            {-33256173, 4144782, -4476029, -6579123, 10770039, -7155542,
++             -6650416, -12936300, -18319198, 10212860},
++            {2756081, 8598110, 7383731, -6859892, 22312759, -1105012, 21179801,
++             2600940, -9988298, -12506466},
++            {-24645692, 13317462, -30449259, -15653928, 21365574, -10869657,
++             11344424, 864440, -2499677, -16710063},
++        },
++        {
++            {-26432803, 6148329, -17184412, -14474154, 18782929, -275997,
++             -22561534, 211300, 2719757, 4940997},
++            {-1323882, 3911313, -6948744, 14759765, -30027150, 7851207,
++             21690126, 8518463, 26699843, 5276295},
++            {-13149873, -6429067, 9396249, 365013, 24703301, -10488939, 1321586,
++             149635, -15452774, 7159369},
++        },
++        {
++            {9987780, -3404759, 17507962, 9505530, 9731535, -2165514, 22356009,
++             8312176, 22477218, -8403385},
++            {18155857, -16504990, 19744716, 9006923, 15154154, -10538976,
++             24256460, -4864995, -22548173, 9334109},
++            {2986088, -4911893, 10776628, -3473844, 10620590, -7083203,
++             -21413845, 14253545, -22587149, 536906},
++        },
++        {
++            {4377756, 8115836, 24567078, 15495314, 11625074, 13064599, 7390551,
++             10589625, 10838060, -15420424},
++            {-19342404, 867880, 9277171, -3218459, -14431572, -1986443,
++             19295826, -15796950, 6378260, 699185},
++            {7895026, 4057113, -7081772, -13077756, -17886831, -323126, -716039,
++             15693155, -5045064, -13373962},
++        },
++        {
++            {-7737563, -5869402, -14566319, -7406919, 11385654, 13201616,
++             31730678, -10962840, -3918636, -9669325},
++            {10188286, -15770834, -7336361, 13427543, 22223443, 14896287,
++             30743455, 7116568, -21786507, 5427593},
++            {696102, 13206899, 27047647, -10632082, 15285305, -9853179,
++             10798490, -4578720, 19236243, 12477404},
++        },
++        {
++            {-11229439, 11243796, -17054270, -8040865, -788228, -8167967,
++             -3897669, 11180504, -23169516, 7733644},
++            {17800790, -14036179, -27000429, -11766671, 23887827, 3149671,
++             23466177, -10538171, 10322027, 15313801},
++            {26246234, 11968874, 32263343, -5468728, 6830755, -13323031,
++             -15794704, -101982, -24449242, 10890804},
++        },
++        {
++            {-31365647, 10271363, -12660625, -6267268, 16690207, -13062544,
++             -14982212, 16484931, 25180797, -5334884},
++            {-586574, 10376444, -32586414, -11286356, 19801893, 10997610,
++             2276632, 9482883, 316878, 13820577},
++            {-9882808, -4510367, -2115506, 16457136, -11100081, 11674996,
++             30756178, -7515054, 30696930, -3712849},
++        },
++        {
++            {32988917, -9603412, 12499366, 7910787, -10617257, -11931514,
++             -7342816, -9985397, -32349517, 7392473},
++            {-8855661, 15927861, 9866406, -3649411, -2396914, -16655781,
++             -30409476, -9134995, 25112947, -2926644},
++            {-2504044, -436966, 25621774, -5678772, 15085042, -5479877,
++             -24884878, -13526194, 5537438, -13914319},
++        },
++    },
++    {
++        {
++            {-11225584, 2320285, -9584280, 10149187, -33444663, 5808648,
++             -14876251, -1729667, 31234590, 6090599},
++            {-9633316, 116426, 26083934, 2897444, -6364437, -2688086, 609721,
++             15878753, -6970405, -9034768},
++            {-27757857, 247744, -15194774, -9002551, 23288161, -10011936,
++             -23869595, 6503646, 20650474, 1804084},
++        },
++        {
++            {-27589786, 15456424, 8972517, 8469608, 15640622, 4439847, 3121995,
++             -10329713, 27842616, -202328},
++            {-15306973, 2839644, 22530074, 10026331, 4602058, 5048462, 28248656,
++             5031932, -11375082, 12714369},
++            {20807691, -7270825, 29286141, 11421711, -27876523, -13868230,
++             -21227475, 1035546, -19733229, 12796920},
++        },
++        {
++            {12076899, -14301286, -8785001, -11848922, -25012791, 16400684,
++             -17591495, -12899438, 3480665, -15182815},
++            {-32361549, 5457597, 28548107, 7833186, 7303070, -11953545,
++             -24363064, -15921875, -33374054, 2771025},
++            {-21389266, 421932, 26597266, 6860826, 22486084, -6737172,
++             -17137485, -4210226, -24552282, 15673397},
++        },
++        {
++            {-20184622, 2338216, 19788685, -9620956, -4001265, -8740893,
++             -20271184, 4733254, 3727144, -12934448},
++            {6120119, 814863, -11794402, -622716, 6812205, -15747771, 2019594,
++             7975683, 31123697, -10958981},
++            {30069250, -11435332, 30434654, 2958439, 18399564, -976289,
++             12296869, 9204260, -16432438, 9648165},
++        },
++        {
++            {32705432, -1550977, 30705658, 7451065, -11805606, 9631813, 3305266,
++             5248604, -26008332, -11377501},
++            {17219865, 2375039, -31570947, -5575615, -19459679, 9219903, 294711,
++             15298639, 2662509, -16297073},
++            {-1172927, -7558695, -4366770, -4287744, -21346413, -8434326,
++             32087529, -1222777, 32247248, -14389861},
++        },
++        {
++            {14312628, 1221556, 17395390, -8700143, -4945741, -8684635,
++             -28197744, -9637817, -16027623, -13378845},
++            {-1428825, -9678990, -9235681, 6549687, -7383069, -468664, 23046502,
++             9803137, 17597934, 2346211},
++            {18510800, 15337574, 26171504, 981392, -22241552, 7827556,
++             -23491134, -11323352, 3059833, -11782870},
++        },
++        {
++            {10141598, 6082907, 17829293, -1947643, 9830092, 13613136,
++             -25556636, -5544586, -33502212, 3592096},
++            {33114168, -15889352, -26525686, -13343397, 33076705, 8716171,
++             1151462, 1521897, -982665, -6837803},
++            {-32939165, -4255815, 23947181, -324178, -33072974, -12305637,
++             -16637686, 3891704, 26353178, 693168},
++        },
++        {
++            {30374239, 1595580, -16884039, 13186931, 4600344, 406904, 9585294,
++             -400668, 31375464, 14369965},
++            {-14370654, -7772529, 1510301, 6434173, -18784789, -6262728,
++             32732230, -13108839, 17901441, 16011505},
++            {18171223, -11934626, -12500402, 15197122, -11038147, -15230035,
++             -19172240, -16046376, 8764035, 12309598},
++        },
++    },
++    {
++        {
++            {5975908, -5243188, -19459362, -9681747, -11541277, 14015782,
++             -23665757, 1228319, 17544096, -10593782},
++            {5811932, -1715293, 3442887, -2269310, -18367348, -8359541,
++             -18044043, -15410127, -5565381, 12348900},
++            {-31399660, 11407555, 25755363, 6891399, -3256938, 14872274,
++             -24849353, 8141295, -10632534, -585479},
++        },
++        {
++            {-12675304, 694026, -5076145, 13300344, 14015258, -14451394,
++             -9698672, -11329050, 30944593, 1130208},
++            {8247766, -6710942, -26562381, -7709309, -14401939, -14648910,
++             4652152, 2488540, 23550156, -271232},
++            {17294316, -3788438, 7026748, 15626851, 22990044, 113481, 2267737,
++             -5908146, -408818, -137719},
++        },
++        {
++            {16091085, -16253926, 18599252, 7340678, 2137637, -1221657,
++             -3364161, 14550936, 3260525, -7166271},
++            {-4910104, -13332887, 18550887, 10864893, -16459325, -7291596,
++             -23028869, -13204905, -12748722, 2701326},
++            {-8574695, 16099415, 4629974, -16340524, -20786213, -6005432,
++             -10018363, 9276971, 11329923, 1862132},
++        },
++        {
++            {14763076, -15903608, -30918270, 3689867, 3511892, 10313526,
++             -21951088, 12219231, -9037963, -940300},
++            {8894987, -3446094, 6150753, 3013931, 301220, 15693451, -31981216,
++             -2909717, -15438168, 11595570},
++            {15214962, 3537601, -26238722, -14058872, 4418657, -15230761,
++             13947276, 10730794, -13489462, -4363670},
++        },
++        {
++            {-2538306, 7682793, 32759013, 263109, -29984731, -7955452,
++             -22332124, -10188635, 977108, 699994},
++            {-12466472, 4195084, -9211532, 550904, -15565337, 12917920,
++             19118110, -439841, -30534533, -14337913},
++            {31788461, -14507657, 4799989, 7372237, 8808585, -14747943, 9408237,
++             -10051775, 12493932, -5409317},
++        },
++        {
++            {-25680606, 5260744, -19235809, -6284470, -3695942, 16566087,
++             27218280, 2607121, 29375955, 6024730},
++            {842132, -2794693, -4763381, -8722815, 26332018, -12405641,
++             11831880, 6985184, -9940361, 2854096},
++            {-4847262, -7969331, 2516242, -5847713, 9695691, -7221186, 16512645,
++             960770, 12121869, 16648078},
++        },
++        {
++            {-15218652, 14667096, -13336229, 2013717, 30598287, -464137,
++             -31504922, -7882064, 20237806, 2838411},
++            {-19288047, 4453152, 15298546, -16178388, 22115043, -15972604,
++             12544294, -13470457, 1068881, -12499905},
++            {-9558883, -16518835, 33238498, 13506958, 30505848, -1114596,
++             -8486907, -2630053, 12521378, 4845654},
++        },
++        {
++            {-28198521, 10744108, -2958380, 10199664, 7759311, -13088600,
++             3409348, -873400, -6482306, -12885870},
++            {-23561822, 6230156, -20382013, 10655314, -24040585, -11621172,
++             10477734, -1240216, -3113227, 13974498},
++            {12966261, 15550616, -32038948, -1615346, 21025980, -629444,
++             5642325, 7188737, 18895762, 12629579},
++        },
++    },
++    {
++        {
++            {14741879, -14946887, 22177208, -11721237, 1279741, 8058600,
++             11758140, 789443, 32195181, 3895677},
++            {10758205, 15755439, -4509950, 9243698, -4879422, 6879879, -2204575,
++             -3566119, -8982069, 4429647},
++            {-2453894, 15725973, -20436342, -10410672, -5803908, -11040220,
++             -7135870, -11642895, 18047436, -15281743},
++        },
++        {
++            {-25173001, -11307165, 29759956, 11776784, -22262383, -15820455,
++             10993114, -12850837, -17620701, -9408468},
++            {21987233, 700364, -24505048, 14972008, -7774265, -5718395,
++             32155026, 2581431, -29958985, 8773375},
++            {-25568350, 454463, -13211935, 16126715, 25240068, 8594567,
++             20656846, 12017935, -7874389, -13920155},
++        },
++        {
++            {6028182, 6263078, -31011806, -11301710, -818919, 2461772,
++             -31841174, -5468042, -1721788, -2776725},
++            {-12278994, 16624277, 987579, -5922598, 32908203, 1248608, 7719845,
++             -4166698, 28408820, 6816612},
++            {-10358094, -8237829, 19549651, -12169222, 22082623, 16147817,
++             20613181, 13982702, -10339570, 5067943},
++        },
++        {
++            {-30505967, -3821767, 12074681, 13582412, -19877972, 2443951,
++             -19719286, 12746132, 5331210, -10105944},
++            {30528811, 3601899, -1957090, 4619785, -27361822, -15436388,
++             24180793, -12570394, 27679908, -1648928},
++            {9402404, -13957065, 32834043, 10838634, -26580150, -13237195,
++             26653274, -8685565, 22611444, -12715406},
++        },
++        {
++            {22190590, 1118029, 22736441, 15130463, -30460692, -5991321,
++             19189625, -4648942, 4854859, 6622139},
++            {-8310738, -2953450, -8262579, -3388049, -10401731, -271929,
++             13424426, -3567227, 26404409, 13001963},
++            {-31241838, -15415700, -2994250, 8939346, 11562230, -12840670,
++             -26064365, -11621720, -15405155, 11020693},
++        },
++        {
++            {1866042, -7949489, -7898649, -10301010, 12483315, 13477547,
++             3175636, -12424163, 28761762, 1406734},
++            {-448555, -1777666, 13018551, 3194501, -9580420, -11161737,
++             24760585, -4347088, 25577411, -13378680},
++            {-24290378, 4759345, -690653, -1852816, 2066747, 10693769,
++             -29595790, 9884936, -9368926, 4745410},
++        },
++        {
++            {-9141284, 6049714, -19531061, -4341411, -31260798, 9944276,
++             -15462008, -11311852, 10931924, -11931931},
++            {-16561513, 14112680, -8012645, 4817318, -8040464, -11414606,
++             -22853429, 10856641, -20470770, 13434654},
++            {22759489, -10073434, -16766264, -1871422, 13637442, -10168091,
++             1765144, -12654326, 28445307, -5364710},
++        },
++        {
++            {29875063, 12493613, 2795536, -3786330, 1710620, 15181182,
++             -10195717, -8788675, 9074234, 1167180},
++            {-26205683, 11014233, -9842651, -2635485, -26908120, 7532294,
++             -18716888, -9535498, 3843903, 9367684},
++            {-10969595, -6403711, 9591134, 9582310, 11349256, 108879, 16235123,
++             8601684, -139197, 4242895},
++        },
++    },
++    {
++        {
++            {22092954, -13191123, -2042793, -11968512, 32186753, -11517388,
++             -6574341, 2470660, -27417366, 16625501},
++            {-11057722, 3042016, 13770083, -9257922, 584236, -544855, -7770857,
++             2602725, -27351616, 14247413},
++            {6314175, -10264892, -32772502, 15957557, -10157730, 168750,
++             -8618807, 14290061, 27108877, -1180880},
++        },
++        {
++            {-8586597, -7170966, 13241782, 10960156, -32991015, -13794596,
++             33547976, -11058889, -27148451, 981874},
++            {22833440, 9293594, -32649448, -13618667, -9136966, 14756819,
++             -22928859, -13970780, -10479804, -16197962},
++            {-7768587, 3326786, -28111797, 10783824, 19178761, 14905060,
++             22680049, 13906969, -15933690, 3797899},
++        },
++        {
++            {21721356, -4212746, -12206123, 9310182, -3882239, -13653110,
++             23740224, -2709232, 20491983, -8042152},
++            {9209270, -15135055, -13256557, -6167798, -731016, 15289673,
++             25947805, 15286587, 30997318, -6703063},
++            {7392032, 16618386, 23946583, -8039892, -13265164, -1533858,
++             -14197445, -2321576, 17649998, -250080},
++        },
++        {
++            {-9301088, -14193827, 30609526, -3049543, -25175069, -1283752,
++             -15241566, -9525724, -2233253, 7662146},
++            {-17558673, 1763594, -33114336, 15908610, -30040870, -12174295,
++             7335080, -8472199, -3174674, 3440183},
++            {-19889700, -5977008, -24111293, -9688870, 10799743, -16571957,
++             40450, -4431835, 4862400, 1133},
++        },
++        {
++            {-32856209, -7873957, -5422389, 14860950, -16319031, 7956142,
++             7258061, 311861, -30594991, -7379421},
++            {-3773428, -1565936, 28985340, 7499440, 24445838, 9325937, 29727763,
++             16527196, 18278453, 15405622},
++            {-4381906, 8508652, -19898366, -3674424, -5984453, 15149970,
++             -13313598, 843523, -21875062, 13626197},
++        },
++        {
++            {2281448, -13487055, -10915418, -2609910, 1879358, 16164207,
++             -10783882, 3953792, 13340839, 15928663},
++            {31727126, -7179855, -18437503, -8283652, 2875793, -16390330,
++             -25269894, -7014826, -23452306, 5964753},
++            {4100420, -5959452, -17179337, 6017714, -18705837, 12227141,
++             -26684835, 11344144, 2538215, -7570755},
++        },
++        {
++            {-9433605, 6123113, 11159803, -2156608, 30016280, 14966241,
++             -20474983, 1485421, -629256, -15958862},
++            {-26804558, 4260919, 11851389, 9658551, -32017107, 16367492,
++             -20205425, -13191288, 11659922, -11115118},
++            {26180396, 10015009, -30844224, -8581293, 5418197, 9480663, 2231568,
++             -10170080, 33100372, -1306171},
++        },
++        {
++            {15121113, -5201871, -10389905, 15427821, -27509937, -15992507,
++             21670947, 4486675, -5931810, -14466380},
++            {16166486, -9483733, -11104130, 6023908, -31926798, -1364923,
++             2340060, -16254968, -10735770, -10039824},
++            {28042865, -3557089, -12126526, 12259706, -3717498, -6945899,
++             6766453, -8689599, 18036436, 5803270},
++        },
++    },
++    {
++        {
++            {-817581, 6763912, 11803561, 1585585, 10958447, -2671165, 23855391,
++             4598332, -6159431, -14117438},
++            {-31031306, -14256194, 17332029, -2383520, 31312682, -5967183,
++             696309, 50292, -20095739, 11763584},
++            {-594563, -2514283, -32234153, 12643980, 12650761, 14811489, 665117,
++             -12613632, -19773211, -10713562},
++        },
++        {
++            {30464590, -11262872, -4127476, -12734478, 19835327, -7105613,
++             -24396175, 2075773, -17020157, 992471},
++            {18357185, -6994433, 7766382, 16342475, -29324918, 411174, 14578841,
++             8080033, -11574335, -10601610},
++            {19598397, 10334610, 12555054, 2555664, 18821899, -10339780,
++             21873263, 16014234, 26224780, 16452269},
++        },
++        {
++            {-30223925, 5145196, 5944548, 16385966, 3976735, 2009897, -11377804,
++             -7618186, -20533829, 3698650},
++            {14187449, 3448569, -10636236, -10810935, -22663880, -3433596,
++             7268410, -10890444, 27394301, 12015369},
++            {19695761, 16087646, 28032085, 12999827, 6817792, 11427614,
++             20244189, -1312777, -13259127, -3402461},
++        },
++        {
++            {30860103, 12735208, -1888245, -4699734, -16974906, 2256940,
++             -8166013, 12298312, -8550524, -10393462},
++            {-5719826, -11245325, -1910649, 15569035, 26642876, -7587760,
++             -5789354, -15118654, -4976164, 12651793},
++            {-2848395, 9953421, 11531313, -5282879, 26895123, -12697089,
++             -13118820, -16517902, 9768698, -2533218},
++        },
++        {
++            {-24719459, 1894651, -287698, -4704085, 15348719, -8156530,
++             32767513, 12765450, 4940095, 10678226},
++            {18860224, 15980149, -18987240, -1562570, -26233012, -11071856,
++             -7843882, 13944024, -24372348, 16582019},
++            {-15504260, 4970268, -29893044, 4175593, -20993212, -2199756,
++             -11704054, 15444560, -11003761, 7989037},
++        },
++        {
++            {31490452, 5568061, -2412803, 2182383, -32336847, 4531686,
++             -32078269, 6200206, -19686113, -14800171},
++            {-17308668, -15879940, -31522777, -2831, -32887382, 16375549,
++             8680158, -16371713, 28550068, -6857132},
++            {-28126887, -5688091, 16837845, -1820458, -6850681, 12700016,
++             -30039981, 4364038, 1155602, 5988841},
++        },
++        {
++            {21890435, -13272907, -12624011, 12154349, -7831873, 15300496,
++             23148983, -4470481, 24618407, 8283181},
++            {-33136107, -10512751, 9975416, 6841041, -31559793, 16356536,
++             3070187, -7025928, 1466169, 10740210},
++            {-1509399, -15488185, -13503385, -10655916, 32799044, 909394,
++             -13938903, -5779719, -32164649, -15327040},
++        },
++        {
++            {3960823, -14267803, -28026090, -15918051, -19404858, 13146868,
++             15567327, 951507, -3260321, -573935},
++            {24740841, 5052253, -30094131, 8961361, 25877428, 6165135,
++             -24368180, 14397372, -7380369, -6144105},
++            {-28888365, 3510803, -28103278, -1158478, -11238128, -10631454,
++             -15441463, -14453128, -1625486, -6494814},
++        },
++    },
++    {
++        {
++            {793299, -9230478, 8836302, -6235707, -27360908, -2369593, 33152843,
++             -4885251, -9906200, -621852},
++            {5666233, 525582, 20782575, -8038419, -24538499, 14657740, 16099374,
++             1468826, -6171428, -15186581},
++            {-4859255, -3779343, -2917758, -6748019, 7778750, 11688288,
++             -30404353, -9871238, -1558923, -9863646},
++        },
++        {
++            {10896332, -7719704, 824275, 472601, -19460308, 3009587, 25248958,
++             14783338, -30581476, -15757844},
++            {10566929, 12612572, -31944212, 11118703, -12633376, 12362879,
++             21752402, 8822496, 24003793, 14264025},
++            {27713862, -7355973, -11008240, 9227530, 27050101, 2504721,
++             23886875, -13117525, 13958495, -5732453},
++        },
++        {
++            {-23481610, 4867226, -27247128, 3900521, 29838369, -8212291,
++             -31889399, -10041781, 7340521, -15410068},
++            {4646514, -8011124, -22766023, -11532654, 23184553, 8566613,
++             31366726, -1381061, -15066784, -10375192},
++            {-17270517, 12723032, -16993061, 14878794, 21619651, -6197576,
++             27584817, 3093888, -8843694, 3849921},
++        },
++        {
++            {-9064912, 2103172, 25561640, -15125738, -5239824, 9582958,
++             32477045, -9017955, 5002294, -15550259},
++            {-12057553, -11177906, 21115585, -13365155, 8808712, -12030708,
++             16489530, 13378448, -25845716, 12741426},
++            {-5946367, 10645103, -30911586, 15390284, -3286982, -7118677,
++             24306472, 15852464, 28834118, -7646072},
++        },
++        {
++            {-17335748, -9107057, -24531279, 9434953, -8472084, -583362,
++             -13090771, 455841, 20461858, 5491305},
++            {13669248, -16095482, -12481974, -10203039, -14569770, -11893198,
++             -24995986, 11293807, -28588204, -9421832},
++            {28497928, 6272777, -33022994, 14470570, 8906179, -1225630,
++             18504674, -14165166, 29867745, -8795943},
++        },
++        {
++            {-16207023, 13517196, -27799630, -13697798, 24009064, -6373891,
++             -6367600, -13175392, 22853429, -4012011},
++            {24191378, 16712145, -13931797, 15217831, 14542237, 1646131,
++             18603514, -11037887, 12876623, -2112447},
++            {17902668, 4518229, -411702, -2829247, 26878217, 5258055, -12860753,
++             608397, 16031844, 3723494},
++        },
++        {
++            {-28632773, 12763728, -20446446, 7577504, 33001348, -13017745,
++             17558842, -7872890, 23896954, -4314245},
++            {-20005381, -12011952, 31520464, 605201, 2543521, 5991821, -2945064,
++             7229064, -9919646, -8826859},
++            {28816045, 298879, -28165016, -15920938, 19000928, -1665890,
++             -12680833, -2949325, -18051778, -2082915},
++        },
++        {
++            {16000882, -344896, 3493092, -11447198, -29504595, -13159789,
++             12577740, 16041268, -19715240, 7847707},
++            {10151868, 10572098, 27312476, 7922682, 14825339, 4723128,
++             -32855931, -6519018, -10020567, 3852848},
++            {-11430470, 15697596, -21121557, -4420647, 5386314, 15063598,
++             16514493, -15932110, 29330899, -15076224},
++        },
++    },
++    {
++        {
++            {-25499735, -4378794, -15222908, -6901211, 16615731, 2051784,
++             3303702, 15490, -27548796, 12314391},
++            {15683520, -6003043, 18109120, -9980648, 15337968, -5997823,
++             -16717435, 15921866, 16103996, -3731215},
++            {-23169824, -10781249, 13588192, -1628807, -3798557, -1074929,
++             -19273607, 5402699, -29815713, -9841101},
++        },
++        {
++            {23190676, 2384583, -32714340, 3462154, -29903655, -1529132,
++             -11266856, 8911517, -25205859, 2739713},
++            {21374101, -3554250, -33524649, 9874411, 15377179, 11831242,
++             -33529904, 6134907, 4931255, 11987849},
++            {-7732, -2978858, -16223486, 7277597, 105524, -322051, -31480539,
++             13861388, -30076310, 10117930},
++        },
++        {
++            {-29501170, -10744872, -26163768, 13051539, -25625564, 5089643,
++             -6325503, 6704079, 12890019, 15728940},
++            {-21972360, -11771379, -951059, -4418840, 14704840, 2695116, 903376,
++             -10428139, 12885167, 8311031},
++            {-17516482, 5352194, 10384213, -13811658, 7506451, 13453191,
++             26423267, 4384730, 1888765, -5435404},
++        },
++        {
++            {-25817338, -3107312, -13494599, -3182506, 30896459, -13921729,
++             -32251644, -12707869, -19464434, -3340243},
++            {-23607977, -2665774, -526091, 4651136, 5765089, 4618330, 6092245,
++             14845197, 17151279, -9854116},
++            {-24830458, -12733720, -15165978, 10367250, -29530908, -265356,
++             22825805, -7087279, -16866484, 16176525},
++        },
++        {
++            {-23583256, 6564961, 20063689, 3798228, -4740178, 7359225, 2006182,
++             -10363426, -28746253, -10197509},
++            {-10626600, -4486402, -13320562, -5125317, 3432136, -6393229,
++             23632037, -1940610, 32808310, 1099883},
++            {15030977, 5768825, -27451236, -2887299, -6427378, -15361371,
++             -15277896, -6809350, 2051441, -15225865},
++        },
++        {
++            {-3362323, -7239372, 7517890, 9824992, 23555850, 295369, 5148398,
++             -14154188, -22686354, 16633660},
++            {4577086, -16752288, 13249841, -15304328, 19958763, -14537274,
++             18559670, -10759549, 8402478, -9864273},
++            {-28406330, -1051581, -26790155, -907698, -17212414, -11030789,
++             9453451, -14980072, 17983010, 9967138},
++        },
++        {
++            {-25762494, 6524722, 26585488, 9969270, 24709298, 1220360, -1677990,
++             7806337, 17507396, 3651560},
++            {-10420457, -4118111, 14584639, 15971087, -15768321, 8861010,
++             26556809, -5574557, -18553322, -11357135},
++            {2839101, 14284142, 4029895, 3472686, 14402957, 12689363, -26642121,
++             8459447, -5605463, -7621941},
++        },
++        {
++            {-4839289, -3535444, 9744961, 2871048, 25113978, 3187018, -25110813,
++             -849066, 17258084, -7977739},
++            {18164541, -10595176, -17154882, -1542417, 19237078, -9745295,
++             23357533, -15217008, 26908270, 12150756},
++            {-30264870, -7647865, 5112249, -7036672, -1499807, -6974257, 43168,
++             -5537701, -32302074, 16215819},
++        },
++    },
++    {
++        {
++            {-6898905, 9824394, -12304779, -4401089, -31397141, -6276835,
++             32574489, 12532905, -7503072, -8675347},
++            {-27343522, -16515468, -27151524, -10722951, 946346, 16291093,
++             254968, 7168080, 21676107, -1943028},
++            {21260961, -8424752, -16831886, -11920822, -23677961, 3968121,
++             -3651949, -6215466, -3556191, -7913075},
++        },
++        {
++            {16544754, 13250366, -16804428, 15546242, -4583003, 12757258,
++             -2462308, -8680336, -18907032, -9662799},
++            {-2415239, -15577728, 18312303, 4964443, -15272530, -12653564,
++             26820651, 16690659, 25459437, -4564609},
++            {-25144690, 11425020, 28423002, -11020557, -6144921, -15826224,
++             9142795, -2391602, -6432418, -1644817},
++        },
++        {
++            {-23104652, 6253476, 16964147, -3768872, -25113972, -12296437,
++             -27457225, -16344658, 6335692, 7249989},
++            {-30333227, 13979675, 7503222, -12368314, -11956721, -4621693,
++             -30272269, 2682242, 25993170, -12478523},
++            {4364628, 5930691, 32304656, -10044554, -8054781, 15091131,
++             22857016, -10598955, 31820368, 15075278},
++        },
++        {
++            {31879134, -8918693, 17258761, 90626, -8041836, -4917709, 24162788,
++             -9650886, -17970238, 12833045},
++            {19073683, 14851414, -24403169, -11860168, 7625278, 11091125,
++             -19619190, 2074449, -9413939, 14905377},
++            {24483667, -11935567, -2518866, -11547418, -1553130, 15355506,
++             -25282080, 9253129, 27628530, -7555480},
++        },
++        {
++            {17597607, 8340603, 19355617, 552187, 26198470, -3176583, 4593324,
++             -9157582, -14110875, 15297016},
++            {510886, 14337390, -31785257, 16638632, 6328095, 2713355, -20217417,
++             -11864220, 8683221, 2921426},
++            {18606791, 11874196, 27155355, -5281482, -24031742, 6265446,
++             -25178240, -1278924, 4674690, 13890525},
++        },
++        {
++            {13609624, 13069022, -27372361, -13055908, 24360586, 9592974,
++             14977157, 9835105, 4389687, 288396},
++            {9922506, -519394, 13613107, 5883594, -18758345, -434263, -12304062,
++             8317628, 23388070, 16052080},
++            {12720016, 11937594, -31970060, -5028689, 26900120, 8561328,
++             -20155687, -11632979, -14754271, -10812892},
++        },
++        {
++            {15961858, 14150409, 26716931, -665832, -22794328, 13603569,
++             11829573, 7467844, -28822128, 929275},
++            {11038231, -11582396, -27310482, -7316562, -10498527, -16307831,
++             -23479533, -9371869, -21393143, 2465074},
++            {20017163, -4323226, 27915242, 1529148, 12396362, 15675764,
++             13817261, -9658066, 2463391, -4622140},
++        },
++        {
++            {-16358878, -12663911, -12065183, 4996454, -1256422, 1073572,
++             9583558, 12851107, 4003896, 12673717},
++            {-1731589, -15155870, -3262930, 16143082, 19294135, 13385325,
++             14741514, -9103726, 7903886, 2348101},
++            {24536016, -16515207, 12715592, -3862155, 1511293, 10047386,
++             -3842346, -7129159, -28377538, 10048127},
++        },
++    },
++    {
++        {
++            {-12622226, -6204820, 30718825, 2591312, -10617028, 12192840,
++             18873298, -7297090, -32297756, 15221632},
++            {-26478122, -11103864, 11546244, -1852483, 9180880, 7656409,
++             -21343950, 2095755, 29769758, 6593415},
++            {-31994208, -2907461, 4176912, 3264766, 12538965, -868111, 26312345,
++             -6118678, 30958054, 8292160},
++        },
++        {
++            {31429822, -13959116, 29173532, 15632448, 12174511, -2760094,
++             32808831, 3977186, 26143136, -3148876},
++            {22648901, 1402143, -22799984, 13746059, 7936347, 365344, -8668633,
++             -1674433, -3758243, -2304625},
++            {-15491917, 8012313, -2514730, -12702462, -23965846, -10254029,
++             -1612713, -1535569, -16664475, 8194478},
++        },
++        {
++            {27338066, -7507420, -7414224, 10140405, -19026427, -6589889,
++             27277191, 8855376, 28572286, 3005164},
++            {26287124, 4821776, 25476601, -4145903, -3764513, -15788984,
++             -18008582, 1182479, -26094821, -13079595},
++            {-7171154, 3178080, 23970071, 6201893, -17195577, -4489192,
++             -21876275, -13982627, 32208683, -1198248},
++        },
++        {
++            {-16657702, 2817643, -10286362, 14811298, 6024667, 13349505,
++             -27315504, -10497842, -27672585, -11539858},
++            {15941029, -9405932, -21367050, 8062055, 31876073, -238629,
++             -15278393, -1444429, 15397331, -4130193},
++            {8934485, -13485467, -23286397, -13423241, -32446090, 14047986,
++             31170398, -1441021, -27505566, 15087184},
++        },
++        {
++            {-18357243, -2156491, 24524913, -16677868, 15520427, -6360776,
++             -15502406, 11461896, 16788528, -5868942},
++            {-1947386, 16013773, 21750665, 3714552, -17401782, -16055433,
++             -3770287, -10323320, 31322514, -11615635},
++            {21426655, -5650218, -13648287, -5347537, -28812189, -4920970,
++             -18275391, -14621414, 13040862, -12112948},
++        },
++        {
++            {11293895, 12478086, -27136401, 15083750, -29307421, 14748872,
++             14555558, -13417103, 1613711, 4896935},
++            {-25894883, 15323294, -8489791, -8057900, 25967126, -13425460,
++             2825960, -4897045, -23971776, -11267415},
++            {-15924766, -5229880, -17443532, 6410664, 3622847, 10243618,
++             20615400, 12405433, -23753030, -8436416},
++        },
++        {
++            {-7091295, 12556208, -20191352, 9025187, -17072479, 4333801,
++             4378436, 2432030, 23097949, -566018},
++            {4565804, -16025654, 20084412, -7842817, 1724999, 189254, 24767264,
++             10103221, -18512313, 2424778},
++            {366633, -11976806, 8173090, -6890119, 30788634, 5745705, -7168678,
++             1344109, -3642553, 12412659},
++        },
++        {
++            {-24001791, 7690286, 14929416, -168257, -32210835, -13412986,
++             24162697, -15326504, -3141501, 11179385},
++            {18289522, -14724954, 8056945, 16430056, -21729724, 7842514,
++             -6001441, -1486897, -18684645, -11443503},
++            {476239, 6601091, -6152790, -9723375, 17503545, -4863900, 27672959,
++             13403813, 11052904, 5219329},
++        },
++    },
++    {
++        {
++            {20678546, -8375738, -32671898, 8849123, -5009758, 14574752,
++             31186971, -3973730, 9014762, -8579056},
++            {-13644050, -10350239, -15962508, 5075808, -1514661, -11534600,
++             -33102500, 9160280, 8473550, -3256838},
++            {24900749, 14435722, 17209120, -15292541, -22592275, 9878983,
++             -7689309, -16335821, -24568481, 11788948},
++        },
++        {
++            {-3118155, -11395194, -13802089, 14797441, 9652448, -6845904,
++             -20037437, 10410733, -24568470, -1458691},
++            {-15659161, 16736706, -22467150, 10215878, -9097177, 7563911,
++             11871841, -12505194, -18513325, 8464118},
++            {-23400612, 8348507, -14585951, -861714, -3950205, -6373419,
++             14325289, 8628612, 33313881, -8370517},
++        },
++        {
++            {-20186973, -4967935, 22367356, 5271547, -1097117, -4788838,
++             -24805667, -10236854, -8940735, -5818269},
++            {-6948785, -1795212, -32625683, -16021179, 32635414, -7374245,
++             15989197, -12838188, 28358192, -4253904},
++            {-23561781, -2799059, -32351682, -1661963, -9147719, 10429267,
++             -16637684, 4072016, -5351664, 5596589},
++        },
++        {
++            {-28236598, -3390048, 12312896, 6213178, 3117142, 16078565,
++             29266239, 2557221, 1768301, 15373193},
++            {-7243358, -3246960, -4593467, -7553353, -127927, -912245, -1090902,
++             -4504991, -24660491, 3442910},
++            {-30210571, 5124043, 14181784, 8197961, 18964734, -11939093,
++             22597931, 7176455, -18585478, 13365930},
++        },
++        {
++            {-7877390, -1499958, 8324673, 4690079, 6261860, 890446, 24538107,
++             -8570186, -9689599, -3031667},
++            {25008904, -10771599, -4305031, -9638010, 16265036, 15721635,
++             683793, -11823784, 15723479, -15163481},
++            {-9660625, 12374379, -27006999, -7026148, -7724114, -12314514,
++             11879682, 5400171, 519526, -1235876},
++        },
++        {
++            {22258397, -16332233, -7869817, 14613016, -22520255, -2950923,
++             -20353881, 7315967, 16648397, 7605640},
++            {-8081308, -8464597, -8223311, 9719710, 19259459, -15348212,
++             23994942, -5281555, -9468848, 4763278},
++            {-21699244, 9220969, -15730624, 1084137, -25476107, -2852390,
++             31088447, -7764523, -11356529, 728112},
++        },
++        {
++            {26047220, -11751471, -6900323, -16521798, 24092068, 9158119,
++             -4273545, -12555558, -29365436, -5498272},
++            {17510331, -322857, 5854289, 8403524, 17133918, -3112612, -28111007,
++             12327945, 10750447, 10014012},
++            {-10312768, 3936952, 9156313, -8897683, 16498692, -994647,
++             -27481051, -666732, 3424691, 7540221},
++        },
++        {
++            {30322361, -6964110, 11361005, -4143317, 7433304, 4989748, -7071422,
++             -16317219, -9244265, 15258046},
++            {13054562, -2779497, 19155474, 469045, -12482797, 4566042, 5631406,
++             2711395, 1062915, -5136345},
++            {-19240248, -11254599, -29509029, -7499965, -5835763, 13005411,
++             -6066489, 12194497, 32960380, 1459310},
++        },
++    },
++    {
++        {
++            {19852034, 7027924, 23669353, 10020366, 8586503, -6657907, 394197,
++             -6101885, 18638003, -11174937},
++            {31395534, 15098109, 26581030, 8030562, -16527914, -5007134,
++             9012486, -7584354, -6643087, -5442636},
++            {-9192165, -2347377, -1997099, 4529534, 25766844, 607986, -13222,
++             9677543, -32294889, -6456008},
++        },
++        {
++            {-2444496, -149937, 29348902, 8186665, 1873760, 12489863, -30934579,
++             -7839692, -7852844, -8138429},
++            {-15236356, -15433509, 7766470, 746860, 26346930, -10221762,
++             -27333451, 10754588, -9431476, 5203576},
++            {31834314, 14135496, -770007, 5159118, 20917671, -16768096,
++             -7467973, -7337524, 31809243, 7347066},
++        },
++        {
++            {-9606723, -11874240, 20414459, 13033986, 13716524, -11691881,
++             19797970, -12211255, 15192876, -2087490},
++            {-12663563, -2181719, 1168162, -3804809, 26747877, -14138091,
++             10609330, 12694420, 33473243, -13382104},
++            {33184999, 11180355, 15832085, -11385430, -1633671, 225884,
++             15089336, -11023903, -6135662, 14480053},
++        },
++        {
++            {31308717, -5619998, 31030840, -1897099, 15674547, -6582883,
++             5496208, 13685227, 27595050, 8737275},
++            {-20318852, -15150239, 10933843, -16178022, 8335352, -7546022,
++             -31008351, -12610604, 26498114, 66511},
++            {22644454, -8761729, -16671776, 4884562, -3105614, -13559366,
++             30540766, -4286747, -13327787, -7515095},
++        },
++        {
++            {-28017847, 9834845, 18617207, -2681312, -3401956, -13307506,
++             8205540, 13585437, -17127465, 15115439},
++            {23711543, -672915, 31206561, -8362711, 6164647, -9709987,
++             -33535882, -1426096, 8236921, 16492939},
++            {-23910559, -13515526, -26299483, -4503841, 25005590, -7687270,
++             19574902, 10071562, 6708380, -6222424},
++        },
++        {
++            {2101391, -4930054, 19702731, 2367575, -15427167, 1047675, 5301017,
++             9328700, 29955601, -11678310},
++            {3096359, 9271816, -21620864, -15521844, -14847996, -7592937,
++             -25892142, -12635595, -9917575, 6216608},
++            {-32615849, 338663, -25195611, 2510422, -29213566, -13820213,
++             24822830, -6146567, -26767480, 7525079},
++        },
++        {
++            {-23066649, -13985623, 16133487, -7896178, -3389565, 778788,
++             -910336, -2782495, -19386633, 11994101},
++            {21691500, -13624626, -641331, -14367021, 3285881, -3483596,
++             -25064666, 9718258, -7477437, 13381418},
++            {18445390, -4202236, 14979846, 11622458, -1727110, -3582980,
++             23111648, -6375247, 28535282, 15779576},
++        },
++        {
++            {30098053, 3089662, -9234387, 16662135, -21306940, 11308411,
++             -14068454, 12021730, 9955285, -16303356},
++            {9734894, -14576830, -7473633, -9138735, 2060392, 11313496,
++             -18426029, 9924399, 20194861, 13380996},
++            {-26378102, -7965207, -22167821, 15789297, -18055342, -6168792,
++             -1984914, 15707771, 26342023, 10146099},
++        },
++    },
++    {
++        {
++            {-26016874, -219943, 21339191, -41388, 19745256, -2878700,
++             -29637280, 2227040, 21612326, -545728},
++            {-13077387, 1184228, 23562814, -5970442, -20351244, -6348714,
++             25764461, 12243797, -20856566, 11649658},
++            {-10031494, 11262626, 27384172, 2271902, 26947504, -15997771, 39944,
++             6114064, 33514190, 2333242},
++        },
++        {
++            {-21433588, -12421821, 8119782, 7219913, -21830522, -9016134,
++             -6679750, -12670638, 24350578, -13450001},
++            {-4116307, -11271533, -23886186, 4843615, -30088339, 690623,
++             -31536088, -10406836, 8317860, 12352766},
++            {18200138, -14475911, -33087759, -2696619, -23702521, -9102511,
++             -23552096, -2287550, 20712163, 6719373},
++        },
++        {
++            {26656208, 6075253, -7858556, 1886072, -28344043, 4262326, 11117530,
++             -3763210, 26224235, -3297458},
++            {-17168938, -14854097, -3395676, -16369877, -19954045, 14050420,
++             21728352, 9493610, 18620611, -16428628},
++            {-13323321, 13325349, 11432106, 5964811, 18609221, 6062965,
++             -5269471, -9725556, -30701573, -16479657},
++        },
++        {
++            {-23860538, -11233159, 26961357, 1640861, -32413112, -16737940,
++             12248509, -5240639, 13735342, 1934062},
++            {25089769, 6742589, 17081145, -13406266, 21909293, -16067981,
++             -15136294, -3765346, -21277997, 5473616},
++            {31883677, -7961101, 1083432, -11572403, 22828471, 13290673,
++             -7125085, 12469656, 29111212, -5451014},
++        },
++        {
++            {24244947, -15050407, -26262976, 2791540, -14997599, 16666678,
++             24367466, 6388839, -10295587, 452383},
++            {-25640782, -3417841, 5217916, 16224624, 19987036, -4082269,
++             -24236251, -5915248, 15766062, 8407814},
++            {-20406999, 13990231, 15495425, 16395525, 5377168, 15166495,
++             -8917023, -4388953, -8067909, 2276718},
++        },
++        {
++            {30157918, 12924066, -17712050, 9245753, 19895028, 3368142,
++             -23827587, 5096219, 22740376, -7303417},
++            {2041139, -14256350, 7783687, 13876377, -25946985, -13352459,
++             24051124, 13742383, -15637599, 13295222},
++            {33338237, -8505733, 12532113, 7977527, 9106186, -1715251,
++             -17720195, -4612972, -4451357, -14669444},
++        },
++        {
++            {-20045281, 5454097, -14346548, 6447146, 28862071, 1883651,
++             -2469266, -4141880, 7770569, 9620597},
++            {23208068, 7979712, 33071466, 8149229, 1758231, -10834995, 30945528,
++             -1694323, -33502340, -14767970},
++            {1439958, -16270480, -1079989, -793782, 4625402, 10647766, -5043801,
++             1220118, 30494170, -11440799},
++        },
++        {
++            {-5037580, -13028295, -2970559, -3061767, 15640974, -6701666,
++             -26739026, 926050, -1684339, -13333647},
++            {13908495, -3549272, 30919928, -6273825, -21521863, 7989039,
++             9021034, 9078865, 3353509, 4033511},
++            {-29663431, -15113610, 32259991, -344482, 24295849, -12912123,
++             23161163, 8839127, 27485041, 7356032},
++        },
++    },
++    {
++        {
++            {9661027, 705443, 11980065, -5370154, -1628543, 14661173, -6346142,
++             2625015, 28431036, -16771834},
++            {-23839233, -8311415, -25945511, 7480958, -17681669, -8354183,
++             -22545972, 14150565, 15970762, 4099461},
++            {29262576, 16756590, 26350592, -8793563, 8529671, -11208050,
++             13617293, -9937143, 11465739, 8317062},
++        },
++        {
++            {-25493081, -6962928, 32500200, -9419051, -23038724, -2302222,
++             14898637, 3848455, 20969334, -5157516},
++            {-20384450, -14347713, -18336405, 13884722, -33039454, 2842114,
++             -21610826, -3649888, 11177095, 14989547},
++            {-24496721, -11716016, 16959896, 2278463, 12066309, 10137771,
++             13515641, 2581286, -28487508, 9930240},
++        },
++        {
++            {-17751622, -2097826, 16544300, -13009300, -15914807, -14949081,
++             18345767, -13403753, 16291481, -5314038},
++            {-33229194, 2553288, 32678213, 9875984, 8534129, 6889387, -9676774,
++             6957617, 4368891, 9788741},
++            {16660756, 7281060, -10830758, 12911820, 20108584, -8101676,
++             -21722536, -8613148, 16250552, -11111103},
++        },
++        {
++            {-19765507, 2390526, -16551031, 14161980, 1905286, 6414907, 4689584,
++             10604807, -30190403, 4782747},
++            {-1354539, 14736941, -7367442, -13292886, 7710542, -14155590,
++             -9981571, 4383045, 22546403, 437323},
++            {31665577, -12180464, -16186830, 1491339, -18368625, 3294682,
++             27343084, 2786261, -30633590, -14097016},
++        },
++        {
++            {-14467279, -683715, -33374107, 7448552, 19294360, 14334329,
++             -19690631, 2355319, -19284671, -6114373},
++            {15121312, -15796162, 6377020, -6031361, -10798111, -12957845,
++             18952177, 15496498, -29380133, 11754228},
++            {-2637277, -13483075, 8488727, -14303896, 12728761, -1622493,
++             7141596, 11724556, 22761615, -10134141},
++        },
++        {
++            {16918416, 11729663, -18083579, 3022987, -31015732, -13339659,
++             -28741185, -12227393, 32851222, 11717399},
++            {11166634, 7338049, -6722523, 4531520, -29468672, -7302055,
++             31474879, 3483633, -1193175, -4030831},
++            {-185635, 9921305, 31456609, -13536438, -12013818, 13348923,
++             33142652, 6546660, -19985279, -3948376},
++        },
++        {
++            {-32460596, 11266712, -11197107, -7899103, 31703694, 3855903,
++             -8537131, -12833048, -30772034, -15486313},
++            {-18006477, 12709068, 3991746, -6479188, -21491523, -10550425,
++             -31135347, -16049879, 10928917, 3011958},
++            {-6957757, -15594337, 31696059, 334240, 29576716, 14796075,
++             -30831056, -12805180, 18008031, 10258577},
++        },
++        {
++            {-22448644, 15655569, 7018479, -4410003, -30314266, -1201591,
++             -1853465, 1367120, 25127874, 6671743},
++            {29701166, -14373934, -10878120, 9279288, -17568, 13127210,
++             21382910, 11042292, 25838796, 4642684},
++            {-20430234, 14955537, -24126347, 8124619, -5369288, -5990470,
++             30468147, -13900640, 18423289, 4177476},
++        },
++    },
++};
++
++static uint8_t negative(signed char b) {
++  uint32_t x = b;
++  x >>= 31; /* 1: yes; 0: no */
++  return x;
++}
++
++static void table_select(ge_precomp *t, int pos, signed char b) {
++  ge_precomp minust;
++  uint8_t bnegative = negative(b);
++  uint8_t babs = b - ((uint8_t)((-bnegative) & b) << 1);
++
++  ge_precomp_0(t);
++  cmov(t, &k25519Precomp[pos][0], equal(babs, 1));
++  cmov(t, &k25519Precomp[pos][1], equal(babs, 2));
++  cmov(t, &k25519Precomp[pos][2], equal(babs, 3));
++  cmov(t, &k25519Precomp[pos][3], equal(babs, 4));
++  cmov(t, &k25519Precomp[pos][4], equal(babs, 5));
++  cmov(t, &k25519Precomp[pos][5], equal(babs, 6));
++  cmov(t, &k25519Precomp[pos][6], equal(babs, 7));
++  cmov(t, &k25519Precomp[pos][7], equal(babs, 8));
++  fe_copy(minust.yplusx, t->yminusx);
++  fe_copy(minust.yminusx, t->yplusx);
++  fe_neg(minust.xy2d, t->xy2d);
++  cmov(t, &minust, bnegative);
++}
++
++/* h = a * B
++ * where a = a[0]+256*a[1]+...+256^31 a[31]
++ * B is the Ed25519 base point (x,4/5) with x positive.
++ *
++ * Preconditions:
++ *   a[31] <= 127 */
++static void ge_scalarmult_base(ge_p3 *h, const uint8_t *a) {
++  signed char e[64];
++  signed char carry;
++  ge_p1p1 r;
++  ge_p2 s;
++  ge_precomp t;
++  int i;
++
++  for (i = 0; i < 32; ++i) {
++    e[2 * i + 0] = (a[i] >> 0) & 15;
++    e[2 * i + 1] = (a[i] >> 4) & 15;
++  }
++  /* each e[i] is between 0 and 15 */
++  /* e[63] is between 0 and 7 */
++
++  carry = 0;
++  for (i = 0; i < 63; ++i) {
++    e[i] += carry;
++    carry = e[i] + 8;
++    carry >>= 4;
++    e[i] -= carry << 4;
++  }
++  e[63] += carry;
++  /* each e[i] is between -8 and 8 */
++
++  ge_p3_0(h);
++  for (i = 1; i < 64; i += 2) {
++    table_select(&t, i / 2, e[i]);
++    ge_madd(&r, h, &t);
++    ge_p1p1_to_p3(h, &r);
++  }
++
++  ge_p3_dbl(&r, h);
++  ge_p1p1_to_p2(&s, &r);
++  ge_p2_dbl(&r, &s);
++  ge_p1p1_to_p2(&s, &r);
++  ge_p2_dbl(&r, &s);
++  ge_p1p1_to_p2(&s, &r);
++  ge_p2_dbl(&r, &s);
++  ge_p1p1_to_p3(h, &r);
++
++  for (i = 0; i < 64; i += 2) {
++    table_select(&t, i / 2, e[i]);
++    ge_madd(&r, h, &t);
++    ge_p1p1_to_p3(h, &r);
++  }
++}
++
++/* Replace (f,g) with (g,f) if b == 1;
++ * replace (f,g) with (f,g) if b == 0.
++ *
++ * Preconditions: b in {0,1}. */
++static void fe_cswap(fe f, fe g, unsigned int b) {
++  size_t i;
++  b = 0-b;
++  for (i = 0; i < 10; i++) {
++    int32_t x = f[i] ^ g[i];
++    x &= b;
++    f[i] ^= x;
++    g[i] ^= x;
++  }
++}
++
++/* h = f * 121666
++ * Can overlap h with f.
++ *
++ * Preconditions:
++ *    |f| bounded by 1.1*2^26,1.1*2^25,1.1*2^26,1.1*2^25,etc.
++ *
++ * Postconditions:
++ *    |h| bounded by 1.1*2^25,1.1*2^24,1.1*2^25,1.1*2^24,etc. */
++static void fe_mul121666(fe h, fe f) {
++  int32_t f0 = f[0];
++  int32_t f1 = f[1];
++  int32_t f2 = f[2];
++  int32_t f3 = f[3];
++  int32_t f4 = f[4];
++  int32_t f5 = f[5];
++  int32_t f6 = f[6];
++  int32_t f7 = f[7];
++  int32_t f8 = f[8];
++  int32_t f9 = f[9];
++  int64_t h0 = f0 * (int64_t) 121666;
++  int64_t h1 = f1 * (int64_t) 121666;
++  int64_t h2 = f2 * (int64_t) 121666;
++  int64_t h3 = f3 * (int64_t) 121666;
++  int64_t h4 = f4 * (int64_t) 121666;
++  int64_t h5 = f5 * (int64_t) 121666;
++  int64_t h6 = f6 * (int64_t) 121666;
++  int64_t h7 = f7 * (int64_t) 121666;
++  int64_t h8 = f8 * (int64_t) 121666;
++  int64_t h9 = f9 * (int64_t) 121666;
++  int64_t carry0;
++  int64_t carry1;
++  int64_t carry2;
++  int64_t carry3;
++  int64_t carry4;
++  int64_t carry5;
++  int64_t carry6;
++  int64_t carry7;
++  int64_t carry8;
++  int64_t carry9;
++
++  carry9 = h9 + (1 << 24); h0 += (carry9 >> 25) * 19; h9 -= carry9 & kTop39Bits;
++  carry1 = h1 + (1 << 24); h2 += carry1 >> 25; h1 -= carry1 & kTop39Bits;
++  carry3 = h3 + (1 << 24); h4 += carry3 >> 25; h3 -= carry3 & kTop39Bits;
++  carry5 = h5 + (1 << 24); h6 += carry5 >> 25; h5 -= carry5 & kTop39Bits;
++  carry7 = h7 + (1 << 24); h8 += carry7 >> 25; h7 -= carry7 & kTop39Bits;
++
++  carry0 = h0 + (1 << 25); h1 += carry0 >> 26; h0 -= carry0 & kTop38Bits;
++  carry2 = h2 + (1 << 25); h3 += carry2 >> 26; h2 -= carry2 & kTop38Bits;
++  carry4 = h4 + (1 << 25); h5 += carry4 >> 26; h4 -= carry4 & kTop38Bits;
++  carry6 = h6 + (1 << 25); h7 += carry6 >> 26; h6 -= carry6 & kTop38Bits;
++  carry8 = h8 + (1 << 25); h9 += carry8 >> 26; h8 -= carry8 & kTop38Bits;
++
++  h[0] = h0;
++  h[1] = h1;
++  h[2] = h2;
++  h[3] = h3;
++  h[4] = h4;
++  h[5] = h5;
++  h[6] = h6;
++  h[7] = h7;
++  h[8] = h8;
++  h[9] = h9;
++}
++
++static void x25519_scalar_mult_generic(uint8_t out[32],
++                                       const uint8_t scalar[32],
++                                       const uint8_t point[32]) {
++  fe x1, x2, z2, x3, z3, tmp0, tmp1;
++  uint8_t e[32];
++  unsigned swap = 0;
++  int pos;
++
++  memcpy(e, scalar, 32);
++  e[0] &= 248;
++  e[31] &= 127;
++  e[31] |= 64;
++  fe_frombytes(x1, point);
++  fe_1(x2);
++  fe_0(z2);
++  fe_copy(x3, x1);
++  fe_1(z3);
++
++  for (pos = 254; pos >= 0; --pos) {
++    unsigned b = 1 & (e[pos / 8] >> (pos & 7));
++    swap ^= b;
++    fe_cswap(x2, x3, swap);
++    fe_cswap(z2, z3, swap);
++    swap = b;
++    fe_sub(tmp0, x3, z3);
++    fe_sub(tmp1, x2, z2);
++    fe_add(x2, x2, z2);
++    fe_add(z2, x3, z3);
++    fe_mul(z3, tmp0, x2);
++    fe_mul(z2, z2, tmp1);
++    fe_sq(tmp0, tmp1);
++    fe_sq(tmp1, x2);
++    fe_add(x3, z3, z2);
++    fe_sub(z2, z3, z2);
++    fe_mul(x2, tmp1, tmp0);
++    fe_sub(tmp1, tmp1, tmp0);
++    fe_sq(z2, z2);
++    fe_mul121666(z3, tmp1);
++    fe_sq(x3, x3);
++    fe_add(tmp0, tmp0, z3);
++    fe_mul(z3, x1, z2);
++    fe_mul(z2, tmp1, tmp0);
++  }
++  fe_cswap(x2, x3, swap);
++  fe_cswap(z2, z3, swap);
++
++  fe_invert(z2, z2);
++  fe_mul(x2, x2, z2);
++  fe_tobytes(out, x2);
++}
++
++static void x25519_scalar_mult(uint8_t out[32], const uint8_t scalar[32],
++                               const uint8_t point[32]) {
++  x25519_scalar_mult_generic(out, scalar, point);
++}
++
++int X25519(uint8_t out_shared_key[32], const uint8_t private_key[32],
++           const uint8_t peer_public_value[32]) {
++  static const uint8_t kZeros[32] = {0};
++  x25519_scalar_mult(out_shared_key, private_key, peer_public_value);
++  /* The all-zero output results when the input is a point of small order. */
++  return CRYPTO_memcmp(kZeros, out_shared_key, 32) != 0;
++}
++
++void X25519_public_from_private(uint8_t out_public_value[32],
++                                const uint8_t private_key[32]) {
++  uint8_t e[32];
++  ge_p3 A;
++  fe zplusy, zminusy, zminusy_inv;
++
++  memcpy(e, private_key, 32);
++  e[0] &= 248;
++  e[31] &= 127;
++  e[31] |= 64;
++
++  ge_scalarmult_base(&A, e);
++
++  /* We only need the u-coordinate of the curve25519 point. The map is
++   * u=(y+1)/(1-y). Since y=Y/Z, this gives u=(Z+Y)/(Z-Y). */
++  fe_add(zplusy, A.Z, A.Y);
++  fe_sub(zminusy, A.Z, A.Y);
++  fe_invert(zminusy_inv, zminusy);
++  fe_mul(zplusy, zplusy, zminusy_inv);
++  fe_tobytes(out_public_value, zplusy);
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/ec/ec2_mult.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/ec/ec2_mult.c
+new file mode 100644
+index 0000000..e69de29
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/ec/ec2_oct.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/ec/ec2_oct.c
+new file mode 100644
+index 0000000..e69de29
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/ec/ec2_smpl.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/ec/ec2_smpl.c
+new file mode 100644
+index 0000000..e69de29
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/ec/ec_ameth.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/ec/ec_ameth.c
+new file mode 100644
+index 0000000..fa5bd03
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/ec/ec_ameth.c
+@@ -0,0 +1,881 @@
++/*
++ * Copyright 2006-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include "internal/cryptlib.h"
++#include 
++#include 
++#include 
++#include 
++#include 
++#include "internal/asn1_int.h"
++#include "internal/evp_int.h"
++#include "ec_lcl.h"
++
++#ifndef OPENSSL_NO_CMS
++static int ecdh_cms_decrypt(CMS_RecipientInfo *ri);
++static int ecdh_cms_encrypt(CMS_RecipientInfo *ri);
++#endif
++
++static int eckey_param2type(int *pptype, void **ppval, EC_KEY *ec_key)
++{
++    const EC_GROUP *group;
++    int nid;
++    if (ec_key == NULL || (group = EC_KEY_get0_group(ec_key)) == NULL) {
++        ECerr(EC_F_ECKEY_PARAM2TYPE, EC_R_MISSING_PARAMETERS);
++        return 0;
++    }
++    if (EC_GROUP_get_asn1_flag(group)
++        && (nid = EC_GROUP_get_curve_name(group)))
++        /* we have a 'named curve' => just set the OID */
++    {
++        *ppval = OBJ_nid2obj(nid);
++        *pptype = V_ASN1_OBJECT;
++    } else {                    /* explicit parameters */
++
++        ASN1_STRING *pstr = NULL;
++        pstr = ASN1_STRING_new();
++        if (pstr == NULL)
++            return 0;
++        pstr->length = i2d_ECParameters(ec_key, &pstr->data);
++        if (pstr->length <= 0) {
++            ASN1_STRING_free(pstr);
++            ECerr(EC_F_ECKEY_PARAM2TYPE, ERR_R_EC_LIB);
++            return 0;
++        }
++        *ppval = pstr;
++        *pptype = V_ASN1_SEQUENCE;
++    }
++    return 1;
++}
++
++static int eckey_pub_encode(X509_PUBKEY *pk, const EVP_PKEY *pkey)
++{
++    EC_KEY *ec_key = pkey->pkey.ec;
++    void *pval = NULL;
++    int ptype;
++    unsigned char *penc = NULL, *p;
++    int penclen;
++
++    if (!eckey_param2type(&ptype, &pval, ec_key)) {
++        ECerr(EC_F_ECKEY_PUB_ENCODE, ERR_R_EC_LIB);
++        return 0;
++    }
++    penclen = i2o_ECPublicKey(ec_key, NULL);
++    if (penclen <= 0)
++        goto err;
++    penc = OPENSSL_malloc(penclen);
++    if (penc == NULL)
++        goto err;
++    p = penc;
++    penclen = i2o_ECPublicKey(ec_key, &p);
++    if (penclen <= 0)
++        goto err;
++    if (X509_PUBKEY_set0_param(pk, OBJ_nid2obj(EVP_PKEY_EC),
++                               ptype, pval, penc, penclen))
++        return 1;
++ err:
++    if (ptype == V_ASN1_OBJECT)
++        ASN1_OBJECT_free(pval);
++    else
++        ASN1_STRING_free(pval);
++    OPENSSL_free(penc);
++    return 0;
++}
++
++static EC_KEY *eckey_type2param(int ptype, const void *pval)
++{
++    EC_KEY *eckey = NULL;
++    if (ptype == V_ASN1_SEQUENCE) {
++        const ASN1_STRING *pstr = pval;
++        const unsigned char *pm = NULL;
++        int pmlen;
++        pm = pstr->data;
++        pmlen = pstr->length;
++        if ((eckey = d2i_ECParameters(NULL, &pm, pmlen)) == NULL) {
++            ECerr(EC_F_ECKEY_TYPE2PARAM, EC_R_DECODE_ERROR);
++            goto ecerr;
++        }
++    } else if (ptype == V_ASN1_OBJECT) {
++        const ASN1_OBJECT *poid = pval;
++        EC_GROUP *group;
++
++        /*
++         * type == V_ASN1_OBJECT => the parameters are given by an asn1 OID
++         */
++        if ((eckey = EC_KEY_new()) == NULL) {
++            ECerr(EC_F_ECKEY_TYPE2PARAM, ERR_R_MALLOC_FAILURE);
++            goto ecerr;
++        }
++        group = EC_GROUP_new_by_curve_name(OBJ_obj2nid(poid));
++        if (group == NULL)
++            goto ecerr;
++        EC_GROUP_set_asn1_flag(group, OPENSSL_EC_NAMED_CURVE);
++        if (EC_KEY_set_group(eckey, group) == 0)
++            goto ecerr;
++        EC_GROUP_free(group);
++    } else {
++        ECerr(EC_F_ECKEY_TYPE2PARAM, EC_R_DECODE_ERROR);
++        goto ecerr;
++    }
++
++    return eckey;
++
++ ecerr:
++    EC_KEY_free(eckey);
++    return NULL;
++}
++
++static int eckey_pub_decode(EVP_PKEY *pkey, X509_PUBKEY *pubkey)
++{
++    const unsigned char *p = NULL;
++    const void *pval;
++    int ptype, pklen;
++    EC_KEY *eckey = NULL;
++    X509_ALGOR *palg;
++
++    if (!X509_PUBKEY_get0_param(NULL, &p, &pklen, &palg, pubkey))
++        return 0;
++    X509_ALGOR_get0(NULL, &ptype, &pval, palg);
++
++    eckey = eckey_type2param(ptype, pval);
++
++    if (!eckey) {
++        ECerr(EC_F_ECKEY_PUB_DECODE, ERR_R_EC_LIB);
++        return 0;
++    }
++
++    /* We have parameters now set public key */
++    if (!o2i_ECPublicKey(&eckey, &p, pklen)) {
++        ECerr(EC_F_ECKEY_PUB_DECODE, EC_R_DECODE_ERROR);
++        goto ecerr;
++    }
++
++    EVP_PKEY_assign_EC_KEY(pkey, eckey);
++    return 1;
++
++ ecerr:
++    EC_KEY_free(eckey);
++    return 0;
++}
++
++static int eckey_pub_cmp(const EVP_PKEY *a, const EVP_PKEY *b)
++{
++    int r;
++    const EC_GROUP *group = EC_KEY_get0_group(b->pkey.ec);
++    const EC_POINT *pa = EC_KEY_get0_public_key(a->pkey.ec),
++        *pb = EC_KEY_get0_public_key(b->pkey.ec);
++    if (group == NULL || pa == NULL || pb == NULL)
++        return -2;
++    r = EC_POINT_cmp(group, pa, pb, NULL);
++    if (r == 0)
++        return 1;
++    if (r == 1)
++        return 0;
++    return -2;
++}
++
++static int eckey_priv_decode(EVP_PKEY *pkey, const PKCS8_PRIV_KEY_INFO *p8)
++{
++    const unsigned char *p = NULL;
++    const void *pval;
++    int ptype, pklen;
++    EC_KEY *eckey = NULL;
++    const X509_ALGOR *palg;
++
++    if (!PKCS8_pkey_get0(NULL, &p, &pklen, &palg, p8))
++        return 0;
++    X509_ALGOR_get0(NULL, &ptype, &pval, palg);
++
++    eckey = eckey_type2param(ptype, pval);
++
++    if (!eckey)
++        goto ecliberr;
++
++    /* We have parameters now set private key */
++    if (!d2i_ECPrivateKey(&eckey, &p, pklen)) {
++        ECerr(EC_F_ECKEY_PRIV_DECODE, EC_R_DECODE_ERROR);
++        goto ecerr;
++    }
++
++    EVP_PKEY_assign_EC_KEY(pkey, eckey);
++    return 1;
++
++ ecliberr:
++    ECerr(EC_F_ECKEY_PRIV_DECODE, ERR_R_EC_LIB);
++ ecerr:
++    EC_KEY_free(eckey);
++    return 0;
++}
++
++static int eckey_priv_encode(PKCS8_PRIV_KEY_INFO *p8, const EVP_PKEY *pkey)
++{
++    EC_KEY ec_key = *(pkey->pkey.ec);
++    unsigned char *ep, *p;
++    int eplen, ptype;
++    void *pval;
++    unsigned int old_flags;
++
++    if (!eckey_param2type(&ptype, &pval, &ec_key)) {
++        ECerr(EC_F_ECKEY_PRIV_ENCODE, EC_R_DECODE_ERROR);
++        return 0;
++    }
++
++    /* set the private key */
++
++    /*
++     * do not include the parameters in the SEC1 private key see PKCS#11
++     * 12.11
++     */
++    old_flags = EC_KEY_get_enc_flags(&ec_key);
++    EC_KEY_set_enc_flags(&ec_key, old_flags | EC_PKEY_NO_PARAMETERS);
++
++    eplen = i2d_ECPrivateKey(&ec_key, NULL);
++    if (!eplen) {
++        ECerr(EC_F_ECKEY_PRIV_ENCODE, ERR_R_EC_LIB);
++        return 0;
++    }
++    ep = OPENSSL_malloc(eplen);
++    if (ep == NULL) {
++        ECerr(EC_F_ECKEY_PRIV_ENCODE, ERR_R_MALLOC_FAILURE);
++        return 0;
++    }
++    p = ep;
++    if (!i2d_ECPrivateKey(&ec_key, &p)) {
++        OPENSSL_free(ep);
++        ECerr(EC_F_ECKEY_PRIV_ENCODE, ERR_R_EC_LIB);
++        return 0;
++    }
++
++    if (!PKCS8_pkey_set0(p8, OBJ_nid2obj(NID_X9_62_id_ecPublicKey), 0,
++                         ptype, pval, ep, eplen)) {
++        OPENSSL_free(ep);
++        return 0;
++    }
++
++    return 1;
++}
++
++static int int_ec_size(const EVP_PKEY *pkey)
++{
++    return ECDSA_size(pkey->pkey.ec);
++}
++
++static int ec_bits(const EVP_PKEY *pkey)
++{
++    return EC_GROUP_order_bits(EC_KEY_get0_group(pkey->pkey.ec));
++}
++
++static int ec_security_bits(const EVP_PKEY *pkey)
++{
++    int ecbits = ec_bits(pkey);
++    if (ecbits >= 512)
++        return 256;
++    if (ecbits >= 384)
++        return 192;
++    if (ecbits >= 256)
++        return 128;
++    if (ecbits >= 224)
++        return 112;
++    if (ecbits >= 160)
++        return 80;
++    return ecbits / 2;
++}
++
++static int ec_missing_parameters(const EVP_PKEY *pkey)
++{
++    if (pkey->pkey.ec == NULL || EC_KEY_get0_group(pkey->pkey.ec) == NULL)
++        return 1;
++    return 0;
++}
++
++static int ec_copy_parameters(EVP_PKEY *to, const EVP_PKEY *from)
++{
++    EC_GROUP *group = EC_GROUP_dup(EC_KEY_get0_group(from->pkey.ec));
++    if (group == NULL)
++        return 0;
++    if (to->pkey.ec == NULL) {
++        to->pkey.ec = EC_KEY_new();
++        if (to->pkey.ec == NULL)
++            return 0;
++    }
++    if (EC_KEY_set_group(to->pkey.ec, group) == 0)
++        return 0;
++    EC_GROUP_free(group);
++    return 1;
++}
++
++static int ec_cmp_parameters(const EVP_PKEY *a, const EVP_PKEY *b)
++{
++    const EC_GROUP *group_a = EC_KEY_get0_group(a->pkey.ec),
++        *group_b = EC_KEY_get0_group(b->pkey.ec);
++    if (group_a == NULL || group_b == NULL)
++        return -2;
++    if (EC_GROUP_cmp(group_a, group_b, NULL))
++        return 0;
++    else
++        return 1;
++}
++
++static void int_ec_free(EVP_PKEY *pkey)
++{
++    EC_KEY_free(pkey->pkey.ec);
++}
++
++typedef enum {
++    EC_KEY_PRINT_PRIVATE,
++    EC_KEY_PRINT_PUBLIC,
++    EC_KEY_PRINT_PARAM
++} ec_print_t;
++
++static int do_EC_KEY_print(BIO *bp, const EC_KEY *x, int off, ec_print_t ktype)
++{
++    const char *ecstr;
++    unsigned char *priv = NULL, *pub = NULL;
++    size_t privlen = 0, publen = 0;
++    int ret = 0;
++    const EC_GROUP *group;
++
++    if (x == NULL || (group = EC_KEY_get0_group(x)) == NULL) {
++        ECerr(EC_F_DO_EC_KEY_PRINT, ERR_R_PASSED_NULL_PARAMETER);
++        return 0;
++    }
++
++    if (ktype != EC_KEY_PRINT_PARAM && EC_KEY_get0_public_key(x) != NULL) {
++        publen = EC_KEY_key2buf(x, EC_KEY_get_conv_form(x), &pub, NULL);
++        if (publen == 0)
++            goto err;
++    }
++
++    if (ktype == EC_KEY_PRINT_PRIVATE && EC_KEY_get0_private_key(x) != NULL) {
++        privlen = EC_KEY_priv2buf(x, &priv);
++        if (privlen == 0)
++            goto err;
++    }
++
++    if (ktype == EC_KEY_PRINT_PRIVATE)
++        ecstr = "Private-Key";
++    else if (ktype == EC_KEY_PRINT_PUBLIC)
++        ecstr = "Public-Key";
++    else
++        ecstr = "ECDSA-Parameters";
++
++    if (!BIO_indent(bp, off, 128))
++        goto err;
++    if (BIO_printf(bp, "%s: (%d bit)\n", ecstr,
++                   EC_GROUP_order_bits(group)) <= 0)
++        goto err;
++
++    if (privlen != 0) {
++        if (BIO_printf(bp, "%*spriv:\n", off, "") <= 0)
++            goto err;
++        if (ASN1_buf_print(bp, priv, privlen, off + 4) == 0)
++            goto err;
++    }
++
++    if (publen != 0) {
++        if (BIO_printf(bp, "%*spub:\n", off, "") <= 0)
++            goto err;
++        if (ASN1_buf_print(bp, pub, publen, off + 4) == 0)
++            goto err;
++    }
++
++    if (!ECPKParameters_print(bp, group, off))
++        goto err;
++    ret = 1;
++ err:
++    if (!ret)
++        ECerr(EC_F_DO_EC_KEY_PRINT, ERR_R_EC_LIB);
++    OPENSSL_clear_free(priv, privlen);
++    OPENSSL_free(pub);
++    return ret;
++}
++
++static int eckey_param_decode(EVP_PKEY *pkey,
++                              const unsigned char **pder, int derlen)
++{
++    EC_KEY *eckey;
++
++    if ((eckey = d2i_ECParameters(NULL, pder, derlen)) == NULL) {
++        ECerr(EC_F_ECKEY_PARAM_DECODE, ERR_R_EC_LIB);
++        return 0;
++    }
++    EVP_PKEY_assign_EC_KEY(pkey, eckey);
++    return 1;
++}
++
++static int eckey_param_encode(const EVP_PKEY *pkey, unsigned char **pder)
++{
++    return i2d_ECParameters(pkey->pkey.ec, pder);
++}
++
++static int eckey_param_print(BIO *bp, const EVP_PKEY *pkey, int indent,
++                             ASN1_PCTX *ctx)
++{
++    return do_EC_KEY_print(bp, pkey->pkey.ec, indent, EC_KEY_PRINT_PARAM);
++}
++
++static int eckey_pub_print(BIO *bp, const EVP_PKEY *pkey, int indent,
++                           ASN1_PCTX *ctx)
++{
++    return do_EC_KEY_print(bp, pkey->pkey.ec, indent, EC_KEY_PRINT_PUBLIC);
++}
++
++static int eckey_priv_print(BIO *bp, const EVP_PKEY *pkey, int indent,
++                            ASN1_PCTX *ctx)
++{
++    return do_EC_KEY_print(bp, pkey->pkey.ec, indent, EC_KEY_PRINT_PRIVATE);
++}
++
++static int old_ec_priv_decode(EVP_PKEY *pkey,
++                              const unsigned char **pder, int derlen)
++{
++    EC_KEY *ec;
++
++    if ((ec = d2i_ECPrivateKey(NULL, pder, derlen)) == NULL) {
++        ECerr(EC_F_OLD_EC_PRIV_DECODE, EC_R_DECODE_ERROR);
++        return 0;
++    }
++    EVP_PKEY_assign_EC_KEY(pkey, ec);
++    return 1;
++}
++
++static int old_ec_priv_encode(const EVP_PKEY *pkey, unsigned char **pder)
++{
++    return i2d_ECPrivateKey(pkey->pkey.ec, pder);
++}
++
++static int ec_pkey_ctrl(EVP_PKEY *pkey, int op, long arg1, void *arg2)
++{
++    switch (op) {
++    case ASN1_PKEY_CTRL_PKCS7_SIGN:
++        if (arg1 == 0) {
++            int snid, hnid;
++            X509_ALGOR *alg1, *alg2;
++            PKCS7_SIGNER_INFO_get0_algs(arg2, NULL, &alg1, &alg2);
++            if (alg1 == NULL || alg1->algorithm == NULL)
++                return -1;
++            hnid = OBJ_obj2nid(alg1->algorithm);
++            if (hnid == NID_undef)
++                return -1;
++            if (!OBJ_find_sigid_by_algs(&snid, hnid, EVP_PKEY_id(pkey)))
++                return -1;
++            X509_ALGOR_set0(alg2, OBJ_nid2obj(snid), V_ASN1_UNDEF, 0);
++        }
++        return 1;
++#ifndef OPENSSL_NO_CMS
++    case ASN1_PKEY_CTRL_CMS_SIGN:
++        if (arg1 == 0) {
++            int snid, hnid;
++            X509_ALGOR *alg1, *alg2;
++            CMS_SignerInfo_get0_algs(arg2, NULL, NULL, &alg1, &alg2);
++            if (alg1 == NULL || alg1->algorithm == NULL)
++                return -1;
++            hnid = OBJ_obj2nid(alg1->algorithm);
++            if (hnid == NID_undef)
++                return -1;
++            if (!OBJ_find_sigid_by_algs(&snid, hnid, EVP_PKEY_id(pkey)))
++                return -1;
++            X509_ALGOR_set0(alg2, OBJ_nid2obj(snid), V_ASN1_UNDEF, 0);
++        }
++        return 1;
++
++    case ASN1_PKEY_CTRL_CMS_ENVELOPE:
++        if (arg1 == 1)
++            return ecdh_cms_decrypt(arg2);
++        else if (arg1 == 0)
++            return ecdh_cms_encrypt(arg2);
++        return -2;
++
++    case ASN1_PKEY_CTRL_CMS_RI_TYPE:
++        *(int *)arg2 = CMS_RECIPINFO_AGREE;
++        return 1;
++#endif
++
++    case ASN1_PKEY_CTRL_DEFAULT_MD_NID:
++        *(int *)arg2 = NID_sha256;
++        return 2;
++
++    case ASN1_PKEY_CTRL_SET1_TLS_ENCPT:
++        return EC_KEY_oct2key(EVP_PKEY_get0_EC_KEY(pkey), arg2, arg1, NULL);
++
++    case ASN1_PKEY_CTRL_GET1_TLS_ENCPT:
++        return EC_KEY_key2buf(EVP_PKEY_get0_EC_KEY(pkey),
++                              POINT_CONVERSION_UNCOMPRESSED, arg2, NULL);
++
++    default:
++        return -2;
++
++    }
++
++}
++
++const EVP_PKEY_ASN1_METHOD eckey_asn1_meth = {
++    EVP_PKEY_EC,
++    EVP_PKEY_EC,
++    0,
++    "EC",
++    "OpenSSL EC algorithm",
++
++    eckey_pub_decode,
++    eckey_pub_encode,
++    eckey_pub_cmp,
++    eckey_pub_print,
++
++    eckey_priv_decode,
++    eckey_priv_encode,
++    eckey_priv_print,
++
++    int_ec_size,
++    ec_bits,
++    ec_security_bits,
++
++    eckey_param_decode,
++    eckey_param_encode,
++    ec_missing_parameters,
++    ec_copy_parameters,
++    ec_cmp_parameters,
++    eckey_param_print,
++    0,
++
++    int_ec_free,
++    ec_pkey_ctrl,
++    old_ec_priv_decode,
++    old_ec_priv_encode
++};
++
++int EC_KEY_print(BIO *bp, const EC_KEY *x, int off)
++{
++    int private = EC_KEY_get0_private_key(x) != NULL;
++
++    return do_EC_KEY_print(bp, x, off,
++                private ? EC_KEY_PRINT_PRIVATE : EC_KEY_PRINT_PUBLIC);
++}
++
++int ECParameters_print(BIO *bp, const EC_KEY *x)
++{
++    return do_EC_KEY_print(bp, x, 4, EC_KEY_PRINT_PARAM);
++}
++
++#ifndef OPENSSL_NO_CMS
++
++static int ecdh_cms_set_peerkey(EVP_PKEY_CTX *pctx,
++                                X509_ALGOR *alg, ASN1_BIT_STRING *pubkey)
++{
++    const ASN1_OBJECT *aoid;
++    int atype;
++    const void *aval;
++    int rv = 0;
++    EVP_PKEY *pkpeer = NULL;
++    EC_KEY *ecpeer = NULL;
++    const unsigned char *p;
++    int plen;
++    X509_ALGOR_get0(&aoid, &atype, &aval, alg);
++    if (OBJ_obj2nid(aoid) != NID_X9_62_id_ecPublicKey)
++        goto err;
++    /* If absent parameters get group from main key */
++    if (atype == V_ASN1_UNDEF || atype == V_ASN1_NULL) {
++        const EC_GROUP *grp;
++        EVP_PKEY *pk;
++        pk = EVP_PKEY_CTX_get0_pkey(pctx);
++        if (!pk)
++            goto err;
++        grp = EC_KEY_get0_group(pk->pkey.ec);
++        ecpeer = EC_KEY_new();
++        if (ecpeer == NULL)
++            goto err;
++        if (!EC_KEY_set_group(ecpeer, grp))
++            goto err;
++    } else {
++        ecpeer = eckey_type2param(atype, aval);
++        if (!ecpeer)
++            goto err;
++    }
++    /* We have parameters now set public key */
++    plen = ASN1_STRING_length(pubkey);
++    p = ASN1_STRING_get0_data(pubkey);
++    if (!p || !plen)
++        goto err;
++    if (!o2i_ECPublicKey(&ecpeer, &p, plen))
++        goto err;
++    pkpeer = EVP_PKEY_new();
++    if (pkpeer == NULL)
++        goto err;
++    EVP_PKEY_set1_EC_KEY(pkpeer, ecpeer);
++    if (EVP_PKEY_derive_set_peer(pctx, pkpeer) > 0)
++        rv = 1;
++ err:
++    EC_KEY_free(ecpeer);
++    EVP_PKEY_free(pkpeer);
++    return rv;
++}
++
++/* Set KDF parameters based on KDF NID */
++static int ecdh_cms_set_kdf_param(EVP_PKEY_CTX *pctx, int eckdf_nid)
++{
++    int kdf_nid, kdfmd_nid, cofactor;
++    const EVP_MD *kdf_md;
++    if (eckdf_nid == NID_undef)
++        return 0;
++
++    /* Lookup KDF type, cofactor mode and digest */
++    if (!OBJ_find_sigid_algs(eckdf_nid, &kdfmd_nid, &kdf_nid))
++        return 0;
++
++    if (kdf_nid == NID_dh_std_kdf)
++        cofactor = 0;
++    else if (kdf_nid == NID_dh_cofactor_kdf)
++        cofactor = 1;
++    else
++        return 0;
++
++    if (EVP_PKEY_CTX_set_ecdh_cofactor_mode(pctx, cofactor) <= 0)
++        return 0;
++
++    if (EVP_PKEY_CTX_set_ecdh_kdf_type(pctx, EVP_PKEY_ECDH_KDF_X9_62) <= 0)
++        return 0;
++
++    kdf_md = EVP_get_digestbynid(kdfmd_nid);
++    if (!kdf_md)
++        return 0;
++
++    if (EVP_PKEY_CTX_set_ecdh_kdf_md(pctx, kdf_md) <= 0)
++        return 0;
++    return 1;
++}
++
++static int ecdh_cms_set_shared_info(EVP_PKEY_CTX *pctx, CMS_RecipientInfo *ri)
++{
++    int rv = 0;
++
++    X509_ALGOR *alg, *kekalg = NULL;
++    ASN1_OCTET_STRING *ukm;
++    const unsigned char *p;
++    unsigned char *der = NULL;
++    int plen, keylen;
++    const EVP_CIPHER *kekcipher;
++    EVP_CIPHER_CTX *kekctx;
++
++    if (!CMS_RecipientInfo_kari_get0_alg(ri, &alg, &ukm))
++        return 0;
++
++    if (!ecdh_cms_set_kdf_param(pctx, OBJ_obj2nid(alg->algorithm))) {
++        ECerr(EC_F_ECDH_CMS_SET_SHARED_INFO, EC_R_KDF_PARAMETER_ERROR);
++        return 0;
++    }
++
++    if (alg->parameter->type != V_ASN1_SEQUENCE)
++        return 0;
++
++    p = alg->parameter->value.sequence->data;
++    plen = alg->parameter->value.sequence->length;
++    kekalg = d2i_X509_ALGOR(NULL, &p, plen);
++    if (!kekalg)
++        goto err;
++    kekctx = CMS_RecipientInfo_kari_get0_ctx(ri);
++    if (!kekctx)
++        goto err;
++    kekcipher = EVP_get_cipherbyobj(kekalg->algorithm);
++    if (!kekcipher || EVP_CIPHER_mode(kekcipher) != EVP_CIPH_WRAP_MODE)
++        goto err;
++    if (!EVP_EncryptInit_ex(kekctx, kekcipher, NULL, NULL, NULL))
++        goto err;
++    if (EVP_CIPHER_asn1_to_param(kekctx, kekalg->parameter) <= 0)
++        goto err;
++
++    keylen = EVP_CIPHER_CTX_key_length(kekctx);
++    if (EVP_PKEY_CTX_set_ecdh_kdf_outlen(pctx, keylen) <= 0)
++        goto err;
++
++    plen = CMS_SharedInfo_encode(&der, kekalg, ukm, keylen);
++
++    if (!plen)
++        goto err;
++
++    if (EVP_PKEY_CTX_set0_ecdh_kdf_ukm(pctx, der, plen) <= 0)
++        goto err;
++    der = NULL;
++
++    rv = 1;
++ err:
++    X509_ALGOR_free(kekalg);
++    OPENSSL_free(der);
++    return rv;
++}
++
++static int ecdh_cms_decrypt(CMS_RecipientInfo *ri)
++{
++    EVP_PKEY_CTX *pctx;
++    pctx = CMS_RecipientInfo_get0_pkey_ctx(ri);
++    if (!pctx)
++        return 0;
++    /* See if we need to set peer key */
++    if (!EVP_PKEY_CTX_get0_peerkey(pctx)) {
++        X509_ALGOR *alg;
++        ASN1_BIT_STRING *pubkey;
++        if (!CMS_RecipientInfo_kari_get0_orig_id(ri, &alg, &pubkey,
++                                                 NULL, NULL, NULL))
++            return 0;
++        if (!alg || !pubkey)
++            return 0;
++        if (!ecdh_cms_set_peerkey(pctx, alg, pubkey)) {
++            ECerr(EC_F_ECDH_CMS_DECRYPT, EC_R_PEER_KEY_ERROR);
++            return 0;
++        }
++    }
++    /* Set ECDH derivation parameters and initialise unwrap context */
++    if (!ecdh_cms_set_shared_info(pctx, ri)) {
++        ECerr(EC_F_ECDH_CMS_DECRYPT, EC_R_SHARED_INFO_ERROR);
++        return 0;
++    }
++    return 1;
++}
++
++static int ecdh_cms_encrypt(CMS_RecipientInfo *ri)
++{
++    EVP_PKEY_CTX *pctx;
++    EVP_PKEY *pkey;
++    EVP_CIPHER_CTX *ctx;
++    int keylen;
++    X509_ALGOR *talg, *wrap_alg = NULL;
++    const ASN1_OBJECT *aoid;
++    ASN1_BIT_STRING *pubkey;
++    ASN1_STRING *wrap_str;
++    ASN1_OCTET_STRING *ukm;
++    unsigned char *penc = NULL;
++    int penclen;
++    int rv = 0;
++    int ecdh_nid, kdf_type, kdf_nid, wrap_nid;
++    const EVP_MD *kdf_md;
++    pctx = CMS_RecipientInfo_get0_pkey_ctx(ri);
++    if (!pctx)
++        return 0;
++    /* Get ephemeral key */
++    pkey = EVP_PKEY_CTX_get0_pkey(pctx);
++    if (!CMS_RecipientInfo_kari_get0_orig_id(ri, &talg, &pubkey,
++                                             NULL, NULL, NULL))
++        goto err;
++    X509_ALGOR_get0(&aoid, NULL, NULL, talg);
++    /* Is everything uninitialised? */
++    if (aoid == OBJ_nid2obj(NID_undef)) {
++
++        EC_KEY *eckey = pkey->pkey.ec;
++        /* Set the key */
++        unsigned char *p;
++
++        penclen = i2o_ECPublicKey(eckey, NULL);
++        if (penclen <= 0)
++            goto err;
++        penc = OPENSSL_malloc(penclen);
++        if (penc == NULL)
++            goto err;
++        p = penc;
++        penclen = i2o_ECPublicKey(eckey, &p);
++        if (penclen <= 0)
++            goto err;
++        ASN1_STRING_set0(pubkey, penc, penclen);
++        pubkey->flags &= ~(ASN1_STRING_FLAG_BITS_LEFT | 0x07);
++        pubkey->flags |= ASN1_STRING_FLAG_BITS_LEFT;
++
++        penc = NULL;
++        X509_ALGOR_set0(talg, OBJ_nid2obj(NID_X9_62_id_ecPublicKey),
++                        V_ASN1_UNDEF, NULL);
++    }
++
++    /* See if custom parameters set */
++    kdf_type = EVP_PKEY_CTX_get_ecdh_kdf_type(pctx);
++    if (kdf_type <= 0)
++        goto err;
++    if (!EVP_PKEY_CTX_get_ecdh_kdf_md(pctx, &kdf_md))
++        goto err;
++    ecdh_nid = EVP_PKEY_CTX_get_ecdh_cofactor_mode(pctx);
++    if (ecdh_nid < 0)
++        goto err;
++    else if (ecdh_nid == 0)
++        ecdh_nid = NID_dh_std_kdf;
++    else if (ecdh_nid == 1)
++        ecdh_nid = NID_dh_cofactor_kdf;
++
++    if (kdf_type == EVP_PKEY_ECDH_KDF_NONE) {
++        kdf_type = EVP_PKEY_ECDH_KDF_X9_62;
++        if (EVP_PKEY_CTX_set_ecdh_kdf_type(pctx, kdf_type) <= 0)
++            goto err;
++    } else
++        /* Unknown KDF */
++        goto err;
++    if (kdf_md == NULL) {
++        /* Fixme later for better MD */
++        kdf_md = EVP_sha1();
++        if (EVP_PKEY_CTX_set_ecdh_kdf_md(pctx, kdf_md) <= 0)
++            goto err;
++    }
++
++    if (!CMS_RecipientInfo_kari_get0_alg(ri, &talg, &ukm))
++        goto err;
++
++    /* Lookup NID for KDF+cofactor+digest */
++
++    if (!OBJ_find_sigid_by_algs(&kdf_nid, EVP_MD_type(kdf_md), ecdh_nid))
++        goto err;
++    /* Get wrap NID */
++    ctx = CMS_RecipientInfo_kari_get0_ctx(ri);
++    wrap_nid = EVP_CIPHER_CTX_type(ctx);
++    keylen = EVP_CIPHER_CTX_key_length(ctx);
++
++    /* Package wrap algorithm in an AlgorithmIdentifier */
++
++    wrap_alg = X509_ALGOR_new();
++    if (wrap_alg == NULL)
++        goto err;
++    wrap_alg->algorithm = OBJ_nid2obj(wrap_nid);
++    wrap_alg->parameter = ASN1_TYPE_new();
++    if (wrap_alg->parameter == NULL)
++        goto err;
++    if (EVP_CIPHER_param_to_asn1(ctx, wrap_alg->parameter) <= 0)
++        goto err;
++    if (ASN1_TYPE_get(wrap_alg->parameter) == NID_undef) {
++        ASN1_TYPE_free(wrap_alg->parameter);
++        wrap_alg->parameter = NULL;
++    }
++
++    if (EVP_PKEY_CTX_set_ecdh_kdf_outlen(pctx, keylen) <= 0)
++        goto err;
++
++    penclen = CMS_SharedInfo_encode(&penc, wrap_alg, ukm, keylen);
++
++    if (!penclen)
++        goto err;
++
++    if (EVP_PKEY_CTX_set0_ecdh_kdf_ukm(pctx, penc, penclen) <= 0)
++        goto err;
++    penc = NULL;
++
++    /*
++     * Now need to wrap encoding of wrap AlgorithmIdentifier into parameter
++     * of another AlgorithmIdentifier.
++     */
++    penclen = i2d_X509_ALGOR(wrap_alg, &penc);
++    if (!penc || !penclen)
++        goto err;
++    wrap_str = ASN1_STRING_new();
++    if (wrap_str == NULL)
++        goto err;
++    ASN1_STRING_set0(wrap_str, penc, penclen);
++    penc = NULL;
++    X509_ALGOR_set0(talg, OBJ_nid2obj(kdf_nid), V_ASN1_SEQUENCE, wrap_str);
++
++    rv = 1;
++
++ err:
++    OPENSSL_free(penc);
++    X509_ALGOR_free(wrap_alg);
++    return rv;
++}
++
++#endif
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/ec/ec_asn1.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/ec/ec_asn1.c
+new file mode 100644
+index 0000000..4f4d1ed
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/ec/ec_asn1.c
+@@ -0,0 +1,1234 @@
++/*
++ * Copyright 2002-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include "ec_lcl.h"
++#include 
++#include 
++#include 
++
++int EC_GROUP_get_basis_type(const EC_GROUP *group)
++{
++    int i = 0;
++
++    if (EC_METHOD_get_field_type(EC_GROUP_method_of(group)) !=
++        NID_X9_62_characteristic_two_field)
++        /* everything else is currently not supported */
++        return 0;
++
++    while (group->poly[i] != 0)
++        i++;
++
++    if (i == 4)
++        return NID_X9_62_ppBasis;
++    else if (i == 2)
++        return NID_X9_62_tpBasis;
++    else
++        /* everything else is currently not supported */
++        return 0;
++}
++
++#ifndef OPENSSL_NO_EC2M
++int EC_GROUP_get_trinomial_basis(const EC_GROUP *group, unsigned int *k)
++{
++    if (group == NULL)
++        return 0;
++
++    if (EC_METHOD_get_field_type(EC_GROUP_method_of(group)) !=
++        NID_X9_62_characteristic_two_field
++        || !((group->poly[0] != 0) && (group->poly[1] != 0)
++             && (group->poly[2] == 0))) {
++        ECerr(EC_F_EC_GROUP_GET_TRINOMIAL_BASIS,
++              ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
++        return 0;
++    }
++
++    if (k)
++        *k = group->poly[1];
++
++    return 1;
++}
++
++int EC_GROUP_get_pentanomial_basis(const EC_GROUP *group, unsigned int *k1,
++                                   unsigned int *k2, unsigned int *k3)
++{
++    if (group == NULL)
++        return 0;
++
++    if (EC_METHOD_get_field_type(EC_GROUP_method_of(group)) !=
++        NID_X9_62_characteristic_two_field
++        || !((group->poly[0] != 0) && (group->poly[1] != 0)
++             && (group->poly[2] != 0) && (group->poly[3] != 0)
++             && (group->poly[4] == 0))) {
++        ECerr(EC_F_EC_GROUP_GET_PENTANOMIAL_BASIS,
++              ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
++        return 0;
++    }
++
++    if (k1)
++        *k1 = group->poly[3];
++    if (k2)
++        *k2 = group->poly[2];
++    if (k3)
++        *k3 = group->poly[1];
++
++    return 1;
++}
++#endif
++
++/* some structures needed for the asn1 encoding */
++typedef struct x9_62_pentanomial_st {
++    long k1;
++    long k2;
++    long k3;
++} X9_62_PENTANOMIAL;
++
++typedef struct x9_62_characteristic_two_st {
++    long m;
++    ASN1_OBJECT *type;
++    union {
++        char *ptr;
++        /* NID_X9_62_onBasis */
++        ASN1_NULL *onBasis;
++        /* NID_X9_62_tpBasis */
++        ASN1_INTEGER *tpBasis;
++        /* NID_X9_62_ppBasis */
++        X9_62_PENTANOMIAL *ppBasis;
++        /* anything else */
++        ASN1_TYPE *other;
++    } p;
++} X9_62_CHARACTERISTIC_TWO;
++
++typedef struct x9_62_fieldid_st {
++    ASN1_OBJECT *fieldType;
++    union {
++        char *ptr;
++        /* NID_X9_62_prime_field */
++        ASN1_INTEGER *prime;
++        /* NID_X9_62_characteristic_two_field */
++        X9_62_CHARACTERISTIC_TWO *char_two;
++        /* anything else */
++        ASN1_TYPE *other;
++    } p;
++} X9_62_FIELDID;
++
++typedef struct x9_62_curve_st {
++    ASN1_OCTET_STRING *a;
++    ASN1_OCTET_STRING *b;
++    ASN1_BIT_STRING *seed;
++} X9_62_CURVE;
++
++struct ec_parameters_st {
++    long version;
++    X9_62_FIELDID *fieldID;
++    X9_62_CURVE *curve;
++    ASN1_OCTET_STRING *base;
++    ASN1_INTEGER *order;
++    ASN1_INTEGER *cofactor;
++} /* ECPARAMETERS */ ;
++
++struct ecpk_parameters_st {
++    int type;
++    union {
++        ASN1_OBJECT *named_curve;
++        ECPARAMETERS *parameters;
++        ASN1_NULL *implicitlyCA;
++    } value;
++} /* ECPKPARAMETERS */ ;
++
++/* SEC1 ECPrivateKey */
++typedef struct ec_privatekey_st {
++    long version;
++    ASN1_OCTET_STRING *privateKey;
++    ECPKPARAMETERS *parameters;
++    ASN1_BIT_STRING *publicKey;
++} EC_PRIVATEKEY;
++
++/* the OpenSSL ASN.1 definitions */
++ASN1_SEQUENCE(X9_62_PENTANOMIAL) = {
++        ASN1_SIMPLE(X9_62_PENTANOMIAL, k1, LONG),
++        ASN1_SIMPLE(X9_62_PENTANOMIAL, k2, LONG),
++        ASN1_SIMPLE(X9_62_PENTANOMIAL, k3, LONG)
++} static_ASN1_SEQUENCE_END(X9_62_PENTANOMIAL)
++
++DECLARE_ASN1_ALLOC_FUNCTIONS(X9_62_PENTANOMIAL)
++IMPLEMENT_ASN1_ALLOC_FUNCTIONS(X9_62_PENTANOMIAL)
++
++ASN1_ADB_TEMPLATE(char_two_def) = ASN1_SIMPLE(X9_62_CHARACTERISTIC_TWO, p.other, ASN1_ANY);
++
++ASN1_ADB(X9_62_CHARACTERISTIC_TWO) = {
++        ADB_ENTRY(NID_X9_62_onBasis, ASN1_SIMPLE(X9_62_CHARACTERISTIC_TWO, p.onBasis, ASN1_NULL)),
++        ADB_ENTRY(NID_X9_62_tpBasis, ASN1_SIMPLE(X9_62_CHARACTERISTIC_TWO, p.tpBasis, ASN1_INTEGER)),
++        ADB_ENTRY(NID_X9_62_ppBasis, ASN1_SIMPLE(X9_62_CHARACTERISTIC_TWO, p.ppBasis, X9_62_PENTANOMIAL))
++} ASN1_ADB_END(X9_62_CHARACTERISTIC_TWO, 0, type, 0, &char_two_def_tt, NULL);
++
++ASN1_SEQUENCE(X9_62_CHARACTERISTIC_TWO) = {
++        ASN1_SIMPLE(X9_62_CHARACTERISTIC_TWO, m, LONG),
++        ASN1_SIMPLE(X9_62_CHARACTERISTIC_TWO, type, ASN1_OBJECT),
++        ASN1_ADB_OBJECT(X9_62_CHARACTERISTIC_TWO)
++} static_ASN1_SEQUENCE_END(X9_62_CHARACTERISTIC_TWO)
++
++DECLARE_ASN1_ALLOC_FUNCTIONS(X9_62_CHARACTERISTIC_TWO)
++IMPLEMENT_ASN1_ALLOC_FUNCTIONS(X9_62_CHARACTERISTIC_TWO)
++
++ASN1_ADB_TEMPLATE(fieldID_def) = ASN1_SIMPLE(X9_62_FIELDID, p.other, ASN1_ANY);
++
++ASN1_ADB(X9_62_FIELDID) = {
++        ADB_ENTRY(NID_X9_62_prime_field, ASN1_SIMPLE(X9_62_FIELDID, p.prime, ASN1_INTEGER)),
++        ADB_ENTRY(NID_X9_62_characteristic_two_field, ASN1_SIMPLE(X9_62_FIELDID, p.char_two, X9_62_CHARACTERISTIC_TWO))
++} ASN1_ADB_END(X9_62_FIELDID, 0, fieldType, 0, &fieldID_def_tt, NULL);
++
++ASN1_SEQUENCE(X9_62_FIELDID) = {
++        ASN1_SIMPLE(X9_62_FIELDID, fieldType, ASN1_OBJECT),
++        ASN1_ADB_OBJECT(X9_62_FIELDID)
++} static_ASN1_SEQUENCE_END(X9_62_FIELDID)
++
++ASN1_SEQUENCE(X9_62_CURVE) = {
++        ASN1_SIMPLE(X9_62_CURVE, a, ASN1_OCTET_STRING),
++        ASN1_SIMPLE(X9_62_CURVE, b, ASN1_OCTET_STRING),
++        ASN1_OPT(X9_62_CURVE, seed, ASN1_BIT_STRING)
++} static_ASN1_SEQUENCE_END(X9_62_CURVE)
++
++ASN1_SEQUENCE(ECPARAMETERS) = {
++        ASN1_SIMPLE(ECPARAMETERS, version, LONG),
++        ASN1_SIMPLE(ECPARAMETERS, fieldID, X9_62_FIELDID),
++        ASN1_SIMPLE(ECPARAMETERS, curve, X9_62_CURVE),
++        ASN1_SIMPLE(ECPARAMETERS, base, ASN1_OCTET_STRING),
++        ASN1_SIMPLE(ECPARAMETERS, order, ASN1_INTEGER),
++        ASN1_OPT(ECPARAMETERS, cofactor, ASN1_INTEGER)
++} ASN1_SEQUENCE_END(ECPARAMETERS)
++
++DECLARE_ASN1_ALLOC_FUNCTIONS(ECPARAMETERS)
++IMPLEMENT_ASN1_ALLOC_FUNCTIONS(ECPARAMETERS)
++
++ASN1_CHOICE(ECPKPARAMETERS) = {
++        ASN1_SIMPLE(ECPKPARAMETERS, value.named_curve, ASN1_OBJECT),
++        ASN1_SIMPLE(ECPKPARAMETERS, value.parameters, ECPARAMETERS),
++        ASN1_SIMPLE(ECPKPARAMETERS, value.implicitlyCA, ASN1_NULL)
++} ASN1_CHOICE_END(ECPKPARAMETERS)
++
++DECLARE_ASN1_FUNCTIONS_const(ECPKPARAMETERS)
++DECLARE_ASN1_ENCODE_FUNCTIONS_const(ECPKPARAMETERS, ECPKPARAMETERS)
++IMPLEMENT_ASN1_FUNCTIONS_const(ECPKPARAMETERS)
++
++ASN1_SEQUENCE(EC_PRIVATEKEY) = {
++        ASN1_SIMPLE(EC_PRIVATEKEY, version, LONG),
++        ASN1_SIMPLE(EC_PRIVATEKEY, privateKey, ASN1_OCTET_STRING),
++        ASN1_EXP_OPT(EC_PRIVATEKEY, parameters, ECPKPARAMETERS, 0),
++        ASN1_EXP_OPT(EC_PRIVATEKEY, publicKey, ASN1_BIT_STRING, 1)
++} static_ASN1_SEQUENCE_END(EC_PRIVATEKEY)
++
++DECLARE_ASN1_FUNCTIONS_const(EC_PRIVATEKEY)
++DECLARE_ASN1_ENCODE_FUNCTIONS_const(EC_PRIVATEKEY, EC_PRIVATEKEY)
++IMPLEMENT_ASN1_FUNCTIONS_const(EC_PRIVATEKEY)
++
++/* some declarations of internal function */
++
++/* ec_asn1_group2field() sets the values in a X9_62_FIELDID object */
++static int ec_asn1_group2fieldid(const EC_GROUP *, X9_62_FIELDID *);
++/* ec_asn1_group2curve() sets the values in a X9_62_CURVE object */
++static int ec_asn1_group2curve(const EC_GROUP *, X9_62_CURVE *);
++
++/* the function definitions */
++
++static int ec_asn1_group2fieldid(const EC_GROUP *group, X9_62_FIELDID *field)
++{
++    int ok = 0, nid;
++    BIGNUM *tmp = NULL;
++
++    if (group == NULL || field == NULL)
++        return 0;
++
++    /* clear the old values (if necessary) */
++    ASN1_OBJECT_free(field->fieldType);
++    ASN1_TYPE_free(field->p.other);
++
++    nid = EC_METHOD_get_field_type(EC_GROUP_method_of(group));
++    /* set OID for the field */
++    if ((field->fieldType = OBJ_nid2obj(nid)) == NULL) {
++        ECerr(EC_F_EC_ASN1_GROUP2FIELDID, ERR_R_OBJ_LIB);
++        goto err;
++    }
++
++    if (nid == NID_X9_62_prime_field) {
++        if ((tmp = BN_new()) == NULL) {
++            ECerr(EC_F_EC_ASN1_GROUP2FIELDID, ERR_R_MALLOC_FAILURE);
++            goto err;
++        }
++        /* the parameters are specified by the prime number p */
++        if (!EC_GROUP_get_curve_GFp(group, tmp, NULL, NULL, NULL)) {
++            ECerr(EC_F_EC_ASN1_GROUP2FIELDID, ERR_R_EC_LIB);
++            goto err;
++        }
++        /* set the prime number */
++        field->p.prime = BN_to_ASN1_INTEGER(tmp, NULL);
++        if (field->p.prime == NULL) {
++            ECerr(EC_F_EC_ASN1_GROUP2FIELDID, ERR_R_ASN1_LIB);
++            goto err;
++        }
++    } else if (nid == NID_X9_62_characteristic_two_field)
++#ifdef OPENSSL_NO_EC2M
++    {
++        ECerr(EC_F_EC_ASN1_GROUP2FIELDID, EC_R_GF2M_NOT_SUPPORTED);
++        goto err;
++    }
++#else
++    {
++        int field_type;
++        X9_62_CHARACTERISTIC_TWO *char_two;
++
++        field->p.char_two = X9_62_CHARACTERISTIC_TWO_new();
++        char_two = field->p.char_two;
++
++        if (char_two == NULL) {
++            ECerr(EC_F_EC_ASN1_GROUP2FIELDID, ERR_R_MALLOC_FAILURE);
++            goto err;
++        }
++
++        char_two->m = (long)EC_GROUP_get_degree(group);
++
++        field_type = EC_GROUP_get_basis_type(group);
++
++        if (field_type == 0) {
++            ECerr(EC_F_EC_ASN1_GROUP2FIELDID, ERR_R_EC_LIB);
++            goto err;
++        }
++        /* set base type OID */
++        if ((char_two->type = OBJ_nid2obj(field_type)) == NULL) {
++            ECerr(EC_F_EC_ASN1_GROUP2FIELDID, ERR_R_OBJ_LIB);
++            goto err;
++        }
++
++        if (field_type == NID_X9_62_tpBasis) {
++            unsigned int k;
++
++            if (!EC_GROUP_get_trinomial_basis(group, &k))
++                goto err;
++
++            char_two->p.tpBasis = ASN1_INTEGER_new();
++            if (char_two->p.tpBasis == NULL) {
++                ECerr(EC_F_EC_ASN1_GROUP2FIELDID, ERR_R_MALLOC_FAILURE);
++                goto err;
++            }
++            if (!ASN1_INTEGER_set(char_two->p.tpBasis, (long)k)) {
++                ECerr(EC_F_EC_ASN1_GROUP2FIELDID, ERR_R_ASN1_LIB);
++                goto err;
++            }
++        } else if (field_type == NID_X9_62_ppBasis) {
++            unsigned int k1, k2, k3;
++
++            if (!EC_GROUP_get_pentanomial_basis(group, &k1, &k2, &k3))
++                goto err;
++
++            char_two->p.ppBasis = X9_62_PENTANOMIAL_new();
++            if (char_two->p.ppBasis == NULL) {
++                ECerr(EC_F_EC_ASN1_GROUP2FIELDID, ERR_R_MALLOC_FAILURE);
++                goto err;
++            }
++
++            /* set k? values */
++            char_two->p.ppBasis->k1 = (long)k1;
++            char_two->p.ppBasis->k2 = (long)k2;
++            char_two->p.ppBasis->k3 = (long)k3;
++        } else {                /* field_type == NID_X9_62_onBasis */
++
++            /* for ONB the parameters are (asn1) NULL */
++            char_two->p.onBasis = ASN1_NULL_new();
++            if (char_two->p.onBasis == NULL) {
++                ECerr(EC_F_EC_ASN1_GROUP2FIELDID, ERR_R_MALLOC_FAILURE);
++                goto err;
++            }
++        }
++    }
++#endif
++    else {
++        ECerr(EC_F_EC_ASN1_GROUP2FIELDID, EC_R_UNSUPPORTED_FIELD);
++        goto err;
++    }
++
++    ok = 1;
++
++ err:
++    BN_free(tmp);
++    return (ok);
++}
++
++static int ec_asn1_group2curve(const EC_GROUP *group, X9_62_CURVE *curve)
++{
++    int ok = 0, nid;
++    BIGNUM *tmp_1 = NULL, *tmp_2 = NULL;
++    unsigned char *buffer_1 = NULL, *buffer_2 = NULL,
++        *a_buf = NULL, *b_buf = NULL;
++    size_t len_1, len_2;
++    unsigned char char_zero = 0;
++
++    if (!group || !curve || !curve->a || !curve->b)
++        return 0;
++
++    if ((tmp_1 = BN_new()) == NULL || (tmp_2 = BN_new()) == NULL) {
++        ECerr(EC_F_EC_ASN1_GROUP2CURVE, ERR_R_MALLOC_FAILURE);
++        goto err;
++    }
++
++    nid = EC_METHOD_get_field_type(EC_GROUP_method_of(group));
++
++    /* get a and b */
++    if (nid == NID_X9_62_prime_field) {
++        if (!EC_GROUP_get_curve_GFp(group, NULL, tmp_1, tmp_2, NULL)) {
++            ECerr(EC_F_EC_ASN1_GROUP2CURVE, ERR_R_EC_LIB);
++            goto err;
++        }
++    }
++#ifndef OPENSSL_NO_EC2M
++    else {                      /* nid == NID_X9_62_characteristic_two_field */
++
++        if (!EC_GROUP_get_curve_GF2m(group, NULL, tmp_1, tmp_2, NULL)) {
++            ECerr(EC_F_EC_ASN1_GROUP2CURVE, ERR_R_EC_LIB);
++            goto err;
++        }
++    }
++#endif
++    len_1 = (size_t)BN_num_bytes(tmp_1);
++    len_2 = (size_t)BN_num_bytes(tmp_2);
++
++    if (len_1 == 0) {
++        /* len_1 == 0 => a == 0 */
++        a_buf = &char_zero;
++        len_1 = 1;
++    } else {
++        if ((buffer_1 = OPENSSL_malloc(len_1)) == NULL) {
++            ECerr(EC_F_EC_ASN1_GROUP2CURVE, ERR_R_MALLOC_FAILURE);
++            goto err;
++        }
++        if ((len_1 = BN_bn2bin(tmp_1, buffer_1)) == 0) {
++            ECerr(EC_F_EC_ASN1_GROUP2CURVE, ERR_R_BN_LIB);
++            goto err;
++        }
++        a_buf = buffer_1;
++    }
++
++    if (len_2 == 0) {
++        /* len_2 == 0 => b == 0 */
++        b_buf = &char_zero;
++        len_2 = 1;
++    } else {
++        if ((buffer_2 = OPENSSL_malloc(len_2)) == NULL) {
++            ECerr(EC_F_EC_ASN1_GROUP2CURVE, ERR_R_MALLOC_FAILURE);
++            goto err;
++        }
++        if ((len_2 = BN_bn2bin(tmp_2, buffer_2)) == 0) {
++            ECerr(EC_F_EC_ASN1_GROUP2CURVE, ERR_R_BN_LIB);
++            goto err;
++        }
++        b_buf = buffer_2;
++    }
++
++    /* set a and b */
++    if (!ASN1_OCTET_STRING_set(curve->a, a_buf, len_1) ||
++        !ASN1_OCTET_STRING_set(curve->b, b_buf, len_2)) {
++        ECerr(EC_F_EC_ASN1_GROUP2CURVE, ERR_R_ASN1_LIB);
++        goto err;
++    }
++
++    /* set the seed (optional) */
++    if (group->seed) {
++        if (!curve->seed)
++            if ((curve->seed = ASN1_BIT_STRING_new()) == NULL) {
++                ECerr(EC_F_EC_ASN1_GROUP2CURVE, ERR_R_MALLOC_FAILURE);
++                goto err;
++            }
++        curve->seed->flags &= ~(ASN1_STRING_FLAG_BITS_LEFT | 0x07);
++        curve->seed->flags |= ASN1_STRING_FLAG_BITS_LEFT;
++        if (!ASN1_BIT_STRING_set(curve->seed, group->seed,
++                                 (int)group->seed_len)) {
++            ECerr(EC_F_EC_ASN1_GROUP2CURVE, ERR_R_ASN1_LIB);
++            goto err;
++        }
++    } else {
++        ASN1_BIT_STRING_free(curve->seed);
++        curve->seed = NULL;
++    }
++
++    ok = 1;
++
++ err:
++    OPENSSL_free(buffer_1);
++    OPENSSL_free(buffer_2);
++    BN_free(tmp_1);
++    BN_free(tmp_2);
++    return (ok);
++}
++
++ECPARAMETERS *EC_GROUP_get_ecparameters(const EC_GROUP *group,
++                                               ECPARAMETERS *params)
++{
++    size_t len = 0;
++    ECPARAMETERS *ret = NULL;
++    const BIGNUM *tmp;
++    unsigned char *buffer = NULL;
++    const EC_POINT *point = NULL;
++    point_conversion_form_t form;
++
++    if (params == NULL) {
++        if ((ret = ECPARAMETERS_new()) == NULL) {
++            ECerr(EC_F_EC_GROUP_GET_ECPARAMETERS, ERR_R_MALLOC_FAILURE);
++            goto err;
++        }
++    } else
++        ret = params;
++
++    /* set the version (always one) */
++    ret->version = (long)0x1;
++
++    /* set the fieldID */
++    if (!ec_asn1_group2fieldid(group, ret->fieldID)) {
++        ECerr(EC_F_EC_GROUP_GET_ECPARAMETERS, ERR_R_EC_LIB);
++        goto err;
++    }
++
++    /* set the curve */
++    if (!ec_asn1_group2curve(group, ret->curve)) {
++        ECerr(EC_F_EC_GROUP_GET_ECPARAMETERS, ERR_R_EC_LIB);
++        goto err;
++    }
++
++    /* set the base point */
++    if ((point = EC_GROUP_get0_generator(group)) == NULL) {
++        ECerr(EC_F_EC_GROUP_GET_ECPARAMETERS, EC_R_UNDEFINED_GENERATOR);
++        goto err;
++    }
++
++    form = EC_GROUP_get_point_conversion_form(group);
++
++    len = EC_POINT_point2buf(group, point, form, &buffer, NULL);
++    if (len == 0) {
++        ECerr(EC_F_EC_GROUP_GET_ECPARAMETERS, ERR_R_EC_LIB);
++        goto err;
++    }
++    if (ret->base == NULL && (ret->base = ASN1_OCTET_STRING_new()) == NULL) {
++        OPENSSL_free(buffer);
++        ECerr(EC_F_EC_GROUP_GET_ECPARAMETERS, ERR_R_MALLOC_FAILURE);
++        goto err;
++    }
++    ASN1_STRING_set0(ret->base, buffer, len);
++
++    /* set the order */
++    tmp = EC_GROUP_get0_order(group);
++    if (tmp == NULL) {
++        ECerr(EC_F_EC_GROUP_GET_ECPARAMETERS, ERR_R_EC_LIB);
++        goto err;
++    }
++    ret->order = BN_to_ASN1_INTEGER(tmp, ret->order);
++    if (ret->order == NULL) {
++        ECerr(EC_F_EC_GROUP_GET_ECPARAMETERS, ERR_R_ASN1_LIB);
++        goto err;
++    }
++
++    /* set the cofactor (optional) */
++    tmp = EC_GROUP_get0_cofactor(group);
++    if (tmp != NULL) {
++        ret->cofactor = BN_to_ASN1_INTEGER(tmp, ret->cofactor);
++        if (ret->cofactor == NULL) {
++            ECerr(EC_F_EC_GROUP_GET_ECPARAMETERS, ERR_R_ASN1_LIB);
++            goto err;
++        }
++    }
++
++    return ret;
++
++ err:
++    if (params == NULL)
++        ECPARAMETERS_free(ret);
++    return NULL;
++}
++
++ECPKPARAMETERS *EC_GROUP_get_ecpkparameters(const EC_GROUP *group,
++                                            ECPKPARAMETERS *params)
++{
++    int ok = 1, tmp;
++    ECPKPARAMETERS *ret = params;
++
++    if (ret == NULL) {
++        if ((ret = ECPKPARAMETERS_new()) == NULL) {
++            ECerr(EC_F_EC_GROUP_GET_ECPKPARAMETERS, ERR_R_MALLOC_FAILURE);
++            return NULL;
++        }
++    } else {
++        if (ret->type == 0)
++            ASN1_OBJECT_free(ret->value.named_curve);
++        else if (ret->type == 1 && ret->value.parameters)
++            ECPARAMETERS_free(ret->value.parameters);
++    }
++
++    if (EC_GROUP_get_asn1_flag(group)) {
++        /*
++         * use the asn1 OID to describe the the elliptic curve parameters
++         */
++        tmp = EC_GROUP_get_curve_name(group);
++        if (tmp) {
++            ret->type = 0;
++            if ((ret->value.named_curve = OBJ_nid2obj(tmp)) == NULL)
++                ok = 0;
++        } else
++            /* we don't know the nid => ERROR */
++            ok = 0;
++    } else {
++        /* use the ECPARAMETERS structure */
++        ret->type = 1;
++        if ((ret->value.parameters =
++             EC_GROUP_get_ecparameters(group, NULL)) == NULL)
++            ok = 0;
++    }
++
++    if (!ok) {
++        ECPKPARAMETERS_free(ret);
++        return NULL;
++    }
++    return ret;
++}
++
++EC_GROUP *EC_GROUP_new_from_ecparameters(const ECPARAMETERS *params)
++{
++    int ok = 0, tmp;
++    EC_GROUP *ret = NULL;
++    BIGNUM *p = NULL, *a = NULL, *b = NULL;
++    EC_POINT *point = NULL;
++    long field_bits;
++
++    if (!params->fieldID || !params->fieldID->fieldType ||
++        !params->fieldID->p.ptr) {
++        ECerr(EC_F_EC_GROUP_NEW_FROM_ECPARAMETERS, EC_R_ASN1_ERROR);
++        goto err;
++    }
++
++    /* now extract the curve parameters a and b */
++    if (!params->curve || !params->curve->a ||
++        !params->curve->a->data || !params->curve->b ||
++        !params->curve->b->data) {
++        ECerr(EC_F_EC_GROUP_NEW_FROM_ECPARAMETERS, EC_R_ASN1_ERROR);
++        goto err;
++    }
++    a = BN_bin2bn(params->curve->a->data, params->curve->a->length, NULL);
++    if (a == NULL) {
++        ECerr(EC_F_EC_GROUP_NEW_FROM_ECPARAMETERS, ERR_R_BN_LIB);
++        goto err;
++    }
++    b = BN_bin2bn(params->curve->b->data, params->curve->b->length, NULL);
++    if (b == NULL) {
++        ECerr(EC_F_EC_GROUP_NEW_FROM_ECPARAMETERS, ERR_R_BN_LIB);
++        goto err;
++    }
++
++    /* get the field parameters */
++    tmp = OBJ_obj2nid(params->fieldID->fieldType);
++    if (tmp == NID_X9_62_characteristic_two_field)
++#ifdef OPENSSL_NO_EC2M
++    {
++        ECerr(EC_F_EC_GROUP_NEW_FROM_ECPARAMETERS, EC_R_GF2M_NOT_SUPPORTED);
++        goto err;
++    }
++#else
++    {
++        X9_62_CHARACTERISTIC_TWO *char_two;
++
++        char_two = params->fieldID->p.char_two;
++
++        field_bits = char_two->m;
++        if (field_bits > OPENSSL_ECC_MAX_FIELD_BITS) {
++            ECerr(EC_F_EC_GROUP_NEW_FROM_ECPARAMETERS, EC_R_FIELD_TOO_LARGE);
++            goto err;
++        }
++
++        if ((p = BN_new()) == NULL) {
++            ECerr(EC_F_EC_GROUP_NEW_FROM_ECPARAMETERS, ERR_R_MALLOC_FAILURE);
++            goto err;
++        }
++
++        /* get the base type */
++        tmp = OBJ_obj2nid(char_two->type);
++
++        if (tmp == NID_X9_62_tpBasis) {
++            long tmp_long;
++
++            if (!char_two->p.tpBasis) {
++                ECerr(EC_F_EC_GROUP_NEW_FROM_ECPARAMETERS, EC_R_ASN1_ERROR);
++                goto err;
++            }
++
++            tmp_long = ASN1_INTEGER_get(char_two->p.tpBasis);
++
++            if (!(char_two->m > tmp_long && tmp_long > 0)) {
++                ECerr(EC_F_EC_GROUP_NEW_FROM_ECPARAMETERS,
++                      EC_R_INVALID_TRINOMIAL_BASIS);
++                goto err;
++            }
++
++            /* create the polynomial */
++            if (!BN_set_bit(p, (int)char_two->m))
++                goto err;
++            if (!BN_set_bit(p, (int)tmp_long))
++                goto err;
++            if (!BN_set_bit(p, 0))
++                goto err;
++        } else if (tmp == NID_X9_62_ppBasis) {
++            X9_62_PENTANOMIAL *penta;
++
++            penta = char_two->p.ppBasis;
++            if (!penta) {
++                ECerr(EC_F_EC_GROUP_NEW_FROM_ECPARAMETERS, EC_R_ASN1_ERROR);
++                goto err;
++            }
++
++            if (!
++                (char_two->m > penta->k3 && penta->k3 > penta->k2
++                 && penta->k2 > penta->k1 && penta->k1 > 0)) {
++                ECerr(EC_F_EC_GROUP_NEW_FROM_ECPARAMETERS,
++                      EC_R_INVALID_PENTANOMIAL_BASIS);
++                goto err;
++            }
++
++            /* create the polynomial */
++            if (!BN_set_bit(p, (int)char_two->m))
++                goto err;
++            if (!BN_set_bit(p, (int)penta->k1))
++                goto err;
++            if (!BN_set_bit(p, (int)penta->k2))
++                goto err;
++            if (!BN_set_bit(p, (int)penta->k3))
++                goto err;
++            if (!BN_set_bit(p, 0))
++                goto err;
++        } else if (tmp == NID_X9_62_onBasis) {
++            ECerr(EC_F_EC_GROUP_NEW_FROM_ECPARAMETERS, EC_R_NOT_IMPLEMENTED);
++            goto err;
++        } else {                /* error */
++
++            ECerr(EC_F_EC_GROUP_NEW_FROM_ECPARAMETERS, EC_R_ASN1_ERROR);
++            goto err;
++        }
++
++        /* create the EC_GROUP structure */
++        ret = EC_GROUP_new_curve_GF2m(p, a, b, NULL);
++    }
++#endif
++    else if (tmp == NID_X9_62_prime_field) {
++        /* we have a curve over a prime field */
++        /* extract the prime number */
++        if (!params->fieldID->p.prime) {
++            ECerr(EC_F_EC_GROUP_NEW_FROM_ECPARAMETERS, EC_R_ASN1_ERROR);
++            goto err;
++        }
++        p = ASN1_INTEGER_to_BN(params->fieldID->p.prime, NULL);
++        if (p == NULL) {
++            ECerr(EC_F_EC_GROUP_NEW_FROM_ECPARAMETERS, ERR_R_ASN1_LIB);
++            goto err;
++        }
++
++        if (BN_is_negative(p) || BN_is_zero(p)) {
++            ECerr(EC_F_EC_GROUP_NEW_FROM_ECPARAMETERS, EC_R_INVALID_FIELD);
++            goto err;
++        }
++
++        field_bits = BN_num_bits(p);
++        if (field_bits > OPENSSL_ECC_MAX_FIELD_BITS) {
++            ECerr(EC_F_EC_GROUP_NEW_FROM_ECPARAMETERS, EC_R_FIELD_TOO_LARGE);
++            goto err;
++        }
++
++        /* create the EC_GROUP structure */
++        ret = EC_GROUP_new_curve_GFp(p, a, b, NULL);
++    } else {
++        ECerr(EC_F_EC_GROUP_NEW_FROM_ECPARAMETERS, EC_R_INVALID_FIELD);
++        goto err;
++    }
++
++    if (ret == NULL) {
++        ECerr(EC_F_EC_GROUP_NEW_FROM_ECPARAMETERS, ERR_R_EC_LIB);
++        goto err;
++    }
++
++    /* extract seed (optional) */
++    if (params->curve->seed != NULL) {
++        OPENSSL_free(ret->seed);
++        if ((ret->seed = OPENSSL_malloc(params->curve->seed->length)) == NULL) {
++            ECerr(EC_F_EC_GROUP_NEW_FROM_ECPARAMETERS, ERR_R_MALLOC_FAILURE);
++            goto err;
++        }
++        memcpy(ret->seed, params->curve->seed->data,
++               params->curve->seed->length);
++        ret->seed_len = params->curve->seed->length;
++    }
++
++    if (!params->order || !params->base || !params->base->data) {
++        ECerr(EC_F_EC_GROUP_NEW_FROM_ECPARAMETERS, EC_R_ASN1_ERROR);
++        goto err;
++    }
++
++    if ((point = EC_POINT_new(ret)) == NULL)
++        goto err;
++
++    /* set the point conversion form */
++    EC_GROUP_set_point_conversion_form(ret, (point_conversion_form_t)
++                                       (params->base->data[0] & ~0x01));
++
++    /* extract the ec point */
++    if (!EC_POINT_oct2point(ret, point, params->base->data,
++                            params->base->length, NULL)) {
++        ECerr(EC_F_EC_GROUP_NEW_FROM_ECPARAMETERS, ERR_R_EC_LIB);
++        goto err;
++    }
++
++    /* extract the order */
++    if ((a = ASN1_INTEGER_to_BN(params->order, a)) == NULL) {
++        ECerr(EC_F_EC_GROUP_NEW_FROM_ECPARAMETERS, ERR_R_ASN1_LIB);
++        goto err;
++    }
++    if (BN_is_negative(a) || BN_is_zero(a)) {
++        ECerr(EC_F_EC_GROUP_NEW_FROM_ECPARAMETERS, EC_R_INVALID_GROUP_ORDER);
++        goto err;
++    }
++    if (BN_num_bits(a) > (int)field_bits + 1) { /* Hasse bound */
++        ECerr(EC_F_EC_GROUP_NEW_FROM_ECPARAMETERS, EC_R_INVALID_GROUP_ORDER);
++        goto err;
++    }
++
++    /* extract the cofactor (optional) */
++    if (params->cofactor == NULL) {
++        BN_free(b);
++        b = NULL;
++    } else if ((b = ASN1_INTEGER_to_BN(params->cofactor, b)) == NULL) {
++        ECerr(EC_F_EC_GROUP_NEW_FROM_ECPARAMETERS, ERR_R_ASN1_LIB);
++        goto err;
++    }
++    /* set the generator, order and cofactor (if present) */
++    if (!EC_GROUP_set_generator(ret, point, a, b)) {
++        ECerr(EC_F_EC_GROUP_NEW_FROM_ECPARAMETERS, ERR_R_EC_LIB);
++        goto err;
++    }
++
++    ok = 1;
++
++ err:
++    if (!ok) {
++        EC_GROUP_clear_free(ret);
++        ret = NULL;
++    }
++
++    BN_free(p);
++    BN_free(a);
++    BN_free(b);
++    EC_POINT_free(point);
++    return (ret);
++}
++
++EC_GROUP *EC_GROUP_new_from_ecpkparameters(const ECPKPARAMETERS *params)
++{
++    EC_GROUP *ret = NULL;
++    int tmp = 0;
++
++    if (params == NULL) {
++        ECerr(EC_F_EC_GROUP_NEW_FROM_ECPKPARAMETERS, EC_R_MISSING_PARAMETERS);
++        return NULL;
++    }
++
++    if (params->type == 0) {    /* the curve is given by an OID */
++        tmp = OBJ_obj2nid(params->value.named_curve);
++        if ((ret = EC_GROUP_new_by_curve_name(tmp)) == NULL) {
++            ECerr(EC_F_EC_GROUP_NEW_FROM_ECPKPARAMETERS,
++                  EC_R_EC_GROUP_NEW_BY_NAME_FAILURE);
++            return NULL;
++        }
++        EC_GROUP_set_asn1_flag(ret, OPENSSL_EC_NAMED_CURVE);
++    } else if (params->type == 1) { /* the parameters are given by a
++                                     * ECPARAMETERS structure */
++        ret = EC_GROUP_new_from_ecparameters(params->value.parameters);
++        if (!ret) {
++            ECerr(EC_F_EC_GROUP_NEW_FROM_ECPKPARAMETERS, ERR_R_EC_LIB);
++            return NULL;
++        }
++        EC_GROUP_set_asn1_flag(ret, 0x0);
++    } else if (params->type == 2) { /* implicitlyCA */
++        return NULL;
++    } else {
++        ECerr(EC_F_EC_GROUP_NEW_FROM_ECPKPARAMETERS, EC_R_ASN1_ERROR);
++        return NULL;
++    }
++
++    return ret;
++}
++
++/* EC_GROUP <-> DER encoding of ECPKPARAMETERS */
++
++EC_GROUP *d2i_ECPKParameters(EC_GROUP **a, const unsigned char **in, long len)
++{
++    EC_GROUP *group = NULL;
++    ECPKPARAMETERS *params = NULL;
++    const unsigned char *p = *in;
++
++    if ((params = d2i_ECPKPARAMETERS(NULL, &p, len)) == NULL) {
++        ECerr(EC_F_D2I_ECPKPARAMETERS, EC_R_D2I_ECPKPARAMETERS_FAILURE);
++        ECPKPARAMETERS_free(params);
++        return NULL;
++    }
++
++    if ((group = EC_GROUP_new_from_ecpkparameters(params)) == NULL) {
++        ECerr(EC_F_D2I_ECPKPARAMETERS, EC_R_PKPARAMETERS2GROUP_FAILURE);
++        ECPKPARAMETERS_free(params);
++        return NULL;
++    }
++
++    if (a) {
++        EC_GROUP_clear_free(*a);
++        *a = group;
++    }
++
++    ECPKPARAMETERS_free(params);
++    *in = p;
++    return (group);
++}
++
++int i2d_ECPKParameters(const EC_GROUP *a, unsigned char **out)
++{
++    int ret = 0;
++    ECPKPARAMETERS *tmp = EC_GROUP_get_ecpkparameters(a, NULL);
++    if (tmp == NULL) {
++        ECerr(EC_F_I2D_ECPKPARAMETERS, EC_R_GROUP2PKPARAMETERS_FAILURE);
++        return 0;
++    }
++    if ((ret = i2d_ECPKPARAMETERS(tmp, out)) == 0) {
++        ECerr(EC_F_I2D_ECPKPARAMETERS, EC_R_I2D_ECPKPARAMETERS_FAILURE);
++        ECPKPARAMETERS_free(tmp);
++        return 0;
++    }
++    ECPKPARAMETERS_free(tmp);
++    return (ret);
++}
++
++/* some EC_KEY functions */
++
++EC_KEY *d2i_ECPrivateKey(EC_KEY **a, const unsigned char **in, long len)
++{
++    EC_KEY *ret = NULL;
++    EC_PRIVATEKEY *priv_key = NULL;
++    const unsigned char *p = *in;
++
++    if ((priv_key = d2i_EC_PRIVATEKEY(NULL, &p, len)) == NULL) {
++        ECerr(EC_F_D2I_ECPRIVATEKEY, ERR_R_EC_LIB);
++        return NULL;
++    }
++
++    if (a == NULL || *a == NULL) {
++        if ((ret = EC_KEY_new()) == NULL) {
++            ECerr(EC_F_D2I_ECPRIVATEKEY, ERR_R_MALLOC_FAILURE);
++            goto err;
++        }
++    } else
++        ret = *a;
++
++    if (priv_key->parameters) {
++        EC_GROUP_clear_free(ret->group);
++        ret->group = EC_GROUP_new_from_ecpkparameters(priv_key->parameters);
++    }
++
++    if (ret->group == NULL) {
++        ECerr(EC_F_D2I_ECPRIVATEKEY, ERR_R_EC_LIB);
++        goto err;
++    }
++
++    ret->version = priv_key->version;
++
++    if (priv_key->privateKey) {
++        ASN1_OCTET_STRING *pkey = priv_key->privateKey;
++        if (EC_KEY_oct2priv(ret, ASN1_STRING_get0_data(pkey),
++                            ASN1_STRING_length(pkey)) == 0)
++            goto err;
++    } else {
++        ECerr(EC_F_D2I_ECPRIVATEKEY, EC_R_MISSING_PRIVATE_KEY);
++        goto err;
++    }
++
++    EC_POINT_clear_free(ret->pub_key);
++    ret->pub_key = EC_POINT_new(ret->group);
++    if (ret->pub_key == NULL) {
++        ECerr(EC_F_D2I_ECPRIVATEKEY, ERR_R_EC_LIB);
++        goto err;
++    }
++
++    if (priv_key->publicKey) {
++        const unsigned char *pub_oct;
++        int pub_oct_len;
++
++        pub_oct = ASN1_STRING_get0_data(priv_key->publicKey);
++        pub_oct_len = ASN1_STRING_length(priv_key->publicKey);
++        if (!EC_KEY_oct2key(ret, pub_oct, pub_oct_len, NULL)) {
++            ECerr(EC_F_D2I_ECPRIVATEKEY, ERR_R_EC_LIB);
++            goto err;
++        }
++    } else {
++        if (ret->group->meth->keygenpub == NULL
++            || ret->group->meth->keygenpub(ret) == 0)
++                goto err;
++        /* Remember the original private-key-only encoding. */
++        ret->enc_flag |= EC_PKEY_NO_PUBKEY;
++    }
++
++    if (a)
++        *a = ret;
++    EC_PRIVATEKEY_free(priv_key);
++    *in = p;
++    return (ret);
++
++ err:
++    if (a == NULL || *a != ret)
++        EC_KEY_free(ret);
++    EC_PRIVATEKEY_free(priv_key);
++    return NULL;
++}
++
++int i2d_ECPrivateKey(EC_KEY *a, unsigned char **out)
++{
++    int ret = 0, ok = 0;
++    unsigned char *priv= NULL, *pub= NULL;
++    size_t privlen = 0, publen = 0;
++
++    EC_PRIVATEKEY *priv_key = NULL;
++
++    if (a == NULL || a->group == NULL ||
++        (!(a->enc_flag & EC_PKEY_NO_PUBKEY) && a->pub_key == NULL)) {
++        ECerr(EC_F_I2D_ECPRIVATEKEY, ERR_R_PASSED_NULL_PARAMETER);
++        goto err;
++    }
++
++    if ((priv_key = EC_PRIVATEKEY_new()) == NULL) {
++        ECerr(EC_F_I2D_ECPRIVATEKEY, ERR_R_MALLOC_FAILURE);
++        goto err;
++    }
++
++    priv_key->version = a->version;
++
++    privlen = EC_KEY_priv2buf(a, &priv);
++
++    if (privlen == 0) {
++        ECerr(EC_F_I2D_ECPRIVATEKEY, ERR_R_EC_LIB);
++        goto err;
++    }
++
++    ASN1_STRING_set0(priv_key->privateKey, priv, privlen);
++    priv = NULL;
++
++    if (!(a->enc_flag & EC_PKEY_NO_PARAMETERS)) {
++        if ((priv_key->parameters =
++             EC_GROUP_get_ecpkparameters(a->group,
++                                        priv_key->parameters)) == NULL) {
++            ECerr(EC_F_I2D_ECPRIVATEKEY, ERR_R_EC_LIB);
++            goto err;
++        }
++    }
++
++    if (!(a->enc_flag & EC_PKEY_NO_PUBKEY)) {
++        priv_key->publicKey = ASN1_BIT_STRING_new();
++        if (priv_key->publicKey == NULL) {
++            ECerr(EC_F_I2D_ECPRIVATEKEY, ERR_R_MALLOC_FAILURE);
++            goto err;
++        }
++
++        publen = EC_KEY_key2buf(a, a->conv_form, &pub, NULL);
++
++        if (publen == 0) {
++            ECerr(EC_F_I2D_ECPRIVATEKEY, ERR_R_EC_LIB);
++            goto err;
++        }
++
++        priv_key->publicKey->flags &= ~(ASN1_STRING_FLAG_BITS_LEFT | 0x07);
++        priv_key->publicKey->flags |= ASN1_STRING_FLAG_BITS_LEFT;
++        ASN1_STRING_set0(priv_key->publicKey, pub, publen);
++        pub = NULL;
++    }
++
++    if ((ret = i2d_EC_PRIVATEKEY(priv_key, out)) == 0) {
++        ECerr(EC_F_I2D_ECPRIVATEKEY, ERR_R_EC_LIB);
++        goto err;
++    }
++    ok = 1;
++ err:
++    OPENSSL_clear_free(priv, privlen);
++    OPENSSL_free(pub);
++    EC_PRIVATEKEY_free(priv_key);
++    return (ok ? ret : 0);
++}
++
++int i2d_ECParameters(EC_KEY *a, unsigned char **out)
++{
++    if (a == NULL) {
++        ECerr(EC_F_I2D_ECPARAMETERS, ERR_R_PASSED_NULL_PARAMETER);
++        return 0;
++    }
++    return i2d_ECPKParameters(a->group, out);
++}
++
++EC_KEY *d2i_ECParameters(EC_KEY **a, const unsigned char **in, long len)
++{
++    EC_KEY *ret;
++
++    if (in == NULL || *in == NULL) {
++        ECerr(EC_F_D2I_ECPARAMETERS, ERR_R_PASSED_NULL_PARAMETER);
++        return NULL;
++    }
++
++    if (a == NULL || *a == NULL) {
++        if ((ret = EC_KEY_new()) == NULL) {
++            ECerr(EC_F_D2I_ECPARAMETERS, ERR_R_MALLOC_FAILURE);
++            return NULL;
++        }
++    } else
++        ret = *a;
++
++    if (!d2i_ECPKParameters(&ret->group, in, len)) {
++        ECerr(EC_F_D2I_ECPARAMETERS, ERR_R_EC_LIB);
++        if (a == NULL || *a != ret)
++             EC_KEY_free(ret);
++        return NULL;
++    }
++
++    if (a)
++        *a = ret;
++
++    return ret;
++}
++
++EC_KEY *o2i_ECPublicKey(EC_KEY **a, const unsigned char **in, long len)
++{
++    EC_KEY *ret = NULL;
++
++    if (a == NULL || (*a) == NULL || (*a)->group == NULL) {
++        /*
++         * sorry, but a EC_GROUP-structure is necessary to set the public key
++         */
++        ECerr(EC_F_O2I_ECPUBLICKEY, ERR_R_PASSED_NULL_PARAMETER);
++        return 0;
++    }
++    ret = *a;
++    if (!EC_KEY_oct2key(ret, *in, len, NULL)) {
++        ECerr(EC_F_O2I_ECPUBLICKEY, ERR_R_EC_LIB);
++        return 0;
++    }
++    *in += len;
++    return ret;
++}
++
++int i2o_ECPublicKey(const EC_KEY *a, unsigned char **out)
++{
++    size_t buf_len = 0;
++    int new_buffer = 0;
++
++    if (a == NULL) {
++        ECerr(EC_F_I2O_ECPUBLICKEY, ERR_R_PASSED_NULL_PARAMETER);
++        return 0;
++    }
++
++    buf_len = EC_POINT_point2oct(a->group, a->pub_key,
++                                 a->conv_form, NULL, 0, NULL);
++
++    if (out == NULL || buf_len == 0)
++        /* out == NULL => just return the length of the octet string */
++        return buf_len;
++
++    if (*out == NULL) {
++        if ((*out = OPENSSL_malloc(buf_len)) == NULL) {
++            ECerr(EC_F_I2O_ECPUBLICKEY, ERR_R_MALLOC_FAILURE);
++            return 0;
++        }
++        new_buffer = 1;
++    }
++    if (!EC_POINT_point2oct(a->group, a->pub_key, a->conv_form,
++                            *out, buf_len, NULL)) {
++        ECerr(EC_F_I2O_ECPUBLICKEY, ERR_R_EC_LIB);
++        if (new_buffer) {
++            OPENSSL_free(*out);
++            *out = NULL;
++        }
++        return 0;
++    }
++    if (!new_buffer)
++        *out += buf_len;
++    return buf_len;
++}
++
++ASN1_SEQUENCE(ECDSA_SIG) = {
++        ASN1_SIMPLE(ECDSA_SIG, r, CBIGNUM),
++        ASN1_SIMPLE(ECDSA_SIG, s, CBIGNUM)
++} static_ASN1_SEQUENCE_END(ECDSA_SIG)
++
++DECLARE_ASN1_FUNCTIONS_const(ECDSA_SIG)
++DECLARE_ASN1_ENCODE_FUNCTIONS_const(ECDSA_SIG, ECDSA_SIG)
++IMPLEMENT_ASN1_ENCODE_FUNCTIONS_const_fname(ECDSA_SIG, ECDSA_SIG, ECDSA_SIG)
++
++ECDSA_SIG *ECDSA_SIG_new(void)
++{
++    ECDSA_SIG *sig = OPENSSL_zalloc(sizeof(*sig));
++    if (sig == NULL)
++        ECerr(EC_F_ECDSA_SIG_NEW, ERR_R_MALLOC_FAILURE);
++    return sig;
++}
++
++void ECDSA_SIG_free(ECDSA_SIG *sig)
++{
++    if (sig == NULL)
++        return;
++    BN_clear_free(sig->r);
++    BN_clear_free(sig->s);
++    OPENSSL_free(sig);
++}
++
++void ECDSA_SIG_get0(const ECDSA_SIG *sig, const BIGNUM **pr, const BIGNUM **ps)
++{
++    if (pr != NULL)
++        *pr = sig->r;
++    if (ps != NULL)
++        *ps = sig->s;
++}
++
++int ECDSA_SIG_set0(ECDSA_SIG *sig, BIGNUM *r, BIGNUM *s)
++{
++    if (r == NULL || s == NULL)
++        return 0;
++    BN_clear_free(sig->r);
++    BN_clear_free(sig->s);
++    sig->r = r;
++    sig->s = s;
++    return 1;
++}
++
++int ECDSA_size(const EC_KEY *r)
++{
++    int ret, i;
++    ASN1_INTEGER bs;
++    unsigned char buf[4];
++    const EC_GROUP *group;
++
++    if (r == NULL)
++        return 0;
++    group = EC_KEY_get0_group(r);
++    if (group == NULL)
++        return 0;
++
++    i = EC_GROUP_order_bits(group);
++    if (i == 0)
++        return 0;
++    bs.length = (i + 7) / 8;
++    bs.data = buf;
++    bs.type = V_ASN1_INTEGER;
++    /* If the top bit is set the asn1 encoding is 1 larger. */
++    buf[0] = 0xff;
++
++    i = i2d_ASN1_INTEGER(&bs, NULL);
++    i += i;                     /* r and s */
++    ret = ASN1_object_size(1, i, V_ASN1_SEQUENCE);
++    return (ret);
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/ec/ec_check.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/ec/ec_check.c
+new file mode 100644
+index 0000000..eeb06ec
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/ec/ec_check.c
+@@ -0,0 +1,72 @@
++/*
++ * Copyright 2002-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include "ec_lcl.h"
++#include 
++
++int EC_GROUP_check(const EC_GROUP *group, BN_CTX *ctx)
++{
++    int ret = 0;
++    const BIGNUM *order;
++    BN_CTX *new_ctx = NULL;
++    EC_POINT *point = NULL;
++
++    /* Custom curves assumed to be correct */
++    if ((group->meth->flags & EC_FLAGS_CUSTOM_CURVE) != 0)
++        return 1;
++
++    if (ctx == NULL) {
++        ctx = new_ctx = BN_CTX_new();
++        if (ctx == NULL) {
++            ECerr(EC_F_EC_GROUP_CHECK, ERR_R_MALLOC_FAILURE);
++            goto err;
++        }
++    }
++
++    /* check the discriminant */
++    if (!EC_GROUP_check_discriminant(group, ctx)) {
++        ECerr(EC_F_EC_GROUP_CHECK, EC_R_DISCRIMINANT_IS_ZERO);
++        goto err;
++    }
++
++    /* check the generator */
++    if (group->generator == NULL) {
++        ECerr(EC_F_EC_GROUP_CHECK, EC_R_UNDEFINED_GENERATOR);
++        goto err;
++    }
++    if (EC_POINT_is_on_curve(group, group->generator, ctx) <= 0) {
++        ECerr(EC_F_EC_GROUP_CHECK, EC_R_POINT_IS_NOT_ON_CURVE);
++        goto err;
++    }
++
++    /* check the order of the generator */
++    if ((point = EC_POINT_new(group)) == NULL)
++        goto err;
++    order = EC_GROUP_get0_order(group);
++    if (order == NULL)
++        goto err;
++    if (BN_is_zero(order)) {
++        ECerr(EC_F_EC_GROUP_CHECK, EC_R_UNDEFINED_ORDER);
++        goto err;
++    }
++
++    if (!EC_POINT_mul(group, point, order, NULL, NULL, ctx))
++        goto err;
++    if (!EC_POINT_is_at_infinity(group, point)) {
++        ECerr(EC_F_EC_GROUP_CHECK, EC_R_INVALID_GROUP_ORDER);
++        goto err;
++    }
++
++    ret = 1;
++
++ err:
++    BN_CTX_free(new_ctx);
++    EC_POINT_free(point);
++    return ret;
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/ec/ec_curve.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/ec/ec_curve.c
+new file mode 100644
+index 0000000..e69de29
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/ec/ec_cvt.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/ec/ec_cvt.c
+new file mode 100644
+index 0000000..bfff6d6
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/ec/ec_cvt.c
+@@ -0,0 +1,95 @@
++/*
++ * Copyright 2001-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++/* ====================================================================
++ * Copyright 2002 Sun Microsystems, Inc. ALL RIGHTS RESERVED.
++ *
++ * Portions of the attached software ("Contribution") are developed by
++ * SUN MICROSYSTEMS, INC., and are contributed to the OpenSSL project.
++ *
++ * The Contribution is licensed pursuant to the OpenSSL open source
++ * license provided above.
++ *
++ * The elliptic curve binary polynomial software is originally written by
++ * Sheueling Chang Shantz and Douglas Stebila of Sun Microsystems Laboratories.
++ *
++ */
++
++#include 
++#include "ec_lcl.h"
++
++EC_GROUP *EC_GROUP_new_curve_GFp(const BIGNUM *p, const BIGNUM *a,
++                                 const BIGNUM *b, BN_CTX *ctx)
++{
++    const EC_METHOD *meth;
++    EC_GROUP *ret;
++
++#if defined(OPENSSL_BN_ASM_MONT)
++    /*
++     * This might appear controversial, but the fact is that generic
++     * prime method was observed to deliver better performance even
++     * for NIST primes on a range of platforms, e.g.: 60%-15%
++     * improvement on IA-64, ~25% on ARM, 30%-90% on P4, 20%-25%
++     * in 32-bit build and 35%--12% in 64-bit build on Core2...
++     * Coefficients are relative to optimized bn_nist.c for most
++     * intensive ECDSA verify and ECDH operations for 192- and 521-
++     * bit keys respectively. Choice of these boundary values is
++     * arguable, because the dependency of improvement coefficient
++     * from key length is not a "monotone" curve. For example while
++     * 571-bit result is 23% on ARM, 384-bit one is -1%. But it's
++     * generally faster, sometimes "respectfully" faster, sometimes
++     * "tolerably" slower... What effectively happens is that loop
++     * with bn_mul_add_words is put against bn_mul_mont, and the
++     * latter "wins" on short vectors. Correct solution should be
++     * implementing dedicated NxN multiplication subroutines for
++     * small N. But till it materializes, let's stick to generic
++     * prime method...
++     *                                              
++     */
++    meth = EC_GFp_mont_method();
++#else
++    if (BN_nist_mod_func(p))
++        meth = EC_GFp_nist_method();
++    else
++        meth = EC_GFp_mont_method();
++#endif
++
++    ret = EC_GROUP_new(meth);
++    if (ret == NULL)
++        return NULL;
++
++    if (!EC_GROUP_set_curve_GFp(ret, p, a, b, ctx)) {
++        EC_GROUP_clear_free(ret);
++        return NULL;
++    }
++
++    return ret;
++}
++
++#ifndef OPENSSL_NO_EC2M
++EC_GROUP *EC_GROUP_new_curve_GF2m(const BIGNUM *p, const BIGNUM *a,
++                                  const BIGNUM *b, BN_CTX *ctx)
++{
++    const EC_METHOD *meth;
++    EC_GROUP *ret;
++
++    meth = EC_GF2m_simple_method();
++
++    ret = EC_GROUP_new(meth);
++    if (ret == NULL)
++        return NULL;
++
++    if (!EC_GROUP_set_curve_GF2m(ret, p, a, b, ctx)) {
++        EC_GROUP_clear_free(ret);
++        return NULL;
++    }
++
++    return ret;
++}
++#endif
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/ec/ec_err.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/ec/ec_err.c
+new file mode 100644
+index 0000000..e4c2c1c
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/ec/ec_err.c
+@@ -0,0 +1,290 @@
++/*
++ * Generated by util/mkerr.pl DO NOT EDIT
++ * Copyright 1995-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include 
++#include 
++
++/* BEGIN ERROR CODES */
++#ifndef OPENSSL_NO_ERR
++
++# define ERR_FUNC(func) ERR_PACK(ERR_LIB_EC,func,0)
++# define ERR_REASON(reason) ERR_PACK(ERR_LIB_EC,0,reason)
++
++static ERR_STRING_DATA EC_str_functs[] = {
++    {ERR_FUNC(EC_F_BN_TO_FELEM), "BN_to_felem"},
++    {ERR_FUNC(EC_F_D2I_ECPARAMETERS), "d2i_ECParameters"},
++    {ERR_FUNC(EC_F_D2I_ECPKPARAMETERS), "d2i_ECPKParameters"},
++    {ERR_FUNC(EC_F_D2I_ECPRIVATEKEY), "d2i_ECPrivateKey"},
++    {ERR_FUNC(EC_F_DO_EC_KEY_PRINT), "do_EC_KEY_print"},
++    {ERR_FUNC(EC_F_ECDH_CMS_DECRYPT), "ecdh_cms_decrypt"},
++    {ERR_FUNC(EC_F_ECDH_CMS_SET_SHARED_INFO), "ecdh_cms_set_shared_info"},
++    {ERR_FUNC(EC_F_ECDH_COMPUTE_KEY), "ECDH_compute_key"},
++    {ERR_FUNC(EC_F_ECDH_SIMPLE_COMPUTE_KEY), "ecdh_simple_compute_key"},
++    {ERR_FUNC(EC_F_ECDSA_DO_SIGN_EX), "ECDSA_do_sign_ex"},
++    {ERR_FUNC(EC_F_ECDSA_DO_VERIFY), "ECDSA_do_verify"},
++    {ERR_FUNC(EC_F_ECDSA_SIGN_EX), "ECDSA_sign_ex"},
++    {ERR_FUNC(EC_F_ECDSA_SIGN_SETUP), "ECDSA_sign_setup"},
++    {ERR_FUNC(EC_F_ECDSA_SIG_NEW), "ECDSA_SIG_new"},
++    {ERR_FUNC(EC_F_ECDSA_VERIFY), "ECDSA_verify"},
++    {ERR_FUNC(EC_F_ECKEY_PARAM2TYPE), "eckey_param2type"},
++    {ERR_FUNC(EC_F_ECKEY_PARAM_DECODE), "eckey_param_decode"},
++    {ERR_FUNC(EC_F_ECKEY_PRIV_DECODE), "eckey_priv_decode"},
++    {ERR_FUNC(EC_F_ECKEY_PRIV_ENCODE), "eckey_priv_encode"},
++    {ERR_FUNC(EC_F_ECKEY_PUB_DECODE), "eckey_pub_decode"},
++    {ERR_FUNC(EC_F_ECKEY_PUB_ENCODE), "eckey_pub_encode"},
++    {ERR_FUNC(EC_F_ECKEY_TYPE2PARAM), "eckey_type2param"},
++    {ERR_FUNC(EC_F_ECPARAMETERS_PRINT), "ECParameters_print"},
++    {ERR_FUNC(EC_F_ECPARAMETERS_PRINT_FP), "ECParameters_print_fp"},
++    {ERR_FUNC(EC_F_ECPKPARAMETERS_PRINT), "ECPKParameters_print"},
++    {ERR_FUNC(EC_F_ECPKPARAMETERS_PRINT_FP), "ECPKParameters_print_fp"},
++    {ERR_FUNC(EC_F_ECP_NISTZ256_GET_AFFINE), "ecp_nistz256_get_affine"},
++    {ERR_FUNC(EC_F_ECP_NISTZ256_MULT_PRECOMPUTE),
++     "ecp_nistz256_mult_precompute"},
++    {ERR_FUNC(EC_F_ECP_NISTZ256_POINTS_MUL), "ecp_nistz256_points_mul"},
++    {ERR_FUNC(EC_F_ECP_NISTZ256_PRE_COMP_NEW), "ecp_nistz256_pre_comp_new"},
++    {ERR_FUNC(EC_F_ECP_NISTZ256_WINDOWED_MUL), "ecp_nistz256_windowed_mul"},
++    {ERR_FUNC(EC_F_ECX_KEY_OP), "ecx_key_op"},
++    {ERR_FUNC(EC_F_ECX_PRIV_ENCODE), "ecx_priv_encode"},
++    {ERR_FUNC(EC_F_ECX_PUB_ENCODE), "ecx_pub_encode"},
++    {ERR_FUNC(EC_F_EC_ASN1_GROUP2CURVE), "ec_asn1_group2curve"},
++    {ERR_FUNC(EC_F_EC_ASN1_GROUP2FIELDID), "ec_asn1_group2fieldid"},
++    {ERR_FUNC(EC_F_EC_GF2M_MONTGOMERY_POINT_MULTIPLY),
++     "ec_GF2m_montgomery_point_multiply"},
++    {ERR_FUNC(EC_F_EC_GF2M_SIMPLE_GROUP_CHECK_DISCRIMINANT),
++     "ec_GF2m_simple_group_check_discriminant"},
++    {ERR_FUNC(EC_F_EC_GF2M_SIMPLE_GROUP_SET_CURVE),
++     "ec_GF2m_simple_group_set_curve"},
++    {ERR_FUNC(EC_F_EC_GF2M_SIMPLE_OCT2POINT), "ec_GF2m_simple_oct2point"},
++    {ERR_FUNC(EC_F_EC_GF2M_SIMPLE_POINT2OCT), "ec_GF2m_simple_point2oct"},
++    {ERR_FUNC(EC_F_EC_GF2M_SIMPLE_POINT_GET_AFFINE_COORDINATES),
++     "ec_GF2m_simple_point_get_affine_coordinates"},
++    {ERR_FUNC(EC_F_EC_GF2M_SIMPLE_POINT_SET_AFFINE_COORDINATES),
++     "ec_GF2m_simple_point_set_affine_coordinates"},
++    {ERR_FUNC(EC_F_EC_GF2M_SIMPLE_SET_COMPRESSED_COORDINATES),
++     "ec_GF2m_simple_set_compressed_coordinates"},
++    {ERR_FUNC(EC_F_EC_GFP_MONT_FIELD_DECODE), "ec_GFp_mont_field_decode"},
++    {ERR_FUNC(EC_F_EC_GFP_MONT_FIELD_ENCODE), "ec_GFp_mont_field_encode"},
++    {ERR_FUNC(EC_F_EC_GFP_MONT_FIELD_MUL), "ec_GFp_mont_field_mul"},
++    {ERR_FUNC(EC_F_EC_GFP_MONT_FIELD_SET_TO_ONE),
++     "ec_GFp_mont_field_set_to_one"},
++    {ERR_FUNC(EC_F_EC_GFP_MONT_FIELD_SQR), "ec_GFp_mont_field_sqr"},
++    {ERR_FUNC(EC_F_EC_GFP_MONT_GROUP_SET_CURVE),
++     "ec_GFp_mont_group_set_curve"},
++    {ERR_FUNC(EC_F_EC_GFP_NISTP224_GROUP_SET_CURVE),
++     "ec_GFp_nistp224_group_set_curve"},
++    {ERR_FUNC(EC_F_EC_GFP_NISTP224_POINTS_MUL), "ec_GFp_nistp224_points_mul"},
++    {ERR_FUNC(EC_F_EC_GFP_NISTP224_POINT_GET_AFFINE_COORDINATES),
++     "ec_GFp_nistp224_point_get_affine_coordinates"},
++    {ERR_FUNC(EC_F_EC_GFP_NISTP256_GROUP_SET_CURVE),
++     "ec_GFp_nistp256_group_set_curve"},
++    {ERR_FUNC(EC_F_EC_GFP_NISTP256_POINTS_MUL), "ec_GFp_nistp256_points_mul"},
++    {ERR_FUNC(EC_F_EC_GFP_NISTP256_POINT_GET_AFFINE_COORDINATES),
++     "ec_GFp_nistp256_point_get_affine_coordinates"},
++    {ERR_FUNC(EC_F_EC_GFP_NISTP521_GROUP_SET_CURVE),
++     "ec_GFp_nistp521_group_set_curve"},
++    {ERR_FUNC(EC_F_EC_GFP_NISTP521_POINTS_MUL), "ec_GFp_nistp521_points_mul"},
++    {ERR_FUNC(EC_F_EC_GFP_NISTP521_POINT_GET_AFFINE_COORDINATES),
++     "ec_GFp_nistp521_point_get_affine_coordinates"},
++    {ERR_FUNC(EC_F_EC_GFP_NIST_FIELD_MUL), "ec_GFp_nist_field_mul"},
++    {ERR_FUNC(EC_F_EC_GFP_NIST_FIELD_SQR), "ec_GFp_nist_field_sqr"},
++    {ERR_FUNC(EC_F_EC_GFP_NIST_GROUP_SET_CURVE),
++     "ec_GFp_nist_group_set_curve"},
++    {ERR_FUNC(EC_F_EC_GFP_SIMPLE_GROUP_CHECK_DISCRIMINANT),
++     "ec_GFp_simple_group_check_discriminant"},
++    {ERR_FUNC(EC_F_EC_GFP_SIMPLE_GROUP_SET_CURVE),
++     "ec_GFp_simple_group_set_curve"},
++    {ERR_FUNC(EC_F_EC_GFP_SIMPLE_MAKE_AFFINE), "ec_GFp_simple_make_affine"},
++    {ERR_FUNC(EC_F_EC_GFP_SIMPLE_OCT2POINT), "ec_GFp_simple_oct2point"},
++    {ERR_FUNC(EC_F_EC_GFP_SIMPLE_POINT2OCT), "ec_GFp_simple_point2oct"},
++    {ERR_FUNC(EC_F_EC_GFP_SIMPLE_POINTS_MAKE_AFFINE),
++     "ec_GFp_simple_points_make_affine"},
++    {ERR_FUNC(EC_F_EC_GFP_SIMPLE_POINT_GET_AFFINE_COORDINATES),
++     "ec_GFp_simple_point_get_affine_coordinates"},
++    {ERR_FUNC(EC_F_EC_GFP_SIMPLE_POINT_SET_AFFINE_COORDINATES),
++     "ec_GFp_simple_point_set_affine_coordinates"},
++    {ERR_FUNC(EC_F_EC_GFP_SIMPLE_SET_COMPRESSED_COORDINATES),
++     "ec_GFp_simple_set_compressed_coordinates"},
++    {ERR_FUNC(EC_F_EC_GROUP_CHECK), "EC_GROUP_check"},
++    {ERR_FUNC(EC_F_EC_GROUP_CHECK_DISCRIMINANT),
++     "EC_GROUP_check_discriminant"},
++    {ERR_FUNC(EC_F_EC_GROUP_COPY), "EC_GROUP_copy"},
++    {ERR_FUNC(EC_F_EC_GROUP_GET_CURVE_GF2M), "EC_GROUP_get_curve_GF2m"},
++    {ERR_FUNC(EC_F_EC_GROUP_GET_CURVE_GFP), "EC_GROUP_get_curve_GFp"},
++    {ERR_FUNC(EC_F_EC_GROUP_GET_DEGREE), "EC_GROUP_get_degree"},
++    {ERR_FUNC(EC_F_EC_GROUP_GET_ECPARAMETERS), "EC_GROUP_get_ecparameters"},
++    {ERR_FUNC(EC_F_EC_GROUP_GET_ECPKPARAMETERS),
++     "EC_GROUP_get_ecpkparameters"},
++    {ERR_FUNC(EC_F_EC_GROUP_GET_PENTANOMIAL_BASIS),
++     "EC_GROUP_get_pentanomial_basis"},
++    {ERR_FUNC(EC_F_EC_GROUP_GET_TRINOMIAL_BASIS),
++     "EC_GROUP_get_trinomial_basis"},
++    {ERR_FUNC(EC_F_EC_GROUP_NEW), "EC_GROUP_new"},
++    {ERR_FUNC(EC_F_EC_GROUP_NEW_BY_CURVE_NAME), "EC_GROUP_new_by_curve_name"},
++    {ERR_FUNC(EC_F_EC_GROUP_NEW_FROM_DATA), "ec_group_new_from_data"},
++    {ERR_FUNC(EC_F_EC_GROUP_NEW_FROM_ECPARAMETERS),
++     "EC_GROUP_new_from_ecparameters"},
++    {ERR_FUNC(EC_F_EC_GROUP_NEW_FROM_ECPKPARAMETERS),
++     "EC_GROUP_new_from_ecpkparameters"},
++    {ERR_FUNC(EC_F_EC_GROUP_SET_CURVE_GF2M), "EC_GROUP_set_curve_GF2m"},
++    {ERR_FUNC(EC_F_EC_GROUP_SET_CURVE_GFP), "EC_GROUP_set_curve_GFp"},
++    {ERR_FUNC(EC_F_EC_GROUP_SET_GENERATOR), "EC_GROUP_set_generator"},
++    {ERR_FUNC(EC_F_EC_KEY_CHECK_KEY), "EC_KEY_check_key"},
++    {ERR_FUNC(EC_F_EC_KEY_COPY), "EC_KEY_copy"},
++    {ERR_FUNC(EC_F_EC_KEY_GENERATE_KEY), "EC_KEY_generate_key"},
++    {ERR_FUNC(EC_F_EC_KEY_NEW), "EC_KEY_new"},
++    {ERR_FUNC(EC_F_EC_KEY_NEW_METHOD), "EC_KEY_new_method"},
++    {ERR_FUNC(EC_F_EC_KEY_OCT2PRIV), "EC_KEY_oct2priv"},
++    {ERR_FUNC(EC_F_EC_KEY_PRINT), "EC_KEY_print"},
++    {ERR_FUNC(EC_F_EC_KEY_PRINT_FP), "EC_KEY_print_fp"},
++    {ERR_FUNC(EC_F_EC_KEY_PRIV2OCT), "EC_KEY_priv2oct"},
++    {ERR_FUNC(EC_F_EC_KEY_SET_PUBLIC_KEY_AFFINE_COORDINATES),
++     "EC_KEY_set_public_key_affine_coordinates"},
++    {ERR_FUNC(EC_F_EC_KEY_SIMPLE_CHECK_KEY), "ec_key_simple_check_key"},
++    {ERR_FUNC(EC_F_EC_KEY_SIMPLE_OCT2PRIV), "ec_key_simple_oct2priv"},
++    {ERR_FUNC(EC_F_EC_KEY_SIMPLE_PRIV2OCT), "ec_key_simple_priv2oct"},
++    {ERR_FUNC(EC_F_EC_POINTS_MAKE_AFFINE), "EC_POINTs_make_affine"},
++    {ERR_FUNC(EC_F_EC_POINT_ADD), "EC_POINT_add"},
++    {ERR_FUNC(EC_F_EC_POINT_CMP), "EC_POINT_cmp"},
++    {ERR_FUNC(EC_F_EC_POINT_COPY), "EC_POINT_copy"},
++    {ERR_FUNC(EC_F_EC_POINT_DBL), "EC_POINT_dbl"},
++    {ERR_FUNC(EC_F_EC_POINT_GET_AFFINE_COORDINATES_GF2M),
++     "EC_POINT_get_affine_coordinates_GF2m"},
++    {ERR_FUNC(EC_F_EC_POINT_GET_AFFINE_COORDINATES_GFP),
++     "EC_POINT_get_affine_coordinates_GFp"},
++    {ERR_FUNC(EC_F_EC_POINT_GET_JPROJECTIVE_COORDINATES_GFP),
++     "EC_POINT_get_Jprojective_coordinates_GFp"},
++    {ERR_FUNC(EC_F_EC_POINT_INVERT), "EC_POINT_invert"},
++    {ERR_FUNC(EC_F_EC_POINT_IS_AT_INFINITY), "EC_POINT_is_at_infinity"},
++    {ERR_FUNC(EC_F_EC_POINT_IS_ON_CURVE), "EC_POINT_is_on_curve"},
++    {ERR_FUNC(EC_F_EC_POINT_MAKE_AFFINE), "EC_POINT_make_affine"},
++    {ERR_FUNC(EC_F_EC_POINT_NEW), "EC_POINT_new"},
++    {ERR_FUNC(EC_F_EC_POINT_OCT2POINT), "EC_POINT_oct2point"},
++    {ERR_FUNC(EC_F_EC_POINT_POINT2OCT), "EC_POINT_point2oct"},
++    {ERR_FUNC(EC_F_EC_POINT_SET_AFFINE_COORDINATES_GF2M),
++     "EC_POINT_set_affine_coordinates_GF2m"},
++    {ERR_FUNC(EC_F_EC_POINT_SET_AFFINE_COORDINATES_GFP),
++     "EC_POINT_set_affine_coordinates_GFp"},
++    {ERR_FUNC(EC_F_EC_POINT_SET_COMPRESSED_COORDINATES_GF2M),
++     "EC_POINT_set_compressed_coordinates_GF2m"},
++    {ERR_FUNC(EC_F_EC_POINT_SET_COMPRESSED_COORDINATES_GFP),
++     "EC_POINT_set_compressed_coordinates_GFp"},
++    {ERR_FUNC(EC_F_EC_POINT_SET_JPROJECTIVE_COORDINATES_GFP),
++     "EC_POINT_set_Jprojective_coordinates_GFp"},
++    {ERR_FUNC(EC_F_EC_POINT_SET_TO_INFINITY), "EC_POINT_set_to_infinity"},
++    {ERR_FUNC(EC_F_EC_PRE_COMP_NEW), "ec_pre_comp_new"},
++    {ERR_FUNC(EC_F_EC_WNAF_MUL), "ec_wNAF_mul"},
++    {ERR_FUNC(EC_F_EC_WNAF_PRECOMPUTE_MULT), "ec_wNAF_precompute_mult"},
++    {ERR_FUNC(EC_F_I2D_ECPARAMETERS), "i2d_ECParameters"},
++    {ERR_FUNC(EC_F_I2D_ECPKPARAMETERS), "i2d_ECPKParameters"},
++    {ERR_FUNC(EC_F_I2D_ECPRIVATEKEY), "i2d_ECPrivateKey"},
++    {ERR_FUNC(EC_F_I2O_ECPUBLICKEY), "i2o_ECPublicKey"},
++    {ERR_FUNC(EC_F_NISTP224_PRE_COMP_NEW), "nistp224_pre_comp_new"},
++    {ERR_FUNC(EC_F_NISTP256_PRE_COMP_NEW), "nistp256_pre_comp_new"},
++    {ERR_FUNC(EC_F_NISTP521_PRE_COMP_NEW), "nistp521_pre_comp_new"},
++    {ERR_FUNC(EC_F_O2I_ECPUBLICKEY), "o2i_ECPublicKey"},
++    {ERR_FUNC(EC_F_OLD_EC_PRIV_DECODE), "old_ec_priv_decode"},
++    {ERR_FUNC(EC_F_OSSL_ECDH_COMPUTE_KEY), "ossl_ecdh_compute_key"},
++    {ERR_FUNC(EC_F_OSSL_ECDSA_SIGN_SIG), "ossl_ecdsa_sign_sig"},
++    {ERR_FUNC(EC_F_OSSL_ECDSA_VERIFY_SIG), "ossl_ecdsa_verify_sig"},
++    {ERR_FUNC(EC_F_PKEY_ECX_DERIVE), "pkey_ecx_derive"},
++    {ERR_FUNC(EC_F_PKEY_EC_CTRL), "pkey_ec_ctrl"},
++    {ERR_FUNC(EC_F_PKEY_EC_CTRL_STR), "pkey_ec_ctrl_str"},
++    {ERR_FUNC(EC_F_PKEY_EC_DERIVE), "pkey_ec_derive"},
++    {ERR_FUNC(EC_F_PKEY_EC_KEYGEN), "pkey_ec_keygen"},
++    {ERR_FUNC(EC_F_PKEY_EC_PARAMGEN), "pkey_ec_paramgen"},
++    {ERR_FUNC(EC_F_PKEY_EC_SIGN), "pkey_ec_sign"},
++    {0, NULL}
++};
++
++static ERR_STRING_DATA EC_str_reasons[] = {
++    {ERR_REASON(EC_R_ASN1_ERROR), "asn1 error"},
++    {ERR_REASON(EC_R_BAD_SIGNATURE), "bad signature"},
++    {ERR_REASON(EC_R_BIGNUM_OUT_OF_RANGE), "bignum out of range"},
++    {ERR_REASON(EC_R_BUFFER_TOO_SMALL), "buffer too small"},
++    {ERR_REASON(EC_R_COORDINATES_OUT_OF_RANGE), "coordinates out of range"},
++    {ERR_REASON(EC_R_CURVE_DOES_NOT_SUPPORT_ECDH),
++     "curve does not support ecdh"},
++    {ERR_REASON(EC_R_CURVE_DOES_NOT_SUPPORT_SIGNING),
++     "curve does not support signing"},
++    {ERR_REASON(EC_R_D2I_ECPKPARAMETERS_FAILURE),
++     "d2i ecpkparameters failure"},
++    {ERR_REASON(EC_R_DECODE_ERROR), "decode error"},
++    {ERR_REASON(EC_R_DISCRIMINANT_IS_ZERO), "discriminant is zero"},
++    {ERR_REASON(EC_R_EC_GROUP_NEW_BY_NAME_FAILURE),
++     "ec group new by name failure"},
++    {ERR_REASON(EC_R_FIELD_TOO_LARGE), "field too large"},
++    {ERR_REASON(EC_R_GF2M_NOT_SUPPORTED), "gf2m not supported"},
++    {ERR_REASON(EC_R_GROUP2PKPARAMETERS_FAILURE),
++     "group2pkparameters failure"},
++    {ERR_REASON(EC_R_I2D_ECPKPARAMETERS_FAILURE),
++     "i2d ecpkparameters failure"},
++    {ERR_REASON(EC_R_INCOMPATIBLE_OBJECTS), "incompatible objects"},
++    {ERR_REASON(EC_R_INVALID_ARGUMENT), "invalid argument"},
++    {ERR_REASON(EC_R_INVALID_COMPRESSED_POINT), "invalid compressed point"},
++    {ERR_REASON(EC_R_INVALID_COMPRESSION_BIT), "invalid compression bit"},
++    {ERR_REASON(EC_R_INVALID_CURVE), "invalid curve"},
++    {ERR_REASON(EC_R_INVALID_DIGEST), "invalid digest"},
++    {ERR_REASON(EC_R_INVALID_DIGEST_TYPE), "invalid digest type"},
++    {ERR_REASON(EC_R_INVALID_ENCODING), "invalid encoding"},
++    {ERR_REASON(EC_R_INVALID_FIELD), "invalid field"},
++    {ERR_REASON(EC_R_INVALID_FORM), "invalid form"},
++    {ERR_REASON(EC_R_INVALID_GROUP_ORDER), "invalid group order"},
++    {ERR_REASON(EC_R_INVALID_KEY), "invalid key"},
++    {ERR_REASON(EC_R_INVALID_OUTPUT_LENGTH), "invalid output length"},
++    {ERR_REASON(EC_R_INVALID_PEER_KEY), "invalid peer key"},
++    {ERR_REASON(EC_R_INVALID_PENTANOMIAL_BASIS), "invalid pentanomial basis"},
++    {ERR_REASON(EC_R_INVALID_PRIVATE_KEY), "invalid private key"},
++    {ERR_REASON(EC_R_INVALID_TRINOMIAL_BASIS), "invalid trinomial basis"},
++    {ERR_REASON(EC_R_KDF_PARAMETER_ERROR), "kdf parameter error"},
++    {ERR_REASON(EC_R_KEYS_NOT_SET), "keys not set"},
++    {ERR_REASON(EC_R_MISSING_PARAMETERS), "missing parameters"},
++    {ERR_REASON(EC_R_MISSING_PRIVATE_KEY), "missing private key"},
++    {ERR_REASON(EC_R_NEED_NEW_SETUP_VALUES), "need new setup values"},
++    {ERR_REASON(EC_R_NOT_A_NIST_PRIME), "not a NIST prime"},
++    {ERR_REASON(EC_R_NOT_IMPLEMENTED), "not implemented"},
++    {ERR_REASON(EC_R_NOT_INITIALIZED), "not initialized"},
++    {ERR_REASON(EC_R_NO_PARAMETERS_SET), "no parameters set"},
++    {ERR_REASON(EC_R_NO_PRIVATE_VALUE), "no private value"},
++    {ERR_REASON(EC_R_OPERATION_NOT_SUPPORTED), "operation not supported"},
++    {ERR_REASON(EC_R_PASSED_NULL_PARAMETER), "passed null parameter"},
++    {ERR_REASON(EC_R_PEER_KEY_ERROR), "peer key error"},
++    {ERR_REASON(EC_R_PKPARAMETERS2GROUP_FAILURE),
++     "pkparameters2group failure"},
++    {ERR_REASON(EC_R_POINT_ARITHMETIC_FAILURE), "point arithmetic failure"},
++    {ERR_REASON(EC_R_POINT_AT_INFINITY), "point at infinity"},
++    {ERR_REASON(EC_R_POINT_IS_NOT_ON_CURVE), "point is not on curve"},
++    {ERR_REASON(EC_R_RANDOM_NUMBER_GENERATION_FAILED),
++     "random number generation failed"},
++    {ERR_REASON(EC_R_SHARED_INFO_ERROR), "shared info error"},
++    {ERR_REASON(EC_R_SLOT_FULL), "slot full"},
++    {ERR_REASON(EC_R_UNDEFINED_GENERATOR), "undefined generator"},
++    {ERR_REASON(EC_R_UNDEFINED_ORDER), "undefined order"},
++    {ERR_REASON(EC_R_UNKNOWN_GROUP), "unknown group"},
++    {ERR_REASON(EC_R_UNKNOWN_ORDER), "unknown order"},
++    {ERR_REASON(EC_R_UNSUPPORTED_FIELD), "unsupported field"},
++    {ERR_REASON(EC_R_WRONG_CURVE_PARAMETERS), "wrong curve parameters"},
++    {ERR_REASON(EC_R_WRONG_ORDER), "wrong order"},
++    {0, NULL}
++};
++
++#endif
++
++int ERR_load_EC_strings(void)
++{
++#ifndef OPENSSL_NO_ERR
++
++    if (ERR_func_error_string(EC_str_functs[0].error) == NULL) {
++        ERR_load_strings(0, EC_str_functs);
++        ERR_load_strings(0, EC_str_reasons);
++    }
++#endif
++    return 1;
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/ec/ec_key.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/ec/ec_key.c
+new file mode 100644
+index 0000000..f1f0afb
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/ec/ec_key.c
+@@ -0,0 +1,637 @@
++/*
++ * Copyright 2002-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++/* ====================================================================
++ * Copyright 2002 Sun Microsystems, Inc. ALL RIGHTS RESERVED.
++ * Portions originally developed by SUN MICROSYSTEMS, INC., and
++ * contributed to the OpenSSL project.
++ */
++
++#include 
++#include 
++#include "ec_lcl.h"
++#include 
++#include 
++
++EC_KEY *EC_KEY_new(void)
++{
++    return EC_KEY_new_method(NULL);
++}
++
++EC_KEY *EC_KEY_new_by_curve_name(int nid)
++{
++    EC_KEY *ret = EC_KEY_new();
++    if (ret == NULL)
++        return NULL;
++    ret->group = EC_GROUP_new_by_curve_name(nid);
++    if (ret->group == NULL) {
++        EC_KEY_free(ret);
++        return NULL;
++    }
++    if (ret->meth->set_group != NULL
++        && ret->meth->set_group(ret, ret->group) == 0) {
++        EC_KEY_free(ret);
++        return NULL;
++    }
++    return ret;
++}
++
++void EC_KEY_free(EC_KEY *r)
++{
++    int i;
++
++    if (r == NULL)
++        return;
++
++    CRYPTO_atomic_add(&r->references, -1, &i, r->lock);
++    REF_PRINT_COUNT("EC_KEY", r);
++    if (i > 0)
++        return;
++    REF_ASSERT_ISNT(i < 0);
++
++    if (r->meth->finish != NULL)
++        r->meth->finish(r);
++
++#ifndef OPENSSL_NO_ENGINE
++    ENGINE_finish(r->engine);
++#endif
++
++    if (r->group && r->group->meth->keyfinish)
++        r->group->meth->keyfinish(r);
++
++    CRYPTO_free_ex_data(CRYPTO_EX_INDEX_EC_KEY, r, &r->ex_data);
++    CRYPTO_THREAD_lock_free(r->lock);
++    EC_GROUP_free(r->group);
++    EC_POINT_free(r->pub_key);
++    BN_clear_free(r->priv_key);
++
++    OPENSSL_clear_free((void *)r, sizeof(EC_KEY));
++}
++
++EC_KEY *EC_KEY_copy(EC_KEY *dest, const EC_KEY *src)
++{
++    if (dest == NULL || src == NULL) {
++        ECerr(EC_F_EC_KEY_COPY, ERR_R_PASSED_NULL_PARAMETER);
++        return NULL;
++    }
++    if (src->meth != dest->meth) {
++        if (dest->meth->finish != NULL)
++            dest->meth->finish(dest);
++        if (dest->group && dest->group->meth->keyfinish)
++            dest->group->meth->keyfinish(dest);
++#ifndef OPENSSL_NO_ENGINE
++        if (ENGINE_finish(dest->engine) == 0)
++            return 0;
++        dest->engine = NULL;
++#endif
++    }
++    /* copy the parameters */
++    if (src->group != NULL) {
++        const EC_METHOD *meth = EC_GROUP_method_of(src->group);
++        /* clear the old group */
++        EC_GROUP_free(dest->group);
++        dest->group = EC_GROUP_new(meth);
++        if (dest->group == NULL)
++            return NULL;
++        if (!EC_GROUP_copy(dest->group, src->group))
++            return NULL;
++
++        /*  copy the public key */
++        if (src->pub_key != NULL) {
++            EC_POINT_free(dest->pub_key);
++            dest->pub_key = EC_POINT_new(src->group);
++            if (dest->pub_key == NULL)
++                return NULL;
++            if (!EC_POINT_copy(dest->pub_key, src->pub_key))
++                return NULL;
++        }
++        /* copy the private key */
++        if (src->priv_key != NULL) {
++            if (dest->priv_key == NULL) {
++                dest->priv_key = BN_new();
++                if (dest->priv_key == NULL)
++                    return NULL;
++            }
++            if (!BN_copy(dest->priv_key, src->priv_key))
++                return NULL;
++            if (src->group->meth->keycopy
++                && src->group->meth->keycopy(dest, src) == 0)
++                return NULL;
++        }
++    }
++
++
++    /* copy the rest */
++    dest->enc_flag = src->enc_flag;
++    dest->conv_form = src->conv_form;
++    dest->version = src->version;
++    dest->flags = src->flags;
++    if (!CRYPTO_dup_ex_data(CRYPTO_EX_INDEX_EC_KEY,
++                            &dest->ex_data, &src->ex_data))
++        return NULL;
++
++    if (src->meth != dest->meth) {
++#ifndef OPENSSL_NO_ENGINE
++        if (src->engine != NULL && ENGINE_init(src->engine) == 0)
++            return NULL;
++        dest->engine = src->engine;
++#endif
++        dest->meth = src->meth;
++    }
++
++    if (src->meth->copy != NULL && src->meth->copy(dest, src) == 0)
++        return NULL;
++
++    return dest;
++}
++
++EC_KEY *EC_KEY_dup(const EC_KEY *ec_key)
++{
++    EC_KEY *ret = EC_KEY_new_method(ec_key->engine);
++
++    if (ret == NULL)
++        return NULL;
++
++    if (EC_KEY_copy(ret, ec_key) == NULL) {
++        EC_KEY_free(ret);
++        return NULL;
++    }
++    return ret;
++}
++
++int EC_KEY_up_ref(EC_KEY *r)
++{
++    int i;
++
++    if (CRYPTO_atomic_add(&r->references, 1, &i, r->lock) <= 0)
++        return 0;
++
++    REF_PRINT_COUNT("EC_KEY", r);
++    REF_ASSERT_ISNT(i < 2);
++    return ((i > 1) ? 1 : 0);
++}
++
++int EC_KEY_generate_key(EC_KEY *eckey)
++{
++    if (eckey == NULL || eckey->group == NULL) {
++        ECerr(EC_F_EC_KEY_GENERATE_KEY, ERR_R_PASSED_NULL_PARAMETER);
++        return 0;
++    }
++    if (eckey->meth->keygen != NULL)
++        return eckey->meth->keygen(eckey);
++    ECerr(EC_F_EC_KEY_GENERATE_KEY, EC_R_OPERATION_NOT_SUPPORTED);
++    return 0;
++}
++
++int ossl_ec_key_gen(EC_KEY *eckey)
++{
++    OPENSSL_assert(eckey->group->meth->keygen != NULL);
++    return eckey->group->meth->keygen(eckey);
++}
++
++int ec_key_simple_generate_key(EC_KEY *eckey)
++{
++    int ok = 0;
++    BN_CTX *ctx = NULL;
++    BIGNUM *priv_key = NULL;
++    const BIGNUM *order = NULL;
++    EC_POINT *pub_key = NULL;
++
++    if ((ctx = BN_CTX_new()) == NULL)
++        goto err;
++
++    if (eckey->priv_key == NULL) {
++        priv_key = BN_new();
++        if (priv_key == NULL)
++            goto err;
++    } else
++        priv_key = eckey->priv_key;
++
++    order = EC_GROUP_get0_order(eckey->group);
++    if (order == NULL)
++        goto err;
++
++    do
++        if (!BN_rand_range(priv_key, order))
++            goto err;
++    while (BN_is_zero(priv_key)) ;
++
++    if (eckey->pub_key == NULL) {
++        pub_key = EC_POINT_new(eckey->group);
++        if (pub_key == NULL)
++            goto err;
++    } else
++        pub_key = eckey->pub_key;
++
++    if (!EC_POINT_mul(eckey->group, pub_key, priv_key, NULL, NULL, ctx))
++        goto err;
++
++    eckey->priv_key = priv_key;
++    eckey->pub_key = pub_key;
++
++    ok = 1;
++
++ err:
++    if (eckey->pub_key == NULL)
++        EC_POINT_free(pub_key);
++    if (eckey->priv_key != priv_key)
++        BN_free(priv_key);
++    BN_CTX_free(ctx);
++    return ok;
++}
++
++int ec_key_simple_generate_public_key(EC_KEY *eckey)
++{
++    return EC_POINT_mul(eckey->group, eckey->pub_key, eckey->priv_key, NULL,
++                        NULL, NULL);
++}
++
++int EC_KEY_check_key(const EC_KEY *eckey)
++{
++    if (eckey == NULL || eckey->group == NULL || eckey->pub_key == NULL) {
++        ECerr(EC_F_EC_KEY_CHECK_KEY, ERR_R_PASSED_NULL_PARAMETER);
++        return 0;
++    }
++
++    if (eckey->group->meth->keycheck == NULL) {
++        ECerr(EC_F_EC_KEY_CHECK_KEY, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
++        return 0;
++    }
++
++    return eckey->group->meth->keycheck(eckey);
++}
++
++int ec_key_simple_check_key(const EC_KEY *eckey)
++{
++    int ok = 0;
++    BN_CTX *ctx = NULL;
++    const BIGNUM *order = NULL;
++    EC_POINT *point = NULL;
++
++    if (eckey == NULL || eckey->group == NULL || eckey->pub_key == NULL) {
++        ECerr(EC_F_EC_KEY_SIMPLE_CHECK_KEY, ERR_R_PASSED_NULL_PARAMETER);
++        return 0;
++    }
++
++    if (EC_POINT_is_at_infinity(eckey->group, eckey->pub_key)) {
++        ECerr(EC_F_EC_KEY_SIMPLE_CHECK_KEY, EC_R_POINT_AT_INFINITY);
++        goto err;
++    }
++
++    if ((ctx = BN_CTX_new()) == NULL)
++        goto err;
++    if ((point = EC_POINT_new(eckey->group)) == NULL)
++        goto err;
++
++    /* testing whether the pub_key is on the elliptic curve */
++    if (EC_POINT_is_on_curve(eckey->group, eckey->pub_key, ctx) <= 0) {
++        ECerr(EC_F_EC_KEY_SIMPLE_CHECK_KEY, EC_R_POINT_IS_NOT_ON_CURVE);
++        goto err;
++    }
++    /* testing whether pub_key * order is the point at infinity */
++    order = eckey->group->order;
++    if (BN_is_zero(order)) {
++        ECerr(EC_F_EC_KEY_SIMPLE_CHECK_KEY, EC_R_INVALID_GROUP_ORDER);
++        goto err;
++    }
++    if (!EC_POINT_mul(eckey->group, point, NULL, eckey->pub_key, order, ctx)) {
++        ECerr(EC_F_EC_KEY_SIMPLE_CHECK_KEY, ERR_R_EC_LIB);
++        goto err;
++    }
++    if (!EC_POINT_is_at_infinity(eckey->group, point)) {
++        ECerr(EC_F_EC_KEY_SIMPLE_CHECK_KEY, EC_R_WRONG_ORDER);
++        goto err;
++    }
++    /*
++     * in case the priv_key is present : check if generator * priv_key ==
++     * pub_key
++     */
++    if (eckey->priv_key != NULL) {
++        if (BN_cmp(eckey->priv_key, order) >= 0) {
++            ECerr(EC_F_EC_KEY_SIMPLE_CHECK_KEY, EC_R_WRONG_ORDER);
++            goto err;
++        }
++        if (!EC_POINT_mul(eckey->group, point, eckey->priv_key,
++                          NULL, NULL, ctx)) {
++            ECerr(EC_F_EC_KEY_SIMPLE_CHECK_KEY, ERR_R_EC_LIB);
++            goto err;
++        }
++        if (EC_POINT_cmp(eckey->group, point, eckey->pub_key, ctx) != 0) {
++            ECerr(EC_F_EC_KEY_SIMPLE_CHECK_KEY, EC_R_INVALID_PRIVATE_KEY);
++            goto err;
++        }
++    }
++    ok = 1;
++ err:
++    BN_CTX_free(ctx);
++    EC_POINT_free(point);
++    return ok;
++}
++
++int EC_KEY_set_public_key_affine_coordinates(EC_KEY *key, BIGNUM *x,
++                                             BIGNUM *y)
++{
++    BN_CTX *ctx = NULL;
++    BIGNUM *tx, *ty;
++    EC_POINT *point = NULL;
++    int ok = 0;
++#ifndef OPENSSL_NO_EC2M
++    int tmp_nid, is_char_two = 0;
++#endif
++
++    if (key == NULL || key->group == NULL || x == NULL || y == NULL) {
++        ECerr(EC_F_EC_KEY_SET_PUBLIC_KEY_AFFINE_COORDINATES,
++              ERR_R_PASSED_NULL_PARAMETER);
++        return 0;
++    }
++    ctx = BN_CTX_new();
++    if (ctx == NULL)
++        return 0;
++
++    BN_CTX_start(ctx);
++    point = EC_POINT_new(key->group);
++
++    if (point == NULL)
++        goto err;
++
++    tx = BN_CTX_get(ctx);
++    ty = BN_CTX_get(ctx);
++    if (ty == NULL)
++        goto err;
++
++#ifndef OPENSSL_NO_EC2M
++    tmp_nid = EC_METHOD_get_field_type(EC_GROUP_method_of(key->group));
++
++    if (tmp_nid == NID_X9_62_characteristic_two_field)
++        is_char_two = 1;
++
++    if (is_char_two) {
++        if (!EC_POINT_set_affine_coordinates_GF2m(key->group, point,
++                                                  x, y, ctx))
++            goto err;
++        if (!EC_POINT_get_affine_coordinates_GF2m(key->group, point,
++                                                  tx, ty, ctx))
++            goto err;
++    } else
++#endif
++    {
++        if (!EC_POINT_set_affine_coordinates_GFp(key->group, point,
++                                                 x, y, ctx))
++            goto err;
++        if (!EC_POINT_get_affine_coordinates_GFp(key->group, point,
++                                                 tx, ty, ctx))
++            goto err;
++    }
++    /*
++     * Check if retrieved coordinates match originals and are less than field
++     * order: if not values are out of range.
++     */
++    if (BN_cmp(x, tx) || BN_cmp(y, ty)
++        || (BN_cmp(x, key->group->field) >= 0)
++        || (BN_cmp(y, key->group->field) >= 0)) {
++        ECerr(EC_F_EC_KEY_SET_PUBLIC_KEY_AFFINE_COORDINATES,
++              EC_R_COORDINATES_OUT_OF_RANGE);
++        goto err;
++    }
++
++    if (!EC_KEY_set_public_key(key, point))
++        goto err;
++
++    if (EC_KEY_check_key(key) == 0)
++        goto err;
++
++    ok = 1;
++
++ err:
++    BN_CTX_end(ctx);
++    BN_CTX_free(ctx);
++    EC_POINT_free(point);
++    return ok;
++
++}
++
++const EC_GROUP *EC_KEY_get0_group(const EC_KEY *key)
++{
++    return key->group;
++}
++
++int EC_KEY_set_group(EC_KEY *key, const EC_GROUP *group)
++{
++    if (key->meth->set_group != NULL && key->meth->set_group(key, group) == 0)
++        return 0;
++    EC_GROUP_free(key->group);
++    key->group = EC_GROUP_dup(group);
++    return (key->group == NULL) ? 0 : 1;
++}
++
++const BIGNUM *EC_KEY_get0_private_key(const EC_KEY *key)
++{
++    return key->priv_key;
++}
++
++int EC_KEY_set_private_key(EC_KEY *key, const BIGNUM *priv_key)
++{
++    if (key->group == NULL || key->group->meth == NULL)
++        return 0;
++    if (key->group->meth->set_private != NULL
++        && key->group->meth->set_private(key, priv_key) == 0)
++        return 0;
++    if (key->meth->set_private != NULL
++        && key->meth->set_private(key, priv_key) == 0)
++        return 0;
++    BN_clear_free(key->priv_key);
++    key->priv_key = BN_dup(priv_key);
++    return (key->priv_key == NULL) ? 0 : 1;
++}
++
++const EC_POINT *EC_KEY_get0_public_key(const EC_KEY *key)
++{
++    return key->pub_key;
++}
++
++int EC_KEY_set_public_key(EC_KEY *key, const EC_POINT *pub_key)
++{
++    if (key->meth->set_public != NULL
++        && key->meth->set_public(key, pub_key) == 0)
++        return 0;
++    EC_POINT_free(key->pub_key);
++    key->pub_key = EC_POINT_dup(pub_key, key->group);
++    return (key->pub_key == NULL) ? 0 : 1;
++}
++
++unsigned int EC_KEY_get_enc_flags(const EC_KEY *key)
++{
++    return key->enc_flag;
++}
++
++void EC_KEY_set_enc_flags(EC_KEY *key, unsigned int flags)
++{
++    key->enc_flag = flags;
++}
++
++point_conversion_form_t EC_KEY_get_conv_form(const EC_KEY *key)
++{
++    return key->conv_form;
++}
++
++void EC_KEY_set_conv_form(EC_KEY *key, point_conversion_form_t cform)
++{
++    key->conv_form = cform;
++    if (key->group != NULL)
++        EC_GROUP_set_point_conversion_form(key->group, cform);
++}
++
++void EC_KEY_set_asn1_flag(EC_KEY *key, int flag)
++{
++    if (key->group != NULL)
++        EC_GROUP_set_asn1_flag(key->group, flag);
++}
++
++int EC_KEY_precompute_mult(EC_KEY *key, BN_CTX *ctx)
++{
++    if (key->group == NULL)
++        return 0;
++    return EC_GROUP_precompute_mult(key->group, ctx);
++}
++
++int EC_KEY_get_flags(const EC_KEY *key)
++{
++    return key->flags;
++}
++
++void EC_KEY_set_flags(EC_KEY *key, int flags)
++{
++    key->flags |= flags;
++}
++
++void EC_KEY_clear_flags(EC_KEY *key, int flags)
++{
++    key->flags &= ~flags;
++}
++
++size_t EC_KEY_key2buf(const EC_KEY *key, point_conversion_form_t form,
++                        unsigned char **pbuf, BN_CTX *ctx)
++{
++    if (key == NULL || key->pub_key == NULL || key->group == NULL)
++        return 0;
++    return EC_POINT_point2buf(key->group, key->pub_key, form, pbuf, ctx);
++}
++
++int EC_KEY_oct2key(EC_KEY *key, const unsigned char *buf, size_t len,
++                   BN_CTX *ctx)
++{
++    if (key == NULL || key->group == NULL)
++        return 0;
++    if (key->pub_key == NULL)
++        key->pub_key = EC_POINT_new(key->group);
++    if (key->pub_key == NULL)
++        return 0;
++    if (EC_POINT_oct2point(key->group, key->pub_key, buf, len, ctx) == 0)
++        return 0;
++    /*
++     * Save the point conversion form.
++     * For non-custom curves the first octet of the buffer (excluding
++     * the last significant bit) contains the point conversion form.
++     * EC_POINT_oct2point() has already performed sanity checking of
++     * the buffer so we know it is valid.
++     */
++    if ((key->group->meth->flags & EC_FLAGS_CUSTOM_CURVE) == 0)
++        key->conv_form = (point_conversion_form_t)(buf[0] & ~0x01);
++    return 1;
++}
++
++size_t EC_KEY_priv2oct(const EC_KEY *eckey,
++                       unsigned char *buf, size_t len)
++{
++    if (eckey->group == NULL || eckey->group->meth == NULL)
++        return 0;
++    if (eckey->group->meth->priv2oct == NULL) {
++        ECerr(EC_F_EC_KEY_PRIV2OCT, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
++        return 0;
++    }
++
++    return eckey->group->meth->priv2oct(eckey, buf, len);
++}
++
++size_t ec_key_simple_priv2oct(const EC_KEY *eckey,
++                              unsigned char *buf, size_t len)
++{
++    size_t buf_len;
++
++    buf_len = (EC_GROUP_order_bits(eckey->group) + 7) / 8;
++    if (eckey->priv_key == NULL)
++        return 0;
++    if (buf == NULL)
++        return buf_len;
++    else if (len < buf_len)
++        return 0;
++
++    /* Octetstring may need leading zeros if BN is to short */
++
++    if (BN_bn2binpad(eckey->priv_key, buf, buf_len) == -1) {
++        ECerr(EC_F_EC_KEY_SIMPLE_PRIV2OCT, EC_R_BUFFER_TOO_SMALL);
++        return 0;
++    }
++
++    return buf_len;
++}
++
++int EC_KEY_oct2priv(EC_KEY *eckey, const unsigned char *buf, size_t len)
++{
++    if (eckey->group == NULL || eckey->group->meth == NULL)
++        return 0;
++    if (eckey->group->meth->oct2priv == NULL) {
++        ECerr(EC_F_EC_KEY_OCT2PRIV, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
++        return 0;
++    }
++    return eckey->group->meth->oct2priv(eckey, buf, len);
++}
++
++int ec_key_simple_oct2priv(EC_KEY *eckey, const unsigned char *buf, size_t len)
++{
++    if (eckey->priv_key == NULL)
++        eckey->priv_key = BN_secure_new();
++    if (eckey->priv_key == NULL) {
++        ECerr(EC_F_EC_KEY_SIMPLE_OCT2PRIV, ERR_R_MALLOC_FAILURE);
++        return 0;
++    }
++    eckey->priv_key = BN_bin2bn(buf, len, eckey->priv_key);
++    if (eckey->priv_key == NULL) {
++        ECerr(EC_F_EC_KEY_SIMPLE_OCT2PRIV, ERR_R_BN_LIB);
++        return 0;
++    }
++    return 1;
++}
++
++size_t EC_KEY_priv2buf(const EC_KEY *eckey, unsigned char **pbuf)
++{
++    size_t len;
++    unsigned char *buf;
++    len = EC_KEY_priv2oct(eckey, NULL, 0);
++    if (len == 0)
++        return 0;
++    buf = OPENSSL_malloc(len);
++    if (buf == NULL)
++        return 0;
++    len = EC_KEY_priv2oct(eckey, buf, len);
++    if (len == 0) {
++        OPENSSL_free(buf);
++        return 0;
++    }
++    *pbuf = buf;
++    return len;
++}
++
++int EC_KEY_can_sign(const EC_KEY *eckey)
++{
++    if (eckey->group == NULL || eckey->group->meth == NULL
++        || (eckey->group->meth->flags & EC_FLAGS_NO_SIGN))
++        return 0;
++    return 1;
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/ec/ec_kmeth.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/ec/ec_kmeth.c
+new file mode 100644
+index 0000000..eb469ba
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/ec/ec_kmeth.c
+@@ -0,0 +1,317 @@
++/*
++ * Copyright 2015-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include 
++#include 
++#include 
++#include "ec_lcl.h"
++
++
++static const EC_KEY_METHOD openssl_ec_key_method = {
++    "OpenSSL EC_KEY method",
++    0,
++    0,0,0,0,0,0,
++    ossl_ec_key_gen,
++    ossl_ecdh_compute_key,
++    ossl_ecdsa_sign,
++    ossl_ecdsa_sign_setup,
++    ossl_ecdsa_sign_sig,
++    ossl_ecdsa_verify,
++    ossl_ecdsa_verify_sig
++};
++
++static const EC_KEY_METHOD *default_ec_key_meth = &openssl_ec_key_method;
++
++const EC_KEY_METHOD *EC_KEY_OpenSSL(void)
++{
++    return &openssl_ec_key_method;
++}
++
++const EC_KEY_METHOD *EC_KEY_get_default_method(void)
++{
++    return default_ec_key_meth;
++}
++
++void EC_KEY_set_default_method(const EC_KEY_METHOD *meth)
++{
++    if (meth == NULL)
++        default_ec_key_meth = &openssl_ec_key_method;
++    else
++        default_ec_key_meth = meth;
++}
++
++const EC_KEY_METHOD *EC_KEY_get_method(const EC_KEY *key)
++{
++    return key->meth;
++}
++
++int EC_KEY_set_method(EC_KEY *key, const EC_KEY_METHOD *meth)
++{
++    void (*finish)(EC_KEY *key) = key->meth->finish;
++
++    if (finish != NULL)
++        finish(key);
++
++#ifndef OPENSSL_NO_ENGINE
++    ENGINE_finish(key->engine);
++    key->engine = NULL;
++#endif
++
++    key->meth = meth;
++    if (meth->init != NULL)
++        return meth->init(key);
++    return 1;
++}
++
++EC_KEY *EC_KEY_new_method(ENGINE *engine)
++{
++    EC_KEY *ret = OPENSSL_zalloc(sizeof(*ret));
++
++    if (ret == NULL) {
++        ECerr(EC_F_EC_KEY_NEW_METHOD, ERR_R_MALLOC_FAILURE);
++        return NULL;
++    }
++
++    ret->references = 1;
++    ret->lock = CRYPTO_THREAD_lock_new();
++    if (ret->lock == NULL) {
++        ECerr(EC_F_EC_KEY_NEW_METHOD, ERR_R_MALLOC_FAILURE);
++        OPENSSL_free(ret);
++        return NULL;
++    }
++
++    ret->meth = EC_KEY_get_default_method();
++#ifndef OPENSSL_NO_ENGINE
++    if (engine != NULL) {
++        if (!ENGINE_init(engine)) {
++            ECerr(EC_F_EC_KEY_NEW_METHOD, ERR_R_ENGINE_LIB);
++            goto err;
++        }
++        ret->engine = engine;
++    } else
++        ret->engine = ENGINE_get_default_EC();
++    if (ret->engine != NULL) {
++        ret->meth = ENGINE_get_EC(ret->engine);
++        if (ret->meth == NULL) {
++            ECerr(EC_F_EC_KEY_NEW_METHOD, ERR_R_ENGINE_LIB);
++            goto err;
++        }
++    }
++#endif
++
++    ret->version = 1;
++    ret->conv_form = POINT_CONVERSION_UNCOMPRESSED;
++
++    if (!CRYPTO_new_ex_data(CRYPTO_EX_INDEX_EC_KEY, ret, &ret->ex_data)) {
++        goto err;
++    }
++
++    if (ret->meth->init != NULL && ret->meth->init(ret) == 0) {
++        ECerr(EC_F_EC_KEY_NEW_METHOD, ERR_R_INIT_FAIL);
++        goto err;
++    }
++    return ret;
++
++err:
++    EC_KEY_free(ret);
++    return NULL;
++}
++
++int ECDH_compute_key(void *out, size_t outlen, const EC_POINT *pub_key,
++                     const EC_KEY *eckey,
++                     void *(*KDF) (const void *in, size_t inlen, void *out,
++                                   size_t *outlen))
++{
++    unsigned char *sec = NULL;
++    size_t seclen;
++    if (eckey->meth->compute_key == NULL) {
++        ECerr(EC_F_ECDH_COMPUTE_KEY, EC_R_OPERATION_NOT_SUPPORTED);
++        return 0;
++    }
++    if (outlen > INT_MAX) {
++        ECerr(EC_F_ECDH_COMPUTE_KEY, EC_R_INVALID_OUTPUT_LENGTH);
++        return 0;
++    }
++    if (!eckey->meth->compute_key(&sec, &seclen, pub_key, eckey))
++        return 0;
++    if (KDF != NULL) {
++        KDF(sec, seclen, out, &outlen);
++    } else {
++        if (outlen > seclen)
++            outlen = seclen;
++        memcpy(out, sec, outlen);
++    }
++    OPENSSL_clear_free(sec, seclen);
++    return outlen;
++}
++
++EC_KEY_METHOD *EC_KEY_METHOD_new(const EC_KEY_METHOD *meth)
++{
++    EC_KEY_METHOD *ret = OPENSSL_zalloc(sizeof(*meth));
++
++    if (ret == NULL)
++        return NULL;
++    if (meth != NULL)
++        *ret = *meth;
++    ret->flags |= EC_KEY_METHOD_DYNAMIC;
++    return ret;
++}
++
++void EC_KEY_METHOD_free(EC_KEY_METHOD *meth)
++{
++    if (meth->flags & EC_KEY_METHOD_DYNAMIC)
++        OPENSSL_free(meth);
++}
++
++void EC_KEY_METHOD_set_init(EC_KEY_METHOD *meth,
++                            int (*init)(EC_KEY *key),
++                            void (*finish)(EC_KEY *key),
++                            int (*copy)(EC_KEY *dest, const EC_KEY *src),
++                            int (*set_group)(EC_KEY *key, const EC_GROUP *grp),
++                            int (*set_private)(EC_KEY *key,
++                                               const BIGNUM *priv_key),
++                            int (*set_public)(EC_KEY *key,
++                                              const EC_POINT *pub_key))
++{
++    meth->init = init;
++    meth->finish = finish;
++    meth->copy = copy;
++    meth->set_group = set_group;
++    meth->set_private = set_private;
++    meth->set_public = set_public;
++}
++
++void EC_KEY_METHOD_set_keygen(EC_KEY_METHOD *meth,
++                              int (*keygen)(EC_KEY *key))
++{
++    meth->keygen = keygen;
++}
++
++void EC_KEY_METHOD_set_compute_key(EC_KEY_METHOD *meth,
++                                   int (*ckey)(unsigned char **psec,
++                                               size_t *pseclen,
++                                               const EC_POINT *pub_key,
++                                               const EC_KEY *ecdh))
++{
++    meth->compute_key = ckey;
++}
++
++void EC_KEY_METHOD_set_sign(EC_KEY_METHOD *meth,
++                            int (*sign)(int type, const unsigned char *dgst,
++                                        int dlen, unsigned char *sig,
++                                        unsigned int *siglen,
++                                        const BIGNUM *kinv, const BIGNUM *r,
++                                        EC_KEY *eckey),
++                            int (*sign_setup)(EC_KEY *eckey, BN_CTX *ctx_in,
++                                              BIGNUM **kinvp, BIGNUM **rp),
++                            ECDSA_SIG *(*sign_sig)(const unsigned char *dgst,
++                                                   int dgst_len,
++                                                   const BIGNUM *in_kinv,
++                                                   const BIGNUM *in_r,
++                                                   EC_KEY *eckey))
++{
++    meth->sign = sign;
++    meth->sign_setup = sign_setup;
++    meth->sign_sig = sign_sig;
++}
++
++void EC_KEY_METHOD_set_verify(EC_KEY_METHOD *meth,
++                              int (*verify)(int type, const unsigned
++                                            char *dgst, int dgst_len,
++                                            const unsigned char *sigbuf,
++                                            int sig_len, EC_KEY *eckey),
++                              int (*verify_sig)(const unsigned char *dgst,
++                                                int dgst_len,
++                                                const ECDSA_SIG *sig,
++                                                EC_KEY *eckey))
++{
++    meth->verify = verify;
++    meth->verify_sig = verify_sig;
++}
++
++void EC_KEY_METHOD_get_init(EC_KEY_METHOD *meth,
++                            int (**pinit)(EC_KEY *key),
++                            void (**pfinish)(EC_KEY *key),
++                            int (**pcopy)(EC_KEY *dest, const EC_KEY *src),
++                            int (**pset_group)(EC_KEY *key,
++                                               const EC_GROUP *grp),
++                            int (**pset_private)(EC_KEY *key,
++                                                 const BIGNUM *priv_key),
++                            int (**pset_public)(EC_KEY *key,
++                                                const EC_POINT *pub_key))
++{
++    if (pinit != NULL)
++        *pinit = meth->init;
++    if (pfinish != NULL)
++        *pfinish = meth->finish;
++    if (pcopy != NULL)
++        *pcopy = meth->copy;
++    if (pset_group != NULL)
++        *pset_group = meth->set_group;
++    if (pset_private != NULL)
++        *pset_private = meth->set_private;
++    if (pset_public != NULL)
++        *pset_public = meth->set_public;
++}
++
++void EC_KEY_METHOD_get_keygen(EC_KEY_METHOD *meth,
++                              int (**pkeygen)(EC_KEY *key))
++{
++    if (pkeygen != NULL)
++        *pkeygen = meth->keygen;
++}
++
++void EC_KEY_METHOD_get_compute_key(EC_KEY_METHOD *meth,
++                                   int (**pck)(unsigned char **pout,
++                                               size_t *poutlen,
++                                               const EC_POINT *pub_key,
++                                               const EC_KEY *ecdh))
++{
++    if (pck != NULL)
++        *pck = meth->compute_key;
++}
++
++void EC_KEY_METHOD_get_sign(EC_KEY_METHOD *meth,
++                            int (**psign)(int type, const unsigned char *dgst,
++                                          int dlen, unsigned char *sig,
++                                          unsigned int *siglen,
++                                          const BIGNUM *kinv, const BIGNUM *r,
++                                          EC_KEY *eckey),
++                            int (**psign_setup)(EC_KEY *eckey, BN_CTX *ctx_in,
++                                                BIGNUM **kinvp, BIGNUM **rp),
++                            ECDSA_SIG *(**psign_sig)(const unsigned char *dgst,
++                                                     int dgst_len,
++                                                     const BIGNUM *in_kinv,
++                                                     const BIGNUM *in_r,
++                                                     EC_KEY *eckey))
++{
++    if (psign != NULL)
++        *psign = meth->sign;
++    if (psign_setup != NULL)
++        *psign_setup = meth->sign_setup;
++    if (psign_sig != NULL)
++        *psign_sig = meth->sign_sig;
++}
++
++void EC_KEY_METHOD_get_verify(EC_KEY_METHOD *meth,
++                              int (**pverify)(int type, const unsigned
++                                              char *dgst, int dgst_len,
++                                              const unsigned char *sigbuf,
++                                              int sig_len, EC_KEY *eckey),
++                              int (**pverify_sig)(const unsigned char *dgst,
++                                                  int dgst_len,
++                                                  const ECDSA_SIG *sig,
++                                                  EC_KEY *eckey))
++{
++    if (pverify != NULL)
++        *pverify = meth->verify;
++    if (pverify_sig != NULL)
++        *pverify_sig = meth->verify_sig;
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/ec/ec_lcl.h b/CryptoPkg/Library/OpensslLib/openssl/crypto/ec/ec_lcl.h
+new file mode 100644
+index 0000000..ded35a7
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/ec/ec_lcl.h
+@@ -0,0 +1,613 @@
++/*
++ * Copyright 2001-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++/* ====================================================================
++ * Copyright 2002 Sun Microsystems, Inc. ALL RIGHTS RESERVED.
++ *
++ * Portions of the attached software ("Contribution") are developed by
++ * SUN MICROSYSTEMS, INC., and are contributed to the OpenSSL project.
++ *
++ * The Contribution is licensed pursuant to the OpenSSL open source
++ * license provided above.
++ *
++ * The elliptic curve binary polynomial software is originally written by
++ * Sheueling Chang Shantz and Douglas Stebila of Sun Microsystems Laboratories.
++ *
++ */
++
++#include 
++
++#include 
++#include 
++#include 
++
++#include "e_os.h"
++
++#if defined(__SUNPRO_C)
++# if __SUNPRO_C >= 0x520
++#  pragma error_messages (off,E_ARRAY_OF_INCOMPLETE_NONAME,E_ARRAY_OF_INCOMPLETE)
++# endif
++#endif
++
++/* Use default functions for poin2oct, oct2point and compressed coordinates */
++#define EC_FLAGS_DEFAULT_OCT    0x1
++
++/* Use custom formats for EC_GROUP, EC_POINT and EC_KEY */
++#define EC_FLAGS_CUSTOM_CURVE   0x2
++
++/* Curve does not support signing operations */
++#define EC_FLAGS_NO_SIGN        0x4
++
++/*
++ * Structure details are not part of the exported interface, so all this may
++ * change in future versions.
++ */
++
++struct ec_method_st {
++    /* Various method flags */
++    int flags;
++    /* used by EC_METHOD_get_field_type: */
++    int field_type;             /* a NID */
++    /*
++     * used by EC_GROUP_new, EC_GROUP_free, EC_GROUP_clear_free,
++     * EC_GROUP_copy:
++     */
++    int (*group_init) (EC_GROUP *);
++    void (*group_finish) (EC_GROUP *);
++    void (*group_clear_finish) (EC_GROUP *);
++    int (*group_copy) (EC_GROUP *, const EC_GROUP *);
++    /* used by EC_GROUP_set_curve_GFp, EC_GROUP_get_curve_GFp, */
++    /* EC_GROUP_set_curve_GF2m, and EC_GROUP_get_curve_GF2m: */
++    int (*group_set_curve) (EC_GROUP *, const BIGNUM *p, const BIGNUM *a,
++                            const BIGNUM *b, BN_CTX *);
++    int (*group_get_curve) (const EC_GROUP *, BIGNUM *p, BIGNUM *a, BIGNUM *b,
++                            BN_CTX *);
++    /* used by EC_GROUP_get_degree: */
++    int (*group_get_degree) (const EC_GROUP *);
++    int (*group_order_bits) (const EC_GROUP *);
++    /* used by EC_GROUP_check: */
++    int (*group_check_discriminant) (const EC_GROUP *, BN_CTX *);
++    /*
++     * used by EC_POINT_new, EC_POINT_free, EC_POINT_clear_free,
++     * EC_POINT_copy:
++     */
++    int (*point_init) (EC_POINT *);
++    void (*point_finish) (EC_POINT *);
++    void (*point_clear_finish) (EC_POINT *);
++    int (*point_copy) (EC_POINT *, const EC_POINT *);
++    /*-
++     * used by EC_POINT_set_to_infinity,
++     * EC_POINT_set_Jprojective_coordinates_GFp,
++     * EC_POINT_get_Jprojective_coordinates_GFp,
++     * EC_POINT_set_affine_coordinates_GFp,     ..._GF2m,
++     * EC_POINT_get_affine_coordinates_GFp,     ..._GF2m,
++     * EC_POINT_set_compressed_coordinates_GFp, ..._GF2m:
++     */
++    int (*point_set_to_infinity) (const EC_GROUP *, EC_POINT *);
++    int (*point_set_Jprojective_coordinates_GFp) (const EC_GROUP *,
++                                                  EC_POINT *, const BIGNUM *x,
++                                                  const BIGNUM *y,
++                                                  const BIGNUM *z, BN_CTX *);
++    int (*point_get_Jprojective_coordinates_GFp) (const EC_GROUP *,
++                                                  const EC_POINT *, BIGNUM *x,
++                                                  BIGNUM *y, BIGNUM *z,
++                                                  BN_CTX *);
++    int (*point_set_affine_coordinates) (const EC_GROUP *, EC_POINT *,
++                                         const BIGNUM *x, const BIGNUM *y,
++                                         BN_CTX *);
++    int (*point_get_affine_coordinates) (const EC_GROUP *, const EC_POINT *,
++                                         BIGNUM *x, BIGNUM *y, BN_CTX *);
++    int (*point_set_compressed_coordinates) (const EC_GROUP *, EC_POINT *,
++                                             const BIGNUM *x, int y_bit,
++                                             BN_CTX *);
++    /* used by EC_POINT_point2oct, EC_POINT_oct2point: */
++    size_t (*point2oct) (const EC_GROUP *, const EC_POINT *,
++                         point_conversion_form_t form, unsigned char *buf,
++                         size_t len, BN_CTX *);
++    int (*oct2point) (const EC_GROUP *, EC_POINT *, const unsigned char *buf,
++                      size_t len, BN_CTX *);
++    /* used by EC_POINT_add, EC_POINT_dbl, ECP_POINT_invert: */
++    int (*add) (const EC_GROUP *, EC_POINT *r, const EC_POINT *a,
++                const EC_POINT *b, BN_CTX *);
++    int (*dbl) (const EC_GROUP *, EC_POINT *r, const EC_POINT *a, BN_CTX *);
++    int (*invert) (const EC_GROUP *, EC_POINT *, BN_CTX *);
++    /*
++     * used by EC_POINT_is_at_infinity, EC_POINT_is_on_curve, EC_POINT_cmp:
++     */
++    int (*is_at_infinity) (const EC_GROUP *, const EC_POINT *);
++    int (*is_on_curve) (const EC_GROUP *, const EC_POINT *, BN_CTX *);
++    int (*point_cmp) (const EC_GROUP *, const EC_POINT *a, const EC_POINT *b,
++                      BN_CTX *);
++    /* used by EC_POINT_make_affine, EC_POINTs_make_affine: */
++    int (*make_affine) (const EC_GROUP *, EC_POINT *, BN_CTX *);
++    int (*points_make_affine) (const EC_GROUP *, size_t num, EC_POINT *[],
++                               BN_CTX *);
++    /*
++     * used by EC_POINTs_mul, EC_POINT_mul, EC_POINT_precompute_mult,
++     * EC_POINT_have_precompute_mult (default implementations are used if the
++     * 'mul' pointer is 0):
++     */
++    int (*mul) (const EC_GROUP *group, EC_POINT *r, const BIGNUM *scalar,
++                size_t num, const EC_POINT *points[], const BIGNUM *scalars[],
++                BN_CTX *);
++    int (*precompute_mult) (EC_GROUP *group, BN_CTX *);
++    int (*have_precompute_mult) (const EC_GROUP *group);
++    /* internal functions */
++    /*
++     * 'field_mul', 'field_sqr', and 'field_div' can be used by 'add' and
++     * 'dbl' so that the same implementations of point operations can be used
++     * with different optimized implementations of expensive field
++     * operations:
++     */
++    int (*field_mul) (const EC_GROUP *, BIGNUM *r, const BIGNUM *a,
++                      const BIGNUM *b, BN_CTX *);
++    int (*field_sqr) (const EC_GROUP *, BIGNUM *r, const BIGNUM *a, BN_CTX *);
++    int (*field_div) (const EC_GROUP *, BIGNUM *r, const BIGNUM *a,
++                      const BIGNUM *b, BN_CTX *);
++    /* e.g. to Montgomery */
++    int (*field_encode) (const EC_GROUP *, BIGNUM *r, const BIGNUM *a,
++                         BN_CTX *);
++    /* e.g. from Montgomery */
++    int (*field_decode) (const EC_GROUP *, BIGNUM *r, const BIGNUM *a,
++                         BN_CTX *);
++    int (*field_set_to_one) (const EC_GROUP *, BIGNUM *r, BN_CTX *);
++    /* private key operations */
++    size_t (*priv2oct)(const EC_KEY *eckey, unsigned char *buf, size_t len);
++    int (*oct2priv)(EC_KEY *eckey, const unsigned char *buf, size_t len);
++    int (*set_private)(EC_KEY *eckey, const BIGNUM *priv_key);
++    int (*keygen)(EC_KEY *eckey);
++    int (*keycheck)(const EC_KEY *eckey);
++    int (*keygenpub)(EC_KEY *eckey);
++    int (*keycopy)(EC_KEY *dst, const EC_KEY *src);
++    void (*keyfinish)(EC_KEY *eckey);
++    /* custom ECDH operation */
++    int (*ecdh_compute_key)(unsigned char **pout, size_t *poutlen,
++                            const EC_POINT *pub_key, const EC_KEY *ecdh);
++};
++
++/*
++ * Types and functions to manipulate pre-computed values.
++ */
++typedef struct nistp224_pre_comp_st NISTP224_PRE_COMP;
++typedef struct nistp256_pre_comp_st NISTP256_PRE_COMP;
++typedef struct nistp521_pre_comp_st NISTP521_PRE_COMP;
++typedef struct nistz256_pre_comp_st NISTZ256_PRE_COMP;
++typedef struct ec_pre_comp_st EC_PRE_COMP;
++
++struct ec_group_st {
++    const EC_METHOD *meth;
++    EC_POINT *generator;        /* optional */
++    BIGNUM *order, *cofactor;
++    int curve_name;             /* optional NID for named curve */
++    int asn1_flag;              /* flag to control the asn1 encoding */
++    point_conversion_form_t asn1_form;
++    unsigned char *seed;        /* optional seed for parameters (appears in
++                                 * ASN1) */
++    size_t seed_len;
++    /*
++     * The following members are handled by the method functions, even if
++     * they appear generic
++     */
++    /*
++     * Field specification. For curves over GF(p), this is the modulus; for
++     * curves over GF(2^m), this is the irreducible polynomial defining the
++     * field.
++     */
++    BIGNUM *field;
++    /*
++     * Field specification for curves over GF(2^m). The irreducible f(t) is
++     * then of the form: t^poly[0] + t^poly[1] + ... + t^poly[k] where m =
++     * poly[0] > poly[1] > ... > poly[k] = 0. The array is terminated with
++     * poly[k+1]=-1. All elliptic curve irreducibles have at most 5 non-zero
++     * terms.
++     */
++    int poly[6];
++    /*
++     * Curve coefficients. (Here the assumption is that BIGNUMs can be used
++     * or abused for all kinds of fields, not just GF(p).) For characteristic
++     * > 3, the curve is defined by a Weierstrass equation of the form y^2 =
++     * x^3 + a*x + b. For characteristic 2, the curve is defined by an
++     * equation of the form y^2 + x*y = x^3 + a*x^2 + b.
++     */
++    BIGNUM *a, *b;
++    /* enable optimized point arithmetics for special case */
++    int a_is_minus3;
++    /* method-specific (e.g., Montgomery structure) */
++    void *field_data1;
++    /* method-specific */
++    void *field_data2;
++    /* method-specific */
++    int (*field_mod_func) (BIGNUM *, const BIGNUM *, const BIGNUM *,
++                           BN_CTX *);
++    /* data for ECDSA inverse */
++    BN_MONT_CTX *mont_data;
++
++    /*
++     * Precomputed values for speed. The PCT_xxx names match the
++     * pre_comp.xxx union names; see the SETPRECOMP and HAVEPRECOMP
++     * macros, below.
++     */
++    enum {
++        PCT_none,
++        PCT_nistp224, PCT_nistp256, PCT_nistp521, PCT_nistz256,
++        PCT_ec
++    } pre_comp_type;
++    union {
++        NISTP224_PRE_COMP *nistp224;
++        NISTP256_PRE_COMP *nistp256;
++        NISTP521_PRE_COMP *nistp521;
++        NISTZ256_PRE_COMP *nistz256;
++        EC_PRE_COMP *ec;
++    } pre_comp;
++};
++
++#define SETPRECOMP(g, type, pre) \
++    g->pre_comp_type = PCT_##type, g->pre_comp.type = pre
++#define HAVEPRECOMP(g, type) \
++    g->pre_comp_type == PCT_##type && g->pre_comp.type != NULL
++
++struct ec_key_st {
++    const EC_KEY_METHOD *meth;
++    ENGINE *engine;
++    int version;
++    EC_GROUP *group;
++    EC_POINT *pub_key;
++    BIGNUM *priv_key;
++    unsigned int enc_flag;
++    point_conversion_form_t conv_form;
++    int references;
++    int flags;
++    CRYPTO_EX_DATA ex_data;
++    CRYPTO_RWLOCK *lock;
++};
++
++struct ec_point_st {
++    const EC_METHOD *meth;
++    /*
++     * All members except 'meth' are handled by the method functions, even if
++     * they appear generic
++     */
++    BIGNUM *X;
++    BIGNUM *Y;
++    BIGNUM *Z;                  /* Jacobian projective coordinates: * (X, Y,
++                                 * Z) represents (X/Z^2, Y/Z^3) if Z != 0 */
++    int Z_is_one;               /* enable optimized point arithmetics for
++                                 * special case */
++};
++
++NISTP224_PRE_COMP *EC_nistp224_pre_comp_dup(NISTP224_PRE_COMP *);
++NISTP256_PRE_COMP *EC_nistp256_pre_comp_dup(NISTP256_PRE_COMP *);
++NISTP521_PRE_COMP *EC_nistp521_pre_comp_dup(NISTP521_PRE_COMP *);
++NISTZ256_PRE_COMP *EC_nistz256_pre_comp_dup(NISTZ256_PRE_COMP *);
++NISTP256_PRE_COMP *EC_nistp256_pre_comp_dup(NISTP256_PRE_COMP *);
++EC_PRE_COMP *EC_ec_pre_comp_dup(EC_PRE_COMP *);
++
++void EC_pre_comp_free(EC_GROUP *group);
++void EC_nistp224_pre_comp_free(NISTP224_PRE_COMP *);
++void EC_nistp256_pre_comp_free(NISTP256_PRE_COMP *);
++void EC_nistp521_pre_comp_free(NISTP521_PRE_COMP *);
++void EC_nistz256_pre_comp_free(NISTZ256_PRE_COMP *);
++void EC_ec_pre_comp_free(EC_PRE_COMP *);
++
++/*
++ * method functions in ec_mult.c (ec_lib.c uses these as defaults if
++ * group->method->mul is 0)
++ */
++int ec_wNAF_mul(const EC_GROUP *group, EC_POINT *r, const BIGNUM *scalar,
++                size_t num, const EC_POINT *points[], const BIGNUM *scalars[],
++                BN_CTX *);
++int ec_wNAF_precompute_mult(EC_GROUP *group, BN_CTX *);
++int ec_wNAF_have_precompute_mult(const EC_GROUP *group);
++
++/* method functions in ecp_smpl.c */
++int ec_GFp_simple_group_init(EC_GROUP *);
++void ec_GFp_simple_group_finish(EC_GROUP *);
++void ec_GFp_simple_group_clear_finish(EC_GROUP *);
++int ec_GFp_simple_group_copy(EC_GROUP *, const EC_GROUP *);
++int ec_GFp_simple_group_set_curve(EC_GROUP *, const BIGNUM *p,
++                                  const BIGNUM *a, const BIGNUM *b, BN_CTX *);
++int ec_GFp_simple_group_get_curve(const EC_GROUP *, BIGNUM *p, BIGNUM *a,
++                                  BIGNUM *b, BN_CTX *);
++int ec_GFp_simple_group_get_degree(const EC_GROUP *);
++int ec_GFp_simple_group_check_discriminant(const EC_GROUP *, BN_CTX *);
++int ec_GFp_simple_point_init(EC_POINT *);
++void ec_GFp_simple_point_finish(EC_POINT *);
++void ec_GFp_simple_point_clear_finish(EC_POINT *);
++int ec_GFp_simple_point_copy(EC_POINT *, const EC_POINT *);
++int ec_GFp_simple_point_set_to_infinity(const EC_GROUP *, EC_POINT *);
++int ec_GFp_simple_set_Jprojective_coordinates_GFp(const EC_GROUP *,
++                                                  EC_POINT *, const BIGNUM *x,
++                                                  const BIGNUM *y,
++                                                  const BIGNUM *z, BN_CTX *);
++int ec_GFp_simple_get_Jprojective_coordinates_GFp(const EC_GROUP *,
++                                                  const EC_POINT *, BIGNUM *x,
++                                                  BIGNUM *y, BIGNUM *z,
++                                                  BN_CTX *);
++int ec_GFp_simple_point_set_affine_coordinates(const EC_GROUP *, EC_POINT *,
++                                               const BIGNUM *x,
++                                               const BIGNUM *y, BN_CTX *);
++int ec_GFp_simple_point_get_affine_coordinates(const EC_GROUP *,
++                                               const EC_POINT *, BIGNUM *x,
++                                               BIGNUM *y, BN_CTX *);
++int ec_GFp_simple_set_compressed_coordinates(const EC_GROUP *, EC_POINT *,
++                                             const BIGNUM *x, int y_bit,
++                                             BN_CTX *);
++size_t ec_GFp_simple_point2oct(const EC_GROUP *, const EC_POINT *,
++                               point_conversion_form_t form,
++                               unsigned char *buf, size_t len, BN_CTX *);
++int ec_GFp_simple_oct2point(const EC_GROUP *, EC_POINT *,
++                            const unsigned char *buf, size_t len, BN_CTX *);
++int ec_GFp_simple_add(const EC_GROUP *, EC_POINT *r, const EC_POINT *a,
++                      const EC_POINT *b, BN_CTX *);
++int ec_GFp_simple_dbl(const EC_GROUP *, EC_POINT *r, const EC_POINT *a,
++                      BN_CTX *);
++int ec_GFp_simple_invert(const EC_GROUP *, EC_POINT *, BN_CTX *);
++int ec_GFp_simple_is_at_infinity(const EC_GROUP *, const EC_POINT *);
++int ec_GFp_simple_is_on_curve(const EC_GROUP *, const EC_POINT *, BN_CTX *);
++int ec_GFp_simple_cmp(const EC_GROUP *, const EC_POINT *a, const EC_POINT *b,
++                      BN_CTX *);
++int ec_GFp_simple_make_affine(const EC_GROUP *, EC_POINT *, BN_CTX *);
++int ec_GFp_simple_points_make_affine(const EC_GROUP *, size_t num,
++                                     EC_POINT *[], BN_CTX *);
++int ec_GFp_simple_field_mul(const EC_GROUP *, BIGNUM *r, const BIGNUM *a,
++                            const BIGNUM *b, BN_CTX *);
++int ec_GFp_simple_field_sqr(const EC_GROUP *, BIGNUM *r, const BIGNUM *a,
++                            BN_CTX *);
++
++/* method functions in ecp_mont.c */
++int ec_GFp_mont_group_init(EC_GROUP *);
++int ec_GFp_mont_group_set_curve(EC_GROUP *, const BIGNUM *p, const BIGNUM *a,
++                                const BIGNUM *b, BN_CTX *);
++void ec_GFp_mont_group_finish(EC_GROUP *);
++void ec_GFp_mont_group_clear_finish(EC_GROUP *);
++int ec_GFp_mont_group_copy(EC_GROUP *, const EC_GROUP *);
++int ec_GFp_mont_field_mul(const EC_GROUP *, BIGNUM *r, const BIGNUM *a,
++                          const BIGNUM *b, BN_CTX *);
++int ec_GFp_mont_field_sqr(const EC_GROUP *, BIGNUM *r, const BIGNUM *a,
++                          BN_CTX *);
++int ec_GFp_mont_field_encode(const EC_GROUP *, BIGNUM *r, const BIGNUM *a,
++                             BN_CTX *);
++int ec_GFp_mont_field_decode(const EC_GROUP *, BIGNUM *r, const BIGNUM *a,
++                             BN_CTX *);
++int ec_GFp_mont_field_set_to_one(const EC_GROUP *, BIGNUM *r, BN_CTX *);
++
++/* method functions in ecp_nist.c */
++int ec_GFp_nist_group_copy(EC_GROUP *dest, const EC_GROUP *src);
++int ec_GFp_nist_group_set_curve(EC_GROUP *, const BIGNUM *p, const BIGNUM *a,
++                                const BIGNUM *b, BN_CTX *);
++int ec_GFp_nist_field_mul(const EC_GROUP *, BIGNUM *r, const BIGNUM *a,
++                          const BIGNUM *b, BN_CTX *);
++int ec_GFp_nist_field_sqr(const EC_GROUP *, BIGNUM *r, const BIGNUM *a,
++                          BN_CTX *);
++
++/* method functions in ec2_smpl.c */
++int ec_GF2m_simple_group_init(EC_GROUP *);
++void ec_GF2m_simple_group_finish(EC_GROUP *);
++void ec_GF2m_simple_group_clear_finish(EC_GROUP *);
++int ec_GF2m_simple_group_copy(EC_GROUP *, const EC_GROUP *);
++int ec_GF2m_simple_group_set_curve(EC_GROUP *, const BIGNUM *p,
++                                   const BIGNUM *a, const BIGNUM *b,
++                                   BN_CTX *);
++int ec_GF2m_simple_group_get_curve(const EC_GROUP *, BIGNUM *p, BIGNUM *a,
++                                   BIGNUM *b, BN_CTX *);
++int ec_GF2m_simple_group_get_degree(const EC_GROUP *);
++int ec_GF2m_simple_group_check_discriminant(const EC_GROUP *, BN_CTX *);
++int ec_GF2m_simple_point_init(EC_POINT *);
++void ec_GF2m_simple_point_finish(EC_POINT *);
++void ec_GF2m_simple_point_clear_finish(EC_POINT *);
++int ec_GF2m_simple_point_copy(EC_POINT *, const EC_POINT *);
++int ec_GF2m_simple_point_set_to_infinity(const EC_GROUP *, EC_POINT *);
++int ec_GF2m_simple_point_set_affine_coordinates(const EC_GROUP *, EC_POINT *,
++                                                const BIGNUM *x,
++                                                const BIGNUM *y, BN_CTX *);
++int ec_GF2m_simple_point_get_affine_coordinates(const EC_GROUP *,
++                                                const EC_POINT *, BIGNUM *x,
++                                                BIGNUM *y, BN_CTX *);
++int ec_GF2m_simple_set_compressed_coordinates(const EC_GROUP *, EC_POINT *,
++                                              const BIGNUM *x, int y_bit,
++                                              BN_CTX *);
++size_t ec_GF2m_simple_point2oct(const EC_GROUP *, const EC_POINT *,
++                                point_conversion_form_t form,
++                                unsigned char *buf, size_t len, BN_CTX *);
++int ec_GF2m_simple_oct2point(const EC_GROUP *, EC_POINT *,
++                             const unsigned char *buf, size_t len, BN_CTX *);
++int ec_GF2m_simple_add(const EC_GROUP *, EC_POINT *r, const EC_POINT *a,
++                       const EC_POINT *b, BN_CTX *);
++int ec_GF2m_simple_dbl(const EC_GROUP *, EC_POINT *r, const EC_POINT *a,
++                       BN_CTX *);
++int ec_GF2m_simple_invert(const EC_GROUP *, EC_POINT *, BN_CTX *);
++int ec_GF2m_simple_is_at_infinity(const EC_GROUP *, const EC_POINT *);
++int ec_GF2m_simple_is_on_curve(const EC_GROUP *, const EC_POINT *, BN_CTX *);
++int ec_GF2m_simple_cmp(const EC_GROUP *, const EC_POINT *a, const EC_POINT *b,
++                       BN_CTX *);
++int ec_GF2m_simple_make_affine(const EC_GROUP *, EC_POINT *, BN_CTX *);
++int ec_GF2m_simple_points_make_affine(const EC_GROUP *, size_t num,
++                                      EC_POINT *[], BN_CTX *);
++int ec_GF2m_simple_field_mul(const EC_GROUP *, BIGNUM *r, const BIGNUM *a,
++                             const BIGNUM *b, BN_CTX *);
++int ec_GF2m_simple_field_sqr(const EC_GROUP *, BIGNUM *r, const BIGNUM *a,
++                             BN_CTX *);
++int ec_GF2m_simple_field_div(const EC_GROUP *, BIGNUM *r, const BIGNUM *a,
++                             const BIGNUM *b, BN_CTX *);
++
++/* method functions in ec2_mult.c */
++int ec_GF2m_simple_mul(const EC_GROUP *group, EC_POINT *r,
++                       const BIGNUM *scalar, size_t num,
++                       const EC_POINT *points[], const BIGNUM *scalars[],
++                       BN_CTX *);
++int ec_GF2m_precompute_mult(EC_GROUP *group, BN_CTX *ctx);
++int ec_GF2m_have_precompute_mult(const EC_GROUP *group);
++
++#ifndef OPENSSL_NO_EC_NISTP_64_GCC_128
++/* method functions in ecp_nistp224.c */
++int ec_GFp_nistp224_group_init(EC_GROUP *group);
++int ec_GFp_nistp224_group_set_curve(EC_GROUP *group, const BIGNUM *p,
++                                    const BIGNUM *a, const BIGNUM *n,
++                                    BN_CTX *);
++int ec_GFp_nistp224_point_get_affine_coordinates(const EC_GROUP *group,
++                                                 const EC_POINT *point,
++                                                 BIGNUM *x, BIGNUM *y,
++                                                 BN_CTX *ctx);
++int ec_GFp_nistp224_mul(const EC_GROUP *group, EC_POINT *r,
++                        const BIGNUM *scalar, size_t num,
++                        const EC_POINT *points[], const BIGNUM *scalars[],
++                        BN_CTX *);
++int ec_GFp_nistp224_points_mul(const EC_GROUP *group, EC_POINT *r,
++                               const BIGNUM *scalar, size_t num,
++                               const EC_POINT *points[],
++                               const BIGNUM *scalars[], BN_CTX *ctx);
++int ec_GFp_nistp224_precompute_mult(EC_GROUP *group, BN_CTX *ctx);
++int ec_GFp_nistp224_have_precompute_mult(const EC_GROUP *group);
++
++/* method functions in ecp_nistp256.c */
++int ec_GFp_nistp256_group_init(EC_GROUP *group);
++int ec_GFp_nistp256_group_set_curve(EC_GROUP *group, const BIGNUM *p,
++                                    const BIGNUM *a, const BIGNUM *n,
++                                    BN_CTX *);
++int ec_GFp_nistp256_point_get_affine_coordinates(const EC_GROUP *group,
++                                                 const EC_POINT *point,
++                                                 BIGNUM *x, BIGNUM *y,
++                                                 BN_CTX *ctx);
++int ec_GFp_nistp256_mul(const EC_GROUP *group, EC_POINT *r,
++                        const BIGNUM *scalar, size_t num,
++                        const EC_POINT *points[], const BIGNUM *scalars[],
++                        BN_CTX *);
++int ec_GFp_nistp256_points_mul(const EC_GROUP *group, EC_POINT *r,
++                               const BIGNUM *scalar, size_t num,
++                               const EC_POINT *points[],
++                               const BIGNUM *scalars[], BN_CTX *ctx);
++int ec_GFp_nistp256_precompute_mult(EC_GROUP *group, BN_CTX *ctx);
++int ec_GFp_nistp256_have_precompute_mult(const EC_GROUP *group);
++
++/* method functions in ecp_nistp521.c */
++int ec_GFp_nistp521_group_init(EC_GROUP *group);
++int ec_GFp_nistp521_group_set_curve(EC_GROUP *group, const BIGNUM *p,
++                                    const BIGNUM *a, const BIGNUM *n,
++                                    BN_CTX *);
++int ec_GFp_nistp521_point_get_affine_coordinates(const EC_GROUP *group,
++                                                 const EC_POINT *point,
++                                                 BIGNUM *x, BIGNUM *y,
++                                                 BN_CTX *ctx);
++int ec_GFp_nistp521_mul(const EC_GROUP *group, EC_POINT *r,
++                        const BIGNUM *scalar, size_t num,
++                        const EC_POINT *points[], const BIGNUM *scalars[],
++                        BN_CTX *);
++int ec_GFp_nistp521_points_mul(const EC_GROUP *group, EC_POINT *r,
++                               const BIGNUM *scalar, size_t num,
++                               const EC_POINT *points[],
++                               const BIGNUM *scalars[], BN_CTX *ctx);
++int ec_GFp_nistp521_precompute_mult(EC_GROUP *group, BN_CTX *ctx);
++int ec_GFp_nistp521_have_precompute_mult(const EC_GROUP *group);
++
++/* utility functions in ecp_nistputil.c */
++void ec_GFp_nistp_points_make_affine_internal(size_t num, void *point_array,
++                                              size_t felem_size,
++                                              void *tmp_felems,
++                                              void (*felem_one) (void *out),
++                                              int (*felem_is_zero) (const void
++                                                                    *in),
++                                              void (*felem_assign) (void *out,
++                                                                    const void
++                                                                    *in),
++                                              void (*felem_square) (void *out,
++                                                                    const void
++                                                                    *in),
++                                              void (*felem_mul) (void *out,
++                                                                 const void
++                                                                 *in1,
++                                                                 const void
++                                                                 *in2),
++                                              void (*felem_inv) (void *out,
++                                                                 const void
++                                                                 *in),
++                                              void (*felem_contract) (void
++                                                                      *out,
++                                                                      const
++                                                                      void
++                                                                      *in));
++void ec_GFp_nistp_recode_scalar_bits(unsigned char *sign,
++                                     unsigned char *digit, unsigned char in);
++#endif
++int ec_precompute_mont_data(EC_GROUP *);
++int ec_group_simple_order_bits(const EC_GROUP *group);
++
++#ifdef ECP_NISTZ256_ASM
++/** Returns GFp methods using montgomery multiplication, with x86-64 optimized
++ * P256. See http://eprint.iacr.org/2013/816.
++ *  \return  EC_METHOD object
++ */
++const EC_METHOD *EC_GFp_nistz256_method(void);
++#endif
++
++size_t ec_key_simple_priv2oct(const EC_KEY *eckey,
++                              unsigned char *buf, size_t len);
++int ec_key_simple_oct2priv(EC_KEY *eckey, const unsigned char *buf, size_t len);
++int ec_key_simple_generate_key(EC_KEY *eckey);
++int ec_key_simple_generate_public_key(EC_KEY *eckey);
++int ec_key_simple_check_key(const EC_KEY *eckey);
++
++/* EC_METHOD definitions */
++
++struct ec_key_method_st {
++    const char *name;
++    int32_t flags;
++    int (*init)(EC_KEY *key);
++    void (*finish)(EC_KEY *key);
++    int (*copy)(EC_KEY *dest, const EC_KEY *src);
++    int (*set_group)(EC_KEY *key, const EC_GROUP *grp);
++    int (*set_private)(EC_KEY *key, const BIGNUM *priv_key);
++    int (*set_public)(EC_KEY *key, const EC_POINT *pub_key);
++    int (*keygen)(EC_KEY *key);
++    int (*compute_key)(unsigned char **pout, size_t *poutlen,
++                       const EC_POINT *pub_key, const EC_KEY *ecdh);
++    int (*sign)(int type, const unsigned char *dgst, int dlen, unsigned char
++                *sig, unsigned int *siglen, const BIGNUM *kinv,
++                const BIGNUM *r, EC_KEY *eckey);
++    int (*sign_setup)(EC_KEY *eckey, BN_CTX *ctx_in, BIGNUM **kinvp,
++                      BIGNUM **rp);
++    ECDSA_SIG *(*sign_sig)(const unsigned char *dgst, int dgst_len,
++                           const BIGNUM *in_kinv, const BIGNUM *in_r,
++                           EC_KEY *eckey);
++
++    int (*verify)(int type, const unsigned char *dgst, int dgst_len,
++                  const unsigned char *sigbuf, int sig_len, EC_KEY *eckey);
++    int (*verify_sig)(const unsigned char *dgst, int dgst_len,
++                      const ECDSA_SIG *sig, EC_KEY *eckey);
++};
++
++#define EC_KEY_METHOD_DYNAMIC   1
++
++int ossl_ec_key_gen(EC_KEY *eckey);
++int ossl_ecdh_compute_key(unsigned char **pout, size_t *poutlen,
++                          const EC_POINT *pub_key, const EC_KEY *ecdh);
++int ecdh_simple_compute_key(unsigned char **pout, size_t *poutlen,
++                            const EC_POINT *pub_key, const EC_KEY *ecdh);
++
++struct ECDSA_SIG_st {
++    BIGNUM *r;
++    BIGNUM *s;
++};
++
++int ossl_ecdsa_sign_setup(EC_KEY *eckey, BN_CTX *ctx_in, BIGNUM **kinvp,
++                          BIGNUM **rp);
++int ossl_ecdsa_sign(int type, const unsigned char *dgst, int dlen,
++                    unsigned char *sig, unsigned int *siglen,
++                    const BIGNUM *kinv, const BIGNUM *r, EC_KEY *eckey);
++ECDSA_SIG *ossl_ecdsa_sign_sig(const unsigned char *dgst, int dgst_len,
++                               const BIGNUM *in_kinv, const BIGNUM *in_r,
++                               EC_KEY *eckey);
++int ossl_ecdsa_verify(int type, const unsigned char *dgst, int dgst_len,
++                      const unsigned char *sigbuf, int sig_len, EC_KEY *eckey);
++int ossl_ecdsa_verify_sig(const unsigned char *dgst, int dgst_len,
++                          const ECDSA_SIG *sig, EC_KEY *eckey);
++
++int X25519(uint8_t out_shared_key[32], const uint8_t private_key[32],
++           const uint8_t peer_public_value[32]);
++void X25519_public_from_private(uint8_t out_public_value[32],
++                                const uint8_t private_key[32]);
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/ec/ec_lib.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/ec/ec_lib.c
+new file mode 100644
+index 0000000..7cb4bfe
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/ec/ec_lib.c
+@@ -0,0 +1,1004 @@
++/*
++ * Copyright 2001-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++/* ====================================================================
++ * Copyright 2002 Sun Microsystems, Inc. ALL RIGHTS RESERVED.
++ * Binary polynomial ECC support in OpenSSL originally developed by
++ * SUN MICROSYSTEMS, INC., and contributed to the OpenSSL project.
++ */
++
++#include 
++
++#include 
++#include 
++
++#include "ec_lcl.h"
++
++/* functions for EC_GROUP objects */
++
++EC_GROUP *EC_GROUP_new(const EC_METHOD *meth)
++{
++    EC_GROUP *ret;
++
++    if (meth == NULL) {
++        ECerr(EC_F_EC_GROUP_NEW, EC_R_SLOT_FULL);
++        return NULL;
++    }
++    if (meth->group_init == 0) {
++        ECerr(EC_F_EC_GROUP_NEW, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
++        return NULL;
++    }
++
++    ret = OPENSSL_zalloc(sizeof(*ret));
++    if (ret == NULL) {
++        ECerr(EC_F_EC_GROUP_NEW, ERR_R_MALLOC_FAILURE);
++        return NULL;
++    }
++
++    ret->meth = meth;
++    if ((ret->meth->flags & EC_FLAGS_CUSTOM_CURVE) == 0) {
++        ret->order = BN_new();
++        if (ret->order == NULL)
++            goto err;
++        ret->cofactor = BN_new();
++        if (ret->cofactor == NULL)
++            goto err;
++    }
++    ret->asn1_flag = OPENSSL_EC_NAMED_CURVE;
++    ret->asn1_form = POINT_CONVERSION_UNCOMPRESSED;
++    if (!meth->group_init(ret))
++        goto err;
++    return ret;
++
++ err:
++    BN_free(ret->order);
++    BN_free(ret->cofactor);
++    OPENSSL_free(ret);
++    return NULL;
++}
++
++void EC_pre_comp_free(EC_GROUP *group)
++{
++    switch (group->pre_comp_type) {
++    default:
++        break;
++#ifdef ECP_NISTZ256_REFERENCE_IMPLEMENTATION
++    case PCT_nistz256:
++        EC_nistz256_pre_comp_free(group->pre_comp.nistz256);
++        break;
++#endif
++#ifndef OPENSSL_NO_EC_NISTP_64_GCC_128
++    case PCT_nistp224:
++        EC_nistp224_pre_comp_free(group->pre_comp.nistp224);
++        break;
++    case PCT_nistp256:
++        EC_nistp256_pre_comp_free(group->pre_comp.nistp256);
++        break;
++    case PCT_nistp521:
++        EC_nistp521_pre_comp_free(group->pre_comp.nistp521);
++        break;
++#endif
++    case PCT_ec:
++        EC_ec_pre_comp_free(group->pre_comp.ec);
++        break;
++    }
++    group->pre_comp.ec = NULL;
++}
++
++void EC_GROUP_free(EC_GROUP *group)
++{
++    if (!group)
++        return;
++
++    if (group->meth->group_finish != 0)
++        group->meth->group_finish(group);
++
++    EC_pre_comp_free(group);
++    BN_MONT_CTX_free(group->mont_data);
++    EC_POINT_free(group->generator);
++    BN_free(group->order);
++    BN_free(group->cofactor);
++    OPENSSL_free(group->seed);
++    OPENSSL_free(group);
++}
++
++void EC_GROUP_clear_free(EC_GROUP *group)
++{
++    if (!group)
++        return;
++
++    if (group->meth->group_clear_finish != 0)
++        group->meth->group_clear_finish(group);
++    else if (group->meth->group_finish != 0)
++        group->meth->group_finish(group);
++
++    EC_pre_comp_free(group);
++    BN_MONT_CTX_free(group->mont_data);
++    EC_POINT_clear_free(group->generator);
++    BN_clear_free(group->order);
++    BN_clear_free(group->cofactor);
++    OPENSSL_clear_free(group->seed, group->seed_len);
++    OPENSSL_clear_free(group, sizeof(*group));
++}
++
++int EC_GROUP_copy(EC_GROUP *dest, const EC_GROUP *src)
++{
++    if (dest->meth->group_copy == 0) {
++        ECerr(EC_F_EC_GROUP_COPY, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
++        return 0;
++    }
++    if (dest->meth != src->meth) {
++        ECerr(EC_F_EC_GROUP_COPY, EC_R_INCOMPATIBLE_OBJECTS);
++        return 0;
++    }
++    if (dest == src)
++        return 1;
++
++    /* Copy precomputed */
++    dest->pre_comp_type = src->pre_comp_type;
++    switch (src->pre_comp_type) {
++    default:
++        dest->pre_comp.ec = NULL;
++        break;
++#ifdef ECP_NISTZ256_REFERENCE_IMPLEMENTATION
++    case PCT_nistz256:
++        dest->pre_comp.nistz256 = EC_nistz256_pre_comp_dup(src->pre_comp.nistz256);
++        break;
++#endif
++#ifndef OPENSSL_NO_EC_NISTP_64_GCC_128
++    case PCT_nistp224:
++        dest->pre_comp.nistp224 = EC_nistp224_pre_comp_dup(src->pre_comp.nistp224);
++        break;
++    case PCT_nistp256:
++        dest->pre_comp.nistp256 = EC_nistp256_pre_comp_dup(src->pre_comp.nistp256);
++        break;
++    case PCT_nistp521:
++        dest->pre_comp.nistp521 = EC_nistp521_pre_comp_dup(src->pre_comp.nistp521);
++        break;
++#endif
++    case PCT_ec:
++        dest->pre_comp.ec = EC_ec_pre_comp_dup(src->pre_comp.ec);
++        break;
++    }
++
++    if (src->mont_data != NULL) {
++        if (dest->mont_data == NULL) {
++            dest->mont_data = BN_MONT_CTX_new();
++            if (dest->mont_data == NULL)
++                return 0;
++        }
++        if (!BN_MONT_CTX_copy(dest->mont_data, src->mont_data))
++            return 0;
++    } else {
++        /* src->generator == NULL */
++        BN_MONT_CTX_free(dest->mont_data);
++        dest->mont_data = NULL;
++    }
++
++    if (src->generator != NULL) {
++        if (dest->generator == NULL) {
++            dest->generator = EC_POINT_new(dest);
++            if (dest->generator == NULL)
++                return 0;
++        }
++        if (!EC_POINT_copy(dest->generator, src->generator))
++            return 0;
++    } else {
++        /* src->generator == NULL */
++        EC_POINT_clear_free(dest->generator);
++        dest->generator = NULL;
++    }
++
++    if ((src->meth->flags & EC_FLAGS_CUSTOM_CURVE) == 0) {
++        if (!BN_copy(dest->order, src->order))
++            return 0;
++        if (!BN_copy(dest->cofactor, src->cofactor))
++            return 0;
++    }
++
++    dest->curve_name = src->curve_name;
++    dest->asn1_flag = src->asn1_flag;
++    dest->asn1_form = src->asn1_form;
++
++    if (src->seed) {
++        OPENSSL_free(dest->seed);
++        dest->seed = OPENSSL_malloc(src->seed_len);
++        if (dest->seed == NULL)
++            return 0;
++        if (!memcpy(dest->seed, src->seed, src->seed_len))
++            return 0;
++        dest->seed_len = src->seed_len;
++    } else {
++        OPENSSL_free(dest->seed);
++        dest->seed = NULL;
++        dest->seed_len = 0;
++    }
++
++    return dest->meth->group_copy(dest, src);
++}
++
++EC_GROUP *EC_GROUP_dup(const EC_GROUP *a)
++{
++    EC_GROUP *t = NULL;
++    int ok = 0;
++
++    if (a == NULL)
++        return NULL;
++
++    if ((t = EC_GROUP_new(a->meth)) == NULL)
++        return (NULL);
++    if (!EC_GROUP_copy(t, a))
++        goto err;
++
++    ok = 1;
++
++ err:
++    if (!ok) {
++        EC_GROUP_free(t);
++        return NULL;
++    }
++        return t;
++}
++
++const EC_METHOD *EC_GROUP_method_of(const EC_GROUP *group)
++{
++    return group->meth;
++}
++
++int EC_METHOD_get_field_type(const EC_METHOD *meth)
++{
++    return meth->field_type;
++}
++
++int EC_GROUP_set_generator(EC_GROUP *group, const EC_POINT *generator,
++                           const BIGNUM *order, const BIGNUM *cofactor)
++{
++    if (generator == NULL) {
++        ECerr(EC_F_EC_GROUP_SET_GENERATOR, ERR_R_PASSED_NULL_PARAMETER);
++        return 0;
++    }
++
++    if (group->generator == NULL) {
++        group->generator = EC_POINT_new(group);
++        if (group->generator == NULL)
++            return 0;
++    }
++    if (!EC_POINT_copy(group->generator, generator))
++        return 0;
++
++    if (order != NULL) {
++        if (!BN_copy(group->order, order))
++            return 0;
++    } else
++        BN_zero(group->order);
++
++    if (cofactor != NULL) {
++        if (!BN_copy(group->cofactor, cofactor))
++            return 0;
++    } else
++        BN_zero(group->cofactor);
++
++    /*
++     * Some groups have an order with
++     * factors of two, which makes the Montgomery setup fail.
++     * |group->mont_data| will be NULL in this case.
++     */
++    if (BN_is_odd(group->order)) {
++        return ec_precompute_mont_data(group);
++    }
++
++    BN_MONT_CTX_free(group->mont_data);
++    group->mont_data = NULL;
++    return 1;
++}
++
++const EC_POINT *EC_GROUP_get0_generator(const EC_GROUP *group)
++{
++    return group->generator;
++}
++
++BN_MONT_CTX *EC_GROUP_get_mont_data(const EC_GROUP *group)
++{
++    return group->mont_data;
++}
++
++int EC_GROUP_get_order(const EC_GROUP *group, BIGNUM *order, BN_CTX *ctx)
++{
++    if (group->order == NULL)
++        return 0;
++    if (!BN_copy(order, group->order))
++        return 0;
++
++    return !BN_is_zero(order);
++}
++
++const BIGNUM *EC_GROUP_get0_order(const EC_GROUP *group)
++{
++    return group->order;
++}
++
++int EC_GROUP_order_bits(const EC_GROUP *group)
++{
++    OPENSSL_assert(group->meth->group_order_bits != NULL);
++    return group->meth->group_order_bits(group);
++}
++
++int EC_GROUP_get_cofactor(const EC_GROUP *group, BIGNUM *cofactor,
++                          BN_CTX *ctx)
++{
++
++    if (group->cofactor == NULL)
++        return 0;
++    if (!BN_copy(cofactor, group->cofactor))
++        return 0;
++
++    return !BN_is_zero(group->cofactor);
++}
++
++const BIGNUM *EC_GROUP_get0_cofactor(const EC_GROUP *group)
++{
++    return group->cofactor;
++}
++
++void EC_GROUP_set_curve_name(EC_GROUP *group, int nid)
++{
++    group->curve_name = nid;
++}
++
++int EC_GROUP_get_curve_name(const EC_GROUP *group)
++{
++    return group->curve_name;
++}
++
++void EC_GROUP_set_asn1_flag(EC_GROUP *group, int flag)
++{
++    group->asn1_flag = flag;
++}
++
++int EC_GROUP_get_asn1_flag(const EC_GROUP *group)
++{
++    return group->asn1_flag;
++}
++
++void EC_GROUP_set_point_conversion_form(EC_GROUP *group,
++                                        point_conversion_form_t form)
++{
++    group->asn1_form = form;
++}
++
++point_conversion_form_t EC_GROUP_get_point_conversion_form(const EC_GROUP
++                                                           *group)
++{
++    return group->asn1_form;
++}
++
++size_t EC_GROUP_set_seed(EC_GROUP *group, const unsigned char *p, size_t len)
++{
++    OPENSSL_free(group->seed);
++    group->seed = NULL;
++    group->seed_len = 0;
++
++    if (!len || !p)
++        return 1;
++
++    if ((group->seed = OPENSSL_malloc(len)) == NULL)
++        return 0;
++    memcpy(group->seed, p, len);
++    group->seed_len = len;
++
++    return len;
++}
++
++unsigned char *EC_GROUP_get0_seed(const EC_GROUP *group)
++{
++    return group->seed;
++}
++
++size_t EC_GROUP_get_seed_len(const EC_GROUP *group)
++{
++    return group->seed_len;
++}
++
++int EC_GROUP_set_curve_GFp(EC_GROUP *group, const BIGNUM *p, const BIGNUM *a,
++                           const BIGNUM *b, BN_CTX *ctx)
++{
++    if (group->meth->group_set_curve == 0) {
++        ECerr(EC_F_EC_GROUP_SET_CURVE_GFP, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
++        return 0;
++    }
++    return group->meth->group_set_curve(group, p, a, b, ctx);
++}
++
++int EC_GROUP_get_curve_GFp(const EC_GROUP *group, BIGNUM *p, BIGNUM *a,
++                           BIGNUM *b, BN_CTX *ctx)
++{
++    if (group->meth->group_get_curve == 0) {
++        ECerr(EC_F_EC_GROUP_GET_CURVE_GFP, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
++        return 0;
++    }
++    return group->meth->group_get_curve(group, p, a, b, ctx);
++}
++
++#ifndef OPENSSL_NO_EC2M
++int EC_GROUP_set_curve_GF2m(EC_GROUP *group, const BIGNUM *p, const BIGNUM *a,
++                            const BIGNUM *b, BN_CTX *ctx)
++{
++    if (group->meth->group_set_curve == 0) {
++        ECerr(EC_F_EC_GROUP_SET_CURVE_GF2M,
++              ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
++        return 0;
++    }
++    return group->meth->group_set_curve(group, p, a, b, ctx);
++}
++
++int EC_GROUP_get_curve_GF2m(const EC_GROUP *group, BIGNUM *p, BIGNUM *a,
++                            BIGNUM *b, BN_CTX *ctx)
++{
++    if (group->meth->group_get_curve == 0) {
++        ECerr(EC_F_EC_GROUP_GET_CURVE_GF2M,
++              ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
++        return 0;
++    }
++    return group->meth->group_get_curve(group, p, a, b, ctx);
++}
++#endif
++
++int EC_GROUP_get_degree(const EC_GROUP *group)
++{
++    if (group->meth->group_get_degree == 0) {
++        ECerr(EC_F_EC_GROUP_GET_DEGREE, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
++        return 0;
++    }
++    return group->meth->group_get_degree(group);
++}
++
++int EC_GROUP_check_discriminant(const EC_GROUP *group, BN_CTX *ctx)
++{
++    if (group->meth->group_check_discriminant == 0) {
++        ECerr(EC_F_EC_GROUP_CHECK_DISCRIMINANT,
++              ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
++        return 0;
++    }
++    return group->meth->group_check_discriminant(group, ctx);
++}
++
++int EC_GROUP_cmp(const EC_GROUP *a, const EC_GROUP *b, BN_CTX *ctx)
++{
++    int r = 0;
++    BIGNUM *a1, *a2, *a3, *b1, *b2, *b3;
++    BN_CTX *ctx_new = NULL;
++
++    /* compare the field types */
++    if (EC_METHOD_get_field_type(EC_GROUP_method_of(a)) !=
++        EC_METHOD_get_field_type(EC_GROUP_method_of(b)))
++        return 1;
++    /* compare the curve name (if present in both) */
++    if (EC_GROUP_get_curve_name(a) && EC_GROUP_get_curve_name(b) &&
++        EC_GROUP_get_curve_name(a) != EC_GROUP_get_curve_name(b))
++        return 1;
++    if (a->meth->flags & EC_FLAGS_CUSTOM_CURVE)
++        return 0;
++
++    if (ctx == NULL)
++        ctx_new = ctx = BN_CTX_new();
++    if (ctx == NULL)
++        return -1;
++
++    BN_CTX_start(ctx);
++    a1 = BN_CTX_get(ctx);
++    a2 = BN_CTX_get(ctx);
++    a3 = BN_CTX_get(ctx);
++    b1 = BN_CTX_get(ctx);
++    b2 = BN_CTX_get(ctx);
++    b3 = BN_CTX_get(ctx);
++    if (b3 == NULL) {
++        BN_CTX_end(ctx);
++        BN_CTX_free(ctx_new);
++        return -1;
++    }
++
++    /*
++     * XXX This approach assumes that the external representation of curves
++     * over the same field type is the same.
++     */
++    if (!a->meth->group_get_curve(a, a1, a2, a3, ctx) ||
++        !b->meth->group_get_curve(b, b1, b2, b3, ctx))
++        r = 1;
++
++    if (r || BN_cmp(a1, b1) || BN_cmp(a2, b2) || BN_cmp(a3, b3))
++        r = 1;
++
++    /* XXX EC_POINT_cmp() assumes that the methods are equal */
++    if (r || EC_POINT_cmp(a, EC_GROUP_get0_generator(a),
++                          EC_GROUP_get0_generator(b), ctx))
++        r = 1;
++
++    if (!r) {
++        const BIGNUM *ao, *bo, *ac, *bc;
++        /* compare the order and cofactor */
++        ao = EC_GROUP_get0_order(a);
++        bo = EC_GROUP_get0_order(b);
++        ac = EC_GROUP_get0_cofactor(a);
++        bc = EC_GROUP_get0_cofactor(b);
++        if (ao == NULL || bo == NULL) {
++            BN_CTX_end(ctx);
++            BN_CTX_free(ctx_new);
++            return -1;
++        }
++        if (BN_cmp(ao, bo) || BN_cmp(ac, bc))
++            r = 1;
++    }
++
++    BN_CTX_end(ctx);
++    BN_CTX_free(ctx_new);
++
++    return r;
++}
++
++/* functions for EC_POINT objects */
++
++EC_POINT *EC_POINT_new(const EC_GROUP *group)
++{
++    EC_POINT *ret;
++
++    if (group == NULL) {
++        ECerr(EC_F_EC_POINT_NEW, ERR_R_PASSED_NULL_PARAMETER);
++        return NULL;
++    }
++    if (group->meth->point_init == 0) {
++        ECerr(EC_F_EC_POINT_NEW, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
++        return NULL;
++    }
++
++    ret = OPENSSL_zalloc(sizeof(*ret));
++    if (ret == NULL) {
++        ECerr(EC_F_EC_POINT_NEW, ERR_R_MALLOC_FAILURE);
++        return NULL;
++    }
++
++    ret->meth = group->meth;
++
++    if (!ret->meth->point_init(ret)) {
++        OPENSSL_free(ret);
++        return NULL;
++    }
++
++    return ret;
++}
++
++void EC_POINT_free(EC_POINT *point)
++{
++    if (!point)
++        return;
++
++    if (point->meth->point_finish != 0)
++        point->meth->point_finish(point);
++    OPENSSL_free(point);
++}
++
++void EC_POINT_clear_free(EC_POINT *point)
++{
++    if (!point)
++        return;
++
++    if (point->meth->point_clear_finish != 0)
++        point->meth->point_clear_finish(point);
++    else if (point->meth->point_finish != 0)
++        point->meth->point_finish(point);
++    OPENSSL_clear_free(point, sizeof(*point));
++}
++
++int EC_POINT_copy(EC_POINT *dest, const EC_POINT *src)
++{
++    if (dest->meth->point_copy == 0) {
++        ECerr(EC_F_EC_POINT_COPY, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
++        return 0;
++    }
++    if (dest->meth != src->meth) {
++        ECerr(EC_F_EC_POINT_COPY, EC_R_INCOMPATIBLE_OBJECTS);
++        return 0;
++    }
++    if (dest == src)
++        return 1;
++    return dest->meth->point_copy(dest, src);
++}
++
++EC_POINT *EC_POINT_dup(const EC_POINT *a, const EC_GROUP *group)
++{
++    EC_POINT *t;
++    int r;
++
++    if (a == NULL)
++        return NULL;
++
++    t = EC_POINT_new(group);
++    if (t == NULL)
++        return (NULL);
++    r = EC_POINT_copy(t, a);
++    if (!r) {
++        EC_POINT_free(t);
++        return NULL;
++    }
++    return t;
++}
++
++const EC_METHOD *EC_POINT_method_of(const EC_POINT *point)
++{
++    return point->meth;
++}
++
++int EC_POINT_set_to_infinity(const EC_GROUP *group, EC_POINT *point)
++{
++    if (group->meth->point_set_to_infinity == 0) {
++        ECerr(EC_F_EC_POINT_SET_TO_INFINITY,
++              ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
++        return 0;
++    }
++    if (group->meth != point->meth) {
++        ECerr(EC_F_EC_POINT_SET_TO_INFINITY, EC_R_INCOMPATIBLE_OBJECTS);
++        return 0;
++    }
++    return group->meth->point_set_to_infinity(group, point);
++}
++
++int EC_POINT_set_Jprojective_coordinates_GFp(const EC_GROUP *group,
++                                             EC_POINT *point, const BIGNUM *x,
++                                             const BIGNUM *y, const BIGNUM *z,
++                                             BN_CTX *ctx)
++{
++    if (group->meth->point_set_Jprojective_coordinates_GFp == 0) {
++        ECerr(EC_F_EC_POINT_SET_JPROJECTIVE_COORDINATES_GFP,
++              ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
++        return 0;
++    }
++    if (group->meth != point->meth) {
++        ECerr(EC_F_EC_POINT_SET_JPROJECTIVE_COORDINATES_GFP,
++              EC_R_INCOMPATIBLE_OBJECTS);
++        return 0;
++    }
++    return group->meth->point_set_Jprojective_coordinates_GFp(group, point, x,
++                                                              y, z, ctx);
++}
++
++int EC_POINT_get_Jprojective_coordinates_GFp(const EC_GROUP *group,
++                                             const EC_POINT *point, BIGNUM *x,
++                                             BIGNUM *y, BIGNUM *z,
++                                             BN_CTX *ctx)
++{
++    if (group->meth->point_get_Jprojective_coordinates_GFp == 0) {
++        ECerr(EC_F_EC_POINT_GET_JPROJECTIVE_COORDINATES_GFP,
++              ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
++        return 0;
++    }
++    if (group->meth != point->meth) {
++        ECerr(EC_F_EC_POINT_GET_JPROJECTIVE_COORDINATES_GFP,
++              EC_R_INCOMPATIBLE_OBJECTS);
++        return 0;
++    }
++    return group->meth->point_get_Jprojective_coordinates_GFp(group, point, x,
++                                                              y, z, ctx);
++}
++
++int EC_POINT_set_affine_coordinates_GFp(const EC_GROUP *group,
++                                        EC_POINT *point, const BIGNUM *x,
++                                        const BIGNUM *y, BN_CTX *ctx)
++{
++    if (group->meth->point_set_affine_coordinates == 0) {
++        ECerr(EC_F_EC_POINT_SET_AFFINE_COORDINATES_GFP,
++              ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
++        return 0;
++    }
++    if (group->meth != point->meth) {
++        ECerr(EC_F_EC_POINT_SET_AFFINE_COORDINATES_GFP,
++              EC_R_INCOMPATIBLE_OBJECTS);
++        return 0;
++    }
++    if (!group->meth->point_set_affine_coordinates(group, point, x, y, ctx))
++        return 0;
++
++    if (EC_POINT_is_on_curve(group, point, ctx) <= 0) {
++        ECerr(EC_F_EC_POINT_SET_AFFINE_COORDINATES_GFP,
++              EC_R_POINT_IS_NOT_ON_CURVE);
++        return 0;
++    }
++    return 1;
++}
++
++#ifndef OPENSSL_NO_EC2M
++int EC_POINT_set_affine_coordinates_GF2m(const EC_GROUP *group,
++                                         EC_POINT *point, const BIGNUM *x,
++                                         const BIGNUM *y, BN_CTX *ctx)
++{
++    if (group->meth->point_set_affine_coordinates == 0) {
++        ECerr(EC_F_EC_POINT_SET_AFFINE_COORDINATES_GF2M,
++              ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
++        return 0;
++    }
++    if (group->meth != point->meth) {
++        ECerr(EC_F_EC_POINT_SET_AFFINE_COORDINATES_GF2M,
++              EC_R_INCOMPATIBLE_OBJECTS);
++        return 0;
++    }
++    if (!group->meth->point_set_affine_coordinates(group, point, x, y, ctx))
++        return 0;
++
++    if (EC_POINT_is_on_curve(group, point, ctx) <= 0) {
++        ECerr(EC_F_EC_POINT_SET_AFFINE_COORDINATES_GF2M,
++              EC_R_POINT_IS_NOT_ON_CURVE);
++        return 0;
++    }
++    return 1;
++}
++#endif
++
++int EC_POINT_get_affine_coordinates_GFp(const EC_GROUP *group,
++                                        const EC_POINT *point, BIGNUM *x,
++                                        BIGNUM *y, BN_CTX *ctx)
++{
++    if (group->meth->point_get_affine_coordinates == 0) {
++        ECerr(EC_F_EC_POINT_GET_AFFINE_COORDINATES_GFP,
++              ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
++        return 0;
++    }
++    if (group->meth != point->meth) {
++        ECerr(EC_F_EC_POINT_GET_AFFINE_COORDINATES_GFP,
++              EC_R_INCOMPATIBLE_OBJECTS);
++        return 0;
++    }
++    return group->meth->point_get_affine_coordinates(group, point, x, y, ctx);
++}
++
++#ifndef OPENSSL_NO_EC2M
++int EC_POINT_get_affine_coordinates_GF2m(const EC_GROUP *group,
++                                         const EC_POINT *point, BIGNUM *x,
++                                         BIGNUM *y, BN_CTX *ctx)
++{
++    if (group->meth->point_get_affine_coordinates == 0) {
++        ECerr(EC_F_EC_POINT_GET_AFFINE_COORDINATES_GF2M,
++              ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
++        return 0;
++    }
++    if (group->meth != point->meth) {
++        ECerr(EC_F_EC_POINT_GET_AFFINE_COORDINATES_GF2M,
++              EC_R_INCOMPATIBLE_OBJECTS);
++        return 0;
++    }
++    return group->meth->point_get_affine_coordinates(group, point, x, y, ctx);
++}
++#endif
++
++int EC_POINT_add(const EC_GROUP *group, EC_POINT *r, const EC_POINT *a,
++                 const EC_POINT *b, BN_CTX *ctx)
++{
++    if (group->meth->add == 0) {
++        ECerr(EC_F_EC_POINT_ADD, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
++        return 0;
++    }
++    if ((group->meth != r->meth) || (r->meth != a->meth)
++        || (a->meth != b->meth)) {
++        ECerr(EC_F_EC_POINT_ADD, EC_R_INCOMPATIBLE_OBJECTS);
++        return 0;
++    }
++    return group->meth->add(group, r, a, b, ctx);
++}
++
++int EC_POINT_dbl(const EC_GROUP *group, EC_POINT *r, const EC_POINT *a,
++                 BN_CTX *ctx)
++{
++    if (group->meth->dbl == 0) {
++        ECerr(EC_F_EC_POINT_DBL, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
++        return 0;
++    }
++    if ((group->meth != r->meth) || (r->meth != a->meth)) {
++        ECerr(EC_F_EC_POINT_DBL, EC_R_INCOMPATIBLE_OBJECTS);
++        return 0;
++    }
++    return group->meth->dbl(group, r, a, ctx);
++}
++
++int EC_POINT_invert(const EC_GROUP *group, EC_POINT *a, BN_CTX *ctx)
++{
++    if (group->meth->invert == 0) {
++        ECerr(EC_F_EC_POINT_INVERT, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
++        return 0;
++    }
++    if (group->meth != a->meth) {
++        ECerr(EC_F_EC_POINT_INVERT, EC_R_INCOMPATIBLE_OBJECTS);
++        return 0;
++    }
++    return group->meth->invert(group, a, ctx);
++}
++
++int EC_POINT_is_at_infinity(const EC_GROUP *group, const EC_POINT *point)
++{
++    if (group->meth->is_at_infinity == 0) {
++        ECerr(EC_F_EC_POINT_IS_AT_INFINITY,
++              ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
++        return 0;
++    }
++    if (group->meth != point->meth) {
++        ECerr(EC_F_EC_POINT_IS_AT_INFINITY, EC_R_INCOMPATIBLE_OBJECTS);
++        return 0;
++    }
++    return group->meth->is_at_infinity(group, point);
++}
++
++/*
++ * Check whether an EC_POINT is on the curve or not. Note that the return
++ * value for this function should NOT be treated as a boolean. Return values:
++ *  1: The point is on the curve
++ *  0: The point is not on the curve
++ * -1: An error occurred
++ */
++int EC_POINT_is_on_curve(const EC_GROUP *group, const EC_POINT *point,
++                         BN_CTX *ctx)
++{
++    if (group->meth->is_on_curve == 0) {
++        ECerr(EC_F_EC_POINT_IS_ON_CURVE, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
++        return 0;
++    }
++    if (group->meth != point->meth) {
++        ECerr(EC_F_EC_POINT_IS_ON_CURVE, EC_R_INCOMPATIBLE_OBJECTS);
++        return 0;
++    }
++    return group->meth->is_on_curve(group, point, ctx);
++}
++
++int EC_POINT_cmp(const EC_GROUP *group, const EC_POINT *a, const EC_POINT *b,
++                 BN_CTX *ctx)
++{
++    if (group->meth->point_cmp == 0) {
++        ECerr(EC_F_EC_POINT_CMP, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
++        return -1;
++    }
++    if ((group->meth != a->meth) || (a->meth != b->meth)) {
++        ECerr(EC_F_EC_POINT_CMP, EC_R_INCOMPATIBLE_OBJECTS);
++        return -1;
++    }
++    return group->meth->point_cmp(group, a, b, ctx);
++}
++
++int EC_POINT_make_affine(const EC_GROUP *group, EC_POINT *point, BN_CTX *ctx)
++{
++    if (group->meth->make_affine == 0) {
++        ECerr(EC_F_EC_POINT_MAKE_AFFINE, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
++        return 0;
++    }
++    if (group->meth != point->meth) {
++        ECerr(EC_F_EC_POINT_MAKE_AFFINE, EC_R_INCOMPATIBLE_OBJECTS);
++        return 0;
++    }
++    return group->meth->make_affine(group, point, ctx);
++}
++
++int EC_POINTs_make_affine(const EC_GROUP *group, size_t num,
++                          EC_POINT *points[], BN_CTX *ctx)
++{
++    size_t i;
++
++    if (group->meth->points_make_affine == 0) {
++        ECerr(EC_F_EC_POINTS_MAKE_AFFINE, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
++        return 0;
++    }
++    for (i = 0; i < num; i++) {
++        if (group->meth != points[i]->meth) {
++            ECerr(EC_F_EC_POINTS_MAKE_AFFINE, EC_R_INCOMPATIBLE_OBJECTS);
++            return 0;
++        }
++    }
++    return group->meth->points_make_affine(group, num, points, ctx);
++}
++
++/*
++ * Functions for point multiplication. If group->meth->mul is 0, we use the
++ * wNAF-based implementations in ec_mult.c; otherwise we dispatch through
++ * methods.
++ */
++
++int EC_POINTs_mul(const EC_GROUP *group, EC_POINT *r, const BIGNUM *scalar,
++                  size_t num, const EC_POINT *points[],
++                  const BIGNUM *scalars[], BN_CTX *ctx)
++{
++    if (group->meth->mul == 0)
++        /* use default */
++        return ec_wNAF_mul(group, r, scalar, num, points, scalars, ctx);
++
++    return group->meth->mul(group, r, scalar, num, points, scalars, ctx);
++}
++
++int EC_POINT_mul(const EC_GROUP *group, EC_POINT *r, const BIGNUM *g_scalar,
++                 const EC_POINT *point, const BIGNUM *p_scalar, BN_CTX *ctx)
++{
++    /* just a convenient interface to EC_POINTs_mul() */
++
++    const EC_POINT *points[1];
++    const BIGNUM *scalars[1];
++
++    points[0] = point;
++    scalars[0] = p_scalar;
++
++    return EC_POINTs_mul(group, r, g_scalar,
++                         (point != NULL
++                          && p_scalar != NULL), points, scalars, ctx);
++}
++
++int EC_GROUP_precompute_mult(EC_GROUP *group, BN_CTX *ctx)
++{
++    if (group->meth->mul == 0)
++        /* use default */
++        return ec_wNAF_precompute_mult(group, ctx);
++
++    if (group->meth->precompute_mult != 0)
++        return group->meth->precompute_mult(group, ctx);
++    else
++        return 1;               /* nothing to do, so report success */
++}
++
++int EC_GROUP_have_precompute_mult(const EC_GROUP *group)
++{
++    if (group->meth->mul == 0)
++        /* use default */
++        return ec_wNAF_have_precompute_mult(group);
++
++    if (group->meth->have_precompute_mult != 0)
++        return group->meth->have_precompute_mult(group);
++    else
++        return 0;               /* cannot tell whether precomputation has
++                                 * been performed */
++}
++
++/*
++ * ec_precompute_mont_data sets |group->mont_data| from |group->order| and
++ * returns one on success. On error it returns zero.
++ */
++int ec_precompute_mont_data(EC_GROUP *group)
++{
++    BN_CTX *ctx = BN_CTX_new();
++    int ret = 0;
++
++    BN_MONT_CTX_free(group->mont_data);
++    group->mont_data = NULL;
++
++    if (ctx == NULL)
++        goto err;
++
++    group->mont_data = BN_MONT_CTX_new();
++    if (group->mont_data == NULL)
++        goto err;
++
++    if (!BN_MONT_CTX_set(group->mont_data, group->order, ctx)) {
++        BN_MONT_CTX_free(group->mont_data);
++        group->mont_data = NULL;
++        goto err;
++    }
++
++    ret = 1;
++
++ err:
++
++    BN_CTX_free(ctx);
++    return ret;
++}
++
++int EC_KEY_set_ex_data(EC_KEY *key, int idx, void *arg)
++{
++    return CRYPTO_set_ex_data(&key->ex_data, idx, arg);
++}
++
++void *EC_KEY_get_ex_data(const EC_KEY *key, int idx)
++{
++    return CRYPTO_get_ex_data(&key->ex_data, idx);
++}
++
++int ec_group_simple_order_bits(const EC_GROUP *group)
++{
++    if (group->order == NULL)
++        return 0;
++    return BN_num_bits(group->order);
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/ec/ec_mult.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/ec/ec_mult.c
+new file mode 100644
+index 0000000..036cdde
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/ec/ec_mult.c
+@@ -0,0 +1,680 @@
++/*
++ * Copyright 2001-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++/* ====================================================================
++ * Copyright 2002 Sun Microsystems, Inc. ALL RIGHTS RESERVED.
++ * Portions of this software developed by SUN MICROSYSTEMS, INC.,
++ * and contributed to the OpenSSL project.
++ */
++
++#include 
++#include 
++
++#include "internal/cryptlib.h"
++#include "internal/bn_int.h"
++#include "ec_lcl.h"
++
++/*
++ * This file implements the wNAF-based interleaving multi-exponentiation method
++ * ();
++ * for multiplication with precomputation, we use wNAF splitting
++ * ().
++ */
++
++/* structure for precomputed multiples of the generator */
++struct ec_pre_comp_st {
++    const EC_GROUP *group;      /* parent EC_GROUP object */
++    size_t blocksize;           /* block size for wNAF splitting */
++    size_t numblocks;           /* max. number of blocks for which we have
++                                 * precomputation */
++    size_t w;                   /* window size */
++    EC_POINT **points;          /* array with pre-calculated multiples of
++                                 * generator: 'num' pointers to EC_POINT
++                                 * objects followed by a NULL */
++    size_t num;                 /* numblocks * 2^(w-1) */
++    int references;
++    CRYPTO_RWLOCK *lock;
++};
++
++static EC_PRE_COMP *ec_pre_comp_new(const EC_GROUP *group)
++{
++    EC_PRE_COMP *ret = NULL;
++
++    if (!group)
++        return NULL;
++
++    ret = OPENSSL_zalloc(sizeof(*ret));
++    if (ret == NULL) {
++        ECerr(EC_F_EC_PRE_COMP_NEW, ERR_R_MALLOC_FAILURE);
++        return ret;
++    }
++
++    ret->group = group;
++    ret->blocksize = 8;         /* default */
++    ret->w = 4;                 /* default */
++    ret->references = 1;
++
++    ret->lock = CRYPTO_THREAD_lock_new();
++    if (ret->lock == NULL) {
++        ECerr(EC_F_EC_PRE_COMP_NEW, ERR_R_MALLOC_FAILURE);
++        OPENSSL_free(ret);
++        return NULL;
++    }
++    return ret;
++}
++
++EC_PRE_COMP *EC_ec_pre_comp_dup(EC_PRE_COMP *pre)
++{
++    int i;
++    if (pre != NULL)
++        CRYPTO_atomic_add(&pre->references, 1, &i, pre->lock);
++    return pre;
++}
++
++void EC_ec_pre_comp_free(EC_PRE_COMP *pre)
++{
++    int i;
++
++    if (pre == NULL)
++        return;
++
++    CRYPTO_atomic_add(&pre->references, -1, &i, pre->lock);
++    REF_PRINT_COUNT("EC_ec", pre);
++    if (i > 0)
++        return;
++    REF_ASSERT_ISNT(i < 0);
++
++    if (pre->points != NULL) {
++        EC_POINT **pts;
++
++        for (pts = pre->points; *pts != NULL; pts++)
++            EC_POINT_free(*pts);
++        OPENSSL_free(pre->points);
++    }
++    CRYPTO_THREAD_lock_free(pre->lock);
++    OPENSSL_free(pre);
++}
++
++/*
++ * TODO: table should be optimised for the wNAF-based implementation,
++ * sometimes smaller windows will give better performance (thus the
++ * boundaries should be increased)
++ */
++#define EC_window_bits_for_scalar_size(b) \
++                ((size_t) \
++                 ((b) >= 2000 ? 6 : \
++                  (b) >=  800 ? 5 : \
++                  (b) >=  300 ? 4 : \
++                  (b) >=   70 ? 3 : \
++                  (b) >=   20 ? 2 : \
++                  1))
++
++/*-
++ * Compute
++ *      \sum scalars[i]*points[i],
++ * also including
++ *      scalar*generator
++ * in the addition if scalar != NULL
++ */
++int ec_wNAF_mul(const EC_GROUP *group, EC_POINT *r, const BIGNUM *scalar,
++                size_t num, const EC_POINT *points[], const BIGNUM *scalars[],
++                BN_CTX *ctx)
++{
++    BN_CTX *new_ctx = NULL;
++    const EC_POINT *generator = NULL;
++    EC_POINT *tmp = NULL;
++    size_t totalnum;
++    size_t blocksize = 0, numblocks = 0; /* for wNAF splitting */
++    size_t pre_points_per_block = 0;
++    size_t i, j;
++    int k;
++    int r_is_inverted = 0;
++    int r_is_at_infinity = 1;
++    size_t *wsize = NULL;       /* individual window sizes */
++    signed char **wNAF = NULL;  /* individual wNAFs */
++    size_t *wNAF_len = NULL;
++    size_t max_len = 0;
++    size_t num_val;
++    EC_POINT **val = NULL;      /* precomputation */
++    EC_POINT **v;
++    EC_POINT ***val_sub = NULL; /* pointers to sub-arrays of 'val' or
++                                 * 'pre_comp->points' */
++    const EC_PRE_COMP *pre_comp = NULL;
++    int num_scalar = 0;         /* flag: will be set to 1 if 'scalar' must be
++                                 * treated like other scalars, i.e.
++                                 * precomputation is not available */
++    int ret = 0;
++
++    if (group->meth != r->meth) {
++        ECerr(EC_F_EC_WNAF_MUL, EC_R_INCOMPATIBLE_OBJECTS);
++        return 0;
++    }
++
++    if ((scalar == NULL) && (num == 0)) {
++        return EC_POINT_set_to_infinity(group, r);
++    }
++
++    for (i = 0; i < num; i++) {
++        if (group->meth != points[i]->meth) {
++            ECerr(EC_F_EC_WNAF_MUL, EC_R_INCOMPATIBLE_OBJECTS);
++            return 0;
++        }
++    }
++
++    if (ctx == NULL) {
++        ctx = new_ctx = BN_CTX_new();
++        if (ctx == NULL)
++            goto err;
++    }
++
++    if (scalar != NULL) {
++        generator = EC_GROUP_get0_generator(group);
++        if (generator == NULL) {
++            ECerr(EC_F_EC_WNAF_MUL, EC_R_UNDEFINED_GENERATOR);
++            goto err;
++        }
++
++        /* look if we can use precomputed multiples of generator */
++
++        pre_comp = group->pre_comp.ec;
++        if (pre_comp && pre_comp->numblocks
++            && (EC_POINT_cmp(group, generator, pre_comp->points[0], ctx) ==
++                0)) {
++            blocksize = pre_comp->blocksize;
++
++            /*
++             * determine maximum number of blocks that wNAF splitting may
++             * yield (NB: maximum wNAF length is bit length plus one)
++             */
++            numblocks = (BN_num_bits(scalar) / blocksize) + 1;
++
++            /*
++             * we cannot use more blocks than we have precomputation for
++             */
++            if (numblocks > pre_comp->numblocks)
++                numblocks = pre_comp->numblocks;
++
++            pre_points_per_block = (size_t)1 << (pre_comp->w - 1);
++
++            /* check that pre_comp looks sane */
++            if (pre_comp->num != (pre_comp->numblocks * pre_points_per_block)) {
++                ECerr(EC_F_EC_WNAF_MUL, ERR_R_INTERNAL_ERROR);
++                goto err;
++            }
++        } else {
++            /* can't use precomputation */
++            pre_comp = NULL;
++            numblocks = 1;
++            num_scalar = 1;     /* treat 'scalar' like 'num'-th element of
++                                 * 'scalars' */
++        }
++    }
++
++    totalnum = num + numblocks;
++
++    wsize = OPENSSL_malloc(totalnum * sizeof wsize[0]);
++    wNAF_len = OPENSSL_malloc(totalnum * sizeof wNAF_len[0]);
++    wNAF = OPENSSL_malloc((totalnum + 1) * sizeof wNAF[0]); /* includes space
++                                                             * for pivot */
++    val_sub = OPENSSL_malloc(totalnum * sizeof val_sub[0]);
++
++    /* Ensure wNAF is initialised in case we end up going to err */
++    if (wNAF != NULL)
++        wNAF[0] = NULL;         /* preliminary pivot */
++
++    if (wsize == NULL || wNAF_len == NULL || wNAF == NULL || val_sub == NULL) {
++        ECerr(EC_F_EC_WNAF_MUL, ERR_R_MALLOC_FAILURE);
++        goto err;
++    }
++
++    /*
++     * num_val will be the total number of temporarily precomputed points
++     */
++    num_val = 0;
++
++    for (i = 0; i < num + num_scalar; i++) {
++        size_t bits;
++
++        bits = i < num ? BN_num_bits(scalars[i]) : BN_num_bits(scalar);
++        wsize[i] = EC_window_bits_for_scalar_size(bits);
++        num_val += (size_t)1 << (wsize[i] - 1);
++        wNAF[i + 1] = NULL;     /* make sure we always have a pivot */
++        wNAF[i] =
++            bn_compute_wNAF((i < num ? scalars[i] : scalar), wsize[i],
++                            &wNAF_len[i]);
++        if (wNAF[i] == NULL)
++            goto err;
++        if (wNAF_len[i] > max_len)
++            max_len = wNAF_len[i];
++    }
++
++    if (numblocks) {
++        /* we go here iff scalar != NULL */
++
++        if (pre_comp == NULL) {
++            if (num_scalar != 1) {
++                ECerr(EC_F_EC_WNAF_MUL, ERR_R_INTERNAL_ERROR);
++                goto err;
++            }
++            /* we have already generated a wNAF for 'scalar' */
++        } else {
++            signed char *tmp_wNAF = NULL;
++            size_t tmp_len = 0;
++
++            if (num_scalar != 0) {
++                ECerr(EC_F_EC_WNAF_MUL, ERR_R_INTERNAL_ERROR);
++                goto err;
++            }
++
++            /*
++             * use the window size for which we have precomputation
++             */
++            wsize[num] = pre_comp->w;
++            tmp_wNAF = bn_compute_wNAF(scalar, wsize[num], &tmp_len);
++            if (!tmp_wNAF)
++                goto err;
++
++            if (tmp_len <= max_len) {
++                /*
++                 * One of the other wNAFs is at least as long as the wNAF
++                 * belonging to the generator, so wNAF splitting will not buy
++                 * us anything.
++                 */
++
++                numblocks = 1;
++                totalnum = num + 1; /* don't use wNAF splitting */
++                wNAF[num] = tmp_wNAF;
++                wNAF[num + 1] = NULL;
++                wNAF_len[num] = tmp_len;
++                /*
++                 * pre_comp->points starts with the points that we need here:
++                 */
++                val_sub[num] = pre_comp->points;
++            } else {
++                /*
++                 * don't include tmp_wNAF directly into wNAF array - use wNAF
++                 * splitting and include the blocks
++                 */
++
++                signed char *pp;
++                EC_POINT **tmp_points;
++
++                if (tmp_len < numblocks * blocksize) {
++                    /*
++                     * possibly we can do with fewer blocks than estimated
++                     */
++                    numblocks = (tmp_len + blocksize - 1) / blocksize;
++                    if (numblocks > pre_comp->numblocks) {
++                        ECerr(EC_F_EC_WNAF_MUL, ERR_R_INTERNAL_ERROR);
++                        OPENSSL_free(tmp_wNAF);
++                        goto err;
++                    }
++                    totalnum = num + numblocks;
++                }
++
++                /* split wNAF in 'numblocks' parts */
++                pp = tmp_wNAF;
++                tmp_points = pre_comp->points;
++
++                for (i = num; i < totalnum; i++) {
++                    if (i < totalnum - 1) {
++                        wNAF_len[i] = blocksize;
++                        if (tmp_len < blocksize) {
++                            ECerr(EC_F_EC_WNAF_MUL, ERR_R_INTERNAL_ERROR);
++                            OPENSSL_free(tmp_wNAF);
++                            goto err;
++                        }
++                        tmp_len -= blocksize;
++                    } else
++                        /*
++                         * last block gets whatever is left (this could be
++                         * more or less than 'blocksize'!)
++                         */
++                        wNAF_len[i] = tmp_len;
++
++                    wNAF[i + 1] = NULL;
++                    wNAF[i] = OPENSSL_malloc(wNAF_len[i]);
++                    if (wNAF[i] == NULL) {
++                        ECerr(EC_F_EC_WNAF_MUL, ERR_R_MALLOC_FAILURE);
++                        OPENSSL_free(tmp_wNAF);
++                        goto err;
++                    }
++                    memcpy(wNAF[i], pp, wNAF_len[i]);
++                    if (wNAF_len[i] > max_len)
++                        max_len = wNAF_len[i];
++
++                    if (*tmp_points == NULL) {
++                        ECerr(EC_F_EC_WNAF_MUL, ERR_R_INTERNAL_ERROR);
++                        OPENSSL_free(tmp_wNAF);
++                        goto err;
++                    }
++                    val_sub[i] = tmp_points;
++                    tmp_points += pre_points_per_block;
++                    pp += blocksize;
++                }
++                OPENSSL_free(tmp_wNAF);
++            }
++        }
++    }
++
++    /*
++     * All points we precompute now go into a single array 'val'.
++     * 'val_sub[i]' is a pointer to the subarray for the i-th point, or to a
++     * subarray of 'pre_comp->points' if we already have precomputation.
++     */
++    val = OPENSSL_malloc((num_val + 1) * sizeof val[0]);
++    if (val == NULL) {
++        ECerr(EC_F_EC_WNAF_MUL, ERR_R_MALLOC_FAILURE);
++        goto err;
++    }
++    val[num_val] = NULL;        /* pivot element */
++
++    /* allocate points for precomputation */
++    v = val;
++    for (i = 0; i < num + num_scalar; i++) {
++        val_sub[i] = v;
++        for (j = 0; j < ((size_t)1 << (wsize[i] - 1)); j++) {
++            *v = EC_POINT_new(group);
++            if (*v == NULL)
++                goto err;
++            v++;
++        }
++    }
++    if (!(v == val + num_val)) {
++        ECerr(EC_F_EC_WNAF_MUL, ERR_R_INTERNAL_ERROR);
++        goto err;
++    }
++
++    if ((tmp = EC_POINT_new(group)) == NULL)
++        goto err;
++
++    /*-
++     * prepare precomputed values:
++     *    val_sub[i][0] :=     points[i]
++     *    val_sub[i][1] := 3 * points[i]
++     *    val_sub[i][2] := 5 * points[i]
++     *    ...
++     */
++    for (i = 0; i < num + num_scalar; i++) {
++        if (i < num) {
++            if (!EC_POINT_copy(val_sub[i][0], points[i]))
++                goto err;
++        } else {
++            if (!EC_POINT_copy(val_sub[i][0], generator))
++                goto err;
++        }
++
++        if (wsize[i] > 1) {
++            if (!EC_POINT_dbl(group, tmp, val_sub[i][0], ctx))
++                goto err;
++            for (j = 1; j < ((size_t)1 << (wsize[i] - 1)); j++) {
++                if (!EC_POINT_add
++                    (group, val_sub[i][j], val_sub[i][j - 1], tmp, ctx))
++                    goto err;
++            }
++        }
++    }
++
++    if (!EC_POINTs_make_affine(group, num_val, val, ctx))
++        goto err;
++
++    r_is_at_infinity = 1;
++
++    for (k = max_len - 1; k >= 0; k--) {
++        if (!r_is_at_infinity) {
++            if (!EC_POINT_dbl(group, r, r, ctx))
++                goto err;
++        }
++
++        for (i = 0; i < totalnum; i++) {
++            if (wNAF_len[i] > (size_t)k) {
++                int digit = wNAF[i][k];
++                int is_neg;
++
++                if (digit) {
++                    is_neg = digit < 0;
++
++                    if (is_neg)
++                        digit = -digit;
++
++                    if (is_neg != r_is_inverted) {
++                        if (!r_is_at_infinity) {
++                            if (!EC_POINT_invert(group, r, ctx))
++                                goto err;
++                        }
++                        r_is_inverted = !r_is_inverted;
++                    }
++
++                    /* digit > 0 */
++
++                    if (r_is_at_infinity) {
++                        if (!EC_POINT_copy(r, val_sub[i][digit >> 1]))
++                            goto err;
++                        r_is_at_infinity = 0;
++                    } else {
++                        if (!EC_POINT_add
++                            (group, r, r, val_sub[i][digit >> 1], ctx))
++                            goto err;
++                    }
++                }
++            }
++        }
++    }
++
++    if (r_is_at_infinity) {
++        if (!EC_POINT_set_to_infinity(group, r))
++            goto err;
++    } else {
++        if (r_is_inverted)
++            if (!EC_POINT_invert(group, r, ctx))
++                goto err;
++    }
++
++    ret = 1;
++
++ err:
++    BN_CTX_free(new_ctx);
++    EC_POINT_free(tmp);
++    OPENSSL_free(wsize);
++    OPENSSL_free(wNAF_len);
++    if (wNAF != NULL) {
++        signed char **w;
++
++        for (w = wNAF; *w != NULL; w++)
++            OPENSSL_free(*w);
++
++        OPENSSL_free(wNAF);
++    }
++    if (val != NULL) {
++        for (v = val; *v != NULL; v++)
++            EC_POINT_clear_free(*v);
++
++        OPENSSL_free(val);
++    }
++    OPENSSL_free(val_sub);
++    return ret;
++}
++
++/*-
++ * ec_wNAF_precompute_mult()
++ * creates an EC_PRE_COMP object with preprecomputed multiples of the generator
++ * for use with wNAF splitting as implemented in ec_wNAF_mul().
++ *
++ * 'pre_comp->points' is an array of multiples of the generator
++ * of the following form:
++ * points[0] =     generator;
++ * points[1] = 3 * generator;
++ * ...
++ * points[2^(w-1)-1] =     (2^(w-1)-1) * generator;
++ * points[2^(w-1)]   =     2^blocksize * generator;
++ * points[2^(w-1)+1] = 3 * 2^blocksize * generator;
++ * ...
++ * points[2^(w-1)*(numblocks-1)-1] = (2^(w-1)) *  2^(blocksize*(numblocks-2)) * generator
++ * points[2^(w-1)*(numblocks-1)]   =              2^(blocksize*(numblocks-1)) * generator
++ * ...
++ * points[2^(w-1)*numblocks-1]     = (2^(w-1)) *  2^(blocksize*(numblocks-1)) * generator
++ * points[2^(w-1)*numblocks]       = NULL
++ */
++int ec_wNAF_precompute_mult(EC_GROUP *group, BN_CTX *ctx)
++{
++    const EC_POINT *generator;
++    EC_POINT *tmp_point = NULL, *base = NULL, **var;
++    BN_CTX *new_ctx = NULL;
++    const BIGNUM *order;
++    size_t i, bits, w, pre_points_per_block, blocksize, numblocks, num;
++    EC_POINT **points = NULL;
++    EC_PRE_COMP *pre_comp;
++    int ret = 0;
++
++    /* if there is an old EC_PRE_COMP object, throw it away */
++    EC_pre_comp_free(group);
++    if ((pre_comp = ec_pre_comp_new(group)) == NULL)
++        return 0;
++
++    generator = EC_GROUP_get0_generator(group);
++    if (generator == NULL) {
++        ECerr(EC_F_EC_WNAF_PRECOMPUTE_MULT, EC_R_UNDEFINED_GENERATOR);
++        goto err;
++    }
++
++    if (ctx == NULL) {
++        ctx = new_ctx = BN_CTX_new();
++        if (ctx == NULL)
++            goto err;
++    }
++
++    BN_CTX_start(ctx);
++
++    order = EC_GROUP_get0_order(group);
++    if (order == NULL)
++        goto err;
++    if (BN_is_zero(order)) {
++        ECerr(EC_F_EC_WNAF_PRECOMPUTE_MULT, EC_R_UNKNOWN_ORDER);
++        goto err;
++    }
++
++    bits = BN_num_bits(order);
++    /*
++     * The following parameters mean we precompute (approximately) one point
++     * per bit. TBD: The combination 8, 4 is perfect for 160 bits; for other
++     * bit lengths, other parameter combinations might provide better
++     * efficiency.
++     */
++    blocksize = 8;
++    w = 4;
++    if (EC_window_bits_for_scalar_size(bits) > w) {
++        /* let's not make the window too small ... */
++        w = EC_window_bits_for_scalar_size(bits);
++    }
++
++    numblocks = (bits + blocksize - 1) / blocksize; /* max. number of blocks
++                                                     * to use for wNAF
++                                                     * splitting */
++
++    pre_points_per_block = (size_t)1 << (w - 1);
++    num = pre_points_per_block * numblocks; /* number of points to compute
++                                             * and store */
++
++    points = OPENSSL_malloc(sizeof(*points) * (num + 1));
++    if (points == NULL) {
++        ECerr(EC_F_EC_WNAF_PRECOMPUTE_MULT, ERR_R_MALLOC_FAILURE);
++        goto err;
++    }
++
++    var = points;
++    var[num] = NULL;            /* pivot */
++    for (i = 0; i < num; i++) {
++        if ((var[i] = EC_POINT_new(group)) == NULL) {
++            ECerr(EC_F_EC_WNAF_PRECOMPUTE_MULT, ERR_R_MALLOC_FAILURE);
++            goto err;
++        }
++    }
++
++    if ((tmp_point = EC_POINT_new(group)) == NULL
++        || (base = EC_POINT_new(group)) == NULL) {
++        ECerr(EC_F_EC_WNAF_PRECOMPUTE_MULT, ERR_R_MALLOC_FAILURE);
++        goto err;
++    }
++
++    if (!EC_POINT_copy(base, generator))
++        goto err;
++
++    /* do the precomputation */
++    for (i = 0; i < numblocks; i++) {
++        size_t j;
++
++        if (!EC_POINT_dbl(group, tmp_point, base, ctx))
++            goto err;
++
++        if (!EC_POINT_copy(*var++, base))
++            goto err;
++
++        for (j = 1; j < pre_points_per_block; j++, var++) {
++            /*
++             * calculate odd multiples of the current base point
++             */
++            if (!EC_POINT_add(group, *var, tmp_point, *(var - 1), ctx))
++                goto err;
++        }
++
++        if (i < numblocks - 1) {
++            /*
++             * get the next base (multiply current one by 2^blocksize)
++             */
++            size_t k;
++
++            if (blocksize <= 2) {
++                ECerr(EC_F_EC_WNAF_PRECOMPUTE_MULT, ERR_R_INTERNAL_ERROR);
++                goto err;
++            }
++
++            if (!EC_POINT_dbl(group, base, tmp_point, ctx))
++                goto err;
++            for (k = 2; k < blocksize; k++) {
++                if (!EC_POINT_dbl(group, base, base, ctx))
++                    goto err;
++            }
++        }
++    }
++
++    if (!EC_POINTs_make_affine(group, num, points, ctx))
++        goto err;
++
++    pre_comp->group = group;
++    pre_comp->blocksize = blocksize;
++    pre_comp->numblocks = numblocks;
++    pre_comp->w = w;
++    pre_comp->points = points;
++    points = NULL;
++    pre_comp->num = num;
++    SETPRECOMP(group, ec, pre_comp);
++    pre_comp = NULL;
++    ret = 1;
++
++ err:
++    if (ctx != NULL)
++        BN_CTX_end(ctx);
++    BN_CTX_free(new_ctx);
++    EC_ec_pre_comp_free(pre_comp);
++    if (points) {
++        EC_POINT **p;
++
++        for (p = points; *p != NULL; p++)
++            EC_POINT_free(*p);
++        OPENSSL_free(points);
++    }
++    EC_POINT_free(tmp_point);
++    EC_POINT_free(base);
++    return ret;
++}
++
++int ec_wNAF_have_precompute_mult(const EC_GROUP *group)
++{
++    return HAVEPRECOMP(group, ec);
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/ec/ec_oct.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/ec/ec_oct.c
+new file mode 100644
+index 0000000..effc42a
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/ec/ec_oct.c
+@@ -0,0 +1,165 @@
++/*
++ * Copyright 2011-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++/* ====================================================================
++ * Copyright 2002 Sun Microsystems, Inc. ALL RIGHTS RESERVED.
++ * Binary polynomial ECC support in OpenSSL originally developed by
++ * SUN MICROSYSTEMS, INC., and contributed to the OpenSSL project.
++ */
++
++#include 
++
++#include 
++#include 
++
++#include "ec_lcl.h"
++
++int EC_POINT_set_compressed_coordinates_GFp(const EC_GROUP *group,
++                                            EC_POINT *point, const BIGNUM *x,
++                                            int y_bit, BN_CTX *ctx)
++{
++    if (group->meth->point_set_compressed_coordinates == 0
++        && !(group->meth->flags & EC_FLAGS_DEFAULT_OCT)) {
++        ECerr(EC_F_EC_POINT_SET_COMPRESSED_COORDINATES_GFP,
++              ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
++        return 0;
++    }
++    if (group->meth != point->meth) {
++        ECerr(EC_F_EC_POINT_SET_COMPRESSED_COORDINATES_GFP,
++              EC_R_INCOMPATIBLE_OBJECTS);
++        return 0;
++    }
++    if (group->meth->flags & EC_FLAGS_DEFAULT_OCT) {
++        if (group->meth->field_type == NID_X9_62_prime_field)
++            return ec_GFp_simple_set_compressed_coordinates(group, point, x,
++                                                            y_bit, ctx);
++        else
++#ifdef OPENSSL_NO_EC2M
++        {
++            ECerr(EC_F_EC_POINT_SET_COMPRESSED_COORDINATES_GFP,
++                  EC_R_GF2M_NOT_SUPPORTED);
++            return 0;
++        }
++#else
++            return ec_GF2m_simple_set_compressed_coordinates(group, point, x,
++                                                             y_bit, ctx);
++#endif
++    }
++    return group->meth->point_set_compressed_coordinates(group, point, x,
++                                                         y_bit, ctx);
++}
++
++#ifndef OPENSSL_NO_EC2M
++int EC_POINT_set_compressed_coordinates_GF2m(const EC_GROUP *group,
++                                             EC_POINT *point, const BIGNUM *x,
++                                             int y_bit, BN_CTX *ctx)
++{
++    if (group->meth->point_set_compressed_coordinates == 0
++        && !(group->meth->flags & EC_FLAGS_DEFAULT_OCT)) {
++        ECerr(EC_F_EC_POINT_SET_COMPRESSED_COORDINATES_GF2M,
++              ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
++        return 0;
++    }
++    if (group->meth != point->meth) {
++        ECerr(EC_F_EC_POINT_SET_COMPRESSED_COORDINATES_GF2M,
++              EC_R_INCOMPATIBLE_OBJECTS);
++        return 0;
++    }
++    if (group->meth->flags & EC_FLAGS_DEFAULT_OCT) {
++        if (group->meth->field_type == NID_X9_62_prime_field)
++            return ec_GFp_simple_set_compressed_coordinates(group, point, x,
++                                                            y_bit, ctx);
++        else
++            return ec_GF2m_simple_set_compressed_coordinates(group, point, x,
++                                                             y_bit, ctx);
++    }
++    return group->meth->point_set_compressed_coordinates(group, point, x,
++                                                         y_bit, ctx);
++}
++#endif
++
++size_t EC_POINT_point2oct(const EC_GROUP *group, const EC_POINT *point,
++                          point_conversion_form_t form, unsigned char *buf,
++                          size_t len, BN_CTX *ctx)
++{
++    if (group->meth->point2oct == 0
++        && !(group->meth->flags & EC_FLAGS_DEFAULT_OCT)) {
++        ECerr(EC_F_EC_POINT_POINT2OCT, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
++        return 0;
++    }
++    if (group->meth != point->meth) {
++        ECerr(EC_F_EC_POINT_POINT2OCT, EC_R_INCOMPATIBLE_OBJECTS);
++        return 0;
++    }
++    if (group->meth->flags & EC_FLAGS_DEFAULT_OCT) {
++        if (group->meth->field_type == NID_X9_62_prime_field)
++            return ec_GFp_simple_point2oct(group, point, form, buf, len, ctx);
++        else
++#ifdef OPENSSL_NO_EC2M
++        {
++            ECerr(EC_F_EC_POINT_POINT2OCT, EC_R_GF2M_NOT_SUPPORTED);
++            return 0;
++        }
++#else
++            return ec_GF2m_simple_point2oct(group, point,
++                                            form, buf, len, ctx);
++#endif
++    }
++
++    return group->meth->point2oct(group, point, form, buf, len, ctx);
++}
++
++int EC_POINT_oct2point(const EC_GROUP *group, EC_POINT *point,
++                       const unsigned char *buf, size_t len, BN_CTX *ctx)
++{
++    if (group->meth->oct2point == 0
++        && !(group->meth->flags & EC_FLAGS_DEFAULT_OCT)) {
++        ECerr(EC_F_EC_POINT_OCT2POINT, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
++        return 0;
++    }
++    if (group->meth != point->meth) {
++        ECerr(EC_F_EC_POINT_OCT2POINT, EC_R_INCOMPATIBLE_OBJECTS);
++        return 0;
++    }
++    if (group->meth->flags & EC_FLAGS_DEFAULT_OCT) {
++        if (group->meth->field_type == NID_X9_62_prime_field)
++            return ec_GFp_simple_oct2point(group, point, buf, len, ctx);
++        else
++#ifdef OPENSSL_NO_EC2M
++        {
++            ECerr(EC_F_EC_POINT_OCT2POINT, EC_R_GF2M_NOT_SUPPORTED);
++            return 0;
++        }
++#else
++            return ec_GF2m_simple_oct2point(group, point, buf, len, ctx);
++#endif
++    }
++    return group->meth->oct2point(group, point, buf, len, ctx);
++}
++
++size_t EC_POINT_point2buf(const EC_GROUP *group, const EC_POINT *point,
++                          point_conversion_form_t form,
++                          unsigned char **pbuf, BN_CTX *ctx)
++{
++    size_t len;
++    unsigned char *buf;
++    len = EC_POINT_point2oct(group, point, form, NULL, 0, NULL);
++    if (len == 0)
++        return 0;
++    buf = OPENSSL_malloc(len);
++    if (buf == NULL)
++        return 0;
++    len = EC_POINT_point2oct(group, point, form, buf, len, ctx);
++    if (len == 0) {
++        OPENSSL_free(buf);
++        return 0;
++    }
++    *pbuf = buf;
++    return len;
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/ec/ec_pmeth.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/ec/ec_pmeth.c
+new file mode 100644
+index 0000000..68ff2bb
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/ec/ec_pmeth.c
+@@ -0,0 +1,463 @@
++/*
++ * Copyright 2006-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include "internal/cryptlib.h"
++#include 
++#include 
++#include 
++#include "ec_lcl.h"
++#include 
++#include "internal/evp_int.h"
++
++/* EC pkey context structure */
++
++typedef struct {
++    /* Key and paramgen group */
++    EC_GROUP *gen_group;
++    /* message digest */
++    const EVP_MD *md;
++    /* Duplicate key if custom cofactor needed */
++    EC_KEY *co_key;
++    /* Cofactor mode */
++    signed char cofactor_mode;
++    /* KDF (if any) to use for ECDH */
++    char kdf_type;
++    /* Message digest to use for key derivation */
++    const EVP_MD *kdf_md;
++    /* User key material */
++    unsigned char *kdf_ukm;
++    size_t kdf_ukmlen;
++    /* KDF output length */
++    size_t kdf_outlen;
++} EC_PKEY_CTX;
++
++static int pkey_ec_init(EVP_PKEY_CTX *ctx)
++{
++    EC_PKEY_CTX *dctx;
++
++    dctx = OPENSSL_zalloc(sizeof(*dctx));
++    if (dctx == NULL)
++        return 0;
++
++    dctx->cofactor_mode = -1;
++    dctx->kdf_type = EVP_PKEY_ECDH_KDF_NONE;
++    ctx->data = dctx;
++    return 1;
++}
++
++static int pkey_ec_copy(EVP_PKEY_CTX *dst, EVP_PKEY_CTX *src)
++{
++    EC_PKEY_CTX *dctx, *sctx;
++    if (!pkey_ec_init(dst))
++        return 0;
++    sctx = src->data;
++    dctx = dst->data;
++    if (sctx->gen_group) {
++        dctx->gen_group = EC_GROUP_dup(sctx->gen_group);
++        if (!dctx->gen_group)
++            return 0;
++    }
++    dctx->md = sctx->md;
++
++    if (sctx->co_key) {
++        dctx->co_key = EC_KEY_dup(sctx->co_key);
++        if (!dctx->co_key)
++            return 0;
++    }
++    dctx->kdf_type = sctx->kdf_type;
++    dctx->kdf_md = sctx->kdf_md;
++    dctx->kdf_outlen = sctx->kdf_outlen;
++    if (sctx->kdf_ukm) {
++        dctx->kdf_ukm = OPENSSL_memdup(sctx->kdf_ukm, sctx->kdf_ukmlen);
++        if (!dctx->kdf_ukm)
++            return 0;
++    } else
++        dctx->kdf_ukm = NULL;
++    dctx->kdf_ukmlen = sctx->kdf_ukmlen;
++    return 1;
++}
++
++static void pkey_ec_cleanup(EVP_PKEY_CTX *ctx)
++{
++    EC_PKEY_CTX *dctx = ctx->data;
++    if (dctx) {
++        EC_GROUP_free(dctx->gen_group);
++        EC_KEY_free(dctx->co_key);
++        OPENSSL_free(dctx->kdf_ukm);
++        OPENSSL_free(dctx);
++    }
++}
++
++static int pkey_ec_sign(EVP_PKEY_CTX *ctx, unsigned char *sig, size_t *siglen,
++                        const unsigned char *tbs, size_t tbslen)
++{
++    int ret, type;
++    unsigned int sltmp;
++    EC_PKEY_CTX *dctx = ctx->data;
++    EC_KEY *ec = ctx->pkey->pkey.ec;
++
++    if (!sig) {
++        *siglen = ECDSA_size(ec);
++        return 1;
++    } else if (*siglen < (size_t)ECDSA_size(ec)) {
++        ECerr(EC_F_PKEY_EC_SIGN, EC_R_BUFFER_TOO_SMALL);
++        return 0;
++    }
++
++    if (dctx->md)
++        type = EVP_MD_type(dctx->md);
++    else
++        type = NID_sha1;
++
++    ret = ECDSA_sign(type, tbs, tbslen, sig, &sltmp, ec);
++
++    if (ret <= 0)
++        return ret;
++    *siglen = (size_t)sltmp;
++    return 1;
++}
++
++static int pkey_ec_verify(EVP_PKEY_CTX *ctx,
++                          const unsigned char *sig, size_t siglen,
++                          const unsigned char *tbs, size_t tbslen)
++{
++    int ret, type;
++    EC_PKEY_CTX *dctx = ctx->data;
++    EC_KEY *ec = ctx->pkey->pkey.ec;
++
++    if (dctx->md)
++        type = EVP_MD_type(dctx->md);
++    else
++        type = NID_sha1;
++
++    ret = ECDSA_verify(type, tbs, tbslen, sig, siglen, ec);
++
++    return ret;
++}
++
++#ifndef OPENSSL_NO_EC
++static int pkey_ec_derive(EVP_PKEY_CTX *ctx, unsigned char *key,
++                          size_t *keylen)
++{
++    int ret;
++    size_t outlen;
++    const EC_POINT *pubkey = NULL;
++    EC_KEY *eckey;
++    EC_PKEY_CTX *dctx = ctx->data;
++    if (!ctx->pkey || !ctx->peerkey) {
++        ECerr(EC_F_PKEY_EC_DERIVE, EC_R_KEYS_NOT_SET);
++        return 0;
++    }
++
++    eckey = dctx->co_key ? dctx->co_key : ctx->pkey->pkey.ec;
++
++    if (!key) {
++        const EC_GROUP *group;
++        group = EC_KEY_get0_group(eckey);
++        *keylen = (EC_GROUP_get_degree(group) + 7) / 8;
++        return 1;
++    }
++    pubkey = EC_KEY_get0_public_key(ctx->peerkey->pkey.ec);
++
++    /*
++     * NB: unlike PKCS#3 DH, if *outlen is less than maximum size this is not
++     * an error, the result is truncated.
++     */
++
++    outlen = *keylen;
++
++    ret = ECDH_compute_key(key, outlen, pubkey, eckey, 0);
++    if (ret <= 0)
++        return 0;
++    *keylen = ret;
++    return 1;
++}
++
++static int pkey_ec_kdf_derive(EVP_PKEY_CTX *ctx,
++                              unsigned char *key, size_t *keylen)
++{
++    EC_PKEY_CTX *dctx = ctx->data;
++    unsigned char *ktmp = NULL;
++    size_t ktmplen;
++    int rv = 0;
++    if (dctx->kdf_type == EVP_PKEY_ECDH_KDF_NONE)
++        return pkey_ec_derive(ctx, key, keylen);
++    if (!key) {
++        *keylen = dctx->kdf_outlen;
++        return 1;
++    }
++    if (*keylen != dctx->kdf_outlen)
++        return 0;
++    if (!pkey_ec_derive(ctx, NULL, &ktmplen))
++        return 0;
++    ktmp = OPENSSL_malloc(ktmplen);
++    if (ktmp == NULL)
++        return 0;
++    if (!pkey_ec_derive(ctx, ktmp, &ktmplen))
++        goto err;
++    /* Do KDF stuff */
++    if (!ECDH_KDF_X9_62(key, *keylen, ktmp, ktmplen,
++                        dctx->kdf_ukm, dctx->kdf_ukmlen, dctx->kdf_md))
++        goto err;
++    rv = 1;
++
++ err:
++    OPENSSL_clear_free(ktmp, ktmplen);
++    return rv;
++}
++#endif
++
++static int pkey_ec_ctrl(EVP_PKEY_CTX *ctx, int type, int p1, void *p2)
++{
++    EC_PKEY_CTX *dctx = ctx->data;
++    EC_GROUP *group;
++    switch (type) {
++    case EVP_PKEY_CTRL_EC_PARAMGEN_CURVE_NID:
++        group = EC_GROUP_new_by_curve_name(p1);
++        if (group == NULL) {
++            ECerr(EC_F_PKEY_EC_CTRL, EC_R_INVALID_CURVE);
++            return 0;
++        }
++        EC_GROUP_free(dctx->gen_group);
++        dctx->gen_group = group;
++        return 1;
++
++    case EVP_PKEY_CTRL_EC_PARAM_ENC:
++        if (!dctx->gen_group) {
++            ECerr(EC_F_PKEY_EC_CTRL, EC_R_NO_PARAMETERS_SET);
++            return 0;
++        }
++        EC_GROUP_set_asn1_flag(dctx->gen_group, p1);
++        return 1;
++
++#ifndef OPENSSL_NO_EC
++    case EVP_PKEY_CTRL_EC_ECDH_COFACTOR:
++        if (p1 == -2) {
++            if (dctx->cofactor_mode != -1)
++                return dctx->cofactor_mode;
++            else {
++                EC_KEY *ec_key = ctx->pkey->pkey.ec;
++                return EC_KEY_get_flags(ec_key) & EC_FLAG_COFACTOR_ECDH ? 1 :
++                    0;
++            }
++        } else if (p1 < -1 || p1 > 1)
++            return -2;
++        dctx->cofactor_mode = p1;
++        if (p1 != -1) {
++            EC_KEY *ec_key = ctx->pkey->pkey.ec;
++            if (!ec_key->group)
++                return -2;
++            /* If cofactor is 1 cofactor mode does nothing */
++            if (BN_is_one(ec_key->group->cofactor))
++                return 1;
++            if (!dctx->co_key) {
++                dctx->co_key = EC_KEY_dup(ec_key);
++                if (!dctx->co_key)
++                    return 0;
++            }
++            if (p1)
++                EC_KEY_set_flags(dctx->co_key, EC_FLAG_COFACTOR_ECDH);
++            else
++                EC_KEY_clear_flags(dctx->co_key, EC_FLAG_COFACTOR_ECDH);
++        } else {
++            EC_KEY_free(dctx->co_key);
++            dctx->co_key = NULL;
++        }
++        return 1;
++#endif
++
++    case EVP_PKEY_CTRL_EC_KDF_TYPE:
++        if (p1 == -2)
++            return dctx->kdf_type;
++        if (p1 != EVP_PKEY_ECDH_KDF_NONE && p1 != EVP_PKEY_ECDH_KDF_X9_62)
++            return -2;
++        dctx->kdf_type = p1;
++        return 1;
++
++    case EVP_PKEY_CTRL_EC_KDF_MD:
++        dctx->kdf_md = p2;
++        return 1;
++
++    case EVP_PKEY_CTRL_GET_EC_KDF_MD:
++        *(const EVP_MD **)p2 = dctx->kdf_md;
++        return 1;
++
++    case EVP_PKEY_CTRL_EC_KDF_OUTLEN:
++        if (p1 <= 0)
++            return -2;
++        dctx->kdf_outlen = (size_t)p1;
++        return 1;
++
++    case EVP_PKEY_CTRL_GET_EC_KDF_OUTLEN:
++        *(int *)p2 = dctx->kdf_outlen;
++        return 1;
++
++    case EVP_PKEY_CTRL_EC_KDF_UKM:
++        OPENSSL_free(dctx->kdf_ukm);
++        dctx->kdf_ukm = p2;
++        if (p2)
++            dctx->kdf_ukmlen = p1;
++        else
++            dctx->kdf_ukmlen = 0;
++        return 1;
++
++    case EVP_PKEY_CTRL_GET_EC_KDF_UKM:
++        *(unsigned char **)p2 = dctx->kdf_ukm;
++        return dctx->kdf_ukmlen;
++
++    case EVP_PKEY_CTRL_MD:
++        if (EVP_MD_type((const EVP_MD *)p2) != NID_sha1 &&
++            EVP_MD_type((const EVP_MD *)p2) != NID_ecdsa_with_SHA1 &&
++            EVP_MD_type((const EVP_MD *)p2) != NID_sha224 &&
++            EVP_MD_type((const EVP_MD *)p2) != NID_sha256 &&
++            EVP_MD_type((const EVP_MD *)p2) != NID_sha384 &&
++            EVP_MD_type((const EVP_MD *)p2) != NID_sha512) {
++            ECerr(EC_F_PKEY_EC_CTRL, EC_R_INVALID_DIGEST_TYPE);
++            return 0;
++        }
++        dctx->md = p2;
++        return 1;
++
++    case EVP_PKEY_CTRL_GET_MD:
++        *(const EVP_MD **)p2 = dctx->md;
++        return 1;
++
++    case EVP_PKEY_CTRL_PEER_KEY:
++        /* Default behaviour is OK */
++    case EVP_PKEY_CTRL_DIGESTINIT:
++    case EVP_PKEY_CTRL_PKCS7_SIGN:
++    case EVP_PKEY_CTRL_CMS_SIGN:
++        return 1;
++
++    default:
++        return -2;
++
++    }
++}
++
++static int pkey_ec_ctrl_str(EVP_PKEY_CTX *ctx,
++                            const char *type, const char *value)
++{
++    if (strcmp(type, "ec_paramgen_curve") == 0) {
++        int nid;
++        nid = EC_curve_nist2nid(value);
++        if (nid == NID_undef)
++            nid = OBJ_sn2nid(value);
++        if (nid == NID_undef)
++            nid = OBJ_ln2nid(value);
++        if (nid == NID_undef) {
++            ECerr(EC_F_PKEY_EC_CTRL_STR, EC_R_INVALID_CURVE);
++            return 0;
++        }
++        return EVP_PKEY_CTX_set_ec_paramgen_curve_nid(ctx, nid);
++    } else if (strcmp(type, "ec_param_enc") == 0) {
++        int param_enc;
++        if (strcmp(value, "explicit") == 0)
++            param_enc = 0;
++        else if (strcmp(value, "named_curve") == 0)
++            param_enc = OPENSSL_EC_NAMED_CURVE;
++        else
++            return -2;
++        return EVP_PKEY_CTX_set_ec_param_enc(ctx, param_enc);
++    } else if (strcmp(type, "ecdh_kdf_md") == 0) {
++        const EVP_MD *md;
++        if ((md = EVP_get_digestbyname(value)) == NULL) {
++            ECerr(EC_F_PKEY_EC_CTRL_STR, EC_R_INVALID_DIGEST);
++            return 0;
++        }
++        return EVP_PKEY_CTX_set_ecdh_kdf_md(ctx, md);
++    } else if (strcmp(type, "ecdh_cofactor_mode") == 0) {
++        int co_mode;
++        co_mode = atoi(value);
++        return EVP_PKEY_CTX_set_ecdh_cofactor_mode(ctx, co_mode);
++    }
++
++    return -2;
++}
++
++static int pkey_ec_paramgen(EVP_PKEY_CTX *ctx, EVP_PKEY *pkey)
++{
++    EC_KEY *ec = NULL;
++    EC_PKEY_CTX *dctx = ctx->data;
++    int ret = 0;
++    if (dctx->gen_group == NULL) {
++        ECerr(EC_F_PKEY_EC_PARAMGEN, EC_R_NO_PARAMETERS_SET);
++        return 0;
++    }
++    ec = EC_KEY_new();
++    if (ec == NULL)
++        return 0;
++    ret = EC_KEY_set_group(ec, dctx->gen_group);
++    if (ret)
++        EVP_PKEY_assign_EC_KEY(pkey, ec);
++    else
++        EC_KEY_free(ec);
++    return ret;
++}
++
++static int pkey_ec_keygen(EVP_PKEY_CTX *ctx, EVP_PKEY *pkey)
++{
++    EC_KEY *ec = NULL;
++    EC_PKEY_CTX *dctx = ctx->data;
++    if (ctx->pkey == NULL && dctx->gen_group == NULL) {
++        ECerr(EC_F_PKEY_EC_KEYGEN, EC_R_NO_PARAMETERS_SET);
++        return 0;
++    }
++    ec = EC_KEY_new();
++    if (!ec)
++        return 0;
++    EVP_PKEY_assign_EC_KEY(pkey, ec);
++    if (ctx->pkey) {
++        /* Note: if error return, pkey is freed by parent routine */
++        if (!EVP_PKEY_copy_parameters(pkey, ctx->pkey))
++            return 0;
++    } else {
++        if (!EC_KEY_set_group(ec, dctx->gen_group))
++            return 0;
++    }
++    return EC_KEY_generate_key(pkey->pkey.ec);
++}
++
++const EVP_PKEY_METHOD ec_pkey_meth = {
++    EVP_PKEY_EC,
++    0,
++    pkey_ec_init,
++    pkey_ec_copy,
++    pkey_ec_cleanup,
++
++    0,
++    pkey_ec_paramgen,
++
++    0,
++    pkey_ec_keygen,
++
++    0,
++    pkey_ec_sign,
++
++    0,
++    pkey_ec_verify,
++
++    0, 0,
++
++    0, 0, 0, 0,
++
++    0, 0,
++
++    0, 0,
++
++    0,
++#ifndef OPENSSL_NO_EC
++    pkey_ec_kdf_derive,
++#else
++    0,
++#endif
++    pkey_ec_ctrl,
++    pkey_ec_ctrl_str
++};
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/ec/ec_print.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/ec/ec_print.c
+new file mode 100644
+index 0000000..1afa2ce
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/ec/ec_print.c
+@@ -0,0 +1,119 @@
++/*
++ * Copyright 2002-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include "ec_lcl.h"
++
++BIGNUM *EC_POINT_point2bn(const EC_GROUP *group,
++                          const EC_POINT *point,
++                          point_conversion_form_t form,
++                          BIGNUM *ret, BN_CTX *ctx)
++{
++    size_t buf_len = 0;
++    unsigned char *buf;
++
++    buf_len = EC_POINT_point2buf(group, point, form, &buf, ctx);
++
++    if (buf_len == 0)
++        return NULL;
++
++    ret = BN_bin2bn(buf, buf_len, ret);
++
++    OPENSSL_free(buf);
++
++    return ret;
++}
++
++EC_POINT *EC_POINT_bn2point(const EC_GROUP *group,
++                            const BIGNUM *bn, EC_POINT *point, BN_CTX *ctx)
++{
++    size_t buf_len = 0;
++    unsigned char *buf;
++    EC_POINT *ret;
++
++    if ((buf_len = BN_num_bytes(bn)) == 0)
++        return NULL;
++    buf = OPENSSL_malloc(buf_len);
++    if (buf == NULL)
++        return NULL;
++
++    if (!BN_bn2bin(bn, buf)) {
++        OPENSSL_free(buf);
++        return NULL;
++    }
++
++    if (point == NULL) {
++        if ((ret = EC_POINT_new(group)) == NULL) {
++            OPENSSL_free(buf);
++            return NULL;
++        }
++    } else
++        ret = point;
++
++    if (!EC_POINT_oct2point(group, ret, buf, buf_len, ctx)) {
++        if (ret != point)
++            EC_POINT_clear_free(ret);
++        OPENSSL_free(buf);
++        return NULL;
++    }
++
++    OPENSSL_free(buf);
++    return ret;
++}
++
++static const char *HEX_DIGITS = "0123456789ABCDEF";
++
++/* the return value must be freed (using OPENSSL_free()) */
++char *EC_POINT_point2hex(const EC_GROUP *group,
++                         const EC_POINT *point,
++                         point_conversion_form_t form, BN_CTX *ctx)
++{
++    char *ret, *p;
++    size_t buf_len = 0, i;
++    unsigned char *buf = NULL, *pbuf;
++
++    buf_len = EC_POINT_point2buf(group, point, form, &buf, ctx);
++
++    if (buf_len == 0)
++        return NULL;
++
++    ret = OPENSSL_malloc(buf_len * 2 + 2);
++    if (ret == NULL) {
++        OPENSSL_free(buf);
++        return NULL;
++    }
++    p = ret;
++    pbuf = buf;
++    for (i = buf_len; i > 0; i--) {
++        int v = (int)*(pbuf++);
++        *(p++) = HEX_DIGITS[v >> 4];
++        *(p++) = HEX_DIGITS[v & 0x0F];
++    }
++    *p = '\0';
++
++    OPENSSL_free(buf);
++
++    return ret;
++}
++
++EC_POINT *EC_POINT_hex2point(const EC_GROUP *group,
++                             const char *buf, EC_POINT *point, BN_CTX *ctx)
++{
++    EC_POINT *ret = NULL;
++    BIGNUM *tmp_bn = NULL;
++
++    if (!BN_hex2bn(&tmp_bn, buf))
++        return NULL;
++
++    ret = EC_POINT_bn2point(group, tmp_bn, point, ctx);
++
++    BN_clear_free(tmp_bn);
++
++    return ret;
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/ec/ecdh_kdf.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/ec/ecdh_kdf.c
+new file mode 100644
+index 0000000..d47486e
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/ec/ecdh_kdf.c
+@@ -0,0 +1,68 @@
++/*
++ * Copyright 2015-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include 
++#include 
++
++/* Key derivation function from X9.62/SECG */
++/* Way more than we will ever need */
++#define ECDH_KDF_MAX    (1 << 30)
++
++int ECDH_KDF_X9_62(unsigned char *out, size_t outlen,
++                   const unsigned char *Z, size_t Zlen,
++                   const unsigned char *sinfo, size_t sinfolen,
++                   const EVP_MD *md)
++{
++    EVP_MD_CTX *mctx = NULL;
++    int rv = 0;
++    unsigned int i;
++    size_t mdlen;
++    unsigned char ctr[4];
++    if (sinfolen > ECDH_KDF_MAX || outlen > ECDH_KDF_MAX
++        || Zlen > ECDH_KDF_MAX)
++        return 0;
++    mctx = EVP_MD_CTX_new();
++    if (mctx == NULL)
++        return 0;
++    mdlen = EVP_MD_size(md);
++    for (i = 1;; i++) {
++        unsigned char mtmp[EVP_MAX_MD_SIZE];
++        if (!EVP_DigestInit_ex(mctx, md, NULL))
++            goto err;
++        ctr[3] = i & 0xFF;
++        ctr[2] = (i >> 8) & 0xFF;
++        ctr[1] = (i >> 16) & 0xFF;
++        ctr[0] = (i >> 24) & 0xFF;
++        if (!EVP_DigestUpdate(mctx, Z, Zlen))
++            goto err;
++        if (!EVP_DigestUpdate(mctx, ctr, sizeof(ctr)))
++            goto err;
++        if (!EVP_DigestUpdate(mctx, sinfo, sinfolen))
++            goto err;
++        if (outlen >= mdlen) {
++            if (!EVP_DigestFinal(mctx, out, NULL))
++                goto err;
++            outlen -= mdlen;
++            if (outlen == 0)
++                break;
++            out += mdlen;
++        } else {
++            if (!EVP_DigestFinal(mctx, mtmp, NULL))
++                goto err;
++            memcpy(out, mtmp, outlen);
++            OPENSSL_cleanse(mtmp, mdlen);
++            break;
++        }
++    }
++    rv = 1;
++ err:
++    EVP_MD_CTX_free(mctx);
++    return rv;
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/ec/ecdh_ossl.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/ec/ecdh_ossl.c
+new file mode 100644
+index 0000000..caf65de
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/ec/ecdh_ossl.c
+@@ -0,0 +1,143 @@
++/*
++ * Copyright 2002-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++/* ====================================================================
++ * Copyright 2002 Sun Microsystems, Inc. ALL RIGHTS RESERVED.
++ *
++ * The Elliptic Curve Public-Key Crypto Library (ECC Code) included
++ * herein is developed by SUN MICROSYSTEMS, INC., and is contributed
++ * to the OpenSSL project.
++ *
++ * The ECC Code is licensed pursuant to the OpenSSL open source
++ * license provided below.
++ *
++ * The ECDH software is originally written by Douglas Stebila of
++ * Sun Microsystems Laboratories.
++ *
++ */
++
++#include 
++#include 
++
++#include "internal/cryptlib.h"
++
++#include 
++#include 
++#include 
++#include 
++#include "ec_lcl.h"
++
++int ossl_ecdh_compute_key(unsigned char **psec, size_t *pseclen,
++                          const EC_POINT *pub_key, const EC_KEY *ecdh)
++{
++    if (ecdh->group->meth->ecdh_compute_key == NULL) {
++        ECerr(EC_F_OSSL_ECDH_COMPUTE_KEY, EC_R_CURVE_DOES_NOT_SUPPORT_ECDH);
++        return 0;
++    }
++
++    return ecdh->group->meth->ecdh_compute_key(psec, pseclen, pub_key, ecdh);
++}
++
++/*-
++ * This implementation is based on the following primitives in the IEEE 1363 standard:
++ *  - ECKAS-DH1
++ *  - ECSVDP-DH
++ */
++int ecdh_simple_compute_key(unsigned char **pout, size_t *poutlen,
++                            const EC_POINT *pub_key, const EC_KEY *ecdh)
++{
++    BN_CTX *ctx;
++    EC_POINT *tmp = NULL;
++    BIGNUM *x = NULL, *y = NULL;
++    const BIGNUM *priv_key;
++    const EC_GROUP *group;
++    int ret = 0;
++    size_t buflen, len;
++    unsigned char *buf = NULL;
++
++    if ((ctx = BN_CTX_new()) == NULL)
++        goto err;
++    BN_CTX_start(ctx);
++    x = BN_CTX_get(ctx);
++    y = BN_CTX_get(ctx);
++
++    priv_key = EC_KEY_get0_private_key(ecdh);
++    if (priv_key == NULL) {
++        ECerr(EC_F_ECDH_SIMPLE_COMPUTE_KEY, EC_R_NO_PRIVATE_VALUE);
++        goto err;
++    }
++
++    group = EC_KEY_get0_group(ecdh);
++
++    if (EC_KEY_get_flags(ecdh) & EC_FLAG_COFACTOR_ECDH) {
++        if (!EC_GROUP_get_cofactor(group, x, NULL) ||
++            !BN_mul(x, x, priv_key, ctx)) {
++            ECerr(EC_F_ECDH_SIMPLE_COMPUTE_KEY, ERR_R_MALLOC_FAILURE);
++            goto err;
++        }
++        priv_key = x;
++    }
++
++    if ((tmp = EC_POINT_new(group)) == NULL) {
++        ECerr(EC_F_ECDH_SIMPLE_COMPUTE_KEY, ERR_R_MALLOC_FAILURE);
++        goto err;
++    }
++
++    if (!EC_POINT_mul(group, tmp, NULL, pub_key, priv_key, ctx)) {
++        ECerr(EC_F_ECDH_SIMPLE_COMPUTE_KEY, EC_R_POINT_ARITHMETIC_FAILURE);
++        goto err;
++    }
++
++    if (EC_METHOD_get_field_type(EC_GROUP_method_of(group)) ==
++        NID_X9_62_prime_field) {
++        if (!EC_POINT_get_affine_coordinates_GFp(group, tmp, x, y, ctx)) {
++            ECerr(EC_F_ECDH_SIMPLE_COMPUTE_KEY, EC_R_POINT_ARITHMETIC_FAILURE);
++            goto err;
++        }
++    }
++#ifndef OPENSSL_NO_EC2M
++    else {
++        if (!EC_POINT_get_affine_coordinates_GF2m(group, tmp, x, y, ctx)) {
++            ECerr(EC_F_ECDH_SIMPLE_COMPUTE_KEY, EC_R_POINT_ARITHMETIC_FAILURE);
++            goto err;
++        }
++    }
++#endif
++
++    buflen = (EC_GROUP_get_degree(group) + 7) / 8;
++    len = BN_num_bytes(x);
++    if (len > buflen) {
++        ECerr(EC_F_ECDH_SIMPLE_COMPUTE_KEY, ERR_R_INTERNAL_ERROR);
++        goto err;
++    }
++    if ((buf = OPENSSL_malloc(buflen)) == NULL) {
++        ECerr(EC_F_ECDH_SIMPLE_COMPUTE_KEY, ERR_R_MALLOC_FAILURE);
++        goto err;
++    }
++
++    memset(buf, 0, buflen - len);
++    if (len != (size_t)BN_bn2bin(x, buf + buflen - len)) {
++        ECerr(EC_F_ECDH_SIMPLE_COMPUTE_KEY, ERR_R_BN_LIB);
++        goto err;
++    }
++
++    *pout = buf;
++    *poutlen = buflen;
++    buf = NULL;
++
++    ret = 1;
++
++ err:
++    EC_POINT_free(tmp);
++    if (ctx)
++        BN_CTX_end(ctx);
++    BN_CTX_free(ctx);
++    OPENSSL_free(buf);
++    return ret;
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/ec/ecdsa_ossl.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/ec/ecdsa_ossl.c
+new file mode 100644
+index 0000000..d67c485
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/ec/ecdsa_ossl.c
+@@ -0,0 +1,462 @@
++/*
++ * Copyright 2002-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include 
++#include 
++#include 
++#include 
++#include 
++#include "ec_lcl.h"
++
++int ossl_ecdsa_sign(int type, const unsigned char *dgst, int dlen,
++                    unsigned char *sig, unsigned int *siglen,
++                    const BIGNUM *kinv, const BIGNUM *r, EC_KEY *eckey)
++{
++    ECDSA_SIG *s;
++    RAND_seed(dgst, dlen);
++    s = ECDSA_do_sign_ex(dgst, dlen, kinv, r, eckey);
++    if (s == NULL) {
++        *siglen = 0;
++        return 0;
++    }
++    *siglen = i2d_ECDSA_SIG(s, &sig);
++    ECDSA_SIG_free(s);
++    return 1;
++}
++
++static int ecdsa_sign_setup(EC_KEY *eckey, BN_CTX *ctx_in,
++                            BIGNUM **kinvp, BIGNUM **rp,
++                            const unsigned char *dgst, int dlen)
++{
++    BN_CTX *ctx = NULL;
++    BIGNUM *k = NULL, *r = NULL, *X = NULL;
++    const BIGNUM *order;
++    EC_POINT *tmp_point = NULL;
++    const EC_GROUP *group;
++    int ret = 0;
++
++    if (eckey == NULL || (group = EC_KEY_get0_group(eckey)) == NULL) {
++        ECerr(EC_F_ECDSA_SIGN_SETUP, ERR_R_PASSED_NULL_PARAMETER);
++        return 0;
++    }
++
++    if (!EC_KEY_can_sign(eckey)) {
++        ECerr(EC_F_ECDSA_SIGN_SETUP, EC_R_CURVE_DOES_NOT_SUPPORT_SIGNING);
++        return 0;
++    }
++
++    if (ctx_in == NULL) {
++        if ((ctx = BN_CTX_new()) == NULL) {
++            ECerr(EC_F_ECDSA_SIGN_SETUP, ERR_R_MALLOC_FAILURE);
++            return 0;
++        }
++    } else
++        ctx = ctx_in;
++
++    k = BN_new();               /* this value is later returned in *kinvp */
++    r = BN_new();               /* this value is later returned in *rp */
++    X = BN_new();
++    if (k == NULL || r == NULL || X == NULL) {
++        ECerr(EC_F_ECDSA_SIGN_SETUP, ERR_R_MALLOC_FAILURE);
++        goto err;
++    }
++    if ((tmp_point = EC_POINT_new(group)) == NULL) {
++        ECerr(EC_F_ECDSA_SIGN_SETUP, ERR_R_EC_LIB);
++        goto err;
++    }
++    order = EC_GROUP_get0_order(group);
++    if (order == NULL) {
++        ECerr(EC_F_ECDSA_SIGN_SETUP, ERR_R_EC_LIB);
++        goto err;
++    }
++
++    do {
++        /* get random k */
++        do
++            if (dgst != NULL) {
++                if (!BN_generate_dsa_nonce
++                    (k, order, EC_KEY_get0_private_key(eckey), dgst, dlen,
++                     ctx)) {
++                    ECerr(EC_F_ECDSA_SIGN_SETUP,
++                             EC_R_RANDOM_NUMBER_GENERATION_FAILED);
++                    goto err;
++                }
++            } else {
++                if (!BN_rand_range(k, order)) {
++                    ECerr(EC_F_ECDSA_SIGN_SETUP,
++                             EC_R_RANDOM_NUMBER_GENERATION_FAILED);
++                    goto err;
++                }
++            }
++        while (BN_is_zero(k));
++
++        /*
++         * We do not want timing information to leak the length of k, so we
++         * compute G*k using an equivalent scalar of fixed bit-length.
++         */
++
++        if (!BN_add(k, k, order))
++            goto err;
++        if (BN_num_bits(k) <= BN_num_bits(order))
++            if (!BN_add(k, k, order))
++                goto err;
++
++        /* compute r the x-coordinate of generator * k */
++        if (!EC_POINT_mul(group, tmp_point, k, NULL, NULL, ctx)) {
++            ECerr(EC_F_ECDSA_SIGN_SETUP, ERR_R_EC_LIB);
++            goto err;
++        }
++        if (EC_METHOD_get_field_type(EC_GROUP_method_of(group)) ==
++            NID_X9_62_prime_field) {
++            if (!EC_POINT_get_affine_coordinates_GFp
++                (group, tmp_point, X, NULL, ctx)) {
++                ECerr(EC_F_ECDSA_SIGN_SETUP, ERR_R_EC_LIB);
++                goto err;
++            }
++        }
++#ifndef OPENSSL_NO_EC2M
++        else {                  /* NID_X9_62_characteristic_two_field */
++
++            if (!EC_POINT_get_affine_coordinates_GF2m(group,
++                                                      tmp_point, X, NULL,
++                                                      ctx)) {
++                ECerr(EC_F_ECDSA_SIGN_SETUP, ERR_R_EC_LIB);
++                goto err;
++            }
++        }
++#endif
++        if (!BN_nnmod(r, X, order, ctx)) {
++            ECerr(EC_F_ECDSA_SIGN_SETUP, ERR_R_BN_LIB);
++            goto err;
++        }
++    }
++    while (BN_is_zero(r));
++
++    /* compute the inverse of k */
++    if (EC_GROUP_get_mont_data(group) != NULL) {
++        /*
++         * We want inverse in constant time, therefore we utilize the fact
++         * order must be prime and use Fermats Little Theorem instead.
++         */
++        if (!BN_set_word(X, 2)) {
++            ECerr(EC_F_ECDSA_SIGN_SETUP, ERR_R_BN_LIB);
++            goto err;
++        }
++        if (!BN_mod_sub(X, order, X, order, ctx)) {
++            ECerr(EC_F_ECDSA_SIGN_SETUP, ERR_R_BN_LIB);
++            goto err;
++        }
++        BN_set_flags(X, BN_FLG_CONSTTIME);
++        if (!BN_mod_exp_mont_consttime
++            (k, k, X, order, ctx, EC_GROUP_get_mont_data(group))) {
++            ECerr(EC_F_ECDSA_SIGN_SETUP, ERR_R_BN_LIB);
++            goto err;
++        }
++    } else {
++        if (!BN_mod_inverse(k, k, order, ctx)) {
++            ECerr(EC_F_ECDSA_SIGN_SETUP, ERR_R_BN_LIB);
++            goto err;
++        }
++    }
++
++    /* clear old values if necessary */
++    BN_clear_free(*rp);
++    BN_clear_free(*kinvp);
++    /* save the pre-computed values  */
++    *rp = r;
++    *kinvp = k;
++    ret = 1;
++ err:
++    if (!ret) {
++        BN_clear_free(k);
++        BN_clear_free(r);
++    }
++    if (ctx != ctx_in)
++        BN_CTX_free(ctx);
++    EC_POINT_free(tmp_point);
++    BN_clear_free(X);
++    return (ret);
++}
++
++int ossl_ecdsa_sign_setup(EC_KEY *eckey, BN_CTX *ctx_in, BIGNUM **kinvp,
++                          BIGNUM **rp)
++{
++    return ecdsa_sign_setup(eckey, ctx_in, kinvp, rp, NULL, 0);
++}
++
++ECDSA_SIG *ossl_ecdsa_sign_sig(const unsigned char *dgst, int dgst_len,
++                               const BIGNUM *in_kinv, const BIGNUM *in_r,
++                               EC_KEY *eckey)
++{
++    int ok = 0, i;
++    BIGNUM *kinv = NULL, *s, *m = NULL, *tmp = NULL;
++    const BIGNUM *order, *ckinv;
++    BN_CTX *ctx = NULL;
++    const EC_GROUP *group;
++    ECDSA_SIG *ret;
++    const BIGNUM *priv_key;
++
++    group = EC_KEY_get0_group(eckey);
++    priv_key = EC_KEY_get0_private_key(eckey);
++
++    if (group == NULL || priv_key == NULL) {
++        ECerr(EC_F_OSSL_ECDSA_SIGN_SIG, ERR_R_PASSED_NULL_PARAMETER);
++        return NULL;
++    }
++
++    if (!EC_KEY_can_sign(eckey)) {
++        ECerr(EC_F_OSSL_ECDSA_SIGN_SIG, EC_R_CURVE_DOES_NOT_SUPPORT_SIGNING);
++        return NULL;
++    }
++
++    ret = ECDSA_SIG_new();
++    if (ret == NULL) {
++        ECerr(EC_F_OSSL_ECDSA_SIGN_SIG, ERR_R_MALLOC_FAILURE);
++        return NULL;
++    }
++    ret->r = BN_new();
++    ret->s = BN_new();
++    if (ret->r == NULL || ret->s == NULL) {
++        ECerr(EC_F_OSSL_ECDSA_SIGN_SIG, ERR_R_MALLOC_FAILURE);
++        goto err;
++    }
++    s = ret->s;
++
++    if ((ctx = BN_CTX_new()) == NULL ||
++        (tmp = BN_new()) == NULL || (m = BN_new()) == NULL) {
++        ECerr(EC_F_OSSL_ECDSA_SIGN_SIG, ERR_R_MALLOC_FAILURE);
++        goto err;
++    }
++
++    order = EC_GROUP_get0_order(group);
++    if (order == NULL) {
++        ECerr(EC_F_OSSL_ECDSA_SIGN_SIG, ERR_R_EC_LIB);
++        goto err;
++    }
++    i = BN_num_bits(order);
++    /*
++     * Need to truncate digest if it is too long: first truncate whole bytes.
++     */
++    if (8 * dgst_len > i)
++        dgst_len = (i + 7) / 8;
++    if (!BN_bin2bn(dgst, dgst_len, m)) {
++        ECerr(EC_F_OSSL_ECDSA_SIGN_SIG, ERR_R_BN_LIB);
++        goto err;
++    }
++    /* If still too long truncate remaining bits with a shift */
++    if ((8 * dgst_len > i) && !BN_rshift(m, m, 8 - (i & 0x7))) {
++        ECerr(EC_F_OSSL_ECDSA_SIGN_SIG, ERR_R_BN_LIB);
++        goto err;
++    }
++    do {
++        if (in_kinv == NULL || in_r == NULL) {
++            if (!ecdsa_sign_setup(eckey, ctx, &kinv, &ret->r, dgst, dgst_len)) {
++                ECerr(EC_F_OSSL_ECDSA_SIGN_SIG, ERR_R_ECDSA_LIB);
++                goto err;
++            }
++            ckinv = kinv;
++        } else {
++            ckinv = in_kinv;
++            if (BN_copy(ret->r, in_r) == NULL) {
++                ECerr(EC_F_OSSL_ECDSA_SIGN_SIG, ERR_R_MALLOC_FAILURE);
++                goto err;
++            }
++        }
++
++        if (!BN_mod_mul(tmp, priv_key, ret->r, order, ctx)) {
++            ECerr(EC_F_OSSL_ECDSA_SIGN_SIG, ERR_R_BN_LIB);
++            goto err;
++        }
++        if (!BN_mod_add_quick(s, tmp, m, order)) {
++            ECerr(EC_F_OSSL_ECDSA_SIGN_SIG, ERR_R_BN_LIB);
++            goto err;
++        }
++        if (!BN_mod_mul(s, s, ckinv, order, ctx)) {
++            ECerr(EC_F_OSSL_ECDSA_SIGN_SIG, ERR_R_BN_LIB);
++            goto err;
++        }
++        if (BN_is_zero(s)) {
++            /*
++             * if kinv and r have been supplied by the caller don't to
++             * generate new kinv and r values
++             */
++            if (in_kinv != NULL && in_r != NULL) {
++                ECerr(EC_F_OSSL_ECDSA_SIGN_SIG, EC_R_NEED_NEW_SETUP_VALUES);
++                goto err;
++            }
++        } else
++            /* s != 0 => we have a valid signature */
++            break;
++    }
++    while (1);
++
++    ok = 1;
++ err:
++    if (!ok) {
++        ECDSA_SIG_free(ret);
++        ret = NULL;
++    }
++    BN_CTX_free(ctx);
++    BN_clear_free(m);
++    BN_clear_free(tmp);
++    BN_clear_free(kinv);
++    return ret;
++}
++
++/*-
++ * returns
++ *      1: correct signature
++ *      0: incorrect signature
++ *     -1: error
++ */
++int ossl_ecdsa_verify(int type, const unsigned char *dgst, int dgst_len,
++                      const unsigned char *sigbuf, int sig_len, EC_KEY *eckey)
++{
++    ECDSA_SIG *s;
++    const unsigned char *p = sigbuf;
++    unsigned char *der = NULL;
++    int derlen = -1;
++    int ret = -1;
++
++    s = ECDSA_SIG_new();
++    if (s == NULL)
++        return (ret);
++    if (d2i_ECDSA_SIG(&s, &p, sig_len) == NULL)
++        goto err;
++    /* Ensure signature uses DER and doesn't have trailing garbage */
++    derlen = i2d_ECDSA_SIG(s, &der);
++    if (derlen != sig_len || memcmp(sigbuf, der, derlen) != 0)
++        goto err;
++    ret = ECDSA_do_verify(dgst, dgst_len, s, eckey);
++ err:
++    OPENSSL_clear_free(der, derlen);
++    ECDSA_SIG_free(s);
++    return (ret);
++}
++
++int ossl_ecdsa_verify_sig(const unsigned char *dgst, int dgst_len,
++                          const ECDSA_SIG *sig, EC_KEY *eckey)
++{
++    int ret = -1, i;
++    BN_CTX *ctx;
++    const BIGNUM *order;
++    BIGNUM *u1, *u2, *m, *X;
++    EC_POINT *point = NULL;
++    const EC_GROUP *group;
++    const EC_POINT *pub_key;
++
++    /* check input values */
++    if (eckey == NULL || (group = EC_KEY_get0_group(eckey)) == NULL ||
++        (pub_key = EC_KEY_get0_public_key(eckey)) == NULL || sig == NULL) {
++        ECerr(EC_F_OSSL_ECDSA_VERIFY_SIG, EC_R_MISSING_PARAMETERS);
++        return -1;
++    }
++
++    if (!EC_KEY_can_sign(eckey)) {
++        ECerr(EC_F_OSSL_ECDSA_VERIFY_SIG, EC_R_CURVE_DOES_NOT_SUPPORT_SIGNING);
++        return -1;
++    }
++
++    ctx = BN_CTX_new();
++    if (ctx == NULL) {
++        ECerr(EC_F_OSSL_ECDSA_VERIFY_SIG, ERR_R_MALLOC_FAILURE);
++        return -1;
++    }
++    BN_CTX_start(ctx);
++    u1 = BN_CTX_get(ctx);
++    u2 = BN_CTX_get(ctx);
++    m = BN_CTX_get(ctx);
++    X = BN_CTX_get(ctx);
++    if (X == NULL) {
++        ECerr(EC_F_OSSL_ECDSA_VERIFY_SIG, ERR_R_BN_LIB);
++        goto err;
++    }
++
++    order = EC_GROUP_get0_order(group);
++    if (order == NULL) {
++        ECerr(EC_F_OSSL_ECDSA_VERIFY_SIG, ERR_R_EC_LIB);
++        goto err;
++    }
++
++    if (BN_is_zero(sig->r) || BN_is_negative(sig->r) ||
++        BN_ucmp(sig->r, order) >= 0 || BN_is_zero(sig->s) ||
++        BN_is_negative(sig->s) || BN_ucmp(sig->s, order) >= 0) {
++        ECerr(EC_F_OSSL_ECDSA_VERIFY_SIG, EC_R_BAD_SIGNATURE);
++        ret = 0;                /* signature is invalid */
++        goto err;
++    }
++    /* calculate tmp1 = inv(S) mod order */
++    if (!BN_mod_inverse(u2, sig->s, order, ctx)) {
++        ECerr(EC_F_OSSL_ECDSA_VERIFY_SIG, ERR_R_BN_LIB);
++        goto err;
++    }
++    /* digest -> m */
++    i = BN_num_bits(order);
++    /*
++     * Need to truncate digest if it is too long: first truncate whole bytes.
++     */
++    if (8 * dgst_len > i)
++        dgst_len = (i + 7) / 8;
++    if (!BN_bin2bn(dgst, dgst_len, m)) {
++        ECerr(EC_F_OSSL_ECDSA_VERIFY_SIG, ERR_R_BN_LIB);
++        goto err;
++    }
++    /* If still too long truncate remaining bits with a shift */
++    if ((8 * dgst_len > i) && !BN_rshift(m, m, 8 - (i & 0x7))) {
++        ECerr(EC_F_OSSL_ECDSA_VERIFY_SIG, ERR_R_BN_LIB);
++        goto err;
++    }
++    /* u1 = m * tmp mod order */
++    if (!BN_mod_mul(u1, m, u2, order, ctx)) {
++        ECerr(EC_F_OSSL_ECDSA_VERIFY_SIG, ERR_R_BN_LIB);
++        goto err;
++    }
++    /* u2 = r * w mod q */
++    if (!BN_mod_mul(u2, sig->r, u2, order, ctx)) {
++        ECerr(EC_F_OSSL_ECDSA_VERIFY_SIG, ERR_R_BN_LIB);
++        goto err;
++    }
++
++    if ((point = EC_POINT_new(group)) == NULL) {
++        ECerr(EC_F_OSSL_ECDSA_VERIFY_SIG, ERR_R_MALLOC_FAILURE);
++        goto err;
++    }
++    if (!EC_POINT_mul(group, point, u1, pub_key, u2, ctx)) {
++        ECerr(EC_F_OSSL_ECDSA_VERIFY_SIG, ERR_R_EC_LIB);
++        goto err;
++    }
++    if (EC_METHOD_get_field_type(EC_GROUP_method_of(group)) ==
++        NID_X9_62_prime_field) {
++        if (!EC_POINT_get_affine_coordinates_GFp(group, point, X, NULL, ctx)) {
++            ECerr(EC_F_OSSL_ECDSA_VERIFY_SIG, ERR_R_EC_LIB);
++            goto err;
++        }
++    }
++#ifndef OPENSSL_NO_EC2M
++    else {                      /* NID_X9_62_characteristic_two_field */
++
++        if (!EC_POINT_get_affine_coordinates_GF2m(group, point, X, NULL, ctx)) {
++            ECerr(EC_F_OSSL_ECDSA_VERIFY_SIG, ERR_R_EC_LIB);
++            goto err;
++        }
++    }
++#endif
++    if (!BN_nnmod(u1, X, order, ctx)) {
++        ECerr(EC_F_OSSL_ECDSA_VERIFY_SIG, ERR_R_BN_LIB);
++        goto err;
++    }
++    /*  if the signature is correct u1 is equal to sig->r */
++    ret = (BN_ucmp(u1, sig->r) == 0);
++ err:
++    BN_CTX_end(ctx);
++    BN_CTX_free(ctx);
++    EC_POINT_free(point);
++    return ret;
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/ec/ecdsa_sign.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/ec/ecdsa_sign.c
+new file mode 100644
+index 0000000..aee06e9
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/ec/ecdsa_sign.c
+@@ -0,0 +1,52 @@
++/*
++ * Copyright 2015-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include "ec_lcl.h"
++#include 
++
++ECDSA_SIG *ECDSA_do_sign(const unsigned char *dgst, int dlen, EC_KEY *eckey)
++{
++    return ECDSA_do_sign_ex(dgst, dlen, NULL, NULL, eckey);
++}
++
++ECDSA_SIG *ECDSA_do_sign_ex(const unsigned char *dgst, int dlen,
++                            const BIGNUM *kinv, const BIGNUM *rp,
++                            EC_KEY *eckey)
++{
++    if (eckey->meth->sign_sig != NULL)
++        return eckey->meth->sign_sig(dgst, dlen, kinv, rp, eckey);
++    ECerr(EC_F_ECDSA_DO_SIGN_EX, EC_R_OPERATION_NOT_SUPPORTED);
++    return NULL;
++}
++
++int ECDSA_sign(int type, const unsigned char *dgst, int dlen, unsigned char
++               *sig, unsigned int *siglen, EC_KEY *eckey)
++{
++    return ECDSA_sign_ex(type, dgst, dlen, sig, siglen, NULL, NULL, eckey);
++}
++
++int ECDSA_sign_ex(int type, const unsigned char *dgst, int dlen,
++                  unsigned char *sig, unsigned int *siglen, const BIGNUM *kinv,
++                  const BIGNUM *r, EC_KEY *eckey)
++{
++    if (eckey->meth->sign != NULL)
++        return eckey->meth->sign(type, dgst, dlen, sig, siglen, kinv, r, eckey);
++    ECerr(EC_F_ECDSA_SIGN_EX, EC_R_OPERATION_NOT_SUPPORTED);
++    return 0;
++}
++
++int ECDSA_sign_setup(EC_KEY *eckey, BN_CTX *ctx_in, BIGNUM **kinvp,
++                     BIGNUM **rp)
++{
++    if (eckey->meth->sign_setup != NULL)
++        return eckey->meth->sign_setup(eckey, ctx_in, kinvp, rp);
++    ECerr(EC_F_ECDSA_SIGN_SETUP, EC_R_OPERATION_NOT_SUPPORTED);
++    return 0;
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/ec/ecdsa_vrf.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/ec/ecdsa_vrf.c
+new file mode 100644
+index 0000000..f61a200
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/ec/ecdsa_vrf.c
+@@ -0,0 +1,43 @@
++/*
++ * Copyright 2002-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include "ec_lcl.h"
++#include 
++
++/*-
++ * returns
++ *      1: correct signature
++ *      0: incorrect signature
++ *     -1: error
++ */
++int ECDSA_do_verify(const unsigned char *dgst, int dgst_len,
++                    const ECDSA_SIG *sig, EC_KEY *eckey)
++{
++    if (eckey->meth->verify_sig != NULL)
++        return eckey->meth->verify_sig(dgst, dgst_len, sig, eckey);
++    ECerr(EC_F_ECDSA_DO_VERIFY, EC_R_OPERATION_NOT_SUPPORTED);
++    return 0;
++}
++
++/*-
++ * returns
++ *      1: correct signature
++ *      0: incorrect signature
++ *     -1: error
++ */
++int ECDSA_verify(int type, const unsigned char *dgst, int dgst_len,
++                 const unsigned char *sigbuf, int sig_len, EC_KEY *eckey)
++{
++    if (eckey->meth->verify != NULL)
++        return eckey->meth->verify(type, dgst, dgst_len, sigbuf, sig_len,
++                                   eckey);
++    ECerr(EC_F_ECDSA_VERIFY, EC_R_OPERATION_NOT_SUPPORTED);
++    return 0;
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/ec/eck_prn.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/ec/eck_prn.c
+new file mode 100644
+index 0000000..dd3f857
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/ec/eck_prn.c
+@@ -0,0 +1,273 @@
++/*
++ * Copyright 2006-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++/* ====================================================================
++ * Copyright 2002 Sun Microsystems, Inc. ALL RIGHTS RESERVED.
++ * Portions originally developed by SUN MICROSYSTEMS, INC., and
++ * contributed to the OpenSSL project.
++ */
++
++#include 
++#include "internal/cryptlib.h"
++#include 
++#include 
++#include 
++
++#ifndef OPENSSL_NO_STDIO
++int ECPKParameters_print_fp(FILE *fp, const EC_GROUP *x, int off)
++{
++    BIO *b;
++    int ret;
++
++    if ((b = BIO_new(BIO_s_file())) == NULL) {
++        ECerr(EC_F_ECPKPARAMETERS_PRINT_FP, ERR_R_BUF_LIB);
++        return (0);
++    }
++    BIO_set_fp(b, fp, BIO_NOCLOSE);
++    ret = ECPKParameters_print(b, x, off);
++    BIO_free(b);
++    return (ret);
++}
++
++int EC_KEY_print_fp(FILE *fp, const EC_KEY *x, int off)
++{
++    BIO *b;
++    int ret;
++
++    if ((b = BIO_new(BIO_s_file())) == NULL) {
++        ECerr(EC_F_EC_KEY_PRINT_FP, ERR_R_BIO_LIB);
++        return (0);
++    }
++    BIO_set_fp(b, fp, BIO_NOCLOSE);
++    ret = EC_KEY_print(b, x, off);
++    BIO_free(b);
++    return (ret);
++}
++
++int ECParameters_print_fp(FILE *fp, const EC_KEY *x)
++{
++    BIO *b;
++    int ret;
++
++    if ((b = BIO_new(BIO_s_file())) == NULL) {
++        ECerr(EC_F_ECPARAMETERS_PRINT_FP, ERR_R_BIO_LIB);
++        return (0);
++    }
++    BIO_set_fp(b, fp, BIO_NOCLOSE);
++    ret = ECParameters_print(b, x);
++    BIO_free(b);
++    return (ret);
++}
++#endif
++
++static int print_bin(BIO *fp, const char *str, const unsigned char *num,
++                     size_t len, int off);
++
++int ECPKParameters_print(BIO *bp, const EC_GROUP *x, int off)
++{
++    int ret = 0, reason = ERR_R_BIO_LIB;
++    BN_CTX *ctx = NULL;
++    const EC_POINT *point = NULL;
++    BIGNUM *p = NULL, *a = NULL, *b = NULL, *gen = NULL;
++    const BIGNUM *order = NULL, *cofactor = NULL;
++    const unsigned char *seed;
++    size_t seed_len = 0;
++
++    static const char *gen_compressed = "Generator (compressed):";
++    static const char *gen_uncompressed = "Generator (uncompressed):";
++    static const char *gen_hybrid = "Generator (hybrid):";
++
++    if (!x) {
++        reason = ERR_R_PASSED_NULL_PARAMETER;
++        goto err;
++    }
++
++    ctx = BN_CTX_new();
++    if (ctx == NULL) {
++        reason = ERR_R_MALLOC_FAILURE;
++        goto err;
++    }
++
++    if (EC_GROUP_get_asn1_flag(x)) {
++        /* the curve parameter are given by an asn1 OID */
++        int nid;
++        const char *nname;
++
++        if (!BIO_indent(bp, off, 128))
++            goto err;
++
++        nid = EC_GROUP_get_curve_name(x);
++        if (nid == 0)
++            goto err;
++        if (BIO_printf(bp, "ASN1 OID: %s", OBJ_nid2sn(nid)) <= 0)
++            goto err;
++        if (BIO_printf(bp, "\n") <= 0)
++            goto err;
++        nname = EC_curve_nid2nist(nid);
++        if (nname) {
++            if (!BIO_indent(bp, off, 128))
++                goto err;
++            if (BIO_printf(bp, "NIST CURVE: %s\n", nname) <= 0)
++                goto err;
++        }
++    } else {
++        /* explicit parameters */
++        int is_char_two = 0;
++        point_conversion_form_t form;
++        int tmp_nid = EC_METHOD_get_field_type(EC_GROUP_method_of(x));
++
++        if (tmp_nid == NID_X9_62_characteristic_two_field)
++            is_char_two = 1;
++
++        if ((p = BN_new()) == NULL || (a = BN_new()) == NULL ||
++            (b = BN_new()) == NULL) {
++            reason = ERR_R_MALLOC_FAILURE;
++            goto err;
++        }
++#ifndef OPENSSL_NO_EC2M
++        if (is_char_two) {
++            if (!EC_GROUP_get_curve_GF2m(x, p, a, b, ctx)) {
++                reason = ERR_R_EC_LIB;
++                goto err;
++            }
++        } else                  /* prime field */
++#endif
++        {
++            if (!EC_GROUP_get_curve_GFp(x, p, a, b, ctx)) {
++                reason = ERR_R_EC_LIB;
++                goto err;
++            }
++        }
++
++        if ((point = EC_GROUP_get0_generator(x)) == NULL) {
++            reason = ERR_R_EC_LIB;
++            goto err;
++        }
++        order = EC_GROUP_get0_order(x);
++        cofactor = EC_GROUP_get0_cofactor(x);
++        if (order == NULL) {
++            reason = ERR_R_EC_LIB;
++            goto err;
++        }
++
++        form = EC_GROUP_get_point_conversion_form(x);
++
++        if ((gen = EC_POINT_point2bn(x, point, form, NULL, ctx)) == NULL) {
++            reason = ERR_R_EC_LIB;
++            goto err;
++        }
++
++        if ((seed = EC_GROUP_get0_seed(x)) != NULL)
++            seed_len = EC_GROUP_get_seed_len(x);
++
++        if (!BIO_indent(bp, off, 128))
++            goto err;
++
++        /* print the 'short name' of the field type */
++        if (BIO_printf(bp, "Field Type: %s\n", OBJ_nid2sn(tmp_nid))
++            <= 0)
++            goto err;
++
++        if (is_char_two) {
++            /* print the 'short name' of the base type OID */
++            int basis_type = EC_GROUP_get_basis_type(x);
++            if (basis_type == 0)
++                goto err;
++
++            if (!BIO_indent(bp, off, 128))
++                goto err;
++
++            if (BIO_printf(bp, "Basis Type: %s\n",
++                           OBJ_nid2sn(basis_type)) <= 0)
++                goto err;
++
++            /* print the polynomial */
++            if ((p != NULL) && !ASN1_bn_print(bp, "Polynomial:", p, NULL,
++                                              off))
++                goto err;
++        } else {
++            if ((p != NULL) && !ASN1_bn_print(bp, "Prime:", p, NULL, off))
++                goto err;
++        }
++        if ((a != NULL) && !ASN1_bn_print(bp, "A:   ", a, NULL, off))
++            goto err;
++        if ((b != NULL) && !ASN1_bn_print(bp, "B:   ", b, NULL, off))
++            goto err;
++        if (form == POINT_CONVERSION_COMPRESSED) {
++            if ((gen != NULL) && !ASN1_bn_print(bp, gen_compressed, gen,
++                                                NULL, off))
++                goto err;
++        } else if (form == POINT_CONVERSION_UNCOMPRESSED) {
++            if ((gen != NULL) && !ASN1_bn_print(bp, gen_uncompressed, gen,
++                                                NULL, off))
++                goto err;
++        } else {                /* form == POINT_CONVERSION_HYBRID */
++
++            if ((gen != NULL) && !ASN1_bn_print(bp, gen_hybrid, gen,
++                                                NULL, off))
++                goto err;
++        }
++        if ((order != NULL) && !ASN1_bn_print(bp, "Order: ", order,
++                                              NULL, off))
++            goto err;
++        if ((cofactor != NULL) && !ASN1_bn_print(bp, "Cofactor: ", cofactor,
++                                                 NULL, off))
++            goto err;
++        if (seed && !print_bin(bp, "Seed:", seed, seed_len, off))
++            goto err;
++    }
++    ret = 1;
++ err:
++    if (!ret)
++        ECerr(EC_F_ECPKPARAMETERS_PRINT, reason);
++    BN_free(p);
++    BN_free(a);
++    BN_free(b);
++    BN_free(gen);
++    BN_CTX_free(ctx);
++    return (ret);
++}
++
++static int print_bin(BIO *fp, const char *name, const unsigned char *buf,
++                     size_t len, int off)
++{
++    size_t i;
++    char str[128];
++
++    if (buf == NULL)
++        return 1;
++    if (off > 0) {
++        if (off > 128)
++            off = 128;
++        memset(str, ' ', off);
++        if (BIO_write(fp, str, off) <= 0)
++            return 0;
++    } else {
++        off = 0;
++    }
++
++    if (BIO_printf(fp, "%s", name) <= 0)
++        return 0;
++
++    for (i = 0; i < len; i++) {
++        if ((i % 15) == 0) {
++            str[0] = '\n';
++            memset(&(str[1]), ' ', off + 4);
++            if (BIO_write(fp, str, off + 1 + 4) <= 0)
++                return 0;
++        }
++        if (BIO_printf(fp, "%02x%s", buf[i], ((i + 1) == len) ? "" : ":") <=
++            0)
++            return 0;
++    }
++    if (BIO_write(fp, "\n", 1) <= 0)
++        return 0;
++
++    return 1;
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/ec/ecp_mont.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/ec/ecp_mont.c
+new file mode 100644
+index 0000000..994cc1d
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/ec/ecp_mont.c
+@@ -0,0 +1,242 @@
++/*
++ * Copyright 2001-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++/* ====================================================================
++ * Copyright 2002 Sun Microsystems, Inc. ALL RIGHTS RESERVED.
++ * Portions of this software developed by SUN MICROSYSTEMS, INC.,
++ * and contributed to the OpenSSL project.
++ */
++
++#include 
++
++#include "ec_lcl.h"
++
++const EC_METHOD *EC_GFp_mont_method(void)
++{
++    static const EC_METHOD ret = {
++        EC_FLAGS_DEFAULT_OCT,
++        NID_X9_62_prime_field,
++        ec_GFp_mont_group_init,
++        ec_GFp_mont_group_finish,
++        ec_GFp_mont_group_clear_finish,
++        ec_GFp_mont_group_copy,
++        ec_GFp_mont_group_set_curve,
++        ec_GFp_simple_group_get_curve,
++        ec_GFp_simple_group_get_degree,
++        ec_group_simple_order_bits,
++        ec_GFp_simple_group_check_discriminant,
++        ec_GFp_simple_point_init,
++        ec_GFp_simple_point_finish,
++        ec_GFp_simple_point_clear_finish,
++        ec_GFp_simple_point_copy,
++        ec_GFp_simple_point_set_to_infinity,
++        ec_GFp_simple_set_Jprojective_coordinates_GFp,
++        ec_GFp_simple_get_Jprojective_coordinates_GFp,
++        ec_GFp_simple_point_set_affine_coordinates,
++        ec_GFp_simple_point_get_affine_coordinates,
++        0, 0, 0,
++        ec_GFp_simple_add,
++        ec_GFp_simple_dbl,
++        ec_GFp_simple_invert,
++        ec_GFp_simple_is_at_infinity,
++        ec_GFp_simple_is_on_curve,
++        ec_GFp_simple_cmp,
++        ec_GFp_simple_make_affine,
++        ec_GFp_simple_points_make_affine,
++        0 /* mul */ ,
++        0 /* precompute_mult */ ,
++        0 /* have_precompute_mult */ ,
++        ec_GFp_mont_field_mul,
++        ec_GFp_mont_field_sqr,
++        0 /* field_div */ ,
++        ec_GFp_mont_field_encode,
++        ec_GFp_mont_field_decode,
++        ec_GFp_mont_field_set_to_one,
++        ec_key_simple_priv2oct,
++        ec_key_simple_oct2priv,
++        0, /* set private */
++        ec_key_simple_generate_key,
++        ec_key_simple_check_key,
++        ec_key_simple_generate_public_key,
++        0, /* keycopy */
++        0, /* keyfinish */
++        ecdh_simple_compute_key
++    };
++
++    return &ret;
++}
++
++int ec_GFp_mont_group_init(EC_GROUP *group)
++{
++    int ok;
++
++    ok = ec_GFp_simple_group_init(group);
++    group->field_data1 = NULL;
++    group->field_data2 = NULL;
++    return ok;
++}
++
++void ec_GFp_mont_group_finish(EC_GROUP *group)
++{
++    BN_MONT_CTX_free(group->field_data1);
++    group->field_data1 = NULL;
++    BN_free(group->field_data2);
++    group->field_data2 = NULL;
++    ec_GFp_simple_group_finish(group);
++}
++
++void ec_GFp_mont_group_clear_finish(EC_GROUP *group)
++{
++    BN_MONT_CTX_free(group->field_data1);
++    group->field_data1 = NULL;
++    BN_clear_free(group->field_data2);
++    group->field_data2 = NULL;
++    ec_GFp_simple_group_clear_finish(group);
++}
++
++int ec_GFp_mont_group_copy(EC_GROUP *dest, const EC_GROUP *src)
++{
++    BN_MONT_CTX_free(dest->field_data1);
++    dest->field_data1 = NULL;
++    BN_clear_free(dest->field_data2);
++    dest->field_data2 = NULL;
++
++    if (!ec_GFp_simple_group_copy(dest, src))
++        return 0;
++
++    if (src->field_data1 != NULL) {
++        dest->field_data1 = BN_MONT_CTX_new();
++        if (dest->field_data1 == NULL)
++            return 0;
++        if (!BN_MONT_CTX_copy(dest->field_data1, src->field_data1))
++            goto err;
++    }
++    if (src->field_data2 != NULL) {
++        dest->field_data2 = BN_dup(src->field_data2);
++        if (dest->field_data2 == NULL)
++            goto err;
++    }
++
++    return 1;
++
++ err:
++    BN_MONT_CTX_free(dest->field_data1);
++    dest->field_data1 = NULL;
++    return 0;
++}
++
++int ec_GFp_mont_group_set_curve(EC_GROUP *group, const BIGNUM *p,
++                                const BIGNUM *a, const BIGNUM *b, BN_CTX *ctx)
++{
++    BN_CTX *new_ctx = NULL;
++    BN_MONT_CTX *mont = NULL;
++    BIGNUM *one = NULL;
++    int ret = 0;
++
++    BN_MONT_CTX_free(group->field_data1);
++    group->field_data1 = NULL;
++    BN_free(group->field_data2);
++    group->field_data2 = NULL;
++
++    if (ctx == NULL) {
++        ctx = new_ctx = BN_CTX_new();
++        if (ctx == NULL)
++            return 0;
++    }
++
++    mont = BN_MONT_CTX_new();
++    if (mont == NULL)
++        goto err;
++    if (!BN_MONT_CTX_set(mont, p, ctx)) {
++        ECerr(EC_F_EC_GFP_MONT_GROUP_SET_CURVE, ERR_R_BN_LIB);
++        goto err;
++    }
++    one = BN_new();
++    if (one == NULL)
++        goto err;
++    if (!BN_to_montgomery(one, BN_value_one(), mont, ctx))
++        goto err;
++
++    group->field_data1 = mont;
++    mont = NULL;
++    group->field_data2 = one;
++    one = NULL;
++
++    ret = ec_GFp_simple_group_set_curve(group, p, a, b, ctx);
++
++    if (!ret) {
++        BN_MONT_CTX_free(group->field_data1);
++        group->field_data1 = NULL;
++        BN_free(group->field_data2);
++        group->field_data2 = NULL;
++    }
++
++ err:
++    BN_free(one);
++    BN_CTX_free(new_ctx);
++    BN_MONT_CTX_free(mont);
++    return ret;
++}
++
++int ec_GFp_mont_field_mul(const EC_GROUP *group, BIGNUM *r, const BIGNUM *a,
++                          const BIGNUM *b, BN_CTX *ctx)
++{
++    if (group->field_data1 == NULL) {
++        ECerr(EC_F_EC_GFP_MONT_FIELD_MUL, EC_R_NOT_INITIALIZED);
++        return 0;
++    }
++
++    return BN_mod_mul_montgomery(r, a, b, group->field_data1, ctx);
++}
++
++int ec_GFp_mont_field_sqr(const EC_GROUP *group, BIGNUM *r, const BIGNUM *a,
++                          BN_CTX *ctx)
++{
++    if (group->field_data1 == NULL) {
++        ECerr(EC_F_EC_GFP_MONT_FIELD_SQR, EC_R_NOT_INITIALIZED);
++        return 0;
++    }
++
++    return BN_mod_mul_montgomery(r, a, a, group->field_data1, ctx);
++}
++
++int ec_GFp_mont_field_encode(const EC_GROUP *group, BIGNUM *r,
++                             const BIGNUM *a, BN_CTX *ctx)
++{
++    if (group->field_data1 == NULL) {
++        ECerr(EC_F_EC_GFP_MONT_FIELD_ENCODE, EC_R_NOT_INITIALIZED);
++        return 0;
++    }
++
++    return BN_to_montgomery(r, a, (BN_MONT_CTX *)group->field_data1, ctx);
++}
++
++int ec_GFp_mont_field_decode(const EC_GROUP *group, BIGNUM *r,
++                             const BIGNUM *a, BN_CTX *ctx)
++{
++    if (group->field_data1 == NULL) {
++        ECerr(EC_F_EC_GFP_MONT_FIELD_DECODE, EC_R_NOT_INITIALIZED);
++        return 0;
++    }
++
++    return BN_from_montgomery(r, a, group->field_data1, ctx);
++}
++
++int ec_GFp_mont_field_set_to_one(const EC_GROUP *group, BIGNUM *r,
++                                 BN_CTX *ctx)
++{
++    if (group->field_data2 == NULL) {
++        ECerr(EC_F_EC_GFP_MONT_FIELD_SET_TO_ONE, EC_R_NOT_INITIALIZED);
++        return 0;
++    }
++
++    if (!BN_copy(r, group->field_data2))
++        return 0;
++    return 1;
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/ec/ecp_nist.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/ec/ecp_nist.c
+new file mode 100644
+index 0000000..615563b
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/ec/ecp_nist.c
+@@ -0,0 +1,167 @@
++/*
++ * Copyright 2001-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++/* ====================================================================
++ * Copyright 2002 Sun Microsystems, Inc. ALL RIGHTS RESERVED.
++ * Portions of this software developed by SUN MICROSYSTEMS, INC.,
++ * and contributed to the OpenSSL project.
++ */
++
++#include 
++
++#include 
++#include 
++#include "ec_lcl.h"
++
++const EC_METHOD *EC_GFp_nist_method(void)
++{
++    static const EC_METHOD ret = {
++        EC_FLAGS_DEFAULT_OCT,
++        NID_X9_62_prime_field,
++        ec_GFp_simple_group_init,
++        ec_GFp_simple_group_finish,
++        ec_GFp_simple_group_clear_finish,
++        ec_GFp_nist_group_copy,
++        ec_GFp_nist_group_set_curve,
++        ec_GFp_simple_group_get_curve,
++        ec_GFp_simple_group_get_degree,
++        ec_group_simple_order_bits,
++        ec_GFp_simple_group_check_discriminant,
++        ec_GFp_simple_point_init,
++        ec_GFp_simple_point_finish,
++        ec_GFp_simple_point_clear_finish,
++        ec_GFp_simple_point_copy,
++        ec_GFp_simple_point_set_to_infinity,
++        ec_GFp_simple_set_Jprojective_coordinates_GFp,
++        ec_GFp_simple_get_Jprojective_coordinates_GFp,
++        ec_GFp_simple_point_set_affine_coordinates,
++        ec_GFp_simple_point_get_affine_coordinates,
++        0, 0, 0,
++        ec_GFp_simple_add,
++        ec_GFp_simple_dbl,
++        ec_GFp_simple_invert,
++        ec_GFp_simple_is_at_infinity,
++        ec_GFp_simple_is_on_curve,
++        ec_GFp_simple_cmp,
++        ec_GFp_simple_make_affine,
++        ec_GFp_simple_points_make_affine,
++        0 /* mul */ ,
++        0 /* precompute_mult */ ,
++        0 /* have_precompute_mult */ ,
++        ec_GFp_nist_field_mul,
++        ec_GFp_nist_field_sqr,
++        0 /* field_div */ ,
++        0 /* field_encode */ ,
++        0 /* field_decode */ ,
++        0,                      /* field_set_to_one */
++        ec_key_simple_priv2oct,
++        ec_key_simple_oct2priv,
++        0, /* set private */
++        ec_key_simple_generate_key,
++        ec_key_simple_check_key,
++        ec_key_simple_generate_public_key,
++        0, /* keycopy */
++        0, /* keyfinish */
++        ecdh_simple_compute_key
++    };
++
++    return &ret;
++}
++
++int ec_GFp_nist_group_copy(EC_GROUP *dest, const EC_GROUP *src)
++{
++    dest->field_mod_func = src->field_mod_func;
++
++    return ec_GFp_simple_group_copy(dest, src);
++}
++
++int ec_GFp_nist_group_set_curve(EC_GROUP *group, const BIGNUM *p,
++                                const BIGNUM *a, const BIGNUM *b, BN_CTX *ctx)
++{
++    int ret = 0;
++    BN_CTX *new_ctx = NULL;
++
++    if (ctx == NULL)
++        if ((ctx = new_ctx = BN_CTX_new()) == NULL)
++            return 0;
++
++    BN_CTX_start(ctx);
++
++    if (BN_ucmp(BN_get0_nist_prime_192(), p) == 0)
++        group->field_mod_func = BN_nist_mod_192;
++    else if (BN_ucmp(BN_get0_nist_prime_224(), p) == 0)
++        group->field_mod_func = BN_nist_mod_224;
++    else if (BN_ucmp(BN_get0_nist_prime_256(), p) == 0)
++        group->field_mod_func = BN_nist_mod_256;
++    else if (BN_ucmp(BN_get0_nist_prime_384(), p) == 0)
++        group->field_mod_func = BN_nist_mod_384;
++    else if (BN_ucmp(BN_get0_nist_prime_521(), p) == 0)
++        group->field_mod_func = BN_nist_mod_521;
++    else {
++        ECerr(EC_F_EC_GFP_NIST_GROUP_SET_CURVE, EC_R_NOT_A_NIST_PRIME);
++        goto err;
++    }
++
++    ret = ec_GFp_simple_group_set_curve(group, p, a, b, ctx);
++
++ err:
++    BN_CTX_end(ctx);
++    BN_CTX_free(new_ctx);
++    return ret;
++}
++
++int ec_GFp_nist_field_mul(const EC_GROUP *group, BIGNUM *r, const BIGNUM *a,
++                          const BIGNUM *b, BN_CTX *ctx)
++{
++    int ret = 0;
++    BN_CTX *ctx_new = NULL;
++
++    if (!group || !r || !a || !b) {
++        ECerr(EC_F_EC_GFP_NIST_FIELD_MUL, ERR_R_PASSED_NULL_PARAMETER);
++        goto err;
++    }
++    if (!ctx)
++        if ((ctx_new = ctx = BN_CTX_new()) == NULL)
++            goto err;
++
++    if (!BN_mul(r, a, b, ctx))
++        goto err;
++    if (!group->field_mod_func(r, r, group->field, ctx))
++        goto err;
++
++    ret = 1;
++ err:
++    BN_CTX_free(ctx_new);
++    return ret;
++}
++
++int ec_GFp_nist_field_sqr(const EC_GROUP *group, BIGNUM *r, const BIGNUM *a,
++                          BN_CTX *ctx)
++{
++    int ret = 0;
++    BN_CTX *ctx_new = NULL;
++
++    if (!group || !r || !a) {
++        ECerr(EC_F_EC_GFP_NIST_FIELD_SQR, EC_R_PASSED_NULL_PARAMETER);
++        goto err;
++    }
++    if (!ctx)
++        if ((ctx_new = ctx = BN_CTX_new()) == NULL)
++            goto err;
++
++    if (!BN_sqr(r, a, ctx))
++        goto err;
++    if (!group->field_mod_func(r, r, group->field, ctx))
++        goto err;
++
++    ret = 1;
++ err:
++    BN_CTX_free(ctx_new);
++    return ret;
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/ec/ecp_nistp224.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/ec/ecp_nistp224.c
+new file mode 100644
+index 0000000..0c11abc
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/ec/ecp_nistp224.c
+@@ -0,0 +1,1717 @@
++/*
++ * Copyright 2010-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++/* Copyright 2011 Google Inc.
++ *
++ * Licensed under the Apache License, Version 2.0 (the "License");
++ *
++ * you may not use this file except in compliance with the License.
++ * You may obtain a copy of the License at
++ *
++ *     http://www.apache.org/licenses/LICENSE-2.0
++ *
++ *  Unless required by applicable law or agreed to in writing, software
++ *  distributed under the License is distributed on an "AS IS" BASIS,
++ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ *  See the License for the specific language governing permissions and
++ *  limitations under the License.
++ */
++
++/*
++ * A 64-bit implementation of the NIST P-224 elliptic curve point multiplication
++ *
++ * Inspired by Daniel J. Bernstein's public domain nistp224 implementation
++ * and Adam Langley's public domain 64-bit C implementation of curve25519
++ */
++
++#include 
++#ifdef OPENSSL_NO_EC_NISTP_64_GCC_128
++NON_EMPTY_TRANSLATION_UNIT
++#else
++
++# include 
++# include 
++# include 
++# include "ec_lcl.h"
++
++# if defined(__GNUC__) && (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 1))
++  /* even with gcc, the typedef won't work for 32-bit platforms */
++typedef __uint128_t uint128_t;  /* nonstandard; implemented by gcc on 64-bit
++                                 * platforms */
++# else
++#  error "Need GCC 3.1 or later to define type uint128_t"
++# endif
++
++typedef uint8_t u8;
++typedef uint64_t u64;
++typedef int64_t s64;
++
++/******************************************************************************/
++/*-
++ * INTERNAL REPRESENTATION OF FIELD ELEMENTS
++ *
++ * Field elements are represented as a_0 + 2^56*a_1 + 2^112*a_2 + 2^168*a_3
++ * using 64-bit coefficients called 'limbs',
++ * and sometimes (for multiplication results) as
++ * b_0 + 2^56*b_1 + 2^112*b_2 + 2^168*b_3 + 2^224*b_4 + 2^280*b_5 + 2^336*b_6
++ * using 128-bit coefficients called 'widelimbs'.
++ * A 4-limb representation is an 'felem';
++ * a 7-widelimb representation is a 'widefelem'.
++ * Even within felems, bits of adjacent limbs overlap, and we don't always
++ * reduce the representations: we ensure that inputs to each felem
++ * multiplication satisfy a_i < 2^60, so outputs satisfy b_i < 4*2^60*2^60,
++ * and fit into a 128-bit word without overflow. The coefficients are then
++ * again partially reduced to obtain an felem satisfying a_i < 2^57.
++ * We only reduce to the unique minimal representation at the end of the
++ * computation.
++ */
++
++typedef uint64_t limb;
++typedef uint128_t widelimb;
++
++typedef limb felem[4];
++typedef widelimb widefelem[7];
++
++/*
++ * Field element represented as a byte arrary. 28*8 = 224 bits is also the
++ * group order size for the elliptic curve, and we also use this type for
++ * scalars for point multiplication.
++ */
++typedef u8 felem_bytearray[28];
++
++static const felem_bytearray nistp224_curve_params[5] = {
++    {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, /* p */
++     0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00,
++     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01},
++    {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, /* a */
++     0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF,
++     0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE},
++    {0xB4, 0x05, 0x0A, 0x85, 0x0C, 0x04, 0xB3, 0xAB, 0xF5, 0x41, /* b */
++     0x32, 0x56, 0x50, 0x44, 0xB0, 0xB7, 0xD7, 0xBF, 0xD8, 0xBA,
++     0x27, 0x0B, 0x39, 0x43, 0x23, 0x55, 0xFF, 0xB4},
++    {0xB7, 0x0E, 0x0C, 0xBD, 0x6B, 0xB4, 0xBF, 0x7F, 0x32, 0x13, /* x */
++     0x90, 0xB9, 0x4A, 0x03, 0xC1, 0xD3, 0x56, 0xC2, 0x11, 0x22,
++     0x34, 0x32, 0x80, 0xD6, 0x11, 0x5C, 0x1D, 0x21},
++    {0xbd, 0x37, 0x63, 0x88, 0xb5, 0xf7, 0x23, 0xfb, 0x4c, 0x22, /* y */
++     0xdf, 0xe6, 0xcd, 0x43, 0x75, 0xa0, 0x5a, 0x07, 0x47, 0x64,
++     0x44, 0xd5, 0x81, 0x99, 0x85, 0x00, 0x7e, 0x34}
++};
++
++/*-
++ * Precomputed multiples of the standard generator
++ * Points are given in coordinates (X, Y, Z) where Z normally is 1
++ * (0 for the point at infinity).
++ * For each field element, slice a_0 is word 0, etc.
++ *
++ * The table has 2 * 16 elements, starting with the following:
++ * index | bits    | point
++ * ------+---------+------------------------------
++ *     0 | 0 0 0 0 | 0G
++ *     1 | 0 0 0 1 | 1G
++ *     2 | 0 0 1 0 | 2^56G
++ *     3 | 0 0 1 1 | (2^56 + 1)G
++ *     4 | 0 1 0 0 | 2^112G
++ *     5 | 0 1 0 1 | (2^112 + 1)G
++ *     6 | 0 1 1 0 | (2^112 + 2^56)G
++ *     7 | 0 1 1 1 | (2^112 + 2^56 + 1)G
++ *     8 | 1 0 0 0 | 2^168G
++ *     9 | 1 0 0 1 | (2^168 + 1)G
++ *    10 | 1 0 1 0 | (2^168 + 2^56)G
++ *    11 | 1 0 1 1 | (2^168 + 2^56 + 1)G
++ *    12 | 1 1 0 0 | (2^168 + 2^112)G
++ *    13 | 1 1 0 1 | (2^168 + 2^112 + 1)G
++ *    14 | 1 1 1 0 | (2^168 + 2^112 + 2^56)G
++ *    15 | 1 1 1 1 | (2^168 + 2^112 + 2^56 + 1)G
++ * followed by a copy of this with each element multiplied by 2^28.
++ *
++ * The reason for this is so that we can clock bits into four different
++ * locations when doing simple scalar multiplies against the base point,
++ * and then another four locations using the second 16 elements.
++ */
++static const felem gmul[2][16][3] = {
++{{{0, 0, 0, 0},
++  {0, 0, 0, 0},
++  {0, 0, 0, 0}},
++ {{0x3280d6115c1d21, 0xc1d356c2112234, 0x7f321390b94a03, 0xb70e0cbd6bb4bf},
++  {0xd5819985007e34, 0x75a05a07476444, 0xfb4c22dfe6cd43, 0xbd376388b5f723},
++  {1, 0, 0, 0}},
++ {{0xfd9675666ebbe9, 0xbca7664d40ce5e, 0x2242df8d8a2a43, 0x1f49bbb0f99bc5},
++  {0x29e0b892dc9c43, 0xece8608436e662, 0xdc858f185310d0, 0x9812dd4eb8d321},
++  {1, 0, 0, 0}},
++ {{0x6d3e678d5d8eb8, 0x559eed1cb362f1, 0x16e9a3bbce8a3f, 0xeedcccd8c2a748},
++  {0xf19f90ed50266d, 0xabf2b4bf65f9df, 0x313865468fafec, 0x5cb379ba910a17},
++  {1, 0, 0, 0}},
++ {{0x0641966cab26e3, 0x91fb2991fab0a0, 0xefec27a4e13a0b, 0x0499aa8a5f8ebe},
++  {0x7510407766af5d, 0x84d929610d5450, 0x81d77aae82f706, 0x6916f6d4338c5b},
++  {1, 0, 0, 0}},
++ {{0xea95ac3b1f15c6, 0x086000905e82d4, 0xdd323ae4d1c8b1, 0x932b56be7685a3},
++  {0x9ef93dea25dbbf, 0x41665960f390f0, 0xfdec76dbe2a8a7, 0x523e80f019062a},
++  {1, 0, 0, 0}},
++ {{0x822fdd26732c73, 0xa01c83531b5d0f, 0x363f37347c1ba4, 0xc391b45c84725c},
++  {0xbbd5e1b2d6ad24, 0xddfbcde19dfaec, 0xc393da7e222a7f, 0x1efb7890ede244},
++  {1, 0, 0, 0}},
++ {{0x4c9e90ca217da1, 0xd11beca79159bb, 0xff8d33c2c98b7c, 0x2610b39409f849},
++  {0x44d1352ac64da0, 0xcdbb7b2c46b4fb, 0x966c079b753c89, 0xfe67e4e820b112},
++  {1, 0, 0, 0}},
++ {{0xe28cae2df5312d, 0xc71b61d16f5c6e, 0x79b7619a3e7c4c, 0x05c73240899b47},
++  {0x9f7f6382c73e3a, 0x18615165c56bda, 0x641fab2116fd56, 0x72855882b08394},
++  {1, 0, 0, 0}},
++ {{0x0469182f161c09, 0x74a98ca8d00fb5, 0xb89da93489a3e0, 0x41c98768fb0c1d},
++  {0xe5ea05fb32da81, 0x3dce9ffbca6855, 0x1cfe2d3fbf59e6, 0x0e5e03408738a7},
++  {1, 0, 0, 0}},
++ {{0xdab22b2333e87f, 0x4430137a5dd2f6, 0xe03ab9f738beb8, 0xcb0c5d0dc34f24},
++  {0x764a7df0c8fda5, 0x185ba5c3fa2044, 0x9281d688bcbe50, 0xc40331df893881},
++  {1, 0, 0, 0}},
++ {{0xb89530796f0f60, 0xade92bd26909a3, 0x1a0c83fb4884da, 0x1765bf22a5a984},
++  {0x772a9ee75db09e, 0x23bc6c67cec16f, 0x4c1edba8b14e2f, 0xe2a215d9611369},
++  {1, 0, 0, 0}},
++ {{0x571e509fb5efb3, 0xade88696410552, 0xc8ae85fada74fe, 0x6c7e4be83bbde3},
++  {0xff9f51160f4652, 0xb47ce2495a6539, 0xa2946c53b582f4, 0x286d2db3ee9a60},
++  {1, 0, 0, 0}},
++ {{0x40bbd5081a44af, 0x0995183b13926c, 0xbcefba6f47f6d0, 0x215619e9cc0057},
++  {0x8bc94d3b0df45e, 0xf11c54a3694f6f, 0x8631b93cdfe8b5, 0xe7e3f4b0982db9},
++  {1, 0, 0, 0}},
++ {{0xb17048ab3e1c7b, 0xac38f36ff8a1d8, 0x1c29819435d2c6, 0xc813132f4c07e9},
++  {0x2891425503b11f, 0x08781030579fea, 0xf5426ba5cc9674, 0x1e28ebf18562bc},
++  {1, 0, 0, 0}},
++ {{0x9f31997cc864eb, 0x06cd91d28b5e4c, 0xff17036691a973, 0xf1aef351497c58},
++  {0xdd1f2d600564ff, 0xdead073b1402db, 0x74a684435bd693, 0xeea7471f962558},
++  {1, 0, 0, 0}}},
++{{{0, 0, 0, 0},
++  {0, 0, 0, 0},
++  {0, 0, 0, 0}},
++ {{0x9665266dddf554, 0x9613d78b60ef2d, 0xce27a34cdba417, 0xd35ab74d6afc31},
++  {0x85ccdd22deb15e, 0x2137e5783a6aab, 0xa141cffd8c93c6, 0x355a1830e90f2d},
++  {1, 0, 0, 0}},
++ {{0x1a494eadaade65, 0xd6da4da77fe53c, 0xe7992996abec86, 0x65c3553c6090e3},
++  {0xfa610b1fb09346, 0xf1c6540b8a4aaf, 0xc51a13ccd3cbab, 0x02995b1b18c28a},
++  {1, 0, 0, 0}},
++ {{0x7874568e7295ef, 0x86b419fbe38d04, 0xdc0690a7550d9a, 0xd3966a44beac33},
++  {0x2b7280ec29132f, 0xbeaa3b6a032df3, 0xdc7dd88ae41200, 0xd25e2513e3a100},
++  {1, 0, 0, 0}},
++ {{0x924857eb2efafd, 0xac2bce41223190, 0x8edaa1445553fc, 0x825800fd3562d5},
++  {0x8d79148ea96621, 0x23a01c3dd9ed8d, 0xaf8b219f9416b5, 0xd8db0cc277daea},
++  {1, 0, 0, 0}},
++ {{0x76a9c3b1a700f0, 0xe9acd29bc7e691, 0x69212d1a6b0327, 0x6322e97fe154be},
++  {0x469fc5465d62aa, 0x8d41ed18883b05, 0x1f8eae66c52b88, 0xe4fcbe9325be51},
++  {1, 0, 0, 0}},
++ {{0x825fdf583cac16, 0x020b857c7b023a, 0x683c17744b0165, 0x14ffd0a2daf2f1},
++  {0x323b36184218f9, 0x4944ec4e3b47d4, 0xc15b3080841acf, 0x0bced4b01a28bb},
++  {1, 0, 0, 0}},
++ {{0x92ac22230df5c4, 0x52f33b4063eda8, 0xcb3f19870c0c93, 0x40064f2ba65233},
++  {0xfe16f0924f8992, 0x012da25af5b517, 0x1a57bb24f723a6, 0x06f8bc76760def},
++  {1, 0, 0, 0}},
++ {{0x4a7084f7817cb9, 0xbcab0738ee9a78, 0x3ec11e11d9c326, 0xdc0fe90e0f1aae},
++  {0xcf639ea5f98390, 0x5c350aa22ffb74, 0x9afae98a4047b7, 0x956ec2d617fc45},
++  {1, 0, 0, 0}},
++ {{0x4306d648c1be6a, 0x9247cd8bc9a462, 0xf5595e377d2f2e, 0xbd1c3caff1a52e},
++  {0x045e14472409d0, 0x29f3e17078f773, 0x745a602b2d4f7d, 0x191837685cdfbb},
++  {1, 0, 0, 0}},
++ {{0x5b6ee254a8cb79, 0x4953433f5e7026, 0xe21faeb1d1def4, 0xc4c225785c09de},
++  {0x307ce7bba1e518, 0x31b125b1036db8, 0x47e91868839e8f, 0xc765866e33b9f3},
++  {1, 0, 0, 0}},
++ {{0x3bfece24f96906, 0x4794da641e5093, 0xde5df64f95db26, 0x297ecd89714b05},
++  {0x701bd3ebb2c3aa, 0x7073b4f53cb1d5, 0x13c5665658af16, 0x9895089d66fe58},
++  {1, 0, 0, 0}},
++ {{0x0fef05f78c4790, 0x2d773633b05d2e, 0x94229c3a951c94, 0xbbbd70df4911bb},
++  {0xb2c6963d2c1168, 0x105f47a72b0d73, 0x9fdf6111614080, 0x7b7e94b39e67b0},
++  {1, 0, 0, 0}},
++ {{0xad1a7d6efbe2b3, 0xf012482c0da69d, 0x6b3bdf12438345, 0x40d7558d7aa4d9},
++  {0x8a09fffb5c6d3d, 0x9a356e5d9ffd38, 0x5973f15f4f9b1c, 0xdcd5f59f63c3ea},
++  {1, 0, 0, 0}},
++ {{0xacf39f4c5ca7ab, 0x4c8071cc5fd737, 0xc64e3602cd1184, 0x0acd4644c9abba},
++  {0x6c011a36d8bf6e, 0xfecd87ba24e32a, 0x19f6f56574fad8, 0x050b204ced9405},
++  {1, 0, 0, 0}},
++ {{0xed4f1cae7d9a96, 0x5ceef7ad94c40a, 0x778e4a3bf3ef9b, 0x7405783dc3b55e},
++  {0x32477c61b6e8c6, 0xb46a97570f018b, 0x91176d0a7e95d1, 0x3df90fbc4c7d0e},
++  {1, 0, 0, 0}}}
++};
++
++/* Precomputation for the group generator. */
++struct nistp224_pre_comp_st {
++    felem g_pre_comp[2][16][3];
++    int references;
++    CRYPTO_RWLOCK *lock;
++};
++
++const EC_METHOD *EC_GFp_nistp224_method(void)
++{
++    static const EC_METHOD ret = {
++        EC_FLAGS_DEFAULT_OCT,
++        NID_X9_62_prime_field,
++        ec_GFp_nistp224_group_init,
++        ec_GFp_simple_group_finish,
++        ec_GFp_simple_group_clear_finish,
++        ec_GFp_nist_group_copy,
++        ec_GFp_nistp224_group_set_curve,
++        ec_GFp_simple_group_get_curve,
++        ec_GFp_simple_group_get_degree,
++        ec_group_simple_order_bits,
++        ec_GFp_simple_group_check_discriminant,
++        ec_GFp_simple_point_init,
++        ec_GFp_simple_point_finish,
++        ec_GFp_simple_point_clear_finish,
++        ec_GFp_simple_point_copy,
++        ec_GFp_simple_point_set_to_infinity,
++        ec_GFp_simple_set_Jprojective_coordinates_GFp,
++        ec_GFp_simple_get_Jprojective_coordinates_GFp,
++        ec_GFp_simple_point_set_affine_coordinates,
++        ec_GFp_nistp224_point_get_affine_coordinates,
++        0 /* point_set_compressed_coordinates */ ,
++        0 /* point2oct */ ,
++        0 /* oct2point */ ,
++        ec_GFp_simple_add,
++        ec_GFp_simple_dbl,
++        ec_GFp_simple_invert,
++        ec_GFp_simple_is_at_infinity,
++        ec_GFp_simple_is_on_curve,
++        ec_GFp_simple_cmp,
++        ec_GFp_simple_make_affine,
++        ec_GFp_simple_points_make_affine,
++        ec_GFp_nistp224_points_mul,
++        ec_GFp_nistp224_precompute_mult,
++        ec_GFp_nistp224_have_precompute_mult,
++        ec_GFp_nist_field_mul,
++        ec_GFp_nist_field_sqr,
++        0 /* field_div */ ,
++        0 /* field_encode */ ,
++        0 /* field_decode */ ,
++        0,                      /* field_set_to_one */
++        ec_key_simple_priv2oct,
++        ec_key_simple_oct2priv,
++        0, /* set private */
++        ec_key_simple_generate_key,
++        ec_key_simple_check_key,
++        ec_key_simple_generate_public_key,
++        0, /* keycopy */
++        0, /* keyfinish */
++        ecdh_simple_compute_key
++    };
++
++    return &ret;
++}
++
++/*
++ * Helper functions to convert field elements to/from internal representation
++ */
++static void bin28_to_felem(felem out, const u8 in[28])
++{
++    out[0] = *((const uint64_t *)(in)) & 0x00ffffffffffffff;
++    out[1] = (*((const uint64_t *)(in + 7))) & 0x00ffffffffffffff;
++    out[2] = (*((const uint64_t *)(in + 14))) & 0x00ffffffffffffff;
++    out[3] = (*((const uint64_t *)(in+20))) >> 8;
++}
++
++static void felem_to_bin28(u8 out[28], const felem in)
++{
++    unsigned i;
++    for (i = 0; i < 7; ++i) {
++        out[i] = in[0] >> (8 * i);
++        out[i + 7] = in[1] >> (8 * i);
++        out[i + 14] = in[2] >> (8 * i);
++        out[i + 21] = in[3] >> (8 * i);
++    }
++}
++
++/* To preserve endianness when using BN_bn2bin and BN_bin2bn */
++static void flip_endian(u8 *out, const u8 *in, unsigned len)
++{
++    unsigned i;
++    for (i = 0; i < len; ++i)
++        out[i] = in[len - 1 - i];
++}
++
++/* From OpenSSL BIGNUM to internal representation */
++static int BN_to_felem(felem out, const BIGNUM *bn)
++{
++    felem_bytearray b_in;
++    felem_bytearray b_out;
++    unsigned num_bytes;
++
++    /* BN_bn2bin eats leading zeroes */
++    memset(b_out, 0, sizeof(b_out));
++    num_bytes = BN_num_bytes(bn);
++    if (num_bytes > sizeof b_out) {
++        ECerr(EC_F_BN_TO_FELEM, EC_R_BIGNUM_OUT_OF_RANGE);
++        return 0;
++    }
++    if (BN_is_negative(bn)) {
++        ECerr(EC_F_BN_TO_FELEM, EC_R_BIGNUM_OUT_OF_RANGE);
++        return 0;
++    }
++    num_bytes = BN_bn2bin(bn, b_in);
++    flip_endian(b_out, b_in, num_bytes);
++    bin28_to_felem(out, b_out);
++    return 1;
++}
++
++/* From internal representation to OpenSSL BIGNUM */
++static BIGNUM *felem_to_BN(BIGNUM *out, const felem in)
++{
++    felem_bytearray b_in, b_out;
++    felem_to_bin28(b_in, in);
++    flip_endian(b_out, b_in, sizeof b_out);
++    return BN_bin2bn(b_out, sizeof b_out, out);
++}
++
++/******************************************************************************/
++/*-
++ *                              FIELD OPERATIONS
++ *
++ * Field operations, using the internal representation of field elements.
++ * NB! These operations are specific to our point multiplication and cannot be
++ * expected to be correct in general - e.g., multiplication with a large scalar
++ * will cause an overflow.
++ *
++ */
++
++static void felem_one(felem out)
++{
++    out[0] = 1;
++    out[1] = 0;
++    out[2] = 0;
++    out[3] = 0;
++}
++
++static void felem_assign(felem out, const felem in)
++{
++    out[0] = in[0];
++    out[1] = in[1];
++    out[2] = in[2];
++    out[3] = in[3];
++}
++
++/* Sum two field elements: out += in */
++static void felem_sum(felem out, const felem in)
++{
++    out[0] += in[0];
++    out[1] += in[1];
++    out[2] += in[2];
++    out[3] += in[3];
++}
++
++/* Get negative value: out = -in */
++/* Assumes in[i] < 2^57 */
++static void felem_neg(felem out, const felem in)
++{
++    static const limb two58p2 = (((limb) 1) << 58) + (((limb) 1) << 2);
++    static const limb two58m2 = (((limb) 1) << 58) - (((limb) 1) << 2);
++    static const limb two58m42m2 = (((limb) 1) << 58) -
++        (((limb) 1) << 42) - (((limb) 1) << 2);
++
++    /* Set to 0 mod 2^224-2^96+1 to ensure out > in */
++    out[0] = two58p2 - in[0];
++    out[1] = two58m42m2 - in[1];
++    out[2] = two58m2 - in[2];
++    out[3] = two58m2 - in[3];
++}
++
++/* Subtract field elements: out -= in */
++/* Assumes in[i] < 2^57 */
++static void felem_diff(felem out, const felem in)
++{
++    static const limb two58p2 = (((limb) 1) << 58) + (((limb) 1) << 2);
++    static const limb two58m2 = (((limb) 1) << 58) - (((limb) 1) << 2);
++    static const limb two58m42m2 = (((limb) 1) << 58) -
++        (((limb) 1) << 42) - (((limb) 1) << 2);
++
++    /* Add 0 mod 2^224-2^96+1 to ensure out > in */
++    out[0] += two58p2;
++    out[1] += two58m42m2;
++    out[2] += two58m2;
++    out[3] += two58m2;
++
++    out[0] -= in[0];
++    out[1] -= in[1];
++    out[2] -= in[2];
++    out[3] -= in[3];
++}
++
++/* Subtract in unreduced 128-bit mode: out -= in */
++/* Assumes in[i] < 2^119 */
++static void widefelem_diff(widefelem out, const widefelem in)
++{
++    static const widelimb two120 = ((widelimb) 1) << 120;
++    static const widelimb two120m64 = (((widelimb) 1) << 120) -
++        (((widelimb) 1) << 64);
++    static const widelimb two120m104m64 = (((widelimb) 1) << 120) -
++        (((widelimb) 1) << 104) - (((widelimb) 1) << 64);
++
++    /* Add 0 mod 2^224-2^96+1 to ensure out > in */
++    out[0] += two120;
++    out[1] += two120m64;
++    out[2] += two120m64;
++    out[3] += two120;
++    out[4] += two120m104m64;
++    out[5] += two120m64;
++    out[6] += two120m64;
++
++    out[0] -= in[0];
++    out[1] -= in[1];
++    out[2] -= in[2];
++    out[3] -= in[3];
++    out[4] -= in[4];
++    out[5] -= in[5];
++    out[6] -= in[6];
++}
++
++/* Subtract in mixed mode: out128 -= in64 */
++/* in[i] < 2^63 */
++static void felem_diff_128_64(widefelem out, const felem in)
++{
++    static const widelimb two64p8 = (((widelimb) 1) << 64) +
++        (((widelimb) 1) << 8);
++    static const widelimb two64m8 = (((widelimb) 1) << 64) -
++        (((widelimb) 1) << 8);
++    static const widelimb two64m48m8 = (((widelimb) 1) << 64) -
++        (((widelimb) 1) << 48) - (((widelimb) 1) << 8);
++
++    /* Add 0 mod 2^224-2^96+1 to ensure out > in */
++    out[0] += two64p8;
++    out[1] += two64m48m8;
++    out[2] += two64m8;
++    out[3] += two64m8;
++
++    out[0] -= in[0];
++    out[1] -= in[1];
++    out[2] -= in[2];
++    out[3] -= in[3];
++}
++
++/*
++ * Multiply a field element by a scalar: out = out * scalar The scalars we
++ * actually use are small, so results fit without overflow
++ */
++static void felem_scalar(felem out, const limb scalar)
++{
++    out[0] *= scalar;
++    out[1] *= scalar;
++    out[2] *= scalar;
++    out[3] *= scalar;
++}
++
++/*
++ * Multiply an unreduced field element by a scalar: out = out * scalar The
++ * scalars we actually use are small, so results fit without overflow
++ */
++static void widefelem_scalar(widefelem out, const widelimb scalar)
++{
++    out[0] *= scalar;
++    out[1] *= scalar;
++    out[2] *= scalar;
++    out[3] *= scalar;
++    out[4] *= scalar;
++    out[5] *= scalar;
++    out[6] *= scalar;
++}
++
++/* Square a field element: out = in^2 */
++static void felem_square(widefelem out, const felem in)
++{
++    limb tmp0, tmp1, tmp2;
++    tmp0 = 2 * in[0];
++    tmp1 = 2 * in[1];
++    tmp2 = 2 * in[2];
++    out[0] = ((widelimb) in[0]) * in[0];
++    out[1] = ((widelimb) in[0]) * tmp1;
++    out[2] = ((widelimb) in[0]) * tmp2 + ((widelimb) in[1]) * in[1];
++    out[3] = ((widelimb) in[3]) * tmp0 + ((widelimb) in[1]) * tmp2;
++    out[4] = ((widelimb) in[3]) * tmp1 + ((widelimb) in[2]) * in[2];
++    out[5] = ((widelimb) in[3]) * tmp2;
++    out[6] = ((widelimb) in[3]) * in[3];
++}
++
++/* Multiply two field elements: out = in1 * in2 */
++static void felem_mul(widefelem out, const felem in1, const felem in2)
++{
++    out[0] = ((widelimb) in1[0]) * in2[0];
++    out[1] = ((widelimb) in1[0]) * in2[1] + ((widelimb) in1[1]) * in2[0];
++    out[2] = ((widelimb) in1[0]) * in2[2] + ((widelimb) in1[1]) * in2[1] +
++             ((widelimb) in1[2]) * in2[0];
++    out[3] = ((widelimb) in1[0]) * in2[3] + ((widelimb) in1[1]) * in2[2] +
++             ((widelimb) in1[2]) * in2[1] + ((widelimb) in1[3]) * in2[0];
++    out[4] = ((widelimb) in1[1]) * in2[3] + ((widelimb) in1[2]) * in2[2] +
++             ((widelimb) in1[3]) * in2[1];
++    out[5] = ((widelimb) in1[2]) * in2[3] + ((widelimb) in1[3]) * in2[2];
++    out[6] = ((widelimb) in1[3]) * in2[3];
++}
++
++/*-
++ * Reduce seven 128-bit coefficients to four 64-bit coefficients.
++ * Requires in[i] < 2^126,
++ * ensures out[0] < 2^56, out[1] < 2^56, out[2] < 2^56, out[3] <= 2^56 + 2^16 */
++static void felem_reduce(felem out, const widefelem in)
++{
++    static const widelimb two127p15 = (((widelimb) 1) << 127) +
++        (((widelimb) 1) << 15);
++    static const widelimb two127m71 = (((widelimb) 1) << 127) -
++        (((widelimb) 1) << 71);
++    static const widelimb two127m71m55 = (((widelimb) 1) << 127) -
++        (((widelimb) 1) << 71) - (((widelimb) 1) << 55);
++    widelimb output[5];
++
++    /* Add 0 mod 2^224-2^96+1 to ensure all differences are positive */
++    output[0] = in[0] + two127p15;
++    output[1] = in[1] + two127m71m55;
++    output[2] = in[2] + two127m71;
++    output[3] = in[3];
++    output[4] = in[4];
++
++    /* Eliminate in[4], in[5], in[6] */
++    output[4] += in[6] >> 16;
++    output[3] += (in[6] & 0xffff) << 40;
++    output[2] -= in[6];
++
++    output[3] += in[5] >> 16;
++    output[2] += (in[5] & 0xffff) << 40;
++    output[1] -= in[5];
++
++    output[2] += output[4] >> 16;
++    output[1] += (output[4] & 0xffff) << 40;
++    output[0] -= output[4];
++
++    /* Carry 2 -> 3 -> 4 */
++    output[3] += output[2] >> 56;
++    output[2] &= 0x00ffffffffffffff;
++
++    output[4] = output[3] >> 56;
++    output[3] &= 0x00ffffffffffffff;
++
++    /* Now output[2] < 2^56, output[3] < 2^56, output[4] < 2^72 */
++
++    /* Eliminate output[4] */
++    output[2] += output[4] >> 16;
++    /* output[2] < 2^56 + 2^56 = 2^57 */
++    output[1] += (output[4] & 0xffff) << 40;
++    output[0] -= output[4];
++
++    /* Carry 0 -> 1 -> 2 -> 3 */
++    output[1] += output[0] >> 56;
++    out[0] = output[0] & 0x00ffffffffffffff;
++
++    output[2] += output[1] >> 56;
++    /* output[2] < 2^57 + 2^72 */
++    out[1] = output[1] & 0x00ffffffffffffff;
++    output[3] += output[2] >> 56;
++    /* output[3] <= 2^56 + 2^16 */
++    out[2] = output[2] & 0x00ffffffffffffff;
++
++    /*-
++     * out[0] < 2^56, out[1] < 2^56, out[2] < 2^56,
++     * out[3] <= 2^56 + 2^16 (due to final carry),
++     * so out < 2*p
++     */
++    out[3] = output[3];
++}
++
++static void felem_square_reduce(felem out, const felem in)
++{
++    widefelem tmp;
++    felem_square(tmp, in);
++    felem_reduce(out, tmp);
++}
++
++static void felem_mul_reduce(felem out, const felem in1, const felem in2)
++{
++    widefelem tmp;
++    felem_mul(tmp, in1, in2);
++    felem_reduce(out, tmp);
++}
++
++/*
++ * Reduce to unique minimal representation. Requires 0 <= in < 2*p (always
++ * call felem_reduce first)
++ */
++static void felem_contract(felem out, const felem in)
++{
++    static const int64_t two56 = ((limb) 1) << 56;
++    /* 0 <= in < 2*p, p = 2^224 - 2^96 + 1 */
++    /* if in > p , reduce in = in - 2^224 + 2^96 - 1 */
++    int64_t tmp[4], a;
++    tmp[0] = in[0];
++    tmp[1] = in[1];
++    tmp[2] = in[2];
++    tmp[3] = in[3];
++    /* Case 1: a = 1 iff in >= 2^224 */
++    a = (in[3] >> 56);
++    tmp[0] -= a;
++    tmp[1] += a << 40;
++    tmp[3] &= 0x00ffffffffffffff;
++    /*
++     * Case 2: a = 0 iff p <= in < 2^224, i.e., the high 128 bits are all 1
++     * and the lower part is non-zero
++     */
++    a = ((in[3] & in[2] & (in[1] | 0x000000ffffffffff)) + 1) |
++        (((int64_t) (in[0] + (in[1] & 0x000000ffffffffff)) - 1) >> 63);
++    a &= 0x00ffffffffffffff;
++    /* turn a into an all-one mask (if a = 0) or an all-zero mask */
++    a = (a - 1) >> 63;
++    /* subtract 2^224 - 2^96 + 1 if a is all-one */
++    tmp[3] &= a ^ 0xffffffffffffffff;
++    tmp[2] &= a ^ 0xffffffffffffffff;
++    tmp[1] &= (a ^ 0xffffffffffffffff) | 0x000000ffffffffff;
++    tmp[0] -= 1 & a;
++
++    /*
++     * eliminate negative coefficients: if tmp[0] is negative, tmp[1] must be
++     * non-zero, so we only need one step
++     */
++    a = tmp[0] >> 63;
++    tmp[0] += two56 & a;
++    tmp[1] -= 1 & a;
++
++    /* carry 1 -> 2 -> 3 */
++    tmp[2] += tmp[1] >> 56;
++    tmp[1] &= 0x00ffffffffffffff;
++
++    tmp[3] += tmp[2] >> 56;
++    tmp[2] &= 0x00ffffffffffffff;
++
++    /* Now 0 <= out < p */
++    out[0] = tmp[0];
++    out[1] = tmp[1];
++    out[2] = tmp[2];
++    out[3] = tmp[3];
++}
++
++/*
++ * Zero-check: returns 1 if input is 0, and 0 otherwise. We know that field
++ * elements are reduced to in < 2^225, so we only need to check three cases:
++ * 0, 2^224 - 2^96 + 1, and 2^225 - 2^97 + 2
++ */
++static limb felem_is_zero(const felem in)
++{
++    limb zero, two224m96p1, two225m97p2;
++
++    zero = in[0] | in[1] | in[2] | in[3];
++    zero = (((int64_t) (zero) - 1) >> 63) & 1;
++    two224m96p1 = (in[0] ^ 1) | (in[1] ^ 0x00ffff0000000000)
++        | (in[2] ^ 0x00ffffffffffffff) | (in[3] ^ 0x00ffffffffffffff);
++    two224m96p1 = (((int64_t) (two224m96p1) - 1) >> 63) & 1;
++    two225m97p2 = (in[0] ^ 2) | (in[1] ^ 0x00fffe0000000000)
++        | (in[2] ^ 0x00ffffffffffffff) | (in[3] ^ 0x01ffffffffffffff);
++    two225m97p2 = (((int64_t) (two225m97p2) - 1) >> 63) & 1;
++    return (zero | two224m96p1 | two225m97p2);
++}
++
++static limb felem_is_zero_int(const felem in)
++{
++    return (int)(felem_is_zero(in) & ((limb) 1));
++}
++
++/* Invert a field element */
++/* Computation chain copied from djb's code */
++static void felem_inv(felem out, const felem in)
++{
++    felem ftmp, ftmp2, ftmp3, ftmp4;
++    widefelem tmp;
++    unsigned i;
++
++    felem_square(tmp, in);
++    felem_reduce(ftmp, tmp);    /* 2 */
++    felem_mul(tmp, in, ftmp);
++    felem_reduce(ftmp, tmp);    /* 2^2 - 1 */
++    felem_square(tmp, ftmp);
++    felem_reduce(ftmp, tmp);    /* 2^3 - 2 */
++    felem_mul(tmp, in, ftmp);
++    felem_reduce(ftmp, tmp);    /* 2^3 - 1 */
++    felem_square(tmp, ftmp);
++    felem_reduce(ftmp2, tmp);   /* 2^4 - 2 */
++    felem_square(tmp, ftmp2);
++    felem_reduce(ftmp2, tmp);   /* 2^5 - 4 */
++    felem_square(tmp, ftmp2);
++    felem_reduce(ftmp2, tmp);   /* 2^6 - 8 */
++    felem_mul(tmp, ftmp2, ftmp);
++    felem_reduce(ftmp, tmp);    /* 2^6 - 1 */
++    felem_square(tmp, ftmp);
++    felem_reduce(ftmp2, tmp);   /* 2^7 - 2 */
++    for (i = 0; i < 5; ++i) {   /* 2^12 - 2^6 */
++        felem_square(tmp, ftmp2);
++        felem_reduce(ftmp2, tmp);
++    }
++    felem_mul(tmp, ftmp2, ftmp);
++    felem_reduce(ftmp2, tmp);   /* 2^12 - 1 */
++    felem_square(tmp, ftmp2);
++    felem_reduce(ftmp3, tmp);   /* 2^13 - 2 */
++    for (i = 0; i < 11; ++i) {  /* 2^24 - 2^12 */
++        felem_square(tmp, ftmp3);
++        felem_reduce(ftmp3, tmp);
++    }
++    felem_mul(tmp, ftmp3, ftmp2);
++    felem_reduce(ftmp2, tmp);   /* 2^24 - 1 */
++    felem_square(tmp, ftmp2);
++    felem_reduce(ftmp3, tmp);   /* 2^25 - 2 */
++    for (i = 0; i < 23; ++i) {  /* 2^48 - 2^24 */
++        felem_square(tmp, ftmp3);
++        felem_reduce(ftmp3, tmp);
++    }
++    felem_mul(tmp, ftmp3, ftmp2);
++    felem_reduce(ftmp3, tmp);   /* 2^48 - 1 */
++    felem_square(tmp, ftmp3);
++    felem_reduce(ftmp4, tmp);   /* 2^49 - 2 */
++    for (i = 0; i < 47; ++i) {  /* 2^96 - 2^48 */
++        felem_square(tmp, ftmp4);
++        felem_reduce(ftmp4, tmp);
++    }
++    felem_mul(tmp, ftmp3, ftmp4);
++    felem_reduce(ftmp3, tmp);   /* 2^96 - 1 */
++    felem_square(tmp, ftmp3);
++    felem_reduce(ftmp4, tmp);   /* 2^97 - 2 */
++    for (i = 0; i < 23; ++i) {  /* 2^120 - 2^24 */
++        felem_square(tmp, ftmp4);
++        felem_reduce(ftmp4, tmp);
++    }
++    felem_mul(tmp, ftmp2, ftmp4);
++    felem_reduce(ftmp2, tmp);   /* 2^120 - 1 */
++    for (i = 0; i < 6; ++i) {   /* 2^126 - 2^6 */
++        felem_square(tmp, ftmp2);
++        felem_reduce(ftmp2, tmp);
++    }
++    felem_mul(tmp, ftmp2, ftmp);
++    felem_reduce(ftmp, tmp);    /* 2^126 - 1 */
++    felem_square(tmp, ftmp);
++    felem_reduce(ftmp, tmp);    /* 2^127 - 2 */
++    felem_mul(tmp, ftmp, in);
++    felem_reduce(ftmp, tmp);    /* 2^127 - 1 */
++    for (i = 0; i < 97; ++i) {  /* 2^224 - 2^97 */
++        felem_square(tmp, ftmp);
++        felem_reduce(ftmp, tmp);
++    }
++    felem_mul(tmp, ftmp, ftmp3);
++    felem_reduce(out, tmp);     /* 2^224 - 2^96 - 1 */
++}
++
++/*
++ * Copy in constant time: if icopy == 1, copy in to out, if icopy == 0, copy
++ * out to itself.
++ */
++static void copy_conditional(felem out, const felem in, limb icopy)
++{
++    unsigned i;
++    /*
++     * icopy is a (64-bit) 0 or 1, so copy is either all-zero or all-one
++     */
++    const limb copy = -icopy;
++    for (i = 0; i < 4; ++i) {
++        const limb tmp = copy & (in[i] ^ out[i]);
++        out[i] ^= tmp;
++    }
++}
++
++/******************************************************************************/
++/*-
++ *                       ELLIPTIC CURVE POINT OPERATIONS
++ *
++ * Points are represented in Jacobian projective coordinates:
++ * (X, Y, Z) corresponds to the affine point (X/Z^2, Y/Z^3),
++ * or to the point at infinity if Z == 0.
++ *
++ */
++
++/*-
++ * Double an elliptic curve point:
++ * (X', Y', Z') = 2 * (X, Y, Z), where
++ * X' = (3 * (X - Z^2) * (X + Z^2))^2 - 8 * X * Y^2
++ * Y' = 3 * (X - Z^2) * (X + Z^2) * (4 * X * Y^2 - X') - 8 * Y^2
++ * Z' = (Y + Z)^2 - Y^2 - Z^2 = 2 * Y * Z
++ * Outputs can equal corresponding inputs, i.e., x_out == x_in is allowed,
++ * while x_out == y_in is not (maybe this works, but it's not tested).
++ */
++static void
++point_double(felem x_out, felem y_out, felem z_out,
++             const felem x_in, const felem y_in, const felem z_in)
++{
++    widefelem tmp, tmp2;
++    felem delta, gamma, beta, alpha, ftmp, ftmp2;
++
++    felem_assign(ftmp, x_in);
++    felem_assign(ftmp2, x_in);
++
++    /* delta = z^2 */
++    felem_square(tmp, z_in);
++    felem_reduce(delta, tmp);
++
++    /* gamma = y^2 */
++    felem_square(tmp, y_in);
++    felem_reduce(gamma, tmp);
++
++    /* beta = x*gamma */
++    felem_mul(tmp, x_in, gamma);
++    felem_reduce(beta, tmp);
++
++    /* alpha = 3*(x-delta)*(x+delta) */
++    felem_diff(ftmp, delta);
++    /* ftmp[i] < 2^57 + 2^58 + 2 < 2^59 */
++    felem_sum(ftmp2, delta);
++    /* ftmp2[i] < 2^57 + 2^57 = 2^58 */
++    felem_scalar(ftmp2, 3);
++    /* ftmp2[i] < 3 * 2^58 < 2^60 */
++    felem_mul(tmp, ftmp, ftmp2);
++    /* tmp[i] < 2^60 * 2^59 * 4 = 2^121 */
++    felem_reduce(alpha, tmp);
++
++    /* x' = alpha^2 - 8*beta */
++    felem_square(tmp, alpha);
++    /* tmp[i] < 4 * 2^57 * 2^57 = 2^116 */
++    felem_assign(ftmp, beta);
++    felem_scalar(ftmp, 8);
++    /* ftmp[i] < 8 * 2^57 = 2^60 */
++    felem_diff_128_64(tmp, ftmp);
++    /* tmp[i] < 2^116 + 2^64 + 8 < 2^117 */
++    felem_reduce(x_out, tmp);
++
++    /* z' = (y + z)^2 - gamma - delta */
++    felem_sum(delta, gamma);
++    /* delta[i] < 2^57 + 2^57 = 2^58 */
++    felem_assign(ftmp, y_in);
++    felem_sum(ftmp, z_in);
++    /* ftmp[i] < 2^57 + 2^57 = 2^58 */
++    felem_square(tmp, ftmp);
++    /* tmp[i] < 4 * 2^58 * 2^58 = 2^118 */
++    felem_diff_128_64(tmp, delta);
++    /* tmp[i] < 2^118 + 2^64 + 8 < 2^119 */
++    felem_reduce(z_out, tmp);
++
++    /* y' = alpha*(4*beta - x') - 8*gamma^2 */
++    felem_scalar(beta, 4);
++    /* beta[i] < 4 * 2^57 = 2^59 */
++    felem_diff(beta, x_out);
++    /* beta[i] < 2^59 + 2^58 + 2 < 2^60 */
++    felem_mul(tmp, alpha, beta);
++    /* tmp[i] < 4 * 2^57 * 2^60 = 2^119 */
++    felem_square(tmp2, gamma);
++    /* tmp2[i] < 4 * 2^57 * 2^57 = 2^116 */
++    widefelem_scalar(tmp2, 8);
++    /* tmp2[i] < 8 * 2^116 = 2^119 */
++    widefelem_diff(tmp, tmp2);
++    /* tmp[i] < 2^119 + 2^120 < 2^121 */
++    felem_reduce(y_out, tmp);
++}
++
++/*-
++ * Add two elliptic curve points:
++ * (X_1, Y_1, Z_1) + (X_2, Y_2, Z_2) = (X_3, Y_3, Z_3), where
++ * X_3 = (Z_1^3 * Y_2 - Z_2^3 * Y_1)^2 - (Z_1^2 * X_2 - Z_2^2 * X_1)^3 -
++ * 2 * Z_2^2 * X_1 * (Z_1^2 * X_2 - Z_2^2 * X_1)^2
++ * Y_3 = (Z_1^3 * Y_2 - Z_2^3 * Y_1) * (Z_2^2 * X_1 * (Z_1^2 * X_2 - Z_2^2 * X_1)^2 - X_3) -
++ *        Z_2^3 * Y_1 * (Z_1^2 * X_2 - Z_2^2 * X_1)^3
++ * Z_3 = (Z_1^2 * X_2 - Z_2^2 * X_1) * (Z_1 * Z_2)
++ *
++ * This runs faster if 'mixed' is set, which requires Z_2 = 1 or Z_2 = 0.
++ */
++
++/*
++ * This function is not entirely constant-time: it includes a branch for
++ * checking whether the two input points are equal, (while not equal to the
++ * point at infinity). This case never happens during single point
++ * multiplication, so there is no timing leak for ECDH or ECDSA signing.
++ */
++static void point_add(felem x3, felem y3, felem z3,
++                      const felem x1, const felem y1, const felem z1,
++                      const int mixed, const felem x2, const felem y2,
++                      const felem z2)
++{
++    felem ftmp, ftmp2, ftmp3, ftmp4, ftmp5, x_out, y_out, z_out;
++    widefelem tmp, tmp2;
++    limb z1_is_zero, z2_is_zero, x_equal, y_equal;
++
++    if (!mixed) {
++        /* ftmp2 = z2^2 */
++        felem_square(tmp, z2);
++        felem_reduce(ftmp2, tmp);
++
++        /* ftmp4 = z2^3 */
++        felem_mul(tmp, ftmp2, z2);
++        felem_reduce(ftmp4, tmp);
++
++        /* ftmp4 = z2^3*y1 */
++        felem_mul(tmp2, ftmp4, y1);
++        felem_reduce(ftmp4, tmp2);
++
++        /* ftmp2 = z2^2*x1 */
++        felem_mul(tmp2, ftmp2, x1);
++        felem_reduce(ftmp2, tmp2);
++    } else {
++        /*
++         * We'll assume z2 = 1 (special case z2 = 0 is handled later)
++         */
++
++        /* ftmp4 = z2^3*y1 */
++        felem_assign(ftmp4, y1);
++
++        /* ftmp2 = z2^2*x1 */
++        felem_assign(ftmp2, x1);
++    }
++
++    /* ftmp = z1^2 */
++    felem_square(tmp, z1);
++    felem_reduce(ftmp, tmp);
++
++    /* ftmp3 = z1^3 */
++    felem_mul(tmp, ftmp, z1);
++    felem_reduce(ftmp3, tmp);
++
++    /* tmp = z1^3*y2 */
++    felem_mul(tmp, ftmp3, y2);
++    /* tmp[i] < 4 * 2^57 * 2^57 = 2^116 */
++
++    /* ftmp3 = z1^3*y2 - z2^3*y1 */
++    felem_diff_128_64(tmp, ftmp4);
++    /* tmp[i] < 2^116 + 2^64 + 8 < 2^117 */
++    felem_reduce(ftmp3, tmp);
++
++    /* tmp = z1^2*x2 */
++    felem_mul(tmp, ftmp, x2);
++    /* tmp[i] < 4 * 2^57 * 2^57 = 2^116 */
++
++    /* ftmp = z1^2*x2 - z2^2*x1 */
++    felem_diff_128_64(tmp, ftmp2);
++    /* tmp[i] < 2^116 + 2^64 + 8 < 2^117 */
++    felem_reduce(ftmp, tmp);
++
++    /*
++     * the formulae are incorrect if the points are equal so we check for
++     * this and do doubling if this happens
++     */
++    x_equal = felem_is_zero(ftmp);
++    y_equal = felem_is_zero(ftmp3);
++    z1_is_zero = felem_is_zero(z1);
++    z2_is_zero = felem_is_zero(z2);
++    /* In affine coordinates, (X_1, Y_1) == (X_2, Y_2) */
++    if (x_equal && y_equal && !z1_is_zero && !z2_is_zero) {
++        point_double(x3, y3, z3, x1, y1, z1);
++        return;
++    }
++
++    /* ftmp5 = z1*z2 */
++    if (!mixed) {
++        felem_mul(tmp, z1, z2);
++        felem_reduce(ftmp5, tmp);
++    } else {
++        /* special case z2 = 0 is handled later */
++        felem_assign(ftmp5, z1);
++    }
++
++    /* z_out = (z1^2*x2 - z2^2*x1)*(z1*z2) */
++    felem_mul(tmp, ftmp, ftmp5);
++    felem_reduce(z_out, tmp);
++
++    /* ftmp = (z1^2*x2 - z2^2*x1)^2 */
++    felem_assign(ftmp5, ftmp);
++    felem_square(tmp, ftmp);
++    felem_reduce(ftmp, tmp);
++
++    /* ftmp5 = (z1^2*x2 - z2^2*x1)^3 */
++    felem_mul(tmp, ftmp, ftmp5);
++    felem_reduce(ftmp5, tmp);
++
++    /* ftmp2 = z2^2*x1*(z1^2*x2 - z2^2*x1)^2 */
++    felem_mul(tmp, ftmp2, ftmp);
++    felem_reduce(ftmp2, tmp);
++
++    /* tmp = z2^3*y1*(z1^2*x2 - z2^2*x1)^3 */
++    felem_mul(tmp, ftmp4, ftmp5);
++    /* tmp[i] < 4 * 2^57 * 2^57 = 2^116 */
++
++    /* tmp2 = (z1^3*y2 - z2^3*y1)^2 */
++    felem_square(tmp2, ftmp3);
++    /* tmp2[i] < 4 * 2^57 * 2^57 < 2^116 */
++
++    /* tmp2 = (z1^3*y2 - z2^3*y1)^2 - (z1^2*x2 - z2^2*x1)^3 */
++    felem_diff_128_64(tmp2, ftmp5);
++    /* tmp2[i] < 2^116 + 2^64 + 8 < 2^117 */
++
++    /* ftmp5 = 2*z2^2*x1*(z1^2*x2 - z2^2*x1)^2 */
++    felem_assign(ftmp5, ftmp2);
++    felem_scalar(ftmp5, 2);
++    /* ftmp5[i] < 2 * 2^57 = 2^58 */
++
++    /*-
++     * x_out = (z1^3*y2 - z2^3*y1)^2 - (z1^2*x2 - z2^2*x1)^3 -
++     *  2*z2^2*x1*(z1^2*x2 - z2^2*x1)^2
++     */
++    felem_diff_128_64(tmp2, ftmp5);
++    /* tmp2[i] < 2^117 + 2^64 + 8 < 2^118 */
++    felem_reduce(x_out, tmp2);
++
++    /* ftmp2 = z2^2*x1*(z1^2*x2 - z2^2*x1)^2 - x_out */
++    felem_diff(ftmp2, x_out);
++    /* ftmp2[i] < 2^57 + 2^58 + 2 < 2^59 */
++
++    /*
++     * tmp2 = (z1^3*y2 - z2^3*y1)*(z2^2*x1*(z1^2*x2 - z2^2*x1)^2 - x_out)
++     */
++    felem_mul(tmp2, ftmp3, ftmp2);
++    /* tmp2[i] < 4 * 2^57 * 2^59 = 2^118 */
++
++    /*-
++     * y_out = (z1^3*y2 - z2^3*y1)*(z2^2*x1*(z1^2*x2 - z2^2*x1)^2 - x_out) -
++     *  z2^3*y1*(z1^2*x2 - z2^2*x1)^3
++     */
++    widefelem_diff(tmp2, tmp);
++    /* tmp2[i] < 2^118 + 2^120 < 2^121 */
++    felem_reduce(y_out, tmp2);
++
++    /*
++     * the result (x_out, y_out, z_out) is incorrect if one of the inputs is
++     * the point at infinity, so we need to check for this separately
++     */
++
++    /*
++     * if point 1 is at infinity, copy point 2 to output, and vice versa
++     */
++    copy_conditional(x_out, x2, z1_is_zero);
++    copy_conditional(x_out, x1, z2_is_zero);
++    copy_conditional(y_out, y2, z1_is_zero);
++    copy_conditional(y_out, y1, z2_is_zero);
++    copy_conditional(z_out, z2, z1_is_zero);
++    copy_conditional(z_out, z1, z2_is_zero);
++    felem_assign(x3, x_out);
++    felem_assign(y3, y_out);
++    felem_assign(z3, z_out);
++}
++
++/*
++ * select_point selects the |idx|th point from a precomputation table and
++ * copies it to out.
++ * The pre_comp array argument should be size of |size| argument
++ */
++static void select_point(const u64 idx, unsigned int size,
++                         const felem pre_comp[][3], felem out[3])
++{
++    unsigned i, j;
++    limb *outlimbs = &out[0][0];
++
++    memset(out, 0, sizeof(*out) * 3);
++    for (i = 0; i < size; i++) {
++        const limb *inlimbs = &pre_comp[i][0][0];
++        u64 mask = i ^ idx;
++        mask |= mask >> 4;
++        mask |= mask >> 2;
++        mask |= mask >> 1;
++        mask &= 1;
++        mask--;
++        for (j = 0; j < 4 * 3; j++)
++            outlimbs[j] |= inlimbs[j] & mask;
++    }
++}
++
++/* get_bit returns the |i|th bit in |in| */
++static char get_bit(const felem_bytearray in, unsigned i)
++{
++    if (i >= 224)
++        return 0;
++    return (in[i >> 3] >> (i & 7)) & 1;
++}
++
++/*
++ * Interleaved point multiplication using precomputed point multiples: The
++ * small point multiples 0*P, 1*P, ..., 16*P are in pre_comp[], the scalars
++ * in scalars[]. If g_scalar is non-NULL, we also add this multiple of the
++ * generator, using certain (large) precomputed multiples in g_pre_comp.
++ * Output point (X, Y, Z) is stored in x_out, y_out, z_out
++ */
++static void batch_mul(felem x_out, felem y_out, felem z_out,
++                      const felem_bytearray scalars[],
++                      const unsigned num_points, const u8 *g_scalar,
++                      const int mixed, const felem pre_comp[][17][3],
++                      const felem g_pre_comp[2][16][3])
++{
++    int i, skip;
++    unsigned num;
++    unsigned gen_mul = (g_scalar != NULL);
++    felem nq[3], tmp[4];
++    u64 bits;
++    u8 sign, digit;
++
++    /* set nq to the point at infinity */
++    memset(nq, 0, sizeof(nq));
++
++    /*
++     * Loop over all scalars msb-to-lsb, interleaving additions of multiples
++     * of the generator (two in each of the last 28 rounds) and additions of
++     * other points multiples (every 5th round).
++     */
++    skip = 1;                   /* save two point operations in the first
++                                 * round */
++    for (i = (num_points ? 220 : 27); i >= 0; --i) {
++        /* double */
++        if (!skip)
++            point_double(nq[0], nq[1], nq[2], nq[0], nq[1], nq[2]);
++
++        /* add multiples of the generator */
++        if (gen_mul && (i <= 27)) {
++            /* first, look 28 bits upwards */
++            bits = get_bit(g_scalar, i + 196) << 3;
++            bits |= get_bit(g_scalar, i + 140) << 2;
++            bits |= get_bit(g_scalar, i + 84) << 1;
++            bits |= get_bit(g_scalar, i + 28);
++            /* select the point to add, in constant time */
++            select_point(bits, 16, g_pre_comp[1], tmp);
++
++            if (!skip) {
++                /* value 1 below is argument for "mixed" */
++                point_add(nq[0], nq[1], nq[2],
++                          nq[0], nq[1], nq[2], 1, tmp[0], tmp[1], tmp[2]);
++            } else {
++                memcpy(nq, tmp, 3 * sizeof(felem));
++                skip = 0;
++            }
++
++            /* second, look at the current position */
++            bits = get_bit(g_scalar, i + 168) << 3;
++            bits |= get_bit(g_scalar, i + 112) << 2;
++            bits |= get_bit(g_scalar, i + 56) << 1;
++            bits |= get_bit(g_scalar, i);
++            /* select the point to add, in constant time */
++            select_point(bits, 16, g_pre_comp[0], tmp);
++            point_add(nq[0], nq[1], nq[2],
++                      nq[0], nq[1], nq[2],
++                      1 /* mixed */ , tmp[0], tmp[1], tmp[2]);
++        }
++
++        /* do other additions every 5 doublings */
++        if (num_points && (i % 5 == 0)) {
++            /* loop over all scalars */
++            for (num = 0; num < num_points; ++num) {
++                bits = get_bit(scalars[num], i + 4) << 5;
++                bits |= get_bit(scalars[num], i + 3) << 4;
++                bits |= get_bit(scalars[num], i + 2) << 3;
++                bits |= get_bit(scalars[num], i + 1) << 2;
++                bits |= get_bit(scalars[num], i) << 1;
++                bits |= get_bit(scalars[num], i - 1);
++                ec_GFp_nistp_recode_scalar_bits(&sign, &digit, bits);
++
++                /* select the point to add or subtract */
++                select_point(digit, 17, pre_comp[num], tmp);
++                felem_neg(tmp[3], tmp[1]); /* (X, -Y, Z) is the negative
++                                            * point */
++                copy_conditional(tmp[1], tmp[3], sign);
++
++                if (!skip) {
++                    point_add(nq[0], nq[1], nq[2],
++                              nq[0], nq[1], nq[2],
++                              mixed, tmp[0], tmp[1], tmp[2]);
++                } else {
++                    memcpy(nq, tmp, 3 * sizeof(felem));
++                    skip = 0;
++                }
++            }
++        }
++    }
++    felem_assign(x_out, nq[0]);
++    felem_assign(y_out, nq[1]);
++    felem_assign(z_out, nq[2]);
++}
++
++/******************************************************************************/
++/*
++ * FUNCTIONS TO MANAGE PRECOMPUTATION
++ */
++
++static NISTP224_PRE_COMP *nistp224_pre_comp_new()
++{
++    NISTP224_PRE_COMP *ret = OPENSSL_zalloc(sizeof(*ret));
++
++    if (!ret) {
++        ECerr(EC_F_NISTP224_PRE_COMP_NEW, ERR_R_MALLOC_FAILURE);
++        return ret;
++    }
++
++    ret->references = 1;
++
++    ret->lock = CRYPTO_THREAD_lock_new();
++    if (ret->lock == NULL) {
++        ECerr(EC_F_NISTP224_PRE_COMP_NEW, ERR_R_MALLOC_FAILURE);
++        OPENSSL_free(ret);
++        return NULL;
++    }
++    return ret;
++}
++
++NISTP224_PRE_COMP *EC_nistp224_pre_comp_dup(NISTP224_PRE_COMP *p)
++{
++    int i;
++    if (p != NULL)
++        CRYPTO_atomic_add(&p->references, 1, &i, p->lock);
++    return p;
++}
++
++void EC_nistp224_pre_comp_free(NISTP224_PRE_COMP *p)
++{
++    int i;
++
++    if (p == NULL)
++        return;
++
++    CRYPTO_atomic_add(&p->references, -1, &i, p->lock);
++    REF_PRINT_COUNT("EC_nistp224", x);
++    if (i > 0)
++        return;
++    REF_ASSERT_ISNT(i < 0);
++
++    CRYPTO_THREAD_lock_free(p->lock);
++    OPENSSL_free(p);
++}
++
++/******************************************************************************/
++/*
++ * OPENSSL EC_METHOD FUNCTIONS
++ */
++
++int ec_GFp_nistp224_group_init(EC_GROUP *group)
++{
++    int ret;
++    ret = ec_GFp_simple_group_init(group);
++    group->a_is_minus3 = 1;
++    return ret;
++}
++
++int ec_GFp_nistp224_group_set_curve(EC_GROUP *group, const BIGNUM *p,
++                                    const BIGNUM *a, const BIGNUM *b,
++                                    BN_CTX *ctx)
++{
++    int ret = 0;
++    BN_CTX *new_ctx = NULL;
++    BIGNUM *curve_p, *curve_a, *curve_b;
++
++    if (ctx == NULL)
++        if ((ctx = new_ctx = BN_CTX_new()) == NULL)
++            return 0;
++    BN_CTX_start(ctx);
++    if (((curve_p = BN_CTX_get(ctx)) == NULL) ||
++        ((curve_a = BN_CTX_get(ctx)) == NULL) ||
++        ((curve_b = BN_CTX_get(ctx)) == NULL))
++        goto err;
++    BN_bin2bn(nistp224_curve_params[0], sizeof(felem_bytearray), curve_p);
++    BN_bin2bn(nistp224_curve_params[1], sizeof(felem_bytearray), curve_a);
++    BN_bin2bn(nistp224_curve_params[2], sizeof(felem_bytearray), curve_b);
++    if ((BN_cmp(curve_p, p)) || (BN_cmp(curve_a, a)) || (BN_cmp(curve_b, b))) {
++        ECerr(EC_F_EC_GFP_NISTP224_GROUP_SET_CURVE,
++              EC_R_WRONG_CURVE_PARAMETERS);
++        goto err;
++    }
++    group->field_mod_func = BN_nist_mod_224;
++    ret = ec_GFp_simple_group_set_curve(group, p, a, b, ctx);
++ err:
++    BN_CTX_end(ctx);
++    BN_CTX_free(new_ctx);
++    return ret;
++}
++
++/*
++ * Takes the Jacobian coordinates (X, Y, Z) of a point and returns (X', Y') =
++ * (X/Z^2, Y/Z^3)
++ */
++int ec_GFp_nistp224_point_get_affine_coordinates(const EC_GROUP *group,
++                                                 const EC_POINT *point,
++                                                 BIGNUM *x, BIGNUM *y,
++                                                 BN_CTX *ctx)
++{
++    felem z1, z2, x_in, y_in, x_out, y_out;
++    widefelem tmp;
++
++    if (EC_POINT_is_at_infinity(group, point)) {
++        ECerr(EC_F_EC_GFP_NISTP224_POINT_GET_AFFINE_COORDINATES,
++              EC_R_POINT_AT_INFINITY);
++        return 0;
++    }
++    if ((!BN_to_felem(x_in, point->X)) || (!BN_to_felem(y_in, point->Y)) ||
++        (!BN_to_felem(z1, point->Z)))
++        return 0;
++    felem_inv(z2, z1);
++    felem_square(tmp, z2);
++    felem_reduce(z1, tmp);
++    felem_mul(tmp, x_in, z1);
++    felem_reduce(x_in, tmp);
++    felem_contract(x_out, x_in);
++    if (x != NULL) {
++        if (!felem_to_BN(x, x_out)) {
++            ECerr(EC_F_EC_GFP_NISTP224_POINT_GET_AFFINE_COORDINATES,
++                  ERR_R_BN_LIB);
++            return 0;
++        }
++    }
++    felem_mul(tmp, z1, z2);
++    felem_reduce(z1, tmp);
++    felem_mul(tmp, y_in, z1);
++    felem_reduce(y_in, tmp);
++    felem_contract(y_out, y_in);
++    if (y != NULL) {
++        if (!felem_to_BN(y, y_out)) {
++            ECerr(EC_F_EC_GFP_NISTP224_POINT_GET_AFFINE_COORDINATES,
++                  ERR_R_BN_LIB);
++            return 0;
++        }
++    }
++    return 1;
++}
++
++static void make_points_affine(size_t num, felem points[ /* num */ ][3],
++                               felem tmp_felems[ /* num+1 */ ])
++{
++    /*
++     * Runs in constant time, unless an input is the point at infinity (which
++     * normally shouldn't happen).
++     */
++    ec_GFp_nistp_points_make_affine_internal(num,
++                                             points,
++                                             sizeof(felem),
++                                             tmp_felems,
++                                             (void (*)(void *))felem_one,
++                                             (int (*)(const void *))
++                                             felem_is_zero_int,
++                                             (void (*)(void *, const void *))
++                                             felem_assign,
++                                             (void (*)(void *, const void *))
++                                             felem_square_reduce, (void (*)
++                                                                   (void *,
++                                                                    const void
++                                                                    *,
++                                                                    const void
++                                                                    *))
++                                             felem_mul_reduce,
++                                             (void (*)(void *, const void *))
++                                             felem_inv,
++                                             (void (*)(void *, const void *))
++                                             felem_contract);
++}
++
++/*
++ * Computes scalar*generator + \sum scalars[i]*points[i], ignoring NULL
++ * values Result is stored in r (r can equal one of the inputs).
++ */
++int ec_GFp_nistp224_points_mul(const EC_GROUP *group, EC_POINT *r,
++                               const BIGNUM *scalar, size_t num,
++                               const EC_POINT *points[],
++                               const BIGNUM *scalars[], BN_CTX *ctx)
++{
++    int ret = 0;
++    int j;
++    unsigned i;
++    int mixed = 0;
++    BN_CTX *new_ctx = NULL;
++    BIGNUM *x, *y, *z, *tmp_scalar;
++    felem_bytearray g_secret;
++    felem_bytearray *secrets = NULL;
++    felem (*pre_comp)[17][3] = NULL;
++    felem *tmp_felems = NULL;
++    felem_bytearray tmp;
++    unsigned num_bytes;
++    int have_pre_comp = 0;
++    size_t num_points = num;
++    felem x_in, y_in, z_in, x_out, y_out, z_out;
++    NISTP224_PRE_COMP *pre = NULL;
++    const felem(*g_pre_comp)[16][3] = NULL;
++    EC_POINT *generator = NULL;
++    const EC_POINT *p = NULL;
++    const BIGNUM *p_scalar = NULL;
++
++    if (ctx == NULL)
++        if ((ctx = new_ctx = BN_CTX_new()) == NULL)
++            return 0;
++    BN_CTX_start(ctx);
++    if (((x = BN_CTX_get(ctx)) == NULL) ||
++        ((y = BN_CTX_get(ctx)) == NULL) ||
++        ((z = BN_CTX_get(ctx)) == NULL) ||
++        ((tmp_scalar = BN_CTX_get(ctx)) == NULL))
++        goto err;
++
++    if (scalar != NULL) {
++        pre = group->pre_comp.nistp224;
++        if (pre)
++            /* we have precomputation, try to use it */
++            g_pre_comp = (const felem(*)[16][3])pre->g_pre_comp;
++        else
++            /* try to use the standard precomputation */
++            g_pre_comp = &gmul[0];
++        generator = EC_POINT_new(group);
++        if (generator == NULL)
++            goto err;
++        /* get the generator from precomputation */
++        if (!felem_to_BN(x, g_pre_comp[0][1][0]) ||
++            !felem_to_BN(y, g_pre_comp[0][1][1]) ||
++            !felem_to_BN(z, g_pre_comp[0][1][2])) {
++            ECerr(EC_F_EC_GFP_NISTP224_POINTS_MUL, ERR_R_BN_LIB);
++            goto err;
++        }
++        if (!EC_POINT_set_Jprojective_coordinates_GFp(group,
++                                                      generator, x, y, z,
++                                                      ctx))
++            goto err;
++        if (0 == EC_POINT_cmp(group, generator, group->generator, ctx))
++            /* precomputation matches generator */
++            have_pre_comp = 1;
++        else
++            /*
++             * we don't have valid precomputation: treat the generator as a
++             * random point
++             */
++            num_points = num_points + 1;
++    }
++
++    if (num_points > 0) {
++        if (num_points >= 3) {
++            /*
++             * unless we precompute multiples for just one or two points,
++             * converting those into affine form is time well spent
++             */
++            mixed = 1;
++        }
++        secrets = OPENSSL_zalloc(sizeof(*secrets) * num_points);
++        pre_comp = OPENSSL_zalloc(sizeof(*pre_comp) * num_points);
++        if (mixed)
++            tmp_felems =
++                OPENSSL_malloc(sizeof(felem) * (num_points * 17 + 1));
++        if ((secrets == NULL) || (pre_comp == NULL)
++            || (mixed && (tmp_felems == NULL))) {
++            ECerr(EC_F_EC_GFP_NISTP224_POINTS_MUL, ERR_R_MALLOC_FAILURE);
++            goto err;
++        }
++
++        /*
++         * we treat NULL scalars as 0, and NULL points as points at infinity,
++         * i.e., they contribute nothing to the linear combination
++         */
++        for (i = 0; i < num_points; ++i) {
++            if (i == num)
++                /* the generator */
++            {
++                p = EC_GROUP_get0_generator(group);
++                p_scalar = scalar;
++            } else
++                /* the i^th point */
++            {
++                p = points[i];
++                p_scalar = scalars[i];
++            }
++            if ((p_scalar != NULL) && (p != NULL)) {
++                /* reduce scalar to 0 <= scalar < 2^224 */
++                if ((BN_num_bits(p_scalar) > 224)
++                    || (BN_is_negative(p_scalar))) {
++                    /*
++                     * this is an unusual input, and we don't guarantee
++                     * constant-timeness
++                     */
++                    if (!BN_nnmod(tmp_scalar, p_scalar, group->order, ctx)) {
++                        ECerr(EC_F_EC_GFP_NISTP224_POINTS_MUL, ERR_R_BN_LIB);
++                        goto err;
++                    }
++                    num_bytes = BN_bn2bin(tmp_scalar, tmp);
++                } else
++                    num_bytes = BN_bn2bin(p_scalar, tmp);
++                flip_endian(secrets[i], tmp, num_bytes);
++                /* precompute multiples */
++                if ((!BN_to_felem(x_out, p->X)) ||
++                    (!BN_to_felem(y_out, p->Y)) ||
++                    (!BN_to_felem(z_out, p->Z)))
++                    goto err;
++                felem_assign(pre_comp[i][1][0], x_out);
++                felem_assign(pre_comp[i][1][1], y_out);
++                felem_assign(pre_comp[i][1][2], z_out);
++                for (j = 2; j <= 16; ++j) {
++                    if (j & 1) {
++                        point_add(pre_comp[i][j][0], pre_comp[i][j][1],
++                                  pre_comp[i][j][2], pre_comp[i][1][0],
++                                  pre_comp[i][1][1], pre_comp[i][1][2], 0,
++                                  pre_comp[i][j - 1][0],
++                                  pre_comp[i][j - 1][1],
++                                  pre_comp[i][j - 1][2]);
++                    } else {
++                        point_double(pre_comp[i][j][0], pre_comp[i][j][1],
++                                     pre_comp[i][j][2], pre_comp[i][j / 2][0],
++                                     pre_comp[i][j / 2][1],
++                                     pre_comp[i][j / 2][2]);
++                    }
++                }
++            }
++        }
++        if (mixed)
++            make_points_affine(num_points * 17, pre_comp[0], tmp_felems);
++    }
++
++    /* the scalar for the generator */
++    if ((scalar != NULL) && (have_pre_comp)) {
++        memset(g_secret, 0, sizeof(g_secret));
++        /* reduce scalar to 0 <= scalar < 2^224 */
++        if ((BN_num_bits(scalar) > 224) || (BN_is_negative(scalar))) {
++            /*
++             * this is an unusual input, and we don't guarantee
++             * constant-timeness
++             */
++            if (!BN_nnmod(tmp_scalar, scalar, group->order, ctx)) {
++                ECerr(EC_F_EC_GFP_NISTP224_POINTS_MUL, ERR_R_BN_LIB);
++                goto err;
++            }
++            num_bytes = BN_bn2bin(tmp_scalar, tmp);
++        } else
++            num_bytes = BN_bn2bin(scalar, tmp);
++        flip_endian(g_secret, tmp, num_bytes);
++        /* do the multiplication with generator precomputation */
++        batch_mul(x_out, y_out, z_out,
++                  (const felem_bytearray(*))secrets, num_points,
++                  g_secret,
++                  mixed, (const felem(*)[17][3])pre_comp, g_pre_comp);
++    } else
++        /* do the multiplication without generator precomputation */
++        batch_mul(x_out, y_out, z_out,
++                  (const felem_bytearray(*))secrets, num_points,
++                  NULL, mixed, (const felem(*)[17][3])pre_comp, NULL);
++    /* reduce the output to its unique minimal representation */
++    felem_contract(x_in, x_out);
++    felem_contract(y_in, y_out);
++    felem_contract(z_in, z_out);
++    if ((!felem_to_BN(x, x_in)) || (!felem_to_BN(y, y_in)) ||
++        (!felem_to_BN(z, z_in))) {
++        ECerr(EC_F_EC_GFP_NISTP224_POINTS_MUL, ERR_R_BN_LIB);
++        goto err;
++    }
++    ret = EC_POINT_set_Jprojective_coordinates_GFp(group, r, x, y, z, ctx);
++
++ err:
++    BN_CTX_end(ctx);
++    EC_POINT_free(generator);
++    BN_CTX_free(new_ctx);
++    OPENSSL_free(secrets);
++    OPENSSL_free(pre_comp);
++    OPENSSL_free(tmp_felems);
++    return ret;
++}
++
++int ec_GFp_nistp224_precompute_mult(EC_GROUP *group, BN_CTX *ctx)
++{
++    int ret = 0;
++    NISTP224_PRE_COMP *pre = NULL;
++    int i, j;
++    BN_CTX *new_ctx = NULL;
++    BIGNUM *x, *y;
++    EC_POINT *generator = NULL;
++    felem tmp_felems[32];
++
++    /* throw away old precomputation */
++    EC_pre_comp_free(group);
++    if (ctx == NULL)
++        if ((ctx = new_ctx = BN_CTX_new()) == NULL)
++            return 0;
++    BN_CTX_start(ctx);
++    if (((x = BN_CTX_get(ctx)) == NULL) || ((y = BN_CTX_get(ctx)) == NULL))
++        goto err;
++    /* get the generator */
++    if (group->generator == NULL)
++        goto err;
++    generator = EC_POINT_new(group);
++    if (generator == NULL)
++        goto err;
++    BN_bin2bn(nistp224_curve_params[3], sizeof(felem_bytearray), x);
++    BN_bin2bn(nistp224_curve_params[4], sizeof(felem_bytearray), y);
++    if (!EC_POINT_set_affine_coordinates_GFp(group, generator, x, y, ctx))
++        goto err;
++    if ((pre = nistp224_pre_comp_new()) == NULL)
++        goto err;
++    /*
++     * if the generator is the standard one, use built-in precomputation
++     */
++    if (0 == EC_POINT_cmp(group, generator, group->generator, ctx)) {
++        memcpy(pre->g_pre_comp, gmul, sizeof(pre->g_pre_comp));
++        goto done;
++    }
++    if ((!BN_to_felem(pre->g_pre_comp[0][1][0], group->generator->X)) ||
++        (!BN_to_felem(pre->g_pre_comp[0][1][1], group->generator->Y)) ||
++        (!BN_to_felem(pre->g_pre_comp[0][1][2], group->generator->Z)))
++        goto err;
++    /*
++     * compute 2^56*G, 2^112*G, 2^168*G for the first table, 2^28*G, 2^84*G,
++     * 2^140*G, 2^196*G for the second one
++     */
++    for (i = 1; i <= 8; i <<= 1) {
++        point_double(pre->g_pre_comp[1][i][0], pre->g_pre_comp[1][i][1],
++                     pre->g_pre_comp[1][i][2], pre->g_pre_comp[0][i][0],
++                     pre->g_pre_comp[0][i][1], pre->g_pre_comp[0][i][2]);
++        for (j = 0; j < 27; ++j) {
++            point_double(pre->g_pre_comp[1][i][0], pre->g_pre_comp[1][i][1],
++                         pre->g_pre_comp[1][i][2], pre->g_pre_comp[1][i][0],
++                         pre->g_pre_comp[1][i][1], pre->g_pre_comp[1][i][2]);
++        }
++        if (i == 8)
++            break;
++        point_double(pre->g_pre_comp[0][2 * i][0],
++                     pre->g_pre_comp[0][2 * i][1],
++                     pre->g_pre_comp[0][2 * i][2], pre->g_pre_comp[1][i][0],
++                     pre->g_pre_comp[1][i][1], pre->g_pre_comp[1][i][2]);
++        for (j = 0; j < 27; ++j) {
++            point_double(pre->g_pre_comp[0][2 * i][0],
++                         pre->g_pre_comp[0][2 * i][1],
++                         pre->g_pre_comp[0][2 * i][2],
++                         pre->g_pre_comp[0][2 * i][0],
++                         pre->g_pre_comp[0][2 * i][1],
++                         pre->g_pre_comp[0][2 * i][2]);
++        }
++    }
++    for (i = 0; i < 2; i++) {
++        /* g_pre_comp[i][0] is the point at infinity */
++        memset(pre->g_pre_comp[i][0], 0, sizeof(pre->g_pre_comp[i][0]));
++        /* the remaining multiples */
++        /* 2^56*G + 2^112*G resp. 2^84*G + 2^140*G */
++        point_add(pre->g_pre_comp[i][6][0], pre->g_pre_comp[i][6][1],
++                  pre->g_pre_comp[i][6][2], pre->g_pre_comp[i][4][0],
++                  pre->g_pre_comp[i][4][1], pre->g_pre_comp[i][4][2],
++                  0, pre->g_pre_comp[i][2][0], pre->g_pre_comp[i][2][1],
++                  pre->g_pre_comp[i][2][2]);
++        /* 2^56*G + 2^168*G resp. 2^84*G + 2^196*G */
++        point_add(pre->g_pre_comp[i][10][0], pre->g_pre_comp[i][10][1],
++                  pre->g_pre_comp[i][10][2], pre->g_pre_comp[i][8][0],
++                  pre->g_pre_comp[i][8][1], pre->g_pre_comp[i][8][2],
++                  0, pre->g_pre_comp[i][2][0], pre->g_pre_comp[i][2][1],
++                  pre->g_pre_comp[i][2][2]);
++        /* 2^112*G + 2^168*G resp. 2^140*G + 2^196*G */
++        point_add(pre->g_pre_comp[i][12][0], pre->g_pre_comp[i][12][1],
++                  pre->g_pre_comp[i][12][2], pre->g_pre_comp[i][8][0],
++                  pre->g_pre_comp[i][8][1], pre->g_pre_comp[i][8][2],
++                  0, pre->g_pre_comp[i][4][0], pre->g_pre_comp[i][4][1],
++                  pre->g_pre_comp[i][4][2]);
++        /*
++         * 2^56*G + 2^112*G + 2^168*G resp. 2^84*G + 2^140*G + 2^196*G
++         */
++        point_add(pre->g_pre_comp[i][14][0], pre->g_pre_comp[i][14][1],
++                  pre->g_pre_comp[i][14][2], pre->g_pre_comp[i][12][0],
++                  pre->g_pre_comp[i][12][1], pre->g_pre_comp[i][12][2],
++                  0, pre->g_pre_comp[i][2][0], pre->g_pre_comp[i][2][1],
++                  pre->g_pre_comp[i][2][2]);
++        for (j = 1; j < 8; ++j) {
++            /* odd multiples: add G resp. 2^28*G */
++            point_add(pre->g_pre_comp[i][2 * j + 1][0],
++                      pre->g_pre_comp[i][2 * j + 1][1],
++                      pre->g_pre_comp[i][2 * j + 1][2],
++                      pre->g_pre_comp[i][2 * j][0],
++                      pre->g_pre_comp[i][2 * j][1],
++                      pre->g_pre_comp[i][2 * j][2], 0,
++                      pre->g_pre_comp[i][1][0], pre->g_pre_comp[i][1][1],
++                      pre->g_pre_comp[i][1][2]);
++        }
++    }
++    make_points_affine(31, &(pre->g_pre_comp[0][1]), tmp_felems);
++
++ done:
++    SETPRECOMP(group, nistp224, pre);
++    pre = NULL;
++    ret = 1;
++ err:
++    BN_CTX_end(ctx);
++    EC_POINT_free(generator);
++    BN_CTX_free(new_ctx);
++    EC_nistp224_pre_comp_free(pre);
++    return ret;
++}
++
++int ec_GFp_nistp224_have_precompute_mult(const EC_GROUP *group)
++{
++    return HAVEPRECOMP(group, nistp224);
++}
++
++#endif
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/ec/ecp_nistp256.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/ec/ecp_nistp256.c
+new file mode 100644
+index 0000000..8cd7222
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/ec/ecp_nistp256.c
+@@ -0,0 +1,2350 @@
++/*
++ * Copyright 2011-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++/* Copyright 2011 Google Inc.
++ *
++ * Licensed under the Apache License, Version 2.0 (the "License");
++ *
++ * you may not use this file except in compliance with the License.
++ * You may obtain a copy of the License at
++ *
++ *     http://www.apache.org/licenses/LICENSE-2.0
++ *
++ *  Unless required by applicable law or agreed to in writing, software
++ *  distributed under the License is distributed on an "AS IS" BASIS,
++ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ *  See the License for the specific language governing permissions and
++ *  limitations under the License.
++ */
++
++/*
++ * A 64-bit implementation of the NIST P-256 elliptic curve point multiplication
++ *
++ * OpenSSL integration was taken from Emilia Kasper's work in ecp_nistp224.c.
++ * Otherwise based on Emilia's P224 work, which was inspired by my curve25519
++ * work which got its smarts from Daniel J. Bernstein's work on the same.
++ */
++
++#include 
++#ifdef OPENSSL_NO_EC_NISTP_64_GCC_128
++NON_EMPTY_TRANSLATION_UNIT
++#else
++
++# include 
++# include 
++# include 
++# include "ec_lcl.h"
++
++# if defined(__GNUC__) && (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 1))
++  /* even with gcc, the typedef won't work for 32-bit platforms */
++typedef __uint128_t uint128_t;  /* nonstandard; implemented by gcc on 64-bit
++                                 * platforms */
++typedef __int128_t int128_t;
++# else
++#  error "Need GCC 3.1 or later to define type uint128_t"
++# endif
++
++typedef uint8_t u8;
++typedef uint32_t u32;
++typedef uint64_t u64;
++typedef int64_t s64;
++
++/*
++ * The underlying field. P256 operates over GF(2^256-2^224+2^192+2^96-1). We
++ * can serialise an element of this field into 32 bytes. We call this an
++ * felem_bytearray.
++ */
++
++typedef u8 felem_bytearray[32];
++
++/*
++ * These are the parameters of P256, taken from FIPS 186-3, page 86. These
++ * values are big-endian.
++ */
++static const felem_bytearray nistp256_curve_params[5] = {
++    {0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x01, /* p */
++     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
++     0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
++     0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
++    {0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x01, /* a = -3 */
++     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
++     0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
++     0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc}, /* b */
++    {0x5a, 0xc6, 0x35, 0xd8, 0xaa, 0x3a, 0x93, 0xe7,
++     0xb3, 0xeb, 0xbd, 0x55, 0x76, 0x98, 0x86, 0xbc,
++     0x65, 0x1d, 0x06, 0xb0, 0xcc, 0x53, 0xb0, 0xf6,
++     0x3b, 0xce, 0x3c, 0x3e, 0x27, 0xd2, 0x60, 0x4b},
++    {0x6b, 0x17, 0xd1, 0xf2, 0xe1, 0x2c, 0x42, 0x47, /* x */
++     0xf8, 0xbc, 0xe6, 0xe5, 0x63, 0xa4, 0x40, 0xf2,
++     0x77, 0x03, 0x7d, 0x81, 0x2d, 0xeb, 0x33, 0xa0,
++     0xf4, 0xa1, 0x39, 0x45, 0xd8, 0x98, 0xc2, 0x96},
++    {0x4f, 0xe3, 0x42, 0xe2, 0xfe, 0x1a, 0x7f, 0x9b, /* y */
++     0x8e, 0xe7, 0xeb, 0x4a, 0x7c, 0x0f, 0x9e, 0x16,
++     0x2b, 0xce, 0x33, 0x57, 0x6b, 0x31, 0x5e, 0xce,
++     0xcb, 0xb6, 0x40, 0x68, 0x37, 0xbf, 0x51, 0xf5}
++};
++
++/*-
++ * The representation of field elements.
++ * ------------------------------------
++ *
++ * We represent field elements with either four 128-bit values, eight 128-bit
++ * values, or four 64-bit values. The field element represented is:
++ *   v[0]*2^0 + v[1]*2^64 + v[2]*2^128 + v[3]*2^192  (mod p)
++ * or:
++ *   v[0]*2^0 + v[1]*2^64 + v[2]*2^128 + ... + v[8]*2^512  (mod p)
++ *
++ * 128-bit values are called 'limbs'. Since the limbs are spaced only 64 bits
++ * apart, but are 128-bits wide, the most significant bits of each limb overlap
++ * with the least significant bits of the next.
++ *
++ * A field element with four limbs is an 'felem'. One with eight limbs is a
++ * 'longfelem'
++ *
++ * A field element with four, 64-bit values is called a 'smallfelem'. Small
++ * values are used as intermediate values before multiplication.
++ */
++
++# define NLIMBS 4
++
++typedef uint128_t limb;
++typedef limb felem[NLIMBS];
++typedef limb longfelem[NLIMBS * 2];
++typedef u64 smallfelem[NLIMBS];
++
++/* This is the value of the prime as four 64-bit words, little-endian. */
++static const u64 kPrime[4] =
++    { 0xfffffffffffffffful, 0xffffffff, 0, 0xffffffff00000001ul };
++static const u64 bottom63bits = 0x7ffffffffffffffful;
++
++/*
++ * bin32_to_felem takes a little-endian byte array and converts it into felem
++ * form. This assumes that the CPU is little-endian.
++ */
++static void bin32_to_felem(felem out, const u8 in[32])
++{
++    out[0] = *((u64 *)&in[0]);
++    out[1] = *((u64 *)&in[8]);
++    out[2] = *((u64 *)&in[16]);
++    out[3] = *((u64 *)&in[24]);
++}
++
++/*
++ * smallfelem_to_bin32 takes a smallfelem and serialises into a little
++ * endian, 32 byte array. This assumes that the CPU is little-endian.
++ */
++static void smallfelem_to_bin32(u8 out[32], const smallfelem in)
++{
++    *((u64 *)&out[0]) = in[0];
++    *((u64 *)&out[8]) = in[1];
++    *((u64 *)&out[16]) = in[2];
++    *((u64 *)&out[24]) = in[3];
++}
++
++/* To preserve endianness when using BN_bn2bin and BN_bin2bn */
++static void flip_endian(u8 *out, const u8 *in, unsigned len)
++{
++    unsigned i;
++    for (i = 0; i < len; ++i)
++        out[i] = in[len - 1 - i];
++}
++
++/* BN_to_felem converts an OpenSSL BIGNUM into an felem */
++static int BN_to_felem(felem out, const BIGNUM *bn)
++{
++    felem_bytearray b_in;
++    felem_bytearray b_out;
++    unsigned num_bytes;
++
++    /* BN_bn2bin eats leading zeroes */
++    memset(b_out, 0, sizeof(b_out));
++    num_bytes = BN_num_bytes(bn);
++    if (num_bytes > sizeof b_out) {
++        ECerr(EC_F_BN_TO_FELEM, EC_R_BIGNUM_OUT_OF_RANGE);
++        return 0;
++    }
++    if (BN_is_negative(bn)) {
++        ECerr(EC_F_BN_TO_FELEM, EC_R_BIGNUM_OUT_OF_RANGE);
++        return 0;
++    }
++    num_bytes = BN_bn2bin(bn, b_in);
++    flip_endian(b_out, b_in, num_bytes);
++    bin32_to_felem(out, b_out);
++    return 1;
++}
++
++/* felem_to_BN converts an felem into an OpenSSL BIGNUM */
++static BIGNUM *smallfelem_to_BN(BIGNUM *out, const smallfelem in)
++{
++    felem_bytearray b_in, b_out;
++    smallfelem_to_bin32(b_in, in);
++    flip_endian(b_out, b_in, sizeof b_out);
++    return BN_bin2bn(b_out, sizeof b_out, out);
++}
++
++/*-
++ * Field operations
++ * ----------------
++ */
++
++static void smallfelem_one(smallfelem out)
++{
++    out[0] = 1;
++    out[1] = 0;
++    out[2] = 0;
++    out[3] = 0;
++}
++
++static void smallfelem_assign(smallfelem out, const smallfelem in)
++{
++    out[0] = in[0];
++    out[1] = in[1];
++    out[2] = in[2];
++    out[3] = in[3];
++}
++
++static void felem_assign(felem out, const felem in)
++{
++    out[0] = in[0];
++    out[1] = in[1];
++    out[2] = in[2];
++    out[3] = in[3];
++}
++
++/* felem_sum sets out = out + in. */
++static void felem_sum(felem out, const felem in)
++{
++    out[0] += in[0];
++    out[1] += in[1];
++    out[2] += in[2];
++    out[3] += in[3];
++}
++
++/* felem_small_sum sets out = out + in. */
++static void felem_small_sum(felem out, const smallfelem in)
++{
++    out[0] += in[0];
++    out[1] += in[1];
++    out[2] += in[2];
++    out[3] += in[3];
++}
++
++/* felem_scalar sets out = out * scalar */
++static void felem_scalar(felem out, const u64 scalar)
++{
++    out[0] *= scalar;
++    out[1] *= scalar;
++    out[2] *= scalar;
++    out[3] *= scalar;
++}
++
++/* longfelem_scalar sets out = out * scalar */
++static void longfelem_scalar(longfelem out, const u64 scalar)
++{
++    out[0] *= scalar;
++    out[1] *= scalar;
++    out[2] *= scalar;
++    out[3] *= scalar;
++    out[4] *= scalar;
++    out[5] *= scalar;
++    out[6] *= scalar;
++    out[7] *= scalar;
++}
++
++# define two105m41m9 (((limb)1) << 105) - (((limb)1) << 41) - (((limb)1) << 9)
++# define two105 (((limb)1) << 105)
++# define two105m41p9 (((limb)1) << 105) - (((limb)1) << 41) + (((limb)1) << 9)
++
++/* zero105 is 0 mod p */
++static const felem zero105 =
++    { two105m41m9, two105, two105m41p9, two105m41p9 };
++
++/*-
++ * smallfelem_neg sets |out| to |-small|
++ * On exit:
++ *   out[i] < out[i] + 2^105
++ */
++static void smallfelem_neg(felem out, const smallfelem small)
++{
++    /* In order to prevent underflow, we subtract from 0 mod p. */
++    out[0] = zero105[0] - small[0];
++    out[1] = zero105[1] - small[1];
++    out[2] = zero105[2] - small[2];
++    out[3] = zero105[3] - small[3];
++}
++
++/*-
++ * felem_diff subtracts |in| from |out|
++ * On entry:
++ *   in[i] < 2^104
++ * On exit:
++ *   out[i] < out[i] + 2^105
++ */
++static void felem_diff(felem out, const felem in)
++{
++    /*
++     * In order to prevent underflow, we add 0 mod p before subtracting.
++     */
++    out[0] += zero105[0];
++    out[1] += zero105[1];
++    out[2] += zero105[2];
++    out[3] += zero105[3];
++
++    out[0] -= in[0];
++    out[1] -= in[1];
++    out[2] -= in[2];
++    out[3] -= in[3];
++}
++
++# define two107m43m11 (((limb)1) << 107) - (((limb)1) << 43) - (((limb)1) << 11)
++# define two107 (((limb)1) << 107)
++# define two107m43p11 (((limb)1) << 107) - (((limb)1) << 43) + (((limb)1) << 11)
++
++/* zero107 is 0 mod p */
++static const felem zero107 =
++    { two107m43m11, two107, two107m43p11, two107m43p11 };
++
++/*-
++ * An alternative felem_diff for larger inputs |in|
++ * felem_diff_zero107 subtracts |in| from |out|
++ * On entry:
++ *   in[i] < 2^106
++ * On exit:
++ *   out[i] < out[i] + 2^107
++ */
++static void felem_diff_zero107(felem out, const felem in)
++{
++    /*
++     * In order to prevent underflow, we add 0 mod p before subtracting.
++     */
++    out[0] += zero107[0];
++    out[1] += zero107[1];
++    out[2] += zero107[2];
++    out[3] += zero107[3];
++
++    out[0] -= in[0];
++    out[1] -= in[1];
++    out[2] -= in[2];
++    out[3] -= in[3];
++}
++
++/*-
++ * longfelem_diff subtracts |in| from |out|
++ * On entry:
++ *   in[i] < 7*2^67
++ * On exit:
++ *   out[i] < out[i] + 2^70 + 2^40
++ */
++static void longfelem_diff(longfelem out, const longfelem in)
++{
++    static const limb two70m8p6 =
++        (((limb) 1) << 70) - (((limb) 1) << 8) + (((limb) 1) << 6);
++    static const limb two70p40 = (((limb) 1) << 70) + (((limb) 1) << 40);
++    static const limb two70 = (((limb) 1) << 70);
++    static const limb two70m40m38p6 =
++        (((limb) 1) << 70) - (((limb) 1) << 40) - (((limb) 1) << 38) +
++        (((limb) 1) << 6);
++    static const limb two70m6 = (((limb) 1) << 70) - (((limb) 1) << 6);
++
++    /* add 0 mod p to avoid underflow */
++    out[0] += two70m8p6;
++    out[1] += two70p40;
++    out[2] += two70;
++    out[3] += two70m40m38p6;
++    out[4] += two70m6;
++    out[5] += two70m6;
++    out[6] += two70m6;
++    out[7] += two70m6;
++
++    /* in[i] < 7*2^67 < 2^70 - 2^40 - 2^38 + 2^6 */
++    out[0] -= in[0];
++    out[1] -= in[1];
++    out[2] -= in[2];
++    out[3] -= in[3];
++    out[4] -= in[4];
++    out[5] -= in[5];
++    out[6] -= in[6];
++    out[7] -= in[7];
++}
++
++# define two64m0 (((limb)1) << 64) - 1
++# define two110p32m0 (((limb)1) << 110) + (((limb)1) << 32) - 1
++# define two64m46 (((limb)1) << 64) - (((limb)1) << 46)
++# define two64m32 (((limb)1) << 64) - (((limb)1) << 32)
++
++/* zero110 is 0 mod p */
++static const felem zero110 = { two64m0, two110p32m0, two64m46, two64m32 };
++
++/*-
++ * felem_shrink converts an felem into a smallfelem. The result isn't quite
++ * minimal as the value may be greater than p.
++ *
++ * On entry:
++ *   in[i] < 2^109
++ * On exit:
++ *   out[i] < 2^64
++ */
++static void felem_shrink(smallfelem out, const felem in)
++{
++    felem tmp;
++    u64 a, b, mask;
++    s64 high, low;
++    static const u64 kPrime3Test = 0x7fffffff00000001ul; /* 2^63 - 2^32 + 1 */
++
++    /* Carry 2->3 */
++    tmp[3] = zero110[3] + in[3] + ((u64)(in[2] >> 64));
++    /* tmp[3] < 2^110 */
++
++    tmp[2] = zero110[2] + (u64)in[2];
++    tmp[0] = zero110[0] + in[0];
++    tmp[1] = zero110[1] + in[1];
++    /* tmp[0] < 2**110, tmp[1] < 2^111, tmp[2] < 2**65 */
++
++    /*
++     * We perform two partial reductions where we eliminate the high-word of
++     * tmp[3]. We don't update the other words till the end.
++     */
++    a = tmp[3] >> 64;           /* a < 2^46 */
++    tmp[3] = (u64)tmp[3];
++    tmp[3] -= a;
++    tmp[3] += ((limb) a) << 32;
++    /* tmp[3] < 2^79 */
++
++    b = a;
++    a = tmp[3] >> 64;           /* a < 2^15 */
++    b += a;                     /* b < 2^46 + 2^15 < 2^47 */
++    tmp[3] = (u64)tmp[3];
++    tmp[3] -= a;
++    tmp[3] += ((limb) a) << 32;
++    /* tmp[3] < 2^64 + 2^47 */
++
++    /*
++     * This adjusts the other two words to complete the two partial
++     * reductions.
++     */
++    tmp[0] += b;
++    tmp[1] -= (((limb) b) << 32);
++
++    /*
++     * In order to make space in tmp[3] for the carry from 2 -> 3, we
++     * conditionally subtract kPrime if tmp[3] is large enough.
++     */
++    high = tmp[3] >> 64;
++    /* As tmp[3] < 2^65, high is either 1 or 0 */
++    high <<= 63;
++    high >>= 63;
++    /*-
++     * high is:
++     *   all ones   if the high word of tmp[3] is 1
++     *   all zeros  if the high word of tmp[3] if 0 */
++    low = tmp[3];
++    mask = low >> 63;
++    /*-
++     * mask is:
++     *   all ones   if the MSB of low is 1
++     *   all zeros  if the MSB of low if 0 */
++    low &= bottom63bits;
++    low -= kPrime3Test;
++    /* if low was greater than kPrime3Test then the MSB is zero */
++    low = ~low;
++    low >>= 63;
++    /*-
++     * low is:
++     *   all ones   if low was > kPrime3Test
++     *   all zeros  if low was <= kPrime3Test */
++    mask = (mask & low) | high;
++    tmp[0] -= mask & kPrime[0];
++    tmp[1] -= mask & kPrime[1];
++    /* kPrime[2] is zero, so omitted */
++    tmp[3] -= mask & kPrime[3];
++    /* tmp[3] < 2**64 - 2**32 + 1 */
++
++    tmp[1] += ((u64)(tmp[0] >> 64));
++    tmp[0] = (u64)tmp[0];
++    tmp[2] += ((u64)(tmp[1] >> 64));
++    tmp[1] = (u64)tmp[1];
++    tmp[3] += ((u64)(tmp[2] >> 64));
++    tmp[2] = (u64)tmp[2];
++    /* tmp[i] < 2^64 */
++
++    out[0] = tmp[0];
++    out[1] = tmp[1];
++    out[2] = tmp[2];
++    out[3] = tmp[3];
++}
++
++/* smallfelem_expand converts a smallfelem to an felem */
++static void smallfelem_expand(felem out, const smallfelem in)
++{
++    out[0] = in[0];
++    out[1] = in[1];
++    out[2] = in[2];
++    out[3] = in[3];
++}
++
++/*-
++ * smallfelem_square sets |out| = |small|^2
++ * On entry:
++ *   small[i] < 2^64
++ * On exit:
++ *   out[i] < 7 * 2^64 < 2^67
++ */
++static void smallfelem_square(longfelem out, const smallfelem small)
++{
++    limb a;
++    u64 high, low;
++
++    a = ((uint128_t) small[0]) * small[0];
++    low = a;
++    high = a >> 64;
++    out[0] = low;
++    out[1] = high;
++
++    a = ((uint128_t) small[0]) * small[1];
++    low = a;
++    high = a >> 64;
++    out[1] += low;
++    out[1] += low;
++    out[2] = high;
++
++    a = ((uint128_t) small[0]) * small[2];
++    low = a;
++    high = a >> 64;
++    out[2] += low;
++    out[2] *= 2;
++    out[3] = high;
++
++    a = ((uint128_t) small[0]) * small[3];
++    low = a;
++    high = a >> 64;
++    out[3] += low;
++    out[4] = high;
++
++    a = ((uint128_t) small[1]) * small[2];
++    low = a;
++    high = a >> 64;
++    out[3] += low;
++    out[3] *= 2;
++    out[4] += high;
++
++    a = ((uint128_t) small[1]) * small[1];
++    low = a;
++    high = a >> 64;
++    out[2] += low;
++    out[3] += high;
++
++    a = ((uint128_t) small[1]) * small[3];
++    low = a;
++    high = a >> 64;
++    out[4] += low;
++    out[4] *= 2;
++    out[5] = high;
++
++    a = ((uint128_t) small[2]) * small[3];
++    low = a;
++    high = a >> 64;
++    out[5] += low;
++    out[5] *= 2;
++    out[6] = high;
++    out[6] += high;
++
++    a = ((uint128_t) small[2]) * small[2];
++    low = a;
++    high = a >> 64;
++    out[4] += low;
++    out[5] += high;
++
++    a = ((uint128_t) small[3]) * small[3];
++    low = a;
++    high = a >> 64;
++    out[6] += low;
++    out[7] = high;
++}
++
++/*-
++ * felem_square sets |out| = |in|^2
++ * On entry:
++ *   in[i] < 2^109
++ * On exit:
++ *   out[i] < 7 * 2^64 < 2^67
++ */
++static void felem_square(longfelem out, const felem in)
++{
++    u64 small[4];
++    felem_shrink(small, in);
++    smallfelem_square(out, small);
++}
++
++/*-
++ * smallfelem_mul sets |out| = |small1| * |small2|
++ * On entry:
++ *   small1[i] < 2^64
++ *   small2[i] < 2^64
++ * On exit:
++ *   out[i] < 7 * 2^64 < 2^67
++ */
++static void smallfelem_mul(longfelem out, const smallfelem small1,
++                           const smallfelem small2)
++{
++    limb a;
++    u64 high, low;
++
++    a = ((uint128_t) small1[0]) * small2[0];
++    low = a;
++    high = a >> 64;
++    out[0] = low;
++    out[1] = high;
++
++    a = ((uint128_t) small1[0]) * small2[1];
++    low = a;
++    high = a >> 64;
++    out[1] += low;
++    out[2] = high;
++
++    a = ((uint128_t) small1[1]) * small2[0];
++    low = a;
++    high = a >> 64;
++    out[1] += low;
++    out[2] += high;
++
++    a = ((uint128_t) small1[0]) * small2[2];
++    low = a;
++    high = a >> 64;
++    out[2] += low;
++    out[3] = high;
++
++    a = ((uint128_t) small1[1]) * small2[1];
++    low = a;
++    high = a >> 64;
++    out[2] += low;
++    out[3] += high;
++
++    a = ((uint128_t) small1[2]) * small2[0];
++    low = a;
++    high = a >> 64;
++    out[2] += low;
++    out[3] += high;
++
++    a = ((uint128_t) small1[0]) * small2[3];
++    low = a;
++    high = a >> 64;
++    out[3] += low;
++    out[4] = high;
++
++    a = ((uint128_t) small1[1]) * small2[2];
++    low = a;
++    high = a >> 64;
++    out[3] += low;
++    out[4] += high;
++
++    a = ((uint128_t) small1[2]) * small2[1];
++    low = a;
++    high = a >> 64;
++    out[3] += low;
++    out[4] += high;
++
++    a = ((uint128_t) small1[3]) * small2[0];
++    low = a;
++    high = a >> 64;
++    out[3] += low;
++    out[4] += high;
++
++    a = ((uint128_t) small1[1]) * small2[3];
++    low = a;
++    high = a >> 64;
++    out[4] += low;
++    out[5] = high;
++
++    a = ((uint128_t) small1[2]) * small2[2];
++    low = a;
++    high = a >> 64;
++    out[4] += low;
++    out[5] += high;
++
++    a = ((uint128_t) small1[3]) * small2[1];
++    low = a;
++    high = a >> 64;
++    out[4] += low;
++    out[5] += high;
++
++    a = ((uint128_t) small1[2]) * small2[3];
++    low = a;
++    high = a >> 64;
++    out[5] += low;
++    out[6] = high;
++
++    a = ((uint128_t) small1[3]) * small2[2];
++    low = a;
++    high = a >> 64;
++    out[5] += low;
++    out[6] += high;
++
++    a = ((uint128_t) small1[3]) * small2[3];
++    low = a;
++    high = a >> 64;
++    out[6] += low;
++    out[7] = high;
++}
++
++/*-
++ * felem_mul sets |out| = |in1| * |in2|
++ * On entry:
++ *   in1[i] < 2^109
++ *   in2[i] < 2^109
++ * On exit:
++ *   out[i] < 7 * 2^64 < 2^67
++ */
++static void felem_mul(longfelem out, const felem in1, const felem in2)
++{
++    smallfelem small1, small2;
++    felem_shrink(small1, in1);
++    felem_shrink(small2, in2);
++    smallfelem_mul(out, small1, small2);
++}
++
++/*-
++ * felem_small_mul sets |out| = |small1| * |in2|
++ * On entry:
++ *   small1[i] < 2^64
++ *   in2[i] < 2^109
++ * On exit:
++ *   out[i] < 7 * 2^64 < 2^67
++ */
++static void felem_small_mul(longfelem out, const smallfelem small1,
++                            const felem in2)
++{
++    smallfelem small2;
++    felem_shrink(small2, in2);
++    smallfelem_mul(out, small1, small2);
++}
++
++# define two100m36m4 (((limb)1) << 100) - (((limb)1) << 36) - (((limb)1) << 4)
++# define two100 (((limb)1) << 100)
++# define two100m36p4 (((limb)1) << 100) - (((limb)1) << 36) + (((limb)1) << 4)
++/* zero100 is 0 mod p */
++static const felem zero100 =
++    { two100m36m4, two100, two100m36p4, two100m36p4 };
++
++/*-
++ * Internal function for the different flavours of felem_reduce.
++ * felem_reduce_ reduces the higher coefficients in[4]-in[7].
++ * On entry:
++ *   out[0] >= in[6] + 2^32*in[6] + in[7] + 2^32*in[7]
++ *   out[1] >= in[7] + 2^32*in[4]
++ *   out[2] >= in[5] + 2^32*in[5]
++ *   out[3] >= in[4] + 2^32*in[5] + 2^32*in[6]
++ * On exit:
++ *   out[0] <= out[0] + in[4] + 2^32*in[5]
++ *   out[1] <= out[1] + in[5] + 2^33*in[6]
++ *   out[2] <= out[2] + in[7] + 2*in[6] + 2^33*in[7]
++ *   out[3] <= out[3] + 2^32*in[4] + 3*in[7]
++ */
++static void felem_reduce_(felem out, const longfelem in)
++{
++    int128_t c;
++    /* combine common terms from below */
++    c = in[4] + (in[5] << 32);
++    out[0] += c;
++    out[3] -= c;
++
++    c = in[5] - in[7];
++    out[1] += c;
++    out[2] -= c;
++
++    /* the remaining terms */
++    /* 256: [(0,1),(96,-1),(192,-1),(224,1)] */
++    out[1] -= (in[4] << 32);
++    out[3] += (in[4] << 32);
++
++    /* 320: [(32,1),(64,1),(128,-1),(160,-1),(224,-1)] */
++    out[2] -= (in[5] << 32);
++
++    /* 384: [(0,-1),(32,-1),(96,2),(128,2),(224,-1)] */
++    out[0] -= in[6];
++    out[0] -= (in[6] << 32);
++    out[1] += (in[6] << 33);
++    out[2] += (in[6] * 2);
++    out[3] -= (in[6] << 32);
++
++    /* 448: [(0,-1),(32,-1),(64,-1),(128,1),(160,2),(192,3)] */
++    out[0] -= in[7];
++    out[0] -= (in[7] << 32);
++    out[2] += (in[7] << 33);
++    out[3] += (in[7] * 3);
++}
++
++/*-
++ * felem_reduce converts a longfelem into an felem.
++ * To be called directly after felem_square or felem_mul.
++ * On entry:
++ *   in[0] < 2^64, in[1] < 3*2^64, in[2] < 5*2^64, in[3] < 7*2^64
++ *   in[4] < 7*2^64, in[5] < 5*2^64, in[6] < 3*2^64, in[7] < 2*64
++ * On exit:
++ *   out[i] < 2^101
++ */
++static void felem_reduce(felem out, const longfelem in)
++{
++    out[0] = zero100[0] + in[0];
++    out[1] = zero100[1] + in[1];
++    out[2] = zero100[2] + in[2];
++    out[3] = zero100[3] + in[3];
++
++    felem_reduce_(out, in);
++
++    /*-
++     * out[0] > 2^100 - 2^36 - 2^4 - 3*2^64 - 3*2^96 - 2^64 - 2^96 > 0
++     * out[1] > 2^100 - 2^64 - 7*2^96 > 0
++     * out[2] > 2^100 - 2^36 + 2^4 - 5*2^64 - 5*2^96 > 0
++     * out[3] > 2^100 - 2^36 + 2^4 - 7*2^64 - 5*2^96 - 3*2^96 > 0
++     *
++     * out[0] < 2^100 + 2^64 + 7*2^64 + 5*2^96 < 2^101
++     * out[1] < 2^100 + 3*2^64 + 5*2^64 + 3*2^97 < 2^101
++     * out[2] < 2^100 + 5*2^64 + 2^64 + 3*2^65 + 2^97 < 2^101
++     * out[3] < 2^100 + 7*2^64 + 7*2^96 + 3*2^64 < 2^101
++     */
++}
++
++/*-
++ * felem_reduce_zero105 converts a larger longfelem into an felem.
++ * On entry:
++ *   in[0] < 2^71
++ * On exit:
++ *   out[i] < 2^106
++ */
++static void felem_reduce_zero105(felem out, const longfelem in)
++{
++    out[0] = zero105[0] + in[0];
++    out[1] = zero105[1] + in[1];
++    out[2] = zero105[2] + in[2];
++    out[3] = zero105[3] + in[3];
++
++    felem_reduce_(out, in);
++
++    /*-
++     * out[0] > 2^105 - 2^41 - 2^9 - 2^71 - 2^103 - 2^71 - 2^103 > 0
++     * out[1] > 2^105 - 2^71 - 2^103 > 0
++     * out[2] > 2^105 - 2^41 + 2^9 - 2^71 - 2^103 > 0
++     * out[3] > 2^105 - 2^41 + 2^9 - 2^71 - 2^103 - 2^103 > 0
++     *
++     * out[0] < 2^105 + 2^71 + 2^71 + 2^103 < 2^106
++     * out[1] < 2^105 + 2^71 + 2^71 + 2^103 < 2^106
++     * out[2] < 2^105 + 2^71 + 2^71 + 2^71 + 2^103 < 2^106
++     * out[3] < 2^105 + 2^71 + 2^103 + 2^71 < 2^106
++     */
++}
++
++/*
++ * subtract_u64 sets *result = *result - v and *carry to one if the
++ * subtraction underflowed.
++ */
++static void subtract_u64(u64 *result, u64 *carry, u64 v)
++{
++    uint128_t r = *result;
++    r -= v;
++    *carry = (r >> 64) & 1;
++    *result = (u64)r;
++}
++
++/*
++ * felem_contract converts |in| to its unique, minimal representation. On
++ * entry: in[i] < 2^109
++ */
++static void felem_contract(smallfelem out, const felem in)
++{
++    unsigned i;
++    u64 all_equal_so_far = 0, result = 0, carry;
++
++    felem_shrink(out, in);
++    /* small is minimal except that the value might be > p */
++
++    all_equal_so_far--;
++    /*
++     * We are doing a constant time test if out >= kPrime. We need to compare
++     * each u64, from most-significant to least significant. For each one, if
++     * all words so far have been equal (m is all ones) then a non-equal
++     * result is the answer. Otherwise we continue.
++     */
++    for (i = 3; i < 4; i--) {
++        u64 equal;
++        uint128_t a = ((uint128_t) kPrime[i]) - out[i];
++        /*
++         * if out[i] > kPrime[i] then a will underflow and the high 64-bits
++         * will all be set.
++         */
++        result |= all_equal_so_far & ((u64)(a >> 64));
++
++        /*
++         * if kPrime[i] == out[i] then |equal| will be all zeros and the
++         * decrement will make it all ones.
++         */
++        equal = kPrime[i] ^ out[i];
++        equal--;
++        equal &= equal << 32;
++        equal &= equal << 16;
++        equal &= equal << 8;
++        equal &= equal << 4;
++        equal &= equal << 2;
++        equal &= equal << 1;
++        equal = ((s64) equal) >> 63;
++
++        all_equal_so_far &= equal;
++    }
++
++    /*
++     * if all_equal_so_far is still all ones then the two values are equal
++     * and so out >= kPrime is true.
++     */
++    result |= all_equal_so_far;
++
++    /* if out >= kPrime then we subtract kPrime. */
++    subtract_u64(&out[0], &carry, result & kPrime[0]);
++    subtract_u64(&out[1], &carry, carry);
++    subtract_u64(&out[2], &carry, carry);
++    subtract_u64(&out[3], &carry, carry);
++
++    subtract_u64(&out[1], &carry, result & kPrime[1]);
++    subtract_u64(&out[2], &carry, carry);
++    subtract_u64(&out[3], &carry, carry);
++
++    subtract_u64(&out[2], &carry, result & kPrime[2]);
++    subtract_u64(&out[3], &carry, carry);
++
++    subtract_u64(&out[3], &carry, result & kPrime[3]);
++}
++
++static void smallfelem_square_contract(smallfelem out, const smallfelem in)
++{
++    longfelem longtmp;
++    felem tmp;
++
++    smallfelem_square(longtmp, in);
++    felem_reduce(tmp, longtmp);
++    felem_contract(out, tmp);
++}
++
++static void smallfelem_mul_contract(smallfelem out, const smallfelem in1,
++                                    const smallfelem in2)
++{
++    longfelem longtmp;
++    felem tmp;
++
++    smallfelem_mul(longtmp, in1, in2);
++    felem_reduce(tmp, longtmp);
++    felem_contract(out, tmp);
++}
++
++/*-
++ * felem_is_zero returns a limb with all bits set if |in| == 0 (mod p) and 0
++ * otherwise.
++ * On entry:
++ *   small[i] < 2^64
++ */
++static limb smallfelem_is_zero(const smallfelem small)
++{
++    limb result;
++    u64 is_p;
++
++    u64 is_zero = small[0] | small[1] | small[2] | small[3];
++    is_zero--;
++    is_zero &= is_zero << 32;
++    is_zero &= is_zero << 16;
++    is_zero &= is_zero << 8;
++    is_zero &= is_zero << 4;
++    is_zero &= is_zero << 2;
++    is_zero &= is_zero << 1;
++    is_zero = ((s64) is_zero) >> 63;
++
++    is_p = (small[0] ^ kPrime[0]) |
++        (small[1] ^ kPrime[1]) |
++        (small[2] ^ kPrime[2]) | (small[3] ^ kPrime[3]);
++    is_p--;
++    is_p &= is_p << 32;
++    is_p &= is_p << 16;
++    is_p &= is_p << 8;
++    is_p &= is_p << 4;
++    is_p &= is_p << 2;
++    is_p &= is_p << 1;
++    is_p = ((s64) is_p) >> 63;
++
++    is_zero |= is_p;
++
++    result = is_zero;
++    result |= ((limb) is_zero) << 64;
++    return result;
++}
++
++static int smallfelem_is_zero_int(const smallfelem small)
++{
++    return (int)(smallfelem_is_zero(small) & ((limb) 1));
++}
++
++/*-
++ * felem_inv calculates |out| = |in|^{-1}
++ *
++ * Based on Fermat's Little Theorem:
++ *   a^p = a (mod p)
++ *   a^{p-1} = 1 (mod p)
++ *   a^{p-2} = a^{-1} (mod p)
++ */
++static void felem_inv(felem out, const felem in)
++{
++    felem ftmp, ftmp2;
++    /* each e_I will hold |in|^{2^I - 1} */
++    felem e2, e4, e8, e16, e32, e64;
++    longfelem tmp;
++    unsigned i;
++
++    felem_square(tmp, in);
++    felem_reduce(ftmp, tmp);    /* 2^1 */
++    felem_mul(tmp, in, ftmp);
++    felem_reduce(ftmp, tmp);    /* 2^2 - 2^0 */
++    felem_assign(e2, ftmp);
++    felem_square(tmp, ftmp);
++    felem_reduce(ftmp, tmp);    /* 2^3 - 2^1 */
++    felem_square(tmp, ftmp);
++    felem_reduce(ftmp, tmp);    /* 2^4 - 2^2 */
++    felem_mul(tmp, ftmp, e2);
++    felem_reduce(ftmp, tmp);    /* 2^4 - 2^0 */
++    felem_assign(e4, ftmp);
++    felem_square(tmp, ftmp);
++    felem_reduce(ftmp, tmp);    /* 2^5 - 2^1 */
++    felem_square(tmp, ftmp);
++    felem_reduce(ftmp, tmp);    /* 2^6 - 2^2 */
++    felem_square(tmp, ftmp);
++    felem_reduce(ftmp, tmp);    /* 2^7 - 2^3 */
++    felem_square(tmp, ftmp);
++    felem_reduce(ftmp, tmp);    /* 2^8 - 2^4 */
++    felem_mul(tmp, ftmp, e4);
++    felem_reduce(ftmp, tmp);    /* 2^8 - 2^0 */
++    felem_assign(e8, ftmp);
++    for (i = 0; i < 8; i++) {
++        felem_square(tmp, ftmp);
++        felem_reduce(ftmp, tmp);
++    }                           /* 2^16 - 2^8 */
++    felem_mul(tmp, ftmp, e8);
++    felem_reduce(ftmp, tmp);    /* 2^16 - 2^0 */
++    felem_assign(e16, ftmp);
++    for (i = 0; i < 16; i++) {
++        felem_square(tmp, ftmp);
++        felem_reduce(ftmp, tmp);
++    }                           /* 2^32 - 2^16 */
++    felem_mul(tmp, ftmp, e16);
++    felem_reduce(ftmp, tmp);    /* 2^32 - 2^0 */
++    felem_assign(e32, ftmp);
++    for (i = 0; i < 32; i++) {
++        felem_square(tmp, ftmp);
++        felem_reduce(ftmp, tmp);
++    }                           /* 2^64 - 2^32 */
++    felem_assign(e64, ftmp);
++    felem_mul(tmp, ftmp, in);
++    felem_reduce(ftmp, tmp);    /* 2^64 - 2^32 + 2^0 */
++    for (i = 0; i < 192; i++) {
++        felem_square(tmp, ftmp);
++        felem_reduce(ftmp, tmp);
++    }                           /* 2^256 - 2^224 + 2^192 */
++
++    felem_mul(tmp, e64, e32);
++    felem_reduce(ftmp2, tmp);   /* 2^64 - 2^0 */
++    for (i = 0; i < 16; i++) {
++        felem_square(tmp, ftmp2);
++        felem_reduce(ftmp2, tmp);
++    }                           /* 2^80 - 2^16 */
++    felem_mul(tmp, ftmp2, e16);
++    felem_reduce(ftmp2, tmp);   /* 2^80 - 2^0 */
++    for (i = 0; i < 8; i++) {
++        felem_square(tmp, ftmp2);
++        felem_reduce(ftmp2, tmp);
++    }                           /* 2^88 - 2^8 */
++    felem_mul(tmp, ftmp2, e8);
++    felem_reduce(ftmp2, tmp);   /* 2^88 - 2^0 */
++    for (i = 0; i < 4; i++) {
++        felem_square(tmp, ftmp2);
++        felem_reduce(ftmp2, tmp);
++    }                           /* 2^92 - 2^4 */
++    felem_mul(tmp, ftmp2, e4);
++    felem_reduce(ftmp2, tmp);   /* 2^92 - 2^0 */
++    felem_square(tmp, ftmp2);
++    felem_reduce(ftmp2, tmp);   /* 2^93 - 2^1 */
++    felem_square(tmp, ftmp2);
++    felem_reduce(ftmp2, tmp);   /* 2^94 - 2^2 */
++    felem_mul(tmp, ftmp2, e2);
++    felem_reduce(ftmp2, tmp);   /* 2^94 - 2^0 */
++    felem_square(tmp, ftmp2);
++    felem_reduce(ftmp2, tmp);   /* 2^95 - 2^1 */
++    felem_square(tmp, ftmp2);
++    felem_reduce(ftmp2, tmp);   /* 2^96 - 2^2 */
++    felem_mul(tmp, ftmp2, in);
++    felem_reduce(ftmp2, tmp);   /* 2^96 - 3 */
++
++    felem_mul(tmp, ftmp2, ftmp);
++    felem_reduce(out, tmp);     /* 2^256 - 2^224 + 2^192 + 2^96 - 3 */
++}
++
++static void smallfelem_inv_contract(smallfelem out, const smallfelem in)
++{
++    felem tmp;
++
++    smallfelem_expand(tmp, in);
++    felem_inv(tmp, tmp);
++    felem_contract(out, tmp);
++}
++
++/*-
++ * Group operations
++ * ----------------
++ *
++ * Building on top of the field operations we have the operations on the
++ * elliptic curve group itself. Points on the curve are represented in Jacobian
++ * coordinates
++ */
++
++/*-
++ * point_double calculates 2*(x_in, y_in, z_in)
++ *
++ * The method is taken from:
++ *   http://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-3.html#doubling-dbl-2001-b
++ *
++ * Outputs can equal corresponding inputs, i.e., x_out == x_in is allowed.
++ * while x_out == y_in is not (maybe this works, but it's not tested).
++ */
++static void
++point_double(felem x_out, felem y_out, felem z_out,
++             const felem x_in, const felem y_in, const felem z_in)
++{
++    longfelem tmp, tmp2;
++    felem delta, gamma, beta, alpha, ftmp, ftmp2;
++    smallfelem small1, small2;
++
++    felem_assign(ftmp, x_in);
++    /* ftmp[i] < 2^106 */
++    felem_assign(ftmp2, x_in);
++    /* ftmp2[i] < 2^106 */
++
++    /* delta = z^2 */
++    felem_square(tmp, z_in);
++    felem_reduce(delta, tmp);
++    /* delta[i] < 2^101 */
++
++    /* gamma = y^2 */
++    felem_square(tmp, y_in);
++    felem_reduce(gamma, tmp);
++    /* gamma[i] < 2^101 */
++    felem_shrink(small1, gamma);
++
++    /* beta = x*gamma */
++    felem_small_mul(tmp, small1, x_in);
++    felem_reduce(beta, tmp);
++    /* beta[i] < 2^101 */
++
++    /* alpha = 3*(x-delta)*(x+delta) */
++    felem_diff(ftmp, delta);
++    /* ftmp[i] < 2^105 + 2^106 < 2^107 */
++    felem_sum(ftmp2, delta);
++    /* ftmp2[i] < 2^105 + 2^106 < 2^107 */
++    felem_scalar(ftmp2, 3);
++    /* ftmp2[i] < 3 * 2^107 < 2^109 */
++    felem_mul(tmp, ftmp, ftmp2);
++    felem_reduce(alpha, tmp);
++    /* alpha[i] < 2^101 */
++    felem_shrink(small2, alpha);
++
++    /* x' = alpha^2 - 8*beta */
++    smallfelem_square(tmp, small2);
++    felem_reduce(x_out, tmp);
++    felem_assign(ftmp, beta);
++    felem_scalar(ftmp, 8);
++    /* ftmp[i] < 8 * 2^101 = 2^104 */
++    felem_diff(x_out, ftmp);
++    /* x_out[i] < 2^105 + 2^101 < 2^106 */
++
++    /* z' = (y + z)^2 - gamma - delta */
++    felem_sum(delta, gamma);
++    /* delta[i] < 2^101 + 2^101 = 2^102 */
++    felem_assign(ftmp, y_in);
++    felem_sum(ftmp, z_in);
++    /* ftmp[i] < 2^106 + 2^106 = 2^107 */
++    felem_square(tmp, ftmp);
++    felem_reduce(z_out, tmp);
++    felem_diff(z_out, delta);
++    /* z_out[i] < 2^105 + 2^101 < 2^106 */
++
++    /* y' = alpha*(4*beta - x') - 8*gamma^2 */
++    felem_scalar(beta, 4);
++    /* beta[i] < 4 * 2^101 = 2^103 */
++    felem_diff_zero107(beta, x_out);
++    /* beta[i] < 2^107 + 2^103 < 2^108 */
++    felem_small_mul(tmp, small2, beta);
++    /* tmp[i] < 7 * 2^64 < 2^67 */
++    smallfelem_square(tmp2, small1);
++    /* tmp2[i] < 7 * 2^64 */
++    longfelem_scalar(tmp2, 8);
++    /* tmp2[i] < 8 * 7 * 2^64 = 7 * 2^67 */
++    longfelem_diff(tmp, tmp2);
++    /* tmp[i] < 2^67 + 2^70 + 2^40 < 2^71 */
++    felem_reduce_zero105(y_out, tmp);
++    /* y_out[i] < 2^106 */
++}
++
++/*
++ * point_double_small is the same as point_double, except that it operates on
++ * smallfelems
++ */
++static void
++point_double_small(smallfelem x_out, smallfelem y_out, smallfelem z_out,
++                   const smallfelem x_in, const smallfelem y_in,
++                   const smallfelem z_in)
++{
++    felem felem_x_out, felem_y_out, felem_z_out;
++    felem felem_x_in, felem_y_in, felem_z_in;
++
++    smallfelem_expand(felem_x_in, x_in);
++    smallfelem_expand(felem_y_in, y_in);
++    smallfelem_expand(felem_z_in, z_in);
++    point_double(felem_x_out, felem_y_out, felem_z_out,
++                 felem_x_in, felem_y_in, felem_z_in);
++    felem_shrink(x_out, felem_x_out);
++    felem_shrink(y_out, felem_y_out);
++    felem_shrink(z_out, felem_z_out);
++}
++
++/* copy_conditional copies in to out iff mask is all ones. */
++static void copy_conditional(felem out, const felem in, limb mask)
++{
++    unsigned i;
++    for (i = 0; i < NLIMBS; ++i) {
++        const limb tmp = mask & (in[i] ^ out[i]);
++        out[i] ^= tmp;
++    }
++}
++
++/* copy_small_conditional copies in to out iff mask is all ones. */
++static void copy_small_conditional(felem out, const smallfelem in, limb mask)
++{
++    unsigned i;
++    const u64 mask64 = mask;
++    for (i = 0; i < NLIMBS; ++i) {
++        out[i] = ((limb) (in[i] & mask64)) | (out[i] & ~mask);
++    }
++}
++
++/*-
++ * point_add calculates (x1, y1, z1) + (x2, y2, z2)
++ *
++ * The method is taken from:
++ *   http://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-3.html#addition-add-2007-bl,
++ * adapted for mixed addition (z2 = 1, or z2 = 0 for the point at infinity).
++ *
++ * This function includes a branch for checking whether the two input points
++ * are equal, (while not equal to the point at infinity). This case never
++ * happens during single point multiplication, so there is no timing leak for
++ * ECDH or ECDSA signing.
++ */
++static void point_add(felem x3, felem y3, felem z3,
++                      const felem x1, const felem y1, const felem z1,
++                      const int mixed, const smallfelem x2,
++                      const smallfelem y2, const smallfelem z2)
++{
++    felem ftmp, ftmp2, ftmp3, ftmp4, ftmp5, ftmp6, x_out, y_out, z_out;
++    longfelem tmp, tmp2;
++    smallfelem small1, small2, small3, small4, small5;
++    limb x_equal, y_equal, z1_is_zero, z2_is_zero;
++
++    felem_shrink(small3, z1);
++
++    z1_is_zero = smallfelem_is_zero(small3);
++    z2_is_zero = smallfelem_is_zero(z2);
++
++    /* ftmp = z1z1 = z1**2 */
++    smallfelem_square(tmp, small3);
++    felem_reduce(ftmp, tmp);
++    /* ftmp[i] < 2^101 */
++    felem_shrink(small1, ftmp);
++
++    if (!mixed) {
++        /* ftmp2 = z2z2 = z2**2 */
++        smallfelem_square(tmp, z2);
++        felem_reduce(ftmp2, tmp);
++        /* ftmp2[i] < 2^101 */
++        felem_shrink(small2, ftmp2);
++
++        felem_shrink(small5, x1);
++
++        /* u1 = ftmp3 = x1*z2z2 */
++        smallfelem_mul(tmp, small5, small2);
++        felem_reduce(ftmp3, tmp);
++        /* ftmp3[i] < 2^101 */
++
++        /* ftmp5 = z1 + z2 */
++        felem_assign(ftmp5, z1);
++        felem_small_sum(ftmp5, z2);
++        /* ftmp5[i] < 2^107 */
++
++        /* ftmp5 = (z1 + z2)**2 - (z1z1 + z2z2) = 2z1z2 */
++        felem_square(tmp, ftmp5);
++        felem_reduce(ftmp5, tmp);
++        /* ftmp2 = z2z2 + z1z1 */
++        felem_sum(ftmp2, ftmp);
++        /* ftmp2[i] < 2^101 + 2^101 = 2^102 */
++        felem_diff(ftmp5, ftmp2);
++        /* ftmp5[i] < 2^105 + 2^101 < 2^106 */
++
++        /* ftmp2 = z2 * z2z2 */
++        smallfelem_mul(tmp, small2, z2);
++        felem_reduce(ftmp2, tmp);
++
++        /* s1 = ftmp2 = y1 * z2**3 */
++        felem_mul(tmp, y1, ftmp2);
++        felem_reduce(ftmp6, tmp);
++        /* ftmp6[i] < 2^101 */
++    } else {
++        /*
++         * We'll assume z2 = 1 (special case z2 = 0 is handled later)
++         */
++
++        /* u1 = ftmp3 = x1*z2z2 */
++        felem_assign(ftmp3, x1);
++        /* ftmp3[i] < 2^106 */
++
++        /* ftmp5 = 2z1z2 */
++        felem_assign(ftmp5, z1);
++        felem_scalar(ftmp5, 2);
++        /* ftmp5[i] < 2*2^106 = 2^107 */
++
++        /* s1 = ftmp2 = y1 * z2**3 */
++        felem_assign(ftmp6, y1);
++        /* ftmp6[i] < 2^106 */
++    }
++
++    /* u2 = x2*z1z1 */
++    smallfelem_mul(tmp, x2, small1);
++    felem_reduce(ftmp4, tmp);
++
++    /* h = ftmp4 = u2 - u1 */
++    felem_diff_zero107(ftmp4, ftmp3);
++    /* ftmp4[i] < 2^107 + 2^101 < 2^108 */
++    felem_shrink(small4, ftmp4);
++
++    x_equal = smallfelem_is_zero(small4);
++
++    /* z_out = ftmp5 * h */
++    felem_small_mul(tmp, small4, ftmp5);
++    felem_reduce(z_out, tmp);
++    /* z_out[i] < 2^101 */
++
++    /* ftmp = z1 * z1z1 */
++    smallfelem_mul(tmp, small1, small3);
++    felem_reduce(ftmp, tmp);
++
++    /* s2 = tmp = y2 * z1**3 */
++    felem_small_mul(tmp, y2, ftmp);
++    felem_reduce(ftmp5, tmp);
++
++    /* r = ftmp5 = (s2 - s1)*2 */
++    felem_diff_zero107(ftmp5, ftmp6);
++    /* ftmp5[i] < 2^107 + 2^107 = 2^108 */
++    felem_scalar(ftmp5, 2);
++    /* ftmp5[i] < 2^109 */
++    felem_shrink(small1, ftmp5);
++    y_equal = smallfelem_is_zero(small1);
++
++    if (x_equal && y_equal && !z1_is_zero && !z2_is_zero) {
++        point_double(x3, y3, z3, x1, y1, z1);
++        return;
++    }
++
++    /* I = ftmp = (2h)**2 */
++    felem_assign(ftmp, ftmp4);
++    felem_scalar(ftmp, 2);
++    /* ftmp[i] < 2*2^108 = 2^109 */
++    felem_square(tmp, ftmp);
++    felem_reduce(ftmp, tmp);
++
++    /* J = ftmp2 = h * I */
++    felem_mul(tmp, ftmp4, ftmp);
++    felem_reduce(ftmp2, tmp);
++
++    /* V = ftmp4 = U1 * I */
++    felem_mul(tmp, ftmp3, ftmp);
++    felem_reduce(ftmp4, tmp);
++
++    /* x_out = r**2 - J - 2V */
++    smallfelem_square(tmp, small1);
++    felem_reduce(x_out, tmp);
++    felem_assign(ftmp3, ftmp4);
++    felem_scalar(ftmp4, 2);
++    felem_sum(ftmp4, ftmp2);
++    /* ftmp4[i] < 2*2^101 + 2^101 < 2^103 */
++    felem_diff(x_out, ftmp4);
++    /* x_out[i] < 2^105 + 2^101 */
++
++    /* y_out = r(V-x_out) - 2 * s1 * J */
++    felem_diff_zero107(ftmp3, x_out);
++    /* ftmp3[i] < 2^107 + 2^101 < 2^108 */
++    felem_small_mul(tmp, small1, ftmp3);
++    felem_mul(tmp2, ftmp6, ftmp2);
++    longfelem_scalar(tmp2, 2);
++    /* tmp2[i] < 2*2^67 = 2^68 */
++    longfelem_diff(tmp, tmp2);
++    /* tmp[i] < 2^67 + 2^70 + 2^40 < 2^71 */
++    felem_reduce_zero105(y_out, tmp);
++    /* y_out[i] < 2^106 */
++
++    copy_small_conditional(x_out, x2, z1_is_zero);
++    copy_conditional(x_out, x1, z2_is_zero);
++    copy_small_conditional(y_out, y2, z1_is_zero);
++    copy_conditional(y_out, y1, z2_is_zero);
++    copy_small_conditional(z_out, z2, z1_is_zero);
++    copy_conditional(z_out, z1, z2_is_zero);
++    felem_assign(x3, x_out);
++    felem_assign(y3, y_out);
++    felem_assign(z3, z_out);
++}
++
++/*
++ * point_add_small is the same as point_add, except that it operates on
++ * smallfelems
++ */
++static void point_add_small(smallfelem x3, smallfelem y3, smallfelem z3,
++                            smallfelem x1, smallfelem y1, smallfelem z1,
++                            smallfelem x2, smallfelem y2, smallfelem z2)
++{
++    felem felem_x3, felem_y3, felem_z3;
++    felem felem_x1, felem_y1, felem_z1;
++    smallfelem_expand(felem_x1, x1);
++    smallfelem_expand(felem_y1, y1);
++    smallfelem_expand(felem_z1, z1);
++    point_add(felem_x3, felem_y3, felem_z3, felem_x1, felem_y1, felem_z1, 0,
++              x2, y2, z2);
++    felem_shrink(x3, felem_x3);
++    felem_shrink(y3, felem_y3);
++    felem_shrink(z3, felem_z3);
++}
++
++/*-
++ * Base point pre computation
++ * --------------------------
++ *
++ * Two different sorts of precomputed tables are used in the following code.
++ * Each contain various points on the curve, where each point is three field
++ * elements (x, y, z).
++ *
++ * For the base point table, z is usually 1 (0 for the point at infinity).
++ * This table has 2 * 16 elements, starting with the following:
++ * index | bits    | point
++ * ------+---------+------------------------------
++ *     0 | 0 0 0 0 | 0G
++ *     1 | 0 0 0 1 | 1G
++ *     2 | 0 0 1 0 | 2^64G
++ *     3 | 0 0 1 1 | (2^64 + 1)G
++ *     4 | 0 1 0 0 | 2^128G
++ *     5 | 0 1 0 1 | (2^128 + 1)G
++ *     6 | 0 1 1 0 | (2^128 + 2^64)G
++ *     7 | 0 1 1 1 | (2^128 + 2^64 + 1)G
++ *     8 | 1 0 0 0 | 2^192G
++ *     9 | 1 0 0 1 | (2^192 + 1)G
++ *    10 | 1 0 1 0 | (2^192 + 2^64)G
++ *    11 | 1 0 1 1 | (2^192 + 2^64 + 1)G
++ *    12 | 1 1 0 0 | (2^192 + 2^128)G
++ *    13 | 1 1 0 1 | (2^192 + 2^128 + 1)G
++ *    14 | 1 1 1 0 | (2^192 + 2^128 + 2^64)G
++ *    15 | 1 1 1 1 | (2^192 + 2^128 + 2^64 + 1)G
++ * followed by a copy of this with each element multiplied by 2^32.
++ *
++ * The reason for this is so that we can clock bits into four different
++ * locations when doing simple scalar multiplies against the base point,
++ * and then another four locations using the second 16 elements.
++ *
++ * Tables for other points have table[i] = iG for i in 0 .. 16. */
++
++/* gmul is the table of precomputed base points */
++static const smallfelem gmul[2][16][3] = {
++    {{{0, 0, 0, 0},
++      {0, 0, 0, 0},
++      {0, 0, 0, 0}},
++     {{0xf4a13945d898c296, 0x77037d812deb33a0, 0xf8bce6e563a440f2,
++       0x6b17d1f2e12c4247},
++      {0xcbb6406837bf51f5, 0x2bce33576b315ece, 0x8ee7eb4a7c0f9e16,
++       0x4fe342e2fe1a7f9b},
++      {1, 0, 0, 0}},
++     {{0x90e75cb48e14db63, 0x29493baaad651f7e, 0x8492592e326e25de,
++       0x0fa822bc2811aaa5},
++      {0xe41124545f462ee7, 0x34b1a65050fe82f5, 0x6f4ad4bcb3df188b,
++       0xbff44ae8f5dba80d},
++      {1, 0, 0, 0}},
++     {{0x93391ce2097992af, 0xe96c98fd0d35f1fa, 0xb257c0de95e02789,
++       0x300a4bbc89d6726f},
++      {0xaa54a291c08127a0, 0x5bb1eeada9d806a5, 0x7f1ddb25ff1e3c6f,
++       0x72aac7e0d09b4644},
++      {1, 0, 0, 0}},
++     {{0x57c84fc9d789bd85, 0xfc35ff7dc297eac3, 0xfb982fd588c6766e,
++       0x447d739beedb5e67},
++      {0x0c7e33c972e25b32, 0x3d349b95a7fae500, 0xe12e9d953a4aaff7,
++       0x2d4825ab834131ee},
++      {1, 0, 0, 0}},
++     {{0x13949c932a1d367f, 0xef7fbd2b1a0a11b7, 0xddc6068bb91dfc60,
++       0xef9519328a9c72ff},
++      {0x196035a77376d8a8, 0x23183b0895ca1740, 0xc1ee9807022c219c,
++       0x611e9fc37dbb2c9b},
++      {1, 0, 0, 0}},
++     {{0xcae2b1920b57f4bc, 0x2936df5ec6c9bc36, 0x7dea6482e11238bf,
++       0x550663797b51f5d8},
++      {0x44ffe216348a964c, 0x9fb3d576dbdefbe1, 0x0afa40018d9d50e5,
++       0x157164848aecb851},
++      {1, 0, 0, 0}},
++     {{0xe48ecafffc5cde01, 0x7ccd84e70d715f26, 0xa2e8f483f43e4391,
++       0xeb5d7745b21141ea},
++      {0xcac917e2731a3479, 0x85f22cfe2844b645, 0x0990e6a158006cee,
++       0xeafd72ebdbecc17b},
++      {1, 0, 0, 0}},
++     {{0x6cf20ffb313728be, 0x96439591a3c6b94a, 0x2736ff8344315fc5,
++       0xa6d39677a7849276},
++      {0xf2bab833c357f5f4, 0x824a920c2284059b, 0x66b8babd2d27ecdf,
++       0x674f84749b0b8816},
++      {1, 0, 0, 0}},
++     {{0x2df48c04677c8a3e, 0x74e02f080203a56b, 0x31855f7db8c7fedb,
++       0x4e769e7672c9ddad},
++      {0xa4c36165b824bbb0, 0xfb9ae16f3b9122a5, 0x1ec0057206947281,
++       0x42b99082de830663},
++      {1, 0, 0, 0}},
++     {{0x6ef95150dda868b9, 0xd1f89e799c0ce131, 0x7fdc1ca008a1c478,
++       0x78878ef61c6ce04d},
++      {0x9c62b9121fe0d976, 0x6ace570ebde08d4f, 0xde53142c12309def,
++       0xb6cb3f5d7b72c321},
++      {1, 0, 0, 0}},
++     {{0x7f991ed2c31a3573, 0x5b82dd5bd54fb496, 0x595c5220812ffcae,
++       0x0c88bc4d716b1287},
++      {0x3a57bf635f48aca8, 0x7c8181f4df2564f3, 0x18d1b5b39c04e6aa,
++       0xdd5ddea3f3901dc6},
++      {1, 0, 0, 0}},
++     {{0xe96a79fb3e72ad0c, 0x43a0a28c42ba792f, 0xefe0a423083e49f3,
++       0x68f344af6b317466},
++      {0xcdfe17db3fb24d4a, 0x668bfc2271f5c626, 0x604ed93c24d67ff3,
++       0x31b9c405f8540a20},
++      {1, 0, 0, 0}},
++     {{0xd36b4789a2582e7f, 0x0d1a10144ec39c28, 0x663c62c3edbad7a0,
++       0x4052bf4b6f461db9},
++      {0x235a27c3188d25eb, 0xe724f33999bfcc5b, 0x862be6bd71d70cc8,
++       0xfecf4d5190b0fc61},
++      {1, 0, 0, 0}},
++     {{0x74346c10a1d4cfac, 0xafdf5cc08526a7a4, 0x123202a8f62bff7a,
++       0x1eddbae2c802e41a},
++      {0x8fa0af2dd603f844, 0x36e06b7e4c701917, 0x0c45f45273db33a0,
++       0x43104d86560ebcfc},
++      {1, 0, 0, 0}},
++     {{0x9615b5110d1d78e5, 0x66b0de3225c4744b, 0x0a4a46fb6aaf363a,
++       0xb48e26b484f7a21c},
++      {0x06ebb0f621a01b2d, 0xc004e4048b7b0f98, 0x64131bcdfed6f668,
++       0xfac015404d4d3dab},
++      {1, 0, 0, 0}}},
++    {{{0, 0, 0, 0},
++      {0, 0, 0, 0},
++      {0, 0, 0, 0}},
++     {{0x3a5a9e22185a5943, 0x1ab919365c65dfb6, 0x21656b32262c71da,
++       0x7fe36b40af22af89},
++      {0xd50d152c699ca101, 0x74b3d5867b8af212, 0x9f09f40407dca6f1,
++       0xe697d45825b63624},
++      {1, 0, 0, 0}},
++     {{0xa84aa9397512218e, 0xe9a521b074ca0141, 0x57880b3a18a2e902,
++       0x4a5b506612a677a6},
++      {0x0beada7a4c4f3840, 0x626db15419e26d9d, 0xc42604fbe1627d40,
++       0xeb13461ceac089f1},
++      {1, 0, 0, 0}},
++     {{0xf9faed0927a43281, 0x5e52c4144103ecbc, 0xc342967aa815c857,
++       0x0781b8291c6a220a},
++      {0x5a8343ceeac55f80, 0x88f80eeee54a05e3, 0x97b2a14f12916434,
++       0x690cde8df0151593},
++      {1, 0, 0, 0}},
++     {{0xaee9c75df7f82f2a, 0x9e4c35874afdf43a, 0xf5622df437371326,
++       0x8a535f566ec73617},
++      {0xc5f9a0ac223094b7, 0xcde533864c8c7669, 0x37e02819085a92bf,
++       0x0455c08468b08bd7},
++      {1, 0, 0, 0}},
++     {{0x0c0a6e2c9477b5d9, 0xf9a4bf62876dc444, 0x5050a949b6cdc279,
++       0x06bada7ab77f8276},
++      {0xc8b4aed1ea48dac9, 0xdebd8a4b7ea1070f, 0x427d49101366eb70,
++       0x5b476dfd0e6cb18a},
++      {1, 0, 0, 0}},
++     {{0x7c5c3e44278c340a, 0x4d54606812d66f3b, 0x29a751b1ae23c5d8,
++       0x3e29864e8a2ec908},
++      {0x142d2a6626dbb850, 0xad1744c4765bd780, 0x1f150e68e322d1ed,
++       0x239b90ea3dc31e7e},
++      {1, 0, 0, 0}},
++     {{0x78c416527a53322a, 0x305dde6709776f8e, 0xdbcab759f8862ed4,
++       0x820f4dd949f72ff7},
++      {0x6cc544a62b5debd4, 0x75be5d937b4e8cc4, 0x1b481b1b215c14d3,
++       0x140406ec783a05ec},
++      {1, 0, 0, 0}},
++     {{0x6a703f10e895df07, 0xfd75f3fa01876bd8, 0xeb5b06e70ce08ffe,
++       0x68f6b8542783dfee},
++      {0x90c76f8a78712655, 0xcf5293d2f310bf7f, 0xfbc8044dfda45028,
++       0xcbe1feba92e40ce6},
++      {1, 0, 0, 0}},
++     {{0xe998ceea4396e4c1, 0xfc82ef0b6acea274, 0x230f729f2250e927,
++       0xd0b2f94d2f420109},
++      {0x4305adddb38d4966, 0x10b838f8624c3b45, 0x7db2636658954e7a,
++       0x971459828b0719e5},
++      {1, 0, 0, 0}},
++     {{0x4bd6b72623369fc9, 0x57f2929e53d0b876, 0xc2d5cba4f2340687,
++       0x961610004a866aba},
++      {0x49997bcd2e407a5e, 0x69ab197d92ddcb24, 0x2cf1f2438fe5131c,
++       0x7acb9fadcee75e44},
++      {1, 0, 0, 0}},
++     {{0x254e839423d2d4c0, 0xf57f0c917aea685b, 0xa60d880f6f75aaea,
++       0x24eb9acca333bf5b},
++      {0xe3de4ccb1cda5dea, 0xfeef9341c51a6b4f, 0x743125f88bac4c4d,
++       0x69f891c5acd079cc},
++      {1, 0, 0, 0}},
++     {{0xeee44b35702476b5, 0x7ed031a0e45c2258, 0xb422d1e7bd6f8514,
++       0xe51f547c5972a107},
++      {0xa25bcd6fc9cf343d, 0x8ca922ee097c184e, 0xa62f98b3a9fe9a06,
++       0x1c309a2b25bb1387},
++      {1, 0, 0, 0}},
++     {{0x9295dbeb1967c459, 0xb00148833472c98e, 0xc504977708011828,
++       0x20b87b8aa2c4e503},
++      {0x3063175de057c277, 0x1bd539338fe582dd, 0x0d11adef5f69a044,
++       0xf5c6fa49919776be},
++      {1, 0, 0, 0}},
++     {{0x8c944e760fd59e11, 0x3876cba1102fad5f, 0xa454c3fad83faa56,
++       0x1ed7d1b9332010b9},
++      {0xa1011a270024b889, 0x05e4d0dcac0cd344, 0x52b520f0eb6a2a24,
++       0x3a2b03f03217257a},
++      {1, 0, 0, 0}},
++     {{0xf20fc2afdf1d043d, 0xf330240db58d5a62, 0xfc7d229ca0058c3b,
++       0x15fee545c78dd9f6},
++      {0x501e82885bc98cda, 0x41ef80e5d046ac04, 0x557d9f49461210fb,
++       0x4ab5b6b2b8753f81},
++      {1, 0, 0, 0}}}
++};
++
++/*
++ * select_point selects the |idx|th point from a precomputation table and
++ * copies it to out.
++ */
++static void select_point(const u64 idx, unsigned int size,
++                         const smallfelem pre_comp[16][3], smallfelem out[3])
++{
++    unsigned i, j;
++    u64 *outlimbs = &out[0][0];
++
++    memset(out, 0, sizeof(*out) * 3);
++
++    for (i = 0; i < size; i++) {
++        const u64 *inlimbs = (u64 *)&pre_comp[i][0][0];
++        u64 mask = i ^ idx;
++        mask |= mask >> 4;
++        mask |= mask >> 2;
++        mask |= mask >> 1;
++        mask &= 1;
++        mask--;
++        for (j = 0; j < NLIMBS * 3; j++)
++            outlimbs[j] |= inlimbs[j] & mask;
++    }
++}
++
++/* get_bit returns the |i|th bit in |in| */
++static char get_bit(const felem_bytearray in, int i)
++{
++    if ((i < 0) || (i >= 256))
++        return 0;
++    return (in[i >> 3] >> (i & 7)) & 1;
++}
++
++/*
++ * Interleaved point multiplication using precomputed point multiples: The
++ * small point multiples 0*P, 1*P, ..., 17*P are in pre_comp[], the scalars
++ * in scalars[]. If g_scalar is non-NULL, we also add this multiple of the
++ * generator, using certain (large) precomputed multiples in g_pre_comp.
++ * Output point (X, Y, Z) is stored in x_out, y_out, z_out
++ */
++static void batch_mul(felem x_out, felem y_out, felem z_out,
++                      const felem_bytearray scalars[],
++                      const unsigned num_points, const u8 *g_scalar,
++                      const int mixed, const smallfelem pre_comp[][17][3],
++                      const smallfelem g_pre_comp[2][16][3])
++{
++    int i, skip;
++    unsigned num, gen_mul = (g_scalar != NULL);
++    felem nq[3], ftmp;
++    smallfelem tmp[3];
++    u64 bits;
++    u8 sign, digit;
++
++    /* set nq to the point at infinity */
++    memset(nq, 0, sizeof(nq));
++
++    /*
++     * Loop over all scalars msb-to-lsb, interleaving additions of multiples
++     * of the generator (two in each of the last 32 rounds) and additions of
++     * other points multiples (every 5th round).
++     */
++    skip = 1;                   /* save two point operations in the first
++                                 * round */
++    for (i = (num_points ? 255 : 31); i >= 0; --i) {
++        /* double */
++        if (!skip)
++            point_double(nq[0], nq[1], nq[2], nq[0], nq[1], nq[2]);
++
++        /* add multiples of the generator */
++        if (gen_mul && (i <= 31)) {
++            /* first, look 32 bits upwards */
++            bits = get_bit(g_scalar, i + 224) << 3;
++            bits |= get_bit(g_scalar, i + 160) << 2;
++            bits |= get_bit(g_scalar, i + 96) << 1;
++            bits |= get_bit(g_scalar, i + 32);
++            /* select the point to add, in constant time */
++            select_point(bits, 16, g_pre_comp[1], tmp);
++
++            if (!skip) {
++                /* Arg 1 below is for "mixed" */
++                point_add(nq[0], nq[1], nq[2],
++                          nq[0], nq[1], nq[2], 1, tmp[0], tmp[1], tmp[2]);
++            } else {
++                smallfelem_expand(nq[0], tmp[0]);
++                smallfelem_expand(nq[1], tmp[1]);
++                smallfelem_expand(nq[2], tmp[2]);
++                skip = 0;
++            }
++
++            /* second, look at the current position */
++            bits = get_bit(g_scalar, i + 192) << 3;
++            bits |= get_bit(g_scalar, i + 128) << 2;
++            bits |= get_bit(g_scalar, i + 64) << 1;
++            bits |= get_bit(g_scalar, i);
++            /* select the point to add, in constant time */
++            select_point(bits, 16, g_pre_comp[0], tmp);
++            /* Arg 1 below is for "mixed" */
++            point_add(nq[0], nq[1], nq[2],
++                      nq[0], nq[1], nq[2], 1, tmp[0], tmp[1], tmp[2]);
++        }
++
++        /* do other additions every 5 doublings */
++        if (num_points && (i % 5 == 0)) {
++            /* loop over all scalars */
++            for (num = 0; num < num_points; ++num) {
++                bits = get_bit(scalars[num], i + 4) << 5;
++                bits |= get_bit(scalars[num], i + 3) << 4;
++                bits |= get_bit(scalars[num], i + 2) << 3;
++                bits |= get_bit(scalars[num], i + 1) << 2;
++                bits |= get_bit(scalars[num], i) << 1;
++                bits |= get_bit(scalars[num], i - 1);
++                ec_GFp_nistp_recode_scalar_bits(&sign, &digit, bits);
++
++                /*
++                 * select the point to add or subtract, in constant time
++                 */
++                select_point(digit, 17, pre_comp[num], tmp);
++                smallfelem_neg(ftmp, tmp[1]); /* (X, -Y, Z) is the negative
++                                               * point */
++                copy_small_conditional(ftmp, tmp[1], (((limb) sign) - 1));
++                felem_contract(tmp[1], ftmp);
++
++                if (!skip) {
++                    point_add(nq[0], nq[1], nq[2],
++                              nq[0], nq[1], nq[2],
++                              mixed, tmp[0], tmp[1], tmp[2]);
++                } else {
++                    smallfelem_expand(nq[0], tmp[0]);
++                    smallfelem_expand(nq[1], tmp[1]);
++                    smallfelem_expand(nq[2], tmp[2]);
++                    skip = 0;
++                }
++            }
++        }
++    }
++    felem_assign(x_out, nq[0]);
++    felem_assign(y_out, nq[1]);
++    felem_assign(z_out, nq[2]);
++}
++
++/* Precomputation for the group generator. */
++struct nistp256_pre_comp_st {
++    smallfelem g_pre_comp[2][16][3];
++    int references;
++    CRYPTO_RWLOCK *lock;
++};
++
++const EC_METHOD *EC_GFp_nistp256_method(void)
++{
++    static const EC_METHOD ret = {
++        EC_FLAGS_DEFAULT_OCT,
++        NID_X9_62_prime_field,
++        ec_GFp_nistp256_group_init,
++        ec_GFp_simple_group_finish,
++        ec_GFp_simple_group_clear_finish,
++        ec_GFp_nist_group_copy,
++        ec_GFp_nistp256_group_set_curve,
++        ec_GFp_simple_group_get_curve,
++        ec_GFp_simple_group_get_degree,
++        ec_group_simple_order_bits,
++        ec_GFp_simple_group_check_discriminant,
++        ec_GFp_simple_point_init,
++        ec_GFp_simple_point_finish,
++        ec_GFp_simple_point_clear_finish,
++        ec_GFp_simple_point_copy,
++        ec_GFp_simple_point_set_to_infinity,
++        ec_GFp_simple_set_Jprojective_coordinates_GFp,
++        ec_GFp_simple_get_Jprojective_coordinates_GFp,
++        ec_GFp_simple_point_set_affine_coordinates,
++        ec_GFp_nistp256_point_get_affine_coordinates,
++        0 /* point_set_compressed_coordinates */ ,
++        0 /* point2oct */ ,
++        0 /* oct2point */ ,
++        ec_GFp_simple_add,
++        ec_GFp_simple_dbl,
++        ec_GFp_simple_invert,
++        ec_GFp_simple_is_at_infinity,
++        ec_GFp_simple_is_on_curve,
++        ec_GFp_simple_cmp,
++        ec_GFp_simple_make_affine,
++        ec_GFp_simple_points_make_affine,
++        ec_GFp_nistp256_points_mul,
++        ec_GFp_nistp256_precompute_mult,
++        ec_GFp_nistp256_have_precompute_mult,
++        ec_GFp_nist_field_mul,
++        ec_GFp_nist_field_sqr,
++        0 /* field_div */ ,
++        0 /* field_encode */ ,
++        0 /* field_decode */ ,
++        0,                      /* field_set_to_one */
++        ec_key_simple_priv2oct,
++        ec_key_simple_oct2priv,
++        0, /* set private */
++        ec_key_simple_generate_key,
++        ec_key_simple_check_key,
++        ec_key_simple_generate_public_key,
++        0, /* keycopy */
++        0, /* keyfinish */
++        ecdh_simple_compute_key
++    };
++
++    return &ret;
++}
++
++/******************************************************************************/
++/*
++ * FUNCTIONS TO MANAGE PRECOMPUTATION
++ */
++
++static NISTP256_PRE_COMP *nistp256_pre_comp_new()
++{
++    NISTP256_PRE_COMP *ret = OPENSSL_zalloc(sizeof(*ret));
++
++    if (ret == NULL) {
++        ECerr(EC_F_NISTP256_PRE_COMP_NEW, ERR_R_MALLOC_FAILURE);
++        return ret;
++    }
++
++    ret->references = 1;
++
++    ret->lock = CRYPTO_THREAD_lock_new();
++    if (ret->lock == NULL) {
++        ECerr(EC_F_NISTP256_PRE_COMP_NEW, ERR_R_MALLOC_FAILURE);
++        OPENSSL_free(ret);
++        return NULL;
++    }
++    return ret;
++}
++
++NISTP256_PRE_COMP *EC_nistp256_pre_comp_dup(NISTP256_PRE_COMP *p)
++{
++    int i;
++    if (p != NULL)
++        CRYPTO_atomic_add(&p->references, 1, &i, p->lock);
++    return p;
++}
++
++void EC_nistp256_pre_comp_free(NISTP256_PRE_COMP *pre)
++{
++    int i;
++
++    if (pre == NULL)
++        return;
++
++    CRYPTO_atomic_add(&pre->references, -1, &i, pre->lock);
++    REF_PRINT_COUNT("EC_nistp256", x);
++    if (i > 0)
++        return;
++    REF_ASSERT_ISNT(i < 0);
++
++    CRYPTO_THREAD_lock_free(pre->lock);
++    OPENSSL_free(pre);
++}
++
++/******************************************************************************/
++/*
++ * OPENSSL EC_METHOD FUNCTIONS
++ */
++
++int ec_GFp_nistp256_group_init(EC_GROUP *group)
++{
++    int ret;
++    ret = ec_GFp_simple_group_init(group);
++    group->a_is_minus3 = 1;
++    return ret;
++}
++
++int ec_GFp_nistp256_group_set_curve(EC_GROUP *group, const BIGNUM *p,
++                                    const BIGNUM *a, const BIGNUM *b,
++                                    BN_CTX *ctx)
++{
++    int ret = 0;
++    BN_CTX *new_ctx = NULL;
++    BIGNUM *curve_p, *curve_a, *curve_b;
++
++    if (ctx == NULL)
++        if ((ctx = new_ctx = BN_CTX_new()) == NULL)
++            return 0;
++    BN_CTX_start(ctx);
++    if (((curve_p = BN_CTX_get(ctx)) == NULL) ||
++        ((curve_a = BN_CTX_get(ctx)) == NULL) ||
++        ((curve_b = BN_CTX_get(ctx)) == NULL))
++        goto err;
++    BN_bin2bn(nistp256_curve_params[0], sizeof(felem_bytearray), curve_p);
++    BN_bin2bn(nistp256_curve_params[1], sizeof(felem_bytearray), curve_a);
++    BN_bin2bn(nistp256_curve_params[2], sizeof(felem_bytearray), curve_b);
++    if ((BN_cmp(curve_p, p)) || (BN_cmp(curve_a, a)) || (BN_cmp(curve_b, b))) {
++        ECerr(EC_F_EC_GFP_NISTP256_GROUP_SET_CURVE,
++              EC_R_WRONG_CURVE_PARAMETERS);
++        goto err;
++    }
++    group->field_mod_func = BN_nist_mod_256;
++    ret = ec_GFp_simple_group_set_curve(group, p, a, b, ctx);
++ err:
++    BN_CTX_end(ctx);
++    BN_CTX_free(new_ctx);
++    return ret;
++}
++
++/*
++ * Takes the Jacobian coordinates (X, Y, Z) of a point and returns (X', Y') =
++ * (X/Z^2, Y/Z^3)
++ */
++int ec_GFp_nistp256_point_get_affine_coordinates(const EC_GROUP *group,
++                                                 const EC_POINT *point,
++                                                 BIGNUM *x, BIGNUM *y,
++                                                 BN_CTX *ctx)
++{
++    felem z1, z2, x_in, y_in;
++    smallfelem x_out, y_out;
++    longfelem tmp;
++
++    if (EC_POINT_is_at_infinity(group, point)) {
++        ECerr(EC_F_EC_GFP_NISTP256_POINT_GET_AFFINE_COORDINATES,
++              EC_R_POINT_AT_INFINITY);
++        return 0;
++    }
++    if ((!BN_to_felem(x_in, point->X)) || (!BN_to_felem(y_in, point->Y)) ||
++        (!BN_to_felem(z1, point->Z)))
++        return 0;
++    felem_inv(z2, z1);
++    felem_square(tmp, z2);
++    felem_reduce(z1, tmp);
++    felem_mul(tmp, x_in, z1);
++    felem_reduce(x_in, tmp);
++    felem_contract(x_out, x_in);
++    if (x != NULL) {
++        if (!smallfelem_to_BN(x, x_out)) {
++            ECerr(EC_F_EC_GFP_NISTP256_POINT_GET_AFFINE_COORDINATES,
++                  ERR_R_BN_LIB);
++            return 0;
++        }
++    }
++    felem_mul(tmp, z1, z2);
++    felem_reduce(z1, tmp);
++    felem_mul(tmp, y_in, z1);
++    felem_reduce(y_in, tmp);
++    felem_contract(y_out, y_in);
++    if (y != NULL) {
++        if (!smallfelem_to_BN(y, y_out)) {
++            ECerr(EC_F_EC_GFP_NISTP256_POINT_GET_AFFINE_COORDINATES,
++                  ERR_R_BN_LIB);
++            return 0;
++        }
++    }
++    return 1;
++}
++
++/* points below is of size |num|, and tmp_smallfelems is of size |num+1| */
++static void make_points_affine(size_t num, smallfelem points[][3],
++                               smallfelem tmp_smallfelems[])
++{
++    /*
++     * Runs in constant time, unless an input is the point at infinity (which
++     * normally shouldn't happen).
++     */
++    ec_GFp_nistp_points_make_affine_internal(num,
++                                             points,
++                                             sizeof(smallfelem),
++                                             tmp_smallfelems,
++                                             (void (*)(void *))smallfelem_one,
++                                             (int (*)(const void *))
++                                             smallfelem_is_zero_int,
++                                             (void (*)(void *, const void *))
++                                             smallfelem_assign,
++                                             (void (*)(void *, const void *))
++                                             smallfelem_square_contract,
++                                             (void (*)
++                                              (void *, const void *,
++                                               const void *))
++                                             smallfelem_mul_contract,
++                                             (void (*)(void *, const void *))
++                                             smallfelem_inv_contract,
++                                             /* nothing to contract */
++                                             (void (*)(void *, const void *))
++                                             smallfelem_assign);
++}
++
++/*
++ * Computes scalar*generator + \sum scalars[i]*points[i], ignoring NULL
++ * values Result is stored in r (r can equal one of the inputs).
++ */
++int ec_GFp_nistp256_points_mul(const EC_GROUP *group, EC_POINT *r,
++                               const BIGNUM *scalar, size_t num,
++                               const EC_POINT *points[],
++                               const BIGNUM *scalars[], BN_CTX *ctx)
++{
++    int ret = 0;
++    int j;
++    int mixed = 0;
++    BN_CTX *new_ctx = NULL;
++    BIGNUM *x, *y, *z, *tmp_scalar;
++    felem_bytearray g_secret;
++    felem_bytearray *secrets = NULL;
++    smallfelem (*pre_comp)[17][3] = NULL;
++    smallfelem *tmp_smallfelems = NULL;
++    felem_bytearray tmp;
++    unsigned i, num_bytes;
++    int have_pre_comp = 0;
++    size_t num_points = num;
++    smallfelem x_in, y_in, z_in;
++    felem x_out, y_out, z_out;
++    NISTP256_PRE_COMP *pre = NULL;
++    const smallfelem(*g_pre_comp)[16][3] = NULL;
++    EC_POINT *generator = NULL;
++    const EC_POINT *p = NULL;
++    const BIGNUM *p_scalar = NULL;
++
++    if (ctx == NULL)
++        if ((ctx = new_ctx = BN_CTX_new()) == NULL)
++            return 0;
++    BN_CTX_start(ctx);
++    if (((x = BN_CTX_get(ctx)) == NULL) ||
++        ((y = BN_CTX_get(ctx)) == NULL) ||
++        ((z = BN_CTX_get(ctx)) == NULL) ||
++        ((tmp_scalar = BN_CTX_get(ctx)) == NULL))
++        goto err;
++
++    if (scalar != NULL) {
++        pre = group->pre_comp.nistp256;
++        if (pre)
++            /* we have precomputation, try to use it */
++            g_pre_comp = (const smallfelem(*)[16][3])pre->g_pre_comp;
++        else
++            /* try to use the standard precomputation */
++            g_pre_comp = &gmul[0];
++        generator = EC_POINT_new(group);
++        if (generator == NULL)
++            goto err;
++        /* get the generator from precomputation */
++        if (!smallfelem_to_BN(x, g_pre_comp[0][1][0]) ||
++            !smallfelem_to_BN(y, g_pre_comp[0][1][1]) ||
++            !smallfelem_to_BN(z, g_pre_comp[0][1][2])) {
++            ECerr(EC_F_EC_GFP_NISTP256_POINTS_MUL, ERR_R_BN_LIB);
++            goto err;
++        }
++        if (!EC_POINT_set_Jprojective_coordinates_GFp(group,
++                                                      generator, x, y, z,
++                                                      ctx))
++            goto err;
++        if (0 == EC_POINT_cmp(group, generator, group->generator, ctx))
++            /* precomputation matches generator */
++            have_pre_comp = 1;
++        else
++            /*
++             * we don't have valid precomputation: treat the generator as a
++             * random point
++             */
++            num_points++;
++    }
++    if (num_points > 0) {
++        if (num_points >= 3) {
++            /*
++             * unless we precompute multiples for just one or two points,
++             * converting those into affine form is time well spent
++             */
++            mixed = 1;
++        }
++        secrets = OPENSSL_malloc(sizeof(*secrets) * num_points);
++        pre_comp = OPENSSL_malloc(sizeof(*pre_comp) * num_points);
++        if (mixed)
++            tmp_smallfelems =
++              OPENSSL_malloc(sizeof(*tmp_smallfelems) * (num_points * 17 + 1));
++        if ((secrets == NULL) || (pre_comp == NULL)
++            || (mixed && (tmp_smallfelems == NULL))) {
++            ECerr(EC_F_EC_GFP_NISTP256_POINTS_MUL, ERR_R_MALLOC_FAILURE);
++            goto err;
++        }
++
++        /*
++         * we treat NULL scalars as 0, and NULL points as points at infinity,
++         * i.e., they contribute nothing to the linear combination
++         */
++        memset(secrets, 0, sizeof(*secrets) * num_points);
++        memset(pre_comp, 0, sizeof(*pre_comp) * num_points);
++        for (i = 0; i < num_points; ++i) {
++            if (i == num)
++                /*
++                 * we didn't have a valid precomputation, so we pick the
++                 * generator
++                 */
++            {
++                p = EC_GROUP_get0_generator(group);
++                p_scalar = scalar;
++            } else
++                /* the i^th point */
++            {
++                p = points[i];
++                p_scalar = scalars[i];
++            }
++            if ((p_scalar != NULL) && (p != NULL)) {
++                /* reduce scalar to 0 <= scalar < 2^256 */
++                if ((BN_num_bits(p_scalar) > 256)
++                    || (BN_is_negative(p_scalar))) {
++                    /*
++                     * this is an unusual input, and we don't guarantee
++                     * constant-timeness
++                     */
++                    if (!BN_nnmod(tmp_scalar, p_scalar, group->order, ctx)) {
++                        ECerr(EC_F_EC_GFP_NISTP256_POINTS_MUL, ERR_R_BN_LIB);
++                        goto err;
++                    }
++                    num_bytes = BN_bn2bin(tmp_scalar, tmp);
++                } else
++                    num_bytes = BN_bn2bin(p_scalar, tmp);
++                flip_endian(secrets[i], tmp, num_bytes);
++                /* precompute multiples */
++                if ((!BN_to_felem(x_out, p->X)) ||
++                    (!BN_to_felem(y_out, p->Y)) ||
++                    (!BN_to_felem(z_out, p->Z)))
++                    goto err;
++                felem_shrink(pre_comp[i][1][0], x_out);
++                felem_shrink(pre_comp[i][1][1], y_out);
++                felem_shrink(pre_comp[i][1][2], z_out);
++                for (j = 2; j <= 16; ++j) {
++                    if (j & 1) {
++                        point_add_small(pre_comp[i][j][0], pre_comp[i][j][1],
++                                        pre_comp[i][j][2], pre_comp[i][1][0],
++                                        pre_comp[i][1][1], pre_comp[i][1][2],
++                                        pre_comp[i][j - 1][0],
++                                        pre_comp[i][j - 1][1],
++                                        pre_comp[i][j - 1][2]);
++                    } else {
++                        point_double_small(pre_comp[i][j][0],
++                                           pre_comp[i][j][1],
++                                           pre_comp[i][j][2],
++                                           pre_comp[i][j / 2][0],
++                                           pre_comp[i][j / 2][1],
++                                           pre_comp[i][j / 2][2]);
++                    }
++                }
++            }
++        }
++        if (mixed)
++            make_points_affine(num_points * 17, pre_comp[0], tmp_smallfelems);
++    }
++
++    /* the scalar for the generator */
++    if ((scalar != NULL) && (have_pre_comp)) {
++        memset(g_secret, 0, sizeof(g_secret));
++        /* reduce scalar to 0 <= scalar < 2^256 */
++        if ((BN_num_bits(scalar) > 256) || (BN_is_negative(scalar))) {
++            /*
++             * this is an unusual input, and we don't guarantee
++             * constant-timeness
++             */
++            if (!BN_nnmod(tmp_scalar, scalar, group->order, ctx)) {
++                ECerr(EC_F_EC_GFP_NISTP256_POINTS_MUL, ERR_R_BN_LIB);
++                goto err;
++            }
++            num_bytes = BN_bn2bin(tmp_scalar, tmp);
++        } else
++            num_bytes = BN_bn2bin(scalar, tmp);
++        flip_endian(g_secret, tmp, num_bytes);
++        /* do the multiplication with generator precomputation */
++        batch_mul(x_out, y_out, z_out,
++                  (const felem_bytearray(*))secrets, num_points,
++                  g_secret,
++                  mixed, (const smallfelem(*)[17][3])pre_comp, g_pre_comp);
++    } else
++        /* do the multiplication without generator precomputation */
++        batch_mul(x_out, y_out, z_out,
++                  (const felem_bytearray(*))secrets, num_points,
++                  NULL, mixed, (const smallfelem(*)[17][3])pre_comp, NULL);
++    /* reduce the output to its unique minimal representation */
++    felem_contract(x_in, x_out);
++    felem_contract(y_in, y_out);
++    felem_contract(z_in, z_out);
++    if ((!smallfelem_to_BN(x, x_in)) || (!smallfelem_to_BN(y, y_in)) ||
++        (!smallfelem_to_BN(z, z_in))) {
++        ECerr(EC_F_EC_GFP_NISTP256_POINTS_MUL, ERR_R_BN_LIB);
++        goto err;
++    }
++    ret = EC_POINT_set_Jprojective_coordinates_GFp(group, r, x, y, z, ctx);
++
++ err:
++    BN_CTX_end(ctx);
++    EC_POINT_free(generator);
++    BN_CTX_free(new_ctx);
++    OPENSSL_free(secrets);
++    OPENSSL_free(pre_comp);
++    OPENSSL_free(tmp_smallfelems);
++    return ret;
++}
++
++int ec_GFp_nistp256_precompute_mult(EC_GROUP *group, BN_CTX *ctx)
++{
++    int ret = 0;
++    NISTP256_PRE_COMP *pre = NULL;
++    int i, j;
++    BN_CTX *new_ctx = NULL;
++    BIGNUM *x, *y;
++    EC_POINT *generator = NULL;
++    smallfelem tmp_smallfelems[32];
++    felem x_tmp, y_tmp, z_tmp;
++
++    /* throw away old precomputation */
++    EC_pre_comp_free(group);
++    if (ctx == NULL)
++        if ((ctx = new_ctx = BN_CTX_new()) == NULL)
++            return 0;
++    BN_CTX_start(ctx);
++    if (((x = BN_CTX_get(ctx)) == NULL) || ((y = BN_CTX_get(ctx)) == NULL))
++        goto err;
++    /* get the generator */
++    if (group->generator == NULL)
++        goto err;
++    generator = EC_POINT_new(group);
++    if (generator == NULL)
++        goto err;
++    BN_bin2bn(nistp256_curve_params[3], sizeof(felem_bytearray), x);
++    BN_bin2bn(nistp256_curve_params[4], sizeof(felem_bytearray), y);
++    if (!EC_POINT_set_affine_coordinates_GFp(group, generator, x, y, ctx))
++        goto err;
++    if ((pre = nistp256_pre_comp_new()) == NULL)
++        goto err;
++    /*
++     * if the generator is the standard one, use built-in precomputation
++     */
++    if (0 == EC_POINT_cmp(group, generator, group->generator, ctx)) {
++        memcpy(pre->g_pre_comp, gmul, sizeof(pre->g_pre_comp));
++        goto done;
++    }
++    if ((!BN_to_felem(x_tmp, group->generator->X)) ||
++        (!BN_to_felem(y_tmp, group->generator->Y)) ||
++        (!BN_to_felem(z_tmp, group->generator->Z)))
++        goto err;
++    felem_shrink(pre->g_pre_comp[0][1][0], x_tmp);
++    felem_shrink(pre->g_pre_comp[0][1][1], y_tmp);
++    felem_shrink(pre->g_pre_comp[0][1][2], z_tmp);
++    /*
++     * compute 2^64*G, 2^128*G, 2^192*G for the first table, 2^32*G, 2^96*G,
++     * 2^160*G, 2^224*G for the second one
++     */
++    for (i = 1; i <= 8; i <<= 1) {
++        point_double_small(pre->g_pre_comp[1][i][0], pre->g_pre_comp[1][i][1],
++                           pre->g_pre_comp[1][i][2], pre->g_pre_comp[0][i][0],
++                           pre->g_pre_comp[0][i][1],
++                           pre->g_pre_comp[0][i][2]);
++        for (j = 0; j < 31; ++j) {
++            point_double_small(pre->g_pre_comp[1][i][0],
++                               pre->g_pre_comp[1][i][1],
++                               pre->g_pre_comp[1][i][2],
++                               pre->g_pre_comp[1][i][0],
++                               pre->g_pre_comp[1][i][1],
++                               pre->g_pre_comp[1][i][2]);
++        }
++        if (i == 8)
++            break;
++        point_double_small(pre->g_pre_comp[0][2 * i][0],
++                           pre->g_pre_comp[0][2 * i][1],
++                           pre->g_pre_comp[0][2 * i][2],
++                           pre->g_pre_comp[1][i][0], pre->g_pre_comp[1][i][1],
++                           pre->g_pre_comp[1][i][2]);
++        for (j = 0; j < 31; ++j) {
++            point_double_small(pre->g_pre_comp[0][2 * i][0],
++                               pre->g_pre_comp[0][2 * i][1],
++                               pre->g_pre_comp[0][2 * i][2],
++                               pre->g_pre_comp[0][2 * i][0],
++                               pre->g_pre_comp[0][2 * i][1],
++                               pre->g_pre_comp[0][2 * i][2]);
++        }
++    }
++    for (i = 0; i < 2; i++) {
++        /* g_pre_comp[i][0] is the point at infinity */
++        memset(pre->g_pre_comp[i][0], 0, sizeof(pre->g_pre_comp[i][0]));
++        /* the remaining multiples */
++        /* 2^64*G + 2^128*G resp. 2^96*G + 2^160*G */
++        point_add_small(pre->g_pre_comp[i][6][0], pre->g_pre_comp[i][6][1],
++                        pre->g_pre_comp[i][6][2], pre->g_pre_comp[i][4][0],
++                        pre->g_pre_comp[i][4][1], pre->g_pre_comp[i][4][2],
++                        pre->g_pre_comp[i][2][0], pre->g_pre_comp[i][2][1],
++                        pre->g_pre_comp[i][2][2]);
++        /* 2^64*G + 2^192*G resp. 2^96*G + 2^224*G */
++        point_add_small(pre->g_pre_comp[i][10][0], pre->g_pre_comp[i][10][1],
++                        pre->g_pre_comp[i][10][2], pre->g_pre_comp[i][8][0],
++                        pre->g_pre_comp[i][8][1], pre->g_pre_comp[i][8][2],
++                        pre->g_pre_comp[i][2][0], pre->g_pre_comp[i][2][1],
++                        pre->g_pre_comp[i][2][2]);
++        /* 2^128*G + 2^192*G resp. 2^160*G + 2^224*G */
++        point_add_small(pre->g_pre_comp[i][12][0], pre->g_pre_comp[i][12][1],
++                        pre->g_pre_comp[i][12][2], pre->g_pre_comp[i][8][0],
++                        pre->g_pre_comp[i][8][1], pre->g_pre_comp[i][8][2],
++                        pre->g_pre_comp[i][4][0], pre->g_pre_comp[i][4][1],
++                        pre->g_pre_comp[i][4][2]);
++        /*
++         * 2^64*G + 2^128*G + 2^192*G resp. 2^96*G + 2^160*G + 2^224*G
++         */
++        point_add_small(pre->g_pre_comp[i][14][0], pre->g_pre_comp[i][14][1],
++                        pre->g_pre_comp[i][14][2], pre->g_pre_comp[i][12][0],
++                        pre->g_pre_comp[i][12][1], pre->g_pre_comp[i][12][2],
++                        pre->g_pre_comp[i][2][0], pre->g_pre_comp[i][2][1],
++                        pre->g_pre_comp[i][2][2]);
++        for (j = 1; j < 8; ++j) {
++            /* odd multiples: add G resp. 2^32*G */
++            point_add_small(pre->g_pre_comp[i][2 * j + 1][0],
++                            pre->g_pre_comp[i][2 * j + 1][1],
++                            pre->g_pre_comp[i][2 * j + 1][2],
++                            pre->g_pre_comp[i][2 * j][0],
++                            pre->g_pre_comp[i][2 * j][1],
++                            pre->g_pre_comp[i][2 * j][2],
++                            pre->g_pre_comp[i][1][0],
++                            pre->g_pre_comp[i][1][1],
++                            pre->g_pre_comp[i][1][2]);
++        }
++    }
++    make_points_affine(31, &(pre->g_pre_comp[0][1]), tmp_smallfelems);
++
++ done:
++    SETPRECOMP(group, nistp256, pre);
++    pre = NULL;
++    ret = 1;
++
++ err:
++    BN_CTX_end(ctx);
++    EC_POINT_free(generator);
++    BN_CTX_free(new_ctx);
++    EC_nistp256_pre_comp_free(pre);
++    return ret;
++}
++
++int ec_GFp_nistp256_have_precompute_mult(const EC_GROUP *group)
++{
++    return HAVEPRECOMP(group, nistp256);
++}
++#endif
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/ec/ecp_nistp521.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/ec/ecp_nistp521.c
+new file mode 100644
+index 0000000..7207494
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/ec/ecp_nistp521.c
+@@ -0,0 +1,2146 @@
++/*
++ * Copyright 2011-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++/* Copyright 2011 Google Inc.
++ *
++ * Licensed under the Apache License, Version 2.0 (the "License");
++ *
++ * you may not use this file except in compliance with the License.
++ * You may obtain a copy of the License at
++ *
++ *     http://www.apache.org/licenses/LICENSE-2.0
++ *
++ *  Unless required by applicable law or agreed to in writing, software
++ *  distributed under the License is distributed on an "AS IS" BASIS,
++ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ *  See the License for the specific language governing permissions and
++ *  limitations under the License.
++ */
++
++/*
++ * A 64-bit implementation of the NIST P-521 elliptic curve point multiplication
++ *
++ * OpenSSL integration was taken from Emilia Kasper's work in ecp_nistp224.c.
++ * Otherwise based on Emilia's P224 work, which was inspired by my curve25519
++ * work which got its smarts from Daniel J. Bernstein's work on the same.
++ */
++
++#include 
++#ifdef OPENSSL_NO_EC_NISTP_64_GCC_128
++NON_EMPTY_TRANSLATION_UNIT
++#else
++
++# ifndef OPENSSL_SYS_VMS
++#  include 
++# else
++#  include 
++# endif
++
++# include 
++# include 
++# include "ec_lcl.h"
++
++# if defined(__GNUC__) && (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 1))
++  /* even with gcc, the typedef won't work for 32-bit platforms */
++typedef __uint128_t uint128_t;  /* nonstandard; implemented by gcc on 64-bit
++                                 * platforms */
++# else
++#  error "Need GCC 3.1 or later to define type uint128_t"
++# endif
++
++typedef uint8_t u8;
++typedef uint64_t u64;
++typedef int64_t s64;
++
++/*
++ * The underlying field. P521 operates over GF(2^521-1). We can serialise an
++ * element of this field into 66 bytes where the most significant byte
++ * contains only a single bit. We call this an felem_bytearray.
++ */
++
++typedef u8 felem_bytearray[66];
++
++/*
++ * These are the parameters of P521, taken from FIPS 186-3, section D.1.2.5.
++ * These values are big-endian.
++ */
++static const felem_bytearray nistp521_curve_params[5] = {
++    {0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* p */
++     0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++     0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++     0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++     0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++     0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++     0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++     0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++     0xff, 0xff},
++    {0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* a = -3 */
++     0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++     0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++     0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++     0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++     0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++     0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++     0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++     0xff, 0xfc},
++    {0x00, 0x51, 0x95, 0x3e, 0xb9, 0x61, 0x8e, 0x1c, /* b */
++     0x9a, 0x1f, 0x92, 0x9a, 0x21, 0xa0, 0xb6, 0x85,
++     0x40, 0xee, 0xa2, 0xda, 0x72, 0x5b, 0x99, 0xb3,
++     0x15, 0xf3, 0xb8, 0xb4, 0x89, 0x91, 0x8e, 0xf1,
++     0x09, 0xe1, 0x56, 0x19, 0x39, 0x51, 0xec, 0x7e,
++     0x93, 0x7b, 0x16, 0x52, 0xc0, 0xbd, 0x3b, 0xb1,
++     0xbf, 0x07, 0x35, 0x73, 0xdf, 0x88, 0x3d, 0x2c,
++     0x34, 0xf1, 0xef, 0x45, 0x1f, 0xd4, 0x6b, 0x50,
++     0x3f, 0x00},
++    {0x00, 0xc6, 0x85, 0x8e, 0x06, 0xb7, 0x04, 0x04, /* x */
++     0xe9, 0xcd, 0x9e, 0x3e, 0xcb, 0x66, 0x23, 0x95,
++     0xb4, 0x42, 0x9c, 0x64, 0x81, 0x39, 0x05, 0x3f,
++     0xb5, 0x21, 0xf8, 0x28, 0xaf, 0x60, 0x6b, 0x4d,
++     0x3d, 0xba, 0xa1, 0x4b, 0x5e, 0x77, 0xef, 0xe7,
++     0x59, 0x28, 0xfe, 0x1d, 0xc1, 0x27, 0xa2, 0xff,
++     0xa8, 0xde, 0x33, 0x48, 0xb3, 0xc1, 0x85, 0x6a,
++     0x42, 0x9b, 0xf9, 0x7e, 0x7e, 0x31, 0xc2, 0xe5,
++     0xbd, 0x66},
++    {0x01, 0x18, 0x39, 0x29, 0x6a, 0x78, 0x9a, 0x3b, /* y */
++     0xc0, 0x04, 0x5c, 0x8a, 0x5f, 0xb4, 0x2c, 0x7d,
++     0x1b, 0xd9, 0x98, 0xf5, 0x44, 0x49, 0x57, 0x9b,
++     0x44, 0x68, 0x17, 0xaf, 0xbd, 0x17, 0x27, 0x3e,
++     0x66, 0x2c, 0x97, 0xee, 0x72, 0x99, 0x5e, 0xf4,
++     0x26, 0x40, 0xc5, 0x50, 0xb9, 0x01, 0x3f, 0xad,
++     0x07, 0x61, 0x35, 0x3c, 0x70, 0x86, 0xa2, 0x72,
++     0xc2, 0x40, 0x88, 0xbe, 0x94, 0x76, 0x9f, 0xd1,
++     0x66, 0x50}
++};
++
++/*-
++ * The representation of field elements.
++ * ------------------------------------
++ *
++ * We represent field elements with nine values. These values are either 64 or
++ * 128 bits and the field element represented is:
++ *   v[0]*2^0 + v[1]*2^58 + v[2]*2^116 + ... + v[8]*2^464  (mod p)
++ * Each of the nine values is called a 'limb'. Since the limbs are spaced only
++ * 58 bits apart, but are greater than 58 bits in length, the most significant
++ * bits of each limb overlap with the least significant bits of the next.
++ *
++ * A field element with 64-bit limbs is an 'felem'. One with 128-bit limbs is a
++ * 'largefelem' */
++
++# define NLIMBS 9
++
++typedef uint64_t limb;
++typedef limb felem[NLIMBS];
++typedef uint128_t largefelem[NLIMBS];
++
++static const limb bottom57bits = 0x1ffffffffffffff;
++static const limb bottom58bits = 0x3ffffffffffffff;
++
++/*
++ * bin66_to_felem takes a little-endian byte array and converts it into felem
++ * form. This assumes that the CPU is little-endian.
++ */
++static void bin66_to_felem(felem out, const u8 in[66])
++{
++    out[0] = (*((limb *) & in[0])) & bottom58bits;
++    out[1] = (*((limb *) & in[7]) >> 2) & bottom58bits;
++    out[2] = (*((limb *) & in[14]) >> 4) & bottom58bits;
++    out[3] = (*((limb *) & in[21]) >> 6) & bottom58bits;
++    out[4] = (*((limb *) & in[29])) & bottom58bits;
++    out[5] = (*((limb *) & in[36]) >> 2) & bottom58bits;
++    out[6] = (*((limb *) & in[43]) >> 4) & bottom58bits;
++    out[7] = (*((limb *) & in[50]) >> 6) & bottom58bits;
++    out[8] = (*((limb *) & in[58])) & bottom57bits;
++}
++
++/*
++ * felem_to_bin66 takes an felem and serialises into a little endian, 66 byte
++ * array. This assumes that the CPU is little-endian.
++ */
++static void felem_to_bin66(u8 out[66], const felem in)
++{
++    memset(out, 0, 66);
++    (*((limb *) & out[0])) = in[0];
++    (*((limb *) & out[7])) |= in[1] << 2;
++    (*((limb *) & out[14])) |= in[2] << 4;
++    (*((limb *) & out[21])) |= in[3] << 6;
++    (*((limb *) & out[29])) = in[4];
++    (*((limb *) & out[36])) |= in[5] << 2;
++    (*((limb *) & out[43])) |= in[6] << 4;
++    (*((limb *) & out[50])) |= in[7] << 6;
++    (*((limb *) & out[58])) = in[8];
++}
++
++/* To preserve endianness when using BN_bn2bin and BN_bin2bn */
++static void flip_endian(u8 *out, const u8 *in, unsigned len)
++{
++    unsigned i;
++    for (i = 0; i < len; ++i)
++        out[i] = in[len - 1 - i];
++}
++
++/* BN_to_felem converts an OpenSSL BIGNUM into an felem */
++static int BN_to_felem(felem out, const BIGNUM *bn)
++{
++    felem_bytearray b_in;
++    felem_bytearray b_out;
++    unsigned num_bytes;
++
++    /* BN_bn2bin eats leading zeroes */
++    memset(b_out, 0, sizeof(b_out));
++    num_bytes = BN_num_bytes(bn);
++    if (num_bytes > sizeof b_out) {
++        ECerr(EC_F_BN_TO_FELEM, EC_R_BIGNUM_OUT_OF_RANGE);
++        return 0;
++    }
++    if (BN_is_negative(bn)) {
++        ECerr(EC_F_BN_TO_FELEM, EC_R_BIGNUM_OUT_OF_RANGE);
++        return 0;
++    }
++    num_bytes = BN_bn2bin(bn, b_in);
++    flip_endian(b_out, b_in, num_bytes);
++    bin66_to_felem(out, b_out);
++    return 1;
++}
++
++/* felem_to_BN converts an felem into an OpenSSL BIGNUM */
++static BIGNUM *felem_to_BN(BIGNUM *out, const felem in)
++{
++    felem_bytearray b_in, b_out;
++    felem_to_bin66(b_in, in);
++    flip_endian(b_out, b_in, sizeof b_out);
++    return BN_bin2bn(b_out, sizeof b_out, out);
++}
++
++/*-
++ * Field operations
++ * ----------------
++ */
++
++static void felem_one(felem out)
++{
++    out[0] = 1;
++    out[1] = 0;
++    out[2] = 0;
++    out[3] = 0;
++    out[4] = 0;
++    out[5] = 0;
++    out[6] = 0;
++    out[7] = 0;
++    out[8] = 0;
++}
++
++static void felem_assign(felem out, const felem in)
++{
++    out[0] = in[0];
++    out[1] = in[1];
++    out[2] = in[2];
++    out[3] = in[3];
++    out[4] = in[4];
++    out[5] = in[5];
++    out[6] = in[6];
++    out[7] = in[7];
++    out[8] = in[8];
++}
++
++/* felem_sum64 sets out = out + in. */
++static void felem_sum64(felem out, const felem in)
++{
++    out[0] += in[0];
++    out[1] += in[1];
++    out[2] += in[2];
++    out[3] += in[3];
++    out[4] += in[4];
++    out[5] += in[5];
++    out[6] += in[6];
++    out[7] += in[7];
++    out[8] += in[8];
++}
++
++/* felem_scalar sets out = in * scalar */
++static void felem_scalar(felem out, const felem in, limb scalar)
++{
++    out[0] = in[0] * scalar;
++    out[1] = in[1] * scalar;
++    out[2] = in[2] * scalar;
++    out[3] = in[3] * scalar;
++    out[4] = in[4] * scalar;
++    out[5] = in[5] * scalar;
++    out[6] = in[6] * scalar;
++    out[7] = in[7] * scalar;
++    out[8] = in[8] * scalar;
++}
++
++/* felem_scalar64 sets out = out * scalar */
++static void felem_scalar64(felem out, limb scalar)
++{
++    out[0] *= scalar;
++    out[1] *= scalar;
++    out[2] *= scalar;
++    out[3] *= scalar;
++    out[4] *= scalar;
++    out[5] *= scalar;
++    out[6] *= scalar;
++    out[7] *= scalar;
++    out[8] *= scalar;
++}
++
++/* felem_scalar128 sets out = out * scalar */
++static void felem_scalar128(largefelem out, limb scalar)
++{
++    out[0] *= scalar;
++    out[1] *= scalar;
++    out[2] *= scalar;
++    out[3] *= scalar;
++    out[4] *= scalar;
++    out[5] *= scalar;
++    out[6] *= scalar;
++    out[7] *= scalar;
++    out[8] *= scalar;
++}
++
++/*-
++ * felem_neg sets |out| to |-in|
++ * On entry:
++ *   in[i] < 2^59 + 2^14
++ * On exit:
++ *   out[i] < 2^62
++ */
++static void felem_neg(felem out, const felem in)
++{
++    /* In order to prevent underflow, we subtract from 0 mod p. */
++    static const limb two62m3 = (((limb) 1) << 62) - (((limb) 1) << 5);
++    static const limb two62m2 = (((limb) 1) << 62) - (((limb) 1) << 4);
++
++    out[0] = two62m3 - in[0];
++    out[1] = two62m2 - in[1];
++    out[2] = two62m2 - in[2];
++    out[3] = two62m2 - in[3];
++    out[4] = two62m2 - in[4];
++    out[5] = two62m2 - in[5];
++    out[6] = two62m2 - in[6];
++    out[7] = two62m2 - in[7];
++    out[8] = two62m2 - in[8];
++}
++
++/*-
++ * felem_diff64 subtracts |in| from |out|
++ * On entry:
++ *   in[i] < 2^59 + 2^14
++ * On exit:
++ *   out[i] < out[i] + 2^62
++ */
++static void felem_diff64(felem out, const felem in)
++{
++    /*
++     * In order to prevent underflow, we add 0 mod p before subtracting.
++     */
++    static const limb two62m3 = (((limb) 1) << 62) - (((limb) 1) << 5);
++    static const limb two62m2 = (((limb) 1) << 62) - (((limb) 1) << 4);
++
++    out[0] += two62m3 - in[0];
++    out[1] += two62m2 - in[1];
++    out[2] += two62m2 - in[2];
++    out[3] += two62m2 - in[3];
++    out[4] += two62m2 - in[4];
++    out[5] += two62m2 - in[5];
++    out[6] += two62m2 - in[6];
++    out[7] += two62m2 - in[7];
++    out[8] += two62m2 - in[8];
++}
++
++/*-
++ * felem_diff_128_64 subtracts |in| from |out|
++ * On entry:
++ *   in[i] < 2^62 + 2^17
++ * On exit:
++ *   out[i] < out[i] + 2^63
++ */
++static void felem_diff_128_64(largefelem out, const felem in)
++{
++    /*
++     * In order to prevent underflow, we add 0 mod p before subtracting.
++     */
++    static const limb two63m6 = (((limb) 1) << 62) - (((limb) 1) << 5);
++    static const limb two63m5 = (((limb) 1) << 62) - (((limb) 1) << 4);
++
++    out[0] += two63m6 - in[0];
++    out[1] += two63m5 - in[1];
++    out[2] += two63m5 - in[2];
++    out[3] += two63m5 - in[3];
++    out[4] += two63m5 - in[4];
++    out[5] += two63m5 - in[5];
++    out[6] += two63m5 - in[6];
++    out[7] += two63m5 - in[7];
++    out[8] += two63m5 - in[8];
++}
++
++/*-
++ * felem_diff_128_64 subtracts |in| from |out|
++ * On entry:
++ *   in[i] < 2^126
++ * On exit:
++ *   out[i] < out[i] + 2^127 - 2^69
++ */
++static void felem_diff128(largefelem out, const largefelem in)
++{
++    /*
++     * In order to prevent underflow, we add 0 mod p before subtracting.
++     */
++    static const uint128_t two127m70 =
++        (((uint128_t) 1) << 127) - (((uint128_t) 1) << 70);
++    static const uint128_t two127m69 =
++        (((uint128_t) 1) << 127) - (((uint128_t) 1) << 69);
++
++    out[0] += (two127m70 - in[0]);
++    out[1] += (two127m69 - in[1]);
++    out[2] += (two127m69 - in[2]);
++    out[3] += (two127m69 - in[3]);
++    out[4] += (two127m69 - in[4]);
++    out[5] += (two127m69 - in[5]);
++    out[6] += (two127m69 - in[6]);
++    out[7] += (two127m69 - in[7]);
++    out[8] += (two127m69 - in[8]);
++}
++
++/*-
++ * felem_square sets |out| = |in|^2
++ * On entry:
++ *   in[i] < 2^62
++ * On exit:
++ *   out[i] < 17 * max(in[i]) * max(in[i])
++ */
++static void felem_square(largefelem out, const felem in)
++{
++    felem inx2, inx4;
++    felem_scalar(inx2, in, 2);
++    felem_scalar(inx4, in, 4);
++
++    /*-
++     * We have many cases were we want to do
++     *   in[x] * in[y] +
++     *   in[y] * in[x]
++     * This is obviously just
++     *   2 * in[x] * in[y]
++     * However, rather than do the doubling on the 128 bit result, we
++     * double one of the inputs to the multiplication by reading from
++     * |inx2|
++     */
++
++    out[0] = ((uint128_t) in[0]) * in[0];
++    out[1] = ((uint128_t) in[0]) * inx2[1];
++    out[2] = ((uint128_t) in[0]) * inx2[2] + ((uint128_t) in[1]) * in[1];
++    out[3] = ((uint128_t) in[0]) * inx2[3] + ((uint128_t) in[1]) * inx2[2];
++    out[4] = ((uint128_t) in[0]) * inx2[4] +
++             ((uint128_t) in[1]) * inx2[3] + ((uint128_t) in[2]) * in[2];
++    out[5] = ((uint128_t) in[0]) * inx2[5] +
++             ((uint128_t) in[1]) * inx2[4] + ((uint128_t) in[2]) * inx2[3];
++    out[6] = ((uint128_t) in[0]) * inx2[6] +
++             ((uint128_t) in[1]) * inx2[5] +
++             ((uint128_t) in[2]) * inx2[4] + ((uint128_t) in[3]) * in[3];
++    out[7] = ((uint128_t) in[0]) * inx2[7] +
++             ((uint128_t) in[1]) * inx2[6] +
++             ((uint128_t) in[2]) * inx2[5] + ((uint128_t) in[3]) * inx2[4];
++    out[8] = ((uint128_t) in[0]) * inx2[8] +
++             ((uint128_t) in[1]) * inx2[7] +
++             ((uint128_t) in[2]) * inx2[6] +
++             ((uint128_t) in[3]) * inx2[5] + ((uint128_t) in[4]) * in[4];
++
++    /*
++     * The remaining limbs fall above 2^521, with the first falling at 2^522.
++     * They correspond to locations one bit up from the limbs produced above
++     * so we would have to multiply by two to align them. Again, rather than
++     * operate on the 128-bit result, we double one of the inputs to the
++     * multiplication. If we want to double for both this reason, and the
++     * reason above, then we end up multiplying by four.
++     */
++
++    /* 9 */
++    out[0] += ((uint128_t) in[1]) * inx4[8] +
++              ((uint128_t) in[2]) * inx4[7] +
++              ((uint128_t) in[3]) * inx4[6] + ((uint128_t) in[4]) * inx4[5];
++
++    /* 10 */
++    out[1] += ((uint128_t) in[2]) * inx4[8] +
++              ((uint128_t) in[3]) * inx4[7] +
++              ((uint128_t) in[4]) * inx4[6] + ((uint128_t) in[5]) * inx2[5];
++
++    /* 11 */
++    out[2] += ((uint128_t) in[3]) * inx4[8] +
++              ((uint128_t) in[4]) * inx4[7] + ((uint128_t) in[5]) * inx4[6];
++
++    /* 12 */
++    out[3] += ((uint128_t) in[4]) * inx4[8] +
++              ((uint128_t) in[5]) * inx4[7] + ((uint128_t) in[6]) * inx2[6];
++
++    /* 13 */
++    out[4] += ((uint128_t) in[5]) * inx4[8] + ((uint128_t) in[6]) * inx4[7];
++
++    /* 14 */
++    out[5] += ((uint128_t) in[6]) * inx4[8] + ((uint128_t) in[7]) * inx2[7];
++
++    /* 15 */
++    out[6] += ((uint128_t) in[7]) * inx4[8];
++
++    /* 16 */
++    out[7] += ((uint128_t) in[8]) * inx2[8];
++}
++
++/*-
++ * felem_mul sets |out| = |in1| * |in2|
++ * On entry:
++ *   in1[i] < 2^64
++ *   in2[i] < 2^63
++ * On exit:
++ *   out[i] < 17 * max(in1[i]) * max(in2[i])
++ */
++static void felem_mul(largefelem out, const felem in1, const felem in2)
++{
++    felem in2x2;
++    felem_scalar(in2x2, in2, 2);
++
++    out[0] = ((uint128_t) in1[0]) * in2[0];
++
++    out[1] = ((uint128_t) in1[0]) * in2[1] +
++             ((uint128_t) in1[1]) * in2[0];
++
++    out[2] = ((uint128_t) in1[0]) * in2[2] +
++             ((uint128_t) in1[1]) * in2[1] +
++             ((uint128_t) in1[2]) * in2[0];
++
++    out[3] = ((uint128_t) in1[0]) * in2[3] +
++             ((uint128_t) in1[1]) * in2[2] +
++             ((uint128_t) in1[2]) * in2[1] +
++             ((uint128_t) in1[3]) * in2[0];
++
++    out[4] = ((uint128_t) in1[0]) * in2[4] +
++             ((uint128_t) in1[1]) * in2[3] +
++             ((uint128_t) in1[2]) * in2[2] +
++             ((uint128_t) in1[3]) * in2[1] +
++             ((uint128_t) in1[4]) * in2[0];
++
++    out[5] = ((uint128_t) in1[0]) * in2[5] +
++             ((uint128_t) in1[1]) * in2[4] +
++             ((uint128_t) in1[2]) * in2[3] +
++             ((uint128_t) in1[3]) * in2[2] +
++             ((uint128_t) in1[4]) * in2[1] +
++             ((uint128_t) in1[5]) * in2[0];
++
++    out[6] = ((uint128_t) in1[0]) * in2[6] +
++             ((uint128_t) in1[1]) * in2[5] +
++             ((uint128_t) in1[2]) * in2[4] +
++             ((uint128_t) in1[3]) * in2[3] +
++             ((uint128_t) in1[4]) * in2[2] +
++             ((uint128_t) in1[5]) * in2[1] +
++             ((uint128_t) in1[6]) * in2[0];
++
++    out[7] = ((uint128_t) in1[0]) * in2[7] +
++             ((uint128_t) in1[1]) * in2[6] +
++             ((uint128_t) in1[2]) * in2[5] +
++             ((uint128_t) in1[3]) * in2[4] +
++             ((uint128_t) in1[4]) * in2[3] +
++             ((uint128_t) in1[5]) * in2[2] +
++             ((uint128_t) in1[6]) * in2[1] +
++             ((uint128_t) in1[7]) * in2[0];
++
++    out[8] = ((uint128_t) in1[0]) * in2[8] +
++             ((uint128_t) in1[1]) * in2[7] +
++             ((uint128_t) in1[2]) * in2[6] +
++             ((uint128_t) in1[3]) * in2[5] +
++             ((uint128_t) in1[4]) * in2[4] +
++             ((uint128_t) in1[5]) * in2[3] +
++             ((uint128_t) in1[6]) * in2[2] +
++             ((uint128_t) in1[7]) * in2[1] +
++             ((uint128_t) in1[8]) * in2[0];
++
++    /* See comment in felem_square about the use of in2x2 here */
++
++    out[0] += ((uint128_t) in1[1]) * in2x2[8] +
++              ((uint128_t) in1[2]) * in2x2[7] +
++              ((uint128_t) in1[3]) * in2x2[6] +
++              ((uint128_t) in1[4]) * in2x2[5] +
++              ((uint128_t) in1[5]) * in2x2[4] +
++              ((uint128_t) in1[6]) * in2x2[3] +
++              ((uint128_t) in1[7]) * in2x2[2] +
++              ((uint128_t) in1[8]) * in2x2[1];
++
++    out[1] += ((uint128_t) in1[2]) * in2x2[8] +
++              ((uint128_t) in1[3]) * in2x2[7] +
++              ((uint128_t) in1[4]) * in2x2[6] +
++              ((uint128_t) in1[5]) * in2x2[5] +
++              ((uint128_t) in1[6]) * in2x2[4] +
++              ((uint128_t) in1[7]) * in2x2[3] +
++              ((uint128_t) in1[8]) * in2x2[2];
++
++    out[2] += ((uint128_t) in1[3]) * in2x2[8] +
++              ((uint128_t) in1[4]) * in2x2[7] +
++              ((uint128_t) in1[5]) * in2x2[6] +
++              ((uint128_t) in1[6]) * in2x2[5] +
++              ((uint128_t) in1[7]) * in2x2[4] +
++              ((uint128_t) in1[8]) * in2x2[3];
++
++    out[3] += ((uint128_t) in1[4]) * in2x2[8] +
++              ((uint128_t) in1[5]) * in2x2[7] +
++              ((uint128_t) in1[6]) * in2x2[6] +
++              ((uint128_t) in1[7]) * in2x2[5] +
++              ((uint128_t) in1[8]) * in2x2[4];
++
++    out[4] += ((uint128_t) in1[5]) * in2x2[8] +
++              ((uint128_t) in1[6]) * in2x2[7] +
++              ((uint128_t) in1[7]) * in2x2[6] +
++              ((uint128_t) in1[8]) * in2x2[5];
++
++    out[5] += ((uint128_t) in1[6]) * in2x2[8] +
++              ((uint128_t) in1[7]) * in2x2[7] +
++              ((uint128_t) in1[8]) * in2x2[6];
++
++    out[6] += ((uint128_t) in1[7]) * in2x2[8] +
++              ((uint128_t) in1[8]) * in2x2[7];
++
++    out[7] += ((uint128_t) in1[8]) * in2x2[8];
++}
++
++static const limb bottom52bits = 0xfffffffffffff;
++
++/*-
++ * felem_reduce converts a largefelem to an felem.
++ * On entry:
++ *   in[i] < 2^128
++ * On exit:
++ *   out[i] < 2^59 + 2^14
++ */
++static void felem_reduce(felem out, const largefelem in)
++{
++    u64 overflow1, overflow2;
++
++    out[0] = ((limb) in[0]) & bottom58bits;
++    out[1] = ((limb) in[1]) & bottom58bits;
++    out[2] = ((limb) in[2]) & bottom58bits;
++    out[3] = ((limb) in[3]) & bottom58bits;
++    out[4] = ((limb) in[4]) & bottom58bits;
++    out[5] = ((limb) in[5]) & bottom58bits;
++    out[6] = ((limb) in[6]) & bottom58bits;
++    out[7] = ((limb) in[7]) & bottom58bits;
++    out[8] = ((limb) in[8]) & bottom58bits;
++
++    /* out[i] < 2^58 */
++
++    out[1] += ((limb) in[0]) >> 58;
++    out[1] += (((limb) (in[0] >> 64)) & bottom52bits) << 6;
++    /*-
++     * out[1] < 2^58 + 2^6 + 2^58
++     *        = 2^59 + 2^6
++     */
++    out[2] += ((limb) (in[0] >> 64)) >> 52;
++
++    out[2] += ((limb) in[1]) >> 58;
++    out[2] += (((limb) (in[1] >> 64)) & bottom52bits) << 6;
++    out[3] += ((limb) (in[1] >> 64)) >> 52;
++
++    out[3] += ((limb) in[2]) >> 58;
++    out[3] += (((limb) (in[2] >> 64)) & bottom52bits) << 6;
++    out[4] += ((limb) (in[2] >> 64)) >> 52;
++
++    out[4] += ((limb) in[3]) >> 58;
++    out[4] += (((limb) (in[3] >> 64)) & bottom52bits) << 6;
++    out[5] += ((limb) (in[3] >> 64)) >> 52;
++
++    out[5] += ((limb) in[4]) >> 58;
++    out[5] += (((limb) (in[4] >> 64)) & bottom52bits) << 6;
++    out[6] += ((limb) (in[4] >> 64)) >> 52;
++
++    out[6] += ((limb) in[5]) >> 58;
++    out[6] += (((limb) (in[5] >> 64)) & bottom52bits) << 6;
++    out[7] += ((limb) (in[5] >> 64)) >> 52;
++
++    out[7] += ((limb) in[6]) >> 58;
++    out[7] += (((limb) (in[6] >> 64)) & bottom52bits) << 6;
++    out[8] += ((limb) (in[6] >> 64)) >> 52;
++
++    out[8] += ((limb) in[7]) >> 58;
++    out[8] += (((limb) (in[7] >> 64)) & bottom52bits) << 6;
++    /*-
++     * out[x > 1] < 2^58 + 2^6 + 2^58 + 2^12
++     *            < 2^59 + 2^13
++     */
++    overflow1 = ((limb) (in[7] >> 64)) >> 52;
++
++    overflow1 += ((limb) in[8]) >> 58;
++    overflow1 += (((limb) (in[8] >> 64)) & bottom52bits) << 6;
++    overflow2 = ((limb) (in[8] >> 64)) >> 52;
++
++    overflow1 <<= 1;            /* overflow1 < 2^13 + 2^7 + 2^59 */
++    overflow2 <<= 1;            /* overflow2 < 2^13 */
++
++    out[0] += overflow1;        /* out[0] < 2^60 */
++    out[1] += overflow2;        /* out[1] < 2^59 + 2^6 + 2^13 */
++
++    out[1] += out[0] >> 58;
++    out[0] &= bottom58bits;
++    /*-
++     * out[0] < 2^58
++     * out[1] < 2^59 + 2^6 + 2^13 + 2^2
++     *        < 2^59 + 2^14
++     */
++}
++
++static void felem_square_reduce(felem out, const felem in)
++{
++    largefelem tmp;
++    felem_square(tmp, in);
++    felem_reduce(out, tmp);
++}
++
++static void felem_mul_reduce(felem out, const felem in1, const felem in2)
++{
++    largefelem tmp;
++    felem_mul(tmp, in1, in2);
++    felem_reduce(out, tmp);
++}
++
++/*-
++ * felem_inv calculates |out| = |in|^{-1}
++ *
++ * Based on Fermat's Little Theorem:
++ *   a^p = a (mod p)
++ *   a^{p-1} = 1 (mod p)
++ *   a^{p-2} = a^{-1} (mod p)
++ */
++static void felem_inv(felem out, const felem in)
++{
++    felem ftmp, ftmp2, ftmp3, ftmp4;
++    largefelem tmp;
++    unsigned i;
++
++    felem_square(tmp, in);
++    felem_reduce(ftmp, tmp);    /* 2^1 */
++    felem_mul(tmp, in, ftmp);
++    felem_reduce(ftmp, tmp);    /* 2^2 - 2^0 */
++    felem_assign(ftmp2, ftmp);
++    felem_square(tmp, ftmp);
++    felem_reduce(ftmp, tmp);    /* 2^3 - 2^1 */
++    felem_mul(tmp, in, ftmp);
++    felem_reduce(ftmp, tmp);    /* 2^3 - 2^0 */
++    felem_square(tmp, ftmp);
++    felem_reduce(ftmp, tmp);    /* 2^4 - 2^1 */
++
++    felem_square(tmp, ftmp2);
++    felem_reduce(ftmp3, tmp);   /* 2^3 - 2^1 */
++    felem_square(tmp, ftmp3);
++    felem_reduce(ftmp3, tmp);   /* 2^4 - 2^2 */
++    felem_mul(tmp, ftmp3, ftmp2);
++    felem_reduce(ftmp3, tmp);   /* 2^4 - 2^0 */
++
++    felem_assign(ftmp2, ftmp3);
++    felem_square(tmp, ftmp3);
++    felem_reduce(ftmp3, tmp);   /* 2^5 - 2^1 */
++    felem_square(tmp, ftmp3);
++    felem_reduce(ftmp3, tmp);   /* 2^6 - 2^2 */
++    felem_square(tmp, ftmp3);
++    felem_reduce(ftmp3, tmp);   /* 2^7 - 2^3 */
++    felem_square(tmp, ftmp3);
++    felem_reduce(ftmp3, tmp);   /* 2^8 - 2^4 */
++    felem_assign(ftmp4, ftmp3);
++    felem_mul(tmp, ftmp3, ftmp);
++    felem_reduce(ftmp4, tmp);   /* 2^8 - 2^1 */
++    felem_square(tmp, ftmp4);
++    felem_reduce(ftmp4, tmp);   /* 2^9 - 2^2 */
++    felem_mul(tmp, ftmp3, ftmp2);
++    felem_reduce(ftmp3, tmp);   /* 2^8 - 2^0 */
++    felem_assign(ftmp2, ftmp3);
++
++    for (i = 0; i < 8; i++) {
++        felem_square(tmp, ftmp3);
++        felem_reduce(ftmp3, tmp); /* 2^16 - 2^8 */
++    }
++    felem_mul(tmp, ftmp3, ftmp2);
++    felem_reduce(ftmp3, tmp);   /* 2^16 - 2^0 */
++    felem_assign(ftmp2, ftmp3);
++
++    for (i = 0; i < 16; i++) {
++        felem_square(tmp, ftmp3);
++        felem_reduce(ftmp3, tmp); /* 2^32 - 2^16 */
++    }
++    felem_mul(tmp, ftmp3, ftmp2);
++    felem_reduce(ftmp3, tmp);   /* 2^32 - 2^0 */
++    felem_assign(ftmp2, ftmp3);
++
++    for (i = 0; i < 32; i++) {
++        felem_square(tmp, ftmp3);
++        felem_reduce(ftmp3, tmp); /* 2^64 - 2^32 */
++    }
++    felem_mul(tmp, ftmp3, ftmp2);
++    felem_reduce(ftmp3, tmp);   /* 2^64 - 2^0 */
++    felem_assign(ftmp2, ftmp3);
++
++    for (i = 0; i < 64; i++) {
++        felem_square(tmp, ftmp3);
++        felem_reduce(ftmp3, tmp); /* 2^128 - 2^64 */
++    }
++    felem_mul(tmp, ftmp3, ftmp2);
++    felem_reduce(ftmp3, tmp);   /* 2^128 - 2^0 */
++    felem_assign(ftmp2, ftmp3);
++
++    for (i = 0; i < 128; i++) {
++        felem_square(tmp, ftmp3);
++        felem_reduce(ftmp3, tmp); /* 2^256 - 2^128 */
++    }
++    felem_mul(tmp, ftmp3, ftmp2);
++    felem_reduce(ftmp3, tmp);   /* 2^256 - 2^0 */
++    felem_assign(ftmp2, ftmp3);
++
++    for (i = 0; i < 256; i++) {
++        felem_square(tmp, ftmp3);
++        felem_reduce(ftmp3, tmp); /* 2^512 - 2^256 */
++    }
++    felem_mul(tmp, ftmp3, ftmp2);
++    felem_reduce(ftmp3, tmp);   /* 2^512 - 2^0 */
++
++    for (i = 0; i < 9; i++) {
++        felem_square(tmp, ftmp3);
++        felem_reduce(ftmp3, tmp); /* 2^521 - 2^9 */
++    }
++    felem_mul(tmp, ftmp3, ftmp4);
++    felem_reduce(ftmp3, tmp);   /* 2^512 - 2^2 */
++    felem_mul(tmp, ftmp3, in);
++    felem_reduce(out, tmp);     /* 2^512 - 3 */
++}
++
++/* This is 2^521-1, expressed as an felem */
++static const felem kPrime = {
++    0x03ffffffffffffff, 0x03ffffffffffffff, 0x03ffffffffffffff,
++    0x03ffffffffffffff, 0x03ffffffffffffff, 0x03ffffffffffffff,
++    0x03ffffffffffffff, 0x03ffffffffffffff, 0x01ffffffffffffff
++};
++
++/*-
++ * felem_is_zero returns a limb with all bits set if |in| == 0 (mod p) and 0
++ * otherwise.
++ * On entry:
++ *   in[i] < 2^59 + 2^14
++ */
++static limb felem_is_zero(const felem in)
++{
++    felem ftmp;
++    limb is_zero, is_p;
++    felem_assign(ftmp, in);
++
++    ftmp[0] += ftmp[8] >> 57;
++    ftmp[8] &= bottom57bits;
++    /* ftmp[8] < 2^57 */
++    ftmp[1] += ftmp[0] >> 58;
++    ftmp[0] &= bottom58bits;
++    ftmp[2] += ftmp[1] >> 58;
++    ftmp[1] &= bottom58bits;
++    ftmp[3] += ftmp[2] >> 58;
++    ftmp[2] &= bottom58bits;
++    ftmp[4] += ftmp[3] >> 58;
++    ftmp[3] &= bottom58bits;
++    ftmp[5] += ftmp[4] >> 58;
++    ftmp[4] &= bottom58bits;
++    ftmp[6] += ftmp[5] >> 58;
++    ftmp[5] &= bottom58bits;
++    ftmp[7] += ftmp[6] >> 58;
++    ftmp[6] &= bottom58bits;
++    ftmp[8] += ftmp[7] >> 58;
++    ftmp[7] &= bottom58bits;
++    /* ftmp[8] < 2^57 + 4 */
++
++    /*
++     * The ninth limb of 2*(2^521-1) is 0x03ffffffffffffff, which is greater
++     * than our bound for ftmp[8]. Therefore we only have to check if the
++     * zero is zero or 2^521-1.
++     */
++
++    is_zero = 0;
++    is_zero |= ftmp[0];
++    is_zero |= ftmp[1];
++    is_zero |= ftmp[2];
++    is_zero |= ftmp[3];
++    is_zero |= ftmp[4];
++    is_zero |= ftmp[5];
++    is_zero |= ftmp[6];
++    is_zero |= ftmp[7];
++    is_zero |= ftmp[8];
++
++    is_zero--;
++    /*
++     * We know that ftmp[i] < 2^63, therefore the only way that the top bit
++     * can be set is if is_zero was 0 before the decrement.
++     */
++    is_zero = ((s64) is_zero) >> 63;
++
++    is_p = ftmp[0] ^ kPrime[0];
++    is_p |= ftmp[1] ^ kPrime[1];
++    is_p |= ftmp[2] ^ kPrime[2];
++    is_p |= ftmp[3] ^ kPrime[3];
++    is_p |= ftmp[4] ^ kPrime[4];
++    is_p |= ftmp[5] ^ kPrime[5];
++    is_p |= ftmp[6] ^ kPrime[6];
++    is_p |= ftmp[7] ^ kPrime[7];
++    is_p |= ftmp[8] ^ kPrime[8];
++
++    is_p--;
++    is_p = ((s64) is_p) >> 63;
++
++    is_zero |= is_p;
++    return is_zero;
++}
++
++static int felem_is_zero_int(const felem in)
++{
++    return (int)(felem_is_zero(in) & ((limb) 1));
++}
++
++/*-
++ * felem_contract converts |in| to its unique, minimal representation.
++ * On entry:
++ *   in[i] < 2^59 + 2^14
++ */
++static void felem_contract(felem out, const felem in)
++{
++    limb is_p, is_greater, sign;
++    static const limb two58 = ((limb) 1) << 58;
++
++    felem_assign(out, in);
++
++    out[0] += out[8] >> 57;
++    out[8] &= bottom57bits;
++    /* out[8] < 2^57 */
++    out[1] += out[0] >> 58;
++    out[0] &= bottom58bits;
++    out[2] += out[1] >> 58;
++    out[1] &= bottom58bits;
++    out[3] += out[2] >> 58;
++    out[2] &= bottom58bits;
++    out[4] += out[3] >> 58;
++    out[3] &= bottom58bits;
++    out[5] += out[4] >> 58;
++    out[4] &= bottom58bits;
++    out[6] += out[5] >> 58;
++    out[5] &= bottom58bits;
++    out[7] += out[6] >> 58;
++    out[6] &= bottom58bits;
++    out[8] += out[7] >> 58;
++    out[7] &= bottom58bits;
++    /* out[8] < 2^57 + 4 */
++
++    /*
++     * If the value is greater than 2^521-1 then we have to subtract 2^521-1
++     * out. See the comments in felem_is_zero regarding why we don't test for
++     * other multiples of the prime.
++     */
++
++    /*
++     * First, if |out| is equal to 2^521-1, we subtract it out to get zero.
++     */
++
++    is_p = out[0] ^ kPrime[0];
++    is_p |= out[1] ^ kPrime[1];
++    is_p |= out[2] ^ kPrime[2];
++    is_p |= out[3] ^ kPrime[3];
++    is_p |= out[4] ^ kPrime[4];
++    is_p |= out[5] ^ kPrime[5];
++    is_p |= out[6] ^ kPrime[6];
++    is_p |= out[7] ^ kPrime[7];
++    is_p |= out[8] ^ kPrime[8];
++
++    is_p--;
++    is_p &= is_p << 32;
++    is_p &= is_p << 16;
++    is_p &= is_p << 8;
++    is_p &= is_p << 4;
++    is_p &= is_p << 2;
++    is_p &= is_p << 1;
++    is_p = ((s64) is_p) >> 63;
++    is_p = ~is_p;
++
++    /* is_p is 0 iff |out| == 2^521-1 and all ones otherwise */
++
++    out[0] &= is_p;
++    out[1] &= is_p;
++    out[2] &= is_p;
++    out[3] &= is_p;
++    out[4] &= is_p;
++    out[5] &= is_p;
++    out[6] &= is_p;
++    out[7] &= is_p;
++    out[8] &= is_p;
++
++    /*
++     * In order to test that |out| >= 2^521-1 we need only test if out[8] >>
++     * 57 is greater than zero as (2^521-1) + x >= 2^522
++     */
++    is_greater = out[8] >> 57;
++    is_greater |= is_greater << 32;
++    is_greater |= is_greater << 16;
++    is_greater |= is_greater << 8;
++    is_greater |= is_greater << 4;
++    is_greater |= is_greater << 2;
++    is_greater |= is_greater << 1;
++    is_greater = ((s64) is_greater) >> 63;
++
++    out[0] -= kPrime[0] & is_greater;
++    out[1] -= kPrime[1] & is_greater;
++    out[2] -= kPrime[2] & is_greater;
++    out[3] -= kPrime[3] & is_greater;
++    out[4] -= kPrime[4] & is_greater;
++    out[5] -= kPrime[5] & is_greater;
++    out[6] -= kPrime[6] & is_greater;
++    out[7] -= kPrime[7] & is_greater;
++    out[8] -= kPrime[8] & is_greater;
++
++    /* Eliminate negative coefficients */
++    sign = -(out[0] >> 63);
++    out[0] += (two58 & sign);
++    out[1] -= (1 & sign);
++    sign = -(out[1] >> 63);
++    out[1] += (two58 & sign);
++    out[2] -= (1 & sign);
++    sign = -(out[2] >> 63);
++    out[2] += (two58 & sign);
++    out[3] -= (1 & sign);
++    sign = -(out[3] >> 63);
++    out[3] += (two58 & sign);
++    out[4] -= (1 & sign);
++    sign = -(out[4] >> 63);
++    out[4] += (two58 & sign);
++    out[5] -= (1 & sign);
++    sign = -(out[0] >> 63);
++    out[5] += (two58 & sign);
++    out[6] -= (1 & sign);
++    sign = -(out[6] >> 63);
++    out[6] += (two58 & sign);
++    out[7] -= (1 & sign);
++    sign = -(out[7] >> 63);
++    out[7] += (two58 & sign);
++    out[8] -= (1 & sign);
++    sign = -(out[5] >> 63);
++    out[5] += (two58 & sign);
++    out[6] -= (1 & sign);
++    sign = -(out[6] >> 63);
++    out[6] += (two58 & sign);
++    out[7] -= (1 & sign);
++    sign = -(out[7] >> 63);
++    out[7] += (two58 & sign);
++    out[8] -= (1 & sign);
++}
++
++/*-
++ * Group operations
++ * ----------------
++ *
++ * Building on top of the field operations we have the operations on the
++ * elliptic curve group itself. Points on the curve are represented in Jacobian
++ * coordinates */
++
++/*-
++ * point_double calculates 2*(x_in, y_in, z_in)
++ *
++ * The method is taken from:
++ *   http://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-3.html#doubling-dbl-2001-b
++ *
++ * Outputs can equal corresponding inputs, i.e., x_out == x_in is allowed.
++ * while x_out == y_in is not (maybe this works, but it's not tested). */
++static void
++point_double(felem x_out, felem y_out, felem z_out,
++             const felem x_in, const felem y_in, const felem z_in)
++{
++    largefelem tmp, tmp2;
++    felem delta, gamma, beta, alpha, ftmp, ftmp2;
++
++    felem_assign(ftmp, x_in);
++    felem_assign(ftmp2, x_in);
++
++    /* delta = z^2 */
++    felem_square(tmp, z_in);
++    felem_reduce(delta, tmp);   /* delta[i] < 2^59 + 2^14 */
++
++    /* gamma = y^2 */
++    felem_square(tmp, y_in);
++    felem_reduce(gamma, tmp);   /* gamma[i] < 2^59 + 2^14 */
++
++    /* beta = x*gamma */
++    felem_mul(tmp, x_in, gamma);
++    felem_reduce(beta, tmp);    /* beta[i] < 2^59 + 2^14 */
++
++    /* alpha = 3*(x-delta)*(x+delta) */
++    felem_diff64(ftmp, delta);
++    /* ftmp[i] < 2^61 */
++    felem_sum64(ftmp2, delta);
++    /* ftmp2[i] < 2^60 + 2^15 */
++    felem_scalar64(ftmp2, 3);
++    /* ftmp2[i] < 3*2^60 + 3*2^15 */
++    felem_mul(tmp, ftmp, ftmp2);
++    /*-
++     * tmp[i] < 17(3*2^121 + 3*2^76)
++     *        = 61*2^121 + 61*2^76
++     *        < 64*2^121 + 64*2^76
++     *        = 2^127 + 2^82
++     *        < 2^128
++     */
++    felem_reduce(alpha, tmp);
++
++    /* x' = alpha^2 - 8*beta */
++    felem_square(tmp, alpha);
++    /*
++     * tmp[i] < 17*2^120 < 2^125
++     */
++    felem_assign(ftmp, beta);
++    felem_scalar64(ftmp, 8);
++    /* ftmp[i] < 2^62 + 2^17 */
++    felem_diff_128_64(tmp, ftmp);
++    /* tmp[i] < 2^125 + 2^63 + 2^62 + 2^17 */
++    felem_reduce(x_out, tmp);
++
++    /* z' = (y + z)^2 - gamma - delta */
++    felem_sum64(delta, gamma);
++    /* delta[i] < 2^60 + 2^15 */
++    felem_assign(ftmp, y_in);
++    felem_sum64(ftmp, z_in);
++    /* ftmp[i] < 2^60 + 2^15 */
++    felem_square(tmp, ftmp);
++    /*
++     * tmp[i] < 17(2^122) < 2^127
++     */
++    felem_diff_128_64(tmp, delta);
++    /* tmp[i] < 2^127 + 2^63 */
++    felem_reduce(z_out, tmp);
++
++    /* y' = alpha*(4*beta - x') - 8*gamma^2 */
++    felem_scalar64(beta, 4);
++    /* beta[i] < 2^61 + 2^16 */
++    felem_diff64(beta, x_out);
++    /* beta[i] < 2^61 + 2^60 + 2^16 */
++    felem_mul(tmp, alpha, beta);
++    /*-
++     * tmp[i] < 17*((2^59 + 2^14)(2^61 + 2^60 + 2^16))
++     *        = 17*(2^120 + 2^75 + 2^119 + 2^74 + 2^75 + 2^30)
++     *        = 17*(2^120 + 2^119 + 2^76 + 2^74 + 2^30)
++     *        < 2^128
++     */
++    felem_square(tmp2, gamma);
++    /*-
++     * tmp2[i] < 17*(2^59 + 2^14)^2
++     *         = 17*(2^118 + 2^74 + 2^28)
++     */
++    felem_scalar128(tmp2, 8);
++    /*-
++     * tmp2[i] < 8*17*(2^118 + 2^74 + 2^28)
++     *         = 2^125 + 2^121 + 2^81 + 2^77 + 2^35 + 2^31
++     *         < 2^126
++     */
++    felem_diff128(tmp, tmp2);
++    /*-
++     * tmp[i] < 2^127 - 2^69 + 17(2^120 + 2^119 + 2^76 + 2^74 + 2^30)
++     *        = 2^127 + 2^124 + 2^122 + 2^120 + 2^118 + 2^80 + 2^78 + 2^76 +
++     *          2^74 + 2^69 + 2^34 + 2^30
++     *        < 2^128
++     */
++    felem_reduce(y_out, tmp);
++}
++
++/* copy_conditional copies in to out iff mask is all ones. */
++static void copy_conditional(felem out, const felem in, limb mask)
++{
++    unsigned i;
++    for (i = 0; i < NLIMBS; ++i) {
++        const limb tmp = mask & (in[i] ^ out[i]);
++        out[i] ^= tmp;
++    }
++}
++
++/*-
++ * point_add calculates (x1, y1, z1) + (x2, y2, z2)
++ *
++ * The method is taken from
++ *   http://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-3.html#addition-add-2007-bl,
++ * adapted for mixed addition (z2 = 1, or z2 = 0 for the point at infinity).
++ *
++ * This function includes a branch for checking whether the two input points
++ * are equal (while not equal to the point at infinity). This case never
++ * happens during single point multiplication, so there is no timing leak for
++ * ECDH or ECDSA signing. */
++static void point_add(felem x3, felem y3, felem z3,
++                      const felem x1, const felem y1, const felem z1,
++                      const int mixed, const felem x2, const felem y2,
++                      const felem z2)
++{
++    felem ftmp, ftmp2, ftmp3, ftmp4, ftmp5, ftmp6, x_out, y_out, z_out;
++    largefelem tmp, tmp2;
++    limb x_equal, y_equal, z1_is_zero, z2_is_zero;
++
++    z1_is_zero = felem_is_zero(z1);
++    z2_is_zero = felem_is_zero(z2);
++
++    /* ftmp = z1z1 = z1**2 */
++    felem_square(tmp, z1);
++    felem_reduce(ftmp, tmp);
++
++    if (!mixed) {
++        /* ftmp2 = z2z2 = z2**2 */
++        felem_square(tmp, z2);
++        felem_reduce(ftmp2, tmp);
++
++        /* u1 = ftmp3 = x1*z2z2 */
++        felem_mul(tmp, x1, ftmp2);
++        felem_reduce(ftmp3, tmp);
++
++        /* ftmp5 = z1 + z2 */
++        felem_assign(ftmp5, z1);
++        felem_sum64(ftmp5, z2);
++        /* ftmp5[i] < 2^61 */
++
++        /* ftmp5 = (z1 + z2)**2 - z1z1 - z2z2 = 2*z1z2 */
++        felem_square(tmp, ftmp5);
++        /* tmp[i] < 17*2^122 */
++        felem_diff_128_64(tmp, ftmp);
++        /* tmp[i] < 17*2^122 + 2^63 */
++        felem_diff_128_64(tmp, ftmp2);
++        /* tmp[i] < 17*2^122 + 2^64 */
++        felem_reduce(ftmp5, tmp);
++
++        /* ftmp2 = z2 * z2z2 */
++        felem_mul(tmp, ftmp2, z2);
++        felem_reduce(ftmp2, tmp);
++
++        /* s1 = ftmp6 = y1 * z2**3 */
++        felem_mul(tmp, y1, ftmp2);
++        felem_reduce(ftmp6, tmp);
++    } else {
++        /*
++         * We'll assume z2 = 1 (special case z2 = 0 is handled later)
++         */
++
++        /* u1 = ftmp3 = x1*z2z2 */
++        felem_assign(ftmp3, x1);
++
++        /* ftmp5 = 2*z1z2 */
++        felem_scalar(ftmp5, z1, 2);
++
++        /* s1 = ftmp6 = y1 * z2**3 */
++        felem_assign(ftmp6, y1);
++    }
++
++    /* u2 = x2*z1z1 */
++    felem_mul(tmp, x2, ftmp);
++    /* tmp[i] < 17*2^120 */
++
++    /* h = ftmp4 = u2 - u1 */
++    felem_diff_128_64(tmp, ftmp3);
++    /* tmp[i] < 17*2^120 + 2^63 */
++    felem_reduce(ftmp4, tmp);
++
++    x_equal = felem_is_zero(ftmp4);
++
++    /* z_out = ftmp5 * h */
++    felem_mul(tmp, ftmp5, ftmp4);
++    felem_reduce(z_out, tmp);
++
++    /* ftmp = z1 * z1z1 */
++    felem_mul(tmp, ftmp, z1);
++    felem_reduce(ftmp, tmp);
++
++    /* s2 = tmp = y2 * z1**3 */
++    felem_mul(tmp, y2, ftmp);
++    /* tmp[i] < 17*2^120 */
++
++    /* r = ftmp5 = (s2 - s1)*2 */
++    felem_diff_128_64(tmp, ftmp6);
++    /* tmp[i] < 17*2^120 + 2^63 */
++    felem_reduce(ftmp5, tmp);
++    y_equal = felem_is_zero(ftmp5);
++    felem_scalar64(ftmp5, 2);
++    /* ftmp5[i] < 2^61 */
++
++    if (x_equal && y_equal && !z1_is_zero && !z2_is_zero) {
++        point_double(x3, y3, z3, x1, y1, z1);
++        return;
++    }
++
++    /* I = ftmp = (2h)**2 */
++    felem_assign(ftmp, ftmp4);
++    felem_scalar64(ftmp, 2);
++    /* ftmp[i] < 2^61 */
++    felem_square(tmp, ftmp);
++    /* tmp[i] < 17*2^122 */
++    felem_reduce(ftmp, tmp);
++
++    /* J = ftmp2 = h * I */
++    felem_mul(tmp, ftmp4, ftmp);
++    felem_reduce(ftmp2, tmp);
++
++    /* V = ftmp4 = U1 * I */
++    felem_mul(tmp, ftmp3, ftmp);
++    felem_reduce(ftmp4, tmp);
++
++    /* x_out = r**2 - J - 2V */
++    felem_square(tmp, ftmp5);
++    /* tmp[i] < 17*2^122 */
++    felem_diff_128_64(tmp, ftmp2);
++    /* tmp[i] < 17*2^122 + 2^63 */
++    felem_assign(ftmp3, ftmp4);
++    felem_scalar64(ftmp4, 2);
++    /* ftmp4[i] < 2^61 */
++    felem_diff_128_64(tmp, ftmp4);
++    /* tmp[i] < 17*2^122 + 2^64 */
++    felem_reduce(x_out, tmp);
++
++    /* y_out = r(V-x_out) - 2 * s1 * J */
++    felem_diff64(ftmp3, x_out);
++    /*
++     * ftmp3[i] < 2^60 + 2^60 = 2^61
++     */
++    felem_mul(tmp, ftmp5, ftmp3);
++    /* tmp[i] < 17*2^122 */
++    felem_mul(tmp2, ftmp6, ftmp2);
++    /* tmp2[i] < 17*2^120 */
++    felem_scalar128(tmp2, 2);
++    /* tmp2[i] < 17*2^121 */
++    felem_diff128(tmp, tmp2);
++        /*-
++         * tmp[i] < 2^127 - 2^69 + 17*2^122
++         *        = 2^126 - 2^122 - 2^6 - 2^2 - 1
++         *        < 2^127
++         */
++    felem_reduce(y_out, tmp);
++
++    copy_conditional(x_out, x2, z1_is_zero);
++    copy_conditional(x_out, x1, z2_is_zero);
++    copy_conditional(y_out, y2, z1_is_zero);
++    copy_conditional(y_out, y1, z2_is_zero);
++    copy_conditional(z_out, z2, z1_is_zero);
++    copy_conditional(z_out, z1, z2_is_zero);
++    felem_assign(x3, x_out);
++    felem_assign(y3, y_out);
++    felem_assign(z3, z_out);
++}
++
++/*-
++ * Base point pre computation
++ * --------------------------
++ *
++ * Two different sorts of precomputed tables are used in the following code.
++ * Each contain various points on the curve, where each point is three field
++ * elements (x, y, z).
++ *
++ * For the base point table, z is usually 1 (0 for the point at infinity).
++ * This table has 16 elements:
++ * index | bits    | point
++ * ------+---------+------------------------------
++ *     0 | 0 0 0 0 | 0G
++ *     1 | 0 0 0 1 | 1G
++ *     2 | 0 0 1 0 | 2^130G
++ *     3 | 0 0 1 1 | (2^130 + 1)G
++ *     4 | 0 1 0 0 | 2^260G
++ *     5 | 0 1 0 1 | (2^260 + 1)G
++ *     6 | 0 1 1 0 | (2^260 + 2^130)G
++ *     7 | 0 1 1 1 | (2^260 + 2^130 + 1)G
++ *     8 | 1 0 0 0 | 2^390G
++ *     9 | 1 0 0 1 | (2^390 + 1)G
++ *    10 | 1 0 1 0 | (2^390 + 2^130)G
++ *    11 | 1 0 1 1 | (2^390 + 2^130 + 1)G
++ *    12 | 1 1 0 0 | (2^390 + 2^260)G
++ *    13 | 1 1 0 1 | (2^390 + 2^260 + 1)G
++ *    14 | 1 1 1 0 | (2^390 + 2^260 + 2^130)G
++ *    15 | 1 1 1 1 | (2^390 + 2^260 + 2^130 + 1)G
++ *
++ * The reason for this is so that we can clock bits into four different
++ * locations when doing simple scalar multiplies against the base point.
++ *
++ * Tables for other points have table[i] = iG for i in 0 .. 16. */
++
++/* gmul is the table of precomputed base points */
++static const felem gmul[16][3] = {
++{{0, 0, 0, 0, 0, 0, 0, 0, 0},
++ {0, 0, 0, 0, 0, 0, 0, 0, 0},
++ {0, 0, 0, 0, 0, 0, 0, 0, 0}},
++{{0x017e7e31c2e5bd66, 0x022cf0615a90a6fe, 0x00127a2ffa8de334,
++  0x01dfbf9d64a3f877, 0x006b4d3dbaa14b5e, 0x014fed487e0a2bd8,
++  0x015b4429c6481390, 0x03a73678fb2d988e, 0x00c6858e06b70404},
++ {0x00be94769fd16650, 0x031c21a89cb09022, 0x039013fad0761353,
++  0x02657bd099031542, 0x03273e662c97ee72, 0x01e6d11a05ebef45,
++  0x03d1bd998f544495, 0x03001172297ed0b1, 0x011839296a789a3b},
++ {1, 0, 0, 0, 0, 0, 0, 0, 0}},
++{{0x0373faacbc875bae, 0x00f325023721c671, 0x00f666fd3dbde5ad,
++  0x01a6932363f88ea7, 0x01fc6d9e13f9c47b, 0x03bcbffc2bbf734e,
++  0x013ee3c3647f3a92, 0x029409fefe75d07d, 0x00ef9199963d85e5},
++ {0x011173743ad5b178, 0x02499c7c21bf7d46, 0x035beaeabb8b1a58,
++  0x00f989c4752ea0a3, 0x0101e1de48a9c1a3, 0x01a20076be28ba6c,
++  0x02f8052e5eb2de95, 0x01bfe8f82dea117c, 0x0160074d3c36ddb7},
++ {1, 0, 0, 0, 0, 0, 0, 0, 0}},
++{{0x012f3fc373393b3b, 0x03d3d6172f1419fa, 0x02adc943c0b86873,
++  0x00d475584177952b, 0x012a4d1673750ee2, 0x00512517a0f13b0c,
++  0x02b184671a7b1734, 0x0315b84236f1a50a, 0x00a4afc472edbdb9},
++ {0x00152a7077f385c4, 0x03044007d8d1c2ee, 0x0065829d61d52b52,
++  0x00494ff6b6631d0d, 0x00a11d94d5f06bcf, 0x02d2f89474d9282e,
++  0x0241c5727c06eeb9, 0x0386928710fbdb9d, 0x01f883f727b0dfbe},
++ {1, 0, 0, 0, 0, 0, 0, 0, 0}},
++{{0x019b0c3c9185544d, 0x006243a37c9d97db, 0x02ee3cbe030a2ad2,
++  0x00cfdd946bb51e0d, 0x0271c00932606b91, 0x03f817d1ec68c561,
++  0x03f37009806a369c, 0x03c1f30baf184fd5, 0x01091022d6d2f065},
++ {0x0292c583514c45ed, 0x0316fca51f9a286c, 0x00300af507c1489a,
++  0x0295f69008298cf1, 0x02c0ed8274943d7b, 0x016509b9b47a431e,
++  0x02bc9de9634868ce, 0x005b34929bffcb09, 0x000c1a0121681524},
++ {1, 0, 0, 0, 0, 0, 0, 0, 0}},
++{{0x0286abc0292fb9f2, 0x02665eee9805b3f7, 0x01ed7455f17f26d6,
++  0x0346355b83175d13, 0x006284944cd0a097, 0x0191895bcdec5e51,
++  0x02e288370afda7d9, 0x03b22312bfefa67a, 0x01d104d3fc0613fe},
++ {0x0092421a12f7e47f, 0x0077a83fa373c501, 0x03bd25c5f696bd0d,
++  0x035c41e4d5459761, 0x01ca0d1742b24f53, 0x00aaab27863a509c,
++  0x018b6de47df73917, 0x025c0b771705cd01, 0x01fd51d566d760a7},
++ {1, 0, 0, 0, 0, 0, 0, 0, 0}},
++{{0x01dd92ff6b0d1dbd, 0x039c5e2e8f8afa69, 0x0261ed13242c3b27,
++  0x0382c6e67026e6a0, 0x01d60b10be2089f9, 0x03c15f3dce86723f,
++  0x03c764a32d2a062d, 0x017307eac0fad056, 0x018207c0b96c5256},
++ {0x0196a16d60e13154, 0x03e6ce74c0267030, 0x00ddbf2b4e52a5aa,
++  0x012738241bbf31c8, 0x00ebe8dc04685a28, 0x024c2ad6d380d4a2,
++  0x035ee062a6e62d0e, 0x0029ed74af7d3a0f, 0x00eef32aec142ebd},
++ {1, 0, 0, 0, 0, 0, 0, 0, 0}},
++{{0x00c31ec398993b39, 0x03a9f45bcda68253, 0x00ac733c24c70890,
++  0x00872b111401ff01, 0x01d178c23195eafb, 0x03bca2c816b87f74,
++  0x0261a9af46fbad7a, 0x0324b2a8dd3d28f9, 0x00918121d8f24e23},
++ {0x032bc8c1ca983cd7, 0x00d869dfb08fc8c6, 0x01693cb61fce1516,
++  0x012a5ea68f4e88a8, 0x010869cab88d7ae3, 0x009081ad277ceee1,
++  0x033a77166d064cdc, 0x03955235a1fb3a95, 0x01251a4a9b25b65e},
++ {1, 0, 0, 0, 0, 0, 0, 0, 0}},
++{{0x00148a3a1b27f40b, 0x0123186df1b31fdc, 0x00026e7beaad34ce,
++  0x01db446ac1d3dbba, 0x0299c1a33437eaec, 0x024540610183cbb7,
++  0x0173bb0e9ce92e46, 0x02b937e43921214b, 0x01ab0436a9bf01b5},
++ {0x0383381640d46948, 0x008dacbf0e7f330f, 0x03602122bcc3f318,
++  0x01ee596b200620d6, 0x03bd0585fda430b3, 0x014aed77fd123a83,
++  0x005ace749e52f742, 0x0390fe041da2b842, 0x0189a8ceb3299242},
++ {1, 0, 0, 0, 0, 0, 0, 0, 0}},
++{{0x012a19d6b3282473, 0x00c0915918b423ce, 0x023a954eb94405ae,
++  0x00529f692be26158, 0x0289fa1b6fa4b2aa, 0x0198ae4ceea346ef,
++  0x0047d8cdfbdedd49, 0x00cc8c8953f0f6b8, 0x001424abbff49203},
++ {0x0256732a1115a03a, 0x0351bc38665c6733, 0x03f7b950fb4a6447,
++  0x000afffa94c22155, 0x025763d0a4dab540, 0x000511e92d4fc283,
++  0x030a7e9eda0ee96c, 0x004c3cd93a28bf0a, 0x017edb3a8719217f},
++ {1, 0, 0, 0, 0, 0, 0, 0, 0}},
++{{0x011de5675a88e673, 0x031d7d0f5e567fbe, 0x0016b2062c970ae5,
++  0x03f4a2be49d90aa7, 0x03cef0bd13822866, 0x03f0923dcf774a6c,
++  0x0284bebc4f322f72, 0x016ab2645302bb2c, 0x01793f95dace0e2a},
++ {0x010646e13527a28f, 0x01ca1babd59dc5e7, 0x01afedfd9a5595df,
++  0x01f15785212ea6b1, 0x0324e5d64f6ae3f4, 0x02d680f526d00645,
++  0x0127920fadf627a7, 0x03b383f75df4f684, 0x0089e0057e783b0a},
++ {1, 0, 0, 0, 0, 0, 0, 0, 0}},
++{{0x00f334b9eb3c26c6, 0x0298fdaa98568dce, 0x01c2d24843a82292,
++  0x020bcb24fa1b0711, 0x02cbdb3d2b1875e6, 0x0014907598f89422,
++  0x03abe3aa43b26664, 0x02cbf47f720bc168, 0x0133b5e73014b79b},
++ {0x034aab5dab05779d, 0x00cdc5d71fee9abb, 0x0399f16bd4bd9d30,
++  0x03582fa592d82647, 0x02be1cdfb775b0e9, 0x0034f7cea32e94cb,
++  0x0335a7f08f56f286, 0x03b707e9565d1c8b, 0x0015c946ea5b614f},
++ {1, 0, 0, 0, 0, 0, 0, 0, 0}},
++{{0x024676f6cff72255, 0x00d14625cac96378, 0x00532b6008bc3767,
++  0x01fc16721b985322, 0x023355ea1b091668, 0x029de7afdc0317c3,
++  0x02fc8a7ca2da037c, 0x02de1217d74a6f30, 0x013f7173175b73bf},
++ {0x0344913f441490b5, 0x0200f9e272b61eca, 0x0258a246b1dd55d2,
++  0x03753db9ea496f36, 0x025e02937a09c5ef, 0x030cbd3d14012692,
++  0x01793a67e70dc72a, 0x03ec1d37048a662e, 0x006550f700c32a8d},
++ {1, 0, 0, 0, 0, 0, 0, 0, 0}},
++{{0x00d3f48a347eba27, 0x008e636649b61bd8, 0x00d3b93716778fb3,
++  0x004d1915757bd209, 0x019d5311a3da44e0, 0x016d1afcbbe6aade,
++  0x0241bf5f73265616, 0x0384672e5d50d39b, 0x005009fee522b684},
++ {0x029b4fab064435fe, 0x018868ee095bbb07, 0x01ea3d6936cc92b8,
++  0x000608b00f78a2f3, 0x02db911073d1c20f, 0x018205938470100a,
++  0x01f1e4964cbe6ff2, 0x021a19a29eed4663, 0x01414485f42afa81},
++ {1, 0, 0, 0, 0, 0, 0, 0, 0}},
++{{0x01612b3a17f63e34, 0x03813992885428e6, 0x022b3c215b5a9608,
++  0x029b4057e19f2fcb, 0x0384059a587af7e6, 0x02d6400ace6fe610,
++  0x029354d896e8e331, 0x00c047ee6dfba65e, 0x0037720542e9d49d},
++ {0x02ce9eed7c5e9278, 0x0374ed703e79643b, 0x01316c54c4072006,
++  0x005aaa09054b2ee8, 0x002824000c840d57, 0x03d4eba24771ed86,
++  0x0189c50aabc3bdae, 0x0338c01541e15510, 0x00466d56e38eed42},
++ {1, 0, 0, 0, 0, 0, 0, 0, 0}},
++{{0x007efd8330ad8bd6, 0x02465ed48047710b, 0x0034c6606b215e0c,
++  0x016ae30c53cbf839, 0x01fa17bd37161216, 0x018ead4e61ce8ab9,
++  0x005482ed5f5dee46, 0x037543755bba1d7f, 0x005e5ac7e70a9d0f},
++ {0x0117e1bb2fdcb2a2, 0x03deea36249f40c4, 0x028d09b4a6246cb7,
++  0x03524b8855bcf756, 0x023d7d109d5ceb58, 0x0178e43e3223ef9c,
++  0x0154536a0c6e966a, 0x037964d1286ee9fe, 0x0199bcd90e125055},
++ {1, 0, 0, 0, 0, 0, 0, 0, 0}}
++};
++
++/*
++ * select_point selects the |idx|th point from a precomputation table and
++ * copies it to out.
++ */
++ /* pre_comp below is of the size provided in |size| */
++static void select_point(const limb idx, unsigned int size,
++                         const felem pre_comp[][3], felem out[3])
++{
++    unsigned i, j;
++    limb *outlimbs = &out[0][0];
++
++    memset(out, 0, sizeof(*out) * 3);
++
++    for (i = 0; i < size; i++) {
++        const limb *inlimbs = &pre_comp[i][0][0];
++        limb mask = i ^ idx;
++        mask |= mask >> 4;
++        mask |= mask >> 2;
++        mask |= mask >> 1;
++        mask &= 1;
++        mask--;
++        for (j = 0; j < NLIMBS * 3; j++)
++            outlimbs[j] |= inlimbs[j] & mask;
++    }
++}
++
++/* get_bit returns the |i|th bit in |in| */
++static char get_bit(const felem_bytearray in, int i)
++{
++    if (i < 0)
++        return 0;
++    return (in[i >> 3] >> (i & 7)) & 1;
++}
++
++/*
++ * Interleaved point multiplication using precomputed point multiples: The
++ * small point multiples 0*P, 1*P, ..., 16*P are in pre_comp[], the scalars
++ * in scalars[]. If g_scalar is non-NULL, we also add this multiple of the
++ * generator, using certain (large) precomputed multiples in g_pre_comp.
++ * Output point (X, Y, Z) is stored in x_out, y_out, z_out
++ */
++static void batch_mul(felem x_out, felem y_out, felem z_out,
++                      const felem_bytearray scalars[],
++                      const unsigned num_points, const u8 *g_scalar,
++                      const int mixed, const felem pre_comp[][17][3],
++                      const felem g_pre_comp[16][3])
++{
++    int i, skip;
++    unsigned num, gen_mul = (g_scalar != NULL);
++    felem nq[3], tmp[4];
++    limb bits;
++    u8 sign, digit;
++
++    /* set nq to the point at infinity */
++    memset(nq, 0, sizeof(nq));
++
++    /*
++     * Loop over all scalars msb-to-lsb, interleaving additions of multiples
++     * of the generator (last quarter of rounds) and additions of other
++     * points multiples (every 5th round).
++     */
++    skip = 1;                   /* save two point operations in the first
++                                 * round */
++    for (i = (num_points ? 520 : 130); i >= 0; --i) {
++        /* double */
++        if (!skip)
++            point_double(nq[0], nq[1], nq[2], nq[0], nq[1], nq[2]);
++
++        /* add multiples of the generator */
++        if (gen_mul && (i <= 130)) {
++            bits = get_bit(g_scalar, i + 390) << 3;
++            if (i < 130) {
++                bits |= get_bit(g_scalar, i + 260) << 2;
++                bits |= get_bit(g_scalar, i + 130) << 1;
++                bits |= get_bit(g_scalar, i);
++            }
++            /* select the point to add, in constant time */
++            select_point(bits, 16, g_pre_comp, tmp);
++            if (!skip) {
++                /* The 1 argument below is for "mixed" */
++                point_add(nq[0], nq[1], nq[2],
++                          nq[0], nq[1], nq[2], 1, tmp[0], tmp[1], tmp[2]);
++            } else {
++                memcpy(nq, tmp, 3 * sizeof(felem));
++                skip = 0;
++            }
++        }
++
++        /* do other additions every 5 doublings */
++        if (num_points && (i % 5 == 0)) {
++            /* loop over all scalars */
++            for (num = 0; num < num_points; ++num) {
++                bits = get_bit(scalars[num], i + 4) << 5;
++                bits |= get_bit(scalars[num], i + 3) << 4;
++                bits |= get_bit(scalars[num], i + 2) << 3;
++                bits |= get_bit(scalars[num], i + 1) << 2;
++                bits |= get_bit(scalars[num], i) << 1;
++                bits |= get_bit(scalars[num], i - 1);
++                ec_GFp_nistp_recode_scalar_bits(&sign, &digit, bits);
++
++                /*
++                 * select the point to add or subtract, in constant time
++                 */
++                select_point(digit, 17, pre_comp[num], tmp);
++                felem_neg(tmp[3], tmp[1]); /* (X, -Y, Z) is the negative
++                                            * point */
++                copy_conditional(tmp[1], tmp[3], (-(limb) sign));
++
++                if (!skip) {
++                    point_add(nq[0], nq[1], nq[2],
++                              nq[0], nq[1], nq[2],
++                              mixed, tmp[0], tmp[1], tmp[2]);
++                } else {
++                    memcpy(nq, tmp, 3 * sizeof(felem));
++                    skip = 0;
++                }
++            }
++        }
++    }
++    felem_assign(x_out, nq[0]);
++    felem_assign(y_out, nq[1]);
++    felem_assign(z_out, nq[2]);
++}
++
++/* Precomputation for the group generator. */
++struct nistp521_pre_comp_st {
++    felem g_pre_comp[16][3];
++    int references;
++    CRYPTO_RWLOCK *lock;
++};
++
++const EC_METHOD *EC_GFp_nistp521_method(void)
++{
++    static const EC_METHOD ret = {
++        EC_FLAGS_DEFAULT_OCT,
++        NID_X9_62_prime_field,
++        ec_GFp_nistp521_group_init,
++        ec_GFp_simple_group_finish,
++        ec_GFp_simple_group_clear_finish,
++        ec_GFp_nist_group_copy,
++        ec_GFp_nistp521_group_set_curve,
++        ec_GFp_simple_group_get_curve,
++        ec_GFp_simple_group_get_degree,
++        ec_group_simple_order_bits,
++        ec_GFp_simple_group_check_discriminant,
++        ec_GFp_simple_point_init,
++        ec_GFp_simple_point_finish,
++        ec_GFp_simple_point_clear_finish,
++        ec_GFp_simple_point_copy,
++        ec_GFp_simple_point_set_to_infinity,
++        ec_GFp_simple_set_Jprojective_coordinates_GFp,
++        ec_GFp_simple_get_Jprojective_coordinates_GFp,
++        ec_GFp_simple_point_set_affine_coordinates,
++        ec_GFp_nistp521_point_get_affine_coordinates,
++        0 /* point_set_compressed_coordinates */ ,
++        0 /* point2oct */ ,
++        0 /* oct2point */ ,
++        ec_GFp_simple_add,
++        ec_GFp_simple_dbl,
++        ec_GFp_simple_invert,
++        ec_GFp_simple_is_at_infinity,
++        ec_GFp_simple_is_on_curve,
++        ec_GFp_simple_cmp,
++        ec_GFp_simple_make_affine,
++        ec_GFp_simple_points_make_affine,
++        ec_GFp_nistp521_points_mul,
++        ec_GFp_nistp521_precompute_mult,
++        ec_GFp_nistp521_have_precompute_mult,
++        ec_GFp_nist_field_mul,
++        ec_GFp_nist_field_sqr,
++        0 /* field_div */ ,
++        0 /* field_encode */ ,
++        0 /* field_decode */ ,
++        0,                      /* field_set_to_one */
++        ec_key_simple_priv2oct,
++        ec_key_simple_oct2priv,
++        0, /* set private */
++        ec_key_simple_generate_key,
++        ec_key_simple_check_key,
++        ec_key_simple_generate_public_key,
++        0, /* keycopy */
++        0, /* keyfinish */
++        ecdh_simple_compute_key
++    };
++
++    return &ret;
++}
++
++/******************************************************************************/
++/*
++ * FUNCTIONS TO MANAGE PRECOMPUTATION
++ */
++
++static NISTP521_PRE_COMP *nistp521_pre_comp_new()
++{
++    NISTP521_PRE_COMP *ret = OPENSSL_zalloc(sizeof(*ret));
++
++    if (ret == NULL) {
++        ECerr(EC_F_NISTP521_PRE_COMP_NEW, ERR_R_MALLOC_FAILURE);
++        return ret;
++    }
++
++    ret->references = 1;
++
++    ret->lock = CRYPTO_THREAD_lock_new();
++    if (ret->lock == NULL) {
++        ECerr(EC_F_NISTP521_PRE_COMP_NEW, ERR_R_MALLOC_FAILURE);
++        OPENSSL_free(ret);
++        return NULL;
++    }
++    return ret;
++}
++
++NISTP521_PRE_COMP *EC_nistp521_pre_comp_dup(NISTP521_PRE_COMP *p)
++{
++    int i;
++    if (p != NULL)
++        CRYPTO_atomic_add(&p->references, 1, &i, p->lock);
++    return p;
++}
++
++void EC_nistp521_pre_comp_free(NISTP521_PRE_COMP *p)
++{
++    int i;
++
++    if (p == NULL)
++        return;
++
++    CRYPTO_atomic_add(&p->references, -1, &i, p->lock);
++    REF_PRINT_COUNT("EC_nistp521", x);
++    if (i > 0)
++        return;
++    REF_ASSERT_ISNT(i < 0);
++
++    CRYPTO_THREAD_lock_free(p->lock);
++    OPENSSL_free(p);
++}
++
++/******************************************************************************/
++/*
++ * OPENSSL EC_METHOD FUNCTIONS
++ */
++
++int ec_GFp_nistp521_group_init(EC_GROUP *group)
++{
++    int ret;
++    ret = ec_GFp_simple_group_init(group);
++    group->a_is_minus3 = 1;
++    return ret;
++}
++
++int ec_GFp_nistp521_group_set_curve(EC_GROUP *group, const BIGNUM *p,
++                                    const BIGNUM *a, const BIGNUM *b,
++                                    BN_CTX *ctx)
++{
++    int ret = 0;
++    BN_CTX *new_ctx = NULL;
++    BIGNUM *curve_p, *curve_a, *curve_b;
++
++    if (ctx == NULL)
++        if ((ctx = new_ctx = BN_CTX_new()) == NULL)
++            return 0;
++    BN_CTX_start(ctx);
++    if (((curve_p = BN_CTX_get(ctx)) == NULL) ||
++        ((curve_a = BN_CTX_get(ctx)) == NULL) ||
++        ((curve_b = BN_CTX_get(ctx)) == NULL))
++        goto err;
++    BN_bin2bn(nistp521_curve_params[0], sizeof(felem_bytearray), curve_p);
++    BN_bin2bn(nistp521_curve_params[1], sizeof(felem_bytearray), curve_a);
++    BN_bin2bn(nistp521_curve_params[2], sizeof(felem_bytearray), curve_b);
++    if ((BN_cmp(curve_p, p)) || (BN_cmp(curve_a, a)) || (BN_cmp(curve_b, b))) {
++        ECerr(EC_F_EC_GFP_NISTP521_GROUP_SET_CURVE,
++              EC_R_WRONG_CURVE_PARAMETERS);
++        goto err;
++    }
++    group->field_mod_func = BN_nist_mod_521;
++    ret = ec_GFp_simple_group_set_curve(group, p, a, b, ctx);
++ err:
++    BN_CTX_end(ctx);
++    BN_CTX_free(new_ctx);
++    return ret;
++}
++
++/*
++ * Takes the Jacobian coordinates (X, Y, Z) of a point and returns (X', Y') =
++ * (X/Z^2, Y/Z^3)
++ */
++int ec_GFp_nistp521_point_get_affine_coordinates(const EC_GROUP *group,
++                                                 const EC_POINT *point,
++                                                 BIGNUM *x, BIGNUM *y,
++                                                 BN_CTX *ctx)
++{
++    felem z1, z2, x_in, y_in, x_out, y_out;
++    largefelem tmp;
++
++    if (EC_POINT_is_at_infinity(group, point)) {
++        ECerr(EC_F_EC_GFP_NISTP521_POINT_GET_AFFINE_COORDINATES,
++              EC_R_POINT_AT_INFINITY);
++        return 0;
++    }
++    if ((!BN_to_felem(x_in, point->X)) || (!BN_to_felem(y_in, point->Y)) ||
++        (!BN_to_felem(z1, point->Z)))
++        return 0;
++    felem_inv(z2, z1);
++    felem_square(tmp, z2);
++    felem_reduce(z1, tmp);
++    felem_mul(tmp, x_in, z1);
++    felem_reduce(x_in, tmp);
++    felem_contract(x_out, x_in);
++    if (x != NULL) {
++        if (!felem_to_BN(x, x_out)) {
++            ECerr(EC_F_EC_GFP_NISTP521_POINT_GET_AFFINE_COORDINATES,
++                  ERR_R_BN_LIB);
++            return 0;
++        }
++    }
++    felem_mul(tmp, z1, z2);
++    felem_reduce(z1, tmp);
++    felem_mul(tmp, y_in, z1);
++    felem_reduce(y_in, tmp);
++    felem_contract(y_out, y_in);
++    if (y != NULL) {
++        if (!felem_to_BN(y, y_out)) {
++            ECerr(EC_F_EC_GFP_NISTP521_POINT_GET_AFFINE_COORDINATES,
++                  ERR_R_BN_LIB);
++            return 0;
++        }
++    }
++    return 1;
++}
++
++/* points below is of size |num|, and tmp_felems is of size |num+1/ */
++static void make_points_affine(size_t num, felem points[][3],
++                               felem tmp_felems[])
++{
++    /*
++     * Runs in constant time, unless an input is the point at infinity (which
++     * normally shouldn't happen).
++     */
++    ec_GFp_nistp_points_make_affine_internal(num,
++                                             points,
++                                             sizeof(felem),
++                                             tmp_felems,
++                                             (void (*)(void *))felem_one,
++                                             (int (*)(const void *))
++                                             felem_is_zero_int,
++                                             (void (*)(void *, const void *))
++                                             felem_assign,
++                                             (void (*)(void *, const void *))
++                                             felem_square_reduce, (void (*)
++                                                                   (void *,
++                                                                    const void
++                                                                    *,
++                                                                    const void
++                                                                    *))
++                                             felem_mul_reduce,
++                                             (void (*)(void *, const void *))
++                                             felem_inv,
++                                             (void (*)(void *, const void *))
++                                             felem_contract);
++}
++
++/*
++ * Computes scalar*generator + \sum scalars[i]*points[i], ignoring NULL
++ * values Result is stored in r (r can equal one of the inputs).
++ */
++int ec_GFp_nistp521_points_mul(const EC_GROUP *group, EC_POINT *r,
++                               const BIGNUM *scalar, size_t num,
++                               const EC_POINT *points[],
++                               const BIGNUM *scalars[], BN_CTX *ctx)
++{
++    int ret = 0;
++    int j;
++    int mixed = 0;
++    BN_CTX *new_ctx = NULL;
++    BIGNUM *x, *y, *z, *tmp_scalar;
++    felem_bytearray g_secret;
++    felem_bytearray *secrets = NULL;
++    felem (*pre_comp)[17][3] = NULL;
++    felem *tmp_felems = NULL;
++    felem_bytearray tmp;
++    unsigned i, num_bytes;
++    int have_pre_comp = 0;
++    size_t num_points = num;
++    felem x_in, y_in, z_in, x_out, y_out, z_out;
++    NISTP521_PRE_COMP *pre = NULL;
++    felem(*g_pre_comp)[3] = NULL;
++    EC_POINT *generator = NULL;
++    const EC_POINT *p = NULL;
++    const BIGNUM *p_scalar = NULL;
++
++    if (ctx == NULL)
++        if ((ctx = new_ctx = BN_CTX_new()) == NULL)
++            return 0;
++    BN_CTX_start(ctx);
++    if (((x = BN_CTX_get(ctx)) == NULL) ||
++        ((y = BN_CTX_get(ctx)) == NULL) ||
++        ((z = BN_CTX_get(ctx)) == NULL) ||
++        ((tmp_scalar = BN_CTX_get(ctx)) == NULL))
++        goto err;
++
++    if (scalar != NULL) {
++        pre = group->pre_comp.nistp521;
++        if (pre)
++            /* we have precomputation, try to use it */
++            g_pre_comp = &pre->g_pre_comp[0];
++        else
++            /* try to use the standard precomputation */
++            g_pre_comp = (felem(*)[3]) gmul;
++        generator = EC_POINT_new(group);
++        if (generator == NULL)
++            goto err;
++        /* get the generator from precomputation */
++        if (!felem_to_BN(x, g_pre_comp[1][0]) ||
++            !felem_to_BN(y, g_pre_comp[1][1]) ||
++            !felem_to_BN(z, g_pre_comp[1][2])) {
++            ECerr(EC_F_EC_GFP_NISTP521_POINTS_MUL, ERR_R_BN_LIB);
++            goto err;
++        }
++        if (!EC_POINT_set_Jprojective_coordinates_GFp(group,
++                                                      generator, x, y, z,
++                                                      ctx))
++            goto err;
++        if (0 == EC_POINT_cmp(group, generator, group->generator, ctx))
++            /* precomputation matches generator */
++            have_pre_comp = 1;
++        else
++            /*
++             * we don't have valid precomputation: treat the generator as a
++             * random point
++             */
++            num_points++;
++    }
++
++    if (num_points > 0) {
++        if (num_points >= 2) {
++            /*
++             * unless we precompute multiples for just one point, converting
++             * those into affine form is time well spent
++             */
++            mixed = 1;
++        }
++        secrets = OPENSSL_zalloc(sizeof(*secrets) * num_points);
++        pre_comp = OPENSSL_zalloc(sizeof(*pre_comp) * num_points);
++        if (mixed)
++            tmp_felems =
++                OPENSSL_malloc(sizeof(*tmp_felems) * (num_points * 17 + 1));
++        if ((secrets == NULL) || (pre_comp == NULL)
++            || (mixed && (tmp_felems == NULL))) {
++            ECerr(EC_F_EC_GFP_NISTP521_POINTS_MUL, ERR_R_MALLOC_FAILURE);
++            goto err;
++        }
++
++        /*
++         * we treat NULL scalars as 0, and NULL points as points at infinity,
++         * i.e., they contribute nothing to the linear combination
++         */
++        for (i = 0; i < num_points; ++i) {
++            if (i == num)
++                /*
++                 * we didn't have a valid precomputation, so we pick the
++                 * generator
++                 */
++            {
++                p = EC_GROUP_get0_generator(group);
++                p_scalar = scalar;
++            } else
++                /* the i^th point */
++            {
++                p = points[i];
++                p_scalar = scalars[i];
++            }
++            if ((p_scalar != NULL) && (p != NULL)) {
++                /* reduce scalar to 0 <= scalar < 2^521 */
++                if ((BN_num_bits(p_scalar) > 521)
++                    || (BN_is_negative(p_scalar))) {
++                    /*
++                     * this is an unusual input, and we don't guarantee
++                     * constant-timeness
++                     */
++                    if (!BN_nnmod(tmp_scalar, p_scalar, group->order, ctx)) {
++                        ECerr(EC_F_EC_GFP_NISTP521_POINTS_MUL, ERR_R_BN_LIB);
++                        goto err;
++                    }
++                    num_bytes = BN_bn2bin(tmp_scalar, tmp);
++                } else
++                    num_bytes = BN_bn2bin(p_scalar, tmp);
++                flip_endian(secrets[i], tmp, num_bytes);
++                /* precompute multiples */
++                if ((!BN_to_felem(x_out, p->X)) ||
++                    (!BN_to_felem(y_out, p->Y)) ||
++                    (!BN_to_felem(z_out, p->Z)))
++                    goto err;
++                memcpy(pre_comp[i][1][0], x_out, sizeof(felem));
++                memcpy(pre_comp[i][1][1], y_out, sizeof(felem));
++                memcpy(pre_comp[i][1][2], z_out, sizeof(felem));
++                for (j = 2; j <= 16; ++j) {
++                    if (j & 1) {
++                        point_add(pre_comp[i][j][0], pre_comp[i][j][1],
++                                  pre_comp[i][j][2], pre_comp[i][1][0],
++                                  pre_comp[i][1][1], pre_comp[i][1][2], 0,
++                                  pre_comp[i][j - 1][0],
++                                  pre_comp[i][j - 1][1],
++                                  pre_comp[i][j - 1][2]);
++                    } else {
++                        point_double(pre_comp[i][j][0], pre_comp[i][j][1],
++                                     pre_comp[i][j][2], pre_comp[i][j / 2][0],
++                                     pre_comp[i][j / 2][1],
++                                     pre_comp[i][j / 2][2]);
++                    }
++                }
++            }
++        }
++        if (mixed)
++            make_points_affine(num_points * 17, pre_comp[0], tmp_felems);
++    }
++
++    /* the scalar for the generator */
++    if ((scalar != NULL) && (have_pre_comp)) {
++        memset(g_secret, 0, sizeof(g_secret));
++        /* reduce scalar to 0 <= scalar < 2^521 */
++        if ((BN_num_bits(scalar) > 521) || (BN_is_negative(scalar))) {
++            /*
++             * this is an unusual input, and we don't guarantee
++             * constant-timeness
++             */
++            if (!BN_nnmod(tmp_scalar, scalar, group->order, ctx)) {
++                ECerr(EC_F_EC_GFP_NISTP521_POINTS_MUL, ERR_R_BN_LIB);
++                goto err;
++            }
++            num_bytes = BN_bn2bin(tmp_scalar, tmp);
++        } else
++            num_bytes = BN_bn2bin(scalar, tmp);
++        flip_endian(g_secret, tmp, num_bytes);
++        /* do the multiplication with generator precomputation */
++        batch_mul(x_out, y_out, z_out,
++                  (const felem_bytearray(*))secrets, num_points,
++                  g_secret,
++                  mixed, (const felem(*)[17][3])pre_comp,
++                  (const felem(*)[3])g_pre_comp);
++    } else
++        /* do the multiplication without generator precomputation */
++        batch_mul(x_out, y_out, z_out,
++                  (const felem_bytearray(*))secrets, num_points,
++                  NULL, mixed, (const felem(*)[17][3])pre_comp, NULL);
++    /* reduce the output to its unique minimal representation */
++    felem_contract(x_in, x_out);
++    felem_contract(y_in, y_out);
++    felem_contract(z_in, z_out);
++    if ((!felem_to_BN(x, x_in)) || (!felem_to_BN(y, y_in)) ||
++        (!felem_to_BN(z, z_in))) {
++        ECerr(EC_F_EC_GFP_NISTP521_POINTS_MUL, ERR_R_BN_LIB);
++        goto err;
++    }
++    ret = EC_POINT_set_Jprojective_coordinates_GFp(group, r, x, y, z, ctx);
++
++ err:
++    BN_CTX_end(ctx);
++    EC_POINT_free(generator);
++    BN_CTX_free(new_ctx);
++    OPENSSL_free(secrets);
++    OPENSSL_free(pre_comp);
++    OPENSSL_free(tmp_felems);
++    return ret;
++}
++
++int ec_GFp_nistp521_precompute_mult(EC_GROUP *group, BN_CTX *ctx)
++{
++    int ret = 0;
++    NISTP521_PRE_COMP *pre = NULL;
++    int i, j;
++    BN_CTX *new_ctx = NULL;
++    BIGNUM *x, *y;
++    EC_POINT *generator = NULL;
++    felem tmp_felems[16];
++
++    /* throw away old precomputation */
++    EC_pre_comp_free(group);
++    if (ctx == NULL)
++        if ((ctx = new_ctx = BN_CTX_new()) == NULL)
++            return 0;
++    BN_CTX_start(ctx);
++    if (((x = BN_CTX_get(ctx)) == NULL) || ((y = BN_CTX_get(ctx)) == NULL))
++        goto err;
++    /* get the generator */
++    if (group->generator == NULL)
++        goto err;
++    generator = EC_POINT_new(group);
++    if (generator == NULL)
++        goto err;
++    BN_bin2bn(nistp521_curve_params[3], sizeof(felem_bytearray), x);
++    BN_bin2bn(nistp521_curve_params[4], sizeof(felem_bytearray), y);
++    if (!EC_POINT_set_affine_coordinates_GFp(group, generator, x, y, ctx))
++        goto err;
++    if ((pre = nistp521_pre_comp_new()) == NULL)
++        goto err;
++    /*
++     * if the generator is the standard one, use built-in precomputation
++     */
++    if (0 == EC_POINT_cmp(group, generator, group->generator, ctx)) {
++        memcpy(pre->g_pre_comp, gmul, sizeof(pre->g_pre_comp));
++        goto done;
++    }
++    if ((!BN_to_felem(pre->g_pre_comp[1][0], group->generator->X)) ||
++        (!BN_to_felem(pre->g_pre_comp[1][1], group->generator->Y)) ||
++        (!BN_to_felem(pre->g_pre_comp[1][2], group->generator->Z)))
++        goto err;
++    /* compute 2^130*G, 2^260*G, 2^390*G */
++    for (i = 1; i <= 4; i <<= 1) {
++        point_double(pre->g_pre_comp[2 * i][0], pre->g_pre_comp[2 * i][1],
++                     pre->g_pre_comp[2 * i][2], pre->g_pre_comp[i][0],
++                     pre->g_pre_comp[i][1], pre->g_pre_comp[i][2]);
++        for (j = 0; j < 129; ++j) {
++            point_double(pre->g_pre_comp[2 * i][0],
++                         pre->g_pre_comp[2 * i][1],
++                         pre->g_pre_comp[2 * i][2],
++                         pre->g_pre_comp[2 * i][0],
++                         pre->g_pre_comp[2 * i][1],
++                         pre->g_pre_comp[2 * i][2]);
++        }
++    }
++    /* g_pre_comp[0] is the point at infinity */
++    memset(pre->g_pre_comp[0], 0, sizeof(pre->g_pre_comp[0]));
++    /* the remaining multiples */
++    /* 2^130*G + 2^260*G */
++    point_add(pre->g_pre_comp[6][0], pre->g_pre_comp[6][1],
++              pre->g_pre_comp[6][2], pre->g_pre_comp[4][0],
++              pre->g_pre_comp[4][1], pre->g_pre_comp[4][2],
++              0, pre->g_pre_comp[2][0], pre->g_pre_comp[2][1],
++              pre->g_pre_comp[2][2]);
++    /* 2^130*G + 2^390*G */
++    point_add(pre->g_pre_comp[10][0], pre->g_pre_comp[10][1],
++              pre->g_pre_comp[10][2], pre->g_pre_comp[8][0],
++              pre->g_pre_comp[8][1], pre->g_pre_comp[8][2],
++              0, pre->g_pre_comp[2][0], pre->g_pre_comp[2][1],
++              pre->g_pre_comp[2][2]);
++    /* 2^260*G + 2^390*G */
++    point_add(pre->g_pre_comp[12][0], pre->g_pre_comp[12][1],
++              pre->g_pre_comp[12][2], pre->g_pre_comp[8][0],
++              pre->g_pre_comp[8][1], pre->g_pre_comp[8][2],
++              0, pre->g_pre_comp[4][0], pre->g_pre_comp[4][1],
++              pre->g_pre_comp[4][2]);
++    /* 2^130*G + 2^260*G + 2^390*G */
++    point_add(pre->g_pre_comp[14][0], pre->g_pre_comp[14][1],
++              pre->g_pre_comp[14][2], pre->g_pre_comp[12][0],
++              pre->g_pre_comp[12][1], pre->g_pre_comp[12][2],
++              0, pre->g_pre_comp[2][0], pre->g_pre_comp[2][1],
++              pre->g_pre_comp[2][2]);
++    for (i = 1; i < 8; ++i) {
++        /* odd multiples: add G */
++        point_add(pre->g_pre_comp[2 * i + 1][0],
++                  pre->g_pre_comp[2 * i + 1][1],
++                  pre->g_pre_comp[2 * i + 1][2], pre->g_pre_comp[2 * i][0],
++                  pre->g_pre_comp[2 * i][1], pre->g_pre_comp[2 * i][2], 0,
++                  pre->g_pre_comp[1][0], pre->g_pre_comp[1][1],
++                  pre->g_pre_comp[1][2]);
++    }
++    make_points_affine(15, &(pre->g_pre_comp[1]), tmp_felems);
++
++ done:
++    SETPRECOMP(group, nistp521, pre);
++    ret = 1;
++    pre = NULL;
++ err:
++    BN_CTX_end(ctx);
++    EC_POINT_free(generator);
++    BN_CTX_free(new_ctx);
++    EC_nistp521_pre_comp_free(pre);
++    return ret;
++}
++
++int ec_GFp_nistp521_have_precompute_mult(const EC_GROUP *group)
++{
++    return HAVEPRECOMP(group, nistp521);
++}
++
++#endif
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/ec/ecp_nistputil.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/ec/ecp_nistputil.c
+new file mode 100644
+index 0000000..97fb631
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/ec/ecp_nistputil.c
+@@ -0,0 +1,223 @@
++/*
++ * Copyright 2011-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++/* Copyright 2011 Google Inc.
++ *
++ * Licensed under the Apache License, Version 2.0 (the "License");
++ *
++ * you may not use this file except in compliance with the License.
++ * You may obtain a copy of the License at
++ *
++ *     http://www.apache.org/licenses/LICENSE-2.0
++ *
++ *  Unless required by applicable law or agreed to in writing, software
++ *  distributed under the License is distributed on an "AS IS" BASIS,
++ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ *  See the License for the specific language governing permissions and
++ *  limitations under the License.
++ */
++
++#include 
++#ifdef OPENSSL_NO_EC_NISTP_64_GCC_128
++NON_EMPTY_TRANSLATION_UNIT
++#else
++
++/*
++ * Common utility functions for ecp_nistp224.c, ecp_nistp256.c, ecp_nistp521.c.
++ */
++
++# include 
++# include "ec_lcl.h"
++
++/*
++ * Convert an array of points into affine coordinates. (If the point at
++ * infinity is found (Z = 0), it remains unchanged.) This function is
++ * essentially an equivalent to EC_POINTs_make_affine(), but works with the
++ * internal representation of points as used by ecp_nistp###.c rather than
++ * with (BIGNUM-based) EC_POINT data structures. point_array is the
++ * input/output buffer ('num' points in projective form, i.e. three
++ * coordinates each), based on an internal representation of field elements
++ * of size 'felem_size'. tmp_felems needs to point to a temporary array of
++ * 'num'+1 field elements for storage of intermediate values.
++ */
++void ec_GFp_nistp_points_make_affine_internal(size_t num, void *point_array,
++                                              size_t felem_size,
++                                              void *tmp_felems,
++                                              void (*felem_one) (void *out),
++                                              int (*felem_is_zero) (const void
++                                                                    *in),
++                                              void (*felem_assign) (void *out,
++                                                                    const void
++                                                                    *in),
++                                              void (*felem_square) (void *out,
++                                                                    const void
++                                                                    *in),
++                                              void (*felem_mul) (void *out,
++                                                                 const void
++                                                                 *in1,
++                                                                 const void
++                                                                 *in2),
++                                              void (*felem_inv) (void *out,
++                                                                 const void
++                                                                 *in),
++                                              void (*felem_contract) (void
++                                                                      *out,
++                                                                      const
++                                                                      void
++                                                                      *in))
++{
++    int i = 0;
++
++# define tmp_felem(I) (&((char *)tmp_felems)[(I) * felem_size])
++# define X(I) (&((char *)point_array)[3*(I) * felem_size])
++# define Y(I) (&((char *)point_array)[(3*(I) + 1) * felem_size])
++# define Z(I) (&((char *)point_array)[(3*(I) + 2) * felem_size])
++
++    if (!felem_is_zero(Z(0)))
++        felem_assign(tmp_felem(0), Z(0));
++    else
++        felem_one(tmp_felem(0));
++    for (i = 1; i < (int)num; i++) {
++        if (!felem_is_zero(Z(i)))
++            felem_mul(tmp_felem(i), tmp_felem(i - 1), Z(i));
++        else
++            felem_assign(tmp_felem(i), tmp_felem(i - 1));
++    }
++    /*
++     * Now each tmp_felem(i) is the product of Z(0) .. Z(i), skipping any
++     * zero-valued factors: if Z(i) = 0, we essentially pretend that Z(i) = 1
++     */
++
++    felem_inv(tmp_felem(num - 1), tmp_felem(num - 1));
++    for (i = num - 1; i >= 0; i--) {
++        if (i > 0)
++            /*
++             * tmp_felem(i-1) is the product of Z(0) .. Z(i-1), tmp_felem(i)
++             * is the inverse of the product of Z(0) .. Z(i)
++             */
++            /* 1/Z(i) */
++            felem_mul(tmp_felem(num), tmp_felem(i - 1), tmp_felem(i));
++        else
++            felem_assign(tmp_felem(num), tmp_felem(0)); /* 1/Z(0) */
++
++        if (!felem_is_zero(Z(i))) {
++            if (i > 0)
++                /*
++                 * For next iteration, replace tmp_felem(i-1) by its inverse
++                 */
++                felem_mul(tmp_felem(i - 1), tmp_felem(i), Z(i));
++
++            /*
++             * Convert point (X, Y, Z) into affine form (X/(Z^2), Y/(Z^3), 1)
++             */
++            felem_square(Z(i), tmp_felem(num)); /* 1/(Z^2) */
++            felem_mul(X(i), X(i), Z(i)); /* X/(Z^2) */
++            felem_mul(Z(i), Z(i), tmp_felem(num)); /* 1/(Z^3) */
++            felem_mul(Y(i), Y(i), Z(i)); /* Y/(Z^3) */
++            felem_contract(X(i), X(i));
++            felem_contract(Y(i), Y(i));
++            felem_one(Z(i));
++        } else {
++            if (i > 0)
++                /*
++                 * For next iteration, replace tmp_felem(i-1) by its inverse
++                 */
++                felem_assign(tmp_felem(i - 1), tmp_felem(i));
++        }
++    }
++}
++
++/*-
++ * This function looks at 5+1 scalar bits (5 current, 1 adjacent less
++ * significant bit), and recodes them into a signed digit for use in fast point
++ * multiplication: the use of signed rather than unsigned digits means that
++ * fewer points need to be precomputed, given that point inversion is easy
++ * (a precomputed point dP makes -dP available as well).
++ *
++ * BACKGROUND:
++ *
++ * Signed digits for multiplication were introduced by Booth ("A signed binary
++ * multiplication technique", Quart. Journ. Mech. and Applied Math., vol. IV,
++ * pt. 2 (1951), pp. 236-240), in that case for multiplication of integers.
++ * Booth's original encoding did not generally improve the density of nonzero
++ * digits over the binary representation, and was merely meant to simplify the
++ * handling of signed factors given in two's complement; but it has since been
++ * shown to be the basis of various signed-digit representations that do have
++ * further advantages, including the wNAF, using the following general approach:
++ *
++ * (1) Given a binary representation
++ *
++ *       b_k  ...  b_2  b_1  b_0,
++ *
++ *     of a nonnegative integer (b_k in {0, 1}), rewrite it in digits 0, 1, -1
++ *     by using bit-wise subtraction as follows:
++ *
++ *        b_k b_(k-1)  ...  b_2  b_1  b_0
++ *      -     b_k      ...  b_3  b_2  b_1  b_0
++ *       -------------------------------------
++ *        s_k b_(k-1)  ...  s_3  s_2  s_1  s_0
++ *
++ *     A left-shift followed by subtraction of the original value yields a new
++ *     representation of the same value, using signed bits s_i = b_(i+1) - b_i.
++ *     This representation from Booth's paper has since appeared in the
++ *     literature under a variety of different names including "reversed binary
++ *     form", "alternating greedy expansion", "mutual opposite form", and
++ *     "sign-alternating {+-1}-representation".
++ *
++ *     An interesting property is that among the nonzero bits, values 1 and -1
++ *     strictly alternate.
++ *
++ * (2) Various window schemes can be applied to the Booth representation of
++ *     integers: for example, right-to-left sliding windows yield the wNAF
++ *     (a signed-digit encoding independently discovered by various researchers
++ *     in the 1990s), and left-to-right sliding windows yield a left-to-right
++ *     equivalent of the wNAF (independently discovered by various researchers
++ *     around 2004).
++ *
++ * To prevent leaking information through side channels in point multiplication,
++ * we need to recode the given integer into a regular pattern: sliding windows
++ * as in wNAFs won't do, we need their fixed-window equivalent -- which is a few
++ * decades older: we'll be using the so-called "modified Booth encoding" due to
++ * MacSorley ("High-speed arithmetic in binary computers", Proc. IRE, vol. 49
++ * (1961), pp. 67-91), in a radix-2^5 setting.  That is, we always combine five
++ * signed bits into a signed digit:
++ *
++ *       s_(4j + 4) s_(4j + 3) s_(4j + 2) s_(4j + 1) s_(4j)
++ *
++ * The sign-alternating property implies that the resulting digit values are
++ * integers from -16 to 16.
++ *
++ * Of course, we don't actually need to compute the signed digits s_i as an
++ * intermediate step (that's just a nice way to see how this scheme relates
++ * to the wNAF): a direct computation obtains the recoded digit from the
++ * six bits b_(4j + 4) ... b_(4j - 1).
++ *
++ * This function takes those five bits as an integer (0 .. 63), writing the
++ * recoded digit to *sign (0 for positive, 1 for negative) and *digit (absolute
++ * value, in the range 0 .. 8).  Note that this integer essentially provides the
++ * input bits "shifted to the left" by one position: for example, the input to
++ * compute the least significant recoded digit, given that there's no bit b_-1,
++ * has to be b_4 b_3 b_2 b_1 b_0 0.
++ *
++ */
++void ec_GFp_nistp_recode_scalar_bits(unsigned char *sign,
++                                     unsigned char *digit, unsigned char in)
++{
++    unsigned char s, d;
++
++    s = ~((in >> 5) - 1);       /* sets all bits to MSB(in), 'in' seen as
++                                 * 6-bit value */
++    d = (1 << 6) - in - 1;
++    d = (d & s) | (in & ~s);
++    d = (d >> 1) + (d & 1);
++
++    *sign = s & 1;
++    *digit = d;
++}
++#endif
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/ec/ecp_nistz256.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/ec/ecp_nistz256.c
+new file mode 100644
+index 0000000..dca3a2d
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/ec/ecp_nistz256.c
+@@ -0,0 +1,1559 @@
++/*
++ * Copyright 2014-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++/******************************************************************************
++ *                                                                            *
++ * Copyright 2014 Intel Corporation                                           *
++ *                                                                            *
++ * Licensed under the Apache License, Version 2.0 (the "License");            *
++ * you may not use this file except in compliance with the License.           *
++ * You may obtain a copy of the License at                                    *
++ *                                                                            *
++ *    http://www.apache.org/licenses/LICENSE-2.0                              *
++ *                                                                            *
++ * Unless required by applicable law or agreed to in writing, software        *
++ * distributed under the License is distributed on an "AS IS" BASIS,          *
++ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   *
++ * See the License for the specific language governing permissions and        *
++ * limitations under the License.                                             *
++ *                                                                            *
++ ******************************************************************************
++ *                                                                            *
++ * Developers and authors:                                                    *
++ * Shay Gueron (1, 2), and Vlad Krasnov (1)                                   *
++ * (1) Intel Corporation, Israel Development Center                           *
++ * (2) University of Haifa                                                    *
++ * Reference:                                                                 *
++ * S.Gueron and V.Krasnov, "Fast Prime Field Elliptic Curve Cryptography with *
++ *                          256 Bit Primes"                                   *
++ *                                                                            *
++ ******************************************************************************/
++
++#include 
++
++#include "internal/cryptlib.h"
++#include "internal/bn_int.h"
++#include "ec_lcl.h"
++
++#if BN_BITS2 != 64
++# define TOBN(hi,lo)    lo,hi
++#else
++# define TOBN(hi,lo)    ((BN_ULONG)hi<<32|lo)
++#endif
++
++#if defined(__GNUC__)
++# define ALIGN32        __attribute((aligned(32)))
++#elif defined(_MSC_VER)
++# define ALIGN32        __declspec(align(32))
++#else
++# define ALIGN32
++#endif
++
++#define ALIGNPTR(p,N)   ((unsigned char *)p+N-(size_t)p%N)
++#define P256_LIMBS      (256/BN_BITS2)
++
++typedef unsigned short u16;
++
++typedef struct {
++    BN_ULONG X[P256_LIMBS];
++    BN_ULONG Y[P256_LIMBS];
++    BN_ULONG Z[P256_LIMBS];
++} P256_POINT;
++
++typedef struct {
++    BN_ULONG X[P256_LIMBS];
++    BN_ULONG Y[P256_LIMBS];
++} P256_POINT_AFFINE;
++
++typedef P256_POINT_AFFINE PRECOMP256_ROW[64];
++
++/* structure for precomputed multiples of the generator */
++struct nistz256_pre_comp_st {
++    const EC_GROUP *group;      /* Parent EC_GROUP object */
++    size_t w;                   /* Window size */
++    /*
++     * Constant time access to the X and Y coordinates of the pre-computed,
++     * generator multiplies, in the Montgomery domain. Pre-calculated
++     * multiplies are stored in affine form.
++     */
++    PRECOMP256_ROW *precomp;
++    void *precomp_storage;
++    int references;
++    CRYPTO_RWLOCK *lock;
++};
++
++/* Functions implemented in assembly */
++/*
++ * Most of below mentioned functions *preserve* the property of inputs
++ * being fully reduced, i.e. being in [0, modulus) range. Simply put if
++ * inputs are fully reduced, then output is too. Note that reverse is
++ * not true, in sense that given partially reduced inputs output can be
++ * either, not unlikely reduced. And "most" in first sentence refers to
++ * the fact that given the calculations flow one can tolerate that
++ * addition, 1st function below, produces partially reduced result *if*
++ * multiplications by 2 and 3, which customarily use addition, fully
++ * reduce it. This effectively gives two options: a) addition produces
++ * fully reduced result [as long as inputs are, just like remaining
++ * functions]; b) addition is allowed to produce partially reduced
++ * result, but multiplications by 2 and 3 perform additional reduction
++ * step. Choice between the two can be platform-specific, but it was a)
++ * in all cases so far...
++ */
++/* Modular add: res = a+b mod P   */
++void ecp_nistz256_add(BN_ULONG res[P256_LIMBS],
++                      const BN_ULONG a[P256_LIMBS],
++                      const BN_ULONG b[P256_LIMBS]);
++/* Modular mul by 2: res = 2*a mod P */
++void ecp_nistz256_mul_by_2(BN_ULONG res[P256_LIMBS],
++                           const BN_ULONG a[P256_LIMBS]);
++/* Modular mul by 3: res = 3*a mod P */
++void ecp_nistz256_mul_by_3(BN_ULONG res[P256_LIMBS],
++                           const BN_ULONG a[P256_LIMBS]);
++
++/* Modular div by 2: res = a/2 mod P */
++void ecp_nistz256_div_by_2(BN_ULONG res[P256_LIMBS],
++                           const BN_ULONG a[P256_LIMBS]);
++/* Modular sub: res = a-b mod P   */
++void ecp_nistz256_sub(BN_ULONG res[P256_LIMBS],
++                      const BN_ULONG a[P256_LIMBS],
++                      const BN_ULONG b[P256_LIMBS]);
++/* Modular neg: res = -a mod P    */
++void ecp_nistz256_neg(BN_ULONG res[P256_LIMBS], const BN_ULONG a[P256_LIMBS]);
++/* Montgomery mul: res = a*b*2^-256 mod P */
++void ecp_nistz256_mul_mont(BN_ULONG res[P256_LIMBS],
++                           const BN_ULONG a[P256_LIMBS],
++                           const BN_ULONG b[P256_LIMBS]);
++/* Montgomery sqr: res = a*a*2^-256 mod P */
++void ecp_nistz256_sqr_mont(BN_ULONG res[P256_LIMBS],
++                           const BN_ULONG a[P256_LIMBS]);
++/* Convert a number from Montgomery domain, by multiplying with 1 */
++void ecp_nistz256_from_mont(BN_ULONG res[P256_LIMBS],
++                            const BN_ULONG in[P256_LIMBS]);
++/* Convert a number to Montgomery domain, by multiplying with 2^512 mod P*/
++void ecp_nistz256_to_mont(BN_ULONG res[P256_LIMBS],
++                          const BN_ULONG in[P256_LIMBS]);
++/* Functions that perform constant time access to the precomputed tables */
++void ecp_nistz256_scatter_w5(P256_POINT *val,
++                             const P256_POINT *in_t, int idx);
++void ecp_nistz256_gather_w5(P256_POINT *val,
++                            const P256_POINT *in_t, int idx);
++void ecp_nistz256_scatter_w7(P256_POINT_AFFINE *val,
++                             const P256_POINT_AFFINE *in_t, int idx);
++void ecp_nistz256_gather_w7(P256_POINT_AFFINE *val,
++                            const P256_POINT_AFFINE *in_t, int idx);
++
++/* One converted into the Montgomery domain */
++static const BN_ULONG ONE[P256_LIMBS] = {
++    TOBN(0x00000000, 0x00000001), TOBN(0xffffffff, 0x00000000),
++    TOBN(0xffffffff, 0xffffffff), TOBN(0x00000000, 0xfffffffe)
++};
++
++static NISTZ256_PRE_COMP *ecp_nistz256_pre_comp_new(const EC_GROUP *group);
++
++/* Precomputed tables for the default generator */
++extern const PRECOMP256_ROW ecp_nistz256_precomputed[37];
++
++/* Recode window to a signed digit, see ecp_nistputil.c for details */
++static unsigned int _booth_recode_w5(unsigned int in)
++{
++    unsigned int s, d;
++
++    s = ~((in >> 5) - 1);
++    d = (1 << 6) - in - 1;
++    d = (d & s) | (in & ~s);
++    d = (d >> 1) + (d & 1);
++
++    return (d << 1) + (s & 1);
++}
++
++static unsigned int _booth_recode_w7(unsigned int in)
++{
++    unsigned int s, d;
++
++    s = ~((in >> 7) - 1);
++    d = (1 << 8) - in - 1;
++    d = (d & s) | (in & ~s);
++    d = (d >> 1) + (d & 1);
++
++    return (d << 1) + (s & 1);
++}
++
++static void copy_conditional(BN_ULONG dst[P256_LIMBS],
++                             const BN_ULONG src[P256_LIMBS], BN_ULONG move)
++{
++    BN_ULONG mask1 = 0-move;
++    BN_ULONG mask2 = ~mask1;
++
++    dst[0] = (src[0] & mask1) ^ (dst[0] & mask2);
++    dst[1] = (src[1] & mask1) ^ (dst[1] & mask2);
++    dst[2] = (src[2] & mask1) ^ (dst[2] & mask2);
++    dst[3] = (src[3] & mask1) ^ (dst[3] & mask2);
++    if (P256_LIMBS == 8) {
++        dst[4] = (src[4] & mask1) ^ (dst[4] & mask2);
++        dst[5] = (src[5] & mask1) ^ (dst[5] & mask2);
++        dst[6] = (src[6] & mask1) ^ (dst[6] & mask2);
++        dst[7] = (src[7] & mask1) ^ (dst[7] & mask2);
++    }
++}
++
++static BN_ULONG is_zero(BN_ULONG in)
++{
++    in |= (0 - in);
++    in = ~in;
++    in >>= BN_BITS2 - 1;
++    return in;
++}
++
++static BN_ULONG is_equal(const BN_ULONG a[P256_LIMBS],
++                         const BN_ULONG b[P256_LIMBS])
++{
++    BN_ULONG res;
++
++    res = a[0] ^ b[0];
++    res |= a[1] ^ b[1];
++    res |= a[2] ^ b[2];
++    res |= a[3] ^ b[3];
++    if (P256_LIMBS == 8) {
++        res |= a[4] ^ b[4];
++        res |= a[5] ^ b[5];
++        res |= a[6] ^ b[6];
++        res |= a[7] ^ b[7];
++    }
++
++    return is_zero(res);
++}
++
++static BN_ULONG is_one(const BIGNUM *z)
++{
++    BN_ULONG res = 0;
++    BN_ULONG *a = bn_get_words(z);
++
++    if (bn_get_top(z) == (P256_LIMBS - P256_LIMBS / 8)) {
++        res = a[0] ^ ONE[0];
++        res |= a[1] ^ ONE[1];
++        res |= a[2] ^ ONE[2];
++        res |= a[3] ^ ONE[3];
++        if (P256_LIMBS == 8) {
++            res |= a[4] ^ ONE[4];
++            res |= a[5] ^ ONE[5];
++            res |= a[6] ^ ONE[6];
++            /*
++             * no check for a[7] (being zero) on 32-bit platforms,
++             * because value of "one" takes only 7 limbs.
++             */
++        }
++        res = is_zero(res);
++    }
++
++    return res;
++}
++
++#ifndef ECP_NISTZ256_REFERENCE_IMPLEMENTATION
++void ecp_nistz256_point_double(P256_POINT *r, const P256_POINT *a);
++void ecp_nistz256_point_add(P256_POINT *r,
++                            const P256_POINT *a, const P256_POINT *b);
++void ecp_nistz256_point_add_affine(P256_POINT *r,
++                                   const P256_POINT *a,
++                                   const P256_POINT_AFFINE *b);
++#else
++/* Point double: r = 2*a */
++static void ecp_nistz256_point_double(P256_POINT *r, const P256_POINT *a)
++{
++    BN_ULONG S[P256_LIMBS];
++    BN_ULONG M[P256_LIMBS];
++    BN_ULONG Zsqr[P256_LIMBS];
++    BN_ULONG tmp0[P256_LIMBS];
++
++    const BN_ULONG *in_x = a->X;
++    const BN_ULONG *in_y = a->Y;
++    const BN_ULONG *in_z = a->Z;
++
++    BN_ULONG *res_x = r->X;
++    BN_ULONG *res_y = r->Y;
++    BN_ULONG *res_z = r->Z;
++
++    ecp_nistz256_mul_by_2(S, in_y);
++
++    ecp_nistz256_sqr_mont(Zsqr, in_z);
++
++    ecp_nistz256_sqr_mont(S, S);
++
++    ecp_nistz256_mul_mont(res_z, in_z, in_y);
++    ecp_nistz256_mul_by_2(res_z, res_z);
++
++    ecp_nistz256_add(M, in_x, Zsqr);
++    ecp_nistz256_sub(Zsqr, in_x, Zsqr);
++
++    ecp_nistz256_sqr_mont(res_y, S);
++    ecp_nistz256_div_by_2(res_y, res_y);
++
++    ecp_nistz256_mul_mont(M, M, Zsqr);
++    ecp_nistz256_mul_by_3(M, M);
++
++    ecp_nistz256_mul_mont(S, S, in_x);
++    ecp_nistz256_mul_by_2(tmp0, S);
++
++    ecp_nistz256_sqr_mont(res_x, M);
++
++    ecp_nistz256_sub(res_x, res_x, tmp0);
++    ecp_nistz256_sub(S, S, res_x);
++
++    ecp_nistz256_mul_mont(S, S, M);
++    ecp_nistz256_sub(res_y, S, res_y);
++}
++
++/* Point addition: r = a+b */
++static void ecp_nistz256_point_add(P256_POINT *r,
++                                   const P256_POINT *a, const P256_POINT *b)
++{
++    BN_ULONG U2[P256_LIMBS], S2[P256_LIMBS];
++    BN_ULONG U1[P256_LIMBS], S1[P256_LIMBS];
++    BN_ULONG Z1sqr[P256_LIMBS];
++    BN_ULONG Z2sqr[P256_LIMBS];
++    BN_ULONG H[P256_LIMBS], R[P256_LIMBS];
++    BN_ULONG Hsqr[P256_LIMBS];
++    BN_ULONG Rsqr[P256_LIMBS];
++    BN_ULONG Hcub[P256_LIMBS];
++
++    BN_ULONG res_x[P256_LIMBS];
++    BN_ULONG res_y[P256_LIMBS];
++    BN_ULONG res_z[P256_LIMBS];
++
++    BN_ULONG in1infty, in2infty;
++
++    const BN_ULONG *in1_x = a->X;
++    const BN_ULONG *in1_y = a->Y;
++    const BN_ULONG *in1_z = a->Z;
++
++    const BN_ULONG *in2_x = b->X;
++    const BN_ULONG *in2_y = b->Y;
++    const BN_ULONG *in2_z = b->Z;
++
++    /*
++     * Infinity in encoded as (,,0)
++     */
++    in1infty = (in1_z[0] | in1_z[1] | in1_z[2] | in1_z[3]);
++    if (P256_LIMBS == 8)
++        in1infty |= (in1_z[4] | in1_z[5] | in1_z[6] | in1_z[7]);
++
++    in2infty = (in2_z[0] | in2_z[1] | in2_z[2] | in2_z[3]);
++    if (P256_LIMBS == 8)
++        in2infty |= (in2_z[4] | in2_z[5] | in2_z[6] | in2_z[7]);
++
++    in1infty = is_zero(in1infty);
++    in2infty = is_zero(in2infty);
++
++    ecp_nistz256_sqr_mont(Z2sqr, in2_z);        /* Z2^2 */
++    ecp_nistz256_sqr_mont(Z1sqr, in1_z);        /* Z1^2 */
++
++    ecp_nistz256_mul_mont(S1, Z2sqr, in2_z);    /* S1 = Z2^3 */
++    ecp_nistz256_mul_mont(S2, Z1sqr, in1_z);    /* S2 = Z1^3 */
++
++    ecp_nistz256_mul_mont(S1, S1, in1_y);       /* S1 = Y1*Z2^3 */
++    ecp_nistz256_mul_mont(S2, S2, in2_y);       /* S2 = Y2*Z1^3 */
++    ecp_nistz256_sub(R, S2, S1);                /* R = S2 - S1 */
++
++    ecp_nistz256_mul_mont(U1, in1_x, Z2sqr);    /* U1 = X1*Z2^2 */
++    ecp_nistz256_mul_mont(U2, in2_x, Z1sqr);    /* U2 = X2*Z1^2 */
++    ecp_nistz256_sub(H, U2, U1);                /* H = U2 - U1 */
++
++    /*
++     * This should not happen during sign/ecdh, so no constant time violation
++     */
++    if (is_equal(U1, U2) && !in1infty && !in2infty) {
++        if (is_equal(S1, S2)) {
++            ecp_nistz256_point_double(r, a);
++            return;
++        } else {
++            memset(r, 0, sizeof(*r));
++            return;
++        }
++    }
++
++    ecp_nistz256_sqr_mont(Rsqr, R);             /* R^2 */
++    ecp_nistz256_mul_mont(res_z, H, in1_z);     /* Z3 = H*Z1*Z2 */
++    ecp_nistz256_sqr_mont(Hsqr, H);             /* H^2 */
++    ecp_nistz256_mul_mont(res_z, res_z, in2_z); /* Z3 = H*Z1*Z2 */
++    ecp_nistz256_mul_mont(Hcub, Hsqr, H);       /* H^3 */
++
++    ecp_nistz256_mul_mont(U2, U1, Hsqr);        /* U1*H^2 */
++    ecp_nistz256_mul_by_2(Hsqr, U2);            /* 2*U1*H^2 */
++
++    ecp_nistz256_sub(res_x, Rsqr, Hsqr);
++    ecp_nistz256_sub(res_x, res_x, Hcub);
++
++    ecp_nistz256_sub(res_y, U2, res_x);
++
++    ecp_nistz256_mul_mont(S2, S1, Hcub);
++    ecp_nistz256_mul_mont(res_y, R, res_y);
++    ecp_nistz256_sub(res_y, res_y, S2);
++
++    copy_conditional(res_x, in2_x, in1infty);
++    copy_conditional(res_y, in2_y, in1infty);
++    copy_conditional(res_z, in2_z, in1infty);
++
++    copy_conditional(res_x, in1_x, in2infty);
++    copy_conditional(res_y, in1_y, in2infty);
++    copy_conditional(res_z, in1_z, in2infty);
++
++    memcpy(r->X, res_x, sizeof(res_x));
++    memcpy(r->Y, res_y, sizeof(res_y));
++    memcpy(r->Z, res_z, sizeof(res_z));
++}
++
++/* Point addition when b is known to be affine: r = a+b */
++static void ecp_nistz256_point_add_affine(P256_POINT *r,
++                                          const P256_POINT *a,
++                                          const P256_POINT_AFFINE *b)
++{
++    BN_ULONG U2[P256_LIMBS], S2[P256_LIMBS];
++    BN_ULONG Z1sqr[P256_LIMBS];
++    BN_ULONG H[P256_LIMBS], R[P256_LIMBS];
++    BN_ULONG Hsqr[P256_LIMBS];
++    BN_ULONG Rsqr[P256_LIMBS];
++    BN_ULONG Hcub[P256_LIMBS];
++
++    BN_ULONG res_x[P256_LIMBS];
++    BN_ULONG res_y[P256_LIMBS];
++    BN_ULONG res_z[P256_LIMBS];
++
++    BN_ULONG in1infty, in2infty;
++
++    const BN_ULONG *in1_x = a->X;
++    const BN_ULONG *in1_y = a->Y;
++    const BN_ULONG *in1_z = a->Z;
++
++    const BN_ULONG *in2_x = b->X;
++    const BN_ULONG *in2_y = b->Y;
++
++    /*
++     * Infinity in encoded as (,,0)
++     */
++    in1infty = (in1_z[0] | in1_z[1] | in1_z[2] | in1_z[3]);
++    if (P256_LIMBS == 8)
++        in1infty |= (in1_z[4] | in1_z[5] | in1_z[6] | in1_z[7]);
++
++    /*
++     * In affine representation we encode infinity as (0,0), which is
++     * not on the curve, so it is OK
++     */
++    in2infty = (in2_x[0] | in2_x[1] | in2_x[2] | in2_x[3] |
++                in2_y[0] | in2_y[1] | in2_y[2] | in2_y[3]);
++    if (P256_LIMBS == 8)
++        in2infty |= (in2_x[4] | in2_x[5] | in2_x[6] | in2_x[7] |
++                     in2_y[4] | in2_y[5] | in2_y[6] | in2_y[7]);
++
++    in1infty = is_zero(in1infty);
++    in2infty = is_zero(in2infty);
++
++    ecp_nistz256_sqr_mont(Z1sqr, in1_z);        /* Z1^2 */
++
++    ecp_nistz256_mul_mont(U2, in2_x, Z1sqr);    /* U2 = X2*Z1^2 */
++    ecp_nistz256_sub(H, U2, in1_x);             /* H = U2 - U1 */
++
++    ecp_nistz256_mul_mont(S2, Z1sqr, in1_z);    /* S2 = Z1^3 */
++
++    ecp_nistz256_mul_mont(res_z, H, in1_z);     /* Z3 = H*Z1*Z2 */
++
++    ecp_nistz256_mul_mont(S2, S2, in2_y);       /* S2 = Y2*Z1^3 */
++    ecp_nistz256_sub(R, S2, in1_y);             /* R = S2 - S1 */
++
++    ecp_nistz256_sqr_mont(Hsqr, H);             /* H^2 */
++    ecp_nistz256_sqr_mont(Rsqr, R);             /* R^2 */
++    ecp_nistz256_mul_mont(Hcub, Hsqr, H);       /* H^3 */
++
++    ecp_nistz256_mul_mont(U2, in1_x, Hsqr);     /* U1*H^2 */
++    ecp_nistz256_mul_by_2(Hsqr, U2);            /* 2*U1*H^2 */
++
++    ecp_nistz256_sub(res_x, Rsqr, Hsqr);
++    ecp_nistz256_sub(res_x, res_x, Hcub);
++    ecp_nistz256_sub(H, U2, res_x);
++
++    ecp_nistz256_mul_mont(S2, in1_y, Hcub);
++    ecp_nistz256_mul_mont(H, H, R);
++    ecp_nistz256_sub(res_y, H, S2);
++
++    copy_conditional(res_x, in2_x, in1infty);
++    copy_conditional(res_x, in1_x, in2infty);
++
++    copy_conditional(res_y, in2_y, in1infty);
++    copy_conditional(res_y, in1_y, in2infty);
++
++    copy_conditional(res_z, ONE, in1infty);
++    copy_conditional(res_z, in1_z, in2infty);
++
++    memcpy(r->X, res_x, sizeof(res_x));
++    memcpy(r->Y, res_y, sizeof(res_y));
++    memcpy(r->Z, res_z, sizeof(res_z));
++}
++#endif
++
++/* r = in^-1 mod p */
++static void ecp_nistz256_mod_inverse(BN_ULONG r[P256_LIMBS],
++                                     const BN_ULONG in[P256_LIMBS])
++{
++    /*
++     * The poly is ffffffff 00000001 00000000 00000000 00000000 ffffffff
++     * ffffffff ffffffff We use FLT and used poly-2 as exponent
++     */
++    BN_ULONG p2[P256_LIMBS];
++    BN_ULONG p4[P256_LIMBS];
++    BN_ULONG p8[P256_LIMBS];
++    BN_ULONG p16[P256_LIMBS];
++    BN_ULONG p32[P256_LIMBS];
++    BN_ULONG res[P256_LIMBS];
++    int i;
++
++    ecp_nistz256_sqr_mont(res, in);
++    ecp_nistz256_mul_mont(p2, res, in);         /* 3*p */
++
++    ecp_nistz256_sqr_mont(res, p2);
++    ecp_nistz256_sqr_mont(res, res);
++    ecp_nistz256_mul_mont(p4, res, p2);         /* f*p */
++
++    ecp_nistz256_sqr_mont(res, p4);
++    ecp_nistz256_sqr_mont(res, res);
++    ecp_nistz256_sqr_mont(res, res);
++    ecp_nistz256_sqr_mont(res, res);
++    ecp_nistz256_mul_mont(p8, res, p4);         /* ff*p */
++
++    ecp_nistz256_sqr_mont(res, p8);
++    for (i = 0; i < 7; i++)
++        ecp_nistz256_sqr_mont(res, res);
++    ecp_nistz256_mul_mont(p16, res, p8);        /* ffff*p */
++
++    ecp_nistz256_sqr_mont(res, p16);
++    for (i = 0; i < 15; i++)
++        ecp_nistz256_sqr_mont(res, res);
++    ecp_nistz256_mul_mont(p32, res, p16);       /* ffffffff*p */
++
++    ecp_nistz256_sqr_mont(res, p32);
++    for (i = 0; i < 31; i++)
++        ecp_nistz256_sqr_mont(res, res);
++    ecp_nistz256_mul_mont(res, res, in);
++
++    for (i = 0; i < 32 * 4; i++)
++        ecp_nistz256_sqr_mont(res, res);
++    ecp_nistz256_mul_mont(res, res, p32);
++
++    for (i = 0; i < 32; i++)
++        ecp_nistz256_sqr_mont(res, res);
++    ecp_nistz256_mul_mont(res, res, p32);
++
++    for (i = 0; i < 16; i++)
++        ecp_nistz256_sqr_mont(res, res);
++    ecp_nistz256_mul_mont(res, res, p16);
++
++    for (i = 0; i < 8; i++)
++        ecp_nistz256_sqr_mont(res, res);
++    ecp_nistz256_mul_mont(res, res, p8);
++
++    ecp_nistz256_sqr_mont(res, res);
++    ecp_nistz256_sqr_mont(res, res);
++    ecp_nistz256_sqr_mont(res, res);
++    ecp_nistz256_sqr_mont(res, res);
++    ecp_nistz256_mul_mont(res, res, p4);
++
++    ecp_nistz256_sqr_mont(res, res);
++    ecp_nistz256_sqr_mont(res, res);
++    ecp_nistz256_mul_mont(res, res, p2);
++
++    ecp_nistz256_sqr_mont(res, res);
++    ecp_nistz256_sqr_mont(res, res);
++    ecp_nistz256_mul_mont(res, res, in);
++
++    memcpy(r, res, sizeof(res));
++}
++
++/*
++ * ecp_nistz256_bignum_to_field_elem copies the contents of |in| to |out| and
++ * returns one if it fits. Otherwise it returns zero.
++ */
++__owur static int ecp_nistz256_bignum_to_field_elem(BN_ULONG out[P256_LIMBS],
++                                                    const BIGNUM *in)
++{
++    return bn_copy_words(out, in, P256_LIMBS);
++}
++
++/* r = sum(scalar[i]*point[i]) */
++__owur static int ecp_nistz256_windowed_mul(const EC_GROUP *group,
++                                            P256_POINT *r,
++                                            const BIGNUM **scalar,
++                                            const EC_POINT **point,
++                                            size_t num, BN_CTX *ctx)
++{
++    size_t i;
++    int j, ret = 0;
++    unsigned int idx;
++    unsigned char (*p_str)[33] = NULL;
++    const unsigned int window_size = 5;
++    const unsigned int mask = (1 << (window_size + 1)) - 1;
++    unsigned int wvalue;
++    P256_POINT *temp;           /* place for 5 temporary points */
++    const BIGNUM **scalars = NULL;
++    P256_POINT (*table)[16] = NULL;
++    void *table_storage = NULL;
++
++    if ((num * 16 + 6) > OPENSSL_MALLOC_MAX_NELEMS(P256_POINT)
++        || (table_storage =
++            OPENSSL_malloc((num * 16 + 5) * sizeof(P256_POINT) + 64)) == NULL
++        || (p_str =
++            OPENSSL_malloc(num * 33 * sizeof(unsigned char))) == NULL
++        || (scalars = OPENSSL_malloc(num * sizeof(BIGNUM *))) == NULL) {
++        ECerr(EC_F_ECP_NISTZ256_WINDOWED_MUL, ERR_R_MALLOC_FAILURE);
++        goto err;
++    }
++
++    table = (void *)ALIGNPTR(table_storage, 64);
++    temp = (P256_POINT *)(table + num);
++
++    for (i = 0; i < num; i++) {
++        P256_POINT *row = table[i];
++
++        /* This is an unusual input, we don't guarantee constant-timeness. */
++        if ((BN_num_bits(scalar[i]) > 256) || BN_is_negative(scalar[i])) {
++            BIGNUM *mod;
++
++            if ((mod = BN_CTX_get(ctx)) == NULL)
++                goto err;
++            if (!BN_nnmod(mod, scalar[i], group->order, ctx)) {
++                ECerr(EC_F_ECP_NISTZ256_WINDOWED_MUL, ERR_R_BN_LIB);
++                goto err;
++            }
++            scalars[i] = mod;
++        } else
++            scalars[i] = scalar[i];
++
++        for (j = 0; j < bn_get_top(scalars[i]) * BN_BYTES; j += BN_BYTES) {
++            BN_ULONG d = bn_get_words(scalars[i])[j / BN_BYTES];
++
++            p_str[i][j + 0] = (unsigned char)d;
++            p_str[i][j + 1] = (unsigned char)(d >> 8);
++            p_str[i][j + 2] = (unsigned char)(d >> 16);
++            p_str[i][j + 3] = (unsigned char)(d >>= 24);
++            if (BN_BYTES == 8) {
++                d >>= 8;
++                p_str[i][j + 4] = (unsigned char)d;
++                p_str[i][j + 5] = (unsigned char)(d >> 8);
++                p_str[i][j + 6] = (unsigned char)(d >> 16);
++                p_str[i][j + 7] = (unsigned char)(d >> 24);
++            }
++        }
++        for (; j < 33; j++)
++            p_str[i][j] = 0;
++
++        if (!ecp_nistz256_bignum_to_field_elem(temp[0].X, point[i]->X)
++            || !ecp_nistz256_bignum_to_field_elem(temp[0].Y, point[i]->Y)
++            || !ecp_nistz256_bignum_to_field_elem(temp[0].Z, point[i]->Z)) {
++            ECerr(EC_F_ECP_NISTZ256_WINDOWED_MUL,
++                  EC_R_COORDINATES_OUT_OF_RANGE);
++            goto err;
++        }
++
++        /*
++         * row[0] is implicitly (0,0,0) (the point at infinity), therefore it
++         * is not stored. All other values are actually stored with an offset
++         * of -1 in table.
++         */
++
++        ecp_nistz256_scatter_w5  (row, &temp[0], 1);
++        ecp_nistz256_point_double(&temp[1], &temp[0]);              /*1+1=2  */
++        ecp_nistz256_scatter_w5  (row, &temp[1], 2);
++        ecp_nistz256_point_add   (&temp[2], &temp[1], &temp[0]);    /*2+1=3  */
++        ecp_nistz256_scatter_w5  (row, &temp[2], 3);
++        ecp_nistz256_point_double(&temp[1], &temp[1]);              /*2*2=4  */
++        ecp_nistz256_scatter_w5  (row, &temp[1], 4);
++        ecp_nistz256_point_double(&temp[2], &temp[2]);              /*2*3=6  */
++        ecp_nistz256_scatter_w5  (row, &temp[2], 6);
++        ecp_nistz256_point_add   (&temp[3], &temp[1], &temp[0]);    /*4+1=5  */
++        ecp_nistz256_scatter_w5  (row, &temp[3], 5);
++        ecp_nistz256_point_add   (&temp[4], &temp[2], &temp[0]);    /*6+1=7  */
++        ecp_nistz256_scatter_w5  (row, &temp[4], 7);
++        ecp_nistz256_point_double(&temp[1], &temp[1]);              /*2*4=8  */
++        ecp_nistz256_scatter_w5  (row, &temp[1], 8);
++        ecp_nistz256_point_double(&temp[2], &temp[2]);              /*2*6=12 */
++        ecp_nistz256_scatter_w5  (row, &temp[2], 12);
++        ecp_nistz256_point_double(&temp[3], &temp[3]);              /*2*5=10 */
++        ecp_nistz256_scatter_w5  (row, &temp[3], 10);
++        ecp_nistz256_point_double(&temp[4], &temp[4]);              /*2*7=14 */
++        ecp_nistz256_scatter_w5  (row, &temp[4], 14);
++        ecp_nistz256_point_add   (&temp[2], &temp[2], &temp[0]);    /*12+1=13*/
++        ecp_nistz256_scatter_w5  (row, &temp[2], 13);
++        ecp_nistz256_point_add   (&temp[3], &temp[3], &temp[0]);    /*10+1=11*/
++        ecp_nistz256_scatter_w5  (row, &temp[3], 11);
++        ecp_nistz256_point_add   (&temp[4], &temp[4], &temp[0]);    /*14+1=15*/
++        ecp_nistz256_scatter_w5  (row, &temp[4], 15);
++        ecp_nistz256_point_add   (&temp[2], &temp[1], &temp[0]);    /*8+1=9  */
++        ecp_nistz256_scatter_w5  (row, &temp[2], 9);
++        ecp_nistz256_point_double(&temp[1], &temp[1]);              /*2*8=16 */
++        ecp_nistz256_scatter_w5  (row, &temp[1], 16);
++    }
++
++    idx = 255;
++
++    wvalue = p_str[0][(idx - 1) / 8];
++    wvalue = (wvalue >> ((idx - 1) % 8)) & mask;
++
++    /*
++     * We gather to temp[0], because we know it's position relative
++     * to table
++     */
++    ecp_nistz256_gather_w5(&temp[0], table[0], _booth_recode_w5(wvalue) >> 1);
++    memcpy(r, &temp[0], sizeof(temp[0]));
++
++    while (idx >= 5) {
++        for (i = (idx == 255 ? 1 : 0); i < num; i++) {
++            unsigned int off = (idx - 1) / 8;
++
++            wvalue = p_str[i][off] | p_str[i][off + 1] << 8;
++            wvalue = (wvalue >> ((idx - 1) % 8)) & mask;
++
++            wvalue = _booth_recode_w5(wvalue);
++
++            ecp_nistz256_gather_w5(&temp[0], table[i], wvalue >> 1);
++
++            ecp_nistz256_neg(temp[1].Y, temp[0].Y);
++            copy_conditional(temp[0].Y, temp[1].Y, (wvalue & 1));
++
++            ecp_nistz256_point_add(r, r, &temp[0]);
++        }
++
++        idx -= window_size;
++
++        ecp_nistz256_point_double(r, r);
++        ecp_nistz256_point_double(r, r);
++        ecp_nistz256_point_double(r, r);
++        ecp_nistz256_point_double(r, r);
++        ecp_nistz256_point_double(r, r);
++    }
++
++    /* Final window */
++    for (i = 0; i < num; i++) {
++        wvalue = p_str[i][0];
++        wvalue = (wvalue << 1) & mask;
++
++        wvalue = _booth_recode_w5(wvalue);
++
++        ecp_nistz256_gather_w5(&temp[0], table[i], wvalue >> 1);
++
++        ecp_nistz256_neg(temp[1].Y, temp[0].Y);
++        copy_conditional(temp[0].Y, temp[1].Y, wvalue & 1);
++
++        ecp_nistz256_point_add(r, r, &temp[0]);
++    }
++
++    ret = 1;
++ err:
++    OPENSSL_free(table_storage);
++    OPENSSL_free(p_str);
++    OPENSSL_free(scalars);
++    return ret;
++}
++
++/* Coordinates of G, for which we have precomputed tables */
++const static BN_ULONG def_xG[P256_LIMBS] = {
++    TOBN(0x79e730d4, 0x18a9143c), TOBN(0x75ba95fc, 0x5fedb601),
++    TOBN(0x79fb732b, 0x77622510), TOBN(0x18905f76, 0xa53755c6)
++};
++
++const static BN_ULONG def_yG[P256_LIMBS] = {
++    TOBN(0xddf25357, 0xce95560a), TOBN(0x8b4ab8e4, 0xba19e45c),
++    TOBN(0xd2e88688, 0xdd21f325), TOBN(0x8571ff18, 0x25885d85)
++};
++
++/*
++ * ecp_nistz256_is_affine_G returns one if |generator| is the standard, P-256
++ * generator.
++ */
++static int ecp_nistz256_is_affine_G(const EC_POINT *generator)
++{
++    return (bn_get_top(generator->X) == P256_LIMBS) &&
++        (bn_get_top(generator->Y) == P256_LIMBS) &&
++        is_equal(bn_get_words(generator->X), def_xG) &&
++        is_equal(bn_get_words(generator->Y), def_yG) &&
++        is_one(generator->Z);
++}
++
++__owur static int ecp_nistz256_mult_precompute(EC_GROUP *group, BN_CTX *ctx)
++{
++    /*
++     * We precompute a table for a Booth encoded exponent (wNAF) based
++     * computation. Each table holds 64 values for safe access, with an
++     * implicit value of infinity at index zero. We use window of size 7, and
++     * therefore require ceil(256/7) = 37 tables.
++     */
++    const BIGNUM *order;
++    EC_POINT *P = NULL, *T = NULL;
++    const EC_POINT *generator;
++    NISTZ256_PRE_COMP *pre_comp;
++    BN_CTX *new_ctx = NULL;
++    int i, j, k, ret = 0;
++    size_t w;
++
++    PRECOMP256_ROW *preComputedTable = NULL;
++    unsigned char *precomp_storage = NULL;
++
++    /* if there is an old NISTZ256_PRE_COMP object, throw it away */
++    EC_pre_comp_free(group);
++    generator = EC_GROUP_get0_generator(group);
++    if (generator == NULL) {
++        ECerr(EC_F_ECP_NISTZ256_MULT_PRECOMPUTE, EC_R_UNDEFINED_GENERATOR);
++        return 0;
++    }
++
++    if (ecp_nistz256_is_affine_G(generator)) {
++        /*
++         * No need to calculate tables for the standard generator because we
++         * have them statically.
++         */
++        return 1;
++    }
++
++    if ((pre_comp = ecp_nistz256_pre_comp_new(group)) == NULL)
++        return 0;
++
++    if (ctx == NULL) {
++        ctx = new_ctx = BN_CTX_new();
++        if (ctx == NULL)
++            goto err;
++    }
++
++    BN_CTX_start(ctx);
++
++    order = EC_GROUP_get0_order(group);
++    if (order == NULL)
++        goto err;
++
++    if (BN_is_zero(order)) {
++        ECerr(EC_F_ECP_NISTZ256_MULT_PRECOMPUTE, EC_R_UNKNOWN_ORDER);
++        goto err;
++    }
++
++    w = 7;
++
++    if ((precomp_storage =
++         OPENSSL_malloc(37 * 64 * sizeof(P256_POINT_AFFINE) + 64)) == NULL) {
++        ECerr(EC_F_ECP_NISTZ256_MULT_PRECOMPUTE, ERR_R_MALLOC_FAILURE);
++        goto err;
++    }
++
++    preComputedTable = (void *)ALIGNPTR(precomp_storage, 64);
++
++    P = EC_POINT_new(group);
++    T = EC_POINT_new(group);
++    if (P == NULL || T == NULL)
++        goto err;
++
++    /*
++     * The zero entry is implicitly infinity, and we skip it, storing other
++     * values with -1 offset.
++     */
++    if (!EC_POINT_copy(T, generator))
++        goto err;
++
++    for (k = 0; k < 64; k++) {
++        if (!EC_POINT_copy(P, T))
++            goto err;
++        for (j = 0; j < 37; j++) {
++            P256_POINT_AFFINE temp;
++            /*
++             * It would be faster to use EC_POINTs_make_affine and
++             * make multiple points affine at the same time.
++             */
++            if (!EC_POINT_make_affine(group, P, ctx))
++                goto err;
++            if (!ecp_nistz256_bignum_to_field_elem(temp.X, P->X) ||
++                !ecp_nistz256_bignum_to_field_elem(temp.Y, P->Y)) {
++                ECerr(EC_F_ECP_NISTZ256_MULT_PRECOMPUTE,
++                      EC_R_COORDINATES_OUT_OF_RANGE);
++                goto err;
++            }
++            ecp_nistz256_scatter_w7(preComputedTable[j], &temp, k);
++            for (i = 0; i < 7; i++) {
++                if (!EC_POINT_dbl(group, P, P, ctx))
++                    goto err;
++            }
++        }
++        if (!EC_POINT_add(group, T, T, generator, ctx))
++            goto err;
++    }
++
++    pre_comp->group = group;
++    pre_comp->w = w;
++    pre_comp->precomp = preComputedTable;
++    pre_comp->precomp_storage = precomp_storage;
++    precomp_storage = NULL;
++    SETPRECOMP(group, nistz256, pre_comp);
++    pre_comp = NULL;
++    ret = 1;
++
++ err:
++    if (ctx != NULL)
++        BN_CTX_end(ctx);
++    BN_CTX_free(new_ctx);
++
++    EC_nistz256_pre_comp_free(pre_comp);
++    OPENSSL_free(precomp_storage);
++    EC_POINT_free(P);
++    EC_POINT_free(T);
++    return ret;
++}
++
++/*
++ * Note that by default ECP_NISTZ256_AVX2 is undefined. While it's great
++ * code processing 4 points in parallel, corresponding serial operation
++ * is several times slower, because it uses 29x29=58-bit multiplication
++ * as opposite to 64x64=128-bit in integer-only scalar case. As result
++ * it doesn't provide *significant* performance improvement. Note that
++ * just defining ECP_NISTZ256_AVX2 is not sufficient to make it work,
++ * you'd need to compile even asm/ecp_nistz256-avx.pl module.
++ */
++#if defined(ECP_NISTZ256_AVX2)
++# if !(defined(__x86_64) || defined(__x86_64__) || \
++       defined(_M_AMD64) || defined(_MX64)) || \
++     !(defined(__GNUC__) || defined(_MSC_VER)) /* this is for ALIGN32 */
++#  undef ECP_NISTZ256_AVX2
++# else
++/* Constant time access, loading four values, from four consecutive tables */
++void ecp_nistz256_avx2_multi_gather_w7(void *result, const void *in,
++                                       int index0, int index1, int index2,
++                                       int index3);
++void ecp_nistz256_avx2_transpose_convert(void *RESULTx4, const void *in);
++void ecp_nistz256_avx2_convert_transpose_back(void *result, const void *Ax4);
++void ecp_nistz256_avx2_point_add_affine_x4(void *RESULTx4, const void *Ax4,
++                                           const void *Bx4);
++void ecp_nistz256_avx2_point_add_affines_x4(void *RESULTx4, const void *Ax4,
++                                            const void *Bx4);
++void ecp_nistz256_avx2_to_mont(void *RESULTx4, const void *Ax4);
++void ecp_nistz256_avx2_from_mont(void *RESULTx4, const void *Ax4);
++void ecp_nistz256_avx2_set1(void *RESULTx4);
++int ecp_nistz_avx2_eligible(void);
++
++static void booth_recode_w7(unsigned char *sign,
++                            unsigned char *digit, unsigned char in)
++{
++    unsigned char s, d;
++
++    s = ~((in >> 7) - 1);
++    d = (1 << 8) - in - 1;
++    d = (d & s) | (in & ~s);
++    d = (d >> 1) + (d & 1);
++
++    *sign = s & 1;
++    *digit = d;
++}
++
++/*
++ * ecp_nistz256_avx2_mul_g performs multiplication by G, using only the
++ * precomputed table. It does 4 affine point additions in parallel,
++ * significantly speeding up point multiplication for a fixed value.
++ */
++static void ecp_nistz256_avx2_mul_g(P256_POINT *r,
++                                    unsigned char p_str[33],
++                                    const P256_POINT_AFFINE(*preComputedTable)[64])
++{
++    const unsigned int window_size = 7;
++    const unsigned int mask = (1 << (window_size + 1)) - 1;
++    unsigned int wvalue;
++    /* Using 4 windows at a time */
++    unsigned char sign0, digit0;
++    unsigned char sign1, digit1;
++    unsigned char sign2, digit2;
++    unsigned char sign3, digit3;
++    unsigned int idx = 0;
++    BN_ULONG tmp[P256_LIMBS];
++    int i;
++
++    ALIGN32 BN_ULONG aX4[4 * 9 * 3] = { 0 };
++    ALIGN32 BN_ULONG bX4[4 * 9 * 2] = { 0 };
++    ALIGN32 P256_POINT_AFFINE point_arr[4];
++    ALIGN32 P256_POINT res_point_arr[4];
++
++    /* Initial four windows */
++    wvalue = *((u16 *) & p_str[0]);
++    wvalue = (wvalue << 1) & mask;
++    idx += window_size;
++    booth_recode_w7(&sign0, &digit0, wvalue);
++    wvalue = *((u16 *) & p_str[(idx - 1) / 8]);
++    wvalue = (wvalue >> ((idx - 1) % 8)) & mask;
++    idx += window_size;
++    booth_recode_w7(&sign1, &digit1, wvalue);
++    wvalue = *((u16 *) & p_str[(idx - 1) / 8]);
++    wvalue = (wvalue >> ((idx - 1) % 8)) & mask;
++    idx += window_size;
++    booth_recode_w7(&sign2, &digit2, wvalue);
++    wvalue = *((u16 *) & p_str[(idx - 1) / 8]);
++    wvalue = (wvalue >> ((idx - 1) % 8)) & mask;
++    idx += window_size;
++    booth_recode_w7(&sign3, &digit3, wvalue);
++
++    ecp_nistz256_avx2_multi_gather_w7(point_arr, preComputedTable[0],
++                                      digit0, digit1, digit2, digit3);
++
++    ecp_nistz256_neg(tmp, point_arr[0].Y);
++    copy_conditional(point_arr[0].Y, tmp, sign0);
++    ecp_nistz256_neg(tmp, point_arr[1].Y);
++    copy_conditional(point_arr[1].Y, tmp, sign1);
++    ecp_nistz256_neg(tmp, point_arr[2].Y);
++    copy_conditional(point_arr[2].Y, tmp, sign2);
++    ecp_nistz256_neg(tmp, point_arr[3].Y);
++    copy_conditional(point_arr[3].Y, tmp, sign3);
++
++    ecp_nistz256_avx2_transpose_convert(aX4, point_arr);
++    ecp_nistz256_avx2_to_mont(aX4, aX4);
++    ecp_nistz256_avx2_to_mont(&aX4[4 * 9], &aX4[4 * 9]);
++    ecp_nistz256_avx2_set1(&aX4[4 * 9 * 2]);
++
++    wvalue = *((u16 *) & p_str[(idx - 1) / 8]);
++    wvalue = (wvalue >> ((idx - 1) % 8)) & mask;
++    idx += window_size;
++    booth_recode_w7(&sign0, &digit0, wvalue);
++    wvalue = *((u16 *) & p_str[(idx - 1) / 8]);
++    wvalue = (wvalue >> ((idx - 1) % 8)) & mask;
++    idx += window_size;
++    booth_recode_w7(&sign1, &digit1, wvalue);
++    wvalue = *((u16 *) & p_str[(idx - 1) / 8]);
++    wvalue = (wvalue >> ((idx - 1) % 8)) & mask;
++    idx += window_size;
++    booth_recode_w7(&sign2, &digit2, wvalue);
++    wvalue = *((u16 *) & p_str[(idx - 1) / 8]);
++    wvalue = (wvalue >> ((idx - 1) % 8)) & mask;
++    idx += window_size;
++    booth_recode_w7(&sign3, &digit3, wvalue);
++
++    ecp_nistz256_avx2_multi_gather_w7(point_arr, preComputedTable[4 * 1],
++                                      digit0, digit1, digit2, digit3);
++
++    ecp_nistz256_neg(tmp, point_arr[0].Y);
++    copy_conditional(point_arr[0].Y, tmp, sign0);
++    ecp_nistz256_neg(tmp, point_arr[1].Y);
++    copy_conditional(point_arr[1].Y, tmp, sign1);
++    ecp_nistz256_neg(tmp, point_arr[2].Y);
++    copy_conditional(point_arr[2].Y, tmp, sign2);
++    ecp_nistz256_neg(tmp, point_arr[3].Y);
++    copy_conditional(point_arr[3].Y, tmp, sign3);
++
++    ecp_nistz256_avx2_transpose_convert(bX4, point_arr);
++    ecp_nistz256_avx2_to_mont(bX4, bX4);
++    ecp_nistz256_avx2_to_mont(&bX4[4 * 9], &bX4[4 * 9]);
++    /* Optimized when both inputs are affine */
++    ecp_nistz256_avx2_point_add_affines_x4(aX4, aX4, bX4);
++
++    for (i = 2; i < 9; i++) {
++        wvalue = *((u16 *) & p_str[(idx - 1) / 8]);
++        wvalue = (wvalue >> ((idx - 1) % 8)) & mask;
++        idx += window_size;
++        booth_recode_w7(&sign0, &digit0, wvalue);
++        wvalue = *((u16 *) & p_str[(idx - 1) / 8]);
++        wvalue = (wvalue >> ((idx - 1) % 8)) & mask;
++        idx += window_size;
++        booth_recode_w7(&sign1, &digit1, wvalue);
++        wvalue = *((u16 *) & p_str[(idx - 1) / 8]);
++        wvalue = (wvalue >> ((idx - 1) % 8)) & mask;
++        idx += window_size;
++        booth_recode_w7(&sign2, &digit2, wvalue);
++        wvalue = *((u16 *) & p_str[(idx - 1) / 8]);
++        wvalue = (wvalue >> ((idx - 1) % 8)) & mask;
++        idx += window_size;
++        booth_recode_w7(&sign3, &digit3, wvalue);
++
++        ecp_nistz256_avx2_multi_gather_w7(point_arr,
++                                          preComputedTable[4 * i],
++                                          digit0, digit1, digit2, digit3);
++
++        ecp_nistz256_neg(tmp, point_arr[0].Y);
++        copy_conditional(point_arr[0].Y, tmp, sign0);
++        ecp_nistz256_neg(tmp, point_arr[1].Y);
++        copy_conditional(point_arr[1].Y, tmp, sign1);
++        ecp_nistz256_neg(tmp, point_arr[2].Y);
++        copy_conditional(point_arr[2].Y, tmp, sign2);
++        ecp_nistz256_neg(tmp, point_arr[3].Y);
++        copy_conditional(point_arr[3].Y, tmp, sign3);
++
++        ecp_nistz256_avx2_transpose_convert(bX4, point_arr);
++        ecp_nistz256_avx2_to_mont(bX4, bX4);
++        ecp_nistz256_avx2_to_mont(&bX4[4 * 9], &bX4[4 * 9]);
++
++        ecp_nistz256_avx2_point_add_affine_x4(aX4, aX4, bX4);
++    }
++
++    ecp_nistz256_avx2_from_mont(&aX4[4 * 9 * 0], &aX4[4 * 9 * 0]);
++    ecp_nistz256_avx2_from_mont(&aX4[4 * 9 * 1], &aX4[4 * 9 * 1]);
++    ecp_nistz256_avx2_from_mont(&aX4[4 * 9 * 2], &aX4[4 * 9 * 2]);
++
++    ecp_nistz256_avx2_convert_transpose_back(res_point_arr, aX4);
++    /* Last window is performed serially */
++    wvalue = *((u16 *) & p_str[(idx - 1) / 8]);
++    wvalue = (wvalue >> ((idx - 1) % 8)) & mask;
++    booth_recode_w7(&sign0, &digit0, wvalue);
++    ecp_nistz256_gather_w7((P256_POINT_AFFINE *)r,
++                           preComputedTable[36], digit0);
++    ecp_nistz256_neg(tmp, r->Y);
++    copy_conditional(r->Y, tmp, sign0);
++    memcpy(r->Z, ONE, sizeof(ONE));
++    /* Sum the four windows */
++    ecp_nistz256_point_add(r, r, &res_point_arr[0]);
++    ecp_nistz256_point_add(r, r, &res_point_arr[1]);
++    ecp_nistz256_point_add(r, r, &res_point_arr[2]);
++    ecp_nistz256_point_add(r, r, &res_point_arr[3]);
++}
++# endif
++#endif
++
++__owur static int ecp_nistz256_set_from_affine(EC_POINT *out, const EC_GROUP *group,
++                                               const P256_POINT_AFFINE *in,
++                                               BN_CTX *ctx)
++{
++    BIGNUM *x, *y;
++    BN_ULONG d_x[P256_LIMBS], d_y[P256_LIMBS];
++    int ret = 0;
++
++    x = BN_new();
++    if (x == NULL)
++        return 0;
++    y = BN_new();
++    if (y == NULL) {
++        BN_free(x);
++        return 0;
++    }
++    memcpy(d_x, in->X, sizeof(d_x));
++    bn_set_static_words(x, d_x, P256_LIMBS);
++
++    memcpy(d_y, in->Y, sizeof(d_y));
++    bn_set_static_words(y, d_y, P256_LIMBS);
++
++    ret = EC_POINT_set_affine_coordinates_GFp(group, out, x, y, ctx);
++
++    BN_free(x);
++    BN_free(y);
++
++    return ret;
++}
++
++/* r = scalar*G + sum(scalars[i]*points[i]) */
++__owur static int ecp_nistz256_points_mul(const EC_GROUP *group,
++                                          EC_POINT *r,
++                                          const BIGNUM *scalar,
++                                          size_t num,
++                                          const EC_POINT *points[],
++                                          const BIGNUM *scalars[], BN_CTX *ctx)
++{
++    int i = 0, ret = 0, no_precomp_for_generator = 0, p_is_infinity = 0;
++    size_t j;
++    unsigned char p_str[33] = { 0 };
++    const PRECOMP256_ROW *preComputedTable = NULL;
++    const NISTZ256_PRE_COMP *pre_comp = NULL;
++    const EC_POINT *generator = NULL;
++    BN_CTX *new_ctx = NULL;
++    const BIGNUM **new_scalars = NULL;
++    const EC_POINT **new_points = NULL;
++    unsigned int idx = 0;
++    const unsigned int window_size = 7;
++    const unsigned int mask = (1 << (window_size + 1)) - 1;
++    unsigned int wvalue;
++    ALIGN32 union {
++        P256_POINT p;
++        P256_POINT_AFFINE a;
++    } t, p;
++    BIGNUM *tmp_scalar;
++
++    if ((num + 1) == 0 || (num + 1) > OPENSSL_MALLOC_MAX_NELEMS(void *)) {
++        ECerr(EC_F_ECP_NISTZ256_POINTS_MUL, ERR_R_MALLOC_FAILURE);
++        return 0;
++    }
++
++    if (group->meth != r->meth) {
++        ECerr(EC_F_ECP_NISTZ256_POINTS_MUL, EC_R_INCOMPATIBLE_OBJECTS);
++        return 0;
++    }
++
++    if ((scalar == NULL) && (num == 0))
++        return EC_POINT_set_to_infinity(group, r);
++
++    for (j = 0; j < num; j++) {
++        if (group->meth != points[j]->meth) {
++            ECerr(EC_F_ECP_NISTZ256_POINTS_MUL, EC_R_INCOMPATIBLE_OBJECTS);
++            return 0;
++        }
++    }
++
++    if (ctx == NULL) {
++        ctx = new_ctx = BN_CTX_new();
++        if (ctx == NULL)
++            goto err;
++    }
++
++    BN_CTX_start(ctx);
++
++    if (scalar) {
++        generator = EC_GROUP_get0_generator(group);
++        if (generator == NULL) {
++            ECerr(EC_F_ECP_NISTZ256_POINTS_MUL, EC_R_UNDEFINED_GENERATOR);
++            goto err;
++        }
++
++        /* look if we can use precomputed multiples of generator */
++        pre_comp = group->pre_comp.nistz256;
++
++        if (pre_comp) {
++            /*
++             * If there is a precomputed table for the generator, check that
++             * it was generated with the same generator.
++             */
++            EC_POINT *pre_comp_generator = EC_POINT_new(group);
++            if (pre_comp_generator == NULL)
++                goto err;
++
++            if (!ecp_nistz256_set_from_affine(pre_comp_generator,
++                                              group, pre_comp->precomp[0],
++                                              ctx)) {
++                EC_POINT_free(pre_comp_generator);
++                goto err;
++            }
++
++            if (0 == EC_POINT_cmp(group, generator, pre_comp_generator, ctx))
++                preComputedTable = (const PRECOMP256_ROW *)pre_comp->precomp;
++
++            EC_POINT_free(pre_comp_generator);
++        }
++
++        if (preComputedTable == NULL && ecp_nistz256_is_affine_G(generator)) {
++            /*
++             * If there is no precomputed data, but the generator is the
++             * default, a hardcoded table of precomputed data is used. This
++             * is because applications, such as Apache, do not use
++             * EC_KEY_precompute_mult.
++             */
++            preComputedTable = ecp_nistz256_precomputed;
++        }
++
++        if (preComputedTable) {
++            if ((BN_num_bits(scalar) > 256)
++                || BN_is_negative(scalar)) {
++                if ((tmp_scalar = BN_CTX_get(ctx)) == NULL)
++                    goto err;
++
++                if (!BN_nnmod(tmp_scalar, scalar, group->order, ctx)) {
++                    ECerr(EC_F_ECP_NISTZ256_POINTS_MUL, ERR_R_BN_LIB);
++                    goto err;
++                }
++                scalar = tmp_scalar;
++            }
++
++            for (i = 0; i < bn_get_top(scalar) * BN_BYTES; i += BN_BYTES) {
++                BN_ULONG d = bn_get_words(scalar)[i / BN_BYTES];
++
++                p_str[i + 0] = (unsigned char)d;
++                p_str[i + 1] = (unsigned char)(d >> 8);
++                p_str[i + 2] = (unsigned char)(d >> 16);
++                p_str[i + 3] = (unsigned char)(d >>= 24);
++                if (BN_BYTES == 8) {
++                    d >>= 8;
++                    p_str[i + 4] = (unsigned char)d;
++                    p_str[i + 5] = (unsigned char)(d >> 8);
++                    p_str[i + 6] = (unsigned char)(d >> 16);
++                    p_str[i + 7] = (unsigned char)(d >> 24);
++                }
++            }
++
++            for (; i < 33; i++)
++                p_str[i] = 0;
++
++#if defined(ECP_NISTZ256_AVX2)
++            if (ecp_nistz_avx2_eligible()) {
++                ecp_nistz256_avx2_mul_g(&p.p, p_str, preComputedTable);
++            } else
++#endif
++            {
++                BN_ULONG infty;
++
++                /* First window */
++                wvalue = (p_str[0] << 1) & mask;
++                idx += window_size;
++
++                wvalue = _booth_recode_w7(wvalue);
++
++                ecp_nistz256_gather_w7(&p.a, preComputedTable[0],
++                                       wvalue >> 1);
++
++                ecp_nistz256_neg(p.p.Z, p.p.Y);
++                copy_conditional(p.p.Y, p.p.Z, wvalue & 1);
++
++                /*
++                 * Since affine infinity is encoded as (0,0) and
++                 * Jacobian ias (,,0), we need to harmonize them
++                 * by assigning "one" or zero to Z.
++                 */
++                infty = (p.p.X[0] | p.p.X[1] | p.p.X[2] | p.p.X[3] |
++                         p.p.Y[0] | p.p.Y[1] | p.p.Y[2] | p.p.Y[3]);
++                if (P256_LIMBS == 8)
++                    infty |= (p.p.X[4] | p.p.X[5] | p.p.X[6] | p.p.X[7] |
++                              p.p.Y[4] | p.p.Y[5] | p.p.Y[6] | p.p.Y[7]);
++
++                infty = 0 - is_zero(infty);
++                infty = ~infty;
++
++                p.p.Z[0] = ONE[0] & infty;
++                p.p.Z[1] = ONE[1] & infty;
++                p.p.Z[2] = ONE[2] & infty;
++                p.p.Z[3] = ONE[3] & infty;
++                if (P256_LIMBS == 8) {
++                    p.p.Z[4] = ONE[4] & infty;
++                    p.p.Z[5] = ONE[5] & infty;
++                    p.p.Z[6] = ONE[6] & infty;
++                    p.p.Z[7] = ONE[7] & infty;
++                }
++
++                for (i = 1; i < 37; i++) {
++                    unsigned int off = (idx - 1) / 8;
++                    wvalue = p_str[off] | p_str[off + 1] << 8;
++                    wvalue = (wvalue >> ((idx - 1) % 8)) & mask;
++                    idx += window_size;
++
++                    wvalue = _booth_recode_w7(wvalue);
++
++                    ecp_nistz256_gather_w7(&t.a,
++                                           preComputedTable[i], wvalue >> 1);
++
++                    ecp_nistz256_neg(t.p.Z, t.a.Y);
++                    copy_conditional(t.a.Y, t.p.Z, wvalue & 1);
++
++                    ecp_nistz256_point_add_affine(&p.p, &p.p, &t.a);
++                }
++            }
++        } else {
++            p_is_infinity = 1;
++            no_precomp_for_generator = 1;
++        }
++    } else
++        p_is_infinity = 1;
++
++    if (no_precomp_for_generator) {
++        /*
++         * Without a precomputed table for the generator, it has to be
++         * handled like a normal point.
++         */
++        new_scalars = OPENSSL_malloc((num + 1) * sizeof(BIGNUM *));
++        if (new_scalars == NULL) {
++            ECerr(EC_F_ECP_NISTZ256_POINTS_MUL, ERR_R_MALLOC_FAILURE);
++            goto err;
++        }
++
++        new_points = OPENSSL_malloc((num + 1) * sizeof(EC_POINT *));
++        if (new_points == NULL) {
++            ECerr(EC_F_ECP_NISTZ256_POINTS_MUL, ERR_R_MALLOC_FAILURE);
++            goto err;
++        }
++
++        memcpy(new_scalars, scalars, num * sizeof(BIGNUM *));
++        new_scalars[num] = scalar;
++        memcpy(new_points, points, num * sizeof(EC_POINT *));
++        new_points[num] = generator;
++
++        scalars = new_scalars;
++        points = new_points;
++        num++;
++    }
++
++    if (num) {
++        P256_POINT *out = &t.p;
++        if (p_is_infinity)
++            out = &p.p;
++
++        if (!ecp_nistz256_windowed_mul(group, out, scalars, points, num, ctx))
++            goto err;
++
++        if (!p_is_infinity)
++            ecp_nistz256_point_add(&p.p, &p.p, out);
++    }
++
++    /* Not constant-time, but we're only operating on the public output. */
++    if (!bn_set_words(r->X, p.p.X, P256_LIMBS) ||
++        !bn_set_words(r->Y, p.p.Y, P256_LIMBS) ||
++        !bn_set_words(r->Z, p.p.Z, P256_LIMBS)) {
++        goto err;
++    }
++    r->Z_is_one = is_one(r->Z) & 1;
++
++    ret = 1;
++
++err:
++    if (ctx)
++        BN_CTX_end(ctx);
++    BN_CTX_free(new_ctx);
++    OPENSSL_free(new_points);
++    OPENSSL_free(new_scalars);
++    return ret;
++}
++
++__owur static int ecp_nistz256_get_affine(const EC_GROUP *group,
++                                          const EC_POINT *point,
++                                          BIGNUM *x, BIGNUM *y, BN_CTX *ctx)
++{
++    BN_ULONG z_inv2[P256_LIMBS];
++    BN_ULONG z_inv3[P256_LIMBS];
++    BN_ULONG x_aff[P256_LIMBS];
++    BN_ULONG y_aff[P256_LIMBS];
++    BN_ULONG point_x[P256_LIMBS], point_y[P256_LIMBS], point_z[P256_LIMBS];
++    BN_ULONG x_ret[P256_LIMBS], y_ret[P256_LIMBS];
++
++    if (EC_POINT_is_at_infinity(group, point)) {
++        ECerr(EC_F_ECP_NISTZ256_GET_AFFINE, EC_R_POINT_AT_INFINITY);
++        return 0;
++    }
++
++    if (!ecp_nistz256_bignum_to_field_elem(point_x, point->X) ||
++        !ecp_nistz256_bignum_to_field_elem(point_y, point->Y) ||
++        !ecp_nistz256_bignum_to_field_elem(point_z, point->Z)) {
++        ECerr(EC_F_ECP_NISTZ256_GET_AFFINE, EC_R_COORDINATES_OUT_OF_RANGE);
++        return 0;
++    }
++
++    ecp_nistz256_mod_inverse(z_inv3, point_z);
++    ecp_nistz256_sqr_mont(z_inv2, z_inv3);
++    ecp_nistz256_mul_mont(x_aff, z_inv2, point_x);
++
++    if (x != NULL) {
++        ecp_nistz256_from_mont(x_ret, x_aff);
++        if (!bn_set_words(x, x_ret, P256_LIMBS))
++            return 0;
++    }
++
++    if (y != NULL) {
++        ecp_nistz256_mul_mont(z_inv3, z_inv3, z_inv2);
++        ecp_nistz256_mul_mont(y_aff, z_inv3, point_y);
++        ecp_nistz256_from_mont(y_ret, y_aff);
++        if (!bn_set_words(y, y_ret, P256_LIMBS))
++            return 0;
++    }
++
++    return 1;
++}
++
++static NISTZ256_PRE_COMP *ecp_nistz256_pre_comp_new(const EC_GROUP *group)
++{
++    NISTZ256_PRE_COMP *ret = NULL;
++
++    if (!group)
++        return NULL;
++
++    ret = OPENSSL_zalloc(sizeof(*ret));
++
++    if (ret == NULL) {
++        ECerr(EC_F_ECP_NISTZ256_PRE_COMP_NEW, ERR_R_MALLOC_FAILURE);
++        return ret;
++    }
++
++    ret->group = group;
++    ret->w = 6;                 /* default */
++    ret->references = 1;
++
++    ret->lock = CRYPTO_THREAD_lock_new();
++    if (ret->lock == NULL) {
++        ECerr(EC_F_ECP_NISTZ256_PRE_COMP_NEW, ERR_R_MALLOC_FAILURE);
++        OPENSSL_free(ret);
++        return NULL;
++    }
++    return ret;
++}
++
++NISTZ256_PRE_COMP *EC_nistz256_pre_comp_dup(NISTZ256_PRE_COMP *p)
++{
++    int i;
++    if (p != NULL)
++        CRYPTO_atomic_add(&p->references, 1, &i, p->lock);
++    return p;
++}
++
++void EC_nistz256_pre_comp_free(NISTZ256_PRE_COMP *pre)
++{
++    int i;
++
++    if (pre == NULL)
++        return;
++
++    CRYPTO_atomic_add(&pre->references, -1, &i, pre->lock);
++    REF_PRINT_COUNT("EC_nistz256", x);
++    if (i > 0)
++        return;
++    REF_ASSERT_ISNT(i < 0);
++
++    OPENSSL_free(pre->precomp_storage);
++    CRYPTO_THREAD_lock_free(pre->lock);
++    OPENSSL_free(pre);
++}
++
++
++static int ecp_nistz256_window_have_precompute_mult(const EC_GROUP *group)
++{
++    /* There is a hard-coded table for the default generator. */
++    const EC_POINT *generator = EC_GROUP_get0_generator(group);
++
++    if (generator != NULL && ecp_nistz256_is_affine_G(generator)) {
++        /* There is a hard-coded table for the default generator. */
++        return 1;
++    }
++
++    return HAVEPRECOMP(group, nistz256);
++}
++
++const EC_METHOD *EC_GFp_nistz256_method(void)
++{
++    static const EC_METHOD ret = {
++        EC_FLAGS_DEFAULT_OCT,
++        NID_X9_62_prime_field,
++        ec_GFp_mont_group_init,
++        ec_GFp_mont_group_finish,
++        ec_GFp_mont_group_clear_finish,
++        ec_GFp_mont_group_copy,
++        ec_GFp_mont_group_set_curve,
++        ec_GFp_simple_group_get_curve,
++        ec_GFp_simple_group_get_degree,
++        ec_group_simple_order_bits,
++        ec_GFp_simple_group_check_discriminant,
++        ec_GFp_simple_point_init,
++        ec_GFp_simple_point_finish,
++        ec_GFp_simple_point_clear_finish,
++        ec_GFp_simple_point_copy,
++        ec_GFp_simple_point_set_to_infinity,
++        ec_GFp_simple_set_Jprojective_coordinates_GFp,
++        ec_GFp_simple_get_Jprojective_coordinates_GFp,
++        ec_GFp_simple_point_set_affine_coordinates,
++        ecp_nistz256_get_affine,
++        0, 0, 0,
++        ec_GFp_simple_add,
++        ec_GFp_simple_dbl,
++        ec_GFp_simple_invert,
++        ec_GFp_simple_is_at_infinity,
++        ec_GFp_simple_is_on_curve,
++        ec_GFp_simple_cmp,
++        ec_GFp_simple_make_affine,
++        ec_GFp_simple_points_make_affine,
++        ecp_nistz256_points_mul,                    /* mul */
++        ecp_nistz256_mult_precompute,               /* precompute_mult */
++        ecp_nistz256_window_have_precompute_mult,   /* have_precompute_mult */
++        ec_GFp_mont_field_mul,
++        ec_GFp_mont_field_sqr,
++        0,                                          /* field_div */
++        ec_GFp_mont_field_encode,
++        ec_GFp_mont_field_decode,
++        ec_GFp_mont_field_set_to_one,
++        ec_key_simple_priv2oct,
++        ec_key_simple_oct2priv,
++        0, /* set private */
++        ec_key_simple_generate_key,
++        ec_key_simple_check_key,
++        ec_key_simple_generate_public_key,
++        0, /* keycopy */
++        0, /* keyfinish */
++        ecdh_simple_compute_key
++    };
++
++    return &ret;
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/ec/ecp_nistz256_table.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/ec/ecp_nistz256_table.c
+new file mode 100644
+index 0000000..3f5625c
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/ec/ecp_nistz256_table.c
+@@ -0,0 +1,9542 @@
++/*
++ * Copyright 2014-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++/*
++ * This is the precomputed constant time access table for the code in
++ * ecp_montp256.c, for the default generator. The table consists of 37
++ * subtables, each subtable contains 64 affine points. The affine points are
++ * encoded as eight uint64's, four for the x coordinate and four for the y.
++ * Both values are in little-endian order. There are 37 tables because a
++ * signed, 6-bit wNAF form of the scalar is used and ceil(256/(6 + 1)) = 37.
++ * Within each table there are 64 values because the 6-bit wNAF value can
++ * take 64 values, ignoring the sign bit, which is implemented by performing
++ * a negation of the affine point when required. We would like to align it
++ * to 2MB in order to increase the chances of using a large page but that
++ * appears to lead to invalid ELF files being produced.
++ */
++
++#if defined(__GNUC__)
++__attribute((aligned(4096)))
++#elif defined(_MSC_VER)
++__declspec(align(4096))
++#elif defined(__SUNPRO_C)
++# pragma align 4096(ecp_nistz256_precomputed)
++#endif
++static const BN_ULONG ecp_nistz256_precomputed[37][64 *
++                                                   sizeof(P256_POINT_AFFINE) /
++                                                   sizeof(BN_ULONG)] = {
++    {TOBN(0x79e730d4, 0x18a9143c), TOBN(0x75ba95fc, 0x5fedb601),
++     TOBN(0x79fb732b, 0x77622510), TOBN(0x18905f76, 0xa53755c6),
++     TOBN(0xddf25357, 0xce95560a), TOBN(0x8b4ab8e4, 0xba19e45c),
++     TOBN(0xd2e88688, 0xdd21f325), TOBN(0x8571ff18, 0x25885d85),
++     TOBN(0x850046d4, 0x10ddd64d), TOBN(0xaa6ae3c1, 0xa433827d),
++     TOBN(0x73220503, 0x8d1490d9), TOBN(0xf6bb32e4, 0x3dcf3a3b),
++     TOBN(0x2f3648d3, 0x61bee1a5), TOBN(0x152cd7cb, 0xeb236ff8),
++     TOBN(0x19a8fb0e, 0x92042dbe), TOBN(0x78c57751, 0x0a5b8a3b),
++     TOBN(0xffac3f90, 0x4eebc127), TOBN(0xb027f84a, 0x087d81fb),
++     TOBN(0x66ad77dd, 0x87cbbc98), TOBN(0x26936a3f, 0xb6ff747e),
++     TOBN(0xb04c5c1f, 0xc983a7eb), TOBN(0x583e47ad, 0x0861fe1a),
++     TOBN(0x78820831, 0x1a2ee98e), TOBN(0xd5f06a29, 0xe587cc07),
++     TOBN(0x74b0b50d, 0x46918dcc), TOBN(0x4650a6ed, 0xc623c173),
++     TOBN(0x0cdaacac, 0xe8100af2), TOBN(0x577362f5, 0x41b0176b),
++     TOBN(0x2d96f24c, 0xe4cbaba6), TOBN(0x17628471, 0xfad6f447),
++     TOBN(0x6b6c36de, 0xe5ddd22e), TOBN(0x84b14c39, 0x4c5ab863),
++     TOBN(0xbe1b8aae, 0xc45c61f5), TOBN(0x90ec649a, 0x94b9537d),
++     TOBN(0x941cb5aa, 0xd076c20c), TOBN(0xc9079605, 0x890523c8),
++     TOBN(0xeb309b4a, 0xe7ba4f10), TOBN(0x73c568ef, 0xe5eb882b),
++     TOBN(0x3540a987, 0x7e7a1f68), TOBN(0x73a076bb, 0x2dd1e916),
++     TOBN(0x40394737, 0x3e77664a), TOBN(0x55ae744f, 0x346cee3e),
++     TOBN(0xd50a961a, 0x5b17a3ad), TOBN(0x13074b59, 0x54213673),
++     TOBN(0x93d36220, 0xd377e44b), TOBN(0x299c2b53, 0xadff14b5),
++     TOBN(0xf424d44c, 0xef639f11), TOBN(0xa4c9916d, 0x4a07f75f),
++     TOBN(0x0746354e, 0xa0173b4f), TOBN(0x2bd20213, 0xd23c00f7),
++     TOBN(0xf43eaab5, 0x0c23bb08), TOBN(0x13ba5119, 0xc3123e03),
++     TOBN(0x2847d030, 0x3f5b9d4d), TOBN(0x6742f2f2, 0x5da67bdd),
++     TOBN(0xef933bdc, 0x77c94195), TOBN(0xeaedd915, 0x6e240867),
++     TOBN(0x27f14cd1, 0x9499a78f), TOBN(0x462ab5c5, 0x6f9b3455),
++     TOBN(0x8f90f02a, 0xf02cfc6b), TOBN(0xb763891e, 0xb265230d),
++     TOBN(0xf59da3a9, 0x532d4977), TOBN(0x21e3327d, 0xcf9eba15),
++     TOBN(0x123c7b84, 0xbe60bbf0), TOBN(0x56ec12f2, 0x7706df76),
++     TOBN(0x75c96e8f, 0x264e20e8), TOBN(0xabe6bfed, 0x59a7a841),
++     TOBN(0x2cc09c04, 0x44c8eb00), TOBN(0xe05b3080, 0xf0c4e16b),
++     TOBN(0x1eb7777a, 0xa45f3314), TOBN(0x56af7bed, 0xce5d45e3),
++     TOBN(0x2b6e019a, 0x88b12f1a), TOBN(0x086659cd, 0xfd835f9b),
++     TOBN(0x2c18dbd1, 0x9dc21ec8), TOBN(0x98f9868a, 0x0fcf8139),
++     TOBN(0x737d2cd6, 0x48250b49), TOBN(0xcc61c947, 0x24b3428f),
++     TOBN(0x0c2b4078, 0x80dd9e76), TOBN(0xc43a8991, 0x383fbe08),
++     TOBN(0x5f7d2d65, 0x779be5d2), TOBN(0x78719a54, 0xeb3b4ab5),
++     TOBN(0xea7d260a, 0x6245e404), TOBN(0x9de40795, 0x6e7fdfe0),
++     TOBN(0x1ff3a415, 0x8dac1ab5), TOBN(0x3e7090f1, 0x649c9073),
++     TOBN(0x1a768561, 0x2b944e88), TOBN(0x250f939e, 0xe57f61c8),
++     TOBN(0x0c0daa89, 0x1ead643d), TOBN(0x68930023, 0xe125b88e),
++     TOBN(0x04b71aa7, 0xd2697768), TOBN(0xabdedef5, 0xca345a33),
++     TOBN(0x2409d29d, 0xee37385e), TOBN(0x4ee1df77, 0xcb83e156),
++     TOBN(0x0cac12d9, 0x1cbb5b43), TOBN(0x170ed2f6, 0xca895637),
++     TOBN(0x28228cfa, 0x8ade6d66), TOBN(0x7ff57c95, 0x53238aca),
++     TOBN(0xccc42563, 0x4b2ed709), TOBN(0x0e356769, 0x856fd30d),
++     TOBN(0xbcbcd43f, 0x559e9811), TOBN(0x738477ac, 0x5395b759),
++     TOBN(0x35752b90, 0xc00ee17f), TOBN(0x68748390, 0x742ed2e3),
++     TOBN(0x7cd06422, 0xbd1f5bc1), TOBN(0xfbc08769, 0xc9e7b797),
++     TOBN(0xa242a35b, 0xb0cf664a), TOBN(0x126e48f7, 0x7f9707e3),
++     TOBN(0x1717bf54, 0xc6832660), TOBN(0xfaae7332, 0xfd12c72e),
++     TOBN(0x27b52db7, 0x995d586b), TOBN(0xbe29569e, 0x832237c2),
++     TOBN(0xe8e4193e, 0x2a65e7db), TOBN(0x152706dc, 0x2eaa1bbb),
++     TOBN(0x72bcd8b7, 0xbc60055b), TOBN(0x03cc23ee, 0x56e27e4b),
++     TOBN(0xee337424, 0xe4819370), TOBN(0xe2aa0e43, 0x0ad3da09),
++     TOBN(0x40b8524f, 0x6383c45d), TOBN(0xd7663554, 0x42a41b25),
++     TOBN(0x64efa6de, 0x778a4797), TOBN(0x2042170a, 0x7079adf4),
++     TOBN(0x808b0b65, 0x0bc6fb80), TOBN(0x5882e075, 0x3ffe2e6b),
++     TOBN(0xd5ef2f7c, 0x2c83f549), TOBN(0x54d63c80, 0x9103b723),
++     TOBN(0xf2f11bd6, 0x52a23f9b), TOBN(0x3670c319, 0x4b0b6587),
++     TOBN(0x55c4623b, 0xb1580e9e), TOBN(0x64edf7b2, 0x01efe220),
++     TOBN(0x97091dcb, 0xd53c5c9d), TOBN(0xf17624b6, 0xac0a177b),
++     TOBN(0xb0f13975, 0x2cfe2dff), TOBN(0xc1a35c0a, 0x6c7a574e),
++     TOBN(0x227d3146, 0x93e79987), TOBN(0x0575bf30, 0xe89cb80e),
++     TOBN(0x2f4e247f, 0x0d1883bb), TOBN(0xebd51226, 0x3274c3d0),
++     TOBN(0x5f3e51c8, 0x56ada97a), TOBN(0x4afc964d, 0x8f8b403e),
++     TOBN(0xa6f247ab, 0x412e2979), TOBN(0x675abd1b, 0x6f80ebda),
++     TOBN(0x66a2bd72, 0x5e485a1d), TOBN(0x4b2a5caf, 0x8f4f0b3c),
++     TOBN(0x2626927f, 0x1b847bba), TOBN(0x6c6fc7d9, 0x0502394d),
++     TOBN(0xfea912ba, 0xa5659ae8), TOBN(0x68363aba, 0x25e1a16e),
++     TOBN(0xb8842277, 0x752c41ac), TOBN(0xfe545c28, 0x2897c3fc),
++     TOBN(0x2d36e9e7, 0xdc4c696b), TOBN(0x5806244a, 0xfba977c5),
++     TOBN(0x85665e9b, 0xe39508c1), TOBN(0xf720ee25, 0x6d12597b),
++     TOBN(0x8a979129, 0xd2337a31), TOBN(0x5916868f, 0x0f862bdc),
++     TOBN(0x048099d9, 0x5dd283ba), TOBN(0xe2d1eeb6, 0xfe5bfb4e),
++     TOBN(0x82ef1c41, 0x7884005d), TOBN(0xa2d4ec17, 0xffffcbae),
++     TOBN(0x9161c53f, 0x8aa95e66), TOBN(0x5ee104e1, 0xc5fee0d0),
++     TOBN(0x562e4cec, 0xc135b208), TOBN(0x74e1b265, 0x4783f47d),
++     TOBN(0x6d2a506c, 0x5a3f3b30), TOBN(0xecead9f4, 0xc16762fc),
++     TOBN(0xf29dd4b2, 0xe286e5b9), TOBN(0x1b0fadc0, 0x83bb3c61),
++     TOBN(0x7a75023e, 0x7fac29a4), TOBN(0xc086d5f1, 0xc9477fa3),
++     TOBN(0x0fc61135, 0x2f6f3076), TOBN(0xc99ffa23, 0xe3912a9a),
++     TOBN(0x6a0b0685, 0xd2f8ba3d), TOBN(0xfdc777e8, 0xe93358a4),
++     TOBN(0x94a787bb, 0x35415f04), TOBN(0x640c2d6a, 0x4d23fea4),
++     TOBN(0x9de917da, 0x153a35b5), TOBN(0x793e8d07, 0x5d5cd074),
++     TOBN(0xf4f87653, 0x2de45068), TOBN(0x37c7a7e8, 0x9e2e1f6e),
++     TOBN(0xd0825fa2, 0xa3584069), TOBN(0xaf2cea7c, 0x1727bf42),
++     TOBN(0x0360a4fb, 0x9e4785a9), TOBN(0xe5fda49c, 0x27299f4a),
++     TOBN(0x48068e13, 0x71ac2f71), TOBN(0x83d0687b, 0x9077666f),
++     TOBN(0x6d3883b2, 0x15d02819), TOBN(0x6d0d7550, 0x40dd9a35),
++     TOBN(0x61d7cbf9, 0x1d2b469f), TOBN(0xf97b232f, 0x2efc3115),
++     TOBN(0xa551d750, 0xb24bcbc7), TOBN(0x11ea4949, 0x88a1e356),
++     TOBN(0x7669f031, 0x93cb7501), TOBN(0x595dc55e, 0xca737b8a),
++     TOBN(0xa4a319ac, 0xd837879f), TOBN(0x6fc1b49e, 0xed6b67b0),
++     TOBN(0xe3959933, 0x32f1f3af), TOBN(0x966742eb, 0x65432a2e),
++     TOBN(0x4b8dc9fe, 0xb4966228), TOBN(0x96cc6312, 0x43f43950),
++     TOBN(0x12068859, 0xc9b731ee), TOBN(0x7b948dc3, 0x56f79968),
++     TOBN(0x61e4ad32, 0xed1f8008), TOBN(0xe6c9267a, 0xd8b17538),
++     TOBN(0x1ac7c5eb, 0x857ff6fb), TOBN(0x994baaa8, 0x55f2fb10),
++     TOBN(0x84cf14e1, 0x1d248018), TOBN(0x5a39898b, 0x628ac508),
++     TOBN(0x14fde97b, 0x5fa944f5), TOBN(0xed178030, 0xd12e5ac7),
++     TOBN(0x042c2af4, 0x97e2feb4), TOBN(0xd36a42d7, 0xaebf7313),
++     TOBN(0x49d2c9eb, 0x084ffdd7), TOBN(0x9f8aa54b, 0x2ef7c76a),
++     TOBN(0x9200b7ba, 0x09895e70), TOBN(0x3bd0c66f, 0xddb7fb58),
++     TOBN(0x2d97d108, 0x78eb4cbb), TOBN(0x2d431068, 0xd84bde31),
++     TOBN(0x4b523eb7, 0x172ccd1f), TOBN(0x7323cb28, 0x30a6a892),
++     TOBN(0x97082ec0, 0xcfe153eb), TOBN(0xe97f6b6a, 0xf2aadb97),
++     TOBN(0x1d3d393e, 0xd1a83da1), TOBN(0xa6a7f9c7, 0x804b2a68),
++     TOBN(0x4a688b48, 0x2d0cb71e), TOBN(0xa9b4cc5f, 0x40585278),
++     TOBN(0x5e5db46a, 0xcb66e132), TOBN(0xf1be963a, 0x0d925880),
++     TOBN(0x944a7027, 0x0317b9e2), TOBN(0xe266f959, 0x48603d48),
++     TOBN(0x98db6673, 0x5c208899), TOBN(0x90472447, 0xa2fb18a3),
++     TOBN(0x8a966939, 0x777c619f), TOBN(0x3798142a, 0x2a3be21b),
++     TOBN(0xb4241cb1, 0x3298b343), TOBN(0xa3a14e49, 0xb44f65a1),
++     TOBN(0xc5f4d6cd, 0x3ac77acd), TOBN(0xd0288cb5, 0x52b6fc3c),
++     TOBN(0xd5cc8c2f, 0x1c040abc), TOBN(0xb675511e, 0x06bf9b4a),
++     TOBN(0xd667da37, 0x9b3aa441), TOBN(0x460d45ce, 0x51601f72),
++     TOBN(0xe2f73c69, 0x6755ff89), TOBN(0xdd3cf7e7, 0x473017e6),
++     TOBN(0x8ef5689d, 0x3cf7600d), TOBN(0x948dc4f8, 0xb1fc87b4),
++     TOBN(0xd9e9fe81, 0x4ea53299), TOBN(0x2d921ca2, 0x98eb6028),
++     TOBN(0xfaecedfd, 0x0c9803fc), TOBN(0xf38ae891, 0x4d7b4745),
++     TOBN(0xd8c5fccf, 0xc5e3a3d8), TOBN(0xbefd904c, 0x4079dfbf),
++     TOBN(0xbc6d6a58, 0xfead0197), TOBN(0x39227077, 0x695532a4),
++     TOBN(0x09e23e6d, 0xdbef42f5), TOBN(0x7e449b64, 0x480a9908),
++     TOBN(0x7b969c1a, 0xad9a2e40), TOBN(0x6231d792, 0x9591c2a4),
++     TOBN(0x87151456, 0x0f664534), TOBN(0x85ceae7c, 0x4b68f103),
++     TOBN(0xac09c4ae, 0x65578ab9), TOBN(0x33ec6868, 0xf044b10c),
++     TOBN(0x6ac4832b, 0x3a8ec1f1), TOBN(0x5509d128, 0x5847d5ef),
++     TOBN(0xf909604f, 0x763f1574), TOBN(0xb16c4303, 0xc32f63c4),
++     TOBN(0xb6ab2014, 0x7ca23cd3), TOBN(0xcaa7a5c6, 0xa391849d),
++     TOBN(0x5b0673a3, 0x75678d94), TOBN(0xc982ddd4, 0xdd303e64),
++     TOBN(0xfd7b000b, 0x5db6f971), TOBN(0xbba2cb1f, 0x6f876f92),
++     TOBN(0xc77332a3, 0x3c569426), TOBN(0xa159100c, 0x570d74f8),
++     TOBN(0xfd16847f, 0xdec67ef5), TOBN(0x742ee464, 0x233e76b7),
++     TOBN(0x0b8e4134, 0xefc2b4c8), TOBN(0xca640b86, 0x42a3e521),
++     TOBN(0x653a0190, 0x8ceb6aa9), TOBN(0x313c300c, 0x547852d5),
++     TOBN(0x24e4ab12, 0x6b237af7), TOBN(0x2ba90162, 0x8bb47af8),
++     TOBN(0x3d5e58d6, 0xa8219bb7), TOBN(0xc691d0bd, 0x1b06c57f),
++     TOBN(0x0ae4cb10, 0xd257576e), TOBN(0x3569656c, 0xd54a3dc3),
++     TOBN(0xe5ebaebd, 0x94cda03a), TOBN(0x934e82d3, 0x162bfe13),
++     TOBN(0x450ac0ba, 0xe251a0c6), TOBN(0x480b9e11, 0xdd6da526),
++     TOBN(0x00467bc5, 0x8cce08b5), TOBN(0xb636458c, 0x7f178d55),
++     TOBN(0xc5748bae, 0xa677d806), TOBN(0x2763a387, 0xdfa394eb),
++     TOBN(0xa12b448a, 0x7d3cebb6), TOBN(0xe7adda3e, 0x6f20d850),
++     TOBN(0xf63ebce5, 0x1558462c), TOBN(0x58b36143, 0x620088a8),
++     TOBN(0x8a2cc3ca, 0x4d63c0ee), TOBN(0x51233117, 0x0fe948ce),
++     TOBN(0x7463fd85, 0x222ef33b), TOBN(0xadf0c7dc, 0x7c603d6c),
++     TOBN(0x0ec32d3b, 0xfe7765e5), TOBN(0xccaab359, 0xbf380409),
++     TOBN(0xbdaa84d6, 0x8e59319c), TOBN(0xd9a4c280, 0x9c80c34d),
++     TOBN(0xa9d89488, 0xa059c142), TOBN(0x6f5ae714, 0xff0b9346),
++     TOBN(0x068f237d, 0x16fb3664), TOBN(0x5853e4c4, 0x363186ac),
++     TOBN(0xe2d87d23, 0x63c52f98), TOBN(0x2ec4a766, 0x81828876),
++     TOBN(0x47b864fa, 0xe14e7b1c), TOBN(0x0c0bc0e5, 0x69192408),
++     TOBN(0xe4d7681d, 0xb82e9f3e), TOBN(0x83200f0b, 0xdf25e13c),
++     TOBN(0x8909984c, 0x66f27280), TOBN(0x462d7b00, 0x75f73227),
++     TOBN(0xd90ba188, 0xf2651798), TOBN(0x74c6e18c, 0x36ab1c34),
++     TOBN(0xab256ea3, 0x5ef54359), TOBN(0x03466612, 0xd1aa702f),
++     TOBN(0x624d6049, 0x2ed22e91), TOBN(0x6fdfe0b5, 0x6f072822),
++     TOBN(0xeeca1115, 0x39ce2271), TOBN(0x98100a4f, 0xdb01614f),
++     TOBN(0xb6b0daa2, 0xa35c628f), TOBN(0xb6f94d2e, 0xc87e9a47),
++     TOBN(0xc6773259, 0x1d57d9ce), TOBN(0xf70bfeec, 0x03884a7b),
++     TOBN(0x5fb35ccf, 0xed2bad01), TOBN(0xa155cbe3, 0x1da6a5c7),
++     TOBN(0xc2e2594c, 0x30a92f8f), TOBN(0x649c89ce, 0x5bfafe43),
++     TOBN(0xd158667d, 0xe9ff257a), TOBN(0x9b359611, 0xf32c50ae),
++     TOBN(0x4b00b20b, 0x906014cf), TOBN(0xf3a8cfe3, 0x89bc7d3d),
++     TOBN(0x4ff23ffd, 0x248a7d06), TOBN(0x80c5bfb4, 0x878873fa),
++     TOBN(0xb7d9ad90, 0x05745981), TOBN(0x179c85db, 0x3db01994),
++     TOBN(0xba41b062, 0x61a6966c), TOBN(0x4d82d052, 0xeadce5a8),
++     TOBN(0x9e91cd3b, 0xa5e6a318), TOBN(0x47795f4f, 0x95b2dda0),
++     TOBN(0xecfd7c1f, 0xd55a897c), TOBN(0x009194ab, 0xb29110fb),
++     TOBN(0x5f0e2046, 0xe381d3b0), TOBN(0x5f3425f6, 0xa98dd291),
++     TOBN(0xbfa06687, 0x730d50da), TOBN(0x0423446c, 0x4b083b7f),
++     TOBN(0x397a247d, 0xd69d3417), TOBN(0xeb629f90, 0x387ba42a),
++     TOBN(0x1ee426cc, 0xd5cd79bf), TOBN(0x0032940b, 0x946c6e18),
++     TOBN(0x1b1e8ae0, 0x57477f58), TOBN(0xe94f7d34, 0x6d823278),
++     TOBN(0xc747cb96, 0x782ba21a), TOBN(0xc5254469, 0xf72b33a5),
++     TOBN(0x772ef6de, 0xc7f80c81), TOBN(0xd73acbfe, 0x2cd9e6b5),
++     TOBN(0x4075b5b1, 0x49ee90d9), TOBN(0x785c339a, 0xa06e9eba),
++     TOBN(0xa1030d5b, 0xabf825e0), TOBN(0xcec684c3, 0xa42931dc),
++     TOBN(0x42ab62c9, 0xc1586e63), TOBN(0x45431d66, 0x5ab43f2b),
++     TOBN(0x57c8b2c0, 0x55f7835d), TOBN(0x033da338, 0xc1b7f865),
++     TOBN(0x283c7513, 0xcaa76097), TOBN(0x0a624fa9, 0x36c83906),
++     TOBN(0x6b20afec, 0x715af2c7), TOBN(0x4b969974, 0xeba78bfd),
++     TOBN(0x220755cc, 0xd921d60e), TOBN(0x9b944e10, 0x7baeca13),
++     TOBN(0x04819d51, 0x5ded93d4), TOBN(0x9bbff86e, 0x6dddfd27),
++     TOBN(0x6b344130, 0x77adc612), TOBN(0xa7496529, 0xbbd803a0),
++     TOBN(0x1a1baaa7, 0x6d8805bd), TOBN(0xc8403902, 0x470343ad),
++     TOBN(0x39f59f66, 0x175adff1), TOBN(0x0b26d7fb, 0xb7d8c5b7),
++     TOBN(0xa875f5ce, 0x529d75e3), TOBN(0x85efc7e9, 0x41325cc2),
++     TOBN(0x21950b42, 0x1ff6acd3), TOBN(0xffe70484, 0x53dc6909),
++     TOBN(0xff4cd0b2, 0x28766127), TOBN(0xabdbe608, 0x4fb7db2b),
++     TOBN(0x837c9228, 0x5e1109e8), TOBN(0x26147d27, 0xf4645b5a),
++     TOBN(0x4d78f592, 0xf7818ed8), TOBN(0xd394077e, 0xf247fa36),
++     TOBN(0x0fb9c2d0, 0x488c171a), TOBN(0xa78bfbaa, 0x13685278),
++     TOBN(0xedfbe268, 0xd5b1fa6a), TOBN(0x0dceb8db, 0x2b7eaba7),
++     TOBN(0xbf9e8089, 0x9ae2b710), TOBN(0xefde7ae6, 0xa4449c96),
++     TOBN(0x43b7716b, 0xcc143a46), TOBN(0xd7d34194, 0xc3628c13),
++     TOBN(0x508cec1c, 0x3b3f64c9), TOBN(0xe20bc0ba, 0x1e5edf3f),
++     TOBN(0xda1deb85, 0x2f4318d4), TOBN(0xd20ebe0d, 0x5c3fa443),
++     TOBN(0x370b4ea7, 0x73241ea3), TOBN(0x61f1511c, 0x5e1a5f65),
++     TOBN(0x99a5e23d, 0x82681c62), TOBN(0xd731e383, 0xa2f54c2d),
++     TOBN(0x2692f36e, 0x83445904), TOBN(0x2e0ec469, 0xaf45f9c0),
++     TOBN(0x905a3201, 0xc67528b7), TOBN(0x88f77f34, 0xd0e5e542),
++     TOBN(0xf67a8d29, 0x5864687c), TOBN(0x23b92eae, 0x22df3562),
++     TOBN(0x5c27014b, 0x9bbec39e), TOBN(0x7ef2f226, 0x9c0f0f8d),
++     TOBN(0x97359638, 0x546c4d8d), TOBN(0x5f9c3fc4, 0x92f24679),
++     TOBN(0x912e8bed, 0xa8c8acd9), TOBN(0xec3a318d, 0x306634b0),
++     TOBN(0x80167f41, 0xc31cb264), TOBN(0x3db82f6f, 0x522113f2),
++     TOBN(0xb155bcd2, 0xdcafe197), TOBN(0xfba1da59, 0x43465283),
++     TOBN(0xa0425b8e, 0xb212cf53), TOBN(0x4f2e512e, 0xf8557c5f),
++     TOBN(0xc1286ff9, 0x25c4d56c), TOBN(0xbb8a0fea, 0xee26c851),
++     TOBN(0xc28f70d2, 0xe7d6107e), TOBN(0x7ee0c444, 0xe76265aa),
++     TOBN(0x3df277a4, 0x1d1936b1), TOBN(0x1a556e3f, 0xea9595eb),
++     TOBN(0x258bbbf9, 0xe7305683), TOBN(0x31eea5bf, 0x07ef5be6),
++     TOBN(0x0deb0e4a, 0x46c814c1), TOBN(0x5cee8449, 0xa7b730dd),
++     TOBN(0xeab495c5, 0xa0182bde), TOBN(0xee759f87, 0x9e27a6b4),
++     TOBN(0xc2cf6a68, 0x80e518ca), TOBN(0x25e8013f, 0xf14cf3f4),
++     TOBN(0x8fc44140, 0x7e8d7a14), TOBN(0xbb1ff3ca, 0x9556f36a),
++     TOBN(0x6a844385, 0x14600044), TOBN(0xba3f0c4a, 0x7451ae63),
++     TOBN(0xdfcac25b, 0x1f9af32a), TOBN(0x01e0db86, 0xb1f2214b),
++     TOBN(0x4e9a5bc2, 0xa4b596ac), TOBN(0x83927681, 0x026c2c08),
++     TOBN(0x3ec832e7, 0x7acaca28), TOBN(0x1bfeea57, 0xc7385b29),
++     TOBN(0x068212e3, 0xfd1eaf38), TOBN(0xc1329830, 0x6acf8ccc),
++     TOBN(0xb909f2db, 0x2aac9e59), TOBN(0x5748060d, 0xb661782a),
++     TOBN(0xc5ab2632, 0xc79b7a01), TOBN(0xda44c6c6, 0x00017626),
++     TOBN(0xf26c00e8, 0xa7ea82f0), TOBN(0x99cac80d, 0xe4299aaf),
++     TOBN(0xd66fe3b6, 0x7ed78be1), TOBN(0x305f725f, 0x648d02cd),
++     TOBN(0x33ed1bc4, 0x623fb21b), TOBN(0xfa70533e, 0x7a6319ad),
++     TOBN(0x17ab562d, 0xbe5ffb3e), TOBN(0x06374994, 0x56674741),
++     TOBN(0x69d44ed6, 0x5c46aa8e), TOBN(0x2100d5d3, 0xa8d063d1),
++     TOBN(0xcb9727ea, 0xa2d17c36), TOBN(0x4c2bab1b, 0x8add53b7),
++     TOBN(0xa084e90c, 0x15426704), TOBN(0x778afcd3, 0xa837ebea),
++     TOBN(0x6651f701, 0x7ce477f8), TOBN(0xa0624998, 0x46fb7a8b),
++     TOBN(0xdc1e6828, 0xed8a6e19), TOBN(0x33fc2336, 0x4189d9c7),
++     TOBN(0x026f8fe2, 0x671c39bc), TOBN(0xd40c4ccd, 0xbc6f9915),
++     TOBN(0xafa135bb, 0xf80e75ca), TOBN(0x12c651a0, 0x22adff2c),
++     TOBN(0xc40a04bd, 0x4f51ad96), TOBN(0x04820109, 0xbbe4e832),
++     TOBN(0x3667eb1a, 0x7f4c04cc), TOBN(0x59556621, 0xa9404f84),
++     TOBN(0x71cdf653, 0x7eceb50a), TOBN(0x994a44a6, 0x9b8335fa),
++     TOBN(0xd7faf819, 0xdbeb9b69), TOBN(0x473c5680, 0xeed4350d),
++     TOBN(0xb6658466, 0xda44bba2), TOBN(0x0d1bc780, 0x872bdbf3),
++     TOBN(0xe535f175, 0xa1962f91), TOBN(0x6ed7e061, 0xed58f5a7),
++     TOBN(0x177aa4c0, 0x2089a233), TOBN(0x0dbcb03a, 0xe539b413),
++     TOBN(0xe3dc424e, 0xbb32e38e), TOBN(0x6472e5ef, 0x6806701e),
++     TOBN(0xdd47ff98, 0x814be9ee), TOBN(0x6b60cfff, 0x35ace009),
++     TOBN(0xb8d3d931, 0x9ff91fe5), TOBN(0x039c4800, 0xf0518eed),
++     TOBN(0x95c37632, 0x9182cb26), TOBN(0x0763a434, 0x82fc568d),
++     TOBN(0x707c04d5, 0x383e76ba), TOBN(0xac98b930, 0x824e8197),
++     TOBN(0x92bf7c8f, 0x91230de0), TOBN(0x90876a01, 0x40959b70),
++     TOBN(0xdb6d96f3, 0x05968b80), TOBN(0x380a0913, 0x089f73b9),
++     TOBN(0x7da70b83, 0xc2c61e01), TOBN(0x95fb8394, 0x569b38c7),
++     TOBN(0x9a3c6512, 0x80edfe2f), TOBN(0x8f726bb9, 0x8faeaf82),
++     TOBN(0x8010a4a0, 0x78424bf8), TOBN(0x29672044, 0x0e844970)}
++    ,
++    {TOBN(0x63c5cb81, 0x7a2ad62a), TOBN(0x7ef2b6b9, 0xac62ff54),
++     TOBN(0x3749bba4, 0xb3ad9db5), TOBN(0xad311f2c, 0x46d5a617),
++     TOBN(0xb77a8087, 0xc2ff3b6d), TOBN(0xb46feaf3, 0x367834ff),
++     TOBN(0xf8aa266d, 0x75d6b138), TOBN(0xfa38d320, 0xec008188),
++     TOBN(0x486d8ffa, 0x696946fc), TOBN(0x50fbc6d8, 0xb9cba56d),
++     TOBN(0x7e3d423e, 0x90f35a15), TOBN(0x7c3da195, 0xc0dd962c),
++     TOBN(0xe673fdb0, 0x3cfd5d8b), TOBN(0x0704b7c2, 0x889dfca5),
++     TOBN(0xf6ce581f, 0xf52305aa), TOBN(0x399d49eb, 0x914d5e53),
++     TOBN(0x380a496d, 0x6ec293cd), TOBN(0x733dbda7, 0x8e7051f5),
++     TOBN(0x037e388d, 0xb849140a), TOBN(0xee4b32b0, 0x5946dbf6),
++     TOBN(0xb1c4fda9, 0xcae368d1), TOBN(0x5001a7b0, 0xfdb0b2f3),
++     TOBN(0x6df59374, 0x2e3ac46e), TOBN(0x4af675f2, 0x39b3e656),
++     TOBN(0x44e38110, 0x39949296), TOBN(0x5b63827b, 0x361db1b5),
++     TOBN(0x3e5323ed, 0x206eaff5), TOBN(0x942370d2, 0xc21f4290),
++     TOBN(0xf2caaf2e, 0xe0d985a1), TOBN(0x192cc64b, 0x7239846d),
++     TOBN(0x7c0b8f47, 0xae6312f8), TOBN(0x7dc61f91, 0x96620108),
++     TOBN(0xb830fb5b, 0xc2da7de9), TOBN(0xd0e643df, 0x0ff8d3be),
++     TOBN(0x31ee77ba, 0x188a9641), TOBN(0x4e8aa3aa, 0xbcf6d502),
++     TOBN(0xf9fb6532, 0x9a49110f), TOBN(0xd18317f6, 0x2dd6b220),
++     TOBN(0x7e3ced41, 0x52c3ea5a), TOBN(0x0d296a14, 0x7d579c4a),
++     TOBN(0x35d6a53e, 0xed4c3717), TOBN(0x9f8240cf, 0x3d0ed2a3),
++     TOBN(0x8c0d4d05, 0xe5543aa5), TOBN(0x45d5bbfb, 0xdd33b4b4),
++     TOBN(0xfa04cc73, 0x137fd28e), TOBN(0x862ac6ef, 0xc73b3ffd),
++     TOBN(0x403ff9f5, 0x31f51ef2), TOBN(0x34d5e0fc, 0xbc73f5a2),
++     TOBN(0xf2526820, 0x08913f4f), TOBN(0xea20ed61, 0xeac93d95),
++     TOBN(0x51ed38b4, 0x6ca6b26c), TOBN(0x8662dcbc, 0xea4327b0),
++     TOBN(0x6daf295c, 0x725d2aaa), TOBN(0xbad2752f, 0x8e52dcda),
++     TOBN(0x2210e721, 0x0b17dacc), TOBN(0xa37f7912, 0xd51e8232),
++     TOBN(0x4f7081e1, 0x44cc3add), TOBN(0xd5ffa1d6, 0x87be82cf),
++     TOBN(0x89890b6c, 0x0edd6472), TOBN(0xada26e1a, 0x3ed17863),
++     TOBN(0x276f2715, 0x63483caa), TOBN(0xe6924cd9, 0x2f6077fd),
++     TOBN(0x05a7fe98, 0x0a466e3c), TOBN(0xf1c794b0, 0xb1902d1f),
++     TOBN(0xe5213688, 0x82a8042c), TOBN(0xd931cfaf, 0xcd278298),
++     TOBN(0x069a0ae0, 0xf597a740), TOBN(0x0adbb3f3, 0xeb59107c),
++     TOBN(0x983e951e, 0x5eaa8eb8), TOBN(0xe663a8b5, 0x11b48e78),
++     TOBN(0x1631cc0d, 0x8a03f2c5), TOBN(0x7577c11e, 0x11e271e2),
++     TOBN(0x33b2385c, 0x08369a90), TOBN(0x2990c59b, 0x190eb4f8),
++     TOBN(0x819a6145, 0xc68eac80), TOBN(0x7a786d62, 0x2ec4a014),
++     TOBN(0x33faadbe, 0x20ac3a8d), TOBN(0x31a21781, 0x5aba2d30),
++     TOBN(0x209d2742, 0xdba4f565), TOBN(0xdb2ce9e3, 0x55aa0fbb),
++     TOBN(0x8cef334b, 0x168984df), TOBN(0xe81dce17, 0x33879638),
++     TOBN(0xf6e6949c, 0x263720f0), TOBN(0x5c56feaf, 0xf593cbec),
++     TOBN(0x8bff5601, 0xfde58c84), TOBN(0x74e24117, 0x2eccb314),
++     TOBN(0xbcf01b61, 0x4c9a8a78), TOBN(0xa233e35e, 0x544c9868),
++     TOBN(0xb3156bf3, 0x8bd7aff1), TOBN(0x1b5ee4cb, 0x1d81b146),
++     TOBN(0x7ba1ac41, 0xd628a915), TOBN(0x8f3a8f9c, 0xfd89699e),
++     TOBN(0x7329b9c9, 0xa0748be7), TOBN(0x1d391c95, 0xa92e621f),
++     TOBN(0xe51e6b21, 0x4d10a837), TOBN(0xd255f53a, 0x4947b435),
++     TOBN(0x07669e04, 0xf1788ee3), TOBN(0xc14f27af, 0xa86938a2),
++     TOBN(0x8b47a334, 0xe93a01c0), TOBN(0xff627438, 0xd9366808),
++     TOBN(0x7a0985d8, 0xca2a5965), TOBN(0x3d9a5542, 0xd6e9b9b3),
++     TOBN(0xc23eb80b, 0x4cf972e8), TOBN(0x5c1c33bb, 0x4fdf72fd),
++     TOBN(0x0c4a58d4, 0x74a86108), TOBN(0xf8048a8f, 0xee4c5d90),
++     TOBN(0xe3c7c924, 0xe86d4c80), TOBN(0x28c889de, 0x056a1e60),
++     TOBN(0x57e2662e, 0xb214a040), TOBN(0xe8c48e98, 0x37e10347),
++     TOBN(0x87742862, 0x80ac748a), TOBN(0xf1c24022, 0x186b06f2),
++     TOBN(0xac2dd4c3, 0x5f74040a), TOBN(0x409aeb71, 0xfceac957),
++     TOBN(0x4fbad782, 0x55c4ec23), TOBN(0xb359ed61, 0x8a7b76ec),
++     TOBN(0x12744926, 0xed6f4a60), TOBN(0xe21e8d7f, 0x4b912de3),
++     TOBN(0xe2575a59, 0xfc705a59), TOBN(0x72f1d4de, 0xed2dbc0e),
++     TOBN(0x3d2b24b9, 0xeb7926b8), TOBN(0xbff88cb3, 0xcdbe5509),
++     TOBN(0xd0f399af, 0xe4dd640b), TOBN(0x3c5fe130, 0x2f76ed45),
++     TOBN(0x6f3562f4, 0x3764fb3d), TOBN(0x7b5af318, 0x3151b62d),
++     TOBN(0xd5bd0bc7, 0xd79ce5f3), TOBN(0xfdaf6b20, 0xec66890f),
++     TOBN(0x735c67ec, 0x6063540c), TOBN(0x50b259c2, 0xe5f9cb8f),
++     TOBN(0xb8734f9a, 0x3f99c6ab), TOBN(0xf8cc13d5, 0xa3a7bc85),
++     TOBN(0x80c1b305, 0xc5217659), TOBN(0xfe5364d4, 0x4ec12a54),
++     TOBN(0xbd87045e, 0x681345fe), TOBN(0x7f8efeb1, 0x582f897f),
++     TOBN(0xe8cbf1e5, 0xd5923359), TOBN(0xdb0cea9d, 0x539b9fb0),
++     TOBN(0x0c5b34cf, 0x49859b98), TOBN(0x5e583c56, 0xa4403cc6),
++     TOBN(0x11fc1a2d, 0xd48185b7), TOBN(0xc93fbc7e, 0x6e521787),
++     TOBN(0x47e7a058, 0x05105b8b), TOBN(0x7b4d4d58, 0xdb8260c8),
++     TOBN(0xe33930b0, 0x46eb842a), TOBN(0x8e844a9a, 0x7bdae56d),
++     TOBN(0x34ef3a9e, 0x13f7fdfc), TOBN(0xb3768f82, 0x636ca176),
++     TOBN(0x2821f4e0, 0x4e09e61c), TOBN(0x414dc3a1, 0xa0c7cddc),
++     TOBN(0xd5379437, 0x54945fcd), TOBN(0x151b6eef, 0xb3555ff1),
++     TOBN(0xb31bd613, 0x6339c083), TOBN(0x39ff8155, 0xdfb64701),
++     TOBN(0x7c3388d2, 0xe29604ab), TOBN(0x1e19084b, 0xa6b10442),
++     TOBN(0x17cf54c0, 0xeccd47ef), TOBN(0x89693385, 0x4a5dfb30),
++     TOBN(0x69d023fb, 0x47daf9f6), TOBN(0x9222840b, 0x7d91d959),
++     TOBN(0x439108f5, 0x803bac62), TOBN(0x0b7dd91d, 0x379bd45f),
++     TOBN(0xd651e827, 0xca63c581), TOBN(0x5c5d75f6, 0x509c104f),
++     TOBN(0x7d5fc738, 0x1f2dc308), TOBN(0x20faa7bf, 0xd98454be),
++     TOBN(0x95374bee, 0xa517b031), TOBN(0xf036b9b1, 0x642692ac),
++     TOBN(0xc5106109, 0x39842194), TOBN(0xb7e2353e, 0x49d05295),
++     TOBN(0xfc8c1d5c, 0xefb42ee0), TOBN(0xe04884eb, 0x08ce811c),
++     TOBN(0xf1f75d81, 0x7419f40e), TOBN(0x5b0ac162, 0xa995c241),
++     TOBN(0x120921bb, 0xc4c55646), TOBN(0x713520c2, 0x8d33cf97),
++     TOBN(0xb4a65a5c, 0xe98c5100), TOBN(0x6cec871d, 0x2ddd0f5a),
++     TOBN(0x251f0b7f, 0x9ba2e78b), TOBN(0x224a8434, 0xce3a2a5f),
++     TOBN(0x26827f61, 0x25f5c46f), TOBN(0x6a22bedc, 0x48545ec0),
++     TOBN(0x25ae5fa0, 0xb1bb5cdc), TOBN(0xd693682f, 0xfcb9b98f),
++     TOBN(0x32027fe8, 0x91e5d7d3), TOBN(0xf14b7d17, 0x73a07678),
++     TOBN(0xf88497b3, 0xc0dfdd61), TOBN(0xf7c2eec0, 0x2a8c4f48),
++     TOBN(0xaa5573f4, 0x3756e621), TOBN(0xc013a240, 0x1825b948),
++     TOBN(0x1c03b345, 0x63878572), TOBN(0xa0472bea, 0x653a4184),
++     TOBN(0xf4222e27, 0x0ac69a80), TOBN(0x34096d25, 0xf51e54f6),
++     TOBN(0x00a648cb, 0x8fffa591), TOBN(0x4e87acdc, 0x69b6527f),
++     TOBN(0x0575e037, 0xe285ccb4), TOBN(0x188089e4, 0x50ddcf52),
++     TOBN(0xaa96c9a8, 0x870ff719), TOBN(0x74a56cd8, 0x1fc7e369),
++     TOBN(0x41d04ee2, 0x1726931a), TOBN(0x0bbbb2c8, 0x3660ecfd),
++     TOBN(0xa6ef6de5, 0x24818e18), TOBN(0xe421cc51, 0xe7d57887),
++     TOBN(0xf127d208, 0xbea87be6), TOBN(0x16a475d3, 0xb1cdd682),
++     TOBN(0x9db1b684, 0x439b63f7), TOBN(0x5359b3db, 0xf0f113b6),
++     TOBN(0xdfccf1de, 0x8bf06e31), TOBN(0x1fdf8f44, 0xdd383901),
++     TOBN(0x10775cad, 0x5017e7d2), TOBN(0xdfc3a597, 0x58d11eef),
++     TOBN(0x6ec9c8a0, 0xb1ecff10), TOBN(0xee6ed6cc, 0x28400549),
++     TOBN(0xb5ad7bae, 0x1b4f8d73), TOBN(0x61b4f11d, 0xe00aaab9),
++     TOBN(0x7b32d69b, 0xd4eff2d7), TOBN(0x88ae6771, 0x4288b60f),
++     TOBN(0x159461b4, 0x37a1e723), TOBN(0x1f3d4789, 0x570aae8c),
++     TOBN(0x869118c0, 0x7f9871da), TOBN(0x35fbda78, 0xf635e278),
++     TOBN(0x738f3641, 0xe1541dac), TOBN(0x6794b13a, 0xc0dae45f),
++     TOBN(0x065064ac, 0x09cc0917), TOBN(0x27c53729, 0xc68540fd),
++     TOBN(0x0d2d4c8e, 0xef227671), TOBN(0xd23a9f80, 0xa1785a04),
++     TOBN(0x98c59528, 0x52650359), TOBN(0xfa09ad01, 0x74a1acad),
++     TOBN(0x082d5a29, 0x0b55bf5c), TOBN(0xa40f1c67, 0x419b8084),
++     TOBN(0x3a5c752e, 0xdcc18770), TOBN(0x4baf1f2f, 0x8825c3a5),
++     TOBN(0xebd63f74, 0x21b153ed), TOBN(0xa2383e47, 0xb2f64723),
++     TOBN(0xe7bf620a, 0x2646d19a), TOBN(0x56cb44ec, 0x03c83ffd),
++     TOBN(0xaf7267c9, 0x4f6be9f1), TOBN(0x8b2dfd7b, 0xc06bb5e9),
++     TOBN(0xb87072f2, 0xa672c5c7), TOBN(0xeacb11c8, 0x0d53c5e2),
++     TOBN(0x22dac29d, 0xff435932), TOBN(0x37bdb99d, 0x4408693c),
++     TOBN(0xf6e62fb6, 0x2899c20f), TOBN(0x3535d512, 0x447ece24),
++     TOBN(0xfbdc6b88, 0xff577ce3), TOBN(0x726693bd, 0x190575f2),
++     TOBN(0x6772b0e5, 0xab4b35a2), TOBN(0x1d8b6001, 0xf5eeaacf),
++     TOBN(0x728f7ce4, 0x795b9580), TOBN(0x4a20ed2a, 0x41fb81da),
++     TOBN(0x9f685cd4, 0x4fec01e6), TOBN(0x3ed7ddcc, 0xa7ff50ad),
++     TOBN(0x460fd264, 0x0c2d97fd), TOBN(0x3a241426, 0xeb82f4f9),
++     TOBN(0x17d1df2c, 0x6a8ea820), TOBN(0xb2b50d3b, 0xf22cc254),
++     TOBN(0x03856cba, 0xb7291426), TOBN(0x87fd26ae, 0x04f5ee39),
++     TOBN(0x9cb696cc, 0x02bee4ba), TOBN(0x53121804, 0x06820fd6),
++     TOBN(0xa5dfc269, 0x0212e985), TOBN(0x666f7ffa, 0x160f9a09),
++     TOBN(0xc503cd33, 0xbccd9617), TOBN(0x365dede4, 0xba7730a3),
++     TOBN(0x798c6355, 0x5ddb0786), TOBN(0xa6c3200e, 0xfc9cd3bc),
++     TOBN(0x060ffb2c, 0xe5e35efd), TOBN(0x99a4e25b, 0x5555a1c1),
++     TOBN(0x11d95375, 0xf70b3751), TOBN(0x0a57354a, 0x160e1bf6),
++     TOBN(0xecb3ae4b, 0xf8e4b065), TOBN(0x07a834c4, 0x2e53022b),
++     TOBN(0x1cd300b3, 0x8692ed96), TOBN(0x16a6f792, 0x61ee14ec),
++     TOBN(0x8f1063c6, 0x6a8649ed), TOBN(0xfbcdfcfe, 0x869f3e14),
++     TOBN(0x2cfb97c1, 0x00a7b3ec), TOBN(0xcea49b3c, 0x7130c2f1),
++     TOBN(0x462d044f, 0xe9d96488), TOBN(0x4b53d52e, 0x8182a0c1),
++     TOBN(0x84b6ddd3, 0x0391e9e9), TOBN(0x80ab7b48, 0xb1741a09),
++     TOBN(0xec0e15d4, 0x27d3317f), TOBN(0x8dfc1ddb, 0x1a64671e),
++     TOBN(0x93cc5d5f, 0xd49c5b92), TOBN(0xc995d53d, 0x3674a331),
++     TOBN(0x302e41ec, 0x090090ae), TOBN(0x2278a0cc, 0xedb06830),
++     TOBN(0x1d025932, 0xfbc99690), TOBN(0x0c32fbd2, 0xb80d68da),
++     TOBN(0xd79146da, 0xf341a6c1), TOBN(0xae0ba139, 0x1bef68a0),
++     TOBN(0xc6b8a563, 0x8d774b3a), TOBN(0x1cf307bd, 0x880ba4d7),
++     TOBN(0xc033bdc7, 0x19803511), TOBN(0xa9f97b3b, 0x8888c3be),
++     TOBN(0x3d68aebc, 0x85c6d05e), TOBN(0xc3b88a9d, 0x193919eb),
++     TOBN(0x2d300748, 0xc48b0ee3), TOBN(0x7506bc7c, 0x07a746c1),
++     TOBN(0xfc48437c, 0x6e6d57f3), TOBN(0x5bd71587, 0xcfeaa91a),
++     TOBN(0xa4ed0408, 0xc1bc5225), TOBN(0xd0b946db, 0x2719226d),
++     TOBN(0x109ecd62, 0x758d2d43), TOBN(0x75c8485a, 0x2751759b),
++     TOBN(0xb0b75f49, 0x9ce4177a), TOBN(0x4fa61a1e, 0x79c10c3d),
++     TOBN(0xc062d300, 0xa167fcd7), TOBN(0x4df3874c, 0x750f0fa8),
++     TOBN(0x29ae2cf9, 0x83dfedc9), TOBN(0xf8437134, 0x8d87631a),
++     TOBN(0xaf571711, 0x7429c8d2), TOBN(0x18d15867, 0x146d9272),
++     TOBN(0x83053ecf, 0x69769bb7), TOBN(0xc55eb856, 0xc479ab82),
++     TOBN(0x5ef7791c, 0x21b0f4b2), TOBN(0xaa5956ba, 0x3d491525),
++     TOBN(0x407a96c2, 0x9fe20eba), TOBN(0xf27168bb, 0xe52a5ad3),
++     TOBN(0x43b60ab3, 0xbf1d9d89), TOBN(0xe45c51ef, 0x710e727a),
++     TOBN(0xdfca5276, 0x099b4221), TOBN(0x8dc6407c, 0x2557a159),
++     TOBN(0x0ead8335, 0x91035895), TOBN(0x0a9db957, 0x9c55dc32),
++     TOBN(0xe40736d3, 0xdf61bc76), TOBN(0x13a619c0, 0x3f778cdb),
++     TOBN(0x6dd921a4, 0xc56ea28f), TOBN(0x76a52433, 0x2fa647b4),
++     TOBN(0x23591891, 0xac5bdc5d), TOBN(0xff4a1a72, 0xbac7dc01),
++     TOBN(0x9905e261, 0x62df8453), TOBN(0x3ac045df, 0xe63b265f),
++     TOBN(0x8a3f341b, 0xad53dba7), TOBN(0x8ec269cc, 0x837b625a),
++     TOBN(0xd71a2782, 0x3ae31189), TOBN(0x8fb4f9a3, 0x55e96120),
++     TOBN(0x804af823, 0xff9875cf), TOBN(0x23224f57, 0x5d442a9b),
++     TOBN(0x1c4d3b9e, 0xecc62679), TOBN(0x91da22fb, 0xa0e7ddb1),
++     TOBN(0xa370324d, 0x6c04a661), TOBN(0x9710d3b6, 0x5e376d17),
++     TOBN(0xed8c98f0, 0x3044e357), TOBN(0xc364ebbe, 0x6422701c),
++     TOBN(0x347f5d51, 0x7733d61c), TOBN(0xd55644b9, 0xcea826c3),
++     TOBN(0x80c6e0ad, 0x55a25548), TOBN(0x0aa7641d, 0x844220a7),
++     TOBN(0x1438ec81, 0x31810660), TOBN(0x9dfa6507, 0xde4b4043),
++     TOBN(0x10b515d8, 0xcc3e0273), TOBN(0x1b6066dd, 0x28d8cfb2),
++     TOBN(0xd3b04591, 0x9c9efebd), TOBN(0x425d4bdf, 0xa21c1ff4),
++     TOBN(0x5fe5af19, 0xd57607d3), TOBN(0xbbf773f7, 0x54481084),
++     TOBN(0x8435bd69, 0x94b03ed1), TOBN(0xd9ad1de3, 0x634cc546),
++     TOBN(0x2cf423fc, 0x00e420ca), TOBN(0xeed26d80, 0xa03096dd),
++     TOBN(0xd7f60be7, 0xa4db09d2), TOBN(0xf47f569d, 0x960622f7),
++     TOBN(0xe5925fd7, 0x7296c729), TOBN(0xeff2db26, 0x26ca2715),
++     TOBN(0xa6fcd014, 0xb913e759), TOBN(0x53da4786, 0x8ff4de93),
++     TOBN(0x14616d79, 0xc32068e1), TOBN(0xb187d664, 0xccdf352e),
++     TOBN(0xf7afb650, 0x1dc90b59), TOBN(0x8170e943, 0x7daa1b26),
++     TOBN(0xc8e3bdd8, 0x700c0a84), TOBN(0x6e8d345f, 0x6482bdfa),
++     TOBN(0x84cfbfa1, 0xc5c5ea50), TOBN(0xd3baf14c, 0x67960681),
++     TOBN(0x26398403, 0x0dd50942), TOBN(0xe4b7839c, 0x4716a663),
++     TOBN(0xd5f1f794, 0xe7de6dc0), TOBN(0x5cd0f4d4, 0x622aa7ce),
++     TOBN(0x5295f3f1, 0x59acfeec), TOBN(0x8d933552, 0x953e0607),
++     TOBN(0xc7db8ec5, 0x776c5722), TOBN(0xdc467e62, 0x2b5f290c),
++     TOBN(0xd4297e70, 0x4ff425a9), TOBN(0x4be924c1, 0x0cf7bb72),
++     TOBN(0x0d5dc5ae, 0xa1892131), TOBN(0x8bf8a8e3, 0xa705c992),
++     TOBN(0x73a0b064, 0x7a305ac5), TOBN(0x00c9ca4e, 0x9a8c77a8),
++     TOBN(0x5dfee80f, 0x83774bdd), TOBN(0x63131602, 0x85734485),
++     TOBN(0xa1b524ae, 0x914a69a9), TOBN(0xebc2ffaf, 0xd4e300d7),
++     TOBN(0x52c93db7, 0x7cfa46a5), TOBN(0x71e6161f, 0x21653b50),
++     TOBN(0x3574fc57, 0xa4bc580a), TOBN(0xc09015dd, 0xe1bc1253),
++     TOBN(0x4b7b47b2, 0xd174d7aa), TOBN(0x4072d8e8, 0xf3a15d04),
++     TOBN(0xeeb7d47f, 0xd6fa07ed), TOBN(0x6f2b9ff9, 0xedbdafb1),
++     TOBN(0x18c51615, 0x3760fe8a), TOBN(0x7a96e6bf, 0xf06c6c13),
++     TOBN(0x4d7a0410, 0x0ea2d071), TOBN(0xa1914e9b, 0x0be2a5ce),
++     TOBN(0x5726e357, 0xd8a3c5cf), TOBN(0x1197ecc3, 0x2abb2b13),
++     TOBN(0x6c0d7f7f, 0x31ae88dd), TOBN(0x15b20d1a, 0xfdbb3efe),
++     TOBN(0xcd06aa26, 0x70584039), TOBN(0x2277c969, 0xa7dc9747),
++     TOBN(0xbca69587, 0x7855d815), TOBN(0x899ea238, 0x5188b32a),
++     TOBN(0x37d9228b, 0x760c1c9d), TOBN(0xc7efbb11, 0x9b5c18da),
++     TOBN(0x7f0d1bc8, 0x19f6dbc5), TOBN(0x4875384b, 0x07e6905b),
++     TOBN(0xc7c50baa, 0x3ba8cd86), TOBN(0xb0ce40fb, 0xc2905de0),
++     TOBN(0x70840673, 0x7a231952), TOBN(0xa912a262, 0xcf43de26),
++     TOBN(0x9c38ddcc, 0xeb5b76c1), TOBN(0x746f5285, 0x26fc0ab4),
++     TOBN(0x52a63a50, 0xd62c269f), TOBN(0x60049c55, 0x99458621),
++     TOBN(0xe7f48f82, 0x3c2f7c9e), TOBN(0x6bd99043, 0x917d5cf3),
++     TOBN(0xeb1317a8, 0x8701f469), TOBN(0xbd3fe2ed, 0x9a449fe0),
++     TOBN(0x421e79ca, 0x12ef3d36), TOBN(0x9ee3c36c, 0x3e7ea5de),
++     TOBN(0xe48198b5, 0xcdff36f7), TOBN(0xaff4f967, 0xc6b82228),
++     TOBN(0x15e19dd0, 0xc47adb7e), TOBN(0x45699b23, 0x032e7dfa),
++     TOBN(0x40680c8b, 0x1fae026a), TOBN(0x5a347a48, 0x550dbf4d),
++     TOBN(0xe652533b, 0x3cef0d7d), TOBN(0xd94f7b18, 0x2bbb4381),
++     TOBN(0x838752be, 0x0e80f500), TOBN(0x8e6e2488, 0x9e9c9bfb),
++     TOBN(0xc9751697, 0x16caca6a), TOBN(0x866c49d8, 0x38531ad9),
++     TOBN(0xc917e239, 0x7151ade1), TOBN(0x2d016ec1, 0x6037c407),
++     TOBN(0xa407ccc9, 0x00eac3f9), TOBN(0x835f6280, 0xe2ed4748),
++     TOBN(0xcc54c347, 0x1cc98e0d), TOBN(0x0e969937, 0xdcb572eb),
++     TOBN(0x1b16c8e8, 0x8f30c9cb), TOBN(0xa606ae75, 0x373c4661),
++     TOBN(0x47aa689b, 0x35502cab), TOBN(0xf89014ae, 0x4d9bb64f),
++     TOBN(0x202f6a9c, 0x31c71f7b), TOBN(0x01f95aa3, 0x296ffe5c),
++     TOBN(0x5fc06014, 0x53cec3a3), TOBN(0xeb991237, 0x5f498a45),
++     TOBN(0xae9a935e, 0x5d91ba87), TOBN(0xc6ac6281, 0x0b564a19),
++     TOBN(0x8a8fe81c, 0x3bd44e69), TOBN(0x7c8b467f, 0x9dd11d45),
++     TOBN(0xf772251f, 0xea5b8e69), TOBN(0xaeecb3bd, 0xc5b75fbc),
++     TOBN(0x1aca3331, 0x887ff0e5), TOBN(0xbe5d49ff, 0x19f0a131),
++     TOBN(0x582c13aa, 0xe5c8646f), TOBN(0xdbaa12e8, 0x20e19980),
++     TOBN(0x8f40f31a, 0xf7abbd94), TOBN(0x1f13f5a8, 0x1dfc7663),
++     TOBN(0x5d81f1ee, 0xaceb4fc0), TOBN(0x36256002, 0x5e6f0f42),
++     TOBN(0x4b67d6d7, 0x751370c8), TOBN(0x2608b698, 0x03e80589),
++     TOBN(0xcfc0d2fc, 0x05268301), TOBN(0xa6943d39, 0x40309212),
++     TOBN(0x192a90c2, 0x1fd0e1c2), TOBN(0xb209f113, 0x37f1dc76),
++     TOBN(0xefcc5e06, 0x97bf1298), TOBN(0xcbdb6730, 0x219d639e),
++     TOBN(0xd009c116, 0xb81e8c6f), TOBN(0xa3ffdde3, 0x1a7ce2e5),
++     TOBN(0xc53fbaaa, 0xa914d3ba), TOBN(0x836d500f, 0x88df85ee),
++     TOBN(0xd98dc71b, 0x66ee0751), TOBN(0x5a3d7005, 0x714516fd),
++     TOBN(0x21d3634d, 0x39eedbba), TOBN(0x35cd2e68, 0x0455a46d),
++     TOBN(0xc8cafe65, 0xf9d7eb0c), TOBN(0xbda3ce9e, 0x00cefb3e),
++     TOBN(0xddc17a60, 0x2c9cf7a4), TOBN(0x01572ee4, 0x7bcb8773),
++     TOBN(0xa92b2b01, 0x8c7548df), TOBN(0x732fd309, 0xa84600e3),
++     TOBN(0xe22109c7, 0x16543a40), TOBN(0x9acafd36, 0xfede3c6c),
++     TOBN(0xfb206852, 0x6824e614), TOBN(0x2a4544a9, 0xda25dca0),
++     TOBN(0x25985262, 0x91d60b06), TOBN(0x281b7be9, 0x28753545),
++     TOBN(0xec667b1a, 0x90f13b27), TOBN(0x33a83aff, 0x940e2eb4),
++     TOBN(0x80009862, 0xd5d721d5), TOBN(0x0c3357a3, 0x5bd3a182),
++     TOBN(0x27f3a83b, 0x7aa2cda4), TOBN(0xb58ae74e, 0xf6f83085),
++     TOBN(0x2a911a81, 0x2e6dad6b), TOBN(0xde286051, 0xf43d6c5b),
++     TOBN(0x4bdccc41, 0xf996c4d8), TOBN(0xe7312ec0, 0x0ae1e24e)}
++    ,
++    {TOBN(0xf8d112e7, 0x6e6485b3), TOBN(0x4d3e24db, 0x771c52f8),
++     TOBN(0x48e3ee41, 0x684a2f6d), TOBN(0x7161957d, 0x21d95551),
++     TOBN(0x19631283, 0xcdb12a6c), TOBN(0xbf3fa882, 0x2e50e164),
++     TOBN(0xf6254b63, 0x3166cc73), TOBN(0x3aefa7ae, 0xaee8cc38),
++     TOBN(0x79b0fe62, 0x3b36f9fd), TOBN(0x26543b23, 0xfde19fc0),
++     TOBN(0x136e64a0, 0x958482ef), TOBN(0x23f63771, 0x9b095825),
++     TOBN(0x14cfd596, 0xb6a1142e), TOBN(0x5ea6aac6, 0x335aac0b),
++     TOBN(0x86a0e8bd, 0xf3081dd5), TOBN(0x5fb89d79, 0x003dc12a),
++     TOBN(0xf615c33a, 0xf72e34d4), TOBN(0x0bd9ea40, 0x110eec35),
++     TOBN(0x1c12bc5b, 0xc1dea34e), TOBN(0x686584c9, 0x49ae4699),
++     TOBN(0x13ad95d3, 0x8c97b942), TOBN(0x4609561a, 0x4e5c7562),
++     TOBN(0x9e94a4ae, 0xf2737f89), TOBN(0xf57594c6, 0x371c78b6),
++     TOBN(0x0f0165fc, 0xe3779ee3), TOBN(0xe00e7f9d, 0xbd495d9e),
++     TOBN(0x1fa4efa2, 0x20284e7a), TOBN(0x4564bade, 0x47ac6219),
++     TOBN(0x90e6312a, 0xc4708e8e), TOBN(0x4f5725fb, 0xa71e9adf),
++     TOBN(0xe95f55ae, 0x3d684b9f), TOBN(0x47f7ccb1, 0x1e94b415),
++     TOBN(0x7322851b, 0x8d946581), TOBN(0xf0d13133, 0xbdf4a012),
++     TOBN(0xa3510f69, 0x6584dae0), TOBN(0x03a7c171, 0x3c9f6c6d),
++     TOBN(0x5be97f38, 0xe475381a), TOBN(0xca1ba422, 0x85823334),
++     TOBN(0xf83cc5c7, 0x0be17dda), TOBN(0x158b1494, 0x0b918c0f),
++     TOBN(0xda3a77e5, 0x522e6b69), TOBN(0x69c908c3, 0xbbcd6c18),
++     TOBN(0x1f1b9e48, 0xd924fd56), TOBN(0x37c64e36, 0xaa4bb3f7),
++     TOBN(0x5a4fdbdf, 0xee478d7d), TOBN(0xba75c8bc, 0x0193f7a0),
++     TOBN(0x84bc1e84, 0x56cd16df), TOBN(0x1fb08f08, 0x46fad151),
++     TOBN(0x8a7cabf9, 0x842e9f30), TOBN(0xa331d4bf, 0x5eab83af),
++     TOBN(0xd272cfba, 0x017f2a6a), TOBN(0x27560abc, 0x83aba0e3),
++     TOBN(0x94b83387, 0x0e3a6b75), TOBN(0x25c6aea2, 0x6b9f50f5),
++     TOBN(0x803d691d, 0xb5fdf6d0), TOBN(0x03b77509, 0xe6333514),
++     TOBN(0x36178903, 0x61a341c1), TOBN(0x3604dc60, 0x0cfd6142),
++     TOBN(0x022295eb, 0x8533316c), TOBN(0x3dbde4ac, 0x44af2922),
++     TOBN(0x898afc5d, 0x1c7eef69), TOBN(0x58896805, 0xd14f4fa1),
++     TOBN(0x05002160, 0x203c21ca), TOBN(0x6f0d1f30, 0x40ef730b),
++     TOBN(0x8e8c44d4, 0x196224f8), TOBN(0x75a4ab95, 0x374d079d),
++     TOBN(0x79085ecc, 0x7d48f123), TOBN(0x56f04d31, 0x1bf65ad8),
++     TOBN(0xe220bf1c, 0xbda602b2), TOBN(0x73ee1742, 0xf9612c69),
++     TOBN(0x76008fc8, 0x084fd06b), TOBN(0x4000ef9f, 0xf11380d1),
++     TOBN(0x48201b4b, 0x12cfe297), TOBN(0x3eee129c, 0x292f74e5),
++     TOBN(0xe1fe114e, 0xc9e874e8), TOBN(0x899b055c, 0x92c5fc41),
++     TOBN(0x4e477a64, 0x3a39c8cf), TOBN(0x82f09efe, 0x78963cc9),
++     TOBN(0x6fd3fd8f, 0xd333f863), TOBN(0x85132b2a, 0xdc949c63),
++     TOBN(0x7e06a3ab, 0x516eb17b), TOBN(0x73bec06f, 0xd2c7372b),
++     TOBN(0xe4f74f55, 0xba896da6), TOBN(0xbb4afef8, 0x8e9eb40f),
++     TOBN(0x2d75bec8, 0xe61d66b0), TOBN(0x02bda4b4, 0xef29300b),
++     TOBN(0x8bbaa8de, 0x026baa5a), TOBN(0xff54befd, 0xa07f4440),
++     TOBN(0xbd9b8b1d, 0xbe7a2af3), TOBN(0xec51caa9, 0x4fb74a72),
++     TOBN(0xb9937a4b, 0x63879697), TOBN(0x7c9a9d20, 0xec2687d5),
++     TOBN(0x1773e44f, 0x6ef5f014), TOBN(0x8abcf412, 0xe90c6900),
++     TOBN(0x387bd022, 0x8142161e), TOBN(0x50393755, 0xfcb6ff2a),
++     TOBN(0x9813fd56, 0xed6def63), TOBN(0x53cf6482, 0x7d53106c),
++     TOBN(0x991a35bd, 0x431f7ac1), TOBN(0xf1e274dd, 0x63e65faf),
++     TOBN(0xf63ffa3c, 0x44cc7880), TOBN(0x411a426b, 0x7c256981),
++     TOBN(0xb698b9fd, 0x93a420e0), TOBN(0x89fdddc0, 0xae53f8fe),
++     TOBN(0x766e0722, 0x32398baa), TOBN(0x205fee42, 0x5cfca031),
++     TOBN(0xa49f5341, 0x7a029cf2), TOBN(0xa88c68b8, 0x4023890d),
++     TOBN(0xbc275041, 0x7337aaa8), TOBN(0x9ed364ad, 0x0eb384f4),
++     TOBN(0xe0816f85, 0x29aba92f), TOBN(0x2e9e1941, 0x04e38a88),
++     TOBN(0x57eef44a, 0x3dafd2d5), TOBN(0x35d1fae5, 0x97ed98d8),
++     TOBN(0x50628c09, 0x2307f9b1), TOBN(0x09d84aae, 0xd6cba5c6),
++     TOBN(0x67071bc7, 0x88aaa691), TOBN(0x2dea57a9, 0xafe6cb03),
++     TOBN(0xdfe11bb4, 0x3d78ac01), TOBN(0x7286418c, 0x7fd7aa51),
++     TOBN(0xfabf7709, 0x77f7195a), TOBN(0x8ec86167, 0xadeb838f),
++     TOBN(0xea1285a8, 0xbb4f012d), TOBN(0xd6883503, 0x9a3eab3f),
++     TOBN(0xee5d24f8, 0x309004c2), TOBN(0xa96e4b76, 0x13ffe95e),
++     TOBN(0x0cdffe12, 0xbd223ea4), TOBN(0x8f5c2ee5, 0xb6739a53),
++     TOBN(0x5cb4aaa5, 0xdd968198), TOBN(0xfa131c52, 0x72413a6c),
++     TOBN(0x53d46a90, 0x9536d903), TOBN(0xb270f0d3, 0x48606d8e),
++     TOBN(0x518c7564, 0xa053a3bc), TOBN(0x088254b7, 0x1a86caef),
++     TOBN(0xb3ba8cb4, 0x0ab5efd0), TOBN(0x5c59900e, 0x4605945d),
++     TOBN(0xecace1dd, 0xa1887395), TOBN(0x40960f36, 0x932a65de),
++     TOBN(0x9611ff5c, 0x3aa95529), TOBN(0xc58215b0, 0x7c1e5a36),
++     TOBN(0xd48c9b58, 0xf0e1a524), TOBN(0xb406856b, 0xf590dfb8),
++     TOBN(0xc7605e04, 0x9cd95662), TOBN(0x0dd036ee, 0xa33ecf82),
++     TOBN(0xa50171ac, 0xc33156b3), TOBN(0xf09d24ea, 0x4a80172e),
++     TOBN(0x4e1f72c6, 0x76dc8eef), TOBN(0xe60caadc, 0x5e3d44ee),
++     TOBN(0x006ef8a6, 0x979b1d8f), TOBN(0x60908a1c, 0x97788d26),
++     TOBN(0x6e08f95b, 0x266feec0), TOBN(0x618427c2, 0x22e8c94e),
++     TOBN(0x3d613339, 0x59145a65), TOBN(0xcd9bc368, 0xfa406337),
++     TOBN(0x82d11be3, 0x2d8a52a0), TOBN(0xf6877b27, 0x97a1c590),
++     TOBN(0x837a819b, 0xf5cbdb25), TOBN(0x2a4fd1d8, 0xde090249),
++     TOBN(0x622a7de7, 0x74990e5f), TOBN(0x840fa5a0, 0x7945511b),
++     TOBN(0x30b974be, 0x6558842d), TOBN(0x70df8c64, 0x17f3d0a6),
++     TOBN(0x7c803520, 0x7542e46d), TOBN(0x7251fe7f, 0xe4ecc823),
++     TOBN(0xe59134cb, 0x5e9aac9a), TOBN(0x11bb0934, 0xf0045d71),
++     TOBN(0x53e5d9b5, 0xdbcb1d4e), TOBN(0x8d97a905, 0x92defc91),
++     TOBN(0xfe289327, 0x7946d3f9), TOBN(0xe132bd24, 0x07472273),
++     TOBN(0xeeeb510c, 0x1eb6ae86), TOBN(0x777708c5, 0xf0595067),
++     TOBN(0x18e2c8cd, 0x1297029e), TOBN(0x2c61095c, 0xbbf9305e),
++     TOBN(0xe466c258, 0x6b85d6d9), TOBN(0x8ac06c36, 0xda1ea530),
++     TOBN(0xa365dc39, 0xa1304668), TOBN(0xe4a9c885, 0x07f89606),
++     TOBN(0x65a4898f, 0xacc7228d), TOBN(0x3e2347ff, 0x84ca8303),
++     TOBN(0xa5f6fb77, 0xea7d23a3), TOBN(0x2fac257d, 0x672a71cd),
++     TOBN(0x6908bef8, 0x7e6a44d3), TOBN(0x8ff87566, 0x891d3d7a),
++     TOBN(0xe58e90b3, 0x6b0cf82e), TOBN(0x6438d246, 0x2615b5e7),
++     TOBN(0x07b1f8fc, 0x669c145a), TOBN(0xb0d8b2da, 0x36f1e1cb),
++     TOBN(0x54d5dadb, 0xd9184c4d), TOBN(0x3dbb18d5, 0xf93d9976),
++     TOBN(0x0a3e0f56, 0xd1147d47), TOBN(0x2afa8c8d, 0xa0a48609),
++     TOBN(0x275353e8, 0xbc36742c), TOBN(0x898f427e, 0xeea0ed90),
++     TOBN(0x26f4947e, 0x3e477b00), TOBN(0x8ad8848a, 0x308741e3),
++     TOBN(0x6c703c38, 0xd74a2a46), TOBN(0x5e3e05a9, 0x9ba17ba2),
++     TOBN(0xc1fa6f66, 0x4ab9a9e4), TOBN(0x474a2d9a, 0x3841d6ec),
++     TOBN(0x871239ad, 0x653ae326), TOBN(0x14bcf72a, 0xa74cbb43),
++     TOBN(0x8737650e, 0x20d4c083), TOBN(0x3df86536, 0x110ed4af),
++     TOBN(0xd2d86fe7, 0xb53ca555), TOBN(0x688cb00d, 0xabd5d538),
++     TOBN(0xcf81bda3, 0x1ad38468), TOBN(0x7ccfe3cc, 0xf01167b6),
++     TOBN(0xcf4f47e0, 0x6c4c1fe6), TOBN(0x557e1f1a, 0x298bbb79),
++     TOBN(0xf93b974f, 0x30d45a14), TOBN(0x174a1d2d, 0x0baf97c4),
++     TOBN(0x7a003b30, 0xc51fbf53), TOBN(0xd8940991, 0xee68b225),
++     TOBN(0x5b0aa7b7, 0x1c0f4173), TOBN(0x975797c9, 0xa20a7153),
++     TOBN(0x26e08c07, 0xe3533d77), TOBN(0xd7222e6a, 0x2e341c99),
++     TOBN(0x9d60ec3d, 0x8d2dc4ed), TOBN(0xbdfe0d8f, 0x7c476cf8),
++     TOBN(0x1fe59ab6, 0x1d056605), TOBN(0xa9ea9df6, 0x86a8551f),
++     TOBN(0x8489941e, 0x47fb8d8c), TOBN(0xfeb874eb, 0x4a7f1b10),
++     TOBN(0xfe5fea86, 0x7ee0d98f), TOBN(0x201ad34b, 0xdbf61864),
++     TOBN(0x45d8fe47, 0x37c031d4), TOBN(0xd5f49fae, 0x795f0822),
++     TOBN(0xdb0fb291, 0xc7f4a40c), TOBN(0x2e69d9c1, 0x730ddd92),
++     TOBN(0x754e1054, 0x49d76987), TOBN(0x8a24911d, 0x7662db87),
++     TOBN(0x61fc1810, 0x60a71676), TOBN(0xe852d1a8, 0xf66a8ad1),
++     TOBN(0x172bbd65, 0x6417231e), TOBN(0x0d6de7bd, 0x3babb11f),
++     TOBN(0x6fde6f88, 0xc8e347f8), TOBN(0x1c587547, 0x9bd99cc3),
++     TOBN(0x78e54ed0, 0x34076950), TOBN(0x97f0f334, 0x796e83ba),
++     TOBN(0xe4dbe1ce, 0x4924867a), TOBN(0xbd5f51b0, 0x60b84917),
++     TOBN(0x37530040, 0x3cb09a79), TOBN(0xdb3fe0f8, 0xff1743d8),
++     TOBN(0xed7894d8, 0x556fa9db), TOBN(0xfa262169, 0x23412fbf),
++     TOBN(0x563be0db, 0xba7b9291), TOBN(0x6ca8b8c0, 0x0c9fb234),
++     TOBN(0xed406aa9, 0xbd763802), TOBN(0xc21486a0, 0x65303da1),
++     TOBN(0x61ae291e, 0xc7e62ec4), TOBN(0x622a0492, 0xdf99333e),
++     TOBN(0x7fd80c9d, 0xbb7a8ee0), TOBN(0xdc2ed3bc, 0x6c01aedb),
++     TOBN(0x35c35a12, 0x08be74ec), TOBN(0xd540cb1a, 0x469f671f),
++     TOBN(0xd16ced4e, 0xcf84f6c7), TOBN(0x8561fb9c, 0x2d090f43),
++     TOBN(0x7e693d79, 0x6f239db4), TOBN(0xa736f928, 0x77bd0d94),
++     TOBN(0x07b4d929, 0x2c1950ee), TOBN(0xda177543, 0x56dc11b3),
++     TOBN(0xa5dfbbaa, 0x7a6a878e), TOBN(0x1c70cb29, 0x4decb08a),
++     TOBN(0xfba28c8b, 0x6f0f7c50), TOBN(0xa8eba2b8, 0x854dcc6d),
++     TOBN(0x5ff8e89a, 0x36b78642), TOBN(0x070c1c8e, 0xf6873adf),
++     TOBN(0xbbd3c371, 0x6484d2e4), TOBN(0xfb78318f, 0x0d414129),
++     TOBN(0x2621a39c, 0x6ad93b0b), TOBN(0x979d74c2, 0xa9e917f7),
++     TOBN(0xfc195647, 0x61fb0428), TOBN(0x4d78954a, 0xbee624d4),
++     TOBN(0xb94896e0, 0xb8ae86fd), TOBN(0x6667ac0c, 0xc91c8b13),
++     TOBN(0x9f180512, 0x43bcf832), TOBN(0xfbadf8b7, 0xa0010137),
++     TOBN(0xc69b4089, 0xb3ba8aa7), TOBN(0xfac4bacd, 0xe687ce85),
++     TOBN(0x9164088d, 0x977eab40), TOBN(0x51f4c5b6, 0x2760b390),
++     TOBN(0xd238238f, 0x340dd553), TOBN(0x358566c3, 0xdb1d31c9),
++     TOBN(0x3a5ad69e, 0x5068f5ff), TOBN(0xf31435fc, 0xdaff6b06),
++     TOBN(0xae549a5b, 0xd6debff0), TOBN(0x59e5f0b7, 0x75e01331),
++     TOBN(0x5d492fb8, 0x98559acf), TOBN(0x96018c2e, 0x4db79b50),
++     TOBN(0x55f4a48f, 0x609f66aa), TOBN(0x1943b3af, 0x4900a14f),
++     TOBN(0xc22496df, 0x15a40d39), TOBN(0xb2a44684, 0x4c20f7c5),
++     TOBN(0x76a35afa, 0x3b98404c), TOBN(0xbec75725, 0xff5d1b77),
++     TOBN(0xb67aa163, 0xbea06444), TOBN(0x27e95bb2, 0xf724b6f2),
++     TOBN(0x3c20e3e9, 0xd238c8ab), TOBN(0x1213754e, 0xddd6ae17),
++     TOBN(0x8c431020, 0x716e0f74), TOBN(0x6679c82e, 0xffc095c2),
++     TOBN(0x2eb3adf4, 0xd0ac2932), TOBN(0x2cc970d3, 0x01bb7a76),
++     TOBN(0x70c71f2f, 0x740f0e66), TOBN(0x545c616b, 0x2b6b23cc),
++     TOBN(0x4528cfcb, 0xb40a8bd7), TOBN(0xff839633, 0x2ab27722),
++     TOBN(0x049127d9, 0x025ac99a), TOBN(0xd314d4a0, 0x2b63e33b),
++     TOBN(0xc8c310e7, 0x28d84519), TOBN(0x0fcb8983, 0xb3bc84ba),
++     TOBN(0x2cc52261, 0x38634818), TOBN(0x501814f4, 0xb44c2e0b),
++     TOBN(0xf7e181aa, 0x54dfdba3), TOBN(0xcfd58ff0, 0xe759718c),
++     TOBN(0xf90cdb14, 0xd3b507a8), TOBN(0x57bd478e, 0xc50bdad8),
++     TOBN(0x29c197e2, 0x50e5f9aa), TOBN(0x4db6eef8, 0xe40bc855),
++     TOBN(0x2cc8f21a, 0xd1fc0654), TOBN(0xc71cc963, 0x81269d73),
++     TOBN(0xecfbb204, 0x077f49f9), TOBN(0xdde92571, 0xca56b793),
++     TOBN(0x9abed6a3, 0xf97ad8f7), TOBN(0xe6c19d3f, 0x924de3bd),
++     TOBN(0x8dce92f4, 0xa140a800), TOBN(0x85f44d1e, 0x1337af07),
++     TOBN(0x5953c08b, 0x09d64c52), TOBN(0xa1b5e49f, 0xf5df9749),
++     TOBN(0x336a8fb8, 0x52735f7d), TOBN(0xb332b6db, 0x9add676b),
++     TOBN(0x558b88a0, 0xb4511aa4), TOBN(0x09788752, 0xdbd5cc55),
++     TOBN(0x16b43b9c, 0xd8cd52bd), TOBN(0x7f0bc5a0, 0xc2a2696b),
++     TOBN(0x146e12d4, 0xc11f61ef), TOBN(0x9ce10754, 0x3a83e79e),
++     TOBN(0x08ec73d9, 0x6cbfca15), TOBN(0x09ff29ad, 0x5b49653f),
++     TOBN(0xe31b72bd, 0xe7da946e), TOBN(0xebf9eb3b, 0xee80a4f2),
++     TOBN(0xd1aabd08, 0x17598ce4), TOBN(0x18b5fef4, 0x53f37e80),
++     TOBN(0xd5d5cdd3, 0x5958cd79), TOBN(0x3580a1b5, 0x1d373114),
++     TOBN(0xa36e4c91, 0xfa935726), TOBN(0xa38c534d, 0xef20d760),
++     TOBN(0x7088e40a, 0x2ff5845b), TOBN(0xe5bb40bd, 0xbd78177f),
++     TOBN(0x4f06a7a8, 0x857f9920), TOBN(0xe3cc3e50, 0xe968f05d),
++     TOBN(0x1d68b7fe, 0xe5682d26), TOBN(0x5206f76f, 0xaec7f87c),
++     TOBN(0x41110530, 0x041951ab), TOBN(0x58ec52c1, 0xd4b5a71a),
++     TOBN(0xf3488f99, 0x0f75cf9a), TOBN(0xf411951f, 0xba82d0d5),
++     TOBN(0x27ee75be, 0x618895ab), TOBN(0xeae060d4, 0x6d8aab14),
++     TOBN(0x9ae1df73, 0x7fb54dc2), TOBN(0x1f3e391b, 0x25963649),
++     TOBN(0x242ec32a, 0xfe055081), TOBN(0x5bd450ef, 0x8491c9bd),
++     TOBN(0x367efc67, 0x981eb389), TOBN(0xed7e1928, 0x3a0550d5),
++     TOBN(0x362e776b, 0xab3ce75c), TOBN(0xe890e308, 0x1f24c523),
++     TOBN(0xb961b682, 0xfeccef76), TOBN(0x8b8e11f5, 0x8bba6d92),
++     TOBN(0x8f2ccc4c, 0x2b2375c4), TOBN(0x0d7f7a52, 0xe2f86cfa),
++     TOBN(0xfd94d30a, 0x9efe5633), TOBN(0x2d8d246b, 0x5451f934),
++     TOBN(0x2234c6e3, 0x244e6a00), TOBN(0xde2b5b0d, 0xddec8c50),
++     TOBN(0x2ce53c5a, 0xbf776f5b), TOBN(0x6f724071, 0x60357b05),
++     TOBN(0xb2593717, 0x71bf3f7a), TOBN(0x87d2501c, 0x440c4a9f),
++     TOBN(0x440552e1, 0x87b05340), TOBN(0xb7bf7cc8, 0x21624c32),
++     TOBN(0x4155a6ce, 0x22facddb), TOBN(0x5a4228cb, 0x889837ef),
++     TOBN(0xef87d6d6, 0xfd4fd671), TOBN(0xa233687e, 0xc2daa10e),
++     TOBN(0x75622244, 0x03c0eb96), TOBN(0x7632d184, 0x8bf19be6),
++     TOBN(0x05d0f8e9, 0x40735ff4), TOBN(0x3a3e6e13, 0xc00931f1),
++     TOBN(0x31ccde6a, 0xdafe3f18), TOBN(0xf381366a, 0xcfe51207),
++     TOBN(0x24c222a9, 0x60167d92), TOBN(0x62f9d6f8, 0x7529f18c),
++     TOBN(0x412397c0, 0x0353b114), TOBN(0x334d89dc, 0xef808043),
++     TOBN(0xd9ec63ba, 0x2a4383ce), TOBN(0xcec8e937, 0x5cf92ba0),
++     TOBN(0xfb8b4288, 0xc8be74c0), TOBN(0x67d6912f, 0x105d4391),
++     TOBN(0x7b996c46, 0x1b913149), TOBN(0x36aae2ef, 0x3a4e02da),
++     TOBN(0xb68aa003, 0x972de594), TOBN(0x284ec70d, 0x4ec6d545),
++     TOBN(0xf3d2b2d0, 0x61391d54), TOBN(0x69c5d5d6, 0xfe114e92),
++     TOBN(0xbe0f00b5, 0xb4482dff), TOBN(0xe1596fa5, 0xf5bf33c5),
++     TOBN(0x10595b56, 0x96a71cba), TOBN(0x944938b2, 0xfdcadeb7),
++     TOBN(0xa282da4c, 0xfccd8471), TOBN(0x98ec05f3, 0x0d37bfe1),
++     TOBN(0xe171ce1b, 0x0698304a), TOBN(0x2d691444, 0x21bdf79b),
++     TOBN(0xd0cd3b74, 0x1b21dec1), TOBN(0x712ecd8b, 0x16a15f71),
++     TOBN(0x8d4c00a7, 0x00fd56e1), TOBN(0x02ec9692, 0xf9527c18),
++     TOBN(0x21c44937, 0x4a3e42e1), TOBN(0x9176fbab, 0x1392ae0a),
++     TOBN(0x8726f1ba, 0x44b7b618), TOBN(0xb4d7aae9, 0xf1de491c),
++     TOBN(0xf91df7b9, 0x07b582c0), TOBN(0x7e116c30, 0xef60aa3a),
++     TOBN(0x99270f81, 0x466265d7), TOBN(0xb15b6fe2, 0x4df7adf0),
++     TOBN(0xfe33b2d3, 0xf9738f7f), TOBN(0x48553ab9, 0xd6d70f95),
++     TOBN(0x2cc72ac8, 0xc21e94db), TOBN(0x795ac38d, 0xbdc0bbee),
++     TOBN(0x0a1be449, 0x2e40478f), TOBN(0x81bd3394, 0x052bde55),
++     TOBN(0x63c8dbe9, 0x56b3c4f2), TOBN(0x017a99cf, 0x904177cc),
++     TOBN(0x947bbddb, 0x4d010fc1), TOBN(0xacf9b00b, 0xbb2c9b21),
++     TOBN(0x2970bc8d, 0x47173611), TOBN(0x1a4cbe08, 0xac7d756f),
++     TOBN(0x06d9f4aa, 0x67d541a2), TOBN(0xa3e8b689, 0x59c2cf44),
++     TOBN(0xaad066da, 0x4d88f1dd), TOBN(0xc604f165, 0x7ad35dea),
++     TOBN(0x7edc0720, 0x4478ca67), TOBN(0xa10dfae0, 0xba02ce06),
++     TOBN(0xeceb1c76, 0xaf36f4e4), TOBN(0x994b2292, 0xaf3f8f48),
++     TOBN(0xbf9ed77b, 0x77c8a68c), TOBN(0x74f544ea, 0x51744c9d),
++     TOBN(0x82d05bb9, 0x8113a757), TOBN(0x4ef2d2b4, 0x8a9885e4),
++     TOBN(0x1e332be5, 0x1aa7865f), TOBN(0x22b76b18, 0x290d1a52),
++     TOBN(0x308a2310, 0x44351683), TOBN(0x9d861896, 0xa3f22840),
++     TOBN(0x5959ddcd, 0x841ed947), TOBN(0x0def0c94, 0x154b73bf),
++     TOBN(0xf0105417, 0x4c7c15e0), TOBN(0x539bfb02, 0x3a277c32),
++     TOBN(0xe699268e, 0xf9dccf5f), TOBN(0x9f5796a5, 0x0247a3bd),
++     TOBN(0x8b839de8, 0x4f157269), TOBN(0xc825c1e5, 0x7a30196b),
++     TOBN(0x6ef0aabc, 0xdc8a5a91), TOBN(0xf4a8ce6c, 0x498b7fe6),
++     TOBN(0x1cce35a7, 0x70cbac78), TOBN(0x83488e9b, 0xf6b23958),
++     TOBN(0x0341a070, 0xd76cb011), TOBN(0xda6c9d06, 0xae1b2658),
++     TOBN(0xb701fb30, 0xdd648c52), TOBN(0x994ca02c, 0x52fb9fd1),
++     TOBN(0x06933117, 0x6f563086), TOBN(0x3d2b8100, 0x17856bab),
++     TOBN(0xe89f48c8, 0x5963a46e), TOBN(0x658ab875, 0xa99e61c7),
++     TOBN(0x6e296f87, 0x4b8517b4), TOBN(0x36c4fcdc, 0xfc1bc656),
++     TOBN(0xde5227a1, 0xa3906def), TOBN(0x9fe95f57, 0x62418945),
++     TOBN(0x20c91e81, 0xfdd96cde), TOBN(0x5adbe47e, 0xda4480de),
++     TOBN(0xa009370f, 0x396de2b6), TOBN(0x98583d4b, 0xf0ecc7bd),
++     TOBN(0xf44f6b57, 0xe51d0672), TOBN(0x03d6b078, 0x556b1984),
++     TOBN(0x27dbdd93, 0xb0b64912), TOBN(0x9b3a3434, 0x15687b09),
++     TOBN(0x0dba6461, 0x51ec20a9), TOBN(0xec93db7f, 0xff28187c),
++     TOBN(0x00ff8c24, 0x66e48bdd), TOBN(0x2514f2f9, 0x11ccd78e),
++     TOBN(0xeba11f4f, 0xe1250603), TOBN(0x8a22cd41, 0x243fa156),
++     TOBN(0xa4e58df4, 0xb283e4c6), TOBN(0x78c29859, 0x8b39783f),
++     TOBN(0x5235aee2, 0xa5259809), TOBN(0xc16284b5, 0x0e0227dd),
++     TOBN(0xa5f57916, 0x1338830d), TOBN(0x6d4b8a6b, 0xd2123fca),
++     TOBN(0x236ea68a, 0xf9c546f8), TOBN(0xc1d36873, 0xfa608d36),
++     TOBN(0xcd76e495, 0x8d436d13), TOBN(0xd4d9c221, 0x8fb080af),
++     TOBN(0x665c1728, 0xe8ad3fb5), TOBN(0xcf1ebe4d, 0xb3d572e0),
++     TOBN(0xa7a8746a, 0x584c5e20), TOBN(0x267e4ea1, 0xb9dc7035),
++     TOBN(0x593a15cf, 0xb9548c9b), TOBN(0x5e6e2135, 0x4bd012f3),
++     TOBN(0xdf31cc6a, 0x8c8f936e), TOBN(0x8af84d04, 0xb5c241dc),
++     TOBN(0x63990a6f, 0x345efb86), TOBN(0x6fef4e61, 0xb9b962cb)}
++    ,
++    {TOBN(0xf6368f09, 0x25722608), TOBN(0x131260db, 0x131cf5c6),
++     TOBN(0x40eb353b, 0xfab4f7ac), TOBN(0x85c78880, 0x37eee829),
++     TOBN(0x4c1581ff, 0xc3bdf24e), TOBN(0x5bff75cb, 0xf5c3c5a8),
++     TOBN(0x35e8c83f, 0xa14e6f40), TOBN(0xb81d1c0f, 0x0295e0ca),
++     TOBN(0xfcde7cc8, 0xf43a730f), TOBN(0xe89b6f3c, 0x33ab590e),
++     TOBN(0xc823f529, 0xad03240b), TOBN(0x82b79afe, 0x98bea5db),
++     TOBN(0x568f2856, 0x962fe5de), TOBN(0x0c590adb, 0x60c591f3),
++     TOBN(0x1fc74a14, 0x4a28a858), TOBN(0x3b662498, 0xb3203f4c),
++     TOBN(0x91e3cf0d, 0x6c39765a), TOBN(0xa2db3acd, 0xac3cca0b),
++     TOBN(0x288f2f08, 0xcb953b50), TOBN(0x2414582c, 0xcf43cf1a),
++     TOBN(0x8dec8bbc, 0x60eee9a8), TOBN(0x54c79f02, 0x729aa042),
++     TOBN(0xd81cd5ec, 0x6532f5d5), TOBN(0xa672303a, 0xcf82e15f),
++     TOBN(0x376aafa8, 0x719c0563), TOBN(0xcd8ad2dc, 0xbc5fc79f),
++     TOBN(0x303fdb9f, 0xcb750cd3), TOBN(0x14ff052f, 0x4418b08e),
++     TOBN(0xf75084cf, 0x3e2d6520), TOBN(0x7ebdf0f8, 0x144ed509),
++     TOBN(0xf43bf0f2, 0xd3f25b98), TOBN(0x86ad71cf, 0xa354d837),
++     TOBN(0xb827fe92, 0x26f43572), TOBN(0xdfd3ab5b, 0x5d824758),
++     TOBN(0x315dd23a, 0x539094c1), TOBN(0x85c0e37a, 0x66623d68),
++     TOBN(0x575c7972, 0x7be19ae0), TOBN(0x616a3396, 0xdf0d36b5),
++     TOBN(0xa1ebb3c8, 0x26b1ff7e), TOBN(0x635b9485, 0x140ad453),
++     TOBN(0x92bf3cda, 0xda430c0b), TOBN(0x4702850e, 0x3a96dac6),
++     TOBN(0xc91cf0a5, 0x15ac326a), TOBN(0x95de4f49, 0xab8c25e4),
++     TOBN(0xb01bad09, 0xe265c17c), TOBN(0x24e45464, 0x087b3881),
++     TOBN(0xd43e583c, 0xe1fac5ca), TOBN(0xe17cb318, 0x6ead97a6),
++     TOBN(0x6cc39243, 0x74dcec46), TOBN(0x33cfc02d, 0x54c2b73f),
++     TOBN(0x82917844, 0xf26cd99c), TOBN(0x8819dd95, 0xd1773f89),
++     TOBN(0x09572aa6, 0x0871f427), TOBN(0x8e0cf365, 0xf6f01c34),
++     TOBN(0x7fa52988, 0xbff1f5af), TOBN(0x4eb357ea, 0xe75e8e50),
++     TOBN(0xd9d0c8c4, 0x868af75d), TOBN(0xd7325cff, 0x45c8c7ea),
++     TOBN(0xab471996, 0xcc81ecb0), TOBN(0xff5d55f3, 0x611824ed),
++     TOBN(0xbe314541, 0x1977a0ee), TOBN(0x5085c4c5, 0x722038c6),
++     TOBN(0x2d5335bf, 0xf94bb495), TOBN(0x894ad8a6, 0xc8e2a082),
++     TOBN(0x5c3e2341, 0xada35438), TOBN(0xf4a9fc89, 0x049b8c4e),
++     TOBN(0xbeeb355a, 0x9f17cf34), TOBN(0x3f311e0e, 0x6c91fe10),
++     TOBN(0xc2d20038, 0x92ab9891), TOBN(0x257bdcc1, 0x3e8ce9a9),
++     TOBN(0x1b2d9789, 0x88c53bee), TOBN(0x927ce89a, 0xcdba143a),
++     TOBN(0xb0a32cca, 0x523db280), TOBN(0x5c889f8a, 0x50d43783),
++     TOBN(0x503e04b3, 0x4897d16f), TOBN(0x8cdb6e78, 0x08f5f2e8),
++     TOBN(0x6ab91cf0, 0x179c8e74), TOBN(0xd8874e52, 0x48211d60),
++     TOBN(0xf948d4d5, 0xea851200), TOBN(0x4076d41e, 0xe6f9840a),
++     TOBN(0xc20e263c, 0x47b517ea), TOBN(0x79a448fd, 0x30685e5e),
++     TOBN(0xe55f6f78, 0xf90631a0), TOBN(0x88a790b1, 0xa79e6346),
++     TOBN(0x62160c7d, 0x80969fe8), TOBN(0x54f92fd4, 0x41491bb9),
++     TOBN(0xa6645c23, 0x5c957526), TOBN(0xf44cc5ae, 0xbea3ce7b),
++     TOBN(0xf7628327, 0x8b1e68b7), TOBN(0xc731ad7a, 0x303f29d3),
++     TOBN(0xfe5a9ca9, 0x57d03ecb), TOBN(0x96c0d50c, 0x41bc97a7),
++     TOBN(0xc4669fe7, 0x9b4f7f24), TOBN(0xfdd781d8, 0x3d9967ef),
++     TOBN(0x7892c7c3, 0x5d2c208d), TOBN(0x8bf64f7c, 0xae545cb3),
++     TOBN(0xc01f862c, 0x467be912), TOBN(0xf4c85ee9, 0xc73d30cc),
++     TOBN(0x1fa6f4be, 0x6ab83ec7), TOBN(0xa07a3c1c, 0x4e3e3cf9),
++     TOBN(0x87f8ef45, 0x0c00beb3), TOBN(0x30e2c2b3, 0x000d4c3e),
++     TOBN(0x1aa00b94, 0xfe08bf5b), TOBN(0x32c133aa, 0x9224ef52),
++     TOBN(0x38df16bb, 0x32e5685d), TOBN(0x68a9e069, 0x58e6f544),
++     TOBN(0x495aaff7, 0xcdc5ebc6), TOBN(0xf894a645, 0x378b135f),
++     TOBN(0xf316350a, 0x09e27ecf), TOBN(0xeced201e, 0x58f7179d),
++     TOBN(0x2eec273c, 0xe97861ba), TOBN(0x47ec2cae, 0xd693be2e),
++     TOBN(0xfa4c97c4, 0xf68367ce), TOBN(0xe4f47d0b, 0xbe5a5755),
++     TOBN(0x17de815d, 0xb298a979), TOBN(0xd7eca659, 0xc177dc7d),
++     TOBN(0x20fdbb71, 0x49ded0a3), TOBN(0x4cb2aad4, 0xfb34d3c5),
++     TOBN(0x2cf31d28, 0x60858a33), TOBN(0x3b6873ef, 0xa24aa40f),
++     TOBN(0x540234b2, 0x2c11bb37), TOBN(0x2d0366dd, 0xed4c74a3),
++     TOBN(0xf9a968da, 0xeec5f25d), TOBN(0x36601068, 0x67b63142),
++     TOBN(0x07cd6d2c, 0x68d7b6d4), TOBN(0xa8f74f09, 0x0c842942),
++     TOBN(0xe2751404, 0x7768b1ee), TOBN(0x4b5f7e89, 0xfe62aee4),
++     TOBN(0xc6a77177, 0x89070d26), TOBN(0xa1f28e4e, 0xdd1c8bc7),
++     TOBN(0xea5f4f06, 0x469e1f17), TOBN(0x78fc242a, 0xfbdb78e0),
++     TOBN(0xc9c7c592, 0x8b0588f1), TOBN(0xb6b7a0fd, 0x1535921e),
++     TOBN(0xcc5bdb91, 0xbde5ae35), TOBN(0xb42c485e, 0x12ff1864),
++     TOBN(0xa1113e13, 0xdbab98aa), TOBN(0xde9d469b, 0xa17b1024),
++     TOBN(0x23f48b37, 0xc0462d3a), TOBN(0x3752e537, 0x7c5c078d),
++     TOBN(0xe3a86add, 0x15544eb9), TOBN(0xf013aea7, 0x80fba279),
++     TOBN(0x8b5bb76c, 0xf22001b5), TOBN(0xe617ba14, 0xf02891ab),
++     TOBN(0xd39182a6, 0x936219d3), TOBN(0x5ce1f194, 0xae51cb19),
++     TOBN(0xc78f8598, 0xbf07a74c), TOBN(0x6d7158f2, 0x22cbf1bc),
++     TOBN(0x3b846b21, 0xe300ce18), TOBN(0x35fba630, 0x2d11275d),
++     TOBN(0x5fe25c36, 0xa0239b9b), TOBN(0xd8beb35d, 0xdf05d940),
++     TOBN(0x4db02bb0, 0x1f7e320d), TOBN(0x0641c364, 0x6da320ea),
++     TOBN(0x6d95fa5d, 0x821389a3), TOBN(0x92699748, 0x8fcd8e3d),
++     TOBN(0x316fef17, 0xceb6c143), TOBN(0x67fcb841, 0xd933762b),
++     TOBN(0xbb837e35, 0x118b17f8), TOBN(0x4b92552f, 0x9fd24821),
++     TOBN(0xae6bc70e, 0x46aca793), TOBN(0x1cf0b0e4, 0xe579311b),
++     TOBN(0x8dc631be, 0x5802f716), TOBN(0x099bdc6f, 0xbddbee4d),
++     TOBN(0xcc352bb2, 0x0caf8b05), TOBN(0xf74d505a, 0x72d63df2),
++     TOBN(0xb9876d4b, 0x91c4f408), TOBN(0x1ce18473, 0x9e229b2d),
++     TOBN(0x49507597, 0x83abdb4a), TOBN(0x850fbcb6, 0xdee84b18),
++     TOBN(0x6325236e, 0x609e67dc), TOBN(0x04d831d9, 0x9336c6d8),
++     TOBN(0x8deaae3b, 0xfa12d45d), TOBN(0xe425f8ce, 0x4746e246),
++     TOBN(0x8004c175, 0x24f5f31e), TOBN(0xaca16d8f, 0xad62c3b7),
++     TOBN(0x0dc15a6a, 0x9152f934), TOBN(0xf1235e5d, 0xed0e12c1),
++     TOBN(0xc33c06ec, 0xda477dac), TOBN(0x76be8732, 0xb2ea0006),
++     TOBN(0xcf3f7831, 0x0c0cd313), TOBN(0x3c524553, 0xa614260d),
++     TOBN(0x31a756f8, 0xcab22d15), TOBN(0x03ee10d1, 0x77827a20),
++     TOBN(0xd1e059b2, 0x1994ef20), TOBN(0x2a653b69, 0x638ae318),
++     TOBN(0x70d5eb58, 0x2f699010), TOBN(0x279739f7, 0x09f5f84a),
++     TOBN(0x5da4663c, 0x8b799336), TOBN(0xfdfdf14d, 0x203c37eb),
++     TOBN(0x32d8a9dc, 0xa1dbfb2d), TOBN(0xab40cff0, 0x77d48f9b),
++     TOBN(0xc018b383, 0xd20b42d5), TOBN(0xf9a810ef, 0x9f78845f),
++     TOBN(0x40af3753, 0xbdba9df0), TOBN(0xb90bdcfc, 0x131dfdf9),
++     TOBN(0x18720591, 0xf01ab782), TOBN(0xc823f211, 0x6af12a88),
++     TOBN(0xa51b80f3, 0x0dc14401), TOBN(0xde248f77, 0xfb2dfbe3),
++     TOBN(0xef5a44e5, 0x0cafe751), TOBN(0x73997c9c, 0xd4dcd221),
++     TOBN(0x32fd86d1, 0xde854024), TOBN(0xd5b53adc, 0xa09b84bb),
++     TOBN(0x008d7a11, 0xdcedd8d1), TOBN(0x406bd1c8, 0x74b32c84),
++     TOBN(0x5d4472ff, 0x05dde8b1), TOBN(0x2e25f2cd, 0xfce2b32f),
++     TOBN(0xbec0dd5e, 0x29dfc254), TOBN(0x4455fcf6, 0x2b98b267),
++     TOBN(0x0b4d43a5, 0xc72df2ad), TOBN(0xea70e6be, 0x48a75397),
++     TOBN(0x2aad6169, 0x5820f3bf), TOBN(0xf410d2dd, 0x9e37f68f),
++     TOBN(0x70fb7dba, 0x7be5ac83), TOBN(0x636bb645, 0x36ec3eec),
++     TOBN(0x27104ea3, 0x9754e21c), TOBN(0xbc87a3e6, 0x8d63c373),
++     TOBN(0x483351d7, 0x4109db9a), TOBN(0x0fa724e3, 0x60134da7),
++     TOBN(0x9ff44c29, 0xb0720b16), TOBN(0x2dd0cf13, 0x06aceead),
++     TOBN(0x5942758c, 0xe26929a6), TOBN(0x96c5db92, 0xb766a92b),
++     TOBN(0xcec7d4c0, 0x5f18395e), TOBN(0xd3f22744, 0x1f80d032),
++     TOBN(0x7a68b37a, 0xcb86075b), TOBN(0x074764dd, 0xafef92db),
++     TOBN(0xded1e950, 0x7bc7f389), TOBN(0xc580c850, 0xb9756460),
++     TOBN(0xaeeec2a4, 0x7da48157), TOBN(0x3f0b4e7f, 0x82c587b3),
++     TOBN(0x231c6de8, 0xa9f19c53), TOBN(0x5717bd73, 0x6974e34e),
++     TOBN(0xd9e1d216, 0xf1508fa9), TOBN(0x9f112361, 0xdadaa124),
++     TOBN(0x80145e31, 0x823b7348), TOBN(0x4dd8f0d5, 0xac634069),
++     TOBN(0xe3d82fc7, 0x2297c258), TOBN(0x276fcfee, 0x9cee7431),
++     TOBN(0x8eb61b5e, 0x2bc0aea9), TOBN(0x4f668fd5, 0xde329431),
++     TOBN(0x03a32ab1, 0x38e4b87e), TOBN(0xe1374517, 0x73d0ef0b),
++     TOBN(0x1a46f7e6, 0x853ac983), TOBN(0xc3bdf42e, 0x68e78a57),
++     TOBN(0xacf20785, 0x2ea96dd1), TOBN(0xa10649b9, 0xf1638460),
++     TOBN(0xf2369f0b, 0x879fbbed), TOBN(0x0ff0ae86, 0xda9d1869),
++     TOBN(0x5251d759, 0x56766f45), TOBN(0x4984d8c0, 0x2be8d0fc),
++     TOBN(0x7ecc95a6, 0xd21008f0), TOBN(0x29bd54a0, 0x3a1a1c49),
++     TOBN(0xab9828c5, 0xd26c50f3), TOBN(0x32c0087c, 0x51d0d251),
++     TOBN(0x9bac3ce6, 0x0c1cdb26), TOBN(0xcd94d947, 0x557ca205),
++     TOBN(0x1b1bd598, 0x9db1fdcd), TOBN(0x0eda0108, 0xa3d8b149),
++     TOBN(0x95066610, 0x56152fcc), TOBN(0xc2f037e6, 0xe7192b33),
++     TOBN(0xdeffb41a, 0xc92e05a4), TOBN(0x1105f6c2, 0xc2f6c62e),
++     TOBN(0x68e73500, 0x8733913c), TOBN(0xcce86163, 0x3f3adc40),
++     TOBN(0xf407a942, 0x38a278e9), TOBN(0xd13c1b9d, 0x2ab21292),
++     TOBN(0x93ed7ec7, 0x1c74cf5c), TOBN(0x8887dc48, 0xf1a4c1b4),
++     TOBN(0x3830ff30, 0x4b3a11f1), TOBN(0x358c5a3c, 0x58937cb6),
++     TOBN(0x027dc404, 0x89022829), TOBN(0x40e93977, 0x3b798f79),
++     TOBN(0x90ad3337, 0x38be6ead), TOBN(0x9c23f6bc, 0xf34c0a5d),
++     TOBN(0xd1711a35, 0xfbffd8bb), TOBN(0x60fcfb49, 0x1949d3dd),
++     TOBN(0x09c8ef4b, 0x7825d93a), TOBN(0x24233cff, 0xa0a8c968),
++     TOBN(0x67ade46c, 0xe6d982af), TOBN(0xebb6bf3e, 0xe7544d7c),
++     TOBN(0xd6b9ba76, 0x3d8bd087), TOBN(0x46fe382d, 0x4dc61280),
++     TOBN(0xbd39a7e8, 0xb5bdbd75), TOBN(0xab381331, 0xb8f228fe),
++     TOBN(0x0709a77c, 0xce1c4300), TOBN(0x6a247e56, 0xf337ceac),
++     TOBN(0x8f34f21b, 0x636288be), TOBN(0x9dfdca74, 0xc8a7c305),
++     TOBN(0x6decfd1b, 0xea919e04), TOBN(0xcdf2688d, 0x8e1991f8),
++     TOBN(0xe607df44, 0xd0f8a67e), TOBN(0xd985df4b, 0x0b58d010),
++     TOBN(0x57f834c5, 0x0c24f8f4), TOBN(0xe976ef56, 0xa0bf01ae),
++     TOBN(0x536395ac, 0xa1c32373), TOBN(0x351027aa, 0x734c0a13),
++     TOBN(0xd2f1b5d6, 0x5e6bd5bc), TOBN(0x2b539e24, 0x223debed),
++     TOBN(0xd4994cec, 0x0eaa1d71), TOBN(0x2a83381d, 0x661dcf65),
++     TOBN(0x5f1aed2f, 0x7b54c740), TOBN(0x0bea3fa5, 0xd6dda5ee),
++     TOBN(0x9d4fb684, 0x36cc6134), TOBN(0x8eb9bbf3, 0xc0a443dd),
++     TOBN(0xfc500e2e, 0x383b7d2a), TOBN(0x7aad621c, 0x5b775257),
++     TOBN(0x69284d74, 0x0a8f7cc0), TOBN(0xe820c2ce, 0x07562d65),
++     TOBN(0xbf9531b9, 0x499758ee), TOBN(0x73e95ca5, 0x6ee0cc2d),
++     TOBN(0xf61790ab, 0xfbaf50a5), TOBN(0xdf55e76b, 0x684e0750),
++     TOBN(0xec516da7, 0xf176b005), TOBN(0x575553bb, 0x7a2dddc7),
++     TOBN(0x37c87ca3, 0x553afa73), TOBN(0x315f3ffc, 0x4d55c251),
++     TOBN(0xe846442a, 0xaf3e5d35), TOBN(0x61b91149, 0x6495ff28),
++     TOBN(0x23cc95d3, 0xfa326dc3), TOBN(0x1df4da1f, 0x18fc2cea),
++     TOBN(0x24bf9adc, 0xd0a37d59), TOBN(0xb6710053, 0x320d6e1e),
++     TOBN(0x96f9667e, 0x618344d1), TOBN(0xcc7ce042, 0xa06445af),
++     TOBN(0xa02d8514, 0xd68dbc3a), TOBN(0x4ea109e4, 0x280b5a5b),
++     TOBN(0x5741a7ac, 0xb40961bf), TOBN(0x4ada5937, 0x6aa56bfa),
++     TOBN(0x7feb9145, 0x02b765d1), TOBN(0x561e97be, 0xe6ad1582),
++     TOBN(0xbbc4a5b6, 0xda3982f5), TOBN(0x0c2659ed, 0xb546f468),
++     TOBN(0xb8e7e6aa, 0x59612d20), TOBN(0xd83dfe20, 0xac19e8e0),
++     TOBN(0x8530c45f, 0xb835398c), TOBN(0x6106a8bf, 0xb38a41c2),
++     TOBN(0x21e8f9a6, 0x35f5dcdb), TOBN(0x39707137, 0xcae498ed),
++     TOBN(0x70c23834, 0xd8249f00), TOBN(0x9f14b58f, 0xab2537a0),
++     TOBN(0xd043c365, 0x5f61c0c2), TOBN(0xdc5926d6, 0x09a194a7),
++     TOBN(0xddec0339, 0x8e77738a), TOBN(0xd07a63ef, 0xfba46426),
++     TOBN(0x2e58e79c, 0xee7f6e86), TOBN(0xe59b0459, 0xff32d241),
++     TOBN(0xc5ec84e5, 0x20fa0338), TOBN(0x97939ac8, 0xeaff5ace),
++     TOBN(0x0310a4e3, 0xb4a38313), TOBN(0x9115fba2, 0x8f9d9885),
++     TOBN(0x8dd710c2, 0x5fadf8c3), TOBN(0x66be38a2, 0xce19c0e2),
++     TOBN(0xd42a279c, 0x4cfe5022), TOBN(0x597bb530, 0x0e24e1b8),
++     TOBN(0x3cde86b7, 0xc153ca7f), TOBN(0xa8d30fb3, 0x707d63bd),
++     TOBN(0xac905f92, 0xbd60d21e), TOBN(0x98e7ffb6, 0x7b9a54ab),
++     TOBN(0xd7147df8, 0xe9726a30), TOBN(0xb5e216ff, 0xafce3533),
++     TOBN(0xb550b799, 0x2ff1ec40), TOBN(0x6b613b87, 0xa1e953fd),
++     TOBN(0x87b88dba, 0x792d5610), TOBN(0x2ee1270a, 0xa190fbe1),
++     TOBN(0x02f4e2dc, 0x2ef581da), TOBN(0x016530e4, 0xeff82a95),
++     TOBN(0xcbb93dfd, 0x8fd6ee89), TOBN(0x16d3d986, 0x46848fff),
++     TOBN(0x600eff24, 0x1da47adf), TOBN(0x1b9754a0, 0x0ad47a71),
++     TOBN(0x8f9266df, 0x70c33b98), TOBN(0xaadc87ae, 0xdf34186e),
++     TOBN(0x0d2ce8e1, 0x4ad24132), TOBN(0x8a47cbfc, 0x19946eba),
++     TOBN(0x47feeb66, 0x62b5f3af), TOBN(0xcefab561, 0x0abb3734),
++     TOBN(0x449de60e, 0x19f35cb1), TOBN(0x39f8db14, 0x157f0eb9),
++     TOBN(0xffaecc5b, 0x3c61bfd6), TOBN(0xa5a4d41d, 0x41216703),
++     TOBN(0x7f8fabed, 0x224e1cc2), TOBN(0x0d5a8186, 0x871ad953),
++     TOBN(0xf10774f7, 0xd22da9a9), TOBN(0x45b8a678, 0xcc8a9b0d),
++     TOBN(0xd9c2e722, 0xbdc32cff), TOBN(0xbf71b5f5, 0x337202a5),
++     TOBN(0x95c57f2f, 0x69fc4db9), TOBN(0xb6dad34c, 0x765d01e1),
++     TOBN(0x7e0bd13f, 0xcb904635), TOBN(0x61751253, 0x763a588c),
++     TOBN(0xd85c2997, 0x81af2c2d), TOBN(0xc0f7d9c4, 0x81b9d7da),
++     TOBN(0x838a34ae, 0x08533e8d), TOBN(0x15c4cb08, 0x311d8311),
++     TOBN(0x97f83285, 0x8e121e14), TOBN(0xeea7dc1e, 0x85000a5f),
++     TOBN(0x0c6059b6, 0x5d256274), TOBN(0xec9beace, 0xb95075c0),
++     TOBN(0x173daad7, 0x1df97828), TOBN(0xbf851cb5, 0xa8937877),
++     TOBN(0xb083c594, 0x01646f3c), TOBN(0x3bad30cf, 0x50c6d352),
++     TOBN(0xfeb2b202, 0x496bbcea), TOBN(0x3cf9fd4f, 0x18a1e8ba),
++     TOBN(0xd26de7ff, 0x1c066029), TOBN(0x39c81e9e, 0x4e9ed4f8),
++     TOBN(0xd8be0cb9, 0x7b390d35), TOBN(0x01df2bbd, 0x964aab27),
++     TOBN(0x3e8c1a65, 0xc3ef64f8), TOBN(0x567291d1, 0x716ed1dd),
++     TOBN(0x95499c6c, 0x5f5406d3), TOBN(0x71fdda39, 0x5ba8e23f),
++     TOBN(0xcfeb320e, 0xd5096ece), TOBN(0xbe7ba92b, 0xca66dd16),
++     TOBN(0x4608d36b, 0xc6fb5a7d), TOBN(0xe3eea15a, 0x6d2dd0e0),
++     TOBN(0x75b0a3eb, 0x8f97a36a), TOBN(0xf59814cc, 0x1c83de1e),
++     TOBN(0x56c9c5b0, 0x1c33c23f), TOBN(0xa96c1da4, 0x6faa4136),
++     TOBN(0x46bf2074, 0xde316551), TOBN(0x3b866e7b, 0x1f756c8f),
++     TOBN(0x727727d8, 0x1495ed6b), TOBN(0xb2394243, 0xb682dce7),
++     TOBN(0x8ab8454e, 0x758610f3), TOBN(0xc243ce84, 0x857d72a4),
++     TOBN(0x7b320d71, 0xdbbf370f), TOBN(0xff9afa37, 0x78e0f7ca),
++     TOBN(0x0119d1e0, 0xea7b523f), TOBN(0xb997f8cb, 0x058c7d42),
++     TOBN(0x285bcd2a, 0x37bbb184), TOBN(0x51dcec49, 0xa45d1fa6),
++     TOBN(0x6ade3b64, 0xe29634cb), TOBN(0x080c94a7, 0x26b86ef1),
++     TOBN(0xba583db1, 0x2283fbe3), TOBN(0x902bddc8, 0x5a9315ed),
++     TOBN(0x07c1ccb3, 0x86964bec), TOBN(0x78f4eacf, 0xb6258301),
++     TOBN(0x4bdf3a49, 0x56f90823), TOBN(0xba0f5080, 0x741d777b),
++     TOBN(0x091d71c3, 0xf38bf760), TOBN(0x9633d50f, 0x9b625b02),
++     TOBN(0x03ecb743, 0xb8c9de61), TOBN(0xb4751254, 0x5de74720),
++     TOBN(0x9f9defc9, 0x74ce1cb2), TOBN(0x774a4f6a, 0x00bd32ef),
++     TOBN(0xaca385f7, 0x73848f22), TOBN(0x53dad716, 0xf3f8558e),
++     TOBN(0xab7b34b0, 0x93c471f9), TOBN(0xf530e069, 0x19644bc7),
++     TOBN(0x3d9fb1ff, 0xdd59d31a), TOBN(0x4382e0df, 0x08daa795),
++     TOBN(0x165c6f4b, 0xd5cc88d7), TOBN(0xeaa392d5, 0x4a18c900),
++     TOBN(0x94203c67, 0x648024ee), TOBN(0x188763f2, 0x8c2fabcd),
++     TOBN(0xa80f87ac, 0xbbaec835), TOBN(0x632c96e0, 0xf29d8d54),
++     TOBN(0x29b0a60e, 0x4c00a95e), TOBN(0x2ef17f40, 0xe011e9fa),
++     TOBN(0xf6c0e1d1, 0x15b77223), TOBN(0xaaec2c62, 0x14b04e32),
++     TOBN(0xd35688d8, 0x3d84e58c), TOBN(0x2af5094c, 0x958571db),
++     TOBN(0x4fff7e19, 0x760682a6), TOBN(0x4cb27077, 0xe39a407c),
++     TOBN(0x0f59c547, 0x4ff0e321), TOBN(0x169f34a6, 0x1b34c8ff),
++     TOBN(0x2bff1096, 0x52bc1ba7), TOBN(0xa25423b7, 0x83583544),
++     TOBN(0x5d55d5d5, 0x0ac8b782), TOBN(0xff6622ec, 0x2db3c892),
++     TOBN(0x48fce741, 0x6b8bb642), TOBN(0x31d6998c, 0x69d7e3dc),
++     TOBN(0xdbaf8004, 0xcadcaed0), TOBN(0x801b0142, 0xd81d053c),
++     TOBN(0x94b189fc, 0x59630ec6), TOBN(0x120e9934, 0xaf762c8e),
++     TOBN(0x53a29aa4, 0xfdc6a404), TOBN(0x19d8e01e, 0xa1909948),
++     TOBN(0x3cfcabf1, 0xd7e89681), TOBN(0x3321a50d, 0x4e132d37),
++     TOBN(0xd0496863, 0xe9a86111), TOBN(0x8c0cde61, 0x06a3bc65),
++     TOBN(0xaf866c49, 0xfc9f8eef), TOBN(0x2066350e, 0xff7f5141),
++     TOBN(0x4f8a4689, 0xe56ddfbd), TOBN(0xea1b0c07, 0xfe32983a),
++     TOBN(0x2b317462, 0x873cb8cb), TOBN(0x658deddc, 0x2d93229f),
++     TOBN(0x65efaf4d, 0x0f64ef58), TOBN(0xfe43287d, 0x730cc7a8),
++     TOBN(0xaebc0c72, 0x3d047d70), TOBN(0x92efa539, 0xd92d26c9),
++     TOBN(0x06e78457, 0x94b56526), TOBN(0x415cb80f, 0x0961002d),
++     TOBN(0x89e5c565, 0x76dcb10f), TOBN(0x8bbb6982, 0xff9259fe),
++     TOBN(0x4fe8795b, 0x9abc2668), TOBN(0xb5d4f534, 0x1e678fb1),
++     TOBN(0x6601f3be, 0x7b7da2b9), TOBN(0x98da59e2, 0xa13d6805),
++     TOBN(0x190d8ea6, 0x01799a52), TOBN(0xa20cec41, 0xb86d2952),
++     TOBN(0x3062ffb2, 0x7fff2a7c), TOBN(0x741b32e5, 0x79f19d37),
++     TOBN(0xf80d8181, 0x4eb57d47), TOBN(0x7a2d0ed4, 0x16aef06b),
++     TOBN(0x09735fb0, 0x1cecb588), TOBN(0x1641caaa, 0xc6061f5b)}
++    ,
++    {TOBN(0x7f99824f, 0x20151427), TOBN(0x206828b6, 0x92430206),
++     TOBN(0xaa9097d7, 0xe1112357), TOBN(0xacf9a2f2, 0x09e414ec),
++     TOBN(0xdbdac9da, 0x27915356), TOBN(0x7e0734b7, 0x001efee3),
++     TOBN(0x54fab5bb, 0xd2b288e2), TOBN(0x4c630fc4, 0xf62dd09c),
++     TOBN(0x8537107a, 0x1ac2703b), TOBN(0xb49258d8, 0x6bc857b5),
++     TOBN(0x57df14de, 0xbcdaccd1), TOBN(0x24ab68d7, 0xc4ae8529),
++     TOBN(0x7ed8b5d4, 0x734e59d0), TOBN(0x5f8740c8, 0xc495cc80),
++     TOBN(0x84aedd5a, 0x291db9b3), TOBN(0x80b360f8, 0x4fb995be),
++     TOBN(0xae915f5d, 0x5fa067d1), TOBN(0x4134b57f, 0x9668960c),
++     TOBN(0xbd3656d6, 0xa48edaac), TOBN(0xdac1e3e4, 0xfc1d7436),
++     TOBN(0x674ff869, 0xd81fbb26), TOBN(0x449ed3ec, 0xb26c33d4),
++     TOBN(0x85138705, 0xd94203e8), TOBN(0xccde538b, 0xbeeb6f4a),
++     TOBN(0x55d5c68d, 0xa61a76fa), TOBN(0x598b441d, 0xca1554dc),
++     TOBN(0xd39923b9, 0x773b279c), TOBN(0x33331d3c, 0x36bf9efc),
++     TOBN(0x2d4c848e, 0x298de399), TOBN(0xcfdb8e77, 0xa1a27f56),
++     TOBN(0x94c855ea, 0x57b8ab70), TOBN(0xdcdb9dae, 0x6f7879ba),
++     TOBN(0x7bdff8c2, 0x019f2a59), TOBN(0xb3ce5bb3, 0xcb4fbc74),
++     TOBN(0xea907f68, 0x8a9173dd), TOBN(0x6cd3d0d3, 0x95a75439),
++     TOBN(0x92ecc4d6, 0xefed021c), TOBN(0x09a9f9b0, 0x6a77339a),
++     TOBN(0x87ca6b15, 0x7188c64a), TOBN(0x10c29968, 0x44899158),
++     TOBN(0x5859a229, 0xed6e82ef), TOBN(0x16f338e3, 0x65ebaf4e),
++     TOBN(0x0cd31387, 0x5ead67ae), TOBN(0x1c73d228, 0x54ef0bb4),
++     TOBN(0x4cb55131, 0x74a5c8c7), TOBN(0x01cd2970, 0x7f69ad6a),
++     TOBN(0xa04d00dd, 0xe966f87e), TOBN(0xd96fe447, 0x0b7b0321),
++     TOBN(0x342ac06e, 0x88fbd381), TOBN(0x02cd4a84, 0x5c35a493),
++     TOBN(0xe8fa89de, 0x54f1bbcd), TOBN(0x341d6367, 0x2575ed4c),
++     TOBN(0xebe357fb, 0xd238202b), TOBN(0x600b4d1a, 0xa984ead9),
++     TOBN(0xc35c9f44, 0x52436ea0), TOBN(0x96fe0a39, 0xa370751b),
++     TOBN(0x4c4f0736, 0x7f636a38), TOBN(0x9f943fb7, 0x0e76d5cb),
++     TOBN(0xb03510ba, 0xa8b68b8b), TOBN(0xc246780a, 0x9ed07a1f),
++     TOBN(0x3c051415, 0x6d549fc2), TOBN(0xc2953f31, 0x607781ca),
++     TOBN(0x955e2c69, 0xd8d95413), TOBN(0xb300fadc, 0x7bd282e3),
++     TOBN(0x81fe7b50, 0x87e9189f), TOBN(0xdb17375c, 0xf42dda27),
++     TOBN(0x22f7d896, 0xcf0a5904), TOBN(0xa0e57c5a, 0xebe348e6),
++     TOBN(0xa61011d3, 0xf40e3c80), TOBN(0xb1189321, 0x8db705c5),
++     TOBN(0x4ed9309e, 0x50fedec3), TOBN(0xdcf14a10, 0x4d6d5c1d),
++     TOBN(0x056c265b, 0x55691342), TOBN(0xe8e08504, 0x91049dc7),
++     TOBN(0x131329f5, 0xc9bae20a), TOBN(0x96c8b3e8, 0xd9dccdb4),
++     TOBN(0x8c5ff838, 0xfb4ee6b4), TOBN(0xfc5a9aeb, 0x41e8ccf0),
++     TOBN(0x7417b764, 0xfae050c6), TOBN(0x0953c3d7, 0x00452080),
++     TOBN(0x21372682, 0x38dfe7e8), TOBN(0xea417e15, 0x2bb79d4b),
++     TOBN(0x59641f1c, 0x76e7cf2d), TOBN(0x271e3059, 0xea0bcfcc),
++     TOBN(0x624c7dfd, 0x7253ecbd), TOBN(0x2f552e25, 0x4fca6186),
++     TOBN(0xcbf84ecd, 0x4d866e9c), TOBN(0x73967709, 0xf68d4610),
++     TOBN(0xa14b1163, 0xc27901b4), TOBN(0xfd9236e0, 0x899b8bf3),
++     TOBN(0x42b091ec, 0xcbc6da0a), TOBN(0xbb1dac6f, 0x5ad1d297),
++     TOBN(0x80e61d53, 0xa91cf76e), TOBN(0x4110a412, 0xd31f1ee7),
++     TOBN(0x2d87c3ba, 0x13efcf77), TOBN(0x1f374bb4, 0xdf450d76),
++     TOBN(0x5e78e2f2, 0x0d188dab), TOBN(0xe3968ed0, 0xf4b885ef),
++     TOBN(0x46c0568e, 0x7314570f), TOBN(0x31616338, 0x01170521),
++     TOBN(0x18e1e7e2, 0x4f0c8afe), TOBN(0x4caa75ff, 0xdeea78da),
++     TOBN(0x82db67f2, 0x7c5d8a51), TOBN(0x36a44d86, 0x6f505370),
++     TOBN(0xd72c5bda, 0x0333974f), TOBN(0x5db516ae, 0x27a70146),
++     TOBN(0x34705281, 0x210ef921), TOBN(0xbff17a8f, 0x0c9c38e5),
++     TOBN(0x78f4814e, 0x12476da1), TOBN(0xc1e16613, 0x33c16980),
++     TOBN(0x9e5b386f, 0x424d4bca), TOBN(0x4c274e87, 0xc85740de),
++     TOBN(0xb6a9b88d, 0x6c2f5226), TOBN(0x14d1b944, 0x550d7ca8),
++     TOBN(0x580c85fc, 0x1fc41709), TOBN(0xc1da368b, 0x54c6d519),
++     TOBN(0x2b0785ce, 0xd5113cf7), TOBN(0x0670f633, 0x5a34708f),
++     TOBN(0x46e23767, 0x15cc3f88), TOBN(0x1b480cfa, 0x50c72c8f),
++     TOBN(0x20288602, 0x4147519a), TOBN(0xd0981eac, 0x26b372f0),
++     TOBN(0xa9d4a7ca, 0xa785ebc8), TOBN(0xd953c50d, 0xdbdf58e9),
++     TOBN(0x9d6361cc, 0xfd590f8f), TOBN(0x72e9626b, 0x44e6c917),
++     TOBN(0x7fd96110, 0x22eb64cf), TOBN(0x863ebb7e, 0x9eb288f3),
++     TOBN(0x6e6ab761, 0x6aca8ee7), TOBN(0x97d10b39, 0xd7b40358),
++     TOBN(0x1687d377, 0x1e5feb0d), TOBN(0xc83e50e4, 0x8265a27a),
++     TOBN(0x8f75a9fe, 0xc954b313), TOBN(0xcc2e8f47, 0x310d1f61),
++     TOBN(0xf5ba81c5, 0x6557d0e0), TOBN(0x25f9680c, 0x3eaf6207),
++     TOBN(0xf95c6609, 0x4354080b), TOBN(0x5225bfa5, 0x7bf2fe1c),
++     TOBN(0xc5c004e2, 0x5c7d98fa), TOBN(0x3561bf1c, 0x019aaf60),
++     TOBN(0x5e6f9f17, 0xba151474), TOBN(0xdec2f934, 0xb04f6eca),
++     TOBN(0x64e368a1, 0x269acb1e), TOBN(0x1332d9e4, 0x0cdda493),
++     TOBN(0x60d6cf69, 0xdf23de05), TOBN(0x66d17da2, 0x009339a0),
++     TOBN(0x9fcac985, 0x0a693923), TOBN(0xbcf057fc, 0xed7c6a6d),
++     TOBN(0xc3c5c8c5, 0xf0b5662c), TOBN(0x25318dd8, 0xdcba4f24),
++     TOBN(0x60e8cb75, 0x082b69ff), TOBN(0x7c23b3ee, 0x1e728c01),
++     TOBN(0x15e10a0a, 0x097e4403), TOBN(0xcb3d0a86, 0x19854665),
++     TOBN(0x88d8e211, 0xd67d4826), TOBN(0xb39af66e, 0x0b9d2839),
++     TOBN(0xa5f94588, 0xbd475ca8), TOBN(0xe06b7966, 0xc077b80b),
++     TOBN(0xfedb1485, 0xda27c26c), TOBN(0xd290d33a, 0xfe0fd5e0),
++     TOBN(0xa40bcc47, 0xf34fb0fa), TOBN(0xb4760cc8, 0x1fb1ab09),
++     TOBN(0x8fca0993, 0xa273bfe3), TOBN(0x13e4fe07, 0xf70b213c),
++     TOBN(0x3bcdb992, 0xfdb05163), TOBN(0x8c484b11, 0x0c2b19b6),
++     TOBN(0x1acb815f, 0xaaf2e3e2), TOBN(0xc6905935, 0xb89ff1b4),
++     TOBN(0xb2ad6f9d, 0x586e74e1), TOBN(0x488883ad, 0x67b80484),
++     TOBN(0x758aa2c7, 0x369c3ddb), TOBN(0x8ab74e69, 0x9f9afd31),
++     TOBN(0x10fc2d28, 0x5e21beb1), TOBN(0x3484518a, 0x318c42f9),
++     TOBN(0x377427dc, 0x53cf40c3), TOBN(0x9de0781a, 0x391bc1d9),
++     TOBN(0x8faee858, 0x693807e1), TOBN(0xa3865327, 0x4e81ccc7),
++     TOBN(0x02c30ff2, 0x6f835b84), TOBN(0xb604437b, 0x0d3d38d4),
++     TOBN(0xb3fc8a98, 0x5ca1823d), TOBN(0xb82f7ec9, 0x03be0324),
++     TOBN(0xee36d761, 0xcf684a33), TOBN(0x5a01df0e, 0x9f29bf7d),
++     TOBN(0x686202f3, 0x1306583d), TOBN(0x05b10da0, 0x437c622e),
++     TOBN(0xbf9aaa0f, 0x076a7bc8), TOBN(0x25e94efb, 0x8f8f4e43),
++     TOBN(0x8a35c9b7, 0xfa3dc26d), TOBN(0xe0e5fb93, 0x96ff03c5),
++     TOBN(0xa77e3843, 0xebc394ce), TOBN(0xcede6595, 0x8361de60),
++     TOBN(0xd27c22f6, 0xa1993545), TOBN(0xab01cc36, 0x24d671ba),
++     TOBN(0x63fa2877, 0xa169c28e), TOBN(0x925ef904, 0x2eb08376),
++     TOBN(0x3b2fa3cf, 0x53aa0b32), TOBN(0xb27beb5b, 0x71c49d7a),
++     TOBN(0xb60e1834, 0xd105e27f), TOBN(0xd6089788, 0x4f68570d),
++     TOBN(0x23094ce0, 0xd6fbc2ac), TOBN(0x738037a1, 0x815ff551),
++     TOBN(0xda73b1bb, 0x6bef119c), TOBN(0xdcf6c430, 0xeef506ba),
++     TOBN(0x00e4fe7b, 0xe3ef104a), TOBN(0xebdd9a2c, 0x0a065628),
++     TOBN(0x853a81c3, 0x8792043e), TOBN(0x22ad6ece, 0xb3b59108),
++     TOBN(0x9fb813c0, 0x39cd297d), TOBN(0x8ec7e16e, 0x05bda5d9),
++     TOBN(0x2834797c, 0x0d104b96), TOBN(0xcc11a2e7, 0x7c511510),
++     TOBN(0x96ca5a53, 0x96ee6380), TOBN(0x054c8655, 0xcea38742),
++     TOBN(0xb5946852, 0xd54dfa7d), TOBN(0x97c422e7, 0x1f4ab207),
++     TOBN(0xbf907509, 0x0c22b540), TOBN(0x2cde42aa, 0xb7c267d4),
++     TOBN(0xba18f9ed, 0x5ab0d693), TOBN(0x3ba62aa6, 0x6e4660d9),
++     TOBN(0xb24bf97b, 0xab9ea96a), TOBN(0x5d039642, 0xe3b60e32),
++     TOBN(0x4e6a4506, 0x7c4d9bd5), TOBN(0x666c5b9e, 0x7ed4a6a4),
++     TOBN(0xfa3fdcd9, 0x8edbd7cc), TOBN(0x4660bb87, 0xc6ccd753),
++     TOBN(0x9ae90820, 0x21e6b64f), TOBN(0x8a56a713, 0xb36bfb3f),
++     TOBN(0xabfce096, 0x5726d47f), TOBN(0x9eed01b2, 0x0b1a9a7f),
++     TOBN(0x30e9cad4, 0x4eb74a37), TOBN(0x7b2524cc, 0x53e9666d),
++     TOBN(0x6a29683b, 0x8f4b002f), TOBN(0xc2200d7a, 0x41f4fc20),
++     TOBN(0xcf3af47a, 0x3a338acc), TOBN(0x6539a4fb, 0xe7128975),
++     TOBN(0xcec31c14, 0xc33c7fcf), TOBN(0x7eb6799b, 0xc7be322b),
++     TOBN(0x119ef4e9, 0x6646f623), TOBN(0x7b7a26a5, 0x54d7299b),
++     TOBN(0xcb37f08d, 0x403f46f2), TOBN(0x94b8fc43, 0x1a0ec0c7),
++     TOBN(0xbb8514e3, 0xc332142f), TOBN(0xf3ed2c33, 0xe80d2a7a),
++     TOBN(0x8d2080af, 0xb639126c), TOBN(0xf7b6be60, 0xe3553ade),
++     TOBN(0x3950aa9f, 0x1c7e2b09), TOBN(0x847ff958, 0x6410f02b),
++     TOBN(0x877b7cf5, 0x678a31b0), TOBN(0xd50301ae, 0x3998b620),
++     TOBN(0x734257c5, 0xc00fb396), TOBN(0xf9fb18a0, 0x04e672a6),
++     TOBN(0xff8bd8eb, 0xe8758851), TOBN(0x1e64e4c6, 0x5d99ba44),
++     TOBN(0x4b8eaedf, 0x7dfd93b7), TOBN(0xba2f2a98, 0x04e76b8c),
++     TOBN(0x7d790cba, 0xe8053433), TOBN(0xc8e725a0, 0x3d2c9585),
++     TOBN(0x58c5c476, 0xcdd8f5ed), TOBN(0xd106b952, 0xefa9fe1d),
++     TOBN(0x3c5c775b, 0x0eff13a9), TOBN(0x242442ba, 0xe057b930),
++     TOBN(0xe9f458d4, 0xc9b70cbd), TOBN(0x69b71448, 0xa3cdb89a),
++     TOBN(0x41ee46f6, 0x0e2ed742), TOBN(0x573f1045, 0x40067493),
++     TOBN(0xb1e154ff, 0x9d54c304), TOBN(0x2ad0436a, 0x8d3a7502),
++     TOBN(0xee4aaa2d, 0x431a8121), TOBN(0xcd38b3ab, 0x886f11ed),
++     TOBN(0x57d49ea6, 0x034a0eb7), TOBN(0xd2b773bd, 0xf7e85e58),
++     TOBN(0x4a559ac4, 0x9b5c1f14), TOBN(0xc444be1a, 0x3e54df2b),
++     TOBN(0x13aad704, 0xeda41891), TOBN(0xcd927bec, 0x5eb5c788),
++     TOBN(0xeb3c8516, 0xe48c8a34), TOBN(0x1b7ac812, 0x4b546669),
++     TOBN(0x1815f896, 0x594df8ec), TOBN(0x87c6a79c, 0x79227865),
++     TOBN(0xae02a2f0, 0x9b56ddbd), TOBN(0x1339b5ac, 0x8a2f1cf3),
++     TOBN(0xf2b569c7, 0x839dff0d), TOBN(0xb0b9e864, 0xfee9a43d),
++     TOBN(0x4ff8ca41, 0x77bb064e), TOBN(0x145a2812, 0xfd249f63),
++     TOBN(0x3ab7beac, 0xf86f689a), TOBN(0x9bafec27, 0x01d35f5e),
++     TOBN(0x28054c65, 0x4265aa91), TOBN(0xa4b18304, 0x035efe42),
++     TOBN(0x6887b0e6, 0x9639dec7), TOBN(0xf4b8f6ad, 0x3d52aea5),
++     TOBN(0xfb9293cc, 0x971a8a13), TOBN(0x3f159e5d, 0x4c934d07),
++     TOBN(0x2c50e9b1, 0x09acbc29), TOBN(0x08eb65e6, 0x7154d129),
++     TOBN(0x4feff589, 0x30b75c3e), TOBN(0x0bb82fe2, 0x94491c93),
++     TOBN(0xd8ac377a, 0x89af62bb), TOBN(0xd7b51490, 0x9685e49f),
++     TOBN(0xabca9a7b, 0x04497f19), TOBN(0x1b35ed0a, 0x1a7ad13f),
++     TOBN(0x6b601e21, 0x3ec86ed6), TOBN(0xda91fcb9, 0xce0c76f1),
++     TOBN(0x9e28507b, 0xd7ab27e1), TOBN(0x7c19a555, 0x63945b7b),
++     TOBN(0x6b43f0a1, 0xaafc9827), TOBN(0x443b4fbd, 0x3aa55b91),
++     TOBN(0x962b2e65, 0x6962c88f), TOBN(0x139da8d4, 0xce0db0ca),
++     TOBN(0xb93f05dd, 0x1b8d6c4f), TOBN(0x779cdff7, 0x180b9824),
++     TOBN(0xbba23fdd, 0xae57c7b7), TOBN(0x345342f2, 0x1b932522),
++     TOBN(0xfd9c80fe, 0x556d4aa3), TOBN(0xa03907ba, 0x6525bb61),
++     TOBN(0x38b010e1, 0xff218933), TOBN(0xc066b654, 0xaa52117b),
++     TOBN(0x8e141920, 0x94f2e6ea), TOBN(0x66a27dca, 0x0d32f2b2),
++     TOBN(0x69c7f993, 0x048b3717), TOBN(0xbf5a989a, 0xb178ae1c),
++     TOBN(0x49fa9058, 0x564f1d6b), TOBN(0x27ec6e15, 0xd31fde4e),
++     TOBN(0x4cce0373, 0x7276e7fc), TOBN(0x64086d79, 0x89d6bf02),
++     TOBN(0x5a72f046, 0x4ccdd979), TOBN(0x909c3566, 0x47775631),
++     TOBN(0x1c07bc6b, 0x75dd7125), TOBN(0xb4c6bc97, 0x87a0428d),
++     TOBN(0x507ece52, 0xfdeb6b9d), TOBN(0xfca56512, 0xb2c95432),
++     TOBN(0x15d97181, 0xd0e8bd06), TOBN(0x384dd317, 0xc6bb46ea),
++     TOBN(0x5441ea20, 0x3952b624), TOBN(0xbcf70dee, 0x4e7dc2fb),
++     TOBN(0x372b016e, 0x6628e8c3), TOBN(0x07a0d667, 0xb60a7522),
++     TOBN(0xcf05751b, 0x0a344ee2), TOBN(0x0ec09a48, 0x118bdeec),
++     TOBN(0x6e4b3d4e, 0xd83dce46), TOBN(0x43a6316d, 0x99d2fc6e),
++     TOBN(0xa99d8989, 0x56cf044c), TOBN(0x7c7f4454, 0xae3e5fb7),
++     TOBN(0xb2e6b121, 0xfbabbe92), TOBN(0x281850fb, 0xe1330076),
++     TOBN(0x093581ec, 0x97890015), TOBN(0x69b1dded, 0x75ff77f5),
++     TOBN(0x7cf0b18f, 0xab105105), TOBN(0x953ced31, 0xa89ccfef),
++     TOBN(0x3151f85f, 0xeb914009), TOBN(0x3c9f1b87, 0x88ed48ad),
++     TOBN(0xc9aba1a1, 0x4a7eadcb), TOBN(0x928e7501, 0x522e71cf),
++     TOBN(0xeaede727, 0x3a2e4f83), TOBN(0x467e10d1, 0x1ce3bbd3),
++     TOBN(0xf3442ac3, 0xb955dcf0), TOBN(0xba96307d, 0xd3d5e527),
++     TOBN(0xf763a10e, 0xfd77f474), TOBN(0x5d744bd0, 0x6a6e1ff0),
++     TOBN(0xd287282a, 0xa777899e), TOBN(0xe20eda8f, 0xd03f3cde),
++     TOBN(0x6a7e75bb, 0x50b07d31), TOBN(0x0b7e2a94, 0x6f379de4),
++     TOBN(0x31cb64ad, 0x19f593cf), TOBN(0x7b1a9e4f, 0x1e76ef1d),
++     TOBN(0xe18c9c9d, 0xb62d609c), TOBN(0x439bad6d, 0xe779a650),
++     TOBN(0x219d9066, 0xe032f144), TOBN(0x1db632b8, 0xe8b2ec6a),
++     TOBN(0xff0d0fd4, 0xfda12f78), TOBN(0x56fb4c2d, 0x2a25d265),
++     TOBN(0x5f4e2ee1, 0x255a03f1), TOBN(0x61cd6af2, 0xe96af176),
++     TOBN(0xe0317ba8, 0xd068bc97), TOBN(0x927d6bab, 0x264b988e),
++     TOBN(0xa18f07e0, 0xe90fb21e), TOBN(0x00fd2b80, 0xbba7fca1),
++     TOBN(0x20387f27, 0x95cd67b5), TOBN(0x5b89a4e7, 0xd39707f7),
++     TOBN(0x8f83ad3f, 0x894407ce), TOBN(0xa0025b94, 0x6c226132),
++     TOBN(0xc79563c7, 0xf906c13b), TOBN(0x5f548f31, 0x4e7bb025),
++     TOBN(0x2b4c6b8f, 0xeac6d113), TOBN(0xa67e3f9c, 0x0e813c76),
++     TOBN(0x3982717c, 0x3fe1f4b9), TOBN(0x58865819, 0x26d8050e),
++     TOBN(0x99f3640c, 0xf7f06f20), TOBN(0xdc610216, 0x2a66ebc2),
++     TOBN(0x52f2c175, 0x767a1e08), TOBN(0x05660e1a, 0x5999871b),
++     TOBN(0x6b0f1762, 0x6d3c4693), TOBN(0xf0e7d627, 0x37ed7bea),
++     TOBN(0xc51758c7, 0xb75b226d), TOBN(0x40a88628, 0x1f91613b),
++     TOBN(0x889dbaa7, 0xbbb38ce0), TOBN(0xe0404b65, 0xbddcad81),
++     TOBN(0xfebccd3a, 0x8bc9671f), TOBN(0xfbf9a357, 0xee1f5375),
++     TOBN(0x5dc169b0, 0x28f33398), TOBN(0xb07ec11d, 0x72e90f65),
++     TOBN(0xae7f3b4a, 0xfaab1eb1), TOBN(0xd970195e, 0x5f17538a),
++     TOBN(0x52b05cbe, 0x0181e640), TOBN(0xf5debd62, 0x2643313d),
++     TOBN(0x76148154, 0x5df31f82), TOBN(0x23e03b33, 0x3a9e13c5),
++     TOBN(0xff758949, 0x4fde0c1f), TOBN(0xbf8a1abe, 0xe5b6ec20),
++     TOBN(0x702278fb, 0x87e1db6c), TOBN(0xc447ad7a, 0x35ed658f),
++     TOBN(0x48d4aa38, 0x03d0ccf2), TOBN(0x80acb338, 0x819a7c03),
++     TOBN(0x9bc7c89e, 0x6e17cecc), TOBN(0x46736b8b, 0x03be1d82),
++     TOBN(0xd65d7b60, 0xc0432f96), TOBN(0xddebe7a3, 0xdeb5442f),
++     TOBN(0x79a25307, 0x7dff69a2), TOBN(0x37a56d94, 0x02cf3122),
++     TOBN(0x8bab8aed, 0xf2350d0a), TOBN(0x13c3f276, 0x037b0d9a),
++     TOBN(0xc664957c, 0x44c65cae), TOBN(0x88b44089, 0xc2e71a88),
++     TOBN(0xdb88e5a3, 0x5cb02664), TOBN(0x5d4c0bf1, 0x8686c72e),
++     TOBN(0xea3d9b62, 0xa682d53e), TOBN(0x9b605ef4, 0x0b2ad431),
++     TOBN(0x71bac202, 0xc69645d0), TOBN(0xa115f03a, 0x6a1b66e7),
++     TOBN(0xfe2c563a, 0x158f4dc4), TOBN(0xf715b3a0, 0x4d12a78c),
++     TOBN(0x8f7f0a48, 0xd413213a), TOBN(0x2035806d, 0xc04becdb),
++     TOBN(0xecd34a99, 0x5d8587f5), TOBN(0x4d8c3079, 0x9f6d3a71),
++     TOBN(0x1b2a2a67, 0x8d95a8f6), TOBN(0xc58c9d7d, 0xf2110d0d),
++     TOBN(0xdeee81d5, 0xcf8fba3f), TOBN(0xa42be3c0, 0x0c7cdf68),
++     TOBN(0x2126f742, 0xd43b5eaa), TOBN(0x054a0766, 0xdfa59b85),
++     TOBN(0x9d0d5e36, 0x126bfd45), TOBN(0xa1f8fbd7, 0x384f8a8f),
++     TOBN(0x317680f5, 0xd563fccc), TOBN(0x48ca5055, 0xf280a928),
++     TOBN(0xe00b81b2, 0x27b578cf), TOBN(0x10aad918, 0x2994a514),
++     TOBN(0xd9e07b62, 0xb7bdc953), TOBN(0x9f0f6ff2, 0x5bc086dd),
++     TOBN(0x09d1ccff, 0x655eee77), TOBN(0x45475f79, 0x5bef7df1),
++     TOBN(0x3faa28fa, 0x86f702cc), TOBN(0x92e60905, 0x0f021f07),
++     TOBN(0xe9e62968, 0x7f8fa8c6), TOBN(0xbd71419a, 0xf036ea2c),
++     TOBN(0x171ee1cc, 0x6028da9a), TOBN(0x5352fe1a, 0xc251f573),
++     TOBN(0xf8ff236e, 0x3fa997f4), TOBN(0xd831b6c9, 0xa5749d5f),
++     TOBN(0x7c872e1d, 0xe350e2c2), TOBN(0xc56240d9, 0x1e0ce403),
++     TOBN(0xf9deb077, 0x6974f5cb), TOBN(0x7d50ba87, 0x961c3728),
++     TOBN(0xd6f89426, 0x5a3a2518), TOBN(0xcf817799, 0xc6303d43),
++     TOBN(0x510a0471, 0x619e5696), TOBN(0xab049ff6, 0x3a5e307b),
++     TOBN(0xe4cdf9b0, 0xfeb13ec7), TOBN(0xd5e97117, 0x9d8ff90c),
++     TOBN(0xf6f64d06, 0x9afa96af), TOBN(0x00d0bf5e, 0x9d2012a2),
++     TOBN(0xe63f301f, 0x358bcdc0), TOBN(0x07689e99, 0x0a9d47f8),
++     TOBN(0x1f689e2f, 0x4f43d43a), TOBN(0x4d542a16, 0x90920904),
++     TOBN(0xaea293d5, 0x9ca0a707), TOBN(0xd061fe45, 0x8ac68065),
++     TOBN(0x1033bf1b, 0x0090008c), TOBN(0x29749558, 0xc08a6db6),
++     TOBN(0x74b5fc59, 0xc1d5d034), TOBN(0xf712e9f6, 0x67e215e0),
++     TOBN(0xfd520cbd, 0x860200e6), TOBN(0x0229acb4, 0x3ea22588),
++     TOBN(0x9cd1e14c, 0xfff0c82e), TOBN(0x87684b62, 0x59c69e73),
++     TOBN(0xda85e61c, 0x96ccb989), TOBN(0x2d5dbb02, 0xa3d06493),
++     TOBN(0xf22ad33a, 0xe86b173c), TOBN(0xe8e41ea5, 0xa79ff0e3),
++     TOBN(0x01d2d725, 0xdd0d0c10), TOBN(0x31f39088, 0x032d28f9),
++     TOBN(0x7b3f71e1, 0x7829839e), TOBN(0x0cf691b4, 0x4502ae58),
++     TOBN(0xef658dbd, 0xbefc6115), TOBN(0xa5cd6ee5, 0xb3ab5314),
++     TOBN(0x206c8d7b, 0x5f1d2347), TOBN(0x794645ba, 0x4cc2253a),
++     TOBN(0xd517d8ff, 0x58389e08), TOBN(0x4fa20dee, 0x9f847288),
++     TOBN(0xeba072d8, 0xd797770a), TOBN(0x7360c91d, 0xbf429e26),
++     TOBN(0x7200a3b3, 0x80af8279), TOBN(0x6a1c9150, 0x82dadce3),
++     TOBN(0x0ee6d3a7, 0xc35d8794), TOBN(0x042e6558, 0x0356bae5),
++     TOBN(0x9f59698d, 0x643322fd), TOBN(0x9379ae15, 0x50a61967),
++     TOBN(0x64b9ae62, 0xfcc9981e), TOBN(0xaed3d631, 0x6d2934c6),
++     TOBN(0x2454b302, 0x5e4e65eb), TOBN(0xab09f647, 0xf9950428)}
++    ,
++    {TOBN(0xb2083a12, 0x22248acc), TOBN(0x1f6ec0ef, 0x3264e366),
++     TOBN(0x5659b704, 0x5afdee28), TOBN(0x7a823a40, 0xe6430bb5),
++     TOBN(0x24592a04, 0xe1900a79), TOBN(0xcde09d4a, 0xc9ee6576),
++     TOBN(0x52b6463f, 0x4b5ea54a), TOBN(0x1efe9ed3, 0xd3ca65a7),
++     TOBN(0xe27a6dbe, 0x305406dd), TOBN(0x8eb7dc7f, 0xdd5d1957),
++     TOBN(0xf54a6876, 0x387d4d8f), TOBN(0x9c479409, 0xc7762de4),
++     TOBN(0xbe4d5b5d, 0x99b30778), TOBN(0x25380c56, 0x6e793682),
++     TOBN(0x602d37f3, 0xdac740e3), TOBN(0x140deabe, 0x1566e4ae),
++     TOBN(0x4481d067, 0xafd32acf), TOBN(0xd8f0fcca, 0xe1f71ccf),
++     TOBN(0xd208dd0c, 0xb596f2da), TOBN(0xd049d730, 0x9aad93f9),
++     TOBN(0xc79f263d, 0x42ab580e), TOBN(0x09411bb1, 0x23f707b4),
++     TOBN(0x8cfde1ff, 0x835e0eda), TOBN(0x72707490, 0x90f03402),
++     TOBN(0xeaee6126, 0xc49a861e), TOBN(0x024f3b65, 0xe14f0d06),
++     TOBN(0x51a3f1e8, 0xc69bfc17), TOBN(0xc3c3a8e9, 0xa7686381),
++     TOBN(0x3400752c, 0xb103d4c8), TOBN(0x02bc4613, 0x9218b36b),
++     TOBN(0xc67f75eb, 0x7651504a), TOBN(0xd6848b56, 0xd02aebfa),
++     TOBN(0xbd9802e6, 0xc30fa92b), TOBN(0x5a70d96d, 0x9a552784),
++     TOBN(0x9085c4ea, 0x3f83169b), TOBN(0xfa9423bb, 0x06908228),
++     TOBN(0x2ffebe12, 0xfe97a5b9), TOBN(0x85da6049, 0x71b99118),
++     TOBN(0x9cbc2f7f, 0x63178846), TOBN(0xfd96bc70, 0x9153218e),
++     TOBN(0x958381db, 0x1782269b), TOBN(0xae34bf79, 0x2597e550),
++     TOBN(0xbb5c6064, 0x5f385153), TOBN(0x6f0e96af, 0xe3088048),
++     TOBN(0xbf6a0215, 0x77884456), TOBN(0xb3b5688c, 0x69310ea7),
++     TOBN(0x17c94295, 0x04fad2de), TOBN(0xe020f0e5, 0x17896d4d),
++     TOBN(0x730ba0ab, 0x0976505f), TOBN(0x567f6813, 0x095e2ec5),
++     TOBN(0x47062010, 0x6331ab71), TOBN(0x72cfa977, 0x41d22b9f),
++     TOBN(0x33e55ead, 0x8a2373da), TOBN(0xa8d0d5f4, 0x7ba45a68),
++     TOBN(0xba1d8f9c, 0x03029d15), TOBN(0x8f34f1cc, 0xfc55b9f3),
++     TOBN(0xcca4428d, 0xbbe5a1a9), TOBN(0x8187fd5f, 0x3126bd67),
++     TOBN(0x0036973a, 0x48105826), TOBN(0xa39b6663, 0xb8bd61a0),
++     TOBN(0x6d42deef, 0x2d65a808), TOBN(0x4969044f, 0x94636b19),
++     TOBN(0xf611ee47, 0xdd5d564c), TOBN(0x7b2f3a49, 0xd2873077),
++     TOBN(0x94157d45, 0x300eb294), TOBN(0x2b2a656e, 0x169c1494),
++     TOBN(0xc000dd76, 0xd3a47aa9), TOBN(0xa2864e4f, 0xa6243ea4),
++     TOBN(0x82716c47, 0xdb89842e), TOBN(0x12dfd7d7, 0x61479fb7),
++     TOBN(0x3b9a2c56, 0xe0b2f6dc), TOBN(0x46be862a, 0xd7f85d67),
++     TOBN(0x03b0d8dd, 0x0f82b214), TOBN(0x460c34f9, 0xf103cbc6),
++     TOBN(0xf32e5c03, 0x18d79e19), TOBN(0x8b8888ba, 0xa84117f8),
++     TOBN(0x8f3c37dc, 0xc0722677), TOBN(0x10d21be9, 0x1c1c0f27),
++     TOBN(0xd47c8468, 0xe0f7a0c6), TOBN(0x9bf02213, 0xadecc0e0),
++     TOBN(0x0baa7d12, 0x42b48b99), TOBN(0x1bcb665d, 0x48424096),
++     TOBN(0x8b847cd6, 0xebfb5cfb), TOBN(0x87c2ae56, 0x9ad4d10d),
++     TOBN(0xf1cbb122, 0x0de36726), TOBN(0xe7043c68, 0x3fdfbd21),
++     TOBN(0x4bd0826a, 0x4e79d460), TOBN(0x11f5e598, 0x4bd1a2cb),
++     TOBN(0x97554160, 0xb7fe7b6e), TOBN(0x7d16189a, 0x400a3fb2),
++     TOBN(0xd73e9bea, 0xe328ca1e), TOBN(0x0dd04b97, 0xe793d8cc),
++     TOBN(0xa9c83c9b, 0x506db8cc), TOBN(0x5cd47aae, 0xcf38814c),
++     TOBN(0x26fc430d, 0xb64b45e6), TOBN(0x079b5499, 0xd818ea84),
++     TOBN(0xebb01102, 0xc1c24a3b), TOBN(0xca24e568, 0x1c161c1a),
++     TOBN(0x103eea69, 0x36f00a4a), TOBN(0x9ad76ee8, 0x76176c7b),
++     TOBN(0x97451fc2, 0x538e0ff7), TOBN(0x94f89809, 0x6604b3b0),
++     TOBN(0x6311436e, 0x3249cfd7), TOBN(0x27b4a7bd, 0x41224f69),
++     TOBN(0x03b5d21a, 0xe0ac2941), TOBN(0x279b0254, 0xc2d31937),
++     TOBN(0x3307c052, 0xcac992d0), TOBN(0x6aa7cb92, 0xefa8b1f3),
++     TOBN(0x5a182580, 0x0d37c7a5), TOBN(0x13380c37, 0x342d5422),
++     TOBN(0x92ac2d66, 0xd5d2ef92), TOBN(0x035a70c9, 0x030c63c6),
++     TOBN(0xc16025dd, 0x4ce4f152), TOBN(0x1f419a71, 0xf9df7c06),
++     TOBN(0x6d5b2214, 0x91e4bb14), TOBN(0xfc43c6cc, 0x839fb4ce),
++     TOBN(0x49f06591, 0x925d6b2d), TOBN(0x4b37d9d3, 0x62186598),
++     TOBN(0x8c54a971, 0xd01b1629), TOBN(0xe1a9c29f, 0x51d50e05),
++     TOBN(0x5109b785, 0x71ba1861), TOBN(0x48b22d5c, 0xd0c8f93d),
++     TOBN(0xe8fa84a7, 0x8633bb93), TOBN(0x53fba6ba, 0x5aebbd08),
++     TOBN(0x7ff27df3, 0xe5eea7d8), TOBN(0x521c8796, 0x68ca7158),
++     TOBN(0xb9d5133b, 0xce6f1a05), TOBN(0x2d50cd53, 0xfd0ebee4),
++     TOBN(0xc82115d6, 0xc5a3ef16), TOBN(0x993eff9d, 0xba079221),
++     TOBN(0xe4da2c5e, 0x4b5da81c), TOBN(0x9a89dbdb, 0x8033fd85),
++     TOBN(0x60819ebf, 0x2b892891), TOBN(0x53902b21, 0x5d14a4d5),
++     TOBN(0x6ac35051, 0xd7fda421), TOBN(0xcc6ab885, 0x61c83284),
++     TOBN(0x14eba133, 0xf74cff17), TOBN(0x240aaa03, 0xecb813f2),
++     TOBN(0xcfbb6540, 0x6f665bee), TOBN(0x084b1fe4, 0xa425ad73),
++     TOBN(0x009d5d16, 0xd081f6a6), TOBN(0x35304fe8, 0xeef82c90),
++     TOBN(0xf20346d5, 0xaa9eaa22), TOBN(0x0ada9f07, 0xac1c91e3),
++     TOBN(0xa6e21678, 0x968a6144), TOBN(0x54c1f77c, 0x07b31a1e),
++     TOBN(0xd6bb787e, 0x5781fbe1), TOBN(0x61bd2ee0, 0xe31f1c4a),
++     TOBN(0xf25aa1e9, 0x781105fc), TOBN(0x9cf2971f, 0x7b2f8e80),
++     TOBN(0x26d15412, 0xcdff919b), TOBN(0x01db4ebe, 0x34bc896e),
++     TOBN(0x7d9b3e23, 0xb40df1cf), TOBN(0x59337373, 0x94e971b4),
++     TOBN(0xbf57bd14, 0x669cf921), TOBN(0x865daedf, 0x0c1a1064),
++     TOBN(0x3eb70bd3, 0x83279125), TOBN(0xbc3d5b9f, 0x34ecdaab),
++     TOBN(0x91e3ed7e, 0x5f755caf), TOBN(0x49699f54, 0xd41e6f02),
++     TOBN(0x185770e1, 0xd4a7a15b), TOBN(0x08f3587a, 0xeaac87e7),
++     TOBN(0x352018db, 0x473133ea), TOBN(0x674ce719, 0x04fd30fc),
++     TOBN(0x7b8d9835, 0x088b3e0e), TOBN(0x7a0356a9, 0x5d0d47a1),
++     TOBN(0x9d9e7659, 0x6474a3c4), TOBN(0x61ea48a7, 0xff66966c),
++     TOBN(0x30417758, 0x0f3e4834), TOBN(0xfdbb21c2, 0x17a9afcb),
++     TOBN(0x756fa17f, 0x2f9a67b3), TOBN(0x2a6b2421, 0xa245c1a8),
++     TOBN(0x64be2794, 0x4af02291), TOBN(0xade465c6, 0x2a5804fe),
++     TOBN(0x8dffbd39, 0xa6f08fd7), TOBN(0xc4efa84c, 0xaa14403b),
++     TOBN(0xa1b91b2a, 0x442b0f5c), TOBN(0xb748e317, 0xcf997736),
++     TOBN(0x8d1b62bf, 0xcee90e16), TOBN(0x907ae271, 0x0b2078c0),
++     TOBN(0xdf31534b, 0x0c9bcddd), TOBN(0x043fb054, 0x39adce83),
++     TOBN(0x99031043, 0xd826846a), TOBN(0x61a9c0d6, 0xb144f393),
++     TOBN(0xdab48046, 0x47718427), TOBN(0xdf17ff9b, 0x6e830f8b),
++     TOBN(0x408d7ee8, 0xe49a1347), TOBN(0x6ac71e23, 0x91c1d4ae),
++     TOBN(0xc8cbb9fd, 0x1defd73c), TOBN(0x19840657, 0xbbbbfec5),
++     TOBN(0x39db1cb5, 0x9e7ef8ea), TOBN(0x78aa8296, 0x64105f30),
++     TOBN(0xa3d9b7f0, 0xa3738c29), TOBN(0x0a2f235a, 0xbc3250a3),
++     TOBN(0x55e506f6, 0x445e4caf), TOBN(0x0974f73d, 0x33475f7a),
++     TOBN(0xd37dbba3, 0x5ba2f5a8), TOBN(0x542c6e63, 0x6af40066),
++     TOBN(0x26d99b53, 0xc5d73e2c), TOBN(0x06060d7d, 0x6c3ca33e),
++     TOBN(0xcdbef1c2, 0x065fef4a), TOBN(0x77e60f7d, 0xfd5b92e3),
++     TOBN(0xd7c549f0, 0x26708350), TOBN(0x201b3ad0, 0x34f121bf),
++     TOBN(0x5fcac2a1, 0x0334fc14), TOBN(0x8a9a9e09, 0x344552f6),
++     TOBN(0x7dd8a1d3, 0x97653082), TOBN(0x5fc0738f, 0x79d4f289),
++     TOBN(0x787d244d, 0x17d2d8c3), TOBN(0xeffc6345, 0x70830684),
++     TOBN(0x5ddb96dd, 0xe4f73ae5), TOBN(0x8efb14b1, 0x172549a5),
++     TOBN(0x6eb73eee, 0x2245ae7a), TOBN(0xbca4061e, 0xea11f13e),
++     TOBN(0xb577421d, 0x30b01f5d), TOBN(0xaa688b24, 0x782e152c),
++     TOBN(0x67608e71, 0xbd3502ba), TOBN(0x4ef41f24, 0xb4de75a0),
++     TOBN(0xb08dde5e, 0xfd6125e5), TOBN(0xde484825, 0xa409543f),
++     TOBN(0x1f198d98, 0x65cc2295), TOBN(0x428a3771, 0x6e0edfa2),
++     TOBN(0x4f9697a2, 0xadf35fc7), TOBN(0x01a43c79, 0xf7cac3c7),
++     TOBN(0xb05d7059, 0x0fd3659a), TOBN(0x8927f30c, 0xbb7f2d9a),
++     TOBN(0x4023d1ac, 0x8cf984d3), TOBN(0x32125ed3, 0x02897a45),
++     TOBN(0xfb572dad, 0x3d414205), TOBN(0x73000ef2, 0xe3fa82a9),
++     TOBN(0x4c0868e9, 0xf10a5581), TOBN(0x5b61fc67, 0x6b0b3ca5),
++     TOBN(0xc1258d5b, 0x7cae440c), TOBN(0x21c08b41, 0x402b7531),
++     TOBN(0xf61a8955, 0xde932321), TOBN(0x3568faf8, 0x2d1408af),
++     TOBN(0x71b15e99, 0x9ecf965b), TOBN(0xf14ed248, 0xe917276f),
++     TOBN(0xc6f4caa1, 0x820cf9e2), TOBN(0x681b20b2, 0x18d83c7e),
++     TOBN(0x6cde738d, 0xc6c01120), TOBN(0x71db0813, 0xae70e0db),
++     TOBN(0x95fc0644, 0x74afe18c), TOBN(0x34619053, 0x129e2be7),
++     TOBN(0x80615cea, 0xdb2a3b15), TOBN(0x0a49a19e, 0xdb4c7073),
++     TOBN(0x0e1b84c8, 0x8fd2d367), TOBN(0xd74bf462, 0x033fb8aa),
++     TOBN(0x889f6d65, 0x533ef217), TOBN(0x7158c7e4, 0xc3ca2e87),
++     TOBN(0xfb670dfb, 0xdc2b4167), TOBN(0x75910a01, 0x844c257f),
++     TOBN(0xf336bf07, 0xcf88577d), TOBN(0x22245250, 0xe45e2ace),
++     TOBN(0x2ed92e8d, 0x7ca23d85), TOBN(0x29f8be4c, 0x2b812f58),
++     TOBN(0xdd9ebaa7, 0x076fe12b), TOBN(0x3f2400cb, 0xae1537f9),
++     TOBN(0x1aa93528, 0x17bdfb46), TOBN(0xc0f98430, 0x67883b41),
++     TOBN(0x5590ede1, 0x0170911d), TOBN(0x7562f5bb, 0x34d4b17f),
++     TOBN(0xe1fa1df2, 0x1826b8d2), TOBN(0xb40b796a, 0x6bd80d59),
++     TOBN(0xd65bf197, 0x3467ba92), TOBN(0x8c9b46db, 0xf70954b0),
++     TOBN(0x97c8a0f3, 0x0e78f15d), TOBN(0xa8f3a69a, 0x85a4c961),
++     TOBN(0x4242660f, 0x61e4ce9b), TOBN(0xbf06aab3, 0x6ea6790c),
++     TOBN(0xc6706f8e, 0xec986416), TOBN(0x9e56dec1, 0x9a9fc225),
++     TOBN(0x527c46f4, 0x9a9898d9), TOBN(0xd799e77b, 0x5633cdef),
++     TOBN(0x24eacc16, 0x7d9e4297), TOBN(0xabb61cea, 0x6b1cb734),
++     TOBN(0xbee2e8a7, 0xf778443c), TOBN(0x3bb42bf1, 0x29de2fe6),
++     TOBN(0xcbed86a1, 0x3003bb6f), TOBN(0xd3918e6c, 0xd781cdf6),
++     TOBN(0x4bee3271, 0x9a5103f1), TOBN(0x5243efc6, 0xf50eac06),
++     TOBN(0xb8e122cb, 0x6adcc119), TOBN(0x1b7faa84, 0xc0b80a08),
++     TOBN(0x32c3d1bd, 0x6dfcd08c), TOBN(0x129dec4e, 0x0be427de),
++     TOBN(0x98ab679c, 0x1d263c83), TOBN(0xafc83cb7, 0xcef64eff),
++     TOBN(0x85eb6088, 0x2fa6be76), TOBN(0x892585fb, 0x1328cbfe),
++     TOBN(0xc154d3ed, 0xcf618dda), TOBN(0xc44f601b, 0x3abaf26e),
++     TOBN(0x7bf57d0b, 0x2be1fdfd), TOBN(0xa833bd2d, 0x21137fee),
++     TOBN(0x9353af36, 0x2db591a8), TOBN(0xc76f26dc, 0x5562a056),
++     TOBN(0x1d87e47d, 0x3fdf5a51), TOBN(0x7afb5f93, 0x55c9cab0),
++     TOBN(0x91bbf58f, 0x89e0586e), TOBN(0x7c72c018, 0x0d843709),
++     TOBN(0xa9a5aafb, 0x99b5c3dc), TOBN(0xa48a0f1d, 0x3844aeb0),
++     TOBN(0x7178b7dd, 0xb667e482), TOBN(0x453985e9, 0x6e23a59a),
++     TOBN(0x4a54c860, 0x01b25dd8), TOBN(0x0dd37f48, 0xfb897c8a),
++     TOBN(0x5f8aa610, 0x0ea90cd9), TOBN(0xc8892c68, 0x16d5830d),
++     TOBN(0xeb4befc0, 0xef514ca5), TOBN(0x478eb679, 0xe72c9ee6),
++     TOBN(0x9bca20da, 0xdbc40d5f), TOBN(0xf015de21, 0xdde4f64a),
++     TOBN(0xaa6a4de0, 0xeaf4b8a5), TOBN(0x68cfd9ca, 0x4bc60e32),
++     TOBN(0x668a4b01, 0x7fd15e70), TOBN(0xd9f0694a, 0xf27dc09d),
++     TOBN(0xf6c3cad5, 0xba708bcd), TOBN(0x5cd2ba69, 0x5bb95c2a),
++     TOBN(0xaa28c1d3, 0x33c0a58f), TOBN(0x23e274e3, 0xabc77870),
++     TOBN(0x44c3692d, 0xdfd20a4a), TOBN(0x091c5fd3, 0x81a66653),
++     TOBN(0x6c0bb691, 0x09a0757d), TOBN(0x9072e8b9, 0x667343ea),
++     TOBN(0x31d40eb0, 0x80848bec), TOBN(0x95bd480a, 0x79fd36cc),
++     TOBN(0x01a77c61, 0x65ed43f5), TOBN(0xafccd127, 0x2e0d40bf),
++     TOBN(0xeccfc82d, 0x1cc1884b), TOBN(0xc85ac201, 0x5d4753b4),
++     TOBN(0xc7a6caac, 0x658e099f), TOBN(0xcf46369e, 0x04b27390),
++     TOBN(0xe2e7d049, 0x506467ea), TOBN(0x481b63a2, 0x37cdeccc),
++     TOBN(0x4029abd8, 0xed80143a), TOBN(0x28bfe3c7, 0xbcb00b88),
++     TOBN(0x3bec1009, 0x0643d84a), TOBN(0x885f3668, 0xabd11041),
++     TOBN(0xdb02432c, 0xf83a34d6), TOBN(0x32f7b360, 0x719ceebe),
++     TOBN(0xf06c7837, 0xdad1fe7a), TOBN(0x60a157a9, 0x5441a0b0),
++     TOBN(0x704970e9, 0xe2d47550), TOBN(0xcd2bd553, 0x271b9020),
++     TOBN(0xff57f82f, 0x33e24a0b), TOBN(0x9cbee23f, 0xf2565079),
++     TOBN(0x16353427, 0xeb5f5825), TOBN(0x276feec4, 0xe948d662),
++     TOBN(0xd1b62bc6, 0xda10032b), TOBN(0x718351dd, 0xf0e72a53),
++     TOBN(0x93452076, 0x2420e7ba), TOBN(0x96368fff, 0x3a00118d),
++     TOBN(0x00ce2d26, 0x150a49e4), TOBN(0x0c28b636, 0x3f04706b),
++     TOBN(0xbad65a46, 0x58b196d0), TOBN(0x6c8455fc, 0xec9f8b7c),
++     TOBN(0xe90c895f, 0x2d71867e), TOBN(0x5c0be31b, 0xedf9f38c),
++     TOBN(0x2a37a15e, 0xd8f6ec04), TOBN(0x239639e7, 0x8cd85251),
++     TOBN(0xd8975315, 0x9c7c4c6b), TOBN(0x603aa3c0, 0xd7409af7),
++     TOBN(0xb8d53d0c, 0x007132fb), TOBN(0x68d12af7, 0xa6849238),
++     TOBN(0xbe0607e7, 0xbf5d9279), TOBN(0x9aa50055, 0xaada74ce),
++     TOBN(0xe81079cb, 0xba7e8ccb), TOBN(0x610c71d1, 0xa5f4ff5e),
++     TOBN(0x9e2ee1a7, 0x5aa07093), TOBN(0xca84004b, 0xa75da47c),
++     TOBN(0x074d3951, 0x3de75401), TOBN(0xf938f756, 0xbb311592),
++     TOBN(0x96197618, 0x00a43421), TOBN(0x39a25362, 0x07bc78c8),
++     TOBN(0x278f710a, 0x0a171276), TOBN(0xb28446ea, 0x8d1a8f08),
++     TOBN(0x184781bf, 0xe3b6a661), TOBN(0x7751cb1d, 0xe6d279f7),
++     TOBN(0xf8ff95d6, 0xc59eb662), TOBN(0x186d90b7, 0x58d3dea7),
++     TOBN(0x0e4bb6c1, 0xdfb4f754), TOBN(0x5c5cf56b, 0x2b2801dc),
++     TOBN(0xc561e452, 0x1f54564d), TOBN(0xb4fb8c60, 0xf0dd7f13),
++     TOBN(0xf8849630, 0x33ff98c7), TOBN(0x9619fffa, 0xcf17769c),
++     TOBN(0xf8090bf6, 0x1bfdd80a), TOBN(0x14d9a149, 0x422cfe63),
++     TOBN(0xb354c360, 0x6f6df9ea), TOBN(0xdbcf770d, 0x218f17ea),
++     TOBN(0x207db7c8, 0x79eb3480), TOBN(0x213dbda8, 0x559b6a26),
++     TOBN(0xac4c200b, 0x29fc81b3), TOBN(0xebc3e09f, 0x171d87c1),
++     TOBN(0x91799530, 0x1481aa9e), TOBN(0x051b92e1, 0x92e114fa),
++     TOBN(0xdf8f92e9, 0xecb5537f), TOBN(0x44b1b2cc, 0x290c7483),
++     TOBN(0xa711455a, 0x2adeb016), TOBN(0x964b6856, 0x81a10c2c),
++     TOBN(0x4f159d99, 0xcec03623), TOBN(0x05532225, 0xef3271ea),
++     TOBN(0xb231bea3, 0xc5ee4849), TOBN(0x57a54f50, 0x7094f103),
++     TOBN(0x3e2d421d, 0x9598b352), TOBN(0xe865a49c, 0x67412ab4),
++     TOBN(0xd2998a25, 0x1cc3a912), TOBN(0x5d092808, 0x0c74d65d),
++     TOBN(0x73f45908, 0x4088567a), TOBN(0xeb6b280e, 0x1f214a61),
++     TOBN(0x8c9adc34, 0xcaf0c13d), TOBN(0x39d12938, 0xf561fb80),
++     TOBN(0xb2dc3a5e, 0xbc6edfb4), TOBN(0x7485b1b1, 0xfe4d210e),
++     TOBN(0x062e0400, 0xe186ae72), TOBN(0x91e32d5c, 0x6eeb3b88),
++     TOBN(0x6df574d7, 0x4be59224), TOBN(0xebc88ccc, 0x716d55f3),
++     TOBN(0x26c2e6d0, 0xcad6ed33), TOBN(0xc6e21e7d, 0x0d3e8b10),
++     TOBN(0x2cc5840e, 0x5bcc36bb), TOBN(0x9292445e, 0x7da74f69),
++     TOBN(0x8be8d321, 0x4e5193a8), TOBN(0x3ec23629, 0x8df06413),
++     TOBN(0xc7e9ae85, 0xb134defa), TOBN(0x6073b1d0, 0x1bb2d475),
++     TOBN(0xb9ad615e, 0x2863c00d), TOBN(0x9e29493d, 0x525f4ac4),
++     TOBN(0xc32b1dea, 0x4e9acf4f), TOBN(0x3e1f01c8, 0xa50db88d),
++     TOBN(0xb05d70ea, 0x04da916c), TOBN(0x714b0d0a, 0xd865803e),
++     TOBN(0x4bd493fc, 0x9920cb5e), TOBN(0x5b44b1f7, 0x92c7a3ac),
++     TOBN(0xa2a77293, 0xbcec9235), TOBN(0x5ee06e87, 0xcd378553),
++     TOBN(0xceff8173, 0xda621607), TOBN(0x2bb03e4c, 0x99f5d290),
++     TOBN(0x2945106a, 0xa6f734ac), TOBN(0xb5056604, 0xd25c4732),
++     TOBN(0x5945920c, 0xe079afee), TOBN(0x686e17a0, 0x6789831f),
++     TOBN(0x5966bee8, 0xb74a5ae5), TOBN(0x38a673a2, 0x1e258d46),
++     TOBN(0xbd1cc1f2, 0x83141c95), TOBN(0x3b2ecf4f, 0x0e96e486),
++     TOBN(0xcd3aa896, 0x74e5fc78), TOBN(0x415ec10c, 0x2482fa7a),
++     TOBN(0x15234419, 0x80503380), TOBN(0x513d917a, 0xd314b392),
++     TOBN(0xb0b52f4e, 0x63caecae), TOBN(0x07bf22ad, 0x2dc7780b),
++     TOBN(0xe761e8a1, 0xe4306839), TOBN(0x1b3be962, 0x5dd7feaa),
++     TOBN(0x4fe728de, 0x74c778f1), TOBN(0xf1fa0bda, 0x5e0070f6),
++     TOBN(0x85205a31, 0x6ec3f510), TOBN(0x2c7e4a14, 0xd2980475),
++     TOBN(0xde3c19c0, 0x6f30ebfd), TOBN(0xdb1c1f38, 0xd4b7e644),
++     TOBN(0xfe291a75, 0x5dce364a), TOBN(0xb7b22a3c, 0x058f5be3),
++     TOBN(0x2cd2c302, 0x37fea38c), TOBN(0x2930967a, 0x2e17be17),
++     TOBN(0x87f009de, 0x0c061c65), TOBN(0xcb014aac, 0xedc6ed44),
++     TOBN(0x49bd1cb4, 0x3bafb1eb), TOBN(0x81bd8b5c, 0x282d3688),
++     TOBN(0x1cdab87e, 0xf01a17af), TOBN(0x21f37ac4, 0xe710063b),
++     TOBN(0x5a6c5676, 0x42fc8193), TOBN(0xf4753e70, 0x56a6015c),
++     TOBN(0x020f795e, 0xa15b0a44), TOBN(0x8f37c8d7, 0x8958a958),
++     TOBN(0x63b7e89b, 0xa4b675b5), TOBN(0xb4fb0c0c, 0x0fc31aea),
++     TOBN(0xed95e639, 0xa7ff1f2e), TOBN(0x9880f5a3, 0x619614fb),
++     TOBN(0xdeb6ff02, 0x947151ab), TOBN(0x5bc5118c, 0xa868dcdb),
++     TOBN(0xd8da2055, 0x4c20cea5), TOBN(0xcac2776e, 0x14c4d69a),
++     TOBN(0xcccb22c1, 0x622d599b), TOBN(0xa4ddb653, 0x68a9bb50),
++     TOBN(0x2c4ff151, 0x1b4941b4), TOBN(0xe1ff19b4, 0x6efba588),
++     TOBN(0x35034363, 0xc48345e0), TOBN(0x45542e3d, 0x1e29dfc4),
++     TOBN(0xf197cb91, 0x349f7aed), TOBN(0x3b2b5a00, 0x8fca8420),
++     TOBN(0x7c175ee8, 0x23aaf6d8), TOBN(0x54dcf421, 0x35af32b6),
++     TOBN(0x0ba14307, 0x27d6561e), TOBN(0x879d5ee4, 0xd175b1e2),
++     TOBN(0xc7c43673, 0x99807db5), TOBN(0x77a54455, 0x9cd55bcd),
++     TOBN(0xe6c2ff13, 0x0105c072), TOBN(0x18f7a99f, 0x8dda7da4),
++     TOBN(0x4c301820, 0x0e2d35c1), TOBN(0x06a53ca0, 0xd9cc6c82),
++     TOBN(0xaa21cc1e, 0xf1aa1d9e), TOBN(0x32414334, 0x4a75b1e8),
++     TOBN(0x2a6d1328, 0x0ebe9fdc), TOBN(0x16bd173f, 0x98a4755a),
++     TOBN(0xfbb9b245, 0x2133ffd9), TOBN(0x39a8b2f1, 0x830f1a20),
++     TOBN(0x484bc97d, 0xd5a1f52a), TOBN(0xd6aebf56, 0xa40eddf8),
++     TOBN(0x32257acb, 0x76ccdac6), TOBN(0xaf4d36ec, 0x1586ff27),
++     TOBN(0x8eaa8863, 0xf8de7dd1), TOBN(0x0045d5cf, 0x88647c16)}
++    ,
++    {TOBN(0xa6f3d574, 0xc005979d), TOBN(0xc2072b42, 0x6a40e350),
++     TOBN(0xfca5c156, 0x8de2ecf9), TOBN(0xa8c8bf5b, 0xa515344e),
++     TOBN(0x97aee555, 0x114df14a), TOBN(0xd4374a4d, 0xfdc5ec6b),
++     TOBN(0x754cc28f, 0x2ca85418), TOBN(0x71cb9e27, 0xd3c41f78),
++     TOBN(0x89105079, 0x03605c39), TOBN(0xf0843d9e, 0xa142c96c),
++     TOBN(0xf3744934, 0x16923684), TOBN(0x732caa2f, 0xfa0a2893),
++     TOBN(0xb2e8c270, 0x61160170), TOBN(0xc32788cc, 0x437fbaa3),
++     TOBN(0x39cd818e, 0xa6eda3ac), TOBN(0xe2e94239, 0x9e2b2e07),
++     TOBN(0x6967d39b, 0x0260e52a), TOBN(0xd42585cc, 0x90653325),
++     TOBN(0x0d9bd605, 0x21ca7954), TOBN(0x4fa20877, 0x81ed57b3),
++     TOBN(0x60c1eff8, 0xe34a0bbe), TOBN(0x56b0040c, 0x84f6ef64),
++     TOBN(0x28be2b24, 0xb1af8483), TOBN(0xb2278163, 0xf5531614),
++     TOBN(0x8df27545, 0x5922ac1c), TOBN(0xa7b3ef5c, 0xa52b3f63),
++     TOBN(0x8e77b214, 0x71de57c4), TOBN(0x31682c10, 0x834c008b),
++     TOBN(0xc76824f0, 0x4bd55d31), TOBN(0xb6d1c086, 0x17b61c71),
++     TOBN(0x31db0903, 0xc2a5089d), TOBN(0x9c092172, 0x184e5d3f),
++     TOBN(0xdd7ced5b, 0xc00cc638), TOBN(0x1a2015eb, 0x61278fc2),
++     TOBN(0x2e8e5288, 0x6a37f8d6), TOBN(0xc457786f, 0xe79933ad),
++     TOBN(0xb3fe4cce, 0x2c51211a), TOBN(0xad9b10b2, 0x24c20498),
++     TOBN(0x90d87a4f, 0xd28db5e5), TOBN(0x698cd105, 0x3aca2fc3),
++     TOBN(0x4f112d07, 0xe91b536d), TOBN(0xceb982f2, 0x9eba09d6),
++     TOBN(0x3c157b2c, 0x197c396f), TOBN(0xe23c2d41, 0x7b66eb24),
++     TOBN(0x480c57d9, 0x3f330d37), TOBN(0xb3a4c8a1, 0x79108deb),
++     TOBN(0x702388de, 0xcb199ce5), TOBN(0x0b019211, 0xb944a8d4),
++     TOBN(0x24f2a692, 0x840bb336), TOBN(0x7c353bdc, 0xa669fa7b),
++     TOBN(0xda20d6fc, 0xdec9c300), TOBN(0x625fbe2f, 0xa13a4f17),
++     TOBN(0xa2b1b61a, 0xdbc17328), TOBN(0x008965bf, 0xa9515621),
++     TOBN(0x49690939, 0xc620ff46), TOBN(0x182dd27d, 0x8717e91c),
++     TOBN(0x5ace5035, 0xea6c3997), TOBN(0x54259aaa, 0xc2610bef),
++     TOBN(0xef18bb3f, 0x3c80dd39), TOBN(0x6910b95b, 0x5fc3fa39),
++     TOBN(0xfce2f510, 0x43e09aee), TOBN(0xced56c9f, 0xa7675665),
++     TOBN(0x10e265ac, 0xd872db61), TOBN(0x6982812e, 0xae9fce69),
++     TOBN(0x29be11c6, 0xce800998), TOBN(0x72bb1752, 0xb90360d9),
++     TOBN(0x2c193197, 0x5a4ad590), TOBN(0x2ba2f548, 0x9fc1dbc0),
++     TOBN(0x7fe4eebb, 0xe490ebe0), TOBN(0x12a0a4cd, 0x7fae11c0),
++     TOBN(0x7197cf81, 0xe903ba37), TOBN(0xcf7d4aa8, 0xde1c6dd8),
++     TOBN(0x92af6bf4, 0x3fd5684c), TOBN(0x2b26eecf, 0x80360aa1),
++     TOBN(0xbd960f30, 0x00546a82), TOBN(0x407b3c43, 0xf59ad8fe),
++     TOBN(0x86cae5fe, 0x249c82ba), TOBN(0x9e0faec7, 0x2463744c),
++     TOBN(0x87f551e8, 0x94916272), TOBN(0x033f9344, 0x6ceb0615),
++     TOBN(0x1e5eb0d1, 0x8be82e84), TOBN(0x89967f0e, 0x7a582fef),
++     TOBN(0xbcf687d5, 0xa6e921fa), TOBN(0xdfee4cf3, 0xd37a09ba),
++     TOBN(0x94f06965, 0xb493c465), TOBN(0x638b9a1c, 0x7635c030),
++     TOBN(0x76667864, 0x66f05e9f), TOBN(0xccaf6808, 0xc04da725),
++     TOBN(0xca2eb690, 0x768fccfc), TOBN(0xf402d37d, 0xb835b362),
++     TOBN(0x0efac0d0, 0xe2fdfcce), TOBN(0xefc9cdef, 0xb638d990),
++     TOBN(0x2af12b72, 0xd1669a8b), TOBN(0x33c536bc, 0x5774ccbd),
++     TOBN(0x30b21909, 0xfb34870e), TOBN(0xc38fa2f7, 0x7df25aca),
++     TOBN(0x74c5f02b, 0xbf81f3f5), TOBN(0x0525a5ae, 0xaf7e4581),
++     TOBN(0x88d2aaba, 0x433c54ae), TOBN(0xed9775db, 0x806a56c5),
++     TOBN(0xd320738a, 0xc0edb37d), TOBN(0x25fdb6ee, 0x66cc1f51),
++     TOBN(0xac661d17, 0x10600d76), TOBN(0x931ec1f3, 0xbdd1ed76),
++     TOBN(0x65c11d62, 0x19ee43f1), TOBN(0x5cd57c3e, 0x60829d97),
++     TOBN(0xd26c91a3, 0x984be6e8), TOBN(0xf08d9309, 0x8b0c53bd),
++     TOBN(0x94bc9e5b, 0xc016e4ea), TOBN(0xd3916839, 0x11d43d2b),
++     TOBN(0x886c5ad7, 0x73701155), TOBN(0xe0377626, 0x20b00715),
++     TOBN(0x7f01c9ec, 0xaa80ba59), TOBN(0x3083411a, 0x68538e51),
++     TOBN(0x970370f1, 0xe88128af), TOBN(0x625cc3db, 0x91dec14b),
++     TOBN(0xfef9666c, 0x01ac3107), TOBN(0xb2a8d577, 0xd5057ac3),
++     TOBN(0xb0f26299, 0x92be5df7), TOBN(0xf579c8e5, 0x00353924),
++     TOBN(0xb8fa3d93, 0x1341ed7a), TOBN(0x4223272c, 0xa7b59d49),
++     TOBN(0x3dcb1947, 0x83b8c4a4), TOBN(0x4e413c01, 0xed1302e4),
++     TOBN(0x6d999127, 0xe17e44ce), TOBN(0xee86bf75, 0x33b3adfb),
++     TOBN(0xf6902fe6, 0x25aa96ca), TOBN(0xb73540e4, 0xe5aae47d),
++     TOBN(0x32801d7b, 0x1b4a158c), TOBN(0xe571c99e, 0x27e2a369),
++     TOBN(0x40cb76c0, 0x10d9f197), TOBN(0xc308c289, 0x3167c0ae),
++     TOBN(0xa6ef9dd3, 0xeb7958f2), TOBN(0xa7226dfc, 0x300879b1),
++     TOBN(0x6cd0b362, 0x7edf0636), TOBN(0x4efbce6c, 0x7bc37eed),
++     TOBN(0x75f92a05, 0x8d699021), TOBN(0x586d4c79, 0x772566e3),
++     TOBN(0x378ca5f1, 0x761ad23a), TOBN(0x650d86fc, 0x1465a8ac),
++     TOBN(0x7a4ed457, 0x842ba251), TOBN(0x6b65e3e6, 0x42234933),
++     TOBN(0xaf1543b7, 0x31aad657), TOBN(0xa4cefe98, 0xcbfec369),
++     TOBN(0xb587da90, 0x9f47befb), TOBN(0x6562e9fb, 0x41312d13),
++     TOBN(0xa691ea59, 0xeff1cefe), TOBN(0xcc30477a, 0x05fc4cf6),
++     TOBN(0xa1632461, 0x0b0ffd3d), TOBN(0xa1f16f3b, 0x5b355956),
++     TOBN(0x5b148d53, 0x4224ec24), TOBN(0xdc834e7b, 0xf977012a),
++     TOBN(0x7bfc5e75, 0xb2c69dbc), TOBN(0x3aa77a29, 0x03c3da6c),
++     TOBN(0xde0df03c, 0xca910271), TOBN(0xcbd5ca4a, 0x7806dc55),
++     TOBN(0xe1ca5807, 0x6db476cb), TOBN(0xfde15d62, 0x5f37a31e),
++     TOBN(0xf49af520, 0xf41af416), TOBN(0x96c5c5b1, 0x7d342db5),
++     TOBN(0x155c43b7, 0xeb4ceb9b), TOBN(0x2e993010, 0x4e77371a),
++     TOBN(0x1d2987da, 0x675d43af), TOBN(0xef2bc1c0, 0x8599fd72),
++     TOBN(0x96894b7b, 0x9342f6b2), TOBN(0x201eadf2, 0x7c8e71f0),
++     TOBN(0xf3479d9f, 0x4a1f3efc), TOBN(0xe0f8a742, 0x702a9704),
++     TOBN(0xeafd44b6, 0xb3eba40c), TOBN(0xf9739f29, 0xc1c1e0d0),
++     TOBN(0x0091471a, 0x619d505e), TOBN(0xc15f9c96, 0x9d7c263e),
++     TOBN(0x5be47285, 0x83afbe33), TOBN(0xa3b6d6af, 0x04f1e092),
++     TOBN(0xe76526b9, 0x751a9d11), TOBN(0x2ec5b26d, 0x9a4ae4d2),
++     TOBN(0xeb66f4d9, 0x02f6fb8d), TOBN(0x4063c561, 0x96912164),
++     TOBN(0xeb7050c1, 0x80ef3000), TOBN(0x288d1c33, 0xeaa5b3f0),
++     TOBN(0xe87c68d6, 0x07806fd8), TOBN(0xb2f7f9d5, 0x4bbbf50f),
++     TOBN(0x25972f3a, 0xac8d6627), TOBN(0xf8547774, 0x10e8c13b),
++     TOBN(0xcc50ef6c, 0x872b4a60), TOBN(0xab2a34a4, 0x4613521b),
++     TOBN(0x39c5c190, 0x983e15d1), TOBN(0x61dde5df, 0x59905512),
++     TOBN(0xe417f621, 0x9f2275f3), TOBN(0x0750c8b6, 0x451d894b),
++     TOBN(0x75b04ab9, 0x78b0bdaa), TOBN(0x3bfd9fd4, 0x458589bd),
++     TOBN(0xf1013e30, 0xee9120b6), TOBN(0x2b51af93, 0x23a4743e),
++     TOBN(0xea96ffae, 0x48d14d9e), TOBN(0x71dc0dbe, 0x698a1d32),
++     TOBN(0x914962d2, 0x0180cca4), TOBN(0x1ae60677, 0xc3568963),
++     TOBN(0x8cf227b1, 0x437bc444), TOBN(0xc650c83b, 0xc9962c7a),
++     TOBN(0x23c2c7dd, 0xfe7ccfc4), TOBN(0xf925c89d, 0x1b929d48),
++     TOBN(0x4460f74b, 0x06783c33), TOBN(0xac2c8d49, 0xa590475a),
++     TOBN(0xfb40b407, 0xb807bba0), TOBN(0x9d1e362d, 0x69ff8f3a),
++     TOBN(0xa33e9681, 0xcbef64a4), TOBN(0x67ece5fa, 0x332fb4b2),
++     TOBN(0x6900a99b, 0x739f10e3), TOBN(0xc3341ca9, 0xff525925),
++     TOBN(0xee18a626, 0xa9e2d041), TOBN(0xa5a83685, 0x29580ddd),
++     TOBN(0xf3470c81, 0x9d7de3cd), TOBN(0xedf02586, 0x2062cf9c),
++     TOBN(0xf43522fa, 0xc010edb0), TOBN(0x30314135, 0x13a4b1ae),
++     TOBN(0xc792e02a, 0xdb22b94b), TOBN(0x993d8ae9, 0xa1eaa45b),
++     TOBN(0x8aad6cd3, 0xcd1e1c63), TOBN(0x89529ca7, 0xc5ce688a),
++     TOBN(0x2ccee3aa, 0xe572a253), TOBN(0xe02b6438, 0x02a21efb),
++     TOBN(0xa7091b6e, 0xc9430358), TOBN(0x06d1b1fa, 0x9d7db504),
++     TOBN(0x58846d32, 0xc4744733), TOBN(0x40517c71, 0x379f9e34),
++     TOBN(0x2f65655f, 0x130ef6ca), TOBN(0x526e4488, 0xf1f3503f),
++     TOBN(0x8467bd17, 0x7ee4a976), TOBN(0x1d9dc913, 0x921363d1),
++     TOBN(0xd8d24c33, 0xb069e041), TOBN(0x5eb5da0a, 0x2cdf7f51),
++     TOBN(0x1c0f3cb1, 0x197b994f), TOBN(0x3c95a6c5, 0x2843eae9),
++     TOBN(0x7766ffc9, 0xa6097ea5), TOBN(0x7bea4093, 0xd723b867),
++     TOBN(0xb48e1f73, 0x4db378f9), TOBN(0x70025b00, 0xe37b77ac),
++     TOBN(0x943dc8e7, 0xaf24ad46), TOBN(0xb98a15ac, 0x16d00a85),
++     TOBN(0x3adc38ba, 0x2743b004), TOBN(0xb1c7f4f7, 0x334415ee),
++     TOBN(0xea43df8f, 0x1e62d05a), TOBN(0x32618905, 0x9d76a3b6),
++     TOBN(0x2fbd0bb5, 0xa23a0f46), TOBN(0x5bc971db, 0x6a01918c),
++     TOBN(0x7801d94a, 0xb4743f94), TOBN(0xb94df65e, 0x676ae22b),
++     TOBN(0xaafcbfab, 0xaf95894c), TOBN(0x7b9bdc07, 0x276b2241),
++     TOBN(0xeaf98362, 0x5bdda48b), TOBN(0x5977faf2, 0xa3fcb4df),
++     TOBN(0xbed042ef, 0x052c4b5b), TOBN(0x9fe87f71, 0x067591f0),
++     TOBN(0xc89c73ca, 0x22f24ec7), TOBN(0x7d37fa9e, 0xe64a9f1b),
++     TOBN(0x2710841a, 0x15562627), TOBN(0x2c01a613, 0xc243b034),
++     TOBN(0x1d135c56, 0x2bc68609), TOBN(0xc2ca1715, 0x8b03f1f6),
++     TOBN(0xc9966c2d, 0x3eb81d82), TOBN(0xc02abf4a, 0x8f6df13e),
++     TOBN(0x77b34bd7, 0x8f72b43b), TOBN(0xaff6218f, 0x360c82b0),
++     TOBN(0x0aa5726c, 0x8d55b9d2), TOBN(0xdc0adbe9, 0x99e9bffb),
++     TOBN(0x9097549c, 0xefb9e72a), TOBN(0x16755712, 0x9dfb3111),
++     TOBN(0xdd8bf984, 0xf26847f9), TOBN(0xbcb8e387, 0xdfb30cb7),
++     TOBN(0xc1fd32a7, 0x5171ef9c), TOBN(0x977f3fc7, 0x389b363f),
++     TOBN(0x116eaf2b, 0xf4babda0), TOBN(0xfeab68bd, 0xf7113c8e),
++     TOBN(0xd1e3f064, 0xb7def526), TOBN(0x1ac30885, 0xe0b3fa02),
++     TOBN(0x1c5a6e7b, 0x40142d9d), TOBN(0x839b5603, 0x30921c0b),
++     TOBN(0x48f301fa, 0x36a116a3), TOBN(0x380e1107, 0xcfd9ee6d),
++     TOBN(0x7945ead8, 0x58854be1), TOBN(0x4111c12e, 0xcbd4d49d),
++     TOBN(0xece3b1ec, 0x3a29c2ef), TOBN(0x6356d404, 0x8d3616f5),
++     TOBN(0x9f0d6a8f, 0x594d320e), TOBN(0x0989316d, 0xf651ccd2),
++     TOBN(0x6c32117a, 0x0f8fdde4), TOBN(0x9abe5cc5, 0xa26a9bbc),
++     TOBN(0xcff560fb, 0x9723f671), TOBN(0x21b2a12d, 0x7f3d593c),
++     TOBN(0xe4cb18da, 0x24ba0696), TOBN(0x186e2220, 0xc3543384),
++     TOBN(0x722f64e0, 0x88312c29), TOBN(0x94282a99, 0x17dc7752),
++     TOBN(0x62467bbf, 0x5a85ee89), TOBN(0xf435c650, 0xf10076a0),
++     TOBN(0xc9ff1539, 0x43b3a50b), TOBN(0x7132130c, 0x1a53efbc),
++     TOBN(0x31bfe063, 0xf7b0c5b7), TOBN(0xb0179a7d, 0x4ea994cc),
++     TOBN(0x12d064b3, 0xc85f455b), TOBN(0x47259328, 0x8f6e0062),
++     TOBN(0xf64e590b, 0xb875d6d9), TOBN(0x22dd6225, 0xad92bcc7),
++     TOBN(0xb658038e, 0xb9c3bd6d), TOBN(0x00cdb0d6, 0xfbba27c8),
++     TOBN(0x0c681337, 0x1062c45d), TOBN(0xd8515b8c, 0x2d33407d),
++     TOBN(0xcb8f699e, 0x8cbb5ecf), TOBN(0x8c4347f8, 0xc608d7d8),
++     TOBN(0x2c11850a, 0xbb3e00db), TOBN(0x20a8dafd, 0xecb49d19),
++     TOBN(0xbd781480, 0x45ee2f40), TOBN(0x75e354af, 0x416b60cf),
++     TOBN(0xde0b58a1, 0x8d49a8c4), TOBN(0xe40e94e2, 0xfa359536),
++     TOBN(0xbd4fa59f, 0x62accd76), TOBN(0x05cf466a, 0x8c762837),
++     TOBN(0xb5abda99, 0x448c277b), TOBN(0x5a9e01bf, 0x48b13740),
++     TOBN(0x9d457798, 0x326aad8d), TOBN(0xbdef4954, 0xc396f7e7),
++     TOBN(0x6fb274a2, 0xc253e292), TOBN(0x2800bf0a, 0x1cfe53e7),
++     TOBN(0x22426d31, 0x44438fd4), TOBN(0xef233923, 0x5e259f9a),
++     TOBN(0x4188503c, 0x03f66264), TOBN(0x9e5e7f13, 0x7f9fdfab),
++     TOBN(0x565eb76c, 0x5fcc1aba), TOBN(0xea632548, 0x59b5bff8),
++     TOBN(0x5587c087, 0xaab6d3fa), TOBN(0x92b639ea, 0x6ce39c1b),
++     TOBN(0x0706e782, 0x953b135c), TOBN(0x7308912e, 0x425268ef),
++     TOBN(0x599e92c7, 0x090e7469), TOBN(0x83b90f52, 0x9bc35e75),
++     TOBN(0x4750b3d0, 0x244975b3), TOBN(0xf3a44358, 0x11965d72),
++     TOBN(0x179c6774, 0x9c8dc751), TOBN(0xff18cdfe, 0xd23d9ff0),
++     TOBN(0xc4013833, 0x2028e247), TOBN(0x96e280e2, 0xf3bfbc79),
++     TOBN(0xf60417bd, 0xd0880a84), TOBN(0x263c9f3d, 0x2a568151),
++     TOBN(0x36be15b3, 0x2d2ce811), TOBN(0x846dc0c2, 0xf8291d21),
++     TOBN(0x5cfa0ecb, 0x789fcfdb), TOBN(0x45a0beed, 0xd7535b9a),
++     TOBN(0xec8e9f07, 0x96d69af1), TOBN(0x31a7c5b8, 0x599ab6dc),
++     TOBN(0xd36d45ef, 0xf9e2e09f), TOBN(0x3cf49ef1, 0xdcee954b),
++     TOBN(0x6be34cf3, 0x086cff9b), TOBN(0x88dbd491, 0x39a3360f),
++     TOBN(0x1e96b8cc, 0x0dbfbd1d), TOBN(0xc1e5f7bf, 0xcb7e2552),
++     TOBN(0x0547b214, 0x28819d98), TOBN(0xc770dd9c, 0x7aea9dcb),
++     TOBN(0xaef0d4c7, 0x041d68c8), TOBN(0xcc2b9818, 0x13cb9ba8),
++     TOBN(0x7fc7bc76, 0xfe86c607), TOBN(0x6b7b9337, 0x502a9a95),
++     TOBN(0x1948dc27, 0xd14dab63), TOBN(0x249dd198, 0xdae047be),
++     TOBN(0xe8356584, 0xa981a202), TOBN(0x3531dd18, 0x3a893387),
++     TOBN(0x1be11f90, 0xc85c7209), TOBN(0x93d2fe1e, 0xe2a52b5a),
++     TOBN(0x8225bfe2, 0xec6d6b97), TOBN(0x9cf6d6f4, 0xbd0aa5de),
++     TOBN(0x911459cb, 0x54779f5f), TOBN(0x5649cddb, 0x86aeb1f3),
++     TOBN(0x32133579, 0x3f26ce5a), TOBN(0xc289a102, 0x550f431e),
++     TOBN(0x559dcfda, 0x73b84c6f), TOBN(0x84973819, 0xee3ac4d7),
++     TOBN(0xb51e55e6, 0xf2606a82), TOBN(0xe25f7061, 0x90f2fb57),
++     TOBN(0xacef6c2a, 0xb1a4e37c), TOBN(0x864e359d, 0x5dcf2706),
++     TOBN(0x479e6b18, 0x7ce57316), TOBN(0x2cab2500, 0x3a96b23d),
++     TOBN(0xed489862, 0x8ef16df7), TOBN(0x2056538c, 0xef3758b5),
++     TOBN(0xa7df865e, 0xf15d3101), TOBN(0x80c5533a, 0x61b553d7),
++     TOBN(0x366e1997, 0x4ed14294), TOBN(0x6620741f, 0xb3c0bcd6),
++     TOBN(0x21d1d9c4, 0xedc45418), TOBN(0x005b859e, 0xc1cc4a9d),
++     TOBN(0xdf01f630, 0xa1c462f0), TOBN(0x15d06cf3, 0xf26820c7),
++     TOBN(0x9f7f24ee, 0x3484be47), TOBN(0x2ff33e96, 0x4a0c902f),
++     TOBN(0x00bdf457, 0x5a0bc453), TOBN(0x2378dfaf, 0x1aa238db),
++     TOBN(0x272420ec, 0x856720f2), TOBN(0x2ad9d95b, 0x96797291),
++     TOBN(0xd1242cc6, 0x768a1558), TOBN(0x2e287f8b, 0x5cc86aa8),
++     TOBN(0x796873d0, 0x990cecaa), TOBN(0xade55f81, 0x675d4080),
++     TOBN(0x2645eea3, 0x21f0cd84), TOBN(0x7a1efa0f, 0xb4e17d02),
++     TOBN(0xf6858420, 0x037cc061), TOBN(0x682e05f0, 0xd5d43e12),
++     TOBN(0x59c36994, 0x27218710), TOBN(0x85cbba4d, 0x3f7cd2fc),
++     TOBN(0x726f9729, 0x7a3cd22a), TOBN(0x9f8cd5dc, 0x4a628397),
++     TOBN(0x17b93ab9, 0xc23165ed), TOBN(0xff5f5dbf, 0x122823d4),
++     TOBN(0xc1e4e4b5, 0x654a446d), TOBN(0xd1a9496f, 0x677257ba),
++     TOBN(0x6387ba94, 0xde766a56), TOBN(0x23608bc8, 0x521ec74a),
++     TOBN(0x16a522d7, 0x6688c4d4), TOBN(0x9d6b4282, 0x07373abd),
++     TOBN(0xa62f07ac, 0xb42efaa3), TOBN(0xf73e00f7, 0xe3b90180),
++     TOBN(0x36175fec, 0x49421c3e), TOBN(0xc4e44f9b, 0x3dcf2678),
++     TOBN(0x76df436b, 0x7220f09f), TOBN(0x172755fb, 0x3aa8b6cf),
++     TOBN(0xbab89d57, 0x446139cc), TOBN(0x0a0a6e02, 0x5fe0208f),
++     TOBN(0xcdbb63e2, 0x11e5d399), TOBN(0x33ecaa12, 0xa8977f0b),
++     TOBN(0x59598b21, 0xf7c42664), TOBN(0xb3e91b32, 0xab65d08a),
++     TOBN(0x035822ee, 0xf4502526), TOBN(0x1dcf0176, 0x720a82a9),
++     TOBN(0x50f8598f, 0x3d589e02), TOBN(0xdf0478ff, 0xb1d63d2c),
++     TOBN(0x8b8068bd, 0x1571cd07), TOBN(0x30c3aa4f, 0xd79670cd),
++     TOBN(0x25e8fd4b, 0x941ade7f), TOBN(0x3d1debdc, 0x32790011),
++     TOBN(0x65b6dcbd, 0x3a3f9ff0), TOBN(0x282736a4, 0x793de69c),
++     TOBN(0xef69a0c3, 0xd41d3bd3), TOBN(0xb533b8c9, 0x07a26bde),
++     TOBN(0xe2801d97, 0xdb2edf9f), TOBN(0xdc4a8269, 0xe1877af0),
++     TOBN(0x6c1c5851, 0x3d590dbe), TOBN(0x84632f6b, 0xee4e9357),
++     TOBN(0xd36d36b7, 0x79b33374), TOBN(0xb46833e3, 0x9bbca2e6),
++     TOBN(0x37893913, 0xf7fc0586), TOBN(0x385315f7, 0x66bf4719),
++     TOBN(0x72c56293, 0xb31855dc), TOBN(0xd1416d4e, 0x849061fe),
++     TOBN(0xbeb3ab78, 0x51047213), TOBN(0x447f6e61, 0xf040c996),
++     TOBN(0xd06d310d, 0x638b1d0c), TOBN(0xe28a413f, 0xbad1522e),
++     TOBN(0x685a76cb, 0x82003f86), TOBN(0x610d07f7, 0x0bcdbca3),
++     TOBN(0x6ff66021, 0x9ca4c455), TOBN(0x7df39b87, 0xcea10eec),
++     TOBN(0xb9255f96, 0xe22db218), TOBN(0x8cc6d9eb, 0x08a34c44),
++     TOBN(0xcd4ffb86, 0x859f9276), TOBN(0x8fa15eb2, 0x50d07335),
++     TOBN(0xdf553845, 0xcf2c24b5), TOBN(0x89f66a9f, 0x52f9c3ba),
++     TOBN(0x8f22b5b9, 0xe4a7ceb3), TOBN(0xaffef809, 0x0e134686),
++     TOBN(0x3e53e1c6, 0x8eb8fac2), TOBN(0x93c1e4eb, 0x28aec98e),
++     TOBN(0xb6b91ec5, 0x32a43bcb), TOBN(0x2dbfa947, 0xb2d74a51),
++     TOBN(0xe065d190, 0xca84bad7), TOBN(0xfb13919f, 0xad58e65c),
++     TOBN(0x3c41718b, 0xf1cb6e31), TOBN(0x688969f0, 0x06d05c3f),
++     TOBN(0xd4f94ce7, 0x21264d45), TOBN(0xfdfb65e9, 0x7367532b),
++     TOBN(0x5b1be8b1, 0x0945a39d), TOBN(0x229f789c, 0x2b8baf3b),
++     TOBN(0xd8f41f3e, 0x6f49f15d), TOBN(0x678ce828, 0x907f0792),
++     TOBN(0xc69ace82, 0xfca6e867), TOBN(0x106451ae, 0xd01dcc89),
++     TOBN(0x1bb4f7f0, 0x19fc32d2), TOBN(0x64633dfc, 0xb00c52d2),
++     TOBN(0x8f13549a, 0xad9ea445), TOBN(0x99a3bf50, 0xfb323705),
++     TOBN(0x0c9625a2, 0x534d4dbc), TOBN(0x45b8f1d1, 0xc2a2fea3),
++     TOBN(0x76ec21a1, 0xa530fc1a), TOBN(0x4bac9c2a, 0x9e5bd734),
++     TOBN(0x5996d76a, 0x7b4e3587), TOBN(0x0045cdee, 0x1182d9e3),
++     TOBN(0x1aee24b9, 0x1207f13d), TOBN(0x66452e97, 0x97345a41),
++     TOBN(0x16e5b054, 0x9f950cd0), TOBN(0x9cc72fb1, 0xd7fdd075),
++     TOBN(0x6edd61e7, 0x66249663), TOBN(0xde4caa4d, 0xf043cccb),
++     TOBN(0x11b1f57a, 0x55c7ac17), TOBN(0x779cbd44, 0x1a85e24d),
++     TOBN(0x78030f86, 0xe46081e7), TOBN(0xfd4a6032, 0x8e20f643),
++     TOBN(0xcc7a6488, 0x0a750c0f), TOBN(0x39bacfe3, 0x4e548e83),
++     TOBN(0x3d418c76, 0x0c110f05), TOBN(0x3e4daa4c, 0xb1f11588),
++     TOBN(0x2733e7b5, 0x5ffc69ff), TOBN(0x46f147bc, 0x92053127),
++     TOBN(0x885b2434, 0xd722df94), TOBN(0x6a444f65, 0xe6fc6b7c)}
++    ,
++    {TOBN(0x7a1a465a, 0xc3f16ea8), TOBN(0x115a461d, 0xb2f1d11c),
++     TOBN(0x4767dd95, 0x6c68a172), TOBN(0x3392f2eb, 0xd13a4698),
++     TOBN(0xc7a99ccd, 0xe526cdc7), TOBN(0x8e537fdc, 0x22292b81),
++     TOBN(0x76d8cf69, 0xa6d39198), TOBN(0xffc5ff43, 0x2446852d),
++     TOBN(0x97b14f7e, 0xa90567e6), TOBN(0x513257b7, 0xb6ae5cb7),
++     TOBN(0x85454a3c, 0x9f10903d), TOBN(0xd8d2c9ad, 0x69bc3724),
++     TOBN(0x38da9324, 0x6b29cb44), TOBN(0xb540a21d, 0x77c8cbac),
++     TOBN(0x9bbfe435, 0x01918e42), TOBN(0xfffa707a, 0x56c3614e),
++     TOBN(0x0ce4e3f1, 0xd4e353b7), TOBN(0x062d8a14, 0xef46b0a0),
++     TOBN(0x6408d5ab, 0x574b73fd), TOBN(0xbc41d1c9, 0xd3273ffd),
++     TOBN(0x3538e1e7, 0x6be77800), TOBN(0x71fe8b37, 0xc5655031),
++     TOBN(0x1cd91621, 0x6b9b331a), TOBN(0xad825d0b, 0xbb388f73),
++     TOBN(0x56c2e05b, 0x1cb76219), TOBN(0x0ec0bf91, 0x71567e7e),
++     TOBN(0xe7076f86, 0x61c4c910), TOBN(0xd67b085b, 0xbabc04d9),
++     TOBN(0x9fb90459, 0x5e93a96a), TOBN(0x7526c1ea, 0xfbdc249a),
++     TOBN(0x0d44d367, 0xecdd0bb7), TOBN(0x95399917, 0x9dc0d695),
++     TOBN(0x61360ee9, 0x9e240d18), TOBN(0x057cdcac, 0xb4b94466),
++     TOBN(0xe7667cd1, 0x2fe5325c), TOBN(0x1fa297b5, 0x21974e3b),
++     TOBN(0xfa4081e7, 0xdb083d76), TOBN(0x31993be6, 0xf206bd15),
++     TOBN(0x8949269b, 0x14c19f8c), TOBN(0x21468d72, 0xa9d92357),
++     TOBN(0x2ccbc583, 0xa4c506ec), TOBN(0x957ed188, 0xd1acfe97),
++     TOBN(0x8baed833, 0x12f1aea2), TOBN(0xef2a6cb4, 0x8325362d),
++     TOBN(0x130dde42, 0x8e195c43), TOBN(0xc842025a, 0x0e6050c6),
++     TOBN(0x2da972a7, 0x08686a5d), TOBN(0xb52999a1, 0xe508b4a8),
++     TOBN(0xd9f090b9, 0x10a5a8bd), TOBN(0xca91d249, 0x096864da),
++     TOBN(0x8e6a93be, 0x3f67dbc1), TOBN(0xacae6fba, 0xf5f4764c),
++     TOBN(0x1563c6e0, 0xd21411a0), TOBN(0x28fa787f, 0xda0a4ad8),
++     TOBN(0xd524491c, 0x908c8030), TOBN(0x1257ba0e, 0x4c795f07),
++     TOBN(0x83f49167, 0xceca9754), TOBN(0x426d2cf6, 0x4b7939a0),
++     TOBN(0x2555e355, 0x723fd0bf), TOBN(0xa96e6d06, 0xc4f144e2),
++     TOBN(0x4768a8dd, 0x87880e61), TOBN(0x15543815, 0xe508e4d5),
++     TOBN(0x09d7e772, 0xb1b65e15), TOBN(0x63439dd6, 0xac302fa0),
++     TOBN(0xb93f802f, 0xc14e35c2), TOBN(0x71735b7c, 0x4341333c),
++     TOBN(0x03a25104, 0x16d4f362), TOBN(0x3f4d069b, 0xbf433c8e),
++     TOBN(0x0d83ae01, 0xf78f5a7c), TOBN(0x50a8ffbe, 0x7c4eed07),
++     TOBN(0xc74f8906, 0x76e10f83), TOBN(0x7d080966, 0x9ddaf8e1),
++     TOBN(0xb11df8e1, 0x698e04cc), TOBN(0x877be203, 0x169005c8),
++     TOBN(0x32749e8c, 0x4f3c6179), TOBN(0x2dbc9d0a, 0x7853fc05),
++     TOBN(0x187d4f93, 0x9454d937), TOBN(0xe682ce9d, 0xb4800e1b),
++     TOBN(0xa9129ad8, 0x165e68e8), TOBN(0x0fe29735, 0xbe7f785b),
++     TOBN(0x5303f40c, 0x5b9e02b7), TOBN(0xa37c9692, 0x35ee04e8),
++     TOBN(0x5f46cc20, 0x34d6632b), TOBN(0x55ef72b2, 0x96ac545b),
++     TOBN(0xabec5c1f, 0x7b91b062), TOBN(0x0a79e1c7, 0xbb33e821),
++     TOBN(0xbb04b428, 0x3a9f4117), TOBN(0x0de1f28f, 0xfd2a475a),
++     TOBN(0x31019ccf, 0x3a4434b4), TOBN(0xa3458111, 0x1a7954dc),
++     TOBN(0xa9dac80d, 0xe34972a7), TOBN(0xb043d054, 0x74f6b8dd),
++     TOBN(0x021c319e, 0x11137b1a), TOBN(0x00a754ce, 0xed5cc03f),
++     TOBN(0x0aa2c794, 0xcbea5ad4), TOBN(0x093e67f4, 0x70c015b6),
++     TOBN(0x72cdfee9, 0xc97e3f6b), TOBN(0xc10bcab4, 0xb6da7461),
++     TOBN(0x3b02d2fc, 0xb59806b9), TOBN(0x85185e89, 0xa1de6f47),
++     TOBN(0x39e6931f, 0x0eb6c4d4), TOBN(0x4d4440bd, 0xd4fa5b04),
++     TOBN(0x5418786e, 0x34be7eb8), TOBN(0x6380e521, 0x9d7259bc),
++     TOBN(0x20ac0351, 0xd598d710), TOBN(0x272c4166, 0xcb3a4da4),
++     TOBN(0xdb82fe1a, 0xca71de1f), TOBN(0x746e79f2, 0xd8f54b0f),
++     TOBN(0x6e7fc736, 0x4b573e9b), TOBN(0x75d03f46, 0xfd4b5040),
++     TOBN(0x5c1cc36d, 0x0b98d87b), TOBN(0x513ba3f1, 0x1f472da1),
++     TOBN(0x79d0af26, 0xabb177dd), TOBN(0xf82ab568, 0x7891d564),
++     TOBN(0x2b6768a9, 0x72232173), TOBN(0xefbb3bb0, 0x8c1f6619),
++     TOBN(0xb29c11db, 0xa6d18358), TOBN(0x519e2797, 0xb0916d3a),
++     TOBN(0xd4dc18f0, 0x9188e290), TOBN(0x648e86e3, 0x98b0ca7f),
++     TOBN(0x859d3145, 0x983c38b5), TOBN(0xb14f176c, 0x637abc8b),
++     TOBN(0x2793fb9d, 0xcaff7be6), TOBN(0xebe5a55f, 0x35a66a5a),
++     TOBN(0x7cec1dcd, 0x9f87dc59), TOBN(0x7c595cd3, 0xfbdbf560),
++     TOBN(0x5b543b22, 0x26eb3257), TOBN(0x69080646, 0xc4c935fd),
++     TOBN(0x7f2e4403, 0x81e9ede3), TOBN(0x243c3894, 0xcaf6df0a),
++     TOBN(0x7c605bb1, 0x1c073b11), TOBN(0xcd06a541, 0xba6a4a62),
++     TOBN(0x29168949, 0x49d4e2e5), TOBN(0x33649d07, 0x4af66880),
++     TOBN(0xbfc0c885, 0xe9a85035), TOBN(0xb4e52113, 0xfc410f4b),
++     TOBN(0xdca3b706, 0x78a6513b), TOBN(0x92ea4a2a, 0x9edb1943),
++     TOBN(0x02642216, 0xdb6e2dd8), TOBN(0x9b45d0b4, 0x9fd57894),
++     TOBN(0x114e70db, 0xc69d11ae), TOBN(0x1477dd19, 0x4c57595f),
++     TOBN(0xbc2208b4, 0xec77c272), TOBN(0x95c5b4d7, 0xdb68f59c),
++     TOBN(0xb8c4fc63, 0x42e532b7), TOBN(0x386ba422, 0x9ae35290),
++     TOBN(0xfb5dda42, 0xd201ecbc), TOBN(0x2353dc8b, 0xa0e38fd6),
++     TOBN(0x9a0b85ea, 0x68f7e978), TOBN(0x96ec5682, 0x2ad6d11f),
++     TOBN(0x5e279d6c, 0xe5f6886d), TOBN(0xd3fe03cd, 0x3cb1914d),
++     TOBN(0xfe541fa4, 0x7ea67c77), TOBN(0x952bd2af, 0xe3ea810c),
++     TOBN(0x791fef56, 0x8d01d374), TOBN(0xa3a1c621, 0x0f11336e),
++     TOBN(0x5ad0d5a9, 0xc7ec6d79), TOBN(0xff7038af, 0x3225c342),
++     TOBN(0x003c6689, 0xbc69601b), TOBN(0x25059bc7, 0x45e8747d),
++     TOBN(0xfa4965b2, 0xf2086fbf), TOBN(0xf6840ea6, 0x86916078),
++     TOBN(0xd7ac7620, 0x70081d6c), TOBN(0xe600da31, 0xb5328645),
++     TOBN(0x01916f63, 0x529b8a80), TOBN(0xe80e4858, 0x2d7d6f3e),
++     TOBN(0x29eb0fe8, 0xd664ca7c), TOBN(0xf017637b, 0xe7b43b0c),
++     TOBN(0x9a75c806, 0x76cb2566), TOBN(0x8f76acb1, 0xb24892d9),
++     TOBN(0x7ae7b9cc, 0x1f08fe45), TOBN(0x19ef7329, 0x6a4907d8),
++     TOBN(0x2db4ab71, 0x5f228bf0), TOBN(0xf3cdea39, 0x817032d7),
++     TOBN(0x0b1f482e, 0xdcabe3c0), TOBN(0x3baf76b4, 0xbb86325c),
++     TOBN(0xd49065e0, 0x10089465), TOBN(0x3bab5d29, 0x8e77c596),
++     TOBN(0x7636c3a6, 0x193dbd95), TOBN(0xdef5d294, 0xb246e499),
++     TOBN(0xb22c58b9, 0x286b2475), TOBN(0xa0b93939, 0xcd80862b),
++     TOBN(0x3002c83a, 0xf0992388), TOBN(0x6de01f9b, 0xeacbe14c),
++     TOBN(0x6aac688e, 0xadd70482), TOBN(0x708de92a, 0x7b4a4e8a),
++     TOBN(0x75b6dd73, 0x758a6eef), TOBN(0xea4bf352, 0x725b3c43),
++     TOBN(0x10041f2c, 0x87912868), TOBN(0xb1b1be95, 0xef09297a),
++     TOBN(0x19ae23c5, 0xa9f3860a), TOBN(0xc4f0f839, 0x515dcf4b),
++     TOBN(0x3c7ecca3, 0x97f6306a), TOBN(0x744c44ae, 0x68a3a4b0),
++     TOBN(0x69cd13a0, 0xb3a1d8a2), TOBN(0x7cad0a1e, 0x5256b578),
++     TOBN(0xea653fcd, 0x33791d9e), TOBN(0x9cc2a05d, 0x74b2e05f),
++     TOBN(0x73b391dc, 0xfd7affa2), TOBN(0xddb7091e, 0xb6b05442),
++     TOBN(0xc71e27bf, 0x8538a5c6), TOBN(0x195c63dd, 0x89abff17),
++     TOBN(0xfd315285, 0x1b71e3da), TOBN(0x9cbdfda7, 0xfa680fa0),
++     TOBN(0x9db876ca, 0x849d7eab), TOBN(0xebe2764b, 0x3c273271),
++     TOBN(0x663357e3, 0xf208dcea), TOBN(0x8c5bd833, 0x565b1b70),
++     TOBN(0xccc3b4f5, 0x9837fc0d), TOBN(0x9b641ba8, 0xa79cf00f),
++     TOBN(0x7428243d, 0xdfdf3990), TOBN(0x83a594c4, 0x020786b1),
++     TOBN(0xb712451a, 0x526c4502), TOBN(0x9d39438e, 0x6adb3f93),
++     TOBN(0xfdb261e3, 0xe9ff0ccd), TOBN(0x80344e3c, 0xe07af4c3),
++     TOBN(0x75900d7c, 0x2fa4f126), TOBN(0x08a3b865, 0x5c99a232),
++     TOBN(0x2478b6bf, 0xdb25e0c3), TOBN(0x482cc2c2, 0x71db2edf),
++     TOBN(0x37df7e64, 0x5f321bb8), TOBN(0x8a93821b, 0x9a8005b4),
++     TOBN(0x3fa2f10c, 0xcc8c1958), TOBN(0x0d332218, 0x2c269d0a),
++     TOBN(0x20ab8119, 0xe246b0e6), TOBN(0xb39781e4, 0xd349fd17),
++     TOBN(0xd293231e, 0xb31aa100), TOBN(0x4b779c97, 0xbb032168),
++     TOBN(0x4b3f19e1, 0xc8470500), TOBN(0x45b7efe9, 0x0c4c869d),
++     TOBN(0xdb84f38a, 0xa1a6bbcc), TOBN(0x3b59cb15, 0xb2fddbc1),
++     TOBN(0xba5514df, 0x3fd165e8), TOBN(0x499fd6a9, 0x061f8811),
++     TOBN(0x72cd1fe0, 0xbfef9f00), TOBN(0x120a4bb9, 0x79ad7e8a),
++     TOBN(0xf2ffd095, 0x5f4a5ac5), TOBN(0xcfd174f1, 0x95a7a2f0),
++     TOBN(0xd42301ba, 0x9d17baf1), TOBN(0xd2fa487a, 0x77f22089),
++     TOBN(0x9cb09efe, 0xb1dc77e1), TOBN(0xe9566939, 0x21c99682),
++     TOBN(0x8c546901, 0x6c6067bb), TOBN(0xfd378574, 0x61c24456),
++     TOBN(0x2b6a6cbe, 0x81796b33), TOBN(0x62d550f6, 0x58e87f8b),
++     TOBN(0x1b763e1c, 0x7f1b01b4), TOBN(0x4b93cfea, 0x1b1b5e12),
++     TOBN(0xb9345238, 0x1d531696), TOBN(0x57201c00, 0x88cdde69),
++     TOBN(0xdde92251, 0x9a86afc7), TOBN(0xe3043895, 0xbd35cea8),
++     TOBN(0x7608c1e1, 0x8555970d), TOBN(0x8267dfa9, 0x2535935e),
++     TOBN(0xd4c60a57, 0x322ea38b), TOBN(0xe0bf7977, 0x804ef8b5),
++     TOBN(0x1a0dab28, 0xc06fece4), TOBN(0xd405991e, 0x94e7b49d),
++     TOBN(0xc542b6d2, 0x706dab28), TOBN(0xcb228da3, 0xa91618fb),
++     TOBN(0x224e4164, 0x107d1cea), TOBN(0xeb9fdab3, 0xd0f5d8f1),
++     TOBN(0xc02ba386, 0x0d6e41cd), TOBN(0x676a72c5, 0x9b1f7146),
++     TOBN(0xffd6dd98, 0x4d6cb00b), TOBN(0xcef9c5ca, 0xde2e8d7c),
++     TOBN(0xa1bbf5d7, 0x641c7936), TOBN(0x1b95b230, 0xee8f772e),
++     TOBN(0xf765a92e, 0xe8ac25b1), TOBN(0xceb04cfc, 0x3a18b7c6),
++     TOBN(0x27944cef, 0x0acc8966), TOBN(0xcbb3c957, 0x434c1004),
++     TOBN(0x9c9971a1, 0xa43ff93c), TOBN(0x5bc2db17, 0xa1e358a9),
++     TOBN(0x45b4862e, 0xa8d9bc82), TOBN(0x70ebfbfb, 0x2201e052),
++     TOBN(0xafdf64c7, 0x92871591), TOBN(0xea5bcae6, 0xb42d0219),
++     TOBN(0xde536c55, 0x2ad8f03c), TOBN(0xcd6c3f4d, 0xa76aa33c),
++     TOBN(0xbeb5f623, 0x0bca6de3), TOBN(0xdd20dd99, 0xb1e706fd),
++     TOBN(0x90b3ff9d, 0xac9059d4), TOBN(0x2d7b2902, 0x7ccccc4e),
++     TOBN(0x8a090a59, 0xce98840f), TOBN(0xa5d947e0, 0x8410680a),
++     TOBN(0x49ae346a, 0x923379a5), TOBN(0x7dbc84f9, 0xb28a3156),
++     TOBN(0xfd40d916, 0x54a1aff2), TOBN(0xabf318ba, 0x3a78fb9b),
++     TOBN(0x50152ed8, 0x3029f95e), TOBN(0x9fc1dd77, 0xc58ad7fa),
++     TOBN(0x5fa57915, 0x13595c17), TOBN(0xb9504668, 0x8f62b3a9),
++     TOBN(0x907b5b24, 0xff3055b0), TOBN(0x2e995e35, 0x9a84f125),
++     TOBN(0x87dacf69, 0x7e9bbcfb), TOBN(0x95d0c1d6, 0xe86d96e3),
++     TOBN(0x65726e3c, 0x2d95a75c), TOBN(0x2c3c9001, 0xacd27f21),
++     TOBN(0x1deab561, 0x6c973f57), TOBN(0x108b7e2c, 0xa5221643),
++     TOBN(0x5fee9859, 0xc4ef79d4), TOBN(0xbd62b88a, 0x40d4b8c6),
++     TOBN(0xb4dd29c4, 0x197c75d6), TOBN(0x266a6df2, 0xb7076feb),
++     TOBN(0x9512d0ea, 0x4bf2df11), TOBN(0x1320c24f, 0x6b0cc9ec),
++     TOBN(0x6bb1e0e1, 0x01a59596), TOBN(0x8317c5bb, 0xeff9aaac),
++     TOBN(0x65bb405e, 0x385aa6c9), TOBN(0x613439c1, 0x8f07988f),
++     TOBN(0xd730049f, 0x16a66e91), TOBN(0xe97f2820, 0xfa1b0e0d),
++     TOBN(0x4131e003, 0x304c28ea), TOBN(0x820ab732, 0x526bac62),
++     TOBN(0xb2ac9ef9, 0x28714423), TOBN(0x54ecfffa, 0xadb10cb2),
++     TOBN(0x8781476e, 0xf886a4cc), TOBN(0x4b2c87b5, 0xdb2f8d49),
++     TOBN(0xe857cd20, 0x0a44295d), TOBN(0x707d7d21, 0x58c6b044),
++     TOBN(0xae8521f9, 0xf596757c), TOBN(0x87448f03, 0x67b2b714),
++     TOBN(0x13a9bc45, 0x5ebcd58d), TOBN(0x79bcced9, 0x9122d3c1),
++     TOBN(0x3c644247, 0x9e076642), TOBN(0x0cf22778, 0x2df4767d),
++     TOBN(0x5e61aee4, 0x71d444b6), TOBN(0x211236bf, 0xc5084a1d),
++     TOBN(0x7e15bc9a, 0x4fd3eaf6), TOBN(0x68df2c34, 0xab622bf5),
++     TOBN(0x9e674f0f, 0x59bf4f36), TOBN(0xf883669b, 0xd7f34d73),
++     TOBN(0xc48ac1b8, 0x31497b1d), TOBN(0x323b925d, 0x5106703b),
++     TOBN(0x22156f42, 0x74082008), TOBN(0xeffc521a, 0xc8482bcb),
++     TOBN(0x5c6831bf, 0x12173479), TOBN(0xcaa2528f, 0xc4739490),
++     TOBN(0x84d2102a, 0x8f1b3c4d), TOBN(0xcf64dfc1, 0x2d9bec0d),
++     TOBN(0x433febad, 0x78a546ef), TOBN(0x1f621ec3, 0x7b73cef1),
++     TOBN(0x6aecd627, 0x37338615), TOBN(0x162082ab, 0x01d8edf6),
++     TOBN(0x833a8119, 0x19e86b66), TOBN(0x6023a251, 0xd299b5db),
++     TOBN(0xf5bb0c3a, 0xbbf04b89), TOBN(0x6735eb69, 0xae749a44),
++     TOBN(0xd0e058c5, 0x4713de3b), TOBN(0xfdf2593e, 0x2c3d4ccd),
++     TOBN(0x1b8f414e, 0xfdd23667), TOBN(0xdd52aaca, 0xfa2015ee),
++     TOBN(0x3e31b517, 0xbd9625ff), TOBN(0x5ec9322d, 0x8db5918c),
++     TOBN(0xbc73ac85, 0xa96f5294), TOBN(0x82aa5bf3, 0x61a0666a),
++     TOBN(0x49755810, 0xbf08ac42), TOBN(0xd21cdfd5, 0x891cedfc),
++     TOBN(0x918cb57b, 0x67f8be10), TOBN(0x365d1a7c, 0x56ffa726),
++     TOBN(0x2435c504, 0x6532de93), TOBN(0xc0fc5e10, 0x2674cd02),
++     TOBN(0x6e51fcf8, 0x9cbbb142), TOBN(0x1d436e5a, 0xafc50692),
++     TOBN(0x766bffff, 0x3fbcae22), TOBN(0x3148c2fd, 0xfd55d3b8),
++     TOBN(0x52c7fdc9, 0x233222fa), TOBN(0x89ff1092, 0xe419fb6b),
++     TOBN(0x3cd6db99, 0x25254977), TOBN(0x2e85a161, 0x1cf12ca7),
++     TOBN(0xadd2547c, 0xdc810bc9), TOBN(0xea3f458f, 0x9d257c22),
++     TOBN(0x642c1fbe, 0x27d6b19b), TOBN(0xed07e6b5, 0x140481a6),
++     TOBN(0x6ada1d42, 0x86d2e0f8), TOBN(0xe5920122, 0x0e8a9fd5),
++     TOBN(0x02c936af, 0x708c1b49), TOBN(0x60f30fee, 0x2b4bfaff),
++     TOBN(0x6637ad06, 0x858e6a61), TOBN(0xce4c7767, 0x3fd374d0),
++     TOBN(0x39d54b2d, 0x7188defb), TOBN(0xa8c9d250, 0xf56a6b66),
++     TOBN(0x58fc0f5e, 0xb24fe1dc), TOBN(0x9eaf9dee, 0x6b73f24c),
++     TOBN(0xa90d588b, 0x33650705), TOBN(0xde5b62c5, 0xaf2ec729),
++     TOBN(0x5c72cfae, 0xd3c2b36e), TOBN(0x868c19d5, 0x034435da),
++     TOBN(0x88605f93, 0xe17ee145), TOBN(0xaa60c4ee, 0x77a5d5b1),
++     TOBN(0xbcf5bfd2, 0x3b60c472), TOBN(0xaf4ef13c, 0xeb1d3049),
++     TOBN(0x373f44fc, 0xe13895c9), TOBN(0xf29b382f, 0x0cbc9822),
++     TOBN(0x1bfcb853, 0x73efaef6), TOBN(0xcf56ac9c, 0xa8c96f40),
++     TOBN(0xd7adf109, 0x7a191e24), TOBN(0x98035f44, 0xbf8a8dc2),
++     TOBN(0xf40a71b9, 0x1e750c84), TOBN(0xc57f7b0c, 0x5dc6c469),
++     TOBN(0x49a0e79c, 0x6fbc19c1), TOBN(0x6b0f5889, 0xa48ebdb8),
++     TOBN(0x5d3fd084, 0xa07c4e9f), TOBN(0xc3830111, 0xab27de14),
++     TOBN(0x0e4929fe, 0x33e08dcc), TOBN(0xf4a5ad24, 0x40bb73a3),
++     TOBN(0xde86c2bf, 0x490f97ca), TOBN(0x288f09c6, 0x67a1ce18),
++     TOBN(0x364bb886, 0x1844478d), TOBN(0x7840fa42, 0xceedb040),
++     TOBN(0x1269fdd2, 0x5a631b37), TOBN(0x94761f1e, 0xa47c8b7d),
++     TOBN(0xfc0c2e17, 0x481c6266), TOBN(0x85e16ea2, 0x3daa5fa7),
++     TOBN(0xccd86033, 0x92491048), TOBN(0x0c2f6963, 0xf4d402d7),
++     TOBN(0x6336f7df, 0xdf6a865c), TOBN(0x0a2a463c, 0xb5c02a87),
++     TOBN(0xb0e29be7, 0xbf2f12ee), TOBN(0xf0a22002, 0x66bad988),
++     TOBN(0x27f87e03, 0x9123c1d7), TOBN(0x21669c55, 0x328a8c98),
++     TOBN(0x186b9803, 0x92f14529), TOBN(0xd3d056cc, 0x63954df3),
++     TOBN(0x2f03fd58, 0x175a46f6), TOBN(0x63e34ebe, 0x11558558),
++     TOBN(0xe13fedee, 0x5b80cfa5), TOBN(0xe872a120, 0xd401dbd1),
++     TOBN(0x52657616, 0xe8a9d667), TOBN(0xbc8da4b6, 0xe08d6693),
++     TOBN(0x370fb9bb, 0x1b703e75), TOBN(0x6773b186, 0xd4338363),
++     TOBN(0x18dad378, 0xecef7bff), TOBN(0xaac787ed, 0x995677da),
++     TOBN(0x4801ea8b, 0x0437164b), TOBN(0xf430ad20, 0x73fe795e),
++     TOBN(0xb164154d, 0x8ee5eb73), TOBN(0x0884ecd8, 0x108f7c0e),
++     TOBN(0x0e6ec096, 0x5f520698), TOBN(0x640631fe, 0x44f7b8d9),
++     TOBN(0x92fd34fc, 0xa35a68b9), TOBN(0x9c5a4b66, 0x4d40cf4e),
++     TOBN(0x949454bf, 0x80b6783d), TOBN(0x80e701fe, 0x3a320a10),
++     TOBN(0x8d1a564a, 0x1a0a39b2), TOBN(0x1436d53d, 0x320587db),
++     TOBN(0xf5096e6d, 0x6556c362), TOBN(0xbc23a3c0, 0xe2455d7e),
++     TOBN(0x3a7aee54, 0x807230f9), TOBN(0x9ba1cfa6, 0x22ae82fd),
++     TOBN(0x833a057a, 0x99c5d706), TOBN(0x8be85f4b, 0x842315c9),
++     TOBN(0xd083179a, 0x66a72f12), TOBN(0x2fc77d5d, 0xcdcc73cd),
++     TOBN(0x22b88a80, 0x5616ee30), TOBN(0xfb09548f, 0xe7ab1083),
++     TOBN(0x8ad6ab0d, 0x511270cd), TOBN(0x61f6c57a, 0x6924d9ab),
++     TOBN(0xa0f7bf72, 0x90aecb08), TOBN(0x849f87c9, 0x0df784a4),
++     TOBN(0x27c79c15, 0xcfaf1d03), TOBN(0xbbf9f675, 0xc463face),
++     TOBN(0x91502c65, 0x765ba543), TOBN(0x18ce3cac, 0x42ea60dd),
++     TOBN(0xe5cee6ac, 0x6e43ecb3), TOBN(0x63e4e910, 0x68f2aeeb),
++     TOBN(0x26234fa3, 0xc85932ee), TOBN(0x96883e8b, 0x4c90c44d),
++     TOBN(0x29b9e738, 0xa18a50f6), TOBN(0xbfc62b2a, 0x3f0420df),
++     TOBN(0xd22a7d90, 0x6d3e1fa9), TOBN(0x17115618, 0xfe05b8a3),
++     TOBN(0x2a0c9926, 0xbb2b9c01), TOBN(0xc739fcc6, 0xe07e76a2),
++     TOBN(0x540e9157, 0x165e439a), TOBN(0x06353a62, 0x6a9063d8),
++     TOBN(0x84d95594, 0x61e927a3), TOBN(0x013b9b26, 0xe2e0be7f),
++     TOBN(0x4feaec3b, 0x973497f1), TOBN(0x15c0f94e, 0x093ebc2d),
++     TOBN(0x6af5f227, 0x33af0583), TOBN(0x0c2af206, 0xc61f3340),
++     TOBN(0xd25dbdf1, 0x4457397c), TOBN(0x2e8ed017, 0xcabcbae0),
++     TOBN(0xe3010938, 0xc2815306), TOBN(0xbaa99337, 0xe8c6cd68),
++     TOBN(0x08513182, 0x3b0ec7de), TOBN(0x1e1b822b, 0x58df05df),
++     TOBN(0x5c14842f, 0xa5c3b683), TOBN(0x98fe977e, 0x3eba34ce),
++     TOBN(0xfd2316c2, 0x0d5e8873), TOBN(0xe48d839a, 0xbd0d427d),
++     TOBN(0x495b2218, 0x623fc961), TOBN(0x24ee56e7, 0xb46fba5e),
++     TOBN(0x9184a55b, 0x91e4de58), TOBN(0xa7488ca5, 0xdfdea288),
++     TOBN(0xa723862e, 0xa8dcc943), TOBN(0x92d762b2, 0x849dc0fc),
++     TOBN(0x3c444a12, 0x091ff4a9), TOBN(0x581113fa, 0x0cada274),
++     TOBN(0xb9de0a45, 0x30d8eae2), TOBN(0x5e0fcd85, 0xdf6b41ea),
++     TOBN(0x6233ea68, 0xc094dbb5), TOBN(0xb77d062e, 0xd968d410),
++     TOBN(0x3e719bbc, 0x58b3002d), TOBN(0x68e7dd3d, 0x3dc49d58),
++     TOBN(0x8d825740, 0x013a5e58), TOBN(0x21311747, 0x3c9e3c1b),
++     TOBN(0x0cb0a2a7, 0x7c99b6ab), TOBN(0x5c48a3b3, 0xc2f888f2)}
++    ,
++    {TOBN(0xc7913e91, 0x991724f3), TOBN(0x5eda799c, 0x39cbd686),
++     TOBN(0xddb595c7, 0x63d4fc1e), TOBN(0x6b63b80b, 0xac4fed54),
++     TOBN(0x6ea0fc69, 0x7e5fb516), TOBN(0x737708ba, 0xd0f1c964),
++     TOBN(0x9628745f, 0x11a92ca5), TOBN(0x61f37958, 0x9a86967a),
++     TOBN(0x9af39b2c, 0xaa665072), TOBN(0x78322fa4, 0xefd324ef),
++     TOBN(0x3d153394, 0xc327bd31), TOBN(0x81d5f271, 0x3129dab0),
++     TOBN(0xc72e0c42, 0xf48027f5), TOBN(0xaa40cdbc, 0x8536e717),
++     TOBN(0xf45a657a, 0x2d369d0f), TOBN(0xb03bbfc4, 0xea7f74e6),
++     TOBN(0x46a8c418, 0x0d738ded), TOBN(0x6f1a5bb0, 0xe0de5729),
++     TOBN(0xf10230b9, 0x8ba81675), TOBN(0x32c6f30c, 0x112b33d4),
++     TOBN(0x7559129d, 0xd8fffb62), TOBN(0x6a281b47, 0xb459bf05),
++     TOBN(0x77c1bd3a, 0xfa3b6776), TOBN(0x0709b380, 0x7829973a),
++     TOBN(0x8c26b232, 0xa3326505), TOBN(0x38d69272, 0xee1d41bf),
++     TOBN(0x0459453e, 0xffe32afa), TOBN(0xce8143ad, 0x7cb3ea87),
++     TOBN(0x932ec1fa, 0x7e6ab666), TOBN(0x6cd2d230, 0x22286264),
++     TOBN(0x459a46fe, 0x6736f8ed), TOBN(0x50bf0d00, 0x9eca85bb),
++     TOBN(0x0b825852, 0x877a21ec), TOBN(0x300414a7, 0x0f537a94),
++     TOBN(0x3f1cba40, 0x21a9a6a2), TOBN(0x50824eee, 0x76943c00),
++     TOBN(0xa0dbfcec, 0xf83cba5d), TOBN(0xf9538148, 0x93b4f3c0),
++     TOBN(0x61744162, 0x48f24dd7), TOBN(0x5322d64d, 0xe4fb09dd),
++     TOBN(0x57447384, 0x3d9325f3), TOBN(0xa9bef2d0, 0xf371cb84),
++     TOBN(0x77d2188b, 0xa61e36c5), TOBN(0xbbd6a7d7, 0xc602df72),
++     TOBN(0xba3aa902, 0x8f61bc0b), TOBN(0xf49085ed, 0x6ed0b6a1),
++     TOBN(0x8bc625d6, 0xae6e8298), TOBN(0x832b0b1d, 0xa2e9c01d),
++     TOBN(0xa337c447, 0xf1f0ced1), TOBN(0x800cc793, 0x9492dd2b),
++     TOBN(0x4b93151d, 0xbea08efa), TOBN(0x820cf3f8, 0xde0a741e),
++     TOBN(0xff1982dc, 0x1c0f7d13), TOBN(0xef921960, 0x84dde6ca),
++     TOBN(0x1ad7d972, 0x45f96ee3), TOBN(0x319c8dbe, 0x29dea0c7),
++     TOBN(0xd3ea3871, 0x7b82b99b), TOBN(0x75922d4d, 0x470eb624),
++     TOBN(0x8f66ec54, 0x3b95d466), TOBN(0x66e673cc, 0xbee1e346),
++     TOBN(0x6afe67c4, 0xb5f2b89a), TOBN(0x3de9c1e6, 0x290e5cd3),
++     TOBN(0x8c278bb6, 0x310a2ada), TOBN(0x420fa384, 0x0bdb323b),
++     TOBN(0x0ae1d63b, 0x0eb919b0), TOBN(0xd74ee51d, 0xa74b9620),
++     TOBN(0x395458d0, 0xa674290c), TOBN(0x324c930f, 0x4620a510),
++     TOBN(0x2d1f4d19, 0xfbac27d4), TOBN(0x4086e8ca, 0x9bedeeac),
++     TOBN(0x0cdd211b, 0x9b679ab8), TOBN(0x5970167d, 0x7090fec4),
++     TOBN(0x3420f2c9, 0xfaf1fc63), TOBN(0x616d333a, 0x328c8bb4),
++     TOBN(0x7d65364c, 0x57f1fe4a), TOBN(0x9343e877, 0x55e5c73a),
++     TOBN(0x5795176b, 0xe970e78c), TOBN(0xa36ccebf, 0x60533627),
++     TOBN(0xfc7c7380, 0x09cdfc1b), TOBN(0xb39a2afe, 0xb3fec326),
++     TOBN(0xb7ff1ba1, 0x6224408a), TOBN(0xcc856e92, 0x247cfc5e),
++     TOBN(0x01f102e7, 0xc18bc493), TOBN(0x4613ab74, 0x2091c727),
++     TOBN(0xaa25e89c, 0xc420bf2b), TOBN(0x00a53176, 0x90337ec2),
++     TOBN(0xd2be9f43, 0x7d025fc7), TOBN(0x3316fb85, 0x6e6fe3dc),
++     TOBN(0x27520af5, 0x9ac50814), TOBN(0xfdf95e78, 0x9a8e4223),
++     TOBN(0xb7e7df2a, 0x56bec5a0), TOBN(0xf7022f7d, 0xdf159e5d),
++     TOBN(0x93eeeab1, 0xcac1fe8f), TOBN(0x8040188c, 0x37451168),
++     TOBN(0x7ee8aa8a, 0xd967dce6), TOBN(0xfa0e79e7, 0x3abc9299),
++     TOBN(0x67332cfc, 0x2064cfd1), TOBN(0x339c31de, 0xb0651934),
++     TOBN(0x719b28d5, 0x2a3bcbea), TOBN(0xee74c82b, 0x9d6ae5c6),
++     TOBN(0x0927d05e, 0xbaf28ee6), TOBN(0x82cecf2c, 0x9d719028),
++     TOBN(0x0b0d353e, 0xddb30289), TOBN(0xfe4bb977, 0xfddb2e29),
++     TOBN(0xbb5bb990, 0x640bfd9e), TOBN(0xd226e277, 0x82f62108),
++     TOBN(0x4bf00985, 0x02ffdd56), TOBN(0x7756758a, 0x2ca1b1b5),
++     TOBN(0xc32b62a3, 0x5285fe91), TOBN(0xedbc546a, 0x8c9cd140),
++     TOBN(0x1e47a013, 0xaf5cb008), TOBN(0xbca7e720, 0x073ce8f2),
++     TOBN(0xe10b2ab8, 0x17a91cae), TOBN(0xb89aab65, 0x08e27f63),
++     TOBN(0x7b3074a7, 0xdba3ddf9), TOBN(0x1c20ce09, 0x330c2972),
++     TOBN(0x6b9917b4, 0x5fcf7e33), TOBN(0xe6793743, 0x945ceb42),
++     TOBN(0x18fc2215, 0x5c633d19), TOBN(0xad1adb3c, 0xc7485474),
++     TOBN(0x646f9679, 0x6424c49b), TOBN(0xf888dfe8, 0x67c241c9),
++     TOBN(0xe12d4b93, 0x24f68b49), TOBN(0x9a6b62d8, 0xa571df20),
++     TOBN(0x81b4b26d, 0x179483cb), TOBN(0x666f9632, 0x9511fae2),
++     TOBN(0xd281b3e4, 0xd53aa51f), TOBN(0x7f96a765, 0x7f3dbd16),
++     TOBN(0xa7f8b5bf, 0x074a30ce), TOBN(0xd7f52107, 0x005a32e6),
++     TOBN(0x6f9e0907, 0x50237ed4), TOBN(0x2f21da47, 0x8096fa2b),
++     TOBN(0xf3e19cb4, 0xeec863a0), TOBN(0xd18f77fd, 0x9527620a),
++     TOBN(0x9505c81c, 0x407c1cf8), TOBN(0x9998db4e, 0x1b6ec284),
++     TOBN(0x7e3389e5, 0xc247d44d), TOBN(0x12507141, 0x3f4f3d80),
++     TOBN(0xd4ba0110, 0x4a78a6c7), TOBN(0x312874a0, 0x767720be),
++     TOBN(0xded059a6, 0x75944370), TOBN(0xd6123d90, 0x3b2c0bdd),
++     TOBN(0xa56b717b, 0x51c108e3), TOBN(0x9bb7940e, 0x070623e9),
++     TOBN(0x794e2d59, 0x84ac066c), TOBN(0xf5954a92, 0xe68c69a0),
++     TOBN(0x28c52458, 0x4fd99dcc), TOBN(0x60e639fc, 0xb1012517),
++     TOBN(0xc2e60125, 0x7de79248), TOBN(0xe9ef6404, 0xf12fc6d7),
++     TOBN(0x4c4f2808, 0x2a3b5d32), TOBN(0x865ad32e, 0xc768eb8a),
++     TOBN(0xac02331b, 0x13fb70b6), TOBN(0x037b44c1, 0x95599b27),
++     TOBN(0x1a860fc4, 0x60bd082c), TOBN(0xa2e25745, 0xc980cd01),
++     TOBN(0xee3387a8, 0x1da0263e), TOBN(0x931bfb95, 0x2d10f3d6),
++     TOBN(0x5b687270, 0xa1f24a32), TOBN(0xf140e65d, 0xca494b86),
++     TOBN(0x4f4ddf91, 0xb2f1ac7a), TOBN(0xf99eaabb, 0x760fee27),
++     TOBN(0x57f4008a, 0x49c228e5), TOBN(0x090be440, 0x1cf713bb),
++     TOBN(0xac91fbe4, 0x5004f022), TOBN(0xd838c2c2, 0x569e1af6),
++     TOBN(0xd6c7d20b, 0x0f1daaa5), TOBN(0xaa063ac1, 0x1bbb02c0),
++     TOBN(0x0938a422, 0x59558a78), TOBN(0x5343c669, 0x8435da2f),
++     TOBN(0x96f67b18, 0x034410dc), TOBN(0x7cc1e424, 0x84510804),
++     TOBN(0x86a1543f, 0x16dfbb7d), TOBN(0x921fa942, 0x5b5bd592),
++     TOBN(0x9dcccb6e, 0xb33dd03c), TOBN(0x8581ddd9, 0xb843f51e),
++     TOBN(0x54935fcb, 0x81d73c9e), TOBN(0x6d07e979, 0x0a5e97ab),
++     TOBN(0x4dc7b30a, 0xcf3a6bab), TOBN(0x147ab1f3, 0x170bee11),
++     TOBN(0x0aaf8e3d, 0x9fafdee4), TOBN(0xfab3dbcb, 0x538a8b95),
++     TOBN(0x405df4b3, 0x6ef13871), TOBN(0xf1f4e9cb, 0x088d5a49),
++     TOBN(0x9bcd24d3, 0x66b33f1d), TOBN(0x3b97b820, 0x5ce445c0),
++     TOBN(0xe2926549, 0xba93ff61), TOBN(0xd9c341ce, 0x4dafe616),
++     TOBN(0xfb30a76e, 0x16efb6f3), TOBN(0xdf24b8ca, 0x605b953c),
++     TOBN(0x8bd52afe, 0xc2fffb9f), TOBN(0xbbac5ff7, 0xe19d0b96),
++     TOBN(0x43c01b87, 0x459afccd), TOBN(0x6bd45143, 0xb7432652),
++     TOBN(0x84734530, 0x55b5d78e), TOBN(0x81088fdb, 0x1554ba7d),
++     TOBN(0xada0a52c, 0x1e269375), TOBN(0xf9f037c4, 0x2dc5ec10),
++     TOBN(0xc0660607, 0x94bfbc11), TOBN(0xc0a630bb, 0xc9c40d2f),
++     TOBN(0x5efc797e, 0xab64c31e), TOBN(0xffdb1dab, 0x74507144),
++     TOBN(0xf6124287, 0x1ca6790c), TOBN(0xe9609d81, 0xe69bf1bf),
++     TOBN(0xdb898595, 0x00d24fc9), TOBN(0x9c750333, 0xe51fb417),
++     TOBN(0x51830a91, 0xfef7bbde), TOBN(0x0ce67dc8, 0x945f585c),
++     TOBN(0x9a730ed4, 0x4763eb50), TOBN(0x24a0e221, 0xc1ab0d66),
++     TOBN(0x643b6393, 0x648748f3), TOBN(0x1982daa1, 0x6d3c6291),
++     TOBN(0x6f00a9f7, 0x8bbc5549), TOBN(0x7a1783e1, 0x7f36384e),
++     TOBN(0xe8346323, 0xde977f50), TOBN(0x91ab688d, 0xb245502a),
++     TOBN(0x331ab6b5, 0x6d0bdd66), TOBN(0x0a6ef32e, 0x64b71229),
++     TOBN(0x1028150e, 0xfe7c352f), TOBN(0x27e04350, 0xce7b39d3),
++     TOBN(0x2a3c8acd, 0xc1070c82), TOBN(0xfb2034d3, 0x80c9feef),
++     TOBN(0x2d729621, 0x709f3729), TOBN(0x8df290bf, 0x62cb4549),
++     TOBN(0x02f99f33, 0xfc2e4326), TOBN(0x3b30076d, 0x5eddf032),
++     TOBN(0xbb21f8cf, 0x0c652fb5), TOBN(0x314fb49e, 0xed91cf7b),
++     TOBN(0xa013eca5, 0x2f700750), TOBN(0x2b9e3c23, 0x712a4575),
++     TOBN(0xe5355557, 0xaf30fbb0), TOBN(0x1ada3516, 0x7c77e771),
++     TOBN(0x45f6ecb2, 0x7b135670), TOBN(0xe85d19df, 0x7cfc202e),
++     TOBN(0x0f1b50c7, 0x58d1be9f), TOBN(0x5ebf2c0a, 0xead2e344),
++     TOBN(0x1531fe4e, 0xabc199c9), TOBN(0xc7032592, 0x56bab0ae),
++     TOBN(0x16ab2e48, 0x6c1fec54), TOBN(0x0f87fda8, 0x04280188),
++     TOBN(0xdc9f46fc, 0x609e4a74), TOBN(0x2a44a143, 0xba667f91),
++     TOBN(0xbc3d8b95, 0xb4d83436), TOBN(0xa01e4bd0, 0xc7bd2958),
++     TOBN(0x7b182932, 0x73483c90), TOBN(0xa79c6aa1, 0xa7c7b598),
++     TOBN(0xbf3983c6, 0xeaaac07e), TOBN(0x8f18181e, 0x96e0d4e6),
++     TOBN(0x8553d37c, 0x051af62b), TOBN(0xe9a998eb, 0x0bf94496),
++     TOBN(0xe0844f9f, 0xb0d59aa1), TOBN(0x983fd558, 0xe6afb813),
++     TOBN(0x9670c0ca, 0x65d69804), TOBN(0x732b22de, 0x6ea5ff2d),
++     TOBN(0xd7640ba9, 0x5fd8623b), TOBN(0x9f619163, 0xa6351782),
++     TOBN(0x0bfc27ee, 0xacee5043), TOBN(0xae419e73, 0x2eb10f02),
++     TOBN(0x19c028d1, 0x8943fb05), TOBN(0x71f01cf7, 0xff13aa2a),
++     TOBN(0x7790737e, 0x8887a132), TOBN(0x67513309, 0x66318410),
++     TOBN(0x9819e8a3, 0x7ddb795e), TOBN(0xfecb8ef5, 0xdad100b2),
++     TOBN(0x59f74a22, 0x3021926a), TOBN(0xb7c28a49, 0x6f9b4c1c),
++     TOBN(0xed1a733f, 0x912ad0ab), TOBN(0x42a910af, 0x01a5659c),
++     TOBN(0x3842c6e0, 0x7bd68cab), TOBN(0x2b57fa38, 0x76d70ac8),
++     TOBN(0x8a6707a8, 0x3c53aaeb), TOBN(0x62c1c510, 0x65b4db18),
++     TOBN(0x8de2c1fb, 0xb2d09dc7), TOBN(0xc3dfed12, 0x266bd23b),
++     TOBN(0x927d039b, 0xd5b27db6), TOBN(0x2fb2f0f1, 0x103243da),
++     TOBN(0xf855a07b, 0x80be7399), TOBN(0xed9327ce, 0x1f9f27a8),
++     TOBN(0xa0bd99c7, 0x729bdef7), TOBN(0x2b67125e, 0x28250d88),
++     TOBN(0x784b26e8, 0x8670ced7), TOBN(0xe3dfe41f, 0xc31bd3b4),
++     TOBN(0x9e353a06, 0xbcc85cbc), TOBN(0x302e2909, 0x60178a9d),
++     TOBN(0x860abf11, 0xa6eac16e), TOBN(0x76447000, 0xaa2b3aac),
++     TOBN(0x46ff9d19, 0x850afdab), TOBN(0x35bdd6a5, 0xfdb2d4c1),
++     TOBN(0xe82594b0, 0x7e5c9ce9), TOBN(0x0f379e53, 0x20af346e),
++     TOBN(0x608b31e3, 0xbc65ad4a), TOBN(0x710c6b12, 0x267c4826),
++     TOBN(0x51c966f9, 0x71954cf1), TOBN(0xb1cec793, 0x0d0aa215),
++     TOBN(0x1f155989, 0x86bd23a8), TOBN(0xae2ff99c, 0xf9452e86),
++     TOBN(0xd8dd953c, 0x340ceaa2), TOBN(0x26355275, 0x2e2e9333),
++     TOBN(0x15d4e5f9, 0x8586f06d), TOBN(0xd6bf94a8, 0xf7cab546),
++     TOBN(0x33c59a0a, 0xb76a9af0), TOBN(0x52740ab3, 0xba095af7),
++     TOBN(0xc444de8a, 0x24389ca0), TOBN(0xcc6f9863, 0x706da0cb),
++     TOBN(0xb5a741a7, 0x6b2515cf), TOBN(0x71c41601, 0x9585c749),
++     TOBN(0x78350d4f, 0xe683de97), TOBN(0x31d61524, 0x63d0b5f5),
++     TOBN(0x7a0cc5e1, 0xfbce090b), TOBN(0xaac927ed, 0xfbcb2a5b),
++     TOBN(0xe920de49, 0x20d84c35), TOBN(0x8c06a0b6, 0x22b4de26),
++     TOBN(0xd34dd58b, 0xafe7ddf3), TOBN(0x55851fed, 0xc1e6e55b),
++     TOBN(0xd1395616, 0x960696e7), TOBN(0x940304b2, 0x5f22705f),
++     TOBN(0x6f43f861, 0xb0a2a860), TOBN(0xcf121282, 0x0e7cc981),
++     TOBN(0x12186212, 0x0ab64a96), TOBN(0x09215b9a, 0xb789383c),
++     TOBN(0x311eb305, 0x37387c09), TOBN(0xc5832fce, 0xf03ee760),
++     TOBN(0x30358f58, 0x32f7ea19), TOBN(0xe01d3c34, 0x91d53551),
++     TOBN(0x1ca5ee41, 0xda48ea80), TOBN(0x34e71e8e, 0xcf4fa4c1),
++     TOBN(0x312abd25, 0x7af1e1c7), TOBN(0xe3afcdeb, 0x2153f4a5),
++     TOBN(0x9d5c84d7, 0x00235e9a), TOBN(0x0308d3f4, 0x8c4c836f),
++     TOBN(0xc0a66b04, 0x89332de5), TOBN(0x610dd399, 0x89e566ef),
++     TOBN(0xf8eea460, 0xd1ac1635), TOBN(0x84cbb3fb, 0x20a2c0df),
++     TOBN(0x40afb488, 0xe74a48c5), TOBN(0x29738198, 0xd326b150),
++     TOBN(0x2a17747f, 0xa6d74081), TOBN(0x60ea4c05, 0x55a26214),
++     TOBN(0x53514bb4, 0x1f88c5fe), TOBN(0xedd64567, 0x7e83426c),
++     TOBN(0xd5d6cbec, 0x96460b25), TOBN(0xa12fd0ce, 0x68dc115e),
++     TOBN(0xc5bc3ed2, 0x697840ea), TOBN(0x969876a8, 0xa6331e31),
++     TOBN(0x60c36217, 0x472ff580), TOBN(0xf4229705, 0x4ad41393),
++     TOBN(0x4bd99ef0, 0xa03b8b92), TOBN(0x501c7317, 0xc144f4f6),
++     TOBN(0x159009b3, 0x18464945), TOBN(0x6d5e594c, 0x74c5c6be),
++     TOBN(0x2d587011, 0x321a3660), TOBN(0xd1e184b1, 0x3898d022),
++     TOBN(0x5ba04752, 0x4c6a7e04), TOBN(0x47fa1e2b, 0x45550b65),
++     TOBN(0x9419daf0, 0x48c0a9a5), TOBN(0x66362953, 0x7c243236),
++     TOBN(0xcd0744b1, 0x5cb12a88), TOBN(0x561b6f9a, 0x2b646188),
++     TOBN(0x599415a5, 0x66c2c0c0), TOBN(0xbe3f0859, 0x0f83f09a),
++     TOBN(0x9141c5be, 0xb92041b8), TOBN(0x01ae38c7, 0x26477d0d),
++     TOBN(0xca8b71f3, 0xd12c7a94), TOBN(0xfab5b31f, 0x765c70db),
++     TOBN(0x76ae7492, 0x487443e9), TOBN(0x8595a310, 0x990d1349),
++     TOBN(0xf8dbeda8, 0x7d460a37), TOBN(0x7f7ad082, 0x1e45a38f),
++     TOBN(0xed1d4db6, 0x1059705a), TOBN(0xa3dd492a, 0xe6b9c697),
++     TOBN(0x4b92ee3a, 0x6eb38bd5), TOBN(0xbab2609d, 0x67cc0bb7),
++     TOBN(0x7fc4fe89, 0x6e70ee82), TOBN(0xeff2c56e, 0x13e6b7e3),
++     TOBN(0x9b18959e, 0x34d26fca), TOBN(0x2517ab66, 0x889d6b45),
++     TOBN(0xf167b4e0, 0xbdefdd4f), TOBN(0x69958465, 0xf366e401),
++     TOBN(0x5aa368ab, 0xa73bbec0), TOBN(0x12148709, 0x7b240c21),
++     TOBN(0x378c3233, 0x18969006), TOBN(0xcb4d73ce, 0xe1fe53d1),
++     TOBN(0x5f50a80e, 0x130c4361), TOBN(0xd67f5951, 0x7ef5212b),
++     TOBN(0xf145e21e, 0x9e70c72e), TOBN(0xb2e52e29, 0x5566d2fb),
++     TOBN(0x44eaba4a, 0x032397f5), TOBN(0x5e56937b, 0x7e31a7de),
++     TOBN(0x68dcf517, 0x456c61e1), TOBN(0xbc2e954a, 0xa8b0a388),
++     TOBN(0xe3552fa7, 0x60a8b755), TOBN(0x03442dae, 0x73ad0cde),
++     TOBN(0x37ffe747, 0xceb26210), TOBN(0x983545e8, 0x787baef9),
++     TOBN(0x8b8c8535, 0x86a3de31), TOBN(0xc621dbcb, 0xfacd46db),
++     TOBN(0x82e442e9, 0x59266fbb), TOBN(0xa3514c37, 0x339d471c),
++     TOBN(0x3a11b771, 0x62cdad96), TOBN(0xf0cb3b3c, 0xecf9bdf0),
++     TOBN(0x3fcbdbce, 0x478e2135), TOBN(0x7547b5cf, 0xbda35342),
++     TOBN(0xa97e81f1, 0x8a677af6), TOBN(0xc8c2bf83, 0x28817987),
++     TOBN(0xdf07eaaf, 0x45580985), TOBN(0xc68d1f05, 0xc93b45cb),
++     TOBN(0x106aa2fe, 0xc77b4cac), TOBN(0x4c1d8afc, 0x04a7ae86),
++     TOBN(0xdb41c3fd, 0x9eb45ab2), TOBN(0x5b234b5b, 0xd4b22e74),
++     TOBN(0xda253dec, 0xf215958a), TOBN(0x67e0606e, 0xa04edfa0),
++     TOBN(0xabbbf070, 0xef751b11), TOBN(0xf352f175, 0xf6f06dce),
++     TOBN(0xdfc4b6af, 0x6839f6b4), TOBN(0x53ddf9a8, 0x9959848e),
++     TOBN(0xda49c379, 0xc21520b0), TOBN(0x90864ff0, 0xdbd5d1b6),
++     TOBN(0x2f055d23, 0x5f49c7f7), TOBN(0xe51e4e6a, 0xa796b2d8),
++     TOBN(0xc361a67f, 0x5c9dc340), TOBN(0x5ad53c37, 0xbca7c620),
++     TOBN(0xda1d6588, 0x32c756d0), TOBN(0xad60d911, 0x8bb67e13),
++     TOBN(0xd6c47bdf, 0x0eeec8c6), TOBN(0x4a27fec1, 0x078a1821),
++     TOBN(0x081f7415, 0xc3099524), TOBN(0x8effdf0b, 0x82cd8060),
++     TOBN(0xdb70ec1c, 0x65842df8), TOBN(0x8821b358, 0xd319a901),
++     TOBN(0x72ee56ee, 0xde42b529), TOBN(0x5bb39592, 0x236e4286),
++     TOBN(0xd1183316, 0xfd6f7140), TOBN(0xf9fadb5b, 0xbd8e81f7),
++     TOBN(0x701d5e0c, 0x5a02d962), TOBN(0xfdee4dbf, 0x1b601324),
++     TOBN(0xbed17407, 0x35d7620e), TOBN(0x04e3c2c3, 0xf48c0012),
++     TOBN(0x9ee29da7, 0x3455449a), TOBN(0x562cdef4, 0x91a836c4),
++     TOBN(0x8f682a5f, 0x47701097), TOBN(0x617125d8, 0xff88d0c2),
++     TOBN(0x948fda24, 0x57bb86dd), TOBN(0x348abb8f, 0x289f7286),
++     TOBN(0xeb10eab5, 0x99d94bbd), TOBN(0xd51ba28e, 0x4684d160),
++     TOBN(0xabe0e51c, 0x30c8f41a), TOBN(0x66588b45, 0x13254f4a),
++     TOBN(0x147ebf01, 0xfad097a5), TOBN(0x49883ea8, 0x610e815d),
++     TOBN(0xe44d60ba, 0x8a11de56), TOBN(0xa970de6e, 0x827a7a6d),
++     TOBN(0x2be41424, 0x5e17fc19), TOBN(0xd833c657, 0x01214057),
++     TOBN(0x1375813b, 0x363e723f), TOBN(0x6820bb88, 0xe6a52e9b),
++     TOBN(0x7e7f6970, 0xd875d56a), TOBN(0xd6a0a9ac, 0x51fbf6bf),
++     TOBN(0x54ba8790, 0xa3083c12), TOBN(0xebaeb23d, 0x6ae7eb64),
++     TOBN(0xa8685c3a, 0xb99a907a), TOBN(0xf1e74550, 0x026bf40b),
++     TOBN(0x7b73a027, 0xc802cd9e), TOBN(0x9a8a927c, 0x4fef4635),
++     TOBN(0xe1b6f60c, 0x08191224), TOBN(0xc4126ebb, 0xde4ec091),
++     TOBN(0xe1dff4dc, 0x4ae38d84), TOBN(0xde3f57db, 0x4f2ef985),
++     TOBN(0x34964337, 0xd446a1dd), TOBN(0x7bf217a0, 0x859e77f6),
++     TOBN(0x8ff10527, 0x8e1d13f5), TOBN(0xa304ef03, 0x74eeae27),
++     TOBN(0xfc6f5e47, 0xd19dfa5a), TOBN(0xdb007de3, 0x7fad982b),
++     TOBN(0x28205ad1, 0x613715f5), TOBN(0x251e6729, 0x7889529e),
++     TOBN(0x72705184, 0x1ae98e78), TOBN(0xf818537d, 0x271cac32),
++     TOBN(0xc8a15b7e, 0xb7f410f5), TOBN(0xc474356f, 0x81f62393),
++     TOBN(0x92dbdc5a, 0xc242316b), TOBN(0xabe060ac, 0xdbf4aff5),
++     TOBN(0x6e8c38fe, 0x909a8ec6), TOBN(0x43e514e5, 0x6116cb94),
++     TOBN(0x2078fa38, 0x07d784f9), TOBN(0x1161a880, 0xf4b5b357),
++     TOBN(0x5283ce79, 0x13adea3d), TOBN(0x0756c3e6, 0xcc6a910b),
++     TOBN(0x60bcfe01, 0xaaa79697), TOBN(0x04a73b29, 0x56391db1),
++     TOBN(0xdd8dad47, 0x189b45a0), TOBN(0xbfac0dd0, 0x48d5b8d9),
++     TOBN(0x34ab3af5, 0x7d3d2ec2), TOBN(0x6fa2fc2d, 0x207bd3af),
++     TOBN(0x9ff40092, 0x66550ded), TOBN(0x719b3e87, 0x1fd5b913),
++     TOBN(0xa573a496, 0x6d17fbc7), TOBN(0x0cd1a70a, 0x73d2b24e),
++     TOBN(0x34e2c5ca, 0xb2676937), TOBN(0xe7050b06, 0xbf669f21),
++     TOBN(0xfbe948b6, 0x1ede9046), TOBN(0xa0530051, 0x97662659),
++     TOBN(0x58cbd4ed, 0xf10124c5), TOBN(0xde2646e4, 0xdd6c06c8),
++     TOBN(0x332f8108, 0x8cad38c0), TOBN(0x471b7e90, 0x6bd68ae2),
++     TOBN(0x56ac3fb2, 0x0d8e27a3), TOBN(0xb54660db, 0x136b4b0d),
++     TOBN(0x123a1e11, 0xa6fd8de4), TOBN(0x44dbffea, 0xa37799ef),
++     TOBN(0x4540b977, 0xce6ac17c), TOBN(0x495173a8, 0xaf60acef)}
++    ,
++    {TOBN(0x9ebb284d, 0x391c2a82), TOBN(0xbcdd4863, 0x158308e8),
++     TOBN(0x006f16ec, 0x83f1edca), TOBN(0xa13e2c37, 0x695dc6c8),
++     TOBN(0x2ab756f0, 0x4a057a87), TOBN(0xa8765500, 0xa6b48f98),
++     TOBN(0x4252face, 0x68651c44), TOBN(0xa52b540b, 0xe1765e02),
++     TOBN(0x4f922fc5, 0x16a0d2bb), TOBN(0x0d5cc16c, 0x1a623499),
++     TOBN(0x9241cf3a, 0x57c62c8b), TOBN(0x2f5e6961, 0xfd1b667f),
++     TOBN(0x5c15c70b, 0xf5a01797), TOBN(0x3d20b44d, 0x60956192),
++     TOBN(0x04911b37, 0x071fdb52), TOBN(0xf648f916, 0x8d6f0f7b),
++     TOBN(0x6dc1acaf, 0xe60b7cf7), TOBN(0x25860a50, 0x84a9d869),
++     TOBN(0x56fc6f09, 0xe7ba8ac4), TOBN(0x828c5bd0, 0x6148d29e),
++     TOBN(0xac6b435e, 0xdc55ae5f), TOBN(0xa527f56c, 0xc0117411),
++     TOBN(0x94d5045e, 0xfd24342c), TOBN(0x2c4c0a35, 0x70b67c0d),
++     TOBN(0x027cc8b8, 0xfac61d9a), TOBN(0x7d25e062, 0xe3c6fe8a),
++     TOBN(0xe08805bf, 0xe5bff503), TOBN(0x13271e6c, 0x6ff632f7),
++     TOBN(0x55dca6c0, 0x232f76a5), TOBN(0x8957c32d, 0x701ef426),
++     TOBN(0xee728bcb, 0xa10a5178), TOBN(0x5ea60411, 0xb62c5173),
++     TOBN(0xfc4e964e, 0xd0b8892b), TOBN(0x9ea17683, 0x9301bb74),
++     TOBN(0x6265c5ae, 0xfcc48626), TOBN(0xe60cf82e, 0xbb3e9102),
++     TOBN(0x57adf797, 0xd4df5531), TOBN(0x235b59a1, 0x8deeefe2),
++     TOBN(0x60adcf58, 0x3f306eb1), TOBN(0x105c2753, 0x3d09492d),
++     TOBN(0x4090914b, 0xb5def996), TOBN(0x1cb69c83, 0x233dd1e7),
++     TOBN(0xc1e9c1d3, 0x9b3d5e76), TOBN(0x1f3338ed, 0xfccf6012),
++     TOBN(0xb1e95d0d, 0x2f5378a8), TOBN(0xacf4c2c7, 0x2f00cd21),
++     TOBN(0x6e984240, 0xeb5fe290), TOBN(0xd66c038d, 0x248088ae),
++     TOBN(0x804d264a, 0xf94d70cf), TOBN(0xbdb802ef, 0x7314bf7e),
++     TOBN(0x8fb54de2, 0x4333ed02), TOBN(0x740461e0, 0x285635d9),
++     TOBN(0x4113b2c8, 0x365e9383), TOBN(0xea762c83, 0x3fdef652),
++     TOBN(0x4eec6e2e, 0x47b956c1), TOBN(0xa3d814be, 0x65620fa4),
++     TOBN(0x9ad5462b, 0xb4d8bc50), TOBN(0x181c0b16, 0xa9195770),
++     TOBN(0xebd4fe1c, 0x78412a68), TOBN(0xae0341bc, 0xc0dff48c),
++     TOBN(0xb6bc45cf, 0x7003e866), TOBN(0xf11a6dea, 0x8a24a41b),
++     TOBN(0x5407151a, 0xd04c24c2), TOBN(0x62c9d27d, 0xda5b7b68),
++     TOBN(0x2e964235, 0x88cceff6), TOBN(0x8594c54f, 0x8b07ed69),
++     TOBN(0x1578e73c, 0xc84d0d0d), TOBN(0x7b4e1055, 0xff532868),
++     TOBN(0xa348c0d5, 0xb5ec995a), TOBN(0xbf4b9d55, 0x14289a54),
++     TOBN(0x9ba155a6, 0x58fbd777), TOBN(0x186ed7a8, 0x1a84491d),
++     TOBN(0xd4992b30, 0x614c0900), TOBN(0xda98d121, 0xbd00c24b),
++     TOBN(0x7f534dc8, 0x7ec4bfa1), TOBN(0x4a5ff674, 0x37dc34bc),
++     TOBN(0x68c196b8, 0x1d7ea1d7), TOBN(0x38cf2893, 0x80a6d208),
++     TOBN(0xfd56cd09, 0xe3cbbd6e), TOBN(0xec72e27e, 0x4205a5b6),
++     TOBN(0x15ea68f5, 0xa44f77f7), TOBN(0x7aa5f9fd, 0xb43c52bc),
++     TOBN(0x86ff676f, 0x94f0e609), TOBN(0xa4cde963, 0x2e2d432b),
++     TOBN(0x8cafa0c0, 0xeee470af), TOBN(0x84137d0e, 0x8a3f5ec8),
++     TOBN(0xebb40411, 0xfaa31231), TOBN(0xa239c13f, 0x6f7f7ccf),
++     TOBN(0x32865719, 0xa8afd30b), TOBN(0x86798328, 0x8a826dce),
++     TOBN(0xdf04e891, 0xc4a8fbe0), TOBN(0xbb6b6e1b, 0xebf56ad3),
++     TOBN(0x0a695b11, 0x471f1ff0), TOBN(0xd76c3389, 0xbe15baf0),
++     TOBN(0x018edb95, 0xbe96c43e), TOBN(0xf2beaaf4, 0x90794158),
++     TOBN(0x152db09e, 0xc3076a27), TOBN(0x5e82908e, 0xe416545d),
++     TOBN(0xa2c41272, 0x356d6f2e), TOBN(0xdc9c9642, 0x31fd74e1),
++     TOBN(0x66ceb88d, 0x519bf615), TOBN(0xe29ecd76, 0x05a2274e),
++     TOBN(0x3a0473c4, 0xbf5e2fa0), TOBN(0x6b6eb671, 0x64284e67),
++     TOBN(0xe8b97932, 0xb88756dd), TOBN(0xed4e8652, 0xf17e3e61),
++     TOBN(0xc2dd1499, 0x3ee1c4a4), TOBN(0xc0aaee17, 0x597f8c0e),
++     TOBN(0x15c4edb9, 0x6c168af3), TOBN(0x6563c7bf, 0xb39ae875),
++     TOBN(0xadfadb6f, 0x20adb436), TOBN(0xad55e8c9, 0x9a042ac0),
++     TOBN(0x975a1ed8, 0xb76da1f5), TOBN(0x10dfa466, 0xa58acb94),
++     TOBN(0x8dd7f7e3, 0xac060282), TOBN(0x6813e66a, 0x572a051e),
++     TOBN(0xb4ccae1e, 0x350cb901), TOBN(0xb653d656, 0x50cb7822),
++     TOBN(0x42484710, 0xdfab3b87), TOBN(0xcd7ee537, 0x9b670fd0),
++     TOBN(0x0a50b12e, 0x523b8bf6), TOBN(0x8009eb5b, 0x8f910c1b),
++     TOBN(0xf535af82, 0x4a167588), TOBN(0x0f835f9c, 0xfb2a2abd),
++     TOBN(0xf59b2931, 0x2afceb62), TOBN(0xc797df2a, 0x169d383f),
++     TOBN(0xeb3f5fb0, 0x66ac02b0), TOBN(0x029d4c6f, 0xdaa2d0ca),
++     TOBN(0xd4059bc1, 0xafab4bc5), TOBN(0x833f5c6f, 0x56783247),
++     TOBN(0xb5346630, 0x8d2d3605), TOBN(0x83387891, 0xd34d8433),
++     TOBN(0xd973b30f, 0xadd9419a), TOBN(0xbcca1099, 0xafe3fce8),
++     TOBN(0x08178315, 0x0809aac6), TOBN(0x01b7f21a, 0x540f0f11),
++     TOBN(0x65c29219, 0x909523c8), TOBN(0xa62f648f, 0xa3a1c741),
++     TOBN(0x88598d4f, 0x60c9e55a), TOBN(0xbce9141b, 0x0e4f347a),
++     TOBN(0x9af97d84, 0x35f9b988), TOBN(0x0210da62, 0x320475b6),
++     TOBN(0x3c076e22, 0x9191476c), TOBN(0x7520dbd9, 0x44fc7834),
++     TOBN(0x6a6b2cfe, 0xc1ab1bbd), TOBN(0xef8a65be, 0xdc650938),
++     TOBN(0x72855540, 0x805d7bc4), TOBN(0xda389396, 0xed11fdfd),
++     TOBN(0xa9d5bd36, 0x74660876), TOBN(0x11d67c54, 0xb45dff35),
++     TOBN(0x6af7d148, 0xa4f5da94), TOBN(0xbb8d4c3f, 0xc0bbeb31),
++     TOBN(0x87a7ebd1, 0xe0a1b12a), TOBN(0x1e4ef88d, 0x770ba95f),
++     TOBN(0x8c33345c, 0xdc2ae9cb), TOBN(0xcecf1276, 0x01cc8403),
++     TOBN(0x687c012e, 0x1b39b80f), TOBN(0xfd90d0ad, 0x35c33ba4),
++     TOBN(0xa3ef5a67, 0x5c9661c2), TOBN(0x368fc88e, 0xe017429e),
++     TOBN(0xd30c6761, 0x196a2fa2), TOBN(0x931b9817, 0xbd5b312e),
++     TOBN(0xba01000c, 0x72f54a31), TOBN(0xa203d2c8, 0x66eaa541),
++     TOBN(0xf2abdee0, 0x98939db3), TOBN(0xe37d6c2c, 0x3e606c02),
++     TOBN(0xf2921574, 0x521ff643), TOBN(0x2781b3c4, 0xd7e2fca3),
++     TOBN(0x664300b0, 0x7850ec06), TOBN(0xac5a38b9, 0x7d3a10cf),
++     TOBN(0x9233188d, 0xe34ab39d), TOBN(0xe77057e4, 0x5072cbb9),
++     TOBN(0xbcf0c042, 0xb59e78df), TOBN(0x4cfc91e8, 0x1d97de52),
++     TOBN(0x4661a26c, 0x3ee0ca4a), TOBN(0x5620a4c1, 0xfb8507bc),
++     TOBN(0x4b44d4aa, 0x049f842c), TOBN(0xceabc5d5, 0x1540e82b),
++     TOBN(0x306710fd, 0x15c6f156), TOBN(0xbe5ae52b, 0x63db1d72),
++     TOBN(0x06f1e7e6, 0x334957f1), TOBN(0x57e388f0, 0x31144a70),
++     TOBN(0xfb69bb2f, 0xdf96447b), TOBN(0x0f78ebd3, 0x73e38a12),
++     TOBN(0xb8222605, 0x2b7ce542), TOBN(0xe6d4ce99, 0x7472bde1),
++     TOBN(0x53e16ebe, 0x09d2f4da), TOBN(0x180ff42e, 0x53b92b2e),
++     TOBN(0xc59bcc02, 0x2c34a1c6), TOBN(0x3803d6f9, 0x422c46c2),
++     TOBN(0x18aff74f, 0x5c14a8a2), TOBN(0x55aebf80, 0x10a08b28),
++     TOBN(0x66097d58, 0x7135593f), TOBN(0x32e6eff7, 0x2be570cd),
++     TOBN(0x584e6a10, 0x2a8c860d), TOBN(0xcd185890, 0xa2eb4163),
++     TOBN(0x7ceae99d, 0x6d97e134), TOBN(0xd42c6b70, 0xdd8447ce),
++     TOBN(0x59ddbb4a, 0xb8c50273), TOBN(0x03c612df, 0x3cf34e1e),
++     TOBN(0x84b9ca15, 0x04b6c5a0), TOBN(0x35216f39, 0x18f0e3a3),
++     TOBN(0x3ec2d2bc, 0xbd986c00), TOBN(0x8bf546d9, 0xd19228fe),
++     TOBN(0xd1c655a4, 0x4cd623c3), TOBN(0x366ce718, 0x502b8e5a),
++     TOBN(0x2cfc84b4, 0xeea0bfe7), TOBN(0xe01d5cee, 0xcf443e8e),
++     TOBN(0x8ec045d9, 0x036520f8), TOBN(0xdfb3c3d1, 0x92d40e98),
++     TOBN(0x0bac4cce, 0xcc559a04), TOBN(0x35eccae5, 0x240ea6b1),
++     TOBN(0x180b32db, 0xf8a5a0ac), TOBN(0x547972a5, 0xeb699700),
++     TOBN(0xa3765801, 0xca26bca0), TOBN(0x57e09d0e, 0xa647f25a),
++     TOBN(0xb956970e, 0x2fdd23cc), TOBN(0xb80288bc, 0x5682e971),
++     TOBN(0xe6e6d91e, 0x9ae86ebc), TOBN(0x0564c83f, 0x8c9f1939),
++     TOBN(0x551932a2, 0x39560368), TOBN(0xe893752b, 0x049c28e2),
++     TOBN(0x0b03cee5, 0xa6a158c3), TOBN(0xe12d656b, 0x04964263),
++     TOBN(0x4b47554e, 0x63e3bc1d), TOBN(0xc719b6a2, 0x45044ff7),
++     TOBN(0x4f24d30a, 0xe48daa07), TOBN(0xa3f37556, 0xc8c1edc3),
++     TOBN(0x9a47bf76, 0x0700d360), TOBN(0xbb1a1824, 0x822ae4e2),
++     TOBN(0x22e275a3, 0x89f1fb4c), TOBN(0x72b1aa23, 0x9968c5f5),
++     TOBN(0xa75feaca, 0xbe063f64), TOBN(0x9b392f43, 0xbce47a09),
++     TOBN(0xd4241509, 0x1ad07aca), TOBN(0x4b0c591b, 0x8d26cd0f),
++     TOBN(0x2d42ddfd, 0x92f1169a), TOBN(0x63aeb1ac, 0x4cbf2392),
++     TOBN(0x1de9e877, 0x0691a2af), TOBN(0xebe79af7, 0xd98021da),
++     TOBN(0xcfdf2a4e, 0x40e50acf), TOBN(0xf0a98ad7, 0xaf01d665),
++     TOBN(0xefb640bf, 0x1831be1f), TOBN(0x6fe8bd2f, 0x80e9ada0),
++     TOBN(0x94c103a1, 0x6cafbc91), TOBN(0x170f8759, 0x8308e08c),
++     TOBN(0x5de2d2ab, 0x9780ff4f), TOBN(0x666466bc, 0x45b201f2),
++     TOBN(0x58af2010, 0xf5b343bc), TOBN(0x0f2e400a, 0xf2f142fe),
++     TOBN(0x3483bfde, 0xa85f4bdf), TOBN(0xf0b1d093, 0x03bfeaa9),
++     TOBN(0x2ea01b95, 0xc7081603), TOBN(0xe943e4c9, 0x3dba1097),
++     TOBN(0x47be92ad, 0xb438f3a6), TOBN(0x00bb7742, 0xe5bf6636),
++     TOBN(0x136b7083, 0x824297b4), TOBN(0x9d0e5580, 0x5584455f),
++     TOBN(0xab48cedc, 0xf1c7d69e), TOBN(0x53a9e481, 0x2a256e76),
++     TOBN(0x0402b0e0, 0x65eb2413), TOBN(0xdadbbb84, 0x8fc407a7),
++     TOBN(0xa65cd5a4, 0x8d7f5492), TOBN(0x21d44293, 0x74bae294),
++     TOBN(0x66917ce6, 0x3b5f1cc4), TOBN(0x37ae52ea, 0xce872e62),
++     TOBN(0xbb087b72, 0x2905f244), TOBN(0x12077086, 0x1e6af74f),
++     TOBN(0x4b644e49, 0x1058edea), TOBN(0x827510e3, 0xb638ca1d),
++     TOBN(0x8cf2b704, 0x6038591c), TOBN(0xffc8b47a, 0xfe635063),
++     TOBN(0x3ae220e6, 0x1b4d5e63), TOBN(0xbd864742, 0x9d961b4b),
++     TOBN(0x610c107e, 0x9bd16bed), TOBN(0x4270352a, 0x1127147b),
++     TOBN(0x7d17ffe6, 0x64cfc50e), TOBN(0x50dee01a, 0x1e36cb42),
++     TOBN(0x068a7622, 0x35dc5f9a), TOBN(0x9a08d536, 0xdf53f62c),
++     TOBN(0x4ed71457, 0x6be5f7de), TOBN(0xd93006f8, 0xc2263c9e),
++     TOBN(0xe073694c, 0xcacacb36), TOBN(0x2ff7a5b4, 0x3ae118ab),
++     TOBN(0x3cce53f1, 0xcd871236), TOBN(0xf156a39d, 0xc2aa6d52),
++     TOBN(0x9cc5f271, 0xb198d76d), TOBN(0xbc615b6f, 0x81383d39),
++     TOBN(0xa54538e8, 0xde3eee6b), TOBN(0x58c77538, 0xab910d91),
++     TOBN(0x31e5bdbc, 0x58d278bd), TOBN(0x3cde4adf, 0xb963acae),
++     TOBN(0xb1881fd2, 0x5302169c), TOBN(0x8ca60fa0, 0xa989ed8b),
++     TOBN(0xa1999458, 0xff96a0ee), TOBN(0xc1141f03, 0xac6c283d),
++     TOBN(0x7677408d, 0x6dfafed3), TOBN(0x33a01653, 0x39661588),
++     TOBN(0x3c9c15ec, 0x0b726fa0), TOBN(0x090cfd93, 0x6c9b56da),
++     TOBN(0xe34f4bae, 0xa3c40af5), TOBN(0x3469eadb, 0xd21129f1),
++     TOBN(0xcc51674a, 0x1e207ce8), TOBN(0x1e293b24, 0xc83b1ef9),
++     TOBN(0x17173d13, 0x1e6c0bb4), TOBN(0x19004695, 0x90776d35),
++     TOBN(0xe7980e34, 0x6de6f922), TOBN(0x873554cb, 0xf4dd9a22),
++     TOBN(0x0316c627, 0xcbf18a51), TOBN(0x4d93651b, 0x3032c081),
++     TOBN(0x207f2771, 0x3946834d), TOBN(0x2c08d7b4, 0x30cdbf80),
++     TOBN(0x137a4fb4, 0x86df2a61), TOBN(0xa1ed9c07, 0xecf7b4a2),
++     TOBN(0xb2e460e2, 0x7bd042ff), TOBN(0xb7f5e2fa, 0x5f62f5ec),
++     TOBN(0x7aa6ec6b, 0xcc2423b7), TOBN(0x75ce0a7f, 0xba63eea7),
++     TOBN(0x67a45fb1, 0xf250a6e1), TOBN(0x93bc919c, 0xe53cdc9f),
++     TOBN(0x9271f56f, 0x871942df), TOBN(0x2372ff6f, 0x7859ad66),
++     TOBN(0x5f4c2b96, 0x33cb1a78), TOBN(0xe3e29101, 0x5838aa83),
++     TOBN(0xa7ed1611, 0xe4e8110c), TOBN(0x2a2d70d5, 0x330198ce),
++     TOBN(0xbdf132e8, 0x6720efe0), TOBN(0xe61a8962, 0x66a471bf),
++     TOBN(0x796d3a85, 0x825808bd), TOBN(0x51dc3cb7, 0x3fd6e902),
++     TOBN(0x643c768a, 0x916219d1), TOBN(0x36cd7685, 0xa2ad7d32),
++     TOBN(0xe3db9d05, 0xb22922a4), TOBN(0x6494c87e, 0xdba29660),
++     TOBN(0xf0ac91df, 0xbcd2ebc7), TOBN(0x4deb57a0, 0x45107f8d),
++     TOBN(0x42271f59, 0xc3d12a73), TOBN(0x5f71687c, 0xa5c2c51d),
++     TOBN(0xcb1f50c6, 0x05797bcb), TOBN(0x29ed0ed9, 0xd6d34eb0),
++     TOBN(0xe5fe5b47, 0x4683c2eb), TOBN(0x4956eeb5, 0x97447c46),
++     TOBN(0x5b163a43, 0x71207167), TOBN(0x93fa2fed, 0x0248c5ef),
++     TOBN(0x67930af2, 0x31f63950), TOBN(0xa77797c1, 0x14caa2c9),
++     TOBN(0x526e80ee, 0x27ac7e62), TOBN(0xe1e6e626, 0x58b28aec),
++     TOBN(0x636178b0, 0xb3c9fef0), TOBN(0xaf7752e0, 0x6d5f90be),
++     TOBN(0x94ecaf18, 0xeece51cf), TOBN(0x2864d0ed, 0xca806e1f),
++     TOBN(0x6de2e383, 0x97c69134), TOBN(0x5a42c316, 0xeb291293),
++     TOBN(0xc7779219, 0x6a60bae0), TOBN(0xa24de346, 0x6b7599d1),
++     TOBN(0x49d374aa, 0xb75d4941), TOBN(0x98900586, 0x2d501ff0),
++     TOBN(0x9f16d40e, 0xeb7974cf), TOBN(0x1033860b, 0xcdd8c115),
++     TOBN(0xb6c69ac8, 0x2094cec3), TOBN(0x9976fb88, 0x403b770c),
++     TOBN(0x1dea026c, 0x4859590d), TOBN(0xb6acbb46, 0x8562d1fd),
++     TOBN(0x7cd6c461, 0x44569d85), TOBN(0xc3190a36, 0x97f0891d),
++     TOBN(0xc6f53195, 0x48d5a17d), TOBN(0x7d919966, 0xd749abc8),
++     TOBN(0x65104837, 0xdd1c8a20), TOBN(0x7e5410c8, 0x2f683419),
++     TOBN(0x958c3ca8, 0xbe94022e), TOBN(0x605c3197, 0x6145dac2),
++     TOBN(0x3fc07501, 0x01683d54), TOBN(0x1d7127c5, 0x595b1234),
++     TOBN(0x10b8f87c, 0x9481277f), TOBN(0x677db2a8, 0xe65a1adb),
++     TOBN(0xec2fccaa, 0xddce3345), TOBN(0x2a6811b7, 0x012a4350),
++     TOBN(0x96760ff1, 0xac598bdc), TOBN(0x054d652a, 0xd1bf4128),
++     TOBN(0x0a1151d4, 0x92a21005), TOBN(0xad7f3971, 0x33110fdf),
++     TOBN(0x8c95928c, 0x1960100f), TOBN(0x6c91c825, 0x7bf03362),
++     TOBN(0xc8c8b2a2, 0xce309f06), TOBN(0xfdb27b59, 0xca27204b),
++     TOBN(0xd223eaa5, 0x0848e32e), TOBN(0xb93e4b2e, 0xe7bfaf1e),
++     TOBN(0xc5308ae6, 0x44aa3ded), TOBN(0x317a666a, 0xc015d573),
++     TOBN(0xc888ce23, 0x1a979707), TOBN(0xf141c1e6, 0x0d5c4958),
++     TOBN(0xb53b7de5, 0x61906373), TOBN(0x858dbade, 0xeb999595),
++     TOBN(0x8cbb47b2, 0xa59e5c36), TOBN(0x660318b3, 0xdcf4e842),
++     TOBN(0xbd161ccd, 0x12ba4b7a), TOBN(0xf399daab, 0xf8c8282a),
++     TOBN(0x1587633a, 0xeeb2130d), TOBN(0xa465311a, 0xda38dd7d),
++     TOBN(0x5f75eec8, 0x64d3779b), TOBN(0x3c5d0476, 0xad64c171),
++     TOBN(0x87410371, 0x2a914428), TOBN(0x8096a891, 0x90e2fc29),
++     TOBN(0xd3d2ae9d, 0x23b3ebc2), TOBN(0x90bdd6db, 0xa580cfd6),
++     TOBN(0x52dbb7f3, 0xc5b01f6c), TOBN(0xe68eded4, 0xe102a2dc),
++     TOBN(0x17785b77, 0x99eb6df0), TOBN(0x26c3cc51, 0x7386b779),
++     TOBN(0x345ed988, 0x6417a48e), TOBN(0xe990b4e4, 0x07d6ef31),
++     TOBN(0x0f456b7e, 0x2586abba), TOBN(0x239ca6a5, 0x59c96e9a),
++     TOBN(0xe327459c, 0xe2eb4206), TOBN(0x3a4c3313, 0xa002b90a),
++     TOBN(0x2a114806, 0xf6a3f6fb), TOBN(0xad5cad2f, 0x85c251dd),
++     TOBN(0x92c1f613, 0xf5a784d3), TOBN(0xec7bfacf, 0x349766d5),
++     TOBN(0x04b3cd33, 0x3e23cb3b), TOBN(0x3979fe84, 0xc5a64b2d),
++     TOBN(0x192e2720, 0x7e589106), TOBN(0xa60c43d1, 0xa15b527f),
++     TOBN(0x2dae9082, 0xbe7cf3a6), TOBN(0xcc86ba92, 0xbc967274),
++     TOBN(0xf28a2ce8, 0xaea0a8a9), TOBN(0x404ca6d9, 0x6ee988b3),
++     TOBN(0xfd7e9c5d, 0x005921b8), TOBN(0xf56297f1, 0x44e79bf9),
++     TOBN(0xa163b460, 0x0d75ddc2), TOBN(0x30b23616, 0xa1f2be87),
++     TOBN(0x4b070d21, 0xbfe50e2b), TOBN(0x7ef8cfd0, 0xe1bfede1),
++     TOBN(0xadba0011, 0x2aac4ae0), TOBN(0x2a3e7d01, 0xb9ebd033),
++     TOBN(0x995277ec, 0xe38d9d1c), TOBN(0xb500249e, 0x9c5d2de3),
++     TOBN(0x8912b820, 0xf13ca8c9), TOBN(0xc8798114, 0x877793af),
++     TOBN(0x19e6125d, 0xec3f1dec), TOBN(0x07b1f040, 0x911178da),
++     TOBN(0xd93ededa, 0x904a6738), TOBN(0x55187a5a, 0x0bebedcd),
++     TOBN(0xf7d04722, 0xeb329d41), TOBN(0xf449099e, 0xf170b391),
++     TOBN(0xfd317a69, 0xca99f828), TOBN(0x50c3db2b, 0x34a4976d),
++     TOBN(0xe9ba7784, 0x3757b392), TOBN(0x326caefd, 0xaa3ca05a),
++     TOBN(0x78e5293b, 0xf1e593d4), TOBN(0x7842a937, 0x0d98fd13),
++     TOBN(0xe694bf96, 0x5f96b10d), TOBN(0x373a9df6, 0x06a8cd05),
++     TOBN(0x997d1e51, 0xe8f0c7fc), TOBN(0x1d019790, 0x63fd972e),
++     TOBN(0x0064d858, 0x5499fb32), TOBN(0x7b67bad9, 0x77a8aeb7),
++     TOBN(0x1d3eb977, 0x2d08eec5), TOBN(0x5fc047a6, 0xcbabae1d),
++     TOBN(0x0577d159, 0xe54a64bb), TOBN(0x8862201b, 0xc43497e4),
++     TOBN(0xad6b4e28, 0x2ce0608d), TOBN(0x8b687b7d, 0x0b167aac),
++     TOBN(0x6ed4d367, 0x8b2ecfa9), TOBN(0x24dfe62d, 0xa90c3c38),
++     TOBN(0xa1862e10, 0x3fe5c42b), TOBN(0x1ca73dca, 0xd5732a9f),
++     TOBN(0x35f038b7, 0x76bb87ad), TOBN(0x674976ab, 0xf242b81f),
++     TOBN(0x4f2bde7e, 0xb0fd90cd), TOBN(0x6efc172e, 0xa7fdf092),
++     TOBN(0x3806b69b, 0x92222f1f), TOBN(0x5a2459ca, 0x6cf7ae70),
++     TOBN(0x6789f69c, 0xa85217ee), TOBN(0x5f232b5e, 0xe3dc85ac),
++     TOBN(0x660e3ec5, 0x48e9e516), TOBN(0x124b4e47, 0x3197eb31),
++     TOBN(0x10a0cb13, 0xaafcca23), TOBN(0x7bd63ba4, 0x8213224f),
++     TOBN(0xaffad7cc, 0x290a7f4f), TOBN(0x6b409c9e, 0x0286b461),
++     TOBN(0x58ab809f, 0xffa407af), TOBN(0xc3122eed, 0xc68ac073),
++     TOBN(0x17bf9e50, 0x4ef24d7e), TOBN(0x5d929794, 0x3e2a5811),
++     TOBN(0x519bc867, 0x02902e01), TOBN(0x76bba5da, 0x39c8a851),
++     TOBN(0xe9f9669c, 0xda94951e), TOBN(0x4b6af58d, 0x66b8d418),
++     TOBN(0xfa321074, 0x17d426a4), TOBN(0xc78e66a9, 0x9dde6027),
++     TOBN(0x0516c083, 0x4a53b964), TOBN(0xfc659d38, 0xff602330),
++     TOBN(0x0ab55e5c, 0x58c5c897), TOBN(0x985099b2, 0x838bc5df),
++     TOBN(0x061d9efc, 0xc52fc238), TOBN(0x712b2728, 0x6ac1da3f),
++     TOBN(0xfb658149, 0x9283fe08), TOBN(0x4954ac94, 0xb8aaa2f7),
++     TOBN(0x85c0ada4, 0x7fb2e74f), TOBN(0xee8ba98e, 0xb89926b0),
++     TOBN(0xe4f9d37d, 0x23d1af5b), TOBN(0x14ccdbf9, 0xba9b015e),
++     TOBN(0xb674481b, 0x7bfe7178), TOBN(0x4e1debae, 0x65405868),
++     TOBN(0x061b2821, 0xc48c867d), TOBN(0x69c15b35, 0x513b30ea),
++     TOBN(0x3b4a1666, 0x36871088), TOBN(0xe5e29f5d, 0x1220b1ff),
++     TOBN(0x4b82bb35, 0x233d9f4d), TOBN(0x4e076333, 0x18cdc675)}
++    ,
++    {TOBN(0x0d53f5c7, 0xa3e6fced), TOBN(0xe8cbbdd5, 0xf45fbdeb),
++     TOBN(0xf85c01df, 0x13339a70), TOBN(0x0ff71880, 0x142ceb81),
++     TOBN(0x4c4e8774, 0xbd70437a), TOBN(0x5fb32891, 0xba0bda6a),
++     TOBN(0x1cdbebd2, 0xf18bd26e), TOBN(0x2f9526f1, 0x03a9d522),
++     TOBN(0x40ce3051, 0x92c4d684), TOBN(0x8b04d725, 0x7612efcd),
++     TOBN(0xb9dcda36, 0x6f9cae20), TOBN(0x0edc4d24, 0xf058856c),
++     TOBN(0x64f2e6bf, 0x85427900), TOBN(0x3de81295, 0xdc09dfea),
++     TOBN(0xd41b4487, 0x379bf26c), TOBN(0x50b62c6d, 0x6df135a9),
++     TOBN(0xd4f8e3b4, 0xc72dfe67), TOBN(0xc416b0f6, 0x90e19fdf),
++     TOBN(0x18b9098d, 0x4c13bd35), TOBN(0xac11118a, 0x15b8cb9e),
++     TOBN(0xf598a318, 0xf0062841), TOBN(0xbfe0602f, 0x89f356f4),
++     TOBN(0x7ae3637e, 0x30177a0c), TOBN(0x34097747, 0x61136537),
++     TOBN(0x0db2fb5e, 0xd005832a), TOBN(0x5f5efd3b, 0x91042e4f),
++     TOBN(0x8c4ffdc6, 0xed70f8ca), TOBN(0xe4645d0b, 0xb52da9cc),
++     TOBN(0x9596f58b, 0xc9001d1f), TOBN(0x52c8f0bc, 0x4e117205),
++     TOBN(0xfd4aa0d2, 0xe398a084), TOBN(0x815bfe3a, 0x104f49de),
++     TOBN(0x97e5443f, 0x23885e5f), TOBN(0xf72f8f99, 0xe8433aab),
++     TOBN(0xbd00b154, 0xe4d4e604), TOBN(0xd0b35e6a, 0xe5e173ff),
++     TOBN(0x57b2a048, 0x9164722d), TOBN(0x3e3c665b, 0x88761ec8),
++     TOBN(0x6bdd1397, 0x3da83832), TOBN(0x3c8b1a1e, 0x73dafe3b),
++     TOBN(0x4497ace6, 0x54317cac), TOBN(0xbe600ab9, 0x521771b3),
++     TOBN(0xb42e409e, 0xb0dfe8b8), TOBN(0x386a67d7, 0x3942310f),
++     TOBN(0x25548d8d, 0x4431cc28), TOBN(0xa7cff142, 0x985dc524),
++     TOBN(0x4d60f5a1, 0x93c4be32), TOBN(0x83ebd5c8, 0xd071c6e1),
++     TOBN(0xba3a80a7, 0xb1fd2b0b), TOBN(0x9b3ad396, 0x5bec33e8),
++     TOBN(0xb3868d61, 0x79743fb3), TOBN(0xcfd169fc, 0xfdb462fa),
++     TOBN(0xd3b499d7, 0x9ce0a6af), TOBN(0x55dc1cf1, 0xe42d3ff8),
++     TOBN(0x04fb9e6c, 0xc6c3e1b2), TOBN(0x47e6961d, 0x6f69a474),
++     TOBN(0x54eb3acc, 0xe548b37b), TOBN(0xb38e7542, 0x84d40549),
++     TOBN(0x8c3daa51, 0x7b341b4f), TOBN(0x2f6928ec, 0x690bf7fa),
++     TOBN(0x0496b323, 0x86ce6c41), TOBN(0x01be1c55, 0x10adadcd),
++     TOBN(0xc04e67e7, 0x4bb5faf9), TOBN(0x3cbaf678, 0xe15c9985),
++     TOBN(0x8cd12145, 0x50ca4247), TOBN(0xba1aa47a, 0xe7dd30aa),
++     TOBN(0x2f81ddf1, 0xe58fee24), TOBN(0x03452936, 0xeec9b0e8),
++     TOBN(0x8bdc3b81, 0x243aea96), TOBN(0x9a2919af, 0x15c3d0e5),
++     TOBN(0x9ea640ec, 0x10948361), TOBN(0x5ac86d5b, 0x6e0bcccf),
++     TOBN(0xf892d918, 0xc36cf440), TOBN(0xaed3e837, 0xc939719c),
++     TOBN(0xb07b08d2, 0xc0218b64), TOBN(0x6f1bcbba, 0xce9790dd),
++     TOBN(0x4a84d6ed, 0x60919b8e), TOBN(0xd8900791, 0x8ac1f9eb),
++     TOBN(0xf84941aa, 0x0dd5daef), TOBN(0xb22fe40a, 0x67fd62c5),
++     TOBN(0x97e15ba2, 0x157f2db3), TOBN(0xbda2fc8f, 0x8e28ca9c),
++     TOBN(0x5d050da4, 0x37b9f454), TOBN(0x3d57eb57, 0x2379d72e),
++     TOBN(0xe9b5eba2, 0xfb5ee997), TOBN(0x01648ca2, 0xe11538ca),
++     TOBN(0x32bb76f6, 0xf6327974), TOBN(0x338f14b8, 0xff3f4bb7),
++     TOBN(0x524d226a, 0xd7ab9a2d), TOBN(0x9c00090d, 0x7dfae958),
++     TOBN(0x0ba5f539, 0x8751d8c2), TOBN(0x8afcbcdd, 0x3ab8262d),
++     TOBN(0x57392729, 0xe99d043b), TOBN(0xef51263b, 0xaebc943a),
++     TOBN(0x9feace93, 0x20862935), TOBN(0x639efc03, 0xb06c817b),
++     TOBN(0x1fe054b3, 0x66b4be7a), TOBN(0x3f25a9de, 0x84a37a1e),
++     TOBN(0xf39ef1ad, 0x78d75cd9), TOBN(0xd7b58f49, 0x5062c1b5),
++     TOBN(0x6f74f9a9, 0xff563436), TOBN(0xf718ff29, 0xe8af51e7),
++     TOBN(0x5234d313, 0x15e97fec), TOBN(0xb6a8e2b1, 0x292f1c0a),
++     TOBN(0xa7f53aa8, 0x327720c1), TOBN(0x956ca322, 0xba092cc8),
++     TOBN(0x8f03d64a, 0x28746c4d), TOBN(0x51fe1782, 0x66d0d392),
++     TOBN(0xd19b34db, 0x3c832c80), TOBN(0x60dccc5c, 0x6da2e3b4),
++     TOBN(0x245dd62e, 0x0a104ccc), TOBN(0xa7ab1de1, 0x620b21fd),
++     TOBN(0xb293ae0b, 0x3893d123), TOBN(0xf7b75783, 0xb15ee71c),
++     TOBN(0x5aa3c614, 0x42a9468b), TOBN(0xd686123c, 0xdb15d744),
++     TOBN(0x8c616891, 0xa7ab4116), TOBN(0x6fcd72c8, 0xa4e6a459),
++     TOBN(0xac219110, 0x77e5fad7), TOBN(0xfb6a20e7, 0x704fa46b),
++     TOBN(0xe839be7d, 0x341d81dc), TOBN(0xcddb6889, 0x32148379),
++     TOBN(0xda6211a1, 0xf7026ead), TOBN(0xf3b2575f, 0xf4d1cc5e),
++     TOBN(0x40cfc8f6, 0xa7a73ae6), TOBN(0x83879a5e, 0x61d5b483),
++     TOBN(0xc5acb1ed, 0x41a50ebc), TOBN(0x59a60cc8, 0x3c07d8fa),
++     TOBN(0x1b73bdce, 0xb1876262), TOBN(0x2b0d79f0, 0x12af4ee9),
++     TOBN(0x8bcf3b0b, 0xd46e1d07), TOBN(0x17d6af9d, 0xe45d152f),
++     TOBN(0x73520461, 0x6d736451), TOBN(0x43cbbd97, 0x56b0bf5a),
++     TOBN(0xb0833a5b, 0xd5999b9d), TOBN(0x702614f0, 0xeb72e398),
++     TOBN(0x0aadf01a, 0x59c3e9f8), TOBN(0x40200e77, 0xce6b3d16),
++     TOBN(0xda22bdd3, 0xdeddafad), TOBN(0x76dedaf4, 0x310d72e1),
++     TOBN(0x49ef807c, 0x4bc2e88f), TOBN(0x6ba81291, 0x146dd5a5),
++     TOBN(0xa1a4077a, 0x7d8d59e9), TOBN(0x87b6a2e7, 0x802db349),
++     TOBN(0xd5679997, 0x1b4e598e), TOBN(0xf499ef1f, 0x06fe4b1d),
++     TOBN(0x3978d3ae, 0xfcb267c5), TOBN(0xb582b557, 0x235786d0),
++     TOBN(0x32b3b2ca, 0x1715cb07), TOBN(0x4c3de6a2, 0x8480241d),
++     TOBN(0x63b5ffed, 0xcb571ecd), TOBN(0xeaf53900, 0xed2fe9a9),
++     TOBN(0xdec98d4a, 0xc3b81990), TOBN(0x1cb83722, 0x9e0cc8fe),
++     TOBN(0xfe0b0491, 0xd2b427b9), TOBN(0x0f2386ac, 0xe983a66c),
++     TOBN(0x930c4d1e, 0xb3291213), TOBN(0xa2f82b2e, 0x59a62ae4),
++     TOBN(0x77233853, 0xf93e89e3), TOBN(0x7f8063ac, 0x11777c7f),
++     TOBN(0xff0eb567, 0x59ad2877), TOBN(0x6f454642, 0x9865c754),
++     TOBN(0xe6fe701a, 0x236e9a84), TOBN(0xc586ef16, 0x06e40fc3),
++     TOBN(0x3f62b6e0, 0x24bafad9), TOBN(0xc8b42bd2, 0x64da906a),
++     TOBN(0xc98e1eb4, 0xda3276a0), TOBN(0x30d0e5fc, 0x06cbf852),
++     TOBN(0x1b6b2ae1, 0xe8b4dfd4), TOBN(0xd754d5c7, 0x8301cbac),
++     TOBN(0x66097629, 0x112a39ac), TOBN(0xf86b5999, 0x93ba4ab9),
++     TOBN(0x26c9dea7, 0x99f9d581), TOBN(0x0473b1a8, 0xc2fafeaa),
++     TOBN(0x1469af55, 0x3b2505a5), TOBN(0x227d16d7, 0xd6a43323),
++     TOBN(0x3316f73c, 0xad3d97f9), TOBN(0x52bf3bb5, 0x1f137455),
++     TOBN(0x953eafeb, 0x09954e7c), TOBN(0xa721dfed, 0xdd732411),
++     TOBN(0xb4929821, 0x141d4579), TOBN(0x3411321c, 0xaa3bd435),
++     TOBN(0xafb355aa, 0x17fa6015), TOBN(0xb4e7ef4a, 0x18e42f0e),
++     TOBN(0x604ac97c, 0x59371000), TOBN(0xe1c48c70, 0x7f759c18),
++     TOBN(0x3f62ecc5, 0xa5db6b65), TOBN(0x0a78b173, 0x38a21495),
++     TOBN(0x6be1819d, 0xbcc8ad94), TOBN(0x70dc04f6, 0xd89c3400),
++     TOBN(0x462557b4, 0xa6b4840a), TOBN(0x544c6ade, 0x60bd21c0),
++     TOBN(0x6a00f24e, 0x907a544b), TOBN(0xa7520dcb, 0x313da210),
++     TOBN(0xfe939b75, 0x11e4994b), TOBN(0x918b6ba6, 0xbc275d70),
++     TOBN(0xd3e5e0fc, 0x644be892), TOBN(0x707a9816, 0xfdaf6c42),
++     TOBN(0x60145567, 0xf15c13fe), TOBN(0x4818ebaa, 0xe130a54a),
++     TOBN(0x28aad3ad, 0x58d2f767), TOBN(0xdc5267fd, 0xd7e7c773),
++     TOBN(0x4919cc88, 0xc3afcc98), TOBN(0xaa2e6ab0, 0x2db8cd4b),
++     TOBN(0xd46fec04, 0xd0c63eaa), TOBN(0xa1cb92c5, 0x19ffa832),
++     TOBN(0x678dd178, 0xe43a631f), TOBN(0xfb5ae1cd, 0x3dc788b3),
++     TOBN(0x68b4fb90, 0x6e77de04), TOBN(0x7992bcf0, 0xf06dbb97),
++     TOBN(0x896e6a13, 0xc417c01d), TOBN(0x8d96332c, 0xb956be01),
++     TOBN(0x902fc93a, 0x413aa2b9), TOBN(0x99a4d915, 0xfc98c8a5),
++     TOBN(0x52c29407, 0x565f1137), TOBN(0x4072690f, 0x21e4f281),
++     TOBN(0x36e607cf, 0x02ff6072), TOBN(0xa47d2ca9, 0x8ad98cdc),
++     TOBN(0xbf471d1e, 0xf5f56609), TOBN(0xbcf86623, 0xf264ada0),
++     TOBN(0xb70c0687, 0xaa9e5cb6), TOBN(0xc98124f2, 0x17401c6c),
++     TOBN(0x8189635f, 0xd4a61435), TOBN(0xd28fb8af, 0xa9d98ea6),
++     TOBN(0xb9a67c2a, 0x40c251f8), TOBN(0x88cd5d87, 0xa2da44be),
++     TOBN(0x437deb96, 0xe09b5423), TOBN(0x150467db, 0x64287dc1),
++     TOBN(0xe161debb, 0xcdabb839), TOBN(0xa79e9742, 0xf1839a3e),
++     TOBN(0xbb8dd3c2, 0x652d202b), TOBN(0x7b3e67f7, 0xe9f97d96),
++     TOBN(0x5aa5d78f, 0xb1cb6ac9), TOBN(0xffa13e8e, 0xca1d0d45),
++     TOBN(0x369295dd, 0x2ba5bf95), TOBN(0xd68bd1f8, 0x39aff05e),
++     TOBN(0xaf0d86f9, 0x26d783f2), TOBN(0x543a59b3, 0xfc3aafc1),
++     TOBN(0x3fcf81d2, 0x7b7da97c), TOBN(0xc990a056, 0xd25dee46),
++     TOBN(0x3e6775b8, 0x519cce2c), TOBN(0xfc9af71f, 0xae13d863),
++     TOBN(0x774a4a6f, 0x47c1605c), TOBN(0x46ba4245, 0x2fd205e8),
++     TOBN(0xa06feea4, 0xd3fd524d), TOBN(0x1e724641, 0x6de1acc2),
++     TOBN(0xf53816f1, 0x334e2b42), TOBN(0x49e5918e, 0x922f0024),
++     TOBN(0x439530b6, 0x65c7322d), TOBN(0xcf12cc01, 0xb3c1b3fb),
++     TOBN(0xc70b0186, 0x0172f685), TOBN(0xb915ee22, 0x1b58391d),
++     TOBN(0x9afdf03b, 0xa317db24), TOBN(0x87dec659, 0x17b8ffc4),
++     TOBN(0x7f46597b, 0xe4d3d050), TOBN(0x80a1c1ed, 0x006500e7),
++     TOBN(0x84902a96, 0x78bf030e), TOBN(0xfb5e9c9a, 0x50560148),
++     TOBN(0x6dae0a92, 0x63362426), TOBN(0xdcaeecf4, 0xa9e30c40),
++     TOBN(0xc0d887bb, 0x518d0c6b), TOBN(0x99181152, 0xcb985b9d),
++     TOBN(0xad186898, 0xef7bc381), TOBN(0x18168ffb, 0x9ee46201),
++     TOBN(0x9a04cdaa, 0x2502753c), TOBN(0xbb279e26, 0x51407c41),
++     TOBN(0xeacb03aa, 0xf23564e5), TOBN(0x18336582, 0x71e61016),
++     TOBN(0x8684b8c4, 0xeb809877), TOBN(0xb336e18d, 0xea0e672e),
++     TOBN(0xefb601f0, 0x34ee5867), TOBN(0x2733edbe, 0x1341cfd1),
++     TOBN(0xb15e809a, 0x26025c3c), TOBN(0xe6e981a6, 0x9350df88),
++     TOBN(0x92376237, 0x8502fd8e), TOBN(0x4791f216, 0x0c12be9b),
++     TOBN(0xb7256789, 0x25f02425), TOBN(0xec863194, 0x7a974443),
++     TOBN(0x7c0ce882, 0xfb41cc52), TOBN(0xc266ff7e, 0xf25c07f2),
++     TOBN(0x3d4da8c3, 0x017025f3), TOBN(0xefcf628c, 0xfb9579b4),
++     TOBN(0x5c4d0016, 0x1f3716ec), TOBN(0x9c27ebc4, 0x6801116e),
++     TOBN(0x5eba0ea1, 0x1da1767e), TOBN(0xfe151452, 0x47004c57),
++     TOBN(0x3ace6df6, 0x8c2373b7), TOBN(0x75c3dffe, 0x5dbc37ac),
++     TOBN(0x3dc32a73, 0xddc925fc), TOBN(0xb679c841, 0x2f65ee0b),
++     TOBN(0x715a3295, 0x451cbfeb), TOBN(0xd9889768, 0xf76e9a29),
++     TOBN(0xec20ce7f, 0xb28ad247), TOBN(0xe99146c4, 0x00894d79),
++     TOBN(0x71457d7c, 0x9f5e3ea7), TOBN(0x097b2662, 0x38030031),
++     TOBN(0xdb7f6ae6, 0xcf9f82a8), TOBN(0x319decb9, 0x438f473a),
++     TOBN(0xa63ab386, 0x283856c3), TOBN(0x13e3172f, 0xb06a361b),
++     TOBN(0x2959f8dc, 0x7d5a006c), TOBN(0x2dbc27c6, 0x75fba752),
++     TOBN(0xc1227ab2, 0x87c22c9e), TOBN(0x06f61f75, 0x71a268b2),
++     TOBN(0x1b6bb971, 0x04779ce2), TOBN(0xaca83812, 0x0aadcb1d),
++     TOBN(0x297ae0bc, 0xaeaab2d5), TOBN(0xa5c14ee7, 0x5bfb9f13),
++     TOBN(0xaa00c583, 0xf17a62c7), TOBN(0x39eb962c, 0x173759f6),
++     TOBN(0x1eeba1d4, 0x86c9a88f), TOBN(0x0ab6c37a, 0xdf016c5e),
++     TOBN(0xa2a147db, 0xa28a0749), TOBN(0x246c20d6, 0xee519165),
++     TOBN(0x5068d1b1, 0xd3810715), TOBN(0xb1e7018c, 0x748160b9),
++     TOBN(0x03f5b1fa, 0xf380ff62), TOBN(0xef7fb1dd, 0xf3cb2c1e),
++     TOBN(0xeab539a8, 0xfc91a7da), TOBN(0x83ddb707, 0xf3f9b561),
++     TOBN(0xc550e211, 0xfe7df7a4), TOBN(0xa7cd07f2, 0x063f6f40),
++     TOBN(0xb0de3635, 0x2976879c), TOBN(0xb5f83f85, 0xe55741da),
++     TOBN(0x4ea9d25e, 0xf3d8ac3d), TOBN(0x6fe2066f, 0x62819f02),
++     TOBN(0x4ab2b9c2, 0xcef4a564), TOBN(0x1e155d96, 0x5ffa2de3),
++     TOBN(0x0eb0a19b, 0xc3a72d00), TOBN(0x4037665b, 0x8513c31b),
++     TOBN(0x2fb2b6bf, 0x04c64637), TOBN(0x45c34d6e, 0x08cdc639),
++     TOBN(0x56f1e10f, 0xf01fd796), TOBN(0x4dfb8101, 0xfe3667b8),
++     TOBN(0xe0eda253, 0x9021d0c0), TOBN(0x7a94e9ff, 0x8a06c6ab),
++     TOBN(0x2d3bb0d9, 0xbb9aa882), TOBN(0xea20e4e5, 0xec05fd10),
++     TOBN(0xed7eeb5f, 0x1a1ca64e), TOBN(0x2fa6b43c, 0xc6327cbd),
++     TOBN(0xb577e3cf, 0x3aa91121), TOBN(0x8c6bd5ea, 0x3a34079b),
++     TOBN(0xd7e5ba39, 0x60e02fc0), TOBN(0xf16dd2c3, 0x90141bf8),
++     TOBN(0xb57276d9, 0x80101b98), TOBN(0x760883fd, 0xb82f0f66),
++     TOBN(0x89d7de75, 0x4bc3eff3), TOBN(0x03b60643, 0x5dc2ab40),
++     TOBN(0xcd6e53df, 0xe05beeac), TOBN(0xf2f1e862, 0xbc3325cd),
++     TOBN(0xdd0f7921, 0x774f03c3), TOBN(0x97ca7221, 0x4552cc1b),
++     TOBN(0x5a0d6afe, 0x1cd19f72), TOBN(0xa20915dc, 0xf183fbeb),
++     TOBN(0x9fda4b40, 0x832c403c), TOBN(0x32738edd, 0xbe425442),
++     TOBN(0x469a1df6, 0xb5eccf1a), TOBN(0x4b5aff42, 0x28bbe1f0),
++     TOBN(0x31359d7f, 0x570dfc93), TOBN(0xa18be235, 0xf0088628),
++     TOBN(0xa5b30fba, 0xb00ed3a9), TOBN(0x34c61374, 0x73cdf8be),
++     TOBN(0x2c5c5f46, 0xabc56797), TOBN(0x5cecf93d, 0xb82a8ae2),
++     TOBN(0x7d3dbe41, 0xa968fbf0), TOBN(0xd23d4583, 0x1a5c7f3d),
++     TOBN(0xf28f69a0, 0xc087a9c7), TOBN(0xc2d75471, 0x474471ca),
++     TOBN(0x36ec9f4a, 0x4eb732ec), TOBN(0x6c943bbd, 0xb1ca6bed),
++     TOBN(0xd64535e1, 0xf2457892), TOBN(0x8b84a8ea, 0xf7e2ac06),
++     TOBN(0xe0936cd3, 0x2499dd5f), TOBN(0x12053d7e, 0x0ed04e57),
++     TOBN(0x4bdd0076, 0xe4305d9d), TOBN(0x34a527b9, 0x1f67f0a2),
++     TOBN(0xe79a4af0, 0x9cec46ea), TOBN(0xb15347a1, 0x658b9bc7),
++     TOBN(0x6bd2796f, 0x35af2f75), TOBN(0xac957990, 0x4051c435),
++     TOBN(0x2669dda3, 0xc33a655d), TOBN(0x5d503c2e, 0x88514aa3),
++     TOBN(0xdfa11337, 0x3753dd41), TOBN(0x3f054673, 0x0b754f78),
++     TOBN(0xbf185677, 0x496125bd), TOBN(0xfb0023c8, 0x3775006c),
++     TOBN(0xfa0f072f, 0x3a037899), TOBN(0x4222b6eb, 0x0e4aea57),
++     TOBN(0x3dde5e76, 0x7866d25a), TOBN(0xb6eb04f8, 0x4837aa6f),
++     TOBN(0x5315591a, 0x2cf1cdb8), TOBN(0x6dfb4f41, 0x2d4e683c),
++     TOBN(0x7e923ea4, 0x48ee1f3a), TOBN(0x9604d9f7, 0x05a2afd5),
++     TOBN(0xbe1d4a33, 0x40ea4948), TOBN(0x5b45f1f4, 0xb44cbd2f),
++     TOBN(0x5faf8376, 0x4acc757e), TOBN(0xa7cf9ab8, 0x63d68ff7),
++     TOBN(0x8ad62f69, 0xdf0e404b), TOBN(0xd65f33c2, 0x12bdafdf),
++     TOBN(0xc365de15, 0xa377b14e), TOBN(0x6bf5463b, 0x8e39f60c),
++     TOBN(0x62030d2d, 0x2ce68148), TOBN(0xd95867ef, 0xe6f843a8),
++     TOBN(0xd39a0244, 0xef5ab017), TOBN(0x0bd2d8c1, 0x4ab55d12),
++     TOBN(0xc9503db3, 0x41639169), TOBN(0x2d4e25b0, 0xf7660c8a),
++     TOBN(0x760cb3b5, 0xe224c5d7), TOBN(0xfa3baf8c, 0x68616919),
++     TOBN(0x9fbca113, 0x8d142552), TOBN(0x1ab18bf1, 0x7669ebf5),
++     TOBN(0x55e6f53e, 0x9bdf25dd), TOBN(0x04cc0bf3, 0xcb6cd154),
++     TOBN(0x595bef49, 0x95e89080), TOBN(0xfe9459a8, 0x104a9ac1),
++     TOBN(0xad2d89ca, 0xcce9bb32), TOBN(0xddea65e1, 0xf7de8285),
++     TOBN(0x62ed8c35, 0xb351bd4b), TOBN(0x4150ff36, 0x0c0e19a7),
++     TOBN(0x86e3c801, 0x345f4e47), TOBN(0x3bf21f71, 0x203a266c),
++     TOBN(0x7ae110d4, 0x855b1f13), TOBN(0x5d6aaf6a, 0x07262517),
++     TOBN(0x1e0f12e1, 0x813d28f1), TOBN(0x6000e11d, 0x7ad7a523),
++     TOBN(0xc7d8deef, 0xc744a17b), TOBN(0x1e990b48, 0x14c05a00),
++     TOBN(0x68fddaee, 0x93e976d5), TOBN(0x696241d1, 0x46610d63),
++     TOBN(0xb204e7c3, 0x893dda88), TOBN(0x8bccfa65, 0x6a3a6946),
++     TOBN(0xb59425b4, 0xc5cd1411), TOBN(0x701b4042, 0xff3658b1),
++     TOBN(0xe3e56bca, 0x4784cf93), TOBN(0x27de5f15, 0x8fe68d60),
++     TOBN(0x4ab9cfce, 0xf8d53f19), TOBN(0xddb10311, 0xa40a730d),
++     TOBN(0x6fa73cd1, 0x4eee0a8a), TOBN(0xfd548748, 0x5249719d),
++     TOBN(0x49d66316, 0xa8123ef0), TOBN(0x73c32db4, 0xe7f95438),
++     TOBN(0x2e2ed209, 0x0d9e7854), TOBN(0xf98a9329, 0x9d9f0507),
++     TOBN(0xc5d33cf6, 0x0c6aa20a), TOBN(0x9a32ba14, 0x75279bb2),
++     TOBN(0x7e3202cb, 0x774a7307), TOBN(0x64ed4bc4, 0xe8c42dbd),
++     TOBN(0xc20f1a06, 0xd4caed0d), TOBN(0xb8021407, 0x171d22b3),
++     TOBN(0xd426ca04, 0xd13268d7), TOBN(0x92377007, 0x25f4d126),
++     TOBN(0x4204cbc3, 0x71f21a85), TOBN(0x18461b7a, 0xf82369ba),
++     TOBN(0xc0c07d31, 0x3fc858f9), TOBN(0x5deb5a50, 0xe2bab569),
++     TOBN(0xd5959d46, 0xd5eea89e), TOBN(0xfdff8424, 0x08437f4b),
++     TOBN(0xf21071e4, 0x3cfe254f), TOBN(0x72417696, 0x95468321),
++     TOBN(0x5d8288b9, 0x102cae3e), TOBN(0x2d143e3d, 0xf1965dff),
++     TOBN(0x00c9a376, 0xa078d847), TOBN(0x6fc0da31, 0x26028731),
++     TOBN(0xa2baeadf, 0xe45083a2), TOBN(0x66bc7218, 0x5e5b4bcd),
++     TOBN(0x2c826442, 0xd04b8e7f), TOBN(0xc19f5451, 0x6c4b586b),
++     TOBN(0x60182c49, 0x5b7eeed5), TOBN(0xd9954ecd, 0x7aa9dfa1),
++     TOBN(0xa403a8ec, 0xc73884ad), TOBN(0x7fb17de2, 0x9bb39041),
++     TOBN(0x694b64c5, 0xabb020e8), TOBN(0x3d18c184, 0x19c4eec7),
++     TOBN(0x9c4673ef, 0x1c4793e5), TOBN(0xc7b8aeb5, 0x056092e6),
++     TOBN(0x3aa1ca43, 0xf0f8c16b), TOBN(0x224ed5ec, 0xd679b2f6),
++     TOBN(0x0d56eeaf, 0x55a205c9), TOBN(0xbfe115ba, 0x4b8e028b),
++     TOBN(0x97e60849, 0x3927f4fe), TOBN(0xf91fbf94, 0x759aa7c5),
++     TOBN(0x985af769, 0x6be90a51), TOBN(0xc1277b78, 0x78ccb823),
++     TOBN(0x395b656e, 0xe7a75952), TOBN(0x00df7de0, 0x928da5f5),
++     TOBN(0x09c23175, 0x4ca4454f), TOBN(0x4ec971f4, 0x7aa2d3c1),
++     TOBN(0x45c3c507, 0xe75d9ccc), TOBN(0x63b7be8a, 0x3dc90306),
++     TOBN(0x37e09c66, 0x5db44bdc), TOBN(0x50d60da1, 0x6841c6a2),
++     TOBN(0x6f9b65ee, 0x08df1b12), TOBN(0x38734879, 0x7ff089df),
++     TOBN(0x9c331a66, 0x3fe8013d), TOBN(0x017f5de9, 0x5f42fcc8),
++     TOBN(0x43077866, 0xe8e57567), TOBN(0xc9f781ce, 0xf9fcdb18),
++     TOBN(0x38131dda, 0x9b12e174), TOBN(0x25d84aa3, 0x8a03752a),
++     TOBN(0x45e09e09, 0x4d0c0ce2), TOBN(0x1564008b, 0x92bebba5),
++     TOBN(0xf7e8ad31, 0xa87284c7), TOBN(0xb7c4b46c, 0x97e7bbaa),
++     TOBN(0x3e22a7b3, 0x97acf4ec), TOBN(0x0426c400, 0x5ea8b640),
++     TOBN(0x5e3295a6, 0x4e969285), TOBN(0x22aabc59, 0xa6a45670),
++     TOBN(0xb929714c, 0x5f5942bc), TOBN(0x9a6168bd, 0xfa3182ed),
++     TOBN(0x2216a665, 0x104152ba), TOBN(0x46908d03, 0xb6926368)}
++    ,
++    {TOBN(0xa9f5d874, 0x5a1251fb), TOBN(0x967747a8, 0xc72725c7),
++     TOBN(0x195c33e5, 0x31ffe89e), TOBN(0x609d210f, 0xe964935e),
++     TOBN(0xcafd6ca8, 0x2fe12227), TOBN(0xaf9b5b96, 0x0426469d),
++     TOBN(0x2e9ee04c, 0x5693183c), TOBN(0x1084a333, 0xc8146fef),
++     TOBN(0x96649933, 0xaed1d1f7), TOBN(0x566eaff3, 0x50563090),
++     TOBN(0x345057f0, 0xad2e39cf), TOBN(0x148ff65b, 0x1f832124),
++     TOBN(0x042e89d4, 0xcf94cf0d), TOBN(0x319bec84, 0x520c58b3),
++     TOBN(0x2a267626, 0x5361aa0d), TOBN(0xc86fa302, 0x8fbc87ad),
++     TOBN(0xfc83d2ab, 0x5c8b06d5), TOBN(0xb1a785a2, 0xfe4eac46),
++     TOBN(0xb99315bc, 0x846f7779), TOBN(0xcf31d816, 0xef9ea505),
++     TOBN(0x2391fe6a, 0x15d7dc85), TOBN(0x2f132b04, 0xb4016b33),
++     TOBN(0x29547fe3, 0x181cb4c7), TOBN(0xdb66d8a6, 0x650155a1),
++     TOBN(0x6b66d7e1, 0xadc1696f), TOBN(0x98ebe593, 0x0acd72d0),
++     TOBN(0x65f24550, 0xcc1b7435), TOBN(0xce231393, 0xb4b9a5ec),
++     TOBN(0x234a22d4, 0xdb067df9), TOBN(0x98dda095, 0xcaff9b00),
++     TOBN(0x1bbc75a0, 0x6100c9c1), TOBN(0x1560a9c8, 0x939cf695),
++     TOBN(0xcf006d3e, 0x99e0925f), TOBN(0x2dd74a96, 0x6322375a),
++     TOBN(0xc58b446a, 0xb56af5ba), TOBN(0x50292683, 0xe0b9b4f1),
++     TOBN(0xe2c34cb4, 0x1aeaffa3), TOBN(0x8b17203f, 0x9b9587c1),
++     TOBN(0x6d559207, 0xead1350c), TOBN(0x2b66a215, 0xfb7f9604),
++     TOBN(0x0850325e, 0xfe51bf74), TOBN(0x9c4f579e, 0x5e460094),
++     TOBN(0x5c87b92a, 0x76da2f25), TOBN(0x889de4e0, 0x6febef33),
++     TOBN(0x6900ec06, 0x646083ce), TOBN(0xbe2a0335, 0xbfe12773),
++     TOBN(0xadd1da35, 0xc5344110), TOBN(0x757568b7, 0xb802cd20),
++     TOBN(0x75559779, 0x00f7e6c8), TOBN(0x38e8b94f, 0x0facd2f0),
++     TOBN(0xfea1f3af, 0x03fde375), TOBN(0x5e11a1d8, 0x75881dfc),
++     TOBN(0xb3a6b02e, 0xc1e2f2ef), TOBN(0x193d2bbb, 0xc605a6c5),
++     TOBN(0x325ffeee, 0x339a0b2d), TOBN(0x27b6a724, 0x9e0c8846),
++     TOBN(0xe4050f1c, 0xf1c367ca), TOBN(0x9bc85a9b, 0xc90fbc7d),
++     TOBN(0xa373c4a2, 0xe1a11032), TOBN(0xb64232b7, 0xad0393a9),
++     TOBN(0xf5577eb0, 0x167dad29), TOBN(0x1604f301, 0x94b78ab2),
++     TOBN(0x0baa94af, 0xe829348b), TOBN(0x77fbd8dd, 0x41654342),
++     TOBN(0xdab50ea5, 0xb964e39a), TOBN(0xd4c29e3c, 0xd0d3c76e),
++     TOBN(0x80dae67c, 0x56d11964), TOBN(0x7307a8bf, 0xe5ffcc2f),
++     TOBN(0x65bbc1aa, 0x91708c3b), TOBN(0xa151e62c, 0x28bf0eeb),
++     TOBN(0x6cb53381, 0x6fa34db7), TOBN(0x5139e05c, 0xa29403a8),
++     TOBN(0x6ff651b4, 0x94a7cd2e), TOBN(0x5671ffd1, 0x0699336c),
++     TOBN(0x6f5fd2cc, 0x979a896a), TOBN(0x11e893a8, 0xd8148cef),
++     TOBN(0x988906a1, 0x65cf7b10), TOBN(0x81b67178, 0xc50d8485),
++     TOBN(0x7c0deb35, 0x8a35b3de), TOBN(0x423ac855, 0xc1d29799),
++     TOBN(0xaf580d87, 0xdac50b74), TOBN(0x28b2b89f, 0x5869734c),
++     TOBN(0x99a3b936, 0x874e28fb), TOBN(0xbb2c9190, 0x25f3f73a),
++     TOBN(0x199f6918, 0x84a9d5b7), TOBN(0x7ebe2325, 0x7e770374),
++     TOBN(0xf442e107, 0x0738efe2), TOBN(0xcf9f3f56, 0xcf9082d2),
++     TOBN(0x719f69e1, 0x09618708), TOBN(0xcc9e8364, 0xc183f9b1),
++     TOBN(0xec203a95, 0x366a21af), TOBN(0x6aec5d6d, 0x068b141f),
++     TOBN(0xee2df78a, 0x994f04e9), TOBN(0xb39ccae8, 0x271245b0),
++     TOBN(0xb875a4a9, 0x97e43f4f), TOBN(0x507dfe11, 0xdb2cea98),
++     TOBN(0x4fbf81cb, 0x489b03e9), TOBN(0xdb86ec5b, 0x6ec414fa),
++     TOBN(0xfad444f9, 0xf51b3ae5), TOBN(0xca7d33d6, 0x1914e3fe),
++     TOBN(0xa9c32f5c, 0x0ae6c4d0), TOBN(0xa9ca1d1e, 0x73969568),
++     TOBN(0x98043c31, 0x1aa7467e), TOBN(0xe832e75c, 0xe21b5ac6),
++     TOBN(0x314b7aea, 0x5232123d), TOBN(0x08307c8c, 0x65ae86db),
++     TOBN(0x06e7165c, 0xaa4668ed), TOBN(0xb170458b, 0xb4d3ec39),
++     TOBN(0x4d2e3ec6, 0xc19bb986), TOBN(0xc5f34846, 0xae0304ed),
++     TOBN(0x917695a0, 0x6c9f9722), TOBN(0x6c7f7317, 0x4cab1c0a),
++     TOBN(0x6295940e, 0x9d6d2e8b), TOBN(0xd318b8c1, 0x549f7c97),
++     TOBN(0x22453204, 0x97713885), TOBN(0x468d834b, 0xa8a440fe),
++     TOBN(0xd81fe5b2, 0xbfba796e), TOBN(0x152364db, 0x6d71f116),
++     TOBN(0xbb8c7c59, 0xb5b66e53), TOBN(0x0b12c61b, 0x2641a192),
++     TOBN(0x31f14802, 0xfcf0a7fd), TOBN(0x42fd0789, 0x5488b01e),
++     TOBN(0x71d78d6d, 0x9952b498), TOBN(0x8eb572d9, 0x07ac5201),
++     TOBN(0xe0a2a44c, 0x4d194a88), TOBN(0xd2b63fd9, 0xba017e66),
++     TOBN(0x78efc6c8, 0xf888aefc), TOBN(0xb76f6bda, 0x4a881a11),
++     TOBN(0x187f314b, 0xb46c2397), TOBN(0x004cf566, 0x5ded2819),
++     TOBN(0xa9ea5704, 0x38764d34), TOBN(0xbba45217, 0x78084709),
++     TOBN(0x06474571, 0x1171121e), TOBN(0xad7b7eb1, 0xe7c9b671),
++     TOBN(0xdacfbc40, 0x730f7507), TOBN(0x178cd8c6, 0xc7ad7bd1),
++     TOBN(0xbf0be101, 0xb2a67238), TOBN(0x3556d367, 0xaf9c14f2),
++     TOBN(0x104b7831, 0xa5662075), TOBN(0x58ca59bb, 0x79d9e60a),
++     TOBN(0x4bc45392, 0xa569a73b), TOBN(0x517a52e8, 0x5698f6c9),
++     TOBN(0x85643da5, 0xaeadd755), TOBN(0x1aed0cd5, 0x2a581b84),
++     TOBN(0xb9b4ff84, 0x80af1372), TOBN(0x244c3113, 0xf1ba5d1f),
++     TOBN(0x2a5dacbe, 0xf5f98d31), TOBN(0x2c3323e8, 0x4375bc2a),
++     TOBN(0x17a3ab4a, 0x5594b1dd), TOBN(0xa1928bfb, 0xceb4797e),
++     TOBN(0xe83af245, 0xe4886a19), TOBN(0x8979d546, 0x72b5a74a),
++     TOBN(0xa0f726bc, 0x19f9e967), TOBN(0xd9d03152, 0xe8fbbf4e),
++     TOBN(0xcfd6f51d, 0xb7707d40), TOBN(0x633084d9, 0x63f6e6e0),
++     TOBN(0xedcd9cdc, 0x55667eaf), TOBN(0x73b7f92b, 0x2e44d56f),
++     TOBN(0xfb2e39b6, 0x4e962b14), TOBN(0x7d408f6e, 0xf671fcbf),
++     TOBN(0xcc634ddc, 0x164a89bb), TOBN(0x74a42bb2, 0x3ef3bd05),
++     TOBN(0x1280dbb2, 0x428decbb), TOBN(0x6103f6bb, 0x402c8596),
++     TOBN(0xfa2bf581, 0x355a5752), TOBN(0x562f96a8, 0x00946674),
++     TOBN(0x4e4ca16d, 0x6da0223b), TOBN(0xfe47819f, 0x28d3aa25),
++     TOBN(0x9eea3075, 0xf8dfcf8a), TOBN(0xa284f0aa, 0x95669825),
++     TOBN(0xb3fca250, 0x867d3fd8), TOBN(0x20757b5f, 0x269d691e),
++     TOBN(0xf2c24020, 0x93b8a5de), TOBN(0xd3f93359, 0xebc06da6),
++     TOBN(0x1178293e, 0xb2739c33), TOBN(0xd2a3e770, 0xbcd686e5),
++     TOBN(0xa76f49f4, 0xcd941534), TOBN(0x0d37406b, 0xe3c71c0e),
++     TOBN(0x172d9397, 0x3b97f7e3), TOBN(0xec17e239, 0xbd7fd0de),
++     TOBN(0xe3290551, 0x6f496ba2), TOBN(0x6a693172, 0x36ad50e7),
++     TOBN(0xc4e539a2, 0x83e7eff5), TOBN(0x752737e7, 0x18e1b4cf),
++     TOBN(0xa2f7932c, 0x68af43ee), TOBN(0x5502468e, 0x703d00bd),
++     TOBN(0xe5dc978f, 0x2fb061f5), TOBN(0xc9a1904a, 0x28c815ad),
++     TOBN(0xd3af538d, 0x470c56a4), TOBN(0x159abc5f, 0x193d8ced),
++     TOBN(0x2a37245f, 0x20108ef3), TOBN(0xfa17081e, 0x223f7178),
++     TOBN(0x27b0fb2b, 0x10c8c0f5), TOBN(0x2102c3ea, 0x40650547),
++     TOBN(0x594564df, 0x8ac3bfa7), TOBN(0x98102033, 0x509dad96),
++     TOBN(0x6989643f, 0xf1d18a13), TOBN(0x35eebd91, 0xd7fc5af0),
++     TOBN(0x078d096a, 0xfaeaafd8), TOBN(0xb7a89341, 0xdef3de98),
++     TOBN(0x2a206e8d, 0xecf2a73a), TOBN(0x066a6397, 0x8e551994),
++     TOBN(0x3a6a088a, 0xb98d53a2), TOBN(0x0ce7c67c, 0x2d1124aa),
++     TOBN(0x48cec671, 0x759a113c), TOBN(0xe3b373d3, 0x4f6f67fa),
++     TOBN(0x5455d479, 0xfd36727b), TOBN(0xe5a428ee, 0xa13c0d81),
++     TOBN(0xb853dbc8, 0x1c86682b), TOBN(0xb78d2727, 0xb8d02b2a),
++     TOBN(0xaaf69bed, 0x8ebc329a), TOBN(0xdb6b40b3, 0x293b2148),
++     TOBN(0xe42ea77d, 0xb8c4961f), TOBN(0xb1a12f7c, 0x20e5e0ab),
++     TOBN(0xa0ec5274, 0x79e8b05e), TOBN(0x68027391, 0xfab60a80),
++     TOBN(0x6bfeea5f, 0x16b1bd5e), TOBN(0xf957e420, 0x4de30ad3),
++     TOBN(0xcbaf664e, 0x6a353b9e), TOBN(0x5c873312, 0x26d14feb),
++     TOBN(0x4e87f98c, 0xb65f57cb), TOBN(0xdb60a621, 0x5e0cdd41),
++     TOBN(0x67c16865, 0xa6881440), TOBN(0x1093ef1a, 0x46ab52aa),
++     TOBN(0xc095afb5, 0x3f4ece64), TOBN(0x6a6bb02e, 0x7604551a),
++     TOBN(0x55d44b4e, 0x0b26b8cd), TOBN(0xe5f9a999, 0xf971268a),
++     TOBN(0xc08ec425, 0x11a7de84), TOBN(0x83568095, 0xfda469dd),
++     TOBN(0x737bfba1, 0x6c6c90a2), TOBN(0x1cb9c4a0, 0xbe229831),
++     TOBN(0x93bccbba, 0xbb2eec64), TOBN(0xa0c23b64, 0xda03adbe),
++     TOBN(0x5f7aa00a, 0xe0e86ac4), TOBN(0x470b941e, 0xfc1401e6),
++     TOBN(0x5ad8d679, 0x9df43574), TOBN(0x4ccfb8a9, 0x0f65d810),
++     TOBN(0x1bce80e3, 0xaa7fbd81), TOBN(0x273291ad, 0x9508d20a),
++     TOBN(0xf5c4b46b, 0x42a92806), TOBN(0x810684ec, 0xa86ab44a),
++     TOBN(0x4591640b, 0xca0bc9f8), TOBN(0xb5efcdfc, 0x5c4b6054),
++     TOBN(0x16fc8907, 0x6e9edd12), TOBN(0xe29d0b50, 0xd4d792f9),
++     TOBN(0xa45fd01c, 0x9b03116d), TOBN(0x85035235, 0xc81765a4),
++     TOBN(0x1fe2a9b2, 0xb4b4b67c), TOBN(0xc1d10df0, 0xe8020604),
++     TOBN(0x9d64abfc, 0xbc8058d8), TOBN(0x8943b9b2, 0x712a0fbb),
++     TOBN(0x90eed914, 0x3b3def04), TOBN(0x85ab3aa2, 0x4ce775ff),
++     TOBN(0x605fd4ca, 0x7bbc9040), TOBN(0x8b34a564, 0xe2c75dfb),
++     TOBN(0x41ffc94a, 0x10358560), TOBN(0x2d8a5072, 0x9e5c28aa),
++     TOBN(0xe915a0fc, 0x4cc7eb15), TOBN(0xe9efab05, 0x8f6d0f5d),
++     TOBN(0xdbab47a9, 0xd19e9b91), TOBN(0x8cfed745, 0x0276154c),
++     TOBN(0x154357ae, 0x2cfede0d), TOBN(0x520630df, 0x19f5a4ef),
++     TOBN(0x25759f7c, 0xe382360f), TOBN(0xb6db05c9, 0x88bf5857),
++     TOBN(0x2917d61d, 0x6c58d46c), TOBN(0x14f8e491, 0xfd20cb7a),
++     TOBN(0xb68a727a, 0x11c20340), TOBN(0x0386f86f, 0xaf7ccbb6),
++     TOBN(0x5c8bc6cc, 0xfee09a20), TOBN(0x7d76ff4a, 0xbb7eea35),
++     TOBN(0xa7bdebe7, 0xdb15be7a), TOBN(0x67a08054, 0xd89f0302),
++     TOBN(0x56bf0ea9, 0xc1193364), TOBN(0xc8244467, 0x62837ebe),
++     TOBN(0x32bd8e8b, 0x20d841b8), TOBN(0x127a0548, 0xdbb8a54f),
++     TOBN(0x83dd4ca6, 0x63b20236), TOBN(0x87714718, 0x203491fa),
++     TOBN(0x4dabcaaa, 0xaa8a5288), TOBN(0x91cc0c8a, 0xaf23a1c9),
++     TOBN(0x34c72c6a, 0x3f220e0c), TOBN(0xbcc20bdf, 0x1232144a),
++     TOBN(0x6e2f42da, 0xa20ede1b), TOBN(0xc441f00c, 0x74a00515),
++     TOBN(0xbf46a5b6, 0x734b8c4b), TOBN(0x57409503, 0x7b56c9a4),
++     TOBN(0x9f735261, 0xe4585d45), TOBN(0x9231faed, 0x6734e642),
++     TOBN(0x1158a176, 0xbe70ee6c), TOBN(0x35f1068d, 0x7c3501bf),
++     TOBN(0x6beef900, 0xa2d26115), TOBN(0x649406f2, 0xef0afee3),
++     TOBN(0x3f43a60a, 0xbc2420a1), TOBN(0x509002a7, 0xd5aee4ac),
++     TOBN(0xb46836a5, 0x3ff3571b), TOBN(0x24f98b78, 0x837927c1),
++     TOBN(0x6254256a, 0x4533c716), TOBN(0xf27abb0b, 0xd07ee196),
++     TOBN(0xd7cf64fc, 0x5c6d5bfd), TOBN(0x6915c751, 0xf0cd7a77),
++     TOBN(0xd9f59012, 0x8798f534), TOBN(0x772b0da8, 0xf81d8b5f),
++     TOBN(0x1244260c, 0x2e03fa69), TOBN(0x36cf0e3a, 0x3be1a374),
++     TOBN(0x6e7c1633, 0xef06b960), TOBN(0xa71a4c55, 0x671f90f6),
++     TOBN(0x7a941251, 0x33c673db), TOBN(0xc0bea510, 0x73e8c131),
++     TOBN(0x61a8a699, 0xd4f6c734), TOBN(0x25e78c88, 0x341ed001),
++     TOBN(0x5c18acf8, 0x8e2f7d90), TOBN(0xfdbf33d7, 0x77be32cd),
++     TOBN(0x0a085cd7, 0xd2eb5ee9), TOBN(0x2d702cfb, 0xb3201115),
++     TOBN(0xb6e0ebdb, 0x85c88ce8), TOBN(0x23a3ce3c, 0x1e01d617),
++     TOBN(0x3041618e, 0x567333ac), TOBN(0x9dd0fd8f, 0x157edb6b),
++     TOBN(0x27f74702, 0xb57872b8), TOBN(0x2ef26b4f, 0x657d5fe1),
++     TOBN(0x95426f0a, 0x57cf3d40), TOBN(0x847e2ad1, 0x65a6067a),
++     TOBN(0xd474d9a0, 0x09996a74), TOBN(0x16a56acd, 0x2a26115c),
++     TOBN(0x02a615c3, 0xd16f4d43), TOBN(0xcc3fc965, 0xaadb85b7),
++     TOBN(0x386bda73, 0xce07d1b0), TOBN(0xd82910c2, 0x58ad4178),
++     TOBN(0x124f82cf, 0xcd2617f4), TOBN(0xcc2f5e8d, 0xef691770),
++     TOBN(0x82702550, 0xb8c30ccc), TOBN(0x7b856aea, 0x1a8e575a),
++     TOBN(0xbb822fef, 0xb1ab9459), TOBN(0x085928bc, 0xec24e38e),
++     TOBN(0x5d0402ec, 0xba8f4b4d), TOBN(0xc07cd4ba, 0x00b4d58b),
++     TOBN(0x5d8dffd5, 0x29227e7a), TOBN(0x61d44d0c, 0x31bf386f),
++     TOBN(0xe486dc2b, 0x135e6f4d), TOBN(0x680962eb, 0xe79410ef),
++     TOBN(0xa61bd343, 0xf10088b5), TOBN(0x6aa76076, 0xe2e28686),
++     TOBN(0x80463d11, 0x8fb98871), TOBN(0xcb26f5c3, 0xbbc76aff),
++     TOBN(0xd4ab8edd, 0xfbe03614), TOBN(0xc8eb579b, 0xc0cf2dee),
++     TOBN(0xcc004c15, 0xc93bae41), TOBN(0x46fbae5d, 0x3aeca3b2),
++     TOBN(0x671235cf, 0x0f1e9ab1), TOBN(0xadfba934, 0x9ec285c1),
++     TOBN(0x88ded013, 0xf216c980), TOBN(0xc8ac4fb8, 0xf79e0bc1),
++     TOBN(0xa29b89c6, 0xfb97a237), TOBN(0xb697b780, 0x9922d8e7),
++     TOBN(0x3142c639, 0xddb945b5), TOBN(0x447b06c7, 0xe094c3a9),
++     TOBN(0xcdcb3642, 0x72266c90), TOBN(0x633aad08, 0xa9385046),
++     TOBN(0xa36c936b, 0xb57c6477), TOBN(0x871f8b64, 0xe94dbcc6),
++     TOBN(0x28d0fb62, 0xa591a67b), TOBN(0x9d40e081, 0xc1d926f5),
++     TOBN(0x3111eaf6, 0xf2d84b5a), TOBN(0x228993f9, 0xa565b644),
++     TOBN(0x0ccbf592, 0x2c83188b), TOBN(0xf87b30ab, 0x3df3e197),
++     TOBN(0xb8658b31, 0x7642bca8), TOBN(0x1a032d7f, 0x52800f17),
++     TOBN(0x051dcae5, 0x79bf9445), TOBN(0xeba6b8ee, 0x54a2e253),
++     TOBN(0x5c8b9cad, 0xd4485692), TOBN(0x84bda40e, 0x8986e9be),
++     TOBN(0xd16d16a4, 0x2f0db448), TOBN(0x8ec80050, 0xa14d4188),
++     TOBN(0xb2b26107, 0x98fa7aaa), TOBN(0x41209ee4, 0xf073aa4e),
++     TOBN(0xf1570359, 0xf2d6b19b), TOBN(0xcbe6868c, 0xfc577caf),
++     TOBN(0x186c4bdc, 0x32c04dd3), TOBN(0xa6c35fae, 0xcfeee397),
++     TOBN(0xb4a1b312, 0xf086c0cf), TOBN(0xe0a5ccc6, 0xd9461fe2),
++     TOBN(0xc32278aa, 0x1536189f), TOBN(0x1126c55f, 0xba6df571),
++     TOBN(0x0f71a602, 0xb194560e), TOBN(0x8b2d7405, 0x324bd6e1),
++     TOBN(0x8481939e, 0x3738be71), TOBN(0xb5090b1a, 0x1a4d97a9),
++     TOBN(0x116c65a3, 0xf05ba915), TOBN(0x21863ad3, 0xaae448aa),
++     TOBN(0xd24e2679, 0xa7aae5d3), TOBN(0x7076013d, 0x0de5c1c4),
++     TOBN(0x2d50f8ba, 0xbb05b629), TOBN(0x73c1abe2, 0x6e66efbb),
++     TOBN(0xefd4b422, 0xf2488af7), TOBN(0xe4105d02, 0x663ba575),
++     TOBN(0x7eb60a8b, 0x53a69457), TOBN(0x62210008, 0xc945973b),
++     TOBN(0xfb255478, 0x77a50ec6), TOBN(0xbf0392f7, 0x0a37a72c),
++     TOBN(0xa0a7a19c, 0x4be18e7a), TOBN(0x90d8ea16, 0x25b1e0af),
++     TOBN(0x7582a293, 0xef953f57), TOBN(0x90a64d05, 0xbdc5465a),
++     TOBN(0xca79c497, 0xe2510717), TOBN(0x560dbb7c, 0x18cb641f),
++     TOBN(0x1d8e3286, 0x4b66abfb), TOBN(0xd26f52e5, 0x59030900),
++     TOBN(0x1ee3f643, 0x5584941a), TOBN(0x6d3b3730, 0x569f5958),
++     TOBN(0x9ff2a62f, 0x4789dba5), TOBN(0x91fcb815, 0x72b5c9b7),
++     TOBN(0xf446cb7d, 0x6c8f9a0e), TOBN(0x48f625c1, 0x39b7ecb5),
++     TOBN(0xbabae801, 0x1c6219b8), TOBN(0xe7a562d9, 0x28ac2f23),
++     TOBN(0xe1b48732, 0x26e20588), TOBN(0x06ee1cad, 0x775af051),
++     TOBN(0xda29ae43, 0xfaff79f7), TOBN(0xc141a412, 0x652ee9e0),
++     TOBN(0x1e127f6f, 0x195f4bd0), TOBN(0x29c6ab4f, 0x072f34f8),
++     TOBN(0x7b7c1477, 0x30448112), TOBN(0x82b51af1, 0xe4a38656),
++     TOBN(0x2bf2028a, 0x2f315010), TOBN(0xc9a4a01f, 0x6ea88cd4),
++     TOBN(0xf63e95d8, 0x257e5818), TOBN(0xdd8efa10, 0xb4519b16),
++     TOBN(0xed8973e0, 0x0da910bf), TOBN(0xed49d077, 0x5c0fe4a9),
++     TOBN(0xac3aac5e, 0xb7caee1e), TOBN(0x1033898d, 0xa7f4da57),
++     TOBN(0x42145c0e, 0x5c6669b9), TOBN(0x42daa688, 0xc1aa2aa0),
++     TOBN(0x629cc15c, 0x1a1d885a), TOBN(0x25572ec0, 0xf4b76817),
++     TOBN(0x8312e435, 0x9c8f8f28), TOBN(0x8107f8cd, 0x81965490),
++     TOBN(0x516ff3a3, 0x6fa6110c), TOBN(0x74fb1eb1, 0xfb93561f),
++     TOBN(0x6c0c9047, 0x8457522b), TOBN(0xcfd32104, 0x6bb8bdc6),
++     TOBN(0x2d6884a2, 0xcc80ad57), TOBN(0x7c27fc35, 0x86a9b637),
++     TOBN(0x3461baed, 0xadf4e8cd), TOBN(0x1d56251a, 0x617242f0),
++     TOBN(0x0b80d209, 0xc955bef4), TOBN(0xdf02cad2, 0x06adb047),
++     TOBN(0xf0d7cb91, 0x5ec74fee), TOBN(0xd2503375, 0x1111ba44),
++     TOBN(0x9671755e, 0xdf53cb36), TOBN(0x54dcb612, 0x3368551b),
++     TOBN(0x66d69aac, 0xc8a025a4), TOBN(0x6be946c6, 0xe77ef445),
++     TOBN(0x719946d1, 0xa995e094), TOBN(0x65e848f6, 0xe51e04d8),
++     TOBN(0xe62f3300, 0x6a1e3113), TOBN(0x1541c7c1, 0x501de503),
++     TOBN(0x4daac9fa, 0xf4acfade), TOBN(0x0e585897, 0x44cd0b71),
++     TOBN(0x544fd869, 0x0a51cd77), TOBN(0x60fc20ed, 0x0031016d),
++     TOBN(0x58b404ec, 0xa4276867), TOBN(0x46f6c3cc, 0x34f34993),
++     TOBN(0x477ca007, 0xc636e5bd), TOBN(0x8018f5e5, 0x7c458b47),
++     TOBN(0xa1202270, 0xe47b668f), TOBN(0xcef48ccd, 0xee14f203),
++     TOBN(0x23f98bae, 0x62ff9b4d), TOBN(0x55acc035, 0xc589eddd),
++     TOBN(0x3fe712af, 0x64db4444), TOBN(0x19e9d634, 0xbecdd480),
++     TOBN(0xe08bc047, 0xa930978a), TOBN(0x2dbf24ec, 0xa1280733),
++     TOBN(0x3c0ae38c, 0x2cd706b2), TOBN(0x5b012a5b, 0x359017b9),
++     TOBN(0x3943c38c, 0x72e0f5ae), TOBN(0x786167ea, 0x57176fa3),
++     TOBN(0xe5f9897d, 0x594881dc), TOBN(0x6b5efad8, 0xcfb820c1),
++     TOBN(0xb2179093, 0xd55018de), TOBN(0x39ad7d32, 0x0bac56ce),
++     TOBN(0xb55122e0, 0x2cfc0e81), TOBN(0x117c4661, 0xf6d89daa),
++     TOBN(0x362d01e1, 0xcb64fa09), TOBN(0x6a309b4e, 0x3e9c4ddd),
++     TOBN(0xfa979fb7, 0xabea49b1), TOBN(0xb4b1d27d, 0x10e2c6c5),
++     TOBN(0xbd61c2c4, 0x23afde7a), TOBN(0xeb6614f8, 0x9786d358),
++     TOBN(0x4a5d816b, 0x7f6f7459), TOBN(0xe431a44f, 0x09360e7b),
++     TOBN(0x8c27a032, 0xc309914c), TOBN(0xcea5d68a, 0xcaede3d8),
++     TOBN(0x3668f665, 0x3a0a3f95), TOBN(0x89369416, 0x7ceba27b),
++     TOBN(0x89981fad, 0xe4728fe9), TOBN(0x7102c8a0, 0x8a093562),
++     TOBN(0xbb80310e, 0x235d21c8), TOBN(0x505e55d1, 0xbefb7f7b),
++     TOBN(0xa0a90811, 0x12958a67), TOBN(0xd67e106a, 0x4d851fef),
++     TOBN(0xb84011a9, 0x431dd80e), TOBN(0xeb7c7cca, 0x73306cd9),
++     TOBN(0x20fadd29, 0xd1b3b730), TOBN(0x83858b5b, 0xfe37b3d3),
++     TOBN(0xbf4cd193, 0xb6251d5c), TOBN(0x1cca1fd3, 0x1352d952),
++     TOBN(0xc66157a4, 0x90fbc051), TOBN(0x7990a638, 0x89b98636),}
++    ,
++    {TOBN(0xe5aa692a, 0x87dec0e1), TOBN(0x010ded8d, 0xf7b39d00),
++     TOBN(0x7b1b80c8, 0x54cfa0b5), TOBN(0x66beb876, 0xa0f8ea28),
++     TOBN(0x50d7f531, 0x3476cd0e), TOBN(0xa63d0e65, 0xb08d3949),
++     TOBN(0x1a09eea9, 0x53479fc6), TOBN(0x82ae9891, 0xf499e742),
++     TOBN(0xab58b910, 0x5ca7d866), TOBN(0x582967e2, 0x3adb3b34),
++     TOBN(0x89ae4447, 0xcceac0bc), TOBN(0x919c667c, 0x7bf56af5),
++     TOBN(0x9aec17b1, 0x60f5dcd7), TOBN(0xec697b9f, 0xddcaadbc),
++     TOBN(0x0b98f341, 0x463467f5), TOBN(0xb187f1f7, 0xa967132f),
++     TOBN(0x90fe7a1d, 0x214aeb18), TOBN(0x1506af3c, 0x741432f7),
++     TOBN(0xbb5565f9, 0xe591a0c4), TOBN(0x10d41a77, 0xb44f1bc3),
++     TOBN(0xa09d65e4, 0xa84bde96), TOBN(0x42f060d8, 0xf20a6a1c),
++     TOBN(0x652a3bfd, 0xf27f9ce7), TOBN(0xb6bdb65c, 0x3b3d739f),
++     TOBN(0xeb5ddcb6, 0xec7fae9f), TOBN(0x995f2714, 0xefb66e5a),
++     TOBN(0xdee95d8e, 0x69445d52), TOBN(0x1b6c2d46, 0x09e27620),
++     TOBN(0x32621c31, 0x8129d716), TOBN(0xb03909f1, 0x0958c1aa),
++     TOBN(0x8c468ef9, 0x1af4af63), TOBN(0x162c429f, 0xfba5cdf6),
++     TOBN(0x2f682343, 0x753b9371), TOBN(0x29cab45a, 0x5f1f9cd7),
++     TOBN(0x571623ab, 0xb245db96), TOBN(0xc507db09, 0x3fd79999),
++     TOBN(0x4e2ef652, 0xaf036c32), TOBN(0x86f0cc78, 0x05018e5c),
++     TOBN(0xc10a73d4, 0xab8be350), TOBN(0x6519b397, 0x7e826327),
++     TOBN(0xe8cb5eef, 0x9c053df7), TOBN(0x8de25b37, 0xb300ea6f),
++     TOBN(0xdb03fa92, 0xc849cffb), TOBN(0x242e43a7, 0xe84169bb),
++     TOBN(0xe4fa51f4, 0xdd6f958e), TOBN(0x6925a77f, 0xf4445a8d),
++     TOBN(0xe6e72a50, 0xe90d8949), TOBN(0xc66648e3, 0x2b1f6390),
++     TOBN(0xb2ab1957, 0x173e460c), TOBN(0x1bbbce75, 0x30704590),
++     TOBN(0xc0a90dbd, 0xdb1c7162), TOBN(0x505e399e, 0x15cdd65d),
++     TOBN(0x68434dcb, 0x57797ab7), TOBN(0x60ad35ba, 0x6a2ca8e8),
++     TOBN(0x4bfdb1e0, 0xde3336c1), TOBN(0xbbef99eb, 0xd8b39015),
++     TOBN(0x6c3b96f3, 0x1711ebec), TOBN(0x2da40f1f, 0xce98fdc4),
++     TOBN(0xb99774d3, 0x57b4411f), TOBN(0x87c8bdf4, 0x15b65bb6),
++     TOBN(0xda3a89e3, 0xc2eef12d), TOBN(0xde95bb9b, 0x3c7471f3),
++     TOBN(0x600f225b, 0xd812c594), TOBN(0x54907c5d, 0x2b75a56b),
++     TOBN(0xa93cc5f0, 0x8db60e35), TOBN(0x743e3cd6, 0xfa833319),
++     TOBN(0x7dad5c41, 0xf81683c9), TOBN(0x70c1e7d9, 0x9c34107e),
++     TOBN(0x0edc4a39, 0xa6be0907), TOBN(0x36d47035, 0x86d0b7d3),
++     TOBN(0x8c76da03, 0x272bfa60), TOBN(0x0b4a07ea, 0x0f08a414),
++     TOBN(0x699e4d29, 0x45c1dd53), TOBN(0xcadc5898, 0x231debb5),
++     TOBN(0xdf49fcc7, 0xa77f00e0), TOBN(0x93057bbf, 0xa73e5a0e),
++     TOBN(0x2f8b7ecd, 0x027a4cd1), TOBN(0x114734b3, 0xc614011a),
++     TOBN(0xe7a01db7, 0x67677c68), TOBN(0x89d9be5e, 0x7e273f4f),
++     TOBN(0xd225cb2e, 0x089808ef), TOBN(0xf1f7a27d, 0xd59e4107),
++     TOBN(0x53afc761, 0x8211b9c9), TOBN(0x0361bc67, 0xe6819159),
++     TOBN(0x2a865d0b, 0x7f071426), TOBN(0x6a3c1810, 0xe7072567),
++     TOBN(0x3e3bca1e, 0x0d6bcabd), TOBN(0xa1b02bc1, 0x408591bc),
++     TOBN(0xe0deee59, 0x31fba239), TOBN(0xf47424d3, 0x98bd91d1),
++     TOBN(0x0f8886f4, 0x071a3c1d), TOBN(0x3f7d41e8, 0xa819233b),
++     TOBN(0x708623c2, 0xcf6eb998), TOBN(0x86bb49af, 0x609a287f),
++     TOBN(0x942bb249, 0x63c90762), TOBN(0x0ef6eea5, 0x55a9654b),
++     TOBN(0x5f6d2d72, 0x36f5defe), TOBN(0xfa9922dc, 0x56f99176),
++     TOBN(0x6c8c5ece, 0xf78ce0c7), TOBN(0x7b44589d, 0xbe09b55e),
++     TOBN(0xe11b3bca, 0x9ea83770), TOBN(0xd7fa2c7f, 0x2ab71547),
++     TOBN(0x2a3dd6fa, 0x2a1ddcc0), TOBN(0x09acb430, 0x5a7b7707),
++     TOBN(0x4add4a2e, 0x649d4e57), TOBN(0xcd53a2b0, 0x1917526e),
++     TOBN(0xc5262330, 0x20b44ac4), TOBN(0x4028746a, 0xbaa2c31d),
++     TOBN(0x51318390, 0x64291d4c), TOBN(0xbf48f151, 0xee5ad909),
++     TOBN(0xcce57f59, 0x7b185681), TOBN(0x7c3ac1b0, 0x4854d442),
++     TOBN(0x65587dc3, 0xc093c171), TOBN(0xae7acb24, 0x24f42b65),
++     TOBN(0x5a338adb, 0x955996cb), TOBN(0xc8e65675, 0x6051f91b),
++     TOBN(0x66711fba, 0x28b8d0b1), TOBN(0x15d74137, 0xb6c10a90),
++     TOBN(0x70cdd7eb, 0x3a232a80), TOBN(0xc9e2f07f, 0x6191ed24),
++     TOBN(0xa80d1db6, 0xf79588c0), TOBN(0xfa52fc69, 0xb55768cc),
++     TOBN(0x0b4df1ae, 0x7f54438a), TOBN(0x0cadd1a7, 0xf9b46a4f),
++     TOBN(0xb40ea6b3, 0x1803dd6f), TOBN(0x488e4fa5, 0x55eaae35),
++     TOBN(0x9f047d55, 0x382e4e16), TOBN(0xc9b5b7e0, 0x2f6e0c98),
++     TOBN(0x6b1bd2d3, 0x95762649), TOBN(0xa9604ee7, 0xc7aea3f6),
++     TOBN(0x3646ff27, 0x6dc6f896), TOBN(0x9bf0e7f5, 0x2860bad1),
++     TOBN(0x2d92c821, 0x7cb44b92), TOBN(0xa2f5ce63, 0xaea9c182),
++     TOBN(0xd0a2afb1, 0x9154a5fd), TOBN(0x482e474c, 0x95801da6),
++     TOBN(0xc19972d0, 0xb611c24b), TOBN(0x1d468e65, 0x60a8f351),
++     TOBN(0xeb758069, 0x7bcf6421), TOBN(0xec9dd0ee, 0x88fbc491),
++     TOBN(0x5b59d2bf, 0x956c2e32), TOBN(0x73dc6864, 0xdcddf94e),
++     TOBN(0xfd5e2321, 0xbcee7665), TOBN(0xa7b4f8ef, 0x5e9a06c4),
++     TOBN(0xfba918dd, 0x7280f855), TOBN(0xbbaac260, 0x8baec688),
++     TOBN(0xa3b3f00f, 0x33400f42), TOBN(0x3d2dba29, 0x66f2e6e4),
++     TOBN(0xb6f71a94, 0x98509375), TOBN(0x8f33031f, 0xcea423cc),
++     TOBN(0x009b8dd0, 0x4807e6fb), TOBN(0x5163cfe5, 0x5cdb954c),
++     TOBN(0x03cc8f17, 0xcf41c6e8), TOBN(0xf1f03c2a, 0x037b925c),
++     TOBN(0xc39c19cc, 0x66d2427c), TOBN(0x823d24ba, 0x7b6c18e4),
++     TOBN(0x32ef9013, 0x901f0b4f), TOBN(0x684360f1, 0xf8941c2e),
++     TOBN(0x0ebaff52, 0x2c28092e), TOBN(0x7891e4e3, 0x256c932f),
++     TOBN(0x51264319, 0xac445e3d), TOBN(0x553432e7, 0x8ea74381),
++     TOBN(0xe6eeaa69, 0x67e9c50a), TOBN(0x27ced284, 0x62e628c7),
++     TOBN(0x3f96d375, 0x7a4afa57), TOBN(0xde0a14c3, 0xe484c150),
++     TOBN(0x364a24eb, 0x38bd9923), TOBN(0x1df18da0, 0xe5177422),
++     TOBN(0x174e8f82, 0xd8d38a9b), TOBN(0x2e97c600, 0xe7de1391),
++     TOBN(0xc5709850, 0xa1c175dd), TOBN(0x969041a0, 0x32ae5035),
++     TOBN(0xcbfd533b, 0x76a2086b), TOBN(0xd6bba71b, 0xd7c2e8fe),
++     TOBN(0xb2d58ee6, 0x099dfb67), TOBN(0x3a8b342d, 0x064a85d9),
++     TOBN(0x3bc07649, 0x522f9be3), TOBN(0x690c075b, 0xdf1f49a8),
++     TOBN(0x80e1aee8, 0x3854ec42), TOBN(0x2a7dbf44, 0x17689dc7),
++     TOBN(0xc004fc0e, 0x3faf4078), TOBN(0xb2f02e9e, 0xdf11862c),
++     TOBN(0xf10a5e0f, 0xa0a1b7b3), TOBN(0x30aca623, 0x8936ec80),
++     TOBN(0xf83cbf05, 0x02f40d9a), TOBN(0x4681c468, 0x2c318a4d),
++     TOBN(0x98575618, 0x0e9c2674), TOBN(0xbe79d046, 0x1847092e),
++     TOBN(0xaf1e480a, 0x78bd01e0), TOBN(0x6dd359e4, 0x72a51db9),
++     TOBN(0x62ce3821, 0xe3afbab6), TOBN(0xc5cee5b6, 0x17733199),
++     TOBN(0xe08b30d4, 0x6ffd9fbb), TOBN(0x6e5bc699, 0x36c610b7),
++     TOBN(0xf343cff2, 0x9ce262cf), TOBN(0xca2e4e35, 0x68b914c1),
++     TOBN(0x011d64c0, 0x16de36c5), TOBN(0xe0b10fdd, 0x42e2b829),
++     TOBN(0x78942981, 0x6685aaf8), TOBN(0xe7511708, 0x230ede97),
++     TOBN(0x671ed8fc, 0x3b922bf8), TOBN(0xe4d8c0a0, 0x4c29b133),
++     TOBN(0x87eb1239, 0x3b6e99c4), TOBN(0xaff3974c, 0x8793beba),
++     TOBN(0x03749405, 0x2c18df9b), TOBN(0xc5c3a293, 0x91007139),
++     TOBN(0x6a77234f, 0xe37a0b95), TOBN(0x02c29a21, 0xb661c96b),
++     TOBN(0xc3aaf1d6, 0x141ecf61), TOBN(0x9195509e, 0x3bb22f53),
++     TOBN(0x29597404, 0x22d51357), TOBN(0x1b083822, 0x537bed60),
++     TOBN(0xcd7d6e35, 0xe07289f0), TOBN(0x1f94c48c, 0x6dd86eff),
++     TOBN(0xc8bb1f82, 0xeb0f9cfa), TOBN(0x9ee0b7e6, 0x1b2eb97d),
++     TOBN(0x5a52fe2e, 0x34d74e31), TOBN(0xa352c310, 0x3bf79ab6),
++     TOBN(0x97ff6c5a, 0xabfeeb8f), TOBN(0xbfbe8fef, 0xf5c97305),
++     TOBN(0xd6081ce6, 0xa7904608), TOBN(0x1f812f3a, 0xc4fca249),
++     TOBN(0x9b24bc9a, 0xb9e5e200), TOBN(0x91022c67, 0x38012ee8),
++     TOBN(0xe83d9c5d, 0x30a713a1), TOBN(0x4876e3f0, 0x84ef0f93),
++     TOBN(0xc9777029, 0xc1fbf928), TOBN(0xef7a6bb3, 0xbce7d2a4),
++     TOBN(0xb8067228, 0xdfa2a659), TOBN(0xd5cd3398, 0xd877a48f),
++     TOBN(0xbea4fd8f, 0x025d0f3f), TOBN(0xd67d2e35, 0x2eae7c2b),
++     TOBN(0x184de7d7, 0xcc5f4394), TOBN(0xb5551b5c, 0x4536e142),
++     TOBN(0x2e89b212, 0xd34aa60a), TOBN(0x14a96fea, 0xf50051d5),
++     TOBN(0x4e21ef74, 0x0d12bb0b), TOBN(0xc522f020, 0x60b9677e),
++     TOBN(0x8b12e467, 0x2df7731d), TOBN(0x39f80382, 0x7b326d31),
++     TOBN(0xdfb8630c, 0x39024a94), TOBN(0xaacb96a8, 0x97319452),
++     TOBN(0xd68a3961, 0xeda3867c), TOBN(0x0c58e2b0, 0x77c4ffca),
++     TOBN(0x3d545d63, 0x4da919fa), TOBN(0xef79b69a, 0xf15e2289),
++     TOBN(0x54bc3d3d, 0x808bab10), TOBN(0xc8ab3007, 0x45f82c37),
++     TOBN(0xc12738b6, 0x7c4a658a), TOBN(0xb3c47639, 0x40e72182),
++     TOBN(0x3b77be46, 0x8798e44f), TOBN(0xdc047df2, 0x17a7f85f),
++     TOBN(0x2439d4c5, 0x5e59d92d), TOBN(0xcedca475, 0xe8e64d8d),
++     TOBN(0xa724cd0d, 0x87ca9b16), TOBN(0x35e4fd59, 0xa5540dfe),
++     TOBN(0xf8c1ff18, 0xe4bcf6b1), TOBN(0x856d6285, 0x295018fa),
++     TOBN(0x433f665c, 0x3263c949), TOBN(0xa6a76dd6, 0xa1f21409),
++     TOBN(0x17d32334, 0xcc7b4f79), TOBN(0xa1d03122, 0x06720e4a),
++     TOBN(0xadb6661d, 0x81d9bed5), TOBN(0xf0d6fb02, 0x11db15d1),
++     TOBN(0x7fd11ad5, 0x1fb747d2), TOBN(0xab50f959, 0x3033762b),
++     TOBN(0x2a7e711b, 0xfbefaf5a), TOBN(0xc7393278, 0x3fef2bbf),
++     TOBN(0xe29fa244, 0x0df6f9be), TOBN(0x9092757b, 0x71efd215),
++     TOBN(0xee60e311, 0x4f3d6fd9), TOBN(0x338542d4, 0x0acfb78b),
++     TOBN(0x44a23f08, 0x38961a0f), TOBN(0x1426eade, 0x986987ca),
++     TOBN(0x36e6ee2e, 0x4a863cc6), TOBN(0x48059420, 0x628b8b79),
++     TOBN(0x30303ad8, 0x7396e1de), TOBN(0x5c8bdc48, 0x38c5aad1),
++     TOBN(0x3e40e11f, 0x5c8f5066), TOBN(0xabd6e768, 0x8d246bbd),
++     TOBN(0x68aa40bb, 0x23330a01), TOBN(0xd23f5ee4, 0xc34eafa0),
++     TOBN(0x3bbee315, 0x5de02c21), TOBN(0x18dd4397, 0xd1d8dd06),
++     TOBN(0x3ba1939a, 0x122d7b44), TOBN(0xe6d3b40a, 0xa33870d6),
++     TOBN(0x8e620f70, 0x1c4fe3f8), TOBN(0xf6bba1a5, 0xd3a50cbf),
++     TOBN(0x4a78bde5, 0xcfc0aee0), TOBN(0x847edc46, 0xc08c50bd),
++     TOBN(0xbaa2439c, 0xad63c9b2), TOBN(0xceb4a728, 0x10fc2acb),
++     TOBN(0xa419e40e, 0x26da033d), TOBN(0x6cc3889d, 0x03e02683),
++     TOBN(0x1cd28559, 0xfdccf725), TOBN(0x0fd7e0f1, 0x8d13d208),
++     TOBN(0x01b9733b, 0x1f0df9d4), TOBN(0x8cc2c5f3, 0xa2b5e4f3),
++     TOBN(0x43053bfa, 0x3a304fd4), TOBN(0x8e87665c, 0x0a9f1aa7),
++     TOBN(0x087f29ec, 0xd73dc965), TOBN(0x15ace455, 0x3e9023db),
++     TOBN(0x2370e309, 0x2bce28b4), TOBN(0xf9723442, 0xb6b1e84a),
++     TOBN(0xbeee662e, 0xb72d9f26), TOBN(0xb19396de, 0xf0e47109),
++     TOBN(0x85b1fa73, 0xe13289d0), TOBN(0x436cf77e, 0x54e58e32),
++     TOBN(0x0ec833b3, 0xe990ef77), TOBN(0x7373e3ed, 0x1b11fc25),
++     TOBN(0xbe0eda87, 0x0fc332ce), TOBN(0xced04970, 0x8d7ea856),
++     TOBN(0xf85ff785, 0x7e977ca0), TOBN(0xb66ee8da, 0xdfdd5d2b),
++     TOBN(0xf5e37950, 0x905af461), TOBN(0x587b9090, 0x966d487c),
++     TOBN(0x6a198a1b, 0x32ba0127), TOBN(0xa7720e07, 0x141615ac),
++     TOBN(0xa23f3499, 0x996ef2f2), TOBN(0xef5f64b4, 0x470bcb3d),
++     TOBN(0xa526a962, 0x92b8c559), TOBN(0x0c14aac0, 0x69740a0f),
++     TOBN(0x0d41a9e3, 0xa6bdc0a5), TOBN(0x97d52106, 0x9c48aef4),
++     TOBN(0xcf16bd30, 0x3e7c253b), TOBN(0xcc834b1a, 0x47fdedc1),
++     TOBN(0x7362c6e5, 0x373aab2e), TOBN(0x264ed85e, 0xc5f590ff),
++     TOBN(0x7a46d9c0, 0x66d41870), TOBN(0xa50c20b1, 0x4787ba09),
++     TOBN(0x185e7e51, 0xe3d44635), TOBN(0xb3b3e080, 0x31e2d8dc),
++     TOBN(0xbed1e558, 0xa179e9d9), TOBN(0x2daa3f79, 0x74a76781),
++     TOBN(0x4372baf2, 0x3a40864f), TOBN(0x46900c54, 0x4fe75cb5),
++     TOBN(0xb95f171e, 0xf76765d0), TOBN(0x4ad726d2, 0x95c87502),
++     TOBN(0x2ec769da, 0x4d7c99bd), TOBN(0x5e2ddd19, 0xc36cdfa8),
++     TOBN(0xc22117fc, 0xa93e6dea), TOBN(0xe8a2583b, 0x93771123),
++     TOBN(0xbe2f6089, 0xfa08a3a2), TOBN(0x4809d5ed, 0x8f0e1112),
++     TOBN(0x3b414aa3, 0xda7a095e), TOBN(0x9049acf1, 0x26f5aadd),
++     TOBN(0x78d46a4d, 0x6be8b84a), TOBN(0xd66b1963, 0xb732b9b3),
++     TOBN(0x5c2ac2a0, 0xde6e9555), TOBN(0xcf52d098, 0xb5bd8770),
++     TOBN(0x15a15fa6, 0x0fd28921), TOBN(0x56ccb81e, 0x8b27536d),
++     TOBN(0x0f0d8ab8, 0x9f4ccbb8), TOBN(0xed5f44d2, 0xdb221729),
++     TOBN(0x43141988, 0x00bed10c), TOBN(0xc94348a4, 0x1d735b8b),
++     TOBN(0x79f3e9c4, 0x29ef8479), TOBN(0x4c13a4e3, 0x614c693f),
++     TOBN(0x32c9af56, 0x8e143a14), TOBN(0xbc517799, 0xe29ac5c4),
++     TOBN(0x05e17992, 0x2774856f), TOBN(0x6e52fb05, 0x6c1bf55f),
++     TOBN(0xaeda4225, 0xe4f19e16), TOBN(0x70f4728a, 0xaf5ccb26),
++     TOBN(0x5d2118d1, 0xb2947f22), TOBN(0xc827ea16, 0x281d6fb9),
++     TOBN(0x8412328d, 0x8cf0eabd), TOBN(0x45ee9fb2, 0x03ef9dcf),
++     TOBN(0x8e700421, 0xbb937d63), TOBN(0xdf8ff2d5, 0xcc4b37a6),
++     TOBN(0xa4c0d5b2, 0x5ced7b68), TOBN(0x6537c1ef, 0xc7308f59),
++     TOBN(0x25ce6a26, 0x3b37f8e8), TOBN(0x170e9a9b, 0xdeebc6ce),
++     TOBN(0xdd037952, 0x8728d72c), TOBN(0x445b0e55, 0x850154bc),
++     TOBN(0x4b7d0e06, 0x83a7337b), TOBN(0x1e3416d4, 0xffecf249),
++     TOBN(0x24840eff, 0x66a2b71f), TOBN(0xd0d9a50a, 0xb37cc26d),
++     TOBN(0xe2198150, 0x6fe28ef7), TOBN(0x3cc5ef16, 0x23324c7f),
++     TOBN(0x220f3455, 0x769b5263), TOBN(0xe2ade2f1, 0xa10bf475),
++     TOBN(0x28cd20fa, 0x458d3671), TOBN(0x1549722c, 0x2dc4847b),
++     TOBN(0x6dd01e55, 0x591941e3), TOBN(0x0e6fbcea, 0x27128ccb),
++     TOBN(0xae1a1e6b, 0x3bef0262), TOBN(0xfa8c472c, 0x8f54e103),
++     TOBN(0x7539c0a8, 0x72c052ec), TOBN(0xd7b27369, 0x5a3490e9),
++     TOBN(0x143fe1f1, 0x71684349), TOBN(0x36b4722e, 0x32e19b97),
++     TOBN(0xdc059227, 0x90980aff), TOBN(0x175c9c88, 0x9e13d674),
++     TOBN(0xa7de5b22, 0x6e6bfdb1), TOBN(0x5ea5b7b2, 0xbedb4b46),
++     TOBN(0xd5570191, 0xd34a6e44), TOBN(0xfcf60d2e, 0xa24ff7e6),
++     TOBN(0x614a392d, 0x677819e1), TOBN(0x7be74c7e, 0xaa5a29e8),
++     TOBN(0xab50fece, 0x63c85f3f), TOBN(0xaca2e2a9, 0x46cab337),
++     TOBN(0x7f700388, 0x122a6fe3), TOBN(0xdb69f703, 0x882a04a8),
++     TOBN(0x9a77935d, 0xcf7aed57), TOBN(0xdf16207c, 0x8d91c86f),
++     TOBN(0x2fca49ab, 0x63ed9998), TOBN(0xa3125c44, 0xa77ddf96),
++     TOBN(0x05dd8a86, 0x24344072), TOBN(0xa023dda2, 0xfec3fb56),
++     TOBN(0x421b41fc, 0x0c743032), TOBN(0x4f2120c1, 0x5e438639),
++     TOBN(0xfb7cae51, 0xc83c1b07), TOBN(0xb2370caa, 0xcac2171a),
++     TOBN(0x2eb2d962, 0x6cc820fb), TOBN(0x59feee5c, 0xb85a44bf),
++     TOBN(0x94620fca, 0x5b6598f0), TOBN(0x6b922cae, 0x7e314051),
++     TOBN(0xff8745ad, 0x106bed4e), TOBN(0x546e71f5, 0xdfa1e9ab),
++     TOBN(0x935c1e48, 0x1ec29487), TOBN(0x9509216c, 0x4d936530),
++     TOBN(0xc7ca3067, 0x85c9a2db), TOBN(0xd6ae5152, 0x6be8606f),
++     TOBN(0x09dbcae6, 0xe14c651d), TOBN(0xc9536e23, 0x9bc32f96),
++     TOBN(0xa90535a9, 0x34521b03), TOBN(0xf39c526c, 0x878756ff),
++     TOBN(0x383172ec, 0x8aedf03c), TOBN(0x20a8075e, 0xefe0c034),
++     TOBN(0xf22f9c62, 0x64026422), TOBN(0x8dd10780, 0x24b9d076),
++     TOBN(0x944c742a, 0x3bef2950), TOBN(0x55b9502e, 0x88a2b00b),
++     TOBN(0xa59e14b4, 0x86a09817), TOBN(0xa39dd3ac, 0x47bb4071),
++     TOBN(0x55137f66, 0x3be0592f), TOBN(0x07fcafd4, 0xc9e63f5b),
++     TOBN(0x963652ee, 0x346eb226), TOBN(0x7dfab085, 0xec2facb7),
++     TOBN(0x273bf2b8, 0x691add26), TOBN(0x30d74540, 0xf2b46c44),
++     TOBN(0x05e8e73e, 0xf2c2d065), TOBN(0xff9b8a00, 0xd42eeac9),
++     TOBN(0x2fcbd205, 0x97209d22), TOBN(0xeb740ffa, 0xde14ea2c),
++     TOBN(0xc71ff913, 0xa8aef518), TOBN(0x7bfc74bb, 0xfff4cfa2),
++     TOBN(0x1716680c, 0xb6b36048), TOBN(0x121b2cce, 0x9ef79af1),
++     TOBN(0xbff3c836, 0xa01eb3d3), TOBN(0x50eb1c6a, 0x5f79077b),
++     TOBN(0xa48c32d6, 0xa004bbcf), TOBN(0x47a59316, 0x7d64f61d),
++     TOBN(0x6068147f, 0x93102016), TOBN(0x12c5f654, 0x94d12576),
++     TOBN(0xefb071a7, 0xc9bc6b91), TOBN(0x7c2da0c5, 0x6e23ea95),
++     TOBN(0xf4fd45b6, 0xd4a1dd5d), TOBN(0x3e7ad9b6, 0x9122b13c),
++     TOBN(0x342ca118, 0xe6f57a48), TOBN(0x1c2e94a7, 0x06f8288f),
++     TOBN(0x99e68f07, 0x5a97d231), TOBN(0x7c80de97, 0x4d838758),
++     TOBN(0xbce0f5d0, 0x05872727), TOBN(0xbe5d95c2, 0x19c4d016),
++     TOBN(0x921d5cb1, 0x9c2492ee), TOBN(0x42192dc1, 0x404d6fb3),
++     TOBN(0x4c84dcd1, 0x32f988d3), TOBN(0xde26d61f, 0xa17b8e85),
++     TOBN(0xc466dcb6, 0x137c7408), TOBN(0x9a38d7b6, 0x36a266da),
++     TOBN(0x7ef5cb06, 0x83bebf1b), TOBN(0xe5cdcbbf, 0x0fd014e3),
++     TOBN(0x30aa376d, 0xf65965a0), TOBN(0x60fe88c2, 0xebb3e95e),
++     TOBN(0x33fd0b61, 0x66ee6f20), TOBN(0x8827dcdb, 0x3f41f0a0),
++     TOBN(0xbf8a9d24, 0x0c56c690), TOBN(0x40265dad, 0xddb7641d),
++     TOBN(0x522b05bf, 0x3a6b662b), TOBN(0x466d1dfe, 0xb1478c9b),
++     TOBN(0xaa616962, 0x1484469b), TOBN(0x0db60549, 0x02df8f9f),
++     TOBN(0xc37bca02, 0x3cb8bf51), TOBN(0x5effe346, 0x21371ce8),
++     TOBN(0xe8f65264, 0xff112c32), TOBN(0x8a9c736d, 0x7b971fb2),
++     TOBN(0xa4f19470, 0x7b75080d), TOBN(0xfc3f2c5a, 0x8839c59b),
++     TOBN(0x1d6c777e, 0x5aeb49c2), TOBN(0xf3db034d, 0xda1addfe),
++     TOBN(0xd76fee5a, 0x5535affc), TOBN(0x0853ac70, 0xb92251fd),
++     TOBN(0x37e3d594, 0x8b2a29d5), TOBN(0x28f1f457, 0x4de00ddb),
++     TOBN(0x8083c1b5, 0xf42c328b), TOBN(0xd8ef1d8f, 0xe493c73b),
++     TOBN(0x96fb6260, 0x41dc61bd), TOBN(0xf74e8a9d, 0x27ee2f8a),
++     TOBN(0x7c605a80, 0x2c946a5d), TOBN(0xeed48d65, 0x3839ccfd),
++     TOBN(0x9894344f, 0x3a29467a), TOBN(0xde81e949, 0xc51eba6d),
++     TOBN(0xdaea066b, 0xa5e5c2f2), TOBN(0x3fc8a614, 0x08c8c7b3),
++     TOBN(0x7adff88f, 0x06d0de9f), TOBN(0xbbc11cf5, 0x3b75ce0a),
++     TOBN(0x9fbb7acc, 0xfbbc87d5), TOBN(0xa1458e26, 0x7badfde2)}
++    ,
++    {TOBN(0x1cb43668, 0xe039c256), TOBN(0x5f26fb8b, 0x7c17fd5d),
++     TOBN(0xeee426af, 0x79aa062b), TOBN(0x072002d0, 0xd78fbf04),
++     TOBN(0x4c9ca237, 0xe84fb7e3), TOBN(0xb401d8a1, 0x0c82133d),
++     TOBN(0xaaa52592, 0x6d7e4181), TOBN(0xe9430833, 0x73dbb152),
++     TOBN(0xf92dda31, 0xbe24319a), TOBN(0x03f7d28b, 0xe095a8e7),
++     TOBN(0xa52fe840, 0x98782185), TOBN(0x276ddafe, 0x29c24dbc),
++     TOBN(0x80cd5496, 0x1d7a64eb), TOBN(0xe4360889, 0x7f1dbe42),
++     TOBN(0x2f81a877, 0x8438d2d5), TOBN(0x7e4d52a8, 0x85169036),
++     TOBN(0x19e3d5b1, 0x1d59715d), TOBN(0xc7eaa762, 0xd788983e),
++     TOBN(0xe5a730b0, 0xabf1f248), TOBN(0xfbab8084, 0xfae3fd83),
++     TOBN(0x65e50d21, 0x53765b2f), TOBN(0xbdd4e083, 0xfa127f3d),
++     TOBN(0x9cf3c074, 0x397b1b10), TOBN(0x59f8090c, 0xb1b59fd3),
++     TOBN(0x7b15fd9d, 0x615faa8f), TOBN(0x8fa1eb40, 0x968554ed),
++     TOBN(0x7bb4447e, 0x7aa44882), TOBN(0x2bb2d0d1, 0x029fff32),
++     TOBN(0x075e2a64, 0x6caa6d2f), TOBN(0x8eb879de, 0x22e7351b),
++     TOBN(0xbcd5624e, 0x9a506c62), TOBN(0x218eaef0, 0xa87e24dc),
++     TOBN(0x37e56847, 0x44ddfa35), TOBN(0x9ccfc5c5, 0xdab3f747),
++     TOBN(0x9ac1df3f, 0x1ee96cf4), TOBN(0x0c0571a1, 0x3b480b8f),
++     TOBN(0x2fbeb3d5, 0x4b3a7b3c), TOBN(0x35c03669, 0x5dcdbb99),
++     TOBN(0x52a0f5dc, 0xb2415b3a), TOBN(0xd57759b4, 0x4413ed9a),
++     TOBN(0x1fe647d8, 0x3d30a2c5), TOBN(0x0857f77e, 0xf78a81dc),
++     TOBN(0x11d5a334, 0x131a4a9b), TOBN(0xc0a94af9, 0x29d393f5),
++     TOBN(0xbc3a5c0b, 0xdaa6ec1a), TOBN(0xba9fe493, 0x88d2d7ed),
++     TOBN(0xbb4335b4, 0xbb614797), TOBN(0x991c4d68, 0x72f83533),
++     TOBN(0x53258c28, 0xd2f01cb3), TOBN(0x93d6eaa3, 0xd75db0b1),
++     TOBN(0x419a2b0d, 0xe87d0db4), TOBN(0xa1e48f03, 0xd8fe8493),
++     TOBN(0xf747faf6, 0xc508b23a), TOBN(0xf137571a, 0x35d53549),
++     TOBN(0x9f5e58e2, 0xfcf9b838), TOBN(0xc7186cee, 0xa7fd3cf5),
++     TOBN(0x77b868ce, 0xe978a1d3), TOBN(0xe3a68b33, 0x7ab92d04),
++     TOBN(0x51029794, 0x87a5b862), TOBN(0x5f0606c3, 0x3a61d41d),
++     TOBN(0x2814be27, 0x6f9326f1), TOBN(0x2f521c14, 0xc6fe3c2e),
++     TOBN(0x17464d7d, 0xacdf7351), TOBN(0x10f5f9d3, 0x777f7e44),
++     TOBN(0xce8e616b, 0x269fb37d), TOBN(0xaaf73804, 0x7de62de5),
++     TOBN(0xaba11175, 0x4fdd4153), TOBN(0x515759ba, 0x3770b49b),
++     TOBN(0x8b09ebf8, 0xaa423a61), TOBN(0x592245a1, 0xcd41fb92),
++     TOBN(0x1cba8ec1, 0x9b4c8936), TOBN(0xa87e91e3, 0xaf36710e),
++     TOBN(0x1fd84ce4, 0x3d34a2e3), TOBN(0xee3759ce, 0xb43b5d61),
++     TOBN(0x895bc78c, 0x619186c7), TOBN(0xf19c3809, 0xcbb9725a),
++     TOBN(0xc0be21aa, 0xde744b1f), TOBN(0xa7d222b0, 0x60f8056b),
++     TOBN(0x74be6157, 0xb23efe11), TOBN(0x6fab2b4f, 0x0cd68253),
++     TOBN(0xad33ea5f, 0x4bf1d725), TOBN(0x9c1d8ee2, 0x4f6c950f),
++     TOBN(0x544ee78a, 0xa377af06), TOBN(0x54f489bb, 0x94a113e1),
++     TOBN(0x8f11d634, 0x992fb7e8), TOBN(0x0169a7aa, 0xa2a44347),
++     TOBN(0x1d49d4af, 0x95020e00), TOBN(0x95945722, 0xe08e120b),
++     TOBN(0xb6e33878, 0xa4d32282), TOBN(0xe36e029d, 0x48020ae7),
++     TOBN(0xe05847fb, 0x37a9b750), TOBN(0xf876812c, 0xb29e3819),
++     TOBN(0x84ad138e, 0xd23a17f0), TOBN(0x6d7b4480, 0xf0b3950e),
++     TOBN(0xdfa8aef4, 0x2fd67ae0), TOBN(0x8d3eea24, 0x52333af6),
++     TOBN(0x0d052075, 0xb15d5acc), TOBN(0xc6d9c79f, 0xbd815bc4),
++     TOBN(0x8dcafd88, 0xdfa36cf2), TOBN(0x908ccbe2, 0x38aa9070),
++     TOBN(0x638722c4, 0xba35afce), TOBN(0x5a3da8b0, 0xfd6abf0b),
++     TOBN(0x2dce252c, 0xc9c335c1), TOBN(0x84e7f0de, 0x65aa799b),
++     TOBN(0x2101a522, 0xb99a72cb), TOBN(0x06de6e67, 0x87618016),
++     TOBN(0x5ff8c7cd, 0xe6f3653e), TOBN(0x0a821ab5, 0xc7a6754a),
++     TOBN(0x7e3fa52b, 0x7cb0b5a2), TOBN(0xa7fb121c, 0xc9048790),
++     TOBN(0x1a725020, 0x06ce053a), TOBN(0xb490a31f, 0x04e929b0),
++     TOBN(0xe17be47d, 0x62dd61ad), TOBN(0x781a961c, 0x6be01371),
++     TOBN(0x1063bfd3, 0xdae3cbba), TOBN(0x35647406, 0x7f73c9ba),
++     TOBN(0xf50e957b, 0x2736a129), TOBN(0xa6313702, 0xed13f256),
++     TOBN(0x9436ee65, 0x3a19fcc5), TOBN(0xcf2bdb29, 0xe7a4c8b6),
++     TOBN(0xb06b1244, 0xc5f95cd8), TOBN(0xda8c8af0, 0xf4ab95f4),
++     TOBN(0x1bae59c2, 0xb9e5836d), TOBN(0x07d51e7e, 0x3acffffc),
++     TOBN(0x01e15e6a, 0xc2ccbcda), TOBN(0x3bc1923f, 0x8528c3e0),
++     TOBN(0x43324577, 0xa49fead4), TOBN(0x61a1b884, 0x2aa7a711),
++     TOBN(0xf9a86e08, 0x700230ef), TOBN(0x0af585a1, 0xbd19adf8),
++     TOBN(0x7645f361, 0xf55ad8f2), TOBN(0x6e676223, 0x46c3614c),
++     TOBN(0x23cb257c, 0x4e774d3f), TOBN(0x82a38513, 0xac102d1b),
++     TOBN(0x9bcddd88, 0x7b126aa5), TOBN(0xe716998b, 0xeefd3ee4),
++     TOBN(0x4239d571, 0xfb167583), TOBN(0xdd011c78, 0xd16c8f8a),
++     TOBN(0x271c2895, 0x69a27519), TOBN(0x9ce0a3b7, 0xd2d64b6a),
++     TOBN(0x8c977289, 0xd5ec6738), TOBN(0xa3b49f9a, 0x8840ef6b),
++     TOBN(0x808c14c9, 0x9a453419), TOBN(0x5c00295b, 0x0cf0a2d5),
++     TOBN(0x524414fb, 0x1d4bcc76), TOBN(0xb07691d2, 0x459a88f1),
++     TOBN(0x77f43263, 0xf70d110f), TOBN(0x64ada5e0, 0xb7abf9f3),
++     TOBN(0xafd0f94e, 0x5b544cf5), TOBN(0xb4a13a15, 0xfd2713fe),
++     TOBN(0xb99b7d6e, 0x250c74f4), TOBN(0x097f2f73, 0x20324e45),
++     TOBN(0x994b37d8, 0xaffa8208), TOBN(0xc3c31b0b, 0xdc29aafc),
++     TOBN(0x3da74651, 0x7a3a607f), TOBN(0xd8e1b8c1, 0xfe6955d6),
++     TOBN(0x716e1815, 0xc8418682), TOBN(0x541d487f, 0x7dc91d97),
++     TOBN(0x48a04669, 0xc6996982), TOBN(0xf39cab15, 0x83a6502e),
++     TOBN(0x025801a0, 0xe68db055), TOBN(0xf3569758, 0xba3338d5),
++     TOBN(0xb0c8c0aa, 0xee2afa84), TOBN(0x4f6985d3, 0xfb6562d1),
++     TOBN(0x351f1f15, 0x132ed17a), TOBN(0x510ed0b4, 0xc04365fe),
++     TOBN(0xa3f98138, 0xe5b1f066), TOBN(0xbc9d95d6, 0x32df03dc),
++     TOBN(0xa83ccf6e, 0x19abd09e), TOBN(0x0b4097c1, 0x4ff17edb),
++     TOBN(0x58a5c478, 0xd64a06ce), TOBN(0x2ddcc3fd, 0x544a58fd),
++     TOBN(0xd449503d, 0x9e8153b8), TOBN(0x3324fd02, 0x7774179b),
++     TOBN(0xaf5d47c8, 0xdbd9120c), TOBN(0xeb860162, 0x34fa94db),
++     TOBN(0x5817bdd1, 0x972f07f4), TOBN(0xe5579e2e, 0xd27bbceb),
++     TOBN(0x86847a1f, 0x5f11e5a6), TOBN(0xb39ed255, 0x7c3cf048),
++     TOBN(0xe1076417, 0xa2f62e55), TOBN(0x6b9ab38f, 0x1bcf82a2),
++     TOBN(0x4bb7c319, 0x7aeb29f9), TOBN(0xf6d17da3, 0x17227a46),
++     TOBN(0xab53ddbd, 0x0f968c00), TOBN(0xa03da7ec, 0x000c880b),
++     TOBN(0x7b239624, 0x6a9ad24d), TOBN(0x612c0401, 0x01ec60d0),
++     TOBN(0x70d10493, 0x109f5df1), TOBN(0xfbda4030, 0x80af7550),
++     TOBN(0x30b93f95, 0xc6b9a9b3), TOBN(0x0c74ec71, 0x007d9418),
++     TOBN(0x94175564, 0x6edb951f), TOBN(0x5f4a9d78, 0x7f22c282),
++     TOBN(0xb7870895, 0xb38d1196), TOBN(0xbc593df3, 0xa228ce7c),
++     TOBN(0xc78c5bd4, 0x6af3641a), TOBN(0x7802200b, 0x3d9b3dcc),
++     TOBN(0x0dc73f32, 0x8be33304), TOBN(0x847ed87d, 0x61ffb79a),
++     TOBN(0xf85c974e, 0x6d671192), TOBN(0x1e14100a, 0xde16f60f),
++     TOBN(0x45cb0d5a, 0x95c38797), TOBN(0x18923bba, 0x9b022da4),
++     TOBN(0xef2be899, 0xbbe7e86e), TOBN(0x4a1510ee, 0x216067bf),
++     TOBN(0xd98c8154, 0x84d5ce3e), TOBN(0x1af777f0, 0xf92a2b90),
++     TOBN(0x9fbcb400, 0x4ef65724), TOBN(0x3e04a4c9, 0x3c0ca6fe),
++     TOBN(0xfb3e2cb5, 0x55002994), TOBN(0x1f3a93c5, 0x5363ecab),
++     TOBN(0x1fe00efe, 0x3923555b), TOBN(0x744bedd9, 0x1e1751ea),
++     TOBN(0x3fb2db59, 0x6ab69357), TOBN(0x8dbd7365, 0xf5e6618b),
++     TOBN(0x99d53099, 0xdf1ea40e), TOBN(0xb3f24a0b, 0x57d61e64),
++     TOBN(0xd088a198, 0x596eb812), TOBN(0x22c8361b, 0x5762940b),
++     TOBN(0x66f01f97, 0xf9c0d95c), TOBN(0x88461172, 0x8e43cdae),
++     TOBN(0x11599a7f, 0xb72b15c3), TOBN(0x135a7536, 0x420d95cc),
++     TOBN(0x2dcdf0f7, 0x5f7ae2f6), TOBN(0x15fc6e1d, 0xd7fa6da2),
++     TOBN(0x81ca829a, 0xd1d441b6), TOBN(0x84c10cf8, 0x04a106b6),
++     TOBN(0xa9b26c95, 0xa73fbbd0), TOBN(0x7f24e0cb, 0x4d8f6ee8),
++     TOBN(0x48b45937, 0x1e25a043), TOBN(0xf8a74fca, 0x036f3dfe),
++     TOBN(0x1ed46585, 0xc9f84296), TOBN(0x7fbaa8fb, 0x3bc278b0),
++     TOBN(0xa8e96cd4, 0x6c4fcbd0), TOBN(0x940a1202, 0x73b60a5f),
++     TOBN(0x34aae120, 0x55a4aec8), TOBN(0x550e9a74, 0xdbd742f0),
++     TOBN(0x794456d7, 0x228c68ab), TOBN(0x492f8868, 0xa4e25ec6),
++     TOBN(0x682915ad, 0xb2d8f398), TOBN(0xf13b51cc, 0x5b84c953),
++     TOBN(0xcda90ab8, 0x5bb917d6), TOBN(0x4b615560, 0x4ea3dee1),
++     TOBN(0x578b4e85, 0x0a52c1c8), TOBN(0xeab1a695, 0x20b75fc4),
++     TOBN(0x60c14f3c, 0xaa0bb3c6), TOBN(0x220f448a, 0xb8216094),
++     TOBN(0x4fe7ee31, 0xb0e63d34), TOBN(0xf4600572, 0xa9e54fab),
++     TOBN(0xc0493334, 0xd5e7b5a4), TOBN(0x8589fb92, 0x06d54831),
++     TOBN(0xaa70f5cc, 0x6583553a), TOBN(0x0879094a, 0xe25649e5),
++     TOBN(0xcc904507, 0x10044652), TOBN(0xebb0696d, 0x02541c4f),
++     TOBN(0x5a171fde, 0xb9718710), TOBN(0x38f1bed8, 0xf374a9f5),
++     TOBN(0xc8c582e1, 0xba39bdc1), TOBN(0xfc457b0a, 0x908cc0ce),
++     TOBN(0x9a187fd4, 0x883841e2), TOBN(0x8ec25b39, 0x38725381),
++     TOBN(0x2553ed05, 0x96f84395), TOBN(0x095c7661, 0x6f6c6897),
++     TOBN(0x917ac85c, 0x4bdc5610), TOBN(0xb2885fe4, 0x179eb301),
++     TOBN(0x5fc65547, 0x8b78bdcc), TOBN(0x4a9fc893, 0xe59e4699),
++     TOBN(0xbb7ff0cd, 0x3ce299af), TOBN(0x195be9b3, 0xadf38b20),
++     TOBN(0x6a929c87, 0xd38ddb8f), TOBN(0x55fcc99c, 0xb21a51b9),
++     TOBN(0x2b695b4c, 0x721a4593), TOBN(0xed1e9a15, 0x768eaac2),
++     TOBN(0xfb63d71c, 0x7489f914), TOBN(0xf98ba31c, 0x78118910),
++     TOBN(0x80291373, 0x9b128eb4), TOBN(0x7801214e, 0xd448af4a),
++     TOBN(0xdbd2e22b, 0x55418dd3), TOBN(0xeffb3c0d, 0xd3998242),
++     TOBN(0xdfa6077c, 0xc7bf3827), TOBN(0xf2165bcb, 0x47f8238f),
++     TOBN(0xfe37cf68, 0x8564d554), TOBN(0xe5f825c4, 0x0a81fb98),
++     TOBN(0x43cc4f67, 0xffed4d6f), TOBN(0xbc609578, 0xb50a34b0),
++     TOBN(0x8aa8fcf9, 0x5041faf1), TOBN(0x5659f053, 0x651773b6),
++     TOBN(0xe87582c3, 0x6044d63b), TOBN(0xa6089409, 0x0cdb0ca0),
++     TOBN(0x8c993e0f, 0xbfb2bcf6), TOBN(0xfc64a719, 0x45985cfc),
++     TOBN(0x15c4da80, 0x83dbedba), TOBN(0x804ae112, 0x2be67df7),
++     TOBN(0xda4c9658, 0xa23defde), TOBN(0x12002ddd, 0x5156e0d3),
++     TOBN(0xe68eae89, 0x5dd21b96), TOBN(0x8b99f28b, 0xcf44624d),
++     TOBN(0x0ae00808, 0x1ec8897a), TOBN(0xdd0a9303, 0x6712f76e),
++     TOBN(0x96237522, 0x4e233de4), TOBN(0x192445b1, 0x2b36a8a5),
++     TOBN(0xabf9ff74, 0x023993d9), TOBN(0x21f37bf4, 0x2aad4a8f),
++     TOBN(0x340a4349, 0xf8bd2bbd), TOBN(0x1d902cd9, 0x4868195d),
++     TOBN(0x3d27bbf1, 0xe5fdb6f1), TOBN(0x7a5ab088, 0x124f9f1c),
++     TOBN(0xc466ab06, 0xf7a09e03), TOBN(0x2f8a1977, 0x31f2c123),
++     TOBN(0xda355dc7, 0x041b6657), TOBN(0xcb840d12, 0x8ece2a7c),
++     TOBN(0xb600ad9f, 0x7db32675), TOBN(0x78fea133, 0x07a06f1b),
++     TOBN(0x5d032269, 0xb31f6094), TOBN(0x07753ef5, 0x83ec37aa),
++     TOBN(0x03485aed, 0x9c0bea78), TOBN(0x41bb3989, 0xbc3f4524),
++     TOBN(0x09403761, 0x697f726d), TOBN(0x6109beb3, 0xdf394820),
++     TOBN(0x804111ea, 0x3b6d1145), TOBN(0xb6271ea9, 0xa8582654),
++     TOBN(0x619615e6, 0x24e66562), TOBN(0xa2554945, 0xd7b6ad9c),
++     TOBN(0xd9c4985e, 0x99bfe35f), TOBN(0x9770ccc0, 0x7b51cdf6),
++     TOBN(0x7c327013, 0x92881832), TOBN(0x8777d45f, 0x286b26d1),
++     TOBN(0x9bbeda22, 0xd847999d), TOBN(0x03aa33b6, 0xc3525d32),
++     TOBN(0x4b7b96d4, 0x28a959a1), TOBN(0xbb3786e5, 0x31e5d234),
++     TOBN(0xaeb5d3ce, 0x6961f247), TOBN(0x20aa85af, 0x02f93d3f),
++     TOBN(0x9cd1ad3d, 0xd7a7ae4f), TOBN(0xbf6688f0, 0x781adaa8),
++     TOBN(0xb1b40e86, 0x7469cead), TOBN(0x1904c524, 0x309fca48),
++     TOBN(0x9b7312af, 0x4b54bbc7), TOBN(0xbe24bf8f, 0x593affa2),
++     TOBN(0xbe5e0790, 0xbd98764b), TOBN(0xa0f45f17, 0xa26e299e),
++     TOBN(0x4af0d2c2, 0x6b8fe4c7), TOBN(0xef170db1, 0x8ae8a3e6),
++     TOBN(0x0e8d61a0, 0x29e0ccc1), TOBN(0xcd53e87e, 0x60ad36ca),
++     TOBN(0x328c6623, 0xc8173822), TOBN(0x7ee1767d, 0xa496be55),
++     TOBN(0x89f13259, 0x648945af), TOBN(0x9e45a5fd, 0x25c8009c),
++     TOBN(0xaf2febd9, 0x1f61ab8c), TOBN(0x43f6bc86, 0x8a275385),
++     TOBN(0x87792348, 0xf2142e79), TOBN(0x17d89259, 0xc6e6238a),
++     TOBN(0x7536d2f6, 0x4a839d9b), TOBN(0x1f428fce, 0x76a1fbdc),
++     TOBN(0x1c109601, 0x0db06dfe), TOBN(0xbfc16bc1, 0x50a3a3cc),
++     TOBN(0xf9cbd9ec, 0x9b30f41b), TOBN(0x5b5da0d6, 0x00138cce),
++     TOBN(0xec1d0a48, 0x56ef96a7), TOBN(0xb47eb848, 0x982bf842),
++     TOBN(0x66deae32, 0xec3f700d), TOBN(0x4e43c42c, 0xaa1181e0),
++     TOBN(0xa1d72a31, 0xd1a4aa2a), TOBN(0x440d4668, 0xc004f3ce),
++     TOBN(0x0d6a2d3b, 0x45fe8a7a), TOBN(0x820e52e2, 0xfb128365),
++     TOBN(0x29ac5fcf, 0x25e51b09), TOBN(0x180cd2bf, 0x2023d159),
++     TOBN(0xa9892171, 0xa1ebf90e), TOBN(0xf97c4c87, 0x7c132181),
++     TOBN(0x9f1dc724, 0xc03dbb7e), TOBN(0xae043765, 0x018cbbe4),
++     TOBN(0xfb0b2a36, 0x0767d153), TOBN(0xa8e2f4d6, 0x249cbaeb),
++     TOBN(0x172a5247, 0xd95ea168), TOBN(0x1758fada, 0x2970764a),
++     TOBN(0xac803a51, 0x1d978169), TOBN(0x299cfe2e, 0xde77e01b),
++     TOBN(0x652a1e17, 0xb0a98927), TOBN(0x2e26e1d1, 0x20014495),
++     TOBN(0x7ae0af9f, 0x7175b56a), TOBN(0xc2e22a80, 0xd64b9f95),
++     TOBN(0x4d0ff9fb, 0xd90a060a), TOBN(0x496a27db, 0xbaf38085),
++     TOBN(0x32305401, 0xda776bcf), TOBN(0xb8cdcef6, 0x725f209e),
++     TOBN(0x61ba0f37, 0x436a0bba), TOBN(0x263fa108, 0x76860049),
++     TOBN(0x92beb98e, 0xda3542cf), TOBN(0xa2d4d14a, 0xd5849538),
++     TOBN(0x989b9d68, 0x12e9a1bc), TOBN(0x61d9075c, 0x5f6e3268),
++     TOBN(0x352c6aa9, 0x99ace638), TOBN(0xde4e4a55, 0x920f43ff),
++     TOBN(0xe5e4144a, 0xd673c017), TOBN(0x667417ae, 0x6f6e05ea),
++     TOBN(0x613416ae, 0xdcd1bd56), TOBN(0x5eb36201, 0x86693711),
++     TOBN(0x2d7bc504, 0x3a1aa914), TOBN(0x175a1299, 0x76dc5975),
++     TOBN(0xe900e0f2, 0x3fc8125c), TOBN(0x569ef68c, 0x11198875),
++     TOBN(0x9012db63, 0x63a113b4), TOBN(0xe3bd3f56, 0x98835766),
++     TOBN(0xa5c94a52, 0x76412dea), TOBN(0xad9e2a09, 0xaa735e5c),
++     TOBN(0x405a984c, 0x508b65e9), TOBN(0xbde4a1d1, 0x6df1a0d1),
++     TOBN(0x1a9433a1, 0xdfba80da), TOBN(0xe9192ff9, 0x9440ad2e),
++     TOBN(0x9f649696, 0x5099fe92), TOBN(0x25ddb65c, 0x0b27a54a),
++     TOBN(0x178279dd, 0xc590da61), TOBN(0x5479a999, 0xfbde681a),
++     TOBN(0xd0e84e05, 0x013fe162), TOBN(0xbe11dc92, 0x632d471b),
++     TOBN(0xdf0b0c45, 0xfc0e089f), TOBN(0x04fb15b0, 0x4c144025),
++     TOBN(0xa61d5fc2, 0x13c99927), TOBN(0xa033e9e0, 0x3de2eb35),
++     TOBN(0xf8185d5c, 0xb8dacbb4), TOBN(0x9a88e265, 0x8644549d),
++     TOBN(0xf717af62, 0x54671ff6), TOBN(0x4bd4241b, 0x5fa58603),
++     TOBN(0x06fba40b, 0xe67773c0), TOBN(0xc1d933d2, 0x6a2847e9),
++     TOBN(0xf4f5acf3, 0x689e2c70), TOBN(0x92aab0e7, 0x46bafd31),
++     TOBN(0x798d76aa, 0x3473f6e5), TOBN(0xcc6641db, 0x93141934),
++     TOBN(0xcae27757, 0xd31e535e), TOBN(0x04cc43b6, 0x87c2ee11),
++     TOBN(0x8d1f9675, 0x2e029ffa), TOBN(0xc2150672, 0xe4cc7a2c),
++     TOBN(0x3b03c1e0, 0x8d68b013), TOBN(0xa9d6816f, 0xedf298f3),
++     TOBN(0x1bfbb529, 0xa2804464), TOBN(0x95a52fae, 0x5db22125),
++     TOBN(0x55b32160, 0x0e1cb64e), TOBN(0x004828f6, 0x7e7fc9fe),
++     TOBN(0x13394b82, 0x1bb0fb93), TOBN(0xb6293a2d, 0x35f1a920),
++     TOBN(0xde35ef21, 0xd145d2d9), TOBN(0xbe6225b3, 0xbb8fa603),
++     TOBN(0x00fc8f6b, 0x32cf252d), TOBN(0xa28e52e6, 0x117cf8c2),
++     TOBN(0x9d1dc89b, 0x4c371e6d), TOBN(0xcebe0675, 0x36ef0f28),
++     TOBN(0x5de05d09, 0xa4292f81), TOBN(0xa8303593, 0x353e3083),
++     TOBN(0xa1715b0a, 0x7e37a9bb), TOBN(0x8c56f61e, 0x2b8faec3),
++     TOBN(0x52507431, 0x33c9b102), TOBN(0x0130cefc, 0xa44431f0),
++     TOBN(0x56039fa0, 0xbd865cfb), TOBN(0x4b03e578, 0xbc5f1dd7),
++     TOBN(0x40edf2e4, 0xbabe7224), TOBN(0xc752496d, 0x3a1988f6),
++     TOBN(0xd1572d3b, 0x564beb6b), TOBN(0x0db1d110, 0x39a1c608),
++     TOBN(0x568d1934, 0x16f60126), TOBN(0x05ae9668, 0xf354af33),
++     TOBN(0x19de6d37, 0xc92544f2), TOBN(0xcc084353, 0xa35837d5),
++     TOBN(0xcbb6869c, 0x1a514ece), TOBN(0xb633e728, 0x2e1d1066),
++     TOBN(0xf15dd69f, 0x936c581c), TOBN(0x96e7b8ce, 0x7439c4f9),
++     TOBN(0x5e676f48, 0x2e448a5b), TOBN(0xb2ca7d5b, 0xfd916bbb),
++     TOBN(0xd55a2541, 0xf5024025), TOBN(0x47bc5769, 0xe4c2d937),
++     TOBN(0x7d31b92a, 0x0362189f), TOBN(0x83f3086e, 0xef7816f9),
++     TOBN(0xf9f46d94, 0xb587579a), TOBN(0xec2d22d8, 0x30e76c5f),
++     TOBN(0x27d57461, 0xb000ffcf), TOBN(0xbb7e65f9, 0x364ffc2c),
++     TOBN(0x7c7c9477, 0x6652a220), TOBN(0x61618f89, 0xd696c981),
++     TOBN(0x5021701d, 0x89effff3), TOBN(0xf2c8ff8e, 0x7c314163),
++     TOBN(0x2da413ad, 0x8efb4d3e), TOBN(0x937b5adf, 0xce176d95),
++     TOBN(0x22867d34, 0x2a67d51c), TOBN(0x262b9b10, 0x18eb3ac9),
++     TOBN(0x4e314fe4, 0xc43ff28b), TOBN(0x76476627, 0x6a664e7a),
++     TOBN(0x3e90e40b, 0xb7a565c2), TOBN(0x8588993a, 0xc1acf831),
++     TOBN(0xd7b501d6, 0x8f938829), TOBN(0x996627ee, 0x3edd7d4c),
++     TOBN(0x37d44a62, 0x90cd34c7), TOBN(0xa8327499, 0xf3833e8d),
++     TOBN(0x2e18917d, 0x4bf50353), TOBN(0x85dd726b, 0x556765fb),
++     TOBN(0x54fe65d6, 0x93d5ab66), TOBN(0x3ddbaced, 0x915c25fe),
++     TOBN(0xa799d9a4, 0x12f22e85), TOBN(0xe2a24867, 0x6d06f6bc),
++     TOBN(0xf4f1ee56, 0x43ca1637), TOBN(0xfda2828b, 0x61ece30a),
++     TOBN(0x758c1a3e, 0xa2dee7a6), TOBN(0xdcde2f3c, 0x734b2284),
++     TOBN(0xaba445d2, 0x4eaba6ad), TOBN(0x35aaf668, 0x76cee0a7),
++     TOBN(0x7e0b04a9, 0xe5aa049a), TOBN(0xe74083ad, 0x91103e84),
++     TOBN(0xbeb183ce, 0x40afecc3), TOBN(0x6b89de9f, 0xea043f7a),}
++    ,
++    {TOBN(0x0e299d23, 0xfe67ba66), TOBN(0x91450760, 0x93cf2f34),
++     TOBN(0xf45b5ea9, 0x97fcf913), TOBN(0x5be00843, 0x8bd7ddda),
++     TOBN(0x358c3e05, 0xd53ff04d), TOBN(0xbf7ccdc3, 0x5de91ef7),
++     TOBN(0xad684dbf, 0xb69ec1a0), TOBN(0x367e7cf2, 0x801fd997),
++     TOBN(0x0ca1f3b7, 0xb0dc8595), TOBN(0x27de4608, 0x9f1d9f2e),
++     TOBN(0x1af3bf39, 0xbadd82a7), TOBN(0x79356a79, 0x65862448),
++     TOBN(0xc0602345, 0xf5f9a052), TOBN(0x1a8b0f89, 0x139a42f9),
++     TOBN(0xb53eee42, 0x844d40fc), TOBN(0x93b0bfe5, 0x4e5b6368),
++     TOBN(0x5434dd02, 0xc024789c), TOBN(0x90dca9ea, 0x41b57bfc),
++     TOBN(0x8aa898e2, 0x243398df), TOBN(0xf607c834, 0x894a94bb),
++     TOBN(0xbb07be97, 0xc2c99b76), TOBN(0x6576ba67, 0x18c29302),
++     TOBN(0x3d79efcc, 0xe703a88c), TOBN(0xf259ced7, 0xb6a0d106),
++     TOBN(0x0f893a5d, 0xc8de610b), TOBN(0xe8c515fb, 0x67e223ce),
++     TOBN(0x7774bfa6, 0x4ead6dc5), TOBN(0x89d20f95, 0x925c728f),
++     TOBN(0x7a1e0966, 0x098583ce), TOBN(0xa2eedb94, 0x93f2a7d7),
++     TOBN(0x1b282097, 0x4c304d4a), TOBN(0x0842e3da, 0xc077282d),
++     TOBN(0xe4d972a3, 0x3b9e2d7b), TOBN(0x7cc60b27, 0xc48218ff),
++     TOBN(0x8fc70838, 0x84149d91), TOBN(0x5c04346f, 0x2f461ecc),
++     TOBN(0xebe9fdf2, 0x614650a9), TOBN(0x5e35b537, 0xc1f666ac),
++     TOBN(0x645613d1, 0x88babc83), TOBN(0x88cace3a, 0xc5e1c93e),
++     TOBN(0x209ca375, 0x3de92e23), TOBN(0xccb03cc8, 0x5fbbb6e3),
++     TOBN(0xccb90f03, 0xd7b1487e), TOBN(0xfa9c2a38, 0xc710941f),
++     TOBN(0x756c3823, 0x6724ceed), TOBN(0x3a902258, 0x192d0323),
++     TOBN(0xb150e519, 0xea5e038e), TOBN(0xdcba2865, 0xc7427591),
++     TOBN(0xe549237f, 0x78890732), TOBN(0xc443bef9, 0x53fcb4d9),
++     TOBN(0x9884d8a6, 0xeb3480d6), TOBN(0x8a35b6a1, 0x3048b186),
++     TOBN(0xb4e44716, 0x65e9a90a), TOBN(0x45bf380d, 0x653006c0),
++     TOBN(0x8f3f820d, 0x4fe9ae3b), TOBN(0x244a35a0, 0x979a3b71),
++     TOBN(0xa1010e9d, 0x74cd06ff), TOBN(0x9c17c7df, 0xaca3eeac),
++     TOBN(0x74c86cd3, 0x8063aa2b), TOBN(0x8595c4b3, 0x734614ff),
++     TOBN(0xa3de00ca, 0x990f62cc), TOBN(0xd9bed213, 0xca0c3be5),
++     TOBN(0x7886078a, 0xdf8ce9f5), TOBN(0xddb27ce3, 0x5cd44444),
++     TOBN(0xed374a66, 0x58926ddd), TOBN(0x138b2d49, 0x908015b8),
++     TOBN(0x886c6579, 0xde1f7ab8), TOBN(0x888b9aa0, 0xc3020b7a),
++     TOBN(0xd3ec034e, 0x3a96e355), TOBN(0xba65b0b8, 0xf30fbe9a),
++     TOBN(0x064c8e50, 0xff21367a), TOBN(0x1f508ea4, 0x0b04b46e),
++     TOBN(0x98561a49, 0x747c866c), TOBN(0xbbb1e5fe, 0x0518a062),
++     TOBN(0x20ff4e8b, 0xecdc3608), TOBN(0x7f55cded, 0x20184027),
++     TOBN(0x8d73ec95, 0xf38c85f0), TOBN(0x5b589fdf, 0x8bc3b8c3),
++     TOBN(0xbe95dd98, 0x0f12b66f), TOBN(0xf5bd1a09, 0x0e338e01),
++     TOBN(0x65163ae5, 0x5e915918), TOBN(0x6158d6d9, 0x86f8a46b),
++     TOBN(0x8466b538, 0xeeebf99c), TOBN(0xca8761f6, 0xbca477ef),
++     TOBN(0xaf3449c2, 0x9ebbc601), TOBN(0xef3b0f41, 0xe0c3ae2f),
++     TOBN(0xaa6c577d, 0x5de63752), TOBN(0xe9166601, 0x64682a51),
++     TOBN(0x5a3097be, 0xfc15aa1e), TOBN(0x40d12548, 0xb54b0745),
++     TOBN(0x5bad4706, 0x519a5f12), TOBN(0xed03f717, 0xa439dee6),
++     TOBN(0x0794bb6c, 0x4a02c499), TOBN(0xf725083d, 0xcffe71d2),
++     TOBN(0x2cad7519, 0x0f3adcaf), TOBN(0x7f68ea1c, 0x43729310),
++     TOBN(0xe747c8c7, 0xb7ffd977), TOBN(0xec104c35, 0x80761a22),
++     TOBN(0x8395ebaf, 0x5a3ffb83), TOBN(0xfb3261f4, 0xe4b63db7),
++     TOBN(0x53544960, 0xd883e544), TOBN(0x13520d70, 0x8cc2eeb8),
++     TOBN(0x08f6337b, 0xd3d65f99), TOBN(0x83997db2, 0x781cf95b),
++     TOBN(0xce6ff106, 0x0dbd2c01), TOBN(0x4f8eea6b, 0x1f9ce934),
++     TOBN(0x546f7c4b, 0x0e993921), TOBN(0x6236a324, 0x5e753fc7),
++     TOBN(0x65a41f84, 0xa16022e9), TOBN(0x0c18d878, 0x43d1dbb2),
++     TOBN(0x73c55640, 0x2d4cef9c), TOBN(0xa0428108, 0x70444c74),
++     TOBN(0x68e4f15e, 0x9afdfb3c), TOBN(0x49a56143, 0x5bdfb6df),
++     TOBN(0xa9bc1bd4, 0x5f823d97), TOBN(0xbceb5970, 0xea111c2a),
++     TOBN(0x366b455f, 0xb269bbc4), TOBN(0x7cd85e1e, 0xe9bc5d62),
++     TOBN(0xc743c41c, 0x4f18b086), TOBN(0xa4b40990, 0x95294fb9),
++     TOBN(0x9c7c581d, 0x26ee8382), TOBN(0xcf17dcc5, 0x359d638e),
++     TOBN(0xee8273ab, 0xb728ae3d), TOBN(0x1d112926, 0xf821f047),
++     TOBN(0x11498477, 0x50491a74), TOBN(0x687fa761, 0xfde0dfb9),
++     TOBN(0x2c258022, 0x7ea435ab), TOBN(0x6b8bdb94, 0x91ce7e3f),
++     TOBN(0x4c5b5dc9, 0x3bf834aa), TOBN(0x04371819, 0x4f6c7e4b),
++     TOBN(0xc284e00a, 0x3736bcad), TOBN(0x0d881118, 0x21ae8f8d),
++     TOBN(0xf9cf0f82, 0xf48c8e33), TOBN(0xa11fd075, 0xa1bf40db),
++     TOBN(0xdceab0de, 0xdc2733e5), TOBN(0xc560a8b5, 0x8e986bd7),
++     TOBN(0x48dd1fe2, 0x3929d097), TOBN(0x3885b290, 0x92f188f1),
++     TOBN(0x0f2ae613, 0xda6fcdac), TOBN(0x9054303e, 0xb662a46c),
++     TOBN(0xb6871e44, 0x0738042a), TOBN(0x98e6a977, 0xbdaf6449),
++     TOBN(0xd8bc0650, 0xd1c9df1b), TOBN(0xef3d6451, 0x36e098f9),
++     TOBN(0x03fbae82, 0xb6d72d28), TOBN(0x77ca9db1, 0xf5d84080),
++     TOBN(0x8a112cff, 0xa58efc1c), TOBN(0x518d761c, 0xc564cb4a),
++     TOBN(0x69b5740e, 0xf0d1b5ce), TOBN(0x717039cc, 0xe9eb1785),
++     TOBN(0x3fe29f90, 0x22f53382), TOBN(0x8e54ba56, 0x6bc7c95c),
++     TOBN(0x9c806d8a, 0xf7f91d0f), TOBN(0x3b61b0f1, 0xa82a5728),
++     TOBN(0x4640032d, 0x94d76754), TOBN(0x273eb5de, 0x47d834c6),
++     TOBN(0x2988abf7, 0x7b4e4d53), TOBN(0xb7ce66bf, 0xde401777),
++     TOBN(0x9fba6b32, 0x715071b3), TOBN(0x82413c24, 0xad3a1a98),
++     TOBN(0x5b7fc8c4, 0xe0e8ad93), TOBN(0xb5679aee, 0x5fab868d),
++     TOBN(0xb1f9d2fa, 0x2b3946f3), TOBN(0x458897dc, 0x5685b50a),
++     TOBN(0x1e98c930, 0x89d0caf3), TOBN(0x39564c5f, 0x78642e92),
++     TOBN(0x1b77729a, 0x0dbdaf18), TOBN(0xf9170722, 0x579e82e6),
++     TOBN(0x680c0317, 0xe4515fa5), TOBN(0xf85cff84, 0xfb0c790f),
++     TOBN(0xc7a82aab, 0x6d2e0765), TOBN(0x7446bca9, 0x35c82b32),
++     TOBN(0x5de607aa, 0x6d63184f), TOBN(0x7c1a46a8, 0x262803a6),
++     TOBN(0xd218313d, 0xaebe8035), TOBN(0x92113ffd, 0xc73c51f8),
++     TOBN(0x4b38e083, 0x12e7e46c), TOBN(0x69d0a37a, 0x56126bd5),
++     TOBN(0xfb3f324b, 0x73c07e04), TOBN(0xa0c22f67, 0x8fda7267),
++     TOBN(0x8f2c0051, 0x4d2c7d8f), TOBN(0xbc45ced3, 0xcbe2cae5),
++     TOBN(0xe1c6cf07, 0xa8f0f277), TOBN(0xbc392312, 0x1eb99a98),
++     TOBN(0x75537b7e, 0x3cc8ac85), TOBN(0x8d725f57, 0xdd02753b),
++     TOBN(0xfd05ff64, 0xb737df2f), TOBN(0x55fe8712, 0xf6d2531d),
++     TOBN(0x57ce04a9, 0x6ab6b01c), TOBN(0x69a02a89, 0x7cd93724),
++     TOBN(0x4f82ac35, 0xcf86699b), TOBN(0x8242d3ad, 0x9cb4b232),
++     TOBN(0x713d0f65, 0xd62105e5), TOBN(0xbb222bfa, 0x2d29be61),
++     TOBN(0xf2f9a79e, 0x6cfbef09), TOBN(0xfc24d8d3, 0xd5d6782f),
++     TOBN(0x5db77085, 0xd4129967), TOBN(0xdb81c3cc, 0xdc3c2a43),
++     TOBN(0x9d655fc0, 0x05d8d9a3), TOBN(0x3f5d057a, 0x54298026),
++     TOBN(0x1157f56d, 0x88c54694), TOBN(0xb26baba5, 0x9b09573e),
++     TOBN(0x2cab03b0, 0x22adffd1), TOBN(0x60a412c8, 0xdd69f383),
++     TOBN(0xed76e98b, 0x54b25039), TOBN(0xd4ee67d3, 0x687e714d),
++     TOBN(0x87739648, 0x7b00b594), TOBN(0xce419775, 0xc9ef709b),
++     TOBN(0x40f76f85, 0x1c203a40), TOBN(0x30d352d6, 0xeafd8f91),
++     TOBN(0xaf196d3d, 0x95578dd2), TOBN(0xea4bb3d7, 0x77cc3f3d),
++     TOBN(0x42a5bd03, 0xb98e782b), TOBN(0xac958c40, 0x0624920d),
++     TOBN(0xb838134c, 0xfc56fcc8), TOBN(0x86ec4ccf, 0x89572e5e),
++     TOBN(0x69c43526, 0x9be47be0), TOBN(0x323b7dd8, 0xcb28fea1),
++     TOBN(0xfa5538ba, 0x3a6c67e5), TOBN(0xef921d70, 0x1d378e46),
++     TOBN(0xf92961fc, 0x3c4b880e), TOBN(0x3f6f914e, 0x98940a67),
++     TOBN(0xa990eb0a, 0xfef0ff39), TOBN(0xa6c2920f, 0xf0eeff9c),
++     TOBN(0xca804166, 0x51b8d9a3), TOBN(0x42531bc9, 0x0ffb0db1),
++     TOBN(0x72ce4718, 0xaa82e7ce), TOBN(0x6e199913, 0xdf574741),
++     TOBN(0xd5f1b13d, 0xd5d36946), TOBN(0x8255dc65, 0xf68f0194),
++     TOBN(0xdc9df4cd, 0x8710d230), TOBN(0x3453c20f, 0x138c1988),
++     TOBN(0x9af98dc0, 0x89a6ef01), TOBN(0x4dbcc3f0, 0x9857df85),
++     TOBN(0x34805601, 0x5c1ad924), TOBN(0x40448da5, 0xd0493046),
++     TOBN(0xf629926d, 0x4ee343e2), TOBN(0x6343f1bd, 0x90e8a301),
++     TOBN(0xefc93491, 0x40815b3f), TOBN(0xf882a423, 0xde8f66fb),
++     TOBN(0x3a12d5f4, 0xe7db9f57), TOBN(0x7dfba38a, 0x3c384c27),
++     TOBN(0x7a904bfd, 0x6fc660b1), TOBN(0xeb6c5db3, 0x2773b21c),
++     TOBN(0xc350ee66, 0x1cdfe049), TOBN(0x9baac0ce, 0x44540f29),
++     TOBN(0xbc57b6ab, 0xa5ec6aad), TOBN(0x167ce8c3, 0x0a7c1baa),
++     TOBN(0xb23a03a5, 0x53fb2b56), TOBN(0x6ce141e7, 0x4e057f78),
++     TOBN(0x796525c3, 0x89e490d9), TOBN(0x0bc95725, 0xa31a7e75),
++     TOBN(0x1ec56791, 0x1220fd06), TOBN(0x716e3a3c, 0x408b0bd6),
++     TOBN(0x31cd6bf7, 0xe8ebeba9), TOBN(0xa7326ca6, 0xbee6b670),
++     TOBN(0x3d9f851c, 0xcd090c43), TOBN(0x561e8f13, 0xf12c3988),
++     TOBN(0x50490b6a, 0x904b7be4), TOBN(0x61690ce1, 0x0410737b),
++     TOBN(0x299e9a37, 0x0f009052), TOBN(0x258758f0, 0xf026092e),
++     TOBN(0x9fa255f3, 0xfdfcdc0f), TOBN(0xdbc9fb1f, 0xc0e1bcd2),
++     TOBN(0x35f9dd6e, 0x24651840), TOBN(0xdca45a84, 0xa5c59abc),
++     TOBN(0x103d396f, 0xecca4938), TOBN(0x4532da0a, 0xb97b3f29),
++     TOBN(0xc4135ea5, 0x1999a6bf), TOBN(0x3aa9505a, 0x5e6bf2ee),
++     TOBN(0xf77cef06, 0x3f5be093), TOBN(0x97d1a0f8, 0xa943152e),
++     TOBN(0x2cb0ebba, 0x2e1c21dd), TOBN(0xf41b29fc, 0x2c6797c4),
++     TOBN(0xc6e17321, 0xb300101f), TOBN(0x4422b0e9, 0xd0d79a89),
++     TOBN(0x49e4901c, 0x92f1bfc4), TOBN(0x06ab1f8f, 0xe1e10ed9),
++     TOBN(0x84d35577, 0xdb2926b8), TOBN(0xca349d39, 0x356e8ec2),
++     TOBN(0x70b63d32, 0x343bf1a9), TOBN(0x8fd3bd28, 0x37d1a6b1),
++     TOBN(0x0454879c, 0x316865b4), TOBN(0xee959ff6, 0xc458efa2),
++     TOBN(0x0461dcf8, 0x9706dc3f), TOBN(0x737db0e2, 0x164e4b2e),
++     TOBN(0x09262680, 0x2f8843c8), TOBN(0x54498bbc, 0x7745e6f6),
++     TOBN(0x359473fa, 0xa29e24af), TOBN(0xfcc3c454, 0x70aa87a1),
++     TOBN(0xfd2c4bf5, 0x00573ace), TOBN(0xb65b514e, 0x28dd1965),
++     TOBN(0xe46ae7cf, 0x2193e393), TOBN(0x60e9a4e1, 0xf5444d97),
++     TOBN(0xe7594e96, 0x00ff38ed), TOBN(0x43d84d2f, 0x0a0e0f02),
++     TOBN(0x8b6db141, 0xee398a21), TOBN(0xb88a56ae, 0xe3bcc5be),
++     TOBN(0x0a1aa52f, 0x373460ea), TOBN(0x20da1a56, 0x160bb19b),
++     TOBN(0xfb54999d, 0x65bf0384), TOBN(0x71a14d24, 0x5d5a180e),
++     TOBN(0xbc44db7b, 0x21737b04), TOBN(0xd84fcb18, 0x01dd8e92),
++     TOBN(0x80de937b, 0xfa44b479), TOBN(0x53505499, 0x5c98fd4f),
++     TOBN(0x1edb12ab, 0x28f08727), TOBN(0x4c58b582, 0xa5f3ef53),
++     TOBN(0xbfb236d8, 0x8327f246), TOBN(0xc3a3bfaa, 0x4d7df320),
++     TOBN(0xecd96c59, 0xb96024f2), TOBN(0xfc293a53, 0x7f4e0433),
++     TOBN(0x5341352b, 0x5acf6e10), TOBN(0xc50343fd, 0xafe652c3),
++     TOBN(0x4af3792d, 0x18577a7f), TOBN(0xe1a4c617, 0xaf16823d),
++     TOBN(0x9b26d0cd, 0x33425d0a), TOBN(0x306399ed, 0x9b7bc47f),
++     TOBN(0x2a792f33, 0x706bb20b), TOBN(0x31219614, 0x98111055),
++     TOBN(0x864ec064, 0x87f5d28b), TOBN(0x11392d91, 0x962277fd),
++     TOBN(0xb5aa7942, 0xbb6aed5f), TOBN(0x080094dc, 0x47e799d9),
++     TOBN(0x4afa588c, 0x208ba19b), TOBN(0xd3e7570f, 0x8512f284),
++     TOBN(0xcbae64e6, 0x02f5799a), TOBN(0xdeebe7ef, 0x514b9492),
++     TOBN(0x30300f98, 0xe5c298ff), TOBN(0x17f561be, 0x3678361f),
++     TOBN(0xf52ff312, 0x98cb9a16), TOBN(0x6233c3bc, 0x5562d490),
++     TOBN(0x7bfa15a1, 0x92e3a2cb), TOBN(0x961bcfd1, 0xe6365119),
++     TOBN(0x3bdd29bf, 0x2c8c53b1), TOBN(0x739704df, 0x822844ba),
++     TOBN(0x7dacfb58, 0x7e7b754b), TOBN(0x23360791, 0xa806c9b9),
++     TOBN(0xe7eb88c9, 0x23504452), TOBN(0x2983e996, 0x852c1783),
++     TOBN(0xdd4ae529, 0x958d881d), TOBN(0x026bae03, 0x262c7b3c),
++     TOBN(0x3a6f9193, 0x960b52d1), TOBN(0xd0980f90, 0x92696cfb),
++     TOBN(0x4c1f428c, 0xd5f30851), TOBN(0x94dfed27, 0x2a4f6630),
++     TOBN(0x4df53772, 0xfc5d48a4), TOBN(0xdd2d5a2f, 0x933260ce),
++     TOBN(0x574115bd, 0xd44cc7a5), TOBN(0x4ba6b20d, 0xbd12533a),
++     TOBN(0x30e93cb8, 0x243057c9), TOBN(0x794c486a, 0x14de320e),
++     TOBN(0xe925d4ce, 0xf21496e4), TOBN(0xf951d198, 0xec696331),
++     TOBN(0x9810e2de, 0x3e8d812f), TOBN(0xd0a47259, 0x389294ab),
++     TOBN(0x513ba2b5, 0x0e3bab66), TOBN(0x462caff5, 0xabad306f),
++     TOBN(0xe2dc6d59, 0xaf04c49e), TOBN(0x1aeb8750, 0xe0b84b0b),
++     TOBN(0xc034f12f, 0x2f7d0ca2), TOBN(0x6d2e8128, 0xe06acf2f),
++     TOBN(0x801f4f83, 0x21facc2f), TOBN(0xa1170c03, 0xf40ef607),
++     TOBN(0xfe0a1d4f, 0x7805a99c), TOBN(0xbde56a36, 0xcc26aba5),
++     TOBN(0x5b1629d0, 0x35531f40), TOBN(0xac212c2b, 0x9afa6108),
++     TOBN(0x30a06bf3, 0x15697be5), TOBN(0x6f0545dc, 0x2c63c7c1),
++     TOBN(0x5d8cb842, 0x7ccdadaf), TOBN(0xd52e379b, 0xac7015bb),
++     TOBN(0xc4f56147, 0xf462c23e), TOBN(0xd44a4298, 0x46bc24b0),
++     TOBN(0xbc73d23a, 0xe2856d4f), TOBN(0x61cedd8c, 0x0832bcdf),
++     TOBN(0x60953556, 0x99f241d7), TOBN(0xee4adbd7, 0x001a349d),
++     TOBN(0x0b35bf6a, 0xaa89e491), TOBN(0x7f0076f4, 0x136f7546),
++     TOBN(0xd19a18ba, 0x9264da3d), TOBN(0x6eb2d2cd, 0x62a7a28b),
++     TOBN(0xcdba941f, 0x8761c971), TOBN(0x1550518b, 0xa3be4a5d),
++     TOBN(0xd0e8e2f0, 0x57d0b70c), TOBN(0xeea8612e, 0xcd133ba3),
++     TOBN(0x814670f0, 0x44416aec), TOBN(0x424db6c3, 0x30775061),
++     TOBN(0xd96039d1, 0x16213fd1), TOBN(0xc61e7fa5, 0x18a3478f),
++     TOBN(0xa805bdcc, 0xcb0c5021), TOBN(0xbdd6f3a8, 0x0cc616dd),
++     TOBN(0x06009667, 0x5d97f7e2), TOBN(0x31db0fc1, 0xaf0bf4b6),
++     TOBN(0x23680ed4, 0x5491627a), TOBN(0xb99a3c66, 0x7d741fb1),
++     TOBN(0xe9bb5f55, 0x36b1ff92), TOBN(0x29738577, 0x512b388d),
++     TOBN(0xdb8a2ce7, 0x50fcf263), TOBN(0x385346d4, 0x6c4f7b47),
++     TOBN(0xbe86c5ef, 0x31631f9e), TOBN(0xbf91da21, 0x03a57a29),
++     TOBN(0xc3b1f796, 0x7b23f821), TOBN(0x0f7d00d2, 0x770db354),
++     TOBN(0x8ffc6c3b, 0xd8fe79da), TOBN(0xcc5e8c40, 0xd525c996),
++     TOBN(0x4640991d, 0xcfff632a), TOBN(0x64d97e8c, 0x67112528),
++     TOBN(0xc232d973, 0x02f1cd1e), TOBN(0xce87eacb, 0x1dd212a4),
++     TOBN(0x6e4c8c73, 0xe69802f7), TOBN(0x12ef0290, 0x1fffddbd),
++     TOBN(0x941ec74e, 0x1bcea6e2), TOBN(0xd0b54024, 0x3cb92cbb),
++     TOBN(0x809fb9d4, 0x7e8f9d05), TOBN(0x3bf16159, 0xf2992aae),
++     TOBN(0xad40f279, 0xf8a7a838), TOBN(0x11aea631, 0x05615660),
++     TOBN(0xbf52e6f1, 0xa01f6fa1), TOBN(0xef046995, 0x3dc2aec9),
++     TOBN(0x785dbec9, 0xd8080711), TOBN(0xe1aec60a, 0x9fdedf76),
++     TOBN(0xece797b5, 0xfa21c126), TOBN(0xc66e898f, 0x05e52732),
++     TOBN(0x39bb69c4, 0x08811fdb), TOBN(0x8bfe1ef8, 0x2fc7f082),
++     TOBN(0xc8e7a393, 0x174f4138), TOBN(0xfba8ad1d, 0xd58d1f98),
++     TOBN(0xbc21d0ce, 0xbfd2fd5b), TOBN(0x0b839a82, 0x6ee60d61),
++     TOBN(0xaacf7658, 0xafd22253), TOBN(0xb526bed8, 0xaae396b3),
++     TOBN(0xccc1bbc2, 0x38564464), TOBN(0x9e3ff947, 0x8c45bc73),
++     TOBN(0xcde9bca3, 0x58188a78), TOBN(0x138b8ee0, 0xd73bf8f7),
++     TOBN(0x5c7e234c, 0x4123c489), TOBN(0x66e69368, 0xfa643297),
++     TOBN(0x0629eeee, 0x39a15fa3), TOBN(0x95fab881, 0xa9e2a927),
++     TOBN(0xb2497007, 0xeafbb1e1), TOBN(0xd75c9ce6, 0xe75b7a93),
++     TOBN(0x3558352d, 0xefb68d78), TOBN(0xa2f26699, 0x223f6396),
++     TOBN(0xeb911ecf, 0xe469b17a), TOBN(0x62545779, 0xe72d3ec2),
++     TOBN(0x8ea47de7, 0x82cb113f), TOBN(0xebe4b086, 0x4e1fa98d),
++     TOBN(0xec2d5ed7, 0x8cdfedb1), TOBN(0xa535c077, 0xfe211a74),
++     TOBN(0x9678109b, 0x11d244c5), TOBN(0xf17c8bfb, 0xbe299a76),
++     TOBN(0xb651412e, 0xfb11fbc4), TOBN(0xea0b5482, 0x94ab3f65),
++     TOBN(0xd8dffd95, 0x0cf78243), TOBN(0x2e719e57, 0xce0361d4),
++     TOBN(0x9007f085, 0x304ddc5b), TOBN(0x095e8c6d, 0x4daba2ea),
++     TOBN(0x5a33cdb4, 0x3f9d28a9), TOBN(0x85b95cd8, 0xe2283003),
++     TOBN(0xbcd6c819, 0xb9744733), TOBN(0x29c5f538, 0xfc7f5783),
++     TOBN(0x6c49b2fa, 0xd59038e4), TOBN(0x68349cc1, 0x3bbe1018),
++     TOBN(0xcc490c1d, 0x21830ee5), TOBN(0x36f9c4ee, 0xe9bfa297),
++     TOBN(0x58fd7294, 0x48de1a94), TOBN(0xaadb13a8, 0x4e8f2cdc),
++     TOBN(0x515eaaa0, 0x81313dba), TOBN(0xc76bb468, 0xc2152dd8),
++     TOBN(0x357f8d75, 0xa653dbf8), TOBN(0xe4d8c4d1, 0xb14ac143),
++     TOBN(0xbdb8e675, 0xb055cb40), TOBN(0x898f8e7b, 0x977b5167),
++     TOBN(0xecc65651, 0xb82fb863), TOBN(0x56544814, 0x6d88f01f),
++     TOBN(0xb0928e95, 0x263a75a9), TOBN(0xcfb6836f, 0x1a22fcda),
++     TOBN(0x651d14db, 0x3f3bd37c), TOBN(0x1d3837fb, 0xb6ad4664),
++     TOBN(0x7c5fb538, 0xff4f94ab), TOBN(0x7243c712, 0x6d7fb8f2),
++     TOBN(0xef13d60c, 0xa85c5287), TOBN(0x18cfb7c7, 0x4bb8dd1b),
++     TOBN(0x82f9bfe6, 0x72908219), TOBN(0x35c4592b, 0x9d5144ab),
++     TOBN(0x52734f37, 0x9cf4b42f), TOBN(0x6bac55e7, 0x8c60ddc4),
++     TOBN(0xb5cd811e, 0x94dea0f6), TOBN(0x259ecae4, 0xe18cc1a3),
++     TOBN(0x6a0e836e, 0x15e660f8), TOBN(0x6c639ea6, 0x0e02bff2),
++     TOBN(0x8721b8cb, 0x7e1026fd), TOBN(0x9e73b50b, 0x63261942),
++     TOBN(0xb8c70974, 0x77f01da3), TOBN(0x1839e6a6, 0x8268f57f),
++     TOBN(0x571b9415, 0x5150b805), TOBN(0x1892389e, 0xf92c7097),
++     TOBN(0x8d69c18e, 0x4a084b95), TOBN(0x7014c512, 0xbe5b495c),
++     TOBN(0x4780db36, 0x1b07523c), TOBN(0x2f6219ce, 0x2c1c64fa),
++     TOBN(0xc38b81b0, 0x602c105a), TOBN(0xab4f4f20, 0x5dc8e360),
++     TOBN(0x20d3c982, 0xcf7d62d2), TOBN(0x1f36e29d, 0x23ba8150),
++     TOBN(0x48ae0bf0, 0x92763f9e), TOBN(0x7a527e6b, 0x1d3a7007),
++     TOBN(0xb4a89097, 0x581a85e3), TOBN(0x1f1a520f, 0xdc158be5),
++     TOBN(0xf98db37d, 0x167d726e), TOBN(0x8802786e, 0x1113e862)}
++    ,
++    {TOBN(0xefb2149e, 0x36f09ab0), TOBN(0x03f163ca, 0x4a10bb5b),
++     TOBN(0xd0297045, 0x06e20998), TOBN(0x56f0af00, 0x1b5a3bab),
++     TOBN(0x7af4cfec, 0x70880e0d), TOBN(0x7332a66f, 0xbe3d913f),
++     TOBN(0x32e6c84a, 0x7eceb4bd), TOBN(0xedc4a79a, 0x9c228f55),
++     TOBN(0xc37c7dd0, 0xc55c4496), TOBN(0xa6a96357, 0x25bbabd2),
++     TOBN(0x5b7e63f2, 0xadd7f363), TOBN(0x9dce3782, 0x2e73f1df),
++     TOBN(0xe1e5a16a, 0xb2b91f71), TOBN(0xe4489823, 0x5ba0163c),
++     TOBN(0xf2759c32, 0xf6e515ad), TOBN(0xa5e2f1f8, 0x8615eecf),
++     TOBN(0x74519be7, 0xabded551), TOBN(0x03d358b8, 0xc8b74410),
++     TOBN(0x4d00b10b, 0x0e10d9a9), TOBN(0x6392b0b1, 0x28da52b7),
++     TOBN(0x6744a298, 0x0b75c904), TOBN(0xc305b0ae, 0xa8f7f96c),
++     TOBN(0x042e421d, 0x182cf932), TOBN(0xf6fc5d50, 0x9e4636ca),
++     TOBN(0x795847c9, 0xd64cc78c), TOBN(0x6c50621b, 0x9b6cb27b),
++     TOBN(0x07099bf8, 0xdf8022ab), TOBN(0x48f862eb, 0xc04eda1d),
++     TOBN(0xd12732ed, 0xe1603c16), TOBN(0x19a80e0f, 0x5c9a9450),
++     TOBN(0xe2257f54, 0xb429b4fc), TOBN(0x66d3b2c6, 0x45460515),
++     TOBN(0x6ca4f87e, 0x822e37be), TOBN(0x73f237b4, 0x253bda4e),
++     TOBN(0xf747f3a2, 0x41190aeb), TOBN(0xf06fa36f, 0x804cf284),
++     TOBN(0x0a6bbb6e, 0xfc621c12), TOBN(0x5d624b64, 0x40b80ec6),
++     TOBN(0x4b072425, 0x7ba556f3), TOBN(0x7fa0c354, 0x3e2d20a8),
++     TOBN(0xe921fa31, 0xe3229d41), TOBN(0xa929c652, 0x94531bd4),
++     TOBN(0x84156027, 0xa6d38209), TOBN(0xf3d69f73, 0x6bdb97bd),
++     TOBN(0x8906d19a, 0x16833631), TOBN(0x68a34c2e, 0x03d51be3),
++     TOBN(0xcb59583b, 0x0e511cd8), TOBN(0x99ce6bfd, 0xfdc132a8),
++     TOBN(0x3facdaaa, 0xffcdb463), TOBN(0x658bbc1a, 0x34a38b08),
++     TOBN(0x12a801f8, 0xf1a9078d), TOBN(0x1567bcf9, 0x6ab855de),
++     TOBN(0xe08498e0, 0x3572359b), TOBN(0xcf0353e5, 0x8659e68b),
++     TOBN(0xbb86e9c8, 0x7d23807c), TOBN(0xbc08728d, 0x2198e8a2),
++     TOBN(0x8de2b7bc, 0x453cadd6), TOBN(0x203900a7, 0xbc0bc1f8),
++     TOBN(0xbcd86e47, 0xa6abd3af), TOBN(0x911cac12, 0x8502effb),
++     TOBN(0x2d550242, 0xec965469), TOBN(0x0e9f7692, 0x29e0017e),
++     TOBN(0x633f078f, 0x65979885), TOBN(0xfb87d449, 0x4cf751ef),
++     TOBN(0xe1790e4b, 0xfc25419a), TOBN(0x36467203, 0x4bff3cfd),
++     TOBN(0xc8db6386, 0x25b6e83f), TOBN(0x6cc69f23, 0x6cad6fd2),
++     TOBN(0x0219e45a, 0x6bc68bb9), TOBN(0xe43d79b6, 0x297f7334),
++     TOBN(0x7d445368, 0x465dc97c), TOBN(0x4b9eea32, 0x2a0b949a),
++     TOBN(0x1b96c6ba, 0x6102d021), TOBN(0xeaafac78, 0x2f4461ea),
++     TOBN(0xd4b85c41, 0xc49f19a8), TOBN(0x275c28e4, 0xcf538875),
++     TOBN(0x35451a9d, 0xdd2e54e0), TOBN(0x6991adb5, 0x0605618b),
++     TOBN(0x5b8b4bcd, 0x7b36cd24), TOBN(0x372a4f8c, 0x56f37216),
++     TOBN(0xc890bd73, 0xa6a5da60), TOBN(0x6f083da0, 0xdc4c9ff0),
++     TOBN(0xf4e14d94, 0xf0536e57), TOBN(0xf9ee1eda, 0xaaec8243),
++     TOBN(0x571241ec, 0x8bdcf8e7), TOBN(0xa5db8271, 0x0b041e26),
++     TOBN(0x9a0b9a99, 0xe3fff040), TOBN(0xcaaf21dd, 0x7c271202),
++     TOBN(0xb4e2b2e1, 0x4f0dd2e8), TOBN(0xe77e7c4f, 0x0a377ac7),
++     TOBN(0x69202c3f, 0x0d7a2198), TOBN(0xf759b7ff, 0x28200eb8),
++     TOBN(0xc87526ed, 0xdcfe314e), TOBN(0xeb84c524, 0x53d5cf99),
++     TOBN(0xb1b52ace, 0x515138b6), TOBN(0x5aa7ff8c, 0x23fca3f4),
++     TOBN(0xff0b13c3, 0xb9791a26), TOBN(0x960022da, 0xcdd58b16),
++     TOBN(0xdbd55c92, 0x57aad2de), TOBN(0x3baaaaa3, 0xf30fe619),
++     TOBN(0x9a4b2346, 0x0d881efd), TOBN(0x506416c0, 0x46325e2a),
++     TOBN(0x91381e76, 0x035c18d4), TOBN(0xb3bb68be, 0xf27817b0),
++     TOBN(0x15bfb8bf, 0x5116f937), TOBN(0x7c64a586, 0xc1268943),
++     TOBN(0x71e25cc3, 0x8419a2c8), TOBN(0x9fd6b0c4, 0x8335f463),
++     TOBN(0x4bf0ba3c, 0xe8ee0e0e), TOBN(0x6f6fba60, 0x298c21fa),
++     TOBN(0x57d57b39, 0xae66bee0), TOBN(0x292d5130, 0x22672544),
++     TOBN(0xf451105d, 0xbab093b3), TOBN(0x012f59b9, 0x02839986),
++     TOBN(0x8a915802, 0x3474a89c), TOBN(0x048c919c, 0x2de03e97),
++     TOBN(0xc476a2b5, 0x91071cd5), TOBN(0x791ed89a, 0x034970a5),
++     TOBN(0x89bd9042, 0xe1b7994b), TOBN(0x8eaf5179, 0xa1057ffd),
++     TOBN(0x6066e2a2, 0xd551ee10), TOBN(0x87a8f1d8, 0x727e09a6),
++     TOBN(0x00d08bab, 0x2c01148d), TOBN(0x6da8e4f1, 0x424f33fe),
++     TOBN(0x466d17f0, 0xcf9a4e71), TOBN(0xff502010, 0x3bf5cb19),
++     TOBN(0xdccf97d8, 0xd062ecc0), TOBN(0x80c0d9af, 0x81d80ac4),
++     TOBN(0xe87771d8, 0x033f2876), TOBN(0xb0186ec6, 0x7d5cc3db),
++     TOBN(0x58e8bb80, 0x3bc9bc1d), TOBN(0x4d1395cc, 0x6f6ef60e),
++     TOBN(0xa73c62d6, 0x186244a0), TOBN(0x918e5f23, 0x110a5b53),
++     TOBN(0xed4878ca, 0x741b7eab), TOBN(0x3038d71a, 0xdbe03e51),
++     TOBN(0x840204b7, 0xa93c3246), TOBN(0x21ab6069, 0xa0b9b4cd),
++     TOBN(0xf5fa6e2b, 0xb1d64218), TOBN(0x1de6ad0e, 0xf3d56191),
++     TOBN(0x570aaa88, 0xff1929c7), TOBN(0xc6df4c6b, 0x640e87b5),
++     TOBN(0xde8a74f2, 0xc65f0ccc), TOBN(0x8b972fd5, 0xe6f6cc01),
++     TOBN(0x3fff36b6, 0x0b846531), TOBN(0xba7e45e6, 0x10a5e475),
++     TOBN(0x84a1d10e, 0x4145b6c5), TOBN(0xf1f7f91a, 0x5e046d9d),
++     TOBN(0x0317a692, 0x44de90d7), TOBN(0x951a1d4a, 0xf199c15e),
++     TOBN(0x91f78046, 0xc9d73deb), TOBN(0x74c82828, 0xfab8224f),
++     TOBN(0xaa6778fc, 0xe7560b90), TOBN(0xb4073e61, 0xa7e824ce),
++     TOBN(0xff0d693c, 0xd642eba8), TOBN(0x7ce2e57a, 0x5dccef38),
++     TOBN(0x89c2c789, 0x1df1ad46), TOBN(0x83a06922, 0x098346fd),
++     TOBN(0x2d715d72, 0xda2fc177), TOBN(0x7b6dd71d, 0x85b6cf1d),
++     TOBN(0xc60a6d0a, 0x73fa9cb0), TOBN(0xedd3992e, 0x328bf5a9),
++     TOBN(0xc380ddd0, 0x832c8c82), TOBN(0xd182d410, 0xa2a0bf50),
++     TOBN(0x7d9d7438, 0xd9a528db), TOBN(0xe8b1a0e9, 0xcaf53994),
++     TOBN(0xddd6e5fe, 0x0e19987c), TOBN(0xacb8df03, 0x190b059d),
++     TOBN(0x53703a32, 0x8300129f), TOBN(0x1f637662, 0x68c43bfd),
++     TOBN(0xbcbd1913, 0x00e54051), TOBN(0x812fcc62, 0x7bf5a8c5),
++     TOBN(0x3f969d5f, 0x29fb85da), TOBN(0x72f4e00a, 0x694759e8),
++     TOBN(0x426b6e52, 0x790726b7), TOBN(0x617bbc87, 0x3bdbb209),
++     TOBN(0x511f8bb9, 0x97aee317), TOBN(0x812a4096, 0xe81536a8),
++     TOBN(0x137dfe59, 0x3ac09b9b), TOBN(0x0682238f, 0xba8c9a7a),
++     TOBN(0x7072ead6, 0xaeccb4bd), TOBN(0x6a34e9aa, 0x692ba633),
++     TOBN(0xc82eaec2, 0x6fff9d33), TOBN(0xfb753512, 0x1d4d2b62),
++     TOBN(0x1a0445ff, 0x1d7aadab), TOBN(0x65d38260, 0xd5f6a67c),
++     TOBN(0x6e62fb08, 0x91cfb26f), TOBN(0xef1e0fa5, 0x5c7d91d6),
++     TOBN(0x47e7c7ba, 0x33db72cd), TOBN(0x017cbc09, 0xfa7c74b2),
++     TOBN(0x3c931590, 0xf50a503c), TOBN(0xcac54f60, 0x616baa42),
++     TOBN(0x9b6cd380, 0xb2369f0f), TOBN(0x97d3a70d, 0x23c76151),
++     TOBN(0x5f9dd6fc, 0x9862a9c6), TOBN(0x044c4ab2, 0x12312f51),
++     TOBN(0x035ea0fd, 0x834a2ddc), TOBN(0x49e6b862, 0xcc7b826d),
++     TOBN(0xb03d6883, 0x62fce490), TOBN(0x62f2497a, 0xb37e36e9),
++     TOBN(0x04b005b6, 0xc6458293), TOBN(0x36bb5276, 0xe8d10af7),
++     TOBN(0xacf2dc13, 0x8ee617b8), TOBN(0x470d2d35, 0xb004b3d4),
++     TOBN(0x06790832, 0xfeeb1b77), TOBN(0x2bb75c39, 0x85657f9c),
++     TOBN(0xd70bd4ed, 0xc0f60004), TOBN(0xfe797ecc, 0x219b018b),
++     TOBN(0x9b5bec2a, 0x753aebcc), TOBN(0xdaf9f3dc, 0xc939eca5),
++     TOBN(0xd6bc6833, 0xd095ad09), TOBN(0x98abdd51, 0xdaa4d2fc),
++     TOBN(0xd9840a31, 0x8d168be5), TOBN(0xcf7c10e0, 0x2325a23c),
++     TOBN(0xa5c02aa0, 0x7e6ecfaf), TOBN(0x2462e7e6, 0xb5bfdf18),
++     TOBN(0xab2d8a8b, 0xa0cc3f12), TOBN(0x68dd485d, 0xbc672a29),
++     TOBN(0x72039752, 0x596f2cd3), TOBN(0x5d3eea67, 0xa0cf3d8d),
++     TOBN(0x810a1a81, 0xe6602671), TOBN(0x8f144a40, 0x14026c0c),
++     TOBN(0xbc753a6d, 0x76b50f85), TOBN(0xc4dc21e8, 0x645cd4a4),
++     TOBN(0xc5262dea, 0x521d0378), TOBN(0x802b8e0e, 0x05011c6f),
++     TOBN(0x1ba19cbb, 0x0b4c19ea), TOBN(0x21db64b5, 0xebf0aaec),
++     TOBN(0x1f394ee9, 0x70342f9d), TOBN(0x93a10aee, 0x1bc44a14),
++     TOBN(0xa7eed31b, 0x3efd0baa), TOBN(0x6e7c824e, 0x1d154e65),
++     TOBN(0xee23fa81, 0x9966e7ee), TOBN(0x64ec4aa8, 0x05b7920d),
++     TOBN(0x2d44462d, 0x2d90aad4), TOBN(0xf44dd195, 0xdf277ad5),
++     TOBN(0x8d6471f1, 0xbb46b6a1), TOBN(0x1e65d313, 0xfd885090),
++     TOBN(0x33a800f5, 0x13a977b4), TOBN(0xaca9d721, 0x0797e1ef),
++     TOBN(0x9a5a85a0, 0xfcff6a17), TOBN(0x9970a3f3, 0x1eca7cee),
++     TOBN(0xbb9f0d6b, 0xc9504be3), TOBN(0xe0c504be, 0xadd24ee2),
++     TOBN(0x7e09d956, 0x77fcc2f4), TOBN(0xef1a5227, 0x65bb5fc4),
++     TOBN(0x145d4fb1, 0x8b9286aa), TOBN(0x66fd0c5d, 0x6649028b),
++     TOBN(0x98857ceb, 0x1bf4581c), TOBN(0xe635e186, 0xaca7b166),
++     TOBN(0x278ddd22, 0x659722ac), TOBN(0xa0903c4c, 0x1db68007),
++     TOBN(0x366e4589, 0x48f21402), TOBN(0x31b49c14, 0xb96abda2),
++     TOBN(0x329c4b09, 0xe0403190), TOBN(0x97197ca3, 0xd29f43fe),
++     TOBN(0x8073dd1e, 0x274983d8), TOBN(0xda1a3bde, 0x55717c8f),
++     TOBN(0xfd3d4da2, 0x0361f9d1), TOBN(0x1332d081, 0x4c7de1ce),
++     TOBN(0x9b7ef7a3, 0xaa6d0e10), TOBN(0x17db2e73, 0xf54f1c4a),
++     TOBN(0xaf3dffae, 0x4cd35567), TOBN(0xaaa2f406, 0xe56f4e71),
++     TOBN(0x8966759e, 0x7ace3fc7), TOBN(0x9594eacf, 0x45a8d8c6),
++     TOBN(0x8de3bd8b, 0x91834e0e), TOBN(0xafe4ca53, 0x548c0421),
++     TOBN(0xfdd7e856, 0xe6ee81c6), TOBN(0x8f671beb, 0x6b891a3a),
++     TOBN(0xf7a58f2b, 0xfae63829), TOBN(0x9ab186fb, 0x9c11ac9f),
++     TOBN(0x8d6eb369, 0x10b5be76), TOBN(0x046b7739, 0xfb040bcd),
++     TOBN(0xccb4529f, 0xcb73de88), TOBN(0x1df0fefc, 0xcf26be03),
++     TOBN(0xad7757a6, 0xbcfcd027), TOBN(0xa8786c75, 0xbb3165ca),
++     TOBN(0xe9db1e34, 0x7e99a4d9), TOBN(0x99ee86df, 0xb06c504b),
++     TOBN(0x5b7c2ddd, 0xc15c9f0a), TOBN(0xdf87a734, 0x4295989e),
++     TOBN(0x59ece47c, 0x03d08fda), TOBN(0xb074d3dd, 0xad5fc702),
++     TOBN(0x20407903, 0x51a03776), TOBN(0x2bb1f77b, 0x2a608007),
++     TOBN(0x25c58f4f, 0xe1153185), TOBN(0xe6df62f6, 0x766e6447),
++     TOBN(0xefb3d1be, 0xed51275a), TOBN(0x5de47dc7, 0x2f0f483f),
++     TOBN(0x7932d98e, 0x97c2bedf), TOBN(0xd5c11927, 0x0219f8a1),
++     TOBN(0x9d751200, 0xa73a294e), TOBN(0x5f88434a, 0x9dc20172),
++     TOBN(0xd28d9fd3, 0xa26f506a), TOBN(0xa890cd31, 0x9d1dcd48),
++     TOBN(0x0aebaec1, 0x70f4d3b4), TOBN(0xfd1a1369, 0x0ffc8d00),
++     TOBN(0xb9d9c240, 0x57d57838), TOBN(0x45929d26, 0x68bac361),
++     TOBN(0x5a2cd060, 0x25b15ca6), TOBN(0x4b3c83e1, 0x6e474446),
++     TOBN(0x1aac7578, 0xee1e5134), TOBN(0xa418f5d6, 0xc91e2f41),
++     TOBN(0x6936fc8a, 0x213ed68b), TOBN(0x860ae7ed, 0x510a5224),
++     TOBN(0x63660335, 0xdef09b53), TOBN(0x641b2897, 0xcd79c98d),
++     TOBN(0x29bd38e1, 0x01110f35), TOBN(0x79c26f42, 0x648b1937),
++     TOBN(0x64dae519, 0x9d9164f4), TOBN(0xd85a2310, 0x0265c273),
++     TOBN(0x7173dd5d, 0x4b07e2b1), TOBN(0xd144c4cb, 0x8d9ea221),
++     TOBN(0xe8b04ea4, 0x1105ab14), TOBN(0x92dda542, 0xfe80d8f1),
++     TOBN(0xe9982fa8, 0xcf03dce6), TOBN(0x8b5ea965, 0x1a22cffc),
++     TOBN(0xf7f4ea7f, 0x3fad88c4), TOBN(0x62db773e, 0x6a5ba95c),
++     TOBN(0xd20f02fb, 0x93f24567), TOBN(0xfd46c69a, 0x315257ca),
++     TOBN(0x0ac74cc7, 0x8bcab987), TOBN(0x46f31c01, 0x5ceca2f5),
++     TOBN(0x40aedb59, 0x888b219e), TOBN(0xe50ecc37, 0xe1fccd02),
++     TOBN(0x1bcd9dad, 0x911f816c), TOBN(0x583cc1ec, 0x8db9b00c),
++     TOBN(0xf3cd2e66, 0xa483bf11), TOBN(0xfa08a6f5, 0xb1b2c169),
++     TOBN(0xf375e245, 0x4be9fa28), TOBN(0x99a7ffec, 0x5b6d011f),
++     TOBN(0x6a3ebddb, 0xc4ae62da), TOBN(0x6cea00ae, 0x374aef5d),
++     TOBN(0xab5fb98d, 0x9d4d05bc), TOBN(0x7cba1423, 0xd560f252),
++     TOBN(0x49b2cc21, 0x208490de), TOBN(0x1ca66ec3, 0xbcfb2879),
++     TOBN(0x7f1166b7, 0x1b6fb16f), TOBN(0xfff63e08, 0x65fe5db3),
++     TOBN(0xb8345abe, 0x8b2610be), TOBN(0xb732ed80, 0x39de3df4),
++     TOBN(0x0e24ed50, 0x211c32b4), TOBN(0xd10d8a69, 0x848ff27d),
++     TOBN(0xc1074398, 0xed4de248), TOBN(0xd7cedace, 0x10488927),
++     TOBN(0xa4aa6bf8, 0x85673e13), TOBN(0xb46bae91, 0x6daf30af),
++     TOBN(0x07088472, 0xfcef7ad8), TOBN(0x61151608, 0xd4b35e97),
++     TOBN(0xbcfe8f26, 0xdde29986), TOBN(0xeb84c4c7, 0xd5a34c79),
++     TOBN(0xc1eec55c, 0x164e1214), TOBN(0x891be86d, 0xa147bb03),
++     TOBN(0x9fab4d10, 0x0ba96835), TOBN(0xbf01e9b8, 0xa5c1ae9f),
++     TOBN(0x6b4de139, 0xb186ebc0), TOBN(0xd5c74c26, 0x85b91bca),
++     TOBN(0x5086a99c, 0xc2d93854), TOBN(0xeed62a7b, 0xa7a9dfbc),
++     TOBN(0x8778ed6f, 0x76b7618a), TOBN(0xbff750a5, 0x03b66062),
++     TOBN(0x4cb7be22, 0xb65186db), TOBN(0x369dfbf0, 0xcc3a6d13),
++     TOBN(0xc7dab26c, 0x7191a321), TOBN(0x9edac3f9, 0x40ed718e),
++     TOBN(0xbc142b36, 0xd0cfd183), TOBN(0xc8af82f6, 0x7c991693),
++     TOBN(0xb3d1e4d8, 0x97ce0b2a), TOBN(0xe6d7c87f, 0xc3a55cdf),
++     TOBN(0x35846b95, 0x68b81afe), TOBN(0x018d12af, 0xd3c239d8),
++     TOBN(0x2b2c6208, 0x01206e15), TOBN(0xe0e42453, 0xa3b882c6),
++     TOBN(0x854470a3, 0xa50162d5), TOBN(0x08157478, 0x7017a62a),
++     TOBN(0x18bd3fb4, 0x820357c7), TOBN(0x992039ae, 0x6f1458ad),
++     TOBN(0x9a1df3c5, 0x25b44aa1), TOBN(0x2d780357, 0xed3d5281),
++     TOBN(0x58cf7e4d, 0xc77ad4d4), TOBN(0xd49a7998, 0xf9df4fc4),
++     TOBN(0x4465a8b5, 0x1d71205e), TOBN(0xa0ee0ea6, 0x649254aa),
++     TOBN(0x4b5eeecf, 0xab7bd771), TOBN(0x6c873073, 0x35c262b9),
++     TOBN(0xdc5bd648, 0x3c9d61e7), TOBN(0x233d6d54, 0x321460d2),
++     TOBN(0xd20c5626, 0xfc195bcc), TOBN(0x25445958, 0x04d78b63),
++     TOBN(0xe03fcb3d, 0x17ec8ef3), TOBN(0x54b690d1, 0x46b8f781),
++     TOBN(0x82fa2c8a, 0x21230646), TOBN(0xf51aabb9, 0x084f418c),
++     TOBN(0xff4fbec1, 0x1a30ba43), TOBN(0x6a5acf73, 0x743c9df7),
++     TOBN(0x1da2b357, 0xd635b4d5), TOBN(0xc3de68dd, 0xecd5c1da),
++     TOBN(0xa689080b, 0xd61af0dd), TOBN(0xdea5938a, 0xd665bf99),
++     TOBN(0x0231d71a, 0xfe637294), TOBN(0x01968aa6, 0xa5a81cd8),
++     TOBN(0x11252d50, 0x048e63b5), TOBN(0xc446bc52, 0x6ca007e9),
++     TOBN(0xef8c50a6, 0x96d6134b), TOBN(0x9361fbf5, 0x9e09a05c),
++     TOBN(0xf17f85a6, 0xdca3291a), TOBN(0xb178d548, 0xff251a21),
++     TOBN(0x87f6374b, 0xa4df3915), TOBN(0x566ce1bf, 0x2fd5d608),
++     TOBN(0x425cba4d, 0x7de35102), TOBN(0x6b745f8f, 0x58c5d5e2),
++     TOBN(0x88402af6, 0x63122edf), TOBN(0x3190f9ed, 0x3b989a89),
++     TOBN(0x4ad3d387, 0xebba3156), TOBN(0xef385ad9, 0xc7c469a5),
++     TOBN(0xb08281de, 0x3f642c29), TOBN(0x20be0888, 0x910ffb88),
++     TOBN(0xf353dd4a, 0xd5292546), TOBN(0x3f1627de, 0x8377a262),
++     TOBN(0xa5faa013, 0xeefcd638), TOBN(0x8f3bf626, 0x74cc77c3),
++     TOBN(0x32618f65, 0xa348f55e), TOBN(0x5787c0dc, 0x9fefeb9e),
++     TOBN(0xf1673aa2, 0xd9a23e44), TOBN(0x88dfa993, 0x4e10690d),
++     TOBN(0x1ced1b36, 0x2bf91108), TOBN(0x9193ceca, 0x3af48649),
++     TOBN(0xfb34327d, 0x2d738fc5), TOBN(0x6697b037, 0x975fee6c),
++     TOBN(0x2f485da0, 0xc04079a5), TOBN(0x2cdf5735, 0x2feaa1ac),
++     TOBN(0x76944420, 0xbd55659e), TOBN(0x7973e32b, 0x4376090c),
++     TOBN(0x86bb4fe1, 0x163b591a), TOBN(0x10441aed, 0xc196f0ca),
++     TOBN(0x3b431f4a, 0x045ad915), TOBN(0x6c11b437, 0xa4afacb1),
++     TOBN(0x30b0c7db, 0x71fdbbd8), TOBN(0xb642931f, 0xeda65acd),
++     TOBN(0x4baae6e8, 0x9c92b235), TOBN(0xa73bbd0e, 0x6b3993a1),
++     TOBN(0xd06d60ec, 0x693dd031), TOBN(0x03cab91b, 0x7156881c),
++     TOBN(0xd615862f, 0x1db3574b), TOBN(0x485b0185, 0x64bb061a),
++     TOBN(0x27434988, 0xa0181e06), TOBN(0x2cd61ad4, 0xc1c0c757),
++     TOBN(0x3effed5a, 0x2ff9f403), TOBN(0x8dc98d8b, 0x62239029),
++     TOBN(0x2206021e, 0x1f17b70d), TOBN(0xafbec0ca, 0xbf510015),
++     TOBN(0x9fed7164, 0x80130dfa), TOBN(0x306dc2b5, 0x8a02dcf5),
++     TOBN(0x48f06620, 0xfeb10fc0), TOBN(0x78d1e1d5, 0x5a57cf51),
++     TOBN(0xadef8c5a, 0x192ef710), TOBN(0x88afbd4b, 0x3b7431f9),
++     TOBN(0x7e1f7407, 0x64250c9e), TOBN(0x6e31318d, 0xb58bec07),
++     TOBN(0xfd4fc4b8, 0x24f89b4e), TOBN(0x65a5dd88, 0x48c36a2a),
++     TOBN(0x4f1eccff, 0xf024baa7), TOBN(0x22a21cf2, 0xcba94650),
++     TOBN(0x95d29dee, 0x42a554f7), TOBN(0x828983a5, 0x002ec4ba),
++     TOBN(0x8112a1f7, 0x8badb73d), TOBN(0x79ea8897, 0xa27c1839),
++     TOBN(0x8969a5a7, 0xd065fd83), TOBN(0xf49af791, 0xb262a0bc),
++     TOBN(0xfcdea8b6, 0xaf2b5127), TOBN(0x10e913e1, 0x564c2dbc),
++     TOBN(0x51239d14, 0xbc21ef51), TOBN(0xe51c3ceb, 0x4ce57292),
++     TOBN(0x795ff068, 0x47bbcc3b), TOBN(0x86b46e1e, 0xbd7e11e6),
++     TOBN(0x0ea6ba23, 0x80041ef4), TOBN(0xd72fe505, 0x6262342e),
++     TOBN(0x8abc6dfd, 0x31d294d4), TOBN(0xbbe017a2, 0x1278c2c9),
++     TOBN(0xb1fcfa09, 0xb389328a), TOBN(0x322fbc62, 0xd01771b5),
++     TOBN(0x04c0d063, 0x60b045bf), TOBN(0xdb652edc, 0x10e52d01),
++     TOBN(0x50ef932c, 0x03ec6627), TOBN(0xde1b3b2d, 0xc1ee50e3),
++     TOBN(0x5ab7bdc5, 0xdc37a90d), TOBN(0xfea67213, 0x31e33a96),
++     TOBN(0x6482b5cb, 0x4f2999aa), TOBN(0x38476cc6, 0xb8cbf0dd),
++     TOBN(0x93ebfacb, 0x173405bb), TOBN(0x15cdafe7, 0xe52369ec),
++     TOBN(0xd42d5ba4, 0xd935b7db), TOBN(0x648b6004, 0x1c99a4cd),
++     TOBN(0x785101bd, 0xa3b5545b), TOBN(0x4bf2c38a, 0x9dd67faf),
++     TOBN(0xb1aadc63, 0x4442449c), TOBN(0xe0e9921a, 0x33ad4fb8),
++     TOBN(0x5c552313, 0xaa686d82), TOBN(0xdee635fa, 0x465d866c),
++     TOBN(0xbc3c224a, 0x18ee6e8a), TOBN(0xeed748a6, 0xed42e02f),
++     TOBN(0xe70f930a, 0xd474cd08), TOBN(0x774ea6ec, 0xfff24adf),
++     TOBN(0x03e2de1c, 0xf3480d4a), TOBN(0xf0d8edc7, 0xbc8acf1a),
++     TOBN(0xf23e3303, 0x68295a9c), TOBN(0xfadd5f68, 0xc546a97d),
++     TOBN(0x895597ad, 0x96f8acb1), TOBN(0xbddd49d5, 0x671bdae2),
++     TOBN(0x16fcd528, 0x21dd43f4), TOBN(0xa5a45412, 0x6619141a)}
++    ,
++    {TOBN(0x8ce9b6bf, 0xc360e25a), TOBN(0xe6425195, 0x075a1a78),
++     TOBN(0x9dc756a8, 0x481732f4), TOBN(0x83c0440f, 0x5432b57a),
++     TOBN(0xc670b3f1, 0xd720281f), TOBN(0x2205910e, 0xd135e051),
++     TOBN(0xded14b0e, 0xdb052be7), TOBN(0x697b3d27, 0xc568ea39),
++     TOBN(0x2e599b9a, 0xfb3ff9ed), TOBN(0x28c2e0ab, 0x17f6515c),
++     TOBN(0x1cbee4fd, 0x474da449), TOBN(0x071279a4, 0x4f364452),
++     TOBN(0x97abff66, 0x01fbe855), TOBN(0x3ee394e8, 0x5fda51c4),
++     TOBN(0x190385f6, 0x67597c0b), TOBN(0x6e9fccc6, 0xa27ee34b),
++     TOBN(0x0b89de93, 0x14092ebb), TOBN(0xf17256bd, 0x428e240c),
++     TOBN(0xcf89a7f3, 0x93d2f064), TOBN(0x4f57841e, 0xe1ed3b14),
++     TOBN(0x4ee14405, 0xe708d855), TOBN(0x856aae72, 0x03f1c3d0),
++     TOBN(0xc8e5424f, 0xbdd7eed5), TOBN(0x3333e4ef, 0x73ab4270),
++     TOBN(0x3bc77ade, 0xdda492f8), TOBN(0xc11a3aea, 0x78297205),
++     TOBN(0x5e89a3e7, 0x34931b4c), TOBN(0x17512e2e, 0x9f5694bb),
++     TOBN(0x5dc349f3, 0x177bf8b6), TOBN(0x232ea4ba, 0x08c7ff3e),
++     TOBN(0x9c4f9d16, 0xf511145d), TOBN(0xccf109a3, 0x33b379c3),
++     TOBN(0xe75e7a88, 0xa1f25897), TOBN(0x7ac6961f, 0xa1b5d4d8),
++     TOBN(0xe3e10773, 0x08f3ed5c), TOBN(0x208a54ec, 0x0a892dfb),
++     TOBN(0xbe826e19, 0x78660710), TOBN(0x0cf70a97, 0x237df2c8),
++     TOBN(0x418a7340, 0xed704da5), TOBN(0xa3eeb9a9, 0x08ca33fd),
++     TOBN(0x49d96233, 0x169bca96), TOBN(0x04d286d4, 0x2da6aafb),
++     TOBN(0xc09606ec, 0xa0c2fa94), TOBN(0x8869d0d5, 0x23ff0fb3),
++     TOBN(0xa99937e5, 0xd0150d65), TOBN(0xa92e2503, 0x240c14c9),
++     TOBN(0x656bf945, 0x108e2d49), TOBN(0x152a733a, 0xa2f59e2b),
++     TOBN(0xb4323d58, 0x8434a920), TOBN(0xc0af8e93, 0x622103c5),
++     TOBN(0x667518ef, 0x938dbf9a), TOBN(0xa1843073, 0x83a9cdf2),
++     TOBN(0x350a94aa, 0x5447ab80), TOBN(0xe5e5a325, 0xc75a3d61),
++     TOBN(0x74ba507f, 0x68411a9e), TOBN(0x10581fc1, 0x594f70c5),
++     TOBN(0x60e28570, 0x80eb24a9), TOBN(0x7bedfb4d, 0x488e0cfd),
++     TOBN(0x721ebbd7, 0xc259cdb8), TOBN(0x0b0da855, 0xbc6390a9),
++     TOBN(0x2b4d04db, 0xde314c70), TOBN(0xcdbf1fbc, 0x6c32e846),
++     TOBN(0x33833eab, 0xb162fc9e), TOBN(0x9939b48b, 0xb0dd3ab7),
++     TOBN(0x5aaa98a7, 0xcb0c9c8c), TOBN(0x75105f30, 0x81c4375c),
++     TOBN(0xceee5057, 0x5ef1c90f), TOBN(0xb31e065f, 0xc23a17bf),
++     TOBN(0x5364d275, 0xd4b6d45a), TOBN(0xd363f3ad, 0x62ec8996),
++     TOBN(0xb5d21239, 0x4391c65b), TOBN(0x84564765, 0xebb41b47),
++     TOBN(0x20d18ecc, 0x37107c78), TOBN(0xacff3b6b, 0x570c2a66),
++     TOBN(0x22f975d9, 0x9bd0d845), TOBN(0xef0a0c46, 0xba178fa0),
++     TOBN(0x1a419651, 0x76b6028e), TOBN(0xc49ec674, 0x248612d4),
++     TOBN(0x5b6ac4f2, 0x7338af55), TOBN(0x06145e62, 0x7bee5a36),
++     TOBN(0x33e95d07, 0xe75746b5), TOBN(0x1c1e1f6d, 0xc40c78be),
++     TOBN(0x967833ef, 0x222ff8e2), TOBN(0x4bedcf6a, 0xb49180ad),
++     TOBN(0x6b37e9c1, 0x3d7a4c8a), TOBN(0x2748887c, 0x6ddfe760),
++     TOBN(0xf7055123, 0xaa3a5bbc), TOBN(0x954ff225, 0x7bbb8e74),
++     TOBN(0xc42b8ab1, 0x97c3dfb9), TOBN(0x55a549b0, 0xcf168154),
++     TOBN(0xad6748e7, 0xc1b50692), TOBN(0x2775780f, 0x6fc5cbcb),
++     TOBN(0x4eab80b8, 0xe1c9d7c8), TOBN(0x8c69dae1, 0x3fdbcd56),
++     TOBN(0x47e6b4fb, 0x9969eace), TOBN(0x002f1085, 0xa705cb5a),
++     TOBN(0x4e23ca44, 0x6d3fea55), TOBN(0xb4ae9c86, 0xf4810568),
++     TOBN(0x47bfb91b, 0x2a62f27d), TOBN(0x60deb4c9, 0xd9bac28c),
++     TOBN(0xa892d894, 0x7de6c34c), TOBN(0x4ee68259, 0x4494587d),
++     TOBN(0x914ee14e, 0x1a3f8a5b), TOBN(0xbb113eaa, 0x28700385),
++     TOBN(0x81ca03b9, 0x2115b4c9), TOBN(0x7c163d38, 0x8908cad1),
++     TOBN(0xc912a118, 0xaa18179a), TOBN(0xe09ed750, 0x886e3081),
++     TOBN(0xa676e3fa, 0x26f516ca), TOBN(0x753cacf7, 0x8e732f91),
++     TOBN(0x51592aea, 0x833da8b4), TOBN(0xc626f42f, 0x4cbea8aa),
++     TOBN(0xef9dc899, 0xa7b56eaf), TOBN(0x00c0e52c, 0x34ef7316),
++     TOBN(0x5b1e4e24, 0xfe818a86), TOBN(0x9d31e20d, 0xc538be47),
++     TOBN(0x22eb932d, 0x3ed68974), TOBN(0xe44bbc08, 0x7c4e87c4),
++     TOBN(0x4121086e, 0x0dde9aef), TOBN(0x8e6b9cff, 0x134f4345),
++     TOBN(0x96892c1f, 0x711b0eb9), TOBN(0xb905f2c8, 0x780ab954),
++     TOBN(0xace26309, 0xa20792db), TOBN(0xec8ac9b3, 0x0684e126),
++     TOBN(0x486ad8b6, 0xb40a2447), TOBN(0x60121fc1, 0x9fe3fb24),
++     TOBN(0x5626fccf, 0x1a8e3b3f), TOBN(0x4e568622, 0x6ad1f394),
++     TOBN(0xda7aae0d, 0x196aa5a1), TOBN(0xe0df8c77, 0x1041b5fb),
++     TOBN(0x451465d9, 0x26b318b7), TOBN(0xc29b6e55, 0x7ab136e9),
++     TOBN(0x2c2ab48b, 0x71148463), TOBN(0xb5738de3, 0x64454a76),
++     TOBN(0x54ccf9a0, 0x5a03abe4), TOBN(0x377c0296, 0x0427d58e),
++     TOBN(0x73f5f0b9, 0x2bb39c1f), TOBN(0x14373f2c, 0xe608d8c5),
++     TOBN(0xdcbfd314, 0x00fbb805), TOBN(0xdf18fb20, 0x83afdcfb),
++     TOBN(0x81a57f42, 0x42b3523f), TOBN(0xe958532d, 0x87f650fb),
++     TOBN(0xaa8dc8b6, 0x8b0a7d7c), TOBN(0x1b75dfb7, 0x150166be),
++     TOBN(0x90e4f7c9, 0x2d7d1413), TOBN(0x67e2d6b5, 0x9834f597),
++     TOBN(0x4fd4f4f9, 0xa808c3e8), TOBN(0xaf8237e0, 0xd5281ec1),
++     TOBN(0x25ab5fdc, 0x84687cee), TOBN(0xc5ded6b1, 0xa5b26c09),
++     TOBN(0x8e4a5aec, 0xc8ea7650), TOBN(0x23b73e5c, 0x14cc417f),
++     TOBN(0x2bfb4318, 0x3037bf52), TOBN(0xb61e6db5, 0x78c725d7),
++     TOBN(0x8efd4060, 0xbbb3e5d7), TOBN(0x2e014701, 0xdbac488e),
++     TOBN(0xac75cf9a, 0x360aa449), TOBN(0xb70cfd05, 0x79634d08),
++     TOBN(0xa591536d, 0xfffb15ef), TOBN(0xb2c37582, 0xd07c106c),
++     TOBN(0xb4293fdc, 0xf50225f9), TOBN(0xc52e175c, 0xb0e12b03),
++     TOBN(0xf649c3ba, 0xd0a8bf64), TOBN(0x745a8fef, 0xeb8ae3c6),
++     TOBN(0x30d7e5a3, 0x58321bc3), TOBN(0xb1732be7, 0x0bc4df48),
++     TOBN(0x1f217993, 0xe9ea5058), TOBN(0xf7a71cde, 0x3e4fd745),
++     TOBN(0x86cc533e, 0x894c5bbb), TOBN(0x6915c7d9, 0x69d83082),
++     TOBN(0xa6aa2d05, 0x5815c244), TOBN(0xaeeee592, 0x49b22ce5),
++     TOBN(0x89e39d13, 0x78135486), TOBN(0x3a275c1f, 0x16b76f2f),
++     TOBN(0xdb6bcc1b, 0xe036e8f5), TOBN(0x4df69b21, 0x5e4709f5),
++     TOBN(0xa188b250, 0x2d0f39aa), TOBN(0x622118bb, 0x15a85947),
++     TOBN(0x2ebf520f, 0xfde0f4fa), TOBN(0xa40e9f29, 0x4860e539),
++     TOBN(0x7b6a51eb, 0x22b57f0f), TOBN(0x849a33b9, 0x7e80644a),
++     TOBN(0x50e5d16f, 0x1cf095fe), TOBN(0xd754b54e, 0xec55f002),
++     TOBN(0x5cfbbb22, 0x236f4a98), TOBN(0x0b0c59e9, 0x066800bb),
++     TOBN(0x4ac69a8f, 0x5a9a7774), TOBN(0x2b33f804, 0xd6bec948),
++     TOBN(0xb3729295, 0x32e6c466), TOBN(0x68956d0f, 0x4e599c73),
++     TOBN(0xa47a249f, 0x155c31cc), TOBN(0x24d80f0d, 0xe1ce284e),
++     TOBN(0xcd821dfb, 0x988baf01), TOBN(0xe6331a7d, 0xdbb16647),
++     TOBN(0x1eb8ad33, 0x094cb960), TOBN(0x593cca38, 0xc91bbca5),
++     TOBN(0x384aac8d, 0x26567456), TOBN(0x40fa0309, 0xc04b6490),
++     TOBN(0x97834cd6, 0xdab6c8f6), TOBN(0x68a7318d, 0x3f91e55f),
++     TOBN(0xa00fd04e, 0xfc4d3157), TOBN(0xb56f8ab2, 0x2bf3bdea),
++     TOBN(0x014f5648, 0x4fa57172), TOBN(0x948c5860, 0x450abdb3),
++     TOBN(0x342b5df0, 0x0ebd4f08), TOBN(0x3e5168cd, 0x0e82938e),
++     TOBN(0x7aedc1ce, 0xb0df5dd0), TOBN(0x6bbbc6d9, 0xe5732516),
++     TOBN(0xc7bfd486, 0x605daaa6), TOBN(0x46fd72b7, 0xbb9a6c9e),
++     TOBN(0xe4847fb1, 0xa124fb89), TOBN(0x75959cbd, 0xa2d8ffbc),
++     TOBN(0x42579f65, 0xc8a588ee), TOBN(0x368c92e6, 0xb80b499d),
++     TOBN(0xea4ef6cd, 0x999a5df1), TOBN(0xaa73bb7f, 0x936fe604),
++     TOBN(0xf347a70d, 0x6457d188), TOBN(0x86eda86b, 0x8b7a388b),
++     TOBN(0xb7cdff06, 0x0ccd6013), TOBN(0xbeb1b6c7, 0xd0053fb2),
++     TOBN(0x0b022387, 0x99240a9f), TOBN(0x1bbb384f, 0x776189b2),
++     TOBN(0x8695e71e, 0x9066193a), TOBN(0x2eb50097, 0x06ffac7e),
++     TOBN(0x0654a9c0, 0x4a7d2caa), TOBN(0x6f3fb3d1, 0xa5aaa290),
++     TOBN(0x835db041, 0xff476e8f), TOBN(0x540b8b0b, 0xc42295e4),
++     TOBN(0xa5c73ac9, 0x05e214f5), TOBN(0x9a74075a, 0x56a0b638),
++     TOBN(0x2e4b1090, 0xce9e680b), TOBN(0x57a5b479, 0x6b8d9afa),
++     TOBN(0x0dca48e7, 0x26bfe65c), TOBN(0x097e391c, 0x7290c307),
++     TOBN(0x683c462e, 0x6669e72e), TOBN(0xf505be1e, 0x062559ac),
++     TOBN(0x5fbe3ea1, 0xe3a3035a), TOBN(0x6431ebf6, 0x9cd50da8),
++     TOBN(0xfd169d5c, 0x1f6407f2), TOBN(0x8d838a95, 0x60fce6b8),
++     TOBN(0x2a2bfa7f, 0x650006f0), TOBN(0xdfd7dad3, 0x50c0fbb2),
++     TOBN(0x92452495, 0xccf9ad96), TOBN(0x183bf494, 0xd95635f9),
++     TOBN(0x02d5df43, 0x4a7bd989), TOBN(0x505385cc, 0xa5431095),
++     TOBN(0xdd98e67d, 0xfd43f53e), TOBN(0xd61e1a6c, 0x500c34a9),
++     TOBN(0x5a4b46c6, 0x4a8a3d62), TOBN(0x8469c4d0, 0x247743d2),
++     TOBN(0x2bb3a13d, 0x88f7e433), TOBN(0x62b23a10, 0x01be5849),
++     TOBN(0xe83596b4, 0xa63d1a4c), TOBN(0x454e7fea, 0x7d183f3e),
++     TOBN(0x643fce61, 0x17afb01c), TOBN(0x4e65e5e6, 0x1c4c3638),
++     TOBN(0x41d85ea1, 0xef74c45b), TOBN(0x2cfbfa66, 0xae328506),
++     TOBN(0x98b078f5, 0x3ada7da9), TOBN(0xd985fe37, 0xec752fbb),
++     TOBN(0xeece68fe, 0x5a0148b4), TOBN(0x6f9a55c7, 0x2d78136d),
++     TOBN(0x232dccc4, 0xd2b729ce), TOBN(0xa27e0dfd, 0x90aafbc4),
++     TOBN(0x96474452, 0x12b4603e), TOBN(0xa876c551, 0x6b706d14),
++     TOBN(0xdf145fcf, 0x69a9d412), TOBN(0xe2ab75b7, 0x2d479c34),
++     TOBN(0x12df9a76, 0x1a23ff97), TOBN(0xc6138992, 0x5d359d10),
++     TOBN(0x6e51c7ae, 0xfa835f22), TOBN(0x69a79cb1, 0xc0fcc4d9),
++     TOBN(0xf57f350d, 0x594cc7e1), TOBN(0x3079ca63, 0x3350ab79),
++     TOBN(0x226fb614, 0x9aff594a), TOBN(0x35afec02, 0x6d59a62b),
++     TOBN(0x9bee46f4, 0x06ed2c6e), TOBN(0x58da1735, 0x7d939a57),
++     TOBN(0x44c50402, 0x8fd1797e), TOBN(0xd8853e7c, 0x5ccea6ca),
++     TOBN(0x4065508d, 0xa35fcd5f), TOBN(0x8965df8c, 0x495ccaeb),
++     TOBN(0x0f2da850, 0x12e1a962), TOBN(0xee471b94, 0xc1cf1cc4),
++     TOBN(0xcef19bc8, 0x0a08fb75), TOBN(0x704958f5, 0x81de3591),
++     TOBN(0x2867f8b2, 0x3aef4f88), TOBN(0x8d749384, 0xea9f9a5f),
++     TOBN(0x1b385537, 0x8c9049f4), TOBN(0x5be948f3, 0x7b92d8b6),
++     TOBN(0xd96f725d, 0xb6e2bd6b), TOBN(0x37a222bc, 0x958c454d),
++     TOBN(0xe7c61abb, 0x8809bf61), TOBN(0x46f07fbc, 0x1346f18d),
++     TOBN(0xfb567a7a, 0xe87c0d1c), TOBN(0x84a461c8, 0x7ef3d07a),
++     TOBN(0x0a5adce6, 0xd9278d98), TOBN(0x24d94813, 0x9dfc73e1),
++     TOBN(0x4f3528b6, 0x054321c3), TOBN(0x2e03fdde, 0x692ea706),
++     TOBN(0x10e60619, 0x47b533c0), TOBN(0x1a8bc73f, 0x2ca3c055),
++     TOBN(0xae58d4b2, 0x1bb62b8f), TOBN(0xb2045a73, 0x584a24e3),
++     TOBN(0x3ab3d5af, 0xbd76e195), TOBN(0x478dd1ad, 0x6938a810),
++     TOBN(0x6ffab393, 0x6ee3d5cb), TOBN(0xdfb693db, 0x22b361e4),
++     TOBN(0xf9694496, 0x51dbf1a7), TOBN(0xcab4b4ef, 0x08a2e762),
++     TOBN(0xe8c92f25, 0xd39bba9a), TOBN(0x850e61bc, 0xf1464d96),
++     TOBN(0xb7e830e3, 0xdc09508b), TOBN(0xfaf6d2cf, 0x74317655),
++     TOBN(0x72606ceb, 0xdf690355), TOBN(0x48bb92b3, 0xd0c3ded6),
++     TOBN(0x65b75484, 0x5c7cf892), TOBN(0xf6cd7ac9, 0xd5d5f01f),
++     TOBN(0xc2c30a59, 0x96401d69), TOBN(0x91268650, 0xed921878),
++     TOBN(0x380bf913, 0xb78c558f), TOBN(0x43c0baeb, 0xc8afdaa9),
++     TOBN(0x377f61d5, 0x54f169d3), TOBN(0xf8da07e3, 0xae5ff20b),
++     TOBN(0xb676c49d, 0xa8a90ea8), TOBN(0x81c1ff2b, 0x83a29b21),
++     TOBN(0x383297ac, 0x2ad8d276), TOBN(0x3001122f, 0xba89f982),
++     TOBN(0xe1d794be, 0x6718e448), TOBN(0x246c1482, 0x7c3e6e13),
++     TOBN(0x56646ef8, 0x5d26b5ef), TOBN(0x80f5091e, 0x88069cdd),
++     TOBN(0xc5992e2f, 0x724bdd38), TOBN(0x02e915b4, 0x8471e8c7),
++     TOBN(0x96ff320a, 0x0d0ff2a9), TOBN(0xbf886487, 0x4384d1a0),
++     TOBN(0xbbe1e6a6, 0xc93f72d6), TOBN(0xd5f75d12, 0xcad800ea),
++     TOBN(0xfa40a09f, 0xe7acf117), TOBN(0x32c8cdd5, 0x7581a355),
++     TOBN(0x74221992, 0x7023c499), TOBN(0xa8afe5d7, 0x38ec3901),
++     TOBN(0x5691afcb, 0xa90e83f0), TOBN(0x41bcaa03, 0x0b8f8eac),
++     TOBN(0xe38b5ff9, 0x8d2668d5), TOBN(0x0715281a, 0x7ad81965),
++     TOBN(0x1bc8fc7c, 0x03c6ce11), TOBN(0xcbbee6e2, 0x8b650436),
++     TOBN(0x06b00fe8, 0x0cdb9808), TOBN(0x17d6e066, 0xfe3ed315),
++     TOBN(0x2e9d38c6, 0x4d0b5018), TOBN(0xab8bfd56, 0x844dcaef),
++     TOBN(0x42894a59, 0x513aed8b), TOBN(0xf77f3b6d, 0x314bd07a),
++     TOBN(0xbbdecb8f, 0x8e42b582), TOBN(0xf10e2fa8, 0xd2390fe6),
++     TOBN(0xefb95022, 0x62a2f201), TOBN(0x4d59ea50, 0x50ee32b0),
++     TOBN(0xd87f7728, 0x6da789a8), TOBN(0xcf98a2cf, 0xf79492c4),
++     TOBN(0xf9577239, 0x720943c2), TOBN(0xba044cf5, 0x3990b9d0),
++     TOBN(0x5aa8e823, 0x95f2884a), TOBN(0x834de6ed, 0x0278a0af),
++     TOBN(0xc8e1ee9a, 0x5f25bd12), TOBN(0x9259ceaa, 0x6f7ab271),
++     TOBN(0x7e6d97a2, 0x77d00b76), TOBN(0x5c0c6eea, 0xa437832a),
++     TOBN(0x5232c20f, 0x5606b81d), TOBN(0xabd7b375, 0x0d991ee5),
++     TOBN(0x4d2bfe35, 0x8632d951), TOBN(0x78f85146, 0x98ed9364),
++     TOBN(0x951873f0, 0xf30c3282), TOBN(0x0da8ac80, 0xa789230b),
++     TOBN(0x3ac7789c, 0x5398967f), TOBN(0xa69b8f7f, 0xbdda0fb5),
++     TOBN(0xe5db7717, 0x6add8545), TOBN(0x1b71cb66, 0x72c49b66),
++     TOBN(0xd8560739, 0x68421d77), TOBN(0x03840fe8, 0x83e3afea),
++     TOBN(0xb391dad5, 0x1ec69977), TOBN(0xae243fb9, 0x307f6726),
++     TOBN(0xc88ac87b, 0xe8ca160c), TOBN(0x5174cced, 0x4ce355f4),
++     TOBN(0x98a35966, 0xe58ba37d), TOBN(0xfdcc8da2, 0x7817335d),
++     TOBN(0x5b752830, 0x83fbc7bf), TOBN(0x68e419d4, 0xd9c96984),
++     TOBN(0x409a39f4, 0x02a40380), TOBN(0x88940faf, 0x1fe977bc),
++     TOBN(0xc640a94b, 0x8f8edea6), TOBN(0x1e22cd17, 0xed11547d),
++     TOBN(0xe28568ce, 0x59ffc3e2), TOBN(0x60aa1b55, 0xc1dee4e7),
++     TOBN(0xc67497c8, 0x837cb363), TOBN(0x06fb438a, 0x105a2bf2),
++     TOBN(0x30357ec4, 0x500d8e20), TOBN(0x1ad9095d, 0x0670db10),
++     TOBN(0x7f589a05, 0xc73b7cfd), TOBN(0xf544607d, 0x880d6d28),
++     TOBN(0x17ba93b1, 0xa20ef103), TOBN(0xad859130, 0x6ba6577b),
++     TOBN(0x65c91cf6, 0x6fa214a0), TOBN(0xd7d49c6c, 0x27990da5),
++     TOBN(0xecd9ec8d, 0x20bb569d), TOBN(0xbd4b2502, 0xeeffbc33),
++     TOBN(0x2056ca5a, 0x6bed0467), TOBN(0x7916a1f7, 0x5b63728c),
++     TOBN(0xd4f9497d, 0x53a4f566), TOBN(0x89734664, 0x97b56810),
++     TOBN(0xf8e1da74, 0x0494a621), TOBN(0x82546a93, 0x8d011c68),
++     TOBN(0x1f3acb19, 0xc61ac162), TOBN(0x52f8fa9c, 0xabad0d3e),
++     TOBN(0x15356523, 0xb4b7ea43), TOBN(0x5a16ad61, 0xae608125),
++     TOBN(0xb0bcb87f, 0x4faed184), TOBN(0x5f236b1d, 0x5029f45f),
++     TOBN(0xd42c7607, 0x0bc6b1fc), TOBN(0xc644324e, 0x68aefce3),
++     TOBN(0x8e191d59, 0x5c5d8446), TOBN(0xc0208077, 0x13ae1979),
++     TOBN(0xadcaee55, 0x3ba59cc7), TOBN(0x20ed6d6b, 0xa2cb81ba),
++     TOBN(0x0952ba19, 0xb6efcffc), TOBN(0x60f12d68, 0x97c0b87c),
++     TOBN(0x4ee2c7c4, 0x9caa30bc), TOBN(0x767238b7, 0x97fbff4e),
++     TOBN(0xebc73921, 0x501b5d92), TOBN(0x3279e3df, 0xc2a37737),
++     TOBN(0x9fc12bc8, 0x6d197543), TOBN(0xfa94dc6f, 0x0a40db4e),
++     TOBN(0x7392b41a, 0x530ccbbd), TOBN(0x87c82146, 0xea823525),
++     TOBN(0xa52f984c, 0x05d98d0c), TOBN(0x2ae57d73, 0x5ef6974c),
++     TOBN(0x9377f7bf, 0x3042a6dd), TOBN(0xb1a007c0, 0x19647a64),
++     TOBN(0xfaa9079a, 0x0cca9767), TOBN(0x3d81a25b, 0xf68f72d5),
++     TOBN(0x752067f8, 0xff81578e), TOBN(0x78622150, 0x9045447d),
++     TOBN(0xc0c22fcf, 0x0505aa6f), TOBN(0x1030f0a6, 0x6bed1c77),
++     TOBN(0x31f29f15, 0x1f0bd739), TOBN(0x2d7989c7, 0xe6debe85),
++     TOBN(0x5c070e72, 0x8e677e98), TOBN(0x0a817bd3, 0x06e81fd5),
++     TOBN(0xc110d830, 0xb0f2ac95), TOBN(0x48d0995a, 0xab20e64e),
++     TOBN(0x0f3e00e1, 0x7729cd9a), TOBN(0x2a570c20, 0xdd556946),
++     TOBN(0x912dbcfd, 0x4e86214d), TOBN(0x2d014ee2, 0xcf615498),
++     TOBN(0x55e2b1e6, 0x3530d76e), TOBN(0xc5135ae4, 0xfd0fd6d1),
++     TOBN(0x0066273a, 0xd4f3049f), TOBN(0xbb8e9893, 0xe7087477),
++     TOBN(0x2dba1ddb, 0x14c6e5fd), TOBN(0xdba37886, 0x51f57e6c),
++     TOBN(0x5aaee0a6, 0x5a72f2cf), TOBN(0x1208bfbf, 0x7bea5642),
++     TOBN(0xf5c6aa3b, 0x67872c37), TOBN(0xd726e083, 0x43f93224),
++     TOBN(0x1854daa5, 0x061f1658), TOBN(0xc0016df1, 0xdf0cd2b3),
++     TOBN(0xc2a3f23e, 0x833d50de), TOBN(0x73b681d2, 0xbbbd3017),
++     TOBN(0x2f046dc4, 0x3ac343c0), TOBN(0x9c847e7d, 0x85716421),
++     TOBN(0xe1e13c91, 0x0917eed4), TOBN(0x3fc9eebd, 0x63a1b9c6),
++     TOBN(0x0f816a72, 0x7fe02299), TOBN(0x6335ccc2, 0x294f3319),
++     TOBN(0x3820179f, 0x4745c5be), TOBN(0xe647b782, 0x922f066e),
++     TOBN(0xc22e49de, 0x02cafb8a), TOBN(0x299bc2ff, 0xfcc2eccc),
++     TOBN(0x9a8feea2, 0x6e0e8282), TOBN(0xa627278b, 0xfe893205),
++     TOBN(0xa7e19733, 0x7933e47b), TOBN(0xf4ff6b13, 0x2e766402),
++     TOBN(0xa4d8be0a, 0x98440d9f), TOBN(0x658f5c2f, 0x38938808),
++     TOBN(0x90b75677, 0xc95b3b3e), TOBN(0xfa044269, 0x3137b6ff),
++     TOBN(0x077b039b, 0x43c47c29), TOBN(0xcca95dd3, 0x8a6445b2),
++     TOBN(0x0b498ba4, 0x2333fc4c), TOBN(0x274f8e68, 0xf736a1b1),
++     TOBN(0x6ca348fd, 0x5f1d4b2e), TOBN(0x24d3be78, 0xa8f10199),
++     TOBN(0x8535f858, 0xca14f530), TOBN(0xa6e7f163, 0x5b982e51),
++     TOBN(0x847c8512, 0x36e1bf62), TOBN(0xf6a7c58e, 0x03448418),
++     TOBN(0x583f3703, 0xf9374ab6), TOBN(0x864f9195, 0x6e564145),
++     TOBN(0x33bc3f48, 0x22526d50), TOBN(0x9f323c80, 0x1262a496),
++     TOBN(0xaa97a7ae, 0x3f046a9a), TOBN(0x70da183e, 0xdf8a039a),
++     TOBN(0x5b68f71c, 0x52aa0ba6), TOBN(0x9be0fe51, 0x21459c2d),
++     TOBN(0xc1e17eb6, 0xcbc613e5), TOBN(0x33131d55, 0x497ea61c),
++     TOBN(0x2f69d39e, 0xaf7eded5), TOBN(0x73c2f434, 0xde6af11b),
++     TOBN(0x4ca52493, 0xa4a375fa), TOBN(0x5f06787c, 0xb833c5c2),
++     TOBN(0x814e091f, 0x3e6e71cf), TOBN(0x76451f57, 0x8b746666)}
++    ,
++    {TOBN(0x80f9bdef, 0x694db7e0), TOBN(0xedca8787, 0xb9fcddc6),
++     TOBN(0x51981c34, 0x03b8dce1), TOBN(0x4274dcf1, 0x70e10ba1),
++     TOBN(0xf72743b8, 0x6def6d1a), TOBN(0xd25b1670, 0xebdb1866),
++     TOBN(0xc4491e8c, 0x050c6f58), TOBN(0x2be2b2ab, 0x87fbd7f5),
++     TOBN(0x3e0e5c9d, 0xd111f8ec), TOBN(0xbcc33f8d, 0xb7c4e760),
++     TOBN(0x702f9a91, 0xbd392a51), TOBN(0x7da4a795, 0xc132e92d),
++     TOBN(0x1a0b0ae3, 0x0bb1151b), TOBN(0x54febac8, 0x02e32251),
++     TOBN(0xea3a5082, 0x694e9e78), TOBN(0xe58ffec1, 0xe4fe40b8),
++     TOBN(0xf85592fc, 0xd1e0cf9e), TOBN(0xdea75f0d, 0xc0e7b2e8),
++     TOBN(0xc04215cf, 0xc135584e), TOBN(0x174fc727, 0x2f57092a),
++     TOBN(0xe7277877, 0xeb930bea), TOBN(0x504caccb, 0x5eb02a5a),
++     TOBN(0xf9fe08f7, 0xf5241b9b), TOBN(0xe7fb62f4, 0x8d5ca954),
++     TOBN(0xfbb8349d, 0x29c4120b), TOBN(0x9f94391f, 0xc0d0d915),
++     TOBN(0xc4074fa7, 0x5410ba51), TOBN(0xa66adbf6, 0x150a5911),
++     TOBN(0xc164543c, 0x34bfca38), TOBN(0xe0f27560, 0xb9e1ccfc),
++     TOBN(0x99da0f53, 0xe820219c), TOBN(0xe8234498, 0xc6b4997a),
++     TOBN(0xcfb88b76, 0x9d4c5423), TOBN(0x9e56eb10, 0xb0521c49),
++     TOBN(0x418e0b5e, 0xbe8700a1), TOBN(0x00cbaad6, 0xf93cb58a),
++     TOBN(0xe923fbde, 0xd92a5e67), TOBN(0xca4979ac, 0x1f347f11),
++     TOBN(0x89162d85, 0x6bc0585b), TOBN(0xdd6254af, 0xac3c70e3),
++     TOBN(0x7b23c513, 0x516e19e4), TOBN(0x56e2e847, 0xc5c4d593),
++     TOBN(0x9f727d73, 0x5ce71ef6), TOBN(0x5b6304a6, 0xf79a44c5),
++     TOBN(0x6638a736, 0x3ab7e433), TOBN(0x1adea470, 0xfe742f83),
++     TOBN(0xe054b854, 0x5b7fc19f), TOBN(0xf935381a, 0xba1d0698),
++     TOBN(0x546eab2d, 0x799e9a74), TOBN(0x96239e0e, 0xa949f729),
++     TOBN(0xca274c6b, 0x7090055a), TOBN(0x835142c3, 0x9020c9b0),
++     TOBN(0xa405667a, 0xa2e8807f), TOBN(0x29f2c085, 0x1aa3d39e),
++     TOBN(0xcc555d64, 0x42fc72f5), TOBN(0xe856e0e7, 0xfbeacb3c),
++     TOBN(0xb5504f9d, 0x918e4936), TOBN(0x65035ef6, 0xb2513982),
++     TOBN(0x0553a0c2, 0x6f4d9cb9), TOBN(0x6cb10d56, 0xbea85509),
++     TOBN(0x48d957b7, 0xa242da11), TOBN(0x16a4d3dd, 0x672b7268),
++     TOBN(0x3d7e637c, 0x8502a96b), TOBN(0x27c7032b, 0x730d463b),
++     TOBN(0xbdc02b18, 0xe4136a14), TOBN(0xbacf969d, 0x678e32bf),
++     TOBN(0xc98d89a3, 0xdd9c3c03), TOBN(0x7b92420a, 0x23becc4f),
++     TOBN(0xd4b41f78, 0xc64d565c), TOBN(0x9f969d00, 0x10f28295),
++     TOBN(0xec7f7f76, 0xb13d051a), TOBN(0x08945e1e, 0xa92da585),
++     TOBN(0x55366b7d, 0x5846426f), TOBN(0xe7d09e89, 0x247d441d),
++     TOBN(0x510b404d, 0x736fbf48), TOBN(0x7fa003d0, 0xe784bd7d),
++     TOBN(0x25f7614f, 0x17fd9596), TOBN(0x49e0e0a1, 0x35cb98db),
++     TOBN(0x2c65957b, 0x2e83a76a), TOBN(0x5d40da8d, 0xcddbe0f8),
++     TOBN(0xf2b8c405, 0x050bad24), TOBN(0x8918426d, 0xc2aa4823),
++     TOBN(0x2aeab3dd, 0xa38365a7), TOBN(0x72031717, 0x7c91b690),
++     TOBN(0x8b00d699, 0x60a94120), TOBN(0x478a255d, 0xe99eaeec),
++     TOBN(0xbf656a5f, 0x6f60aafd), TOBN(0xdfd7cb75, 0x5dee77b3),
++     TOBN(0x37f68bb4, 0xa595939d), TOBN(0x03556479, 0x28740217),
++     TOBN(0x8e740e7c, 0x84ad7612), TOBN(0xd89bc843, 0x9044695f),
++     TOBN(0xf7f3da5d, 0x85a9184d), TOBN(0x562563bb, 0x9fc0b074),
++     TOBN(0x06d2e6aa, 0xf88a888e), TOBN(0x612d8643, 0x161fbe7c),
++     TOBN(0x465edba7, 0xf64085e7), TOBN(0xb230f304, 0x29aa8511),
++     TOBN(0x53388426, 0xcda2d188), TOBN(0x90885735, 0x4b666649),
++     TOBN(0x6f02ff9a, 0x652f54f6), TOBN(0x65c82294, 0x5fae2bf0),
++     TOBN(0x7816ade0, 0x62f5eee3), TOBN(0xdcdbdf43, 0xfcc56d70),
++     TOBN(0x9fb3bba3, 0x54530bb2), TOBN(0xbde3ef77, 0xcb0869ea),
++     TOBN(0x89bc9046, 0x0b431163), TOBN(0x4d03d7d2, 0xe4819a35),
++     TOBN(0x33ae4f9e, 0x43b6a782), TOBN(0x216db307, 0x9c88a686),
++     TOBN(0x91dd88e0, 0x00ffedd9), TOBN(0xb280da9f, 0x12bd4840),
++     TOBN(0x32a7cb8a, 0x1635e741), TOBN(0xfe14008a, 0x78be02a7),
++     TOBN(0x3fafb334, 0x1b7ae030), TOBN(0x7fd508e7, 0x5add0ce9),
++     TOBN(0x72c83219, 0xd607ad51), TOBN(0x0f229c0a, 0x8d40964a),
++     TOBN(0x1be2c336, 0x1c878da2), TOBN(0xe0c96742, 0xeab2ab86),
++     TOBN(0x458f8691, 0x3e538cd7), TOBN(0xa7001f6c, 0x8e08ad53),
++     TOBN(0x52b8c6e6, 0xbf5d15ff), TOBN(0x548234a4, 0x011215dd),
++     TOBN(0xff5a9d2d, 0x3d5b4045), TOBN(0xb0ffeeb6, 0x4a904190),
++     TOBN(0x55a3aca4, 0x48607f8b), TOBN(0x8cbd665c, 0x30a0672a),
++     TOBN(0x87f834e0, 0x42583068), TOBN(0x02da2aeb, 0xf3f6e683),
++     TOBN(0x6b763e5d, 0x05c12248), TOBN(0x7230378f, 0x65a8aefc),
++     TOBN(0x93bd80b5, 0x71e8e5ca), TOBN(0x53ab041c, 0xb3b62524),
++     TOBN(0x1b860513, 0x6c9c552e), TOBN(0xe84d402c, 0xd5524e66),
++     TOBN(0xa37f3573, 0xf37f5937), TOBN(0xeb0f6c7d, 0xd1e4fca5),
++     TOBN(0x2965a554, 0xac8ab0fc), TOBN(0x17fbf56c, 0x274676ac),
++     TOBN(0x2e2f6bd9, 0xacf7d720), TOBN(0x41fc8f88, 0x10224766),
++     TOBN(0x517a14b3, 0x85d53bef), TOBN(0xdae327a5, 0x7d76a7d1),
++     TOBN(0x6ad0a065, 0xc4818267), TOBN(0x33aa189b, 0x37c1bbc1),
++     TOBN(0x64970b52, 0x27392a92), TOBN(0x21699a1c, 0x2d1535ea),
++     TOBN(0xcd20779c, 0xc2d7a7fd), TOBN(0xe3186059, 0x99c83cf2),
++     TOBN(0x9b69440b, 0x72c0b8c7), TOBN(0xa81497d7, 0x7b9e0e4d),
++     TOBN(0x515d5c89, 0x1f5f82dc), TOBN(0x9a7f67d7, 0x6361079e),
++     TOBN(0xa8da81e3, 0x11a35330), TOBN(0xe44990c4, 0x4b18be1b),
++     TOBN(0xc7d5ed95, 0xaf103e59), TOBN(0xece8aba7, 0x8dac9261),
++     TOBN(0xbe82b099, 0x9394b8d3), TOBN(0x6830f09a, 0x16adfe83),
++     TOBN(0x250a29b4, 0x88172d01), TOBN(0x8b20bd65, 0xcaff9e02),
++     TOBN(0xb8a7661e, 0xe8a6329a), TOBN(0x4520304d, 0xd3fce920),
++     TOBN(0xae45da1f, 0x2b47f7ef), TOBN(0xe07f5288, 0x5bffc540),
++     TOBN(0xf7997009, 0x3464f874), TOBN(0x2244c2cd, 0xa6fa1f38),
++     TOBN(0x43c41ac1, 0x94d7d9b1), TOBN(0x5bafdd82, 0xc82e7f17),
++     TOBN(0xdf0614c1, 0x5fda0fca), TOBN(0x74b043a7, 0xa8ae37ad),
++     TOBN(0x3ba6afa1, 0x9e71734c), TOBN(0x15d5437e, 0x9c450f2e),
++     TOBN(0x4a5883fe, 0x67e242b1), TOBN(0x5143bdc2, 0x2c1953c2),
++     TOBN(0x542b8b53, 0xfc5e8920), TOBN(0x363bf9a8, 0x9a9cee08),
++     TOBN(0x02375f10, 0xc3486e08), TOBN(0x2037543b, 0x8c5e70d2),
++     TOBN(0x7109bccc, 0x625640b4), TOBN(0xcbc1051e, 0x8bc62c3b),
++     TOBN(0xf8455fed, 0x803f26ea), TOBN(0x6badceab, 0xeb372424),
++     TOBN(0xa2a9ce7c, 0x6b53f5f9), TOBN(0x64246595, 0x1b176d99),
++     TOBN(0xb1298d36, 0xb95c081b), TOBN(0x53505bb8, 0x1d9a9ee6),
++     TOBN(0x3f6f9e61, 0xf2ba70b0), TOBN(0xd07e16c9, 0x8afad453),
++     TOBN(0x9f1694bb, 0xe7eb4a6a), TOBN(0xdfebced9, 0x3cb0bc8e),
++     TOBN(0x92d3dcdc, 0x53868c8b), TOBN(0x174311a2, 0x386107a6),
++     TOBN(0x4109e07c, 0x689b4e64), TOBN(0x30e4587f, 0x2df3dcb6),
++     TOBN(0x841aea31, 0x0811b3b2), TOBN(0x6144d41d, 0x0cce43ea),
++     TOBN(0x464c4581, 0x2a9a7803), TOBN(0xd03d371f, 0x3e158930),
++     TOBN(0xc676d7f2, 0xb1f3390b), TOBN(0x9f7a1b8c, 0xa5b61272),
++     TOBN(0x4ebebfc9, 0xc2e127a9), TOBN(0x4602500c, 0x5dd997bf),
++     TOBN(0x7f09771c, 0x4711230f), TOBN(0x058eb37c, 0x020f09c1),
++     TOBN(0xab693d4b, 0xfee5e38b), TOBN(0x9289eb1f, 0x4653cbc0),
++     TOBN(0xbecf46ab, 0xd51b9cf5), TOBN(0xd2aa9c02, 0x9f0121af),
++     TOBN(0x36aaf7d2, 0xe90dc274), TOBN(0x909e4ea0, 0x48b95a3c),
++     TOBN(0xe6b70496, 0x6f32dbdb), TOBN(0x672188a0, 0x8b030b3e),
++     TOBN(0xeeffe5b3, 0xcfb617e2), TOBN(0x87e947de, 0x7c82709e),
++     TOBN(0xa44d2b39, 0x1770f5a7), TOBN(0xe4d4d791, 0x0e44eb82),
++     TOBN(0x42e69d1e, 0x3f69712a), TOBN(0xbf11c4d6, 0xac6a820e),
++     TOBN(0xb5e7f3e5, 0x42c4224c), TOBN(0xd6b4e81c, 0x449d941c),
++     TOBN(0x5d72bd16, 0x5450e878), TOBN(0x6a61e28a, 0xee25ac54),
++     TOBN(0x33272094, 0xe6f1cd95), TOBN(0x7512f30d, 0x0d18673f),
++     TOBN(0x32f7a4ca, 0x5afc1464), TOBN(0x2f095656, 0x6bbb977b),
++     TOBN(0x586f47ca, 0xa8226200), TOBN(0x02c868ad, 0x1ac07369),
++     TOBN(0x4ef2b845, 0xc613acbe), TOBN(0x43d7563e, 0x0386054c),
++     TOBN(0x54da9dc7, 0xab952578), TOBN(0xb5423df2, 0x26e84d0b),
++     TOBN(0xa8b64eeb, 0x9b872042), TOBN(0xac205782, 0x5990f6df),
++     TOBN(0x4ff696eb, 0x21f4c77a), TOBN(0x1a79c3e4, 0xaab273af),
++     TOBN(0x29bc922e, 0x9436b3f1), TOBN(0xff807ef8, 0xd6d9a27a),
++     TOBN(0x82acea3d, 0x778f22a0), TOBN(0xfb10b2e8, 0x5b5e7469),
++     TOBN(0xc0b16980, 0x2818ee7d), TOBN(0x011afff4, 0xc91c1a2f),
++     TOBN(0x95a6d126, 0xad124418), TOBN(0x31c081a5, 0xe72e295f),
++     TOBN(0x36bb283a, 0xf2f4db75), TOBN(0xd115540f, 0x7acef462),
++     TOBN(0xc7f3a8f8, 0x33f6746c), TOBN(0x21e46f65, 0xfea990ca),
++     TOBN(0x915fd5c5, 0xcaddb0a9), TOBN(0xbd41f016, 0x78614555),
++     TOBN(0x346f4434, 0x426ffb58), TOBN(0x80559436, 0x14dbc204),
++     TOBN(0xf3dd20fe, 0x5a969b7f), TOBN(0x9d59e956, 0xe899a39a),
++     TOBN(0xf1b0971c, 0x8ad4cf4b), TOBN(0x03448860, 0x2ffb8fb8),
++     TOBN(0xf071ac3c, 0x65340ba4), TOBN(0x408d0596, 0xb27fd758),
++     TOBN(0xe7c78ea4, 0x98c364b0), TOBN(0xa4aac4a5, 0x051e8ab5),
++     TOBN(0xb9e1d560, 0x485d9002), TOBN(0x9acd518a, 0x88844455),
++     TOBN(0xe4ca688f, 0xd06f56c0), TOBN(0xa48af70d, 0xdf027972),
++     TOBN(0x691f0f04, 0x5e9a609d), TOBN(0xa9dd82cd, 0xee61270e),
++     TOBN(0x8903ca63, 0xa0ef18d3), TOBN(0x9fb7ee35, 0x3d6ca3bd),
++     TOBN(0xa7b4a09c, 0xabf47d03), TOBN(0x4cdada01, 0x1c67de8e),
++     TOBN(0x52003749, 0x9355a244), TOBN(0xe77fd2b6, 0x4f2151a9),
++     TOBN(0x695d6cf6, 0x66b4efcb), TOBN(0xc5a0cacf, 0xda2cfe25),
++     TOBN(0x104efe5c, 0xef811865), TOBN(0xf52813e8, 0x9ea5cc3d),
++     TOBN(0x855683dc, 0x40b58dbc), TOBN(0x0338ecde, 0x175fcb11),
++     TOBN(0xf9a05637, 0x74921592), TOBN(0xb4f1261d, 0xb9bb9d31),
++     TOBN(0x551429b7, 0x4e9c5459), TOBN(0xbe182e6f, 0x6ea71f53),
++     TOBN(0xd3a3b07c, 0xdfc50573), TOBN(0x9ba1afda, 0x62be8d44),
++     TOBN(0x9bcfd2cb, 0x52ab65d3), TOBN(0xdf11d547, 0xa9571802),
++     TOBN(0x099403ee, 0x02a2404a), TOBN(0x497406f4, 0x21088a71),
++     TOBN(0x99479409, 0x5004ae71), TOBN(0xbdb42078, 0xa812c362),
++     TOBN(0x2b72a30f, 0xd8828442), TOBN(0x283add27, 0xfcb5ed1c),
++     TOBN(0xf7c0e200, 0x66a40015), TOBN(0x3e3be641, 0x08b295ef),
++     TOBN(0xac127dc1, 0xe038a675), TOBN(0x729deff3, 0x8c5c6320),
++     TOBN(0xb7df8fd4, 0xa90d2c53), TOBN(0x9b74b0ec, 0x681e7cd3),
++     TOBN(0x5cb5a623, 0xdab407e5), TOBN(0xcdbd3615, 0x76b340c6),
++     TOBN(0xa184415a, 0x7d28392c), TOBN(0xc184c1d8, 0xe96f7830),
++     TOBN(0xc3204f19, 0x81d3a80f), TOBN(0xfde0c841, 0xc8e02432),
++     TOBN(0x78203b3e, 0x8149e0c1), TOBN(0x5904bdbb, 0x08053a73),
++     TOBN(0x30fc1dd1, 0x101b6805), TOBN(0x43c223bc, 0x49aa6d49),
++     TOBN(0x9ed67141, 0x7a174087), TOBN(0x311469a0, 0xd5997008),
++     TOBN(0xb189b684, 0x5e43fc61), TOBN(0xf3282375, 0xe0d3ab57),
++     TOBN(0x4fa34b67, 0xb1181da8), TOBN(0x621ed0b2, 0x99ee52b8),
++     TOBN(0x9b178de1, 0xad990676), TOBN(0xd51de67b, 0x56d54065),
++     TOBN(0x2a2c27c4, 0x7538c201), TOBN(0x33856ec8, 0x38a40f5c),
++     TOBN(0x2522fc15, 0xbe6cdcde), TOBN(0x1e603f33, 0x9f0c6f89),
++     TOBN(0x7994edc3, 0x103e30a6), TOBN(0x033a00db, 0x220c853e),
++     TOBN(0xd3cfa409, 0xf7bb7fd7), TOBN(0x70f8781e, 0x462d18f6),
++     TOBN(0xbbd82980, 0x687fe295), TOBN(0x6eef4c32, 0x595669f3),
++     TOBN(0x86a9303b, 0x2f7e85c3), TOBN(0x5fce4621, 0x71988f9b),
++     TOBN(0x5b935bf6, 0xc138acb5), TOBN(0x30ea7d67, 0x25661212),
++     TOBN(0xef1eb5f4, 0xe51ab9a2), TOBN(0x0587c98a, 0xae067c78),
++     TOBN(0xb3ce1b3c, 0x77ca9ca6), TOBN(0x2a553d4d, 0x54b5f057),
++     TOBN(0xc7898236, 0x4da29ec2), TOBN(0xdbdd5d13, 0xb9c57316),
++     TOBN(0xc57d6e6b, 0x2cd80d47), TOBN(0x80b460cf, 0xfe9e7391),
++     TOBN(0x98648cab, 0xf963c31e), TOBN(0x67f9f633, 0xcc4d32fd),
++     TOBN(0x0af42a9d, 0xfdf7c687), TOBN(0x55f292a3, 0x0b015ea7),
++     TOBN(0x89e468b2, 0xcd21ab3d), TOBN(0xe504f022, 0xc393d392),
++     TOBN(0xab21e1d4, 0xa5013af9), TOBN(0xe3283f78, 0xc2c28acb),
++     TOBN(0xf38b35f6, 0x226bf99f), TOBN(0xe8354274, 0x0e291e69),
++     TOBN(0x61673a15, 0xb20c162d), TOBN(0xc101dc75, 0xb04fbdbe),
++     TOBN(0x8323b4c2, 0x255bd617), TOBN(0x6c969693, 0x6c2a9154),
++     TOBN(0xc6e65860, 0x62679387), TOBN(0x8e01db0c, 0xb8c88e23),
++     TOBN(0x33c42873, 0x893a5559), TOBN(0x7630f04b, 0x47a3e149),
++     TOBN(0xb5d80805, 0xddcf35f8), TOBN(0x582ca080, 0x77dfe732),
++     TOBN(0x2c7156e1, 0x0b1894a0), TOBN(0x92034001, 0xd81c68c0),
++     TOBN(0xed225d00, 0xc8b115b5), TOBN(0x237f9c22, 0x83b907f2),
++     TOBN(0x0ea2f32f, 0x4470e2c0), TOBN(0xb725f7c1, 0x58be4e95),
++     TOBN(0x0f1dcafa, 0xb1ae5463), TOBN(0x59ed5187, 0x1ba2fc04),
++     TOBN(0xf6e0f316, 0xd0115d4d), TOBN(0x5180b12f, 0xd3691599),
++     TOBN(0x157e32c9, 0x527f0a41), TOBN(0x7b0b081d, 0xa8e0ecc0),
++     TOBN(0x6dbaaa8a, 0xbf4f0dd0), TOBN(0x99b289c7, 0x4d252696),
++     TOBN(0x79b7755e, 0xdbf864fe), TOBN(0x6974e2b1, 0x76cad3ab),
++     TOBN(0x35dbbee2, 0x06ddd657), TOBN(0xe7cbdd11, 0x2ff3a96d),
++     TOBN(0x88381968, 0x076be758), TOBN(0x2d737e72, 0x08c91f5d),
++     TOBN(0x5f83ab62, 0x86ec3776), TOBN(0x98aa649d, 0x945fa7a1),
++     TOBN(0xf477ec37, 0x72ef0933), TOBN(0x66f52b1e, 0x098c17b1),
++     TOBN(0x9eec58fb, 0xd803738b), TOBN(0x91aaade7, 0xe4e86aa4),
++     TOBN(0x6b1ae617, 0xa5b51492), TOBN(0x63272121, 0xbbc45974),
++     TOBN(0x7e0e28f0, 0x862c5129), TOBN(0x0a8f79a9, 0x3321a4a0),
++     TOBN(0xe26d1664, 0x5041c88f), TOBN(0x0571b805, 0x53233e3a),
++     TOBN(0xd1b0ccde, 0xc9520711), TOBN(0x55a9e4ed, 0x3c8b84bf),
++     TOBN(0x9426bd39, 0xa1fef314), TOBN(0x4f5f638e, 0x6eb93f2b),
++     TOBN(0xba2a1ed3, 0x2bf9341b), TOBN(0xd63c1321, 0x4d42d5a9),
++     TOBN(0xd2964a89, 0x316dc7c5), TOBN(0xd1759606, 0xca511851),
++     TOBN(0xd8a9201f, 0xf9e6ed35), TOBN(0xb7b5ee45, 0x6736925a),
++     TOBN(0x0a83fbbc, 0x99581af7), TOBN(0x3076bc40, 0x64eeb051),
++     TOBN(0x5511c98c, 0x02dec312), TOBN(0x270de898, 0x238dcb78),
++     TOBN(0x2cf4cf9c, 0x539c08c9), TOBN(0xa70cb65e, 0x38d3b06e),
++     TOBN(0xb12ec10e, 0xcfe57bbd), TOBN(0x82c7b656, 0x35a0c2b5),
++     TOBN(0xddc7d5cd, 0x161c67bd), TOBN(0xe32e8985, 0xae3a32cc),
++     TOBN(0x7aba9444, 0xd11a5529), TOBN(0xe964ed02, 0x2427fa1a),
++     TOBN(0x1528392d, 0x24a1770a), TOBN(0xa152ce2c, 0x12c72fcd),
++     TOBN(0x714553a4, 0x8ec07649), TOBN(0x18b4c290, 0x459dd453),
++     TOBN(0xea32b714, 0x7b64b110), TOBN(0xb871bfa5, 0x2e6f07a2),
++     TOBN(0xb67112e5, 0x9e2e3c9b), TOBN(0xfbf250e5, 0x44aa90f6),
++     TOBN(0xf77aedb8, 0xbd539006), TOBN(0x3b0cdf9a, 0xd172a66f),
++     TOBN(0xedf69fea, 0xf8c51187), TOBN(0x05bb67ec, 0x741e4da7),
++     TOBN(0x47df0f32, 0x08114345), TOBN(0x56facb07, 0xbb9792b1),
++     TOBN(0xf3e007e9, 0x8f6229e4), TOBN(0x62d103f4, 0x526fba0f),
++     TOBN(0x4f33bef7, 0xb0339d79), TOBN(0x9841357b, 0xb59bfec1),
++     TOBN(0xfa8dbb59, 0xc34e6705), TOBN(0xc3c7180b, 0x7fdaa84c),
++     TOBN(0xf95872fc, 0xa4108537), TOBN(0x8750cc3b, 0x932a3e5a),
++     TOBN(0xb61cc69d, 0xb7275d7d), TOBN(0xffa0168b, 0x2e59b2e9),
++     TOBN(0xca032abc, 0x6ecbb493), TOBN(0x1d86dbd3, 0x2c9082d8),
++     TOBN(0xae1e0b67, 0xe28ef5ba), TOBN(0x2c9a4699, 0xcb18e169),
++     TOBN(0x0ecd0e33, 0x1e6bbd20), TOBN(0x571b360e, 0xaf5e81d2),
++     TOBN(0xcd9fea58, 0x101c1d45), TOBN(0x6651788e, 0x18880452),
++     TOBN(0xa9972635, 0x1f8dd446), TOBN(0x44bed022, 0xe37281d0),
++     TOBN(0x094b2b2d, 0x33da525d), TOBN(0xf193678e, 0x13144fd8),
++     TOBN(0xb8ab5ba4, 0xf4c1061d), TOBN(0x4343b5fa, 0xdccbe0f4),
++     TOBN(0xa8702371, 0x63812713), TOBN(0x47bf6d2d, 0xf7611d93),
++     TOBN(0x46729b8c, 0xbd21e1d7), TOBN(0x7484d4e0, 0xd629e77d),
++     TOBN(0x830e6eea, 0x60dbac1f), TOBN(0x23d8c484, 0xda06a2f7),
++     TOBN(0x896714b0, 0x50ca535b), TOBN(0xdc8d3644, 0xebd97a9b),
++     TOBN(0x106ef9fa, 0xb12177b4), TOBN(0xf79bf464, 0x534d5d9c),
++     TOBN(0x2537a349, 0xa6ab360b), TOBN(0xc7c54253, 0xa00c744f),
++     TOBN(0xb3c7a047, 0xe5911a76), TOBN(0x61ffa5c8, 0x647f1ee7),
++     TOBN(0x15aed36f, 0x8f56ab42), TOBN(0x6a0d41b0, 0xa3ff9ac9),
++     TOBN(0x68f469f5, 0xcc30d357), TOBN(0xbe9adf81, 0x6b72be96),
++     TOBN(0x1cd926fe, 0x903ad461), TOBN(0x7e89e38f, 0xcaca441b),
++     TOBN(0xf0f82de5, 0xfacf69d4), TOBN(0x363b7e76, 0x4775344c),
++     TOBN(0x6894f312, 0xb2e36d04), TOBN(0x3c6cb4fe, 0x11d1c9a5),
++     TOBN(0x85d9c339, 0x4008e1f2), TOBN(0x5e9a85ea, 0x249f326c),
++     TOBN(0xdc35c60a, 0x678c5e06), TOBN(0xc08b944f, 0x9f86fba9),
++     TOBN(0xde40c02c, 0x89f71f0f), TOBN(0xad8f3e31, 0xff3da3c0),
++     TOBN(0x3ea5096b, 0x42125ded), TOBN(0x13879cbf, 0xa7379183),
++     TOBN(0x6f4714a5, 0x6b306a0b), TOBN(0x359c2ea6, 0x67646c5e),
++     TOBN(0xfacf8943, 0x07726368), TOBN(0x07a58935, 0x65ff431e),
++     TOBN(0x24d661d1, 0x68754ab0), TOBN(0x801fce1d, 0x6f429a76),
++     TOBN(0xc068a85f, 0xa58ce769), TOBN(0xedc35c54, 0x5d5eca2b),
++     TOBN(0xea31276f, 0xa3f660d1), TOBN(0xa0184ebe, 0xb8fc7167),
++     TOBN(0x0f20f21a, 0x1d8db0ae), TOBN(0xd96d095f, 0x56c35e12),
++     TOBN(0xedf402b5, 0xf8c2a25b), TOBN(0x1bb772b9, 0x059204b6),
++     TOBN(0x50cbeae2, 0x19b4e34c), TOBN(0x93109d80, 0x3fa0845a),
++     TOBN(0x54f7ccf7, 0x8ef59fb5), TOBN(0x3b438fe2, 0x88070963),
++     TOBN(0x9e28c659, 0x31f3ba9b), TOBN(0x9cc31b46, 0xead9da92),
++     TOBN(0x3c2f0ba9, 0xb733aa5f), TOBN(0xdece47cb, 0xf05af235),
++     TOBN(0xf8e3f715, 0xa2ac82a5), TOBN(0xc97ba641, 0x2203f18a),
++     TOBN(0xc3af5504, 0x09c11060), TOBN(0x56ea2c05, 0x46af512d),
++     TOBN(0xfac28daf, 0xf3f28146), TOBN(0x87fab43a, 0x959ef494),}
++    ,
++    {TOBN(0x09891641, 0xd4c5105f), TOBN(0x1ae80f8e, 0x6d7fbd65),
++     TOBN(0x9d67225f, 0xbee6bdb0), TOBN(0x3b433b59, 0x7fc4d860),
++     TOBN(0x44e66db6, 0x93e85638), TOBN(0xf7b59252, 0xe3e9862f),
++     TOBN(0xdb785157, 0x665c32ec), TOBN(0x702fefd7, 0xae362f50),
++     TOBN(0x3754475d, 0x0fefb0c3), TOBN(0xd48fb56b, 0x46d7c35d),
++     TOBN(0xa070b633, 0x363798a4), TOBN(0xae89f3d2, 0x8fdb98e6),
++     TOBN(0x970b89c8, 0x6363d14c), TOBN(0x89817521, 0x67abd27d),
++     TOBN(0x9bf7d474, 0x44d5a021), TOBN(0xb3083baf, 0xcac72aee),
++     TOBN(0x389741de, 0xbe949a44), TOBN(0x638e9388, 0x546a4fa5),
++     TOBN(0x3fe6419c, 0xa0047bdc), TOBN(0x7047f648, 0xaaea57ca),
++     TOBN(0x54e48a90, 0x41fbab17), TOBN(0xda8e0b28, 0x576bdba2),
++     TOBN(0xe807eebc, 0xc72afddc), TOBN(0x07d3336d, 0xf42577bf),
++     TOBN(0x62a8c244, 0xbfe20925), TOBN(0x91c19ac3, 0x8fdce867),
++     TOBN(0x5a96a5d5, 0xdd387063), TOBN(0x61d587d4, 0x21d324f6),
++     TOBN(0xe87673a2, 0xa37173ea), TOBN(0x23848008, 0x53778b65),
++     TOBN(0x10f8441e, 0x05bab43e), TOBN(0xfa11fe12, 0x4621efbe),
++     TOBN(0x047b772e, 0x81685d7b), TOBN(0x23f27d81, 0xbf34a976),
++     TOBN(0xc27608e2, 0x915f48ef), TOBN(0x3b0b43fa, 0xa521d5c3),
++     TOBN(0x7613fb26, 0x63ca7284), TOBN(0x7f5729b4, 0x1d4db837),
++     TOBN(0x87b14898, 0x583b526b), TOBN(0x00b732a6, 0xbbadd3d1),
++     TOBN(0x8e02f426, 0x2048e396), TOBN(0x436b50b6, 0x383d9de4),
++     TOBN(0xf78d3481, 0x471e85ad), TOBN(0x8b01ea6a, 0xd005c8d6),
++     TOBN(0xd3c7afee, 0x97015c07), TOBN(0x46cdf1a9, 0x4e3ba2ae),
++     TOBN(0x7a42e501, 0x83d3a1d2), TOBN(0xd54b5268, 0xb541dff4),
++     TOBN(0x3f24cf30, 0x4e23e9bc), TOBN(0x4387f816, 0x126e3624),
++     TOBN(0x26a46a03, 0x3b0b6d61), TOBN(0xaf1bc845, 0x8b2d777c),
++     TOBN(0x25c401ba, 0x527de79c), TOBN(0x0e1346d4, 0x4261bbb6),
++     TOBN(0x4b96c44b, 0x287b4bc7), TOBN(0x658493c7, 0x5254562f),
++     TOBN(0x23f949fe, 0xb8a24a20), TOBN(0x17ebfed1, 0xf52ca53f),
++     TOBN(0x9b691bbe, 0xbcfb4853), TOBN(0x5617ff6b, 0x6278a05d),
++     TOBN(0x241b34c5, 0xe3c99ebd), TOBN(0xfc64242e, 0x1784156a),
++     TOBN(0x4206482f, 0x695d67df), TOBN(0xb967ce0e, 0xee27c011),
++     TOBN(0x65db3751, 0x21c80b5d), TOBN(0x2e7a563c, 0xa31ecca0),
++     TOBN(0xe56ffc4e, 0x5238a07e), TOBN(0x3d6c2966, 0x32ced854),
++     TOBN(0xe99d7d1a, 0xaf70b885), TOBN(0xafc3bad9, 0x2d686459),
++     TOBN(0x9c78bf46, 0x0cc8ba5b), TOBN(0x5a439519, 0x18955aa3),
++     TOBN(0xf8b517a8, 0x5fe4e314), TOBN(0xe60234d0, 0xfcb8906f),
++     TOBN(0xffe542ac, 0xf2061b23), TOBN(0x287e191f, 0x6b4cb59c),
++     TOBN(0x21857ddc, 0x09d877d8), TOBN(0x1c23478c, 0x14678941),
++     TOBN(0xbbf0c056, 0xb6e05ea4), TOBN(0x82da4b53, 0xb01594fe),
++     TOBN(0xf7526791, 0xfadb8608), TOBN(0x049e832d, 0x7b74cdf6),
++     TOBN(0xa43581cc, 0xc2b90a34), TOBN(0x73639eb8, 0x9360b10c),
++     TOBN(0x4fba331f, 0xe1e4a71b), TOBN(0x6ffd6b93, 0x8072f919),
++     TOBN(0x6e53271c, 0x65679032), TOBN(0x67206444, 0xf14272ce),
++     TOBN(0xc0f734a3, 0xb2335834), TOBN(0x9526205a, 0x90ef6860),
++     TOBN(0xcb8be717, 0x04e2bb0d), TOBN(0x2418871e, 0x02f383fa),
++     TOBN(0xd7177681, 0x4082c157), TOBN(0xcc914ad0, 0x29c20073),
++     TOBN(0xf186c1eb, 0xe587e728), TOBN(0x6fdb3c22, 0x61bcd5fd),
++     TOBN(0x30d014a6, 0xf2f9f8e9), TOBN(0x963ece23, 0x4fec49d2),
++     TOBN(0x862025c5, 0x9605a8d9), TOBN(0x39874445, 0x19f8929a),
++     TOBN(0x01b6ff65, 0x12bf476a), TOBN(0x598a64d8, 0x09cf7d91),
++     TOBN(0xd7ec7749, 0x93be56ca), TOBN(0x10899785, 0xcbb33615),
++     TOBN(0xb8a092fd, 0x02eee3ad), TOBN(0xa86b3d35, 0x30145270),
++     TOBN(0x323d98c6, 0x8512b675), TOBN(0x4b8bc785, 0x62ebb40f),
++     TOBN(0x7d301f54, 0x413f9cde), TOBN(0xa5e4fb4f, 0x2bab5664),
++     TOBN(0x1d2b252d, 0x1cbfec23), TOBN(0xfcd576bb, 0xe177120d),
++     TOBN(0x04427d3e, 0x83731a34), TOBN(0x2bb9028e, 0xed836e8e),
++     TOBN(0xb36acff8, 0xb612ca7c), TOBN(0xb88fe5ef, 0xd3d9c73a),
++     TOBN(0xbe2a6bc6, 0xedea4eb3), TOBN(0x43b93133, 0x488eec77),
++     TOBN(0xf41ff566, 0xb17106e1), TOBN(0x469e9172, 0x654efa32),
++     TOBN(0xb4480f04, 0x41c23fa3), TOBN(0xb4712eb0, 0xc1989a2e),
++     TOBN(0x3ccbba0f, 0x93a29ca7), TOBN(0x6e205c14, 0xd619428c),
++     TOBN(0x90db7957, 0xb3641686), TOBN(0x0432691d, 0x45ac8b4e),
++     TOBN(0x07a759ac, 0xf64e0350), TOBN(0x0514d89c, 0x9c972517),
++     TOBN(0x1701147f, 0xa8e67fc3), TOBN(0x9e2e0b8b, 0xab2085be),
++     TOBN(0xd5651824, 0xac284e57), TOBN(0x890d4325, 0x74893664),
++     TOBN(0x8a7c5e6e, 0xc55e68a3), TOBN(0xbf12e90b, 0x4339c85a),
++     TOBN(0x31846b85, 0xf922b655), TOBN(0x9a54ce4d, 0x0bf4d700),
++     TOBN(0xd7f4e83a, 0xf1a14295), TOBN(0x916f955c, 0xb285d4f9),
++     TOBN(0xe57bb0e0, 0x99ffdaba), TOBN(0x28a43034, 0xeab0d152),
++     TOBN(0x0a36ffa2, 0xb8a9cef8), TOBN(0x5517407e, 0xb9ec051a),
++     TOBN(0x9c796096, 0xea68e672), TOBN(0x853db5fb, 0xfb3c77fb),
++     TOBN(0x21474ba9, 0xe864a51a), TOBN(0x6c267699, 0x6e8a1b8b),
++     TOBN(0x7c823626, 0x94120a28), TOBN(0xe61e9a48, 0x8383a5db),
++     TOBN(0x7dd75003, 0x9f84216d), TOBN(0xab020d07, 0xad43cd85),
++     TOBN(0x9437ae48, 0xda12c659), TOBN(0x6449c2eb, 0xe65452ad),
++     TOBN(0xcc7c4c1c, 0x2cf9d7c1), TOBN(0x1320886a, 0xee95e5ab),
++     TOBN(0xbb7b9056, 0xbeae170c), TOBN(0xc8a5b250, 0xdbc0d662),
++     TOBN(0x4ed81432, 0xc11d2303), TOBN(0x7da66912, 0x1f03769f),
++     TOBN(0x3ac7a5fd, 0x84539828), TOBN(0x14dada94, 0x3bccdd02),
++     TOBN(0x8b84c321, 0x7ef6b0d1), TOBN(0x52a9477a, 0x7c933f22),
++     TOBN(0x5ef6728a, 0xfd440b82), TOBN(0x5c3bd859, 0x6ce4bd5e),
++     TOBN(0x918b80f5, 0xf22c2d3e), TOBN(0x368d5040, 0xb7bb6cc5),
++     TOBN(0xb66142a1, 0x2695a11c), TOBN(0x60ac583a, 0xeb19ea70),
++     TOBN(0x317cbb98, 0x0eab2437), TOBN(0x8cc08c55, 0x5e2654c8),
++     TOBN(0xfe2d6520, 0xe6d8307f), TOBN(0xe9f147f3, 0x57428993),
++     TOBN(0x5f9c7d14, 0xd2fd6cf1), TOBN(0xa3ecd064, 0x2d4fcbb0),
++     TOBN(0xad83fef0, 0x8e7341f7), TOBN(0x643f23a0, 0x3a63115c),
++     TOBN(0xd38a78ab, 0xe65ab743), TOBN(0xbf7c75b1, 0x35edc89c),
++     TOBN(0x3dd8752e, 0x530df568), TOBN(0xf85c4a76, 0xe308c682),
++     TOBN(0x4c9955b2, 0xe68acf37), TOBN(0xa544df3d, 0xab32af85),
++     TOBN(0x4b8ec3f5, 0xa25cf493), TOBN(0x4d8f2764, 0x1a622feb),
++     TOBN(0x7bb4f7aa, 0xf0dcbc49), TOBN(0x7de551f9, 0x70bbb45b),
++     TOBN(0xcfd0f3e4, 0x9f2ca2e5), TOBN(0xece58709, 0x1f5c76ef),
++     TOBN(0x32920edd, 0x167d79ae), TOBN(0x039df8a2, 0xfa7d7ec1),
++     TOBN(0xf46206c0, 0xbb30af91), TOBN(0x1ff5e2f5, 0x22676b59),
++     TOBN(0x11f4a039, 0x6ea51d66), TOBN(0x506c1445, 0x807d7a26),
++     TOBN(0x60da5705, 0x755a9b24), TOBN(0x8fc8cc32, 0x1f1a319e),
++     TOBN(0x83642d4d, 0x9433d67d), TOBN(0x7fa5cb8f, 0x6a7dd296),
++     TOBN(0x576591db, 0x9b7bde07), TOBN(0x13173d25, 0x419716fb),
++     TOBN(0xea30599d, 0xd5b340ff), TOBN(0xfc6b5297, 0xb0fe76c5),
++     TOBN(0x1c6968c8, 0xab8f5adc), TOBN(0xf723c7f5, 0x901c928d),
++     TOBN(0x4203c321, 0x9773d402), TOBN(0xdf7c6aa3, 0x1b51dd47),
++     TOBN(0x3d49e37a, 0x552be23c), TOBN(0x57febee8, 0x0b5a6e87),
++     TOBN(0xc5ecbee4, 0x7bd8e739), TOBN(0x79d44994, 0xae63bf75),
++     TOBN(0x168bd00f, 0x38fb8923), TOBN(0x75d48ee4, 0xd0533130),
++     TOBN(0x554f77aa, 0xdb5cdf33), TOBN(0x3396e896, 0x3c696769),
++     TOBN(0x2fdddbf2, 0xd3fd674e), TOBN(0xbbb8f6ee, 0x99d0e3e5),
++     TOBN(0x51b90651, 0xcbae2f70), TOBN(0xefc4bc05, 0x93aaa8eb),
++     TOBN(0x8ecd8689, 0xdd1df499), TOBN(0x1aee99a8, 0x22f367a5),
++     TOBN(0x95d485b9, 0xae8274c5), TOBN(0x6c14d445, 0x7d30b39c),
++     TOBN(0xbafea90b, 0xbcc1ef81), TOBN(0x7c5f317a, 0xa459a2ed),
++     TOBN(0x01211075, 0x4ef44227), TOBN(0xa17bed6e, 0xdc20f496),
++     TOBN(0x0cdfe424, 0x819853cd), TOBN(0x13793298, 0xf71e2ce7),
++     TOBN(0x3c1f3078, 0xdbbe307b), TOBN(0x6dd1c20e, 0x76ee9936),
++     TOBN(0x23ee4b57, 0x423caa20), TOBN(0x4ac3793b, 0x8efb840e),
++     TOBN(0x934438eb, 0xed1f8ca0), TOBN(0x3e546658, 0x4ebb25a2),
++     TOBN(0xc415af0e, 0xc069896f), TOBN(0xc13eddb0, 0x9a5aa43d),
++     TOBN(0x7a04204f, 0xd49eb8f6), TOBN(0xd0d5bdfc, 0xd74f1670),
++     TOBN(0x3697e286, 0x56fc0558), TOBN(0x10207371, 0x01cebade),
++     TOBN(0x5f87e690, 0x0647a82b), TOBN(0x908e0ed4, 0x8f40054f),
++     TOBN(0xa9f633d4, 0x79853803), TOBN(0x8ed13c9a, 0x4a28b252),
++     TOBN(0x3e2ef676, 0x1f460f64), TOBN(0x53930b9b, 0x36d06336),
++     TOBN(0x347073ac, 0x8fc4979b), TOBN(0x84380e0e, 0x5ecd5597),
++     TOBN(0xe3b22c6b, 0xc4fe3c39), TOBN(0xba4a8153, 0x6c7bebdf),
++     TOBN(0xf23ab6b7, 0x25693459), TOBN(0x53bc3770, 0x14922b11),
++     TOBN(0x4645c8ab, 0x5afc60db), TOBN(0xaa022355, 0x20b9f2a3),
++     TOBN(0x52a2954c, 0xce0fc507), TOBN(0x8c2731bb, 0x7ce1c2e7),
++     TOBN(0xf39608ab, 0x18a0339d), TOBN(0xac7a658d, 0x3735436c),
++     TOBN(0xb22c2b07, 0xcd992b4f), TOBN(0x4e83daec, 0xf40dcfd4),
++     TOBN(0x8a34c7be, 0x2f39ea3e), TOBN(0xef0c005f, 0xb0a56d2e),
++     TOBN(0x62731f6a, 0x6edd8038), TOBN(0x5721d740, 0x4e3cb075),
++     TOBN(0x1ea41511, 0xfbeeee1b), TOBN(0xd1ef5e73, 0xef1d0c05),
++     TOBN(0x42feefd1, 0x73c07d35), TOBN(0xe530a00a, 0x8a329493),
++     TOBN(0x5d55b7fe, 0xf15ebfb0), TOBN(0x549de03c, 0xd322491a),
++     TOBN(0xf7b5f602, 0x745b3237), TOBN(0x3632a3a2, 0x1ab6e2b6),
++     TOBN(0x0d3bba89, 0x0ef59f78), TOBN(0x0dfc6443, 0xc9e52b9a),
++     TOBN(0x1dc79699, 0x72631447), TOBN(0xef033917, 0xb3be20b1),
++     TOBN(0x0c92735d, 0xb1383948), TOBN(0xc1fc29a2, 0xc0dd7d7d),
++     TOBN(0x6485b697, 0x403ed068), TOBN(0x13bfaab3, 0xaac93bdc),
++     TOBN(0x410dc6a9, 0x0deeaf52), TOBN(0xb003fb02, 0x4c641c15),
++     TOBN(0x1384978c, 0x5bc504c4), TOBN(0x37640487, 0x864a6a77),
++     TOBN(0x05991bc6, 0x222a77da), TOBN(0x62260a57, 0x5e47eb11),
++     TOBN(0xc7af6613, 0xf21b432c), TOBN(0x22f3acc9, 0xab4953e9),
++     TOBN(0x52934922, 0x8e41d155), TOBN(0x4d024568, 0x3ac059ef),
++     TOBN(0xb0201755, 0x4d884411), TOBN(0xce8055cf, 0xa59a178f),
++     TOBN(0xcd77d1af, 0xf6204549), TOBN(0xa0a00a3e, 0xc7066759),
++     TOBN(0x471071ef, 0x0272c229), TOBN(0x009bcf6b, 0xd3c4b6b0),
++     TOBN(0x2a2638a8, 0x22305177), TOBN(0xd51d59df, 0x41645bbf),
++     TOBN(0xa81142fd, 0xc0a7a3c0), TOBN(0xa17eca6d, 0x4c7063ee),
++     TOBN(0x0bb887ed, 0x60d9dcec), TOBN(0xd6d28e51, 0x20ad2455),
++     TOBN(0xebed6308, 0xa67102ba), TOBN(0x042c3114, 0x8bffa408),
++     TOBN(0xfd099ac5, 0x8aa68e30), TOBN(0x7a6a3d7c, 0x1483513e),
++     TOBN(0xffcc6b75, 0xba2d8f0c), TOBN(0x54dacf96, 0x1e78b954),
++     TOBN(0xf645696f, 0xa4a9af89), TOBN(0x3a411940, 0x06ac98ec),
++     TOBN(0x41b8b3f6, 0x22a67a20), TOBN(0x2d0b1e0f, 0x99dec626),
++     TOBN(0x27c89192, 0x40be34e8), TOBN(0xc7162b37, 0x91907f35),
++     TOBN(0x90188ec1, 0xa956702b), TOBN(0xca132f7d, 0xdf93769c),
++     TOBN(0x3ece44f9, 0x0e2025b4), TOBN(0x67aaec69, 0x0c62f14c),
++     TOBN(0xad741418, 0x22e3cc11), TOBN(0xcf9b75c3, 0x7ff9a50e),
++     TOBN(0x02fa2b16, 0x4d348272), TOBN(0xbd99d61a, 0x9959d56d),
++     TOBN(0xbc4f19db, 0x18762916), TOBN(0xcc7cce50, 0x49c1ac80),
++     TOBN(0x4d59ebaa, 0xd846bd83), TOBN(0x8775a9dc, 0xa9202849),
++     TOBN(0x07ec4ae1, 0x6e1f4ca9), TOBN(0x27eb5875, 0xba893f11),
++     TOBN(0x00284d51, 0x662cc565), TOBN(0x82353a6b, 0x0db4138d),
++     TOBN(0xd9c7aaaa, 0xaa32a594), TOBN(0xf5528b5e, 0xa5669c47),
++     TOBN(0xf3220231, 0x2f23c5ff), TOBN(0xe3e8147a, 0x6affa3a1),
++     TOBN(0xfb423d5c, 0x202ddda0), TOBN(0x3d6414ac, 0x6b871bd4),
++     TOBN(0x586f82e1, 0xa51a168a), TOBN(0xb712c671, 0x48ae5448),
++     TOBN(0x9a2e4bd1, 0x76233eb8), TOBN(0x0188223a, 0x78811ca9),
++     TOBN(0x553c5e21, 0xf7c18de1), TOBN(0x7682e451, 0xb27bb286),
++     TOBN(0x3ed036b3, 0x0e51e929), TOBN(0xf487211b, 0xec9cb34f),
++     TOBN(0x0d094277, 0x0c24efc8), TOBN(0x0349fd04, 0xbef737a4),
++     TOBN(0x6d1c9dd2, 0x514cdd28), TOBN(0x29c135ff, 0x30da9521),
++     TOBN(0xea6e4508, 0xf78b0b6f), TOBN(0x176f5dd2, 0x678c143c),
++     TOBN(0x08148418, 0x4be21e65), TOBN(0x27f7525c, 0xe7df38c4),
++     TOBN(0x1fb70e09, 0x748ab1a4), TOBN(0x9cba50a0, 0x5efe4433),
++     TOBN(0x7846c7a6, 0x15f75af2), TOBN(0x2a7c2c57, 0x5ee73ea8),
++     TOBN(0x42e566a4, 0x3f0a449a), TOBN(0x45474c3b, 0xad90fc3d),
++     TOBN(0x7447be3d, 0x8b61d057), TOBN(0x3e9d1cf1, 0x3a4ec092),
++     TOBN(0x1603e453, 0xf380a6e6), TOBN(0x0b86e431, 0x9b1437c2),
++     TOBN(0x7a4173f2, 0xef29610a), TOBN(0x8fa729a7, 0xf03d57f7),
++     TOBN(0x3e186f6e, 0x6c9c217e), TOBN(0xbe1d3079, 0x91919524),
++     TOBN(0x92a62a70, 0x153d4fb1), TOBN(0x32ed3e34, 0xd68c2f71),
++     TOBN(0xd785027f, 0x9eb1a8b7), TOBN(0xbc37eb77, 0xc5b22fe8),
++     TOBN(0x466b34f0, 0xb9d6a191), TOBN(0x008a89af, 0x9a05f816),
++     TOBN(0x19b028fb, 0x7d42c10a), TOBN(0x7fe8c92f, 0x49b3f6b8),
++     TOBN(0x58907cc0, 0xa5a0ade3), TOBN(0xb3154f51, 0x559d1a7c),
++     TOBN(0x5066efb6, 0xd9790ed6), TOBN(0xa77a0cbc, 0xa6aa793b),
++     TOBN(0x1a915f3c, 0x223e042e), TOBN(0x1c5def04, 0x69c5874b),
++     TOBN(0x0e830078, 0x73b6c1da), TOBN(0x55cf85d2, 0xfcd8557a),
++     TOBN(0x0f7c7c76, 0x0460f3b1), TOBN(0x87052acb, 0x46e58063),
++     TOBN(0x09212b80, 0x907eae66), TOBN(0x3cb068e0, 0x4d721c89),
++     TOBN(0xa87941ae, 0xdd45ac1c), TOBN(0xde8d5c0d, 0x0daa0dbb),
++     TOBN(0xda421fdc, 0xe3502e6e), TOBN(0xc8944201, 0x4d89a084),
++     TOBN(0x7307ba5e, 0xf0c24bfb), TOBN(0xda212beb, 0x20bde0ef),
++     TOBN(0xea2da24b, 0xf82ce682), TOBN(0x058d3816, 0x07f71fe4),
++     TOBN(0x35a02462, 0x5ffad8de), TOBN(0xcd7b05dc, 0xaadcefab),
++     TOBN(0xd442f8ed, 0x1d9f54ec), TOBN(0x8be3d618, 0xb2d3b5ca),
++     TOBN(0xe2220ed0, 0xe06b2ce2), TOBN(0x82699a5f, 0x1b0da4c0),
++     TOBN(0x3ff106f5, 0x71c0c3a7), TOBN(0x8f580f5a, 0x0d34180c),
++     TOBN(0x4ebb120e, 0x22d7d375), TOBN(0x5e5782cc, 0xe9513675),
++     TOBN(0x2275580c, 0x99c82a70), TOBN(0xe8359fbf, 0x15ea8c4c),
++     TOBN(0x53b48db8, 0x7b415e70), TOBN(0xaacf2240, 0x100c6014),
++     TOBN(0x9faaccf5, 0xe4652f1d), TOBN(0xbd6fdd2a, 0xd56157b2),
++     TOBN(0xa4f4fb1f, 0x6261ec50), TOBN(0x244e55ad, 0x476bcd52),
++     TOBN(0x881c9305, 0x047d320b), TOBN(0x1ca983d5, 0x6181263f),
++     TOBN(0x354e9a44, 0x278fb8ee), TOBN(0xad2dbc0f, 0x396e4964),
++     TOBN(0x723f3aa2, 0x9268b3de), TOBN(0x0d1ca29a, 0xe6e0609a),
++     TOBN(0x794866aa, 0x6cf44252), TOBN(0x0b59f3e3, 0x01af87ed),
++     TOBN(0xe234e5ff, 0x7f4a6c51), TOBN(0xa8768fd2, 0x61dc2f7e),
++     TOBN(0xdafc7332, 0x0a94d81f), TOBN(0xd7f84282, 0x06938ce1),
++     TOBN(0xae0b3c0e, 0x0546063e), TOBN(0x7fbadcb2, 0x5d61abc6),
++     TOBN(0xd5d7a2c9, 0x369ac400), TOBN(0xa5978d09, 0xae67d10c),
++     TOBN(0x290f211e, 0x4f85eaac), TOBN(0xe61e2ad1, 0xfacac681),
++     TOBN(0xae125225, 0x388384cd), TOBN(0xa7fb68e9, 0xccfde30f),
++     TOBN(0x7a59b936, 0x3daed4c2), TOBN(0x80a9aa40, 0x2606f789),
++     TOBN(0xb40c1ea5, 0xf6a6d90a), TOBN(0x948364d3, 0x514d5885),
++     TOBN(0x062ebc60, 0x70985182), TOBN(0xa6db5b0e, 0x33310895),
++     TOBN(0x64a12175, 0xe329c2f5), TOBN(0xc5f25bd2, 0x90ea237e),
++     TOBN(0x7915c524, 0x2d0a4c23), TOBN(0xeb5d26e4, 0x6bb3cc52),
++     TOBN(0x369a9116, 0xc09e2c92), TOBN(0x0c527f92, 0xcf182cf8),
++     TOBN(0x9e591938, 0x2aede0ac), TOBN(0xb2922208, 0x6cc34939),
++     TOBN(0x3c9d8962, 0x99a34361), TOBN(0x3c81836d, 0xc1905fe6),
++     TOBN(0x4bfeb57f, 0xa001ec5a), TOBN(0xe993f5bb, 0xa0dc5dba),
++     TOBN(0x47884109, 0x724a1380), TOBN(0x8a0369ab, 0x32fe9a04),
++     TOBN(0xea068d60, 0x8c927db8), TOBN(0xbf5f37cf, 0x94655741),
++     TOBN(0x47d402a2, 0x04b6c7ea), TOBN(0x4551c295, 0x6af259cb),
++     TOBN(0x698b71e7, 0xed77ee8b), TOBN(0xbddf7bd0, 0xf309d5c7),
++     TOBN(0x6201c22c, 0x34e780ca), TOBN(0xab04f7d8, 0x4c295ef4),
++     TOBN(0x1c947294, 0x4313a8ce), TOBN(0xe532e4ac, 0x92ca4cfe),
++     TOBN(0x89738f80, 0xd0a7a97a), TOBN(0xec088c88, 0xa580fd5b),
++     TOBN(0x612b1ecc, 0x42ce9e51), TOBN(0x8f9840fd, 0xb25fdd2a),
++     TOBN(0x3cda78c0, 0x01e7f839), TOBN(0x546b3d3a, 0xece05480),
++     TOBN(0x271719a9, 0x80d30916), TOBN(0x45497107, 0x584c20c4),
++     TOBN(0xaf8f9478, 0x5bc78608), TOBN(0x28c7d484, 0x277e2a4c),
++     TOBN(0xfce01767, 0x88a2ffe4), TOBN(0xdc506a35, 0x28e169a5),
++     TOBN(0x0ea10861, 0x7af9c93a), TOBN(0x1ed24361, 0x03fa0e08),
++     TOBN(0x96eaaa92, 0xa3d694e7), TOBN(0xc0f43b4d, 0xef50bc74),
++     TOBN(0xce6aa58c, 0x64114db4), TOBN(0x8218e8ea, 0x7c000fd4),
++     TOBN(0xac815dfb, 0x185f8844), TOBN(0xcd7e90cb, 0x1557abfb),
++     TOBN(0x23d16655, 0xafbfecdf), TOBN(0x80f3271f, 0x085cac4a),
++     TOBN(0x7fc39aa7, 0xd0e62f47), TOBN(0x88d519d1, 0x460a48e5),
++     TOBN(0x59559ac4, 0xd28f101e), TOBN(0x7981d9e9, 0xca9ae816),
++     TOBN(0x5c38652c, 0x9ac38203), TOBN(0x86eaf87f, 0x57657fe5),
++     TOBN(0x568fc472, 0xe21f5416), TOBN(0x2afff39c, 0xe7e597b5),
++     TOBN(0x3adbbb07, 0x256d4eab), TOBN(0x22598692, 0x8285ab89),
++     TOBN(0x35f8112a, 0x041caefe), TOBN(0x95df02e3, 0xa5064c8b),
++     TOBN(0x4d63356e, 0xc7004bf3), TOBN(0x230a08f4, 0xdb83c7de),
++     TOBN(0xca27b270, 0x8709a7b7), TOBN(0x0d1c4cc4, 0xcb9abd2d),
++     TOBN(0x8a0bc66e, 0x7550fee8), TOBN(0x369cd4c7, 0x9cf7247e),
++     TOBN(0x75562e84, 0x92b5b7e7), TOBN(0x8fed0da0, 0x5802af7b),
++     TOBN(0x6a7091c2, 0xe48fb889), TOBN(0x26882c13, 0x7b8a9d06),
++     TOBN(0xa2498663, 0x1b82a0e2), TOBN(0x844ed736, 0x3518152d),
++     TOBN(0x282f476f, 0xd86e27c7), TOBN(0xa04edaca, 0x04afefdc),
++     TOBN(0x8b256ebc, 0x6119e34d), TOBN(0x56a413e9, 0x0787d78b),}
++    ,
++    {TOBN(0x82ee061d, 0x5a74be50), TOBN(0xe41781c4, 0xdea16ff5),
++     TOBN(0xe0b0c81e, 0x99bfc8a2), TOBN(0x624f4d69, 0x0b547e2d),
++     TOBN(0x3a83545d, 0xbdcc9ae4), TOBN(0x2573dbb6, 0x409b1e8e),
++     TOBN(0x482960c4, 0xa6c93539), TOBN(0xf01059ad, 0x5ae18798),
++     TOBN(0x715c9f97, 0x3112795f), TOBN(0xe8244437, 0x984e6ee1),
++     TOBN(0x55cb4858, 0xecb66bcd), TOBN(0x7c136735, 0xabaffbee),
++     TOBN(0x54661595, 0x5dbec38e), TOBN(0x51c0782c, 0x388ad153),
++     TOBN(0x9ba4c53a, 0xc6e0952f), TOBN(0x27e6782a, 0x1b21dfa8),
++     TOBN(0x682f903d, 0x4ed2dbc2), TOBN(0x0eba59c8, 0x7c3b2d83),
++     TOBN(0x8e9dc84d, 0x9c7e9335), TOBN(0x5f9b21b0, 0x0eb226d7),
++     TOBN(0xe33bd394, 0xaf267bae), TOBN(0xaa86cc25, 0xbe2e15ae),
++     TOBN(0x4f0bf67d, 0x6a8ec500), TOBN(0x5846aa44, 0xf9630658),
++     TOBN(0xfeb09740, 0xe2c2bf15), TOBN(0x627a2205, 0xa9e99704),
++     TOBN(0xec8d73d0, 0xc2fbc565), TOBN(0x223eed8f, 0xc20c8de8),
++     TOBN(0x1ee32583, 0xa8363b49), TOBN(0x1a0b6cb9, 0xc9c2b0a6),
++     TOBN(0x49f7c3d2, 0x90dbc85c), TOBN(0xa8dfbb97, 0x1ef4c1ac),
++     TOBN(0xafb34d4c, 0x65c7c2ab), TOBN(0x1d4610e7, 0xe2c5ea84),
++     TOBN(0x893f6d1b, 0x973c4ab5), TOBN(0xa3cdd7e9, 0x945ba5c4),
++     TOBN(0x60514983, 0x064417ee), TOBN(0x1459b23c, 0xad6bdf2b),
++     TOBN(0x23b2c341, 0x5cf726c3), TOBN(0x3a829635, 0x32d6354a),
++     TOBN(0x294f901f, 0xab192c18), TOBN(0xec5fcbfe, 0x7030164f),
++     TOBN(0xe2e2fcb7, 0xe2246ba6), TOBN(0x1e7c88b3, 0x221a1a0c),
++     TOBN(0x72c7dd93, 0xc92d88c5), TOBN(0x41c2148e, 0x1106fb59),
++     TOBN(0x547dd4f5, 0xa0f60f14), TOBN(0xed9b52b2, 0x63960f31),
++     TOBN(0x6c8349eb, 0xb0a5b358), TOBN(0xb154c5c2, 0x9e7e2ed6),
++     TOBN(0xcad5eccf, 0xeda462db), TOBN(0xf2d6dbe4, 0x2de66b69),
++     TOBN(0x426aedf3, 0x8665e5b2), TOBN(0x488a8513, 0x7b7f5723),
++     TOBN(0x15cc43b3, 0x8bcbb386), TOBN(0x27ad0af3, 0xd791d879),
++     TOBN(0xc16c236e, 0x846e364f), TOBN(0x7f33527c, 0xdea50ca0),
++     TOBN(0xc4810775, 0x0926b86d), TOBN(0x6c2a3609, 0x0598e70c),
++     TOBN(0xa6755e52, 0xf024e924), TOBN(0xe0fa07a4, 0x9db4afca),
++     TOBN(0x15c3ce7d, 0x66831790), TOBN(0x5b4ef350, 0xa6cbb0d6),
++     TOBN(0x2c4aafc4, 0xb6205969), TOBN(0x42563f02, 0xf6c7854f),
++     TOBN(0x016aced5, 0x1d983b48), TOBN(0xfeb356d8, 0x99949755),
++     TOBN(0x8c2a2c81, 0xd1a39bd7), TOBN(0x8f44340f, 0xe6934ae9),
++     TOBN(0x148cf91c, 0x447904da), TOBN(0x7340185f, 0x0f51a926),
++     TOBN(0x2f8f00fb, 0x7409ab46), TOBN(0x057e78e6, 0x80e289b2),
++     TOBN(0x03e5022c, 0xa888e5d1), TOBN(0x3c87111a, 0x9dede4e2),
++     TOBN(0x5b9b0e1c, 0x7809460b), TOBN(0xe751c852, 0x71c9abc7),
++     TOBN(0x8b944e28, 0xc7cc1dc9), TOBN(0x4f201ffa, 0x1d3cfa08),
++     TOBN(0x02fc905c, 0x3e6721ce), TOBN(0xd52d70da, 0xd0b3674c),
++     TOBN(0x5dc2e5ca, 0x18810da4), TOBN(0xa984b273, 0x5c69dd99),
++     TOBN(0x63b92527, 0x84de5ca4), TOBN(0x2f1c9872, 0xc852dec4),
++     TOBN(0x18b03593, 0xc2e3de09), TOBN(0x19d70b01, 0x9813dc2f),
++     TOBN(0x42806b2d, 0xa6dc1d29), TOBN(0xd3030009, 0xf871e144),
++     TOBN(0xa1feb333, 0xaaf49276), TOBN(0xb5583b9e, 0xc70bc04b),
++     TOBN(0x1db0be78, 0x95695f20), TOBN(0xfc841811, 0x89d012b5),
++     TOBN(0x6409f272, 0x05f61643), TOBN(0x40d34174, 0xd5883128),
++     TOBN(0xd79196f5, 0x67419833), TOBN(0x6059e252, 0x863b7b08),
++     TOBN(0x84da1817, 0x1c56700c), TOBN(0x5758ee56, 0xb28d3ec4),
++     TOBN(0x7da2771d, 0x013b0ea6), TOBN(0xfddf524b, 0x54c5e9b9),
++     TOBN(0x7df4faf8, 0x24305d80), TOBN(0x58f5c1bf, 0x3a97763f),
++     TOBN(0xa5af37f1, 0x7c696042), TOBN(0xd4cba22c, 0x4a2538de),
++     TOBN(0x211cb995, 0x9ea42600), TOBN(0xcd105f41, 0x7b069889),
++     TOBN(0xb1e1cf19, 0xddb81e74), TOBN(0x472f2d89, 0x5157b8ca),
++     TOBN(0x086fb008, 0xee9db885), TOBN(0x365cd570, 0x0f26d131),
++     TOBN(0x284b02bb, 0xa2be7053), TOBN(0xdcbbf7c6, 0x7ab9a6d6),
++     TOBN(0x4425559c, 0x20f7a530), TOBN(0x961f2dfa, 0x188767c8),
++     TOBN(0xe2fd9435, 0x70dc80c4), TOBN(0x104d6b63, 0xf0784120),
++     TOBN(0x7f592bc1, 0x53567122), TOBN(0xf6bc1246, 0xf688ad77),
++     TOBN(0x05214c05, 0x0f15dde9), TOBN(0xa47a76a8, 0x0d5f2b82),
++     TOBN(0xbb254d30, 0x62e82b62), TOBN(0x11a05fe0, 0x3ec955ee),
++     TOBN(0x7eaff46e, 0x9d529b36), TOBN(0x55ab1301, 0x8f9e3df6),
++     TOBN(0xc463e371, 0x99317698), TOBN(0xfd251438, 0xccda47ad),
++     TOBN(0xca9c3547, 0x23d695ea), TOBN(0x48ce626e, 0x16e589b5),
++     TOBN(0x6b5b64c7, 0xb187d086), TOBN(0xd02e1794, 0xb2207948),
++     TOBN(0x8b58e98f, 0x7198111d), TOBN(0x90ca6305, 0xdcf9c3cc),
++     TOBN(0x5691fe72, 0xf34089b0), TOBN(0x60941af1, 0xfc7c80ff),
++     TOBN(0xa09bc0a2, 0x22eb51e5), TOBN(0xc0bb7244, 0xaa9cf09a),
++     TOBN(0x36a8077f, 0x80159f06), TOBN(0x8b5c989e, 0xdddc560e),
++     TOBN(0x19d2f316, 0x512e1f43), TOBN(0x02eac554, 0xad08ff62),
++     TOBN(0x012ab84c, 0x07d20b4e), TOBN(0x37d1e115, 0xd6d4e4e1),
++     TOBN(0xb6443e1a, 0xab7b19a8), TOBN(0xf08d067e, 0xdef8cd45),
++     TOBN(0x63adf3e9, 0x685e03da), TOBN(0xcf15a10e, 0x4792b916),
++     TOBN(0xf44bcce5, 0xb738a425), TOBN(0xebe131d5, 0x9636b2fd),
++     TOBN(0x94068841, 0x7850d605), TOBN(0x09684eaa, 0xb40d749d),
++     TOBN(0x8c3c669c, 0x72ba075b), TOBN(0x89f78b55, 0xba469015),
++     TOBN(0x5706aade, 0x3e9f8ba8), TOBN(0x6d8bd565, 0xb32d7ed7),
++     TOBN(0x25f4e63b, 0x805f08d6), TOBN(0x7f48200d, 0xc3bcc1b5),
++     TOBN(0x4e801968, 0xb025d847), TOBN(0x74afac04, 0x87cbe0a8),
++     TOBN(0x43ed2c2b, 0x7e63d690), TOBN(0xefb6bbf0, 0x0223cdb8),
++     TOBN(0x4fec3cae, 0x2884d3fe), TOBN(0x065ecce6, 0xd75e25a4),
++     TOBN(0x6c2294ce, 0x69f79071), TOBN(0x0d9a8e5f, 0x044b8666),
++     TOBN(0x5009f238, 0x17b69d8f), TOBN(0x3c29f8fe, 0xc5dfdaf7),
++     TOBN(0x9067528f, 0xebae68c4), TOBN(0x5b385632, 0x30c5ba21),
++     TOBN(0x540df119, 0x1fdd1aec), TOBN(0xcf37825b, 0xcfba4c78),
++     TOBN(0x77eff980, 0xbeb11454), TOBN(0x40a1a991, 0x60c1b066),
++     TOBN(0xe8018980, 0xf889a1c7), TOBN(0xb9c52ae9, 0x76c24be0),
++     TOBN(0x05fbbcce, 0x45650ef4), TOBN(0xae000f10, 0x8aa29ac7),
++     TOBN(0x884b7172, 0x4f04c470), TOBN(0x7cd4fde2, 0x19bb5c25),
++     TOBN(0x6477b22a, 0xe8840869), TOBN(0xa8868859, 0x5fbd0686),
++     TOBN(0xf23cc02e, 0x1116dfba), TOBN(0x76cd563f, 0xd87d7776),
++     TOBN(0xe2a37598, 0xa9d82abf), TOBN(0x5f188ccb, 0xe6c170f5),
++     TOBN(0x81682200, 0x5066b087), TOBN(0xda22c212, 0xc7155ada),
++     TOBN(0x151e5d3a, 0xfbddb479), TOBN(0x4b606b84, 0x6d715b99),
++     TOBN(0x4a73b54b, 0xf997cb2e), TOBN(0x9a1bfe43, 0x3ecd8b66),
++     TOBN(0x1c312809, 0x2a67d48a), TOBN(0xcd6a671e, 0x031fa9e2),
++     TOBN(0xbec3312a, 0x0e43a34a), TOBN(0x1d935639, 0x55ef47d3),
++     TOBN(0x5ea02489, 0x8fea73ea), TOBN(0x8247b364, 0xa035afb2),
++     TOBN(0xb58300a6, 0x5265b54c), TOBN(0x3286662f, 0x722c7148),
++     TOBN(0xb77fd76b, 0xb4ec4c20), TOBN(0xf0a12fa7, 0x0f3fe3fd),
++     TOBN(0xf845bbf5, 0x41d8c7e8), TOBN(0xe4d969ca, 0x5ec10aa8),
++     TOBN(0x4c0053b7, 0x43e232a3), TOBN(0xdc7a3fac, 0x37f8a45a),
++     TOBN(0x3c4261c5, 0x20d81c8f), TOBN(0xfd4b3453, 0xb00eab00),
++     TOBN(0x76d48f86, 0xd36e3062), TOBN(0x626c5277, 0xa143ff02),
++     TOBN(0x538174de, 0xaf76f42e), TOBN(0x2267aa86, 0x6407ceac),
++     TOBN(0xfad76351, 0x72e572d5), TOBN(0xab861af7, 0xba7330eb),
++     TOBN(0xa0a1c8c7, 0x418d8657), TOBN(0x988821cb, 0x20289a52),
++     TOBN(0x79732522, 0xcccc18ad), TOBN(0xaadf3f8d, 0xf1a6e027),
++     TOBN(0xf7382c93, 0x17c2354d), TOBN(0x5ce1680c, 0xd818b689),
++     TOBN(0x359ebbfc, 0xd9ecbee9), TOBN(0x4330689c, 0x1cae62ac),
++     TOBN(0xb55ce5b4, 0xc51ac38a), TOBN(0x7921dfea, 0xfe238ee8),
++     TOBN(0x3972bef8, 0x271d1ca5), TOBN(0x3e423bc7, 0xe8aabd18),
++     TOBN(0x57b09f3f, 0x44a3e5e3), TOBN(0x5da886ae, 0x7b444d66),
++     TOBN(0x68206634, 0xa9964375), TOBN(0x356a2fa3, 0x699cd0ff),
++     TOBN(0xaf0faa24, 0xdba515e9), TOBN(0x536e1f5c, 0xb321d79a),
++     TOBN(0xd3b9913a, 0x5c04e4ea), TOBN(0xd549dcfe, 0xd6f11513),
++     TOBN(0xee227bf5, 0x79fd1d94), TOBN(0x9f35afee, 0xb43f2c67),
++     TOBN(0xd2638d24, 0xf1314f53), TOBN(0x62baf948, 0xcabcd822),
++     TOBN(0x5542de29, 0x4ef48db0), TOBN(0xb3eb6a04, 0xfc5f6bb2),
++     TOBN(0x23c110ae, 0x1208e16a), TOBN(0x1a4d15b5, 0xf8363e24),
++     TOBN(0x30716844, 0x164be00b), TOBN(0xa8e24824, 0xf6f4690d),
++     TOBN(0x548773a2, 0x90b170cf), TOBN(0xa1bef331, 0x42f191f4),
++     TOBN(0x70f418d0, 0x9247aa97), TOBN(0xea06028e, 0x48be9147),
++     TOBN(0xe13122f3, 0xdbfb894e), TOBN(0xbe9b79f6, 0xce274b18),
++     TOBN(0x85a49de5, 0xca58aadf), TOBN(0x24957758, 0x11487351),
++     TOBN(0x111def61, 0xbb939099), TOBN(0x1d6a974a, 0x26d13694),
++     TOBN(0x4474b4ce, 0xd3fc253b), TOBN(0x3a1485e6, 0x4c5db15e),
++     TOBN(0xe79667b4, 0x147c15b4), TOBN(0xe34f553b, 0x7bc61301),
++     TOBN(0x032b80f8, 0x17094381), TOBN(0x55d8bafd, 0x723eaa21),
++     TOBN(0x5a987995, 0xf1c0e74e), TOBN(0x5a9b292e, 0xebba289c),
++     TOBN(0x413cd4b2, 0xeb4c8251), TOBN(0x98b5d243, 0xd162db0a),
++     TOBN(0xbb47bf66, 0x68342520), TOBN(0x08d68949, 0xbaa862d1),
++     TOBN(0x11f349c7, 0xe906abcd), TOBN(0x454ce985, 0xed7bf00e),
++     TOBN(0xacab5c9e, 0xb55b803b), TOBN(0xb03468ea, 0x31e3c16d),
++     TOBN(0x5c24213d, 0xd273bf12), TOBN(0x211538eb, 0x71587887),
++     TOBN(0x198e4a2f, 0x731dea2d), TOBN(0xd5856cf2, 0x74ed7b2a),
++     TOBN(0x86a632eb, 0x13a664fe), TOBN(0x932cd909, 0xbda41291),
++     TOBN(0x850e95d4, 0xc0c4ddc0), TOBN(0xc0f422f8, 0x347fc2c9),
++     TOBN(0xe68cbec4, 0x86076bcb), TOBN(0xf9e7c0c0, 0xcd6cd286),
++     TOBN(0x65994ddb, 0x0f5f27ca), TOBN(0xe85461fb, 0xa80d59ff),
++     TOBN(0xff05481a, 0x66601023), TOBN(0xc665427a, 0xfc9ebbfb),
++     TOBN(0xb0571a69, 0x7587fd52), TOBN(0x935289f8, 0x8d49efce),
++     TOBN(0x61becc60, 0xea420688), TOBN(0xb22639d9, 0x13a786af),
++     TOBN(0x1a8e6220, 0x361ecf90), TOBN(0x001f23e0, 0x25506463),
++     TOBN(0xe4ae9b5d, 0x0a5c2b79), TOBN(0xebc9cdad, 0xd8149db5),
++     TOBN(0xb33164a1, 0x934aa728), TOBN(0x750eb00e, 0xae9b60f3),
++     TOBN(0x5a91615b, 0x9b9cfbfd), TOBN(0x97015cbf, 0xef45f7f6),
++     TOBN(0xb462c4a5, 0xbf5151df), TOBN(0x21adcc41, 0xb07118f2),
++     TOBN(0xd60c545b, 0x043fa42c), TOBN(0xfc21aa54, 0xe96be1ab),
++     TOBN(0xe84bc32f, 0x4e51ea80), TOBN(0x3dae45f0, 0x259b5d8d),
++     TOBN(0xbb73c7eb, 0xc38f1b5e), TOBN(0xe405a74a, 0xe8ae617d),
++     TOBN(0xbb1ae9c6, 0x9f1c56bd), TOBN(0x8c176b98, 0x49f196a4),
++     TOBN(0xc448f311, 0x6875092b), TOBN(0xb5afe3de, 0x9f976033),
++     TOBN(0xa8dafd49, 0x145813e5), TOBN(0x687fc4d9, 0xe2b34226),
++     TOBN(0xf2dfc92d, 0x4c7ff57f), TOBN(0x004e3fc1, 0x401f1b46),
++     TOBN(0x5afddab6, 0x1430c9ab), TOBN(0x0bdd41d3, 0x2238e997),
++     TOBN(0xf0947430, 0x418042ae), TOBN(0x71f9adda, 0xcdddc4cb),
++     TOBN(0x7090c016, 0xc52dd907), TOBN(0xd9bdf44d, 0x29e2047f),
++     TOBN(0xe6f1fe80, 0x1b1011a6), TOBN(0xb63accbc, 0xd9acdc78),
++     TOBN(0xcfc7e235, 0x1272a95b), TOBN(0x0c667717, 0xa6276ac8),
++     TOBN(0x3c0d3709, 0xe2d7eef7), TOBN(0x5add2b06, 0x9a685b3e),
++     TOBN(0x363ad32d, 0x14ea5d65), TOBN(0xf8e01f06, 0x8d7dd506),
++     TOBN(0xc9ea2213, 0x75b4aac6), TOBN(0xed2a2bf9, 0x0d353466),
++     TOBN(0x439d79b5, 0xe9d3a7c3), TOBN(0x8e0ee5a6, 0x81b7f34b),
++     TOBN(0xcf3dacf5, 0x1dc4ba75), TOBN(0x1d3d1773, 0xeb3310c7),
++     TOBN(0xa8e67112, 0x7747ae83), TOBN(0x31f43160, 0x197d6b40),
++     TOBN(0x0521ccee, 0xcd961400), TOBN(0x67246f11, 0xf6535768),
++     TOBN(0x702fcc5a, 0xef0c3133), TOBN(0x247cc45d, 0x7e16693b),
++     TOBN(0xfd484e49, 0xc729b749), TOBN(0x522cef7d, 0xb218320f),
++     TOBN(0xe56ef405, 0x59ab93b3), TOBN(0x225fba11, 0x9f181071),
++     TOBN(0x33bd6595, 0x15330ed0), TOBN(0xc4be69d5, 0x1ddb32f7),
++     TOBN(0x264c7668, 0x0448087c), TOBN(0xac30903f, 0x71432dae),
++     TOBN(0x3851b266, 0x00f9bf47), TOBN(0x400ed311, 0x6cdd6d03),
++     TOBN(0x045e79fe, 0xf8fd2424), TOBN(0xfdfd974a, 0xfa6da98b),
++     TOBN(0x45c9f641, 0x0c1e673a), TOBN(0x76f2e733, 0x5b2c5168),
++     TOBN(0x1adaebb5, 0x2a601753), TOBN(0xb286514c, 0xc57c2d49),
++     TOBN(0xd8769670, 0x1e0bfd24), TOBN(0x950c547e, 0x04478922),
++     TOBN(0xd1d41969, 0xe5d32bfe), TOBN(0x30bc1472, 0x750d6c3e),
++     TOBN(0x8f3679fe, 0xe0e27f3a), TOBN(0x8f64a7dc, 0xa4a6ee0c),
++     TOBN(0x2fe59937, 0x633dfb1f), TOBN(0xea82c395, 0x977f2547),
++     TOBN(0xcbdfdf1a, 0x661ea646), TOBN(0xc7ccc591, 0xb9085451),
++     TOBN(0x82177962, 0x81761e13), TOBN(0xda57596f, 0x9196885c),
++     TOBN(0xbc17e849, 0x28ffbd70), TOBN(0x1e6e0a41, 0x2671d36f),
++     TOBN(0x61ae872c, 0x4152fcf5), TOBN(0x441c87b0, 0x9e77e754),
++     TOBN(0xd0799dd5, 0xa34dff09), TOBN(0x766b4e44, 0x88a6b171),
++     TOBN(0xdc06a512, 0x11f1c792), TOBN(0xea02ae93, 0x4be35c3e),
++     TOBN(0xe5ca4d6d, 0xe90c469e), TOBN(0x4df4368e, 0x56e4ff5c),
++     TOBN(0x7817acab, 0x4baef62e), TOBN(0x9f5a2202, 0xa85b91e8),
++     TOBN(0x9666ebe6, 0x6ce57610), TOBN(0x32ad31f3, 0xf73bfe03),
++     TOBN(0x628330a4, 0x25bcf4d6), TOBN(0xea950593, 0x515056e6),
++     TOBN(0x59811c89, 0xe1332156), TOBN(0xc89cf1fe, 0x8c11b2d7),
++     TOBN(0x75b63913, 0x04e60cc0), TOBN(0xce811e8d, 0x4625d375),
++     TOBN(0x030e43fc, 0x2d26e562), TOBN(0xfbb30b4b, 0x608d36a0),
++     TOBN(0x634ff82c, 0x48528118), TOBN(0x7c6fe085, 0xcd285911),
++     TOBN(0x7f2830c0, 0x99358f28), TOBN(0x2e60a95e, 0x665e6c09),
++     TOBN(0x08407d3d, 0x9b785dbf), TOBN(0x530889ab, 0xa759bce7),
++     TOBN(0xf228e0e6, 0x52f61239), TOBN(0x2b6d1461, 0x6879be3c),
++     TOBN(0xe6902c04, 0x51a7bbf7), TOBN(0x30ad99f0, 0x76f24a64),
++     TOBN(0x66d9317a, 0x98bc6da0), TOBN(0xf4f877f3, 0xcb596ac0),
++     TOBN(0xb05ff62d, 0x4c44f119), TOBN(0x4555f536, 0xe9b77416),
++     TOBN(0xc7c0d059, 0x8caed63b), TOBN(0x0cd2b7ce, 0xc358b2a9),
++     TOBN(0x3f33287b, 0x46945fa3), TOBN(0xf8785b20, 0xd67c8791),
++     TOBN(0xc54a7a61, 0x9637bd08), TOBN(0x54d4598c, 0x18be79d7),
++     TOBN(0x889e5acb, 0xc46d7ce1), TOBN(0x9a515bb7, 0x8b085877),
++     TOBN(0xfac1a03d, 0x0b7a5050), TOBN(0x7d3e738a, 0xf2926035),
++     TOBN(0x861cc2ce, 0x2a6cb0eb), TOBN(0x6f2e2955, 0x8f7adc79),
++     TOBN(0x61c4d451, 0x33016376), TOBN(0xd9fd2c80, 0x5ad59090),
++     TOBN(0xe5a83738, 0xb2b836a1), TOBN(0x855b41a0, 0x7c0d6622),
++     TOBN(0x186fe317, 0x7cc19af1), TOBN(0x6465c1ff, 0xfdd99acb),
++     TOBN(0x46e5c23f, 0x6974b99e), TOBN(0x75a7cf8b, 0xa2717cbe),
++     TOBN(0x4d2ebc3f, 0x062be658), TOBN(0x094b4447, 0x5f209c98),
++     TOBN(0x4af285ed, 0xb940cb5a), TOBN(0x6706d792, 0x7cc82f10),
++     TOBN(0xc8c8776c, 0x030526fa), TOBN(0xfa8e6f76, 0xa0da9140),
++     TOBN(0x77ea9d34, 0x591ee4f0), TOBN(0x5f46e337, 0x40274166),
++     TOBN(0x1bdf98bb, 0xea671457), TOBN(0xd7c08b46, 0x862a1fe2),
++     TOBN(0x46cc303c, 0x1c08ad63), TOBN(0x99543440, 0x4c845e7b),
++     TOBN(0x1b8fbdb5, 0x48f36bf7), TOBN(0x5b82c392, 0x8c8273a7),
++     TOBN(0x08f712c4, 0x928435d5), TOBN(0x071cf0f1, 0x79330380),
++     TOBN(0xc74c2d24, 0xa8da054a), TOBN(0xcb0e7201, 0x43c46b5c),
++     TOBN(0x0ad7337a, 0xc0b7eff3), TOBN(0x8552225e, 0xc5e48b3c),
++     TOBN(0xe6f78b0c, 0x73f13a5f), TOBN(0x5e70062e, 0x82349cbe),
++     TOBN(0x6b8d5048, 0xe7073969), TOBN(0x392d2a29, 0xc33cb3d2),
++     TOBN(0xee4f727c, 0x4ecaa20f), TOBN(0xa068c99e, 0x2ccde707),
++     TOBN(0xfcd5651f, 0xb87a2913), TOBN(0xea3e3c15, 0x3cc252f0),
++     TOBN(0x777d92df, 0x3b6cd3e4), TOBN(0x7a414143, 0xc5a732e7),
++     TOBN(0xa895951a, 0xa71ff493), TOBN(0xfe980c92, 0xbbd37cf6),
++     TOBN(0x45bd5e64, 0xdecfeeff), TOBN(0x910dc2a9, 0xa44c43e9),
++     TOBN(0xcb403f26, 0xcca9f54d), TOBN(0x928bbdfb, 0x9303f6db),
++     TOBN(0x3c37951e, 0xa9eee67c), TOBN(0x3bd61a52, 0xf79961c3),
++     TOBN(0x09a238e6, 0x395c9a79), TOBN(0x6940ca2d, 0x61eb352d),
++     TOBN(0x7d1e5c5e, 0xc1875631), TOBN(0x1e19742c, 0x1e1b20d1),
++     TOBN(0x4633d908, 0x23fc2e6e), TOBN(0xa76e29a9, 0x08959149),
++     TOBN(0x61069d9c, 0x84ed7da5), TOBN(0x0baa11cf, 0x5dbcad51),
++     TOBN(0xd01eec64, 0x961849da), TOBN(0x93b75f1f, 0xaf3d8c28),
++     TOBN(0x57bc4f9f, 0x1ca2ee44), TOBN(0x5a26322d, 0x00e00558),
++     TOBN(0x1888d658, 0x61a023ef), TOBN(0x1d72aab4, 0xb9e5246e),
++     TOBN(0xa9a26348, 0xe5563ec0), TOBN(0xa0971963, 0xc3439a43),
++     TOBN(0x567dd54b, 0xadb9b5b7), TOBN(0x73fac1a1, 0xc45a524b),
++     TOBN(0x8fe97ef7, 0xfe38e608), TOBN(0x608748d2, 0x3f384f48),
++     TOBN(0xb0571794, 0xc486094f), TOBN(0x869254a3, 0x8bf3a8d6),
++     TOBN(0x148a8dd1, 0x310b0e25), TOBN(0x99ab9f3f, 0x9aa3f7d8),
++     TOBN(0x0927c68a, 0x6706c02e), TOBN(0x22b5e76c, 0x69790e6c),
++     TOBN(0x6c325260, 0x6c71376c), TOBN(0x53a57690, 0x09ef6657),
++     TOBN(0x8d63f852, 0xedffcf3a), TOBN(0xb4d2ed04, 0x3c0a6f55),
++     TOBN(0xdb3aa8de, 0x12519b9e), TOBN(0x5d38e9c4, 0x1e0a569a),
++     TOBN(0x871528bf, 0x303747e2), TOBN(0xa208e77c, 0xf5b5c18d),
++     TOBN(0x9d129c88, 0xca6bf923), TOBN(0xbcbf197f, 0xbf02839f),
++     TOBN(0x9b9bf030, 0x27323194), TOBN(0x3b055a8b, 0x339ca59d),
++     TOBN(0xb46b2312, 0x0f669520), TOBN(0x19789f1f, 0x497e5f24),
++     TOBN(0x9c499468, 0xaaf01801), TOBN(0x72ee1190, 0x8b69d59c),
++     TOBN(0x8bd39595, 0xacf4c079), TOBN(0x3ee11ece, 0x8e0cd048),
++     TOBN(0xebde86ec, 0x1ed66f18), TOBN(0x225d906b, 0xd61fce43),
++     TOBN(0x5cab07d6, 0xe8bed74d), TOBN(0x16e4617f, 0x27855ab7),
++     TOBN(0x6568aadd, 0xb2fbc3dd), TOBN(0xedb5484f, 0x8aeddf5b),
++     TOBN(0x878f20e8, 0x6dcf2fad), TOBN(0x3516497c, 0x615f5699),}
++    ,
++    {TOBN(0xef0a3fec, 0xfa181e69), TOBN(0x9ea02f81, 0x30d69a98),
++     TOBN(0xb2e9cf8e, 0x66eab95d), TOBN(0x520f2beb, 0x24720021),
++     TOBN(0x621c540a, 0x1df84361), TOBN(0x12037721, 0x71fa6d5d),
++     TOBN(0x6e3c7b51, 0x0ff5f6ff), TOBN(0x817a069b, 0xabb2bef3),
++     TOBN(0x83572fb6, 0xb294cda6), TOBN(0x6ce9bf75, 0xb9039f34),
++     TOBN(0x20e012f0, 0x095cbb21), TOBN(0xa0aecc1b, 0xd063f0da),
++     TOBN(0x57c21c3a, 0xf02909e5), TOBN(0xc7d59ecf, 0x48ce9cdc),
++     TOBN(0x2732b844, 0x8ae336f8), TOBN(0x056e3723, 0x3f4f85f4),
++     TOBN(0x8a10b531, 0x89e800ca), TOBN(0x50fe0c17, 0x145208fd),
++     TOBN(0x9e43c0d3, 0xb714ba37), TOBN(0x427d200e, 0x34189acc),
++     TOBN(0x05dee24f, 0xe616e2c0), TOBN(0x9c25f4c8, 0xee1854c1),
++     TOBN(0x4d3222a5, 0x8f342a73), TOBN(0x0807804f, 0xa027c952),
++     TOBN(0xc222653a, 0x4f0d56f3), TOBN(0x961e4047, 0xca28b805),
++     TOBN(0x2c03f8b0, 0x4a73434b), TOBN(0x4c966787, 0xab712a19),
++     TOBN(0xcc196c42, 0x864fee42), TOBN(0xc1be93da, 0x5b0ece5c),
++     TOBN(0xa87d9f22, 0xc131c159), TOBN(0x2bb6d593, 0xdce45655),
++     TOBN(0x22c49ec9, 0xb809b7ce), TOBN(0x8a41486b, 0xe2c72c2c),
++     TOBN(0x813b9420, 0xfea0bf36), TOBN(0xb3d36ee9, 0xa66dac69),
++     TOBN(0x6fddc08a, 0x328cc987), TOBN(0x0a3bcd2c, 0x3a326461),
++     TOBN(0x7103c49d, 0xd810dbba), TOBN(0xf9d81a28, 0x4b78a4c4),
++     TOBN(0x3de865ad, 0xe4d55941), TOBN(0xdedafa5e, 0x30384087),
++     TOBN(0x6f414abb, 0x4ef18b9b), TOBN(0x9ee9ea42, 0xfaee5268),
++     TOBN(0x260faa16, 0x37a55a4a), TOBN(0xeb19a514, 0x015f93b9),
++     TOBN(0x51d7ebd2, 0x9e9c3598), TOBN(0x523fc56d, 0x1932178e),
++     TOBN(0x501d070c, 0xb98fe684), TOBN(0xd60fbe9a, 0x124a1458),
++     TOBN(0xa45761c8, 0x92bc6b3f), TOBN(0xf5384858, 0xfe6f27cb),
++     TOBN(0x4b0271f7, 0xb59e763b), TOBN(0x3d4606a9, 0x5b5a8e5e),
++     TOBN(0x1eda5d9b, 0x05a48292), TOBN(0xda7731d0, 0xe6fec446),
++     TOBN(0xa3e33693, 0x90d45871), TOBN(0xe9764040, 0x06166d8d),
++     TOBN(0xb5c33682, 0x89a90403), TOBN(0x4bd17983, 0x72f1d637),
++     TOBN(0xa616679e, 0xd5d2c53a), TOBN(0x5ec4bcd8, 0xfdcf3b87),
++     TOBN(0xae6d7613, 0xb66a694e), TOBN(0x7460fc76, 0xe3fc27e5),
++     TOBN(0x70469b82, 0x95caabee), TOBN(0xde024ca5, 0x889501e3),
++     TOBN(0x6bdadc06, 0x076ed265), TOBN(0x0cb1236b, 0x5a0ef8b2),
++     TOBN(0x4065ddbf, 0x0972ebf9), TOBN(0xf1dd3875, 0x22aca432),
++     TOBN(0xa88b97cf, 0x744aff76), TOBN(0xd1359afd, 0xfe8e3d24),
++     TOBN(0x52a3ba2b, 0x91502cf3), TOBN(0x2c3832a8, 0x084db75d),
++     TOBN(0x04a12ddd, 0xde30b1c9), TOBN(0x7802eabc, 0xe31fd60c),
++     TOBN(0x33707327, 0xa37fddab), TOBN(0x65d6f2ab, 0xfaafa973),
++     TOBN(0x3525c5b8, 0x11e6f91a), TOBN(0x76aeb0c9, 0x5f46530b),
++     TOBN(0xe8815ff6, 0x2f93a675), TOBN(0xa6ec9684, 0x05f48679),
++     TOBN(0x6dcbb556, 0x358ae884), TOBN(0x0af61472, 0xe19e3873),
++     TOBN(0x72334372, 0xa5f696be), TOBN(0xc65e57ea, 0x6f22fb70),
++     TOBN(0x268da30c, 0x946cea90), TOBN(0x136a8a87, 0x65681b2a),
++     TOBN(0xad5e81dc, 0x0f9f44d4), TOBN(0xf09a6960, 0x2c46585a),
++     TOBN(0xd1649164, 0xc447d1b1), TOBN(0x3b4b36c8, 0x879dc8b1),
++     TOBN(0x20d4177b, 0x3b6b234c), TOBN(0x096a2505, 0x1730d9d0),
++     TOBN(0x0611b9b8, 0xef80531d), TOBN(0xba904b3b, 0x64bb495d),
++     TOBN(0x1192d9d4, 0x93a3147a), TOBN(0x9f30a5dc, 0x9a565545),
++     TOBN(0x90b1f9cb, 0x6ef07212), TOBN(0x29958546, 0x0d87fc13),
++     TOBN(0xd3323eff, 0xc17db9ba), TOBN(0xcb18548c, 0xcb1644a8),
++     TOBN(0x18a306d4, 0x4f49ffbc), TOBN(0x28d658f1, 0x4c2e8684),
++     TOBN(0x44ba60cd, 0xa99f8c71), TOBN(0x67b7abdb, 0x4bf742ff),
++     TOBN(0x66310f9c, 0x914b3f99), TOBN(0xae430a32, 0xf412c161),
++     TOBN(0x1e6776d3, 0x88ace52f), TOBN(0x4bc0fa24, 0x52d7067d),
++     TOBN(0x03c286aa, 0x8f07cd1b), TOBN(0x4cb8f38c, 0xa985b2c1),
++     TOBN(0x83ccbe80, 0x8c3bff36), TOBN(0x005a0bd2, 0x5263e575),
++     TOBN(0x460d7dda, 0x259bdcd1), TOBN(0x4a1c5642, 0xfa5cab6b),
++     TOBN(0x2b7bdbb9, 0x9fe4fc88), TOBN(0x09418e28, 0xcc97bbb5),
++     TOBN(0xd8274fb4, 0xa12321ae), TOBN(0xb137007d, 0x5c87b64e),
++     TOBN(0x80531fe1, 0xc63c4962), TOBN(0x50541e89, 0x981fdb25),
++     TOBN(0xdc1291a1, 0xfd4c2b6b), TOBN(0xc0693a17, 0xa6df4fca),
++     TOBN(0xb2c4604e, 0x0117f203), TOBN(0x245f1963, 0x0a99b8d0),
++     TOBN(0xaedc20aa, 0xc6212c44), TOBN(0xb1ed4e56, 0x520f52a8),
++     TOBN(0xfe48f575, 0xf8547be3), TOBN(0x0a7033cd, 0xa9e45f98),
++     TOBN(0x4b45d3a9, 0x18c50100), TOBN(0xb2a6cd6a, 0xa61d41da),
++     TOBN(0x60bbb4f5, 0x57933c6b), TOBN(0xa7538ebd, 0x2b0d7ffc),
++     TOBN(0x9ea3ab8d, 0x8cd626b6), TOBN(0x8273a484, 0x3601625a),
++     TOBN(0x88859845, 0x0168e508), TOBN(0x8cbc9bb2, 0x99a94abd),
++     TOBN(0x713ac792, 0xfab0a671), TOBN(0xa3995b19, 0x6c9ebffc),
++     TOBN(0xe711668e, 0x1239e152), TOBN(0x56892558, 0xbbb8dff4),
++     TOBN(0x8bfc7dab, 0xdbf17963), TOBN(0x5b59fe5a, 0xb3de1253),
++     TOBN(0x7e3320eb, 0x34a9f7ae), TOBN(0xe5e8cf72, 0xd751efe4),
++     TOBN(0x7ea003bc, 0xd9be2f37), TOBN(0xc0f551a0, 0xb6c08ef7),
++     TOBN(0x56606268, 0x038f6725), TOBN(0x1dd38e35, 0x6d92d3b6),
++     TOBN(0x07dfce7c, 0xc3cbd686), TOBN(0x4e549e04, 0x651c5da8),
++     TOBN(0x4058f93b, 0x08b19340), TOBN(0xc2fae6f4, 0xcac6d89d),
++     TOBN(0x4bad8a8c, 0x8f159cc7), TOBN(0x0ddba4b3, 0xcb0b601c),
++     TOBN(0xda4fc7b5, 0x1dd95f8c), TOBN(0x1d163cd7, 0xcea5c255),
++     TOBN(0x30707d06, 0x274a8c4c), TOBN(0x79d9e008, 0x2802e9ce),
++     TOBN(0x02a29ebf, 0xe6ddd505), TOBN(0x37064e74, 0xb50bed1a),
++     TOBN(0x3f6bae65, 0xa7327d57), TOBN(0x3846f5f1, 0xf83920bc),
++     TOBN(0x87c37491, 0x60df1b9b), TOBN(0x4cfb2895, 0x2d1da29f),
++     TOBN(0x10a478ca, 0x4ed1743c), TOBN(0x390c6030, 0x3edd47c6),
++     TOBN(0x8f3e5312, 0x8c0a78de), TOBN(0xccd02bda, 0x1e85df70),
++     TOBN(0xd6c75c03, 0xa61b6582), TOBN(0x0762921c, 0xfc0eebd1),
++     TOBN(0xd34d0823, 0xd85010c0), TOBN(0xd73aaacb, 0x0044cf1f),
++     TOBN(0xfb4159bb, 0xa3b5e78a), TOBN(0x2287c7f7, 0xe5826f3f),
++     TOBN(0x4aeaf742, 0x580b1a01), TOBN(0xf080415d, 0x60423b79),
++     TOBN(0xe12622cd, 0xa7dea144), TOBN(0x49ea4996, 0x59d62472),
++     TOBN(0xb42991ef, 0x571f3913), TOBN(0x0610f214, 0xf5b25a8a),
++     TOBN(0x47adc585, 0x30b79e8f), TOBN(0xf90e3df6, 0x07a065a2),
++     TOBN(0x5d0a5deb, 0x43e2e034), TOBN(0x53fb5a34, 0x444024aa),
++     TOBN(0xa8628c68, 0x6b0c9f7f), TOBN(0x9c69c29c, 0xac563656),
++     TOBN(0x5a231feb, 0xbace47b6), TOBN(0xbdce0289, 0x9ea5a2ec),
++     TOBN(0x05da1fac, 0x9463853e), TOBN(0x96812c52, 0x509e78aa),
++     TOBN(0xd3fb5771, 0x57151692), TOBN(0xeb2721f8, 0xd98e1c44),
++     TOBN(0xc0506087, 0x32399be1), TOBN(0xda5a5511, 0xd979d8b8),
++     TOBN(0x737ed55d, 0xc6f56780), TOBN(0xe20d3004, 0x0dc7a7f4),
++     TOBN(0x02ce7301, 0xf5941a03), TOBN(0x91ef5215, 0xed30f83a),
++     TOBN(0x28727fc1, 0x4092d85f), TOBN(0x72d223c6, 0x5c49e41a),
++     TOBN(0xa7cf30a2, 0xba6a4d81), TOBN(0x7c086209, 0xb030d87d),
++     TOBN(0x04844c7d, 0xfc588b09), TOBN(0x728cd499, 0x5874bbb0),
++     TOBN(0xcc1281ee, 0xe84c0495), TOBN(0x0769b5ba, 0xec31958f),
++     TOBN(0x665c228b, 0xf99c2471), TOBN(0xf2d8a11b, 0x191eb110),
++     TOBN(0x4594f494, 0xd36d7024), TOBN(0x482ded8b, 0xcdcb25a1),
++     TOBN(0xc958a9d8, 0xdadd4885), TOBN(0x7004477e, 0xf1d2b547),
++     TOBN(0x0a45f6ef, 0x2a0af550), TOBN(0x4fc739d6, 0x2f8d6351),
++     TOBN(0x75cdaf27, 0x786f08a9), TOBN(0x8700bb26, 0x42c2737f),
++     TOBN(0x855a7141, 0x1c4e2670), TOBN(0x810188c1, 0x15076fef),
++     TOBN(0xc251d0c9, 0xabcd3297), TOBN(0xae4c8967, 0xf48108eb),
++     TOBN(0xbd146de7, 0x18ceed30), TOBN(0xf9d4f07a, 0xc986bced),
++     TOBN(0x5ad98ed5, 0x83fa1e08), TOBN(0x7780d33e, 0xbeabd1fb),
++     TOBN(0xe330513c, 0x903b1196), TOBN(0xba11de9e, 0xa47bc8c4),
++     TOBN(0x684334da, 0x02c2d064), TOBN(0x7ecf360d, 0xa48de23b),
++     TOBN(0x57a1b474, 0x0a9089d8), TOBN(0xf28fa439, 0xff36734c),
++     TOBN(0xf2a482cb, 0xea4570b3), TOBN(0xee65d68b, 0xa5ebcee9),
++     TOBN(0x988d0036, 0xb9694cd5), TOBN(0x53edd0e9, 0x37885d32),
++     TOBN(0xe37e3307, 0xbeb9bc6d), TOBN(0xe9abb907, 0x9f5c6768),
++     TOBN(0x4396ccd5, 0x51f2160f), TOBN(0x2500888c, 0x47336da6),
++     TOBN(0x383f9ed9, 0x926fce43), TOBN(0x809dd1c7, 0x04da2930),
++     TOBN(0x30f6f596, 0x8a4cb227), TOBN(0x0d700c7f, 0x73a56b38),
++     TOBN(0x1825ea33, 0xab64a065), TOBN(0xaab9b735, 0x1338df80),
++     TOBN(0x1516100d, 0x9b63f57f), TOBN(0x2574395a, 0x27a6a634),
++     TOBN(0xb5560fb6, 0x700a1acd), TOBN(0xe823fd73, 0xfd999681),
++     TOBN(0xda915d1f, 0x6cb4e1ba), TOBN(0x0d030118, 0x6ebe00a3),
++     TOBN(0x744fb0c9, 0x89fca8cd), TOBN(0x970d01db, 0xf9da0e0b),
++     TOBN(0x0ad8c564, 0x7931d76f), TOBN(0xb15737bf, 0xf659b96a),
++     TOBN(0xdc9933e8, 0xa8b484e7), TOBN(0xb2fdbdf9, 0x7a26dec7),
++     TOBN(0x2349e9a4, 0x9f1f0136), TOBN(0x7860368e, 0x70fddddb),
++     TOBN(0xd93d2c1c, 0xf9ad3e18), TOBN(0x6d6c5f17, 0x689f4e79),
++     TOBN(0x7a544d91, 0xb24ff1b6), TOBN(0x3e12a5eb, 0xfe16cd8c),
++     TOBN(0x543574e9, 0xa56b872f), TOBN(0xa1ad550c, 0xfcf68ea2),
++     TOBN(0x689e37d2, 0x3f560ef7), TOBN(0x8c54b9ca, 0xc9d47a8b),
++     TOBN(0x46d40a4a, 0x088ac342), TOBN(0xec450c7c, 0x1576c6d0),
++     TOBN(0xb589e31c, 0x1f9689e9), TOBN(0xdacf2602, 0xb8781718),
++     TOBN(0xa89237c6, 0xc8cb6b42), TOBN(0x1326fc93, 0xb96ef381),
++     TOBN(0x55d56c6d, 0xb5f07825), TOBN(0xacba2eea, 0x7449e22d),
++     TOBN(0x74e0887a, 0x633c3000), TOBN(0xcb6cd172, 0xd7cbcf71),
++     TOBN(0x309e81de, 0xc36cf1be), TOBN(0x07a18a6d, 0x60ae399b),
++     TOBN(0xb36c2679, 0x9edce57e), TOBN(0x52b892f4, 0xdf001d41),
++     TOBN(0xd884ae5d, 0x16a1f2c6), TOBN(0x9b329424, 0xefcc370a),
++     TOBN(0x3120daf2, 0xbd2e21df), TOBN(0x55298d2d, 0x02470a99),
++     TOBN(0x0b78af6c, 0xa05db32e), TOBN(0x5c76a331, 0x601f5636),
++     TOBN(0xaae861ff, 0xf8a4f29c), TOBN(0x70dc9240, 0xd68f8d49),
++     TOBN(0x960e649f, 0x81b1321c), TOBN(0x3d2c801b, 0x8792e4ce),
++     TOBN(0xf479f772, 0x42521876), TOBN(0x0bed93bc, 0x416c79b1),
++     TOBN(0xa67fbc05, 0x263e5bc9), TOBN(0x01e8e630, 0x521db049),
++     TOBN(0x76f26738, 0xc6f3431e), TOBN(0xe609cb02, 0xe3267541),
++     TOBN(0xb10cff2d, 0x818c877c), TOBN(0x1f0e75ce, 0x786a13cb),
++     TOBN(0xf4fdca64, 0x1158544d), TOBN(0x5d777e89, 0x6cb71ed0),
++     TOBN(0x3c233737, 0xa9aa4755), TOBN(0x7b453192, 0xe527ab40),
++     TOBN(0xdb59f688, 0x39f05ffe), TOBN(0x8f4f4be0, 0x6d82574e),
++     TOBN(0xcce3450c, 0xee292d1b), TOBN(0xaa448a12, 0x61ccd086),
++     TOBN(0xabce91b3, 0xf7914967), TOBN(0x4537f09b, 0x1908a5ed),
++     TOBN(0xa812421e, 0xf51042e7), TOBN(0xfaf5cebc, 0xec0b3a34),
++     TOBN(0x730ffd87, 0x4ca6b39a), TOBN(0x70fb72ed, 0x02efd342),
++     TOBN(0xeb4735f9, 0xd75c8edb), TOBN(0xc11f2157, 0xc278aa51),
++     TOBN(0xc459f635, 0xbf3bfebf), TOBN(0x3a1ff0b4, 0x6bd9601f),
++     TOBN(0xc9d12823, 0xc420cb73), TOBN(0x3e9af3e2, 0x3c2915a3),
++     TOBN(0xe0c82c72, 0xb41c3440), TOBN(0x175239e5, 0xe3039a5f),
++     TOBN(0xe1084b8a, 0x558795a3), TOBN(0x328d0a1d, 0xd01e5c60),
++     TOBN(0x0a495f2e, 0xd3788a04), TOBN(0x25d8ff16, 0x66c11a9f),
++     TOBN(0xf5155f05, 0x9ed692d6), TOBN(0x954fa107, 0x4f425fe4),
++     TOBN(0xd16aabf2, 0xe98aaa99), TOBN(0x90cd8ba0, 0x96b0f88a),
++     TOBN(0x957f4782, 0xc154026a), TOBN(0x54ee0734, 0x52af56d2),
++     TOBN(0xbcf89e54, 0x45b4147a), TOBN(0x3d102f21, 0x9a52816c),
++     TOBN(0x6808517e, 0x39b62e77), TOBN(0x92e25421, 0x69169ad8),
++     TOBN(0xd721d871, 0xbb608558), TOBN(0x60e4ebae, 0xf6d4ff9b),
++     TOBN(0x0ba10819, 0x41f2763e), TOBN(0xca2e45be, 0x51ee3247),
++     TOBN(0x66d172ec, 0x2bfd7a5f), TOBN(0x528a8f2f, 0x74d0b12d),
++     TOBN(0xe17f1e38, 0xdabe70dc), TOBN(0x1d5d7316, 0x9f93983c),
++     TOBN(0x51b2184a, 0xdf423e31), TOBN(0xcb417291, 0xaedb1a10),
++     TOBN(0x2054ca93, 0x625bcab9), TOBN(0x54396860, 0xa98998f0),
++     TOBN(0x4e53f6c4, 0xa54ae57e), TOBN(0x0ffeb590, 0xee648e9d),
++     TOBN(0xfbbdaadc, 0x6afaf6bc), TOBN(0xf88ae796, 0xaa3bfb8a),
++     TOBN(0x209f1d44, 0xd2359ed9), TOBN(0xac68dd03, 0xf3544ce2),
++     TOBN(0xf378da47, 0xfd51e569), TOBN(0xe1abd860, 0x2cc80097),
++     TOBN(0x23ca18d9, 0x343b6e3a), TOBN(0x480797e8, 0xb40a1bae),
++     TOBN(0xd1f0c717, 0x533f3e67), TOBN(0x44896970, 0x06e6cdfc),
++     TOBN(0x8ca21055, 0x52a82e8d), TOBN(0xb2caf785, 0x78460cdc),
++     TOBN(0x4c1b7b62, 0xe9037178), TOBN(0xefc09d2c, 0xdb514b58),
++     TOBN(0x5f2df9ee, 0x9113be5c), TOBN(0x2fbda78f, 0xb3f9271c),
++     TOBN(0xe09a81af, 0x8f83fc54), TOBN(0x06b13866, 0x8afb5141),
++     TOBN(0x38f6480f, 0x43e3865d), TOBN(0x72dd77a8, 0x1ddf47d9),
++     TOBN(0xf2a8e971, 0x4c205ff7), TOBN(0x46d449d8, 0x9d088ad8),
++     TOBN(0x926619ea, 0x185d706f), TOBN(0xe47e02eb, 0xc7dd7f62),
++     TOBN(0xe7f120a7, 0x8cbc2031), TOBN(0xc18bef00, 0x998d4ac9),
++     TOBN(0x18f37a9c, 0x6bdf22da), TOBN(0xefbc432f, 0x90dc82df),
++     TOBN(0xc52cef8e, 0x5d703651), TOBN(0x82887ba0, 0xd99881a5),
++     TOBN(0x7cec9dda, 0xb920ec1d), TOBN(0xd0d7e8c3, 0xec3e8d3b),
++     TOBN(0x445bc395, 0x4ca88747), TOBN(0xedeaa2e0, 0x9fd53535),
++     TOBN(0x461b1d93, 0x6cc87475), TOBN(0xd92a52e2, 0x6d2383bd),
++     TOBN(0xfabccb59, 0xd7903546), TOBN(0x6111a761, 0x3d14b112),
++     TOBN(0x0ae584fe, 0xb3d5f612), TOBN(0x5ea69b8d, 0x60e828ec),
++     TOBN(0x6c078985, 0x54087030), TOBN(0x649cab04, 0xac4821fe),
++     TOBN(0x25ecedcf, 0x8bdce214), TOBN(0xb5622f72, 0x86af7361),
++     TOBN(0x0e1227aa, 0x7038b9e2), TOBN(0xd0efb273, 0xac20fa77),
++     TOBN(0x817ff88b, 0x79df975b), TOBN(0x856bf286, 0x1999503e),
++     TOBN(0xb4d5351f, 0x5038ec46), TOBN(0x740a52c5, 0xfc42af6e),
++     TOBN(0x2e38bb15, 0x2cbb1a3f), TOBN(0xc3eb99fe, 0x17a83429),
++     TOBN(0xca4fcbf1, 0xdd66bb74), TOBN(0x880784d6, 0xcde5e8fc),
++     TOBN(0xddc84c1c, 0xb4e7a0be), TOBN(0x8780510d, 0xbd15a72f),
++     TOBN(0x44bcf1af, 0x81ec30e1), TOBN(0x141e50a8, 0x0a61073e),
++     TOBN(0x0d955718, 0x47be87ae), TOBN(0x68a61417, 0xf76a4372),
++     TOBN(0xf57e7e87, 0xc607c3d3), TOBN(0x043afaf8, 0x5252f332),
++     TOBN(0xcc14e121, 0x1552a4d2), TOBN(0xb6dee692, 0xbb4d4ab4),
++     TOBN(0xb6ab74c8, 0xa03816a4), TOBN(0x84001ae4, 0x6f394a29),
++     TOBN(0x5bed8344, 0xd795fb45), TOBN(0x57326e7d, 0xb79f55a5),
++     TOBN(0xc9533ce0, 0x4accdffc), TOBN(0x53473caf, 0x3993fa04),
++     TOBN(0x7906eb93, 0xa13df4c8), TOBN(0xa73e51f6, 0x97cbe46f),
++     TOBN(0xd1ab3ae1, 0x0ae4ccf8), TOBN(0x25614508, 0x8a5b3dbc),
++     TOBN(0x61eff962, 0x11a71b27), TOBN(0xdf71412b, 0x6bb7fa39),
++     TOBN(0xb31ba6b8, 0x2bd7f3ef), TOBN(0xb0b9c415, 0x69180d29),
++     TOBN(0xeec14552, 0x014cdde5), TOBN(0x702c624b, 0x227b4bbb),
++     TOBN(0x2b15e8c2, 0xd3e988f3), TOBN(0xee3bcc6d, 0xa4f7fd04),
++     TOBN(0x9d00822a, 0x42ac6c85), TOBN(0x2db0cea6, 0x1df9f2b7),
++     TOBN(0xd7cad2ab, 0x42de1e58), TOBN(0x346ed526, 0x2d6fbb61),
++     TOBN(0xb3962995, 0x1a2faf09), TOBN(0x2fa8a580, 0x7c25612e),
++     TOBN(0x30ae04da, 0x7cf56490), TOBN(0x75662908, 0x0eea3961),
++     TOBN(0x3609f5c5, 0x3d080847), TOBN(0xcb081d39, 0x5241d4f6),
++     TOBN(0xb4fb3810, 0x77961a63), TOBN(0xc20c5984, 0x2abb66fc),
++     TOBN(0x3d40aa7c, 0xf902f245), TOBN(0x9cb12736, 0x4e536b1e),
++     TOBN(0x5eda24da, 0x99b3134f), TOBN(0xafbd9c69, 0x5cd011af),
++     TOBN(0x9a16e30a, 0xc7088c7d), TOBN(0x5ab65710, 0x3207389f),
++     TOBN(0x1b09547f, 0xe7407a53), TOBN(0x2322f9d7, 0x4fdc6eab),
++     TOBN(0xc0f2f22d, 0x7430de4d), TOBN(0x19382696, 0xe68ca9a9),
++     TOBN(0x17f1eff1, 0x918e5868), TOBN(0xe3b5b635, 0x586f4204),
++     TOBN(0x146ef980, 0x3fbc4341), TOBN(0x359f2c80, 0x5b5eed4e),
++     TOBN(0x9f35744e, 0x7482e41d), TOBN(0x9a9ac3ec, 0xf3b224c2),
++     TOBN(0x9161a6fe, 0x91fc50ae), TOBN(0x89ccc66b, 0xc613fa7c),
++     TOBN(0x89268b14, 0xc732f15a), TOBN(0x7cd6f4e2, 0xb467ed03),
++     TOBN(0xfbf79869, 0xce56b40e), TOBN(0xf93e094c, 0xc02dde98),
++     TOBN(0xefe0c3a8, 0xedee2cd7), TOBN(0x90f3ffc0, 0xb268fd42),
++     TOBN(0x81a7fd56, 0x08241aed), TOBN(0x95ab7ad8, 0x00b1afe8),
++     TOBN(0x40127056, 0x3e310d52), TOBN(0xd3ffdeb1, 0x09d9fc43),
++     TOBN(0xc8f85c91, 0xd11a8594), TOBN(0x2e74d258, 0x31cf6db8),
++     TOBN(0x829c7ca3, 0x02b5dfd0), TOBN(0xe389cfbe, 0x69143c86),
++     TOBN(0xd01b6405, 0x941768d8), TOBN(0x45103995, 0x03bf825d),
++     TOBN(0xcc4ee166, 0x56cd17e2), TOBN(0xbea3c283, 0xba037e79),
++     TOBN(0x4e1ac06e, 0xd9a47520), TOBN(0xfbfe18aa, 0xaf852404),
++     TOBN(0x5615f8e2, 0x8087648a), TOBN(0x7301e47e, 0xb9d150d9),
++     TOBN(0x79f9f9dd, 0xb299b977), TOBN(0x76697a7b, 0xa5b78314),
++     TOBN(0x10d67468, 0x7d7c90e7), TOBN(0x7afffe03, 0x937210b5),
++     TOBN(0x5aef3e4b, 0x28c22cee), TOBN(0xefb0ecd8, 0x09fd55ae),
++     TOBN(0x4cea7132, 0x0d2a5d6a), TOBN(0x9cfb5fa1, 0x01db6357),
++     TOBN(0x395e0b57, 0xf36e1ac5), TOBN(0x008fa9ad, 0x36cafb7d),
++     TOBN(0x8f6cdf70, 0x5308c4db), TOBN(0x51527a37, 0x95ed2477),
++     TOBN(0xba0dee30, 0x5bd21311), TOBN(0x6ed41b22, 0x909c90d7),
++     TOBN(0xc5f6b758, 0x7c8696d3), TOBN(0x0db8eaa8, 0x3ce83a80),
++     TOBN(0xd297fe37, 0xb24b4b6f), TOBN(0xfe58afe8, 0x522d1f0d),
++     TOBN(0x97358736, 0x8c98dbd9), TOBN(0x6bc226ca, 0x9454a527),
++     TOBN(0xa12b384e, 0xce53c2d0), TOBN(0x779d897d, 0x5e4606da),
++     TOBN(0xa53e47b0, 0x73ec12b0), TOBN(0x462dbbba, 0x5756f1ad),
++     TOBN(0x69fe09f2, 0xcafe37b6), TOBN(0x273d1ebf, 0xecce2e17),
++     TOBN(0x8ac1d538, 0x3cf607fd), TOBN(0x8035f7ff, 0x12e10c25),}
++    ,
++    {TOBN(0x854d34c7, 0x7e6c5520), TOBN(0xc27df9ef, 0xdcb9ea58),
++     TOBN(0x405f2369, 0xd686666d), TOBN(0x29d1febf, 0x0417aa85),
++     TOBN(0x9846819e, 0x93470afe), TOBN(0x3e6a9669, 0xe2a27f9e),
++     TOBN(0x24d008a2, 0xe31e6504), TOBN(0xdba7cecf, 0x9cb7680a),
++     TOBN(0xecaff541, 0x338d6e43), TOBN(0x56f7dd73, 0x4541d5cc),
++     TOBN(0xb5d426de, 0x96bc88ca), TOBN(0x48d94f6b, 0x9ed3a2c3),
++     TOBN(0x6354a3bb, 0x2ef8279c), TOBN(0xd575465b, 0x0b1867f2),
++     TOBN(0xef99b0ff, 0x95225151), TOBN(0xf3e19d88, 0xf94500d8),
++     TOBN(0x92a83268, 0xe32dd620), TOBN(0x913ec99f, 0x627849a2),
++     TOBN(0xedd8fdfa, 0x2c378882), TOBN(0xaf96f33e, 0xee6f8cfe),
++     TOBN(0xc06737e5, 0xdc3fa8a5), TOBN(0x236bb531, 0xb0b03a1d),
++     TOBN(0x33e59f29, 0x89f037b0), TOBN(0x13f9b5a7, 0xd9a12a53),
++     TOBN(0x0d0df6ce, 0x51efb310), TOBN(0xcb5b2eb4, 0x958df5be),
++     TOBN(0xd6459e29, 0x36158e59), TOBN(0x82aae2b9, 0x1466e336),
++     TOBN(0xfb658a39, 0x411aa636), TOBN(0x7152ecc5, 0xd4c0a933),
++     TOBN(0xf10c758a, 0x49f026b7), TOBN(0xf4837f97, 0xcb09311f),
++     TOBN(0xddfb02c4, 0xc753c45f), TOBN(0x18ca81b6, 0xf9c840fe),
++     TOBN(0x846fd09a, 0xb0f8a3e6), TOBN(0xb1162add, 0xe7733dbc),
++     TOBN(0x7070ad20, 0x236e3ab6), TOBN(0xf88cdaf5, 0xb2a56326),
++     TOBN(0x05fc8719, 0x997cbc7a), TOBN(0x442cd452, 0x4b665272),
++     TOBN(0x7807f364, 0xb71698f5), TOBN(0x6ba418d2, 0x9f7b605e),
++     TOBN(0xfd20b00f, 0xa03b2cbb), TOBN(0x883eca37, 0xda54386f),
++     TOBN(0xff0be43f, 0xf3437f24), TOBN(0xe910b432, 0xa48bb33c),
++     TOBN(0x4963a128, 0x329df765), TOBN(0xac1dd556, 0xbe2fe6f7),
++     TOBN(0x557610f9, 0x24a0a3fc), TOBN(0x38e17bf4, 0xe881c3f9),
++     TOBN(0x6ba84faf, 0xed0dac99), TOBN(0xd4a222c3, 0x59eeb918),
++     TOBN(0xc79c1dbe, 0x13f542b6), TOBN(0x1fc65e0d, 0xe425d457),
++     TOBN(0xeffb754f, 0x1debb779), TOBN(0x638d8fd0, 0x9e08af60),
++     TOBN(0x994f523a, 0x626332d5), TOBN(0x7bc38833, 0x5561bb44),
++     TOBN(0x005ed4b0, 0x3d845ea2), TOBN(0xd39d3ee1, 0xc2a1f08a),
++     TOBN(0x6561fdd3, 0xe7676b0d), TOBN(0x620e35ff, 0xfb706017),
++     TOBN(0x36ce424f, 0xf264f9a8), TOBN(0xc4c3419f, 0xda2681f7),
++     TOBN(0xfb6afd2f, 0x69beb6e8), TOBN(0x3a50b993, 0x6d700d03),
++     TOBN(0xc840b2ad, 0x0c83a14f), TOBN(0x573207be, 0x54085bef),
++     TOBN(0x5af882e3, 0x09fe7e5b), TOBN(0x957678a4, 0x3b40a7e1),
++     TOBN(0x172d4bdd, 0x543056e2), TOBN(0x9c1b26b4, 0x0df13c0a),
++     TOBN(0x1c30861c, 0xf405ff06), TOBN(0xebac86bd, 0x486e828b),
++     TOBN(0xe791a971, 0x636933fc), TOBN(0x50e7c2be, 0x7aeee947),
++     TOBN(0xc3d4a095, 0xfa90d767), TOBN(0xae60eb7b, 0xe670ab7b),
++     TOBN(0x17633a64, 0x397b056d), TOBN(0x93a21f33, 0x105012aa),
++     TOBN(0x663c370b, 0xabb88643), TOBN(0x91df36d7, 0x22e21599),
++     TOBN(0x183ba835, 0x8b761671), TOBN(0x381eea1d, 0x728f3bf1),
++     TOBN(0xb9b2f1ba, 0x39966e6c), TOBN(0x7c464a28, 0xe7295492),
++     TOBN(0x0fd5f70a, 0x09b26b7f), TOBN(0xa9aba1f9, 0xfbe009df),
++     TOBN(0x857c1f22, 0x369b87ad), TOBN(0x3c00e5d9, 0x32fca556),
++     TOBN(0x1ad74cab, 0x90b06466), TOBN(0xa7112386, 0x550faaf2),
++     TOBN(0x7435e198, 0x6d9bd5f5), TOBN(0x2dcc7e38, 0x59c3463f),
++     TOBN(0xdc7df748, 0xca7bd4b2), TOBN(0x13cd4c08, 0x9dec2f31),
++     TOBN(0x0d3b5df8, 0xe3237710), TOBN(0x0dadb26e, 0xcbd2f7b0),
++     TOBN(0x9f5966ab, 0xe4aa082b), TOBN(0x666ec8de, 0x350e966e),
++     TOBN(0x1bfd1ed5, 0xee524216), TOBN(0xcd93c59b, 0x41dab0b6),
++     TOBN(0x658a8435, 0xd186d6ba), TOBN(0x1b7d34d2, 0x159d1195),
++     TOBN(0x5936e460, 0x22caf46b), TOBN(0x6a45dd8f, 0x9a96fe4f),
++     TOBN(0xf7925434, 0xb98f474e), TOBN(0x41410412, 0x0053ef15),
++     TOBN(0x71cf8d12, 0x41de97bf), TOBN(0xb8547b61, 0xbd80bef4),
++     TOBN(0xb47d3970, 0xc4db0037), TOBN(0xf1bcd328, 0xfef20dff),
++     TOBN(0x31a92e09, 0x10caad67), TOBN(0x1f591960, 0x5531a1e1),
++     TOBN(0x3bb852e0, 0x5f4fc840), TOBN(0x63e297ca, 0x93a72c6c),
++     TOBN(0x3c2b0b2e, 0x49abad67), TOBN(0x6ec405fc, 0xed3db0d9),
++     TOBN(0xdc14a530, 0x7fef1d40), TOBN(0xccd19846, 0x280896fc),
++     TOBN(0x00f83176, 0x9bb81648), TOBN(0xd69eb485, 0x653120d0),
++     TOBN(0xd17d75f4, 0x4ccabc62), TOBN(0x34a07f82, 0xb749fcb1),
++     TOBN(0x2c3af787, 0xbbfb5554), TOBN(0xb06ed4d0, 0x62e283f8),
++     TOBN(0x5722889f, 0xa19213a0), TOBN(0x162b085e, 0xdcf3c7b4),
++     TOBN(0xbcaecb31, 0xe0dd3eca), TOBN(0xc6237fbc, 0xe52f13a5),
++     TOBN(0xcc2b6b03, 0x27bac297), TOBN(0x2ae1cac5, 0xb917f54a),
++     TOBN(0x474807d4, 0x7845ae4f), TOBN(0xfec7dd92, 0xce5972e0),
++     TOBN(0xc3bd2541, 0x1d7915bb), TOBN(0x66f85dc4, 0xd94907ca),
++     TOBN(0xd981b888, 0xbdbcf0ca), TOBN(0xd75f5da6, 0xdf279e9f),
++     TOBN(0x128bbf24, 0x7054e934), TOBN(0x3c6ff6e5, 0x81db134b),
++     TOBN(0x795b7cf4, 0x047d26e4), TOBN(0xf370f7b8, 0x5049ec37),
++     TOBN(0xc6712d4d, 0xced945af), TOBN(0xdf30b5ec, 0x095642bc),
++     TOBN(0x9b034c62, 0x4896246e), TOBN(0x5652c016, 0xee90bbd1),
++     TOBN(0xeb38636f, 0x87fedb73), TOBN(0x5e32f847, 0x0135a613),
++     TOBN(0x0703b312, 0xcf933c83), TOBN(0xd05bb76e, 0x1a7f47e6),
++     TOBN(0x825e4f0c, 0x949c2415), TOBN(0x569e5622, 0x7250d6f8),
++     TOBN(0xbbe9eb3a, 0x6568013e), TOBN(0x8dbd203f, 0x22f243fc),
++     TOBN(0x9dbd7694, 0xb342734a), TOBN(0x8f6d12f8, 0x46afa984),
++     TOBN(0xb98610a2, 0xc9eade29), TOBN(0xbab4f323, 0x47dd0f18),
++     TOBN(0x5779737b, 0x671c0d46), TOBN(0x10b6a7c6, 0xd3e0a42a),
++     TOBN(0xfb19ddf3, 0x3035b41c), TOBN(0xd336343f, 0x99c45895),
++     TOBN(0x61fe4938, 0x54c857e5), TOBN(0xc4d506be, 0xae4e57d5),
++     TOBN(0x3cd8c8cb, 0xbbc33f75), TOBN(0x7281f08a, 0x9262c77d),
++     TOBN(0x083f4ea6, 0xf11a2823), TOBN(0x8895041e, 0x9fba2e33),
++     TOBN(0xfcdfea49, 0x9c438edf), TOBN(0x7678dcc3, 0x91edba44),
++     TOBN(0xf07b3b87, 0xe2ba50f0), TOBN(0xc13888ef, 0x43948c1b),
++     TOBN(0xc2135ad4, 0x1140af42), TOBN(0x8e5104f3, 0x926ed1a7),
++     TOBN(0xf24430cb, 0x88f6695f), TOBN(0x0ce0637b, 0x6d73c120),
++     TOBN(0xb2db01e6, 0xfe631e8f), TOBN(0x1c5563d7, 0xd7bdd24b),
++     TOBN(0x8daea3ba, 0x369ad44f), TOBN(0x000c81b6, 0x8187a9f9),
++     TOBN(0x5f48a951, 0xaae1fd9a), TOBN(0xe35626c7, 0x8d5aed8a),
++     TOBN(0x20952763, 0x0498c622), TOBN(0x76d17634, 0x773aa504),
++     TOBN(0x36d90dda, 0xeb300f7a), TOBN(0x9dcf7dfc, 0xedb5e801),
++     TOBN(0x645cb268, 0x74d5244c), TOBN(0xa127ee79, 0x348e3aa2),
++     TOBN(0x488acc53, 0x575f1dbb), TOBN(0x95037e85, 0x80e6161e),
++     TOBN(0x57e59283, 0x292650d0), TOBN(0xabe67d99, 0x14938216),
++     TOBN(0x3c7f944b, 0x3f8e1065), TOBN(0xed908cb6, 0x330e8924),
++     TOBN(0x08ee8fd5, 0x6f530136), TOBN(0x2227b7d5, 0xd7ffc169),
++     TOBN(0x4f55c893, 0xb5cd6dd5), TOBN(0x82225e11, 0xa62796e8),
++     TOBN(0x5c6cead1, 0xcb18e12c), TOBN(0x4381ae0c, 0x84f5a51a),
++     TOBN(0x345913d3, 0x7fafa4c8), TOBN(0x3d918082, 0x0491aac0),
++     TOBN(0x9347871f, 0x3e69264c), TOBN(0xbea9dd3c, 0xb4f4f0cd),
++     TOBN(0xbda5d067, 0x3eadd3e7), TOBN(0x0033c1b8, 0x0573bcd8),
++     TOBN(0x25589379, 0x5da2486c), TOBN(0xcb89ee5b, 0x86abbee7),
++     TOBN(0x8fe0a8f3, 0x22532e5d), TOBN(0xb6410ff0, 0x727dfc4c),
++     TOBN(0x619b9d58, 0x226726db), TOBN(0x5ec25669, 0x7a2b2dc7),
++     TOBN(0xaf4d2e06, 0x4c3beb01), TOBN(0x852123d0, 0x7acea556),
++     TOBN(0x0e9470fa, 0xf783487a), TOBN(0x75a7ea04, 0x5664b3eb),
++     TOBN(0x4ad78f35, 0x6798e4ba), TOBN(0x9214e6e5, 0xc7d0e091),
++     TOBN(0xc420b488, 0xb1290403), TOBN(0x64049e0a, 0xfc295749),
++     TOBN(0x03ef5af1, 0x3ae9841f), TOBN(0xdbe4ca19, 0xb0b662a6),
++     TOBN(0x46845c5f, 0xfa453458), TOBN(0xf8dabf19, 0x10b66722),
++     TOBN(0xb650f0aa, 0xcce2793b), TOBN(0x71db851e, 0xc5ec47c1),
++     TOBN(0x3eb78f3e, 0x3b234fa9), TOBN(0xb0c60f35, 0xfc0106ce),
++     TOBN(0x05427121, 0x774eadbd), TOBN(0x25367faf, 0xce323863),
++     TOBN(0x7541b5c9, 0xcd086976), TOBN(0x4ff069e2, 0xdc507ad1),
++     TOBN(0x74145256, 0x8776e667), TOBN(0x6e76142c, 0xb23c6bb5),
++     TOBN(0xdbf30712, 0x1b3a8a87), TOBN(0x60e7363e, 0x98450836),
++     TOBN(0x5741450e, 0xb7366d80), TOBN(0xe4ee14ca, 0x4837dbdf),
++     TOBN(0xa765eb9b, 0x69d4316f), TOBN(0x04548dca, 0x8ef43825),
++     TOBN(0x9c9f4e4c, 0x5ae888eb), TOBN(0x733abb51, 0x56e9ac99),
++     TOBN(0xdaad3c20, 0xba6ac029), TOBN(0x9b8dd3d3, 0x2ba3e38e),
++     TOBN(0xa9bb4c92, 0x0bc5d11a), TOBN(0xf20127a7, 0x9c5f88a3),
++     TOBN(0x4f52b06e, 0x161d3cb8), TOBN(0x26c1ff09, 0x6afaf0a6),
++     TOBN(0x32670d2f, 0x7189e71f), TOBN(0xc6438748, 0x5ecf91e7),
++     TOBN(0x15758e57, 0xdb757a21), TOBN(0x427d09f8, 0x290a9ce5),
++     TOBN(0x846a308f, 0x38384a7a), TOBN(0xaac3acb4, 0xb0732b99),
++     TOBN(0x9e941009, 0x17845819), TOBN(0x95cba111, 0xa7ce5e03),
++     TOBN(0x6f3d4f7f, 0xb00009c4), TOBN(0xb8396c27, 0x8ff28b5f),
++     TOBN(0xb1a9ae43, 0x1c97975d), TOBN(0x9d7ba8af, 0xe5d9fed5),
++     TOBN(0x338cf09f, 0x34f485b6), TOBN(0xbc0ddacc, 0x64122516),
++     TOBN(0xa450da12, 0x05d471fe), TOBN(0x4c3a6250, 0x628dd8c9),
++     TOBN(0x69c7d103, 0xd1295837), TOBN(0xa2893e50, 0x3807eb2f),
++     TOBN(0xd6e1e1de, 0xbdb41491), TOBN(0xc630745b, 0x5e138235),
++     TOBN(0xc892109e, 0x48661ae1), TOBN(0x8d17e7eb, 0xea2b2674),
++     TOBN(0x00ec0f87, 0xc328d6b5), TOBN(0x6d858645, 0xf079ff9e),
++     TOBN(0x6cdf243e, 0x19115ead), TOBN(0x1ce1393e, 0x4bac4fcf),
++     TOBN(0x2c960ed0, 0x9c29f25b), TOBN(0x59be4d8e, 0x9d388a05),
++     TOBN(0x0d46e06c, 0xd0def72b), TOBN(0xb923db5d, 0xe0342748),
++     TOBN(0xf7d3aacd, 0x936d4a3d), TOBN(0x558519cc, 0x0b0b099e),
++     TOBN(0x3ea8ebf8, 0x827097ef), TOBN(0x259353db, 0xd054f55d),
++     TOBN(0x84c89abc, 0x6d2ed089), TOBN(0x5c548b69, 0x8e096a7c),
++     TOBN(0xd587f616, 0x994b995d), TOBN(0x4d1531f6, 0xa5845601),
++     TOBN(0x792ab31e, 0x451fd9f0), TOBN(0xc8b57bb2, 0x65adf6ca),
++     TOBN(0x68440fcb, 0x1cd5ad73), TOBN(0xb9c860e6, 0x6144da4f),
++     TOBN(0x2ab286aa, 0x8462beb8), TOBN(0xcc6b8fff, 0xef46797f),
++     TOBN(0xac820da4, 0x20c8a471), TOBN(0x69ae05a1, 0x77ff7faf),
++     TOBN(0xb9163f39, 0xbfb5da77), TOBN(0xbd03e590, 0x2c73ab7a),
++     TOBN(0x7e862b5e, 0xb2940d9e), TOBN(0x3c663d86, 0x4b9af564),
++     TOBN(0xd8309031, 0xbde3033d), TOBN(0x298231b2, 0xd42c5bc6),
++     TOBN(0x42090d2c, 0x552ad093), TOBN(0xa4799d1c, 0xff854695),
++     TOBN(0x0a88b5d6, 0xd31f0d00), TOBN(0xf8b40825, 0xa2f26b46),
++     TOBN(0xec29b1ed, 0xf1bd7218), TOBN(0xd491c53b, 0x4b24c86e),
++     TOBN(0xd2fe588f, 0x3395ea65), TOBN(0x6f3764f7, 0x4456ef15),
++     TOBN(0xdb43116d, 0xcdc34800), TOBN(0xcdbcd456, 0xc1e33955),
++     TOBN(0xefdb5540, 0x74ab286b), TOBN(0x948c7a51, 0xd18c5d7c),
++     TOBN(0xeb81aa37, 0x7378058e), TOBN(0x41c746a1, 0x04411154),
++     TOBN(0xa10c73bc, 0xfb828ac7), TOBN(0x6439be91, 0x9d972b29),
++     TOBN(0x4bf3b4b0, 0x43a2fbad), TOBN(0x39e6dadf, 0x82b5e840),
++     TOBN(0x4f716408, 0x6397bd4c), TOBN(0x0f7de568, 0x7f1eeccb),
++     TOBN(0x5865c5a1, 0xd2ffbfc1), TOBN(0xf74211fa, 0x4ccb6451),
++     TOBN(0x66368a88, 0xc0b32558), TOBN(0x5b539dc2, 0x9ad7812e),
++     TOBN(0x579483d0, 0x2f3af6f6), TOBN(0x52132078, 0x99934ece),
++     TOBN(0x50b9650f, 0xdcc9e983), TOBN(0xca989ec9, 0xaee42b8a),
++     TOBN(0x6a44c829, 0xd6f62f99), TOBN(0x8f06a309, 0x4c2a7c0c),
++     TOBN(0x4ea2b3a0, 0x98a0cb0a), TOBN(0x5c547b70, 0xbeee8364),
++     TOBN(0x461d40e1, 0x682afe11), TOBN(0x9e0fc77a, 0x7b41c0a8),
++     TOBN(0x79e4aefd, 0xe20d5d36), TOBN(0x2916e520, 0x32dd9f63),
++     TOBN(0xf59e52e8, 0x3f883faf), TOBN(0x396f9639, 0x2b868d35),
++     TOBN(0xc902a9df, 0x4ca19881), TOBN(0x0fc96822, 0xdb2401a6),
++     TOBN(0x41237587, 0x66f1c68d), TOBN(0x10fc6de3, 0xfb476c0d),
++     TOBN(0xf8b6b579, 0x841f5d90), TOBN(0x2ba8446c, 0xfa24f44a),
++     TOBN(0xa237b920, 0xef4a9975), TOBN(0x60bb6004, 0x2330435f),
++     TOBN(0xd6f4ab5a, 0xcfb7e7b5), TOBN(0xb2ac5097, 0x83435391),
++     TOBN(0xf036ee2f, 0xb0d1ea67), TOBN(0xae779a6a, 0x74c56230),
++     TOBN(0x59bff8c8, 0xab838ae6), TOBN(0xcd83ca99, 0x9b38e6f0),
++     TOBN(0xbb27bef5, 0xe33deed3), TOBN(0xe6356f6f, 0x001892a8),
++     TOBN(0xbf3be6cc, 0x7adfbd3e), TOBN(0xaecbc81c, 0x33d1ac9d),
++     TOBN(0xe4feb909, 0xe6e861dc), TOBN(0x90a247a4, 0x53f5f801),
++     TOBN(0x01c50acb, 0x27346e57), TOBN(0xce29242e, 0x461acc1b),
++     TOBN(0x04dd214a, 0x2f998a91), TOBN(0x271ee9b1, 0xd4baf27b),
++     TOBN(0x7e3027d1, 0xe8c26722), TOBN(0x21d1645c, 0x1820dce5),
++     TOBN(0x086f242c, 0x7501779c), TOBN(0xf0061407, 0xfa0e8009),
++     TOBN(0xf23ce477, 0x60187129), TOBN(0x05bbdedb, 0x0fde9bd0),
++     TOBN(0x682f4832, 0x25d98473), TOBN(0xf207fe85, 0x5c658427),
++     TOBN(0xb6fdd7ba, 0x4166ffa1), TOBN(0x0c314056, 0x9eed799d),
++     TOBN(0x0db8048f, 0x4107e28f), TOBN(0x74ed3871, 0x41216840),
++     TOBN(0x74489f8f, 0x56a3c06e), TOBN(0x1e1c005b, 0x12777134),
++     TOBN(0xdb332a73, 0xf37ec3c3), TOBN(0xc65259bd, 0xdd59eba0),
++     TOBN(0x2291709c, 0xdb4d3257), TOBN(0x9a793b25, 0xbd389390),
++     TOBN(0xf39fe34b, 0xe43756f0), TOBN(0x2f76bdce, 0x9afb56c9),
++     TOBN(0x9f37867a, 0x61208b27), TOBN(0xea1d4307, 0x089972c3),
++     TOBN(0x8c595330, 0x8bdf623a), TOBN(0x5f5accda, 0x8441fb7d),
++     TOBN(0xfafa9418, 0x32ddfd95), TOBN(0x6ad40c5a, 0x0fde9be7),
++     TOBN(0x43faba89, 0xaeca8709), TOBN(0xc64a7cf1, 0x2c248a9d),
++     TOBN(0x16620252, 0x72637a76), TOBN(0xaee1c791, 0x22b8d1bb),
++     TOBN(0xf0f798fd, 0x21a843b2), TOBN(0x56e4ed4d, 0x8d005cb1),
++     TOBN(0x355f7780, 0x1f0d8abe), TOBN(0x197b04cf, 0x34522326),
++     TOBN(0x41f9b31f, 0xfd42c13f), TOBN(0x5ef7feb2, 0xb40f933d),
++     TOBN(0x27326f42, 0x5d60bad4), TOBN(0x027ecdb2, 0x8c92cf89),
++     TOBN(0x04aae4d1, 0x4e3352fe), TOBN(0x08414d2f, 0x73591b90),
++     TOBN(0x5ed6124e, 0xb7da7d60), TOBN(0xb985b931, 0x4d13d4ec),
++     TOBN(0xa592d3ab, 0x96bf36f9), TOBN(0x012dbed5, 0xbbdf51df),
++     TOBN(0xa57963c0, 0xdf6c177d), TOBN(0x010ec869, 0x87ca29cf),
++     TOBN(0xba1700f6, 0xbf926dff), TOBN(0x7c9fdbd1, 0xf4bf6bc2),
++     TOBN(0xdc18dc8f, 0x64da11f5), TOBN(0xa6074b7a, 0xd938ae75),
++     TOBN(0x14270066, 0xe84f44a4), TOBN(0x99998d38, 0xd27b954e),
++     TOBN(0xc1be8ab2, 0xb4f38e9a), TOBN(0x8bb55bbf, 0x15c01016),
++     TOBN(0xf73472b4, 0x0ea2ab30), TOBN(0xd365a340, 0xf73d68dd),
++     TOBN(0xc01a7168, 0x19c2e1eb), TOBN(0x32f49e37, 0x34061719),
++     TOBN(0xb73c57f1, 0x01d8b4d6), TOBN(0x03c8423c, 0x26b47700),
++     TOBN(0x321d0bc8, 0xa4d8826a), TOBN(0x6004213c, 0x4bc0e638),
++     TOBN(0xf78c64a1, 0xc1c06681), TOBN(0x16e0a16f, 0xef018e50),
++     TOBN(0x31cbdf91, 0xdb42b2b3), TOBN(0xf8f4ffce, 0xe0d36f58),
++     TOBN(0xcdcc71cd, 0x4cc5e3e0), TOBN(0xd55c7cfa, 0xa129e3e0),
++     TOBN(0xccdb6ba0, 0x0fb2cbf1), TOBN(0x6aba0005, 0xc4bce3cb),
++     TOBN(0x501cdb30, 0xd232cfc4), TOBN(0x9ddcf12e, 0xd58a3cef),
++     TOBN(0x02d2cf9c, 0x87e09149), TOBN(0xdc5d7ec7, 0x2c976257),
++     TOBN(0x6447986e, 0x0b50d7dd), TOBN(0x88fdbaf7, 0x807f112a),
++     TOBN(0x58c9822a, 0xb00ae9f6), TOBN(0x6abfb950, 0x6d3d27e0),
++     TOBN(0xd0a74487, 0x8a429f4f), TOBN(0x0649712b, 0xdb516609),
++     TOBN(0xb826ba57, 0xe769b5df), TOBN(0x82335df2, 0x1fc7aaf2),
++     TOBN(0x2389f067, 0x5c93d995), TOBN(0x59ac367a, 0x68677be6),
++     TOBN(0xa77985ff, 0x21d9951b), TOBN(0x038956fb, 0x85011cce),
++     TOBN(0x608e48cb, 0xbb734e37), TOBN(0xc08c0bf2, 0x2be5b26f),
++     TOBN(0x17bbdd3b, 0xf9b1a0d9), TOBN(0xeac7d898, 0x10483319),
++     TOBN(0xc95c4baf, 0xbc1a6dea), TOBN(0xfdd0e2bf, 0x172aafdb),
++     TOBN(0x40373cbc, 0x8235c41a), TOBN(0x14303f21, 0xfb6f41d5),
++     TOBN(0xba063621, 0x0408f237), TOBN(0xcad3b09a, 0xecd2d1ed),
++     TOBN(0x4667855a, 0x52abb6a2), TOBN(0xba9157dc, 0xaa8b417b),
++     TOBN(0xfe7f3507, 0x4f013efb), TOBN(0x1b112c4b, 0xaa38c4a2),
++     TOBN(0xa1406a60, 0x9ba64345), TOBN(0xe53cba33, 0x6993c80b),
++     TOBN(0x45466063, 0xded40d23), TOBN(0x3d5f1f4d, 0x54908e25),
++     TOBN(0x9ebefe62, 0x403c3c31), TOBN(0x274ea0b5, 0x0672a624),
++     TOBN(0xff818d99, 0x451d1b71), TOBN(0x80e82643, 0x8f79cf79),
++     TOBN(0xa165df13, 0x73ce37f5), TOBN(0xa744ef4f, 0xfe3a21fd),
++     TOBN(0x73f1e7f5, 0xcf551396), TOBN(0xc616898e, 0x868c676b),
++     TOBN(0x671c28c7, 0x8c442c36), TOBN(0xcfe5e558, 0x5e0a317d),
++     TOBN(0x1242d818, 0x7051f476), TOBN(0x56fad2a6, 0x14f03442),
++     TOBN(0x262068bc, 0x0a44d0f6), TOBN(0xdfa2cd6e, 0xce6edf4e),
++     TOBN(0x0f43813a, 0xd15d1517), TOBN(0x61214cb2, 0x377d44f5),
++     TOBN(0xd399aa29, 0xc639b35f), TOBN(0x42136d71, 0x54c51c19),
++     TOBN(0x9774711b, 0x08417221), TOBN(0x0a5546b3, 0x52545a57),
++     TOBN(0x80624c41, 0x1150582d), TOBN(0x9ec5c418, 0xfbc555bc),
++     TOBN(0x2c87dcad, 0x771849f1), TOBN(0xb0c932c5, 0x01d7bf6f),
++     TOBN(0x6aa5cd3e, 0x89116eb2), TOBN(0xd378c25a, 0x51ca7bd3),
++     TOBN(0xc612a0da, 0x9e6e3e31), TOBN(0x0417a54d, 0xb68ad5d0),
++     TOBN(0x00451e4a, 0x22c6edb8), TOBN(0x9fbfe019, 0xb42827ce),
++     TOBN(0x2fa92505, 0xba9384a2), TOBN(0x21b8596e, 0x64ad69c1),
++     TOBN(0x8f4fcc49, 0x983b35a6), TOBN(0xde093760, 0x72754672),
++     TOBN(0x2f14ccc8, 0xf7bffe6d), TOBN(0x27566bff, 0x5d94263d),
++     TOBN(0xb5b4e9c6, 0x2df3ec30), TOBN(0x94f1d7d5, 0x3e6ea6ba),
++     TOBN(0x97b7851a, 0xaaca5e9b), TOBN(0x518aa521, 0x56713b97),
++     TOBN(0x3357e8c7, 0x150a61f6), TOBN(0x7842e7e2, 0xec2c2b69),
++     TOBN(0x8dffaf65, 0x6868a548), TOBN(0xd963bd82, 0xe068fc81),
++     TOBN(0x64da5c8b, 0x65917733), TOBN(0x927090ff, 0x7b247328),}
++    ,
++    {TOBN(0x214bc9a7, 0xd298c241), TOBN(0xe3b697ba, 0x56807cfd),
++     TOBN(0xef1c7802, 0x4564eadb), TOBN(0xdde8cdcf, 0xb48149c5),
++     TOBN(0x946bf0a7, 0x5a4d2604), TOBN(0x27154d7f, 0x6c1538af),
++     TOBN(0x95cc9230, 0xde5b1fcc), TOBN(0xd88519e9, 0x66864f82),
++     TOBN(0xb828dd1a, 0x7cb1282c), TOBN(0xa08d7626, 0xbe46973a),
++     TOBN(0x6baf8d40, 0xe708d6b2), TOBN(0x72571fa1, 0x4daeb3f3),
++     TOBN(0x85b1732f, 0xf22dfd98), TOBN(0x87ab01a7, 0x0087108d),
++     TOBN(0xaaaafea8, 0x5988207a), TOBN(0xccc832f8, 0x69f00755),
++     TOBN(0x964d950e, 0x36ff3bf0), TOBN(0x8ad20f6f, 0xf0b34638),
++     TOBN(0x4d9177b3, 0xb5d7585f), TOBN(0xcf839760, 0xef3f019f),
++     TOBN(0x582fc5b3, 0x8288c545), TOBN(0x2f8e4e9b, 0x13116bd1),
++     TOBN(0xf91e1b2f, 0x332120ef), TOBN(0xcf568724, 0x2a17dd23),
++     TOBN(0x488f1185, 0xca8d9d1a), TOBN(0xadf2c77d, 0xd987ded2),
++     TOBN(0x5f3039f0, 0x60c46124), TOBN(0xe5d70b75, 0x71e095f4),
++     TOBN(0x82d58650, 0x6260e70f), TOBN(0x39d75ea7, 0xf750d105),
++     TOBN(0x8cf3d0b1, 0x75bac364), TOBN(0xf3a7564d, 0x21d01329),
++     TOBN(0x182f04cd, 0x2f52d2a7), TOBN(0x4fde149a, 0xe2df565a),
++     TOBN(0xb80c5eec, 0xa79fb2f7), TOBN(0xab491d7b, 0x22ddc897),
++     TOBN(0x99d76c18, 0xc6312c7f), TOBN(0xca0d5f3d, 0x6aa41a57),
++     TOBN(0x71207325, 0xd15363a0), TOBN(0xe82aa265, 0xbeb252c2),
++     TOBN(0x94ab4700, 0xec3128c2), TOBN(0x6c76d862, 0x8e383f49),
++     TOBN(0xdc36b150, 0xc03024eb), TOBN(0xfb439477, 0x53daac69),
++     TOBN(0xfc68764a, 0x8dc79623), TOBN(0x5b86995d, 0xb440fbb2),
++     TOBN(0xd66879bf, 0xccc5ee0d), TOBN(0x05228942, 0x95aa8bd3),
++     TOBN(0xb51a40a5, 0x1e6a75c1), TOBN(0x24327c76, 0x0ea7d817),
++     TOBN(0x06630182, 0x07774597), TOBN(0xd6fdbec3, 0x97fa7164),
++     TOBN(0x20c99dfb, 0x13c90f48), TOBN(0xd6ac5273, 0x686ef263),
++     TOBN(0xc6a50bdc, 0xfef64eeb), TOBN(0xcd87b281, 0x86fdfc32),
++     TOBN(0xb24aa43e, 0x3fcd3efc), TOBN(0xdd26c034, 0xb8088e9a),
++     TOBN(0xa5ef4dc9, 0xbd3d46ea), TOBN(0xa2f99d58, 0x8a4c6a6f),
++     TOBN(0xddabd355, 0x2f1da46c), TOBN(0x72c3f8ce, 0x1afacdd1),
++     TOBN(0xd90c4eee, 0x92d40578), TOBN(0xd28bb41f, 0xca623b94),
++     TOBN(0x50fc0711, 0x745edc11), TOBN(0x9dd9ad7d, 0x3dc87558),
++     TOBN(0xce6931fb, 0xb49d1e64), TOBN(0x6c77a0a2, 0xc98bd0f9),
++     TOBN(0x62b9a629, 0x6baf7cb1), TOBN(0xcf065f91, 0xccf72d22),
++     TOBN(0x7203cce9, 0x79639071), TOBN(0x09ae4885, 0xf9cb732f),
++     TOBN(0x5e7c3bec, 0xee8314f3), TOBN(0x1c068aed, 0xdbea298f),
++     TOBN(0x08d381f1, 0x7c80acec), TOBN(0x03b56be8, 0xe330495b),
++     TOBN(0xaeffb8f2, 0x9222882d), TOBN(0x95ff38f6, 0xc4af8bf7),
++     TOBN(0x50e32d35, 0x1fc57d8c), TOBN(0x6635be52, 0x17b444f0),
++     TOBN(0x04d15276, 0xa5177900), TOBN(0x4e1dbb47, 0xf6858752),
++     TOBN(0x5b475622, 0xc615796c), TOBN(0xa6fa0387, 0x691867bf),
++     TOBN(0xed7f5d56, 0x2844c6d0), TOBN(0xc633cf9b, 0x03a2477d),
++     TOBN(0xf6be5c40, 0x2d3721d6), TOBN(0xaf312eb7, 0xe9fd68e6),
++     TOBN(0x242792d2, 0xe7417ce1), TOBN(0xff42bc71, 0x970ee7f5),
++     TOBN(0x1ff4dc6d, 0x5c67a41e), TOBN(0x77709b7b, 0x20882a58),
++     TOBN(0x3554731d, 0xbe217f2c), TOBN(0x2af2a8cd, 0x5bb72177),
++     TOBN(0x58eee769, 0x591dd059), TOBN(0xbb2930c9, 0x4bba6477),
++     TOBN(0x863ee047, 0x7d930cfc), TOBN(0x4c262ad1, 0x396fd1f4),
++     TOBN(0xf4765bc8, 0x039af7e1), TOBN(0x2519834b, 0x5ba104f6),
++     TOBN(0x7cd61b4c, 0xd105f961), TOBN(0xa5415da5, 0xd63bca54),
++     TOBN(0x778280a0, 0x88a1f17c), TOBN(0xc4968949, 0x2329512c),
++     TOBN(0x174a9126, 0xcecdaa7a), TOBN(0xfc8c7e0e, 0x0b13247b),
++     TOBN(0x29c110d2, 0x3484c1c4), TOBN(0xf8eb8757, 0x831dfc3b),
++     TOBN(0x022f0212, 0xc0067452), TOBN(0x3f6f69ee, 0x7b9b926c),
++     TOBN(0x09032da0, 0xef42daf4), TOBN(0x79f00ade, 0x83f80de4),
++     TOBN(0x6210db71, 0x81236c97), TOBN(0x74f7685b, 0x3ee0781f),
++     TOBN(0x4df7da7b, 0xa3e41372), TOBN(0x2aae38b1, 0xb1a1553e),
++     TOBN(0x1688e222, 0xf6dd9d1b), TOBN(0x57695448, 0x5b8b6487),
++     TOBN(0x478d2127, 0x4b2edeaa), TOBN(0xb2818fa5, 0x1e85956a),
++     TOBN(0x1e6addda, 0xf176f2c0), TOBN(0x01ca4604, 0xe2572658),
++     TOBN(0x0a404ded, 0x85342ffb), TOBN(0x8cf60f96, 0x441838d6),
++     TOBN(0x9bbc691c, 0xc9071c4a), TOBN(0xfd588744, 0x34442803),
++     TOBN(0x97101c85, 0x809c0d81), TOBN(0xa7fb754c, 0x8c456f7f),
++     TOBN(0xc95f3c5c, 0xd51805e1), TOBN(0xab4ccd39, 0xb299dca8),
++     TOBN(0x3e03d20b, 0x47eaf500), TOBN(0xfa3165c1, 0xd7b80893),
++     TOBN(0x005e8b54, 0xe160e552), TOBN(0xdc4972ba, 0x9019d11f),
++     TOBN(0x21a6972e, 0x0c9a4a7a), TOBN(0xa52c258f, 0x37840fd7),
++     TOBN(0xf8559ff4, 0xc1e99d81), TOBN(0x08e1a7d6, 0xa3c617c0),
++     TOBN(0xb398fd43, 0x248c6ba7), TOBN(0x6ffedd91, 0xd1283794),
++     TOBN(0x8a6a59d2, 0xd629d208), TOBN(0xa9d141d5, 0x3490530e),
++     TOBN(0x42f6fc18, 0x38505989), TOBN(0x09bf250d, 0x479d94ee),
++     TOBN(0x223ad3b1, 0xb3822790), TOBN(0x6c5926c0, 0x93b8971c),
++     TOBN(0x609efc7e, 0x75f7fa62), TOBN(0x45d66a6d, 0x1ec2d989),
++     TOBN(0x4422d663, 0x987d2792), TOBN(0x4a73caad, 0x3eb31d2b),
++     TOBN(0xf06c2ac1, 0xa32cb9e6), TOBN(0xd9445c5f, 0x91aeba84),
++     TOBN(0x6af7a1d5, 0xaf71013f), TOBN(0xe68216e5, 0x0bedc946),
++     TOBN(0xf4cba30b, 0xd27370a0), TOBN(0x7981afbf, 0x870421cc),
++     TOBN(0x02496a67, 0x9449f0e1), TOBN(0x86cfc4be, 0x0a47edae),
++     TOBN(0x3073c936, 0xb1feca22), TOBN(0xf5694612, 0x03f8f8fb),
++     TOBN(0xd063b723, 0x901515ea), TOBN(0x4c6c77a5, 0x749cf038),
++     TOBN(0x6361e360, 0xab9e5059), TOBN(0x596cf171, 0xa76a37c0),
++     TOBN(0x800f53fa, 0x6530ae7a), TOBN(0x0f5e631e, 0x0792a7a6),
++     TOBN(0x5cc29c24, 0xefdb81c9), TOBN(0xa269e868, 0x3f9c40ba),
++     TOBN(0xec14f9e1, 0x2cb7191e), TOBN(0x78ea1bd8, 0xe5b08ea6),
++     TOBN(0x3c65aa9b, 0x46332bb9), TOBN(0x84cc22b3, 0xbf80ce25),
++     TOBN(0x0098e9e9, 0xd49d5bf1), TOBN(0xcd4ec1c6, 0x19087da4),
++     TOBN(0x3c9d07c5, 0xaef6e357), TOBN(0x839a0268, 0x9f8f64b8),
++     TOBN(0xc5e9eb62, 0xc6d8607f), TOBN(0x759689f5, 0x6aa995e4),
++     TOBN(0x70464669, 0xbbb48317), TOBN(0x921474bf, 0xe402417d),
++     TOBN(0xcabe135b, 0x2a354c8c), TOBN(0xd51e52d2, 0x812fa4b5),
++     TOBN(0xec741096, 0x53311fe8), TOBN(0x4f774535, 0xb864514b),
++     TOBN(0xbcadd671, 0x5bde48f8), TOBN(0xc9703873, 0x2189bc7d),
++     TOBN(0x5d45299e, 0xc709ee8a), TOBN(0xd1287ee2, 0x845aaff8),
++     TOBN(0x7d1f8874, 0xdb1dbf1f), TOBN(0xea46588b, 0x990c88d6),
++     TOBN(0x60ba649a, 0x84368313), TOBN(0xd5fdcbce, 0x60d543ae),
++     TOBN(0x90b46d43, 0x810d5ab0), TOBN(0x6739d8f9, 0x04d7e5cc),
++     TOBN(0x021c1a58, 0x0d337c33), TOBN(0x00a61162, 0x68e67c40),
++     TOBN(0x95ef413b, 0x379f0a1f), TOBN(0xfe126605, 0xe9e2ab95),
++     TOBN(0x67578b85, 0x2f5f199c), TOBN(0xf5c00329, 0x2cb84913),
++     TOBN(0xf7956430, 0x37577dd8), TOBN(0x83b82af4, 0x29c5fe88),
++     TOBN(0x9c1bea26, 0xcdbdc132), TOBN(0x589fa086, 0x9c04339e),
++     TOBN(0x033e9538, 0xb13799df), TOBN(0x85fa8b21, 0xd295d034),
++     TOBN(0xdf17f73f, 0xbd9ddcca), TOBN(0xf32bd122, 0xddb66334),
++     TOBN(0x55ef88a7, 0x858b044c), TOBN(0x1f0d69c2, 0x5aa9e397),
++     TOBN(0x55fd9cc3, 0x40d85559), TOBN(0xc774df72, 0x7785ddb2),
++     TOBN(0x5dcce9f6, 0xd3bd2e1c), TOBN(0xeb30da20, 0xa85dfed0),
++     TOBN(0x5ed7f5bb, 0xd3ed09c4), TOBN(0x7d42a35c, 0x82a9c1bd),
++     TOBN(0xcf3de995, 0x9890272d), TOBN(0x75f3432a, 0x3e713a10),
++     TOBN(0x5e13479f, 0xe28227b8), TOBN(0xb8561ea9, 0xfefacdc8),
++     TOBN(0xa6a297a0, 0x8332aafd), TOBN(0x9b0d8bb5, 0x73809b62),
++     TOBN(0xd2fa1cfd, 0x0c63036f), TOBN(0x7a16eb55, 0xbd64bda8),
++     TOBN(0x3f5cf5f6, 0x78e62ddc), TOBN(0x2267c454, 0x07fd752b),
++     TOBN(0x5e361b6b, 0x5e437bbe), TOBN(0x95c59501, 0x8354e075),
++     TOBN(0xec725f85, 0xf2b254d9), TOBN(0x844b617d, 0x2cb52b4e),
++     TOBN(0xed8554f5, 0xcf425fb5), TOBN(0xab67703e, 0x2af9f312),
++     TOBN(0x4cc34ec1, 0x3cf48283), TOBN(0xb09daa25, 0x9c8a705e),
++     TOBN(0xd1e9d0d0, 0x5b7d4f84), TOBN(0x4df6ef64, 0xdb38929d),
++     TOBN(0xe16b0763, 0xaa21ba46), TOBN(0xc6b1d178, 0xa293f8fb),
++     TOBN(0x0ff5b602, 0xd520aabf), TOBN(0x94d671bd, 0xc339397a),
++     TOBN(0x7c7d98cf, 0x4f5792fa), TOBN(0x7c5e0d67, 0x11215261),
++     TOBN(0x9b19a631, 0xa7c5a6d4), TOBN(0xc8511a62, 0x7a45274d),
++     TOBN(0x0c16621c, 0xa5a60d99), TOBN(0xf7fbab88, 0xcf5e48cb),
++     TOBN(0xab1e6ca2, 0xf7ddee08), TOBN(0x83bd08ce, 0xe7867f3c),
++     TOBN(0xf7e48e8a, 0x2ac13e27), TOBN(0x4494f6df, 0x4eb1a9f5),
++     TOBN(0xedbf84eb, 0x981f0a62), TOBN(0x49badc32, 0x536438f0),
++     TOBN(0x50bea541, 0x004f7571), TOBN(0xbac67d10, 0xdf1c94ee),
++     TOBN(0x253d73a1, 0xb727bc31), TOBN(0xb3d01cf2, 0x30686e28),
++     TOBN(0x51b77b1b, 0x55fd0b8b), TOBN(0xa099d183, 0xfeec3173),
++     TOBN(0x202b1fb7, 0x670e72b7), TOBN(0xadc88b33, 0xa8e1635f),
++     TOBN(0x34e8216a, 0xf989d905), TOBN(0xc2e68d20, 0x29b58d01),
++     TOBN(0x11f81c92, 0x6fe55a93), TOBN(0x15f1462a, 0x8f296f40),
++     TOBN(0x1915d375, 0xea3d62f2), TOBN(0xa17765a3, 0x01c8977d),
++     TOBN(0x7559710a, 0xe47b26f6), TOBN(0xe0bd29c8, 0x535077a5),
++     TOBN(0x615f976d, 0x08d84858), TOBN(0x370dfe85, 0x69ced5c1),
++     TOBN(0xbbc7503c, 0xa734fa56), TOBN(0xfbb9f1ec, 0x91ac4574),
++     TOBN(0x95d7ec53, 0x060dd7ef), TOBN(0xeef2dacd, 0x6e657979),
++     TOBN(0x54511af3, 0xe2a08235), TOBN(0x1e324aa4, 0x1f4aea3d),
++     TOBN(0x550e7e71, 0xe6e67671), TOBN(0xbccd5190, 0xbf52faf7),
++     TOBN(0xf880d316, 0x223cc62a), TOBN(0x0d402c7e, 0x2b32eb5d),
++     TOBN(0xa40bc039, 0x306a5a3b), TOBN(0x4e0a41fd, 0x96783a1b),
++     TOBN(0xa1e8d39a, 0x0253cdd4), TOBN(0x6480be26, 0xc7388638),
++     TOBN(0xee365e1d, 0x2285f382), TOBN(0x188d8d8f, 0xec0b5c36),
++     TOBN(0x34ef1a48, 0x1f0f4d82), TOBN(0x1a8f43e1, 0xa487d29a),
++     TOBN(0x8168226d, 0x77aefb3a), TOBN(0xf69a751e, 0x1e72c253),
++     TOBN(0x8e04359a, 0xe9594df1), TOBN(0x475ffd7d, 0xd14c0467),
++     TOBN(0xb5a2c2b1, 0x3844e95c), TOBN(0x85caf647, 0xdd12ef94),
++     TOBN(0x1ecd2a9f, 0xf1063d00), TOBN(0x1dd2e229, 0x23843311),
++     TOBN(0x38f0e09d, 0x73d17244), TOBN(0x3ede7746, 0x8fc653f1),
++     TOBN(0xae4459f5, 0xdc20e21c), TOBN(0x00db2ffa, 0x6a8599ea),
++     TOBN(0x11682c39, 0x30cfd905), TOBN(0x4934d074, 0xa5c112a6),
++     TOBN(0xbdf063c5, 0x568bfe95), TOBN(0x779a440a, 0x016c441a),
++     TOBN(0x0c23f218, 0x97d6fbdc), TOBN(0xd3a5cd87, 0xe0776aac),
++     TOBN(0xcee37f72, 0xd712e8db), TOBN(0xfb28c70d, 0x26f74e8d),
++     TOBN(0xffe0c728, 0xb61301a0), TOBN(0xa6282168, 0xd3724354),
++     TOBN(0x7ff4cb00, 0x768ffedc), TOBN(0xc51b3088, 0x03b02de9),
++     TOBN(0xa5a8147c, 0x3902dda5), TOBN(0x35d2f706, 0xfe6973b4),
++     TOBN(0x5ac2efcf, 0xc257457e), TOBN(0x933f48d4, 0x8700611b),
++     TOBN(0xc365af88, 0x4912beb2), TOBN(0x7f5a4de6, 0x162edf94),
++     TOBN(0xc646ba7c, 0x0c32f34b), TOBN(0x632c6af3, 0xb2091074),
++     TOBN(0x58d4f2e3, 0x753e43a9), TOBN(0x70e1d217, 0x24d4e23f),
++     TOBN(0xb24bf729, 0xafede6a6), TOBN(0x7f4a94d8, 0x710c8b60),
++     TOBN(0xaad90a96, 0x8d4faa6a), TOBN(0xd9ed0b32, 0xb066b690),
++     TOBN(0x52fcd37b, 0x78b6dbfd), TOBN(0x0b64615e, 0x8bd2b431),
++     TOBN(0x228e2048, 0xcfb9fad5), TOBN(0xbeaa386d, 0x240b76bd),
++     TOBN(0x2d6681c8, 0x90dad7bc), TOBN(0x3e553fc3, 0x06d38f5e),
++     TOBN(0xf27cdb9b, 0x9d5f9750), TOBN(0x3e85c52a, 0xd28c5b0e),
++     TOBN(0x190795af, 0x5247c39b), TOBN(0x547831eb, 0xbddd6828),
++     TOBN(0xf327a227, 0x4a82f424), TOBN(0x36919c78, 0x7e47f89d),
++     TOBN(0xe4783919, 0x43c7392c), TOBN(0xf101b9aa, 0x2316fefe),
++     TOBN(0xbcdc9e9c, 0x1c5009d2), TOBN(0xfb55ea13, 0x9cd18345),
++     TOBN(0xf5b5e231, 0xa3ce77c7), TOBN(0xde6b4527, 0xd2f2cb3d),
++     TOBN(0x10f6a333, 0x9bb26f5f), TOBN(0x1e85db8e, 0x044d85b6),
++     TOBN(0xc3697a08, 0x94197e54), TOBN(0x65e18cc0, 0xa7cb4ea8),
++     TOBN(0xa38c4f50, 0xa471fe6e), TOBN(0xf031747a, 0x2f13439c),
++     TOBN(0x53c4a6ba, 0xc007318b), TOBN(0xa8da3ee5, 0x1deccb3d),
++     TOBN(0x0555b31c, 0x558216b1), TOBN(0x90c7810c, 0x2f79e6c2),
++     TOBN(0x9b669f4d, 0xfe8eed3c), TOBN(0x70398ec8, 0xe0fac126),
++     TOBN(0xa96a449e, 0xf701b235), TOBN(0x0ceecdb3, 0xeb94f395),
++     TOBN(0x285fc368, 0xd0cb7431), TOBN(0x0d37bb52, 0x16a18c64),
++     TOBN(0x05110d38, 0xb880d2dd), TOBN(0xa60f177b, 0x65930d57),
++     TOBN(0x7da34a67, 0xf36235f5), TOBN(0x47f5e17c, 0x183816b9),
++     TOBN(0xc7664b57, 0xdb394af4), TOBN(0x39ba215d, 0x7036f789),
++     TOBN(0x46d2ca0e, 0x2f27b472), TOBN(0xc42647ee, 0xf73a84b7),
++     TOBN(0x44bc7545, 0x64488f1d), TOBN(0xaa922708, 0xf4cf85d5),
++     TOBN(0x721a01d5, 0x53e4df63), TOBN(0x649c0c51, 0x5db46ced),
++     TOBN(0x6bf0d64e, 0x3cffcb6c), TOBN(0xe3bf93fe, 0x50f71d96),
++     TOBN(0x75044558, 0xbcc194a0), TOBN(0x16ae3372, 0x6afdc554),
++     TOBN(0xbfc01adf, 0x5ca48f3f), TOBN(0x64352f06, 0xe22a9b84),
++     TOBN(0xcee54da1, 0xc1099e4a), TOBN(0xbbda54e8, 0xfa1b89c0),
++     TOBN(0x166a3df5, 0x6f6e55fb), TOBN(0x1ca44a24, 0x20176f88),
++     TOBN(0x936afd88, 0xdfb7b5ff), TOBN(0xe34c2437, 0x8611d4a0),
++     TOBN(0x7effbb75, 0x86142103), TOBN(0x6704ba1b, 0x1f34fc4d),
++     TOBN(0x7c2a468f, 0x10c1b122), TOBN(0x36b3a610, 0x8c6aace9),
++     TOBN(0xabfcc0a7, 0x75a0d050), TOBN(0x066f9197, 0x3ce33e32),
++     TOBN(0xce905ef4, 0x29fe09be), TOBN(0x89ee25ba, 0xa8376351),
++     TOBN(0x2a3ede22, 0xfd29dc76), TOBN(0x7fd32ed9, 0x36f17260),
++     TOBN(0x0cadcf68, 0x284b4126), TOBN(0x63422f08, 0xa7951fc8),
++     TOBN(0x562b24f4, 0x0807e199), TOBN(0xfe9ce5d1, 0x22ad4490),
++     TOBN(0xc2f51b10, 0x0db2b1b4), TOBN(0xeb3613ff, 0xe4541d0d),
++     TOBN(0xbd2c4a05, 0x2680813b), TOBN(0x527aa55d, 0x561b08d6),
++     TOBN(0xa9f8a40e, 0xa7205558), TOBN(0xe3eea56f, 0x243d0bec),
++     TOBN(0x7b853817, 0xa0ff58b3), TOBN(0xb67d3f65, 0x1a69e627),
++     TOBN(0x0b76bbb9, 0xa869b5d6), TOBN(0xa3afeb82, 0x546723ed),
++     TOBN(0x5f24416d, 0x3e554892), TOBN(0x8413b53d, 0x430e2a45),
++     TOBN(0x99c56aee, 0x9032a2a0), TOBN(0x09432bf6, 0xeec367b1),
++     TOBN(0x552850c6, 0xdaf0ecc1), TOBN(0x49ebce55, 0x5bc92048),
++     TOBN(0xdfb66ba6, 0x54811307), TOBN(0x1b84f797, 0x6f298597),
++     TOBN(0x79590481, 0x8d1d7a0d), TOBN(0xd9fabe03, 0x3a6fa556),
++     TOBN(0xa40f9c59, 0xba9e5d35), TOBN(0xcb1771c1, 0xf6247577),
++     TOBN(0x542a47ca, 0xe9a6312b), TOBN(0xa34b3560, 0x552dd8c5),
++     TOBN(0xfdf94de0, 0x0d794716), TOBN(0xd46124a9, 0x9c623094),
++     TOBN(0x56b7435d, 0x68afe8b4), TOBN(0x27f20540, 0x6c0d8ea1),
++     TOBN(0x12b77e14, 0x73186898), TOBN(0xdbc3dd46, 0x7479490f),
++     TOBN(0x951a9842, 0xc03b0c05), TOBN(0x8b1b3bb3, 0x7921bc96),
++     TOBN(0xa573b346, 0x2b202e0a), TOBN(0x77e4665d, 0x47254d56),
++     TOBN(0x08b70dfc, 0xd23e3984), TOBN(0xab86e8bc, 0xebd14236),
++     TOBN(0xaa3e07f8, 0x57114ba7), TOBN(0x5ac71689, 0xab0ef4f2),
++     TOBN(0x88fca384, 0x0139d9af), TOBN(0x72733f88, 0x76644af0),
++     TOBN(0xf122f72a, 0x65d74f4a), TOBN(0x13931577, 0xa5626c7a),
++     TOBN(0xd5b5d9eb, 0x70f8d5a4), TOBN(0x375adde7, 0xd7bbb228),
++     TOBN(0x31e88b86, 0x0c1c0b32), TOBN(0xd1f568c4, 0x173edbaa),
++     TOBN(0x1592fc83, 0x5459df02), TOBN(0x2beac0fb, 0x0fcd9a7e),
++     TOBN(0xb0a6fdb8, 0x1b473b0a), TOBN(0xe3224c6f, 0x0fe8fc48),
++     TOBN(0x680bd00e, 0xe87edf5b), TOBN(0x30385f02, 0x20e77cf5),
++     TOBN(0xe9ab98c0, 0x4d42d1b2), TOBN(0x72d191d2, 0xd3816d77),
++     TOBN(0x1564daca, 0x0917d9e5), TOBN(0x394eab59, 0x1f8fed7f),
++     TOBN(0xa209aa8d, 0x7fbb3896), TOBN(0x5564f3b9, 0xbe6ac98e),
++     TOBN(0xead21d05, 0xd73654ef), TOBN(0x68d1a9c4, 0x13d78d74),
++     TOBN(0x61e01708, 0x6d4973a0), TOBN(0x83da3500, 0x46e6d32a),
++     TOBN(0x6a3dfca4, 0x68ae0118), TOBN(0xa1b9a4c9, 0xd02da069),
++     TOBN(0x0b2ff9c7, 0xebab8302), TOBN(0x98af07c3, 0x944ba436),
++     TOBN(0x85997326, 0x995f0f9f), TOBN(0x467fade0, 0x71b58bc6),
++     TOBN(0x47e4495a, 0xbd625a2b), TOBN(0xfdd2d01d, 0x33c3b8cd),
++     TOBN(0x2c38ae28, 0xc693f9fa), TOBN(0x48622329, 0x348f7999),
++     TOBN(0x97bf738e, 0x2161f583), TOBN(0x15ee2fa7, 0x565e8cc9),
++     TOBN(0xa1a5c845, 0x5777e189), TOBN(0xcc10bee0, 0x456f2829),
++     TOBN(0x8ad95c56, 0xda762bd5), TOBN(0x152e2214, 0xe9d91da8),
++     TOBN(0x975b0e72, 0x7cb23c74), TOBN(0xfd5d7670, 0xa90c66df),
++     TOBN(0xb5b5b8ad, 0x225ffc53), TOBN(0xab6dff73, 0xfaded2ae),
++     TOBN(0xebd56781, 0x6f4cbe9d), TOBN(0x0ed8b249, 0x6a574bd7),
++     TOBN(0x41c246fe, 0x81a881fa), TOBN(0x91564805, 0xc3db9c70),
++     TOBN(0xd7c12b08, 0x5b862809), TOBN(0x1facd1f1, 0x55858d7b),
++     TOBN(0x7693747c, 0xaf09e92a), TOBN(0x3b69dcba, 0x189a425f),
++     TOBN(0x0be28e9f, 0x967365ef), TOBN(0x57300eb2, 0xe801f5c9),
++     TOBN(0x93b8ac6a, 0xd583352f), TOBN(0xa2cf1f89, 0xcd05b2b7),
++     TOBN(0x7c0c9b74, 0x4dcc40cc), TOBN(0xfee38c45, 0xada523fb),
++     TOBN(0xb49a4dec, 0x1099cc4d), TOBN(0x325c377f, 0x69f069c6),
++     TOBN(0xe12458ce, 0x476cc9ff), TOBN(0x580e0b6c, 0xc6d4cb63),
++     TOBN(0xd561c8b7, 0x9072289b), TOBN(0x0377f264, 0xa619e6da),
++     TOBN(0x26685362, 0x88e591a5), TOBN(0xa453a7bd, 0x7523ca2b),
++     TOBN(0x8a9536d2, 0xc1df4533), TOBN(0xc8e50f2f, 0xbe972f79),
++     TOBN(0xd433e50f, 0x6d3549cf), TOBN(0x6f33696f, 0xfacd665e),
++     TOBN(0x695bfdac, 0xce11fcb4), TOBN(0x810ee252, 0xaf7c9860),
++     TOBN(0x65450fe1, 0x7159bb2c), TOBN(0xf7dfbebe, 0x758b357b),
++     TOBN(0x2b057e74, 0xd69fea72), TOBN(0xd485717a, 0x92731745),}
++    ,
++    {TOBN(0x896c42e8, 0xee36860c), TOBN(0xdaf04dfd, 0x4113c22d),
++     TOBN(0x1adbb7b7, 0x44104213), TOBN(0xe5fd5fa1, 0x1fd394ea),
++     TOBN(0x68235d94, 0x1a4e0551), TOBN(0x6772cfbe, 0x18d10151),
++     TOBN(0x276071e3, 0x09984523), TOBN(0xe4e879de, 0x5a56ba98),
++     TOBN(0xaaafafb0, 0x285b9491), TOBN(0x01a0be88, 0x1e4c705e),
++     TOBN(0xff1d4f5d, 0x2ad9caab), TOBN(0x6e349a4a, 0xc37a233f),
++     TOBN(0xcf1c1246, 0x4a1c6a16), TOBN(0xd99e6b66, 0x29383260),
++     TOBN(0xea3d4366, 0x5f6d5471), TOBN(0x36974d04, 0xff8cc89b),
++     TOBN(0xc26c49a1, 0xcfe89d80), TOBN(0xb42c026d, 0xda9c8371),
++     TOBN(0xca6c013a, 0xdad066d2), TOBN(0xfb8f7228, 0x56a4f3ee),
++     TOBN(0x08b579ec, 0xd850935b), TOBN(0x34c1a74c, 0xd631e1b3),
++     TOBN(0xcb5fe596, 0xac198534), TOBN(0x39ff21f6, 0xe1f24f25),
++     TOBN(0x27f29e14, 0x8f929057), TOBN(0x7a64ae06, 0xc0c853df),
++     TOBN(0x256cd183, 0x58e9c5ce), TOBN(0x9d9cce82, 0xded092a5),
++     TOBN(0xcc6e5979, 0x6e93b7c7), TOBN(0xe1e47092, 0x31bb9e27),
++     TOBN(0xb70b3083, 0xaa9e29a0), TOBN(0xbf181a75, 0x3785e644),
++     TOBN(0xf53f2c65, 0x8ead09f7), TOBN(0x1335e1d5, 0x9780d14d),
++     TOBN(0x69cc20e0, 0xcd1b66bc), TOBN(0x9b670a37, 0xbbe0bfc8),
++     TOBN(0xce53dc81, 0x28efbeed), TOBN(0x0c74e77c, 0x8326a6e5),
++     TOBN(0x3604e0d2, 0xb88e9a63), TOBN(0xbab38fca, 0x13dc2248),
++     TOBN(0x8ed6e8c8, 0x5c0a3f1e), TOBN(0xbcad2492, 0x7c87c37f),
++     TOBN(0xfdfb62bb, 0x9ee3b78d), TOBN(0xeba8e477, 0xcbceba46),
++     TOBN(0x37d38cb0, 0xeeaede4b), TOBN(0x0bc498e8, 0x7976deb6),
++     TOBN(0xb2944c04, 0x6b6147fb), TOBN(0x8b123f35, 0xf71f9609),
++     TOBN(0xa155dcc7, 0xde79dc24), TOBN(0xf1168a32, 0x558f69cd),
++     TOBN(0xbac21595, 0x0d1850df), TOBN(0x15c8295b, 0xb204c848),
++     TOBN(0xf661aa36, 0x7d8184ff), TOBN(0xc396228e, 0x30447bdb),
++     TOBN(0x11cd5143, 0xbde4a59e), TOBN(0xe3a26e3b, 0x6beab5e6),
++     TOBN(0xd3b3a13f, 0x1402b9d0), TOBN(0x573441c3, 0x2c7bc863),
++     TOBN(0x4b301ec4, 0x578c3e6e), TOBN(0xc26fc9c4, 0x0adaf57e),
++     TOBN(0x96e71bfd, 0x7493cea3), TOBN(0xd05d4b3f, 0x1af81456),
++     TOBN(0xdaca2a8a, 0x6a8c608f), TOBN(0x53ef07f6, 0x0725b276),
++     TOBN(0x07a5fbd2, 0x7824fc56), TOBN(0x34675218, 0x13289077),
++     TOBN(0x5bf69fd5, 0xe0c48349), TOBN(0xa613ddd3, 0xb6aa7875),
++     TOBN(0x7f78c19c, 0x5450d866), TOBN(0x46f4409c, 0x8f84a481),
++     TOBN(0x9f1d1928, 0x90fce239), TOBN(0x016c4168, 0xb2ce44b9),
++     TOBN(0xbae023f0, 0xc7435978), TOBN(0xb152c888, 0x20e30e19),
++     TOBN(0x9c241645, 0xe3fa6faf), TOBN(0x735d95c1, 0x84823e60),
++     TOBN(0x03197573, 0x03955317), TOBN(0x0b4b02a9, 0xf03b4995),
++     TOBN(0x076bf559, 0x70274600), TOBN(0x32c5cc53, 0xaaf57508),
++     TOBN(0xe8af6d1f, 0x60624129), TOBN(0xb7bc5d64, 0x9a5e2b5e),
++     TOBN(0x3814b048, 0x5f082d72), TOBN(0x76f267f2, 0xce19677a),
++     TOBN(0x626c630f, 0xb36eed93), TOBN(0x55230cd7, 0x3bf56803),
++     TOBN(0x78837949, 0xce2736a0), TOBN(0x0d792d60, 0xaa6c55f1),
++     TOBN(0x0318dbfd, 0xd5c7c5d2), TOBN(0xb38f8da7, 0x072b342d),
++     TOBN(0x3569bddc, 0x7b8de38a), TOBN(0xf25b5887, 0xa1c94842),
++     TOBN(0xb2d5b284, 0x2946ad60), TOBN(0x854f29ad, 0xe9d1707e),
++     TOBN(0xaa5159dc, 0x2c6a4509), TOBN(0x899f94c0, 0x57189837),
++     TOBN(0xcf6adc51, 0xf4a55b03), TOBN(0x261762de, 0x35e3b2d5),
++     TOBN(0x4cc43012, 0x04827b51), TOBN(0xcd22a113, 0xc6021442),
++     TOBN(0xce2fd61a, 0x247c9569), TOBN(0x59a50973, 0xd152beca),
++     TOBN(0x6c835a11, 0x63a716d4), TOBN(0xc26455ed, 0x187dedcf),
++     TOBN(0x27f536e0, 0x49ce89e7), TOBN(0x18908539, 0xcc890cb5),
++     TOBN(0x308909ab, 0xd83c2aa1), TOBN(0xecd3142b, 0x1ab73bd3),
++     TOBN(0x6a85bf59, 0xb3f5ab84), TOBN(0x3c320a68, 0xf2bea4c6),
++     TOBN(0xad8dc538, 0x6da4541f), TOBN(0xeaf34eb0, 0xb7c41186),
++     TOBN(0x1c780129, 0x977c97c4), TOBN(0x5ff9beeb, 0xc57eb9fa),
++     TOBN(0xa24d0524, 0xc822c478), TOBN(0xfd8eec2a, 0x461cd415),
++     TOBN(0xfbde194e, 0xf027458c), TOBN(0xb4ff5319, 0x1d1be115),
++     TOBN(0x63f874d9, 0x4866d6f4), TOBN(0x35c75015, 0xb21ad0c9),
++     TOBN(0xa6b5c9d6, 0x46ac49d2), TOBN(0x42c77c0b, 0x83137aa9),
++     TOBN(0x24d000fc, 0x68225a38), TOBN(0x0f63cfc8, 0x2fe1e907),
++     TOBN(0x22d1b01b, 0xc6441f95), TOBN(0x7d38f719, 0xec8e448f),
++     TOBN(0x9b33fa5f, 0x787fb1ba), TOBN(0x94dcfda1, 0x190158df),
++     TOBN(0xc47cb339, 0x5f6d4a09), TOBN(0x6b4f355c, 0xee52b826),
++     TOBN(0x3d100f5d, 0xf51b930a), TOBN(0xf4512fac, 0x9f668f69),
++     TOBN(0x546781d5, 0x206c4c74), TOBN(0xd021d4d4, 0xcb4d2e48),
++     TOBN(0x494a54c2, 0xca085c2d), TOBN(0xf1dbaca4, 0x520850a8),
++     TOBN(0x63c79326, 0x490a1aca), TOBN(0xcb64dd9c, 0x41526b02),
++     TOBN(0xbb772591, 0xa2979258), TOBN(0x3f582970, 0x48d97846),
++     TOBN(0xd66b70d1, 0x7c213ba7), TOBN(0xc28febb5, 0xe8a0ced4),
++     TOBN(0x6b911831, 0xc10338c1), TOBN(0x0d54e389, 0xbf0126f3),
++     TOBN(0x7048d460, 0x4af206ee), TOBN(0x786c88f6, 0x77e97cb9),
++     TOBN(0xd4375ae1, 0xac64802e), TOBN(0x469bcfe1, 0xd53ec11c),
++     TOBN(0xfc9b340d, 0x47062230), TOBN(0xe743bb57, 0xc5b4a3ac),
++     TOBN(0xfe00b4aa, 0x59ef45ac), TOBN(0x29a4ef23, 0x59edf188),
++     TOBN(0x40242efe, 0xb483689b), TOBN(0x2575d3f6, 0x513ac262),
++     TOBN(0xf30037c8, 0x0ca6db72), TOBN(0xc9fcce82, 0x98864be2),
++     TOBN(0x84a112ff, 0x0149362d), TOBN(0x95e57582, 0x1c4ae971),
++     TOBN(0x1fa4b1a8, 0x945cf86c), TOBN(0x4525a734, 0x0b024a2f),
++     TOBN(0xe76c8b62, 0x8f338360), TOBN(0x483ff593, 0x28edf32b),
++     TOBN(0x67e8e90a, 0x298b1aec), TOBN(0x9caab338, 0x736d9a21),
++     TOBN(0x5c09d2fd, 0x66892709), TOBN(0x2496b4dc, 0xb55a1d41),
++     TOBN(0x93f5fb1a, 0xe24a4394), TOBN(0x08c75049, 0x6fa8f6c1),
++     TOBN(0xcaead1c2, 0xc905d85f), TOBN(0xe9d7f790, 0x0733ae57),
++     TOBN(0x24c9a65c, 0xf07cdd94), TOBN(0x7389359c, 0xa4b55931),
++     TOBN(0xf58709b7, 0x367e45f7), TOBN(0x1f203067, 0xcb7e7adc),
++     TOBN(0x82444bff, 0xc7b72818), TOBN(0x07303b35, 0xbaac8033),
++     TOBN(0x1e1ee4e4, 0xd13b7ea1), TOBN(0xe6489b24, 0xe0e74180),
++     TOBN(0xa5f2c610, 0x7e70ef70), TOBN(0xa1655412, 0xbdd10894),
++     TOBN(0x555ebefb, 0x7af4194e), TOBN(0x533c1c3c, 0x8e89bd9c),
++     TOBN(0x735b9b57, 0x89895856), TOBN(0x15fb3cd2, 0x567f5c15),
++     TOBN(0x057fed45, 0x526f09fd), TOBN(0xe8a4f10c, 0x8128240a),
++     TOBN(0x9332efc4, 0xff2bfd8d), TOBN(0x214e77a0, 0xbd35aa31),
++     TOBN(0x32896d73, 0x14faa40e), TOBN(0x767867ec, 0x01e5f186),
++     TOBN(0xc9adf8f1, 0x17a1813e), TOBN(0xcb6cda78, 0x54741795),
++     TOBN(0xb7521b6d, 0x349d51aa), TOBN(0xf56b5a9e, 0xe3c7b8e9),
++     TOBN(0xc6f1e5c9, 0x32a096df), TOBN(0x083667c4, 0xa3635024),
++     TOBN(0x365ea135, 0x18087f2f), TOBN(0xf1b8eaac, 0xd136e45d),
++     TOBN(0xc8a0e484, 0x73aec989), TOBN(0xd75a324b, 0x142c9259),
++     TOBN(0xb7b4d001, 0x01dae185), TOBN(0x45434e0b, 0x9b7a94bc),
++     TOBN(0xf54339af, 0xfbd8cb0b), TOBN(0xdcc4569e, 0xe98ef49e),
++     TOBN(0x7789318a, 0x09a51299), TOBN(0x81b4d206, 0xb2b025d8),
++     TOBN(0xf64aa418, 0xfae85792), TOBN(0x3e50258f, 0xacd7baf7),
++     TOBN(0xdce84cdb, 0x2996864b), TOBN(0xa2e67089, 0x1f485fa4),
++     TOBN(0xb28b2bb6, 0x534c6a5a), TOBN(0x31a7ec6b, 0xc94b9d39),
++     TOBN(0x1d217766, 0xd6bc20da), TOBN(0x4acdb5ec, 0x86761190),
++     TOBN(0x68726328, 0x73701063), TOBN(0x4d24ee7c, 0x2128c29b),
++     TOBN(0xc072ebd3, 0xa19fd868), TOBN(0x612e481c, 0xdb8ddd3b),
++     TOBN(0xb4e1d754, 0x1a64d852), TOBN(0x00ef95ac, 0xc4c6c4ab),
++     TOBN(0x1536d2ed, 0xaa0a6c46), TOBN(0x61294086, 0x43774790),
++     TOBN(0x54af25e8, 0x343fda10), TOBN(0x9ff9d98d, 0xfd25d6f2),
++     TOBN(0x0746af7c, 0x468b8835), TOBN(0x977a31cb, 0x730ecea7),
++     TOBN(0xa5096b80, 0xc2cf4a81), TOBN(0xaa986833, 0x6458c37a),
++     TOBN(0x6af29bf3, 0xa6bd9d34), TOBN(0x6a62fe9b, 0x33c5d854),
++     TOBN(0x50e6c304, 0xb7133b5e), TOBN(0x04b60159, 0x7d6e6848),
++     TOBN(0x4cd296df, 0x5579bea4), TOBN(0x10e35ac8, 0x5ceedaf1),
++     TOBN(0x04c4c5fd, 0xe3bcc5b1), TOBN(0x95f9ee8a, 0x89412cf9),
++     TOBN(0x2c9459ee, 0x82b6eb0f), TOBN(0x2e845765, 0x95c2aadd),
++     TOBN(0x774a84ae, 0xd327fcfe), TOBN(0xd8c93722, 0x0368d476),
++     TOBN(0x0dbd5748, 0xf83e8a3b), TOBN(0xa579aa96, 0x8d2495f3),
++     TOBN(0x535996a0, 0xae496e9b), TOBN(0x07afbfe9, 0xb7f9bcc2),
++     TOBN(0x3ac1dc6d, 0x5b7bd293), TOBN(0x3b592cff, 0x7022323d),
++     TOBN(0xba0deb98, 0x9c0a3e76), TOBN(0x18e78e9f, 0x4b197acb),
++     TOBN(0x211cde10, 0x296c36ef), TOBN(0x7ee89672, 0x82c4da77),
++     TOBN(0xb617d270, 0xa57836da), TOBN(0xf0cd9c31, 0x9cb7560b),
++     TOBN(0x01fdcbf7, 0xe455fe90), TOBN(0x3fb53cbb, 0x7e7334f3),
++     TOBN(0x781e2ea4, 0x4e7de4ec), TOBN(0x8adab3ad, 0x0b384fd0),
++     TOBN(0x129eee2f, 0x53d64829), TOBN(0x7a471e17, 0xa261492b),
++     TOBN(0xe4f9adb9, 0xe4cb4a2c), TOBN(0x3d359f6f, 0x97ba2c2d),
++     TOBN(0x346c6786, 0x0aacd697), TOBN(0x92b444c3, 0x75c2f8a8),
++     TOBN(0xc79fa117, 0xd85df44e), TOBN(0x56782372, 0x398ddf31),
++     TOBN(0x60e690f2, 0xbbbab3b8), TOBN(0x4851f8ae, 0x8b04816b),
++     TOBN(0xc72046ab, 0x9c92e4d2), TOBN(0x518c74a1, 0x7cf3136b),
++     TOBN(0xff4eb50a, 0xf9877d4c), TOBN(0x14578d90, 0xa919cabb),
++     TOBN(0x8218f8c4, 0xac5eb2b6), TOBN(0xa3ccc547, 0x542016e4),
++     TOBN(0x025bf48e, 0x327f8349), TOBN(0xf3e97346, 0xf43cb641),
++     TOBN(0xdc2bafdf, 0x500f1085), TOBN(0x57167876, 0x2f063055),
++     TOBN(0x5bd914b9, 0x411925a6), TOBN(0x7c078d48, 0xa1123de5),
++     TOBN(0xee6bf835, 0x182b165d), TOBN(0xb11b5e5b, 0xba519727),
++     TOBN(0xe33ea76c, 0x1eea7b85), TOBN(0x2352b461, 0x92d4f85e),
++     TOBN(0xf101d334, 0xafe115bb), TOBN(0xfabc1294, 0x889175a3),
++     TOBN(0x7f6bcdc0, 0x5233f925), TOBN(0xe0a802db, 0xe77fec55),
++     TOBN(0xbdb47b75, 0x8069b659), TOBN(0x1c5e12de, 0xf98fbd74),
++     TOBN(0x869c58c6, 0x4b8457ee), TOBN(0xa5360f69, 0x4f7ea9f7),
++     TOBN(0xe576c09f, 0xf460b38f), TOBN(0x6b70d548, 0x22b7fb36),
++     TOBN(0x3fd237f1, 0x3bfae315), TOBN(0x33797852, 0xcbdff369),
++     TOBN(0x97df25f5, 0x25b516f9), TOBN(0x46f388f2, 0xba38ad2d),
++     TOBN(0x656c4658, 0x89d8ddbb), TOBN(0x8830b26e, 0x70f38ee8),
++     TOBN(0x4320fd5c, 0xde1212b0), TOBN(0xc34f30cf, 0xe4a2edb2),
++     TOBN(0xabb131a3, 0x56ab64b8), TOBN(0x7f77f0cc, 0xd99c5d26),
++     TOBN(0x66856a37, 0xbf981d94), TOBN(0x19e76d09, 0x738bd76e),
++     TOBN(0xe76c8ac3, 0x96238f39), TOBN(0xc0a482be, 0xa830b366),
++     TOBN(0xb7b8eaff, 0x0b4eb499), TOBN(0x8ecd83bc, 0x4bfb4865),
++     TOBN(0x971b2cb7, 0xa2f3776f), TOBN(0xb42176a4, 0xf4b88adf),
++     TOBN(0xb9617df5, 0xbe1fa446), TOBN(0x8b32d508, 0xcd031bd2),
++     TOBN(0x1c6bd47d, 0x53b618c0), TOBN(0xc424f46c, 0x6a227923),
++     TOBN(0x7303ffde, 0xdd92d964), TOBN(0xe9712878, 0x71b5abf2),
++     TOBN(0x8f48a632, 0xf815561d), TOBN(0x85f48ff5, 0xd3c055d1),
++     TOBN(0x222a1427, 0x7525684f), TOBN(0xd0d841a0, 0x67360cc3),
++     TOBN(0x4245a926, 0x0b9267c6), TOBN(0xc78913f1, 0xcf07f863),
++     TOBN(0xaa844c8e, 0x4d0d9e24), TOBN(0xa42ad522, 0x3d5f9017),
++     TOBN(0xbd371749, 0xa2c989d5), TOBN(0x928292df, 0xe1f5e78e),
++     TOBN(0x493b383e, 0x0a1ea6da), TOBN(0x5136fd8d, 0x13aee529),
++     TOBN(0x860c44b1, 0xf2c34a99), TOBN(0x3b00aca4, 0xbf5855ac),
++     TOBN(0xabf6aaa0, 0xfaaf37be), TOBN(0x65f43682, 0x2a53ec08),
++     TOBN(0x1d9a5801, 0xa11b12e1), TOBN(0x78a7ab2c, 0xe20ed475),
++     TOBN(0x0de1067e, 0x9a41e0d5), TOBN(0x30473f5f, 0x305023ea),
++     TOBN(0xdd3ae09d, 0x169c7d97), TOBN(0x5cd5baa4, 0xcfaef9cd),
++     TOBN(0x5cd7440b, 0x65a44803), TOBN(0xdc13966a, 0x47f364de),
++     TOBN(0x077b2be8, 0x2b8357c1), TOBN(0x0cb1b4c5, 0xe9d57c2a),
++     TOBN(0x7a4ceb32, 0x05ff363e), TOBN(0xf310fa4d, 0xca35a9ef),
++     TOBN(0xdbb7b352, 0xf97f68c6), TOBN(0x0c773b50, 0x0b02cf58),
++     TOBN(0xea2e4821, 0x3c1f96d9), TOBN(0xffb357b0, 0xeee01815),
++     TOBN(0xb9c924cd, 0xe0f28039), TOBN(0x0b36c95a, 0x46a3fbe4),
++     TOBN(0x1faaaea4, 0x5e46db6c), TOBN(0xcae575c3, 0x1928aaff),
++     TOBN(0x7f671302, 0xa70dab86), TOBN(0xfcbd12a9, 0x71c58cfc),
++     TOBN(0xcbef9acf, 0xbee0cb92), TOBN(0x573da0b9, 0xf8c1b583),
++     TOBN(0x4752fcfe, 0x0d41d550), TOBN(0xe7eec0e3, 0x2155cffe),
++     TOBN(0x0fc39fcb, 0x545ae248), TOBN(0x522cb8d1, 0x8065f44e),
++     TOBN(0x263c962a, 0x70cbb96c), TOBN(0xe034362a, 0xbcd124a9),
++     TOBN(0xf120db28, 0x3c2ae58d), TOBN(0xb9a38d49, 0xfef6d507),
++     TOBN(0xb1fd2a82, 0x1ff140fd), TOBN(0xbd162f30, 0x20aee7e0),
++     TOBN(0x4e17a5d4, 0xcb251949), TOBN(0x2aebcb83, 0x4f7e1c3d),
++     TOBN(0x608eb25f, 0x937b0527), TOBN(0xf42e1e47, 0xeb7d9997),
++     TOBN(0xeba699c4, 0xb8a53a29), TOBN(0x1f921c71, 0xe091b536),
++     TOBN(0xcce29e7b, 0x5b26bbd5), TOBN(0x7a8ef5ed, 0x3b61a680),
++     TOBN(0xe5ef8043, 0xba1f1c7e), TOBN(0x16ea8217, 0x18158dda),
++     TOBN(0x01778a2b, 0x599ff0f9), TOBN(0x68a923d7, 0x8104fc6b),
++     TOBN(0x5bfa44df, 0xda694ff3), TOBN(0x4f7199db, 0xf7667f12),
++     TOBN(0xc06d8ff6, 0xe46f2a79), TOBN(0x08b5dead, 0xe9f8131d),
++     TOBN(0x02519a59, 0xabb4ce7c), TOBN(0xc4f710bc, 0xb42aec3e),
++     TOBN(0x3d77b057, 0x78bde41a), TOBN(0x6474bf80, 0xb4186b5a),
++     TOBN(0x048b3f67, 0x88c65741), TOBN(0xc64519de, 0x03c7c154),
++     TOBN(0xdf073846, 0x0edfcc4f), TOBN(0x319aa737, 0x48f1aa6b),
++     TOBN(0x8b9f8a02, 0xca909f77), TOBN(0x90258139, 0x7580bfef),
++     TOBN(0xd8bfd3ca, 0xc0c22719), TOBN(0xc60209e4, 0xc9ca151e),
++     TOBN(0x7a744ab5, 0xd9a1a69c), TOBN(0x6de5048b, 0x14937f8f),
++     TOBN(0x171938d8, 0xe115ac04), TOBN(0x7df70940, 0x1c6b16d2),
++     TOBN(0xa6aeb663, 0x7f8e94e7), TOBN(0xc130388e, 0x2a2cf094),
++     TOBN(0x1850be84, 0x77f54e6e), TOBN(0x9f258a72, 0x65d60fe5),
++     TOBN(0xff7ff0c0, 0x6c9146d6), TOBN(0x039aaf90, 0xe63a830b),
++     TOBN(0x38f27a73, 0x9460342f), TOBN(0x4703148c, 0x3f795f8a),
++     TOBN(0x1bb5467b, 0x9681a97e), TOBN(0x00931ba5, 0xecaeb594),
++     TOBN(0xcdb6719d, 0x786f337c), TOBN(0xd9c01cd2, 0xe704397d),
++     TOBN(0x0f4a3f20, 0x555c2fef), TOBN(0x00452509, 0x7c0af223),
++     TOBN(0x54a58047, 0x84db8e76), TOBN(0x3bacf1aa, 0x93c8aa06),
++     TOBN(0x11ca957c, 0xf7919422), TOBN(0x50641053, 0x78cdaa40),
++     TOBN(0x7a303874, 0x9f7144ae), TOBN(0x170c963f, 0x43d4acfd),
++     TOBN(0x5e148149, 0x58ddd3ef), TOBN(0xa7bde582, 0x9e72dba8),
++     TOBN(0x0769da8b, 0x6fa68750), TOBN(0xfa64e532, 0x572e0249),
++     TOBN(0xfcaadf9d, 0x2619ad31), TOBN(0x87882daa, 0xa7b349cd),
++     TOBN(0x9f6eb731, 0x6c67a775), TOBN(0xcb10471a, 0xefc5d0b1),
++     TOBN(0xb433750c, 0xe1b806b2), TOBN(0x19c5714d, 0x57b1ae7e),
++     TOBN(0xc0dc8b7b, 0xed03fd3f), TOBN(0xdd03344f, 0x31bc194e),
++     TOBN(0xa66c52a7, 0x8c6320b5), TOBN(0x8bc82ce3, 0xd0b6fd93),
++     TOBN(0xf8e13501, 0xb35f1341), TOBN(0xe53156dd, 0x25a43e42),
++     TOBN(0xd3adf27e, 0x4daeb85c), TOBN(0xb81d8379, 0xbbeddeb5),
++     TOBN(0x1b0b546e, 0x2e435867), TOBN(0x9020eb94, 0xeba5dd60),
++     TOBN(0x37d91161, 0x8210cb9d), TOBN(0x4c596b31, 0x5c91f1cf),
++     TOBN(0xb228a90f, 0x0e0b040d), TOBN(0xbaf02d82, 0x45ff897f),
++     TOBN(0x2aac79e6, 0x00fa6122), TOBN(0x24828817, 0x8e36f557),
++     TOBN(0xb9521d31, 0x113ec356), TOBN(0x9e48861e, 0x15eff1f8),
++     TOBN(0x2aa1d412, 0xe0d41715), TOBN(0x71f86203, 0x53f131b8),
++     TOBN(0xf60da8da, 0x3fd19408), TOBN(0x4aa716dc, 0x278d9d99),
++     TOBN(0x394531f7, 0xa8c51c90), TOBN(0xb560b0e8, 0xf59db51c),
++     TOBN(0xa28fc992, 0xfa34bdad), TOBN(0xf024fa14, 0x9cd4f8bd),
++     TOBN(0x5cf530f7, 0x23a9d0d3), TOBN(0x615ca193, 0xe28c9b56),
++     TOBN(0x6d2a483d, 0x6f73c51e), TOBN(0xa4cb2412, 0xea0dc2dd),
++     TOBN(0x50663c41, 0x1eb917ff), TOBN(0x3d3a74cf, 0xeade299e),
++     TOBN(0x29b3990f, 0x4a7a9202), TOBN(0xa9bccf59, 0xa7b15c3d),
++     TOBN(0x66a3ccdc, 0xa5df9208), TOBN(0x48027c14, 0x43f2f929),
++     TOBN(0xd385377c, 0x40b557f0), TOBN(0xe001c366, 0xcd684660),
++     TOBN(0x1b18ed6b, 0xe2183a27), TOBN(0x879738d8, 0x63210329),
++     TOBN(0xa687c74b, 0xbda94882), TOBN(0xd1bbcc48, 0xa684b299),
++     TOBN(0xaf6f1112, 0x863b3724), TOBN(0x6943d1b4, 0x2c8ce9f8),
++     TOBN(0xe044a3bb, 0x098cafb4), TOBN(0x27ed2310, 0x60d48caf),
++     TOBN(0x542b5675, 0x3a31b84d), TOBN(0xcbf3dd50, 0xfcddbed7),
++     TOBN(0x25031f16, 0x41b1d830), TOBN(0xa7ec851d, 0xcb0c1e27),
++     TOBN(0xac1c8fe0, 0xb5ae75db), TOBN(0xb24c7557, 0x08c52120),
++     TOBN(0x57f811dc, 0x1d4636c3), TOBN(0xf8436526, 0x681a9939),
++     TOBN(0x1f6bc6d9, 0x9c81adb3), TOBN(0x840f8ac3, 0x5b7d80d4),
++     TOBN(0x731a9811, 0xf4387f1a), TOBN(0x7c501cd3, 0xb5156880),
++     TOBN(0xa5ca4a07, 0xdfe68867), TOBN(0xf123d8f0, 0x5fcea120),
++     TOBN(0x1fbb0e71, 0xd607039e), TOBN(0x2b70e215, 0xcd3a4546),
++     TOBN(0x32d2f01d, 0x53324091), TOBN(0xb796ff08, 0x180ab19b),
++     TOBN(0x32d87a86, 0x3c57c4aa), TOBN(0x2aed9caf, 0xb7c49a27),
++     TOBN(0x9fb35eac, 0x31630d98), TOBN(0x338e8cdf, 0x5c3e20a3),
++     TOBN(0x80f16182, 0x66cde8db), TOBN(0x4e159980, 0x2d72fd36),
++     TOBN(0xd7b8f13b, 0x9b6e5072), TOBN(0xf5213907, 0x3b7b5dc1),
++     TOBN(0x4d431f1d, 0x8ce4396e), TOBN(0x37a1a680, 0xa7ed2142),
++     TOBN(0xbf375696, 0xd01aaf6b), TOBN(0xaa1c0c54, 0xe63aab66),
++     TOBN(0x3014368b, 0x4ed80940), TOBN(0x67e6d056, 0x7a6fcedd),
++     TOBN(0x7c208c49, 0xca97579f), TOBN(0xfe3d7a81, 0xa23597f6),
++     TOBN(0x5e203202, 0x7e096ae2), TOBN(0xb1f3e1e7, 0x24b39366),
++     TOBN(0x26da26f3, 0x2fdcdffc), TOBN(0x79422f1d, 0x6097be83),}
++    ,
++    {TOBN(0x263a2cfb, 0x9db3b381), TOBN(0x9c3a2dee, 0xd4df0a4b),
++     TOBN(0x728d06e9, 0x7d04e61f), TOBN(0x8b1adfbc, 0x42449325),
++     TOBN(0x6ec1d939, 0x7e053a1b), TOBN(0xee2be5c7, 0x66daf707),
++     TOBN(0x80ba1e14, 0x810ac7ab), TOBN(0xdd2ae778, 0xf530f174),
++     TOBN(0x0435d97a, 0x205b9d8b), TOBN(0x6eb8f064, 0x056756d4),
++     TOBN(0xd5e88a8b, 0xb6f8210e), TOBN(0x070ef12d, 0xec9fd9ea),
++     TOBN(0x4d849505, 0x3bcc876a), TOBN(0x12a75338, 0xa7404ce3),
++     TOBN(0xd22b49e1, 0xb8a1db5e), TOBN(0xec1f2051, 0x14bfa5ad),
++     TOBN(0xadbaeb79, 0xb6828f36), TOBN(0x9d7a0258, 0x01bd5b9e),
++     TOBN(0xeda01e0d, 0x1e844b0c), TOBN(0x4b625175, 0x887edfc9),
++     TOBN(0x14109fdd, 0x9669b621), TOBN(0x88a2ca56, 0xf6f87b98),
++     TOBN(0xfe2eb788, 0x170df6bc), TOBN(0x0cea06f4, 0xffa473f9),
++     TOBN(0x43ed81b5, 0xc4e83d33), TOBN(0xd9f35879, 0x5efd488b),
++     TOBN(0x164a620f, 0x9deb4d0f), TOBN(0xc6927bdb, 0xac6a7394),
++     TOBN(0x45c28df7, 0x9f9e0f03), TOBN(0x2868661e, 0xfcd7e1a9),
++     TOBN(0x7cf4e8d0, 0xffa348f1), TOBN(0x6bd4c284, 0x398538e0),
++     TOBN(0x2618a091, 0x289a8619), TOBN(0xef796e60, 0x6671b173),
++     TOBN(0x664e46e5, 0x9090c632), TOBN(0xa38062d4, 0x1e66f8fb),
++     TOBN(0x6c744a20, 0x0573274e), TOBN(0xd07b67e4, 0xa9271394),
++     TOBN(0x391223b2, 0x6bdc0e20), TOBN(0xbe2d93f1, 0xeb0a05a7),
++     TOBN(0xf23e2e53, 0x3f36d141), TOBN(0xe84bb3d4, 0x4dfca442),
++     TOBN(0xb804a48d, 0x6b7c023a), TOBN(0x1e16a8fa, 0x76431c3b),
++     TOBN(0x1b5452ad, 0xddd472e0), TOBN(0x7d405ee7, 0x0d1ee127),
++     TOBN(0x50fc6f1d, 0xffa27599), TOBN(0x351ac53c, 0xbf391b35),
++     TOBN(0x7efa14b8, 0x4444896b), TOBN(0x64974d2f, 0xf94027fb),
++     TOBN(0xefdcd0e8, 0xde84487d), TOBN(0x8c45b260, 0x2b48989b),
++     TOBN(0xa8fcbbc2, 0xd8463487), TOBN(0xd1b2b3f7, 0x3fbc476c),
++     TOBN(0x21d005b7, 0xc8f443c0), TOBN(0x518f2e67, 0x40c0139c),
++     TOBN(0x56036e8c, 0x06d75fc1), TOBN(0x2dcf7bb7, 0x3249a89f),
++     TOBN(0x81dd1d3d, 0xe245e7dd), TOBN(0xf578dc4b, 0xebd6e2a7),
++     TOBN(0x4c028903, 0xdf2ce7a0), TOBN(0xaee36288, 0x9c39afac),
++     TOBN(0xdc847c31, 0x146404ab), TOBN(0x6304c0d8, 0xa4e97818),
++     TOBN(0xae51dca2, 0xa91f6791), TOBN(0x2abe4190, 0x9baa9efc),
++     TOBN(0xd9d2e2f4, 0x559c7ac1), TOBN(0xe82f4b51, 0xfc9f773a),
++     TOBN(0xa7713027, 0x4073e81c), TOBN(0xc0276fac, 0xfbb596fc),
++     TOBN(0x1d819fc9, 0xa684f70c), TOBN(0x29b47fdd, 0xc9f7b1e0),
++     TOBN(0x358de103, 0x459b1940), TOBN(0xec881c59, 0x5b013e93),
++     TOBN(0x51574c93, 0x49532ad3), TOBN(0x2db1d445, 0xb37b46de),
++     TOBN(0xc6445b87, 0xdf239fd8), TOBN(0xc718af75, 0x151d24ee),
++     TOBN(0xaea1c4a4, 0xf43c6259), TOBN(0x40c0e5d7, 0x70be02f7),
++     TOBN(0x6a4590f4, 0x721b33f2), TOBN(0x2124f1fb, 0xfedf04ea),
++     TOBN(0xf8e53cde, 0x9745efe7), TOBN(0xe7e10432, 0x65f046d9),
++     TOBN(0xc3fca28e, 0xe4d0c7e6), TOBN(0x847e339a, 0x87253b1b),
++     TOBN(0x9b595348, 0x3743e643), TOBN(0xcb6a0a0b, 0x4fd12fc5),
++     TOBN(0xfb6836c3, 0x27d02dcc), TOBN(0x5ad00982, 0x7a68bcc2),
++     TOBN(0x1b24b44c, 0x005e912d), TOBN(0xcc83d20f, 0x811fdcfe),
++     TOBN(0x36527ec1, 0x666fba0c), TOBN(0x69948197, 0x14754635),
++     TOBN(0xfcdcb1a8, 0x556da9c2), TOBN(0xa5934267, 0x81a732b2),
++     TOBN(0xec1214ed, 0xa714181d), TOBN(0x609ac13b, 0x6067b341),
++     TOBN(0xff4b4c97, 0xa545df1f), TOBN(0xa1240501, 0x34d2076b),
++     TOBN(0x6efa0c23, 0x1409ca97), TOBN(0x254cc1a8, 0x20638c43),
++     TOBN(0xd4e363af, 0xdcfb46cd), TOBN(0x62c2adc3, 0x03942a27),
++     TOBN(0xc67b9df0, 0x56e46483), TOBN(0xa55abb20, 0x63736356),
++     TOBN(0xab93c098, 0xc551bc52), TOBN(0x382b49f9, 0xb15fe64b),
++     TOBN(0x9ec221ad, 0x4dff8d47), TOBN(0x79caf615, 0x437df4d6),
++     TOBN(0x5f13dc64, 0xbb456509), TOBN(0xe4c589d9, 0x191f0714),
++     TOBN(0x27b6a8ab, 0x3fd40e09), TOBN(0xe455842e, 0x77313ea9),
++     TOBN(0x8b51d1e2, 0x1f55988b), TOBN(0x5716dd73, 0x062bbbfc),
++     TOBN(0x633c11e5, 0x4e8bf3de), TOBN(0x9a0e77b6, 0x1b85be3b),
++     TOBN(0x56510729, 0x0911cca6), TOBN(0x27e76495, 0xefa6590f),
++     TOBN(0xe4ac8b33, 0x070d3aab), TOBN(0x2643672b, 0x9a2cd5e5),
++     TOBN(0x52eff79b, 0x1cfc9173), TOBN(0x665ca49b, 0x90a7c13f),
++     TOBN(0x5a8dda59, 0xb3efb998), TOBN(0x8a5b922d, 0x052f1341),
++     TOBN(0xae9ebbab, 0x3cf9a530), TOBN(0x35986e7b, 0xf56da4d7),
++     TOBN(0x3a636b5c, 0xff3513cc), TOBN(0xbb0cf8ba, 0x3198f7dd),
++     TOBN(0xb8d40522, 0x41f16f86), TOBN(0x760575d8, 0xde13a7bf),
++     TOBN(0x36f74e16, 0x9f7aa181), TOBN(0x163a3ecf, 0xf509ed1c),
++     TOBN(0x6aead61f, 0x3c40a491), TOBN(0x158c95fc, 0xdfe8fcaa),
++     TOBN(0xa3991b6e, 0x13cda46f), TOBN(0x79482415, 0x342faed0),
++     TOBN(0xf3ba5bde, 0x666b5970), TOBN(0x1d52e6bc, 0xb26ab6dd),
++     TOBN(0x768ba1e7, 0x8608dd3d), TOBN(0x4930db2a, 0xea076586),
++     TOBN(0xd9575714, 0xe7dc1afa), TOBN(0x1fc7bf7d, 0xf7c58817),
++     TOBN(0x6b47accd, 0xd9eee96c), TOBN(0x0ca277fb, 0xe58cec37),
++     TOBN(0x113fe413, 0xe702c42a), TOBN(0xdd1764ee, 0xc47cbe51),
++     TOBN(0x041e7cde, 0x7b3ed739), TOBN(0x50cb7459, 0x5ce9e1c0),
++     TOBN(0x35568513, 0x2925b212), TOBN(0x7cff95c4, 0x001b081c),
++     TOBN(0x63ee4cbd, 0x8088b454), TOBN(0xdb7f32f7, 0x9a9e0c8a),
++     TOBN(0xb377d418, 0x6b2447cb), TOBN(0xe3e982aa, 0xd370219b),
++     TOBN(0x06ccc1e4, 0xc2a2a593), TOBN(0x72c36865, 0x0773f24f),
++     TOBN(0xa13b4da7, 0x95859423), TOBN(0x8bbf1d33, 0x75040c8f),
++     TOBN(0x726f0973, 0xda50c991), TOBN(0x48afcd5b, 0x822d6ee2),
++     TOBN(0xe5fc718b, 0x20fd7771), TOBN(0xb9e8e77d, 0xfd0807a1),
++     TOBN(0x7f5e0f44, 0x99a7703d), TOBN(0x6972930e, 0x618e36f3),
++     TOBN(0x2b7c77b8, 0x23807bbe), TOBN(0xe5b82405, 0xcb27ff50),
++     TOBN(0xba8b8be3, 0xbd379062), TOBN(0xd64b7a1d, 0x2dce4a92),
++     TOBN(0x040a73c5, 0xb2952e37), TOBN(0x0a9e252e, 0xd438aeca),
++     TOBN(0xdd43956b, 0xc39d3bcb), TOBN(0x1a31ca00, 0xb32b2d63),
++     TOBN(0xd67133b8, 0x5c417a18), TOBN(0xd08e4790, 0x2ef442c8),
++     TOBN(0x98cb1ae9, 0x255c0980), TOBN(0x4bd86381, 0x2b4a739f),
++     TOBN(0x5a5c31e1, 0x1e4a45a1), TOBN(0x1e5d55fe, 0x9cb0db2f),
++     TOBN(0x74661b06, 0x8ff5cc29), TOBN(0x026b389f, 0x0eb8a4f4),
++     TOBN(0x536b21a4, 0x58848c24), TOBN(0x2e5bf8ec, 0x81dc72b0),
++     TOBN(0x03c187d0, 0xad886aac), TOBN(0x5c16878a, 0xb771b645),
++     TOBN(0xb07dfc6f, 0xc74045ab), TOBN(0x2c6360bf, 0x7800caed),
++     TOBN(0x24295bb5, 0xb9c972a3), TOBN(0xc9e6f88e, 0x7c9a6dba),
++     TOBN(0x90ffbf24, 0x92a79aa6), TOBN(0xde29d50a, 0x41c26ac2),
++     TOBN(0x9f0af483, 0xd309cbe6), TOBN(0x5b020d8a, 0xe0bced4f),
++     TOBN(0x606e986d, 0xb38023e3), TOBN(0xad8f2c9d, 0x1abc6933),
++     TOBN(0x19292e1d, 0xe7400e93), TOBN(0xfe3e18a9, 0x52be5e4d),
++     TOBN(0xe8e9771d, 0x2e0680bf), TOBN(0x8c5bec98, 0xc54db063),
++     TOBN(0x2af9662a, 0x74a55d1f), TOBN(0xe3fbf28f, 0x046f66d8),
++     TOBN(0xa3a72ab4, 0xd4dc4794), TOBN(0x09779f45, 0x5c7c2dd8),
++     TOBN(0xd893bdaf, 0xc3d19d8d), TOBN(0xd5a75094, 0x57d6a6df),
++     TOBN(0x8cf8fef9, 0x952e6255), TOBN(0x3da67cfb, 0xda9a8aff),
++     TOBN(0x4c23f62a, 0x2c160dcd), TOBN(0x34e6c5e3, 0x8f90eaef),
++     TOBN(0x35865519, 0xa9a65d5a), TOBN(0x07c48aae, 0x8fd38a3d),
++     TOBN(0xb7e7aeda, 0x50068527), TOBN(0x2c09ef23, 0x1c90936a),
++     TOBN(0x31ecfeb6, 0xe879324c), TOBN(0xa0871f6b, 0xfb0ec938),
++     TOBN(0xb1f0fb68, 0xd84d835d), TOBN(0xc90caf39, 0x861dc1e6),
++     TOBN(0x12e5b046, 0x7594f8d7), TOBN(0x26897ae2, 0x65012b92),
++     TOBN(0xbcf68a08, 0xa4d6755d), TOBN(0x403ee41c, 0x0991fbda),
++     TOBN(0x733e343e, 0x3bbf17e8), TOBN(0xd2c7980d, 0x679b3d65),
++     TOBN(0x33056232, 0xd2e11305), TOBN(0x966be492, 0xf3c07a6f),
++     TOBN(0x6a8878ff, 0xbb15509d), TOBN(0xff221101, 0x0a9b59a4),
++     TOBN(0x6c9f564a, 0xabe30129), TOBN(0xc6f2c940, 0x336e64cf),
++     TOBN(0x0fe75262, 0x8b0c8022), TOBN(0xbe0267e9, 0x6ae8db87),
++     TOBN(0x22e192f1, 0x93bc042b), TOBN(0xf085b534, 0xb237c458),
++     TOBN(0xa0d192bd, 0x832c4168), TOBN(0x7a76e9e3, 0xbdf6271d),
++     TOBN(0x52a882fa, 0xb88911b5), TOBN(0xc85345e4, 0xb4db0eb5),
++     TOBN(0xa3be02a6, 0x81a7c3ff), TOBN(0x51889c8c, 0xf0ec0469),
++     TOBN(0x9d031369, 0xa5e829e5), TOBN(0xcbb4c6fc, 0x1607aa41),
++     TOBN(0x75ac59a6, 0x241d84c1), TOBN(0xc043f2bf, 0x8829e0ee),
++     TOBN(0x82a38f75, 0x8ea5e185), TOBN(0x8bda40b9, 0xd87cbd9f),
++     TOBN(0x9e65e75e, 0x2d8fc601), TOBN(0x3d515f74, 0xa35690b3),
++     TOBN(0x534acf4f, 0xda79e5ac), TOBN(0x68b83b3a, 0x8630215f),
++     TOBN(0x5c748b2e, 0xd085756e), TOBN(0xb0317258, 0xe5d37cb2),
++     TOBN(0x6735841a, 0xc5ccc2c4), TOBN(0x7d7dc96b, 0x3d9d5069),
++     TOBN(0xa147e410, 0xfd1754bd), TOBN(0x65296e94, 0xd399ddd5),
++     TOBN(0xf6b5b2d0, 0xbc8fa5bc), TOBN(0x8a5ead67, 0x500c277b),
++     TOBN(0x214625e6, 0xdfa08a5d), TOBN(0x51fdfedc, 0x959cf047),
++     TOBN(0x6bc9430b, 0x289fca32), TOBN(0xe36ff0cf, 0x9d9bdc3f),
++     TOBN(0x2fe187cb, 0x58ea0ede), TOBN(0xed66af20, 0x5a900b3f),
++     TOBN(0x00e0968b, 0x5fa9f4d6), TOBN(0x2d4066ce, 0x37a362e7),
++     TOBN(0xa99a9748, 0xbd07e772), TOBN(0x710989c0, 0x06a4f1d0),
++     TOBN(0xd5dedf35, 0xce40cbd8), TOBN(0xab55c5f0, 0x1743293d),
++     TOBN(0x766f1144, 0x8aa24e2c), TOBN(0x94d874f8, 0x605fbcb4),
++     TOBN(0xa365f0e8, 0xa518001b), TOBN(0xee605eb6, 0x9d04ef0f),
++     TOBN(0x5a3915cd, 0xba8d4d25), TOBN(0x44c0e1b8, 0xb5113472),
++     TOBN(0xcbb024e8, 0x8b6740dc), TOBN(0x89087a53, 0xee1d4f0c),
++     TOBN(0xa88fa05c, 0x1fc4e372), TOBN(0x8bf395cb, 0xaf8b3af2),
++     TOBN(0x1e71c9a1, 0xdeb8568b), TOBN(0xa35daea0, 0x80fb3d32),
++     TOBN(0xe8b6f266, 0x2cf8fb81), TOBN(0x6d51afe8, 0x9490696a),
++     TOBN(0x81beac6e, 0x51803a19), TOBN(0xe3d24b7f, 0x86219080),
++     TOBN(0x727cfd9d, 0xdf6f463c), TOBN(0x8c6865ca, 0x72284ee8),
++     TOBN(0x32c88b7d, 0xb743f4ef), TOBN(0x3793909b, 0xe7d11dce),
++     TOBN(0xd398f922, 0x2ff2ebe8), TOBN(0x2c70ca44, 0xe5e49796),
++     TOBN(0xdf4d9929, 0xcb1131b1), TOBN(0x7826f298, 0x25888e79),
++     TOBN(0x4d3a112c, 0xf1d8740a), TOBN(0x00384cb6, 0x270afa8b),
++     TOBN(0xcb64125b, 0x3ab48095), TOBN(0x3451c256, 0x62d05106),
++     TOBN(0xd73d577d, 0xa4955845), TOBN(0x39570c16, 0xbf9f4433),
++     TOBN(0xd7dfaad3, 0xadecf263), TOBN(0xf1c3d8d1, 0xdc76e102),
++     TOBN(0x5e774a58, 0x54c6a836), TOBN(0xdad4b672, 0x3e92d47b),
++     TOBN(0xbe7e990f, 0xf0d796a0), TOBN(0x5fc62478, 0xdf0e8b02),
++     TOBN(0x8aae8bf4, 0x030c00ad), TOBN(0x3d2db93b, 0x9004ba0f),
++     TOBN(0xe48c8a79, 0xd85d5ddc), TOBN(0xe907caa7, 0x6bb07f34),
++     TOBN(0x58db343a, 0xa39eaed5), TOBN(0x0ea6e007, 0xadaf5724),
++     TOBN(0xe00df169, 0xd23233f3), TOBN(0x3e322796, 0x77cb637f),
++     TOBN(0x1f897c0e, 0x1da0cf6c), TOBN(0xa651f5d8, 0x31d6bbdd),
++     TOBN(0xdd61af19, 0x1a230c76), TOBN(0xbd527272, 0xcdaa5e4a),
++     TOBN(0xca753636, 0xd0abcd7e), TOBN(0x78bdd37c, 0x370bd8dc),
++     TOBN(0xc23916c2, 0x17cd93fe), TOBN(0x65b97a4d, 0xdadce6e2),
++     TOBN(0xe04ed4eb, 0x174e42f8), TOBN(0x1491ccaa, 0xbb21480a),
++     TOBN(0x145a8280, 0x23196332), TOBN(0x3c3862d7, 0x587b479a),
++     TOBN(0x9f4a88a3, 0x01dcd0ed), TOBN(0x4da2b7ef, 0x3ea12f1f),
++     TOBN(0xf8e7ae33, 0xb126e48e), TOBN(0x404a0b32, 0xf494e237),
++     TOBN(0x9beac474, 0xc55acadb), TOBN(0x4ee5cf3b, 0xcbec9fd9),
++     TOBN(0x336b33b9, 0x7df3c8c3), TOBN(0xbd905fe3, 0xb76808fd),
++     TOBN(0x8f436981, 0xaa45c16a), TOBN(0x255c5bfa, 0x3dd27b62),
++     TOBN(0x71965cbf, 0xc3dd9b4d), TOBN(0xce23edbf, 0xfc068a87),
++     TOBN(0xb78d4725, 0x745b029b), TOBN(0x74610713, 0xcefdd9bd),
++     TOBN(0x7116f75f, 0x1266bf52), TOBN(0x02046722, 0x18e49bb6),
++     TOBN(0xdf43df9f, 0x3d6f19e3), TOBN(0xef1bc7d0, 0xe685cb2f),
++     TOBN(0xcddb27c1, 0x7078c432), TOBN(0xe1961b9c, 0xb77fedb7),
++     TOBN(0x1edc2f5c, 0xc2290570), TOBN(0x2c3fefca, 0x19cbd886),
++     TOBN(0xcf880a36, 0xc2af389a), TOBN(0x96c610fd, 0xbda71cea),
++     TOBN(0xf03977a9, 0x32aa8463), TOBN(0x8eb7763f, 0x8586d90a),
++     TOBN(0x3f342454, 0x2a296e77), TOBN(0xc8718683, 0x42837a35),
++     TOBN(0x7dc71090, 0x6a09c731), TOBN(0x54778ffb, 0x51b816db),
++     TOBN(0x6b33bfec, 0xaf06defd), TOBN(0xfe3c105f, 0x8592b70b),
++     TOBN(0xf937fda4, 0x61da6114), TOBN(0x3c13e651, 0x4c266ad7),
++     TOBN(0xe363a829, 0x855938e8), TOBN(0x2eeb5d9e, 0x9de54b72),
++     TOBN(0xbeb93b0e, 0x20ccfab9), TOBN(0x3dffbb5f, 0x25e61a25),
++     TOBN(0x7f655e43, 0x1acc093d), TOBN(0x0cb6cc3d, 0x3964ce61),
++     TOBN(0x6ab283a1, 0xe5e9b460), TOBN(0x55d787c5, 0xa1c7e72d),
++     TOBN(0x4d2efd47, 0xdeadbf02), TOBN(0x11e80219, 0xac459068),
++     TOBN(0x810c7626, 0x71f311f0), TOBN(0xfa17ef8d, 0x4ab6ef53),
++     TOBN(0xaf47fd25, 0x93e43bff), TOBN(0x5cb5ff3f, 0x0be40632),
++     TOBN(0x54687106, 0x8ee61da3), TOBN(0x7764196e, 0xb08afd0f),
++     TOBN(0x831ab3ed, 0xf0290a8f), TOBN(0xcae81966, 0xcb47c387),
++     TOBN(0xaad7dece, 0x184efb4f), TOBN(0xdcfc53b3, 0x4749110e),
++     TOBN(0x6698f23c, 0x4cb632f9), TOBN(0xc42a1ad6, 0xb91f8067),
++     TOBN(0xb116a81d, 0x6284180a), TOBN(0xebedf5f8, 0xe901326f),
++     TOBN(0xf2274c9f, 0x97e3e044), TOBN(0x42018520, 0x11d09fc9),
++     TOBN(0x56a65f17, 0xd18e6e23), TOBN(0x2ea61e2a, 0x352b683c),
++     TOBN(0x27d291bc, 0x575eaa94), TOBN(0x9e7bc721, 0xb8ff522d),
++     TOBN(0x5f7268bf, 0xa7f04d6f), TOBN(0x5868c73f, 0xaba41748),
++     TOBN(0x9f85c2db, 0x7be0eead), TOBN(0x511e7842, 0xff719135),
++     TOBN(0x5a06b1e9, 0xc5ea90d7), TOBN(0x0c19e283, 0x26fab631),
++     TOBN(0x8af8f0cf, 0xe9206c55), TOBN(0x89389cb4, 0x3553c06a),
++     TOBN(0x39dbed97, 0xf65f8004), TOBN(0x0621b037, 0xc508991d),
++     TOBN(0x1c52e635, 0x96e78cc4), TOBN(0x5385c8b2, 0x0c06b4a8),
++     TOBN(0xd84ddfdb, 0xb0e87d03), TOBN(0xc49dfb66, 0x934bafad),
++     TOBN(0x7071e170, 0x59f70772), TOBN(0x3a073a84, 0x3a1db56b),
++     TOBN(0x03494903, 0x3b8af190), TOBN(0x7d882de3, 0xd32920f0),
++     TOBN(0x91633f0a, 0xb2cf8940), TOBN(0x72b0b178, 0x6f948f51),
++     TOBN(0x2d28dc30, 0x782653c8), TOBN(0x88829849, 0xdb903a05),
++     TOBN(0xb8095d0c, 0x6a19d2bb), TOBN(0x4b9e7f0c, 0x86f782cb),
++     TOBN(0x7af73988, 0x2d907064), TOBN(0xd12be0fe, 0x8b32643c),
++     TOBN(0x358ed23d, 0x0e165dc3), TOBN(0x3d47ce62, 0x4e2378ce),
++     TOBN(0x7e2bb0b9, 0xfeb8a087), TOBN(0x3246e8ae, 0xe29e10b9),
++     TOBN(0x459f4ec7, 0x03ce2b4d), TOBN(0xe9b4ca1b, 0xbbc077cf),
++     TOBN(0x2613b4f2, 0x0e9940c1), TOBN(0xfc598bb9, 0x047d1eb1),
++     TOBN(0x9744c62b, 0x45036099), TOBN(0xa9dee742, 0x167c65d8),
++     TOBN(0x0c511525, 0xdabe1943), TOBN(0xda110554, 0x93c6c624),
++     TOBN(0xae00a52c, 0x651a3be2), TOBN(0xcda5111d, 0x884449a6),
++     TOBN(0x063c06f4, 0xff33bed1), TOBN(0x73baaf9a, 0x0d3d76b4),
++     TOBN(0x52fb0c9d, 0x7fc63668), TOBN(0x6886c9dd, 0x0c039cde),
++     TOBN(0x602bd599, 0x55b22351), TOBN(0xb00cab02, 0x360c7c13),
++     TOBN(0x8cb616bc, 0x81b69442), TOBN(0x41486700, 0xb55c3cee),
++     TOBN(0x71093281, 0xf49ba278), TOBN(0xad956d9c, 0x64a50710),
++     TOBN(0x9561f28b, 0x638a7e81), TOBN(0x54155cdf, 0x5980ddc3),
++     TOBN(0xb2db4a96, 0xd26f247a), TOBN(0x9d774e4e, 0x4787d100),
++     TOBN(0x1a9e6e2e, 0x078637d2), TOBN(0x1c363e2d, 0x5e0ae06a),
++     TOBN(0x7493483e, 0xe9cfa354), TOBN(0x76843cb3, 0x7f74b98d),
++     TOBN(0xbaca6591, 0xd4b66947), TOBN(0xb452ce98, 0x04460a8c),
++     TOBN(0x6830d246, 0x43768f55), TOBN(0xf4197ed8, 0x7dff12df),
++     TOBN(0x6521b472, 0x400dd0f7), TOBN(0x59f5ca8f, 0x4b1e7093),
++     TOBN(0x6feff11b, 0x080338ae), TOBN(0x0ada31f6, 0xa29ca3c6),
++     TOBN(0x24794eb6, 0x94a2c215), TOBN(0xd83a43ab, 0x05a57ab4),
++     TOBN(0x264a543a, 0x2a6f89fe), TOBN(0x2c2a3868, 0xdd5ec7c2),
++     TOBN(0xd3373940, 0x8439d9b2), TOBN(0x715ea672, 0x0acd1f11),
++     TOBN(0x42c1d235, 0xe7e6cc19), TOBN(0x81ce6e96, 0xb990585c),
++     TOBN(0x04e5dfe0, 0xd809c7bd), TOBN(0xd7b2580c, 0x8f1050ab),
++     TOBN(0x6d91ad78, 0xd8a4176f), TOBN(0x0af556ee, 0x4e2e897c),
++     TOBN(0x162a8b73, 0x921de0ac), TOBN(0x52ac9c22, 0x7ea78400),
++     TOBN(0xee2a4eea, 0xefce2174), TOBN(0xbe61844e, 0x6d637f79),
++     TOBN(0x0491f1bc, 0x789a283b), TOBN(0x72d3ac3d, 0x880836f4),
++     TOBN(0xaa1c5ea3, 0x88e5402d), TOBN(0x1b192421, 0xd5cc473d),
++     TOBN(0x5c0b9998, 0x9dc84cac), TOBN(0xb0a8482d, 0x9c6e75b8),
++     TOBN(0x639961d0, 0x3a191ce2), TOBN(0xda3bc865, 0x6d837930),
++     TOBN(0xca990653, 0x056e6f8f), TOBN(0x84861c41, 0x64d133a7),
++     TOBN(0x8b403276, 0x746abe40), TOBN(0xb7b4d51a, 0xebf8e303),
++     TOBN(0x05b43211, 0x220a255d), TOBN(0xc997152c, 0x02419e6e),
++     TOBN(0x76ff47b6, 0x630c2fea), TOBN(0x50518677, 0x281fdade),
++     TOBN(0x3283b8ba, 0xcf902b0b), TOBN(0x8d4b4eb5, 0x37db303b),
++     TOBN(0xcc89f42d, 0x755011bc), TOBN(0xb43d74bb, 0xdd09d19b),
++     TOBN(0x65746bc9, 0x8adba350), TOBN(0x364eaf8c, 0xb51c1927),
++     TOBN(0x13c76596, 0x10ad72ec), TOBN(0x30045121, 0xf8d40c20),
++     TOBN(0x6d2d99b7, 0xea7b979b), TOBN(0xcd78cd74, 0xe6fb3bcd),
++     TOBN(0x11e45a9e, 0x86cffbfe), TOBN(0x78a61cf4, 0x637024f6),
++     TOBN(0xd06bc872, 0x3d502295), TOBN(0xf1376854, 0x458cb288),
++     TOBN(0xb9db26a1, 0x342f8586), TOBN(0xf33effcf, 0x4beee09e),
++     TOBN(0xd7e0c4cd, 0xb30cfb3a), TOBN(0x6d09b8c1, 0x6c9db4c8),
++     TOBN(0x40ba1a42, 0x07c8d9df), TOBN(0x6fd495f7, 0x1c52c66d),
++     TOBN(0xfb0e169f, 0x275264da), TOBN(0x80c2b746, 0xe57d8362),
++     TOBN(0xedd987f7, 0x49ad7222), TOBN(0xfdc229af, 0x4398ec7b),}
++    ,
++    {TOBN(0xb0d1ed84, 0x52666a58), TOBN(0x4bcb6e00, 0xe6a9c3c2),
++     TOBN(0x3c57411c, 0x26906408), TOBN(0xcfc20755, 0x13556400),
++     TOBN(0xa08b1c50, 0x5294dba3), TOBN(0xa30ba286, 0x8b7dd31e),
++     TOBN(0xd70ba90e, 0x991eca74), TOBN(0x094e142c, 0xe762c2b9),
++     TOBN(0xb81d783e, 0x979f3925), TOBN(0x1efd130a, 0xaf4c89a7),
++     TOBN(0x525c2144, 0xfd1bf7fa), TOBN(0x4b296904, 0x1b265a9e),
++     TOBN(0xed8e9634, 0xb9db65b6), TOBN(0x35c82e32, 0x03599d8a),
++     TOBN(0xdaa7a54f, 0x403563f3), TOBN(0x9df088ad, 0x022c38ab),
++     TOBN(0xe5cfb066, 0xbb3fd30a), TOBN(0x429169da, 0xeff0354e),
++     TOBN(0x809cf852, 0x3524e36c), TOBN(0x136f4fb3, 0x0155be1d),
++     TOBN(0x4826af01, 0x1fbba712), TOBN(0x6ef0f0b4, 0x506ba1a1),
++     TOBN(0xd9928b31, 0x77aea73e), TOBN(0xe2bf6af2, 0x5eaa244e),
++     TOBN(0x8d084f12, 0x4237b64b), TOBN(0x688ebe99, 0xe3ecfd07),
++     TOBN(0x57b8a70c, 0xf6845dd8), TOBN(0x808fc59c, 0x5da4a325),
++     TOBN(0xa9032b2b, 0xa3585862), TOBN(0xb66825d5, 0xedf29386),
++     TOBN(0xb5a5a8db, 0x431ec29b), TOBN(0xbb143a98, 0x3a1e8dc8),
++     TOBN(0x35ee94ce, 0x12ae381b), TOBN(0x3a7f176c, 0x86ccda90),
++     TOBN(0xc63a657e, 0x4606eaca), TOBN(0x9ae5a380, 0x43cd04df),
++     TOBN(0x9bec8d15, 0xed251b46), TOBN(0x1f5d6d30, 0xcaca5e64),
++     TOBN(0x347b3b35, 0x9ff20f07), TOBN(0x4d65f034, 0xf7e4b286),
++     TOBN(0x9e93ba24, 0xf111661e), TOBN(0xedced484, 0xb105eb04),
++     TOBN(0x96dc9ba1, 0xf424b578), TOBN(0xbf8f66b7, 0xe83e9069),
++     TOBN(0x872d4df4, 0xd7ed8216), TOBN(0xbf07f377, 0x8e2cbecf),
++     TOBN(0x4281d899, 0x98e73754), TOBN(0xfec85fbb, 0x8aab8708),
++     TOBN(0x9a3c0dee, 0xa5ba5b0b), TOBN(0xe6a116ce, 0x42d05299),
++     TOBN(0xae9775fe, 0xe9b02d42), TOBN(0x72b05200, 0xa1545cb6),
++     TOBN(0xbc506f7d, 0x31a3b4ea), TOBN(0xe5893078, 0x8bbd9b32),
++     TOBN(0xc8bc5f37, 0xe4b12a97), TOBN(0x6b000c06, 0x4a73b671),
++     TOBN(0x13b5bf22, 0x765fa7d0), TOBN(0x59805bf0, 0x1d6a5370),
++     TOBN(0x67a5e29d, 0x4280db98), TOBN(0x4f53916f, 0x776b1ce3),
++     TOBN(0x714ff61f, 0x33ddf626), TOBN(0x4206238e, 0xa085d103),
++     TOBN(0x1c50d4b7, 0xe5809ee3), TOBN(0x999f450d, 0x85f8eb1d),
++     TOBN(0x658a6051, 0xe4c79e9b), TOBN(0x1394cb73, 0xc66a9fea),
++     TOBN(0x27f31ed5, 0xc6be7b23), TOBN(0xf4c88f36, 0x5aa6f8fe),
++     TOBN(0x0fb0721f, 0x4aaa499e), TOBN(0x68b3a7d5, 0xe3fb2a6b),
++     TOBN(0xa788097d, 0x3a92851d), TOBN(0x060e7f8a, 0xe96f4913),
++     TOBN(0x82eebe73, 0x1a3a93bc), TOBN(0x42bbf465, 0xa21adc1a),
++     TOBN(0xc10b6fa4, 0xef030efd), TOBN(0x247aa4c7, 0x87b097bb),
++     TOBN(0x8b8dc632, 0xf60c77da), TOBN(0x6ffbc26a, 0xc223523e),
++     TOBN(0xa4f6ff11, 0x344579cf), TOBN(0x5825653c, 0x980250f6),
++     TOBN(0xb2dd097e, 0xbc1aa2b9), TOBN(0x07889393, 0x37a0333a),
++     TOBN(0x1cf55e71, 0x37a0db38), TOBN(0x2648487f, 0x792c1613),
++     TOBN(0xdad01336, 0x3fcef261), TOBN(0x6239c81d, 0x0eabf129),
++     TOBN(0x8ee761de, 0x9d276be2), TOBN(0x406a7a34, 0x1eda6ad3),
++     TOBN(0x4bf367ba, 0x4a493b31), TOBN(0x54f20a52, 0x9bf7f026),
++     TOBN(0xb696e062, 0x9795914b), TOBN(0xcddab96d, 0x8bf236ac),
++     TOBN(0x4ff2c70a, 0xed25ea13), TOBN(0xfa1d09eb, 0x81cbbbe7),
++     TOBN(0x88fc8c87, 0x468544c5), TOBN(0x847a670d, 0x696b3317),
++     TOBN(0xf133421e, 0x64bcb626), TOBN(0xaea638c8, 0x26dee0b5),
++     TOBN(0xd6e7680b, 0xb310346c), TOBN(0xe06f4097, 0xd5d4ced3),
++     TOBN(0x09961452, 0x7512a30b), TOBN(0xf3d867fd, 0xe589a59a),
++     TOBN(0x2e73254f, 0x52d0c180), TOBN(0x9063d8a3, 0x333c74ac),
++     TOBN(0xeda6c595, 0xd314e7bc), TOBN(0x2ee7464b, 0x467899ed),
++     TOBN(0x1cef423c, 0x0a1ed5d3), TOBN(0x217e76ea, 0x69cc7613),
++     TOBN(0x27ccce1f, 0xe7cda917), TOBN(0x12d8016b, 0x8a893f16),
++     TOBN(0xbcd6de84, 0x9fc74f6b), TOBN(0xfa5817e2, 0xf3144e61),
++     TOBN(0x1f354164, 0x0821ee4c), TOBN(0x1583eab4, 0x0bc61992),
++     TOBN(0x7490caf6, 0x1d72879f), TOBN(0x998ad9f3, 0xf76ae7b2),
++     TOBN(0x1e181950, 0xa41157f7), TOBN(0xa9d7e1e6, 0xe8da3a7e),
++     TOBN(0x963784eb, 0x8426b95f), TOBN(0x0ee4ed6e, 0x542e2a10),
++     TOBN(0xb79d4cc5, 0xac751e7b), TOBN(0x93f96472, 0xfd4211bd),
++     TOBN(0x8c72d3d2, 0xc8de4fc6), TOBN(0x7b69cbf5, 0xdf44f064),
++     TOBN(0x3da90ca2, 0xf4bf94e1), TOBN(0x1a5325f8, 0xf12894e2),
++     TOBN(0x0a437f6c, 0x7917d60b), TOBN(0x9be70486, 0x96c9cb5d),
++     TOBN(0xb4d880bf, 0xe1dc5c05), TOBN(0xd738adda, 0xeebeeb57),
++     TOBN(0x6f0119d3, 0xdf0fe6a3), TOBN(0x5c686e55, 0x66eaaf5a),
++     TOBN(0x9cb10b50, 0xdfd0b7ec), TOBN(0xbdd0264b, 0x6a497c21),
++     TOBN(0xfc093514, 0x8c546c96), TOBN(0x58a947fa, 0x79dbf42a),
++     TOBN(0xc0b48d4e, 0x49ccd6d7), TOBN(0xff8fb02c, 0x88bd5580),
++     TOBN(0xc75235e9, 0x07d473b2), TOBN(0x4fab1ac5, 0xa2188af3),
++     TOBN(0x030fa3bc, 0x97576ec0), TOBN(0xe8c946e8, 0x0b7e7d2f),
++     TOBN(0x40a5c9cc, 0x70305600), TOBN(0x6d8260a9, 0xc8b013b4),
++     TOBN(0x0368304f, 0x70bba85c), TOBN(0xad090da1, 0xa4a0d311),
++     TOBN(0x7170e870, 0x2415eec1), TOBN(0xbfba35fe, 0x8461ea47),
++     TOBN(0x6279019a, 0xc1e91938), TOBN(0xa47638f3, 0x1afc415f),
++     TOBN(0x36c65cbb, 0xbcba0e0f), TOBN(0x02160efb, 0x034e2c48),
++     TOBN(0xe6c51073, 0x615cd9e4), TOBN(0x498ec047, 0xf1243c06),
++     TOBN(0x3e5a8809, 0xb17b3d8c), TOBN(0x5cd99e61, 0x0cc565f1),
++     TOBN(0x81e312df, 0x7851dafe), TOBN(0xf156f5ba, 0xa79061e2),
++     TOBN(0x80d62b71, 0x880c590e), TOBN(0xbec9746f, 0x0a39faa1),
++     TOBN(0x1d98a9c1, 0xc8ed1f7a), TOBN(0x09e43bb5, 0xa81d5ff2),
++     TOBN(0xd5f00f68, 0x0da0794a), TOBN(0x412050d9, 0x661aa836),
++     TOBN(0xa89f7c4e, 0x90747e40), TOBN(0x6dc05ebb, 0xb62a3686),
++     TOBN(0xdf4de847, 0x308e3353), TOBN(0x53868fbb, 0x9fb53bb9),
++     TOBN(0x2b09d2c3, 0xcfdcf7dd), TOBN(0x41a9fce3, 0x723fcab4),
++     TOBN(0x73d905f7, 0x07f57ca3), TOBN(0x080f9fb1, 0xac8e1555),
++     TOBN(0x7c088e84, 0x9ba7a531), TOBN(0x07d35586, 0xed9a147f),
++     TOBN(0x602846ab, 0xaf48c336), TOBN(0x7320fd32, 0x0ccf0e79),
++     TOBN(0xaa780798, 0xb18bd1ff), TOBN(0x52c2e300, 0xafdd2905),
++     TOBN(0xf27ea3d6, 0x434267cd), TOBN(0x8b96d16d, 0x15605b5f),
++     TOBN(0x7bb31049, 0x4b45706b), TOBN(0xe7f58b8e, 0x743d25f8),
++     TOBN(0xe9b5e45b, 0x87f30076), TOBN(0xd19448d6, 0x5d053d5a),
++     TOBN(0x1ecc8cb9, 0xd3210a04), TOBN(0x6bc7d463, 0xdafb5269),
++     TOBN(0x3e59b10a, 0x67c3489f), TOBN(0x1769788c, 0x65641e1b),
++     TOBN(0x8a53b82d, 0xbd6cb838), TOBN(0x7066d6e6, 0x236d5f22),
++     TOBN(0x03aa1c61, 0x6908536e), TOBN(0xc971da0d, 0x66ae9809),
++     TOBN(0x01b3a86b, 0xc49a2fac), TOBN(0x3b8420c0, 0x3092e77a),
++     TOBN(0x02057300, 0x7d6fb556), TOBN(0x6941b2a1, 0xbff40a87),
++     TOBN(0x140b6308, 0x0658ff2a), TOBN(0x87804363, 0x3424ab36),
++     TOBN(0x0253bd51, 0x5751e299), TOBN(0xc75bcd76, 0x449c3e3a),
++     TOBN(0x92eb4090, 0x7f8f875d), TOBN(0x9c9d754e, 0x56c26bbf),
++     TOBN(0x158cea61, 0x8110bbe7), TOBN(0x62a6b802, 0x745f91ea),
++     TOBN(0xa79c41aa, 0xc6e7394b), TOBN(0x445b6a83, 0xad57ef10),
++     TOBN(0x0c5277eb, 0x6ea6f40c), TOBN(0x319fe96b, 0x88633365),
++     TOBN(0x0b0fc61f, 0x385f63cb), TOBN(0x41250c84, 0x22bdd127),
++     TOBN(0x67d153f1, 0x09e942c2), TOBN(0x60920d08, 0xc021ad5d),
++     TOBN(0x229f5746, 0x724d81a5), TOBN(0xb7ffb892, 0x5bba3299),
++     TOBN(0x518c51a1, 0xde413032), TOBN(0x2a9bfe77, 0x3c2fd94c),
++     TOBN(0xcbcde239, 0x3191f4fd), TOBN(0x43093e16, 0xd3d6ada1),
++     TOBN(0x184579f3, 0x58769606), TOBN(0x2c94a8b3, 0xd236625c),
++     TOBN(0x6922b9c0, 0x5c437d8e), TOBN(0x3d4ae423, 0xd8d9f3c8),
++     TOBN(0xf72c31c1, 0x2e7090a2), TOBN(0x4ac3f5f3, 0xd76a55bd),
++     TOBN(0x342508fc, 0x6b6af991), TOBN(0x0d527100, 0x1b5cebbd),
++     TOBN(0xb84740d0, 0xdd440dd7), TOBN(0x748ef841, 0x780162fd),
++     TOBN(0xa8dbfe0e, 0xdfc6fafb), TOBN(0xeadfdf05, 0xf7300f27),
++     TOBN(0x7d06555f, 0xfeba4ec9), TOBN(0x12c56f83, 0x9e25fa97),
++     TOBN(0x77f84203, 0xd39b8c34), TOBN(0xed8b1be6, 0x3125eddb),
++     TOBN(0x5bbf2441, 0xf6e39dc5), TOBN(0xb00f6ee6, 0x6a5d678a),
++     TOBN(0xba456ecf, 0x57d0ea99), TOBN(0xdcae0f58, 0x17e06c43),
++     TOBN(0x01643de4, 0x0f5b4baa), TOBN(0x2c324341, 0xd161b9be),
++     TOBN(0x80177f55, 0xe126d468), TOBN(0xed325f1f, 0x76748e09),
++     TOBN(0x6116004a, 0xcfa9bdc2), TOBN(0x2d8607e6, 0x3a9fb468),
++     TOBN(0x0e573e27, 0x6009d660), TOBN(0x3a525d2e, 0x8d10c5a1),
++     TOBN(0xd26cb45c, 0x3b9009a0), TOBN(0xb6b0cdc0, 0xde9d7448),
++     TOBN(0x949c9976, 0xe1337c26), TOBN(0x6faadebd, 0xd73d68e5),
++     TOBN(0x9e158614, 0xf1b768d9), TOBN(0x22dfa557, 0x9cc4f069),
++     TOBN(0xccd6da17, 0xbe93c6d6), TOBN(0x24866c61, 0xa504f5b9),
++     TOBN(0x2121353c, 0x8d694da1), TOBN(0x1c6ca580, 0x0140b8c6),
++     TOBN(0xc245ad8c, 0xe964021e), TOBN(0xb83bffba, 0x032b82b3),
++     TOBN(0xfaa220c6, 0x47ef9898), TOBN(0x7e8d3ac6, 0x982c948a),
++     TOBN(0x1faa2091, 0xbc2d124a), TOBN(0xbd54c3dd, 0x05b15ff4),
++     TOBN(0x386bf3ab, 0xc87c6fb7), TOBN(0xfb2b0563, 0xfdeb6f66),
++     TOBN(0x4e77c557, 0x5b45afb4), TOBN(0xe9ded649, 0xefb8912d),
++     TOBN(0x7ec9bbf5, 0x42f6e557), TOBN(0x2570dfff, 0x62671f00),
++     TOBN(0x2b3bfb78, 0x88e084bd), TOBN(0xa024b238, 0xf37fe5b4),
++     TOBN(0x44e7dc04, 0x95649aee), TOBN(0x498ca255, 0x5e7ec1d8),
++     TOBN(0x3bc766ea, 0xaaa07e86), TOBN(0x0db6facb, 0xf3608586),
++     TOBN(0xbadd2549, 0xbdc259c8), TOBN(0x95af3c6e, 0x041c649f),
++     TOBN(0xb36a928c, 0x02e30afb), TOBN(0x9b5356ad, 0x008a88b8),
++     TOBN(0x4b67a5f1, 0xcf1d9e9d), TOBN(0xc6542e47, 0xa5d8d8ce),
++     TOBN(0x73061fe8, 0x7adfb6cc), TOBN(0xcc826fd3, 0x98678141),
++     TOBN(0x00e758b1, 0x3c80515a), TOBN(0x6afe3247, 0x41485083),
++     TOBN(0x0fcb08b9, 0xb6ae8a75), TOBN(0xb8cf388d, 0x4acf51e1),
++     TOBN(0x344a5560, 0x6961b9d6), TOBN(0x1a6778b8, 0x6a97fd0c),
++     TOBN(0xd840fdc1, 0xecc4c7e3), TOBN(0xde9fe47d, 0x16db68cc),
++     TOBN(0xe95f89de, 0xa3e216aa), TOBN(0x84f1a6a4, 0x9594a8be),
++     TOBN(0x7ddc7d72, 0x5a7b162b), TOBN(0xc5cfda19, 0xadc817a3),
++     TOBN(0x80a5d350, 0x78b58d46), TOBN(0x93365b13, 0x82978f19),
++     TOBN(0x2e44d225, 0x26a1fc90), TOBN(0x0d6d10d2, 0x4d70705d),
++     TOBN(0xd94b6b10, 0xd70c45f4), TOBN(0x0f201022, 0xb216c079),
++     TOBN(0xcec966c5, 0x658fde41), TOBN(0xa8d2bc7d, 0x7e27601d),
++     TOBN(0xbfcce3e1, 0xff230be7), TOBN(0x3394ff6b, 0x0033ffb5),
++     TOBN(0xd890c509, 0x8132c9af), TOBN(0xaac4b0eb, 0x361e7868),
++     TOBN(0x5194ded3, 0xe82d15aa), TOBN(0x4550bd2e, 0x23ae6b7d),
++     TOBN(0x3fda318e, 0xea5399d4), TOBN(0xd989bffa, 0x91638b80),
++     TOBN(0x5ea124d0, 0xa14aa12d), TOBN(0x1fb1b899, 0x3667b944),
++     TOBN(0x95ec7969, 0x44c44d6a), TOBN(0x91df144a, 0x57e86137),
++     TOBN(0x915fd620, 0x73adac44), TOBN(0x8f01732d, 0x59a83801),
++     TOBN(0xec579d25, 0x3aa0a633), TOBN(0x06de5e7c, 0xc9d6d59c),
++     TOBN(0xc132f958, 0xb1ef8010), TOBN(0x29476f96, 0xe65c1a02),
++     TOBN(0x336a77c0, 0xd34c3565), TOBN(0xef1105b2, 0x1b9f1e9e),
++     TOBN(0x63e6d08b, 0xf9e08002), TOBN(0x9aff2f21, 0xc613809e),
++     TOBN(0xb5754f85, 0x3a80e75d), TOBN(0xde71853e, 0x6bbda681),
++     TOBN(0x86f041df, 0x8197fd7a), TOBN(0x8b332e08, 0x127817fa),
++     TOBN(0x05d99be8, 0xb9c20cda), TOBN(0x89f7aad5, 0xd5cd0c98),
++     TOBN(0x7ef936fe, 0x5bb94183), TOBN(0x92ca0753, 0xb05cd7f2),
++     TOBN(0x9d65db11, 0x74a1e035), TOBN(0x02628cc8, 0x13eaea92),
++     TOBN(0xf2d9e242, 0x49e4fbf2), TOBN(0x94fdfd9b, 0xe384f8b7),
++     TOBN(0x65f56054, 0x63428c6b), TOBN(0x2f7205b2, 0x90b409a5),
++     TOBN(0xf778bb78, 0xff45ae11), TOBN(0xa13045be, 0xc5ee53b2),
++     TOBN(0xe00a14ff, 0x03ef77fe), TOBN(0x689cd59f, 0xffef8bef),
++     TOBN(0x3578f0ed, 0x1e9ade22), TOBN(0xe99f3ec0, 0x6268b6a8),
++     TOBN(0xa2057d91, 0xea1b3c3e), TOBN(0x2d1a7053, 0xb8823a4a),
++     TOBN(0xabbb336a, 0x2cca451e), TOBN(0xcd2466e3, 0x2218bb5d),
++     TOBN(0x3ac1f42f, 0xc8cb762d), TOBN(0x7e312aae, 0x7690211f),
++     TOBN(0xebb9bd73, 0x45d07450), TOBN(0x207c4b82, 0x46c2213f),
++     TOBN(0x99d425c1, 0x375913ec), TOBN(0x94e45e96, 0x67908220),
++     TOBN(0xc08f3087, 0xcd67dbf6), TOBN(0xa5670fbe, 0xc0887056),
++     TOBN(0x6717b64a, 0x66f5b8fc), TOBN(0xd5a56aea, 0x786fec28),
++     TOBN(0xa8c3f55f, 0xc0ff4952), TOBN(0xa77fefae, 0x457ac49b),
++     TOBN(0x29882d7c, 0x98379d44), TOBN(0xd000bdfb, 0x509edc8a),
++     TOBN(0xc6f95979, 0xe66fe464), TOBN(0x504a6115, 0xfa61bde0),
++     TOBN(0x56b3b871, 0xeffea31a), TOBN(0x2d3de26d, 0xf0c21a54),
++     TOBN(0x21dbff31, 0x834753bf), TOBN(0xe67ecf49, 0x69269d86),
++     TOBN(0x7a176952, 0x151fe690), TOBN(0x03515804, 0x7f2adb5f),
++     TOBN(0xee794b15, 0xd1b62a8d), TOBN(0xf004ceec, 0xaae454e6),
++     TOBN(0x0897ea7c, 0xf0386fac), TOBN(0x3b62ff12, 0xd1fca751),
++     TOBN(0x154181df, 0x1b7a04ec), TOBN(0x2008e04a, 0xfb5847ec),
++     TOBN(0xd147148e, 0x41dbd772), TOBN(0x2b419f73, 0x22942654),
++     TOBN(0x669f30d3, 0xe9c544f7), TOBN(0x52a2c223, 0xc8540149),
++     TOBN(0x5da9ee14, 0x634dfb02), TOBN(0x5f074ff0, 0xf47869f3),
++     TOBN(0x74ee878d, 0xa3933acc), TOBN(0xe6510651, 0x4fe35ed1),
++     TOBN(0xb3eb9482, 0xf1012e7a), TOBN(0x51013cc0, 0xa8a566ae),
++     TOBN(0xdd5e9243, 0x47c00d3b), TOBN(0x7fde089d, 0x946bb0e5),
++     TOBN(0x030754fe, 0xc731b4b3), TOBN(0x12a136a4, 0x99fda062),
++     TOBN(0x7c1064b8, 0x5a1a35bc), TOBN(0xbf1f5763, 0x446c84ef),
++     TOBN(0xed29a56d, 0xa16d4b34), TOBN(0x7fba9d09, 0xdca21c4f),
++     TOBN(0x66d7ac00, 0x6d8de486), TOBN(0x60061987, 0x73a2a5e1),
++     TOBN(0x8b400f86, 0x9da28ff0), TOBN(0x3133f708, 0x43c4599c),
++     TOBN(0x9911c9b8, 0xee28cb0d), TOBN(0xcd7e2874, 0x8e0af61d),
++     TOBN(0x5a85f0f2, 0x72ed91fc), TOBN(0x85214f31, 0x9cd4a373),
++     TOBN(0x881fe5be, 0x1925253c), TOBN(0xd8dc98e0, 0x91e8bc76),
++     TOBN(0x7120affe, 0x585cc3a2), TOBN(0x724952ed, 0x735bf97a),
++     TOBN(0x5581e7dc, 0x3eb34581), TOBN(0x5cbff4f2, 0xe52ee57d),
++     TOBN(0x8d320a0e, 0x87d8cc7b), TOBN(0x9beaa7f3, 0xf1d280d0),
++     TOBN(0x7a0b9571, 0x9beec704), TOBN(0x9126332e, 0x5b7f0057),
++     TOBN(0x01fbc1b4, 0x8ed3bd6d), TOBN(0x35bb2c12, 0xd945eb24),
++     TOBN(0x6404694e, 0x9a8ae255), TOBN(0xb6092eec, 0x8d6abfb3),
++     TOBN(0x4d76143f, 0xcc058865), TOBN(0x7b0a5af2, 0x6e249922),
++     TOBN(0x8aef9440, 0x6a50d353), TOBN(0xe11e4bcc, 0x64f0e07a),
++     TOBN(0x4472993a, 0xa14a90fa), TOBN(0x7706e20c, 0xba0c51d4),
++     TOBN(0xf403292f, 0x1532672d), TOBN(0x52573bfa, 0x21829382),
++     TOBN(0x6a7bb6a9, 0x3b5bdb83), TOBN(0x08da65c0, 0xa4a72318),
++     TOBN(0xc58d22aa, 0x63eb065f), TOBN(0x1717596c, 0x1b15d685),
++     TOBN(0x112df0d0, 0xb266d88b), TOBN(0xf688ae97, 0x5941945a),
++     TOBN(0x487386e3, 0x7c292cac), TOBN(0x42f3b50d, 0x57d6985c),
++     TOBN(0x6da4f998, 0x6a90fc34), TOBN(0xc8f257d3, 0x65ca8a8d),
++     TOBN(0xc2feabca, 0x6951f762), TOBN(0xe1bc81d0, 0x74c323ac),
++     TOBN(0x1bc68f67, 0x251a2a12), TOBN(0x10d86587, 0xbe8a70dc),
++     TOBN(0xd648af7f, 0xf0f84d2e), TOBN(0xf0aa9ebc, 0x6a43ac92),
++     TOBN(0x69e3be04, 0x27596893), TOBN(0xb6bb02a6, 0x45bf452b),
++     TOBN(0x0875c11a, 0xf4c698c8), TOBN(0x6652b5c7, 0xbece3794),
++     TOBN(0x7b3755fd, 0x4f5c0499), TOBN(0x6ea16558, 0xb5532b38),
++     TOBN(0xd1c69889, 0xa2e96ef7), TOBN(0x9c773c3a, 0x61ed8f48),
++     TOBN(0x2b653a40, 0x9b323abc), TOBN(0xe26605e1, 0xf0e1d791),
++     TOBN(0x45d41064, 0x4a87157a), TOBN(0x8f9a78b7, 0xcbbce616),
++     TOBN(0xcf1e44aa, 0xc407eddd), TOBN(0x81ddd1d8, 0xa35b964f),
++     TOBN(0x473e339e, 0xfd083999), TOBN(0x6c94bdde, 0x8e796802),
++     TOBN(0x5a304ada, 0x8545d185), TOBN(0x82ae44ea, 0x738bb8cb),
++     TOBN(0x628a35e3, 0xdf87e10e), TOBN(0xd3624f3d, 0xa15b9fe3),
++     TOBN(0xcc44209b, 0x14be4254), TOBN(0x7d0efcbc, 0xbdbc2ea5),
++     TOBN(0x1f603362, 0x04c37bbe), TOBN(0x21f363f5, 0x56a5852c),
++     TOBN(0xa1503d1c, 0xa8501550), TOBN(0x2251e0e1, 0xd8ab10bb),
++     TOBN(0xde129c96, 0x6961c51c), TOBN(0x1f7246a4, 0x81910f68),
++     TOBN(0x2eb744ee, 0x5f2591f2), TOBN(0x3c47d33f, 0x5e627157),
++     TOBN(0x4d6d62c9, 0x22f3bd68), TOBN(0x6120a64b, 0xcb8df856),
++     TOBN(0x3a9ac6c0, 0x7b5d07df), TOBN(0xa92b9558, 0x7ef39783),
++     TOBN(0xe128a134, 0xab3a9b4f), TOBN(0x41c18807, 0xb1252f05),
++     TOBN(0xfc7ed089, 0x80ba9b1c), TOBN(0xac8dc6de, 0xc532a9dd),
++     TOBN(0xbf829cef, 0x55246809), TOBN(0x101b784f, 0x5b4ee80f),
++     TOBN(0xc09945bb, 0xb6f11603), TOBN(0x57b09dbe, 0x41d2801e),
++     TOBN(0xfba5202f, 0xa97534a8), TOBN(0x7fd8ae5f, 0xc17b9614),
++     TOBN(0xa50ba666, 0x78308435), TOBN(0x9572f77c, 0xd3868c4d),
++     TOBN(0x0cef7bfd, 0x2dd7aab0), TOBN(0xe7958e08, 0x2c7c79ff),
++     TOBN(0x81262e42, 0x25346689), TOBN(0x716da290, 0xb07c7004),
++     TOBN(0x35f911ea, 0xb7950ee3), TOBN(0x6fd72969, 0x261d21b5),
++     TOBN(0x52389803, 0x08b640d3), TOBN(0x5b0026ee, 0x887f12a1),
++     TOBN(0x20e21660, 0x742e9311), TOBN(0x0ef6d541, 0x5ff77ff7),
++     TOBN(0x969127f0, 0xf9c41135), TOBN(0xf21d60c9, 0x68a64993),
++     TOBN(0x656e5d0c, 0xe541875c), TOBN(0xf1e0f84e, 0xa1d3c233),
++     TOBN(0x9bcca359, 0x06002d60), TOBN(0xbe2da60c, 0x06191552),
++     TOBN(0x5da8bbae, 0x61181ec3), TOBN(0x9f04b823, 0x65806f19),
++     TOBN(0xf1604a7d, 0xd4b79bb8), TOBN(0xaee806fb, 0x52c878c8),
++     TOBN(0x34144f11, 0x8d47b8e8), TOBN(0x72edf52b, 0x949f9054),
++     TOBN(0xebfca84e, 0x2127015a), TOBN(0x9051d0c0, 0x9cb7cef3),
++     TOBN(0x86e8fe58, 0x296deec8), TOBN(0x33b28188, 0x41010d74),}
++    ,
++    {TOBN(0x01079383, 0x171b445f), TOBN(0x9bcf21e3, 0x8131ad4c),
++     TOBN(0x8cdfe205, 0xc93987e8), TOBN(0xe63f4152, 0xc92e8c8f),
++     TOBN(0x729462a9, 0x30add43d), TOBN(0x62ebb143, 0xc980f05a),
++     TOBN(0x4f3954e5, 0x3b06e968), TOBN(0xfe1d75ad, 0x242cf6b1),
++     TOBN(0x5f95c6c7, 0xaf8685c8), TOBN(0xd4c1c8ce, 0x2f8f01aa),
++     TOBN(0xc44bbe32, 0x2574692a), TOBN(0xb8003478, 0xd4a4a068),
++     TOBN(0x7c8fc6e5, 0x2eca3cdb), TOBN(0xea1db16b, 0xec04d399),
++     TOBN(0xb05bc82e, 0x8f2bc5cf), TOBN(0x763d517f, 0xf44793d2),
++     TOBN(0x4451c1b8, 0x08bd98d0), TOBN(0x644b1cd4, 0x6575f240),
++     TOBN(0x6907eb33, 0x7375d270), TOBN(0x56c8bebd, 0xfa2286bd),
++     TOBN(0xc713d2ac, 0xc4632b46), TOBN(0x17da427a, 0xafd60242),
++     TOBN(0x313065b7, 0xc95c7546), TOBN(0xf8239898, 0xbf17a3de),
++     TOBN(0xf3b7963f, 0x4c830320), TOBN(0x842c7aa0, 0x903203e3),
++     TOBN(0xaf22ca0a, 0xe7327afb), TOBN(0x38e13092, 0x967609b6),
++     TOBN(0x73b8fb62, 0x757558f1), TOBN(0x3cc3e831, 0xf7eca8c1),
++     TOBN(0xe4174474, 0xf6331627), TOBN(0xa77989ca, 0xc3c40234),
++     TOBN(0xe5fd17a1, 0x44a081e0), TOBN(0xd797fb7d, 0xb70e296a),
++     TOBN(0x2b472b30, 0x481f719c), TOBN(0x0e632a98, 0xfe6f8c52),
++     TOBN(0x89ccd116, 0xc5f0c284), TOBN(0xf51088af, 0x2d987c62),
++     TOBN(0x2a2bccda, 0x4c2de6cf), TOBN(0x810f9efe, 0xf679f0f9),
++     TOBN(0xb0f394b9, 0x7ffe4b3e), TOBN(0x0b691d21, 0xe5fa5d21),
++     TOBN(0xb0bd7747, 0x9dfbbc75), TOBN(0xd2830fda, 0xfaf78b00),
++     TOBN(0xf78c249c, 0x52434f57), TOBN(0x4b1f7545, 0x98096dab),
++     TOBN(0x73bf6f94, 0x8ff8c0b3), TOBN(0x34aef03d, 0x454e134c),
++     TOBN(0xf8d151f4, 0xb7ac7ec5), TOBN(0xd6ceb95a, 0xe50da7d5),
++     TOBN(0xa1b492b0, 0xdc3a0eb8), TOBN(0x75157b69, 0xb3dd2863),
++     TOBN(0xe2c4c74e, 0xc5413d62), TOBN(0xbe329ff7, 0xbc5fc4c7),
++     TOBN(0x835a2aea, 0x60fa9dda), TOBN(0xf117f5ad, 0x7445cb87),
++     TOBN(0xae8317f4, 0xb0166f7a), TOBN(0xfbd3e3f7, 0xceec74e6),
++     TOBN(0xfdb516ac, 0xe0874bfd), TOBN(0x3d846019, 0xc681f3a3),
++     TOBN(0x0b12ee5c, 0x7c1620b0), TOBN(0xba68b4dd, 0x2b63c501),
++     TOBN(0xac03cd32, 0x6668c51e), TOBN(0x2a6279f7, 0x4e0bcb5b),
++     TOBN(0x17bd69b0, 0x6ae85c10), TOBN(0x72946979, 0x1dfdd3a6),
++     TOBN(0xd9a03268, 0x2c078bec), TOBN(0x41c6a658, 0xbfd68a52),
++     TOBN(0xcdea1024, 0x0e023900), TOBN(0xbaeec121, 0xb10d144d),
++     TOBN(0x5a600e74, 0x058ab8dc), TOBN(0x1333af21, 0xbb89ccdd),
++     TOBN(0xdf25eae0, 0x3aaba1f1), TOBN(0x2cada16e, 0x3b7144cf),
++     TOBN(0x657ee27d, 0x71ab98bc), TOBN(0x99088b4c, 0x7a6fc96e),
++     TOBN(0x05d5c0a0, 0x3549dbd4), TOBN(0x42cbdf8f, 0xf158c3ac),
++     TOBN(0x3fb6b3b0, 0x87edd685), TOBN(0x22071cf6, 0x86f064d0),
++     TOBN(0xd2d6721f, 0xff2811e5), TOBN(0xdb81b703, 0xfe7fae8c),
++     TOBN(0x3cfb74ef, 0xd3f1f7bb), TOBN(0x0cdbcd76, 0x16cdeb5d),
++     TOBN(0x4f39642a, 0x566a808c), TOBN(0x02b74454, 0x340064d6),
++     TOBN(0xfabbadca, 0x0528fa6f), TOBN(0xe4c3074c, 0xd3fc0bb6),
++     TOBN(0xb32cb8b0, 0xb796d219), TOBN(0xc3e95f4f, 0x34741dd9),
++     TOBN(0x87212125, 0x68edf6f5), TOBN(0x7a03aee4, 0xa2b9cb8e),
++     TOBN(0x0cd3c376, 0xf53a89aa), TOBN(0x0d8af9b1, 0x948a28dc),
++     TOBN(0xcf86a3f4, 0x902ab04f), TOBN(0x8aacb62a, 0x7f42002d),
++     TOBN(0x106985eb, 0xf62ffd52), TOBN(0xe670b54e, 0x5797bf10),
++     TOBN(0x4b405209, 0xc5e30aef), TOBN(0x12c97a20, 0x4365b5e9),
++     TOBN(0x104646ce, 0x1fe32093), TOBN(0x13cb4ff6, 0x3907a8c9),
++     TOBN(0x8b9f30d1, 0xd46e726b), TOBN(0xe1985e21, 0xaba0f499),
++     TOBN(0xc573dea9, 0x10a230cd), TOBN(0x24f46a93, 0xcd30f947),
++     TOBN(0xf2623fcf, 0xabe2010a), TOBN(0x3f278cb2, 0x73f00e4f),
++     TOBN(0xed55c67d, 0x50b920eb), TOBN(0xf1cb9a2d, 0x8e760571),
++     TOBN(0x7c50d109, 0x0895b709), TOBN(0x4207cf07, 0x190d4369),
++     TOBN(0x3b027e81, 0xc4127fe1), TOBN(0xa9f8b9ad, 0x3ae9c566),
++     TOBN(0x5ab10851, 0xacbfbba5), TOBN(0xa747d648, 0x569556f5),
++     TOBN(0xcc172b5c, 0x2ba97bf7), TOBN(0x15e0f77d, 0xbcfa3324),
++     TOBN(0xa345b797, 0x7686279d), TOBN(0x5a723480, 0xe38003d3),
++     TOBN(0xfd8e139f, 0x8f5fcda8), TOBN(0xf3e558c4, 0xbdee5bfd),
++     TOBN(0xd76cbaf4, 0xe33f9f77), TOBN(0x3a4c97a4, 0x71771969),
++     TOBN(0xda27e84b, 0xf6dce6a7), TOBN(0xff373d96, 0x13e6c2d1),
++     TOBN(0xf115193c, 0xd759a6e9), TOBN(0x3f9b7025, 0x63d2262c),
++     TOBN(0xd9764a31, 0x317cd062), TOBN(0x30779d8e, 0x199f8332),
++     TOBN(0xd8074106, 0x16b11b0b), TOBN(0x7917ab9f, 0x78aeaed8),
++     TOBN(0xb67a9cbe, 0x28fb1d8e), TOBN(0x2e313563, 0x136eda33),
++     TOBN(0x010b7069, 0xa371a86c), TOBN(0x44d90fa2, 0x6744e6b7),
++     TOBN(0x68190867, 0xd6b3e243), TOBN(0x9fe6cd9d, 0x59048c48),
++     TOBN(0xb900b028, 0x95731538), TOBN(0xa012062f, 0x32cae04f),
++     TOBN(0x8107c8bc, 0x9399d082), TOBN(0x47e8c54a, 0x41df12e2),
++     TOBN(0x14ba5117, 0xb6ef3f73), TOBN(0x22260bea, 0x81362f0b),
++     TOBN(0x90ea261e, 0x1a18cc20), TOBN(0x2192999f, 0x2321d636),
++     TOBN(0xef64d314, 0xe311b6a0), TOBN(0xd7401e4c, 0x3b54a1f5),
++     TOBN(0x19019983, 0x6fbca2ba), TOBN(0x46ad3293, 0x8fbffc4b),
++     TOBN(0xa142d3f6, 0x3786bf40), TOBN(0xeb5cbc26, 0xb67039fc),
++     TOBN(0x9cb0ae6c, 0x252bd479), TOBN(0x05e0f88a, 0x12b5848f),
++     TOBN(0x78f6d2b2, 0xa5c97663), TOBN(0x6f6e149b, 0xc162225c),
++     TOBN(0xe602235c, 0xde601a89), TOBN(0xd17bbe98, 0xf373be1f),
++     TOBN(0xcaf49a5b, 0xa8471827), TOBN(0x7e1a0a85, 0x18aaa116),
++     TOBN(0x6c833196, 0x270580c3), TOBN(0x1e233839, 0xf1c98a14),
++     TOBN(0x67b2f7b4, 0xae34e0a5), TOBN(0x47ac8745, 0xd8ce7289),
++     TOBN(0x2b74779a, 0x100dd467), TOBN(0x274a4337, 0x4ee50d09),
++     TOBN(0x603dcf13, 0x83608bc9), TOBN(0xcd9da6c3, 0xc89e8388),
++     TOBN(0x2660199f, 0x355116ac), TOBN(0xcc38bb59, 0xb6d18eed),
++     TOBN(0x3075f31f, 0x2f4bc071), TOBN(0x9774457f, 0x265dc57e),
++     TOBN(0x06a6a9c8, 0xc6db88bb), TOBN(0x6429d07f, 0x4ec98e04),
++     TOBN(0x8d05e57b, 0x05ecaa8b), TOBN(0x20f140b1, 0x7872ea7b),
++     TOBN(0xdf8c0f09, 0xca494693), TOBN(0x48d3a020, 0xf252e909),
++     TOBN(0x4c5c29af, 0x57b14b12), TOBN(0x7e6fa37d, 0xbf47ad1c),
++     TOBN(0x66e7b506, 0x49a0c938), TOBN(0xb72c0d48, 0x6be5f41f),
++     TOBN(0x6a6242b8, 0xb2359412), TOBN(0xcd35c774, 0x8e859480),
++     TOBN(0x12536fea, 0x87baa627), TOBN(0x58c1fec1, 0xf72aa680),
++     TOBN(0x6c29b637, 0x601e5dc9), TOBN(0x9e3c3c1c, 0xde9e01b9),
++     TOBN(0xefc8127b, 0x2bcfe0b0), TOBN(0x35107102, 0x2a12f50d),
++     TOBN(0x6ccd6cb1, 0x4879b397), TOBN(0xf792f804, 0xf8a82f21),
++     TOBN(0x509d4804, 0xa9b46402), TOBN(0xedddf85d, 0xc10f0850),
++     TOBN(0x928410dc, 0x4b6208aa), TOBN(0xf6229c46, 0x391012dc),
++     TOBN(0xc5a7c41e, 0x7727b9b6), TOBN(0x289e4e4b, 0xaa444842),
++     TOBN(0x049ba1d9, 0xe9a947ea), TOBN(0x44f9e47f, 0x83c8debc),
++     TOBN(0xfa77a1fe, 0x611f8b8e), TOBN(0xfd2e416a, 0xf518f427),
++     TOBN(0xc5fffa70, 0x114ebac3), TOBN(0xfe57c4e9, 0x5d89697b),
++     TOBN(0xfdd053ac, 0xb1aaf613), TOBN(0x31df210f, 0xea585a45),
++     TOBN(0x318cc10e, 0x24985034), TOBN(0x1a38efd1, 0x5f1d6130),
++     TOBN(0xbf86f237, 0x0b1e9e21), TOBN(0xb258514d, 0x1dbe88aa),
++     TOBN(0x1e38a588, 0x90c1baf9), TOBN(0x2936a01e, 0xbdb9b692),
++     TOBN(0xd576de98, 0x6dd5b20c), TOBN(0xb586bf71, 0x70f98ecf),
++     TOBN(0xcccf0f12, 0xc42d2fd7), TOBN(0x8717e61c, 0xfb35bd7b),
++     TOBN(0x8b1e5722, 0x35e6fc06), TOBN(0x3477728f, 0x0b3e13d5),
++     TOBN(0x150c294d, 0xaa8a7372), TOBN(0xc0291d43, 0x3bfa528a),
++     TOBN(0xc6c8bc67, 0xcec5a196), TOBN(0xdeeb31e4, 0x5c2e8a7c),
++     TOBN(0xba93e244, 0xfb6e1c51), TOBN(0xb9f8b71b, 0x2e28e156),
++     TOBN(0xce65a287, 0x968a2ab9), TOBN(0xe3c5ce69, 0x46bbcb1f),
++     TOBN(0xf8c835b9, 0xe7ae3f30), TOBN(0x16bbee26, 0xff72b82b),
++     TOBN(0x665e2017, 0xfd42cd22), TOBN(0x1e139970, 0xf8b1d2a0),
++     TOBN(0x125cda29, 0x79204932), TOBN(0x7aee94a5, 0x49c3bee5),
++     TOBN(0x68c70160, 0x89821a66), TOBN(0xf7c37678, 0x8f981669),
++     TOBN(0xd90829fc, 0x48cc3645), TOBN(0x346af049, 0xd70addfc),
++     TOBN(0x2057b232, 0x370bf29c), TOBN(0xf90c73ce, 0x42e650ee),
++     TOBN(0xe03386ea, 0xa126ab90), TOBN(0x0e266e7e, 0x975a087b),
++     TOBN(0x80578eb9, 0x0fca65d9), TOBN(0x7e2989ea, 0x16af45b8),
++     TOBN(0x7438212d, 0xcac75a4e), TOBN(0x38c7ca39, 0x4fef36b8),
++     TOBN(0x8650c494, 0xd402676a), TOBN(0x26ab5a66, 0xf72c7c48),
++     TOBN(0x4e6cb426, 0xce3a464e), TOBN(0xf8f99896, 0x2b72f841),
++     TOBN(0x8c318491, 0x1a335cc8), TOBN(0x563459ba, 0x6a5913e4),
++     TOBN(0x1b920d61, 0xc7b32919), TOBN(0x805ab8b6, 0xa02425ad),
++     TOBN(0x2ac512da, 0x8d006086), TOBN(0x6ca4846a, 0xbcf5c0fd),
++     TOBN(0xafea51d8, 0xac2138d7), TOBN(0xcb647545, 0x344cd443),
++     TOBN(0x0429ee8f, 0xbd7d9040), TOBN(0xee66a2de, 0x819b9c96),
++     TOBN(0x54f9ec25, 0xdea7d744), TOBN(0x2ffea642, 0x671721bb),
++     TOBN(0x4f19dbd1, 0x114344ea), TOBN(0x04304536, 0xfd0dbc8b),
++     TOBN(0x014b50aa, 0x29ec7f91), TOBN(0xb5fc22fe, 0xbb06014d),
++     TOBN(0x60d963a9, 0x1ee682e0), TOBN(0xdf48abc0, 0xfe85c727),
++     TOBN(0x0cadba13, 0x2e707c2d), TOBN(0xde608d3a, 0xa645aeff),
++     TOBN(0x05f1c28b, 0xedafd883), TOBN(0x3c362ede, 0xbd94de1f),
++     TOBN(0x8dd0629d, 0x13593e41), TOBN(0x0a5e736f, 0x766d6eaf),
++     TOBN(0xbfa92311, 0xf68cf9d1), TOBN(0xa4f9ef87, 0xc1797556),
++     TOBN(0x10d75a1f, 0x5601c209), TOBN(0x651c374c, 0x09b07361),
++     TOBN(0x49950b58, 0x88b5cead), TOBN(0x0ef00058, 0x6fa9dbaa),
++     TOBN(0xf51ddc26, 0x4e15f33a), TOBN(0x1f8b5ca6, 0x2ef46140),
++     TOBN(0x343ac0a3, 0xee9523f0), TOBN(0xbb75eab2, 0x975ea978),
++     TOBN(0x1bccf332, 0x107387f4), TOBN(0x790f9259, 0x9ab0062e),
++     TOBN(0xf1a363ad, 0x1e4f6a5f), TOBN(0x06e08b84, 0x62519a50),
++     TOBN(0x60915187, 0x7265f1ee), TOBN(0x6a80ca34, 0x93ae985e),
++     TOBN(0x81b29768, 0xaaba4864), TOBN(0xb13cabf2, 0x8d52a7d6),
++     TOBN(0xb5c36348, 0x8ead03f1), TOBN(0xc932ad95, 0x81c7c1c0),
++     TOBN(0x5452708e, 0xcae1e27b), TOBN(0x9dac4269, 0x1b0df648),
++     TOBN(0x233e3f0c, 0xdfcdb8bc), TOBN(0xe6ceccdf, 0xec540174),
++     TOBN(0xbd0d845e, 0x95081181), TOBN(0xcc8a7920, 0x699355d5),
++     TOBN(0x111c0f6d, 0xc3b375a8), TOBN(0xfd95bc6b, 0xfd51e0dc),
++     TOBN(0x4a106a26, 0x6888523a), TOBN(0x4d142bd6, 0xcb01a06d),
++     TOBN(0x79bfd289, 0xadb9b397), TOBN(0x0bdbfb94, 0xe9863914),
++     TOBN(0x29d8a229, 0x1660f6a6), TOBN(0x7f6abcd6, 0x551c042d),
++     TOBN(0x13039deb, 0x0ac3ffe8), TOBN(0xa01be628, 0xec8523fb),
++     TOBN(0x6ea34103, 0x0ca1c328), TOBN(0xc74114bd, 0xb903928e),
++     TOBN(0x8aa4ff4e, 0x9e9144b0), TOBN(0x7064091f, 0x7f9a4b17),
++     TOBN(0xa3f4f521, 0xe447f2c4), TOBN(0x81b8da7a, 0x604291f0),
++     TOBN(0xd680bc46, 0x7d5926de), TOBN(0x84f21fd5, 0x34a1202f),
++     TOBN(0x1d1e3181, 0x4e9df3d8), TOBN(0x1ca4861a, 0x39ab8d34),
++     TOBN(0x809ddeec, 0x5b19aa4a), TOBN(0x59f72f7e, 0x4d329366),
++     TOBN(0xa2f93f41, 0x386d5087), TOBN(0x40bf739c, 0xdd67d64f),
++     TOBN(0xb4494205, 0x66702158), TOBN(0xc33c65be, 0x73b1e178),
++     TOBN(0xcdcd657c, 0x38ca6153), TOBN(0x97f4519a, 0xdc791976),
++     TOBN(0xcc7c7f29, 0xcd6e1f39), TOBN(0x38de9cfb, 0x7e3c3932),
++     TOBN(0xe448eba3, 0x7b793f85), TOBN(0xe9f8dbf9, 0xf067e914),
++     TOBN(0xc0390266, 0xf114ae87), TOBN(0x39ed75a7, 0xcd6a8e2a),
++     TOBN(0xadb14848, 0x7ffba390), TOBN(0x67f8cb8b, 0x6af9bc09),
++     TOBN(0x322c3848, 0x9c7476db), TOBN(0xa320fecf, 0x52a538d6),
++     TOBN(0xe0493002, 0xb2aced2b), TOBN(0xdfba1809, 0x616bd430),
++     TOBN(0x531c4644, 0xc331be70), TOBN(0xbc04d32e, 0x90d2e450),
++     TOBN(0x1805a0d1, 0x0f9f142d), TOBN(0x2c44a0c5, 0x47ee5a23),
++     TOBN(0x31875a43, 0x3989b4e3), TOBN(0x6b1949fd, 0x0c063481),
++     TOBN(0x2dfb9e08, 0xbe0f4492), TOBN(0x3ff0da03, 0xe9d5e517),
++     TOBN(0x03dbe9a1, 0xf79466a8), TOBN(0x0b87bcd0, 0x15ea9932),
++     TOBN(0xeb64fc83, 0xab1f58ab), TOBN(0x6d9598da, 0x817edc8a),
++     TOBN(0x699cff66, 0x1d3b67e5), TOBN(0x645c0f29, 0x92635853),
++     TOBN(0x253cdd82, 0xeabaf21c), TOBN(0x82b9602a, 0x2241659e),
++     TOBN(0x2cae07ec, 0x2d9f7091), TOBN(0xbe4c720c, 0x8b48cd9b),
++     TOBN(0x6ce5bc03, 0x6f08d6c9), TOBN(0x36e8a997, 0xaf10bf40),
++     TOBN(0x83422d21, 0x3e10ff12), TOBN(0x7b26d3eb, 0xbcc12494),
++     TOBN(0xb240d2d0, 0xc9469ad6), TOBN(0xc4a11b4d, 0x30afa05b),
++     TOBN(0x4b604ace, 0xdd6ba286), TOBN(0x18486600, 0x3ee2864c),
++     TOBN(0x5869d6ba, 0x8d9ce5be), TOBN(0x0d8f68c5, 0xff4bfb0d),
++     TOBN(0xb69f210b, 0x5700cf73), TOBN(0x61f6653a, 0x6d37c135),
++     TOBN(0xff3d432b, 0x5aff5a48), TOBN(0x0d81c4b9, 0x72ba3a69),
++     TOBN(0xee879ae9, 0xfa1899ef), TOBN(0xbac7e2a0, 0x2d6acafd),
++     TOBN(0xd6d93f6c, 0x1c664399), TOBN(0x4c288de1, 0x5bcb135d),
++     TOBN(0x83031dab, 0x9dab7cbf), TOBN(0xfe23feb0, 0x3abbf5f0),
++     TOBN(0x9f1b2466, 0xcdedca85), TOBN(0x140bb710, 0x1a09538c),
++     TOBN(0xac8ae851, 0x5e11115d), TOBN(0x0d63ff67, 0x6f03f59e),
++     TOBN(0x755e5551, 0x7d234afb), TOBN(0x61c2db4e, 0x7e208fc1),
++     TOBN(0xaa9859ce, 0xf28a4b5d), TOBN(0xbdd6d4fc, 0x34af030f),
++     TOBN(0xd1c4a26d, 0x3be01cb1), TOBN(0x9ba14ffc, 0x243aa07c),
++     TOBN(0xf95cd3a9, 0xb2503502), TOBN(0xe379bc06, 0x7d2a93ab),
++     TOBN(0x3efc18e9, 0xd4ca8d68), TOBN(0x083558ec, 0x80bb412a),
++     TOBN(0xd903b940, 0x9645a968), TOBN(0xa499f0b6, 0x9ba6054f),
++     TOBN(0x208b573c, 0xb8349abe), TOBN(0x3baab3e5, 0x30b4fc1c),
++     TOBN(0x87e978ba, 0xcb524990), TOBN(0x3524194e, 0xccdf0e80),
++     TOBN(0x62711725, 0x7d4bcc42), TOBN(0xe90a3d9b, 0xb90109ba),
++     TOBN(0x3b1bdd57, 0x1323e1e0), TOBN(0xb78e9bd5, 0x5eae1599),
++     TOBN(0x0794b746, 0x9e03d278), TOBN(0x80178605, 0xd70e6297),
++     TOBN(0x171792f8, 0x99c97855), TOBN(0x11b393ee, 0xf5a86b5c),
++     TOBN(0x48ef6582, 0xd8884f27), TOBN(0xbd44737a, 0xbf19ba5f),
++     TOBN(0x8698de4c, 0xa42062c6), TOBN(0x8975eb80, 0x61ce9c54),
++     TOBN(0xd50e57c7, 0xd7fe71f3), TOBN(0x15342190, 0xbc97ce38),
++     TOBN(0x51bda2de, 0x4df07b63), TOBN(0xba12aeae, 0x200eb87d),
++     TOBN(0xabe135d2, 0xa9b4f8f6), TOBN(0x04619d65, 0xfad6d99c),
++     TOBN(0x4a6683a7, 0x7994937c), TOBN(0x7a778c8b, 0x6f94f09a),
++     TOBN(0x8c508623, 0x20a71b89), TOBN(0x241a2aed, 0x1c229165),
++     TOBN(0x352be595, 0xaaf83a99), TOBN(0x9fbfee7f, 0x1562bac8),
++     TOBN(0xeaf658b9, 0x5c4017e3), TOBN(0x1dc7f9e0, 0x15120b86),
++     TOBN(0xd84f13dd, 0x4c034d6f), TOBN(0x283dd737, 0xeaea3038),
++     TOBN(0x197f2609, 0xcd85d6a2), TOBN(0x6ebbc345, 0xfae60177),
++     TOBN(0xb80f031b, 0x4e12fede), TOBN(0xde55d0c2, 0x07a2186b),
++     TOBN(0x1fb3e37f, 0x24dcdd5a), TOBN(0x8d602da5, 0x7ed191fb),
++     TOBN(0x108fb056, 0x76023e0d), TOBN(0x70178c71, 0x459c20c0),
++     TOBN(0xfad5a386, 0x3fe54cf0), TOBN(0xa4a3ec4f, 0x02bbb475),
++     TOBN(0x1aa5ec20, 0x919d94d7), TOBN(0x5d3b63b5, 0xa81e4ab3),
++     TOBN(0x7fa733d8, 0x5ad3d2af), TOBN(0xfbc586dd, 0xd1ac7a37),
++     TOBN(0x282925de, 0x40779614), TOBN(0xfe0ffffb, 0xe74a242a),
++     TOBN(0x3f39e67f, 0x906151e5), TOBN(0xcea27f5f, 0x55e10649),
++     TOBN(0xdca1d4e1, 0xc17cf7b7), TOBN(0x0c326d12, 0x2fe2362d),
++     TOBN(0x05f7ac33, 0x7dd35df3), TOBN(0x0c3b7639, 0xc396dbdf),
++     TOBN(0x0912f5ac, 0x03b7db1c), TOBN(0x9dea4b70, 0x5c9ed4a9),
++     TOBN(0x475e6e53, 0xaae3f639), TOBN(0xfaba0e7c, 0xfc278bac),
++     TOBN(0x16f9e221, 0x9490375f), TOBN(0xaebf9746, 0xa5a7ed0a),
++     TOBN(0x45f9af3f, 0xf41ad5d6), TOBN(0x03c4623c, 0xb2e99224),
++     TOBN(0x82c5bb5c, 0xb3cf56aa), TOBN(0x64311819, 0x34567ed3),
++     TOBN(0xec57f211, 0x8be489ac), TOBN(0x2821895d, 0xb9a1104b),
++     TOBN(0x610dc875, 0x6064e007), TOBN(0x8e526f3f, 0x5b20d0fe),
++     TOBN(0x6e71ca77, 0x5b645aee), TOBN(0x3d1dcb9f, 0x800e10ff),
++     TOBN(0x36b51162, 0x189cf6de), TOBN(0x2c5a3e30, 0x6bb17353),
++     TOBN(0xc186cd3e, 0x2a6c6fbf), TOBN(0xa74516fa, 0x4bf97906),
++     TOBN(0x5b4b8f4b, 0x279d6901), TOBN(0x0c4e57b4, 0x2b573743),
++     TOBN(0x75fdb229, 0xb6e386b6), TOBN(0xb46793fd, 0x99deac27),
++     TOBN(0xeeec47ea, 0xcf712629), TOBN(0xe965f3c4, 0xcbc3b2dd),
++     TOBN(0x8dd1fb83, 0x425c6559), TOBN(0x7fc00ee6, 0x0af06fda),
++     TOBN(0xe98c9225, 0x33d956df), TOBN(0x0f1ef335, 0x4fbdc8a2),
++     TOBN(0x2abb5145, 0xb79b8ea2), TOBN(0x40fd2945, 0xbdbff288),
++     TOBN(0x6a814ac4, 0xd7185db7), TOBN(0xc4329d6f, 0xc084609a),
++     TOBN(0xc9ba7b52, 0xed1be45d), TOBN(0x891dd20d, 0xe4cd2c74),
++     TOBN(0x5a4d4a7f, 0x824139b1), TOBN(0x66c17716, 0xb873c710),
++     TOBN(0x5e5bc141, 0x2843c4e0), TOBN(0xd5ac4817, 0xb97eb5bf),
++     TOBN(0xc0f8af54, 0x450c95c7), TOBN(0xc91b3fa0, 0x318406c5),
++     TOBN(0x360c340a, 0xab9d97f8), TOBN(0xfb57bd07, 0x90a2d611),
++     TOBN(0x4339ae3c, 0xa6a6f7e5), TOBN(0x9c1fcd2a, 0x2feb8a10),
++     TOBN(0x972bcca9, 0xc7ea7432), TOBN(0x1b0b924c, 0x308076f6),
++     TOBN(0x80b2814a, 0x2a5b4ca5), TOBN(0x2f78f55b, 0x61ef3b29),
++     TOBN(0xf838744a, 0xc18a414f), TOBN(0xc611eaae, 0x903d0a86),
++     TOBN(0x94dabc16, 0x2a453f55), TOBN(0xe6f2e3da, 0x14efb279),
++     TOBN(0x5b7a6017, 0x9320dc3c), TOBN(0x692e382f, 0x8df6b5a4),
++     TOBN(0x3f5e15e0, 0x2d40fa90), TOBN(0xc87883ae, 0x643dd318),
++     TOBN(0x511053e4, 0x53544774), TOBN(0x834d0ecc, 0x3adba2bc),
++     TOBN(0x4215d7f7, 0xbae371f5), TOBN(0xfcfd57bf, 0x6c8663bc),
++     TOBN(0xded2383d, 0xd6901b1d), TOBN(0x3b49fbb4, 0xb5587dc3),
++     TOBN(0xfd44a08d, 0x07625f62), TOBN(0x3ee4d65b, 0x9de9b762),}
++    ,
++    {TOBN(0x64e5137d, 0x0d63d1fa), TOBN(0x658fc052, 0x02a9d89f),
++     TOBN(0x48894874, 0x50436309), TOBN(0xe9ae30f8, 0xd598da61),
++     TOBN(0x2ed710d1, 0x818baf91), TOBN(0xe27e9e06, 0x8b6a0c20),
++     TOBN(0x1e28dcfb, 0x1c1a6b44), TOBN(0x883acb64, 0xd6ac57dc),
++     TOBN(0x8735728d, 0xc2c6ff70), TOBN(0x79d6122f, 0xc5dc2235),
++     TOBN(0x23f5d003, 0x19e277f9), TOBN(0x7ee84e25, 0xdded8cc7),
++     TOBN(0x91a8afb0, 0x63cd880a), TOBN(0x3f3ea7c6, 0x3574af60),
++     TOBN(0x0cfcdc84, 0x02de7f42), TOBN(0x62d0792f, 0xb31aa152),
++     TOBN(0x8e1b4e43, 0x8a5807ce), TOBN(0xad283893, 0xe4109a7e),
++     TOBN(0xc30cc9cb, 0xafd59dda), TOBN(0xf65f36c6, 0x3d8d8093),
++     TOBN(0xdf31469e, 0xa60d32b2), TOBN(0xee93df4b, 0x3e8191c8),
++     TOBN(0x9c1017c5, 0x355bdeb5), TOBN(0xd2623185, 0x8616aa28),
++     TOBN(0xb02c83f9, 0xdec31a21), TOBN(0x988c8b23, 0x6ad9d573),
++     TOBN(0x53e983ae, 0xa57be365), TOBN(0xe968734d, 0x646f834e),
++     TOBN(0x9137ea8f, 0x5da6309b), TOBN(0x10f3a624, 0xc1f1ce16),
++     TOBN(0x782a9ea2, 0xca440921), TOBN(0xdf94739e, 0x5b46f1b5),
++     TOBN(0x9f9be006, 0xcce85c9b), TOBN(0x360e70d6, 0xa4c7c2d3),
++     TOBN(0x2cd5beea, 0xaefa1e60), TOBN(0x64cf63c0, 0x8c3d2b6d),
++     TOBN(0xfb107fa3, 0xe1cf6f90), TOBN(0xb7e937c6, 0xd5e044e6),
++     TOBN(0x74e8ca78, 0xce34db9f), TOBN(0x4f8b36c1, 0x3e210bd0),
++     TOBN(0x1df165a4, 0x34a35ea8), TOBN(0x3418e0f7, 0x4d4412f6),
++     TOBN(0x5af1f8af, 0x518836c3), TOBN(0x42ceef4d, 0x130e1965),
++     TOBN(0x5560ca0b, 0x543a1957), TOBN(0xc33761e5, 0x886cb123),
++     TOBN(0x66624b1f, 0xfe98ed30), TOBN(0xf772f4bf, 0x1090997d),
++     TOBN(0xf4e540bb, 0x4885d410), TOBN(0x7287f810, 0x9ba5f8d7),
++     TOBN(0x22d0d865, 0xde98dfb1), TOBN(0x49ff51a1, 0xbcfbb8a3),
++     TOBN(0xb6b6fa53, 0x6bc3012e), TOBN(0x3d31fd72, 0x170d541d),
++     TOBN(0x8018724f, 0x4b0f4966), TOBN(0x79e7399f, 0x87dbde07),
++     TOBN(0x56f8410e, 0xf4f8b16a), TOBN(0x97241afe, 0xc47b266a),
++     TOBN(0x0a406b8e, 0x6d9c87c1), TOBN(0x803f3e02, 0xcd42ab1b),
++     TOBN(0x7f0309a8, 0x04dbec69), TOBN(0xa83b85f7, 0x3bbad05f),
++     TOBN(0xc6097273, 0xad8e197f), TOBN(0xc097440e, 0x5067adc1),
++     TOBN(0x730eafb6, 0x3524ff16), TOBN(0xd7f9b51e, 0x823fc6ce),
++     TOBN(0x27bd0d32, 0x443e4ac0), TOBN(0x40c59ad9, 0x4d66f217),
++     TOBN(0x6c33136f, 0x17c387a4), TOBN(0x5043b8d5, 0xeb86804d),
++     TOBN(0x74970312, 0x675a73c9), TOBN(0x838fdb31, 0xf16669b6),
++     TOBN(0xc507b6dd, 0x418e7ddd), TOBN(0x39888d93, 0x472f19d6),
++     TOBN(0x7eae26be, 0x0c27eb4d), TOBN(0x17b53ed3, 0xfbabb884),
++     TOBN(0xfc27021b, 0x2b01ae4f), TOBN(0x88462e87, 0xcf488682),
++     TOBN(0xbee096ec, 0x215e2d87), TOBN(0xeb2fea9a, 0xd242e29b),
++     TOBN(0x5d985b5f, 0xb821fc28), TOBN(0x89d2e197, 0xdc1e2ad2),
++     TOBN(0x55b566b8, 0x9030ba62), TOBN(0xe3fd41b5, 0x4f41b1c6),
++     TOBN(0xb738ac2e, 0xb9a96d61), TOBN(0x7f8567ca, 0x369443f4),
++     TOBN(0x8698622d, 0xf803a440), TOBN(0x2b586236, 0x8fe2f4dc),
++     TOBN(0xbbcc00c7, 0x56b95bce), TOBN(0x5ec03906, 0x616da680),
++     TOBN(0x79162ee6, 0x72214252), TOBN(0x43132b63, 0x86a892d2),
++     TOBN(0x4bdd3ff2, 0x2f3263bf), TOBN(0xd5b3733c, 0x9cd0a142),
++     TOBN(0x592eaa82, 0x44415ccb), TOBN(0x663e8924, 0x8d5474ea),
++     TOBN(0x8058a25e, 0x5236344e), TOBN(0x82e8df9d, 0xbda76ee6),
++     TOBN(0xdcf6efd8, 0x11cc3d22), TOBN(0x00089cda, 0x3b4ab529),
++     TOBN(0x91d3a071, 0xbd38a3db), TOBN(0x4ea97fc0, 0xef72b925),
++     TOBN(0x0c9fc15b, 0xea3edf75), TOBN(0x5a6297cd, 0xa4348ed3),
++     TOBN(0x0d38ab35, 0xce7c42d4), TOBN(0x9fd493ef, 0x82feab10),
++     TOBN(0x46056b6d, 0x82111b45), TOBN(0xda11dae1, 0x73efc5c3),
++     TOBN(0xdc740278, 0x5545a7fb), TOBN(0xbdb2601c, 0x40d507e6),
++     TOBN(0x121dfeeb, 0x7066fa58), TOBN(0x214369a8, 0x39ae8c2a),
++     TOBN(0x195709cb, 0x06e0956c), TOBN(0x4c9d254f, 0x010cd34b),
++     TOBN(0xf51e13f7, 0x0471a532), TOBN(0xe19d6791, 0x1e73054d),
++     TOBN(0xf702a628, 0xdb5c7be3), TOBN(0xc7141218, 0xb24dde05),
++     TOBN(0xdc18233c, 0xf29b2e2e), TOBN(0x3a6bd1e8, 0x85342dba),
++     TOBN(0x3f747fa0, 0xb311898c), TOBN(0xe2a272e4, 0xcd0eac65),
++     TOBN(0x4bba5851, 0xf914d0bc), TOBN(0x7a1a9660, 0xc4a43ee3),
++     TOBN(0xe5a367ce, 0xa1c8cde9), TOBN(0x9d958ba9, 0x7271abe3),
++     TOBN(0xf3ff7eb6, 0x3d1615cd), TOBN(0xa2280dce, 0xf5ae20b0),
++     TOBN(0x56dba5c1, 0xcf640147), TOBN(0xea5a2e3d, 0x5e83d118),
++     TOBN(0x04cd6b6d, 0xda24c511), TOBN(0x1c0f4671, 0xe854d214),
++     TOBN(0x91a6b7a9, 0x69565381), TOBN(0xdc966240, 0xdecf1f5b),
++     TOBN(0x1b22d21c, 0xfcf5d009), TOBN(0x2a05f641, 0x9021dbd5),
++     TOBN(0x8c0ed566, 0xd4312483), TOBN(0x5179a95d, 0x643e216f),
++     TOBN(0xcc185fec, 0x17044493), TOBN(0xb3063339, 0x54991a21),
++     TOBN(0xd801ecdb, 0x0081a726), TOBN(0x0149b0c6, 0x4fa89bbb),
++     TOBN(0xafe9065a, 0x4391b6b9), TOBN(0xedc92786, 0xd633f3a3),
++     TOBN(0xe408c24a, 0xae6a8e13), TOBN(0x85833fde, 0x9f3897ab),
++     TOBN(0x43800e7e, 0xd81a0715), TOBN(0xde08e346, 0xb44ffc5f),
++     TOBN(0x7094184c, 0xcdeff2e0), TOBN(0x49f9387b, 0x165eaed1),
++     TOBN(0x635d6129, 0x777c468a), TOBN(0x8c0dcfd1, 0x538c2dd8),
++     TOBN(0xd6d9d9e3, 0x7a6a308b), TOBN(0x62375830, 0x4c2767d3),
++     TOBN(0x874a8bc6, 0xf38cbeb6), TOBN(0xd94d3f1a, 0xccb6fd9e),
++     TOBN(0x92a9735b, 0xba21f248), TOBN(0x272ad0e5, 0x6cd1efb0),
++     TOBN(0x7437b69c, 0x05b03284), TOBN(0xe7f04702, 0x6948c225),
++     TOBN(0x8a56c04a, 0xcba2ecec), TOBN(0x0c181270, 0xe3a73e41),
++     TOBN(0x6cb34e9d, 0x03e93725), TOBN(0xf77c8713, 0x496521a9),
++     TOBN(0x94569183, 0xfa7f9f90), TOBN(0xf2e7aa4c, 0x8c9707ad),
++     TOBN(0xced2c9ba, 0x26c1c9a3), TOBN(0x9109fe96, 0x40197507),
++     TOBN(0x9ae868a9, 0xe9adfe1c), TOBN(0x3984403d, 0x314e39bb),
++     TOBN(0xb5875720, 0xf2fe378f), TOBN(0x33f901e0, 0xba44a628),
++     TOBN(0xea1125fe, 0x3652438c), TOBN(0xae9ec4e6, 0x9dd1f20b),
++     TOBN(0x1e740d9e, 0xbebf7fbd), TOBN(0x6dbd3ddc, 0x42dbe79c),
++     TOBN(0x62082aec, 0xedd36776), TOBN(0xf612c478, 0xe9859039),
++     TOBN(0xa493b201, 0x032f7065), TOBN(0xebd4d8f2, 0x4ff9b211),
++     TOBN(0x3f23a0aa, 0xaac4cb32), TOBN(0xea3aadb7, 0x15ed4005),
++     TOBN(0xacf17ea4, 0xafa27e63), TOBN(0x56125c1a, 0xc11fd66c),
++     TOBN(0x266344a4, 0x3794f8dc), TOBN(0xdcca923a, 0x483c5c36),
++     TOBN(0x2d6b6bbf, 0x3f9d10a0), TOBN(0xb320c5ca, 0x81d9bdf3),
++     TOBN(0x620e28ff, 0x47b50a95), TOBN(0x933e3b01, 0xcef03371),
++     TOBN(0xf081bf85, 0x99100153), TOBN(0x183be9a0, 0xc3a8c8d6),
++     TOBN(0x4e3ddc5a, 0xd6bbe24d), TOBN(0xc6c74630, 0x53843795),
++     TOBN(0x78193dd7, 0x65ec2d4c), TOBN(0xb8df26cc, 0xcd3c89b2),
++     TOBN(0x98dbe399, 0x5a483f8d), TOBN(0x72d8a957, 0x7dd3313a),
++     TOBN(0x65087294, 0xab0bd375), TOBN(0xfcd89248, 0x7c259d16),
++     TOBN(0x8a9443d7, 0x7613aa81), TOBN(0x80100800, 0x85fe6584),
++     TOBN(0x70fc4dbc, 0x7fb10288), TOBN(0xf58280d3, 0xe86beee8),
++     TOBN(0x14fdd82f, 0x7c978c38), TOBN(0xdf1204c1, 0x0de44d7b),
++     TOBN(0xa08a1c84, 0x4160252f), TOBN(0x591554ca, 0xc17646a5),
++     TOBN(0x214a37d6, 0xa05bd525), TOBN(0x48d5f09b, 0x07957b3c),
++     TOBN(0x0247cdcb, 0xd7109bc9), TOBN(0x40f9e4bb, 0x30599ce7),
++     TOBN(0xc325fa03, 0xf46ad2ec), TOBN(0x00f766cf, 0xc3e3f9ee),
++     TOBN(0xab556668, 0xd43a4577), TOBN(0x68d30a61, 0x3ee03b93),
++     TOBN(0x7ddc81ea, 0x77b46a08), TOBN(0xcf5a6477, 0xc7480699),
++     TOBN(0x43a8cb34, 0x6633f683), TOBN(0x1b867e6b, 0x92363c60),
++     TOBN(0x43921114, 0x1f60558e), TOBN(0xcdbcdd63, 0x2f41450e),
++     TOBN(0x7fc04601, 0xcc630e8b), TOBN(0xea7c66d5, 0x97038b43),
++     TOBN(0x7259b8a5, 0x04e99fd8), TOBN(0x98a8dd12, 0x4785549a),
++     TOBN(0x0e459a7c, 0x840552e1), TOBN(0xcdfcf4d0, 0x4bb0909e),
++     TOBN(0x34a86db2, 0x53758da7), TOBN(0xe643bb83, 0xeac997e1),
++     TOBN(0x96400bd7, 0x530c5b7e), TOBN(0x9f97af87, 0xb41c8b52),
++     TOBN(0x34fc8820, 0xfbeee3f9), TOBN(0x93e53490, 0x49091afd),
++     TOBN(0x764b9be5, 0x9a31f35c), TOBN(0x71f37864, 0x57e3d924),
++     TOBN(0x02fb34e0, 0x943aa75e), TOBN(0xa18c9c58, 0xab8ff6e4),
++     TOBN(0x080f31b1, 0x33cf0d19), TOBN(0x5c9682db, 0x083518a7),
++     TOBN(0x873d4ca6, 0xb709c3de), TOBN(0x64a84262, 0x3575b8f0),
++     TOBN(0x6275da1f, 0x020154bb), TOBN(0x97678caa, 0xd17cf1ab),
++     TOBN(0x8779795f, 0x951a95c3), TOBN(0xdd35b163, 0x50fccc08),
++     TOBN(0x32709627, 0x33d8f031), TOBN(0x3c5ab10a, 0x498dd85c),
++     TOBN(0xb6c185c3, 0x41dca566), TOBN(0x7de7feda, 0xd8622aa3),
++     TOBN(0x99e84d92, 0x901b6dfb), TOBN(0x30a02b0e, 0x7c4ad288),
++     TOBN(0xc7c81daa, 0x2fd3cf36), TOBN(0xd1319547, 0xdf89e59f),
++     TOBN(0xb2be8184, 0xcd496733), TOBN(0xd5f449eb, 0x93d3412b),
++     TOBN(0x7ea41b1b, 0x25fe531d), TOBN(0xf9797432, 0x6a1d5646),
++     TOBN(0x86067f72, 0x2bde501a), TOBN(0xf91481c0, 0x0c85e89c),
++     TOBN(0xca8ee465, 0xf8b05bc6), TOBN(0x1844e1cf, 0x02e83cda),
++     TOBN(0xca82114a, 0xb4dbe33b), TOBN(0x0f9f8769, 0x4eabfde2),
++     TOBN(0x4936b1c0, 0x38b27fe2), TOBN(0x63b6359b, 0xaba402df),
++     TOBN(0x40c0ea2f, 0x656bdbab), TOBN(0x9c992a89, 0x6580c39c),
++     TOBN(0x600e8f15, 0x2a60aed1), TOBN(0xeb089ca4, 0xe0bf49df),
++     TOBN(0x9c233d7d, 0x2d42d99a), TOBN(0x648d3f95, 0x4c6bc2fa),
++     TOBN(0xdcc383a8, 0xe1add3f3), TOBN(0xf42c0c6a, 0x4f64a348),
++     TOBN(0x2abd176f, 0x0030dbdb), TOBN(0x4de501a3, 0x7d6c215e),
++     TOBN(0x4a107c1f, 0x4b9a64bc), TOBN(0xa77f0ad3, 0x2496cd59),
++     TOBN(0xfb78ac62, 0x7688dffb), TOBN(0x7025a2ca, 0x67937d8e),
++     TOBN(0xfde8b2d1, 0xd1a8f4e7), TOBN(0xf5b3da47, 0x7354927c),
++     TOBN(0xe48606a3, 0xd9205735), TOBN(0xac477cc6, 0xe177b917),
++     TOBN(0xfb1f73d2, 0xa883239a), TOBN(0xe12572f6, 0xcc8b8357),
++     TOBN(0x9d355e9c, 0xfb1f4f86), TOBN(0x89b795f8, 0xd9f3ec6e),
++     TOBN(0x27be56f1, 0xb54398dc), TOBN(0x1890efd7, 0x3fedeed5),
++     TOBN(0x62f77f1f, 0x9c6d0140), TOBN(0x7ef0e314, 0x596f0ee4),
++     TOBN(0x50ca6631, 0xcc61dab3), TOBN(0x4a39801d, 0xf4866e4f),
++     TOBN(0x66c8d032, 0xae363b39), TOBN(0x22c591e5, 0x2ead66aa),
++     TOBN(0x954ba308, 0xde02a53e), TOBN(0x2a6c060f, 0xd389f357),
++     TOBN(0xe6cfcde8, 0xfbf40b66), TOBN(0x8e02fc56, 0xc6340ce1),
++     TOBN(0xe4957795, 0x73adb4ba), TOBN(0x7b86122c, 0xa7b03805),
++     TOBN(0x63f83512, 0x0c8e6fa6), TOBN(0x83660ea0, 0x057d7804),
++     TOBN(0xbad79105, 0x21ba473c), TOBN(0xb6c50bee, 0xded5389d),
++     TOBN(0xee2caf4d, 0xaa7c9bc0), TOBN(0xd97b8de4, 0x8c4e98a7),
++     TOBN(0xa9f63e70, 0xab3bbddb), TOBN(0x3898aabf, 0x2597815a),
++     TOBN(0x7659af89, 0xac15b3d9), TOBN(0xedf7725b, 0x703ce784),
++     TOBN(0x25470fab, 0xe085116b), TOBN(0x04a43375, 0x87285310),
++     TOBN(0x4e39187e, 0xe2bfd52f), TOBN(0x36166b44, 0x7d9ebc74),
++     TOBN(0x92ad433c, 0xfd4b322c), TOBN(0x726aa817, 0xba79ab51),
++     TOBN(0xf96eacd8, 0xc1db15eb), TOBN(0xfaf71e91, 0x0476be63),
++     TOBN(0xdd69a640, 0x641fad98), TOBN(0xb7995918, 0x29622559),
++     TOBN(0x03c6daa5, 0xde4199dc), TOBN(0x92cadc97, 0xad545eb4),
++     TOBN(0x1028238b, 0x256534e4), TOBN(0x73e80ce6, 0x8595409a),
++     TOBN(0x690d4c66, 0xd05dc59b), TOBN(0xc95f7b8f, 0x981dee80),
++     TOBN(0xf4337014, 0xd856ac25), TOBN(0x441bd9dd, 0xac524dca),
++     TOBN(0x640b3d85, 0x5f0499f5), TOBN(0x39cf84a9, 0xd5fda182),
++     TOBN(0x04e7b055, 0xb2aa95a0), TOBN(0x29e33f0a, 0x0ddf1860),
++     TOBN(0x082e74b5, 0x423f6b43), TOBN(0x217edeb9, 0x0aaa2b0f),
++     TOBN(0x58b83f35, 0x83cbea55), TOBN(0xc485ee4d, 0xbc185d70),
++     TOBN(0x833ff03b, 0x1e5f6992), TOBN(0xb5b9b9cc, 0xcf0c0dd5),
++     TOBN(0x7caaee8e, 0x4e9e8a50), TOBN(0x462e907b, 0x6269dafd),
++     TOBN(0x6ed5cee9, 0xfbe791c6), TOBN(0x68ca3259, 0xed430790),
++     TOBN(0x2b72bdf2, 0x13b5ba88), TOBN(0x60294c8a, 0x35ef0ac4),
++     TOBN(0x9c3230ed, 0x19b99b08), TOBN(0x560fff17, 0x6c2589aa),
++     TOBN(0x552b8487, 0xd6770374), TOBN(0xa373202d, 0x9a56f685),
++     TOBN(0xd3e7f907, 0x45f175d9), TOBN(0x3c2f315f, 0xd080d810),
++     TOBN(0x1130e9dd, 0x7b9520e8), TOBN(0xc078f9e2, 0x0af037b5),
++     TOBN(0x38cd2ec7, 0x1e9c104c), TOBN(0x0f684368, 0xc472fe92),
++     TOBN(0xd3f1b5ed, 0x6247e7ef), TOBN(0xb32d33a9, 0x396dfe21),
++     TOBN(0x46f59cf4, 0x4a9aa2c2), TOBN(0x69cd5168, 0xff0f7e41),
++     TOBN(0x3f59da0f, 0x4b3234da), TOBN(0xcf0b0235, 0xb4579ebe),
++     TOBN(0x6d1cbb25, 0x6d2476c7), TOBN(0x4f0837e6, 0x9dc30f08),
++     TOBN(0x9a4075bb, 0x906f6e98), TOBN(0x253bb434, 0xc761e7d1),
++     TOBN(0xde2e645f, 0x6e73af10), TOBN(0xb89a4060, 0x0c5f131c),
++     TOBN(0xd12840c5, 0xb8cc037f), TOBN(0x3d093a5b, 0x7405bb47),
++     TOBN(0x6202c253, 0x206348b8), TOBN(0xbf5d57fc, 0xc55a3ca7),
++     TOBN(0x89f6c90c, 0x8c3bef48), TOBN(0x23ac7623, 0x5a0a960a),
++     TOBN(0xdfbd3d6b, 0x552b42ab), TOBN(0x3ef22458, 0x132061f6),
++     TOBN(0xd74e9bda, 0xc97e6516), TOBN(0x88779360, 0xc230f49e),
++     TOBN(0xa6ec1de3, 0x1e74ea49), TOBN(0x581dcee5, 0x3fb645a2),
++     TOBN(0xbaef2391, 0x8f483f14), TOBN(0x6d2dddfc, 0xd137d13b),
++     TOBN(0x54cde50e, 0xd2743a42), TOBN(0x89a34fc5, 0xe4d97e67),
++     TOBN(0x13f1f5b3, 0x12e08ce5), TOBN(0xa80540b8, 0xa7f0b2ca),
++     TOBN(0x854bcf77, 0x01982805), TOBN(0xb8653ffd, 0x233bea04),
++     TOBN(0x8e7b8787, 0x02b0b4c9), TOBN(0x2675261f, 0x9acb170a),
++     TOBN(0x061a9d90, 0x930c14e5), TOBN(0xb59b30e0, 0xdef0abea),
++     TOBN(0x1dc19ea6, 0x0200ec7d), TOBN(0xb6f4a3f9, 0x0bce132b),
++     TOBN(0xb8d5de90, 0xf13e27e0), TOBN(0xbaee5ef0, 0x1fade16f),
++     TOBN(0x6f406aaa, 0xe4c6cf38), TOBN(0xab4cfe06, 0xd1369815),
++     TOBN(0x0dcffe87, 0xefd550c6), TOBN(0x9d4f59c7, 0x75ff7d39),
++     TOBN(0xb02553b1, 0x51deb6ad), TOBN(0x812399a4, 0xb1877749),
++     TOBN(0xce90f71f, 0xca6006e1), TOBN(0xc32363a6, 0xb02b6e77),
++     TOBN(0x02284fbe, 0xdc36c64d), TOBN(0x86c81e31, 0xa7e1ae61),
++     TOBN(0x2576c7e5, 0xb909d94a), TOBN(0x8b6f7d02, 0x818b2bb0),
++     TOBN(0xeca3ed07, 0x56faa38a), TOBN(0xa3790e6c, 0x9305bb54),
++     TOBN(0xd784eeda, 0x7bc73061), TOBN(0xbd56d369, 0x6dd50614),
++     TOBN(0xd6575949, 0x229a8aa9), TOBN(0xdcca8f47, 0x4595ec28),
++     TOBN(0x814305c1, 0x06ab4fe6), TOBN(0xc8c39768, 0x24f43f16),
++     TOBN(0xe2a45f36, 0x523f2b36), TOBN(0x995c6493, 0x920d93bb),
++     TOBN(0xf8afdab7, 0x90f1632b), TOBN(0x79ebbecd, 0x1c295954),
++     TOBN(0xc7bb3ddb, 0x79592f48), TOBN(0x67216a7b, 0x5f88e998),
++     TOBN(0xd91f098b, 0xbc01193e), TOBN(0xf7d928a5, 0xb1db83fc),
++     TOBN(0x55e38417, 0xe991f600), TOBN(0x2a91113e, 0x2981a934),
++     TOBN(0xcbc9d648, 0x06b13bde), TOBN(0xb011b6ac, 0x0755ff44),
++     TOBN(0x6f4cb518, 0x045ec613), TOBN(0x522d2d31, 0xc2f5930a),
++     TOBN(0x5acae1af, 0x382e65de), TOBN(0x57643067, 0x27bc966f),
++     TOBN(0x5e12705d, 0x1c7193f0), TOBN(0xf0f32f47, 0x3be8858e),
++     TOBN(0x785c3d7d, 0x96c6dfc7), TOBN(0xd75b4a20, 0xbf31795d),
++     TOBN(0x91acf17b, 0x342659d4), TOBN(0xe596ea34, 0x44f0378f),
++     TOBN(0x4515708f, 0xce52129d), TOBN(0x17387e1e, 0x79f2f585),
++     TOBN(0x72cfd2e9, 0x49dee168), TOBN(0x1ae05223, 0x3e2af239),
++     TOBN(0x009e75be, 0x1d94066a), TOBN(0x6cca31c7, 0x38abf413),
++     TOBN(0xb50bd61d, 0x9bc49908), TOBN(0x4a9b4a8c, 0xf5e2bc1e),
++     TOBN(0xeb6cc5f7, 0x946f83ac), TOBN(0x27da93fc, 0xebffab28),
++     TOBN(0xea314c96, 0x4821c8c5), TOBN(0x8de49ded, 0xa83c15f4),
++     TOBN(0x7a64cf20, 0x7af33004), TOBN(0x45f1bfeb, 0xc9627e10),
++     TOBN(0x878b0626, 0x54b9df60), TOBN(0x5e4fdc3c, 0xa95c0b33),
++     TOBN(0xe54a37ca, 0xc2035d8e), TOBN(0x9087cda9, 0x80f20b8c),
++     TOBN(0x36f61c23, 0x8319ade4), TOBN(0x766f287a, 0xde8cfdf8),
++     TOBN(0x48821948, 0x346f3705), TOBN(0x49a7b853, 0x16e4f4a2),
++     TOBN(0xb9b3f8a7, 0x5cedadfd), TOBN(0x8f562815, 0x8db2a815),
++     TOBN(0xc0b7d554, 0x01f68f95), TOBN(0x12971e27, 0x688a208e),
++     TOBN(0xc9f8b696, 0xd0ff34fc), TOBN(0x20824de2, 0x1222718c),
++     TOBN(0x7213cf9f, 0x0c95284d), TOBN(0xe2ad741b, 0xdc158240),
++     TOBN(0x0ee3a6df, 0x54043ccf), TOBN(0x16ff479b, 0xd84412b3),
++     TOBN(0xf6c74ee0, 0xdfc98af0), TOBN(0xa78a169f, 0x52fcd2fb),
++     TOBN(0xd8ae8746, 0x99c930e9), TOBN(0x1d33e858, 0x49e117a5),
++     TOBN(0x7581fcb4, 0x6624759f), TOBN(0xde50644f, 0x5bedc01d),
++     TOBN(0xbeec5d00, 0xcaf3155e), TOBN(0x672d66ac, 0xbc73e75f),
++     TOBN(0x86b9d8c6, 0x270b01db), TOBN(0xd249ef83, 0x50f55b79),
++     TOBN(0x6131d6d4, 0x73978fe3), TOBN(0xcc4e4542, 0x754b00a1),
++     TOBN(0x4e05df05, 0x57dfcfe9), TOBN(0x94b29cdd, 0x51ef6bf0),
++     TOBN(0xe4530cff, 0x9bc7edf2), TOBN(0x8ac236fd, 0xd3da65f3),
++     TOBN(0x0faf7d5f, 0xc8eb0b48), TOBN(0x4d2de14c, 0x660eb039),
++     TOBN(0xc006bba7, 0x60430e54), TOBN(0x10a2d0d6, 0xda3289ab),
++     TOBN(0x9c037a5d, 0xd7979c59), TOBN(0x04d1f3d3, 0xa116d944),
++     TOBN(0x9ff22473, 0x8a0983cd), TOBN(0x28e25b38, 0xc883cabb),
++     TOBN(0xe968dba5, 0x47a58995), TOBN(0x2c80b505, 0x774eebdf),
++     TOBN(0xee763b71, 0x4a953beb), TOBN(0x502e223f, 0x1642e7f6),
++     TOBN(0x6fe4b641, 0x61d5e722), TOBN(0x9d37c5b0, 0xdbef5316),
++     TOBN(0x0115ed70, 0xf8330bc7), TOBN(0x139850e6, 0x75a72789),
++     TOBN(0x27d7faec, 0xffceccc2), TOBN(0x3016a860, 0x4fd9f7f6),
++     TOBN(0xc492ec64, 0x4cd8f64c), TOBN(0x58a2d790, 0x279d7b51),
++     TOBN(0x0ced1fc5, 0x1fc75256), TOBN(0x3e658aed, 0x8f433017),
++     TOBN(0x0b61942e, 0x05da59eb), TOBN(0xba3d60a3, 0x0ddc3722),
++     TOBN(0x7c311cd1, 0x742e7f87), TOBN(0x6473ffee, 0xf6b01b6e),}
++    ,
++    {TOBN(0x8303604f, 0x692ac542), TOBN(0xf079ffe1, 0x227b91d3),
++     TOBN(0x19f63e63, 0x15aaf9bd), TOBN(0xf99ee565, 0xf1f344fb),
++     TOBN(0x8a1d661f, 0xd6219199), TOBN(0x8c883bc6, 0xd48ce41c),
++     TOBN(0x1065118f, 0x3c74d904), TOBN(0x713889ee, 0x0faf8b1b),
++     TOBN(0x972b3f8f, 0x81a1b3be), TOBN(0x4f3ce145, 0xce2764a0),
++     TOBN(0xe2d0f1cc, 0x28c4f5f7), TOBN(0xdeee0c0d, 0xc7f3985b),
++     TOBN(0x7df4adc0, 0xd39e25c3), TOBN(0x40619820, 0xc467a080),
++     TOBN(0x440ebc93, 0x61cf5a58), TOBN(0x527729a6, 0x422ad600),
++     TOBN(0xca6c0937, 0xb1b76ba6), TOBN(0x1a2eab85, 0x4d2026dc),
++     TOBN(0xb1715e15, 0x19d9ae0a), TOBN(0xf1ad9199, 0xbac4a026),
++     TOBN(0x35b3dfb8, 0x07ea7b0e), TOBN(0xedf5496f, 0x3ed9eb89),
++     TOBN(0x8932e5ff, 0x2d6d08ab), TOBN(0xf314874e, 0x25bd2731),
++     TOBN(0xefb26a75, 0x3f73f449), TOBN(0x1d1c94f8, 0x8d44fc79),
++     TOBN(0x49f0fbc5, 0x3bc0dc4d), TOBN(0xb747ea0b, 0x3698a0d0),
++     TOBN(0x5218c3fe, 0x228d291e), TOBN(0x35b804b5, 0x43c129d6),
++     TOBN(0xfac859b8, 0xd1acc516), TOBN(0x6c10697d, 0x95d6e668),
++     TOBN(0xc38e438f, 0x0876fd4e), TOBN(0x45f0c307, 0x83d2f383),
++     TOBN(0x203cc2ec, 0xb10934cb), TOBN(0x6a8f2439, 0x2c9d46ee),
++     TOBN(0xf16b431b, 0x65ccde7b), TOBN(0x41e2cd18, 0x27e76a6f),
++     TOBN(0xb9c8cf8f, 0x4e3484d7), TOBN(0x64426efd, 0x8315244a),
++     TOBN(0x1c0a8e44, 0xfc94dea3), TOBN(0x34c8cdbf, 0xdad6a0b0),
++     TOBN(0x919c3840, 0x04113cef), TOBN(0xfd32fba4, 0x15490ffa),
++     TOBN(0x58d190f6, 0x795dcfb7), TOBN(0xfef01b03, 0x83588baf),
++     TOBN(0x9e6d1d63, 0xca1fc1c0), TOBN(0x53173f96, 0xf0a41ac9),
++     TOBN(0x2b1d402a, 0xba16f73b), TOBN(0x2fb31014, 0x8cf9b9fc),
++     TOBN(0x2d51e60e, 0x446ef7bf), TOBN(0xc731021b, 0xb91e1745),
++     TOBN(0x9d3b4724, 0x4fee99d4), TOBN(0x4bca48b6, 0xfac5c1ea),
++     TOBN(0x70f5f514, 0xbbea9af7), TOBN(0x751f55a5, 0x974c283a),
++     TOBN(0x6e30251a, 0xcb452fdb), TOBN(0x31ee6965, 0x50f30650),
++     TOBN(0xb0b3e508, 0x933548d9), TOBN(0xb8949a4f, 0xf4b0ef5b),
++     TOBN(0x208b8326, 0x3c88f3bd), TOBN(0xab147c30, 0xdb1d9989),
++     TOBN(0xed6515fd, 0x44d4df03), TOBN(0x17a12f75, 0xe72eb0c5),
++     TOBN(0x3b59796d, 0x36cf69db), TOBN(0x1219eee9, 0x56670c18),
++     TOBN(0xfe3341f7, 0x7a070d8e), TOBN(0x9b70130b, 0xa327f90c),
++     TOBN(0x36a32462, 0x0ae18e0e), TOBN(0x2021a623, 0x46c0a638),
++     TOBN(0x251b5817, 0xc62eb0d4), TOBN(0x87bfbcdf, 0x4c762293),
++     TOBN(0xf78ab505, 0xcdd61d64), TOBN(0x8c7a53fc, 0xc8c18857),
++     TOBN(0xa653ce6f, 0x16147515), TOBN(0x9c923aa5, 0xea7d52d5),
++     TOBN(0xc24709cb, 0x5c18871f), TOBN(0x7d53bec8, 0x73b3cc74),
++     TOBN(0x59264aff, 0xfdd1d4c4), TOBN(0x5555917e, 0x240da582),
++     TOBN(0xcae8bbda, 0x548f5a0e), TOBN(0x1910eaba, 0x3bbfbbe1),
++     TOBN(0xae579685, 0x7677afc3), TOBN(0x49ea61f1, 0x73ff0b5c),
++     TOBN(0x78655478, 0x4f7c3922), TOBN(0x95d337cd, 0x20c68eef),
++     TOBN(0x68f1e1e5, 0xdf779ab9), TOBN(0x14b491b0, 0xb5cf69a8),
++     TOBN(0x7a6cbbe0, 0x28e3fe89), TOBN(0xe7e1fee4, 0xc5aac0eb),
++     TOBN(0x7f47eda5, 0x697e5140), TOBN(0x4f450137, 0xb454921f),
++     TOBN(0xdb625f84, 0x95cd8185), TOBN(0x74be0ba1, 0xcdb2e583),
++     TOBN(0xaee4fd7c, 0xdd5e6de4), TOBN(0x4251437d, 0xe8101739),
++     TOBN(0x686d72a0, 0xac620366), TOBN(0x4be3fb9c, 0xb6d59344),
++     TOBN(0x6e8b44e7, 0xa1eb75b9), TOBN(0x84e39da3, 0x91a5c10c),
++     TOBN(0x37cc1490, 0xb38f0409), TOBN(0x02951943, 0x2c2ade82),
++     TOBN(0x9b688783, 0x1190a2d8), TOBN(0x25627d14, 0x231182ba),
++     TOBN(0x6eb550aa, 0x658a6d87), TOBN(0x1405aaa7, 0xcf9c7325),
++     TOBN(0xd147142e, 0x5c8748c9), TOBN(0x7f637e4f, 0x53ede0e0),
++     TOBN(0xf8ca2776, 0x14ffad2c), TOBN(0xe58fb1bd, 0xbafb6791),
++     TOBN(0x17158c23, 0xbf8f93fc), TOBN(0x7f15b373, 0x0a4a4655),
++     TOBN(0x39d4add2, 0xd842ca72), TOBN(0xa71e4391, 0x3ed96305),
++     TOBN(0x5bb09cbe, 0x6700be14), TOBN(0x68d69d54, 0xd8befcf6),
++     TOBN(0xa45f5367, 0x37183bcf), TOBN(0x7152b7bb, 0x3370dff7),
++     TOBN(0xcf887baa, 0xbf12525b), TOBN(0xe7ac7bdd, 0xd6d1e3cd),
++     TOBN(0x25914f78, 0x81fdad90), TOBN(0xcf638f56, 0x0d2cf6ab),
++     TOBN(0xb90bc03f, 0xcc054de5), TOBN(0x932811a7, 0x18b06350),
++     TOBN(0x2f00b330, 0x9bbd11ff), TOBN(0x76108a6f, 0xb4044974),
++     TOBN(0x801bb9e0, 0xa851d266), TOBN(0x0dd099be, 0xbf8990c1),
++     TOBN(0x58c5aaaa, 0xabe32986), TOBN(0x0fe9dd2a, 0x50d59c27),
++     TOBN(0x84951ff4, 0x8d307305), TOBN(0x6c23f829, 0x86529b78),
++     TOBN(0x50bb2218, 0x0b136a79), TOBN(0x7e2174de, 0x77a20996),
++     TOBN(0x6f00a4b9, 0xc0bb4da6), TOBN(0x89a25a17, 0xefdde8da),
++     TOBN(0xf728a27e, 0xc11ee01d), TOBN(0xf900553a, 0xe5f10dfb),
++     TOBN(0x189a83c8, 0x02ec893c), TOBN(0x3ca5bdc1, 0x23f66d77),
++     TOBN(0x98781537, 0x97eada9f), TOBN(0x59c50ab3, 0x10256230),
++     TOBN(0x346042d9, 0x323c69b3), TOBN(0x1b715a6d, 0x2c460449),
++     TOBN(0xa41dd476, 0x6ae06e0b), TOBN(0xcdd7888e, 0x9d42e25f),
++     TOBN(0x0f395f74, 0x56b25a20), TOBN(0xeadfe0ae, 0x8700e27e),
++     TOBN(0xb09d52a9, 0x69950093), TOBN(0x3525d9cb, 0x327f8d40),
++     TOBN(0xb8235a94, 0x67df886a), TOBN(0x77e4b0dd, 0x035faec2),
++     TOBN(0x115eb20a, 0x517d7061), TOBN(0x77fe3433, 0x6c2df683),
++     TOBN(0x6870ddc7, 0xcdc6fc67), TOBN(0xb1610588, 0x0b87de83),
++     TOBN(0x343584ca, 0xd9c4ddbe), TOBN(0xb3164f1c, 0x3d754be2),
++     TOBN(0x0731ed3a, 0xc1e6c894), TOBN(0x26327dec, 0x4f6b904c),
++     TOBN(0x9d49c6de, 0x97b5cd32), TOBN(0x40835dae, 0xb5eceecd),
++     TOBN(0xc66350ed, 0xd9ded7fe), TOBN(0x8aeebb5c, 0x7a678804),
++     TOBN(0x51d42fb7, 0x5b8ee9ec), TOBN(0xd7a17bdd, 0x8e3ca118),
++     TOBN(0x40d7511a, 0x2ef4400e), TOBN(0xc48990ac, 0x875a66f4),
++     TOBN(0x8de07d2a, 0x2199e347), TOBN(0xbee75556, 0x2a39e051),
++     TOBN(0x56918786, 0x916e51dc), TOBN(0xeb191313, 0x4a2d89ec),
++     TOBN(0x6679610d, 0x37d341ed), TOBN(0x434fbb41, 0x56d51c2b),
++     TOBN(0xe54b7ee7, 0xd7492dba), TOBN(0xaa33a79a, 0x59021493),
++     TOBN(0x49fc5054, 0xe4bd6d3d), TOBN(0x09540f04, 0x5ab551d0),
++     TOBN(0x8acc9085, 0x4942d3a6), TOBN(0x231af02f, 0x2d28323b),
++     TOBN(0x93458cac, 0x0992c163), TOBN(0x1fef8e71, 0x888e3bb4),
++     TOBN(0x27578da5, 0xbe8c268c), TOBN(0xcc8be792, 0xe805ec00),
++     TOBN(0x29267bae, 0xc61c3855), TOBN(0xebff429d, 0x58c1fd3b),
++     TOBN(0x22d886c0, 0x8c0b93b8), TOBN(0xca5e00b2, 0x2ddb8953),
++     TOBN(0xcf330117, 0xc3fed8b7), TOBN(0xd49ac6fa, 0x819c01f6),
++     TOBN(0x6ddaa6bd, 0x3c0fbd54), TOBN(0x91743068, 0x8049a2cf),
++     TOBN(0xd67f981e, 0xaff2ef81), TOBN(0xc3654d35, 0x2818ae80),
++     TOBN(0x81d05044, 0x1b2aa892), TOBN(0x2db067bf, 0x3d099328),
++     TOBN(0xe7c79e86, 0x703dcc97), TOBN(0xe66f9b37, 0xe133e215),
++     TOBN(0xcdf119a6, 0xe39a7a5c), TOBN(0x47c60de3, 0x876f1b61),
++     TOBN(0x6e405939, 0xd860f1b2), TOBN(0x3e9a1dbc, 0xf5ed4d4a),
++     TOBN(0x3f23619e, 0xc9b6bcbd), TOBN(0x5ee790cf, 0x734e4497),
++     TOBN(0xf0a834b1, 0x5bdaf9bb), TOBN(0x02cedda7, 0x4ca295f0),
++     TOBN(0x4619aa2b, 0xcb8e378c), TOBN(0xe5613244, 0xcc987ea4),
++     TOBN(0x0bc022cc, 0x76b23a50), TOBN(0x4a2793ad, 0x0a6c21ce),
++     TOBN(0x38328780, 0x89cac3f5), TOBN(0x29176f1b, 0xcba26d56),
++     TOBN(0x06296187, 0x4f6f59eb), TOBN(0x86e9bca9, 0x8bdc658e),
++     TOBN(0x2ca9c4d3, 0x57e30402), TOBN(0x5438b216, 0x516a09bb),
++     TOBN(0x0a6a063c, 0x7672765a), TOBN(0x37a3ce64, 0x0547b9bf),
++     TOBN(0x42c099c8, 0x98b1a633), TOBN(0xb5ab800d, 0x05ee6961),
++     TOBN(0xf1963f59, 0x11a5acd6), TOBN(0xbaee6157, 0x46201063),
++     TOBN(0x36d9a649, 0xa596210a), TOBN(0xaed04363, 0x1ba7138c),
++     TOBN(0xcf817d1c, 0xa4a82b76), TOBN(0x5586960e, 0xf3806be9),
++     TOBN(0x7ab67c89, 0x09dc6bb5), TOBN(0x52ace7a0, 0x114fe7eb),
++     TOBN(0xcd987618, 0xcbbc9b70), TOBN(0x4f06fd5a, 0x604ca5e1),
++     TOBN(0x90af14ca, 0x6dbde133), TOBN(0x1afe4322, 0x948a3264),
++     TOBN(0xa70d2ca6, 0xc44b2c6c), TOBN(0xab726799, 0x0ef87dfe),
++     TOBN(0x310f64dc, 0x2e696377), TOBN(0x49b42e68, 0x4c8126a0),
++     TOBN(0x0ea444c3, 0xcea0b176), TOBN(0x53a8ddf7, 0xcb269182),
++     TOBN(0xf3e674eb, 0xbbba9dcb), TOBN(0x0d2878a8, 0xd8669d33),
++     TOBN(0x04b935d5, 0xd019b6a3), TOBN(0xbb5cf88e, 0x406f1e46),
++     TOBN(0xa1912d16, 0x5b57c111), TOBN(0x9803fc21, 0x19ebfd78),
++     TOBN(0x4f231c9e, 0xc07764a9), TOBN(0xd93286ee, 0xb75bd055),
++     TOBN(0x83a9457d, 0x8ee6c9de), TOBN(0x04695915, 0x6087ec90),
++     TOBN(0x14c6dd8a, 0x58d6cd46), TOBN(0x9cb633b5, 0x8e6634d2),
++     TOBN(0xc1305047, 0xf81bc328), TOBN(0x12ede0e2, 0x26a177e5),
++     TOBN(0x332cca62, 0x065a6f4f), TOBN(0xc3a47ecd, 0x67be487b),
++     TOBN(0x741eb187, 0x0f47ed1c), TOBN(0x99e66e58, 0xe7598b14),
++     TOBN(0x6f0544ca, 0x63d0ff12), TOBN(0xe5efc784, 0xb610a05f),
++     TOBN(0xf72917b1, 0x7cad7b47), TOBN(0x3ff6ea20, 0xf2cac0c0),
++     TOBN(0xcc23791b, 0xf21db8b7), TOBN(0x7dac70b1, 0xd7d93565),
++     TOBN(0x682cda1d, 0x694bdaad), TOBN(0xeb88bb8c, 0x1023516d),
++     TOBN(0xc4c634b4, 0xdfdbeb1b), TOBN(0x22f5ca72, 0xb4ee4dea),
++     TOBN(0x1045a368, 0xe6524821), TOBN(0xed9e8a3f, 0x052b18b2),
++     TOBN(0x9b7f2cb1, 0xb961f49a), TOBN(0x7fee2ec1, 0x7b009670),
++     TOBN(0x350d8754, 0x22507a6d), TOBN(0x561bd711, 0x4db55f1d),
++     TOBN(0x4c189ccc, 0x320bbcaf), TOBN(0x568434cf, 0xdf1de48c),
++     TOBN(0x6af1b00e, 0x0fa8f128), TOBN(0xf0ba9d02, 0x8907583c),
++     TOBN(0x735a4004, 0x32ff9f60), TOBN(0x3dd8e4b6, 0xc25dcf33),
++     TOBN(0xf2230f16, 0x42c74cef), TOBN(0xd8117623, 0x013fa8ad),
++     TOBN(0x36822876, 0xf51fe76e), TOBN(0x8a6811cc, 0x11d62589),
++     TOBN(0xc3fc7e65, 0x46225718), TOBN(0xb7df2c9f, 0xc82fdbcd),
++     TOBN(0x3b1d4e52, 0xdd7b205b), TOBN(0xb6959478, 0x47a2e414),
++     TOBN(0x05e4d793, 0xefa91148), TOBN(0xb47ed446, 0xfd2e9675),
++     TOBN(0x1a7098b9, 0x04c9d9bf), TOBN(0x661e2881, 0x1b793048),
++     TOBN(0xb1a16966, 0xb01ee461), TOBN(0xbc521308, 0x2954746f),
++     TOBN(0xc909a0fc, 0x2477de50), TOBN(0xd80bb41c, 0x7dbd51ef),
++     TOBN(0xa85be7ec, 0x53294905), TOBN(0x6d465b18, 0x83958f97),
++     TOBN(0x16f6f330, 0xfb6840fd), TOBN(0xfaaeb214, 0x3401e6c8),
++     TOBN(0xaf83d30f, 0xccb5b4f8), TOBN(0x22885739, 0x266dec4b),
++     TOBN(0x51b4367c, 0x7bc467df), TOBN(0x926562e3, 0xd842d27a),
++     TOBN(0xdfcb6614, 0x0fea14a6), TOBN(0xeb394dae, 0xf2734cd9),
++     TOBN(0x3eeae5d2, 0x11c0be98), TOBN(0xb1e6ed11, 0x814e8165),
++     TOBN(0x191086bc, 0xe52bce1c), TOBN(0x14b74cc6, 0xa75a04da),
++     TOBN(0x63cf1186, 0x8c060985), TOBN(0x071047de, 0x2dbd7f7c),
++     TOBN(0x4e433b8b, 0xce0942ca), TOBN(0xecbac447, 0xd8fec61d),
++     TOBN(0x8f0ed0e2, 0xebf3232f), TOBN(0xfff80f9e, 0xc52a2edd),
++     TOBN(0xad9ab433, 0x75b55fdb), TOBN(0x73ca7820, 0xe42e0c11),
++     TOBN(0x6dace0a0, 0xe6251b46), TOBN(0x89bc6b5c, 0x4c0d932d),
++     TOBN(0x3438cd77, 0x095da19a), TOBN(0x2f24a939, 0x8d48bdfb),
++     TOBN(0x99b47e46, 0x766561b7), TOBN(0x736600e6, 0x0ed0322a),
++     TOBN(0x06a47cb1, 0x638e1865), TOBN(0x927c1c2d, 0xcb136000),
++     TOBN(0x29542337, 0x0cc5df69), TOBN(0x99b37c02, 0x09d649a9),
++     TOBN(0xc5f0043c, 0x6aefdb27), TOBN(0x6cdd9987, 0x1be95c27),
++     TOBN(0x69850931, 0x390420d2), TOBN(0x299c40ac, 0x0983efa4),
++     TOBN(0x3a05e778, 0xaf39aead), TOBN(0x84274408, 0x43a45193),
++     TOBN(0x6bcd0fb9, 0x91a711a0), TOBN(0x461592c8, 0x9f52ab17),
++     TOBN(0xb49302b4, 0xda3c6ed6), TOBN(0xc51fddc7, 0x330d7067),
++     TOBN(0x94babeb6, 0xda50d531), TOBN(0x521b840d, 0xa6a7b9da),
++     TOBN(0x5305151e, 0x404bdc89), TOBN(0x1bcde201, 0xd0d07449),
++     TOBN(0xf427a78b, 0x3b76a59a), TOBN(0xf84841ce, 0x07791a1b),
++     TOBN(0xebd314be, 0xbf91ed1c), TOBN(0x8e61d34c, 0xbf172943),
++     TOBN(0x1d5dc451, 0x5541b892), TOBN(0xb186ee41, 0xfc9d9e54),
++     TOBN(0x9d9f345e, 0xd5bf610d), TOBN(0x3e7ba65d, 0xf6acca9f),
++     TOBN(0x9dda787a, 0xa8369486), TOBN(0x09f9dab7, 0x8eb5ba53),
++     TOBN(0x5afb2033, 0xd6481bc3), TOBN(0x76f4ce30, 0xafa62104),
++     TOBN(0xa8fa00cf, 0xf4f066b5), TOBN(0x89ab5143, 0x461dafc2),
++     TOBN(0x44339ed7, 0xa3389998), TOBN(0x2ff862f1, 0xbc214903),
++     TOBN(0x2c88f985, 0xb05556e3), TOBN(0xcd96058e, 0x3467081e),
++     TOBN(0x7d6a4176, 0xedc637ea), TOBN(0xe1743d09, 0x36a5acdc),
++     TOBN(0x66fd72e2, 0x7eb37726), TOBN(0xf7fa264e, 0x1481a037),
++     TOBN(0x9fbd3bde, 0x45f4aa79), TOBN(0xed1e0147, 0x767c3e22),
++     TOBN(0x7621f979, 0x82e7abe2), TOBN(0x19eedc72, 0x45f633f8),
++     TOBN(0xe69b155e, 0x6137bf3a), TOBN(0xa0ad13ce, 0x414ee94e),
++     TOBN(0x93e3d524, 0x1c0e651a), TOBN(0xab1a6e2a, 0x02ce227e),
++     TOBN(0xe7af1797, 0x4ab27eca), TOBN(0x245446de, 0xbd444f39),
++     TOBN(0x59e22a21, 0x56c07613), TOBN(0x43deafce, 0xf4275498),
++     TOBN(0x10834ccb, 0x67fd0946), TOBN(0xa75841e5, 0x47406edf),
++     TOBN(0xebd6a677, 0x7b0ac93d), TOBN(0xa6e37b0d, 0x78f5e0d7),
++     TOBN(0x2516c096, 0x76f5492b), TOBN(0x1e4bf888, 0x9ac05f3a),
++     TOBN(0xcdb42ce0, 0x4df0ba2b), TOBN(0x935d5cfd, 0x5062341b),
++     TOBN(0x8a303333, 0x82acac20), TOBN(0x429438c4, 0x5198b00e),
++     TOBN(0x1d083bc9, 0x049d33fa), TOBN(0x58b82dda, 0x946f67ff),
++     TOBN(0xac3e2db8, 0x67a1d6a3), TOBN(0x62e6bead, 0x1798aac8),
++     TOBN(0xfc85980f, 0xde46c58c), TOBN(0xa7f69379, 0x69c8d7be),
++     TOBN(0x23557927, 0x837b35ec), TOBN(0x06a933d8, 0xe0790c0c),
++     TOBN(0x827c0e9b, 0x077ff55d), TOBN(0x53977798, 0xbb26e680),
++     TOBN(0x59530874, 0x1d9cb54f), TOBN(0xcca3f449, 0x4aac53ef),
++     TOBN(0x11dc5c87, 0xa07eda0f), TOBN(0xc138bccf, 0xfd6400c8),
++     TOBN(0x549680d3, 0x13e5da72), TOBN(0xc93eed82, 0x4540617e),
++     TOBN(0xfd3db157, 0x4d0b75c0), TOBN(0x9716eb42, 0x6386075b),
++     TOBN(0x0639605c, 0x817b2c16), TOBN(0x09915109, 0xf1e4f201),
++     TOBN(0x35c9a928, 0x5cca6c3b), TOBN(0xb25f7d1a, 0x3505c900),
++     TOBN(0xeb9f7d20, 0x630480c4), TOBN(0xc3c7b8c6, 0x2a1a501c),
++     TOBN(0x3f99183c, 0x5a1f8e24), TOBN(0xfdb118fa, 0x9dd255f0),
++     TOBN(0xb9b18b90, 0xc27f62a6), TOBN(0xe8f732f7, 0x396ec191),
++     TOBN(0x524a2d91, 0x0be786ab), TOBN(0x5d32adef, 0x0ac5a0f5),
++     TOBN(0x9b53d4d6, 0x9725f694), TOBN(0x032a76c6, 0x0510ba89),
++     TOBN(0x840391a3, 0xebeb1544), TOBN(0x44b7b88c, 0x3ed73ac3),
++     TOBN(0xd24bae7a, 0x256cb8b3), TOBN(0x7ceb151a, 0xe394cb12),
++     TOBN(0xbd6b66d0, 0x5bc1e6a8), TOBN(0xec70cecb, 0x090f07bf),
++     TOBN(0x270644ed, 0x7d937589), TOBN(0xee9e1a3d, 0x5f1dccfe),
++     TOBN(0xb0d40a84, 0x745b98d2), TOBN(0xda429a21, 0x2556ed40),
++     TOBN(0xf676eced, 0x85148cb9), TOBN(0x5a22d40c, 0xded18936),
++     TOBN(0x3bc4b9e5, 0x70e8a4ce), TOBN(0xbfd1445b, 0x9eae0379),
++     TOBN(0xf23f2c0c, 0x1a0bd47e), TOBN(0xa9c0bb31, 0xe1845531),
++     TOBN(0x9ddc4d60, 0x0a4c3f6b), TOBN(0xbdfaad79, 0x2c15ef44),
++     TOBN(0xce55a236, 0x7f484acc), TOBN(0x08653ca7, 0x055b1f15),
++     TOBN(0x2efa8724, 0x538873a3), TOBN(0x09299e5d, 0xace1c7e7),
++     TOBN(0x07afab66, 0xade332ba), TOBN(0x9be1fdf6, 0x92dd71b7),
++     TOBN(0xa49b5d59, 0x5758b11c), TOBN(0x0b852893, 0xc8654f40),
++     TOBN(0xb63ef6f4, 0x52379447), TOBN(0xd4957d29, 0x105e690c),
++     TOBN(0x7d484363, 0x646559b0), TOBN(0xf4a8273c, 0x49788a8e),
++     TOBN(0xee406cb8, 0x34ce54a9), TOBN(0x1e1c260f, 0xf86fda9b),
++     TOBN(0xe150e228, 0xcf6a4a81), TOBN(0x1fa3b6a3, 0x1b488772),
++     TOBN(0x1e6ff110, 0xc5a9c15b), TOBN(0xc6133b91, 0x8ad6aa47),
++     TOBN(0x8ac5d55c, 0x9dffa978), TOBN(0xba1d1c1d, 0x5f3965f2),
++     TOBN(0xf969f4e0, 0x7732b52f), TOBN(0xfceecdb5, 0xa5172a07),
++     TOBN(0xb0120a5f, 0x10f2b8f5), TOBN(0xc83a6cdf, 0x5c4c2f63),
++     TOBN(0x4d47a491, 0xf8f9c213), TOBN(0xd9e1cce5, 0xd3f1bbd5),
++     TOBN(0x0d91bc7c, 0xaba7e372), TOBN(0xfcdc74c8, 0xdfd1a2db),
++     TOBN(0x05efa800, 0x374618e5), TOBN(0x11216969, 0x15a7925e),
++     TOBN(0xd4c89823, 0xf6021c5d), TOBN(0x880d5e84, 0xeff14423),
++     TOBN(0x6523bc5a, 0x6dcd1396), TOBN(0xd1acfdfc, 0x113c978b),
++     TOBN(0xb0c164e8, 0xbbb66840), TOBN(0xf7f4301e, 0x72b58459),
++     TOBN(0xc29ad4a6, 0xa638e8ec), TOBN(0xf5ab8961, 0x46b78699),
++     TOBN(0x9dbd7974, 0x0e954750), TOBN(0x0121de88, 0x64f9d2c6),
++     TOBN(0x2e597b42, 0xd985232e), TOBN(0x55b6c3c5, 0x53451777),
++     TOBN(0xbb53e547, 0x519cb9fb), TOBN(0xf134019f, 0x8428600d),
++     TOBN(0x5a473176, 0xe081791a), TOBN(0x2f3e2263, 0x35fb0c08),
++     TOBN(0xb28c3017, 0x73d273b0), TOBN(0xccd21076, 0x7721ef9a),
++     TOBN(0x054cc292, 0xb650dc39), TOBN(0x662246de, 0x6188045e),
++     TOBN(0x904b52fa, 0x6b83c0d1), TOBN(0xa72df267, 0x97e9cd46),
++     TOBN(0x886b43cd, 0x899725e4), TOBN(0x2b651688, 0xd849ff22),
++     TOBN(0x60479b79, 0x02f34533), TOBN(0x5e354c14, 0x0c77c148),
++     TOBN(0xb4bb7581, 0xa8537c78), TOBN(0x188043d7, 0xefe1495f),
++     TOBN(0x9ba12f42, 0x8c1d5026), TOBN(0x2e0c8a26, 0x93d4aaab),
++     TOBN(0xbdba7b8b, 0xaa57c450), TOBN(0x140c9ad6, 0x9bbdafef),
++     TOBN(0x2067aa42, 0x25ac0f18), TOBN(0xf7b1295b, 0x04d1fbf3),
++     TOBN(0x14829111, 0xa4b04824), TOBN(0x2ce3f192, 0x33bd5e91),
++     TOBN(0x9c7a1d55, 0x8f2e1b72), TOBN(0xfe932286, 0x302aa243),
++     TOBN(0x497ca7b4, 0xd4be9554), TOBN(0xb8e821b8, 0xe0547a6e),
++     TOBN(0xfb2838be, 0x67e573e0), TOBN(0x05891db9, 0x4084c44b),
++     TOBN(0x91311373, 0x96c1c2c5), TOBN(0x6aebfa3f, 0xd958444b),
++     TOBN(0xac9cdce9, 0xe56e55c1), TOBN(0x7148ced3, 0x2caa46d0),
++     TOBN(0x2e10c7ef, 0xb61fe8eb), TOBN(0x9fd835da, 0xff97cf4d),}
++    ,
++    {TOBN(0xa36da109, 0x081e9387), TOBN(0xfb9780d7, 0x8c935828),
++     TOBN(0xd5940332, 0xe540b015), TOBN(0xc9d7b51b, 0xe0f466fa),
++     TOBN(0xfaadcd41, 0xd6d9f671), TOBN(0xba6c1e28, 0xb1a2ac17),
++     TOBN(0x066a7833, 0xed201e5f), TOBN(0x19d99719, 0xf90f462b),
++     TOBN(0xf431f462, 0x060b5f61), TOBN(0xa56f46b4, 0x7bd057c2),
++     TOBN(0x348dca6c, 0x47e1bf65), TOBN(0x9a38783e, 0x41bcf1ff),
++     TOBN(0x7a5d33a9, 0xda710718), TOBN(0x5a779987, 0x2e0aeaf6),
++     TOBN(0xca87314d, 0x2d29d187), TOBN(0xfa0edc3e, 0xc687d733),
++     TOBN(0x9df33621, 0x6a31e09b), TOBN(0xde89e44d, 0xc1350e35),
++     TOBN(0x29214871, 0x4ca0cf52), TOBN(0xdf379672, 0x0b88a538),
++     TOBN(0xc92a510a, 0x2591d61b), TOBN(0x79aa87d7, 0x585b447b),
++     TOBN(0xf67db604, 0xe5287f77), TOBN(0x1697c8bf, 0x5efe7a80),
++     TOBN(0x1c894849, 0xcb198ac7), TOBN(0xa884a93d, 0x0f264665),
++     TOBN(0x2da964ef, 0x9b200678), TOBN(0x3c351b87, 0x009834e6),
++     TOBN(0xafb2ef9f, 0xe2c4b44b), TOBN(0x580f6c47, 0x3326790c),
++     TOBN(0xb8480521, 0x0b02264a), TOBN(0x8ba6f9e2, 0x42a194e2),
++     TOBN(0xfc87975f, 0x8fb54738), TOBN(0x35160788, 0x27c3ead3),
++     TOBN(0x834116d2, 0xb74a085a), TOBN(0x53c99a73, 0xa62fe996),
++     TOBN(0x87585be0, 0x5b81c51b), TOBN(0x925bafa8, 0xbe0852b7),
++     TOBN(0x76a4fafd, 0xa84d19a7), TOBN(0x39a45982, 0x585206d4),
++     TOBN(0x499b6ab6, 0x5eb03c0e), TOBN(0xf19b7954, 0x72bc3fde),
++     TOBN(0xa86b5b9c, 0x6e3a80d2), TOBN(0xe4377508, 0x6d42819f),
++     TOBN(0xc1663650, 0xbb3ee8a3), TOBN(0x75eb14fc, 0xb132075f),
++     TOBN(0xa8ccc906, 0x7ad834f6), TOBN(0xea6a2474, 0xe6e92ffd),
++     TOBN(0x9d72fd95, 0x0f8d6758), TOBN(0xcb84e101, 0x408c07dd),
++     TOBN(0xb9114bfd, 0xa5e23221), TOBN(0x358b5fe2, 0xe94e742c),
++     TOBN(0x1c0577ec, 0x95f40e75), TOBN(0xf0155451, 0x3d73f3d6),
++     TOBN(0x9d55cd67, 0xbd1b9b66), TOBN(0x63e86e78, 0xaf8d63c7),
++     TOBN(0x39d934ab, 0xd3c095f1), TOBN(0x04b261be, 0xe4b76d71),
++     TOBN(0x1d2e6970, 0xe73e6984), TOBN(0x879fb23b, 0x5e5fcb11),
++     TOBN(0x11506c72, 0xdfd75490), TOBN(0x3a97d085, 0x61bcf1c1),
++     TOBN(0x43201d82, 0xbf5e7007), TOBN(0x7f0ac52f, 0x798232a7),
++     TOBN(0x2715cbc4, 0x6eb564d4), TOBN(0x8d6c752c, 0x9e570e29),
++     TOBN(0xf80247c8, 0x9ef5fd5d), TOBN(0xc3c66b46, 0xd53eb514),
++     TOBN(0x9666b401, 0x0f87de56), TOBN(0xce62c06f, 0xc6c603b5),
++     TOBN(0xae7b4c60, 0x7e4fc942), TOBN(0x38ac0b77, 0x663a9c19),
++     TOBN(0xcb4d20ee, 0x4b049136), TOBN(0x8b63bf12, 0x356a4613),
++     TOBN(0x1221aef6, 0x70e08128), TOBN(0xe62d8c51, 0x4acb6b16),
++     TOBN(0x71f64a67, 0x379e7896), TOBN(0xb25237a2, 0xcafd7fa5),
++     TOBN(0xf077bd98, 0x3841ba6a), TOBN(0xc4ac0244, 0x3cd16e7e),
++     TOBN(0x548ba869, 0x21fea4ca), TOBN(0xd36d0817, 0xf3dfdac1),
++     TOBN(0x09d8d71f, 0xf4685faf), TOBN(0x8eff66be, 0xc52c459a),
++     TOBN(0x182faee7, 0x0b57235e), TOBN(0xee3c39b1, 0x0106712b),
++     TOBN(0x5107331f, 0xc0fcdcb0), TOBN(0x669fb9dc, 0xa51054ba),
++     TOBN(0xb25101fb, 0x319d7682), TOBN(0xb0293129, 0x0a982fee),
++     TOBN(0x51c1c9b9, 0x0261b344), TOBN(0x0e008c5b, 0xbfd371fa),
++     TOBN(0xd866dd1c, 0x0278ca33), TOBN(0x666f76a6, 0xe5aa53b1),
++     TOBN(0xe5cfb779, 0x6013a2cf), TOBN(0x1d3a1aad, 0xa3521836),
++     TOBN(0xcedd2531, 0x73faa485), TOBN(0xc8ee6c4f, 0xc0a76878),
++     TOBN(0xddbccfc9, 0x2a11667d), TOBN(0x1a418ea9, 0x1c2f695a),
++     TOBN(0xdb11bd92, 0x51f73971), TOBN(0x3e4b3c82, 0xda2ed89f),
++     TOBN(0x9a44f3f4, 0xe73e0319), TOBN(0xd1e3de0f, 0x303431af),
++     TOBN(0x3c5604ff, 0x50f75f9c), TOBN(0x1d8eddf3, 0x7e752b22),
++     TOBN(0x0ef074dd, 0x3c9a1118), TOBN(0xd0ffc172, 0xccb86d7b),
++     TOBN(0xabd1ece3, 0x037d90f2), TOBN(0xe3f307d6, 0x6055856c),
++     TOBN(0x422f9328, 0x7e4c6daf), TOBN(0x902aac66, 0x334879a0),
++     TOBN(0xb6a1e7bf, 0x94cdfade), TOBN(0x6c97e1ed, 0x7fc6d634),
++     TOBN(0x662ad24d, 0xa2fb63f8), TOBN(0xf81be1b9, 0xa5928405),
++     TOBN(0x86d765e4, 0xd14b4206), TOBN(0xbecc2e0e, 0x8fa0db65),
++     TOBN(0xa28838e0, 0xb17fc76c), TOBN(0xe49a602a, 0xe37cf24e),
++     TOBN(0x76b4131a, 0x567193ec), TOBN(0xaf3c305a, 0xe5f6e70b),
++     TOBN(0x9587bd39, 0x031eebdd), TOBN(0x5709def8, 0x71bbe831),
++     TOBN(0x57059983, 0x0eb2b669), TOBN(0x4d80ce1b, 0x875b7029),
++     TOBN(0x838a7da8, 0x0364ac16), TOBN(0x2f431d23, 0xbe1c83ab),
++     TOBN(0xe56812a6, 0xf9294dd3), TOBN(0xb448d01f, 0x9b4b0d77),
++     TOBN(0xf3ae6061, 0x04e8305c), TOBN(0x2bead645, 0x94d8c63e),
++     TOBN(0x0a85434d, 0x84fd8b07), TOBN(0x537b983f, 0xf7a9dee5),
++     TOBN(0xedcc5f18, 0xef55bd85), TOBN(0x2041af62, 0x21c6cf8b),
++     TOBN(0x8e52874c, 0xb940c71e), TOBN(0x211935a9, 0xdb5f4b3a),
++     TOBN(0x94350492, 0x301b1dc3), TOBN(0x33d2646d, 0x29958620),
++     TOBN(0x16b0d64b, 0xef911404), TOBN(0x9d1f25ea, 0x9a3c5ef4),
++     TOBN(0x20f200eb, 0x4a352c78), TOBN(0x43929f2c, 0x4bd0b428),
++     TOBN(0xa5656667, 0xc7196e29), TOBN(0x7992c2f0, 0x9391be48),
++     TOBN(0xaaa97cbd, 0x9ee0cd6e), TOBN(0x51b0310c, 0x3dc8c9bf),
++     TOBN(0x237f8acf, 0xdd9f22cb), TOBN(0xbb1d81a1, 0xb585d584),
++     TOBN(0x8d5d85f5, 0x8c416388), TOBN(0x0d6e5a5a, 0x42fe474f),
++     TOBN(0xe7812766, 0x38235d4e), TOBN(0x1c62bd67, 0x496e3298),
++     TOBN(0x8378660c, 0x3f175bc8), TOBN(0x4d04e189, 0x17afdd4d),
++     TOBN(0x32a81601, 0x85a8068c), TOBN(0xdb58e4e1, 0x92b29a85),
++     TOBN(0xe8a65b86, 0xc70d8a3b), TOBN(0x5f0e6f4e, 0x98a0403b),
++     TOBN(0x08129684, 0x69ed2370), TOBN(0x34dc30bd, 0x0871ee26),
++     TOBN(0x3a5ce948, 0x7c9c5b05), TOBN(0x7d487b80, 0x43a90c87),
++     TOBN(0x4089ba37, 0xdd0e7179), TOBN(0x45f80191, 0xb4041811),
++     TOBN(0x1c3e1058, 0x98747ba5), TOBN(0x98c4e13a, 0x6e1ae592),
++     TOBN(0xd44636e6, 0xe82c9f9e), TOBN(0x711db87c, 0xc33a1043),
++     TOBN(0x6f431263, 0xaa8aec05), TOBN(0x43ff120d, 0x2744a4aa),
++     TOBN(0xd3bd892f, 0xae77779b), TOBN(0xf0fe0cc9, 0x8cdc9f82),
++     TOBN(0xca5f7fe6, 0xf1c5b1bc), TOBN(0xcc63a682, 0x44929a72),
++     TOBN(0xc7eaba0c, 0x09dbe19a), TOBN(0x2f3585ad, 0x6b5c73c2),
++     TOBN(0x8ab8924b, 0x0ae50c30), TOBN(0x17fcd27a, 0x638b30ba),
++     TOBN(0xaf414d34, 0x10b3d5a5), TOBN(0x09c107d2, 0x2a9accf1),
++     TOBN(0x15dac49f, 0x946a6242), TOBN(0xaec3df2a, 0xd707d642),
++     TOBN(0x2c2492b7, 0x3f894ae0), TOBN(0xf59df3e5, 0xb75f18ce),
++     TOBN(0x7cb740d2, 0x8f53cad0), TOBN(0x3eb585fb, 0xc4f01294),
++     TOBN(0x17da0c86, 0x32c7f717), TOBN(0xeb8c795b, 0xaf943f4c),
++     TOBN(0x4ee23fb5, 0xf67c51d2), TOBN(0xef187575, 0x68889949),
++     TOBN(0xa6b4bdb2, 0x0389168b), TOBN(0xc4ecd258, 0xea577d03),
++     TOBN(0x3a63782b, 0x55743082), TOBN(0x6f678f4c, 0xc72f08cd),
++     TOBN(0x553511cf, 0x65e58dd8), TOBN(0xd53b4e3e, 0xd402c0cd),
++     TOBN(0x37de3e29, 0xa037c14c), TOBN(0x86b6c516, 0xc05712aa),
++     TOBN(0x2834da3e, 0xb38dff6f), TOBN(0xbe012c52, 0xea636be8),
++     TOBN(0x292d238c, 0x61dd37f8), TOBN(0x0e54523f, 0x8f8142db),
++     TOBN(0xe31eb436, 0x036a05d8), TOBN(0x83e3cdff, 0x1e93c0ff),
++     TOBN(0x3fd2fe0f, 0x50821ddf), TOBN(0xc8e19b0d, 0xff9eb33b),
++     TOBN(0xc8cc943f, 0xb569a5fe), TOBN(0xad0090d4, 0xd4342d75),
++     TOBN(0x82090b4b, 0xcaeca000), TOBN(0xca39687f, 0x1bd410eb),
++     TOBN(0xe7bb0df7, 0x65959d77), TOBN(0x39d78218, 0x9c964999),
++     TOBN(0xd87f62e8, 0xb2415451), TOBN(0xe5efb774, 0xbed76108),
++     TOBN(0x3ea011a4, 0xe822f0d0), TOBN(0xbc647ad1, 0x5a8704f8),
++     TOBN(0xbb315b35, 0x50c6820f), TOBN(0x863dec3d, 0xb7e76bec),
++     TOBN(0x01ff5d3a, 0xf017bfc7), TOBN(0x20054439, 0x976b8229),
++     TOBN(0x067fca37, 0x0bbd0d3b), TOBN(0xf63dde64, 0x7f5e3d0f),
++     TOBN(0x22dbefb3, 0x2a4c94e9), TOBN(0xafbff0fe, 0x96f8278a),
++     TOBN(0x80aea0b1, 0x3503793d), TOBN(0xb2238029, 0x5f06cd29),
++     TOBN(0x65703e57, 0x8ec3feca), TOBN(0x06c38314, 0x393e7053),
++     TOBN(0xa0b751eb, 0x7c6734c4), TOBN(0xd2e8a435, 0xc59f0f1e),
++     TOBN(0x147d9052, 0x5e9ca895), TOBN(0x2f4dd31e, 0x972072df),
++     TOBN(0xa16fda8e, 0xe6c6755c), TOBN(0xc66826ff, 0xcf196558),
++     TOBN(0x1f1a76a3, 0x0cf43895), TOBN(0xa9d604e0, 0x83c3097b),
++     TOBN(0xe1908309, 0x66390e0e), TOBN(0xa50bf753, 0xb3c85eff),
++     TOBN(0x0696bdde, 0xf6a70251), TOBN(0x548b801b, 0x3c6ab16a),
++     TOBN(0x37fcf704, 0xa4d08762), TOBN(0x090b3def, 0xdff76c4e),
++     TOBN(0x87e8cb89, 0x69cb9158), TOBN(0x44a90744, 0x995ece43),
++     TOBN(0xf85395f4, 0x0ad9fbf5), TOBN(0x49b0f6c5, 0x4fb0c82d),
++     TOBN(0x75d9bc15, 0xadf7cccf), TOBN(0x81a3e5d6, 0xdfa1e1b0),
++     TOBN(0x8c39e444, 0x249bc17e), TOBN(0xf37dccb2, 0x8ea7fd43),
++     TOBN(0xda654873, 0x907fba12), TOBN(0x35daa6da, 0x4a372904),
++     TOBN(0x0564cfc6, 0x6283a6c5), TOBN(0xd09fa4f6, 0x4a9395bf),
++     TOBN(0x688e9ec9, 0xaeb19a36), TOBN(0xd913f1ce, 0xc7bfbfb4),
++     TOBN(0x797b9a3c, 0x61c2faa6), TOBN(0x2f979bec, 0x6a0a9c12),
++     TOBN(0xb5969d0f, 0x359679ec), TOBN(0xebcf523d, 0x079b0460),
++     TOBN(0xfd6b0008, 0x10fab870), TOBN(0x3f2edcda, 0x9373a39c),
++     TOBN(0x0d64f9a7, 0x6f568431), TOBN(0xf848c27c, 0x02f8898c),
++     TOBN(0xf418ade1, 0x260b5bd5), TOBN(0xc1f3e323, 0x6973dee8),
++     TOBN(0x46e9319c, 0x26c185dd), TOBN(0x6d85b7d8, 0x546f0ac4),
++     TOBN(0x427965f2, 0x247f9d57), TOBN(0xb519b636, 0xb0035f48),
++     TOBN(0x6b6163a9, 0xab87d59c), TOBN(0xff9f58c3, 0x39caaa11),
++     TOBN(0x4ac39cde, 0x3177387b), TOBN(0x5f6557c2, 0x873e77f9),
++     TOBN(0x67504006, 0x36a83041), TOBN(0x9b1c96ca, 0x75ef196c),
++     TOBN(0xf34283de, 0xb08c7940), TOBN(0x7ea09644, 0x1128c316),
++     TOBN(0xb510b3b5, 0x6aa39dff), TOBN(0x59b43da2, 0x9f8e4d8c),
++     TOBN(0xa8ce31fd, 0x9e4c4b9f), TOBN(0x0e20be26, 0xc1303c01),
++     TOBN(0x18187182, 0xe8ee47c9), TOBN(0xd9687cdb, 0x7db98101),
++     TOBN(0x7a520e4d, 0xa1e14ff6), TOBN(0x429808ba, 0x8836d572),
++     TOBN(0xa37ca60d, 0x4944b663), TOBN(0xf901f7a9, 0xa3f91ae5),
++     TOBN(0xe4e3e76e, 0x9e36e3b1), TOBN(0x9aa219cf, 0x29d93250),
++     TOBN(0x347fe275, 0x056a2512), TOBN(0xa4d643d9, 0xde65d95c),
++     TOBN(0x9669d396, 0x699fc3ed), TOBN(0xb598dee2, 0xcf8c6bbe),
++     TOBN(0x682ac1e5, 0xdda9e5c6), TOBN(0x4e0d3c72, 0xcaa9fc95),
++     TOBN(0x17faaade, 0x772bea44), TOBN(0x5ef8428c, 0xab0009c8),
++     TOBN(0xcc4ce47a, 0x460ff016), TOBN(0xda6d12bf, 0x725281cb),
++     TOBN(0x44c67848, 0x0223aad2), TOBN(0x6e342afa, 0x36256e28),
++     TOBN(0x1400bb0b, 0x93a37c04), TOBN(0x62b1bc9b, 0xdd10bd96),
++     TOBN(0x7251adeb, 0x0dac46b7), TOBN(0x7d33b92e, 0x7be4ef51),
++     TOBN(0x28b2a94b, 0xe61fa29a), TOBN(0x4b2be13f, 0x06422233),
++     TOBN(0x36d6d062, 0x330d8d37), TOBN(0x5ef80e1e, 0xb28ca005),
++     TOBN(0x174d4699, 0x6d16768e), TOBN(0x9fc4ff6a, 0x628bf217),
++     TOBN(0x77705a94, 0x154e490d), TOBN(0x9d96dd28, 0x8d2d997a),
++     TOBN(0x77e2d9d8, 0xce5d72c4), TOBN(0x9d06c5a4, 0xc11c714f),
++     TOBN(0x02aa5136, 0x79e4a03e), TOBN(0x1386b3c2, 0x030ff28b),
++     TOBN(0xfe82e8a6, 0xfb283f61), TOBN(0x7df203e5, 0xf3abc3fb),
++     TOBN(0xeec7c351, 0x3a4d3622), TOBN(0xf7d17dbf, 0xdf762761),
++     TOBN(0xc3956e44, 0x522055f0), TOBN(0xde3012db, 0x8fa748db),
++     TOBN(0xca9fcb63, 0xbf1dcc14), TOBN(0xa56d9dcf, 0xbe4e2f3a),
++     TOBN(0xb86186b6, 0x8bcec9c2), TOBN(0x7cf24df9, 0x680b9f06),
++     TOBN(0xc46b45ea, 0xc0d29281), TOBN(0xfff42bc5, 0x07b10e12),
++     TOBN(0x12263c40, 0x4d289427), TOBN(0x3d5f1899, 0xb4848ec4),
++     TOBN(0x11f97010, 0xd040800c), TOBN(0xb4c5f529, 0x300feb20),
++     TOBN(0xcc543f8f, 0xde94fdcb), TOBN(0xe96af739, 0xc7c2f05e),
++     TOBN(0xaa5e0036, 0x882692e1), TOBN(0x09c75b68, 0x950d4ae9),
++     TOBN(0x62f63df2, 0xb5932a7a), TOBN(0x2658252e, 0xde0979ad),
++     TOBN(0x2a19343f, 0xb5e69631), TOBN(0x718c7501, 0x525b666b),
++     TOBN(0x26a42d69, 0xea40dc3a), TOBN(0xdc84ad22, 0xaecc018f),
++     TOBN(0x25c36c7b, 0x3270f04a), TOBN(0x46ba6d47, 0x50fa72ed),
++     TOBN(0x6c37d1c5, 0x93e58a8e), TOBN(0xa2394731, 0x120c088c),
++     TOBN(0xc3be4263, 0xcb6e86da), TOBN(0x2c417d36, 0x7126d038),
++     TOBN(0x5b70f9c5, 0x8b6f8efa), TOBN(0x671a2faa, 0x37718536),
++     TOBN(0xd3ced3c6, 0xb539c92b), TOBN(0xe56f1bd9, 0xa31203c2),
++     TOBN(0x8b096ec4, 0x9ff3c8eb), TOBN(0x2deae432, 0x43491cea),
++     TOBN(0x2465c6eb, 0x17943794), TOBN(0x5d267e66, 0x20586843),
++     TOBN(0x9d3d116d, 0xb07159d0), TOBN(0xae07a67f, 0xc1896210),
++     TOBN(0x8fc84d87, 0xbb961579), TOBN(0x30009e49, 0x1c1f8dd6),
++     TOBN(0x8a8caf22, 0xe3132819), TOBN(0xcffa197c, 0xf23ab4ff),
++     TOBN(0x58103a44, 0x205dd687), TOBN(0x57b796c3, 0x0ded67a2),
++     TOBN(0x0b9c3a6c, 0xa1779ad7), TOBN(0xa33cfe2e, 0x357c09c5),
++     TOBN(0x2ea29315, 0x3db4a57e), TOBN(0x91959695, 0x8ebeb52e),
++     TOBN(0x118db9a6, 0xe546c879), TOBN(0x8e996df4, 0x6295c8d6),
++     TOBN(0xdd990484, 0x55ec806b), TOBN(0x24f291ca, 0x165c1035),
++     TOBN(0xcca523bb, 0x440e2229), TOBN(0x324673a2, 0x73ef4d04),
++     TOBN(0xaf3adf34, 0x3e11ec39), TOBN(0x6136d7f1, 0xdc5968d3),
++     TOBN(0x7a7b2899, 0xb053a927), TOBN(0x3eaa2661, 0xae067ecd),
++     TOBN(0x8549b9c8, 0x02779cd9), TOBN(0x061d7940, 0xc53385ea),
++     TOBN(0x3e0ba883, 0xf06d18bd), TOBN(0x4ba6de53, 0xb2700843),
++     TOBN(0xb966b668, 0x591a9e4d), TOBN(0x93f67567, 0x7f4fa0ed),
++     TOBN(0x5a02711b, 0x4347237b), TOBN(0xbc041e2f, 0xe794608e),
++     TOBN(0x55af10f5, 0x70f73d8c), TOBN(0xd2d4d4f7, 0xbb7564f7),
++     TOBN(0xd7d27a89, 0xb3e93ce7), TOBN(0xf7b5a875, 0x5d3a2c1b),
++     TOBN(0xb29e68a0, 0x255b218a), TOBN(0xb533837e, 0x8af76754),
++     TOBN(0xd1b05a73, 0x579fab2e), TOBN(0xb41055a1, 0xecd74385),
++     TOBN(0xb2369274, 0x445e9115), TOBN(0x2972a7c4, 0xf520274e),
++     TOBN(0x6c08334e, 0xf678e68a), TOBN(0x4e4160f0, 0x99b057ed),
++     TOBN(0x3cfe11b8, 0x52ccb69a), TOBN(0x2fd1823a, 0x21c8f772),
++     TOBN(0xdf7f072f, 0x3298f055), TOBN(0x8c0566f9, 0xfec74a6e),
++     TOBN(0xe549e019, 0x5bb4d041), TOBN(0x7c3930ba, 0x9208d850),
++     TOBN(0xe07141fc, 0xaaa2902b), TOBN(0x539ad799, 0xe4f69ad3),
++     TOBN(0xa6453f94, 0x813f9ffd), TOBN(0xc58d3c48, 0x375bc2f7),
++     TOBN(0xb3326fad, 0x5dc64e96), TOBN(0x3aafcaa9, 0xb240e354),
++     TOBN(0x1d1b0903, 0xaca1e7a9), TOBN(0x4ceb9767, 0x1211b8a0),
++     TOBN(0xeca83e49, 0xe32a858e), TOBN(0x4c32892e, 0xae907bad),
++     TOBN(0xd5b42ab6, 0x2eb9b494), TOBN(0x7fde3ee2, 0x1eabae1b),
++     TOBN(0x13b5ab09, 0xcaf54957), TOBN(0xbfb028be, 0xe5f5d5d5),
++     TOBN(0x928a0650, 0x2003e2c0), TOBN(0x90793aac, 0x67476843),
++     TOBN(0x5e942e79, 0xc81710a0), TOBN(0x557e4a36, 0x27ccadd4),
++     TOBN(0x72a2bc56, 0x4bcf6d0c), TOBN(0x09ee5f43, 0x26d7b80c),
++     TOBN(0x6b70dbe9, 0xd4292f19), TOBN(0x56f74c26, 0x63f16b18),
++     TOBN(0xc23db0f7, 0x35fbb42a), TOBN(0xb606bdf6, 0x6ae10040),
++     TOBN(0x1eb15d4d, 0x044573ac), TOBN(0x7dc3cf86, 0x556b0ba4),
++     TOBN(0x97af9a33, 0xc60df6f7), TOBN(0x0b1ef85c, 0xa716ce8c),
++     TOBN(0x2922f884, 0xc96958be), TOBN(0x7c32fa94, 0x35690963),
++     TOBN(0x2d7f667c, 0xeaa00061), TOBN(0xeaaf7c17, 0x3547365c),
++     TOBN(0x1eb4de46, 0x87032d58), TOBN(0xc54f3d83, 0x5e2c79e0),
++     TOBN(0x07818df4, 0x5d04ef23), TOBN(0x55faa9c8, 0x673d41b4),
++     TOBN(0xced64f6f, 0x89b95355), TOBN(0x4860d2ea, 0xb7415c84),
++     TOBN(0x5fdb9bd2, 0x050ebad3), TOBN(0xdb53e0cc, 0x6685a5bf),
++     TOBN(0xb830c031, 0x9feb6593), TOBN(0xdd87f310, 0x6accff17),
++     TOBN(0x2303ebab, 0x9f555c10), TOBN(0x94603695, 0x287e7065),
++     TOBN(0xf88311c3, 0x2e83358c), TOBN(0x508dd9b4, 0xeefb0178),
++     TOBN(0x7ca23706, 0x2dba8652), TOBN(0x62aac5a3, 0x0047abe5),
++     TOBN(0x9a61d2a0, 0x8b1ea7b3), TOBN(0xd495ab63, 0xae8b1485),
++     TOBN(0x38740f84, 0x87052f99), TOBN(0x178ebe5b, 0xb2974eea),
++     TOBN(0x030bbcca, 0x5b36d17f), TOBN(0xb5e4cce3, 0xaaf86eea),
++     TOBN(0xb51a0220, 0x68f8e9e0), TOBN(0xa4348796, 0x09eb3e75),
++     TOBN(0xbe592309, 0xeef1a752), TOBN(0x5d7162d7, 0x6f2aa1ed),
++     TOBN(0xaebfb5ed, 0x0f007dd2), TOBN(0x255e14b2, 0xc89edd22),
++     TOBN(0xba85e072, 0x0303b697), TOBN(0xc5d17e25, 0xf05720ff),
++     TOBN(0x02b58d6e, 0x5128ebb6), TOBN(0x2c80242d, 0xd754e113),
++     TOBN(0x919fca5f, 0xabfae1ca), TOBN(0x937afaac, 0x1a21459b),
++     TOBN(0x9e0ca91c, 0x1f66a4d2), TOBN(0x194cc7f3, 0x23ec1331),
++     TOBN(0xad25143a, 0x8aa11690), TOBN(0xbe40ad8d, 0x09b59e08),
++     TOBN(0x37d60d9b, 0xe750860a), TOBN(0x6c53b008, 0xc6bf434c),
++     TOBN(0xb572415d, 0x1356eb80), TOBN(0xb8bf9da3, 0x9578ded8),
++     TOBN(0x22658e36, 0x5e8fb38b), TOBN(0x9b70ce22, 0x5af8cb22),
++     TOBN(0x7c00018a, 0x829a8180), TOBN(0x84329f93, 0xb81ed295),
++     TOBN(0x7c343ea2, 0x5f3cea83), TOBN(0x38f8655f, 0x67586536),
++     TOBN(0xa661a0d0, 0x1d3ec517), TOBN(0x98744652, 0x512321ae),
++     TOBN(0x084ca591, 0xeca92598), TOBN(0xa9bb9dc9, 0x1dcb3feb),
++     TOBN(0x14c54355, 0x78b4c240), TOBN(0x5ed62a3b, 0x610cafdc),
++     TOBN(0x07512f37, 0x1b38846b), TOBN(0x571bb70a, 0xb0e38161),
++     TOBN(0xb556b95b, 0x2da705d2), TOBN(0x3ef8ada6, 0xb1a08f98),
++     TOBN(0x85302ca7, 0xddecfbe5), TOBN(0x0e530573, 0x943105cd),
++     TOBN(0x60554d55, 0x21a9255d), TOBN(0x63a32fa1, 0xf2f3802a),
++     TOBN(0x35c8c5b0, 0xcd477875), TOBN(0x97f458ea, 0x6ad42da1),
++     TOBN(0x832d7080, 0xeb6b242d), TOBN(0xd30bd023, 0x3b71e246),
++     TOBN(0x7027991b, 0xbe31139d), TOBN(0x68797e91, 0x462e4e53),
++     TOBN(0x423fe20a, 0x6b4e185a), TOBN(0x82f2c67e, 0x42d9b707),
++     TOBN(0x25c81768, 0x4cf7811b), TOBN(0xbd53005e, 0x045bb95d),}
++    ,
++    {TOBN(0xe5f649be, 0x9d8e68fd), TOBN(0xdb0f0533, 0x1b044320),
++     TOBN(0xf6fde9b3, 0xe0c33398), TOBN(0x92f4209b, 0x66c8cfae),
++     TOBN(0xe9d1afcc, 0x1a739d4b), TOBN(0x09aea75f, 0xa28ab8de),
++     TOBN(0x14375fb5, 0xeac6f1d0), TOBN(0x6420b560, 0x708f7aa5),
++     TOBN(0x9eae499c, 0x6254dc41), TOBN(0x7e293924, 0x7a837e7e),
++     TOBN(0x74aec08c, 0x090524a7), TOBN(0xf82b9219, 0x8d6f55f2),
++     TOBN(0x493c962e, 0x1402cec5), TOBN(0x9f17ca17, 0xfa2f30e7),
++     TOBN(0xbcd783e8, 0xe9b879cb), TOBN(0xea3d8c14, 0x5a6f145f),
++     TOBN(0xdede15e7, 0x5e0dee6e), TOBN(0x74f24872, 0xdc628aa2),
++     TOBN(0xd3e9c4fe, 0x7861bb93), TOBN(0x56d4822a, 0x6187b2e0),
++     TOBN(0xb66417cf, 0xc59826f9), TOBN(0xca260969, 0x2408169e),
++     TOBN(0xedf69d06, 0xc79ef885), TOBN(0x00031f8a, 0xdc7d138f),
++     TOBN(0x103c46e6, 0x0ebcf726), TOBN(0x4482b831, 0x6231470e),
++     TOBN(0x6f6dfaca, 0x487c2109), TOBN(0x2e0ace97, 0x62e666ef),
++     TOBN(0x3246a9d3, 0x1f8d1f42), TOBN(0x1b1e83f1, 0x574944d2),
++     TOBN(0x13dfa63a, 0xa57f334b), TOBN(0x0cf8daed, 0x9f025d81),
++     TOBN(0x30d78ea8, 0x00ee11c1), TOBN(0xeb053cd4, 0xb5e3dd75),
++     TOBN(0x9b65b13e, 0xd58c43c5), TOBN(0xc3ad49bd, 0xbd151663),
++     TOBN(0x99fd8e41, 0xb6427990), TOBN(0x12cf15bd, 0x707eae1e),
++     TOBN(0x29ad4f1b, 0x1aabb71e), TOBN(0x5143e74d, 0x07545d0e),
++     TOBN(0x30266336, 0xc88bdee1), TOBN(0x25f29306, 0x5876767c),
++     TOBN(0x9c078571, 0xc6731996), TOBN(0xc88690b2, 0xed552951),
++     TOBN(0x274f2c2d, 0x852705b4), TOBN(0xb0bf8d44, 0x4e09552d),
++     TOBN(0x7628beeb, 0x986575d1), TOBN(0x407be238, 0x7f864651),
++     TOBN(0x0e5e3049, 0xa639fc6b), TOBN(0xe75c35d9, 0x86003625),
++     TOBN(0x0cf35bd8, 0x5dcc1646), TOBN(0x8bcaced2, 0x6c26273a),
++     TOBN(0xe22ecf1d, 0xb5536742), TOBN(0x013dd897, 0x1a9e068b),
++     TOBN(0x17f411cb, 0x8a7909c5), TOBN(0x5757ac98, 0x861dd506),
++     TOBN(0x85de1f0d, 0x1e935abb), TOBN(0xdefd10b4, 0x154de37a),
++     TOBN(0xb8d9e392, 0x369cebb5), TOBN(0x54d5ef9b, 0x761324be),
++     TOBN(0x4d6341ba, 0x74f17e26), TOBN(0xc0a0e3c8, 0x78c1dde4),
++     TOBN(0xa6d77581, 0x87d918fd), TOBN(0x66876015, 0x02ca3a13),
++     TOBN(0xc7313e9c, 0xf36658f0), TOBN(0xc433ef1c, 0x71f8057e),
++     TOBN(0x85326246, 0x1b6a835a), TOBN(0xc8f05398, 0x7c86394c),
++     TOBN(0xff398cdf, 0xe983c4a1), TOBN(0xbf5e8162, 0x03b7b931),
++     TOBN(0x93193c46, 0xb7b9045b), TOBN(0x1e4ebf5d, 0xa4a6e46b),
++     TOBN(0xf9942a60, 0x43a24fe7), TOBN(0x29c1191e, 0xffb3492b),
++     TOBN(0x9f662449, 0x902fde05), TOBN(0xc792a7ac, 0x6713c32d),
++     TOBN(0x2fd88ad8, 0xb737982c), TOBN(0x7e3a0319, 0xa21e60e3),
++     TOBN(0x09b0de44, 0x7383591a), TOBN(0x6df141ee, 0x8310a456),
++     TOBN(0xaec1a039, 0xe6d6f471), TOBN(0x14b2ba0f, 0x1198d12e),
++     TOBN(0xebc1a160, 0x3aeee5ac), TOBN(0x401f4836, 0xe0b964ce),
++     TOBN(0x2ee43796, 0x4fd03f66), TOBN(0x3fdb4e49, 0xdd8f3f12),
++     TOBN(0x6ef267f6, 0x29380f18), TOBN(0x3e8e9670, 0x8da64d16),
++     TOBN(0xbc19180c, 0x207674f1), TOBN(0x112e09a7, 0x33ae8fdb),
++     TOBN(0x99667554, 0x6aaeb71e), TOBN(0x79432af1, 0xe101b1c7),
++     TOBN(0xd5eb558f, 0xde2ddec6), TOBN(0x81392d1f, 0x5357753f),
++     TOBN(0xa7a76b97, 0x3ae1158a), TOBN(0x416fbbff, 0x4a899991),
++     TOBN(0x9e65fdfd, 0x0d4a9dcf), TOBN(0x7bc29e48, 0x944ddf12),
++     TOBN(0xbc1a92d9, 0x3c856866), TOBN(0x273c6905, 0x6e98dfe2),
++     TOBN(0x69fce418, 0xcdfaa6b8), TOBN(0x606bd823, 0x5061c69f),
++     TOBN(0x42d495a0, 0x6af75e27), TOBN(0x8ed3d505, 0x6d873a1f),
++     TOBN(0xaf552841, 0x6ab25b6a), TOBN(0xc6c0ffc7, 0x2b1a4523),
++     TOBN(0xab18827b, 0x21c99e03), TOBN(0x060e8648, 0x9034691b),
++     TOBN(0x5207f90f, 0x93c7f398), TOBN(0x9f4a96cb, 0x82f8d10b),
++     TOBN(0xdd71cd79, 0x3ad0f9e3), TOBN(0x84f435d2, 0xfc3a54f5),
++     TOBN(0x4b03c55b, 0x8e33787f), TOBN(0xef42f975, 0xa6384673),
++     TOBN(0xff7304f7, 0x5051b9f0), TOBN(0x18aca1dc, 0x741c87c2),
++     TOBN(0x56f120a7, 0x2d4bfe80), TOBN(0xfd823b3d, 0x053e732c),
++     TOBN(0x11bccfe4, 0x7537ca16), TOBN(0xdf6c9c74, 0x1b5a996b),
++     TOBN(0xee7332c7, 0x904fc3fa), TOBN(0x14a23f45, 0xc7e3636a),
++     TOBN(0xc38659c3, 0xf091d9aa), TOBN(0x4a995e5d, 0xb12d8540),
++     TOBN(0x20a53bec, 0xf3a5598a), TOBN(0x56534b17, 0xb1eaa995),
++     TOBN(0x9ed3dca4, 0xbf04e03c), TOBN(0x716c563a, 0xd8d56268),
++     TOBN(0x27ba77a4, 0x1d6178e7), TOBN(0xe4c80c40, 0x68a1ff8e),
++     TOBN(0x75011099, 0x0a13f63d), TOBN(0x7bf33521, 0xa61d46f3),
++     TOBN(0x0aff218e, 0x10b365bb), TOBN(0x81021804, 0x0fd7ea75),
++     TOBN(0x05a3fd8a, 0xa4b3a925), TOBN(0xb829e75f, 0x9b3db4e6),
++     TOBN(0x6bdc75a5, 0x4d53e5fb), TOBN(0x04a5dc02, 0xd52717e3),
++     TOBN(0x86af502f, 0xe9a42ec2), TOBN(0x8867e8fb, 0x2630e382),
++     TOBN(0xbf845c6e, 0xbec9889b), TOBN(0x54f491f2, 0xcb47c98d),
++     TOBN(0xa3091fba, 0x790c2a12), TOBN(0xd7f6fd78, 0xc20f708b),
++     TOBN(0xa569ac30, 0xacde5e17), TOBN(0xd0f996d0, 0x6852b4d7),
++     TOBN(0xe51d4bb5, 0x4609ae54), TOBN(0x3fa37d17, 0x0daed061),
++     TOBN(0x62a88684, 0x34b8fb41), TOBN(0x99a2acbd, 0x9efb64f1),
++     TOBN(0xb75c1a5e, 0x6448e1f2), TOBN(0xfa99951a, 0x42b5a069),
++     TOBN(0x6d956e89, 0x2f3b26e7), TOBN(0xf4709860, 0xda875247),
++     TOBN(0x3ad15179, 0x2482dda3), TOBN(0xd64110e3, 0x017d82f0),
++     TOBN(0x14928d2c, 0xfad414e4), TOBN(0x2b155f58, 0x2ed02b24),
++     TOBN(0x481a141b, 0xcb821bf1), TOBN(0x12e3c770, 0x4f81f5da),
++     TOBN(0xe49c5de5, 0x9fff8381), TOBN(0x11053232, 0x5bbec894),
++     TOBN(0xa0d051cc, 0x454d88c4), TOBN(0x4f6db89c, 0x1f8e531b),
++     TOBN(0x34fe3fd6, 0xca563a44), TOBN(0x7f5c2215, 0x58da8ab9),
++     TOBN(0x8445016d, 0x9474f0a1), TOBN(0x17d34d61, 0xcb7d8a0a),
++     TOBN(0x8e9d3910, 0x1c474019), TOBN(0xcaff2629, 0xd52ceefb),
++     TOBN(0xf9cf3e32, 0xc1622c2b), TOBN(0xd4b95e3c, 0xe9071a05),
++     TOBN(0xfbbca61f, 0x1594438c), TOBN(0x1eb6e6a6, 0x04aadedf),
++     TOBN(0x853027f4, 0x68e14940), TOBN(0x221d322a, 0xdfabda9c),
++     TOBN(0xed8ea9f6, 0xb7cb179a), TOBN(0xdc7b764d, 0xb7934dcc),
++     TOBN(0xfcb13940, 0x5e09180d), TOBN(0x6629a6bf, 0xb47dc2dd),
++     TOBN(0xbfc55e4e, 0x9f5a915e), TOBN(0xb1db9d37, 0x6204441e),
++     TOBN(0xf82d68cf, 0x930c5f53), TOBN(0x17d3a142, 0xcbb605b1),
++     TOBN(0xdd5944ea, 0x308780f2), TOBN(0xdc8de761, 0x3845f5e4),
++     TOBN(0x6beaba7d, 0x7624d7a3), TOBN(0x1e709afd, 0x304df11e),
++     TOBN(0x95364376, 0x02170456), TOBN(0xbf204b3a, 0xc8f94b64),
++     TOBN(0x4e53af7c, 0x5680ca68), TOBN(0x0526074a, 0xe0c67574),
++     TOBN(0x95d8cef8, 0xecd92af6), TOBN(0xe6b9fa7a, 0x6cd1745a),
++     TOBN(0x3d546d3d, 0xa325c3e4), TOBN(0x1f57691d, 0x9ae93aae),
++     TOBN(0xe891f3fe, 0x9d2e1a33), TOBN(0xd430093f, 0xac063d35),
++     TOBN(0xeda59b12, 0x5513a327), TOBN(0xdc2134f3, 0x5536f18f),
++     TOBN(0xaa51fe2c, 0x5c210286), TOBN(0x3f68aaee, 0x1cab658c),
++     TOBN(0x5a23a00b, 0xf9357292), TOBN(0x9a626f39, 0x7efdabed),
++     TOBN(0xfe2b3bf3, 0x199d78e3), TOBN(0xb7a2af77, 0x71bbc345),
++     TOBN(0x3d19827a, 0x1e59802c), TOBN(0x823bbc15, 0xb487a51c),
++     TOBN(0x856139f2, 0x99d0a422), TOBN(0x9ac3df65, 0xf456c6fb),
++     TOBN(0xaddf65c6, 0x701f8bd6), TOBN(0x149f321e, 0x3758df87),
++     TOBN(0xb1ecf714, 0x721b7eba), TOBN(0xe17df098, 0x31a3312a),
++     TOBN(0xdb2fd6ec, 0xd5c4d581), TOBN(0xfd02996f, 0x8fcea1b3),
++     TOBN(0xe29fa63e, 0x7882f14f), TOBN(0xc9f6dc35, 0x07c6cadc),
++     TOBN(0x46f22d6f, 0xb882bed0), TOBN(0x1a45755b, 0xd118e52c),
++     TOBN(0x9f2c7c27, 0x7c4608cf), TOBN(0x7ccbdf32, 0x568012c2),
++     TOBN(0xfcb0aedd, 0x61729b0e), TOBN(0x7ca2ca9e, 0xf7d75dbf),
++     TOBN(0xf58fecb1, 0x6f640f62), TOBN(0xe274b92b, 0x39f51946),
++     TOBN(0x7f4dfc04, 0x6288af44), TOBN(0x0a91f32a, 0xeac329e5),
++     TOBN(0x43ad274b, 0xd6aaba31), TOBN(0x719a1640, 0x0f6884f9),
++     TOBN(0x685d29f6, 0xdaf91e20), TOBN(0x5ec1cc33, 0x27e49d52),
++     TOBN(0x38f4de96, 0x3b54a059), TOBN(0x0e0015e5, 0xefbcfdb3),
++     TOBN(0x177d23d9, 0x4dbb8da6), TOBN(0x98724aa2, 0x97a617ad),
++     TOBN(0x30f0885b, 0xfdb6558e), TOBN(0xf9f7a28a, 0xc7899a96),
++     TOBN(0xd2ae8ac8, 0x872dc112), TOBN(0xfa0642ca, 0x73c3c459),
++     TOBN(0x15296981, 0xe7dfc8d6), TOBN(0x67cd4450, 0x1fb5b94a),
++     TOBN(0x0ec71cf1, 0x0eddfd37), TOBN(0xc7e5eeb3, 0x9a8eddc7),
++     TOBN(0x02ac8e3d, 0x81d95028), TOBN(0x0088f172, 0x70b0e35d),
++     TOBN(0xec041fab, 0xe1881fe3), TOBN(0x62cf71b8, 0xd99e7faa),
++     TOBN(0x5043dea7, 0xe0f222c2), TOBN(0x309d42ac, 0x72e65142),
++     TOBN(0x94fe9ddd, 0x9216cd30), TOBN(0xd6539c7d, 0x0f87feec),
++     TOBN(0x03c5a57c, 0x432ac7d7), TOBN(0x72692cf0, 0x327fda10),
++     TOBN(0xec28c85f, 0x280698de), TOBN(0x2331fb46, 0x7ec283b1),
++     TOBN(0xd34bfa32, 0x2867e633), TOBN(0x78709a82, 0x0a9cc815),
++     TOBN(0xb7fe6964, 0x875e2fa5), TOBN(0x25cc064f, 0x9e98bfb5),
++     TOBN(0x9eb0151c, 0x493a65c5), TOBN(0x5fb5d941, 0x53182464),
++     TOBN(0x69e6f130, 0xf04618e2), TOBN(0xa8ecec22, 0xf89c8ab6),
++     TOBN(0xcd6ac88b, 0xb96209bd), TOBN(0x65fa8cdb, 0xb3e1c9e0),
++     TOBN(0xa47d22f5, 0x4a8d8eac), TOBN(0x83895cdf, 0x8d33f963),
++     TOBN(0xa8adca59, 0xb56cd3d1), TOBN(0x10c8350b, 0xdaf38232),
++     TOBN(0x2b161fb3, 0xa5080a9f), TOBN(0xbe7f5c64, 0x3af65b3a),
++     TOBN(0x2c754039, 0x97403a11), TOBN(0x94626cf7, 0x121b96af),
++     TOBN(0x431de7c4, 0x6a983ec2), TOBN(0x3780dd3a, 0x52cc3df7),
++     TOBN(0xe28a0e46, 0x2baf8e3b), TOBN(0xabe68aad, 0x51d299ae),
++     TOBN(0x603eb8f9, 0x647a2408), TOBN(0x14c61ed6, 0x5c750981),
++     TOBN(0x88b34414, 0xc53352e7), TOBN(0x5a34889c, 0x1337d46e),
++     TOBN(0x612c1560, 0xf95f2bc8), TOBN(0x8a3f8441, 0xd4807a3a),
++     TOBN(0x680d9e97, 0x5224da68), TOBN(0x60cd6e88, 0xc3eb00e9),
++     TOBN(0x3875a98e, 0x9a6bc375), TOBN(0xdc80f924, 0x4fd554c2),
++     TOBN(0x6c4b3415, 0x6ac77407), TOBN(0xa1e5ea8f, 0x25420681),
++     TOBN(0x541bfa14, 0x4607a458), TOBN(0x5dbc7e7a, 0x96d7fbf9),
++     TOBN(0x646a851b, 0x31590a47), TOBN(0x039e85ba, 0x15ee6df8),
++     TOBN(0xd19fa231, 0xd7b43fc0), TOBN(0x84bc8be8, 0x299a0e04),
++     TOBN(0x2b9d2936, 0xf20df03a), TOBN(0x24054382, 0x8608d472),
++     TOBN(0x76b6ba04, 0x9149202a), TOBN(0xb21c3831, 0x3670e7b7),
++     TOBN(0xddd93059, 0xd6fdee10), TOBN(0x9da47ad3, 0x78488e71),
++     TOBN(0x99cc1dfd, 0xa0fcfb25), TOBN(0x42abde10, 0x64696954),
++     TOBN(0x14cc15fc, 0x17eab9fe), TOBN(0xd6e863e4, 0xd3e70972),
++     TOBN(0x29a7765c, 0x6432112c), TOBN(0x88660001, 0x5b0774d8),
++     TOBN(0x3729175a, 0x2c088eae), TOBN(0x13afbcae, 0x8230b8d4),
++     TOBN(0x44768151, 0x915f4379), TOBN(0xf086431a, 0xd8d22812),
++     TOBN(0x37461955, 0xc298b974), TOBN(0x905fb5f0, 0xf8711e04),
++     TOBN(0x787abf3a, 0xfe969d18), TOBN(0x392167c2, 0x6f6a494e),
++     TOBN(0xfc7a0d2d, 0x28c511da), TOBN(0xf127c7dc, 0xb66a262d),
++     TOBN(0xf9c4bb95, 0xfd63fdf0), TOBN(0x90016589, 0x3913ef46),
++     TOBN(0x74d2a73c, 0x11aa600d), TOBN(0x2f5379bd, 0x9fb5ab52),
++     TOBN(0xe49e53a4, 0x7fb70068), TOBN(0x68dd39e5, 0x404aa9a7),
++     TOBN(0xb9b0cf57, 0x2ecaa9c3), TOBN(0xba0e103b, 0xe824826b),
++     TOBN(0x60c2198b, 0x4631a3c4), TOBN(0xc5ff84ab, 0xfa8966a2),
++     TOBN(0x2d6ebe22, 0xac95aff8), TOBN(0x1c9bb6db, 0xb5a46d09),
++     TOBN(0x419062da, 0x53ee4f8d), TOBN(0x7b9042d0, 0xbb97efef),
++     TOBN(0x0f87f080, 0x830cf6bd), TOBN(0x4861d19a, 0x6ec8a6c6),
++     TOBN(0xd3a0daa1, 0x202f01aa), TOBN(0xb0111674, 0xf25afbd5),
++     TOBN(0x6d00d6cf, 0x1afb20d9), TOBN(0x13695000, 0x40671bc5),
++     TOBN(0x913ab0dc, 0x2485ea9b), TOBN(0x1f2bed06, 0x9eef61ac),
++     TOBN(0x850c8217, 0x6d799e20), TOBN(0x93415f37, 0x3271c2de),
++     TOBN(0x5afb06e9, 0x6c4f5910), TOBN(0x688a52df, 0xc4e9e421),
++     TOBN(0x30495ba3, 0xe2a9a6db), TOBN(0x4601303d, 0x58f9268b),
++     TOBN(0xbe3b0dad, 0x7eb0f04f), TOBN(0x4ea47250, 0x4456936d),
++     TOBN(0x8caf8798, 0xd33fd3e7), TOBN(0x1ccd8a89, 0xeb433708),
++     TOBN(0x9effe3e8, 0x87fd50ad), TOBN(0xbe240a56, 0x6b29c4df),
++     TOBN(0xec4ffd98, 0xca0e7ebd), TOBN(0xf586783a, 0xe748616e),
++     TOBN(0xa5b00d8f, 0xc77baa99), TOBN(0x0acada29, 0xb4f34c9c),
++     TOBN(0x36dad67d, 0x0fe723ac), TOBN(0x1d8e53a5, 0x39c36c1e),
++     TOBN(0xe4dd342d, 0x1f4bea41), TOBN(0x64fd5e35, 0xebc9e4e0),
++     TOBN(0x96f01f90, 0x57908805), TOBN(0xb5b9ea3d, 0x5ed480dd),
++     TOBN(0x366c5dc2, 0x3efd2dd0), TOBN(0xed2fe305, 0x6e9dfa27),
++     TOBN(0x4575e892, 0x6e9197e2), TOBN(0x11719c09, 0xab502a5d),
++     TOBN(0x264c7bec, 0xe81f213f), TOBN(0x741b9241, 0x55f5c457),
++     TOBN(0x78ac7b68, 0x49a5f4f4), TOBN(0xf91d70a2, 0x9fc45b7d),
++     TOBN(0x39b05544, 0xb0f5f355), TOBN(0x11f06bce, 0xeef930d9),
++     TOBN(0xdb84d25d, 0x038d05e1), TOBN(0x04838ee5, 0xbacc1d51),
++     TOBN(0x9da3ce86, 0x9e8ee00b), TOBN(0xc3412057, 0xc36eda1f),
++     TOBN(0xae80b913, 0x64d9c2f4), TOBN(0x7468bac3, 0xa010a8ff),
++     TOBN(0xdfd20037, 0x37359d41), TOBN(0x1a0f5ab8, 0x15efeacc),
++     TOBN(0x7c25ad2f, 0x659d0ce0), TOBN(0x4011bcbb, 0x6785cff1),
++     TOBN(0x128b9912, 0x7e2192c7), TOBN(0xa549d8e1, 0x13ccb0e8),
++     TOBN(0x805588d8, 0xc85438b1), TOBN(0x5680332d, 0xbc25cb27),
++     TOBN(0xdcd1bc96, 0x1a4bfdf4), TOBN(0x779ff428, 0x706f6566),
++     TOBN(0x8bbee998, 0xf059987a), TOBN(0xf6ce8cf2, 0xcc686de7),
++     TOBN(0xf8ad3c4a, 0x953cfdb2), TOBN(0xd1d426d9, 0x2205da36),
++     TOBN(0xb3c0f13f, 0xc781a241), TOBN(0x3e89360e, 0xd75362a8),
++     TOBN(0xccd05863, 0xc8a91184), TOBN(0x9bd0c9b7, 0xefa8a7f4),
++     TOBN(0x97ee4d53, 0x8a912a4b), TOBN(0xde5e15f8, 0xbcf518fd),
++     TOBN(0x6a055bf8, 0xc467e1e0), TOBN(0x10be4b4b, 0x1587e256),
++     TOBN(0xd90c14f2, 0x668621c9), TOBN(0xd5518f51, 0xab9c92c1),
++     TOBN(0x8e6a0100, 0xd6d47b3c), TOBN(0xcbe980dd, 0x66716175),
++     TOBN(0x500d3f10, 0xddd83683), TOBN(0x3b6cb35d, 0x99cac73c),
++     TOBN(0x53730c8b, 0x6083d550), TOBN(0xcf159767, 0xdf0a1987),
++     TOBN(0x84bfcf53, 0x43ad73b3), TOBN(0x1b528c20, 0x4f035a94),
++     TOBN(0x4294edf7, 0x33eeac69), TOBN(0xb6283e83, 0x817f3240),
++     TOBN(0xc3fdc959, 0x0a5f25b1), TOBN(0xefaf8aa5, 0x5844ee22),
++     TOBN(0xde269ba5, 0xdbdde4de), TOBN(0xe3347160, 0xc56133bf),
++     TOBN(0xc1184219, 0x8d9ea9f8), TOBN(0x090de5db, 0xf3fc1ab5),
++     TOBN(0x404c37b1, 0x0bf22cda), TOBN(0x7de20ec8, 0xf5618894),
++     TOBN(0x754c588e, 0xecdaecab), TOBN(0x6ca4b0ed, 0x88342743),
++     TOBN(0x76f08bdd, 0xf4a938ec), TOBN(0xd182de89, 0x91493ccb),
++     TOBN(0xd652c53e, 0xc8a4186a), TOBN(0xb3e878db, 0x946d8e33),
++     TOBN(0x088453c0, 0x5f37663c), TOBN(0x5cd9daaa, 0xb407748b),
++     TOBN(0xa1f5197f, 0x586d5e72), TOBN(0x47500be8, 0xc443ca59),
++     TOBN(0x78ef35b2, 0xe2652424), TOBN(0x09c5d26f, 0x6dd7767d),
++     TOBN(0x7175a79a, 0xa74d3f7b), TOBN(0x0428fd8d, 0xcf5ea459),
++     TOBN(0x511cb97c, 0xa5d1746d), TOBN(0x36363939, 0xe71d1278),
++     TOBN(0xcf2df955, 0x10350bf4), TOBN(0xb3817439, 0x60aae782),
++     TOBN(0xa748c0e4, 0x3e688809), TOBN(0x98021fbf, 0xd7a5a006),
++     TOBN(0x9076a70c, 0x0e367a98), TOBN(0xbea1bc15, 0x0f62b7c2),
++     TOBN(0x2645a68c, 0x30fe0343), TOBN(0xacaffa78, 0x699dc14f),
++     TOBN(0xf4469964, 0x457bf9c4), TOBN(0x0db6407b, 0x0d2ead83),
++     TOBN(0x68d56cad, 0xb2c6f3eb), TOBN(0x3b512e73, 0xf376356c),
++     TOBN(0xe43b0e1f, 0xfce10408), TOBN(0x89ddc003, 0x5a5e257d),
++     TOBN(0xb0ae0d12, 0x0362e5b3), TOBN(0x07f983c7, 0xb0519161),
++     TOBN(0xc2e94d15, 0x5d5231e7), TOBN(0xcff22aed, 0x0b4f9513),
++     TOBN(0xb02588dd, 0x6ad0b0b5), TOBN(0xb967d1ac, 0x11d0dcd5),
++     TOBN(0x8dac6bc6, 0xcf777b6c), TOBN(0x0062bdbd, 0x4c6d1959),
++     TOBN(0x53da71b5, 0x0ef5cc85), TOBN(0x07012c7d, 0x4006f14f),
++     TOBN(0x4617f962, 0xac47800d), TOBN(0x53365f2b, 0xc102ed75),
++     TOBN(0xb422efcb, 0x4ab8c9d3), TOBN(0x195cb26b, 0x34af31c9),
++     TOBN(0x3a926e29, 0x05f2c4ce), TOBN(0xbd2bdecb, 0x9856966c),
++     TOBN(0x5d16ab3a, 0x85527015), TOBN(0x9f81609e, 0x4486c231),
++     TOBN(0xd8b96b2c, 0xda350002), TOBN(0xbd054690, 0xfa1b7d36),
++     TOBN(0xdc90ebf5, 0xe71d79bc), TOBN(0xf241b6f9, 0x08964e4e),
++     TOBN(0x7c838643, 0x2fe3cd4c), TOBN(0xe0f33acb, 0xb4bc633c),
++     TOBN(0xb4a9ecec, 0x3d139f1f), TOBN(0x05ce69cd, 0xdc4a1f49),
++     TOBN(0xa19d1b16, 0xf5f98aaf), TOBN(0x45bb71d6, 0x6f23e0ef),
++     TOBN(0x33789fcd, 0x46cdfdd3), TOBN(0x9b8e2978, 0xcee040ca),
++     TOBN(0x9c69b246, 0xae0a6828), TOBN(0xba533d24, 0x7078d5aa),
++     TOBN(0x7a2e42c0, 0x7bb4fbdb), TOBN(0xcfb4879a, 0x7035385c),
++     TOBN(0x8c3dd30b, 0x3281705b), TOBN(0x7e361c6c, 0x404fe081),
++     TOBN(0x7b21649c, 0x3f604edf), TOBN(0x5dbf6a3f, 0xe52ffe47),
++     TOBN(0xc41b7c23, 0x4b54d9bf), TOBN(0x1374e681, 0x3511c3d9),
++     TOBN(0x1863bf16, 0xc1b2b758), TOBN(0x90e78507, 0x1e9e6a96),
++     TOBN(0xab4bf98d, 0x5d86f174), TOBN(0xd74e0bd3, 0x85e96fe4),
++     TOBN(0x8afde39f, 0xcac5d344), TOBN(0x90946dbc, 0xbd91b847),
++     TOBN(0xf5b42358, 0xfe1a838c), TOBN(0x05aae6c5, 0x620ac9d8),
++     TOBN(0x8e193bd8, 0xa1ce5a0b), TOBN(0x8f710571, 0x4dabfd72),
++     TOBN(0x8d8fdd48, 0x182caaac), TOBN(0x8c4aeefa, 0x040745cf),
++     TOBN(0x73c6c30a, 0xf3b93e6d), TOBN(0x991241f3, 0x16f42011),
++     TOBN(0xa0158eea, 0xe457a477), TOBN(0xd19857db, 0xee6ddc05),
++     TOBN(0xb3265224, 0x18c41671), TOBN(0x3ffdfc7e, 0x3c2c0d58),
++     TOBN(0x3a3a5254, 0x26ee7cda), TOBN(0x341b0869, 0xdf02c3a8),
++     TOBN(0xa023bf42, 0x723bbfc8), TOBN(0x3d15002a, 0x14452691),}
++    ,
++    {TOBN(0x5ef7324c, 0x85edfa30), TOBN(0x25976554, 0x87d4f3da),
++     TOBN(0x352f5bc0, 0xdcb50c86), TOBN(0x8f6927b0, 0x4832a96c),
++     TOBN(0xd08ee1ba, 0x55f2f94c), TOBN(0x6a996f99, 0x344b45fa),
++     TOBN(0xe133cb8d, 0xa8aa455d), TOBN(0x5d0721ec, 0x758dc1f7),
++     TOBN(0x6ba7a920, 0x79e5fb67), TOBN(0xe1331feb, 0x70aa725e),
++     TOBN(0x5080ccf5, 0x7df5d837), TOBN(0xe4cae01d, 0x7ff72e21),
++     TOBN(0xd9243ee6, 0x0412a77d), TOBN(0x06ff7cac, 0xdf449025),
++     TOBN(0xbe75f7cd, 0x23ef5a31), TOBN(0xbc957822, 0x0ddef7a8),
++     TOBN(0x8cf7230c, 0xb0ce1c55), TOBN(0x5b534d05, 0x0bbfb607),
++     TOBN(0xee1ef113, 0x0e16363b), TOBN(0x27e0aa7a, 0xb4999e82),
++     TOBN(0xce1dac2d, 0x79362c41), TOBN(0x67920c90, 0x91bb6cb0),
++     TOBN(0x1e648d63, 0x2223df24), TOBN(0x0f7d9eef, 0xe32e8f28),
++     TOBN(0x6943f39a, 0xfa833834), TOBN(0x22951722, 0xa6328562),
++     TOBN(0x81d63dd5, 0x4170fc10), TOBN(0x9f5fa58f, 0xaecc2e6d),
++     TOBN(0xb66c8725, 0xe77d9a3b), TOBN(0x11235cea, 0x6384ebe0),
++     TOBN(0x06a8c118, 0x5845e24a), TOBN(0x0137b286, 0xebd093b1),
++     TOBN(0xc589e1ce, 0x44ace150), TOBN(0xe0f8d3d9, 0x4381e97c),
++     TOBN(0x59e99b11, 0x62c5a4b8), TOBN(0x90d262f7, 0xfd0ec9f9),
++     TOBN(0xfbc854c9, 0x283e13c9), TOBN(0x2d04fde7, 0xaedc7085),
++     TOBN(0x057d7765, 0x47dcbecb), TOBN(0x8dbdf591, 0x9a76fa5f),
++     TOBN(0xd0150695, 0x0de1e578), TOBN(0x2e1463e7, 0xe9f72bc6),
++     TOBN(0xffa68441, 0x1b39eca5), TOBN(0x673c8530, 0x7c037f2f),
++     TOBN(0xd0d6a600, 0x747f91da), TOBN(0xb08d43e1, 0xc9cb78e9),
++     TOBN(0x0fc0c644, 0x27b5cef5), TOBN(0x5c1d160a, 0xa60a2fd6),
++     TOBN(0xf98cae53, 0x28c8e13b), TOBN(0x375f10c4, 0xb2eddcd1),
++     TOBN(0xd4eb8b7f, 0x5cce06ad), TOBN(0xb4669f45, 0x80a2e1ef),
++     TOBN(0xd593f9d0, 0x5bbd8699), TOBN(0x5528a4c9, 0xe7976d13),
++     TOBN(0x3923e095, 0x1c7e28d3), TOBN(0xb9293790, 0x3f6bb577),
++     TOBN(0xdb567d6a, 0xc42bd6d2), TOBN(0x6df86468, 0xbb1f96ae),
++     TOBN(0x0efe5b1a, 0x4843b28e), TOBN(0x961bbb05, 0x6379b240),
++     TOBN(0xb6caf5f0, 0x70a6a26b), TOBN(0x70686c0d, 0x328e6e39),
++     TOBN(0x80da06cf, 0x895fc8d3), TOBN(0x804d8810, 0xb363fdc9),
++     TOBN(0xbe22877b, 0x207f1670), TOBN(0x9b0dd188, 0x4e615291),
++     TOBN(0x625ae8dc, 0x97a3c2bf), TOBN(0x08584ef7, 0x439b86e8),
++     TOBN(0xde7190a5, 0xdcd898ff), TOBN(0x26286c40, 0x2058ee3d),
++     TOBN(0x3db0b217, 0x5f87b1c1), TOBN(0xcc334771, 0x102a6db5),
++     TOBN(0xd99de954, 0x2f770fb1), TOBN(0x97c1c620, 0x4cd7535e),
++     TOBN(0xd3b6c448, 0x3f09cefc), TOBN(0xd725af15, 0x5a63b4f8),
++     TOBN(0x0c95d24f, 0xc01e20ec), TOBN(0xdfd37494, 0x9ae7121f),
++     TOBN(0x7d6ddb72, 0xec77b7ec), TOBN(0xfe079d3b, 0x0353a4ae),
++     TOBN(0x3066e70a, 0x2e6ac8d2), TOBN(0x9c6b5a43, 0x106e5c05),
++     TOBN(0x52d3c6f5, 0xede59b8c), TOBN(0x30d6a5c3, 0xfccec9ae),
++     TOBN(0xedec7c22, 0x4fc0a9ef), TOBN(0x190ff083, 0x95c16ced),
++     TOBN(0xbe12ec8f, 0x94de0fde), TOBN(0x0d131ab8, 0x852d3433),
++     TOBN(0x42ace07e, 0x85701291), TOBN(0x94793ed9, 0x194061a8),
++     TOBN(0x30e83ed6, 0xd7f4a485), TOBN(0x9eec7269, 0xf9eeff4d),
++     TOBN(0x90acba59, 0x0c9d8005), TOBN(0x5feca458, 0x1e79b9d1),
++     TOBN(0x8fbe5427, 0x1d506a1e), TOBN(0xa32b2c8e, 0x2439cfa7),
++     TOBN(0x1671c173, 0x73dd0b4e), TOBN(0x37a28214, 0x44a054c6),
++     TOBN(0x81760a1b, 0x4e8b53f1), TOBN(0xa6c04224, 0xf9f93b9e),
++     TOBN(0x18784b34, 0xcf671e3c), TOBN(0x81bbecd2, 0xcda9b994),
++     TOBN(0x38831979, 0xb2ab3848), TOBN(0xef54feb7, 0xf2e03c2d),
++     TOBN(0xcf197ca7, 0xfb8088fa), TOBN(0x01427247, 0x4ddc96c5),
++     TOBN(0xa2d2550a, 0x30777176), TOBN(0x53469898, 0x4d0cf71d),
++     TOBN(0x6ce937b8, 0x3a2aaac6), TOBN(0xe9f91dc3, 0x5af38d9b),
++     TOBN(0x2598ad83, 0xc8bf2899), TOBN(0x8e706ac9, 0xb5536c16),
++     TOBN(0x40dc7495, 0xf688dc98), TOBN(0x26490cd7, 0x124c4afc),
++     TOBN(0xe651ec84, 0x1f18775c), TOBN(0x393ea6c3, 0xb4fdaf4a),
++     TOBN(0x1e1f3343, 0x7f338e0d), TOBN(0x39fb832b, 0x6053e7b5),
++     TOBN(0x46e702da, 0x619e14d5), TOBN(0x859cacd1, 0xcdeef6e0),
++     TOBN(0x63b99ce7, 0x4462007d), TOBN(0xb8ab48a5, 0x4cb5f5b7),
++     TOBN(0x9ec673d2, 0xf55edde7), TOBN(0xd1567f74, 0x8cfaefda),
++     TOBN(0x46381b6b, 0x0887bcec), TOBN(0x694497ce, 0xe178f3c2),
++     TOBN(0x5e6525e3, 0x1e6266cb), TOBN(0x5931de26, 0x697d6413),
++     TOBN(0x87f8df7c, 0x0e58d493), TOBN(0xb1ae5ed0, 0x58b73f12),
++     TOBN(0xc368f784, 0xdea0c34d), TOBN(0x9bd0a120, 0x859a91a0),
++     TOBN(0xb00d88b7, 0xcc863c68), TOBN(0x3a1cc11e, 0x3d1f4d65),
++     TOBN(0xea38e0e7, 0x0aa85593), TOBN(0x37f13e98, 0x7dc4aee8),
++     TOBN(0x10d38667, 0xbc947bad), TOBN(0x738e07ce, 0x2a36ee2e),
++     TOBN(0xc93470cd, 0xc577fcac), TOBN(0xdee1b616, 0x2782470d),
++     TOBN(0x36a25e67, 0x2e793d12), TOBN(0xd6aa6cae, 0xe0f186da),
++     TOBN(0x474d0fd9, 0x80e07af7), TOBN(0xf7cdc47d, 0xba8a5cd4),
++     TOBN(0x28af6d9d, 0xab15247f), TOBN(0x7c789c10, 0x493a537f),
++     TOBN(0x7ac9b110, 0x23a334e7), TOBN(0x0236ac09, 0x12c9c277),
++     TOBN(0xa7e5bd25, 0x1d7a5144), TOBN(0x098b9c2a, 0xf13ec4ec),
++     TOBN(0x3639daca, 0xd3f0abca), TOBN(0x642da81a, 0xa23960f9),
++     TOBN(0x7d2e5c05, 0x4f7269b1), TOBN(0xfcf30777, 0xe287c385),
++     TOBN(0x10edc84f, 0xf2a46f21), TOBN(0x35441757, 0x4f43fa36),
++     TOBN(0xf1327899, 0xfd703431), TOBN(0xa438d7a6, 0x16dd587a),
++     TOBN(0x65c34c57, 0xe9c8352d), TOBN(0xa728edab, 0x5cc5a24e),
++     TOBN(0xaed78abc, 0x42531689), TOBN(0x0a51a0e8, 0x010963ef),
++     TOBN(0x5776fa0a, 0xd717d9b3), TOBN(0xf356c239, 0x7dd3428b),
++     TOBN(0x29903fff, 0x8d3a3dac), TOBN(0x409597fa, 0x3d94491f),
++     TOBN(0x4cd7a5ff, 0xbf4a56a4), TOBN(0xe5096474, 0x8adab462),
++     TOBN(0xa97b5126, 0x5c3427b0), TOBN(0x6401405c, 0xd282c9bd),
++     TOBN(0x3629f8d7, 0x222c5c45), TOBN(0xb1c02c16, 0xe8d50aed),
++     TOBN(0xbea2ed75, 0xd9635bc9), TOBN(0x226790c7, 0x6e24552f),
++     TOBN(0x3c33f2a3, 0x65f1d066), TOBN(0x2a43463e, 0x6dfccc2e),
++     TOBN(0x8cc3453a, 0xdb483761), TOBN(0xe7cc6085, 0x65d5672b),
++     TOBN(0x277ed6cb, 0xde3efc87), TOBN(0x19f2f368, 0x69234eaf),
++     TOBN(0x9aaf4317, 0x5c0b800b), TOBN(0x1f1e7c89, 0x8b6da6e2),
++     TOBN(0x6cfb4715, 0xb94ec75e), TOBN(0xd590dd5f, 0x453118c2),
++     TOBN(0x14e49da1, 0x1f17a34c), TOBN(0x5420ab39, 0x235a1456),
++     TOBN(0xb7637241, 0x2f50363b), TOBN(0x7b15d623, 0xc3fabb6e),
++     TOBN(0xa0ef40b1, 0xe274e49c), TOBN(0x5cf50744, 0x96b1860a),
++     TOBN(0xd6583fbf, 0x66afe5a4), TOBN(0x44240510, 0xf47e3e9a),
++     TOBN(0x99254343, 0x11b2d595), TOBN(0xf1367499, 0xeec8df57),
++     TOBN(0x3cb12c61, 0x3e73dd05), TOBN(0xd248c033, 0x7dac102a),
++     TOBN(0xcf154f13, 0xa77739f5), TOBN(0xbf4288cb, 0x23d2af42),
++     TOBN(0xaa64c9b6, 0x32e4a1cf), TOBN(0xee8c07a8, 0xc8a208f3),
++     TOBN(0xe10d4999, 0x6fe8393f), TOBN(0x0f809a3f, 0xe91f3a32),
++     TOBN(0x61096d1c, 0x802f63c8), TOBN(0x289e1462, 0x57750d3d),
++     TOBN(0xed06167e, 0x9889feea), TOBN(0xd5c9c0e2, 0xe0993909),
++     TOBN(0x46fca0d8, 0x56508ac6), TOBN(0x91826047, 0x4f1b8e83),
++     TOBN(0x4f2c877a, 0x9a4a2751), TOBN(0x71bd0072, 0xcae6fead),
++     TOBN(0x38df8dcc, 0x06aa1941), TOBN(0x5a074b4c, 0x63beeaa8),
++     TOBN(0xd6d65934, 0xc1cec8ed), TOBN(0xa6ecb49e, 0xaabc03bd),
++     TOBN(0xaade91c2, 0xde8a8415), TOBN(0xcfb0efdf, 0x691136e0),
++     TOBN(0x11af45ee, 0x23ab3495), TOBN(0xa132df88, 0x0b77463d),
++     TOBN(0x8923c15c, 0x815d06f4), TOBN(0xc3ceb3f5, 0x0d61a436),
++     TOBN(0xaf52291d, 0xe88fb1da), TOBN(0xea057974, 0x1da12179),
++     TOBN(0xb0d7218c, 0xd2fef720), TOBN(0x6c0899c9, 0x8e1d8845),
++     TOBN(0x98157504, 0x752ddad7), TOBN(0xd60bd74f, 0xa1a68a97),
++     TOBN(0x7047a3a9, 0xf658fb99), TOBN(0x1f5d86d6, 0x5f8511e4),
++     TOBN(0xb8a4bc42, 0x4b5a6d88), TOBN(0x69eb2c33, 0x1abefa7d),
++     TOBN(0x95bf39e8, 0x13c9c510), TOBN(0xf571960a, 0xd48aab43),
++     TOBN(0x7e8cfbcf, 0x704e23c6), TOBN(0xc71b7d22, 0x28aaa65b),
++     TOBN(0xa041b2bd, 0x245e3c83), TOBN(0x69b98834, 0xd21854ff),
++     TOBN(0x89d227a3, 0x963bfeec), TOBN(0x99947aaa, 0xde7da7cb),
++     TOBN(0x1d9ee9db, 0xee68a9b1), TOBN(0x0a08f003, 0x698ec368),
++     TOBN(0xe9ea4094, 0x78ef2487), TOBN(0xc8d2d415, 0x02cfec26),
++     TOBN(0xc52f9a6e, 0xb7dcf328), TOBN(0x0ed489e3, 0x85b6a937),
++     TOBN(0x9b94986b, 0xbef3366e), TOBN(0x0de59c70, 0xedddddb8),
++     TOBN(0xffdb748c, 0xeadddbe2), TOBN(0x9b9784bb, 0x8266ea40),
++     TOBN(0x142b5502, 0x1a93507a), TOBN(0xb4cd1187, 0x8d3c06cf),
++     TOBN(0xdf70e76a, 0x91ec3f40), TOBN(0x484e81ad, 0x4e7553c2),
++     TOBN(0x830f87b5, 0x272e9d6e), TOBN(0xea1c93e5, 0xc6ff514a),
++     TOBN(0x67cc2adc, 0xc4192a8e), TOBN(0xc77e27e2, 0x42f4535a),
++     TOBN(0x9cdbab36, 0xd2b713c5), TOBN(0x86274ea0, 0xcf7b0cd3),
++     TOBN(0x784680f3, 0x09af826b), TOBN(0xbfcc837a, 0x0c72dea3),
++     TOBN(0xa8bdfe9d, 0xd6529b73), TOBN(0x708aa228, 0x63a88002),
++     TOBN(0x6c7a9a54, 0xc91d45b9), TOBN(0xdf1a38bb, 0xfd004f56),
++     TOBN(0x2e8c9a26, 0xb8bad853), TOBN(0x2d52cea3, 0x3723eae7),
++     TOBN(0x054d6d81, 0x56ca2830), TOBN(0xa3317d14, 0x9a8dc411),
++     TOBN(0xa08662fe, 0xfd4ddeda), TOBN(0xed2a153a, 0xb55d792b),
++     TOBN(0x7035c16a, 0xbfc6e944), TOBN(0xb6bc5834, 0x00171cf3),
++     TOBN(0xe27152b3, 0x83d102b6), TOBN(0xfe695a47, 0x0646b848),
++     TOBN(0xa5bb09d8, 0x916e6d37), TOBN(0xb4269d64, 0x0d17015e),
++     TOBN(0x8d8156a1, 0x0a1d2285), TOBN(0xfeef6c51, 0x46d26d72),
++     TOBN(0x9dac57c8, 0x4c5434a7), TOBN(0x0282e5be, 0x59d39e31),
++     TOBN(0xedfff181, 0x721c486d), TOBN(0x301baf10, 0xbc58824e),
++     TOBN(0x8136a6aa, 0x00570031), TOBN(0x55aaf78c, 0x1cddde68),
++     TOBN(0x26829371, 0x59c63952), TOBN(0x3a3bd274, 0x8bc25baf),
++     TOBN(0xecdf8657, 0xb7e52dc3), TOBN(0x2dd8c087, 0xfd78e6c8),
++     TOBN(0x20553274, 0xf5531461), TOBN(0x8b4a1281, 0x5d95499b),
++     TOBN(0xe2c8763a, 0x1a80f9d2), TOBN(0xd1dbe32b, 0x4ddec758),
++     TOBN(0xaf12210d, 0x30c34169), TOBN(0xba74a953, 0x78baa533),
++     TOBN(0x3d133c6e, 0xa438f254), TOBN(0xa431531a, 0x201bef5b),
++     TOBN(0x15295e22, 0xf669d7ec), TOBN(0xca374f64, 0x357fb515),
++     TOBN(0x8a8406ff, 0xeaa3fdb3), TOBN(0x106ae448, 0xdf3f2da8),
++     TOBN(0x8f9b0a90, 0x33c8e9a1), TOBN(0x234645e2, 0x71ad5885),
++     TOBN(0x3d083224, 0x1c0aed14), TOBN(0xf10a7d3e, 0x7a942d46),
++     TOBN(0x7c11deee, 0x40d5c9be), TOBN(0xb2bae7ff, 0xba84ed98),
++     TOBN(0x93e97139, 0xaad58ddd), TOBN(0x3d872796, 0x3f6d1fa3),
++     TOBN(0x483aca81, 0x8569ff13), TOBN(0x8b89a5fb, 0x9a600f72),
++     TOBN(0x4cbc27c3, 0xc06f2b86), TOBN(0x22130713, 0x63ad9c0b),
++     TOBN(0xb5358b1e, 0x48ac2840), TOBN(0x18311294, 0xecba9477),
++     TOBN(0xda58f990, 0xa6946b43), TOBN(0x3098baf9, 0x9ab41819),
++     TOBN(0x66c4c158, 0x4198da52), TOBN(0xab4fc17c, 0x146bfd1b),
++     TOBN(0x2f0a4c3c, 0xbf36a908), TOBN(0x2ae9e34b, 0x58cf7838),
++     TOBN(0xf411529e, 0x3fa11b1f), TOBN(0x21e43677, 0x974af2b4),
++     TOBN(0x7c20958e, 0xc230793b), TOBN(0x710ea885, 0x16e840f3),
++     TOBN(0xfc0b21fc, 0xc5dc67cf), TOBN(0x08d51647, 0x88405718),
++     TOBN(0xd955c21f, 0xcfe49eb7), TOBN(0x9722a5d5, 0x56dd4a1f),
++     TOBN(0xc9ef50e2, 0xc861baa5), TOBN(0xc0c21a5d, 0x9505ac3e),
++     TOBN(0xaf6b9a33, 0x8b7c063f), TOBN(0xc6370339, 0x2f4779c1),
++     TOBN(0x22df99c7, 0x638167c3), TOBN(0xfe6ffe76, 0x795db30c),
++     TOBN(0x2b822d33, 0xa4854989), TOBN(0xfef031dd, 0x30563aa5),
++     TOBN(0x16b09f82, 0xd57c667f), TOBN(0xc70312ce, 0xcc0b76f1),
++     TOBN(0xbf04a9e6, 0xc9118aec), TOBN(0x82fcb419, 0x3409d133),
++     TOBN(0x1a8ab385, 0xab45d44d), TOBN(0xfba07222, 0x617b83a3),
++     TOBN(0xb05f50dd, 0x58e81b52), TOBN(0x1d8db553, 0x21ce5aff),
++     TOBN(0x3097b8d4, 0xe344a873), TOBN(0x7d8d116d, 0xfe36d53e),
++     TOBN(0x6db22f58, 0x7875e750), TOBN(0x2dc5e373, 0x43e144ea),
++     TOBN(0xc05f32e6, 0xe799eb95), TOBN(0xe9e5f4df, 0x6899e6ec),
++     TOBN(0xbdc3bd68, 0x1fab23d5), TOBN(0xb72b8ab7, 0x73af60e6),
++     TOBN(0x8db27ae0, 0x2cecc84a), TOBN(0x600016d8, 0x7bdb871c),
++     TOBN(0x42a44b13, 0xd7c46f58), TOBN(0xb8919727, 0xc3a77d39),
++     TOBN(0xcfc6bbbd, 0xdafd6088), TOBN(0x1a740146, 0x6bd20d39),
++     TOBN(0x8c747abd, 0x98c41072), TOBN(0x4c91e765, 0xbdf68ea1),
++     TOBN(0x7c95e5ca, 0x08819a78), TOBN(0xcf48b729, 0xc9587921),
++     TOBN(0x091c7c5f, 0xdebbcc7d), TOBN(0x6f287404, 0xf0e05149),
++     TOBN(0xf83b5ac2, 0x26cd44ec), TOBN(0x88ae32a6, 0xcfea250e),
++     TOBN(0x6ac5047a, 0x1d06ebc5), TOBN(0xc7e550b4, 0xd434f781),
++     TOBN(0x61ab1cf2, 0x5c727bd2), TOBN(0x2e4badb1, 0x1cf915b0),
++     TOBN(0x1b4dadec, 0xf69d3920), TOBN(0xe61b1ca6, 0xf14c1dfe),
++     TOBN(0x90b479cc, 0xbd6bd51f), TOBN(0x8024e401, 0x8045ec30),
++     TOBN(0xcab29ca3, 0x25ef0e62), TOBN(0x4f2e9416, 0x49e4ebc0),
++     TOBN(0x45eb40ec, 0x0ccced58), TOBN(0x25cd4b9c, 0x0da44f98),
++     TOBN(0x43e06458, 0x871812c6), TOBN(0x99f80d55, 0x16cef651),
++     TOBN(0x571340c9, 0xce6dc153), TOBN(0x138d5117, 0xd8665521),
++     TOBN(0xacdb45bc, 0x4e07014d), TOBN(0x2f34bb38, 0x84b60b91),
++     TOBN(0xf44a4fd2, 0x2ae8921e), TOBN(0xb039288e, 0x892ba1e2),
++     TOBN(0x9da50174, 0xb1c180b2), TOBN(0x6b70ab66, 0x1693dc87),
++     TOBN(0x7e9babc9, 0xe7057481), TOBN(0x4581ddef, 0x9c80dc41),
++     TOBN(0x0c890da9, 0x51294682), TOBN(0x0b5629d3, 0x3f4736e5),
++     TOBN(0x2340c79e, 0xb06f5b41), TOBN(0xa42e84ce, 0x4e243469),
++     TOBN(0xf9a20135, 0x045a71a9), TOBN(0xefbfb415, 0xd27b6fb6),
++     TOBN(0x25ebea23, 0x9d33cd6f), TOBN(0x9caedb88, 0xaa6c0af8),
++     TOBN(0x53dc7e9a, 0xd9ce6f96), TOBN(0x3897f9fd, 0x51e0b15a),
++     TOBN(0xf51cb1f8, 0x8e5d788e), TOBN(0x1aec7ba8, 0xe1d490ee),
++     TOBN(0x265991e0, 0xcc58cb3c), TOBN(0x9f306e8c, 0x9fc3ad31),
++     TOBN(0x5fed006e, 0x5040a0ac), TOBN(0xca9d5043, 0xfb476f2e),
++     TOBN(0xa19c06e8, 0xbeea7a23), TOBN(0xd2865801, 0x0edabb63),
++     TOBN(0xdb92293f, 0x6967469a), TOBN(0x2894d839, 0x8d8a8ed8),
++     TOBN(0x87c9e406, 0xbbc77122), TOBN(0x8671c6f1, 0x2ea3a26a),
++     TOBN(0xe42df8d6, 0xd7de9853), TOBN(0x2e3ce346, 0xb1f2bcc7),
++     TOBN(0xda601dfc, 0x899d50cf), TOBN(0xbfc913de, 0xfb1b598f),
++     TOBN(0x81c4909f, 0xe61f7908), TOBN(0x192e304f, 0x9bbc7b29),
++     TOBN(0xc3ed8738, 0xc104b338), TOBN(0xedbe9e47, 0x783f5d61),
++     TOBN(0x0c06e9be, 0x2db30660), TOBN(0xda3e613f, 0xc0eb7d8e),
++     TOBN(0xd8fa3e97, 0x322e096e), TOBN(0xfebd91e8, 0xd336e247),
++     TOBN(0x8f13ccc4, 0xdf655a49), TOBN(0xa9e00dfc, 0x5eb20210),
++     TOBN(0x84631d0f, 0xc656b6ea), TOBN(0x93a058cd, 0xd8c0d947),
++     TOBN(0x6846904a, 0x67bd3448), TOBN(0x4a3d4e1a, 0xf394fd5c),
++     TOBN(0xc102c1a5, 0xdb225f52), TOBN(0xe3455bba, 0xfc4f5e9a),
++     TOBN(0x6b36985b, 0x4b9ad1ce), TOBN(0xa9818536, 0x5bb7f793),
++     TOBN(0x6c25e1d0, 0x48b1a416), TOBN(0x1381dd53, 0x3c81bee7),
++     TOBN(0xd2a30d61, 0x7a4a7620), TOBN(0xc8412926, 0x39b8944c),
++     TOBN(0x3c1c6fbe, 0x7a97c33a), TOBN(0x941e541d, 0x938664e7),
++     TOBN(0x417499e8, 0x4a34f239), TOBN(0x15fdb83c, 0xb90402d5),
++     TOBN(0xb75f46bf, 0x433aa832), TOBN(0xb61e15af, 0x63215db1),
++     TOBN(0xaabe59d4, 0xa127f89a), TOBN(0x5d541e0c, 0x07e816da),
++     TOBN(0xaaba0659, 0xa618b692), TOBN(0x55327733, 0x17266026),
++     TOBN(0xaf53a0fc, 0x95f57552), TOBN(0x32947650, 0x6cacb0c9),
++     TOBN(0x253ff58d, 0xc821be01), TOBN(0xb0309531, 0xa06f1146),
++     TOBN(0x59bbbdf5, 0x05c2e54d), TOBN(0x158f27ad, 0x26e8dd22),
++     TOBN(0xcc5b7ffb, 0x397e1e53), TOBN(0xae03f65b, 0x7fc1e50d),
++     TOBN(0xa9784ebd, 0x9c95f0f9), TOBN(0x5ed9deb2, 0x24640771),
++     TOBN(0x31244af7, 0x035561c4), TOBN(0x87332f3a, 0x7ee857de),
++     TOBN(0x09e16e9e, 0x2b9e0d88), TOBN(0x52d910f4, 0x56a06049),
++     TOBN(0x507ed477, 0xa9592f48), TOBN(0x85cb917b, 0x2365d678),
++     TOBN(0xf8511c93, 0x4c8998d1), TOBN(0x2186a3f1, 0x730ea58f),
++     TOBN(0x50189626, 0xb2029db0), TOBN(0x9137a6d9, 0x02ceb75a),
++     TOBN(0x2fe17f37, 0x748bc82c), TOBN(0x87c2e931, 0x80469f8c),
++     TOBN(0x850f71cd, 0xbf891aa2), TOBN(0x0ca1b89b, 0x75ec3d8d),
++     TOBN(0x516c43aa, 0x5e1cd3cd), TOBN(0x89397808, 0x9a887c28),
++     TOBN(0x0059c699, 0xddea1f9f), TOBN(0x7737d6fa, 0x8e6868f7),
++     TOBN(0x6d93746a, 0x60f1524b), TOBN(0x36985e55, 0xba052aa7),
++     TOBN(0x41b1d322, 0xed923ea5), TOBN(0x3429759f, 0x25852a11),
++     TOBN(0xbeca6ec3, 0x092e9f41), TOBN(0x3a238c66, 0x62256bbd),
++     TOBN(0xd82958ea, 0x70ad487d), TOBN(0x4ac8aaf9, 0x65610d93),
++     TOBN(0x3fa101b1, 0x5e4ccab0), TOBN(0x9bf430f2, 0x9de14bfb),
++     TOBN(0xa10f5cc6, 0x6531899d), TOBN(0x590005fb, 0xea8ce17d),
++     TOBN(0xc437912f, 0x24544cb6), TOBN(0x9987b71a, 0xd79ac2e3),
++     TOBN(0x13e3d9dd, 0xc058a212), TOBN(0x00075aac, 0xd2de9606),
++     TOBN(0x80ab508b, 0x6cac8369), TOBN(0x87842be7, 0xf54f6c89),
++     TOBN(0xa7ad663d, 0x6bc532a4), TOBN(0x67813de7, 0x78a91bc8),
++     TOBN(0x5dcb61ce, 0xc3427239), TOBN(0x5f3c7cf0, 0xc56934d9),
++     TOBN(0xc079e0fb, 0xe3191591), TOBN(0xe40896bd, 0xb01aada7),
++     TOBN(0x8d466791, 0x0492d25f), TOBN(0x8aeb30c9, 0xe7408276),
++     TOBN(0xe9437495, 0x9287aacc), TOBN(0x23d4708d, 0x79fe03d4),
++     TOBN(0x8cda9cf2, 0xd0c05199), TOBN(0x502fbc22, 0xfae78454),
++     TOBN(0xc0bda9df, 0xf572a182), TOBN(0x5f9b71b8, 0x6158b372),
++     TOBN(0xe0f33a59, 0x2b82dd07), TOBN(0x76302735, 0x9523032e),
++     TOBN(0x7fe1a721, 0xc4505a32), TOBN(0x7b6e3e82, 0xf796409f),}
++    ,
++    {TOBN(0xe3417bc0, 0x35d0b34a), TOBN(0x440b386b, 0x8327c0a7),
++     TOBN(0x8fb7262d, 0xac0362d1), TOBN(0x2c41114c, 0xe0cdf943),
++     TOBN(0x2ba5cef1, 0xad95a0b1), TOBN(0xc09b37a8, 0x67d54362),
++     TOBN(0x26d6cdd2, 0x01e486c9), TOBN(0x20477abf, 0x42ff9297),
++     TOBN(0xa004dcb3, 0x292a9287), TOBN(0xddc15cf6, 0x77b092c7),
++     TOBN(0x083a8464, 0x806c0605), TOBN(0x4a68df70, 0x3db997b0),
++     TOBN(0x9c134e45, 0x05bf7dd0), TOBN(0xa4e63d39, 0x8ccf7f8c),
++     TOBN(0xa6e6517f, 0x41b5f8af), TOBN(0xaa8b9342, 0xad7bc1cc),
++     TOBN(0x126f35b5, 0x1e706ad9), TOBN(0xb99cebb4, 0xc3a9ebdf),
++     TOBN(0xa75389af, 0xbf608d90), TOBN(0x76113c4f, 0xc6c89858),
++     TOBN(0x80de8eb0, 0x97e2b5aa), TOBN(0x7e1022cc, 0x63b91304),
++     TOBN(0x3bdab605, 0x6ccc066c), TOBN(0x33cbb144, 0xb2edf900),
++     TOBN(0xc4176471, 0x7af715d2), TOBN(0xe2f7f594, 0xd0134a96),
++     TOBN(0x2c1873ef, 0xa41ec956), TOBN(0xe4e7b4f6, 0x77821304),
++     TOBN(0xe5c8ff97, 0x88d5374a), TOBN(0x2b915e63, 0x80823d5b),
++     TOBN(0xea6bc755, 0xb2ee8fe2), TOBN(0x6657624c, 0xe7112651),
++     TOBN(0x157af101, 0xdace5aca), TOBN(0xc4fdbcf2, 0x11a6a267),
++     TOBN(0xdaddf340, 0xc49c8609), TOBN(0x97e49f52, 0xe9604a65),
++     TOBN(0x9be8e790, 0x937e2ad5), TOBN(0x846e2508, 0x326e17f1),
++     TOBN(0x3f38007a, 0x0bbbc0dc), TOBN(0xcf03603f, 0xb11e16d6),
++     TOBN(0xd6f800e0, 0x7442f1d5), TOBN(0x475607d1, 0x66e0e3ab),
++     TOBN(0x82807f16, 0xb7c64047), TOBN(0x8858e1e3, 0xa749883d),
++     TOBN(0x5859120b, 0x8231ee10), TOBN(0x1b80e7eb, 0x638a1ece),
++     TOBN(0xcb72525a, 0xc6aa73a4), TOBN(0xa7cdea3d, 0x844423ac),
++     TOBN(0x5ed0c007, 0xf8ae7c38), TOBN(0x6db07a5c, 0x3d740192),
++     TOBN(0xbe5e9c2a, 0x5fe36db3), TOBN(0xd5b9d57a, 0x76e95046),
++     TOBN(0x54ac32e7, 0x8eba20f2), TOBN(0xef11ca8f, 0x71b9a352),
++     TOBN(0x305e373e, 0xff98a658), TOBN(0xffe5a100, 0x823eb667),
++     TOBN(0x57477b11, 0xe51732d2), TOBN(0xdfd6eb28, 0x2538fc0e),
++     TOBN(0x5c43b0cc, 0x3b39eec5), TOBN(0x6af12778, 0xcb36cc57),
++     TOBN(0x70b0852d, 0x06c425ae), TOBN(0x6df92f8c, 0x5c221b9b),
++     TOBN(0x6c8d4f9e, 0xce826d9c), TOBN(0xf59aba7b, 0xb49359c3),
++     TOBN(0x5c8ed8d5, 0xda64309d), TOBN(0x61a6de56, 0x91b30704),
++     TOBN(0xd6b52f6a, 0x2f9b5808), TOBN(0x0eee4194, 0x98c958a7),
++     TOBN(0xcddd9aab, 0x771e4caa), TOBN(0x83965dfd, 0x78bc21be),
++     TOBN(0x02affce3, 0xb3b504f5), TOBN(0x30847a21, 0x561c8291),
++     TOBN(0xd2eb2cf1, 0x52bfda05), TOBN(0xe0e4c4e9, 0x6197b98c),
++     TOBN(0x1d35076c, 0xf8a1726f), TOBN(0x6c06085b, 0x2db11e3d),
++     TOBN(0x15c0c4d7, 0x4463ba14), TOBN(0x9d292f83, 0x0030238c),
++     TOBN(0x1311ee8b, 0x3727536d), TOBN(0xfeea86ef, 0xbeaedc1e),
++     TOBN(0xb9d18cd3, 0x66131e2e), TOBN(0xf31d974f, 0x80fe2682),
++     TOBN(0xb6e49e0f, 0xe4160289), TOBN(0x7c48ec0b, 0x08e92799),
++     TOBN(0x818111d8, 0xd1989aa7), TOBN(0xb34fa0aa, 0xebf926f9),
++     TOBN(0xdb5fe2f5, 0xa245474a), TOBN(0xf80a6ebb, 0x3c7ca756),
++     TOBN(0xa7f96054, 0xafa05dd8), TOBN(0x26dfcf21, 0xfcaf119e),
++     TOBN(0xe20ef2e3, 0x0564bb59), TOBN(0xef4dca50, 0x61cb02b8),
++     TOBN(0xcda7838a, 0x65d30672), TOBN(0x8b08d534, 0xfd657e86),
++     TOBN(0x4c5b4395, 0x46d595c8), TOBN(0x39b58725, 0x425cb836),
++     TOBN(0x8ea61059, 0x3de9abe3), TOBN(0x40434881, 0x9cdc03be),
++     TOBN(0x9b261245, 0xcfedce8c), TOBN(0x78c318b4, 0xcf5234a1),
++     TOBN(0x510bcf16, 0xfde24c99), TOBN(0x2a77cb75, 0xa2c2ff5d),
++     TOBN(0x9c895c2b, 0x27960fb4), TOBN(0xd30ce975, 0xb0eda42b),
++     TOBN(0xfda85393, 0x1a62cc26), TOBN(0x23c69b96, 0x50c0e052),
++     TOBN(0xa227df15, 0xbfc633f3), TOBN(0x2ac78848, 0x1bae7d48),
++     TOBN(0x487878f9, 0x187d073d), TOBN(0x6c2be919, 0x967f807d),
++     TOBN(0x765861d8, 0x336e6d8f), TOBN(0x88b8974c, 0xce528a43),
++     TOBN(0x09521177, 0xff57d051), TOBN(0x2ff38037, 0xfb6a1961),
++     TOBN(0xfc0aba74, 0xa3d76ad4), TOBN(0x7c764803, 0x25a7ec17),
++     TOBN(0x7532d75f, 0x48879bc8), TOBN(0xea7eacc0, 0x58ce6bc1),
++     TOBN(0xc82176b4, 0x8e896c16), TOBN(0x9a30e0b2, 0x2c750fed),
++     TOBN(0xc37e2c2e, 0x421d3aa4), TOBN(0xf926407c, 0xe84fa840),
++     TOBN(0x18abc03d, 0x1454e41c), TOBN(0x26605ecd, 0x3f7af644),
++     TOBN(0x242341a6, 0xd6a5eabf), TOBN(0x1edb84f4, 0x216b668e),
++     TOBN(0xd836edb8, 0x04010102), TOBN(0x5b337ce7, 0x945e1d8c),
++     TOBN(0xd2075c77, 0xc055dc14), TOBN(0x2a0ffa25, 0x81d89cdf),
++     TOBN(0x8ce815ea, 0x6ffdcbaf), TOBN(0xa3428878, 0xfb648867),
++     TOBN(0x277699cf, 0x884655fb), TOBN(0xfa5b5bd6, 0x364d3e41),
++     TOBN(0x01f680c6, 0x441e1cb7), TOBN(0x3fd61e66, 0xb70a7d67),
++     TOBN(0x666ba2dc, 0xcc78cf66), TOBN(0xb3018174, 0x6fdbff77),
++     TOBN(0x8d4dd0db, 0x168d4668), TOBN(0x259455d0, 0x1dab3a2a),
++     TOBN(0xf58564c5, 0xcde3acec), TOBN(0x77141925, 0x13adb276),
++     TOBN(0x527d725d, 0x8a303f65), TOBN(0x55deb6c9, 0xe6f38f7b),
++     TOBN(0xfd5bb657, 0xb1fa70fb), TOBN(0xfa07f50f, 0xd8073a00),
++     TOBN(0xf72e3aa7, 0xbca02500), TOBN(0xf68f895d, 0x9975740d),
++     TOBN(0x30112060, 0x5cae2a6a), TOBN(0x01bd7218, 0x02874842),
++     TOBN(0x3d423891, 0x7ce47bd3), TOBN(0xa66663c1, 0x789544f6),
++     TOBN(0x864d05d7, 0x3272d838), TOBN(0xe22924f9, 0xfa6295c5),
++     TOBN(0x8189593f, 0x6c2fda32), TOBN(0x330d7189, 0xb184b544),
++     TOBN(0x79efa62c, 0xbde1f714), TOBN(0x35771c94, 0xe5cb1a63),
++     TOBN(0x2f4826b8, 0x641c8332), TOBN(0x00a894fb, 0xc8cee854),
++     TOBN(0xb4b9a39b, 0x36194d40), TOBN(0xe857a7c5, 0x77612601),
++     TOBN(0xf4209dd2, 0x4ecf2f58), TOBN(0x82b9e66d, 0x5a033487),
++     TOBN(0xc1e36934, 0xe4e8b9dd), TOBN(0xd2372c9d, 0xa42377d7),
++     TOBN(0x51dc94c7, 0x0e3ae43b), TOBN(0x4c57761e, 0x04474f6f),
++     TOBN(0xdcdacd0a, 0x1058a318), TOBN(0x369cf3f5, 0x78053a9a),
++     TOBN(0xc6c3de50, 0x31c68de2), TOBN(0x4653a576, 0x3c4b6d9f),
++     TOBN(0x1688dd5a, 0xaa4e5c97), TOBN(0x5be80aa1, 0xb7ab3c74),
++     TOBN(0x70cefe7c, 0xbc65c283), TOBN(0x57f95f13, 0x06867091),
++     TOBN(0xa39114e2, 0x4415503b), TOBN(0xc08ff7c6, 0x4cbb17e9),
++     TOBN(0x1eff674d, 0xd7dec966), TOBN(0x6d4690af, 0x53376f63),
++     TOBN(0xff6fe32e, 0xea74237b), TOBN(0xc436d17e, 0xcd57508e),
++     TOBN(0x15aa28e1, 0xedcc40fe), TOBN(0x0d769c04, 0x581bbb44),
++     TOBN(0xc240b6de, 0x34eaacda), TOBN(0xd9e116e8, 0x2ba0f1de),
++     TOBN(0xcbe45ec7, 0x79438e55), TOBN(0x91787c9d, 0x96f752d7),
++     TOBN(0x897f532b, 0xf129ac2f), TOBN(0xd307b7c8, 0x5a36e22c),
++     TOBN(0x91940675, 0x749fb8f3), TOBN(0xd14f95d0, 0x157fdb28),
++     TOBN(0xfe51d029, 0x6ae55043), TOBN(0x8931e98f, 0x44a87de1),
++     TOBN(0xe57f1cc6, 0x09e4fee2), TOBN(0x0d063b67, 0x4e072d92),
++     TOBN(0x70a998b9, 0xed0e4316), TOBN(0xe74a736b, 0x306aca46),
++     TOBN(0xecf0fbf2, 0x4fda97c7), TOBN(0xa40f65cb, 0x3e178d93),
++     TOBN(0x16253604, 0x16df4285), TOBN(0xb0c9babb, 0xd0c56ae2),
++     TOBN(0x73032b19, 0xcfc5cfc3), TOBN(0xe497e5c3, 0x09752056),
++     TOBN(0x12096bb4, 0x164bda96), TOBN(0x1ee42419, 0xa0b74da1),
++     TOBN(0x8fc36243, 0x403826ba), TOBN(0x0c8f0069, 0xdc09e660),
++     TOBN(0x8667e981, 0xc27253c9), TOBN(0x05a6aefb, 0x92b36a45),
++     TOBN(0xa62c4b36, 0x9cb7bb46), TOBN(0x8394f375, 0x11f7027b),
++     TOBN(0x747bc79c, 0x5f109d0f), TOBN(0xcad88a76, 0x5b8cc60a),
++     TOBN(0x80c5a66b, 0x58f09e68), TOBN(0xe753d451, 0xf6127eac),
++     TOBN(0xc44b74a1, 0x5b0ec6f5), TOBN(0x47989fe4, 0x5289b2b8),
++     TOBN(0x745f8484, 0x58d6fc73), TOBN(0xec362a6f, 0xf61c70ab),
++     TOBN(0x070c98a7, 0xb3a8ad41), TOBN(0x73a20fc0, 0x7b63db51),
++     TOBN(0xed2c2173, 0xf44c35f4), TOBN(0x8a56149d, 0x9acc9dca),
++     TOBN(0x98f17881, 0x9ac6e0f4), TOBN(0x360fdeaf, 0xa413b5ed),
++     TOBN(0x0625b8f4, 0xa300b0fd), TOBN(0xf1f4d76a, 0x5b3222d3),
++     TOBN(0x9d6f5109, 0x587f76b8), TOBN(0x8b4ee08d, 0x2317fdb5),
++     TOBN(0x88089bb7, 0x8c68b095), TOBN(0x95570e9a, 0x5808d9b9),
++     TOBN(0xa395c36f, 0x35d33ae7), TOBN(0x200ea123, 0x50bb5a94),
++     TOBN(0x20c789bd, 0x0bafe84b), TOBN(0x243ef52d, 0x0919276a),
++     TOBN(0x3934c577, 0xe23ae233), TOBN(0xb93807af, 0xa460d1ec),
++     TOBN(0xb72a53b1, 0xf8fa76a4), TOBN(0xd8914cb0, 0xc3ca4491),
++     TOBN(0x2e128494, 0x3fb42622), TOBN(0x3b2700ac, 0x500907d5),
++     TOBN(0xf370fb09, 0x1a95ec63), TOBN(0xf8f30be2, 0x31b6dfbd),
++     TOBN(0xf2b2f8d2, 0x69e55f15), TOBN(0x1fead851, 0xcc1323e9),
++     TOBN(0xfa366010, 0xd9e5eef6), TOBN(0x64d487b0, 0xe316107e),
++     TOBN(0x4c076b86, 0xd23ddc82), TOBN(0x03fd344c, 0x7e0143f0),
++     TOBN(0xa95362ff, 0x317af2c5), TOBN(0x0add3db7, 0xe18b7a4f),
++     TOBN(0x9c673e3f, 0x8260e01b), TOBN(0xfbeb49e5, 0x54a1cc91),
++     TOBN(0x91351bf2, 0x92f2e433), TOBN(0xc755e7ec, 0x851141eb),
++     TOBN(0xc9a95139, 0x29607745), TOBN(0x0ca07420, 0xa26f2b28),
++     TOBN(0xcb2790e7, 0x4bc6f9dd), TOBN(0x345bbb58, 0xadcaffc0),
++     TOBN(0xc65ea38c, 0xbe0f27a2), TOBN(0x67c24d7c, 0x641fcb56),
++     TOBN(0x2c25f0a7, 0xa9e2c757), TOBN(0x93f5cdb0, 0x16f16c49),
++     TOBN(0x2ca5a9d7, 0xc5ee30a1), TOBN(0xd1593635, 0xb909b729),
++     TOBN(0x804ce9f3, 0xdadeff48), TOBN(0xec464751, 0xb07c30c3),
++     TOBN(0x89d65ff3, 0x9e49af6a), TOBN(0xf2d6238a, 0x6f3d01bc),
++     TOBN(0x1095561e, 0x0bced843), TOBN(0x51789e12, 0xc8a13fd8),
++     TOBN(0xd633f929, 0x763231df), TOBN(0x46df9f7d, 0xe7cbddef),
++     TOBN(0x01c889c0, 0xcb265da8), TOBN(0xfce1ad10, 0xaf4336d2),
++     TOBN(0x8d110df6, 0xfc6a0a7e), TOBN(0xdd431b98, 0x6da425dc),
++     TOBN(0xcdc4aeab, 0x1834aabe), TOBN(0x84deb124, 0x8439b7fc),
++     TOBN(0x8796f169, 0x3c2a5998), TOBN(0x9b9247b4, 0x7947190d),
++     TOBN(0x55b9d9a5, 0x11597014), TOBN(0x7e9dd70d, 0x7b1566ee),
++     TOBN(0x94ad78f7, 0xcbcd5e64), TOBN(0x0359ac17, 0x9bd4c032),
++     TOBN(0x3b11baaf, 0x7cc222ae), TOBN(0xa6a6e284, 0xba78e812),
++     TOBN(0x8392053f, 0x24cea1a0), TOBN(0xc97bce4a, 0x33621491),
++     TOBN(0x7eb1db34, 0x35399ee9), TOBN(0x473f78ef, 0xece81ad1),
++     TOBN(0x41d72fe0, 0xf63d3d0d), TOBN(0xe620b880, 0xafab62fc),
++     TOBN(0x92096bc9, 0x93158383), TOBN(0x41a21357, 0x8f896f6c),
++     TOBN(0x1b5ee2fa, 0xc7dcfcab), TOBN(0x650acfde, 0x9546e007),
++     TOBN(0xc081b749, 0xb1b02e07), TOBN(0xda9e41a0, 0xf9eca03d),
++     TOBN(0x013ba727, 0x175a54ab), TOBN(0xca0cd190, 0xea5d8d10),
++     TOBN(0x85ea52c0, 0x95fd96a9), TOBN(0x2c591b9f, 0xbc5c3940),
++     TOBN(0x6fb4d4e4, 0x2bad4d5f), TOBN(0xfa4c3590, 0xfef0059b),
++     TOBN(0x6a10218a, 0xf5122294), TOBN(0x9a78a81a, 0xa85751d1),
++     TOBN(0x04f20579, 0xa98e84e7), TOBN(0xfe1242c0, 0x4997e5b5),
++     TOBN(0xe77a273b, 0xca21e1e4), TOBN(0xfcc8b1ef, 0x9411939d),
++     TOBN(0xe20ea302, 0x92d0487a), TOBN(0x1442dbec, 0x294b91fe),
++     TOBN(0x1f7a4afe, 0xbb6b0e8f), TOBN(0x1700ef74, 0x6889c318),
++     TOBN(0xf5bbffc3, 0x70f1fc62), TOBN(0x3b31d4b6, 0x69c79cca),
++     TOBN(0xe8bc2aab, 0xa7f6340d), TOBN(0xb0b08ab4, 0xa725e10a),
++     TOBN(0x44f05701, 0xae340050), TOBN(0xba4b3016, 0x1cf0c569),
++     TOBN(0x5aa29f83, 0xfbe19a51), TOBN(0x1b9ed428, 0xb71d752e),
++     TOBN(0x1666e54e, 0xeb4819f5), TOBN(0x616cdfed, 0x9e18b75b),
++     TOBN(0x112ed5be, 0x3ee27b0b), TOBN(0xfbf28319, 0x44c7de4d),
++     TOBN(0xd685ec85, 0xe0e60d84), TOBN(0x68037e30, 0x1db7ee78),
++     TOBN(0x5b65bdcd, 0x003c4d6e), TOBN(0x33e7363a, 0x93e29a6a),
++     TOBN(0x995b3a61, 0x08d0756c), TOBN(0xd727f85c, 0x2faf134b),
++     TOBN(0xfac6edf7, 0x1d337823), TOBN(0x99b9aa50, 0x0439b8b4),
++     TOBN(0x722eb104, 0xe2b4e075), TOBN(0x49987295, 0x437c4926),
++     TOBN(0xb1e4c0e4, 0x46a9b82d), TOBN(0xd0cb3197, 0x57a006f5),
++     TOBN(0xf3de0f7d, 0xd7808c56), TOBN(0xb5c54d8f, 0x51f89772),
++     TOBN(0x500a114a, 0xadbd31aa), TOBN(0x9afaaaa6, 0x295f6cab),
++     TOBN(0x94705e21, 0x04cf667a), TOBN(0xfc2a811b, 0x9d3935d7),
++     TOBN(0x560b0280, 0x6d09267c), TOBN(0xf19ed119, 0xf780e53b),
++     TOBN(0xf0227c09, 0x067b6269), TOBN(0x967b8533, 0x5caef599),
++     TOBN(0x155b9243, 0x68efeebc), TOBN(0xcd6d34f5, 0xc497bae6),
++     TOBN(0x1dd8d5d3, 0x6cceb370), TOBN(0x2aeac579, 0xa78d7bf9),
++     TOBN(0x5d65017d, 0x70b67a62), TOBN(0x70c8e44f, 0x17c53f67),
++     TOBN(0xd1fc0950, 0x86a34d09), TOBN(0xe0fca256, 0xe7134907),
++     TOBN(0xe24fa29c, 0x80fdd315), TOBN(0x2c4acd03, 0xd87499ad),
++     TOBN(0xbaaf7517, 0x3b5a9ba6), TOBN(0xb9cbe1f6, 0x12e51a51),
++     TOBN(0xd88edae3, 0x5e154897), TOBN(0xe4309c3c, 0x77b66ca0),
++     TOBN(0xf5555805, 0xf67f3746), TOBN(0x85fc37ba, 0xa36401ff),
++     TOBN(0xdf86e2ca, 0xd9499a53), TOBN(0x6270b2a3, 0xecbc955b),
++     TOBN(0xafae64f5, 0x974ad33b), TOBN(0x04d85977, 0xfe7b2df1),
++     TOBN(0x2a3db3ff, 0x4ab03f73), TOBN(0x0b87878a, 0x8702740a),
++     TOBN(0x6d263f01, 0x5a061732), TOBN(0xc25430ce, 0xa32a1901),
++     TOBN(0xf7ebab3d, 0xdb155018), TOBN(0x3a86f693, 0x63a9b78e),
++     TOBN(0x349ae368, 0xda9f3804), TOBN(0x470f07fe, 0xa164349c),
++     TOBN(0xd52f4cc9, 0x8562baa5), TOBN(0xc74a9e86, 0x2b290df3),
++     TOBN(0xd3a1aa35, 0x43471a24), TOBN(0x239446be, 0xb8194511),
++     TOBN(0xbec2dd00, 0x81dcd44d), TOBN(0xca3d7f0f, 0xc42ac82d),
++     TOBN(0x1f3db085, 0xfdaf4520), TOBN(0xbb6d3e80, 0x4549daf2),
++     TOBN(0xf5969d8a, 0x19ad5c42), TOBN(0x7052b13d, 0xdbfd1511),
++     TOBN(0x11890d1b, 0x682b9060), TOBN(0xa71d3883, 0xac34452c),
++     TOBN(0xa438055b, 0x783805b4), TOBN(0x43241277, 0x4725b23e),
++     TOBN(0xf20cf96e, 0x4901bbed), TOBN(0x6419c710, 0xf432a2bb),
++     TOBN(0x57a0fbb9, 0xdfa9cd7d), TOBN(0x589111e4, 0x00daa249),
++     TOBN(0x19809a33, 0x7b60554e), TOBN(0xea5f8887, 0xede283a4),
++     TOBN(0x2d713802, 0x503bfd35), TOBN(0x151bb0af, 0x585d2a53),
++     TOBN(0x40b08f74, 0x43b30ca8), TOBN(0xe10b5bba, 0xd9934583),
++     TOBN(0xe8a546d6, 0xb51110ad), TOBN(0x1dd50e66, 0x28e0b6c5),
++     TOBN(0x292e9d54, 0xcff2b821), TOBN(0x3882555d, 0x47281760),
++     TOBN(0x134838f8, 0x3724d6e3), TOBN(0xf2c679e0, 0x22ddcda1),
++     TOBN(0x40ee8815, 0x6d2a5768), TOBN(0x7f227bd2, 0x1c1e7e2d),
++     TOBN(0x487ba134, 0xd04ff443), TOBN(0x76e2ff3d, 0xc614e54b),
++     TOBN(0x36b88d6f, 0xa3177ec7), TOBN(0xbf731d51, 0x2328fff5),
++     TOBN(0x758caea2, 0x49ba158e), TOBN(0x5ab8ff4c, 0x02938188),
++     TOBN(0x33e16056, 0x35edc56d), TOBN(0x5a69d349, 0x7e940d79),
++     TOBN(0x6c4fd001, 0x03866dcb), TOBN(0x20a38f57, 0x4893cdef),
++     TOBN(0xfbf3e790, 0xfac3a15b), TOBN(0x6ed7ea2e, 0x7a4f8e6b),
++     TOBN(0xa663eb4f, 0xbc3aca86), TOBN(0x22061ea5, 0x080d53f7),
++     TOBN(0x2480dfe6, 0xf546783f), TOBN(0xd38bc6da, 0x5a0a641e),
++     TOBN(0xfb093cd1, 0x2ede8965), TOBN(0x89654db4, 0xacb455cf),
++     TOBN(0x413cbf9a, 0x26e1adee), TOBN(0x291f3764, 0x373294d4),
++     TOBN(0x00797257, 0x648083fe), TOBN(0x25f504d3, 0x208cc341),
++     TOBN(0x635a8e5e, 0xc3a0ee43), TOBN(0x70aaebca, 0x679898ff),
++     TOBN(0x9ee9f547, 0x5dc63d56), TOBN(0xce987966, 0xffb34d00),
++     TOBN(0xf9f86b19, 0x5e26310a), TOBN(0x9e435484, 0x382a8ca8),
++     TOBN(0x253bcb81, 0xc2352fe4), TOBN(0xa4eac8b0, 0x4474b571),
++     TOBN(0xc1b97512, 0xc1ad8cf8), TOBN(0x193b4e9e, 0x99e0b697),
++     TOBN(0x939d2716, 0x01e85df0), TOBN(0x4fb265b3, 0xcd44eafd),
++     TOBN(0x321e7dcd, 0xe51e1ae2), TOBN(0x8e3a8ca6, 0xe3d8b096),
++     TOBN(0x8de46cb0, 0x52604998), TOBN(0x91099ad8, 0x39072aa7),
++     TOBN(0x2617f91c, 0x93aa96b8), TOBN(0x0fc8716b, 0x7fca2e13),
++     TOBN(0xa7106f5e, 0x95328723), TOBN(0xd1c9c40b, 0x262e6522),
++     TOBN(0xb9bafe86, 0x42b7c094), TOBN(0x1873439d, 0x1543c021),
++     TOBN(0xe1baa5de, 0x5cbefd5d), TOBN(0xa363fc5e, 0x521e8aff),
++     TOBN(0xefe6320d, 0xf862eaac), TOBN(0x14419c63, 0x22c647dc),
++     TOBN(0x0e06707c, 0x4e46d428), TOBN(0xcb6c834f, 0x4a178f8f),
++     TOBN(0x0f993a45, 0xd30f917c), TOBN(0xd4c4b049, 0x9879afee),
++     TOBN(0xb6142a1e, 0x70500063), TOBN(0x7c9b41c3, 0xa5d9d605),
++     TOBN(0xbc00fc2f, 0x2f8ba2c7), TOBN(0x0966eb2f, 0x7c67aa28),
++     TOBN(0x13f7b516, 0x5a786972), TOBN(0x3bfb7557, 0x8a2fbba0),
++     TOBN(0x131c4f23, 0x5a2b9620), TOBN(0xbff3ed27, 0x6faf46be),
++     TOBN(0x9b4473d1, 0x7e172323), TOBN(0x421e8878, 0x339f6246),
++     TOBN(0x0fa8587a, 0x25a41632), TOBN(0xc0814124, 0xa35b6c93),
++     TOBN(0x2b18a9f5, 0x59ebb8db), TOBN(0x264e3357, 0x76edb29c),
++     TOBN(0xaf245ccd, 0xc87c51e2), TOBN(0x16b3015b, 0x501e6214),
++     TOBN(0xbb31c560, 0x0a3882ce), TOBN(0x6961bb94, 0xfec11e04),
++     TOBN(0x3b825b8d, 0xeff7a3a0), TOBN(0xbec33738, 0xb1df7326),
++     TOBN(0x68ad747c, 0x99604a1f), TOBN(0xd154c934, 0x9a3bd499),
++     TOBN(0xac33506f, 0x1cc7a906), TOBN(0x73bb5392, 0x6c560e8f),
++     TOBN(0x6428fcbe, 0x263e3944), TOBN(0xc11828d5, 0x1c387434),
++     TOBN(0x3cd04be1, 0x3e4b12ff), TOBN(0xc3aad9f9, 0x2d88667c),
++     TOBN(0xc52ddcf8, 0x248120cf), TOBN(0x985a892e, 0x2a389532),
++     TOBN(0xfbb4b21b, 0x3bb85fa0), TOBN(0xf95375e0, 0x8dfc6269),
++     TOBN(0xfb4fb06c, 0x7ee2acea), TOBN(0x6785426e, 0x309c4d1f),
++     TOBN(0x659b17c8, 0xd8ceb147), TOBN(0x9b649eee, 0xb70a5554),
++     TOBN(0x6b7fa0b5, 0xac6bc634), TOBN(0xd99fe2c7, 0x1d6e732f),
++     TOBN(0x30e6e762, 0x8d3abba2), TOBN(0x18fee6e7, 0xa797b799),
++     TOBN(0x5c9d360d, 0xc696464d), TOBN(0xe3baeb48, 0x27bfde12),
++     TOBN(0x2bf5db47, 0xf23206d5), TOBN(0x2f6d3420, 0x1d260152),
++     TOBN(0x17b87653, 0x3f8ff89a), TOBN(0x5157c30c, 0x378fa458),
++     TOBN(0x7517c5c5, 0x2d4fb936), TOBN(0xef22f7ac, 0xe6518cdc),
++     TOBN(0xdeb483e6, 0xbf847a64), TOBN(0xf5084558, 0x92e0fa89),}
++    ,
++    {TOBN(0xab9659d8, 0xdf7304d4), TOBN(0xb71bcf1b, 0xff210e8e),
++     TOBN(0xa9a2438b, 0xd73fbd60), TOBN(0x4595cd1f, 0x5d11b4de),
++     TOBN(0x9c0d329a, 0x4835859d), TOBN(0x4a0f0d2d, 0x7dbb6e56),
++     TOBN(0xc6038e5e, 0xdf928a4e), TOBN(0xc9429621, 0x8f5ad154),
++     TOBN(0x91213462, 0xf23f2d92), TOBN(0x6cab71bd, 0x60b94078),
++     TOBN(0x6bdd0a63, 0x176cde20), TOBN(0x54c9b20c, 0xee4d54bc),
++     TOBN(0x3cd2d8aa, 0x9f2ac02f), TOBN(0x03f8e617, 0x206eedb0),
++     TOBN(0xc7f68e16, 0x93086434), TOBN(0x831469c5, 0x92dd3db9),
++     TOBN(0x8521df24, 0x8f981354), TOBN(0x587e23ec, 0x3588a259),
++     TOBN(0xcbedf281, 0xd7a0992c), TOBN(0x06930a55, 0x38961407),
++     TOBN(0x09320deb, 0xbe5bbe21), TOBN(0xa7ffa5b5, 0x2491817f),
++     TOBN(0xe6c8b4d9, 0x09065160), TOBN(0xac4f3992, 0xfff6d2a9),
++     TOBN(0x7aa7a158, 0x3ae9c1bd), TOBN(0xe0af6d98, 0xe37ce240),
++     TOBN(0xe54342d9, 0x28ab38b4), TOBN(0xe8b75007, 0x0a1c98ca),
++     TOBN(0xefce86af, 0xe02358f2), TOBN(0x31b8b856, 0xea921228),
++     TOBN(0x052a1912, 0x0a1c67fc), TOBN(0xb4069ea4, 0xe3aead59),
++     TOBN(0x3232d6e2, 0x7fa03cb3), TOBN(0xdb938e5b, 0x0fdd7d88),
++     TOBN(0x04c1d2cd, 0x2ccbfc5d), TOBN(0xd2f45c12, 0xaf3a580f),
++     TOBN(0x592620b5, 0x7883e614), TOBN(0x5fd27e68, 0xbe7c5f26),
++     TOBN(0x139e45a9, 0x1567e1e3), TOBN(0x2cc71d2d, 0x44d8aaaf),
++     TOBN(0x4a9090cd, 0xe36d0757), TOBN(0xf722d7b1, 0xd9a29382),
++     TOBN(0xfb7fb04c, 0x04b48ddf), TOBN(0x628ad2a7, 0xebe16f43),
++     TOBN(0xcd3fbfb5, 0x20226040), TOBN(0x6c34ecb1, 0x5104b6c4),
++     TOBN(0x30c0754e, 0xc903c188), TOBN(0xec336b08, 0x2d23cab0),
++     TOBN(0x473d62a2, 0x1e206ee5), TOBN(0xf1e27480, 0x8c49a633),
++     TOBN(0x87ab956c, 0xe9f6b2c3), TOBN(0x61830b48, 0x62b606ea),
++     TOBN(0x67cd6846, 0xe78e815f), TOBN(0xfe40139f, 0x4c02082a),
++     TOBN(0x52bbbfcb, 0x952ec365), TOBN(0x74c11642, 0x6b9836ab),
++     TOBN(0x9f51439e, 0x558df019), TOBN(0x230da4ba, 0xac712b27),
++     TOBN(0x518919e3, 0x55185a24), TOBN(0x4dcefcdd, 0x84b78f50),
++     TOBN(0xa7d90fb2, 0xa47d4c5a), TOBN(0x55ac9abf, 0xb30e009e),
++     TOBN(0xfd2fc359, 0x74eed273), TOBN(0xb72d824c, 0xdbea8faf),
++     TOBN(0xce721a74, 0x4513e2ca), TOBN(0x0b418612, 0x38240b2c),
++     TOBN(0x05199968, 0xd5baa450), TOBN(0xeb1757ed, 0x2b0e8c25),
++     TOBN(0x6ebc3e28, 0x3dfac6d5), TOBN(0xb2431e2e, 0x48a237f5),
++     TOBN(0x2acb5e23, 0x52f61499), TOBN(0x5558a2a7, 0xe06c936b),
++     TOBN(0xd213f923, 0xcbb13d1b), TOBN(0x98799f42, 0x5bfb9bfe),
++     TOBN(0x1ae8ddc9, 0x701144a9), TOBN(0x0b8b3bb6, 0x4c5595ee),
++     TOBN(0x0ea9ef2e, 0x3ecebb21), TOBN(0x17cb6c4b, 0x3671f9a7),
++     TOBN(0x47ef464f, 0x726f1d1f), TOBN(0x171b9484, 0x6943a276),
++     TOBN(0x51a4ae2d, 0x7ef0329c), TOBN(0x08509222, 0x91c4402a),
++     TOBN(0x64a61d35, 0xafd45bbc), TOBN(0x38f096fe, 0x3035a851),
++     TOBN(0xc7468b74, 0xa1dec027), TOBN(0xe8cf10e7, 0x4fc7dcba),
++     TOBN(0xea35ff40, 0xf4a06353), TOBN(0x0b4c0dfa, 0x8b77dd66),
++     TOBN(0x779b8552, 0xde7e5c19), TOBN(0xfab28609, 0xc1c0256c),
++     TOBN(0x64f58eee, 0xabd4743d), TOBN(0x4e8ef838, 0x7b6cc93b),
++     TOBN(0xee650d26, 0x4cb1bf3d), TOBN(0x4c1f9d09, 0x73dedf61),
++     TOBN(0xaef7c9d7, 0xbfb70ced), TOBN(0x1ec0507e, 0x1641de1e),
++     TOBN(0xcd7e5cc7, 0xcde45079), TOBN(0xde173c9a, 0x516ac9e4),
++     TOBN(0x517a8494, 0xc170315c), TOBN(0x438fd905, 0x91d8e8fb),
++     TOBN(0x5145c506, 0xc7d9630b), TOBN(0x6457a87b, 0xf47d4d75),
++     TOBN(0xd31646bf, 0x0d9a80e8), TOBN(0x453add2b, 0xcef3aabe),
++     TOBN(0xc9941109, 0xa607419d), TOBN(0xfaa71e62, 0xbb6bca80),
++     TOBN(0x34158c13, 0x07c431f3), TOBN(0x594abebc, 0x992bc47a),
++     TOBN(0x6dfea691, 0xeb78399f), TOBN(0x48aafb35, 0x3f42cba4),
++     TOBN(0xedcd65af, 0x077c04f0), TOBN(0x1a29a366, 0xe884491a),
++     TOBN(0x023a40e5, 0x1c21f2bf), TOBN(0xf99a513c, 0xa5057aee),
++     TOBN(0xa3fe7e25, 0xbcab072e), TOBN(0x8568d2e1, 0x40e32bcf),
++     TOBN(0x904594eb, 0xd3f69d9f), TOBN(0x181a9733, 0x07affab1),
++     TOBN(0xe4d68d76, 0xb6e330f4), TOBN(0x87a6dafb, 0xc75a7fc1),
++     TOBN(0x549db2b5, 0xef7d9289), TOBN(0x2480d4a8, 0x197f015a),
++     TOBN(0x61d5590b, 0xc40493b6), TOBN(0x3a55b52e, 0x6f780331),
++     TOBN(0x40eb8115, 0x309eadb0), TOBN(0xdea7de5a, 0x92e5c625),
++     TOBN(0x64d631f0, 0xcc6a3d5a), TOBN(0x9d5e9d7c, 0x93e8dd61),
++     TOBN(0xf297bef5, 0x206d3ffc), TOBN(0x23d5e033, 0x7d808bd4),
++     TOBN(0x4a4f6912, 0xd24cf5ba), TOBN(0xe4d8163b, 0x09cdaa8a),
++     TOBN(0x0e0de9ef, 0xd3082e8e), TOBN(0x4fe1246c, 0x0192f360),
++     TOBN(0x1f900150, 0x4b8eee0a), TOBN(0x5219da81, 0xf1da391b),
++     TOBN(0x7bf6a5c1, 0xf7ea25aa), TOBN(0xd165e6bf, 0xfbb07d5f),
++     TOBN(0xe3539361, 0x89e78671), TOBN(0xa3fcac89, 0x2bac4219),
++     TOBN(0xdfab6fd4, 0xf0baa8ab), TOBN(0x5a4adac1, 0xe2c1c2e5),
++     TOBN(0x6cd75e31, 0x40d85849), TOBN(0xce263fea, 0x19b39181),
++     TOBN(0xcb6803d3, 0x07032c72), TOBN(0x7f40d5ce, 0x790968c8),
++     TOBN(0xa6de86bd, 0xdce978f0), TOBN(0x25547c4f, 0x368f751c),
++     TOBN(0xb1e685fd, 0x65fb2a9e), TOBN(0xce69336f, 0x1eb9179c),
++     TOBN(0xb15d1c27, 0x12504442), TOBN(0xb7df465c, 0xb911a06b),
++     TOBN(0xb8d804a3, 0x315980cd), TOBN(0x693bc492, 0xfa3bebf7),
++     TOBN(0x3578aeee, 0x2253c504), TOBN(0x158de498, 0xcd2474a2),
++     TOBN(0x1331f5c7, 0xcfda8368), TOBN(0xd2d7bbb3, 0x78d7177e),
++     TOBN(0xdf61133a, 0xf3c1e46e), TOBN(0x5836ce7d, 0xd30e7be8),
++     TOBN(0x83084f19, 0x94f834cb), TOBN(0xd35653d4, 0x429ed782),
++     TOBN(0xa542f16f, 0x59e58243), TOBN(0xc2b52f65, 0x0470a22d),
++     TOBN(0xe3b6221b, 0x18f23d96), TOBN(0xcb05abac, 0x3f5252b4),
++     TOBN(0xca00938b, 0x87d61402), TOBN(0x2f186cdd, 0x411933e4),
++     TOBN(0xe042ece5, 0x9a29a5c5), TOBN(0xb19b3c07, 0x3b6c8402),
++     TOBN(0xc97667c7, 0x19d92684), TOBN(0xb5624622, 0xebc66372),
++     TOBN(0x0cb96e65, 0x3c04fa02), TOBN(0x83a7176c, 0x8eaa39aa),
++     TOBN(0x2033561d, 0xeaa1633f), TOBN(0x45a9d086, 0x4533df73),
++     TOBN(0xe0542c1d, 0x3dc090bc), TOBN(0x82c996ef, 0xaa59c167),
++     TOBN(0xe3f735e8, 0x0ee7fc4d), TOBN(0x7b179393, 0x7c35db79),
++     TOBN(0xb6419e25, 0xf8c5dbfd), TOBN(0x4d9d7a1e, 0x1f327b04),
++     TOBN(0x979f6f9b, 0x298dfca8), TOBN(0xc7c5dff1, 0x8de9366a),
++     TOBN(0x1b7a588d, 0x04c82bdd), TOBN(0x68005534, 0xf8319dfd),
++     TOBN(0xde8a55b5, 0xd8eb9580), TOBN(0x5ea886da, 0x8d5bca81),
++     TOBN(0xe8530a01, 0x252a0b4d), TOBN(0x1bffb4fe, 0x35eaa0a1),
++     TOBN(0x2ad828b1, 0xd8e99563), TOBN(0x7de96ef5, 0x95f9cd87),
++     TOBN(0x4abb2d0c, 0xd77d970c), TOBN(0x03cfb933, 0xd33ef9cb),
++     TOBN(0xb0547c01, 0x8b211fe9), TOBN(0x2fe64809, 0xa56ed1c6),
++     TOBN(0xcb7d5624, 0xc2ac98cc), TOBN(0x2a1372c0, 0x1a393e33),
++     TOBN(0xc8d1ec1c, 0x29660521), TOBN(0xf3d31b04, 0xb37ac3e9),
++     TOBN(0xa29ae9df, 0x5ece6e7c), TOBN(0x0603ac8f, 0x0facfb55),
++     TOBN(0xcfe85b7a, 0xdda233a5), TOBN(0xe618919f, 0xbd75f0b8),
++     TOBN(0xf555a3d2, 0x99bf1603), TOBN(0x1f43afc9, 0xf184255a),
++     TOBN(0xdcdaf341, 0x319a3e02), TOBN(0xd3b117ef, 0x03903a39),
++     TOBN(0xe095da13, 0x65d1d131), TOBN(0x86f16367, 0xc37ad03e),
++     TOBN(0x5f37389e, 0x462cd8dd), TOBN(0xc103fa04, 0xd67a60e6),
++     TOBN(0x57c34344, 0xf4b478f0), TOBN(0xce91edd8, 0xe117c98d),
++     TOBN(0x001777b0, 0x231fc12e), TOBN(0x11ae47f2, 0xb207bccb),
++     TOBN(0xd983cf8d, 0x20f8a242), TOBN(0x7aff5b1d, 0xf22e1ad8),
++     TOBN(0x68fd11d0, 0x7fc4feb3), TOBN(0x5d53ae90, 0xb0f1c3e1),
++     TOBN(0x50fb7905, 0xec041803), TOBN(0x85e3c977, 0x14404888),
++     TOBN(0x0e67faed, 0xac628d8f), TOBN(0x2e865150, 0x6668532c),
++     TOBN(0x15acaaa4, 0x6a67a6b0), TOBN(0xf4cdee25, 0xb25cec41),
++     TOBN(0x49ee565a, 0xe4c6701e), TOBN(0x2a04ca66, 0xfc7d63d8),
++     TOBN(0xeb105018, 0xef0543fb), TOBN(0xf709a4f5, 0xd1b0d81d),
++     TOBN(0x5b906ee6, 0x2915d333), TOBN(0xf4a87412, 0x96f1f0ab),
++     TOBN(0xb6b82fa7, 0x4d82f4c2), TOBN(0x90725a60, 0x6804efb3),
++     TOBN(0xbc82ec46, 0xadc3425e), TOBN(0xb7b80581, 0x2787843e),
++     TOBN(0xdf46d91c, 0xdd1fc74c), TOBN(0xdc1c62cb, 0xe783a6c4),
++     TOBN(0x59d1b9f3, 0x1a04cbba), TOBN(0xd87f6f72, 0x95e40764),
++     TOBN(0x02b4cfc1, 0x317f4a76), TOBN(0x8d2703eb, 0x91036bce),
++     TOBN(0x98206cc6, 0xa5e72a56), TOBN(0x57be9ed1, 0xcf53fb0f),
++     TOBN(0x09374571, 0xef0b17ac), TOBN(0x74b2655e, 0xd9181b38),
++     TOBN(0xc8f80ea8, 0x89935d0e), TOBN(0xc0d9e942, 0x91529936),
++     TOBN(0x19686041, 0x1e84e0e5), TOBN(0xa5db84d3, 0xaea34c93),
++     TOBN(0xf9d5bb19, 0x7073a732), TOBN(0xb8d2fe56, 0x6bcfd7c0),
++     TOBN(0x45775f36, 0xf3eb82fa), TOBN(0x8cb20ccc, 0xfdff8b58),
++     TOBN(0x1659b65f, 0x8374c110), TOBN(0xb8b4a422, 0x330c789a),
++     TOBN(0x75e3c3ea, 0x6fe8208b), TOBN(0xbd74b9e4, 0x286e78fe),
++     TOBN(0x0be2e81b, 0xd7d93a1a), TOBN(0x7ed06e27, 0xdd0a5aae),
++     TOBN(0x721f5a58, 0x6be8b800), TOBN(0x428299d1, 0xd846db28),
++     TOBN(0x95cb8e6b, 0x5be88ed3), TOBN(0xc3186b23, 0x1c034e11),
++     TOBN(0xa6312c9e, 0x8977d99b), TOBN(0xbe944331, 0x83f531e7),
++     TOBN(0x8232c0c2, 0x18d3b1d4), TOBN(0x617aae8b, 0xe1247b73),
++     TOBN(0x40153fc4, 0x282aec3b), TOBN(0xc6063d2f, 0xf7b8f823),
++     TOBN(0x68f10e58, 0x3304f94c), TOBN(0x31efae74, 0xee676346),
++     TOBN(0xbadb6c6d, 0x40a9b97c), TOBN(0x14702c63, 0x4f666256),
++     TOBN(0xdeb954f1, 0x5184b2e3), TOBN(0x5184a526, 0x94b6ca40),
++     TOBN(0xfff05337, 0x003c32ea), TOBN(0x5aa374dd, 0x205974c7),
++     TOBN(0x9a763854, 0x4b0dd71a), TOBN(0x459cd27f, 0xdeb947ec),
++     TOBN(0xa6e28161, 0x459c2b92), TOBN(0x2f020fa8, 0x75ee8ef5),
++     TOBN(0xb132ec2d, 0x30b06310), TOBN(0xc3e15899, 0xbc6a4530),
++     TOBN(0xdc5f53fe, 0xaa3f451a), TOBN(0x3a3c7f23, 0xc2d9acac),
++     TOBN(0x2ec2f892, 0x6b27e58b), TOBN(0x68466ee7, 0xd742799f),
++     TOBN(0x98324dd4, 0x1fa26613), TOBN(0xa2dc6dab, 0xbdc29d63),
++     TOBN(0xf9675faa, 0xd712d657), TOBN(0x813994be, 0x21fd8d15),
++     TOBN(0x5ccbb722, 0xfd4f7553), TOBN(0x5135ff8b, 0xf3a36b20),
++     TOBN(0x44be28af, 0x69559df5), TOBN(0x40b65bed, 0x9d41bf30),
++     TOBN(0xd98bf2a4, 0x3734e520), TOBN(0x5e3abbe3, 0x209bdcba),
++     TOBN(0x77c76553, 0xbc945b35), TOBN(0x5331c093, 0xc6ef14aa),
++     TOBN(0x518ffe29, 0x76b60c80), TOBN(0x2285593b, 0x7ace16f8),
++     TOBN(0xab1f64cc, 0xbe2b9784), TOBN(0xe8f2c0d9, 0xab2421b6),
++     TOBN(0x617d7174, 0xc1df065c), TOBN(0xafeeb5ab, 0x5f6578fa),
++     TOBN(0x16ff1329, 0x263b54a8), TOBN(0x45c55808, 0xc990dce3),
++     TOBN(0x42eab6c0, 0xecc8c177), TOBN(0x799ea9b5, 0x5982ecaa),
++     TOBN(0xf65da244, 0xb607ef8e), TOBN(0x8ab226ce, 0x32a3fc2c),
++     TOBN(0x745741e5, 0x7ea973dc), TOBN(0x5c00ca70, 0x20888f2e),
++     TOBN(0x7cdce3cf, 0x45fd9cf1), TOBN(0x8a741ef1, 0x5507f872),
++     TOBN(0x47c51c2f, 0x196b4cec), TOBN(0x70d08e43, 0xc97ea618),
++     TOBN(0x930da15c, 0x15b18a2b), TOBN(0x33b6c678, 0x2f610514),
++     TOBN(0xc662e4f8, 0x07ac9794), TOBN(0x1eccf050, 0xba06cb79),
++     TOBN(0x1ff08623, 0xe7d954e5), TOBN(0x6ef2c5fb, 0x24cf71c3),
++     TOBN(0xb2c063d2, 0x67978453), TOBN(0xa0cf3796, 0x1d654af8),
++     TOBN(0x7cb242ea, 0x7ebdaa37), TOBN(0x206e0b10, 0xb86747e0),
++     TOBN(0x481dae5f, 0xd5ecfefc), TOBN(0x07084fd8, 0xc2bff8fc),
++     TOBN(0x8040a01a, 0xea324596), TOBN(0x4c646980, 0xd4de4036),
++     TOBN(0x9eb8ab4e, 0xd65abfc3), TOBN(0xe01cb91f, 0x13541ec7),
++     TOBN(0x8f029adb, 0xfd695012), TOBN(0x9ae28483, 0x3c7569ec),
++     TOBN(0xa5614c9e, 0xa66d80a1), TOBN(0x680a3e44, 0x75f5f911),
++     TOBN(0x0c07b14d, 0xceba4fc1), TOBN(0x891c285b, 0xa13071c1),
++     TOBN(0xcac67ceb, 0x799ece3c), TOBN(0x29b910a9, 0x41e07e27),
++     TOBN(0x66bdb409, 0xf2e43123), TOBN(0x06f8b137, 0x7ac9ecbe),
++     TOBN(0x5981fafd, 0x38547090), TOBN(0x19ab8b9f, 0x85e3415d),
++     TOBN(0xfc28c194, 0xc7e31b27), TOBN(0x843be0aa, 0x6fbcbb42),
++     TOBN(0xf3b1ed43, 0xa6db836c), TOBN(0x2a1330e4, 0x01a45c05),
++     TOBN(0x4f19f3c5, 0x95c1a377), TOBN(0xa85f39d0, 0x44b5ee33),
++     TOBN(0x3da18e6d, 0x4ae52834), TOBN(0x5a403b39, 0x7423dcb0),
++     TOBN(0xbb555e0a, 0xf2374aef), TOBN(0x2ad599c4, 0x1e8ca111),
++     TOBN(0x1b3a2fb9, 0x014b3bf8), TOBN(0x73092684, 0xf66d5007),
++     TOBN(0x079f1426, 0xc4340102), TOBN(0x1827cf81, 0x8fddf4de),
++     TOBN(0xc83605f6, 0xf10ff927), TOBN(0xd3871451, 0x23739fc6),
++     TOBN(0x6d163450, 0xcac1c2cc), TOBN(0x6b521296, 0xa2ec1ac5),
++     TOBN(0x0606c4f9, 0x6e3cb4a5), TOBN(0xe47d3f41, 0x778abff7),
++     TOBN(0x425a8d5e, 0xbe8e3a45), TOBN(0x53ea9e97, 0xa6102160),
++     TOBN(0x477a106e, 0x39cbb688), TOBN(0x532401d2, 0xf3386d32),
++     TOBN(0x8e564f64, 0xb1b9b421), TOBN(0xca9b8388, 0x81dad33f),
++     TOBN(0xb1422b4e, 0x2093913e), TOBN(0x533d2f92, 0x69bc8112),
++     TOBN(0x3fa017be, 0xebe7b2c7), TOBN(0xb2767c4a, 0xcaf197c6),
++     TOBN(0xc925ff87, 0xaedbae9f), TOBN(0x7daf0eb9, 0x36880a54),
++     TOBN(0x9284ddf5, 0x9c4d0e71), TOBN(0x1581cf93, 0x316f8cf5),
++     TOBN(0x3eeca887, 0x3ac1f452), TOBN(0xb417fce9, 0xfb6aeffe),
++     TOBN(0xa5918046, 0xeefb8dc3), TOBN(0x73d318ac, 0x02209400),
++     TOBN(0xe800400f, 0x728693e5), TOBN(0xe87d814b, 0x339927ed),
++     TOBN(0x93e94d3b, 0x57ea9910), TOBN(0xff8a35b6, 0x2245fb69),
++     TOBN(0x043853d7, 0x7f200d34), TOBN(0x470f1e68, 0x0f653ce1),
++     TOBN(0x81ac05bd, 0x59a06379), TOBN(0xa14052c2, 0x03930c29),
++     TOBN(0x6b72fab5, 0x26bc2797), TOBN(0x13670d16, 0x99f16771),
++     TOBN(0x00170052, 0x1e3e48d1), TOBN(0x978fe401, 0xb7adf678),
++     TOBN(0x55ecfb92, 0xd41c5dd4), TOBN(0x5ff8e247, 0xc7b27da5),
++     TOBN(0xe7518272, 0x013fb606), TOBN(0x5768d7e5, 0x2f547a3c),
++     TOBN(0xbb24eaa3, 0x60017a5f), TOBN(0x6b18e6e4, 0x9c64ce9b),
++     TOBN(0xc225c655, 0x103dde07), TOBN(0xfc3672ae, 0x7592f7ea),
++     TOBN(0x9606ad77, 0xd06283a1), TOBN(0x542fc650, 0xe4d59d99),
++     TOBN(0xabb57c49, 0x2a40e7c2), TOBN(0xac948f13, 0xa8db9f55),
++     TOBN(0x6d4c9682, 0xb04465c3), TOBN(0xe3d062fa, 0x6468bd15),
++     TOBN(0xa51729ac, 0x5f318d7e), TOBN(0x1fc87df6, 0x9eb6fc95),
++     TOBN(0x63d146a8, 0x0591f652), TOBN(0xa861b8f7, 0x589621aa),
++     TOBN(0x59f5f15a, 0xce31348c), TOBN(0x8f663391, 0x440da6da),
++     TOBN(0xcfa778ac, 0xb591ffa3), TOBN(0x027ca9c5, 0x4cdfebce),
++     TOBN(0xbe8e05a5, 0x444ea6b3), TOBN(0x8aab4e69, 0xa78d8254),
++     TOBN(0x2437f04f, 0xb474d6b8), TOBN(0x6597ffd4, 0x045b3855),
++     TOBN(0xbb0aea4e, 0xca47ecaa), TOBN(0x568aae83, 0x85c7ebfc),
++     TOBN(0x0e966e64, 0xc73b2383), TOBN(0x49eb3447, 0xd17d8762),
++     TOBN(0xde107821, 0x8da05dab), TOBN(0x443d8baa, 0x016b7236),
++     TOBN(0x163b63a5, 0xea7610d6), TOBN(0xe47e4185, 0xce1ca979),
++     TOBN(0xae648b65, 0x80baa132), TOBN(0xebf53de2, 0x0e0d5b64),
++     TOBN(0x8d3bfcb4, 0xd3c8c1ca), TOBN(0x0d914ef3, 0x5d04b309),
++     TOBN(0x55ef6415, 0x3de7d395), TOBN(0xbde1666f, 0x26b850e8),
++     TOBN(0xdbe1ca6e, 0xd449ab19), TOBN(0x8902b322, 0xe89a2672),
++     TOBN(0xb1674b7e, 0xdacb7a53), TOBN(0x8e9faf6e, 0xf52523ff),
++     TOBN(0x6ba535da, 0x9a85788b), TOBN(0xd21f03ae, 0xbd0626d4),
++     TOBN(0x099f8c47, 0xe873dc64), TOBN(0xcda8564d, 0x018ec97e),
++     TOBN(0x3e8d7a5c, 0xde92c68c), TOBN(0x78e035a1, 0x73323cc4),
++     TOBN(0x3ef26275, 0xf880ff7c), TOBN(0xa4ee3dff, 0x273eedaa),
++     TOBN(0x58823507, 0xaf4e18f8), TOBN(0x967ec9b5, 0x0672f328),
++     TOBN(0x9ded19d9, 0x559d3186), TOBN(0x5e2ab3de, 0x6cdce39c),
++     TOBN(0xabad6e4d, 0x11c226df), TOBN(0xf9783f43, 0x87723014),
++     TOBN(0x9a49a0cf, 0x1a885719), TOBN(0xfc0c1a5a, 0x90da9dbf),
++     TOBN(0x8bbaec49, 0x571d92ac), TOBN(0x569e85fe, 0x4692517f),
++     TOBN(0x8333b014, 0xa14ea4af), TOBN(0x32f2a62f, 0x12e5c5ad),
++     TOBN(0x98c2ce3a, 0x06d89b85), TOBN(0xb90741aa, 0x2ff77a08),
++     TOBN(0x2530defc, 0x01f795a2), TOBN(0xd6e5ba0b, 0x84b3c199),
++     TOBN(0x7d8e8451, 0x12e4c936), TOBN(0xae419f7d, 0xbd0be17b),
++     TOBN(0xa583fc8c, 0x22262bc9), TOBN(0x6b842ac7, 0x91bfe2bd),
++     TOBN(0x33cef4e9, 0x440d6827), TOBN(0x5f69f4de, 0xef81fb14),
++     TOBN(0xf16cf6f6, 0x234fbb92), TOBN(0x76ae3fc3, 0xd9e7e158),
++     TOBN(0x4e89f6c2, 0xe9740b33), TOBN(0x677bc85d, 0x4962d6a1),
++     TOBN(0x6c6d8a7f, 0x68d10d15), TOBN(0x5f9a7224, 0x0257b1cd),
++     TOBN(0x7096b916, 0x4ad85961), TOBN(0x5f8c47f7, 0xe657ab4a),
++     TOBN(0xde57d7d0, 0xf7461d7e), TOBN(0x7eb6094d, 0x80ce5ee2),
++     TOBN(0x0b1e1dfd, 0x34190547), TOBN(0x8a394f43, 0xf05dd150),
++     TOBN(0x0a9eb24d, 0x97df44e6), TOBN(0x78ca06bf, 0x87675719),
++     TOBN(0x6f0b3462, 0x6ffeec22), TOBN(0x9d91bcea, 0x36cdd8fb),
++     TOBN(0xac83363c, 0xa105be47), TOBN(0x81ba76c1, 0x069710e3),
++     TOBN(0x3d1b24cb, 0x28c682c6), TOBN(0x27f25228, 0x8612575b),
++     TOBN(0xb587c779, 0xe8e66e98), TOBN(0x7b0c03e9, 0x405eb1fe),
++     TOBN(0xfdf0d030, 0x15b548e7), TOBN(0xa8be76e0, 0x38b36af7),
++     TOBN(0x4cdab04a, 0x4f310c40), TOBN(0x6287223e, 0xf47ecaec),
++     TOBN(0x678e6055, 0x8b399320), TOBN(0x61fe3fa6, 0xc01e4646),
++     TOBN(0xc482866b, 0x03261a5e), TOBN(0xdfcf45b8, 0x5c2f244a),
++     TOBN(0x8fab9a51, 0x2f684b43), TOBN(0xf796c654, 0xc7220a66),
++     TOBN(0x1d90707e, 0xf5afa58f), TOBN(0x2c421d97, 0x4fdbe0de),
++     TOBN(0xc4f4cda3, 0xaf2ebc2f), TOBN(0xa0af843d, 0xcb4efe24),
++     TOBN(0x53b857c1, 0x9ccd10b1), TOBN(0xddc9d1eb, 0x914d3e04),
++     TOBN(0x7bdec8bb, 0x62771deb), TOBN(0x829277aa, 0x91c5aa81),
++     TOBN(0x7af18dd6, 0x832391ae), TOBN(0x1740f316, 0xc71a84ca),}
++    ,
++    {TOBN(0x8928e99a, 0xeeaf8c49), TOBN(0xee7aa73d, 0x6e24d728),
++     TOBN(0x4c5007c2, 0xe72b156c), TOBN(0x5fcf57c5, 0xed408a1d),
++     TOBN(0x9f719e39, 0xb6057604), TOBN(0x7d343c01, 0xc2868bbf),
++     TOBN(0x2cca254b, 0x7e103e2d), TOBN(0xe6eb38a9, 0xf131bea2),
++     TOBN(0xb33e624f, 0x8be762b4), TOBN(0x2a9ee4d1, 0x058e3413),
++     TOBN(0x968e6369, 0x67d805fa), TOBN(0x9848949b, 0x7db8bfd7),
++     TOBN(0x5308d7e5, 0xd23a8417), TOBN(0x892f3b1d, 0xf3e29da5),
++     TOBN(0xc95c139e, 0x3dee471f), TOBN(0x8631594d, 0xd757e089),
++     TOBN(0xe0c82a3c, 0xde918dcc), TOBN(0x2e7b5994, 0x26fdcf4b),
++     TOBN(0x82c50249, 0x32cb1b2d), TOBN(0xea613a9d, 0x7657ae07),
++     TOBN(0xc2eb5f6c, 0xf1fdc9f7), TOBN(0xb6eae8b8, 0x879fe682),
++     TOBN(0x253dfee0, 0x591cbc7f), TOBN(0x000da713, 0x3e1290e6),
++     TOBN(0x1083e2ea, 0x1f095615), TOBN(0x0a28ad77, 0x14e68c33),
++     TOBN(0x6bfc0252, 0x3d8818be), TOBN(0xb585113a, 0xf35850cd),
++     TOBN(0x7d935f0b, 0x30df8aa1), TOBN(0xaddda07c, 0x4ab7e3ac),
++     TOBN(0x92c34299, 0x552f00cb), TOBN(0xc33ed1de, 0x2909df6c),
++     TOBN(0x22c2195d, 0x80e87766), TOBN(0x9e99e6d8, 0x9ddf4ac0),
++     TOBN(0x09642e4e, 0x65e74934), TOBN(0x2610ffa2, 0xff1ff241),
++     TOBN(0x4d1d47d4, 0x751c8159), TOBN(0x697b4985, 0xaf3a9363),
++     TOBN(0x0318ca46, 0x87477c33), TOBN(0xa90cb565, 0x9441eff3),
++     TOBN(0x58bb3848, 0x36f024cb), TOBN(0x85be1f77, 0x36016168),
++     TOBN(0x6c59587c, 0xdc7e07f1), TOBN(0x191be071, 0xaf1d8f02),
++     TOBN(0xbf169fa5, 0xcca5e55c), TOBN(0x3864ba3c, 0xf7d04eac),
++     TOBN(0x915e367f, 0x8d7d05db), TOBN(0xb48a876d, 0xa6549e5d),
++     TOBN(0xef89c656, 0x580e40a2), TOBN(0xf194ed8c, 0x728068bc),
++     TOBN(0x74528045, 0xa47990c9), TOBN(0xf53fc7d7, 0x5e1a4649),
++     TOBN(0xbec5ae9b, 0x78593e7d), TOBN(0x2cac4ee3, 0x41db65d7),
++     TOBN(0xa8c1eb24, 0x04a3d39b), TOBN(0x53b7d634, 0x03f8f3ef),
++     TOBN(0x2dc40d48, 0x3e07113c), TOBN(0x6e4a5d39, 0x7d8b63ae),
++     TOBN(0x5582a94b, 0x79684c2b), TOBN(0x932b33d4, 0x622da26c),
++     TOBN(0xf534f651, 0x0dbbf08d), TOBN(0x211d07c9, 0x64c23a52),
++     TOBN(0x0eeece0f, 0xee5bdc9b), TOBN(0xdf178168, 0xf7015558),
++     TOBN(0xd4294635, 0x0a712229), TOBN(0x93cbe448, 0x09273f8c),
++     TOBN(0x00b095ef, 0x8f13bc83), TOBN(0xbb741972, 0x8798978c),
++     TOBN(0x9d7309a2, 0x56dbe6e7), TOBN(0xe578ec56, 0x5a5d39ec),
++     TOBN(0x3961151b, 0x851f9a31), TOBN(0x2da7715d, 0xe5709eb4),
++     TOBN(0x867f3017, 0x53dfabf0), TOBN(0x728d2078, 0xb8e39259),
++     TOBN(0x5c75a0cd, 0x815d9958), TOBN(0xf84867a6, 0x16603be1),
++     TOBN(0xc865b13d, 0x70e35b1c), TOBN(0x02414468, 0x19b03e2c),
++     TOBN(0xe46041da, 0xac1f3121), TOBN(0x7c9017ad, 0x6f028a7c),
++     TOBN(0xabc96de9, 0x0a482873), TOBN(0x4265d6b1, 0xb77e54d4),
++     TOBN(0x68c38e79, 0xa57d88e7), TOBN(0xd461d766, 0x9ce82de3),
++     TOBN(0x817a9ec5, 0x64a7e489), TOBN(0xcc5675cd, 0xa0def5f2),
++     TOBN(0x9a00e785, 0x985d494e), TOBN(0xc626833f, 0x1b03514a),
++     TOBN(0xabe7905a, 0x83cdd60e), TOBN(0x50602fb5, 0xa1170184),
++     TOBN(0x689886cd, 0xb023642a), TOBN(0xd568d090, 0xa6e1fb00),
++     TOBN(0x5b1922c7, 0x0259217f), TOBN(0x93831cd9, 0xc43141e4),
++     TOBN(0xdfca3587, 0x0c95f86e), TOBN(0xdec2057a, 0x568ae828),
++     TOBN(0xc44ea599, 0xf98a759a), TOBN(0x55a0a7a2, 0xf7c23c1d),
++     TOBN(0xd5ffb6e6, 0x94c4f687), TOBN(0x3563cce2, 0x12848478),
++     TOBN(0x812b3517, 0xe7b1fbe1), TOBN(0x8a7dc979, 0x4f7338e0),
++     TOBN(0x211ecee9, 0x52d048db), TOBN(0x2eea4056, 0xc86ea3b8),
++     TOBN(0xd8cb68a7, 0xba772b34), TOBN(0xe16ed341, 0x5f4e2541),
++     TOBN(0x9b32f6a6, 0x0fec14db), TOBN(0xeee376f7, 0x391698be),
++     TOBN(0xe9a7aa17, 0x83674c02), TOBN(0x65832f97, 0x5843022a),
++     TOBN(0x29f3a8da, 0x5ba4990f), TOBN(0x79a59c3a, 0xfb8e3216),
++     TOBN(0x9cdc4d2e, 0xbd19bb16), TOBN(0xc6c7cfd0, 0xb3262d86),
++     TOBN(0xd4ce14d0, 0x969c0b47), TOBN(0x1fa352b7, 0x13e56128),
++     TOBN(0x383d55b8, 0x973db6d3), TOBN(0x71836850, 0xe8e5b7bf),
++     TOBN(0xc7714596, 0xe6bb571f), TOBN(0x259df31f, 0x2d5b2dd2),
++     TOBN(0x568f8925, 0x913cc16d), TOBN(0x18bc5b6d, 0xe1a26f5a),
++     TOBN(0xdfa413be, 0xf5f499ae), TOBN(0xf8835dec, 0xc3f0ae84),
++     TOBN(0xb6e60bd8, 0x65a40ab0), TOBN(0x65596439, 0x194b377e),
++     TOBN(0xbcd85625, 0x92084a69), TOBN(0x5ce433b9, 0x4f23ede0),
++     TOBN(0xe8e8f04f, 0x6ad65143), TOBN(0x11511827, 0xd6e14af6),
++     TOBN(0x3d390a10, 0x8295c0c7), TOBN(0x71e29ee4, 0x621eba16),
++     TOBN(0xa588fc09, 0x63717b46), TOBN(0x02be02fe, 0xe06ad4a2),
++     TOBN(0x931558c6, 0x04c22b22), TOBN(0xbb4d4bd6, 0x12f3c849),
++     TOBN(0x54a4f496, 0x20efd662), TOBN(0x92ba6d20, 0xc5952d14),
++     TOBN(0x2db8ea1e, 0xcc9784c2), TOBN(0x81cc10ca, 0x4b353644),
++     TOBN(0x40b570ad, 0x4b4d7f6c), TOBN(0x5c9f1d96, 0x84a1dcd2),
++     TOBN(0x01379f81, 0x3147e797), TOBN(0xe5c6097b, 0x2bd499f5),
++     TOBN(0x40dcafa6, 0x328e5e20), TOBN(0xf7b5244a, 0x54815550),
++     TOBN(0xb9a4f118, 0x47bfc978), TOBN(0x0ea0e79f, 0xd25825b1),
++     TOBN(0xa50f96eb, 0x646c7ecf), TOBN(0xeb811493, 0x446dea9d),
++     TOBN(0x2af04677, 0xdfabcf69), TOBN(0xbe3a068f, 0xc713f6e8),
++     TOBN(0x860d523d, 0x42e06189), TOBN(0xbf077941, 0x4e3aff13),
++     TOBN(0x0b616dca, 0xc1b20650), TOBN(0xe66dd6d1, 0x2131300d),
++     TOBN(0xd4a0fd67, 0xff99abde), TOBN(0xc9903550, 0xc7aac50d),
++     TOBN(0x022ecf8b, 0x7c46b2d7), TOBN(0x3333b1e8, 0x3abf92af),
++     TOBN(0x11cc113c, 0x6c491c14), TOBN(0x05976688, 0x80dd3f88),
++     TOBN(0xf5b4d9e7, 0x29d932ed), TOBN(0xe982aad8, 0xa2c38b6d),
++     TOBN(0x6f925347, 0x8be0dcf0), TOBN(0x700080ae, 0x65ca53f2),
++     TOBN(0xd8131156, 0x443ca77f), TOBN(0xe92d6942, 0xec51f984),
++     TOBN(0xd2a08af8, 0x85dfe9ae), TOBN(0xd825d9a5, 0x4d2a86ca),
++     TOBN(0x2c53988d, 0x39dff020), TOBN(0xf38b135a, 0x430cdc40),
++     TOBN(0x0c918ae0, 0x62a7150b), TOBN(0xf31fd8de, 0x0c340e9b),
++     TOBN(0xafa0e7ae, 0x4dbbf02e), TOBN(0x5847fb2a, 0x5eba6239),
++     TOBN(0x6b1647dc, 0xdccbac8b), TOBN(0xb642aa78, 0x06f485c8),
++     TOBN(0x873f3765, 0x7038ecdf), TOBN(0x2ce5e865, 0xfa49d3fe),
++     TOBN(0xea223788, 0xc98c4400), TOBN(0x8104a8cd, 0xf1fa5279),
++     TOBN(0xbcf7cc7a, 0x06becfd7), TOBN(0x49424316, 0xc8f974ae),
++     TOBN(0xc0da65e7, 0x84d6365d), TOBN(0xbcb7443f, 0x8f759fb8),
++     TOBN(0x35c712b1, 0x7ae81930), TOBN(0x80428dff, 0x4c6e08ab),
++     TOBN(0xf19dafef, 0xa4faf843), TOBN(0xced8538d, 0xffa9855f),
++     TOBN(0x20ac409c, 0xbe3ac7ce), TOBN(0x358c1fb6, 0x882da71e),
++     TOBN(0xafa9c0e5, 0xfd349961), TOBN(0x2b2cfa51, 0x8421c2fc),
++     TOBN(0x2a80db17, 0xf3a28d38), TOBN(0xa8aba539, 0x5d138e7e),
++     TOBN(0x52012d1d, 0x6e96eb8d), TOBN(0x65d8dea0, 0xcbaf9622),
++     TOBN(0x57735447, 0xb264f56c), TOBN(0xbeebef3f, 0x1b6c8da2),
++     TOBN(0xfc346d98, 0xce785254), TOBN(0xd50e8d72, 0xbb64a161),
++     TOBN(0xc03567c7, 0x49794add), TOBN(0x15a76065, 0x752c7ef6),
++     TOBN(0x59f3a222, 0x961f23d6), TOBN(0x378e4438, 0x73ecc0b0),
++     TOBN(0xc74be434, 0x5a82fde4), TOBN(0xae509af2, 0xd8b9cf34),
++     TOBN(0x4a61ee46, 0x577f44a1), TOBN(0xe09b748c, 0xb611deeb),
++     TOBN(0xc0481b2c, 0xf5f7b884), TOBN(0x35626678, 0x61acfa6b),
++     TOBN(0x37f4c518, 0xbf8d21e6), TOBN(0x22d96531, 0xb205a76d),
++     TOBN(0x37fb85e1, 0x954073c0), TOBN(0xbceafe4f, 0x65b3a567),
++     TOBN(0xefecdef7, 0xbe42a582), TOBN(0xd3fc6080, 0x65046be6),
++     TOBN(0xc9af13c8, 0x09e8dba9), TOBN(0x1e6c9847, 0x641491ff),
++     TOBN(0x3b574925, 0xd30c31f7), TOBN(0xb7eb72ba, 0xac2a2122),
++     TOBN(0x776a0dac, 0xef0859e7), TOBN(0x06fec314, 0x21900942),
++     TOBN(0x2464bc10, 0xf8c22049), TOBN(0x9bfbcce7, 0x875ebf69),
++     TOBN(0xd7a88e2a, 0x4336326b), TOBN(0xda05261c, 0x5bc2acfa),
++     TOBN(0xc29f5bdc, 0xeba7efc8), TOBN(0x471237ca, 0x25dbbf2e),
++     TOBN(0xa72773f2, 0x2975f127), TOBN(0xdc744e8e, 0x04d0b326),
++     TOBN(0x38a7ed16, 0xa56edb73), TOBN(0x64357e37, 0x2c007e70),
++     TOBN(0xa167d15b, 0x5080b400), TOBN(0x07b41164, 0x23de4be1),
++     TOBN(0xb2d91e32, 0x74c89883), TOBN(0x3c162821, 0x2882e7ed),
++     TOBN(0xad6b36ba, 0x7503e482), TOBN(0x48434e8e, 0x0ea34331),
++     TOBN(0x79f4f24f, 0x2c7ae0b9), TOBN(0xc46fbf81, 0x1939b44a),
++     TOBN(0x76fefae8, 0x56595eb1), TOBN(0x417b66ab, 0xcd5f29c7),
++     TOBN(0x5f2332b2, 0xc5ceec20), TOBN(0xd69661ff, 0xe1a1cae2),
++     TOBN(0x5ede7e52, 0x9b0286e6), TOBN(0x9d062529, 0xe276b993),
++     TOBN(0x324794b0, 0x7e50122b), TOBN(0xdd744f8b, 0x4af07ca5),
++     TOBN(0x30a12f08, 0xd63fc97b), TOBN(0x39650f1a, 0x76626d9d),
++     TOBN(0x101b47f7, 0x1fa38477), TOBN(0x3d815f19, 0xd4dc124f),
++     TOBN(0x1569ae95, 0xb26eb58a), TOBN(0xc3cde188, 0x95fb1887),
++     TOBN(0x54e9f37b, 0xf9539a48), TOBN(0xb0100e06, 0x7408c1a5),
++     TOBN(0x821d9811, 0xea580cbb), TOBN(0x8af52d35, 0x86e50c56),
++     TOBN(0xdfbd9d47, 0xdbbf698b), TOBN(0x2961a1ea, 0x03dc1c73),
++     TOBN(0x203d38f8, 0xe76a5df8), TOBN(0x08a53a68, 0x6def707a),
++     TOBN(0x26eefb48, 0x1bee45d4), TOBN(0xb3cee346, 0x3c688036),
++     TOBN(0x463c5315, 0xc42f2469), TOBN(0x19d84d2e, 0x81378162),
++     TOBN(0x22d7c3c5, 0x1c4d349f), TOBN(0x65965844, 0x163d59c5),
++     TOBN(0xcf198c56, 0xb8abceae), TOBN(0x6fb1fb1b, 0x628559d5),
++     TOBN(0x8bbffd06, 0x07bf8fe3), TOBN(0x46259c58, 0x3467734b),
++     TOBN(0xd8953cea, 0x35f7f0d3), TOBN(0x1f0bece2, 0xd65b0ff1),
++     TOBN(0xf7d5b4b3, 0xf3c72914), TOBN(0x29e8ea95, 0x3cb53389),
++     TOBN(0x4a365626, 0x836b6d46), TOBN(0xe849f910, 0xea174fde),
++     TOBN(0x7ec62fbb, 0xf4737f21), TOBN(0xd8dba5ab, 0x6209f5ac),
++     TOBN(0x24b5d7a9, 0xa5f9adbe), TOBN(0x707d28f7, 0xa61dc768),
++     TOBN(0x7711460b, 0xcaa999ea), TOBN(0xba7b174d, 0x1c92e4cc),
++     TOBN(0x3c4bab66, 0x18d4bf2d), TOBN(0xb8f0c980, 0xeb8bd279),
++     TOBN(0x024bea9a, 0x324b4737), TOBN(0xfba9e423, 0x32a83bca),
++     TOBN(0x6e635643, 0xa232dced), TOBN(0x99619367, 0x2571c8ba),
++     TOBN(0xe8c9f357, 0x54b7032b), TOBN(0xf936b3ba, 0x2442d54a),
++     TOBN(0x2263f0f0, 0x8290c65a), TOBN(0x48989780, 0xee2c7fdb),
++     TOBN(0xadc5d55a, 0x13d4f95e), TOBN(0x737cff85, 0xad9b8500),
++     TOBN(0x271c557b, 0x8a73f43d), TOBN(0xbed617a4, 0xe18bc476),
++     TOBN(0x66245401, 0x7dfd8ab2), TOBN(0xae7b89ae, 0x3a2870aa),
++     TOBN(0x1b555f53, 0x23a7e545), TOBN(0x6791e247, 0xbe057e4c),
++     TOBN(0x860136ad, 0x324fa34d), TOBN(0xea111447, 0x4cbeae28),
++     TOBN(0x023a4270, 0xbedd3299), TOBN(0x3d5c3a7f, 0xc1c35c34),
++     TOBN(0xb0f6db67, 0x8d0412d2), TOBN(0xd92625e2, 0xfcdc6b9a),
++     TOBN(0x92ae5ccc, 0x4e28a982), TOBN(0xea251c36, 0x47a3ce7e),
++     TOBN(0x9d658932, 0x790691bf), TOBN(0xed610589, 0x06b736ae),
++     TOBN(0x712c2f04, 0xc0d63b6e), TOBN(0x5cf06fd5, 0xc63d488f),
++     TOBN(0x97363fac, 0xd9588e41), TOBN(0x1f9bf762, 0x2b93257e),
++     TOBN(0xa9d1ffc4, 0x667acace), TOBN(0x1cf4a1aa, 0x0a061ecf),
++     TOBN(0x40e48a49, 0xdc1818d0), TOBN(0x0643ff39, 0xa3621ab0),
++     TOBN(0x5768640c, 0xe39ef639), TOBN(0x1fc099ea, 0x04d86854),
++     TOBN(0x9130b9c3, 0xeccd28fd), TOBN(0xd743cbd2, 0x7eec54ab),
++     TOBN(0x052b146f, 0xe5b475b6), TOBN(0x058d9a82, 0x900a7d1f),
++     TOBN(0x65e02292, 0x91262b72), TOBN(0x96f924f9, 0xbb0edf03),
++     TOBN(0x5cfa59c8, 0xfe206842), TOBN(0xf6037004, 0x5eafa720),
++     TOBN(0x5f30699e, 0x18d7dd96), TOBN(0x381e8782, 0xcbab2495),
++     TOBN(0x91669b46, 0xdd8be949), TOBN(0xb40606f5, 0x26aae8ef),
++     TOBN(0x2812b839, 0xfc6751a4), TOBN(0x16196214, 0xfba800ef),
++     TOBN(0x4398d5ca, 0x4c1a2875), TOBN(0x720c00ee, 0x653d8349),
++     TOBN(0xc2699eb0, 0xd820007c), TOBN(0x880ee660, 0xa39b5825),
++     TOBN(0x70694694, 0x471f6984), TOBN(0xf7d16ea8, 0xe3dda99a),
++     TOBN(0x28d675b2, 0xc0519a23), TOBN(0x9ebf94fe, 0x4f6952e3),
++     TOBN(0xf28bb767, 0xa2294a8a), TOBN(0x85512b4d, 0xfe0af3f5),
++     TOBN(0x18958ba8, 0x99b16a0d), TOBN(0x95c2430c, 0xba7548a7),
++     TOBN(0xb30d1b10, 0xa16be615), TOBN(0xe3ebbb97, 0x85bfb74c),
++     TOBN(0xa3273cfe, 0x18549fdb), TOBN(0xf6e200bf, 0x4fcdb792),
++     TOBN(0x54a76e18, 0x83aba56c), TOBN(0x73ec66f6, 0x89ef6aa2),
++     TOBN(0x8d17add7, 0xd1b9a305), TOBN(0xa959c5b9, 0xb7ae1b9d),
++     TOBN(0x88643522, 0x6bcc094a), TOBN(0xcc5616c4, 0xd7d429b9),
++     TOBN(0xa6dada01, 0xe6a33f7c), TOBN(0xc6217a07, 0x9d4e70ad),
++     TOBN(0xd619a818, 0x09c15b7c), TOBN(0xea06b329, 0x0e80c854),
++     TOBN(0x174811ce, 0xa5f5e7b9), TOBN(0x66dfc310, 0x787c65f4),
++     TOBN(0x4ea7bd69, 0x3316ab54), TOBN(0xc12c4acb, 0x1dcc0f70),
++     TOBN(0xe4308d1a, 0x1e407dd9), TOBN(0xe8a3587c, 0x91afa997),
++     TOBN(0xea296c12, 0xab77b7a5), TOBN(0xb5ad49e4, 0x673c0d52),
++     TOBN(0x40f9b2b2, 0x7006085a), TOBN(0xa88ff340, 0x87bf6ec2),
++     TOBN(0x978603b1, 0x4e3066a6), TOBN(0xb3f99fc2, 0xb5e486e2),
++     TOBN(0x07b53f5e, 0xb2e63645), TOBN(0xbe57e547, 0x84c84232),
++     TOBN(0xd779c216, 0x7214d5cf), TOBN(0x617969cd, 0x029a3aca),
++     TOBN(0xd17668cd, 0x8a7017a0), TOBN(0x77b4d19a, 0xbe9b7ee8),
++     TOBN(0x58fd0e93, 0x9c161776), TOBN(0xa8c4f4ef, 0xd5968a72),
++     TOBN(0x296071cc, 0x67b3de77), TOBN(0xae3c0b8e, 0x634f7905),
++     TOBN(0x67e440c2, 0x8a7100c9), TOBN(0xbb8c3c1b, 0xeb4b9b42),
++     TOBN(0x6d71e8ea, 0xc51b3583), TOBN(0x7591f5af, 0x9525e642),
++     TOBN(0xf73a2f7b, 0x13f509f3), TOBN(0x618487aa, 0x5619ac9b),
++     TOBN(0x3a72e5f7, 0x9d61718a), TOBN(0x00413bcc, 0x7592d28c),
++     TOBN(0x7d9b11d3, 0x963c35cf), TOBN(0x77623bcf, 0xb90a46ed),
++     TOBN(0xdeef273b, 0xdcdd2a50), TOBN(0x4a741f9b, 0x0601846e),
++     TOBN(0x33b89e51, 0x0ec6e929), TOBN(0xcb02319f, 0x8b7f22cd),
++     TOBN(0xbbe1500d, 0x084bae24), TOBN(0x2f0ae8d7, 0x343d2693),
++     TOBN(0xacffb5f2, 0x7cdef811), TOBN(0xaa0c030a, 0x263fb94f),
++     TOBN(0x6eef0d61, 0xa0f442de), TOBN(0xf92e1817, 0x27b139d3),
++     TOBN(0x1ae6deb7, 0x0ad8bc28), TOBN(0xa89e38dc, 0xc0514130),
++     TOBN(0x81eeb865, 0xd2fdca23), TOBN(0x5a15ee08, 0xcc8ef895),
++     TOBN(0x768fa10a, 0x01905614), TOBN(0xeff5b8ef, 0x880ee19b),
++     TOBN(0xf0c0cabb, 0xcb1c8a0e), TOBN(0x2e1ee9cd, 0xb8c838f9),
++     TOBN(0x0587d8b8, 0x8a4a14c0), TOBN(0xf6f27896, 0x2ff698e5),
++     TOBN(0xed38ef1c, 0x89ee6256), TOBN(0xf44ee1fe, 0x6b353b45),
++     TOBN(0x9115c0c7, 0x70e903b3), TOBN(0xc78ec0a1, 0x818f31df),
++     TOBN(0x6c003324, 0xb7dccbc6), TOBN(0xd96dd1f3, 0x163bbc25),
++     TOBN(0x33aa82dd, 0x5cedd805), TOBN(0x123aae4f, 0x7f7eb2f1),
++     TOBN(0x1723fcf5, 0xa26262cd), TOBN(0x1f7f4d5d, 0x0060ebd5),
++     TOBN(0xf19c5c01, 0xb2eaa3af), TOBN(0x2ccb9b14, 0x9790accf),
++     TOBN(0x1f9c1cad, 0x52324aa6), TOBN(0x63200526, 0x7247df54),
++     TOBN(0x5732fe42, 0xbac96f82), TOBN(0x52fe771f, 0x01a1c384),
++     TOBN(0x546ca13d, 0xb1001684), TOBN(0xb56b4eee, 0xa1709f75),
++     TOBN(0x266545a9, 0xd5db8672), TOBN(0xed971c90, 0x1e8f3cfb),
++     TOBN(0x4e7d8691, 0xe3a07b29), TOBN(0x7570d9ec, 0xe4b696b9),
++     TOBN(0xdc5fa067, 0x7bc7e9ae), TOBN(0x68b44caf, 0xc82c4844),
++     TOBN(0x519d34b3, 0xbf44da80), TOBN(0x283834f9, 0x5ab32e66),
++     TOBN(0x6e608797, 0x6278a000), TOBN(0x1e62960e, 0x627312f6),
++     TOBN(0x9b87b27b, 0xe6901c55), TOBN(0x80e78538, 0x24fdbc1f),
++     TOBN(0xbbbc0951, 0x2facc27d), TOBN(0x06394239, 0xac143b5a),
++     TOBN(0x35bb4a40, 0x376c1944), TOBN(0x7cb62694, 0x63da1511),
++     TOBN(0xafd29161, 0xb7148a3b), TOBN(0xa6f9d9ed, 0x4e2ea2ee),
++     TOBN(0x15dc2ca2, 0x880dd212), TOBN(0x903c3813, 0xa61139a9),
++     TOBN(0x2aa7b46d, 0x6c0f8785), TOBN(0x36ce2871, 0x901c60ff),
++     TOBN(0xc683b028, 0xe10d9c12), TOBN(0x7573baa2, 0x032f33d3),
++     TOBN(0x87a9b1f6, 0x67a31b58), TOBN(0xfd3ed11a, 0xf4ffae12),
++     TOBN(0x83dcaa9a, 0x0cb2748e), TOBN(0x8239f018, 0x5d6fdf16),
++     TOBN(0xba67b49c, 0x72753941), TOBN(0x2beec455, 0xc321cb36),
++     TOBN(0x88015606, 0x3f8b84ce), TOBN(0x76417083, 0x8d38c86f),
++     TOBN(0x054f1ca7, 0x598953dd), TOBN(0xc939e110, 0x4e8e7429),
++     TOBN(0x9b1ac2b3, 0x5a914f2f), TOBN(0x39e35ed3, 0xe74b8f9c),
++     TOBN(0xd0debdb2, 0x781b2fb0), TOBN(0x1585638f, 0x2d997ba2),
++     TOBN(0x9c4b646e, 0x9e2fce99), TOBN(0x68a21081, 0x1e80857f),
++     TOBN(0x06d54e44, 0x3643b52a), TOBN(0xde8d6d63, 0x0d8eb843),
++     TOBN(0x70321563, 0x42146a0a), TOBN(0x8ba826f2, 0x5eaa3622),
++     TOBN(0x227a58bd, 0x86138787), TOBN(0x43b6c03c, 0x10281d37),
++     TOBN(0x6326afbb, 0xb54dde39), TOBN(0x744e5e8a, 0xdb6f2d5f),
++     TOBN(0x48b2a99a, 0xcff158e1), TOBN(0xa93c8fa0, 0xef87918f),
++     TOBN(0x2182f956, 0xde058c5c), TOBN(0x216235d2, 0x936f9e7a),
++     TOBN(0xace0c0db, 0xd2e31e67), TOBN(0xc96449bf, 0xf23ac3e7),
++     TOBN(0x7e9a2874, 0x170693bd), TOBN(0xa28e14fd, 0xa45e6335),
++     TOBN(0x5757f6b3, 0x56427344), TOBN(0x822e4556, 0xacf8edf9),
++     TOBN(0x2b7a6ee2, 0xe6a285cd), TOBN(0x5866f211, 0xa9df3af0),
++     TOBN(0x40dde2dd, 0xf845b844), TOBN(0x986c3726, 0x110e5e49),
++     TOBN(0x73680c2a, 0xf7172277), TOBN(0x57b94f0f, 0x0cccb244),
++     TOBN(0xbdff7267, 0x2d438ca7), TOBN(0xbad1ce11, 0xcf4663fd),
++     TOBN(0x9813ed9d, 0xd8f71cae), TOBN(0xf43272a6, 0x961fdaa6),
++     TOBN(0xbeff0119, 0xbd6d1637), TOBN(0xfebc4f91, 0x30361978),
++     TOBN(0x02b37a95, 0x2f41deff), TOBN(0x0e44a59a, 0xe63b89b7),
++     TOBN(0x673257dc, 0x143ff951), TOBN(0x19c02205, 0xd752baf4),
++     TOBN(0x46c23069, 0xc4b7d692), TOBN(0x2e6392c3, 0xfd1502ac),
++     TOBN(0x6057b1a2, 0x1b220846), TOBN(0xe51ff946, 0x0c1b5b63),}
++    ,
++    {TOBN(0x6e85cb51, 0x566c5c43), TOBN(0xcff9c919, 0x3597f046),
++     TOBN(0x9354e90c, 0x4994d94a), TOBN(0xe0a39332, 0x2147927d),
++     TOBN(0x8427fac1, 0x0dc1eb2b), TOBN(0x88cfd8c2, 0x2ff319fa),
++     TOBN(0xe2d4e684, 0x01965274), TOBN(0xfa2e067d, 0x67aaa746),
++     TOBN(0xb6d92a7f, 0x3e5f9f11), TOBN(0x9afe153a, 0xd6cb3b8e),
++     TOBN(0x4d1a6dd7, 0xddf800bd), TOBN(0xf6c13cc0, 0xcaf17e19),
++     TOBN(0x15f6c58e, 0x325fc3ee), TOBN(0x71095400, 0xa31dc3b2),
++     TOBN(0x168e7c07, 0xafa3d3e7), TOBN(0x3f8417a1, 0x94c7ae2d),
++     TOBN(0xec234772, 0x813b230d), TOBN(0x634d0f5f, 0x17344427),
++     TOBN(0x11548ab1, 0xd77fc56a), TOBN(0x7fab1750, 0xce06af77),
++     TOBN(0xb62c10a7, 0x4f7c4f83), TOBN(0xa7d2edc4, 0x220a67d9),
++     TOBN(0x1c404170, 0x921209a0), TOBN(0x0b9815a0, 0xface59f0),
++     TOBN(0x2842589b, 0x319540c3), TOBN(0x18490f59, 0xa283d6f8),
++     TOBN(0xa2731f84, 0xdaae9fcb), TOBN(0x3db6d960, 0xc3683ba0),
++     TOBN(0xc85c63bb, 0x14611069), TOBN(0xb19436af, 0x0788bf05),
++     TOBN(0x905459df, 0x347460d2), TOBN(0x73f6e094, 0xe11a7db1),
++     TOBN(0xdc7f938e, 0xb6357f37), TOBN(0xc5d00f79, 0x2bd8aa62),
++     TOBN(0xc878dcb9, 0x2ca979fc), TOBN(0x37e83ed9, 0xeb023a99),
++     TOBN(0x6b23e273, 0x1560bf3d), TOBN(0x1086e459, 0x1d0fae61),
++     TOBN(0x78248316, 0x9a9414bd), TOBN(0x1b956bc0, 0xf0ea9ea1),
++     TOBN(0x7b85bb91, 0xc31b9c38), TOBN(0x0c5aa90b, 0x48ef57b5),
++     TOBN(0xdedeb169, 0xaf3bab6f), TOBN(0xe610ad73, 0x2d373685),
++     TOBN(0xf13870df, 0x02ba8e15), TOBN(0x0337edb6, 0x8ca7f771),
++     TOBN(0xe4acf747, 0xb62c036c), TOBN(0xd921d576, 0xb6b94e81),
++     TOBN(0xdbc86439, 0x2c422f7a), TOBN(0xfb635362, 0xed348898),
++     TOBN(0x83084668, 0xc45bfcd1), TOBN(0xc357c9e3, 0x2b315e11),
++     TOBN(0xb173b540, 0x5b2e5b8c), TOBN(0x7e946931, 0xe102b9a4),
++     TOBN(0x17c890eb, 0x7b0fb199), TOBN(0xec225a83, 0xd61b662b),
++     TOBN(0xf306a3c8, 0xee3c76cb), TOBN(0x3cf11623, 0xd32a1f6e),
++     TOBN(0xe6d5ab64, 0x6863e956), TOBN(0x3b8a4cbe, 0x5c005c26),
++     TOBN(0xdcd529a5, 0x9ce6bb27), TOBN(0xc4afaa52, 0x04d4b16f),
++     TOBN(0xb0624a26, 0x7923798d), TOBN(0x85e56df6, 0x6b307fab),
++     TOBN(0x0281893c, 0x2bf29698), TOBN(0x91fc19a4, 0xd7ce7603),
++     TOBN(0x75a5dca3, 0xad9a558f), TOBN(0x40ceb3fa, 0x4d50bf77),
++     TOBN(0x1baf6060, 0xbc9ba369), TOBN(0x927e1037, 0x597888c2),
++     TOBN(0xd936bf19, 0x86a34c07), TOBN(0xd4cf10c1, 0xc34ae980),
++     TOBN(0x3a3e5334, 0x859dd614), TOBN(0x9c475b5b, 0x18d0c8ee),
++     TOBN(0x63080d1f, 0x07cd51d5), TOBN(0xc9c0d0a6, 0xb88b4326),
++     TOBN(0x1ac98691, 0xc234296f), TOBN(0x2a0a83a4, 0x94887fb6),
++     TOBN(0x56511427, 0x0cea9cf2), TOBN(0x5230a6e8, 0xa24802f5),
++     TOBN(0xf7a2bf0f, 0x72e3d5c1), TOBN(0x37717446, 0x4f21439e),
++     TOBN(0xfedcbf25, 0x9ce30334), TOBN(0xe0030a78, 0x7ce202f9),
++     TOBN(0x6f2d9ebf, 0x1202e9ca), TOBN(0xe79dde6c, 0x75e6e591),
++     TOBN(0xf52072af, 0xf1dac4f8), TOBN(0x6c8d087e, 0xbb9b404d),
++     TOBN(0xad0fc73d, 0xbce913af), TOBN(0x909e587b, 0x458a07cb),
++     TOBN(0x1300da84, 0xd4f00c8a), TOBN(0x425cd048, 0xb54466ac),
++     TOBN(0xb59cb9be, 0x90e9d8bf), TOBN(0x991616db, 0x3e431b0e),
++     TOBN(0xd3aa117a, 0x531aecff), TOBN(0x91af92d3, 0x59f4dc3b),
++     TOBN(0x9b1ec292, 0xe93fda29), TOBN(0x76bb6c17, 0xe97d91bc),
++     TOBN(0x7509d95f, 0xaface1e6), TOBN(0x3653fe47, 0xbe855ae3),
++     TOBN(0x73180b28, 0x0f680e75), TOBN(0x75eefd1b, 0xeeb6c26c),
++     TOBN(0xa4cdf29f, 0xb66d4236), TOBN(0x2d70a997, 0x6b5821d8),
++     TOBN(0x7a3ee207, 0x20445c36), TOBN(0x71d1ac82, 0x59877174),
++     TOBN(0x0fc539f7, 0x949f73e9), TOBN(0xd05cf3d7, 0x982e3081),
++     TOBN(0x8758e20b, 0x7b1c7129), TOBN(0xffadcc20, 0x569e61f2),
++     TOBN(0xb05d3a2f, 0x59544c2d), TOBN(0xbe16f5c1, 0x9fff5e53),
++     TOBN(0x73cf65b8, 0xaad58135), TOBN(0x622c2119, 0x037aa5be),
++     TOBN(0x79373b3f, 0x646fd6a0), TOBN(0x0e029db5, 0x0d3978cf),
++     TOBN(0x8bdfc437, 0x94fba037), TOBN(0xaefbd687, 0x620797a6),
++     TOBN(0x3fa5382b, 0xbd30d38e), TOBN(0x7627cfbf, 0x585d7464),
++     TOBN(0xb2330fef, 0x4e4ca463), TOBN(0xbcef7287, 0x3566cc63),
++     TOBN(0xd161d2ca, 0xcf780900), TOBN(0x135dc539, 0x5b54827d),
++     TOBN(0x638f052e, 0x27bf1bc6), TOBN(0x10a224f0, 0x07dfa06c),
++     TOBN(0xe973586d, 0x6d3321da), TOBN(0x8b0c5738, 0x26152c8f),
++     TOBN(0x07ef4f2a, 0x34606074), TOBN(0x80fe7fe8, 0xa0f7047a),
++     TOBN(0x3d1a8152, 0xe1a0e306), TOBN(0x32cf43d8, 0x88da5222),
++     TOBN(0xbf89a95f, 0x5f02ffe6), TOBN(0x3d9eb9a4, 0x806ad3ea),
++     TOBN(0x012c17bb, 0x79c8e55e), TOBN(0xfdcd1a74, 0x99c81dac),
++     TOBN(0x7043178b, 0xb9556098), TOBN(0x4090a1df, 0x801c3886),
++     TOBN(0x759800ff, 0x9b67b912), TOBN(0x3e5c0304, 0x232620c8),
++     TOBN(0x4b9d3c4b, 0x70dceeca), TOBN(0xbb2d3c15, 0x181f648e),
++     TOBN(0xf981d837, 0x6e33345c), TOBN(0xb626289b, 0x0cf2297a),
++     TOBN(0x766ac659, 0x8baebdcf), TOBN(0x1a28ae09, 0x75df01e5),
++     TOBN(0xb71283da, 0x375876d8), TOBN(0x4865a96d, 0x607b9800),
++     TOBN(0x25dd1bcd, 0x237936b2), TOBN(0x332f4f4b, 0x60417494),
++     TOBN(0xd0923d68, 0x370a2147), TOBN(0x497f5dfb, 0xdc842203),
++     TOBN(0x9dc74cbd, 0x32be5e0f), TOBN(0x7475bcb7, 0x17a01375),
++     TOBN(0x438477c9, 0x50d872b1), TOBN(0xcec67879, 0xffe1d63d),
++     TOBN(0x9b006014, 0xd8578c70), TOBN(0xc9ad99a8, 0x78bb6b8b),
++     TOBN(0x6799008e, 0x11fb3806), TOBN(0xcfe81435, 0xcd44cab3),
++     TOBN(0xa2ee1582, 0x2f4fb344), TOBN(0xb8823450, 0x483fa6eb),
++     TOBN(0x622d323d, 0x652c7749), TOBN(0xd8474a98, 0xbeb0a15b),
++     TOBN(0xe43c154d, 0x5d1c00d0), TOBN(0x7fd581d9, 0x0e3e7aac),
++     TOBN(0x2b44c619, 0x2525ddf8), TOBN(0x67a033eb, 0xb8ae9739),
++     TOBN(0x113ffec1, 0x9ef2d2e4), TOBN(0x1bf6767e, 0xd5a0ea7f),
++     TOBN(0x57fff75e, 0x03714c0a), TOBN(0xa23c422e, 0x0a23e9ee),
++     TOBN(0xdd5f6b2d, 0x540f83af), TOBN(0xc2c2c27e, 0x55ea46a7),
++     TOBN(0xeb6b4246, 0x672a1208), TOBN(0xd13599f7, 0xae634f7a),
++     TOBN(0xcf914b5c, 0xd7b32c6e), TOBN(0x61a5a640, 0xeaf61814),
++     TOBN(0x8dc3df8b, 0x208a1bbb), TOBN(0xef627fd6, 0xb6d79aa5),
++     TOBN(0x44232ffc, 0xc4c86bc8), TOBN(0xe6f9231b, 0x061539fe),
++     TOBN(0x1d04f25a, 0x958b9533), TOBN(0x180cf934, 0x49e8c885),
++     TOBN(0x89689595, 0x9884aaf7), TOBN(0xb1959be3, 0x07b348a6),
++     TOBN(0x96250e57, 0x3c147c87), TOBN(0xae0efb3a, 0xdd0c61f8),
++     TOBN(0xed00745e, 0xca8c325e), TOBN(0x3c911696, 0xecff3f70),
++     TOBN(0x73acbc65, 0x319ad41d), TOBN(0x7b01a020, 0xf0b1c7ef),
++     TOBN(0xea32b293, 0x63a1483f), TOBN(0x89eabe71, 0x7a248f96),
++     TOBN(0x9c6231d3, 0x343157e5), TOBN(0x93a375e5, 0xdf3c546d),
++     TOBN(0xe76e9343, 0x6a2afe69), TOBN(0xc4f89100, 0xe166c88e),
++     TOBN(0x248efd0d, 0x4f872093), TOBN(0xae0eb3ea, 0x8fe0ea61),
++     TOBN(0xaf89790d, 0x9d79046e), TOBN(0x4d650f2d, 0x6cee0976),
++     TOBN(0xa3935d9a, 0x43071eca), TOBN(0x66fcd2c9, 0x283b0bfe),
++     TOBN(0x0e665eb5, 0x696605f1), TOBN(0xe77e5d07, 0xa54cd38d),
++     TOBN(0x90ee050a, 0x43d950cf), TOBN(0x86ddebda, 0xd32e69b5),
++     TOBN(0x6ad94a3d, 0xfddf7415), TOBN(0xf7fa1309, 0x3f6e8d5a),
++     TOBN(0xc4831d1d, 0xe9957f75), TOBN(0x7de28501, 0xd5817447),
++     TOBN(0x6f1d7078, 0x9e2aeb6b), TOBN(0xba2b9ff4, 0xf67a53c2),
++     TOBN(0x36963767, 0xdf9defc3), TOBN(0x479deed3, 0x0d38022c),
++     TOBN(0xd2edb89b, 0x3a8631e8), TOBN(0x8de855de, 0x7a213746),
++     TOBN(0xb2056cb7, 0xb00c5f11), TOBN(0xdeaefbd0, 0x2c9b85e4),
++     TOBN(0x03f39a8d, 0xd150892d), TOBN(0x37b84686, 0x218b7985),
++     TOBN(0x36296dd8, 0xb7375f1a), TOBN(0x472cd4b1, 0xb78e898e),
++     TOBN(0x15dff651, 0xe9f05de9), TOBN(0xd4045069, 0x2ce98ba9),
++     TOBN(0x8466a7ae, 0x9b38024c), TOBN(0xb910e700, 0xe5a6b5ef),
++     TOBN(0xae1c56ea, 0xb3aa8f0d), TOBN(0xbab2a507, 0x7eee74a6),
++     TOBN(0x0dca11e2, 0x4b4c4620), TOBN(0xfd896e2e, 0x4c47d1f4),
++     TOBN(0xeb45ae53, 0x308fbd93), TOBN(0x46cd5a2e, 0x02c36fda),
++     TOBN(0x6a3d4e90, 0xbaa48385), TOBN(0xdd55e62e, 0x9dbe9960),
++     TOBN(0xa1406aa0, 0x2a81ede7), TOBN(0x6860dd14, 0xf9274ea7),
++     TOBN(0xcfdcb0c2, 0x80414f86), TOBN(0xff410b10, 0x22f94327),
++     TOBN(0x5a33cc38, 0x49ad467b), TOBN(0xefb48b6c, 0x0a7335f1),
++     TOBN(0x14fb54a4, 0xb153a360), TOBN(0x604aa9d2, 0xb52469cc),
++     TOBN(0x5e9dc486, 0x754e48e9), TOBN(0x693cb455, 0x37471e8e),
++     TOBN(0xfb2fd7cd, 0x8d3b37b6), TOBN(0x63345e16, 0xcf09ff07),
++     TOBN(0x9910ba6b, 0x23a5d896), TOBN(0x1fe19e35, 0x7fe4364e),
++     TOBN(0x6e1da8c3, 0x9a33c677), TOBN(0x15b4488b, 0x29fd9fd0),
++     TOBN(0x1f439254, 0x1a1f22bf), TOBN(0x920a8a70, 0xab8163e8),
++     TOBN(0x3fd1b249, 0x07e5658e), TOBN(0xf2c4f79c, 0xb6ec839b),
++     TOBN(0x1abbc3d0, 0x4aa38d1b), TOBN(0x3b0db35c, 0xb5d9510e),
++     TOBN(0x1754ac78, 0x3e60dec0), TOBN(0x53272fd7, 0xea099b33),
++     TOBN(0x5fb0494f, 0x07a8e107), TOBN(0x4a89e137, 0x6a8191fa),
++     TOBN(0xa113b7f6, 0x3c4ad544), TOBN(0x88a2e909, 0x6cb9897b),
++     TOBN(0x17d55de3, 0xb44a3f84), TOBN(0xacb2f344, 0x17c6c690),
++     TOBN(0x32088168, 0x10232390), TOBN(0xf2e8a61f, 0x6c733bf7),
++     TOBN(0xa774aab6, 0x9c2d7652), TOBN(0xfb5307e3, 0xed95c5bc),
++     TOBN(0xa05c73c2, 0x4981f110), TOBN(0x1baae31c, 0xa39458c9),
++     TOBN(0x1def185b, 0xcbea62e7), TOBN(0xe8ac9eae, 0xeaf63059),
++     TOBN(0x098a8cfd, 0x9921851c), TOBN(0xd959c3f1, 0x3abe2f5b),
++     TOBN(0xa4f19525, 0x20e40ae5), TOBN(0x320789e3, 0x07a24aa1),
++     TOBN(0x259e6927, 0x7392b2bc), TOBN(0x58f6c667, 0x1918668b),
++     TOBN(0xce1db2bb, 0xc55d2d8b), TOBN(0x41d58bb7, 0xf4f6ca56),
++     TOBN(0x7650b680, 0x8f877614), TOBN(0x905e16ba, 0xf4c349ed),
++     TOBN(0xed415140, 0xf661acac), TOBN(0x3b8784f0, 0xcb2270af),
++     TOBN(0x3bc280ac, 0x8a402cba), TOBN(0xd53f7146, 0x0937921a),
++     TOBN(0xc03c8ee5, 0xe5681e83), TOBN(0x62126105, 0xf6ac9e4a),
++     TOBN(0x9503a53f, 0x936b1a38), TOBN(0x3d45e2d4, 0x782fecbd),
++     TOBN(0x69a5c439, 0x76e8ae98), TOBN(0xb53b2eeb, 0xbfb4b00e),
++     TOBN(0xf1674712, 0x72386c89), TOBN(0x30ca34a2, 0x4268bce4),
++     TOBN(0x7f1ed86c, 0x78341730), TOBN(0x8ef5beb8, 0xb525e248),
++     TOBN(0xbbc489fd, 0xb74fbf38), TOBN(0x38a92a0e, 0x91a0b382),
++     TOBN(0x7a77ba3f, 0x22433ccf), TOBN(0xde8362d6, 0xa29f05a9),
++     TOBN(0x7f6a30ea, 0x61189afc), TOBN(0x693b5505, 0x59ef114f),
++     TOBN(0x50266bc0, 0xcd1797a1), TOBN(0xea17b47e, 0xf4b7af2d),
++     TOBN(0xd6c4025c, 0x3df9483e), TOBN(0x8cbb9d9f, 0xa37b18c9),
++     TOBN(0x91cbfd9c, 0x4d8424cf), TOBN(0xdb7048f1, 0xab1c3506),
++     TOBN(0x9eaf641f, 0x028206a3), TOBN(0xf986f3f9, 0x25bdf6ce),
++     TOBN(0x262143b5, 0x224c08dc), TOBN(0x2bbb09b4, 0x81b50c91),
++     TOBN(0xc16ed709, 0xaca8c84f), TOBN(0xa6210d9d, 0xb2850ca8),
++     TOBN(0x6d8df67a, 0x09cb54d6), TOBN(0x91eef6e0, 0x500919a4),
++     TOBN(0x90f61381, 0x0f132857), TOBN(0x9acede47, 0xf8d5028b),
++     TOBN(0x844d1b71, 0x90b771c3), TOBN(0x563b71e4, 0xba6426be),
++     TOBN(0x2efa2e83, 0xbdb802ff), TOBN(0x3410cbab, 0xab5b4a41),
++     TOBN(0x555b2d26, 0x30da84dd), TOBN(0xd0711ae9, 0xee1cc29a),
++     TOBN(0xcf3e8c60, 0x2f547792), TOBN(0x03d7d5de, 0xdc678b35),
++     TOBN(0x071a2fa8, 0xced806b8), TOBN(0x222e6134, 0x697f1478),
++     TOBN(0xdc16fd5d, 0xabfcdbbf), TOBN(0x44912ebf, 0x121b53b8),
++     TOBN(0xac943674, 0x2496c27c), TOBN(0x8ea3176c, 0x1ffc26b0),
++     TOBN(0xb6e224ac, 0x13debf2c), TOBN(0x524cc235, 0xf372a832),
++     TOBN(0xd706e1d8, 0x9f6f1b18), TOBN(0x2552f005, 0x44cce35b),
++     TOBN(0x8c8326c2, 0xa88e31fc), TOBN(0xb5468b2c, 0xf9552047),
++     TOBN(0xce683e88, 0x3ff90f2b), TOBN(0x77947bdf, 0x2f0a5423),
++     TOBN(0xd0a1b28b, 0xed56e328), TOBN(0xaee35253, 0xc20134ac),
++     TOBN(0x7e98367d, 0x3567962f), TOBN(0x379ed61f, 0x8188bffb),
++     TOBN(0x73bba348, 0xfaf130a1), TOBN(0x6c1f75e1, 0x904ed734),
++     TOBN(0x18956642, 0x3b4a79fc), TOBN(0xf20bc83d, 0x54ef4493),
++     TOBN(0x836d425d, 0x9111eca1), TOBN(0xe5b5c318, 0x009a8dcf),
++     TOBN(0x3360b25d, 0x13221bc5), TOBN(0x707baad2, 0x6b3eeaf7),
++     TOBN(0xd7279ed8, 0x743a95a1), TOBN(0x7450a875, 0x969e809f),
++     TOBN(0x32b6bd53, 0xe5d0338f), TOBN(0x1e77f7af, 0x2b883bbc),
++     TOBN(0x90da12cc, 0x1063ecd0), TOBN(0xe2697b58, 0xc315be47),
++     TOBN(0x2771a5bd, 0xda85d534), TOBN(0x53e78c1f, 0xff980eea),
++     TOBN(0xadf1cf84, 0x900385e7), TOBN(0x7d3b14f6, 0xc9387b62),
++     TOBN(0x170e74b0, 0xcb8f2bd2), TOBN(0x2d50b486, 0x827fa993),
++     TOBN(0xcdbe8c9a, 0xf6f32bab), TOBN(0x55e906b0, 0xc3b93ab8),
++     TOBN(0x747f22fc, 0x8fe280d1), TOBN(0xcd8e0de5, 0xb2e114ab),
++     TOBN(0x5ab7dbeb, 0xe10b68b0), TOBN(0x9dc63a9c, 0xa480d4b2),
++     TOBN(0x78d4bc3b, 0x4be1495f), TOBN(0x25eb3db8, 0x9359122d),
++     TOBN(0x3f8ac05b, 0x0809cbdc), TOBN(0xbf4187bb, 0xd37c702f),
++     TOBN(0x84cea069, 0x1416a6a5), TOBN(0x8f860c79, 0x43ef881c),
++     TOBN(0x41311f8a, 0x38038a5d), TOBN(0xe78c2ec0, 0xfc612067),
++     TOBN(0x494d2e81, 0x5ad73581), TOBN(0xb4cc9e00, 0x59604097),
++     TOBN(0xff558aec, 0xf3612cba), TOBN(0x35beef7a, 0x9e36c39e),
++     TOBN(0x1845c7cf, 0xdbcf41b9), TOBN(0x5703662a, 0xaea997c0),
++     TOBN(0x8b925afe, 0xe402f6d8), TOBN(0xd0a1b1ae, 0x4dd72162),
++     TOBN(0x9f47b375, 0x03c41c4b), TOBN(0xa023829b, 0x0391d042),
++     TOBN(0x5f5045c3, 0x503b8b0a), TOBN(0x123c2688, 0x98c010e5),
++     TOBN(0x324ec0cc, 0x36ba06ee), TOBN(0xface3115, 0x3dd2cc0c),
++     TOBN(0xb364f3be, 0xf333e91f), TOBN(0xef8aff73, 0x28e832b0),
++     TOBN(0x1e9bad04, 0x2d05841b), TOBN(0x42f0e3df, 0x356a21e2),
++     TOBN(0xa3270bcb, 0x4add627e), TOBN(0xb09a8158, 0xd322e711),
++     TOBN(0x86e326a1, 0x0fee104a), TOBN(0xad7788f8, 0x3703f65d),
++     TOBN(0x7e765430, 0x47bc4833), TOBN(0x6cee582b, 0x2b9b893a),
++     TOBN(0x9cd2a167, 0xe8f55a7b), TOBN(0xefbee3c6, 0xd9e4190d),
++     TOBN(0x33ee7185, 0xd40c2e9d), TOBN(0x844cc9c5, 0xa380b548),
++     TOBN(0x323f8ecd, 0x66926e04), TOBN(0x0001e38f, 0x8110c1ba),
++     TOBN(0x8dbcac12, 0xfc6a7f07), TOBN(0xd65e1d58, 0x0cec0827),
++     TOBN(0xd2cd4141, 0xbe76ca2d), TOBN(0x7895cf5c, 0xe892f33a),
++     TOBN(0x956d230d, 0x367139d2), TOBN(0xa91abd3e, 0xd012c4c1),
++     TOBN(0x34fa4883, 0x87eb36bf), TOBN(0xc5f07102, 0x914b8fb4),
++     TOBN(0x90f0e579, 0xadb9c95f), TOBN(0xfe6ea8cb, 0x28888195),
++     TOBN(0x7b9b5065, 0xedfa9284), TOBN(0x6c510bd2, 0x2b8c8d65),
++     TOBN(0xd7b8ebef, 0xcbe8aafd), TOBN(0xedb3af98, 0x96b1da07),
++     TOBN(0x28ff779d, 0x6295d426), TOBN(0x0c4f6ac7, 0x3fa3ad7b),
++     TOBN(0xec44d054, 0x8b8e2604), TOBN(0x9b32a66d, 0x8b0050e1),
++     TOBN(0x1f943366, 0xf0476ce2), TOBN(0x7554d953, 0xa602c7b4),
++     TOBN(0xbe35aca6, 0x524f2809), TOBN(0xb6881229, 0xfd4edbea),
++     TOBN(0xe8cd0c8f, 0x508efb63), TOBN(0x9eb5b5c8, 0x6abcefc7),
++     TOBN(0xf5621f5f, 0xb441ab4f), TOBN(0x79e6c046, 0xb76a2b22),
++     TOBN(0x74a4792c, 0xe37a1f69), TOBN(0xcbd252cb, 0x03542b60),
++     TOBN(0x785f65d5, 0xb3c20bd3), TOBN(0x8dea6143, 0x4fabc60c),
++     TOBN(0x45e21446, 0xde673629), TOBN(0x57f7aa1e, 0x703c2d21),
++     TOBN(0xa0e99b7f, 0x98c868c7), TOBN(0x4e42f66d, 0x8b641676),
++     TOBN(0x602884dc, 0x91077896), TOBN(0xa0d690cf, 0xc2c9885b),
++     TOBN(0xfeb4da33, 0x3b9a5187), TOBN(0x5f789598, 0x153c87ee),
++     TOBN(0x2192dd47, 0x52b16dba), TOBN(0xdeefc0e6, 0x3524c1b1),
++     TOBN(0x465ea76e, 0xe4383693), TOBN(0x79401711, 0x361b8d98),
++     TOBN(0xa5f9ace9, 0xf21a15cb), TOBN(0x73d26163, 0xefee9aeb),
++     TOBN(0xcca844b3, 0xe677016c), TOBN(0x6c122b07, 0x57eaee06),
++     TOBN(0xb782dce7, 0x15f09690), TOBN(0x508b9b12, 0x2dfc0fc9),
++     TOBN(0x9015ab4b, 0x65d89fc6), TOBN(0x5e79dab7, 0xd6d5bb0f),
++     TOBN(0x64f021f0, 0x6c775aa2), TOBN(0xdf09d8cc, 0x37c7eca1),
++     TOBN(0x9a761367, 0xef2fa506), TOBN(0xed4ca476, 0x5b81eec6),
++     TOBN(0x262ede36, 0x10bbb8b5), TOBN(0x0737ce83, 0x0641ada3),
++     TOBN(0x4c94288a, 0xe9831ccc), TOBN(0x487fc1ce, 0x8065e635),
++     TOBN(0xb13d7ab3, 0xb8bb3659), TOBN(0xdea5df3e, 0x855e4120),
++     TOBN(0xb9a18573, 0x85eb0244), TOBN(0x1a1b8ea3, 0xa7cfe0a3),
++     TOBN(0x3b837119, 0x67b0867c), TOBN(0x8d5e0d08, 0x9d364520),
++     TOBN(0x52dccc1e, 0xd930f0e3), TOBN(0xefbbcec7, 0xbf20bbaf),
++     TOBN(0x99cffcab, 0x0263ad10), TOBN(0xd8199e6d, 0xfcd18f8a),
++     TOBN(0x64e2773f, 0xe9f10617), TOBN(0x0079e8e1, 0x08704848),
++     TOBN(0x1169989f, 0x8a342283), TOBN(0x8097799c, 0xa83012e6),
++     TOBN(0xece966cb, 0x8a6a9001), TOBN(0x93b3afef, 0x072ac7fc),
++     TOBN(0xe6893a2a, 0x2db3d5ba), TOBN(0x263dc462, 0x89bf4fdc),
++     TOBN(0x8852dfc9, 0xe0396673), TOBN(0x7ac70895, 0x3af362b6),
++     TOBN(0xbb9cce4d, 0x5c2f342b), TOBN(0xbf80907a, 0xb52d7aae),
++     TOBN(0x97f3d3cd, 0x2161bcd0), TOBN(0xb25b0834, 0x0962744d),
++     TOBN(0xc5b18ea5, 0x6c3a1dda), TOBN(0xfe4ec7eb, 0x06c92317),
++     TOBN(0xb787b890, 0xad1c4afe), TOBN(0xdccd9a92, 0x0ede801a),
++     TOBN(0x9ac6ddda, 0xdb58da1f), TOBN(0x22bbc12f, 0xb8cae6ee),
++     TOBN(0xc6f8bced, 0x815c4a43), TOBN(0x8105a92c, 0xf96480c7),
++     TOBN(0x0dc3dbf3, 0x7a859d51), TOBN(0xe3ec7ce6, 0x3041196b),
++     TOBN(0xd9f64b25, 0x0d1067c9), TOBN(0xf2321321, 0x3d1f8dd8),
++     TOBN(0x8b5c619c, 0x76497ee8), TOBN(0x5d2b0ac6, 0xc717370e),
++     TOBN(0x98204cb6, 0x4fcf68e1), TOBN(0x0bdec211, 0x62bc6792),
++     TOBN(0x6973ccef, 0xa63b1011), TOBN(0xf9e3fa97, 0xe0de1ac5),
++     TOBN(0x5efb693e, 0x3d0e0c8b), TOBN(0x037248e9, 0xd2d4fcb4),}
++    ,
++    {TOBN(0x80802dc9, 0x1ec34f9e), TOBN(0xd8772d35, 0x33810603),
++     TOBN(0x3f06d66c, 0x530cb4f3), TOBN(0x7be5ed0d, 0xc475c129),
++     TOBN(0xcb9e3c19, 0x31e82b10), TOBN(0xc63d2857, 0xc9ff6b4c),
++     TOBN(0xb92118c6, 0x92a1b45e), TOBN(0x0aec4414, 0x7285bbca),
++     TOBN(0xfc189ae7, 0x1e29a3ef), TOBN(0xcbe906f0, 0x4c93302e),
++     TOBN(0xd0107914, 0xceaae10e), TOBN(0xb7a23f34, 0xb68e19f8),
++     TOBN(0xe9d875c2, 0xefd2119d), TOBN(0x03198c6e, 0xfcadc9c8),
++     TOBN(0x65591bf6, 0x4da17113), TOBN(0x3cf0bbf8, 0x3d443038),
++     TOBN(0xae485bb7, 0x2b724759), TOBN(0x945353e1, 0xb2d4c63a),
++     TOBN(0x82159d07, 0xde7d6f2c), TOBN(0x389caef3, 0x4ec5b109),
++     TOBN(0x4a8ebb53, 0xdb65ef14), TOBN(0x2dc2cb7e, 0xdd99de43),
++     TOBN(0x816fa3ed, 0x83f2405f), TOBN(0x73429bb9, 0xc14208a3),
++     TOBN(0xb618d590, 0xb01e6e27), TOBN(0x047e2ccd, 0xe180b2dc),
++     TOBN(0xd1b299b5, 0x04aea4a9), TOBN(0x412c9e1e, 0x9fa403a4),
++     TOBN(0x88d28a36, 0x79407552), TOBN(0x49c50136, 0xf332b8e3),
++     TOBN(0x3a1b6fcc, 0xe668de19), TOBN(0x178851bc, 0x75122b97),
++     TOBN(0xb1e13752, 0xfb85fa4c), TOBN(0xd61257ce, 0x383c8ce9),
++     TOBN(0xd43da670, 0xd2f74dae), TOBN(0xa35aa23f, 0xbf846bbb),
++     TOBN(0x5e74235d, 0x4421fc83), TOBN(0xf6df8ee0, 0xc363473b),
++     TOBN(0x34d7f52a, 0x3c4aa158), TOBN(0x50d05aab, 0x9bc6d22e),
++     TOBN(0x8c56e735, 0xa64785f4), TOBN(0xbc56637b, 0x5f29cd07),
++     TOBN(0x53b2bb80, 0x3ee35067), TOBN(0x50235a0f, 0xdc919270),
++     TOBN(0x191ab6d8, 0xf2c4aa65), TOBN(0xc3475831, 0x8396023b),
++     TOBN(0x80400ba5, 0xf0f805ba), TOBN(0x8881065b, 0x5ec0f80f),
++     TOBN(0xc370e522, 0xcc1b5e83), TOBN(0xde2d4ad1, 0x860b8bfb),
++     TOBN(0xad364df0, 0x67b256df), TOBN(0x8f12502e, 0xe0138997),
++     TOBN(0x503fa0dc, 0x7783920a), TOBN(0xe80014ad, 0xc0bc866a),
++     TOBN(0x3f89b744, 0xd3064ba6), TOBN(0x03511dcd, 0xcba5dba5),
++     TOBN(0x197dd46d, 0x95a7b1a2), TOBN(0x9c4e7ad6, 0x3c6341fb),
++     TOBN(0x426eca29, 0x484c2ece), TOBN(0x9211e489, 0xde7f4f8a),
++     TOBN(0x14997f6e, 0xc78ef1f4), TOBN(0x2b2c0910, 0x06574586),
++     TOBN(0x17286a6e, 0x1c3eede8), TOBN(0x25f92e47, 0x0f60e018),
++     TOBN(0x805c5646, 0x31890a36), TOBN(0x703ef600, 0x57feea5b),
++     TOBN(0x389f747c, 0xaf3c3030), TOBN(0xe0e5daeb, 0x54dd3739),
++     TOBN(0xfe24a4c3, 0xc9c9f155), TOBN(0x7e4bf176, 0xb5393962),
++     TOBN(0x37183de2, 0xaf20bf29), TOBN(0x4a1bd7b5, 0xf95a8c3b),
++     TOBN(0xa83b9699, 0x46191d3d), TOBN(0x281fc8dd, 0x7b87f257),
++     TOBN(0xb18e2c13, 0x54107588), TOBN(0x6372def7, 0x9b2bafe8),
++     TOBN(0xdaf4bb48, 0x0d8972ca), TOBN(0x3f2dd4b7, 0x56167a3f),
++     TOBN(0x1eace32d, 0x84310cf4), TOBN(0xe3bcefaf, 0xe42700aa),
++     TOBN(0x5fe5691e, 0xd785e73d), TOBN(0xa5db5ab6, 0x2ea60467),
++     TOBN(0x02e23d41, 0xdfc6514a), TOBN(0x35e8048e, 0xe03c3665),
++     TOBN(0x3f8b118f, 0x1adaa0f8), TOBN(0x28ec3b45, 0x84ce1a5a),
++     TOBN(0xe8cacc6e, 0x2c6646b8), TOBN(0x1343d185, 0xdbd0e40f),
++     TOBN(0xe5d7f844, 0xcaaa358c), TOBN(0x1a1db7e4, 0x9924182a),
++     TOBN(0xd64cd42d, 0x9c875d9a), TOBN(0xb37b515f, 0x042eeec8),
++     TOBN(0x4d4dd409, 0x7b165fbe), TOBN(0xfc322ed9, 0xe206eff3),
++     TOBN(0x7dee4102, 0x59b7e17e), TOBN(0x55a481c0, 0x8236ca00),
++     TOBN(0x8c885312, 0xc23fc975), TOBN(0x15715806, 0x05d6297b),
++     TOBN(0xa078868e, 0xf78edd39), TOBN(0x956b31e0, 0x03c45e52),
++     TOBN(0x470275d5, 0xff7b33a6), TOBN(0xc8d5dc3a, 0x0c7e673f),
++     TOBN(0x419227b4, 0x7e2f2598), TOBN(0x8b37b634, 0x4c14a975),
++     TOBN(0xd0667ed6, 0x8b11888c), TOBN(0x5e0e8c3e, 0x803e25dc),
++     TOBN(0x34e5d0dc, 0xb987a24a), TOBN(0x9f40ac3b, 0xae920323),
++     TOBN(0x5463de95, 0x34e0f63a), TOBN(0xa128bf92, 0x6b6328f9),
++     TOBN(0x491ccd7c, 0xda64f1b7), TOBN(0x7ef1ec27, 0xc47bde35),
++     TOBN(0xa857240f, 0xa36a2737), TOBN(0x35dc1366, 0x63621bc1),
++     TOBN(0x7a3a6453, 0xd4fb6897), TOBN(0x80f1a439, 0xc929319d),
++     TOBN(0xfc18274b, 0xf8cb0ba0), TOBN(0xb0b53766, 0x8078c5eb),
++     TOBN(0xfb0d4924, 0x1e01d0ef), TOBN(0x50d7c67d, 0x372ab09c),
++     TOBN(0xb4e370af, 0x3aeac968), TOBN(0xe4f7fee9, 0xc4b63266),
++     TOBN(0xb4acd4c2, 0xe3ac5664), TOBN(0xf8910bd2, 0xceb38cbf),
++     TOBN(0x1c3ae50c, 0xc9c0726e), TOBN(0x15309569, 0xd97b40bf),
++     TOBN(0x70884b7f, 0xfd5a5a1b), TOBN(0x3890896a, 0xef8314cd),
++     TOBN(0x58e1515c, 0xa5618c93), TOBN(0xe665432b, 0x77d942d1),
++     TOBN(0xb32181bf, 0xb6f767a8), TOBN(0x753794e8, 0x3a604110),
++     TOBN(0x09afeb7c, 0xe8c0dbcc), TOBN(0x31e02613, 0x598673a3),
++     TOBN(0x5d98e557, 0x7d46db00), TOBN(0xfc21fb8c, 0x9d985b28),
++     TOBN(0xc9040116, 0xb0843e0b), TOBN(0x53b1b3a8, 0x69b04531),
++     TOBN(0xdd1649f0, 0x85d7d830), TOBN(0xbb3bcc87, 0xcb7427e8),
++     TOBN(0x77261100, 0xc93dce83), TOBN(0x7e79da61, 0xa1922a2a),
++     TOBN(0x587a2b02, 0xf3149ce8), TOBN(0x147e1384, 0xde92ec83),
++     TOBN(0x484c83d3, 0xaf077f30), TOBN(0xea78f844, 0x0658b53a),
++     TOBN(0x912076c2, 0x027aec53), TOBN(0xf34714e3, 0x93c8177d),
++     TOBN(0x37ef5d15, 0xc2376c84), TOBN(0x8315b659, 0x3d1aa783),
++     TOBN(0x3a75c484, 0xef852a90), TOBN(0x0ba0c58a, 0x16086bd4),
++     TOBN(0x29688d7a, 0x529a6d48), TOBN(0x9c7f250d, 0xc2f19203),
++     TOBN(0x123042fb, 0x682e2df9), TOBN(0x2b7587e7, 0xad8121bc),
++     TOBN(0x30fc0233, 0xe0182a65), TOBN(0xb82ecf87, 0xe3e1128a),
++     TOBN(0x71682861, 0x93fb098f), TOBN(0x043e21ae, 0x85e9e6a7),
++     TOBN(0xab5b49d6, 0x66c834ea), TOBN(0x3be43e18, 0x47414287),
++     TOBN(0xf40fb859, 0x219a2a47), TOBN(0x0e6559e9, 0xcc58df3c),
++     TOBN(0xfe1dfe8e, 0x0c6615b4), TOBN(0x14abc8fd, 0x56459d70),
++     TOBN(0x7be0fa8e, 0x05de0386), TOBN(0x8e63ef68, 0xe9035c7c),
++     TOBN(0x116401b4, 0x53b31e91), TOBN(0x0cba7ad4, 0x4436b4d8),
++     TOBN(0x9151f9a0, 0x107afd66), TOBN(0xafaca8d0, 0x1f0ee4c4),
++     TOBN(0x75fe5c1d, 0x9ee9761c), TOBN(0x3497a16b, 0xf0c0588f),
++     TOBN(0x3ee2bebd, 0x0304804c), TOBN(0xa8fb9a60, 0xc2c990b9),
++     TOBN(0xd14d32fe, 0x39251114), TOBN(0x36bf25bc, 0xcac73366),
++     TOBN(0xc9562c66, 0xdba7495c), TOBN(0x324d301b, 0x46ad348b),
++     TOBN(0x9f46620c, 0xd670407e), TOBN(0x0ea8d4f1, 0xe3733a01),
++     TOBN(0xd396d532, 0xb0c324e0), TOBN(0x5b211a0e, 0x03c317cd),
++     TOBN(0x090d7d20, 0x5ffe7b37), TOBN(0x3b7f3efb, 0x1747d2da),
++     TOBN(0xa2cb525f, 0xb54fc519), TOBN(0x6e220932, 0xf66a971e),
++     TOBN(0xddc160df, 0xb486d440), TOBN(0x7fcfec46, 0x3fe13465),
++     TOBN(0x83da7e4e, 0x76e4c151), TOBN(0xd6fa48a1, 0xd8d302b5),
++     TOBN(0xc6304f26, 0x5872cd88), TOBN(0x806c1d3c, 0x278b90a1),
++     TOBN(0x3553e725, 0xcaf0bc1c), TOBN(0xff59e603, 0xbb9d8d5c),
++     TOBN(0xa4550f32, 0x7a0b85dd), TOBN(0xdec5720a, 0x93ecc217),
++     TOBN(0x0b88b741, 0x69d62213), TOBN(0x7212f245, 0x5b365955),
++     TOBN(0x20764111, 0xb5cae787), TOBN(0x13cb7f58, 0x1dfd3124),
++     TOBN(0x2dca77da, 0x1175aefb), TOBN(0xeb75466b, 0xffaae775),
++     TOBN(0x74d76f3b, 0xdb6cff32), TOBN(0x7440f37a, 0x61fcda9a),
++     TOBN(0x1bb3ac92, 0xb525028b), TOBN(0x20fbf8f7, 0xa1975f29),
++     TOBN(0x982692e1, 0xdf83097f), TOBN(0x28738f6c, 0x554b0800),
++     TOBN(0xdc703717, 0xa2ce2f2f), TOBN(0x7913b93c, 0x40814194),
++     TOBN(0x04924593, 0x1fe89636), TOBN(0x7b98443f, 0xf78834a6),
++     TOBN(0x11c6ab01, 0x5114a5a1), TOBN(0x60deb383, 0xffba5f4c),
++     TOBN(0x4caa54c6, 0x01a982e6), TOBN(0x1dd35e11, 0x3491cd26),
++     TOBN(0x973c315f, 0x7cbd6b05), TOBN(0xcab00775, 0x52494724),
++     TOBN(0x04659b1f, 0x6565e15a), TOBN(0xbf30f529, 0x8c8fb026),
++     TOBN(0xfc21641b, 0xa8a0de37), TOBN(0xe9c7a366, 0xfa5e5114),
++     TOBN(0xdb849ca5, 0x52f03ad8), TOBN(0xc7e8dbe9, 0x024e35c0),
++     TOBN(0xa1a2bbac, 0xcfc3c789), TOBN(0xbf733e7d, 0x9c26f262),
++     TOBN(0x882ffbf5, 0xb8444823), TOBN(0xb7224e88, 0x6bf8483b),
++     TOBN(0x53023b8b, 0x65bef640), TOBN(0xaabfec91, 0xd4d5f8cd),
++     TOBN(0xa40e1510, 0x079ea1bd), TOBN(0x1ad9addc, 0xd05d5d26),
++     TOBN(0xdb3f2eab, 0x13e68d4f), TOBN(0x1cff1ae2, 0x640f803f),
++     TOBN(0xe0e7b749, 0xd4cee117), TOBN(0x8e9f275b, 0x4036d909),
++     TOBN(0xce34e31d, 0x8f4d4c38), TOBN(0x22b37f69, 0xd75130fc),
++     TOBN(0x83e0f1fd, 0xb4014604), TOBN(0xa8ce9919, 0x89415078),
++     TOBN(0x82375b75, 0x41792efe), TOBN(0x4f59bf5c, 0x97d4515b),
++     TOBN(0xac4f324f, 0x923a277d), TOBN(0xd9bc9b7d, 0x650f3406),
++     TOBN(0xc6fa87d1, 0x8a39bc51), TOBN(0x82588530, 0x5ccc108f),
++     TOBN(0x5ced3c9f, 0x82e4c634), TOBN(0x8efb8314, 0x3a4464f8),
++     TOBN(0xe706381b, 0x7a1dca25), TOBN(0x6cd15a3c, 0x5a2a412b),
++     TOBN(0x9347a8fd, 0xbfcd8fb5), TOBN(0x31db2eef, 0x6e54cd22),
++     TOBN(0xc4aeb11e, 0xf8d8932f), TOBN(0x11e7c1ed, 0x344411af),
++     TOBN(0x2653050c, 0xdc9a151e), TOBN(0x9edbfc08, 0x3bb0a859),
++     TOBN(0x926c81c7, 0xfd5691e7), TOBN(0x9c1b2342, 0x6f39019a),
++     TOBN(0x64a81c8b, 0x7f8474b9), TOBN(0x90657c07, 0x01761819),
++     TOBN(0x390b3331, 0x55e0375a), TOBN(0xc676c626, 0xb6ebc47d),
++     TOBN(0x51623247, 0xb7d6dee8), TOBN(0x0948d927, 0x79659313),
++     TOBN(0x99700161, 0xe9ab35ed), TOBN(0x06cc32b4, 0x8ddde408),
++     TOBN(0x6f2fd664, 0x061ef338), TOBN(0x1606fa02, 0xc202e9ed),
++     TOBN(0x55388bc1, 0x929ba99b), TOBN(0xc4428c5e, 0x1e81df69),
++     TOBN(0xce2028ae, 0xf91b0b2a), TOBN(0xce870a23, 0xf03dfd3f),
++     TOBN(0x66ec2c87, 0x0affe8ed), TOBN(0xb205fb46, 0x284d0c00),
++     TOBN(0xbf5dffe7, 0x44cefa48), TOBN(0xb6fc37a8, 0xa19876d7),
++     TOBN(0xbecfa84c, 0x08b72863), TOBN(0xd7205ff5, 0x2576374f),
++     TOBN(0x80330d32, 0x8887de41), TOBN(0x5de0df0c, 0x869ea534),
++     TOBN(0x13f42753, 0x3c56ea17), TOBN(0xeb1f6069, 0x452b1a78),
++     TOBN(0x50474396, 0xe30ea15c), TOBN(0x575816a1, 0xc1494125),
++     TOBN(0xbe1ce55b, 0xfe6bb38f), TOBN(0xb901a948, 0x96ae30f7),
++     TOBN(0xe5af0f08, 0xd8fc3548), TOBN(0x5010b5d0, 0xd73bfd08),
++     TOBN(0x993d2880, 0x53fe655a), TOBN(0x99f2630b, 0x1c1309fd),
++     TOBN(0xd8677baf, 0xb4e3b76f), TOBN(0x14e51ddc, 0xb840784b),
++     TOBN(0x326c750c, 0xbf0092ce), TOBN(0xc83d306b, 0xf528320f),
++     TOBN(0xc4456715, 0x77d4715c), TOBN(0xd30019f9, 0x6b703235),
++     TOBN(0x207ccb2e, 0xd669e986), TOBN(0x57c824af, 0xf6dbfc28),
++     TOBN(0xf0eb532f, 0xd8f92a23), TOBN(0x4a557fd4, 0x9bb98fd2),
++     TOBN(0xa57acea7, 0xc1e6199a), TOBN(0x0c663820, 0x8b94b1ed),
++     TOBN(0x9b42be8f, 0xf83a9266), TOBN(0xc7741c97, 0x0101bd45),
++     TOBN(0x95770c11, 0x07bd9ceb), TOBN(0x1f50250a, 0x8b2e0744),
++     TOBN(0xf762eec8, 0x1477b654), TOBN(0xc65b900e, 0x15efe59a),
++     TOBN(0x88c96148, 0x9546a897), TOBN(0x7e8025b3, 0xc30b4d7c),
++     TOBN(0xae4065ef, 0x12045cf9), TOBN(0x6fcb2caf, 0x9ccce8bd),
++     TOBN(0x1fa0ba4e, 0xf2cf6525), TOBN(0xf683125d, 0xcb72c312),
++     TOBN(0xa01da4ea, 0xe312410e), TOBN(0x67e28677, 0x6cd8e830),
++     TOBN(0xabd95752, 0x98fb3f07), TOBN(0x05f11e11, 0xeef649a5),
++     TOBN(0xba47faef, 0x9d3472c2), TOBN(0x3adff697, 0xc77d1345),
++     TOBN(0x4761fa04, 0xdd15afee), TOBN(0x64f1f61a, 0xb9e69462),
++     TOBN(0xfa691fab, 0x9bfb9093), TOBN(0x3df8ae8f, 0xa1133dfe),
++     TOBN(0xcd5f8967, 0x58cc710d), TOBN(0xfbb88d50, 0x16c7fe79),
++     TOBN(0x8e011b4c, 0xe88c50d1), TOBN(0x7532e807, 0xa8771c4f),
++     TOBN(0x64c78a48, 0xe2278ee4), TOBN(0x0b283e83, 0x3845072a),
++     TOBN(0x98a6f291, 0x49e69274), TOBN(0xb96e9668, 0x1868b21c),
++     TOBN(0x38f0adc2, 0xb1a8908e), TOBN(0x90afcff7, 0x1feb829d),
++     TOBN(0x9915a383, 0x210b0856), TOBN(0xa5a80602, 0xdef04889),
++     TOBN(0x800e9af9, 0x7c64d509), TOBN(0x81382d0b, 0xb8996f6f),
++     TOBN(0x490eba53, 0x81927e27), TOBN(0x46c63b32, 0x4af50182),
++     TOBN(0x784c5fd9, 0xd3ad62ce), TOBN(0xe4fa1870, 0xf8ae8736),
++     TOBN(0x4ec9d0bc, 0xd7466b25), TOBN(0x84ddbe1a, 0xdb235c65),
++     TOBN(0x5e2645ee, 0x163c1688), TOBN(0x570bd00e, 0x00eba747),
++     TOBN(0xfa51b629, 0x128bfa0f), TOBN(0x92fce1bd, 0x6c1d3b68),
++     TOBN(0x3e7361dc, 0xb66778b1), TOBN(0x9c7d249d, 0x5561d2bb),
++     TOBN(0xa40b28bf, 0x0bbc6229), TOBN(0x1c83c05e, 0xdfd91497),
++     TOBN(0x5f9f5154, 0xf083df05), TOBN(0xbac38b3c, 0xeee66c9d),
++     TOBN(0xf71db7e3, 0xec0dfcfd), TOBN(0xf2ecda8e, 0x8b0a8416),
++     TOBN(0x52fddd86, 0x7812aa66), TOBN(0x2896ef10, 0x4e6f4272),
++     TOBN(0xff27186a, 0x0fe9a745), TOBN(0x08249fcd, 0x49ca70db),
++     TOBN(0x7425a2e6, 0x441cac49), TOBN(0xf4a0885a, 0xece5ff57),
++     TOBN(0x6e2cb731, 0x7d7ead58), TOBN(0xf96cf7d6, 0x1898d104),
++     TOBN(0xafe67c9d, 0x4f2c9a89), TOBN(0x89895a50, 0x1c7bf5bc),
++     TOBN(0xdc7cb8e5, 0x573cecfa), TOBN(0x66497eae, 0xd15f03e6),
++     TOBN(0x6bc0de69, 0x3f084420), TOBN(0x323b9b36, 0xacd532b0),
++     TOBN(0xcfed390a, 0x0115a3c1), TOBN(0x9414c40b, 0x2d65ca0e),
++     TOBN(0x641406bd, 0x2f530c78), TOBN(0x29369a44, 0x833438f2),
++     TOBN(0x996884f5, 0x903fa271), TOBN(0xe6da0fd2, 0xb9da921e),
++     TOBN(0xa6f2f269, 0x5db01e54), TOBN(0x1ee3e9bd, 0x6876214e),
++     TOBN(0xa26e181c, 0xe27a9497), TOBN(0x36d254e4, 0x8e215e04),
++     TOBN(0x42f32a6c, 0x252cabca), TOBN(0x99481487, 0x80b57614),
++     TOBN(0x4c4dfe69, 0x40d9cae1), TOBN(0x05869580, 0x11a10f09),
++     TOBN(0xca287b57, 0x3491b64b), TOBN(0x77862d5d, 0x3fd4a53b),
++     TOBN(0xbf94856e, 0x50349126), TOBN(0x2be30bd1, 0x71c5268f),
++     TOBN(0x10393f19, 0xcbb650a6), TOBN(0x639531fe, 0x778cf9fd),
++     TOBN(0x02556a11, 0xb2935359), TOBN(0xda38aa96, 0xaf8c126e),
++     TOBN(0x47dbe6c2, 0x0960167f), TOBN(0x37bbabb6, 0x501901cd),
++     TOBN(0xb6e979e0, 0x2c947778), TOBN(0xd69a5175, 0x7a1a1dc6),
++     TOBN(0xc3ed5095, 0x9d9faf0c), TOBN(0x4dd9c096, 0x1d5fa5f0),
++     TOBN(0xa0c4304d, 0x64f16ea8), TOBN(0x8b1cac16, 0x7e718623),
++     TOBN(0x0b576546, 0x7c67f03e), TOBN(0x559cf5ad, 0xcbd88c01),
++     TOBN(0x074877bb, 0x0e2af19a), TOBN(0x1f717ec1, 0xa1228c92),
++     TOBN(0x70bcb800, 0x326e8920), TOBN(0xec6e2c5c, 0x4f312804),
++     TOBN(0x426aea7d, 0x3fca4752), TOBN(0xf12c0949, 0x2211f62a),
++     TOBN(0x24beecd8, 0x7be7b6b5), TOBN(0xb77eaf4c, 0x36d7a27d),
++     TOBN(0x154c2781, 0xfda78fd3), TOBN(0x848a83b0, 0x264eeabe),
++     TOBN(0x81287ef0, 0x4ffe2bc4), TOBN(0x7b6d88c6, 0xb6b6fc2a),
++     TOBN(0x805fb947, 0xce417d99), TOBN(0x4b93dcc3, 0x8b916cc4),
++     TOBN(0x72e65bb3, 0x21273323), TOBN(0xbcc1badd, 0x6ea9886e),
++     TOBN(0x0e223011, 0x4bc5ee85), TOBN(0xa561be74, 0xc18ee1e4),
++     TOBN(0x762fd2d4, 0xa6bcf1f1), TOBN(0x50e6a5a4, 0x95231489),
++     TOBN(0xca96001f, 0xa00b500b), TOBN(0x5c098cfc, 0x5d7dcdf5),
++     TOBN(0xa64e2d2e, 0x8c446a85), TOBN(0xbae9bcf1, 0x971f3c62),
++     TOBN(0x4ec22683, 0x8435a2c5), TOBN(0x8ceaed6c, 0x4bad4643),
++     TOBN(0xe9f8fb47, 0xccccf4e3), TOBN(0xbd4f3fa4, 0x1ce3b21e),
++     TOBN(0xd79fb110, 0xa3db3292), TOBN(0xe28a37da, 0xb536c66a),
++     TOBN(0x279ce87b, 0x8e49e6a9), TOBN(0x70ccfe8d, 0xfdcec8e3),
++     TOBN(0x2193e4e0, 0x3ba464b2), TOBN(0x0f39d60e, 0xaca9a398),
++     TOBN(0x7d7932af, 0xf82c12ab), TOBN(0xd8ff50ed, 0x91e7e0f7),
++     TOBN(0xea961058, 0xfa28a7e0), TOBN(0xc726cf25, 0x0bf5ec74),
++     TOBN(0xe74d55c8, 0xdb229666), TOBN(0x0bd9abbf, 0xa57f5799),
++     TOBN(0x7479ef07, 0x4dfc47b3), TOBN(0xd9c65fc3, 0x0c52f91d),
++     TOBN(0x8e0283fe, 0x36a8bde2), TOBN(0xa32a8b5e, 0x7d4b7280),
++     TOBN(0x6a677c61, 0x12e83233), TOBN(0x0fbb3512, 0xdcc9bf28),
++     TOBN(0x562e8ea5, 0x0d780f61), TOBN(0x0db8b22b, 0x1dc4e89c),
++     TOBN(0x0a6fd1fb, 0x89be0144), TOBN(0x8c77d246, 0xca57113b),
++     TOBN(0x4639075d, 0xff09c91c), TOBN(0x5b47b17f, 0x5060824c),
++     TOBN(0x58aea2b0, 0x16287b52), TOBN(0xa1343520, 0xd0cd8eb0),
++     TOBN(0x6148b4d0, 0xc5d58573), TOBN(0xdd2b6170, 0x291c68ae),
++     TOBN(0xa61b3929, 0x1da3b3b7), TOBN(0x5f946d79, 0x08c4ac10),
++     TOBN(0x4105d4a5, 0x7217d583), TOBN(0x5061da3d, 0x25e6de5e),
++     TOBN(0x3113940d, 0xec1b4991), TOBN(0xf12195e1, 0x36f485ae),
++     TOBN(0xa7507fb2, 0x731a2ee0), TOBN(0x95057a8e, 0x6e9e196e),
++     TOBN(0xa3c2c911, 0x2e130136), TOBN(0x97dfbb36, 0x33c60d15),
++     TOBN(0xcaf3c581, 0xb300ee2b), TOBN(0x77f25d90, 0xf4bac8b8),
++     TOBN(0xdb1c4f98, 0x6d840cd6), TOBN(0x471d62c0, 0xe634288c),
++     TOBN(0x8ec2f85e, 0xcec8a161), TOBN(0x41f37cbc, 0xfa6f4ae2),
++     TOBN(0x6793a20f, 0x4b709985), TOBN(0x7a7bd33b, 0xefa8985b),
++     TOBN(0x2c6a3fbd, 0x938e6446), TOBN(0x19042619, 0x2a8d47c1),
++     TOBN(0x16848667, 0xcc36975f), TOBN(0x02acf168, 0x9d5f1dfb),
++     TOBN(0x62d41ad4, 0x613baa94), TOBN(0xb56fbb92, 0x9f684670),
++     TOBN(0xce610d0d, 0xe9e40569), TOBN(0x7b99c65f, 0x35489fef),
++     TOBN(0x0c88ad1b, 0x3df18b97), TOBN(0x81b7d9be, 0x5d0e9edb),
++     TOBN(0xd85218c0, 0xc716cc0a), TOBN(0xf4b5ff90, 0x85691c49),
++     TOBN(0xa4fd666b, 0xce356ac6), TOBN(0x17c72895, 0x4b327a7a),
++     TOBN(0xf93d5085, 0xda6be7de), TOBN(0xff71530e, 0x3301d34e),
++     TOBN(0x4cd96442, 0xd8f448e8), TOBN(0x9283d331, 0x2ed18ffa),
++     TOBN(0x4d33dd99, 0x2a849870), TOBN(0xa716964b, 0x41576335),
++     TOBN(0xff5e3a9b, 0x179be0e5), TOBN(0x5b9d6b1b, 0x83b13632),
++     TOBN(0x3b8bd7d4, 0xa52f313b), TOBN(0xc9dd95a0, 0x637a4660),
++     TOBN(0x30035962, 0x0b3e218f), TOBN(0xce1481a3, 0xc7b28a3c),
++     TOBN(0xab41b43a, 0x43228d83), TOBN(0x24ae1c30, 0x4ad63f99),
++     TOBN(0x8e525f1a, 0x46a51229), TOBN(0x14af860f, 0xcd26d2b4),
++     TOBN(0xd6baef61, 0x3f714aa1), TOBN(0xf51865ad, 0xeb78795e),
++     TOBN(0xd3e21fce, 0xe6a9d694), TOBN(0x82ceb1dd, 0x8a37b527)}
++};
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/ec/ecp_oct.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/ec/ecp_oct.c
+new file mode 100644
+index 0000000..4d142a4
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/ec/ecp_oct.c
+@@ -0,0 +1,372 @@
++/*
++ * Copyright 2011-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++/* ====================================================================
++ * Copyright 2002 Sun Microsystems, Inc. ALL RIGHTS RESERVED.
++ * Portions of this software developed by SUN MICROSYSTEMS, INC.,
++ * and contributed to the OpenSSL project.
++ */
++
++#include 
++#include 
++
++#include "ec_lcl.h"
++
++int ec_GFp_simple_set_compressed_coordinates(const EC_GROUP *group,
++                                             EC_POINT *point,
++                                             const BIGNUM *x_, int y_bit,
++                                             BN_CTX *ctx)
++{
++    BN_CTX *new_ctx = NULL;
++    BIGNUM *tmp1, *tmp2, *x, *y;
++    int ret = 0;
++
++    /* clear error queue */
++    ERR_clear_error();
++
++    if (ctx == NULL) {
++        ctx = new_ctx = BN_CTX_new();
++        if (ctx == NULL)
++            return 0;
++    }
++
++    y_bit = (y_bit != 0);
++
++    BN_CTX_start(ctx);
++    tmp1 = BN_CTX_get(ctx);
++    tmp2 = BN_CTX_get(ctx);
++    x = BN_CTX_get(ctx);
++    y = BN_CTX_get(ctx);
++    if (y == NULL)
++        goto err;
++
++    /*-
++     * Recover y.  We have a Weierstrass equation
++     *     y^2 = x^3 + a*x + b,
++     * so  y  is one of the square roots of  x^3 + a*x + b.
++     */
++
++    /* tmp1 := x^3 */
++    if (!BN_nnmod(x, x_, group->field, ctx))
++        goto err;
++    if (group->meth->field_decode == 0) {
++        /* field_{sqr,mul} work on standard representation */
++        if (!group->meth->field_sqr(group, tmp2, x_, ctx))
++            goto err;
++        if (!group->meth->field_mul(group, tmp1, tmp2, x_, ctx))
++            goto err;
++    } else {
++        if (!BN_mod_sqr(tmp2, x_, group->field, ctx))
++            goto err;
++        if (!BN_mod_mul(tmp1, tmp2, x_, group->field, ctx))
++            goto err;
++    }
++
++    /* tmp1 := tmp1 + a*x */
++    if (group->a_is_minus3) {
++        if (!BN_mod_lshift1_quick(tmp2, x, group->field))
++            goto err;
++        if (!BN_mod_add_quick(tmp2, tmp2, x, group->field))
++            goto err;
++        if (!BN_mod_sub_quick(tmp1, tmp1, tmp2, group->field))
++            goto err;
++    } else {
++        if (group->meth->field_decode) {
++            if (!group->meth->field_decode(group, tmp2, group->a, ctx))
++                goto err;
++            if (!BN_mod_mul(tmp2, tmp2, x, group->field, ctx))
++                goto err;
++        } else {
++            /* field_mul works on standard representation */
++            if (!group->meth->field_mul(group, tmp2, group->a, x, ctx))
++                goto err;
++        }
++
++        if (!BN_mod_add_quick(tmp1, tmp1, tmp2, group->field))
++            goto err;
++    }
++
++    /* tmp1 := tmp1 + b */
++    if (group->meth->field_decode) {
++        if (!group->meth->field_decode(group, tmp2, group->b, ctx))
++            goto err;
++        if (!BN_mod_add_quick(tmp1, tmp1, tmp2, group->field))
++            goto err;
++    } else {
++        if (!BN_mod_add_quick(tmp1, tmp1, group->b, group->field))
++            goto err;
++    }
++
++    if (!BN_mod_sqrt(y, tmp1, group->field, ctx)) {
++        unsigned long err = ERR_peek_last_error();
++
++        if (ERR_GET_LIB(err) == ERR_LIB_BN
++            && ERR_GET_REASON(err) == BN_R_NOT_A_SQUARE) {
++            ERR_clear_error();
++            ECerr(EC_F_EC_GFP_SIMPLE_SET_COMPRESSED_COORDINATES,
++                  EC_R_INVALID_COMPRESSED_POINT);
++        } else
++            ECerr(EC_F_EC_GFP_SIMPLE_SET_COMPRESSED_COORDINATES,
++                  ERR_R_BN_LIB);
++        goto err;
++    }
++
++    if (y_bit != BN_is_odd(y)) {
++        if (BN_is_zero(y)) {
++            int kron;
++
++            kron = BN_kronecker(x, group->field, ctx);
++            if (kron == -2)
++                goto err;
++
++            if (kron == 1)
++                ECerr(EC_F_EC_GFP_SIMPLE_SET_COMPRESSED_COORDINATES,
++                      EC_R_INVALID_COMPRESSION_BIT);
++            else
++                /*
++                 * BN_mod_sqrt() should have cought this error (not a square)
++                 */
++                ECerr(EC_F_EC_GFP_SIMPLE_SET_COMPRESSED_COORDINATES,
++                      EC_R_INVALID_COMPRESSED_POINT);
++            goto err;
++        }
++        if (!BN_usub(y, group->field, y))
++            goto err;
++    }
++    if (y_bit != BN_is_odd(y)) {
++        ECerr(EC_F_EC_GFP_SIMPLE_SET_COMPRESSED_COORDINATES,
++              ERR_R_INTERNAL_ERROR);
++        goto err;
++    }
++
++    if (!EC_POINT_set_affine_coordinates_GFp(group, point, x, y, ctx))
++        goto err;
++
++    ret = 1;
++
++ err:
++    BN_CTX_end(ctx);
++    BN_CTX_free(new_ctx);
++    return ret;
++}
++
++size_t ec_GFp_simple_point2oct(const EC_GROUP *group, const EC_POINT *point,
++                               point_conversion_form_t form,
++                               unsigned char *buf, size_t len, BN_CTX *ctx)
++{
++    size_t ret;
++    BN_CTX *new_ctx = NULL;
++    int used_ctx = 0;
++    BIGNUM *x, *y;
++    size_t field_len, i, skip;
++
++    if ((form != POINT_CONVERSION_COMPRESSED)
++        && (form != POINT_CONVERSION_UNCOMPRESSED)
++        && (form != POINT_CONVERSION_HYBRID)) {
++        ECerr(EC_F_EC_GFP_SIMPLE_POINT2OCT, EC_R_INVALID_FORM);
++        goto err;
++    }
++
++    if (EC_POINT_is_at_infinity(group, point)) {
++        /* encodes to a single 0 octet */
++        if (buf != NULL) {
++            if (len < 1) {
++                ECerr(EC_F_EC_GFP_SIMPLE_POINT2OCT, EC_R_BUFFER_TOO_SMALL);
++                return 0;
++            }
++            buf[0] = 0;
++        }
++        return 1;
++    }
++
++    /* ret := required output buffer length */
++    field_len = BN_num_bytes(group->field);
++    ret =
++        (form ==
++         POINT_CONVERSION_COMPRESSED) ? 1 + field_len : 1 + 2 * field_len;
++
++    /* if 'buf' is NULL, just return required length */
++    if (buf != NULL) {
++        if (len < ret) {
++            ECerr(EC_F_EC_GFP_SIMPLE_POINT2OCT, EC_R_BUFFER_TOO_SMALL);
++            goto err;
++        }
++
++        if (ctx == NULL) {
++            ctx = new_ctx = BN_CTX_new();
++            if (ctx == NULL)
++                return 0;
++        }
++
++        BN_CTX_start(ctx);
++        used_ctx = 1;
++        x = BN_CTX_get(ctx);
++        y = BN_CTX_get(ctx);
++        if (y == NULL)
++            goto err;
++
++        if (!EC_POINT_get_affine_coordinates_GFp(group, point, x, y, ctx))
++            goto err;
++
++        if ((form == POINT_CONVERSION_COMPRESSED
++             || form == POINT_CONVERSION_HYBRID) && BN_is_odd(y))
++            buf[0] = form + 1;
++        else
++            buf[0] = form;
++
++        i = 1;
++
++        skip = field_len - BN_num_bytes(x);
++        if (skip > field_len) {
++            ECerr(EC_F_EC_GFP_SIMPLE_POINT2OCT, ERR_R_INTERNAL_ERROR);
++            goto err;
++        }
++        while (skip > 0) {
++            buf[i++] = 0;
++            skip--;
++        }
++        skip = BN_bn2bin(x, buf + i);
++        i += skip;
++        if (i != 1 + field_len) {
++            ECerr(EC_F_EC_GFP_SIMPLE_POINT2OCT, ERR_R_INTERNAL_ERROR);
++            goto err;
++        }
++
++        if (form == POINT_CONVERSION_UNCOMPRESSED
++            || form == POINT_CONVERSION_HYBRID) {
++            skip = field_len - BN_num_bytes(y);
++            if (skip > field_len) {
++                ECerr(EC_F_EC_GFP_SIMPLE_POINT2OCT, ERR_R_INTERNAL_ERROR);
++                goto err;
++            }
++            while (skip > 0) {
++                buf[i++] = 0;
++                skip--;
++            }
++            skip = BN_bn2bin(y, buf + i);
++            i += skip;
++        }
++
++        if (i != ret) {
++            ECerr(EC_F_EC_GFP_SIMPLE_POINT2OCT, ERR_R_INTERNAL_ERROR);
++            goto err;
++        }
++    }
++
++    if (used_ctx)
++        BN_CTX_end(ctx);
++    BN_CTX_free(new_ctx);
++    return ret;
++
++ err:
++    if (used_ctx)
++        BN_CTX_end(ctx);
++    BN_CTX_free(new_ctx);
++    return 0;
++}
++
++int ec_GFp_simple_oct2point(const EC_GROUP *group, EC_POINT *point,
++                            const unsigned char *buf, size_t len, BN_CTX *ctx)
++{
++    point_conversion_form_t form;
++    int y_bit;
++    BN_CTX *new_ctx = NULL;
++    BIGNUM *x, *y;
++    size_t field_len, enc_len;
++    int ret = 0;
++
++    if (len == 0) {
++        ECerr(EC_F_EC_GFP_SIMPLE_OCT2POINT, EC_R_BUFFER_TOO_SMALL);
++        return 0;
++    }
++    form = buf[0];
++    y_bit = form & 1;
++    form = form & ~1U;
++    if ((form != 0) && (form != POINT_CONVERSION_COMPRESSED)
++        && (form != POINT_CONVERSION_UNCOMPRESSED)
++        && (form != POINT_CONVERSION_HYBRID)) {
++        ECerr(EC_F_EC_GFP_SIMPLE_OCT2POINT, EC_R_INVALID_ENCODING);
++        return 0;
++    }
++    if ((form == 0 || form == POINT_CONVERSION_UNCOMPRESSED) && y_bit) {
++        ECerr(EC_F_EC_GFP_SIMPLE_OCT2POINT, EC_R_INVALID_ENCODING);
++        return 0;
++    }
++
++    if (form == 0) {
++        if (len != 1) {
++            ECerr(EC_F_EC_GFP_SIMPLE_OCT2POINT, EC_R_INVALID_ENCODING);
++            return 0;
++        }
++
++        return EC_POINT_set_to_infinity(group, point);
++    }
++
++    field_len = BN_num_bytes(group->field);
++    enc_len =
++        (form ==
++         POINT_CONVERSION_COMPRESSED) ? 1 + field_len : 1 + 2 * field_len;
++
++    if (len != enc_len) {
++        ECerr(EC_F_EC_GFP_SIMPLE_OCT2POINT, EC_R_INVALID_ENCODING);
++        return 0;
++    }
++
++    if (ctx == NULL) {
++        ctx = new_ctx = BN_CTX_new();
++        if (ctx == NULL)
++            return 0;
++    }
++
++    BN_CTX_start(ctx);
++    x = BN_CTX_get(ctx);
++    y = BN_CTX_get(ctx);
++    if (y == NULL)
++        goto err;
++
++    if (!BN_bin2bn(buf + 1, field_len, x))
++        goto err;
++    if (BN_ucmp(x, group->field) >= 0) {
++        ECerr(EC_F_EC_GFP_SIMPLE_OCT2POINT, EC_R_INVALID_ENCODING);
++        goto err;
++    }
++
++    if (form == POINT_CONVERSION_COMPRESSED) {
++        if (!EC_POINT_set_compressed_coordinates_GFp
++            (group, point, x, y_bit, ctx))
++            goto err;
++    } else {
++        if (!BN_bin2bn(buf + 1 + field_len, field_len, y))
++            goto err;
++        if (BN_ucmp(y, group->field) >= 0) {
++            ECerr(EC_F_EC_GFP_SIMPLE_OCT2POINT, EC_R_INVALID_ENCODING);
++            goto err;
++        }
++        if (form == POINT_CONVERSION_HYBRID) {
++            if (y_bit != BN_is_odd(y)) {
++                ECerr(EC_F_EC_GFP_SIMPLE_OCT2POINT, EC_R_INVALID_ENCODING);
++                goto err;
++            }
++        }
++
++        /*
++         * EC_POINT_set_affine_coordinates_GFp is responsible for checking that
++         * the point is on the curve.
++         */
++        if (!EC_POINT_set_affine_coordinates_GFp(group, point, x, y, ctx))
++            goto err;
++    }
++
++    ret = 1;
++
++ err:
++    BN_CTX_end(ctx);
++    BN_CTX_free(new_ctx);
++    return ret;
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/ec/ecp_smpl.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/ec/ecp_smpl.c
+new file mode 100644
+index 0000000..76e0caf
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/ec/ecp_smpl.c
+@@ -0,0 +1,1369 @@
++/*
++ * Copyright 2001-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++/* ====================================================================
++ * Copyright 2002 Sun Microsystems, Inc. ALL RIGHTS RESERVED.
++ * Portions of this software developed by SUN MICROSYSTEMS, INC.,
++ * and contributed to the OpenSSL project.
++ */
++
++#include 
++#include 
++
++#include "ec_lcl.h"
++
++const EC_METHOD *EC_GFp_simple_method(void)
++{
++    static const EC_METHOD ret = {
++        EC_FLAGS_DEFAULT_OCT,
++        NID_X9_62_prime_field,
++        ec_GFp_simple_group_init,
++        ec_GFp_simple_group_finish,
++        ec_GFp_simple_group_clear_finish,
++        ec_GFp_simple_group_copy,
++        ec_GFp_simple_group_set_curve,
++        ec_GFp_simple_group_get_curve,
++        ec_GFp_simple_group_get_degree,
++        ec_group_simple_order_bits,
++        ec_GFp_simple_group_check_discriminant,
++        ec_GFp_simple_point_init,
++        ec_GFp_simple_point_finish,
++        ec_GFp_simple_point_clear_finish,
++        ec_GFp_simple_point_copy,
++        ec_GFp_simple_point_set_to_infinity,
++        ec_GFp_simple_set_Jprojective_coordinates_GFp,
++        ec_GFp_simple_get_Jprojective_coordinates_GFp,
++        ec_GFp_simple_point_set_affine_coordinates,
++        ec_GFp_simple_point_get_affine_coordinates,
++        0, 0, 0,
++        ec_GFp_simple_add,
++        ec_GFp_simple_dbl,
++        ec_GFp_simple_invert,
++        ec_GFp_simple_is_at_infinity,
++        ec_GFp_simple_is_on_curve,
++        ec_GFp_simple_cmp,
++        ec_GFp_simple_make_affine,
++        ec_GFp_simple_points_make_affine,
++        0 /* mul */ ,
++        0 /* precompute_mult */ ,
++        0 /* have_precompute_mult */ ,
++        ec_GFp_simple_field_mul,
++        ec_GFp_simple_field_sqr,
++        0 /* field_div */ ,
++        0 /* field_encode */ ,
++        0 /* field_decode */ ,
++        0,                      /* field_set_to_one */
++        ec_key_simple_priv2oct,
++        ec_key_simple_oct2priv,
++        0, /* set private */
++        ec_key_simple_generate_key,
++        ec_key_simple_check_key,
++        ec_key_simple_generate_public_key,
++        0, /* keycopy */
++        0, /* keyfinish */
++        ecdh_simple_compute_key
++    };
++
++    return &ret;
++}
++
++/*
++ * Most method functions in this file are designed to work with
++ * non-trivial representations of field elements if necessary
++ * (see ecp_mont.c): while standard modular addition and subtraction
++ * are used, the field_mul and field_sqr methods will be used for
++ * multiplication, and field_encode and field_decode (if defined)
++ * will be used for converting between representations.
++ *
++ * Functions ec_GFp_simple_points_make_affine() and
++ * ec_GFp_simple_point_get_affine_coordinates() specifically assume
++ * that if a non-trivial representation is used, it is a Montgomery
++ * representation (i.e. 'encoding' means multiplying by some factor R).
++ */
++
++int ec_GFp_simple_group_init(EC_GROUP *group)
++{
++    group->field = BN_new();
++    group->a = BN_new();
++    group->b = BN_new();
++    if (group->field == NULL || group->a == NULL || group->b == NULL) {
++        BN_free(group->field);
++        BN_free(group->a);
++        BN_free(group->b);
++        return 0;
++    }
++    group->a_is_minus3 = 0;
++    return 1;
++}
++
++void ec_GFp_simple_group_finish(EC_GROUP *group)
++{
++    BN_free(group->field);
++    BN_free(group->a);
++    BN_free(group->b);
++}
++
++void ec_GFp_simple_group_clear_finish(EC_GROUP *group)
++{
++    BN_clear_free(group->field);
++    BN_clear_free(group->a);
++    BN_clear_free(group->b);
++}
++
++int ec_GFp_simple_group_copy(EC_GROUP *dest, const EC_GROUP *src)
++{
++    if (!BN_copy(dest->field, src->field))
++        return 0;
++    if (!BN_copy(dest->a, src->a))
++        return 0;
++    if (!BN_copy(dest->b, src->b))
++        return 0;
++
++    dest->a_is_minus3 = src->a_is_minus3;
++
++    return 1;
++}
++
++int ec_GFp_simple_group_set_curve(EC_GROUP *group,
++                                  const BIGNUM *p, const BIGNUM *a,
++                                  const BIGNUM *b, BN_CTX *ctx)
++{
++    int ret = 0;
++    BN_CTX *new_ctx = NULL;
++    BIGNUM *tmp_a;
++
++    /* p must be a prime > 3 */
++    if (BN_num_bits(p) <= 2 || !BN_is_odd(p)) {
++        ECerr(EC_F_EC_GFP_SIMPLE_GROUP_SET_CURVE, EC_R_INVALID_FIELD);
++        return 0;
++    }
++
++    if (ctx == NULL) {
++        ctx = new_ctx = BN_CTX_new();
++        if (ctx == NULL)
++            return 0;
++    }
++
++    BN_CTX_start(ctx);
++    tmp_a = BN_CTX_get(ctx);
++    if (tmp_a == NULL)
++        goto err;
++
++    /* group->field */
++    if (!BN_copy(group->field, p))
++        goto err;
++    BN_set_negative(group->field, 0);
++
++    /* group->a */
++    if (!BN_nnmod(tmp_a, a, p, ctx))
++        goto err;
++    if (group->meth->field_encode) {
++        if (!group->meth->field_encode(group, group->a, tmp_a, ctx))
++            goto err;
++    } else if (!BN_copy(group->a, tmp_a))
++        goto err;
++
++    /* group->b */
++    if (!BN_nnmod(group->b, b, p, ctx))
++        goto err;
++    if (group->meth->field_encode)
++        if (!group->meth->field_encode(group, group->b, group->b, ctx))
++            goto err;
++
++    /* group->a_is_minus3 */
++    if (!BN_add_word(tmp_a, 3))
++        goto err;
++    group->a_is_minus3 = (0 == BN_cmp(tmp_a, group->field));
++
++    ret = 1;
++
++ err:
++    BN_CTX_end(ctx);
++    BN_CTX_free(new_ctx);
++    return ret;
++}
++
++int ec_GFp_simple_group_get_curve(const EC_GROUP *group, BIGNUM *p, BIGNUM *a,
++                                  BIGNUM *b, BN_CTX *ctx)
++{
++    int ret = 0;
++    BN_CTX *new_ctx = NULL;
++
++    if (p != NULL) {
++        if (!BN_copy(p, group->field))
++            return 0;
++    }
++
++    if (a != NULL || b != NULL) {
++        if (group->meth->field_decode) {
++            if (ctx == NULL) {
++                ctx = new_ctx = BN_CTX_new();
++                if (ctx == NULL)
++                    return 0;
++            }
++            if (a != NULL) {
++                if (!group->meth->field_decode(group, a, group->a, ctx))
++                    goto err;
++            }
++            if (b != NULL) {
++                if (!group->meth->field_decode(group, b, group->b, ctx))
++                    goto err;
++            }
++        } else {
++            if (a != NULL) {
++                if (!BN_copy(a, group->a))
++                    goto err;
++            }
++            if (b != NULL) {
++                if (!BN_copy(b, group->b))
++                    goto err;
++            }
++        }
++    }
++
++    ret = 1;
++
++ err:
++    BN_CTX_free(new_ctx);
++    return ret;
++}
++
++int ec_GFp_simple_group_get_degree(const EC_GROUP *group)
++{
++    return BN_num_bits(group->field);
++}
++
++int ec_GFp_simple_group_check_discriminant(const EC_GROUP *group, BN_CTX *ctx)
++{
++    int ret = 0;
++    BIGNUM *a, *b, *order, *tmp_1, *tmp_2;
++    const BIGNUM *p = group->field;
++    BN_CTX *new_ctx = NULL;
++
++    if (ctx == NULL) {
++        ctx = new_ctx = BN_CTX_new();
++        if (ctx == NULL) {
++            ECerr(EC_F_EC_GFP_SIMPLE_GROUP_CHECK_DISCRIMINANT,
++                  ERR_R_MALLOC_FAILURE);
++            goto err;
++        }
++    }
++    BN_CTX_start(ctx);
++    a = BN_CTX_get(ctx);
++    b = BN_CTX_get(ctx);
++    tmp_1 = BN_CTX_get(ctx);
++    tmp_2 = BN_CTX_get(ctx);
++    order = BN_CTX_get(ctx);
++    if (order == NULL)
++        goto err;
++
++    if (group->meth->field_decode) {
++        if (!group->meth->field_decode(group, a, group->a, ctx))
++            goto err;
++        if (!group->meth->field_decode(group, b, group->b, ctx))
++            goto err;
++    } else {
++        if (!BN_copy(a, group->a))
++            goto err;
++        if (!BN_copy(b, group->b))
++            goto err;
++    }
++
++    /*-
++     * check the discriminant:
++     * y^2 = x^3 + a*x + b is an elliptic curve <=> 4*a^3 + 27*b^2 != 0 (mod p)
++     * 0 =< a, b < p
++     */
++    if (BN_is_zero(a)) {
++        if (BN_is_zero(b))
++            goto err;
++    } else if (!BN_is_zero(b)) {
++        if (!BN_mod_sqr(tmp_1, a, p, ctx))
++            goto err;
++        if (!BN_mod_mul(tmp_2, tmp_1, a, p, ctx))
++            goto err;
++        if (!BN_lshift(tmp_1, tmp_2, 2))
++            goto err;
++        /* tmp_1 = 4*a^3 */
++
++        if (!BN_mod_sqr(tmp_2, b, p, ctx))
++            goto err;
++        if (!BN_mul_word(tmp_2, 27))
++            goto err;
++        /* tmp_2 = 27*b^2 */
++
++        if (!BN_mod_add(a, tmp_1, tmp_2, p, ctx))
++            goto err;
++        if (BN_is_zero(a))
++            goto err;
++    }
++    ret = 1;
++
++ err:
++    if (ctx != NULL)
++        BN_CTX_end(ctx);
++    BN_CTX_free(new_ctx);
++    return ret;
++}
++
++int ec_GFp_simple_point_init(EC_POINT *point)
++{
++    point->X = BN_new();
++    point->Y = BN_new();
++    point->Z = BN_new();
++    point->Z_is_one = 0;
++
++    if (point->X == NULL || point->Y == NULL || point->Z == NULL) {
++        BN_free(point->X);
++        BN_free(point->Y);
++        BN_free(point->Z);
++        return 0;
++    }
++    return 1;
++}
++
++void ec_GFp_simple_point_finish(EC_POINT *point)
++{
++    BN_free(point->X);
++    BN_free(point->Y);
++    BN_free(point->Z);
++}
++
++void ec_GFp_simple_point_clear_finish(EC_POINT *point)
++{
++    BN_clear_free(point->X);
++    BN_clear_free(point->Y);
++    BN_clear_free(point->Z);
++    point->Z_is_one = 0;
++}
++
++int ec_GFp_simple_point_copy(EC_POINT *dest, const EC_POINT *src)
++{
++    if (!BN_copy(dest->X, src->X))
++        return 0;
++    if (!BN_copy(dest->Y, src->Y))
++        return 0;
++    if (!BN_copy(dest->Z, src->Z))
++        return 0;
++    dest->Z_is_one = src->Z_is_one;
++
++    return 1;
++}
++
++int ec_GFp_simple_point_set_to_infinity(const EC_GROUP *group,
++                                        EC_POINT *point)
++{
++    point->Z_is_one = 0;
++    BN_zero(point->Z);
++    return 1;
++}
++
++int ec_GFp_simple_set_Jprojective_coordinates_GFp(const EC_GROUP *group,
++                                                  EC_POINT *point,
++                                                  const BIGNUM *x,
++                                                  const BIGNUM *y,
++                                                  const BIGNUM *z,
++                                                  BN_CTX *ctx)
++{
++    BN_CTX *new_ctx = NULL;
++    int ret = 0;
++
++    if (ctx == NULL) {
++        ctx = new_ctx = BN_CTX_new();
++        if (ctx == NULL)
++            return 0;
++    }
++
++    if (x != NULL) {
++        if (!BN_nnmod(point->X, x, group->field, ctx))
++            goto err;
++        if (group->meth->field_encode) {
++            if (!group->meth->field_encode(group, point->X, point->X, ctx))
++                goto err;
++        }
++    }
++
++    if (y != NULL) {
++        if (!BN_nnmod(point->Y, y, group->field, ctx))
++            goto err;
++        if (group->meth->field_encode) {
++            if (!group->meth->field_encode(group, point->Y, point->Y, ctx))
++                goto err;
++        }
++    }
++
++    if (z != NULL) {
++        int Z_is_one;
++
++        if (!BN_nnmod(point->Z, z, group->field, ctx))
++            goto err;
++        Z_is_one = BN_is_one(point->Z);
++        if (group->meth->field_encode) {
++            if (Z_is_one && (group->meth->field_set_to_one != 0)) {
++                if (!group->meth->field_set_to_one(group, point->Z, ctx))
++                    goto err;
++            } else {
++                if (!group->
++                    meth->field_encode(group, point->Z, point->Z, ctx))
++                    goto err;
++            }
++        }
++        point->Z_is_one = Z_is_one;
++    }
++
++    ret = 1;
++
++ err:
++    BN_CTX_free(new_ctx);
++    return ret;
++}
++
++int ec_GFp_simple_get_Jprojective_coordinates_GFp(const EC_GROUP *group,
++                                                  const EC_POINT *point,
++                                                  BIGNUM *x, BIGNUM *y,
++                                                  BIGNUM *z, BN_CTX *ctx)
++{
++    BN_CTX *new_ctx = NULL;
++    int ret = 0;
++
++    if (group->meth->field_decode != 0) {
++        if (ctx == NULL) {
++            ctx = new_ctx = BN_CTX_new();
++            if (ctx == NULL)
++                return 0;
++        }
++
++        if (x != NULL) {
++            if (!group->meth->field_decode(group, x, point->X, ctx))
++                goto err;
++        }
++        if (y != NULL) {
++            if (!group->meth->field_decode(group, y, point->Y, ctx))
++                goto err;
++        }
++        if (z != NULL) {
++            if (!group->meth->field_decode(group, z, point->Z, ctx))
++                goto err;
++        }
++    } else {
++        if (x != NULL) {
++            if (!BN_copy(x, point->X))
++                goto err;
++        }
++        if (y != NULL) {
++            if (!BN_copy(y, point->Y))
++                goto err;
++        }
++        if (z != NULL) {
++            if (!BN_copy(z, point->Z))
++                goto err;
++        }
++    }
++
++    ret = 1;
++
++ err:
++    BN_CTX_free(new_ctx);
++    return ret;
++}
++
++int ec_GFp_simple_point_set_affine_coordinates(const EC_GROUP *group,
++                                               EC_POINT *point,
++                                               const BIGNUM *x,
++                                               const BIGNUM *y, BN_CTX *ctx)
++{
++    if (x == NULL || y == NULL) {
++        /*
++         * unlike for projective coordinates, we do not tolerate this
++         */
++        ECerr(EC_F_EC_GFP_SIMPLE_POINT_SET_AFFINE_COORDINATES,
++              ERR_R_PASSED_NULL_PARAMETER);
++        return 0;
++    }
++
++    return EC_POINT_set_Jprojective_coordinates_GFp(group, point, x, y,
++                                                    BN_value_one(), ctx);
++}
++
++int ec_GFp_simple_point_get_affine_coordinates(const EC_GROUP *group,
++                                               const EC_POINT *point,
++                                               BIGNUM *x, BIGNUM *y,
++                                               BN_CTX *ctx)
++{
++    BN_CTX *new_ctx = NULL;
++    BIGNUM *Z, *Z_1, *Z_2, *Z_3;
++    const BIGNUM *Z_;
++    int ret = 0;
++
++    if (EC_POINT_is_at_infinity(group, point)) {
++        ECerr(EC_F_EC_GFP_SIMPLE_POINT_GET_AFFINE_COORDINATES,
++              EC_R_POINT_AT_INFINITY);
++        return 0;
++    }
++
++    if (ctx == NULL) {
++        ctx = new_ctx = BN_CTX_new();
++        if (ctx == NULL)
++            return 0;
++    }
++
++    BN_CTX_start(ctx);
++    Z = BN_CTX_get(ctx);
++    Z_1 = BN_CTX_get(ctx);
++    Z_2 = BN_CTX_get(ctx);
++    Z_3 = BN_CTX_get(ctx);
++    if (Z_3 == NULL)
++        goto err;
++
++    /* transform  (X, Y, Z)  into  (x, y) := (X/Z^2, Y/Z^3) */
++
++    if (group->meth->field_decode) {
++        if (!group->meth->field_decode(group, Z, point->Z, ctx))
++            goto err;
++        Z_ = Z;
++    } else {
++        Z_ = point->Z;
++    }
++
++    if (BN_is_one(Z_)) {
++        if (group->meth->field_decode) {
++            if (x != NULL) {
++                if (!group->meth->field_decode(group, x, point->X, ctx))
++                    goto err;
++            }
++            if (y != NULL) {
++                if (!group->meth->field_decode(group, y, point->Y, ctx))
++                    goto err;
++            }
++        } else {
++            if (x != NULL) {
++                if (!BN_copy(x, point->X))
++                    goto err;
++            }
++            if (y != NULL) {
++                if (!BN_copy(y, point->Y))
++                    goto err;
++            }
++        }
++    } else {
++        if (!BN_mod_inverse(Z_1, Z_, group->field, ctx)) {
++            ECerr(EC_F_EC_GFP_SIMPLE_POINT_GET_AFFINE_COORDINATES,
++                  ERR_R_BN_LIB);
++            goto err;
++        }
++
++        if (group->meth->field_encode == 0) {
++            /* field_sqr works on standard representation */
++            if (!group->meth->field_sqr(group, Z_2, Z_1, ctx))
++                goto err;
++        } else {
++            if (!BN_mod_sqr(Z_2, Z_1, group->field, ctx))
++                goto err;
++        }
++
++        if (x != NULL) {
++            /*
++             * in the Montgomery case, field_mul will cancel out Montgomery
++             * factor in X:
++             */
++            if (!group->meth->field_mul(group, x, point->X, Z_2, ctx))
++                goto err;
++        }
++
++        if (y != NULL) {
++            if (group->meth->field_encode == 0) {
++                /*
++                 * field_mul works on standard representation
++                 */
++                if (!group->meth->field_mul(group, Z_3, Z_2, Z_1, ctx))
++                    goto err;
++            } else {
++                if (!BN_mod_mul(Z_3, Z_2, Z_1, group->field, ctx))
++                    goto err;
++            }
++
++            /*
++             * in the Montgomery case, field_mul will cancel out Montgomery
++             * factor in Y:
++             */
++            if (!group->meth->field_mul(group, y, point->Y, Z_3, ctx))
++                goto err;
++        }
++    }
++
++    ret = 1;
++
++ err:
++    BN_CTX_end(ctx);
++    BN_CTX_free(new_ctx);
++    return ret;
++}
++
++int ec_GFp_simple_add(const EC_GROUP *group, EC_POINT *r, const EC_POINT *a,
++                      const EC_POINT *b, BN_CTX *ctx)
++{
++    int (*field_mul) (const EC_GROUP *, BIGNUM *, const BIGNUM *,
++                      const BIGNUM *, BN_CTX *);
++    int (*field_sqr) (const EC_GROUP *, BIGNUM *, const BIGNUM *, BN_CTX *);
++    const BIGNUM *p;
++    BN_CTX *new_ctx = NULL;
++    BIGNUM *n0, *n1, *n2, *n3, *n4, *n5, *n6;
++    int ret = 0;
++
++    if (a == b)
++        return EC_POINT_dbl(group, r, a, ctx);
++    if (EC_POINT_is_at_infinity(group, a))
++        return EC_POINT_copy(r, b);
++    if (EC_POINT_is_at_infinity(group, b))
++        return EC_POINT_copy(r, a);
++
++    field_mul = group->meth->field_mul;
++    field_sqr = group->meth->field_sqr;
++    p = group->field;
++
++    if (ctx == NULL) {
++        ctx = new_ctx = BN_CTX_new();
++        if (ctx == NULL)
++            return 0;
++    }
++
++    BN_CTX_start(ctx);
++    n0 = BN_CTX_get(ctx);
++    n1 = BN_CTX_get(ctx);
++    n2 = BN_CTX_get(ctx);
++    n3 = BN_CTX_get(ctx);
++    n4 = BN_CTX_get(ctx);
++    n5 = BN_CTX_get(ctx);
++    n6 = BN_CTX_get(ctx);
++    if (n6 == NULL)
++        goto end;
++
++    /*
++     * Note that in this function we must not read components of 'a' or 'b'
++     * once we have written the corresponding components of 'r'. ('r' might
++     * be one of 'a' or 'b'.)
++     */
++
++    /* n1, n2 */
++    if (b->Z_is_one) {
++        if (!BN_copy(n1, a->X))
++            goto end;
++        if (!BN_copy(n2, a->Y))
++            goto end;
++        /* n1 = X_a */
++        /* n2 = Y_a */
++    } else {
++        if (!field_sqr(group, n0, b->Z, ctx))
++            goto end;
++        if (!field_mul(group, n1, a->X, n0, ctx))
++            goto end;
++        /* n1 = X_a * Z_b^2 */
++
++        if (!field_mul(group, n0, n0, b->Z, ctx))
++            goto end;
++        if (!field_mul(group, n2, a->Y, n0, ctx))
++            goto end;
++        /* n2 = Y_a * Z_b^3 */
++    }
++
++    /* n3, n4 */
++    if (a->Z_is_one) {
++        if (!BN_copy(n3, b->X))
++            goto end;
++        if (!BN_copy(n4, b->Y))
++            goto end;
++        /* n3 = X_b */
++        /* n4 = Y_b */
++    } else {
++        if (!field_sqr(group, n0, a->Z, ctx))
++            goto end;
++        if (!field_mul(group, n3, b->X, n0, ctx))
++            goto end;
++        /* n3 = X_b * Z_a^2 */
++
++        if (!field_mul(group, n0, n0, a->Z, ctx))
++            goto end;
++        if (!field_mul(group, n4, b->Y, n0, ctx))
++            goto end;
++        /* n4 = Y_b * Z_a^3 */
++    }
++
++    /* n5, n6 */
++    if (!BN_mod_sub_quick(n5, n1, n3, p))
++        goto end;
++    if (!BN_mod_sub_quick(n6, n2, n4, p))
++        goto end;
++    /* n5 = n1 - n3 */
++    /* n6 = n2 - n4 */
++
++    if (BN_is_zero(n5)) {
++        if (BN_is_zero(n6)) {
++            /* a is the same point as b */
++            BN_CTX_end(ctx);
++            ret = EC_POINT_dbl(group, r, a, ctx);
++            ctx = NULL;
++            goto end;
++        } else {
++            /* a is the inverse of b */
++            BN_zero(r->Z);
++            r->Z_is_one = 0;
++            ret = 1;
++            goto end;
++        }
++    }
++
++    /* 'n7', 'n8' */
++    if (!BN_mod_add_quick(n1, n1, n3, p))
++        goto end;
++    if (!BN_mod_add_quick(n2, n2, n4, p))
++        goto end;
++    /* 'n7' = n1 + n3 */
++    /* 'n8' = n2 + n4 */
++
++    /* Z_r */
++    if (a->Z_is_one && b->Z_is_one) {
++        if (!BN_copy(r->Z, n5))
++            goto end;
++    } else {
++        if (a->Z_is_one) {
++            if (!BN_copy(n0, b->Z))
++                goto end;
++        } else if (b->Z_is_one) {
++            if (!BN_copy(n0, a->Z))
++                goto end;
++        } else {
++            if (!field_mul(group, n0, a->Z, b->Z, ctx))
++                goto end;
++        }
++        if (!field_mul(group, r->Z, n0, n5, ctx))
++            goto end;
++    }
++    r->Z_is_one = 0;
++    /* Z_r = Z_a * Z_b * n5 */
++
++    /* X_r */
++    if (!field_sqr(group, n0, n6, ctx))
++        goto end;
++    if (!field_sqr(group, n4, n5, ctx))
++        goto end;
++    if (!field_mul(group, n3, n1, n4, ctx))
++        goto end;
++    if (!BN_mod_sub_quick(r->X, n0, n3, p))
++        goto end;
++    /* X_r = n6^2 - n5^2 * 'n7' */
++
++    /* 'n9' */
++    if (!BN_mod_lshift1_quick(n0, r->X, p))
++        goto end;
++    if (!BN_mod_sub_quick(n0, n3, n0, p))
++        goto end;
++    /* n9 = n5^2 * 'n7' - 2 * X_r */
++
++    /* Y_r */
++    if (!field_mul(group, n0, n0, n6, ctx))
++        goto end;
++    if (!field_mul(group, n5, n4, n5, ctx))
++        goto end;               /* now n5 is n5^3 */
++    if (!field_mul(group, n1, n2, n5, ctx))
++        goto end;
++    if (!BN_mod_sub_quick(n0, n0, n1, p))
++        goto end;
++    if (BN_is_odd(n0))
++        if (!BN_add(n0, n0, p))
++            goto end;
++    /* now  0 <= n0 < 2*p,  and n0 is even */
++    if (!BN_rshift1(r->Y, n0))
++        goto end;
++    /* Y_r = (n6 * 'n9' - 'n8' * 'n5^3') / 2 */
++
++    ret = 1;
++
++ end:
++    if (ctx)                    /* otherwise we already called BN_CTX_end */
++        BN_CTX_end(ctx);
++    BN_CTX_free(new_ctx);
++    return ret;
++}
++
++int ec_GFp_simple_dbl(const EC_GROUP *group, EC_POINT *r, const EC_POINT *a,
++                      BN_CTX *ctx)
++{
++    int (*field_mul) (const EC_GROUP *, BIGNUM *, const BIGNUM *,
++                      const BIGNUM *, BN_CTX *);
++    int (*field_sqr) (const EC_GROUP *, BIGNUM *, const BIGNUM *, BN_CTX *);
++    const BIGNUM *p;
++    BN_CTX *new_ctx = NULL;
++    BIGNUM *n0, *n1, *n2, *n3;
++    int ret = 0;
++
++    if (EC_POINT_is_at_infinity(group, a)) {
++        BN_zero(r->Z);
++        r->Z_is_one = 0;
++        return 1;
++    }
++
++    field_mul = group->meth->field_mul;
++    field_sqr = group->meth->field_sqr;
++    p = group->field;
++
++    if (ctx == NULL) {
++        ctx = new_ctx = BN_CTX_new();
++        if (ctx == NULL)
++            return 0;
++    }
++
++    BN_CTX_start(ctx);
++    n0 = BN_CTX_get(ctx);
++    n1 = BN_CTX_get(ctx);
++    n2 = BN_CTX_get(ctx);
++    n3 = BN_CTX_get(ctx);
++    if (n3 == NULL)
++        goto err;
++
++    /*
++     * Note that in this function we must not read components of 'a' once we
++     * have written the corresponding components of 'r'. ('r' might the same
++     * as 'a'.)
++     */
++
++    /* n1 */
++    if (a->Z_is_one) {
++        if (!field_sqr(group, n0, a->X, ctx))
++            goto err;
++        if (!BN_mod_lshift1_quick(n1, n0, p))
++            goto err;
++        if (!BN_mod_add_quick(n0, n0, n1, p))
++            goto err;
++        if (!BN_mod_add_quick(n1, n0, group->a, p))
++            goto err;
++        /* n1 = 3 * X_a^2 + a_curve */
++    } else if (group->a_is_minus3) {
++        if (!field_sqr(group, n1, a->Z, ctx))
++            goto err;
++        if (!BN_mod_add_quick(n0, a->X, n1, p))
++            goto err;
++        if (!BN_mod_sub_quick(n2, a->X, n1, p))
++            goto err;
++        if (!field_mul(group, n1, n0, n2, ctx))
++            goto err;
++        if (!BN_mod_lshift1_quick(n0, n1, p))
++            goto err;
++        if (!BN_mod_add_quick(n1, n0, n1, p))
++            goto err;
++        /*-
++         * n1 = 3 * (X_a + Z_a^2) * (X_a - Z_a^2)
++         *    = 3 * X_a^2 - 3 * Z_a^4
++         */
++    } else {
++        if (!field_sqr(group, n0, a->X, ctx))
++            goto err;
++        if (!BN_mod_lshift1_quick(n1, n0, p))
++            goto err;
++        if (!BN_mod_add_quick(n0, n0, n1, p))
++            goto err;
++        if (!field_sqr(group, n1, a->Z, ctx))
++            goto err;
++        if (!field_sqr(group, n1, n1, ctx))
++            goto err;
++        if (!field_mul(group, n1, n1, group->a, ctx))
++            goto err;
++        if (!BN_mod_add_quick(n1, n1, n0, p))
++            goto err;
++        /* n1 = 3 * X_a^2 + a_curve * Z_a^4 */
++    }
++
++    /* Z_r */
++    if (a->Z_is_one) {
++        if (!BN_copy(n0, a->Y))
++            goto err;
++    } else {
++        if (!field_mul(group, n0, a->Y, a->Z, ctx))
++            goto err;
++    }
++    if (!BN_mod_lshift1_quick(r->Z, n0, p))
++        goto err;
++    r->Z_is_one = 0;
++    /* Z_r = 2 * Y_a * Z_a */
++
++    /* n2 */
++    if (!field_sqr(group, n3, a->Y, ctx))
++        goto err;
++    if (!field_mul(group, n2, a->X, n3, ctx))
++        goto err;
++    if (!BN_mod_lshift_quick(n2, n2, 2, p))
++        goto err;
++    /* n2 = 4 * X_a * Y_a^2 */
++
++    /* X_r */
++    if (!BN_mod_lshift1_quick(n0, n2, p))
++        goto err;
++    if (!field_sqr(group, r->X, n1, ctx))
++        goto err;
++    if (!BN_mod_sub_quick(r->X, r->X, n0, p))
++        goto err;
++    /* X_r = n1^2 - 2 * n2 */
++
++    /* n3 */
++    if (!field_sqr(group, n0, n3, ctx))
++        goto err;
++    if (!BN_mod_lshift_quick(n3, n0, 3, p))
++        goto err;
++    /* n3 = 8 * Y_a^4 */
++
++    /* Y_r */
++    if (!BN_mod_sub_quick(n0, n2, r->X, p))
++        goto err;
++    if (!field_mul(group, n0, n1, n0, ctx))
++        goto err;
++    if (!BN_mod_sub_quick(r->Y, n0, n3, p))
++        goto err;
++    /* Y_r = n1 * (n2 - X_r) - n3 */
++
++    ret = 1;
++
++ err:
++    BN_CTX_end(ctx);
++    BN_CTX_free(new_ctx);
++    return ret;
++}
++
++int ec_GFp_simple_invert(const EC_GROUP *group, EC_POINT *point, BN_CTX *ctx)
++{
++    if (EC_POINT_is_at_infinity(group, point) || BN_is_zero(point->Y))
++        /* point is its own inverse */
++        return 1;
++
++    return BN_usub(point->Y, group->field, point->Y);
++}
++
++int ec_GFp_simple_is_at_infinity(const EC_GROUP *group, const EC_POINT *point)
++{
++    return BN_is_zero(point->Z);
++}
++
++int ec_GFp_simple_is_on_curve(const EC_GROUP *group, const EC_POINT *point,
++                              BN_CTX *ctx)
++{
++    int (*field_mul) (const EC_GROUP *, BIGNUM *, const BIGNUM *,
++                      const BIGNUM *, BN_CTX *);
++    int (*field_sqr) (const EC_GROUP *, BIGNUM *, const BIGNUM *, BN_CTX *);
++    const BIGNUM *p;
++    BN_CTX *new_ctx = NULL;
++    BIGNUM *rh, *tmp, *Z4, *Z6;
++    int ret = -1;
++
++    if (EC_POINT_is_at_infinity(group, point))
++        return 1;
++
++    field_mul = group->meth->field_mul;
++    field_sqr = group->meth->field_sqr;
++    p = group->field;
++
++    if (ctx == NULL) {
++        ctx = new_ctx = BN_CTX_new();
++        if (ctx == NULL)
++            return -1;
++    }
++
++    BN_CTX_start(ctx);
++    rh = BN_CTX_get(ctx);
++    tmp = BN_CTX_get(ctx);
++    Z4 = BN_CTX_get(ctx);
++    Z6 = BN_CTX_get(ctx);
++    if (Z6 == NULL)
++        goto err;
++
++    /*-
++     * We have a curve defined by a Weierstrass equation
++     *      y^2 = x^3 + a*x + b.
++     * The point to consider is given in Jacobian projective coordinates
++     * where  (X, Y, Z)  represents  (x, y) = (X/Z^2, Y/Z^3).
++     * Substituting this and multiplying by  Z^6  transforms the above equation into
++     *      Y^2 = X^3 + a*X*Z^4 + b*Z^6.
++     * To test this, we add up the right-hand side in 'rh'.
++     */
++
++    /* rh := X^2 */
++    if (!field_sqr(group, rh, point->X, ctx))
++        goto err;
++
++    if (!point->Z_is_one) {
++        if (!field_sqr(group, tmp, point->Z, ctx))
++            goto err;
++        if (!field_sqr(group, Z4, tmp, ctx))
++            goto err;
++        if (!field_mul(group, Z6, Z4, tmp, ctx))
++            goto err;
++
++        /* rh := (rh + a*Z^4)*X */
++        if (group->a_is_minus3) {
++            if (!BN_mod_lshift1_quick(tmp, Z4, p))
++                goto err;
++            if (!BN_mod_add_quick(tmp, tmp, Z4, p))
++                goto err;
++            if (!BN_mod_sub_quick(rh, rh, tmp, p))
++                goto err;
++            if (!field_mul(group, rh, rh, point->X, ctx))
++                goto err;
++        } else {
++            if (!field_mul(group, tmp, Z4, group->a, ctx))
++                goto err;
++            if (!BN_mod_add_quick(rh, rh, tmp, p))
++                goto err;
++            if (!field_mul(group, rh, rh, point->X, ctx))
++                goto err;
++        }
++
++        /* rh := rh + b*Z^6 */
++        if (!field_mul(group, tmp, group->b, Z6, ctx))
++            goto err;
++        if (!BN_mod_add_quick(rh, rh, tmp, p))
++            goto err;
++    } else {
++        /* point->Z_is_one */
++
++        /* rh := (rh + a)*X */
++        if (!BN_mod_add_quick(rh, rh, group->a, p))
++            goto err;
++        if (!field_mul(group, rh, rh, point->X, ctx))
++            goto err;
++        /* rh := rh + b */
++        if (!BN_mod_add_quick(rh, rh, group->b, p))
++            goto err;
++    }
++
++    /* 'lh' := Y^2 */
++    if (!field_sqr(group, tmp, point->Y, ctx))
++        goto err;
++
++    ret = (0 == BN_ucmp(tmp, rh));
++
++ err:
++    BN_CTX_end(ctx);
++    BN_CTX_free(new_ctx);
++    return ret;
++}
++
++int ec_GFp_simple_cmp(const EC_GROUP *group, const EC_POINT *a,
++                      const EC_POINT *b, BN_CTX *ctx)
++{
++    /*-
++     * return values:
++     *  -1   error
++     *   0   equal (in affine coordinates)
++     *   1   not equal
++     */
++
++    int (*field_mul) (const EC_GROUP *, BIGNUM *, const BIGNUM *,
++                      const BIGNUM *, BN_CTX *);
++    int (*field_sqr) (const EC_GROUP *, BIGNUM *, const BIGNUM *, BN_CTX *);
++    BN_CTX *new_ctx = NULL;
++    BIGNUM *tmp1, *tmp2, *Za23, *Zb23;
++    const BIGNUM *tmp1_, *tmp2_;
++    int ret = -1;
++
++    if (EC_POINT_is_at_infinity(group, a)) {
++        return EC_POINT_is_at_infinity(group, b) ? 0 : 1;
++    }
++
++    if (EC_POINT_is_at_infinity(group, b))
++        return 1;
++
++    if (a->Z_is_one && b->Z_is_one) {
++        return ((BN_cmp(a->X, b->X) == 0) && BN_cmp(a->Y, b->Y) == 0) ? 0 : 1;
++    }
++
++    field_mul = group->meth->field_mul;
++    field_sqr = group->meth->field_sqr;
++
++    if (ctx == NULL) {
++        ctx = new_ctx = BN_CTX_new();
++        if (ctx == NULL)
++            return -1;
++    }
++
++    BN_CTX_start(ctx);
++    tmp1 = BN_CTX_get(ctx);
++    tmp2 = BN_CTX_get(ctx);
++    Za23 = BN_CTX_get(ctx);
++    Zb23 = BN_CTX_get(ctx);
++    if (Zb23 == NULL)
++        goto end;
++
++    /*-
++     * We have to decide whether
++     *     (X_a/Z_a^2, Y_a/Z_a^3) = (X_b/Z_b^2, Y_b/Z_b^3),
++     * or equivalently, whether
++     *     (X_a*Z_b^2, Y_a*Z_b^3) = (X_b*Z_a^2, Y_b*Z_a^3).
++     */
++
++    if (!b->Z_is_one) {
++        if (!field_sqr(group, Zb23, b->Z, ctx))
++            goto end;
++        if (!field_mul(group, tmp1, a->X, Zb23, ctx))
++            goto end;
++        tmp1_ = tmp1;
++    } else
++        tmp1_ = a->X;
++    if (!a->Z_is_one) {
++        if (!field_sqr(group, Za23, a->Z, ctx))
++            goto end;
++        if (!field_mul(group, tmp2, b->X, Za23, ctx))
++            goto end;
++        tmp2_ = tmp2;
++    } else
++        tmp2_ = b->X;
++
++    /* compare  X_a*Z_b^2  with  X_b*Z_a^2 */
++    if (BN_cmp(tmp1_, tmp2_) != 0) {
++        ret = 1;                /* points differ */
++        goto end;
++    }
++
++    if (!b->Z_is_one) {
++        if (!field_mul(group, Zb23, Zb23, b->Z, ctx))
++            goto end;
++        if (!field_mul(group, tmp1, a->Y, Zb23, ctx))
++            goto end;
++        /* tmp1_ = tmp1 */
++    } else
++        tmp1_ = a->Y;
++    if (!a->Z_is_one) {
++        if (!field_mul(group, Za23, Za23, a->Z, ctx))
++            goto end;
++        if (!field_mul(group, tmp2, b->Y, Za23, ctx))
++            goto end;
++        /* tmp2_ = tmp2 */
++    } else
++        tmp2_ = b->Y;
++
++    /* compare  Y_a*Z_b^3  with  Y_b*Z_a^3 */
++    if (BN_cmp(tmp1_, tmp2_) != 0) {
++        ret = 1;                /* points differ */
++        goto end;
++    }
++
++    /* points are equal */
++    ret = 0;
++
++ end:
++    BN_CTX_end(ctx);
++    BN_CTX_free(new_ctx);
++    return ret;
++}
++
++int ec_GFp_simple_make_affine(const EC_GROUP *group, EC_POINT *point,
++                              BN_CTX *ctx)
++{
++    BN_CTX *new_ctx = NULL;
++    BIGNUM *x, *y;
++    int ret = 0;
++
++    if (point->Z_is_one || EC_POINT_is_at_infinity(group, point))
++        return 1;
++
++    if (ctx == NULL) {
++        ctx = new_ctx = BN_CTX_new();
++        if (ctx == NULL)
++            return 0;
++    }
++
++    BN_CTX_start(ctx);
++    x = BN_CTX_get(ctx);
++    y = BN_CTX_get(ctx);
++    if (y == NULL)
++        goto err;
++
++    if (!EC_POINT_get_affine_coordinates_GFp(group, point, x, y, ctx))
++        goto err;
++    if (!EC_POINT_set_affine_coordinates_GFp(group, point, x, y, ctx))
++        goto err;
++    if (!point->Z_is_one) {
++        ECerr(EC_F_EC_GFP_SIMPLE_MAKE_AFFINE, ERR_R_INTERNAL_ERROR);
++        goto err;
++    }
++
++    ret = 1;
++
++ err:
++    BN_CTX_end(ctx);
++    BN_CTX_free(new_ctx);
++    return ret;
++}
++
++int ec_GFp_simple_points_make_affine(const EC_GROUP *group, size_t num,
++                                     EC_POINT *points[], BN_CTX *ctx)
++{
++    BN_CTX *new_ctx = NULL;
++    BIGNUM *tmp, *tmp_Z;
++    BIGNUM **prod_Z = NULL;
++    size_t i;
++    int ret = 0;
++
++    if (num == 0)
++        return 1;
++
++    if (ctx == NULL) {
++        ctx = new_ctx = BN_CTX_new();
++        if (ctx == NULL)
++            return 0;
++    }
++
++    BN_CTX_start(ctx);
++    tmp = BN_CTX_get(ctx);
++    tmp_Z = BN_CTX_get(ctx);
++    if (tmp == NULL || tmp_Z == NULL)
++        goto err;
++
++    prod_Z = OPENSSL_malloc(num * sizeof prod_Z[0]);
++    if (prod_Z == NULL)
++        goto err;
++    for (i = 0; i < num; i++) {
++        prod_Z[i] = BN_new();
++        if (prod_Z[i] == NULL)
++            goto err;
++    }
++
++    /*
++     * Set each prod_Z[i] to the product of points[0]->Z .. points[i]->Z,
++     * skipping any zero-valued inputs (pretend that they're 1).
++     */
++
++    if (!BN_is_zero(points[0]->Z)) {
++        if (!BN_copy(prod_Z[0], points[0]->Z))
++            goto err;
++    } else {
++        if (group->meth->field_set_to_one != 0) {
++            if (!group->meth->field_set_to_one(group, prod_Z[0], ctx))
++                goto err;
++        } else {
++            if (!BN_one(prod_Z[0]))
++                goto err;
++        }
++    }
++
++    for (i = 1; i < num; i++) {
++        if (!BN_is_zero(points[i]->Z)) {
++            if (!group->
++                meth->field_mul(group, prod_Z[i], prod_Z[i - 1], points[i]->Z,
++                                ctx))
++                goto err;
++        } else {
++            if (!BN_copy(prod_Z[i], prod_Z[i - 1]))
++                goto err;
++        }
++    }
++
++    /*
++     * Now use a single explicit inversion to replace every non-zero
++     * points[i]->Z by its inverse.
++     */
++
++    if (!BN_mod_inverse(tmp, prod_Z[num - 1], group->field, ctx)) {
++        ECerr(EC_F_EC_GFP_SIMPLE_POINTS_MAKE_AFFINE, ERR_R_BN_LIB);
++        goto err;
++    }
++    if (group->meth->field_encode != 0) {
++        /*
++         * In the Montgomery case, we just turned R*H (representing H) into
++         * 1/(R*H), but we need R*(1/H) (representing 1/H); i.e. we need to
++         * multiply by the Montgomery factor twice.
++         */
++        if (!group->meth->field_encode(group, tmp, tmp, ctx))
++            goto err;
++        if (!group->meth->field_encode(group, tmp, tmp, ctx))
++            goto err;
++    }
++
++    for (i = num - 1; i > 0; --i) {
++        /*
++         * Loop invariant: tmp is the product of the inverses of points[0]->Z
++         * .. points[i]->Z (zero-valued inputs skipped).
++         */
++        if (!BN_is_zero(points[i]->Z)) {
++            /*
++             * Set tmp_Z to the inverse of points[i]->Z (as product of Z
++             * inverses 0 .. i, Z values 0 .. i - 1).
++             */
++            if (!group->
++                meth->field_mul(group, tmp_Z, prod_Z[i - 1], tmp, ctx))
++                goto err;
++            /*
++             * Update tmp to satisfy the loop invariant for i - 1.
++             */
++            if (!group->meth->field_mul(group, tmp, tmp, points[i]->Z, ctx))
++                goto err;
++            /* Replace points[i]->Z by its inverse. */
++            if (!BN_copy(points[i]->Z, tmp_Z))
++                goto err;
++        }
++    }
++
++    if (!BN_is_zero(points[0]->Z)) {
++        /* Replace points[0]->Z by its inverse. */
++        if (!BN_copy(points[0]->Z, tmp))
++            goto err;
++    }
++
++    /* Finally, fix up the X and Y coordinates for all points. */
++
++    for (i = 0; i < num; i++) {
++        EC_POINT *p = points[i];
++
++        if (!BN_is_zero(p->Z)) {
++            /* turn  (X, Y, 1/Z)  into  (X/Z^2, Y/Z^3, 1) */
++
++            if (!group->meth->field_sqr(group, tmp, p->Z, ctx))
++                goto err;
++            if (!group->meth->field_mul(group, p->X, p->X, tmp, ctx))
++                goto err;
++
++            if (!group->meth->field_mul(group, tmp, tmp, p->Z, ctx))
++                goto err;
++            if (!group->meth->field_mul(group, p->Y, p->Y, tmp, ctx))
++                goto err;
++
++            if (group->meth->field_set_to_one != 0) {
++                if (!group->meth->field_set_to_one(group, p->Z, ctx))
++                    goto err;
++            } else {
++                if (!BN_one(p->Z))
++                    goto err;
++            }
++            p->Z_is_one = 1;
++        }
++    }
++
++    ret = 1;
++
++ err:
++    BN_CTX_end(ctx);
++    BN_CTX_free(new_ctx);
++    if (prod_Z != NULL) {
++        for (i = 0; i < num; i++) {
++            if (prod_Z[i] == NULL)
++                break;
++            BN_clear_free(prod_Z[i]);
++        }
++        OPENSSL_free(prod_Z);
++    }
++    return ret;
++}
++
++int ec_GFp_simple_field_mul(const EC_GROUP *group, BIGNUM *r, const BIGNUM *a,
++                            const BIGNUM *b, BN_CTX *ctx)
++{
++    return BN_mod_mul(r, a, b, group->field, ctx);
++}
++
++int ec_GFp_simple_field_sqr(const EC_GROUP *group, BIGNUM *r, const BIGNUM *a,
++                            BN_CTX *ctx)
++{
++    return BN_mod_sqr(r, a, group->field, ctx);
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/ec/ecx_meth.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/ec/ecx_meth.c
+new file mode 100644
+index 0000000..06e3911
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/ec/ecx_meth.c
+@@ -0,0 +1,373 @@
++/*
++ * Copyright 2006-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include "internal/cryptlib.h"
++#include 
++#include 
++#include 
++#include "internal/asn1_int.h"
++#include "internal/evp_int.h"
++#include "ec_lcl.h"
++
++#define X25519_KEYLEN        32
++#define X25519_BITS          253
++#define X25519_SECURITY_BITS 128
++
++typedef struct {
++    unsigned char pubkey[X25519_KEYLEN];
++    unsigned char *privkey;
++} X25519_KEY;
++
++typedef enum {
++    X25519_PUBLIC,
++    X25519_PRIVATE,
++    X25519_KEYGEN
++} ecx_key_op_t;
++
++/* Setup EVP_PKEY using public, private or generation */
++static int ecx_key_op(EVP_PKEY *pkey, const X509_ALGOR *palg,
++                      const unsigned char *p, int plen, ecx_key_op_t op)
++{
++    X25519_KEY *xkey;
++
++    if (op != X25519_KEYGEN) {
++        if (palg != NULL) {
++            int ptype;
++
++            /* Algorithm parameters must be absent */
++            X509_ALGOR_get0(NULL, &ptype, NULL, palg);
++            if (ptype != V_ASN1_UNDEF) {
++                ECerr(EC_F_ECX_KEY_OP, EC_R_INVALID_ENCODING);
++                return 0;
++            }
++        }
++
++        if (p == NULL || plen != X25519_KEYLEN) {
++            ECerr(EC_F_ECX_KEY_OP, EC_R_INVALID_ENCODING);
++            return 0;
++        }
++    }
++
++    xkey = OPENSSL_zalloc(sizeof(*xkey));
++    if (xkey == NULL) {
++        ECerr(EC_F_ECX_KEY_OP, ERR_R_MALLOC_FAILURE);
++        return 0;
++    }
++
++    if (op == X25519_PUBLIC) {
++        memcpy(xkey->pubkey, p, plen);
++    } else {
++        xkey->privkey = OPENSSL_secure_malloc(X25519_KEYLEN);
++        if (xkey->privkey == NULL) {
++            ECerr(EC_F_ECX_KEY_OP, ERR_R_MALLOC_FAILURE);
++            OPENSSL_free(xkey);
++            return 0;
++        }
++        if (op == X25519_KEYGEN) {
++            if (RAND_bytes(xkey->privkey, X25519_KEYLEN) <= 0) {
++                OPENSSL_secure_free(xkey->privkey);
++                OPENSSL_free(xkey);
++                return 0;
++            }
++            xkey->privkey[0] &= 248;
++            xkey->privkey[31] &= 127;
++            xkey->privkey[31] |= 64;
++        } else {
++            memcpy(xkey->privkey, p, X25519_KEYLEN);
++        }
++        X25519_public_from_private(xkey->pubkey, xkey->privkey);
++    }
++
++    EVP_PKEY_assign(pkey, NID_X25519, xkey);
++    return 1;
++}
++
++static int ecx_pub_encode(X509_PUBKEY *pk, const EVP_PKEY *pkey)
++{
++    const X25519_KEY *xkey = pkey->pkey.ptr;
++    unsigned char *penc;
++
++    if (xkey == NULL) {
++        ECerr(EC_F_ECX_PUB_ENCODE, EC_R_INVALID_KEY);
++        return 0;
++    }
++
++    penc = OPENSSL_memdup(xkey->pubkey, X25519_KEYLEN);
++    if (penc == NULL) {
++        ECerr(EC_F_ECX_PUB_ENCODE, ERR_R_MALLOC_FAILURE);
++        return 0;
++    }
++
++    if (!X509_PUBKEY_set0_param(pk, OBJ_nid2obj(NID_X25519), V_ASN1_UNDEF,
++                                NULL, penc, X25519_KEYLEN)) {
++        OPENSSL_free(penc);
++        ECerr(EC_F_ECX_PUB_ENCODE, ERR_R_MALLOC_FAILURE);
++        return 0;
++    }
++    return 1;
++}
++
++static int ecx_pub_decode(EVP_PKEY *pkey, X509_PUBKEY *pubkey)
++{
++    const unsigned char *p;
++    int pklen;
++    X509_ALGOR *palg;
++
++    if (!X509_PUBKEY_get0_param(NULL, &p, &pklen, &palg, pubkey))
++        return 0;
++    return ecx_key_op(pkey, palg, p, pklen, X25519_PUBLIC);
++}
++
++static int ecx_pub_cmp(const EVP_PKEY *a, const EVP_PKEY *b)
++{
++    const X25519_KEY *akey = a->pkey.ptr;
++    const X25519_KEY *bkey = b->pkey.ptr;
++
++    if (akey == NULL || bkey == NULL)
++        return -2;
++    return !CRYPTO_memcmp(akey->pubkey, bkey->pubkey, X25519_KEYLEN);
++}
++
++static int ecx_priv_decode(EVP_PKEY *pkey, const PKCS8_PRIV_KEY_INFO *p8)
++{
++    const unsigned char *p;
++    int plen;
++    ASN1_OCTET_STRING *oct = NULL;
++    const X509_ALGOR *palg;
++    int rv;
++
++    if (!PKCS8_pkey_get0(NULL, &p, &plen, &palg, p8))
++        return 0;
++
++    oct = d2i_ASN1_OCTET_STRING(NULL, &p, plen);
++    if (oct == NULL) {
++        p = NULL;
++        plen = 0;
++    } else {
++        p = ASN1_STRING_get0_data(oct);
++        plen = ASN1_STRING_length(oct);
++    }
++
++    rv = ecx_key_op(pkey, palg, p, plen, X25519_PRIVATE);
++    ASN1_OCTET_STRING_free(oct);
++    return rv;
++}
++
++static int ecx_priv_encode(PKCS8_PRIV_KEY_INFO *p8, const EVP_PKEY *pkey)
++{
++    const X25519_KEY *xkey = pkey->pkey.ptr;
++    ASN1_OCTET_STRING oct;
++    unsigned char *penc = NULL;
++    int penclen;
++
++    if (xkey == NULL || xkey->privkey == NULL) {
++        ECerr(EC_F_ECX_PRIV_ENCODE, EC_R_INVALID_PRIVATE_KEY);
++        return 0;
++    }
++
++    oct.data = xkey->privkey;
++    oct.length = X25519_KEYLEN;
++    oct.flags = 0;
++
++    penclen = i2d_ASN1_OCTET_STRING(&oct, &penc);
++    if (penclen < 0) {
++        ECerr(EC_F_ECX_PRIV_ENCODE, ERR_R_MALLOC_FAILURE);
++        return 0;
++    }
++
++    if (!PKCS8_pkey_set0(p8, OBJ_nid2obj(NID_X25519), 0,
++                         V_ASN1_UNDEF, NULL, penc, penclen)) {
++        OPENSSL_clear_free(penc, penclen);
++        ECerr(EC_F_ECX_PRIV_ENCODE, ERR_R_MALLOC_FAILURE);
++        return 0;
++    }
++
++    return 1;
++}
++
++static int ecx_size(const EVP_PKEY *pkey)
++{
++    return X25519_KEYLEN;
++}
++
++static int ecx_bits(const EVP_PKEY *pkey)
++{
++    return X25519_BITS;
++}
++
++static int ecx_security_bits(const EVP_PKEY *pkey)
++{
++    return X25519_SECURITY_BITS;
++}
++
++static void ecx_free(EVP_PKEY *pkey)
++{
++    X25519_KEY *xkey = pkey->pkey.ptr;
++
++    if (xkey)
++        OPENSSL_secure_free(xkey->privkey);
++    OPENSSL_free(xkey);
++}
++
++/* "parameters" are always equal */
++static int ecx_cmp_parameters(const EVP_PKEY *a, const EVP_PKEY *b)
++{
++    return 1;
++}
++
++static int ecx_key_print(BIO *bp, const EVP_PKEY *pkey, int indent,
++                         ASN1_PCTX *ctx, ecx_key_op_t op)
++{
++    const X25519_KEY *xkey = pkey->pkey.ptr;
++
++    if (op == X25519_PRIVATE) {
++        if (xkey == NULL || xkey->privkey == NULL) {
++            if (BIO_printf(bp, "%*s\n", indent, "") <= 0)
++                return 0;
++            return 1;
++        }
++        if (BIO_printf(bp, "%*sX25519 Private-Key:\n", indent, "") <= 0)
++            return 0;
++        if (BIO_printf(bp, "%*spriv:\n", indent, "") <= 0)
++            return 0;
++        if (ASN1_buf_print(bp, xkey->privkey, X25519_KEYLEN, indent + 4) == 0)
++            return 0;
++    } else {
++        if (xkey == NULL) {
++            if (BIO_printf(bp, "%*s\n", indent, "") <= 0)
++                return 0;
++            return 1;
++        }
++        if (BIO_printf(bp, "%*sX25519 Public-Key:\n", indent, "") <= 0)
++            return 0;
++    }
++    if (BIO_printf(bp, "%*spub:\n", indent, "") <= 0)
++        return 0;
++    if (ASN1_buf_print(bp, xkey->pubkey, X25519_KEYLEN, indent + 4) == 0)
++        return 0;
++    return 1;
++}
++
++static int ecx_priv_print(BIO *bp, const EVP_PKEY *pkey, int indent,
++                          ASN1_PCTX *ctx)
++{
++    return ecx_key_print(bp, pkey, indent, ctx, X25519_PRIVATE);
++}
++
++static int ecx_pub_print(BIO *bp, const EVP_PKEY *pkey, int indent,
++                         ASN1_PCTX *ctx)
++{
++    return ecx_key_print(bp, pkey, indent, ctx, X25519_PUBLIC);
++}
++
++static int ecx_ctrl(EVP_PKEY *pkey, int op, long arg1, void *arg2)
++{
++    switch (op) {
++
++    case ASN1_PKEY_CTRL_SET1_TLS_ENCPT:
++        return ecx_key_op(pkey, NULL, arg2, arg1, X25519_PUBLIC);
++
++    case ASN1_PKEY_CTRL_GET1_TLS_ENCPT:
++        if (pkey->pkey.ptr != NULL) {
++            const X25519_KEY *xkey = pkey->pkey.ptr;
++            unsigned char **ppt = arg2;
++            *ppt = OPENSSL_memdup(xkey->pubkey, X25519_KEYLEN);
++            if (*ppt != NULL)
++                return X25519_KEYLEN;
++        }
++        return 0;
++
++    case ASN1_PKEY_CTRL_DEFAULT_MD_NID:
++        *(int *)arg2 = NID_sha256;
++        return 2;
++
++    default:
++        return -2;
++
++    }
++}
++
++const EVP_PKEY_ASN1_METHOD ecx25519_asn1_meth = {
++    NID_X25519,
++    NID_X25519,
++    0,
++    "X25519",
++    "OpenSSL X25519 algorithm",
++
++    ecx_pub_decode,
++    ecx_pub_encode,
++    ecx_pub_cmp,
++    ecx_pub_print,
++
++    ecx_priv_decode,
++    ecx_priv_encode,
++    ecx_priv_print,
++
++    ecx_size,
++    ecx_bits,
++    ecx_security_bits,
++
++    0, 0, 0, 0,
++    ecx_cmp_parameters,
++    0, 0,
++
++    ecx_free,
++    ecx_ctrl,
++    NULL,
++    NULL
++};
++
++static int pkey_ecx_keygen(EVP_PKEY_CTX *ctx, EVP_PKEY *pkey)
++{
++    return ecx_key_op(pkey, NULL, NULL, 0, X25519_KEYGEN);
++}
++
++static int pkey_ecx_derive(EVP_PKEY_CTX *ctx, unsigned char *key,
++                           size_t *keylen)
++{
++    const X25519_KEY *pkey, *peerkey;
++
++    if (ctx->pkey == NULL || ctx->peerkey == NULL) {
++        ECerr(EC_F_PKEY_ECX_DERIVE, EC_R_KEYS_NOT_SET);
++        return 0;
++    }
++    pkey = ctx->pkey->pkey.ptr;
++    peerkey = ctx->peerkey->pkey.ptr;
++    if (pkey == NULL || pkey->privkey == NULL) {
++        ECerr(EC_F_PKEY_ECX_DERIVE, EC_R_INVALID_PRIVATE_KEY);
++        return 0;
++    }
++    if (peerkey == NULL) {
++        ECerr(EC_F_PKEY_ECX_DERIVE, EC_R_INVALID_PEER_KEY);
++        return 0;
++    }
++    *keylen = X25519_KEYLEN;
++    if (key != NULL && X25519(key, pkey->privkey, peerkey->pubkey) == 0)
++        return 0;
++    return 1;
++}
++
++static int pkey_ecx_ctrl(EVP_PKEY_CTX *ctx, int type, int p1, void *p2)
++{
++    /* Only need to handle peer key for derivation */
++    if (type == EVP_PKEY_CTRL_PEER_KEY)
++        return 1;
++    return -2;
++}
++
++const EVP_PKEY_METHOD ecx25519_pkey_meth = {
++    NID_X25519,
++    0, 0, 0, 0, 0, 0, 0,
++    pkey_ecx_keygen,
++    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
++    pkey_ecx_derive,
++    pkey_ecx_ctrl,
++    0
++};
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/engine/README b/CryptoPkg/Library/OpensslLib/openssl/crypto/engine/README
+new file mode 100644
+index 0000000..41baa18
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/engine/README
+@@ -0,0 +1,211 @@
++Notes: 2001-09-24
++-----------------
++
++This "description" (if one chooses to call it that) needed some major updating
++so here goes. This update addresses a change being made at the same time to
++OpenSSL, and it pretty much completely restructures the underlying mechanics of
++the "ENGINE" code. So it serves a double purpose of being a "ENGINE internals
++for masochists" document *and* a rather extensive commit log message. (I'd get
++lynched for sticking all this in CHANGES or the commit mails :-).
++
++ENGINE_TABLE underlies this restructuring, as described in the internal header
++"eng_int.h", implemented in eng_table.c, and used in each of the "class" files;
++tb_rsa.c, tb_dsa.c, etc.
++
++However, "EVP_CIPHER" underlies the motivation and design of ENGINE_TABLE so
++I'll mention a bit about that first. EVP_CIPHER (and most of this applies
++equally to EVP_MD for digests) is both a "method" and a algorithm/mode
++identifier that, in the current API, "lingers". These cipher description +
++implementation structures can be defined or obtained directly by applications,
++or can be loaded "en masse" into EVP storage so that they can be catalogued and
++searched in various ways, ie. two ways of encrypting with the "des_cbc"
++algorithm/mode pair are;
++
++(i) directly;
++     const EVP_CIPHER *cipher = EVP_des_cbc();
++     EVP_EncryptInit(&ctx, cipher, key, iv);
++     [ ... use EVP_EncryptUpdate() and EVP_EncryptFinal() ...]
++
++(ii) indirectly; 
++     OpenSSL_add_all_ciphers();
++     cipher = EVP_get_cipherbyname("des_cbc");
++     EVP_EncryptInit(&ctx, cipher, key, iv);
++     [ ... etc ... ]
++
++The latter is more generally used because it also allows ciphers/digests to be
++looked up based on other identifiers which can be useful for automatic cipher
++selection, eg. in SSL/TLS, or by user-controllable configuration.
++
++The important point about this is that EVP_CIPHER definitions and structures are
++passed around with impunity and there is no safe way, without requiring massive
++rewrites of many applications, to assume that EVP_CIPHERs can be reference
++counted. One an EVP_CIPHER is exposed to the caller, neither it nor anything it
++comes from can "safely" be destroyed. Unless of course the way of getting to
++such ciphers is via entirely distinct API calls that didn't exist before.
++However existing API usage cannot be made to understand when an EVP_CIPHER
++pointer, that has been passed to the caller, is no longer being used.
++
++The other problem with the existing API w.r.t. to hooking EVP_CIPHER support
++into ENGINE is storage - the OBJ_NAME-based storage used by EVP to register
++ciphers simultaneously registers cipher *types* and cipher *implementations* -
++they are effectively the same thing, an "EVP_CIPHER" pointer. The problem with
++hooking in ENGINEs is that multiple ENGINEs may implement the same ciphers. The
++solution is necessarily that ENGINE-provided ciphers simply are not registered,
++stored, or exposed to the caller in the same manner as existing ciphers. This is
++especially necessary considering the fact ENGINE uses reference counts to allow
++for cleanup, modularity, and DSO support - yet EVP_CIPHERs, as exposed to
++callers in the current API, support no such controls.
++
++Another sticking point for integrating cipher support into ENGINE is linkage.
++Already there is a problem with the way ENGINE supports RSA, DSA, etc whereby
++they are available *because* they're part of a giant ENGINE called "openssl".
++Ie. all implementations *have* to come from an ENGINE, but we get round that by
++having a giant ENGINE with all the software support encapsulated. This creates
++linker hassles if nothing else - linking a 1-line application that calls 2 basic
++RSA functions (eg. "RSA_free(RSA_new());") will result in large quantities of
++ENGINE code being linked in *and* because of that DSA, DH, and RAND also. If we
++continue with this approach for EVP_CIPHER support (even if it *was* possible)
++we would lose our ability to link selectively by selectively loading certain
++implementations of certain functionality. Touching any part of any kind of
++crypto would result in massive static linkage of everything else. So the
++solution is to change the way ENGINE feeds existing "classes", ie. how the
++hooking to ENGINE works from RSA, DSA, DH, RAND, as well as adding new hooking
++for EVP_CIPHER, and EVP_MD.
++
++The way this is now being done is by mostly reverting back to how things used to
++work prior to ENGINE :-). Ie. RSA now has a "RSA_METHOD" pointer again - this
++was previously replaced by an "ENGINE" pointer and all RSA code that required
++the RSA_METHOD would call ENGINE_get_RSA() each time on its ENGINE handle to
++temporarily get and use the ENGINE's RSA implementation. Apart from being more
++efficient, switching back to each RSA having an RSA_METHOD pointer also allows
++us to conceivably operate with *no* ENGINE. As we'll see, this removes any need
++for a fallback ENGINE that encapsulates default implementations - we can simply
++have our RSA structure pointing its RSA_METHOD pointer to the software
++implementation and have its ENGINE pointer set to NULL.
++
++A look at the EVP_CIPHER hooking is most explanatory, the RSA, DSA (etc) cases
++turn out to be degenerate forms of the same thing. The EVP storage of ciphers,
++and the existing EVP API functions that return "software" implementations and
++descriptions remain untouched. However, the storage takes more meaning in terms
++of "cipher description" and less meaning in terms of "implementation". When an
++EVP_CIPHER_CTX is actually initialised with an EVP_CIPHER method and is about to
++begin en/decryption, the hooking to ENGINE comes into play. What happens is that
++cipher-specific ENGINE code is asked for an ENGINE pointer (a functional
++reference) for any ENGINE that is registered to perform the algo/mode that the
++provided EVP_CIPHER structure represents. Under normal circumstances, that
++ENGINE code will return NULL because no ENGINEs will have had any cipher
++implementations *registered*. As such, a NULL ENGINE pointer is stored in the
++EVP_CIPHER_CTX context, and the EVP_CIPHER structure is left hooked into the
++context and so is used as the implementation. Pretty much how things work now
++except we'd have a redundant ENGINE pointer set to NULL and doing nothing.
++
++Conversely, if an ENGINE *has* been registered to perform the algorithm/mode
++combination represented by the provided EVP_CIPHER, then a functional reference
++to that ENGINE will be returned to the EVP_CIPHER_CTX during initialisation.
++That functional reference will be stored in the context (and released on
++cleanup) - and having that reference provides a *safe* way to use an EVP_CIPHER
++definition that is private to the ENGINE. Ie. the EVP_CIPHER provided by the
++application will actually be replaced by an EVP_CIPHER from the registered
++ENGINE - it will support the same algorithm/mode as the original but will be a
++completely different implementation. Because this EVP_CIPHER isn't stored in the
++EVP storage, nor is it returned to applications from traditional API functions,
++there is no associated problem with it not having reference counts. And of
++course, when one of these "private" cipher implementations is hooked into
++EVP_CIPHER_CTX, it is done whilst the EVP_CIPHER_CTX holds a functional
++reference to the ENGINE that owns it, thus the use of the ENGINE's EVP_CIPHER is
++safe.
++
++The "cipher-specific ENGINE code" I mentioned is implemented in tb_cipher.c but
++in essence it is simply an instantiation of "ENGINE_TABLE" code for use by
++EVP_CIPHER code. tb_digest.c is virtually identical but, of course, it is for
++use by EVP_MD code. Ditto for tb_rsa.c, tb_dsa.c, etc. These instantiations of
++ENGINE_TABLE essentially provide linker-separation of the classes so that even
++if ENGINEs implement *all* possible algorithms, an application using only
++EVP_CIPHER code will link at most code relating to EVP_CIPHER, tb_cipher.c, core
++ENGINE code that is independent of class, and of course the ENGINE
++implementation that the application loaded. It will *not* however link any
++class-specific ENGINE code for digests, RSA, etc nor will it bleed over into
++other APIs, such as the RSA/DSA/etc library code.
++
++ENGINE_TABLE is a little more complicated than may seem necessary but this is
++mostly to avoid a lot of "init()"-thrashing on ENGINEs (that may have to load
++DSOs, and other expensive setup that shouldn't be thrashed unnecessarily) *and*
++to duplicate "default" behaviour. Basically an ENGINE_TABLE instantiation, for
++example tb_cipher.c, implements a hash-table keyed by integer "nid" values.
++These nids provide the uniquenness of an algorithm/mode - and each nid will hash
++to a potentially NULL "ENGINE_PILE". An ENGINE_PILE is essentially a list of
++pointers to ENGINEs that implement that particular 'nid'. Each "pile" uses some
++caching tricks such that requests on that 'nid' will be cached and all future
++requests will return immediately (well, at least with minimal operation) unless
++a change is made to the pile, eg. perhaps an ENGINE was unloaded. The reason is
++that an application could have support for 10 ENGINEs statically linked
++in, and the machine in question may not have any of the hardware those 10
++ENGINEs support. If each of those ENGINEs has a "des_cbc" implementation, we
++want to avoid every EVP_CIPHER_CTX setup from trying (and failing) to initialise
++each of those 10 ENGINEs. Instead, the first such request will try to do that
++and will either return (and cache) a NULL ENGINE pointer or will return a
++functional reference to the first that successfully initialised. In the latter
++case it will also cache an extra functional reference to the ENGINE as a
++"default" for that 'nid'. The caching is acknowledged by a 'uptodate' variable
++that is unset only if un/registration takes place on that pile. Ie. if
++implementations of "des_cbc" are added or removed. This behaviour can be
++tweaked; the ENGINE_TABLE_FLAG_NOINIT value can be passed to
++ENGINE_set_table_flags(), in which case the only ENGINEs that tb_cipher.c will
++try to initialise from the "pile" will be those that are already initialised
++(ie. it's simply an increment of the functional reference count, and no real
++"initialisation" will take place).
++
++RSA, DSA, DH, and RAND all have their own ENGINE_TABLE code as well, and the
++difference is that they all use an implicit 'nid' of 1. Whereas EVP_CIPHERs are
++actually qualitatively different depending on 'nid' (the "des_cbc" EVP_CIPHER is
++not an interoperable implementation of "aes_256_cbc"), RSA_METHODs are
++necessarily interoperable and don't have different flavours, only different
++implementations. In other words, the ENGINE_TABLE for RSA will either be empty,
++or will have a single ENGING_PILE hashed to by the 'nid' 1 and that pile
++represents ENGINEs that implement the single "type" of RSA there is.
++
++Cleanup - the registration and unregistration may pose questions about how
++cleanup works with the ENGINE_PILE doing all this caching nonsense (ie. when the
++application or EVP_CIPHER code releases its last reference to an ENGINE, the
++ENGINE_PILE code may still have references and thus those ENGINEs will stay
++hooked in forever). The way this is handled is via "unregistration". With these
++new ENGINE changes, an abstract ENGINE can be loaded and initialised, but that
++is an algorithm-agnostic process. Even if initialised, it will not have
++registered any of its implementations (to do so would link all class "table"
++code despite the fact the application may use only ciphers, for example). This
++is deliberately a distinct step. Moreover, registration and unregistration has
++nothing to do with whether an ENGINE is *functional* or not (ie. you can even
++register an ENGINE and its implementations without it being operational, you may
++not even have the drivers to make it operate). What actually happens with
++respect to cleanup is managed inside eng_lib.c with the "engine_cleanup_***"
++functions. These functions are internal-only and each part of ENGINE code that
++could require cleanup will, upon performing its first allocation, register a
++callback with the "engine_cleanup" code. The other part of this that makes it
++tick is that the ENGINE_TABLE instantiations (tb_***.c) use NULL as their
++initialised state. So if RSA code asks for an ENGINE and no ENGINE has
++registered an implementation, the code will simply return NULL and the tb_rsa.c
++state will be unchanged. Thus, no cleanup is required unless registration takes
++place. ENGINE_cleanup() will simply iterate across a list of registered cleanup
++callbacks calling each in turn, and will then internally delete its own storage
++(a STACK). When a cleanup callback is next registered (eg. if the cleanup() is
++part of a gracefull restart and the application wants to cleanup all state then
++start again), the internal STACK storage will be freshly allocated. This is much
++the same as the situation in the ENGINE_TABLE instantiations ... NULL is the
++initialised state, so only modification operations (not queries) will cause that
++code to have to register a cleanup.
++
++What else? The bignum callbacks and associated ENGINE functions have been
++removed for two obvious reasons; (i) there was no way to generalise them to the
++mechanism now used by RSA/DSA/..., because there's no such thing as a BIGNUM
++method, and (ii) because of (i), there was no meaningful way for library or
++application code to automatically hook and use ENGINE supplied bignum functions
++anyway. Also, ENGINE_cpy() has been removed (although an internal-only version
++exists) - the idea of providing an ENGINE_cpy() function probably wasn't a good
++one and now certainly doesn't make sense in any generalised way. Some of the
++RSA, DSA, DH, and RAND functions that were fiddled during the original ENGINE
++changes have now, as a consequence, been reverted back. This is because the
++hooking of ENGINE is now automatic (and passive, it can interally use a NULL
++ENGINE pointer to simply ignore ENGINE from then on).
++
++Hell, that should be enough for now ... comments welcome: geoff@openssl.org
++
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/engine/build.info b/CryptoPkg/Library/OpensslLib/openssl/crypto/engine/build.info
+new file mode 100644
+index 0000000..161dad4
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/engine/build.info
+@@ -0,0 +1,8 @@
++LIBS=../../libcrypto
++SOURCE[../../libcrypto]=\
++        eng_err.c eng_lib.c eng_list.c eng_init.c eng_ctrl.c \
++        eng_table.c eng_pkey.c eng_fat.c eng_all.c \
++        tb_rsa.c tb_dsa.c tb_dh.c tb_rand.c \
++        tb_cipher.c tb_digest.c tb_pkmeth.c tb_asnmth.c tb_eckey.c \
++        eng_openssl.c eng_cnf.c eng_dyn.c eng_cryptodev.c \
++        eng_rdrand.c
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/engine/eng_all.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/engine/eng_all.c
+new file mode 100644
+index 0000000..ebe0277
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/engine/eng_all.c
+@@ -0,0 +1,31 @@
++/*
++ * Copyright 2001-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include "internal/cryptlib.h"
++#include "eng_int.h"
++
++void ENGINE_load_builtin_engines(void)
++{
++    /* Some ENGINEs need this */
++    OPENSSL_cpuid_setup();
++
++    OPENSSL_init_crypto(OPENSSL_INIT_ENGINE_ALL_BUILTIN, NULL);
++}
++
++#if (defined(__OpenBSD__) || defined(__FreeBSD__) || defined(HAVE_CRYPTODEV)) && !defined(OPENSSL_NO_DEPRECATED)
++void ENGINE_setup_bsd_cryptodev(void)
++{
++    static int bsd_cryptodev_default_loaded = 0;
++    if (!bsd_cryptodev_default_loaded) {
++        OPENSSL_init_crypto(OPENSSL_INIT_ENGINE_CRYPTODEV, NULL);
++        ENGINE_register_all_complete();
++    }
++    bsd_cryptodev_default_loaded = 1;
++}
++#endif
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/engine/eng_cnf.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/engine/eng_cnf.c
+new file mode 100644
+index 0000000..6f0a066
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/engine/eng_cnf.c
+@@ -0,0 +1,192 @@
++/*
++ * Copyright 2002-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include "eng_int.h"
++#include 
++
++/* #define ENGINE_CONF_DEBUG */
++
++/* ENGINE config module */
++
++static const char *skip_dot(const char *name)
++{
++    const char *p = strchr(name, '.');
++
++    if (p != NULL)
++        return p + 1;
++    return name;
++}
++
++static STACK_OF(ENGINE) *initialized_engines = NULL;
++
++static int int_engine_init(ENGINE *e)
++{
++    if (!ENGINE_init(e))
++        return 0;
++    if (!initialized_engines)
++        initialized_engines = sk_ENGINE_new_null();
++    if (!initialized_engines || !sk_ENGINE_push(initialized_engines, e)) {
++        ENGINE_finish(e);
++        return 0;
++    }
++    return 1;
++}
++
++static int int_engine_configure(const char *name, const char *value, const CONF *cnf)
++{
++    int i;
++    int ret = 0;
++    long do_init = -1;
++    STACK_OF(CONF_VALUE) *ecmds;
++    CONF_VALUE *ecmd = NULL;
++    const char *ctrlname, *ctrlvalue;
++    ENGINE *e = NULL;
++    int soft = 0;
++
++    name = skip_dot(name);
++#ifdef ENGINE_CONF_DEBUG
++    fprintf(stderr, "Configuring engine %s\n", name);
++#endif
++    /* Value is a section containing ENGINE commands */
++    ecmds = NCONF_get_section(cnf, value);
++
++    if (!ecmds) {
++        ENGINEerr(ENGINE_F_INT_ENGINE_CONFIGURE,
++                  ENGINE_R_ENGINE_SECTION_ERROR);
++        return 0;
++    }
++
++    for (i = 0; i < sk_CONF_VALUE_num(ecmds); i++) {
++        ecmd = sk_CONF_VALUE_value(ecmds, i);
++        ctrlname = skip_dot(ecmd->name);
++        ctrlvalue = ecmd->value;
++#ifdef ENGINE_CONF_DEBUG
++        fprintf(stderr, "ENGINE conf: doing ctrl(%s,%s)\n", ctrlname,
++                ctrlvalue);
++#endif
++
++        /* First handle some special pseudo ctrls */
++
++        /* Override engine name to use */
++        if (strcmp(ctrlname, "engine_id") == 0)
++            name = ctrlvalue;
++        else if (strcmp(ctrlname, "soft_load") == 0)
++            soft = 1;
++        /* Load a dynamic ENGINE */
++        else if (strcmp(ctrlname, "dynamic_path") == 0) {
++            e = ENGINE_by_id("dynamic");
++            if (!e)
++                goto err;
++            if (!ENGINE_ctrl_cmd_string(e, "SO_PATH", ctrlvalue, 0))
++                goto err;
++            if (!ENGINE_ctrl_cmd_string(e, "LIST_ADD", "2", 0))
++                goto err;
++            if (!ENGINE_ctrl_cmd_string(e, "LOAD", NULL, 0))
++                goto err;
++        }
++        /* ... add other pseudos here ... */
++        else {
++            /*
++             * At this point we need an ENGINE structural reference if we
++             * don't already have one.
++             */
++            if (!e) {
++                e = ENGINE_by_id(name);
++                if (!e && soft) {
++                    ERR_clear_error();
++                    return 1;
++                }
++                if (!e)
++                    goto err;
++            }
++            /*
++             * Allow "EMPTY" to mean no value: this allows a valid "value" to
++             * be passed to ctrls of type NO_INPUT
++             */
++            if (strcmp(ctrlvalue, "EMPTY") == 0)
++                ctrlvalue = NULL;
++            if (strcmp(ctrlname, "init") == 0) {
++                if (!NCONF_get_number_e(cnf, value, "init", &do_init))
++                    goto err;
++                if (do_init == 1) {
++                    if (!int_engine_init(e))
++                        goto err;
++                } else if (do_init != 0) {
++                    ENGINEerr(ENGINE_F_INT_ENGINE_CONFIGURE,
++                              ENGINE_R_INVALID_INIT_VALUE);
++                    goto err;
++                }
++            } else if (strcmp(ctrlname, "default_algorithms") == 0) {
++                if (!ENGINE_set_default_string(e, ctrlvalue))
++                    goto err;
++            } else if (!ENGINE_ctrl_cmd_string(e, ctrlname, ctrlvalue, 0))
++                goto err;
++        }
++
++    }
++    if (e && (do_init == -1) && !int_engine_init(e)) {
++        ecmd = NULL;
++        goto err;
++    }
++    ret = 1;
++ err:
++    if (ret != 1) {
++        ENGINEerr(ENGINE_F_INT_ENGINE_CONFIGURE,
++                  ENGINE_R_ENGINE_CONFIGURATION_ERROR);
++        if (ecmd)
++            ERR_add_error_data(6, "section=", ecmd->section,
++                               ", name=", ecmd->name,
++                               ", value=", ecmd->value);
++    }
++    ENGINE_free(e);
++    return ret;
++}
++
++static int int_engine_module_init(CONF_IMODULE *md, const CONF *cnf)
++{
++    STACK_OF(CONF_VALUE) *elist;
++    CONF_VALUE *cval;
++    int i;
++#ifdef ENGINE_CONF_DEBUG
++    fprintf(stderr, "Called engine module: name %s, value %s\n",
++            CONF_imodule_get_name(md), CONF_imodule_get_value(md));
++#endif
++    /* Value is a section containing ENGINEs to configure */
++    elist = NCONF_get_section(cnf, CONF_imodule_get_value(md));
++
++    if (!elist) {
++        ENGINEerr(ENGINE_F_INT_ENGINE_MODULE_INIT,
++                  ENGINE_R_ENGINES_SECTION_ERROR);
++        return 0;
++    }
++
++    for (i = 0; i < sk_CONF_VALUE_num(elist); i++) {
++        cval = sk_CONF_VALUE_value(elist, i);
++        if (!int_engine_configure(cval->name, cval->value, cnf))
++            return 0;
++    }
++
++    return 1;
++}
++
++static void int_engine_module_finish(CONF_IMODULE *md)
++{
++    ENGINE *e;
++
++    while ((e = sk_ENGINE_pop(initialized_engines)))
++        ENGINE_finish(e);
++    sk_ENGINE_free(initialized_engines);
++    initialized_engines = NULL;
++}
++
++void ENGINE_add_conf_module(void)
++{
++    CONF_module_add("engines",
++                    int_engine_module_init, int_engine_module_finish);
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/engine/eng_cryptodev.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/engine/eng_cryptodev.c
+new file mode 100644
+index 0000000..d63c918
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/engine/eng_cryptodev.c
+@@ -0,0 +1,1754 @@
++/*
++ * Copyright 2002-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++/*
++ * Copyright (c) 2002 Bob Beck 
++ * Copyright (c) 2002 Theo de Raadt
++ * Copyright (c) 2002 Markus Friedl
++ * 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.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY
++ * EXPRESS 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 AUTHOR OR 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.
++ *
++ */
++
++#include 
++#include 
++#include 
++#include 
++#include 
++
++#if (defined(__unix__) || defined(unix)) && !defined(USG) && \
++        (defined(OpenBSD) || defined(__FreeBSD__))
++# include 
++# if (OpenBSD >= 200112) || ((__FreeBSD_version >= 470101 && __FreeBSD_version < 500000) || __FreeBSD_version >= 500041)
++#  define HAVE_CRYPTODEV
++# endif
++# if (OpenBSD >= 200110)
++#  define HAVE_SYSLOG_R
++# endif
++#endif
++
++#include 
++#ifdef HAVE_CRYPTODEV
++# include 
++# include 
++# include 
++# include 
++# include 
++# include 
++# include 
++# include 
++# include 
++# include 
++#endif
++#include 
++#include 
++#include 
++#include 
++
++#ifndef HAVE_CRYPTODEV
++
++void engine_load_cryptodev_int(void)
++{
++    /* This is a NOP on platforms without /dev/crypto */
++    return;
++}
++
++#else
++
++struct dev_crypto_state {
++    struct session_op d_sess;
++    int d_fd;
++# ifdef USE_CRYPTODEV_DIGESTS
++    char dummy_mac_key[HASH_MAX_LEN];
++    unsigned char digest_res[HASH_MAX_LEN];
++    char *mac_data;
++    int mac_len;
++# endif
++};
++
++static u_int32_t cryptodev_asymfeat = 0;
++
++static RSA_METHOD *cryptodev_rsa;
++#ifndef OPENSSL_NO_DSA
++static DSA_METHOD *cryptodev_dsa = NULL;
++#endif
++#ifndef OPENSSL_NO_DH
++static DH_METHOD *cryptodev_dh;
++#endif
++
++static int get_asym_dev_crypto(void);
++static int open_dev_crypto(void);
++static int get_dev_crypto(void);
++static int get_cryptodev_ciphers(const int **cnids);
++# ifdef USE_CRYPTODEV_DIGESTS
++static int get_cryptodev_digests(const int **cnids);
++# endif
++static int cryptodev_usable_ciphers(const int **nids);
++static int cryptodev_usable_digests(const int **nids);
++static int cryptodev_cipher(EVP_CIPHER_CTX *ctx, unsigned char *out,
++                            const unsigned char *in, size_t inl);
++static int cryptodev_init_key(EVP_CIPHER_CTX *ctx, const unsigned char *key,
++                              const unsigned char *iv, int enc);
++static int cryptodev_cleanup(EVP_CIPHER_CTX *ctx);
++static int cryptodev_engine_ciphers(ENGINE *e, const EVP_CIPHER **cipher,
++                                    const int **nids, int nid);
++static int cryptodev_engine_digests(ENGINE *e, const EVP_MD **digest,
++                                    const int **nids, int nid);
++static int bn2crparam(const BIGNUM *a, struct crparam *crp);
++static int crparam2bn(struct crparam *crp, BIGNUM *a);
++static void zapparams(struct crypt_kop *kop);
++static int cryptodev_asym(struct crypt_kop *kop, int rlen, BIGNUM *r,
++                          int slen, BIGNUM *s);
++
++static int cryptodev_bn_mod_exp(BIGNUM *r, const BIGNUM *a,
++                                const BIGNUM *p, const BIGNUM *m, BN_CTX *ctx,
++                                BN_MONT_CTX *m_ctx);
++static int cryptodev_rsa_nocrt_mod_exp(BIGNUM *r0, const BIGNUM *I, RSA *rsa,
++                                       BN_CTX *ctx);
++static int cryptodev_rsa_mod_exp(BIGNUM *r0, const BIGNUM *I, RSA *rsa,
++                                 BN_CTX *ctx);
++#ifndef OPENSSL_NO_DSA
++static int cryptodev_dsa_bn_mod_exp(DSA *dsa, BIGNUM *r, const BIGNUM *a,
++                                    const BIGNUM *p, const BIGNUM *m,
++                                    BN_CTX *ctx, BN_MONT_CTX *m_ctx);
++static int cryptodev_dsa_dsa_mod_exp(DSA *dsa, BIGNUM *t1, const BIGNUM *g,
++                                     const BIGNUM *u1, const BIGNUM *pub_key,
++                                     const BIGNUM *u2, const BIGNUM *p,
++                                     BN_CTX *ctx, BN_MONT_CTX *mont);
++static DSA_SIG *cryptodev_dsa_do_sign(const unsigned char *dgst, int dlen,
++                                      DSA *dsa);
++static int cryptodev_dsa_verify(const unsigned char *dgst, int dgst_len,
++                                DSA_SIG *sig, DSA *dsa);
++#endif
++#ifndef OPENSSL_NO_DH
++static int cryptodev_mod_exp_dh(const DH *dh, BIGNUM *r, const BIGNUM *a,
++                                const BIGNUM *p, const BIGNUM *m, BN_CTX *ctx,
++                                BN_MONT_CTX *m_ctx);
++static int cryptodev_dh_compute_key(unsigned char *key, const BIGNUM *pub_key,
++                                    DH *dh);
++#endif
++static int cryptodev_ctrl(ENGINE *e, int cmd, long i, void *p,
++                          void (*f) (void));
++void engine_load_cryptodev_int(void);
++
++static const ENGINE_CMD_DEFN cryptodev_defns[] = {
++    {0, NULL, NULL, 0}
++};
++
++static struct {
++    int id;
++    int nid;
++    int ivmax;
++    int keylen;
++} ciphers[] = {
++    {
++        CRYPTO_ARC4, NID_rc4, 0, 16,
++    },
++    {
++        CRYPTO_DES_CBC, NID_des_cbc, 8, 8,
++    },
++    {
++        CRYPTO_3DES_CBC, NID_des_ede3_cbc, 8, 24,
++    },
++    {
++        CRYPTO_AES_CBC, NID_aes_128_cbc, 16, 16,
++    },
++    {
++        CRYPTO_AES_CBC, NID_aes_192_cbc, 16, 24,
++    },
++    {
++        CRYPTO_AES_CBC, NID_aes_256_cbc, 16, 32,
++    },
++# ifdef CRYPTO_AES_CTR
++    {
++        CRYPTO_AES_CTR, NID_aes_128_ctr, 14, 16,
++    },
++    {
++        CRYPTO_AES_CTR, NID_aes_192_ctr, 14, 24,
++    },
++    {
++        CRYPTO_AES_CTR, NID_aes_256_ctr, 14, 32,
++    },
++# endif
++    {
++        CRYPTO_BLF_CBC, NID_bf_cbc, 8, 16,
++    },
++    {
++        CRYPTO_CAST_CBC, NID_cast5_cbc, 8, 16,
++    },
++    {
++        CRYPTO_SKIPJACK_CBC, NID_undef, 0, 0,
++    },
++    {
++        0, NID_undef, 0, 0,
++    },
++};
++
++# ifdef USE_CRYPTODEV_DIGESTS
++static struct {
++    int id;
++    int nid;
++    int keylen;
++} digests[] = {
++    {
++        CRYPTO_MD5_HMAC, NID_hmacWithMD5, 16
++    },
++    {
++        CRYPTO_SHA1_HMAC, NID_hmacWithSHA1, 20
++    },
++    {
++        CRYPTO_RIPEMD160_HMAC, NID_ripemd160, 16
++        /* ? */
++    },
++    {
++        CRYPTO_MD5_KPDK, NID_undef, 0
++    },
++    {
++        CRYPTO_SHA1_KPDK, NID_undef, 0
++    },
++    {
++        CRYPTO_MD5, NID_md5, 16
++    },
++    {
++        CRYPTO_SHA1, NID_sha1, 20
++    },
++    {
++        0, NID_undef, 0
++    },
++};
++# endif
++
++/*
++ * Return a fd if /dev/crypto seems usable, 0 otherwise.
++ */
++static int open_dev_crypto(void)
++{
++    static int fd = -1;
++
++    if (fd == -1) {
++        if ((fd = open("/dev/crypto", O_RDWR, 0)) == -1)
++            return (-1);
++        /* close on exec */
++        if (fcntl(fd, F_SETFD, 1) == -1) {
++            close(fd);
++            fd = -1;
++            return (-1);
++        }
++    }
++    return (fd);
++}
++
++static int get_dev_crypto(void)
++{
++    int fd, retfd;
++
++    if ((fd = open_dev_crypto()) == -1)
++        return (-1);
++# ifndef CRIOGET_NOT_NEEDED
++    if (ioctl(fd, CRIOGET, &retfd) == -1)
++        return (-1);
++
++    /* close on exec */
++    if (fcntl(retfd, F_SETFD, 1) == -1) {
++        close(retfd);
++        return (-1);
++    }
++# else
++    retfd = fd;
++# endif
++    return (retfd);
++}
++
++static void put_dev_crypto(int fd)
++{
++# ifndef CRIOGET_NOT_NEEDED
++    close(fd);
++# endif
++}
++
++/* Caching version for asym operations */
++static int get_asym_dev_crypto(void)
++{
++    static int fd = -1;
++
++    if (fd == -1)
++        fd = get_dev_crypto();
++    return fd;
++}
++
++/*
++ * Find out what ciphers /dev/crypto will let us have a session for.
++ * XXX note, that some of these openssl doesn't deal with yet!
++ * returning them here is harmless, as long as we return NULL
++ * when asked for a handler in the cryptodev_engine_ciphers routine
++ */
++static int get_cryptodev_ciphers(const int **cnids)
++{
++    static int nids[CRYPTO_ALGORITHM_MAX];
++    struct session_op sess;
++    int fd, i, count = 0;
++
++    if ((fd = get_dev_crypto()) < 0) {
++        *cnids = NULL;
++        return (0);
++    }
++    memset(&sess, 0, sizeof(sess));
++    sess.key = (caddr_t) "123456789abcdefghijklmno";
++
++    for (i = 0; ciphers[i].id && count < CRYPTO_ALGORITHM_MAX; i++) {
++        if (ciphers[i].nid == NID_undef)
++            continue;
++        sess.cipher = ciphers[i].id;
++        sess.keylen = ciphers[i].keylen;
++        sess.mac = 0;
++        if (ioctl(fd, CIOCGSESSION, &sess) != -1 &&
++            ioctl(fd, CIOCFSESSION, &sess.ses) != -1)
++            nids[count++] = ciphers[i].nid;
++    }
++    put_dev_crypto(fd);
++
++    if (count > 0)
++        *cnids = nids;
++    else
++        *cnids = NULL;
++    return (count);
++}
++
++# ifdef USE_CRYPTODEV_DIGESTS
++/*
++ * Find out what digests /dev/crypto will let us have a session for.
++ * XXX note, that some of these openssl doesn't deal with yet!
++ * returning them here is harmless, as long as we return NULL
++ * when asked for a handler in the cryptodev_engine_digests routine
++ */
++static int get_cryptodev_digests(const int **cnids)
++{
++    static int nids[CRYPTO_ALGORITHM_MAX];
++    struct session_op sess;
++    int fd, i, count = 0;
++
++    if ((fd = get_dev_crypto()) < 0) {
++        *cnids = NULL;
++        return (0);
++    }
++    memset(&sess, 0, sizeof(sess));
++    sess.mackey = (caddr_t) "123456789abcdefghijklmno";
++    for (i = 0; digests[i].id && count < CRYPTO_ALGORITHM_MAX; i++) {
++        if (digests[i].nid == NID_undef)
++            continue;
++        sess.mac = digests[i].id;
++        sess.mackeylen = digests[i].keylen;
++        sess.cipher = 0;
++        if (ioctl(fd, CIOCGSESSION, &sess) != -1 &&
++            ioctl(fd, CIOCFSESSION, &sess.ses) != -1)
++            nids[count++] = digests[i].nid;
++    }
++    put_dev_crypto(fd);
++
++    if (count > 0)
++        *cnids = nids;
++    else
++        *cnids = NULL;
++    return (count);
++}
++# endif                         /* 0 */
++
++/*
++ * Find the useable ciphers|digests from dev/crypto - this is the first
++ * thing called by the engine init crud which determines what it
++ * can use for ciphers from this engine. We want to return
++ * only what we can do, anything else is handled by software.
++ *
++ * If we can't initialize the device to do anything useful for
++ * any reason, we want to return a NULL array, and 0 length,
++ * which forces everything to be done is software. By putting
++ * the initialization of the device in here, we ensure we can
++ * use this engine as the default, and if for whatever reason
++ * /dev/crypto won't do what we want it will just be done in
++ * software
++ *
++ * This can (should) be greatly expanded to perhaps take into
++ * account speed of the device, and what we want to do.
++ * (although the disabling of particular alg's could be controlled
++ * by the device driver with sysctl's.) - this is where we
++ * want most of the decisions made about what we actually want
++ * to use from /dev/crypto.
++ */
++static int cryptodev_usable_ciphers(const int **nids)
++{
++    return (get_cryptodev_ciphers(nids));
++}
++
++static int cryptodev_usable_digests(const int **nids)
++{
++# ifdef USE_CRYPTODEV_DIGESTS
++    return (get_cryptodev_digests(nids));
++# else
++    /*
++     * XXXX just disable all digests for now, because it sucks.
++     * we need a better way to decide this - i.e. I may not
++     * want digests on slow cards like hifn on fast machines,
++     * but might want them on slow or loaded machines, etc.
++     * will also want them when using crypto cards that don't
++     * suck moose gonads - would be nice to be able to decide something
++     * as reasonable default without having hackery that's card dependent.
++     * of course, the default should probably be just do everything,
++     * with perhaps a sysctl to turn algorithms off (or have them off
++     * by default) on cards that generally suck like the hifn.
++     */
++    *nids = NULL;
++    return (0);
++# endif
++}
++
++static int
++cryptodev_cipher(EVP_CIPHER_CTX *ctx, unsigned char *out,
++                 const unsigned char *in, size_t inl)
++{
++    struct crypt_op cryp;
++    struct dev_crypto_state *state = EVP_CIPHER_CTX_get_cipher_data(ctx);
++    struct session_op *sess = &state->d_sess;
++    const void *iiv;
++    unsigned char save_iv[EVP_MAX_IV_LENGTH];
++
++    if (state->d_fd < 0)
++        return (0);
++    if (!inl)
++        return (1);
++    if ((inl % EVP_CIPHER_CTX_block_size(ctx)) != 0)
++        return (0);
++
++    memset(&cryp, 0, sizeof(cryp));
++
++    cryp.ses = sess->ses;
++    cryp.flags = 0;
++    cryp.len = inl;
++    cryp.src = (caddr_t) in;
++    cryp.dst = (caddr_t) out;
++    cryp.mac = 0;
++
++    cryp.op = EVP_CIPHER_CTX_encrypting(ctx) ? COP_ENCRYPT : COP_DECRYPT;
++
++    if (EVP_CIPHER_CTX_iv_length(ctx) > 0) {
++        cryp.iv = (caddr_t) EVP_CIPHER_CTX_iv(ctx);
++        if (!EVP_CIPHER_CTX_encrypting(ctx)) {
++            iiv = in + inl - EVP_CIPHER_CTX_iv_length(ctx);
++            memcpy(save_iv, iiv, EVP_CIPHER_CTX_iv_length(ctx));
++        }
++    } else
++        cryp.iv = NULL;
++
++    if (ioctl(state->d_fd, CIOCCRYPT, &cryp) == -1) {
++        /*
++         * XXX need better error handling this can fail for a number of
++         * different reasons.
++         */
++        return (0);
++    }
++
++    if (EVP_CIPHER_CTX_iv_length(ctx) > 0) {
++        if (EVP_CIPHER_CTX_encrypting(ctx))
++            iiv = out + inl - EVP_CIPHER_CTX_iv_length(ctx);
++        else
++            iiv = save_iv;
++        memcpy(EVP_CIPHER_CTX_iv_noconst(ctx), iiv,
++               EVP_CIPHER_CTX_iv_length(ctx));
++    }
++    return (1);
++}
++
++static int
++cryptodev_init_key(EVP_CIPHER_CTX *ctx, const unsigned char *key,
++                   const unsigned char *iv, int enc)
++{
++    struct dev_crypto_state *state = EVP_CIPHER_CTX_get_cipher_data(ctx);
++    struct session_op *sess = &state->d_sess;
++    int cipher = -1, i;
++
++    for (i = 0; ciphers[i].id; i++)
++        if (EVP_CIPHER_CTX_nid(ctx) == ciphers[i].nid &&
++            EVP_CIPHER_CTX_iv_length(ctx) <= ciphers[i].ivmax &&
++            EVP_CIPHER_CTX_key_length(ctx) == ciphers[i].keylen) {
++            cipher = ciphers[i].id;
++            break;
++        }
++
++    if (!ciphers[i].id) {
++        state->d_fd = -1;
++        return (0);
++    }
++
++    memset(sess, 0, sizeof(*sess));
++
++    if ((state->d_fd = get_dev_crypto()) < 0)
++        return (0);
++
++    sess->key = (caddr_t) key;
++    sess->keylen = EVP_CIPHER_CTX_key_length(ctx);
++    sess->cipher = cipher;
++
++    if (ioctl(state->d_fd, CIOCGSESSION, sess) == -1) {
++        put_dev_crypto(state->d_fd);
++        state->d_fd = -1;
++        return (0);
++    }
++    return (1);
++}
++
++/*
++ * free anything we allocated earlier when initing a
++ * session, and close the session.
++ */
++static int cryptodev_cleanup(EVP_CIPHER_CTX *ctx)
++{
++    int ret = 0;
++    struct dev_crypto_state *state = EVP_CIPHER_CTX_get_cipher_data(ctx);
++    struct session_op *sess = &state->d_sess;
++
++    if (state->d_fd < 0)
++        return (0);
++
++    /*
++     * XXX if this ioctl fails, something's wrong. the invoker may have called
++     * us with a bogus ctx, or we could have a device that for whatever
++     * reason just doesn't want to play ball - it's not clear what's right
++     * here - should this be an error? should it just increase a counter,
++     * hmm. For right now, we return 0 - I don't believe that to be "right".
++     * we could call the gorpy openssl lib error handlers that print messages
++     * to users of the library. hmm..
++     */
++
++    if (ioctl(state->d_fd, CIOCFSESSION, &sess->ses) == -1) {
++        ret = 0;
++    } else {
++        ret = 1;
++    }
++    put_dev_crypto(state->d_fd);
++    state->d_fd = -1;
++
++    return (ret);
++}
++
++/*
++ * libcrypto EVP stuff - this is how we get wired to EVP so the engine
++ * gets called when libcrypto requests a cipher NID.
++ */
++
++/* RC4 */
++static EVP_CIPHER *rc4_cipher = NULL;
++static const EVP_CIPHER *cryptodev_rc4(void)
++{
++    if (rc4_cipher == NULL) {
++        EVP_CIPHER *cipher;
++
++        if ((cipher = EVP_CIPHER_meth_new(NID_rc4, 1, 16)) == NULL
++            || !EVP_CIPHER_meth_set_iv_length(cipher, 0)
++            || !EVP_CIPHER_meth_set_flags(cipher, EVP_CIPH_VARIABLE_LENGTH)
++            || !EVP_CIPHER_meth_set_init(cipher, cryptodev_init_key)
++            || !EVP_CIPHER_meth_set_do_cipher(cipher, cryptodev_cipher)
++            || !EVP_CIPHER_meth_set_cleanup(cipher, cryptodev_cleanup)
++            || !EVP_CIPHER_meth_set_impl_ctx_size(cipher, sizeof(struct dev_crypto_state))) {
++            EVP_CIPHER_meth_free(cipher);
++            cipher = NULL;
++        }
++        rc4_cipher = cipher;
++    }
++    return rc4_cipher;
++}
++
++/* DES CBC EVP */
++static EVP_CIPHER *des_cbc_cipher = NULL;
++static const EVP_CIPHER *cryptodev_des_cbc(void)
++{
++    if (des_cbc_cipher == NULL) {
++        EVP_CIPHER *cipher;
++
++        if ((cipher = EVP_CIPHER_meth_new(NID_des_cbc, 8, 8)) == NULL
++            || !EVP_CIPHER_meth_set_iv_length(cipher, 8)
++            || !EVP_CIPHER_meth_set_flags(cipher, EVP_CIPH_CBC_MODE)
++            || !EVP_CIPHER_meth_set_init(cipher, cryptodev_init_key)
++            || !EVP_CIPHER_meth_set_do_cipher(cipher, cryptodev_cipher)
++            || !EVP_CIPHER_meth_set_cleanup(cipher, cryptodev_cleanup)
++            || !EVP_CIPHER_meth_set_impl_ctx_size(cipher, sizeof(struct dev_crypto_state))
++            || !EVP_CIPHER_meth_set_set_asn1_params(cipher, EVP_CIPHER_set_asn1_iv)
++            || !EVP_CIPHER_meth_set_get_asn1_params(cipher, EVP_CIPHER_get_asn1_iv)) {
++            EVP_CIPHER_meth_free(cipher);
++            cipher = NULL;
++        }
++        des_cbc_cipher = cipher;
++    }
++    return des_cbc_cipher;
++}
++
++/* 3DES CBC EVP */
++static EVP_CIPHER *des3_cbc_cipher = NULL;
++static const EVP_CIPHER *cryptodev_3des_cbc(void)
++{
++    if (des3_cbc_cipher == NULL) {
++        EVP_CIPHER *cipher;
++
++        if ((cipher = EVP_CIPHER_meth_new(NID_des_ede3_cbc, 8, 24)) == NULL
++            || !EVP_CIPHER_meth_set_iv_length(cipher, 8)
++            || !EVP_CIPHER_meth_set_flags(cipher, EVP_CIPH_CBC_MODE)
++            || !EVP_CIPHER_meth_set_init(cipher, cryptodev_init_key)
++            || !EVP_CIPHER_meth_set_do_cipher(cipher, cryptodev_cipher)
++            || !EVP_CIPHER_meth_set_cleanup(cipher, cryptodev_cleanup)
++            || !EVP_CIPHER_meth_set_impl_ctx_size(cipher, sizeof(struct dev_crypto_state))
++            || !EVP_CIPHER_meth_set_set_asn1_params(cipher, EVP_CIPHER_set_asn1_iv)
++            || !EVP_CIPHER_meth_set_get_asn1_params(cipher, EVP_CIPHER_get_asn1_iv)) {
++            EVP_CIPHER_meth_free(cipher);
++            cipher = NULL;
++        }
++        des3_cbc_cipher = cipher;
++    }
++    return des3_cbc_cipher;
++}
++
++static EVP_CIPHER *bf_cbc_cipher = NULL;
++static const EVP_CIPHER *cryptodev_bf_cbc(void)
++{
++    if (bf_cbc_cipher == NULL) {
++        EVP_CIPHER *cipher;
++
++        if ((cipher = EVP_CIPHER_meth_new(NID_bf_cbc, 8, 16)) == NULL
++            || !EVP_CIPHER_meth_set_iv_length(cipher, 8)
++            || !EVP_CIPHER_meth_set_flags(cipher, EVP_CIPH_CBC_MODE)
++            || !EVP_CIPHER_meth_set_init(cipher, cryptodev_init_key)
++            || !EVP_CIPHER_meth_set_do_cipher(cipher, cryptodev_cipher)
++            || !EVP_CIPHER_meth_set_cleanup(cipher, cryptodev_cleanup)
++            || !EVP_CIPHER_meth_set_impl_ctx_size(cipher, sizeof(struct dev_crypto_state))
++            || !EVP_CIPHER_meth_set_set_asn1_params(cipher, EVP_CIPHER_set_asn1_iv)
++            || !EVP_CIPHER_meth_set_get_asn1_params(cipher, EVP_CIPHER_get_asn1_iv)) {
++            EVP_CIPHER_meth_free(cipher);
++            cipher = NULL;
++        }
++        bf_cbc_cipher = cipher;
++    }
++    return bf_cbc_cipher;
++}
++
++static EVP_CIPHER *cast_cbc_cipher = NULL;
++static const EVP_CIPHER *cryptodev_cast_cbc(void)
++{
++    if (cast_cbc_cipher == NULL) {
++        EVP_CIPHER *cipher;
++
++        if ((cipher = EVP_CIPHER_meth_new(NID_cast5_cbc, 8, 16)) == NULL
++            || !EVP_CIPHER_meth_set_iv_length(cipher, 8)
++            || !EVP_CIPHER_meth_set_flags(cipher, EVP_CIPH_CBC_MODE)
++            || !EVP_CIPHER_meth_set_init(cipher, cryptodev_init_key)
++            || !EVP_CIPHER_meth_set_do_cipher(cipher, cryptodev_cipher)
++            || !EVP_CIPHER_meth_set_cleanup(cipher, cryptodev_cleanup)
++            || !EVP_CIPHER_meth_set_impl_ctx_size(cipher, sizeof(struct dev_crypto_state))
++            || !EVP_CIPHER_meth_set_set_asn1_params(cipher, EVP_CIPHER_set_asn1_iv)
++            || !EVP_CIPHER_meth_set_get_asn1_params(cipher, EVP_CIPHER_get_asn1_iv)) {
++            EVP_CIPHER_meth_free(cipher);
++            cipher = NULL;
++        }
++        cast_cbc_cipher = cipher;
++    }
++    return cast_cbc_cipher;
++}
++
++static EVP_CIPHER *aes_cbc_cipher = NULL;
++static const EVP_CIPHER *cryptodev_aes_cbc(void)
++{
++    if (aes_cbc_cipher == NULL) {
++        EVP_CIPHER *cipher;
++
++        if ((cipher = EVP_CIPHER_meth_new(NID_aes_128_cbc, 16, 16)) == NULL
++            || !EVP_CIPHER_meth_set_iv_length(cipher, 16)
++            || !EVP_CIPHER_meth_set_flags(cipher, EVP_CIPH_CBC_MODE)
++            || !EVP_CIPHER_meth_set_init(cipher, cryptodev_init_key)
++            || !EVP_CIPHER_meth_set_do_cipher(cipher, cryptodev_cipher)
++            || !EVP_CIPHER_meth_set_cleanup(cipher, cryptodev_cleanup)
++            || !EVP_CIPHER_meth_set_impl_ctx_size(cipher, sizeof(struct dev_crypto_state))
++            || !EVP_CIPHER_meth_set_set_asn1_params(cipher, EVP_CIPHER_set_asn1_iv)
++            || !EVP_CIPHER_meth_set_get_asn1_params(cipher, EVP_CIPHER_get_asn1_iv)) {
++            EVP_CIPHER_meth_free(cipher);
++            cipher = NULL;
++        }
++        aes_cbc_cipher = cipher;
++    }
++    return aes_cbc_cipher;
++}
++
++static EVP_CIPHER *aes_192_cbc_cipher = NULL;
++static const EVP_CIPHER *cryptodev_aes_192_cbc(void)
++{
++    if (aes_192_cbc_cipher == NULL) {
++        EVP_CIPHER *cipher;
++
++        if ((cipher = EVP_CIPHER_meth_new(NID_aes_192_cbc, 16, 24)) == NULL
++            || !EVP_CIPHER_meth_set_iv_length(cipher, 16)
++            || !EVP_CIPHER_meth_set_flags(cipher, EVP_CIPH_CBC_MODE)
++            || !EVP_CIPHER_meth_set_init(cipher, cryptodev_init_key)
++            || !EVP_CIPHER_meth_set_do_cipher(cipher, cryptodev_cipher)
++            || !EVP_CIPHER_meth_set_cleanup(cipher, cryptodev_cleanup)
++            || !EVP_CIPHER_meth_set_impl_ctx_size(cipher, sizeof(struct dev_crypto_state))
++            || !EVP_CIPHER_meth_set_set_asn1_params(cipher, EVP_CIPHER_set_asn1_iv)
++            || !EVP_CIPHER_meth_set_get_asn1_params(cipher, EVP_CIPHER_get_asn1_iv)) {
++            EVP_CIPHER_meth_free(cipher);
++            cipher = NULL;
++        }
++        aes_192_cbc_cipher = cipher;
++    }
++    return aes_192_cbc_cipher;
++}
++
++static EVP_CIPHER *aes_256_cbc_cipher = NULL;
++static const EVP_CIPHER *cryptodev_aes_256_cbc(void)
++{
++    if (aes_256_cbc_cipher == NULL) {
++        EVP_CIPHER *cipher;
++
++        if ((cipher = EVP_CIPHER_meth_new(NID_aes_256_cbc, 16, 32)) == NULL
++            || !EVP_CIPHER_meth_set_iv_length(cipher, 16)
++            || !EVP_CIPHER_meth_set_flags(cipher, EVP_CIPH_CBC_MODE)
++            || !EVP_CIPHER_meth_set_init(cipher, cryptodev_init_key)
++            || !EVP_CIPHER_meth_set_do_cipher(cipher, cryptodev_cipher)
++            || !EVP_CIPHER_meth_set_cleanup(cipher, cryptodev_cleanup)
++            || !EVP_CIPHER_meth_set_impl_ctx_size(cipher, sizeof(struct dev_crypto_state))
++            || !EVP_CIPHER_meth_set_set_asn1_params(cipher, EVP_CIPHER_set_asn1_iv)
++            || !EVP_CIPHER_meth_set_get_asn1_params(cipher, EVP_CIPHER_get_asn1_iv)) {
++            EVP_CIPHER_meth_free(cipher);
++            cipher = NULL;
++        }
++        aes_256_cbc_cipher = cipher;
++    }
++    return aes_256_cbc_cipher;
++}
++
++# ifdef CRYPTO_AES_CTR
++static EVP_CIPHER *aes_ctr_cipher = NULL;
++static const EVP_CIPHER *cryptodev_aes_ctr(void)
++{
++    if (aes_ctr_cipher == NULL) {
++        EVP_CIPHER *cipher;
++
++        if ((cipher = EVP_CIPHER_meth_new(NID_aes_128_ctr, 16, 16)) == NULL
++            || !EVP_CIPHER_meth_set_iv_length(cipher, 14)
++            || !EVP_CIPHER_meth_set_flags(cipher, EVP_CIPH_CTR_MODE)
++            || !EVP_CIPHER_meth_set_init(cipher, cryptodev_init_key)
++            || !EVP_CIPHER_meth_set_do_cipher(cipher, cryptodev_cipher)
++            || !EVP_CIPHER_meth_set_cleanup(cipher, cryptodev_cleanup)
++            || !EVP_CIPHER_meth_set_impl_ctx_size(cipher, sizeof(struct dev_crypto_state))
++            || !EVP_CIPHER_meth_set_set_asn1_params(cipher, EVP_CIPHER_set_asn1_iv)
++            || !EVP_CIPHER_meth_set_get_asn1_params(cipher, EVP_CIPHER_get_asn1_iv)) {
++            EVP_CIPHER_meth_free(cipher);
++            cipher = NULL;
++        }
++        aes_ctr_cipher = cipher;
++    }
++    return aes_ctr_cipher;
++}
++
++static EVP_CIPHER *aes_192_ctr_cipher = NULL;
++static const EVP_CIPHER *cryptodev_aes_192_ctr(void)
++{
++    if (aes_192_ctr_cipher == NULL) {
++        EVP_CIPHER *cipher;
++
++        if ((cipher = EVP_CIPHER_meth_new(NID_aes_192_ctr, 16, 24)) == NULL
++            || !EVP_CIPHER_meth_set_iv_length(cipher, 14)
++            || !EVP_CIPHER_meth_set_flags(cipher, EVP_CIPH_CTR_MODE)
++            || !EVP_CIPHER_meth_set_init(cipher, cryptodev_init_key)
++            || !EVP_CIPHER_meth_set_do_cipher(cipher, cryptodev_cipher)
++            || !EVP_CIPHER_meth_set_cleanup(cipher, cryptodev_cleanup)
++            || !EVP_CIPHER_meth_set_impl_ctx_size(cipher, sizeof(struct dev_crypto_state))
++            || !EVP_CIPHER_meth_set_set_asn1_params(cipher, EVP_CIPHER_set_asn1_iv)
++            || !EVP_CIPHER_meth_set_get_asn1_params(cipher, EVP_CIPHER_get_asn1_iv)) {
++            EVP_CIPHER_meth_free(cipher);
++            cipher = NULL;
++        }
++        aes_192_ctr_cipher = cipher;
++    }
++    return aes_192_ctr_cipher;
++}
++
++static EVP_CIPHER *aes_256_ctr_cipher = NULL;
++static const EVP_CIPHER *cryptodev_aes_256_ctr(void)
++{
++    if (aes_256_ctr_cipher == NULL) {
++        EVP_CIPHER *cipher;
++
++        if ((cipher = EVP_CIPHER_meth_new(NID_aes_256_ctr, 16, 32)) == NULL
++            || !EVP_CIPHER_meth_set_iv_length(cipher, 14)
++            || !EVP_CIPHER_meth_set_flags(cipher, EVP_CIPH_CTR_MODE)
++            || !EVP_CIPHER_meth_set_init(cipher, cryptodev_init_key)
++            || !EVP_CIPHER_meth_set_do_cipher(cipher, cryptodev_cipher)
++            || !EVP_CIPHER_meth_set_cleanup(cipher, cryptodev_cleanup)
++            || !EVP_CIPHER_meth_set_impl_ctx_size(cipher, sizeof(struct dev_crypto_state))
++            || !EVP_CIPHER_meth_set_set_asn1_params(cipher, EVP_CIPHER_set_asn1_iv)
++            || !EVP_CIPHER_meth_set_get_asn1_params(cipher, EVP_CIPHER_get_asn1_iv)) {
++            EVP_CIPHER_meth_free(cipher);
++            cipher = NULL;
++        }
++        aes_256_ctr_cipher = cipher;
++    }
++    return aes_256_ctr_cipher;
++}
++# endif
++/*
++ * Registered by the ENGINE when used to find out how to deal with
++ * a particular NID in the ENGINE. this says what we'll do at the
++ * top level - note, that list is restricted by what we answer with
++ */
++static int
++cryptodev_engine_ciphers(ENGINE *e, const EVP_CIPHER **cipher,
++                         const int **nids, int nid)
++{
++    if (!cipher)
++        return (cryptodev_usable_ciphers(nids));
++
++    switch (nid) {
++    case NID_rc4:
++        *cipher = cryptodev_rc4();
++        break;
++    case NID_des_ede3_cbc:
++        *cipher = cryptodev_3des_cbc();
++        break;
++    case NID_des_cbc:
++        *cipher = cryptodev_des_cbc();
++        break;
++    case NID_bf_cbc:
++        *cipher = cryptodev_bf_cbc();
++        break;
++    case NID_cast5_cbc:
++        *cipher = cryptodev_cast_cbc();
++        break;
++    case NID_aes_128_cbc:
++        *cipher = cryptodev_aes_cbc();
++        break;
++    case NID_aes_192_cbc:
++        *cipher = cryptodev_aes_192_cbc();
++        break;
++    case NID_aes_256_cbc:
++        *cipher = cryptodev_aes_256_cbc();
++        break;
++# ifdef CRYPTO_AES_CTR
++    case NID_aes_128_ctr:
++        *cipher = cryptodev_aes_ctr();
++        break;
++    case NID_aes_192_ctr:
++        *cipher = cryptodev_aes_192_ctr();
++        break;
++    case NID_aes_256_ctr:
++        *cipher = cryptodev_aes_256_ctr();
++        break;
++# endif
++    default:
++        *cipher = NULL;
++        break;
++    }
++    return (*cipher != NULL);
++}
++
++# ifdef USE_CRYPTODEV_DIGESTS
++
++/* convert digest type to cryptodev */
++static int digest_nid_to_cryptodev(int nid)
++{
++    int i;
++
++    for (i = 0; digests[i].id; i++)
++        if (digests[i].nid == nid)
++            return (digests[i].id);
++    return (0);
++}
++
++static int digest_key_length(int nid)
++{
++    int i;
++
++    for (i = 0; digests[i].id; i++)
++        if (digests[i].nid == nid)
++            return digests[i].keylen;
++    return (0);
++}
++
++static int cryptodev_digest_init(EVP_MD_CTX *ctx)
++{
++    struct dev_crypto_state *state = EVP_MD_CTX_md_data(ctx);
++    struct session_op *sess = &state->d_sess;
++    int digest;
++
++    if ((digest = digest_nid_to_cryptodev(EVP_MD_CTX_type(ctx))) == NID_undef) {
++        printf("cryptodev_digest_init: Can't get digest \n");
++        return (0);
++    }
++
++    memset(state, 0, sizeof(*state));
++
++    if ((state->d_fd = get_dev_crypto()) < 0) {
++        printf("cryptodev_digest_init: Can't get Dev \n");
++        return (0);
++    }
++
++    sess->mackey = state->dummy_mac_key;
++    sess->mackeylen = digest_key_length(EVP_MD_CTX_type(ctx));
++    sess->mac = digest;
++
++    if (ioctl(state->d_fd, CIOCGSESSION, sess) < 0) {
++        put_dev_crypto(state->d_fd);
++        state->d_fd = -1;
++        printf("cryptodev_digest_init: Open session failed\n");
++        return (0);
++    }
++
++    return (1);
++}
++
++static int cryptodev_digest_update(EVP_MD_CTX *ctx, const void *data,
++                                   size_t count)
++{
++    struct crypt_op cryp;
++    struct dev_crypto_state *state = EVP_MD_CTX_md_data(ctx);
++    struct session_op *sess = &state->d_sess;
++    char *new_mac_data;
++
++    if (!data || state->d_fd < 0) {
++        printf("cryptodev_digest_update: illegal inputs \n");
++        return (0);
++    }
++
++    if (!count) {
++        return (0);
++    }
++
++    if (!EVP_MD_CTX_test_flags(ctx, EVP_MD_CTX_FLAG_ONESHOT)) {
++        /* if application doesn't support one buffer */
++        new_mac_data =
++            OPENSSL_realloc(state->mac_data, state->mac_len + count);
++
++        if (!new_mac_data) {
++            printf("cryptodev_digest_update: realloc failed\n");
++            return (0);
++        }
++        state->mac_data = new_mac_data;
++
++        memcpy(state->mac_data + state->mac_len, data, count);
++        state->mac_len += count;
++
++        return (1);
++    }
++
++    memset(&cryp, 0, sizeof(cryp));
++
++    cryp.ses = sess->ses;
++    cryp.flags = 0;
++    cryp.len = count;
++    cryp.src = (caddr_t) data;
++    cryp.dst = NULL;
++    cryp.mac = (caddr_t) state->digest_res;
++    if (ioctl(state->d_fd, CIOCCRYPT, &cryp) < 0) {
++        printf("cryptodev_digest_update: digest failed\n");
++        return (0);
++    }
++    return (1);
++}
++
++static int cryptodev_digest_final(EVP_MD_CTX *ctx, unsigned char *md)
++{
++    struct crypt_op cryp;
++    struct dev_crypto_state *state = EVP_MD_CTX_md_data(ctx);
++    struct session_op *sess = &state->d_sess;
++
++    int ret = 1;
++
++    if (!md || state->d_fd < 0) {
++        printf("cryptodev_digest_final: illegal input\n");
++        return (0);
++    }
++
++    if (!EVP_MD_CTX_test_flags(ctx, EVP_MD_CTX_FLAG_ONESHOT)) {
++        /* if application doesn't support one buffer */
++        memset(&cryp, 0, sizeof(cryp));
++        cryp.ses = sess->ses;
++        cryp.flags = 0;
++        cryp.len = state->mac_len;
++        cryp.src = state->mac_data;
++        cryp.dst = NULL;
++        cryp.mac = (caddr_t) md;
++        if (ioctl(state->d_fd, CIOCCRYPT, &cryp) < 0) {
++            printf("cryptodev_digest_final: digest failed\n");
++            return (0);
++        }
++
++        return 1;
++    }
++
++    memcpy(md, state->digest_res, EVP_MD_CTX_size(ctx));
++
++    return (ret);
++}
++
++static int cryptodev_digest_cleanup(EVP_MD_CTX *ctx)
++{
++    int ret = 1;
++    struct dev_crypto_state *state = EVP_MD_CTX_md_data(ctx);
++    struct session_op *sess = &state->d_sess;
++
++    if (state == NULL)
++        return 0;
++
++    if (state->d_fd < 0) {
++        printf("cryptodev_digest_cleanup: illegal input\n");
++        return (0);
++    }
++
++    OPENSSL_free(state->mac_data);
++    state->mac_data = NULL;
++    state->mac_len = 0;
++
++    if (ioctl(state->d_fd, CIOCFSESSION, &sess->ses) < 0) {
++        printf("cryptodev_digest_cleanup: failed to close session\n");
++        ret = 0;
++    } else {
++        ret = 1;
++    }
++    put_dev_crypto(state->d_fd);
++    state->d_fd = -1;
++
++    return (ret);
++}
++
++static int cryptodev_digest_copy(EVP_MD_CTX *to, const EVP_MD_CTX *from)
++{
++    struct dev_crypto_state *fstate = EVP_MD_CTX_md_data(from);
++    struct dev_crypto_state *dstate = EVP_MD_CTX_md_data(to);
++    struct session_op *sess;
++    int digest;
++
++    if (dstate == NULL || fstate == NULL)
++        return 1;
++
++    memcpy(dstate, fstate, sizeof(struct dev_crypto_state));
++
++    sess = &dstate->d_sess;
++
++    digest = digest_nid_to_cryptodev(EVP_MD_CTX_type(to));
++
++    sess->mackey = dstate->dummy_mac_key;
++    sess->mackeylen = digest_key_length(EVP_MD_CTX_type(to));
++    sess->mac = digest;
++
++    dstate->d_fd = get_dev_crypto();
++
++    if (ioctl(dstate->d_fd, CIOCGSESSION, sess) < 0) {
++        put_dev_crypto(dstate->d_fd);
++        dstate->d_fd = -1;
++        printf("cryptodev_digest_copy: Open session failed\n");
++        return (0);
++    }
++
++    if (fstate->mac_len != 0) {
++        if (fstate->mac_data != NULL) {
++            dstate->mac_data = OPENSSL_malloc(fstate->mac_len);
++            if (dstate->mac_data == NULL) {
++                printf("cryptodev_digest_copy: mac_data allocation failed\n");
++                return (0);
++            }
++            memcpy(dstate->mac_data, fstate->mac_data, fstate->mac_len);
++            dstate->mac_len = fstate->mac_len;
++        }
++    }
++
++    return 1;
++}
++
++static EVP_MD *sha1_md = NULL;
++static const EVP_MD *cryptodev_sha1(void)
++{
++    if (sha1_md == NULL) {
++        EVP_MD *md;
++
++        if ((md = EVP_MD_meth_new(NID_sha1, NID_undef)) == NULL
++            || !EVP_MD_meth_set_result_size(md, SHA_DIGEST_LENGTH)
++            || !EVP_MD_meth_set_flags(md, EVP_MD_FLAG_ONESHOT)
++            || !EVP_MD_meth_set_input_blocksize(md, SHA_CBLOCK)
++            || !EVP_MD_meth_set_app_datasize(md,
++                                             sizeof(struct dev_crypto_state))
++            || !EVP_MD_meth_set_init(md, cryptodev_digest_init)
++            || !EVP_MD_meth_set_update(md, cryptodev_digest_update)
++            || !EVP_MD_meth_set_final(md, cryptodev_digest_final)
++            || !EVP_MD_meth_set_copy(md, cryptodev_digest_copy)
++            || !EVP_MD_meth_set_cleanup(md, cryptodev_digest_cleanup)) {
++            EVP_MD_meth_free(md);
++            md = NULL;
++        }
++        sha1_md = md;
++    }
++    return sha1_md;
++}
++
++static EVP_MD *md5_md = NULL;
++static const EVP_MD *cryptodev_md5(void)
++{
++    if (md5_md == NULL) {
++        EVP_MD *md;
++
++        if ((md = EVP_MD_meth_new(NID_md5, NID_undef)) == NULL
++            || !EVP_MD_meth_set_result_size(md, 16 /* MD5_DIGEST_LENGTH */)
++            || !EVP_MD_meth_set_flags(md, EVP_MD_FLAG_ONESHOT)
++            || !EVP_MD_meth_set_input_blocksize(md, 64 /* MD5_CBLOCK */)
++            || !EVP_MD_meth_set_app_datasize(md,
++                                             sizeof(struct dev_crypto_state))
++            || !EVP_MD_meth_set_init(md, cryptodev_digest_init)
++            || !EVP_MD_meth_set_update(md, cryptodev_digest_update)
++            || !EVP_MD_meth_set_final(md, cryptodev_digest_final)
++            || !EVP_MD_meth_set_copy(md, cryptodev_digest_copy)
++            || !EVP_MD_meth_set_cleanup(md, cryptodev_digest_cleanup)) {
++            EVP_MD_meth_free(md);
++            md = NULL;
++        }
++        md5_md = md;
++    }
++    return md5_md;
++}
++
++# endif                         /* USE_CRYPTODEV_DIGESTS */
++
++static int
++cryptodev_engine_digests(ENGINE *e, const EVP_MD **digest,
++                         const int **nids, int nid)
++{
++    if (!digest)
++        return (cryptodev_usable_digests(nids));
++
++    switch (nid) {
++# ifdef USE_CRYPTODEV_DIGESTS
++    case NID_md5:
++        *digest = cryptodev_md5();
++        break;
++    case NID_sha1:
++        *digest = cryptodev_sha1();
++        break;
++    default:
++# endif                         /* USE_CRYPTODEV_DIGESTS */
++        *digest = NULL;
++        break;
++    }
++    return (*digest != NULL);
++}
++
++static int cryptodev_engine_destroy(ENGINE *e)
++{
++    EVP_CIPHER_meth_free(rc4_cipher);
++    rc4_cipher = NULL;
++    EVP_CIPHER_meth_free(des_cbc_cipher);
++    des_cbc_cipher = NULL;
++    EVP_CIPHER_meth_free(des3_cbc_cipher);
++    des3_cbc_cipher = NULL;
++    EVP_CIPHER_meth_free(bf_cbc_cipher);
++    bf_cbc_cipher = NULL;
++    EVP_CIPHER_meth_free(cast_cbc_cipher);
++    cast_cbc_cipher = NULL;
++    EVP_CIPHER_meth_free(aes_cbc_cipher);
++    aes_cbc_cipher = NULL;
++    EVP_CIPHER_meth_free(aes_192_cbc_cipher);
++    aes_192_cbc_cipher = NULL;
++    EVP_CIPHER_meth_free(aes_256_cbc_cipher);
++    aes_256_cbc_cipher = NULL;
++# ifdef CRYPTO_AES_CTR
++    EVP_CIPHER_meth_free(aes_ctr_cipher);
++    aes_ctr_cipher = NULL;
++    EVP_CIPHER_meth_free(aes_192_ctr_cipher);
++    aes_192_ctr_cipher = NULL;
++    EVP_CIPHER_meth_free(aes_256_ctr_cipher);
++    aes_256_ctr_cipher = NULL;
++# endif
++# ifdef USE_CRYPTODEV_DIGESTS
++    EVP_MD_meth_free(sha1_md);
++    sha1_md = NULL;
++    EVP_MD_meth_free(md5_md);
++    md5_md = NULL;
++# endif
++    RSA_meth_free(cryptodev_rsa);
++    cryptodev_rsa = NULL;
++#ifndef OPENSSL_NO_DSA
++    DSA_meth_free(cryptodev_dsa);
++    cryptodev_dsa = NULL;
++#endif
++#ifndef OPENSSL_NO_DH
++    DH_meth_free(cryptodev_dh);
++    cryptodev_dh = NULL;
++#endif
++    return 1;
++}
++
++/*
++ * Convert a BIGNUM to the representation that /dev/crypto needs.
++ * Upon completion of use, the caller is responsible for freeing
++ * crp->crp_p.
++ */
++static int bn2crparam(const BIGNUM *a, struct crparam *crp)
++{
++    ssize_t bytes, bits;
++    u_char *b;
++
++    crp->crp_p = NULL;
++    crp->crp_nbits = 0;
++
++    bits = BN_num_bits(a);
++    bytes = BN_num_bytes(a);
++
++    b = OPENSSL_zalloc(bytes);
++    if (b == NULL)
++        return (1);
++
++    crp->crp_p = (caddr_t) b;
++    crp->crp_nbits = bits;
++
++    BN_bn2bin(a, b);
++    return (0);
++}
++
++/* Convert a /dev/crypto parameter to a BIGNUM */
++static int crparam2bn(struct crparam *crp, BIGNUM *a)
++{
++    u_int8_t *pd;
++    int i, bytes;
++
++    bytes = (crp->crp_nbits + 7) / 8;
++
++    if (bytes == 0)
++        return (-1);
++
++    if ((pd = OPENSSL_malloc(bytes)) == NULL)
++        return (-1);
++
++    for (i = 0; i < bytes; i++)
++        pd[i] = crp->crp_p[bytes - i - 1];
++
++    BN_bin2bn(pd, bytes, a);
++    free(pd);
++
++    return (0);
++}
++
++static void zapparams(struct crypt_kop *kop)
++{
++    int i;
++
++    for (i = 0; i < kop->crk_iparams + kop->crk_oparams; i++) {
++        OPENSSL_free(kop->crk_param[i].crp_p);
++        kop->crk_param[i].crp_p = NULL;
++        kop->crk_param[i].crp_nbits = 0;
++    }
++}
++
++static int
++cryptodev_asym(struct crypt_kop *kop, int rlen, BIGNUM *r, int slen,
++               BIGNUM *s)
++{
++    int fd, ret = -1;
++
++    if ((fd = get_asym_dev_crypto()) < 0)
++        return ret;
++
++    if (r) {
++        kop->crk_param[kop->crk_iparams].crp_p = OPENSSL_zalloc(rlen);
++        if (kop->crk_param[kop->crk_iparams].crp_p == NULL)
++            return ret;
++        kop->crk_param[kop->crk_iparams].crp_nbits = rlen * 8;
++        kop->crk_oparams++;
++    }
++    if (s) {
++        kop->crk_param[kop->crk_iparams + 1].crp_p =
++            OPENSSL_zalloc(slen);
++        /* No need to free the kop->crk_iparams parameter if it was allocated,
++         * callers of this routine have to free allocated parameters through
++         * zapparams both in case of success and failure
++         */
++        if (kop->crk_param[kop->crk_iparams+1].crp_p == NULL)
++            return ret;
++        kop->crk_param[kop->crk_iparams + 1].crp_nbits = slen * 8;
++        kop->crk_oparams++;
++    }
++
++    if (ioctl(fd, CIOCKEY, kop) == 0) {
++        if (r)
++            crparam2bn(&kop->crk_param[kop->crk_iparams], r);
++        if (s)
++            crparam2bn(&kop->crk_param[kop->crk_iparams + 1], s);
++        ret = 0;
++    }
++
++    return ret;
++}
++
++static int
++cryptodev_bn_mod_exp(BIGNUM *r, const BIGNUM *a, const BIGNUM *p,
++                     const BIGNUM *m, BN_CTX *ctx, BN_MONT_CTX *in_mont)
++{
++    struct crypt_kop kop;
++    int ret = 1;
++
++    /*
++     * Currently, we know we can do mod exp iff we can do any asymmetric
++     * operations at all.
++     */
++    if (cryptodev_asymfeat == 0) {
++        ret = BN_mod_exp(r, a, p, m, ctx);
++        return (ret);
++    }
++
++    memset(&kop, 0, sizeof(kop));
++    kop.crk_op = CRK_MOD_EXP;
++
++    /* inputs: a^p % m */
++    if (bn2crparam(a, &kop.crk_param[0]))
++        goto err;
++    if (bn2crparam(p, &kop.crk_param[1]))
++        goto err;
++    if (bn2crparam(m, &kop.crk_param[2]))
++        goto err;
++    kop.crk_iparams = 3;
++
++    if (cryptodev_asym(&kop, BN_num_bytes(m), r, 0, NULL)) {
++        const RSA_METHOD *meth = RSA_PKCS1_OpenSSL();
++        printf("OCF asym process failed, Running in software\n");
++        ret = RSA_meth_get_bn_mod_exp(meth)(r, a, p, m, ctx, in_mont);
++
++    } else if (ECANCELED == kop.crk_status) {
++        const RSA_METHOD *meth = RSA_PKCS1_OpenSSL();
++        printf("OCF hardware operation cancelled. Running in Software\n");
++        ret = RSA_meth_get_bn_mod_exp(meth)(r, a, p, m, ctx, in_mont);
++    }
++    /* else cryptodev operation worked ok ==> ret = 1 */
++
++ err:
++    zapparams(&kop);
++    return (ret);
++}
++
++static int
++cryptodev_rsa_nocrt_mod_exp(BIGNUM *r0, const BIGNUM *I, RSA *rsa,
++                            BN_CTX *ctx)
++{
++    int r;
++    const BIGNUM *n = NULL;
++    const BIGNUM *d = NULL;
++
++    ctx = BN_CTX_new();
++    RSA_get0_key(rsa, &n, NULL, &d);
++    r = cryptodev_bn_mod_exp(r0, I, d, n, ctx, NULL);
++    BN_CTX_free(ctx);
++    return (r);
++}
++
++static int
++cryptodev_rsa_mod_exp(BIGNUM *r0, const BIGNUM *I, RSA *rsa, BN_CTX *ctx)
++{
++    struct crypt_kop kop;
++    int ret = 1;
++    const BIGNUM *p = NULL;
++    const BIGNUM *q = NULL;
++    const BIGNUM *dmp1 = NULL;
++    const BIGNUM *dmq1 = NULL;
++    const BIGNUM *iqmp = NULL;
++    const BIGNUM *n = NULL;
++
++    RSA_get0_factors(rsa, &p, &q);
++    RSA_get0_crt_params(rsa, &dmp1, &dmq1, &iqmp);
++    RSA_get0_key(rsa, &n, NULL, NULL);
++
++    if (!p || !q || !dmp1 || !dmq1 || !iqmp) {
++        /* XXX 0 means failure?? */
++        return (0);
++    }
++
++    memset(&kop, 0, sizeof(kop));
++    kop.crk_op = CRK_MOD_EXP_CRT;
++    /* inputs: rsa->p rsa->q I rsa->dmp1 rsa->dmq1 rsa->iqmp */
++    if (bn2crparam(p, &kop.crk_param[0]))
++        goto err;
++    if (bn2crparam(q, &kop.crk_param[1]))
++        goto err;
++    if (bn2crparam(I, &kop.crk_param[2]))
++        goto err;
++    if (bn2crparam(dmp1, &kop.crk_param[3]))
++        goto err;
++    if (bn2crparam(dmq1, &kop.crk_param[4]))
++        goto err;
++    if (bn2crparam(iqmp, &kop.crk_param[5]))
++        goto err;
++    kop.crk_iparams = 6;
++
++    if (cryptodev_asym(&kop, BN_num_bytes(n), r0, 0, NULL)) {
++        const RSA_METHOD *meth = RSA_PKCS1_OpenSSL();
++        printf("OCF asym process failed, running in Software\n");
++        ret = RSA_meth_get_mod_exp(meth)(r0, I, rsa, ctx);
++
++    } else if (ECANCELED == kop.crk_status) {
++        const RSA_METHOD *meth = RSA_PKCS1_OpenSSL();
++        printf("OCF hardware operation cancelled. Running in Software\n");
++        ret = RSA_meth_get_mod_exp(meth)(r0, I, rsa, ctx);
++    }
++    /* else cryptodev operation worked ok ==> ret = 1 */
++
++ err:
++    zapparams(&kop);
++    return (ret);
++}
++
++#ifndef OPENSSL_NO_DSA
++static int
++cryptodev_dsa_bn_mod_exp(DSA *dsa, BIGNUM *r, const BIGNUM *a, const BIGNUM *p,
++                         const BIGNUM *m, BN_CTX *ctx, BN_MONT_CTX *m_ctx)
++{
++    return cryptodev_bn_mod_exp(r, a, p, m, ctx, m_ctx);
++}
++
++static int
++cryptodev_dsa_dsa_mod_exp(DSA *dsa, BIGNUM *t1, const BIGNUM *g,
++                          const BIGNUM *u1, const BIGNUM *pub_key,
++                          const BIGNUM *u2, const BIGNUM *p, BN_CTX *ctx,
++                          BN_MONT_CTX *mont)
++{
++    const BIGNUM *dsag, *dsap, *dsapub_key;
++    BIGNUM *t2;
++    int ret = 0;
++    const DSA_METHOD *meth;
++    int (*bn_mod_exp)(DSA *, BIGNUM *, const BIGNUM *, const BIGNUM *, const BIGNUM *,
++                      BN_CTX *, BN_MONT_CTX *);
++
++    t2 = BN_new();
++    if (t2 == NULL)
++        goto err;
++
++    /* v = ( g^u1 * y^u2 mod p ) mod q */
++    /* let t1 = g ^ u1 mod p */
++    ret = 0;
++
++    DSA_get0_pqg(dsa, &dsap, NULL, &dsag);
++    DSA_get0_key(dsa, &dsapub_key, NULL);
++
++    meth = DSA_get_method(dsa);
++    if (meth == NULL)
++        goto err;
++    bn_mod_exp = DSA_meth_get_bn_mod_exp(meth);
++    if (bn_mod_exp == NULL)
++        goto err;
++
++    if (!bn_mod_exp(dsa, t1, dsag, u1, dsap, ctx, mont))
++        goto err;
++
++    /* let t2 = y ^ u2 mod p */
++    if (!bn_mod_exp(dsa, t2, dsapub_key, u2, dsap, ctx, mont))
++        goto err;
++    /* let t1 = t1 * t2 mod p */
++    if (!BN_mod_mul(t1, t1, t2, dsap, ctx))
++        goto err;
++
++    ret = 1;
++ err:
++    BN_free(t2);
++    return (ret);
++}
++
++static DSA_SIG *cryptodev_dsa_do_sign(const unsigned char *dgst, int dlen,
++                                      DSA *dsa)
++{
++    struct crypt_kop kop;
++    BIGNUM *r, *s;
++    const BIGNUM *dsap = NULL, *dsaq = NULL, *dsag = NULL;
++    const BIGNUM *priv_key = NULL;
++    DSA_SIG *dsasig, *dsaret = NULL;
++
++    dsasig = DSA_SIG_new();
++    if (dsasig == NULL)
++        goto err;
++
++    memset(&kop, 0, sizeof(kop));
++    kop.crk_op = CRK_DSA_SIGN;
++
++    /* inputs: dgst dsa->p dsa->q dsa->g dsa->priv_key */
++    kop.crk_param[0].crp_p = (caddr_t) dgst;
++    kop.crk_param[0].crp_nbits = dlen * 8;
++    DSA_get0_pqg(dsa, &dsap, &dsaq, &dsag);
++    DSA_get0_key(dsa, NULL, &priv_key);
++    if (bn2crparam(dsap, &kop.crk_param[1]))
++        goto err;
++    if (bn2crparam(dsaq, &kop.crk_param[2]))
++        goto err;
++    if (bn2crparam(dsag, &kop.crk_param[3]))
++        goto err;
++    if (bn2crparam(priv_key, &kop.crk_param[4]))
++        goto err;
++    kop.crk_iparams = 5;
++
++    r = BN_new();
++    if (r == NULL)
++        goto err;
++    s = BN_new();
++    if (s == NULL)
++        goto err;
++    if (cryptodev_asym(&kop, BN_num_bytes(dsaq), r,
++                       BN_num_bytes(dsaq), s) == 0) {
++        DSA_SIG_set0(dsasig, r, s);
++        dsaret = dsasig;
++    } else {
++        dsaret = DSA_meth_get_sign(DSA_OpenSSL())(dgst, dlen, dsa);
++    }
++ err:
++    if (dsaret != dsasig)
++        DSA_SIG_free(dsasig);
++    kop.crk_param[0].crp_p = NULL;
++    zapparams(&kop);
++    return dsaret;
++}
++
++static int
++cryptodev_dsa_verify(const unsigned char *dgst, int dlen,
++                     DSA_SIG *sig, DSA *dsa)
++{
++    struct crypt_kop kop;
++    int dsaret = 1;
++    const BIGNUM *pr, *ps, *p = NULL, *q = NULL, *g = NULL, *pub_key = NULL;
++
++    memset(&kop, 0, sizeof(kop));
++    kop.crk_op = CRK_DSA_VERIFY;
++
++    /* inputs: dgst dsa->p dsa->q dsa->g dsa->pub_key sig->r sig->s */
++    kop.crk_param[0].crp_p = (caddr_t) dgst;
++    kop.crk_param[0].crp_nbits = dlen * 8;
++    DSA_get0_pqg(dsa, &p, &q, &g);
++    if (bn2crparam(p, &kop.crk_param[1]))
++        goto err;
++    if (bn2crparam(q, &kop.crk_param[2]))
++        goto err;
++    if (bn2crparam(g, &kop.crk_param[3]))
++        goto err;
++    DSA_get0_key(dsa, &pub_key, NULL);
++    if (bn2crparam(pub_key, &kop.crk_param[4]))
++        goto err;
++    DSA_SIG_get0(sig, &pr, &ps);
++    if (bn2crparam(pr, &kop.crk_param[5]))
++        goto err;
++    if (bn2crparam(ps, &kop.crk_param[6]))
++        goto err;
++    kop.crk_iparams = 7;
++
++    if (cryptodev_asym(&kop, 0, NULL, 0, NULL) == 0) {
++        /*
++         * OCF success value is 0, if not zero, change dsaret to fail
++         */
++        if (0 != kop.crk_status)
++            dsaret = 0;
++    } else {
++        dsaret = DSA_meth_get_verify(DSA_OpenSSL())(dgst, dlen, sig, dsa);
++    }
++ err:
++    kop.crk_param[0].crp_p = NULL;
++    zapparams(&kop);
++    return (dsaret);
++}
++#endif
++
++#ifndef OPENSSL_NO_DH
++static int
++cryptodev_mod_exp_dh(const DH *dh, BIGNUM *r, const BIGNUM *a,
++                     const BIGNUM *p, const BIGNUM *m, BN_CTX *ctx,
++                     BN_MONT_CTX *m_ctx)
++{
++    return (cryptodev_bn_mod_exp(r, a, p, m, ctx, m_ctx));
++}
++
++static int
++cryptodev_dh_compute_key(unsigned char *key, const BIGNUM *pub_key, DH *dh)
++{
++    struct crypt_kop kop;
++    int dhret = 1;
++    int fd, keylen;
++    const BIGNUM *p = NULL;
++    const BIGNUM *priv_key = NULL;
++
++    if ((fd = get_asym_dev_crypto()) < 0) {
++        const DH_METHOD *meth = DH_OpenSSL();
++
++        return DH_meth_get_compute_key(meth)(key, pub_key, dh);
++    }
++
++    DH_get0_pqg(dh, &p, NULL, NULL);
++    DH_get0_key(dh, NULL, &priv_key);
++
++    keylen = BN_num_bits(p);
++
++    memset(&kop, 0, sizeof(kop));
++    kop.crk_op = CRK_DH_COMPUTE_KEY;
++
++    /* inputs: dh->priv_key pub_key dh->p key */
++    if (bn2crparam(priv_key, &kop.crk_param[0]))
++        goto err;
++    if (bn2crparam(pub_key, &kop.crk_param[1]))
++        goto err;
++    if (bn2crparam(p, &kop.crk_param[2]))
++        goto err;
++    kop.crk_iparams = 3;
++
++    kop.crk_param[3].crp_p = (caddr_t) key;
++    kop.crk_param[3].crp_nbits = keylen * 8;
++    kop.crk_oparams = 1;
++
++    if (ioctl(fd, CIOCKEY, &kop) == -1) {
++        const DH_METHOD *meth = DH_OpenSSL();
++
++        dhret = DH_meth_get_compute_key(meth)(key, pub_key, dh);
++    }
++ err:
++    kop.crk_param[3].crp_p = NULL;
++    zapparams(&kop);
++    return (dhret);
++}
++
++#endif /* ndef OPENSSL_NO_DH */
++
++/*
++ * ctrl right now is just a wrapper that doesn't do much
++ * but I expect we'll want some options soon.
++ */
++static int
++cryptodev_ctrl(ENGINE *e, int cmd, long i, void *p, void (*f) (void))
++{
++# ifdef HAVE_SYSLOG_R
++    struct syslog_data sd = SYSLOG_DATA_INIT;
++# endif
++
++    switch (cmd) {
++    default:
++# ifdef HAVE_SYSLOG_R
++        syslog_r(LOG_ERR, &sd, "cryptodev_ctrl: unknown command %d", cmd);
++# else
++        syslog(LOG_ERR, "cryptodev_ctrl: unknown command %d", cmd);
++# endif
++        break;
++    }
++    return (1);
++}
++
++void engine_load_cryptodev_int(void)
++{
++    ENGINE *engine = ENGINE_new();
++    int fd;
++
++    if (engine == NULL)
++        return;
++    if ((fd = get_dev_crypto()) < 0) {
++        ENGINE_free(engine);
++        return;
++    }
++
++    /*
++     * find out what asymmetric crypto algorithms we support
++     */
++    if (ioctl(fd, CIOCASYMFEAT, &cryptodev_asymfeat) == -1) {
++        put_dev_crypto(fd);
++        ENGINE_free(engine);
++        return;
++    }
++    put_dev_crypto(fd);
++
++    if (!ENGINE_set_id(engine, "cryptodev") ||
++        !ENGINE_set_name(engine, "BSD cryptodev engine") ||
++        !ENGINE_set_destroy_function(engine, cryptodev_engine_destroy) ||
++        !ENGINE_set_ciphers(engine, cryptodev_engine_ciphers) ||
++        !ENGINE_set_digests(engine, cryptodev_engine_digests) ||
++        !ENGINE_set_ctrl_function(engine, cryptodev_ctrl) ||
++        !ENGINE_set_cmd_defns(engine, cryptodev_defns)) {
++        ENGINE_free(engine);
++        return;
++    }
++
++    cryptodev_rsa = RSA_meth_dup(RSA_PKCS1_OpenSSL());
++    if (cryptodev_rsa != NULL) {
++        RSA_meth_set1_name(cryptodev_rsa, "cryptodev RSA method");
++        RSA_meth_set_flags(cryptodev_rsa, 0);
++        if (ENGINE_set_RSA(engine, cryptodev_rsa)) {
++            if (cryptodev_asymfeat & CRF_MOD_EXP) {
++                RSA_meth_set_bn_mod_exp(cryptodev_rsa, cryptodev_bn_mod_exp);
++                if (cryptodev_asymfeat & CRF_MOD_EXP_CRT)
++                    RSA_meth_set_mod_exp(cryptodev_rsa, cryptodev_rsa_mod_exp);
++                else
++                    RSA_meth_set_mod_exp(cryptodev_rsa,
++                                         cryptodev_rsa_nocrt_mod_exp);
++            }
++        }
++    } else {
++        ENGINE_free(engine);
++        return;
++    }
++
++#ifndef OPENSSL_NO_DSA
++    cryptodev_dsa = DSA_meth_dup(DSA_OpenSSL());
++    if (cryptodev_dsa != NULL) {
++        DSA_meth_set1_name(cryptodev_dsa, "cryptodev DSA method");
++        DSA_meth_set_flags(cryptodev_dsa, 0);
++        if (ENGINE_set_DSA(engine, cryptodev_dsa)) {
++            if (cryptodev_asymfeat & CRF_DSA_SIGN)
++                DSA_meth_set_sign(cryptodev_dsa, cryptodev_dsa_do_sign);
++            if (cryptodev_asymfeat & CRF_MOD_EXP) {
++                DSA_meth_set_bn_mod_exp(cryptodev_dsa,
++                                        cryptodev_dsa_bn_mod_exp);
++                DSA_meth_set_mod_exp(cryptodev_dsa, cryptodev_dsa_dsa_mod_exp);
++            }
++            if (cryptodev_asymfeat & CRF_DSA_VERIFY)
++                DSA_meth_set_verify(cryptodev_dsa, cryptodev_dsa_verify);
++        }
++    } else {
++        ENGINE_free(engine);
++        return;
++    }
++#endif
++
++#ifndef OPENSSL_NO_DH
++    cryptodev_dh = DH_meth_dup(DH_OpenSSL());
++    if (cryptodev_dh != NULL) {
++        DH_meth_set1_name(cryptodev_dh, "cryptodev DH method");
++        DH_meth_set_flags(cryptodev_dh, 0);
++        if (ENGINE_set_DH(engine, cryptodev_dh)) {
++            if (cryptodev_asymfeat & CRF_MOD_EXP) {
++                DH_meth_set_bn_mod_exp(cryptodev_dh, cryptodev_mod_exp_dh);
++                if (cryptodev_asymfeat & CRF_DH_COMPUTE_KEY)
++                    DH_meth_set_compute_key(cryptodev_dh,
++                                            cryptodev_dh_compute_key);
++            }
++        }
++    } else {
++        ENGINE_free(engine);
++        return;
++    }
++#endif
++
++    ENGINE_add(engine);
++    ENGINE_free(engine);
++    ERR_clear_error();
++}
++
++#endif                          /* HAVE_CRYPTODEV */
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/engine/eng_ctrl.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/engine/eng_ctrl.c
+new file mode 100644
+index 0000000..7925f4f
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/engine/eng_ctrl.c
+@@ -0,0 +1,338 @@
++/*
++ * Copyright 2001-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include "eng_int.h"
++
++/*
++ * When querying a ENGINE-specific control command's 'description', this
++ * string is used if the ENGINE_CMD_DEFN has cmd_desc set to NULL.
++ */
++static const char *int_no_description = "";
++
++/*
++ * These internal functions handle 'CMD'-related control commands when the
++ * ENGINE in question has asked us to take care of it (ie. the ENGINE did not
++ * set the ENGINE_FLAGS_MANUAL_CMD_CTRL flag.
++ */
++
++static int int_ctrl_cmd_is_null(const ENGINE_CMD_DEFN *defn)
++{
++    if ((defn->cmd_num == 0) || (defn->cmd_name == NULL))
++        return 1;
++    return 0;
++}
++
++static int int_ctrl_cmd_by_name(const ENGINE_CMD_DEFN *defn, const char *s)
++{
++    int idx = 0;
++    while (!int_ctrl_cmd_is_null(defn) && (strcmp(defn->cmd_name, s) != 0)) {
++        idx++;
++        defn++;
++    }
++    if (int_ctrl_cmd_is_null(defn))
++        /* The given name wasn't found */
++        return -1;
++    return idx;
++}
++
++static int int_ctrl_cmd_by_num(const ENGINE_CMD_DEFN *defn, unsigned int num)
++{
++    int idx = 0;
++    /*
++     * NB: It is stipulated that 'cmd_defn' lists are ordered by cmd_num. So
++     * our searches don't need to take any longer than necessary.
++     */
++    while (!int_ctrl_cmd_is_null(defn) && (defn->cmd_num < num)) {
++        idx++;
++        defn++;
++    }
++    if (defn->cmd_num == num)
++        return idx;
++    /* The given cmd_num wasn't found */
++    return -1;
++}
++
++static int int_ctrl_helper(ENGINE *e, int cmd, long i, void *p,
++                           void (*f) (void))
++{
++    int idx;
++    char *s = (char *)p;
++    /* Take care of the easy one first (eg. it requires no searches) */
++    if (cmd == ENGINE_CTRL_GET_FIRST_CMD_TYPE) {
++        if ((e->cmd_defns == NULL) || int_ctrl_cmd_is_null(e->cmd_defns))
++            return 0;
++        return e->cmd_defns->cmd_num;
++    }
++    /* One or two commands require that "p" be a valid string buffer */
++    if ((cmd == ENGINE_CTRL_GET_CMD_FROM_NAME) ||
++        (cmd == ENGINE_CTRL_GET_NAME_FROM_CMD) ||
++        (cmd == ENGINE_CTRL_GET_DESC_FROM_CMD)) {
++        if (s == NULL) {
++            ENGINEerr(ENGINE_F_INT_CTRL_HELPER, ERR_R_PASSED_NULL_PARAMETER);
++            return -1;
++        }
++    }
++    /* Now handle cmd_name -> cmd_num conversion */
++    if (cmd == ENGINE_CTRL_GET_CMD_FROM_NAME) {
++        if ((e->cmd_defns == NULL)
++            || ((idx = int_ctrl_cmd_by_name(e->cmd_defns, s)) < 0)) {
++            ENGINEerr(ENGINE_F_INT_CTRL_HELPER, ENGINE_R_INVALID_CMD_NAME);
++            return -1;
++        }
++        return e->cmd_defns[idx].cmd_num;
++    }
++    /*
++     * For the rest of the commands, the 'long' argument must specify a valid
++     * command number - so we need to conduct a search.
++     */
++    if ((e->cmd_defns == NULL) || ((idx = int_ctrl_cmd_by_num(e->cmd_defns,
++                                                              (unsigned int)
++                                                              i)) < 0)) {
++        ENGINEerr(ENGINE_F_INT_CTRL_HELPER, ENGINE_R_INVALID_CMD_NUMBER);
++        return -1;
++    }
++    /* Now the logic splits depending on command type */
++    switch (cmd) {
++    case ENGINE_CTRL_GET_NEXT_CMD_TYPE:
++        idx++;
++        if (int_ctrl_cmd_is_null(e->cmd_defns + idx))
++            /* end-of-list */
++            return 0;
++        else
++            return e->cmd_defns[idx].cmd_num;
++    case ENGINE_CTRL_GET_NAME_LEN_FROM_CMD:
++        return strlen(e->cmd_defns[idx].cmd_name);
++    case ENGINE_CTRL_GET_NAME_FROM_CMD:
++        return BIO_snprintf(s, strlen(e->cmd_defns[idx].cmd_name) + 1,
++                            "%s", e->cmd_defns[idx].cmd_name);
++    case ENGINE_CTRL_GET_DESC_LEN_FROM_CMD:
++        if (e->cmd_defns[idx].cmd_desc)
++            return strlen(e->cmd_defns[idx].cmd_desc);
++        return strlen(int_no_description);
++    case ENGINE_CTRL_GET_DESC_FROM_CMD:
++        if (e->cmd_defns[idx].cmd_desc)
++            return BIO_snprintf(s,
++                                strlen(e->cmd_defns[idx].cmd_desc) + 1,
++                                "%s", e->cmd_defns[idx].cmd_desc);
++        return BIO_snprintf(s, strlen(int_no_description) + 1, "%s",
++                            int_no_description);
++    case ENGINE_CTRL_GET_CMD_FLAGS:
++        return e->cmd_defns[idx].cmd_flags;
++    }
++    /* Shouldn't really be here ... */
++    ENGINEerr(ENGINE_F_INT_CTRL_HELPER, ENGINE_R_INTERNAL_LIST_ERROR);
++    return -1;
++}
++
++int ENGINE_ctrl(ENGINE *e, int cmd, long i, void *p, void (*f) (void))
++{
++    int ctrl_exists, ref_exists;
++    if (e == NULL) {
++        ENGINEerr(ENGINE_F_ENGINE_CTRL, ERR_R_PASSED_NULL_PARAMETER);
++        return 0;
++    }
++    CRYPTO_THREAD_write_lock(global_engine_lock);
++    ref_exists = ((e->struct_ref > 0) ? 1 : 0);
++    CRYPTO_THREAD_unlock(global_engine_lock);
++    ctrl_exists = ((e->ctrl == NULL) ? 0 : 1);
++    if (!ref_exists) {
++        ENGINEerr(ENGINE_F_ENGINE_CTRL, ENGINE_R_NO_REFERENCE);
++        return 0;
++    }
++    /*
++     * Intercept any "root-level" commands before trying to hand them on to
++     * ctrl() handlers.
++     */
++    switch (cmd) {
++    case ENGINE_CTRL_HAS_CTRL_FUNCTION:
++        return ctrl_exists;
++    case ENGINE_CTRL_GET_FIRST_CMD_TYPE:
++    case ENGINE_CTRL_GET_NEXT_CMD_TYPE:
++    case ENGINE_CTRL_GET_CMD_FROM_NAME:
++    case ENGINE_CTRL_GET_NAME_LEN_FROM_CMD:
++    case ENGINE_CTRL_GET_NAME_FROM_CMD:
++    case ENGINE_CTRL_GET_DESC_LEN_FROM_CMD:
++    case ENGINE_CTRL_GET_DESC_FROM_CMD:
++    case ENGINE_CTRL_GET_CMD_FLAGS:
++        if (ctrl_exists && !(e->flags & ENGINE_FLAGS_MANUAL_CMD_CTRL))
++            return int_ctrl_helper(e, cmd, i, p, f);
++        if (!ctrl_exists) {
++            ENGINEerr(ENGINE_F_ENGINE_CTRL, ENGINE_R_NO_CONTROL_FUNCTION);
++            /*
++             * For these cmd-related functions, failure is indicated by a -1
++             * return value (because 0 is used as a valid return in some
++             * places).
++             */
++            return -1;
++        }
++    default:
++        break;
++    }
++    /* Anything else requires a ctrl() handler to exist. */
++    if (!ctrl_exists) {
++        ENGINEerr(ENGINE_F_ENGINE_CTRL, ENGINE_R_NO_CONTROL_FUNCTION);
++        return 0;
++    }
++    return e->ctrl(e, cmd, i, p, f);
++}
++
++int ENGINE_cmd_is_executable(ENGINE *e, int cmd)
++{
++    int flags;
++    if ((flags =
++         ENGINE_ctrl(e, ENGINE_CTRL_GET_CMD_FLAGS, cmd, NULL, NULL)) < 0) {
++        ENGINEerr(ENGINE_F_ENGINE_CMD_IS_EXECUTABLE,
++                  ENGINE_R_INVALID_CMD_NUMBER);
++        return 0;
++    }
++    if (!(flags & ENGINE_CMD_FLAG_NO_INPUT) &&
++        !(flags & ENGINE_CMD_FLAG_NUMERIC) &&
++        !(flags & ENGINE_CMD_FLAG_STRING))
++        return 0;
++    return 1;
++}
++
++int ENGINE_ctrl_cmd(ENGINE *e, const char *cmd_name,
++                    long i, void *p, void (*f) (void), int cmd_optional)
++{
++    int num;
++
++    if (e == NULL || cmd_name == NULL) {
++        ENGINEerr(ENGINE_F_ENGINE_CTRL_CMD, ERR_R_PASSED_NULL_PARAMETER);
++        return 0;
++    }
++    if (e->ctrl == NULL
++        || (num = ENGINE_ctrl(e, ENGINE_CTRL_GET_CMD_FROM_NAME,
++                              0, (void *)cmd_name, NULL)) <= 0) {
++        /*
++         * If the command didn't *have* to be supported, we fake success.
++         * This allows certain settings to be specified for multiple ENGINEs
++         * and only require a change of ENGINE id (without having to
++         * selectively apply settings). Eg. changing from a hardware device
++         * back to the regular software ENGINE without editing the config
++         * file, etc.
++         */
++        if (cmd_optional) {
++            ERR_clear_error();
++            return 1;
++        }
++        ENGINEerr(ENGINE_F_ENGINE_CTRL_CMD, ENGINE_R_INVALID_CMD_NAME);
++        return 0;
++    }
++    /*
++     * Force the result of the control command to 0 or 1, for the reasons
++     * mentioned before.
++     */
++    if (ENGINE_ctrl(e, num, i, p, f) > 0)
++        return 1;
++    return 0;
++}
++
++int ENGINE_ctrl_cmd_string(ENGINE *e, const char *cmd_name, const char *arg,
++                           int cmd_optional)
++{
++    int num, flags;
++    long l;
++    char *ptr;
++
++    if (e == NULL || cmd_name == NULL) {
++        ENGINEerr(ENGINE_F_ENGINE_CTRL_CMD_STRING, ERR_R_PASSED_NULL_PARAMETER);
++        return 0;
++    }
++    if (e->ctrl == NULL
++        || (num = ENGINE_ctrl(e, ENGINE_CTRL_GET_CMD_FROM_NAME,
++                              0, (void *)cmd_name, NULL)) <= 0) {
++        /*
++         * If the command didn't *have* to be supported, we fake success.
++         * This allows certain settings to be specified for multiple ENGINEs
++         * and only require a change of ENGINE id (without having to
++         * selectively apply settings). Eg. changing from a hardware device
++         * back to the regular software ENGINE without editing the config
++         * file, etc.
++         */
++        if (cmd_optional) {
++            ERR_clear_error();
++            return 1;
++        }
++        ENGINEerr(ENGINE_F_ENGINE_CTRL_CMD_STRING, ENGINE_R_INVALID_CMD_NAME);
++        return 0;
++    }
++    if (!ENGINE_cmd_is_executable(e, num)) {
++        ENGINEerr(ENGINE_F_ENGINE_CTRL_CMD_STRING,
++                  ENGINE_R_CMD_NOT_EXECUTABLE);
++        return 0;
++    }
++
++    flags = ENGINE_ctrl(e, ENGINE_CTRL_GET_CMD_FLAGS, num, NULL, NULL);
++    if (flags < 0) {
++        /*
++         * Shouldn't happen, given that ENGINE_cmd_is_executable() returned
++         * success.
++         */
++        ENGINEerr(ENGINE_F_ENGINE_CTRL_CMD_STRING,
++                  ENGINE_R_INTERNAL_LIST_ERROR);
++        return 0;
++    }
++    /*
++     * If the command takes no input, there must be no input. And vice versa.
++     */
++    if (flags & ENGINE_CMD_FLAG_NO_INPUT) {
++        if (arg != NULL) {
++            ENGINEerr(ENGINE_F_ENGINE_CTRL_CMD_STRING,
++                      ENGINE_R_COMMAND_TAKES_NO_INPUT);
++            return 0;
++        }
++        /*
++         * We deliberately force the result of ENGINE_ctrl() to 0 or 1 rather
++         * than returning it as "return data". This is to ensure usage of
++         * these commands is consistent across applications and that certain
++         * applications don't understand it one way, and others another.
++         */
++        if (ENGINE_ctrl(e, num, 0, (void *)arg, NULL) > 0)
++            return 1;
++        return 0;
++    }
++    /* So, we require input */
++    if (arg == NULL) {
++        ENGINEerr(ENGINE_F_ENGINE_CTRL_CMD_STRING,
++                  ENGINE_R_COMMAND_TAKES_INPUT);
++        return 0;
++    }
++    /* If it takes string input, that's easy */
++    if (flags & ENGINE_CMD_FLAG_STRING) {
++        /* Same explanation as above */
++        if (ENGINE_ctrl(e, num, 0, (void *)arg, NULL) > 0)
++            return 1;
++        return 0;
++    }
++    /*
++     * If it doesn't take numeric either, then it is unsupported for use in a
++     * config-setting situation, which is what this function is for. This
++     * should never happen though, because ENGINE_cmd_is_executable() was
++     * used.
++     */
++    if (!(flags & ENGINE_CMD_FLAG_NUMERIC)) {
++        ENGINEerr(ENGINE_F_ENGINE_CTRL_CMD_STRING,
++                  ENGINE_R_INTERNAL_LIST_ERROR);
++        return 0;
++    }
++    l = strtol(arg, &ptr, 10);
++    if ((arg == ptr) || (*ptr != '\0')) {
++        ENGINEerr(ENGINE_F_ENGINE_CTRL_CMD_STRING,
++                  ENGINE_R_ARGUMENT_IS_NOT_A_NUMBER);
++        return 0;
++    }
++    /*
++     * Force the result of the control command to 0 or 1, for the reasons
++     * mentioned before.
++     */
++    if (ENGINE_ctrl(e, num, l, NULL, NULL) > 0)
++        return 1;
++    return 0;
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/engine/eng_dyn.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/engine/eng_dyn.c
+new file mode 100644
+index 0000000..843226c
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/engine/eng_dyn.c
+@@ -0,0 +1,510 @@
++/*
++ * Copyright 2001-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include "eng_int.h"
++#include "internal/dso.h"
++#include 
++
++/*
++ * Shared libraries implementing ENGINEs for use by the "dynamic" ENGINE
++ * loader should implement the hook-up functions with the following
++ * prototypes.
++ */
++
++/* Our ENGINE handlers */
++static int dynamic_init(ENGINE *e);
++static int dynamic_finish(ENGINE *e);
++static int dynamic_ctrl(ENGINE *e, int cmd, long i, void *p,
++                        void (*f) (void));
++/* Predeclare our context type */
++typedef struct st_dynamic_data_ctx dynamic_data_ctx;
++/* The implementation for the important control command */
++static int dynamic_load(ENGINE *e, dynamic_data_ctx *ctx);
++
++#define DYNAMIC_CMD_SO_PATH             ENGINE_CMD_BASE
++#define DYNAMIC_CMD_NO_VCHECK           (ENGINE_CMD_BASE + 1)
++#define DYNAMIC_CMD_ID                  (ENGINE_CMD_BASE + 2)
++#define DYNAMIC_CMD_LIST_ADD            (ENGINE_CMD_BASE + 3)
++#define DYNAMIC_CMD_DIR_LOAD            (ENGINE_CMD_BASE + 4)
++#define DYNAMIC_CMD_DIR_ADD             (ENGINE_CMD_BASE + 5)
++#define DYNAMIC_CMD_LOAD                (ENGINE_CMD_BASE + 6)
++
++/* The constants used when creating the ENGINE */
++static const char *engine_dynamic_id = "dynamic";
++static const char *engine_dynamic_name = "Dynamic engine loading support";
++static const ENGINE_CMD_DEFN dynamic_cmd_defns[] = {
++    {DYNAMIC_CMD_SO_PATH,
++     "SO_PATH",
++     "Specifies the path to the new ENGINE shared library",
++     ENGINE_CMD_FLAG_STRING},
++    {DYNAMIC_CMD_NO_VCHECK,
++     "NO_VCHECK",
++     "Specifies to continue even if version checking fails (boolean)",
++     ENGINE_CMD_FLAG_NUMERIC},
++    {DYNAMIC_CMD_ID,
++     "ID",
++     "Specifies an ENGINE id name for loading",
++     ENGINE_CMD_FLAG_STRING},
++    {DYNAMIC_CMD_LIST_ADD,
++     "LIST_ADD",
++     "Whether to add a loaded ENGINE to the internal list (0=no,1=yes,2=mandatory)",
++     ENGINE_CMD_FLAG_NUMERIC},
++    {DYNAMIC_CMD_DIR_LOAD,
++     "DIR_LOAD",
++     "Specifies whether to load from 'DIR_ADD' directories (0=no,1=yes,2=mandatory)",
++     ENGINE_CMD_FLAG_NUMERIC},
++    {DYNAMIC_CMD_DIR_ADD,
++     "DIR_ADD",
++     "Adds a directory from which ENGINEs can be loaded",
++     ENGINE_CMD_FLAG_STRING},
++    {DYNAMIC_CMD_LOAD,
++     "LOAD",
++     "Load up the ENGINE specified by other settings",
++     ENGINE_CMD_FLAG_NO_INPUT},
++    {0, NULL, NULL, 0}
++};
++
++/*
++ * Loading code stores state inside the ENGINE structure via the "ex_data"
++ * element. We load all our state into a single structure and use that as a
++ * single context in the "ex_data" stack.
++ */
++struct st_dynamic_data_ctx {
++    /* The DSO object we load that supplies the ENGINE code */
++    DSO *dynamic_dso;
++    /*
++     * The function pointer to the version checking shared library function
++     */
++    dynamic_v_check_fn v_check;
++    /*
++     * The function pointer to the engine-binding shared library function
++     */
++    dynamic_bind_engine bind_engine;
++    /* The default name/path for loading the shared library */
++    char *DYNAMIC_LIBNAME;
++    /* Whether to continue loading on a version check failure */
++    int no_vcheck;
++    /* If non-NULL, stipulates the 'id' of the ENGINE to be loaded */
++    char *engine_id;
++    /*
++     * If non-zero, a successfully loaded ENGINE should be added to the
++     * internal ENGINE list. If 2, the add must succeed or the entire load
++     * should fail.
++     */
++    int list_add_value;
++    /* The symbol name for the version checking function */
++    const char *DYNAMIC_F1;
++    /* The symbol name for the "initialise ENGINE structure" function */
++    const char *DYNAMIC_F2;
++    /*
++     * Whether to never use 'dirs', use 'dirs' as a fallback, or only use
++     * 'dirs' for loading. Default is to use 'dirs' as a fallback.
++     */
++    int dir_load;
++    /* A stack of directories from which ENGINEs could be loaded */
++    STACK_OF(OPENSSL_STRING) *dirs;
++};
++
++/*
++ * This is the "ex_data" index we obtain and reserve for use with our context
++ * structure.
++ */
++static int dynamic_ex_data_idx = -1;
++
++static void int_free_str(char *s)
++{
++    OPENSSL_free(s);
++}
++
++/*
++ * Because our ex_data element may or may not get allocated depending on
++ * whether a "first-use" occurs before the ENGINE is freed, we have a memory
++ * leak problem to solve. We can't declare a "new" handler for the ex_data as
++ * we don't want a dynamic_data_ctx in *all* ENGINE structures of all types
++ * (this is a bug in the design of CRYPTO_EX_DATA). As such, we just declare
++ * a "free" handler and that will get called if an ENGINE is being destroyed
++ * and there was an ex_data element corresponding to our context type.
++ */
++static void dynamic_data_ctx_free_func(void *parent, void *ptr,
++                                       CRYPTO_EX_DATA *ad, int idx, long argl,
++                                       void *argp)
++{
++    if (ptr) {
++        dynamic_data_ctx *ctx = (dynamic_data_ctx *)ptr;
++        DSO_free(ctx->dynamic_dso);
++        OPENSSL_free(ctx->DYNAMIC_LIBNAME);
++        OPENSSL_free(ctx->engine_id);
++        sk_OPENSSL_STRING_pop_free(ctx->dirs, int_free_str);
++        OPENSSL_free(ctx);
++    }
++}
++
++/*
++ * Construct the per-ENGINE context. We create it blindly and then use a lock
++ * to check for a race - if so, all but one of the threads "racing" will have
++ * wasted their time. The alternative involves creating everything inside the
++ * lock which is far worse.
++ */
++static int dynamic_set_data_ctx(ENGINE *e, dynamic_data_ctx **ctx)
++{
++    dynamic_data_ctx *c = OPENSSL_zalloc(sizeof(*c));
++    int ret = 1;
++
++    if (c == NULL) {
++        ENGINEerr(ENGINE_F_DYNAMIC_SET_DATA_CTX, ERR_R_MALLOC_FAILURE);
++        return 0;
++    }
++    c->dirs = sk_OPENSSL_STRING_new_null();
++    if (c->dirs == NULL) {
++        ENGINEerr(ENGINE_F_DYNAMIC_SET_DATA_CTX, ERR_R_MALLOC_FAILURE);
++        OPENSSL_free(c);
++        return 0;
++    }
++    c->DYNAMIC_F1 = "v_check";
++    c->DYNAMIC_F2 = "bind_engine";
++    c->dir_load = 1;
++    CRYPTO_THREAD_write_lock(global_engine_lock);
++    if ((*ctx = (dynamic_data_ctx *)ENGINE_get_ex_data(e,
++                                                       dynamic_ex_data_idx))
++        == NULL) {
++        /* Good, we're the first */
++        ret = ENGINE_set_ex_data(e, dynamic_ex_data_idx, c);
++        if (ret) {
++            *ctx = c;
++            c = NULL;
++        }
++    }
++    CRYPTO_THREAD_unlock(global_engine_lock);
++    /*
++     * If we lost the race to set the context, c is non-NULL and *ctx is the
++     * context of the thread that won.
++     */
++    if (c)
++        sk_OPENSSL_STRING_free(c->dirs);
++    OPENSSL_free(c);
++    return ret;
++}
++
++/*
++ * This function retrieves the context structure from an ENGINE's "ex_data",
++ * or if it doesn't exist yet, sets it up.
++ */
++static dynamic_data_ctx *dynamic_get_data_ctx(ENGINE *e)
++{
++    dynamic_data_ctx *ctx;
++    if (dynamic_ex_data_idx < 0) {
++        /*
++         * Create and register the ENGINE ex_data, and associate our "free"
++         * function with it to ensure any allocated contexts get freed when
++         * an ENGINE goes underground.
++         */
++        int new_idx = ENGINE_get_ex_new_index(0, NULL, NULL, NULL,
++                                              dynamic_data_ctx_free_func);
++        if (new_idx == -1) {
++            ENGINEerr(ENGINE_F_DYNAMIC_GET_DATA_CTX, ENGINE_R_NO_INDEX);
++            return NULL;
++        }
++        CRYPTO_THREAD_write_lock(global_engine_lock);
++        /* Avoid a race by checking again inside this lock */
++        if (dynamic_ex_data_idx < 0) {
++            /* Good, someone didn't beat us to it */
++            dynamic_ex_data_idx = new_idx;
++            new_idx = -1;
++        }
++        CRYPTO_THREAD_unlock(global_engine_lock);
++        /*
++         * In theory we could "give back" the index here if (new_idx>-1), but
++         * it's not possible and wouldn't gain us much if it were.
++         */
++    }
++    ctx = (dynamic_data_ctx *)ENGINE_get_ex_data(e, dynamic_ex_data_idx);
++    /* Check if the context needs to be created */
++    if ((ctx == NULL) && !dynamic_set_data_ctx(e, &ctx))
++        /* "set_data" will set errors if necessary */
++        return NULL;
++    return ctx;
++}
++
++static ENGINE *engine_dynamic(void)
++{
++    ENGINE *ret = ENGINE_new();
++    if (ret == NULL)
++        return NULL;
++    if (!ENGINE_set_id(ret, engine_dynamic_id) ||
++        !ENGINE_set_name(ret, engine_dynamic_name) ||
++        !ENGINE_set_init_function(ret, dynamic_init) ||
++        !ENGINE_set_finish_function(ret, dynamic_finish) ||
++        !ENGINE_set_ctrl_function(ret, dynamic_ctrl) ||
++        !ENGINE_set_flags(ret, ENGINE_FLAGS_BY_ID_COPY) ||
++        !ENGINE_set_cmd_defns(ret, dynamic_cmd_defns)) {
++        ENGINE_free(ret);
++        return NULL;
++    }
++    return ret;
++}
++
++void engine_load_dynamic_int(void)
++{
++    ENGINE *toadd = engine_dynamic();
++    if (!toadd)
++        return;
++    ENGINE_add(toadd);
++    /*
++     * If the "add" worked, it gets a structural reference. So either way, we
++     * release our just-created reference.
++     */
++    ENGINE_free(toadd);
++    /*
++     * If the "add" didn't work, it was probably a conflict because it was
++     * already added (eg. someone calling ENGINE_load_blah then calling
++     * ENGINE_load_builtin_engines() perhaps).
++     */
++    ERR_clear_error();
++}
++
++static int dynamic_init(ENGINE *e)
++{
++    /*
++     * We always return failure - the "dynamic" engine itself can't be used
++     * for anything.
++     */
++    return 0;
++}
++
++static int dynamic_finish(ENGINE *e)
++{
++    /*
++     * This should never be called on account of "dynamic_init" always
++     * failing.
++     */
++    return 0;
++}
++
++static int dynamic_ctrl(ENGINE *e, int cmd, long i, void *p, void (*f) (void))
++{
++    dynamic_data_ctx *ctx = dynamic_get_data_ctx(e);
++    int initialised;
++
++    if (!ctx) {
++        ENGINEerr(ENGINE_F_DYNAMIC_CTRL, ENGINE_R_NOT_LOADED);
++        return 0;
++    }
++    initialised = ((ctx->dynamic_dso == NULL) ? 0 : 1);
++    /* All our control commands require the ENGINE to be uninitialised */
++    if (initialised) {
++        ENGINEerr(ENGINE_F_DYNAMIC_CTRL, ENGINE_R_ALREADY_LOADED);
++        return 0;
++    }
++    switch (cmd) {
++    case DYNAMIC_CMD_SO_PATH:
++        /* a NULL 'p' or a string of zero-length is the same thing */
++        if (p && (strlen((const char *)p) < 1))
++            p = NULL;
++        OPENSSL_free(ctx->DYNAMIC_LIBNAME);
++        if (p)
++            ctx->DYNAMIC_LIBNAME = OPENSSL_strdup(p);
++        else
++            ctx->DYNAMIC_LIBNAME = NULL;
++        return (ctx->DYNAMIC_LIBNAME ? 1 : 0);
++    case DYNAMIC_CMD_NO_VCHECK:
++        ctx->no_vcheck = ((i == 0) ? 0 : 1);
++        return 1;
++    case DYNAMIC_CMD_ID:
++        /* a NULL 'p' or a string of zero-length is the same thing */
++        if (p && (strlen((const char *)p) < 1))
++            p = NULL;
++        OPENSSL_free(ctx->engine_id);
++        if (p)
++            ctx->engine_id = OPENSSL_strdup(p);
++        else
++            ctx->engine_id = NULL;
++        return (ctx->engine_id ? 1 : 0);
++    case DYNAMIC_CMD_LIST_ADD:
++        if ((i < 0) || (i > 2)) {
++            ENGINEerr(ENGINE_F_DYNAMIC_CTRL, ENGINE_R_INVALID_ARGUMENT);
++            return 0;
++        }
++        ctx->list_add_value = (int)i;
++        return 1;
++    case DYNAMIC_CMD_LOAD:
++        return dynamic_load(e, ctx);
++    case DYNAMIC_CMD_DIR_LOAD:
++        if ((i < 0) || (i > 2)) {
++            ENGINEerr(ENGINE_F_DYNAMIC_CTRL, ENGINE_R_INVALID_ARGUMENT);
++            return 0;
++        }
++        ctx->dir_load = (int)i;
++        return 1;
++    case DYNAMIC_CMD_DIR_ADD:
++        /* a NULL 'p' or a string of zero-length is the same thing */
++        if (!p || (strlen((const char *)p) < 1)) {
++            ENGINEerr(ENGINE_F_DYNAMIC_CTRL, ENGINE_R_INVALID_ARGUMENT);
++            return 0;
++        }
++        {
++            char *tmp_str = OPENSSL_strdup(p);
++            if (tmp_str == NULL) {
++                ENGINEerr(ENGINE_F_DYNAMIC_CTRL, ERR_R_MALLOC_FAILURE);
++                return 0;
++            }
++            if (!sk_OPENSSL_STRING_push(ctx->dirs, tmp_str)) {
++                OPENSSL_free(tmp_str);
++                ENGINEerr(ENGINE_F_DYNAMIC_CTRL, ERR_R_MALLOC_FAILURE);
++                return 0;
++            }
++        }
++        return 1;
++    default:
++        break;
++    }
++    ENGINEerr(ENGINE_F_DYNAMIC_CTRL, ENGINE_R_CTRL_COMMAND_NOT_IMPLEMENTED);
++    return 0;
++}
++
++static int int_load(dynamic_data_ctx *ctx)
++{
++    int num, loop;
++    /* Unless told not to, try a direct load */
++    if ((ctx->dir_load != 2) && (DSO_load(ctx->dynamic_dso,
++                                          ctx->DYNAMIC_LIBNAME, NULL,
++                                          0)) != NULL)
++        return 1;
++    /* If we're not allowed to use 'dirs' or we have none, fail */
++    if (!ctx->dir_load || (num = sk_OPENSSL_STRING_num(ctx->dirs)) < 1)
++        return 0;
++    for (loop = 0; loop < num; loop++) {
++        const char *s = sk_OPENSSL_STRING_value(ctx->dirs, loop);
++        char *merge = DSO_merge(ctx->dynamic_dso, ctx->DYNAMIC_LIBNAME, s);
++        if (!merge)
++            return 0;
++        if (DSO_load(ctx->dynamic_dso, merge, NULL, 0)) {
++            /* Found what we're looking for */
++            OPENSSL_free(merge);
++            return 1;
++        }
++        OPENSSL_free(merge);
++    }
++    return 0;
++}
++
++static int dynamic_load(ENGINE *e, dynamic_data_ctx *ctx)
++{
++    ENGINE cpy;
++    dynamic_fns fns;
++
++    if (ctx->dynamic_dso == NULL)
++        ctx->dynamic_dso = DSO_new();
++    if (ctx->dynamic_dso == NULL)
++        return 0;
++    if (!ctx->DYNAMIC_LIBNAME) {
++        if (!ctx->engine_id)
++            return 0;
++        DSO_ctrl(ctx->dynamic_dso, DSO_CTRL_SET_FLAGS,
++                 DSO_FLAG_NAME_TRANSLATION_EXT_ONLY, NULL);
++        ctx->DYNAMIC_LIBNAME =
++            DSO_convert_filename(ctx->dynamic_dso, ctx->engine_id);
++    }
++    if (!int_load(ctx)) {
++        ENGINEerr(ENGINE_F_DYNAMIC_LOAD, ENGINE_R_DSO_NOT_FOUND);
++        DSO_free(ctx->dynamic_dso);
++        ctx->dynamic_dso = NULL;
++        return 0;
++    }
++    /* We have to find a bind function otherwise it'll always end badly */
++    if (!
++        (ctx->bind_engine =
++         (dynamic_bind_engine) DSO_bind_func(ctx->dynamic_dso,
++                                             ctx->DYNAMIC_F2))) {
++        ctx->bind_engine = NULL;
++        DSO_free(ctx->dynamic_dso);
++        ctx->dynamic_dso = NULL;
++        ENGINEerr(ENGINE_F_DYNAMIC_LOAD, ENGINE_R_DSO_FAILURE);
++        return 0;
++    }
++    /* Do we perform version checking? */
++    if (!ctx->no_vcheck) {
++        unsigned long vcheck_res = 0;
++        /*
++         * Now we try to find a version checking function and decide how to
++         * cope with failure if/when it fails.
++         */
++        ctx->v_check =
++            (dynamic_v_check_fn) DSO_bind_func(ctx->dynamic_dso,
++                                               ctx->DYNAMIC_F1);
++        if (ctx->v_check)
++            vcheck_res = ctx->v_check(OSSL_DYNAMIC_VERSION);
++        /*
++         * We fail if the version checker veto'd the load *or* if it is
++         * deferring to us (by returning its version) and we think it is too
++         * old.
++         */
++        if (vcheck_res < OSSL_DYNAMIC_OLDEST) {
++            /* Fail */
++            ctx->bind_engine = NULL;
++            ctx->v_check = NULL;
++            DSO_free(ctx->dynamic_dso);
++            ctx->dynamic_dso = NULL;
++            ENGINEerr(ENGINE_F_DYNAMIC_LOAD,
++                      ENGINE_R_VERSION_INCOMPATIBILITY);
++            return 0;
++        }
++    }
++    /*
++     * First binary copy the ENGINE structure so that we can roll back if the
++     * hand-over fails
++     */
++    memcpy(&cpy, e, sizeof(ENGINE));
++    /*
++     * Provide the ERR, "ex_data", memory, and locking callbacks so the
++     * loaded library uses our state rather than its own. FIXME: As noted in
++     * engine.h, much of this would be simplified if each area of code
++     * provided its own "summary" structure of all related callbacks. It
++     * would also increase opaqueness.
++     */
++    fns.static_state = ENGINE_get_static_state();
++    CRYPTO_get_mem_functions(&fns.mem_fns.malloc_fn, &fns.mem_fns.realloc_fn,
++                             &fns.mem_fns.free_fn);
++    /*
++     * Now that we've loaded the dynamic engine, make sure no "dynamic"
++     * ENGINE elements will show through.
++     */
++    engine_set_all_null(e);
++
++    /* Try to bind the ENGINE onto our own ENGINE structure */
++    if (!ctx->bind_engine(e, ctx->engine_id, &fns)) {
++        ctx->bind_engine = NULL;
++        ctx->v_check = NULL;
++        DSO_free(ctx->dynamic_dso);
++        ctx->dynamic_dso = NULL;
++        ENGINEerr(ENGINE_F_DYNAMIC_LOAD, ENGINE_R_INIT_FAILED);
++        /* Copy the original ENGINE structure back */
++        memcpy(e, &cpy, sizeof(ENGINE));
++        return 0;
++    }
++    /* Do we try to add this ENGINE to the internal list too? */
++    if (ctx->list_add_value > 0) {
++        if (!ENGINE_add(e)) {
++            /* Do we tolerate this or fail? */
++            if (ctx->list_add_value > 1) {
++                /*
++                 * Fail - NB: By this time, it's too late to rollback, and
++                 * trying to do so allows the bind_engine() code to have
++                 * created leaks. We just have to fail where we are, after
++                 * the ENGINE has changed.
++                 */
++                ENGINEerr(ENGINE_F_DYNAMIC_LOAD,
++                          ENGINE_R_CONFLICTING_ENGINE_ID);
++                return 0;
++            }
++            /* Tolerate */
++            ERR_clear_error();
++        }
++    }
++    return 1;
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/engine/eng_err.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/engine/eng_err.c
+new file mode 100644
+index 0000000..5e9d16f
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/engine/eng_err.c
+@@ -0,0 +1,123 @@
++/*
++ * Generated by util/mkerr.pl DO NOT EDIT
++ * Copyright 1995-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include 
++#include 
++
++/* BEGIN ERROR CODES */
++#ifndef OPENSSL_NO_ERR
++
++# define ERR_FUNC(func) ERR_PACK(ERR_LIB_ENGINE,func,0)
++# define ERR_REASON(reason) ERR_PACK(ERR_LIB_ENGINE,0,reason)
++
++static ERR_STRING_DATA ENGINE_str_functs[] = {
++    {ERR_FUNC(ENGINE_F_DYNAMIC_CTRL), "dynamic_ctrl"},
++    {ERR_FUNC(ENGINE_F_DYNAMIC_GET_DATA_CTX), "dynamic_get_data_ctx"},
++    {ERR_FUNC(ENGINE_F_DYNAMIC_LOAD), "dynamic_load"},
++    {ERR_FUNC(ENGINE_F_DYNAMIC_SET_DATA_CTX), "dynamic_set_data_ctx"},
++    {ERR_FUNC(ENGINE_F_ENGINE_ADD), "ENGINE_add"},
++    {ERR_FUNC(ENGINE_F_ENGINE_BY_ID), "ENGINE_by_id"},
++    {ERR_FUNC(ENGINE_F_ENGINE_CMD_IS_EXECUTABLE), "ENGINE_cmd_is_executable"},
++    {ERR_FUNC(ENGINE_F_ENGINE_CTRL), "ENGINE_ctrl"},
++    {ERR_FUNC(ENGINE_F_ENGINE_CTRL_CMD), "ENGINE_ctrl_cmd"},
++    {ERR_FUNC(ENGINE_F_ENGINE_CTRL_CMD_STRING), "ENGINE_ctrl_cmd_string"},
++    {ERR_FUNC(ENGINE_F_ENGINE_FINISH), "ENGINE_finish"},
++    {ERR_FUNC(ENGINE_F_ENGINE_GET_CIPHER), "ENGINE_get_cipher"},
++    {ERR_FUNC(ENGINE_F_ENGINE_GET_DIGEST), "ENGINE_get_digest"},
++    {ERR_FUNC(ENGINE_F_ENGINE_GET_FIRST), "ENGINE_get_first"},
++    {ERR_FUNC(ENGINE_F_ENGINE_GET_LAST), "ENGINE_get_last"},
++    {ERR_FUNC(ENGINE_F_ENGINE_GET_NEXT), "ENGINE_get_next"},
++    {ERR_FUNC(ENGINE_F_ENGINE_GET_PKEY_ASN1_METH),
++     "ENGINE_get_pkey_asn1_meth"},
++    {ERR_FUNC(ENGINE_F_ENGINE_GET_PKEY_METH), "ENGINE_get_pkey_meth"},
++    {ERR_FUNC(ENGINE_F_ENGINE_GET_PREV), "ENGINE_get_prev"},
++    {ERR_FUNC(ENGINE_F_ENGINE_INIT), "ENGINE_init"},
++    {ERR_FUNC(ENGINE_F_ENGINE_LIST_ADD), "engine_list_add"},
++    {ERR_FUNC(ENGINE_F_ENGINE_LIST_REMOVE), "engine_list_remove"},
++    {ERR_FUNC(ENGINE_F_ENGINE_LOAD_PRIVATE_KEY), "ENGINE_load_private_key"},
++    {ERR_FUNC(ENGINE_F_ENGINE_LOAD_PUBLIC_KEY), "ENGINE_load_public_key"},
++    {ERR_FUNC(ENGINE_F_ENGINE_LOAD_SSL_CLIENT_CERT),
++     "ENGINE_load_ssl_client_cert"},
++    {ERR_FUNC(ENGINE_F_ENGINE_NEW), "ENGINE_new"},
++    {ERR_FUNC(ENGINE_F_ENGINE_PKEY_ASN1_FIND_STR),
++     "ENGINE_pkey_asn1_find_str"},
++    {ERR_FUNC(ENGINE_F_ENGINE_REMOVE), "ENGINE_remove"},
++    {ERR_FUNC(ENGINE_F_ENGINE_SET_DEFAULT_STRING),
++     "ENGINE_set_default_string"},
++    {ERR_FUNC(ENGINE_F_ENGINE_SET_ID), "ENGINE_set_id"},
++    {ERR_FUNC(ENGINE_F_ENGINE_SET_NAME), "ENGINE_set_name"},
++    {ERR_FUNC(ENGINE_F_ENGINE_TABLE_REGISTER), "engine_table_register"},
++    {ERR_FUNC(ENGINE_F_ENGINE_UNLOCKED_FINISH), "engine_unlocked_finish"},
++    {ERR_FUNC(ENGINE_F_ENGINE_UP_REF), "ENGINE_up_ref"},
++    {ERR_FUNC(ENGINE_F_INT_CTRL_HELPER), "int_ctrl_helper"},
++    {ERR_FUNC(ENGINE_F_INT_ENGINE_CONFIGURE), "int_engine_configure"},
++    {ERR_FUNC(ENGINE_F_INT_ENGINE_MODULE_INIT), "int_engine_module_init"},
++    {0, NULL}
++};
++
++static ERR_STRING_DATA ENGINE_str_reasons[] = {
++    {ERR_REASON(ENGINE_R_ALREADY_LOADED), "already loaded"},
++    {ERR_REASON(ENGINE_R_ARGUMENT_IS_NOT_A_NUMBER),
++     "argument is not a number"},
++    {ERR_REASON(ENGINE_R_CMD_NOT_EXECUTABLE), "cmd not executable"},
++    {ERR_REASON(ENGINE_R_COMMAND_TAKES_INPUT), "command takes input"},
++    {ERR_REASON(ENGINE_R_COMMAND_TAKES_NO_INPUT), "command takes no input"},
++    {ERR_REASON(ENGINE_R_CONFLICTING_ENGINE_ID), "conflicting engine id"},
++    {ERR_REASON(ENGINE_R_CTRL_COMMAND_NOT_IMPLEMENTED),
++     "ctrl command not implemented"},
++    {ERR_REASON(ENGINE_R_DSO_FAILURE), "DSO failure"},
++    {ERR_REASON(ENGINE_R_DSO_NOT_FOUND), "dso not found"},
++    {ERR_REASON(ENGINE_R_ENGINES_SECTION_ERROR), "engines section error"},
++    {ERR_REASON(ENGINE_R_ENGINE_CONFIGURATION_ERROR),
++     "engine configuration error"},
++    {ERR_REASON(ENGINE_R_ENGINE_IS_NOT_IN_LIST), "engine is not in the list"},
++    {ERR_REASON(ENGINE_R_ENGINE_SECTION_ERROR), "engine section error"},
++    {ERR_REASON(ENGINE_R_FAILED_LOADING_PRIVATE_KEY),
++     "failed loading private key"},
++    {ERR_REASON(ENGINE_R_FAILED_LOADING_PUBLIC_KEY),
++     "failed loading public key"},
++    {ERR_REASON(ENGINE_R_FINISH_FAILED), "finish failed"},
++    {ERR_REASON(ENGINE_R_ID_OR_NAME_MISSING), "'id' or 'name' missing"},
++    {ERR_REASON(ENGINE_R_INIT_FAILED), "init failed"},
++    {ERR_REASON(ENGINE_R_INTERNAL_LIST_ERROR), "internal list error"},
++    {ERR_REASON(ENGINE_R_INVALID_ARGUMENT), "invalid argument"},
++    {ERR_REASON(ENGINE_R_INVALID_CMD_NAME), "invalid cmd name"},
++    {ERR_REASON(ENGINE_R_INVALID_CMD_NUMBER), "invalid cmd number"},
++    {ERR_REASON(ENGINE_R_INVALID_INIT_VALUE), "invalid init value"},
++    {ERR_REASON(ENGINE_R_INVALID_STRING), "invalid string"},
++    {ERR_REASON(ENGINE_R_NOT_INITIALISED), "not initialised"},
++    {ERR_REASON(ENGINE_R_NOT_LOADED), "not loaded"},
++    {ERR_REASON(ENGINE_R_NO_CONTROL_FUNCTION), "no control function"},
++    {ERR_REASON(ENGINE_R_NO_INDEX), "no index"},
++    {ERR_REASON(ENGINE_R_NO_LOAD_FUNCTION), "no load function"},
++    {ERR_REASON(ENGINE_R_NO_REFERENCE), "no reference"},
++    {ERR_REASON(ENGINE_R_NO_SUCH_ENGINE), "no such engine"},
++    {ERR_REASON(ENGINE_R_UNIMPLEMENTED_CIPHER), "unimplemented cipher"},
++    {ERR_REASON(ENGINE_R_UNIMPLEMENTED_DIGEST), "unimplemented digest"},
++    {ERR_REASON(ENGINE_R_UNIMPLEMENTED_PUBLIC_KEY_METHOD),
++     "unimplemented public key method"},
++    {ERR_REASON(ENGINE_R_VERSION_INCOMPATIBILITY), "version incompatibility"},
++    {0, NULL}
++};
++
++#endif
++
++int ERR_load_ENGINE_strings(void)
++{
++#ifndef OPENSSL_NO_ERR
++
++    if (ERR_func_error_string(ENGINE_str_functs[0].error) == NULL) {
++        ERR_load_strings(0, ENGINE_str_functs);
++        ERR_load_strings(0, ENGINE_str_reasons);
++    }
++#endif
++    return 1;
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/engine/eng_fat.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/engine/eng_fat.c
+new file mode 100644
+index 0000000..631aa39
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/engine/eng_fat.c
+@@ -0,0 +1,127 @@
++/*
++ * Copyright 2001-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++/* ====================================================================
++ * Copyright 2002 Sun Microsystems, Inc. ALL RIGHTS RESERVED.
++ * ECDH support in OpenSSL originally developed by
++ * SUN MICROSYSTEMS, INC., and contributed to the OpenSSL project.
++ */
++
++#include "eng_int.h"
++#include 
++
++int ENGINE_set_default(ENGINE *e, unsigned int flags)
++{
++    if ((flags & ENGINE_METHOD_CIPHERS) && !ENGINE_set_default_ciphers(e))
++        return 0;
++    if ((flags & ENGINE_METHOD_DIGESTS) && !ENGINE_set_default_digests(e))
++        return 0;
++#ifndef OPENSSL_NO_RSA
++    if ((flags & ENGINE_METHOD_RSA) && !ENGINE_set_default_RSA(e))
++        return 0;
++#endif
++#ifndef OPENSSL_NO_DSA
++    if ((flags & ENGINE_METHOD_DSA) && !ENGINE_set_default_DSA(e))
++        return 0;
++#endif
++#ifndef OPENSSL_NO_DH
++    if ((flags & ENGINE_METHOD_DH) && !ENGINE_set_default_DH(e))
++        return 0;
++#endif
++#ifndef OPENSSL_NO_EC
++    if ((flags & ENGINE_METHOD_EC) && !ENGINE_set_default_EC(e))
++        return 0;
++#endif
++    if ((flags & ENGINE_METHOD_RAND) && !ENGINE_set_default_RAND(e))
++        return 0;
++    if ((flags & ENGINE_METHOD_PKEY_METHS)
++        && !ENGINE_set_default_pkey_meths(e))
++        return 0;
++    if ((flags & ENGINE_METHOD_PKEY_ASN1_METHS)
++        && !ENGINE_set_default_pkey_asn1_meths(e))
++        return 0;
++    return 1;
++}
++
++/* Set default algorithms using a string */
++
++static int int_def_cb(const char *alg, int len, void *arg)
++{
++    unsigned int *pflags = arg;
++    if (alg == NULL)
++        return 0;
++    if (strncmp(alg, "ALL", len) == 0)
++        *pflags |= ENGINE_METHOD_ALL;
++    else if (strncmp(alg, "RSA", len) == 0)
++        *pflags |= ENGINE_METHOD_RSA;
++    else if (strncmp(alg, "DSA", len) == 0)
++        *pflags |= ENGINE_METHOD_DSA;
++    else if (strncmp(alg, "DH", len) == 0)
++        *pflags |= ENGINE_METHOD_DH;
++    else if (strncmp(alg, "EC", len) == 0)
++        *pflags |= ENGINE_METHOD_EC;
++    else if (strncmp(alg, "RAND", len) == 0)
++        *pflags |= ENGINE_METHOD_RAND;
++    else if (strncmp(alg, "CIPHERS", len) == 0)
++        *pflags |= ENGINE_METHOD_CIPHERS;
++    else if (strncmp(alg, "DIGESTS", len) == 0)
++        *pflags |= ENGINE_METHOD_DIGESTS;
++    else if (strncmp(alg, "PKEY", len) == 0)
++        *pflags |= ENGINE_METHOD_PKEY_METHS | ENGINE_METHOD_PKEY_ASN1_METHS;
++    else if (strncmp(alg, "PKEY_CRYPTO", len) == 0)
++        *pflags |= ENGINE_METHOD_PKEY_METHS;
++    else if (strncmp(alg, "PKEY_ASN1", len) == 0)
++        *pflags |= ENGINE_METHOD_PKEY_ASN1_METHS;
++    else
++        return 0;
++    return 1;
++}
++
++int ENGINE_set_default_string(ENGINE *e, const char *def_list)
++{
++    unsigned int flags = 0;
++    if (!CONF_parse_list(def_list, ',', 1, int_def_cb, &flags)) {
++        ENGINEerr(ENGINE_F_ENGINE_SET_DEFAULT_STRING,
++                  ENGINE_R_INVALID_STRING);
++        ERR_add_error_data(2, "str=", def_list);
++        return 0;
++    }
++    return ENGINE_set_default(e, flags);
++}
++
++int ENGINE_register_complete(ENGINE *e)
++{
++    ENGINE_register_ciphers(e);
++    ENGINE_register_digests(e);
++#ifndef OPENSSL_NO_RSA
++    ENGINE_register_RSA(e);
++#endif
++#ifndef OPENSSL_NO_DSA
++    ENGINE_register_DSA(e);
++#endif
++#ifndef OPENSSL_NO_DH
++    ENGINE_register_DH(e);
++#endif
++#ifndef OPENSSL_NO_EC
++    ENGINE_register_EC(e);
++#endif
++    ENGINE_register_RAND(e);
++    ENGINE_register_pkey_meths(e);
++    return 1;
++}
++
++int ENGINE_register_all_complete(void)
++{
++    ENGINE *e;
++
++    for (e = ENGINE_get_first(); e; e = ENGINE_get_next(e))
++        if (!(e->flags & ENGINE_FLAGS_NO_REGISTER_ALL))
++            ENGINE_register_complete(e);
++    return 1;
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/engine/eng_init.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/engine/eng_init.c
+new file mode 100644
+index 0000000..8be7c6f
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/engine/eng_init.c
+@@ -0,0 +1,108 @@
++/*
++ * Copyright 2001-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include "eng_int.h"
++
++/*
++ * Initialise a engine type for use (or up its functional reference count if
++ * it's already in use). This version is only used internally.
++ */
++int engine_unlocked_init(ENGINE *e)
++{
++    int to_return = 1;
++
++    if ((e->funct_ref == 0) && e->init)
++        /*
++         * This is the first functional reference and the engine requires
++         * initialisation so we do it now.
++         */
++        to_return = e->init(e);
++    if (to_return) {
++        /*
++         * OK, we return a functional reference which is also a structural
++         * reference.
++         */
++        e->struct_ref++;
++        e->funct_ref++;
++        engine_ref_debug(e, 0, 1);
++        engine_ref_debug(e, 1, 1);
++    }
++    return to_return;
++}
++
++/*
++ * Free a functional reference to a engine type. This version is only used
++ * internally.
++ */
++int engine_unlocked_finish(ENGINE *e, int unlock_for_handlers)
++{
++    int to_return = 1;
++
++    /*
++     * Reduce the functional reference count here so if it's the terminating
++     * case, we can release the lock safely and call the finish() handler
++     * without risk of a race. We get a race if we leave the count until
++     * after and something else is calling "finish" at the same time -
++     * there's a chance that both threads will together take the count from 2
++     * to 0 without either calling finish().
++     */
++    e->funct_ref--;
++    engine_ref_debug(e, 1, -1);
++    if ((e->funct_ref == 0) && e->finish) {
++        if (unlock_for_handlers)
++            CRYPTO_THREAD_unlock(global_engine_lock);
++        to_return = e->finish(e);
++        if (unlock_for_handlers)
++            CRYPTO_THREAD_write_lock(global_engine_lock);
++        if (!to_return)
++            return 0;
++    }
++    REF_ASSERT_ISNT(e->funct_ref < 0);
++    /* Release the structural reference too */
++    if (!engine_free_util(e, 0)) {
++        ENGINEerr(ENGINE_F_ENGINE_UNLOCKED_FINISH, ENGINE_R_FINISH_FAILED);
++        return 0;
++    }
++    return to_return;
++}
++
++/* The API (locked) version of "init" */
++int ENGINE_init(ENGINE *e)
++{
++    int ret;
++    if (e == NULL) {
++        ENGINEerr(ENGINE_F_ENGINE_INIT, ERR_R_PASSED_NULL_PARAMETER);
++        return 0;
++    }
++    if (!RUN_ONCE(&engine_lock_init, do_engine_lock_init)) {
++        ENGINEerr(ENGINE_F_ENGINE_INIT, ERR_R_MALLOC_FAILURE);
++        return 0;
++    }
++    CRYPTO_THREAD_write_lock(global_engine_lock);
++    ret = engine_unlocked_init(e);
++    CRYPTO_THREAD_unlock(global_engine_lock);
++    return ret;
++}
++
++/* The API (locked) version of "finish" */
++int ENGINE_finish(ENGINE *e)
++{
++    int to_return = 1;
++
++    if (e == NULL)
++        return 1;
++    CRYPTO_THREAD_write_lock(global_engine_lock);
++    to_return = engine_unlocked_finish(e, 1);
++    CRYPTO_THREAD_unlock(global_engine_lock);
++    if (!to_return) {
++        ENGINEerr(ENGINE_F_ENGINE_FINISH, ENGINE_R_FINISH_FAILED);
++        return 0;
++    }
++    return to_return;
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/engine/eng_int.h b/CryptoPkg/Library/OpensslLib/openssl/crypto/engine/eng_int.h
+new file mode 100644
+index 0000000..c604fad
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/engine/eng_int.h
+@@ -0,0 +1,183 @@
++/*
++ * Copyright 2001-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++/* ====================================================================
++ * Copyright 2002 Sun Microsystems, Inc. ALL RIGHTS RESERVED.
++ * ECDH support in OpenSSL originally developed by
++ * SUN MICROSYSTEMS, INC., and contributed to the OpenSSL project.
++ */
++
++#ifndef HEADER_ENGINE_INT_H
++# define HEADER_ENGINE_INT_H
++
++# include "internal/cryptlib.h"
++# include 
++# include 
++
++#ifdef  __cplusplus
++extern "C" {
++#endif
++
++extern CRYPTO_RWLOCK *global_engine_lock;
++
++/*
++ * If we compile with this symbol defined, then both reference counts in the
++ * ENGINE structure will be monitored with a line of output on stderr for
++ * each change. This prints the engine's pointer address (truncated to
++ * unsigned int), "struct" or "funct" to indicate the reference type, the
++ * before and after reference count, and the file:line-number pair. The
++ * "engine_ref_debug" statements must come *after* the change.
++ */
++# ifdef ENGINE_REF_COUNT_DEBUG
++
++#  define engine_ref_debug(e, isfunct, diff) \
++        fprintf(stderr, "engine: %08x %s from %d to %d (%s:%d)\n", \
++                (unsigned int)(e), (isfunct ? "funct" : "struct"), \
++                ((isfunct) ? ((e)->funct_ref - (diff)) : ((e)->struct_ref - (diff))), \
++                ((isfunct) ? (e)->funct_ref : (e)->struct_ref), \
++                (OPENSSL_FILE), (OPENSSL_LINE))
++
++# else
++
++#  define engine_ref_debug(e, isfunct, diff)
++
++# endif
++
++/*
++ * Any code that will need cleanup operations should use these functions to
++ * register callbacks. engine_cleanup_int() will call all registered
++ * callbacks in order. NB: both the "add" functions assume the engine lock to
++ * already be held (in "write" mode).
++ */
++typedef void (ENGINE_CLEANUP_CB) (void);
++typedef struct st_engine_cleanup_item {
++    ENGINE_CLEANUP_CB *cb;
++} ENGINE_CLEANUP_ITEM;
++DEFINE_STACK_OF(ENGINE_CLEANUP_ITEM)
++void engine_cleanup_add_first(ENGINE_CLEANUP_CB *cb);
++void engine_cleanup_add_last(ENGINE_CLEANUP_CB *cb);
++
++/* We need stacks of ENGINEs for use in eng_table.c */
++DEFINE_STACK_OF(ENGINE)
++
++/*
++ * If this symbol is defined then engine_table_select(), the function that is
++ * used by RSA, DSA (etc) code to select registered ENGINEs, cache defaults
++ * and functional references (etc), will display debugging summaries to
++ * stderr.
++ */
++/* #define ENGINE_TABLE_DEBUG */
++
++/*
++ * This represents an implementation table. Dependent code should instantiate
++ * it as a (ENGINE_TABLE *) pointer value set initially to NULL.
++ */
++typedef struct st_engine_table ENGINE_TABLE;
++int engine_table_register(ENGINE_TABLE **table, ENGINE_CLEANUP_CB *cleanup,
++                          ENGINE *e, const int *nids, int num_nids,
++                          int setdefault);
++void engine_table_unregister(ENGINE_TABLE **table, ENGINE *e);
++void engine_table_cleanup(ENGINE_TABLE **table);
++# ifndef ENGINE_TABLE_DEBUG
++ENGINE *engine_table_select(ENGINE_TABLE **table, int nid);
++# else
++ENGINE *engine_table_select_tmp(ENGINE_TABLE **table, int nid, const char *f,
++                                int l);
++#  define engine_table_select(t,n) engine_table_select_tmp(t,n,OPENSSL_FILE,OPENSSL_LINE)
++# endif
++typedef void (engine_table_doall_cb) (int nid, STACK_OF(ENGINE) *sk,
++                                      ENGINE *def, void *arg);
++void engine_table_doall(ENGINE_TABLE *table, engine_table_doall_cb *cb,
++                        void *arg);
++
++/*
++ * Internal versions of API functions that have control over locking. These
++ * are used between C files when functionality needs to be shared but the
++ * caller may already be controlling of the engine lock.
++ */
++int engine_unlocked_init(ENGINE *e);
++int engine_unlocked_finish(ENGINE *e, int unlock_for_handlers);
++int engine_free_util(ENGINE *e, int locked);
++
++/*
++ * This function will reset all "set"able values in an ENGINE to NULL. This
++ * won't touch reference counts or ex_data, but is equivalent to calling all
++ * the ENGINE_set_***() functions with a NULL value.
++ */
++void engine_set_all_null(ENGINE *e);
++
++/*
++ * NB: Bitwise OR-able values for the "flags" variable in ENGINE are now
++ * exposed in engine.h.
++ */
++
++/* Free up dynamically allocated public key methods associated with ENGINE */
++
++void engine_pkey_meths_free(ENGINE *e);
++void engine_pkey_asn1_meths_free(ENGINE *e);
++
++/* Once initialisation function */
++extern CRYPTO_ONCE engine_lock_init;
++DECLARE_RUN_ONCE(do_engine_lock_init)
++
++/*
++ * This is a structure for storing implementations of various crypto
++ * algorithms and functions.
++ */
++struct engine_st {
++    const char *id;
++    const char *name;
++    const RSA_METHOD *rsa_meth;
++    const DSA_METHOD *dsa_meth;
++    const DH_METHOD *dh_meth;
++    const EC_KEY_METHOD *ec_meth;
++    const RAND_METHOD *rand_meth;
++    /* Cipher handling is via this callback */
++    ENGINE_CIPHERS_PTR ciphers;
++    /* Digest handling is via this callback */
++    ENGINE_DIGESTS_PTR digests;
++    /* Public key handling via this callback */
++    ENGINE_PKEY_METHS_PTR pkey_meths;
++    /* ASN1 public key handling via this callback */
++    ENGINE_PKEY_ASN1_METHS_PTR pkey_asn1_meths;
++    ENGINE_GEN_INT_FUNC_PTR destroy;
++    ENGINE_GEN_INT_FUNC_PTR init;
++    ENGINE_GEN_INT_FUNC_PTR finish;
++    ENGINE_CTRL_FUNC_PTR ctrl;
++    ENGINE_LOAD_KEY_PTR load_privkey;
++    ENGINE_LOAD_KEY_PTR load_pubkey;
++    ENGINE_SSL_CLIENT_CERT_PTR load_ssl_client_cert;
++    const ENGINE_CMD_DEFN *cmd_defns;
++    int flags;
++    /* reference count on the structure itself */
++    int struct_ref;
++    /*
++     * reference count on usability of the engine type. NB: This controls the
++     * loading and initialisation of any functionality required by this
++     * engine, whereas the previous count is simply to cope with
++     * (de)allocation of this structure. Hence, running_ref <= struct_ref at
++     * all times.
++     */
++    int funct_ref;
++    /* A place to store per-ENGINE data */
++    CRYPTO_EX_DATA ex_data;
++    /* Used to maintain the linked-list of engines. */
++    struct engine_st *prev;
++    struct engine_st *next;
++};
++
++typedef struct st_engine_pile ENGINE_PILE;
++
++DEFINE_LHASH_OF(ENGINE_PILE);
++
++#ifdef  __cplusplus
++}
++#endif
++
++#endif                          /* HEADER_ENGINE_INT_H */
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/engine/eng_lib.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/engine/eng_lib.c
+new file mode 100644
+index 0000000..28de21d
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/engine/eng_lib.c
+@@ -0,0 +1,295 @@
++/*
++ * Copyright 2001-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include "eng_int.h"
++#include 
++
++CRYPTO_RWLOCK *global_engine_lock;
++
++CRYPTO_ONCE engine_lock_init = CRYPTO_ONCE_STATIC_INIT;
++
++/* The "new"/"free" stuff first */
++
++DEFINE_RUN_ONCE(do_engine_lock_init)
++{
++    OPENSSL_init_crypto(0, NULL);
++    global_engine_lock = CRYPTO_THREAD_lock_new();
++    return global_engine_lock != NULL;
++}
++
++ENGINE *ENGINE_new(void)
++{
++    ENGINE *ret;
++
++    if (!RUN_ONCE(&engine_lock_init, do_engine_lock_init)
++        || (ret = OPENSSL_zalloc(sizeof(*ret))) == NULL) {
++        ENGINEerr(ENGINE_F_ENGINE_NEW, ERR_R_MALLOC_FAILURE);
++        return NULL;
++    }
++    ret->struct_ref = 1;
++    engine_ref_debug(ret, 0, 1);
++    if (!CRYPTO_new_ex_data(CRYPTO_EX_INDEX_ENGINE, ret, &ret->ex_data)) {
++        OPENSSL_free(ret);
++        return NULL;
++    }
++    return ret;
++}
++
++/*
++ * Placed here (close proximity to ENGINE_new) so that modifications to the
++ * elements of the ENGINE structure are more likely to be caught and changed
++ * here.
++ */
++void engine_set_all_null(ENGINE *e)
++{
++    e->id = NULL;
++    e->name = NULL;
++    e->rsa_meth = NULL;
++    e->dsa_meth = NULL;
++    e->dh_meth = NULL;
++    e->rand_meth = NULL;
++    e->ciphers = NULL;
++    e->digests = NULL;
++    e->destroy = NULL;
++    e->init = NULL;
++    e->finish = NULL;
++    e->ctrl = NULL;
++    e->load_privkey = NULL;
++    e->load_pubkey = NULL;
++    e->cmd_defns = NULL;
++    e->flags = 0;
++}
++
++int engine_free_util(ENGINE *e, int locked)
++{
++    int i;
++
++    if (e == NULL)
++        return 1;
++    if (locked)
++        CRYPTO_atomic_add(&e->struct_ref, -1, &i, global_engine_lock);
++    else
++        i = --e->struct_ref;
++    engine_ref_debug(e, 0, -1)
++    if (i > 0)
++        return 1;
++    REF_ASSERT_ISNT(i < 0);
++    /* Free up any dynamically allocated public key methods */
++    engine_pkey_meths_free(e);
++    engine_pkey_asn1_meths_free(e);
++    /*
++     * Give the ENGINE a chance to do any structural cleanup corresponding to
++     * allocation it did in its constructor (eg. unload error strings)
++     */
++    if (e->destroy)
++        e->destroy(e);
++    CRYPTO_free_ex_data(CRYPTO_EX_INDEX_ENGINE, e, &e->ex_data);
++    OPENSSL_free(e);
++    return 1;
++}
++
++int ENGINE_free(ENGINE *e)
++{
++    return engine_free_util(e, 1);
++}
++
++/* Cleanup stuff */
++
++/*
++ * engine_cleanup_int() is coded such that anything that does work that will
++ * need cleanup can register a "cleanup" callback here. That way we don't get
++ * linker bloat by referring to all *possible* cleanups, but any linker bloat
++ * into code "X" will cause X's cleanup function to end up here.
++ */
++static STACK_OF(ENGINE_CLEANUP_ITEM) *cleanup_stack = NULL;
++static int int_cleanup_check(int create)
++{
++    if (cleanup_stack)
++        return 1;
++    if (!create)
++        return 0;
++    cleanup_stack = sk_ENGINE_CLEANUP_ITEM_new_null();
++    return (cleanup_stack ? 1 : 0);
++}
++
++static ENGINE_CLEANUP_ITEM *int_cleanup_item(ENGINE_CLEANUP_CB *cb)
++{
++    ENGINE_CLEANUP_ITEM *item = OPENSSL_malloc(sizeof(*item));
++    if (item == NULL)
++        return NULL;
++    item->cb = cb;
++    return item;
++}
++
++void engine_cleanup_add_first(ENGINE_CLEANUP_CB *cb)
++{
++    ENGINE_CLEANUP_ITEM *item;
++    if (!int_cleanup_check(1))
++        return;
++    item = int_cleanup_item(cb);
++    if (item)
++        sk_ENGINE_CLEANUP_ITEM_insert(cleanup_stack, item, 0);
++}
++
++void engine_cleanup_add_last(ENGINE_CLEANUP_CB *cb)
++{
++    ENGINE_CLEANUP_ITEM *item;
++    if (!int_cleanup_check(1))
++        return;
++    item = int_cleanup_item(cb);
++    if (item)
++        sk_ENGINE_CLEANUP_ITEM_push(cleanup_stack, item);
++}
++
++/* The API function that performs all cleanup */
++static void engine_cleanup_cb_free(ENGINE_CLEANUP_ITEM *item)
++{
++    (*(item->cb)) ();
++    OPENSSL_free(item);
++}
++
++void engine_cleanup_int(void)
++{
++    if (int_cleanup_check(0)) {
++        sk_ENGINE_CLEANUP_ITEM_pop_free(cleanup_stack,
++                                        engine_cleanup_cb_free);
++        cleanup_stack = NULL;
++    }
++    /*
++     * FIXME: This should be handled (somehow) through RAND, eg. by it
++     * registering a cleanup callback.
++     */
++    RAND_set_rand_method(NULL);
++    CRYPTO_THREAD_lock_free(global_engine_lock);
++}
++
++/* Now the "ex_data" support */
++
++int ENGINE_set_ex_data(ENGINE *e, int idx, void *arg)
++{
++    return (CRYPTO_set_ex_data(&e->ex_data, idx, arg));
++}
++
++void *ENGINE_get_ex_data(const ENGINE *e, int idx)
++{
++    return (CRYPTO_get_ex_data(&e->ex_data, idx));
++}
++
++/*
++ * Functions to get/set an ENGINE's elements - mainly to avoid exposing the
++ * ENGINE structure itself.
++ */
++
++int ENGINE_set_id(ENGINE *e, const char *id)
++{
++    if (id == NULL) {
++        ENGINEerr(ENGINE_F_ENGINE_SET_ID, ERR_R_PASSED_NULL_PARAMETER);
++        return 0;
++    }
++    e->id = id;
++    return 1;
++}
++
++int ENGINE_set_name(ENGINE *e, const char *name)
++{
++    if (name == NULL) {
++        ENGINEerr(ENGINE_F_ENGINE_SET_NAME, ERR_R_PASSED_NULL_PARAMETER);
++        return 0;
++    }
++    e->name = name;
++    return 1;
++}
++
++int ENGINE_set_destroy_function(ENGINE *e, ENGINE_GEN_INT_FUNC_PTR destroy_f)
++{
++    e->destroy = destroy_f;
++    return 1;
++}
++
++int ENGINE_set_init_function(ENGINE *e, ENGINE_GEN_INT_FUNC_PTR init_f)
++{
++    e->init = init_f;
++    return 1;
++}
++
++int ENGINE_set_finish_function(ENGINE *e, ENGINE_GEN_INT_FUNC_PTR finish_f)
++{
++    e->finish = finish_f;
++    return 1;
++}
++
++int ENGINE_set_ctrl_function(ENGINE *e, ENGINE_CTRL_FUNC_PTR ctrl_f)
++{
++    e->ctrl = ctrl_f;
++    return 1;
++}
++
++int ENGINE_set_flags(ENGINE *e, int flags)
++{
++    e->flags = flags;
++    return 1;
++}
++
++int ENGINE_set_cmd_defns(ENGINE *e, const ENGINE_CMD_DEFN *defns)
++{
++    e->cmd_defns = defns;
++    return 1;
++}
++
++const char *ENGINE_get_id(const ENGINE *e)
++{
++    return e->id;
++}
++
++const char *ENGINE_get_name(const ENGINE *e)
++{
++    return e->name;
++}
++
++ENGINE_GEN_INT_FUNC_PTR ENGINE_get_destroy_function(const ENGINE *e)
++{
++    return e->destroy;
++}
++
++ENGINE_GEN_INT_FUNC_PTR ENGINE_get_init_function(const ENGINE *e)
++{
++    return e->init;
++}
++
++ENGINE_GEN_INT_FUNC_PTR ENGINE_get_finish_function(const ENGINE *e)
++{
++    return e->finish;
++}
++
++ENGINE_CTRL_FUNC_PTR ENGINE_get_ctrl_function(const ENGINE *e)
++{
++    return e->ctrl;
++}
++
++int ENGINE_get_flags(const ENGINE *e)
++{
++    return e->flags;
++}
++
++const ENGINE_CMD_DEFN *ENGINE_get_cmd_defns(const ENGINE *e)
++{
++    return e->cmd_defns;
++}
++
++/*
++ * eng_lib.o is pretty much linked into anything that touches ENGINE already,
++ * so put the "static_state" hack here.
++ */
++
++static int internal_static_hack = 0;
++
++void *ENGINE_get_static_state(void)
++{
++    return &internal_static_hack;
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/engine/eng_list.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/engine/eng_list.c
+new file mode 100644
+index 0000000..934389f
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/engine/eng_list.c
+@@ -0,0 +1,354 @@
++/*
++ * Copyright 2001-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++/* ====================================================================
++ * Copyright 2002 Sun Microsystems, Inc. ALL RIGHTS RESERVED.
++ * ECDH support in OpenSSL originally developed by
++ * SUN MICROSYSTEMS, INC., and contributed to the OpenSSL project.
++ */
++
++#include "eng_int.h"
++
++/*
++ * The linked-list of pointers to engine types. engine_list_head incorporates
++ * an implicit structural reference but engine_list_tail does not - the
++ * latter is a computational niceity and only points to something that is
++ * already pointed to by its predecessor in the list (or engine_list_head
++ * itself). In the same way, the use of the "prev" pointer in each ENGINE is
++ * to save excessive list iteration, it doesn't correspond to an extra
++ * structural reference. Hence, engine_list_head, and each non-null "next"
++ * pointer account for the list itself assuming exactly 1 structural
++ * reference on each list member.
++ */
++static ENGINE *engine_list_head = NULL;
++static ENGINE *engine_list_tail = NULL;
++
++/*
++ * This cleanup function is only needed internally. If it should be called,
++ * we register it with the "engine_cleanup_int()" stack to be called during
++ * cleanup.
++ */
++
++static void engine_list_cleanup(void)
++{
++    ENGINE *iterator = engine_list_head;
++
++    while (iterator != NULL) {
++        ENGINE_remove(iterator);
++        iterator = engine_list_head;
++    }
++    return;
++}
++
++/*
++ * These static functions starting with a lower case "engine_" always take
++ * place when global_engine_lock has been locked up.
++ */
++static int engine_list_add(ENGINE *e)
++{
++    int conflict = 0;
++    ENGINE *iterator = NULL;
++
++    if (e == NULL) {
++        ENGINEerr(ENGINE_F_ENGINE_LIST_ADD, ERR_R_PASSED_NULL_PARAMETER);
++        return 0;
++    }
++    iterator = engine_list_head;
++    while (iterator && !conflict) {
++        conflict = (strcmp(iterator->id, e->id) == 0);
++        iterator = iterator->next;
++    }
++    if (conflict) {
++        ENGINEerr(ENGINE_F_ENGINE_LIST_ADD, ENGINE_R_CONFLICTING_ENGINE_ID);
++        return 0;
++    }
++    if (engine_list_head == NULL) {
++        /* We are adding to an empty list. */
++        if (engine_list_tail) {
++            ENGINEerr(ENGINE_F_ENGINE_LIST_ADD, ENGINE_R_INTERNAL_LIST_ERROR);
++            return 0;
++        }
++        engine_list_head = e;
++        e->prev = NULL;
++        /*
++         * The first time the list allocates, we should register the cleanup.
++         */
++        engine_cleanup_add_last(engine_list_cleanup);
++    } else {
++        /* We are adding to the tail of an existing list. */
++        if ((engine_list_tail == NULL) || (engine_list_tail->next != NULL)) {
++            ENGINEerr(ENGINE_F_ENGINE_LIST_ADD, ENGINE_R_INTERNAL_LIST_ERROR);
++            return 0;
++        }
++        engine_list_tail->next = e;
++        e->prev = engine_list_tail;
++    }
++    /*
++     * Having the engine in the list assumes a structural reference.
++     */
++    e->struct_ref++;
++    engine_ref_debug(e, 0, 1);
++    /* However it came to be, e is the last item in the list. */
++    engine_list_tail = e;
++    e->next = NULL;
++    return 1;
++}
++
++static int engine_list_remove(ENGINE *e)
++{
++    ENGINE *iterator;
++
++    if (e == NULL) {
++        ENGINEerr(ENGINE_F_ENGINE_LIST_REMOVE, ERR_R_PASSED_NULL_PARAMETER);
++        return 0;
++    }
++    /* We need to check that e is in our linked list! */
++    iterator = engine_list_head;
++    while (iterator && (iterator != e))
++        iterator = iterator->next;
++    if (iterator == NULL) {
++        ENGINEerr(ENGINE_F_ENGINE_LIST_REMOVE,
++                  ENGINE_R_ENGINE_IS_NOT_IN_LIST);
++        return 0;
++    }
++    /* un-link e from the chain. */
++    if (e->next)
++        e->next->prev = e->prev;
++    if (e->prev)
++        e->prev->next = e->next;
++    /* Correct our head/tail if necessary. */
++    if (engine_list_head == e)
++        engine_list_head = e->next;
++    if (engine_list_tail == e)
++        engine_list_tail = e->prev;
++    engine_free_util(e, 0);
++    return 1;
++}
++
++/* Get the first/last "ENGINE" type available. */
++ENGINE *ENGINE_get_first(void)
++{
++    ENGINE *ret;
++
++    if (!RUN_ONCE(&engine_lock_init, do_engine_lock_init)) {
++        ENGINEerr(ENGINE_F_ENGINE_GET_FIRST, ERR_R_MALLOC_FAILURE);
++        return NULL;
++    }
++
++    CRYPTO_THREAD_write_lock(global_engine_lock);
++    ret = engine_list_head;
++    if (ret) {
++        ret->struct_ref++;
++        engine_ref_debug(ret, 0, 1);
++    }
++    CRYPTO_THREAD_unlock(global_engine_lock);
++    return ret;
++}
++
++ENGINE *ENGINE_get_last(void)
++{
++    ENGINE *ret;
++
++    if (!RUN_ONCE(&engine_lock_init, do_engine_lock_init)) {
++        ENGINEerr(ENGINE_F_ENGINE_GET_LAST, ERR_R_MALLOC_FAILURE);
++        return NULL;
++    }
++
++    CRYPTO_THREAD_write_lock(global_engine_lock);
++    ret = engine_list_tail;
++    if (ret) {
++        ret->struct_ref++;
++        engine_ref_debug(ret, 0, 1);
++    }
++    CRYPTO_THREAD_unlock(global_engine_lock);
++    return ret;
++}
++
++/* Iterate to the next/previous "ENGINE" type (NULL = end of the list). */
++ENGINE *ENGINE_get_next(ENGINE *e)
++{
++    ENGINE *ret = NULL;
++    if (e == NULL) {
++        ENGINEerr(ENGINE_F_ENGINE_GET_NEXT, ERR_R_PASSED_NULL_PARAMETER);
++        return 0;
++    }
++    CRYPTO_THREAD_write_lock(global_engine_lock);
++    ret = e->next;
++    if (ret) {
++        /* Return a valid structural reference to the next ENGINE */
++        ret->struct_ref++;
++        engine_ref_debug(ret, 0, 1);
++    }
++    CRYPTO_THREAD_unlock(global_engine_lock);
++    /* Release the structural reference to the previous ENGINE */
++    ENGINE_free(e);
++    return ret;
++}
++
++ENGINE *ENGINE_get_prev(ENGINE *e)
++{
++    ENGINE *ret = NULL;
++    if (e == NULL) {
++        ENGINEerr(ENGINE_F_ENGINE_GET_PREV, ERR_R_PASSED_NULL_PARAMETER);
++        return 0;
++    }
++    CRYPTO_THREAD_write_lock(global_engine_lock);
++    ret = e->prev;
++    if (ret) {
++        /* Return a valid structural reference to the next ENGINE */
++        ret->struct_ref++;
++        engine_ref_debug(ret, 0, 1);
++    }
++    CRYPTO_THREAD_unlock(global_engine_lock);
++    /* Release the structural reference to the previous ENGINE */
++    ENGINE_free(e);
++    return ret;
++}
++
++/* Add another "ENGINE" type into the list. */
++int ENGINE_add(ENGINE *e)
++{
++    int to_return = 1;
++    if (e == NULL) {
++        ENGINEerr(ENGINE_F_ENGINE_ADD, ERR_R_PASSED_NULL_PARAMETER);
++        return 0;
++    }
++    if ((e->id == NULL) || (e->name == NULL)) {
++        ENGINEerr(ENGINE_F_ENGINE_ADD, ENGINE_R_ID_OR_NAME_MISSING);
++        return 0;
++    }
++    CRYPTO_THREAD_write_lock(global_engine_lock);
++    if (!engine_list_add(e)) {
++        ENGINEerr(ENGINE_F_ENGINE_ADD, ENGINE_R_INTERNAL_LIST_ERROR);
++        to_return = 0;
++    }
++    CRYPTO_THREAD_unlock(global_engine_lock);
++    return to_return;
++}
++
++/* Remove an existing "ENGINE" type from the array. */
++int ENGINE_remove(ENGINE *e)
++{
++    int to_return = 1;
++    if (e == NULL) {
++        ENGINEerr(ENGINE_F_ENGINE_REMOVE, ERR_R_PASSED_NULL_PARAMETER);
++        return 0;
++    }
++    CRYPTO_THREAD_write_lock(global_engine_lock);
++    if (!engine_list_remove(e)) {
++        ENGINEerr(ENGINE_F_ENGINE_REMOVE, ENGINE_R_INTERNAL_LIST_ERROR);
++        to_return = 0;
++    }
++    CRYPTO_THREAD_unlock(global_engine_lock);
++    return to_return;
++}
++
++static void engine_cpy(ENGINE *dest, const ENGINE *src)
++{
++    dest->id = src->id;
++    dest->name = src->name;
++#ifndef OPENSSL_NO_RSA
++    dest->rsa_meth = src->rsa_meth;
++#endif
++#ifndef OPENSSL_NO_DSA
++    dest->dsa_meth = src->dsa_meth;
++#endif
++#ifndef OPENSSL_NO_DH
++    dest->dh_meth = src->dh_meth;
++#endif
++#ifndef OPENSSL_NO_EC
++    dest->ec_meth = src->ec_meth;
++#endif
++    dest->rand_meth = src->rand_meth;
++    dest->ciphers = src->ciphers;
++    dest->digests = src->digests;
++    dest->pkey_meths = src->pkey_meths;
++    dest->destroy = src->destroy;
++    dest->init = src->init;
++    dest->finish = src->finish;
++    dest->ctrl = src->ctrl;
++    dest->load_privkey = src->load_privkey;
++    dest->load_pubkey = src->load_pubkey;
++    dest->cmd_defns = src->cmd_defns;
++    dest->flags = src->flags;
++}
++
++ENGINE *ENGINE_by_id(const char *id)
++{
++    ENGINE *iterator;
++    char *load_dir = NULL;
++    if (id == NULL) {
++        ENGINEerr(ENGINE_F_ENGINE_BY_ID, ERR_R_PASSED_NULL_PARAMETER);
++        return NULL;
++    }
++    if (!RUN_ONCE(&engine_lock_init, do_engine_lock_init)) {
++        ENGINEerr(ENGINE_F_ENGINE_BY_ID, ERR_R_MALLOC_FAILURE);
++        return NULL;
++    }
++
++    CRYPTO_THREAD_write_lock(global_engine_lock);
++    iterator = engine_list_head;
++    while (iterator && (strcmp(id, iterator->id) != 0))
++        iterator = iterator->next;
++    if (iterator != NULL) {
++        /*
++         * We need to return a structural reference. If this is an ENGINE
++         * type that returns copies, make a duplicate - otherwise increment
++         * the existing ENGINE's reference count.
++         */
++        if (iterator->flags & ENGINE_FLAGS_BY_ID_COPY) {
++            ENGINE *cp = ENGINE_new();
++            if (cp == NULL)
++                iterator = NULL;
++            else {
++                engine_cpy(cp, iterator);
++                iterator = cp;
++            }
++        } else {
++            iterator->struct_ref++;
++            engine_ref_debug(iterator, 0, 1);
++        }
++    }
++    CRYPTO_THREAD_unlock(global_engine_lock);
++    if (iterator != NULL)
++        return iterator;
++    /*
++     * Prevent infinite recursion if we're looking for the dynamic engine.
++     */
++    if (strcmp(id, "dynamic")) {
++        if ((load_dir = getenv("OPENSSL_ENGINES")) == 0)
++            load_dir = ENGINESDIR;
++        iterator = ENGINE_by_id("dynamic");
++        if (!iterator || !ENGINE_ctrl_cmd_string(iterator, "ID", id, 0) ||
++            !ENGINE_ctrl_cmd_string(iterator, "DIR_LOAD", "2", 0) ||
++            !ENGINE_ctrl_cmd_string(iterator, "DIR_ADD",
++                                    load_dir, 0) ||
++            !ENGINE_ctrl_cmd_string(iterator, "LIST_ADD", "1", 0) ||
++            !ENGINE_ctrl_cmd_string(iterator, "LOAD", NULL, 0))
++            goto notfound;
++        return iterator;
++    }
++ notfound:
++    ENGINE_free(iterator);
++    ENGINEerr(ENGINE_F_ENGINE_BY_ID, ENGINE_R_NO_SUCH_ENGINE);
++    ERR_add_error_data(2, "id=", id);
++    return NULL;
++    /* EEK! Experimental code ends */
++}
++
++int ENGINE_up_ref(ENGINE *e)
++{
++    int i;
++    if (e == NULL) {
++        ENGINEerr(ENGINE_F_ENGINE_UP_REF, ERR_R_PASSED_NULL_PARAMETER);
++        return 0;
++    }
++    CRYPTO_atomic_add(&e->struct_ref, 1, &i, global_engine_lock);
++    return 1;
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/engine/eng_openssl.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/engine/eng_openssl.c
+new file mode 100644
+index 0000000..9208f7e
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/engine/eng_openssl.c
+@@ -0,0 +1,652 @@
++/*
++ * Copyright 2001-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++/* ====================================================================
++ * Copyright 2002 Sun Microsystems, Inc. ALL RIGHTS RESERVED.
++ * ECDH support in OpenSSL originally developed by
++ * SUN MICROSYSTEMS, INC., and contributed to the OpenSSL project.
++ */
++
++#include 
++#include 
++#include "internal/cryptlib.h"
++#include 
++#include 
++#include 
++#include 
++#include 
++#include 
++#include 
++
++#include 
++#include 
++
++/*
++ * This testing gunk is implemented (and explained) lower down. It also
++ * assumes the application explicitly calls "ENGINE_load_openssl()" because
++ * this is no longer automatic in ENGINE_load_builtin_engines().
++ */
++#define TEST_ENG_OPENSSL_RC4
++#ifndef OPENSSL_NO_STDIO
++#define TEST_ENG_OPENSSL_PKEY
++#endif
++/* #define TEST_ENG_OPENSSL_HMAC */
++/* #define TEST_ENG_OPENSSL_HMAC_INIT */
++/* #define TEST_ENG_OPENSSL_RC4_OTHERS */
++#define TEST_ENG_OPENSSL_RC4_P_INIT
++/* #define TEST_ENG_OPENSSL_RC4_P_CIPHER */
++#define TEST_ENG_OPENSSL_SHA
++/* #define TEST_ENG_OPENSSL_SHA_OTHERS */
++/* #define TEST_ENG_OPENSSL_SHA_P_INIT */
++/* #define TEST_ENG_OPENSSL_SHA_P_UPDATE */
++/* #define TEST_ENG_OPENSSL_SHA_P_FINAL */
++
++/* Now check what of those algorithms are actually enabled */
++#ifdef OPENSSL_NO_RC4
++# undef TEST_ENG_OPENSSL_RC4
++# undef TEST_ENG_OPENSSL_RC4_OTHERS
++# undef TEST_ENG_OPENSSL_RC4_P_INIT
++# undef TEST_ENG_OPENSSL_RC4_P_CIPHER
++#endif
++
++static int openssl_destroy(ENGINE *e);
++
++#ifdef TEST_ENG_OPENSSL_RC4
++static int openssl_ciphers(ENGINE *e, const EVP_CIPHER **cipher,
++                           const int **nids, int nid);
++#endif
++#ifdef TEST_ENG_OPENSSL_SHA
++static int openssl_digests(ENGINE *e, const EVP_MD **digest,
++                           const int **nids, int nid);
++#endif
++
++#ifdef TEST_ENG_OPENSSL_PKEY
++static EVP_PKEY *openssl_load_privkey(ENGINE *eng, const char *key_id,
++                                      UI_METHOD *ui_method,
++                                      void *callback_data);
++#endif
++
++#ifdef TEST_ENG_OPENSSL_HMAC
++static int ossl_register_hmac_meth(void);
++static int ossl_pkey_meths(ENGINE *e, EVP_PKEY_METHOD **pmeth,
++                           const int **nids, int nid);
++#endif
++
++/* The constants used when creating the ENGINE */
++static const char *engine_openssl_id = "openssl";
++static const char *engine_openssl_name = "Software engine support";
++
++/*
++ * This internal function is used by ENGINE_openssl() and possibly by the
++ * "dynamic" ENGINE support too
++ */
++static int bind_helper(ENGINE *e)
++{
++    if (!ENGINE_set_id(e, engine_openssl_id)
++        || !ENGINE_set_name(e, engine_openssl_name)
++        || !ENGINE_set_destroy_function(e, openssl_destroy)
++#ifndef TEST_ENG_OPENSSL_NO_ALGORITHMS
++# ifndef OPENSSL_NO_RSA
++        || !ENGINE_set_RSA(e, RSA_get_default_method())
++# endif
++# ifndef OPENSSL_NO_DSA
++        || !ENGINE_set_DSA(e, DSA_get_default_method())
++# endif
++# ifndef OPENSSL_NO_EC
++        || !ENGINE_set_EC(e, EC_KEY_OpenSSL())
++# endif
++# ifndef OPENSSL_NO_DH
++        || !ENGINE_set_DH(e, DH_get_default_method())
++# endif
++        || !ENGINE_set_RAND(e, RAND_OpenSSL())
++# ifdef TEST_ENG_OPENSSL_RC4
++        || !ENGINE_set_ciphers(e, openssl_ciphers)
++# endif
++# ifdef TEST_ENG_OPENSSL_SHA
++        || !ENGINE_set_digests(e, openssl_digests)
++# endif
++#endif
++#ifdef TEST_ENG_OPENSSL_PKEY
++        || !ENGINE_set_load_privkey_function(e, openssl_load_privkey)
++#endif
++#ifdef TEST_ENG_OPENSSL_HMAC
++        || !ossl_register_hmac_meth()
++        || !ENGINE_set_pkey_meths(e, ossl_pkey_meths)
++#endif
++        )
++        return 0;
++    /*
++     * If we add errors to this ENGINE, ensure the error handling is setup
++     * here
++     */
++    /* openssl_load_error_strings(); */
++    return 1;
++}
++
++static ENGINE *engine_openssl(void)
++{
++    ENGINE *ret = ENGINE_new();
++    if (ret == NULL)
++        return NULL;
++    if (!bind_helper(ret)) {
++        ENGINE_free(ret);
++        return NULL;
++    }
++    return ret;
++}
++
++void engine_load_openssl_int(void)
++{
++    ENGINE *toadd = engine_openssl();
++    if (!toadd)
++        return;
++    ENGINE_add(toadd);
++    /*
++     * If the "add" worked, it gets a structural reference. So either way, we
++     * release our just-created reference.
++     */
++    ENGINE_free(toadd);
++    ERR_clear_error();
++}
++
++/*
++ * This stuff is needed if this ENGINE is being compiled into a
++ * self-contained shared-library.
++ */
++#ifdef ENGINE_DYNAMIC_SUPPORT
++static int bind_fn(ENGINE *e, const char *id)
++{
++    if (id && (strcmp(id, engine_openssl_id) != 0))
++        return 0;
++    if (!bind_helper(e))
++        return 0;
++    return 1;
++}
++
++IMPLEMENT_DYNAMIC_CHECK_FN()
++    IMPLEMENT_DYNAMIC_BIND_FN(bind_fn)
++#endif                          /* ENGINE_DYNAMIC_SUPPORT */
++#ifdef TEST_ENG_OPENSSL_RC4
++/*-
++ * This section of code compiles an "alternative implementation" of two modes of
++ * RC4 into this ENGINE. The result is that EVP_CIPHER operation for "rc4"
++ * should under normal circumstances go via this support rather than the default
++ * EVP support. There are other symbols to tweak the testing;
++ *    TEST_ENC_OPENSSL_RC4_OTHERS - print a one line message to stderr each time
++ *        we're asked for a cipher we don't support (should not happen).
++ *    TEST_ENG_OPENSSL_RC4_P_INIT - print a one line message to stderr each time
++ *        the "init_key" handler is called.
++ *    TEST_ENG_OPENSSL_RC4_P_CIPHER - ditto for the "cipher" handler.
++ */
++# include 
++# define TEST_RC4_KEY_SIZE               16
++typedef struct {
++    unsigned char key[TEST_RC4_KEY_SIZE];
++    RC4_KEY ks;
++} TEST_RC4_KEY;
++# define test(ctx) ((TEST_RC4_KEY *)EVP_CIPHER_CTX_get_cipher_data(ctx))
++static int test_rc4_init_key(EVP_CIPHER_CTX *ctx, const unsigned char *key,
++                             const unsigned char *iv, int enc)
++{
++# ifdef TEST_ENG_OPENSSL_RC4_P_INIT
++    fprintf(stderr, "(TEST_ENG_OPENSSL_RC4) test_init_key() called\n");
++# endif
++    memcpy(&test(ctx)->key[0], key, EVP_CIPHER_CTX_key_length(ctx));
++    RC4_set_key(&test(ctx)->ks, EVP_CIPHER_CTX_key_length(ctx),
++                test(ctx)->key);
++    return 1;
++}
++
++static int test_rc4_cipher(EVP_CIPHER_CTX *ctx, unsigned char *out,
++                           const unsigned char *in, size_t inl)
++{
++# ifdef TEST_ENG_OPENSSL_RC4_P_CIPHER
++    fprintf(stderr, "(TEST_ENG_OPENSSL_RC4) test_cipher() called\n");
++# endif
++    RC4(&test(ctx)->ks, inl, in, out);
++    return 1;
++}
++
++static EVP_CIPHER *r4_cipher = NULL;
++static const EVP_CIPHER *test_r4_cipher(void)
++{
++    if (r4_cipher == NULL) {
++        EVP_CIPHER *cipher;
++
++        if ((cipher = EVP_CIPHER_meth_new(NID_rc4, 1, TEST_RC4_KEY_SIZE)) == NULL
++            || !EVP_CIPHER_meth_set_iv_length(cipher, 0)
++            || !EVP_CIPHER_meth_set_flags(cipher, EVP_CIPH_VARIABLE_LENGTH)
++            || !EVP_CIPHER_meth_set_init(cipher, test_rc4_init_key)
++            || !EVP_CIPHER_meth_set_do_cipher(cipher, test_rc4_cipher)
++            || !EVP_CIPHER_meth_set_impl_ctx_size(cipher, sizeof(TEST_RC4_KEY))) {
++            EVP_CIPHER_meth_free(cipher);
++            cipher = NULL;
++        }
++        r4_cipher = cipher;
++    }
++    return r4_cipher;
++}
++static void test_r4_cipher_destroy(void)
++{
++    EVP_CIPHER_meth_free(r4_cipher);
++    r4_cipher = NULL;
++}
++
++static EVP_CIPHER *r4_40_cipher = NULL;
++static const EVP_CIPHER *test_r4_40_cipher(void)
++{
++    if (r4_40_cipher == NULL) {
++        EVP_CIPHER *cipher;
++
++        if ((cipher = EVP_CIPHER_meth_new(NID_rc4, 1, 5 /* 40 bits */)) == NULL
++            || !EVP_CIPHER_meth_set_iv_length(cipher, 0)
++            || !EVP_CIPHER_meth_set_flags(cipher, EVP_CIPH_VARIABLE_LENGTH)
++            || !EVP_CIPHER_meth_set_init(cipher, test_rc4_init_key)
++            || !EVP_CIPHER_meth_set_do_cipher(cipher, test_rc4_cipher)
++            || !EVP_CIPHER_meth_set_impl_ctx_size(cipher, sizeof(TEST_RC4_KEY))) {
++            EVP_CIPHER_meth_free(cipher);
++            cipher = NULL;
++        }
++        r4_40_cipher = cipher;
++    }
++    return r4_40_cipher;
++}
++static void test_r4_40_cipher_destroy(void)
++{
++    EVP_CIPHER_meth_free(r4_40_cipher);
++    r4_40_cipher = NULL;
++}
++static int test_cipher_nids(const int **nids)
++{
++    static int cipher_nids[4] = { 0, 0, 0, 0 };
++    static int pos = 0;
++    static int init = 0;
++
++    if (!init) {
++        const EVP_CIPHER *cipher;
++        if ((cipher = test_r4_cipher()) != NULL)
++            cipher_nids[pos++] = EVP_CIPHER_nid(cipher);
++        if ((cipher = test_r4_40_cipher()) != NULL)
++            cipher_nids[pos++] = EVP_CIPHER_nid(cipher);
++        cipher_nids[pos] = 0;
++        init = 1;
++    }
++    *nids = cipher_nids;
++    return pos;
++}
++
++static int openssl_ciphers(ENGINE *e, const EVP_CIPHER **cipher,
++                           const int **nids, int nid)
++{
++    if (!cipher) {
++        /* We are returning a list of supported nids */
++        return test_cipher_nids(nids);
++    }
++    /* We are being asked for a specific cipher */
++    if (nid == NID_rc4)
++        *cipher = test_r4_cipher();
++    else if (nid == NID_rc4_40)
++        *cipher = test_r4_40_cipher();
++    else {
++# ifdef TEST_ENG_OPENSSL_RC4_OTHERS
++        fprintf(stderr, "(TEST_ENG_OPENSSL_RC4) returning NULL for "
++                "nid %d\n", nid);
++# endif
++        *cipher = NULL;
++        return 0;
++    }
++    return 1;
++}
++#endif
++
++#ifdef TEST_ENG_OPENSSL_SHA
++/* Much the same sort of comment as for TEST_ENG_OPENSSL_RC4 */
++# include 
++
++static int test_sha1_init(EVP_MD_CTX *ctx)
++{
++# ifdef TEST_ENG_OPENSSL_SHA_P_INIT
++    fprintf(stderr, "(TEST_ENG_OPENSSL_SHA) test_sha1_init() called\n");
++# endif
++    return SHA1_Init(EVP_MD_CTX_md_data(ctx));
++}
++
++static int test_sha1_update(EVP_MD_CTX *ctx, const void *data, size_t count)
++{
++# ifdef TEST_ENG_OPENSSL_SHA_P_UPDATE
++    fprintf(stderr, "(TEST_ENG_OPENSSL_SHA) test_sha1_update() called\n");
++# endif
++    return SHA1_Update(EVP_MD_CTX_md_data(ctx), data, count);
++}
++
++static int test_sha1_final(EVP_MD_CTX *ctx, unsigned char *md)
++{
++# ifdef TEST_ENG_OPENSSL_SHA_P_FINAL
++    fprintf(stderr, "(TEST_ENG_OPENSSL_SHA) test_sha1_final() called\n");
++# endif
++    return SHA1_Final(md, EVP_MD_CTX_md_data(ctx));
++}
++
++static EVP_MD *sha1_md = NULL;
++static const EVP_MD *test_sha_md(void)
++{
++    if (sha1_md == NULL) {
++        EVP_MD *md;
++
++        if ((md = EVP_MD_meth_new(NID_sha1, NID_sha1WithRSAEncryption)) == NULL
++            || !EVP_MD_meth_set_result_size(md, SHA_DIGEST_LENGTH)
++            || !EVP_MD_meth_set_input_blocksize(md, SHA_CBLOCK)
++            || !EVP_MD_meth_set_app_datasize(md,
++                                             sizeof(EVP_MD *) + sizeof(SHA_CTX))
++            || !EVP_MD_meth_set_flags(md, 0)
++            || !EVP_MD_meth_set_init(md, test_sha1_init)
++            || !EVP_MD_meth_set_update(md, test_sha1_update)
++            || !EVP_MD_meth_set_final(md, test_sha1_final)) {
++            EVP_MD_meth_free(md);
++            md = NULL;
++        }
++        sha1_md = md;
++    }
++    return sha1_md;
++}
++static void test_sha_md_destroy(void)
++{
++    EVP_MD_meth_free(sha1_md);
++    sha1_md = NULL;
++}
++static int test_digest_nids(const int **nids)
++{
++    static int digest_nids[2] = { 0, 0 };
++    static int pos = 0;
++    static int init = 0;
++
++    if (!init) {
++        const EVP_MD *md;
++        if ((md = test_sha_md()) != NULL)
++            digest_nids[pos++] = EVP_MD_type(md);
++        digest_nids[pos] = 0;
++        init = 1;
++    }
++    *nids = digest_nids;
++    return pos;
++}
++
++static int openssl_digests(ENGINE *e, const EVP_MD **digest,
++                           const int **nids, int nid)
++{
++    if (!digest) {
++        /* We are returning a list of supported nids */
++        return test_digest_nids(nids);
++    }
++    /* We are being asked for a specific digest */
++    if (nid == NID_sha1)
++        *digest = test_sha_md();
++    else {
++# ifdef TEST_ENG_OPENSSL_SHA_OTHERS
++        fprintf(stderr, "(TEST_ENG_OPENSSL_SHA) returning NULL for "
++                "nid %d\n", nid);
++# endif
++        *digest = NULL;
++        return 0;
++    }
++    return 1;
++}
++#endif
++
++#ifdef TEST_ENG_OPENSSL_PKEY
++static EVP_PKEY *openssl_load_privkey(ENGINE *eng, const char *key_id,
++                                      UI_METHOD *ui_method,
++                                      void *callback_data)
++{
++    BIO *in;
++    EVP_PKEY *key;
++    fprintf(stderr, "(TEST_ENG_OPENSSL_PKEY)Loading Private key %s\n",
++            key_id);
++    in = BIO_new_file(key_id, "r");
++    if (!in)
++        return NULL;
++    key = PEM_read_bio_PrivateKey(in, NULL, 0, NULL);
++    BIO_free(in);
++    return key;
++}
++#endif
++
++#ifdef TEST_ENG_OPENSSL_HMAC
++
++/*
++ * Experimental HMAC redirection implementation: mainly copied from
++ * hm_pmeth.c
++ */
++
++/* HMAC pkey context structure */
++
++typedef struct {
++    const EVP_MD *md;           /* MD for HMAC use */
++    ASN1_OCTET_STRING ktmp;     /* Temp storage for key */
++    HMAC_CTX *ctx;
++} OSSL_HMAC_PKEY_CTX;
++
++static int ossl_hmac_init(EVP_PKEY_CTX *ctx)
++{
++    OSSL_HMAC_PKEY_CTX *hctx;
++
++    hctx = OPENSSL_zalloc(sizeof(*hctx));
++    if (hctx == NULL)
++        return 0;
++    hctx->ktmp.type = V_ASN1_OCTET_STRING;
++    hctx->ctx = HMAC_CTX_new();
++    if (hctx->ctx == NULL) {
++        OPENSSL_free(hctx);
++        return 0;
++    }
++    EVP_PKEY_CTX_set_data(ctx, hctx);
++    EVP_PKEY_CTX_set0_keygen_info(ctx, NULL, 0);
++# ifdef TEST_ENG_OPENSSL_HMAC_INIT
++    fprintf(stderr, "(TEST_ENG_OPENSSL_HMAC) ossl_hmac_init() called\n");
++# endif
++    return 1;
++}
++
++static void ossl_hmac_cleanup(EVP_PKEY_CTX *ctx);
++
++static int ossl_hmac_copy(EVP_PKEY_CTX *dst, EVP_PKEY_CTX *src)
++{
++    OSSL_HMAC_PKEY_CTX *sctx, *dctx;
++
++    /* allocate memory for dst->data and a new HMAC_CTX in dst->data->ctx */
++    if (!ossl_hmac_init(dst))
++        return 0;
++    sctx = EVP_PKEY_CTX_get_data(src);
++    dctx = EVP_PKEY_CTX_get_data(dst);
++    dctx->md = sctx->md;
++    if (!HMAC_CTX_copy(dctx->ctx, sctx->ctx))
++        goto err;
++    if (sctx->ktmp.data) {
++        if (!ASN1_OCTET_STRING_set(&dctx->ktmp,
++                                   sctx->ktmp.data, sctx->ktmp.length))
++            goto err;
++    }
++    return 1;
++err:
++    /* release HMAC_CTX in dst->data->ctx and memory allocated for dst->data */
++    ossl_hmac_cleanup(dst);
++    return 0;
++}
++
++static void ossl_hmac_cleanup(EVP_PKEY_CTX *ctx)
++{
++    OSSL_HMAC_PKEY_CTX *hctx = EVP_PKEY_CTX_get_data(ctx);
++
++    if (hctx) {
++        HMAC_CTX_free(hctx->ctx);
++        OPENSSL_clear_free(hctx->ktmp.data, hctx->ktmp.length);
++        OPENSSL_free(hctx);
++        EVP_PKEY_CTX_set_data(ctx, NULL);
++    }
++}
++
++static int ossl_hmac_keygen(EVP_PKEY_CTX *ctx, EVP_PKEY *pkey)
++{
++    ASN1_OCTET_STRING *hkey = NULL;
++    OSSL_HMAC_PKEY_CTX *hctx = EVP_PKEY_CTX_get_data(ctx);
++    if (!hctx->ktmp.data)
++        return 0;
++    hkey = ASN1_OCTET_STRING_dup(&hctx->ktmp);
++    if (!hkey)
++        return 0;
++    EVP_PKEY_assign(pkey, EVP_PKEY_HMAC, hkey);
++
++    return 1;
++}
++
++static int ossl_int_update(EVP_MD_CTX *ctx, const void *data, size_t count)
++{
++    OSSL_HMAC_PKEY_CTX *hctx = EVP_PKEY_CTX_get_data(EVP_MD_CTX_pkey_ctx(ctx));
++    if (!HMAC_Update(hctx->ctx, data, count))
++        return 0;
++    return 1;
++}
++
++static int ossl_hmac_signctx_init(EVP_PKEY_CTX *ctx, EVP_MD_CTX *mctx)
++{
++    EVP_MD_CTX_set_flags(mctx, EVP_MD_CTX_FLAG_NO_INIT);
++    EVP_MD_CTX_set_update_fn(mctx, ossl_int_update);
++    return 1;
++}
++
++static int ossl_hmac_signctx(EVP_PKEY_CTX *ctx, unsigned char *sig,
++                             size_t *siglen, EVP_MD_CTX *mctx)
++{
++    unsigned int hlen;
++    OSSL_HMAC_PKEY_CTX *hctx = EVP_PKEY_CTX_get_data(ctx);
++    int l = EVP_MD_CTX_size(mctx);
++
++    if (l < 0)
++        return 0;
++    *siglen = l;
++    if (!sig)
++        return 1;
++
++    if (!HMAC_Final(hctx->ctx, sig, &hlen))
++        return 0;
++    *siglen = (size_t)hlen;
++    return 1;
++}
++
++static int ossl_hmac_ctrl(EVP_PKEY_CTX *ctx, int type, int p1, void *p2)
++{
++    OSSL_HMAC_PKEY_CTX *hctx = EVP_PKEY_CTX_get_data(ctx);
++    EVP_PKEY *pk;
++    ASN1_OCTET_STRING *key;
++    switch (type) {
++
++    case EVP_PKEY_CTRL_SET_MAC_KEY:
++        if ((!p2 && p1 > 0) || (p1 < -1))
++            return 0;
++        if (!ASN1_OCTET_STRING_set(&hctx->ktmp, p2, p1))
++            return 0;
++        break;
++
++    case EVP_PKEY_CTRL_MD:
++        hctx->md = p2;
++        break;
++
++    case EVP_PKEY_CTRL_DIGESTINIT:
++        pk = EVP_PKEY_CTX_get0_pkey(ctx);
++        key = EVP_PKEY_get0(pk);
++        if (!HMAC_Init_ex(hctx->ctx, key->data, key->length, hctx->md, NULL))
++            return 0;
++        break;
++
++    default:
++        return -2;
++
++    }
++    return 1;
++}
++
++static int ossl_hmac_ctrl_str(EVP_PKEY_CTX *ctx,
++                              const char *type, const char *value)
++{
++    if (!value) {
++        return 0;
++    }
++    if (strcmp(type, "key") == 0) {
++        void *p = (void *)value;
++        return ossl_hmac_ctrl(ctx, EVP_PKEY_CTRL_SET_MAC_KEY, -1, p);
++    }
++    if (strcmp(type, "hexkey") == 0) {
++        unsigned char *key;
++        int r;
++        long keylen;
++        key = OPENSSL_hexstr2buf(value, &keylen);
++        if (!key)
++            return 0;
++        r = ossl_hmac_ctrl(ctx, EVP_PKEY_CTRL_SET_MAC_KEY, keylen, key);
++        OPENSSL_free(key);
++        return r;
++    }
++    return -2;
++}
++
++static EVP_PKEY_METHOD *ossl_hmac_meth;
++
++static int ossl_register_hmac_meth(void)
++{
++    EVP_PKEY_METHOD *meth;
++    meth = EVP_PKEY_meth_new(EVP_PKEY_HMAC, 0);
++    if (meth == NULL)
++        return 0;
++    EVP_PKEY_meth_set_init(meth, ossl_hmac_init);
++    EVP_PKEY_meth_set_copy(meth, ossl_hmac_copy);
++    EVP_PKEY_meth_set_cleanup(meth, ossl_hmac_cleanup);
++
++    EVP_PKEY_meth_set_keygen(meth, 0, ossl_hmac_keygen);
++
++    EVP_PKEY_meth_set_signctx(meth, ossl_hmac_signctx_init,
++                              ossl_hmac_signctx);
++
++    EVP_PKEY_meth_set_ctrl(meth, ossl_hmac_ctrl, ossl_hmac_ctrl_str);
++    ossl_hmac_meth = meth;
++    return 1;
++}
++
++static int ossl_pkey_meths(ENGINE *e, EVP_PKEY_METHOD **pmeth,
++                           const int **nids, int nid)
++{
++    static int ossl_pkey_nids[] = {
++        EVP_PKEY_HMAC,
++        0
++    };
++    if (!pmeth) {
++        *nids = ossl_pkey_nids;
++        return 1;
++    }
++
++    if (nid == EVP_PKEY_HMAC) {
++        *pmeth = ossl_hmac_meth;
++        return 1;
++    }
++
++    *pmeth = NULL;
++    return 0;
++}
++
++#endif
++
++int openssl_destroy(ENGINE *e)
++{
++    test_sha_md_destroy();
++#ifdef TEST_ENG_OPENSSL_RC4
++    test_r4_cipher_destroy();
++    test_r4_40_cipher_destroy();
++#endif
++    return 1;
++}
++
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/engine/eng_pkey.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/engine/eng_pkey.c
+new file mode 100644
+index 0000000..305a648
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/engine/eng_pkey.c
+@@ -0,0 +1,140 @@
++/*
++ * Copyright 2001-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include "eng_int.h"
++
++/* Basic get/set stuff */
++
++int ENGINE_set_load_privkey_function(ENGINE *e,
++                                     ENGINE_LOAD_KEY_PTR loadpriv_f)
++{
++    e->load_privkey = loadpriv_f;
++    return 1;
++}
++
++int ENGINE_set_load_pubkey_function(ENGINE *e, ENGINE_LOAD_KEY_PTR loadpub_f)
++{
++    e->load_pubkey = loadpub_f;
++    return 1;
++}
++
++int ENGINE_set_load_ssl_client_cert_function(ENGINE *e,
++                                             ENGINE_SSL_CLIENT_CERT_PTR
++                                             loadssl_f)
++{
++    e->load_ssl_client_cert = loadssl_f;
++    return 1;
++}
++
++ENGINE_LOAD_KEY_PTR ENGINE_get_load_privkey_function(const ENGINE *e)
++{
++    return e->load_privkey;
++}
++
++ENGINE_LOAD_KEY_PTR ENGINE_get_load_pubkey_function(const ENGINE *e)
++{
++    return e->load_pubkey;
++}
++
++ENGINE_SSL_CLIENT_CERT_PTR ENGINE_get_ssl_client_cert_function(const ENGINE
++                                                               *e)
++{
++    return e->load_ssl_client_cert;
++}
++
++/* API functions to load public/private keys */
++
++EVP_PKEY *ENGINE_load_private_key(ENGINE *e, const char *key_id,
++                                  UI_METHOD *ui_method, void *callback_data)
++{
++    EVP_PKEY *pkey;
++
++    if (e == NULL) {
++        ENGINEerr(ENGINE_F_ENGINE_LOAD_PRIVATE_KEY,
++                  ERR_R_PASSED_NULL_PARAMETER);
++        return 0;
++    }
++    CRYPTO_THREAD_write_lock(global_engine_lock);
++    if (e->funct_ref == 0) {
++        CRYPTO_THREAD_unlock(global_engine_lock);
++        ENGINEerr(ENGINE_F_ENGINE_LOAD_PRIVATE_KEY, ENGINE_R_NOT_INITIALISED);
++        return 0;
++    }
++    CRYPTO_THREAD_unlock(global_engine_lock);
++    if (!e->load_privkey) {
++        ENGINEerr(ENGINE_F_ENGINE_LOAD_PRIVATE_KEY,
++                  ENGINE_R_NO_LOAD_FUNCTION);
++        return 0;
++    }
++    pkey = e->load_privkey(e, key_id, ui_method, callback_data);
++    if (!pkey) {
++        ENGINEerr(ENGINE_F_ENGINE_LOAD_PRIVATE_KEY,
++                  ENGINE_R_FAILED_LOADING_PRIVATE_KEY);
++        return 0;
++    }
++    return pkey;
++}
++
++EVP_PKEY *ENGINE_load_public_key(ENGINE *e, const char *key_id,
++                                 UI_METHOD *ui_method, void *callback_data)
++{
++    EVP_PKEY *pkey;
++
++    if (e == NULL) {
++        ENGINEerr(ENGINE_F_ENGINE_LOAD_PUBLIC_KEY,
++                  ERR_R_PASSED_NULL_PARAMETER);
++        return 0;
++    }
++    CRYPTO_THREAD_write_lock(global_engine_lock);
++    if (e->funct_ref == 0) {
++        CRYPTO_THREAD_unlock(global_engine_lock);
++        ENGINEerr(ENGINE_F_ENGINE_LOAD_PUBLIC_KEY, ENGINE_R_NOT_INITIALISED);
++        return 0;
++    }
++    CRYPTO_THREAD_unlock(global_engine_lock);
++    if (!e->load_pubkey) {
++        ENGINEerr(ENGINE_F_ENGINE_LOAD_PUBLIC_KEY, ENGINE_R_NO_LOAD_FUNCTION);
++        return 0;
++    }
++    pkey = e->load_pubkey(e, key_id, ui_method, callback_data);
++    if (!pkey) {
++        ENGINEerr(ENGINE_F_ENGINE_LOAD_PUBLIC_KEY,
++                  ENGINE_R_FAILED_LOADING_PUBLIC_KEY);
++        return 0;
++    }
++    return pkey;
++}
++
++int ENGINE_load_ssl_client_cert(ENGINE *e, SSL *s,
++                                STACK_OF(X509_NAME) *ca_dn, X509 **pcert,
++                                EVP_PKEY **ppkey, STACK_OF(X509) **pother,
++                                UI_METHOD *ui_method, void *callback_data)
++{
++
++    if (e == NULL) {
++        ENGINEerr(ENGINE_F_ENGINE_LOAD_SSL_CLIENT_CERT,
++                  ERR_R_PASSED_NULL_PARAMETER);
++        return 0;
++    }
++    CRYPTO_THREAD_write_lock(global_engine_lock);
++    if (e->funct_ref == 0) {
++        CRYPTO_THREAD_unlock(global_engine_lock);
++        ENGINEerr(ENGINE_F_ENGINE_LOAD_SSL_CLIENT_CERT,
++                  ENGINE_R_NOT_INITIALISED);
++        return 0;
++    }
++    CRYPTO_THREAD_unlock(global_engine_lock);
++    if (!e->load_ssl_client_cert) {
++        ENGINEerr(ENGINE_F_ENGINE_LOAD_SSL_CLIENT_CERT,
++                  ENGINE_R_NO_LOAD_FUNCTION);
++        return 0;
++    }
++    return e->load_ssl_client_cert(e, s, ca_dn, pcert, ppkey, pother,
++                                   ui_method, callback_data);
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/engine/eng_rdrand.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/engine/eng_rdrand.c
+new file mode 100644
+index 0000000..b3defcb
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/engine/eng_rdrand.c
+@@ -0,0 +1,110 @@
++/*
++ * Copyright 2011-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++
++#include 
++#include 
++#include 
++#include 
++#include 
++#include 
++
++#if (defined(__i386)   || defined(__i386__)   || defined(_M_IX86) || \
++     defined(__x86_64) || defined(__x86_64__) || \
++     defined(_M_AMD64) || defined (_M_X64)) && defined(OPENSSL_CPUID_OBJ)
++
++size_t OPENSSL_ia32_rdrand(void);
++
++static int get_random_bytes(unsigned char *buf, int num)
++{
++    size_t rnd;
++
++    while (num >= (int)sizeof(size_t)) {
++        if ((rnd = OPENSSL_ia32_rdrand()) == 0)
++            return 0;
++
++        *((size_t *)buf) = rnd;
++        buf += sizeof(size_t);
++        num -= sizeof(size_t);
++    }
++    if (num) {
++        if ((rnd = OPENSSL_ia32_rdrand()) == 0)
++            return 0;
++
++        memcpy(buf, &rnd, num);
++    }
++
++    return 1;
++}
++
++static int random_status(void)
++{
++    return 1;
++}
++
++static RAND_METHOD rdrand_meth = {
++    NULL,                       /* seed */
++    get_random_bytes,
++    NULL,                       /* cleanup */
++    NULL,                       /* add */
++    get_random_bytes,
++    random_status,
++};
++
++static int rdrand_init(ENGINE *e)
++{
++    return 1;
++}
++
++static const char *engine_e_rdrand_id = "rdrand";
++static const char *engine_e_rdrand_name = "Intel RDRAND engine";
++
++static int bind_helper(ENGINE *e)
++{
++    if (!ENGINE_set_id(e, engine_e_rdrand_id) ||
++        !ENGINE_set_name(e, engine_e_rdrand_name) ||
++        !ENGINE_set_flags(e, ENGINE_FLAGS_NO_REGISTER_ALL) ||
++        !ENGINE_set_init_function(e, rdrand_init) ||
++        !ENGINE_set_RAND(e, &rdrand_meth))
++        return 0;
++
++    return 1;
++}
++
++static ENGINE *ENGINE_rdrand(void)
++{
++    ENGINE *ret = ENGINE_new();
++    if (ret == NULL)
++        return NULL;
++    if (!bind_helper(ret)) {
++        ENGINE_free(ret);
++        return NULL;
++    }
++    return ret;
++}
++
++void engine_load_rdrand_int(void)
++{
++    extern unsigned int OPENSSL_ia32cap_P[];
++
++    if (OPENSSL_ia32cap_P[1] & (1 << (62 - 32))) {
++        ENGINE *toadd = ENGINE_rdrand();
++        if (!toadd)
++            return;
++        ENGINE_add(toadd);
++        ENGINE_free(toadd);
++        ERR_clear_error();
++    }
++}
++#else
++void engine_load_rdrand_int(void)
++{
++}
++#endif
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/engine/eng_table.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/engine/eng_table.c
+new file mode 100644
+index 0000000..219253a
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/engine/eng_table.c
+@@ -0,0 +1,303 @@
++/*
++ * Copyright 2001-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include "internal/cryptlib.h"
++#include 
++#include 
++#include "eng_int.h"
++
++/* The type of the items in the table */
++struct st_engine_pile {
++    /* The 'nid' of this algorithm/mode */
++    int nid;
++    /* ENGINEs that implement this algorithm/mode. */
++    STACK_OF(ENGINE) *sk;
++    /* The default ENGINE to perform this algorithm/mode. */
++    ENGINE *funct;
++    /*
++     * Zero if 'sk' is newer than the cached 'funct', non-zero otherwise
++     */
++    int uptodate;
++};
++
++/* The type exposed in eng_int.h */
++struct st_engine_table {
++    LHASH_OF(ENGINE_PILE) piles;
++};                              /* ENGINE_TABLE */
++
++typedef struct st_engine_pile_doall {
++    engine_table_doall_cb *cb;
++    void *arg;
++} ENGINE_PILE_DOALL;
++
++/* Global flags (ENGINE_TABLE_FLAG_***). */
++static unsigned int table_flags = 0;
++
++/* API function manipulating 'table_flags' */
++unsigned int ENGINE_get_table_flags(void)
++{
++    return table_flags;
++}
++
++void ENGINE_set_table_flags(unsigned int flags)
++{
++    table_flags = flags;
++}
++
++/* Internal functions for the "piles" hash table */
++static unsigned long engine_pile_hash(const ENGINE_PILE *c)
++{
++    return c->nid;
++}
++
++static int engine_pile_cmp(const ENGINE_PILE *a, const ENGINE_PILE *b)
++{
++    return a->nid - b->nid;
++}
++
++static int int_table_check(ENGINE_TABLE **t, int create)
++{
++    LHASH_OF(ENGINE_PILE) *lh;
++
++    if (*t)
++        return 1;
++    if (!create)
++        return 0;
++    if ((lh = lh_ENGINE_PILE_new(engine_pile_hash, engine_pile_cmp)) == NULL)
++        return 0;
++    *t = (ENGINE_TABLE *)lh;
++    return 1;
++}
++
++/*
++ * Privately exposed (via eng_int.h) functions for adding and/or removing
++ * ENGINEs from the implementation table
++ */
++int engine_table_register(ENGINE_TABLE **table, ENGINE_CLEANUP_CB *cleanup,
++                          ENGINE *e, const int *nids, int num_nids,
++                          int setdefault)
++{
++    int ret = 0, added = 0;
++    ENGINE_PILE tmplate, *fnd;
++    CRYPTO_THREAD_write_lock(global_engine_lock);
++    if (!(*table))
++        added = 1;
++    if (!int_table_check(table, 1))
++        goto end;
++    if (added)
++        /* The cleanup callback needs to be added */
++        engine_cleanup_add_first(cleanup);
++    while (num_nids--) {
++        tmplate.nid = *nids;
++        fnd = lh_ENGINE_PILE_retrieve(&(*table)->piles, &tmplate);
++        if (!fnd) {
++            fnd = OPENSSL_malloc(sizeof(*fnd));
++            if (fnd == NULL)
++                goto end;
++            fnd->uptodate = 1;
++            fnd->nid = *nids;
++            fnd->sk = sk_ENGINE_new_null();
++            if (!fnd->sk) {
++                OPENSSL_free(fnd);
++                goto end;
++            }
++            fnd->funct = NULL;
++            (void)lh_ENGINE_PILE_insert(&(*table)->piles, fnd);
++        }
++        /* A registration shouldn't add duplicate entries */
++        (void)sk_ENGINE_delete_ptr(fnd->sk, e);
++        /*
++         * if 'setdefault', this ENGINE goes to the head of the list
++         */
++        if (!sk_ENGINE_push(fnd->sk, e))
++            goto end;
++        /* "touch" this ENGINE_PILE */
++        fnd->uptodate = 0;
++        if (setdefault) {
++            if (!engine_unlocked_init(e)) {
++                ENGINEerr(ENGINE_F_ENGINE_TABLE_REGISTER,
++                          ENGINE_R_INIT_FAILED);
++                goto end;
++            }
++            if (fnd->funct)
++                engine_unlocked_finish(fnd->funct, 0);
++            fnd->funct = e;
++            fnd->uptodate = 1;
++        }
++        nids++;
++    }
++    ret = 1;
++ end:
++    CRYPTO_THREAD_unlock(global_engine_lock);
++    return ret;
++}
++
++static void int_unregister_cb(ENGINE_PILE *pile, ENGINE *e)
++{
++    int n;
++    /* Iterate the 'c->sk' stack removing any occurrence of 'e' */
++    while ((n = sk_ENGINE_find(pile->sk, e)) >= 0) {
++        (void)sk_ENGINE_delete(pile->sk, n);
++        pile->uptodate = 0;
++    }
++    if (pile->funct == e) {
++        engine_unlocked_finish(e, 0);
++        pile->funct = NULL;
++    }
++}
++
++IMPLEMENT_LHASH_DOALL_ARG(ENGINE_PILE, ENGINE);
++
++void engine_table_unregister(ENGINE_TABLE **table, ENGINE *e)
++{
++    CRYPTO_THREAD_write_lock(global_engine_lock);
++    if (int_table_check(table, 0))
++        lh_ENGINE_PILE_doall_ENGINE(&(*table)->piles, int_unregister_cb, e);
++    CRYPTO_THREAD_unlock(global_engine_lock);
++}
++
++static void int_cleanup_cb_doall(ENGINE_PILE *p)
++{
++    if (!p)
++        return;
++    sk_ENGINE_free(p->sk);
++    if (p->funct)
++        engine_unlocked_finish(p->funct, 0);
++    OPENSSL_free(p);
++}
++
++void engine_table_cleanup(ENGINE_TABLE **table)
++{
++    CRYPTO_THREAD_write_lock(global_engine_lock);
++    if (*table) {
++        lh_ENGINE_PILE_doall(&(*table)->piles, int_cleanup_cb_doall);
++        lh_ENGINE_PILE_free(&(*table)->piles);
++        *table = NULL;
++    }
++    CRYPTO_THREAD_unlock(global_engine_lock);
++}
++
++/* return a functional reference for a given 'nid' */
++#ifndef ENGINE_TABLE_DEBUG
++ENGINE *engine_table_select(ENGINE_TABLE **table, int nid)
++#else
++ENGINE *engine_table_select_tmp(ENGINE_TABLE **table, int nid, const char *f,
++                                int l)
++#endif
++{
++    ENGINE *ret = NULL;
++    ENGINE_PILE tmplate, *fnd = NULL;
++    int initres, loop = 0;
++
++    if (!(*table)) {
++#ifdef ENGINE_TABLE_DEBUG
++        fprintf(stderr, "engine_table_dbg: %s:%d, nid=%d, nothing "
++                "registered!\n", f, l, nid);
++#endif
++        return NULL;
++    }
++    ERR_set_mark();
++    CRYPTO_THREAD_write_lock(global_engine_lock);
++    /*
++     * Check again inside the lock otherwise we could race against cleanup
++     * operations. But don't worry about a fprintf(stderr).
++     */
++    if (!int_table_check(table, 0))
++        goto end;
++    tmplate.nid = nid;
++    fnd = lh_ENGINE_PILE_retrieve(&(*table)->piles, &tmplate);
++    if (!fnd)
++        goto end;
++    if (fnd->funct && engine_unlocked_init(fnd->funct)) {
++#ifdef ENGINE_TABLE_DEBUG
++        fprintf(stderr, "engine_table_dbg: %s:%d, nid=%d, using "
++                "ENGINE '%s' cached\n", f, l, nid, fnd->funct->id);
++#endif
++        ret = fnd->funct;
++        goto end;
++    }
++    if (fnd->uptodate) {
++        ret = fnd->funct;
++        goto end;
++    }
++ trynext:
++    ret = sk_ENGINE_value(fnd->sk, loop++);
++    if (!ret) {
++#ifdef ENGINE_TABLE_DEBUG
++        fprintf(stderr, "engine_table_dbg: %s:%d, nid=%d, no "
++                "registered implementations would initialise\n", f, l, nid);
++#endif
++        goto end;
++    }
++    /* Try to initialise the ENGINE? */
++    if ((ret->funct_ref > 0) || !(table_flags & ENGINE_TABLE_FLAG_NOINIT))
++        initres = engine_unlocked_init(ret);
++    else
++        initres = 0;
++    if (initres) {
++        /* Update 'funct' */
++        if ((fnd->funct != ret) && engine_unlocked_init(ret)) {
++            /* If there was a previous default we release it. */
++            if (fnd->funct)
++                engine_unlocked_finish(fnd->funct, 0);
++            fnd->funct = ret;
++#ifdef ENGINE_TABLE_DEBUG
++            fprintf(stderr, "engine_table_dbg: %s:%d, nid=%d, "
++                    "setting default to '%s'\n", f, l, nid, ret->id);
++#endif
++        }
++#ifdef ENGINE_TABLE_DEBUG
++        fprintf(stderr, "engine_table_dbg: %s:%d, nid=%d, using "
++                "newly initialised '%s'\n", f, l, nid, ret->id);
++#endif
++        goto end;
++    }
++    goto trynext;
++ end:
++    /*
++     * If it failed, it is unlikely to succeed again until some future
++     * registrations have taken place. In all cases, we cache.
++     */
++    if (fnd)
++        fnd->uptodate = 1;
++#ifdef ENGINE_TABLE_DEBUG
++    if (ret)
++        fprintf(stderr, "engine_table_dbg: %s:%d, nid=%d, caching "
++                "ENGINE '%s'\n", f, l, nid, ret->id);
++    else
++        fprintf(stderr, "engine_table_dbg: %s:%d, nid=%d, caching "
++                "'no matching ENGINE'\n", f, l, nid);
++#endif
++    CRYPTO_THREAD_unlock(global_engine_lock);
++    /*
++     * Whatever happened, any failed init()s are not failures in this
++     * context, so clear our error state.
++     */
++    ERR_pop_to_mark();
++    return ret;
++}
++
++/* Table enumeration */
++
++static void int_dall(const ENGINE_PILE *pile, ENGINE_PILE_DOALL *dall)
++{
++    dall->cb(pile->nid, pile->sk, pile->funct, dall->arg);
++}
++
++IMPLEMENT_LHASH_DOALL_ARG_CONST(ENGINE_PILE, ENGINE_PILE_DOALL);
++
++void engine_table_doall(ENGINE_TABLE *table, engine_table_doall_cb *cb,
++                        void *arg)
++{
++    ENGINE_PILE_DOALL dall;
++    dall.cb = cb;
++    dall.arg = arg;
++    if (table)
++        lh_ENGINE_PILE_doall_ENGINE_PILE_DOALL(&table->piles, int_dall, &dall);
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/engine/tb_asnmth.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/engine/tb_asnmth.c
+new file mode 100644
+index 0000000..480267d
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/engine/tb_asnmth.c
+@@ -0,0 +1,207 @@
++/*
++ * Copyright 2006-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include "eng_int.h"
++#include 
++#include "internal/asn1_int.h"
++
++/*
++ * If this symbol is defined then ENGINE_get_pkey_asn1_meth_engine(), the
++ * function that is used by EVP to hook in pkey_asn1_meth code and cache
++ * defaults (etc), will display brief debugging summaries to stderr with the
++ * 'nid'.
++ */
++/* #define ENGINE_PKEY_ASN1_METH_DEBUG */
++
++static ENGINE_TABLE *pkey_asn1_meth_table = NULL;
++
++void ENGINE_unregister_pkey_asn1_meths(ENGINE *e)
++{
++    engine_table_unregister(&pkey_asn1_meth_table, e);
++}
++
++static void engine_unregister_all_pkey_asn1_meths(void)
++{
++    engine_table_cleanup(&pkey_asn1_meth_table);
++}
++
++int ENGINE_register_pkey_asn1_meths(ENGINE *e)
++{
++    if (e->pkey_asn1_meths) {
++        const int *nids;
++        int num_nids = e->pkey_asn1_meths(e, NULL, &nids, 0);
++        if (num_nids > 0)
++            return engine_table_register(&pkey_asn1_meth_table,
++                                         engine_unregister_all_pkey_asn1_meths,
++                                         e, nids, num_nids, 0);
++    }
++    return 1;
++}
++
++void ENGINE_register_all_pkey_asn1_meths(void)
++{
++    ENGINE *e;
++
++    for (e = ENGINE_get_first(); e; e = ENGINE_get_next(e))
++        ENGINE_register_pkey_asn1_meths(e);
++}
++
++int ENGINE_set_default_pkey_asn1_meths(ENGINE *e)
++{
++    if (e->pkey_asn1_meths) {
++        const int *nids;
++        int num_nids = e->pkey_asn1_meths(e, NULL, &nids, 0);
++        if (num_nids > 0)
++            return engine_table_register(&pkey_asn1_meth_table,
++                                         engine_unregister_all_pkey_asn1_meths,
++                                         e, nids, num_nids, 1);
++    }
++    return 1;
++}
++
++/*
++ * Exposed API function to get a functional reference from the implementation
++ * table (ie. try to get a functional reference from the tabled structural
++ * references) for a given pkey_asn1_meth 'nid'
++ */
++ENGINE *ENGINE_get_pkey_asn1_meth_engine(int nid)
++{
++    return engine_table_select(&pkey_asn1_meth_table, nid);
++}
++
++/*
++ * Obtains a pkey_asn1_meth implementation from an ENGINE functional
++ * reference
++ */
++const EVP_PKEY_ASN1_METHOD *ENGINE_get_pkey_asn1_meth(ENGINE *e, int nid)
++{
++    EVP_PKEY_ASN1_METHOD *ret;
++    ENGINE_PKEY_ASN1_METHS_PTR fn = ENGINE_get_pkey_asn1_meths(e);
++    if (!fn || !fn(e, &ret, NULL, nid)) {
++        ENGINEerr(ENGINE_F_ENGINE_GET_PKEY_ASN1_METH,
++                  ENGINE_R_UNIMPLEMENTED_PUBLIC_KEY_METHOD);
++        return NULL;
++    }
++    return ret;
++}
++
++/* Gets the pkey_asn1_meth callback from an ENGINE structure */
++ENGINE_PKEY_ASN1_METHS_PTR ENGINE_get_pkey_asn1_meths(const ENGINE *e)
++{
++    return e->pkey_asn1_meths;
++}
++
++/* Sets the pkey_asn1_meth callback in an ENGINE structure */
++int ENGINE_set_pkey_asn1_meths(ENGINE *e, ENGINE_PKEY_ASN1_METHS_PTR f)
++{
++    e->pkey_asn1_meths = f;
++    return 1;
++}
++
++/*
++ * Internal function to free up EVP_PKEY_ASN1_METHOD structures before an
++ * ENGINE is destroyed
++ */
++
++void engine_pkey_asn1_meths_free(ENGINE *e)
++{
++    int i;
++    EVP_PKEY_ASN1_METHOD *pkm;
++    if (e->pkey_asn1_meths) {
++        const int *pknids;
++        int npknids;
++        npknids = e->pkey_asn1_meths(e, NULL, &pknids, 0);
++        for (i = 0; i < npknids; i++) {
++            if (e->pkey_asn1_meths(e, &pkm, NULL, pknids[i])) {
++                EVP_PKEY_asn1_free(pkm);
++            }
++        }
++    }
++}
++
++/*
++ * Find a method based on a string. This does a linear search through all
++ * implemented algorithms. This is OK in practice because only a small number
++ * of algorithms are likely to be implemented in an engine and it is not used
++ * for speed critical operations.
++ */
++
++const EVP_PKEY_ASN1_METHOD *ENGINE_get_pkey_asn1_meth_str(ENGINE *e,
++                                                          const char *str,
++                                                          int len)
++{
++    int i, nidcount;
++    const int *nids;
++    EVP_PKEY_ASN1_METHOD *ameth;
++    if (!e->pkey_asn1_meths)
++        return NULL;
++    if (len == -1)
++        len = strlen(str);
++    nidcount = e->pkey_asn1_meths(e, NULL, &nids, 0);
++    for (i = 0; i < nidcount; i++) {
++        e->pkey_asn1_meths(e, &ameth, NULL, nids[i]);
++        if (((int)strlen(ameth->pem_str) == len)
++            && strncasecmp(ameth->pem_str, str, len) == 0)
++            return ameth;
++    }
++    return NULL;
++}
++
++typedef struct {
++    ENGINE *e;
++    const EVP_PKEY_ASN1_METHOD *ameth;
++    const char *str;
++    int len;
++} ENGINE_FIND_STR;
++
++static void look_str_cb(int nid, STACK_OF(ENGINE) *sk, ENGINE *def, void *arg)
++{
++    ENGINE_FIND_STR *lk = arg;
++    int i;
++    if (lk->ameth)
++        return;
++    for (i = 0; i < sk_ENGINE_num(sk); i++) {
++        ENGINE *e = sk_ENGINE_value(sk, i);
++        EVP_PKEY_ASN1_METHOD *ameth;
++        e->pkey_asn1_meths(e, &ameth, NULL, nid);
++        if (((int)strlen(ameth->pem_str) == lk->len)
++                && strncasecmp(ameth->pem_str, lk->str, lk->len) == 0) {
++            lk->e = e;
++            lk->ameth = ameth;
++            return;
++        }
++    }
++}
++
++const EVP_PKEY_ASN1_METHOD *ENGINE_pkey_asn1_find_str(ENGINE **pe,
++                                                      const char *str,
++                                                      int len)
++{
++    ENGINE_FIND_STR fstr;
++    fstr.e = NULL;
++    fstr.ameth = NULL;
++    fstr.str = str;
++    fstr.len = len;
++
++    if (!RUN_ONCE(&engine_lock_init, do_engine_lock_init)) {
++        ENGINEerr(ENGINE_F_ENGINE_PKEY_ASN1_FIND_STR, ERR_R_MALLOC_FAILURE);
++        return NULL;
++    }
++
++    CRYPTO_THREAD_write_lock(global_engine_lock);
++    engine_table_doall(pkey_asn1_meth_table, look_str_cb, &fstr);
++    /* If found obtain a structural reference to engine */
++    if (fstr.e) {
++        fstr.e->struct_ref++;
++        engine_ref_debug(fstr.e, 0, 1);
++    }
++    *pe = fstr.e;
++    CRYPTO_THREAD_unlock(global_engine_lock);
++    return fstr.ameth;
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/engine/tb_cipher.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/engine/tb_cipher.c
+new file mode 100644
+index 0000000..ac49141
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/engine/tb_cipher.c
+@@ -0,0 +1,91 @@
++/*
++ * Copyright 2001-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include "eng_int.h"
++
++static ENGINE_TABLE *cipher_table = NULL;
++
++void ENGINE_unregister_ciphers(ENGINE *e)
++{
++    engine_table_unregister(&cipher_table, e);
++}
++
++static void engine_unregister_all_ciphers(void)
++{
++    engine_table_cleanup(&cipher_table);
++}
++
++int ENGINE_register_ciphers(ENGINE *e)
++{
++    if (e->ciphers) {
++        const int *nids;
++        int num_nids = e->ciphers(e, NULL, &nids, 0);
++        if (num_nids > 0)
++            return engine_table_register(&cipher_table,
++                                         engine_unregister_all_ciphers, e,
++                                         nids, num_nids, 0);
++    }
++    return 1;
++}
++
++void ENGINE_register_all_ciphers()
++{
++    ENGINE *e;
++
++    for (e = ENGINE_get_first(); e; e = ENGINE_get_next(e))
++        ENGINE_register_ciphers(e);
++}
++
++int ENGINE_set_default_ciphers(ENGINE *e)
++{
++    if (e->ciphers) {
++        const int *nids;
++        int num_nids = e->ciphers(e, NULL, &nids, 0);
++        if (num_nids > 0)
++            return engine_table_register(&cipher_table,
++                                         engine_unregister_all_ciphers, e,
++                                         nids, num_nids, 1);
++    }
++    return 1;
++}
++
++/*
++ * Exposed API function to get a functional reference from the implementation
++ * table (ie. try to get a functional reference from the tabled structural
++ * references) for a given cipher 'nid'
++ */
++ENGINE *ENGINE_get_cipher_engine(int nid)
++{
++    return engine_table_select(&cipher_table, nid);
++}
++
++/* Obtains a cipher implementation from an ENGINE functional reference */
++const EVP_CIPHER *ENGINE_get_cipher(ENGINE *e, int nid)
++{
++    const EVP_CIPHER *ret;
++    ENGINE_CIPHERS_PTR fn = ENGINE_get_ciphers(e);
++    if (!fn || !fn(e, &ret, NULL, nid)) {
++        ENGINEerr(ENGINE_F_ENGINE_GET_CIPHER, ENGINE_R_UNIMPLEMENTED_CIPHER);
++        return NULL;
++    }
++    return ret;
++}
++
++/* Gets the cipher callback from an ENGINE structure */
++ENGINE_CIPHERS_PTR ENGINE_get_ciphers(const ENGINE *e)
++{
++    return e->ciphers;
++}
++
++/* Sets the cipher callback in an ENGINE structure */
++int ENGINE_set_ciphers(ENGINE *e, ENGINE_CIPHERS_PTR f)
++{
++    e->ciphers = f;
++    return 1;
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/engine/tb_dh.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/engine/tb_dh.c
+new file mode 100644
+index 0000000..c6440df
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/engine/tb_dh.c
+@@ -0,0 +1,72 @@
++/*
++ * Copyright 2001-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include "eng_int.h"
++
++static ENGINE_TABLE *dh_table = NULL;
++static const int dummy_nid = 1;
++
++void ENGINE_unregister_DH(ENGINE *e)
++{
++    engine_table_unregister(&dh_table, e);
++}
++
++static void engine_unregister_all_DH(void)
++{
++    engine_table_cleanup(&dh_table);
++}
++
++int ENGINE_register_DH(ENGINE *e)
++{
++    if (e->dh_meth)
++        return engine_table_register(&dh_table,
++                                     engine_unregister_all_DH, e, &dummy_nid,
++                                     1, 0);
++    return 1;
++}
++
++void ENGINE_register_all_DH()
++{
++    ENGINE *e;
++
++    for (e = ENGINE_get_first(); e; e = ENGINE_get_next(e))
++        ENGINE_register_DH(e);
++}
++
++int ENGINE_set_default_DH(ENGINE *e)
++{
++    if (e->dh_meth)
++        return engine_table_register(&dh_table,
++                                     engine_unregister_all_DH, e, &dummy_nid,
++                                     1, 1);
++    return 1;
++}
++
++/*
++ * Exposed API function to get a functional reference from the implementation
++ * table (ie. try to get a functional reference from the tabled structural
++ * references).
++ */
++ENGINE *ENGINE_get_default_DH(void)
++{
++    return engine_table_select(&dh_table, dummy_nid);
++}
++
++/* Obtains an DH implementation from an ENGINE functional reference */
++const DH_METHOD *ENGINE_get_DH(const ENGINE *e)
++{
++    return e->dh_meth;
++}
++
++/* Sets an DH implementation in an ENGINE structure */
++int ENGINE_set_DH(ENGINE *e, const DH_METHOD *dh_meth)
++{
++    e->dh_meth = dh_meth;
++    return 1;
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/engine/tb_digest.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/engine/tb_digest.c
+new file mode 100644
+index 0000000..194b9c7
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/engine/tb_digest.c
+@@ -0,0 +1,91 @@
++/*
++ * Copyright 2001-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include "eng_int.h"
++
++static ENGINE_TABLE *digest_table = NULL;
++
++void ENGINE_unregister_digests(ENGINE *e)
++{
++    engine_table_unregister(&digest_table, e);
++}
++
++static void engine_unregister_all_digests(void)
++{
++    engine_table_cleanup(&digest_table);
++}
++
++int ENGINE_register_digests(ENGINE *e)
++{
++    if (e->digests) {
++        const int *nids;
++        int num_nids = e->digests(e, NULL, &nids, 0);
++        if (num_nids > 0)
++            return engine_table_register(&digest_table,
++                                         engine_unregister_all_digests, e,
++                                         nids, num_nids, 0);
++    }
++    return 1;
++}
++
++void ENGINE_register_all_digests()
++{
++    ENGINE *e;
++
++    for (e = ENGINE_get_first(); e; e = ENGINE_get_next(e))
++        ENGINE_register_digests(e);
++}
++
++int ENGINE_set_default_digests(ENGINE *e)
++{
++    if (e->digests) {
++        const int *nids;
++        int num_nids = e->digests(e, NULL, &nids, 0);
++        if (num_nids > 0)
++            return engine_table_register(&digest_table,
++                                         engine_unregister_all_digests, e,
++                                         nids, num_nids, 1);
++    }
++    return 1;
++}
++
++/*
++ * Exposed API function to get a functional reference from the implementation
++ * table (ie. try to get a functional reference from the tabled structural
++ * references) for a given digest 'nid'
++ */
++ENGINE *ENGINE_get_digest_engine(int nid)
++{
++    return engine_table_select(&digest_table, nid);
++}
++
++/* Obtains a digest implementation from an ENGINE functional reference */
++const EVP_MD *ENGINE_get_digest(ENGINE *e, int nid)
++{
++    const EVP_MD *ret;
++    ENGINE_DIGESTS_PTR fn = ENGINE_get_digests(e);
++    if (!fn || !fn(e, &ret, NULL, nid)) {
++        ENGINEerr(ENGINE_F_ENGINE_GET_DIGEST, ENGINE_R_UNIMPLEMENTED_DIGEST);
++        return NULL;
++    }
++    return ret;
++}
++
++/* Gets the digest callback from an ENGINE structure */
++ENGINE_DIGESTS_PTR ENGINE_get_digests(const ENGINE *e)
++{
++    return e->digests;
++}
++
++/* Sets the digest callback in an ENGINE structure */
++int ENGINE_set_digests(ENGINE *e, ENGINE_DIGESTS_PTR f)
++{
++    e->digests = f;
++    return 1;
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/engine/tb_dsa.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/engine/tb_dsa.c
+new file mode 100644
+index 0000000..fdb80cd
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/engine/tb_dsa.c
+@@ -0,0 +1,72 @@
++/*
++ * Copyright 2001-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include "eng_int.h"
++
++static ENGINE_TABLE *dsa_table = NULL;
++static const int dummy_nid = 1;
++
++void ENGINE_unregister_DSA(ENGINE *e)
++{
++    engine_table_unregister(&dsa_table, e);
++}
++
++static void engine_unregister_all_DSA(void)
++{
++    engine_table_cleanup(&dsa_table);
++}
++
++int ENGINE_register_DSA(ENGINE *e)
++{
++    if (e->dsa_meth)
++        return engine_table_register(&dsa_table,
++                                     engine_unregister_all_DSA, e, &dummy_nid,
++                                     1, 0);
++    return 1;
++}
++
++void ENGINE_register_all_DSA()
++{
++    ENGINE *e;
++
++    for (e = ENGINE_get_first(); e; e = ENGINE_get_next(e))
++        ENGINE_register_DSA(e);
++}
++
++int ENGINE_set_default_DSA(ENGINE *e)
++{
++    if (e->dsa_meth)
++        return engine_table_register(&dsa_table,
++                                     engine_unregister_all_DSA, e, &dummy_nid,
++                                     1, 1);
++    return 1;
++}
++
++/*
++ * Exposed API function to get a functional reference from the implementation
++ * table (ie. try to get a functional reference from the tabled structural
++ * references).
++ */
++ENGINE *ENGINE_get_default_DSA(void)
++{
++    return engine_table_select(&dsa_table, dummy_nid);
++}
++
++/* Obtains an DSA implementation from an ENGINE functional reference */
++const DSA_METHOD *ENGINE_get_DSA(const ENGINE *e)
++{
++    return e->dsa_meth;
++}
++
++/* Sets an DSA implementation in an ENGINE structure */
++int ENGINE_set_DSA(ENGINE *e, const DSA_METHOD *dsa_meth)
++{
++    e->dsa_meth = dsa_meth;
++    return 1;
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/engine/tb_eckey.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/engine/tb_eckey.c
+new file mode 100644
+index 0000000..75750b2
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/engine/tb_eckey.c
+@@ -0,0 +1,72 @@
++/*
++ * Copyright 2015-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include "eng_int.h"
++
++static ENGINE_TABLE *dh_table = NULL;
++static const int dummy_nid = 1;
++
++void ENGINE_unregister_EC(ENGINE *e)
++{
++    engine_table_unregister(&dh_table, e);
++}
++
++static void engine_unregister_all_EC(void)
++{
++    engine_table_cleanup(&dh_table);
++}
++
++int ENGINE_register_EC(ENGINE *e)
++{
++    if (e->ec_meth != NULL)
++        return engine_table_register(&dh_table,
++                                     engine_unregister_all_EC, e, &dummy_nid,
++                                     1, 0);
++    return 1;
++}
++
++void ENGINE_register_all_EC()
++{
++    ENGINE *e;
++
++    for (e = ENGINE_get_first(); e; e = ENGINE_get_next(e))
++        ENGINE_register_EC(e);
++}
++
++int ENGINE_set_default_EC(ENGINE *e)
++{
++    if (e->ec_meth != NULL)
++        return engine_table_register(&dh_table,
++                                     engine_unregister_all_EC, e, &dummy_nid,
++                                     1, 1);
++    return 1;
++}
++
++/*
++ * Exposed API function to get a functional reference from the implementation
++ * table (ie. try to get a functional reference from the tabled structural
++ * references).
++ */
++ENGINE *ENGINE_get_default_EC(void)
++{
++    return engine_table_select(&dh_table, dummy_nid);
++}
++
++/* Obtains an EC_KEY implementation from an ENGINE functional reference */
++const EC_KEY_METHOD *ENGINE_get_EC(const ENGINE *e)
++{
++    return e->ec_meth;
++}
++
++/* Sets an EC_KEY implementation in an ENGINE structure */
++int ENGINE_set_EC(ENGINE *e, const EC_KEY_METHOD *ec_meth)
++{
++    e->ec_meth = ec_meth;
++    return 1;
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/engine/tb_pkmeth.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/engine/tb_pkmeth.c
+new file mode 100644
+index 0000000..2e82d85
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/engine/tb_pkmeth.c
+@@ -0,0 +1,114 @@
++/*
++ * Copyright 2006-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include "eng_int.h"
++#include 
++
++static ENGINE_TABLE *pkey_meth_table = NULL;
++
++void ENGINE_unregister_pkey_meths(ENGINE *e)
++{
++    engine_table_unregister(&pkey_meth_table, e);
++}
++
++static void engine_unregister_all_pkey_meths(void)
++{
++    engine_table_cleanup(&pkey_meth_table);
++}
++
++int ENGINE_register_pkey_meths(ENGINE *e)
++{
++    if (e->pkey_meths) {
++        const int *nids;
++        int num_nids = e->pkey_meths(e, NULL, &nids, 0);
++        if (num_nids > 0)
++            return engine_table_register(&pkey_meth_table,
++                                         engine_unregister_all_pkey_meths, e,
++                                         nids, num_nids, 0);
++    }
++    return 1;
++}
++
++void ENGINE_register_all_pkey_meths()
++{
++    ENGINE *e;
++
++    for (e = ENGINE_get_first(); e; e = ENGINE_get_next(e))
++        ENGINE_register_pkey_meths(e);
++}
++
++int ENGINE_set_default_pkey_meths(ENGINE *e)
++{
++    if (e->pkey_meths) {
++        const int *nids;
++        int num_nids = e->pkey_meths(e, NULL, &nids, 0);
++        if (num_nids > 0)
++            return engine_table_register(&pkey_meth_table,
++                                         engine_unregister_all_pkey_meths, e,
++                                         nids, num_nids, 1);
++    }
++    return 1;
++}
++
++/*
++ * Exposed API function to get a functional reference from the implementation
++ * table (ie. try to get a functional reference from the tabled structural
++ * references) for a given pkey_meth 'nid'
++ */
++ENGINE *ENGINE_get_pkey_meth_engine(int nid)
++{
++    return engine_table_select(&pkey_meth_table, nid);
++}
++
++/* Obtains a pkey_meth implementation from an ENGINE functional reference */
++const EVP_PKEY_METHOD *ENGINE_get_pkey_meth(ENGINE *e, int nid)
++{
++    EVP_PKEY_METHOD *ret;
++    ENGINE_PKEY_METHS_PTR fn = ENGINE_get_pkey_meths(e);
++    if (!fn || !fn(e, &ret, NULL, nid)) {
++        ENGINEerr(ENGINE_F_ENGINE_GET_PKEY_METH,
++                  ENGINE_R_UNIMPLEMENTED_PUBLIC_KEY_METHOD);
++        return NULL;
++    }
++    return ret;
++}
++
++/* Gets the pkey_meth callback from an ENGINE structure */
++ENGINE_PKEY_METHS_PTR ENGINE_get_pkey_meths(const ENGINE *e)
++{
++    return e->pkey_meths;
++}
++
++/* Sets the pkey_meth callback in an ENGINE structure */
++int ENGINE_set_pkey_meths(ENGINE *e, ENGINE_PKEY_METHS_PTR f)
++{
++    e->pkey_meths = f;
++    return 1;
++}
++
++/*
++ * Internal function to free up EVP_PKEY_METHOD structures before an ENGINE
++ * is destroyed
++ */
++
++void engine_pkey_meths_free(ENGINE *e)
++{
++    int i;
++    EVP_PKEY_METHOD *pkm;
++    if (e->pkey_meths) {
++        const int *pknids;
++        int npknids;
++        npknids = e->pkey_meths(e, NULL, &pknids, 0);
++        for (i = 0; i < npknids; i++) {
++            if (e->pkey_meths(e, &pkm, NULL, pknids[i])) {
++                EVP_PKEY_meth_free(pkm);
++            }
++        }
++    }
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/engine/tb_rand.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/engine/tb_rand.c
+new file mode 100644
+index 0000000..225e7c8
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/engine/tb_rand.c
+@@ -0,0 +1,72 @@
++/*
++ * Copyright 2001-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include "eng_int.h"
++
++static ENGINE_TABLE *rand_table = NULL;
++static const int dummy_nid = 1;
++
++void ENGINE_unregister_RAND(ENGINE *e)
++{
++    engine_table_unregister(&rand_table, e);
++}
++
++static void engine_unregister_all_RAND(void)
++{
++    engine_table_cleanup(&rand_table);
++}
++
++int ENGINE_register_RAND(ENGINE *e)
++{
++    if (e->rand_meth)
++        return engine_table_register(&rand_table,
++                                     engine_unregister_all_RAND, e,
++                                     &dummy_nid, 1, 0);
++    return 1;
++}
++
++void ENGINE_register_all_RAND()
++{
++    ENGINE *e;
++
++    for (e = ENGINE_get_first(); e; e = ENGINE_get_next(e))
++        ENGINE_register_RAND(e);
++}
++
++int ENGINE_set_default_RAND(ENGINE *e)
++{
++    if (e->rand_meth)
++        return engine_table_register(&rand_table,
++                                     engine_unregister_all_RAND, e,
++                                     &dummy_nid, 1, 1);
++    return 1;
++}
++
++/*
++ * Exposed API function to get a functional reference from the implementation
++ * table (ie. try to get a functional reference from the tabled structural
++ * references).
++ */
++ENGINE *ENGINE_get_default_RAND(void)
++{
++    return engine_table_select(&rand_table, dummy_nid);
++}
++
++/* Obtains an RAND implementation from an ENGINE functional reference */
++const RAND_METHOD *ENGINE_get_RAND(const ENGINE *e)
++{
++    return e->rand_meth;
++}
++
++/* Sets an RAND implementation in an ENGINE structure */
++int ENGINE_set_RAND(ENGINE *e, const RAND_METHOD *rand_meth)
++{
++    e->rand_meth = rand_meth;
++    return 1;
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/engine/tb_rsa.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/engine/tb_rsa.c
+new file mode 100644
+index 0000000..e2cc680
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/engine/tb_rsa.c
+@@ -0,0 +1,72 @@
++/*
++ * Copyright 2001-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include "eng_int.h"
++
++static ENGINE_TABLE *rsa_table = NULL;
++static const int dummy_nid = 1;
++
++void ENGINE_unregister_RSA(ENGINE *e)
++{
++    engine_table_unregister(&rsa_table, e);
++}
++
++static void engine_unregister_all_RSA(void)
++{
++    engine_table_cleanup(&rsa_table);
++}
++
++int ENGINE_register_RSA(ENGINE *e)
++{
++    if (e->rsa_meth)
++        return engine_table_register(&rsa_table,
++                                     engine_unregister_all_RSA, e, &dummy_nid,
++                                     1, 0);
++    return 1;
++}
++
++void ENGINE_register_all_RSA()
++{
++    ENGINE *e;
++
++    for (e = ENGINE_get_first(); e; e = ENGINE_get_next(e))
++        ENGINE_register_RSA(e);
++}
++
++int ENGINE_set_default_RSA(ENGINE *e)
++{
++    if (e->rsa_meth)
++        return engine_table_register(&rsa_table,
++                                     engine_unregister_all_RSA, e, &dummy_nid,
++                                     1, 1);
++    return 1;
++}
++
++/*
++ * Exposed API function to get a functional reference from the implementation
++ * table (ie. try to get a functional reference from the tabled structural
++ * references).
++ */
++ENGINE *ENGINE_get_default_RSA(void)
++{
++    return engine_table_select(&rsa_table, dummy_nid);
++}
++
++/* Obtains an RSA implementation from an ENGINE functional reference */
++const RSA_METHOD *ENGINE_get_RSA(const ENGINE *e)
++{
++    return e->rsa_meth;
++}
++
++/* Sets an RSA implementation in an ENGINE structure */
++int ENGINE_set_RSA(ENGINE *e, const RSA_METHOD *rsa_meth)
++{
++    e->rsa_meth = rsa_meth;
++    return 1;
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/err/README b/CryptoPkg/Library/OpensslLib/openssl/crypto/err/README
+new file mode 100644
+index 0000000..6d2ce0c
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/err/README
+@@ -0,0 +1,44 @@
++Adding new libraries
++--------------------
++
++When adding a new sub-library to OpenSSL, assign it a library number
++ERR_LIB_XXX, define a macro XXXerr() (both in err.h), add its
++name to ERR_str_libraries[] (in crypto/err/err.c), and add
++ERR_load_XXX_strings() to the ERR_load_crypto_strings() function
++(in crypto/err/err_all.c). Finally, add an entry:
++
++    L      XXX     xxx.h   xxx_err.c
++
++to crypto/err/openssl.ec, and add xxx_err.c to the Makefile.
++Running make errors will then generate a file xxx_err.c, and
++add all error codes used in the library to xxx.h.
++
++Additionally the library include file must have a certain form.
++Typically it will initially look like this:
++
++    #ifndef HEADER_XXX_H
++    #define HEADER_XXX_H
++
++    #ifdef __cplusplus
++    extern "C" {
++    #endif
++
++    /* Include files */
++
++    #include 
++    #include 
++
++    /* Macros, structures and function prototypes */
++
++
++    /* BEGIN ERROR CODES */
++
++The BEGIN ERROR CODES sequence is used by the error code
++generation script as the point to place new error codes, any text
++after this point will be overwritten when make errors is run.
++The closing #endif etc will be automatically added by the script.
++
++The generated C error code file xxx_err.c will load the header
++files stdio.h, openssl/err.h and openssl/xxx.h so the
++header file must load any additional header files containing any
++definitions it uses.
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/err/build.info b/CryptoPkg/Library/OpensslLib/openssl/crypto/err/build.info
+new file mode 100644
+index 0000000..6163d95
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/err/build.info
+@@ -0,0 +1,3 @@
++LIBS=../../libcrypto
++SOURCE[../../libcrypto]=\
++        err.c err_all.c err_prn.c
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/err/err.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/err/err.c
+new file mode 100644
+index 0000000..44a293a
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/err/err.c
+@@ -0,0 +1,770 @@
++/*
++ * Copyright 1995-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include 
++#include 
++#include 
++#include 
++#include 
++#include 
++#include 
++#include 
++#include 
++#include 
++#include 
++
++static void err_load_strings(int lib, ERR_STRING_DATA *str);
++
++static void ERR_STATE_free(ERR_STATE *s);
++#ifndef OPENSSL_NO_ERR
++static ERR_STRING_DATA ERR_str_libraries[] = {
++    {ERR_PACK(ERR_LIB_NONE, 0, 0), "unknown library"},
++    {ERR_PACK(ERR_LIB_SYS, 0, 0), "system library"},
++    {ERR_PACK(ERR_LIB_BN, 0, 0), "bignum routines"},
++    {ERR_PACK(ERR_LIB_RSA, 0, 0), "rsa routines"},
++    {ERR_PACK(ERR_LIB_DH, 0, 0), "Diffie-Hellman routines"},
++    {ERR_PACK(ERR_LIB_EVP, 0, 0), "digital envelope routines"},
++    {ERR_PACK(ERR_LIB_BUF, 0, 0), "memory buffer routines"},
++    {ERR_PACK(ERR_LIB_OBJ, 0, 0), "object identifier routines"},
++    {ERR_PACK(ERR_LIB_PEM, 0, 0), "PEM routines"},
++    {ERR_PACK(ERR_LIB_DSA, 0, 0), "dsa routines"},
++    {ERR_PACK(ERR_LIB_X509, 0, 0), "x509 certificate routines"},
++    {ERR_PACK(ERR_LIB_ASN1, 0, 0), "asn1 encoding routines"},
++    {ERR_PACK(ERR_LIB_CONF, 0, 0), "configuration file routines"},
++    {ERR_PACK(ERR_LIB_CRYPTO, 0, 0), "common libcrypto routines"},
++    {ERR_PACK(ERR_LIB_EC, 0, 0), "elliptic curve routines"},
++    {ERR_PACK(ERR_LIB_ECDSA, 0, 0), "ECDSA routines"},
++    {ERR_PACK(ERR_LIB_ECDH, 0, 0), "ECDH routines"},
++    {ERR_PACK(ERR_LIB_SSL, 0, 0), "SSL routines"},
++    {ERR_PACK(ERR_LIB_BIO, 0, 0), "BIO routines"},
++    {ERR_PACK(ERR_LIB_PKCS7, 0, 0), "PKCS7 routines"},
++    {ERR_PACK(ERR_LIB_X509V3, 0, 0), "X509 V3 routines"},
++    {ERR_PACK(ERR_LIB_PKCS12, 0, 0), "PKCS12 routines"},
++    {ERR_PACK(ERR_LIB_RAND, 0, 0), "random number generator"},
++    {ERR_PACK(ERR_LIB_DSO, 0, 0), "DSO support routines"},
++    {ERR_PACK(ERR_LIB_TS, 0, 0), "time stamp routines"},
++    {ERR_PACK(ERR_LIB_ENGINE, 0, 0), "engine routines"},
++    {ERR_PACK(ERR_LIB_OCSP, 0, 0), "OCSP routines"},
++    {ERR_PACK(ERR_LIB_UI, 0, 0), "UI routines"},
++    {ERR_PACK(ERR_LIB_FIPS, 0, 0), "FIPS routines"},
++    {ERR_PACK(ERR_LIB_CMS, 0, 0), "CMS routines"},
++    {ERR_PACK(ERR_LIB_HMAC, 0, 0), "HMAC routines"},
++    {ERR_PACK(ERR_LIB_CT, 0, 0), "CT routines"},
++    {ERR_PACK(ERR_LIB_ASYNC, 0, 0), "ASYNC routines"},
++    {ERR_PACK(ERR_LIB_KDF, 0, 0), "KDF routines"},
++    {0, NULL},
++};
++
++static ERR_STRING_DATA ERR_str_functs[] = {
++    {ERR_PACK(0, SYS_F_FOPEN, 0), "fopen"},
++    {ERR_PACK(0, SYS_F_CONNECT, 0), "connect"},
++    {ERR_PACK(0, SYS_F_GETSERVBYNAME, 0), "getservbyname"},
++    {ERR_PACK(0, SYS_F_SOCKET, 0), "socket"},
++    {ERR_PACK(0, SYS_F_IOCTLSOCKET, 0), "ioctlsocket"},
++    {ERR_PACK(0, SYS_F_BIND, 0), "bind"},
++    {ERR_PACK(0, SYS_F_LISTEN, 0), "listen"},
++    {ERR_PACK(0, SYS_F_ACCEPT, 0), "accept"},
++# ifdef OPENSSL_SYS_WINDOWS
++    {ERR_PACK(0, SYS_F_WSASTARTUP, 0), "WSAstartup"},
++# endif
++    {ERR_PACK(0, SYS_F_OPENDIR, 0), "opendir"},
++    {ERR_PACK(0, SYS_F_FREAD, 0), "fread"},
++    {ERR_PACK(0, SYS_F_GETADDRINFO, 0), "getaddrinfo"},
++    {ERR_PACK(0, SYS_F_GETNAMEINFO, 0), "getnameinfo"},
++    {ERR_PACK(0, SYS_F_SETSOCKOPT, 0), "setsockopt"},
++    {ERR_PACK(0, SYS_F_GETSOCKOPT, 0), "getsockopt"},
++    {ERR_PACK(0, SYS_F_GETSOCKNAME, 0), "getsockname"},
++    {ERR_PACK(0, SYS_F_GETHOSTBYNAME, 0), "gethostbyname"},
++    {0, NULL},
++};
++
++static ERR_STRING_DATA ERR_str_reasons[] = {
++    {ERR_R_SYS_LIB, "system lib"},
++    {ERR_R_BN_LIB, "BN lib"},
++    {ERR_R_RSA_LIB, "RSA lib"},
++    {ERR_R_DH_LIB, "DH lib"},
++    {ERR_R_EVP_LIB, "EVP lib"},
++    {ERR_R_BUF_LIB, "BUF lib"},
++    {ERR_R_OBJ_LIB, "OBJ lib"},
++    {ERR_R_PEM_LIB, "PEM lib"},
++    {ERR_R_DSA_LIB, "DSA lib"},
++    {ERR_R_X509_LIB, "X509 lib"},
++    {ERR_R_ASN1_LIB, "ASN1 lib"},
++    {ERR_R_EC_LIB, "EC lib"},
++    {ERR_R_BIO_LIB, "BIO lib"},
++    {ERR_R_PKCS7_LIB, "PKCS7 lib"},
++    {ERR_R_X509V3_LIB, "X509V3 lib"},
++    {ERR_R_ENGINE_LIB, "ENGINE lib"},
++    {ERR_R_ECDSA_LIB, "ECDSA lib"},
++
++    {ERR_R_NESTED_ASN1_ERROR, "nested asn1 error"},
++    {ERR_R_MISSING_ASN1_EOS, "missing asn1 eos"},
++
++    {ERR_R_FATAL, "fatal"},
++    {ERR_R_MALLOC_FAILURE, "malloc failure"},
++    {ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED,
++     "called a function you should not call"},
++    {ERR_R_PASSED_NULL_PARAMETER, "passed a null parameter"},
++    {ERR_R_INTERNAL_ERROR, "internal error"},
++    {ERR_R_DISABLED, "called a function that was disabled at compile-time"},
++    {ERR_R_INIT_FAIL, "init fail"},
++
++    {0, NULL},
++};
++#endif
++
++static CRYPTO_ONCE err_init = CRYPTO_ONCE_STATIC_INIT;
++static CRYPTO_THREAD_LOCAL err_thread_local;
++
++static CRYPTO_ONCE err_string_init = CRYPTO_ONCE_STATIC_INIT;
++static CRYPTO_RWLOCK *err_string_lock;
++
++static ERR_STRING_DATA *int_err_get_item(const ERR_STRING_DATA *);
++
++/*
++ * The internal state
++ */
++
++static LHASH_OF(ERR_STRING_DATA) *int_error_hash = NULL;
++static int int_err_library_number = ERR_LIB_USER;
++
++static unsigned long get_error_values(int inc, int top, const char **file,
++                                      int *line, const char **data,
++                                      int *flags);
++
++static unsigned long err_string_data_hash(const ERR_STRING_DATA *a)
++{
++    unsigned long ret, l;
++
++    l = a->error;
++    ret = l ^ ERR_GET_LIB(l) ^ ERR_GET_FUNC(l);
++    return (ret ^ ret % 19 * 13);
++}
++
++static int err_string_data_cmp(const ERR_STRING_DATA *a,
++                               const ERR_STRING_DATA *b)
++{
++    return (int)(a->error - b->error);
++}
++
++static ERR_STRING_DATA *int_err_get_item(const ERR_STRING_DATA *d)
++{
++    ERR_STRING_DATA *p = NULL;
++
++    CRYPTO_THREAD_read_lock(err_string_lock);
++    if (int_error_hash != NULL)
++        p = lh_ERR_STRING_DATA_retrieve(int_error_hash, d);
++    CRYPTO_THREAD_unlock(err_string_lock);
++
++    return p;
++}
++
++#ifndef OPENSSL_NO_ERR
++# define NUM_SYS_STR_REASONS 127
++# define LEN_SYS_STR_REASON 32
++
++static ERR_STRING_DATA SYS_str_reasons[NUM_SYS_STR_REASONS + 1];
++/*
++ * SYS_str_reasons is filled with copies of strerror() results at
++ * initialization. 'errno' values up to 127 should cover all usual errors,
++ * others will be displayed numerically by ERR_error_string. It is crucial
++ * that we have something for each reason code that occurs in
++ * ERR_str_reasons, or bogus reason strings will be returned for SYSerr(),
++ * which always gets an errno value and never one of those 'standard' reason
++ * codes.
++ */
++
++static void build_SYS_str_reasons(void)
++{
++    /* OPENSSL_malloc cannot be used here, use static storage instead */
++    static char strerror_tab[NUM_SYS_STR_REASONS][LEN_SYS_STR_REASON];
++    static int init = 1;
++    int i;
++
++    CRYPTO_THREAD_write_lock(err_string_lock);
++    if (!init) {
++        CRYPTO_THREAD_unlock(err_string_lock);
++        return;
++    }
++
++    for (i = 1; i <= NUM_SYS_STR_REASONS; i++) {
++        ERR_STRING_DATA *str = &SYS_str_reasons[i - 1];
++
++        str->error = (unsigned long)i;
++        if (str->string == NULL) {
++            char (*dest)[LEN_SYS_STR_REASON] = &(strerror_tab[i - 1]);
++            if (openssl_strerror_r(i, *dest, sizeof(*dest)))
++                str->string = *dest;
++        }
++        if (str->string == NULL)
++            str->string = "unknown";
++    }
++
++    /*
++     * Now we still have SYS_str_reasons[NUM_SYS_STR_REASONS] = {0, NULL}, as
++     * required by ERR_load_strings.
++     */
++
++    init = 0;
++
++    CRYPTO_THREAD_unlock(err_string_lock);
++}
++#endif
++
++#define err_clear_data(p,i) \
++        do { \
++        if ((p)->err_data_flags[i] & ERR_TXT_MALLOCED) \
++                {  \
++                OPENSSL_free((p)->err_data[i]); \
++                (p)->err_data[i]=NULL; \
++                } \
++        (p)->err_data_flags[i]=0; \
++        } while(0)
++
++#define err_clear(p,i) \
++        do { \
++        (p)->err_flags[i]=0; \
++        (p)->err_buffer[i]=0; \
++        err_clear_data(p,i); \
++        (p)->err_file[i]=NULL; \
++        (p)->err_line[i]= -1; \
++        } while(0)
++
++static void ERR_STATE_free(ERR_STATE *s)
++{
++    int i;
++
++    if (s == NULL)
++        return;
++
++    for (i = 0; i < ERR_NUM_ERRORS; i++) {
++        err_clear_data(s, i);
++    }
++    OPENSSL_free(s);
++}
++
++DEFINE_RUN_ONCE_STATIC(do_err_strings_init)
++{
++    OPENSSL_init_crypto(0, NULL);
++    err_string_lock = CRYPTO_THREAD_lock_new();
++    return err_string_lock != NULL;
++}
++
++void err_cleanup(void)
++{
++    CRYPTO_THREAD_lock_free(err_string_lock);
++    err_string_lock = NULL;
++}
++
++int ERR_load_ERR_strings(void)
++{
++#ifndef OPENSSL_NO_ERR
++    if (!RUN_ONCE(&err_string_init, do_err_strings_init))
++        return 0;
++
++    err_load_strings(0, ERR_str_libraries);
++    err_load_strings(0, ERR_str_reasons);
++    err_load_strings(ERR_LIB_SYS, ERR_str_functs);
++    build_SYS_str_reasons();
++    err_load_strings(ERR_LIB_SYS, SYS_str_reasons);
++#endif
++    return 1;
++}
++
++static void err_load_strings(int lib, ERR_STRING_DATA *str)
++{
++    CRYPTO_THREAD_write_lock(err_string_lock);
++    if (int_error_hash == NULL)
++        int_error_hash = lh_ERR_STRING_DATA_new(err_string_data_hash,
++                                                err_string_data_cmp);
++    if (int_error_hash != NULL) {
++        for (; str->error; str++) {
++            if (lib)
++                str->error |= ERR_PACK(lib, 0, 0);
++            (void)lh_ERR_STRING_DATA_insert(int_error_hash, str);
++        }
++    }
++    CRYPTO_THREAD_unlock(err_string_lock);
++}
++
++int ERR_load_strings(int lib, ERR_STRING_DATA *str)
++{
++    if (ERR_load_ERR_strings() == 0)
++        return 0;
++    err_load_strings(lib, str);
++    return 1;
++}
++
++int ERR_unload_strings(int lib, ERR_STRING_DATA *str)
++{
++    if (!RUN_ONCE(&err_string_init, do_err_strings_init))
++        return 0;
++
++    CRYPTO_THREAD_write_lock(err_string_lock);
++    if (int_error_hash != NULL) {
++        for (; str->error; str++) {
++            if (lib)
++                str->error |= ERR_PACK(lib, 0, 0);
++            (void)lh_ERR_STRING_DATA_delete(int_error_hash, str);
++        }
++    }
++    CRYPTO_THREAD_unlock(err_string_lock);
++
++    return 1;
++}
++
++void err_free_strings_int(void)
++{
++    if (!RUN_ONCE(&err_string_init, do_err_strings_init))
++        return;
++
++    CRYPTO_THREAD_write_lock(err_string_lock);
++    lh_ERR_STRING_DATA_free(int_error_hash);
++    int_error_hash = NULL;
++    CRYPTO_THREAD_unlock(err_string_lock);
++}
++
++/********************************************************/
++
++void ERR_put_error(int lib, int func, int reason, const char *file, int line)
++{
++    ERR_STATE *es;
++
++#ifdef _OSD_POSIX
++    /*
++     * In the BS2000-OSD POSIX subsystem, the compiler generates path names
++     * in the form "*POSIX(/etc/passwd)". This dirty hack strips them to
++     * something sensible. @@@ We shouldn't modify a const string, though.
++     */
++    if (strncmp(file, "*POSIX(", sizeof("*POSIX(") - 1) == 0) {
++        char *end;
++
++        /* Skip the "*POSIX(" prefix */
++        file += sizeof("*POSIX(") - 1;
++        end = &file[strlen(file) - 1];
++        if (*end == ')')
++            *end = '\0';
++        /* Optional: use the basename of the path only. */
++        if ((end = strrchr(file, '/')) != NULL)
++            file = &end[1];
++    }
++#endif
++    es = ERR_get_state();
++
++    es->top = (es->top + 1) % ERR_NUM_ERRORS;
++    if (es->top == es->bottom)
++        es->bottom = (es->bottom + 1) % ERR_NUM_ERRORS;
++    es->err_flags[es->top] = 0;
++    es->err_buffer[es->top] = ERR_PACK(lib, func, reason);
++    es->err_file[es->top] = file;
++    es->err_line[es->top] = line;
++    err_clear_data(es, es->top);
++}
++
++void ERR_clear_error(void)
++{
++    int i;
++    ERR_STATE *es;
++
++    es = ERR_get_state();
++
++    for (i = 0; i < ERR_NUM_ERRORS; i++) {
++        err_clear(es, i);
++    }
++    es->top = es->bottom = 0;
++}
++
++unsigned long ERR_get_error(void)
++{
++    return (get_error_values(1, 0, NULL, NULL, NULL, NULL));
++}
++
++unsigned long ERR_get_error_line(const char **file, int *line)
++{
++    return (get_error_values(1, 0, file, line, NULL, NULL));
++}
++
++unsigned long ERR_get_error_line_data(const char **file, int *line,
++                                      const char **data, int *flags)
++{
++    return (get_error_values(1, 0, file, line, data, flags));
++}
++
++unsigned long ERR_peek_error(void)
++{
++    return (get_error_values(0, 0, NULL, NULL, NULL, NULL));
++}
++
++unsigned long ERR_peek_error_line(const char **file, int *line)
++{
++    return (get_error_values(0, 0, file, line, NULL, NULL));
++}
++
++unsigned long ERR_peek_error_line_data(const char **file, int *line,
++                                       const char **data, int *flags)
++{
++    return (get_error_values(0, 0, file, line, data, flags));
++}
++
++unsigned long ERR_peek_last_error(void)
++{
++    return (get_error_values(0, 1, NULL, NULL, NULL, NULL));
++}
++
++unsigned long ERR_peek_last_error_line(const char **file, int *line)
++{
++    return (get_error_values(0, 1, file, line, NULL, NULL));
++}
++
++unsigned long ERR_peek_last_error_line_data(const char **file, int *line,
++                                            const char **data, int *flags)
++{
++    return (get_error_values(0, 1, file, line, data, flags));
++}
++
++static unsigned long get_error_values(int inc, int top, const char **file,
++                                      int *line, const char **data,
++                                      int *flags)
++{
++    int i = 0;
++    ERR_STATE *es;
++    unsigned long ret;
++
++    es = ERR_get_state();
++
++    if (inc && top) {
++        if (file)
++            *file = "";
++        if (line)
++            *line = 0;
++        if (data)
++            *data = "";
++        if (flags)
++            *flags = 0;
++
++        return ERR_R_INTERNAL_ERROR;
++    }
++
++    if (es->bottom == es->top)
++        return 0;
++    if (top)
++        i = es->top;            /* last error */
++    else
++        i = (es->bottom + 1) % ERR_NUM_ERRORS; /* first error */
++
++    ret = es->err_buffer[i];
++    if (inc) {
++        es->bottom = i;
++        es->err_buffer[i] = 0;
++    }
++
++    if ((file != NULL) && (line != NULL)) {
++        if (es->err_file[i] == NULL) {
++            *file = "NA";
++            if (line != NULL)
++                *line = 0;
++        } else {
++            *file = es->err_file[i];
++            if (line != NULL)
++                *line = es->err_line[i];
++        }
++    }
++
++    if (data == NULL) {
++        if (inc) {
++            err_clear_data(es, i);
++        }
++    } else {
++        if (es->err_data[i] == NULL) {
++            *data = "";
++            if (flags != NULL)
++                *flags = 0;
++        } else {
++            *data = es->err_data[i];
++            if (flags != NULL)
++                *flags = es->err_data_flags[i];
++        }
++    }
++    return ret;
++}
++
++void ERR_error_string_n(unsigned long e, char *buf, size_t len)
++{
++    char lsbuf[64], fsbuf[64], rsbuf[64];
++    const char *ls, *fs, *rs;
++    unsigned long l, f, r;
++
++    if (len == 0)
++        return;
++
++    l = ERR_GET_LIB(e);
++    f = ERR_GET_FUNC(e);
++    r = ERR_GET_REASON(e);
++
++    ls = ERR_lib_error_string(e);
++    fs = ERR_func_error_string(e);
++    rs = ERR_reason_error_string(e);
++
++    if (ls == NULL)
++        BIO_snprintf(lsbuf, sizeof(lsbuf), "lib(%lu)", l);
++    if (fs == NULL)
++        BIO_snprintf(fsbuf, sizeof(fsbuf), "func(%lu)", f);
++    if (rs == NULL)
++        BIO_snprintf(rsbuf, sizeof(rsbuf), "reason(%lu)", r);
++
++    BIO_snprintf(buf, len, "error:%08lX:%s:%s:%s", e, ls ? ls : lsbuf,
++                 fs ? fs : fsbuf, rs ? rs : rsbuf);
++    if (strlen(buf) == len - 1) {
++        /*
++         * output may be truncated; make sure we always have 5
++         * colon-separated fields, i.e. 4 colons ...
++         */
++#define NUM_COLONS 4
++        if (len > NUM_COLONS) { /* ... if possible */
++            int i;
++            char *s = buf;
++
++            for (i = 0; i < NUM_COLONS; i++) {
++                char *colon = strchr(s, ':');
++                if (colon == NULL || colon > &buf[len - 1] - NUM_COLONS + i) {
++                    /*
++                     * set colon no. i at last possible position (buf[len-1]
++                     * is the terminating 0)
++                     */
++                    colon = &buf[len - 1] - NUM_COLONS + i;
++                    *colon = ':';
++                }
++                s = colon + 1;
++            }
++        }
++    }
++}
++
++/*
++ * ERR_error_string_n should be used instead for ret != NULL as
++ * ERR_error_string cannot know how large the buffer is
++ */
++char *ERR_error_string(unsigned long e, char *ret)
++{
++    static char buf[256];
++
++    if (ret == NULL)
++        ret = buf;
++    ERR_error_string_n(e, ret, 256);
++
++    return ret;
++}
++
++const char *ERR_lib_error_string(unsigned long e)
++{
++    ERR_STRING_DATA d, *p;
++    unsigned long l;
++
++    if (!RUN_ONCE(&err_string_init, do_err_strings_init)) {
++        return NULL;
++    }
++
++    l = ERR_GET_LIB(e);
++    d.error = ERR_PACK(l, 0, 0);
++    p = int_err_get_item(&d);
++    return ((p == NULL) ? NULL : p->string);
++}
++
++const char *ERR_func_error_string(unsigned long e)
++{
++    ERR_STRING_DATA d, *p;
++    unsigned long l, f;
++
++    if (!RUN_ONCE(&err_string_init, do_err_strings_init)) {
++        return NULL;
++    }
++
++    l = ERR_GET_LIB(e);
++    f = ERR_GET_FUNC(e);
++    d.error = ERR_PACK(l, f, 0);
++    p = int_err_get_item(&d);
++    return ((p == NULL) ? NULL : p->string);
++}
++
++const char *ERR_reason_error_string(unsigned long e)
++{
++    ERR_STRING_DATA d, *p = NULL;
++    unsigned long l, r;
++
++    if (!RUN_ONCE(&err_string_init, do_err_strings_init)) {
++        return NULL;
++    }
++
++    l = ERR_GET_LIB(e);
++    r = ERR_GET_REASON(e);
++    d.error = ERR_PACK(l, 0, r);
++    p = int_err_get_item(&d);
++    if (!p) {
++        d.error = ERR_PACK(0, 0, r);
++        p = int_err_get_item(&d);
++    }
++    return ((p == NULL) ? NULL : p->string);
++}
++
++void err_delete_thread_state(void)
++{
++    ERR_STATE *state = ERR_get_state();
++    if (state == NULL)
++        return;
++
++    CRYPTO_THREAD_set_local(&err_thread_local, NULL);
++    ERR_STATE_free(state);
++}
++
++#if OPENSSL_API_COMPAT < 0x10100000L
++void ERR_remove_thread_state(void *dummy)
++{
++}
++#endif
++
++#if OPENSSL_API_COMPAT < 0x10000000L
++void ERR_remove_state(unsigned long pid)
++{
++}
++#endif
++
++DEFINE_RUN_ONCE_STATIC(err_do_init)
++{
++    return CRYPTO_THREAD_init_local(&err_thread_local, NULL);
++}
++
++ERR_STATE *ERR_get_state(void)
++{
++    ERR_STATE *state = NULL;
++
++    if (!RUN_ONCE(&err_init, err_do_init))
++        return NULL;
++
++    state = CRYPTO_THREAD_get_local(&err_thread_local);
++
++    if (state == NULL) {
++        state = OPENSSL_zalloc(sizeof(*state));
++        if (state == NULL)
++            return NULL;
++
++        if (!CRYPTO_THREAD_set_local(&err_thread_local, state)) {
++            ERR_STATE_free(state);
++            return NULL;
++        }
++
++        /* Ignore failures from these */
++        OPENSSL_init_crypto(OPENSSL_INIT_LOAD_CRYPTO_STRINGS, NULL);
++        ossl_init_thread_start(OPENSSL_INIT_THREAD_ERR_STATE);
++    }
++
++    return state;
++}
++
++int ERR_get_next_error_library(void)
++{
++    int ret;
++
++    if (!RUN_ONCE(&err_string_init, do_err_strings_init)) {
++        return 0;
++    }
++
++    CRYPTO_THREAD_write_lock(err_string_lock);
++    ret = int_err_library_number++;
++    CRYPTO_THREAD_unlock(err_string_lock);
++    return ret;
++}
++
++void ERR_set_error_data(char *data, int flags)
++{
++    ERR_STATE *es;
++    int i;
++
++    es = ERR_get_state();
++
++    i = es->top;
++    if (i == 0)
++        i = ERR_NUM_ERRORS - 1;
++
++    err_clear_data(es, i);
++    es->err_data[i] = data;
++    es->err_data_flags[i] = flags;
++}
++
++void ERR_add_error_data(int num, ...)
++{
++    va_list args;
++    va_start(args, num);
++    ERR_add_error_vdata(num, args);
++    va_end(args);
++}
++
++void ERR_add_error_vdata(int num, va_list args)
++{
++    int i, n, s;
++    char *str, *p, *a;
++
++    s = 80;
++    str = OPENSSL_malloc(s + 1);
++    if (str == NULL)
++        return;
++    str[0] = '\0';
++
++    n = 0;
++    for (i = 0; i < num; i++) {
++        a = va_arg(args, char *);
++        /* ignore NULLs, thanks to Bob Beck  */
++        if (a != NULL) {
++            n += strlen(a);
++            if (n > s) {
++                s = n + 20;
++                p = OPENSSL_realloc(str, s + 1);
++                if (p == NULL) {
++                    OPENSSL_free(str);
++                    return;
++                }
++                str = p;
++            }
++            OPENSSL_strlcat(str, a, (size_t)s + 1);
++        }
++    }
++    ERR_set_error_data(str, ERR_TXT_MALLOCED | ERR_TXT_STRING);
++}
++
++int ERR_set_mark(void)
++{
++    ERR_STATE *es;
++
++    es = ERR_get_state();
++
++    if (es->bottom == es->top)
++        return 0;
++    es->err_flags[es->top] |= ERR_FLAG_MARK;
++    return 1;
++}
++
++int ERR_pop_to_mark(void)
++{
++    ERR_STATE *es;
++
++    es = ERR_get_state();
++
++    while (es->bottom != es->top
++           && (es->err_flags[es->top] & ERR_FLAG_MARK) == 0) {
++        err_clear(es, es->top);
++        es->top -= 1;
++        if (es->top == -1)
++            es->top = ERR_NUM_ERRORS - 1;
++    }
++
++    if (es->bottom == es->top)
++        return 0;
++    es->err_flags[es->top] &= ~ERR_FLAG_MARK;
++    return 1;
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/err/err_all.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/err/err_all.c
+new file mode 100644
+index 0000000..3b1304f
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/err/err_all.c
+@@ -0,0 +1,109 @@
++/*
++ * Copyright 1995-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include "internal/err_int.h"
++#include 
++#include 
++#include 
++#include 
++#include 
++#include 
++#include 
++#include 
++#include 
++#include 
++#include 
++#include 
++#include 
++#include 
++#include 
++#include 
++#include 
++#include "internal/dso.h"
++#include 
++#include 
++#include 
++#include 
++#ifdef OPENSSL_FIPS
++# include 
++#endif
++#include 
++#include 
++#include 
++#include 
++#include 
++
++int err_load_crypto_strings_int(void)
++{
++    if (
++#ifdef OPENSSL_FIPS
++        FIPS_set_error_callbacks(ERR_put_error, ERR_add_error_vdata) == 0 ||
++#endif
++#ifndef OPENSSL_NO_ERR
++        ERR_load_ERR_strings() == 0 ||    /* include error strings for SYSerr */
++        ERR_load_BN_strings() == 0 ||
++# ifndef OPENSSL_NO_RSA
++        ERR_load_RSA_strings() == 0 ||
++# endif
++# ifndef OPENSSL_NO_DH
++        ERR_load_DH_strings() == 0 ||
++# endif
++        ERR_load_EVP_strings() == 0 ||
++        ERR_load_BUF_strings() == 0 ||
++        ERR_load_OBJ_strings() == 0 ||
++        ERR_load_PEM_strings() == 0 ||
++# ifndef OPENSSL_NO_DSA
++        ERR_load_DSA_strings() == 0 ||
++# endif
++        ERR_load_X509_strings() == 0 ||
++        ERR_load_ASN1_strings() == 0 ||
++        ERR_load_CONF_strings() == 0 ||
++        ERR_load_CRYPTO_strings() == 0 ||
++# ifndef OPENSSL_NO_COMP
++        ERR_load_COMP_strings() == 0 ||
++# endif
++# ifndef OPENSSL_NO_EC
++        ERR_load_EC_strings() == 0 ||
++# endif
++        /* skip ERR_load_SSL_strings() because it is not in this library */
++        ERR_load_BIO_strings() == 0 ||
++        ERR_load_PKCS7_strings() == 0 ||
++        ERR_load_X509V3_strings() == 0 ||
++        ERR_load_PKCS12_strings() == 0 ||
++        ERR_load_RAND_strings() == 0 ||
++        ERR_load_DSO_strings() == 0 ||
++# ifndef OPENSSL_NO_TS
++        ERR_load_TS_strings() == 0 ||
++# endif
++# ifndef OPENSSL_NO_ENGINE
++        ERR_load_ENGINE_strings() == 0 ||
++# endif
++# ifndef OPENSSL_NO_OCSP
++        ERR_load_OCSP_strings() == 0 ||
++# endif
++#ifndef OPENSSL_NO_UI
++        ERR_load_UI_strings() == 0 ||
++#endif
++# ifdef OPENSSL_FIPS
++        ERR_load_FIPS_strings() == 0 ||
++# endif
++# ifndef OPENSSL_NO_CMS
++        ERR_load_CMS_strings() == 0 ||
++# endif
++# ifndef OPENSSL_NO_CT
++        ERR_load_CT_strings() == 0 ||
++# endif
++        ERR_load_ASYNC_strings() == 0 ||
++#endif
++        ERR_load_KDF_strings() == 0)
++        return 0;
++
++    return 1;
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/err/err_prn.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/err/err_prn.c
+new file mode 100644
+index 0000000..c7dc1d1
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/err/err_prn.c
+@@ -0,0 +1,66 @@
++/*
++ * Copyright 1995-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include "internal/cryptlib.h"
++#include 
++#include 
++#include 
++#include 
++
++void ERR_print_errors_cb(int (*cb) (const char *str, size_t len, void *u),
++                         void *u)
++{
++    unsigned long l;
++    char buf[256];
++    char buf2[4096];
++    const char *file, *data;
++    int line, flags;
++    /*
++     * We don't know what kind of thing CRYPTO_THREAD_ID is. Here is our best
++     * attempt to convert it into something we can print.
++     */
++    union {
++        CRYPTO_THREAD_ID tid;
++        unsigned long ltid;
++    } tid;
++
++    tid.ltid = 0;
++    tid.tid = CRYPTO_THREAD_get_current_id();
++
++    while ((l = ERR_get_error_line_data(&file, &line, &data, &flags)) != 0) {
++        ERR_error_string_n(l, buf, sizeof buf);
++        BIO_snprintf(buf2, sizeof(buf2), "%lu:%s:%s:%d:%s\n", tid.ltid, buf,
++                     file, line, (flags & ERR_TXT_STRING) ? data : "");
++        if (cb(buf2, strlen(buf2), u) <= 0)
++            break;              /* abort outputting the error report */
++    }
++}
++
++static int print_bio(const char *str, size_t len, void *bp)
++{
++    return BIO_write((BIO *)bp, str, len);
++}
++
++void ERR_print_errors(BIO *bp)
++{
++    ERR_print_errors_cb(print_bio, bp);
++}
++
++#ifndef OPENSSL_NO_STDIO
++void ERR_print_errors_fp(FILE *fp)
++{
++    BIO *bio = BIO_new_fp(fp, BIO_NOCLOSE);
++    if (bio == NULL)
++        return;
++
++    ERR_print_errors_cb(print_bio, bio);
++    BIO_free(bio);
++}
++#endif
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/err/openssl.ec b/CryptoPkg/Library/OpensslLib/openssl/crypto/err/openssl.ec
+new file mode 100644
+index 0000000..f6f950e
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/err/openssl.ec
+@@ -0,0 +1,100 @@
++# crypto/err/openssl.ec
++
++# configuration file for util/mkerr.pl
++
++# files that may have to be rewritten by util/mkerr.pl
++L ERR		NONE				NONE
++L BN		include/openssl/bn.h		crypto/bn/bn_err.c
++L RSA		include/openssl/rsa.h		crypto/rsa/rsa_err.c
++L DH		include/openssl/dh.h		crypto/dh/dh_err.c
++L EVP		include/openssl/evp.h		crypto/evp/evp_err.c
++L BUF		include/openssl/buffer.h	crypto/buffer/buf_err.c
++L OBJ		include/openssl/objects.h	crypto/objects/obj_err.c
++L PEM		include/openssl/pem.h		crypto/pem/pem_err.c
++L DSA		include/openssl/dsa.h		crypto/dsa/dsa_err.c
++L X509		include/openssl/x509.h		crypto/x509/x509_err.c
++L ASN1		include/openssl/asn1.h		crypto/asn1/asn1_err.c
++L CONF		include/openssl/conf.h		crypto/conf/conf_err.c
++L CRYPTO	include/openssl/crypto.h	crypto/cpt_err.c
++L EC		include/openssl/ec.h		crypto/ec/ec_err.c
++L SSL		include/openssl/ssl.h		ssl/ssl_err.c
++L BIO		include/openssl/bio.h		crypto/bio/bio_err.c
++L PKCS7		include/openssl/pkcs7.h		crypto/pkcs7/pkcs7err.c
++L X509V3	include/openssl/x509v3.h	crypto/x509v3/v3err.c
++L PKCS12	include/openssl/pkcs12.h	crypto/pkcs12/pk12err.c
++L RAND		include/openssl/rand.h		crypto/rand/rand_err.c
++L DSO		include/internal/dso.h		crypto/dso/dso_err.c
++L ENGINE	include/openssl/engine.h	crypto/engine/eng_err.c
++L OCSP		include/openssl/ocsp.h		crypto/ocsp/ocsp_err.c
++L UI		include/openssl/ui.h		crypto/ui/ui_err.c
++L COMP		include/openssl/comp.h		crypto/comp/comp_err.c
++L TS		include/openssl/ts.h		crypto/ts/ts_err.c
++#L HMAC		include/openssl/hmac.h		crypto/hmac/hmac_err.c
++L CMS		include/openssl/cms.h		crypto/cms/cms_err.c
++#L FIPS		include/openssl/fips.h		crypto/fips_err.h
++L CT		include/openssl/ct.h		crypto/ct/ct_err.c
++L ASYNC		include/openssl/async.h		crypto/async/async_err.c
++L KDF		include/openssl/kdf.h		crypto/kdf/kdf_err.c
++
++# additional header files to be scanned for function names
++L NONE		crypto/x509/x509_vfy.h		NONE
++L NONE		crypto/ec/ec_lcl.h		NONE
++L NONE		crypto/asn1/asn_lcl.h		NONE
++L NONE		crypto/cms/cms_lcl.h		NONE
++L NONE		crypto/ct/ct_locl.h		NONE
++L NONE		fips/rand/fips_rand.h		NONE
++L NONE		ssl/ssl_locl.h			NONE
++
++F RSAREF_F_RSA_BN2BIN
++F RSAREF_F_RSA_PRIVATE_DECRYPT
++F RSAREF_F_RSA_PRIVATE_ENCRYPT
++F RSAREF_F_RSA_PUBLIC_DECRYPT
++F RSAREF_F_RSA_PUBLIC_ENCRYPT
++
++R SSL_R_SSLV3_ALERT_UNEXPECTED_MESSAGE         1010
++R SSL_R_SSLV3_ALERT_BAD_RECORD_MAC             1020
++R SSL_R_TLSV1_ALERT_DECRYPTION_FAILED          1021
++R SSL_R_TLSV1_ALERT_RECORD_OVERFLOW            1022
++R SSL_R_SSLV3_ALERT_DECOMPRESSION_FAILURE      1030
++R SSL_R_SSLV3_ALERT_HANDSHAKE_FAILURE          1040
++R SSL_R_SSLV3_ALERT_NO_CERTIFICATE             1041
++R SSL_R_SSLV3_ALERT_BAD_CERTIFICATE            1042
++R SSL_R_SSLV3_ALERT_UNSUPPORTED_CERTIFICATE    1043
++R SSL_R_SSLV3_ALERT_CERTIFICATE_REVOKED        1044
++R SSL_R_SSLV3_ALERT_CERTIFICATE_EXPIRED        1045
++R SSL_R_SSLV3_ALERT_CERTIFICATE_UNKNOWN        1046
++R SSL_R_SSLV3_ALERT_ILLEGAL_PARAMETER          1047
++R SSL_R_TLSV1_ALERT_UNKNOWN_CA                 1048
++R SSL_R_TLSV1_ALERT_ACCESS_DENIED              1049
++R SSL_R_TLSV1_ALERT_DECODE_ERROR               1050
++R SSL_R_TLSV1_ALERT_DECRYPT_ERROR              1051
++R SSL_R_TLSV1_ALERT_EXPORT_RESTRICTION         1060
++R SSL_R_TLSV1_ALERT_PROTOCOL_VERSION           1070
++R SSL_R_TLSV1_ALERT_INSUFFICIENT_SECURITY      1071
++R SSL_R_TLSV1_ALERT_INTERNAL_ERROR             1080
++R SSL_R_TLSV1_ALERT_INAPPROPRIATE_FALLBACK     1086
++R SSL_R_TLSV1_ALERT_USER_CANCELLED             1090
++R SSL_R_TLSV1_ALERT_NO_RENEGOTIATION           1100
++R SSL_R_TLSV1_UNSUPPORTED_EXTENSION            1110
++R SSL_R_TLSV1_CERTIFICATE_UNOBTAINABLE         1111
++R SSL_R_TLSV1_UNRECOGNIZED_NAME                1112
++R SSL_R_TLSV1_BAD_CERTIFICATE_STATUS_RESPONSE  1113
++R SSL_R_TLSV1_BAD_CERTIFICATE_HASH_VALUE       1114
++R TLS1_AD_UNKNOWN_PSK_IDENTITY                 1115
++R TLS1_AD_NO_APPLICATION_PROTOCOL              1120
++
++R RSAREF_R_CONTENT_ENCODING			0x0400
++R RSAREF_R_DATA					0x0401
++R RSAREF_R_DIGEST_ALGORITHM			0x0402
++R RSAREF_R_ENCODING				0x0403
++R RSAREF_R_KEY					0x0404
++R RSAREF_R_KEY_ENCODING				0x0405
++R RSAREF_R_LEN					0x0406
++R RSAREF_R_MODULUS_LEN				0x0407
++R RSAREF_R_NEED_RANDOM				0x0408
++R RSAREF_R_PRIVATE_KEY				0x0409
++R RSAREF_R_PUBLIC_KEY				0x040a
++R RSAREF_R_SIGNATURE				0x040b
++R RSAREF_R_SIGNATURE_ENCODING			0x040c
++R RSAREF_R_ENCRYPTION_ALGORITHM			0x040d
++
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/evp/bio_b64.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/evp/bio_b64.c
+new file mode 100644
+index 0000000..32a884a
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/evp/bio_b64.c
+@@ -0,0 +1,542 @@
++/*
++ * Copyright 1995-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include 
++#include "internal/cryptlib.h"
++#include 
++#include 
++#include "internal/bio.h"
++
++static int b64_write(BIO *h, const char *buf, int num);
++static int b64_read(BIO *h, char *buf, int size);
++static int b64_puts(BIO *h, const char *str);
++/*
++ * static int b64_gets(BIO *h, char *str, int size);
++ */
++static long b64_ctrl(BIO *h, int cmd, long arg1, void *arg2);
++static int b64_new(BIO *h);
++static int b64_free(BIO *data);
++static long b64_callback_ctrl(BIO *h, int cmd, bio_info_cb *fp);
++#define B64_BLOCK_SIZE  1024
++#define B64_BLOCK_SIZE2 768
++#define B64_NONE        0
++#define B64_ENCODE      1
++#define B64_DECODE      2
++
++typedef struct b64_struct {
++    /*
++     * BIO *bio; moved to the BIO structure
++     */
++    int buf_len;
++    int buf_off;
++    int tmp_len;                /* used to find the start when decoding */
++    int tmp_nl;                 /* If true, scan until '\n' */
++    int encode;
++    int start;                  /* have we started decoding yet? */
++    int cont;                   /* <= 0 when finished */
++    EVP_ENCODE_CTX *base64;
++    char buf[EVP_ENCODE_LENGTH(B64_BLOCK_SIZE) + 10];
++    char tmp[B64_BLOCK_SIZE];
++} BIO_B64_CTX;
++
++static const BIO_METHOD methods_b64 = {
++    BIO_TYPE_BASE64, "base64 encoding",
++    b64_write,
++    b64_read,
++    b64_puts,
++    NULL,                       /* b64_gets, */
++    b64_ctrl,
++    b64_new,
++    b64_free,
++    b64_callback_ctrl,
++};
++
++
++const BIO_METHOD *BIO_f_base64(void)
++{
++    return &methods_b64;
++}
++
++static int b64_new(BIO *bi)
++{
++    BIO_B64_CTX *ctx;
++
++    ctx = OPENSSL_zalloc(sizeof(*ctx));
++    if (ctx == NULL)
++        return 0;
++
++    ctx->cont = 1;
++    ctx->start = 1;
++    ctx->base64 = EVP_ENCODE_CTX_new();
++    if (ctx->base64 == NULL) {
++        OPENSSL_free(ctx);
++        return 0;
++    }
++
++    BIO_set_data(bi, ctx);
++    BIO_set_init(bi, 1);
++
++    return 1;
++}
++
++static int b64_free(BIO *a)
++{
++    BIO_B64_CTX *ctx;
++    if (a == NULL)
++        return 0;
++
++    ctx = BIO_get_data(a);
++    if (ctx == NULL)
++        return 0;
++
++    EVP_ENCODE_CTX_free(ctx->base64);
++    OPENSSL_free(ctx);
++    BIO_set_data(a, NULL);
++    BIO_set_init(a, 0);
++
++    return 1;
++}
++
++static int b64_read(BIO *b, char *out, int outl)
++{
++    int ret = 0, i, ii, j, k, x, n, num, ret_code = 0;
++    BIO_B64_CTX *ctx;
++    unsigned char *p, *q;
++    BIO *next;
++
++    if (out == NULL)
++        return (0);
++    ctx = (BIO_B64_CTX *)BIO_get_data(b);
++
++    next = BIO_next(b);
++    if ((ctx == NULL) || (next == NULL))
++        return 0;
++
++    BIO_clear_retry_flags(b);
++
++    if (ctx->encode != B64_DECODE) {
++        ctx->encode = B64_DECODE;
++        ctx->buf_len = 0;
++        ctx->buf_off = 0;
++        ctx->tmp_len = 0;
++        EVP_DecodeInit(ctx->base64);
++    }
++
++    /* First check if there are bytes decoded/encoded */
++    if (ctx->buf_len > 0) {
++        OPENSSL_assert(ctx->buf_len >= ctx->buf_off);
++        i = ctx->buf_len - ctx->buf_off;
++        if (i > outl)
++            i = outl;
++        OPENSSL_assert(ctx->buf_off + i < (int)sizeof(ctx->buf));
++        memcpy(out, &(ctx->buf[ctx->buf_off]), i);
++        ret = i;
++        out += i;
++        outl -= i;
++        ctx->buf_off += i;
++        if (ctx->buf_len == ctx->buf_off) {
++            ctx->buf_len = 0;
++            ctx->buf_off = 0;
++        }
++    }
++
++    /*
++     * At this point, we have room of outl bytes and an empty buffer, so we
++     * should read in some more.
++     */
++
++    ret_code = 0;
++    while (outl > 0) {
++        if (ctx->cont <= 0)
++            break;
++
++        i = BIO_read(next, &(ctx->tmp[ctx->tmp_len]),
++                     B64_BLOCK_SIZE - ctx->tmp_len);
++
++        if (i <= 0) {
++            ret_code = i;
++
++            /* Should we continue next time we are called? */
++            if (!BIO_should_retry(next)) {
++                ctx->cont = i;
++                /* If buffer empty break */
++                if (ctx->tmp_len == 0)
++                    break;
++                /* Fall through and process what we have */
++                else
++                    i = 0;
++            }
++            /* else we retry and add more data to buffer */
++            else
++                break;
++        }
++        i += ctx->tmp_len;
++        ctx->tmp_len = i;
++
++        /*
++         * We need to scan, a line at a time until we have a valid line if we
++         * are starting.
++         */
++        if (ctx->start && (BIO_get_flags(b) & BIO_FLAGS_BASE64_NO_NL)) {
++            /* ctx->start=1; */
++            ctx->tmp_len = 0;
++        } else if (ctx->start) {
++            q = p = (unsigned char *)ctx->tmp;
++            num = 0;
++            for (j = 0; j < i; j++) {
++                if (*(q++) != '\n')
++                    continue;
++
++                /*
++                 * due to a previous very long line, we need to keep on
++                 * scanning for a '\n' before we even start looking for
++                 * base64 encoded stuff.
++                 */
++                if (ctx->tmp_nl) {
++                    p = q;
++                    ctx->tmp_nl = 0;
++                    continue;
++                }
++
++                k = EVP_DecodeUpdate(ctx->base64,
++                                     (unsigned char *)ctx->buf,
++                                     &num, p, q - p);
++                if ((k <= 0) && (num == 0) && (ctx->start))
++                    EVP_DecodeInit(ctx->base64);
++                else {
++                    if (p != (unsigned char *)
++                        &(ctx->tmp[0])) {
++                        i -= (p - (unsigned char *)
++                              &(ctx->tmp[0]));
++                        for (x = 0; x < i; x++)
++                            ctx->tmp[x] = p[x];
++                    }
++                    EVP_DecodeInit(ctx->base64);
++                    ctx->start = 0;
++                    break;
++                }
++                p = q;
++            }
++
++            /* we fell off the end without starting */
++            if ((j == i) && (num == 0)) {
++                /*
++                 * Is this is one long chunk?, if so, keep on reading until a
++                 * new line.
++                 */
++                if (p == (unsigned char *)&(ctx->tmp[0])) {
++                    /* Check buffer full */
++                    if (i == B64_BLOCK_SIZE) {
++                        ctx->tmp_nl = 1;
++                        ctx->tmp_len = 0;
++                    }
++                } else if (p != q) { /* finished on a '\n' */
++                    n = q - p;
++                    for (ii = 0; ii < n; ii++)
++                        ctx->tmp[ii] = p[ii];
++                    ctx->tmp_len = n;
++                }
++                /* else finished on a '\n' */
++                continue;
++            } else {
++                ctx->tmp_len = 0;
++            }
++        } else if ((i < B64_BLOCK_SIZE) && (ctx->cont > 0)) {
++            /*
++             * If buffer isn't full and we can retry then restart to read in
++             * more data.
++             */
++            continue;
++        }
++
++        if (BIO_get_flags(b) & BIO_FLAGS_BASE64_NO_NL) {
++            int z, jj;
++
++            jj = i & ~3;        /* process per 4 */
++            z = EVP_DecodeBlock((unsigned char *)ctx->buf,
++                                (unsigned char *)ctx->tmp, jj);
++            if (jj > 2) {
++                if (ctx->tmp[jj - 1] == '=') {
++                    z--;
++                    if (ctx->tmp[jj - 2] == '=')
++                        z--;
++                }
++            }
++            /*
++             * z is now number of output bytes and jj is the number consumed
++             */
++            if (jj != i) {
++                memmove(ctx->tmp, &ctx->tmp[jj], i - jj);
++                ctx->tmp_len = i - jj;
++            }
++            ctx->buf_len = 0;
++            if (z > 0) {
++                ctx->buf_len = z;
++            }
++            i = z;
++        } else {
++            i = EVP_DecodeUpdate(ctx->base64,
++                                 (unsigned char *)ctx->buf, &ctx->buf_len,
++                                 (unsigned char *)ctx->tmp, i);
++            ctx->tmp_len = 0;
++        }
++        ctx->buf_off = 0;
++        if (i < 0) {
++            ret_code = 0;
++            ctx->buf_len = 0;
++            break;
++        }
++
++        if (ctx->buf_len <= outl)
++            i = ctx->buf_len;
++        else
++            i = outl;
++
++        memcpy(out, ctx->buf, i);
++        ret += i;
++        ctx->buf_off = i;
++        if (ctx->buf_off == ctx->buf_len) {
++            ctx->buf_len = 0;
++            ctx->buf_off = 0;
++        }
++        outl -= i;
++        out += i;
++    }
++    /* BIO_clear_retry_flags(b); */
++    BIO_copy_next_retry(b);
++    return ((ret == 0) ? ret_code : ret);
++}
++
++static int b64_write(BIO *b, const char *in, int inl)
++{
++    int ret = 0;
++    int n;
++    int i;
++    BIO_B64_CTX *ctx;
++    BIO *next;
++
++    ctx = (BIO_B64_CTX *)BIO_get_data(b);
++    next = BIO_next(b);
++    if ((ctx == NULL) || (next == NULL))
++        return 0;
++
++    BIO_clear_retry_flags(b);
++
++    if (ctx->encode != B64_ENCODE) {
++        ctx->encode = B64_ENCODE;
++        ctx->buf_len = 0;
++        ctx->buf_off = 0;
++        ctx->tmp_len = 0;
++        EVP_EncodeInit(ctx->base64);
++    }
++
++    OPENSSL_assert(ctx->buf_off < (int)sizeof(ctx->buf));
++    OPENSSL_assert(ctx->buf_len <= (int)sizeof(ctx->buf));
++    OPENSSL_assert(ctx->buf_len >= ctx->buf_off);
++    n = ctx->buf_len - ctx->buf_off;
++    while (n > 0) {
++        i = BIO_write(next, &(ctx->buf[ctx->buf_off]), n);
++        if (i <= 0) {
++            BIO_copy_next_retry(b);
++            return (i);
++        }
++        OPENSSL_assert(i <= n);
++        ctx->buf_off += i;
++        OPENSSL_assert(ctx->buf_off <= (int)sizeof(ctx->buf));
++        OPENSSL_assert(ctx->buf_len >= ctx->buf_off);
++        n -= i;
++    }
++    /* at this point all pending data has been written */
++    ctx->buf_off = 0;
++    ctx->buf_len = 0;
++
++    if ((in == NULL) || (inl <= 0))
++        return (0);
++
++    while (inl > 0) {
++        n = (inl > B64_BLOCK_SIZE) ? B64_BLOCK_SIZE : inl;
++
++        if (BIO_get_flags(b) & BIO_FLAGS_BASE64_NO_NL) {
++            if (ctx->tmp_len > 0) {
++                OPENSSL_assert(ctx->tmp_len <= 3);
++                n = 3 - ctx->tmp_len;
++                /*
++                 * There's a theoretical possibility for this
++                 */
++                if (n > inl)
++                    n = inl;
++                memcpy(&(ctx->tmp[ctx->tmp_len]), in, n);
++                ctx->tmp_len += n;
++                ret += n;
++                if (ctx->tmp_len < 3)
++                    break;
++                ctx->buf_len =
++                    EVP_EncodeBlock((unsigned char *)ctx->buf,
++                                    (unsigned char *)ctx->tmp, ctx->tmp_len);
++                OPENSSL_assert(ctx->buf_len <= (int)sizeof(ctx->buf));
++                OPENSSL_assert(ctx->buf_len >= ctx->buf_off);
++                /*
++                 * Since we're now done using the temporary buffer, the
++                 * length should be 0'd
++                 */
++                ctx->tmp_len = 0;
++            } else {
++                if (n < 3) {
++                    memcpy(ctx->tmp, in, n);
++                    ctx->tmp_len = n;
++                    ret += n;
++                    break;
++                }
++                n -= n % 3;
++                ctx->buf_len =
++                    EVP_EncodeBlock((unsigned char *)ctx->buf,
++                                    (const unsigned char *)in, n);
++                OPENSSL_assert(ctx->buf_len <= (int)sizeof(ctx->buf));
++                OPENSSL_assert(ctx->buf_len >= ctx->buf_off);
++                ret += n;
++            }
++        } else {
++            if (!EVP_EncodeUpdate(ctx->base64,
++                                 (unsigned char *)ctx->buf, &ctx->buf_len,
++                                 (unsigned char *)in, n))
++                return ((ret == 0) ? -1 : ret);
++            OPENSSL_assert(ctx->buf_len <= (int)sizeof(ctx->buf));
++            OPENSSL_assert(ctx->buf_len >= ctx->buf_off);
++            ret += n;
++        }
++        inl -= n;
++        in += n;
++
++        ctx->buf_off = 0;
++        n = ctx->buf_len;
++        while (n > 0) {
++            i = BIO_write(next, &(ctx->buf[ctx->buf_off]), n);
++            if (i <= 0) {
++                BIO_copy_next_retry(b);
++                return ((ret == 0) ? i : ret);
++            }
++            OPENSSL_assert(i <= n);
++            n -= i;
++            ctx->buf_off += i;
++            OPENSSL_assert(ctx->buf_off <= (int)sizeof(ctx->buf));
++            OPENSSL_assert(ctx->buf_len >= ctx->buf_off);
++        }
++        ctx->buf_len = 0;
++        ctx->buf_off = 0;
++    }
++    return (ret);
++}
++
++static long b64_ctrl(BIO *b, int cmd, long num, void *ptr)
++{
++    BIO_B64_CTX *ctx;
++    long ret = 1;
++    int i;
++    BIO *next;
++
++    ctx = (BIO_B64_CTX *)BIO_get_data(b);
++    next = BIO_next(b);
++    if ((ctx == NULL) || (next == NULL))
++        return 0;
++
++    switch (cmd) {
++    case BIO_CTRL_RESET:
++        ctx->cont = 1;
++        ctx->start = 1;
++        ctx->encode = B64_NONE;
++        ret = BIO_ctrl(next, cmd, num, ptr);
++        break;
++    case BIO_CTRL_EOF:         /* More to read */
++        if (ctx->cont <= 0)
++            ret = 1;
++        else
++            ret = BIO_ctrl(next, cmd, num, ptr);
++        break;
++    case BIO_CTRL_WPENDING:    /* More to write in buffer */
++        OPENSSL_assert(ctx->buf_len >= ctx->buf_off);
++        ret = ctx->buf_len - ctx->buf_off;
++        if ((ret == 0) && (ctx->encode != B64_NONE)
++            && (EVP_ENCODE_CTX_num(ctx->base64) != 0))
++            ret = 1;
++        else if (ret <= 0)
++            ret = BIO_ctrl(next, cmd, num, ptr);
++        break;
++    case BIO_CTRL_PENDING:     /* More to read in buffer */
++        OPENSSL_assert(ctx->buf_len >= ctx->buf_off);
++        ret = ctx->buf_len - ctx->buf_off;
++        if (ret <= 0)
++            ret = BIO_ctrl(next, cmd, num, ptr);
++        break;
++    case BIO_CTRL_FLUSH:
++        /* do a final write */
++ again:
++        while (ctx->buf_len != ctx->buf_off) {
++            i = b64_write(b, NULL, 0);
++            if (i < 0)
++                return i;
++        }
++        if (BIO_get_flags(b) & BIO_FLAGS_BASE64_NO_NL) {
++            if (ctx->tmp_len != 0) {
++                ctx->buf_len = EVP_EncodeBlock((unsigned char *)ctx->buf,
++                                               (unsigned char *)ctx->tmp,
++                                               ctx->tmp_len);
++                ctx->buf_off = 0;
++                ctx->tmp_len = 0;
++                goto again;
++            }
++        } else if (ctx->encode != B64_NONE
++                   && EVP_ENCODE_CTX_num(ctx->base64) != 0) {
++            ctx->buf_off = 0;
++            EVP_EncodeFinal(ctx->base64,
++                            (unsigned char *)ctx->buf, &(ctx->buf_len));
++            /* push out the bytes */
++            goto again;
++        }
++        /* Finally flush the underlying BIO */
++        ret = BIO_ctrl(next, cmd, num, ptr);
++        break;
++
++    case BIO_C_DO_STATE_MACHINE:
++        BIO_clear_retry_flags(b);
++        ret = BIO_ctrl(next, cmd, num, ptr);
++        BIO_copy_next_retry(b);
++        break;
++
++    case BIO_CTRL_DUP:
++        break;
++    case BIO_CTRL_INFO:
++    case BIO_CTRL_GET:
++    case BIO_CTRL_SET:
++    default:
++        ret = BIO_ctrl(next, cmd, num, ptr);
++        break;
++    }
++    return ret;
++}
++
++static long b64_callback_ctrl(BIO *b, int cmd, bio_info_cb *fp)
++{
++    long ret = 1;
++    BIO *next = BIO_next(b);
++
++    if (next == NULL)
++        return 0;
++    switch (cmd) {
++    default:
++        ret = BIO_callback_ctrl(next, cmd, fp);
++        break;
++    }
++    return (ret);
++}
++
++static int b64_puts(BIO *b, const char *str)
++{
++    return b64_write(b, str, strlen(str));
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/evp/bio_enc.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/evp/bio_enc.c
+new file mode 100644
+index 0000000..5a3beef
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/evp/bio_enc.c
+@@ -0,0 +1,449 @@
++/*
++ * Copyright 1995-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include 
++#include "internal/cryptlib.h"
++#include 
++#include 
++#include "internal/bio.h"
++
++static int enc_write(BIO *h, const char *buf, int num);
++static int enc_read(BIO *h, char *buf, int size);
++/*
++ * static int enc_puts(BIO *h, const char *str);
++ */
++/*
++ * static int enc_gets(BIO *h, char *str, int size);
++ */
++static long enc_ctrl(BIO *h, int cmd, long arg1, void *arg2);
++static int enc_new(BIO *h);
++static int enc_free(BIO *data);
++static long enc_callback_ctrl(BIO *h, int cmd, bio_info_cb *fps);
++#define ENC_BLOCK_SIZE  (1024*4)
++#define ENC_MIN_CHUNK   (256)
++#define BUF_OFFSET      (ENC_MIN_CHUNK + EVP_MAX_BLOCK_LENGTH)
++
++typedef struct enc_struct {
++    int buf_len;
++    int buf_off;
++    int cont;                   /* <= 0 when finished */
++    int finished;
++    int ok;                     /* bad decrypt */
++    EVP_CIPHER_CTX *cipher;
++    unsigned char *read_start, *read_end;
++    /*
++     * buf is larger than ENC_BLOCK_SIZE because EVP_DecryptUpdate can return
++     * up to a block more data than is presented to it
++     */
++    unsigned char buf[BUF_OFFSET + ENC_BLOCK_SIZE];
++} BIO_ENC_CTX;
++
++static const BIO_METHOD methods_enc = {
++    BIO_TYPE_CIPHER, "cipher",
++    enc_write,
++    enc_read,
++    NULL,                       /* enc_puts, */
++    NULL,                       /* enc_gets, */
++    enc_ctrl,
++    enc_new,
++    enc_free,
++    enc_callback_ctrl,
++};
++
++const BIO_METHOD *BIO_f_cipher(void)
++{
++    return (&methods_enc);
++}
++
++static int enc_new(BIO *bi)
++{
++    BIO_ENC_CTX *ctx;
++
++    ctx = OPENSSL_zalloc(sizeof(*ctx));
++    if (ctx == NULL)
++        return 0;
++
++    ctx->cipher = EVP_CIPHER_CTX_new();
++    if (ctx->cipher == NULL) {
++        OPENSSL_free(ctx);
++        return 0;
++    }
++    ctx->cont = 1;
++    ctx->ok = 1;
++    ctx->read_end = ctx->read_start = &(ctx->buf[BUF_OFFSET]);
++    BIO_set_data(bi, ctx);
++    BIO_set_init(bi, 1);
++
++    return 1;
++}
++
++static int enc_free(BIO *a)
++{
++    BIO_ENC_CTX *b;
++
++    if (a == NULL)
++        return 0;
++
++    b = BIO_get_data(a);
++    if (b == NULL)
++        return 0;
++
++    EVP_CIPHER_CTX_free(b->cipher);
++    OPENSSL_clear_free(b, sizeof(BIO_ENC_CTX));
++    BIO_set_data(a, NULL);
++    BIO_set_init(a, 0);
++
++    return 1;
++}
++
++static int enc_read(BIO *b, char *out, int outl)
++{
++    int ret = 0, i, blocksize;
++    BIO_ENC_CTX *ctx;
++    BIO *next;
++
++    if (out == NULL)
++        return (0);
++    ctx = BIO_get_data(b);
++
++    next = BIO_next(b);
++    if ((ctx == NULL) || (next == NULL))
++        return 0;
++
++    /* First check if there are bytes decoded/encoded */
++    if (ctx->buf_len > 0) {
++        i = ctx->buf_len - ctx->buf_off;
++        if (i > outl)
++            i = outl;
++        memcpy(out, &(ctx->buf[ctx->buf_off]), i);
++        ret = i;
++        out += i;
++        outl -= i;
++        ctx->buf_off += i;
++        if (ctx->buf_len == ctx->buf_off) {
++            ctx->buf_len = 0;
++            ctx->buf_off = 0;
++        }
++    }
++
++    blocksize = EVP_CIPHER_CTX_block_size(ctx->cipher);
++    if (blocksize == 1)
++        blocksize = 0;
++
++    /*
++     * At this point, we have room of outl bytes and an empty buffer, so we
++     * should read in some more.
++     */
++
++    while (outl > 0) {
++        if (ctx->cont <= 0)
++            break;
++
++        if (ctx->read_start == ctx->read_end) { /* time to read more data */
++            ctx->read_end = ctx->read_start = &(ctx->buf[BUF_OFFSET]);
++            i = BIO_read(next, ctx->read_start, ENC_BLOCK_SIZE);
++            if (i > 0)
++                ctx->read_end += i;
++        } else {
++            i = ctx->read_end - ctx->read_start;
++        }
++
++        if (i <= 0) {
++            /* Should be continue next time we are called? */
++            if (!BIO_should_retry(next)) {
++                ctx->cont = i;
++                i = EVP_CipherFinal_ex(ctx->cipher,
++                                       ctx->buf, &(ctx->buf_len));
++                ctx->ok = i;
++                ctx->buf_off = 0;
++            } else {
++                ret = (ret == 0) ? i : ret;
++                break;
++            }
++        } else {
++            if (outl > ENC_MIN_CHUNK) {
++                /*
++                 * Depending on flags block cipher decrypt can write
++                 * one extra block and then back off, i.e. output buffer
++                 * has to accommodate extra block...
++                 */
++                int j = outl - blocksize, buf_len;
++
++                if (!EVP_CipherUpdate(ctx->cipher,
++                                      (unsigned char *)out, &buf_len,
++                                      ctx->read_start, i > j ? j : i)) {
++                    BIO_clear_retry_flags(b);
++                    return 0;
++                }
++                ret += buf_len;
++                out += buf_len;
++                outl -= buf_len;
++
++                if ((i -= j) <= 0) {
++                    ctx->read_start = ctx->read_end;
++                    continue;
++                }
++                ctx->read_start += j;
++            }
++            if (i > ENC_MIN_CHUNK)
++                i = ENC_MIN_CHUNK;
++            if (!EVP_CipherUpdate(ctx->cipher,
++                                  ctx->buf, &ctx->buf_len,
++                                  ctx->read_start, i)) {
++                BIO_clear_retry_flags(b);
++                ctx->ok = 0;
++                return 0;
++            }
++            ctx->read_start += i;
++            ctx->cont = 1;
++            /*
++             * Note: it is possible for EVP_CipherUpdate to decrypt zero
++             * bytes because this is or looks like the final block: if this
++             * happens we should retry and either read more data or decrypt
++             * the final block
++             */
++            if (ctx->buf_len == 0)
++                continue;
++        }
++
++        if (ctx->buf_len <= outl)
++            i = ctx->buf_len;
++        else
++            i = outl;
++        if (i <= 0)
++            break;
++        memcpy(out, ctx->buf, i);
++        ret += i;
++        ctx->buf_off = i;
++        outl -= i;
++        out += i;
++    }
++
++    BIO_clear_retry_flags(b);
++    BIO_copy_next_retry(b);
++    return ((ret == 0) ? ctx->cont : ret);
++}
++
++static int enc_write(BIO *b, const char *in, int inl)
++{
++    int ret = 0, n, i;
++    BIO_ENC_CTX *ctx;
++    BIO *next;
++
++    ctx = BIO_get_data(b);
++    next = BIO_next(b);
++    if ((ctx == NULL) || (next == NULL))
++        return 0;
++
++    ret = inl;
++
++    BIO_clear_retry_flags(b);
++    n = ctx->buf_len - ctx->buf_off;
++    while (n > 0) {
++        i = BIO_write(next, &(ctx->buf[ctx->buf_off]), n);
++        if (i <= 0) {
++            BIO_copy_next_retry(b);
++            return (i);
++        }
++        ctx->buf_off += i;
++        n -= i;
++    }
++    /* at this point all pending data has been written */
++
++    if ((in == NULL) || (inl <= 0))
++        return (0);
++
++    ctx->buf_off = 0;
++    while (inl > 0) {
++        n = (inl > ENC_BLOCK_SIZE) ? ENC_BLOCK_SIZE : inl;
++        if (!EVP_CipherUpdate(ctx->cipher,
++                              ctx->buf, &ctx->buf_len,
++                              (const unsigned char *)in, n)) {
++            BIO_clear_retry_flags(b);
++            ctx->ok = 0;
++            return 0;
++        }
++        inl -= n;
++        in += n;
++
++        ctx->buf_off = 0;
++        n = ctx->buf_len;
++        while (n > 0) {
++            i = BIO_write(next, &(ctx->buf[ctx->buf_off]), n);
++            if (i <= 0) {
++                BIO_copy_next_retry(b);
++                return (ret == inl) ? i : ret - inl;
++            }
++            n -= i;
++            ctx->buf_off += i;
++        }
++        ctx->buf_len = 0;
++        ctx->buf_off = 0;
++    }
++    BIO_copy_next_retry(b);
++    return (ret);
++}
++
++static long enc_ctrl(BIO *b, int cmd, long num, void *ptr)
++{
++    BIO *dbio;
++    BIO_ENC_CTX *ctx, *dctx;
++    long ret = 1;
++    int i;
++    EVP_CIPHER_CTX **c_ctx;
++    BIO *next;
++
++    ctx = BIO_get_data(b);
++    next = BIO_next(b);
++    if (ctx == NULL)
++        return 0;
++
++    switch (cmd) {
++    case BIO_CTRL_RESET:
++        ctx->ok = 1;
++        ctx->finished = 0;
++        if (!EVP_CipherInit_ex(ctx->cipher, NULL, NULL, NULL, NULL,
++                               EVP_CIPHER_CTX_encrypting(ctx->cipher)))
++            return 0;
++        ret = BIO_ctrl(next, cmd, num, ptr);
++        break;
++    case BIO_CTRL_EOF:         /* More to read */
++        if (ctx->cont <= 0)
++            ret = 1;
++        else
++            ret = BIO_ctrl(next, cmd, num, ptr);
++        break;
++    case BIO_CTRL_WPENDING:
++        ret = ctx->buf_len - ctx->buf_off;
++        if (ret <= 0)
++            ret = BIO_ctrl(next, cmd, num, ptr);
++        break;
++    case BIO_CTRL_PENDING:     /* More to read in buffer */
++        ret = ctx->buf_len - ctx->buf_off;
++        if (ret <= 0)
++            ret = BIO_ctrl(next, cmd, num, ptr);
++        break;
++    case BIO_CTRL_FLUSH:
++        /* do a final write */
++ again:
++        while (ctx->buf_len != ctx->buf_off) {
++            i = enc_write(b, NULL, 0);
++            if (i < 0)
++                return i;
++        }
++
++        if (!ctx->finished) {
++            ctx->finished = 1;
++            ctx->buf_off = 0;
++            ret = EVP_CipherFinal_ex(ctx->cipher,
++                                     (unsigned char *)ctx->buf,
++                                     &(ctx->buf_len));
++            ctx->ok = (int)ret;
++            if (ret <= 0)
++                break;
++
++            /* push out the bytes */
++            goto again;
++        }
++
++        /* Finally flush the underlying BIO */
++        ret = BIO_ctrl(next, cmd, num, ptr);
++        break;
++    case BIO_C_GET_CIPHER_STATUS:
++        ret = (long)ctx->ok;
++        break;
++    case BIO_C_DO_STATE_MACHINE:
++        BIO_clear_retry_flags(b);
++        ret = BIO_ctrl(next, cmd, num, ptr);
++        BIO_copy_next_retry(b);
++        break;
++    case BIO_C_GET_CIPHER_CTX:
++        c_ctx = (EVP_CIPHER_CTX **)ptr;
++        *c_ctx = ctx->cipher;
++        BIO_set_init(b, 1);
++        break;
++    case BIO_CTRL_DUP:
++        dbio = (BIO *)ptr;
++        dctx = BIO_get_data(dbio);
++        dctx->cipher = EVP_CIPHER_CTX_new();
++        if (dctx->cipher == NULL)
++            return 0;
++        ret = EVP_CIPHER_CTX_copy(dctx->cipher, ctx->cipher);
++        if (ret)
++            BIO_set_init(dbio, 1);
++        break;
++    default:
++        ret = BIO_ctrl(next, cmd, num, ptr);
++        break;
++    }
++    return (ret);
++}
++
++static long enc_callback_ctrl(BIO *b, int cmd, bio_info_cb *fp)
++{
++    long ret = 1;
++    BIO *next = BIO_next(b);
++
++    if (next == NULL)
++        return (0);
++    switch (cmd) {
++    default:
++        ret = BIO_callback_ctrl(next, cmd, fp);
++        break;
++    }
++    return (ret);
++}
++
++/*-
++void BIO_set_cipher_ctx(b,c)
++BIO *b;
++EVP_CIPHER_ctx *c;
++        {
++        if (b == NULL) return;
++
++        if ((b->callback != NULL) &&
++                (b->callback(b,BIO_CB_CTRL,(char *)c,BIO_CTRL_SET,e,0L) <= 0))
++                return;
++
++        b->init=1;
++        ctx=(BIO_ENC_CTX *)b->ptr;
++        memcpy(ctx->cipher,c,sizeof(EVP_CIPHER_CTX));
++
++        if (b->callback != NULL)
++                b->callback(b,BIO_CB_CTRL,(char *)c,BIO_CTRL_SET,e,1L);
++        }
++*/
++
++int BIO_set_cipher(BIO *b, const EVP_CIPHER *c, const unsigned char *k,
++                   const unsigned char *i, int e)
++{
++    BIO_ENC_CTX *ctx;
++    long (*callback) (struct bio_st *, int, const char *, int, long, long);
++
++    ctx = BIO_get_data(b);
++    if (ctx == NULL)
++        return 0;
++
++    callback = BIO_get_callback(b);
++
++    if ((callback != NULL) &&
++            (callback(b, BIO_CB_CTRL, (const char *)c, BIO_CTRL_SET, e,
++                      0L) <= 0))
++        return 0;
++
++    BIO_set_init(b, 1);
++
++    if (!EVP_CipherInit_ex(ctx->cipher, c, NULL, k, i, e))
++        return 0;
++
++    if (callback != NULL)
++        return callback(b, BIO_CB_CTRL, (const char *)c, BIO_CTRL_SET, e, 1L);
++    return 1;
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/evp/bio_md.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/evp/bio_md.c
+new file mode 100644
+index 0000000..cd968ec
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/evp/bio_md.c
+@@ -0,0 +1,231 @@
++/*
++ * Copyright 1995-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include 
++#include "internal/cryptlib.h"
++#include 
++#include 
++#include "internal/evp_int.h"
++#include "evp_locl.h"
++#include "internal/bio.h"
++
++/*
++ * BIO_put and BIO_get both add to the digest, BIO_gets returns the digest
++ */
++
++static int md_write(BIO *h, char const *buf, int num);
++static int md_read(BIO *h, char *buf, int size);
++/*
++ * static int md_puts(BIO *h, const char *str);
++ */
++static int md_gets(BIO *h, char *str, int size);
++static long md_ctrl(BIO *h, int cmd, long arg1, void *arg2);
++static int md_new(BIO *h);
++static int md_free(BIO *data);
++static long md_callback_ctrl(BIO *h, int cmd, bio_info_cb *fp);
++
++static const BIO_METHOD methods_md = {
++    BIO_TYPE_MD, "message digest",
++    md_write,
++    md_read,
++    NULL,                       /* md_puts, */
++    md_gets,
++    md_ctrl,
++    md_new,
++    md_free,
++    md_callback_ctrl,
++};
++
++const BIO_METHOD *BIO_f_md(void)
++{
++    return (&methods_md);
++}
++
++static int md_new(BIO *bi)
++{
++    EVP_MD_CTX *ctx;
++
++    ctx = EVP_MD_CTX_new();
++    if (ctx == NULL)
++        return (0);
++
++    BIO_set_init(bi, 1);
++    BIO_set_data(bi, ctx);
++
++    return 1;
++}
++
++static int md_free(BIO *a)
++{
++    if (a == NULL)
++        return (0);
++    EVP_MD_CTX_free(BIO_get_data(a));
++    BIO_set_data(a, NULL);
++    BIO_set_init(a, 0);
++
++    return 1;
++}
++
++static int md_read(BIO *b, char *out, int outl)
++{
++    int ret = 0;
++    EVP_MD_CTX *ctx;
++    BIO *next;
++
++    if (out == NULL)
++        return (0);
++
++    ctx = BIO_get_data(b);
++    next = BIO_next(b);
++
++    if ((ctx == NULL) || (next == NULL))
++        return (0);
++
++    ret = BIO_read(next, out, outl);
++    if (BIO_get_init(b)) {
++        if (ret > 0) {
++            if (EVP_DigestUpdate(ctx, (unsigned char *)out,
++                                 (unsigned int)ret) <= 0)
++                return (-1);
++        }
++    }
++    BIO_clear_retry_flags(b);
++    BIO_copy_next_retry(b);
++    return (ret);
++}
++
++static int md_write(BIO *b, const char *in, int inl)
++{
++    int ret = 0;
++    EVP_MD_CTX *ctx;
++    BIO *next;
++
++    if ((in == NULL) || (inl <= 0))
++        return 0;
++
++    ctx = BIO_get_data(b);
++    next = BIO_next(b);
++    if ((ctx != NULL) && (next != NULL))
++        ret = BIO_write(next, in, inl);
++
++    if (BIO_get_init(b)) {
++        if (ret > 0) {
++            if (!EVP_DigestUpdate(ctx, (const unsigned char *)in,
++                                  (unsigned int)ret)) {
++                BIO_clear_retry_flags(b);
++                return 0;
++            }
++        }
++    }
++    if (next != NULL) {
++        BIO_clear_retry_flags(b);
++        BIO_copy_next_retry(b);
++    }
++    return ret;
++}
++
++static long md_ctrl(BIO *b, int cmd, long num, void *ptr)
++{
++    EVP_MD_CTX *ctx, *dctx, **pctx;
++    const EVP_MD **ppmd;
++    EVP_MD *md;
++    long ret = 1;
++    BIO *dbio, *next;
++
++
++    ctx = BIO_get_data(b);
++    next = BIO_next(b);
++
++    switch (cmd) {
++    case BIO_CTRL_RESET:
++        if (BIO_get_init(b))
++            ret = EVP_DigestInit_ex(ctx, ctx->digest, NULL);
++        else
++            ret = 0;
++        if (ret > 0)
++            ret = BIO_ctrl(next, cmd, num, ptr);
++        break;
++    case BIO_C_GET_MD:
++        if (BIO_get_init(b)) {
++            ppmd = ptr;
++            *ppmd = ctx->digest;
++        } else
++            ret = 0;
++        break;
++    case BIO_C_GET_MD_CTX:
++        pctx = ptr;
++        *pctx = ctx;
++        BIO_set_init(b, 1);
++        break;
++    case BIO_C_SET_MD_CTX:
++        if (BIO_get_init(b))
++            BIO_set_data(b, ptr);
++        else
++            ret = 0;
++        break;
++    case BIO_C_DO_STATE_MACHINE:
++        BIO_clear_retry_flags(b);
++        ret = BIO_ctrl(next, cmd, num, ptr);
++        BIO_copy_next_retry(b);
++        break;
++
++    case BIO_C_SET_MD:
++        md = ptr;
++        ret = EVP_DigestInit_ex(ctx, md, NULL);
++        if (ret > 0)
++            BIO_set_init(b, 1);
++        break;
++    case BIO_CTRL_DUP:
++        dbio = ptr;
++        dctx = BIO_get_data(dbio);
++        if (!EVP_MD_CTX_copy_ex(dctx, ctx))
++            return 0;
++        BIO_set_init(b, 1);
++        break;
++    default:
++        ret = BIO_ctrl(next, cmd, num, ptr);
++        break;
++    }
++    return (ret);
++}
++
++static long md_callback_ctrl(BIO *b, int cmd, bio_info_cb *fp)
++{
++    long ret = 1;
++    BIO *next;
++
++    next = BIO_next(b);
++
++    if (next == NULL)
++        return 0;
++
++    switch (cmd) {
++    default:
++        ret = BIO_callback_ctrl(next, cmd, fp);
++        break;
++    }
++    return (ret);
++}
++
++static int md_gets(BIO *bp, char *buf, int size)
++{
++    EVP_MD_CTX *ctx;
++    unsigned int ret;
++
++    ctx = BIO_get_data(bp);
++
++    if (size < ctx->digest->md_size)
++        return 0;
++
++    if (EVP_DigestFinal_ex(ctx, (unsigned char *)buf, &ret) <= 0)
++        return -1;
++
++    return ((int)ret);
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/evp/bio_ok.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/evp/bio_ok.c
+new file mode 100644
+index 0000000..7974b96
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/evp/bio_ok.c
+@@ -0,0 +1,604 @@
++/*
++ * Copyright 1995-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++/*-
++        From: Arne Ansper 
++
++        Why BIO_f_reliable?
++
++        I wrote function which took BIO* as argument, read data from it
++        and processed it. Then I wanted to store the input file in
++        encrypted form. OK I pushed BIO_f_cipher to the BIO stack
++        and everything was OK. BUT if user types wrong password
++        BIO_f_cipher outputs only garbage and my function crashes. Yes
++        I can and I should fix my function, but BIO_f_cipher is
++        easy way to add encryption support to many existing applications
++        and it's hard to debug and fix them all.
++
++        So I wanted another BIO which would catch the incorrect passwords and
++        file damages which cause garbage on BIO_f_cipher's output.
++
++        The easy way is to push the BIO_f_md and save the checksum at
++        the end of the file. However there are several problems with this
++        approach:
++
++        1) you must somehow separate checksum from actual data.
++        2) you need lot's of memory when reading the file, because you
++        must read to the end of the file and verify the checksum before
++        letting the application to read the data.
++
++        BIO_f_reliable tries to solve both problems, so that you can
++        read and write arbitrary long streams using only fixed amount
++        of memory.
++
++        BIO_f_reliable splits data stream into blocks. Each block is prefixed
++        with it's length and suffixed with it's digest. So you need only
++        several Kbytes of memory to buffer single block before verifying
++        it's digest.
++
++        BIO_f_reliable goes further and adds several important capabilities:
++
++        1) the digest of the block is computed over the whole stream
++        -- so nobody can rearrange the blocks or remove or replace them.
++
++        2) to detect invalid passwords right at the start BIO_f_reliable
++        adds special prefix to the stream. In order to avoid known plain-text
++        attacks this prefix is generated as follows:
++
++                *) digest is initialized with random seed instead of
++                standardized one.
++                *) same seed is written to output
++                *) well-known text is then hashed and the output
++                of the digest is also written to output.
++
++        reader can now read the seed from stream, hash the same string
++        and then compare the digest output.
++
++        Bad things: BIO_f_reliable knows what's going on in EVP_Digest. I
++        initially wrote and tested this code on x86 machine and wrote the
++        digests out in machine-dependent order :( There are people using
++        this code and I cannot change this easily without making existing
++        data files unreadable.
++
++*/
++
++#include 
++#include 
++#include 
++#include "internal/cryptlib.h"
++#include 
++#include "internal/bio.h"
++#include 
++#include 
++#include "internal/evp_int.h"
++
++static int ok_write(BIO *h, const char *buf, int num);
++static int ok_read(BIO *h, char *buf, int size);
++static long ok_ctrl(BIO *h, int cmd, long arg1, void *arg2);
++static int ok_new(BIO *h);
++static int ok_free(BIO *data);
++static long ok_callback_ctrl(BIO *h, int cmd, bio_info_cb *fp);
++
++static __owur int sig_out(BIO *b);
++static __owur int sig_in(BIO *b);
++static __owur int block_out(BIO *b);
++static __owur int block_in(BIO *b);
++#define OK_BLOCK_SIZE   (1024*4)
++#define OK_BLOCK_BLOCK  4
++#define IOBS            (OK_BLOCK_SIZE+ OK_BLOCK_BLOCK+ 3*EVP_MAX_MD_SIZE)
++#define WELLKNOWN "The quick brown fox jumped over the lazy dog's back."
++
++typedef struct ok_struct {
++    size_t buf_len;
++    size_t buf_off;
++    size_t buf_len_save;
++    size_t buf_off_save;
++    int cont;                   /* <= 0 when finished */
++    int finished;
++    EVP_MD_CTX *md;
++    int blockout;               /* output block is ready */
++    int sigio;                  /* must process signature */
++    unsigned char buf[IOBS];
++} BIO_OK_CTX;
++
++static const BIO_METHOD methods_ok = {
++    BIO_TYPE_CIPHER, "reliable",
++    ok_write,
++    ok_read,
++    NULL,                       /* ok_puts, */
++    NULL,                       /* ok_gets, */
++    ok_ctrl,
++    ok_new,
++    ok_free,
++    ok_callback_ctrl,
++};
++
++const BIO_METHOD *BIO_f_reliable(void)
++{
++    return (&methods_ok);
++}
++
++static int ok_new(BIO *bi)
++{
++    BIO_OK_CTX *ctx;
++
++    ctx = OPENSSL_zalloc(sizeof(*ctx));
++    if (ctx == NULL)
++        return 0;
++
++    ctx->cont = 1;
++    ctx->sigio = 1;
++    ctx->md = EVP_MD_CTX_new();
++    if (ctx->md == NULL) {
++        OPENSSL_free(ctx);
++        return 0;
++    }
++    BIO_set_init(bi, 0);
++    BIO_set_data(bi, ctx);
++
++    return 1;
++}
++
++static int ok_free(BIO *a)
++{
++    BIO_OK_CTX *ctx;
++
++    if (a == NULL)
++        return 0;
++
++    ctx = BIO_get_data(a);
++
++    EVP_MD_CTX_free(ctx->md);
++    OPENSSL_clear_free(ctx, sizeof(BIO_OK_CTX));
++    BIO_set_data(a, NULL);
++    BIO_set_init(a, 0);
++
++    return 1;
++}
++
++static int ok_read(BIO *b, char *out, int outl)
++{
++    int ret = 0, i, n;
++    BIO_OK_CTX *ctx;
++    BIO *next;
++
++    if (out == NULL)
++        return 0;
++
++    ctx = BIO_get_data(b);
++    next = BIO_next(b);
++
++    if ((ctx == NULL) || (next == NULL) || (BIO_get_init(b) == 0))
++        return 0;
++
++    while (outl > 0) {
++
++        /* copy clean bytes to output buffer */
++        if (ctx->blockout) {
++            i = ctx->buf_len - ctx->buf_off;
++            if (i > outl)
++                i = outl;
++            memcpy(out, &(ctx->buf[ctx->buf_off]), i);
++            ret += i;
++            out += i;
++            outl -= i;
++            ctx->buf_off += i;
++
++            /* all clean bytes are out */
++            if (ctx->buf_len == ctx->buf_off) {
++                ctx->buf_off = 0;
++
++                /*
++                 * copy start of the next block into proper place
++                 */
++                if (ctx->buf_len_save - ctx->buf_off_save > 0) {
++                    ctx->buf_len = ctx->buf_len_save - ctx->buf_off_save;
++                    memmove(ctx->buf, &(ctx->buf[ctx->buf_off_save]),
++                            ctx->buf_len);
++                } else {
++                    ctx->buf_len = 0;
++                }
++                ctx->blockout = 0;
++            }
++        }
++
++        /* output buffer full -- cancel */
++        if (outl == 0)
++            break;
++
++        /* no clean bytes in buffer -- fill it */
++        n = IOBS - ctx->buf_len;
++        i = BIO_read(next, &(ctx->buf[ctx->buf_len]), n);
++
++        if (i <= 0)
++            break;              /* nothing new */
++
++        ctx->buf_len += i;
++
++        /* no signature yet -- check if we got one */
++        if (ctx->sigio == 1) {
++            if (!sig_in(b)) {
++                BIO_clear_retry_flags(b);
++                return 0;
++            }
++        }
++
++        /* signature ok -- check if we got block */
++        if (ctx->sigio == 0) {
++            if (!block_in(b)) {
++                BIO_clear_retry_flags(b);
++                return 0;
++            }
++        }
++
++        /* invalid block -- cancel */
++        if (ctx->cont <= 0)
++            break;
++
++    }
++
++    BIO_clear_retry_flags(b);
++    BIO_copy_next_retry(b);
++    return ret;
++}
++
++static int ok_write(BIO *b, const char *in, int inl)
++{
++    int ret = 0, n, i;
++    BIO_OK_CTX *ctx;
++    BIO *next;
++
++    if (inl <= 0)
++        return inl;
++
++    ctx = BIO_get_data(b);
++    next = BIO_next(b);
++    ret = inl;
++
++    if ((ctx == NULL) || (next == NULL) || (BIO_get_init(b) == 0))
++        return (0);
++
++    if (ctx->sigio && !sig_out(b))
++        return 0;
++
++    do {
++        BIO_clear_retry_flags(b);
++        n = ctx->buf_len - ctx->buf_off;
++        while (ctx->blockout && n > 0) {
++            i = BIO_write(next, &(ctx->buf[ctx->buf_off]), n);
++            if (i <= 0) {
++                BIO_copy_next_retry(b);
++                if (!BIO_should_retry(b))
++                    ctx->cont = 0;
++                return (i);
++            }
++            ctx->buf_off += i;
++            n -= i;
++        }
++
++        /* at this point all pending data has been written */
++        ctx->blockout = 0;
++        if (ctx->buf_len == ctx->buf_off) {
++            ctx->buf_len = OK_BLOCK_BLOCK;
++            ctx->buf_off = 0;
++        }
++
++        if ((in == NULL) || (inl <= 0))
++            return (0);
++
++        n = (inl + ctx->buf_len > OK_BLOCK_SIZE + OK_BLOCK_BLOCK) ?
++            (int)(OK_BLOCK_SIZE + OK_BLOCK_BLOCK - ctx->buf_len) : inl;
++
++        memcpy(&ctx->buf[ctx->buf_len], in, n);
++        ctx->buf_len += n;
++        inl -= n;
++        in += n;
++
++        if (ctx->buf_len >= OK_BLOCK_SIZE + OK_BLOCK_BLOCK) {
++            if (!block_out(b)) {
++                BIO_clear_retry_flags(b);
++                return 0;
++            }
++        }
++    } while (inl > 0);
++
++    BIO_clear_retry_flags(b);
++    BIO_copy_next_retry(b);
++    return (ret);
++}
++
++static long ok_ctrl(BIO *b, int cmd, long num, void *ptr)
++{
++    BIO_OK_CTX *ctx;
++    EVP_MD *md;
++    const EVP_MD **ppmd;
++    long ret = 1;
++    int i;
++    BIO *next;
++
++    ctx = BIO_get_data(b);
++    next = BIO_next(b);
++
++    switch (cmd) {
++    case BIO_CTRL_RESET:
++        ctx->buf_len = 0;
++        ctx->buf_off = 0;
++        ctx->buf_len_save = 0;
++        ctx->buf_off_save = 0;
++        ctx->cont = 1;
++        ctx->finished = 0;
++        ctx->blockout = 0;
++        ctx->sigio = 1;
++        ret = BIO_ctrl(next, cmd, num, ptr);
++        break;
++    case BIO_CTRL_EOF:         /* More to read */
++        if (ctx->cont <= 0)
++            ret = 1;
++        else
++            ret = BIO_ctrl(next, cmd, num, ptr);
++        break;
++    case BIO_CTRL_PENDING:     /* More to read in buffer */
++    case BIO_CTRL_WPENDING:    /* More to read in buffer */
++        ret = ctx->blockout ? ctx->buf_len - ctx->buf_off : 0;
++        if (ret <= 0)
++            ret = BIO_ctrl(next, cmd, num, ptr);
++        break;
++    case BIO_CTRL_FLUSH:
++        /* do a final write */
++        if (ctx->blockout == 0)
++            if (!block_out(b))
++                return 0;
++
++        while (ctx->blockout) {
++            i = ok_write(b, NULL, 0);
++            if (i < 0) {
++                ret = i;
++                break;
++            }
++        }
++
++        ctx->finished = 1;
++        ctx->buf_off = ctx->buf_len = 0;
++        ctx->cont = (int)ret;
++
++        /* Finally flush the underlying BIO */
++        ret = BIO_ctrl(next, cmd, num, ptr);
++        break;
++    case BIO_C_DO_STATE_MACHINE:
++        BIO_clear_retry_flags(b);
++        ret = BIO_ctrl(next, cmd, num, ptr);
++        BIO_copy_next_retry(b);
++        break;
++    case BIO_CTRL_INFO:
++        ret = (long)ctx->cont;
++        break;
++    case BIO_C_SET_MD:
++        md = ptr;
++        if (!EVP_DigestInit_ex(ctx->md, md, NULL))
++            return 0;
++        BIO_set_init(b, 1);
++        break;
++    case BIO_C_GET_MD:
++        if (BIO_get_init(b)) {
++            ppmd = ptr;
++            *ppmd = EVP_MD_CTX_md(ctx->md);
++        } else
++            ret = 0;
++        break;
++    default:
++        ret = BIO_ctrl(next, cmd, num, ptr);
++        break;
++    }
++    return ret;
++}
++
++static long ok_callback_ctrl(BIO *b, int cmd, bio_info_cb *fp)
++{
++    long ret = 1;
++    BIO *next;
++
++    next = BIO_next(b);
++
++    if (next == NULL)
++        return 0;
++
++    switch (cmd) {
++    default:
++        ret = BIO_callback_ctrl(next, cmd, fp);
++        break;
++    }
++
++    return ret;
++}
++
++static void longswap(void *_ptr, size_t len)
++{
++    const union {
++        long one;
++        char little;
++    } is_endian = {
++        1
++    };
++
++    if (is_endian.little) {
++        size_t i;
++        unsigned char *p = _ptr, c;
++
++        for (i = 0; i < len; i += 4) {
++            c = p[0], p[0] = p[3], p[3] = c;
++            c = p[1], p[1] = p[2], p[2] = c;
++        }
++    }
++}
++
++static int sig_out(BIO *b)
++{
++    BIO_OK_CTX *ctx;
++    EVP_MD_CTX *md;
++    const EVP_MD *digest;
++    int md_size;
++    void *md_data;
++
++    ctx = BIO_get_data(b);
++    md = ctx->md;
++    digest = EVP_MD_CTX_md(md);
++    md_size = EVP_MD_size(digest);
++    md_data = EVP_MD_CTX_md_data(md);
++
++    if (ctx->buf_len + 2 * md_size > OK_BLOCK_SIZE)
++        return 1;
++
++    if (!EVP_DigestInit_ex(md, digest, NULL))
++        goto berr;
++    /*
++     * FIXME: there's absolutely no guarantee this makes any sense at all,
++     * particularly now EVP_MD_CTX has been restructured.
++     */
++    if (RAND_bytes(md_data, md_size) <= 0)
++        goto berr;
++    memcpy(&(ctx->buf[ctx->buf_len]), md_data, md_size);
++    longswap(&(ctx->buf[ctx->buf_len]), md_size);
++    ctx->buf_len += md_size;
++
++    if (!EVP_DigestUpdate(md, WELLKNOWN, strlen(WELLKNOWN)))
++        goto berr;
++    if (!EVP_DigestFinal_ex(md, &(ctx->buf[ctx->buf_len]), NULL))
++        goto berr;
++    ctx->buf_len += md_size;
++    ctx->blockout = 1;
++    ctx->sigio = 0;
++    return 1;
++ berr:
++    BIO_clear_retry_flags(b);
++    return 0;
++}
++
++static int sig_in(BIO *b)
++{
++    BIO_OK_CTX *ctx;
++    EVP_MD_CTX *md;
++    unsigned char tmp[EVP_MAX_MD_SIZE];
++    int ret = 0;
++    const EVP_MD *digest;
++    int md_size;
++    void *md_data;
++
++    ctx = BIO_get_data(b);
++    md = ctx->md;
++    digest = EVP_MD_CTX_md(md);
++    md_size = EVP_MD_size(digest);
++    md_data = EVP_MD_CTX_md_data(md);
++
++    if ((int)(ctx->buf_len - ctx->buf_off) < 2 * md_size)
++        return 1;
++
++    if (!EVP_DigestInit_ex(md, digest, NULL))
++        goto berr;
++    memcpy(md_data, &(ctx->buf[ctx->buf_off]), md_size);
++    longswap(md_data, md_size);
++    ctx->buf_off += md_size;
++
++    if (!EVP_DigestUpdate(md, WELLKNOWN, strlen(WELLKNOWN)))
++        goto berr;
++    if (!EVP_DigestFinal_ex(md, tmp, NULL))
++        goto berr;
++    ret = memcmp(&(ctx->buf[ctx->buf_off]), tmp, md_size) == 0;
++    ctx->buf_off += md_size;
++    if (ret == 1) {
++        ctx->sigio = 0;
++        if (ctx->buf_len != ctx->buf_off) {
++            memmove(ctx->buf, &(ctx->buf[ctx->buf_off]),
++                    ctx->buf_len - ctx->buf_off);
++        }
++        ctx->buf_len -= ctx->buf_off;
++        ctx->buf_off = 0;
++    } else {
++        ctx->cont = 0;
++    }
++    return 1;
++ berr:
++    BIO_clear_retry_flags(b);
++    return 0;
++}
++
++static int block_out(BIO *b)
++{
++    BIO_OK_CTX *ctx;
++    EVP_MD_CTX *md;
++    unsigned long tl;
++    const EVP_MD *digest;
++    int md_size;
++
++    ctx = BIO_get_data(b);
++    md = ctx->md;
++    digest = EVP_MD_CTX_md(md);
++    md_size = EVP_MD_size(digest);
++
++    tl = ctx->buf_len - OK_BLOCK_BLOCK;
++    ctx->buf[0] = (unsigned char)(tl >> 24);
++    ctx->buf[1] = (unsigned char)(tl >> 16);
++    ctx->buf[2] = (unsigned char)(tl >> 8);
++    ctx->buf[3] = (unsigned char)(tl);
++    if (!EVP_DigestUpdate(md,
++                          (unsigned char *)&(ctx->buf[OK_BLOCK_BLOCK]), tl))
++        goto berr;
++    if (!EVP_DigestFinal_ex(md, &(ctx->buf[ctx->buf_len]), NULL))
++        goto berr;
++    ctx->buf_len += md_size;
++    ctx->blockout = 1;
++    return 1;
++ berr:
++    BIO_clear_retry_flags(b);
++    return 0;
++}
++
++static int block_in(BIO *b)
++{
++    BIO_OK_CTX *ctx;
++    EVP_MD_CTX *md;
++    unsigned long tl = 0;
++    unsigned char tmp[EVP_MAX_MD_SIZE];
++    int md_size;
++
++    ctx = BIO_get_data(b);
++    md = ctx->md;
++    md_size = EVP_MD_size(EVP_MD_CTX_md(md));
++
++    assert(sizeof(tl) >= OK_BLOCK_BLOCK); /* always true */
++    tl = ctx->buf[0];
++    tl <<= 8;
++    tl |= ctx->buf[1];
++    tl <<= 8;
++    tl |= ctx->buf[2];
++    tl <<= 8;
++    tl |= ctx->buf[3];
++
++    if (ctx->buf_len < tl + OK_BLOCK_BLOCK + md_size)
++        return 1;
++
++    if (!EVP_DigestUpdate(md,
++                          (unsigned char *)&(ctx->buf[OK_BLOCK_BLOCK]), tl))
++        goto berr;
++    if (!EVP_DigestFinal_ex(md, tmp, NULL))
++        goto berr;
++    if (memcmp(&(ctx->buf[tl + OK_BLOCK_BLOCK]), tmp, md_size) == 0) {
++        /* there might be parts from next block lurking around ! */
++        ctx->buf_off_save = tl + OK_BLOCK_BLOCK + md_size;
++        ctx->buf_len_save = ctx->buf_len;
++        ctx->buf_off = OK_BLOCK_BLOCK;
++        ctx->buf_len = tl + OK_BLOCK_BLOCK;
++        ctx->blockout = 1;
++    } else {
++        ctx->cont = 0;
++    }
++    return 1;
++ berr:
++    BIO_clear_retry_flags(b);
++    return 0;
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/evp/build.info b/CryptoPkg/Library/OpensslLib/openssl/crypto/evp/build.info
+new file mode 100644
+index 0000000..bf633dc
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/evp/build.info
+@@ -0,0 +1,22 @@
++LIBS=../../libcrypto
++SOURCE[../../libcrypto]=\
++        encode.c digest.c evp_enc.c evp_key.c evp_cnf.c \
++        e_des.c e_bf.c e_idea.c e_des3.c e_camellia.c\
++        e_rc4.c e_aes.c names.c e_seed.c \
++        e_xcbc_d.c e_rc2.c e_cast.c e_rc5.c \
++        m_null.c m_md2.c m_md4.c m_md5.c m_sha1.c m_wp.c \
++        m_md5_sha1.c m_mdc2.c m_ripemd.c \
++        p_open.c p_seal.c p_sign.c p_verify.c p_lib.c p_enc.c p_dec.c \
++        bio_md.c bio_b64.c bio_enc.c evp_err.c e_null.c \
++        c_allc.c c_alld.c evp_lib.c bio_ok.c \
++        evp_pkey.c evp_pbe.c p5_crpt.c p5_crpt2.c scrypt.c \
++        e_old.c pmeth_lib.c pmeth_fn.c pmeth_gn.c m_sigver.c \
++        e_aes_cbc_hmac_sha1.c e_aes_cbc_hmac_sha256.c e_rc4_hmac_md5.c \
++        e_chacha20_poly1305.c cmeth_lib.c
++
++INCLUDE[e_aes.o]=.. ../modes
++INCLUDE[e_aes_cbc_hmac_sha1.o]=../modes
++INCLUDE[e_aes_cbc_hmac_sha256.o]=../modes
++INCLUDE[e_camellia.o]=.. ../modes
++INCLUDE[e_des.o]=..
++INCLUDE[e_des3.o]=..
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/evp/c_allc.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/evp/c_allc.c
+new file mode 100644
+index 0000000..6ed31ed
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/evp/c_allc.c
+@@ -0,0 +1,220 @@
++/*
++ * Copyright 1995-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include "internal/cryptlib.h"
++#include 
++#include 
++#include 
++#include 
++
++void openssl_add_all_ciphers_int(void)
++{
++
++#ifndef OPENSSL_NO_DES
++    EVP_add_cipher(EVP_des_cfb());
++    EVP_add_cipher(EVP_des_cfb1());
++    EVP_add_cipher(EVP_des_cfb8());
++    EVP_add_cipher(EVP_des_ede_cfb());
++    EVP_add_cipher(EVP_des_ede3_cfb());
++    EVP_add_cipher(EVP_des_ede3_cfb1());
++    EVP_add_cipher(EVP_des_ede3_cfb8());
++
++    EVP_add_cipher(EVP_des_ofb());
++    EVP_add_cipher(EVP_des_ede_ofb());
++    EVP_add_cipher(EVP_des_ede3_ofb());
++
++    EVP_add_cipher(EVP_desx_cbc());
++    EVP_add_cipher_alias(SN_desx_cbc, "DESX");
++    EVP_add_cipher_alias(SN_desx_cbc, "desx");
++
++    EVP_add_cipher(EVP_des_cbc());
++    EVP_add_cipher_alias(SN_des_cbc, "DES");
++    EVP_add_cipher_alias(SN_des_cbc, "des");
++    EVP_add_cipher(EVP_des_ede_cbc());
++    EVP_add_cipher(EVP_des_ede3_cbc());
++    EVP_add_cipher_alias(SN_des_ede3_cbc, "DES3");
++    EVP_add_cipher_alias(SN_des_ede3_cbc, "des3");
++
++    EVP_add_cipher(EVP_des_ecb());
++    EVP_add_cipher(EVP_des_ede());
++    EVP_add_cipher_alias(SN_des_ede_ecb, "DES-EDE-ECB");
++    EVP_add_cipher_alias(SN_des_ede_ecb, "des-ede-ecb");
++    EVP_add_cipher(EVP_des_ede3());
++    EVP_add_cipher_alias(SN_des_ede3_ecb, "DES-EDE3-ECB");
++    EVP_add_cipher_alias(SN_des_ede3_ecb, "des-ede3-ecb");
++    EVP_add_cipher(EVP_des_ede3_wrap());
++    EVP_add_cipher_alias(SN_id_smime_alg_CMS3DESwrap, "des3-wrap");
++#endif
++
++#ifndef OPENSSL_NO_RC4
++    EVP_add_cipher(EVP_rc4());
++    EVP_add_cipher(EVP_rc4_40());
++# ifndef OPENSSL_NO_MD5
++    EVP_add_cipher(EVP_rc4_hmac_md5());
++# endif
++#endif
++
++#ifndef OPENSSL_NO_IDEA
++    EVP_add_cipher(EVP_idea_ecb());
++    EVP_add_cipher(EVP_idea_cfb());
++    EVP_add_cipher(EVP_idea_ofb());
++    EVP_add_cipher(EVP_idea_cbc());
++    EVP_add_cipher_alias(SN_idea_cbc, "IDEA");
++    EVP_add_cipher_alias(SN_idea_cbc, "idea");
++#endif
++
++#ifndef OPENSSL_NO_SEED
++    EVP_add_cipher(EVP_seed_ecb());
++    EVP_add_cipher(EVP_seed_cfb());
++    EVP_add_cipher(EVP_seed_ofb());
++    EVP_add_cipher(EVP_seed_cbc());
++    EVP_add_cipher_alias(SN_seed_cbc, "SEED");
++    EVP_add_cipher_alias(SN_seed_cbc, "seed");
++#endif
++
++#ifndef OPENSSL_NO_RC2
++    EVP_add_cipher(EVP_rc2_ecb());
++    EVP_add_cipher(EVP_rc2_cfb());
++    EVP_add_cipher(EVP_rc2_ofb());
++    EVP_add_cipher(EVP_rc2_cbc());
++    EVP_add_cipher(EVP_rc2_40_cbc());
++    EVP_add_cipher(EVP_rc2_64_cbc());
++    EVP_add_cipher_alias(SN_rc2_cbc, "RC2");
++    EVP_add_cipher_alias(SN_rc2_cbc, "rc2");
++    EVP_add_cipher_alias(SN_rc2_cbc, "rc2-128");
++    EVP_add_cipher_alias(SN_rc2_64_cbc, "rc2-64");
++    EVP_add_cipher_alias(SN_rc2_40_cbc, "rc2-40");
++#endif
++
++#ifndef OPENSSL_NO_BF
++    EVP_add_cipher(EVP_bf_ecb());
++    EVP_add_cipher(EVP_bf_cfb());
++    EVP_add_cipher(EVP_bf_ofb());
++    EVP_add_cipher(EVP_bf_cbc());
++    EVP_add_cipher_alias(SN_bf_cbc, "BF");
++    EVP_add_cipher_alias(SN_bf_cbc, "bf");
++    EVP_add_cipher_alias(SN_bf_cbc, "blowfish");
++#endif
++
++#ifndef OPENSSL_NO_CAST
++    EVP_add_cipher(EVP_cast5_ecb());
++    EVP_add_cipher(EVP_cast5_cfb());
++    EVP_add_cipher(EVP_cast5_ofb());
++    EVP_add_cipher(EVP_cast5_cbc());
++    EVP_add_cipher_alias(SN_cast5_cbc, "CAST");
++    EVP_add_cipher_alias(SN_cast5_cbc, "cast");
++    EVP_add_cipher_alias(SN_cast5_cbc, "CAST-cbc");
++    EVP_add_cipher_alias(SN_cast5_cbc, "cast-cbc");
++#endif
++
++#ifndef OPENSSL_NO_RC5
++    EVP_add_cipher(EVP_rc5_32_12_16_ecb());
++    EVP_add_cipher(EVP_rc5_32_12_16_cfb());
++    EVP_add_cipher(EVP_rc5_32_12_16_ofb());
++    EVP_add_cipher(EVP_rc5_32_12_16_cbc());
++    EVP_add_cipher_alias(SN_rc5_cbc, "rc5");
++    EVP_add_cipher_alias(SN_rc5_cbc, "RC5");
++#endif
++
++    EVP_add_cipher(EVP_aes_128_ecb());
++    EVP_add_cipher(EVP_aes_128_cbc());
++    EVP_add_cipher(EVP_aes_128_cfb());
++    EVP_add_cipher(EVP_aes_128_cfb1());
++    EVP_add_cipher(EVP_aes_128_cfb8());
++    EVP_add_cipher(EVP_aes_128_ofb());
++    EVP_add_cipher(EVP_aes_128_ctr());
++    EVP_add_cipher(EVP_aes_128_gcm());
++#ifndef OPENSSL_NO_OCB
++    EVP_add_cipher(EVP_aes_128_ocb());
++#endif
++    EVP_add_cipher(EVP_aes_128_xts());
++    EVP_add_cipher(EVP_aes_128_ccm());
++    EVP_add_cipher(EVP_aes_128_wrap());
++    EVP_add_cipher_alias(SN_id_aes128_wrap, "aes128-wrap");
++    EVP_add_cipher(EVP_aes_128_wrap_pad());
++    EVP_add_cipher_alias(SN_aes_128_cbc, "AES128");
++    EVP_add_cipher_alias(SN_aes_128_cbc, "aes128");
++    EVP_add_cipher(EVP_aes_192_ecb());
++    EVP_add_cipher(EVP_aes_192_cbc());
++    EVP_add_cipher(EVP_aes_192_cfb());
++    EVP_add_cipher(EVP_aes_192_cfb1());
++    EVP_add_cipher(EVP_aes_192_cfb8());
++    EVP_add_cipher(EVP_aes_192_ofb());
++    EVP_add_cipher(EVP_aes_192_ctr());
++    EVP_add_cipher(EVP_aes_192_gcm());
++#ifndef OPENSSL_NO_OCB
++    EVP_add_cipher(EVP_aes_192_ocb());
++#endif
++    EVP_add_cipher(EVP_aes_192_ccm());
++    EVP_add_cipher(EVP_aes_192_wrap());
++    EVP_add_cipher_alias(SN_id_aes192_wrap, "aes192-wrap");
++    EVP_add_cipher(EVP_aes_192_wrap_pad());
++    EVP_add_cipher_alias(SN_aes_192_cbc, "AES192");
++    EVP_add_cipher_alias(SN_aes_192_cbc, "aes192");
++    EVP_add_cipher(EVP_aes_256_ecb());
++    EVP_add_cipher(EVP_aes_256_cbc());
++    EVP_add_cipher(EVP_aes_256_cfb());
++    EVP_add_cipher(EVP_aes_256_cfb1());
++    EVP_add_cipher(EVP_aes_256_cfb8());
++    EVP_add_cipher(EVP_aes_256_ofb());
++    EVP_add_cipher(EVP_aes_256_ctr());
++    EVP_add_cipher(EVP_aes_256_gcm());
++#ifndef OPENSSL_NO_OCB
++    EVP_add_cipher(EVP_aes_256_ocb());
++#endif
++    EVP_add_cipher(EVP_aes_256_xts());
++    EVP_add_cipher(EVP_aes_256_ccm());
++    EVP_add_cipher(EVP_aes_256_wrap());
++    EVP_add_cipher_alias(SN_id_aes256_wrap, "aes256-wrap");
++    EVP_add_cipher(EVP_aes_256_wrap_pad());
++    EVP_add_cipher_alias(SN_aes_256_cbc, "AES256");
++    EVP_add_cipher_alias(SN_aes_256_cbc, "aes256");
++    EVP_add_cipher(EVP_aes_128_cbc_hmac_sha1());
++    EVP_add_cipher(EVP_aes_256_cbc_hmac_sha1());
++    EVP_add_cipher(EVP_aes_128_cbc_hmac_sha256());
++    EVP_add_cipher(EVP_aes_256_cbc_hmac_sha256());
++
++#ifndef OPENSSL_NO_CAMELLIA
++    EVP_add_cipher(EVP_camellia_128_ecb());
++    EVP_add_cipher(EVP_camellia_128_cbc());
++    EVP_add_cipher(EVP_camellia_128_cfb());
++    EVP_add_cipher(EVP_camellia_128_cfb1());
++    EVP_add_cipher(EVP_camellia_128_cfb8());
++    EVP_add_cipher(EVP_camellia_128_ofb());
++    EVP_add_cipher_alias(SN_camellia_128_cbc, "CAMELLIA128");
++    EVP_add_cipher_alias(SN_camellia_128_cbc, "camellia128");
++    EVP_add_cipher(EVP_camellia_192_ecb());
++    EVP_add_cipher(EVP_camellia_192_cbc());
++    EVP_add_cipher(EVP_camellia_192_cfb());
++    EVP_add_cipher(EVP_camellia_192_cfb1());
++    EVP_add_cipher(EVP_camellia_192_cfb8());
++    EVP_add_cipher(EVP_camellia_192_ofb());
++    EVP_add_cipher_alias(SN_camellia_192_cbc, "CAMELLIA192");
++    EVP_add_cipher_alias(SN_camellia_192_cbc, "camellia192");
++    EVP_add_cipher(EVP_camellia_256_ecb());
++    EVP_add_cipher(EVP_camellia_256_cbc());
++    EVP_add_cipher(EVP_camellia_256_cfb());
++    EVP_add_cipher(EVP_camellia_256_cfb1());
++    EVP_add_cipher(EVP_camellia_256_cfb8());
++    EVP_add_cipher(EVP_camellia_256_ofb());
++    EVP_add_cipher_alias(SN_camellia_256_cbc, "CAMELLIA256");
++    EVP_add_cipher_alias(SN_camellia_256_cbc, "camellia256");
++    EVP_add_cipher(EVP_camellia_128_ctr());
++    EVP_add_cipher(EVP_camellia_192_ctr());
++    EVP_add_cipher(EVP_camellia_256_ctr());
++#endif
++
++#ifndef OPENSSL_NO_CHACHA
++    EVP_add_cipher(EVP_chacha20());
++# ifndef OPENSSL_NO_POLY1305
++    EVP_add_cipher(EVP_chacha20_poly1305());
++# endif
++#endif
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/evp/c_alld.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/evp/c_alld.c
+new file mode 100644
+index 0000000..ec79734
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/evp/c_alld.c
+@@ -0,0 +1,49 @@
++/*
++ * Copyright 1995-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include "internal/cryptlib.h"
++#include 
++#include 
++#include 
++#include 
++
++void openssl_add_all_digests_int(void)
++{
++#ifndef OPENSSL_NO_MD4
++    EVP_add_digest(EVP_md4());
++#endif
++#ifndef OPENSSL_NO_MD5
++    EVP_add_digest(EVP_md5());
++    EVP_add_digest_alias(SN_md5, "ssl3-md5");
++    EVP_add_digest(EVP_md5_sha1());
++#endif
++    EVP_add_digest(EVP_sha1());
++    EVP_add_digest_alias(SN_sha1, "ssl3-sha1");
++    EVP_add_digest_alias(SN_sha1WithRSAEncryption, SN_sha1WithRSA);
++#if !defined(OPENSSL_NO_MDC2) && !defined(OPENSSL_NO_DES)
++    EVP_add_digest(EVP_mdc2());
++#endif
++#ifndef OPENSSL_NO_RMD160
++    EVP_add_digest(EVP_ripemd160());
++    EVP_add_digest_alias(SN_ripemd160, "ripemd");
++    EVP_add_digest_alias(SN_ripemd160, "rmd160");
++#endif
++    EVP_add_digest(EVP_sha224());
++    EVP_add_digest(EVP_sha256());
++    EVP_add_digest(EVP_sha384());
++    EVP_add_digest(EVP_sha512());
++#ifndef OPENSSL_NO_WHIRLPOOL
++    EVP_add_digest(EVP_whirlpool());
++#endif
++#ifndef OPENSSL_NO_BLAKE2
++    EVP_add_digest(EVP_blake2b512());
++    EVP_add_digest(EVP_blake2s256());
++#endif
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/evp/cmeth_lib.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/evp/cmeth_lib.c
+new file mode 100644
+index 0000000..e2295c4
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/evp/cmeth_lib.c
+@@ -0,0 +1,151 @@
++/*
++ * Copyright 2015-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++
++#include 
++#include "internal/evp_int.h"
++#include "evp_locl.h"
++
++EVP_CIPHER *EVP_CIPHER_meth_new(int cipher_type, int block_size, int key_len)
++{
++    EVP_CIPHER *cipher = OPENSSL_zalloc(sizeof(EVP_CIPHER));
++
++    if (cipher != NULL) {
++        cipher->nid = cipher_type;
++        cipher->block_size = block_size;
++        cipher->key_len = key_len;
++    }
++    return cipher;
++}
++
++EVP_CIPHER *EVP_CIPHER_meth_dup(const EVP_CIPHER *cipher)
++{
++    EVP_CIPHER *to = EVP_CIPHER_meth_new(cipher->nid, cipher->block_size,
++                                         cipher->key_len);
++
++    if (to != NULL)
++        memcpy(to, cipher, sizeof(*to));
++    return to;
++}
++
++void EVP_CIPHER_meth_free(EVP_CIPHER *cipher)
++{
++    OPENSSL_free(cipher);
++}
++
++int EVP_CIPHER_meth_set_iv_length(EVP_CIPHER *cipher, int iv_len)
++{
++    cipher->iv_len = iv_len;
++    return 1;
++}
++
++int EVP_CIPHER_meth_set_flags(EVP_CIPHER *cipher, unsigned long flags)
++{
++    cipher->flags = flags;
++    return 1;
++}
++
++int EVP_CIPHER_meth_set_impl_ctx_size(EVP_CIPHER *cipher, int ctx_size)
++{
++    cipher->ctx_size = ctx_size;
++    return 1;
++}
++
++int EVP_CIPHER_meth_set_init(EVP_CIPHER *cipher,
++                             int (*init) (EVP_CIPHER_CTX *ctx,
++                                          const unsigned char *key,
++                                          const unsigned char *iv,
++                                          int enc))
++{
++    cipher->init = init;
++    return 1;
++}
++
++int EVP_CIPHER_meth_set_do_cipher(EVP_CIPHER *cipher,
++                                  int (*do_cipher) (EVP_CIPHER_CTX *ctx,
++                                                    unsigned char *out,
++                                                    const unsigned char *in,
++                                                    size_t inl))
++{
++    cipher->do_cipher = do_cipher;
++    return 1;
++}
++
++int EVP_CIPHER_meth_set_cleanup(EVP_CIPHER *cipher,
++                                int (*cleanup) (EVP_CIPHER_CTX *))
++{
++    cipher->cleanup = cleanup;
++    return 1;
++}
++
++int EVP_CIPHER_meth_set_set_asn1_params(EVP_CIPHER *cipher,
++                                        int (*set_asn1_parameters) (EVP_CIPHER_CTX *,
++                                                                    ASN1_TYPE *))
++{
++    cipher->set_asn1_parameters = set_asn1_parameters;
++    return 1;
++}
++
++int EVP_CIPHER_meth_set_get_asn1_params(EVP_CIPHER *cipher,
++                                        int (*get_asn1_parameters) (EVP_CIPHER_CTX *,
++                                                                    ASN1_TYPE *))
++{
++    cipher->get_asn1_parameters = get_asn1_parameters;
++    return 1;
++}
++
++int EVP_CIPHER_meth_set_ctrl(EVP_CIPHER *cipher,
++                             int (*ctrl) (EVP_CIPHER_CTX *, int type,
++                                          int arg, void *ptr))
++{
++    cipher->ctrl = ctrl;
++    return 1;
++}
++
++
++int (*EVP_CIPHER_meth_get_init(const EVP_CIPHER *cipher))(EVP_CIPHER_CTX *ctx,
++                                                          const unsigned char *key,
++                                                          const unsigned char *iv,
++                                                          int enc)
++{
++    return cipher->init;
++}
++int (*EVP_CIPHER_meth_get_do_cipher(const EVP_CIPHER *cipher))(EVP_CIPHER_CTX *ctx,
++                                                               unsigned char *out,
++                                                               const unsigned char *in,
++                                                               size_t inl)
++{
++    return cipher->do_cipher;
++}
++
++int (*EVP_CIPHER_meth_get_cleanup(const EVP_CIPHER *cipher))(EVP_CIPHER_CTX *)
++{
++    return cipher->cleanup;
++}
++
++int (*EVP_CIPHER_meth_get_set_asn1_params(const EVP_CIPHER *cipher))(EVP_CIPHER_CTX *,
++                                                                     ASN1_TYPE *)
++{
++    return cipher->set_asn1_parameters;
++}
++
++int (*EVP_CIPHER_meth_get_get_asn1_params(const EVP_CIPHER *cipher))(EVP_CIPHER_CTX *,
++                                                               ASN1_TYPE *)
++{
++    return cipher->get_asn1_parameters;
++}
++
++int (*EVP_CIPHER_meth_get_ctrl(const EVP_CIPHER *cipher))(EVP_CIPHER_CTX *,
++                                                          int type, int arg,
++                                                          void *ptr)
++{
++    return cipher->ctrl;
++}
++
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/evp/digest.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/evp/digest.c
+new file mode 100644
+index 0000000..65eff7c
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/evp/digest.c
+@@ -0,0 +1,269 @@
++/*
++ * Copyright 1995-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include "internal/cryptlib.h"
++#include 
++#include 
++#include 
++#include "internal/evp_int.h"
++#include "evp_locl.h"
++
++/* This call frees resources associated with the context */
++int EVP_MD_CTX_reset(EVP_MD_CTX *ctx)
++{
++    if (ctx == NULL)
++        return 1;
++
++    /*
++     * Don't assume ctx->md_data was cleaned in EVP_Digest_Final, because
++     * sometimes only copies of the context are ever finalised.
++     */
++    if (ctx->digest && ctx->digest->cleanup
++        && !EVP_MD_CTX_test_flags(ctx, EVP_MD_CTX_FLAG_CLEANED))
++        ctx->digest->cleanup(ctx);
++    if (ctx->digest && ctx->digest->ctx_size && ctx->md_data
++        && !EVP_MD_CTX_test_flags(ctx, EVP_MD_CTX_FLAG_REUSE)) {
++        OPENSSL_clear_free(ctx->md_data, ctx->digest->ctx_size);
++    }
++    EVP_PKEY_CTX_free(ctx->pctx);
++#ifndef OPENSSL_NO_ENGINE
++    ENGINE_finish(ctx->engine);
++#endif
++    OPENSSL_cleanse(ctx, sizeof(*ctx));
++
++    return 1;
++}
++
++EVP_MD_CTX *EVP_MD_CTX_new(void)
++{
++    return OPENSSL_zalloc(sizeof(EVP_MD_CTX));
++}
++
++void EVP_MD_CTX_free(EVP_MD_CTX *ctx)
++{
++    EVP_MD_CTX_reset(ctx);
++    OPENSSL_free(ctx);
++}
++
++int EVP_DigestInit(EVP_MD_CTX *ctx, const EVP_MD *type)
++{
++    EVP_MD_CTX_reset(ctx);
++    return EVP_DigestInit_ex(ctx, type, NULL);
++}
++
++int EVP_DigestInit_ex(EVP_MD_CTX *ctx, const EVP_MD *type, ENGINE *impl)
++{
++    EVP_MD_CTX_clear_flags(ctx, EVP_MD_CTX_FLAG_CLEANED);
++#ifndef OPENSSL_NO_ENGINE
++    /*
++     * Whether it's nice or not, "Inits" can be used on "Final"'d contexts so
++     * this context may already have an ENGINE! Try to avoid releasing the
++     * previous handle, re-querying for an ENGINE, and having a
++     * reinitialisation, when it may all be unnecessary.
++     */
++    if (ctx->engine && ctx->digest &&
++        (type == NULL || (type->type == ctx->digest->type)))
++        goto skip_to_init;
++    if (type) {
++        /*
++         * Ensure an ENGINE left lying around from last time is cleared (the
++         * previous check attempted to avoid this if the same ENGINE and
++         * EVP_MD could be used).
++         */
++        ENGINE_finish(ctx->engine);
++        if (impl != NULL) {
++            if (!ENGINE_init(impl)) {
++                EVPerr(EVP_F_EVP_DIGESTINIT_EX, EVP_R_INITIALIZATION_ERROR);
++                return 0;
++            }
++        } else {
++            /* Ask if an ENGINE is reserved for this job */
++            impl = ENGINE_get_digest_engine(type->type);
++        }
++        if (impl != NULL) {
++            /* There's an ENGINE for this job ... (apparently) */
++            const EVP_MD *d = ENGINE_get_digest(impl, type->type);
++
++            if (d == NULL) {
++                EVPerr(EVP_F_EVP_DIGESTINIT_EX, EVP_R_INITIALIZATION_ERROR);
++                ENGINE_finish(impl);
++                return 0;
++            }
++            /* We'll use the ENGINE's private digest definition */
++            type = d;
++            /*
++             * Store the ENGINE functional reference so we know 'type' came
++             * from an ENGINE and we need to release it when done.
++             */
++            ctx->engine = impl;
++        } else
++            ctx->engine = NULL;
++    } else {
++        if (!ctx->digest) {
++            EVPerr(EVP_F_EVP_DIGESTINIT_EX, EVP_R_NO_DIGEST_SET);
++            return 0;
++        }
++        type = ctx->digest;
++    }
++#endif
++    if (ctx->digest != type) {
++        if (ctx->digest && ctx->digest->ctx_size) {
++            OPENSSL_clear_free(ctx->md_data, ctx->digest->ctx_size);
++            ctx->md_data = NULL;
++        }
++        ctx->digest = type;
++        if (!(ctx->flags & EVP_MD_CTX_FLAG_NO_INIT) && type->ctx_size) {
++            ctx->update = type->update;
++            ctx->md_data = OPENSSL_zalloc(type->ctx_size);
++            if (ctx->md_data == NULL) {
++                EVPerr(EVP_F_EVP_DIGESTINIT_EX, ERR_R_MALLOC_FAILURE);
++                return 0;
++            }
++        }
++    }
++#ifndef OPENSSL_NO_ENGINE
++ skip_to_init:
++#endif
++    if (ctx->pctx) {
++        int r;
++        r = EVP_PKEY_CTX_ctrl(ctx->pctx, -1, EVP_PKEY_OP_TYPE_SIG,
++                              EVP_PKEY_CTRL_DIGESTINIT, 0, ctx);
++        if (r <= 0 && (r != -2))
++            return 0;
++    }
++    if (ctx->flags & EVP_MD_CTX_FLAG_NO_INIT)
++        return 1;
++    return ctx->digest->init(ctx);
++}
++
++int EVP_DigestUpdate(EVP_MD_CTX *ctx, const void *data, size_t count)
++{
++    return ctx->update(ctx, data, count);
++}
++
++/* The caller can assume that this removes any secret data from the context */
++int EVP_DigestFinal(EVP_MD_CTX *ctx, unsigned char *md, unsigned int *size)
++{
++    int ret;
++    ret = EVP_DigestFinal_ex(ctx, md, size);
++    EVP_MD_CTX_reset(ctx);
++    return ret;
++}
++
++/* The caller can assume that this removes any secret data from the context */
++int EVP_DigestFinal_ex(EVP_MD_CTX *ctx, unsigned char *md, unsigned int *size)
++{
++    int ret;
++
++    OPENSSL_assert(ctx->digest->md_size <= EVP_MAX_MD_SIZE);
++    ret = ctx->digest->final(ctx, md);
++    if (size != NULL)
++        *size = ctx->digest->md_size;
++    if (ctx->digest->cleanup) {
++        ctx->digest->cleanup(ctx);
++        EVP_MD_CTX_set_flags(ctx, EVP_MD_CTX_FLAG_CLEANED);
++    }
++    OPENSSL_cleanse(ctx->md_data, ctx->digest->ctx_size);
++    return ret;
++}
++
++int EVP_MD_CTX_copy(EVP_MD_CTX *out, const EVP_MD_CTX *in)
++{
++    EVP_MD_CTX_reset(out);
++    return EVP_MD_CTX_copy_ex(out, in);
++}
++
++int EVP_MD_CTX_copy_ex(EVP_MD_CTX *out, const EVP_MD_CTX *in)
++{
++    unsigned char *tmp_buf;
++    if ((in == NULL) || (in->digest == NULL)) {
++        EVPerr(EVP_F_EVP_MD_CTX_COPY_EX, EVP_R_INPUT_NOT_INITIALIZED);
++        return 0;
++    }
++#ifndef OPENSSL_NO_ENGINE
++    /* Make sure it's safe to copy a digest context using an ENGINE */
++    if (in->engine && !ENGINE_init(in->engine)) {
++        EVPerr(EVP_F_EVP_MD_CTX_COPY_EX, ERR_R_ENGINE_LIB);
++        return 0;
++    }
++#endif
++
++    if (out->digest == in->digest) {
++        tmp_buf = out->md_data;
++        EVP_MD_CTX_set_flags(out, EVP_MD_CTX_FLAG_REUSE);
++    } else
++        tmp_buf = NULL;
++    EVP_MD_CTX_reset(out);
++    memcpy(out, in, sizeof(*out));
++
++    /* Null these variables, since they are getting fixed up
++     * properly below.  Anything else may cause a memleak and/or
++     * double free if any of the memory allocations below fail
++     */
++    out->md_data = NULL;
++    out->pctx = NULL;
++
++    if (in->md_data && out->digest->ctx_size) {
++        if (tmp_buf)
++            out->md_data = tmp_buf;
++        else {
++            out->md_data = OPENSSL_malloc(out->digest->ctx_size);
++            if (out->md_data == NULL) {
++                EVPerr(EVP_F_EVP_MD_CTX_COPY_EX, ERR_R_MALLOC_FAILURE);
++                return 0;
++            }
++        }
++        memcpy(out->md_data, in->md_data, out->digest->ctx_size);
++    }
++
++    out->update = in->update;
++
++    if (in->pctx) {
++        out->pctx = EVP_PKEY_CTX_dup(in->pctx);
++        if (!out->pctx) {
++            EVP_MD_CTX_reset(out);
++            return 0;
++        }
++    }
++
++    if (out->digest->copy)
++        return out->digest->copy(out, in);
++
++    return 1;
++}
++
++int EVP_Digest(const void *data, size_t count,
++               unsigned char *md, unsigned int *size, const EVP_MD *type,
++               ENGINE *impl)
++{
++    EVP_MD_CTX *ctx = EVP_MD_CTX_new();
++    int ret;
++
++    if (ctx == NULL)
++        return 0;
++    EVP_MD_CTX_set_flags(ctx, EVP_MD_CTX_FLAG_ONESHOT);
++    ret = EVP_DigestInit_ex(ctx, type, impl)
++        && EVP_DigestUpdate(ctx, data, count)
++        && EVP_DigestFinal_ex(ctx, md, size);
++    EVP_MD_CTX_free(ctx);
++
++    return ret;
++}
++
++int EVP_MD_CTX_ctrl(EVP_MD_CTX *ctx, int cmd, int p1, void *p2)
++{
++    if (ctx->digest && ctx->digest->md_ctrl) {
++        int ret = ctx->digest->md_ctrl(ctx, cmd, p1, p2);
++        if (ret <= 0)
++            return 0;
++        return 1;
++    }
++    return 0;
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/evp/e_aes.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/evp/e_aes.c
+new file mode 100644
+index 0000000..17822f2
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/evp/e_aes.c
+@@ -0,0 +1,2702 @@
++/*
++ * Copyright 2001-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include 
++#include 
++#include 
++#include 
++#include 
++#include 
++#include "internal/evp_int.h"
++#include "modes_lcl.h"
++#include 
++#include "evp_locl.h"
++
++typedef struct {
++    union {
++        double align;
++        AES_KEY ks;
++    } ks;
++    block128_f block;
++    union {
++        cbc128_f cbc;
++        ctr128_f ctr;
++    } stream;
++} EVP_AES_KEY;
++
++typedef struct {
++    union {
++        double align;
++        AES_KEY ks;
++    } ks;                       /* AES key schedule to use */
++    int key_set;                /* Set if key initialised */
++    int iv_set;                 /* Set if an iv is set */
++    GCM128_CONTEXT gcm;
++    unsigned char *iv;          /* Temporary IV store */
++    int ivlen;                  /* IV length */
++    int taglen;
++    int iv_gen;                 /* It is OK to generate IVs */
++    int tls_aad_len;            /* TLS AAD length */
++    ctr128_f ctr;
++} EVP_AES_GCM_CTX;
++
++typedef struct {
++    union {
++        double align;
++        AES_KEY ks;
++    } ks1, ks2;                 /* AES key schedules to use */
++    XTS128_CONTEXT xts;
++    void (*stream) (const unsigned char *in,
++                    unsigned char *out, size_t length,
++                    const AES_KEY *key1, const AES_KEY *key2,
++                    const unsigned char iv[16]);
++} EVP_AES_XTS_CTX;
++
++typedef struct {
++    union {
++        double align;
++        AES_KEY ks;
++    } ks;                       /* AES key schedule to use */
++    int key_set;                /* Set if key initialised */
++    int iv_set;                 /* Set if an iv is set */
++    int tag_set;                /* Set if tag is valid */
++    int len_set;                /* Set if message length set */
++    int L, M;                   /* L and M parameters from RFC3610 */
++    int tls_aad_len;            /* TLS AAD length */
++    CCM128_CONTEXT ccm;
++    ccm128_f str;
++} EVP_AES_CCM_CTX;
++
++#ifndef OPENSSL_NO_OCB
++typedef struct {
++    union {
++        double align;
++        AES_KEY ks;
++    } ksenc;                    /* AES key schedule to use for encryption */
++    union {
++        double align;
++        AES_KEY ks;
++    } ksdec;                    /* AES key schedule to use for decryption */
++    int key_set;                /* Set if key initialised */
++    int iv_set;                 /* Set if an iv is set */
++    OCB128_CONTEXT ocb;
++    unsigned char *iv;          /* Temporary IV store */
++    unsigned char tag[16];
++    unsigned char data_buf[16]; /* Store partial data blocks */
++    unsigned char aad_buf[16];  /* Store partial AAD blocks */
++    int data_buf_len;
++    int aad_buf_len;
++    int ivlen;                  /* IV length */
++    int taglen;
++} EVP_AES_OCB_CTX;
++#endif
++
++#define MAXBITCHUNK     ((size_t)1<<(sizeof(size_t)*8-4))
++
++#ifdef VPAES_ASM
++int vpaes_set_encrypt_key(const unsigned char *userKey, int bits,
++                          AES_KEY *key);
++int vpaes_set_decrypt_key(const unsigned char *userKey, int bits,
++                          AES_KEY *key);
++
++void vpaes_encrypt(const unsigned char *in, unsigned char *out,
++                   const AES_KEY *key);
++void vpaes_decrypt(const unsigned char *in, unsigned char *out,
++                   const AES_KEY *key);
++
++void vpaes_cbc_encrypt(const unsigned char *in,
++                       unsigned char *out,
++                       size_t length,
++                       const AES_KEY *key, unsigned char *ivec, int enc);
++#endif
++#ifdef BSAES_ASM
++void bsaes_cbc_encrypt(const unsigned char *in, unsigned char *out,
++                       size_t length, const AES_KEY *key,
++                       unsigned char ivec[16], int enc);
++void bsaes_ctr32_encrypt_blocks(const unsigned char *in, unsigned char *out,
++                                size_t len, const AES_KEY *key,
++                                const unsigned char ivec[16]);
++void bsaes_xts_encrypt(const unsigned char *inp, unsigned char *out,
++                       size_t len, const AES_KEY *key1,
++                       const AES_KEY *key2, const unsigned char iv[16]);
++void bsaes_xts_decrypt(const unsigned char *inp, unsigned char *out,
++                       size_t len, const AES_KEY *key1,
++                       const AES_KEY *key2, const unsigned char iv[16]);
++#endif
++#ifdef AES_CTR_ASM
++void AES_ctr32_encrypt(const unsigned char *in, unsigned char *out,
++                       size_t blocks, const AES_KEY *key,
++                       const unsigned char ivec[AES_BLOCK_SIZE]);
++#endif
++#ifdef AES_XTS_ASM
++void AES_xts_encrypt(const char *inp, char *out, size_t len,
++                     const AES_KEY *key1, const AES_KEY *key2,
++                     const unsigned char iv[16]);
++void AES_xts_decrypt(const char *inp, char *out, size_t len,
++                     const AES_KEY *key1, const AES_KEY *key2,
++                     const unsigned char iv[16]);
++#endif
++
++#if defined(OPENSSL_CPUID_OBJ) && (defined(__powerpc__) || defined(__ppc__) || defined(_ARCH_PPC))
++# include "ppc_arch.h"
++# ifdef VPAES_ASM
++#  define VPAES_CAPABLE (OPENSSL_ppccap_P & PPC_ALTIVEC)
++# endif
++# define HWAES_CAPABLE  (OPENSSL_ppccap_P & PPC_CRYPTO207)
++# define HWAES_set_encrypt_key aes_p8_set_encrypt_key
++# define HWAES_set_decrypt_key aes_p8_set_decrypt_key
++# define HWAES_encrypt aes_p8_encrypt
++# define HWAES_decrypt aes_p8_decrypt
++# define HWAES_cbc_encrypt aes_p8_cbc_encrypt
++# define HWAES_ctr32_encrypt_blocks aes_p8_ctr32_encrypt_blocks
++# define HWAES_xts_encrypt aes_p8_xts_encrypt
++# define HWAES_xts_decrypt aes_p8_xts_decrypt
++#endif
++
++#if     defined(AES_ASM) && !defined(I386_ONLY) &&      (  \
++        ((defined(__i386)       || defined(__i386__)    || \
++          defined(_M_IX86)) && defined(OPENSSL_IA32_SSE2))|| \
++        defined(__x86_64)       || defined(__x86_64__)  || \
++        defined(_M_AMD64)       || defined(_M_X64)      )
++
++extern unsigned int OPENSSL_ia32cap_P[];
++
++# ifdef VPAES_ASM
++#  define VPAES_CAPABLE   (OPENSSL_ia32cap_P[1]&(1<<(41-32)))
++# endif
++# ifdef BSAES_ASM
++#  define BSAES_CAPABLE   (OPENSSL_ia32cap_P[1]&(1<<(41-32)))
++# endif
++/*
++ * AES-NI section
++ */
++# define AESNI_CAPABLE   (OPENSSL_ia32cap_P[1]&(1<<(57-32)))
++
++int aesni_set_encrypt_key(const unsigned char *userKey, int bits,
++                          AES_KEY *key);
++int aesni_set_decrypt_key(const unsigned char *userKey, int bits,
++                          AES_KEY *key);
++
++void aesni_encrypt(const unsigned char *in, unsigned char *out,
++                   const AES_KEY *key);
++void aesni_decrypt(const unsigned char *in, unsigned char *out,
++                   const AES_KEY *key);
++
++void aesni_ecb_encrypt(const unsigned char *in,
++                       unsigned char *out,
++                       size_t length, const AES_KEY *key, int enc);
++void aesni_cbc_encrypt(const unsigned char *in,
++                       unsigned char *out,
++                       size_t length,
++                       const AES_KEY *key, unsigned char *ivec, int enc);
++
++void aesni_ctr32_encrypt_blocks(const unsigned char *in,
++                                unsigned char *out,
++                                size_t blocks,
++                                const void *key, const unsigned char *ivec);
++
++void aesni_xts_encrypt(const unsigned char *in,
++                       unsigned char *out,
++                       size_t length,
++                       const AES_KEY *key1, const AES_KEY *key2,
++                       const unsigned char iv[16]);
++
++void aesni_xts_decrypt(const unsigned char *in,
++                       unsigned char *out,
++                       size_t length,
++                       const AES_KEY *key1, const AES_KEY *key2,
++                       const unsigned char iv[16]);
++
++void aesni_ccm64_encrypt_blocks(const unsigned char *in,
++                                unsigned char *out,
++                                size_t blocks,
++                                const void *key,
++                                const unsigned char ivec[16],
++                                unsigned char cmac[16]);
++
++void aesni_ccm64_decrypt_blocks(const unsigned char *in,
++                                unsigned char *out,
++                                size_t blocks,
++                                const void *key,
++                                const unsigned char ivec[16],
++                                unsigned char cmac[16]);
++
++# if defined(__x86_64) || defined(__x86_64__) || defined(_M_AMD64) || defined(_M_X64)
++size_t aesni_gcm_encrypt(const unsigned char *in,
++                         unsigned char *out,
++                         size_t len,
++                         const void *key, unsigned char ivec[16], u64 *Xi);
++#  define AES_gcm_encrypt aesni_gcm_encrypt
++size_t aesni_gcm_decrypt(const unsigned char *in,
++                         unsigned char *out,
++                         size_t len,
++                         const void *key, unsigned char ivec[16], u64 *Xi);
++#  define AES_gcm_decrypt aesni_gcm_decrypt
++void gcm_ghash_avx(u64 Xi[2], const u128 Htable[16], const u8 *in,
++                   size_t len);
++#  define AES_GCM_ASM(gctx)       (gctx->ctr==aesni_ctr32_encrypt_blocks && \
++                                 gctx->gcm.ghash==gcm_ghash_avx)
++#  define AES_GCM_ASM2(gctx)      (gctx->gcm.block==(block128_f)aesni_encrypt && \
++                                 gctx->gcm.ghash==gcm_ghash_avx)
++#  undef AES_GCM_ASM2          /* minor size optimization */
++# endif
++
++static int aesni_init_key(EVP_CIPHER_CTX *ctx, const unsigned char *key,
++                          const unsigned char *iv, int enc)
++{
++    int ret, mode;
++    EVP_AES_KEY *dat = EVP_C_DATA(EVP_AES_KEY,ctx);
++
++    mode = EVP_CIPHER_CTX_mode(ctx);
++    if ((mode == EVP_CIPH_ECB_MODE || mode == EVP_CIPH_CBC_MODE)
++        && !enc) {
++        ret = aesni_set_decrypt_key(key, EVP_CIPHER_CTX_key_length(ctx) * 8,
++                                    &dat->ks.ks);
++        dat->block = (block128_f) aesni_decrypt;
++        dat->stream.cbc = mode == EVP_CIPH_CBC_MODE ?
++            (cbc128_f) aesni_cbc_encrypt : NULL;
++    } else {
++        ret = aesni_set_encrypt_key(key, EVP_CIPHER_CTX_key_length(ctx) * 8,
++                                    &dat->ks.ks);
++        dat->block = (block128_f) aesni_encrypt;
++        if (mode == EVP_CIPH_CBC_MODE)
++            dat->stream.cbc = (cbc128_f) aesni_cbc_encrypt;
++        else if (mode == EVP_CIPH_CTR_MODE)
++            dat->stream.ctr = (ctr128_f) aesni_ctr32_encrypt_blocks;
++        else
++            dat->stream.cbc = NULL;
++    }
++
++    if (ret < 0) {
++        EVPerr(EVP_F_AESNI_INIT_KEY, EVP_R_AES_KEY_SETUP_FAILED);
++        return 0;
++    }
++
++    return 1;
++}
++
++static int aesni_cbc_cipher(EVP_CIPHER_CTX *ctx, unsigned char *out,
++                            const unsigned char *in, size_t len)
++{
++    aesni_cbc_encrypt(in, out, len, &EVP_C_DATA(EVP_AES_KEY,ctx)->ks.ks,
++                      EVP_CIPHER_CTX_iv_noconst(ctx),
++                      EVP_CIPHER_CTX_encrypting(ctx));
++
++    return 1;
++}
++
++static int aesni_ecb_cipher(EVP_CIPHER_CTX *ctx, unsigned char *out,
++                            const unsigned char *in, size_t len)
++{
++    size_t bl = EVP_CIPHER_CTX_block_size(ctx);
++
++    if (len < bl)
++        return 1;
++
++    aesni_ecb_encrypt(in, out, len, &EVP_C_DATA(EVP_AES_KEY,ctx)->ks.ks,
++                      EVP_CIPHER_CTX_encrypting(ctx));
++
++    return 1;
++}
++
++# define aesni_ofb_cipher aes_ofb_cipher
++static int aesni_ofb_cipher(EVP_CIPHER_CTX *ctx, unsigned char *out,
++                            const unsigned char *in, size_t len);
++
++# define aesni_cfb_cipher aes_cfb_cipher
++static int aesni_cfb_cipher(EVP_CIPHER_CTX *ctx, unsigned char *out,
++                            const unsigned char *in, size_t len);
++
++# define aesni_cfb8_cipher aes_cfb8_cipher
++static int aesni_cfb8_cipher(EVP_CIPHER_CTX *ctx, unsigned char *out,
++                             const unsigned char *in, size_t len);
++
++# define aesni_cfb1_cipher aes_cfb1_cipher
++static int aesni_cfb1_cipher(EVP_CIPHER_CTX *ctx, unsigned char *out,
++                             const unsigned char *in, size_t len);
++
++# define aesni_ctr_cipher aes_ctr_cipher
++static int aesni_ctr_cipher(EVP_CIPHER_CTX *ctx, unsigned char *out,
++                            const unsigned char *in, size_t len);
++
++static int aesni_gcm_init_key(EVP_CIPHER_CTX *ctx, const unsigned char *key,
++                              const unsigned char *iv, int enc)
++{
++    EVP_AES_GCM_CTX *gctx = EVP_C_DATA(EVP_AES_GCM_CTX,ctx);
++    if (!iv && !key)
++        return 1;
++    if (key) {
++        aesni_set_encrypt_key(key, EVP_CIPHER_CTX_key_length(ctx) * 8,
++                              &gctx->ks.ks);
++        CRYPTO_gcm128_init(&gctx->gcm, &gctx->ks, (block128_f) aesni_encrypt);
++        gctx->ctr = (ctr128_f) aesni_ctr32_encrypt_blocks;
++        /*
++         * If we have an iv can set it directly, otherwise use saved IV.
++         */
++        if (iv == NULL && gctx->iv_set)
++            iv = gctx->iv;
++        if (iv) {
++            CRYPTO_gcm128_setiv(&gctx->gcm, iv, gctx->ivlen);
++            gctx->iv_set = 1;
++        }
++        gctx->key_set = 1;
++    } else {
++        /* If key set use IV, otherwise copy */
++        if (gctx->key_set)
++            CRYPTO_gcm128_setiv(&gctx->gcm, iv, gctx->ivlen);
++        else
++            memcpy(gctx->iv, iv, gctx->ivlen);
++        gctx->iv_set = 1;
++        gctx->iv_gen = 0;
++    }
++    return 1;
++}
++
++# define aesni_gcm_cipher aes_gcm_cipher
++static int aesni_gcm_cipher(EVP_CIPHER_CTX *ctx, unsigned char *out,
++                            const unsigned char *in, size_t len);
++
++static int aesni_xts_init_key(EVP_CIPHER_CTX *ctx, const unsigned char *key,
++                              const unsigned char *iv, int enc)
++{
++    EVP_AES_XTS_CTX *xctx = EVP_C_DATA(EVP_AES_XTS_CTX,ctx);
++    if (!iv && !key)
++        return 1;
++
++    if (key) {
++        /* key_len is two AES keys */
++        if (enc) {
++            aesni_set_encrypt_key(key, EVP_CIPHER_CTX_key_length(ctx) * 4,
++                                  &xctx->ks1.ks);
++            xctx->xts.block1 = (block128_f) aesni_encrypt;
++            xctx->stream = aesni_xts_encrypt;
++        } else {
++            aesni_set_decrypt_key(key, EVP_CIPHER_CTX_key_length(ctx) * 4,
++                                  &xctx->ks1.ks);
++            xctx->xts.block1 = (block128_f) aesni_decrypt;
++            xctx->stream = aesni_xts_decrypt;
++        }
++
++        aesni_set_encrypt_key(key + EVP_CIPHER_CTX_key_length(ctx) / 2,
++                              EVP_CIPHER_CTX_key_length(ctx) * 4,
++                              &xctx->ks2.ks);
++        xctx->xts.block2 = (block128_f) aesni_encrypt;
++
++        xctx->xts.key1 = &xctx->ks1;
++    }
++
++    if (iv) {
++        xctx->xts.key2 = &xctx->ks2;
++        memcpy(EVP_CIPHER_CTX_iv_noconst(ctx), iv, 16);
++    }
++
++    return 1;
++}
++
++# define aesni_xts_cipher aes_xts_cipher
++static int aesni_xts_cipher(EVP_CIPHER_CTX *ctx, unsigned char *out,
++                            const unsigned char *in, size_t len);
++
++static int aesni_ccm_init_key(EVP_CIPHER_CTX *ctx, const unsigned char *key,
++                              const unsigned char *iv, int enc)
++{
++    EVP_AES_CCM_CTX *cctx = EVP_C_DATA(EVP_AES_CCM_CTX,ctx);
++    if (!iv && !key)
++        return 1;
++    if (key) {
++        aesni_set_encrypt_key(key, EVP_CIPHER_CTX_key_length(ctx) * 8,
++                              &cctx->ks.ks);
++        CRYPTO_ccm128_init(&cctx->ccm, cctx->M, cctx->L,
++                           &cctx->ks, (block128_f) aesni_encrypt);
++        cctx->str = enc ? (ccm128_f) aesni_ccm64_encrypt_blocks :
++            (ccm128_f) aesni_ccm64_decrypt_blocks;
++        cctx->key_set = 1;
++    }
++    if (iv) {
++        memcpy(EVP_CIPHER_CTX_iv_noconst(ctx), iv, 15 - cctx->L);
++        cctx->iv_set = 1;
++    }
++    return 1;
++}
++
++# define aesni_ccm_cipher aes_ccm_cipher
++static int aesni_ccm_cipher(EVP_CIPHER_CTX *ctx, unsigned char *out,
++                            const unsigned char *in, size_t len);
++
++# ifndef OPENSSL_NO_OCB
++void aesni_ocb_encrypt(const unsigned char *in, unsigned char *out,
++                       size_t blocks, const void *key,
++                       size_t start_block_num,
++                       unsigned char offset_i[16],
++                       const unsigned char L_[][16],
++                       unsigned char checksum[16]);
++void aesni_ocb_decrypt(const unsigned char *in, unsigned char *out,
++                       size_t blocks, const void *key,
++                       size_t start_block_num,
++                       unsigned char offset_i[16],
++                       const unsigned char L_[][16],
++                       unsigned char checksum[16]);
++
++static int aesni_ocb_init_key(EVP_CIPHER_CTX *ctx, const unsigned char *key,
++                              const unsigned char *iv, int enc)
++{
++    EVP_AES_OCB_CTX *octx = EVP_C_DATA(EVP_AES_OCB_CTX,ctx);
++    if (!iv && !key)
++        return 1;
++    if (key) {
++        do {
++            /*
++             * We set both the encrypt and decrypt key here because decrypt
++             * needs both. We could possibly optimise to remove setting the
++             * decrypt for an encryption operation.
++             */
++            aesni_set_encrypt_key(key, EVP_CIPHER_CTX_key_length(ctx) * 8,
++                                  &octx->ksenc.ks);
++            aesni_set_decrypt_key(key, EVP_CIPHER_CTX_key_length(ctx) * 8,
++                                  &octx->ksdec.ks);
++            if (!CRYPTO_ocb128_init(&octx->ocb,
++                                    &octx->ksenc.ks, &octx->ksdec.ks,
++                                    (block128_f) aesni_encrypt,
++                                    (block128_f) aesni_decrypt,
++                                    enc ? aesni_ocb_encrypt
++                                        : aesni_ocb_decrypt))
++                return 0;
++        }
++        while (0);
++
++        /*
++         * If we have an iv we can set it directly, otherwise use saved IV.
++         */
++        if (iv == NULL && octx->iv_set)
++            iv = octx->iv;
++        if (iv) {
++            if (CRYPTO_ocb128_setiv(&octx->ocb, iv, octx->ivlen, octx->taglen)
++                != 1)
++                return 0;
++            octx->iv_set = 1;
++        }
++        octx->key_set = 1;
++    } else {
++        /* If key set use IV, otherwise copy */
++        if (octx->key_set)
++            CRYPTO_ocb128_setiv(&octx->ocb, iv, octx->ivlen, octx->taglen);
++        else
++            memcpy(octx->iv, iv, octx->ivlen);
++        octx->iv_set = 1;
++    }
++    return 1;
++}
++
++#  define aesni_ocb_cipher aes_ocb_cipher
++static int aesni_ocb_cipher(EVP_CIPHER_CTX *ctx, unsigned char *out,
++                            const unsigned char *in, size_t len);
++# endif                        /* OPENSSL_NO_OCB */
++
++# define BLOCK_CIPHER_generic(nid,keylen,blocksize,ivlen,nmode,mode,MODE,flags) \
++static const EVP_CIPHER aesni_##keylen##_##mode = { \
++        nid##_##keylen##_##nmode,blocksize,keylen/8,ivlen, \
++        flags|EVP_CIPH_##MODE##_MODE,   \
++        aesni_init_key,                 \
++        aesni_##mode##_cipher,          \
++        NULL,                           \
++        sizeof(EVP_AES_KEY),            \
++        NULL,NULL,NULL,NULL }; \
++static const EVP_CIPHER aes_##keylen##_##mode = { \
++        nid##_##keylen##_##nmode,blocksize,     \
++        keylen/8,ivlen, \
++        flags|EVP_CIPH_##MODE##_MODE,   \
++        aes_init_key,                   \
++        aes_##mode##_cipher,            \
++        NULL,                           \
++        sizeof(EVP_AES_KEY),            \
++        NULL,NULL,NULL,NULL }; \
++const EVP_CIPHER *EVP_aes_##keylen##_##mode(void) \
++{ return AESNI_CAPABLE?&aesni_##keylen##_##mode:&aes_##keylen##_##mode; }
++
++# define BLOCK_CIPHER_custom(nid,keylen,blocksize,ivlen,mode,MODE,flags) \
++static const EVP_CIPHER aesni_##keylen##_##mode = { \
++        nid##_##keylen##_##mode,blocksize, \
++        (EVP_CIPH_##MODE##_MODE==EVP_CIPH_XTS_MODE?2:1)*keylen/8, ivlen, \
++        flags|EVP_CIPH_##MODE##_MODE,   \
++        aesni_##mode##_init_key,        \
++        aesni_##mode##_cipher,          \
++        aes_##mode##_cleanup,           \
++        sizeof(EVP_AES_##MODE##_CTX),   \
++        NULL,NULL,aes_##mode##_ctrl,NULL }; \
++static const EVP_CIPHER aes_##keylen##_##mode = { \
++        nid##_##keylen##_##mode,blocksize, \
++        (EVP_CIPH_##MODE##_MODE==EVP_CIPH_XTS_MODE?2:1)*keylen/8, ivlen, \
++        flags|EVP_CIPH_##MODE##_MODE,   \
++        aes_##mode##_init_key,          \
++        aes_##mode##_cipher,            \
++        aes_##mode##_cleanup,           \
++        sizeof(EVP_AES_##MODE##_CTX),   \
++        NULL,NULL,aes_##mode##_ctrl,NULL }; \
++const EVP_CIPHER *EVP_aes_##keylen##_##mode(void) \
++{ return AESNI_CAPABLE?&aesni_##keylen##_##mode:&aes_##keylen##_##mode; }
++
++#elif   defined(AES_ASM) && (defined(__sparc) || defined(__sparc__))
++
++# include "sparc_arch.h"
++
++extern unsigned int OPENSSL_sparcv9cap_P[];
++
++/*
++ * Initial Fujitsu SPARC64 X support
++ */
++# define HWAES_CAPABLE           (OPENSSL_sparcv9cap_P[0] & SPARCV9_FJAESX)
++# define HWAES_set_encrypt_key aes_fx_set_encrypt_key
++# define HWAES_set_decrypt_key aes_fx_set_decrypt_key
++# define HWAES_encrypt aes_fx_encrypt
++# define HWAES_decrypt aes_fx_decrypt
++# define HWAES_cbc_encrypt aes_fx_cbc_encrypt
++# define HWAES_ctr32_encrypt_blocks aes_fx_ctr32_encrypt_blocks
++
++# define SPARC_AES_CAPABLE       (OPENSSL_sparcv9cap_P[1] & CFR_AES)
++
++void aes_t4_set_encrypt_key(const unsigned char *key, int bits, AES_KEY *ks);
++void aes_t4_set_decrypt_key(const unsigned char *key, int bits, AES_KEY *ks);
++void aes_t4_encrypt(const unsigned char *in, unsigned char *out,
++                    const AES_KEY *key);
++void aes_t4_decrypt(const unsigned char *in, unsigned char *out,
++                    const AES_KEY *key);
++/*
++ * Key-length specific subroutines were chosen for following reason.
++ * Each SPARC T4 core can execute up to 8 threads which share core's
++ * resources. Loading as much key material to registers allows to
++ * minimize references to shared memory interface, as well as amount
++ * of instructions in inner loops [much needed on T4]. But then having
++ * non-key-length specific routines would require conditional branches
++ * either in inner loops or on subroutines' entries. Former is hardly
++ * acceptable, while latter means code size increase to size occupied
++ * by multiple key-length specific subroutines, so why fight?
++ */
++void aes128_t4_cbc_encrypt(const unsigned char *in, unsigned char *out,
++                           size_t len, const AES_KEY *key,
++                           unsigned char *ivec);
++void aes128_t4_cbc_decrypt(const unsigned char *in, unsigned char *out,
++                           size_t len, const AES_KEY *key,
++                           unsigned char *ivec);
++void aes192_t4_cbc_encrypt(const unsigned char *in, unsigned char *out,
++                           size_t len, const AES_KEY *key,
++                           unsigned char *ivec);
++void aes192_t4_cbc_decrypt(const unsigned char *in, unsigned char *out,
++                           size_t len, const AES_KEY *key,
++                           unsigned char *ivec);
++void aes256_t4_cbc_encrypt(const unsigned char *in, unsigned char *out,
++                           size_t len, const AES_KEY *key,
++                           unsigned char *ivec);
++void aes256_t4_cbc_decrypt(const unsigned char *in, unsigned char *out,
++                           size_t len, const AES_KEY *key,
++                           unsigned char *ivec);
++void aes128_t4_ctr32_encrypt(const unsigned char *in, unsigned char *out,
++                             size_t blocks, const AES_KEY *key,
++                             unsigned char *ivec);
++void aes192_t4_ctr32_encrypt(const unsigned char *in, unsigned char *out,
++                             size_t blocks, const AES_KEY *key,
++                             unsigned char *ivec);
++void aes256_t4_ctr32_encrypt(const unsigned char *in, unsigned char *out,
++                             size_t blocks, const AES_KEY *key,
++                             unsigned char *ivec);
++void aes128_t4_xts_encrypt(const unsigned char *in, unsigned char *out,
++                           size_t blocks, const AES_KEY *key1,
++                           const AES_KEY *key2, const unsigned char *ivec);
++void aes128_t4_xts_decrypt(const unsigned char *in, unsigned char *out,
++                           size_t blocks, const AES_KEY *key1,
++                           const AES_KEY *key2, const unsigned char *ivec);
++void aes256_t4_xts_encrypt(const unsigned char *in, unsigned char *out,
++                           size_t blocks, const AES_KEY *key1,
++                           const AES_KEY *key2, const unsigned char *ivec);
++void aes256_t4_xts_decrypt(const unsigned char *in, unsigned char *out,
++                           size_t blocks, const AES_KEY *key1,
++                           const AES_KEY *key2, const unsigned char *ivec);
++
++static int aes_t4_init_key(EVP_CIPHER_CTX *ctx, const unsigned char *key,
++                           const unsigned char *iv, int enc)
++{
++    int ret, mode, bits;
++    EVP_AES_KEY *dat = EVP_C_DATA(EVP_AES_KEY,ctx);
++
++    mode = EVP_CIPHER_CTX_mode(ctx);
++    bits = EVP_CIPHER_CTX_key_length(ctx) * 8;
++    if ((mode == EVP_CIPH_ECB_MODE || mode == EVP_CIPH_CBC_MODE)
++        && !enc) {
++        ret = 0;
++        aes_t4_set_decrypt_key(key, bits, &dat->ks.ks);
++        dat->block = (block128_f) aes_t4_decrypt;
++        switch (bits) {
++        case 128:
++            dat->stream.cbc = mode == EVP_CIPH_CBC_MODE ?
++                (cbc128_f) aes128_t4_cbc_decrypt : NULL;
++            break;
++        case 192:
++            dat->stream.cbc = mode == EVP_CIPH_CBC_MODE ?
++                (cbc128_f) aes192_t4_cbc_decrypt : NULL;
++            break;
++        case 256:
++            dat->stream.cbc = mode == EVP_CIPH_CBC_MODE ?
++                (cbc128_f) aes256_t4_cbc_decrypt : NULL;
++            break;
++        default:
++            ret = -1;
++        }
++    } else {
++        ret = 0;
++        aes_t4_set_encrypt_key(key, bits, &dat->ks.ks);
++        dat->block = (block128_f) aes_t4_encrypt;
++        switch (bits) {
++        case 128:
++            if (mode == EVP_CIPH_CBC_MODE)
++                dat->stream.cbc = (cbc128_f) aes128_t4_cbc_encrypt;
++            else if (mode == EVP_CIPH_CTR_MODE)
++                dat->stream.ctr = (ctr128_f) aes128_t4_ctr32_encrypt;
++            else
++                dat->stream.cbc = NULL;
++            break;
++        case 192:
++            if (mode == EVP_CIPH_CBC_MODE)
++                dat->stream.cbc = (cbc128_f) aes192_t4_cbc_encrypt;
++            else if (mode == EVP_CIPH_CTR_MODE)
++                dat->stream.ctr = (ctr128_f) aes192_t4_ctr32_encrypt;
++            else
++                dat->stream.cbc = NULL;
++            break;
++        case 256:
++            if (mode == EVP_CIPH_CBC_MODE)
++                dat->stream.cbc = (cbc128_f) aes256_t4_cbc_encrypt;
++            else if (mode == EVP_CIPH_CTR_MODE)
++                dat->stream.ctr = (ctr128_f) aes256_t4_ctr32_encrypt;
++            else
++                dat->stream.cbc = NULL;
++            break;
++        default:
++            ret = -1;
++        }
++    }
++
++    if (ret < 0) {
++        EVPerr(EVP_F_AES_T4_INIT_KEY, EVP_R_AES_KEY_SETUP_FAILED);
++        return 0;
++    }
++
++    return 1;
++}
++
++# define aes_t4_cbc_cipher aes_cbc_cipher
++static int aes_t4_cbc_cipher(EVP_CIPHER_CTX *ctx, unsigned char *out,
++                             const unsigned char *in, size_t len);
++
++# define aes_t4_ecb_cipher aes_ecb_cipher
++static int aes_t4_ecb_cipher(EVP_CIPHER_CTX *ctx, unsigned char *out,
++                             const unsigned char *in, size_t len);
++
++# define aes_t4_ofb_cipher aes_ofb_cipher
++static int aes_t4_ofb_cipher(EVP_CIPHER_CTX *ctx, unsigned char *out,
++                             const unsigned char *in, size_t len);
++
++# define aes_t4_cfb_cipher aes_cfb_cipher
++static int aes_t4_cfb_cipher(EVP_CIPHER_CTX *ctx, unsigned char *out,
++                             const unsigned char *in, size_t len);
++
++# define aes_t4_cfb8_cipher aes_cfb8_cipher
++static int aes_t4_cfb8_cipher(EVP_CIPHER_CTX *ctx, unsigned char *out,
++                              const unsigned char *in, size_t len);
++
++# define aes_t4_cfb1_cipher aes_cfb1_cipher
++static int aes_t4_cfb1_cipher(EVP_CIPHER_CTX *ctx, unsigned char *out,
++                              const unsigned char *in, size_t len);
++
++# define aes_t4_ctr_cipher aes_ctr_cipher
++static int aes_t4_ctr_cipher(EVP_CIPHER_CTX *ctx, unsigned char *out,
++                             const unsigned char *in, size_t len);
++
++static int aes_t4_gcm_init_key(EVP_CIPHER_CTX *ctx, const unsigned char *key,
++                               const unsigned char *iv, int enc)
++{
++    EVP_AES_GCM_CTX *gctx = EVP_C_DATA(EVP_AES_GCM_CTX,ctx);
++    if (!iv && !key)
++        return 1;
++    if (key) {
++        int bits = EVP_CIPHER_CTX_key_length(ctx) * 8;
++        aes_t4_set_encrypt_key(key, bits, &gctx->ks.ks);
++        CRYPTO_gcm128_init(&gctx->gcm, &gctx->ks,
++                           (block128_f) aes_t4_encrypt);
++        switch (bits) {
++        case 128:
++            gctx->ctr = (ctr128_f) aes128_t4_ctr32_encrypt;
++            break;
++        case 192:
++            gctx->ctr = (ctr128_f) aes192_t4_ctr32_encrypt;
++            break;
++        case 256:
++            gctx->ctr = (ctr128_f) aes256_t4_ctr32_encrypt;
++            break;
++        default:
++            return 0;
++        }
++        /*
++         * If we have an iv can set it directly, otherwise use saved IV.
++         */
++        if (iv == NULL && gctx->iv_set)
++            iv = gctx->iv;
++        if (iv) {
++            CRYPTO_gcm128_setiv(&gctx->gcm, iv, gctx->ivlen);
++            gctx->iv_set = 1;
++        }
++        gctx->key_set = 1;
++    } else {
++        /* If key set use IV, otherwise copy */
++        if (gctx->key_set)
++            CRYPTO_gcm128_setiv(&gctx->gcm, iv, gctx->ivlen);
++        else
++            memcpy(gctx->iv, iv, gctx->ivlen);
++        gctx->iv_set = 1;
++        gctx->iv_gen = 0;
++    }
++    return 1;
++}
++
++# define aes_t4_gcm_cipher aes_gcm_cipher
++static int aes_t4_gcm_cipher(EVP_CIPHER_CTX *ctx, unsigned char *out,
++                             const unsigned char *in, size_t len);
++
++static int aes_t4_xts_init_key(EVP_CIPHER_CTX *ctx, const unsigned char *key,
++                               const unsigned char *iv, int enc)
++{
++    EVP_AES_XTS_CTX *xctx = EVP_C_DATA(EVP_AES_XTS_CTX,ctx);
++    if (!iv && !key)
++        return 1;
++
++    if (key) {
++        int bits = EVP_CIPHER_CTX_key_length(ctx) * 4;
++        xctx->stream = NULL;
++        /* key_len is two AES keys */
++        if (enc) {
++            aes_t4_set_encrypt_key(key, bits, &xctx->ks1.ks);
++            xctx->xts.block1 = (block128_f) aes_t4_encrypt;
++            switch (bits) {
++            case 128:
++                xctx->stream = aes128_t4_xts_encrypt;
++                break;
++            case 256:
++                xctx->stream = aes256_t4_xts_encrypt;
++                break;
++            default:
++                return 0;
++            }
++        } else {
++            aes_t4_set_decrypt_key(key, EVP_CIPHER_CTX_key_length(ctx) * 4,
++                                   &xctx->ks1.ks);
++            xctx->xts.block1 = (block128_f) aes_t4_decrypt;
++            switch (bits) {
++            case 128:
++                xctx->stream = aes128_t4_xts_decrypt;
++                break;
++            case 256:
++                xctx->stream = aes256_t4_xts_decrypt;
++                break;
++            default:
++                return 0;
++            }
++        }
++
++        aes_t4_set_encrypt_key(key + EVP_CIPHER_CTX_key_length(ctx) / 2,
++                               EVP_CIPHER_CTX_key_length(ctx) * 4,
++                               &xctx->ks2.ks);
++        xctx->xts.block2 = (block128_f) aes_t4_encrypt;
++
++        xctx->xts.key1 = &xctx->ks1;
++    }
++
++    if (iv) {
++        xctx->xts.key2 = &xctx->ks2;
++        memcpy(EVP_CIPHER_CTX_iv_noconst(ctx), iv, 16);
++    }
++
++    return 1;
++}
++
++# define aes_t4_xts_cipher aes_xts_cipher
++static int aes_t4_xts_cipher(EVP_CIPHER_CTX *ctx, unsigned char *out,
++                             const unsigned char *in, size_t len);
++
++static int aes_t4_ccm_init_key(EVP_CIPHER_CTX *ctx, const unsigned char *key,
++                               const unsigned char *iv, int enc)
++{
++    EVP_AES_CCM_CTX *cctx = EVP_C_DATA(EVP_AES_CCM_CTX,ctx);
++    if (!iv && !key)
++        return 1;
++    if (key) {
++        int bits = EVP_CIPHER_CTX_key_length(ctx) * 8;
++        aes_t4_set_encrypt_key(key, bits, &cctx->ks.ks);
++        CRYPTO_ccm128_init(&cctx->ccm, cctx->M, cctx->L,
++                           &cctx->ks, (block128_f) aes_t4_encrypt);
++        cctx->str = NULL;
++        cctx->key_set = 1;
++    }
++    if (iv) {
++        memcpy(EVP_CIPHER_CTX_iv_noconst(ctx), iv, 15 - cctx->L);
++        cctx->iv_set = 1;
++    }
++    return 1;
++}
++
++# define aes_t4_ccm_cipher aes_ccm_cipher
++static int aes_t4_ccm_cipher(EVP_CIPHER_CTX *ctx, unsigned char *out,
++                             const unsigned char *in, size_t len);
++
++# ifndef OPENSSL_NO_OCB
++static int aes_t4_ocb_init_key(EVP_CIPHER_CTX *ctx, const unsigned char *key,
++                               const unsigned char *iv, int enc)
++{
++    EVP_AES_OCB_CTX *octx = EVP_C_DATA(EVP_AES_OCB_CTX,ctx);
++    if (!iv && !key)
++        return 1;
++    if (key) {
++        do {
++            /*
++             * We set both the encrypt and decrypt key here because decrypt
++             * needs both. We could possibly optimise to remove setting the
++             * decrypt for an encryption operation.
++             */
++            aes_t4_set_encrypt_key(key, EVP_CIPHER_CTX_key_length(ctx) * 8,
++                                   &octx->ksenc.ks);
++            aes_t4_set_decrypt_key(key, EVP_CIPHER_CTX_key_length(ctx) * 8,
++                                   &octx->ksdec.ks);
++            if (!CRYPTO_ocb128_init(&octx->ocb,
++                                    &octx->ksenc.ks, &octx->ksdec.ks,
++                                    (block128_f) aes_t4_encrypt,
++                                    (block128_f) aes_t4_decrypt,
++                                    NULL))
++                return 0;
++        }
++        while (0);
++
++        /*
++         * If we have an iv we can set it directly, otherwise use saved IV.
++         */
++        if (iv == NULL && octx->iv_set)
++            iv = octx->iv;
++        if (iv) {
++            if (CRYPTO_ocb128_setiv(&octx->ocb, iv, octx->ivlen, octx->taglen)
++                != 1)
++                return 0;
++            octx->iv_set = 1;
++        }
++        octx->key_set = 1;
++    } else {
++        /* If key set use IV, otherwise copy */
++        if (octx->key_set)
++            CRYPTO_ocb128_setiv(&octx->ocb, iv, octx->ivlen, octx->taglen);
++        else
++            memcpy(octx->iv, iv, octx->ivlen);
++        octx->iv_set = 1;
++    }
++    return 1;
++}
++
++#  define aes_t4_ocb_cipher aes_ocb_cipher
++static int aes_t4_ocb_cipher(EVP_CIPHER_CTX *ctx, unsigned char *out,
++                             const unsigned char *in, size_t len);
++# endif                        /* OPENSSL_NO_OCB */
++
++# define BLOCK_CIPHER_generic(nid,keylen,blocksize,ivlen,nmode,mode,MODE,flags) \
++static const EVP_CIPHER aes_t4_##keylen##_##mode = { \
++        nid##_##keylen##_##nmode,blocksize,keylen/8,ivlen, \
++        flags|EVP_CIPH_##MODE##_MODE,   \
++        aes_t4_init_key,                \
++        aes_t4_##mode##_cipher,         \
++        NULL,                           \
++        sizeof(EVP_AES_KEY),            \
++        NULL,NULL,NULL,NULL }; \
++static const EVP_CIPHER aes_##keylen##_##mode = { \
++        nid##_##keylen##_##nmode,blocksize,     \
++        keylen/8,ivlen, \
++        flags|EVP_CIPH_##MODE##_MODE,   \
++        aes_init_key,                   \
++        aes_##mode##_cipher,            \
++        NULL,                           \
++        sizeof(EVP_AES_KEY),            \
++        NULL,NULL,NULL,NULL }; \
++const EVP_CIPHER *EVP_aes_##keylen##_##mode(void) \
++{ return SPARC_AES_CAPABLE?&aes_t4_##keylen##_##mode:&aes_##keylen##_##mode; }
++
++# define BLOCK_CIPHER_custom(nid,keylen,blocksize,ivlen,mode,MODE,flags) \
++static const EVP_CIPHER aes_t4_##keylen##_##mode = { \
++        nid##_##keylen##_##mode,blocksize, \
++        (EVP_CIPH_##MODE##_MODE==EVP_CIPH_XTS_MODE?2:1)*keylen/8, ivlen, \
++        flags|EVP_CIPH_##MODE##_MODE,   \
++        aes_t4_##mode##_init_key,       \
++        aes_t4_##mode##_cipher,         \
++        aes_##mode##_cleanup,           \
++        sizeof(EVP_AES_##MODE##_CTX),   \
++        NULL,NULL,aes_##mode##_ctrl,NULL }; \
++static const EVP_CIPHER aes_##keylen##_##mode = { \
++        nid##_##keylen##_##mode,blocksize, \
++        (EVP_CIPH_##MODE##_MODE==EVP_CIPH_XTS_MODE?2:1)*keylen/8, ivlen, \
++        flags|EVP_CIPH_##MODE##_MODE,   \
++        aes_##mode##_init_key,          \
++        aes_##mode##_cipher,            \
++        aes_##mode##_cleanup,           \
++        sizeof(EVP_AES_##MODE##_CTX),   \
++        NULL,NULL,aes_##mode##_ctrl,NULL }; \
++const EVP_CIPHER *EVP_aes_##keylen##_##mode(void) \
++{ return SPARC_AES_CAPABLE?&aes_t4_##keylen##_##mode:&aes_##keylen##_##mode; }
++
++#else
++
++# define BLOCK_CIPHER_generic(nid,keylen,blocksize,ivlen,nmode,mode,MODE,flags) \
++static const EVP_CIPHER aes_##keylen##_##mode = { \
++        nid##_##keylen##_##nmode,blocksize,keylen/8,ivlen, \
++        flags|EVP_CIPH_##MODE##_MODE,   \
++        aes_init_key,                   \
++        aes_##mode##_cipher,            \
++        NULL,                           \
++        sizeof(EVP_AES_KEY),            \
++        NULL,NULL,NULL,NULL }; \
++const EVP_CIPHER *EVP_aes_##keylen##_##mode(void) \
++{ return &aes_##keylen##_##mode; }
++
++# define BLOCK_CIPHER_custom(nid,keylen,blocksize,ivlen,mode,MODE,flags) \
++static const EVP_CIPHER aes_##keylen##_##mode = { \
++        nid##_##keylen##_##mode,blocksize, \
++        (EVP_CIPH_##MODE##_MODE==EVP_CIPH_XTS_MODE?2:1)*keylen/8, ivlen, \
++        flags|EVP_CIPH_##MODE##_MODE,   \
++        aes_##mode##_init_key,          \
++        aes_##mode##_cipher,            \
++        aes_##mode##_cleanup,           \
++        sizeof(EVP_AES_##MODE##_CTX),   \
++        NULL,NULL,aes_##mode##_ctrl,NULL }; \
++const EVP_CIPHER *EVP_aes_##keylen##_##mode(void) \
++{ return &aes_##keylen##_##mode; }
++
++#endif
++
++#if defined(OPENSSL_CPUID_OBJ) && (defined(__arm__) || defined(__arm) || defined(__aarch64__))
++# include "arm_arch.h"
++# if __ARM_MAX_ARCH__>=7
++#  if defined(BSAES_ASM)
++#   define BSAES_CAPABLE (OPENSSL_armcap_P & ARMV7_NEON)
++#  endif
++#  if defined(VPAES_ASM)
++#   define VPAES_CAPABLE (OPENSSL_armcap_P & ARMV7_NEON)
++#  endif
++#  define HWAES_CAPABLE (OPENSSL_armcap_P & ARMV8_AES)
++#  define HWAES_set_encrypt_key aes_v8_set_encrypt_key
++#  define HWAES_set_decrypt_key aes_v8_set_decrypt_key
++#  define HWAES_encrypt aes_v8_encrypt
++#  define HWAES_decrypt aes_v8_decrypt
++#  define HWAES_cbc_encrypt aes_v8_cbc_encrypt
++#  define HWAES_ctr32_encrypt_blocks aes_v8_ctr32_encrypt_blocks
++# endif
++#endif
++
++#if defined(HWAES_CAPABLE)
++int HWAES_set_encrypt_key(const unsigned char *userKey, const int bits,
++                          AES_KEY *key);
++int HWAES_set_decrypt_key(const unsigned char *userKey, const int bits,
++                          AES_KEY *key);
++void HWAES_encrypt(const unsigned char *in, unsigned char *out,
++                   const AES_KEY *key);
++void HWAES_decrypt(const unsigned char *in, unsigned char *out,
++                   const AES_KEY *key);
++void HWAES_cbc_encrypt(const unsigned char *in, unsigned char *out,
++                       size_t length, const AES_KEY *key,
++                       unsigned char *ivec, const int enc);
++void HWAES_ctr32_encrypt_blocks(const unsigned char *in, unsigned char *out,
++                                size_t len, const AES_KEY *key,
++                                const unsigned char ivec[16]);
++void HWAES_xts_encrypt(const unsigned char *inp, unsigned char *out,
++                       size_t len, const AES_KEY *key1,
++                       const AES_KEY *key2, const unsigned char iv[16]);
++void HWAES_xts_decrypt(const unsigned char *inp, unsigned char *out,
++                       size_t len, const AES_KEY *key1,
++                       const AES_KEY *key2, const unsigned char iv[16]);
++#endif
++
++#define BLOCK_CIPHER_generic_pack(nid,keylen,flags)             \
++        BLOCK_CIPHER_generic(nid,keylen,16,16,cbc,cbc,CBC,flags|EVP_CIPH_FLAG_DEFAULT_ASN1)     \
++        BLOCK_CIPHER_generic(nid,keylen,16,0,ecb,ecb,ECB,flags|EVP_CIPH_FLAG_DEFAULT_ASN1)      \
++        BLOCK_CIPHER_generic(nid,keylen,1,16,ofb128,ofb,OFB,flags|EVP_CIPH_FLAG_DEFAULT_ASN1)   \
++        BLOCK_CIPHER_generic(nid,keylen,1,16,cfb128,cfb,CFB,flags|EVP_CIPH_FLAG_DEFAULT_ASN1)   \
++        BLOCK_CIPHER_generic(nid,keylen,1,16,cfb1,cfb1,CFB,flags)       \
++        BLOCK_CIPHER_generic(nid,keylen,1,16,cfb8,cfb8,CFB,flags)       \
++        BLOCK_CIPHER_generic(nid,keylen,1,16,ctr,ctr,CTR,flags)
++
++static int aes_init_key(EVP_CIPHER_CTX *ctx, const unsigned char *key,
++                        const unsigned char *iv, int enc)
++{
++    int ret, mode;
++    EVP_AES_KEY *dat = EVP_C_DATA(EVP_AES_KEY,ctx);
++
++    mode = EVP_CIPHER_CTX_mode(ctx);
++    if ((mode == EVP_CIPH_ECB_MODE || mode == EVP_CIPH_CBC_MODE)
++        && !enc) {
++#ifdef HWAES_CAPABLE
++        if (HWAES_CAPABLE) {
++            ret = HWAES_set_decrypt_key(key,
++                                        EVP_CIPHER_CTX_key_length(ctx) * 8,
++                                        &dat->ks.ks);
++            dat->block = (block128_f) HWAES_decrypt;
++            dat->stream.cbc = NULL;
++# ifdef HWAES_cbc_encrypt
++            if (mode == EVP_CIPH_CBC_MODE)
++                dat->stream.cbc = (cbc128_f) HWAES_cbc_encrypt;
++# endif
++        } else
++#endif
++#ifdef BSAES_CAPABLE
++        if (BSAES_CAPABLE && mode == EVP_CIPH_CBC_MODE) {
++            ret = AES_set_decrypt_key(key, EVP_CIPHER_CTX_key_length(ctx) * 8,
++                                      &dat->ks.ks);
++            dat->block = (block128_f) AES_decrypt;
++            dat->stream.cbc = (cbc128_f) bsaes_cbc_encrypt;
++        } else
++#endif
++#ifdef VPAES_CAPABLE
++        if (VPAES_CAPABLE) {
++            ret = vpaes_set_decrypt_key(key,
++                                        EVP_CIPHER_CTX_key_length(ctx) * 8,
++                                        &dat->ks.ks);
++            dat->block = (block128_f) vpaes_decrypt;
++            dat->stream.cbc = mode == EVP_CIPH_CBC_MODE ?
++                (cbc128_f) vpaes_cbc_encrypt : NULL;
++        } else
++#endif
++        {
++            ret = AES_set_decrypt_key(key,
++                                      EVP_CIPHER_CTX_key_length(ctx) * 8,
++                                      &dat->ks.ks);
++            dat->block = (block128_f) AES_decrypt;
++            dat->stream.cbc = mode == EVP_CIPH_CBC_MODE ?
++                (cbc128_f) AES_cbc_encrypt : NULL;
++        }
++    } else
++#ifdef HWAES_CAPABLE
++    if (HWAES_CAPABLE) {
++        ret = HWAES_set_encrypt_key(key, EVP_CIPHER_CTX_key_length(ctx) * 8,
++                                    &dat->ks.ks);
++        dat->block = (block128_f) HWAES_encrypt;
++        dat->stream.cbc = NULL;
++# ifdef HWAES_cbc_encrypt
++        if (mode == EVP_CIPH_CBC_MODE)
++            dat->stream.cbc = (cbc128_f) HWAES_cbc_encrypt;
++        else
++# endif
++# ifdef HWAES_ctr32_encrypt_blocks
++        if (mode == EVP_CIPH_CTR_MODE)
++            dat->stream.ctr = (ctr128_f) HWAES_ctr32_encrypt_blocks;
++        else
++# endif
++            (void)0;            /* terminate potentially open 'else' */
++    } else
++#endif
++#ifdef BSAES_CAPABLE
++    if (BSAES_CAPABLE && mode == EVP_CIPH_CTR_MODE) {
++        ret = AES_set_encrypt_key(key, EVP_CIPHER_CTX_key_length(ctx) * 8,
++                                  &dat->ks.ks);
++        dat->block = (block128_f) AES_encrypt;
++        dat->stream.ctr = (ctr128_f) bsaes_ctr32_encrypt_blocks;
++    } else
++#endif
++#ifdef VPAES_CAPABLE
++    if (VPAES_CAPABLE) {
++        ret = vpaes_set_encrypt_key(key, EVP_CIPHER_CTX_key_length(ctx) * 8,
++                                    &dat->ks.ks);
++        dat->block = (block128_f) vpaes_encrypt;
++        dat->stream.cbc = mode == EVP_CIPH_CBC_MODE ?
++            (cbc128_f) vpaes_cbc_encrypt : NULL;
++    } else
++#endif
++    {
++        ret = AES_set_encrypt_key(key, EVP_CIPHER_CTX_key_length(ctx) * 8,
++                                  &dat->ks.ks);
++        dat->block = (block128_f) AES_encrypt;
++        dat->stream.cbc = mode == EVP_CIPH_CBC_MODE ?
++            (cbc128_f) AES_cbc_encrypt : NULL;
++#ifdef AES_CTR_ASM
++        if (mode == EVP_CIPH_CTR_MODE)
++            dat->stream.ctr = (ctr128_f) AES_ctr32_encrypt;
++#endif
++    }
++
++    if (ret < 0) {
++        EVPerr(EVP_F_AES_INIT_KEY, EVP_R_AES_KEY_SETUP_FAILED);
++        return 0;
++    }
++
++    return 1;
++}
++
++static int aes_cbc_cipher(EVP_CIPHER_CTX *ctx, unsigned char *out,
++                          const unsigned char *in, size_t len)
++{
++    EVP_AES_KEY *dat = EVP_C_DATA(EVP_AES_KEY,ctx);
++
++    if (dat->stream.cbc)
++        (*dat->stream.cbc) (in, out, len, &dat->ks,
++                            EVP_CIPHER_CTX_iv_noconst(ctx),
++                            EVP_CIPHER_CTX_encrypting(ctx));
++    else if (EVP_CIPHER_CTX_encrypting(ctx))
++        CRYPTO_cbc128_encrypt(in, out, len, &dat->ks,
++                              EVP_CIPHER_CTX_iv_noconst(ctx), dat->block);
++    else
++        CRYPTO_cbc128_decrypt(in, out, len, &dat->ks,
++                              EVP_CIPHER_CTX_iv_noconst(ctx), dat->block);
++
++    return 1;
++}
++
++static int aes_ecb_cipher(EVP_CIPHER_CTX *ctx, unsigned char *out,
++                          const unsigned char *in, size_t len)
++{
++    size_t bl = EVP_CIPHER_CTX_block_size(ctx);
++    size_t i;
++    EVP_AES_KEY *dat = EVP_C_DATA(EVP_AES_KEY,ctx);
++
++    if (len < bl)
++        return 1;
++
++    for (i = 0, len -= bl; i <= len; i += bl)
++        (*dat->block) (in + i, out + i, &dat->ks);
++
++    return 1;
++}
++
++static int aes_ofb_cipher(EVP_CIPHER_CTX *ctx, unsigned char *out,
++                          const unsigned char *in, size_t len)
++{
++    EVP_AES_KEY *dat = EVP_C_DATA(EVP_AES_KEY,ctx);
++
++    int num = EVP_CIPHER_CTX_num(ctx);
++    CRYPTO_ofb128_encrypt(in, out, len, &dat->ks,
++                          EVP_CIPHER_CTX_iv_noconst(ctx), &num, dat->block);
++    EVP_CIPHER_CTX_set_num(ctx, num);
++    return 1;
++}
++
++static int aes_cfb_cipher(EVP_CIPHER_CTX *ctx, unsigned char *out,
++                          const unsigned char *in, size_t len)
++{
++    EVP_AES_KEY *dat = EVP_C_DATA(EVP_AES_KEY,ctx);
++
++    int num = EVP_CIPHER_CTX_num(ctx);
++    CRYPTO_cfb128_encrypt(in, out, len, &dat->ks,
++                          EVP_CIPHER_CTX_iv_noconst(ctx), &num,
++                          EVP_CIPHER_CTX_encrypting(ctx), dat->block);
++    EVP_CIPHER_CTX_set_num(ctx, num);
++    return 1;
++}
++
++static int aes_cfb8_cipher(EVP_CIPHER_CTX *ctx, unsigned char *out,
++                           const unsigned char *in, size_t len)
++{
++    EVP_AES_KEY *dat = EVP_C_DATA(EVP_AES_KEY,ctx);
++
++    int num = EVP_CIPHER_CTX_num(ctx);
++    CRYPTO_cfb128_8_encrypt(in, out, len, &dat->ks,
++                            EVP_CIPHER_CTX_iv_noconst(ctx), &num,
++                            EVP_CIPHER_CTX_encrypting(ctx), dat->block);
++    EVP_CIPHER_CTX_set_num(ctx, num);
++    return 1;
++}
++
++static int aes_cfb1_cipher(EVP_CIPHER_CTX *ctx, unsigned char *out,
++                           const unsigned char *in, size_t len)
++{
++    EVP_AES_KEY *dat = EVP_C_DATA(EVP_AES_KEY,ctx);
++
++    if (EVP_CIPHER_CTX_test_flags(ctx, EVP_CIPH_FLAG_LENGTH_BITS)) {
++        int num = EVP_CIPHER_CTX_num(ctx);
++        CRYPTO_cfb128_1_encrypt(in, out, len, &dat->ks,
++                                EVP_CIPHER_CTX_iv_noconst(ctx), &num,
++                                EVP_CIPHER_CTX_encrypting(ctx), dat->block);
++        EVP_CIPHER_CTX_set_num(ctx, num);
++        return 1;
++    }
++
++    while (len >= MAXBITCHUNK) {
++        int num = EVP_CIPHER_CTX_num(ctx);
++        CRYPTO_cfb128_1_encrypt(in, out, MAXBITCHUNK * 8, &dat->ks,
++                                EVP_CIPHER_CTX_iv_noconst(ctx), &num,
++                                EVP_CIPHER_CTX_encrypting(ctx), dat->block);
++        EVP_CIPHER_CTX_set_num(ctx, num);
++        len -= MAXBITCHUNK;
++    }
++    if (len) {
++        int num = EVP_CIPHER_CTX_num(ctx);
++        CRYPTO_cfb128_1_encrypt(in, out, len * 8, &dat->ks,
++                                EVP_CIPHER_CTX_iv_noconst(ctx), &num,
++                                EVP_CIPHER_CTX_encrypting(ctx), dat->block);
++        EVP_CIPHER_CTX_set_num(ctx, num);
++    }
++
++    return 1;
++}
++
++static int aes_ctr_cipher(EVP_CIPHER_CTX *ctx, unsigned char *out,
++                          const unsigned char *in, size_t len)
++{
++    unsigned int num = EVP_CIPHER_CTX_num(ctx);
++    EVP_AES_KEY *dat = EVP_C_DATA(EVP_AES_KEY,ctx);
++
++    if (dat->stream.ctr)
++        CRYPTO_ctr128_encrypt_ctr32(in, out, len, &dat->ks,
++                                    EVP_CIPHER_CTX_iv_noconst(ctx),
++                                    EVP_CIPHER_CTX_buf_noconst(ctx),
++                                    &num, dat->stream.ctr);
++    else
++        CRYPTO_ctr128_encrypt(in, out, len, &dat->ks,
++                              EVP_CIPHER_CTX_iv_noconst(ctx),
++                              EVP_CIPHER_CTX_buf_noconst(ctx), &num,
++                              dat->block);
++    EVP_CIPHER_CTX_set_num(ctx, num);
++    return 1;
++}
++
++BLOCK_CIPHER_generic_pack(NID_aes, 128, 0)
++    BLOCK_CIPHER_generic_pack(NID_aes, 192, 0)
++    BLOCK_CIPHER_generic_pack(NID_aes, 256, 0)
++
++static int aes_gcm_cleanup(EVP_CIPHER_CTX *c)
++{
++    EVP_AES_GCM_CTX *gctx = EVP_C_DATA(EVP_AES_GCM_CTX,c);
++    if (gctx == NULL)
++        return 0;
++    OPENSSL_cleanse(&gctx->gcm, sizeof(gctx->gcm));
++    if (gctx->iv != EVP_CIPHER_CTX_iv_noconst(c))
++        OPENSSL_free(gctx->iv);
++    return 1;
++}
++
++/* increment counter (64-bit int) by 1 */
++static void ctr64_inc(unsigned char *counter)
++{
++    int n = 8;
++    unsigned char c;
++
++    do {
++        --n;
++        c = counter[n];
++        ++c;
++        counter[n] = c;
++        if (c)
++            return;
++    } while (n);
++}
++
++static int aes_gcm_ctrl(EVP_CIPHER_CTX *c, int type, int arg, void *ptr)
++{
++    EVP_AES_GCM_CTX *gctx = EVP_C_DATA(EVP_AES_GCM_CTX,c);
++    switch (type) {
++    case EVP_CTRL_INIT:
++        gctx->key_set = 0;
++        gctx->iv_set = 0;
++        gctx->ivlen = EVP_CIPHER_CTX_iv_length(c);
++        gctx->iv = EVP_CIPHER_CTX_iv_noconst(c);
++        gctx->taglen = -1;
++        gctx->iv_gen = 0;
++        gctx->tls_aad_len = -1;
++        return 1;
++
++    case EVP_CTRL_AEAD_SET_IVLEN:
++        if (arg <= 0)
++            return 0;
++        /* Allocate memory for IV if needed */
++        if ((arg > EVP_MAX_IV_LENGTH) && (arg > gctx->ivlen)) {
++            if (gctx->iv != EVP_CIPHER_CTX_iv_noconst(c))
++                OPENSSL_free(gctx->iv);
++            gctx->iv = OPENSSL_malloc(arg);
++            if (gctx->iv == NULL)
++                return 0;
++        }
++        gctx->ivlen = arg;
++        return 1;
++
++    case EVP_CTRL_AEAD_SET_TAG:
++        if (arg <= 0 || arg > 16 || EVP_CIPHER_CTX_encrypting(c))
++            return 0;
++        memcpy(EVP_CIPHER_CTX_buf_noconst(c), ptr, arg);
++        gctx->taglen = arg;
++        return 1;
++
++    case EVP_CTRL_AEAD_GET_TAG:
++        if (arg <= 0 || arg > 16 || !EVP_CIPHER_CTX_encrypting(c)
++            || gctx->taglen < 0)
++            return 0;
++        memcpy(ptr, EVP_CIPHER_CTX_buf_noconst(c), arg);
++        return 1;
++
++    case EVP_CTRL_GCM_SET_IV_FIXED:
++        /* Special case: -1 length restores whole IV */
++        if (arg == -1) {
++            memcpy(gctx->iv, ptr, gctx->ivlen);
++            gctx->iv_gen = 1;
++            return 1;
++        }
++        /*
++         * Fixed field must be at least 4 bytes and invocation field at least
++         * 8.
++         */
++        if ((arg < 4) || (gctx->ivlen - arg) < 8)
++            return 0;
++        if (arg)
++            memcpy(gctx->iv, ptr, arg);
++        if (EVP_CIPHER_CTX_encrypting(c)
++            && RAND_bytes(gctx->iv + arg, gctx->ivlen - arg) <= 0)
++            return 0;
++        gctx->iv_gen = 1;
++        return 1;
++
++    case EVP_CTRL_GCM_IV_GEN:
++        if (gctx->iv_gen == 0 || gctx->key_set == 0)
++            return 0;
++        CRYPTO_gcm128_setiv(&gctx->gcm, gctx->iv, gctx->ivlen);
++        if (arg <= 0 || arg > gctx->ivlen)
++            arg = gctx->ivlen;
++        memcpy(ptr, gctx->iv + gctx->ivlen - arg, arg);
++        /*
++         * Invocation field will be at least 8 bytes in size and so no need
++         * to check wrap around or increment more than last 8 bytes.
++         */
++        ctr64_inc(gctx->iv + gctx->ivlen - 8);
++        gctx->iv_set = 1;
++        return 1;
++
++    case EVP_CTRL_GCM_SET_IV_INV:
++        if (gctx->iv_gen == 0 || gctx->key_set == 0
++            || EVP_CIPHER_CTX_encrypting(c))
++            return 0;
++        memcpy(gctx->iv + gctx->ivlen - arg, ptr, arg);
++        CRYPTO_gcm128_setiv(&gctx->gcm, gctx->iv, gctx->ivlen);
++        gctx->iv_set = 1;
++        return 1;
++
++    case EVP_CTRL_AEAD_TLS1_AAD:
++        /* Save the AAD for later use */
++        if (arg != EVP_AEAD_TLS1_AAD_LEN)
++            return 0;
++        memcpy(EVP_CIPHER_CTX_buf_noconst(c), ptr, arg);
++        gctx->tls_aad_len = arg;
++        {
++            unsigned int len =
++                EVP_CIPHER_CTX_buf_noconst(c)[arg - 2] << 8
++                | EVP_CIPHER_CTX_buf_noconst(c)[arg - 1];
++            /* Correct length for explicit IV */
++            if (len < EVP_GCM_TLS_EXPLICIT_IV_LEN)
++                return 0;
++            len -= EVP_GCM_TLS_EXPLICIT_IV_LEN;
++            /* If decrypting correct for tag too */
++            if (!EVP_CIPHER_CTX_encrypting(c)) {
++                if (len < EVP_GCM_TLS_TAG_LEN)
++                    return 0;
++                len -= EVP_GCM_TLS_TAG_LEN;
++            }
++            EVP_CIPHER_CTX_buf_noconst(c)[arg - 2] = len >> 8;
++            EVP_CIPHER_CTX_buf_noconst(c)[arg - 1] = len & 0xff;
++        }
++        /* Extra padding: tag appended to record */
++        return EVP_GCM_TLS_TAG_LEN;
++
++    case EVP_CTRL_COPY:
++        {
++            EVP_CIPHER_CTX *out = ptr;
++            EVP_AES_GCM_CTX *gctx_out = EVP_C_DATA(EVP_AES_GCM_CTX,out);
++            if (gctx->gcm.key) {
++                if (gctx->gcm.key != &gctx->ks)
++                    return 0;
++                gctx_out->gcm.key = &gctx_out->ks;
++            }
++            if (gctx->iv == EVP_CIPHER_CTX_iv_noconst(c))
++                gctx_out->iv = EVP_CIPHER_CTX_iv_noconst(out);
++            else {
++                gctx_out->iv = OPENSSL_malloc(gctx->ivlen);
++                if (gctx_out->iv == NULL)
++                    return 0;
++                memcpy(gctx_out->iv, gctx->iv, gctx->ivlen);
++            }
++            return 1;
++        }
++
++    default:
++        return -1;
++
++    }
++}
++
++static int aes_gcm_init_key(EVP_CIPHER_CTX *ctx, const unsigned char *key,
++                            const unsigned char *iv, int enc)
++{
++    EVP_AES_GCM_CTX *gctx = EVP_C_DATA(EVP_AES_GCM_CTX,ctx);
++    if (!iv && !key)
++        return 1;
++    if (key) {
++        do {
++#ifdef HWAES_CAPABLE
++            if (HWAES_CAPABLE) {
++                HWAES_set_encrypt_key(key, EVP_CIPHER_CTX_key_length(ctx) * 8,
++                                      &gctx->ks.ks);
++                CRYPTO_gcm128_init(&gctx->gcm, &gctx->ks,
++                                   (block128_f) HWAES_encrypt);
++# ifdef HWAES_ctr32_encrypt_blocks
++                gctx->ctr = (ctr128_f) HWAES_ctr32_encrypt_blocks;
++# else
++                gctx->ctr = NULL;
++# endif
++                break;
++            } else
++#endif
++#ifdef BSAES_CAPABLE
++            if (BSAES_CAPABLE) {
++                AES_set_encrypt_key(key, EVP_CIPHER_CTX_key_length(ctx) * 8,
++                                    &gctx->ks.ks);
++                CRYPTO_gcm128_init(&gctx->gcm, &gctx->ks,
++                                   (block128_f) AES_encrypt);
++                gctx->ctr = (ctr128_f) bsaes_ctr32_encrypt_blocks;
++                break;
++            } else
++#endif
++#ifdef VPAES_CAPABLE
++            if (VPAES_CAPABLE) {
++                vpaes_set_encrypt_key(key, EVP_CIPHER_CTX_key_length(ctx) * 8,
++                                      &gctx->ks.ks);
++                CRYPTO_gcm128_init(&gctx->gcm, &gctx->ks,
++                                   (block128_f) vpaes_encrypt);
++                gctx->ctr = NULL;
++                break;
++            } else
++#endif
++                (void)0;        /* terminate potentially open 'else' */
++
++            AES_set_encrypt_key(key, EVP_CIPHER_CTX_key_length(ctx) * 8,
++                                &gctx->ks.ks);
++            CRYPTO_gcm128_init(&gctx->gcm, &gctx->ks,
++                               (block128_f) AES_encrypt);
++#ifdef AES_CTR_ASM
++            gctx->ctr = (ctr128_f) AES_ctr32_encrypt;
++#else
++            gctx->ctr = NULL;
++#endif
++        } while (0);
++
++        /*
++         * If we have an iv can set it directly, otherwise use saved IV.
++         */
++        if (iv == NULL && gctx->iv_set)
++            iv = gctx->iv;
++        if (iv) {
++            CRYPTO_gcm128_setiv(&gctx->gcm, iv, gctx->ivlen);
++            gctx->iv_set = 1;
++        }
++        gctx->key_set = 1;
++    } else {
++        /* If key set use IV, otherwise copy */
++        if (gctx->key_set)
++            CRYPTO_gcm128_setiv(&gctx->gcm, iv, gctx->ivlen);
++        else
++            memcpy(gctx->iv, iv, gctx->ivlen);
++        gctx->iv_set = 1;
++        gctx->iv_gen = 0;
++    }
++    return 1;
++}
++
++/*
++ * Handle TLS GCM packet format. This consists of the last portion of the IV
++ * followed by the payload and finally the tag. On encrypt generate IV,
++ * encrypt payload and write the tag. On verify retrieve IV, decrypt payload
++ * and verify tag.
++ */
++
++static int aes_gcm_tls_cipher(EVP_CIPHER_CTX *ctx, unsigned char *out,
++                              const unsigned char *in, size_t len)
++{
++    EVP_AES_GCM_CTX *gctx = EVP_C_DATA(EVP_AES_GCM_CTX,ctx);
++    int rv = -1;
++    /* Encrypt/decrypt must be performed in place */
++    if (out != in
++        || len < (EVP_GCM_TLS_EXPLICIT_IV_LEN + EVP_GCM_TLS_TAG_LEN))
++        return -1;
++    /*
++     * Set IV from start of buffer or generate IV and write to start of
++     * buffer.
++     */
++    if (EVP_CIPHER_CTX_ctrl(ctx, EVP_CIPHER_CTX_encrypting(ctx) ?
++                            EVP_CTRL_GCM_IV_GEN : EVP_CTRL_GCM_SET_IV_INV,
++                            EVP_GCM_TLS_EXPLICIT_IV_LEN, out) <= 0)
++        goto err;
++    /* Use saved AAD */
++    if (CRYPTO_gcm128_aad(&gctx->gcm, EVP_CIPHER_CTX_buf_noconst(ctx),
++                          gctx->tls_aad_len))
++        goto err;
++    /* Fix buffer and length to point to payload */
++    in += EVP_GCM_TLS_EXPLICIT_IV_LEN;
++    out += EVP_GCM_TLS_EXPLICIT_IV_LEN;
++    len -= EVP_GCM_TLS_EXPLICIT_IV_LEN + EVP_GCM_TLS_TAG_LEN;
++    if (EVP_CIPHER_CTX_encrypting(ctx)) {
++        /* Encrypt payload */
++        if (gctx->ctr) {
++            size_t bulk = 0;
++#if defined(AES_GCM_ASM)
++            if (len >= 32 && AES_GCM_ASM(gctx)) {
++                if (CRYPTO_gcm128_encrypt(&gctx->gcm, NULL, NULL, 0))
++                    return -1;
++
++                bulk = AES_gcm_encrypt(in, out, len,
++                                       gctx->gcm.key,
++                                       gctx->gcm.Yi.c, gctx->gcm.Xi.u);
++                gctx->gcm.len.u[1] += bulk;
++            }
++#endif
++            if (CRYPTO_gcm128_encrypt_ctr32(&gctx->gcm,
++                                            in + bulk,
++                                            out + bulk,
++                                            len - bulk, gctx->ctr))
++                goto err;
++        } else {
++            size_t bulk = 0;
++#if defined(AES_GCM_ASM2)
++            if (len >= 32 && AES_GCM_ASM2(gctx)) {
++                if (CRYPTO_gcm128_encrypt(&gctx->gcm, NULL, NULL, 0))
++                    return -1;
++
++                bulk = AES_gcm_encrypt(in, out, len,
++                                       gctx->gcm.key,
++                                       gctx->gcm.Yi.c, gctx->gcm.Xi.u);
++                gctx->gcm.len.u[1] += bulk;
++            }
++#endif
++            if (CRYPTO_gcm128_encrypt(&gctx->gcm,
++                                      in + bulk, out + bulk, len - bulk))
++                goto err;
++        }
++        out += len;
++        /* Finally write tag */
++        CRYPTO_gcm128_tag(&gctx->gcm, out, EVP_GCM_TLS_TAG_LEN);
++        rv = len + EVP_GCM_TLS_EXPLICIT_IV_LEN + EVP_GCM_TLS_TAG_LEN;
++    } else {
++        /* Decrypt */
++        if (gctx->ctr) {
++            size_t bulk = 0;
++#if defined(AES_GCM_ASM)
++            if (len >= 16 && AES_GCM_ASM(gctx)) {
++                if (CRYPTO_gcm128_decrypt(&gctx->gcm, NULL, NULL, 0))
++                    return -1;
++
++                bulk = AES_gcm_decrypt(in, out, len,
++                                       gctx->gcm.key,
++                                       gctx->gcm.Yi.c, gctx->gcm.Xi.u);
++                gctx->gcm.len.u[1] += bulk;
++            }
++#endif
++            if (CRYPTO_gcm128_decrypt_ctr32(&gctx->gcm,
++                                            in + bulk,
++                                            out + bulk,
++                                            len - bulk, gctx->ctr))
++                goto err;
++        } else {
++            size_t bulk = 0;
++#if defined(AES_GCM_ASM2)
++            if (len >= 16 && AES_GCM_ASM2(gctx)) {
++                if (CRYPTO_gcm128_decrypt(&gctx->gcm, NULL, NULL, 0))
++                    return -1;
++
++                bulk = AES_gcm_decrypt(in, out, len,
++                                       gctx->gcm.key,
++                                       gctx->gcm.Yi.c, gctx->gcm.Xi.u);
++                gctx->gcm.len.u[1] += bulk;
++            }
++#endif
++            if (CRYPTO_gcm128_decrypt(&gctx->gcm,
++                                      in + bulk, out + bulk, len - bulk))
++                goto err;
++        }
++        /* Retrieve tag */
++        CRYPTO_gcm128_tag(&gctx->gcm, EVP_CIPHER_CTX_buf_noconst(ctx),
++                          EVP_GCM_TLS_TAG_LEN);
++        /* If tag mismatch wipe buffer */
++        if (CRYPTO_memcmp(EVP_CIPHER_CTX_buf_noconst(ctx), in + len,
++                          EVP_GCM_TLS_TAG_LEN)) {
++            OPENSSL_cleanse(out, len);
++            goto err;
++        }
++        rv = len;
++    }
++
++ err:
++    gctx->iv_set = 0;
++    gctx->tls_aad_len = -1;
++    return rv;
++}
++
++static int aes_gcm_cipher(EVP_CIPHER_CTX *ctx, unsigned char *out,
++                          const unsigned char *in, size_t len)
++{
++    EVP_AES_GCM_CTX *gctx = EVP_C_DATA(EVP_AES_GCM_CTX,ctx);
++    /* If not set up, return error */
++    if (!gctx->key_set)
++        return -1;
++
++    if (gctx->tls_aad_len >= 0)
++        return aes_gcm_tls_cipher(ctx, out, in, len);
++
++    if (!gctx->iv_set)
++        return -1;
++    if (in) {
++        if (out == NULL) {
++            if (CRYPTO_gcm128_aad(&gctx->gcm, in, len))
++                return -1;
++        } else if (EVP_CIPHER_CTX_encrypting(ctx)) {
++            if (gctx->ctr) {
++                size_t bulk = 0;
++#if defined(AES_GCM_ASM)
++                if (len >= 32 && AES_GCM_ASM(gctx)) {
++                    size_t res = (16 - gctx->gcm.mres) % 16;
++
++                    if (CRYPTO_gcm128_encrypt(&gctx->gcm, in, out, res))
++                        return -1;
++
++                    bulk = AES_gcm_encrypt(in + res,
++                                           out + res, len - res,
++                                           gctx->gcm.key, gctx->gcm.Yi.c,
++                                           gctx->gcm.Xi.u);
++                    gctx->gcm.len.u[1] += bulk;
++                    bulk += res;
++                }
++#endif
++                if (CRYPTO_gcm128_encrypt_ctr32(&gctx->gcm,
++                                                in + bulk,
++                                                out + bulk,
++                                                len - bulk, gctx->ctr))
++                    return -1;
++            } else {
++                size_t bulk = 0;
++#if defined(AES_GCM_ASM2)
++                if (len >= 32 && AES_GCM_ASM2(gctx)) {
++                    size_t res = (16 - gctx->gcm.mres) % 16;
++
++                    if (CRYPTO_gcm128_encrypt(&gctx->gcm, in, out, res))
++                        return -1;
++
++                    bulk = AES_gcm_encrypt(in + res,
++                                           out + res, len - res,
++                                           gctx->gcm.key, gctx->gcm.Yi.c,
++                                           gctx->gcm.Xi.u);
++                    gctx->gcm.len.u[1] += bulk;
++                    bulk += res;
++                }
++#endif
++                if (CRYPTO_gcm128_encrypt(&gctx->gcm,
++                                          in + bulk, out + bulk, len - bulk))
++                    return -1;
++            }
++        } else {
++            if (gctx->ctr) {
++                size_t bulk = 0;
++#if defined(AES_GCM_ASM)
++                if (len >= 16 && AES_GCM_ASM(gctx)) {
++                    size_t res = (16 - gctx->gcm.mres) % 16;
++
++                    if (CRYPTO_gcm128_decrypt(&gctx->gcm, in, out, res))
++                        return -1;
++
++                    bulk = AES_gcm_decrypt(in + res,
++                                           out + res, len - res,
++                                           gctx->gcm.key,
++                                           gctx->gcm.Yi.c, gctx->gcm.Xi.u);
++                    gctx->gcm.len.u[1] += bulk;
++                    bulk += res;
++                }
++#endif
++                if (CRYPTO_gcm128_decrypt_ctr32(&gctx->gcm,
++                                                in + bulk,
++                                                out + bulk,
++                                                len - bulk, gctx->ctr))
++                    return -1;
++            } else {
++                size_t bulk = 0;
++#if defined(AES_GCM_ASM2)
++                if (len >= 16 && AES_GCM_ASM2(gctx)) {
++                    size_t res = (16 - gctx->gcm.mres) % 16;
++
++                    if (CRYPTO_gcm128_decrypt(&gctx->gcm, in, out, res))
++                        return -1;
++
++                    bulk = AES_gcm_decrypt(in + res,
++                                           out + res, len - res,
++                                           gctx->gcm.key,
++                                           gctx->gcm.Yi.c, gctx->gcm.Xi.u);
++                    gctx->gcm.len.u[1] += bulk;
++                    bulk += res;
++                }
++#endif
++                if (CRYPTO_gcm128_decrypt(&gctx->gcm,
++                                          in + bulk, out + bulk, len - bulk))
++                    return -1;
++            }
++        }
++        return len;
++    } else {
++        if (!EVP_CIPHER_CTX_encrypting(ctx)) {
++            if (gctx->taglen < 0)
++                return -1;
++            if (CRYPTO_gcm128_finish(&gctx->gcm,
++                                     EVP_CIPHER_CTX_buf_noconst(ctx),
++                                     gctx->taglen) != 0)
++                return -1;
++            gctx->iv_set = 0;
++            return 0;
++        }
++        CRYPTO_gcm128_tag(&gctx->gcm, EVP_CIPHER_CTX_buf_noconst(ctx), 16);
++        gctx->taglen = 16;
++        /* Don't reuse the IV */
++        gctx->iv_set = 0;
++        return 0;
++    }
++
++}
++
++#define CUSTOM_FLAGS    (EVP_CIPH_FLAG_DEFAULT_ASN1 \
++                | EVP_CIPH_CUSTOM_IV | EVP_CIPH_FLAG_CUSTOM_CIPHER \
++                | EVP_CIPH_ALWAYS_CALL_INIT | EVP_CIPH_CTRL_INIT \
++                | EVP_CIPH_CUSTOM_COPY)
++
++BLOCK_CIPHER_custom(NID_aes, 128, 1, 12, gcm, GCM,
++                    EVP_CIPH_FLAG_AEAD_CIPHER | CUSTOM_FLAGS)
++    BLOCK_CIPHER_custom(NID_aes, 192, 1, 12, gcm, GCM,
++                    EVP_CIPH_FLAG_AEAD_CIPHER | CUSTOM_FLAGS)
++    BLOCK_CIPHER_custom(NID_aes, 256, 1, 12, gcm, GCM,
++                    EVP_CIPH_FLAG_AEAD_CIPHER | CUSTOM_FLAGS)
++
++static int aes_xts_ctrl(EVP_CIPHER_CTX *c, int type, int arg, void *ptr)
++{
++    EVP_AES_XTS_CTX *xctx = EVP_C_DATA(EVP_AES_XTS_CTX,c);
++    if (type == EVP_CTRL_COPY) {
++        EVP_CIPHER_CTX *out = ptr;
++        EVP_AES_XTS_CTX *xctx_out = EVP_C_DATA(EVP_AES_XTS_CTX,out);
++        if (xctx->xts.key1) {
++            if (xctx->xts.key1 != &xctx->ks1)
++                return 0;
++            xctx_out->xts.key1 = &xctx_out->ks1;
++        }
++        if (xctx->xts.key2) {
++            if (xctx->xts.key2 != &xctx->ks2)
++                return 0;
++            xctx_out->xts.key2 = &xctx_out->ks2;
++        }
++        return 1;
++    } else if (type != EVP_CTRL_INIT)
++        return -1;
++    /* key1 and key2 are used as an indicator both key and IV are set */
++    xctx->xts.key1 = NULL;
++    xctx->xts.key2 = NULL;
++    return 1;
++}
++
++static int aes_xts_init_key(EVP_CIPHER_CTX *ctx, const unsigned char *key,
++                            const unsigned char *iv, int enc)
++{
++    EVP_AES_XTS_CTX *xctx = EVP_C_DATA(EVP_AES_XTS_CTX,ctx);
++    if (!iv && !key)
++        return 1;
++
++    if (key)
++        do {
++#ifdef AES_XTS_ASM
++            xctx->stream = enc ? AES_xts_encrypt : AES_xts_decrypt;
++#else
++            xctx->stream = NULL;
++#endif
++            /* key_len is two AES keys */
++#ifdef HWAES_CAPABLE
++            if (HWAES_CAPABLE) {
++                if (enc) {
++                    HWAES_set_encrypt_key(key,
++                                          EVP_CIPHER_CTX_key_length(ctx) * 4,
++                                          &xctx->ks1.ks);
++                    xctx->xts.block1 = (block128_f) HWAES_encrypt;
++# ifdef HWAES_xts_encrypt
++                    xctx->stream = HWAES_xts_encrypt;
++# endif
++                } else {
++                    HWAES_set_decrypt_key(key,
++                                          EVP_CIPHER_CTX_key_length(ctx) * 4,
++                                          &xctx->ks1.ks);
++                    xctx->xts.block1 = (block128_f) HWAES_decrypt;
++# ifdef HWAES_xts_decrypt
++                    xctx->stream = HWAES_xts_decrypt;
++#endif
++                }
++
++                HWAES_set_encrypt_key(key + EVP_CIPHER_CTX_key_length(ctx) / 2,
++                                      EVP_CIPHER_CTX_key_length(ctx) * 4,
++                                      &xctx->ks2.ks);
++                xctx->xts.block2 = (block128_f) HWAES_encrypt;
++
++                xctx->xts.key1 = &xctx->ks1;
++                break;
++            } else
++#endif
++#ifdef BSAES_CAPABLE
++            if (BSAES_CAPABLE)
++                xctx->stream = enc ? bsaes_xts_encrypt : bsaes_xts_decrypt;
++            else
++#endif
++#ifdef VPAES_CAPABLE
++            if (VPAES_CAPABLE) {
++                if (enc) {
++                    vpaes_set_encrypt_key(key,
++                                          EVP_CIPHER_CTX_key_length(ctx) * 4,
++                                          &xctx->ks1.ks);
++                    xctx->xts.block1 = (block128_f) vpaes_encrypt;
++                } else {
++                    vpaes_set_decrypt_key(key,
++                                          EVP_CIPHER_CTX_key_length(ctx) * 4,
++                                          &xctx->ks1.ks);
++                    xctx->xts.block1 = (block128_f) vpaes_decrypt;
++                }
++
++                vpaes_set_encrypt_key(key + EVP_CIPHER_CTX_key_length(ctx) / 2,
++                                      EVP_CIPHER_CTX_key_length(ctx) * 4,
++                                      &xctx->ks2.ks);
++                xctx->xts.block2 = (block128_f) vpaes_encrypt;
++
++                xctx->xts.key1 = &xctx->ks1;
++                break;
++            } else
++#endif
++                (void)0;        /* terminate potentially open 'else' */
++
++            if (enc) {
++                AES_set_encrypt_key(key, EVP_CIPHER_CTX_key_length(ctx) * 4,
++                                    &xctx->ks1.ks);
++                xctx->xts.block1 = (block128_f) AES_encrypt;
++            } else {
++                AES_set_decrypt_key(key, EVP_CIPHER_CTX_key_length(ctx) * 4,
++                                    &xctx->ks1.ks);
++                xctx->xts.block1 = (block128_f) AES_decrypt;
++            }
++
++            AES_set_encrypt_key(key + EVP_CIPHER_CTX_key_length(ctx) / 2,
++                                EVP_CIPHER_CTX_key_length(ctx) * 4,
++                                &xctx->ks2.ks);
++            xctx->xts.block2 = (block128_f) AES_encrypt;
++
++            xctx->xts.key1 = &xctx->ks1;
++        } while (0);
++
++    if (iv) {
++        xctx->xts.key2 = &xctx->ks2;
++        memcpy(EVP_CIPHER_CTX_iv_noconst(ctx), iv, 16);
++    }
++
++    return 1;
++}
++
++static int aes_xts_cipher(EVP_CIPHER_CTX *ctx, unsigned char *out,
++                          const unsigned char *in, size_t len)
++{
++    EVP_AES_XTS_CTX *xctx = EVP_C_DATA(EVP_AES_XTS_CTX,ctx);
++    if (!xctx->xts.key1 || !xctx->xts.key2)
++        return 0;
++    if (!out || !in || len < AES_BLOCK_SIZE)
++        return 0;
++    if (xctx->stream)
++        (*xctx->stream) (in, out, len,
++                         xctx->xts.key1, xctx->xts.key2,
++                         EVP_CIPHER_CTX_iv_noconst(ctx));
++    else if (CRYPTO_xts128_encrypt(&xctx->xts, EVP_CIPHER_CTX_iv_noconst(ctx),
++                                   in, out, len,
++                                   EVP_CIPHER_CTX_encrypting(ctx)))
++        return 0;
++    return 1;
++}
++
++#define aes_xts_cleanup NULL
++
++#define XTS_FLAGS       (EVP_CIPH_FLAG_DEFAULT_ASN1 | EVP_CIPH_CUSTOM_IV \
++                         | EVP_CIPH_ALWAYS_CALL_INIT | EVP_CIPH_CTRL_INIT \
++                         | EVP_CIPH_CUSTOM_COPY)
++
++BLOCK_CIPHER_custom(NID_aes, 128, 1, 16, xts, XTS, XTS_FLAGS)
++    BLOCK_CIPHER_custom(NID_aes, 256, 1, 16, xts, XTS, XTS_FLAGS)
++
++static int aes_ccm_ctrl(EVP_CIPHER_CTX *c, int type, int arg, void *ptr)
++{
++    EVP_AES_CCM_CTX *cctx = EVP_C_DATA(EVP_AES_CCM_CTX,c);
++    switch (type) {
++    case EVP_CTRL_INIT:
++        cctx->key_set = 0;
++        cctx->iv_set = 0;
++        cctx->L = 8;
++        cctx->M = 12;
++        cctx->tag_set = 0;
++        cctx->len_set = 0;
++        cctx->tls_aad_len = -1;
++        return 1;
++
++    case EVP_CTRL_AEAD_TLS1_AAD:
++        /* Save the AAD for later use */
++        if (arg != EVP_AEAD_TLS1_AAD_LEN)
++            return 0;
++        memcpy(EVP_CIPHER_CTX_buf_noconst(c), ptr, arg);
++        cctx->tls_aad_len = arg;
++        {
++            uint16_t len =
++                EVP_CIPHER_CTX_buf_noconst(c)[arg - 2] << 8
++                | EVP_CIPHER_CTX_buf_noconst(c)[arg - 1];
++            /* Correct length for explicit IV */
++            if (len < EVP_CCM_TLS_EXPLICIT_IV_LEN)
++                return 0;
++            len -= EVP_CCM_TLS_EXPLICIT_IV_LEN;
++            /* If decrypting correct for tag too */
++            if (!EVP_CIPHER_CTX_encrypting(c)) {
++                if (len < cctx->M)
++                    return 0;
++                len -= cctx->M;
++            }
++            EVP_CIPHER_CTX_buf_noconst(c)[arg - 2] = len >> 8;
++            EVP_CIPHER_CTX_buf_noconst(c)[arg - 1] = len & 0xff;
++        }
++        /* Extra padding: tag appended to record */
++        return cctx->M;
++
++    case EVP_CTRL_CCM_SET_IV_FIXED:
++        /* Sanity check length */
++        if (arg != EVP_CCM_TLS_FIXED_IV_LEN)
++            return 0;
++        /* Just copy to first part of IV */
++        memcpy(EVP_CIPHER_CTX_iv_noconst(c), ptr, arg);
++        return 1;
++
++    case EVP_CTRL_AEAD_SET_IVLEN:
++        arg = 15 - arg;
++    case EVP_CTRL_CCM_SET_L:
++        if (arg < 2 || arg > 8)
++            return 0;
++        cctx->L = arg;
++        return 1;
++
++    case EVP_CTRL_AEAD_SET_TAG:
++        if ((arg & 1) || arg < 4 || arg > 16)
++            return 0;
++        if (EVP_CIPHER_CTX_encrypting(c) && ptr)
++            return 0;
++        if (ptr) {
++            cctx->tag_set = 1;
++            memcpy(EVP_CIPHER_CTX_buf_noconst(c), ptr, arg);
++        }
++        cctx->M = arg;
++        return 1;
++
++    case EVP_CTRL_AEAD_GET_TAG:
++        if (!EVP_CIPHER_CTX_encrypting(c) || !cctx->tag_set)
++            return 0;
++        if (!CRYPTO_ccm128_tag(&cctx->ccm, ptr, (size_t)arg))
++            return 0;
++        cctx->tag_set = 0;
++        cctx->iv_set = 0;
++        cctx->len_set = 0;
++        return 1;
++
++    case EVP_CTRL_COPY:
++        {
++            EVP_CIPHER_CTX *out = ptr;
++            EVP_AES_CCM_CTX *cctx_out = EVP_C_DATA(EVP_AES_CCM_CTX,out);
++            if (cctx->ccm.key) {
++                if (cctx->ccm.key != &cctx->ks)
++                    return 0;
++                cctx_out->ccm.key = &cctx_out->ks;
++            }
++            return 1;
++        }
++
++    default:
++        return -1;
++
++    }
++}
++
++static int aes_ccm_init_key(EVP_CIPHER_CTX *ctx, const unsigned char *key,
++                            const unsigned char *iv, int enc)
++{
++    EVP_AES_CCM_CTX *cctx = EVP_C_DATA(EVP_AES_CCM_CTX,ctx);
++    if (!iv && !key)
++        return 1;
++    if (key)
++        do {
++#ifdef HWAES_CAPABLE
++            if (HWAES_CAPABLE) {
++                HWAES_set_encrypt_key(key, EVP_CIPHER_CTX_key_length(ctx) * 8,
++                                      &cctx->ks.ks);
++
++                CRYPTO_ccm128_init(&cctx->ccm, cctx->M, cctx->L,
++                                   &cctx->ks, (block128_f) HWAES_encrypt);
++                cctx->str = NULL;
++                cctx->key_set = 1;
++                break;
++            } else
++#endif
++#ifdef VPAES_CAPABLE
++            if (VPAES_CAPABLE) {
++                vpaes_set_encrypt_key(key, EVP_CIPHER_CTX_key_length(ctx) * 8,
++                                      &cctx->ks.ks);
++                CRYPTO_ccm128_init(&cctx->ccm, cctx->M, cctx->L,
++                                   &cctx->ks, (block128_f) vpaes_encrypt);
++                cctx->str = NULL;
++                cctx->key_set = 1;
++                break;
++            }
++#endif
++            AES_set_encrypt_key(key, EVP_CIPHER_CTX_key_length(ctx) * 8,
++                                &cctx->ks.ks);
++            CRYPTO_ccm128_init(&cctx->ccm, cctx->M, cctx->L,
++                               &cctx->ks, (block128_f) AES_encrypt);
++            cctx->str = NULL;
++            cctx->key_set = 1;
++        } while (0);
++    if (iv) {
++        memcpy(EVP_CIPHER_CTX_iv_noconst(ctx), iv, 15 - cctx->L);
++        cctx->iv_set = 1;
++    }
++    return 1;
++}
++
++static int aes_ccm_tls_cipher(EVP_CIPHER_CTX *ctx, unsigned char *out,
++                              const unsigned char *in, size_t len)
++{
++    EVP_AES_CCM_CTX *cctx = EVP_C_DATA(EVP_AES_CCM_CTX,ctx);
++    CCM128_CONTEXT *ccm = &cctx->ccm;
++    /* Encrypt/decrypt must be performed in place */
++    if (out != in || len < (EVP_CCM_TLS_EXPLICIT_IV_LEN + (size_t)cctx->M))
++        return -1;
++    /* If encrypting set explicit IV from sequence number (start of AAD) */
++    if (EVP_CIPHER_CTX_encrypting(ctx))
++        memcpy(out, EVP_CIPHER_CTX_buf_noconst(ctx),
++               EVP_CCM_TLS_EXPLICIT_IV_LEN);
++    /* Get rest of IV from explicit IV */
++    memcpy(EVP_CIPHER_CTX_iv_noconst(ctx) + EVP_CCM_TLS_FIXED_IV_LEN, in,
++           EVP_CCM_TLS_EXPLICIT_IV_LEN);
++    /* Correct length value */
++    len -= EVP_CCM_TLS_EXPLICIT_IV_LEN + cctx->M;
++    if (CRYPTO_ccm128_setiv(ccm, EVP_CIPHER_CTX_iv_noconst(ctx), 15 - cctx->L,
++                            len))
++            return -1;
++    /* Use saved AAD */
++    CRYPTO_ccm128_aad(ccm, EVP_CIPHER_CTX_buf_noconst(ctx), cctx->tls_aad_len);
++    /* Fix buffer to point to payload */
++    in += EVP_CCM_TLS_EXPLICIT_IV_LEN;
++    out += EVP_CCM_TLS_EXPLICIT_IV_LEN;
++    if (EVP_CIPHER_CTX_encrypting(ctx)) {
++        if (cctx->str ? CRYPTO_ccm128_encrypt_ccm64(ccm, in, out, len,
++                                                    cctx->str) :
++            CRYPTO_ccm128_encrypt(ccm, in, out, len))
++            return -1;
++        if (!CRYPTO_ccm128_tag(ccm, out + len, cctx->M))
++            return -1;
++        return len + EVP_CCM_TLS_EXPLICIT_IV_LEN + cctx->M;
++    } else {
++        if (cctx->str ? !CRYPTO_ccm128_decrypt_ccm64(ccm, in, out, len,
++                                                     cctx->str) :
++            !CRYPTO_ccm128_decrypt(ccm, in, out, len)) {
++            unsigned char tag[16];
++            if (CRYPTO_ccm128_tag(ccm, tag, cctx->M)) {
++                if (!CRYPTO_memcmp(tag, in + len, cctx->M))
++                    return len;
++            }
++        }
++        OPENSSL_cleanse(out, len);
++        return -1;
++    }
++}
++
++static int aes_ccm_cipher(EVP_CIPHER_CTX *ctx, unsigned char *out,
++                          const unsigned char *in, size_t len)
++{
++    EVP_AES_CCM_CTX *cctx = EVP_C_DATA(EVP_AES_CCM_CTX,ctx);
++    CCM128_CONTEXT *ccm = &cctx->ccm;
++    /* If not set up, return error */
++    if (!cctx->key_set)
++        return -1;
++
++    if (cctx->tls_aad_len >= 0)
++        return aes_ccm_tls_cipher(ctx, out, in, len);
++
++    if (!cctx->iv_set)
++        return -1;
++
++    if (!EVP_CIPHER_CTX_encrypting(ctx) && !cctx->tag_set)
++        return -1;
++    if (!out) {
++        if (!in) {
++            if (CRYPTO_ccm128_setiv(ccm, EVP_CIPHER_CTX_iv_noconst(ctx),
++                                    15 - cctx->L, len))
++                return -1;
++            cctx->len_set = 1;
++            return len;
++        }
++        /* If have AAD need message length */
++        if (!cctx->len_set && len)
++            return -1;
++        CRYPTO_ccm128_aad(ccm, in, len);
++        return len;
++    }
++    /* EVP_*Final() doesn't return any data */
++    if (!in)
++        return 0;
++    /* If not set length yet do it */
++    if (!cctx->len_set) {
++        if (CRYPTO_ccm128_setiv(ccm, EVP_CIPHER_CTX_iv_noconst(ctx),
++                                15 - cctx->L, len))
++            return -1;
++        cctx->len_set = 1;
++    }
++    if (EVP_CIPHER_CTX_encrypting(ctx)) {
++        if (cctx->str ? CRYPTO_ccm128_encrypt_ccm64(ccm, in, out, len,
++                                                    cctx->str) :
++            CRYPTO_ccm128_encrypt(ccm, in, out, len))
++            return -1;
++        cctx->tag_set = 1;
++        return len;
++    } else {
++        int rv = -1;
++        if (cctx->str ? !CRYPTO_ccm128_decrypt_ccm64(ccm, in, out, len,
++                                                     cctx->str) :
++            !CRYPTO_ccm128_decrypt(ccm, in, out, len)) {
++            unsigned char tag[16];
++            if (CRYPTO_ccm128_tag(ccm, tag, cctx->M)) {
++                if (!CRYPTO_memcmp(tag, EVP_CIPHER_CTX_buf_noconst(ctx),
++                                   cctx->M))
++                    rv = len;
++            }
++        }
++        if (rv == -1)
++            OPENSSL_cleanse(out, len);
++        cctx->iv_set = 0;
++        cctx->tag_set = 0;
++        cctx->len_set = 0;
++        return rv;
++    }
++}
++
++#define aes_ccm_cleanup NULL
++
++BLOCK_CIPHER_custom(NID_aes, 128, 1, 12, ccm, CCM,
++                    EVP_CIPH_FLAG_AEAD_CIPHER | CUSTOM_FLAGS)
++    BLOCK_CIPHER_custom(NID_aes, 192, 1, 12, ccm, CCM,
++                        EVP_CIPH_FLAG_AEAD_CIPHER | CUSTOM_FLAGS)
++    BLOCK_CIPHER_custom(NID_aes, 256, 1, 12, ccm, CCM,
++                        EVP_CIPH_FLAG_AEAD_CIPHER | CUSTOM_FLAGS)
++
++typedef struct {
++    union {
++        double align;
++        AES_KEY ks;
++    } ks;
++    /* Indicates if IV has been set */
++    unsigned char *iv;
++} EVP_AES_WRAP_CTX;
++
++static int aes_wrap_init_key(EVP_CIPHER_CTX *ctx, const unsigned char *key,
++                             const unsigned char *iv, int enc)
++{
++    EVP_AES_WRAP_CTX *wctx = EVP_C_DATA(EVP_AES_WRAP_CTX,ctx);
++    if (!iv && !key)
++        return 1;
++    if (key) {
++        if (EVP_CIPHER_CTX_encrypting(ctx))
++            AES_set_encrypt_key(key, EVP_CIPHER_CTX_key_length(ctx) * 8,
++                                &wctx->ks.ks);
++        else
++            AES_set_decrypt_key(key, EVP_CIPHER_CTX_key_length(ctx) * 8,
++                                &wctx->ks.ks);
++        if (!iv)
++            wctx->iv = NULL;
++    }
++    if (iv) {
++        memcpy(EVP_CIPHER_CTX_iv_noconst(ctx), iv, EVP_CIPHER_CTX_iv_length(ctx));
++        wctx->iv = EVP_CIPHER_CTX_iv_noconst(ctx);
++    }
++    return 1;
++}
++
++static int aes_wrap_cipher(EVP_CIPHER_CTX *ctx, unsigned char *out,
++                           const unsigned char *in, size_t inlen)
++{
++    EVP_AES_WRAP_CTX *wctx = EVP_C_DATA(EVP_AES_WRAP_CTX,ctx);
++    size_t rv;
++    /* AES wrap with padding has IV length of 4, without padding 8 */
++    int pad = EVP_CIPHER_CTX_iv_length(ctx) == 4;
++    /* No final operation so always return zero length */
++    if (!in)
++        return 0;
++    /* Input length must always be non-zero */
++    if (!inlen)
++        return -1;
++    /* If decrypting need at least 16 bytes and multiple of 8 */
++    if (!EVP_CIPHER_CTX_encrypting(ctx) && (inlen < 16 || inlen & 0x7))
++        return -1;
++    /* If not padding input must be multiple of 8 */
++    if (!pad && inlen & 0x7)
++        return -1;
++    if (is_partially_overlapping(out, in, inlen)) {
++        EVPerr(EVP_F_AES_WRAP_CIPHER, EVP_R_PARTIALLY_OVERLAPPING);
++        return 0;
++    }
++    if (!out) {
++        if (EVP_CIPHER_CTX_encrypting(ctx)) {
++            /* If padding round up to multiple of 8 */
++            if (pad)
++                inlen = (inlen + 7) / 8 * 8;
++            /* 8 byte prefix */
++            return inlen + 8;
++        } else {
++            /*
++             * If not padding output will be exactly 8 bytes smaller than
++             * input. If padding it will be at least 8 bytes smaller but we
++             * don't know how much.
++             */
++            return inlen - 8;
++        }
++    }
++    if (pad) {
++        if (EVP_CIPHER_CTX_encrypting(ctx))
++            rv = CRYPTO_128_wrap_pad(&wctx->ks.ks, wctx->iv,
++                                     out, in, inlen,
++                                     (block128_f) AES_encrypt);
++        else
++            rv = CRYPTO_128_unwrap_pad(&wctx->ks.ks, wctx->iv,
++                                       out, in, inlen,
++                                       (block128_f) AES_decrypt);
++    } else {
++        if (EVP_CIPHER_CTX_encrypting(ctx))
++            rv = CRYPTO_128_wrap(&wctx->ks.ks, wctx->iv,
++                                 out, in, inlen, (block128_f) AES_encrypt);
++        else
++            rv = CRYPTO_128_unwrap(&wctx->ks.ks, wctx->iv,
++                                   out, in, inlen, (block128_f) AES_decrypt);
++    }
++    return rv ? (int)rv : -1;
++}
++
++#define WRAP_FLAGS      (EVP_CIPH_WRAP_MODE \
++                | EVP_CIPH_CUSTOM_IV | EVP_CIPH_FLAG_CUSTOM_CIPHER \
++                | EVP_CIPH_ALWAYS_CALL_INIT | EVP_CIPH_FLAG_DEFAULT_ASN1)
++
++static const EVP_CIPHER aes_128_wrap = {
++    NID_id_aes128_wrap,
++    8, 16, 8, WRAP_FLAGS,
++    aes_wrap_init_key, aes_wrap_cipher,
++    NULL,
++    sizeof(EVP_AES_WRAP_CTX),
++    NULL, NULL, NULL, NULL
++};
++
++const EVP_CIPHER *EVP_aes_128_wrap(void)
++{
++    return &aes_128_wrap;
++}
++
++static const EVP_CIPHER aes_192_wrap = {
++    NID_id_aes192_wrap,
++    8, 24, 8, WRAP_FLAGS,
++    aes_wrap_init_key, aes_wrap_cipher,
++    NULL,
++    sizeof(EVP_AES_WRAP_CTX),
++    NULL, NULL, NULL, NULL
++};
++
++const EVP_CIPHER *EVP_aes_192_wrap(void)
++{
++    return &aes_192_wrap;
++}
++
++static const EVP_CIPHER aes_256_wrap = {
++    NID_id_aes256_wrap,
++    8, 32, 8, WRAP_FLAGS,
++    aes_wrap_init_key, aes_wrap_cipher,
++    NULL,
++    sizeof(EVP_AES_WRAP_CTX),
++    NULL, NULL, NULL, NULL
++};
++
++const EVP_CIPHER *EVP_aes_256_wrap(void)
++{
++    return &aes_256_wrap;
++}
++
++static const EVP_CIPHER aes_128_wrap_pad = {
++    NID_id_aes128_wrap_pad,
++    8, 16, 4, WRAP_FLAGS,
++    aes_wrap_init_key, aes_wrap_cipher,
++    NULL,
++    sizeof(EVP_AES_WRAP_CTX),
++    NULL, NULL, NULL, NULL
++};
++
++const EVP_CIPHER *EVP_aes_128_wrap_pad(void)
++{
++    return &aes_128_wrap_pad;
++}
++
++static const EVP_CIPHER aes_192_wrap_pad = {
++    NID_id_aes192_wrap_pad,
++    8, 24, 4, WRAP_FLAGS,
++    aes_wrap_init_key, aes_wrap_cipher,
++    NULL,
++    sizeof(EVP_AES_WRAP_CTX),
++    NULL, NULL, NULL, NULL
++};
++
++const EVP_CIPHER *EVP_aes_192_wrap_pad(void)
++{
++    return &aes_192_wrap_pad;
++}
++
++static const EVP_CIPHER aes_256_wrap_pad = {
++    NID_id_aes256_wrap_pad,
++    8, 32, 4, WRAP_FLAGS,
++    aes_wrap_init_key, aes_wrap_cipher,
++    NULL,
++    sizeof(EVP_AES_WRAP_CTX),
++    NULL, NULL, NULL, NULL
++};
++
++const EVP_CIPHER *EVP_aes_256_wrap_pad(void)
++{
++    return &aes_256_wrap_pad;
++}
++
++#ifndef OPENSSL_NO_OCB
++static int aes_ocb_ctrl(EVP_CIPHER_CTX *c, int type, int arg, void *ptr)
++{
++    EVP_AES_OCB_CTX *octx = EVP_C_DATA(EVP_AES_OCB_CTX,c);
++    EVP_CIPHER_CTX *newc;
++    EVP_AES_OCB_CTX *new_octx;
++
++    switch (type) {
++    case EVP_CTRL_INIT:
++        octx->key_set = 0;
++        octx->iv_set = 0;
++        octx->ivlen = EVP_CIPHER_CTX_iv_length(c);
++        octx->iv = EVP_CIPHER_CTX_iv_noconst(c);
++        octx->taglen = 16;
++        octx->data_buf_len = 0;
++        octx->aad_buf_len = 0;
++        return 1;
++
++    case EVP_CTRL_AEAD_SET_IVLEN:
++        /* IV len must be 1 to 15 */
++        if (arg <= 0 || arg > 15)
++            return 0;
++
++        octx->ivlen = arg;
++        return 1;
++
++    case EVP_CTRL_AEAD_SET_TAG:
++        if (!ptr) {
++            /* Tag len must be 0 to 16 */
++            if (arg < 0 || arg > 16)
++                return 0;
++
++            octx->taglen = arg;
++            return 1;
++        }
++        if (arg != octx->taglen || EVP_CIPHER_CTX_encrypting(c))
++            return 0;
++        memcpy(octx->tag, ptr, arg);
++        return 1;
++
++    case EVP_CTRL_AEAD_GET_TAG:
++        if (arg != octx->taglen || !EVP_CIPHER_CTX_encrypting(c))
++            return 0;
++
++        memcpy(ptr, octx->tag, arg);
++        return 1;
++
++    case EVP_CTRL_COPY:
++        newc = (EVP_CIPHER_CTX *)ptr;
++        new_octx = EVP_C_DATA(EVP_AES_OCB_CTX,newc);
++        return CRYPTO_ocb128_copy_ctx(&new_octx->ocb, &octx->ocb,
++                                      &new_octx->ksenc.ks,
++                                      &new_octx->ksdec.ks);
++
++    default:
++        return -1;
++
++    }
++}
++
++# ifdef HWAES_CAPABLE
++#  ifdef HWAES_ocb_encrypt
++void HWAES_ocb_encrypt(const unsigned char *in, unsigned char *out,
++                       size_t blocks, const void *key,
++                       size_t start_block_num,
++                       unsigned char offset_i[16],
++                       const unsigned char L_[][16],
++                       unsigned char checksum[16]);
++#  else
++#    define HWAES_ocb_encrypt ((ocb128_f)NULL)
++#  endif
++#  ifdef HWAES_ocb_decrypt
++void HWAES_ocb_decrypt(const unsigned char *in, unsigned char *out,
++                       size_t blocks, const void *key,
++                       size_t start_block_num,
++                       unsigned char offset_i[16],
++                       const unsigned char L_[][16],
++                       unsigned char checksum[16]);
++#  else
++#    define HWAES_ocb_decrypt ((ocb128_f)NULL)
++#  endif
++# endif
++
++static int aes_ocb_init_key(EVP_CIPHER_CTX *ctx, const unsigned char *key,
++                            const unsigned char *iv, int enc)
++{
++    EVP_AES_OCB_CTX *octx = EVP_C_DATA(EVP_AES_OCB_CTX,ctx);
++    if (!iv && !key)
++        return 1;
++    if (key) {
++        do {
++            /*
++             * We set both the encrypt and decrypt key here because decrypt
++             * needs both. We could possibly optimise to remove setting the
++             * decrypt for an encryption operation.
++             */
++# ifdef HWAES_CAPABLE
++            if (HWAES_CAPABLE) {
++                HWAES_set_encrypt_key(key, EVP_CIPHER_CTX_key_length(ctx) * 8,
++                                      &octx->ksenc.ks);
++                HWAES_set_decrypt_key(key, EVP_CIPHER_CTX_key_length(ctx) * 8,
++                                      &octx->ksdec.ks);
++                if (!CRYPTO_ocb128_init(&octx->ocb,
++                                        &octx->ksenc.ks, &octx->ksdec.ks,
++                                        (block128_f) HWAES_encrypt,
++                                        (block128_f) HWAES_decrypt,
++                                        enc ? HWAES_ocb_encrypt
++                                            : HWAES_ocb_decrypt))
++                    return 0;
++                break;
++            }
++# endif
++# ifdef VPAES_CAPABLE
++            if (VPAES_CAPABLE) {
++                vpaes_set_encrypt_key(key, EVP_CIPHER_CTX_key_length(ctx) * 8,
++                                      &octx->ksenc.ks);
++                vpaes_set_decrypt_key(key, EVP_CIPHER_CTX_key_length(ctx) * 8,
++                                      &octx->ksdec.ks);
++                if (!CRYPTO_ocb128_init(&octx->ocb,
++                                        &octx->ksenc.ks, &octx->ksdec.ks,
++                                        (block128_f) vpaes_encrypt,
++                                        (block128_f) vpaes_decrypt,
++                                        NULL))
++                    return 0;
++                break;
++            }
++# endif
++            AES_set_encrypt_key(key, EVP_CIPHER_CTX_key_length(ctx) * 8,
++                                &octx->ksenc.ks);
++            AES_set_decrypt_key(key, EVP_CIPHER_CTX_key_length(ctx) * 8,
++                                &octx->ksdec.ks);
++            if (!CRYPTO_ocb128_init(&octx->ocb,
++                                    &octx->ksenc.ks, &octx->ksdec.ks,
++                                    (block128_f) AES_encrypt,
++                                    (block128_f) AES_decrypt,
++                                    NULL))
++                return 0;
++        }
++        while (0);
++
++        /*
++         * If we have an iv we can set it directly, otherwise use saved IV.
++         */
++        if (iv == NULL && octx->iv_set)
++            iv = octx->iv;
++        if (iv) {
++            if (CRYPTO_ocb128_setiv(&octx->ocb, iv, octx->ivlen, octx->taglen)
++                != 1)
++                return 0;
++            octx->iv_set = 1;
++        }
++        octx->key_set = 1;
++    } else {
++        /* If key set use IV, otherwise copy */
++        if (octx->key_set)
++            CRYPTO_ocb128_setiv(&octx->ocb, iv, octx->ivlen, octx->taglen);
++        else
++            memcpy(octx->iv, iv, octx->ivlen);
++        octx->iv_set = 1;
++    }
++    return 1;
++}
++
++static int aes_ocb_cipher(EVP_CIPHER_CTX *ctx, unsigned char *out,
++                          const unsigned char *in, size_t len)
++{
++    unsigned char *buf;
++    int *buf_len;
++    int written_len = 0;
++    size_t trailing_len;
++    EVP_AES_OCB_CTX *octx = EVP_C_DATA(EVP_AES_OCB_CTX,ctx);
++
++    /* If IV or Key not set then return error */
++    if (!octx->iv_set)
++        return -1;
++
++    if (!octx->key_set)
++        return -1;
++
++    if (in != NULL) {
++        /*
++         * Need to ensure we are only passing full blocks to low level OCB
++         * routines. We do it here rather than in EVP_EncryptUpdate/
++         * EVP_DecryptUpdate because we need to pass full blocks of AAD too
++         * and those routines don't support that
++         */
++
++        /* Are we dealing with AAD or normal data here? */
++        if (out == NULL) {
++            buf = octx->aad_buf;
++            buf_len = &(octx->aad_buf_len);
++        } else {
++            buf = octx->data_buf;
++            buf_len = &(octx->data_buf_len);
++
++            if (is_partially_overlapping(out + *buf_len, in, len)) {
++                EVPerr(EVP_F_AES_OCB_CIPHER, EVP_R_PARTIALLY_OVERLAPPING);
++                return 0;
++            }
++        }
++
++        /*
++         * If we've got a partially filled buffer from a previous call then
++         * use that data first
++         */
++        if (*buf_len > 0) {
++            unsigned int remaining;
++
++            remaining = AES_BLOCK_SIZE - (*buf_len);
++            if (remaining > len) {
++                memcpy(buf + (*buf_len), in, len);
++                *(buf_len) += len;
++                return 0;
++            }
++            memcpy(buf + (*buf_len), in, remaining);
++
++            /*
++             * If we get here we've filled the buffer, so process it
++             */
++            len -= remaining;
++            in += remaining;
++            if (out == NULL) {
++                if (!CRYPTO_ocb128_aad(&octx->ocb, buf, AES_BLOCK_SIZE))
++                    return -1;
++            } else if (EVP_CIPHER_CTX_encrypting(ctx)) {
++                if (!CRYPTO_ocb128_encrypt(&octx->ocb, buf, out,
++                                           AES_BLOCK_SIZE))
++                    return -1;
++            } else {
++                if (!CRYPTO_ocb128_decrypt(&octx->ocb, buf, out,
++                                           AES_BLOCK_SIZE))
++                    return -1;
++            }
++            written_len = AES_BLOCK_SIZE;
++            *buf_len = 0;
++            if (out != NULL)
++                out += AES_BLOCK_SIZE;
++        }
++
++        /* Do we have a partial block to handle at the end? */
++        trailing_len = len % AES_BLOCK_SIZE;
++
++        /*
++         * If we've got some full blocks to handle, then process these first
++         */
++        if (len != trailing_len) {
++            if (out == NULL) {
++                if (!CRYPTO_ocb128_aad(&octx->ocb, in, len - trailing_len))
++                    return -1;
++            } else if (EVP_CIPHER_CTX_encrypting(ctx)) {
++                if (!CRYPTO_ocb128_encrypt
++                    (&octx->ocb, in, out, len - trailing_len))
++                    return -1;
++            } else {
++                if (!CRYPTO_ocb128_decrypt
++                    (&octx->ocb, in, out, len - trailing_len))
++                    return -1;
++            }
++            written_len += len - trailing_len;
++            in += len - trailing_len;
++        }
++
++        /* Handle any trailing partial block */
++        if (trailing_len > 0) {
++            memcpy(buf, in, trailing_len);
++            *buf_len = trailing_len;
++        }
++
++        return written_len;
++    } else {
++        /*
++         * First of all empty the buffer of any partial block that we might
++         * have been provided - both for data and AAD
++         */
++        if (octx->data_buf_len > 0) {
++            if (EVP_CIPHER_CTX_encrypting(ctx)) {
++                if (!CRYPTO_ocb128_encrypt(&octx->ocb, octx->data_buf, out,
++                                           octx->data_buf_len))
++                    return -1;
++            } else {
++                if (!CRYPTO_ocb128_decrypt(&octx->ocb, octx->data_buf, out,
++                                           octx->data_buf_len))
++                    return -1;
++            }
++            written_len = octx->data_buf_len;
++            octx->data_buf_len = 0;
++        }
++        if (octx->aad_buf_len > 0) {
++            if (!CRYPTO_ocb128_aad
++                (&octx->ocb, octx->aad_buf, octx->aad_buf_len))
++                return -1;
++            octx->aad_buf_len = 0;
++        }
++        /* If decrypting then verify */
++        if (!EVP_CIPHER_CTX_encrypting(ctx)) {
++            if (octx->taglen < 0)
++                return -1;
++            if (CRYPTO_ocb128_finish(&octx->ocb,
++                                     octx->tag, octx->taglen) != 0)
++                return -1;
++            octx->iv_set = 0;
++            return written_len;
++        }
++        /* If encrypting then just get the tag */
++        if (CRYPTO_ocb128_tag(&octx->ocb, octx->tag, 16) != 1)
++            return -1;
++        /* Don't reuse the IV */
++        octx->iv_set = 0;
++        return written_len;
++    }
++}
++
++static int aes_ocb_cleanup(EVP_CIPHER_CTX *c)
++{
++    EVP_AES_OCB_CTX *octx = EVP_C_DATA(EVP_AES_OCB_CTX,c);
++    CRYPTO_ocb128_cleanup(&octx->ocb);
++    return 1;
++}
++
++BLOCK_CIPHER_custom(NID_aes, 128, 16, 12, ocb, OCB,
++                    EVP_CIPH_FLAG_AEAD_CIPHER | CUSTOM_FLAGS)
++BLOCK_CIPHER_custom(NID_aes, 192, 16, 12, ocb, OCB,
++                    EVP_CIPH_FLAG_AEAD_CIPHER | CUSTOM_FLAGS)
++BLOCK_CIPHER_custom(NID_aes, 256, 16, 12, ocb, OCB,
++                    EVP_CIPH_FLAG_AEAD_CIPHER | CUSTOM_FLAGS)
++#endif                         /* OPENSSL_NO_OCB */
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/evp/e_aes_cbc_hmac_sha1.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/evp/e_aes_cbc_hmac_sha1.c
+new file mode 100644
+index 0000000..52c7c74
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/evp/e_aes_cbc_hmac_sha1.c
+@@ -0,0 +1,957 @@
++/*
++ * Copyright 2011-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++
++#include 
++#include 
++
++#include 
++#include 
++#include 
++#include 
++#include 
++#include "modes_lcl.h"
++#include "internal/evp_int.h"
++#include "internal/constant_time_locl.h"
++
++typedef struct {
++    AES_KEY ks;
++    SHA_CTX head, tail, md;
++    size_t payload_length;      /* AAD length in decrypt case */
++    union {
++        unsigned int tls_ver;
++        unsigned char tls_aad[16]; /* 13 used */
++    } aux;
++} EVP_AES_HMAC_SHA1;
++
++#define NO_PAYLOAD_LENGTH       ((size_t)-1)
++
++#if     defined(AES_ASM) &&     ( \
++        defined(__x86_64)       || defined(__x86_64__)  || \
++        defined(_M_AMD64)       || defined(_M_X64)      )
++
++extern unsigned int OPENSSL_ia32cap_P[];
++# define AESNI_CAPABLE   (1<<(57-32))
++
++int aesni_set_encrypt_key(const unsigned char *userKey, int bits,
++                          AES_KEY *key);
++int aesni_set_decrypt_key(const unsigned char *userKey, int bits,
++                          AES_KEY *key);
++
++void aesni_cbc_encrypt(const unsigned char *in,
++                       unsigned char *out,
++                       size_t length,
++                       const AES_KEY *key, unsigned char *ivec, int enc);
++
++void aesni_cbc_sha1_enc(const void *inp, void *out, size_t blocks,
++                        const AES_KEY *key, unsigned char iv[16],
++                        SHA_CTX *ctx, const void *in0);
++
++void aesni256_cbc_sha1_dec(const void *inp, void *out, size_t blocks,
++                           const AES_KEY *key, unsigned char iv[16],
++                           SHA_CTX *ctx, const void *in0);
++
++# define data(ctx) ((EVP_AES_HMAC_SHA1 *)EVP_CIPHER_CTX_get_cipher_data(ctx))
++
++static int aesni_cbc_hmac_sha1_init_key(EVP_CIPHER_CTX *ctx,
++                                        const unsigned char *inkey,
++                                        const unsigned char *iv, int enc)
++{
++    EVP_AES_HMAC_SHA1 *key = data(ctx);
++    int ret;
++
++    if (enc)
++        ret = aesni_set_encrypt_key(inkey,
++                                    EVP_CIPHER_CTX_key_length(ctx) * 8,
++                                    &key->ks);
++    else
++        ret = aesni_set_decrypt_key(inkey,
++                                    EVP_CIPHER_CTX_key_length(ctx) * 8,
++                                    &key->ks);
++
++    SHA1_Init(&key->head);      /* handy when benchmarking */
++    key->tail = key->head;
++    key->md = key->head;
++
++    key->payload_length = NO_PAYLOAD_LENGTH;
++
++    return ret < 0 ? 0 : 1;
++}
++
++# define STITCHED_CALL
++# undef  STITCHED_DECRYPT_CALL
++
++# if !defined(STITCHED_CALL)
++#  define aes_off 0
++# endif
++
++void sha1_block_data_order(void *c, const void *p, size_t len);
++
++static void sha1_update(SHA_CTX *c, const void *data, size_t len)
++{
++    const unsigned char *ptr = data;
++    size_t res;
++
++    if ((res = c->num)) {
++        res = SHA_CBLOCK - res;
++        if (len < res)
++            res = len;
++        SHA1_Update(c, ptr, res);
++        ptr += res;
++        len -= res;
++    }
++
++    res = len % SHA_CBLOCK;
++    len -= res;
++
++    if (len) {
++        sha1_block_data_order(c, ptr, len / SHA_CBLOCK);
++
++        ptr += len;
++        c->Nh += len >> 29;
++        c->Nl += len <<= 3;
++        if (c->Nl < (unsigned int)len)
++            c->Nh++;
++    }
++
++    if (res)
++        SHA1_Update(c, ptr, res);
++}
++
++# ifdef SHA1_Update
++#  undef SHA1_Update
++# endif
++# define SHA1_Update sha1_update
++
++# if !defined(OPENSSL_NO_MULTIBLOCK)
++
++typedef struct {
++    unsigned int A[8], B[8], C[8], D[8], E[8];
++} SHA1_MB_CTX;
++typedef struct {
++    const unsigned char *ptr;
++    int blocks;
++} HASH_DESC;
++
++void sha1_multi_block(SHA1_MB_CTX *, const HASH_DESC *, int);
++
++typedef struct {
++    const unsigned char *inp;
++    unsigned char *out;
++    int blocks;
++    u64 iv[2];
++} CIPH_DESC;
++
++void aesni_multi_cbc_encrypt(CIPH_DESC *, void *, int);
++
++static size_t tls1_1_multi_block_encrypt(EVP_AES_HMAC_SHA1 *key,
++                                         unsigned char *out,
++                                         const unsigned char *inp,
++                                         size_t inp_len, int n4x)
++{                               /* n4x is 1 or 2 */
++    HASH_DESC hash_d[8], edges[8];
++    CIPH_DESC ciph_d[8];
++    unsigned char storage[sizeof(SHA1_MB_CTX) + 32];
++    union {
++        u64 q[16];
++        u32 d[32];
++        u8 c[128];
++    } blocks[8];
++    SHA1_MB_CTX *ctx;
++    unsigned int frag, last, packlen, i, x4 = 4 * n4x, minblocks, processed =
++        0;
++    size_t ret = 0;
++    u8 *IVs;
++#  if defined(BSWAP8)
++    u64 seqnum;
++#  endif
++
++    /* ask for IVs in bulk */
++    if (RAND_bytes((IVs = blocks[0].c), 16 * x4) <= 0)
++        return 0;
++
++    ctx = (SHA1_MB_CTX *) (storage + 32 - ((size_t)storage % 32)); /* align */
++
++    frag = (unsigned int)inp_len >> (1 + n4x);
++    last = (unsigned int)inp_len + frag - (frag << (1 + n4x));
++    if (last > frag && ((last + 13 + 9) % 64) < (x4 - 1)) {
++        frag++;
++        last -= x4 - 1;
++    }
++
++    packlen = 5 + 16 + ((frag + 20 + 16) & -16);
++
++    /* populate descriptors with pointers and IVs */
++    hash_d[0].ptr = inp;
++    ciph_d[0].inp = inp;
++    /* 5+16 is place for header and explicit IV */
++    ciph_d[0].out = out + 5 + 16;
++    memcpy(ciph_d[0].out - 16, IVs, 16);
++    memcpy(ciph_d[0].iv, IVs, 16);
++    IVs += 16;
++
++    for (i = 1; i < x4; i++) {
++        ciph_d[i].inp = hash_d[i].ptr = hash_d[i - 1].ptr + frag;
++        ciph_d[i].out = ciph_d[i - 1].out + packlen;
++        memcpy(ciph_d[i].out - 16, IVs, 16);
++        memcpy(ciph_d[i].iv, IVs, 16);
++        IVs += 16;
++    }
++
++#  if defined(BSWAP8)
++    memcpy(blocks[0].c, key->md.data, 8);
++    seqnum = BSWAP8(blocks[0].q[0]);
++#  endif
++    for (i = 0; i < x4; i++) {
++        unsigned int len = (i == (x4 - 1) ? last : frag);
++#  if !defined(BSWAP8)
++        unsigned int carry, j;
++#  endif
++
++        ctx->A[i] = key->md.h0;
++        ctx->B[i] = key->md.h1;
++        ctx->C[i] = key->md.h2;
++        ctx->D[i] = key->md.h3;
++        ctx->E[i] = key->md.h4;
++
++        /* fix seqnum */
++#  if defined(BSWAP8)
++        blocks[i].q[0] = BSWAP8(seqnum + i);
++#  else
++        for (carry = i, j = 8; j--;) {
++            blocks[i].c[j] = ((u8 *)key->md.data)[j] + carry;
++            carry = (blocks[i].c[j] - carry) >> (sizeof(carry) * 8 - 1);
++        }
++#  endif
++        blocks[i].c[8] = ((u8 *)key->md.data)[8];
++        blocks[i].c[9] = ((u8 *)key->md.data)[9];
++        blocks[i].c[10] = ((u8 *)key->md.data)[10];
++        /* fix length */
++        blocks[i].c[11] = (u8)(len >> 8);
++        blocks[i].c[12] = (u8)(len);
++
++        memcpy(blocks[i].c + 13, hash_d[i].ptr, 64 - 13);
++        hash_d[i].ptr += 64 - 13;
++        hash_d[i].blocks = (len - (64 - 13)) / 64;
++
++        edges[i].ptr = blocks[i].c;
++        edges[i].blocks = 1;
++    }
++
++    /* hash 13-byte headers and first 64-13 bytes of inputs */
++    sha1_multi_block(ctx, edges, n4x);
++    /* hash bulk inputs */
++#  define MAXCHUNKSIZE    2048
++#  if     MAXCHUNKSIZE%64
++#   error  "MAXCHUNKSIZE is not divisible by 64"
++#  elif   MAXCHUNKSIZE
++    /*
++     * goal is to minimize pressure on L1 cache by moving in shorter steps,
++     * so that hashed data is still in the cache by the time we encrypt it
++     */
++    minblocks = ((frag <= last ? frag : last) - (64 - 13)) / 64;
++    if (minblocks > MAXCHUNKSIZE / 64) {
++        for (i = 0; i < x4; i++) {
++            edges[i].ptr = hash_d[i].ptr;
++            edges[i].blocks = MAXCHUNKSIZE / 64;
++            ciph_d[i].blocks = MAXCHUNKSIZE / 16;
++        }
++        do {
++            sha1_multi_block(ctx, edges, n4x);
++            aesni_multi_cbc_encrypt(ciph_d, &key->ks, n4x);
++
++            for (i = 0; i < x4; i++) {
++                edges[i].ptr = hash_d[i].ptr += MAXCHUNKSIZE;
++                hash_d[i].blocks -= MAXCHUNKSIZE / 64;
++                edges[i].blocks = MAXCHUNKSIZE / 64;
++                ciph_d[i].inp += MAXCHUNKSIZE;
++                ciph_d[i].out += MAXCHUNKSIZE;
++                ciph_d[i].blocks = MAXCHUNKSIZE / 16;
++                memcpy(ciph_d[i].iv, ciph_d[i].out - 16, 16);
++            }
++            processed += MAXCHUNKSIZE;
++            minblocks -= MAXCHUNKSIZE / 64;
++        } while (minblocks > MAXCHUNKSIZE / 64);
++    }
++#  endif
++#  undef  MAXCHUNKSIZE
++    sha1_multi_block(ctx, hash_d, n4x);
++
++    memset(blocks, 0, sizeof(blocks));
++    for (i = 0; i < x4; i++) {
++        unsigned int len = (i == (x4 - 1) ? last : frag),
++            off = hash_d[i].blocks * 64;
++        const unsigned char *ptr = hash_d[i].ptr + off;
++
++        off = (len - processed) - (64 - 13) - off; /* remainder actually */
++        memcpy(blocks[i].c, ptr, off);
++        blocks[i].c[off] = 0x80;
++        len += 64 + 13;         /* 64 is HMAC header */
++        len *= 8;               /* convert to bits */
++        if (off < (64 - 8)) {
++#  ifdef BSWAP4
++            blocks[i].d[15] = BSWAP4(len);
++#  else
++            PUTU32(blocks[i].c + 60, len);
++#  endif
++            edges[i].blocks = 1;
++        } else {
++#  ifdef BSWAP4
++            blocks[i].d[31] = BSWAP4(len);
++#  else
++            PUTU32(blocks[i].c + 124, len);
++#  endif
++            edges[i].blocks = 2;
++        }
++        edges[i].ptr = blocks[i].c;
++    }
++
++    /* hash input tails and finalize */
++    sha1_multi_block(ctx, edges, n4x);
++
++    memset(blocks, 0, sizeof(blocks));
++    for (i = 0; i < x4; i++) {
++#  ifdef BSWAP4
++        blocks[i].d[0] = BSWAP4(ctx->A[i]);
++        ctx->A[i] = key->tail.h0;
++        blocks[i].d[1] = BSWAP4(ctx->B[i]);
++        ctx->B[i] = key->tail.h1;
++        blocks[i].d[2] = BSWAP4(ctx->C[i]);
++        ctx->C[i] = key->tail.h2;
++        blocks[i].d[3] = BSWAP4(ctx->D[i]);
++        ctx->D[i] = key->tail.h3;
++        blocks[i].d[4] = BSWAP4(ctx->E[i]);
++        ctx->E[i] = key->tail.h4;
++        blocks[i].c[20] = 0x80;
++        blocks[i].d[15] = BSWAP4((64 + 20) * 8);
++#  else
++        PUTU32(blocks[i].c + 0, ctx->A[i]);
++        ctx->A[i] = key->tail.h0;
++        PUTU32(blocks[i].c + 4, ctx->B[i]);
++        ctx->B[i] = key->tail.h1;
++        PUTU32(blocks[i].c + 8, ctx->C[i]);
++        ctx->C[i] = key->tail.h2;
++        PUTU32(blocks[i].c + 12, ctx->D[i]);
++        ctx->D[i] = key->tail.h3;
++        PUTU32(blocks[i].c + 16, ctx->E[i]);
++        ctx->E[i] = key->tail.h4;
++        blocks[i].c[20] = 0x80;
++        PUTU32(blocks[i].c + 60, (64 + 20) * 8);
++#  endif
++        edges[i].ptr = blocks[i].c;
++        edges[i].blocks = 1;
++    }
++
++    /* finalize MACs */
++    sha1_multi_block(ctx, edges, n4x);
++
++    for (i = 0; i < x4; i++) {
++        unsigned int len = (i == (x4 - 1) ? last : frag), pad, j;
++        unsigned char *out0 = out;
++
++        memcpy(ciph_d[i].out, ciph_d[i].inp, len - processed);
++        ciph_d[i].inp = ciph_d[i].out;
++
++        out += 5 + 16 + len;
++
++        /* write MAC */
++        PUTU32(out + 0, ctx->A[i]);
++        PUTU32(out + 4, ctx->B[i]);
++        PUTU32(out + 8, ctx->C[i]);
++        PUTU32(out + 12, ctx->D[i]);
++        PUTU32(out + 16, ctx->E[i]);
++        out += 20;
++        len += 20;
++
++        /* pad */
++        pad = 15 - len % 16;
++        for (j = 0; j <= pad; j++)
++            *(out++) = pad;
++        len += pad + 1;
++
++        ciph_d[i].blocks = (len - processed) / 16;
++        len += 16;              /* account for explicit iv */
++
++        /* arrange header */
++        out0[0] = ((u8 *)key->md.data)[8];
++        out0[1] = ((u8 *)key->md.data)[9];
++        out0[2] = ((u8 *)key->md.data)[10];
++        out0[3] = (u8)(len >> 8);
++        out0[4] = (u8)(len);
++
++        ret += len + 5;
++        inp += frag;
++    }
++
++    aesni_multi_cbc_encrypt(ciph_d, &key->ks, n4x);
++
++    OPENSSL_cleanse(blocks, sizeof(blocks));
++    OPENSSL_cleanse(ctx, sizeof(*ctx));
++
++    return ret;
++}
++# endif
++
++static int aesni_cbc_hmac_sha1_cipher(EVP_CIPHER_CTX *ctx, unsigned char *out,
++                                      const unsigned char *in, size_t len)
++{
++    EVP_AES_HMAC_SHA1 *key = data(ctx);
++    unsigned int l;
++    size_t plen = key->payload_length, iv = 0, /* explicit IV in TLS 1.1 and
++                                                * later */
++        sha_off = 0;
++# if defined(STITCHED_CALL)
++    size_t aes_off = 0, blocks;
++
++    sha_off = SHA_CBLOCK - key->md.num;
++# endif
++
++    key->payload_length = NO_PAYLOAD_LENGTH;
++
++    if (len % AES_BLOCK_SIZE)
++        return 0;
++
++    if (EVP_CIPHER_CTX_encrypting(ctx)) {
++        if (plen == NO_PAYLOAD_LENGTH)
++            plen = len;
++        else if (len !=
++                 ((plen + SHA_DIGEST_LENGTH +
++                   AES_BLOCK_SIZE) & -AES_BLOCK_SIZE))
++            return 0;
++        else if (key->aux.tls_ver >= TLS1_1_VERSION)
++            iv = AES_BLOCK_SIZE;
++
++# if defined(STITCHED_CALL)
++        if (plen > (sha_off + iv)
++            && (blocks = (plen - (sha_off + iv)) / SHA_CBLOCK)) {
++            SHA1_Update(&key->md, in + iv, sha_off);
++
++            aesni_cbc_sha1_enc(in, out, blocks, &key->ks,
++                               EVP_CIPHER_CTX_iv_noconst(ctx),
++                               &key->md, in + iv + sha_off);
++            blocks *= SHA_CBLOCK;
++            aes_off += blocks;
++            sha_off += blocks;
++            key->md.Nh += blocks >> 29;
++            key->md.Nl += blocks <<= 3;
++            if (key->md.Nl < (unsigned int)blocks)
++                key->md.Nh++;
++        } else {
++            sha_off = 0;
++        }
++# endif
++        sha_off += iv;
++        SHA1_Update(&key->md, in + sha_off, plen - sha_off);
++
++        if (plen != len) {      /* "TLS" mode of operation */
++            if (in != out)
++                memcpy(out + aes_off, in + aes_off, plen - aes_off);
++
++            /* calculate HMAC and append it to payload */
++            SHA1_Final(out + plen, &key->md);
++            key->md = key->tail;
++            SHA1_Update(&key->md, out + plen, SHA_DIGEST_LENGTH);
++            SHA1_Final(out + plen, &key->md);
++
++            /* pad the payload|hmac */
++            plen += SHA_DIGEST_LENGTH;
++            for (l = len - plen - 1; plen < len; plen++)
++                out[plen] = l;
++            /* encrypt HMAC|padding at once */
++            aesni_cbc_encrypt(out + aes_off, out + aes_off, len - aes_off,
++                              &key->ks, EVP_CIPHER_CTX_iv_noconst(ctx), 1);
++        } else {
++            aesni_cbc_encrypt(in + aes_off, out + aes_off, len - aes_off,
++                              &key->ks, EVP_CIPHER_CTX_iv_noconst(ctx), 1);
++        }
++    } else {
++        union {
++            unsigned int u[SHA_DIGEST_LENGTH / sizeof(unsigned int)];
++            unsigned char c[32 + SHA_DIGEST_LENGTH];
++        } mac, *pmac;
++
++        /* arrange cache line alignment */
++        pmac = (void *)(((size_t)mac.c + 31) & ((size_t)0 - 32));
++
++        if (plen != NO_PAYLOAD_LENGTH) { /* "TLS" mode of operation */
++            size_t inp_len, mask, j, i;
++            unsigned int res, maxpad, pad, bitlen;
++            int ret = 1;
++            union {
++                unsigned int u[SHA_LBLOCK];
++                unsigned char c[SHA_CBLOCK];
++            } *data = (void *)key->md.data;
++# if defined(STITCHED_DECRYPT_CALL)
++            unsigned char tail_iv[AES_BLOCK_SIZE];
++            int stitch = 0;
++# endif
++
++            if ((key->aux.tls_aad[plen - 4] << 8 | key->aux.tls_aad[plen - 3])
++                >= TLS1_1_VERSION) {
++                if (len < (AES_BLOCK_SIZE + SHA_DIGEST_LENGTH + 1))
++                    return 0;
++
++                /* omit explicit iv */
++                memcpy(EVP_CIPHER_CTX_iv_noconst(ctx), in, AES_BLOCK_SIZE);
++
++                in += AES_BLOCK_SIZE;
++                out += AES_BLOCK_SIZE;
++                len -= AES_BLOCK_SIZE;
++            } else if (len < (SHA_DIGEST_LENGTH + 1))
++                return 0;
++
++# if defined(STITCHED_DECRYPT_CALL)
++            if (len >= 1024 && ctx->key_len == 32) {
++                /* decrypt last block */
++                memcpy(tail_iv, in + len - 2 * AES_BLOCK_SIZE,
++                       AES_BLOCK_SIZE);
++                aesni_cbc_encrypt(in + len - AES_BLOCK_SIZE,
++                                  out + len - AES_BLOCK_SIZE, AES_BLOCK_SIZE,
++                                  &key->ks, tail_iv, 0);
++                stitch = 1;
++            } else
++# endif
++                /* decrypt HMAC|padding at once */
++                aesni_cbc_encrypt(in, out, len, &key->ks,
++                                  EVP_CIPHER_CTX_iv_noconst(ctx), 0);
++
++            /* figure out payload length */
++            pad = out[len - 1];
++            maxpad = len - (SHA_DIGEST_LENGTH + 1);
++            maxpad |= (255 - maxpad) >> (sizeof(maxpad) * 8 - 8);
++            maxpad &= 255;
++
++            ret &= constant_time_ge(maxpad, pad);
++
++            inp_len = len - (SHA_DIGEST_LENGTH + pad + 1);
++            mask = (0 - ((inp_len - len) >> (sizeof(inp_len) * 8 - 1)));
++            inp_len &= mask;
++            ret &= (int)mask;
++
++            key->aux.tls_aad[plen - 2] = inp_len >> 8;
++            key->aux.tls_aad[plen - 1] = inp_len;
++
++            /* calculate HMAC */
++            key->md = key->head;
++            SHA1_Update(&key->md, key->aux.tls_aad, plen);
++
++# if defined(STITCHED_DECRYPT_CALL)
++            if (stitch) {
++                blocks = (len - (256 + 32 + SHA_CBLOCK)) / SHA_CBLOCK;
++                aes_off = len - AES_BLOCK_SIZE - blocks * SHA_CBLOCK;
++                sha_off = SHA_CBLOCK - plen;
++
++                aesni_cbc_encrypt(in, out, aes_off, &key->ks, ctx->iv, 0);
++
++                SHA1_Update(&key->md, out, sha_off);
++                aesni256_cbc_sha1_dec(in + aes_off,
++                                      out + aes_off, blocks, &key->ks,
++                                      ctx->iv, &key->md, out + sha_off);
++
++                sha_off += blocks *= SHA_CBLOCK;
++                out += sha_off;
++                len -= sha_off;
++                inp_len -= sha_off;
++
++                key->md.Nl += (blocks << 3); /* at most 18 bits */
++                memcpy(ctx->iv, tail_iv, AES_BLOCK_SIZE);
++            }
++# endif
++
++# if 1
++            len -= SHA_DIGEST_LENGTH; /* amend mac */
++            if (len >= (256 + SHA_CBLOCK)) {
++                j = (len - (256 + SHA_CBLOCK)) & (0 - SHA_CBLOCK);
++                j += SHA_CBLOCK - key->md.num;
++                SHA1_Update(&key->md, out, j);
++                out += j;
++                len -= j;
++                inp_len -= j;
++            }
++
++            /* but pretend as if we hashed padded payload */
++            bitlen = key->md.Nl + (inp_len << 3); /* at most 18 bits */
++#  ifdef BSWAP4
++            bitlen = BSWAP4(bitlen);
++#  else
++            mac.c[0] = 0;
++            mac.c[1] = (unsigned char)(bitlen >> 16);
++            mac.c[2] = (unsigned char)(bitlen >> 8);
++            mac.c[3] = (unsigned char)bitlen;
++            bitlen = mac.u[0];
++#  endif
++
++            pmac->u[0] = 0;
++            pmac->u[1] = 0;
++            pmac->u[2] = 0;
++            pmac->u[3] = 0;
++            pmac->u[4] = 0;
++
++            for (res = key->md.num, j = 0; j < len; j++) {
++                size_t c = out[j];
++                mask = (j - inp_len) >> (sizeof(j) * 8 - 8);
++                c &= mask;
++                c |= 0x80 & ~mask & ~((inp_len - j) >> (sizeof(j) * 8 - 8));
++                data->c[res++] = (unsigned char)c;
++
++                if (res != SHA_CBLOCK)
++                    continue;
++
++                /* j is not incremented yet */
++                mask = 0 - ((inp_len + 7 - j) >> (sizeof(j) * 8 - 1));
++                data->u[SHA_LBLOCK - 1] |= bitlen & mask;
++                sha1_block_data_order(&key->md, data, 1);
++                mask &= 0 - ((j - inp_len - 72) >> (sizeof(j) * 8 - 1));
++                pmac->u[0] |= key->md.h0 & mask;
++                pmac->u[1] |= key->md.h1 & mask;
++                pmac->u[2] |= key->md.h2 & mask;
++                pmac->u[3] |= key->md.h3 & mask;
++                pmac->u[4] |= key->md.h4 & mask;
++                res = 0;
++            }
++
++            for (i = res; i < SHA_CBLOCK; i++, j++)
++                data->c[i] = 0;
++
++            if (res > SHA_CBLOCK - 8) {
++                mask = 0 - ((inp_len + 8 - j) >> (sizeof(j) * 8 - 1));
++                data->u[SHA_LBLOCK - 1] |= bitlen & mask;
++                sha1_block_data_order(&key->md, data, 1);
++                mask &= 0 - ((j - inp_len - 73) >> (sizeof(j) * 8 - 1));
++                pmac->u[0] |= key->md.h0 & mask;
++                pmac->u[1] |= key->md.h1 & mask;
++                pmac->u[2] |= key->md.h2 & mask;
++                pmac->u[3] |= key->md.h3 & mask;
++                pmac->u[4] |= key->md.h4 & mask;
++
++                memset(data, 0, SHA_CBLOCK);
++                j += 64;
++            }
++            data->u[SHA_LBLOCK - 1] = bitlen;
++            sha1_block_data_order(&key->md, data, 1);
++            mask = 0 - ((j - inp_len - 73) >> (sizeof(j) * 8 - 1));
++            pmac->u[0] |= key->md.h0 & mask;
++            pmac->u[1] |= key->md.h1 & mask;
++            pmac->u[2] |= key->md.h2 & mask;
++            pmac->u[3] |= key->md.h3 & mask;
++            pmac->u[4] |= key->md.h4 & mask;
++
++#  ifdef BSWAP4
++            pmac->u[0] = BSWAP4(pmac->u[0]);
++            pmac->u[1] = BSWAP4(pmac->u[1]);
++            pmac->u[2] = BSWAP4(pmac->u[2]);
++            pmac->u[3] = BSWAP4(pmac->u[3]);
++            pmac->u[4] = BSWAP4(pmac->u[4]);
++#  else
++            for (i = 0; i < 5; i++) {
++                res = pmac->u[i];
++                pmac->c[4 * i + 0] = (unsigned char)(res >> 24);
++                pmac->c[4 * i + 1] = (unsigned char)(res >> 16);
++                pmac->c[4 * i + 2] = (unsigned char)(res >> 8);
++                pmac->c[4 * i + 3] = (unsigned char)res;
++            }
++#  endif
++            len += SHA_DIGEST_LENGTH;
++# else
++            SHA1_Update(&key->md, out, inp_len);
++            res = key->md.num;
++            SHA1_Final(pmac->c, &key->md);
++
++            {
++                unsigned int inp_blocks, pad_blocks;
++
++                /* but pretend as if we hashed padded payload */
++                inp_blocks =
++                    1 + ((SHA_CBLOCK - 9 - res) >> (sizeof(res) * 8 - 1));
++                res += (unsigned int)(len - inp_len);
++                pad_blocks = res / SHA_CBLOCK;
++                res %= SHA_CBLOCK;
++                pad_blocks +=
++                    1 + ((SHA_CBLOCK - 9 - res) >> (sizeof(res) * 8 - 1));
++                for (; inp_blocks < pad_blocks; inp_blocks++)
++                    sha1_block_data_order(&key->md, data, 1);
++            }
++# endif
++            key->md = key->tail;
++            SHA1_Update(&key->md, pmac->c, SHA_DIGEST_LENGTH);
++            SHA1_Final(pmac->c, &key->md);
++
++            /* verify HMAC */
++            out += inp_len;
++            len -= inp_len;
++# if 1
++            {
++                unsigned char *p = out + len - 1 - maxpad - SHA_DIGEST_LENGTH;
++                size_t off = out - p;
++                unsigned int c, cmask;
++
++                maxpad += SHA_DIGEST_LENGTH;
++                for (res = 0, i = 0, j = 0; j < maxpad; j++) {
++                    c = p[j];
++                    cmask =
++                        ((int)(j - off - SHA_DIGEST_LENGTH)) >> (sizeof(int) *
++                                                                 8 - 1);
++                    res |= (c ^ pad) & ~cmask; /* ... and padding */
++                    cmask &= ((int)(off - 1 - j)) >> (sizeof(int) * 8 - 1);
++                    res |= (c ^ pmac->c[i]) & cmask;
++                    i += 1 & cmask;
++                }
++                maxpad -= SHA_DIGEST_LENGTH;
++
++                res = 0 - ((0 - res) >> (sizeof(res) * 8 - 1));
++                ret &= (int)~res;
++            }
++# else
++            for (res = 0, i = 0; i < SHA_DIGEST_LENGTH; i++)
++                res |= out[i] ^ pmac->c[i];
++            res = 0 - ((0 - res) >> (sizeof(res) * 8 - 1));
++            ret &= (int)~res;
++
++            /* verify padding */
++            pad = (pad & ~res) | (maxpad & res);
++            out = out + len - 1 - pad;
++            for (res = 0, i = 0; i < pad; i++)
++                res |= out[i] ^ pad;
++
++            res = (0 - res) >> (sizeof(res) * 8 - 1);
++            ret &= (int)~res;
++# endif
++            return ret;
++        } else {
++# if defined(STITCHED_DECRYPT_CALL)
++            if (len >= 1024 && ctx->key_len == 32) {
++                if (sha_off %= SHA_CBLOCK)
++                    blocks = (len - 3 * SHA_CBLOCK) / SHA_CBLOCK;
++                else
++                    blocks = (len - 2 * SHA_CBLOCK) / SHA_CBLOCK;
++                aes_off = len - blocks * SHA_CBLOCK;
++
++                aesni_cbc_encrypt(in, out, aes_off, &key->ks, ctx->iv, 0);
++                SHA1_Update(&key->md, out, sha_off);
++                aesni256_cbc_sha1_dec(in + aes_off,
++                                      out + aes_off, blocks, &key->ks,
++                                      ctx->iv, &key->md, out + sha_off);
++
++                sha_off += blocks *= SHA_CBLOCK;
++                out += sha_off;
++                len -= sha_off;
++
++                key->md.Nh += blocks >> 29;
++                key->md.Nl += blocks <<= 3;
++                if (key->md.Nl < (unsigned int)blocks)
++                    key->md.Nh++;
++            } else
++# endif
++                /* decrypt HMAC|padding at once */
++                aesni_cbc_encrypt(in, out, len, &key->ks,
++                                  EVP_CIPHER_CTX_iv_noconst(ctx), 0);
++
++            SHA1_Update(&key->md, out, len);
++        }
++    }
++
++    return 1;
++}
++
++static int aesni_cbc_hmac_sha1_ctrl(EVP_CIPHER_CTX *ctx, int type, int arg,
++                                    void *ptr)
++{
++    EVP_AES_HMAC_SHA1 *key = data(ctx);
++
++    switch (type) {
++    case EVP_CTRL_AEAD_SET_MAC_KEY:
++        {
++            unsigned int i;
++            unsigned char hmac_key[64];
++
++            memset(hmac_key, 0, sizeof(hmac_key));
++
++            if (arg > (int)sizeof(hmac_key)) {
++                SHA1_Init(&key->head);
++                SHA1_Update(&key->head, ptr, arg);
++                SHA1_Final(hmac_key, &key->head);
++            } else {
++                memcpy(hmac_key, ptr, arg);
++            }
++
++            for (i = 0; i < sizeof(hmac_key); i++)
++                hmac_key[i] ^= 0x36; /* ipad */
++            SHA1_Init(&key->head);
++            SHA1_Update(&key->head, hmac_key, sizeof(hmac_key));
++
++            for (i = 0; i < sizeof(hmac_key); i++)
++                hmac_key[i] ^= 0x36 ^ 0x5c; /* opad */
++            SHA1_Init(&key->tail);
++            SHA1_Update(&key->tail, hmac_key, sizeof(hmac_key));
++
++            OPENSSL_cleanse(hmac_key, sizeof(hmac_key));
++
++            return 1;
++        }
++    case EVP_CTRL_AEAD_TLS1_AAD:
++        {
++            unsigned char *p = ptr;
++            unsigned int len;
++
++            if (arg != EVP_AEAD_TLS1_AAD_LEN)
++                return -1;
++
++            len = p[arg - 2] << 8 | p[arg - 1];
++
++            if (EVP_CIPHER_CTX_encrypting(ctx)) {
++                key->payload_length = len;
++                if ((key->aux.tls_ver =
++                     p[arg - 4] << 8 | p[arg - 3]) >= TLS1_1_VERSION) {
++                    len -= AES_BLOCK_SIZE;
++                    p[arg - 2] = len >> 8;
++                    p[arg - 1] = len;
++                }
++                key->md = key->head;
++                SHA1_Update(&key->md, p, arg);
++
++                return (int)(((len + SHA_DIGEST_LENGTH +
++                               AES_BLOCK_SIZE) & -AES_BLOCK_SIZE)
++                             - len);
++            } else {
++                memcpy(key->aux.tls_aad, ptr, arg);
++                key->payload_length = arg;
++
++                return SHA_DIGEST_LENGTH;
++            }
++        }
++# if !defined(OPENSSL_NO_MULTIBLOCK)
++    case EVP_CTRL_TLS1_1_MULTIBLOCK_MAX_BUFSIZE:
++        return (int)(5 + 16 + ((arg + 20 + 16) & -16));
++    case EVP_CTRL_TLS1_1_MULTIBLOCK_AAD:
++        {
++            EVP_CTRL_TLS1_1_MULTIBLOCK_PARAM *param =
++                (EVP_CTRL_TLS1_1_MULTIBLOCK_PARAM *) ptr;
++            unsigned int n4x = 1, x4;
++            unsigned int frag, last, packlen, inp_len;
++
++            if (arg < (int)sizeof(EVP_CTRL_TLS1_1_MULTIBLOCK_PARAM))
++                return -1;
++
++            inp_len = param->inp[11] << 8 | param->inp[12];
++
++            if (EVP_CIPHER_CTX_encrypting(ctx)) {
++                if ((param->inp[9] << 8 | param->inp[10]) < TLS1_1_VERSION)
++                    return -1;
++
++                if (inp_len) {
++                    if (inp_len < 4096)
++                        return 0; /* too short */
++
++                    if (inp_len >= 8192 && OPENSSL_ia32cap_P[2] & (1 << 5))
++                        n4x = 2; /* AVX2 */
++                } else if ((n4x = param->interleave / 4) && n4x <= 2)
++                    inp_len = param->len;
++                else
++                    return -1;
++
++                key->md = key->head;
++                SHA1_Update(&key->md, param->inp, 13);
++
++                x4 = 4 * n4x;
++                n4x += 1;
++
++                frag = inp_len >> n4x;
++                last = inp_len + frag - (frag << n4x);
++                if (last > frag && ((last + 13 + 9) % 64 < (x4 - 1))) {
++                    frag++;
++                    last -= x4 - 1;
++                }
++
++                packlen = 5 + 16 + ((frag + 20 + 16) & -16);
++                packlen = (packlen << n4x) - packlen;
++                packlen += 5 + 16 + ((last + 20 + 16) & -16);
++
++                param->interleave = x4;
++
++                return (int)packlen;
++            } else
++                return -1;      /* not yet */
++        }
++    case EVP_CTRL_TLS1_1_MULTIBLOCK_ENCRYPT:
++        {
++            EVP_CTRL_TLS1_1_MULTIBLOCK_PARAM *param =
++                (EVP_CTRL_TLS1_1_MULTIBLOCK_PARAM *) ptr;
++
++            return (int)tls1_1_multi_block_encrypt(key, param->out,
++                                                   param->inp, param->len,
++                                                   param->interleave / 4);
++        }
++    case EVP_CTRL_TLS1_1_MULTIBLOCK_DECRYPT:
++# endif
++    default:
++        return -1;
++    }
++}
++
++static EVP_CIPHER aesni_128_cbc_hmac_sha1_cipher = {
++# ifdef NID_aes_128_cbc_hmac_sha1
++    NID_aes_128_cbc_hmac_sha1,
++# else
++    NID_undef,
++# endif
++    AES_BLOCK_SIZE, 16, AES_BLOCK_SIZE,
++    EVP_CIPH_CBC_MODE | EVP_CIPH_FLAG_DEFAULT_ASN1 |
++        EVP_CIPH_FLAG_AEAD_CIPHER | EVP_CIPH_FLAG_TLS1_1_MULTIBLOCK,
++    aesni_cbc_hmac_sha1_init_key,
++    aesni_cbc_hmac_sha1_cipher,
++    NULL,
++    sizeof(EVP_AES_HMAC_SHA1),
++    EVP_CIPH_FLAG_DEFAULT_ASN1 ? NULL : EVP_CIPHER_set_asn1_iv,
++    EVP_CIPH_FLAG_DEFAULT_ASN1 ? NULL : EVP_CIPHER_get_asn1_iv,
++    aesni_cbc_hmac_sha1_ctrl,
++    NULL
++};
++
++static EVP_CIPHER aesni_256_cbc_hmac_sha1_cipher = {
++# ifdef NID_aes_256_cbc_hmac_sha1
++    NID_aes_256_cbc_hmac_sha1,
++# else
++    NID_undef,
++# endif
++    AES_BLOCK_SIZE, 32, AES_BLOCK_SIZE,
++    EVP_CIPH_CBC_MODE | EVP_CIPH_FLAG_DEFAULT_ASN1 |
++        EVP_CIPH_FLAG_AEAD_CIPHER | EVP_CIPH_FLAG_TLS1_1_MULTIBLOCK,
++    aesni_cbc_hmac_sha1_init_key,
++    aesni_cbc_hmac_sha1_cipher,
++    NULL,
++    sizeof(EVP_AES_HMAC_SHA1),
++    EVP_CIPH_FLAG_DEFAULT_ASN1 ? NULL : EVP_CIPHER_set_asn1_iv,
++    EVP_CIPH_FLAG_DEFAULT_ASN1 ? NULL : EVP_CIPHER_get_asn1_iv,
++    aesni_cbc_hmac_sha1_ctrl,
++    NULL
++};
++
++const EVP_CIPHER *EVP_aes_128_cbc_hmac_sha1(void)
++{
++    return (OPENSSL_ia32cap_P[1] & AESNI_CAPABLE ?
++            &aesni_128_cbc_hmac_sha1_cipher : NULL);
++}
++
++const EVP_CIPHER *EVP_aes_256_cbc_hmac_sha1(void)
++{
++    return (OPENSSL_ia32cap_P[1] & AESNI_CAPABLE ?
++            &aesni_256_cbc_hmac_sha1_cipher : NULL);
++}
++#else
++const EVP_CIPHER *EVP_aes_128_cbc_hmac_sha1(void)
++{
++    return NULL;
++}
++
++const EVP_CIPHER *EVP_aes_256_cbc_hmac_sha1(void)
++{
++    return NULL;
++}
++#endif
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/evp/e_aes_cbc_hmac_sha256.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/evp/e_aes_cbc_hmac_sha256.c
+new file mode 100644
+index 0000000..5a92e0b
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/evp/e_aes_cbc_hmac_sha256.c
+@@ -0,0 +1,939 @@
++/*
++ * Copyright 2013-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++
++#include 
++#include 
++
++
++#include 
++#include 
++#include 
++#include 
++#include 
++#include "modes_lcl.h"
++#include "internal/constant_time_locl.h"
++#include "internal/evp_int.h"
++
++typedef struct {
++    AES_KEY ks;
++    SHA256_CTX head, tail, md;
++    size_t payload_length;      /* AAD length in decrypt case */
++    union {
++        unsigned int tls_ver;
++        unsigned char tls_aad[16]; /* 13 used */
++    } aux;
++} EVP_AES_HMAC_SHA256;
++
++# define NO_PAYLOAD_LENGTH       ((size_t)-1)
++
++#if     defined(AES_ASM) &&     ( \
++        defined(__x86_64)       || defined(__x86_64__)  || \
++        defined(_M_AMD64)       || defined(_M_X64)      )
++
++extern unsigned int OPENSSL_ia32cap_P[];
++# define AESNI_CAPABLE   (1<<(57-32))
++
++int aesni_set_encrypt_key(const unsigned char *userKey, int bits,
++                          AES_KEY *key);
++int aesni_set_decrypt_key(const unsigned char *userKey, int bits,
++                          AES_KEY *key);
++
++void aesni_cbc_encrypt(const unsigned char *in,
++                       unsigned char *out,
++                       size_t length,
++                       const AES_KEY *key, unsigned char *ivec, int enc);
++
++int aesni_cbc_sha256_enc(const void *inp, void *out, size_t blocks,
++                         const AES_KEY *key, unsigned char iv[16],
++                         SHA256_CTX *ctx, const void *in0);
++
++# define data(ctx) ((EVP_AES_HMAC_SHA256 *)EVP_CIPHER_CTX_get_cipher_data(ctx))
++
++static int aesni_cbc_hmac_sha256_init_key(EVP_CIPHER_CTX *ctx,
++                                          const unsigned char *inkey,
++                                          const unsigned char *iv, int enc)
++{
++    EVP_AES_HMAC_SHA256 *key = data(ctx);
++    int ret;
++
++    if (enc)
++        ret = aesni_set_encrypt_key(inkey,
++                                    EVP_CIPHER_CTX_key_length(ctx) * 8,
++                                    &key->ks);
++    else
++        ret = aesni_set_decrypt_key(inkey,
++                                    EVP_CIPHER_CTX_key_length(ctx) * 8,
++                                    &key->ks);
++
++    SHA256_Init(&key->head);    /* handy when benchmarking */
++    key->tail = key->head;
++    key->md = key->head;
++
++    key->payload_length = NO_PAYLOAD_LENGTH;
++
++    return ret < 0 ? 0 : 1;
++}
++
++# define STITCHED_CALL
++
++# if !defined(STITCHED_CALL)
++#  define aes_off 0
++# endif
++
++void sha256_block_data_order(void *c, const void *p, size_t len);
++
++static void sha256_update(SHA256_CTX *c, const void *data, size_t len)
++{
++    const unsigned char *ptr = data;
++    size_t res;
++
++    if ((res = c->num)) {
++        res = SHA256_CBLOCK - res;
++        if (len < res)
++            res = len;
++        SHA256_Update(c, ptr, res);
++        ptr += res;
++        len -= res;
++    }
++
++    res = len % SHA256_CBLOCK;
++    len -= res;
++
++    if (len) {
++        sha256_block_data_order(c, ptr, len / SHA256_CBLOCK);
++
++        ptr += len;
++        c->Nh += len >> 29;
++        c->Nl += len <<= 3;
++        if (c->Nl < (unsigned int)len)
++            c->Nh++;
++    }
++
++    if (res)
++        SHA256_Update(c, ptr, res);
++}
++
++# ifdef SHA256_Update
++#  undef SHA256_Update
++# endif
++# define SHA256_Update sha256_update
++
++# if !defined(OPENSSL_NO_MULTIBLOCK)
++
++typedef struct {
++    unsigned int A[8], B[8], C[8], D[8], E[8], F[8], G[8], H[8];
++} SHA256_MB_CTX;
++typedef struct {
++    const unsigned char *ptr;
++    int blocks;
++} HASH_DESC;
++
++void sha256_multi_block(SHA256_MB_CTX *, const HASH_DESC *, int);
++
++typedef struct {
++    const unsigned char *inp;
++    unsigned char *out;
++    int blocks;
++    u64 iv[2];
++} CIPH_DESC;
++
++void aesni_multi_cbc_encrypt(CIPH_DESC *, void *, int);
++
++static size_t tls1_1_multi_block_encrypt(EVP_AES_HMAC_SHA256 *key,
++                                         unsigned char *out,
++                                         const unsigned char *inp,
++                                         size_t inp_len, int n4x)
++{                               /* n4x is 1 or 2 */
++    HASH_DESC hash_d[8], edges[8];
++    CIPH_DESC ciph_d[8];
++    unsigned char storage[sizeof(SHA256_MB_CTX) + 32];
++    union {
++        u64 q[16];
++        u32 d[32];
++        u8 c[128];
++    } blocks[8];
++    SHA256_MB_CTX *ctx;
++    unsigned int frag, last, packlen, i, x4 = 4 * n4x, minblocks, processed =
++        0;
++    size_t ret = 0;
++    u8 *IVs;
++#  if defined(BSWAP8)
++    u64 seqnum;
++#  endif
++
++    /* ask for IVs in bulk */
++    if (RAND_bytes((IVs = blocks[0].c), 16 * x4) <= 0)
++        return 0;
++
++    /* align */
++    ctx = (SHA256_MB_CTX *) (storage + 32 - ((size_t)storage % 32));
++
++    frag = (unsigned int)inp_len >> (1 + n4x);
++    last = (unsigned int)inp_len + frag - (frag << (1 + n4x));
++    if (last > frag && ((last + 13 + 9) % 64) < (x4 - 1)) {
++        frag++;
++        last -= x4 - 1;
++    }
++
++    packlen = 5 + 16 + ((frag + 32 + 16) & -16);
++
++    /* populate descriptors with pointers and IVs */
++    hash_d[0].ptr = inp;
++    ciph_d[0].inp = inp;
++    /* 5+16 is place for header and explicit IV */
++    ciph_d[0].out = out + 5 + 16;
++    memcpy(ciph_d[0].out - 16, IVs, 16);
++    memcpy(ciph_d[0].iv, IVs, 16);
++    IVs += 16;
++
++    for (i = 1; i < x4; i++) {
++        ciph_d[i].inp = hash_d[i].ptr = hash_d[i - 1].ptr + frag;
++        ciph_d[i].out = ciph_d[i - 1].out + packlen;
++        memcpy(ciph_d[i].out - 16, IVs, 16);
++        memcpy(ciph_d[i].iv, IVs, 16);
++        IVs += 16;
++    }
++
++#  if defined(BSWAP8)
++    memcpy(blocks[0].c, key->md.data, 8);
++    seqnum = BSWAP8(blocks[0].q[0]);
++#  endif
++    for (i = 0; i < x4; i++) {
++        unsigned int len = (i == (x4 - 1) ? last : frag);
++#  if !defined(BSWAP8)
++        unsigned int carry, j;
++#  endif
++
++        ctx->A[i] = key->md.h[0];
++        ctx->B[i] = key->md.h[1];
++        ctx->C[i] = key->md.h[2];
++        ctx->D[i] = key->md.h[3];
++        ctx->E[i] = key->md.h[4];
++        ctx->F[i] = key->md.h[5];
++        ctx->G[i] = key->md.h[6];
++        ctx->H[i] = key->md.h[7];
++
++        /* fix seqnum */
++#  if defined(BSWAP8)
++        blocks[i].q[0] = BSWAP8(seqnum + i);
++#  else
++        for (carry = i, j = 8; j--;) {
++            blocks[i].c[j] = ((u8 *)key->md.data)[j] + carry;
++            carry = (blocks[i].c[j] - carry) >> (sizeof(carry) * 8 - 1);
++        }
++#  endif
++        blocks[i].c[8] = ((u8 *)key->md.data)[8];
++        blocks[i].c[9] = ((u8 *)key->md.data)[9];
++        blocks[i].c[10] = ((u8 *)key->md.data)[10];
++        /* fix length */
++        blocks[i].c[11] = (u8)(len >> 8);
++        blocks[i].c[12] = (u8)(len);
++
++        memcpy(blocks[i].c + 13, hash_d[i].ptr, 64 - 13);
++        hash_d[i].ptr += 64 - 13;
++        hash_d[i].blocks = (len - (64 - 13)) / 64;
++
++        edges[i].ptr = blocks[i].c;
++        edges[i].blocks = 1;
++    }
++
++    /* hash 13-byte headers and first 64-13 bytes of inputs */
++    sha256_multi_block(ctx, edges, n4x);
++    /* hash bulk inputs */
++#  define MAXCHUNKSIZE    2048
++#  if     MAXCHUNKSIZE%64
++#   error  "MAXCHUNKSIZE is not divisible by 64"
++#  elif   MAXCHUNKSIZE
++    /*
++     * goal is to minimize pressure on L1 cache by moving in shorter steps,
++     * so that hashed data is still in the cache by the time we encrypt it
++     */
++    minblocks = ((frag <= last ? frag : last) - (64 - 13)) / 64;
++    if (minblocks > MAXCHUNKSIZE / 64) {
++        for (i = 0; i < x4; i++) {
++            edges[i].ptr = hash_d[i].ptr;
++            edges[i].blocks = MAXCHUNKSIZE / 64;
++            ciph_d[i].blocks = MAXCHUNKSIZE / 16;
++        }
++        do {
++            sha256_multi_block(ctx, edges, n4x);
++            aesni_multi_cbc_encrypt(ciph_d, &key->ks, n4x);
++
++            for (i = 0; i < x4; i++) {
++                edges[i].ptr = hash_d[i].ptr += MAXCHUNKSIZE;
++                hash_d[i].blocks -= MAXCHUNKSIZE / 64;
++                edges[i].blocks = MAXCHUNKSIZE / 64;
++                ciph_d[i].inp += MAXCHUNKSIZE;
++                ciph_d[i].out += MAXCHUNKSIZE;
++                ciph_d[i].blocks = MAXCHUNKSIZE / 16;
++                memcpy(ciph_d[i].iv, ciph_d[i].out - 16, 16);
++            }
++            processed += MAXCHUNKSIZE;
++            minblocks -= MAXCHUNKSIZE / 64;
++        } while (minblocks > MAXCHUNKSIZE / 64);
++    }
++#  endif
++#  undef  MAXCHUNKSIZE
++    sha256_multi_block(ctx, hash_d, n4x);
++
++    memset(blocks, 0, sizeof(blocks));
++    for (i = 0; i < x4; i++) {
++        unsigned int len = (i == (x4 - 1) ? last : frag),
++            off = hash_d[i].blocks * 64;
++        const unsigned char *ptr = hash_d[i].ptr + off;
++
++        off = (len - processed) - (64 - 13) - off; /* remainder actually */
++        memcpy(blocks[i].c, ptr, off);
++        blocks[i].c[off] = 0x80;
++        len += 64 + 13;         /* 64 is HMAC header */
++        len *= 8;               /* convert to bits */
++        if (off < (64 - 8)) {
++#  ifdef BSWAP4
++            blocks[i].d[15] = BSWAP4(len);
++#  else
++            PUTU32(blocks[i].c + 60, len);
++#  endif
++            edges[i].blocks = 1;
++        } else {
++#  ifdef BSWAP4
++            blocks[i].d[31] = BSWAP4(len);
++#  else
++            PUTU32(blocks[i].c + 124, len);
++#  endif
++            edges[i].blocks = 2;
++        }
++        edges[i].ptr = blocks[i].c;
++    }
++
++    /* hash input tails and finalize */
++    sha256_multi_block(ctx, edges, n4x);
++
++    memset(blocks, 0, sizeof(blocks));
++    for (i = 0; i < x4; i++) {
++#  ifdef BSWAP4
++        blocks[i].d[0] = BSWAP4(ctx->A[i]);
++        ctx->A[i] = key->tail.h[0];
++        blocks[i].d[1] = BSWAP4(ctx->B[i]);
++        ctx->B[i] = key->tail.h[1];
++        blocks[i].d[2] = BSWAP4(ctx->C[i]);
++        ctx->C[i] = key->tail.h[2];
++        blocks[i].d[3] = BSWAP4(ctx->D[i]);
++        ctx->D[i] = key->tail.h[3];
++        blocks[i].d[4] = BSWAP4(ctx->E[i]);
++        ctx->E[i] = key->tail.h[4];
++        blocks[i].d[5] = BSWAP4(ctx->F[i]);
++        ctx->F[i] = key->tail.h[5];
++        blocks[i].d[6] = BSWAP4(ctx->G[i]);
++        ctx->G[i] = key->tail.h[6];
++        blocks[i].d[7] = BSWAP4(ctx->H[i]);
++        ctx->H[i] = key->tail.h[7];
++        blocks[i].c[32] = 0x80;
++        blocks[i].d[15] = BSWAP4((64 + 32) * 8);
++#  else
++        PUTU32(blocks[i].c + 0, ctx->A[i]);
++        ctx->A[i] = key->tail.h[0];
++        PUTU32(blocks[i].c + 4, ctx->B[i]);
++        ctx->B[i] = key->tail.h[1];
++        PUTU32(blocks[i].c + 8, ctx->C[i]);
++        ctx->C[i] = key->tail.h[2];
++        PUTU32(blocks[i].c + 12, ctx->D[i]);
++        ctx->D[i] = key->tail.h[3];
++        PUTU32(blocks[i].c + 16, ctx->E[i]);
++        ctx->E[i] = key->tail.h[4];
++        PUTU32(blocks[i].c + 20, ctx->F[i]);
++        ctx->F[i] = key->tail.h[5];
++        PUTU32(blocks[i].c + 24, ctx->G[i]);
++        ctx->G[i] = key->tail.h[6];
++        PUTU32(blocks[i].c + 28, ctx->H[i]);
++        ctx->H[i] = key->tail.h[7];
++        blocks[i].c[32] = 0x80;
++        PUTU32(blocks[i].c + 60, (64 + 32) * 8);
++#  endif
++        edges[i].ptr = blocks[i].c;
++        edges[i].blocks = 1;
++    }
++
++    /* finalize MACs */
++    sha256_multi_block(ctx, edges, n4x);
++
++    for (i = 0; i < x4; i++) {
++        unsigned int len = (i == (x4 - 1) ? last : frag), pad, j;
++        unsigned char *out0 = out;
++
++        memcpy(ciph_d[i].out, ciph_d[i].inp, len - processed);
++        ciph_d[i].inp = ciph_d[i].out;
++
++        out += 5 + 16 + len;
++
++        /* write MAC */
++        PUTU32(out + 0, ctx->A[i]);
++        PUTU32(out + 4, ctx->B[i]);
++        PUTU32(out + 8, ctx->C[i]);
++        PUTU32(out + 12, ctx->D[i]);
++        PUTU32(out + 16, ctx->E[i]);
++        PUTU32(out + 20, ctx->F[i]);
++        PUTU32(out + 24, ctx->G[i]);
++        PUTU32(out + 28, ctx->H[i]);
++        out += 32;
++        len += 32;
++
++        /* pad */
++        pad = 15 - len % 16;
++        for (j = 0; j <= pad; j++)
++            *(out++) = pad;
++        len += pad + 1;
++
++        ciph_d[i].blocks = (len - processed) / 16;
++        len += 16;              /* account for explicit iv */
++
++        /* arrange header */
++        out0[0] = ((u8 *)key->md.data)[8];
++        out0[1] = ((u8 *)key->md.data)[9];
++        out0[2] = ((u8 *)key->md.data)[10];
++        out0[3] = (u8)(len >> 8);
++        out0[4] = (u8)(len);
++
++        ret += len + 5;
++        inp += frag;
++    }
++
++    aesni_multi_cbc_encrypt(ciph_d, &key->ks, n4x);
++
++    OPENSSL_cleanse(blocks, sizeof(blocks));
++    OPENSSL_cleanse(ctx, sizeof(*ctx));
++
++    return ret;
++}
++# endif
++
++static int aesni_cbc_hmac_sha256_cipher(EVP_CIPHER_CTX *ctx,
++                                        unsigned char *out,
++                                        const unsigned char *in, size_t len)
++{
++    EVP_AES_HMAC_SHA256 *key = data(ctx);
++    unsigned int l;
++    size_t plen = key->payload_length, iv = 0, /* explicit IV in TLS 1.1 and
++                                                * later */
++        sha_off = 0;
++# if defined(STITCHED_CALL)
++    size_t aes_off = 0, blocks;
++
++    sha_off = SHA256_CBLOCK - key->md.num;
++# endif
++
++    key->payload_length = NO_PAYLOAD_LENGTH;
++
++    if (len % AES_BLOCK_SIZE)
++        return 0;
++
++    if (EVP_CIPHER_CTX_encrypting(ctx)) {
++        if (plen == NO_PAYLOAD_LENGTH)
++            plen = len;
++        else if (len !=
++                 ((plen + SHA256_DIGEST_LENGTH +
++                   AES_BLOCK_SIZE) & -AES_BLOCK_SIZE))
++            return 0;
++        else if (key->aux.tls_ver >= TLS1_1_VERSION)
++            iv = AES_BLOCK_SIZE;
++
++# if defined(STITCHED_CALL)
++        /*
++         * Assembly stitch handles AVX-capable processors, but its
++         * performance is not optimal on AMD Jaguar, ~40% worse, for
++         * unknown reasons. Incidentally processor in question supports
++         * AVX, but not AMD-specific XOP extension, which can be used
++         * to identify it and avoid stitch invocation. So that after we
++         * establish that current CPU supports AVX, we even see if it's
++         * either even XOP-capable Bulldozer-based or GenuineIntel one.
++         */
++        if (OPENSSL_ia32cap_P[1] & (1 << (60 - 32)) && /* AVX? */
++            ((OPENSSL_ia32cap_P[1] & (1 << (43 - 32))) /* XOP? */
++             | (OPENSSL_ia32cap_P[0] & (1<<30))) &&    /* "Intel CPU"? */
++            plen > (sha_off + iv) &&
++            (blocks = (plen - (sha_off + iv)) / SHA256_CBLOCK)) {
++            SHA256_Update(&key->md, in + iv, sha_off);
++
++            (void)aesni_cbc_sha256_enc(in, out, blocks, &key->ks,
++                                       EVP_CIPHER_CTX_iv_noconst(ctx),
++                                       &key->md, in + iv + sha_off);
++            blocks *= SHA256_CBLOCK;
++            aes_off += blocks;
++            sha_off += blocks;
++            key->md.Nh += blocks >> 29;
++            key->md.Nl += blocks <<= 3;
++            if (key->md.Nl < (unsigned int)blocks)
++                key->md.Nh++;
++        } else {
++            sha_off = 0;
++        }
++# endif
++        sha_off += iv;
++        SHA256_Update(&key->md, in + sha_off, plen - sha_off);
++
++        if (plen != len) {      /* "TLS" mode of operation */
++            if (in != out)
++                memcpy(out + aes_off, in + aes_off, plen - aes_off);
++
++            /* calculate HMAC and append it to payload */
++            SHA256_Final(out + plen, &key->md);
++            key->md = key->tail;
++            SHA256_Update(&key->md, out + plen, SHA256_DIGEST_LENGTH);
++            SHA256_Final(out + plen, &key->md);
++
++            /* pad the payload|hmac */
++            plen += SHA256_DIGEST_LENGTH;
++            for (l = len - plen - 1; plen < len; plen++)
++                out[plen] = l;
++            /* encrypt HMAC|padding at once */
++            aesni_cbc_encrypt(out + aes_off, out + aes_off, len - aes_off,
++                              &key->ks, EVP_CIPHER_CTX_iv_noconst(ctx), 1);
++        } else {
++            aesni_cbc_encrypt(in + aes_off, out + aes_off, len - aes_off,
++                              &key->ks, EVP_CIPHER_CTX_iv_noconst(ctx), 1);
++        }
++    } else {
++        union {
++            unsigned int u[SHA256_DIGEST_LENGTH / sizeof(unsigned int)];
++            unsigned char c[64 + SHA256_DIGEST_LENGTH];
++        } mac, *pmac;
++
++        /* arrange cache line alignment */
++        pmac = (void *)(((size_t)mac.c + 63) & ((size_t)0 - 64));
++
++        /* decrypt HMAC|padding at once */
++        aesni_cbc_encrypt(in, out, len, &key->ks,
++                          EVP_CIPHER_CTX_iv_noconst(ctx), 0);
++
++        if (plen != NO_PAYLOAD_LENGTH) { /* "TLS" mode of operation */
++            size_t inp_len, mask, j, i;
++            unsigned int res, maxpad, pad, bitlen;
++            int ret = 1;
++            union {
++                unsigned int u[SHA_LBLOCK];
++                unsigned char c[SHA256_CBLOCK];
++            } *data = (void *)key->md.data;
++
++            if ((key->aux.tls_aad[plen - 4] << 8 | key->aux.tls_aad[plen - 3])
++                >= TLS1_1_VERSION)
++                iv = AES_BLOCK_SIZE;
++
++            if (len < (iv + SHA256_DIGEST_LENGTH + 1))
++                return 0;
++
++            /* omit explicit iv */
++            out += iv;
++            len -= iv;
++
++            /* figure out payload length */
++            pad = out[len - 1];
++            maxpad = len - (SHA256_DIGEST_LENGTH + 1);
++            maxpad |= (255 - maxpad) >> (sizeof(maxpad) * 8 - 8);
++            maxpad &= 255;
++
++            ret &= constant_time_ge(maxpad, pad);
++
++            inp_len = len - (SHA256_DIGEST_LENGTH + pad + 1);
++            mask = (0 - ((inp_len - len) >> (sizeof(inp_len) * 8 - 1)));
++            inp_len &= mask;
++            ret &= (int)mask;
++
++            key->aux.tls_aad[plen - 2] = inp_len >> 8;
++            key->aux.tls_aad[plen - 1] = inp_len;
++
++            /* calculate HMAC */
++            key->md = key->head;
++            SHA256_Update(&key->md, key->aux.tls_aad, plen);
++
++# if 1
++            len -= SHA256_DIGEST_LENGTH; /* amend mac */
++            if (len >= (256 + SHA256_CBLOCK)) {
++                j = (len - (256 + SHA256_CBLOCK)) & (0 - SHA256_CBLOCK);
++                j += SHA256_CBLOCK - key->md.num;
++                SHA256_Update(&key->md, out, j);
++                out += j;
++                len -= j;
++                inp_len -= j;
++            }
++
++            /* but pretend as if we hashed padded payload */
++            bitlen = key->md.Nl + (inp_len << 3); /* at most 18 bits */
++#  ifdef BSWAP4
++            bitlen = BSWAP4(bitlen);
++#  else
++            mac.c[0] = 0;
++            mac.c[1] = (unsigned char)(bitlen >> 16);
++            mac.c[2] = (unsigned char)(bitlen >> 8);
++            mac.c[3] = (unsigned char)bitlen;
++            bitlen = mac.u[0];
++#  endif
++
++            pmac->u[0] = 0;
++            pmac->u[1] = 0;
++            pmac->u[2] = 0;
++            pmac->u[3] = 0;
++            pmac->u[4] = 0;
++            pmac->u[5] = 0;
++            pmac->u[6] = 0;
++            pmac->u[7] = 0;
++
++            for (res = key->md.num, j = 0; j < len; j++) {
++                size_t c = out[j];
++                mask = (j - inp_len) >> (sizeof(j) * 8 - 8);
++                c &= mask;
++                c |= 0x80 & ~mask & ~((inp_len - j) >> (sizeof(j) * 8 - 8));
++                data->c[res++] = (unsigned char)c;
++
++                if (res != SHA256_CBLOCK)
++                    continue;
++
++                /* j is not incremented yet */
++                mask = 0 - ((inp_len + 7 - j) >> (sizeof(j) * 8 - 1));
++                data->u[SHA_LBLOCK - 1] |= bitlen & mask;
++                sha256_block_data_order(&key->md, data, 1);
++                mask &= 0 - ((j - inp_len - 72) >> (sizeof(j) * 8 - 1));
++                pmac->u[0] |= key->md.h[0] & mask;
++                pmac->u[1] |= key->md.h[1] & mask;
++                pmac->u[2] |= key->md.h[2] & mask;
++                pmac->u[3] |= key->md.h[3] & mask;
++                pmac->u[4] |= key->md.h[4] & mask;
++                pmac->u[5] |= key->md.h[5] & mask;
++                pmac->u[6] |= key->md.h[6] & mask;
++                pmac->u[7] |= key->md.h[7] & mask;
++                res = 0;
++            }
++
++            for (i = res; i < SHA256_CBLOCK; i++, j++)
++                data->c[i] = 0;
++
++            if (res > SHA256_CBLOCK - 8) {
++                mask = 0 - ((inp_len + 8 - j) >> (sizeof(j) * 8 - 1));
++                data->u[SHA_LBLOCK - 1] |= bitlen & mask;
++                sha256_block_data_order(&key->md, data, 1);
++                mask &= 0 - ((j - inp_len - 73) >> (sizeof(j) * 8 - 1));
++                pmac->u[0] |= key->md.h[0] & mask;
++                pmac->u[1] |= key->md.h[1] & mask;
++                pmac->u[2] |= key->md.h[2] & mask;
++                pmac->u[3] |= key->md.h[3] & mask;
++                pmac->u[4] |= key->md.h[4] & mask;
++                pmac->u[5] |= key->md.h[5] & mask;
++                pmac->u[6] |= key->md.h[6] & mask;
++                pmac->u[7] |= key->md.h[7] & mask;
++
++                memset(data, 0, SHA256_CBLOCK);
++                j += 64;
++            }
++            data->u[SHA_LBLOCK - 1] = bitlen;
++            sha256_block_data_order(&key->md, data, 1);
++            mask = 0 - ((j - inp_len - 73) >> (sizeof(j) * 8 - 1));
++            pmac->u[0] |= key->md.h[0] & mask;
++            pmac->u[1] |= key->md.h[1] & mask;
++            pmac->u[2] |= key->md.h[2] & mask;
++            pmac->u[3] |= key->md.h[3] & mask;
++            pmac->u[4] |= key->md.h[4] & mask;
++            pmac->u[5] |= key->md.h[5] & mask;
++            pmac->u[6] |= key->md.h[6] & mask;
++            pmac->u[7] |= key->md.h[7] & mask;
++
++#  ifdef BSWAP4
++            pmac->u[0] = BSWAP4(pmac->u[0]);
++            pmac->u[1] = BSWAP4(pmac->u[1]);
++            pmac->u[2] = BSWAP4(pmac->u[2]);
++            pmac->u[3] = BSWAP4(pmac->u[3]);
++            pmac->u[4] = BSWAP4(pmac->u[4]);
++            pmac->u[5] = BSWAP4(pmac->u[5]);
++            pmac->u[6] = BSWAP4(pmac->u[6]);
++            pmac->u[7] = BSWAP4(pmac->u[7]);
++#  else
++            for (i = 0; i < 8; i++) {
++                res = pmac->u[i];
++                pmac->c[4 * i + 0] = (unsigned char)(res >> 24);
++                pmac->c[4 * i + 1] = (unsigned char)(res >> 16);
++                pmac->c[4 * i + 2] = (unsigned char)(res >> 8);
++                pmac->c[4 * i + 3] = (unsigned char)res;
++            }
++#  endif
++            len += SHA256_DIGEST_LENGTH;
++# else
++            SHA256_Update(&key->md, out, inp_len);
++            res = key->md.num;
++            SHA256_Final(pmac->c, &key->md);
++
++            {
++                unsigned int inp_blocks, pad_blocks;
++
++                /* but pretend as if we hashed padded payload */
++                inp_blocks =
++                    1 + ((SHA256_CBLOCK - 9 - res) >> (sizeof(res) * 8 - 1));
++                res += (unsigned int)(len - inp_len);
++                pad_blocks = res / SHA256_CBLOCK;
++                res %= SHA256_CBLOCK;
++                pad_blocks +=
++                    1 + ((SHA256_CBLOCK - 9 - res) >> (sizeof(res) * 8 - 1));
++                for (; inp_blocks < pad_blocks; inp_blocks++)
++                    sha1_block_data_order(&key->md, data, 1);
++            }
++# endif
++            key->md = key->tail;
++            SHA256_Update(&key->md, pmac->c, SHA256_DIGEST_LENGTH);
++            SHA256_Final(pmac->c, &key->md);
++
++            /* verify HMAC */
++            out += inp_len;
++            len -= inp_len;
++# if 1
++            {
++                unsigned char *p =
++                    out + len - 1 - maxpad - SHA256_DIGEST_LENGTH;
++                size_t off = out - p;
++                unsigned int c, cmask;
++
++                maxpad += SHA256_DIGEST_LENGTH;
++                for (res = 0, i = 0, j = 0; j < maxpad; j++) {
++                    c = p[j];
++                    cmask =
++                        ((int)(j - off - SHA256_DIGEST_LENGTH)) >>
++                        (sizeof(int) * 8 - 1);
++                    res |= (c ^ pad) & ~cmask; /* ... and padding */
++                    cmask &= ((int)(off - 1 - j)) >> (sizeof(int) * 8 - 1);
++                    res |= (c ^ pmac->c[i]) & cmask;
++                    i += 1 & cmask;
++                }
++                maxpad -= SHA256_DIGEST_LENGTH;
++
++                res = 0 - ((0 - res) >> (sizeof(res) * 8 - 1));
++                ret &= (int)~res;
++            }
++# else
++            for (res = 0, i = 0; i < SHA256_DIGEST_LENGTH; i++)
++                res |= out[i] ^ pmac->c[i];
++            res = 0 - ((0 - res) >> (sizeof(res) * 8 - 1));
++            ret &= (int)~res;
++
++            /* verify padding */
++            pad = (pad & ~res) | (maxpad & res);
++            out = out + len - 1 - pad;
++            for (res = 0, i = 0; i < pad; i++)
++                res |= out[i] ^ pad;
++
++            res = (0 - res) >> (sizeof(res) * 8 - 1);
++            ret &= (int)~res;
++# endif
++            return ret;
++        } else {
++            SHA256_Update(&key->md, out, len);
++        }
++    }
++
++    return 1;
++}
++
++static int aesni_cbc_hmac_sha256_ctrl(EVP_CIPHER_CTX *ctx, int type, int arg,
++                                      void *ptr)
++{
++    EVP_AES_HMAC_SHA256 *key = data(ctx);
++    unsigned int u_arg = (unsigned int)arg;
++
++    switch (type) {
++    case EVP_CTRL_AEAD_SET_MAC_KEY:
++        {
++            unsigned int i;
++            unsigned char hmac_key[64];
++
++            memset(hmac_key, 0, sizeof(hmac_key));
++
++            if (arg < 0)
++                return -1;
++
++            if (u_arg > sizeof(hmac_key)) {
++                SHA256_Init(&key->head);
++                SHA256_Update(&key->head, ptr, arg);
++                SHA256_Final(hmac_key, &key->head);
++            } else {
++                memcpy(hmac_key, ptr, arg);
++            }
++
++            for (i = 0; i < sizeof(hmac_key); i++)
++                hmac_key[i] ^= 0x36; /* ipad */
++            SHA256_Init(&key->head);
++            SHA256_Update(&key->head, hmac_key, sizeof(hmac_key));
++
++            for (i = 0; i < sizeof(hmac_key); i++)
++                hmac_key[i] ^= 0x36 ^ 0x5c; /* opad */
++            SHA256_Init(&key->tail);
++            SHA256_Update(&key->tail, hmac_key, sizeof(hmac_key));
++
++            OPENSSL_cleanse(hmac_key, sizeof(hmac_key));
++
++            return 1;
++        }
++    case EVP_CTRL_AEAD_TLS1_AAD:
++        {
++            unsigned char *p = ptr;
++            unsigned int len = p[arg - 2] << 8 | p[arg - 1];
++
++            if (arg != EVP_AEAD_TLS1_AAD_LEN)
++                return -1;
++
++            if (EVP_CIPHER_CTX_encrypting(ctx)) {
++                key->payload_length = len;
++                if ((key->aux.tls_ver =
++                     p[arg - 4] << 8 | p[arg - 3]) >= TLS1_1_VERSION) {
++                    len -= AES_BLOCK_SIZE;
++                    p[arg - 2] = len >> 8;
++                    p[arg - 1] = len;
++                }
++                key->md = key->head;
++                SHA256_Update(&key->md, p, arg);
++
++                return (int)(((len + SHA256_DIGEST_LENGTH +
++                               AES_BLOCK_SIZE) & -AES_BLOCK_SIZE)
++                             - len);
++            } else {
++                memcpy(key->aux.tls_aad, ptr, arg);
++                key->payload_length = arg;
++
++                return SHA256_DIGEST_LENGTH;
++            }
++        }
++# if !defined(OPENSSL_NO_MULTIBLOCK)
++    case EVP_CTRL_TLS1_1_MULTIBLOCK_MAX_BUFSIZE:
++        return (int)(5 + 16 + ((arg + 32 + 16) & -16));
++    case EVP_CTRL_TLS1_1_MULTIBLOCK_AAD:
++        {
++            EVP_CTRL_TLS1_1_MULTIBLOCK_PARAM *param =
++                (EVP_CTRL_TLS1_1_MULTIBLOCK_PARAM *) ptr;
++            unsigned int n4x = 1, x4;
++            unsigned int frag, last, packlen, inp_len;
++
++            if (arg < 0)
++                return -1;
++
++            if (u_arg < sizeof(EVP_CTRL_TLS1_1_MULTIBLOCK_PARAM))
++                return -1;
++
++            inp_len = param->inp[11] << 8 | param->inp[12];
++
++            if (EVP_CIPHER_CTX_encrypting(ctx)) {
++                if ((param->inp[9] << 8 | param->inp[10]) < TLS1_1_VERSION)
++                    return -1;
++
++                if (inp_len) {
++                    if (inp_len < 4096)
++                        return 0; /* too short */
++
++                    if (inp_len >= 8192 && OPENSSL_ia32cap_P[2] & (1 << 5))
++                        n4x = 2; /* AVX2 */
++                } else if ((n4x = param->interleave / 4) && n4x <= 2)
++                    inp_len = param->len;
++                else
++                    return -1;
++
++                key->md = key->head;
++                SHA256_Update(&key->md, param->inp, 13);
++
++                x4 = 4 * n4x;
++                n4x += 1;
++
++                frag = inp_len >> n4x;
++                last = inp_len + frag - (frag << n4x);
++                if (last > frag && ((last + 13 + 9) % 64 < (x4 - 1))) {
++                    frag++;
++                    last -= x4 - 1;
++                }
++
++                packlen = 5 + 16 + ((frag + 32 + 16) & -16);
++                packlen = (packlen << n4x) - packlen;
++                packlen += 5 + 16 + ((last + 32 + 16) & -16);
++
++                param->interleave = x4;
++
++                return (int)packlen;
++            } else
++                return -1;      /* not yet */
++        }
++    case EVP_CTRL_TLS1_1_MULTIBLOCK_ENCRYPT:
++        {
++            EVP_CTRL_TLS1_1_MULTIBLOCK_PARAM *param =
++                (EVP_CTRL_TLS1_1_MULTIBLOCK_PARAM *) ptr;
++
++            return (int)tls1_1_multi_block_encrypt(key, param->out,
++                                                   param->inp, param->len,
++                                                   param->interleave / 4);
++        }
++    case EVP_CTRL_TLS1_1_MULTIBLOCK_DECRYPT:
++# endif
++    default:
++        return -1;
++    }
++}
++
++static EVP_CIPHER aesni_128_cbc_hmac_sha256_cipher = {
++# ifdef NID_aes_128_cbc_hmac_sha256
++    NID_aes_128_cbc_hmac_sha256,
++# else
++    NID_undef,
++# endif
++    AES_BLOCK_SIZE, 16, AES_BLOCK_SIZE,
++    EVP_CIPH_CBC_MODE | EVP_CIPH_FLAG_DEFAULT_ASN1 |
++        EVP_CIPH_FLAG_AEAD_CIPHER | EVP_CIPH_FLAG_TLS1_1_MULTIBLOCK,
++    aesni_cbc_hmac_sha256_init_key,
++    aesni_cbc_hmac_sha256_cipher,
++    NULL,
++    sizeof(EVP_AES_HMAC_SHA256),
++    EVP_CIPH_FLAG_DEFAULT_ASN1 ? NULL : EVP_CIPHER_set_asn1_iv,
++    EVP_CIPH_FLAG_DEFAULT_ASN1 ? NULL : EVP_CIPHER_get_asn1_iv,
++    aesni_cbc_hmac_sha256_ctrl,
++    NULL
++};
++
++static EVP_CIPHER aesni_256_cbc_hmac_sha256_cipher = {
++# ifdef NID_aes_256_cbc_hmac_sha256
++    NID_aes_256_cbc_hmac_sha256,
++# else
++    NID_undef,
++# endif
++    AES_BLOCK_SIZE, 32, AES_BLOCK_SIZE,
++    EVP_CIPH_CBC_MODE | EVP_CIPH_FLAG_DEFAULT_ASN1 |
++        EVP_CIPH_FLAG_AEAD_CIPHER | EVP_CIPH_FLAG_TLS1_1_MULTIBLOCK,
++    aesni_cbc_hmac_sha256_init_key,
++    aesni_cbc_hmac_sha256_cipher,
++    NULL,
++    sizeof(EVP_AES_HMAC_SHA256),
++    EVP_CIPH_FLAG_DEFAULT_ASN1 ? NULL : EVP_CIPHER_set_asn1_iv,
++    EVP_CIPH_FLAG_DEFAULT_ASN1 ? NULL : EVP_CIPHER_get_asn1_iv,
++    aesni_cbc_hmac_sha256_ctrl,
++    NULL
++};
++
++const EVP_CIPHER *EVP_aes_128_cbc_hmac_sha256(void)
++{
++    return ((OPENSSL_ia32cap_P[1] & AESNI_CAPABLE) &&
++            aesni_cbc_sha256_enc(NULL, NULL, 0, NULL, NULL, NULL, NULL) ?
++            &aesni_128_cbc_hmac_sha256_cipher : NULL);
++}
++
++const EVP_CIPHER *EVP_aes_256_cbc_hmac_sha256(void)
++{
++    return ((OPENSSL_ia32cap_P[1] & AESNI_CAPABLE) &&
++            aesni_cbc_sha256_enc(NULL, NULL, 0, NULL, NULL, NULL, NULL) ?
++            &aesni_256_cbc_hmac_sha256_cipher : NULL);
++}
++#else
++const EVP_CIPHER *EVP_aes_128_cbc_hmac_sha256(void)
++{
++    return NULL;
++}
++
++const EVP_CIPHER *EVP_aes_256_cbc_hmac_sha256(void)
++{
++    return NULL;
++}
++#endif
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/evp/e_bf.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/evp/e_bf.c
+new file mode 100644
+index 0000000..dc38690
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/evp/e_bf.c
+@@ -0,0 +1,38 @@
++/*
++ * Copyright 1995-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include "internal/cryptlib.h"
++#ifndef OPENSSL_NO_BF
++# include 
++# include "internal/evp_int.h"
++# include 
++# include 
++
++static int bf_init_key(EVP_CIPHER_CTX *ctx, const unsigned char *key,
++                       const unsigned char *iv, int enc);
++
++typedef struct {
++    BF_KEY ks;
++} EVP_BF_KEY;
++
++# define data(ctx)       EVP_C_DATA(EVP_BF_KEY,ctx)
++
++IMPLEMENT_BLOCK_CIPHER(bf, ks, BF, EVP_BF_KEY, NID_bf, 8, 16, 8, 64,
++                       EVP_CIPH_VARIABLE_LENGTH, bf_init_key, NULL,
++                       EVP_CIPHER_set_asn1_iv, EVP_CIPHER_get_asn1_iv, NULL)
++
++static int bf_init_key(EVP_CIPHER_CTX *ctx, const unsigned char *key,
++                       const unsigned char *iv, int enc)
++{
++    BF_set_key(&data(ctx)->ks, EVP_CIPHER_CTX_key_length(ctx), key);
++    return 1;
++}
++
++#endif
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/evp/e_camellia.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/evp/e_camellia.c
+new file mode 100644
+index 0000000..b50fa0b
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/evp/e_camellia.c
+@@ -0,0 +1,364 @@
++/*
++ * Copyright 2006-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#ifdef OPENSSL_NO_CAMELLIA
++NON_EMPTY_TRANSLATION_UNIT
++#else
++
++# include 
++# include 
++# include 
++# include 
++# include 
++# include "internal/evp_int.h"
++# include "modes_lcl.h"
++
++static int camellia_init_key(EVP_CIPHER_CTX *ctx, const unsigned char *key,
++                             const unsigned char *iv, int enc);
++
++/* Camellia subkey Structure */
++typedef struct {
++    CAMELLIA_KEY ks;
++    block128_f block;
++    union {
++        cbc128_f cbc;
++        ctr128_f ctr;
++    } stream;
++} EVP_CAMELLIA_KEY;
++
++# define MAXBITCHUNK     ((size_t)1<<(sizeof(size_t)*8-4))
++
++/* Attribute operation for Camellia */
++# define data(ctx)       EVP_C_DATA(EVP_CAMELLIA_KEY,ctx)
++
++# if defined(AES_ASM) && (defined(__sparc) || defined(__sparc__))
++/* ---------^^^ this is not a typo, just a way to detect that
++ * assembler support was in general requested... */
++#  include "sparc_arch.h"
++
++extern unsigned int OPENSSL_sparcv9cap_P[];
++
++#  define SPARC_CMLL_CAPABLE      (OPENSSL_sparcv9cap_P[1] & CFR_CAMELLIA)
++
++void cmll_t4_set_key(const unsigned char *key, int bits, CAMELLIA_KEY *ks);
++void cmll_t4_encrypt(const unsigned char *in, unsigned char *out,
++                     const CAMELLIA_KEY *key);
++void cmll_t4_decrypt(const unsigned char *in, unsigned char *out,
++                     const CAMELLIA_KEY *key);
++
++void cmll128_t4_cbc_encrypt(const unsigned char *in, unsigned char *out,
++                            size_t len, const CAMELLIA_KEY *key,
++                            unsigned char *ivec);
++void cmll128_t4_cbc_decrypt(const unsigned char *in, unsigned char *out,
++                            size_t len, const CAMELLIA_KEY *key,
++                            unsigned char *ivec);
++void cmll256_t4_cbc_encrypt(const unsigned char *in, unsigned char *out,
++                            size_t len, const CAMELLIA_KEY *key,
++                            unsigned char *ivec);
++void cmll256_t4_cbc_decrypt(const unsigned char *in, unsigned char *out,
++                            size_t len, const CAMELLIA_KEY *key,
++                            unsigned char *ivec);
++void cmll128_t4_ctr32_encrypt(const unsigned char *in, unsigned char *out,
++                              size_t blocks, const CAMELLIA_KEY *key,
++                              unsigned char *ivec);
++void cmll256_t4_ctr32_encrypt(const unsigned char *in, unsigned char *out,
++                              size_t blocks, const CAMELLIA_KEY *key,
++                              unsigned char *ivec);
++
++static int cmll_t4_init_key(EVP_CIPHER_CTX *ctx, const unsigned char *key,
++                            const unsigned char *iv, int enc)
++{
++    int ret, mode, bits;
++    EVP_CAMELLIA_KEY *dat =
++        (EVP_CAMELLIA_KEY *)EVP_CIPHER_CTX_get_cipher_data(ctx);
++
++    mode = EVP_CIPHER_CTX_mode(ctx);
++    bits = EVP_CIPHER_CTX_key_length(ctx) * 8;
++
++    cmll_t4_set_key(key, bits, &dat->ks);
++
++    if ((mode == EVP_CIPH_ECB_MODE || mode == EVP_CIPH_CBC_MODE)
++        && !enc) {
++        ret = 0;
++        dat->block = (block128_f) cmll_t4_decrypt;
++        switch (bits) {
++        case 128:
++            dat->stream.cbc = mode == EVP_CIPH_CBC_MODE ?
++                (cbc128_f) cmll128_t4_cbc_decrypt : NULL;
++            break;
++        case 192:
++        case 256:
++            dat->stream.cbc = mode == EVP_CIPH_CBC_MODE ?
++                (cbc128_f) cmll256_t4_cbc_decrypt : NULL;
++            break;
++        default:
++            ret = -1;
++        }
++    } else {
++        ret = 0;
++        dat->block = (block128_f) cmll_t4_encrypt;
++        switch (bits) {
++        case 128:
++            if (mode == EVP_CIPH_CBC_MODE)
++                dat->stream.cbc = (cbc128_f) cmll128_t4_cbc_encrypt;
++            else if (mode == EVP_CIPH_CTR_MODE)
++                dat->stream.ctr = (ctr128_f) cmll128_t4_ctr32_encrypt;
++            else
++                dat->stream.cbc = NULL;
++            break;
++        case 192:
++        case 256:
++            if (mode == EVP_CIPH_CBC_MODE)
++                dat->stream.cbc = (cbc128_f) cmll256_t4_cbc_encrypt;
++            else if (mode == EVP_CIPH_CTR_MODE)
++                dat->stream.ctr = (ctr128_f) cmll256_t4_ctr32_encrypt;
++            else
++                dat->stream.cbc = NULL;
++            break;
++        default:
++            ret = -1;
++        }
++    }
++
++    if (ret < 0) {
++        EVPerr(EVP_F_CMLL_T4_INIT_KEY, EVP_R_CAMELLIA_KEY_SETUP_FAILED);
++        return 0;
++    }
++
++    return 1;
++}
++
++#  define cmll_t4_cbc_cipher camellia_cbc_cipher
++static int cmll_t4_cbc_cipher(EVP_CIPHER_CTX *ctx, unsigned char *out,
++                              const unsigned char *in, size_t len);
++
++#  define cmll_t4_ecb_cipher camellia_ecb_cipher
++static int cmll_t4_ecb_cipher(EVP_CIPHER_CTX *ctx, unsigned char *out,
++                              const unsigned char *in, size_t len);
++
++#  define cmll_t4_ofb_cipher camellia_ofb_cipher
++static int cmll_t4_ofb_cipher(EVP_CIPHER_CTX *ctx, unsigned char *out,
++                              const unsigned char *in, size_t len);
++
++#  define cmll_t4_cfb_cipher camellia_cfb_cipher
++static int cmll_t4_cfb_cipher(EVP_CIPHER_CTX *ctx, unsigned char *out,
++                              const unsigned char *in, size_t len);
++
++#  define cmll_t4_cfb8_cipher camellia_cfb8_cipher
++static int cmll_t4_cfb8_cipher(EVP_CIPHER_CTX *ctx, unsigned char *out,
++                               const unsigned char *in, size_t len);
++
++#  define cmll_t4_cfb1_cipher camellia_cfb1_cipher
++static int cmll_t4_cfb1_cipher(EVP_CIPHER_CTX *ctx, unsigned char *out,
++                               const unsigned char *in, size_t len);
++
++#  define cmll_t4_ctr_cipher camellia_ctr_cipher
++static int cmll_t4_ctr_cipher(EVP_CIPHER_CTX *ctx, unsigned char *out,
++                              const unsigned char *in, size_t len);
++
++#  define BLOCK_CIPHER_generic(nid,keylen,blocksize,ivlen,nmode,mode,MODE,flags) \
++static const EVP_CIPHER cmll_t4_##keylen##_##mode = { \
++        nid##_##keylen##_##nmode,blocksize,keylen/8,ivlen, \
++        flags|EVP_CIPH_##MODE##_MODE,   \
++        cmll_t4_init_key,               \
++        cmll_t4_##mode##_cipher,        \
++        NULL,                           \
++        sizeof(EVP_CAMELLIA_KEY),       \
++        NULL,NULL,NULL,NULL }; \
++static const EVP_CIPHER camellia_##keylen##_##mode = { \
++        nid##_##keylen##_##nmode,blocksize,     \
++        keylen/8,ivlen, \
++        flags|EVP_CIPH_##MODE##_MODE,   \
++        camellia_init_key,              \
++        camellia_##mode##_cipher,       \
++        NULL,                           \
++        sizeof(EVP_CAMELLIA_KEY),       \
++        NULL,NULL,NULL,NULL }; \
++const EVP_CIPHER *EVP_camellia_##keylen##_##mode(void) \
++{ return SPARC_CMLL_CAPABLE?&cmll_t4_##keylen##_##mode:&camellia_##keylen##_##mode; }
++
++# else
++
++#  define BLOCK_CIPHER_generic(nid,keylen,blocksize,ivlen,nmode,mode,MODE,flags) \
++static const EVP_CIPHER camellia_##keylen##_##mode = { \
++        nid##_##keylen##_##nmode,blocksize,keylen/8,ivlen, \
++        flags|EVP_CIPH_##MODE##_MODE,   \
++        camellia_init_key,              \
++        camellia_##mode##_cipher,       \
++        NULL,                           \
++        sizeof(EVP_CAMELLIA_KEY),       \
++        NULL,NULL,NULL,NULL }; \
++const EVP_CIPHER *EVP_camellia_##keylen##_##mode(void) \
++{ return &camellia_##keylen##_##mode; }
++
++# endif
++
++# define BLOCK_CIPHER_generic_pack(nid,keylen,flags)             \
++        BLOCK_CIPHER_generic(nid,keylen,16,16,cbc,cbc,CBC,flags|EVP_CIPH_FLAG_DEFAULT_ASN1)     \
++        BLOCK_CIPHER_generic(nid,keylen,16,0,ecb,ecb,ECB,flags|EVP_CIPH_FLAG_DEFAULT_ASN1)      \
++        BLOCK_CIPHER_generic(nid,keylen,1,16,ofb128,ofb,OFB,flags|EVP_CIPH_FLAG_DEFAULT_ASN1)   \
++        BLOCK_CIPHER_generic(nid,keylen,1,16,cfb128,cfb,CFB,flags|EVP_CIPH_FLAG_DEFAULT_ASN1)   \
++        BLOCK_CIPHER_generic(nid,keylen,1,16,cfb1,cfb1,CFB,flags)       \
++        BLOCK_CIPHER_generic(nid,keylen,1,16,cfb8,cfb8,CFB,flags)       \
++        BLOCK_CIPHER_generic(nid, keylen, 1, 16, ctr, ctr, CTR, flags)
++
++/* The subkey for Camellia is generated. */
++static int camellia_init_key(EVP_CIPHER_CTX *ctx, const unsigned char *key,
++                             const unsigned char *iv, int enc)
++{
++    int ret, mode;
++    EVP_CAMELLIA_KEY *dat = EVP_C_DATA(EVP_CAMELLIA_KEY,ctx);
++
++    ret = Camellia_set_key(key, EVP_CIPHER_CTX_key_length(ctx) * 8, &dat->ks);
++    if (ret < 0) {
++        EVPerr(EVP_F_CAMELLIA_INIT_KEY, EVP_R_CAMELLIA_KEY_SETUP_FAILED);
++        return 0;
++    }
++
++    mode = EVP_CIPHER_CTX_mode(ctx);
++    if ((mode == EVP_CIPH_ECB_MODE || mode == EVP_CIPH_CBC_MODE)
++        && !enc) {
++        dat->block = (block128_f) Camellia_decrypt;
++        dat->stream.cbc = mode == EVP_CIPH_CBC_MODE ?
++            (cbc128_f) Camellia_cbc_encrypt : NULL;
++    } else {
++        dat->block = (block128_f) Camellia_encrypt;
++        dat->stream.cbc = mode == EVP_CIPH_CBC_MODE ?
++            (cbc128_f) Camellia_cbc_encrypt : NULL;
++    }
++
++    return 1;
++}
++
++static int camellia_cbc_cipher(EVP_CIPHER_CTX *ctx, unsigned char *out,
++                               const unsigned char *in, size_t len)
++{
++    EVP_CAMELLIA_KEY *dat = EVP_C_DATA(EVP_CAMELLIA_KEY,ctx);
++
++    if (dat->stream.cbc)
++        (*dat->stream.cbc) (in, out, len, &dat->ks,
++                            EVP_CIPHER_CTX_iv_noconst(ctx),
++                            EVP_CIPHER_CTX_encrypting(ctx));
++    else if (EVP_CIPHER_CTX_encrypting(ctx))
++        CRYPTO_cbc128_encrypt(in, out, len, &dat->ks,
++                              EVP_CIPHER_CTX_iv_noconst(ctx), dat->block);
++    else
++        CRYPTO_cbc128_decrypt(in, out, len, &dat->ks,
++                              EVP_CIPHER_CTX_iv_noconst(ctx), dat->block);
++
++    return 1;
++}
++
++static int camellia_ecb_cipher(EVP_CIPHER_CTX *ctx, unsigned char *out,
++                               const unsigned char *in, size_t len)
++{
++    size_t bl = EVP_CIPHER_CTX_block_size(ctx);
++    size_t i;
++    EVP_CAMELLIA_KEY *dat = EVP_C_DATA(EVP_CAMELLIA_KEY,ctx);
++
++    if (len < bl)
++        return 1;
++
++    for (i = 0, len -= bl; i <= len; i += bl)
++        (*dat->block) (in + i, out + i, &dat->ks);
++
++    return 1;
++}
++
++static int camellia_ofb_cipher(EVP_CIPHER_CTX *ctx, unsigned char *out,
++                               const unsigned char *in, size_t len)
++{
++    EVP_CAMELLIA_KEY *dat = EVP_C_DATA(EVP_CAMELLIA_KEY,ctx);
++
++    int num = EVP_CIPHER_CTX_num(ctx);
++    CRYPTO_ofb128_encrypt(in, out, len, &dat->ks,
++                          EVP_CIPHER_CTX_iv_noconst(ctx), &num, dat->block);
++    EVP_CIPHER_CTX_set_num(ctx, num);
++    return 1;
++}
++
++static int camellia_cfb_cipher(EVP_CIPHER_CTX *ctx, unsigned char *out,
++                               const unsigned char *in, size_t len)
++{
++    EVP_CAMELLIA_KEY *dat = EVP_C_DATA(EVP_CAMELLIA_KEY,ctx);
++
++    int num = EVP_CIPHER_CTX_num(ctx);
++    CRYPTO_cfb128_encrypt(in, out, len, &dat->ks,
++                          EVP_CIPHER_CTX_iv_noconst(ctx), &num, EVP_CIPHER_CTX_encrypting(ctx), dat->block);
++    EVP_CIPHER_CTX_set_num(ctx, num);
++    return 1;
++}
++
++static int camellia_cfb8_cipher(EVP_CIPHER_CTX *ctx, unsigned char *out,
++                                const unsigned char *in, size_t len)
++{
++    EVP_CAMELLIA_KEY *dat = EVP_C_DATA(EVP_CAMELLIA_KEY,ctx);
++
++    int num = EVP_CIPHER_CTX_num(ctx);
++    CRYPTO_cfb128_8_encrypt(in, out, len, &dat->ks,
++                            EVP_CIPHER_CTX_iv_noconst(ctx), &num, EVP_CIPHER_CTX_encrypting(ctx), dat->block);
++    EVP_CIPHER_CTX_set_num(ctx, num);
++    return 1;
++}
++
++static int camellia_cfb1_cipher(EVP_CIPHER_CTX *ctx, unsigned char *out,
++                                const unsigned char *in, size_t len)
++{
++    EVP_CAMELLIA_KEY *dat = EVP_C_DATA(EVP_CAMELLIA_KEY,ctx);
++
++    if (EVP_CIPHER_CTX_test_flags(ctx, EVP_CIPH_FLAG_LENGTH_BITS)) {
++        int num = EVP_CIPHER_CTX_num(ctx);
++        CRYPTO_cfb128_1_encrypt(in, out, len, &dat->ks,
++                                EVP_CIPHER_CTX_iv_noconst(ctx), &num, EVP_CIPHER_CTX_encrypting(ctx), dat->block);
++        EVP_CIPHER_CTX_set_num(ctx, num);
++        return 1;
++    }
++
++    while (len >= MAXBITCHUNK) {
++        int num = EVP_CIPHER_CTX_num(ctx);
++        CRYPTO_cfb128_1_encrypt(in, out, MAXBITCHUNK * 8, &dat->ks,
++                                EVP_CIPHER_CTX_iv_noconst(ctx), &num, EVP_CIPHER_CTX_encrypting(ctx), dat->block);
++        len -= MAXBITCHUNK;
++        EVP_CIPHER_CTX_set_num(ctx, num);
++    }
++    if (len) {
++        int num = EVP_CIPHER_CTX_num(ctx);
++        CRYPTO_cfb128_1_encrypt(in, out, len * 8, &dat->ks,
++                                EVP_CIPHER_CTX_iv_noconst(ctx), &num, EVP_CIPHER_CTX_encrypting(ctx), dat->block);
++        EVP_CIPHER_CTX_set_num(ctx, num);
++    }
++
++    return 1;
++}
++
++static int camellia_ctr_cipher(EVP_CIPHER_CTX *ctx, unsigned char *out,
++                               const unsigned char *in, size_t len)
++{
++    unsigned int num = EVP_CIPHER_CTX_num(ctx);
++    EVP_CAMELLIA_KEY *dat = EVP_C_DATA(EVP_CAMELLIA_KEY,ctx);
++
++    if (dat->stream.ctr)
++        CRYPTO_ctr128_encrypt_ctr32(in, out, len, &dat->ks,
++                                    EVP_CIPHER_CTX_iv_noconst(ctx),
++                                    EVP_CIPHER_CTX_buf_noconst(ctx), &num,
++                                    dat->stream.ctr);
++    else
++        CRYPTO_ctr128_encrypt(in, out, len, &dat->ks,
++                              EVP_CIPHER_CTX_iv_noconst(ctx),
++                              EVP_CIPHER_CTX_buf_noconst(ctx), &num,
++                              dat->block);
++    EVP_CIPHER_CTX_set_num(ctx, num);
++    return 1;
++}
++
++BLOCK_CIPHER_generic_pack(NID_camellia, 128, 0)
++    BLOCK_CIPHER_generic_pack(NID_camellia, 192, 0)
++    BLOCK_CIPHER_generic_pack(NID_camellia, 256, 0)
++#endif
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/evp/e_cast.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/evp/e_cast.c
+new file mode 100644
+index 0000000..259d440
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/evp/e_cast.c
+@@ -0,0 +1,40 @@
++/*
++ * Copyright 1995-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include "internal/cryptlib.h"
++
++#ifndef OPENSSL_NO_CAST
++# include 
++# include 
++# include "internal/evp_int.h"
++# include 
++
++static int cast_init_key(EVP_CIPHER_CTX *ctx, const unsigned char *key,
++                         const unsigned char *iv, int enc);
++
++typedef struct {
++    CAST_KEY ks;
++} EVP_CAST_KEY;
++
++# define data(ctx)       EVP_C_DATA(EVP_CAST_KEY,ctx)
++
++IMPLEMENT_BLOCK_CIPHER(cast5, ks, CAST, EVP_CAST_KEY,
++                       NID_cast5, 8, CAST_KEY_LENGTH, 8, 64,
++                       EVP_CIPH_VARIABLE_LENGTH, cast_init_key, NULL,
++                       EVP_CIPHER_set_asn1_iv, EVP_CIPHER_get_asn1_iv, NULL)
++
++static int cast_init_key(EVP_CIPHER_CTX *ctx, const unsigned char *key,
++                         const unsigned char *iv, int enc)
++{
++    CAST_set_key(&data(ctx)->ks, EVP_CIPHER_CTX_key_length(ctx), key);
++    return 1;
++}
++
++#endif
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/evp/e_chacha20_poly1305.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/evp/e_chacha20_poly1305.c
+new file mode 100644
+index 0000000..7fd4f8d
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/evp/e_chacha20_poly1305.c
+@@ -0,0 +1,454 @@
++/*
++ * Copyright 2015-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include "internal/cryptlib.h"
++
++#ifndef OPENSSL_NO_CHACHA
++
++# include 
++# include 
++# include "evp_locl.h"
++# include "internal/evp_int.h"
++# include "internal/chacha.h"
++
++typedef struct {
++    union {
++        double align;   /* this ensures even sizeof(EVP_CHACHA_KEY)%8==0 */
++        unsigned int d[CHACHA_KEY_SIZE / 4];
++    } key;
++    unsigned int  counter[CHACHA_CTR_SIZE / 4];
++    unsigned char buf[CHACHA_BLK_SIZE];
++    unsigned int  partial_len;
++} EVP_CHACHA_KEY;
++
++#define data(ctx)   ((EVP_CHACHA_KEY *)(ctx)->cipher_data)
++
++static int chacha_init_key(EVP_CIPHER_CTX *ctx,
++                           const unsigned char user_key[CHACHA_KEY_SIZE],
++                           const unsigned char iv[CHACHA_CTR_SIZE], int enc)
++{
++    EVP_CHACHA_KEY *key = data(ctx);
++    unsigned int i;
++
++    if (user_key)
++        for (i = 0; i < CHACHA_KEY_SIZE; i+=4) {
++            key->key.d[i/4] = CHACHA_U8TOU32(user_key+i);
++        }
++
++    if (iv)
++        for (i = 0; i < CHACHA_CTR_SIZE; i+=4) {
++            key->counter[i/4] = CHACHA_U8TOU32(iv+i);
++        }
++
++    key->partial_len = 0;
++
++    return 1;
++}
++
++static int chacha_cipher(EVP_CIPHER_CTX * ctx, unsigned char *out,
++                         const unsigned char *inp, size_t len)
++{
++    EVP_CHACHA_KEY *key = data(ctx);
++    unsigned int n, rem, ctr32;
++
++    if ((n = key->partial_len)) {
++        while (len && n < CHACHA_BLK_SIZE) {
++            *out++ = *inp++ ^ key->buf[n++];
++            len--;
++        }
++        key->partial_len = n;
++
++        if (len == 0)
++            return 1;
++
++        if (n == CHACHA_BLK_SIZE) {
++            key->partial_len = 0;
++            key->counter[0]++;
++            if (key->counter[0] == 0)
++                key->counter[1]++;
++        }
++    }
++
++    rem = (unsigned int)(len % CHACHA_BLK_SIZE);
++    len -= rem;
++    ctr32 = key->counter[0];
++    while (len >= CHACHA_BLK_SIZE) {
++        size_t blocks = len / CHACHA_BLK_SIZE;
++        /*
++         * 1<<28 is just a not-so-small yet not-so-large number...
++         * Below condition is practically never met, but it has to
++         * be checked for code correctness.
++         */
++        if (sizeof(size_t)>sizeof(unsigned int) && blocks>(1U<<28))
++            blocks = (1U<<28);
++
++        /*
++         * As ChaCha20_ctr32 operates on 32-bit counter, caller
++         * has to handle overflow. 'if' below detects the
++         * overflow, which is then handled by limiting the
++         * amount of blocks to the exact overflow point...
++         */
++        ctr32 += (unsigned int)blocks;
++        if (ctr32 < blocks) {
++            blocks -= ctr32;
++            ctr32 = 0;
++        }
++        blocks *= CHACHA_BLK_SIZE;
++        ChaCha20_ctr32(out, inp, blocks, key->key.d, key->counter);
++        len -= blocks;
++        inp += blocks;
++        out += blocks;
++
++        key->counter[0] = ctr32;
++        if (ctr32 == 0) key->counter[1]++;
++    }
++
++    if (rem) {
++        memset(key->buf, 0, sizeof(key->buf));
++        ChaCha20_ctr32(key->buf, key->buf, CHACHA_BLK_SIZE,
++                       key->key.d, key->counter);
++        for (n = 0; n < rem; n++)
++            out[n] = inp[n] ^ key->buf[n];
++        key->partial_len = rem;
++    }
++
++    return 1;
++}
++
++static const EVP_CIPHER chacha20 = {
++    NID_chacha20,
++    1,                      /* block_size */
++    CHACHA_KEY_SIZE,        /* key_len */
++    CHACHA_CTR_SIZE,        /* iv_len, 128-bit counter in the context */
++    EVP_CIPH_CUSTOM_IV | EVP_CIPH_ALWAYS_CALL_INIT,
++    chacha_init_key,
++    chacha_cipher,
++    NULL,
++    sizeof(EVP_CHACHA_KEY),
++    NULL,
++    NULL,
++    NULL,
++    NULL
++};
++
++const EVP_CIPHER *EVP_chacha20(void)
++{
++    return (&chacha20);
++}
++
++# ifndef OPENSSL_NO_POLY1305
++#  include "internal/poly1305.h"
++
++typedef struct {
++    EVP_CHACHA_KEY key;
++    unsigned int nonce[12/4];
++    unsigned char tag[POLY1305_BLOCK_SIZE];
++    struct { uint64_t aad, text; } len;
++    int aad, mac_inited, tag_len, nonce_len;
++    size_t tls_payload_length;
++} EVP_CHACHA_AEAD_CTX;
++
++#  define NO_TLS_PAYLOAD_LENGTH ((size_t)-1)
++#  define aead_data(ctx)        ((EVP_CHACHA_AEAD_CTX *)(ctx)->cipher_data)
++#  define POLY1305_ctx(actx)    ((POLY1305 *)(actx + 1))
++
++static int chacha20_poly1305_init_key(EVP_CIPHER_CTX *ctx,
++                                      const unsigned char *inkey,
++                                      const unsigned char *iv, int enc)
++{
++    EVP_CHACHA_AEAD_CTX *actx = aead_data(ctx);
++
++    if (!inkey && !iv)
++        return 1;
++
++    actx->len.aad = 0;
++    actx->len.text = 0;
++    actx->aad = 0;
++    actx->mac_inited = 0;
++    actx->tls_payload_length = NO_TLS_PAYLOAD_LENGTH;
++
++    if (iv != NULL) {
++        unsigned char temp[CHACHA_CTR_SIZE] = { 0 };
++
++        /* pad on the left */
++        if (actx->nonce_len <= CHACHA_CTR_SIZE)
++            memcpy(temp + CHACHA_CTR_SIZE - actx->nonce_len, iv, actx->nonce_len);
++
++        chacha_init_key(ctx, inkey, temp, enc);
++
++        actx->nonce[0] = actx->key.counter[1];
++        actx->nonce[1] = actx->key.counter[2];
++        actx->nonce[2] = actx->key.counter[3];
++    } else {
++        chacha_init_key(ctx, inkey, NULL, enc);
++    }
++
++    return 1;
++}
++
++static int chacha20_poly1305_cipher(EVP_CIPHER_CTX *ctx, unsigned char *out,
++                                    const unsigned char *in, size_t len)
++{
++    EVP_CHACHA_AEAD_CTX *actx = aead_data(ctx);
++    size_t rem, plen = actx->tls_payload_length;
++    static const unsigned char zero[POLY1305_BLOCK_SIZE] = { 0 };
++
++    if (!actx->mac_inited) {
++        actx->key.counter[0] = 0;
++        memset(actx->key.buf, 0, sizeof(actx->key.buf));
++        ChaCha20_ctr32(actx->key.buf, actx->key.buf, CHACHA_BLK_SIZE,
++                       actx->key.key.d, actx->key.counter);
++        Poly1305_Init(POLY1305_ctx(actx), actx->key.buf);
++        actx->key.counter[0] = 1;
++        actx->key.partial_len = 0;
++        actx->len.aad = actx->len.text = 0;
++        actx->mac_inited = 1;
++    }
++
++    if (in) {                                   /* aad or text */
++        if (out == NULL) {                      /* aad */
++            Poly1305_Update(POLY1305_ctx(actx), in, len);
++            actx->len.aad += len;
++            actx->aad = 1;
++            return len;
++        } else {                                /* plain- or ciphertext */
++            if (actx->aad) {                    /* wrap up aad */
++                if ((rem = (size_t)actx->len.aad % POLY1305_BLOCK_SIZE))
++                    Poly1305_Update(POLY1305_ctx(actx), zero,
++                                    POLY1305_BLOCK_SIZE - rem);
++                actx->aad = 0;
++            }
++
++            actx->tls_payload_length = NO_TLS_PAYLOAD_LENGTH;
++            if (plen == NO_TLS_PAYLOAD_LENGTH)
++                plen = len;
++            else if (len != plen + POLY1305_BLOCK_SIZE)
++                return -1;
++
++            if (ctx->encrypt) {                 /* plaintext */
++                chacha_cipher(ctx, out, in, plen);
++                Poly1305_Update(POLY1305_ctx(actx), out, plen);
++                in += plen;
++                out += plen;
++                actx->len.text += plen;
++            } else {                            /* ciphertext */
++                Poly1305_Update(POLY1305_ctx(actx), in, plen);
++                chacha_cipher(ctx, out, in, plen);
++                in += plen;
++                out += plen;
++                actx->len.text += plen;
++            }
++        }
++    }
++    if (in == NULL                              /* explicit final */
++        || plen != len) {                       /* or tls mode */
++        const union {
++            long one;
++            char little;
++        } is_endian = { 1 };
++        unsigned char temp[POLY1305_BLOCK_SIZE];
++
++        if (actx->aad) {                        /* wrap up aad */
++            if ((rem = (size_t)actx->len.aad % POLY1305_BLOCK_SIZE))
++                Poly1305_Update(POLY1305_ctx(actx), zero,
++                                POLY1305_BLOCK_SIZE - rem);
++            actx->aad = 0;
++        }
++
++        if ((rem = (size_t)actx->len.text % POLY1305_BLOCK_SIZE))
++            Poly1305_Update(POLY1305_ctx(actx), zero,
++                            POLY1305_BLOCK_SIZE - rem);
++
++        if (is_endian.little) {
++            Poly1305_Update(POLY1305_ctx(actx),
++                            (unsigned char *)&actx->len, POLY1305_BLOCK_SIZE);
++        } else {
++            temp[0]  = (unsigned char)(actx->len.aad);
++            temp[1]  = (unsigned char)(actx->len.aad>>8);
++            temp[2]  = (unsigned char)(actx->len.aad>>16);
++            temp[3]  = (unsigned char)(actx->len.aad>>24);
++            temp[4]  = (unsigned char)(actx->len.aad>>32);
++            temp[5]  = (unsigned char)(actx->len.aad>>40);
++            temp[6]  = (unsigned char)(actx->len.aad>>48);
++            temp[7]  = (unsigned char)(actx->len.aad>>56);
++
++            temp[8]  = (unsigned char)(actx->len.text);
++            temp[9]  = (unsigned char)(actx->len.text>>8);
++            temp[10] = (unsigned char)(actx->len.text>>16);
++            temp[11] = (unsigned char)(actx->len.text>>24);
++            temp[12] = (unsigned char)(actx->len.text>>32);
++            temp[13] = (unsigned char)(actx->len.text>>40);
++            temp[14] = (unsigned char)(actx->len.text>>48);
++            temp[15] = (unsigned char)(actx->len.text>>56);
++
++            Poly1305_Update(POLY1305_ctx(actx), temp, POLY1305_BLOCK_SIZE);
++        }
++        Poly1305_Final(POLY1305_ctx(actx), ctx->encrypt ? actx->tag
++                                                        : temp);
++        actx->mac_inited = 0;
++
++        if (in != NULL && len != plen) {        /* tls mode */
++            if (ctx->encrypt) {
++                memcpy(out, actx->tag, POLY1305_BLOCK_SIZE);
++            } else {
++                if (CRYPTO_memcmp(temp, in, POLY1305_BLOCK_SIZE)) {
++                    memset(out - plen, 0, plen);
++                    return -1;
++                }
++            }
++        }
++        else if (!ctx->encrypt) {
++            if (CRYPTO_memcmp(temp, actx->tag, actx->tag_len))
++                return -1;
++        }
++    }
++    return len;
++}
++
++static int chacha20_poly1305_cleanup(EVP_CIPHER_CTX *ctx)
++{
++    EVP_CHACHA_AEAD_CTX *actx = aead_data(ctx);
++    if (actx)
++        OPENSSL_cleanse(ctx->cipher_data, sizeof(*actx) + Poly1305_ctx_size());
++    return 1;
++}
++
++static int chacha20_poly1305_ctrl(EVP_CIPHER_CTX *ctx, int type, int arg,
++                                  void *ptr)
++{
++    EVP_CHACHA_AEAD_CTX *actx = aead_data(ctx);
++
++    switch(type) {
++    case EVP_CTRL_INIT:
++        if (actx == NULL)
++            actx = ctx->cipher_data
++                 = OPENSSL_zalloc(sizeof(*actx) + Poly1305_ctx_size());
++        if (actx == NULL) {
++            EVPerr(EVP_F_CHACHA20_POLY1305_CTRL, EVP_R_INITIALIZATION_ERROR);
++            return 0;
++        }
++        actx->len.aad = 0;
++        actx->len.text = 0;
++        actx->aad = 0;
++        actx->mac_inited = 0;
++        actx->tag_len = 0;
++        actx->nonce_len = 12;
++        actx->tls_payload_length = NO_TLS_PAYLOAD_LENGTH;
++        return 1;
++
++    case EVP_CTRL_COPY:
++        if (actx) {
++            EVP_CIPHER_CTX *dst = (EVP_CIPHER_CTX *)ptr;
++
++            dst->cipher_data =
++                   OPENSSL_memdup(actx, sizeof(*actx) + Poly1305_ctx_size());
++            if (dst->cipher_data == NULL) {
++                EVPerr(EVP_F_CHACHA20_POLY1305_CTRL, EVP_R_COPY_ERROR);
++                return 0;
++            }
++        }
++        return 1;
++
++    case EVP_CTRL_AEAD_SET_IVLEN:
++        if (arg <= 0 || arg > CHACHA_CTR_SIZE)
++            return 0;
++        actx->nonce_len = arg;
++        return 1;
++
++    case EVP_CTRL_AEAD_SET_IV_FIXED:
++        if (arg != 12)
++            return 0;
++        actx->nonce[0] = actx->key.counter[1]
++                       = CHACHA_U8TOU32((unsigned char *)ptr);
++        actx->nonce[1] = actx->key.counter[2]
++                       = CHACHA_U8TOU32((unsigned char *)ptr+4);
++        actx->nonce[2] = actx->key.counter[3]
++                       = CHACHA_U8TOU32((unsigned char *)ptr+8);
++        return 1;
++
++    case EVP_CTRL_AEAD_SET_TAG:
++        if (arg <= 0 || arg > POLY1305_BLOCK_SIZE)
++            return 0;
++        if (ptr != NULL) {
++            memcpy(actx->tag, ptr, arg);
++            actx->tag_len = arg;
++        }
++        return 1;
++
++    case EVP_CTRL_AEAD_GET_TAG:
++        if (arg <= 0 || arg > POLY1305_BLOCK_SIZE || !ctx->encrypt)
++            return 0;
++        memcpy(ptr, actx->tag, arg);
++        return 1;
++
++    case EVP_CTRL_AEAD_TLS1_AAD:
++        if (arg != EVP_AEAD_TLS1_AAD_LEN)
++            return 0;
++        {
++            unsigned int len;
++            unsigned char *aad = ptr, temp[POLY1305_BLOCK_SIZE];
++
++            len = aad[EVP_AEAD_TLS1_AAD_LEN - 2] << 8 |
++                  aad[EVP_AEAD_TLS1_AAD_LEN - 1];
++            if (!ctx->encrypt) {
++                if (len < POLY1305_BLOCK_SIZE)
++                    return 0;
++                len -= POLY1305_BLOCK_SIZE;     /* discount attached tag */
++                memcpy(temp, aad, EVP_AEAD_TLS1_AAD_LEN - 2);
++                aad = temp;
++                temp[EVP_AEAD_TLS1_AAD_LEN - 2] = (unsigned char)(len >> 8);
++                temp[EVP_AEAD_TLS1_AAD_LEN - 1] = (unsigned char)len;
++            }
++            actx->tls_payload_length = len;
++
++            /*
++             * merge record sequence number as per RFC7905
++             */
++            actx->key.counter[1] = actx->nonce[0];
++            actx->key.counter[2] = actx->nonce[1] ^ CHACHA_U8TOU32(aad);
++            actx->key.counter[3] = actx->nonce[2] ^ CHACHA_U8TOU32(aad+4);
++            actx->mac_inited = 0;
++            chacha20_poly1305_cipher(ctx, NULL, aad, EVP_AEAD_TLS1_AAD_LEN);
++            return POLY1305_BLOCK_SIZE;         /* tag length */
++        }
++
++    case EVP_CTRL_AEAD_SET_MAC_KEY:
++        /* no-op */
++        return 1;
++
++    default:
++        return -1;
++    }
++}
++
++static EVP_CIPHER chacha20_poly1305 = {
++    NID_chacha20_poly1305,
++    1,                  /* block_size */
++    CHACHA_KEY_SIZE,    /* key_len */
++    12,                 /* iv_len, 96-bit nonce in the context */
++    EVP_CIPH_FLAG_AEAD_CIPHER | EVP_CIPH_CUSTOM_IV |
++    EVP_CIPH_ALWAYS_CALL_INIT | EVP_CIPH_CTRL_INIT |
++    EVP_CIPH_CUSTOM_COPY | EVP_CIPH_FLAG_CUSTOM_CIPHER,
++    chacha20_poly1305_init_key,
++    chacha20_poly1305_cipher,
++    chacha20_poly1305_cleanup,
++    0,          /* 0 moves context-specific structure allocation to ctrl */
++    NULL,       /* set_asn1_parameters */
++    NULL,       /* get_asn1_parameters */
++    chacha20_poly1305_ctrl,
++    NULL        /* app_data */
++};
++
++const EVP_CIPHER *EVP_chacha20_poly1305(void)
++{
++    return(&chacha20_poly1305);
++}
++# endif
++#endif
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/evp/e_des.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/evp/e_des.c
+new file mode 100644
+index 0000000..9b2facf
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/evp/e_des.c
+@@ -0,0 +1,242 @@
++/*
++ * Copyright 1995-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include "internal/cryptlib.h"
++#ifndef OPENSSL_NO_DES
++# include 
++# include 
++# include "internal/evp_int.h"
++# include 
++# include 
++
++typedef struct {
++    union {
++        double align;
++        DES_key_schedule ks;
++    } ks;
++    union {
++        void (*cbc) (const void *, void *, size_t,
++                     const DES_key_schedule *, unsigned char *);
++    } stream;
++} EVP_DES_KEY;
++
++# if defined(AES_ASM) && (defined(__sparc) || defined(__sparc__))
++/* ----------^^^ this is not a typo, just a way to detect that
++ * assembler support was in general requested... */
++#  include "sparc_arch.h"
++
++extern unsigned int OPENSSL_sparcv9cap_P[];
++
++#  define SPARC_DES_CAPABLE       (OPENSSL_sparcv9cap_P[1] & CFR_DES)
++
++void des_t4_key_expand(const void *key, DES_key_schedule *ks);
++void des_t4_cbc_encrypt(const void *inp, void *out, size_t len,
++                        const DES_key_schedule *ks, unsigned char iv[8]);
++void des_t4_cbc_decrypt(const void *inp, void *out, size_t len,
++                        const DES_key_schedule *ks, unsigned char iv[8]);
++# endif
++
++static int des_init_key(EVP_CIPHER_CTX *ctx, const unsigned char *key,
++                        const unsigned char *iv, int enc);
++static int des_ctrl(EVP_CIPHER_CTX *c, int type, int arg, void *ptr);
++
++/*
++ * Because of various casts and different names can't use
++ * IMPLEMENT_BLOCK_CIPHER
++ */
++
++static int des_ecb_cipher(EVP_CIPHER_CTX *ctx, unsigned char *out,
++                          const unsigned char *in, size_t inl)
++{
++    BLOCK_CIPHER_ecb_loop()
++        DES_ecb_encrypt((DES_cblock *)(in + i), (DES_cblock *)(out + i),
++                        EVP_CIPHER_CTX_get_cipher_data(ctx),
++                        EVP_CIPHER_CTX_encrypting(ctx));
++    return 1;
++}
++
++static int des_ofb_cipher(EVP_CIPHER_CTX *ctx, unsigned char *out,
++                          const unsigned char *in, size_t inl)
++{
++    while (inl >= EVP_MAXCHUNK) {
++        int num = EVP_CIPHER_CTX_num(ctx);
++        DES_ofb64_encrypt(in, out, (long)EVP_MAXCHUNK,
++                          EVP_CIPHER_CTX_get_cipher_data(ctx),
++                          (DES_cblock *)EVP_CIPHER_CTX_iv_noconst(ctx), &num);
++        EVP_CIPHER_CTX_set_num(ctx, num);
++        inl -= EVP_MAXCHUNK;
++        in += EVP_MAXCHUNK;
++        out += EVP_MAXCHUNK;
++    }
++    if (inl) {
++        int num = EVP_CIPHER_CTX_num(ctx);
++        DES_ofb64_encrypt(in, out, (long)inl,
++                          EVP_CIPHER_CTX_get_cipher_data(ctx),
++                          (DES_cblock *)EVP_CIPHER_CTX_iv_noconst(ctx), &num);
++        EVP_CIPHER_CTX_set_num(ctx, num);
++    }
++    return 1;
++}
++
++static int des_cbc_cipher(EVP_CIPHER_CTX *ctx, unsigned char *out,
++                          const unsigned char *in, size_t inl)
++{
++    EVP_DES_KEY *dat = (EVP_DES_KEY *) EVP_CIPHER_CTX_get_cipher_data(ctx);
++
++    if (dat->stream.cbc != NULL) {
++        (*dat->stream.cbc) (in, out, inl, &dat->ks.ks,
++                            EVP_CIPHER_CTX_iv_noconst(ctx));
++        return 1;
++    }
++    while (inl >= EVP_MAXCHUNK) {
++        DES_ncbc_encrypt(in, out, (long)EVP_MAXCHUNK,
++                         EVP_CIPHER_CTX_get_cipher_data(ctx),
++                         (DES_cblock *)EVP_CIPHER_CTX_iv_noconst(ctx),
++                         EVP_CIPHER_CTX_encrypting(ctx));
++        inl -= EVP_MAXCHUNK;
++        in += EVP_MAXCHUNK;
++        out += EVP_MAXCHUNK;
++    }
++    if (inl)
++        DES_ncbc_encrypt(in, out, (long)inl,
++                         EVP_CIPHER_CTX_get_cipher_data(ctx),
++                         (DES_cblock *)EVP_CIPHER_CTX_iv_noconst(ctx),
++                         EVP_CIPHER_CTX_encrypting(ctx));
++    return 1;
++}
++
++static int des_cfb64_cipher(EVP_CIPHER_CTX *ctx, unsigned char *out,
++                            const unsigned char *in, size_t inl)
++{
++    while (inl >= EVP_MAXCHUNK) {
++        int num = EVP_CIPHER_CTX_num(ctx);
++        DES_cfb64_encrypt(in, out, (long)EVP_MAXCHUNK,
++                          EVP_CIPHER_CTX_get_cipher_data(ctx),
++                          (DES_cblock *)EVP_CIPHER_CTX_iv_noconst(ctx), &num,
++                          EVP_CIPHER_CTX_encrypting(ctx));
++        EVP_CIPHER_CTX_set_num(ctx, num);
++        inl -= EVP_MAXCHUNK;
++        in += EVP_MAXCHUNK;
++        out += EVP_MAXCHUNK;
++    }
++    if (inl) {
++        int num = EVP_CIPHER_CTX_num(ctx);
++        DES_cfb64_encrypt(in, out, (long)inl,
++                          EVP_CIPHER_CTX_get_cipher_data(ctx),
++                          (DES_cblock *)EVP_CIPHER_CTX_iv_noconst(ctx), &num,
++                          EVP_CIPHER_CTX_encrypting(ctx));
++        EVP_CIPHER_CTX_set_num(ctx, num);
++    }
++    return 1;
++}
++
++/*
++ * Although we have a CFB-r implementation for DES, it doesn't pack the right
++ * way, so wrap it here
++ */
++static int des_cfb1_cipher(EVP_CIPHER_CTX *ctx, unsigned char *out,
++                           const unsigned char *in, size_t inl)
++{
++    size_t n, chunk = EVP_MAXCHUNK / 8;
++    unsigned char c[1], d[1];
++
++    if (inl < chunk)
++        chunk = inl;
++
++    while (inl && inl >= chunk) {
++        for (n = 0; n < chunk * 8; ++n) {
++            c[0] = (in[n / 8] & (1 << (7 - n % 8))) ? 0x80 : 0;
++            DES_cfb_encrypt(c, d, 1, 1, EVP_CIPHER_CTX_get_cipher_data(ctx),
++                            (DES_cblock *)EVP_CIPHER_CTX_iv_noconst(ctx),
++                            EVP_CIPHER_CTX_encrypting(ctx));
++            out[n / 8] =
++                (out[n / 8] & ~(0x80 >> (unsigned int)(n % 8))) |
++                ((d[0] & 0x80) >> (unsigned int)(n % 8));
++        }
++        inl -= chunk;
++        in += chunk;
++        out += chunk;
++        if (inl < chunk)
++            chunk = inl;
++    }
++
++    return 1;
++}
++
++static int des_cfb8_cipher(EVP_CIPHER_CTX *ctx, unsigned char *out,
++                           const unsigned char *in, size_t inl)
++{
++    while (inl >= EVP_MAXCHUNK) {
++        DES_cfb_encrypt(in, out, 8, (long)EVP_MAXCHUNK,
++                        EVP_CIPHER_CTX_get_cipher_data(ctx),
++                        (DES_cblock *)EVP_CIPHER_CTX_iv_noconst(ctx),
++                        EVP_CIPHER_CTX_encrypting(ctx));
++        inl -= EVP_MAXCHUNK;
++        in += EVP_MAXCHUNK;
++        out += EVP_MAXCHUNK;
++    }
++    if (inl)
++        DES_cfb_encrypt(in, out, 8, (long)inl,
++                        EVP_CIPHER_CTX_get_cipher_data(ctx),
++                        (DES_cblock *)EVP_CIPHER_CTX_iv_noconst(ctx),
++                        EVP_CIPHER_CTX_encrypting(ctx));
++    return 1;
++}
++
++BLOCK_CIPHER_defs(des, EVP_DES_KEY, NID_des, 8, 8, 8, 64,
++                  EVP_CIPH_RAND_KEY, des_init_key, NULL,
++                  EVP_CIPHER_set_asn1_iv, EVP_CIPHER_get_asn1_iv, des_ctrl)
++
++    BLOCK_CIPHER_def_cfb(des, EVP_DES_KEY, NID_des, 8, 8, 1,
++                     EVP_CIPH_RAND_KEY, des_init_key, NULL,
++                     EVP_CIPHER_set_asn1_iv, EVP_CIPHER_get_asn1_iv, des_ctrl)
++
++    BLOCK_CIPHER_def_cfb(des, EVP_DES_KEY, NID_des, 8, 8, 8,
++                     EVP_CIPH_RAND_KEY, des_init_key, NULL,
++                     EVP_CIPHER_set_asn1_iv, EVP_CIPHER_get_asn1_iv, des_ctrl)
++
++static int des_init_key(EVP_CIPHER_CTX *ctx, const unsigned char *key,
++                        const unsigned char *iv, int enc)
++{
++    DES_cblock *deskey = (DES_cblock *)key;
++    EVP_DES_KEY *dat = (EVP_DES_KEY *) EVP_CIPHER_CTX_get_cipher_data(ctx);
++
++    dat->stream.cbc = NULL;
++# if defined(SPARC_DES_CAPABLE)
++    if (SPARC_DES_CAPABLE) {
++        int mode = EVP_CIPHER_CTX_mode(ctx);
++
++        if (mode == EVP_CIPH_CBC_MODE) {
++            des_t4_key_expand(key, &dat->ks.ks);
++            dat->stream.cbc = enc ? des_t4_cbc_encrypt : des_t4_cbc_decrypt;
++            return 1;
++        }
++    }
++# endif
++    DES_set_key_unchecked(deskey, EVP_CIPHER_CTX_get_cipher_data(ctx));
++    return 1;
++}
++
++static int des_ctrl(EVP_CIPHER_CTX *c, int type, int arg, void *ptr)
++{
++
++    switch (type) {
++    case EVP_CTRL_RAND_KEY:
++        if (RAND_bytes(ptr, 8) <= 0)
++            return 0;
++        DES_set_odd_parity((DES_cblock *)ptr);
++        return 1;
++
++    default:
++        return -1;
++    }
++}
++
++#endif
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/evp/e_des3.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/evp/e_des3.c
+new file mode 100644
+index 0000000..da77936
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/evp/e_des3.c
+@@ -0,0 +1,424 @@
++/*
++ * Copyright 1995-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include "internal/cryptlib.h"
++#ifndef OPENSSL_NO_DES
++# include 
++# include 
++# include "internal/evp_int.h"
++# include 
++# include 
++# include "evp_locl.h"
++
++typedef struct {
++    union {
++        double align;
++        DES_key_schedule ks[3];
++    } ks;
++    union {
++        void (*cbc) (const void *, void *, size_t,
++                     const DES_key_schedule *, unsigned char *);
++    } stream;
++} DES_EDE_KEY;
++# define ks1 ks.ks[0]
++# define ks2 ks.ks[1]
++# define ks3 ks.ks[2]
++
++# if defined(AES_ASM) && (defined(__sparc) || defined(__sparc__))
++/* ---------^^^ this is not a typo, just a way to detect that
++ * assembler support was in general requested... */
++#  include "sparc_arch.h"
++
++extern unsigned int OPENSSL_sparcv9cap_P[];
++
++#  define SPARC_DES_CAPABLE       (OPENSSL_sparcv9cap_P[1] & CFR_DES)
++
++void des_t4_key_expand(const void *key, DES_key_schedule *ks);
++void des_t4_ede3_cbc_encrypt(const void *inp, void *out, size_t len,
++                             const DES_key_schedule ks[3], unsigned char iv[8]);
++void des_t4_ede3_cbc_decrypt(const void *inp, void *out, size_t len,
++                             const DES_key_schedule ks[3], unsigned char iv[8]);
++# endif
++
++static int des_ede_init_key(EVP_CIPHER_CTX *ctx, const unsigned char *key,
++                            const unsigned char *iv, int enc);
++
++static int des_ede3_init_key(EVP_CIPHER_CTX *ctx, const unsigned char *key,
++                             const unsigned char *iv, int enc);
++
++static int des3_ctrl(EVP_CIPHER_CTX *c, int type, int arg, void *ptr);
++
++# define data(ctx) EVP_C_DATA(DES_EDE_KEY,ctx)
++
++/*
++ * Because of various casts and different args can't use
++ * IMPLEMENT_BLOCK_CIPHER
++ */
++
++static int des_ede_ecb_cipher(EVP_CIPHER_CTX *ctx, unsigned char *out,
++                              const unsigned char *in, size_t inl)
++{
++    BLOCK_CIPHER_ecb_loop()
++        DES_ecb3_encrypt((const_DES_cblock *)(in + i),
++                         (DES_cblock *)(out + i),
++                         &data(ctx)->ks1, &data(ctx)->ks2,
++                         &data(ctx)->ks3, EVP_CIPHER_CTX_encrypting(ctx));
++    return 1;
++}
++
++static int des_ede_ofb_cipher(EVP_CIPHER_CTX *ctx, unsigned char *out,
++                              const unsigned char *in, size_t inl)
++{
++    while (inl >= EVP_MAXCHUNK) {
++        int num = EVP_CIPHER_CTX_num(ctx);
++        DES_ede3_ofb64_encrypt(in, out, (long)EVP_MAXCHUNK,
++                               &data(ctx)->ks1, &data(ctx)->ks2,
++                               &data(ctx)->ks3,
++                               (DES_cblock *)EVP_CIPHER_CTX_iv_noconst(ctx),
++                               &num);
++        EVP_CIPHER_CTX_set_num(ctx, num);
++        inl -= EVP_MAXCHUNK;
++        in += EVP_MAXCHUNK;
++        out += EVP_MAXCHUNK;
++    }
++    if (inl) {
++        int num = EVP_CIPHER_CTX_num(ctx);
++        DES_ede3_ofb64_encrypt(in, out, (long)inl,
++                               &data(ctx)->ks1, &data(ctx)->ks2,
++                               &data(ctx)->ks3,
++                               (DES_cblock *)EVP_CIPHER_CTX_iv_noconst(ctx),
++                               &num);
++        EVP_CIPHER_CTX_set_num(ctx, num);
++    }
++    return 1;
++}
++
++static int des_ede_cbc_cipher(EVP_CIPHER_CTX *ctx, unsigned char *out,
++                              const unsigned char *in, size_t inl)
++{
++    DES_EDE_KEY *dat = data(ctx);
++
++    if (dat->stream.cbc != NULL) {
++        (*dat->stream.cbc) (in, out, inl, dat->ks.ks,
++                            EVP_CIPHER_CTX_iv_noconst(ctx));
++        return 1;
++    }
++
++    while (inl >= EVP_MAXCHUNK) {
++        DES_ede3_cbc_encrypt(in, out, (long)EVP_MAXCHUNK,
++                             &dat->ks1, &dat->ks2, &dat->ks3,
++                             (DES_cblock *)EVP_CIPHER_CTX_iv_noconst(ctx),
++                             EVP_CIPHER_CTX_encrypting(ctx));
++        inl -= EVP_MAXCHUNK;
++        in += EVP_MAXCHUNK;
++        out += EVP_MAXCHUNK;
++    }
++    if (inl)
++        DES_ede3_cbc_encrypt(in, out, (long)inl,
++                             &dat->ks1, &dat->ks2, &dat->ks3,
++                             (DES_cblock *)EVP_CIPHER_CTX_iv_noconst(ctx),
++                             EVP_CIPHER_CTX_encrypting(ctx));
++    return 1;
++}
++
++static int des_ede_cfb64_cipher(EVP_CIPHER_CTX *ctx, unsigned char *out,
++                                const unsigned char *in, size_t inl)
++{
++    while (inl >= EVP_MAXCHUNK) {
++        int num = EVP_CIPHER_CTX_num(ctx);
++        DES_ede3_cfb64_encrypt(in, out, (long)EVP_MAXCHUNK,
++                               &data(ctx)->ks1, &data(ctx)->ks2,
++                               &data(ctx)->ks3,
++                               (DES_cblock *)EVP_CIPHER_CTX_iv_noconst(ctx),
++                               &num, EVP_CIPHER_CTX_encrypting(ctx));
++        EVP_CIPHER_CTX_set_num(ctx, num);
++        inl -= EVP_MAXCHUNK;
++        in += EVP_MAXCHUNK;
++        out += EVP_MAXCHUNK;
++    }
++    if (inl) {
++        int num = EVP_CIPHER_CTX_num(ctx);
++        DES_ede3_cfb64_encrypt(in, out, (long)inl,
++                               &data(ctx)->ks1, &data(ctx)->ks2,
++                               &data(ctx)->ks3,
++                               (DES_cblock *)EVP_CIPHER_CTX_iv_noconst(ctx),
++                               &num, EVP_CIPHER_CTX_encrypting(ctx));
++        EVP_CIPHER_CTX_set_num(ctx, num);
++    }
++    return 1;
++}
++
++/*
++ * Although we have a CFB-r implementation for 3-DES, it doesn't pack the
++ * right way, so wrap it here
++ */
++static int des_ede3_cfb1_cipher(EVP_CIPHER_CTX *ctx, unsigned char *out,
++                                const unsigned char *in, size_t inl)
++{
++    size_t n;
++    unsigned char c[1], d[1];
++
++    if (!EVP_CIPHER_CTX_test_flags(ctx, EVP_CIPH_FLAG_LENGTH_BITS))
++            inl *= 8;
++    for (n = 0; n < inl; ++n) {
++        c[0] = (in[n / 8] & (1 << (7 - n % 8))) ? 0x80 : 0;
++        DES_ede3_cfb_encrypt(c, d, 1, 1,
++                             &data(ctx)->ks1, &data(ctx)->ks2,
++                             &data(ctx)->ks3,
++                             (DES_cblock *)EVP_CIPHER_CTX_iv_noconst(ctx),
++                             EVP_CIPHER_CTX_encrypting(ctx));
++        out[n / 8] = (out[n / 8] & ~(0x80 >> (unsigned int)(n % 8)))
++            | ((d[0] & 0x80) >> (unsigned int)(n % 8));
++    }
++
++    return 1;
++}
++
++static int des_ede3_cfb8_cipher(EVP_CIPHER_CTX *ctx, unsigned char *out,
++                                const unsigned char *in, size_t inl)
++{
++    while (inl >= EVP_MAXCHUNK) {
++        DES_ede3_cfb_encrypt(in, out, 8, (long)EVP_MAXCHUNK,
++                             &data(ctx)->ks1, &data(ctx)->ks2,
++                             &data(ctx)->ks3,
++                             (DES_cblock *)EVP_CIPHER_CTX_iv_noconst(ctx),
++                             EVP_CIPHER_CTX_encrypting(ctx));
++        inl -= EVP_MAXCHUNK;
++        in += EVP_MAXCHUNK;
++        out += EVP_MAXCHUNK;
++    }
++    if (inl)
++        DES_ede3_cfb_encrypt(in, out, 8, (long)inl,
++                             &data(ctx)->ks1, &data(ctx)->ks2,
++                             &data(ctx)->ks3,
++                             (DES_cblock *)EVP_CIPHER_CTX_iv_noconst(ctx),
++                             EVP_CIPHER_CTX_encrypting(ctx));
++    return 1;
++}
++
++BLOCK_CIPHER_defs(des_ede, DES_EDE_KEY, NID_des_ede, 8, 16, 8, 64,
++                  EVP_CIPH_RAND_KEY | EVP_CIPH_FLAG_DEFAULT_ASN1,
++                  des_ede_init_key, NULL, NULL, NULL, des3_ctrl)
++# define des_ede3_cfb64_cipher des_ede_cfb64_cipher
++# define des_ede3_ofb_cipher des_ede_ofb_cipher
++# define des_ede3_cbc_cipher des_ede_cbc_cipher
++# define des_ede3_ecb_cipher des_ede_ecb_cipher
++    BLOCK_CIPHER_defs(des_ede3, DES_EDE_KEY, NID_des_ede3, 8, 24, 8, 64,
++                  EVP_CIPH_RAND_KEY | EVP_CIPH_FLAG_DEFAULT_ASN1,
++                  des_ede3_init_key, NULL, NULL, NULL, des3_ctrl)
++
++    BLOCK_CIPHER_def_cfb(des_ede3, DES_EDE_KEY, NID_des_ede3, 24, 8, 1,
++                     EVP_CIPH_RAND_KEY | EVP_CIPH_FLAG_DEFAULT_ASN1,
++                     des_ede3_init_key, NULL, NULL, NULL, des3_ctrl)
++
++    BLOCK_CIPHER_def_cfb(des_ede3, DES_EDE_KEY, NID_des_ede3, 24, 8, 8,
++                     EVP_CIPH_RAND_KEY | EVP_CIPH_FLAG_DEFAULT_ASN1,
++                     des_ede3_init_key, NULL, NULL, NULL, des3_ctrl)
++
++static int des_ede_init_key(EVP_CIPHER_CTX *ctx, const unsigned char *key,
++                            const unsigned char *iv, int enc)
++{
++    DES_cblock *deskey = (DES_cblock *)key;
++    DES_EDE_KEY *dat = data(ctx);
++
++    dat->stream.cbc = NULL;
++# if defined(SPARC_DES_CAPABLE)
++    if (SPARC_DES_CAPABLE) {
++        int mode = EVP_CIPHER_CTX_mode(ctx);
++
++        if (mode == EVP_CIPH_CBC_MODE) {
++            des_t4_key_expand(&deskey[0], &dat->ks1);
++            des_t4_key_expand(&deskey[1], &dat->ks2);
++            memcpy(&dat->ks3, &dat->ks1, sizeof(dat->ks1));
++            dat->stream.cbc = enc ? des_t4_ede3_cbc_encrypt :
++                des_t4_ede3_cbc_decrypt;
++            return 1;
++        }
++    }
++# endif
++    DES_set_key_unchecked(&deskey[0], &dat->ks1);
++    DES_set_key_unchecked(&deskey[1], &dat->ks2);
++    memcpy(&dat->ks3, &dat->ks1, sizeof(dat->ks1));
++    return 1;
++}
++
++static int des_ede3_init_key(EVP_CIPHER_CTX *ctx, const unsigned char *key,
++                             const unsigned char *iv, int enc)
++{
++    DES_cblock *deskey = (DES_cblock *)key;
++    DES_EDE_KEY *dat = data(ctx);
++
++    dat->stream.cbc = NULL;
++# if defined(SPARC_DES_CAPABLE)
++    if (SPARC_DES_CAPABLE) {
++        int mode = EVP_CIPHER_CTX_mode(ctx);
++
++        if (mode == EVP_CIPH_CBC_MODE) {
++            des_t4_key_expand(&deskey[0], &dat->ks1);
++            des_t4_key_expand(&deskey[1], &dat->ks2);
++            des_t4_key_expand(&deskey[2], &dat->ks3);
++            dat->stream.cbc = enc ? des_t4_ede3_cbc_encrypt :
++                des_t4_ede3_cbc_decrypt;
++            return 1;
++        }
++    }
++# endif
++    DES_set_key_unchecked(&deskey[0], &dat->ks1);
++    DES_set_key_unchecked(&deskey[1], &dat->ks2);
++    DES_set_key_unchecked(&deskey[2], &dat->ks3);
++    return 1;
++}
++
++static int des3_ctrl(EVP_CIPHER_CTX *ctx, int type, int arg, void *ptr)
++{
++
++    DES_cblock *deskey = ptr;
++
++    switch (type) {
++    case EVP_CTRL_RAND_KEY:
++        if (RAND_bytes(ptr, EVP_CIPHER_CTX_key_length(ctx)) <= 0)
++            return 0;
++        DES_set_odd_parity(deskey);
++        if (EVP_CIPHER_CTX_key_length(ctx) >= 16)
++            DES_set_odd_parity(deskey + 1);
++        if (EVP_CIPHER_CTX_key_length(ctx) >= 24)
++            DES_set_odd_parity(deskey + 2);
++        return 1;
++
++    default:
++        return -1;
++    }
++}
++
++const EVP_CIPHER *EVP_des_ede(void)
++{
++    return &des_ede_ecb;
++}
++
++const EVP_CIPHER *EVP_des_ede3(void)
++{
++    return &des_ede3_ecb;
++}
++
++
++# include 
++
++static const unsigned char wrap_iv[8] =
++    { 0x4a, 0xdd, 0xa2, 0x2c, 0x79, 0xe8, 0x21, 0x05 };
++
++static int des_ede3_unwrap(EVP_CIPHER_CTX *ctx, unsigned char *out,
++                           const unsigned char *in, size_t inl)
++{
++    unsigned char icv[8], iv[8], sha1tmp[SHA_DIGEST_LENGTH];
++    int rv = -1;
++    if (inl < 24)
++        return -1;
++    if (out == NULL)
++        return inl - 16;
++    memcpy(EVP_CIPHER_CTX_iv_noconst(ctx), wrap_iv, 8);
++    /* Decrypt first block which will end up as icv */
++    des_ede_cbc_cipher(ctx, icv, in, 8);
++    /* Decrypt central blocks */
++    /*
++     * If decrypting in place move whole output along a block so the next
++     * des_ede_cbc_cipher is in place.
++     */
++    if (out == in) {
++        memmove(out, out + 8, inl - 8);
++        in -= 8;
++    }
++    des_ede_cbc_cipher(ctx, out, in + 8, inl - 16);
++    /* Decrypt final block which will be IV */
++    des_ede_cbc_cipher(ctx, iv, in + inl - 8, 8);
++    /* Reverse order of everything */
++    BUF_reverse(icv, NULL, 8);
++    BUF_reverse(out, NULL, inl - 16);
++    BUF_reverse(EVP_CIPHER_CTX_iv_noconst(ctx), iv, 8);
++    /* Decrypt again using new IV */
++    des_ede_cbc_cipher(ctx, out, out, inl - 16);
++    des_ede_cbc_cipher(ctx, icv, icv, 8);
++    /* Work out SHA1 hash of first portion */
++    SHA1(out, inl - 16, sha1tmp);
++
++    if (!CRYPTO_memcmp(sha1tmp, icv, 8))
++        rv = inl - 16;
++    OPENSSL_cleanse(icv, 8);
++    OPENSSL_cleanse(sha1tmp, SHA_DIGEST_LENGTH);
++    OPENSSL_cleanse(iv, 8);
++    OPENSSL_cleanse(EVP_CIPHER_CTX_iv_noconst(ctx), 8);
++    if (rv == -1)
++        OPENSSL_cleanse(out, inl - 16);
++
++    return rv;
++}
++
++static int des_ede3_wrap(EVP_CIPHER_CTX *ctx, unsigned char *out,
++                         const unsigned char *in, size_t inl)
++{
++    unsigned char sha1tmp[SHA_DIGEST_LENGTH];
++    if (out == NULL)
++        return inl + 16;
++    /* Copy input to output buffer + 8 so we have space for IV */
++    memmove(out + 8, in, inl);
++    /* Work out ICV */
++    SHA1(in, inl, sha1tmp);
++    memcpy(out + inl + 8, sha1tmp, 8);
++    OPENSSL_cleanse(sha1tmp, SHA_DIGEST_LENGTH);
++    /* Generate random IV */
++    if (RAND_bytes(EVP_CIPHER_CTX_iv_noconst(ctx), 8) <= 0)
++        return -1;
++    memcpy(out, EVP_CIPHER_CTX_iv_noconst(ctx), 8);
++    /* Encrypt everything after IV in place */
++    des_ede_cbc_cipher(ctx, out + 8, out + 8, inl + 8);
++    BUF_reverse(out, NULL, inl + 16);
++    memcpy(EVP_CIPHER_CTX_iv_noconst(ctx), wrap_iv, 8);
++    des_ede_cbc_cipher(ctx, out, out, inl + 16);
++    return inl + 16;
++}
++
++static int des_ede3_wrap_cipher(EVP_CIPHER_CTX *ctx, unsigned char *out,
++                                const unsigned char *in, size_t inl)
++{
++    /*
++     * Sanity check input length: we typically only wrap keys so EVP_MAXCHUNK
++     * is more than will ever be needed. Also input length must be a multiple
++     * of 8 bits.
++     */
++    if (inl >= EVP_MAXCHUNK || inl % 8)
++        return -1;
++
++    if (is_partially_overlapping(out, in, inl)) {
++        EVPerr(EVP_F_DES_EDE3_WRAP_CIPHER, EVP_R_PARTIALLY_OVERLAPPING);
++        return 0;
++    }
++
++    if (EVP_CIPHER_CTX_encrypting(ctx))
++        return des_ede3_wrap(ctx, out, in, inl);
++    else
++        return des_ede3_unwrap(ctx, out, in, inl);
++}
++
++static const EVP_CIPHER des3_wrap = {
++    NID_id_smime_alg_CMS3DESwrap,
++    8, 24, 0,
++    EVP_CIPH_WRAP_MODE | EVP_CIPH_CUSTOM_IV | EVP_CIPH_FLAG_CUSTOM_CIPHER
++        | EVP_CIPH_FLAG_DEFAULT_ASN1,
++    des_ede3_init_key, des_ede3_wrap_cipher,
++    NULL,
++    sizeof(DES_EDE_KEY),
++    NULL, NULL, NULL, NULL
++};
++
++const EVP_CIPHER *EVP_des_ede3_wrap(void)
++{
++    return &des3_wrap;
++}
++
++#endif
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/evp/e_idea.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/evp/e_idea.c
+new file mode 100644
+index 0000000..93f6a41
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/evp/e_idea.c
+@@ -0,0 +1,70 @@
++/*
++ * Copyright 1995-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include "internal/cryptlib.h"
++
++#ifndef OPENSSL_NO_IDEA
++# include 
++# include 
++# include "internal/evp_int.h"
++# include 
++
++/* Can't use IMPLEMENT_BLOCK_CIPHER because IDEA_ecb_encrypt is different */
++
++typedef struct {
++    IDEA_KEY_SCHEDULE ks;
++} EVP_IDEA_KEY;
++
++static int idea_init_key(EVP_CIPHER_CTX *ctx, const unsigned char *key,
++                         const unsigned char *iv, int enc);
++
++/*
++ * NB IDEA_ecb_encrypt doesn't take an 'encrypt' argument so we treat it as a
++ * special case
++ */
++
++static int idea_ecb_cipher(EVP_CIPHER_CTX *ctx, unsigned char *out,
++                           const unsigned char *in, size_t inl)
++{
++    BLOCK_CIPHER_ecb_loop()
++        IDEA_ecb_encrypt(in + i, out + i, &EVP_C_DATA(EVP_IDEA_KEY,ctx)->ks);
++    return 1;
++}
++
++BLOCK_CIPHER_func_cbc(idea, IDEA, EVP_IDEA_KEY, ks)
++BLOCK_CIPHER_func_ofb(idea, IDEA, 64, EVP_IDEA_KEY, ks)
++BLOCK_CIPHER_func_cfb(idea, IDEA, 64, EVP_IDEA_KEY, ks)
++
++BLOCK_CIPHER_defs(idea, IDEA_KEY_SCHEDULE, NID_idea, 8, 16, 8, 64,
++                  0, idea_init_key, NULL,
++                  EVP_CIPHER_set_asn1_iv, EVP_CIPHER_get_asn1_iv, NULL)
++
++static int idea_init_key(EVP_CIPHER_CTX *ctx, const unsigned char *key,
++                         const unsigned char *iv, int enc)
++{
++    if (!enc) {
++        if (EVP_CIPHER_CTX_mode(ctx) == EVP_CIPH_OFB_MODE)
++            enc = 1;
++        else if (EVP_CIPHER_CTX_mode(ctx) == EVP_CIPH_CFB_MODE)
++            enc = 1;
++    }
++    if (enc)
++        IDEA_set_encrypt_key(key, &EVP_C_DATA(EVP_IDEA_KEY,ctx)->ks);
++    else {
++        IDEA_KEY_SCHEDULE tmp;
++
++        IDEA_set_encrypt_key(key, &tmp);
++        IDEA_set_decrypt_key(&tmp, &EVP_C_DATA(EVP_IDEA_KEY,ctx)->ks);
++        OPENSSL_cleanse((unsigned char *)&tmp, sizeof(IDEA_KEY_SCHEDULE));
++    }
++    return 1;
++}
++
++#endif
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/evp/e_null.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/evp/e_null.c
+new file mode 100644
+index 0000000..0dfc48a
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/evp/e_null.c
+@@ -0,0 +1,50 @@
++/*
++ * Copyright 1995-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include "internal/cryptlib.h"
++#include 
++#include 
++#include "internal/evp_int.h"
++
++static int null_init_key(EVP_CIPHER_CTX *ctx, const unsigned char *key,
++                         const unsigned char *iv, int enc);
++static int null_cipher(EVP_CIPHER_CTX *ctx, unsigned char *out,
++                       const unsigned char *in, size_t inl);
++static const EVP_CIPHER n_cipher = {
++    NID_undef,
++    1, 0, 0, 0,
++    null_init_key,
++    null_cipher,
++    NULL,
++    0,
++    NULL,
++    NULL,
++    NULL,
++    NULL
++};
++
++const EVP_CIPHER *EVP_enc_null(void)
++{
++    return (&n_cipher);
++}
++
++static int null_init_key(EVP_CIPHER_CTX *ctx, const unsigned char *key,
++                         const unsigned char *iv, int enc)
++{
++    return 1;
++}
++
++static int null_cipher(EVP_CIPHER_CTX *ctx, unsigned char *out,
++                       const unsigned char *in, size_t inl)
++{
++    if (in != out)
++        memcpy(out, in, inl);
++    return 1;
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/evp/e_old.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/evp/e_old.c
+new file mode 100644
+index 0000000..927908f
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/evp/e_old.c
+@@ -0,0 +1,113 @@
++/*
++ * Copyright 2004-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#if OPENSSL_API_COMPAT >= 0x00908000L
++NON_EMPTY_TRANSLATION_UNIT
++#else
++
++# include 
++
++/*
++ * Define some deprecated functions, so older programs don't crash and burn
++ * too quickly.  On Windows and VMS, these will never be used, since
++ * functions and variables in shared libraries are selected by entry point
++ * location, not by name.
++ */
++
++# ifndef OPENSSL_NO_BF
++#  undef EVP_bf_cfb
++const EVP_CIPHER *EVP_bf_cfb(void);
++const EVP_CIPHER *EVP_bf_cfb(void)
++{
++    return EVP_bf_cfb64();
++}
++# endif
++
++# ifndef OPENSSL_NO_DES
++#  undef EVP_des_cfb
++const EVP_CIPHER *EVP_des_cfb(void);
++const EVP_CIPHER *EVP_des_cfb(void)
++{
++    return EVP_des_cfb64();
++}
++
++#  undef EVP_des_ede3_cfb
++const EVP_CIPHER *EVP_des_ede3_cfb(void);
++const EVP_CIPHER *EVP_des_ede3_cfb(void)
++{
++    return EVP_des_ede3_cfb64();
++}
++
++#  undef EVP_des_ede_cfb
++const EVP_CIPHER *EVP_des_ede_cfb(void);
++const EVP_CIPHER *EVP_des_ede_cfb(void)
++{
++    return EVP_des_ede_cfb64();
++}
++# endif
++
++# ifndef OPENSSL_NO_IDEA
++#  undef EVP_idea_cfb
++const EVP_CIPHER *EVP_idea_cfb(void);
++const EVP_CIPHER *EVP_idea_cfb(void)
++{
++    return EVP_idea_cfb64();
++}
++# endif
++
++# ifndef OPENSSL_NO_RC2
++#  undef EVP_rc2_cfb
++const EVP_CIPHER *EVP_rc2_cfb(void);
++const EVP_CIPHER *EVP_rc2_cfb(void)
++{
++    return EVP_rc2_cfb64();
++}
++# endif
++
++# ifndef OPENSSL_NO_CAST
++#  undef EVP_cast5_cfb
++const EVP_CIPHER *EVP_cast5_cfb(void);
++const EVP_CIPHER *EVP_cast5_cfb(void)
++{
++    return EVP_cast5_cfb64();
++}
++# endif
++
++# ifndef OPENSSL_NO_RC5
++#  undef EVP_rc5_32_12_16_cfb
++const EVP_CIPHER *EVP_rc5_32_12_16_cfb(void);
++const EVP_CIPHER *EVP_rc5_32_12_16_cfb(void)
++{
++    return EVP_rc5_32_12_16_cfb64();
++}
++# endif
++
++# undef EVP_aes_128_cfb
++const EVP_CIPHER *EVP_aes_128_cfb(void);
++const EVP_CIPHER *EVP_aes_128_cfb(void)
++{
++    return EVP_aes_128_cfb128();
++}
++
++# undef EVP_aes_192_cfb
++const EVP_CIPHER *EVP_aes_192_cfb(void);
++const EVP_CIPHER *EVP_aes_192_cfb(void)
++{
++    return EVP_aes_192_cfb128();
++}
++
++# undef EVP_aes_256_cfb
++const EVP_CIPHER *EVP_aes_256_cfb(void);
++const EVP_CIPHER *EVP_aes_256_cfb(void)
++{
++    return EVP_aes_256_cfb128();
++}
++
++#endif
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/evp/e_rc2.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/evp/e_rc2.c
+new file mode 100644
+index 0000000..ed10bb3
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/evp/e_rc2.c
+@@ -0,0 +1,189 @@
++/*
++ * Copyright 1995-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include "internal/cryptlib.h"
++
++#ifndef OPENSSL_NO_RC2
++
++# include 
++# include 
++# include "internal/evp_int.h"
++# include 
++
++static int rc2_init_key(EVP_CIPHER_CTX *ctx, const unsigned char *key,
++                        const unsigned char *iv, int enc);
++static int rc2_meth_to_magic(EVP_CIPHER_CTX *ctx);
++static int rc2_magic_to_meth(int i);
++static int rc2_set_asn1_type_and_iv(EVP_CIPHER_CTX *c, ASN1_TYPE *type);
++static int rc2_get_asn1_type_and_iv(EVP_CIPHER_CTX *c, ASN1_TYPE *type);
++static int rc2_ctrl(EVP_CIPHER_CTX *c, int type, int arg, void *ptr);
++
++typedef struct {
++    int key_bits;               /* effective key bits */
++    RC2_KEY ks;                 /* key schedule */
++} EVP_RC2_KEY;
++
++# define data(ctx)       EVP_C_DATA(EVP_RC2_KEY,ctx)
++
++IMPLEMENT_BLOCK_CIPHER(rc2, ks, RC2, EVP_RC2_KEY, NID_rc2,
++                       8,
++                       RC2_KEY_LENGTH, 8, 64,
++                       EVP_CIPH_VARIABLE_LENGTH | EVP_CIPH_CTRL_INIT,
++                       rc2_init_key, NULL,
++                       rc2_set_asn1_type_and_iv, rc2_get_asn1_type_and_iv,
++                       rc2_ctrl)
++# define RC2_40_MAGIC    0xa0
++# define RC2_64_MAGIC    0x78
++# define RC2_128_MAGIC   0x3a
++static const EVP_CIPHER r2_64_cbc_cipher = {
++    NID_rc2_64_cbc,
++    8, 8 /* 64 bit */ , 8,
++    EVP_CIPH_CBC_MODE | EVP_CIPH_VARIABLE_LENGTH | EVP_CIPH_CTRL_INIT,
++    rc2_init_key,
++    rc2_cbc_cipher,
++    NULL,
++    sizeof(EVP_RC2_KEY),
++    rc2_set_asn1_type_and_iv,
++    rc2_get_asn1_type_and_iv,
++    rc2_ctrl,
++    NULL
++};
++
++static const EVP_CIPHER r2_40_cbc_cipher = {
++    NID_rc2_40_cbc,
++    8, 5 /* 40 bit */ , 8,
++    EVP_CIPH_CBC_MODE | EVP_CIPH_VARIABLE_LENGTH | EVP_CIPH_CTRL_INIT,
++    rc2_init_key,
++    rc2_cbc_cipher,
++    NULL,
++    sizeof(EVP_RC2_KEY),
++    rc2_set_asn1_type_and_iv,
++    rc2_get_asn1_type_and_iv,
++    rc2_ctrl,
++    NULL
++};
++
++const EVP_CIPHER *EVP_rc2_64_cbc(void)
++{
++    return (&r2_64_cbc_cipher);
++}
++
++const EVP_CIPHER *EVP_rc2_40_cbc(void)
++{
++    return (&r2_40_cbc_cipher);
++}
++
++static int rc2_init_key(EVP_CIPHER_CTX *ctx, const unsigned char *key,
++                        const unsigned char *iv, int enc)
++{
++    RC2_set_key(&data(ctx)->ks, EVP_CIPHER_CTX_key_length(ctx),
++                key, data(ctx)->key_bits);
++    return 1;
++}
++
++static int rc2_meth_to_magic(EVP_CIPHER_CTX *e)
++{
++    int i;
++
++    EVP_CIPHER_CTX_ctrl(e, EVP_CTRL_GET_RC2_KEY_BITS, 0, &i);
++    if (i == 128)
++        return (RC2_128_MAGIC);
++    else if (i == 64)
++        return (RC2_64_MAGIC);
++    else if (i == 40)
++        return (RC2_40_MAGIC);
++    else
++        return (0);
++}
++
++static int rc2_magic_to_meth(int i)
++{
++    if (i == RC2_128_MAGIC)
++        return 128;
++    else if (i == RC2_64_MAGIC)
++        return 64;
++    else if (i == RC2_40_MAGIC)
++        return 40;
++    else {
++        EVPerr(EVP_F_RC2_MAGIC_TO_METH, EVP_R_UNSUPPORTED_KEY_SIZE);
++        return (0);
++    }
++}
++
++static int rc2_get_asn1_type_and_iv(EVP_CIPHER_CTX *c, ASN1_TYPE *type)
++{
++    long num = 0;
++    int i = 0;
++    int key_bits;
++    unsigned int l;
++    unsigned char iv[EVP_MAX_IV_LENGTH];
++
++    if (type != NULL) {
++        l = EVP_CIPHER_CTX_iv_length(c);
++        OPENSSL_assert(l <= sizeof(iv));
++        i = ASN1_TYPE_get_int_octetstring(type, &num, iv, l);
++        if (i != (int)l)
++            return -1;
++        key_bits = rc2_magic_to_meth((int)num);
++        if (!key_bits)
++            return -1;
++        if (i > 0 && !EVP_CipherInit_ex(c, NULL, NULL, NULL, iv, -1))
++            return -1;
++        EVP_CIPHER_CTX_ctrl(c, EVP_CTRL_SET_RC2_KEY_BITS, key_bits, NULL);
++        if (EVP_CIPHER_CTX_set_key_length(c, key_bits / 8) <= 0)
++            return -1;
++    }
++    return i;
++}
++
++static int rc2_set_asn1_type_and_iv(EVP_CIPHER_CTX *c, ASN1_TYPE *type)
++{
++    long num;
++    int i = 0, j;
++
++    if (type != NULL) {
++        num = rc2_meth_to_magic(c);
++        j = EVP_CIPHER_CTX_iv_length(c);
++        i = ASN1_TYPE_set_int_octetstring(type, num,
++                                          (unsigned char *)EVP_CIPHER_CTX_original_iv(c),
++                                          j);
++    }
++    return (i);
++}
++
++static int rc2_ctrl(EVP_CIPHER_CTX *c, int type, int arg, void *ptr)
++{
++    switch (type) {
++    case EVP_CTRL_INIT:
++        data(c)->key_bits = EVP_CIPHER_CTX_key_length(c) * 8;
++        return 1;
++
++    case EVP_CTRL_GET_RC2_KEY_BITS:
++        *(int *)ptr = data(c)->key_bits;
++        return 1;
++
++    case EVP_CTRL_SET_RC2_KEY_BITS:
++        if (arg > 0) {
++            data(c)->key_bits = arg;
++            return 1;
++        }
++        return 0;
++# ifdef PBE_PRF_TEST
++    case EVP_CTRL_PBE_PRF_NID:
++        *(int *)ptr = NID_hmacWithMD5;
++        return 1;
++# endif
++
++    default:
++        return -1;
++    }
++}
++
++#endif
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/evp/e_rc4.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/evp/e_rc4.c
+new file mode 100644
+index 0000000..ea95dea
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/evp/e_rc4.c
+@@ -0,0 +1,82 @@
++/*
++ * Copyright 1995-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include "internal/cryptlib.h"
++
++#ifndef OPENSSL_NO_RC4
++
++# include 
++# include 
++# include 
++
++# include "internal/evp_int.h"
++
++typedef struct {
++    RC4_KEY ks;                 /* working key */
++} EVP_RC4_KEY;
++
++# define data(ctx) ((EVP_RC4_KEY *)EVP_CIPHER_CTX_get_cipher_data(ctx))
++
++static int rc4_init_key(EVP_CIPHER_CTX *ctx, const unsigned char *key,
++                        const unsigned char *iv, int enc);
++static int rc4_cipher(EVP_CIPHER_CTX *ctx, unsigned char *out,
++                      const unsigned char *in, size_t inl);
++static const EVP_CIPHER r4_cipher = {
++    NID_rc4,
++    1, EVP_RC4_KEY_SIZE, 0,
++    EVP_CIPH_VARIABLE_LENGTH,
++    rc4_init_key,
++    rc4_cipher,
++    NULL,
++    sizeof(EVP_RC4_KEY),
++    NULL,
++    NULL,
++    NULL,
++    NULL
++};
++
++static const EVP_CIPHER r4_40_cipher = {
++    NID_rc4_40,
++    1, 5 /* 40 bit */ , 0,
++    EVP_CIPH_VARIABLE_LENGTH,
++    rc4_init_key,
++    rc4_cipher,
++    NULL,
++    sizeof(EVP_RC4_KEY),
++    NULL,
++    NULL,
++    NULL,
++    NULL
++};
++
++const EVP_CIPHER *EVP_rc4(void)
++{
++    return (&r4_cipher);
++}
++
++const EVP_CIPHER *EVP_rc4_40(void)
++{
++    return (&r4_40_cipher);
++}
++
++static int rc4_init_key(EVP_CIPHER_CTX *ctx, const unsigned char *key,
++                        const unsigned char *iv, int enc)
++{
++    RC4_set_key(&data(ctx)->ks, EVP_CIPHER_CTX_key_length(ctx), key);
++    return 1;
++}
++
++static int rc4_cipher(EVP_CIPHER_CTX *ctx, unsigned char *out,
++                      const unsigned char *in, size_t inl)
++{
++    RC4(&data(ctx)->ks, inl, in, out);
++    return 1;
++}
++#endif
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/evp/e_rc4_hmac_md5.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/evp/e_rc4_hmac_md5.c
+new file mode 100644
+index 0000000..8ab18c1
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/evp/e_rc4_hmac_md5.c
+@@ -0,0 +1,262 @@
++/*
++ * Copyright 2011-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++
++#include 
++#include 
++
++#if !defined(OPENSSL_NO_RC4) && !defined(OPENSSL_NO_MD5)
++
++# include 
++# include 
++# include 
++# include 
++# include 
++# include "internal/evp_int.h"
++
++typedef struct {
++    RC4_KEY ks;
++    MD5_CTX head, tail, md;
++    size_t payload_length;
++} EVP_RC4_HMAC_MD5;
++
++# define NO_PAYLOAD_LENGTH       ((size_t)-1)
++
++void rc4_md5_enc(RC4_KEY *key, const void *in0, void *out,
++                 MD5_CTX *ctx, const void *inp, size_t blocks);
++
++# define data(ctx) ((EVP_RC4_HMAC_MD5 *)EVP_CIPHER_CTX_get_cipher_data(ctx))
++
++static int rc4_hmac_md5_init_key(EVP_CIPHER_CTX *ctx,
++                                 const unsigned char *inkey,
++                                 const unsigned char *iv, int enc)
++{
++    EVP_RC4_HMAC_MD5 *key = data(ctx);
++
++    RC4_set_key(&key->ks, EVP_CIPHER_CTX_key_length(ctx), inkey);
++
++    MD5_Init(&key->head);       /* handy when benchmarking */
++    key->tail = key->head;
++    key->md = key->head;
++
++    key->payload_length = NO_PAYLOAD_LENGTH;
++
++    return 1;
++}
++
++# if     defined(RC4_ASM) && defined(MD5_ASM) &&     (	   \
++        defined(__x86_64)       || defined(__x86_64__)  || \
++        defined(_M_AMD64)       || defined(_M_X64)      )
++#  define STITCHED_CALL
++# endif
++
++# if !defined(STITCHED_CALL)
++#  define rc4_off 0
++#  define md5_off 0
++# endif
++
++static int rc4_hmac_md5_cipher(EVP_CIPHER_CTX *ctx, unsigned char *out,
++                               const unsigned char *in, size_t len)
++{
++    EVP_RC4_HMAC_MD5 *key = data(ctx);
++# if defined(STITCHED_CALL)
++    size_t rc4_off = 32 - 1 - (key->ks.x & (32 - 1)), /* 32 is $MOD from
++                                                       * rc4_md5-x86_64.pl */
++        md5_off = MD5_CBLOCK - key->md.num, blocks;
++    unsigned int l;
++    extern unsigned int OPENSSL_ia32cap_P[];
++# endif
++    size_t plen = key->payload_length;
++
++    if (plen != NO_PAYLOAD_LENGTH && len != (plen + MD5_DIGEST_LENGTH))
++        return 0;
++
++    if (EVP_CIPHER_CTX_encrypting(ctx)) {
++        if (plen == NO_PAYLOAD_LENGTH)
++            plen = len;
++# if defined(STITCHED_CALL)
++        /* cipher has to "fall behind" */
++        if (rc4_off > md5_off)
++            md5_off += MD5_CBLOCK;
++
++        if (plen > md5_off && (blocks = (plen - md5_off) / MD5_CBLOCK) &&
++            (OPENSSL_ia32cap_P[0] & (1 << 20)) == 0) {
++            MD5_Update(&key->md, in, md5_off);
++            RC4(&key->ks, rc4_off, in, out);
++
++            rc4_md5_enc(&key->ks, in + rc4_off, out + rc4_off,
++                        &key->md, in + md5_off, blocks);
++            blocks *= MD5_CBLOCK;
++            rc4_off += blocks;
++            md5_off += blocks;
++            key->md.Nh += blocks >> 29;
++            key->md.Nl += blocks <<= 3;
++            if (key->md.Nl < (unsigned int)blocks)
++                key->md.Nh++;
++        } else {
++            rc4_off = 0;
++            md5_off = 0;
++        }
++# endif
++        MD5_Update(&key->md, in + md5_off, plen - md5_off);
++
++        if (plen != len) {      /* "TLS" mode of operation */
++            if (in != out)
++                memcpy(out + rc4_off, in + rc4_off, plen - rc4_off);
++
++            /* calculate HMAC and append it to payload */
++            MD5_Final(out + plen, &key->md);
++            key->md = key->tail;
++            MD5_Update(&key->md, out + plen, MD5_DIGEST_LENGTH);
++            MD5_Final(out + plen, &key->md);
++            /* encrypt HMAC at once */
++            RC4(&key->ks, len - rc4_off, out + rc4_off, out + rc4_off);
++        } else {
++            RC4(&key->ks, len - rc4_off, in + rc4_off, out + rc4_off);
++        }
++    } else {
++        unsigned char mac[MD5_DIGEST_LENGTH];
++# if defined(STITCHED_CALL)
++        /* digest has to "fall behind" */
++        if (md5_off > rc4_off)
++            rc4_off += 2 * MD5_CBLOCK;
++        else
++            rc4_off += MD5_CBLOCK;
++
++        if (len > rc4_off && (blocks = (len - rc4_off) / MD5_CBLOCK) &&
++            (OPENSSL_ia32cap_P[0] & (1 << 20)) == 0) {
++            RC4(&key->ks, rc4_off, in, out);
++            MD5_Update(&key->md, out, md5_off);
++
++            rc4_md5_enc(&key->ks, in + rc4_off, out + rc4_off,
++                        &key->md, out + md5_off, blocks);
++            blocks *= MD5_CBLOCK;
++            rc4_off += blocks;
++            md5_off += blocks;
++            l = (key->md.Nl + (blocks << 3)) & 0xffffffffU;
++            if (l < key->md.Nl)
++                key->md.Nh++;
++            key->md.Nl = l;
++            key->md.Nh += blocks >> 29;
++        } else {
++            md5_off = 0;
++            rc4_off = 0;
++        }
++# endif
++        /* decrypt HMAC at once */
++        RC4(&key->ks, len - rc4_off, in + rc4_off, out + rc4_off);
++        if (plen != NO_PAYLOAD_LENGTH) { /* "TLS" mode of operation */
++            MD5_Update(&key->md, out + md5_off, plen - md5_off);
++
++            /* calculate HMAC and verify it */
++            MD5_Final(mac, &key->md);
++            key->md = key->tail;
++            MD5_Update(&key->md, mac, MD5_DIGEST_LENGTH);
++            MD5_Final(mac, &key->md);
++
++            if (CRYPTO_memcmp(out + plen, mac, MD5_DIGEST_LENGTH))
++                return 0;
++        } else {
++            MD5_Update(&key->md, out + md5_off, len - md5_off);
++        }
++    }
++
++    key->payload_length = NO_PAYLOAD_LENGTH;
++
++    return 1;
++}
++
++static int rc4_hmac_md5_ctrl(EVP_CIPHER_CTX *ctx, int type, int arg,
++                             void *ptr)
++{
++    EVP_RC4_HMAC_MD5 *key = data(ctx);
++
++    switch (type) {
++    case EVP_CTRL_AEAD_SET_MAC_KEY:
++        {
++            unsigned int i;
++            unsigned char hmac_key[64];
++
++            memset(hmac_key, 0, sizeof(hmac_key));
++
++            if (arg > (int)sizeof(hmac_key)) {
++                MD5_Init(&key->head);
++                MD5_Update(&key->head, ptr, arg);
++                MD5_Final(hmac_key, &key->head);
++            } else {
++                memcpy(hmac_key, ptr, arg);
++            }
++
++            for (i = 0; i < sizeof(hmac_key); i++)
++                hmac_key[i] ^= 0x36; /* ipad */
++            MD5_Init(&key->head);
++            MD5_Update(&key->head, hmac_key, sizeof(hmac_key));
++
++            for (i = 0; i < sizeof(hmac_key); i++)
++                hmac_key[i] ^= 0x36 ^ 0x5c; /* opad */
++            MD5_Init(&key->tail);
++            MD5_Update(&key->tail, hmac_key, sizeof(hmac_key));
++
++            OPENSSL_cleanse(hmac_key, sizeof(hmac_key));
++
++            return 1;
++        }
++    case EVP_CTRL_AEAD_TLS1_AAD:
++        {
++            unsigned char *p = ptr;
++            unsigned int len;
++
++            if (arg != EVP_AEAD_TLS1_AAD_LEN)
++                return -1;
++
++            len = p[arg - 2] << 8 | p[arg - 1];
++
++            if (!EVP_CIPHER_CTX_encrypting(ctx)) {
++                if (len < MD5_DIGEST_LENGTH)
++                    return -1;
++                len -= MD5_DIGEST_LENGTH;
++                p[arg - 2] = len >> 8;
++                p[arg - 1] = len;
++            }
++            key->payload_length = len;
++            key->md = key->head;
++            MD5_Update(&key->md, p, arg);
++
++            return MD5_DIGEST_LENGTH;
++        }
++    default:
++        return -1;
++    }
++}
++
++static EVP_CIPHER r4_hmac_md5_cipher = {
++# ifdef NID_rc4_hmac_md5
++    NID_rc4_hmac_md5,
++# else
++    NID_undef,
++# endif
++    1, EVP_RC4_KEY_SIZE, 0,
++    EVP_CIPH_STREAM_CIPHER | EVP_CIPH_VARIABLE_LENGTH |
++        EVP_CIPH_FLAG_AEAD_CIPHER,
++    rc4_hmac_md5_init_key,
++    rc4_hmac_md5_cipher,
++    NULL,
++    sizeof(EVP_RC4_HMAC_MD5),
++    NULL,
++    NULL,
++    rc4_hmac_md5_ctrl,
++    NULL
++};
++
++const EVP_CIPHER *EVP_rc4_hmac_md5(void)
++{
++    return (&r4_hmac_md5_cipher);
++}
++#endif
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/evp/e_rc5.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/evp/e_rc5.c
+new file mode 100644
+index 0000000..f69ba5b
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/evp/e_rc5.c
+@@ -0,0 +1,74 @@
++/*
++ * Copyright 1995-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include "internal/cryptlib.h"
++
++#ifndef OPENSSL_NO_RC5
++
++# include 
++# include 
++# include 
++# include "evp_locl.h"
++# include 
++
++static int r_32_12_16_init_key(EVP_CIPHER_CTX *ctx, const unsigned char *key,
++                               const unsigned char *iv, int enc);
++static int rc5_ctrl(EVP_CIPHER_CTX *c, int type, int arg, void *ptr);
++
++typedef struct {
++    int rounds;                 /* number of rounds */
++    RC5_32_KEY ks;              /* key schedule */
++} EVP_RC5_KEY;
++
++# define data(ctx)       EVP_C_DATA(EVP_RC5_KEY,ctx)
++
++IMPLEMENT_BLOCK_CIPHER(rc5_32_12_16, ks, RC5_32, EVP_RC5_KEY, NID_rc5,
++                       8, RC5_32_KEY_LENGTH, 8, 64,
++                       EVP_CIPH_VARIABLE_LENGTH | EVP_CIPH_CTRL_INIT,
++                       r_32_12_16_init_key, NULL, NULL, NULL, rc5_ctrl)
++
++static int rc5_ctrl(EVP_CIPHER_CTX *c, int type, int arg, void *ptr)
++{
++    switch (type) {
++    case EVP_CTRL_INIT:
++        data(c)->rounds = RC5_12_ROUNDS;
++        return 1;
++
++    case EVP_CTRL_GET_RC5_ROUNDS:
++        *(int *)ptr = data(c)->rounds;
++        return 1;
++
++    case EVP_CTRL_SET_RC5_ROUNDS:
++        switch (arg) {
++        case RC5_8_ROUNDS:
++        case RC5_12_ROUNDS:
++        case RC5_16_ROUNDS:
++            data(c)->rounds = arg;
++            return 1;
++
++        default:
++            EVPerr(EVP_F_RC5_CTRL, EVP_R_UNSUPPORTED_NUMBER_OF_ROUNDS);
++            return 0;
++        }
++
++    default:
++        return -1;
++    }
++}
++
++static int r_32_12_16_init_key(EVP_CIPHER_CTX *ctx, const unsigned char *key,
++                               const unsigned char *iv, int enc)
++{
++    RC5_32_set_key(&data(ctx)->ks, EVP_CIPHER_CTX_key_length(ctx),
++                   key, data(ctx)->rounds);
++    return 1;
++}
++
++#endif
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/evp/e_seed.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/evp/e_seed.c
+new file mode 100644
+index 0000000..40aec5f
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/evp/e_seed.c
+@@ -0,0 +1,39 @@
++/*
++ * Copyright 2007-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#ifdef OPENSSL_NO_SEED
++NON_EMPTY_TRANSLATION_UNIT
++#else
++# include 
++# include 
++# include 
++# include 
++# include 
++# include "internal/evp_int.h"
++
++static int seed_init_key(EVP_CIPHER_CTX *ctx, const unsigned char *key,
++                         const unsigned char *iv, int enc);
++
++typedef struct {
++    SEED_KEY_SCHEDULE ks;
++} EVP_SEED_KEY;
++
++IMPLEMENT_BLOCK_CIPHER(seed, ks, SEED, EVP_SEED_KEY, NID_seed,
++                       16, 16, 16, 128, EVP_CIPH_FLAG_DEFAULT_ASN1,
++                       seed_init_key, 0, 0, 0, 0)
++
++static int seed_init_key(EVP_CIPHER_CTX *ctx, const unsigned char *key,
++                         const unsigned char *iv, int enc)
++{
++    SEED_set_key(key, &EVP_C_DATA(EVP_SEED_KEY,ctx)->ks);
++    return 1;
++}
++
++#endif
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/evp/e_xcbc_d.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/evp/e_xcbc_d.c
+new file mode 100644
+index 0000000..effaf5c
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/evp/e_xcbc_d.c
+@@ -0,0 +1,83 @@
++/*
++ * Copyright 1995-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include "internal/cryptlib.h"
++
++#ifndef OPENSSL_NO_DES
++
++# include 
++# include 
++# include "internal/evp_int.h"
++# include 
++
++static int desx_cbc_init_key(EVP_CIPHER_CTX *ctx, const unsigned char *key,
++                             const unsigned char *iv, int enc);
++static int desx_cbc_cipher(EVP_CIPHER_CTX *ctx, unsigned char *out,
++                           const unsigned char *in, size_t inl);
++
++typedef struct {
++    DES_key_schedule ks;        /* key schedule */
++    DES_cblock inw;
++    DES_cblock outw;
++} DESX_CBC_KEY;
++
++# define data(ctx) EVP_C_DATA(DESX_CBC_KEY,ctx)
++
++static const EVP_CIPHER d_xcbc_cipher = {
++    NID_desx_cbc,
++    8, 24, 8,
++    EVP_CIPH_CBC_MODE,
++    desx_cbc_init_key,
++    desx_cbc_cipher,
++    NULL,
++    sizeof(DESX_CBC_KEY),
++    EVP_CIPHER_set_asn1_iv,
++    EVP_CIPHER_get_asn1_iv,
++    NULL,
++    NULL
++};
++
++const EVP_CIPHER *EVP_desx_cbc(void)
++{
++    return (&d_xcbc_cipher);
++}
++
++static int desx_cbc_init_key(EVP_CIPHER_CTX *ctx, const unsigned char *key,
++                             const unsigned char *iv, int enc)
++{
++    DES_cblock *deskey = (DES_cblock *)key;
++
++    DES_set_key_unchecked(deskey, &data(ctx)->ks);
++    memcpy(&data(ctx)->inw[0], &key[8], 8);
++    memcpy(&data(ctx)->outw[0], &key[16], 8);
++
++    return 1;
++}
++
++static int desx_cbc_cipher(EVP_CIPHER_CTX *ctx, unsigned char *out,
++                           const unsigned char *in, size_t inl)
++{
++    while (inl >= EVP_MAXCHUNK) {
++        DES_xcbc_encrypt(in, out, (long)EVP_MAXCHUNK, &data(ctx)->ks,
++                         (DES_cblock *)EVP_CIPHER_CTX_iv_noconst(ctx),
++                         &data(ctx)->inw, &data(ctx)->outw,
++                         EVP_CIPHER_CTX_encrypting(ctx));
++        inl -= EVP_MAXCHUNK;
++        in += EVP_MAXCHUNK;
++        out += EVP_MAXCHUNK;
++    }
++    if (inl)
++        DES_xcbc_encrypt(in, out, (long)inl, &data(ctx)->ks,
++                         (DES_cblock *)EVP_CIPHER_CTX_iv_noconst(ctx),
++                         &data(ctx)->inw, &data(ctx)->outw,
++                         EVP_CIPHER_CTX_encrypting(ctx));
++    return 1;
++}
++#endif
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/evp/encode.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/evp/encode.c
+new file mode 100644
+index 0000000..abb1044
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/evp/encode.c
+@@ -0,0 +1,404 @@
++/*
++ * Copyright 1995-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include 
++#include "internal/cryptlib.h"
++#include 
++#include "evp_locl.h"
++
++static unsigned char conv_ascii2bin(unsigned char a);
++#ifndef CHARSET_EBCDIC
++# define conv_bin2ascii(a)       (data_bin2ascii[(a)&0x3f])
++#else
++/*
++ * We assume that PEM encoded files are EBCDIC files (i.e., printable text
++ * files). Convert them here while decoding. When encoding, output is EBCDIC
++ * (text) format again. (No need for conversion in the conv_bin2ascii macro,
++ * as the underlying textstring data_bin2ascii[] is already EBCDIC)
++ */
++# define conv_bin2ascii(a)       (data_bin2ascii[(a)&0x3f])
++#endif
++
++/*-
++ * 64 char lines
++ * pad input with 0
++ * left over chars are set to =
++ * 1 byte  => xx==
++ * 2 bytes => xxx=
++ * 3 bytes => xxxx
++ */
++#define BIN_PER_LINE    (64/4*3)
++#define CHUNKS_PER_LINE (64/4)
++#define CHAR_PER_LINE   (64+1)
++
++static const unsigned char data_bin2ascii[65] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ\
++abcdefghijklmnopqrstuvwxyz0123456789+/";
++
++/*-
++ * 0xF0 is a EOLN
++ * 0xF1 is ignore but next needs to be 0xF0 (for \r\n processing).
++ * 0xF2 is EOF
++ * 0xE0 is ignore at start of line.
++ * 0xFF is error
++ */
++
++#define B64_EOLN                0xF0
++#define B64_CR                  0xF1
++#define B64_EOF                 0xF2
++#define B64_WS                  0xE0
++#define B64_ERROR               0xFF
++#define B64_NOT_BASE64(a)       (((a)|0x13) == 0xF3)
++#define B64_BASE64(a)           (!B64_NOT_BASE64(a))
++
++static const unsigned char data_ascii2bin[128] = {
++    0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
++    0xFF, 0xE0, 0xF0, 0xFF, 0xFF, 0xF1, 0xFF, 0xFF,
++    0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
++    0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
++    0xE0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
++    0xFF, 0xFF, 0xFF, 0x3E, 0xFF, 0xF2, 0xFF, 0x3F,
++    0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B,
++    0x3C, 0x3D, 0xFF, 0xFF, 0xFF, 0x00, 0xFF, 0xFF,
++    0xFF, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06,
++    0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E,
++    0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16,
++    0x17, 0x18, 0x19, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
++    0xFF, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x20,
++    0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28,
++    0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, 0x30,
++    0x31, 0x32, 0x33, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
++};
++
++#ifndef CHARSET_EBCDIC
++static unsigned char conv_ascii2bin(unsigned char a)
++{
++    if (a & 0x80)
++        return B64_ERROR;
++    return data_ascii2bin[a];
++}
++#else
++static unsigned char conv_ascii2bin(unsigned char a)
++{
++    a = os_toascii[a];
++    if (a & 0x80)
++        return B64_ERROR;
++    return data_ascii2bin[a];
++}
++#endif
++
++EVP_ENCODE_CTX *EVP_ENCODE_CTX_new(void)
++{
++    return OPENSSL_zalloc(sizeof(EVP_ENCODE_CTX));
++}
++
++void EVP_ENCODE_CTX_free(EVP_ENCODE_CTX *ctx)
++{
++    OPENSSL_free(ctx);
++}
++
++int EVP_ENCODE_CTX_copy(EVP_ENCODE_CTX *dctx, EVP_ENCODE_CTX *sctx)
++{
++    memcpy(dctx, sctx, sizeof(EVP_ENCODE_CTX));
++
++    return 1;
++}
++
++int EVP_ENCODE_CTX_num(EVP_ENCODE_CTX *ctx)
++{
++    return ctx->num;
++}
++
++void EVP_EncodeInit(EVP_ENCODE_CTX *ctx)
++{
++    ctx->length = 48;
++    ctx->num = 0;
++    ctx->line_num = 0;
++}
++
++int EVP_EncodeUpdate(EVP_ENCODE_CTX *ctx, unsigned char *out, int *outl,
++                      const unsigned char *in, int inl)
++{
++    int i, j;
++    size_t total = 0;
++
++    *outl = 0;
++    if (inl <= 0)
++        return 0;
++    OPENSSL_assert(ctx->length <= (int)sizeof(ctx->enc_data));
++    if (ctx->length - ctx->num > inl) {
++        memcpy(&(ctx->enc_data[ctx->num]), in, inl);
++        ctx->num += inl;
++        return 1;
++    }
++    if (ctx->num != 0) {
++        i = ctx->length - ctx->num;
++        memcpy(&(ctx->enc_data[ctx->num]), in, i);
++        in += i;
++        inl -= i;
++        j = EVP_EncodeBlock(out, ctx->enc_data, ctx->length);
++        ctx->num = 0;
++        out += j;
++        *(out++) = '\n';
++        *out = '\0';
++        total = j + 1;
++    }
++    while (inl >= ctx->length && total <= INT_MAX) {
++        j = EVP_EncodeBlock(out, in, ctx->length);
++        in += ctx->length;
++        inl -= ctx->length;
++        out += j;
++        *(out++) = '\n';
++        *out = '\0';
++        total += j + 1;
++    }
++    if (total > INT_MAX) {
++        /* Too much output data! */
++        *outl = 0;
++        return 0;
++    }
++    if (inl != 0)
++        memcpy(&(ctx->enc_data[0]), in, inl);
++    ctx->num = inl;
++    *outl = total;
++
++    return 1;
++}
++
++void EVP_EncodeFinal(EVP_ENCODE_CTX *ctx, unsigned char *out, int *outl)
++{
++    unsigned int ret = 0;
++
++    if (ctx->num != 0) {
++        ret = EVP_EncodeBlock(out, ctx->enc_data, ctx->num);
++        out[ret++] = '\n';
++        out[ret] = '\0';
++        ctx->num = 0;
++    }
++    *outl = ret;
++}
++
++int EVP_EncodeBlock(unsigned char *t, const unsigned char *f, int dlen)
++{
++    int i, ret = 0;
++    unsigned long l;
++
++    for (i = dlen; i > 0; i -= 3) {
++        if (i >= 3) {
++            l = (((unsigned long)f[0]) << 16L) |
++                (((unsigned long)f[1]) << 8L) | f[2];
++            *(t++) = conv_bin2ascii(l >> 18L);
++            *(t++) = conv_bin2ascii(l >> 12L);
++            *(t++) = conv_bin2ascii(l >> 6L);
++            *(t++) = conv_bin2ascii(l);
++        } else {
++            l = ((unsigned long)f[0]) << 16L;
++            if (i == 2)
++                l |= ((unsigned long)f[1] << 8L);
++
++            *(t++) = conv_bin2ascii(l >> 18L);
++            *(t++) = conv_bin2ascii(l >> 12L);
++            *(t++) = (i == 1) ? '=' : conv_bin2ascii(l >> 6L);
++            *(t++) = '=';
++        }
++        ret += 4;
++        f += 3;
++    }
++
++    *t = '\0';
++    return (ret);
++}
++
++void EVP_DecodeInit(EVP_ENCODE_CTX *ctx)
++{
++    /* Only ctx->num is used during decoding. */
++    ctx->num = 0;
++    ctx->length = 0;
++    ctx->line_num = 0;
++    ctx->expect_nl = 0;
++}
++
++/*-
++ * -1 for error
++ *  0 for last line
++ *  1 for full line
++ *
++ * Note: even though EVP_DecodeUpdate attempts to detect and report end of
++ * content, the context doesn't currently remember it and will accept more data
++ * in the next call. Therefore, the caller is responsible for checking and
++ * rejecting a 0 return value in the middle of content.
++ *
++ * Note: even though EVP_DecodeUpdate has historically tried to detect end of
++ * content based on line length, this has never worked properly. Therefore,
++ * we now return 0 when one of the following is true:
++ *   - Padding or B64_EOF was detected and the last block is complete.
++ *   - Input has zero-length.
++ * -1 is returned if:
++ *   - Invalid characters are detected.
++ *   - There is extra trailing padding, or data after padding.
++ *   - B64_EOF is detected after an incomplete base64 block.
++ */
++int EVP_DecodeUpdate(EVP_ENCODE_CTX *ctx, unsigned char *out, int *outl,
++                     const unsigned char *in, int inl)
++{
++    int seof = 0, eof = 0, rv = -1, ret = 0, i, v, tmp, n, decoded_len;
++    unsigned char *d;
++
++    n = ctx->num;
++    d = ctx->enc_data;
++
++    if (n > 0 && d[n - 1] == '=') {
++        eof++;
++        if (n > 1 && d[n - 2] == '=')
++            eof++;
++    }
++
++     /* Legacy behaviour: an empty input chunk signals end of input. */
++    if (inl == 0) {
++        rv = 0;
++        goto end;
++    }
++
++    for (i = 0; i < inl; i++) {
++        tmp = *(in++);
++        v = conv_ascii2bin(tmp);
++        if (v == B64_ERROR) {
++            rv = -1;
++            goto end;
++        }
++
++        if (tmp == '=') {
++            eof++;
++        } else if (eof > 0 && B64_BASE64(v)) {
++            /* More data after padding. */
++            rv = -1;
++            goto end;
++        }
++
++        if (eof > 2) {
++            rv = -1;
++            goto end;
++        }
++
++        if (v == B64_EOF) {
++            seof = 1;
++            goto tail;
++        }
++
++        /* Only save valid base64 characters. */
++        if (B64_BASE64(v)) {
++            if (n >= 64) {
++                /*
++                 * We increment n once per loop, and empty the buffer as soon as
++                 * we reach 64 characters, so this can only happen if someone's
++                 * manually messed with the ctx. Refuse to write any more data.
++                 */
++                rv = -1;
++                goto end;
++            }
++            OPENSSL_assert(n < (int)sizeof(ctx->enc_data));
++            d[n++] = tmp;
++        }
++
++        if (n == 64) {
++            decoded_len = EVP_DecodeBlock(out, d, n);
++            n = 0;
++            if (decoded_len < 0 || eof > decoded_len) {
++                rv = -1;
++                goto end;
++            }
++            ret += decoded_len - eof;
++            out += decoded_len - eof;
++        }
++    }
++
++    /*
++     * Legacy behaviour: if the current line is a full base64-block (i.e., has
++     * 0 mod 4 base64 characters), it is processed immediately. We keep this
++     * behaviour as applications may not be calling EVP_DecodeFinal properly.
++     */
++tail:
++    if (n > 0) {
++        if ((n & 3) == 0) {
++            decoded_len = EVP_DecodeBlock(out, d, n);
++            n = 0;
++            if (decoded_len < 0 || eof > decoded_len) {
++                rv = -1;
++                goto end;
++            }
++            ret += (decoded_len - eof);
++        } else if (seof) {
++            /* EOF in the middle of a base64 block. */
++            rv = -1;
++            goto end;
++        }
++    }
++
++    rv = seof || (n == 0 && eof) ? 0 : 1;
++end:
++    /* Legacy behaviour. This should probably rather be zeroed on error. */
++    *outl = ret;
++    ctx->num = n;
++    return (rv);
++}
++
++int EVP_DecodeBlock(unsigned char *t, const unsigned char *f, int n)
++{
++    int i, ret = 0, a, b, c, d;
++    unsigned long l;
++
++    /* trim white space from the start of the line. */
++    while ((conv_ascii2bin(*f) == B64_WS) && (n > 0)) {
++        f++;
++        n--;
++    }
++
++    /*
++     * strip off stuff at the end of the line ascii2bin values B64_WS,
++     * B64_EOLN, B64_EOLN and B64_EOF
++     */
++    while ((n > 3) && (B64_NOT_BASE64(conv_ascii2bin(f[n - 1]))))
++        n--;
++
++    if (n % 4 != 0)
++        return (-1);
++
++    for (i = 0; i < n; i += 4) {
++        a = conv_ascii2bin(*(f++));
++        b = conv_ascii2bin(*(f++));
++        c = conv_ascii2bin(*(f++));
++        d = conv_ascii2bin(*(f++));
++        if ((a & 0x80) || (b & 0x80) || (c & 0x80) || (d & 0x80))
++            return (-1);
++        l = ((((unsigned long)a) << 18L) |
++             (((unsigned long)b) << 12L) |
++             (((unsigned long)c) << 6L) | (((unsigned long)d)));
++        *(t++) = (unsigned char)(l >> 16L) & 0xff;
++        *(t++) = (unsigned char)(l >> 8L) & 0xff;
++        *(t++) = (unsigned char)(l) & 0xff;
++        ret += 3;
++    }
++    return (ret);
++}
++
++int EVP_DecodeFinal(EVP_ENCODE_CTX *ctx, unsigned char *out, int *outl)
++{
++    int i;
++
++    *outl = 0;
++    if (ctx->num != 0) {
++        i = EVP_DecodeBlock(out, ctx->enc_data, ctx->num);
++        if (i < 0)
++            return (-1);
++        ctx->num = 0;
++        *outl = i;
++        return (1);
++    } else
++        return (1);
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/evp/evp_cnf.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/evp/evp_cnf.c
+new file mode 100644
+index 0000000..71d13b8
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/evp/evp_cnf.c
+@@ -0,0 +1,65 @@
++/*
++ * Copyright 2012-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include 
++#include 
++#include "internal/cryptlib.h"
++#include 
++#include 
++#include 
++
++/* Algorithm configuration module. */
++
++static int alg_module_init(CONF_IMODULE *md, const CONF *cnf)
++{
++    int i;
++    const char *oid_section;
++    STACK_OF(CONF_VALUE) *sktmp;
++    CONF_VALUE *oval;
++
++    oid_section = CONF_imodule_get_value(md);
++    if ((sktmp = NCONF_get_section(cnf, oid_section)) == NULL) {
++        EVPerr(EVP_F_ALG_MODULE_INIT, EVP_R_ERROR_LOADING_SECTION);
++        return 0;
++    }
++    for (i = 0; i < sk_CONF_VALUE_num(sktmp); i++) {
++        oval = sk_CONF_VALUE_value(sktmp, i);
++        if (strcmp(oval->name, "fips_mode") == 0) {
++            int m;
++            if (!X509V3_get_value_bool(oval, &m)) {
++                EVPerr(EVP_F_ALG_MODULE_INIT, EVP_R_INVALID_FIPS_MODE);
++                return 0;
++            }
++            if (m > 0) {
++#ifdef OPENSSL_FIPS
++                if (!FIPS_mode() && !FIPS_mode_set(1)) {
++                    EVPerr(EVP_F_ALG_MODULE_INIT,
++                           EVP_R_ERROR_SETTING_FIPS_MODE);
++                    return 0;
++                }
++#else
++                EVPerr(EVP_F_ALG_MODULE_INIT, EVP_R_FIPS_MODE_NOT_SUPPORTED);
++                return 0;
++#endif
++            }
++        } else {
++            EVPerr(EVP_F_ALG_MODULE_INIT, EVP_R_UNKNOWN_OPTION);
++            ERR_add_error_data(4, "name=", oval->name,
++                               ", value=", oval->value);
++        }
++
++    }
++    return 1;
++}
++
++void EVP_add_alg_module(void)
++{
++    CONF_module_add("alg_section", alg_module_init, 0);
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/evp/evp_enc.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/evp/evp_enc.c
+new file mode 100644
+index 0000000..f829e8d
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/evp/evp_enc.c
+@@ -0,0 +1,641 @@
++/*
++ * Copyright 1995-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include 
++#include "internal/cryptlib.h"
++#include 
++#include 
++#include 
++#include 
++#include "internal/evp_int.h"
++#include "evp_locl.h"
++
++int EVP_CIPHER_CTX_reset(EVP_CIPHER_CTX *c)
++{
++    if (c == NULL)
++        return 1;
++    if (c->cipher != NULL) {
++        if (c->cipher->cleanup && !c->cipher->cleanup(c))
++            return 0;
++        /* Cleanse cipher context data */
++        if (c->cipher_data && c->cipher->ctx_size)
++            OPENSSL_cleanse(c->cipher_data, c->cipher->ctx_size);
++    }
++    OPENSSL_free(c->cipher_data);
++#ifndef OPENSSL_NO_ENGINE
++    ENGINE_finish(c->engine);
++#endif
++    memset(c, 0, sizeof(*c));
++    return 1;
++}
++
++EVP_CIPHER_CTX *EVP_CIPHER_CTX_new(void)
++{
++    return OPENSSL_zalloc(sizeof(EVP_CIPHER_CTX));
++}
++
++void EVP_CIPHER_CTX_free(EVP_CIPHER_CTX *ctx)
++{
++    EVP_CIPHER_CTX_reset(ctx);
++    OPENSSL_free(ctx);
++}
++
++int EVP_CipherInit(EVP_CIPHER_CTX *ctx, const EVP_CIPHER *cipher,
++                   const unsigned char *key, const unsigned char *iv, int enc)
++{
++    EVP_CIPHER_CTX_reset(ctx);
++    return EVP_CipherInit_ex(ctx, cipher, NULL, key, iv, enc);
++}
++
++int EVP_CipherInit_ex(EVP_CIPHER_CTX *ctx, const EVP_CIPHER *cipher,
++                      ENGINE *impl, const unsigned char *key,
++                      const unsigned char *iv, int enc)
++{
++    if (enc == -1)
++        enc = ctx->encrypt;
++    else {
++        if (enc)
++            enc = 1;
++        ctx->encrypt = enc;
++    }
++#ifndef OPENSSL_NO_ENGINE
++    /*
++     * Whether it's nice or not, "Inits" can be used on "Final"'d contexts so
++     * this context may already have an ENGINE! Try to avoid releasing the
++     * previous handle, re-querying for an ENGINE, and having a
++     * reinitialisation, when it may all be unnecessary.
++     */
++    if (ctx->engine && ctx->cipher
++        && (cipher == NULL || cipher->nid == ctx->cipher->nid))
++        goto skip_to_init;
++#endif
++    if (cipher) {
++        /*
++         * Ensure a context left lying around from last time is cleared (the
++         * previous check attempted to avoid this if the same ENGINE and
++         * EVP_CIPHER could be used).
++         */
++        if (ctx->cipher) {
++            unsigned long flags = ctx->flags;
++            EVP_CIPHER_CTX_reset(ctx);
++            /* Restore encrypt and flags */
++            ctx->encrypt = enc;
++            ctx->flags = flags;
++        }
++#ifndef OPENSSL_NO_ENGINE
++        if (impl) {
++            if (!ENGINE_init(impl)) {
++                EVPerr(EVP_F_EVP_CIPHERINIT_EX, EVP_R_INITIALIZATION_ERROR);
++                return 0;
++            }
++        } else
++            /* Ask if an ENGINE is reserved for this job */
++            impl = ENGINE_get_cipher_engine(cipher->nid);
++        if (impl) {
++            /* There's an ENGINE for this job ... (apparently) */
++            const EVP_CIPHER *c = ENGINE_get_cipher(impl, cipher->nid);
++            if (!c) {
++                /*
++                 * One positive side-effect of US's export control history,
++                 * is that we should at least be able to avoid using US
++                 * misspellings of "initialisation"?
++                 */
++                EVPerr(EVP_F_EVP_CIPHERINIT_EX, EVP_R_INITIALIZATION_ERROR);
++                return 0;
++            }
++            /* We'll use the ENGINE's private cipher definition */
++            cipher = c;
++            /*
++             * Store the ENGINE functional reference so we know 'cipher' came
++             * from an ENGINE and we need to release it when done.
++             */
++            ctx->engine = impl;
++        } else
++            ctx->engine = NULL;
++#endif
++
++        ctx->cipher = cipher;
++        if (ctx->cipher->ctx_size) {
++            ctx->cipher_data = OPENSSL_zalloc(ctx->cipher->ctx_size);
++            if (ctx->cipher_data == NULL) {
++                ctx->cipher = NULL;
++                EVPerr(EVP_F_EVP_CIPHERINIT_EX, ERR_R_MALLOC_FAILURE);
++                return 0;
++            }
++        } else {
++            ctx->cipher_data = NULL;
++        }
++        ctx->key_len = cipher->key_len;
++        /* Preserve wrap enable flag, zero everything else */
++        ctx->flags &= EVP_CIPHER_CTX_FLAG_WRAP_ALLOW;
++        if (ctx->cipher->flags & EVP_CIPH_CTRL_INIT) {
++            if (!EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_INIT, 0, NULL)) {
++                ctx->cipher = NULL;
++                EVPerr(EVP_F_EVP_CIPHERINIT_EX, EVP_R_INITIALIZATION_ERROR);
++                return 0;
++            }
++        }
++    } else if (!ctx->cipher) {
++        EVPerr(EVP_F_EVP_CIPHERINIT_EX, EVP_R_NO_CIPHER_SET);
++        return 0;
++    }
++#ifndef OPENSSL_NO_ENGINE
++ skip_to_init:
++#endif
++    /* we assume block size is a power of 2 in *cryptUpdate */
++    OPENSSL_assert(ctx->cipher->block_size == 1
++                   || ctx->cipher->block_size == 8
++                   || ctx->cipher->block_size == 16);
++
++    if (!(ctx->flags & EVP_CIPHER_CTX_FLAG_WRAP_ALLOW)
++        && EVP_CIPHER_CTX_mode(ctx) == EVP_CIPH_WRAP_MODE) {
++        EVPerr(EVP_F_EVP_CIPHERINIT_EX, EVP_R_WRAP_MODE_NOT_ALLOWED);
++        return 0;
++    }
++
++    if (!(EVP_CIPHER_flags(EVP_CIPHER_CTX_cipher(ctx)) & EVP_CIPH_CUSTOM_IV)) {
++        switch (EVP_CIPHER_CTX_mode(ctx)) {
++
++        case EVP_CIPH_STREAM_CIPHER:
++        case EVP_CIPH_ECB_MODE:
++            break;
++
++        case EVP_CIPH_CFB_MODE:
++        case EVP_CIPH_OFB_MODE:
++
++            ctx->num = 0;
++            /* fall-through */
++
++        case EVP_CIPH_CBC_MODE:
++
++            OPENSSL_assert(EVP_CIPHER_CTX_iv_length(ctx) <=
++                           (int)sizeof(ctx->iv));
++            if (iv)
++                memcpy(ctx->oiv, iv, EVP_CIPHER_CTX_iv_length(ctx));
++            memcpy(ctx->iv, ctx->oiv, EVP_CIPHER_CTX_iv_length(ctx));
++            break;
++
++        case EVP_CIPH_CTR_MODE:
++            ctx->num = 0;
++            /* Don't reuse IV for CTR mode */
++            if (iv)
++                memcpy(ctx->iv, iv, EVP_CIPHER_CTX_iv_length(ctx));
++            break;
++
++        default:
++            return 0;
++        }
++    }
++
++    if (key || (ctx->cipher->flags & EVP_CIPH_ALWAYS_CALL_INIT)) {
++        if (!ctx->cipher->init(ctx, key, iv, enc))
++            return 0;
++    }
++    ctx->buf_len = 0;
++    ctx->final_used = 0;
++    ctx->block_mask = ctx->cipher->block_size - 1;
++    return 1;
++}
++
++int EVP_CipherUpdate(EVP_CIPHER_CTX *ctx, unsigned char *out, int *outl,
++                     const unsigned char *in, int inl)
++{
++    if (ctx->encrypt)
++        return EVP_EncryptUpdate(ctx, out, outl, in, inl);
++    else
++        return EVP_DecryptUpdate(ctx, out, outl, in, inl);
++}
++
++int EVP_CipherFinal_ex(EVP_CIPHER_CTX *ctx, unsigned char *out, int *outl)
++{
++    if (ctx->encrypt)
++        return EVP_EncryptFinal_ex(ctx, out, outl);
++    else
++        return EVP_DecryptFinal_ex(ctx, out, outl);
++}
++
++int EVP_CipherFinal(EVP_CIPHER_CTX *ctx, unsigned char *out, int *outl)
++{
++    if (ctx->encrypt)
++        return EVP_EncryptFinal(ctx, out, outl);
++    else
++        return EVP_DecryptFinal(ctx, out, outl);
++}
++
++int EVP_EncryptInit(EVP_CIPHER_CTX *ctx, const EVP_CIPHER *cipher,
++                    const unsigned char *key, const unsigned char *iv)
++{
++    return EVP_CipherInit(ctx, cipher, key, iv, 1);
++}
++
++int EVP_EncryptInit_ex(EVP_CIPHER_CTX *ctx, const EVP_CIPHER *cipher,
++                       ENGINE *impl, const unsigned char *key,
++                       const unsigned char *iv)
++{
++    return EVP_CipherInit_ex(ctx, cipher, impl, key, iv, 1);
++}
++
++int EVP_DecryptInit(EVP_CIPHER_CTX *ctx, const EVP_CIPHER *cipher,
++                    const unsigned char *key, const unsigned char *iv)
++{
++    return EVP_CipherInit(ctx, cipher, key, iv, 0);
++}
++
++int EVP_DecryptInit_ex(EVP_CIPHER_CTX *ctx, const EVP_CIPHER *cipher,
++                       ENGINE *impl, const unsigned char *key,
++                       const unsigned char *iv)
++{
++    return EVP_CipherInit_ex(ctx, cipher, impl, key, iv, 0);
++}
++
++/*
++ * According to the letter of standard difference between pointers
++ * is specified to be valid only within same object. This makes
++ * it formally challenging to determine if input and output buffers
++ * are not partially overlapping with standard pointer arithmetic.
++ */
++#ifdef PTRDIFF_T
++# undef PTRDIFF_T
++#endif
++#if defined(OPENSSL_SYS_VMS) && __INITIAL_POINTER_SIZE==64
++/*
++ * Then we have VMS that distinguishes itself by adhering to
++ * sizeof(size_t)==4 even in 64-bit builds, which means that
++ * difference between two pointers might be truncated to 32 bits.
++ * In the context one can even wonder how comparison for
++ * equality is implemented. To be on the safe side we adhere to
++ * PTRDIFF_T even for comparison for equality.
++ */
++# define PTRDIFF_T uint64_t
++#else
++# define PTRDIFF_T size_t
++#endif
++
++int is_partially_overlapping(const void *ptr1, const void *ptr2, int len)
++{
++    PTRDIFF_T diff = (PTRDIFF_T)ptr1-(PTRDIFF_T)ptr2;
++    /*
++     * Check for partially overlapping buffers. [Binary logical
++     * operations are used instead of boolean to minimize number
++     * of conditional branches.]
++     */
++    int overlapped = (len > 0) & (diff != 0) & ((diff < (PTRDIFF_T)len) |
++                                                (diff > (0 - (PTRDIFF_T)len)));
++
++    return overlapped;
++}
++
++int EVP_EncryptUpdate(EVP_CIPHER_CTX *ctx, unsigned char *out, int *outl,
++                      const unsigned char *in, int inl)
++{
++    int i, j, bl, cmpl = inl;
++
++    if (EVP_CIPHER_CTX_test_flags(ctx, EVP_CIPH_FLAG_LENGTH_BITS))
++        cmpl = (cmpl + 7) / 8;
++
++    bl = ctx->cipher->block_size;
++
++    if (ctx->cipher->flags & EVP_CIPH_FLAG_CUSTOM_CIPHER) {
++        /* If block size > 1 then the cipher will have to do this check */
++        if (bl == 1 && is_partially_overlapping(out, in, cmpl)) {
++            EVPerr(EVP_F_EVP_ENCRYPTUPDATE, EVP_R_PARTIALLY_OVERLAPPING);
++            return 0;
++        }
++
++        i = ctx->cipher->do_cipher(ctx, out, in, inl);
++        if (i < 0)
++            return 0;
++        else
++            *outl = i;
++        return 1;
++    }
++
++    if (inl <= 0) {
++        *outl = 0;
++        return inl == 0;
++    }
++    if (is_partially_overlapping(out + ctx->buf_len, in, cmpl)) {
++        EVPerr(EVP_F_EVP_ENCRYPTUPDATE, EVP_R_PARTIALLY_OVERLAPPING);
++        return 0;
++    }
++
++    if (ctx->buf_len == 0 && (inl & (ctx->block_mask)) == 0) {
++        if (ctx->cipher->do_cipher(ctx, out, in, inl)) {
++            *outl = inl;
++            return 1;
++        } else {
++            *outl = 0;
++            return 0;
++        }
++    }
++    i = ctx->buf_len;
++    OPENSSL_assert(bl <= (int)sizeof(ctx->buf));
++    if (i != 0) {
++        if (bl - i > inl) {
++            memcpy(&(ctx->buf[i]), in, inl);
++            ctx->buf_len += inl;
++            *outl = 0;
++            return 1;
++        } else {
++            j = bl - i;
++            memcpy(&(ctx->buf[i]), in, j);
++            inl -= j;
++            in += j;
++            if (!ctx->cipher->do_cipher(ctx, out, ctx->buf, bl))
++                return 0;
++            out += bl;
++            *outl = bl;
++        }
++    } else
++        *outl = 0;
++    i = inl & (bl - 1);
++    inl -= i;
++    if (inl > 0) {
++        if (!ctx->cipher->do_cipher(ctx, out, in, inl))
++            return 0;
++        *outl += inl;
++    }
++
++    if (i != 0)
++        memcpy(ctx->buf, &(in[inl]), i);
++    ctx->buf_len = i;
++    return 1;
++}
++
++int EVP_EncryptFinal(EVP_CIPHER_CTX *ctx, unsigned char *out, int *outl)
++{
++    int ret;
++    ret = EVP_EncryptFinal_ex(ctx, out, outl);
++    return ret;
++}
++
++int EVP_EncryptFinal_ex(EVP_CIPHER_CTX *ctx, unsigned char *out, int *outl)
++{
++    int n, ret;
++    unsigned int i, b, bl;
++
++    if (ctx->cipher->flags & EVP_CIPH_FLAG_CUSTOM_CIPHER) {
++        ret = ctx->cipher->do_cipher(ctx, out, NULL, 0);
++        if (ret < 0)
++            return 0;
++        else
++            *outl = ret;
++        return 1;
++    }
++
++    b = ctx->cipher->block_size;
++    OPENSSL_assert(b <= sizeof ctx->buf);
++    if (b == 1) {
++        *outl = 0;
++        return 1;
++    }
++    bl = ctx->buf_len;
++    if (ctx->flags & EVP_CIPH_NO_PADDING) {
++        if (bl) {
++            EVPerr(EVP_F_EVP_ENCRYPTFINAL_EX,
++                   EVP_R_DATA_NOT_MULTIPLE_OF_BLOCK_LENGTH);
++            return 0;
++        }
++        *outl = 0;
++        return 1;
++    }
++
++    n = b - bl;
++    for (i = bl; i < b; i++)
++        ctx->buf[i] = n;
++    ret = ctx->cipher->do_cipher(ctx, out, ctx->buf, b);
++
++    if (ret)
++        *outl = b;
++
++    return ret;
++}
++
++int EVP_DecryptUpdate(EVP_CIPHER_CTX *ctx, unsigned char *out, int *outl,
++                      const unsigned char *in, int inl)
++{
++    int fix_len, cmpl = inl;
++    unsigned int b;
++
++    b = ctx->cipher->block_size;
++
++    if (EVP_CIPHER_CTX_test_flags(ctx, EVP_CIPH_FLAG_LENGTH_BITS))
++        cmpl = (cmpl + 7) / 8;
++
++    if (ctx->cipher->flags & EVP_CIPH_FLAG_CUSTOM_CIPHER) {
++        if (b == 1 && is_partially_overlapping(out, in, cmpl)) {
++            EVPerr(EVP_F_EVP_DECRYPTUPDATE, EVP_R_PARTIALLY_OVERLAPPING);
++            return 0;
++        }
++
++        fix_len = ctx->cipher->do_cipher(ctx, out, in, inl);
++        if (fix_len < 0) {
++            *outl = 0;
++            return 0;
++        } else
++            *outl = fix_len;
++        return 1;
++    }
++
++    if (inl <= 0) {
++        *outl = 0;
++        return inl == 0;
++    }
++
++    if (ctx->flags & EVP_CIPH_NO_PADDING)
++        return EVP_EncryptUpdate(ctx, out, outl, in, inl);
++
++    OPENSSL_assert(b <= sizeof ctx->final);
++
++    if (ctx->final_used) {
++        /* see comment about PTRDIFF_T comparison above */
++        if (((PTRDIFF_T)out == (PTRDIFF_T)in)
++            || is_partially_overlapping(out, in, b)) {
++            EVPerr(EVP_F_EVP_DECRYPTUPDATE, EVP_R_PARTIALLY_OVERLAPPING);
++            return 0;
++        }
++        memcpy(out, ctx->final, b);
++        out += b;
++        fix_len = 1;
++    } else
++        fix_len = 0;
++
++    if (!EVP_EncryptUpdate(ctx, out, outl, in, inl))
++        return 0;
++
++    /*
++     * if we have 'decrypted' a multiple of block size, make sure we have a
++     * copy of this last block
++     */
++    if (b > 1 && !ctx->buf_len) {
++        *outl -= b;
++        ctx->final_used = 1;
++        memcpy(ctx->final, &out[*outl], b);
++    } else
++        ctx->final_used = 0;
++
++    if (fix_len)
++        *outl += b;
++
++    return 1;
++}
++
++int EVP_DecryptFinal(EVP_CIPHER_CTX *ctx, unsigned char *out, int *outl)
++{
++    int ret;
++    ret = EVP_DecryptFinal_ex(ctx, out, outl);
++    return ret;
++}
++
++int EVP_DecryptFinal_ex(EVP_CIPHER_CTX *ctx, unsigned char *out, int *outl)
++{
++    int i, n;
++    unsigned int b;
++    *outl = 0;
++
++    if (ctx->cipher->flags & EVP_CIPH_FLAG_CUSTOM_CIPHER) {
++        i = ctx->cipher->do_cipher(ctx, out, NULL, 0);
++        if (i < 0)
++            return 0;
++        else
++            *outl = i;
++        return 1;
++    }
++
++    b = ctx->cipher->block_size;
++    if (ctx->flags & EVP_CIPH_NO_PADDING) {
++        if (ctx->buf_len) {
++            EVPerr(EVP_F_EVP_DECRYPTFINAL_EX,
++                   EVP_R_DATA_NOT_MULTIPLE_OF_BLOCK_LENGTH);
++            return 0;
++        }
++        *outl = 0;
++        return 1;
++    }
++    if (b > 1) {
++        if (ctx->buf_len || !ctx->final_used) {
++            EVPerr(EVP_F_EVP_DECRYPTFINAL_EX, EVP_R_WRONG_FINAL_BLOCK_LENGTH);
++            return (0);
++        }
++        OPENSSL_assert(b <= sizeof ctx->final);
++
++        /*
++         * The following assumes that the ciphertext has been authenticated.
++         * Otherwise it provides a padding oracle.
++         */
++        n = ctx->final[b - 1];
++        if (n == 0 || n > (int)b) {
++            EVPerr(EVP_F_EVP_DECRYPTFINAL_EX, EVP_R_BAD_DECRYPT);
++            return (0);
++        }
++        for (i = 0; i < n; i++) {
++            if (ctx->final[--b] != n) {
++                EVPerr(EVP_F_EVP_DECRYPTFINAL_EX, EVP_R_BAD_DECRYPT);
++                return (0);
++            }
++        }
++        n = ctx->cipher->block_size - n;
++        for (i = 0; i < n; i++)
++            out[i] = ctx->final[i];
++        *outl = n;
++    } else
++        *outl = 0;
++    return (1);
++}
++
++int EVP_CIPHER_CTX_set_key_length(EVP_CIPHER_CTX *c, int keylen)
++{
++    if (c->cipher->flags & EVP_CIPH_CUSTOM_KEY_LENGTH)
++        return EVP_CIPHER_CTX_ctrl(c, EVP_CTRL_SET_KEY_LENGTH, keylen, NULL);
++    if (c->key_len == keylen)
++        return 1;
++    if ((keylen > 0) && (c->cipher->flags & EVP_CIPH_VARIABLE_LENGTH)) {
++        c->key_len = keylen;
++        return 1;
++    }
++    EVPerr(EVP_F_EVP_CIPHER_CTX_SET_KEY_LENGTH, EVP_R_INVALID_KEY_LENGTH);
++    return 0;
++}
++
++int EVP_CIPHER_CTX_set_padding(EVP_CIPHER_CTX *ctx, int pad)
++{
++    if (pad)
++        ctx->flags &= ~EVP_CIPH_NO_PADDING;
++    else
++        ctx->flags |= EVP_CIPH_NO_PADDING;
++    return 1;
++}
++
++int EVP_CIPHER_CTX_ctrl(EVP_CIPHER_CTX *ctx, int type, int arg, void *ptr)
++{
++    int ret;
++    if (!ctx->cipher) {
++        EVPerr(EVP_F_EVP_CIPHER_CTX_CTRL, EVP_R_NO_CIPHER_SET);
++        return 0;
++    }
++
++    if (!ctx->cipher->ctrl) {
++        EVPerr(EVP_F_EVP_CIPHER_CTX_CTRL, EVP_R_CTRL_NOT_IMPLEMENTED);
++        return 0;
++    }
++
++    ret = ctx->cipher->ctrl(ctx, type, arg, ptr);
++    if (ret == -1) {
++        EVPerr(EVP_F_EVP_CIPHER_CTX_CTRL,
++               EVP_R_CTRL_OPERATION_NOT_IMPLEMENTED);
++        return 0;
++    }
++    return ret;
++}
++
++int EVP_CIPHER_CTX_rand_key(EVP_CIPHER_CTX *ctx, unsigned char *key)
++{
++    if (ctx->cipher->flags & EVP_CIPH_RAND_KEY)
++        return EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_RAND_KEY, 0, key);
++    if (RAND_bytes(key, ctx->key_len) <= 0)
++        return 0;
++    return 1;
++}
++
++int EVP_CIPHER_CTX_copy(EVP_CIPHER_CTX *out, const EVP_CIPHER_CTX *in)
++{
++    if ((in == NULL) || (in->cipher == NULL)) {
++        EVPerr(EVP_F_EVP_CIPHER_CTX_COPY, EVP_R_INPUT_NOT_INITIALIZED);
++        return 0;
++    }
++#ifndef OPENSSL_NO_ENGINE
++    /* Make sure it's safe to copy a cipher context using an ENGINE */
++    if (in->engine && !ENGINE_init(in->engine)) {
++        EVPerr(EVP_F_EVP_CIPHER_CTX_COPY, ERR_R_ENGINE_LIB);
++        return 0;
++    }
++#endif
++
++    EVP_CIPHER_CTX_reset(out);
++    memcpy(out, in, sizeof(*out));
++
++    if (in->cipher_data && in->cipher->ctx_size) {
++        out->cipher_data = OPENSSL_malloc(in->cipher->ctx_size);
++        if (out->cipher_data == NULL) {
++            out->cipher = NULL;
++            EVPerr(EVP_F_EVP_CIPHER_CTX_COPY, ERR_R_MALLOC_FAILURE);
++            return 0;
++        }
++        memcpy(out->cipher_data, in->cipher_data, in->cipher->ctx_size);
++    }
++
++    if (in->cipher->flags & EVP_CIPH_CUSTOM_COPY)
++        if (!in->cipher->ctrl((EVP_CIPHER_CTX *)in, EVP_CTRL_COPY, 0, out)) {
++            out->cipher = NULL;
++            EVPerr(EVP_F_EVP_CIPHER_CTX_COPY, EVP_R_INITIALIZATION_ERROR);
++            return 0;
++        }
++    return 1;
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/evp/evp_err.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/evp/evp_err.c
+new file mode 100644
+index 0000000..e32a1c0
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/evp/evp_err.c
+@@ -0,0 +1,180 @@
++/*
++ * Generated by util/mkerr.pl DO NOT EDIT
++ * Copyright 1995-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include 
++#include 
++
++/* BEGIN ERROR CODES */
++#ifndef OPENSSL_NO_ERR
++
++# define ERR_FUNC(func) ERR_PACK(ERR_LIB_EVP,func,0)
++# define ERR_REASON(reason) ERR_PACK(ERR_LIB_EVP,0,reason)
++
++static ERR_STRING_DATA EVP_str_functs[] = {
++    {ERR_FUNC(EVP_F_AESNI_INIT_KEY), "aesni_init_key"},
++    {ERR_FUNC(EVP_F_AES_INIT_KEY), "aes_init_key"},
++    {ERR_FUNC(EVP_F_AES_OCB_CIPHER), "aes_ocb_cipher"},
++    {ERR_FUNC(EVP_F_AES_T4_INIT_KEY), "aes_t4_init_key"},
++    {ERR_FUNC(EVP_F_AES_WRAP_CIPHER), "aes_wrap_cipher"},
++    {ERR_FUNC(EVP_F_ALG_MODULE_INIT), "alg_module_init"},
++    {ERR_FUNC(EVP_F_CAMELLIA_INIT_KEY), "camellia_init_key"},
++    {ERR_FUNC(EVP_F_CHACHA20_POLY1305_CTRL), "chacha20_poly1305_ctrl"},
++    {ERR_FUNC(EVP_F_CMLL_T4_INIT_KEY), "cmll_t4_init_key"},
++    {ERR_FUNC(EVP_F_DES_EDE3_WRAP_CIPHER), "des_ede3_wrap_cipher"},
++    {ERR_FUNC(EVP_F_DO_SIGVER_INIT), "do_sigver_init"},
++    {ERR_FUNC(EVP_F_EVP_CIPHERINIT_EX), "EVP_CipherInit_ex"},
++    {ERR_FUNC(EVP_F_EVP_CIPHER_CTX_COPY), "EVP_CIPHER_CTX_copy"},
++    {ERR_FUNC(EVP_F_EVP_CIPHER_CTX_CTRL), "EVP_CIPHER_CTX_ctrl"},
++    {ERR_FUNC(EVP_F_EVP_CIPHER_CTX_SET_KEY_LENGTH),
++     "EVP_CIPHER_CTX_set_key_length"},
++    {ERR_FUNC(EVP_F_EVP_DECRYPTFINAL_EX), "EVP_DecryptFinal_ex"},
++    {ERR_FUNC(EVP_F_EVP_DECRYPTUPDATE), "EVP_DecryptUpdate"},
++    {ERR_FUNC(EVP_F_EVP_DIGESTINIT_EX), "EVP_DigestInit_ex"},
++    {ERR_FUNC(EVP_F_EVP_ENCRYPTFINAL_EX), "EVP_EncryptFinal_ex"},
++    {ERR_FUNC(EVP_F_EVP_ENCRYPTUPDATE), "EVP_EncryptUpdate"},
++    {ERR_FUNC(EVP_F_EVP_MD_CTX_COPY_EX), "EVP_MD_CTX_copy_ex"},
++    {ERR_FUNC(EVP_F_EVP_MD_SIZE), "EVP_MD_size"},
++    {ERR_FUNC(EVP_F_EVP_OPENINIT), "EVP_OpenInit"},
++    {ERR_FUNC(EVP_F_EVP_PBE_ALG_ADD), "EVP_PBE_alg_add"},
++    {ERR_FUNC(EVP_F_EVP_PBE_ALG_ADD_TYPE), "EVP_PBE_alg_add_type"},
++    {ERR_FUNC(EVP_F_EVP_PBE_CIPHERINIT), "EVP_PBE_CipherInit"},
++    {ERR_FUNC(EVP_F_EVP_PBE_SCRYPT), "EVP_PBE_scrypt"},
++    {ERR_FUNC(EVP_F_EVP_PKCS82PKEY), "EVP_PKCS82PKEY"},
++    {ERR_FUNC(EVP_F_EVP_PKEY2PKCS8), "EVP_PKEY2PKCS8"},
++    {ERR_FUNC(EVP_F_EVP_PKEY_COPY_PARAMETERS), "EVP_PKEY_copy_parameters"},
++    {ERR_FUNC(EVP_F_EVP_PKEY_CTX_CTRL), "EVP_PKEY_CTX_ctrl"},
++    {ERR_FUNC(EVP_F_EVP_PKEY_CTX_CTRL_STR), "EVP_PKEY_CTX_ctrl_str"},
++    {ERR_FUNC(EVP_F_EVP_PKEY_CTX_DUP), "EVP_PKEY_CTX_dup"},
++    {ERR_FUNC(EVP_F_EVP_PKEY_DECRYPT), "EVP_PKEY_decrypt"},
++    {ERR_FUNC(EVP_F_EVP_PKEY_DECRYPT_INIT), "EVP_PKEY_decrypt_init"},
++    {ERR_FUNC(EVP_F_EVP_PKEY_DECRYPT_OLD), "EVP_PKEY_decrypt_old"},
++    {ERR_FUNC(EVP_F_EVP_PKEY_DERIVE), "EVP_PKEY_derive"},
++    {ERR_FUNC(EVP_F_EVP_PKEY_DERIVE_INIT), "EVP_PKEY_derive_init"},
++    {ERR_FUNC(EVP_F_EVP_PKEY_DERIVE_SET_PEER), "EVP_PKEY_derive_set_peer"},
++    {ERR_FUNC(EVP_F_EVP_PKEY_ENCRYPT), "EVP_PKEY_encrypt"},
++    {ERR_FUNC(EVP_F_EVP_PKEY_ENCRYPT_INIT), "EVP_PKEY_encrypt_init"},
++    {ERR_FUNC(EVP_F_EVP_PKEY_ENCRYPT_OLD), "EVP_PKEY_encrypt_old"},
++    {ERR_FUNC(EVP_F_EVP_PKEY_GET0_DH), "EVP_PKEY_get0_DH"},
++    {ERR_FUNC(EVP_F_EVP_PKEY_GET0_DSA), "EVP_PKEY_get0_DSA"},
++    {ERR_FUNC(EVP_F_EVP_PKEY_GET0_EC_KEY), "EVP_PKEY_get0_EC_KEY"},
++    {ERR_FUNC(EVP_F_EVP_PKEY_GET0_HMAC), "EVP_PKEY_get0_hmac"},
++    {ERR_FUNC(EVP_F_EVP_PKEY_GET0_RSA), "EVP_PKEY_get0_RSA"},
++    {ERR_FUNC(EVP_F_EVP_PKEY_KEYGEN), "EVP_PKEY_keygen"},
++    {ERR_FUNC(EVP_F_EVP_PKEY_KEYGEN_INIT), "EVP_PKEY_keygen_init"},
++    {ERR_FUNC(EVP_F_EVP_PKEY_NEW), "EVP_PKEY_new"},
++    {ERR_FUNC(EVP_F_EVP_PKEY_PARAMGEN), "EVP_PKEY_paramgen"},
++    {ERR_FUNC(EVP_F_EVP_PKEY_PARAMGEN_INIT), "EVP_PKEY_paramgen_init"},
++    {ERR_FUNC(EVP_F_EVP_PKEY_SIGN), "EVP_PKEY_sign"},
++    {ERR_FUNC(EVP_F_EVP_PKEY_SIGN_INIT), "EVP_PKEY_sign_init"},
++    {ERR_FUNC(EVP_F_EVP_PKEY_VERIFY), "EVP_PKEY_verify"},
++    {ERR_FUNC(EVP_F_EVP_PKEY_VERIFY_INIT), "EVP_PKEY_verify_init"},
++    {ERR_FUNC(EVP_F_EVP_PKEY_VERIFY_RECOVER), "EVP_PKEY_verify_recover"},
++    {ERR_FUNC(EVP_F_EVP_PKEY_VERIFY_RECOVER_INIT),
++     "EVP_PKEY_verify_recover_init"},
++    {ERR_FUNC(EVP_F_EVP_SIGNFINAL), "EVP_SignFinal"},
++    {ERR_FUNC(EVP_F_EVP_VERIFYFINAL), "EVP_VerifyFinal"},
++    {ERR_FUNC(EVP_F_INT_CTX_NEW), "int_ctx_new"},
++    {ERR_FUNC(EVP_F_PKCS5_PBE_KEYIVGEN), "PKCS5_PBE_keyivgen"},
++    {ERR_FUNC(EVP_F_PKCS5_V2_PBE_KEYIVGEN), "PKCS5_v2_PBE_keyivgen"},
++    {ERR_FUNC(EVP_F_PKCS5_V2_PBKDF2_KEYIVGEN), "PKCS5_v2_PBKDF2_keyivgen"},
++    {ERR_FUNC(EVP_F_PKCS5_V2_SCRYPT_KEYIVGEN), "PKCS5_v2_scrypt_keyivgen"},
++    {ERR_FUNC(EVP_F_PKEY_SET_TYPE), "pkey_set_type"},
++    {ERR_FUNC(EVP_F_RC2_MAGIC_TO_METH), "rc2_magic_to_meth"},
++    {ERR_FUNC(EVP_F_RC5_CTRL), "rc5_ctrl"},
++    {0, NULL}
++};
++
++static ERR_STRING_DATA EVP_str_reasons[] = {
++    {ERR_REASON(EVP_R_AES_KEY_SETUP_FAILED), "aes key setup failed"},
++    {ERR_REASON(EVP_R_BAD_DECRYPT), "bad decrypt"},
++    {ERR_REASON(EVP_R_BUFFER_TOO_SMALL), "buffer too small"},
++    {ERR_REASON(EVP_R_CAMELLIA_KEY_SETUP_FAILED),
++     "camellia key setup failed"},
++    {ERR_REASON(EVP_R_CIPHER_PARAMETER_ERROR), "cipher parameter error"},
++    {ERR_REASON(EVP_R_COMMAND_NOT_SUPPORTED), "command not supported"},
++    {ERR_REASON(EVP_R_COPY_ERROR), "copy error"},
++    {ERR_REASON(EVP_R_CTRL_NOT_IMPLEMENTED), "ctrl not implemented"},
++    {ERR_REASON(EVP_R_CTRL_OPERATION_NOT_IMPLEMENTED),
++     "ctrl operation not implemented"},
++    {ERR_REASON(EVP_R_DATA_NOT_MULTIPLE_OF_BLOCK_LENGTH),
++     "data not multiple of block length"},
++    {ERR_REASON(EVP_R_DECODE_ERROR), "decode error"},
++    {ERR_REASON(EVP_R_DIFFERENT_KEY_TYPES), "different key types"},
++    {ERR_REASON(EVP_R_DIFFERENT_PARAMETERS), "different parameters"},
++    {ERR_REASON(EVP_R_ERROR_LOADING_SECTION), "error loading section"},
++    {ERR_REASON(EVP_R_ERROR_SETTING_FIPS_MODE), "error setting fips mode"},
++    {ERR_REASON(EVP_R_EXPECTING_AN_HMAC_KEY), "expecting an hmac key"},
++    {ERR_REASON(EVP_R_EXPECTING_AN_RSA_KEY), "expecting an rsa key"},
++    {ERR_REASON(EVP_R_EXPECTING_A_DH_KEY), "expecting a dh key"},
++    {ERR_REASON(EVP_R_EXPECTING_A_DSA_KEY), "expecting a dsa key"},
++    {ERR_REASON(EVP_R_EXPECTING_A_EC_KEY), "expecting a ec key"},
++    {ERR_REASON(EVP_R_FIPS_MODE_NOT_SUPPORTED), "fips mode not supported"},
++    {ERR_REASON(EVP_R_ILLEGAL_SCRYPT_PARAMETERS),
++     "illegal scrypt parameters"},
++    {ERR_REASON(EVP_R_INITIALIZATION_ERROR), "initialization error"},
++    {ERR_REASON(EVP_R_INPUT_NOT_INITIALIZED), "input not initialized"},
++    {ERR_REASON(EVP_R_INVALID_DIGEST), "invalid digest"},
++    {ERR_REASON(EVP_R_INVALID_FIPS_MODE), "invalid fips mode"},
++    {ERR_REASON(EVP_R_INVALID_KEY), "invalid key"},
++    {ERR_REASON(EVP_R_INVALID_KEY_LENGTH), "invalid key length"},
++    {ERR_REASON(EVP_R_INVALID_OPERATION), "invalid operation"},
++    {ERR_REASON(EVP_R_KEYGEN_FAILURE), "keygen failure"},
++    {ERR_REASON(EVP_R_MEMORY_LIMIT_EXCEEDED), "memory limit exceeded"},
++    {ERR_REASON(EVP_R_MESSAGE_DIGEST_IS_NULL), "message digest is null"},
++    {ERR_REASON(EVP_R_METHOD_NOT_SUPPORTED), "method not supported"},
++    {ERR_REASON(EVP_R_MISSING_PARAMETERS), "missing parameters"},
++    {ERR_REASON(EVP_R_NO_CIPHER_SET), "no cipher set"},
++    {ERR_REASON(EVP_R_NO_DEFAULT_DIGEST), "no default digest"},
++    {ERR_REASON(EVP_R_NO_DIGEST_SET), "no digest set"},
++    {ERR_REASON(EVP_R_NO_KEY_SET), "no key set"},
++    {ERR_REASON(EVP_R_NO_OPERATION_SET), "no operation set"},
++    {ERR_REASON(EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE),
++     "operation not supported for this keytype"},
++    {ERR_REASON(EVP_R_OPERATON_NOT_INITIALIZED), "operaton not initialized"},
++    {ERR_REASON(EVP_R_PARTIALLY_OVERLAPPING),
++     "partially overlapping buffers"},
++    {ERR_REASON(EVP_R_PRIVATE_KEY_DECODE_ERROR), "private key decode error"},
++    {ERR_REASON(EVP_R_PRIVATE_KEY_ENCODE_ERROR), "private key encode error"},
++    {ERR_REASON(EVP_R_PUBLIC_KEY_NOT_RSA), "public key not rsa"},
++    {ERR_REASON(EVP_R_UNKNOWN_CIPHER), "unknown cipher"},
++    {ERR_REASON(EVP_R_UNKNOWN_DIGEST), "unknown digest"},
++    {ERR_REASON(EVP_R_UNKNOWN_OPTION), "unknown option"},
++    {ERR_REASON(EVP_R_UNKNOWN_PBE_ALGORITHM), "unknown pbe algorithm"},
++    {ERR_REASON(EVP_R_UNSUPPORTED_ALGORITHM), "unsupported algorithm"},
++    {ERR_REASON(EVP_R_UNSUPPORTED_CIPHER), "unsupported cipher"},
++    {ERR_REASON(EVP_R_UNSUPPORTED_KEYLENGTH), "unsupported keylength"},
++    {ERR_REASON(EVP_R_UNSUPPORTED_KEY_DERIVATION_FUNCTION),
++     "unsupported key derivation function"},
++    {ERR_REASON(EVP_R_UNSUPPORTED_KEY_SIZE), "unsupported key size"},
++    {ERR_REASON(EVP_R_UNSUPPORTED_NUMBER_OF_ROUNDS),
++     "unsupported number of rounds"},
++    {ERR_REASON(EVP_R_UNSUPPORTED_PRF), "unsupported prf"},
++    {ERR_REASON(EVP_R_UNSUPPORTED_PRIVATE_KEY_ALGORITHM),
++     "unsupported private key algorithm"},
++    {ERR_REASON(EVP_R_UNSUPPORTED_SALT_TYPE), "unsupported salt type"},
++    {ERR_REASON(EVP_R_WRAP_MODE_NOT_ALLOWED), "wrap mode not allowed"},
++    {ERR_REASON(EVP_R_WRONG_FINAL_BLOCK_LENGTH), "wrong final block length"},
++    {0, NULL}
++};
++
++#endif
++
++int ERR_load_EVP_strings(void)
++{
++#ifndef OPENSSL_NO_ERR
++
++    if (ERR_func_error_string(EVP_str_functs[0].error) == NULL) {
++        ERR_load_strings(0, EVP_str_functs);
++        ERR_load_strings(0, EVP_str_reasons);
++    }
++#endif
++    return 1;
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/evp/evp_key.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/evp/evp_key.c
+new file mode 100644
+index 0000000..8a4297c
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/evp/evp_key.c
+@@ -0,0 +1,150 @@
++/*
++ * Copyright 1995-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include "internal/cryptlib.h"
++#include 
++#include 
++#include 
++#include 
++
++#ifndef OPENSSL_NO_UI
++/* should be init to zeros. */
++static char prompt_string[80];
++
++void EVP_set_pw_prompt(const char *prompt)
++{
++    if (prompt == NULL)
++        prompt_string[0] = '\0';
++    else {
++        strncpy(prompt_string, prompt, 79);
++        prompt_string[79] = '\0';
++    }
++}
++
++char *EVP_get_pw_prompt(void)
++{
++    if (prompt_string[0] == '\0')
++        return (NULL);
++    else
++        return (prompt_string);
++}
++
++/*
++ * For historical reasons, the standard function for reading passwords is in
++ * the DES library -- if someone ever wants to disable DES, this function
++ * will fail
++ */
++int EVP_read_pw_string(char *buf, int len, const char *prompt, int verify)
++{
++    return EVP_read_pw_string_min(buf, 0, len, prompt, verify);
++}
++
++int EVP_read_pw_string_min(char *buf, int min, int len, const char *prompt,
++                           int verify)
++{
++    int ret;
++    char buff[BUFSIZ];
++    UI *ui;
++
++    if ((prompt == NULL) && (prompt_string[0] != '\0'))
++        prompt = prompt_string;
++    ui = UI_new();
++    if (ui == NULL)
++        return -1;
++    UI_add_input_string(ui, prompt, 0, buf, min,
++                        (len >= BUFSIZ) ? BUFSIZ - 1 : len);
++    if (verify)
++        UI_add_verify_string(ui, prompt, 0,
++                             buff, min, (len >= BUFSIZ) ? BUFSIZ - 1 : len,
++                             buf);
++    ret = UI_process(ui);
++    UI_free(ui);
++    OPENSSL_cleanse(buff, BUFSIZ);
++    return ret;
++}
++#endif /* OPENSSL_NO_UI */
++
++int EVP_BytesToKey(const EVP_CIPHER *type, const EVP_MD *md,
++                   const unsigned char *salt, const unsigned char *data,
++                   int datal, int count, unsigned char *key,
++                   unsigned char *iv)
++{
++    EVP_MD_CTX *c;
++    unsigned char md_buf[EVP_MAX_MD_SIZE];
++    int niv, nkey, addmd = 0;
++    unsigned int mds = 0, i;
++    int rv = 0;
++    nkey = EVP_CIPHER_key_length(type);
++    niv = EVP_CIPHER_iv_length(type);
++    OPENSSL_assert(nkey <= EVP_MAX_KEY_LENGTH);
++    OPENSSL_assert(niv <= EVP_MAX_IV_LENGTH);
++
++    if (data == NULL)
++        return (nkey);
++
++    c = EVP_MD_CTX_new();
++    if (c == NULL)
++        goto err;
++    for (;;) {
++        if (!EVP_DigestInit_ex(c, md, NULL))
++            goto err;
++        if (addmd++)
++            if (!EVP_DigestUpdate(c, &(md_buf[0]), mds))
++                goto err;
++        if (!EVP_DigestUpdate(c, data, datal))
++            goto err;
++        if (salt != NULL)
++            if (!EVP_DigestUpdate(c, salt, PKCS5_SALT_LEN))
++                goto err;
++        if (!EVP_DigestFinal_ex(c, &(md_buf[0]), &mds))
++            goto err;
++
++        for (i = 1; i < (unsigned int)count; i++) {
++            if (!EVP_DigestInit_ex(c, md, NULL))
++                goto err;
++            if (!EVP_DigestUpdate(c, &(md_buf[0]), mds))
++                goto err;
++            if (!EVP_DigestFinal_ex(c, &(md_buf[0]), &mds))
++                goto err;
++        }
++        i = 0;
++        if (nkey) {
++            for (;;) {
++                if (nkey == 0)
++                    break;
++                if (i == mds)
++                    break;
++                if (key != NULL)
++                    *(key++) = md_buf[i];
++                nkey--;
++                i++;
++            }
++        }
++        if (niv && (i != mds)) {
++            for (;;) {
++                if (niv == 0)
++                    break;
++                if (i == mds)
++                    break;
++                if (iv != NULL)
++                    *(iv++) = md_buf[i];
++                niv--;
++                i++;
++            }
++        }
++        if ((nkey == 0) && (niv == 0))
++            break;
++    }
++    rv = EVP_CIPHER_key_length(type);
++ err:
++    EVP_MD_CTX_free(c);
++    OPENSSL_cleanse(md_buf, sizeof(md_buf));
++    return rv;
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/evp/evp_lib.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/evp/evp_lib.c
+new file mode 100644
+index 0000000..0c76db5
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/evp/evp_lib.c
+@@ -0,0 +1,497 @@
++/*
++ * Copyright 1995-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include "internal/cryptlib.h"
++#include 
++#include 
++#include "internal/evp_int.h"
++#include "evp_locl.h"
++
++int EVP_CIPHER_param_to_asn1(EVP_CIPHER_CTX *c, ASN1_TYPE *type)
++{
++    int ret;
++
++    if (c->cipher->set_asn1_parameters != NULL)
++        ret = c->cipher->set_asn1_parameters(c, type);
++    else if (c->cipher->flags & EVP_CIPH_FLAG_DEFAULT_ASN1) {
++        switch (EVP_CIPHER_CTX_mode(c)) {
++        case EVP_CIPH_WRAP_MODE:
++            if (EVP_CIPHER_CTX_nid(c) == NID_id_smime_alg_CMS3DESwrap)
++                ASN1_TYPE_set(type, V_ASN1_NULL, NULL);
++            ret = 1;
++            break;
++
++        case EVP_CIPH_GCM_MODE:
++        case EVP_CIPH_CCM_MODE:
++        case EVP_CIPH_XTS_MODE:
++        case EVP_CIPH_OCB_MODE:
++            ret = -1;
++            break;
++
++        default:
++            ret = EVP_CIPHER_set_asn1_iv(c, type);
++        }
++    } else
++        ret = -1;
++    return (ret);
++}
++
++int EVP_CIPHER_asn1_to_param(EVP_CIPHER_CTX *c, ASN1_TYPE *type)
++{
++    int ret;
++
++    if (c->cipher->get_asn1_parameters != NULL)
++        ret = c->cipher->get_asn1_parameters(c, type);
++    else if (c->cipher->flags & EVP_CIPH_FLAG_DEFAULT_ASN1) {
++        switch (EVP_CIPHER_CTX_mode(c)) {
++
++        case EVP_CIPH_WRAP_MODE:
++            ret = 1;
++            break;
++
++        case EVP_CIPH_GCM_MODE:
++        case EVP_CIPH_CCM_MODE:
++        case EVP_CIPH_XTS_MODE:
++        case EVP_CIPH_OCB_MODE:
++            ret = -1;
++            break;
++
++        default:
++            ret = EVP_CIPHER_get_asn1_iv(c, type);
++            break;
++        }
++    } else
++        ret = -1;
++    return (ret);
++}
++
++int EVP_CIPHER_get_asn1_iv(EVP_CIPHER_CTX *c, ASN1_TYPE *type)
++{
++    int i = 0;
++    unsigned int l;
++
++    if (type != NULL) {
++        l = EVP_CIPHER_CTX_iv_length(c);
++        OPENSSL_assert(l <= sizeof(c->iv));
++        i = ASN1_TYPE_get_octetstring(type, c->oiv, l);
++        if (i != (int)l)
++            return (-1);
++        else if (i > 0)
++            memcpy(c->iv, c->oiv, l);
++    }
++    return (i);
++}
++
++int EVP_CIPHER_set_asn1_iv(EVP_CIPHER_CTX *c, ASN1_TYPE *type)
++{
++    int i = 0;
++    unsigned int j;
++
++    if (type != NULL) {
++        j = EVP_CIPHER_CTX_iv_length(c);
++        OPENSSL_assert(j <= sizeof(c->iv));
++        i = ASN1_TYPE_set_octetstring(type, c->oiv, j);
++    }
++    return (i);
++}
++
++/* Convert the various cipher NIDs and dummies to a proper OID NID */
++int EVP_CIPHER_type(const EVP_CIPHER *ctx)
++{
++    int nid;
++    ASN1_OBJECT *otmp;
++    nid = EVP_CIPHER_nid(ctx);
++
++    switch (nid) {
++
++    case NID_rc2_cbc:
++    case NID_rc2_64_cbc:
++    case NID_rc2_40_cbc:
++
++        return NID_rc2_cbc;
++
++    case NID_rc4:
++    case NID_rc4_40:
++
++        return NID_rc4;
++
++    case NID_aes_128_cfb128:
++    case NID_aes_128_cfb8:
++    case NID_aes_128_cfb1:
++
++        return NID_aes_128_cfb128;
++
++    case NID_aes_192_cfb128:
++    case NID_aes_192_cfb8:
++    case NID_aes_192_cfb1:
++
++        return NID_aes_192_cfb128;
++
++    case NID_aes_256_cfb128:
++    case NID_aes_256_cfb8:
++    case NID_aes_256_cfb1:
++
++        return NID_aes_256_cfb128;
++
++    case NID_des_cfb64:
++    case NID_des_cfb8:
++    case NID_des_cfb1:
++
++        return NID_des_cfb64;
++
++    case NID_des_ede3_cfb64:
++    case NID_des_ede3_cfb8:
++    case NID_des_ede3_cfb1:
++
++        return NID_des_cfb64;
++
++    default:
++        /* Check it has an OID and it is valid */
++        otmp = OBJ_nid2obj(nid);
++        if (OBJ_get0_data(otmp) == NULL)
++            nid = NID_undef;
++        ASN1_OBJECT_free(otmp);
++        return nid;
++    }
++}
++
++int EVP_CIPHER_block_size(const EVP_CIPHER *e)
++{
++    return e->block_size;
++}
++
++int EVP_CIPHER_CTX_block_size(const EVP_CIPHER_CTX *ctx)
++{
++    return ctx->cipher->block_size;
++}
++
++int EVP_CIPHER_impl_ctx_size(const EVP_CIPHER *e)
++{
++    return e->ctx_size;
++}
++
++int EVP_Cipher(EVP_CIPHER_CTX *ctx, unsigned char *out,
++               const unsigned char *in, unsigned int inl)
++{
++    return ctx->cipher->do_cipher(ctx, out, in, inl);
++}
++
++const EVP_CIPHER *EVP_CIPHER_CTX_cipher(const EVP_CIPHER_CTX *ctx)
++{
++    return ctx->cipher;
++}
++
++int EVP_CIPHER_CTX_encrypting(const EVP_CIPHER_CTX *ctx)
++{
++    return ctx->encrypt;
++}
++
++unsigned long EVP_CIPHER_flags(const EVP_CIPHER *cipher)
++{
++    return cipher->flags;
++}
++
++void *EVP_CIPHER_CTX_get_app_data(const EVP_CIPHER_CTX *ctx)
++{
++    return ctx->app_data;
++}
++
++void EVP_CIPHER_CTX_set_app_data(EVP_CIPHER_CTX *ctx, void *data)
++{
++    ctx->app_data = data;
++}
++
++void *EVP_CIPHER_CTX_get_cipher_data(const EVP_CIPHER_CTX *ctx)
++{
++    return ctx->cipher_data;
++}
++
++void *EVP_CIPHER_CTX_set_cipher_data(EVP_CIPHER_CTX *ctx, void *cipher_data)
++{
++    void *old_cipher_data;
++
++    old_cipher_data = ctx->cipher_data;
++    ctx->cipher_data = cipher_data;
++
++    return old_cipher_data;
++}
++
++int EVP_CIPHER_iv_length(const EVP_CIPHER *cipher)
++{
++    return cipher->iv_len;
++}
++
++int EVP_CIPHER_CTX_iv_length(const EVP_CIPHER_CTX *ctx)
++{
++    return ctx->cipher->iv_len;
++}
++
++const unsigned char *EVP_CIPHER_CTX_original_iv(const EVP_CIPHER_CTX *ctx)
++{
++    return ctx->oiv;
++}
++
++const unsigned char *EVP_CIPHER_CTX_iv(const EVP_CIPHER_CTX *ctx)
++{
++    return ctx->iv;
++}
++
++unsigned char *EVP_CIPHER_CTX_iv_noconst(EVP_CIPHER_CTX *ctx)
++{
++    return ctx->iv;
++}
++
++unsigned char *EVP_CIPHER_CTX_buf_noconst(EVP_CIPHER_CTX *ctx)
++{
++    return ctx->buf;
++}
++
++int EVP_CIPHER_CTX_num(const EVP_CIPHER_CTX *ctx)
++{
++    return ctx->num;
++}
++
++void EVP_CIPHER_CTX_set_num(EVP_CIPHER_CTX *ctx, int num)
++{
++    ctx->num = num;
++}
++
++int EVP_CIPHER_key_length(const EVP_CIPHER *cipher)
++{
++    return cipher->key_len;
++}
++
++int EVP_CIPHER_CTX_key_length(const EVP_CIPHER_CTX *ctx)
++{
++    return ctx->key_len;
++}
++
++int EVP_CIPHER_nid(const EVP_CIPHER *cipher)
++{
++    return cipher->nid;
++}
++
++int EVP_CIPHER_CTX_nid(const EVP_CIPHER_CTX *ctx)
++{
++    return ctx->cipher->nid;
++}
++
++int EVP_MD_block_size(const EVP_MD *md)
++{
++    return md->block_size;
++}
++
++int EVP_MD_type(const EVP_MD *md)
++{
++    return md->type;
++}
++
++int EVP_MD_pkey_type(const EVP_MD *md)
++{
++    return md->pkey_type;
++}
++
++int EVP_MD_size(const EVP_MD *md)
++{
++    if (!md) {
++        EVPerr(EVP_F_EVP_MD_SIZE, EVP_R_MESSAGE_DIGEST_IS_NULL);
++        return -1;
++    }
++    return md->md_size;
++}
++
++unsigned long EVP_MD_flags(const EVP_MD *md)
++{
++    return md->flags;
++}
++
++EVP_MD *EVP_MD_meth_new(int md_type, int pkey_type)
++{
++    EVP_MD *md = OPENSSL_zalloc(sizeof(*md));
++
++    if (md != NULL) {
++        md->type = md_type;
++        md->pkey_type = pkey_type;
++    }
++    return md;
++}
++EVP_MD *EVP_MD_meth_dup(const EVP_MD *md)
++{
++    EVP_MD *to = EVP_MD_meth_new(md->type, md->pkey_type);
++
++    if (to != NULL)
++        memcpy(to, md, sizeof(*to));
++    return to;
++}
++void EVP_MD_meth_free(EVP_MD *md)
++{
++    OPENSSL_free(md);
++}
++int EVP_MD_meth_set_input_blocksize(EVP_MD *md, int blocksize)
++{
++    md->block_size = blocksize;
++    return 1;
++}
++int EVP_MD_meth_set_result_size(EVP_MD *md, int resultsize)
++{
++    md->md_size = resultsize;
++    return 1;
++}
++int EVP_MD_meth_set_app_datasize(EVP_MD *md, int datasize)
++{
++    md->ctx_size = datasize;
++    return 1;
++}
++int EVP_MD_meth_set_flags(EVP_MD *md, unsigned long flags)
++{
++    md->flags = flags;
++    return 1;
++}
++int EVP_MD_meth_set_init(EVP_MD *md, int (*init)(EVP_MD_CTX *ctx))
++{
++    md->init = init;
++    return 1;
++}
++int EVP_MD_meth_set_update(EVP_MD *md, int (*update)(EVP_MD_CTX *ctx,
++                                                     const void *data,
++                                                     size_t count))
++{
++    md->update = update;
++    return 1;
++}
++int EVP_MD_meth_set_final(EVP_MD *md, int (*final)(EVP_MD_CTX *ctx,
++                                                   unsigned char *md))
++{
++    md->final = final;
++    return 1;
++}
++int EVP_MD_meth_set_copy(EVP_MD *md, int (*copy)(EVP_MD_CTX *to,
++                                                 const EVP_MD_CTX *from))
++{
++    md->copy = copy;
++    return 1;
++}
++int EVP_MD_meth_set_cleanup(EVP_MD *md, int (*cleanup)(EVP_MD_CTX *ctx))
++{
++    md->cleanup = cleanup;
++    return 1;
++}
++int EVP_MD_meth_set_ctrl(EVP_MD *md, int (*ctrl)(EVP_MD_CTX *ctx, int cmd,
++                                                 int p1, void *p2))
++{
++    md->md_ctrl = ctrl;
++    return 1;
++}
++
++int EVP_MD_meth_get_input_blocksize(const EVP_MD *md)
++{
++    return md->block_size;
++}
++int EVP_MD_meth_get_result_size(const EVP_MD *md)
++{
++    return md->md_size;
++}
++int EVP_MD_meth_get_app_datasize(const EVP_MD *md)
++{
++    return md->ctx_size;
++}
++unsigned long EVP_MD_meth_get_flags(const EVP_MD *md)
++{
++    return md->flags;
++}
++int (*EVP_MD_meth_get_init(const EVP_MD *md))(EVP_MD_CTX *ctx)
++{
++    return md->init;
++}
++int (*EVP_MD_meth_get_update(const EVP_MD *md))(EVP_MD_CTX *ctx,
++                                                const void *data,
++                                                size_t count)
++{
++    return md->update;
++}
++int (*EVP_MD_meth_get_final(const EVP_MD *md))(EVP_MD_CTX *ctx,
++                                               unsigned char *md)
++{
++    return md->final;
++}
++int (*EVP_MD_meth_get_copy(const EVP_MD *md))(EVP_MD_CTX *to,
++                                              const EVP_MD_CTX *from)
++{
++    return md->copy;
++}
++int (*EVP_MD_meth_get_cleanup(const EVP_MD *md))(EVP_MD_CTX *ctx)
++{
++    return md->cleanup;
++}
++int (*EVP_MD_meth_get_ctrl(const EVP_MD *md))(EVP_MD_CTX *ctx, int cmd,
++                                              int p1, void *p2)
++{
++    return md->md_ctrl;
++}
++
++const EVP_MD *EVP_MD_CTX_md(const EVP_MD_CTX *ctx)
++{
++    if (!ctx)
++        return NULL;
++    return ctx->digest;
++}
++
++EVP_PKEY_CTX *EVP_MD_CTX_pkey_ctx(const EVP_MD_CTX *ctx)
++{
++    return ctx->pctx;
++}
++
++void *EVP_MD_CTX_md_data(const EVP_MD_CTX *ctx)
++{
++    return ctx->md_data;
++}
++
++int (*EVP_MD_CTX_update_fn(EVP_MD_CTX *ctx))(EVP_MD_CTX *ctx,
++                                             const void *data, size_t count)
++{
++    return ctx->update;
++}
++
++void EVP_MD_CTX_set_update_fn(EVP_MD_CTX *ctx,
++                              int (*update) (EVP_MD_CTX *ctx,
++                                             const void *data, size_t count))
++{
++    ctx->update = update;
++}
++
++void EVP_MD_CTX_set_flags(EVP_MD_CTX *ctx, int flags)
++{
++    ctx->flags |= flags;
++}
++
++void EVP_MD_CTX_clear_flags(EVP_MD_CTX *ctx, int flags)
++{
++    ctx->flags &= ~flags;
++}
++
++int EVP_MD_CTX_test_flags(const EVP_MD_CTX *ctx, int flags)
++{
++    return (ctx->flags & flags);
++}
++
++void EVP_CIPHER_CTX_set_flags(EVP_CIPHER_CTX *ctx, int flags)
++{
++    ctx->flags |= flags;
++}
++
++void EVP_CIPHER_CTX_clear_flags(EVP_CIPHER_CTX *ctx, int flags)
++{
++    ctx->flags &= ~flags;
++}
++
++int EVP_CIPHER_CTX_test_flags(const EVP_CIPHER_CTX *ctx, int flags)
++{
++    return (ctx->flags & flags);
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/evp/evp_locl.h b/CryptoPkg/Library/OpensslLib/openssl/crypto/evp/evp_locl.h
+new file mode 100644
+index 0000000..209577b
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/evp/evp_locl.h
+@@ -0,0 +1,68 @@
++/*
++ * Copyright 2000-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++/* EVP_MD_CTX related stuff */
++
++struct evp_md_ctx_st {
++    const EVP_MD *digest;
++    ENGINE *engine;             /* functional reference if 'digest' is
++                                 * ENGINE-provided */
++    unsigned long flags;
++    void *md_data;
++    /* Public key context for sign/verify */
++    EVP_PKEY_CTX *pctx;
++    /* Update function: usually copied from EVP_MD */
++    int (*update) (EVP_MD_CTX *ctx, const void *data, size_t count);
++} /* EVP_MD_CTX */ ;
++
++struct evp_cipher_ctx_st {
++    const EVP_CIPHER *cipher;
++    ENGINE *engine;             /* functional reference if 'cipher' is
++                                 * ENGINE-provided */
++    int encrypt;                /* encrypt or decrypt */
++    int buf_len;                /* number we have left */
++    unsigned char oiv[EVP_MAX_IV_LENGTH]; /* original iv */
++    unsigned char iv[EVP_MAX_IV_LENGTH]; /* working iv */
++    unsigned char buf[EVP_MAX_BLOCK_LENGTH]; /* saved partial block */
++    int num;                    /* used by cfb/ofb/ctr mode */
++    /* FIXME: Should this even exist? It appears unused */
++    void *app_data;             /* application stuff */
++    int key_len;                /* May change for variable length cipher */
++    unsigned long flags;        /* Various flags */
++    void *cipher_data;          /* per EVP data */
++    int final_used;
++    int block_mask;
++    unsigned char final[EVP_MAX_BLOCK_LENGTH]; /* possible final block */
++} /* EVP_CIPHER_CTX */ ;
++
++int PKCS5_v2_PBKDF2_keyivgen(EVP_CIPHER_CTX *ctx, const char *pass,
++                             int passlen, ASN1_TYPE *param,
++                             const EVP_CIPHER *c, const EVP_MD *md,
++                             int en_de);
++
++struct evp_Encode_Ctx_st {
++    /* number saved in a partial encode/decode */
++    int num;
++    /*
++     * The length is either the output line length (in input bytes) or the
++     * shortest input line length that is ok.  Once decoding begins, the
++     * length is adjusted up each time a longer line is decoded
++     */
++    int length;
++    /* data to encode */
++    unsigned char enc_data[80];
++    /* number read on current line */
++    int line_num;
++    int expect_nl;
++};
++
++typedef struct evp_pbe_st EVP_PBE_CTL;
++DEFINE_STACK_OF(EVP_PBE_CTL)
++
++int is_partially_overlapping(const void *ptr1, const void *ptr2, int len);
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/evp/evp_pbe.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/evp/evp_pbe.c
+new file mode 100644
+index 0000000..ce7aa2c
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/evp/evp_pbe.c
+@@ -0,0 +1,259 @@
++/*
++ * Copyright 1999-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include "internal/cryptlib.h"
++#include 
++#include 
++#include 
++#include "evp_locl.h"
++
++/* Password based encryption (PBE) functions */
++
++/* Setup a cipher context from a PBE algorithm */
++
++struct evp_pbe_st {
++    int pbe_type;
++    int pbe_nid;
++    int cipher_nid;
++    int md_nid;
++    EVP_PBE_KEYGEN *keygen;
++};
++
++static STACK_OF(EVP_PBE_CTL) *pbe_algs;
++
++static const EVP_PBE_CTL builtin_pbe[] = {
++    {EVP_PBE_TYPE_OUTER, NID_pbeWithMD2AndDES_CBC,
++     NID_des_cbc, NID_md2, PKCS5_PBE_keyivgen},
++    {EVP_PBE_TYPE_OUTER, NID_pbeWithMD5AndDES_CBC,
++     NID_des_cbc, NID_md5, PKCS5_PBE_keyivgen},
++    {EVP_PBE_TYPE_OUTER, NID_pbeWithSHA1AndRC2_CBC,
++     NID_rc2_64_cbc, NID_sha1, PKCS5_PBE_keyivgen},
++
++    {EVP_PBE_TYPE_OUTER, NID_id_pbkdf2, -1, -1, PKCS5_v2_PBKDF2_keyivgen},
++
++    {EVP_PBE_TYPE_OUTER, NID_pbe_WithSHA1And128BitRC4,
++     NID_rc4, NID_sha1, PKCS12_PBE_keyivgen},
++    {EVP_PBE_TYPE_OUTER, NID_pbe_WithSHA1And40BitRC4,
++     NID_rc4_40, NID_sha1, PKCS12_PBE_keyivgen},
++    {EVP_PBE_TYPE_OUTER, NID_pbe_WithSHA1And3_Key_TripleDES_CBC,
++     NID_des_ede3_cbc, NID_sha1, PKCS12_PBE_keyivgen},
++    {EVP_PBE_TYPE_OUTER, NID_pbe_WithSHA1And2_Key_TripleDES_CBC,
++     NID_des_ede_cbc, NID_sha1, PKCS12_PBE_keyivgen},
++    {EVP_PBE_TYPE_OUTER, NID_pbe_WithSHA1And128BitRC2_CBC,
++     NID_rc2_cbc, NID_sha1, PKCS12_PBE_keyivgen},
++    {EVP_PBE_TYPE_OUTER, NID_pbe_WithSHA1And40BitRC2_CBC,
++     NID_rc2_40_cbc, NID_sha1, PKCS12_PBE_keyivgen},
++
++    {EVP_PBE_TYPE_OUTER, NID_pbes2, -1, -1, PKCS5_v2_PBE_keyivgen},
++
++    {EVP_PBE_TYPE_OUTER, NID_pbeWithMD2AndRC2_CBC,
++     NID_rc2_64_cbc, NID_md2, PKCS5_PBE_keyivgen},
++    {EVP_PBE_TYPE_OUTER, NID_pbeWithMD5AndRC2_CBC,
++     NID_rc2_64_cbc, NID_md5, PKCS5_PBE_keyivgen},
++    {EVP_PBE_TYPE_OUTER, NID_pbeWithSHA1AndDES_CBC,
++     NID_des_cbc, NID_sha1, PKCS5_PBE_keyivgen},
++
++    {EVP_PBE_TYPE_PRF, NID_hmacWithSHA1, -1, NID_sha1, 0},
++    {EVP_PBE_TYPE_PRF, NID_hmacWithMD5, -1, NID_md5, 0},
++    {EVP_PBE_TYPE_PRF, NID_hmacWithSHA224, -1, NID_sha224, 0},
++    {EVP_PBE_TYPE_PRF, NID_hmacWithSHA256, -1, NID_sha256, 0},
++    {EVP_PBE_TYPE_PRF, NID_hmacWithSHA384, -1, NID_sha384, 0},
++    {EVP_PBE_TYPE_PRF, NID_hmacWithSHA512, -1, NID_sha512, 0},
++    {EVP_PBE_TYPE_PRF, NID_id_HMACGostR3411_94, -1, NID_id_GostR3411_94, 0},
++    {EVP_PBE_TYPE_PRF, NID_id_tc26_hmac_gost_3411_2012_256, -1,
++     NID_id_GostR3411_2012_256, 0},
++    {EVP_PBE_TYPE_PRF, NID_id_tc26_hmac_gost_3411_2012_512, -1,
++     NID_id_GostR3411_2012_512, 0},
++    {EVP_PBE_TYPE_KDF, NID_id_pbkdf2, -1, -1, PKCS5_v2_PBKDF2_keyivgen},
++#ifndef OPENSSL_NO_SCRYPT
++    {EVP_PBE_TYPE_KDF, NID_id_scrypt, -1, -1, PKCS5_v2_scrypt_keyivgen}
++#endif
++};
++
++int EVP_PBE_CipherInit(ASN1_OBJECT *pbe_obj, const char *pass, int passlen,
++                       ASN1_TYPE *param, EVP_CIPHER_CTX *ctx, int en_de)
++{
++    const EVP_CIPHER *cipher;
++    const EVP_MD *md;
++    int cipher_nid, md_nid;
++    EVP_PBE_KEYGEN *keygen;
++
++    if (!EVP_PBE_find(EVP_PBE_TYPE_OUTER, OBJ_obj2nid(pbe_obj),
++                      &cipher_nid, &md_nid, &keygen)) {
++        char obj_tmp[80];
++        EVPerr(EVP_F_EVP_PBE_CIPHERINIT, EVP_R_UNKNOWN_PBE_ALGORITHM);
++        if (!pbe_obj)
++            OPENSSL_strlcpy(obj_tmp, "NULL", sizeof obj_tmp);
++        else
++            i2t_ASN1_OBJECT(obj_tmp, sizeof obj_tmp, pbe_obj);
++        ERR_add_error_data(2, "TYPE=", obj_tmp);
++        return 0;
++    }
++
++    if (!pass)
++        passlen = 0;
++    else if (passlen == -1)
++        passlen = strlen(pass);
++
++    if (cipher_nid == -1)
++        cipher = NULL;
++    else {
++        cipher = EVP_get_cipherbynid(cipher_nid);
++        if (!cipher) {
++            EVPerr(EVP_F_EVP_PBE_CIPHERINIT, EVP_R_UNKNOWN_CIPHER);
++            return 0;
++        }
++    }
++
++    if (md_nid == -1)
++        md = NULL;
++    else {
++        md = EVP_get_digestbynid(md_nid);
++        if (!md) {
++            EVPerr(EVP_F_EVP_PBE_CIPHERINIT, EVP_R_UNKNOWN_DIGEST);
++            return 0;
++        }
++    }
++
++    if (!keygen(ctx, pass, passlen, param, cipher, md, en_de)) {
++        EVPerr(EVP_F_EVP_PBE_CIPHERINIT, EVP_R_KEYGEN_FAILURE);
++        return 0;
++    }
++    return 1;
++}
++
++DECLARE_OBJ_BSEARCH_CMP_FN(EVP_PBE_CTL, EVP_PBE_CTL, pbe2);
++
++static int pbe2_cmp(const EVP_PBE_CTL *pbe1, const EVP_PBE_CTL *pbe2)
++{
++    int ret = pbe1->pbe_type - pbe2->pbe_type;
++    if (ret)
++        return ret;
++    else
++        return pbe1->pbe_nid - pbe2->pbe_nid;
++}
++
++IMPLEMENT_OBJ_BSEARCH_CMP_FN(EVP_PBE_CTL, EVP_PBE_CTL, pbe2);
++
++static int pbe_cmp(const EVP_PBE_CTL *const *a, const EVP_PBE_CTL *const *b)
++{
++    int ret = (*a)->pbe_type - (*b)->pbe_type;
++    if (ret)
++        return ret;
++    else
++        return (*a)->pbe_nid - (*b)->pbe_nid;
++}
++
++/* Add a PBE algorithm */
++
++int EVP_PBE_alg_add_type(int pbe_type, int pbe_nid, int cipher_nid,
++                         int md_nid, EVP_PBE_KEYGEN *keygen)
++{
++    EVP_PBE_CTL *pbe_tmp;
++
++    if (pbe_algs == NULL) {
++        pbe_algs = sk_EVP_PBE_CTL_new(pbe_cmp);
++        if (pbe_algs == NULL)
++            goto err;
++    }
++
++    if ((pbe_tmp = OPENSSL_malloc(sizeof(*pbe_tmp))) == NULL)
++        goto err;
++
++    pbe_tmp->pbe_type = pbe_type;
++    pbe_tmp->pbe_nid = pbe_nid;
++    pbe_tmp->cipher_nid = cipher_nid;
++    pbe_tmp->md_nid = md_nid;
++    pbe_tmp->keygen = keygen;
++
++    if (!sk_EVP_PBE_CTL_push(pbe_algs, pbe_tmp)) {
++        OPENSSL_free(pbe_tmp);
++        goto err;
++    }
++    return 1;
++
++ err:
++    EVPerr(EVP_F_EVP_PBE_ALG_ADD_TYPE, ERR_R_MALLOC_FAILURE);
++    return 0;
++}
++
++int EVP_PBE_alg_add(int nid, const EVP_CIPHER *cipher, const EVP_MD *md,
++                    EVP_PBE_KEYGEN *keygen)
++{
++    int cipher_nid, md_nid;
++
++    if (cipher)
++        cipher_nid = EVP_CIPHER_nid(cipher);
++    else
++        cipher_nid = -1;
++    if (md)
++        md_nid = EVP_MD_type(md);
++    else
++        md_nid = -1;
++
++    return EVP_PBE_alg_add_type(EVP_PBE_TYPE_OUTER, nid,
++                                cipher_nid, md_nid, keygen);
++}
++
++int EVP_PBE_find(int type, int pbe_nid,
++                 int *pcnid, int *pmnid, EVP_PBE_KEYGEN **pkeygen)
++{
++    EVP_PBE_CTL *pbetmp = NULL, pbelu;
++    int i;
++    if (pbe_nid == NID_undef)
++        return 0;
++
++    pbelu.pbe_type = type;
++    pbelu.pbe_nid = pbe_nid;
++
++    if (pbe_algs) {
++        i = sk_EVP_PBE_CTL_find(pbe_algs, &pbelu);
++        if (i != -1)
++            pbetmp = sk_EVP_PBE_CTL_value(pbe_algs, i);
++    }
++    if (pbetmp == NULL) {
++        pbetmp = OBJ_bsearch_pbe2(&pbelu, builtin_pbe, OSSL_NELEM(builtin_pbe));
++    }
++    if (pbetmp == NULL)
++        return 0;
++    if (pcnid)
++        *pcnid = pbetmp->cipher_nid;
++    if (pmnid)
++        *pmnid = pbetmp->md_nid;
++    if (pkeygen)
++        *pkeygen = pbetmp->keygen;
++    return 1;
++}
++
++static void free_evp_pbe_ctl(EVP_PBE_CTL *pbe)
++{
++    OPENSSL_free(pbe);
++}
++
++void EVP_PBE_cleanup(void)
++{
++    sk_EVP_PBE_CTL_pop_free(pbe_algs, free_evp_pbe_ctl);
++    pbe_algs = NULL;
++}
++
++int EVP_PBE_get(int *ptype, int *ppbe_nid, size_t num)
++{
++    const EVP_PBE_CTL *tpbe;
++
++    if (num >= OSSL_NELEM(builtin_pbe))
++        return 0;
++
++    tpbe = builtin_pbe + num;
++    if (ptype)
++        *ptype = tpbe->pbe_type;
++    if (ppbe_nid)
++        *ppbe_nid = tpbe->pbe_nid;
++    return 1;
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/evp/evp_pkey.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/evp/evp_pkey.c
+new file mode 100644
+index 0000000..81bffa6
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/evp/evp_pkey.c
+@@ -0,0 +1,150 @@
++/*
++ * Copyright 1999-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include 
++#include "internal/cryptlib.h"
++#include 
++#include 
++#include "internal/asn1_int.h"
++#include "internal/evp_int.h"
++#include "internal/x509_int.h"
++
++/* Extract a private key from a PKCS8 structure */
++
++EVP_PKEY *EVP_PKCS82PKEY(const PKCS8_PRIV_KEY_INFO *p8)
++{
++    EVP_PKEY *pkey = NULL;
++    const ASN1_OBJECT *algoid;
++    char obj_tmp[80];
++
++    if (!PKCS8_pkey_get0(&algoid, NULL, NULL, NULL, p8))
++        return NULL;
++
++    if ((pkey = EVP_PKEY_new()) == NULL) {
++        EVPerr(EVP_F_EVP_PKCS82PKEY, ERR_R_MALLOC_FAILURE);
++        return NULL;
++    }
++
++    if (!EVP_PKEY_set_type(pkey, OBJ_obj2nid(algoid))) {
++        EVPerr(EVP_F_EVP_PKCS82PKEY, EVP_R_UNSUPPORTED_PRIVATE_KEY_ALGORITHM);
++        i2t_ASN1_OBJECT(obj_tmp, 80, algoid);
++        ERR_add_error_data(2, "TYPE=", obj_tmp);
++        goto error;
++    }
++
++    if (pkey->ameth->priv_decode) {
++        if (!pkey->ameth->priv_decode(pkey, p8)) {
++            EVPerr(EVP_F_EVP_PKCS82PKEY, EVP_R_PRIVATE_KEY_DECODE_ERROR);
++            goto error;
++        }
++    } else {
++        EVPerr(EVP_F_EVP_PKCS82PKEY, EVP_R_METHOD_NOT_SUPPORTED);
++        goto error;
++    }
++
++    return pkey;
++
++ error:
++    EVP_PKEY_free(pkey);
++    return NULL;
++}
++
++/* Turn a private key into a PKCS8 structure */
++
++PKCS8_PRIV_KEY_INFO *EVP_PKEY2PKCS8(EVP_PKEY *pkey)
++{
++    PKCS8_PRIV_KEY_INFO *p8 = PKCS8_PRIV_KEY_INFO_new();
++    if (p8  == NULL) {
++        EVPerr(EVP_F_EVP_PKEY2PKCS8, ERR_R_MALLOC_FAILURE);
++        return NULL;
++    }
++
++    if (pkey->ameth) {
++        if (pkey->ameth->priv_encode) {
++            if (!pkey->ameth->priv_encode(p8, pkey)) {
++                EVPerr(EVP_F_EVP_PKEY2PKCS8, EVP_R_PRIVATE_KEY_ENCODE_ERROR);
++                goto error;
++            }
++        } else {
++            EVPerr(EVP_F_EVP_PKEY2PKCS8, EVP_R_METHOD_NOT_SUPPORTED);
++            goto error;
++        }
++    } else {
++        EVPerr(EVP_F_EVP_PKEY2PKCS8, EVP_R_UNSUPPORTED_PRIVATE_KEY_ALGORITHM);
++        goto error;
++    }
++    RAND_add(p8->pkey->data, p8->pkey->length, 0.0);
++    return p8;
++ error:
++    PKCS8_PRIV_KEY_INFO_free(p8);
++    return NULL;
++}
++
++/* EVP_PKEY attribute functions */
++
++int EVP_PKEY_get_attr_count(const EVP_PKEY *key)
++{
++    return X509at_get_attr_count(key->attributes);
++}
++
++int EVP_PKEY_get_attr_by_NID(const EVP_PKEY *key, int nid, int lastpos)
++{
++    return X509at_get_attr_by_NID(key->attributes, nid, lastpos);
++}
++
++int EVP_PKEY_get_attr_by_OBJ(const EVP_PKEY *key, const ASN1_OBJECT *obj,
++                             int lastpos)
++{
++    return X509at_get_attr_by_OBJ(key->attributes, obj, lastpos);
++}
++
++X509_ATTRIBUTE *EVP_PKEY_get_attr(const EVP_PKEY *key, int loc)
++{
++    return X509at_get_attr(key->attributes, loc);
++}
++
++X509_ATTRIBUTE *EVP_PKEY_delete_attr(EVP_PKEY *key, int loc)
++{
++    return X509at_delete_attr(key->attributes, loc);
++}
++
++int EVP_PKEY_add1_attr(EVP_PKEY *key, X509_ATTRIBUTE *attr)
++{
++    if (X509at_add1_attr(&key->attributes, attr))
++        return 1;
++    return 0;
++}
++
++int EVP_PKEY_add1_attr_by_OBJ(EVP_PKEY *key,
++                              const ASN1_OBJECT *obj, int type,
++                              const unsigned char *bytes, int len)
++{
++    if (X509at_add1_attr_by_OBJ(&key->attributes, obj, type, bytes, len))
++        return 1;
++    return 0;
++}
++
++int EVP_PKEY_add1_attr_by_NID(EVP_PKEY *key,
++                              int nid, int type,
++                              const unsigned char *bytes, int len)
++{
++    if (X509at_add1_attr_by_NID(&key->attributes, nid, type, bytes, len))
++        return 1;
++    return 0;
++}
++
++int EVP_PKEY_add1_attr_by_txt(EVP_PKEY *key,
++                              const char *attrname, int type,
++                              const unsigned char *bytes, int len)
++{
++    if (X509at_add1_attr_by_txt(&key->attributes, attrname, type, bytes, len))
++        return 1;
++    return 0;
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/evp/m_md2.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/evp/m_md2.c
+new file mode 100644
+index 0000000..c4e28ae
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/evp/m_md2.c
+@@ -0,0 +1,56 @@
++/*
++ * Copyright 1995-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include "internal/cryptlib.h"
++
++#ifndef OPENSSL_NO_MD2
++
++# include 
++# include 
++# include 
++# include 
++# include 
++
++#include "internal/evp_int.h"
++
++static int init(EVP_MD_CTX *ctx)
++{
++    return MD2_Init(EVP_MD_CTX_md_data(ctx));
++}
++
++static int update(EVP_MD_CTX *ctx, const void *data, size_t count)
++{
++    return MD2_Update(EVP_MD_CTX_md_data(ctx), data, count);
++}
++
++static int final(EVP_MD_CTX *ctx, unsigned char *md)
++{
++    return MD2_Final(md, EVP_MD_CTX_md_data(ctx));
++}
++
++static const EVP_MD md2_md = {
++    NID_md2,
++    NID_md2WithRSAEncryption,
++    MD2_DIGEST_LENGTH,
++    0,
++    init,
++    update,
++    final,
++    NULL,
++    NULL,
++    MD2_BLOCK,
++    sizeof(EVP_MD *) + sizeof(MD2_CTX),
++};
++
++const EVP_MD *EVP_md2(void)
++{
++    return &md2_md;
++}
++#endif
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/evp/m_md4.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/evp/m_md4.c
+new file mode 100644
+index 0000000..f3decaa
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/evp/m_md4.c
+@@ -0,0 +1,55 @@
++/*
++ * Copyright 1995-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include "internal/cryptlib.h"
++
++#ifndef OPENSSL_NO_MD4
++
++# include 
++# include 
++# include 
++# include 
++# include 
++# include "internal/evp_int.h"
++
++static int init(EVP_MD_CTX *ctx)
++{
++    return MD4_Init(EVP_MD_CTX_md_data(ctx));
++}
++
++static int update(EVP_MD_CTX *ctx, const void *data, size_t count)
++{
++    return MD4_Update(EVP_MD_CTX_md_data(ctx), data, count);
++}
++
++static int final(EVP_MD_CTX *ctx, unsigned char *md)
++{
++    return MD4_Final(md, EVP_MD_CTX_md_data(ctx));
++}
++
++static const EVP_MD md4_md = {
++    NID_md4,
++    NID_md4WithRSAEncryption,
++    MD4_DIGEST_LENGTH,
++    0,
++    init,
++    update,
++    final,
++    NULL,
++    NULL,
++    MD4_CBLOCK,
++    sizeof(EVP_MD *) + sizeof(MD4_CTX),
++};
++
++const EVP_MD *EVP_md4(void)
++{
++    return (&md4_md);
++}
++#endif
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/evp/m_md5.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/evp/m_md5.c
+new file mode 100644
+index 0000000..f4dc0c4
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/evp/m_md5.c
+@@ -0,0 +1,55 @@
++/*
++ * Copyright 1995-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include "internal/cryptlib.h"
++
++#ifndef OPENSSL_NO_MD5
++
++# include 
++# include 
++# include 
++# include 
++# include 
++# include "internal/evp_int.h"
++
++static int init(EVP_MD_CTX *ctx)
++{
++    return MD5_Init(EVP_MD_CTX_md_data(ctx));
++}
++
++static int update(EVP_MD_CTX *ctx, const void *data, size_t count)
++{
++    return MD5_Update(EVP_MD_CTX_md_data(ctx), data, count);
++}
++
++static int final(EVP_MD_CTX *ctx, unsigned char *md)
++{
++    return MD5_Final(md, EVP_MD_CTX_md_data(ctx));
++}
++
++static const EVP_MD md5_md = {
++    NID_md5,
++    NID_md5WithRSAEncryption,
++    MD5_DIGEST_LENGTH,
++    0,
++    init,
++    update,
++    final,
++    NULL,
++    NULL,
++    MD5_CBLOCK,
++    sizeof(EVP_MD *) + sizeof(MD5_CTX),
++};
++
++const EVP_MD *EVP_md5(void)
++{
++    return (&md5_md);
++}
++#endif
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/evp/m_md5_sha1.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/evp/m_md5_sha1.c
+new file mode 100644
+index 0000000..2d98886
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/evp/m_md5_sha1.c
+@@ -0,0 +1,142 @@
++/*
++ * Copyright 2015-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#if !defined(OPENSSL_NO_MD5)
++
++# include 
++# include 
++# include 
++# include 
++# include 
++# include "internal/cryptlib.h"
++# include "internal/evp_int.h"
++# include 
++
++struct md5_sha1_ctx {
++    MD5_CTX md5;
++    SHA_CTX sha1;
++};
++
++static int init(EVP_MD_CTX *ctx)
++{
++    struct md5_sha1_ctx *mctx = EVP_MD_CTX_md_data(ctx);
++    if (!MD5_Init(&mctx->md5))
++        return 0;
++    return SHA1_Init(&mctx->sha1);
++}
++
++static int update(EVP_MD_CTX *ctx, const void *data, size_t count)
++{
++    struct md5_sha1_ctx *mctx = EVP_MD_CTX_md_data(ctx);
++    if (!MD5_Update(&mctx->md5, data, count))
++        return 0;
++    return SHA1_Update(&mctx->sha1, data, count);
++}
++
++static int final(EVP_MD_CTX *ctx, unsigned char *md)
++{
++    struct md5_sha1_ctx *mctx = EVP_MD_CTX_md_data(ctx);
++    if (!MD5_Final(md, &mctx->md5))
++        return 0;
++    return SHA1_Final(md + MD5_DIGEST_LENGTH, &mctx->sha1);
++}
++
++static int ctrl(EVP_MD_CTX *ctx, int cmd, int mslen, void *ms)
++{
++    unsigned char padtmp[48];
++    unsigned char md5tmp[MD5_DIGEST_LENGTH];
++    unsigned char sha1tmp[SHA_DIGEST_LENGTH];
++    struct md5_sha1_ctx *mctx;
++
++    if (cmd != EVP_CTRL_SSL3_MASTER_SECRET)
++        return -2;
++
++    if (ctx == NULL)
++        return 0;
++
++    mctx = EVP_MD_CTX_md_data(ctx);
++
++    /* SSLv3 client auth handling: see RFC-6101 5.6.8 */
++    if (mslen != 48)
++        return 0;
++
++    /* At this point hash contains all handshake messages, update
++     * with master secret and pad_1.
++     */
++
++    if (update(ctx, ms, mslen) <= 0)
++        return 0;
++
++    /* Set padtmp to pad_1 value */
++    memset(padtmp, 0x36, sizeof(padtmp));
++
++    if (!MD5_Update(&mctx->md5, padtmp, sizeof(padtmp)))
++        return 0;
++
++    if (!MD5_Final(md5tmp, &mctx->md5))
++        return 0;
++
++    if (!SHA1_Update(&mctx->sha1, padtmp, 40))
++        return 0;
++
++    if (!SHA1_Final(sha1tmp, &mctx->sha1))
++        return 0;
++
++    /* Reinitialise context */
++
++    if (!init(ctx))
++        return 0;
++
++    if (update(ctx, ms, mslen) <= 0)
++        return 0;
++
++    /* Set padtmp to pad_2 value */
++    memset(padtmp, 0x5c, sizeof(padtmp));
++
++    if (!MD5_Update(&mctx->md5, padtmp, sizeof(padtmp)))
++        return 0;
++
++    if (!MD5_Update(&mctx->md5, md5tmp, sizeof(md5tmp)))
++        return 0;
++
++    if (!SHA1_Update(&mctx->sha1, padtmp, 40))
++        return 0;
++
++    if (!SHA1_Update(&mctx->sha1, sha1tmp, sizeof(sha1tmp)))
++        return 0;
++
++    /* Now when ctx is finalised it will return the SSL v3 hash value */
++
++    OPENSSL_cleanse(md5tmp, sizeof(md5tmp));
++    OPENSSL_cleanse(sha1tmp, sizeof(sha1tmp));
++
++    return 1;
++
++}
++
++static const EVP_MD md5_sha1_md = {
++    NID_md5_sha1,
++    NID_md5_sha1,
++    MD5_DIGEST_LENGTH + SHA_DIGEST_LENGTH,
++    0,
++    init,
++    update,
++    final,
++    NULL,
++    NULL,
++    MD5_CBLOCK,
++    sizeof(EVP_MD *) + sizeof(struct md5_sha1_ctx),
++    ctrl
++};
++
++const EVP_MD *EVP_md5_sha1(void)
++{
++    return &md5_sha1_md;
++}
++#endif
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/evp/m_mdc2.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/evp/m_mdc2.c
+new file mode 100644
+index 0000000..b7f0fd8
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/evp/m_mdc2.c
+@@ -0,0 +1,55 @@
++/*
++ * Copyright 1995-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include "internal/cryptlib.h"
++
++#ifndef OPENSSL_NO_MDC2
++
++# include 
++# include 
++# include 
++# include 
++# include 
++# include "internal/evp_int.h"
++
++static int init(EVP_MD_CTX *ctx)
++{
++    return MDC2_Init(EVP_MD_CTX_md_data(ctx));
++}
++
++static int update(EVP_MD_CTX *ctx, const void *data, size_t count)
++{
++    return MDC2_Update(EVP_MD_CTX_md_data(ctx), data, count);
++}
++
++static int final(EVP_MD_CTX *ctx, unsigned char *md)
++{
++    return MDC2_Final(md, EVP_MD_CTX_md_data(ctx));
++}
++
++static const EVP_MD mdc2_md = {
++    NID_mdc2,
++    NID_mdc2WithRSA,
++    MDC2_DIGEST_LENGTH,
++    0,
++    init,
++    update,
++    final,
++    NULL,
++    NULL,
++    MDC2_BLOCK,
++    sizeof(EVP_MD *) + sizeof(MDC2_CTX),
++};
++
++const EVP_MD *EVP_mdc2(void)
++{
++    return (&mdc2_md);
++}
++#endif
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/evp/m_null.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/evp/m_null.c
+new file mode 100644
+index 0000000..6c4daf5
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/evp/m_null.c
+@@ -0,0 +1,49 @@
++/*
++ * Copyright 1995-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include "internal/cryptlib.h"
++#include 
++#include 
++#include 
++#include "internal/evp_int.h"
++
++static int init(EVP_MD_CTX *ctx)
++{
++    return 1;
++}
++
++static int update(EVP_MD_CTX *ctx, const void *data, size_t count)
++{
++    return 1;
++}
++
++static int final(EVP_MD_CTX *ctx, unsigned char *md)
++{
++    return 1;
++}
++
++static const EVP_MD null_md = {
++    NID_undef,
++    NID_undef,
++    0,
++    0,
++    init,
++    update,
++    final,
++    NULL,
++    NULL,
++    0,
++    sizeof(EVP_MD *),
++};
++
++const EVP_MD *EVP_md_null(void)
++{
++    return (&null_md);
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/evp/m_ripemd.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/evp/m_ripemd.c
+new file mode 100644
+index 0000000..07b46bd
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/evp/m_ripemd.c
+@@ -0,0 +1,55 @@
++/*
++ * Copyright 1995-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include "internal/cryptlib.h"
++
++#ifndef OPENSSL_NO_RMD160
++
++# include 
++# include 
++# include 
++# include 
++# include 
++# include "internal/evp_int.h"
++
++static int init(EVP_MD_CTX *ctx)
++{
++    return RIPEMD160_Init(EVP_MD_CTX_md_data(ctx));
++}
++
++static int update(EVP_MD_CTX *ctx, const void *data, size_t count)
++{
++    return RIPEMD160_Update(EVP_MD_CTX_md_data(ctx), data, count);
++}
++
++static int final(EVP_MD_CTX *ctx, unsigned char *md)
++{
++    return RIPEMD160_Final(md, EVP_MD_CTX_md_data(ctx));
++}
++
++static const EVP_MD ripemd160_md = {
++    NID_ripemd160,
++    NID_ripemd160WithRSA,
++    RIPEMD160_DIGEST_LENGTH,
++    0,
++    init,
++    update,
++    final,
++    NULL,
++    NULL,
++    RIPEMD160_CBLOCK,
++    sizeof(EVP_MD *) + sizeof(RIPEMD160_CTX),
++};
++
++const EVP_MD *EVP_ripemd160(void)
++{
++    return (&ripemd160_md);
++}
++#endif
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/evp/m_sha1.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/evp/m_sha1.c
+new file mode 100644
+index 0000000..8f30077
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/evp/m_sha1.c
+@@ -0,0 +1,233 @@
++/*
++ * Copyright 1995-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include "internal/cryptlib.h"
++
++#include 
++#include 
++#include 
++#include 
++#include "internal/evp_int.h"
++
++static int init(EVP_MD_CTX *ctx)
++{
++    return SHA1_Init(EVP_MD_CTX_md_data(ctx));
++}
++
++static int update(EVP_MD_CTX *ctx, const void *data, size_t count)
++{
++    return SHA1_Update(EVP_MD_CTX_md_data(ctx), data, count);
++}
++
++static int final(EVP_MD_CTX *ctx, unsigned char *md)
++{
++    return SHA1_Final(md, EVP_MD_CTX_md_data(ctx));
++}
++
++static int ctrl(EVP_MD_CTX *ctx, int cmd, int mslen, void *ms)
++{
++    unsigned char padtmp[40];
++    unsigned char sha1tmp[SHA_DIGEST_LENGTH];
++
++    SHA_CTX *sha1;
++
++    if (cmd != EVP_CTRL_SSL3_MASTER_SECRET)
++        return -2;
++
++    if (ctx == NULL)
++        return 0;
++
++    sha1 = EVP_MD_CTX_md_data(ctx);
++
++    /* SSLv3 client auth handling: see RFC-6101 5.6.8 */
++    if (mslen != 48)
++        return 0;
++
++    /* At this point hash contains all handshake messages, update
++     * with master secret and pad_1.
++     */
++
++    if (SHA1_Update(sha1, ms, mslen) <= 0)
++        return 0;
++
++    /* Set padtmp to pad_1 value */
++    memset(padtmp, 0x36, sizeof(padtmp));
++
++    if (!SHA1_Update(sha1, padtmp, sizeof(padtmp)))
++        return 0;
++
++    if (!SHA1_Final(sha1tmp, sha1))
++        return 0;
++
++    /* Reinitialise context */
++
++    if (!SHA1_Init(sha1))
++        return 0;
++
++    if (SHA1_Update(sha1, ms, mslen) <= 0)
++        return 0;
++
++    /* Set padtmp to pad_2 value */
++    memset(padtmp, 0x5c, sizeof(padtmp));
++
++    if (!SHA1_Update(sha1, padtmp, sizeof(padtmp)))
++        return 0;
++
++    if (!SHA1_Update(sha1, sha1tmp, sizeof(sha1tmp)))
++        return 0;
++
++    /* Now when ctx is finalised it will return the SSL v3 hash value */
++    OPENSSL_cleanse(sha1tmp, sizeof(sha1tmp));
++
++    return 1;
++
++}
++
++static const EVP_MD sha1_md = {
++    NID_sha1,
++    NID_sha1WithRSAEncryption,
++    SHA_DIGEST_LENGTH,
++    EVP_MD_FLAG_DIGALGID_ABSENT,
++    init,
++    update,
++    final,
++    NULL,
++    NULL,
++    SHA_CBLOCK,
++    sizeof(EVP_MD *) + sizeof(SHA_CTX),
++    ctrl
++};
++
++const EVP_MD *EVP_sha1(void)
++{
++    return (&sha1_md);
++}
++
++static int init224(EVP_MD_CTX *ctx)
++{
++    return SHA224_Init(EVP_MD_CTX_md_data(ctx));
++}
++
++static int init256(EVP_MD_CTX *ctx)
++{
++    return SHA256_Init(EVP_MD_CTX_md_data(ctx));
++}
++
++/*
++ * Even though there're separate SHA224_[Update|Final], we call
++ * SHA256 functions even in SHA224 context. This is what happens
++ * there anyway, so we can spare few CPU cycles:-)
++ */
++static int update256(EVP_MD_CTX *ctx, const void *data, size_t count)
++{
++    return SHA256_Update(EVP_MD_CTX_md_data(ctx), data, count);
++}
++
++static int final256(EVP_MD_CTX *ctx, unsigned char *md)
++{
++    return SHA256_Final(md, EVP_MD_CTX_md_data(ctx));
++}
++
++static const EVP_MD sha224_md = {
++    NID_sha224,
++    NID_sha224WithRSAEncryption,
++    SHA224_DIGEST_LENGTH,
++    EVP_MD_FLAG_DIGALGID_ABSENT,
++    init224,
++    update256,
++    final256,
++    NULL,
++    NULL,
++    SHA256_CBLOCK,
++    sizeof(EVP_MD *) + sizeof(SHA256_CTX),
++};
++
++const EVP_MD *EVP_sha224(void)
++{
++    return (&sha224_md);
++}
++
++static const EVP_MD sha256_md = {
++    NID_sha256,
++    NID_sha256WithRSAEncryption,
++    SHA256_DIGEST_LENGTH,
++    EVP_MD_FLAG_DIGALGID_ABSENT,
++    init256,
++    update256,
++    final256,
++    NULL,
++    NULL,
++    SHA256_CBLOCK,
++    sizeof(EVP_MD *) + sizeof(SHA256_CTX),
++};
++
++const EVP_MD *EVP_sha256(void)
++{
++    return (&sha256_md);
++}
++
++static int init384(EVP_MD_CTX *ctx)
++{
++    return SHA384_Init(EVP_MD_CTX_md_data(ctx));
++}
++
++static int init512(EVP_MD_CTX *ctx)
++{
++    return SHA512_Init(EVP_MD_CTX_md_data(ctx));
++}
++
++/* See comment in SHA224/256 section */
++static int update512(EVP_MD_CTX *ctx, const void *data, size_t count)
++{
++    return SHA512_Update(EVP_MD_CTX_md_data(ctx), data, count);
++}
++
++static int final512(EVP_MD_CTX *ctx, unsigned char *md)
++{
++    return SHA512_Final(md, EVP_MD_CTX_md_data(ctx));
++}
++
++static const EVP_MD sha384_md = {
++    NID_sha384,
++    NID_sha384WithRSAEncryption,
++    SHA384_DIGEST_LENGTH,
++    EVP_MD_FLAG_DIGALGID_ABSENT,
++    init384,
++    update512,
++    final512,
++    NULL,
++    NULL,
++    SHA512_CBLOCK,
++    sizeof(EVP_MD *) + sizeof(SHA512_CTX),
++};
++
++const EVP_MD *EVP_sha384(void)
++{
++    return (&sha384_md);
++}
++
++static const EVP_MD sha512_md = {
++    NID_sha512,
++    NID_sha512WithRSAEncryption,
++    SHA512_DIGEST_LENGTH,
++    EVP_MD_FLAG_DIGALGID_ABSENT,
++    init512,
++    update512,
++    final512,
++    NULL,
++    NULL,
++    SHA512_CBLOCK,
++    sizeof(EVP_MD *) + sizeof(SHA512_CTX),
++};
++
++const EVP_MD *EVP_sha512(void)
++{
++    return (&sha512_md);
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/evp/m_sigver.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/evp/m_sigver.c
+new file mode 100644
+index 0000000..3b74f72
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/evp/m_sigver.c
+@@ -0,0 +1,169 @@
++/*
++ * Copyright 2006-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include "internal/cryptlib.h"
++#include 
++#include 
++#include 
++#include "internal/evp_int.h"
++#include "evp_locl.h"
++
++static int do_sigver_init(EVP_MD_CTX *ctx, EVP_PKEY_CTX **pctx,
++                          const EVP_MD *type, ENGINE *e, EVP_PKEY *pkey,
++                          int ver)
++{
++    if (ctx->pctx == NULL)
++        ctx->pctx = EVP_PKEY_CTX_new(pkey, e);
++    if (ctx->pctx == NULL)
++        return 0;
++
++    if (!(ctx->pctx->pmeth->flags & EVP_PKEY_FLAG_SIGCTX_CUSTOM)) {
++
++        if (type == NULL) {
++            int def_nid;
++            if (EVP_PKEY_get_default_digest_nid(pkey, &def_nid) > 0)
++                type = EVP_get_digestbynid(def_nid);
++        }
++
++        if (type == NULL) {
++            EVPerr(EVP_F_DO_SIGVER_INIT, EVP_R_NO_DEFAULT_DIGEST);
++            return 0;
++        }
++    }
++
++    if (ver) {
++        if (ctx->pctx->pmeth->verifyctx_init) {
++            if (ctx->pctx->pmeth->verifyctx_init(ctx->pctx, ctx) <= 0)
++                return 0;
++            ctx->pctx->operation = EVP_PKEY_OP_VERIFYCTX;
++        } else if (EVP_PKEY_verify_init(ctx->pctx) <= 0)
++            return 0;
++    } else {
++        if (ctx->pctx->pmeth->signctx_init) {
++            if (ctx->pctx->pmeth->signctx_init(ctx->pctx, ctx) <= 0)
++                return 0;
++            ctx->pctx->operation = EVP_PKEY_OP_SIGNCTX;
++        } else if (EVP_PKEY_sign_init(ctx->pctx) <= 0)
++            return 0;
++    }
++    if (EVP_PKEY_CTX_set_signature_md(ctx->pctx, type) <= 0)
++        return 0;
++    if (pctx)
++        *pctx = ctx->pctx;
++    if (ctx->pctx->pmeth->flags & EVP_PKEY_FLAG_SIGCTX_CUSTOM)
++        return 1;
++    if (!EVP_DigestInit_ex(ctx, type, e))
++        return 0;
++    return 1;
++}
++
++int EVP_DigestSignInit(EVP_MD_CTX *ctx, EVP_PKEY_CTX **pctx,
++                       const EVP_MD *type, ENGINE *e, EVP_PKEY *pkey)
++{
++    return do_sigver_init(ctx, pctx, type, e, pkey, 0);
++}
++
++int EVP_DigestVerifyInit(EVP_MD_CTX *ctx, EVP_PKEY_CTX **pctx,
++                         const EVP_MD *type, ENGINE *e, EVP_PKEY *pkey)
++{
++    return do_sigver_init(ctx, pctx, type, e, pkey, 1);
++}
++
++int EVP_DigestSignFinal(EVP_MD_CTX *ctx, unsigned char *sigret,
++                        size_t *siglen)
++{
++    int sctx = 0, r = 0;
++    EVP_PKEY_CTX *pctx = ctx->pctx;
++    if (pctx->pmeth->flags & EVP_PKEY_FLAG_SIGCTX_CUSTOM) {
++        if (!sigret)
++            return pctx->pmeth->signctx(pctx, sigret, siglen, ctx);
++        if (ctx->flags & EVP_MD_CTX_FLAG_FINALISE)
++            r = pctx->pmeth->signctx(pctx, sigret, siglen, ctx);
++        else {
++            EVP_PKEY_CTX *dctx = EVP_PKEY_CTX_dup(ctx->pctx);
++            if (!dctx)
++                return 0;
++            r = dctx->pmeth->signctx(dctx, sigret, siglen, ctx);
++            EVP_PKEY_CTX_free(dctx);
++        }
++        return r;
++    }
++    if (pctx->pmeth->signctx)
++        sctx = 1;
++    else
++        sctx = 0;
++    if (sigret) {
++        unsigned char md[EVP_MAX_MD_SIZE];
++        unsigned int mdlen = 0;
++        if (ctx->flags & EVP_MD_CTX_FLAG_FINALISE) {
++            if (sctx)
++                r = ctx->pctx->pmeth->signctx(ctx->pctx, sigret, siglen, ctx);
++            else
++                r = EVP_DigestFinal_ex(ctx, md, &mdlen);
++        } else {
++            EVP_MD_CTX *tmp_ctx = EVP_MD_CTX_new();
++            if (tmp_ctx == NULL || !EVP_MD_CTX_copy_ex(tmp_ctx, ctx))
++                return 0;
++            if (sctx)
++                r = tmp_ctx->pctx->pmeth->signctx(tmp_ctx->pctx,
++                                                  sigret, siglen, tmp_ctx);
++            else
++                r = EVP_DigestFinal_ex(tmp_ctx, md, &mdlen);
++            EVP_MD_CTX_free(tmp_ctx);
++        }
++        if (sctx || !r)
++            return r;
++        if (EVP_PKEY_sign(ctx->pctx, sigret, siglen, md, mdlen) <= 0)
++            return 0;
++    } else {
++        if (sctx) {
++            if (pctx->pmeth->signctx(pctx, sigret, siglen, ctx) <= 0)
++                return 0;
++        } else {
++            int s = EVP_MD_size(ctx->digest);
++            if (s < 0 || EVP_PKEY_sign(pctx, sigret, siglen, NULL, s) <= 0)
++                return 0;
++        }
++    }
++    return 1;
++}
++
++int EVP_DigestVerifyFinal(EVP_MD_CTX *ctx, const unsigned char *sig,
++                          size_t siglen)
++{
++    unsigned char md[EVP_MAX_MD_SIZE];
++    int r = 0;
++    unsigned int mdlen = 0;
++    int vctx = 0;
++
++    if (ctx->pctx->pmeth->verifyctx)
++        vctx = 1;
++    else
++        vctx = 0;
++    if (ctx->flags & EVP_MD_CTX_FLAG_FINALISE) {
++        if (vctx) {
++            r = ctx->pctx->pmeth->verifyctx(ctx->pctx, sig, siglen, ctx);
++        } else
++            r = EVP_DigestFinal_ex(ctx, md, &mdlen);
++    } else {
++        EVP_MD_CTX *tmp_ctx = EVP_MD_CTX_new();
++        if (tmp_ctx == NULL || !EVP_MD_CTX_copy_ex(tmp_ctx, ctx))
++            return -1;
++        if (vctx) {
++            r = tmp_ctx->pctx->pmeth->verifyctx(tmp_ctx->pctx,
++                                                sig, siglen, tmp_ctx);
++        } else
++            r = EVP_DigestFinal_ex(tmp_ctx, md, &mdlen);
++        EVP_MD_CTX_free(tmp_ctx);
++    }
++    if (vctx || !r)
++        return r;
++    return EVP_PKEY_verify(ctx->pctx, sig, siglen, md, mdlen);
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/evp/m_wp.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/evp/m_wp.c
+new file mode 100644
+index 0000000..94fac22
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/evp/m_wp.c
+@@ -0,0 +1,54 @@
++/*
++ * Copyright 2005-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include "internal/cryptlib.h"
++
++#ifndef OPENSSL_NO_WHIRLPOOL
++
++# include 
++# include 
++# include 
++# include 
++# include "internal/evp_int.h"
++
++static int init(EVP_MD_CTX *ctx)
++{
++    return WHIRLPOOL_Init(EVP_MD_CTX_md_data(ctx));
++}
++
++static int update(EVP_MD_CTX *ctx, const void *data, size_t count)
++{
++    return WHIRLPOOL_Update(EVP_MD_CTX_md_data(ctx), data, count);
++}
++
++static int final(EVP_MD_CTX *ctx, unsigned char *md)
++{
++    return WHIRLPOOL_Final(md, EVP_MD_CTX_md_data(ctx));
++}
++
++static const EVP_MD whirlpool_md = {
++    NID_whirlpool,
++    0,
++    WHIRLPOOL_DIGEST_LENGTH,
++    0,
++    init,
++    update,
++    final,
++    NULL,
++    NULL,
++    WHIRLPOOL_BBLOCK / 8,
++    sizeof(EVP_MD *) + sizeof(WHIRLPOOL_CTX),
++};
++
++const EVP_MD *EVP_whirlpool(void)
++{
++    return (&whirlpool_md);
++}
++#endif
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/evp/names.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/evp/names.c
+new file mode 100644
+index 0000000..a92be1f
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/evp/names.c
+@@ -0,0 +1,178 @@
++/*
++ * Copyright 1995-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include "internal/cryptlib.h"
++#include 
++#include 
++#include 
++#include "internal/evp_int.h"
++
++int EVP_add_cipher(const EVP_CIPHER *c)
++{
++    int r;
++
++    if (c == NULL)
++        return 0;
++
++    r = OBJ_NAME_add(OBJ_nid2sn(c->nid), OBJ_NAME_TYPE_CIPHER_METH,
++                     (const char *)c);
++    if (r == 0)
++        return (0);
++    r = OBJ_NAME_add(OBJ_nid2ln(c->nid), OBJ_NAME_TYPE_CIPHER_METH,
++                     (const char *)c);
++    return (r);
++}
++
++int EVP_add_digest(const EVP_MD *md)
++{
++    int r;
++    const char *name;
++
++    name = OBJ_nid2sn(md->type);
++    r = OBJ_NAME_add(name, OBJ_NAME_TYPE_MD_METH, (const char *)md);
++    if (r == 0)
++        return (0);
++    r = OBJ_NAME_add(OBJ_nid2ln(md->type), OBJ_NAME_TYPE_MD_METH,
++                     (const char *)md);
++    if (r == 0)
++        return (0);
++
++    if (md->pkey_type && md->type != md->pkey_type) {
++        r = OBJ_NAME_add(OBJ_nid2sn(md->pkey_type),
++                         OBJ_NAME_TYPE_MD_METH | OBJ_NAME_ALIAS, name);
++        if (r == 0)
++            return (0);
++        r = OBJ_NAME_add(OBJ_nid2ln(md->pkey_type),
++                         OBJ_NAME_TYPE_MD_METH | OBJ_NAME_ALIAS, name);
++    }
++    return (r);
++}
++
++const EVP_CIPHER *EVP_get_cipherbyname(const char *name)
++{
++    const EVP_CIPHER *cp;
++
++    if (!OPENSSL_init_crypto(OPENSSL_INIT_ADD_ALL_CIPHERS, NULL))
++        return NULL;
++
++    cp = (const EVP_CIPHER *)OBJ_NAME_get(name, OBJ_NAME_TYPE_CIPHER_METH);
++    return (cp);
++}
++
++const EVP_MD *EVP_get_digestbyname(const char *name)
++{
++    const EVP_MD *cp;
++
++    if (!OPENSSL_init_crypto(OPENSSL_INIT_ADD_ALL_DIGESTS, NULL))
++        return NULL;
++
++    cp = (const EVP_MD *)OBJ_NAME_get(name, OBJ_NAME_TYPE_MD_METH);
++    return (cp);
++}
++
++void evp_cleanup_int(void)
++{
++    OBJ_NAME_cleanup(OBJ_NAME_TYPE_CIPHER_METH);
++    OBJ_NAME_cleanup(OBJ_NAME_TYPE_MD_METH);
++    /*
++     * The above calls will only clean out the contents of the name hash
++     * table, but not the hash table itself.  The following line does that
++     * part.  -- Richard Levitte
++     */
++    OBJ_NAME_cleanup(-1);
++
++    EVP_PBE_cleanup();
++    OBJ_sigid_free();
++}
++
++struct doall_cipher {
++    void *arg;
++    void (*fn) (const EVP_CIPHER *ciph,
++                const char *from, const char *to, void *arg);
++};
++
++static void do_all_cipher_fn(const OBJ_NAME *nm, void *arg)
++{
++    struct doall_cipher *dc = arg;
++    if (nm->alias)
++        dc->fn(NULL, nm->name, nm->data, dc->arg);
++    else
++        dc->fn((const EVP_CIPHER *)nm->data, nm->name, NULL, dc->arg);
++}
++
++void EVP_CIPHER_do_all(void (*fn) (const EVP_CIPHER *ciph,
++                                   const char *from, const char *to, void *x),
++                       void *arg)
++{
++    struct doall_cipher dc;
++
++    /* Ignore errors */
++    OPENSSL_init_crypto(OPENSSL_INIT_ADD_ALL_CIPHERS, NULL);
++
++    dc.fn = fn;
++    dc.arg = arg;
++    OBJ_NAME_do_all(OBJ_NAME_TYPE_CIPHER_METH, do_all_cipher_fn, &dc);
++}
++
++void EVP_CIPHER_do_all_sorted(void (*fn) (const EVP_CIPHER *ciph,
++                                          const char *from, const char *to,
++                                          void *x), void *arg)
++{
++    struct doall_cipher dc;
++
++    /* Ignore errors */
++    OPENSSL_init_crypto(OPENSSL_INIT_ADD_ALL_CIPHERS, NULL);
++
++    dc.fn = fn;
++    dc.arg = arg;
++    OBJ_NAME_do_all_sorted(OBJ_NAME_TYPE_CIPHER_METH, do_all_cipher_fn, &dc);
++}
++
++struct doall_md {
++    void *arg;
++    void (*fn) (const EVP_MD *ciph,
++                const char *from, const char *to, void *arg);
++};
++
++static void do_all_md_fn(const OBJ_NAME *nm, void *arg)
++{
++    struct doall_md *dc = arg;
++    if (nm->alias)
++        dc->fn(NULL, nm->name, nm->data, dc->arg);
++    else
++        dc->fn((const EVP_MD *)nm->data, nm->name, NULL, dc->arg);
++}
++
++void EVP_MD_do_all(void (*fn) (const EVP_MD *md,
++                               const char *from, const char *to, void *x),
++                   void *arg)
++{
++    struct doall_md dc;
++
++    /* Ignore errors */
++    OPENSSL_init_crypto(OPENSSL_INIT_ADD_ALL_DIGESTS, NULL);
++
++    dc.fn = fn;
++    dc.arg = arg;
++    OBJ_NAME_do_all(OBJ_NAME_TYPE_MD_METH, do_all_md_fn, &dc);
++}
++
++void EVP_MD_do_all_sorted(void (*fn) (const EVP_MD *md,
++                                      const char *from, const char *to,
++                                      void *x), void *arg)
++{
++    struct doall_md dc;
++
++    OPENSSL_init_crypto(OPENSSL_INIT_ADD_ALL_DIGESTS, NULL);
++
++    dc.fn = fn;
++    dc.arg = arg;
++    OBJ_NAME_do_all_sorted(OBJ_NAME_TYPE_MD_METH, do_all_md_fn, &dc);
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/evp/p5_crpt.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/evp/p5_crpt.c
+new file mode 100644
+index 0000000..7e55d0b
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/evp/p5_crpt.c
+@@ -0,0 +1,103 @@
++/*
++ * Copyright 1999-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include 
++#include "internal/cryptlib.h"
++#include 
++#include 
++
++/*
++ * Doesn't do anything now: Builtin PBE algorithms in static table.
++ */
++
++void PKCS5_PBE_add(void)
++{
++}
++
++int PKCS5_PBE_keyivgen(EVP_CIPHER_CTX *cctx, const char *pass, int passlen,
++                       ASN1_TYPE *param, const EVP_CIPHER *cipher,
++                       const EVP_MD *md, int en_de)
++{
++    EVP_MD_CTX *ctx;
++    unsigned char md_tmp[EVP_MAX_MD_SIZE];
++    unsigned char key[EVP_MAX_KEY_LENGTH], iv[EVP_MAX_IV_LENGTH];
++    int i;
++    PBEPARAM *pbe;
++    int saltlen, iter;
++    unsigned char *salt;
++    int mdsize;
++    int rv = 0;
++
++    /* Extract useful info from parameter */
++    if (param == NULL || param->type != V_ASN1_SEQUENCE ||
++        param->value.sequence == NULL) {
++        EVPerr(EVP_F_PKCS5_PBE_KEYIVGEN, EVP_R_DECODE_ERROR);
++        return 0;
++    }
++
++    pbe = ASN1_TYPE_unpack_sequence(ASN1_ITEM_rptr(PBEPARAM), param);
++    if (pbe == NULL) {
++        EVPerr(EVP_F_PKCS5_PBE_KEYIVGEN, EVP_R_DECODE_ERROR);
++        return 0;
++    }
++
++    if (!pbe->iter)
++        iter = 1;
++    else
++        iter = ASN1_INTEGER_get(pbe->iter);
++    salt = pbe->salt->data;
++    saltlen = pbe->salt->length;
++
++    if (!pass)
++        passlen = 0;
++    else if (passlen == -1)
++        passlen = strlen(pass);
++
++    ctx = EVP_MD_CTX_new();
++    if (ctx == NULL) {
++        EVPerr(EVP_F_PKCS5_PBE_KEYIVGEN, ERR_R_MALLOC_FAILURE);
++        goto err;
++    }
++
++    if (!EVP_DigestInit_ex(ctx, md, NULL))
++        goto err;
++    if (!EVP_DigestUpdate(ctx, pass, passlen))
++        goto err;
++    if (!EVP_DigestUpdate(ctx, salt, saltlen))
++        goto err;
++    PBEPARAM_free(pbe);
++    if (!EVP_DigestFinal_ex(ctx, md_tmp, NULL))
++        goto err;
++    mdsize = EVP_MD_size(md);
++    if (mdsize < 0)
++        return 0;
++    for (i = 1; i < iter; i++) {
++        if (!EVP_DigestInit_ex(ctx, md, NULL))
++            goto err;
++        if (!EVP_DigestUpdate(ctx, md_tmp, mdsize))
++            goto err;
++        if (!EVP_DigestFinal_ex(ctx, md_tmp, NULL))
++            goto err;
++    }
++    OPENSSL_assert(EVP_CIPHER_key_length(cipher) <= (int)sizeof(md_tmp));
++    memcpy(key, md_tmp, EVP_CIPHER_key_length(cipher));
++    OPENSSL_assert(EVP_CIPHER_iv_length(cipher) <= 16);
++    memcpy(iv, md_tmp + (16 - EVP_CIPHER_iv_length(cipher)),
++           EVP_CIPHER_iv_length(cipher));
++    if (!EVP_CipherInit_ex(cctx, cipher, NULL, key, iv, en_de))
++        goto err;
++    OPENSSL_cleanse(md_tmp, EVP_MAX_MD_SIZE);
++    OPENSSL_cleanse(key, EVP_MAX_KEY_LENGTH);
++    OPENSSL_cleanse(iv, EVP_MAX_IV_LENGTH);
++    rv = 1;
++ err:
++    EVP_MD_CTX_free(ctx);
++    return rv;
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/evp/p5_crpt2.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/evp/p5_crpt2.c
+new file mode 100644
+index 0000000..2e45aa3
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/evp/p5_crpt2.c
+@@ -0,0 +1,277 @@
++/*
++ * Copyright 1999-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include 
++#include "internal/cryptlib.h"
++# include 
++# include 
++# include 
++# include "evp_locl.h"
++
++/* set this to print out info about the keygen algorithm */
++/* #define OPENSSL_DEBUG_PKCS5V2 */
++
++# ifdef OPENSSL_DEBUG_PKCS5V2
++static void h__dump(const unsigned char *p, int len);
++# endif
++
++/*
++ * This is an implementation of PKCS#5 v2.0 password based encryption key
++ * derivation function PBKDF2. SHA1 version verified against test vectors
++ * posted by Peter Gutmann  to the PKCS-TNG
++ *  mailing list.
++ */
++
++int PKCS5_PBKDF2_HMAC(const char *pass, int passlen,
++                      const unsigned char *salt, int saltlen, int iter,
++                      const EVP_MD *digest, int keylen, unsigned char *out)
++{
++    unsigned char digtmp[EVP_MAX_MD_SIZE], *p, itmp[4];
++    int cplen, j, k, tkeylen, mdlen;
++    unsigned long i = 1;
++    HMAC_CTX *hctx_tpl = NULL, *hctx = NULL;
++
++    mdlen = EVP_MD_size(digest);
++    if (mdlen < 0)
++        return 0;
++
++    hctx_tpl = HMAC_CTX_new();
++    if (hctx_tpl == NULL)
++        return 0;
++    p = out;
++    tkeylen = keylen;
++    if (!pass)
++        passlen = 0;
++    else if (passlen == -1)
++        passlen = strlen(pass);
++    if (!HMAC_Init_ex(hctx_tpl, pass, passlen, digest, NULL)) {
++        HMAC_CTX_free(hctx_tpl);
++        return 0;
++    }
++    hctx = HMAC_CTX_new();
++    if (hctx == NULL) {
++        HMAC_CTX_free(hctx_tpl);
++        return 0;
++    }
++    while (tkeylen) {
++        if (tkeylen > mdlen)
++            cplen = mdlen;
++        else
++            cplen = tkeylen;
++        /*
++         * We are unlikely to ever use more than 256 blocks (5120 bits!) but
++         * just in case...
++         */
++        itmp[0] = (unsigned char)((i >> 24) & 0xff);
++        itmp[1] = (unsigned char)((i >> 16) & 0xff);
++        itmp[2] = (unsigned char)((i >> 8) & 0xff);
++        itmp[3] = (unsigned char)(i & 0xff);
++        if (!HMAC_CTX_copy(hctx, hctx_tpl)) {
++            HMAC_CTX_free(hctx);
++            HMAC_CTX_free(hctx_tpl);
++            return 0;
++        }
++        if (!HMAC_Update(hctx, salt, saltlen)
++            || !HMAC_Update(hctx, itmp, 4)
++            || !HMAC_Final(hctx, digtmp, NULL)) {
++            HMAC_CTX_free(hctx);
++            HMAC_CTX_free(hctx_tpl);
++            return 0;
++        }
++        HMAC_CTX_reset(hctx);
++        memcpy(p, digtmp, cplen);
++        for (j = 1; j < iter; j++) {
++            if (!HMAC_CTX_copy(hctx, hctx_tpl)) {
++                HMAC_CTX_free(hctx);
++                HMAC_CTX_free(hctx_tpl);
++                return 0;
++            }
++            if (!HMAC_Update(hctx, digtmp, mdlen)
++                || !HMAC_Final(hctx, digtmp, NULL)) {
++                HMAC_CTX_free(hctx);
++                HMAC_CTX_free(hctx_tpl);
++                return 0;
++            }
++            HMAC_CTX_reset(hctx);
++            for (k = 0; k < cplen; k++)
++                p[k] ^= digtmp[k];
++        }
++        tkeylen -= cplen;
++        i++;
++        p += cplen;
++    }
++    HMAC_CTX_free(hctx);
++    HMAC_CTX_free(hctx_tpl);
++# ifdef OPENSSL_DEBUG_PKCS5V2
++    fprintf(stderr, "Password:\n");
++    h__dump(pass, passlen);
++    fprintf(stderr, "Salt:\n");
++    h__dump(salt, saltlen);
++    fprintf(stderr, "Iteration count %d\n", iter);
++    fprintf(stderr, "Key:\n");
++    h__dump(out, keylen);
++# endif
++    return 1;
++}
++
++int PKCS5_PBKDF2_HMAC_SHA1(const char *pass, int passlen,
++                           const unsigned char *salt, int saltlen, int iter,
++                           int keylen, unsigned char *out)
++{
++    return PKCS5_PBKDF2_HMAC(pass, passlen, salt, saltlen, iter, EVP_sha1(),
++                             keylen, out);
++}
++
++# ifdef DO_TEST
++main()
++{
++    unsigned char out[4];
++    unsigned char salt[] = { 0x12, 0x34, 0x56, 0x78 };
++    PKCS5_PBKDF2_HMAC_SHA1("password", -1, salt, 4, 5, 4, out);
++    fprintf(stderr, "Out %02X %02X %02X %02X\n",
++            out[0], out[1], out[2], out[3]);
++}
++
++# endif
++
++/*
++ * Now the key derivation function itself. This is a bit evil because it has
++ * to check the ASN1 parameters are valid: and there are quite a few of
++ * them...
++ */
++
++int PKCS5_v2_PBE_keyivgen(EVP_CIPHER_CTX *ctx, const char *pass, int passlen,
++                          ASN1_TYPE *param, const EVP_CIPHER *c,
++                          const EVP_MD *md, int en_de)
++{
++    PBE2PARAM *pbe2 = NULL;
++    const EVP_CIPHER *cipher;
++    EVP_PBE_KEYGEN *kdf;
++
++    int rv = 0;
++
++    pbe2 = ASN1_TYPE_unpack_sequence(ASN1_ITEM_rptr(PBE2PARAM), param);
++    if (pbe2 == NULL) {
++        EVPerr(EVP_F_PKCS5_V2_PBE_KEYIVGEN, EVP_R_DECODE_ERROR);
++        goto err;
++    }
++
++    /* See if we recognise the key derivation function */
++    if (!EVP_PBE_find(EVP_PBE_TYPE_KDF, OBJ_obj2nid(pbe2->keyfunc->algorithm),
++                        NULL, NULL, &kdf)) {
++        EVPerr(EVP_F_PKCS5_V2_PBE_KEYIVGEN,
++               EVP_R_UNSUPPORTED_KEY_DERIVATION_FUNCTION);
++        goto err;
++    }
++
++    /*
++     * lets see if we recognise the encryption algorithm.
++     */
++
++    cipher = EVP_get_cipherbyobj(pbe2->encryption->algorithm);
++
++    if (!cipher) {
++        EVPerr(EVP_F_PKCS5_V2_PBE_KEYIVGEN, EVP_R_UNSUPPORTED_CIPHER);
++        goto err;
++    }
++
++    /* Fixup cipher based on AlgorithmIdentifier */
++    if (!EVP_CipherInit_ex(ctx, cipher, NULL, NULL, NULL, en_de))
++        goto err;
++    if (EVP_CIPHER_asn1_to_param(ctx, pbe2->encryption->parameter) < 0) {
++        EVPerr(EVP_F_PKCS5_V2_PBE_KEYIVGEN, EVP_R_CIPHER_PARAMETER_ERROR);
++        goto err;
++    }
++    rv = kdf(ctx, pass, passlen, pbe2->keyfunc->parameter, NULL, NULL, en_de);
++ err:
++    PBE2PARAM_free(pbe2);
++    return rv;
++}
++
++int PKCS5_v2_PBKDF2_keyivgen(EVP_CIPHER_CTX *ctx, const char *pass,
++                             int passlen, ASN1_TYPE *param,
++                             const EVP_CIPHER *c, const EVP_MD *md, int en_de)
++{
++    unsigned char *salt, key[EVP_MAX_KEY_LENGTH];
++    int saltlen, iter;
++    int rv = 0;
++    unsigned int keylen = 0;
++    int prf_nid, hmac_md_nid;
++    PBKDF2PARAM *kdf = NULL;
++    const EVP_MD *prfmd;
++
++    if (EVP_CIPHER_CTX_cipher(ctx) == NULL) {
++        EVPerr(EVP_F_PKCS5_V2_PBKDF2_KEYIVGEN, EVP_R_NO_CIPHER_SET);
++        goto err;
++    }
++    keylen = EVP_CIPHER_CTX_key_length(ctx);
++    OPENSSL_assert(keylen <= sizeof key);
++
++    /* Decode parameter */
++
++    kdf = ASN1_TYPE_unpack_sequence(ASN1_ITEM_rptr(PBKDF2PARAM), param);
++
++    if (kdf == NULL) {
++        EVPerr(EVP_F_PKCS5_V2_PBKDF2_KEYIVGEN, EVP_R_DECODE_ERROR);
++        goto err;
++    }
++
++    keylen = EVP_CIPHER_CTX_key_length(ctx);
++
++    /* Now check the parameters of the kdf */
++
++    if (kdf->keylength && (ASN1_INTEGER_get(kdf->keylength) != (int)keylen)) {
++        EVPerr(EVP_F_PKCS5_V2_PBKDF2_KEYIVGEN, EVP_R_UNSUPPORTED_KEYLENGTH);
++        goto err;
++    }
++
++    if (kdf->prf)
++        prf_nid = OBJ_obj2nid(kdf->prf->algorithm);
++    else
++        prf_nid = NID_hmacWithSHA1;
++
++    if (!EVP_PBE_find(EVP_PBE_TYPE_PRF, prf_nid, NULL, &hmac_md_nid, 0)) {
++        EVPerr(EVP_F_PKCS5_V2_PBKDF2_KEYIVGEN, EVP_R_UNSUPPORTED_PRF);
++        goto err;
++    }
++
++    prfmd = EVP_get_digestbynid(hmac_md_nid);
++    if (prfmd == NULL) {
++        EVPerr(EVP_F_PKCS5_V2_PBKDF2_KEYIVGEN, EVP_R_UNSUPPORTED_PRF);
++        goto err;
++    }
++
++    if (kdf->salt->type != V_ASN1_OCTET_STRING) {
++        EVPerr(EVP_F_PKCS5_V2_PBKDF2_KEYIVGEN, EVP_R_UNSUPPORTED_SALT_TYPE);
++        goto err;
++    }
++
++    /* it seems that its all OK */
++    salt = kdf->salt->value.octet_string->data;
++    saltlen = kdf->salt->value.octet_string->length;
++    iter = ASN1_INTEGER_get(kdf->iter);
++    if (!PKCS5_PBKDF2_HMAC(pass, passlen, salt, saltlen, iter, prfmd,
++                           keylen, key))
++        goto err;
++    rv = EVP_CipherInit_ex(ctx, NULL, NULL, key, NULL, en_de);
++ err:
++    OPENSSL_cleanse(key, keylen);
++    PBKDF2PARAM_free(kdf);
++    return rv;
++}
++
++# ifdef OPENSSL_DEBUG_PKCS5V2
++static void h__dump(const unsigned char *p, int len)
++{
++    for (; len--; p++)
++        fprintf(stderr, "%02X ", *p);
++    fprintf(stderr, "\n");
++}
++# endif
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/evp/p_dec.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/evp/p_dec.c
+new file mode 100644
+index 0000000..6bec406
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/evp/p_dec.c
+@@ -0,0 +1,36 @@
++/*
++ * Copyright 1995-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include "internal/cryptlib.h"
++#include 
++#include 
++#include 
++#include 
++
++int EVP_PKEY_decrypt_old(unsigned char *key, const unsigned char *ek, int ekl,
++                         EVP_PKEY *priv)
++{
++    int ret = -1;
++
++#ifndef OPENSSL_NO_RSA
++    if (EVP_PKEY_id(priv) != EVP_PKEY_RSA) {
++#endif
++        EVPerr(EVP_F_EVP_PKEY_DECRYPT_OLD, EVP_R_PUBLIC_KEY_NOT_RSA);
++#ifndef OPENSSL_NO_RSA
++        goto err;
++    }
++
++    ret =
++        RSA_private_decrypt(ekl, ek, key, EVP_PKEY_get0_RSA(priv),
++                            RSA_PKCS1_PADDING);
++ err:
++#endif
++    return (ret);
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/evp/p_enc.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/evp/p_enc.c
+new file mode 100644
+index 0000000..3277fbb
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/evp/p_enc.c
+@@ -0,0 +1,35 @@
++/*
++ * Copyright 1995-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include "internal/cryptlib.h"
++#include 
++#include 
++#include 
++#include 
++
++int EVP_PKEY_encrypt_old(unsigned char *ek, const unsigned char *key,
++                         int key_len, EVP_PKEY *pubk)
++{
++    int ret = 0;
++
++#ifndef OPENSSL_NO_RSA
++    if (EVP_PKEY_id(pubk) != EVP_PKEY_RSA) {
++#endif
++        EVPerr(EVP_F_EVP_PKEY_ENCRYPT_OLD, EVP_R_PUBLIC_KEY_NOT_RSA);
++#ifndef OPENSSL_NO_RSA
++        goto err;
++    }
++    ret =
++        RSA_public_encrypt(key_len, key, ek, EVP_PKEY_get0_RSA(pubk),
++                           RSA_PKCS1_PADDING);
++ err:
++#endif
++    return (ret);
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/evp/p_lib.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/evp/p_lib.c
+new file mode 100644
+index 0000000..9828620
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/evp/p_lib.c
+@@ -0,0 +1,484 @@
++/*
++ * Copyright 1995-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include "internal/cryptlib.h"
++#include 
++#include 
++#include 
++#include 
++#include 
++#include 
++#include 
++#include 
++#include 
++
++#include "internal/asn1_int.h"
++#include "internal/evp_int.h"
++
++static void EVP_PKEY_free_it(EVP_PKEY *x);
++
++int EVP_PKEY_bits(const EVP_PKEY *pkey)
++{
++    if (pkey && pkey->ameth && pkey->ameth->pkey_bits)
++        return pkey->ameth->pkey_bits(pkey);
++    return 0;
++}
++
++int EVP_PKEY_security_bits(const EVP_PKEY *pkey)
++{
++    if (pkey == NULL)
++        return 0;
++    if (!pkey->ameth || !pkey->ameth->pkey_security_bits)
++        return -2;
++    return pkey->ameth->pkey_security_bits(pkey);
++}
++
++int EVP_PKEY_size(EVP_PKEY *pkey)
++{
++    if (pkey && pkey->ameth && pkey->ameth->pkey_size)
++        return pkey->ameth->pkey_size(pkey);
++    return 0;
++}
++
++int EVP_PKEY_save_parameters(EVP_PKEY *pkey, int mode)
++{
++#ifndef OPENSSL_NO_DSA
++    if (pkey->type == EVP_PKEY_DSA) {
++        int ret = pkey->save_parameters;
++
++        if (mode >= 0)
++            pkey->save_parameters = mode;
++        return (ret);
++    }
++#endif
++#ifndef OPENSSL_NO_EC
++    if (pkey->type == EVP_PKEY_EC) {
++        int ret = pkey->save_parameters;
++
++        if (mode >= 0)
++            pkey->save_parameters = mode;
++        return (ret);
++    }
++#endif
++    return (0);
++}
++
++int EVP_PKEY_copy_parameters(EVP_PKEY *to, const EVP_PKEY *from)
++{
++    if (to->type == EVP_PKEY_NONE) {
++        if (EVP_PKEY_set_type(to, from->type) == 0)
++            return 0;
++    } else if (to->type != from->type) {
++        EVPerr(EVP_F_EVP_PKEY_COPY_PARAMETERS, EVP_R_DIFFERENT_KEY_TYPES);
++        goto err;
++    }
++
++    if (EVP_PKEY_missing_parameters(from)) {
++        EVPerr(EVP_F_EVP_PKEY_COPY_PARAMETERS, EVP_R_MISSING_PARAMETERS);
++        goto err;
++    }
++
++    if (!EVP_PKEY_missing_parameters(to)) {
++        if (EVP_PKEY_cmp_parameters(to, from) == 1)
++            return 1;
++        EVPerr(EVP_F_EVP_PKEY_COPY_PARAMETERS, EVP_R_DIFFERENT_PARAMETERS);
++        return 0;
++    }
++
++    if (from->ameth && from->ameth->param_copy)
++        return from->ameth->param_copy(to, from);
++ err:
++    return 0;
++}
++
++int EVP_PKEY_missing_parameters(const EVP_PKEY *pkey)
++{
++    if (pkey->ameth && pkey->ameth->param_missing)
++        return pkey->ameth->param_missing(pkey);
++    return 0;
++}
++
++int EVP_PKEY_cmp_parameters(const EVP_PKEY *a, const EVP_PKEY *b)
++{
++    if (a->type != b->type)
++        return -1;
++    if (a->ameth && a->ameth->param_cmp)
++        return a->ameth->param_cmp(a, b);
++    return -2;
++}
++
++int EVP_PKEY_cmp(const EVP_PKEY *a, const EVP_PKEY *b)
++{
++    if (a->type != b->type)
++        return -1;
++
++    if (a->ameth) {
++        int ret;
++        /* Compare parameters if the algorithm has them */
++        if (a->ameth->param_cmp) {
++            ret = a->ameth->param_cmp(a, b);
++            if (ret <= 0)
++                return ret;
++        }
++
++        if (a->ameth->pub_cmp)
++            return a->ameth->pub_cmp(a, b);
++    }
++
++    return -2;
++}
++
++EVP_PKEY *EVP_PKEY_new(void)
++{
++    EVP_PKEY *ret = OPENSSL_zalloc(sizeof(*ret));
++
++    if (ret == NULL) {
++        EVPerr(EVP_F_EVP_PKEY_NEW, ERR_R_MALLOC_FAILURE);
++        return NULL;
++    }
++    ret->type = EVP_PKEY_NONE;
++    ret->save_type = EVP_PKEY_NONE;
++    ret->references = 1;
++    ret->save_parameters = 1;
++    ret->lock = CRYPTO_THREAD_lock_new();
++    if (ret->lock == NULL) {
++        EVPerr(EVP_F_EVP_PKEY_NEW, ERR_R_MALLOC_FAILURE);
++        OPENSSL_free(ret);
++        return NULL;
++    }
++    return ret;
++}
++
++int EVP_PKEY_up_ref(EVP_PKEY *pkey)
++{
++    int i;
++
++    if (CRYPTO_atomic_add(&pkey->references, 1, &i, pkey->lock) <= 0)
++        return 0;
++
++    REF_PRINT_COUNT("EVP_PKEY", pkey);
++    REF_ASSERT_ISNT(i < 2);
++    return ((i > 1) ? 1 : 0);
++}
++
++/*
++ * Setup a public key ASN1 method and ENGINE from a NID or a string. If pkey
++ * is NULL just return 1 or 0 if the algorithm exists.
++ */
++
++static int pkey_set_type(EVP_PKEY *pkey, int type, const char *str, int len)
++{
++    const EVP_PKEY_ASN1_METHOD *ameth;
++    ENGINE *e = NULL;
++    if (pkey) {
++        if (pkey->pkey.ptr)
++            EVP_PKEY_free_it(pkey);
++        /*
++         * If key type matches and a method exists then this lookup has
++         * succeeded once so just indicate success.
++         */
++        if ((type == pkey->save_type) && pkey->ameth)
++            return 1;
++#ifndef OPENSSL_NO_ENGINE
++        /* If we have an ENGINE release it */
++        ENGINE_finish(pkey->engine);
++        pkey->engine = NULL;
++#endif
++    }
++    if (str)
++        ameth = EVP_PKEY_asn1_find_str(&e, str, len);
++    else
++        ameth = EVP_PKEY_asn1_find(&e, type);
++#ifndef OPENSSL_NO_ENGINE
++    if (pkey == NULL)
++        ENGINE_finish(e);
++#endif
++    if (ameth == NULL) {
++        EVPerr(EVP_F_PKEY_SET_TYPE, EVP_R_UNSUPPORTED_ALGORITHM);
++        return 0;
++    }
++    if (pkey) {
++        pkey->ameth = ameth;
++        pkey->engine = e;
++
++        pkey->type = pkey->ameth->pkey_id;
++        pkey->save_type = type;
++    }
++    return 1;
++}
++
++int EVP_PKEY_set_type(EVP_PKEY *pkey, int type)
++{
++    return pkey_set_type(pkey, type, NULL, -1);
++}
++
++int EVP_PKEY_set_type_str(EVP_PKEY *pkey, const char *str, int len)
++{
++    return pkey_set_type(pkey, EVP_PKEY_NONE, str, len);
++}
++
++int EVP_PKEY_assign(EVP_PKEY *pkey, int type, void *key)
++{
++    if (pkey == NULL || !EVP_PKEY_set_type(pkey, type))
++        return 0;
++    pkey->pkey.ptr = key;
++    return (key != NULL);
++}
++
++void *EVP_PKEY_get0(const EVP_PKEY *pkey)
++{
++    return pkey->pkey.ptr;
++}
++
++const unsigned char *EVP_PKEY_get0_hmac(const EVP_PKEY *pkey, size_t *len)
++{
++    ASN1_OCTET_STRING *os = NULL;
++    if (pkey->type != EVP_PKEY_HMAC) {
++        EVPerr(EVP_F_EVP_PKEY_GET0_HMAC, EVP_R_EXPECTING_AN_HMAC_KEY);
++        return NULL;
++    }
++    os = EVP_PKEY_get0(pkey);
++    *len = os->length;
++    return os->data;
++}
++
++#ifndef OPENSSL_NO_RSA
++int EVP_PKEY_set1_RSA(EVP_PKEY *pkey, RSA *key)
++{
++    int ret = EVP_PKEY_assign_RSA(pkey, key);
++    if (ret)
++        RSA_up_ref(key);
++    return ret;
++}
++
++RSA *EVP_PKEY_get0_RSA(EVP_PKEY *pkey)
++{
++    if (pkey->type != EVP_PKEY_RSA) {
++        EVPerr(EVP_F_EVP_PKEY_GET0_RSA, EVP_R_EXPECTING_AN_RSA_KEY);
++        return NULL;
++    }
++    return pkey->pkey.rsa;
++}
++
++RSA *EVP_PKEY_get1_RSA(EVP_PKEY *pkey)
++{
++    RSA *ret = EVP_PKEY_get0_RSA(pkey);
++    if (ret != NULL)
++        RSA_up_ref(ret);
++    return ret;
++}
++#endif
++
++#ifndef OPENSSL_NO_DSA
++int EVP_PKEY_set1_DSA(EVP_PKEY *pkey, DSA *key)
++{
++    int ret = EVP_PKEY_assign_DSA(pkey, key);
++    if (ret)
++        DSA_up_ref(key);
++    return ret;
++}
++
++DSA *EVP_PKEY_get0_DSA(EVP_PKEY *pkey)
++{
++    if (pkey->type != EVP_PKEY_DSA) {
++        EVPerr(EVP_F_EVP_PKEY_GET0_DSA, EVP_R_EXPECTING_A_DSA_KEY);
++        return NULL;
++    }
++    return pkey->pkey.dsa;
++}
++
++DSA *EVP_PKEY_get1_DSA(EVP_PKEY *pkey)
++{
++    DSA *ret = EVP_PKEY_get0_DSA(pkey);
++    if (ret != NULL)
++        DSA_up_ref(ret);
++    return ret;
++}
++#endif
++
++#ifndef OPENSSL_NO_EC
++
++int EVP_PKEY_set1_EC_KEY(EVP_PKEY *pkey, EC_KEY *key)
++{
++    int ret = EVP_PKEY_assign_EC_KEY(pkey, key);
++    if (ret)
++        EC_KEY_up_ref(key);
++    return ret;
++}
++
++EC_KEY *EVP_PKEY_get0_EC_KEY(EVP_PKEY *pkey)
++{
++    if (pkey->type != EVP_PKEY_EC) {
++        EVPerr(EVP_F_EVP_PKEY_GET0_EC_KEY, EVP_R_EXPECTING_A_EC_KEY);
++        return NULL;
++    }
++    return pkey->pkey.ec;
++}
++
++EC_KEY *EVP_PKEY_get1_EC_KEY(EVP_PKEY *pkey)
++{
++    EC_KEY *ret = EVP_PKEY_get0_EC_KEY(pkey);
++    if (ret != NULL)
++        EC_KEY_up_ref(ret);
++    return ret;
++}
++#endif
++
++#ifndef OPENSSL_NO_DH
++
++int EVP_PKEY_set1_DH(EVP_PKEY *pkey, DH *key)
++{
++    int ret = EVP_PKEY_assign_DH(pkey, key);
++    if (ret)
++        DH_up_ref(key);
++    return ret;
++}
++
++DH *EVP_PKEY_get0_DH(EVP_PKEY *pkey)
++{
++    if (pkey->type != EVP_PKEY_DH && pkey->type != EVP_PKEY_DHX) {
++        EVPerr(EVP_F_EVP_PKEY_GET0_DH, EVP_R_EXPECTING_A_DH_KEY);
++        return NULL;
++    }
++    return pkey->pkey.dh;
++}
++
++DH *EVP_PKEY_get1_DH(EVP_PKEY *pkey)
++{
++    DH *ret = EVP_PKEY_get0_DH(pkey);
++    if (ret != NULL)
++        DH_up_ref(ret);
++    return ret;
++}
++#endif
++
++int EVP_PKEY_type(int type)
++{
++    int ret;
++    const EVP_PKEY_ASN1_METHOD *ameth;
++    ENGINE *e;
++    ameth = EVP_PKEY_asn1_find(&e, type);
++    if (ameth)
++        ret = ameth->pkey_id;
++    else
++        ret = NID_undef;
++#ifndef OPENSSL_NO_ENGINE
++    ENGINE_finish(e);
++#endif
++    return ret;
++}
++
++int EVP_PKEY_id(const EVP_PKEY *pkey)
++{
++    return pkey->type;
++}
++
++int EVP_PKEY_base_id(const EVP_PKEY *pkey)
++{
++    return EVP_PKEY_type(pkey->type);
++}
++
++void EVP_PKEY_free(EVP_PKEY *x)
++{
++    int i;
++
++    if (x == NULL)
++        return;
++
++    CRYPTO_atomic_add(&x->references, -1, &i, x->lock);
++    REF_PRINT_COUNT("EVP_PKEY", x);
++    if (i > 0)
++        return;
++    REF_ASSERT_ISNT(i < 0);
++    EVP_PKEY_free_it(x);
++    CRYPTO_THREAD_lock_free(x->lock);
++    sk_X509_ATTRIBUTE_pop_free(x->attributes, X509_ATTRIBUTE_free);
++    OPENSSL_free(x);
++}
++
++static void EVP_PKEY_free_it(EVP_PKEY *x)
++{
++    /* internal function; x is never NULL */
++    if (x->ameth && x->ameth->pkey_free) {
++        x->ameth->pkey_free(x);
++        x->pkey.ptr = NULL;
++    }
++#ifndef OPENSSL_NO_ENGINE
++    ENGINE_finish(x->engine);
++    x->engine = NULL;
++#endif
++}
++
++static int unsup_alg(BIO *out, const EVP_PKEY *pkey, int indent,
++                     const char *kstr)
++{
++    BIO_indent(out, indent, 128);
++    BIO_printf(out, "%s algorithm \"%s\" unsupported\n",
++               kstr, OBJ_nid2ln(pkey->type));
++    return 1;
++}
++
++int EVP_PKEY_print_public(BIO *out, const EVP_PKEY *pkey,
++                          int indent, ASN1_PCTX *pctx)
++{
++    if (pkey->ameth && pkey->ameth->pub_print)
++        return pkey->ameth->pub_print(out, pkey, indent, pctx);
++
++    return unsup_alg(out, pkey, indent, "Public Key");
++}
++
++int EVP_PKEY_print_private(BIO *out, const EVP_PKEY *pkey,
++                           int indent, ASN1_PCTX *pctx)
++{
++    if (pkey->ameth && pkey->ameth->priv_print)
++        return pkey->ameth->priv_print(out, pkey, indent, pctx);
++
++    return unsup_alg(out, pkey, indent, "Private Key");
++}
++
++int EVP_PKEY_print_params(BIO *out, const EVP_PKEY *pkey,
++                          int indent, ASN1_PCTX *pctx)
++{
++    if (pkey->ameth && pkey->ameth->param_print)
++        return pkey->ameth->param_print(out, pkey, indent, pctx);
++    return unsup_alg(out, pkey, indent, "Parameters");
++}
++
++static int evp_pkey_asn1_ctrl(EVP_PKEY *pkey, int op, int arg1, void *arg2)
++{
++    if (pkey->ameth == NULL || pkey->ameth->pkey_ctrl == NULL)
++        return -2;
++    return pkey->ameth->pkey_ctrl(pkey, op, arg1, arg2);
++}
++
++int EVP_PKEY_get_default_digest_nid(EVP_PKEY *pkey, int *pnid)
++{
++    return evp_pkey_asn1_ctrl(pkey, ASN1_PKEY_CTRL_DEFAULT_MD_NID, 0, pnid);
++}
++
++int EVP_PKEY_set1_tls_encodedpoint(EVP_PKEY *pkey,
++                               const unsigned char *pt, size_t ptlen)
++{
++    if (ptlen > INT_MAX)
++        return 0;
++    if (evp_pkey_asn1_ctrl(pkey, ASN1_PKEY_CTRL_SET1_TLS_ENCPT, ptlen,
++                           (void *)pt) <= 0)
++        return 0;
++    return 1;
++}
++
++size_t EVP_PKEY_get1_tls_encodedpoint(EVP_PKEY *pkey, unsigned char **ppt)
++{
++    int rv;
++    rv = evp_pkey_asn1_ctrl(pkey, ASN1_PKEY_CTRL_GET1_TLS_ENCPT, 0, ppt);
++    if (rv <= 0)
++        return 0;
++    return rv;
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/evp/p_open.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/evp/p_open.c
+new file mode 100644
+index 0000000..b65bc74
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/evp/p_open.c
+@@ -0,0 +1,73 @@
++/*
++ * Copyright 1995-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include "internal/cryptlib.h"
++#ifdef OPENSSL_NO_RSA
++NON_EMPTY_TRANSLATION_UNIT
++#else
++
++# include 
++# include 
++# include 
++# include 
++# include 
++
++int EVP_OpenInit(EVP_CIPHER_CTX *ctx, const EVP_CIPHER *type,
++                 const unsigned char *ek, int ekl, const unsigned char *iv,
++                 EVP_PKEY *priv)
++{
++    unsigned char *key = NULL;
++    int i, size = 0, ret = 0;
++
++    if (type) {
++        EVP_CIPHER_CTX_reset(ctx);
++        if (!EVP_DecryptInit_ex(ctx, type, NULL, NULL, NULL))
++            return 0;
++    }
++
++    if (!priv)
++        return 1;
++
++    if (EVP_PKEY_id(priv) != EVP_PKEY_RSA) {
++        EVPerr(EVP_F_EVP_OPENINIT, EVP_R_PUBLIC_KEY_NOT_RSA);
++        goto err;
++    }
++
++    size = EVP_PKEY_size(priv);
++    key = OPENSSL_malloc(size + 2);
++    if (key == NULL) {
++        /* ERROR */
++        EVPerr(EVP_F_EVP_OPENINIT, ERR_R_MALLOC_FAILURE);
++        goto err;
++    }
++
++    i = EVP_PKEY_decrypt_old(key, ek, ekl, priv);
++    if ((i <= 0) || !EVP_CIPHER_CTX_set_key_length(ctx, i)) {
++        /* ERROR */
++        goto err;
++    }
++    if (!EVP_DecryptInit_ex(ctx, NULL, NULL, key, iv))
++        goto err;
++
++    ret = 1;
++ err:
++    OPENSSL_clear_free(key, size);
++    return (ret);
++}
++
++int EVP_OpenFinal(EVP_CIPHER_CTX *ctx, unsigned char *out, int *outl)
++{
++    int i;
++
++    i = EVP_DecryptFinal_ex(ctx, out, outl);
++    if (i)
++        i = EVP_DecryptInit_ex(ctx, NULL, NULL, NULL, NULL);
++    return (i);
++}
++#endif
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/evp/p_seal.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/evp/p_seal.c
+new file mode 100644
+index 0000000..faa2464
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/evp/p_seal.c
+@@ -0,0 +1,70 @@
++/*
++ * Copyright 1995-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include "internal/cryptlib.h"
++#include 
++#include 
++#include 
++#include 
++#include 
++
++int EVP_SealInit(EVP_CIPHER_CTX *ctx, const EVP_CIPHER *type,
++                 unsigned char **ek, int *ekl, unsigned char *iv,
++                 EVP_PKEY **pubk, int npubk)
++{
++    unsigned char key[EVP_MAX_KEY_LENGTH];
++    int i;
++
++    if (type) {
++        EVP_CIPHER_CTX_reset(ctx);
++        if (!EVP_EncryptInit_ex(ctx, type, NULL, NULL, NULL))
++            return 0;
++    }
++    if ((npubk <= 0) || !pubk)
++        return 1;
++    if (EVP_CIPHER_CTX_rand_key(ctx, key) <= 0)
++        return 0;
++    if (EVP_CIPHER_CTX_iv_length(ctx)
++        && RAND_bytes(iv, EVP_CIPHER_CTX_iv_length(ctx)) <= 0)
++        return 0;
++
++    if (!EVP_EncryptInit_ex(ctx, NULL, NULL, key, iv))
++        return 0;
++
++    for (i = 0; i < npubk; i++) {
++        ekl[i] =
++            EVP_PKEY_encrypt_old(ek[i], key, EVP_CIPHER_CTX_key_length(ctx),
++                                 pubk[i]);
++        if (ekl[i] <= 0)
++            return (-1);
++    }
++    return (npubk);
++}
++
++/*- MACRO
++void EVP_SealUpdate(ctx,out,outl,in,inl)
++EVP_CIPHER_CTX *ctx;
++unsigned char *out;
++int *outl;
++unsigned char *in;
++int inl;
++        {
++        EVP_EncryptUpdate(ctx,out,outl,in,inl);
++        }
++*/
++
++int EVP_SealFinal(EVP_CIPHER_CTX *ctx, unsigned char *out, int *outl)
++{
++    int i;
++    i = EVP_EncryptFinal_ex(ctx, out, outl);
++    if (i)
++        i = EVP_EncryptInit_ex(ctx, NULL, NULL, NULL, NULL);
++    return i;
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/evp/p_sign.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/evp/p_sign.c
+new file mode 100644
+index 0000000..6cb442e
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/evp/p_sign.c
+@@ -0,0 +1,61 @@
++/*
++ * Copyright 1995-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include "internal/cryptlib.h"
++#include 
++#include 
++#include 
++#include "internal/evp_int.h"
++
++int EVP_SignFinal(EVP_MD_CTX *ctx, unsigned char *sigret,
++                  unsigned int *siglen, EVP_PKEY *pkey)
++{
++    unsigned char m[EVP_MAX_MD_SIZE];
++    unsigned int m_len = 0;
++    int i = 0;
++    size_t sltmp;
++    EVP_PKEY_CTX *pkctx = NULL;
++
++    *siglen = 0;
++    if (EVP_MD_CTX_test_flags(ctx, EVP_MD_CTX_FLAG_FINALISE)) {
++        if (!EVP_DigestFinal_ex(ctx, m, &m_len))
++            goto err;
++    } else {
++        int rv = 0;
++        EVP_MD_CTX *tmp_ctx = EVP_MD_CTX_new();
++        if (tmp_ctx == NULL) {
++            EVPerr(EVP_F_EVP_SIGNFINAL, ERR_R_MALLOC_FAILURE);
++            return 0;
++        }
++        rv = EVP_MD_CTX_copy_ex(tmp_ctx, ctx);
++        if (rv)
++            rv = EVP_DigestFinal_ex(tmp_ctx, m, &m_len);
++        EVP_MD_CTX_free(tmp_ctx);
++        if (!rv)
++            return 0;
++    }
++
++    sltmp = (size_t)EVP_PKEY_size(pkey);
++    i = 0;
++    pkctx = EVP_PKEY_CTX_new(pkey, NULL);
++    if (pkctx == NULL)
++        goto err;
++    if (EVP_PKEY_sign_init(pkctx) <= 0)
++        goto err;
++    if (EVP_PKEY_CTX_set_signature_md(pkctx, EVP_MD_CTX_md(ctx)) <= 0)
++        goto err;
++    if (EVP_PKEY_sign(pkctx, sigret, &sltmp, m, m_len) <= 0)
++        goto err;
++    *siglen = sltmp;
++    i = 1;
++ err:
++    EVP_PKEY_CTX_free(pkctx);
++    return i;
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/evp/p_verify.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/evp/p_verify.c
+new file mode 100644
+index 0000000..6e8c565
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/evp/p_verify.c
+@@ -0,0 +1,55 @@
++/*
++ * Copyright 1995-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include "internal/cryptlib.h"
++#include 
++#include 
++#include 
++#include "internal/evp_int.h"
++
++int EVP_VerifyFinal(EVP_MD_CTX *ctx, const unsigned char *sigbuf,
++                    unsigned int siglen, EVP_PKEY *pkey)
++{
++    unsigned char m[EVP_MAX_MD_SIZE];
++    unsigned int m_len = 0;
++    int i = 0;
++    EVP_PKEY_CTX *pkctx = NULL;
++
++    if (EVP_MD_CTX_test_flags(ctx, EVP_MD_CTX_FLAG_FINALISE)) {
++        if (!EVP_DigestFinal_ex(ctx, m, &m_len))
++            goto err;
++    } else {
++        int rv = 0;
++        EVP_MD_CTX *tmp_ctx = EVP_MD_CTX_new();
++        if (tmp_ctx == NULL) {
++            EVPerr(EVP_F_EVP_VERIFYFINAL, ERR_R_MALLOC_FAILURE);
++            return 0;
++        }
++        rv = EVP_MD_CTX_copy_ex(tmp_ctx, ctx);
++        if (rv)
++            rv = EVP_DigestFinal_ex(tmp_ctx, m, &m_len);
++        EVP_MD_CTX_free(tmp_ctx);
++        if (!rv)
++            return 0;
++    }
++
++    i = -1;
++    pkctx = EVP_PKEY_CTX_new(pkey, NULL);
++    if (pkctx == NULL)
++        goto err;
++    if (EVP_PKEY_verify_init(pkctx) <= 0)
++        goto err;
++    if (EVP_PKEY_CTX_set_signature_md(pkctx, EVP_MD_CTX_md(ctx)) <= 0)
++        goto err;
++    i = EVP_PKEY_verify(pkctx, sigbuf, siglen, m, m_len);
++ err:
++    EVP_PKEY_CTX_free(pkctx);
++    return i;
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/evp/pmeth_fn.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/evp/pmeth_fn.c
+new file mode 100644
+index 0000000..eb63801
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/evp/pmeth_fn.c
+@@ -0,0 +1,297 @@
++/*
++ * Copyright 2006-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include 
++#include "internal/cryptlib.h"
++#include 
++#include 
++#include "internal/evp_int.h"
++
++#define M_check_autoarg(ctx, arg, arglen, err) \
++    if (ctx->pmeth->flags & EVP_PKEY_FLAG_AUTOARGLEN) {           \
++        size_t pksize = (size_t)EVP_PKEY_size(ctx->pkey);         \
++                                                                  \
++        if (pksize == 0) {                                        \
++            EVPerr(err, EVP_R_INVALID_KEY); /*ckerr_ignore*/      \
++            return 0;                                             \
++        }                                                         \
++        if (!arg) {                                               \
++            *arglen = pksize;                                     \
++            return 1;                                             \
++        }                                                         \
++        if (*arglen < pksize) {                                   \
++            EVPerr(err, EVP_R_BUFFER_TOO_SMALL); /*ckerr_ignore*/ \
++            return 0;                                             \
++        }                                                         \
++    }
++
++int EVP_PKEY_sign_init(EVP_PKEY_CTX *ctx)
++{
++    int ret;
++    if (!ctx || !ctx->pmeth || !ctx->pmeth->sign) {
++        EVPerr(EVP_F_EVP_PKEY_SIGN_INIT,
++               EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE);
++        return -2;
++    }
++    ctx->operation = EVP_PKEY_OP_SIGN;
++    if (!ctx->pmeth->sign_init)
++        return 1;
++    ret = ctx->pmeth->sign_init(ctx);
++    if (ret <= 0)
++        ctx->operation = EVP_PKEY_OP_UNDEFINED;
++    return ret;
++}
++
++int EVP_PKEY_sign(EVP_PKEY_CTX *ctx,
++                  unsigned char *sig, size_t *siglen,
++                  const unsigned char *tbs, size_t tbslen)
++{
++    if (!ctx || !ctx->pmeth || !ctx->pmeth->sign) {
++        EVPerr(EVP_F_EVP_PKEY_SIGN,
++               EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE);
++        return -2;
++    }
++    if (ctx->operation != EVP_PKEY_OP_SIGN) {
++        EVPerr(EVP_F_EVP_PKEY_SIGN, EVP_R_OPERATON_NOT_INITIALIZED);
++        return -1;
++    }
++    M_check_autoarg(ctx, sig, siglen, EVP_F_EVP_PKEY_SIGN)
++        return ctx->pmeth->sign(ctx, sig, siglen, tbs, tbslen);
++}
++
++int EVP_PKEY_verify_init(EVP_PKEY_CTX *ctx)
++{
++    int ret;
++    if (!ctx || !ctx->pmeth || !ctx->pmeth->verify) {
++        EVPerr(EVP_F_EVP_PKEY_VERIFY_INIT,
++               EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE);
++        return -2;
++    }
++    ctx->operation = EVP_PKEY_OP_VERIFY;
++    if (!ctx->pmeth->verify_init)
++        return 1;
++    ret = ctx->pmeth->verify_init(ctx);
++    if (ret <= 0)
++        ctx->operation = EVP_PKEY_OP_UNDEFINED;
++    return ret;
++}
++
++int EVP_PKEY_verify(EVP_PKEY_CTX *ctx,
++                    const unsigned char *sig, size_t siglen,
++                    const unsigned char *tbs, size_t tbslen)
++{
++    if (!ctx || !ctx->pmeth || !ctx->pmeth->verify) {
++        EVPerr(EVP_F_EVP_PKEY_VERIFY,
++               EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE);
++        return -2;
++    }
++    if (ctx->operation != EVP_PKEY_OP_VERIFY) {
++        EVPerr(EVP_F_EVP_PKEY_VERIFY, EVP_R_OPERATON_NOT_INITIALIZED);
++        return -1;
++    }
++    return ctx->pmeth->verify(ctx, sig, siglen, tbs, tbslen);
++}
++
++int EVP_PKEY_verify_recover_init(EVP_PKEY_CTX *ctx)
++{
++    int ret;
++    if (!ctx || !ctx->pmeth || !ctx->pmeth->verify_recover) {
++        EVPerr(EVP_F_EVP_PKEY_VERIFY_RECOVER_INIT,
++               EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE);
++        return -2;
++    }
++    ctx->operation = EVP_PKEY_OP_VERIFYRECOVER;
++    if (!ctx->pmeth->verify_recover_init)
++        return 1;
++    ret = ctx->pmeth->verify_recover_init(ctx);
++    if (ret <= 0)
++        ctx->operation = EVP_PKEY_OP_UNDEFINED;
++    return ret;
++}
++
++int EVP_PKEY_verify_recover(EVP_PKEY_CTX *ctx,
++                            unsigned char *rout, size_t *routlen,
++                            const unsigned char *sig, size_t siglen)
++{
++    if (!ctx || !ctx->pmeth || !ctx->pmeth->verify_recover) {
++        EVPerr(EVP_F_EVP_PKEY_VERIFY_RECOVER,
++               EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE);
++        return -2;
++    }
++    if (ctx->operation != EVP_PKEY_OP_VERIFYRECOVER) {
++        EVPerr(EVP_F_EVP_PKEY_VERIFY_RECOVER, EVP_R_OPERATON_NOT_INITIALIZED);
++        return -1;
++    }
++    M_check_autoarg(ctx, rout, routlen, EVP_F_EVP_PKEY_VERIFY_RECOVER)
++        return ctx->pmeth->verify_recover(ctx, rout, routlen, sig, siglen);
++}
++
++int EVP_PKEY_encrypt_init(EVP_PKEY_CTX *ctx)
++{
++    int ret;
++    if (!ctx || !ctx->pmeth || !ctx->pmeth->encrypt) {
++        EVPerr(EVP_F_EVP_PKEY_ENCRYPT_INIT,
++               EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE);
++        return -2;
++    }
++    ctx->operation = EVP_PKEY_OP_ENCRYPT;
++    if (!ctx->pmeth->encrypt_init)
++        return 1;
++    ret = ctx->pmeth->encrypt_init(ctx);
++    if (ret <= 0)
++        ctx->operation = EVP_PKEY_OP_UNDEFINED;
++    return ret;
++}
++
++int EVP_PKEY_encrypt(EVP_PKEY_CTX *ctx,
++                     unsigned char *out, size_t *outlen,
++                     const unsigned char *in, size_t inlen)
++{
++    if (!ctx || !ctx->pmeth || !ctx->pmeth->encrypt) {
++        EVPerr(EVP_F_EVP_PKEY_ENCRYPT,
++               EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE);
++        return -2;
++    }
++    if (ctx->operation != EVP_PKEY_OP_ENCRYPT) {
++        EVPerr(EVP_F_EVP_PKEY_ENCRYPT, EVP_R_OPERATON_NOT_INITIALIZED);
++        return -1;
++    }
++    M_check_autoarg(ctx, out, outlen, EVP_F_EVP_PKEY_ENCRYPT)
++        return ctx->pmeth->encrypt(ctx, out, outlen, in, inlen);
++}
++
++int EVP_PKEY_decrypt_init(EVP_PKEY_CTX *ctx)
++{
++    int ret;
++    if (!ctx || !ctx->pmeth || !ctx->pmeth->decrypt) {
++        EVPerr(EVP_F_EVP_PKEY_DECRYPT_INIT,
++               EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE);
++        return -2;
++    }
++    ctx->operation = EVP_PKEY_OP_DECRYPT;
++    if (!ctx->pmeth->decrypt_init)
++        return 1;
++    ret = ctx->pmeth->decrypt_init(ctx);
++    if (ret <= 0)
++        ctx->operation = EVP_PKEY_OP_UNDEFINED;
++    return ret;
++}
++
++int EVP_PKEY_decrypt(EVP_PKEY_CTX *ctx,
++                     unsigned char *out, size_t *outlen,
++                     const unsigned char *in, size_t inlen)
++{
++    if (!ctx || !ctx->pmeth || !ctx->pmeth->decrypt) {
++        EVPerr(EVP_F_EVP_PKEY_DECRYPT,
++               EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE);
++        return -2;
++    }
++    if (ctx->operation != EVP_PKEY_OP_DECRYPT) {
++        EVPerr(EVP_F_EVP_PKEY_DECRYPT, EVP_R_OPERATON_NOT_INITIALIZED);
++        return -1;
++    }
++    M_check_autoarg(ctx, out, outlen, EVP_F_EVP_PKEY_DECRYPT)
++        return ctx->pmeth->decrypt(ctx, out, outlen, in, inlen);
++}
++
++int EVP_PKEY_derive_init(EVP_PKEY_CTX *ctx)
++{
++    int ret;
++    if (!ctx || !ctx->pmeth || !ctx->pmeth->derive) {
++        EVPerr(EVP_F_EVP_PKEY_DERIVE_INIT,
++               EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE);
++        return -2;
++    }
++    ctx->operation = EVP_PKEY_OP_DERIVE;
++    if (!ctx->pmeth->derive_init)
++        return 1;
++    ret = ctx->pmeth->derive_init(ctx);
++    if (ret <= 0)
++        ctx->operation = EVP_PKEY_OP_UNDEFINED;
++    return ret;
++}
++
++int EVP_PKEY_derive_set_peer(EVP_PKEY_CTX *ctx, EVP_PKEY *peer)
++{
++    int ret;
++    if (!ctx || !ctx->pmeth
++        || !(ctx->pmeth->derive || ctx->pmeth->encrypt || ctx->pmeth->decrypt)
++        || !ctx->pmeth->ctrl) {
++        EVPerr(EVP_F_EVP_PKEY_DERIVE_SET_PEER,
++               EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE);
++        return -2;
++    }
++    if (ctx->operation != EVP_PKEY_OP_DERIVE
++        && ctx->operation != EVP_PKEY_OP_ENCRYPT
++        && ctx->operation != EVP_PKEY_OP_DECRYPT) {
++        EVPerr(EVP_F_EVP_PKEY_DERIVE_SET_PEER,
++               EVP_R_OPERATON_NOT_INITIALIZED);
++        return -1;
++    }
++
++    ret = ctx->pmeth->ctrl(ctx, EVP_PKEY_CTRL_PEER_KEY, 0, peer);
++
++    if (ret <= 0)
++        return ret;
++
++    if (ret == 2)
++        return 1;
++
++    if (!ctx->pkey) {
++        EVPerr(EVP_F_EVP_PKEY_DERIVE_SET_PEER, EVP_R_NO_KEY_SET);
++        return -1;
++    }
++
++    if (ctx->pkey->type != peer->type) {
++        EVPerr(EVP_F_EVP_PKEY_DERIVE_SET_PEER, EVP_R_DIFFERENT_KEY_TYPES);
++        return -1;
++    }
++
++    /*
++     * ran@cryptocom.ru: For clarity.  The error is if parameters in peer are
++     * present (!missing) but don't match.  EVP_PKEY_cmp_parameters may return
++     * 1 (match), 0 (don't match) and -2 (comparison is not defined).  -1
++     * (different key types) is impossible here because it is checked earlier.
++     * -2 is OK for us here, as well as 1, so we can check for 0 only.
++     */
++    if (!EVP_PKEY_missing_parameters(peer) &&
++        !EVP_PKEY_cmp_parameters(ctx->pkey, peer)) {
++        EVPerr(EVP_F_EVP_PKEY_DERIVE_SET_PEER, EVP_R_DIFFERENT_PARAMETERS);
++        return -1;
++    }
++
++    EVP_PKEY_free(ctx->peerkey);
++    ctx->peerkey = peer;
++
++    ret = ctx->pmeth->ctrl(ctx, EVP_PKEY_CTRL_PEER_KEY, 1, peer);
++
++    if (ret <= 0) {
++        ctx->peerkey = NULL;
++        return ret;
++    }
++
++    EVP_PKEY_up_ref(peer);
++    return 1;
++}
++
++int EVP_PKEY_derive(EVP_PKEY_CTX *ctx, unsigned char *key, size_t *pkeylen)
++{
++    if (!ctx || !ctx->pmeth || !ctx->pmeth->derive) {
++        EVPerr(EVP_F_EVP_PKEY_DERIVE,
++               EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE);
++        return -2;
++    }
++    if (ctx->operation != EVP_PKEY_OP_DERIVE) {
++        EVPerr(EVP_F_EVP_PKEY_DERIVE, EVP_R_OPERATON_NOT_INITIALIZED);
++        return -1;
++    }
++    M_check_autoarg(ctx, key, pkeylen, EVP_F_EVP_PKEY_DERIVE)
++        return ctx->pmeth->derive(ctx, key, pkeylen);
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/evp/pmeth_gn.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/evp/pmeth_gn.c
+new file mode 100644
+index 0000000..6adc3a9
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/evp/pmeth_gn.c
+@@ -0,0 +1,169 @@
++/*
++ * Copyright 2006-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include 
++#include "internal/cryptlib.h"
++#include 
++#include 
++#include "internal/bn_int.h"
++#include "internal/evp_int.h"
++
++int EVP_PKEY_paramgen_init(EVP_PKEY_CTX *ctx)
++{
++    int ret;
++    if (!ctx || !ctx->pmeth || !ctx->pmeth->paramgen) {
++        EVPerr(EVP_F_EVP_PKEY_PARAMGEN_INIT,
++               EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE);
++        return -2;
++    }
++    ctx->operation = EVP_PKEY_OP_PARAMGEN;
++    if (!ctx->pmeth->paramgen_init)
++        return 1;
++    ret = ctx->pmeth->paramgen_init(ctx);
++    if (ret <= 0)
++        ctx->operation = EVP_PKEY_OP_UNDEFINED;
++    return ret;
++}
++
++int EVP_PKEY_paramgen(EVP_PKEY_CTX *ctx, EVP_PKEY **ppkey)
++{
++    int ret;
++    if (!ctx || !ctx->pmeth || !ctx->pmeth->paramgen) {
++        EVPerr(EVP_F_EVP_PKEY_PARAMGEN,
++               EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE);
++        return -2;
++    }
++
++    if (ctx->operation != EVP_PKEY_OP_PARAMGEN) {
++        EVPerr(EVP_F_EVP_PKEY_PARAMGEN, EVP_R_OPERATON_NOT_INITIALIZED);
++        return -1;
++    }
++
++    if (ppkey == NULL)
++        return -1;
++
++    if (*ppkey == NULL)
++        *ppkey = EVP_PKEY_new();
++
++    if (*ppkey == NULL) {
++        EVPerr(EVP_F_EVP_PKEY_PARAMGEN, ERR_R_MALLOC_FAILURE);
++        return -1;
++    }
++
++    ret = ctx->pmeth->paramgen(ctx, *ppkey);
++    if (ret <= 0) {
++        EVP_PKEY_free(*ppkey);
++        *ppkey = NULL;
++    }
++    return ret;
++}
++
++int EVP_PKEY_keygen_init(EVP_PKEY_CTX *ctx)
++{
++    int ret;
++    if (!ctx || !ctx->pmeth || !ctx->pmeth->keygen) {
++        EVPerr(EVP_F_EVP_PKEY_KEYGEN_INIT,
++               EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE);
++        return -2;
++    }
++    ctx->operation = EVP_PKEY_OP_KEYGEN;
++    if (!ctx->pmeth->keygen_init)
++        return 1;
++    ret = ctx->pmeth->keygen_init(ctx);
++    if (ret <= 0)
++        ctx->operation = EVP_PKEY_OP_UNDEFINED;
++    return ret;
++}
++
++int EVP_PKEY_keygen(EVP_PKEY_CTX *ctx, EVP_PKEY **ppkey)
++{
++    int ret;
++
++    if (!ctx || !ctx->pmeth || !ctx->pmeth->keygen) {
++        EVPerr(EVP_F_EVP_PKEY_KEYGEN,
++               EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE);
++        return -2;
++    }
++    if (ctx->operation != EVP_PKEY_OP_KEYGEN) {
++        EVPerr(EVP_F_EVP_PKEY_KEYGEN, EVP_R_OPERATON_NOT_INITIALIZED);
++        return -1;
++    }
++
++    if (ppkey == NULL)
++        return -1;
++
++    if (*ppkey == NULL)
++        *ppkey = EVP_PKEY_new();
++    if (*ppkey == NULL)
++        return -1;
++
++    ret = ctx->pmeth->keygen(ctx, *ppkey);
++    if (ret <= 0) {
++        EVP_PKEY_free(*ppkey);
++        *ppkey = NULL;
++    }
++    return ret;
++}
++
++void EVP_PKEY_CTX_set_cb(EVP_PKEY_CTX *ctx, EVP_PKEY_gen_cb *cb)
++{
++    ctx->pkey_gencb = cb;
++}
++
++EVP_PKEY_gen_cb *EVP_PKEY_CTX_get_cb(EVP_PKEY_CTX *ctx)
++{
++    return ctx->pkey_gencb;
++}
++
++/*
++ * "translation callback" to call EVP_PKEY_CTX callbacks using BN_GENCB style
++ * callbacks.
++ */
++
++static int trans_cb(int a, int b, BN_GENCB *gcb)
++{
++    EVP_PKEY_CTX *ctx = BN_GENCB_get_arg(gcb);
++    ctx->keygen_info[0] = a;
++    ctx->keygen_info[1] = b;
++    return ctx->pkey_gencb(ctx);
++}
++
++void evp_pkey_set_cb_translate(BN_GENCB *cb, EVP_PKEY_CTX *ctx)
++{
++    BN_GENCB_set(cb, trans_cb, ctx);
++}
++
++int EVP_PKEY_CTX_get_keygen_info(EVP_PKEY_CTX *ctx, int idx)
++{
++    if (idx == -1)
++        return ctx->keygen_info_count;
++    if (idx < 0 || idx > ctx->keygen_info_count)
++        return 0;
++    return ctx->keygen_info[idx];
++}
++
++EVP_PKEY *EVP_PKEY_new_mac_key(int type, ENGINE *e,
++                               const unsigned char *key, int keylen)
++{
++    EVP_PKEY_CTX *mac_ctx = NULL;
++    EVP_PKEY *mac_key = NULL;
++    mac_ctx = EVP_PKEY_CTX_new_id(type, e);
++    if (!mac_ctx)
++        return NULL;
++    if (EVP_PKEY_keygen_init(mac_ctx) <= 0)
++        goto merr;
++    if (EVP_PKEY_CTX_set_mac_key(mac_ctx, key, keylen) <= 0)
++        goto merr;
++    if (EVP_PKEY_keygen(mac_ctx, &mac_key) <= 0)
++        goto merr;
++ merr:
++    EVP_PKEY_CTX_free(mac_ctx);
++    return mac_key;
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/evp/pmeth_lib.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/evp/pmeth_lib.c
+new file mode 100644
+index 0000000..b7f06be
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/evp/pmeth_lib.c
+@@ -0,0 +1,721 @@
++/*
++ * Copyright 2006-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include 
++#include "internal/cryptlib.h"
++#include 
++#include 
++#include 
++#include "internal/asn1_int.h"
++#include "internal/evp_int.h"
++#include "internal/numbers.h"
++
++typedef int sk_cmp_fn_type(const char *const *a, const char *const *b);
++
++static STACK_OF(EVP_PKEY_METHOD) *app_pkey_methods = NULL;
++
++static const EVP_PKEY_METHOD *standard_methods[] = {
++#ifndef OPENSSL_NO_RSA
++    &rsa_pkey_meth,
++#endif
++#ifndef OPENSSL_NO_DH
++    &dh_pkey_meth,
++#endif
++#ifndef OPENSSL_NO_DSA
++    &dsa_pkey_meth,
++#endif
++#ifndef OPENSSL_NO_EC
++    &ec_pkey_meth,
++#endif
++    &hmac_pkey_meth,
++#ifndef OPENSSL_NO_CMAC
++    &cmac_pkey_meth,
++#endif
++#ifndef OPENSSL_NO_DH
++    &dhx_pkey_meth,
++#endif
++    &tls1_prf_pkey_meth,
++#ifndef OPENSSL_NO_EC
++    &ecx25519_pkey_meth,
++#endif
++    &hkdf_pkey_meth
++};
++
++DECLARE_OBJ_BSEARCH_CMP_FN(const EVP_PKEY_METHOD *, const EVP_PKEY_METHOD *,
++                           pmeth);
++
++static int pmeth_cmp(const EVP_PKEY_METHOD *const *a,
++                     const EVP_PKEY_METHOD *const *b)
++{
++    return ((*a)->pkey_id - (*b)->pkey_id);
++}
++
++IMPLEMENT_OBJ_BSEARCH_CMP_FN(const EVP_PKEY_METHOD *, const EVP_PKEY_METHOD *,
++                             pmeth);
++
++const EVP_PKEY_METHOD *EVP_PKEY_meth_find(int type)
++{
++    EVP_PKEY_METHOD tmp;
++    const EVP_PKEY_METHOD *t = &tmp, **ret;
++    tmp.pkey_id = type;
++    if (app_pkey_methods) {
++        int idx;
++        idx = sk_EVP_PKEY_METHOD_find(app_pkey_methods, &tmp);
++        if (idx >= 0)
++            return sk_EVP_PKEY_METHOD_value(app_pkey_methods, idx);
++    }
++    ret = OBJ_bsearch_pmeth(&t, standard_methods,
++                            sizeof(standard_methods) /
++                            sizeof(EVP_PKEY_METHOD *));
++    if (!ret || !*ret)
++        return NULL;
++    return *ret;
++}
++
++static EVP_PKEY_CTX *int_ctx_new(EVP_PKEY *pkey, ENGINE *e, int id)
++{
++    EVP_PKEY_CTX *ret;
++    const EVP_PKEY_METHOD *pmeth;
++    if (id == -1) {
++        if (!pkey || !pkey->ameth)
++            return NULL;
++        id = pkey->ameth->pkey_id;
++    }
++#ifndef OPENSSL_NO_ENGINE
++    if (pkey && pkey->engine)
++        e = pkey->engine;
++    /* Try to find an ENGINE which implements this method */
++    if (e) {
++        if (!ENGINE_init(e)) {
++            EVPerr(EVP_F_INT_CTX_NEW, ERR_R_ENGINE_LIB);
++            return NULL;
++        }
++    } else
++        e = ENGINE_get_pkey_meth_engine(id);
++
++    /*
++     * If an ENGINE handled this method look it up. Otherwise use internal
++     * tables.
++     */
++
++    if (e)
++        pmeth = ENGINE_get_pkey_meth(e, id);
++    else
++#endif
++        pmeth = EVP_PKEY_meth_find(id);
++
++    if (pmeth == NULL) {
++        EVPerr(EVP_F_INT_CTX_NEW, EVP_R_UNSUPPORTED_ALGORITHM);
++        return NULL;
++    }
++
++    ret = OPENSSL_zalloc(sizeof(*ret));
++    if (ret == NULL) {
++#ifndef OPENSSL_NO_ENGINE
++        ENGINE_finish(e);
++#endif
++        EVPerr(EVP_F_INT_CTX_NEW, ERR_R_MALLOC_FAILURE);
++        return NULL;
++    }
++    ret->engine = e;
++    ret->pmeth = pmeth;
++    ret->operation = EVP_PKEY_OP_UNDEFINED;
++    ret->pkey = pkey;
++    if (pkey)
++        EVP_PKEY_up_ref(pkey);
++
++    if (pmeth->init) {
++        if (pmeth->init(ret) <= 0) {
++            ret->pmeth = NULL;
++            EVP_PKEY_CTX_free(ret);
++            return NULL;
++        }
++    }
++
++    return ret;
++}
++
++EVP_PKEY_METHOD *EVP_PKEY_meth_new(int id, int flags)
++{
++    EVP_PKEY_METHOD *pmeth;
++
++    pmeth = OPENSSL_zalloc(sizeof(*pmeth));
++    if (pmeth == NULL)
++        return NULL;
++
++    pmeth->pkey_id = id;
++    pmeth->flags = flags | EVP_PKEY_FLAG_DYNAMIC;
++    return pmeth;
++}
++
++void EVP_PKEY_meth_get0_info(int *ppkey_id, int *pflags,
++                             const EVP_PKEY_METHOD *meth)
++{
++    if (ppkey_id)
++        *ppkey_id = meth->pkey_id;
++    if (pflags)
++        *pflags = meth->flags;
++}
++
++void EVP_PKEY_meth_copy(EVP_PKEY_METHOD *dst, const EVP_PKEY_METHOD *src)
++{
++
++    dst->init = src->init;
++    dst->copy = src->copy;
++    dst->cleanup = src->cleanup;
++
++    dst->paramgen_init = src->paramgen_init;
++    dst->paramgen = src->paramgen;
++
++    dst->keygen_init = src->keygen_init;
++    dst->keygen = src->keygen;
++
++    dst->sign_init = src->sign_init;
++    dst->sign = src->sign;
++
++    dst->verify_init = src->verify_init;
++    dst->verify = src->verify;
++
++    dst->verify_recover_init = src->verify_recover_init;
++    dst->verify_recover = src->verify_recover;
++
++    dst->signctx_init = src->signctx_init;
++    dst->signctx = src->signctx;
++
++    dst->verifyctx_init = src->verifyctx_init;
++    dst->verifyctx = src->verifyctx;
++
++    dst->encrypt_init = src->encrypt_init;
++    dst->encrypt = src->encrypt;
++
++    dst->decrypt_init = src->decrypt_init;
++    dst->decrypt = src->decrypt;
++
++    dst->derive_init = src->derive_init;
++    dst->derive = src->derive;
++
++    dst->ctrl = src->ctrl;
++    dst->ctrl_str = src->ctrl_str;
++}
++
++void EVP_PKEY_meth_free(EVP_PKEY_METHOD *pmeth)
++{
++    if (pmeth && (pmeth->flags & EVP_PKEY_FLAG_DYNAMIC))
++        OPENSSL_free(pmeth);
++}
++
++EVP_PKEY_CTX *EVP_PKEY_CTX_new(EVP_PKEY *pkey, ENGINE *e)
++{
++    return int_ctx_new(pkey, e, -1);
++}
++
++EVP_PKEY_CTX *EVP_PKEY_CTX_new_id(int id, ENGINE *e)
++{
++    return int_ctx_new(NULL, e, id);
++}
++
++EVP_PKEY_CTX *EVP_PKEY_CTX_dup(EVP_PKEY_CTX *pctx)
++{
++    EVP_PKEY_CTX *rctx;
++    if (!pctx->pmeth || !pctx->pmeth->copy)
++        return NULL;
++#ifndef OPENSSL_NO_ENGINE
++    /* Make sure it's safe to copy a pkey context using an ENGINE */
++    if (pctx->engine && !ENGINE_init(pctx->engine)) {
++        EVPerr(EVP_F_EVP_PKEY_CTX_DUP, ERR_R_ENGINE_LIB);
++        return 0;
++    }
++#endif
++    rctx = OPENSSL_malloc(sizeof(*rctx));
++    if (rctx == NULL)
++        return NULL;
++
++    rctx->pmeth = pctx->pmeth;
++#ifndef OPENSSL_NO_ENGINE
++    rctx->engine = pctx->engine;
++#endif
++
++    if (pctx->pkey)
++        EVP_PKEY_up_ref(pctx->pkey);
++
++    rctx->pkey = pctx->pkey;
++
++    if (pctx->peerkey)
++        EVP_PKEY_up_ref(pctx->peerkey);
++
++    rctx->peerkey = pctx->peerkey;
++
++    rctx->data = NULL;
++    rctx->app_data = NULL;
++    rctx->operation = pctx->operation;
++
++    if (pctx->pmeth->copy(rctx, pctx) > 0)
++        return rctx;
++
++    rctx->pmeth = NULL;
++    EVP_PKEY_CTX_free(rctx);
++    return NULL;
++
++}
++
++int EVP_PKEY_meth_add0(const EVP_PKEY_METHOD *pmeth)
++{
++    if (app_pkey_methods == NULL) {
++        app_pkey_methods = sk_EVP_PKEY_METHOD_new(pmeth_cmp);
++        if (app_pkey_methods == NULL)
++            return 0;
++    }
++    if (!sk_EVP_PKEY_METHOD_push(app_pkey_methods, pmeth))
++        return 0;
++    sk_EVP_PKEY_METHOD_sort(app_pkey_methods);
++    return 1;
++}
++
++void EVP_PKEY_CTX_free(EVP_PKEY_CTX *ctx)
++{
++    if (ctx == NULL)
++        return;
++    if (ctx->pmeth && ctx->pmeth->cleanup)
++        ctx->pmeth->cleanup(ctx);
++    EVP_PKEY_free(ctx->pkey);
++    EVP_PKEY_free(ctx->peerkey);
++#ifndef OPENSSL_NO_ENGINE
++    ENGINE_finish(ctx->engine);
++#endif
++    OPENSSL_free(ctx);
++}
++
++int EVP_PKEY_CTX_ctrl(EVP_PKEY_CTX *ctx, int keytype, int optype,
++                      int cmd, int p1, void *p2)
++{
++    int ret;
++    if (!ctx || !ctx->pmeth || !ctx->pmeth->ctrl) {
++        EVPerr(EVP_F_EVP_PKEY_CTX_CTRL, EVP_R_COMMAND_NOT_SUPPORTED);
++        return -2;
++    }
++    if ((keytype != -1) && (ctx->pmeth->pkey_id != keytype))
++        return -1;
++
++    if (ctx->operation == EVP_PKEY_OP_UNDEFINED) {
++        EVPerr(EVP_F_EVP_PKEY_CTX_CTRL, EVP_R_NO_OPERATION_SET);
++        return -1;
++    }
++
++    if ((optype != -1) && !(ctx->operation & optype)) {
++        EVPerr(EVP_F_EVP_PKEY_CTX_CTRL, EVP_R_INVALID_OPERATION);
++        return -1;
++    }
++
++    ret = ctx->pmeth->ctrl(ctx, cmd, p1, p2);
++
++    if (ret == -2)
++        EVPerr(EVP_F_EVP_PKEY_CTX_CTRL, EVP_R_COMMAND_NOT_SUPPORTED);
++
++    return ret;
++
++}
++
++int EVP_PKEY_CTX_ctrl_str(EVP_PKEY_CTX *ctx,
++                          const char *name, const char *value)
++{
++    if (!ctx || !ctx->pmeth || !ctx->pmeth->ctrl_str) {
++        EVPerr(EVP_F_EVP_PKEY_CTX_CTRL_STR, EVP_R_COMMAND_NOT_SUPPORTED);
++        return -2;
++    }
++    if (strcmp(name, "digest") == 0) {
++        const EVP_MD *md;
++        if (value == NULL || (md = EVP_get_digestbyname(value)) == NULL) {
++            EVPerr(EVP_F_EVP_PKEY_CTX_CTRL_STR, EVP_R_INVALID_DIGEST);
++            return 0;
++        }
++        return EVP_PKEY_CTX_set_signature_md(ctx, md);
++    }
++    return ctx->pmeth->ctrl_str(ctx, name, value);
++}
++
++/* Utility functions to send a string of hex string to a ctrl */
++
++int EVP_PKEY_CTX_str2ctrl(EVP_PKEY_CTX *ctx, int cmd, const char *str)
++{
++    size_t len;
++
++    len = strlen(str);
++    if (len > INT_MAX)
++        return -1;
++    return ctx->pmeth->ctrl(ctx, cmd, len, (void *)str);
++}
++
++int EVP_PKEY_CTX_hex2ctrl(EVP_PKEY_CTX *ctx, int cmd, const char *hex)
++{
++    unsigned char *bin;
++    long binlen;
++    int rv = -1;
++
++    bin = OPENSSL_hexstr2buf(hex, &binlen);
++    if (bin == NULL)
++        return 0;
++    if (binlen <= INT_MAX)
++        rv = ctx->pmeth->ctrl(ctx, cmd, binlen, bin);
++    OPENSSL_free(bin);
++    return rv;
++}
++
++int EVP_PKEY_CTX_get_operation(EVP_PKEY_CTX *ctx)
++{
++    return ctx->operation;
++}
++
++void EVP_PKEY_CTX_set0_keygen_info(EVP_PKEY_CTX *ctx, int *dat, int datlen)
++{
++    ctx->keygen_info = dat;
++    ctx->keygen_info_count = datlen;
++}
++
++void EVP_PKEY_CTX_set_data(EVP_PKEY_CTX *ctx, void *data)
++{
++    ctx->data = data;
++}
++
++void *EVP_PKEY_CTX_get_data(EVP_PKEY_CTX *ctx)
++{
++    return ctx->data;
++}
++
++EVP_PKEY *EVP_PKEY_CTX_get0_pkey(EVP_PKEY_CTX *ctx)
++{
++    return ctx->pkey;
++}
++
++EVP_PKEY *EVP_PKEY_CTX_get0_peerkey(EVP_PKEY_CTX *ctx)
++{
++    return ctx->peerkey;
++}
++
++void EVP_PKEY_CTX_set_app_data(EVP_PKEY_CTX *ctx, void *data)
++{
++    ctx->app_data = data;
++}
++
++void *EVP_PKEY_CTX_get_app_data(EVP_PKEY_CTX *ctx)
++{
++    return ctx->app_data;
++}
++
++void EVP_PKEY_meth_set_init(EVP_PKEY_METHOD *pmeth,
++                            int (*init) (EVP_PKEY_CTX *ctx))
++{
++    pmeth->init = init;
++}
++
++void EVP_PKEY_meth_set_copy(EVP_PKEY_METHOD *pmeth,
++                            int (*copy) (EVP_PKEY_CTX *dst,
++                                         EVP_PKEY_CTX *src))
++{
++    pmeth->copy = copy;
++}
++
++void EVP_PKEY_meth_set_cleanup(EVP_PKEY_METHOD *pmeth,
++                               void (*cleanup) (EVP_PKEY_CTX *ctx))
++{
++    pmeth->cleanup = cleanup;
++}
++
++void EVP_PKEY_meth_set_paramgen(EVP_PKEY_METHOD *pmeth,
++                                int (*paramgen_init) (EVP_PKEY_CTX *ctx),
++                                int (*paramgen) (EVP_PKEY_CTX *ctx,
++                                                 EVP_PKEY *pkey))
++{
++    pmeth->paramgen_init = paramgen_init;
++    pmeth->paramgen = paramgen;
++}
++
++void EVP_PKEY_meth_set_keygen(EVP_PKEY_METHOD *pmeth,
++                              int (*keygen_init) (EVP_PKEY_CTX *ctx),
++                              int (*keygen) (EVP_PKEY_CTX *ctx,
++                                             EVP_PKEY *pkey))
++{
++    pmeth->keygen_init = keygen_init;
++    pmeth->keygen = keygen;
++}
++
++void EVP_PKEY_meth_set_sign(EVP_PKEY_METHOD *pmeth,
++                            int (*sign_init) (EVP_PKEY_CTX *ctx),
++                            int (*sign) (EVP_PKEY_CTX *ctx,
++                                         unsigned char *sig, size_t *siglen,
++                                         const unsigned char *tbs,
++                                         size_t tbslen))
++{
++    pmeth->sign_init = sign_init;
++    pmeth->sign = sign;
++}
++
++void EVP_PKEY_meth_set_verify(EVP_PKEY_METHOD *pmeth,
++                              int (*verify_init) (EVP_PKEY_CTX *ctx),
++                              int (*verify) (EVP_PKEY_CTX *ctx,
++                                             const unsigned char *sig,
++                                             size_t siglen,
++                                             const unsigned char *tbs,
++                                             size_t tbslen))
++{
++    pmeth->verify_init = verify_init;
++    pmeth->verify = verify;
++}
++
++void EVP_PKEY_meth_set_verify_recover(EVP_PKEY_METHOD *pmeth,
++                                      int (*verify_recover_init) (EVP_PKEY_CTX
++                                                                  *ctx),
++                                      int (*verify_recover) (EVP_PKEY_CTX
++                                                             *ctx,
++                                                             unsigned char
++                                                             *sig,
++                                                             size_t *siglen,
++                                                             const unsigned
++                                                             char *tbs,
++                                                             size_t tbslen))
++{
++    pmeth->verify_recover_init = verify_recover_init;
++    pmeth->verify_recover = verify_recover;
++}
++
++void EVP_PKEY_meth_set_signctx(EVP_PKEY_METHOD *pmeth,
++                               int (*signctx_init) (EVP_PKEY_CTX *ctx,
++                                                    EVP_MD_CTX *mctx),
++                               int (*signctx) (EVP_PKEY_CTX *ctx,
++                                               unsigned char *sig,
++                                               size_t *siglen,
++                                               EVP_MD_CTX *mctx))
++{
++    pmeth->signctx_init = signctx_init;
++    pmeth->signctx = signctx;
++}
++
++void EVP_PKEY_meth_set_verifyctx(EVP_PKEY_METHOD *pmeth,
++                                 int (*verifyctx_init) (EVP_PKEY_CTX *ctx,
++                                                        EVP_MD_CTX *mctx),
++                                 int (*verifyctx) (EVP_PKEY_CTX *ctx,
++                                                   const unsigned char *sig,
++                                                   int siglen,
++                                                   EVP_MD_CTX *mctx))
++{
++    pmeth->verifyctx_init = verifyctx_init;
++    pmeth->verifyctx = verifyctx;
++}
++
++void EVP_PKEY_meth_set_encrypt(EVP_PKEY_METHOD *pmeth,
++                               int (*encrypt_init) (EVP_PKEY_CTX *ctx),
++                               int (*encryptfn) (EVP_PKEY_CTX *ctx,
++                                                 unsigned char *out,
++                                                 size_t *outlen,
++                                                 const unsigned char *in,
++                                                 size_t inlen))
++{
++    pmeth->encrypt_init = encrypt_init;
++    pmeth->encrypt = encryptfn;
++}
++
++void EVP_PKEY_meth_set_decrypt(EVP_PKEY_METHOD *pmeth,
++                               int (*decrypt_init) (EVP_PKEY_CTX *ctx),
++                               int (*decrypt) (EVP_PKEY_CTX *ctx,
++                                               unsigned char *out,
++                                               size_t *outlen,
++                                               const unsigned char *in,
++                                               size_t inlen))
++{
++    pmeth->decrypt_init = decrypt_init;
++    pmeth->decrypt = decrypt;
++}
++
++void EVP_PKEY_meth_set_derive(EVP_PKEY_METHOD *pmeth,
++                              int (*derive_init) (EVP_PKEY_CTX *ctx),
++                              int (*derive) (EVP_PKEY_CTX *ctx,
++                                             unsigned char *key,
++                                             size_t *keylen))
++{
++    pmeth->derive_init = derive_init;
++    pmeth->derive = derive;
++}
++
++void EVP_PKEY_meth_set_ctrl(EVP_PKEY_METHOD *pmeth,
++                            int (*ctrl) (EVP_PKEY_CTX *ctx, int type, int p1,
++                                         void *p2),
++                            int (*ctrl_str) (EVP_PKEY_CTX *ctx,
++                                             const char *type,
++                                             const char *value))
++{
++    pmeth->ctrl = ctrl;
++    pmeth->ctrl_str = ctrl_str;
++}
++
++void EVP_PKEY_meth_get_init(EVP_PKEY_METHOD *pmeth,
++                            int (**pinit) (EVP_PKEY_CTX *ctx))
++{
++    *pinit = pmeth->init;
++}
++
++void EVP_PKEY_meth_get_copy(EVP_PKEY_METHOD *pmeth,
++                            int (**pcopy) (EVP_PKEY_CTX *dst,
++                                           EVP_PKEY_CTX *src))
++{
++    *pcopy = pmeth->copy;
++}
++
++void EVP_PKEY_meth_get_cleanup(EVP_PKEY_METHOD *pmeth,
++                               void (**pcleanup) (EVP_PKEY_CTX *ctx))
++{
++    *pcleanup = pmeth->cleanup;
++}
++
++void EVP_PKEY_meth_get_paramgen(EVP_PKEY_METHOD *pmeth,
++                                int (**pparamgen_init) (EVP_PKEY_CTX *ctx),
++                                int (**pparamgen) (EVP_PKEY_CTX *ctx,
++                                                   EVP_PKEY *pkey))
++{
++    if (pparamgen_init)
++        *pparamgen_init = pmeth->paramgen_init;
++    if (pparamgen)
++        *pparamgen = pmeth->paramgen;
++}
++
++void EVP_PKEY_meth_get_keygen(EVP_PKEY_METHOD *pmeth,
++                              int (**pkeygen_init) (EVP_PKEY_CTX *ctx),
++                              int (**pkeygen) (EVP_PKEY_CTX *ctx,
++                                               EVP_PKEY *pkey))
++{
++    if (pkeygen_init)
++        *pkeygen_init = pmeth->keygen_init;
++    if (pkeygen)
++        *pkeygen = pmeth->keygen;
++}
++
++void EVP_PKEY_meth_get_sign(EVP_PKEY_METHOD *pmeth,
++                            int (**psign_init) (EVP_PKEY_CTX *ctx),
++                            int (**psign) (EVP_PKEY_CTX *ctx,
++                                           unsigned char *sig, size_t *siglen,
++                                           const unsigned char *tbs,
++                                           size_t tbslen))
++{
++    if (psign_init)
++        *psign_init = pmeth->sign_init;
++    if (psign)
++        *psign = pmeth->sign;
++}
++
++void EVP_PKEY_meth_get_verify(EVP_PKEY_METHOD *pmeth,
++                              int (**pverify_init) (EVP_PKEY_CTX *ctx),
++                              int (**pverify) (EVP_PKEY_CTX *ctx,
++                                               const unsigned char *sig,
++                                               size_t siglen,
++                                               const unsigned char *tbs,
++                                               size_t tbslen))
++{
++    if (pverify_init)
++        *pverify_init = pmeth->verify_init;
++    if (pverify)
++        *pverify = pmeth->verify;
++}
++
++void EVP_PKEY_meth_get_verify_recover(EVP_PKEY_METHOD *pmeth,
++                                      int (**pverify_recover_init) (EVP_PKEY_CTX
++                                                                    *ctx),
++                                      int (**pverify_recover) (EVP_PKEY_CTX
++                                                               *ctx,
++                                                               unsigned char
++                                                               *sig,
++                                                               size_t *siglen,
++                                                               const unsigned
++                                                               char *tbs,
++                                                               size_t tbslen))
++{
++    if (pverify_recover_init)
++        *pverify_recover_init = pmeth->verify_recover_init;
++    if (pverify_recover)
++        *pverify_recover = pmeth->verify_recover;
++}
++
++void EVP_PKEY_meth_get_signctx(EVP_PKEY_METHOD *pmeth,
++                               int (**psignctx_init) (EVP_PKEY_CTX *ctx,
++                                                      EVP_MD_CTX *mctx),
++                               int (**psignctx) (EVP_PKEY_CTX *ctx,
++                                                 unsigned char *sig,
++                                                 size_t *siglen,
++                                                 EVP_MD_CTX *mctx))
++{
++    if (psignctx_init)
++        *psignctx_init = pmeth->signctx_init;
++    if (psignctx)
++        *psignctx = pmeth->signctx;
++}
++
++void EVP_PKEY_meth_get_verifyctx(EVP_PKEY_METHOD *pmeth,
++                                 int (**pverifyctx_init) (EVP_PKEY_CTX *ctx,
++                                                          EVP_MD_CTX *mctx),
++                                 int (**pverifyctx) (EVP_PKEY_CTX *ctx,
++                                                     const unsigned char *sig,
++                                                     int siglen,
++                                                     EVP_MD_CTX *mctx))
++{
++    if (pverifyctx_init)
++        *pverifyctx_init = pmeth->verifyctx_init;
++    if (pverifyctx)
++        *pverifyctx = pmeth->verifyctx;
++}
++
++void EVP_PKEY_meth_get_encrypt(EVP_PKEY_METHOD *pmeth,
++                               int (**pencrypt_init) (EVP_PKEY_CTX *ctx),
++                               int (**pencryptfn) (EVP_PKEY_CTX *ctx,
++                                                   unsigned char *out,
++                                                   size_t *outlen,
++                                                   const unsigned char *in,
++                                                   size_t inlen))
++{
++    if (pencrypt_init)
++        *pencrypt_init = pmeth->encrypt_init;
++    if (pencryptfn)
++        *pencryptfn = pmeth->encrypt;
++}
++
++void EVP_PKEY_meth_get_decrypt(EVP_PKEY_METHOD *pmeth,
++                               int (**pdecrypt_init) (EVP_PKEY_CTX *ctx),
++                               int (**pdecrypt) (EVP_PKEY_CTX *ctx,
++                                                 unsigned char *out,
++                                                 size_t *outlen,
++                                                 const unsigned char *in,
++                                                 size_t inlen))
++{
++    if (pdecrypt_init)
++        *pdecrypt_init = pmeth->decrypt_init;
++    if (pdecrypt)
++        *pdecrypt = pmeth->decrypt;
++}
++
++void EVP_PKEY_meth_get_derive(EVP_PKEY_METHOD *pmeth,
++                              int (**pderive_init) (EVP_PKEY_CTX *ctx),
++                              int (**pderive) (EVP_PKEY_CTX *ctx,
++                                               unsigned char *key,
++                                               size_t *keylen))
++{
++    if (pderive_init)
++        *pderive_init = pmeth->derive_init;
++    if (pderive)
++        *pderive = pmeth->derive;
++}
++
++void EVP_PKEY_meth_get_ctrl(EVP_PKEY_METHOD *pmeth,
++                            int (**pctrl) (EVP_PKEY_CTX *ctx, int type, int p1,
++                                           void *p2),
++                            int (**pctrl_str) (EVP_PKEY_CTX *ctx,
++                                               const char *type,
++                                               const char *value))
++{
++    if (pctrl)
++        *pctrl = pmeth->ctrl;
++    if (pctrl_str)
++        *pctrl_str = pmeth->ctrl_str;
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/evp/scrypt.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/evp/scrypt.c
+new file mode 100644
+index 0000000..101bb1e
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/evp/scrypt.c
+@@ -0,0 +1,248 @@
++/*
++ * Copyright 2015-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include 
++#include 
++#include 
++#include 
++#include 
++
++#ifndef OPENSSL_NO_SCRYPT
++
++#define R(a,b) (((a) << (b)) | ((a) >> (32 - (b))))
++static void salsa208_word_specification(uint32_t inout[16])
++{
++    int i;
++    uint32_t x[16];
++    memcpy(x, inout, sizeof(x));
++    for (i = 8; i > 0; i -= 2) {
++        x[4] ^= R(x[0] + x[12], 7);
++        x[8] ^= R(x[4] + x[0], 9);
++        x[12] ^= R(x[8] + x[4], 13);
++        x[0] ^= R(x[12] + x[8], 18);
++        x[9] ^= R(x[5] + x[1], 7);
++        x[13] ^= R(x[9] + x[5], 9);
++        x[1] ^= R(x[13] + x[9], 13);
++        x[5] ^= R(x[1] + x[13], 18);
++        x[14] ^= R(x[10] + x[6], 7);
++        x[2] ^= R(x[14] + x[10], 9);
++        x[6] ^= R(x[2] + x[14], 13);
++        x[10] ^= R(x[6] + x[2], 18);
++        x[3] ^= R(x[15] + x[11], 7);
++        x[7] ^= R(x[3] + x[15], 9);
++        x[11] ^= R(x[7] + x[3], 13);
++        x[15] ^= R(x[11] + x[7], 18);
++        x[1] ^= R(x[0] + x[3], 7);
++        x[2] ^= R(x[1] + x[0], 9);
++        x[3] ^= R(x[2] + x[1], 13);
++        x[0] ^= R(x[3] + x[2], 18);
++        x[6] ^= R(x[5] + x[4], 7);
++        x[7] ^= R(x[6] + x[5], 9);
++        x[4] ^= R(x[7] + x[6], 13);
++        x[5] ^= R(x[4] + x[7], 18);
++        x[11] ^= R(x[10] + x[9], 7);
++        x[8] ^= R(x[11] + x[10], 9);
++        x[9] ^= R(x[8] + x[11], 13);
++        x[10] ^= R(x[9] + x[8], 18);
++        x[12] ^= R(x[15] + x[14], 7);
++        x[13] ^= R(x[12] + x[15], 9);
++        x[14] ^= R(x[13] + x[12], 13);
++        x[15] ^= R(x[14] + x[13], 18);
++    }
++    for (i = 0; i < 16; ++i)
++        inout[i] += x[i];
++    OPENSSL_cleanse(x, sizeof(x));
++}
++
++static void scryptBlockMix(uint32_t *B_, uint32_t *B, uint64_t r)
++{
++    uint64_t i, j;
++    uint32_t X[16], *pB;
++
++    memcpy(X, B + (r * 2 - 1) * 16, sizeof(X));
++    pB = B;
++    for (i = 0; i < r * 2; i++) {
++        for (j = 0; j < 16; j++)
++            X[j] ^= *pB++;
++        salsa208_word_specification(X);
++        memcpy(B_ + (i / 2 + (i & 1) * r) * 16, X, sizeof(X));
++    }
++    OPENSSL_cleanse(X, sizeof(X));
++}
++
++static void scryptROMix(unsigned char *B, uint64_t r, uint64_t N,
++                        uint32_t *X, uint32_t *T, uint32_t *V)
++{
++    unsigned char *pB;
++    uint32_t *pV;
++    uint64_t i, k;
++
++    /* Convert from little endian input */
++    for (pV = V, i = 0, pB = B; i < 32 * r; i++, pV++) {
++        *pV = *pB++;
++        *pV |= *pB++ << 8;
++        *pV |= *pB++ << 16;
++        *pV |= (uint32_t)*pB++ << 24;
++    }
++
++    for (i = 1; i < N; i++, pV += 32 * r)
++        scryptBlockMix(pV, pV - 32 * r, r);
++
++    scryptBlockMix(X, V + (N - 1) * 32 * r, r);
++
++    for (i = 0; i < N; i++) {
++        uint32_t j;
++        j = X[16 * (2 * r - 1)] % N;
++        pV = V + 32 * r * j;
++        for (k = 0; k < 32 * r; k++)
++            T[k] = X[k] ^ *pV++;
++        scryptBlockMix(X, T, r);
++    }
++    /* Convert output to little endian */
++    for (i = 0, pB = B; i < 32 * r; i++) {
++        uint32_t xtmp = X[i];
++        *pB++ = xtmp & 0xff;
++        *pB++ = (xtmp >> 8) & 0xff;
++        *pB++ = (xtmp >> 16) & 0xff;
++        *pB++ = (xtmp >> 24) & 0xff;
++    }
++}
++
++#ifndef SIZE_MAX
++# define SIZE_MAX    ((size_t)-1)
++#endif
++
++/*
++ * Maximum power of two that will fit in uint64_t: this should work on
++ * most (all?) platforms.
++ */
++
++#define LOG2_UINT64_MAX         (sizeof(uint64_t) * 8 - 1)
++
++/*
++ * Maximum value of p * r:
++ * p <= ((2^32-1) * hLen) / MFLen =>
++ * p <= ((2^32-1) * 32) / (128 * r) =>
++ * p * r <= (2^30-1)
++ *
++ */
++
++#define SCRYPT_PR_MAX   ((1 << 30) - 1)
++
++/*
++ * Maximum permitted memory allow this to be overridden with Configuration
++ * option: e.g. -DSCRYPT_MAX_MEM=0 for maximum possible.
++ */
++
++#ifdef SCRYPT_MAX_MEM
++# if SCRYPT_MAX_MEM == 0
++#  undef SCRYPT_MAX_MEM
++/*
++ * Although we could theoretically allocate SIZE_MAX memory that would leave
++ * no memory available for anything else so set limit as half that.
++ */
++#  define SCRYPT_MAX_MEM (SIZE_MAX/2)
++# endif
++#else
++/* Default memory limit: 32 MB */
++# define SCRYPT_MAX_MEM  (1024 * 1024 * 32)
++#endif
++
++int EVP_PBE_scrypt(const char *pass, size_t passlen,
++                   const unsigned char *salt, size_t saltlen,
++                   uint64_t N, uint64_t r, uint64_t p, uint64_t maxmem,
++                   unsigned char *key, size_t keylen)
++{
++    int rv = 0;
++    unsigned char *B;
++    uint32_t *X, *V, *T;
++    uint64_t i, Blen, Vlen;
++    size_t allocsize;
++
++    /* Sanity check parameters */
++    /* initial check, r,p must be non zero, N >= 2 and a power of 2 */
++    if (r == 0 || p == 0 || N < 2 || (N & (N - 1)))
++        return 0;
++    /* Check p * r < SCRYPT_PR_MAX avoiding overflow */
++    if (p > SCRYPT_PR_MAX / r)
++        return 0;
++
++    /*
++     * Need to check N: if 2^(128 * r / 8) overflows limit this is
++     * automatically satisfied since N <= UINT64_MAX.
++     */
++
++    if (16 * r <= LOG2_UINT64_MAX) {
++        if (N >= (((uint64_t)1) << (16 * r)))
++            return 0;
++    }
++
++    /* Memory checks: check total allocated buffer size fits in uint64_t */
++
++    /*
++     * B size in section 5 step 1.S
++     * Note: we know p * 128 * r < UINT64_MAX because we already checked
++     * p * r < SCRYPT_PR_MAX
++     */
++    Blen = p * 128 * r;
++
++    /*
++     * Check 32 * r * (N + 2) * sizeof(uint32_t) fits in
++     * uint64_t and also size_t (their sizes are unrelated).
++     * This is combined size V, X and T (section 4)
++     */
++    i = UINT64_MAX / (32 * sizeof(uint32_t));
++    if (N + 2 > i / r)
++        return 0;
++    Vlen = 32 * r * (N + 2) * sizeof(uint32_t);
++
++    /* check total allocated size fits in uint64_t */
++    if (Blen > UINT64_MAX - Vlen)
++        return 0;
++    /* check total allocated size fits in size_t */
++    if (Blen > SIZE_MAX - Vlen)
++        return 0;
++
++    allocsize = (size_t)(Blen + Vlen);
++
++    if (maxmem == 0)
++        maxmem = SCRYPT_MAX_MEM;
++
++    if (allocsize > maxmem) {
++        EVPerr(EVP_F_EVP_PBE_SCRYPT, EVP_R_MEMORY_LIMIT_EXCEEDED);
++        return 0;
++    }
++
++    /* If no key return to indicate parameters are OK */
++    if (key == NULL)
++        return 1;
++
++    B = OPENSSL_malloc(allocsize);
++    if (B == NULL)
++        return 0;
++    X = (uint32_t *)(B + Blen);
++    T = X + 32 * r;
++    V = T + 32 * r;
++    if (PKCS5_PBKDF2_HMAC(pass, passlen, salt, saltlen, 1, EVP_sha256(),
++                          Blen, B) == 0)
++        goto err;
++
++    for (i = 0; i < p; i++)
++        scryptROMix(B + 128 * r * i, r, N, X, T, V);
++
++    if (PKCS5_PBKDF2_HMAC(pass, passlen, B, Blen, 1, EVP_sha256(),
++                          keylen, key) == 0)
++        goto err;
++    rv = 1;
++ err:
++    OPENSSL_clear_free(B, allocsize);
++    return rv;
++}
++#endif
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/ex_data.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/ex_data.c
+new file mode 100644
+index 0000000..84b6555
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/ex_data.c
+@@ -0,0 +1,384 @@
++/*
++ * Copyright 1995-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include "internal/cryptlib_int.h"
++#include "internal/thread_once.h"
++#include 
++
++/*
++ * Each structure type (sometimes called a class), that supports
++ * exdata has a stack of callbacks for each instance.
++ */
++struct ex_callback_st {
++    long argl;                  /* Arbitrary long */
++    void *argp;                 /* Arbitrary void * */
++    CRYPTO_EX_new *new_func;
++    CRYPTO_EX_free *free_func;
++    CRYPTO_EX_dup *dup_func;
++};
++
++/*
++ * The state for each class.  This could just be a typedef, but
++ * a structure allows future changes.
++ */
++typedef struct ex_callbacks_st {
++    STACK_OF(EX_CALLBACK) *meth;
++} EX_CALLBACKS;
++
++static EX_CALLBACKS ex_data[CRYPTO_EX_INDEX__COUNT];
++
++static CRYPTO_RWLOCK *ex_data_lock = NULL;
++static CRYPTO_ONCE ex_data_init = CRYPTO_ONCE_STATIC_INIT;
++
++DEFINE_RUN_ONCE_STATIC(do_ex_data_init)
++{
++    OPENSSL_init_crypto(0, NULL);
++    ex_data_lock = CRYPTO_THREAD_lock_new();
++    return ex_data_lock != NULL;
++}
++
++/*
++ * Return the EX_CALLBACKS from the |ex_data| array that corresponds to
++ * a given class.  On success, *holds the lock.*
++ */
++static EX_CALLBACKS *get_and_lock(int class_index)
++{
++    EX_CALLBACKS *ip;
++
++    if (class_index < 0 || class_index >= CRYPTO_EX_INDEX__COUNT) {
++        CRYPTOerr(CRYPTO_F_GET_AND_LOCK, ERR_R_PASSED_INVALID_ARGUMENT);
++        return NULL;
++    }
++
++    if (!RUN_ONCE(&ex_data_init, do_ex_data_init)) {
++        CRYPTOerr(CRYPTO_F_GET_AND_LOCK, ERR_R_MALLOC_FAILURE);
++        return NULL;
++    }
++
++    if (ex_data_lock == NULL) {
++        /*
++         * This can happen in normal operation when using CRYPTO_mem_leaks().
++         * The CRYPTO_mem_leaks() function calls OPENSSL_cleanup() which cleans
++         * up the locks. Subsequently the BIO that CRYPTO_mem_leaks() uses gets
++         * freed, which also attempts to free the ex_data. However
++         * CRYPTO_mem_leaks() ensures that the ex_data is freed early (i.e.
++         * before OPENSSL_cleanup() is called), so if we get here we can safely
++         * ignore this operation. We just treat it as an error.
++         */
++         return NULL;
++    }
++
++    ip = &ex_data[class_index];
++    CRYPTO_THREAD_write_lock(ex_data_lock);
++    return ip;
++}
++
++static void cleanup_cb(EX_CALLBACK *funcs)
++{
++    OPENSSL_free(funcs);
++}
++
++/*
++ * Release all "ex_data" state to prevent memory leaks. This can't be made
++ * thread-safe without overhauling a lot of stuff, and shouldn't really be
++ * called under potential race-conditions anyway (it's for program shutdown
++ * after all).
++ */
++void crypto_cleanup_all_ex_data_int(void)
++{
++    int i;
++
++    for (i = 0; i < CRYPTO_EX_INDEX__COUNT; ++i) {
++        EX_CALLBACKS *ip = &ex_data[i];
++
++        sk_EX_CALLBACK_pop_free(ip->meth, cleanup_cb);
++        ip->meth = NULL;
++    }
++
++    CRYPTO_THREAD_lock_free(ex_data_lock);
++    ex_data_lock = NULL;
++}
++
++
++/*
++ * Unregister a new index by replacing the callbacks with no-ops.
++ * Any in-use instances are leaked.
++ */
++static void dummy_new(void *parent, void *ptr, CRYPTO_EX_DATA *ad, int idx,
++                     long argl, void *argp)
++{
++}
++
++static void dummy_free(void *parent, void *ptr, CRYPTO_EX_DATA *ad, int idx,
++                       long argl, void *argp)
++{
++}
++
++static int dummy_dup(CRYPTO_EX_DATA *to, const CRYPTO_EX_DATA *from,
++                     void *from_d, int idx,
++                     long argl, void *argp)
++{
++    return 0;
++}
++
++int CRYPTO_free_ex_index(int class_index, int idx)
++{
++    EX_CALLBACKS *ip = get_and_lock(class_index);
++    EX_CALLBACK *a;
++    int toret = 0;
++
++    if (ip == NULL)
++        return 0;
++    if (idx < 0 || idx >= sk_EX_CALLBACK_num(ip->meth))
++        goto err;
++    a = sk_EX_CALLBACK_value(ip->meth, idx);
++    if (a == NULL)
++        goto err;
++    a->new_func = dummy_new;
++    a->dup_func = dummy_dup;
++    a->free_func = dummy_free;
++    toret = 1;
++err:
++    CRYPTO_THREAD_unlock(ex_data_lock);
++    return toret;
++}
++
++/*
++ * Register a new index.
++ */
++int CRYPTO_get_ex_new_index(int class_index, long argl, void *argp,
++                            CRYPTO_EX_new *new_func, CRYPTO_EX_dup *dup_func,
++                            CRYPTO_EX_free *free_func)
++{
++    int toret = -1;
++    EX_CALLBACK *a;
++    EX_CALLBACKS *ip = get_and_lock(class_index);
++
++    if (ip == NULL)
++        return -1;
++
++    if (ip->meth == NULL) {
++        ip->meth = sk_EX_CALLBACK_new_null();
++        /* We push an initial value on the stack because the SSL
++         * "app_data" routines use ex_data index zero.  See RT 3710. */
++        if (ip->meth == NULL
++            || !sk_EX_CALLBACK_push(ip->meth, NULL)) {
++            CRYPTOerr(CRYPTO_F_CRYPTO_GET_EX_NEW_INDEX, ERR_R_MALLOC_FAILURE);
++            goto err;
++        }
++    }
++
++    a = (EX_CALLBACK *)OPENSSL_malloc(sizeof(*a));
++    if (a == NULL) {
++        CRYPTOerr(CRYPTO_F_CRYPTO_GET_EX_NEW_INDEX, ERR_R_MALLOC_FAILURE);
++        goto err;
++    }
++    a->argl = argl;
++    a->argp = argp;
++    a->new_func = new_func;
++    a->dup_func = dup_func;
++    a->free_func = free_func;
++
++    if (!sk_EX_CALLBACK_push(ip->meth, NULL)) {
++        CRYPTOerr(CRYPTO_F_CRYPTO_GET_EX_NEW_INDEX, ERR_R_MALLOC_FAILURE);
++        OPENSSL_free(a);
++        goto err;
++    }
++    toret = sk_EX_CALLBACK_num(ip->meth) - 1;
++    (void)sk_EX_CALLBACK_set(ip->meth, toret, a);
++
++ err:
++    CRYPTO_THREAD_unlock(ex_data_lock);
++    return toret;
++}
++
++/*
++ * Initialise a new CRYPTO_EX_DATA for use in a particular class - including
++ * calling new() callbacks for each index in the class used by this variable
++ * Thread-safe by copying a class's array of "EX_CALLBACK" entries
++ * in the lock, then using them outside the lock. Note this only applies
++ * to the global "ex_data" state (ie. class definitions), not 'ad' itself.
++ */
++int CRYPTO_new_ex_data(int class_index, void *obj, CRYPTO_EX_DATA *ad)
++{
++    int mx, i;
++    void *ptr;
++    EX_CALLBACK **storage = NULL;
++    EX_CALLBACK *stack[10];
++    EX_CALLBACKS *ip = get_and_lock(class_index);
++
++    if (ip == NULL)
++        return 0;
++
++    ad->sk = NULL;
++
++    mx = sk_EX_CALLBACK_num(ip->meth);
++    if (mx > 0) {
++        if (mx < (int)OSSL_NELEM(stack))
++            storage = stack;
++        else
++            storage = OPENSSL_malloc(sizeof(*storage) * mx);
++        if (storage != NULL)
++            for (i = 0; i < mx; i++)
++                storage[i] = sk_EX_CALLBACK_value(ip->meth, i);
++    }
++    CRYPTO_THREAD_unlock(ex_data_lock);
++
++    if (mx > 0 && storage == NULL) {
++        CRYPTOerr(CRYPTO_F_CRYPTO_NEW_EX_DATA, ERR_R_MALLOC_FAILURE);
++        return 0;
++    }
++    for (i = 0; i < mx; i++) {
++        if (storage[i] && storage[i]->new_func) {
++            ptr = CRYPTO_get_ex_data(ad, i);
++            storage[i]->new_func(obj, ptr, ad, i,
++                                 storage[i]->argl, storage[i]->argp);
++        }
++    }
++    if (storage != stack)
++        OPENSSL_free(storage);
++    return 1;
++}
++
++/*
++ * Duplicate a CRYPTO_EX_DATA variable - including calling dup() callbacks
++ * for each index in the class used by this variable
++ */
++int CRYPTO_dup_ex_data(int class_index, CRYPTO_EX_DATA *to,
++                       const CRYPTO_EX_DATA *from)
++{
++    int mx, j, i;
++    char *ptr;
++    EX_CALLBACK *stack[10];
++    EX_CALLBACK **storage = NULL;
++    EX_CALLBACKS *ip;
++
++    if (from->sk == NULL)
++        /* Nothing to copy over */
++        return 1;
++    if ((ip = get_and_lock(class_index)) == NULL)
++        return 0;
++
++    mx = sk_EX_CALLBACK_num(ip->meth);
++    j = sk_void_num(from->sk);
++    if (j < mx)
++        mx = j;
++    if (mx > 0) {
++        if (mx < (int)OSSL_NELEM(stack))
++            storage = stack;
++        else
++            storage = OPENSSL_malloc(sizeof(*storage) * mx);
++        if (storage != NULL)
++            for (i = 0; i < mx; i++)
++                storage[i] = sk_EX_CALLBACK_value(ip->meth, i);
++    }
++    CRYPTO_THREAD_unlock(ex_data_lock);
++
++    if (mx > 0 && storage == NULL) {
++        CRYPTOerr(CRYPTO_F_CRYPTO_DUP_EX_DATA, ERR_R_MALLOC_FAILURE);
++        return 0;
++    }
++
++    for (i = 0; i < mx; i++) {
++        ptr = CRYPTO_get_ex_data(from, i);
++        if (storage[i] && storage[i]->dup_func)
++            storage[i]->dup_func(to, from, &ptr, i,
++                                 storage[i]->argl, storage[i]->argp);
++        CRYPTO_set_ex_data(to, i, ptr);
++    }
++    if (storage != stack)
++        OPENSSL_free(storage);
++    return 1;
++}
++
++
++/*
++ * Cleanup a CRYPTO_EX_DATA variable - including calling free() callbacks for
++ * each index in the class used by this variable
++ */
++void CRYPTO_free_ex_data(int class_index, void *obj, CRYPTO_EX_DATA *ad)
++{
++    int mx, i;
++    EX_CALLBACKS *ip;
++    void *ptr;
++    EX_CALLBACK *f;
++    EX_CALLBACK *stack[10];
++    EX_CALLBACK **storage = NULL;
++
++    if ((ip = get_and_lock(class_index)) == NULL)
++        goto err;
++
++    mx = sk_EX_CALLBACK_num(ip->meth);
++    if (mx > 0) {
++        if (mx < (int)OSSL_NELEM(stack))
++            storage = stack;
++        else
++            storage = OPENSSL_malloc(sizeof(*storage) * mx);
++        if (storage != NULL)
++            for (i = 0; i < mx; i++)
++                storage[i] = sk_EX_CALLBACK_value(ip->meth, i);
++    }
++    CRYPTO_THREAD_unlock(ex_data_lock);
++
++    for (i = 0; i < mx; i++) {
++        if (storage != NULL)
++            f = storage[i];
++        else {
++            CRYPTO_THREAD_write_lock(ex_data_lock);
++            f = sk_EX_CALLBACK_value(ip->meth, i);
++            CRYPTO_THREAD_unlock(ex_data_lock);
++        }
++        if (f != NULL && f->free_func != NULL) {
++            ptr = CRYPTO_get_ex_data(ad, i);
++            f->free_func(obj, ptr, ad, i, f->argl, f->argp);
++        }
++    }
++
++    if (storage != stack)
++        OPENSSL_free(storage);
++ err:
++    sk_void_free(ad->sk);
++    ad->sk = NULL;
++}
++
++/*
++ * For a given CRYPTO_EX_DATA variable, set the value corresponding to a
++ * particular index in the class used by this variable
++ */
++int CRYPTO_set_ex_data(CRYPTO_EX_DATA *ad, int idx, void *val)
++{
++    int i;
++
++    if (ad->sk == NULL) {
++        if ((ad->sk = sk_void_new_null()) == NULL) {
++            CRYPTOerr(CRYPTO_F_CRYPTO_SET_EX_DATA, ERR_R_MALLOC_FAILURE);
++            return 0;
++        }
++    }
++
++    for (i = sk_void_num(ad->sk); i <= idx; ++i) {
++        if (!sk_void_push(ad->sk, NULL)) {
++            CRYPTOerr(CRYPTO_F_CRYPTO_SET_EX_DATA, ERR_R_MALLOC_FAILURE);
++            return 0;
++        }
++    }
++    sk_void_set(ad->sk, idx, val);
++    return 1;
++}
++
++/*
++ * For a given CRYPTO_EX_DATA_ variable, get the value corresponding to a
++ * particular index in the class used by this variable
++ */
++void *CRYPTO_get_ex_data(const CRYPTO_EX_DATA *ad, int idx)
++{
++    if (ad->sk == NULL || idx >= sk_void_num(ad->sk))
++        return NULL;
++    return sk_void_value(ad->sk, idx);
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/hmac/build.info b/CryptoPkg/Library/OpensslLib/openssl/crypto/hmac/build.info
+new file mode 100644
+index 0000000..09f67c2
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/hmac/build.info
+@@ -0,0 +1,3 @@
++LIBS=../../libcrypto
++SOURCE[../../libcrypto]=\
++        hmac.c hm_ameth.c hm_pmeth.c
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/hmac/hm_ameth.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/hmac/hm_ameth.c
+new file mode 100644
+index 0000000..78ae0ea
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/hmac/hm_ameth.c
+@@ -0,0 +1,125 @@
++/*
++ * Copyright 2007-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include "internal/cryptlib.h"
++#include 
++#include "internal/asn1_int.h"
++
++#define HMAC_TEST_PRIVATE_KEY_FORMAT
++
++/*
++ * HMAC "ASN1" method. This is just here to indicate the maximum HMAC output
++ * length and to free up an HMAC key.
++ */
++
++static int hmac_size(const EVP_PKEY *pkey)
++{
++    return EVP_MAX_MD_SIZE;
++}
++
++static void hmac_key_free(EVP_PKEY *pkey)
++{
++    ASN1_OCTET_STRING *os = EVP_PKEY_get0(pkey);
++    if (os) {
++        if (os->data)
++            OPENSSL_cleanse(os->data, os->length);
++        ASN1_OCTET_STRING_free(os);
++    }
++}
++
++static int hmac_pkey_ctrl(EVP_PKEY *pkey, int op, long arg1, void *arg2)
++{
++    switch (op) {
++    case ASN1_PKEY_CTRL_DEFAULT_MD_NID:
++        *(int *)arg2 = NID_sha256;
++        return 1;
++
++    default:
++        return -2;
++    }
++}
++
++static int hmac_pkey_public_cmp(const EVP_PKEY *a, const EVP_PKEY *b)
++{
++    return ASN1_OCTET_STRING_cmp(EVP_PKEY_get0(a), EVP_PKEY_get0(b));
++}
++
++#ifdef HMAC_TEST_PRIVATE_KEY_FORMAT
++/*
++ * A bogus private key format for test purposes. This is simply the HMAC key
++ * with "HMAC PRIVATE KEY" in the headers. When enabled the genpkey utility
++ * can be used to "generate" HMAC keys.
++ */
++
++static int old_hmac_decode(EVP_PKEY *pkey,
++                           const unsigned char **pder, int derlen)
++{
++    ASN1_OCTET_STRING *os;
++    os = ASN1_OCTET_STRING_new();
++    if (os == NULL || !ASN1_OCTET_STRING_set(os, *pder, derlen))
++        goto err;
++    if (!EVP_PKEY_assign(pkey, EVP_PKEY_HMAC, os))
++        goto err;
++    return 1;
++
++ err:
++    ASN1_OCTET_STRING_free(os);
++    return 0;
++}
++
++static int old_hmac_encode(const EVP_PKEY *pkey, unsigned char **pder)
++{
++    int inc;
++    ASN1_OCTET_STRING *os = EVP_PKEY_get0(pkey);
++    if (pder) {
++        if (!*pder) {
++            *pder = OPENSSL_malloc(os->length);
++            if (*pder == NULL)
++                return -1;
++            inc = 0;
++        } else
++            inc = 1;
++
++        memcpy(*pder, os->data, os->length);
++
++        if (inc)
++            *pder += os->length;
++    }
++
++    return os->length;
++}
++
++#endif
++
++const EVP_PKEY_ASN1_METHOD hmac_asn1_meth = {
++    EVP_PKEY_HMAC,
++    EVP_PKEY_HMAC,
++    0,
++
++    "HMAC",
++    "OpenSSL HMAC method",
++
++    0, 0, hmac_pkey_public_cmp, 0,
++
++    0, 0, 0,
++
++    hmac_size,
++    0, 0,
++    0, 0, 0, 0, 0, 0, 0,
++
++    hmac_key_free,
++    hmac_pkey_ctrl,
++#ifdef HMAC_TEST_PRIVATE_KEY_FORMAT
++    old_hmac_decode,
++    old_hmac_encode
++#else
++    0, 0
++#endif
++};
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/hmac/hm_pmeth.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/hmac/hm_pmeth.c
+new file mode 100644
+index 0000000..5b98477
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/hmac/hm_pmeth.c
+@@ -0,0 +1,210 @@
++/*
++ * Copyright 2007-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include "internal/cryptlib.h"
++#include 
++#include 
++#include 
++#include 
++#include "internal/evp_int.h"
++
++/* HMAC pkey context structure */
++
++typedef struct {
++    const EVP_MD *md;           /* MD for HMAC use */
++    ASN1_OCTET_STRING ktmp;     /* Temp storage for key */
++    HMAC_CTX *ctx;
++} HMAC_PKEY_CTX;
++
++static int pkey_hmac_init(EVP_PKEY_CTX *ctx)
++{
++    HMAC_PKEY_CTX *hctx;
++
++    hctx = OPENSSL_zalloc(sizeof(*hctx));
++    if (hctx == NULL)
++        return 0;
++    hctx->ktmp.type = V_ASN1_OCTET_STRING;
++    hctx->ctx = HMAC_CTX_new();
++    if (hctx->ctx == NULL) {
++        OPENSSL_free(hctx);
++        return 0;
++    }
++
++    ctx->data = hctx;
++    ctx->keygen_info_count = 0;
++
++    return 1;
++}
++
++static void pkey_hmac_cleanup(EVP_PKEY_CTX *ctx);
++
++static int pkey_hmac_copy(EVP_PKEY_CTX *dst, EVP_PKEY_CTX *src)
++{
++    HMAC_PKEY_CTX *sctx, *dctx;
++
++    /* allocate memory for dst->data and a new HMAC_CTX in dst->data->ctx */
++    if (!pkey_hmac_init(dst))
++        return 0;
++    sctx = EVP_PKEY_CTX_get_data(src);
++    dctx = EVP_PKEY_CTX_get_data(dst);
++    dctx->md = sctx->md;
++    if (!HMAC_CTX_copy(dctx->ctx, sctx->ctx))
++        goto err;
++    if (sctx->ktmp.data) {
++        if (!ASN1_OCTET_STRING_set(&dctx->ktmp,
++                                   sctx->ktmp.data, sctx->ktmp.length))
++            goto err;
++    }
++    return 1;
++err:
++    /* release HMAC_CTX in dst->data->ctx and memory allocated for dst->data */
++    pkey_hmac_cleanup (dst);
++    return 0;
++}
++
++static void pkey_hmac_cleanup(EVP_PKEY_CTX *ctx)
++{
++    HMAC_PKEY_CTX *hctx = EVP_PKEY_CTX_get_data(ctx);
++
++    if (hctx != NULL) {
++        HMAC_CTX_free(hctx->ctx);
++        OPENSSL_clear_free(hctx->ktmp.data, hctx->ktmp.length);
++        OPENSSL_free(hctx);
++        EVP_PKEY_CTX_set_data(ctx, NULL);
++    }
++}
++
++static int pkey_hmac_keygen(EVP_PKEY_CTX *ctx, EVP_PKEY *pkey)
++{
++    ASN1_OCTET_STRING *hkey = NULL;
++    HMAC_PKEY_CTX *hctx = ctx->data;
++    if (!hctx->ktmp.data)
++        return 0;
++    hkey = ASN1_OCTET_STRING_dup(&hctx->ktmp);
++    if (!hkey)
++        return 0;
++    EVP_PKEY_assign(pkey, EVP_PKEY_HMAC, hkey);
++
++    return 1;
++}
++
++static int int_update(EVP_MD_CTX *ctx, const void *data, size_t count)
++{
++    HMAC_PKEY_CTX *hctx = EVP_MD_CTX_pkey_ctx(ctx)->data;
++    if (!HMAC_Update(hctx->ctx, data, count))
++        return 0;
++    return 1;
++}
++
++static int hmac_signctx_init(EVP_PKEY_CTX *ctx, EVP_MD_CTX *mctx)
++{
++    HMAC_PKEY_CTX *hctx = ctx->data;
++    HMAC_CTX_set_flags(hctx->ctx,
++                       EVP_MD_CTX_test_flags(mctx, ~EVP_MD_CTX_FLAG_NO_INIT));
++    EVP_MD_CTX_set_flags(mctx, EVP_MD_CTX_FLAG_NO_INIT);
++    EVP_MD_CTX_set_update_fn(mctx, int_update);
++    return 1;
++}
++
++static int hmac_signctx(EVP_PKEY_CTX *ctx, unsigned char *sig, size_t *siglen,
++                        EVP_MD_CTX *mctx)
++{
++    unsigned int hlen;
++    HMAC_PKEY_CTX *hctx = ctx->data;
++    int l = EVP_MD_CTX_size(mctx);
++
++    if (l < 0)
++        return 0;
++    *siglen = l;
++    if (!sig)
++        return 1;
++
++    if (!HMAC_Final(hctx->ctx, sig, &hlen))
++        return 0;
++    *siglen = (size_t)hlen;
++    return 1;
++}
++
++static int pkey_hmac_ctrl(EVP_PKEY_CTX *ctx, int type, int p1, void *p2)
++{
++    HMAC_PKEY_CTX *hctx = ctx->data;
++    ASN1_OCTET_STRING *key;
++    switch (type) {
++
++    case EVP_PKEY_CTRL_SET_MAC_KEY:
++        if ((!p2 && p1 > 0) || (p1 < -1))
++            return 0;
++        if (!ASN1_OCTET_STRING_set(&hctx->ktmp, p2, p1))
++            return 0;
++        break;
++
++    case EVP_PKEY_CTRL_MD:
++        hctx->md = p2;
++        break;
++
++    case EVP_PKEY_CTRL_DIGESTINIT:
++        key = (ASN1_OCTET_STRING *)ctx->pkey->pkey.ptr;
++        if (!HMAC_Init_ex(hctx->ctx, key->data, key->length, hctx->md,
++                          ctx->engine))
++            return 0;
++        break;
++
++    default:
++        return -2;
++
++    }
++    return 1;
++}
++
++static int pkey_hmac_ctrl_str(EVP_PKEY_CTX *ctx,
++                              const char *type, const char *value)
++{
++    if (!value) {
++        return 0;
++    }
++    if (strcmp(type, "key") == 0)
++        return EVP_PKEY_CTX_str2ctrl(ctx, EVP_PKEY_CTRL_SET_MAC_KEY, value);
++    if (strcmp(type, "hexkey") == 0)
++        return EVP_PKEY_CTX_hex2ctrl(ctx, EVP_PKEY_CTRL_SET_MAC_KEY, value);
++    return -2;
++}
++
++const EVP_PKEY_METHOD hmac_pkey_meth = {
++    EVP_PKEY_HMAC,
++    0,
++    pkey_hmac_init,
++    pkey_hmac_copy,
++    pkey_hmac_cleanup,
++
++    0, 0,
++
++    0,
++    pkey_hmac_keygen,
++
++    0, 0,
++
++    0, 0,
++
++    0, 0,
++
++    hmac_signctx_init,
++    hmac_signctx,
++
++    0, 0,
++
++    0, 0,
++
++    0, 0,
++
++    0, 0,
++
++    pkey_hmac_ctrl,
++    pkey_hmac_ctrl_str
++};
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/hmac/hmac.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/hmac/hmac.c
+new file mode 100644
+index 0000000..3374105
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/hmac/hmac.c
+@@ -0,0 +1,240 @@
++/*
++ * Copyright 1995-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include 
++#include 
++#include "internal/cryptlib.h"
++#include 
++#include 
++#include "hmac_lcl.h"
++
++int HMAC_Init_ex(HMAC_CTX *ctx, const void *key, int len,
++                 const EVP_MD *md, ENGINE *impl)
++{
++    int i, j, reset = 0;
++    unsigned char pad[HMAC_MAX_MD_CBLOCK];
++
++    /* If we are changing MD then we must have a key */
++    if (md != NULL && md != ctx->md && (key == NULL || len < 0))
++        return 0;
++
++    if (md != NULL) {
++        reset = 1;
++        ctx->md = md;
++    } else if (ctx->md) {
++        md = ctx->md;
++    } else {
++        return 0;
++    }
++
++    if (key != NULL) {
++        reset = 1;
++        j = EVP_MD_block_size(md);
++        OPENSSL_assert(j <= (int)sizeof(ctx->key));
++        if (j < len) {
++            if (!EVP_DigestInit_ex(ctx->md_ctx, md, impl))
++                goto err;
++            if (!EVP_DigestUpdate(ctx->md_ctx, key, len))
++                goto err;
++            if (!EVP_DigestFinal_ex(ctx->md_ctx, ctx->key,
++                                    &ctx->key_length))
++                goto err;
++        } else {
++            if (len < 0 || len > (int)sizeof(ctx->key))
++                return 0;
++            memcpy(ctx->key, key, len);
++            ctx->key_length = len;
++        }
++        if (ctx->key_length != HMAC_MAX_MD_CBLOCK)
++            memset(&ctx->key[ctx->key_length], 0,
++                   HMAC_MAX_MD_CBLOCK - ctx->key_length);
++    }
++
++    if (reset) {
++        for (i = 0; i < HMAC_MAX_MD_CBLOCK; i++)
++            pad[i] = 0x36 ^ ctx->key[i];
++        if (!EVP_DigestInit_ex(ctx->i_ctx, md, impl))
++            goto err;
++        if (!EVP_DigestUpdate(ctx->i_ctx, pad, EVP_MD_block_size(md)))
++            goto err;
++
++        for (i = 0; i < HMAC_MAX_MD_CBLOCK; i++)
++            pad[i] = 0x5c ^ ctx->key[i];
++        if (!EVP_DigestInit_ex(ctx->o_ctx, md, impl))
++            goto err;
++        if (!EVP_DigestUpdate(ctx->o_ctx, pad, EVP_MD_block_size(md)))
++            goto err;
++    }
++    if (!EVP_MD_CTX_copy_ex(ctx->md_ctx, ctx->i_ctx))
++        goto err;
++    return 1;
++ err:
++    return 0;
++}
++
++#if OPENSSL_API_COMPAT < 0x10100000L
++int HMAC_Init(HMAC_CTX *ctx, const void *key, int len, const EVP_MD *md)
++{
++    if (key && md)
++        HMAC_CTX_reset(ctx);
++    return HMAC_Init_ex(ctx, key, len, md, NULL);
++}
++#endif
++
++int HMAC_Update(HMAC_CTX *ctx, const unsigned char *data, size_t len)
++{
++    if (!ctx->md)
++        return 0;
++    return EVP_DigestUpdate(ctx->md_ctx, data, len);
++}
++
++int HMAC_Final(HMAC_CTX *ctx, unsigned char *md, unsigned int *len)
++{
++    unsigned int i;
++    unsigned char buf[EVP_MAX_MD_SIZE];
++
++    if (!ctx->md)
++        goto err;
++
++    if (!EVP_DigestFinal_ex(ctx->md_ctx, buf, &i))
++        goto err;
++    if (!EVP_MD_CTX_copy_ex(ctx->md_ctx, ctx->o_ctx))
++        goto err;
++    if (!EVP_DigestUpdate(ctx->md_ctx, buf, i))
++        goto err;
++    if (!EVP_DigestFinal_ex(ctx->md_ctx, md, len))
++        goto err;
++    return 1;
++ err:
++    return 0;
++}
++
++size_t HMAC_size(const HMAC_CTX *ctx)
++{
++    return EVP_MD_size((ctx)->md);
++}
++
++HMAC_CTX *HMAC_CTX_new(void)
++{
++    HMAC_CTX *ctx = OPENSSL_zalloc(sizeof(HMAC_CTX));
++
++    if (ctx != NULL) {
++        if (!HMAC_CTX_reset(ctx)) {
++            HMAC_CTX_free(ctx);
++            return NULL;
++        }
++    }
++    return ctx;
++}
++
++static void hmac_ctx_cleanup(HMAC_CTX *ctx)
++{
++    EVP_MD_CTX_reset(ctx->i_ctx);
++    EVP_MD_CTX_reset(ctx->o_ctx);
++    EVP_MD_CTX_reset(ctx->md_ctx);
++    ctx->md = NULL;
++    ctx->key_length = 0;
++    OPENSSL_cleanse(ctx->key, sizeof(ctx->key));
++}
++
++void HMAC_CTX_free(HMAC_CTX *ctx)
++{
++    if (ctx != NULL) {
++        hmac_ctx_cleanup(ctx);
++        EVP_MD_CTX_free(ctx->i_ctx);
++        EVP_MD_CTX_free(ctx->o_ctx);
++        EVP_MD_CTX_free(ctx->md_ctx);
++        OPENSSL_free(ctx);
++    }
++}
++
++int HMAC_CTX_reset(HMAC_CTX *ctx)
++{
++    hmac_ctx_cleanup(ctx);
++    if (ctx->i_ctx == NULL)
++        ctx->i_ctx = EVP_MD_CTX_new();
++    if (ctx->i_ctx == NULL)
++        goto err;
++    if (ctx->o_ctx == NULL)
++        ctx->o_ctx = EVP_MD_CTX_new();
++    if (ctx->o_ctx == NULL)
++        goto err;
++    if (ctx->md_ctx == NULL)
++        ctx->md_ctx = EVP_MD_CTX_new();
++    if (ctx->md_ctx == NULL)
++        goto err;
++    ctx->md = NULL;
++    return 1;
++ err:
++    hmac_ctx_cleanup(ctx);
++    return 0;
++}
++
++int HMAC_CTX_copy(HMAC_CTX *dctx, HMAC_CTX *sctx)
++{
++    if (!HMAC_CTX_reset(dctx))
++        goto err;
++    if (!EVP_MD_CTX_copy_ex(dctx->i_ctx, sctx->i_ctx))
++        goto err;
++    if (!EVP_MD_CTX_copy_ex(dctx->o_ctx, sctx->o_ctx))
++        goto err;
++    if (!EVP_MD_CTX_copy_ex(dctx->md_ctx, sctx->md_ctx))
++        goto err;
++    memcpy(dctx->key, sctx->key, HMAC_MAX_MD_CBLOCK);
++    dctx->key_length = sctx->key_length;
++    dctx->md = sctx->md;
++    return 1;
++ err:
++    hmac_ctx_cleanup(dctx);
++    return 0;
++}
++
++unsigned char *HMAC(const EVP_MD *evp_md, const void *key, int key_len,
++                    const unsigned char *d, size_t n, unsigned char *md,
++                    unsigned int *md_len)
++{
++    HMAC_CTX *c = NULL;
++    static unsigned char m[EVP_MAX_MD_SIZE];
++    static const unsigned char dummy_key[1] = {'\0'};
++
++    if (md == NULL)
++        md = m;
++    if ((c = HMAC_CTX_new()) == NULL)
++        goto err;
++
++    /* For HMAC_Init_ex, NULL key signals reuse. */
++    if (key == NULL && key_len == 0) {
++        key = dummy_key;
++    }
++
++    if (!HMAC_Init_ex(c, key, key_len, evp_md, NULL))
++        goto err;
++    if (!HMAC_Update(c, d, n))
++        goto err;
++    if (!HMAC_Final(c, md, md_len))
++        goto err;
++    HMAC_CTX_free(c);
++    return md;
++ err:
++    HMAC_CTX_free(c);
++    return NULL;
++}
++
++void HMAC_CTX_set_flags(HMAC_CTX *ctx, unsigned long flags)
++{
++    EVP_MD_CTX_set_flags(ctx->i_ctx, flags);
++    EVP_MD_CTX_set_flags(ctx->o_ctx, flags);
++    EVP_MD_CTX_set_flags(ctx->md_ctx, flags);
++}
++
++const EVP_MD *HMAC_CTX_get_md(const HMAC_CTX *ctx)
++{
++    return ctx->md;
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/hmac/hmac_lcl.h b/CryptoPkg/Library/OpensslLib/openssl/crypto/hmac/hmac_lcl.h
+new file mode 100644
+index 0000000..4c156dc
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/hmac/hmac_lcl.h
+@@ -0,0 +1,33 @@
++/*
++ * Copyright 1995-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#ifndef HEADER_HMAC_LCL_H
++# define HEADER_HMAC_LCL_H
++
++#ifdef  __cplusplus
++extern "C" {
++#endif
++#if 0                            /* emacs indentation fix */
++}
++#endif
++
++struct hmac_ctx_st {
++    const EVP_MD *md;
++    EVP_MD_CTX *md_ctx;
++    EVP_MD_CTX *i_ctx;
++    EVP_MD_CTX *o_ctx;
++    unsigned int key_length;
++    unsigned char key[HMAC_MAX_MD_CBLOCK];
++};
++
++#ifdef __cplusplus
++} /* extern "C" */
++#endif
++
++#endif
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/ia64cpuid.S b/CryptoPkg/Library/OpensslLib/openssl/crypto/ia64cpuid.S
+new file mode 100644
+index 0000000..ffd6d6c
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/ia64cpuid.S
+@@ -0,0 +1,297 @@
++// Copyright 2004-2016 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
++// in the file LICENSE in the source distribution or at
++// https://www.openssl.org/source/license.html
++// Works on all IA-64 platforms: Linux, HP-UX, Win64i...
++// On Win64i compile with ias.exe.
++.text
++
++#if defined(_HPUX_SOURCE) && !defined(_LP64)
++#define	ADDP	addp4
++#else
++#define	ADDP	add
++#endif
++
++.global	OPENSSL_cpuid_setup#
++.proc	OPENSSL_cpuid_setup#
++OPENSSL_cpuid_setup:
++{ .mib;	br.ret.sptk.many	b0		};;
++.endp	OPENSSL_cpuid_setup#
++
++.global	OPENSSL_rdtsc#
++.proc	OPENSSL_rdtsc#
++OPENSSL_rdtsc:
++{ .mib;	mov			r8=ar.itc
++	br.ret.sptk.many	b0		};;
++.endp   OPENSSL_rdtsc#
++
++.global	OPENSSL_atomic_add#
++.proc	OPENSSL_atomic_add#
++.align	32
++OPENSSL_atomic_add:
++{ .mii;	ld4		r2=[r32]
++	nop.i		0
++	nop.i		0		};;
++.Lspin:
++{ .mii;	mov		ar.ccv=r2
++	add		r8=r2,r33
++	mov		r3=r2		};;
++{ .mmi;	mf;;
++	cmpxchg4.acq	r2=[r32],r8,ar.ccv
++	nop.i		0		};;
++{ .mib;	cmp.ne		p6,p0=r2,r3
++	nop.i		0
++(p6)	br.dpnt		.Lspin		};;
++{ .mib;	nop.m		0
++	sxt4		r8=r8
++	br.ret.sptk.many	b0	};;
++.endp	OPENSSL_atomic_add#
++
++// Returns a structure comprising pointer to the top of stack of
++// the caller and pointer beyond backing storage for the current
++// register frame. The latter is required, because it might be
++// insufficient to wipe backing storage for the current frame
++// (as this procedure does), one might have to go further, toward
++// higher addresses to reach for whole "retroactively" saved
++// context...
++.global	OPENSSL_wipe_cpu#
++.proc	OPENSSL_wipe_cpu#
++.align	32
++OPENSSL_wipe_cpu:
++	.prologue
++	.fframe	0
++	.save	ar.pfs,r2
++	.save	ar.lc,r3
++{ .mib;	alloc		r2=ar.pfs,0,96,0,96
++	mov		r3=ar.lc
++	brp.loop.imp	.L_wipe_top,.L_wipe_end-16
++					};;
++{ .mii;	mov		r9=ar.bsp
++	mov		r8=pr
++	mov		ar.lc=96	};;
++	.body
++{ .mii;	add		r9=96*8-8,r9
++	mov		ar.ec=1		};;
++
++// One can sweep double as fast, but then we can't quarantee
++// that backing storage is wiped...
++.L_wipe_top:
++{ .mfi;	st8		[r9]=r0,-8
++	mov		f127=f0
++	mov		r127=r0		}
++{ .mfb;	nop.m		0
++	nop.f		0
++	br.ctop.sptk	.L_wipe_top	};;
++.L_wipe_end:
++
++{ .mfi;	mov		r11=r0
++	mov		f6=f0
++	mov		r14=r0		}
++{ .mfi;	mov		r15=r0
++	mov		f7=f0
++	mov		r16=r0		}
++{ .mfi;	mov		r17=r0
++	mov		f8=f0
++	mov		r18=r0		}
++{ .mfi;	mov		r19=r0
++	mov		f9=f0
++	mov		r20=r0		}
++{ .mfi;	mov		r21=r0
++	mov		f10=f0
++	mov		r22=r0		}
++{ .mfi;	mov		r23=r0
++	mov		f11=f0
++	mov		r24=r0		}
++{ .mfi;	mov		r25=r0
++	mov		f12=f0
++	mov		r26=r0		}
++{ .mfi;	mov		r27=r0
++	mov		f13=f0
++	mov		r28=r0		}
++{ .mfi;	mov		r29=r0
++	mov		f14=f0
++	mov		r30=r0		}
++{ .mfi;	mov		r31=r0
++	mov		f15=f0
++	nop.i		0		}
++{ .mfi;	mov		f16=f0		}
++{ .mfi;	mov		f17=f0		}
++{ .mfi;	mov		f18=f0		}
++{ .mfi;	mov		f19=f0		}
++{ .mfi;	mov		f20=f0		}
++{ .mfi;	mov		f21=f0		}
++{ .mfi;	mov		f22=f0		}
++{ .mfi;	mov		f23=f0		}
++{ .mfi;	mov		f24=f0		}
++{ .mfi;	mov		f25=f0		}
++{ .mfi;	mov		f26=f0		}
++{ .mfi;	mov		f27=f0		}
++{ .mfi;	mov		f28=f0		}
++{ .mfi;	mov		f29=f0		}
++{ .mfi;	mov		f30=f0		}
++{ .mfi;	add		r9=96*8+8,r9
++	mov		f31=f0
++	mov		pr=r8,0x1ffff	}
++{ .mib;	mov		r8=sp
++	mov		ar.lc=r3
++	br.ret.sptk	b0		};;
++.endp	OPENSSL_wipe_cpu#
++
++.global	OPENSSL_cleanse#
++.proc	OPENSSL_cleanse#
++OPENSSL_cleanse:
++{ .mib;	cmp.eq		p6,p0=0,r33	    // len==0
++	ADDP		r32=0,r32
++(p6)	br.ret.spnt	b0		};;
++{ .mib;	and		r2=7,r32
++	cmp.leu		p6,p0=15,r33	    // len>=15
++(p6)	br.cond.dptk	.Lot		};;
++
++.Little:
++{ .mib;	st1		[r32]=r0,1
++	cmp.ltu		p6,p7=1,r33	}  // len>1
++{ .mbb;	add		r33=-1,r33	   // len--
++(p6)	br.cond.dptk	.Little
++(p7)	br.ret.sptk.many	b0	};;
++
++.Lot:
++{ .mib;	cmp.eq		p6,p0=0,r2
++(p6)	br.cond.dptk	.Laligned	};;
++{ .mmi;	st1		[r32]=r0,1;;
++	and		r2=7,r32	}
++{ .mib;	add		r33=-1,r33
++	br		.Lot		};;
++
++.Laligned:
++{ .mmi;	st8		[r32]=r0,8
++	and		r2=-8,r33	    // len&~7
++	add		r33=-8,r33	};; // len-=8
++{ .mib;	cmp.ltu		p6,p0=8,r2	    // ((len+8)&~7)>8
++(p6)	br.cond.dptk	.Laligned	};;
++
++{ .mbb;	cmp.eq		p6,p7=r0,r33
++(p7)	br.cond.dpnt	.Little
++(p6)	br.ret.sptk.many	b0	};;
++.endp	OPENSSL_cleanse#
++
++.global	CRYPTO_memcmp#
++.proc	CRYPTO_memcmp#
++.align	32
++.skip	16
++CRYPTO_memcmp:
++	.prologue
++{ .mib;	mov		r8=0
++	cmp.eq		p6,p0=0,r34	    // len==0?
++(p6)	br.ret.spnt	b0		};;
++	.save		ar.pfs,r2
++{ .mib;	alloc		r2=ar.pfs,3,5,0,8
++	.save		ar.lc,r3
++	mov		r3=ar.lc
++	brp.loop.imp	.Loop_cmp_ctop,.Loop_cmp_cend-16
++					}
++{ .mib;	sub		r10=r34,r0,1
++	.save		pr,r9
++	mov		r9=pr		};;
++{ .mii;	ADDP		r16=0,r32
++	mov		ar.lc=r10
++	mov		ar.ec=4		}
++{ .mib;	ADDP		r17=0,r33
++	mov		pr.rot=1<<16	};;
++
++.Loop_cmp_ctop:
++{ .mib;	(p16)	ld1	r32=[r16],1
++	(p18)	xor	r34=r34,r38	}
++{ .mib;	(p16)	ld1	r36=[r17],1
++	(p19)	or	r8=r8,r35
++	br.ctop.sptk	.Loop_cmp_ctop	};;
++.Loop_cmp_cend:
++
++{ .mib;	cmp.ne		p6,p0=0,r8
++	mov		ar.lc=r3	};;
++{ .mib;
++(p6)	mov		r8=1
++	mov		pr=r9,0x1ffff
++	br.ret.sptk.many	b0	};;
++.endp	CRYPTO_memcmp#
++
++.global	OPENSSL_instrument_bus#
++.proc	OPENSSL_instrument_bus#
++OPENSSL_instrument_bus:
++{ .mmi;	mov		r2=r33
++	ADDP		r32=0,r32	}
++{ .mmi;	mov		r8=ar.itc;;
++	mov		r10=r0
++	mov		r9=r8		};;
++
++{ .mmi;	fc		r32;;
++	ld4		r8=[r32]	};;
++{ .mmi;	mf
++	mov		ar.ccv=r8
++	add		r8=r8,r10	};;
++{ .mmi;	cmpxchg4.acq	r3=[r32],r8,ar.ccv
++					};;
++.Loop:
++{ .mmi;	mov		r8=ar.itc;;
++	sub		r10=r8,r9		// diff=tick-lasttick
++	mov		r9=r8		};;	// lasttick=tick
++{ .mmi;	fc		r32;;
++	ld4		r8=[r32]	};;
++{ .mmi;	mf
++	mov		ar.ccv=r8
++	add		r8=r8,r10	};;
++{ .mmi;	cmpxchg4.acq	r3=[r32],r8,ar.ccv
++	add		r33=-1,r33
++	add		r32=4,r32	};;
++{ .mib;	cmp4.ne		p6,p0=0,r33
++(p6)	br.cond.dptk	.Loop		};;
++
++{ .mib;	sub		r8=r2,r33
++	br.ret.sptk.many	b0	};;
++.endp	OPENSSL_instrument_bus#
++
++.global	OPENSSL_instrument_bus2#
++.proc	OPENSSL_instrument_bus2#
++OPENSSL_instrument_bus2:
++{ .mmi;	mov		r2=r33			// put aside cnt
++	ADDP		r32=0,r32	}
++{ .mmi;	mov		r8=ar.itc;;
++	mov		r10=r0
++	mov		r9=r8		};;
++
++{ .mmi;	fc		r32;;
++	ld4		r8=[r32]	};;
++{ .mmi;	mf
++	mov		ar.ccv=r8
++	add		r8=r8,r10	};;
++{ .mmi;	cmpxchg4.acq	r3=[r32],r8,ar.ccv
++					};;
++
++{ .mmi;	mov		r8=ar.itc;;
++	sub		r10=r8,r9
++	mov		r9=r8		};;
++.Loop2:
++{ .mmi;	mov		r11=r10			// lastdiff=diff
++	add		r34=-1,r34	};;	// --max
++{ .mmi;	fc		r32;;
++	ld4		r8=[r32]
++	cmp4.eq		p6,p0=0,r34	};;
++{ .mmi;	mf
++	mov		ar.ccv=r8
++	add		r8=r8,r10	};;
++{ .mmb;	cmpxchg4.acq	r3=[r32],r8,ar.ccv
++(p6)	br.cond.spnt	.Ldone2		};;
++
++{ .mmi;	mov		r8=ar.itc;;
++	sub		r10=r8,r9		// diff=tick-lasttick
++	mov		r9=r8		};;	// lasttick=tick
++{ .mmi;	cmp.ne		p6,p0=r10,r11;;		// diff!=lastdiff
++(p6)	add		r33=-1,r33	};;	// conditional --cnt
++{ .mib;	cmp4.ne		p7,p0=0,r33
++(p6)	add		r32=4,r32		// conditional ++out
++(p7)	br.cond.dptk	.Loop2		};;
++.Ldone2:
++{ .mib;	sub		r8=r2,r33
++	br.ret.sptk.many	b0	};;
++.endp	OPENSSL_instrument_bus2#
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/idea/build.info b/CryptoPkg/Library/OpensslLib/openssl/crypto/idea/build.info
+new file mode 100644
+index 0000000..2326123
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/idea/build.info
+@@ -0,0 +1,3 @@
++LIBS=../../libcrypto
++SOURCE[../../libcrypto]=\
++        i_cbc.c i_cfb64.c i_ofb64.c i_ecb.c i_skey.c
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/idea/i_cbc.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/idea/i_cbc.c
+new file mode 100644
+index 0000000..a70a868
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/idea/i_cbc.c
+@@ -0,0 +1,122 @@
++/*
++ * Copyright 1995-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include "idea_lcl.h"
++
++void IDEA_cbc_encrypt(const unsigned char *in, unsigned char *out,
++                      long length, IDEA_KEY_SCHEDULE *ks, unsigned char *iv,
++                      int encrypt)
++{
++    register unsigned long tin0, tin1;
++    register unsigned long tout0, tout1, xor0, xor1;
++    register long l = length;
++    unsigned long tin[2];
++
++    if (encrypt) {
++        n2l(iv, tout0);
++        n2l(iv, tout1);
++        iv -= 8;
++        for (l -= 8; l >= 0; l -= 8) {
++            n2l(in, tin0);
++            n2l(in, tin1);
++            tin0 ^= tout0;
++            tin1 ^= tout1;
++            tin[0] = tin0;
++            tin[1] = tin1;
++            IDEA_encrypt(tin, ks);
++            tout0 = tin[0];
++            l2n(tout0, out);
++            tout1 = tin[1];
++            l2n(tout1, out);
++        }
++        if (l != -8) {
++            n2ln(in, tin0, tin1, l + 8);
++            tin0 ^= tout0;
++            tin1 ^= tout1;
++            tin[0] = tin0;
++            tin[1] = tin1;
++            IDEA_encrypt(tin, ks);
++            tout0 = tin[0];
++            l2n(tout0, out);
++            tout1 = tin[1];
++            l2n(tout1, out);
++        }
++        l2n(tout0, iv);
++        l2n(tout1, iv);
++    } else {
++        n2l(iv, xor0);
++        n2l(iv, xor1);
++        iv -= 8;
++        for (l -= 8; l >= 0; l -= 8) {
++            n2l(in, tin0);
++            tin[0] = tin0;
++            n2l(in, tin1);
++            tin[1] = tin1;
++            IDEA_encrypt(tin, ks);
++            tout0 = tin[0] ^ xor0;
++            tout1 = tin[1] ^ xor1;
++            l2n(tout0, out);
++            l2n(tout1, out);
++            xor0 = tin0;
++            xor1 = tin1;
++        }
++        if (l != -8) {
++            n2l(in, tin0);
++            tin[0] = tin0;
++            n2l(in, tin1);
++            tin[1] = tin1;
++            IDEA_encrypt(tin, ks);
++            tout0 = tin[0] ^ xor0;
++            tout1 = tin[1] ^ xor1;
++            l2nn(tout0, tout1, out, l + 8);
++            xor0 = tin0;
++            xor1 = tin1;
++        }
++        l2n(xor0, iv);
++        l2n(xor1, iv);
++    }
++    tin0 = tin1 = tout0 = tout1 = xor0 = xor1 = 0;
++    tin[0] = tin[1] = 0;
++}
++
++void IDEA_encrypt(unsigned long *d, IDEA_KEY_SCHEDULE *key)
++{
++    register IDEA_INT *p;
++    register unsigned long x1, x2, x3, x4, t0, t1, ul;
++
++    x2 = d[0];
++    x1 = (x2 >> 16);
++    x4 = d[1];
++    x3 = (x4 >> 16);
++
++    p = &(key->data[0][0]);
++
++    E_IDEA(0);
++    E_IDEA(1);
++    E_IDEA(2);
++    E_IDEA(3);
++    E_IDEA(4);
++    E_IDEA(5);
++    E_IDEA(6);
++    E_IDEA(7);
++
++    x1 &= 0xffff;
++    idea_mul(x1, x1, *p, ul);
++    p++;
++
++    t0 = x3 + *(p++);
++    t1 = x2 + *(p++);
++
++    x4 &= 0xffff;
++    idea_mul(x4, x4, *p, ul);
++
++    d[0] = (t0 & 0xffff) | ((x1 & 0xffff) << 16);
++    d[1] = (x4 & 0xffff) | ((t1 & 0xffff) << 16);
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/idea/i_cfb64.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/idea/i_cfb64.c
+new file mode 100644
+index 0000000..daf467e
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/idea/i_cfb64.c
+@@ -0,0 +1,74 @@
++/*
++ * Copyright 1995-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include "idea_lcl.h"
++
++/*
++ * The input and output encrypted as though 64bit cfb mode is being used.
++ * The extra state information to record how much of the 64bit block we have
++ * used is contained in *num;
++ */
++
++void IDEA_cfb64_encrypt(const unsigned char *in, unsigned char *out,
++                        long length, IDEA_KEY_SCHEDULE *schedule,
++                        unsigned char *ivec, int *num, int encrypt)
++{
++    register unsigned long v0, v1, t;
++    register int n = *num;
++    register long l = length;
++    unsigned long ti[2];
++    unsigned char *iv, c, cc;
++
++    iv = (unsigned char *)ivec;
++    if (encrypt) {
++        while (l--) {
++            if (n == 0) {
++                n2l(iv, v0);
++                ti[0] = v0;
++                n2l(iv, v1);
++                ti[1] = v1;
++                IDEA_encrypt((unsigned long *)ti, schedule);
++                iv = (unsigned char *)ivec;
++                t = ti[0];
++                l2n(t, iv);
++                t = ti[1];
++                l2n(t, iv);
++                iv = (unsigned char *)ivec;
++            }
++            c = *(in++) ^ iv[n];
++            *(out++) = c;
++            iv[n] = c;
++            n = (n + 1) & 0x07;
++        }
++    } else {
++        while (l--) {
++            if (n == 0) {
++                n2l(iv, v0);
++                ti[0] = v0;
++                n2l(iv, v1);
++                ti[1] = v1;
++                IDEA_encrypt((unsigned long *)ti, schedule);
++                iv = (unsigned char *)ivec;
++                t = ti[0];
++                l2n(t, iv);
++                t = ti[1];
++                l2n(t, iv);
++                iv = (unsigned char *)ivec;
++            }
++            cc = *(in++);
++            c = iv[n];
++            iv[n] = cc;
++            *(out++) = c ^ cc;
++            n = (n + 1) & 0x07;
++        }
++    }
++    v0 = v1 = ti[0] = ti[1] = t = c = cc = 0;
++    *num = n;
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/idea/i_ecb.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/idea/i_ecb.c
+new file mode 100644
+index 0000000..2208287
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/idea/i_ecb.c
+@@ -0,0 +1,34 @@
++/*
++ * Copyright 1995-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include "idea_lcl.h"
++#include 
++
++const char *IDEA_options(void)
++{
++    return ("idea(int)");
++}
++
++void IDEA_ecb_encrypt(const unsigned char *in, unsigned char *out,
++                      IDEA_KEY_SCHEDULE *ks)
++{
++    unsigned long l0, l1, d[2];
++
++    n2l(in, l0);
++    d[0] = l0;
++    n2l(in, l1);
++    d[1] = l1;
++    IDEA_encrypt(d, ks);
++    l0 = d[0];
++    l2n(l0, out);
++    l1 = d[1];
++    l2n(l1, out);
++    l0 = l1 = d[0] = d[1] = 0;
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/idea/i_ofb64.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/idea/i_ofb64.c
+new file mode 100644
+index 0000000..997a7b8
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/idea/i_ofb64.c
+@@ -0,0 +1,61 @@
++/*
++ * Copyright 1995-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include "idea_lcl.h"
++
++/*
++ * The input and output encrypted as though 64bit ofb mode is being used.
++ * The extra state information to record how much of the 64bit block we have
++ * used is contained in *num;
++ */
++void IDEA_ofb64_encrypt(const unsigned char *in, unsigned char *out,
++                        long length, IDEA_KEY_SCHEDULE *schedule,
++                        unsigned char *ivec, int *num)
++{
++    register unsigned long v0, v1, t;
++    register int n = *num;
++    register long l = length;
++    unsigned char d[8];
++    register char *dp;
++    unsigned long ti[2];
++    unsigned char *iv;
++    int save = 0;
++
++    iv = (unsigned char *)ivec;
++    n2l(iv, v0);
++    n2l(iv, v1);
++    ti[0] = v0;
++    ti[1] = v1;
++    dp = (char *)d;
++    l2n(v0, dp);
++    l2n(v1, dp);
++    while (l--) {
++        if (n == 0) {
++            IDEA_encrypt((unsigned long *)ti, schedule);
++            dp = (char *)d;
++            t = ti[0];
++            l2n(t, dp);
++            t = ti[1];
++            l2n(t, dp);
++            save++;
++        }
++        *(out++) = *(in++) ^ d[n];
++        n = (n + 1) & 0x07;
++    }
++    if (save) {
++        v0 = ti[0];
++        v1 = ti[1];
++        iv = (unsigned char *)ivec;
++        l2n(v0, iv);
++        l2n(v1, iv);
++    }
++    t = v0 = v1 = ti[0] = ti[1] = 0;
++    *num = n;
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/idea/i_skey.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/idea/i_skey.c
+new file mode 100644
+index 0000000..0285324
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/idea/i_skey.c
+@@ -0,0 +1,112 @@
++/*
++ * Copyright 1995-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include "idea_lcl.h"
++
++static IDEA_INT inverse(unsigned int xin);
++void IDEA_set_encrypt_key(const unsigned char *key, IDEA_KEY_SCHEDULE *ks)
++{
++    int i;
++    register IDEA_INT *kt, *kf, r0, r1, r2;
++
++    kt = &(ks->data[0][0]);
++    n2s(key, kt[0]);
++    n2s(key, kt[1]);
++    n2s(key, kt[2]);
++    n2s(key, kt[3]);
++    n2s(key, kt[4]);
++    n2s(key, kt[5]);
++    n2s(key, kt[6]);
++    n2s(key, kt[7]);
++
++    kf = kt;
++    kt += 8;
++    for (i = 0; i < 6; i++) {
++        r2 = kf[1];
++        r1 = kf[2];
++        *(kt++) = ((r2 << 9) | (r1 >> 7)) & 0xffff;
++        r0 = kf[3];
++        *(kt++) = ((r1 << 9) | (r0 >> 7)) & 0xffff;
++        r1 = kf[4];
++        *(kt++) = ((r0 << 9) | (r1 >> 7)) & 0xffff;
++        r0 = kf[5];
++        *(kt++) = ((r1 << 9) | (r0 >> 7)) & 0xffff;
++        r1 = kf[6];
++        *(kt++) = ((r0 << 9) | (r1 >> 7)) & 0xffff;
++        r0 = kf[7];
++        *(kt++) = ((r1 << 9) | (r0 >> 7)) & 0xffff;
++        r1 = kf[0];
++        if (i >= 5)
++            break;
++        *(kt++) = ((r0 << 9) | (r1 >> 7)) & 0xffff;
++        *(kt++) = ((r1 << 9) | (r2 >> 7)) & 0xffff;
++        kf += 8;
++    }
++}
++
++void IDEA_set_decrypt_key(IDEA_KEY_SCHEDULE *ek, IDEA_KEY_SCHEDULE *dk)
++{
++    int r;
++    register IDEA_INT *fp, *tp, t;
++
++    tp = &(dk->data[0][0]);
++    fp = &(ek->data[8][0]);
++    for (r = 0; r < 9; r++) {
++        *(tp++) = inverse(fp[0]);
++        *(tp++) = ((int)(0x10000L - fp[2]) & 0xffff);
++        *(tp++) = ((int)(0x10000L - fp[1]) & 0xffff);
++        *(tp++) = inverse(fp[3]);
++        if (r == 8)
++            break;
++        fp -= 6;
++        *(tp++) = fp[4];
++        *(tp++) = fp[5];
++    }
++
++    tp = &(dk->data[0][0]);
++    t = tp[1];
++    tp[1] = tp[2];
++    tp[2] = t;
++
++    t = tp[49];
++    tp[49] = tp[50];
++    tp[50] = t;
++}
++
++/* taken directly from the 'paper' I'll have a look at it later */
++static IDEA_INT inverse(unsigned int xin)
++{
++    long n1, n2, q, r, b1, b2, t;
++
++    if (xin == 0)
++        b2 = 0;
++    else {
++        n1 = 0x10001;
++        n2 = xin;
++        b2 = 1;
++        b1 = 0;
++
++        do {
++            r = (n1 % n2);
++            q = (n1 - r) / n2;
++            if (r == 0) {
++                if (b2 < 0)
++                    b2 = 0x10001 + b2;
++            } else {
++                n1 = n2;
++                n2 = r;
++                t = b2;
++                b2 = b1 - q * b2;
++                b1 = t;
++            }
++        } while (r != 0);
++    }
++    return ((IDEA_INT) b2);
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/idea/idea_lcl.h b/CryptoPkg/Library/OpensslLib/openssl/crypto/idea/idea_lcl.h
+new file mode 100644
+index 0000000..f227d0d
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/idea/idea_lcl.h
+@@ -0,0 +1,103 @@
++/*
++ * Copyright 1995-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++/*
++ * The new form of this macro (check if the a*b == 0) was suggested by Colin
++ * Plumb 
++ */
++/* Removal of the inner if from from Wei Dai 24/4/96 */
++#define idea_mul(r,a,b,ul) \
++ul=(unsigned long)a*b; \
++if (ul != 0) \
++        { \
++        r=(ul&0xffff)-(ul>>16); \
++        r-=((r)>>16); \
++        } \
++else \
++        r=(-(int)a-b+1);        /* assuming a or b is 0 and in range */
++
++/*
++ * 7/12/95 - Many thanks to Rhys Weatherley  for
++ * pointing out that I was assuming little endian byte order for all
++ * quantities what idea actually used bigendian.  No where in the spec does
++ * it mention this, it is all in terms of 16 bit numbers and even the example
++ * does not use byte streams for the input example :-(. If you byte swap each
++ * pair of input, keys and iv, the functions would produce the output as the
++ * old version :-(.
++ */
++
++/* NOTE - c is not incremented as per n2l */
++#define n2ln(c,l1,l2,n) { \
++                        c+=n; \
++                        l1=l2=0; \
++                        switch (n) { \
++                        case 8: l2 =((unsigned long)(*(--(c))))    ; \
++                        case 7: l2|=((unsigned long)(*(--(c))))<< 8; \
++                        case 6: l2|=((unsigned long)(*(--(c))))<<16; \
++                        case 5: l2|=((unsigned long)(*(--(c))))<<24; \
++                        case 4: l1 =((unsigned long)(*(--(c))))    ; \
++                        case 3: l1|=((unsigned long)(*(--(c))))<< 8; \
++                        case 2: l1|=((unsigned long)(*(--(c))))<<16; \
++                        case 1: l1|=((unsigned long)(*(--(c))))<<24; \
++                                } \
++                        }
++
++/* NOTE - c is not incremented as per l2n */
++#define l2nn(l1,l2,c,n) { \
++                        c+=n; \
++                        switch (n) { \
++                        case 8: *(--(c))=(unsigned char)(((l2)    )&0xff); \
++                        case 7: *(--(c))=(unsigned char)(((l2)>> 8)&0xff); \
++                        case 6: *(--(c))=(unsigned char)(((l2)>>16)&0xff); \
++                        case 5: *(--(c))=(unsigned char)(((l2)>>24)&0xff); \
++                        case 4: *(--(c))=(unsigned char)(((l1)    )&0xff); \
++                        case 3: *(--(c))=(unsigned char)(((l1)>> 8)&0xff); \
++                        case 2: *(--(c))=(unsigned char)(((l1)>>16)&0xff); \
++                        case 1: *(--(c))=(unsigned char)(((l1)>>24)&0xff); \
++                                } \
++                        }
++
++#undef n2l
++#define n2l(c,l)        (l =((unsigned long)(*((c)++)))<<24L, \
++                         l|=((unsigned long)(*((c)++)))<<16L, \
++                         l|=((unsigned long)(*((c)++)))<< 8L, \
++                         l|=((unsigned long)(*((c)++))))
++
++#undef l2n
++#define l2n(l,c)        (*((c)++)=(unsigned char)(((l)>>24L)&0xff), \
++                         *((c)++)=(unsigned char)(((l)>>16L)&0xff), \
++                         *((c)++)=(unsigned char)(((l)>> 8L)&0xff), \
++                         *((c)++)=(unsigned char)(((l)     )&0xff))
++
++#undef s2n
++#define s2n(l,c)        (*((c)++)=(unsigned char)(((l)     )&0xff), \
++                         *((c)++)=(unsigned char)(((l)>> 8L)&0xff))
++
++#undef n2s
++#define n2s(c,l)        (l =((IDEA_INT)(*((c)++)))<< 8L, \
++                         l|=((IDEA_INT)(*((c)++)))      )
++
++
++#define E_IDEA(num) \
++        x1&=0xffff; \
++        idea_mul(x1,x1,*p,ul); p++; \
++        x2+= *(p++); \
++        x3+= *(p++); \
++        x4&=0xffff; \
++        idea_mul(x4,x4,*p,ul); p++; \
++        t0=(x1^x3)&0xffff; \
++        idea_mul(t0,t0,*p,ul); p++; \
++        t1=(t0+(x2^x4))&0xffff; \
++        idea_mul(t1,t1,*p,ul); p++; \
++        t0+=t1; \
++        x1^=t1; \
++        x4^=t0; \
++        ul=x2^t0; /* do the swap to x3 */ \
++        x2=x3^t1; \
++        x3=ul;
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/include/internal/asn1_int.h b/CryptoPkg/Library/OpensslLib/openssl/crypto/include/internal/asn1_int.h
+new file mode 100644
+index 0000000..f70e3b4
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/include/internal/asn1_int.h
+@@ -0,0 +1,94 @@
++/*
++ * Copyright 2015-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++/* Internal ASN1 structures and functions: not for application use */
++
++/* ASN1 public key method structure */
++
++struct evp_pkey_asn1_method_st {
++    int pkey_id;
++    int pkey_base_id;
++    unsigned long pkey_flags;
++    char *pem_str;
++    char *info;
++    int (*pub_decode) (EVP_PKEY *pk, X509_PUBKEY *pub);
++    int (*pub_encode) (X509_PUBKEY *pub, const EVP_PKEY *pk);
++    int (*pub_cmp) (const EVP_PKEY *a, const EVP_PKEY *b);
++    int (*pub_print) (BIO *out, const EVP_PKEY *pkey, int indent,
++                      ASN1_PCTX *pctx);
++    int (*priv_decode) (EVP_PKEY *pk, const PKCS8_PRIV_KEY_INFO *p8inf);
++    int (*priv_encode) (PKCS8_PRIV_KEY_INFO *p8, const EVP_PKEY *pk);
++    int (*priv_print) (BIO *out, const EVP_PKEY *pkey, int indent,
++                       ASN1_PCTX *pctx);
++    int (*pkey_size) (const EVP_PKEY *pk);
++    int (*pkey_bits) (const EVP_PKEY *pk);
++    int (*pkey_security_bits) (const EVP_PKEY *pk);
++    int (*param_decode) (EVP_PKEY *pkey,
++                         const unsigned char **pder, int derlen);
++    int (*param_encode) (const EVP_PKEY *pkey, unsigned char **pder);
++    int (*param_missing) (const EVP_PKEY *pk);
++    int (*param_copy) (EVP_PKEY *to, const EVP_PKEY *from);
++    int (*param_cmp) (const EVP_PKEY *a, const EVP_PKEY *b);
++    int (*param_print) (BIO *out, const EVP_PKEY *pkey, int indent,
++                        ASN1_PCTX *pctx);
++    int (*sig_print) (BIO *out,
++                      const X509_ALGOR *sigalg, const ASN1_STRING *sig,
++                      int indent, ASN1_PCTX *pctx);
++    void (*pkey_free) (EVP_PKEY *pkey);
++    int (*pkey_ctrl) (EVP_PKEY *pkey, int op, long arg1, void *arg2);
++    /* Legacy functions for old PEM */
++    int (*old_priv_decode) (EVP_PKEY *pkey,
++                            const unsigned char **pder, int derlen);
++    int (*old_priv_encode) (const EVP_PKEY *pkey, unsigned char **pder);
++    /* Custom ASN1 signature verification */
++    int (*item_verify) (EVP_MD_CTX *ctx, const ASN1_ITEM *it, void *asn,
++                        X509_ALGOR *a, ASN1_BIT_STRING *sig, EVP_PKEY *pkey);
++    int (*item_sign) (EVP_MD_CTX *ctx, const ASN1_ITEM *it, void *asn,
++                      X509_ALGOR *alg1, X509_ALGOR *alg2,
++                      ASN1_BIT_STRING *sig);
++} /* EVP_PKEY_ASN1_METHOD */ ;
++
++DEFINE_STACK_OF_CONST(EVP_PKEY_ASN1_METHOD)
++
++extern const EVP_PKEY_ASN1_METHOD cmac_asn1_meth;
++extern const EVP_PKEY_ASN1_METHOD dh_asn1_meth;
++extern const EVP_PKEY_ASN1_METHOD dhx_asn1_meth;
++extern const EVP_PKEY_ASN1_METHOD dsa_asn1_meths[5];
++extern const EVP_PKEY_ASN1_METHOD eckey_asn1_meth;
++extern const EVP_PKEY_ASN1_METHOD ecx25519_asn1_meth;
++extern const EVP_PKEY_ASN1_METHOD hmac_asn1_meth;
++extern const EVP_PKEY_ASN1_METHOD rsa_asn1_meths[2];
++
++/*
++ * These are used internally in the ASN1_OBJECT to keep track of whether the
++ * names and data need to be free()ed
++ */
++# define ASN1_OBJECT_FLAG_DYNAMIC         0x01/* internal use */
++# define ASN1_OBJECT_FLAG_CRITICAL        0x02/* critical x509v3 object id */
++# define ASN1_OBJECT_FLAG_DYNAMIC_STRINGS 0x04/* internal use */
++# define ASN1_OBJECT_FLAG_DYNAMIC_DATA    0x08/* internal use */
++struct asn1_object_st {
++    const char *sn, *ln;
++    int nid;
++    int length;
++    const unsigned char *data;  /* data remains const after init */
++    int flags;                  /* Should we free this one */
++};
++
++/* ASN1 print context structure */
++
++struct asn1_pctx_st {
++    unsigned long flags;
++    unsigned long nm_flags;
++    unsigned long cert_flags;
++    unsigned long oid_flags;
++    unsigned long str_flags;
++} /* ASN1_PCTX */ ;
++
++int asn1_valid_host(const ASN1_STRING *host);
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/include/internal/async.h b/CryptoPkg/Library/OpensslLib/openssl/crypto/include/internal/async.h
+new file mode 100644
+index 0000000..db56258
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/include/internal/async.h
+@@ -0,0 +1,14 @@
++/*
++ * Copyright 2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++
++int async_init(void);
++void async_deinit(void);
++
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/include/internal/bn_conf.h.in b/CryptoPkg/Library/OpensslLib/openssl/crypto/include/internal/bn_conf.h.in
+new file mode 100644
+index 0000000..ec6e4f6
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/include/internal/bn_conf.h.in
+@@ -0,0 +1,27 @@
++{- join("\n",map { "/* $_ */" } @autowarntext) -}
++/*
++ * Copyright 2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#ifndef HEADER_BN_CONF_H
++# define HEADER_BN_CONF_H
++
++/*
++ * The contents of this file are not used in the UEFI build, as
++ * both 32-bit and 64-bit builds are supported from a single run
++ * of the Configure script.
++ */
++
++/* Should we define BN_DIV2W here? */
++
++/* Only one for the following should be defined */
++{- $config{b64l} ? "#define" : "#undef" -} SIXTY_FOUR_BIT_LONG
++{- $config{b64}  ? "#define" : "#undef" -} SIXTY_FOUR_BIT
++{- $config{b32}  ? "#define" : "#undef" -} THIRTY_TWO_BIT
++
++#endif
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/include/internal/bn_dh.h b/CryptoPkg/Library/OpensslLib/openssl/crypto/include/internal/bn_dh.h
+new file mode 100644
+index 0000000..b4bca40
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/include/internal/bn_dh.h
+@@ -0,0 +1,17 @@
++/*
++ * Copyright 2015-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#define declare_dh_bn(x) \
++    const extern BIGNUM _bignum_dh##x##_p;              \
++    const extern BIGNUM _bignum_dh##x##_g;              \
++    const extern BIGNUM _bignum_dh##x##_q;
++
++declare_dh_bn(1024_160)
++declare_dh_bn(2048_224)
++declare_dh_bn(2048_256)
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/include/internal/bn_int.h b/CryptoPkg/Library/OpensslLib/openssl/crypto/include/internal/bn_int.h
+new file mode 100644
+index 0000000..9c984ba
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/include/internal/bn_int.h
+@@ -0,0 +1,82 @@
++/*
++ * Copyright 2014-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#ifndef HEADER_BN_INT_H
++# define HEADER_BN_INT_H
++
++# include 
++# include 
++
++#ifdef  __cplusplus
++extern "C" {
++#endif
++
++BIGNUM *bn_wexpand(BIGNUM *a, int words);
++BIGNUM *bn_expand2(BIGNUM *a, int words);
++
++void bn_correct_top(BIGNUM *a);
++
++/*
++ * Determine the modified width-(w+1) Non-Adjacent Form (wNAF) of 'scalar'.
++ * This is an array r[] of values that are either zero or odd with an
++ * absolute value less than 2^w satisfying scalar = \sum_j r[j]*2^j where at
++ * most one of any w+1 consecutive digits is non-zero with the exception that
++ * the most significant digit may be only w-1 zeros away from that next
++ * non-zero digit.
++ */
++signed char *bn_compute_wNAF(const BIGNUM *scalar, int w, size_t *ret_len);
++
++int bn_get_top(const BIGNUM *a);
++
++void bn_set_top(BIGNUM *a, int top);
++
++int bn_get_dmax(const BIGNUM *a);
++
++/* Set all words to zero */
++void bn_set_all_zero(BIGNUM *a);
++
++/*
++ * Copy the internal BIGNUM words into out which holds size elements (and size
++ * must be bigger than top)
++ */
++int bn_copy_words(BN_ULONG *out, const BIGNUM *in, int size);
++
++BN_ULONG *bn_get_words(const BIGNUM *a);
++
++/*
++ * Set the internal data words in a to point to words which contains size
++ * elements. The BN_FLG_STATIC_DATA flag is set
++ */
++void bn_set_static_words(BIGNUM *a, BN_ULONG *words, int size);
++
++/*
++ * Copy words into the BIGNUM |a|, reallocating space as necessary.
++ * The negative flag of |a| is not modified.
++ * Returns 1 on success and 0 on failure.
++ */
++/*
++ * |num_words| is int because bn_expand2 takes an int. This is an internal
++ * function so we simply trust callers not to pass negative values.
++ */
++int bn_set_words(BIGNUM *a, BN_ULONG *words, int num_words);
++
++size_t bn_sizeof_BIGNUM(void);
++
++/*
++ * Return element el from an array of BIGNUMs starting at base (required
++ * because callers do not know the size of BIGNUM at compilation time)
++ */
++BIGNUM *bn_array_el(BIGNUM *base, int el);
++
++
++#ifdef  __cplusplus
++}
++#endif
++
++#endif
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/include/internal/bn_srp.h b/CryptoPkg/Library/OpensslLib/openssl/crypto/include/internal/bn_srp.h
+new file mode 100644
+index 0000000..844fd01
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/include/internal/bn_srp.h
+@@ -0,0 +1,9 @@
++/*
++ * Copyright 2014-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/include/internal/chacha.h b/CryptoPkg/Library/OpensslLib/openssl/crypto/include/internal/chacha.h
+new file mode 100644
+index 0000000..7d4366e
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/include/internal/chacha.h
+@@ -0,0 +1,49 @@
++/*
++ * Copyright 2015-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#ifndef HEADER_CHACHA_H
++#define HEADER_CHACHA_H
++
++#include 
++
++#ifdef __cplusplus
++extern "C" {
++#endif
++
++/*
++ * ChaCha20_ctr32 encrypts |len| bytes from |inp| with the given key and
++ * nonce and writes the result to |out|, which may be equal to |inp|.
++ * The |key| is not 32 bytes of verbatim key material though, but the
++ * said material collected into 8 32-bit elements array in host byte
++ * order. Same approach applies to nonce: the |counter| argument is
++ * pointer to concatenated nonce and counter values collected into 4
++ * 32-bit elements. This, passing crypto material collected into 32-bit
++ * elements as opposite to passing verbatim byte vectors, is chosen for
++ * efficiency in multi-call scenarios.
++ */
++void ChaCha20_ctr32(unsigned char *out, const unsigned char *inp,
++                    size_t len, const unsigned int key[8],
++                    const unsigned int counter[4]);
++/*
++ * You can notice that there is no key setup procedure. Because it's
++ * as trivial as collecting bytes into 32-bit elements, it's reckoned
++ * that below macro is sufficient.
++ */
++#define CHACHA_U8TOU32(p)  ( \
++                ((unsigned int)(p)[0])     | ((unsigned int)(p)[1]<<8) | \
++                ((unsigned int)(p)[2]<<16) | ((unsigned int)(p)[3]<<24)  )
++
++#define CHACHA_KEY_SIZE		32
++#define CHACHA_CTR_SIZE		16
++#define CHACHA_BLK_SIZE		64
++
++#ifdef __cplusplus
++}
++#endif
++#endif
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/include/internal/cryptlib.h b/CryptoPkg/Library/OpensslLib/openssl/crypto/include/internal/cryptlib.h
+new file mode 100644
+index 0000000..f3ec9b6
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/include/internal/cryptlib.h
+@@ -0,0 +1,81 @@
++/*
++ * Copyright 1995-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#ifndef HEADER_CRYPTLIB_H
++# define HEADER_CRYPTLIB_H
++
++# include 
++# include 
++
++# include "e_os.h"
++
++# ifdef OPENSSL_USE_APPLINK
++#  undef BIO_FLAGS_UPLINK
++#  define BIO_FLAGS_UPLINK 0x8000
++#  include "ms/uplink.h"
++# endif
++
++# include 
++# include 
++# include 
++# include 
++
++#ifdef  __cplusplus
++extern "C" {
++#endif
++
++typedef struct ex_callback_st EX_CALLBACK;
++
++DEFINE_STACK_OF(EX_CALLBACK)
++
++typedef struct app_mem_info_st APP_INFO;
++
++typedef struct mem_st MEM;
++DEFINE_LHASH_OF(MEM);
++
++# ifndef OPENSSL_SYS_VMS
++#  define X509_CERT_AREA          OPENSSLDIR
++#  define X509_CERT_DIR           OPENSSLDIR "/certs"
++#  define X509_CERT_FILE          OPENSSLDIR "/cert.pem"
++#  define X509_PRIVATE_DIR        OPENSSLDIR "/private"
++#  define CTLOG_FILE              OPENSSLDIR "/ct_log_list.cnf"
++# else
++#  define X509_CERT_AREA          "OSSL$DATAROOT:[000000]"
++#  define X509_CERT_DIR           "OSSL$DATAROOT:[CERTS]"
++#  define X509_CERT_FILE          "OSSL$DATAROOT:[000000]cert.pem"
++#  define X509_PRIVATE_DIR        "OSSL$DATAROOT:[PRIVATE]"
++#  define CTLOG_FILE              "OSSL$DATAROOT:[000000]ct_log_list.cnf"
++# endif
++
++# define X509_CERT_DIR_EVP        "SSL_CERT_DIR"
++# define X509_CERT_FILE_EVP       "SSL_CERT_FILE"
++# define CTLOG_FILE_EVP           "CTLOG_FILE"
++
++/* size of string representations */
++# define DECIMAL_SIZE(type)      ((sizeof(type)*8+2)/3+1)
++# define HEX_SIZE(type)          (sizeof(type)*2)
++
++void OPENSSL_cpuid_setup(void);
++extern unsigned int OPENSSL_ia32cap_P[];
++void OPENSSL_showfatal(const char *fmta, ...);
++extern int OPENSSL_NONPIC_relocated;
++void crypto_cleanup_all_ex_data_int(void);
++
++int openssl_strerror_r(int errnum, char *buf, size_t buflen);
++# if !defined(OPENSSL_NO_STDIO)
++FILE *openssl_fopen(const char *filename, const char *mode);
++# else
++void *openssl_fopen(const char *filename, const char *mode);
++# endif
++
++#ifdef  __cplusplus
++}
++#endif
++
++#endif
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/include/internal/cryptlib_int.h b/CryptoPkg/Library/OpensslLib/openssl/crypto/include/internal/cryptlib_int.h
+new file mode 100644
+index 0000000..8e2a719
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/include/internal/cryptlib_int.h
+@@ -0,0 +1,31 @@
++/*
++ * Copyright 2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++
++/* This file is not scanned by mkdef.pl, whereas cryptlib.h is */
++
++struct thread_local_inits_st {
++    int async;
++    int err_state;
++};
++
++int ossl_init_thread_start(uint64_t opts);
++
++/*
++ * OPENSSL_INIT flags. The primary list of these is in crypto.h. Flags below
++ * are those omitted from crypto.h because they are "reserved for internal
++ * use".
++ */
++# define OPENSSL_INIT_ZLIB                   0x00010000L
++
++/* OPENSSL_INIT_THREAD flags */
++# define OPENSSL_INIT_THREAD_ASYNC           0x01
++# define OPENSSL_INIT_THREAD_ERR_STATE       0x02
++
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/include/internal/dso_conf.h.in b/CryptoPkg/Library/OpensslLib/openssl/crypto/include/internal/dso_conf.h.in
+new file mode 100644
+index 0000000..daa5e24
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/include/internal/dso_conf.h.in
+@@ -0,0 +1,15 @@
++{- join("\n",map { "/* $_ */" } @autowarntext) -}
++/*
++ * Copyright 2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#ifndef HEADER_DSO_CONF_H
++# define HEADER_DSO_CONF_H
++
++# define DSO_EXTENSION "{- $target{dso_extension} -}"
++#endif
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/include/internal/engine.h b/CryptoPkg/Library/OpensslLib/openssl/crypto/include/internal/engine.h
+new file mode 100644
+index 0000000..977cf06
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/include/internal/engine.h
+@@ -0,0 +1,20 @@
++/*
++ * Copyright 2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++
++void engine_load_openssl_int(void);
++void engine_load_cryptodev_int(void);
++void engine_load_rdrand_int(void);
++void engine_load_dynamic_int(void);
++void engine_load_padlock_int(void);
++void engine_load_capi_int(void);
++void engine_load_dasync_int(void);
++void engine_load_afalg_int(void);
++void engine_cleanup_int(void);
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/include/internal/err_int.h b/CryptoPkg/Library/OpensslLib/openssl/crypto/include/internal/err_int.h
+new file mode 100644
+index 0000000..7fec3ed
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/include/internal/err_int.h
+@@ -0,0 +1,17 @@
++/*
++ * Copyright 2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#ifndef INTERNAL_ERR_INT_H
++# define INTERNAL_ERR_INT_H
++
++int err_load_crypto_strings_int(void);
++void err_cleanup(void);
++void err_delete_thread_state(void);
++
++#endif
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/include/internal/evp_int.h b/CryptoPkg/Library/OpensslLib/openssl/crypto/include/internal/evp_int.h
+new file mode 100644
+index 0000000..c9ef582
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/include/internal/evp_int.h
+@@ -0,0 +1,389 @@
++/*
++ * Copyright 2015-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++struct evp_pkey_ctx_st {
++    /* Method associated with this operation */
++    const EVP_PKEY_METHOD *pmeth;
++    /* Engine that implements this method or NULL if builtin */
++    ENGINE *engine;
++    /* Key: may be NULL */
++    EVP_PKEY *pkey;
++    /* Peer key for key agreement, may be NULL */
++    EVP_PKEY *peerkey;
++    /* Actual operation */
++    int operation;
++    /* Algorithm specific data */
++    void *data;
++    /* Application specific data */
++    void *app_data;
++    /* Keygen callback */
++    EVP_PKEY_gen_cb *pkey_gencb;
++    /* implementation specific keygen data */
++    int *keygen_info;
++    int keygen_info_count;
++} /* EVP_PKEY_CTX */ ;
++
++#define EVP_PKEY_FLAG_DYNAMIC   1
++
++struct evp_pkey_method_st {
++    int pkey_id;
++    int flags;
++    int (*init) (EVP_PKEY_CTX *ctx);
++    int (*copy) (EVP_PKEY_CTX *dst, EVP_PKEY_CTX *src);
++    void (*cleanup) (EVP_PKEY_CTX *ctx);
++    int (*paramgen_init) (EVP_PKEY_CTX *ctx);
++    int (*paramgen) (EVP_PKEY_CTX *ctx, EVP_PKEY *pkey);
++    int (*keygen_init) (EVP_PKEY_CTX *ctx);
++    int (*keygen) (EVP_PKEY_CTX *ctx, EVP_PKEY *pkey);
++    int (*sign_init) (EVP_PKEY_CTX *ctx);
++    int (*sign) (EVP_PKEY_CTX *ctx, unsigned char *sig, size_t *siglen,
++                 const unsigned char *tbs, size_t tbslen);
++    int (*verify_init) (EVP_PKEY_CTX *ctx);
++    int (*verify) (EVP_PKEY_CTX *ctx,
++                   const unsigned char *sig, size_t siglen,
++                   const unsigned char *tbs, size_t tbslen);
++    int (*verify_recover_init) (EVP_PKEY_CTX *ctx);
++    int (*verify_recover) (EVP_PKEY_CTX *ctx,
++                           unsigned char *rout, size_t *routlen,
++                           const unsigned char *sig, size_t siglen);
++    int (*signctx_init) (EVP_PKEY_CTX *ctx, EVP_MD_CTX *mctx);
++    int (*signctx) (EVP_PKEY_CTX *ctx, unsigned char *sig, size_t *siglen,
++                    EVP_MD_CTX *mctx);
++    int (*verifyctx_init) (EVP_PKEY_CTX *ctx, EVP_MD_CTX *mctx);
++    int (*verifyctx) (EVP_PKEY_CTX *ctx, const unsigned char *sig, int siglen,
++                      EVP_MD_CTX *mctx);
++    int (*encrypt_init) (EVP_PKEY_CTX *ctx);
++    int (*encrypt) (EVP_PKEY_CTX *ctx, unsigned char *out, size_t *outlen,
++                    const unsigned char *in, size_t inlen);
++    int (*decrypt_init) (EVP_PKEY_CTX *ctx);
++    int (*decrypt) (EVP_PKEY_CTX *ctx, unsigned char *out, size_t *outlen,
++                    const unsigned char *in, size_t inlen);
++    int (*derive_init) (EVP_PKEY_CTX *ctx);
++    int (*derive) (EVP_PKEY_CTX *ctx, unsigned char *key, size_t *keylen);
++    int (*ctrl) (EVP_PKEY_CTX *ctx, int type, int p1, void *p2);
++    int (*ctrl_str) (EVP_PKEY_CTX *ctx, const char *type, const char *value);
++} /* EVP_PKEY_METHOD */ ;
++
++DEFINE_STACK_OF_CONST(EVP_PKEY_METHOD)
++
++void evp_pkey_set_cb_translate(BN_GENCB *cb, EVP_PKEY_CTX *ctx);
++
++extern const EVP_PKEY_METHOD cmac_pkey_meth;
++extern const EVP_PKEY_METHOD dh_pkey_meth;
++extern const EVP_PKEY_METHOD dhx_pkey_meth;
++extern const EVP_PKEY_METHOD dsa_pkey_meth;
++extern const EVP_PKEY_METHOD ec_pkey_meth;
++extern const EVP_PKEY_METHOD ecx25519_pkey_meth;
++extern const EVP_PKEY_METHOD hmac_pkey_meth;
++extern const EVP_PKEY_METHOD rsa_pkey_meth;
++extern const EVP_PKEY_METHOD tls1_prf_pkey_meth;
++extern const EVP_PKEY_METHOD hkdf_pkey_meth;
++
++struct evp_md_st {
++    int type;
++    int pkey_type;
++    int md_size;
++    unsigned long flags;
++    int (*init) (EVP_MD_CTX *ctx);
++    int (*update) (EVP_MD_CTX *ctx, const void *data, size_t count);
++    int (*final) (EVP_MD_CTX *ctx, unsigned char *md);
++    int (*copy) (EVP_MD_CTX *to, const EVP_MD_CTX *from);
++    int (*cleanup) (EVP_MD_CTX *ctx);
++    int block_size;
++    int ctx_size;               /* how big does the ctx->md_data need to be */
++    /* control function */
++    int (*md_ctrl) (EVP_MD_CTX *ctx, int cmd, int p1, void *p2);
++} /* EVP_MD */ ;
++
++struct evp_cipher_st {
++    int nid;
++    int block_size;
++    /* Default value for variable length ciphers */
++    int key_len;
++    int iv_len;
++    /* Various flags */
++    unsigned long flags;
++    /* init key */
++    int (*init) (EVP_CIPHER_CTX *ctx, const unsigned char *key,
++                 const unsigned char *iv, int enc);
++    /* encrypt/decrypt data */
++    int (*do_cipher) (EVP_CIPHER_CTX *ctx, unsigned char *out,
++                      const unsigned char *in, size_t inl);
++    /* cleanup ctx */
++    int (*cleanup) (EVP_CIPHER_CTX *);
++    /* how big ctx->cipher_data needs to be */
++    int ctx_size;
++    /* Populate a ASN1_TYPE with parameters */
++    int (*set_asn1_parameters) (EVP_CIPHER_CTX *, ASN1_TYPE *);
++    /* Get parameters from a ASN1_TYPE */
++    int (*get_asn1_parameters) (EVP_CIPHER_CTX *, ASN1_TYPE *);
++    /* Miscellaneous operations */
++    int (*ctrl) (EVP_CIPHER_CTX *, int type, int arg, void *ptr);
++    /* Application data */
++    void *app_data;
++} /* EVP_CIPHER */ ;
++
++/* Macros to code block cipher wrappers */
++
++/* Wrapper functions for each cipher mode */
++
++#define EVP_C_DATA(kstruct, ctx) \
++        ((kstruct *)EVP_CIPHER_CTX_get_cipher_data(ctx))
++
++#define BLOCK_CIPHER_ecb_loop() \
++        size_t i, bl; \
++        bl = EVP_CIPHER_CTX_cipher(ctx)->block_size;    \
++        if (inl < bl) return 1;\
++        inl -= bl; \
++        for (i=0; i <= inl; i+=bl)
++
++#define BLOCK_CIPHER_func_ecb(cname, cprefix, kstruct, ksched) \
++static int cname##_ecb_cipher(EVP_CIPHER_CTX *ctx, unsigned char *out, const unsigned char *in, size_t inl) \
++{\
++        BLOCK_CIPHER_ecb_loop() \
++            cprefix##_ecb_encrypt(in + i, out + i, &EVP_C_DATA(kstruct,ctx)->ksched, EVP_CIPHER_CTX_encrypting(ctx)); \
++        return 1;\
++}
++
++#define EVP_MAXCHUNK ((size_t)1<<(sizeof(long)*8-2))
++
++#define BLOCK_CIPHER_func_ofb(cname, cprefix, cbits, kstruct, ksched) \
++    static int cname##_ofb_cipher(EVP_CIPHER_CTX *ctx, unsigned char *out, const unsigned char *in, size_t inl) \
++{\
++        while(inl>=EVP_MAXCHUNK) {\
++            int num = EVP_CIPHER_CTX_num(ctx);\
++            cprefix##_ofb##cbits##_encrypt(in, out, (long)EVP_MAXCHUNK, &EVP_C_DATA(kstruct,ctx)->ksched, EVP_CIPHER_CTX_iv_noconst(ctx), &num); \
++            EVP_CIPHER_CTX_set_num(ctx, num);\
++            inl-=EVP_MAXCHUNK;\
++            in +=EVP_MAXCHUNK;\
++            out+=EVP_MAXCHUNK;\
++        }\
++        if (inl) {\
++            int num = EVP_CIPHER_CTX_num(ctx);\
++            cprefix##_ofb##cbits##_encrypt(in, out, (long)inl, &EVP_C_DATA(kstruct,ctx)->ksched, EVP_CIPHER_CTX_iv_noconst(ctx), &num); \
++            EVP_CIPHER_CTX_set_num(ctx, num);\
++        }\
++        return 1;\
++}
++
++#define BLOCK_CIPHER_func_cbc(cname, cprefix, kstruct, ksched) \
++static int cname##_cbc_cipher(EVP_CIPHER_CTX *ctx, unsigned char *out, const unsigned char *in, size_t inl) \
++{\
++        while(inl>=EVP_MAXCHUNK) \
++            {\
++            cprefix##_cbc_encrypt(in, out, (long)EVP_MAXCHUNK, &EVP_C_DATA(kstruct,ctx)->ksched, EVP_CIPHER_CTX_iv_noconst(ctx), EVP_CIPHER_CTX_encrypting(ctx));\
++            inl-=EVP_MAXCHUNK;\
++            in +=EVP_MAXCHUNK;\
++            out+=EVP_MAXCHUNK;\
++            }\
++        if (inl)\
++            cprefix##_cbc_encrypt(in, out, (long)inl, &EVP_C_DATA(kstruct,ctx)->ksched, EVP_CIPHER_CTX_iv_noconst(ctx), EVP_CIPHER_CTX_encrypting(ctx));\
++        return 1;\
++}
++
++#define BLOCK_CIPHER_func_cfb(cname, cprefix, cbits, kstruct, ksched)  \
++static int cname##_cfb##cbits##_cipher(EVP_CIPHER_CTX *ctx, unsigned char *out, const unsigned char *in, size_t inl) \
++{\
++    size_t chunk = EVP_MAXCHUNK;\
++    if (cbits == 1)  chunk >>= 3;\
++    if (inl < chunk) chunk = inl;\
++    while (inl && inl >= chunk)\
++    {\
++        int num = EVP_CIPHER_CTX_num(ctx);\
++        cprefix##_cfb##cbits##_encrypt(in, out, (long) \
++            ((cbits == 1) \
++                && !EVP_CIPHER_CTX_test_flags(ctx, EVP_CIPH_FLAG_LENGTH_BITS) \
++                ? inl*8 : inl), \
++            &EVP_C_DATA(kstruct, ctx)->ksched, EVP_CIPHER_CTX_iv_noconst(ctx),\
++            &num, EVP_CIPHER_CTX_encrypting(ctx));\
++        EVP_CIPHER_CTX_set_num(ctx, num);\
++        inl -= chunk;\
++        in += chunk;\
++        out += chunk;\
++        if (inl < chunk) chunk = inl;\
++    }\
++    return 1;\
++}
++
++#define BLOCK_CIPHER_all_funcs(cname, cprefix, cbits, kstruct, ksched) \
++        BLOCK_CIPHER_func_cbc(cname, cprefix, kstruct, ksched) \
++        BLOCK_CIPHER_func_cfb(cname, cprefix, cbits, kstruct, ksched) \
++        BLOCK_CIPHER_func_ecb(cname, cprefix, kstruct, ksched) \
++        BLOCK_CIPHER_func_ofb(cname, cprefix, cbits, kstruct, ksched)
++
++#define BLOCK_CIPHER_def1(cname, nmode, mode, MODE, kstruct, nid, block_size, \
++                          key_len, iv_len, flags, init_key, cleanup, \
++                          set_asn1, get_asn1, ctrl) \
++static const EVP_CIPHER cname##_##mode = { \
++        nid##_##nmode, block_size, key_len, iv_len, \
++        flags | EVP_CIPH_##MODE##_MODE, \
++        init_key, \
++        cname##_##mode##_cipher, \
++        cleanup, \
++        sizeof(kstruct), \
++        set_asn1, get_asn1,\
++        ctrl, \
++        NULL \
++}; \
++const EVP_CIPHER *EVP_##cname##_##mode(void) { return &cname##_##mode; }
++
++#define BLOCK_CIPHER_def_cbc(cname, kstruct, nid, block_size, key_len, \
++                             iv_len, flags, init_key, cleanup, set_asn1, \
++                             get_asn1, ctrl) \
++BLOCK_CIPHER_def1(cname, cbc, cbc, CBC, kstruct, nid, block_size, key_len, \
++                  iv_len, flags, init_key, cleanup, set_asn1, get_asn1, ctrl)
++
++#define BLOCK_CIPHER_def_cfb(cname, kstruct, nid, key_len, \
++                             iv_len, cbits, flags, init_key, cleanup, \
++                             set_asn1, get_asn1, ctrl) \
++BLOCK_CIPHER_def1(cname, cfb##cbits, cfb##cbits, CFB, kstruct, nid, 1, \
++                  key_len, iv_len, flags, init_key, cleanup, set_asn1, \
++                  get_asn1, ctrl)
++
++#define BLOCK_CIPHER_def_ofb(cname, kstruct, nid, key_len, \
++                             iv_len, cbits, flags, init_key, cleanup, \
++                             set_asn1, get_asn1, ctrl) \
++BLOCK_CIPHER_def1(cname, ofb##cbits, ofb, OFB, kstruct, nid, 1, \
++                  key_len, iv_len, flags, init_key, cleanup, set_asn1, \
++                  get_asn1, ctrl)
++
++#define BLOCK_CIPHER_def_ecb(cname, kstruct, nid, block_size, key_len, \
++                             flags, init_key, cleanup, set_asn1, \
++                             get_asn1, ctrl) \
++BLOCK_CIPHER_def1(cname, ecb, ecb, ECB, kstruct, nid, block_size, key_len, \
++                  0, flags, init_key, cleanup, set_asn1, get_asn1, ctrl)
++
++#define BLOCK_CIPHER_defs(cname, kstruct, \
++                          nid, block_size, key_len, iv_len, cbits, flags, \
++                          init_key, cleanup, set_asn1, get_asn1, ctrl) \
++BLOCK_CIPHER_def_cbc(cname, kstruct, nid, block_size, key_len, iv_len, flags, \
++                     init_key, cleanup, set_asn1, get_asn1, ctrl) \
++BLOCK_CIPHER_def_cfb(cname, kstruct, nid, key_len, iv_len, cbits, \
++                     flags, init_key, cleanup, set_asn1, get_asn1, ctrl) \
++BLOCK_CIPHER_def_ofb(cname, kstruct, nid, key_len, iv_len, cbits, \
++                     flags, init_key, cleanup, set_asn1, get_asn1, ctrl) \
++BLOCK_CIPHER_def_ecb(cname, kstruct, nid, block_size, key_len, flags, \
++                     init_key, cleanup, set_asn1, get_asn1, ctrl)
++
++/*-
++#define BLOCK_CIPHER_defs(cname, kstruct, \
++                                nid, block_size, key_len, iv_len, flags,\
++                                 init_key, cleanup, set_asn1, get_asn1, ctrl)\
++static const EVP_CIPHER cname##_cbc = {\
++        nid##_cbc, block_size, key_len, iv_len, \
++        flags | EVP_CIPH_CBC_MODE,\
++        init_key,\
++        cname##_cbc_cipher,\
++        cleanup,\
++        sizeof(EVP_CIPHER_CTX)-sizeof((((EVP_CIPHER_CTX *)NULL)->c))+\
++                sizeof((((EVP_CIPHER_CTX *)NULL)->c.kstruct)),\
++        set_asn1, get_asn1,\
++        ctrl, \
++        NULL \
++};\
++const EVP_CIPHER *EVP_##cname##_cbc(void) { return &cname##_cbc; }\
++static const EVP_CIPHER cname##_cfb = {\
++        nid##_cfb64, 1, key_len, iv_len, \
++        flags | EVP_CIPH_CFB_MODE,\
++        init_key,\
++        cname##_cfb_cipher,\
++        cleanup,\
++        sizeof(EVP_CIPHER_CTX)-sizeof((((EVP_CIPHER_CTX *)NULL)->c))+\
++                sizeof((((EVP_CIPHER_CTX *)NULL)->c.kstruct)),\
++        set_asn1, get_asn1,\
++        ctrl,\
++        NULL \
++};\
++const EVP_CIPHER *EVP_##cname##_cfb(void) { return &cname##_cfb; }\
++static const EVP_CIPHER cname##_ofb = {\
++        nid##_ofb64, 1, key_len, iv_len, \
++        flags | EVP_CIPH_OFB_MODE,\
++        init_key,\
++        cname##_ofb_cipher,\
++        cleanup,\
++        sizeof(EVP_CIPHER_CTX)-sizeof((((EVP_CIPHER_CTX *)NULL)->c))+\
++                sizeof((((EVP_CIPHER_CTX *)NULL)->c.kstruct)),\
++        set_asn1, get_asn1,\
++        ctrl,\
++        NULL \
++};\
++const EVP_CIPHER *EVP_##cname##_ofb(void) { return &cname##_ofb; }\
++static const EVP_CIPHER cname##_ecb = {\
++        nid##_ecb, block_size, key_len, iv_len, \
++        flags | EVP_CIPH_ECB_MODE,\
++        init_key,\
++        cname##_ecb_cipher,\
++        cleanup,\
++        sizeof(EVP_CIPHER_CTX)-sizeof((((EVP_CIPHER_CTX *)NULL)->c))+\
++                sizeof((((EVP_CIPHER_CTX *)NULL)->c.kstruct)),\
++        set_asn1, get_asn1,\
++        ctrl,\
++        NULL \
++};\
++const EVP_CIPHER *EVP_##cname##_ecb(void) { return &cname##_ecb; }
++*/
++
++#define IMPLEMENT_BLOCK_CIPHER(cname, ksched, cprefix, kstruct, nid, \
++                               block_size, key_len, iv_len, cbits, \
++                               flags, init_key, \
++                               cleanup, set_asn1, get_asn1, ctrl) \
++        BLOCK_CIPHER_all_funcs(cname, cprefix, cbits, kstruct, ksched) \
++        BLOCK_CIPHER_defs(cname, kstruct, nid, block_size, key_len, iv_len, \
++                          cbits, flags, init_key, cleanup, set_asn1, \
++                          get_asn1, ctrl)
++
++#define IMPLEMENT_CFBR(cipher,cprefix,kstruct,ksched,keysize,cbits,iv_len,fl) \
++        BLOCK_CIPHER_func_cfb(cipher##_##keysize,cprefix,cbits,kstruct,ksched) \
++        BLOCK_CIPHER_def_cfb(cipher##_##keysize,kstruct, \
++                             NID_##cipher##_##keysize, keysize/8, iv_len, cbits, \
++                             (fl)|EVP_CIPH_FLAG_DEFAULT_ASN1, \
++                             cipher##_init_key, NULL, NULL, NULL, NULL)
++
++
++/*
++ * Type needs to be a bit field Sub-type needs to be for variations on the
++ * method, as in, can it do arbitrary encryption....
++ */
++struct evp_pkey_st {
++    int type;
++    int save_type;
++    int references;
++    const EVP_PKEY_ASN1_METHOD *ameth;
++    ENGINE *engine;
++    union {
++        void *ptr;
++# ifndef OPENSSL_NO_RSA
++        struct rsa_st *rsa;     /* RSA */
++# endif
++# ifndef OPENSSL_NO_DSA
++        struct dsa_st *dsa;     /* DSA */
++# endif
++# ifndef OPENSSL_NO_DH
++        struct dh_st *dh;       /* DH */
++# endif
++# ifndef OPENSSL_NO_EC
++        struct ec_key_st *ec;   /* ECC */
++# endif
++    } pkey;
++    int save_parameters;
++    STACK_OF(X509_ATTRIBUTE) *attributes; /* [ 0 ] */
++    CRYPTO_RWLOCK *lock;
++} /* EVP_PKEY */ ;
++
++
++void openssl_add_all_ciphers_int(void);
++void openssl_add_all_digests_int(void);
++void evp_cleanup_int(void);
++
++/* Pulling defines out of C soure files */
++
++#define EVP_RC4_KEY_SIZE 16
++#ifndef TLS1_1_VERSION
++# define TLS1_1_VERSION   0x0302
++#endif
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/include/internal/md32_common.h b/CryptoPkg/Library/OpensslLib/openssl/crypto/include/internal/md32_common.h
+new file mode 100644
+index 0000000..6e4ce14
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/include/internal/md32_common.h
+@@ -0,0 +1,383 @@
++/*
++ * Copyright 1999-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++/*-
++ * This is a generic 32 bit "collector" for message digest algorithms.
++ * Whenever needed it collects input character stream into chunks of
++ * 32 bit values and invokes a block function that performs actual hash
++ * calculations.
++ *
++ * Porting guide.
++ *
++ * Obligatory macros:
++ *
++ * DATA_ORDER_IS_BIG_ENDIAN or DATA_ORDER_IS_LITTLE_ENDIAN
++ *      this macro defines byte order of input stream.
++ * HASH_CBLOCK
++ *      size of a unit chunk HASH_BLOCK operates on.
++ * HASH_LONG
++ *      has to be at lest 32 bit wide.
++ * HASH_CTX
++ *      context structure that at least contains following
++ *      members:
++ *              typedef struct {
++ *                      ...
++ *                      HASH_LONG       Nl,Nh;
++ *                      either {
++ *                      HASH_LONG       data[HASH_LBLOCK];
++ *                      unsigned char   data[HASH_CBLOCK];
++ *                      };
++ *                      unsigned int    num;
++ *                      ...
++ *                      } HASH_CTX;
++ *      data[] vector is expected to be zeroed upon first call to
++ *      HASH_UPDATE.
++ * HASH_UPDATE
++ *      name of "Update" function, implemented here.
++ * HASH_TRANSFORM
++ *      name of "Transform" function, implemented here.
++ * HASH_FINAL
++ *      name of "Final" function, implemented here.
++ * HASH_BLOCK_DATA_ORDER
++ *      name of "block" function capable of treating *unaligned* input
++ *      message in original (data) byte order, implemented externally.
++ * HASH_MAKE_STRING
++ *      macro convering context variables to an ASCII hash string.
++ *
++ * MD5 example:
++ *
++ *      #define DATA_ORDER_IS_LITTLE_ENDIAN
++ *
++ *      #define HASH_LONG               MD5_LONG
++ *      #define HASH_CTX                MD5_CTX
++ *      #define HASH_CBLOCK             MD5_CBLOCK
++ *      #define HASH_UPDATE             MD5_Update
++ *      #define HASH_TRANSFORM          MD5_Transform
++ *      #define HASH_FINAL              MD5_Final
++ *      #define HASH_BLOCK_DATA_ORDER   md5_block_data_order
++ *
++ *                                      
++ */
++
++#include 
++
++#if !defined(DATA_ORDER_IS_BIG_ENDIAN) && !defined(DATA_ORDER_IS_LITTLE_ENDIAN)
++# error "DATA_ORDER must be defined!"
++#endif
++
++#ifndef HASH_CBLOCK
++# error "HASH_CBLOCK must be defined!"
++#endif
++#ifndef HASH_LONG
++# error "HASH_LONG must be defined!"
++#endif
++#ifndef HASH_CTX
++# error "HASH_CTX must be defined!"
++#endif
++
++#ifndef HASH_UPDATE
++# error "HASH_UPDATE must be defined!"
++#endif
++#ifndef HASH_TRANSFORM
++# error "HASH_TRANSFORM must be defined!"
++#endif
++#ifndef HASH_FINAL
++# error "HASH_FINAL must be defined!"
++#endif
++
++#ifndef HASH_BLOCK_DATA_ORDER
++# error "HASH_BLOCK_DATA_ORDER must be defined!"
++#endif
++
++/*
++ * Engage compiler specific rotate intrinsic function if available.
++ */
++#undef ROTATE
++#ifndef PEDANTIC
++# if defined(_MSC_VER)
++#  define ROTATE(a,n)   _lrotl(a,n)
++# elif defined(__ICC)
++#  define ROTATE(a,n)   _rotl(a,n)
++# elif defined(__GNUC__) && __GNUC__>=2 && !defined(OPENSSL_NO_ASM) && !defined(OPENSSL_NO_INLINE_ASM)
++  /*
++   * Some GNU C inline assembler templates. Note that these are
++   * rotates by *constant* number of bits! But that's exactly
++   * what we need here...
++   *                                    
++   */
++#  if defined(__i386) || defined(__i386__) || defined(__x86_64) || defined(__x86_64__)
++#   define ROTATE(a,n)  ({ register unsigned int ret;   \
++                                asm (                   \
++                                "roll %1,%0"            \
++                                : "=r"(ret)             \
++                                : "I"(n), "0"((unsigned int)(a))        \
++                                : "cc");                \
++                           ret;                         \
++                        })
++#  elif defined(_ARCH_PPC) || defined(_ARCH_PPC64) || \
++        defined(__powerpc) || defined(__ppc__) || defined(__powerpc64__)
++#   define ROTATE(a,n)  ({ register unsigned int ret;   \
++                                asm (                   \
++                                "rlwinm %0,%1,%2,0,31"  \
++                                : "=r"(ret)             \
++                                : "r"(a), "I"(n));      \
++                           ret;                         \
++                        })
++#  elif defined(__s390x__)
++#   define ROTATE(a,n) ({ register unsigned int ret;    \
++                                asm ("rll %0,%1,%2"     \
++                                : "=r"(ret)             \
++                                : "r"(a), "I"(n));      \
++                          ret;                          \
++                        })
++#  endif
++# endif
++#endif                          /* PEDANTIC */
++
++#ifndef ROTATE
++# define ROTATE(a,n)     (((a)<<(n))|(((a)&0xffffffff)>>(32-(n))))
++#endif
++
++#if defined(DATA_ORDER_IS_BIG_ENDIAN)
++
++# ifndef PEDANTIC
++#  if defined(__GNUC__) && __GNUC__>=2 && !defined(OPENSSL_NO_ASM) && !defined(OPENSSL_NO_INLINE_ASM)
++#   if ((defined(__i386) || defined(__i386__)) && !defined(I386_ONLY)) || \
++      (defined(__x86_64) || defined(__x86_64__))
++#    if !defined(B_ENDIAN)
++    /*
++     * This gives ~30-40% performance improvement in SHA-256 compiled
++     * with gcc [on P4]. Well, first macro to be frank. We can pull
++     * this trick on x86* platforms only, because these CPUs can fetch
++     * unaligned data without raising an exception.
++     */
++#     define HOST_c2l(c,l)        ({ unsigned int r=*((const unsigned int *)(c)); \
++                                   asm ("bswapl %0":"=r"(r):"0"(r));    \
++                                   (c)+=4; (l)=r;                       })
++#     define HOST_l2c(l,c)        ({ unsigned int r=(l);                  \
++                                   asm ("bswapl %0":"=r"(r):"0"(r));    \
++                                   *((unsigned int *)(c))=r; (c)+=4; r; })
++#    endif
++#   elif defined(__aarch64__)
++#    if defined(__BYTE_ORDER__)
++#     if defined(__ORDER_LITTLE_ENDIAN__) && __BYTE_ORDER__==__ORDER_LITTLE_ENDIAN__
++#      define HOST_c2l(c,l)      ({ unsigned int r;              \
++                                   asm ("rev    %w0,%w1"        \
++                                        :"=r"(r)                \
++                                        :"r"(*((const unsigned int *)(c))));\
++                                   (c)+=4; (l)=r;               })
++#      define HOST_l2c(l,c)      ({ unsigned int r;              \
++                                   asm ("rev    %w0,%w1"        \
++                                        :"=r"(r)                \
++                                        :"r"((unsigned int)(l)));\
++                                   *((unsigned int *)(c))=r; (c)+=4; r; })
++#     elif defined(__ORDER_BIG_ENDIAN__) && __BYTE_ORDER__==__ORDER_BIG_ENDIAN__
++#      define HOST_c2l(c,l)      ((l)=*((const unsigned int *)(c)), (c)+=4, (l))
++#      define HOST_l2c(l,c)      (*((unsigned int *)(c))=(l), (c)+=4, (l))
++#     endif
++#    endif
++#   endif
++#  endif
++#  if defined(__s390__) || defined(__s390x__)
++#   define HOST_c2l(c,l) ((l)=*((const unsigned int *)(c)), (c)+=4, (l))
++#   define HOST_l2c(l,c) (*((unsigned int *)(c))=(l), (c)+=4, (l))
++#  endif
++# endif
++
++# ifndef HOST_c2l
++#  define HOST_c2l(c,l)   (l =(((unsigned long)(*((c)++)))<<24),          \
++                         l|=(((unsigned long)(*((c)++)))<<16),          \
++                         l|=(((unsigned long)(*((c)++)))<< 8),          \
++                         l|=(((unsigned long)(*((c)++)))    )           )
++# endif
++# ifndef HOST_l2c
++#  define HOST_l2c(l,c)   (*((c)++)=(unsigned char)(((l)>>24)&0xff),      \
++                         *((c)++)=(unsigned char)(((l)>>16)&0xff),      \
++                         *((c)++)=(unsigned char)(((l)>> 8)&0xff),      \
++                         *((c)++)=(unsigned char)(((l)    )&0xff),      \
++                         l)
++# endif
++
++#elif defined(DATA_ORDER_IS_LITTLE_ENDIAN)
++
++# ifndef PEDANTIC
++#  if defined(__GNUC__) && __GNUC__>=2 && !defined(OPENSSL_NO_ASM) && !defined(OPENSSL_NO_INLINE_ASM)
++#   if defined(__s390x__)
++#    define HOST_c2l(c,l)        ({ asm ("lrv    %0,%1"                  \
++                                   :"=d"(l) :"m"(*(const unsigned int *)(c)));\
++                                   (c)+=4; (l);                         })
++#    define HOST_l2c(l,c)        ({ asm ("strv   %1,%0"                  \
++                                   :"=m"(*(unsigned int *)(c)) :"d"(l));\
++                                   (c)+=4; (l);                         })
++#   endif
++#  endif
++#  if defined(__i386) || defined(__i386__) || defined(__x86_64) || defined(__x86_64__)
++#   ifndef B_ENDIAN
++    /* See comment in DATA_ORDER_IS_BIG_ENDIAN section. */
++#    define HOST_c2l(c,l)        ((l)=*((const unsigned int *)(c)), (c)+=4, l)
++#    define HOST_l2c(l,c)        (*((unsigned int *)(c))=(l), (c)+=4, l)
++#   endif
++#  endif
++# endif
++
++# ifndef HOST_c2l
++#  define HOST_c2l(c,l)   (l =(((unsigned long)(*((c)++)))    ),          \
++                         l|=(((unsigned long)(*((c)++)))<< 8),          \
++                         l|=(((unsigned long)(*((c)++)))<<16),          \
++                         l|=(((unsigned long)(*((c)++)))<<24)           )
++# endif
++# ifndef HOST_l2c
++#  define HOST_l2c(l,c)   (*((c)++)=(unsigned char)(((l)    )&0xff),      \
++                         *((c)++)=(unsigned char)(((l)>> 8)&0xff),      \
++                         *((c)++)=(unsigned char)(((l)>>16)&0xff),      \
++                         *((c)++)=(unsigned char)(((l)>>24)&0xff),      \
++                         l)
++# endif
++
++#endif
++
++/*
++ * Time for some action:-)
++ */
++
++int HASH_UPDATE(HASH_CTX *c, const void *data_, size_t len)
++{
++    const unsigned char *data = data_;
++    unsigned char *p;
++    HASH_LONG l;
++    size_t n;
++
++    if (len == 0)
++        return 1;
++
++    l = (c->Nl + (((HASH_LONG) len) << 3)) & 0xffffffffUL;
++    /*
++     * 95-05-24 eay Fixed a bug with the overflow handling, thanks to Wei Dai
++     *  for pointing it out.
++     */
++    if (l < c->Nl)              /* overflow */
++        c->Nh++;
++    c->Nh += (HASH_LONG) (len >> 29); /* might cause compiler warning on
++                                       * 16-bit */
++    c->Nl = l;
++
++    n = c->num;
++    if (n != 0) {
++        p = (unsigned char *)c->data;
++
++        if (len >= HASH_CBLOCK || len + n >= HASH_CBLOCK) {
++            memcpy(p + n, data, HASH_CBLOCK - n);
++            HASH_BLOCK_DATA_ORDER(c, p, 1);
++            n = HASH_CBLOCK - n;
++            data += n;
++            len -= n;
++            c->num = 0;
++            /*
++             * We use memset rather than OPENSSL_cleanse() here deliberately.
++             * Using OPENSSL_cleanse() here could be a performance issue. It
++             * will get properly cleansed on finalisation so this isn't a
++             * security problem.
++             */
++            memset(p, 0, HASH_CBLOCK); /* keep it zeroed */
++        } else {
++            memcpy(p + n, data, len);
++            c->num += (unsigned int)len;
++            return 1;
++        }
++    }
++
++    n = len / HASH_CBLOCK;
++    if (n > 0) {
++        HASH_BLOCK_DATA_ORDER(c, data, n);
++        n *= HASH_CBLOCK;
++        data += n;
++        len -= n;
++    }
++
++    if (len != 0) {
++        p = (unsigned char *)c->data;
++        c->num = (unsigned int)len;
++        memcpy(p, data, len);
++    }
++    return 1;
++}
++
++void HASH_TRANSFORM(HASH_CTX *c, const unsigned char *data)
++{
++    HASH_BLOCK_DATA_ORDER(c, data, 1);
++}
++
++int HASH_FINAL(unsigned char *md, HASH_CTX *c)
++{
++    unsigned char *p = (unsigned char *)c->data;
++    size_t n = c->num;
++
++    p[n] = 0x80;                /* there is always room for one */
++    n++;
++
++    if (n > (HASH_CBLOCK - 8)) {
++        memset(p + n, 0, HASH_CBLOCK - n);
++        n = 0;
++        HASH_BLOCK_DATA_ORDER(c, p, 1);
++    }
++    memset(p + n, 0, HASH_CBLOCK - 8 - n);
++
++    p += HASH_CBLOCK - 8;
++#if   defined(DATA_ORDER_IS_BIG_ENDIAN)
++    (void)HOST_l2c(c->Nh, p);
++    (void)HOST_l2c(c->Nl, p);
++#elif defined(DATA_ORDER_IS_LITTLE_ENDIAN)
++    (void)HOST_l2c(c->Nl, p);
++    (void)HOST_l2c(c->Nh, p);
++#endif
++    p -= HASH_CBLOCK;
++    HASH_BLOCK_DATA_ORDER(c, p, 1);
++    c->num = 0;
++    OPENSSL_cleanse(p, HASH_CBLOCK);
++
++#ifndef HASH_MAKE_STRING
++# error "HASH_MAKE_STRING must be defined!"
++#else
++    HASH_MAKE_STRING(c, md);
++#endif
++
++    return 1;
++}
++
++#ifndef MD32_REG_T
++# if defined(__alpha) || defined(__sparcv9) || defined(__mips)
++#  define MD32_REG_T long
++/*
++ * This comment was originally written for MD5, which is why it
++ * discusses A-D. But it basically applies to all 32-bit digests,
++ * which is why it was moved to common header file.
++ *
++ * In case you wonder why A-D are declared as long and not
++ * as MD5_LONG. Doing so results in slight performance
++ * boost on LP64 architectures. The catch is we don't
++ * really care if 32 MSBs of a 64-bit register get polluted
++ * with eventual overflows as we *save* only 32 LSBs in
++ * *either* case. Now declaring 'em long excuses the compiler
++ * from keeping 32 MSBs zeroed resulting in 13% performance
++ * improvement under SPARC Solaris7/64 and 5% under AlphaLinux.
++ * Well, to be honest it should say that this *prevents*
++ * performance degradation.
++ *                              
++ */
++# else
++/*
++ * Above is not absolute and there are LP64 compilers that
++ * generate better code if MD32_REG_T is defined int. The above
++ * pre-processor condition reflects the circumstances under which
++ * the conclusion was made and is subject to further extension.
++ *                              
++ */
++#  define MD32_REG_T int
++# endif
++#endif
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/include/internal/objects.h b/CryptoPkg/Library/OpensslLib/openssl/crypto/include/internal/objects.h
+new file mode 100644
+index 0000000..76e1b4d
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/include/internal/objects.h
+@@ -0,0 +1,12 @@
++/*
++ * Copyright 2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++
++void obj_cleanup_int(void);
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/include/internal/poly1305.h b/CryptoPkg/Library/OpensslLib/openssl/crypto/include/internal/poly1305.h
+new file mode 100644
+index 0000000..1bc8716
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/include/internal/poly1305.h
+@@ -0,0 +1,19 @@
++/*
++ * Copyright 2015-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++
++#define POLY1305_BLOCK_SIZE 16
++
++typedef struct poly1305_context POLY1305;
++
++size_t Poly1305_ctx_size(void);
++void Poly1305_Init(POLY1305 *ctx, const unsigned char key[32]);
++void Poly1305_Update(POLY1305 *ctx, const unsigned char *inp, size_t len);
++void Poly1305_Final(POLY1305 *ctx, unsigned char mac[16]);
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/include/internal/rand.h b/CryptoPkg/Library/OpensslLib/openssl/crypto/include/internal/rand.h
+new file mode 100644
+index 0000000..30887c4
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/include/internal/rand.h
+@@ -0,0 +1,20 @@
++/*
++ * Copyright 2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++/*
++ * Licensed under the OpenSSL licenses, (the "License");
++ * you may not use this file except in compliance with the License.
++ * You may obtain a copy of the License at
++ * https://www.openssl.org/source/license.html
++ * or in the file LICENSE in the source distribution.
++ */
++
++#include 
++
++void rand_cleanup_int(void);
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/include/internal/x509_int.h b/CryptoPkg/Library/OpensslLib/openssl/crypto/include/internal/x509_int.h
+new file mode 100644
+index 0000000..2845026
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/include/internal/x509_int.h
+@@ -0,0 +1,267 @@
++/*
++ * Copyright 2015-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++/* Internal X509 structures and functions: not for application use */
++
++/* Note: unless otherwise stated a field pointer is mandatory and should
++ * never be set to NULL: the ASN.1 code and accessors rely on mandatory
++ * fields never being NULL.
++ */
++
++/*
++ * name entry structure, equivalent to AttributeTypeAndValue defined
++ * in RFC5280 et al.
++ */
++struct X509_name_entry_st {
++    ASN1_OBJECT *object;        /* AttributeType */
++    ASN1_STRING *value;         /* AttributeValue */
++    int set;                    /* index of RDNSequence for this entry */
++    int size;                   /* temp variable */
++};
++
++/* Name from RFC 5280. */
++struct X509_name_st {
++    STACK_OF(X509_NAME_ENTRY) *entries; /* DN components */
++    int modified;               /* true if 'bytes' needs to be built */
++    BUF_MEM *bytes;             /* cached encoding: cannot be NULL */
++    /* canonical encoding used for rapid Name comparison */
++    unsigned char *canon_enc;
++    int canon_enclen;
++} /* X509_NAME */ ;
++
++/* PKCS#10 certificate request */
++
++struct X509_req_info_st {
++    ASN1_ENCODING enc;          /* cached encoding of signed part */
++    ASN1_INTEGER *version;      /* version, defaults to v1(0) so can be NULL */
++    X509_NAME *subject;         /* certificate request DN */
++    X509_PUBKEY *pubkey;        /* public key of request */
++    /*
++     * Zero or more attributes.
++     * NB: although attributes is a mandatory field some broken
++     * encodings omit it so this may be NULL in that case.
++     */
++    STACK_OF(X509_ATTRIBUTE) *attributes;
++};
++
++struct X509_req_st {
++    X509_REQ_INFO req_info;     /* signed certificate request data */
++    X509_ALGOR sig_alg;         /* signature algorithm */
++    ASN1_BIT_STRING *signature; /* signature */
++    int references;
++    CRYPTO_RWLOCK *lock;
++};
++
++struct X509_crl_info_st {
++    ASN1_INTEGER *version;      /* version: defaults to v1(0) so may be NULL */
++    X509_ALGOR sig_alg;         /* signature algorithm */
++    X509_NAME *issuer;          /* CRL issuer name */
++    ASN1_TIME *lastUpdate;      /* lastUpdate field */
++    ASN1_TIME *nextUpdate;      /* nextUpdate field: optional */
++    STACK_OF(X509_REVOKED) *revoked;        /* revoked entries: optional */
++    STACK_OF(X509_EXTENSION) *extensions;   /* extensions: optional */
++    ASN1_ENCODING enc;                      /* encoding of signed portion of CRL */
++};
++
++struct X509_crl_st {
++    X509_CRL_INFO crl;          /* signed CRL data */
++    X509_ALGOR sig_alg;         /* CRL signature algorithm */
++    ASN1_BIT_STRING signature;  /* CRL signature */
++    int references;
++    int flags;
++    /*
++     * Cached copies of decoded extension values, since extensions
++     * are optional any of these can be NULL.
++     */
++    AUTHORITY_KEYID *akid;
++    ISSUING_DIST_POINT *idp;
++    /* Convenient breakdown of IDP */
++    int idp_flags;
++    int idp_reasons;
++    /* CRL and base CRL numbers for delta processing */
++    ASN1_INTEGER *crl_number;
++    ASN1_INTEGER *base_crl_number;
++    STACK_OF(GENERAL_NAMES) *issuers;
++    /* hash of CRL */
++    unsigned char sha1_hash[SHA_DIGEST_LENGTH];
++    /* alternative method to handle this CRL */
++    const X509_CRL_METHOD *meth;
++    void *meth_data;
++    CRYPTO_RWLOCK *lock;
++};
++
++struct x509_revoked_st {
++    ASN1_INTEGER serialNumber; /* revoked entry serial number */
++    ASN1_TIME *revocationDate;  /* revocation date */
++    STACK_OF(X509_EXTENSION) *extensions;   /* CRL entry extensions: optional */
++    /* decoded value of CRLissuer extension: set if indirect CRL */
++    STACK_OF(GENERAL_NAME) *issuer;
++    /* revocation reason: set to CRL_REASON_NONE if reason extension absent */
++    int reason;
++    /*
++     * CRL entries are reordered for faster lookup of serial numbers. This
++     * field contains the original load sequence for this entry.
++     */
++    int sequence;
++};
++
++/*
++ * This stuff is certificate "auxiliary info": it contains details which are
++ * useful in certificate stores and databases. When used this is tagged onto
++ * the end of the certificate itself. OpenSSL specific structure not defined
++ * in any RFC.
++ */
++
++struct x509_cert_aux_st {
++    STACK_OF(ASN1_OBJECT) *trust; /* trusted uses */
++    STACK_OF(ASN1_OBJECT) *reject; /* rejected uses */
++    ASN1_UTF8STRING *alias;     /* "friendly name" */
++    ASN1_OCTET_STRING *keyid;   /* key id of private key */
++    STACK_OF(X509_ALGOR) *other; /* other unspecified info */
++};
++
++struct x509_cinf_st {
++    ASN1_INTEGER *version;      /* [ 0 ] default of v1 */
++    ASN1_INTEGER serialNumber;
++    X509_ALGOR signature;
++    X509_NAME *issuer;
++    X509_VAL validity;
++    X509_NAME *subject;
++    X509_PUBKEY *key;
++    ASN1_BIT_STRING *issuerUID; /* [ 1 ] optional in v2 */
++    ASN1_BIT_STRING *subjectUID; /* [ 2 ] optional in v2 */
++    STACK_OF(X509_EXTENSION) *extensions; /* [ 3 ] optional in v3 */
++    ASN1_ENCODING enc;
++};
++
++struct x509_st {
++    X509_CINF cert_info;
++    X509_ALGOR sig_alg;
++    ASN1_BIT_STRING signature;
++    int references;
++    CRYPTO_EX_DATA ex_data;
++    /* These contain copies of various extension values */
++    long ex_pathlen;
++    long ex_pcpathlen;
++    uint32_t ex_flags;
++    uint32_t ex_kusage;
++    uint32_t ex_xkusage;
++    uint32_t ex_nscert;
++    ASN1_OCTET_STRING *skid;
++    AUTHORITY_KEYID *akid;
++    X509_POLICY_CACHE *policy_cache;
++    STACK_OF(DIST_POINT) *crldp;
++    STACK_OF(GENERAL_NAME) *altname;
++    NAME_CONSTRAINTS *nc;
++#ifndef OPENSSL_NO_RFC3779
++    STACK_OF(IPAddressFamily) *rfc3779_addr;
++    struct ASIdentifiers_st *rfc3779_asid;
++# endif
++    unsigned char sha1_hash[SHA_DIGEST_LENGTH];
++    X509_CERT_AUX *aux;
++    CRYPTO_RWLOCK *lock;
++} /* X509 */ ;
++
++/*
++ * This is a used when verifying cert chains.  Since the gathering of the
++ * cert chain can take some time (and have to be 'retried', this needs to be
++ * kept and passed around.
++ */
++struct x509_store_ctx_st {      /* X509_STORE_CTX */
++    X509_STORE *ctx;
++    /* The following are set by the caller */
++    /* The cert to check */
++    X509 *cert;
++    /* chain of X509s - untrusted - passed in */
++    STACK_OF(X509) *untrusted;
++    /* set of CRLs passed in */
++    STACK_OF(X509_CRL) *crls;
++    X509_VERIFY_PARAM *param;
++    /* Other info for use with get_issuer() */
++    void *other_ctx;
++    /* Callbacks for various operations */
++    /* called to verify a certificate */
++    int (*verify) (X509_STORE_CTX *ctx);
++    /* error callback */
++    int (*verify_cb) (int ok, X509_STORE_CTX *ctx);
++    /* get issuers cert from ctx */
++    int (*get_issuer) (X509 **issuer, X509_STORE_CTX *ctx, X509 *x);
++    /* check issued */
++    int (*check_issued) (X509_STORE_CTX *ctx, X509 *x, X509 *issuer);
++    /* Check revocation status of chain */
++    int (*check_revocation) (X509_STORE_CTX *ctx);
++    /* retrieve CRL */
++    int (*get_crl) (X509_STORE_CTX *ctx, X509_CRL **crl, X509 *x);
++    /* Check CRL validity */
++    int (*check_crl) (X509_STORE_CTX *ctx, X509_CRL *crl);
++    /* Check certificate against CRL */
++    int (*cert_crl) (X509_STORE_CTX *ctx, X509_CRL *crl, X509 *x);
++    /* Check policy status of the chain */
++    int (*check_policy) (X509_STORE_CTX *ctx);
++    STACK_OF(X509) *(*lookup_certs) (X509_STORE_CTX *ctx, X509_NAME *nm);
++    STACK_OF(X509_CRL) *(*lookup_crls) (X509_STORE_CTX *ctx, X509_NAME *nm);
++    int (*cleanup) (X509_STORE_CTX *ctx);
++    /* The following is built up */
++    /* if 0, rebuild chain */
++    int valid;
++    /* number of untrusted certs */
++    int num_untrusted;
++    /* chain of X509s - built up and trusted */
++    STACK_OF(X509) *chain;
++    /* Valid policy tree */
++    X509_POLICY_TREE *tree;
++    /* Require explicit policy value */
++    int explicit_policy;
++    /* When something goes wrong, this is why */
++    int error_depth;
++    int error;
++    X509 *current_cert;
++    /* cert currently being tested as valid issuer */
++    X509 *current_issuer;
++    /* current CRL */
++    X509_CRL *current_crl;
++    /* score of current CRL */
++    int current_crl_score;
++    /* Reason mask */
++    unsigned int current_reasons;
++    /* For CRL path validation: parent context */
++    X509_STORE_CTX *parent;
++    CRYPTO_EX_DATA ex_data;
++    SSL_DANE *dane;
++    /* signed via bare TA public key, rather than CA certificate */
++    int bare_ta_signed;
++};
++
++/* PKCS#8 private key info structure */
++
++struct pkcs8_priv_key_info_st {
++    ASN1_INTEGER *version;
++    X509_ALGOR *pkeyalg;
++    ASN1_OCTET_STRING *pkey;
++    STACK_OF(X509_ATTRIBUTE) *attributes;
++};
++
++struct X509_sig_st {
++    X509_ALGOR *algor;
++    ASN1_OCTET_STRING *digest;
++};
++
++struct x509_object_st {
++    /* one of the above types */
++    X509_LOOKUP_TYPE type;
++    union {
++        char *ptr;
++        X509 *x509;
++        X509_CRL *crl;
++        EVP_PKEY *pkey;
++    } data;
++};
++
++int a2i_ipadd(unsigned char *ipout, const char *ipasc);
++int x509_set1_time(ASN1_TIME **ptm, const ASN1_TIME *tm);
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/init.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/init.c
+new file mode 100644
+index 0000000..c730e38
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/init.c
+@@ -0,0 +1,664 @@
++/*
++ * Copyright 2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include 
++#include 
++#include 
++#include 
++#include 
++#include 
++#include 
++#include 
++#include 
++#include 
++#include 
++#include 
++#include 
++#include 
++#include 
++#include 
++
++static int stopped = 0;
++
++static void ossl_init_thread_stop(struct thread_local_inits_st *locals);
++
++static CRYPTO_THREAD_LOCAL threadstopkey;
++
++static void ossl_init_thread_stop_wrap(void *local)
++{
++    ossl_init_thread_stop((struct thread_local_inits_st *)local);
++}
++
++static struct thread_local_inits_st *ossl_init_get_thread_local(int alloc)
++{
++    struct thread_local_inits_st *local =
++        CRYPTO_THREAD_get_local(&threadstopkey);
++
++    if (local == NULL && alloc) {
++        local = OPENSSL_zalloc(sizeof *local);
++        CRYPTO_THREAD_set_local(&threadstopkey, local);
++    }
++    if (!alloc) {
++        CRYPTO_THREAD_set_local(&threadstopkey, NULL);
++    }
++
++    return local;
++}
++
++typedef struct ossl_init_stop_st OPENSSL_INIT_STOP;
++struct ossl_init_stop_st {
++    void (*handler)(void);
++    OPENSSL_INIT_STOP *next;
++};
++
++static OPENSSL_INIT_STOP *stop_handlers = NULL;
++static CRYPTO_RWLOCK *init_lock = NULL;
++
++static CRYPTO_ONCE base = CRYPTO_ONCE_STATIC_INIT;
++static int base_inited = 0;
++DEFINE_RUN_ONCE_STATIC(ossl_init_base)
++{
++#ifdef OPENSSL_INIT_DEBUG
++    fprintf(stderr, "OPENSSL_INIT: ossl_init_base: Setting up stop handlers\n");
++#endif
++    /*
++     * We use a dummy thread local key here. We use the destructor to detect
++     * when the thread is going to stop (where that feature is available)
++     */
++    CRYPTO_THREAD_init_local(&threadstopkey, ossl_init_thread_stop_wrap);
++#ifndef OPENSSL_SYS_UEFI
++    atexit(OPENSSL_cleanup);
++#endif
++    if ((init_lock = CRYPTO_THREAD_lock_new()) == NULL)
++        return 0;
++    OPENSSL_cpuid_setup();
++
++    /*
++     * BIG FAT WARNING!
++     * Everything needed to be initialized in this function before threads
++     * come along MUST happen before base_inited is set to 1, or we will
++     * see race conditions.
++     */
++    base_inited = 1;
++
++#if !defined(OPENSSL_NO_DSO) && !defined(OPENSSL_USE_NODELETE)
++# ifdef DSO_WIN32
++    {
++        HMODULE handle = NULL;
++        BOOL ret;
++
++        /* We don't use the DSO route for WIN32 because there is a better way */
++        ret = GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS
++                                | GET_MODULE_HANDLE_EX_FLAG_PIN,
++                                (void *)&base_inited, &handle);
++
++        return (ret == TRUE) ? 1 : 0;
++    }
++# else
++    /*
++     * Deliberately leak a reference to ourselves. This will force the library
++     * to remain loaded until the atexit() handler is run a process exit.
++     */
++    {
++        DSO *dso = NULL;
++
++        dso = DSO_dsobyaddr(&base_inited, DSO_FLAG_NO_UNLOAD_ON_FREE);
++        DSO_free(dso);
++    }
++# endif
++#endif
++
++    return 1;
++}
++
++static CRYPTO_ONCE load_crypto_strings = CRYPTO_ONCE_STATIC_INIT;
++static int load_crypto_strings_inited = 0;
++DEFINE_RUN_ONCE_STATIC(ossl_init_no_load_crypto_strings)
++{
++    /* Do nothing in this case */
++    return 1;
++}
++
++DEFINE_RUN_ONCE_STATIC(ossl_init_load_crypto_strings)
++{
++    int ret = 1;
++    /*
++     * OPENSSL_NO_AUTOERRINIT is provided here to prevent at compile time
++     * pulling in all the error strings during static linking
++     */
++#if !defined(OPENSSL_NO_ERR) && !defined(OPENSSL_NO_AUTOERRINIT)
++# ifdef OPENSSL_INIT_DEBUG
++    fprintf(stderr, "OPENSSL_INIT: ossl_init_load_crypto_strings: "
++                    "err_load_crypto_strings_int()\n");
++# endif
++    ret = err_load_crypto_strings_int();
++    load_crypto_strings_inited = 1;
++#endif    
++    return ret;
++}
++
++static CRYPTO_ONCE add_all_ciphers = CRYPTO_ONCE_STATIC_INIT;
++DEFINE_RUN_ONCE_STATIC(ossl_init_add_all_ciphers)
++{
++    /*
++     * OPENSSL_NO_AUTOALGINIT is provided here to prevent at compile time
++     * pulling in all the ciphers during static linking
++     */
++#ifndef OPENSSL_NO_AUTOALGINIT
++# ifdef OPENSSL_INIT_DEBUG
++    fprintf(stderr, "OPENSSL_INIT: ossl_init_add_all_ciphers: "
++                    "openssl_add_all_ciphers_int()\n");
++# endif
++    openssl_add_all_ciphers_int();
++#endif
++    return 1;
++}
++
++static CRYPTO_ONCE add_all_digests = CRYPTO_ONCE_STATIC_INIT;
++DEFINE_RUN_ONCE_STATIC(ossl_init_add_all_digests)
++{
++    /*
++     * OPENSSL_NO_AUTOALGINIT is provided here to prevent at compile time
++     * pulling in all the ciphers during static linking
++     */
++#ifndef OPENSSL_NO_AUTOALGINIT
++# ifdef OPENSSL_INIT_DEBUG
++    fprintf(stderr, "OPENSSL_INIT: ossl_init_add_all_digests: "
++                    "openssl_add_all_digests()\n");
++# endif
++    openssl_add_all_digests_int();
++#endif
++    return 1;
++}
++
++DEFINE_RUN_ONCE_STATIC(ossl_init_no_add_algs)
++{
++    /* Do nothing */
++    return 1;
++}
++
++static CRYPTO_ONCE config = CRYPTO_ONCE_STATIC_INIT;
++static int config_inited = 0;
++static const char *appname;
++DEFINE_RUN_ONCE_STATIC(ossl_init_config)
++{
++#ifdef OPENSSL_INIT_DEBUG
++    fprintf(stderr,
++            "OPENSSL_INIT: ossl_init_config: openssl_config(%s)\n",
++            appname == NULL ? "NULL" : appname);
++#endif
++    openssl_config_int(appname);
++    config_inited = 1;
++    return 1;
++}
++DEFINE_RUN_ONCE_STATIC(ossl_init_no_config)
++{
++#ifdef OPENSSL_INIT_DEBUG
++    fprintf(stderr,
++            "OPENSSL_INIT: ossl_init_config: openssl_no_config_int()\n");
++#endif
++    openssl_no_config_int();
++    config_inited = 1;
++    return 1;
++}
++
++static CRYPTO_ONCE async = CRYPTO_ONCE_STATIC_INIT;
++static int async_inited = 0;
++DEFINE_RUN_ONCE_STATIC(ossl_init_async)
++{
++#ifdef OPENSSL_INIT_DEBUG
++    fprintf(stderr, "OPENSSL_INIT: ossl_init_async: async_init()\n");
++#endif
++    if (!async_init())
++        return 0;
++    async_inited = 1;
++    return 1;
++}
++
++#ifndef OPENSSL_NO_ENGINE
++static CRYPTO_ONCE engine_openssl = CRYPTO_ONCE_STATIC_INIT;
++DEFINE_RUN_ONCE_STATIC(ossl_init_engine_openssl)
++{
++# ifdef OPENSSL_INIT_DEBUG
++    fprintf(stderr, "OPENSSL_INIT: ossl_init_engine_openssl: "
++                    "engine_load_openssl_int()\n");
++# endif
++    engine_load_openssl_int();
++    return 1;
++}
++# if !defined(OPENSSL_NO_HW) && \
++    (defined(__OpenBSD__) || defined(__FreeBSD__) || defined(HAVE_CRYPTODEV))
++static CRYPTO_ONCE engine_cryptodev = CRYPTO_ONCE_STATIC_INIT;
++DEFINE_RUN_ONCE_STATIC(ossl_init_engine_cryptodev)
++{
++#  ifdef OPENSSL_INIT_DEBUG
++    fprintf(stderr, "OPENSSL_INIT: ossl_init_engine_cryptodev: "
++                    "engine_load_cryptodev_int()\n");
++#  endif
++    engine_load_cryptodev_int();
++    return 1;
++}
++# endif
++
++# ifndef OPENSSL_NO_RDRAND
++static CRYPTO_ONCE engine_rdrand = CRYPTO_ONCE_STATIC_INIT;
++DEFINE_RUN_ONCE_STATIC(ossl_init_engine_rdrand)
++{
++#  ifdef OPENSSL_INIT_DEBUG
++    fprintf(stderr, "OPENSSL_INIT: ossl_init_engine_rdrand: "
++                    "engine_load_rdrand_int()\n");
++#  endif
++    engine_load_rdrand_int();
++    return 1;
++}
++# endif
++static CRYPTO_ONCE engine_dynamic = CRYPTO_ONCE_STATIC_INIT;
++DEFINE_RUN_ONCE_STATIC(ossl_init_engine_dynamic)
++{
++# ifdef OPENSSL_INIT_DEBUG
++    fprintf(stderr, "OPENSSL_INIT: ossl_init_engine_dynamic: "
++                    "engine_load_dynamic_int()\n");
++# endif
++    engine_load_dynamic_int();
++    return 1;
++}
++# ifndef OPENSSL_NO_STATIC_ENGINE
++#  if !defined(OPENSSL_NO_HW) && !defined(OPENSSL_NO_HW_PADLOCK)
++static CRYPTO_ONCE engine_padlock = CRYPTO_ONCE_STATIC_INIT;
++DEFINE_RUN_ONCE_STATIC(ossl_init_engine_padlock)
++{
++#   ifdef OPENSSL_INIT_DEBUG
++    fprintf(stderr, "OPENSSL_INIT: ossl_init_engine_padlock: "
++                    "engine_load_padlock_int()\n");
++#   endif
++    engine_load_padlock_int();
++    return 1;
++}
++#  endif
++#  if defined(OPENSSL_SYS_WIN32) && !defined(OPENSSL_NO_CAPIENG)
++static CRYPTO_ONCE engine_capi = CRYPTO_ONCE_STATIC_INIT;
++DEFINE_RUN_ONCE_STATIC(ossl_init_engine_capi)
++{
++#   ifdef OPENSSL_INIT_DEBUG
++    fprintf(stderr, "OPENSSL_INIT: ossl_init_engine_capi: "
++                    "engine_load_capi_int()\n");
++#   endif
++    engine_load_capi_int();
++    return 1;
++}
++#  endif
++#  if !defined(OPENSSL_NO_AFALGENG)
++static CRYPTO_ONCE engine_afalg = CRYPTO_ONCE_STATIC_INIT;
++DEFINE_RUN_ONCE_STATIC(ossl_init_engine_afalg)
++{
++#   ifdef OPENSSL_INIT_DEBUG
++    fprintf(stderr, "OPENSSL_INIT: ossl_init_engine_afalg: "
++                    "engine_load_afalg_int()\n");
++#   endif
++    engine_load_afalg_int();
++    return 1;
++}
++#  endif
++# endif
++#endif
++
++#ifndef OPENSSL_NO_COMP
++static CRYPTO_ONCE zlib = CRYPTO_ONCE_STATIC_INIT;
++
++static int zlib_inited = 0;
++DEFINE_RUN_ONCE_STATIC(ossl_init_zlib)
++{
++    /* Do nothing - we need to know about this for the later cleanup */
++    zlib_inited = 1;
++    return 1;
++}
++#endif
++
++static void ossl_init_thread_stop(struct thread_local_inits_st *locals)
++{
++    /* Can't do much about this */
++    if (locals == NULL)
++        return;
++
++    if (locals->async) {
++#ifdef OPENSSL_INIT_DEBUG
++        fprintf(stderr, "OPENSSL_INIT: ossl_init_thread_stop: "
++                        "ASYNC_cleanup_thread()\n");
++#endif
++        ASYNC_cleanup_thread();
++    }
++
++    if (locals->err_state) {
++#ifdef OPENSSL_INIT_DEBUG
++        fprintf(stderr, "OPENSSL_INIT: ossl_init_thread_stop: "
++                        "err_delete_thread_state()\n");
++#endif
++        err_delete_thread_state();
++    }
++
++    OPENSSL_free(locals);
++}
++
++void OPENSSL_thread_stop(void)
++{
++    ossl_init_thread_stop(
++        (struct thread_local_inits_st *)ossl_init_get_thread_local(0));
++}
++
++int ossl_init_thread_start(uint64_t opts)
++{
++    struct thread_local_inits_st *locals = ossl_init_get_thread_local(1);
++
++    if (locals == NULL)
++        return 0;
++
++    if (opts & OPENSSL_INIT_THREAD_ASYNC) {
++#ifdef OPENSSL_INIT_DEBUG
++        fprintf(stderr, "OPENSSL_INIT: ossl_init_thread_start: "
++                        "marking thread for async\n");
++#endif
++        locals->async = 1;
++    }
++
++    if (opts & OPENSSL_INIT_THREAD_ERR_STATE) {
++#ifdef OPENSSL_INIT_DEBUG
++        fprintf(stderr, "OPENSSL_INIT: ossl_init_thread_start: "
++                        "marking thread for err_state\n");
++#endif
++        locals->err_state = 1;
++    }
++
++    return 1;
++}
++
++void OPENSSL_cleanup(void)
++{
++    OPENSSL_INIT_STOP *currhandler, *lasthandler;
++
++    /* If we've not been inited then no need to deinit */
++    if (!base_inited)
++        return;
++
++    /* Might be explicitly called and also by atexit */
++    if (stopped)
++        return;
++    stopped = 1;
++
++    /*
++     * Thread stop may not get automatically called by the thread library for
++     * the very last thread in some situations, so call it directly.
++     */
++    ossl_init_thread_stop(ossl_init_get_thread_local(0));
++
++    currhandler = stop_handlers;
++    while (currhandler != NULL) {
++        currhandler->handler();
++        lasthandler = currhandler;
++        currhandler = currhandler->next;
++        OPENSSL_free(lasthandler);
++    }
++    stop_handlers = NULL;
++
++    CRYPTO_THREAD_lock_free(init_lock);
++
++    /*
++     * We assume we are single-threaded for this function, i.e. no race
++     * conditions for the various "*_inited" vars below.
++     */
++
++#ifndef OPENSSL_NO_COMP
++    if (zlib_inited) {
++#ifdef OPENSSL_INIT_DEBUG
++        fprintf(stderr, "OPENSSL_INIT: OPENSSL_cleanup: "
++                        "comp_zlib_cleanup_int()\n");
++#endif
++        comp_zlib_cleanup_int();
++    }
++#endif
++
++    if (async_inited) {
++# ifdef OPENSSL_INIT_DEBUG
++        fprintf(stderr, "OPENSSL_INIT: OPENSSL_cleanup: "
++                        "async_deinit()\n");
++# endif
++        async_deinit();
++    }
++
++    if (load_crypto_strings_inited) {
++#ifdef OPENSSL_INIT_DEBUG
++        fprintf(stderr, "OPENSSL_INIT: OPENSSL_cleanup: "
++                        "err_free_strings_int()\n");
++#endif
++        err_free_strings_int();
++    }
++
++    CRYPTO_THREAD_cleanup_local(&threadstopkey);
++
++#ifdef OPENSSL_INIT_DEBUG
++    fprintf(stderr, "OPENSSL_INIT: OPENSSL_cleanup: "
++                    "rand_cleanup_int()\n");
++    fprintf(stderr, "OPENSSL_INIT: OPENSSL_cleanup: "
++                    "conf_modules_free_int()\n");
++#ifndef OPENSSL_NO_ENGINE
++    fprintf(stderr, "OPENSSL_INIT: OPENSSL_cleanup: "
++                    "engine_cleanup_int()\n");
++#endif
++    fprintf(stderr, "OPENSSL_INIT: OPENSSL_cleanup: "
++                    "crypto_cleanup_all_ex_data_int()\n");
++    fprintf(stderr, "OPENSSL_INIT: OPENSSL_cleanup: "
++                    "bio_sock_cleanup_int()\n");
++    fprintf(stderr, "OPENSSL_INIT: OPENSSL_cleanup: "
++                    "bio_cleanup()\n");
++    fprintf(stderr, "OPENSSL_INIT: OPENSSL_cleanup: "
++                    "evp_cleanup_int()\n");
++    fprintf(stderr, "OPENSSL_INIT: OPENSSL_cleanup: "
++                    "obj_cleanup_int()\n");
++    fprintf(stderr, "OPENSSL_INIT: OPENSSL_cleanup: "
++                    "err_cleanup()\n");
++#endif
++    /*
++     * Note that cleanup order is important:
++     * - rand_cleanup_int could call an ENGINE's RAND cleanup function so
++     * must be called before engine_cleanup_int()
++     * - ENGINEs use CRYPTO_EX_DATA and therefore, must be cleaned up
++     * before the ex data handlers are wiped in CRYPTO_cleanup_all_ex_data().
++     * - conf_modules_free_int() can end up in ENGINE code so must be called
++     * before engine_cleanup_int()
++     * - ENGINEs and additional EVP algorithms might use added OIDs names so
++     * obj_cleanup_int() must be called last
++     */
++    rand_cleanup_int();
++    conf_modules_free_int();
++#ifndef OPENSSL_NO_ENGINE
++    engine_cleanup_int();
++#endif
++    crypto_cleanup_all_ex_data_int();
++    bio_cleanup();
++    evp_cleanup_int();
++    obj_cleanup_int();
++    err_cleanup();
++
++    base_inited = 0;
++}
++
++/*
++ * If this function is called with a non NULL settings value then it must be
++ * called prior to any threads making calls to any OpenSSL functions,
++ * i.e. passing a non-null settings value is assumed to be single-threaded.
++ */
++int OPENSSL_init_crypto(uint64_t opts, const OPENSSL_INIT_SETTINGS *settings)
++{
++    static int stoperrset = 0;
++
++    if (stopped) {
++        if (!stoperrset) {
++            /*
++             * We only ever set this once to avoid getting into an infinite
++             * loop where the error system keeps trying to init and fails so
++             * sets an error etc
++             */
++            stoperrset = 1;
++            CRYPTOerr(CRYPTO_F_OPENSSL_INIT_CRYPTO, ERR_R_INIT_FAIL);
++        }
++        return 0;
++    }
++
++    if (!base_inited && !RUN_ONCE(&base, ossl_init_base))
++        return 0;
++
++    if ((opts & OPENSSL_INIT_NO_LOAD_CRYPTO_STRINGS)
++            && !RUN_ONCE(&load_crypto_strings,
++                         ossl_init_no_load_crypto_strings))
++        return 0;
++
++    if ((opts & OPENSSL_INIT_LOAD_CRYPTO_STRINGS)
++            && !RUN_ONCE(&load_crypto_strings, ossl_init_load_crypto_strings))
++        return 0;
++
++    if ((opts & OPENSSL_INIT_NO_ADD_ALL_CIPHERS)
++            && !RUN_ONCE(&add_all_ciphers, ossl_init_no_add_algs))
++        return 0;
++
++    if ((opts & OPENSSL_INIT_ADD_ALL_CIPHERS)
++            && !RUN_ONCE(&add_all_ciphers, ossl_init_add_all_ciphers))
++        return 0;
++
++    if ((opts & OPENSSL_INIT_NO_ADD_ALL_DIGESTS)
++            && !RUN_ONCE(&add_all_digests, ossl_init_no_add_algs))
++        return 0;
++
++    if ((opts & OPENSSL_INIT_ADD_ALL_DIGESTS)
++            && !RUN_ONCE(&add_all_digests, ossl_init_add_all_digests))
++        return 0;
++
++    if ((opts & OPENSSL_INIT_NO_LOAD_CONFIG)
++            && !RUN_ONCE(&config, ossl_init_no_config))
++        return 0;
++
++    if (opts & OPENSSL_INIT_LOAD_CONFIG) {
++        int ret;
++        CRYPTO_THREAD_write_lock(init_lock);
++        appname = (settings == NULL) ? NULL : settings->appname;
++        ret = RUN_ONCE(&config, ossl_init_config);
++        CRYPTO_THREAD_unlock(init_lock);
++        if (!ret)
++            return 0;
++    }
++
++    if ((opts & OPENSSL_INIT_ASYNC)
++            && !RUN_ONCE(&async, ossl_init_async))
++        return 0;
++
++#ifndef OPENSSL_NO_ENGINE
++    if ((opts & OPENSSL_INIT_ENGINE_OPENSSL)
++            && !RUN_ONCE(&engine_openssl, ossl_init_engine_openssl))
++        return 0;
++# if !defined(OPENSSL_NO_HW) && \
++    (defined(__OpenBSD__) || defined(__FreeBSD__) || defined(HAVE_CRYPTODEV))
++    if ((opts & OPENSSL_INIT_ENGINE_CRYPTODEV)
++            && !RUN_ONCE(&engine_cryptodev, ossl_init_engine_cryptodev))
++        return 0;
++# endif
++# ifndef OPENSSL_NO_RDRAND
++    if ((opts & OPENSSL_INIT_ENGINE_RDRAND)
++            && !RUN_ONCE(&engine_rdrand, ossl_init_engine_rdrand))
++        return 0;
++# endif
++    if ((opts & OPENSSL_INIT_ENGINE_DYNAMIC)
++            && !RUN_ONCE(&engine_dynamic, ossl_init_engine_dynamic))
++        return 0;
++# ifndef OPENSSL_NO_STATIC_ENGINE
++#  if !defined(OPENSSL_NO_HW) && !defined(OPENSSL_NO_HW_PADLOCK)
++    if ((opts & OPENSSL_INIT_ENGINE_PADLOCK)
++            && !RUN_ONCE(&engine_padlock, ossl_init_engine_padlock))
++        return 0;
++#  endif
++#  if defined(OPENSSL_SYS_WIN32) && !defined(OPENSSL_NO_CAPIENG)
++    if ((opts & OPENSSL_INIT_ENGINE_CAPI)
++            && !RUN_ONCE(&engine_capi, ossl_init_engine_capi))
++        return 0;
++#  endif
++#  if !defined(OPENSSL_NO_AFALGENG)
++    if ((opts & OPENSSL_INIT_ENGINE_AFALG)
++            && !RUN_ONCE(&engine_afalg, ossl_init_engine_afalg))
++        return 0;
++#  endif
++# endif
++    if (opts & (OPENSSL_INIT_ENGINE_ALL_BUILTIN
++                | OPENSSL_INIT_ENGINE_OPENSSL
++                | OPENSSL_INIT_ENGINE_AFALG)) {
++        ENGINE_register_all_complete();
++    }
++#endif
++
++#ifndef OPENSSL_NO_COMP
++    if ((opts & OPENSSL_INIT_ZLIB)
++            && !RUN_ONCE(&zlib, ossl_init_zlib))
++        return 0;
++#endif
++
++    return 1;
++}
++
++int OPENSSL_atexit(void (*handler)(void))
++{
++    OPENSSL_INIT_STOP *newhand;
++
++#if !defined(OPENSSL_NO_DSO) && !defined(OPENSSL_USE_NODELETE)
++    {
++        union {
++            void *sym;
++            void (*func)(void);
++        } handlersym;
++
++        handlersym.func = handler;
++# ifdef DSO_WIN32
++        {
++            HMODULE handle = NULL;
++            BOOL ret;
++
++            /*
++             * We don't use the DSO route for WIN32 because there is a better
++             * way
++             */
++            ret = GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS
++                                    | GET_MODULE_HANDLE_EX_FLAG_PIN,
++                                    handlersym.sym, &handle);
++
++            if (!ret)
++                return 0;
++        }
++# else
++        /*
++         * Deliberately leak a reference to the handler. This will force the
++         * library/code containing the handler to remain loaded until we run the
++         * atexit handler. If -znodelete has been used then this is
++         * unneccessary.
++         */
++        {
++            DSO *dso = NULL;
++
++            dso = DSO_dsobyaddr(handlersym.sym, DSO_FLAG_NO_UNLOAD_ON_FREE);
++            DSO_free(dso);
++        }
++# endif
++    }
++#endif
++
++    newhand = OPENSSL_malloc(sizeof(*newhand));
++    if (newhand == NULL)
++        return 0;
++
++    newhand->handler = handler;
++    newhand->next = stop_handlers;
++    stop_handlers = newhand;
++
++    return 1;
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/kdf/build.info b/CryptoPkg/Library/OpensslLib/openssl/crypto/kdf/build.info
+new file mode 100644
+index 0000000..cbe2080
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/kdf/build.info
+@@ -0,0 +1,3 @@
++LIBS=../../libcrypto
++SOURCE[../../libcrypto]=\
++        tls1_prf.c kdf_err.c hkdf.c
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/kdf/hkdf.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/kdf/hkdf.c
+new file mode 100644
+index 0000000..00b95b5
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/kdf/hkdf.c
+@@ -0,0 +1,293 @@
++/*
++ * Copyright 2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include 
++#include 
++#include 
++#include 
++#include "internal/cryptlib.h"
++#include "internal/evp_int.h"
++
++#define HKDF_MAXBUF 1024
++
++static unsigned char *HKDF(const EVP_MD *evp_md,
++                           const unsigned char *salt, size_t salt_len,
++                           const unsigned char *key, size_t key_len,
++                           const unsigned char *info, size_t info_len,
++                           unsigned char *okm, size_t okm_len);
++
++static unsigned char *HKDF_Extract(const EVP_MD *evp_md,
++                                   const unsigned char *salt, size_t salt_len,
++                                   const unsigned char *key, size_t key_len,
++                                   unsigned char *prk, size_t *prk_len);
++
++static unsigned char *HKDF_Expand(const EVP_MD *evp_md,
++                                  const unsigned char *prk, size_t prk_len,
++                                  const unsigned char *info, size_t info_len,
++                                  unsigned char *okm, size_t okm_len);
++
++typedef struct {
++    const EVP_MD *md;
++    unsigned char *salt;
++    size_t salt_len;
++    unsigned char *key;
++    size_t key_len;
++    unsigned char info[HKDF_MAXBUF];
++    size_t info_len;
++} HKDF_PKEY_CTX;
++
++static int pkey_hkdf_init(EVP_PKEY_CTX *ctx)
++{
++    HKDF_PKEY_CTX *kctx;
++
++    kctx = OPENSSL_zalloc(sizeof(*kctx));
++    if (kctx == NULL)
++        return 0;
++
++    ctx->data = kctx;
++
++    return 1;
++}
++
++static void pkey_hkdf_cleanup(EVP_PKEY_CTX *ctx)
++{
++    HKDF_PKEY_CTX *kctx = ctx->data;
++    OPENSSL_clear_free(kctx->salt, kctx->salt_len);
++    OPENSSL_clear_free(kctx->key, kctx->key_len);
++    OPENSSL_cleanse(kctx->info, kctx->info_len);
++    OPENSSL_free(kctx);
++}
++
++static int pkey_hkdf_ctrl(EVP_PKEY_CTX *ctx, int type, int p1, void *p2)
++{
++    HKDF_PKEY_CTX *kctx = ctx->data;
++
++    switch (type) {
++    case EVP_PKEY_CTRL_HKDF_MD:
++        if (p2 == NULL)
++            return 0;
++
++        kctx->md = p2;
++        return 1;
++
++    case EVP_PKEY_CTRL_HKDF_SALT:
++        if (p1 == 0 || p2 == NULL)
++            return 1;
++
++        if (p1 < 0)
++            return 0;
++
++        if (kctx->salt != NULL)
++            OPENSSL_clear_free(kctx->salt, kctx->salt_len);
++
++        kctx->salt = OPENSSL_memdup(p2, p1);
++        if (kctx->salt == NULL)
++            return 0;
++
++        kctx->salt_len = p1;
++        return 1;
++
++    case EVP_PKEY_CTRL_HKDF_KEY:
++        if (p1 < 0)
++            return 0;
++
++        if (kctx->key != NULL)
++            OPENSSL_clear_free(kctx->key, kctx->key_len);
++
++        kctx->key = OPENSSL_memdup(p2, p1);
++        if (kctx->key == NULL)
++            return 0;
++
++        kctx->key_len  = p1;
++        return 1;
++
++    case EVP_PKEY_CTRL_HKDF_INFO:
++        if (p1 == 0 || p2 == NULL)
++            return 1;
++
++        if (p1 < 0 || p1 > (int)(HKDF_MAXBUF - kctx->info_len))
++            return 0;
++
++        memcpy(kctx->info + kctx->info_len, p2, p1);
++        kctx->info_len += p1;
++        return 1;
++
++    default:
++        return -2;
++
++    }
++}
++
++static int pkey_hkdf_ctrl_str(EVP_PKEY_CTX *ctx, const char *type,
++                              const char *value)
++{
++    if (strcmp(type, "md") == 0)
++        return EVP_PKEY_CTX_set_hkdf_md(ctx, EVP_get_digestbyname(value));
++
++    if (strcmp(type, "salt") == 0)
++        return EVP_PKEY_CTX_str2ctrl(ctx, EVP_PKEY_CTRL_HKDF_SALT, value);
++
++    if (strcmp(type, "hexsalt") == 0)
++        return EVP_PKEY_CTX_hex2ctrl(ctx, EVP_PKEY_CTRL_HKDF_SALT, value);
++
++    if (strcmp(type, "key") == 0)
++        return EVP_PKEY_CTX_str2ctrl(ctx, EVP_PKEY_CTRL_HKDF_KEY, value);
++
++    if (strcmp(type, "hexkey") == 0)
++        return EVP_PKEY_CTX_hex2ctrl(ctx, EVP_PKEY_CTRL_HKDF_KEY, value);
++
++    if (strcmp(type, "info") == 0)
++        return EVP_PKEY_CTX_str2ctrl(ctx, EVP_PKEY_CTRL_HKDF_INFO, value);
++
++    if (strcmp(type, "hexinfo") == 0)
++        return EVP_PKEY_CTX_hex2ctrl(ctx, EVP_PKEY_CTRL_HKDF_INFO, value);
++
++    return -2;
++}
++
++static int pkey_hkdf_derive(EVP_PKEY_CTX *ctx, unsigned char *key,
++                            size_t *keylen)
++{
++    HKDF_PKEY_CTX *kctx = ctx->data;
++
++    if (kctx->md == NULL || kctx->key == NULL)
++        return 0;
++
++    if (HKDF(kctx->md, kctx->salt, kctx->salt_len, kctx->key, kctx->key_len,
++             kctx->info, kctx->info_len, key, *keylen) == NULL)
++    {
++        return 0;
++    }
++
++    return 1;
++}
++
++const EVP_PKEY_METHOD hkdf_pkey_meth = {
++    EVP_PKEY_HKDF,
++    0,
++    pkey_hkdf_init,
++    0,
++    pkey_hkdf_cleanup,
++
++    0, 0,
++    0, 0,
++
++    0,
++    0,
++
++    0,
++    0,
++
++    0, 0,
++
++    0, 0, 0, 0,
++
++    0, 0,
++
++    0, 0,
++
++    0,
++    pkey_hkdf_derive,
++    pkey_hkdf_ctrl,
++    pkey_hkdf_ctrl_str
++};
++
++static unsigned char *HKDF(const EVP_MD *evp_md,
++                           const unsigned char *salt, size_t salt_len,
++                           const unsigned char *key, size_t key_len,
++                           const unsigned char *info, size_t info_len,
++                           unsigned char *okm, size_t okm_len)
++{
++    unsigned char prk[EVP_MAX_MD_SIZE];
++    size_t prk_len;
++
++    if (!HKDF_Extract(evp_md, salt, salt_len, key, key_len, prk, &prk_len))
++        return NULL;
++
++    return HKDF_Expand(evp_md, prk, prk_len, info, info_len, okm, okm_len);
++}
++
++static unsigned char *HKDF_Extract(const EVP_MD *evp_md,
++                                   const unsigned char *salt, size_t salt_len,
++                                   const unsigned char *key, size_t key_len,
++                                   unsigned char *prk, size_t *prk_len)
++{
++    unsigned int tmp_len;
++
++    if (!HMAC(evp_md, salt, salt_len, key, key_len, prk, &tmp_len))
++        return NULL;
++
++    *prk_len = tmp_len;
++    return prk;
++}
++
++static unsigned char *HKDF_Expand(const EVP_MD *evp_md,
++                                  const unsigned char *prk, size_t prk_len,
++                                  const unsigned char *info, size_t info_len,
++                                  unsigned char *okm, size_t okm_len)
++{
++    HMAC_CTX *hmac;
++
++    unsigned int i;
++
++    unsigned char prev[EVP_MAX_MD_SIZE];
++
++    size_t done_len = 0, dig_len = EVP_MD_size(evp_md);
++
++    size_t n = okm_len / dig_len;
++    if (okm_len % dig_len)
++        n++;
++
++    if (n > 255)
++        return NULL;
++
++    if ((hmac = HMAC_CTX_new()) == NULL)
++        return NULL;
++
++    if (!HMAC_Init_ex(hmac, prk, prk_len, evp_md, NULL))
++        goto err;
++
++    for (i = 1; i <= n; i++) {
++        size_t copy_len;
++        const unsigned char ctr = i;
++
++        if (i > 1) {
++            if (!HMAC_Init_ex(hmac, NULL, 0, NULL, NULL))
++                goto err;
++
++            if (!HMAC_Update(hmac, prev, dig_len))
++                goto err;
++        }
++
++        if (!HMAC_Update(hmac, info, info_len))
++            goto err;
++
++        if (!HMAC_Update(hmac, &ctr, 1))
++            goto err;
++
++        if (!HMAC_Final(hmac, prev, NULL))
++            goto err;
++
++        copy_len = (done_len + dig_len > okm_len) ?
++                       okm_len - done_len :
++                       dig_len;
++
++        memcpy(okm + done_len, prev, copy_len);
++
++        done_len += copy_len;
++    }
++
++    HMAC_CTX_free(hmac);
++    return okm;
++
++ err:
++    HMAC_CTX_free(hmac);
++    return NULL;
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/kdf/kdf_err.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/kdf/kdf_err.c
+new file mode 100644
+index 0000000..d7d71b3
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/kdf/kdf_err.c
+@@ -0,0 +1,46 @@
++/*
++ * Generated by util/mkerr.pl DO NOT EDIT
++ * Copyright 1995-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include 
++#include 
++
++/* BEGIN ERROR CODES */
++#ifndef OPENSSL_NO_ERR
++
++# define ERR_FUNC(func) ERR_PACK(ERR_LIB_KDF,func,0)
++# define ERR_REASON(reason) ERR_PACK(ERR_LIB_KDF,0,reason)
++
++static ERR_STRING_DATA KDF_str_functs[] = {
++    {ERR_FUNC(KDF_F_PKEY_TLS1_PRF_CTRL_STR), "pkey_tls1_prf_ctrl_str"},
++    {ERR_FUNC(KDF_F_PKEY_TLS1_PRF_DERIVE), "pkey_tls1_prf_derive"},
++    {0, NULL}
++};
++
++static ERR_STRING_DATA KDF_str_reasons[] = {
++    {ERR_REASON(KDF_R_INVALID_DIGEST), "invalid digest"},
++    {ERR_REASON(KDF_R_MISSING_PARAMETER), "missing parameter"},
++    {ERR_REASON(KDF_R_VALUE_MISSING), "value missing"},
++    {0, NULL}
++};
++
++#endif
++
++int ERR_load_KDF_strings(void)
++{
++#ifndef OPENSSL_NO_ERR
++
++    if (ERR_func_error_string(KDF_str_functs[0].error) == NULL) {
++        ERR_load_strings(0, KDF_str_functs);
++        ERR_load_strings(0, KDF_str_reasons);
++    }
++#endif
++    return 1;
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/kdf/tls1_prf.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/kdf/tls1_prf.c
+new file mode 100644
+index 0000000..fa13732
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/kdf/tls1_prf.c
+@@ -0,0 +1,265 @@
++/*
++ * Copyright 2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include "internal/cryptlib.h"
++#include 
++#include 
++#include "internal/evp_int.h"
++
++static int tls1_prf_alg(const EVP_MD *md,
++                        const unsigned char *sec, size_t slen,
++                        const unsigned char *seed, size_t seed_len,
++                        unsigned char *out, size_t olen);
++
++#define TLS1_PRF_MAXBUF 1024
++
++/* TLS KDF pkey context structure */
++
++typedef struct {
++    /* Digest to use for PRF */
++    const EVP_MD *md;
++    /* Secret value to use for PRF */
++    unsigned char *sec;
++    size_t seclen;
++    /* Buffer of concatenated seed data */
++    unsigned char seed[TLS1_PRF_MAXBUF];
++    size_t seedlen;
++} TLS1_PRF_PKEY_CTX;
++
++static int pkey_tls1_prf_init(EVP_PKEY_CTX *ctx)
++{
++    TLS1_PRF_PKEY_CTX *kctx;
++
++    kctx = OPENSSL_zalloc(sizeof(*kctx));
++    if (kctx == NULL)
++        return 0;
++    ctx->data = kctx;
++
++    return 1;
++}
++
++static void pkey_tls1_prf_cleanup(EVP_PKEY_CTX *ctx)
++{
++    TLS1_PRF_PKEY_CTX *kctx = ctx->data;
++    OPENSSL_clear_free(kctx->sec, kctx->seclen);
++    OPENSSL_cleanse(kctx->seed, kctx->seedlen);
++    OPENSSL_free(kctx);
++}
++
++static int pkey_tls1_prf_ctrl(EVP_PKEY_CTX *ctx, int type, int p1, void *p2)
++{
++    TLS1_PRF_PKEY_CTX *kctx = ctx->data;
++    switch (type) {
++    case EVP_PKEY_CTRL_TLS_MD:
++        kctx->md = p2;
++        return 1;
++
++    case EVP_PKEY_CTRL_TLS_SECRET:
++        if (p1 < 0)
++            return 0;
++        if (kctx->sec != NULL)
++            OPENSSL_clear_free(kctx->sec, kctx->seclen);
++        OPENSSL_cleanse(kctx->seed, kctx->seedlen);
++        kctx->seedlen = 0;
++        kctx->sec = OPENSSL_memdup(p2, p1);
++        if (kctx->sec == NULL)
++            return 0;
++        kctx->seclen  = p1;
++        return 1;
++
++    case EVP_PKEY_CTRL_TLS_SEED:
++        if (p1 == 0 || p2 == NULL)
++            return 1;
++        if (p1 < 0 || p1 > (int)(TLS1_PRF_MAXBUF - kctx->seedlen))
++            return 0;
++        memcpy(kctx->seed + kctx->seedlen, p2, p1);
++        kctx->seedlen += p1;
++        return 1;
++
++    default:
++        return -2;
++
++    }
++}
++
++static int pkey_tls1_prf_ctrl_str(EVP_PKEY_CTX *ctx,
++                                  const char *type, const char *value)
++{
++    if (value == NULL) {
++        KDFerr(KDF_F_PKEY_TLS1_PRF_CTRL_STR, KDF_R_VALUE_MISSING);
++        return 0;
++    }
++    if (strcmp(type, "md") == 0) {
++        TLS1_PRF_PKEY_CTX *kctx = ctx->data;
++
++        const EVP_MD *md = EVP_get_digestbyname(value);
++        if (md == NULL) {
++            KDFerr(KDF_F_PKEY_TLS1_PRF_CTRL_STR, KDF_R_INVALID_DIGEST);
++            return 0;
++        }
++        kctx->md = md;
++        return 1;
++    }
++    if (strcmp(type, "secret") == 0)
++        return EVP_PKEY_CTX_str2ctrl(ctx, EVP_PKEY_CTRL_TLS_SECRET, value);
++    if (strcmp(type, "hexsecret") == 0)
++        return EVP_PKEY_CTX_hex2ctrl(ctx, EVP_PKEY_CTRL_TLS_SECRET, value);
++    if (strcmp(type, "seed") == 0)
++        return EVP_PKEY_CTX_str2ctrl(ctx, EVP_PKEY_CTRL_TLS_SEED, value);
++    if (strcmp(type, "hexseed") == 0)
++        return EVP_PKEY_CTX_hex2ctrl(ctx, EVP_PKEY_CTRL_TLS_SEED, value);
++    return -2;
++}
++
++static int pkey_tls1_prf_derive(EVP_PKEY_CTX *ctx, unsigned char *key,
++                                size_t *keylen)
++{
++    TLS1_PRF_PKEY_CTX *kctx = ctx->data;
++    if (kctx->md == NULL || kctx->sec == NULL || kctx->seedlen == 0) {
++        KDFerr(KDF_F_PKEY_TLS1_PRF_DERIVE, KDF_R_MISSING_PARAMETER);
++        return 0;
++    }
++    return tls1_prf_alg(kctx->md, kctx->sec, kctx->seclen,
++                        kctx->seed, kctx->seedlen,
++                        key, *keylen);
++}
++
++const EVP_PKEY_METHOD tls1_prf_pkey_meth = {
++    EVP_PKEY_TLS1_PRF,
++    0,
++    pkey_tls1_prf_init,
++    0,
++    pkey_tls1_prf_cleanup,
++
++    0, 0,
++    0, 0,
++
++    0,
++    0,
++
++    0,
++    0,
++
++    0, 0,
++
++    0, 0, 0, 0,
++
++    0, 0,
++
++    0, 0,
++
++    0,
++    pkey_tls1_prf_derive,
++    pkey_tls1_prf_ctrl,
++    pkey_tls1_prf_ctrl_str
++};
++
++static int tls1_prf_P_hash(const EVP_MD *md,
++                           const unsigned char *sec, size_t sec_len,
++                           const unsigned char *seed, size_t seed_len,
++                           unsigned char *out, size_t olen)
++{
++    int chunk;
++    EVP_MD_CTX *ctx = NULL, *ctx_tmp = NULL, *ctx_init = NULL;
++    EVP_PKEY *mac_key = NULL;
++    unsigned char A1[EVP_MAX_MD_SIZE];
++    size_t A1_len;
++    int ret = 0;
++
++    chunk = EVP_MD_size(md);
++    OPENSSL_assert(chunk >= 0);
++
++    ctx = EVP_MD_CTX_new();
++    ctx_tmp = EVP_MD_CTX_new();
++    ctx_init = EVP_MD_CTX_new();
++    if (ctx == NULL || ctx_tmp == NULL || ctx_init == NULL)
++        goto err;
++    EVP_MD_CTX_set_flags(ctx_init, EVP_MD_CTX_FLAG_NON_FIPS_ALLOW);
++    mac_key = EVP_PKEY_new_mac_key(EVP_PKEY_HMAC, NULL, sec, sec_len);
++    if (mac_key == NULL)
++        goto err;
++    if (!EVP_DigestSignInit(ctx_init, NULL, md, NULL, mac_key))
++        goto err;
++    if (!EVP_MD_CTX_copy_ex(ctx, ctx_init))
++        goto err;
++    if (seed != NULL && !EVP_DigestSignUpdate(ctx, seed, seed_len))
++        goto err;
++    if (!EVP_DigestSignFinal(ctx, A1, &A1_len))
++        goto err;
++
++    for (;;) {
++        /* Reinit mac contexts */
++        if (!EVP_MD_CTX_copy_ex(ctx, ctx_init))
++            goto err;
++        if (!EVP_DigestSignUpdate(ctx, A1, A1_len))
++            goto err;
++        if (olen > (size_t)chunk && !EVP_MD_CTX_copy_ex(ctx_tmp, ctx))
++            goto err;
++        if (seed && !EVP_DigestSignUpdate(ctx, seed, seed_len))
++            goto err;
++
++        if (olen > (size_t)chunk) {
++            size_t mac_len;
++            if (!EVP_DigestSignFinal(ctx, out, &mac_len))
++                goto err;
++            out += mac_len;
++            olen -= mac_len;
++            /* calc the next A1 value */
++            if (!EVP_DigestSignFinal(ctx_tmp, A1, &A1_len))
++                goto err;
++        } else {                /* last one */
++
++            if (!EVP_DigestSignFinal(ctx, A1, &A1_len))
++                goto err;
++            memcpy(out, A1, olen);
++            break;
++        }
++    }
++    ret = 1;
++ err:
++    EVP_PKEY_free(mac_key);
++    EVP_MD_CTX_free(ctx);
++    EVP_MD_CTX_free(ctx_tmp);
++    EVP_MD_CTX_free(ctx_init);
++    OPENSSL_cleanse(A1, sizeof(A1));
++    return ret;
++}
++
++static int tls1_prf_alg(const EVP_MD *md,
++                        const unsigned char *sec, size_t slen,
++                        const unsigned char *seed, size_t seed_len,
++                        unsigned char *out, size_t olen)
++{
++
++    if (EVP_MD_type(md) == NID_md5_sha1) {
++        size_t i;
++        unsigned char *tmp;
++        if (!tls1_prf_P_hash(EVP_md5(), sec, slen/2 + (slen & 1),
++                         seed, seed_len, out, olen))
++            return 0;
++
++        tmp = OPENSSL_malloc(olen);
++        if (tmp == NULL)
++            return 0;
++        if (!tls1_prf_P_hash(EVP_sha1(), sec + slen/2, slen/2 + (slen & 1),
++                         seed, seed_len, tmp, olen)) {
++            OPENSSL_clear_free(tmp, olen);
++            return 0;
++        }
++        for (i = 0; i < olen; i++)
++            out[i] ^= tmp[i];
++        OPENSSL_clear_free(tmp, olen);
++        return 1;
++    }
++    if (!tls1_prf_P_hash(md, sec, slen, seed, seed_len, out, olen))
++        return 0;
++
++    return 1;
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/lhash/build.info b/CryptoPkg/Library/OpensslLib/openssl/crypto/lhash/build.info
+new file mode 100644
+index 0000000..30797f2
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/lhash/build.info
+@@ -0,0 +1,3 @@
++LIBS=../../libcrypto
++SOURCE[../../libcrypto]=\
++        lhash.c lh_stats.c
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/lhash/lh_stats.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/lhash/lh_stats.c
+new file mode 100644
+index 0000000..7337832
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/lhash/lh_stats.c
+@@ -0,0 +1,118 @@
++/*
++ * Copyright 1995-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include 
++#include 
++/*
++ * If you wish to build this outside of OpenSSL, remove the following lines
++ * and things should work as expected
++ */
++#include "internal/cryptlib.h"
++
++#include 
++#include 
++#include "lhash_lcl.h"
++
++# ifndef OPENSSL_NO_STDIO
++void OPENSSL_LH_stats(const OPENSSL_LHASH *lh, FILE *fp)
++{
++    BIO *bp;
++
++    bp = BIO_new(BIO_s_file());
++    if (bp == NULL)
++        return;
++    BIO_set_fp(bp, fp, BIO_NOCLOSE);
++    OPENSSL_LH_stats_bio(lh, bp);
++    BIO_free(bp);
++}
++
++void OPENSSL_LH_node_stats(const OPENSSL_LHASH *lh, FILE *fp)
++{
++    BIO *bp;
++
++    bp = BIO_new(BIO_s_file());
++    if (bp == NULL)
++        return;
++    BIO_set_fp(bp, fp, BIO_NOCLOSE);
++    OPENSSL_LH_node_stats_bio(lh, bp);
++    BIO_free(bp);
++}
++
++void OPENSSL_LH_node_usage_stats(const OPENSSL_LHASH *lh, FILE *fp)
++{
++    BIO *bp;
++
++    bp = BIO_new(BIO_s_file());
++    if (bp == NULL)
++        return;
++    BIO_set_fp(bp, fp, BIO_NOCLOSE);
++    OPENSSL_LH_node_usage_stats_bio(lh, bp);
++    BIO_free(bp);
++}
++
++# endif
++
++void OPENSSL_LH_stats_bio(const OPENSSL_LHASH *lh, BIO *out)
++{
++    BIO_printf(out, "num_items             = %lu\n", lh->num_items);
++    BIO_printf(out, "num_nodes             = %u\n", lh->num_nodes);
++    BIO_printf(out, "num_alloc_nodes       = %u\n", lh->num_alloc_nodes);
++    BIO_printf(out, "num_expands           = %lu\n", lh->num_expands);
++    BIO_printf(out, "num_expand_reallocs   = %lu\n", lh->num_expand_reallocs);
++    BIO_printf(out, "num_contracts         = %lu\n", lh->num_contracts);
++    BIO_printf(out, "num_contract_reallocs = %lu\n",
++               lh->num_contract_reallocs);
++    BIO_printf(out, "num_hash_calls        = %lu\n", lh->num_hash_calls);
++    BIO_printf(out, "num_comp_calls        = %lu\n", lh->num_comp_calls);
++    BIO_printf(out, "num_insert            = %lu\n", lh->num_insert);
++    BIO_printf(out, "num_replace           = %lu\n", lh->num_replace);
++    BIO_printf(out, "num_delete            = %lu\n", lh->num_delete);
++    BIO_printf(out, "num_no_delete         = %lu\n", lh->num_no_delete);
++    BIO_printf(out, "num_retrieve          = %lu\n", lh->num_retrieve);
++    BIO_printf(out, "num_retrieve_miss     = %lu\n", lh->num_retrieve_miss);
++    BIO_printf(out, "num_hash_comps        = %lu\n", lh->num_hash_comps);
++}
++
++void OPENSSL_LH_node_stats_bio(const OPENSSL_LHASH *lh, BIO *out)
++{
++    OPENSSL_LH_NODE *n;
++    unsigned int i, num;
++
++    for (i = 0; i < lh->num_nodes; i++) {
++        for (n = lh->b[i], num = 0; n != NULL; n = n->next)
++            num++;
++        BIO_printf(out, "node %6u -> %3u\n", i, num);
++    }
++}
++
++void OPENSSL_LH_node_usage_stats_bio(const OPENSSL_LHASH *lh, BIO *out)
++{
++    OPENSSL_LH_NODE *n;
++    unsigned long num;
++    unsigned int i;
++    unsigned long total = 0, n_used = 0;
++
++    for (i = 0; i < lh->num_nodes; i++) {
++        for (n = lh->b[i], num = 0; n != NULL; n = n->next)
++            num++;
++        if (num != 0) {
++            n_used++;
++            total += num;
++        }
++    }
++    BIO_printf(out, "%lu nodes used out of %u\n", n_used, lh->num_nodes);
++    BIO_printf(out, "%lu items\n", total);
++    if (n_used == 0)
++        return;
++    BIO_printf(out, "load %d.%02d  actual load %d.%02d\n",
++               (int)(total / lh->num_nodes),
++               (int)((total % lh->num_nodes) * 100 / lh->num_nodes),
++               (int)(total / n_used), (int)((total % n_used) * 100 / n_used));
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/lhash/lhash.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/lhash/lhash.c
+new file mode 100644
+index 0000000..adde832
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/lhash/lhash.c
+@@ -0,0 +1,349 @@
++/*
++ * Copyright 1995-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include 
++#include 
++#include 
++#include 
++#include "lhash_lcl.h"
++
++
++#undef MIN_NODES
++#define MIN_NODES       16
++#define UP_LOAD         (2*LH_LOAD_MULT) /* load times 256 (default 2) */
++#define DOWN_LOAD       (LH_LOAD_MULT) /* load times 256 (default 1) */
++
++static int expand(OPENSSL_LHASH *lh);
++static void contract(OPENSSL_LHASH *lh);
++static OPENSSL_LH_NODE **getrn(OPENSSL_LHASH *lh, const void *data, unsigned long *rhash);
++
++OPENSSL_LHASH *OPENSSL_LH_new(OPENSSL_LH_HASHFUNC h, OPENSSL_LH_COMPFUNC c)
++{
++    OPENSSL_LHASH *ret;
++
++    if ((ret = OPENSSL_zalloc(sizeof(*ret))) == NULL)
++        goto err0;
++    if ((ret->b = OPENSSL_zalloc(sizeof(*ret->b) * MIN_NODES)) == NULL)
++        goto err1;
++    ret->comp = ((c == NULL) ? (OPENSSL_LH_COMPFUNC)strcmp : c);
++    ret->hash = ((h == NULL) ? (OPENSSL_LH_HASHFUNC)OPENSSL_LH_strhash : h);
++    ret->num_nodes = MIN_NODES / 2;
++    ret->num_alloc_nodes = MIN_NODES;
++    ret->pmax = MIN_NODES / 2;
++    ret->up_load = UP_LOAD;
++    ret->down_load = DOWN_LOAD;
++    return (ret);
++
++ err1:
++    OPENSSL_free(ret);
++ err0:
++    return (NULL);
++}
++
++void OPENSSL_LH_free(OPENSSL_LHASH *lh)
++{
++    unsigned int i;
++    OPENSSL_LH_NODE *n, *nn;
++
++    if (lh == NULL)
++        return;
++
++    for (i = 0; i < lh->num_nodes; i++) {
++        n = lh->b[i];
++        while (n != NULL) {
++            nn = n->next;
++            OPENSSL_free(n);
++            n = nn;
++        }
++    }
++    OPENSSL_free(lh->b);
++    OPENSSL_free(lh);
++}
++
++void *OPENSSL_LH_insert(OPENSSL_LHASH *lh, void *data)
++{
++    unsigned long hash;
++    OPENSSL_LH_NODE *nn, **rn;
++    void *ret;
++
++    lh->error = 0;
++    if ((lh->up_load <= (lh->num_items * LH_LOAD_MULT / lh->num_nodes)) && !expand(lh))
++        return NULL;        /* 'lh->error++' already done in 'expand' */
++
++    rn = getrn(lh, data, &hash);
++
++    if (*rn == NULL) {
++        if ((nn = OPENSSL_malloc(sizeof(*nn))) == NULL) {
++            lh->error++;
++            return (NULL);
++        }
++        nn->data = data;
++        nn->next = NULL;
++        nn->hash = hash;
++        *rn = nn;
++        ret = NULL;
++        lh->num_insert++;
++        lh->num_items++;
++    } else {                    /* replace same key */
++
++        ret = (*rn)->data;
++        (*rn)->data = data;
++        lh->num_replace++;
++    }
++    return (ret);
++}
++
++void *OPENSSL_LH_delete(OPENSSL_LHASH *lh, const void *data)
++{
++    unsigned long hash;
++    OPENSSL_LH_NODE *nn, **rn;
++    void *ret;
++
++    lh->error = 0;
++    rn = getrn(lh, data, &hash);
++
++    if (*rn == NULL) {
++        lh->num_no_delete++;
++        return (NULL);
++    } else {
++        nn = *rn;
++        *rn = nn->next;
++        ret = nn->data;
++        OPENSSL_free(nn);
++        lh->num_delete++;
++    }
++
++    lh->num_items--;
++    if ((lh->num_nodes > MIN_NODES) &&
++        (lh->down_load >= (lh->num_items * LH_LOAD_MULT / lh->num_nodes)))
++        contract(lh);
++
++    return (ret);
++}
++
++void *OPENSSL_LH_retrieve(OPENSSL_LHASH *lh, const void *data)
++{
++    unsigned long hash;
++    OPENSSL_LH_NODE **rn;
++    void *ret;
++
++    lh->error = 0;
++    rn = getrn(lh, data, &hash);
++
++    if (*rn == NULL) {
++        lh->num_retrieve_miss++;
++        return (NULL);
++    } else {
++        ret = (*rn)->data;
++        lh->num_retrieve++;
++    }
++    return (ret);
++}
++
++static void doall_util_fn(OPENSSL_LHASH *lh, int use_arg,
++                          OPENSSL_LH_DOALL_FUNC func,
++                          OPENSSL_LH_DOALL_FUNCARG func_arg, void *arg)
++{
++    int i;
++    OPENSSL_LH_NODE *a, *n;
++
++    if (lh == NULL)
++        return;
++
++    /*
++     * reverse the order so we search from 'top to bottom' We were having
++     * memory leaks otherwise
++     */
++    for (i = lh->num_nodes - 1; i >= 0; i--) {
++        a = lh->b[i];
++        while (a != NULL) {
++            n = a->next;
++            if (use_arg)
++                func_arg(a->data, arg);
++            else
++                func(a->data);
++            a = n;
++        }
++    }
++}
++
++void OPENSSL_LH_doall(OPENSSL_LHASH *lh, OPENSSL_LH_DOALL_FUNC func)
++{
++    doall_util_fn(lh, 0, func, (OPENSSL_LH_DOALL_FUNCARG)0, NULL);
++}
++
++void OPENSSL_LH_doall_arg(OPENSSL_LHASH *lh, OPENSSL_LH_DOALL_FUNCARG func, void *arg)
++{
++    doall_util_fn(lh, 1, (OPENSSL_LH_DOALL_FUNC)0, func, arg);
++}
++
++static int expand(OPENSSL_LHASH *lh)
++{
++    OPENSSL_LH_NODE **n, **n1, **n2, *np;
++    unsigned int p, i, j;
++    unsigned long hash, nni;
++
++    lh->num_nodes++;
++    lh->num_expands++;
++    p = (int)lh->p++;
++    n1 = &(lh->b[p]);
++    n2 = &(lh->b[p + (int)lh->pmax]);
++    *n2 = NULL;
++    nni = lh->num_alloc_nodes;
++
++    for (np = *n1; np != NULL;) {
++        hash = np->hash;
++        if ((hash % nni) != p) { /* move it */
++            *n1 = (*n1)->next;
++            np->next = *n2;
++            *n2 = np;
++        } else
++            n1 = &((*n1)->next);
++        np = *n1;
++    }
++
++    if ((lh->p) >= lh->pmax) {
++        j = (int)lh->num_alloc_nodes * 2;
++        n = OPENSSL_realloc(lh->b, (int)(sizeof(OPENSSL_LH_NODE *) * j));
++        if (n == NULL) {
++            lh->error++;
++            lh->num_nodes--;
++            lh->p = 0;
++            return 0;
++        }
++        for (i = (int)lh->num_alloc_nodes; i < j; i++) /* 26/02/92 eay */
++            n[i] = NULL;        /* 02/03/92 eay */
++        lh->pmax = lh->num_alloc_nodes;
++        lh->num_alloc_nodes = j;
++        lh->num_expand_reallocs++;
++        lh->p = 0;
++        lh->b = n;
++    }
++    return 1;
++}
++
++static void contract(OPENSSL_LHASH *lh)
++{
++    OPENSSL_LH_NODE **n, *n1, *np;
++
++    np = lh->b[lh->p + lh->pmax - 1];
++    lh->b[lh->p + lh->pmax - 1] = NULL; /* 24/07-92 - eay - weird but :-( */
++    if (lh->p == 0) {
++        n = OPENSSL_realloc(lh->b,
++                            (unsigned int)(sizeof(OPENSSL_LH_NODE *) * lh->pmax));
++        if (n == NULL) {
++            /* fputs("realloc error in lhash",stderr); */
++            lh->error++;
++            return;
++        }
++        lh->num_contract_reallocs++;
++        lh->num_alloc_nodes /= 2;
++        lh->pmax /= 2;
++        lh->p = lh->pmax - 1;
++        lh->b = n;
++    } else
++        lh->p--;
++
++    lh->num_nodes--;
++    lh->num_contracts++;
++
++    n1 = lh->b[(int)lh->p];
++    if (n1 == NULL)
++        lh->b[(int)lh->p] = np;
++    else {
++        while (n1->next != NULL)
++            n1 = n1->next;
++        n1->next = np;
++    }
++}
++
++static OPENSSL_LH_NODE **getrn(OPENSSL_LHASH *lh,
++                               const void *data, unsigned long *rhash)
++{
++    OPENSSL_LH_NODE **ret, *n1;
++    unsigned long hash, nn;
++    OPENSSL_LH_COMPFUNC cf;
++
++    hash = (*(lh->hash)) (data);
++    lh->num_hash_calls++;
++    *rhash = hash;
++
++    nn = hash % lh->pmax;
++    if (nn < lh->p)
++        nn = hash % lh->num_alloc_nodes;
++
++    cf = lh->comp;
++    ret = &(lh->b[(int)nn]);
++    for (n1 = *ret; n1 != NULL; n1 = n1->next) {
++        lh->num_hash_comps++;
++        if (n1->hash != hash) {
++            ret = &(n1->next);
++            continue;
++        }
++        lh->num_comp_calls++;
++        if (cf(n1->data, data) == 0)
++            break;
++        ret = &(n1->next);
++    }
++    return (ret);
++}
++
++/*
++ * The following hash seems to work very well on normal text strings no
++ * collisions on /usr/dict/words and it distributes on %2^n quite well, not
++ * as good as MD5, but still good.
++ */
++unsigned long OPENSSL_LH_strhash(const char *c)
++{
++    unsigned long ret = 0;
++    long n;
++    unsigned long v;
++    int r;
++
++    if ((c == NULL) || (*c == '\0'))
++        return (ret);
++/*-
++    unsigned char b[16];
++    MD5(c,strlen(c),b);
++    return(b[0]|(b[1]<<8)|(b[2]<<16)|(b[3]<<24));
++*/
++
++    n = 0x100;
++    while (*c) {
++        v = n | (*c);
++        n += 0x100;
++        r = (int)((v >> 2) ^ v) & 0x0f;
++        ret = (ret << r) | (ret >> (32 - r));
++        ret &= 0xFFFFFFFFL;
++        ret ^= v * v;
++        c++;
++    }
++    return ((ret >> 16) ^ ret);
++}
++
++unsigned long OPENSSL_LH_num_items(const OPENSSL_LHASH *lh)
++{
++    return lh ? lh->num_items : 0;
++}
++
++unsigned long OPENSSL_LH_get_down_load(const OPENSSL_LHASH *lh)
++{
++    return lh->down_load;
++}
++
++void OPENSSL_LH_set_down_load(OPENSSL_LHASH *lh, unsigned long down_load)
++{
++    lh->down_load = down_load;
++}
++
++int OPENSSL_LH_error(OPENSSL_LHASH *lh)
++{
++    return lh->error;
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/lhash/lhash_lcl.h b/CryptoPkg/Library/OpensslLib/openssl/crypto/lhash/lhash_lcl.h
+new file mode 100644
+index 0000000..eb4a1a3
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/lhash/lhash_lcl.h
+@@ -0,0 +1,42 @@
++/*
++ * Copyright 1995-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++
++struct lhash_node_st {
++    void *data;
++    struct lhash_node_st *next;
++    unsigned long hash;
++};
++
++struct lhash_st {
++    OPENSSL_LH_NODE **b;
++    OPENSSL_LH_COMPFUNC comp;
++    OPENSSL_LH_HASHFUNC hash;
++    unsigned int num_nodes;
++    unsigned int num_alloc_nodes;
++    unsigned int p;
++    unsigned int pmax;
++    unsigned long up_load;      /* load times 256 */
++    unsigned long down_load;    /* load times 256 */
++    unsigned long num_items;
++    unsigned long num_expands;
++    unsigned long num_expand_reallocs;
++    unsigned long num_contracts;
++    unsigned long num_contract_reallocs;
++    unsigned long num_hash_calls;
++    unsigned long num_comp_calls;
++    unsigned long num_insert;
++    unsigned long num_replace;
++    unsigned long num_delete;
++    unsigned long num_no_delete;
++    unsigned long num_retrieve;
++    unsigned long num_retrieve_miss;
++    unsigned long num_hash_comps;
++    int error;
++};
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/lhash/num.pl b/CryptoPkg/Library/OpensslLib/openssl/crypto/lhash/num.pl
+new file mode 100644
+index 0000000..8a8c42c
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/lhash/num.pl
+@@ -0,0 +1,23 @@
++#! /usr/bin/env perl
++# Copyright 1995-2016 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
++# in the file LICENSE in the source distribution or at
++# https://www.openssl.org/source/license.html
++
++#node     10 ->   4
++
++while (<>)
++	{
++	next unless /^node/;
++	s|\R$||;                # Better chomp
++	@a=split;
++	$num{$a[3]}++;
++	}
++
++@a=sort {$a <=> $b } keys %num;
++foreach (0 .. $a[$#a])
++	{
++	printf "%4d:%4d\n",$_,$num{$_};
++	}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/md2/build.info b/CryptoPkg/Library/OpensslLib/openssl/crypto/md2/build.info
+new file mode 100644
+index 0000000..e31948c
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/md2/build.info
+@@ -0,0 +1,3 @@
++LIBS=../../libcrypto
++SOURCE[../../libcrypto]=\
++        md2_dgst.c md2_one.c
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/md2/md2_dgst.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/md2/md2_dgst.c
+new file mode 100644
+index 0000000..ff062fd
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/md2/md2_dgst.c
+@@ -0,0 +1,173 @@
++/*
++ * Copyright 1995-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include 
++#include 
++#include 
++#include 
++#include 
++
++/*
++ * Implemented from RFC1319 The MD2 Message-Digest Algorithm
++ */
++
++#define UCHAR   unsigned char
++
++static void md2_block(MD2_CTX *c, const unsigned char *d);
++/*
++ * The magic S table - I have converted it to hex since it is basically just
++ * a random byte string.
++ */
++static const MD2_INT S[256] = {
++    0x29, 0x2E, 0x43, 0xC9, 0xA2, 0xD8, 0x7C, 0x01,
++    0x3D, 0x36, 0x54, 0xA1, 0xEC, 0xF0, 0x06, 0x13,
++    0x62, 0xA7, 0x05, 0xF3, 0xC0, 0xC7, 0x73, 0x8C,
++    0x98, 0x93, 0x2B, 0xD9, 0xBC, 0x4C, 0x82, 0xCA,
++    0x1E, 0x9B, 0x57, 0x3C, 0xFD, 0xD4, 0xE0, 0x16,
++    0x67, 0x42, 0x6F, 0x18, 0x8A, 0x17, 0xE5, 0x12,
++    0xBE, 0x4E, 0xC4, 0xD6, 0xDA, 0x9E, 0xDE, 0x49,
++    0xA0, 0xFB, 0xF5, 0x8E, 0xBB, 0x2F, 0xEE, 0x7A,
++    0xA9, 0x68, 0x79, 0x91, 0x15, 0xB2, 0x07, 0x3F,
++    0x94, 0xC2, 0x10, 0x89, 0x0B, 0x22, 0x5F, 0x21,
++    0x80, 0x7F, 0x5D, 0x9A, 0x5A, 0x90, 0x32, 0x27,
++    0x35, 0x3E, 0xCC, 0xE7, 0xBF, 0xF7, 0x97, 0x03,
++    0xFF, 0x19, 0x30, 0xB3, 0x48, 0xA5, 0xB5, 0xD1,
++    0xD7, 0x5E, 0x92, 0x2A, 0xAC, 0x56, 0xAA, 0xC6,
++    0x4F, 0xB8, 0x38, 0xD2, 0x96, 0xA4, 0x7D, 0xB6,
++    0x76, 0xFC, 0x6B, 0xE2, 0x9C, 0x74, 0x04, 0xF1,
++    0x45, 0x9D, 0x70, 0x59, 0x64, 0x71, 0x87, 0x20,
++    0x86, 0x5B, 0xCF, 0x65, 0xE6, 0x2D, 0xA8, 0x02,
++    0x1B, 0x60, 0x25, 0xAD, 0xAE, 0xB0, 0xB9, 0xF6,
++    0x1C, 0x46, 0x61, 0x69, 0x34, 0x40, 0x7E, 0x0F,
++    0x55, 0x47, 0xA3, 0x23, 0xDD, 0x51, 0xAF, 0x3A,
++    0xC3, 0x5C, 0xF9, 0xCE, 0xBA, 0xC5, 0xEA, 0x26,
++    0x2C, 0x53, 0x0D, 0x6E, 0x85, 0x28, 0x84, 0x09,
++    0xD3, 0xDF, 0xCD, 0xF4, 0x41, 0x81, 0x4D, 0x52,
++    0x6A, 0xDC, 0x37, 0xC8, 0x6C, 0xC1, 0xAB, 0xFA,
++    0x24, 0xE1, 0x7B, 0x08, 0x0C, 0xBD, 0xB1, 0x4A,
++    0x78, 0x88, 0x95, 0x8B, 0xE3, 0x63, 0xE8, 0x6D,
++    0xE9, 0xCB, 0xD5, 0xFE, 0x3B, 0x00, 0x1D, 0x39,
++    0xF2, 0xEF, 0xB7, 0x0E, 0x66, 0x58, 0xD0, 0xE4,
++    0xA6, 0x77, 0x72, 0xF8, 0xEB, 0x75, 0x4B, 0x0A,
++    0x31, 0x44, 0x50, 0xB4, 0x8F, 0xED, 0x1F, 0x1A,
++    0xDB, 0x99, 0x8D, 0x33, 0x9F, 0x11, 0x83, 0x14,
++};
++
++const char *MD2_options(void)
++{
++    if (sizeof(MD2_INT) == 1)
++        return ("md2(char)");
++    else
++        return ("md2(int)");
++}
++
++int MD2_Init(MD2_CTX *c)
++{
++    c->num = 0;
++    memset(c->state, 0, sizeof(c->state));
++    memset(c->cksm, 0, sizeof(c->cksm));
++    memset(c->data, 0, sizeof(c->data));
++    return 1;
++}
++
++int MD2_Update(MD2_CTX *c, const unsigned char *data, size_t len)
++{
++    register UCHAR *p;
++
++    if (len == 0)
++        return 1;
++
++    p = c->data;
++    if (c->num != 0) {
++        if ((c->num + len) >= MD2_BLOCK) {
++            memcpy(&(p[c->num]), data, MD2_BLOCK - c->num);
++            md2_block(c, c->data);
++            data += (MD2_BLOCK - c->num);
++            len -= (MD2_BLOCK - c->num);
++            c->num = 0;
++            /* drop through and do the rest */
++        } else {
++            memcpy(&(p[c->num]), data, len);
++            /* data+=len; */
++            c->num += (int)len;
++            return 1;
++        }
++    }
++    /*
++     * we now can process the input data in blocks of MD2_BLOCK chars and
++     * save the leftovers to c->data.
++     */
++    while (len >= MD2_BLOCK) {
++        md2_block(c, data);
++        data += MD2_BLOCK;
++        len -= MD2_BLOCK;
++    }
++    memcpy(p, data, len);
++    c->num = (int)len;
++    return 1;
++}
++
++static void md2_block(MD2_CTX *c, const unsigned char *d)
++{
++    register MD2_INT t, *sp1, *sp2;
++    register int i, j;
++    MD2_INT state[48];
++
++    sp1 = c->state;
++    sp2 = c->cksm;
++    j = sp2[MD2_BLOCK - 1];
++    for (i = 0; i < 16; i++) {
++        state[i] = sp1[i];
++        state[i + 16] = t = d[i];
++        state[i + 32] = (t ^ sp1[i]);
++        j = sp2[i] ^= S[t ^ j];
++    }
++    t = 0;
++    for (i = 0; i < 18; i++) {
++        for (j = 0; j < 48; j += 8) {
++            t = state[j + 0] ^= S[t];
++            t = state[j + 1] ^= S[t];
++            t = state[j + 2] ^= S[t];
++            t = state[j + 3] ^= S[t];
++            t = state[j + 4] ^= S[t];
++            t = state[j + 5] ^= S[t];
++            t = state[j + 6] ^= S[t];
++            t = state[j + 7] ^= S[t];
++        }
++        t = (t + i) & 0xff;
++    }
++    memcpy(sp1, state, 16 * sizeof(MD2_INT));
++    OPENSSL_cleanse(state, 48 * sizeof(MD2_INT));
++}
++
++int MD2_Final(unsigned char *md, MD2_CTX *c)
++{
++    int i, v;
++    register UCHAR *cp;
++    register MD2_INT *p1, *p2;
++
++    cp = c->data;
++    p1 = c->state;
++    p2 = c->cksm;
++    v = MD2_BLOCK - c->num;
++    for (i = c->num; i < MD2_BLOCK; i++)
++        cp[i] = (UCHAR) v;
++
++    md2_block(c, cp);
++
++    for (i = 0; i < MD2_BLOCK; i++)
++        cp[i] = (UCHAR) p2[i];
++    md2_block(c, cp);
++
++    for (i = 0; i < 16; i++)
++        md[i] = (UCHAR) (p1[i] & 0xff);
++    OPENSSL_cleanse(c, sizeof(*c));
++    return 1;
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/md2/md2_one.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/md2/md2_one.c
+new file mode 100644
+index 0000000..460f96e
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/md2/md2_one.c
+@@ -0,0 +1,47 @@
++/*
++ * Copyright 1995-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include "internal/cryptlib.h"
++#include 
++
++/*
++ * This is a separate file so that #defines in cryptlib.h can map my MD
++ * functions to different names
++ */
++
++unsigned char *MD2(const unsigned char *d, size_t n, unsigned char *md)
++{
++    MD2_CTX c;
++    static unsigned char m[MD2_DIGEST_LENGTH];
++
++    if (md == NULL)
++        md = m;
++    if (!MD2_Init(&c))
++        return NULL;
++#ifndef CHARSET_EBCDIC
++    MD2_Update(&c, d, n);
++#else
++    {
++        char temp[1024];
++        unsigned long chunk;
++
++        while (n > 0) {
++            chunk = (n > sizeof(temp)) ? sizeof(temp) : n;
++            ebcdic2ascii(temp, d, chunk);
++            MD2_Update(&c, temp, chunk);
++            n -= chunk;
++            d += chunk;
++        }
++    }
++#endif
++    MD2_Final(md, &c);
++    OPENSSL_cleanse(&c, sizeof(c)); /* Security consideration */
++    return (md);
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/md4/build.info b/CryptoPkg/Library/OpensslLib/openssl/crypto/md4/build.info
+new file mode 100644
+index 0000000..20846e0
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/md4/build.info
+@@ -0,0 +1,3 @@
++LIBS=../../libcrypto
++SOURCE[../../libcrypto]=\
++        md4_dgst.c md4_one.c
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/md4/md4_dgst.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/md4/md4_dgst.c
+new file mode 100644
+index 0000000..5319618
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/md4/md4_dgst.c
+@@ -0,0 +1,147 @@
++/*
++ * Copyright 1995-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include 
++#include "md4_locl.h"
++
++/*
++ * Implemented from RFC1186 The MD4 Message-Digest Algorithm
++ */
++
++#define INIT_DATA_A (unsigned long)0x67452301L
++#define INIT_DATA_B (unsigned long)0xefcdab89L
++#define INIT_DATA_C (unsigned long)0x98badcfeL
++#define INIT_DATA_D (unsigned long)0x10325476L
++
++int MD4_Init(MD4_CTX *c)
++{
++    memset(c, 0, sizeof(*c));
++    c->A = INIT_DATA_A;
++    c->B = INIT_DATA_B;
++    c->C = INIT_DATA_C;
++    c->D = INIT_DATA_D;
++    return 1;
++}
++
++#ifndef md4_block_data_order
++# ifdef X
++#  undef X
++# endif
++void md4_block_data_order(MD4_CTX *c, const void *data_, size_t num)
++{
++    const unsigned char *data = data_;
++    register unsigned MD32_REG_T A, B, C, D, l;
++# ifndef MD32_XARRAY
++    /* See comment in crypto/sha/sha_locl.h for details. */
++    unsigned MD32_REG_T XX0, XX1, XX2, XX3, XX4, XX5, XX6, XX7,
++        XX8, XX9, XX10, XX11, XX12, XX13, XX14, XX15;
++#  define X(i)   XX##i
++# else
++    MD4_LONG XX[MD4_LBLOCK];
++#  define X(i)   XX[i]
++# endif
++
++    A = c->A;
++    B = c->B;
++    C = c->C;
++    D = c->D;
++
++    for (; num--;) {
++        (void)HOST_c2l(data, l);
++        X(0) = l;
++        (void)HOST_c2l(data, l);
++        X(1) = l;
++        /* Round 0 */
++        R0(A, B, C, D, X(0), 3, 0);
++        (void)HOST_c2l(data, l);
++        X(2) = l;
++        R0(D, A, B, C, X(1), 7, 0);
++        (void)HOST_c2l(data, l);
++        X(3) = l;
++        R0(C, D, A, B, X(2), 11, 0);
++        (void)HOST_c2l(data, l);
++        X(4) = l;
++        R0(B, C, D, A, X(3), 19, 0);
++        (void)HOST_c2l(data, l);
++        X(5) = l;
++        R0(A, B, C, D, X(4), 3, 0);
++        (void)HOST_c2l(data, l);
++        X(6) = l;
++        R0(D, A, B, C, X(5), 7, 0);
++        (void)HOST_c2l(data, l);
++        X(7) = l;
++        R0(C, D, A, B, X(6), 11, 0);
++        (void)HOST_c2l(data, l);
++        X(8) = l;
++        R0(B, C, D, A, X(7), 19, 0);
++        (void)HOST_c2l(data, l);
++        X(9) = l;
++        R0(A, B, C, D, X(8), 3, 0);
++        (void)HOST_c2l(data, l);
++        X(10) = l;
++        R0(D, A, B, C, X(9), 7, 0);
++        (void)HOST_c2l(data, l);
++        X(11) = l;
++        R0(C, D, A, B, X(10), 11, 0);
++        (void)HOST_c2l(data, l);
++        X(12) = l;
++        R0(B, C, D, A, X(11), 19, 0);
++        (void)HOST_c2l(data, l);
++        X(13) = l;
++        R0(A, B, C, D, X(12), 3, 0);
++        (void)HOST_c2l(data, l);
++        X(14) = l;
++        R0(D, A, B, C, X(13), 7, 0);
++        (void)HOST_c2l(data, l);
++        X(15) = l;
++        R0(C, D, A, B, X(14), 11, 0);
++        R0(B, C, D, A, X(15), 19, 0);
++        /* Round 1 */
++        R1(A, B, C, D, X(0), 3, 0x5A827999L);
++        R1(D, A, B, C, X(4), 5, 0x5A827999L);
++        R1(C, D, A, B, X(8), 9, 0x5A827999L);
++        R1(B, C, D, A, X(12), 13, 0x5A827999L);
++        R1(A, B, C, D, X(1), 3, 0x5A827999L);
++        R1(D, A, B, C, X(5), 5, 0x5A827999L);
++        R1(C, D, A, B, X(9), 9, 0x5A827999L);
++        R1(B, C, D, A, X(13), 13, 0x5A827999L);
++        R1(A, B, C, D, X(2), 3, 0x5A827999L);
++        R1(D, A, B, C, X(6), 5, 0x5A827999L);
++        R1(C, D, A, B, X(10), 9, 0x5A827999L);
++        R1(B, C, D, A, X(14), 13, 0x5A827999L);
++        R1(A, B, C, D, X(3), 3, 0x5A827999L);
++        R1(D, A, B, C, X(7), 5, 0x5A827999L);
++        R1(C, D, A, B, X(11), 9, 0x5A827999L);
++        R1(B, C, D, A, X(15), 13, 0x5A827999L);
++        /* Round 2 */
++        R2(A, B, C, D, X(0), 3, 0x6ED9EBA1L);
++        R2(D, A, B, C, X(8), 9, 0x6ED9EBA1L);
++        R2(C, D, A, B, X(4), 11, 0x6ED9EBA1L);
++        R2(B, C, D, A, X(12), 15, 0x6ED9EBA1L);
++        R2(A, B, C, D, X(2), 3, 0x6ED9EBA1L);
++        R2(D, A, B, C, X(10), 9, 0x6ED9EBA1L);
++        R2(C, D, A, B, X(6), 11, 0x6ED9EBA1L);
++        R2(B, C, D, A, X(14), 15, 0x6ED9EBA1L);
++        R2(A, B, C, D, X(1), 3, 0x6ED9EBA1L);
++        R2(D, A, B, C, X(9), 9, 0x6ED9EBA1L);
++        R2(C, D, A, B, X(5), 11, 0x6ED9EBA1L);
++        R2(B, C, D, A, X(13), 15, 0x6ED9EBA1L);
++        R2(A, B, C, D, X(3), 3, 0x6ED9EBA1L);
++        R2(D, A, B, C, X(11), 9, 0x6ED9EBA1L);
++        R2(C, D, A, B, X(7), 11, 0x6ED9EBA1L);
++        R2(B, C, D, A, X(15), 15, 0x6ED9EBA1L);
++
++        A = c->A += A;
++        B = c->B += B;
++        C = c->C += C;
++        D = c->D += D;
++    }
++}
++#endif
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/md4/md4_locl.h b/CryptoPkg/Library/OpensslLib/openssl/crypto/md4/md4_locl.h
+new file mode 100644
+index 0000000..6aec556
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/md4/md4_locl.h
+@@ -0,0 +1,60 @@
++/*
++ * Copyright 1995-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include 
++#include 
++#include 
++
++void md4_block_data_order(MD4_CTX *c, const void *p, size_t num);
++
++#define DATA_ORDER_IS_LITTLE_ENDIAN
++
++#define HASH_LONG               MD4_LONG
++#define HASH_CTX                MD4_CTX
++#define HASH_CBLOCK             MD4_CBLOCK
++#define HASH_UPDATE             MD4_Update
++#define HASH_TRANSFORM          MD4_Transform
++#define HASH_FINAL              MD4_Final
++#define HASH_MAKE_STRING(c,s)   do {    \
++        unsigned long ll;               \
++        ll=(c)->A; (void)HOST_l2c(ll,(s));      \
++        ll=(c)->B; (void)HOST_l2c(ll,(s));      \
++        ll=(c)->C; (void)HOST_l2c(ll,(s));      \
++        ll=(c)->D; (void)HOST_l2c(ll,(s));      \
++        } while (0)
++#define HASH_BLOCK_DATA_ORDER   md4_block_data_order
++
++#include "internal/md32_common.h"
++
++/*-
++#define F(x,y,z)        (((x) & (y))  |  ((~(x)) & (z)))
++#define G(x,y,z)        (((x) & (y))  |  ((x) & ((z))) | ((y) & ((z))))
++*/
++
++/*
++ * As pointed out by Wei Dai , the above can be simplified
++ * to the code below.  Wei attributes these optimizations to Peter Gutmann's
++ * SHS code, and he attributes it to Rich Schroeppel.
++ */
++#define F(b,c,d)        ((((c) ^ (d)) & (b)) ^ (d))
++#define G(b,c,d)        (((b) & (c)) | ((b) & (d)) | ((c) & (d)))
++#define H(b,c,d)        ((b) ^ (c) ^ (d))
++
++#define R0(a,b,c,d,k,s,t) { \
++        a+=((k)+(t)+F((b),(c),(d))); \
++        a=ROTATE(a,s); };
++
++#define R1(a,b,c,d,k,s,t) { \
++        a+=((k)+(t)+G((b),(c),(d))); \
++        a=ROTATE(a,s); };\
++
++#define R2(a,b,c,d,k,s,t) { \
++        a+=((k)+(t)+H((b),(c),(d))); \
++        a=ROTATE(a,s); };
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/md4/md4_one.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/md4/md4_one.c
+new file mode 100644
+index 0000000..9f0989f
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/md4/md4_one.c
+@@ -0,0 +1,47 @@
++/*
++ * Copyright 1995-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include 
++#include 
++#include 
++
++#ifdef CHARSET_EBCDIC
++# include 
++#endif
++
++unsigned char *MD4(const unsigned char *d, size_t n, unsigned char *md)
++{
++    MD4_CTX c;
++    static unsigned char m[MD4_DIGEST_LENGTH];
++
++    if (md == NULL)
++        md = m;
++    if (!MD4_Init(&c))
++        return NULL;
++#ifndef CHARSET_EBCDIC
++    MD4_Update(&c, d, n);
++#else
++    {
++        char temp[1024];
++        unsigned long chunk;
++
++        while (n > 0) {
++            chunk = (n > sizeof(temp)) ? sizeof(temp) : n;
++            ebcdic2ascii(temp, d, chunk);
++            MD4_Update(&c, temp, chunk);
++            n -= chunk;
++            d += chunk;
++        }
++    }
++#endif
++    MD4_Final(md, &c);
++    OPENSSL_cleanse(&c, sizeof(c)); /* security consideration */
++    return (md);
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/md5/asm/md5-586.pl b/CryptoPkg/Library/OpensslLib/openssl/crypto/md5/asm/md5-586.pl
+new file mode 100644
+index 0000000..24f68af
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/md5/asm/md5-586.pl
+@@ -0,0 +1,318 @@
++#! /usr/bin/env perl
++# Copyright 1995-2016 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
++# in the file LICENSE in the source distribution or at
++# https://www.openssl.org/source/license.html
++
++
++# Normal is the
++# md5_block_x86(MD5_CTX *c, ULONG *X);
++# version, non-normal is the
++# md5_block_x86(MD5_CTX *c, ULONG *X,int blocks);
++
++$normal=0;
++
++$0 =~ m/(.*[\/\\])[^\/\\]+$/; $dir=$1;
++push(@INC,"${dir}","${dir}../../perlasm");
++require "x86asm.pl";
++
++$output=pop;
++open STDOUT,">$output";
++
++&asm_init($ARGV[0],$0);
++
++$A="eax";
++$B="ebx";
++$C="ecx";
++$D="edx";
++$tmp1="edi";
++$tmp2="ebp";
++$X="esi";
++
++# What we need to load into $tmp for the next round
++%Ltmp1=("R0",&Np($C), "R1",&Np($C), "R2",&Np($C), "R3",&Np($D));
++@xo=(
++ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,	# R0
++ 1, 6, 11, 0, 5, 10, 15, 4, 9, 14, 3, 8, 13, 2, 7, 12,	# R1
++ 5, 8, 11, 14, 1, 4, 7, 10, 13, 0, 3, 6, 9, 12, 15, 2,	# R2
++ 0, 7, 14, 5, 12, 3, 10, 1, 8, 15, 6, 13, 4, 11, 2, 9,	# R3
++ );
++
++&md5_block("md5_block_asm_data_order");
++&asm_finish();
++
++close STDOUT;
++
++sub Np
++	{
++	local($p)=@_;
++	local(%n)=($A,$D,$B,$A,$C,$B,$D,$C);
++	return($n{$p});
++	}
++
++sub R0
++	{
++	local($pos,$a,$b,$c,$d,$K,$ki,$s,$t)=@_;
++
++	&mov($tmp1,$C)  if $pos < 0;
++	&mov($tmp2,&DWP($xo[$ki]*4,$K,"",0)) if $pos < 0; # very first one 
++
++	# body proper
++
++	&comment("R0 $ki");
++	&xor($tmp1,$d); # F function - part 2
++
++	&and($tmp1,$b); # F function - part 3
++	&lea($a,&DWP($t,$a,$tmp2,1));
++
++	&xor($tmp1,$d); # F function - part 4
++	&mov($tmp2,&DWP($xo[$ki+1]*4,$K,"",0)) if ($pos != 2);
++
++	&add($a,$tmp1);
++
++	&rotl($a,$s);
++
++	&mov($tmp1,&Np($c)) if $pos < 1;	# next tmp1 for R0
++	&mov($tmp1,&Np($c)) if $pos == 1;	# next tmp1 for R1
++
++	&add($a,$b);
++	}
++
++sub R1
++	{
++	local($pos,$a,$b,$c,$d,$K,$ki,$s,$t)=@_;
++
++	&comment("R1 $ki");
++
++	&xor($tmp1,$b); # G function - part 2
++	&and($tmp1,$d); # G function - part 3
++	&lea($a,&DWP($t,$a,$tmp2,1));
++
++	&xor($tmp1,$c);			# G function - part 4
++	&mov($tmp2,&DWP($xo[$ki+1]*4,$K,"",0)) if ($pos != 2);
++
++	&add($a,$tmp1);
++	&mov($tmp1,&Np($c)) if $pos < 1;	# G function - part 1
++	&mov($tmp1,&Np($c)) if $pos == 1;	# G function - part 1
++
++	&rotl($a,$s);
++
++	&add($a,$b);
++	}
++
++sub R2
++	{
++	local($n,$pos,$a,$b,$c,$d,$K,$ki,$s,$t)=@_;
++	# This one is different, only 3 logical operations
++
++if (($n & 1) == 0)
++	{
++	&comment("R2 $ki");
++	# make sure to do 'D' first, not 'B', else we clash with
++	# the last add from the previous round.
++
++	&xor($tmp1,$d); # H function - part 2
++
++	&xor($tmp1,$b); # H function - part 3
++	&lea($a,&DWP($t,$a,$tmp2,1));
++
++	&add($a,$tmp1);
++	&mov($tmp2,&DWP($xo[$ki+1]*4,$K,"",0));
++
++	&rotl($a,$s);
++
++	&mov($tmp1,&Np($c));
++	}
++else
++	{
++	&comment("R2 $ki");
++	# make sure to do 'D' first, not 'B', else we clash with
++	# the last add from the previous round.
++
++	&add($b,$c);			# MOVED FORWARD
++	&xor($tmp1,$d); # H function - part 2
++
++	&lea($a,&DWP($t,$a,$tmp2,1));
++
++	&xor($tmp1,$b); # H function - part 3
++	&mov($tmp2,&DWP($xo[$ki+1]*4,$K,"",0)) if ($pos != 2);
++
++	&add($a,$tmp1);
++	&mov($tmp1,&Np($c)) if $pos < 1;	# H function - part 1
++	&mov($tmp1,-1) if $pos == 1;		# I function - part 1
++
++	&rotl($a,$s);
++
++	&add($a,$b);
++	}
++	}
++
++sub R3
++	{
++	local($pos,$a,$b,$c,$d,$K,$ki,$s,$t)=@_;
++
++	&comment("R3 $ki");
++
++	# ¬($tmp1)
++	&xor($tmp1,$d) if $pos < 0; 	# I function - part 2
++
++	&or($tmp1,$b);				# I function - part 3
++	&lea($a,&DWP($t,$a,$tmp2,1));
++
++	&xor($tmp1,$c); 			# I function - part 4
++	&mov($tmp2,&DWP($xo[$ki+1]*4,$K,"",0))	if $pos != 2; # load X/k value
++	&mov($tmp2,&wparam(0)) if $pos == 2;
++
++	&add($a,$tmp1);
++	&mov($tmp1,-1) if $pos < 1;	# H function - part 1
++	&add($K,64) if $pos >=1 && !$normal;
++
++	&rotl($a,$s);
++
++	&xor($tmp1,&Np($d)) if $pos <= 0; 	# I function - part = first time
++	&mov($tmp1,&DWP( 0,$tmp2,"",0)) if $pos > 0;
++	&add($a,$b);
++	}
++
++
++sub md5_block
++	{
++	local($name)=@_;
++
++	&function_begin_B($name,"",3);
++
++	# parameter 1 is the MD5_CTX structure.
++	# A	0
++	# B	4
++	# C	8
++	# D 	12
++
++	&push("esi");
++	 &push("edi");
++	&mov($tmp1,	&wparam(0)); # edi
++	 &mov($X,	&wparam(1)); # esi
++	&mov($C,	&wparam(2));
++	 &push("ebp");
++	&shl($C,	6);
++	&push("ebx");
++	 &add($C,	$X); # offset we end at
++	&sub($C,	64);
++	 &mov($A,	&DWP( 0,$tmp1,"",0));
++	&push($C);	# Put on the TOS
++	 &mov($B,	&DWP( 4,$tmp1,"",0));
++	&mov($C,	&DWP( 8,$tmp1,"",0));
++	 &mov($D,	&DWP(12,$tmp1,"",0));
++
++	&set_label("start") unless $normal;
++	&comment("");
++	&comment("R0 section");
++
++	&R0(-2,$A,$B,$C,$D,$X, 0, 7,0xd76aa478);
++	&R0( 0,$D,$A,$B,$C,$X, 1,12,0xe8c7b756);
++	&R0( 0,$C,$D,$A,$B,$X, 2,17,0x242070db);
++	&R0( 0,$B,$C,$D,$A,$X, 3,22,0xc1bdceee);
++	&R0( 0,$A,$B,$C,$D,$X, 4, 7,0xf57c0faf);
++	&R0( 0,$D,$A,$B,$C,$X, 5,12,0x4787c62a);
++	&R0( 0,$C,$D,$A,$B,$X, 6,17,0xa8304613);
++	&R0( 0,$B,$C,$D,$A,$X, 7,22,0xfd469501);
++	&R0( 0,$A,$B,$C,$D,$X, 8, 7,0x698098d8);
++	&R0( 0,$D,$A,$B,$C,$X, 9,12,0x8b44f7af);
++	&R0( 0,$C,$D,$A,$B,$X,10,17,0xffff5bb1);
++	&R0( 0,$B,$C,$D,$A,$X,11,22,0x895cd7be);
++	&R0( 0,$A,$B,$C,$D,$X,12, 7,0x6b901122);
++	&R0( 0,$D,$A,$B,$C,$X,13,12,0xfd987193);
++	&R0( 0,$C,$D,$A,$B,$X,14,17,0xa679438e);
++	&R0( 1,$B,$C,$D,$A,$X,15,22,0x49b40821);
++
++	&comment("");
++	&comment("R1 section");
++	&R1(-1,$A,$B,$C,$D,$X,16, 5,0xf61e2562);
++	&R1( 0,$D,$A,$B,$C,$X,17, 9,0xc040b340);
++	&R1( 0,$C,$D,$A,$B,$X,18,14,0x265e5a51);
++	&R1( 0,$B,$C,$D,$A,$X,19,20,0xe9b6c7aa);
++	&R1( 0,$A,$B,$C,$D,$X,20, 5,0xd62f105d);
++	&R1( 0,$D,$A,$B,$C,$X,21, 9,0x02441453);
++	&R1( 0,$C,$D,$A,$B,$X,22,14,0xd8a1e681);
++	&R1( 0,$B,$C,$D,$A,$X,23,20,0xe7d3fbc8);
++	&R1( 0,$A,$B,$C,$D,$X,24, 5,0x21e1cde6);
++	&R1( 0,$D,$A,$B,$C,$X,25, 9,0xc33707d6);
++	&R1( 0,$C,$D,$A,$B,$X,26,14,0xf4d50d87);
++	&R1( 0,$B,$C,$D,$A,$X,27,20,0x455a14ed);
++	&R1( 0,$A,$B,$C,$D,$X,28, 5,0xa9e3e905);
++	&R1( 0,$D,$A,$B,$C,$X,29, 9,0xfcefa3f8);
++	&R1( 0,$C,$D,$A,$B,$X,30,14,0x676f02d9);
++	&R1( 1,$B,$C,$D,$A,$X,31,20,0x8d2a4c8a);
++
++	&comment("");
++	&comment("R2 section");
++	&R2( 0,-1,$A,$B,$C,$D,$X,32, 4,0xfffa3942);
++	&R2( 1, 0,$D,$A,$B,$C,$X,33,11,0x8771f681);
++	&R2( 2, 0,$C,$D,$A,$B,$X,34,16,0x6d9d6122);
++	&R2( 3, 0,$B,$C,$D,$A,$X,35,23,0xfde5380c);
++	&R2( 4, 0,$A,$B,$C,$D,$X,36, 4,0xa4beea44);
++	&R2( 5, 0,$D,$A,$B,$C,$X,37,11,0x4bdecfa9);
++	&R2( 6, 0,$C,$D,$A,$B,$X,38,16,0xf6bb4b60);
++	&R2( 7, 0,$B,$C,$D,$A,$X,39,23,0xbebfbc70);
++	&R2( 8, 0,$A,$B,$C,$D,$X,40, 4,0x289b7ec6);
++	&R2( 9, 0,$D,$A,$B,$C,$X,41,11,0xeaa127fa);
++	&R2(10, 0,$C,$D,$A,$B,$X,42,16,0xd4ef3085);
++	&R2(11, 0,$B,$C,$D,$A,$X,43,23,0x04881d05);
++	&R2(12, 0,$A,$B,$C,$D,$X,44, 4,0xd9d4d039);
++	&R2(13, 0,$D,$A,$B,$C,$X,45,11,0xe6db99e5);
++	&R2(14, 0,$C,$D,$A,$B,$X,46,16,0x1fa27cf8);
++	&R2(15, 1,$B,$C,$D,$A,$X,47,23,0xc4ac5665);
++
++	&comment("");
++	&comment("R3 section");
++	&R3(-1,$A,$B,$C,$D,$X,48, 6,0xf4292244);
++	&R3( 0,$D,$A,$B,$C,$X,49,10,0x432aff97);
++	&R3( 0,$C,$D,$A,$B,$X,50,15,0xab9423a7);
++	&R3( 0,$B,$C,$D,$A,$X,51,21,0xfc93a039);
++	&R3( 0,$A,$B,$C,$D,$X,52, 6,0x655b59c3);
++	&R3( 0,$D,$A,$B,$C,$X,53,10,0x8f0ccc92);
++	&R3( 0,$C,$D,$A,$B,$X,54,15,0xffeff47d);
++	&R3( 0,$B,$C,$D,$A,$X,55,21,0x85845dd1);
++	&R3( 0,$A,$B,$C,$D,$X,56, 6,0x6fa87e4f);
++	&R3( 0,$D,$A,$B,$C,$X,57,10,0xfe2ce6e0);
++	&R3( 0,$C,$D,$A,$B,$X,58,15,0xa3014314);
++	&R3( 0,$B,$C,$D,$A,$X,59,21,0x4e0811a1);
++	&R3( 0,$A,$B,$C,$D,$X,60, 6,0xf7537e82);
++	&R3( 0,$D,$A,$B,$C,$X,61,10,0xbd3af235);
++	&R3( 0,$C,$D,$A,$B,$X,62,15,0x2ad7d2bb);
++	&R3( 2,$B,$C,$D,$A,$X,63,21,0xeb86d391);
++
++	# &mov($tmp2,&wparam(0));	# done in the last R3
++	# &mov($tmp1,	&DWP( 0,$tmp2,"",0)); # done is the last R3
++
++	&add($A,$tmp1);
++	 &mov($tmp1,	&DWP( 4,$tmp2,"",0));
++
++	&add($B,$tmp1);
++	&mov($tmp1,	&DWP( 8,$tmp2,"",0));
++
++	&add($C,$tmp1);
++	&mov($tmp1,	&DWP(12,$tmp2,"",0));
++
++	&add($D,$tmp1);
++	&mov(&DWP( 0,$tmp2,"",0),$A);
++
++	&mov(&DWP( 4,$tmp2,"",0),$B);
++	&mov($tmp1,&swtmp(0)) unless $normal;
++
++	&mov(&DWP( 8,$tmp2,"",0),$C);
++	 &mov(&DWP(12,$tmp2,"",0),$D);
++
++	&cmp($tmp1,$X) unless $normal;			# check count
++	 &jae(&label("start")) unless $normal;
++
++	&pop("eax"); # pop the temp variable off the stack
++	 &pop("ebx");
++	&pop("ebp");
++	 &pop("edi");
++	&pop("esi");
++	 &ret();
++	&function_end_B($name);
++	}
++
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/md5/asm/md5-ia64.S b/CryptoPkg/Library/OpensslLib/openssl/crypto/md5/asm/md5-ia64.S
+new file mode 100644
+index 0000000..c20467b
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/md5/asm/md5-ia64.S
+@@ -0,0 +1,1002 @@
++/*
++ *
++ * Copyright 2005-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++/* Copyright (c) 2005 Hewlett-Packard Development Company, L.P.
++
++Permission is hereby granted, free of charge, to any person obtaining
++a copy of this software and associated documentation files (the
++"Software"), to deal in the Software without restriction, including
++without limitation the rights to use, copy, modify, merge, publish,
++distribute, sublicense, and/or sell copies of the Software, and to
++permit persons to whom the Software is furnished to do so, subject to
++the following conditions:
++
++The above copyright notice and this permission notice shall be
++included in all copies or substantial portions of the Software.
++
++THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
++EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
++MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
++NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
++LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
++OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
++WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.  */
++
++//	Common registers are assigned as follows:
++//
++//	COMMON
++//
++//	t0		Const Tbl Ptr	TPtr
++//	t1		Round Constant	TRound
++//	t4		Block residual	LenResid
++//	t5		Residual Data	DTmp
++//
++//	{in,out}0	Block 0 Cycle	RotateM0
++//	{in,out}1	Block Value 12	M12
++//	{in,out}2	Block Value 8	M8
++//	{in,out}3	Block Value 4	M4
++//	{in,out}4	Block Value 0	M0
++//	{in,out}5	Block 1 Cycle	RotateM1
++//	{in,out}6	Block Value 13	M13
++//	{in,out}7	Block Value 9	M9
++//	{in,out}8	Block Value 5	M5
++//	{in,out}9	Block Value 1	M1
++//	{in,out}10	Block 2 Cycle	RotateM2
++//	{in,out}11	Block Value 14	M14
++//	{in,out}12	Block Value 10	M10
++//	{in,out}13	Block Value 6	M6
++//	{in,out}14	Block Value 2	M2
++//	{in,out}15	Block 3 Cycle	RotateM3
++//	{in,out}16	Block Value 15	M15
++//	{in,out}17	Block Value 11	M11
++//	{in,out}18	Block Value 7	M7
++//	{in,out}19	Block Value 3	M3
++//	{in,out}20	Scratch			Z
++//	{in,out}21	Scratch			Y
++//	{in,out}22	Scratch			X
++//	{in,out}23	Scratch			W
++//	{in,out}24	Digest A		A
++//	{in,out}25	Digest B		B
++//	{in,out}26	Digest C		C
++//	{in,out}27	Digest D		D
++//	{in,out}28	Active Data Ptr	DPtr
++//	in28		Dummy Value		-
++//	out28		Dummy Value		-
++//	bt0			Coroutine Link	QUICK_RTN
++//
++///	These predicates are used for computing the padding block(s) and
++///	are shared between the driver and digest co-routines
++//
++//	pt0			Extra Pad Block	pExtra
++//	pt1			Load next word	pLoad
++//	pt2			Skip next word	pSkip
++//	pt3			Search for Pad	pNoPad
++//	pt4			Pad Word 0		pPad0
++//	pt5			Pad Word 1		pPad1
++//	pt6			Pad Word 2		pPad2
++//	pt7			Pad Word 3		pPad3
++
++#define	DTmp		r19
++#define	LenResid	r18
++#define	QUICK_RTN	b6
++#define	TPtr		r14
++#define	TRound		r15
++#define	pExtra		p6
++#define	pLoad		p7
++#define	pNoPad		p9
++#define	pPad0		p10
++#define	pPad1		p11
++#define	pPad2		p12
++#define	pPad3		p13
++#define	pSkip		p8
++
++#define	A_		out24
++#define	B_		out25
++#define	C_		out26
++#define	D_		out27
++#define	DPtr_		out28
++#define	M0_		out4
++#define	M1_		out9
++#define	M10_		out12
++#define	M11_		out17
++#define	M12_		out1
++#define	M13_		out6
++#define	M14_		out11
++#define	M15_		out16
++#define	M2_		out14
++#define	M3_		out19
++#define	M4_		out3
++#define	M5_		out8
++#define	M6_		out13
++#define	M7_		out18
++#define	M8_		out2
++#define	M9_		out7
++#define	RotateM0_	out0
++#define	RotateM1_	out5
++#define	RotateM2_	out10
++#define	RotateM3_	out15
++#define	W_		out23
++#define	X_		out22
++#define	Y_		out21
++#define	Z_		out20
++
++#define	A		in24
++#define	B		in25
++#define	C		in26
++#define	D		in27
++#define	DPtr		in28
++#define	M0		in4
++#define	M1		in9
++#define	M10		in12
++#define	M11		in17
++#define	M12		in1
++#define	M13		in6
++#define	M14		in11
++#define	M15		in16
++#define	M2		in14
++#define	M3		in19
++#define	M4		in3
++#define	M5		in8
++#define	M6		in13
++#define	M7		in18
++#define	M8		in2
++#define	M9		in7
++#define	RotateM0	in0
++#define	RotateM1	in5
++#define	RotateM2	in10
++#define	RotateM3	in15
++#define	W		in23
++#define	X		in22
++#define	Y		in21
++#define	Z		in20
++
++/* register stack configuration for md5_block_asm_data_order(): */
++#define	MD5_NINP	3
++#define	MD5_NLOC	0
++#define MD5_NOUT	29
++#define MD5_NROT	0
++
++/* register stack configuration for helpers: */
++#define	_NINPUTS	MD5_NOUT
++#define	_NLOCALS	0
++#define _NOUTPUT	0
++#define	_NROTATE	24	/* this must be <= _NINPUTS */
++
++#if defined(_HPUX_SOURCE) && !defined(_LP64)
++#define	ADDP	addp4
++#else
++#define	ADDP	add
++#endif
++
++#if defined(_HPUX_SOURCE) || defined(B_ENDIAN)
++#define HOST_IS_BIG_ENDIAN
++#endif
++
++//	Macros for getting the left and right portions of little-endian words
++
++#define	GETLW(dst, src, align)	dep.z dst = src, 32 - 8 * align, 8 * align
++#define	GETRW(dst, src, align)	extr.u dst = src, 8 * align, 32 - 8 * align
++
++//	MD5 driver
++//
++//		Reads an input block, then calls the digest block
++//		subroutine and adds the results to the accumulated
++//		digest.  It allocates 32 outs which the subroutine
++//		uses as it's inputs and rotating
++//		registers. Initializes the round constant pointer and
++//		takes care of saving/restoring ar.lc
++//
++///	INPUT
++//
++//	in0		Context Ptr		CtxPtr0
++//	in1		Input Data Ptr		DPtrIn
++//	in2		Integral Blocks		BlockCount
++//	rp		Return Address		-
++//
++///	CODE
++//
++//	v2		Input Align		InAlign
++//	t0		Shared w/digest		-
++//	t1		Shared w/digest		-
++//	t2		Shared w/digest		-
++//	t3		Shared w/digest		-
++//	t4		Shared w/digest		-
++//	t5		Shared w/digest		-
++//	t6		PFS Save		PFSSave
++//	t7		ar.lc Save		LCSave
++//	t8		Saved PR		PRSave
++//	t9		2nd CtxPtr		CtxPtr1
++//	t10		Table Base		CTable
++//	t11		Table[0]		CTable0
++//	t13		Accumulator A		AccumA
++//	t14		Accumulator B		AccumB
++//	t15		Accumulator C		AccumC
++//	t16		Accumulator D		AccumD
++//	pt0		Shared w/digest		-
++//	pt1		Shared w/digest		-
++//	pt2		Shared w/digest		-
++//	pt3		Shared w/digest		-
++//	pt4		Shared w/digest		-
++//	pt5		Shared w/digest		-
++//	pt6		Shared w/digest		-
++//	pt7		Shared w/digest		-
++//	pt8		Not Aligned		pOff
++//	pt8		Blocks Left		pAgain
++
++#define	AccumA		r27
++#define	AccumB		r28
++#define	AccumC		r29
++#define	AccumD		r30
++#define	CTable		r24
++#define	CTable0		r25
++#define	CtxPtr0		in0
++#define	CtxPtr1		r23
++#define	DPtrIn		in1
++#define	BlockCount	in2
++#define	InAlign		r10
++#define	LCSave		r21
++#define	PFSSave		r20
++#define	PRSave		r22
++#define	pAgain		p63
++#define	pOff		p63
++
++	.text
++
++/* md5_block_asm_data_order(MD5_CTX *c, const void *data, size_t num)
++
++     where:
++      c: a pointer to a structure of this type:
++
++	   typedef struct MD5state_st
++	     {
++	       MD5_LONG A,B,C,D;
++	       MD5_LONG Nl,Nh;
++	       MD5_LONG data[MD5_LBLOCK];
++	       unsigned int num;
++	     }
++	   MD5_CTX;
++
++      data: a pointer to the input data (may be misaligned)
++      num:  the number of 16-byte blocks to hash (i.e., the length
++            of DATA is 16*NUM.
++
++   */
++
++	.type	md5_block_asm_data_order, @function
++	.global	md5_block_asm_data_order
++	.align	32
++	.proc	md5_block_asm_data_order
++md5_block_asm_data_order:
++.md5_block:
++	.prologue
++{	.mmi
++	.save	ar.pfs, PFSSave
++	alloc	PFSSave = ar.pfs, MD5_NINP, MD5_NLOC, MD5_NOUT, MD5_NROT
++	ADDP	CtxPtr1 = 8, CtxPtr0
++	mov	CTable = ip
++}
++{	.mmi
++	ADDP	DPtrIn = 0, DPtrIn
++	ADDP	CtxPtr0 = 0, CtxPtr0
++	.save	ar.lc, LCSave
++	mov	LCSave = ar.lc
++}
++;;
++{	.mmi
++	add	CTable = .md5_tbl_data_order#-.md5_block#, CTable
++	and	InAlign = 0x3, DPtrIn
++}
++
++{	.mmi
++	ld4	AccumA = [CtxPtr0], 4
++	ld4	AccumC = [CtxPtr1], 4
++	.save pr, PRSave
++	mov	PRSave = pr
++	.body
++}
++;;
++{	.mmi
++	ld4	AccumB = [CtxPtr0]
++	ld4	AccumD = [CtxPtr1]
++	dep	DPtr_ = 0, DPtrIn, 0, 2
++} ;;
++#ifdef HOST_IS_BIG_ENDIAN
++	rum	psr.be;;	// switch to little-endian
++#endif
++{	.mmb
++	ld4	CTable0 = [CTable], 4
++	cmp.ne	pOff, p0 = 0, InAlign
++(pOff)	br.cond.spnt.many .md5_unaligned
++} ;;
++
++//	The FF load/compute loop rotates values three times, so that
++//	loading into M12 here produces the M0 value, M13 -> M1, etc.
++
++.md5_block_loop0:
++{	.mmi
++	ld4	M12_ = [DPtr_], 4
++	mov	TPtr = CTable
++	mov	TRound = CTable0
++} ;;
++{	.mmi
++	ld4	M13_ = [DPtr_], 4
++	mov	A_ = AccumA
++	mov	B_ = AccumB
++} ;;
++{	.mmi
++	ld4	M14_ = [DPtr_], 4
++	mov	C_ = AccumC
++	mov	D_ = AccumD
++} ;;
++{	.mmb
++	ld4	M15_ = [DPtr_], 4
++	add	BlockCount = -1, BlockCount
++	br.call.sptk.many QUICK_RTN = md5_digest_block0
++} ;;
++
++//	Now, we add the new digest values and do some clean-up
++//	before checking if there's another full block to process
++
++{	.mmi
++	add	AccumA = AccumA, A_
++	add	AccumB = AccumB, B_
++	cmp.ne	pAgain, p0 = 0, BlockCount
++}
++{	.mib
++	add	AccumC = AccumC, C_
++	add	AccumD = AccumD, D_
++(pAgain) br.cond.dptk.many .md5_block_loop0
++} ;;
++
++.md5_exit:
++#ifdef HOST_IS_BIG_ENDIAN
++	sum	psr.be;;	// switch back to big-endian mode
++#endif
++{	.mmi
++	st4	[CtxPtr0] = AccumB, -4
++	st4	[CtxPtr1] = AccumD, -4
++	mov	pr = PRSave, 0x1ffff ;;
++}
++{	.mmi
++	st4	[CtxPtr0] = AccumA
++	st4	[CtxPtr1] = AccumC
++	mov	ar.lc = LCSave
++} ;;
++{	.mib
++	mov	ar.pfs = PFSSave
++	br.ret.sptk.few	rp
++} ;;
++
++#define	MD5UNALIGNED(offset)						\
++.md5_process##offset:							\
++{	.mib ;								\
++	nop	0x0	;						\
++	GETRW(DTmp, DTmp, offset) ;					\
++} ;;									\
++.md5_block_loop##offset:						\
++{	.mmi ;								\
++	ld4	Y_ = [DPtr_], 4 ;					\
++	mov	TPtr = CTable ;						\
++	mov	TRound = CTable0 ;					\
++} ;;									\
++{	.mmi ;								\
++	ld4	M13_ = [DPtr_], 4 ;					\
++	mov	A_ = AccumA ;						\
++	mov	B_ = AccumB ;						\
++} ;;									\
++{	.mii ;								\
++	ld4	M14_ = [DPtr_], 4 ;					\
++	GETLW(W_, Y_, offset) ;						\
++	mov	C_ = AccumC ;						\
++}									\
++{	.mmi ;								\
++	mov	D_ = AccumD ;;						\
++	or	M12_ = W_, DTmp ;					\
++	GETRW(DTmp, Y_, offset) ;					\
++}									\
++{	.mib ;								\
++	ld4	M15_ = [DPtr_], 4 ;					\
++	add	BlockCount = -1, BlockCount ;				\
++	br.call.sptk.many QUICK_RTN = md5_digest_block##offset;		\
++} ;;									\
++{	.mmi ;								\
++	add	AccumA = AccumA, A_ ;					\
++	add	AccumB = AccumB, B_ ;					\
++	cmp.ne	pAgain, p0 = 0, BlockCount ;				\
++}									\
++{	.mib ;								\
++	add	AccumC = AccumC, C_ ;					\
++	add	AccumD = AccumD, D_ ;					\
++(pAgain) br.cond.dptk.many .md5_block_loop##offset ;			\
++} ;;									\
++{	.mib ;								\
++	nop	0x0 ;							\
++	nop	0x0 ;							\
++	br.cond.sptk.many .md5_exit ;					\
++} ;;
++
++	.align	32
++.md5_unaligned:
++//
++//	Because variable shifts are expensive, we special case each of
++//	the four alignements. In practice, this won't hurt too much
++//	since only one working set of code will be loaded.
++//
++{	.mib
++	ld4	DTmp = [DPtr_], 4
++	cmp.eq	pOff, p0 = 1, InAlign
++(pOff)	br.cond.dpnt.many .md5_process1
++} ;;
++{	.mib
++	cmp.eq	pOff, p0 = 2, InAlign
++	nop	0x0
++(pOff)	br.cond.dpnt.many .md5_process2
++} ;;
++	MD5UNALIGNED(3)
++	MD5UNALIGNED(1)
++	MD5UNALIGNED(2)
++
++	.endp md5_block_asm_data_order
++
++
++// MD5 Perform the F function and load
++//
++// Passed the first 4 words (M0 - M3) and initial (A, B, C, D) values,
++// computes the FF() round of functions, then branches to the common
++// digest code to finish up with GG(), HH, and II().
++//
++// INPUT
++//
++// rp Return Address -
++//
++// CODE
++//
++// v0 PFS bit bucket PFS
++// v1 Loop Trip Count LTrip
++// pt0 Load next word pMore
++
++/* For F round: */
++#define LTrip	r9
++#define PFS	r8
++#define pMore	p6
++
++/* For GHI rounds: */
++#define T	r9
++#define U	r10
++#define V	r11
++
++#define COMPUTE(a, b, s, M, R)			\
++{						\
++	.mii ;					\
++	ld4 TRound = [TPtr], 4 ;		\
++	dep.z Y = Z, 32, 32 ;;			\
++	shrp Z = Z, Y, 64 - s ;			\
++} ;;						\
++{						\
++	.mmi ;					\
++	add a = Z, b ;				\
++	mov R = M ;				\
++	nop 0x0 ;				\
++} ;;
++
++#define LOOP(a, b, s, M, R, label)		\
++{	.mii ;					\
++	ld4 TRound = [TPtr], 4 ;		\
++	dep.z Y = Z, 32, 32 ;;			\
++	shrp Z = Z, Y, 64 - s ;			\
++} ;;						\
++{	.mib ;					\
++	add a = Z, b ;				\
++	mov R = M ;				\
++	br.ctop.sptk.many label ;		\
++} ;;
++
++// G(B, C, D) = (B & D) | (C & ~D)
++
++#define G(a, b, c, d, M)			\
++{	.mmi ;					\
++	add Z = M, TRound ;			\
++	and Y = b, d ;				\
++	andcm X = c, d ;			\
++} ;;						\
++{	.mii ;					\
++	add Z = Z, a ;				\
++	or Y = Y, X ;;				\
++	add Z = Z, Y ;				\
++} ;;
++
++// H(B, C, D) = B ^ C ^ D
++
++#define H(a, b, c, d, M)			\
++{	.mmi ;					\
++	add Z = M, TRound ;			\
++	xor Y = b, c ;				\
++	nop 0x0 ;				\
++} ;;						\
++{	.mii ;					\
++	add Z = Z, a ;				\
++	xor Y = Y, d ;;				\
++	add Z = Z, Y ;				\
++} ;;
++
++// I(B, C, D) = C ^ (B | ~D)
++//
++// However, since we have an andcm operator, we use the fact that
++//
++// Y ^ Z == ~Y ^ ~Z
++//
++// to rewrite the expression as
++//
++// I(B, C, D) = ~C ^ (~B & D)
++
++#define I(a, b, c, d, M)			\
++{	.mmi ;					\
++	add Z = M, TRound ;			\
++	andcm Y = d, b ;			\
++	andcm X = -1, c ;			\
++} ;;						\
++{	.mii ;					\
++	add Z = Z, a ;				\
++	xor Y = Y, X ;;				\
++	add Z = Z, Y ;				\
++} ;;
++
++#define GG4(label)				\
++	G(A, B, C, D, M0)			\
++	COMPUTE(A, B, 5, M0, RotateM0)		\
++	G(D, A, B, C, M1)			\
++	COMPUTE(D, A, 9, M1, RotateM1)		\
++	G(C, D, A, B, M2)			\
++	COMPUTE(C, D, 14, M2, RotateM2)		\
++	G(B, C, D, A, M3)			\
++	LOOP(B, C, 20, M3, RotateM3, label)
++
++#define HH4(label)				\
++	H(A, B, C, D, M0)			\
++	COMPUTE(A, B, 4, M0, RotateM0)		\
++	H(D, A, B, C, M1)			\
++	COMPUTE(D, A, 11, M1, RotateM1)		\
++	H(C, D, A, B, M2)			\
++	COMPUTE(C, D, 16, M2, RotateM2)		\
++	H(B, C, D, A, M3)			\
++	LOOP(B, C, 23, M3, RotateM3, label)
++
++#define II4(label)				\
++	I(A, B, C, D, M0)			\
++	COMPUTE(A, B, 6, M0, RotateM0)		\
++	I(D, A, B, C, M1)			\
++	COMPUTE(D, A, 10, M1, RotateM1)		\
++	I(C, D, A, B, M2)			\
++	COMPUTE(C, D, 15, M2, RotateM2)		\
++	I(B, C, D, A, M3)			\
++	LOOP(B, C, 21, M3, RotateM3, label)
++
++#define FFLOAD(a, b, c, d, M, N, s)		\
++{	.mii ;					\
++(pMore) ld4 N = [DPtr], 4 ;			\
++	add Z = M, TRound ;			\
++	and Y = c, b ;				\
++}						\
++{	.mmi ;					\
++	andcm X = d, b ;;			\
++	add Z = Z, a ;				\
++	or Y = Y, X ;				\
++} ;;						\
++{	.mii ;					\
++	ld4 TRound = [TPtr], 4 ;		\
++	add Z = Z, Y ;;				\
++	dep.z Y = Z, 32, 32 ;			\
++} ;;						\
++{	.mii ;					\
++	nop 0x0 ;				\
++	shrp Z = Z, Y, 64 - s ;;		\
++	add a = Z, b ;				\
++} ;;
++
++#define FFLOOP(a, b, c, d, M, N, s, dest)	\
++{	.mii ;					\
++(pMore)	ld4 N = [DPtr], 4 ;			\
++	add Z = M, TRound ;			\
++	and Y = c, b ;				\
++}						\
++{	.mmi ;					\
++	andcm X = d, b ;;			\
++	add Z = Z, a ;				\
++	or Y = Y, X ;				\
++} ;;						\
++{	.mii ;					\
++	ld4 TRound = [TPtr], 4 ;		\
++	add Z = Z, Y ;;				\
++	dep.z Y = Z, 32, 32 ;			\
++} ;;						\
++{	.mii ;					\
++	nop 0x0 ;				\
++	shrp Z = Z, Y, 64 - s ;;		\
++	add a = Z, b ;				\
++}						\
++{	.mib ;					\
++	cmp.ne pMore, p0 = 0, LTrip ;		\
++	add LTrip = -1, LTrip ;			\
++	br.ctop.dptk.many dest ;		\
++} ;;
++
++	.type md5_digest_block0, @function
++	.align 32
++
++	.proc md5_digest_block0
++	.prologue
++md5_digest_block0:
++	.altrp QUICK_RTN
++	.body
++{	.mmi
++	alloc PFS = ar.pfs, _NINPUTS, _NLOCALS, _NOUTPUT, _NROTATE
++	mov LTrip = 2
++	mov ar.lc = 3
++} ;;
++{	.mii
++	cmp.eq pMore, p0 = r0, r0
++	mov ar.ec = 0
++	nop 0x0
++} ;;
++
++.md5_FF_round0:
++	FFLOAD(A, B, C, D, M12, RotateM0, 7)
++	FFLOAD(D, A, B, C, M13, RotateM1, 12)
++	FFLOAD(C, D, A, B, M14, RotateM2, 17)
++	FFLOOP(B, C, D, A, M15, RotateM3, 22, .md5_FF_round0)
++	//
++	// !!! Fall through to md5_digest_GHI
++	//
++	.endp md5_digest_block0
++
++	.type md5_digest_GHI, @function
++	.align 32
++
++	.proc md5_digest_GHI
++	.prologue
++	.regstk _NINPUTS, _NLOCALS, _NOUTPUT, _NROTATE
++md5_digest_GHI:
++	.altrp QUICK_RTN
++	.body
++//
++// The following sequence shuffles the block counstants round for the
++// next round:
++//
++// 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
++// 1 6 11 0 5 10 14 4 9 14 3 8 13 2 7 12
++//
++{	.mmi
++	mov Z = M0
++	mov Y = M15
++	mov ar.lc = 3
++}
++{	.mmi
++	mov X = M2
++	mov W = M9
++	mov V = M4
++} ;;
++
++{	.mmi
++	mov M0 = M1
++	mov M15 = M12
++	mov ar.ec = 1
++}
++{	.mmi
++	mov M2 = M11
++	mov M9 = M14
++	mov M4 = M5
++} ;;
++
++{	.mmi
++	mov M1 = M6
++	mov M12 = M13
++	mov U = M3
++}
++{	.mmi
++	mov M11 = M8
++	mov M14 = M7
++	mov M5 = M10
++} ;;
++
++{	.mmi
++	mov M6 = Y
++	mov M13 = X
++	mov M3 = Z
++}
++{	.mmi
++	mov M8 = W
++	mov M7 = V
++	mov M10 = U
++} ;;
++
++.md5_GG_round:
++	GG4(.md5_GG_round)
++
++// The following sequence shuffles the block constants round for the
++// next round:
++//
++// 1 6 11 0 5 10 14 4 9 14 3 8 13 2 7 12
++// 5 8 11 14 1 4 7 10 13 0 3 6 9 12 15 2
++
++{	.mmi
++	mov Z = M0
++	mov Y = M1
++	mov ar.lc = 3
++}
++{	.mmi
++	mov X = M3
++	mov W = M5
++	mov V = M6
++} ;;
++
++{	.mmi
++	mov M0 = M4
++	mov M1 = M11
++	mov ar.ec = 1
++}
++{	.mmi
++	mov M3 = M9
++	mov U = M8
++	mov T = M13
++} ;;
++
++{	.mmi
++	mov M4 = Z
++	mov M11 = Y
++	mov M5 = M7
++}
++{	.mmi
++	mov M6 = M14
++	mov M8 = M12
++	mov M13 = M15
++} ;;
++
++{	.mmi
++	mov M7 = W
++	mov M14 = V
++	nop 0x0
++}
++{	.mmi
++	mov M9 = X
++	mov M12 = U
++	mov M15 = T
++} ;;
++
++.md5_HH_round:
++	HH4(.md5_HH_round)
++
++// The following sequence shuffles the block constants round for the
++// next round:
++//
++// 5 8 11 14 1 4 7 10 13 0 3 6 9 12 15 2
++// 0 7 14 5 12 3 10 1 8 15 6 13 4 11 2 9
++
++{	.mmi
++	mov Z = M0
++	mov Y = M15
++	mov ar.lc = 3
++}
++{	.mmi
++	mov X = M10
++	mov W = M1
++	mov V = M4
++} ;;
++
++{	.mmi
++	mov M0 = M9
++	mov M15 = M12
++	mov ar.ec = 1
++}
++{	.mmi
++	mov M10 = M11
++	mov M1 = M6
++	mov M4 = M13
++} ;;
++
++{	.mmi
++	mov M9 = M14
++	mov M12 = M5
++	mov U = M3
++}
++{	.mmi
++	mov M11 = M8
++	mov M6 = M7
++	mov M13 = M2
++} ;;
++
++{	.mmi
++	mov M14 = Y
++	mov M5 = X
++	mov M3 = Z
++}
++{	.mmi
++	mov M8 = W
++	mov M7 = V
++	mov M2 = U
++} ;;
++
++.md5_II_round:
++	II4(.md5_II_round)
++
++{	.mib
++	nop 0x0
++	nop 0x0
++	br.ret.sptk.many QUICK_RTN
++} ;;
++
++	.endp md5_digest_GHI
++
++#define FFLOADU(a, b, c, d, M, P, N, s, offset)	\
++{	.mii ;					\
++(pMore) ld4 N = [DPtr], 4 ;			\
++	add Z = M, TRound ;			\
++	and Y = c, b ;				\
++}						\
++{	.mmi ;					\
++	andcm X = d, b ;;			\
++	add Z = Z, a ;				\
++	or Y = Y, X ;				\
++} ;;						\
++{	.mii ;					\
++	ld4 TRound = [TPtr], 4 ;		\
++	GETLW(W, P, offset) ;			\
++	add Z = Z, Y ;				\
++} ;;						\
++{	.mii ;					\
++	or W = W, DTmp ;			\
++	dep.z Y = Z, 32, 32 ;;			\
++	shrp Z = Z, Y, 64 - s ;			\
++} ;;						\
++{	.mii ;					\
++	add a = Z, b ;				\
++	GETRW(DTmp, P, offset) ;		\
++	mov P = W ;				\
++} ;;
++
++#define FFLOOPU(a, b, c, d, M, P, N, s, offset)		\
++{	.mii ;						\
++(pMore) ld4 N = [DPtr], 4 ;				\
++	add Z = M, TRound ;				\
++	and Y = c, b ;					\
++}							\
++{	.mmi ;						\
++	andcm X = d, b ;;				\
++	add Z = Z, a ;					\
++	or Y = Y, X ;					\
++} ;;							\
++{	.mii ;						\
++	ld4 TRound = [TPtr], 4 ;			\
++(pMore) GETLW(W, P, offset) 	;			\
++	add Z = Z, Y ;					\
++} ;;							\
++{	.mii ;						\
++(pMore) or W = W, DTmp ;				\
++	dep.z Y = Z, 32, 32 ;;				\
++	shrp Z = Z, Y, 64 - s ;				\
++} ;;							\
++{	.mii ;						\
++	add a = Z, b ;					\
++(pMore) GETRW(DTmp, P, offset) 	;			\
++(pMore) mov P = W ;					\
++}							\
++{	.mib ;						\
++	cmp.ne pMore, p0 = 0, LTrip ;			\
++	add LTrip = -1, LTrip ;				\
++	br.ctop.sptk.many .md5_FF_round##offset ;	\
++} ;;
++
++#define MD5FBLOCK(offset)						\
++	.type md5_digest_block##offset, @function ;			\
++									\
++	.align 32 ;							\
++	.proc md5_digest_block##offset ;				\
++	.prologue ;							\
++	.altrp QUICK_RTN ;						\
++	.body ;								\
++md5_digest_block##offset:						\
++{	.mmi ;								\
++	alloc PFS = ar.pfs, _NINPUTS, _NLOCALS, _NOUTPUT, _NROTATE ;	\
++	mov LTrip = 2 ;							\
++	mov ar.lc = 3 ;							\
++} ;;									\
++{	.mii ;								\
++	cmp.eq pMore, p0 = r0, r0 ;					\
++	mov ar.ec = 0 ;							\
++	nop 0x0 ;							\
++} ;;									\
++									\
++	.pred.rel "mutex", pLoad, pSkip ;				\
++.md5_FF_round##offset:							\
++	FFLOADU(A, B, C, D, M12, M13, RotateM0, 7, offset)		\
++	FFLOADU(D, A, B, C, M13, M14, RotateM1, 12, offset)		\
++	FFLOADU(C, D, A, B, M14, M15, RotateM2, 17, offset)		\
++	FFLOOPU(B, C, D, A, M15, RotateM0, RotateM3, 22, offset)	\
++									\
++{	.mib ;								\
++	nop 0x0 ;							\
++	nop 0x0 ;							\
++	br.cond.sptk.many md5_digest_GHI ;				\
++} ;;									\
++	.endp md5_digest_block##offset
++
++MD5FBLOCK(1)
++MD5FBLOCK(2)
++MD5FBLOCK(3)
++
++	.align 64
++	.type md5_constants, @object
++md5_constants:
++.md5_tbl_data_order:			// To ensure little-endian data
++					// order, code as bytes.
++	data1 0x78, 0xa4, 0x6a, 0xd7	//     0
++	data1 0x56, 0xb7, 0xc7, 0xe8	//     1
++	data1 0xdb, 0x70, 0x20, 0x24	//     2
++	data1 0xee, 0xce, 0xbd, 0xc1	//     3
++	data1 0xaf, 0x0f, 0x7c, 0xf5	//     4
++	data1 0x2a, 0xc6, 0x87, 0x47	//     5
++	data1 0x13, 0x46, 0x30, 0xa8	//     6
++	data1 0x01, 0x95, 0x46, 0xfd	//     7
++	data1 0xd8, 0x98, 0x80, 0x69	//     8
++	data1 0xaf, 0xf7, 0x44, 0x8b	//     9
++	data1 0xb1, 0x5b, 0xff, 0xff	//    10
++	data1 0xbe, 0xd7, 0x5c, 0x89	//    11
++	data1 0x22, 0x11, 0x90, 0x6b	//    12
++	data1 0x93, 0x71, 0x98, 0xfd	//    13
++	data1 0x8e, 0x43, 0x79, 0xa6	//    14
++	data1 0x21, 0x08, 0xb4, 0x49	//    15
++	data1 0x62, 0x25, 0x1e, 0xf6	//    16
++	data1 0x40, 0xb3, 0x40, 0xc0	//    17
++	data1 0x51, 0x5a, 0x5e, 0x26	//    18
++	data1 0xaa, 0xc7, 0xb6, 0xe9	//    19
++	data1 0x5d, 0x10, 0x2f, 0xd6	//    20
++	data1 0x53, 0x14, 0x44, 0x02	//    21
++	data1 0x81, 0xe6, 0xa1, 0xd8	//    22
++	data1 0xc8, 0xfb, 0xd3, 0xe7	//    23
++	data1 0xe6, 0xcd, 0xe1, 0x21	//    24
++	data1 0xd6, 0x07, 0x37, 0xc3	//    25
++	data1 0x87, 0x0d, 0xd5, 0xf4	//    26
++	data1 0xed, 0x14, 0x5a, 0x45	//    27
++	data1 0x05, 0xe9, 0xe3, 0xa9	//    28
++	data1 0xf8, 0xa3, 0xef, 0xfc	//    29
++	data1 0xd9, 0x02, 0x6f, 0x67	//    30
++	data1 0x8a, 0x4c, 0x2a, 0x8d	//    31
++	data1 0x42, 0x39, 0xfa, 0xff	//    32
++	data1 0x81, 0xf6, 0x71, 0x87	//    33
++	data1 0x22, 0x61, 0x9d, 0x6d	//    34
++	data1 0x0c, 0x38, 0xe5, 0xfd	//    35
++	data1 0x44, 0xea, 0xbe, 0xa4	//    36
++	data1 0xa9, 0xcf, 0xde, 0x4b	//    37
++	data1 0x60, 0x4b, 0xbb, 0xf6	//    38
++	data1 0x70, 0xbc, 0xbf, 0xbe	//    39
++	data1 0xc6, 0x7e, 0x9b, 0x28	//    40
++	data1 0xfa, 0x27, 0xa1, 0xea	//    41
++	data1 0x85, 0x30, 0xef, 0xd4	//    42
++	data1 0x05, 0x1d, 0x88, 0x04	//    43
++	data1 0x39, 0xd0, 0xd4, 0xd9	//    44
++	data1 0xe5, 0x99, 0xdb, 0xe6	//    45
++	data1 0xf8, 0x7c, 0xa2, 0x1f	//    46
++	data1 0x65, 0x56, 0xac, 0xc4	//    47
++	data1 0x44, 0x22, 0x29, 0xf4	//    48
++	data1 0x97, 0xff, 0x2a, 0x43	//    49
++	data1 0xa7, 0x23, 0x94, 0xab	//    50
++	data1 0x39, 0xa0, 0x93, 0xfc	//    51
++	data1 0xc3, 0x59, 0x5b, 0x65	//    52
++	data1 0x92, 0xcc, 0x0c, 0x8f	//    53
++	data1 0x7d, 0xf4, 0xef, 0xff	//    54
++	data1 0xd1, 0x5d, 0x84, 0x85	//    55
++	data1 0x4f, 0x7e, 0xa8, 0x6f	//    56
++	data1 0xe0, 0xe6, 0x2c, 0xfe	//    57
++	data1 0x14, 0x43, 0x01, 0xa3	//    58
++	data1 0xa1, 0x11, 0x08, 0x4e	//    59
++	data1 0x82, 0x7e, 0x53, 0xf7	//    60
++	data1 0x35, 0xf2, 0x3a, 0xbd	//    61
++	data1 0xbb, 0xd2, 0xd7, 0x2a	//    62
++	data1 0x91, 0xd3, 0x86, 0xeb	//    63
++.size	md5_constants#,64*4
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/md5/asm/md5-sparcv9.pl b/CryptoPkg/Library/OpensslLib/openssl/crypto/md5/asm/md5-sparcv9.pl
+new file mode 100644
+index 0000000..09e6d71
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/md5/asm/md5-sparcv9.pl
+@@ -0,0 +1,437 @@
++#! /usr/bin/env perl
++# Copyright 2012-2016 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
++# in the file LICENSE in the source distribution or at
++# https://www.openssl.org/source/license.html
++
++
++# ====================================================================
++# Written by Andy Polyakov  for the OpenSSL
++# project. The module is, however, dual licensed under OpenSSL and
++# CRYPTOGAMS licenses depending on where you obtain it. For further
++# details see http://www.openssl.org/~appro/cryptogams/.
++#
++# Hardware SPARC T4 support by David S. Miller .
++# ====================================================================
++
++# MD5 for SPARCv9, 6.9 cycles per byte on UltraSPARC, >40% faster than
++# code generated by Sun C 5.2.
++
++# SPARC T4 MD5 hardware achieves 3.20 cycles per byte, which is 2.1x
++# faster than software. Multi-process benchmark saturates at 12x
++# single-process result on 8-core processor, or ~11GBps per 2.85GHz
++# socket.
++
++$output=pop;
++open STDOUT,">$output";
++
++use integer;
++
++($ctx,$inp,$len)=("%i0","%i1","%i2");	# input arguments
++
++# 64-bit values
++@X=("%o0","%o1","%o2","%o3","%o4","%o5","%o7","%g1","%g2");
++$tx="%g3";
++($AB,$CD)=("%g4","%g5");
++
++# 32-bit values
++@V=($A,$B,$C,$D)=map("%l$_",(0..3));
++($t1,$t2,$t3,$saved_asi)=map("%l$_",(4..7));
++($shr,$shl1,$shl2)=("%i3","%i4","%i5");
++
++my @K=(	0xd76aa478,0xe8c7b756,0x242070db,0xc1bdceee,
++	0xf57c0faf,0x4787c62a,0xa8304613,0xfd469501,
++	0x698098d8,0x8b44f7af,0xffff5bb1,0x895cd7be,
++	0x6b901122,0xfd987193,0xa679438e,0x49b40821,
++
++	0xf61e2562,0xc040b340,0x265e5a51,0xe9b6c7aa,
++	0xd62f105d,0x02441453,0xd8a1e681,0xe7d3fbc8,
++	0x21e1cde6,0xc33707d6,0xf4d50d87,0x455a14ed,
++	0xa9e3e905,0xfcefa3f8,0x676f02d9,0x8d2a4c8a,
++
++	0xfffa3942,0x8771f681,0x6d9d6122,0xfde5380c,
++	0xa4beea44,0x4bdecfa9,0xf6bb4b60,0xbebfbc70,
++	0x289b7ec6,0xeaa127fa,0xd4ef3085,0x04881d05,
++	0xd9d4d039,0xe6db99e5,0x1fa27cf8,0xc4ac5665,
++
++	0xf4292244,0x432aff97,0xab9423a7,0xfc93a039,
++	0x655b59c3,0x8f0ccc92,0xffeff47d,0x85845dd1,
++	0x6fa87e4f,0xfe2ce6e0,0xa3014314,0x4e0811a1,
++	0xf7537e82,0xbd3af235,0x2ad7d2bb,0xeb86d391, 0	);
++
++sub R0 {
++  my ($i,$a,$b,$c,$d) = @_;
++  my $rot = (7,12,17,22)[$i%4];
++  my $j   = ($i+1)/2;
++
++  if ($i&1) {
++    $code.=<<___;
++	 srlx	@X[$j],$shr,@X[$j]	! align X[`$i+1`]
++	and	$b,$t1,$t1		! round $i
++	 sllx	@X[$j+1],$shl1,$tx
++	add	$t2,$a,$a
++	 sllx	$tx,$shl2,$tx
++	xor	$d,$t1,$t1
++	 or	$tx,@X[$j],@X[$j]
++	 sethi	%hi(@K[$i+1]),$t2
++	add	$t1,$a,$a
++	 or	$t2,%lo(@K[$i+1]),$t2
++	sll	$a,$rot,$t3
++	 add	@X[$j],$t2,$t2		! X[`$i+1`]+K[`$i+1`]
++	srl	$a,32-$rot,$a
++	add	$b,$t3,$t3
++	 xor	 $b,$c,$t1
++	add	$t3,$a,$a
++___
++  } else {
++    $code.=<<___;
++	 srlx	@X[$j],32,$tx		! extract X[`2*$j+1`]
++	and	$b,$t1,$t1		! round $i
++	add	$t2,$a,$a
++	xor	$d,$t1,$t1
++	 sethi	%hi(@K[$i+1]),$t2
++	add	$t1,$a,$a
++	 or	$t2,%lo(@K[$i+1]),$t2
++	sll	$a,$rot,$t3
++	 add	$tx,$t2,$t2		! X[`2*$j+1`]+K[`$i+1`]
++	srl	$a,32-$rot,$a
++	add	$b,$t3,$t3
++	 xor	 $b,$c,$t1
++	add	$t3,$a,$a
++___
++  }
++}
++
++sub R0_1 {
++  my ($i,$a,$b,$c,$d) = @_;
++  my $rot = (7,12,17,22)[$i%4];
++
++$code.=<<___;
++	 srlx	@X[0],32,$tx		! extract X[1]
++	and	$b,$t1,$t1		! round $i
++	add	$t2,$a,$a
++	xor	$d,$t1,$t1
++	 sethi	%hi(@K[$i+1]),$t2
++	add	$t1,$a,$a
++	 or	$t2,%lo(@K[$i+1]),$t2
++	sll	$a,$rot,$t3
++	 add	$tx,$t2,$t2		! X[1]+K[`$i+1`]
++	srl	$a,32-$rot,$a
++	add	$b,$t3,$t3
++	 andn	 $b,$c,$t1
++	add	$t3,$a,$a
++___
++}
++
++sub R1 {
++  my ($i,$a,$b,$c,$d) = @_;
++  my $rot = (5,9,14,20)[$i%4];
++  my $j   = $i<31 ? (1+5*($i+1))%16 : (5+3*($i+1))%16;
++  my $xi  = @X[$j/2];
++
++$code.=<<___ if ($j&1 && ($xi=$tx));
++	 srlx	@X[$j/2],32,$xi		! extract X[$j]
++___
++$code.=<<___;
++	and	$b,$d,$t3		! round $i
++	add	$t2,$a,$a
++	or	$t3,$t1,$t1
++	 sethi	%hi(@K[$i+1]),$t2
++	add	$t1,$a,$a
++	 or	$t2,%lo(@K[$i+1]),$t2
++	sll	$a,$rot,$t3
++	 add	$xi,$t2,$t2		! X[$j]+K[`$i+1`]
++	srl	$a,32-$rot,$a
++	add	$b,$t3,$t3
++	 `$i<31?"andn":"xor"`	 $b,$c,$t1
++	add	$t3,$a,$a
++___
++}
++
++sub R2 {
++  my ($i,$a,$b,$c,$d) = @_;
++  my $rot = (4,11,16,23)[$i%4];
++  my $j   = $i<47 ? (5+3*($i+1))%16 : (0+7*($i+1))%16;
++  my $xi  = @X[$j/2];
++
++$code.=<<___ if ($j&1 && ($xi=$tx));
++	 srlx	@X[$j/2],32,$xi		! extract X[$j]
++___
++$code.=<<___;
++	add	$t2,$a,$a		! round $i
++	xor	$b,$t1,$t1
++	 sethi	%hi(@K[$i+1]),$t2
++	add	$t1,$a,$a
++	 or	$t2,%lo(@K[$i+1]),$t2
++	sll	$a,$rot,$t3
++	 add	$xi,$t2,$t2		! X[$j]+K[`$i+1`]
++	srl	$a,32-$rot,$a
++	add	$b,$t3,$t3
++	 xor	 $b,$c,$t1
++	add	$t3,$a,$a
++___
++}
++
++sub R3 {
++  my ($i,$a,$b,$c,$d) = @_;
++  my $rot = (6,10,15,21)[$i%4];
++  my $j   = (0+7*($i+1))%16;
++  my $xi  = @X[$j/2];
++
++$code.=<<___;
++	add	$t2,$a,$a		! round $i
++___
++$code.=<<___ if ($j&1 && ($xi=$tx));
++	 srlx	@X[$j/2],32,$xi		! extract X[$j]
++___
++$code.=<<___;
++	orn	$b,$d,$t1
++	 sethi	%hi(@K[$i+1]),$t2
++	xor	$c,$t1,$t1
++	 or	$t2,%lo(@K[$i+1]),$t2
++	add	$t1,$a,$a
++	sll	$a,$rot,$t3
++	 add	$xi,$t2,$t2		! X[$j]+K[`$i+1`]
++	srl	$a,32-$rot,$a
++	add	$b,$t3,$t3
++	add	$t3,$a,$a
++___
++}
++
++$code.=<<___;
++#include "sparc_arch.h"
++
++#ifdef __arch64__
++.register	%g2,#scratch
++.register	%g3,#scratch
++#endif
++
++.section	".text",#alloc,#execinstr
++
++#ifdef __PIC__
++SPARC_PIC_THUNK(%g1)
++#endif
++
++.globl	md5_block_asm_data_order
++.align	32
++md5_block_asm_data_order:
++	SPARC_LOAD_ADDRESS_LEAF(OPENSSL_sparcv9cap_P,%g1,%g5)
++	ld	[%g1+4],%g1		! OPENSSL_sparcv9cap_P[1]
++
++	andcc	%g1, CFR_MD5, %g0
++	be	.Lsoftware
++	nop
++
++	mov	4, %g1
++	andcc	%o1, 0x7, %g0
++	lda	[%o0 + %g0]0x88, %f0		! load context
++	lda	[%o0 + %g1]0x88, %f1
++	add	%o0, 8, %o0
++	lda	[%o0 + %g0]0x88, %f2
++	lda	[%o0 + %g1]0x88, %f3
++	bne,pn	%icc, .Lhwunaligned
++	sub	%o0, 8, %o0
++
++.Lhw_loop:
++	ldd	[%o1 + 0x00], %f8
++	ldd	[%o1 + 0x08], %f10
++	ldd	[%o1 + 0x10], %f12
++	ldd	[%o1 + 0x18], %f14
++	ldd	[%o1 + 0x20], %f16
++	ldd	[%o1 + 0x28], %f18
++	ldd	[%o1 + 0x30], %f20
++	subcc	%o2, 1, %o2		! done yet? 
++	ldd	[%o1 + 0x38], %f22
++	add	%o1, 0x40, %o1
++	prefetch [%o1 + 63], 20
++
++	.word	0x81b02800		! MD5
++
++	bne,pt	SIZE_T_CC, .Lhw_loop
++	nop
++
++.Lhwfinish:
++	sta	%f0, [%o0 + %g0]0x88	! store context
++	sta	%f1, [%o0 + %g1]0x88
++	add	%o0, 8, %o0
++	sta	%f2, [%o0 + %g0]0x88
++	sta	%f3, [%o0 + %g1]0x88
++	retl
++	nop
++
++.align	8
++.Lhwunaligned:
++	alignaddr %o1, %g0, %o1
++
++	ldd	[%o1 + 0x00], %f10
++.Lhwunaligned_loop:
++	ldd	[%o1 + 0x08], %f12
++	ldd	[%o1 + 0x10], %f14
++	ldd	[%o1 + 0x18], %f16
++	ldd	[%o1 + 0x20], %f18
++	ldd	[%o1 + 0x28], %f20
++	ldd	[%o1 + 0x30], %f22
++	ldd	[%o1 + 0x38], %f24
++	subcc	%o2, 1, %o2		! done yet?
++	ldd	[%o1 + 0x40], %f26
++	add	%o1, 0x40, %o1
++	prefetch [%o1 + 63], 20
++
++	faligndata %f10, %f12, %f8
++	faligndata %f12, %f14, %f10
++	faligndata %f14, %f16, %f12
++	faligndata %f16, %f18, %f14
++	faligndata %f18, %f20, %f16
++	faligndata %f20, %f22, %f18
++	faligndata %f22, %f24, %f20
++	faligndata %f24, %f26, %f22
++
++	.word	0x81b02800		! MD5
++
++	bne,pt	SIZE_T_CC, .Lhwunaligned_loop
++	for	%f26, %f26, %f10	! %f10=%f26
++
++	ba	.Lhwfinish
++	nop
++
++.align	16
++.Lsoftware:
++	save	%sp,-STACK_FRAME,%sp
++
++	rd	%asi,$saved_asi
++	wr	%g0,0x88,%asi		! ASI_PRIMARY_LITTLE
++	and	$inp,7,$shr
++	andn	$inp,7,$inp
++
++	sll	$shr,3,$shr		! *=8
++	mov	56,$shl2
++	ld	[$ctx+0],$A
++	sub	$shl2,$shr,$shl2
++	ld	[$ctx+4],$B
++	and	$shl2,32,$shl1
++	add	$shl2,8,$shl2
++	ld	[$ctx+8],$C
++	sub	$shl2,$shl1,$shl2	! shr+shl1+shl2==64
++	ld	[$ctx+12],$D
++	nop
++
++.Loop:
++	 cmp	$shr,0			! was inp aligned?
++	ldxa	[$inp+0]%asi,@X[0]	! load little-endian input
++	ldxa	[$inp+8]%asi,@X[1]
++	ldxa	[$inp+16]%asi,@X[2]
++	ldxa	[$inp+24]%asi,@X[3]
++	ldxa	[$inp+32]%asi,@X[4]
++	 sllx	$A,32,$AB		! pack A,B
++	ldxa	[$inp+40]%asi,@X[5]
++	 sllx	$C,32,$CD		! pack C,D
++	ldxa	[$inp+48]%asi,@X[6]
++	 or	$B,$AB,$AB
++	ldxa	[$inp+56]%asi,@X[7]
++	 or	$D,$CD,$CD
++	bnz,a,pn	%icc,.+8
++	ldxa	[$inp+64]%asi,@X[8]
++
++	srlx	@X[0],$shr,@X[0]	! align X[0]
++	sllx	@X[1],$shl1,$tx
++	 sethi	%hi(@K[0]),$t2
++	sllx	$tx,$shl2,$tx
++	 or	$t2,%lo(@K[0]),$t2
++	or	$tx,@X[0],@X[0]
++	 xor	$C,$D,$t1
++	 add	@X[0],$t2,$t2		! X[0]+K[0]
++___
++	for ($i=0;$i<15;$i++)	{ &R0($i,@V);	unshift(@V,pop(@V)); }
++	for (;$i<16;$i++)	{ &R0_1($i,@V);	unshift(@V,pop(@V)); }
++	for (;$i<32;$i++)	{ &R1($i,@V);	unshift(@V,pop(@V)); }
++	for (;$i<48;$i++)	{ &R2($i,@V);	unshift(@V,pop(@V)); }
++	for (;$i<64;$i++)	{ &R3($i,@V);	unshift(@V,pop(@V)); }
++$code.=<<___;
++	srlx	$AB,32,$t1		! unpack A,B,C,D and accumulate
++	add	$inp,64,$inp		! advance inp
++	srlx	$CD,32,$t2
++	add	$t1,$A,$A
++	subcc	$len,1,$len		! done yet?
++	add	$AB,$B,$B
++	add	$t2,$C,$C
++	add	$CD,$D,$D
++	srl	$B,0,$B			! clruw	$B
++	bne	SIZE_T_CC,.Loop
++	srl	$D,0,$D			! clruw	$D
++
++	st	$A,[$ctx+0]		! write out ctx
++	st	$B,[$ctx+4]
++	st	$C,[$ctx+8]
++	st	$D,[$ctx+12]
++
++	wr	%g0,$saved_asi,%asi
++	ret
++	restore
++.type	md5_block_asm_data_order,#function
++.size	md5_block_asm_data_order,(.-md5_block_asm_data_order)
++
++.asciz	"MD5 block transform for SPARCv9, CRYPTOGAMS by "
++.align	4
++___
++
++# Purpose of these subroutines is to explicitly encode VIS instructions,
++# so that one can compile the module without having to specify VIS
++# extensions on compiler command line, e.g. -xarch=v9 vs. -xarch=v9a.
++# Idea is to reserve for option to produce "universal" binary and let
++# programmer detect if current CPU is VIS capable at run-time.
++sub unvis {
++my ($mnemonic,$rs1,$rs2,$rd)=@_;
++my $ref,$opf;
++my %visopf = (	"faligndata"	=> 0x048,
++		"for"		=> 0x07c	);
++
++    $ref = "$mnemonic\t$rs1,$rs2,$rd";
++
++    if ($opf=$visopf{$mnemonic}) {
++	foreach ($rs1,$rs2,$rd) {
++	    return $ref if (!/%f([0-9]{1,2})/);
++	    $_=$1;
++	    if ($1>=32) {
++		return $ref if ($1&1);
++		# re-encode for upper double register addressing
++		$_=($1|$1>>5)&31;
++	    }
++	}
++
++	return	sprintf ".word\t0x%08x !%s",
++			0x81b00000|$rd<<25|$rs1<<14|$opf<<5|$rs2,
++			$ref;
++    } else {
++	return $ref;
++    }
++}
++sub unalignaddr {
++my ($mnemonic,$rs1,$rs2,$rd)=@_;
++my %bias = ( "g" => 0, "o" => 8, "l" => 16, "i" => 24 );
++my $ref="$mnemonic\t$rs1,$rs2,$rd";
++
++    foreach ($rs1,$rs2,$rd) {
++	if (/%([goli])([0-7])/)	{ $_=$bias{$1}+$2; }
++	else			{ return $ref; }
++    }
++    return  sprintf ".word\t0x%08x !%s",
++		    0x81b00300|$rd<<25|$rs1<<14|$rs2,
++		    $ref;
++}
++
++foreach (split("\n",$code)) {
++	s/\`([^\`]*)\`/eval $1/ge;
++
++	s/\b(f[^\s]*)\s+(%f[0-9]{1,2}),\s*(%f[0-9]{1,2}),\s*(%f[0-9]{1,2})/
++		&unvis($1,$2,$3,$4)
++	 /ge;
++	s/\b(alignaddr)\s+(%[goli][0-7]),\s*(%[goli][0-7]),\s*(%[goli][0-7])/
++		&unalignaddr($1,$2,$3,$4)
++	 /ge;
++
++	print $_,"\n";
++}
++
++close STDOUT;
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/md5/asm/md5-x86_64.pl b/CryptoPkg/Library/OpensslLib/openssl/crypto/md5/asm/md5-x86_64.pl
+new file mode 100755
+index 0000000..3f656dc
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/md5/asm/md5-x86_64.pl
+@@ -0,0 +1,380 @@
++#! /usr/bin/env perl
++# Author: Marc Bevand 
++# Copyright 2005-2016 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
++# in the file LICENSE in the source distribution or at
++# https://www.openssl.org/source/license.html
++
++# MD5 optimized for AMD64.
++
++use strict;
++
++my $code;
++
++# round1_step() does:
++#   dst = x + ((dst + F(x,y,z) + X[k] + T_i) <<< s)
++#   %r10d = X[k_next]
++#   %r11d = z' (copy of z for the next step)
++# Each round1_step() takes about 5.3 clocks (9 instructions, 1.7 IPC)
++sub round1_step
++{
++    my ($pos, $dst, $x, $y, $z, $k_next, $T_i, $s) = @_;
++    $code .= " mov	0*4(%rsi),	%r10d		/* (NEXT STEP) X[0] */\n" if ($pos == -1);
++    $code .= " mov	%edx,		%r11d		/* (NEXT STEP) z' = %edx */\n" if ($pos == -1);
++    $code .= <A
++	mov	1*4(%rbp),	%ebx	# ebx = ctx->B
++	mov	2*4(%rbp),	%ecx	# ecx = ctx->C
++	mov	3*4(%rbp),	%edx	# edx = ctx->D
++	# end is 'rdi'
++	# ptr is 'rsi'
++	# A is 'eax'
++	# B is 'ebx'
++	# C is 'ecx'
++	# D is 'edx'
++
++	cmp	%rdi,		%rsi		# cmp end with ptr
++	je	.Lend				# jmp if ptr == end
++
++	# BEGIN of loop over 16-word blocks
++.Lloop:	# save old values of A, B, C, D
++	mov	%eax,		%r8d
++	mov	%ebx,		%r9d
++	mov	%ecx,		%r14d
++	mov	%edx,		%r15d
++EOF
++round1_step(-1,'%eax','%ebx','%ecx','%edx', '1','0xd76aa478', '7');
++round1_step( 0,'%edx','%eax','%ebx','%ecx', '2','0xe8c7b756','12');
++round1_step( 0,'%ecx','%edx','%eax','%ebx', '3','0x242070db','17');
++round1_step( 0,'%ebx','%ecx','%edx','%eax', '4','0xc1bdceee','22');
++round1_step( 0,'%eax','%ebx','%ecx','%edx', '5','0xf57c0faf', '7');
++round1_step( 0,'%edx','%eax','%ebx','%ecx', '6','0x4787c62a','12');
++round1_step( 0,'%ecx','%edx','%eax','%ebx', '7','0xa8304613','17');
++round1_step( 0,'%ebx','%ecx','%edx','%eax', '8','0xfd469501','22');
++round1_step( 0,'%eax','%ebx','%ecx','%edx', '9','0x698098d8', '7');
++round1_step( 0,'%edx','%eax','%ebx','%ecx','10','0x8b44f7af','12');
++round1_step( 0,'%ecx','%edx','%eax','%ebx','11','0xffff5bb1','17');
++round1_step( 0,'%ebx','%ecx','%edx','%eax','12','0x895cd7be','22');
++round1_step( 0,'%eax','%ebx','%ecx','%edx','13','0x6b901122', '7');
++round1_step( 0,'%edx','%eax','%ebx','%ecx','14','0xfd987193','12');
++round1_step( 0,'%ecx','%edx','%eax','%ebx','15','0xa679438e','17');
++round1_step( 1,'%ebx','%ecx','%edx','%eax', '1','0x49b40821','22');
++
++round2_step(-1,'%eax','%ebx','%ecx','%edx', '6','0xf61e2562', '5');
++round2_step( 0,'%edx','%eax','%ebx','%ecx','11','0xc040b340', '9');
++round2_step( 0,'%ecx','%edx','%eax','%ebx', '0','0x265e5a51','14');
++round2_step( 0,'%ebx','%ecx','%edx','%eax', '5','0xe9b6c7aa','20');
++round2_step( 0,'%eax','%ebx','%ecx','%edx','10','0xd62f105d', '5');
++round2_step( 0,'%edx','%eax','%ebx','%ecx','15', '0x2441453', '9');
++round2_step( 0,'%ecx','%edx','%eax','%ebx', '4','0xd8a1e681','14');
++round2_step( 0,'%ebx','%ecx','%edx','%eax', '9','0xe7d3fbc8','20');
++round2_step( 0,'%eax','%ebx','%ecx','%edx','14','0x21e1cde6', '5');
++round2_step( 0,'%edx','%eax','%ebx','%ecx', '3','0xc33707d6', '9');
++round2_step( 0,'%ecx','%edx','%eax','%ebx', '8','0xf4d50d87','14');
++round2_step( 0,'%ebx','%ecx','%edx','%eax','13','0x455a14ed','20');
++round2_step( 0,'%eax','%ebx','%ecx','%edx', '2','0xa9e3e905', '5');
++round2_step( 0,'%edx','%eax','%ebx','%ecx', '7','0xfcefa3f8', '9');
++round2_step( 0,'%ecx','%edx','%eax','%ebx','12','0x676f02d9','14');
++round2_step( 1,'%ebx','%ecx','%edx','%eax', '5','0x8d2a4c8a','20');
++
++round3_step(-1,'%eax','%ebx','%ecx','%edx', '8','0xfffa3942', '4');
++round3_step( 0,'%edx','%eax','%ebx','%ecx','11','0x8771f681','11');
++round3_step( 0,'%ecx','%edx','%eax','%ebx','14','0x6d9d6122','16');
++round3_step( 0,'%ebx','%ecx','%edx','%eax', '1','0xfde5380c','23');
++round3_step( 0,'%eax','%ebx','%ecx','%edx', '4','0xa4beea44', '4');
++round3_step( 0,'%edx','%eax','%ebx','%ecx', '7','0x4bdecfa9','11');
++round3_step( 0,'%ecx','%edx','%eax','%ebx','10','0xf6bb4b60','16');
++round3_step( 0,'%ebx','%ecx','%edx','%eax','13','0xbebfbc70','23');
++round3_step( 0,'%eax','%ebx','%ecx','%edx', '0','0x289b7ec6', '4');
++round3_step( 0,'%edx','%eax','%ebx','%ecx', '3','0xeaa127fa','11');
++round3_step( 0,'%ecx','%edx','%eax','%ebx', '6','0xd4ef3085','16');
++round3_step( 0,'%ebx','%ecx','%edx','%eax', '9', '0x4881d05','23');
++round3_step( 0,'%eax','%ebx','%ecx','%edx','12','0xd9d4d039', '4');
++round3_step( 0,'%edx','%eax','%ebx','%ecx','15','0xe6db99e5','11');
++round3_step( 0,'%ecx','%edx','%eax','%ebx', '2','0x1fa27cf8','16');
++round3_step( 1,'%ebx','%ecx','%edx','%eax', '0','0xc4ac5665','23');
++
++round4_step(-1,'%eax','%ebx','%ecx','%edx', '7','0xf4292244', '6');
++round4_step( 0,'%edx','%eax','%ebx','%ecx','14','0x432aff97','10');
++round4_step( 0,'%ecx','%edx','%eax','%ebx', '5','0xab9423a7','15');
++round4_step( 0,'%ebx','%ecx','%edx','%eax','12','0xfc93a039','21');
++round4_step( 0,'%eax','%ebx','%ecx','%edx', '3','0x655b59c3', '6');
++round4_step( 0,'%edx','%eax','%ebx','%ecx','10','0x8f0ccc92','10');
++round4_step( 0,'%ecx','%edx','%eax','%ebx', '1','0xffeff47d','15');
++round4_step( 0,'%ebx','%ecx','%edx','%eax', '8','0x85845dd1','21');
++round4_step( 0,'%eax','%ebx','%ecx','%edx','15','0x6fa87e4f', '6');
++round4_step( 0,'%edx','%eax','%ebx','%ecx', '6','0xfe2ce6e0','10');
++round4_step( 0,'%ecx','%edx','%eax','%ebx','13','0xa3014314','15');
++round4_step( 0,'%ebx','%ecx','%edx','%eax', '4','0x4e0811a1','21');
++round4_step( 0,'%eax','%ebx','%ecx','%edx','11','0xf7537e82', '6');
++round4_step( 0,'%edx','%eax','%ebx','%ecx', '2','0xbd3af235','10');
++round4_step( 0,'%ecx','%edx','%eax','%ebx', '9','0x2ad7d2bb','15');
++round4_step( 1,'%ebx','%ecx','%edx','%eax', '0','0xeb86d391','21');
++$code .= <A = A
++	mov	%ebx,		1*4(%rbp)	# ctx->B = B
++	mov	%ecx,		2*4(%rbp)	# ctx->C = C
++	mov	%edx,		3*4(%rbp)	# ctx->D = D
++
++	mov	(%rsp),%r15
++	mov	8(%rsp),%r14
++	mov	16(%rsp),%r12
++	mov	24(%rsp),%rbx
++	mov	32(%rsp),%rbp
++	add	\$40,%rsp
++.Lepilogue:
++	ret
++.size md5_block_asm_data_order,.-md5_block_asm_data_order
++EOF
++
++# EXCEPTION_DISPOSITION handler (EXCEPTION_RECORD *rec,ULONG64 frame,
++#		CONTEXT *context,DISPATCHER_CONTEXT *disp)
++if ($win64) {
++my $rec="%rcx";
++my $frame="%rdx";
++my $context="%r8";
++my $disp="%r9";
++
++$code.=<<___;
++.extern	__imp_RtlVirtualUnwind
++.type	se_handler,\@abi-omnipotent
++.align	16
++se_handler:
++	push	%rsi
++	push	%rdi
++	push	%rbx
++	push	%rbp
++	push	%r12
++	push	%r13
++	push	%r14
++	push	%r15
++	pushfq
++	sub	\$64,%rsp
++
++	mov	120($context),%rax	# pull context->Rax
++	mov	248($context),%rbx	# pull context->Rip
++
++	lea	.Lprologue(%rip),%r10
++	cmp	%r10,%rbx		# context->Rip<.Lprologue
++	jb	.Lin_prologue
++
++	mov	152($context),%rax	# pull context->Rsp
++
++	lea	.Lepilogue(%rip),%r10
++	cmp	%r10,%rbx		# context->Rip>=.Lepilogue
++	jae	.Lin_prologue
++
++	lea	40(%rax),%rax
++
++	mov	-8(%rax),%rbp
++	mov	-16(%rax),%rbx
++	mov	-24(%rax),%r12
++	mov	-32(%rax),%r14
++	mov	-40(%rax),%r15
++	mov	%rbx,144($context)	# restore context->Rbx
++	mov	%rbp,160($context)	# restore context->Rbp
++	mov	%r12,216($context)	# restore context->R12
++	mov	%r14,232($context)	# restore context->R14
++	mov	%r15,240($context)	# restore context->R15
++
++.Lin_prologue:
++	mov	8(%rax),%rdi
++	mov	16(%rax),%rsi
++	mov	%rax,152($context)	# restore context->Rsp
++	mov	%rsi,168($context)	# restore context->Rsi
++	mov	%rdi,176($context)	# restore context->Rdi
++
++	mov	40($disp),%rdi		# disp->ContextRecord
++	mov	$context,%rsi		# context
++	mov	\$154,%ecx		# sizeof(CONTEXT)
++	.long	0xa548f3fc		# cld; rep movsq
++
++	mov	$disp,%rsi
++	xor	%rcx,%rcx		# arg1, UNW_FLAG_NHANDLER
++	mov	8(%rsi),%rdx		# arg2, disp->ImageBase
++	mov	0(%rsi),%r8		# arg3, disp->ControlPc
++	mov	16(%rsi),%r9		# arg4, disp->FunctionEntry
++	mov	40(%rsi),%r10		# disp->ContextRecord
++	lea	56(%rsi),%r11		# &disp->HandlerData
++	lea	24(%rsi),%r12		# &disp->EstablisherFrame
++	mov	%r10,32(%rsp)		# arg5
++	mov	%r11,40(%rsp)		# arg6
++	mov	%r12,48(%rsp)		# arg7
++	mov	%rcx,56(%rsp)		# arg8, (NULL)
++	call	*__imp_RtlVirtualUnwind(%rip)
++
++	mov	\$1,%eax		# ExceptionContinueSearch
++	add	\$64,%rsp
++	popfq
++	pop	%r15
++	pop	%r14
++	pop	%r13
++	pop	%r12
++	pop	%rbp
++	pop	%rbx
++	pop	%rdi
++	pop	%rsi
++	ret
++.size	se_handler,.-se_handler
++
++.section	.pdata
++.align	4
++	.rva	.LSEH_begin_md5_block_asm_data_order
++	.rva	.LSEH_end_md5_block_asm_data_order
++	.rva	.LSEH_info_md5_block_asm_data_order
++
++.section	.xdata
++.align	8
++.LSEH_info_md5_block_asm_data_order:
++	.byte	9,0,0,0
++	.rva	se_handler
++___
++}
++
++print $code;
++
++close STDOUT;
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/md5/build.info b/CryptoPkg/Library/OpensslLib/openssl/crypto/md5/build.info
+new file mode 100644
+index 0000000..38323a3
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/md5/build.info
+@@ -0,0 +1,22 @@
++LIBS=../../libcrypto
++SOURCE[../../libcrypto]=\
++        md5_dgst.c md5_one.c {- $target{md5_asm_src} -}
++
++GENERATE[md5-586.s]=asm/md5-586.pl $(PERLASM_SCHEME) $(CFLAGS) $(LIB_CFLAGS)
++
++GENERATE[md5-x86_64.s]=asm/md5-x86_64.pl $(PERLASM_SCHEME)
++
++GENERATE[md5-sparcv9.S]=asm/md5-sparcv9.pl $(PERLASM_SCHEME)
++INCLUDE[md5-sparcv9.o]=..
++
++BEGINRAW[makefile(windows)]
++{- $builddir -}\md5-ia64.asm: {- $sourcedir -}\asm\md5-ia64.S
++	$(CC) $(CFLAGS) -EP {- $sourcedir -}\asm\md5-ia64.S > $@.i && move /Y $@.i $@
++ENDRAW[makefile(windows)]
++
++BEGINRAW[Makefile]
++{- $builddir -}/md5-ia64.s: {- $sourcedir -}/asm/md5-ia64.S
++	$(CC) $(CFLAGS) -E {- $sourcedir -}/asm/md5-ia64.S | \
++	$(PERL) -ne 's/;\s+/;\n/g; print;' > $@
++
++ENDRAW[Makefile]
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/md5/md5_dgst.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/md5/md5_dgst.c
+new file mode 100644
+index 0000000..fbede67
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/md5/md5_dgst.c
+@@ -0,0 +1,164 @@
++/*
++ * Copyright 1995-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include "md5_locl.h"
++#include 
++
++/*
++ * Implemented from RFC1321 The MD5 Message-Digest Algorithm
++ */
++
++#define INIT_DATA_A (unsigned long)0x67452301L
++#define INIT_DATA_B (unsigned long)0xefcdab89L
++#define INIT_DATA_C (unsigned long)0x98badcfeL
++#define INIT_DATA_D (unsigned long)0x10325476L
++
++int MD5_Init(MD5_CTX *c)
++{
++    memset(c, 0, sizeof(*c));
++    c->A = INIT_DATA_A;
++    c->B = INIT_DATA_B;
++    c->C = INIT_DATA_C;
++    c->D = INIT_DATA_D;
++    return 1;
++}
++
++#ifndef md5_block_data_order
++# ifdef X
++#  undef X
++# endif
++void md5_block_data_order(MD5_CTX *c, const void *data_, size_t num)
++{
++    const unsigned char *data = data_;
++    register unsigned MD32_REG_T A, B, C, D, l;
++# ifndef MD32_XARRAY
++    /* See comment in crypto/sha/sha_locl.h for details. */
++    unsigned MD32_REG_T XX0, XX1, XX2, XX3, XX4, XX5, XX6, XX7,
++        XX8, XX9, XX10, XX11, XX12, XX13, XX14, XX15;
++#  define X(i)   XX##i
++# else
++    MD5_LONG XX[MD5_LBLOCK];
++#  define X(i)   XX[i]
++# endif
++
++    A = c->A;
++    B = c->B;
++    C = c->C;
++    D = c->D;
++
++    for (; num--;) {
++        (void)HOST_c2l(data, l);
++        X(0) = l;
++        (void)HOST_c2l(data, l);
++        X(1) = l;
++        /* Round 0 */
++        R0(A, B, C, D, X(0), 7, 0xd76aa478L);
++        (void)HOST_c2l(data, l);
++        X(2) = l;
++        R0(D, A, B, C, X(1), 12, 0xe8c7b756L);
++        (void)HOST_c2l(data, l);
++        X(3) = l;
++        R0(C, D, A, B, X(2), 17, 0x242070dbL);
++        (void)HOST_c2l(data, l);
++        X(4) = l;
++        R0(B, C, D, A, X(3), 22, 0xc1bdceeeL);
++        (void)HOST_c2l(data, l);
++        X(5) = l;
++        R0(A, B, C, D, X(4), 7, 0xf57c0fafL);
++        (void)HOST_c2l(data, l);
++        X(6) = l;
++        R0(D, A, B, C, X(5), 12, 0x4787c62aL);
++        (void)HOST_c2l(data, l);
++        X(7) = l;
++        R0(C, D, A, B, X(6), 17, 0xa8304613L);
++        (void)HOST_c2l(data, l);
++        X(8) = l;
++        R0(B, C, D, A, X(7), 22, 0xfd469501L);
++        (void)HOST_c2l(data, l);
++        X(9) = l;
++        R0(A, B, C, D, X(8), 7, 0x698098d8L);
++        (void)HOST_c2l(data, l);
++        X(10) = l;
++        R0(D, A, B, C, X(9), 12, 0x8b44f7afL);
++        (void)HOST_c2l(data, l);
++        X(11) = l;
++        R0(C, D, A, B, X(10), 17, 0xffff5bb1L);
++        (void)HOST_c2l(data, l);
++        X(12) = l;
++        R0(B, C, D, A, X(11), 22, 0x895cd7beL);
++        (void)HOST_c2l(data, l);
++        X(13) = l;
++        R0(A, B, C, D, X(12), 7, 0x6b901122L);
++        (void)HOST_c2l(data, l);
++        X(14) = l;
++        R0(D, A, B, C, X(13), 12, 0xfd987193L);
++        (void)HOST_c2l(data, l);
++        X(15) = l;
++        R0(C, D, A, B, X(14), 17, 0xa679438eL);
++        R0(B, C, D, A, X(15), 22, 0x49b40821L);
++        /* Round 1 */
++        R1(A, B, C, D, X(1), 5, 0xf61e2562L);
++        R1(D, A, B, C, X(6), 9, 0xc040b340L);
++        R1(C, D, A, B, X(11), 14, 0x265e5a51L);
++        R1(B, C, D, A, X(0), 20, 0xe9b6c7aaL);
++        R1(A, B, C, D, X(5), 5, 0xd62f105dL);
++        R1(D, A, B, C, X(10), 9, 0x02441453L);
++        R1(C, D, A, B, X(15), 14, 0xd8a1e681L);
++        R1(B, C, D, A, X(4), 20, 0xe7d3fbc8L);
++        R1(A, B, C, D, X(9), 5, 0x21e1cde6L);
++        R1(D, A, B, C, X(14), 9, 0xc33707d6L);
++        R1(C, D, A, B, X(3), 14, 0xf4d50d87L);
++        R1(B, C, D, A, X(8), 20, 0x455a14edL);
++        R1(A, B, C, D, X(13), 5, 0xa9e3e905L);
++        R1(D, A, B, C, X(2), 9, 0xfcefa3f8L);
++        R1(C, D, A, B, X(7), 14, 0x676f02d9L);
++        R1(B, C, D, A, X(12), 20, 0x8d2a4c8aL);
++        /* Round 2 */
++        R2(A, B, C, D, X(5), 4, 0xfffa3942L);
++        R2(D, A, B, C, X(8), 11, 0x8771f681L);
++        R2(C, D, A, B, X(11), 16, 0x6d9d6122L);
++        R2(B, C, D, A, X(14), 23, 0xfde5380cL);
++        R2(A, B, C, D, X(1), 4, 0xa4beea44L);
++        R2(D, A, B, C, X(4), 11, 0x4bdecfa9L);
++        R2(C, D, A, B, X(7), 16, 0xf6bb4b60L);
++        R2(B, C, D, A, X(10), 23, 0xbebfbc70L);
++        R2(A, B, C, D, X(13), 4, 0x289b7ec6L);
++        R2(D, A, B, C, X(0), 11, 0xeaa127faL);
++        R2(C, D, A, B, X(3), 16, 0xd4ef3085L);
++        R2(B, C, D, A, X(6), 23, 0x04881d05L);
++        R2(A, B, C, D, X(9), 4, 0xd9d4d039L);
++        R2(D, A, B, C, X(12), 11, 0xe6db99e5L);
++        R2(C, D, A, B, X(15), 16, 0x1fa27cf8L);
++        R2(B, C, D, A, X(2), 23, 0xc4ac5665L);
++        /* Round 3 */
++        R3(A, B, C, D, X(0), 6, 0xf4292244L);
++        R3(D, A, B, C, X(7), 10, 0x432aff97L);
++        R3(C, D, A, B, X(14), 15, 0xab9423a7L);
++        R3(B, C, D, A, X(5), 21, 0xfc93a039L);
++        R3(A, B, C, D, X(12), 6, 0x655b59c3L);
++        R3(D, A, B, C, X(3), 10, 0x8f0ccc92L);
++        R3(C, D, A, B, X(10), 15, 0xffeff47dL);
++        R3(B, C, D, A, X(1), 21, 0x85845dd1L);
++        R3(A, B, C, D, X(8), 6, 0x6fa87e4fL);
++        R3(D, A, B, C, X(15), 10, 0xfe2ce6e0L);
++        R3(C, D, A, B, X(6), 15, 0xa3014314L);
++        R3(B, C, D, A, X(13), 21, 0x4e0811a1L);
++        R3(A, B, C, D, X(4), 6, 0xf7537e82L);
++        R3(D, A, B, C, X(11), 10, 0xbd3af235L);
++        R3(C, D, A, B, X(2), 15, 0x2ad7d2bbL);
++        R3(B, C, D, A, X(9), 21, 0xeb86d391L);
++
++        A = c->A += A;
++        B = c->B += B;
++        C = c->C += C;
++        D = c->D += D;
++    }
++}
++#endif
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/md5/md5_locl.h b/CryptoPkg/Library/OpensslLib/openssl/crypto/md5/md5_locl.h
+new file mode 100644
+index 0000000..9c7aade
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/md5/md5_locl.h
+@@ -0,0 +1,80 @@
++/*
++ * Copyright 1995-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include 
++#include 
++#include 
++
++#ifdef MD5_ASM
++# if defined(__i386) || defined(__i386__) || defined(_M_IX86) || \
++     defined(__x86_64) || defined(__x86_64__) || defined(_M_AMD64) || defined(_M_X64)
++#  define md5_block_data_order md5_block_asm_data_order
++# elif defined(__ia64) || defined(__ia64__) || defined(_M_IA64)
++#  define md5_block_data_order md5_block_asm_data_order
++# elif defined(__sparc) || defined(__sparc__)
++#  define md5_block_data_order md5_block_asm_data_order
++# endif
++#endif
++
++void md5_block_data_order(MD5_CTX *c, const void *p, size_t num);
++
++#define DATA_ORDER_IS_LITTLE_ENDIAN
++
++#define HASH_LONG               MD5_LONG
++#define HASH_CTX                MD5_CTX
++#define HASH_CBLOCK             MD5_CBLOCK
++#define HASH_UPDATE             MD5_Update
++#define HASH_TRANSFORM          MD5_Transform
++#define HASH_FINAL              MD5_Final
++#define HASH_MAKE_STRING(c,s)   do {    \
++        unsigned long ll;               \
++        ll=(c)->A; (void)HOST_l2c(ll,(s));      \
++        ll=(c)->B; (void)HOST_l2c(ll,(s));      \
++        ll=(c)->C; (void)HOST_l2c(ll,(s));      \
++        ll=(c)->D; (void)HOST_l2c(ll,(s));      \
++        } while (0)
++#define HASH_BLOCK_DATA_ORDER   md5_block_data_order
++
++#include "internal/md32_common.h"
++
++/*-
++#define F(x,y,z)        (((x) & (y))  |  ((~(x)) & (z)))
++#define G(x,y,z)        (((x) & (z))  |  ((y) & (~(z))))
++*/
++
++/*
++ * As pointed out by Wei Dai , the above can be simplified
++ * to the code below.  Wei attributes these optimizations to Peter Gutmann's
++ * SHS code, and he attributes it to Rich Schroeppel.
++ */
++#define F(b,c,d)        ((((c) ^ (d)) & (b)) ^ (d))
++#define G(b,c,d)        ((((b) ^ (c)) & (d)) ^ (c))
++#define H(b,c,d)        ((b) ^ (c) ^ (d))
++#define I(b,c,d)        (((~(d)) | (b)) ^ (c))
++
++#define R0(a,b,c,d,k,s,t) { \
++        a+=((k)+(t)+F((b),(c),(d))); \
++        a=ROTATE(a,s); \
++        a+=b; };\
++
++#define R1(a,b,c,d,k,s,t) { \
++        a+=((k)+(t)+G((b),(c),(d))); \
++        a=ROTATE(a,s); \
++        a+=b; };
++
++#define R2(a,b,c,d,k,s,t) { \
++        a+=((k)+(t)+H((b),(c),(d))); \
++        a=ROTATE(a,s); \
++        a+=b; };
++
++#define R3(a,b,c,d,k,s,t) { \
++        a+=((k)+(t)+I((b),(c),(d))); \
++        a=ROTATE(a,s); \
++        a+=b; };
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/md5/md5_one.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/md5/md5_one.c
+new file mode 100644
+index 0000000..becd87e
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/md5/md5_one.c
+@@ -0,0 +1,47 @@
++/*
++ * Copyright 1995-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include 
++#include 
++#include 
++
++#ifdef CHARSET_EBCDIC
++# include 
++#endif
++
++unsigned char *MD5(const unsigned char *d, size_t n, unsigned char *md)
++{
++    MD5_CTX c;
++    static unsigned char m[MD5_DIGEST_LENGTH];
++
++    if (md == NULL)
++        md = m;
++    if (!MD5_Init(&c))
++        return NULL;
++#ifndef CHARSET_EBCDIC
++    MD5_Update(&c, d, n);
++#else
++    {
++        char temp[1024];
++        unsigned long chunk;
++
++        while (n > 0) {
++            chunk = (n > sizeof(temp)) ? sizeof(temp) : n;
++            ebcdic2ascii(temp, d, chunk);
++            MD5_Update(&c, temp, chunk);
++            n -= chunk;
++            d += chunk;
++        }
++    }
++#endif
++    MD5_Final(md, &c);
++    OPENSSL_cleanse(&c, sizeof(c)); /* security consideration */
++    return (md);
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/mdc2/build.info b/CryptoPkg/Library/OpensslLib/openssl/crypto/mdc2/build.info
+new file mode 100644
+index 0000000..8fe6878
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/mdc2/build.info
+@@ -0,0 +1,3 @@
++LIBS=../../libcrypto
++SOURCE[../../libcrypto]=\
++        mdc2dgst.c mdc2_one.c
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/mdc2/mdc2_one.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/mdc2/mdc2_one.c
+new file mode 100644
+index 0000000..472a5ec
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/mdc2/mdc2_one.c
+@@ -0,0 +1,27 @@
++/*
++ * Copyright 1995-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include "internal/cryptlib.h"
++#include 
++
++unsigned char *MDC2(const unsigned char *d, size_t n, unsigned char *md)
++{
++    MDC2_CTX c;
++    static unsigned char m[MDC2_DIGEST_LENGTH];
++
++    if (md == NULL)
++        md = m;
++    if (!MDC2_Init(&c))
++        return NULL;
++    MDC2_Update(&c, d, n);
++    MDC2_Final(md, &c);
++    OPENSSL_cleanse(&c, sizeof(c)); /* security consideration */
++    return (md);
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/mdc2/mdc2dgst.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/mdc2/mdc2dgst.c
+new file mode 100644
+index 0000000..37d99f4
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/mdc2/mdc2dgst.c
+@@ -0,0 +1,147 @@
++/*
++ * Copyright 1995-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include 
++#include 
++#include 
++#include 
++#include 
++
++#undef c2l
++#define c2l(c,l)        (l =((DES_LONG)(*((c)++)))    , \
++                         l|=((DES_LONG)(*((c)++)))<< 8L, \
++                         l|=((DES_LONG)(*((c)++)))<<16L, \
++                         l|=((DES_LONG)(*((c)++)))<<24L)
++
++#undef l2c
++#define l2c(l,c)        (*((c)++)=(unsigned char)(((l)     )&0xff), \
++                        *((c)++)=(unsigned char)(((l)>> 8L)&0xff), \
++                        *((c)++)=(unsigned char)(((l)>>16L)&0xff), \
++                        *((c)++)=(unsigned char)(((l)>>24L)&0xff))
++
++static void mdc2_body(MDC2_CTX *c, const unsigned char *in, size_t len);
++int MDC2_Init(MDC2_CTX *c)
++{
++    c->num = 0;
++    c->pad_type = 1;
++    memset(&(c->h[0]), 0x52, MDC2_BLOCK);
++    memset(&(c->hh[0]), 0x25, MDC2_BLOCK);
++    return 1;
++}
++
++int MDC2_Update(MDC2_CTX *c, const unsigned char *in, size_t len)
++{
++    size_t i, j;
++
++    i = c->num;
++    if (i != 0) {
++        if (len < MDC2_BLOCK - i) {
++            /* partial block */
++            memcpy(&(c->data[i]), in, len);
++            c->num += (int)len;
++            return 1;
++        } else {
++            /* filled one */
++            j = MDC2_BLOCK - i;
++            memcpy(&(c->data[i]), in, j);
++            len -= j;
++            in += j;
++            c->num = 0;
++            mdc2_body(c, &(c->data[0]), MDC2_BLOCK);
++        }
++    }
++    i = len & ~((size_t)MDC2_BLOCK - 1);
++    if (i > 0)
++        mdc2_body(c, in, i);
++    j = len - i;
++    if (j > 0) {
++        memcpy(&(c->data[0]), &(in[i]), j);
++        c->num = (int)j;
++    }
++    return 1;
++}
++
++static void mdc2_body(MDC2_CTX *c, const unsigned char *in, size_t len)
++{
++    register DES_LONG tin0, tin1;
++    register DES_LONG ttin0, ttin1;
++    DES_LONG d[2], dd[2];
++    DES_key_schedule k;
++    unsigned char *p;
++    size_t i;
++
++    for (i = 0; i < len; i += 8) {
++        c2l(in, tin0);
++        d[0] = dd[0] = tin0;
++        c2l(in, tin1);
++        d[1] = dd[1] = tin1;
++        c->h[0] = (c->h[0] & 0x9f) | 0x40;
++        c->hh[0] = (c->hh[0] & 0x9f) | 0x20;
++
++        DES_set_odd_parity(&c->h);
++        DES_set_key_unchecked(&c->h, &k);
++        DES_encrypt1(d, &k, 1);
++
++        DES_set_odd_parity(&c->hh);
++        DES_set_key_unchecked(&c->hh, &k);
++        DES_encrypt1(dd, &k, 1);
++
++        ttin0 = tin0 ^ dd[0];
++        ttin1 = tin1 ^ dd[1];
++        tin0 ^= d[0];
++        tin1 ^= d[1];
++
++        p = c->h;
++        l2c(tin0, p);
++        l2c(ttin1, p);
++        p = c->hh;
++        l2c(ttin0, p);
++        l2c(tin1, p);
++    }
++}
++
++int MDC2_Final(unsigned char *md, MDC2_CTX *c)
++{
++    unsigned int i;
++    int j;
++
++    i = c->num;
++    j = c->pad_type;
++    if ((i > 0) || (j == 2)) {
++        if (j == 2)
++            c->data[i++] = 0x80;
++        memset(&(c->data[i]), 0, MDC2_BLOCK - i);
++        mdc2_body(c, c->data, MDC2_BLOCK);
++    }
++    memcpy(md, (char *)c->h, MDC2_BLOCK);
++    memcpy(&(md[MDC2_BLOCK]), (char *)c->hh, MDC2_BLOCK);
++    return 1;
++}
++
++#undef TEST
++
++#ifdef TEST
++main()
++{
++    unsigned char md[MDC2_DIGEST_LENGTH];
++    int i;
++    MDC2_CTX c;
++    static char *text = "Now is the time for all ";
++
++    MDC2_Init(&c);
++    MDC2_Update(&c, text, strlen(text));
++    MDC2_Final(&(md[0]), &c);
++
++    for (i = 0; i < MDC2_DIGEST_LENGTH; i++)
++        printf("%02X", md[i]);
++    printf("\n");
++}
++
++#endif
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/mem.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/mem.c
+new file mode 100644
+index 0000000..02aa43a
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/mem.c
+@@ -0,0 +1,190 @@
++/*
++ * Copyright 1995-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include 
++#include 
++#include 
++#include "internal/cryptlib.h"
++
++/*
++ * the following pointers may be changed as long as 'allow_customize' is set
++ */
++static int allow_customize = 1;
++
++static void *(*malloc_impl)(size_t, const char *, int)
++    = CRYPTO_malloc;
++static void *(*realloc_impl)(void *, size_t, const char *, int)
++    = CRYPTO_realloc;
++static void (*free_impl)(void *, const char *, int)
++    = CRYPTO_free;
++
++#ifndef OPENSSL_NO_CRYPTO_MDEBUG
++static int call_malloc_debug = 1;
++#else
++static int call_malloc_debug = 0;
++#endif
++
++int CRYPTO_set_mem_functions(
++        void *(*m)(size_t, const char *, int),
++        void *(*r)(void *, size_t, const char *, int),
++        void (*f)(void *, const char *, int))
++{
++    if (!allow_customize)
++        return 0;
++    if (m)
++        malloc_impl = m;
++    if (r)
++        realloc_impl = r;
++    if (f)
++        free_impl = f;
++    return 1;
++}
++
++int CRYPTO_set_mem_debug(int flag)
++{
++    if (!allow_customize)
++        return 0;
++    call_malloc_debug = flag;
++    return 1;
++}
++
++void CRYPTO_get_mem_functions(
++        void *(**m)(size_t, const char *, int),
++        void *(**r)(void *, size_t, const char *, int),
++        void (**f)(void *, const char *, int))
++{
++    if (m != NULL)
++        *m = malloc_impl;
++    if (r != NULL)
++        *r = realloc_impl;
++    if (f != NULL)
++        *f = free_impl;
++}
++
++void *CRYPTO_malloc(size_t num, const char *file, int line)
++{
++    void *ret = NULL;
++
++    if (malloc_impl != NULL && malloc_impl != CRYPTO_malloc)
++        return malloc_impl(num, file, line);
++
++    if (num <= 0)
++        return NULL;
++
++    allow_customize = 0;
++#ifndef OPENSSL_NO_CRYPTO_MDEBUG
++    if (call_malloc_debug) {
++        CRYPTO_mem_debug_malloc(NULL, num, 0, file, line);
++        ret = malloc(num);
++        CRYPTO_mem_debug_malloc(ret, num, 1, file, line);
++    } else {
++        ret = malloc(num);
++    }
++#else
++    osslargused(file); osslargused(line);
++    ret = malloc(num);
++#endif
++
++    return ret;
++}
++
++void *CRYPTO_zalloc(size_t num, const char *file, int line)
++{
++    void *ret = CRYPTO_malloc(num, file, line);
++
++    if (ret != NULL)
++        memset(ret, 0, num);
++    return ret;
++}
++
++void *CRYPTO_realloc(void *str, size_t num, const char *file, int line)
++{
++    if (realloc_impl != NULL && realloc_impl != &CRYPTO_realloc)
++        return realloc_impl(str, num, file, line);
++
++    if (str == NULL)
++        return CRYPTO_malloc(num, file, line);
++
++    if (num == 0) {
++        CRYPTO_free(str, file, line);
++        return NULL;
++    }
++
++    allow_customize = 0;
++#ifndef OPENSSL_NO_CRYPTO_MDEBUG
++    if (call_malloc_debug) {
++        void *ret;
++        CRYPTO_mem_debug_realloc(str, NULL, num, 0, file, line);
++        ret = realloc(str, num);
++        CRYPTO_mem_debug_realloc(str, ret, num, 1, file, line);
++        return ret;
++    }
++#else
++    osslargused(file); osslargused(line);
++#endif
++    return realloc(str, num);
++
++}
++
++void *CRYPTO_clear_realloc(void *str, size_t old_len, size_t num,
++                           const char *file, int line)
++{
++    void *ret = NULL;
++
++    if (str == NULL)
++        return CRYPTO_malloc(num, file, line);
++
++    if (num == 0) {
++        CRYPTO_clear_free(str, old_len, file, line);
++        return NULL;
++    }
++
++    /* Can't shrink the buffer since memcpy below copies |old_len| bytes. */
++    if (num < old_len) {
++        OPENSSL_cleanse((char*)str + num, old_len - num);
++        return str;
++    }
++
++    ret = CRYPTO_malloc(num, file, line);
++    if (ret != NULL) {
++        memcpy(ret, str, old_len);
++        CRYPTO_clear_free(str, old_len, file, line);
++    }
++    return ret;
++}
++
++void CRYPTO_free(void *str, const char *file, int line)
++{
++    if (free_impl != NULL && free_impl != &CRYPTO_free) {
++        free_impl(str, file, line);
++        return;
++    }
++
++#ifndef OPENSSL_NO_CRYPTO_MDEBUG
++    if (call_malloc_debug) {
++        CRYPTO_mem_debug_free(str, 0, file, line);
++        free(str);
++        CRYPTO_mem_debug_free(str, 1, file, line);
++    } else {
++        free(str);
++    }
++#else
++    free(str);
++#endif
++}
++
++void CRYPTO_clear_free(void *str, size_t num, const char *file, int line)
++{
++    if (str == NULL)
++        return;
++    if (num)
++        OPENSSL_cleanse(str, num);
++    CRYPTO_free(str, file, line);
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/mem_clr.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/mem_clr.c
+new file mode 100644
+index 0000000..35bfb74
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/mem_clr.c
+@@ -0,0 +1,25 @@
++/*
++ * Copyright 2002-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include 
++
++/*
++ * Pointer to memset is volatile so that compiler must de-reference
++ * the pointer and can't assume that it points to any function in
++ * particular (such as memset, which it then might further "optimize")
++ */
++typedef void *(*memset_t)(void *, int, size_t);
++
++static volatile memset_t memset_func = memset;
++
++void OPENSSL_cleanse(void *ptr, size_t len)
++{
++    memset_func(ptr, 0, len);
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/mem_dbg.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/mem_dbg.c
+new file mode 100644
+index 0000000..dc3f8ff
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/mem_dbg.c
+@@ -0,0 +1,629 @@
++/*
++ * Copyright 1995-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include 
++#include 
++#include "internal/cryptlib.h"
++#include "internal/thread_once.h"
++#include 
++#include 
++#include "internal/bio.h"
++#include 
++
++#ifndef OPENSSL_NO_CRYPTO_MDEBUG_BACKTRACE
++# include 
++#endif
++
++/*
++ * The state changes to CRYPTO_MEM_CHECK_ON | CRYPTO_MEM_CHECK_ENABLE when
++ * the application asks for it (usually after library initialisation for
++ * which no book-keeping is desired). State CRYPTO_MEM_CHECK_ON exists only
++ * temporarily when the library thinks that certain allocations should not be
++ * checked (e.g. the data structures used for memory checking).  It is not
++ * suitable as an initial state: the library will unexpectedly enable memory
++ * checking when it executes one of those sections that want to disable
++ * checking temporarily. State CRYPTO_MEM_CHECK_ENABLE without ..._ON makes
++ * no sense whatsoever.
++ */
++#ifndef OPENSSL_NO_CRYPTO_MDEBUG
++static int mh_mode = CRYPTO_MEM_CHECK_OFF;
++#endif
++
++#ifndef OPENSSL_NO_CRYPTO_MDEBUG
++static unsigned long order = 0; /* number of memory requests */
++
++/*-
++ * For application-defined information (static C-string `info')
++ * to be displayed in memory leak list.
++ * Each thread has its own stack.  For applications, there is
++ *   OPENSSL_mem_debug_push("...")     to push an entry,
++ *   OPENSSL_mem_debug_pop()     to pop an entry,
++ */
++struct app_mem_info_st {
++    CRYPTO_THREAD_ID threadid;
++    const char *file;
++    int line;
++    const char *info;
++    struct app_mem_info_st *next; /* tail of thread's stack */
++    int references;
++};
++
++static CRYPTO_ONCE memdbg_init = CRYPTO_ONCE_STATIC_INIT;
++static CRYPTO_RWLOCK *malloc_lock = NULL;
++static CRYPTO_RWLOCK *long_malloc_lock = NULL;
++static CRYPTO_THREAD_LOCAL appinfokey;
++
++/* memory-block description */
++struct mem_st {
++    void *addr;
++    int num;
++    const char *file;
++    int line;
++    CRYPTO_THREAD_ID threadid;
++    unsigned long order;
++    time_t time;
++    APP_INFO *app_info;
++#ifndef OPENSSL_NO_CRYPTO_MDEBUG_BACKTRACE
++    void *array[30];
++    size_t array_siz;
++#endif
++};
++
++static LHASH_OF(MEM) *mh = NULL; /* hash-table of memory requests (address as
++                                  * key); access requires MALLOC2 lock */
++
++/* num_disable > 0 iff mh_mode == CRYPTO_MEM_CHECK_ON (w/o ..._ENABLE) */
++static unsigned int num_disable = 0;
++
++/*
++ * Valid iff num_disable > 0.  long_malloc_lock is locked exactly in this
++ * case (by the thread named in disabling_thread).
++ */
++static CRYPTO_THREAD_ID disabling_threadid;
++
++DEFINE_RUN_ONCE_STATIC(do_memdbg_init)
++{
++    malloc_lock = CRYPTO_THREAD_lock_new();
++    long_malloc_lock = CRYPTO_THREAD_lock_new();
++    if (malloc_lock == NULL || long_malloc_lock == NULL
++        || !CRYPTO_THREAD_init_local(&appinfokey, NULL)) {
++        CRYPTO_THREAD_lock_free(malloc_lock);
++        malloc_lock = NULL;
++        CRYPTO_THREAD_lock_free(long_malloc_lock);
++        long_malloc_lock = NULL;
++        return 0;
++    }
++    return 1;
++}
++
++static void app_info_free(APP_INFO *inf)
++{
++    if (!inf)
++        return;
++    if (--(inf->references) <= 0) {
++        app_info_free(inf->next);
++        OPENSSL_free(inf);
++    }
++}
++#endif
++
++int CRYPTO_mem_ctrl(int mode)
++{
++#ifdef OPENSSL_NO_CRYPTO_MDEBUG
++    return mode - mode;
++#else
++    int ret = mh_mode;
++
++    if (!RUN_ONCE(&memdbg_init, do_memdbg_init))
++        return -1;
++
++    CRYPTO_THREAD_write_lock(malloc_lock);
++    switch (mode) {
++    default:
++        break;
++
++    case CRYPTO_MEM_CHECK_ON:
++        mh_mode = CRYPTO_MEM_CHECK_ON | CRYPTO_MEM_CHECK_ENABLE;
++        num_disable = 0;
++        break;
++
++    case CRYPTO_MEM_CHECK_OFF:
++        mh_mode = 0;
++        num_disable = 0;
++        break;
++
++    /* switch off temporarily (for library-internal use): */
++    case CRYPTO_MEM_CHECK_DISABLE:
++        if (mh_mode & CRYPTO_MEM_CHECK_ON) {
++            CRYPTO_THREAD_ID cur = CRYPTO_THREAD_get_current_id();
++            /* see if we don't have long_malloc_lock already */
++            if (!num_disable
++                || !CRYPTO_THREAD_compare_id(disabling_threadid, cur)) {
++                /*
++                 * Long-time lock long_malloc_lock must not be claimed
++                 * while we're holding malloc_lock, or we'll deadlock
++                 * if somebody else holds long_malloc_lock (and cannot
++                 * release it because we block entry to this function). Give
++                 * them a chance, first, and then claim the locks in
++                 * appropriate order (long-time lock first).
++                 */
++                CRYPTO_THREAD_unlock(malloc_lock);
++                /*
++                 * Note that after we have waited for long_malloc_lock and
++                 * malloc_lock, we'll still be in the right "case" and
++                 * "if" branch because MemCheck_start and MemCheck_stop may
++                 * never be used while there are multiple OpenSSL threads.
++                 */
++                CRYPTO_THREAD_write_lock(long_malloc_lock);
++                CRYPTO_THREAD_write_lock(malloc_lock);
++                mh_mode &= ~CRYPTO_MEM_CHECK_ENABLE;
++                disabling_threadid = cur;
++            }
++            num_disable++;
++        }
++        break;
++
++    case CRYPTO_MEM_CHECK_ENABLE:
++        if (mh_mode & CRYPTO_MEM_CHECK_ON) {
++            if (num_disable) {  /* always true, or something is going wrong */
++                num_disable--;
++                if (num_disable == 0) {
++                    mh_mode |= CRYPTO_MEM_CHECK_ENABLE;
++                    CRYPTO_THREAD_unlock(long_malloc_lock);
++                }
++            }
++        }
++        break;
++    }
++    CRYPTO_THREAD_unlock(malloc_lock);
++    return (ret);
++#endif
++}
++
++#ifndef OPENSSL_NO_CRYPTO_MDEBUG
++
++static int mem_check_on(void)
++{
++    int ret = 0;
++    CRYPTO_THREAD_ID cur;
++
++    if (mh_mode & CRYPTO_MEM_CHECK_ON) {
++        if (!RUN_ONCE(&memdbg_init, do_memdbg_init))
++            return 0;
++
++        cur = CRYPTO_THREAD_get_current_id();
++        CRYPTO_THREAD_read_lock(malloc_lock);
++
++        ret = (mh_mode & CRYPTO_MEM_CHECK_ENABLE)
++            || !CRYPTO_THREAD_compare_id(disabling_threadid, cur);
++
++        CRYPTO_THREAD_unlock(malloc_lock);
++    }
++    return (ret);
++}
++
++static int mem_cmp(const MEM *a, const MEM *b)
++{
++#ifdef _WIN64
++    const char *ap = (const char *)a->addr, *bp = (const char *)b->addr;
++    if (ap == bp)
++        return 0;
++    else if (ap > bp)
++        return 1;
++    else
++        return -1;
++#else
++    return (const char *)a->addr - (const char *)b->addr;
++#endif
++}
++
++static unsigned long mem_hash(const MEM *a)
++{
++    size_t ret;
++
++    ret = (size_t)a->addr;
++
++    ret = ret * 17851 + (ret >> 14) * 7 + (ret >> 4) * 251;
++    return (ret);
++}
++
++/* returns 1 if there was an info to pop, 0 if the stack was empty. */
++static int pop_info(void)
++{
++    APP_INFO *current = NULL;
++
++    if (!RUN_ONCE(&memdbg_init, do_memdbg_init))
++        return 0;
++
++    current = (APP_INFO *)CRYPTO_THREAD_get_local(&appinfokey);
++    if (current != NULL) {
++        APP_INFO *next = current->next;
++
++        if (next != NULL) {
++            next->references++;
++            CRYPTO_THREAD_set_local(&appinfokey, next);
++        } else {
++            CRYPTO_THREAD_set_local(&appinfokey, NULL);
++        }
++        if (--(current->references) <= 0) {
++            current->next = NULL;
++            if (next != NULL)
++                next->references--;
++            OPENSSL_free(current);
++        }
++        return 1;
++    }
++    return 0;
++}
++
++int CRYPTO_mem_debug_push(const char *info, const char *file, int line)
++{
++    APP_INFO *ami, *amim;
++    int ret = 0;
++
++    if (mem_check_on()) {
++        CRYPTO_mem_ctrl(CRYPTO_MEM_CHECK_DISABLE);
++
++        if (!RUN_ONCE(&memdbg_init, do_memdbg_init)
++            || (ami = OPENSSL_malloc(sizeof(*ami))) == NULL)
++            goto err;
++
++        ami->threadid = CRYPTO_THREAD_get_current_id();
++        ami->file = file;
++        ami->line = line;
++        ami->info = info;
++        ami->references = 1;
++        ami->next = NULL;
++
++        amim = (APP_INFO *)CRYPTO_THREAD_get_local(&appinfokey);
++        CRYPTO_THREAD_set_local(&appinfokey, ami);
++
++        if (amim != NULL)
++            ami->next = amim;
++        ret = 1;
++ err:
++        CRYPTO_mem_ctrl(CRYPTO_MEM_CHECK_ENABLE);
++    }
++
++    return (ret);
++}
++
++int CRYPTO_mem_debug_pop(void)
++{
++    int ret = 0;
++
++    if (mem_check_on()) {
++        CRYPTO_mem_ctrl(CRYPTO_MEM_CHECK_DISABLE);
++        ret = pop_info();
++        CRYPTO_mem_ctrl(CRYPTO_MEM_CHECK_ENABLE);
++    }
++    return (ret);
++}
++
++static unsigned long break_order_num = 0;
++
++void CRYPTO_mem_debug_malloc(void *addr, size_t num, int before_p,
++                             const char *file, int line)
++{
++    MEM *m, *mm;
++    APP_INFO *amim;
++
++    switch (before_p & 127) {
++    case 0:
++        break;
++    case 1:
++        if (addr == NULL)
++            break;
++
++        if (mem_check_on()) {
++            CRYPTO_mem_ctrl(CRYPTO_MEM_CHECK_DISABLE);
++
++            if (!RUN_ONCE(&memdbg_init, do_memdbg_init)
++                || (m = OPENSSL_malloc(sizeof(*m))) == NULL) {
++                OPENSSL_free(addr);
++                CRYPTO_mem_ctrl(CRYPTO_MEM_CHECK_ENABLE);
++                return;
++            }
++            if (mh == NULL) {
++                if ((mh = lh_MEM_new(mem_hash, mem_cmp)) == NULL) {
++                    OPENSSL_free(addr);
++                    OPENSSL_free(m);
++                    addr = NULL;
++                    goto err;
++                }
++            }
++
++            m->addr = addr;
++            m->file = file;
++            m->line = line;
++            m->num = num;
++            m->threadid = CRYPTO_THREAD_get_current_id();
++
++            if (order == break_order_num) {
++                /* BREAK HERE */
++                m->order = order;
++            }
++            m->order = order++;
++# ifndef OPENSSL_NO_CRYPTO_MDEBUG_BACKTRACE
++            m->array_siz = backtrace(m->array, OSSL_NELEM(m->array));
++# endif
++            m->time = time(NULL);
++
++            amim = (APP_INFO *)CRYPTO_THREAD_get_local(&appinfokey);
++            m->app_info = amim;
++            if (amim != NULL)
++                amim->references++;
++
++            if ((mm = lh_MEM_insert(mh, m)) != NULL) {
++                /* Not good, but don't sweat it */
++                if (mm->app_info != NULL) {
++                    mm->app_info->references--;
++                }
++                OPENSSL_free(mm);
++            }
++ err:
++            CRYPTO_mem_ctrl(CRYPTO_MEM_CHECK_ENABLE);
++        }
++        break;
++    }
++    return;
++}
++
++void CRYPTO_mem_debug_free(void *addr, int before_p,
++        const char *file, int line)
++{
++    MEM m, *mp;
++
++    switch (before_p) {
++    case 0:
++        if (addr == NULL)
++            break;
++
++        if (mem_check_on() && (mh != NULL)) {
++            CRYPTO_mem_ctrl(CRYPTO_MEM_CHECK_DISABLE);
++
++            m.addr = addr;
++            mp = lh_MEM_delete(mh, &m);
++            if (mp != NULL) {
++                app_info_free(mp->app_info);
++                OPENSSL_free(mp);
++            }
++
++            CRYPTO_mem_ctrl(CRYPTO_MEM_CHECK_ENABLE);
++        }
++        break;
++    case 1:
++        break;
++    }
++}
++
++void CRYPTO_mem_debug_realloc(void *addr1, void *addr2, size_t num,
++                              int before_p, const char *file, int line)
++{
++    MEM m, *mp;
++
++    switch (before_p) {
++    case 0:
++        break;
++    case 1:
++        if (addr2 == NULL)
++            break;
++
++        if (addr1 == NULL) {
++            CRYPTO_mem_debug_malloc(addr2, num, 128 | before_p, file, line);
++            break;
++        }
++
++        if (mem_check_on()) {
++            CRYPTO_mem_ctrl(CRYPTO_MEM_CHECK_DISABLE);
++
++            m.addr = addr1;
++            mp = lh_MEM_delete(mh, &m);
++            if (mp != NULL) {
++                mp->addr = addr2;
++                mp->num = num;
++#ifndef OPENSSL_NO_CRYPTO_MDEBUG_BACKTRACE
++                mp->array_siz = backtrace(mp->array, OSSL_NELEM(mp->array));
++#endif
++                (void)lh_MEM_insert(mh, mp);
++            }
++
++            CRYPTO_mem_ctrl(CRYPTO_MEM_CHECK_ENABLE);
++        }
++        break;
++    }
++    return;
++}
++
++typedef struct mem_leak_st {
++    BIO *bio;
++    int chunks;
++    long bytes;
++} MEM_LEAK;
++
++static void print_leak(const MEM *m, MEM_LEAK *l)
++{
++    char buf[1024];
++    char *bufp = buf;
++    APP_INFO *amip;
++    int ami_cnt;
++    struct tm *lcl = NULL;
++    /*
++     * Convert between CRYPTO_THREAD_ID (which could be anything at all) and
++     * a long. This may not be meaningful depending on what CRYPTO_THREAD_ID is
++     * but hopefully should give something sensible on most platforms
++     */
++    union {
++        CRYPTO_THREAD_ID tid;
++        unsigned long ltid;
++    } tid;
++    CRYPTO_THREAD_ID ti;
++
++#define BUF_REMAIN (sizeof buf - (size_t)(bufp - buf))
++
++    lcl = localtime(&m->time);
++    BIO_snprintf(bufp, BUF_REMAIN, "[%02d:%02d:%02d] ",
++                 lcl->tm_hour, lcl->tm_min, lcl->tm_sec);
++    bufp += strlen(bufp);
++
++    BIO_snprintf(bufp, BUF_REMAIN, "%5lu file=%s, line=%d, ",
++                 m->order, m->file, m->line);
++    bufp += strlen(bufp);
++
++    tid.ltid = 0;
++    tid.tid = m->threadid;
++    BIO_snprintf(bufp, BUF_REMAIN, "thread=%lu, ", tid.ltid);
++    bufp += strlen(bufp);
++
++    BIO_snprintf(bufp, BUF_REMAIN, "number=%d, address=%p\n",
++                 m->num, m->addr);
++    bufp += strlen(bufp);
++
++    BIO_puts(l->bio, buf);
++
++    l->chunks++;
++    l->bytes += m->num;
++
++    amip = m->app_info;
++    ami_cnt = 0;
++
++    if (amip) {
++        ti = amip->threadid;
++
++        do {
++            int buf_len;
++            int info_len;
++
++            ami_cnt++;
++            memset(buf, '>', ami_cnt);
++            tid.ltid = 0;
++            tid.tid = amip->threadid;
++            BIO_snprintf(buf + ami_cnt, sizeof buf - ami_cnt,
++                         " thread=%lu, file=%s, line=%d, info=\"",
++                         tid.ltid, amip->file,
++                         amip->line);
++            buf_len = strlen(buf);
++            info_len = strlen(amip->info);
++            if (128 - buf_len - 3 < info_len) {
++                memcpy(buf + buf_len, amip->info, 128 - buf_len - 3);
++                buf_len = 128 - 3;
++            } else {
++                OPENSSL_strlcpy(buf + buf_len, amip->info, sizeof buf - buf_len);
++                buf_len = strlen(buf);
++            }
++            BIO_snprintf(buf + buf_len, sizeof buf - buf_len, "\"\n");
++
++            BIO_puts(l->bio, buf);
++
++            amip = amip->next;
++        }
++        while (amip && CRYPTO_THREAD_compare_id(amip->threadid, ti));
++    }
++
++#ifndef OPENSSL_NO_CRYPTO_MDEBUG_BACKTRACE
++    {
++        size_t i;
++        char **strings = backtrace_symbols(m->array, m->array_siz);
++
++        for (i = 0; i < m->array_siz; i++)
++            fprintf(stderr, "##> %s\n", strings[i]);
++        free(strings);
++    }
++#endif
++}
++
++IMPLEMENT_LHASH_DOALL_ARG_CONST(MEM, MEM_LEAK);
++
++int CRYPTO_mem_leaks(BIO *b)
++{
++    MEM_LEAK ml;
++
++    /*
++     * OPENSSL_cleanup() will free the ex_data locks so we can't have any
++     * ex_data hanging around
++     */
++    bio_free_ex_data(b);
++
++    /* Ensure all resources are released */
++    OPENSSL_cleanup();
++
++    if (!RUN_ONCE(&memdbg_init, do_memdbg_init))
++        return -1;
++
++    CRYPTO_mem_ctrl(CRYPTO_MEM_CHECK_DISABLE);
++
++    ml.bio = b;
++    ml.bytes = 0;
++    ml.chunks = 0;
++    if (mh != NULL)
++        lh_MEM_doall_MEM_LEAK(mh, print_leak, &ml);
++
++    if (ml.chunks != 0) {
++        BIO_printf(b, "%ld bytes leaked in %d chunks\n", ml.bytes, ml.chunks);
++    } else {
++        /*
++         * Make sure that, if we found no leaks, memory-leak debugging itself
++         * does not introduce memory leaks (which might irritate external
++         * debugging tools). (When someone enables leak checking, but does not
++         * call this function, we declare it to be their fault.)
++         */
++        int old_mh_mode;
++
++        CRYPTO_THREAD_write_lock(malloc_lock);
++
++        /*
++         * avoid deadlock when lh_free() uses CRYPTO_mem_debug_free(), which uses
++         * mem_check_on
++         */
++        old_mh_mode = mh_mode;
++        mh_mode = CRYPTO_MEM_CHECK_OFF;
++
++        lh_MEM_free(mh);
++        mh = NULL;
++
++        mh_mode = old_mh_mode;
++        CRYPTO_THREAD_unlock(malloc_lock);
++    }
++    CRYPTO_mem_ctrl(CRYPTO_MEM_CHECK_OFF);
++
++    /* Clean up locks etc */
++    CRYPTO_THREAD_cleanup_local(&appinfokey);
++    CRYPTO_THREAD_lock_free(malloc_lock);
++    CRYPTO_THREAD_lock_free(long_malloc_lock);
++    malloc_lock = NULL;
++    long_malloc_lock = NULL;
++
++    return ml.chunks == 0 ? 1 : 0;
++}
++
++# ifndef OPENSSL_NO_STDIO
++int CRYPTO_mem_leaks_fp(FILE *fp)
++{
++    BIO *b;
++    int ret;
++
++    /*
++     * Need to turn off memory checking when allocated BIOs ... especially as
++     * we're creating them at a time when we're trying to check we've not
++     * left anything un-free()'d!!
++     */
++    CRYPTO_mem_ctrl(CRYPTO_MEM_CHECK_DISABLE);
++    b = BIO_new(BIO_s_file());
++    CRYPTO_mem_ctrl(CRYPTO_MEM_CHECK_ENABLE);
++    if (b == NULL)
++        return -1;
++    BIO_set_fp(b, fp, BIO_NOCLOSE);
++    ret = CRYPTO_mem_leaks(b);
++    BIO_free(b);
++    return ret;
++}
++# endif
++
++#endif
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/mem_sec.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/mem_sec.c
+new file mode 100644
+index 0000000..0c79b43
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/mem_sec.c
+@@ -0,0 +1,585 @@
++/*
++ * Copyright 2015-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++/*
++ * Copyright 2004-2014, Akamai Technologies. All Rights Reserved.
++ * This file is distributed under the terms of the OpenSSL license.
++ */
++
++/*
++ * This file is in two halves. The first half implements the public API
++ * to be used by external consumers, and to be used by OpenSSL to store
++ * data in a "secure arena." The second half implements the secure arena.
++ * For details on that implementation, see below (look for uppercase
++ * "SECURE HEAP IMPLEMENTATION").
++ */
++#include 
++#include 
++
++#include 
++
++#if defined(OPENSSL_SYS_LINUX) || defined(OPENSSL_SYS_UNIX)
++# define IMPLEMENTED
++# include 
++# include 
++# include 
++# include 
++# include 
++# include 
++# include 
++# include 
++#endif
++
++#define CLEAR(p, s) OPENSSL_cleanse(p, s)
++#ifndef PAGE_SIZE
++# define PAGE_SIZE    4096
++#endif
++
++#ifdef IMPLEMENTED
++static size_t secure_mem_used;
++
++static int secure_mem_initialized;
++
++static CRYPTO_RWLOCK *sec_malloc_lock = NULL;
++
++/*
++ * These are the functions that must be implemented by a secure heap (sh).
++ */
++static int sh_init(size_t size, int minsize);
++static char *sh_malloc(size_t size);
++static void sh_free(char *ptr);
++static void sh_done(void);
++static size_t sh_actual_size(char *ptr);
++static int sh_allocated(const char *ptr);
++#endif
++
++int CRYPTO_secure_malloc_init(size_t size, int minsize)
++{
++#ifdef IMPLEMENTED
++    int ret = 0;
++
++    if (!secure_mem_initialized) {
++        sec_malloc_lock = CRYPTO_THREAD_lock_new();
++        if (sec_malloc_lock == NULL)
++            return 0;
++        ret = sh_init(size, minsize);
++        secure_mem_initialized = 1;
++    }
++
++    return ret;
++#else
++    return 0;
++#endif /* IMPLEMENTED */
++}
++
++int CRYPTO_secure_malloc_done()
++{
++#ifdef IMPLEMENTED
++    if (secure_mem_used == 0) {
++        sh_done();
++        secure_mem_initialized = 0;
++        CRYPTO_THREAD_lock_free(sec_malloc_lock);
++        return 1;
++    }
++#endif /* IMPLEMENTED */
++    return 0;
++}
++
++int CRYPTO_secure_malloc_initialized()
++{
++#ifdef IMPLEMENTED
++    return secure_mem_initialized;
++#else
++    return 0;
++#endif /* IMPLEMENTED */
++}
++
++void *CRYPTO_secure_malloc(size_t num, const char *file, int line)
++{
++#ifdef IMPLEMENTED
++    void *ret;
++    size_t actual_size;
++
++    if (!secure_mem_initialized) {
++        return CRYPTO_malloc(num, file, line);
++    }
++    CRYPTO_THREAD_write_lock(sec_malloc_lock);
++    ret = sh_malloc(num);
++    actual_size = ret ? sh_actual_size(ret) : 0;
++    secure_mem_used += actual_size;
++    CRYPTO_THREAD_unlock(sec_malloc_lock);
++    return ret;
++#else
++    return CRYPTO_malloc(num, file, line);
++#endif /* IMPLEMENTED */
++}
++
++void *CRYPTO_secure_zalloc(size_t num, const char *file, int line)
++{
++    void *ret = CRYPTO_secure_malloc(num, file, line);
++
++    if (ret != NULL)
++        memset(ret, 0, num);
++    return ret;
++}
++
++void CRYPTO_secure_free(void *ptr, const char *file, int line)
++{
++#ifdef IMPLEMENTED
++    size_t actual_size;
++
++    if (ptr == NULL)
++        return;
++    if (!CRYPTO_secure_allocated(ptr)) {
++        CRYPTO_free(ptr, file, line);
++        return;
++    }
++    CRYPTO_THREAD_write_lock(sec_malloc_lock);
++    actual_size = sh_actual_size(ptr);
++    CLEAR(ptr, actual_size);
++    secure_mem_used -= actual_size;
++    sh_free(ptr);
++    CRYPTO_THREAD_unlock(sec_malloc_lock);
++#else
++    CRYPTO_free(ptr, file, line);
++#endif /* IMPLEMENTED */
++}
++
++int CRYPTO_secure_allocated(const void *ptr)
++{
++#ifdef IMPLEMENTED
++    int ret;
++
++    if (!secure_mem_initialized)
++        return 0;
++    CRYPTO_THREAD_write_lock(sec_malloc_lock);
++    ret = sh_allocated(ptr);
++    CRYPTO_THREAD_unlock(sec_malloc_lock);
++    return ret;
++#else
++    return 0;
++#endif /* IMPLEMENTED */
++}
++
++size_t CRYPTO_secure_used()
++{
++#ifdef IMPLEMENTED
++    return secure_mem_used;
++#else
++    return 0;
++#endif /* IMPLEMENTED */
++}
++
++size_t CRYPTO_secure_actual_size(void *ptr)
++{
++#ifdef IMPLEMENTED
++    size_t actual_size;
++
++    CRYPTO_THREAD_write_lock(sec_malloc_lock);
++    actual_size = sh_actual_size(ptr);
++    CRYPTO_THREAD_unlock(sec_malloc_lock);
++    return actual_size;
++#else
++    return 0;
++#endif
++}
++/* END OF PAGE ...
++
++   ... START OF PAGE */
++
++/*
++ * SECURE HEAP IMPLEMENTATION
++ */
++#ifdef IMPLEMENTED
++
++
++/*
++ * The implementation provided here uses a fixed-sized mmap() heap,
++ * which is locked into memory, not written to core files, and protected
++ * on either side by an unmapped page, which will catch pointer overruns
++ * (or underruns) and an attempt to read data out of the secure heap.
++ * Free'd memory is zero'd or otherwise cleansed.
++ *
++ * This is a pretty standard buddy allocator.  We keep areas in a multiple
++ * of "sh.minsize" units.  The freelist and bitmaps are kept separately,
++ * so all (and only) data is kept in the mmap'd heap.
++ *
++ * This code assumes eight-bit bytes.  The numbers 3 and 7 are all over the
++ * place.
++ */
++
++#define ONE ((size_t)1)
++
++# define TESTBIT(t, b)  (t[(b) >> 3] &  (ONE << ((b) & 7)))
++# define SETBIT(t, b)   (t[(b) >> 3] |= (ONE << ((b) & 7)))
++# define CLEARBIT(t, b) (t[(b) >> 3] &= (0xFF & ~(ONE << ((b) & 7))))
++
++#define WITHIN_ARENA(p) \
++    ((char*)(p) >= sh.arena && (char*)(p) < &sh.arena[sh.arena_size])
++#define WITHIN_FREELIST(p) \
++    ((char*)(p) >= (char*)sh.freelist && (char*)(p) < (char*)&sh.freelist[sh.freelist_size])
++
++
++typedef struct sh_list_st
++{
++    struct sh_list_st *next;
++    struct sh_list_st **p_next;
++} SH_LIST;
++
++typedef struct sh_st
++{
++    char* map_result;
++    size_t map_size;
++    char *arena;
++    size_t arena_size;
++    char **freelist;
++    ossl_ssize_t freelist_size;
++    size_t minsize;
++    unsigned char *bittable;
++    unsigned char *bitmalloc;
++    size_t bittable_size; /* size in bits */
++} SH;
++
++static SH sh;
++
++static size_t sh_getlist(char *ptr)
++{
++    ossl_ssize_t list = sh.freelist_size - 1;
++    size_t bit = (sh.arena_size + ptr - sh.arena) / sh.minsize;
++
++    for (; bit; bit >>= 1, list--) {
++        if (TESTBIT(sh.bittable, bit))
++            break;
++        OPENSSL_assert((bit & 1) == 0);
++    }
++
++    return list;
++}
++
++
++static int sh_testbit(char *ptr, int list, unsigned char *table)
++{
++    size_t bit;
++
++    OPENSSL_assert(list >= 0 && list < sh.freelist_size);
++    OPENSSL_assert(((ptr - sh.arena) & ((sh.arena_size >> list) - 1)) == 0);
++    bit = (ONE << list) + ((ptr - sh.arena) / (sh.arena_size >> list));
++    OPENSSL_assert(bit > 0 && bit < sh.bittable_size);
++    return TESTBIT(table, bit);
++}
++
++static void sh_clearbit(char *ptr, int list, unsigned char *table)
++{
++    size_t bit;
++
++    OPENSSL_assert(list >= 0 && list < sh.freelist_size);
++    OPENSSL_assert(((ptr - sh.arena) & ((sh.arena_size >> list) - 1)) == 0);
++    bit = (ONE << list) + ((ptr - sh.arena) / (sh.arena_size >> list));
++    OPENSSL_assert(bit > 0 && bit < sh.bittable_size);
++    OPENSSL_assert(TESTBIT(table, bit));
++    CLEARBIT(table, bit);
++}
++
++static void sh_setbit(char *ptr, int list, unsigned char *table)
++{
++    size_t bit;
++
++    OPENSSL_assert(list >= 0 && list < sh.freelist_size);
++    OPENSSL_assert(((ptr - sh.arena) & ((sh.arena_size >> list) - 1)) == 0);
++    bit = (ONE << list) + ((ptr - sh.arena) / (sh.arena_size >> list));
++    OPENSSL_assert(bit > 0 && bit < sh.bittable_size);
++    OPENSSL_assert(!TESTBIT(table, bit));
++    SETBIT(table, bit);
++}
++
++static void sh_add_to_list(char **list, char *ptr)
++{
++    SH_LIST *temp;
++
++    OPENSSL_assert(WITHIN_FREELIST(list));
++    OPENSSL_assert(WITHIN_ARENA(ptr));
++
++    temp = (SH_LIST *)ptr;
++    temp->next = *(SH_LIST **)list;
++    OPENSSL_assert(temp->next == NULL || WITHIN_ARENA(temp->next));
++    temp->p_next = (SH_LIST **)list;
++
++    if (temp->next != NULL) {
++        OPENSSL_assert((char **)temp->next->p_next == list);
++        temp->next->p_next = &(temp->next);
++    }
++
++    *list = ptr;
++}
++
++static void sh_remove_from_list(char *ptr)
++{
++    SH_LIST *temp, *temp2;
++
++    temp = (SH_LIST *)ptr;
++    if (temp->next != NULL)
++        temp->next->p_next = temp->p_next;
++    *temp->p_next = temp->next;
++    if (temp->next == NULL)
++        return;
++
++    temp2 = temp->next;
++    OPENSSL_assert(WITHIN_FREELIST(temp2->p_next) || WITHIN_ARENA(temp2->p_next));
++}
++
++
++static int sh_init(size_t size, int minsize)
++{
++    int i, ret;
++    size_t pgsize;
++    size_t aligned;
++
++    memset(&sh, 0, sizeof sh);
++
++    /* make sure size and minsize are powers of 2 */
++    OPENSSL_assert(size > 0);
++    OPENSSL_assert((size & (size - 1)) == 0);
++    OPENSSL_assert(minsize > 0);
++    OPENSSL_assert((minsize & (minsize - 1)) == 0);
++    if (size <= 0 || (size & (size - 1)) != 0)
++        goto err;
++    if (minsize <= 0 || (minsize & (minsize - 1)) != 0)
++        goto err;
++
++    sh.arena_size = size;
++    sh.minsize = minsize;
++    sh.bittable_size = (sh.arena_size / sh.minsize) * 2;
++
++    /* Prevent allocations of size 0 later on */
++    if (sh.bittable_size >> 3 == 0)
++        goto err;
++
++    sh.freelist_size = -1;
++    for (i = sh.bittable_size; i; i >>= 1)
++        sh.freelist_size++;
++
++    sh.freelist = OPENSSL_zalloc(sh.freelist_size * sizeof (char *));
++    OPENSSL_assert(sh.freelist != NULL);
++    if (sh.freelist == NULL)
++        goto err;
++
++    sh.bittable = OPENSSL_zalloc(sh.bittable_size >> 3);
++    OPENSSL_assert(sh.bittable != NULL);
++    if (sh.bittable == NULL)
++        goto err;
++
++    sh.bitmalloc = OPENSSL_zalloc(sh.bittable_size >> 3);
++    OPENSSL_assert(sh.bitmalloc != NULL);
++    if (sh.bitmalloc == NULL)
++        goto err;
++
++    /* Allocate space for heap, and two extra pages as guards */
++#if defined(_SC_PAGE_SIZE) || defined (_SC_PAGESIZE)
++    {
++# if defined(_SC_PAGE_SIZE)
++        long tmppgsize = sysconf(_SC_PAGE_SIZE);
++# else
++        long tmppgsize = sysconf(_SC_PAGESIZE);
++# endif
++        if (tmppgsize < 1)
++            pgsize = PAGE_SIZE;
++        else
++            pgsize = (size_t)tmppgsize;
++    }
++#else
++    pgsize = PAGE_SIZE;
++#endif
++    sh.map_size = pgsize + sh.arena_size + pgsize;
++    if (1) {
++#ifdef MAP_ANON
++        sh.map_result = mmap(NULL, sh.map_size,
++                             PROT_READ|PROT_WRITE, MAP_ANON|MAP_PRIVATE, -1, 0);
++    } else {
++#endif
++        int fd;
++
++        sh.map_result = MAP_FAILED;
++        if ((fd = open("/dev/zero", O_RDWR)) >= 0) {
++            sh.map_result = mmap(NULL, sh.map_size,
++                                 PROT_READ|PROT_WRITE, MAP_PRIVATE, fd, 0);
++            close(fd);
++        }
++    }
++    OPENSSL_assert(sh.map_result != MAP_FAILED);
++    if (sh.map_result == MAP_FAILED)
++        goto err;
++    sh.arena = (char *)(sh.map_result + pgsize);
++    sh_setbit(sh.arena, 0, sh.bittable);
++    sh_add_to_list(&sh.freelist[0], sh.arena);
++
++    /* Now try to add guard pages and lock into memory. */
++    ret = 1;
++
++    /* Starting guard is already aligned from mmap. */
++    if (mprotect(sh.map_result, pgsize, PROT_NONE) < 0)
++        ret = 2;
++
++    /* Ending guard page - need to round up to page boundary */
++    aligned = (pgsize + sh.arena_size + (pgsize - 1)) & ~(pgsize - 1);
++    if (mprotect(sh.map_result + aligned, pgsize, PROT_NONE) < 0)
++        ret = 2;
++
++    if (mlock(sh.arena, sh.arena_size) < 0)
++        ret = 2;
++#ifdef MADV_DONTDUMP
++    if (madvise(sh.arena, sh.arena_size, MADV_DONTDUMP) < 0)
++        ret = 2;
++#endif
++
++    return ret;
++
++ err:
++    sh_done();
++    return 0;
++}
++
++static void sh_done()
++{
++    OPENSSL_free(sh.freelist);
++    OPENSSL_free(sh.bittable);
++    OPENSSL_free(sh.bitmalloc);
++    if (sh.map_result != NULL && sh.map_size)
++        munmap(sh.map_result, sh.map_size);
++    memset(&sh, 0, sizeof sh);
++}
++
++static int sh_allocated(const char *ptr)
++{
++    return WITHIN_ARENA(ptr) ? 1 : 0;
++}
++
++static char *sh_find_my_buddy(char *ptr, int list)
++{
++    size_t bit;
++    char *chunk = NULL;
++
++    bit = (ONE << list) + (ptr - sh.arena) / (sh.arena_size >> list);
++    bit ^= 1;
++
++    if (TESTBIT(sh.bittable, bit) && !TESTBIT(sh.bitmalloc, bit))
++        chunk = sh.arena + ((bit & ((ONE << list) - 1)) * (sh.arena_size >> list));
++
++    return chunk;
++}
++
++static char *sh_malloc(size_t size)
++{
++    ossl_ssize_t list, slist;
++    size_t i;
++    char *chunk;
++
++    list = sh.freelist_size - 1;
++    for (i = sh.minsize; i < size; i <<= 1)
++        list--;
++    if (list < 0)
++        return NULL;
++
++    /* try to find a larger entry to split */
++    for (slist = list; slist >= 0; slist--)
++        if (sh.freelist[slist] != NULL)
++            break;
++    if (slist < 0)
++        return NULL;
++
++    /* split larger entry */
++    while (slist != list) {
++        char *temp = sh.freelist[slist];
++
++        /* remove from bigger list */
++        OPENSSL_assert(!sh_testbit(temp, slist, sh.bitmalloc));
++        sh_clearbit(temp, slist, sh.bittable);
++        sh_remove_from_list(temp);
++        OPENSSL_assert(temp != sh.freelist[slist]);
++
++        /* done with bigger list */
++        slist++;
++
++        /* add to smaller list */
++        OPENSSL_assert(!sh_testbit(temp, slist, sh.bitmalloc));
++        sh_setbit(temp, slist, sh.bittable);
++        sh_add_to_list(&sh.freelist[slist], temp);
++        OPENSSL_assert(sh.freelist[slist] == temp);
++
++        /* split in 2 */
++        temp += sh.arena_size >> slist;
++        OPENSSL_assert(!sh_testbit(temp, slist, sh.bitmalloc));
++        sh_setbit(temp, slist, sh.bittable);
++        sh_add_to_list(&sh.freelist[slist], temp);
++        OPENSSL_assert(sh.freelist[slist] == temp);
++
++        OPENSSL_assert(temp-(sh.arena_size >> slist) == sh_find_my_buddy(temp, slist));
++    }
++
++    /* peel off memory to hand back */
++    chunk = sh.freelist[list];
++    OPENSSL_assert(sh_testbit(chunk, list, sh.bittable));
++    sh_setbit(chunk, list, sh.bitmalloc);
++    sh_remove_from_list(chunk);
++
++    OPENSSL_assert(WITHIN_ARENA(chunk));
++
++    return chunk;
++}
++
++static void sh_free(char *ptr)
++{
++    size_t list;
++    char *buddy;
++
++    if (ptr == NULL)
++        return;
++    OPENSSL_assert(WITHIN_ARENA(ptr));
++    if (!WITHIN_ARENA(ptr))
++        return;
++
++    list = sh_getlist(ptr);
++    OPENSSL_assert(sh_testbit(ptr, list, sh.bittable));
++    sh_clearbit(ptr, list, sh.bitmalloc);
++    sh_add_to_list(&sh.freelist[list], ptr);
++
++    /* Try to coalesce two adjacent free areas. */
++    while ((buddy = sh_find_my_buddy(ptr, list)) != NULL) {
++        OPENSSL_assert(ptr == sh_find_my_buddy(buddy, list));
++        OPENSSL_assert(ptr != NULL);
++        OPENSSL_assert(!sh_testbit(ptr, list, sh.bitmalloc));
++        sh_clearbit(ptr, list, sh.bittable);
++        sh_remove_from_list(ptr);
++        OPENSSL_assert(!sh_testbit(ptr, list, sh.bitmalloc));
++        sh_clearbit(buddy, list, sh.bittable);
++        sh_remove_from_list(buddy);
++
++        list--;
++
++        if (ptr > buddy)
++            ptr = buddy;
++
++        OPENSSL_assert(!sh_testbit(ptr, list, sh.bitmalloc));
++        sh_setbit(ptr, list, sh.bittable);
++        sh_add_to_list(&sh.freelist[list], ptr);
++        OPENSSL_assert(sh.freelist[list] == ptr);
++    }
++}
++
++static size_t sh_actual_size(char *ptr)
++{
++    int list;
++
++    OPENSSL_assert(WITHIN_ARENA(ptr));
++    if (!WITHIN_ARENA(ptr))
++        return 0;
++    list = sh_getlist(ptr);
++    OPENSSL_assert(sh_testbit(ptr, list, sh.bittable));
++    return sh.arena_size / (ONE << list);
++}
++#endif /* IMPLEMENTED */
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/modes/asm/aesni-gcm-x86_64.pl b/CryptoPkg/Library/OpensslLib/openssl/crypto/modes/asm/aesni-gcm-x86_64.pl
+new file mode 100644
+index 0000000..5ad62b3
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/modes/asm/aesni-gcm-x86_64.pl
+@@ -0,0 +1,1106 @@
++#! /usr/bin/env perl
++# Copyright 2013-2016 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
++# in the file LICENSE in the source distribution or at
++# https://www.openssl.org/source/license.html
++
++#
++# ====================================================================
++# Written by Andy Polyakov  for the OpenSSL
++# project. The module is, however, dual licensed under OpenSSL and
++# CRYPTOGAMS licenses depending on where you obtain it. For further
++# details see http://www.openssl.org/~appro/cryptogams/.
++# ====================================================================
++#
++#
++# AES-NI-CTR+GHASH stitch.
++#
++# February 2013
++#
++# OpenSSL GCM implementation is organized in such way that its
++# performance is rather close to the sum of its streamed components,
++# in the context parallelized AES-NI CTR and modulo-scheduled
++# PCLMULQDQ-enabled GHASH. Unfortunately, as no stitch implementation
++# was observed to perform significantly better than the sum of the
++# components on contemporary CPUs, the effort was deemed impossible to
++# justify. This module is based on combination of Intel submissions,
++# [1] and [2], with MOVBE twist suggested by Ilya Albrekht and Max
++# Locktyukhin of Intel Corp. who verified that it reduces shuffles
++# pressure with notable relative improvement, achieving 1.0 cycle per
++# byte processed with 128-bit key on Haswell processor, 0.74 - on
++# Broadwell, 0.63 - on Skylake... [Mentioned results are raw profiled
++# measurements for favourable packet size, one divisible by 96.
++# Applications using the EVP interface will observe a few percent
++# worse performance.]
++#
++# [1] http://rt.openssl.org/Ticket/Display.html?id=2900&user=guest&pass=guest
++# [2] http://www.intel.com/content/dam/www/public/us/en/documents/software-support/enabling-high-performance-gcm.pdf
++
++$flavour = shift;
++$output  = shift;
++if ($flavour =~ /\./) { $output = $flavour; undef $flavour; }
++
++$win64=0; $win64=1 if ($flavour =~ /[nm]asm|mingw64/ || $output =~ /\.asm$/);
++
++$0 =~ m/(.*[\/\\])[^\/\\]+$/; $dir=$1;
++( $xlate="${dir}x86_64-xlate.pl" and -f $xlate ) or
++( $xlate="${dir}../../perlasm/x86_64-xlate.pl" and -f $xlate) or
++die "can't locate x86_64-xlate.pl";
++
++if (`$ENV{CC} -Wa,-v -c -o /dev/null -x assembler /dev/null 2>&1`
++		=~ /GNU assembler version ([2-9]\.[0-9]+)/) {
++	$avx = ($1>=2.20) + ($1>=2.22);
++}
++
++if (!$avx && $win64 && ($flavour =~ /nasm/ || $ENV{ASM} =~ /nasm/) &&
++	    `nasm -v 2>&1` =~ /NASM version ([2-9]\.[0-9]+)/) {
++	$avx = ($1>=2.09) + ($1>=2.10);
++}
++
++if (!$avx && $win64 && ($flavour =~ /masm/ || $ENV{ASM} =~ /ml64/) &&
++	    `ml64 2>&1` =~ /Version ([0-9]+)\./) {
++	$avx = ($1>=10) + ($1>=11);
++}
++
++if (!$avx && `$ENV{CC} -v 2>&1` =~ /((?:^clang|LLVM) version|.*based on LLVM) ([3-9]\.[0-9]+)/) {
++	$avx = ($2>=3.0) + ($2>3.0);
++}
++
++open OUT,"| \"$^X\" \"$xlate\" $flavour \"$output\"";
++*STDOUT=*OUT;
++
++if ($avx>1) {{{
++
++($inp,$out,$len,$key,$ivp,$Xip)=("%rdi","%rsi","%rdx","%rcx","%r8","%r9");
++
++($Ii,$T1,$T2,$Hkey,
++ $Z0,$Z1,$Z2,$Z3,$Xi) = map("%xmm$_",(0..8));
++
++($inout0,$inout1,$inout2,$inout3,$inout4,$inout5,$rndkey) = map("%xmm$_",(9..15));
++
++($counter,$rounds,$ret,$const,$in0,$end0)=("%ebx","%ebp","%r10","%r11","%r14","%r15");
++
++$code=<<___;
++.text
++
++.type	_aesni_ctr32_ghash_6x,\@abi-omnipotent
++.align	32
++_aesni_ctr32_ghash_6x:
++	vmovdqu		0x20($const),$T2	# borrow $T2, .Lone_msb
++	sub		\$6,$len
++	vpxor		$Z0,$Z0,$Z0		# $Z0   = 0
++	vmovdqu		0x00-0x80($key),$rndkey
++	vpaddb		$T2,$T1,$inout1
++	vpaddb		$T2,$inout1,$inout2
++	vpaddb		$T2,$inout2,$inout3
++	vpaddb		$T2,$inout3,$inout4
++	vpaddb		$T2,$inout4,$inout5
++	vpxor		$rndkey,$T1,$inout0
++	vmovdqu		$Z0,16+8(%rsp)		# "$Z3" = 0
++	jmp		.Loop6x
++
++.align	32
++.Loop6x:
++	add		\$`6<<24`,$counter
++	jc		.Lhandle_ctr32		# discard $inout[1-5]?
++	vmovdqu		0x00-0x20($Xip),$Hkey	# $Hkey^1
++	  vpaddb	$T2,$inout5,$T1		# next counter value
++	  vpxor		$rndkey,$inout1,$inout1
++	  vpxor		$rndkey,$inout2,$inout2
++
++.Lresume_ctr32:
++	vmovdqu		$T1,($ivp)		# save next counter value
++	vpclmulqdq	\$0x10,$Hkey,$Z3,$Z1
++	  vpxor		$rndkey,$inout3,$inout3
++	  vmovups	0x10-0x80($key),$T2	# borrow $T2 for $rndkey
++	vpclmulqdq	\$0x01,$Hkey,$Z3,$Z2
++
++	# At this point, the current block of 96 (0x60) bytes has already been
++	# loaded into registers. Concurrently with processing it, we want to
++	# load the next 96 bytes of input for the next round. Obviously, we can
++	# only do this if there are at least 96 more bytes of input beyond the
++	# input we're currently processing, or else we'd read past the end of
++	# the input buffer. Here, we set |%r12| to 96 if there are at least 96
++	# bytes of input beyond the 96 bytes we're already processing, and we
++	# set |%r12| to 0 otherwise. In the case where we set |%r12| to 96,
++	# we'll read in the next block so that it is in registers for the next
++	# loop iteration. In the case where we set |%r12| to 0, we'll re-read
++	# the current block and then ignore what we re-read.
++	#
++	# At this point, |$in0| points to the current (already read into
++	# registers) block, and |$end0| points to 2*96 bytes before the end of
++	# the input. Thus, |$in0| > |$end0| means that we do not have the next
++	# 96-byte block to read in, and |$in0| <= |$end0| means we do.
++	xor		%r12,%r12
++	cmp		$in0,$end0
++
++	  vaesenc	$T2,$inout0,$inout0
++	vmovdqu		0x30+8(%rsp),$Ii	# I[4]
++	  vpxor		$rndkey,$inout4,$inout4
++	vpclmulqdq	\$0x00,$Hkey,$Z3,$T1
++	  vaesenc	$T2,$inout1,$inout1
++	  vpxor		$rndkey,$inout5,$inout5
++	setnc		%r12b
++	vpclmulqdq	\$0x11,$Hkey,$Z3,$Z3
++	  vaesenc	$T2,$inout2,$inout2
++	vmovdqu		0x10-0x20($Xip),$Hkey	# $Hkey^2
++	neg		%r12
++	  vaesenc	$T2,$inout3,$inout3
++	 vpxor		$Z1,$Z2,$Z2
++	vpclmulqdq	\$0x00,$Hkey,$Ii,$Z1
++	 vpxor		$Z0,$Xi,$Xi		# modulo-scheduled
++	  vaesenc	$T2,$inout4,$inout4
++	 vpxor		$Z1,$T1,$Z0
++	and		\$0x60,%r12
++	  vmovups	0x20-0x80($key),$rndkey
++	vpclmulqdq	\$0x10,$Hkey,$Ii,$T1
++	  vaesenc	$T2,$inout5,$inout5
++
++	vpclmulqdq	\$0x01,$Hkey,$Ii,$T2
++	lea		($in0,%r12),$in0
++	  vaesenc	$rndkey,$inout0,$inout0
++	 vpxor		16+8(%rsp),$Xi,$Xi	# modulo-scheduled [vpxor $Z3,$Xi,$Xi]
++	vpclmulqdq	\$0x11,$Hkey,$Ii,$Hkey
++	 vmovdqu	0x40+8(%rsp),$Ii	# I[3]
++	  vaesenc	$rndkey,$inout1,$inout1
++	movbe		0x58($in0),%r13
++	  vaesenc	$rndkey,$inout2,$inout2
++	movbe		0x50($in0),%r12
++	  vaesenc	$rndkey,$inout3,$inout3
++	mov		%r13,0x20+8(%rsp)
++	  vaesenc	$rndkey,$inout4,$inout4
++	mov		%r12,0x28+8(%rsp)
++	vmovdqu		0x30-0x20($Xip),$Z1	# borrow $Z1 for $Hkey^3
++	  vaesenc	$rndkey,$inout5,$inout5
++
++	  vmovups	0x30-0x80($key),$rndkey
++	 vpxor		$T1,$Z2,$Z2
++	vpclmulqdq	\$0x00,$Z1,$Ii,$T1
++	  vaesenc	$rndkey,$inout0,$inout0
++	 vpxor		$T2,$Z2,$Z2
++	vpclmulqdq	\$0x10,$Z1,$Ii,$T2
++	  vaesenc	$rndkey,$inout1,$inout1
++	 vpxor		$Hkey,$Z3,$Z3
++	vpclmulqdq	\$0x01,$Z1,$Ii,$Hkey
++	  vaesenc	$rndkey,$inout2,$inout2
++	vpclmulqdq	\$0x11,$Z1,$Ii,$Z1
++	 vmovdqu	0x50+8(%rsp),$Ii	# I[2]
++	  vaesenc	$rndkey,$inout3,$inout3
++	  vaesenc	$rndkey,$inout4,$inout4
++	 vpxor		$T1,$Z0,$Z0
++	vmovdqu		0x40-0x20($Xip),$T1	# borrow $T1 for $Hkey^4
++	  vaesenc	$rndkey,$inout5,$inout5
++
++	  vmovups	0x40-0x80($key),$rndkey
++	 vpxor		$T2,$Z2,$Z2
++	vpclmulqdq	\$0x00,$T1,$Ii,$T2
++	  vaesenc	$rndkey,$inout0,$inout0
++	 vpxor		$Hkey,$Z2,$Z2
++	vpclmulqdq	\$0x10,$T1,$Ii,$Hkey
++	  vaesenc	$rndkey,$inout1,$inout1
++	movbe		0x48($in0),%r13
++	 vpxor		$Z1,$Z3,$Z3
++	vpclmulqdq	\$0x01,$T1,$Ii,$Z1
++	  vaesenc	$rndkey,$inout2,$inout2
++	movbe		0x40($in0),%r12
++	vpclmulqdq	\$0x11,$T1,$Ii,$T1
++	 vmovdqu	0x60+8(%rsp),$Ii	# I[1]
++	  vaesenc	$rndkey,$inout3,$inout3
++	mov		%r13,0x30+8(%rsp)
++	  vaesenc	$rndkey,$inout4,$inout4
++	mov		%r12,0x38+8(%rsp)
++	 vpxor		$T2,$Z0,$Z0
++	vmovdqu		0x60-0x20($Xip),$T2	# borrow $T2 for $Hkey^5
++	  vaesenc	$rndkey,$inout5,$inout5
++
++	  vmovups	0x50-0x80($key),$rndkey
++	 vpxor		$Hkey,$Z2,$Z2
++	vpclmulqdq	\$0x00,$T2,$Ii,$Hkey
++	  vaesenc	$rndkey,$inout0,$inout0
++	 vpxor		$Z1,$Z2,$Z2
++	vpclmulqdq	\$0x10,$T2,$Ii,$Z1
++	  vaesenc	$rndkey,$inout1,$inout1
++	movbe		0x38($in0),%r13
++	 vpxor		$T1,$Z3,$Z3
++	vpclmulqdq	\$0x01,$T2,$Ii,$T1
++	 vpxor		0x70+8(%rsp),$Xi,$Xi	# accumulate I[0]
++	  vaesenc	$rndkey,$inout2,$inout2
++	movbe		0x30($in0),%r12
++	vpclmulqdq	\$0x11,$T2,$Ii,$T2
++	  vaesenc	$rndkey,$inout3,$inout3
++	mov		%r13,0x40+8(%rsp)
++	  vaesenc	$rndkey,$inout4,$inout4
++	mov		%r12,0x48+8(%rsp)
++	 vpxor		$Hkey,$Z0,$Z0
++	 vmovdqu	0x70-0x20($Xip),$Hkey	# $Hkey^6
++	  vaesenc	$rndkey,$inout5,$inout5
++
++	  vmovups	0x60-0x80($key),$rndkey
++	 vpxor		$Z1,$Z2,$Z2
++	vpclmulqdq	\$0x10,$Hkey,$Xi,$Z1
++	  vaesenc	$rndkey,$inout0,$inout0
++	 vpxor		$T1,$Z2,$Z2
++	vpclmulqdq	\$0x01,$Hkey,$Xi,$T1
++	  vaesenc	$rndkey,$inout1,$inout1
++	movbe		0x28($in0),%r13
++	 vpxor		$T2,$Z3,$Z3
++	vpclmulqdq	\$0x00,$Hkey,$Xi,$T2
++	  vaesenc	$rndkey,$inout2,$inout2
++	movbe		0x20($in0),%r12
++	vpclmulqdq	\$0x11,$Hkey,$Xi,$Xi
++	  vaesenc	$rndkey,$inout3,$inout3
++	mov		%r13,0x50+8(%rsp)
++	  vaesenc	$rndkey,$inout4,$inout4
++	mov		%r12,0x58+8(%rsp)
++	vpxor		$Z1,$Z2,$Z2
++	  vaesenc	$rndkey,$inout5,$inout5
++	vpxor		$T1,$Z2,$Z2
++
++	  vmovups	0x70-0x80($key),$rndkey
++	vpslldq		\$8,$Z2,$Z1
++	vpxor		$T2,$Z0,$Z0
++	vmovdqu		0x10($const),$Hkey	# .Lpoly
++
++	  vaesenc	$rndkey,$inout0,$inout0
++	vpxor		$Xi,$Z3,$Z3
++	  vaesenc	$rndkey,$inout1,$inout1
++	vpxor		$Z1,$Z0,$Z0
++	movbe		0x18($in0),%r13
++	  vaesenc	$rndkey,$inout2,$inout2
++	movbe		0x10($in0),%r12
++	vpalignr	\$8,$Z0,$Z0,$Ii		# 1st phase
++	vpclmulqdq	\$0x10,$Hkey,$Z0,$Z0
++	mov		%r13,0x60+8(%rsp)
++	  vaesenc	$rndkey,$inout3,$inout3
++	mov		%r12,0x68+8(%rsp)
++	  vaesenc	$rndkey,$inout4,$inout4
++	  vmovups	0x80-0x80($key),$T1	# borrow $T1 for $rndkey
++	  vaesenc	$rndkey,$inout5,$inout5
++
++	  vaesenc	$T1,$inout0,$inout0
++	  vmovups	0x90-0x80($key),$rndkey
++	  vaesenc	$T1,$inout1,$inout1
++	vpsrldq		\$8,$Z2,$Z2
++	  vaesenc	$T1,$inout2,$inout2
++	vpxor		$Z2,$Z3,$Z3
++	  vaesenc	$T1,$inout3,$inout3
++	vpxor		$Ii,$Z0,$Z0
++	movbe		0x08($in0),%r13
++	  vaesenc	$T1,$inout4,$inout4
++	movbe		0x00($in0),%r12
++	  vaesenc	$T1,$inout5,$inout5
++	  vmovups	0xa0-0x80($key),$T1
++	  cmp		\$11,$rounds
++	  jb		.Lenc_tail		# 128-bit key
++
++	  vaesenc	$rndkey,$inout0,$inout0
++	  vaesenc	$rndkey,$inout1,$inout1
++	  vaesenc	$rndkey,$inout2,$inout2
++	  vaesenc	$rndkey,$inout3,$inout3
++	  vaesenc	$rndkey,$inout4,$inout4
++	  vaesenc	$rndkey,$inout5,$inout5
++
++	  vaesenc	$T1,$inout0,$inout0
++	  vaesenc	$T1,$inout1,$inout1
++	  vaesenc	$T1,$inout2,$inout2
++	  vaesenc	$T1,$inout3,$inout3
++	  vaesenc	$T1,$inout4,$inout4
++	  vmovups	0xb0-0x80($key),$rndkey
++	  vaesenc	$T1,$inout5,$inout5
++	  vmovups	0xc0-0x80($key),$T1
++	  je		.Lenc_tail		# 192-bit key
++
++	  vaesenc	$rndkey,$inout0,$inout0
++	  vaesenc	$rndkey,$inout1,$inout1
++	  vaesenc	$rndkey,$inout2,$inout2
++	  vaesenc	$rndkey,$inout3,$inout3
++	  vaesenc	$rndkey,$inout4,$inout4
++	  vaesenc	$rndkey,$inout5,$inout5
++
++	  vaesenc	$T1,$inout0,$inout0
++	  vaesenc	$T1,$inout1,$inout1
++	  vaesenc	$T1,$inout2,$inout2
++	  vaesenc	$T1,$inout3,$inout3
++	  vaesenc	$T1,$inout4,$inout4
++	  vmovups	0xd0-0x80($key),$rndkey
++	  vaesenc	$T1,$inout5,$inout5
++	  vmovups	0xe0-0x80($key),$T1
++	  jmp		.Lenc_tail		# 256-bit key
++
++.align	32
++.Lhandle_ctr32:
++	vmovdqu		($const),$Ii		# borrow $Ii for .Lbswap_mask
++	  vpshufb	$Ii,$T1,$Z2		# byte-swap counter
++	  vmovdqu	0x30($const),$Z1	# borrow $Z1, .Ltwo_lsb
++	  vpaddd	0x40($const),$Z2,$inout1	# .Lone_lsb
++	  vpaddd	$Z1,$Z2,$inout2
++	vmovdqu		0x00-0x20($Xip),$Hkey	# $Hkey^1
++	  vpaddd	$Z1,$inout1,$inout3
++	  vpshufb	$Ii,$inout1,$inout1
++	  vpaddd	$Z1,$inout2,$inout4
++	  vpshufb	$Ii,$inout2,$inout2
++	  vpxor		$rndkey,$inout1,$inout1
++	  vpaddd	$Z1,$inout3,$inout5
++	  vpshufb	$Ii,$inout3,$inout3
++	  vpxor		$rndkey,$inout2,$inout2
++	  vpaddd	$Z1,$inout4,$T1		# byte-swapped next counter value
++	  vpshufb	$Ii,$inout4,$inout4
++	  vpshufb	$Ii,$inout5,$inout5
++	  vpshufb	$Ii,$T1,$T1		# next counter value
++	jmp		.Lresume_ctr32
++
++.align	32
++.Lenc_tail:
++	  vaesenc	$rndkey,$inout0,$inout0
++	vmovdqu		$Z3,16+8(%rsp)		# postpone vpxor $Z3,$Xi,$Xi
++	vpalignr	\$8,$Z0,$Z0,$Xi		# 2nd phase
++	  vaesenc	$rndkey,$inout1,$inout1
++	vpclmulqdq	\$0x10,$Hkey,$Z0,$Z0
++	  vpxor		0x00($inp),$T1,$T2
++	  vaesenc	$rndkey,$inout2,$inout2
++	  vpxor		0x10($inp),$T1,$Ii
++	  vaesenc	$rndkey,$inout3,$inout3
++	  vpxor		0x20($inp),$T1,$Z1
++	  vaesenc	$rndkey,$inout4,$inout4
++	  vpxor		0x30($inp),$T1,$Z2
++	  vaesenc	$rndkey,$inout5,$inout5
++	  vpxor		0x40($inp),$T1,$Z3
++	  vpxor		0x50($inp),$T1,$Hkey
++	  vmovdqu	($ivp),$T1		# load next counter value
++
++	  vaesenclast	$T2,$inout0,$inout0
++	  vmovdqu	0x20($const),$T2	# borrow $T2, .Lone_msb
++	  vaesenclast	$Ii,$inout1,$inout1
++	 vpaddb		$T2,$T1,$Ii
++	mov		%r13,0x70+8(%rsp)
++	lea		0x60($inp),$inp
++	  vaesenclast	$Z1,$inout2,$inout2
++	 vpaddb		$T2,$Ii,$Z1
++	mov		%r12,0x78+8(%rsp)
++	lea		0x60($out),$out
++	  vmovdqu	0x00-0x80($key),$rndkey
++	  vaesenclast	$Z2,$inout3,$inout3
++	 vpaddb		$T2,$Z1,$Z2
++	  vaesenclast	$Z3, $inout4,$inout4
++	 vpaddb		$T2,$Z2,$Z3
++	  vaesenclast	$Hkey,$inout5,$inout5
++	 vpaddb		$T2,$Z3,$Hkey
++
++	add		\$0x60,$ret
++	sub		\$0x6,$len
++	jc		.L6x_done
++
++	  vmovups	$inout0,-0x60($out)	# save output
++	 vpxor		$rndkey,$T1,$inout0
++	  vmovups	$inout1,-0x50($out)
++	 vmovdqa	$Ii,$inout1		# 0 latency
++	  vmovups	$inout2,-0x40($out)
++	 vmovdqa	$Z1,$inout2		# 0 latency
++	  vmovups	$inout3,-0x30($out)
++	 vmovdqa	$Z2,$inout3		# 0 latency
++	  vmovups	$inout4,-0x20($out)
++	 vmovdqa	$Z3,$inout4		# 0 latency
++	  vmovups	$inout5,-0x10($out)
++	 vmovdqa	$Hkey,$inout5		# 0 latency
++	vmovdqu		0x20+8(%rsp),$Z3	# I[5]
++	jmp		.Loop6x
++
++.L6x_done:
++	vpxor		16+8(%rsp),$Xi,$Xi	# modulo-scheduled
++	vpxor		$Z0,$Xi,$Xi		# modulo-scheduled
++
++	ret
++.size	_aesni_ctr32_ghash_6x,.-_aesni_ctr32_ghash_6x
++___
++######################################################################
++#
++# size_t aesni_gcm_[en|de]crypt(const void *inp, void *out, size_t len,
++#		const AES_KEY *key, unsigned char iv[16],
++#		struct { u128 Xi,H,Htbl[9]; } *Xip);
++$code.=<<___;
++.globl	aesni_gcm_decrypt
++.type	aesni_gcm_decrypt,\@function,6
++.align	32
++aesni_gcm_decrypt:
++	xor	$ret,$ret
++
++	# We call |_aesni_ctr32_ghash_6x|, which requires at least 96 (0x60)
++	# bytes of input.
++	cmp	\$0x60,$len			# minimal accepted length
++	jb	.Lgcm_dec_abort
++
++	lea	(%rsp),%rax			# save stack pointer
++	push	%rbx
++	push	%rbp
++	push	%r12
++	push	%r13
++	push	%r14
++	push	%r15
++___
++$code.=<<___ if ($win64);
++	lea	-0xa8(%rsp),%rsp
++	movaps	%xmm6,-0xd8(%rax)
++	movaps	%xmm7,-0xc8(%rax)
++	movaps	%xmm8,-0xb8(%rax)
++	movaps	%xmm9,-0xa8(%rax)
++	movaps	%xmm10,-0x98(%rax)
++	movaps	%xmm11,-0x88(%rax)
++	movaps	%xmm12,-0x78(%rax)
++	movaps	%xmm13,-0x68(%rax)
++	movaps	%xmm14,-0x58(%rax)
++	movaps	%xmm15,-0x48(%rax)
++.Lgcm_dec_body:
++___
++$code.=<<___;
++	vzeroupper
++
++	vmovdqu		($ivp),$T1		# input counter value
++	add		\$-128,%rsp
++	mov		12($ivp),$counter
++	lea		.Lbswap_mask(%rip),$const
++	lea		-0x80($key),$in0	# borrow $in0
++	mov		\$0xf80,$end0		# borrow $end0
++	vmovdqu		($Xip),$Xi		# load Xi
++	and		\$-128,%rsp		# ensure stack alignment
++	vmovdqu		($const),$Ii		# borrow $Ii for .Lbswap_mask
++	lea		0x80($key),$key		# size optimization
++	lea		0x20+0x20($Xip),$Xip	# size optimization
++	mov		0xf0-0x80($key),$rounds
++	vpshufb		$Ii,$Xi,$Xi
++
++	and		$end0,$in0
++	and		%rsp,$end0
++	sub		$in0,$end0
++	jc		.Ldec_no_key_aliasing
++	cmp		\$768,$end0
++	jnc		.Ldec_no_key_aliasing
++	sub		$end0,%rsp		# avoid aliasing with key
++.Ldec_no_key_aliasing:
++
++	vmovdqu		0x50($inp),$Z3		# I[5]
++	lea		($inp),$in0
++	vmovdqu		0x40($inp),$Z0
++
++	# |_aesni_ctr32_ghash_6x| requires |$end0| to point to 2*96 (0xc0)
++	# bytes before the end of the input. Note, in particular, that this is
++	# correct even if |$len| is not an even multiple of 96 or 16. XXX: This
++	# seems to require that |$inp| + |$len| >= 2*96 (0xc0); i.e. |$inp| must
++	# not be near the very beginning of the address space when |$len| < 2*96
++	# (0xc0).
++	lea		-0xc0($inp,$len),$end0
++
++	vmovdqu		0x30($inp),$Z1
++	shr		\$4,$len
++	xor		$ret,$ret
++	vmovdqu		0x20($inp),$Z2
++	 vpshufb	$Ii,$Z3,$Z3		# passed to _aesni_ctr32_ghash_6x
++	vmovdqu		0x10($inp),$T2
++	 vpshufb	$Ii,$Z0,$Z0
++	vmovdqu		($inp),$Hkey
++	 vpshufb	$Ii,$Z1,$Z1
++	vmovdqu		$Z0,0x30(%rsp)
++	 vpshufb	$Ii,$Z2,$Z2
++	vmovdqu		$Z1,0x40(%rsp)
++	 vpshufb	$Ii,$T2,$T2
++	vmovdqu		$Z2,0x50(%rsp)
++	 vpshufb	$Ii,$Hkey,$Hkey
++	vmovdqu		$T2,0x60(%rsp)
++	vmovdqu		$Hkey,0x70(%rsp)
++
++	call		_aesni_ctr32_ghash_6x
++
++	vmovups		$inout0,-0x60($out)	# save output
++	vmovups		$inout1,-0x50($out)
++	vmovups		$inout2,-0x40($out)
++	vmovups		$inout3,-0x30($out)
++	vmovups		$inout4,-0x20($out)
++	vmovups		$inout5,-0x10($out)
++
++	vpshufb		($const),$Xi,$Xi	# .Lbswap_mask
++	vmovdqu		$Xi,-0x40($Xip)		# output Xi
++
++	vzeroupper
++___
++$code.=<<___ if ($win64);
++	movaps	-0xd8(%rax),%xmm6
++	movaps	-0xc8(%rax),%xmm7
++	movaps	-0xb8(%rax),%xmm8
++	movaps	-0xa8(%rax),%xmm9
++	movaps	-0x98(%rax),%xmm10
++	movaps	-0x88(%rax),%xmm11
++	movaps	-0x78(%rax),%xmm12
++	movaps	-0x68(%rax),%xmm13
++	movaps	-0x58(%rax),%xmm14
++	movaps	-0x48(%rax),%xmm15
++___
++$code.=<<___;
++	mov	-48(%rax),%r15
++	mov	-40(%rax),%r14
++	mov	-32(%rax),%r13
++	mov	-24(%rax),%r12
++	mov	-16(%rax),%rbp
++	mov	-8(%rax),%rbx
++	lea	(%rax),%rsp		# restore %rsp
++.Lgcm_dec_abort:
++	mov	$ret,%rax		# return value
++	ret
++.size	aesni_gcm_decrypt,.-aesni_gcm_decrypt
++___
++
++$code.=<<___;
++.type	_aesni_ctr32_6x,\@abi-omnipotent
++.align	32
++_aesni_ctr32_6x:
++	vmovdqu		0x00-0x80($key),$Z0	# borrow $Z0 for $rndkey
++	vmovdqu		0x20($const),$T2	# borrow $T2, .Lone_msb
++	lea		-1($rounds),%r13
++	vmovups		0x10-0x80($key),$rndkey
++	lea		0x20-0x80($key),%r12
++	vpxor		$Z0,$T1,$inout0
++	add		\$`6<<24`,$counter
++	jc		.Lhandle_ctr32_2
++	vpaddb		$T2,$T1,$inout1
++	vpaddb		$T2,$inout1,$inout2
++	vpxor		$Z0,$inout1,$inout1
++	vpaddb		$T2,$inout2,$inout3
++	vpxor		$Z0,$inout2,$inout2
++	vpaddb		$T2,$inout3,$inout4
++	vpxor		$Z0,$inout3,$inout3
++	vpaddb		$T2,$inout4,$inout5
++	vpxor		$Z0,$inout4,$inout4
++	vpaddb		$T2,$inout5,$T1
++	vpxor		$Z0,$inout5,$inout5
++	jmp		.Loop_ctr32
++
++.align	16
++.Loop_ctr32:
++	vaesenc		$rndkey,$inout0,$inout0
++	vaesenc		$rndkey,$inout1,$inout1
++	vaesenc		$rndkey,$inout2,$inout2
++	vaesenc		$rndkey,$inout3,$inout3
++	vaesenc		$rndkey,$inout4,$inout4
++	vaesenc		$rndkey,$inout5,$inout5
++	vmovups		(%r12),$rndkey
++	lea		0x10(%r12),%r12
++	dec		%r13d
++	jnz		.Loop_ctr32
++
++	vmovdqu		(%r12),$Hkey		# last round key
++	vaesenc		$rndkey,$inout0,$inout0
++	vpxor		0x00($inp),$Hkey,$Z0
++	vaesenc		$rndkey,$inout1,$inout1
++	vpxor		0x10($inp),$Hkey,$Z1
++	vaesenc		$rndkey,$inout2,$inout2
++	vpxor		0x20($inp),$Hkey,$Z2
++	vaesenc		$rndkey,$inout3,$inout3
++	vpxor		0x30($inp),$Hkey,$Xi
++	vaesenc		$rndkey,$inout4,$inout4
++	vpxor		0x40($inp),$Hkey,$T2
++	vaesenc		$rndkey,$inout5,$inout5
++	vpxor		0x50($inp),$Hkey,$Hkey
++	lea		0x60($inp),$inp
++
++	vaesenclast	$Z0,$inout0,$inout0
++	vaesenclast	$Z1,$inout1,$inout1
++	vaesenclast	$Z2,$inout2,$inout2
++	vaesenclast	$Xi,$inout3,$inout3
++	vaesenclast	$T2,$inout4,$inout4
++	vaesenclast	$Hkey,$inout5,$inout5
++	vmovups		$inout0,0x00($out)
++	vmovups		$inout1,0x10($out)
++	vmovups		$inout2,0x20($out)
++	vmovups		$inout3,0x30($out)
++	vmovups		$inout4,0x40($out)
++	vmovups		$inout5,0x50($out)
++	lea		0x60($out),$out
++
++	ret
++.align	32
++.Lhandle_ctr32_2:
++	vpshufb		$Ii,$T1,$Z2		# byte-swap counter
++	vmovdqu		0x30($const),$Z1	# borrow $Z1, .Ltwo_lsb
++	vpaddd		0x40($const),$Z2,$inout1	# .Lone_lsb
++	vpaddd		$Z1,$Z2,$inout2
++	vpaddd		$Z1,$inout1,$inout3
++	vpshufb		$Ii,$inout1,$inout1
++	vpaddd		$Z1,$inout2,$inout4
++	vpshufb		$Ii,$inout2,$inout2
++	vpxor		$Z0,$inout1,$inout1
++	vpaddd		$Z1,$inout3,$inout5
++	vpshufb		$Ii,$inout3,$inout3
++	vpxor		$Z0,$inout2,$inout2
++	vpaddd		$Z1,$inout4,$T1		# byte-swapped next counter value
++	vpshufb		$Ii,$inout4,$inout4
++	vpxor		$Z0,$inout3,$inout3
++	vpshufb		$Ii,$inout5,$inout5
++	vpxor		$Z0,$inout4,$inout4
++	vpshufb		$Ii,$T1,$T1		# next counter value
++	vpxor		$Z0,$inout5,$inout5
++	jmp	.Loop_ctr32
++.size	_aesni_ctr32_6x,.-_aesni_ctr32_6x
++
++.globl	aesni_gcm_encrypt
++.type	aesni_gcm_encrypt,\@function,6
++.align	32
++aesni_gcm_encrypt:
++	xor	$ret,$ret
++
++	# We call |_aesni_ctr32_6x| twice, each call consuming 96 bytes of
++	# input. Then we call |_aesni_ctr32_ghash_6x|, which requires at
++	# least 96 more bytes of input.
++	cmp	\$0x60*3,$len			# minimal accepted length
++	jb	.Lgcm_enc_abort
++
++	lea	(%rsp),%rax			# save stack pointer
++	push	%rbx
++	push	%rbp
++	push	%r12
++	push	%r13
++	push	%r14
++	push	%r15
++___
++$code.=<<___ if ($win64);
++	lea	-0xa8(%rsp),%rsp
++	movaps	%xmm6,-0xd8(%rax)
++	movaps	%xmm7,-0xc8(%rax)
++	movaps	%xmm8,-0xb8(%rax)
++	movaps	%xmm9,-0xa8(%rax)
++	movaps	%xmm10,-0x98(%rax)
++	movaps	%xmm11,-0x88(%rax)
++	movaps	%xmm12,-0x78(%rax)
++	movaps	%xmm13,-0x68(%rax)
++	movaps	%xmm14,-0x58(%rax)
++	movaps	%xmm15,-0x48(%rax)
++.Lgcm_enc_body:
++___
++$code.=<<___;
++	vzeroupper
++
++	vmovdqu		($ivp),$T1		# input counter value
++	add		\$-128,%rsp
++	mov		12($ivp),$counter
++	lea		.Lbswap_mask(%rip),$const
++	lea		-0x80($key),$in0	# borrow $in0
++	mov		\$0xf80,$end0		# borrow $end0
++	lea		0x80($key),$key		# size optimization
++	vmovdqu		($const),$Ii		# borrow $Ii for .Lbswap_mask
++	and		\$-128,%rsp		# ensure stack alignment
++	mov		0xf0-0x80($key),$rounds
++
++	and		$end0,$in0
++	and		%rsp,$end0
++	sub		$in0,$end0
++	jc		.Lenc_no_key_aliasing
++	cmp		\$768,$end0
++	jnc		.Lenc_no_key_aliasing
++	sub		$end0,%rsp		# avoid aliasing with key
++.Lenc_no_key_aliasing:
++
++	lea		($out),$in0
++
++	# |_aesni_ctr32_ghash_6x| requires |$end0| to point to 2*96 (0xc0)
++	# bytes before the end of the input. Note, in particular, that this is
++	# correct even if |$len| is not an even multiple of 96 or 16. Unlike in
++	# the decryption case, there's no caveat that |$out| must not be near
++	# the very beginning of the address space, because we know that
++	# |$len| >= 3*96 from the check above, and so we know
++	# |$out| + |$len| >= 2*96 (0xc0).
++	lea		-0xc0($out,$len),$end0
++
++	shr		\$4,$len
++
++	call		_aesni_ctr32_6x
++	vpshufb		$Ii,$inout0,$Xi		# save bswapped output on stack
++	vpshufb		$Ii,$inout1,$T2
++	vmovdqu		$Xi,0x70(%rsp)
++	vpshufb		$Ii,$inout2,$Z0
++	vmovdqu		$T2,0x60(%rsp)
++	vpshufb		$Ii,$inout3,$Z1
++	vmovdqu		$Z0,0x50(%rsp)
++	vpshufb		$Ii,$inout4,$Z2
++	vmovdqu		$Z1,0x40(%rsp)
++	vpshufb		$Ii,$inout5,$Z3		# passed to _aesni_ctr32_ghash_6x
++	vmovdqu		$Z2,0x30(%rsp)
++
++	call		_aesni_ctr32_6x
++
++	vmovdqu		($Xip),$Xi		# load Xi
++	lea		0x20+0x20($Xip),$Xip	# size optimization
++	sub		\$12,$len
++	mov		\$0x60*2,$ret
++	vpshufb		$Ii,$Xi,$Xi
++
++	call		_aesni_ctr32_ghash_6x
++	vmovdqu		0x20(%rsp),$Z3		# I[5]
++	 vmovdqu	($const),$Ii		# borrow $Ii for .Lbswap_mask
++	vmovdqu		0x00-0x20($Xip),$Hkey	# $Hkey^1
++	vpunpckhqdq	$Z3,$Z3,$T1
++	vmovdqu		0x20-0x20($Xip),$rndkey	# borrow $rndkey for $HK
++	 vmovups	$inout0,-0x60($out)	# save output
++	 vpshufb	$Ii,$inout0,$inout0	# but keep bswapped copy
++	vpxor		$Z3,$T1,$T1
++	 vmovups	$inout1,-0x50($out)
++	 vpshufb	$Ii,$inout1,$inout1
++	 vmovups	$inout2,-0x40($out)
++	 vpshufb	$Ii,$inout2,$inout2
++	 vmovups	$inout3,-0x30($out)
++	 vpshufb	$Ii,$inout3,$inout3
++	 vmovups	$inout4,-0x20($out)
++	 vpshufb	$Ii,$inout4,$inout4
++	 vmovups	$inout5,-0x10($out)
++	 vpshufb	$Ii,$inout5,$inout5
++	 vmovdqu	$inout0,0x10(%rsp)	# free $inout0
++___
++{ my ($HK,$T3)=($rndkey,$inout0);
++
++$code.=<<___;
++	 vmovdqu	0x30(%rsp),$Z2		# I[4]
++	 vmovdqu	0x10-0x20($Xip),$Ii	# borrow $Ii for $Hkey^2
++	 vpunpckhqdq	$Z2,$Z2,$T2
++	vpclmulqdq	\$0x00,$Hkey,$Z3,$Z1
++	 vpxor		$Z2,$T2,$T2
++	vpclmulqdq	\$0x11,$Hkey,$Z3,$Z3
++	vpclmulqdq	\$0x00,$HK,$T1,$T1
++
++	 vmovdqu	0x40(%rsp),$T3		# I[3]
++	vpclmulqdq	\$0x00,$Ii,$Z2,$Z0
++	 vmovdqu	0x30-0x20($Xip),$Hkey	# $Hkey^3
++	vpxor		$Z1,$Z0,$Z0
++	 vpunpckhqdq	$T3,$T3,$Z1
++	vpclmulqdq	\$0x11,$Ii,$Z2,$Z2
++	 vpxor		$T3,$Z1,$Z1
++	vpxor		$Z3,$Z2,$Z2
++	vpclmulqdq	\$0x10,$HK,$T2,$T2
++	 vmovdqu	0x50-0x20($Xip),$HK
++	vpxor		$T1,$T2,$T2
++
++	 vmovdqu	0x50(%rsp),$T1		# I[2]
++	vpclmulqdq	\$0x00,$Hkey,$T3,$Z3
++	 vmovdqu	0x40-0x20($Xip),$Ii	# borrow $Ii for $Hkey^4
++	vpxor		$Z0,$Z3,$Z3
++	 vpunpckhqdq	$T1,$T1,$Z0
++	vpclmulqdq	\$0x11,$Hkey,$T3,$T3
++	 vpxor		$T1,$Z0,$Z0
++	vpxor		$Z2,$T3,$T3
++	vpclmulqdq	\$0x00,$HK,$Z1,$Z1
++	vpxor		$T2,$Z1,$Z1
++
++	 vmovdqu	0x60(%rsp),$T2		# I[1]
++	vpclmulqdq	\$0x00,$Ii,$T1,$Z2
++	 vmovdqu	0x60-0x20($Xip),$Hkey	# $Hkey^5
++	vpxor		$Z3,$Z2,$Z2
++	 vpunpckhqdq	$T2,$T2,$Z3
++	vpclmulqdq	\$0x11,$Ii,$T1,$T1
++	 vpxor		$T2,$Z3,$Z3
++	vpxor		$T3,$T1,$T1
++	vpclmulqdq	\$0x10,$HK,$Z0,$Z0
++	 vmovdqu	0x80-0x20($Xip),$HK
++	vpxor		$Z1,$Z0,$Z0
++
++	 vpxor		0x70(%rsp),$Xi,$Xi	# accumulate I[0]
++	vpclmulqdq	\$0x00,$Hkey,$T2,$Z1
++	 vmovdqu	0x70-0x20($Xip),$Ii	# borrow $Ii for $Hkey^6
++	 vpunpckhqdq	$Xi,$Xi,$T3
++	vpxor		$Z2,$Z1,$Z1
++	vpclmulqdq	\$0x11,$Hkey,$T2,$T2
++	 vpxor		$Xi,$T3,$T3
++	vpxor		$T1,$T2,$T2
++	vpclmulqdq	\$0x00,$HK,$Z3,$Z3
++	vpxor		$Z0,$Z3,$Z0
++
++	vpclmulqdq	\$0x00,$Ii,$Xi,$Z2
++	 vmovdqu	0x00-0x20($Xip),$Hkey	# $Hkey^1
++	 vpunpckhqdq	$inout5,$inout5,$T1
++	vpclmulqdq	\$0x11,$Ii,$Xi,$Xi
++	 vpxor		$inout5,$T1,$T1
++	vpxor		$Z1,$Z2,$Z1
++	vpclmulqdq	\$0x10,$HK,$T3,$T3
++	 vmovdqu	0x20-0x20($Xip),$HK
++	vpxor		$T2,$Xi,$Z3
++	vpxor		$Z0,$T3,$Z2
++
++	 vmovdqu	0x10-0x20($Xip),$Ii	# borrow $Ii for $Hkey^2
++	  vpxor		$Z1,$Z3,$T3		# aggregated Karatsuba post-processing
++	vpclmulqdq	\$0x00,$Hkey,$inout5,$Z0
++	  vpxor		$T3,$Z2,$Z2
++	 vpunpckhqdq	$inout4,$inout4,$T2
++	vpclmulqdq	\$0x11,$Hkey,$inout5,$inout5
++	 vpxor		$inout4,$T2,$T2
++	  vpslldq	\$8,$Z2,$T3
++	vpclmulqdq	\$0x00,$HK,$T1,$T1
++	  vpxor		$T3,$Z1,$Xi
++	  vpsrldq	\$8,$Z2,$Z2
++	  vpxor		$Z2,$Z3,$Z3
++
++	vpclmulqdq	\$0x00,$Ii,$inout4,$Z1
++	 vmovdqu	0x30-0x20($Xip),$Hkey	# $Hkey^3
++	vpxor		$Z0,$Z1,$Z1
++	 vpunpckhqdq	$inout3,$inout3,$T3
++	vpclmulqdq	\$0x11,$Ii,$inout4,$inout4
++	 vpxor		$inout3,$T3,$T3
++	vpxor		$inout5,$inout4,$inout4
++	  vpalignr	\$8,$Xi,$Xi,$inout5	# 1st phase
++	vpclmulqdq	\$0x10,$HK,$T2,$T2
++	 vmovdqu	0x50-0x20($Xip),$HK
++	vpxor		$T1,$T2,$T2
++
++	vpclmulqdq	\$0x00,$Hkey,$inout3,$Z0
++	 vmovdqu	0x40-0x20($Xip),$Ii	# borrow $Ii for $Hkey^4
++	vpxor		$Z1,$Z0,$Z0
++	 vpunpckhqdq	$inout2,$inout2,$T1
++	vpclmulqdq	\$0x11,$Hkey,$inout3,$inout3
++	 vpxor		$inout2,$T1,$T1
++	vpxor		$inout4,$inout3,$inout3
++	  vxorps	0x10(%rsp),$Z3,$Z3	# accumulate $inout0
++	vpclmulqdq	\$0x00,$HK,$T3,$T3
++	vpxor		$T2,$T3,$T3
++
++	  vpclmulqdq	\$0x10,0x10($const),$Xi,$Xi
++	  vxorps	$inout5,$Xi,$Xi
++
++	vpclmulqdq	\$0x00,$Ii,$inout2,$Z1
++	 vmovdqu	0x60-0x20($Xip),$Hkey	# $Hkey^5
++	vpxor		$Z0,$Z1,$Z1
++	 vpunpckhqdq	$inout1,$inout1,$T2
++	vpclmulqdq	\$0x11,$Ii,$inout2,$inout2
++	 vpxor		$inout1,$T2,$T2
++	  vpalignr	\$8,$Xi,$Xi,$inout5	# 2nd phase
++	vpxor		$inout3,$inout2,$inout2
++	vpclmulqdq	\$0x10,$HK,$T1,$T1
++	 vmovdqu	0x80-0x20($Xip),$HK
++	vpxor		$T3,$T1,$T1
++
++	  vxorps	$Z3,$inout5,$inout5
++	  vpclmulqdq	\$0x10,0x10($const),$Xi,$Xi
++	  vxorps	$inout5,$Xi,$Xi
++
++	vpclmulqdq	\$0x00,$Hkey,$inout1,$Z0
++	 vmovdqu	0x70-0x20($Xip),$Ii	# borrow $Ii for $Hkey^6
++	vpxor		$Z1,$Z0,$Z0
++	 vpunpckhqdq	$Xi,$Xi,$T3
++	vpclmulqdq	\$0x11,$Hkey,$inout1,$inout1
++	 vpxor		$Xi,$T3,$T3
++	vpxor		$inout2,$inout1,$inout1
++	vpclmulqdq	\$0x00,$HK,$T2,$T2
++	vpxor		$T1,$T2,$T2
++
++	vpclmulqdq	\$0x00,$Ii,$Xi,$Z1
++	vpclmulqdq	\$0x11,$Ii,$Xi,$Z3
++	vpxor		$Z0,$Z1,$Z1
++	vpclmulqdq	\$0x10,$HK,$T3,$Z2
++	vpxor		$inout1,$Z3,$Z3
++	vpxor		$T2,$Z2,$Z2
++
++	vpxor		$Z1,$Z3,$Z0		# aggregated Karatsuba post-processing
++	vpxor		$Z0,$Z2,$Z2
++	vpslldq		\$8,$Z2,$T1
++	vmovdqu		0x10($const),$Hkey	# .Lpoly
++	vpsrldq		\$8,$Z2,$Z2
++	vpxor		$T1,$Z1,$Xi
++	vpxor		$Z2,$Z3,$Z3
++
++	vpalignr	\$8,$Xi,$Xi,$T2		# 1st phase
++	vpclmulqdq	\$0x10,$Hkey,$Xi,$Xi
++	vpxor		$T2,$Xi,$Xi
++
++	vpalignr	\$8,$Xi,$Xi,$T2		# 2nd phase
++	vpclmulqdq	\$0x10,$Hkey,$Xi,$Xi
++	vpxor		$Z3,$T2,$T2
++	vpxor		$T2,$Xi,$Xi
++___
++}
++$code.=<<___;
++	vpshufb		($const),$Xi,$Xi	# .Lbswap_mask
++	vmovdqu		$Xi,-0x40($Xip)		# output Xi
++
++	vzeroupper
++___
++$code.=<<___ if ($win64);
++	movaps	-0xd8(%rax),%xmm6
++	movaps	-0xc8(%rax),%xmm7
++	movaps	-0xb8(%rax),%xmm8
++	movaps	-0xa8(%rax),%xmm9
++	movaps	-0x98(%rax),%xmm10
++	movaps	-0x88(%rax),%xmm11
++	movaps	-0x78(%rax),%xmm12
++	movaps	-0x68(%rax),%xmm13
++	movaps	-0x58(%rax),%xmm14
++	movaps	-0x48(%rax),%xmm15
++___
++$code.=<<___;
++	mov	-48(%rax),%r15
++	mov	-40(%rax),%r14
++	mov	-32(%rax),%r13
++	mov	-24(%rax),%r12
++	mov	-16(%rax),%rbp
++	mov	-8(%rax),%rbx
++	lea	(%rax),%rsp		# restore %rsp
++.Lgcm_enc_abort:
++	mov	$ret,%rax		# return value
++	ret
++.size	aesni_gcm_encrypt,.-aesni_gcm_encrypt
++___
++
++$code.=<<___;
++.align	64
++.Lbswap_mask:
++	.byte	15,14,13,12,11,10,9,8,7,6,5,4,3,2,1,0
++.Lpoly:
++	.byte	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0xc2
++.Lone_msb:
++	.byte	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1
++.Ltwo_lsb:
++	.byte	2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
++.Lone_lsb:
++	.byte	1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
++.asciz	"AES-NI GCM module for x86_64, CRYPTOGAMS by "
++.align	64
++___
++if ($win64) {
++$rec="%rcx";
++$frame="%rdx";
++$context="%r8";
++$disp="%r9";
++
++$code.=<<___
++.extern	__imp_RtlVirtualUnwind
++.type	gcm_se_handler,\@abi-omnipotent
++.align	16
++gcm_se_handler:
++	push	%rsi
++	push	%rdi
++	push	%rbx
++	push	%rbp
++	push	%r12
++	push	%r13
++	push	%r14
++	push	%r15
++	pushfq
++	sub	\$64,%rsp
++
++	mov	120($context),%rax	# pull context->Rax
++	mov	248($context),%rbx	# pull context->Rip
++
++	mov	8($disp),%rsi		# disp->ImageBase
++	mov	56($disp),%r11		# disp->HandlerData
++
++	mov	0(%r11),%r10d		# HandlerData[0]
++	lea	(%rsi,%r10),%r10	# prologue label
++	cmp	%r10,%rbx		# context->RipRsp
++
++	mov	4(%r11),%r10d		# HandlerData[1]
++	lea	(%rsi,%r10),%r10	# epilogue label
++	cmp	%r10,%rbx		# context->Rip>=epilogue label
++	jae	.Lcommon_seh_tail
++
++	mov	120($context),%rax	# pull context->Rax
++
++	mov	-48(%rax),%r15
++	mov	-40(%rax),%r14
++	mov	-32(%rax),%r13
++	mov	-24(%rax),%r12
++	mov	-16(%rax),%rbp
++	mov	-8(%rax),%rbx
++	mov	%r15,240($context)
++	mov	%r14,232($context)
++	mov	%r13,224($context)
++	mov	%r12,216($context)
++	mov	%rbp,160($context)
++	mov	%rbx,144($context)
++
++	lea	-0xd8(%rax),%rsi	# %xmm save area
++	lea	512($context),%rdi	# & context.Xmm6
++	mov	\$20,%ecx		# 10*sizeof(%xmm0)/sizeof(%rax)
++	.long	0xa548f3fc		# cld; rep movsq
++
++.Lcommon_seh_tail:
++	mov	8(%rax),%rdi
++	mov	16(%rax),%rsi
++	mov	%rax,152($context)	# restore context->Rsp
++	mov	%rsi,168($context)	# restore context->Rsi
++	mov	%rdi,176($context)	# restore context->Rdi
++
++	mov	40($disp),%rdi		# disp->ContextRecord
++	mov	$context,%rsi		# context
++	mov	\$154,%ecx		# sizeof(CONTEXT)
++	.long	0xa548f3fc		# cld; rep movsq
++
++	mov	$disp,%rsi
++	xor	%rcx,%rcx		# arg1, UNW_FLAG_NHANDLER
++	mov	8(%rsi),%rdx		# arg2, disp->ImageBase
++	mov	0(%rsi),%r8		# arg3, disp->ControlPc
++	mov	16(%rsi),%r9		# arg4, disp->FunctionEntry
++	mov	40(%rsi),%r10		# disp->ContextRecord
++	lea	56(%rsi),%r11		# &disp->HandlerData
++	lea	24(%rsi),%r12		# &disp->EstablisherFrame
++	mov	%r10,32(%rsp)		# arg5
++	mov	%r11,40(%rsp)		# arg6
++	mov	%r12,48(%rsp)		# arg7
++	mov	%rcx,56(%rsp)		# arg8, (NULL)
++	call	*__imp_RtlVirtualUnwind(%rip)
++
++	mov	\$1,%eax		# ExceptionContinueSearch
++	add	\$64,%rsp
++	popfq
++	pop	%r15
++	pop	%r14
++	pop	%r13
++	pop	%r12
++	pop	%rbp
++	pop	%rbx
++	pop	%rdi
++	pop	%rsi
++	ret
++.size	gcm_se_handler,.-gcm_se_handler
++
++.section	.pdata
++.align	4
++	.rva	.LSEH_begin_aesni_gcm_decrypt
++	.rva	.LSEH_end_aesni_gcm_decrypt
++	.rva	.LSEH_gcm_dec_info
++
++	.rva	.LSEH_begin_aesni_gcm_encrypt
++	.rva	.LSEH_end_aesni_gcm_encrypt
++	.rva	.LSEH_gcm_enc_info
++.section	.xdata
++.align	8
++.LSEH_gcm_dec_info:
++	.byte	9,0,0,0
++	.rva	gcm_se_handler
++	.rva	.Lgcm_dec_body,.Lgcm_dec_abort
++.LSEH_gcm_enc_info:
++	.byte	9,0,0,0
++	.rva	gcm_se_handler
++	.rva	.Lgcm_enc_body,.Lgcm_enc_abort
++___
++}
++}}} else {{{
++$code=<<___;	# assembler is too old
++.text
++
++.globl	aesni_gcm_encrypt
++.type	aesni_gcm_encrypt,\@abi-omnipotent
++aesni_gcm_encrypt:
++	xor	%eax,%eax
++	ret
++.size	aesni_gcm_encrypt,.-aesni_gcm_encrypt
++
++.globl	aesni_gcm_decrypt
++.type	aesni_gcm_decrypt,\@abi-omnipotent
++aesni_gcm_decrypt:
++	xor	%eax,%eax
++	ret
++.size	aesni_gcm_decrypt,.-aesni_gcm_decrypt
++___
++}}}
++
++$code =~ s/\`([^\`]*)\`/eval($1)/gem;
++
++print $code;
++
++close STDOUT;
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/modes/asm/ghash-alpha.pl b/CryptoPkg/Library/OpensslLib/openssl/crypto/modes/asm/ghash-alpha.pl
+new file mode 100644
+index 0000000..ccf6b2b
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/modes/asm/ghash-alpha.pl
+@@ -0,0 +1,467 @@
++#! /usr/bin/env perl
++# Copyright 2010-2016 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
++# in the file LICENSE in the source distribution or at
++# https://www.openssl.org/source/license.html
++
++#
++# ====================================================================
++# Written by Andy Polyakov  for the OpenSSL
++# project. The module is, however, dual licensed under OpenSSL and
++# CRYPTOGAMS licenses depending on where you obtain it. For further
++# details see http://www.openssl.org/~appro/cryptogams/.
++# ====================================================================
++#
++# March 2010
++#
++# The module implements "4-bit" GCM GHASH function and underlying
++# single multiplication operation in GF(2^128). "4-bit" means that it
++# uses 256 bytes per-key table [+128 bytes shared table]. Even though
++# loops are aggressively modulo-scheduled in respect to references to
++# Htbl and Z.hi updates for 8 cycles per byte, measured performance is
++# ~12 cycles per processed byte on 21264 CPU. It seems to be a dynamic
++# scheduling "glitch," because uprofile(1) indicates uniform sample
++# distribution, as if all instruction bundles execute in 1.5 cycles.
++# Meaning that it could have been even faster, yet 12 cycles is ~60%
++# better than gcc-generated code and ~80% than code generated by vendor
++# compiler.
++
++$cnt="v0";	# $0
++$t0="t0";
++$t1="t1";
++$t2="t2";
++$Thi0="t3";	# $4
++$Tlo0="t4";
++$Thi1="t5";
++$Tlo1="t6";
++$rem="t7";	# $8
++#################
++$Xi="a0";	# $16, input argument block
++$Htbl="a1";
++$inp="a2";
++$len="a3";
++$nlo="a4";	# $20
++$nhi="a5";
++$Zhi="t8";
++$Zlo="t9";
++$Xhi="t10";	# $24
++$Xlo="t11";
++$remp="t12";
++$rem_4bit="AT";	# $28
++
++{ my $N;
++  sub loop() {
++
++	$N++;
++$code.=<<___;
++.align	4
++	extbl	$Xlo,7,$nlo
++	and	$nlo,0xf0,$nhi
++	sll	$nlo,4,$nlo
++	and	$nlo,0xf0,$nlo
++
++	addq	$nlo,$Htbl,$nlo
++	ldq	$Zlo,8($nlo)
++	addq	$nhi,$Htbl,$nhi
++	ldq	$Zhi,0($nlo)
++
++	and	$Zlo,0x0f,$remp
++	sll	$Zhi,60,$t0
++	lda	$cnt,6(zero)
++	extbl	$Xlo,6,$nlo
++
++	ldq	$Tlo1,8($nhi)
++	s8addq	$remp,$rem_4bit,$remp
++	ldq	$Thi1,0($nhi)
++	srl	$Zlo,4,$Zlo
++
++	ldq	$rem,0($remp)
++	srl	$Zhi,4,$Zhi
++	xor	$t0,$Zlo,$Zlo
++	and	$nlo,0xf0,$nhi
++
++	xor	$Tlo1,$Zlo,$Zlo
++	sll	$nlo,4,$nlo
++	xor	$Thi1,$Zhi,$Zhi
++	and	$nlo,0xf0,$nlo
++
++	addq	$nlo,$Htbl,$nlo
++	ldq	$Tlo0,8($nlo)
++	addq	$nhi,$Htbl,$nhi
++	ldq	$Thi0,0($nlo)
++
++.Looplo$N:
++	and	$Zlo,0x0f,$remp
++	sll	$Zhi,60,$t0
++	subq	$cnt,1,$cnt
++	srl	$Zlo,4,$Zlo
++
++	ldq	$Tlo1,8($nhi)
++	xor	$rem,$Zhi,$Zhi
++	ldq	$Thi1,0($nhi)
++	s8addq	$remp,$rem_4bit,$remp
++
++	ldq	$rem,0($remp)
++	srl	$Zhi,4,$Zhi
++	xor	$t0,$Zlo,$Zlo
++	extbl	$Xlo,$cnt,$nlo
++
++	and	$nlo,0xf0,$nhi
++	xor	$Thi0,$Zhi,$Zhi
++	xor	$Tlo0,$Zlo,$Zlo
++	sll	$nlo,4,$nlo
++
++
++	and	$Zlo,0x0f,$remp
++	sll	$Zhi,60,$t0
++	and	$nlo,0xf0,$nlo
++	srl	$Zlo,4,$Zlo
++
++	s8addq	$remp,$rem_4bit,$remp
++	xor	$rem,$Zhi,$Zhi
++	addq	$nlo,$Htbl,$nlo
++	addq	$nhi,$Htbl,$nhi
++
++	ldq	$rem,0($remp)
++	srl	$Zhi,4,$Zhi
++	ldq	$Tlo0,8($nlo)
++	xor	$t0,$Zlo,$Zlo
++
++	xor	$Tlo1,$Zlo,$Zlo
++	xor	$Thi1,$Zhi,$Zhi
++	ldq	$Thi0,0($nlo)
++	bne	$cnt,.Looplo$N
++
++
++	and	$Zlo,0x0f,$remp
++	sll	$Zhi,60,$t0
++	lda	$cnt,7(zero)
++	srl	$Zlo,4,$Zlo
++
++	ldq	$Tlo1,8($nhi)
++	xor	$rem,$Zhi,$Zhi
++	ldq	$Thi1,0($nhi)
++	s8addq	$remp,$rem_4bit,$remp
++
++	ldq	$rem,0($remp)
++	srl	$Zhi,4,$Zhi
++	xor	$t0,$Zlo,$Zlo
++	extbl	$Xhi,$cnt,$nlo
++
++	and	$nlo,0xf0,$nhi
++	xor	$Thi0,$Zhi,$Zhi
++	xor	$Tlo0,$Zlo,$Zlo
++	sll	$nlo,4,$nlo
++
++	and	$Zlo,0x0f,$remp
++	sll	$Zhi,60,$t0
++	and	$nlo,0xf0,$nlo
++	srl	$Zlo,4,$Zlo
++
++	s8addq	$remp,$rem_4bit,$remp
++	xor	$rem,$Zhi,$Zhi
++	addq	$nlo,$Htbl,$nlo
++	addq	$nhi,$Htbl,$nhi
++
++	ldq	$rem,0($remp)
++	srl	$Zhi,4,$Zhi
++	ldq	$Tlo0,8($nlo)
++	xor	$t0,$Zlo,$Zlo
++
++	xor	$Tlo1,$Zlo,$Zlo
++	xor	$Thi1,$Zhi,$Zhi
++	ldq	$Thi0,0($nlo)
++	unop
++
++
++.Loophi$N:
++	and	$Zlo,0x0f,$remp
++	sll	$Zhi,60,$t0
++	subq	$cnt,1,$cnt
++	srl	$Zlo,4,$Zlo
++
++	ldq	$Tlo1,8($nhi)
++	xor	$rem,$Zhi,$Zhi
++	ldq	$Thi1,0($nhi)
++	s8addq	$remp,$rem_4bit,$remp
++
++	ldq	$rem,0($remp)
++	srl	$Zhi,4,$Zhi
++	xor	$t0,$Zlo,$Zlo
++	extbl	$Xhi,$cnt,$nlo
++
++	and	$nlo,0xf0,$nhi
++	xor	$Thi0,$Zhi,$Zhi
++	xor	$Tlo0,$Zlo,$Zlo
++	sll	$nlo,4,$nlo
++
++
++	and	$Zlo,0x0f,$remp
++	sll	$Zhi,60,$t0
++	and	$nlo,0xf0,$nlo
++	srl	$Zlo,4,$Zlo
++
++	s8addq	$remp,$rem_4bit,$remp
++	xor	$rem,$Zhi,$Zhi
++	addq	$nlo,$Htbl,$nlo
++	addq	$nhi,$Htbl,$nhi
++
++	ldq	$rem,0($remp)
++	srl	$Zhi,4,$Zhi
++	ldq	$Tlo0,8($nlo)
++	xor	$t0,$Zlo,$Zlo
++
++	xor	$Tlo1,$Zlo,$Zlo
++	xor	$Thi1,$Zhi,$Zhi
++	ldq	$Thi0,0($nlo)
++	bne	$cnt,.Loophi$N
++
++
++	and	$Zlo,0x0f,$remp
++	sll	$Zhi,60,$t0
++	srl	$Zlo,4,$Zlo
++
++	ldq	$Tlo1,8($nhi)
++	xor	$rem,$Zhi,$Zhi
++	ldq	$Thi1,0($nhi)
++	s8addq	$remp,$rem_4bit,$remp
++
++	ldq	$rem,0($remp)
++	srl	$Zhi,4,$Zhi
++	xor	$t0,$Zlo,$Zlo
++
++	xor	$Tlo0,$Zlo,$Zlo
++	xor	$Thi0,$Zhi,$Zhi
++
++	and	$Zlo,0x0f,$remp
++	sll	$Zhi,60,$t0
++	srl	$Zlo,4,$Zlo
++
++	s8addq	$remp,$rem_4bit,$remp
++	xor	$rem,$Zhi,$Zhi
++
++	ldq	$rem,0($remp)
++	srl	$Zhi,4,$Zhi
++	xor	$Tlo1,$Zlo,$Zlo
++	xor	$Thi1,$Zhi,$Zhi
++	xor	$t0,$Zlo,$Zlo
++	xor	$rem,$Zhi,$Zhi
++___
++}}
++
++$code=<<___;
++#ifdef __linux__
++#include 
++#else
++#include 
++#include 
++#endif
++
++.text
++
++.set	noat
++.set	noreorder
++.globl	gcm_gmult_4bit
++.align	4
++.ent	gcm_gmult_4bit
++gcm_gmult_4bit:
++	.frame	sp,0,ra
++	.prologue 0
++
++	ldq	$Xlo,8($Xi)
++	ldq	$Xhi,0($Xi)
++
++	bsr	$t0,picmeup
++	nop
++___
++
++	&loop();
++
++$code.=<<___;
++	srl	$Zlo,24,$t0	# byte swap
++	srl	$Zlo,8,$t1
++
++	sll	$Zlo,8,$t2
++	sll	$Zlo,24,$Zlo
++	zapnot	$t0,0x11,$t0
++	zapnot	$t1,0x22,$t1
++
++	zapnot	$Zlo,0x88,$Zlo
++	or	$t0,$t1,$t0
++	zapnot	$t2,0x44,$t2
++
++	or	$Zlo,$t0,$Zlo
++	srl	$Zhi,24,$t0
++	srl	$Zhi,8,$t1
++
++	or	$Zlo,$t2,$Zlo
++	sll	$Zhi,8,$t2
++	sll	$Zhi,24,$Zhi
++
++	srl	$Zlo,32,$Xlo
++	sll	$Zlo,32,$Zlo
++
++	zapnot	$t0,0x11,$t0
++	zapnot	$t1,0x22,$t1
++	or	$Zlo,$Xlo,$Xlo
++
++	zapnot	$Zhi,0x88,$Zhi
++	or	$t0,$t1,$t0
++	zapnot	$t2,0x44,$t2
++
++	or	$Zhi,$t0,$Zhi
++	or	$Zhi,$t2,$Zhi
++
++	srl	$Zhi,32,$Xhi
++	sll	$Zhi,32,$Zhi
++
++	or	$Zhi,$Xhi,$Xhi
++	stq	$Xlo,8($Xi)
++	stq	$Xhi,0($Xi)
++
++	ret	(ra)
++.end	gcm_gmult_4bit
++___
++
++$inhi="s0";
++$inlo="s1";
++
++$code.=<<___;
++.globl	gcm_ghash_4bit
++.align	4
++.ent	gcm_ghash_4bit
++gcm_ghash_4bit:
++	lda	sp,-32(sp)
++	stq	ra,0(sp)
++	stq	s0,8(sp)
++	stq	s1,16(sp)
++	.mask	0x04000600,-32
++	.frame	sp,32,ra
++	.prologue 0
++
++	ldq_u	$inhi,0($inp)
++	ldq_u	$Thi0,7($inp)
++	ldq_u	$inlo,8($inp)
++	ldq_u	$Tlo0,15($inp)
++	ldq	$Xhi,0($Xi)
++	ldq	$Xlo,8($Xi)
++
++	bsr	$t0,picmeup
++	nop
++
++.Louter:
++	extql	$inhi,$inp,$inhi
++	extqh	$Thi0,$inp,$Thi0
++	or	$inhi,$Thi0,$inhi
++	lda	$inp,16($inp)
++
++	extql	$inlo,$inp,$inlo
++	extqh	$Tlo0,$inp,$Tlo0
++	or	$inlo,$Tlo0,$inlo
++	subq	$len,16,$len
++
++	xor	$Xlo,$inlo,$Xlo
++	xor	$Xhi,$inhi,$Xhi
++___
++
++	&loop();
++
++$code.=<<___;
++	srl	$Zlo,24,$t0	# byte swap
++	srl	$Zlo,8,$t1
++
++	sll	$Zlo,8,$t2
++	sll	$Zlo,24,$Zlo
++	zapnot	$t0,0x11,$t0
++	zapnot	$t1,0x22,$t1
++
++	zapnot	$Zlo,0x88,$Zlo
++	or	$t0,$t1,$t0
++	zapnot	$t2,0x44,$t2
++
++	or	$Zlo,$t0,$Zlo
++	srl	$Zhi,24,$t0
++	srl	$Zhi,8,$t1
++
++	or	$Zlo,$t2,$Zlo
++	sll	$Zhi,8,$t2
++	sll	$Zhi,24,$Zhi
++
++	srl	$Zlo,32,$Xlo
++	sll	$Zlo,32,$Zlo
++	beq	$len,.Ldone
++
++	zapnot	$t0,0x11,$t0
++	zapnot	$t1,0x22,$t1
++	or	$Zlo,$Xlo,$Xlo
++	ldq_u	$inhi,0($inp)
++
++	zapnot	$Zhi,0x88,$Zhi
++	or	$t0,$t1,$t0
++	zapnot	$t2,0x44,$t2
++	ldq_u	$Thi0,7($inp)
++
++	or	$Zhi,$t0,$Zhi
++	or	$Zhi,$t2,$Zhi
++	ldq_u	$inlo,8($inp)
++	ldq_u	$Tlo0,15($inp)
++
++	srl	$Zhi,32,$Xhi
++	sll	$Zhi,32,$Zhi
++
++	or	$Zhi,$Xhi,$Xhi
++	br	zero,.Louter
++
++.Ldone:
++	zapnot	$t0,0x11,$t0
++	zapnot	$t1,0x22,$t1
++	or	$Zlo,$Xlo,$Xlo
++
++	zapnot	$Zhi,0x88,$Zhi
++	or	$t0,$t1,$t0
++	zapnot	$t2,0x44,$t2
++
++	or	$Zhi,$t0,$Zhi
++	or	$Zhi,$t2,$Zhi
++
++	srl	$Zhi,32,$Xhi
++	sll	$Zhi,32,$Zhi
++
++	or	$Zhi,$Xhi,$Xhi
++
++	stq	$Xlo,8($Xi)
++	stq	$Xhi,0($Xi)
++
++	.set	noreorder
++	/*ldq	ra,0(sp)*/
++	ldq	s0,8(sp)
++	ldq	s1,16(sp)
++	lda	sp,32(sp)
++	ret	(ra)
++.end	gcm_ghash_4bit
++
++.align	4
++.ent	picmeup
++picmeup:
++	.frame	sp,0,$t0
++	.prologue 0
++	br	$rem_4bit,.Lpic
++.Lpic:	lda	$rem_4bit,12($rem_4bit)
++	ret	($t0)
++.end	picmeup
++	nop
++rem_4bit:
++	.long	0,0x0000<<16, 0,0x1C20<<16, 0,0x3840<<16, 0,0x2460<<16
++	.long	0,0x7080<<16, 0,0x6CA0<<16, 0,0x48C0<<16, 0,0x54E0<<16
++	.long	0,0xE100<<16, 0,0xFD20<<16, 0,0xD940<<16, 0,0xC560<<16
++	.long	0,0x9180<<16, 0,0x8DA0<<16, 0,0xA9C0<<16, 0,0xB5E0<<16
++.ascii	"GHASH for Alpha, CRYPTOGAMS by "
++.align	4
++
++___
++$output=pop and open STDOUT,">$output";
++print $code;
++close STDOUT;
++
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/modes/asm/ghash-armv4.pl b/CryptoPkg/Library/OpensslLib/openssl/crypto/modes/asm/ghash-armv4.pl
+new file mode 100644
+index 0000000..7d880c9
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/modes/asm/ghash-armv4.pl
+@@ -0,0 +1,554 @@
++#! /usr/bin/env perl
++# Copyright 2010-2016 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
++# in the file LICENSE in the source distribution or at
++# https://www.openssl.org/source/license.html
++
++#
++# ====================================================================
++# Written by Andy Polyakov  for the OpenSSL
++# project. The module is, however, dual licensed under OpenSSL and
++# CRYPTOGAMS licenses depending on where you obtain it. For further
++# details see http://www.openssl.org/~appro/cryptogams/.
++# ====================================================================
++#
++# April 2010
++#
++# The module implements "4-bit" GCM GHASH function and underlying
++# single multiplication operation in GF(2^128). "4-bit" means that it
++# uses 256 bytes per-key table [+32 bytes shared table]. There is no
++# experimental performance data available yet. The only approximation
++# that can be made at this point is based on code size. Inner loop is
++# 32 instructions long and on single-issue core should execute in <40
++# cycles. Having verified that gcc 3.4 didn't unroll corresponding
++# loop, this assembler loop body was found to be ~3x smaller than
++# compiler-generated one...
++#
++# July 2010
++#
++# Rescheduling for dual-issue pipeline resulted in 8.5% improvement on
++# Cortex A8 core and ~25 cycles per processed byte (which was observed
++# to be ~3 times faster than gcc-generated code:-)
++#
++# February 2011
++#
++# Profiler-assisted and platform-specific optimization resulted in 7%
++# improvement on Cortex A8 core and ~23.5 cycles per byte.
++#
++# March 2011
++#
++# Add NEON implementation featuring polynomial multiplication, i.e. no
++# lookup tables involved. On Cortex A8 it was measured to process one
++# byte in 15 cycles or 55% faster than integer-only code.
++#
++# April 2014
++#
++# Switch to multiplication algorithm suggested in paper referred
++# below and combine it with reduction algorithm from x86 module.
++# Performance improvement over previous version varies from 65% on
++# Snapdragon S4 to 110% on Cortex A9. In absolute terms Cortex A8
++# processes one byte in 8.45 cycles, A9 - in 10.2, A15 - in 7.63,
++# Snapdragon S4 - in 9.33.
++#
++# Câmara, D.; Gouvêa, C. P. L.; López, J. & Dahab, R.: Fast Software
++# Polynomial Multiplication on ARM Processors using the NEON Engine.
++# 
++# http://conradoplg.cryptoland.net/files/2010/12/mocrysen13.pdf
++
++# ====================================================================
++# Note about "528B" variant. In ARM case it makes lesser sense to
++# implement it for following reasons:
++#
++# - performance improvement won't be anywhere near 50%, because 128-
++#   bit shift operation is neatly fused with 128-bit xor here, and
++#   "538B" variant would eliminate only 4-5 instructions out of 32
++#   in the inner loop (meaning that estimated improvement is ~15%);
++# - ARM-based systems are often embedded ones and extra memory
++#   consumption might be unappreciated (for so little improvement);
++#
++# Byte order [in]dependence. =========================================
++#
++# Caller is expected to maintain specific *dword* order in Htable,
++# namely with *least* significant dword of 128-bit value at *lower*
++# address. This differs completely from C code and has everything to
++# do with ldm instruction and order in which dwords are "consumed" by
++# algorithm. *Byte* order within these dwords in turn is whatever
++# *native* byte order on current platform. See gcm128.c for working
++# example...
++
++$flavour = shift;
++if ($flavour=~/\w[\w\-]*\.\w+$/) { $output=$flavour; undef $flavour; }
++else { while (($output=shift) && ($output!~/\w[\w\-]*\.\w+$/)) {} }
++
++if ($flavour && $flavour ne "void") {
++    $0 =~ m/(.*[\/\\])[^\/\\]+$/; $dir=$1;
++    ( $xlate="${dir}arm-xlate.pl" and -f $xlate ) or
++    ( $xlate="${dir}../../perlasm/arm-xlate.pl" and -f $xlate) or
++    die "can't locate arm-xlate.pl";
++
++    open STDOUT,"| \"$^X\" $xlate $flavour $output";
++} else {
++    open STDOUT,">$output";
++}
++
++$Xi="r0";	# argument block
++$Htbl="r1";
++$inp="r2";
++$len="r3";
++
++$Zll="r4";	# variables
++$Zlh="r5";
++$Zhl="r6";
++$Zhh="r7";
++$Tll="r8";
++$Tlh="r9";
++$Thl="r10";
++$Thh="r11";
++$nlo="r12";
++################# r13 is stack pointer
++$nhi="r14";
++################# r15 is program counter
++
++$rem_4bit=$inp;	# used in gcm_gmult_4bit
++$cnt=$len;
++
++sub Zsmash() {
++  my $i=12;
++  my @args=@_;
++  for ($Zll,$Zlh,$Zhl,$Zhh) {
++    $code.=<<___;
++#if __ARM_ARCH__>=7 && defined(__ARMEL__)
++	rev	$_,$_
++	str	$_,[$Xi,#$i]
++#elif defined(__ARMEB__)
++	str	$_,[$Xi,#$i]
++#else
++	mov	$Tlh,$_,lsr#8
++	strb	$_,[$Xi,#$i+3]
++	mov	$Thl,$_,lsr#16
++	strb	$Tlh,[$Xi,#$i+2]
++	mov	$Thh,$_,lsr#24
++	strb	$Thl,[$Xi,#$i+1]
++	strb	$Thh,[$Xi,#$i]
++#endif
++___
++    $code.="\t".shift(@args)."\n";
++    $i-=4;
++  }
++}
++
++$code=<<___;
++#include "arm_arch.h"
++
++.text
++#if defined(__thumb2__) || defined(__clang__)
++.syntax	unified
++#endif
++#if defined(__thumb2__)
++.thumb
++#else
++.code	32
++#endif
++
++#ifdef  __clang__
++#define ldrplb  ldrbpl
++#define ldrneb  ldrbne
++#endif
++
++.type	rem_4bit,%object
++.align	5
++rem_4bit:
++.short	0x0000,0x1C20,0x3840,0x2460
++.short	0x7080,0x6CA0,0x48C0,0x54E0
++.short	0xE100,0xFD20,0xD940,0xC560
++.short	0x9180,0x8DA0,0xA9C0,0xB5E0
++.size	rem_4bit,.-rem_4bit
++
++.type	rem_4bit_get,%function
++rem_4bit_get:
++#if defined(__thumb2__)
++	adr	$rem_4bit,rem_4bit
++#else
++	sub	$rem_4bit,pc,#8+32	@ &rem_4bit
++#endif
++	b	.Lrem_4bit_got
++	nop
++	nop
++.size	rem_4bit_get,.-rem_4bit_get
++
++.global	gcm_ghash_4bit
++.type	gcm_ghash_4bit,%function
++.align	4
++gcm_ghash_4bit:
++#if defined(__thumb2__)
++	adr	r12,rem_4bit
++#else
++	sub	r12,pc,#8+48		@ &rem_4bit
++#endif
++	add	$len,$inp,$len		@ $len to point at the end
++	stmdb	sp!,{r3-r11,lr}		@ save $len/end too
++
++	ldmia	r12,{r4-r11}		@ copy rem_4bit ...
++	stmdb	sp!,{r4-r11}		@ ... to stack
++
++	ldrb	$nlo,[$inp,#15]
++	ldrb	$nhi,[$Xi,#15]
++.Louter:
++	eor	$nlo,$nlo,$nhi
++	and	$nhi,$nlo,#0xf0
++	and	$nlo,$nlo,#0x0f
++	mov	$cnt,#14
++
++	add	$Zhh,$Htbl,$nlo,lsl#4
++	ldmia	$Zhh,{$Zll-$Zhh}	@ load Htbl[nlo]
++	add	$Thh,$Htbl,$nhi
++	ldrb	$nlo,[$inp,#14]
++
++	and	$nhi,$Zll,#0xf		@ rem
++	ldmia	$Thh,{$Tll-$Thh}	@ load Htbl[nhi]
++	add	$nhi,$nhi,$nhi
++	eor	$Zll,$Tll,$Zll,lsr#4
++	ldrh	$Tll,[sp,$nhi]		@ rem_4bit[rem]
++	eor	$Zll,$Zll,$Zlh,lsl#28
++	ldrb	$nhi,[$Xi,#14]
++	eor	$Zlh,$Tlh,$Zlh,lsr#4
++	eor	$Zlh,$Zlh,$Zhl,lsl#28
++	eor	$Zhl,$Thl,$Zhl,lsr#4
++	eor	$Zhl,$Zhl,$Zhh,lsl#28
++	eor	$Zhh,$Thh,$Zhh,lsr#4
++	eor	$nlo,$nlo,$nhi
++	and	$nhi,$nlo,#0xf0
++	and	$nlo,$nlo,#0x0f
++	eor	$Zhh,$Zhh,$Tll,lsl#16
++
++.Linner:
++	add	$Thh,$Htbl,$nlo,lsl#4
++	and	$nlo,$Zll,#0xf		@ rem
++	subs	$cnt,$cnt,#1
++	add	$nlo,$nlo,$nlo
++	ldmia	$Thh,{$Tll-$Thh}	@ load Htbl[nlo]
++	eor	$Zll,$Tll,$Zll,lsr#4
++	eor	$Zll,$Zll,$Zlh,lsl#28
++	eor	$Zlh,$Tlh,$Zlh,lsr#4
++	eor	$Zlh,$Zlh,$Zhl,lsl#28
++	ldrh	$Tll,[sp,$nlo]		@ rem_4bit[rem]
++	eor	$Zhl,$Thl,$Zhl,lsr#4
++#ifdef	__thumb2__
++	it	pl
++#endif
++	ldrplb	$nlo,[$inp,$cnt]
++	eor	$Zhl,$Zhl,$Zhh,lsl#28
++	eor	$Zhh,$Thh,$Zhh,lsr#4
++
++	add	$Thh,$Htbl,$nhi
++	and	$nhi,$Zll,#0xf		@ rem
++	eor	$Zhh,$Zhh,$Tll,lsl#16	@ ^= rem_4bit[rem]
++	add	$nhi,$nhi,$nhi
++	ldmia	$Thh,{$Tll-$Thh}	@ load Htbl[nhi]
++	eor	$Zll,$Tll,$Zll,lsr#4
++#ifdef	__thumb2__
++	it	pl
++#endif
++	ldrplb	$Tll,[$Xi,$cnt]
++	eor	$Zll,$Zll,$Zlh,lsl#28
++	eor	$Zlh,$Tlh,$Zlh,lsr#4
++	ldrh	$Tlh,[sp,$nhi]
++	eor	$Zlh,$Zlh,$Zhl,lsl#28
++	eor	$Zhl,$Thl,$Zhl,lsr#4
++	eor	$Zhl,$Zhl,$Zhh,lsl#28
++#ifdef	__thumb2__
++	it	pl
++#endif
++	eorpl	$nlo,$nlo,$Tll
++	eor	$Zhh,$Thh,$Zhh,lsr#4
++#ifdef	__thumb2__
++	itt	pl
++#endif
++	andpl	$nhi,$nlo,#0xf0
++	andpl	$nlo,$nlo,#0x0f
++	eor	$Zhh,$Zhh,$Tlh,lsl#16	@ ^= rem_4bit[rem]
++	bpl	.Linner
++
++	ldr	$len,[sp,#32]		@ re-load $len/end
++	add	$inp,$inp,#16
++	mov	$nhi,$Zll
++___
++	&Zsmash("cmp\t$inp,$len","\n".
++				 "#ifdef __thumb2__\n".
++				 "	it	ne\n".
++				 "#endif\n".
++				 "	ldrneb	$nlo,[$inp,#15]");
++$code.=<<___;
++	bne	.Louter
++
++	add	sp,sp,#36
++#if __ARM_ARCH__>=5
++	ldmia	sp!,{r4-r11,pc}
++#else
++	ldmia	sp!,{r4-r11,lr}
++	tst	lr,#1
++	moveq	pc,lr			@ be binary compatible with V4, yet
++	bx	lr			@ interoperable with Thumb ISA:-)
++#endif
++.size	gcm_ghash_4bit,.-gcm_ghash_4bit
++
++.global	gcm_gmult_4bit
++.type	gcm_gmult_4bit,%function
++gcm_gmult_4bit:
++	stmdb	sp!,{r4-r11,lr}
++	ldrb	$nlo,[$Xi,#15]
++	b	rem_4bit_get
++.Lrem_4bit_got:
++	and	$nhi,$nlo,#0xf0
++	and	$nlo,$nlo,#0x0f
++	mov	$cnt,#14
++
++	add	$Zhh,$Htbl,$nlo,lsl#4
++	ldmia	$Zhh,{$Zll-$Zhh}	@ load Htbl[nlo]
++	ldrb	$nlo,[$Xi,#14]
++
++	add	$Thh,$Htbl,$nhi
++	and	$nhi,$Zll,#0xf		@ rem
++	ldmia	$Thh,{$Tll-$Thh}	@ load Htbl[nhi]
++	add	$nhi,$nhi,$nhi
++	eor	$Zll,$Tll,$Zll,lsr#4
++	ldrh	$Tll,[$rem_4bit,$nhi]	@ rem_4bit[rem]
++	eor	$Zll,$Zll,$Zlh,lsl#28
++	eor	$Zlh,$Tlh,$Zlh,lsr#4
++	eor	$Zlh,$Zlh,$Zhl,lsl#28
++	eor	$Zhl,$Thl,$Zhl,lsr#4
++	eor	$Zhl,$Zhl,$Zhh,lsl#28
++	eor	$Zhh,$Thh,$Zhh,lsr#4
++	and	$nhi,$nlo,#0xf0
++	eor	$Zhh,$Zhh,$Tll,lsl#16
++	and	$nlo,$nlo,#0x0f
++
++.Loop:
++	add	$Thh,$Htbl,$nlo,lsl#4
++	and	$nlo,$Zll,#0xf		@ rem
++	subs	$cnt,$cnt,#1
++	add	$nlo,$nlo,$nlo
++	ldmia	$Thh,{$Tll-$Thh}	@ load Htbl[nlo]
++	eor	$Zll,$Tll,$Zll,lsr#4
++	eor	$Zll,$Zll,$Zlh,lsl#28
++	eor	$Zlh,$Tlh,$Zlh,lsr#4
++	eor	$Zlh,$Zlh,$Zhl,lsl#28
++	ldrh	$Tll,[$rem_4bit,$nlo]	@ rem_4bit[rem]
++	eor	$Zhl,$Thl,$Zhl,lsr#4
++#ifdef	__thumb2__
++	it	pl
++#endif
++	ldrplb	$nlo,[$Xi,$cnt]
++	eor	$Zhl,$Zhl,$Zhh,lsl#28
++	eor	$Zhh,$Thh,$Zhh,lsr#4
++
++	add	$Thh,$Htbl,$nhi
++	and	$nhi,$Zll,#0xf		@ rem
++	eor	$Zhh,$Zhh,$Tll,lsl#16	@ ^= rem_4bit[rem]
++	add	$nhi,$nhi,$nhi
++	ldmia	$Thh,{$Tll-$Thh}	@ load Htbl[nhi]
++	eor	$Zll,$Tll,$Zll,lsr#4
++	eor	$Zll,$Zll,$Zlh,lsl#28
++	eor	$Zlh,$Tlh,$Zlh,lsr#4
++	ldrh	$Tll,[$rem_4bit,$nhi]	@ rem_4bit[rem]
++	eor	$Zlh,$Zlh,$Zhl,lsl#28
++	eor	$Zhl,$Thl,$Zhl,lsr#4
++	eor	$Zhl,$Zhl,$Zhh,lsl#28
++	eor	$Zhh,$Thh,$Zhh,lsr#4
++#ifdef	__thumb2__
++	itt	pl
++#endif
++	andpl	$nhi,$nlo,#0xf0
++	andpl	$nlo,$nlo,#0x0f
++	eor	$Zhh,$Zhh,$Tll,lsl#16	@ ^= rem_4bit[rem]
++	bpl	.Loop
++___
++	&Zsmash();
++$code.=<<___;
++#if __ARM_ARCH__>=5
++	ldmia	sp!,{r4-r11,pc}
++#else
++	ldmia	sp!,{r4-r11,lr}
++	tst	lr,#1
++	moveq	pc,lr			@ be binary compatible with V4, yet
++	bx	lr			@ interoperable with Thumb ISA:-)
++#endif
++.size	gcm_gmult_4bit,.-gcm_gmult_4bit
++___
++{
++my ($Xl,$Xm,$Xh,$IN)=map("q$_",(0..3));
++my ($t0,$t1,$t2,$t3)=map("q$_",(8..12));
++my ($Hlo,$Hhi,$Hhl,$k48,$k32,$k16)=map("d$_",(26..31));
++
++sub clmul64x64 {
++my ($r,$a,$b)=@_;
++$code.=<<___;
++	vext.8		$t0#lo, $a, $a, #1	@ A1
++	vmull.p8	$t0, $t0#lo, $b		@ F = A1*B
++	vext.8		$r#lo, $b, $b, #1	@ B1
++	vmull.p8	$r, $a, $r#lo		@ E = A*B1
++	vext.8		$t1#lo, $a, $a, #2	@ A2
++	vmull.p8	$t1, $t1#lo, $b		@ H = A2*B
++	vext.8		$t3#lo, $b, $b, #2	@ B2
++	vmull.p8	$t3, $a, $t3#lo		@ G = A*B2
++	vext.8		$t2#lo, $a, $a, #3	@ A3
++	veor		$t0, $t0, $r		@ L = E + F
++	vmull.p8	$t2, $t2#lo, $b		@ J = A3*B
++	vext.8		$r#lo, $b, $b, #3	@ B3
++	veor		$t1, $t1, $t3		@ M = G + H
++	vmull.p8	$r, $a, $r#lo		@ I = A*B3
++	veor		$t0#lo, $t0#lo, $t0#hi	@ t0 = (L) (P0 + P1) << 8
++	vand		$t0#hi, $t0#hi, $k48
++	vext.8		$t3#lo, $b, $b, #4	@ B4
++	veor		$t1#lo, $t1#lo, $t1#hi	@ t1 = (M) (P2 + P3) << 16
++	vand		$t1#hi, $t1#hi, $k32
++	vmull.p8	$t3, $a, $t3#lo		@ K = A*B4
++	veor		$t2, $t2, $r		@ N = I + J
++	veor		$t0#lo, $t0#lo, $t0#hi
++	veor		$t1#lo, $t1#lo, $t1#hi
++	veor		$t2#lo, $t2#lo, $t2#hi	@ t2 = (N) (P4 + P5) << 24
++	vand		$t2#hi, $t2#hi, $k16
++	vext.8		$t0, $t0, $t0, #15
++	veor		$t3#lo, $t3#lo, $t3#hi	@ t3 = (K) (P6 + P7) << 32
++	vmov.i64	$t3#hi, #0
++	vext.8		$t1, $t1, $t1, #14
++	veor		$t2#lo, $t2#lo, $t2#hi
++	vmull.p8	$r, $a, $b		@ D = A*B
++	vext.8		$t3, $t3, $t3, #12
++	vext.8		$t2, $t2, $t2, #13
++	veor		$t0, $t0, $t1
++	veor		$t2, $t2, $t3
++	veor		$r, $r, $t0
++	veor		$r, $r, $t2
++___
++}
++
++$code.=<<___;
++#if __ARM_MAX_ARCH__>=7
++.arch	armv7-a
++.fpu	neon
++
++.global	gcm_init_neon
++.type	gcm_init_neon,%function
++.align	4
++gcm_init_neon:
++	vld1.64		$IN#hi,[r1]!		@ load H
++	vmov.i8		$t0,#0xe1
++	vld1.64		$IN#lo,[r1]
++	vshl.i64	$t0#hi,#57
++	vshr.u64	$t0#lo,#63		@ t0=0xc2....01
++	vdup.8		$t1,$IN#hi[7]
++	vshr.u64	$Hlo,$IN#lo,#63
++	vshr.s8		$t1,#7			@ broadcast carry bit
++	vshl.i64	$IN,$IN,#1
++	vand		$t0,$t0,$t1
++	vorr		$IN#hi,$Hlo		@ H<<<=1
++	veor		$IN,$IN,$t0		@ twisted H
++	vstmia		r0,{$IN}
++
++	ret					@ bx lr
++.size	gcm_init_neon,.-gcm_init_neon
++
++.global	gcm_gmult_neon
++.type	gcm_gmult_neon,%function
++.align	4
++gcm_gmult_neon:
++	vld1.64		$IN#hi,[$Xi]!		@ load Xi
++	vld1.64		$IN#lo,[$Xi]!
++	vmov.i64	$k48,#0x0000ffffffffffff
++	vldmia		$Htbl,{$Hlo-$Hhi}	@ load twisted H
++	vmov.i64	$k32,#0x00000000ffffffff
++#ifdef __ARMEL__
++	vrev64.8	$IN,$IN
++#endif
++	vmov.i64	$k16,#0x000000000000ffff
++	veor		$Hhl,$Hlo,$Hhi		@ Karatsuba pre-processing
++	mov		$len,#16
++	b		.Lgmult_neon
++.size	gcm_gmult_neon,.-gcm_gmult_neon
++
++.global	gcm_ghash_neon
++.type	gcm_ghash_neon,%function
++.align	4
++gcm_ghash_neon:
++	vld1.64		$Xl#hi,[$Xi]!		@ load Xi
++	vld1.64		$Xl#lo,[$Xi]!
++	vmov.i64	$k48,#0x0000ffffffffffff
++	vldmia		$Htbl,{$Hlo-$Hhi}	@ load twisted H
++	vmov.i64	$k32,#0x00000000ffffffff
++#ifdef __ARMEL__
++	vrev64.8	$Xl,$Xl
++#endif
++	vmov.i64	$k16,#0x000000000000ffff
++	veor		$Hhl,$Hlo,$Hhi		@ Karatsuba pre-processing
++
++.Loop_neon:
++	vld1.64		$IN#hi,[$inp]!		@ load inp
++	vld1.64		$IN#lo,[$inp]!
++#ifdef __ARMEL__
++	vrev64.8	$IN,$IN
++#endif
++	veor		$IN,$Xl			@ inp^=Xi
++.Lgmult_neon:
++___
++	&clmul64x64	($Xl,$Hlo,"$IN#lo");	# H.lo·Xi.lo
++$code.=<<___;
++	veor		$IN#lo,$IN#lo,$IN#hi	@ Karatsuba pre-processing
++___
++	&clmul64x64	($Xm,$Hhl,"$IN#lo");	# (H.lo+H.hi)·(Xi.lo+Xi.hi)
++	&clmul64x64	($Xh,$Hhi,"$IN#hi");	# H.hi·Xi.hi
++$code.=<<___;
++	veor		$Xm,$Xm,$Xl		@ Karatsuba post-processing
++	veor		$Xm,$Xm,$Xh
++	veor		$Xl#hi,$Xl#hi,$Xm#lo
++	veor		$Xh#lo,$Xh#lo,$Xm#hi	@ Xh|Xl - 256-bit result
++
++	@ equivalent of reduction_avx from ghash-x86_64.pl
++	vshl.i64	$t1,$Xl,#57		@ 1st phase
++	vshl.i64	$t2,$Xl,#62
++	veor		$t2,$t2,$t1		@
++	vshl.i64	$t1,$Xl,#63
++	veor		$t2, $t2, $t1		@
++ 	veor		$Xl#hi,$Xl#hi,$t2#lo	@
++	veor		$Xh#lo,$Xh#lo,$t2#hi
++
++	vshr.u64	$t2,$Xl,#1		@ 2nd phase
++	veor		$Xh,$Xh,$Xl
++	veor		$Xl,$Xl,$t2		@
++	vshr.u64	$t2,$t2,#6
++	vshr.u64	$Xl,$Xl,#1		@
++	veor		$Xl,$Xl,$Xh		@
++	veor		$Xl,$Xl,$t2		@
++
++	subs		$len,#16
++	bne		.Loop_neon
++
++#ifdef __ARMEL__
++	vrev64.8	$Xl,$Xl
++#endif
++	sub		$Xi,#16	
++	vst1.64		$Xl#hi,[$Xi]!		@ write out Xi
++	vst1.64		$Xl#lo,[$Xi]
++
++	ret					@ bx lr
++.size	gcm_ghash_neon,.-gcm_ghash_neon
++#endif
++___
++}
++$code.=<<___;
++.asciz  "GHASH for ARMv4/NEON, CRYPTOGAMS by "
++.align  2
++___
++
++foreach (split("\n",$code)) {
++	s/\`([^\`]*)\`/eval $1/geo;
++
++	s/\bq([0-9]+)#(lo|hi)/sprintf "d%d",2*$1+($2 eq "hi")/geo	or
++	s/\bret\b/bx	lr/go		or
++	s/\bbx\s+lr\b/.word\t0xe12fff1e/go;    # make it possible to compile with -march=armv4
++
++	print $_,"\n";
++}
++close STDOUT; # enforce flush
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/modes/asm/ghash-c64xplus.pl b/CryptoPkg/Library/OpensslLib/openssl/crypto/modes/asm/ghash-c64xplus.pl
+new file mode 100644
+index 0000000..3cadda3
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/modes/asm/ghash-c64xplus.pl
+@@ -0,0 +1,247 @@
++#! /usr/bin/env perl
++# Copyright 2012-2016 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
++# in the file LICENSE in the source distribution or at
++# https://www.openssl.org/source/license.html
++
++#
++# ====================================================================
++# Written by Andy Polyakov  for the OpenSSL
++# project. The module is, however, dual licensed under OpenSSL and
++# CRYPTOGAMS licenses depending on where you obtain it. For further
++# details see http://www.openssl.org/~appro/cryptogams/.
++# ====================================================================
++#
++# December 2011
++#
++# The module implements GCM GHASH function and underlying single
++# multiplication operation in GF(2^128). Even though subroutines
++# have _4bit suffix, they are not using any tables, but rely on
++# hardware Galois Field Multiply support. Streamed GHASH processes
++# byte in ~7 cycles, which is >6x faster than "4-bit" table-driven
++# code compiled with TI's cl6x 6.0 with -mv6400+ -o2 flags. We are
++# comparing apples vs. oranges, but compiler surely could have done
++# better, because theoretical [though not necessarily achievable]
++# estimate for "4-bit" table-driven implementation is ~12 cycles.
++
++while (($output=shift) && ($output!~/\w[\w\-]*\.\w+$/)) {}
++open STDOUT,">$output";
++
++($Xip,$Htable,$inp,$len)=("A4","B4","A6","B6");	# arguments
++
++($Z0,$Z1,$Z2,$Z3,	$H0, $H1, $H2, $H3,
++			$H0x,$H1x,$H2x,$H3x)=map("A$_",(16..27));
++($H01u,$H01y,$H2u,$H3u,	$H0y,$H1y,$H2y,$H3y,
++			$H0z,$H1z,$H2z,$H3z)=map("B$_",(16..27));
++($FF000000,$E10000)=("B30","B31");
++($xip,$x0,$x1,$xib)=map("B$_",(6..9));	# $xip zaps $len
++ $xia="A9";
++($rem,$res)=("B4","B5");		# $rem zaps $Htable
++
++$code.=<<___;
++	.text
++
++	.if	.ASSEMBLER_VERSION<7000000
++	.asg	0,__TI_EABI__
++	.endif
++	.if	__TI_EABI__
++	.asg	gcm_gmult_1bit,_gcm_gmult_1bit
++	.asg	gcm_gmult_4bit,_gcm_gmult_4bit
++	.asg	gcm_ghash_4bit,_gcm_ghash_4bit
++	.endif
++
++	.asg	B3,RA
++
++	.if	0
++	.global	_gcm_gmult_1bit
++_gcm_gmult_1bit:
++	ADDAD	$Htable,2,$Htable
++	.endif
++	.global	_gcm_gmult_4bit
++_gcm_gmult_4bit:
++	.asmfunc
++	LDDW	*${Htable}[-1],$H1:$H0	; H.lo
++	LDDW	*${Htable}[-2],$H3:$H2	; H.hi
++||	MV	$Xip,${xip}		; reassign Xi
++||	MVK	15,B1			; SPLOOPD constant
++
++	MVK	0xE1,$E10000
++||	LDBU	*++${xip}[15],$x1	; Xi[15]
++	MVK	0xFF,$FF000000
++||	LDBU	*--${xip},$x0		; Xi[14]
++	SHL	$E10000,16,$E10000	; [pre-shifted] reduction polynomial
++	SHL	$FF000000,24,$FF000000	; upper byte mask
++||	BNOP	ghash_loop?
++||	MVK	1,B0			; take a single spin
++
++	PACKH2	$H0,$H1,$xia		; pack H0' and H1's upper bytes
++	AND	$H2,$FF000000,$H2u	; H2's upper byte
++	AND	$H3,$FF000000,$H3u	; H3's upper byte
++||	SHRU	$H2u,8,$H2u
++	SHRU	$H3u,8,$H3u
++||	ZERO	$Z1:$Z0
++	SHRU2	$xia,8,$H01u
++||	ZERO	$Z3:$Z2
++	.endasmfunc
++
++	.global	_gcm_ghash_4bit
++_gcm_ghash_4bit:
++	.asmfunc
++	LDDW	*${Htable}[-1],$H1:$H0	; H.lo
++||	SHRU	$len,4,B0		; reassign len
++	LDDW	*${Htable}[-2],$H3:$H2	; H.hi
++||	MV	$Xip,${xip}		; reassign Xi
++||	MVK	15,B1			; SPLOOPD constant
++
++	MVK	0xE1,$E10000
++|| [B0]	LDNDW	*${inp}[1],$H1x:$H0x
++	MVK	0xFF,$FF000000
++|| [B0]	LDNDW	*${inp}++[2],$H3x:$H2x
++	SHL	$E10000,16,$E10000	; [pre-shifted] reduction polynomial
++||	LDDW	*${xip}[1],$Z1:$Z0
++	SHL	$FF000000,24,$FF000000	; upper byte mask
++||	LDDW	*${xip}[0],$Z3:$Z2
++
++	PACKH2	$H0,$H1,$xia		; pack H0' and H1's upper bytes
++	AND	$H2,$FF000000,$H2u	; H2's upper byte
++	AND	$H3,$FF000000,$H3u	; H3's upper byte
++||	SHRU	$H2u,8,$H2u
++	SHRU	$H3u,8,$H3u
++	SHRU2	$xia,8,$H01u
++
++|| [B0]	XOR	$H0x,$Z0,$Z0		; Xi^=inp
++|| [B0]	XOR	$H1x,$Z1,$Z1
++	.if	.LITTLE_ENDIAN
++   [B0]	XOR	$H2x,$Z2,$Z2
++|| [B0]	XOR	$H3x,$Z3,$Z3
++|| [B0]	SHRU	$Z1,24,$xia		; Xi[15], avoid cross-path stall
++	STDW	$Z1:$Z0,*${xip}[1]
++|| [B0]	SHRU	$Z1,16,$x0		; Xi[14]
++|| [B0]	ZERO	$Z1:$Z0
++	.else
++   [B0]	XOR	$H2x,$Z2,$Z2
++|| [B0]	XOR	$H3x,$Z3,$Z3
++|| [B0]	MV	$Z0,$xia		; Xi[15], avoid cross-path stall
++	STDW	$Z1:$Z0,*${xip}[1]
++|| [B0] SHRU	$Z0,8,$x0		; Xi[14]
++|| [B0]	ZERO	$Z1:$Z0
++	.endif
++	STDW	$Z3:$Z2,*${xip}[0]
++|| [B0]	ZERO	$Z3:$Z2
++|| [B0]	MV	$xia,$x1
++   [B0]	ADDK	14,${xip}
++
++ghash_loop?:
++	SPLOOPD	6			; 6*16+7
++||	MVC	B1,ILC
++|| [B0]	SUB	B0,1,B0
++||	ZERO	A0
++||	ADD	$x1,$x1,$xib		; SHL	$x1,1,$xib
++||	SHL	$x1,1,$xia
++___
++
++########____________________________
++#  0    D2.     M1          M2      |
++#  1            M1                  |
++#  2            M1          M2      |
++#  3        D1. M1          M2      |
++#  4        S1. L1                  |
++#  5    S2  S1x L1          D2  L2  |____________________________
++#  6/0          L1  S1      L2  S2x |D2.     M1          M2      |
++#  7/1          L1  S1  D1x S2  M2  |        M1                  |
++#  8/2              S1  L1x S2      |        M1          M2      |
++#  9/3              S1  L1x         |    D1. M1          M2      |
++# 10/4                  D1x         |    S1. L1                  |
++# 11/5                              |S2  S1x L1          D2  L2  |____________
++# 12/6/0                D1x       __|        L1  S1      L2  S2x |D2.     ....
++#    7/1                                     L1  S1  D1x S2  M2  |        ....
++#    8/2                                         S1  L1x S2      |        ....
++#####...                                         ................|............
++$code.=<<___;
++	XORMPY	$H0,$xia,$H0x		; 0	; H·(Xi[i]<<1)
++||	XORMPY	$H01u,$xib,$H01y
++|| [A0]	LDBU	*--${xip},$x0
++	XORMPY	$H1,$xia,$H1x		; 1
++	XORMPY	$H2,$xia,$H2x		; 2
++||	XORMPY	$H2u,$xib,$H2y
++	XORMPY	$H3,$xia,$H3x		; 3
++||	XORMPY	$H3u,$xib,$H3y
++||[!A0]	MVK.D	15,A0				; *--${xip} counter
++	XOR.L	$H0x,$Z0,$Z0		; 4	; Z^=H·(Xi[i]<<1)
++|| [A0]	SUB.S	A0,1,A0
++	XOR.L	$H1x,$Z1,$Z1		; 5
++||	AND.D	$H01y,$FF000000,$H0z
++||	SWAP2.L	$H01y,$H1y		;	; SHL	$H01y,16,$H1y
++||	SHL	$x0,1,$xib
++||	SHL	$x0,1,$xia
++
++	XOR.L	$H2x,$Z2,$Z2		; 6/0	; [0,0] in epilogue
++||	SHL	$Z0,1,$rem		;	; rem=Z<<1
++||	SHRMB.S	$Z1,$Z0,$Z0		;	; Z>>=8
++||	AND.L	$H1y,$FF000000,$H1z
++	XOR.L	$H3x,$Z3,$Z3		; 7/1
++||	SHRMB.S	$Z2,$Z1,$Z1
++||	XOR.D	$H0z,$Z0,$Z0			; merge upper byte products
++||	AND.S	$H2y,$FF000000,$H2z
++||	XORMPY	$E10000,$rem,$res	;	; implicit rem&0x1FE
++	XOR.L	$H1z,$Z1,$Z1		; 8/2
++||	SHRMB.S	$Z3,$Z2,$Z2
++||	AND.S	$H3y,$FF000000,$H3z
++	XOR.L	$H2z,$Z2,$Z2		; 9/3
++||	SHRU	$Z3,8,$Z3
++	XOR.D	$H3z,$Z3,$Z3		; 10/4
++	NOP				; 11/5
++
++	SPKERNEL 0,2
++||	XOR.D	$res,$Z3,$Z3		; 12/6/0; Z^=res
++
++	; input pre-fetch is possible where D1 slot is available...
++   [B0]	LDNDW	*${inp}[1],$H1x:$H0x	; 8/-
++   [B0]	LDNDW	*${inp}++[2],$H3x:$H2x	; 9/-
++	NOP				; 10/-
++	.if	.LITTLE_ENDIAN
++	SWAP2	$Z0,$Z1			; 11/-
++||	SWAP4	$Z1,$Z0
++	SWAP4	$Z1,$Z1			; 12/-
++||	SWAP2	$Z0,$Z0
++	SWAP2	$Z2,$Z3
++||	SWAP4	$Z3,$Z2
++||[!B0]	BNOP	RA
++	SWAP4	$Z3,$Z3
++||	SWAP2	$Z2,$Z2
++|| [B0]	BNOP	ghash_loop?
++   [B0]	XOR	$H0x,$Z0,$Z0		; Xi^=inp
++|| [B0]	XOR	$H1x,$Z1,$Z1
++   [B0]	XOR	$H2x,$Z2,$Z2
++|| [B0]	XOR	$H3x,$Z3,$Z3
++|| [B0]	SHRU	$Z1,24,$xia		; Xi[15], avoid cross-path stall
++	STDW	$Z1:$Z0,*${xip}[1]
++|| [B0]	SHRU	$Z1,16,$x0		; Xi[14]
++|| [B0]	ZERO	$Z1:$Z0
++	.else
++  [!B0]	BNOP	RA			; 11/-
++   [B0]	BNOP	ghash_loop?		; 12/-
++   [B0]	XOR	$H0x,$Z0,$Z0		; Xi^=inp
++|| [B0]	XOR	$H1x,$Z1,$Z1
++   [B0]	XOR	$H2x,$Z2,$Z2
++|| [B0]	XOR	$H3x,$Z3,$Z3
++|| [B0]	MV	$Z0,$xia		; Xi[15], avoid cross-path stall
++	STDW	$Z1:$Z0,*${xip}[1]
++|| [B0] SHRU	$Z0,8,$x0		; Xi[14]
++|| [B0]	ZERO	$Z1:$Z0
++	.endif
++	STDW	$Z3:$Z2,*${xip}[0]
++|| [B0]	ZERO	$Z3:$Z2
++|| [B0]	MV	$xia,$x1
++   [B0]	ADDK	14,${xip}
++	.endasmfunc
++
++	.sect	.const
++	.cstring "GHASH for C64x+, CRYPTOGAMS by "
++	.align	4
++___
++
++print $code;
++close STDOUT;
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/modes/asm/ghash-ia64.pl b/CryptoPkg/Library/OpensslLib/openssl/crypto/modes/asm/ghash-ia64.pl
+new file mode 100755
+index 0000000..81e75f7
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/modes/asm/ghash-ia64.pl
+@@ -0,0 +1,470 @@
++#! /usr/bin/env perl
++# Copyright 2010-2016 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
++# in the file LICENSE in the source distribution or at
++# https://www.openssl.org/source/license.html
++
++
++# ====================================================================
++# Written by Andy Polyakov  for the OpenSSL
++# project. The module is, however, dual licensed under OpenSSL and
++# CRYPTOGAMS licenses depending on where you obtain it. For further
++# details see http://www.openssl.org/~appro/cryptogams/.
++# ====================================================================
++#
++# March 2010
++#
++# The module implements "4-bit" GCM GHASH function and underlying
++# single multiplication operation in GF(2^128). "4-bit" means that it
++# uses 256 bytes per-key table [+128 bytes shared table]. Streamed
++# GHASH performance was measured to be 6.67 cycles per processed byte
++# on Itanium 2, which is >90% better than Microsoft compiler generated
++# code. To anchor to something else sha1-ia64.pl module processes one
++# byte in 5.7 cycles. On Itanium GHASH should run at ~8.5 cycles per
++# byte.
++
++# September 2010
++#
++# It was originally thought that it makes lesser sense to implement
++# "528B" variant on Itanium 2 for following reason. Because number of
++# functional units is naturally limited, it appeared impossible to
++# implement "528B" loop in 4 cycles, only in 5. This would mean that
++# theoretically performance improvement couldn't be more than 20%.
++# But occasionally you prove yourself wrong:-) I figured out a way to
++# fold couple of instructions and having freed yet another instruction
++# slot by unrolling the loop... Resulting performance is 4.45 cycles
++# per processed byte and 50% better than "256B" version. On original
++# Itanium performance should remain the same as the "256B" version,
++# i.e. ~8.5 cycles.
++
++$output=pop and (open STDOUT,">$output" or die "can't open $output: $!");
++
++if ($^O eq "hpux") {
++    $ADDP="addp4";
++    for (@ARGV) { $ADDP="add" if (/[\+DD|\-mlp]64/); }
++} else { $ADDP="add"; }
++for (@ARGV)  {  $big_endian=1 if (/\-DB_ENDIAN/);
++                $big_endian=0 if (/\-DL_ENDIAN/);  }
++if (!defined($big_endian))
++             {  $big_endian=(unpack('L',pack('N',1))==1);  }
++
++sub loop() {
++my $label=shift;
++my ($p16,$p17)=(shift)?("p63","p63"):("p16","p17"); # mask references to inp
++
++# Loop is scheduled for 6 ticks on Itanium 2 and 8 on Itanium, i.e.
++# in scalable manner;-) Naturally assuming data in L1 cache...
++# Special note about 'dep' instruction, which is used to construct
++# &rem_4bit[Zlo&0xf]. It works, because rem_4bit is aligned at 128
++# bytes boundary and lower 7 bits of its address are guaranteed to
++# be zero.
++$code.=<<___;
++$label:
++{ .mfi;	(p18)	ld8	Hlo=[Hi[1]],-8
++	(p19)	dep	rem=Zlo,rem_4bitp,3,4	}
++{ .mfi;	(p19)	xor	Zhi=Zhi,Hhi
++	($p17)	xor	xi[1]=xi[1],in[1]	};;
++{ .mfi;	(p18)	ld8	Hhi=[Hi[1]]
++	(p19)	shrp	Zlo=Zhi,Zlo,4		}
++{ .mfi;	(p19)	ld8	rem=[rem]
++	(p18)	and	Hi[1]=mask0xf0,xi[2]	};;
++{ .mmi;	($p16)	ld1	in[0]=[inp],-1
++	(p18)	xor	Zlo=Zlo,Hlo
++	(p19)	shr.u	Zhi=Zhi,4		}
++{ .mib;	(p19)	xor	Hhi=Hhi,rem
++	(p18)	add	Hi[1]=Htbl,Hi[1]	};;
++
++{ .mfi;	(p18)	ld8	Hlo=[Hi[1]],-8
++	(p18)	dep	rem=Zlo,rem_4bitp,3,4	}
++{ .mfi;	(p17)	shladd	Hi[0]=xi[1],4,r0
++	(p18)	xor	Zhi=Zhi,Hhi		};;
++{ .mfi;	(p18)	ld8	Hhi=[Hi[1]]
++	(p18)	shrp	Zlo=Zhi,Zlo,4		}
++{ .mfi;	(p18)	ld8	rem=[rem]
++	(p17)	and	Hi[0]=mask0xf0,Hi[0]	};;
++{ .mmi;	(p16)	ld1	xi[0]=[Xi],-1
++	(p18)	xor	Zlo=Zlo,Hlo
++	(p18)	shr.u	Zhi=Zhi,4		}
++{ .mib;	(p18)	xor	Hhi=Hhi,rem
++	(p17)	add	Hi[0]=Htbl,Hi[0]
++	br.ctop.sptk	$label			};;
++___
++}
++
++$code=<<___;
++.explicit
++.text
++
++prevfs=r2;	prevlc=r3;	prevpr=r8;
++mask0xf0=r21;
++rem=r22;	rem_4bitp=r23;
++Xi=r24;		Htbl=r25;
++inp=r26;	end=r27;
++Hhi=r28;	Hlo=r29;
++Zhi=r30;	Zlo=r31;
++
++.align	128
++.skip	16					// aligns loop body
++.global	gcm_gmult_4bit#
++.proc	gcm_gmult_4bit#
++gcm_gmult_4bit:
++	.prologue
++{ .mmi;	.save	ar.pfs,prevfs
++	alloc	prevfs=ar.pfs,2,6,0,8
++	$ADDP	Xi=15,in0			// &Xi[15]
++	mov	rem_4bitp=ip		}
++{ .mii;	$ADDP	Htbl=8,in1			// &Htbl[0].lo
++	.save	ar.lc,prevlc
++	mov	prevlc=ar.lc
++	.save	pr,prevpr
++	mov	prevpr=pr		};;
++
++	.body
++	.rotr	in[3],xi[3],Hi[2]
++
++{ .mib;	ld1	xi[2]=[Xi],-1			// Xi[15]
++	mov	mask0xf0=0xf0
++	brp.loop.imp	.Loop1,.Lend1-16};;
++{ .mmi;	ld1	xi[1]=[Xi],-1			// Xi[14]
++					};;
++{ .mii;	shladd	Hi[1]=xi[2],4,r0
++	mov	pr.rot=0x7<<16
++	mov	ar.lc=13		};;
++{ .mii;	and	Hi[1]=mask0xf0,Hi[1]
++	mov	ar.ec=3
++	xor	Zlo=Zlo,Zlo		};;
++{ .mii;	add	Hi[1]=Htbl,Hi[1]		// &Htbl[nlo].lo
++	add	rem_4bitp=rem_4bit#-gcm_gmult_4bit#,rem_4bitp
++	xor	Zhi=Zhi,Zhi		};;
++___
++	&loop	(".Loop1",1);
++$code.=<<___;
++.Lend1:
++{ .mib;	xor	Zhi=Zhi,Hhi		};;	// modulo-scheduling artefact
++{ .mib;	mux1	Zlo=Zlo,\@rev		};;
++{ .mib;	mux1	Zhi=Zhi,\@rev		};;
++{ .mmi;	add	Hlo=9,Xi;;			// ;; is here to prevent
++	add	Hhi=1,Xi		};;	// pipeline flush on Itanium
++{ .mib;	st8	[Hlo]=Zlo
++	mov	pr=prevpr,0x1ffff	};;
++{ .mib;	st8	[Hhi]=Zhi
++	mov	ar.lc=prevlc
++	br.ret.sptk.many	b0	};;
++.endp	gcm_gmult_4bit#
++___
++
++######################################################################
++# "528B" (well, "512B" actualy) streamed GHASH
++#
++$Xip="in0";
++$Htbl="in1";
++$inp="in2";
++$len="in3";
++$rem_8bit="loc0";
++$mask0xff="loc1";
++($sum,$rum) = $big_endian ? ("nop.m","nop.m") : ("sum","rum");
++
++sub load_htable() {
++    for (my $i=0;$i<8;$i++) {
++	$code.=<<___;
++{ .mmi;	ld8	r`16+2*$i+1`=[r8],16		// Htable[$i].hi
++	ld8	r`16+2*$i`=[r9],16	}	// Htable[$i].lo
++{ .mmi;	ldf8	f`32+2*$i+1`=[r10],16		// Htable[`8+$i`].hi
++	ldf8	f`32+2*$i`=[r11],16		// Htable[`8+$i`].lo
++___
++	$code.=shift	if (($i+$#_)==7);
++	$code.="\t};;\n"
++    }
++}
++
++$code.=<<___;
++prevsp=r3;
++
++.align	32
++.skip	16					// aligns loop body
++.global	gcm_ghash_4bit#
++.proc	gcm_ghash_4bit#
++gcm_ghash_4bit:
++	.prologue
++{ .mmi;	.save	ar.pfs,prevfs
++	alloc	prevfs=ar.pfs,4,2,0,0
++	.vframe	prevsp
++	mov	prevsp=sp
++	mov	$rem_8bit=ip		};;
++	.body
++{ .mfi;	$ADDP	r8=0+0,$Htbl
++	$ADDP	r9=0+8,$Htbl		}
++{ .mfi;	$ADDP	r10=128+0,$Htbl
++	$ADDP	r11=128+8,$Htbl		};;
++___
++	&load_htable(
++	"	$ADDP	$Xip=15,$Xip",		# &Xi[15]
++	"	$ADDP	$len=$len,$inp",	# &inp[len]
++	"	$ADDP	$inp=15,$inp",		# &inp[15]
++	"	mov	$mask0xff=0xff",
++	"	add	sp=-512,sp",
++	"	andcm	sp=sp,$mask0xff",	# align stack frame
++	"	add	r14=0,sp",
++	"	add	r15=8,sp");
++$code.=<<___;
++{ .mmi;	$sum	1<<1				// go big-endian
++	add	r8=256+0,sp
++	add	r9=256+8,sp		}
++{ .mmi;	add	r10=256+128+0,sp
++	add	r11=256+128+8,sp
++	add	$len=-17,$len		};;
++___
++for($i=0;$i<8;$i++) {	# generate first half of Hshr4[]
++my ($rlo,$rhi)=("r".eval(16+2*$i),"r".eval(16+2*$i+1));
++$code.=<<___;
++{ .mmi;	st8	[r8]=$rlo,16			// Htable[$i].lo
++	st8	[r9]=$rhi,16			// Htable[$i].hi
++	shrp	$rlo=$rhi,$rlo,4	}//;;
++{ .mmi;	stf8	[r10]=f`32+2*$i`,16		// Htable[`8+$i`].lo
++	stf8	[r11]=f`32+2*$i+1`,16		// Htable[`8+$i`].hi
++	shr.u	$rhi=$rhi,4		};;
++{ .mmi;	st8	[r14]=$rlo,16			// Htable[$i].lo>>4
++	st8	[r15]=$rhi,16		}//;;	// Htable[$i].hi>>4
++___
++}
++$code.=<<___;
++{ .mmi;	ld8	r16=[r8],16			// Htable[8].lo
++	ld8	r17=[r9],16		};;	// Htable[8].hi
++{ .mmi;	ld8	r18=[r8],16			// Htable[9].lo
++	ld8	r19=[r9],16		}	// Htable[9].hi
++{ .mmi;	rum	1<<5				// clear um.mfh
++	shrp	r16=r17,r16,4		};;
++___
++for($i=0;$i<6;$i++) {	# generate second half of Hshr4[]
++$code.=<<___;
++{ .mmi;	ld8	r`20+2*$i`=[r8],16		// Htable[`10+$i`].lo
++	ld8	r`20+2*$i+1`=[r9],16		// Htable[`10+$i`].hi
++	shr.u	r`16+2*$i+1`=r`16+2*$i+1`,4	};;
++{ .mmi;	st8	[r14]=r`16+2*$i`,16		// Htable[`8+$i`].lo>>4
++	st8	[r15]=r`16+2*$i+1`,16		// Htable[`8+$i`].hi>>4
++	shrp	r`18+2*$i`=r`18+2*$i+1`,r`18+2*$i`,4	}
++___
++}
++$code.=<<___;
++{ .mmi;	shr.u	r`16+2*$i+1`=r`16+2*$i+1`,4	};;
++{ .mmi;	st8	[r14]=r`16+2*$i`,16		// Htable[`8+$i`].lo>>4
++	st8	[r15]=r`16+2*$i+1`,16		// Htable[`8+$i`].hi>>4
++	shrp	r`18+2*$i`=r`18+2*$i+1`,r`18+2*$i`,4	}
++{ .mmi;	add	$Htbl=256,sp			// &Htable[0]
++	add	$rem_8bit=rem_8bit#-gcm_ghash_4bit#,$rem_8bit
++	shr.u	r`18+2*$i+1`=r`18+2*$i+1`,4	};;
++{ .mmi;	st8	[r14]=r`18+2*$i`		// Htable[`8+$i`].lo>>4
++	st8	[r15]=r`18+2*$i+1`	}	// Htable[`8+$i`].hi>>4
++___
++
++$in="r15";
++@xi=("r16","r17");
++@rem=("r18","r19");
++($Alo,$Ahi,$Blo,$Bhi,$Zlo,$Zhi)=("r20","r21","r22","r23","r24","r25");
++($Atbl,$Btbl)=("r26","r27");
++
++$code.=<<___;	# (p16)
++{ .mmi;	ld1	$in=[$inp],-1			//(p16) *inp--
++	ld1	$xi[0]=[$Xip],-1		//(p16) *Xi--
++	cmp.eq	p0,p6=r0,r0		};;	//	clear p6
++___
++push (@xi,shift(@xi)); push (@rem,shift(@rem));	# "rotate" registers
++
++$code.=<<___;	# (p16),(p17)
++{ .mmi;	ld1	$xi[0]=[$Xip],-1		//(p16) *Xi--
++	xor	$xi[1]=$xi[1],$in	};;	//(p17) xi=$xi[i]^inp[i]
++{ .mii;	ld1	$in=[$inp],-1			//(p16) *inp--
++	dep	$Atbl=$xi[1],$Htbl,4,4		//(p17) &Htable[nlo].lo
++	and	$xi[1]=-16,$xi[1]	};;	//(p17) nhi=xi&0xf0
++.align	32
++.LOOP:
++{ .mmi;
++(p6)	st8	[$Xip]=$Zhi,13
++	xor	$Zlo=$Zlo,$Zlo
++	add	$Btbl=$xi[1],$Htbl	};;	//(p17) &Htable[nhi].lo
++___
++push (@xi,shift(@xi)); push (@rem,shift(@rem));	# "rotate" registers
++
++$code.=<<___;	# (p16),(p17),(p18)
++{ .mmi;	ld8	$Alo=[$Atbl],8			//(p18) Htable[nlo].lo,&Htable[nlo].hi
++	ld8	$rem[0]=[$Btbl],-256		//(p18) Htable[nhi].lo,&Hshr4[nhi].lo
++	xor	$xi[1]=$xi[1],$in	};;	//(p17) xi=$xi[i]^inp[i]
++{ .mfi;	ld8	$Ahi=[$Atbl]			//(p18) Htable[nlo].hi
++	dep	$Atbl=$xi[1],$Htbl,4,4	}	//(p17) &Htable[nlo].lo
++{ .mfi;	shladd	$rem[0]=$rem[0],4,r0		//(p18) Htable[nhi].lo<<4
++	xor	$Zlo=$Zlo,$Alo		};;	//(p18) Z.lo^=Htable[nlo].lo
++{ .mmi;	ld8	$Blo=[$Btbl],8			//(p18) Hshr4[nhi].lo,&Hshr4[nhi].hi
++	ld1	$in=[$inp],-1		}	//(p16) *inp--
++{ .mmi;	xor	$rem[0]=$rem[0],$Zlo		//(p18) Z.lo^(Htable[nhi].lo<<4)
++	mov	$Zhi=$Ahi			//(p18) Z.hi^=Htable[nlo].hi
++	and	$xi[1]=-16,$xi[1]	};;	//(p17) nhi=xi&0xf0
++{ .mmi;	ld8	$Bhi=[$Btbl]			//(p18) Hshr4[nhi].hi
++	ld1	$xi[0]=[$Xip],-1		//(p16) *Xi--
++	shrp	$Zlo=$Zhi,$Zlo,8	}	//(p18) Z.lo=(Z.hi<<56)|(Z.lo>>8)
++{ .mmi;	and	$rem[0]=$rem[0],$mask0xff	//(p18) rem=($Zlo^(Htable[nhi].lo<<4))&0xff
++	add	$Btbl=$xi[1],$Htbl	};;	//(p17) &Htable[nhi]
++___
++push (@xi,shift(@xi)); push (@rem,shift(@rem));	# "rotate" registers
++
++for ($i=1;$i<14;$i++) {
++# Above and below fragments are derived from this one by removing
++# unsuitable (p??) instructions.
++$code.=<<___;	# (p16),(p17),(p18),(p19)
++{ .mmi;	ld8	$Alo=[$Atbl],8			//(p18) Htable[nlo].lo,&Htable[nlo].hi
++	ld8	$rem[0]=[$Btbl],-256		//(p18) Htable[nhi].lo,&Hshr4[nhi].lo
++	shr.u	$Zhi=$Zhi,8		}	//(p19) Z.hi>>=8
++{ .mmi;	shladd	$rem[1]=$rem[1],1,$rem_8bit	//(p19) &rem_8bit[rem]
++	xor	$Zlo=$Zlo,$Blo			//(p19) Z.lo^=Hshr4[nhi].lo
++	xor	$xi[1]=$xi[1],$in	};;	//(p17) xi=$xi[i]^inp[i]
++{ .mmi;	ld8	$Ahi=[$Atbl]			//(p18) Htable[nlo].hi
++	ld2	$rem[1]=[$rem[1]]		//(p19) rem_8bit[rem]
++	dep	$Atbl=$xi[1],$Htbl,4,4	}	//(p17) &Htable[nlo].lo
++{ .mmi;	shladd	$rem[0]=$rem[0],4,r0		//(p18) Htable[nhi].lo<<4
++	xor	$Zlo=$Zlo,$Alo			//(p18) Z.lo^=Htable[nlo].lo
++	xor	$Zhi=$Zhi,$Bhi		};;	//(p19) Z.hi^=Hshr4[nhi].hi
++{ .mmi;	ld8	$Blo=[$Btbl],8			//(p18) Hshr4[nhi].lo,&Hshr4[nhi].hi
++	ld1	$in=[$inp],-1			//(p16) *inp--
++	shl	$rem[1]=$rem[1],48	}	//(p19) rem_8bit[rem]<<48
++{ .mmi;	xor	$rem[0]=$rem[0],$Zlo		//(p18) Z.lo^(Htable[nhi].lo<<4)
++	xor	$Zhi=$Zhi,$Ahi			//(p18) Z.hi^=Htable[nlo].hi
++	and	$xi[1]=-16,$xi[1]	};;	//(p17) nhi=xi&0xf0
++{ .mmi;	ld8	$Bhi=[$Btbl]			//(p18) Hshr4[nhi].hi
++	ld1	$xi[0]=[$Xip],-1		//(p16) *Xi--
++	shrp	$Zlo=$Zhi,$Zlo,8	}	//(p18) Z.lo=(Z.hi<<56)|(Z.lo>>8)
++{ .mmi;	and	$rem[0]=$rem[0],$mask0xff	//(p18) rem=($Zlo^(Htable[nhi].lo<<4))&0xff
++	xor	$Zhi=$Zhi,$rem[1]		//(p19) Z.hi^=rem_8bit[rem]<<48
++	add	$Btbl=$xi[1],$Htbl	};;	//(p17) &Htable[nhi]
++___
++push (@xi,shift(@xi)); push (@rem,shift(@rem));	# "rotate" registers
++}
++
++$code.=<<___;	# (p17),(p18),(p19)
++{ .mmi;	ld8	$Alo=[$Atbl],8			//(p18) Htable[nlo].lo,&Htable[nlo].hi
++	ld8	$rem[0]=[$Btbl],-256		//(p18) Htable[nhi].lo,&Hshr4[nhi].lo
++	shr.u	$Zhi=$Zhi,8		}	//(p19) Z.hi>>=8
++{ .mmi;	shladd	$rem[1]=$rem[1],1,$rem_8bit	//(p19) &rem_8bit[rem]
++	xor	$Zlo=$Zlo,$Blo			//(p19) Z.lo^=Hshr4[nhi].lo
++	xor	$xi[1]=$xi[1],$in	};;	//(p17) xi=$xi[i]^inp[i]
++{ .mmi;	ld8	$Ahi=[$Atbl]			//(p18) Htable[nlo].hi
++	ld2	$rem[1]=[$rem[1]]		//(p19) rem_8bit[rem]
++	dep	$Atbl=$xi[1],$Htbl,4,4	};;	//(p17) &Htable[nlo].lo
++{ .mmi;	shladd	$rem[0]=$rem[0],4,r0		//(p18) Htable[nhi].lo<<4
++	xor	$Zlo=$Zlo,$Alo			//(p18) Z.lo^=Htable[nlo].lo
++	xor	$Zhi=$Zhi,$Bhi		};;	//(p19) Z.hi^=Hshr4[nhi].hi
++{ .mmi;	ld8	$Blo=[$Btbl],8			//(p18) Hshr4[nhi].lo,&Hshr4[nhi].hi
++	shl	$rem[1]=$rem[1],48	}	//(p19) rem_8bit[rem]<<48
++{ .mmi;	xor	$rem[0]=$rem[0],$Zlo		//(p18) Z.lo^(Htable[nhi].lo<<4)
++	xor	$Zhi=$Zhi,$Ahi			//(p18) Z.hi^=Htable[nlo].hi
++	and	$xi[1]=-16,$xi[1]	};;	//(p17) nhi=xi&0xf0
++{ .mmi;	ld8	$Bhi=[$Btbl]			//(p18) Hshr4[nhi].hi
++	shrp	$Zlo=$Zhi,$Zlo,8	}	//(p18) Z.lo=(Z.hi<<56)|(Z.lo>>8)
++{ .mmi;	and	$rem[0]=$rem[0],$mask0xff	//(p18) rem=($Zlo^(Htable[nhi].lo<<4))&0xff
++	xor	$Zhi=$Zhi,$rem[1]		//(p19) Z.hi^=rem_8bit[rem]<<48
++	add	$Btbl=$xi[1],$Htbl	};;	//(p17) &Htable[nhi]
++___
++push (@xi,shift(@xi)); push (@rem,shift(@rem));	# "rotate" registers
++
++$code.=<<___;	# (p18),(p19)
++{ .mfi;	ld8	$Alo=[$Atbl],8			//(p18) Htable[nlo].lo,&Htable[nlo].hi
++	shr.u	$Zhi=$Zhi,8		}	//(p19) Z.hi>>=8
++{ .mfi;	shladd	$rem[1]=$rem[1],1,$rem_8bit	//(p19) &rem_8bit[rem]
++	xor	$Zlo=$Zlo,$Blo		};;	//(p19) Z.lo^=Hshr4[nhi].lo
++{ .mfi;	ld8	$Ahi=[$Atbl]			//(p18) Htable[nlo].hi
++	xor	$Zlo=$Zlo,$Alo		}	//(p18) Z.lo^=Htable[nlo].lo
++{ .mfi;	ld2	$rem[1]=[$rem[1]]		//(p19) rem_8bit[rem]
++	xor	$Zhi=$Zhi,$Bhi		};;	//(p19) Z.hi^=Hshr4[nhi].hi
++{ .mfi;	ld8	$Blo=[$Btbl],8			//(p18) Htable[nhi].lo,&Htable[nhi].hi
++	shl	$rem[1]=$rem[1],48	}	//(p19) rem_8bit[rem]<<48
++{ .mfi;	shladd	$rem[0]=$Zlo,4,r0		//(p18) Z.lo<<4
++	xor	$Zhi=$Zhi,$Ahi		};;	//(p18) Z.hi^=Htable[nlo].hi
++{ .mfi;	ld8	$Bhi=[$Btbl]			//(p18) Htable[nhi].hi
++	shrp	$Zlo=$Zhi,$Zlo,4	}	//(p18) Z.lo=(Z.hi<<60)|(Z.lo>>4)
++{ .mfi;	and	$rem[0]=$rem[0],$mask0xff	//(p18) rem=($Zlo^(Htable[nhi].lo<<4))&0xff
++	xor	$Zhi=$Zhi,$rem[1]	};;	//(p19) Z.hi^=rem_8bit[rem]<<48
++___
++push (@xi,shift(@xi)); push (@rem,shift(@rem));	# "rotate" registers
++
++$code.=<<___;	# (p19)
++{ .mmi;	cmp.ltu	p6,p0=$inp,$len
++	add	$inp=32,$inp
++	shr.u	$Zhi=$Zhi,4		}	//(p19) Z.hi>>=4
++{ .mmi;	shladd	$rem[1]=$rem[1],1,$rem_8bit	//(p19) &rem_8bit[rem]
++	xor	$Zlo=$Zlo,$Blo			//(p19) Z.lo^=Hshr4[nhi].lo
++	add	$Xip=9,$Xip		};;	//	&Xi.lo
++{ .mmi;	ld2	$rem[1]=[$rem[1]]		//(p19) rem_8bit[rem]
++(p6)	ld1	$in=[$inp],-1			//[p16] *inp--
++(p6)	extr.u	$xi[1]=$Zlo,8,8		}	//[p17] Xi[14]
++{ .mmi;	xor	$Zhi=$Zhi,$Bhi			//(p19) Z.hi^=Hshr4[nhi].hi
++(p6)	and	$xi[0]=$Zlo,$mask0xff	};;	//[p16] Xi[15]
++{ .mmi;	st8	[$Xip]=$Zlo,-8
++(p6)	xor	$xi[0]=$xi[0],$in		//[p17] xi=$xi[i]^inp[i]
++	shl	$rem[1]=$rem[1],48	};;	//(p19) rem_8bit[rem]<<48
++{ .mmi;
++(p6)	ld1	$in=[$inp],-1			//[p16] *inp--
++	xor	$Zhi=$Zhi,$rem[1]		//(p19) Z.hi^=rem_8bit[rem]<<48
++(p6)	dep	$Atbl=$xi[0],$Htbl,4,4	}	//[p17] &Htable[nlo].lo
++{ .mib;
++(p6)	and	$xi[0]=-16,$xi[0]		//[p17] nhi=xi&0xf0
++(p6)	br.cond.dptk.many	.LOOP	};;
++
++{ .mib;	st8	[$Xip]=$Zhi		};;
++{ .mib;	$rum	1<<1				// return to little-endian
++	.restore	sp
++	mov	sp=prevsp
++	br.ret.sptk.many	b0	};;
++.endp	gcm_ghash_4bit#
++___
++$code.=<<___;
++.align	128
++.type	rem_4bit#,\@object
++rem_4bit:
++        data8	0x0000<<48, 0x1C20<<48, 0x3840<<48, 0x2460<<48
++        data8	0x7080<<48, 0x6CA0<<48, 0x48C0<<48, 0x54E0<<48
++        data8	0xE100<<48, 0xFD20<<48, 0xD940<<48, 0xC560<<48
++        data8	0x9180<<48, 0x8DA0<<48, 0xA9C0<<48, 0xB5E0<<48
++.size	rem_4bit#,128
++.type	rem_8bit#,\@object
++rem_8bit:
++	data1	0x00,0x00, 0x01,0xC2, 0x03,0x84, 0x02,0x46, 0x07,0x08, 0x06,0xCA, 0x04,0x8C, 0x05,0x4E
++	data1	0x0E,0x10, 0x0F,0xD2, 0x0D,0x94, 0x0C,0x56, 0x09,0x18, 0x08,0xDA, 0x0A,0x9C, 0x0B,0x5E
++	data1	0x1C,0x20, 0x1D,0xE2, 0x1F,0xA4, 0x1E,0x66, 0x1B,0x28, 0x1A,0xEA, 0x18,0xAC, 0x19,0x6E
++	data1	0x12,0x30, 0x13,0xF2, 0x11,0xB4, 0x10,0x76, 0x15,0x38, 0x14,0xFA, 0x16,0xBC, 0x17,0x7E
++	data1	0x38,0x40, 0x39,0x82, 0x3B,0xC4, 0x3A,0x06, 0x3F,0x48, 0x3E,0x8A, 0x3C,0xCC, 0x3D,0x0E
++	data1	0x36,0x50, 0x37,0x92, 0x35,0xD4, 0x34,0x16, 0x31,0x58, 0x30,0x9A, 0x32,0xDC, 0x33,0x1E
++	data1	0x24,0x60, 0x25,0xA2, 0x27,0xE4, 0x26,0x26, 0x23,0x68, 0x22,0xAA, 0x20,0xEC, 0x21,0x2E
++	data1	0x2A,0x70, 0x2B,0xB2, 0x29,0xF4, 0x28,0x36, 0x2D,0x78, 0x2C,0xBA, 0x2E,0xFC, 0x2F,0x3E
++	data1	0x70,0x80, 0x71,0x42, 0x73,0x04, 0x72,0xC6, 0x77,0x88, 0x76,0x4A, 0x74,0x0C, 0x75,0xCE
++	data1	0x7E,0x90, 0x7F,0x52, 0x7D,0x14, 0x7C,0xD6, 0x79,0x98, 0x78,0x5A, 0x7A,0x1C, 0x7B,0xDE
++	data1	0x6C,0xA0, 0x6D,0x62, 0x6F,0x24, 0x6E,0xE6, 0x6B,0xA8, 0x6A,0x6A, 0x68,0x2C, 0x69,0xEE
++	data1	0x62,0xB0, 0x63,0x72, 0x61,0x34, 0x60,0xF6, 0x65,0xB8, 0x64,0x7A, 0x66,0x3C, 0x67,0xFE
++	data1	0x48,0xC0, 0x49,0x02, 0x4B,0x44, 0x4A,0x86, 0x4F,0xC8, 0x4E,0x0A, 0x4C,0x4C, 0x4D,0x8E
++	data1	0x46,0xD0, 0x47,0x12, 0x45,0x54, 0x44,0x96, 0x41,0xD8, 0x40,0x1A, 0x42,0x5C, 0x43,0x9E
++	data1	0x54,0xE0, 0x55,0x22, 0x57,0x64, 0x56,0xA6, 0x53,0xE8, 0x52,0x2A, 0x50,0x6C, 0x51,0xAE
++	data1	0x5A,0xF0, 0x5B,0x32, 0x59,0x74, 0x58,0xB6, 0x5D,0xF8, 0x5C,0x3A, 0x5E,0x7C, 0x5F,0xBE
++	data1	0xE1,0x00, 0xE0,0xC2, 0xE2,0x84, 0xE3,0x46, 0xE6,0x08, 0xE7,0xCA, 0xE5,0x8C, 0xE4,0x4E
++	data1	0xEF,0x10, 0xEE,0xD2, 0xEC,0x94, 0xED,0x56, 0xE8,0x18, 0xE9,0xDA, 0xEB,0x9C, 0xEA,0x5E
++	data1	0xFD,0x20, 0xFC,0xE2, 0xFE,0xA4, 0xFF,0x66, 0xFA,0x28, 0xFB,0xEA, 0xF9,0xAC, 0xF8,0x6E
++	data1	0xF3,0x30, 0xF2,0xF2, 0xF0,0xB4, 0xF1,0x76, 0xF4,0x38, 0xF5,0xFA, 0xF7,0xBC, 0xF6,0x7E
++	data1	0xD9,0x40, 0xD8,0x82, 0xDA,0xC4, 0xDB,0x06, 0xDE,0x48, 0xDF,0x8A, 0xDD,0xCC, 0xDC,0x0E
++	data1	0xD7,0x50, 0xD6,0x92, 0xD4,0xD4, 0xD5,0x16, 0xD0,0x58, 0xD1,0x9A, 0xD3,0xDC, 0xD2,0x1E
++	data1	0xC5,0x60, 0xC4,0xA2, 0xC6,0xE4, 0xC7,0x26, 0xC2,0x68, 0xC3,0xAA, 0xC1,0xEC, 0xC0,0x2E
++	data1	0xCB,0x70, 0xCA,0xB2, 0xC8,0xF4, 0xC9,0x36, 0xCC,0x78, 0xCD,0xBA, 0xCF,0xFC, 0xCE,0x3E
++	data1	0x91,0x80, 0x90,0x42, 0x92,0x04, 0x93,0xC6, 0x96,0x88, 0x97,0x4A, 0x95,0x0C, 0x94,0xCE
++	data1	0x9F,0x90, 0x9E,0x52, 0x9C,0x14, 0x9D,0xD6, 0x98,0x98, 0x99,0x5A, 0x9B,0x1C, 0x9A,0xDE
++	data1	0x8D,0xA0, 0x8C,0x62, 0x8E,0x24, 0x8F,0xE6, 0x8A,0xA8, 0x8B,0x6A, 0x89,0x2C, 0x88,0xEE
++	data1	0x83,0xB0, 0x82,0x72, 0x80,0x34, 0x81,0xF6, 0x84,0xB8, 0x85,0x7A, 0x87,0x3C, 0x86,0xFE
++	data1	0xA9,0xC0, 0xA8,0x02, 0xAA,0x44, 0xAB,0x86, 0xAE,0xC8, 0xAF,0x0A, 0xAD,0x4C, 0xAC,0x8E
++	data1	0xA7,0xD0, 0xA6,0x12, 0xA4,0x54, 0xA5,0x96, 0xA0,0xD8, 0xA1,0x1A, 0xA3,0x5C, 0xA2,0x9E
++	data1	0xB5,0xE0, 0xB4,0x22, 0xB6,0x64, 0xB7,0xA6, 0xB2,0xE8, 0xB3,0x2A, 0xB1,0x6C, 0xB0,0xAE
++	data1	0xBB,0xF0, 0xBA,0x32, 0xB8,0x74, 0xB9,0xB6, 0xBC,0xF8, 0xBD,0x3A, 0xBF,0x7C, 0xBE,0xBE
++.size	rem_8bit#,512
++stringz	"GHASH for IA64, CRYPTOGAMS by "
++___
++
++$code =~ s/mux1(\s+)\S+\@rev/nop.i$1 0x0/gm      if ($big_endian);
++$code =~ s/\`([^\`]*)\`/eval $1/gem;
++
++print $code;
++close STDOUT;
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/modes/asm/ghash-parisc.pl b/CryptoPkg/Library/OpensslLib/openssl/crypto/modes/asm/ghash-parisc.pl
+new file mode 100644
+index 0000000..1d62545
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/modes/asm/ghash-parisc.pl
+@@ -0,0 +1,738 @@
++#! /usr/bin/env perl
++# Copyright 2010-2016 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
++# in the file LICENSE in the source distribution or at
++# https://www.openssl.org/source/license.html
++
++#
++# ====================================================================
++# Written by Andy Polyakov  for the OpenSSL
++# project. The module is, however, dual licensed under OpenSSL and
++# CRYPTOGAMS licenses depending on where you obtain it. For further
++# details see http://www.openssl.org/~appro/cryptogams/.
++# ====================================================================
++#
++# April 2010
++#
++# The module implements "4-bit" GCM GHASH function and underlying
++# single multiplication operation in GF(2^128). "4-bit" means that it
++# uses 256 bytes per-key table [+128 bytes shared table]. On PA-7100LC
++# it processes one byte in 19.6 cycles, which is more than twice as
++# fast as code generated by gcc 3.2. PA-RISC 2.0 loop is scheduled for
++# 8 cycles, but measured performance on PA-8600 system is ~9 cycles per
++# processed byte. This is ~2.2x faster than 64-bit code generated by
++# vendor compiler (which used to be very hard to beat:-).
++#
++# Special thanks to polarhome.com for providing HP-UX account.
++
++$flavour = shift;
++$output = shift;
++open STDOUT,">$output";
++
++if ($flavour =~ /64/) {
++	$LEVEL		="2.0W";
++	$SIZE_T		=8;
++	$FRAME_MARKER	=80;
++	$SAVED_RP	=16;
++	$PUSH		="std";
++	$PUSHMA		="std,ma";
++	$POP		="ldd";
++	$POPMB		="ldd,mb";
++	$NREGS		=6;
++} else {
++	$LEVEL		="1.0";	#"\n\t.ALLOW\t2.0";
++	$SIZE_T		=4;
++	$FRAME_MARKER	=48;
++	$SAVED_RP	=20;
++	$PUSH		="stw";
++	$PUSHMA		="stwm";
++	$POP		="ldw";
++	$POPMB		="ldwm";
++	$NREGS		=11;
++}
++
++$FRAME=10*$SIZE_T+$FRAME_MARKER;# NREGS saved regs + frame marker
++				#                 [+ argument transfer]
++
++################# volatile registers
++$Xi="%r26";	# argument block
++$Htbl="%r25";
++$inp="%r24";
++$len="%r23";
++$Hhh=$Htbl;	# variables
++$Hll="%r22";
++$Zhh="%r21";
++$Zll="%r20";
++$cnt="%r19";
++$rem_4bit="%r28";
++$rem="%r29";
++$mask0xf0="%r31";
++
++################# preserved registers
++$Thh="%r1";
++$Tll="%r2";
++$nlo="%r3";
++$nhi="%r4";
++$byte="%r5";
++if ($SIZE_T==4) {
++	$Zhl="%r6";
++	$Zlh="%r7";
++	$Hhl="%r8";
++	$Hlh="%r9";
++	$Thl="%r10";
++	$Tlh="%r11";
++}
++$rem2="%r6";	# used in PA-RISC 2.0 code
++
++$code.=<<___;
++	.LEVEL	$LEVEL
++	.SPACE	\$TEXT\$
++	.SUBSPA	\$CODE\$,QUAD=0,ALIGN=8,ACCESS=0x2C,CODE_ONLY
++
++	.EXPORT	gcm_gmult_4bit,ENTRY,ARGW0=GR,ARGW1=GR
++	.ALIGN	64
++gcm_gmult_4bit
++	.PROC
++	.CALLINFO	FRAME=`$FRAME-10*$SIZE_T`,NO_CALLS,SAVE_RP,ENTRY_GR=$NREGS
++	.ENTRY
++	$PUSH	%r2,-$SAVED_RP(%sp)	; standard prologue
++	$PUSHMA	%r3,$FRAME(%sp)
++	$PUSH	%r4,`-$FRAME+1*$SIZE_T`(%sp)
++	$PUSH	%r5,`-$FRAME+2*$SIZE_T`(%sp)
++	$PUSH	%r6,`-$FRAME+3*$SIZE_T`(%sp)
++___
++$code.=<<___ if ($SIZE_T==4);
++	$PUSH	%r7,`-$FRAME+4*$SIZE_T`(%sp)
++	$PUSH	%r8,`-$FRAME+5*$SIZE_T`(%sp)
++	$PUSH	%r9,`-$FRAME+6*$SIZE_T`(%sp)
++	$PUSH	%r10,`-$FRAME+7*$SIZE_T`(%sp)
++	$PUSH	%r11,`-$FRAME+8*$SIZE_T`(%sp)
++___
++$code.=<<___;
++	blr	%r0,$rem_4bit
++	ldi	3,$rem
++L\$pic_gmult
++	andcm	$rem_4bit,$rem,$rem_4bit
++	addl	$inp,$len,$len
++	ldo	L\$rem_4bit-L\$pic_gmult($rem_4bit),$rem_4bit
++	ldi	0xf0,$mask0xf0
++___
++$code.=<<___ if ($SIZE_T==4);
++	ldi	31,$rem
++	mtctl	$rem,%cr11
++	extrd,u,*= $rem,%sar,1,$rem	; executes on PA-RISC 1.0
++	b	L\$parisc1_gmult
++	nop
++___
++
++$code.=<<___;
++	ldb	15($Xi),$nlo
++	ldo	8($Htbl),$Hll
++
++	and	$mask0xf0,$nlo,$nhi
++	depd,z	$nlo,59,4,$nlo
++
++	ldd	$nlo($Hll),$Zll
++	ldd	$nlo($Hhh),$Zhh
++
++	depd,z	$Zll,60,4,$rem
++	shrpd	$Zhh,$Zll,4,$Zll
++	extrd,u	$Zhh,59,60,$Zhh
++	ldb	14($Xi),$nlo
++
++	ldd	$nhi($Hll),$Tll
++	ldd	$nhi($Hhh),$Thh
++	and	$mask0xf0,$nlo,$nhi
++	depd,z	$nlo,59,4,$nlo
++
++	xor	$Tll,$Zll,$Zll
++	xor	$Thh,$Zhh,$Zhh
++	ldd	$rem($rem_4bit),$rem
++	b	L\$oop_gmult_pa2
++	ldi	13,$cnt
++
++	.ALIGN	8
++L\$oop_gmult_pa2
++	xor	$rem,$Zhh,$Zhh		; moved here to work around gas bug
++	depd,z	$Zll,60,4,$rem
++
++	shrpd	$Zhh,$Zll,4,$Zll
++	extrd,u	$Zhh,59,60,$Zhh
++	ldd	$nlo($Hll),$Tll
++	ldd	$nlo($Hhh),$Thh
++
++	xor	$Tll,$Zll,$Zll
++	xor	$Thh,$Zhh,$Zhh
++	ldd	$rem($rem_4bit),$rem
++
++	xor	$rem,$Zhh,$Zhh
++	depd,z	$Zll,60,4,$rem
++	ldbx	$cnt($Xi),$nlo
++
++	shrpd	$Zhh,$Zll,4,$Zll
++	extrd,u	$Zhh,59,60,$Zhh
++	ldd	$nhi($Hll),$Tll
++	ldd	$nhi($Hhh),$Thh
++
++	and	$mask0xf0,$nlo,$nhi
++	depd,z	$nlo,59,4,$nlo
++	ldd	$rem($rem_4bit),$rem
++
++	xor	$Tll,$Zll,$Zll
++	addib,uv -1,$cnt,L\$oop_gmult_pa2
++	xor	$Thh,$Zhh,$Zhh
++
++	xor	$rem,$Zhh,$Zhh
++	depd,z	$Zll,60,4,$rem
++
++	shrpd	$Zhh,$Zll,4,$Zll
++	extrd,u	$Zhh,59,60,$Zhh
++	ldd	$nlo($Hll),$Tll
++	ldd	$nlo($Hhh),$Thh
++
++	xor	$Tll,$Zll,$Zll
++	xor	$Thh,$Zhh,$Zhh
++	ldd	$rem($rem_4bit),$rem
++
++	xor	$rem,$Zhh,$Zhh
++	depd,z	$Zll,60,4,$rem
++
++	shrpd	$Zhh,$Zll,4,$Zll
++	extrd,u	$Zhh,59,60,$Zhh
++	ldd	$nhi($Hll),$Tll
++	ldd	$nhi($Hhh),$Thh
++
++	xor	$Tll,$Zll,$Zll
++	xor	$Thh,$Zhh,$Zhh
++	ldd	$rem($rem_4bit),$rem
++
++	xor	$rem,$Zhh,$Zhh
++	std	$Zll,8($Xi)
++	std	$Zhh,0($Xi)
++___
++
++$code.=<<___ if ($SIZE_T==4);
++	b	L\$done_gmult
++	nop
++
++L\$parisc1_gmult
++	ldb	15($Xi),$nlo
++	ldo	12($Htbl),$Hll
++	ldo	8($Htbl),$Hlh
++	ldo	4($Htbl),$Hhl
++
++	and	$mask0xf0,$nlo,$nhi
++	zdep	$nlo,27,4,$nlo
++
++	ldwx	$nlo($Hll),$Zll
++	ldwx	$nlo($Hlh),$Zlh
++	ldwx	$nlo($Hhl),$Zhl
++	ldwx	$nlo($Hhh),$Zhh
++	zdep	$Zll,28,4,$rem
++	ldb	14($Xi),$nlo
++	ldwx	$rem($rem_4bit),$rem
++	shrpw	$Zlh,$Zll,4,$Zll
++	ldwx	$nhi($Hll),$Tll
++	shrpw	$Zhl,$Zlh,4,$Zlh
++	ldwx	$nhi($Hlh),$Tlh
++	shrpw	$Zhh,$Zhl,4,$Zhl
++	ldwx	$nhi($Hhl),$Thl
++	extru	$Zhh,27,28,$Zhh
++	ldwx	$nhi($Hhh),$Thh
++	xor	$rem,$Zhh,$Zhh
++	and	$mask0xf0,$nlo,$nhi
++	zdep	$nlo,27,4,$nlo
++
++	xor	$Tll,$Zll,$Zll
++	ldwx	$nlo($Hll),$Tll
++	xor	$Tlh,$Zlh,$Zlh
++	ldwx	$nlo($Hlh),$Tlh
++	xor	$Thl,$Zhl,$Zhl
++	b	L\$oop_gmult_pa1
++	ldi	13,$cnt
++
++	.ALIGN	8
++L\$oop_gmult_pa1
++	zdep	$Zll,28,4,$rem
++	ldwx	$nlo($Hhl),$Thl
++	xor	$Thh,$Zhh,$Zhh
++	ldwx	$rem($rem_4bit),$rem
++	shrpw	$Zlh,$Zll,4,$Zll
++	ldwx	$nlo($Hhh),$Thh
++	shrpw	$Zhl,$Zlh,4,$Zlh
++	ldbx	$cnt($Xi),$nlo
++	xor	$Tll,$Zll,$Zll
++	ldwx	$nhi($Hll),$Tll
++	shrpw	$Zhh,$Zhl,4,$Zhl
++	xor	$Tlh,$Zlh,$Zlh
++	ldwx	$nhi($Hlh),$Tlh
++	extru	$Zhh,27,28,$Zhh
++	xor	$Thl,$Zhl,$Zhl
++	ldwx	$nhi($Hhl),$Thl
++	xor	$rem,$Zhh,$Zhh
++	zdep	$Zll,28,4,$rem
++	xor	$Thh,$Zhh,$Zhh
++	ldwx	$nhi($Hhh),$Thh
++	shrpw	$Zlh,$Zll,4,$Zll
++	ldwx	$rem($rem_4bit),$rem
++	shrpw	$Zhl,$Zlh,4,$Zlh
++	shrpw	$Zhh,$Zhl,4,$Zhl
++	and	$mask0xf0,$nlo,$nhi
++	extru	$Zhh,27,28,$Zhh
++	zdep	$nlo,27,4,$nlo
++	xor	$Tll,$Zll,$Zll
++	ldwx	$nlo($Hll),$Tll
++	xor	$Tlh,$Zlh,$Zlh
++	ldwx	$nlo($Hlh),$Tlh
++	xor	$rem,$Zhh,$Zhh
++	addib,uv -1,$cnt,L\$oop_gmult_pa1
++	xor	$Thl,$Zhl,$Zhl
++
++	zdep	$Zll,28,4,$rem
++	ldwx	$nlo($Hhl),$Thl
++	xor	$Thh,$Zhh,$Zhh
++	ldwx	$rem($rem_4bit),$rem
++	shrpw	$Zlh,$Zll,4,$Zll
++	ldwx	$nlo($Hhh),$Thh
++	shrpw	$Zhl,$Zlh,4,$Zlh
++	xor	$Tll,$Zll,$Zll
++	ldwx	$nhi($Hll),$Tll
++	shrpw	$Zhh,$Zhl,4,$Zhl
++	xor	$Tlh,$Zlh,$Zlh
++	ldwx	$nhi($Hlh),$Tlh
++	extru	$Zhh,27,28,$Zhh
++	xor	$rem,$Zhh,$Zhh
++	xor	$Thl,$Zhl,$Zhl
++	ldwx	$nhi($Hhl),$Thl
++	xor	$Thh,$Zhh,$Zhh
++	ldwx	$nhi($Hhh),$Thh
++	zdep	$Zll,28,4,$rem
++	ldwx	$rem($rem_4bit),$rem
++	shrpw	$Zlh,$Zll,4,$Zll
++	shrpw	$Zhl,$Zlh,4,$Zlh
++	shrpw	$Zhh,$Zhl,4,$Zhl
++	extru	$Zhh,27,28,$Zhh
++	xor	$Tll,$Zll,$Zll
++	xor	$Tlh,$Zlh,$Zlh
++	xor	$rem,$Zhh,$Zhh
++	stw	$Zll,12($Xi)
++	xor	$Thl,$Zhl,$Zhl
++	stw	$Zlh,8($Xi)
++	xor	$Thh,$Zhh,$Zhh
++	stw	$Zhl,4($Xi)
++	stw	$Zhh,0($Xi)
++___
++$code.=<<___;
++L\$done_gmult
++	$POP	`-$FRAME-$SAVED_RP`(%sp),%r2		; standard epilogue
++	$POP	`-$FRAME+1*$SIZE_T`(%sp),%r4
++	$POP	`-$FRAME+2*$SIZE_T`(%sp),%r5
++	$POP	`-$FRAME+3*$SIZE_T`(%sp),%r6
++___
++$code.=<<___ if ($SIZE_T==4);
++	$POP	`-$FRAME+4*$SIZE_T`(%sp),%r7
++	$POP	`-$FRAME+5*$SIZE_T`(%sp),%r8
++	$POP	`-$FRAME+6*$SIZE_T`(%sp),%r9
++	$POP	`-$FRAME+7*$SIZE_T`(%sp),%r10
++	$POP	`-$FRAME+8*$SIZE_T`(%sp),%r11
++___
++$code.=<<___;
++	bv	(%r2)
++	.EXIT
++	$POPMB	-$FRAME(%sp),%r3
++	.PROCEND
++
++	.EXPORT	gcm_ghash_4bit,ENTRY,ARGW0=GR,ARGW1=GR,ARGW2=GR,ARGW3=GR
++	.ALIGN	64
++gcm_ghash_4bit
++	.PROC
++	.CALLINFO	FRAME=`$FRAME-10*$SIZE_T`,NO_CALLS,SAVE_RP,ENTRY_GR=11
++	.ENTRY
++	$PUSH	%r2,-$SAVED_RP(%sp)	; standard prologue
++	$PUSHMA	%r3,$FRAME(%sp)
++	$PUSH	%r4,`-$FRAME+1*$SIZE_T`(%sp)
++	$PUSH	%r5,`-$FRAME+2*$SIZE_T`(%sp)
++	$PUSH	%r6,`-$FRAME+3*$SIZE_T`(%sp)
++___
++$code.=<<___ if ($SIZE_T==4);
++	$PUSH	%r7,`-$FRAME+4*$SIZE_T`(%sp)
++	$PUSH	%r8,`-$FRAME+5*$SIZE_T`(%sp)
++	$PUSH	%r9,`-$FRAME+6*$SIZE_T`(%sp)
++	$PUSH	%r10,`-$FRAME+7*$SIZE_T`(%sp)
++	$PUSH	%r11,`-$FRAME+8*$SIZE_T`(%sp)
++___
++$code.=<<___;
++	blr	%r0,$rem_4bit
++	ldi	3,$rem
++L\$pic_ghash
++	andcm	$rem_4bit,$rem,$rem_4bit
++	addl	$inp,$len,$len
++	ldo	L\$rem_4bit-L\$pic_ghash($rem_4bit),$rem_4bit
++	ldi	0xf0,$mask0xf0
++___
++$code.=<<___ if ($SIZE_T==4);
++	ldi	31,$rem
++	mtctl	$rem,%cr11
++	extrd,u,*= $rem,%sar,1,$rem	; executes on PA-RISC 1.0
++	b	L\$parisc1_ghash
++	nop
++___
++
++$code.=<<___;
++	ldb	15($Xi),$nlo
++	ldo	8($Htbl),$Hll
++
++L\$outer_ghash_pa2
++	ldb	15($inp),$nhi
++	xor	$nhi,$nlo,$nlo
++	and	$mask0xf0,$nlo,$nhi
++	depd,z	$nlo,59,4,$nlo
++
++	ldd	$nlo($Hll),$Zll
++	ldd	$nlo($Hhh),$Zhh
++
++	depd,z	$Zll,60,4,$rem
++	shrpd	$Zhh,$Zll,4,$Zll
++	extrd,u	$Zhh,59,60,$Zhh
++	ldb	14($Xi),$nlo
++	ldb	14($inp),$byte
++
++	ldd	$nhi($Hll),$Tll
++	ldd	$nhi($Hhh),$Thh
++	xor	$byte,$nlo,$nlo
++	and	$mask0xf0,$nlo,$nhi
++	depd,z	$nlo,59,4,$nlo
++
++	xor	$Tll,$Zll,$Zll
++	xor	$Thh,$Zhh,$Zhh
++	ldd	$rem($rem_4bit),$rem
++	b	L\$oop_ghash_pa2
++	ldi	13,$cnt
++
++	.ALIGN	8
++L\$oop_ghash_pa2
++	xor	$rem,$Zhh,$Zhh		; moved here to work around gas bug
++	depd,z	$Zll,60,4,$rem2
++
++	shrpd	$Zhh,$Zll,4,$Zll
++	extrd,u	$Zhh,59,60,$Zhh
++	ldd	$nlo($Hll),$Tll
++	ldd	$nlo($Hhh),$Thh
++
++	xor	$Tll,$Zll,$Zll
++	xor	$Thh,$Zhh,$Zhh
++	ldbx	$cnt($Xi),$nlo
++	ldbx	$cnt($inp),$byte
++
++	depd,z	$Zll,60,4,$rem
++	shrpd	$Zhh,$Zll,4,$Zll
++	ldd	$rem2($rem_4bit),$rem2
++
++	xor	$rem2,$Zhh,$Zhh
++	xor	$byte,$nlo,$nlo
++	ldd	$nhi($Hll),$Tll
++	ldd	$nhi($Hhh),$Thh
++
++	and	$mask0xf0,$nlo,$nhi
++	depd,z	$nlo,59,4,$nlo
++
++	extrd,u	$Zhh,59,60,$Zhh
++	xor	$Tll,$Zll,$Zll
++
++	ldd	$rem($rem_4bit),$rem
++	addib,uv -1,$cnt,L\$oop_ghash_pa2
++	xor	$Thh,$Zhh,$Zhh
++
++	xor	$rem,$Zhh,$Zhh
++	depd,z	$Zll,60,4,$rem2
++
++	shrpd	$Zhh,$Zll,4,$Zll
++	extrd,u	$Zhh,59,60,$Zhh
++	ldd	$nlo($Hll),$Tll
++	ldd	$nlo($Hhh),$Thh
++
++	xor	$Tll,$Zll,$Zll
++	xor	$Thh,$Zhh,$Zhh
++
++	depd,z	$Zll,60,4,$rem
++	shrpd	$Zhh,$Zll,4,$Zll
++	ldd	$rem2($rem_4bit),$rem2
++
++	xor	$rem2,$Zhh,$Zhh
++	ldd	$nhi($Hll),$Tll
++	ldd	$nhi($Hhh),$Thh
++
++	extrd,u	$Zhh,59,60,$Zhh
++	xor	$Tll,$Zll,$Zll
++	xor	$Thh,$Zhh,$Zhh
++	ldd	$rem($rem_4bit),$rem
++
++	xor	$rem,$Zhh,$Zhh
++	std	$Zll,8($Xi)
++	ldo	16($inp),$inp
++	std	$Zhh,0($Xi)
++	cmpb,*<> $inp,$len,L\$outer_ghash_pa2
++	copy	$Zll,$nlo
++___
++
++$code.=<<___ if ($SIZE_T==4);
++	b	L\$done_ghash
++	nop
++
++L\$parisc1_ghash
++	ldb	15($Xi),$nlo
++	ldo	12($Htbl),$Hll
++	ldo	8($Htbl),$Hlh
++	ldo	4($Htbl),$Hhl
++
++L\$outer_ghash_pa1
++	ldb	15($inp),$byte
++	xor	$byte,$nlo,$nlo
++	and	$mask0xf0,$nlo,$nhi
++	zdep	$nlo,27,4,$nlo
++
++	ldwx	$nlo($Hll),$Zll
++	ldwx	$nlo($Hlh),$Zlh
++	ldwx	$nlo($Hhl),$Zhl
++	ldwx	$nlo($Hhh),$Zhh
++	zdep	$Zll,28,4,$rem
++	ldb	14($Xi),$nlo
++	ldb	14($inp),$byte
++	ldwx	$rem($rem_4bit),$rem
++	shrpw	$Zlh,$Zll,4,$Zll
++	ldwx	$nhi($Hll),$Tll
++	shrpw	$Zhl,$Zlh,4,$Zlh
++	ldwx	$nhi($Hlh),$Tlh
++	shrpw	$Zhh,$Zhl,4,$Zhl
++	ldwx	$nhi($Hhl),$Thl
++	extru	$Zhh,27,28,$Zhh
++	ldwx	$nhi($Hhh),$Thh
++	xor	$byte,$nlo,$nlo
++	xor	$rem,$Zhh,$Zhh
++	and	$mask0xf0,$nlo,$nhi
++	zdep	$nlo,27,4,$nlo
++
++	xor	$Tll,$Zll,$Zll
++	ldwx	$nlo($Hll),$Tll
++	xor	$Tlh,$Zlh,$Zlh
++	ldwx	$nlo($Hlh),$Tlh
++	xor	$Thl,$Zhl,$Zhl
++	b	L\$oop_ghash_pa1
++	ldi	13,$cnt
++
++	.ALIGN	8
++L\$oop_ghash_pa1
++	zdep	$Zll,28,4,$rem
++	ldwx	$nlo($Hhl),$Thl
++	xor	$Thh,$Zhh,$Zhh
++	ldwx	$rem($rem_4bit),$rem
++	shrpw	$Zlh,$Zll,4,$Zll
++	ldwx	$nlo($Hhh),$Thh
++	shrpw	$Zhl,$Zlh,4,$Zlh
++	ldbx	$cnt($Xi),$nlo
++	xor	$Tll,$Zll,$Zll
++	ldwx	$nhi($Hll),$Tll
++	shrpw	$Zhh,$Zhl,4,$Zhl
++	ldbx	$cnt($inp),$byte
++	xor	$Tlh,$Zlh,$Zlh
++	ldwx	$nhi($Hlh),$Tlh
++	extru	$Zhh,27,28,$Zhh
++	xor	$Thl,$Zhl,$Zhl
++	ldwx	$nhi($Hhl),$Thl
++	xor	$rem,$Zhh,$Zhh
++	zdep	$Zll,28,4,$rem
++	xor	$Thh,$Zhh,$Zhh
++	ldwx	$nhi($Hhh),$Thh
++	shrpw	$Zlh,$Zll,4,$Zll
++	ldwx	$rem($rem_4bit),$rem
++	shrpw	$Zhl,$Zlh,4,$Zlh
++	xor	$byte,$nlo,$nlo
++	shrpw	$Zhh,$Zhl,4,$Zhl
++	and	$mask0xf0,$nlo,$nhi
++	extru	$Zhh,27,28,$Zhh
++	zdep	$nlo,27,4,$nlo
++	xor	$Tll,$Zll,$Zll
++	ldwx	$nlo($Hll),$Tll
++	xor	$Tlh,$Zlh,$Zlh
++	ldwx	$nlo($Hlh),$Tlh
++	xor	$rem,$Zhh,$Zhh
++	addib,uv -1,$cnt,L\$oop_ghash_pa1
++	xor	$Thl,$Zhl,$Zhl
++
++	zdep	$Zll,28,4,$rem
++	ldwx	$nlo($Hhl),$Thl
++	xor	$Thh,$Zhh,$Zhh
++	ldwx	$rem($rem_4bit),$rem
++	shrpw	$Zlh,$Zll,4,$Zll
++	ldwx	$nlo($Hhh),$Thh
++	shrpw	$Zhl,$Zlh,4,$Zlh
++	xor	$Tll,$Zll,$Zll
++	ldwx	$nhi($Hll),$Tll
++	shrpw	$Zhh,$Zhl,4,$Zhl
++	xor	$Tlh,$Zlh,$Zlh
++	ldwx	$nhi($Hlh),$Tlh
++	extru	$Zhh,27,28,$Zhh
++	xor	$rem,$Zhh,$Zhh
++	xor	$Thl,$Zhl,$Zhl
++	ldwx	$nhi($Hhl),$Thl
++	xor	$Thh,$Zhh,$Zhh
++	ldwx	$nhi($Hhh),$Thh
++	zdep	$Zll,28,4,$rem
++	ldwx	$rem($rem_4bit),$rem
++	shrpw	$Zlh,$Zll,4,$Zll
++	shrpw	$Zhl,$Zlh,4,$Zlh
++	shrpw	$Zhh,$Zhl,4,$Zhl
++	extru	$Zhh,27,28,$Zhh
++	xor	$Tll,$Zll,$Zll
++	xor	$Tlh,$Zlh,$Zlh
++	xor	$rem,$Zhh,$Zhh
++	stw	$Zll,12($Xi)
++	xor	$Thl,$Zhl,$Zhl
++	stw	$Zlh,8($Xi)
++	xor	$Thh,$Zhh,$Zhh
++	stw	$Zhl,4($Xi)
++	ldo	16($inp),$inp
++	stw	$Zhh,0($Xi)
++	comb,<>	$inp,$len,L\$outer_ghash_pa1
++	copy	$Zll,$nlo
++___
++$code.=<<___;
++L\$done_ghash
++	$POP	`-$FRAME-$SAVED_RP`(%sp),%r2		; standard epilogue
++	$POP	`-$FRAME+1*$SIZE_T`(%sp),%r4
++	$POP	`-$FRAME+2*$SIZE_T`(%sp),%r5
++	$POP	`-$FRAME+3*$SIZE_T`(%sp),%r6
++___
++$code.=<<___ if ($SIZE_T==4);
++	$POP	`-$FRAME+4*$SIZE_T`(%sp),%r7
++	$POP	`-$FRAME+5*$SIZE_T`(%sp),%r8
++	$POP	`-$FRAME+6*$SIZE_T`(%sp),%r9
++	$POP	`-$FRAME+7*$SIZE_T`(%sp),%r10
++	$POP	`-$FRAME+8*$SIZE_T`(%sp),%r11
++___
++$code.=<<___;
++	bv	(%r2)
++	.EXIT
++	$POPMB	-$FRAME(%sp),%r3
++	.PROCEND
++
++	.ALIGN	64
++L\$rem_4bit
++	.WORD	`0x0000<<16`,0,`0x1C20<<16`,0,`0x3840<<16`,0,`0x2460<<16`,0
++	.WORD	`0x7080<<16`,0,`0x6CA0<<16`,0,`0x48C0<<16`,0,`0x54E0<<16`,0
++	.WORD	`0xE100<<16`,0,`0xFD20<<16`,0,`0xD940<<16`,0,`0xC560<<16`,0
++	.WORD	`0x9180<<16`,0,`0x8DA0<<16`,0,`0xA9C0<<16`,0,`0xB5E0<<16`,0
++	.STRINGZ "GHASH for PA-RISC, GRYPTOGAMS by "
++	.ALIGN	64
++___
++
++# Explicitly encode PA-RISC 2.0 instructions used in this module, so
++# that it can be compiled with .LEVEL 1.0. It should be noted that I
++# wouldn't have to do this, if GNU assembler understood .ALLOW 2.0
++# directive...
++
++my $ldd = sub {
++  my ($mod,$args) = @_;
++  my $orig = "ldd$mod\t$args";
++
++    if ($args =~ /%r([0-9]+)\(%r([0-9]+)\),%r([0-9]+)/)		# format 4
++    {	my $opcode=(0x03<<26)|($2<<21)|($1<<16)|(3<<6)|$3;
++	sprintf "\t.WORD\t0x%08x\t; %s",$opcode,$orig;
++    }
++    elsif ($args =~ /(\-?[0-9]+)\(%r([0-9]+)\),%r([0-9]+)/)	# format 5
++    {	my $opcode=(0x03<<26)|($2<<21)|(1<<12)|(3<<6)|$3;
++	$opcode|=(($1&0xF)<<17)|(($1&0x10)<<12);		# encode offset
++	$opcode|=(1<<5)  if ($mod =~ /^,m/);
++	$opcode|=(1<<13) if ($mod =~ /^,mb/);
++	sprintf "\t.WORD\t0x%08x\t; %s",$opcode,$orig;
++    }
++    else { "\t".$orig; }
++};
++
++my $std = sub {
++  my ($mod,$args) = @_;
++  my $orig = "std$mod\t$args";
++
++    if ($args =~ /%r([0-9]+),(\-?[0-9]+)\(%r([0-9]+)\)/) # format 3 suffices
++    {	my $opcode=(0x1c<<26)|($3<<21)|($1<<16)|(($2&0x1FF8)<<1)|(($2>>13)&1);
++	sprintf "\t.WORD\t0x%08x\t; %s",$opcode,$orig;
++    }
++    else { "\t".$orig; }
++};
++
++my $extrd = sub {
++  my ($mod,$args) = @_;
++  my $orig = "extrd$mod\t$args";
++
++    # I only have ",u" completer, it's implicitly encoded...
++    if ($args =~ /%r([0-9]+),([0-9]+),([0-9]+),%r([0-9]+)/)	# format 15
++    {	my $opcode=(0x36<<26)|($1<<21)|($4<<16);
++	my $len=32-$3;
++	$opcode |= (($2&0x20)<<6)|(($2&0x1f)<<5);		# encode pos
++	$opcode |= (($len&0x20)<<7)|($len&0x1f);		# encode len
++	sprintf "\t.WORD\t0x%08x\t; %s",$opcode,$orig;
++    }
++    elsif ($args =~ /%r([0-9]+),%sar,([0-9]+),%r([0-9]+)/)	# format 12
++    {	my $opcode=(0x34<<26)|($1<<21)|($3<<16)|(2<<11)|(1<<9);
++	my $len=32-$2;
++	$opcode |= (($len&0x20)<<3)|($len&0x1f);		# encode len
++	$opcode |= (1<<13) if ($mod =~ /,\**=/);
++	sprintf "\t.WORD\t0x%08x\t; %s",$opcode,$orig;
++    }
++    else { "\t".$orig; }
++};
++
++my $shrpd = sub {
++  my ($mod,$args) = @_;
++  my $orig = "shrpd$mod\t$args";
++
++    if ($args =~ /%r([0-9]+),%r([0-9]+),([0-9]+),%r([0-9]+)/)	# format 14
++    {	my $opcode=(0x34<<26)|($2<<21)|($1<<16)|(1<<10)|$4;
++	my $cpos=63-$3;
++	$opcode |= (($cpos&0x20)<<6)|(($cpos&0x1f)<<5);		# encode sa
++	sprintf "\t.WORD\t0x%08x\t; %s",$opcode,$orig;
++    }
++    elsif ($args =~ /%r([0-9]+),%r([0-9]+),%sar,%r([0-9]+)/)	# format 11
++    {	sprintf "\t.WORD\t0x%08x\t; %s",
++		(0x34<<26)|($2<<21)|($1<<16)|(1<<9)|$3,$orig;
++    }
++    else { "\t".$orig; }
++};
++
++my $depd = sub {
++  my ($mod,$args) = @_;
++  my $orig = "depd$mod\t$args";
++
++    # I only have ",z" completer, it's impicitly encoded...
++    if ($args =~ /%r([0-9]+),([0-9]+),([0-9]+),%r([0-9]+)/)	# format 16
++    {	my $opcode=(0x3c<<26)|($4<<21)|($1<<16);
++    	my $cpos=63-$2;
++	my $len=32-$3;
++	$opcode |= (($cpos&0x20)<<6)|(($cpos&0x1f)<<5);		# encode pos
++	$opcode |= (($len&0x20)<<7)|($len&0x1f);		# encode len
++	sprintf "\t.WORD\t0x%08x\t; %s",$opcode,$orig;
++    }
++    else { "\t".$orig; }
++};
++
++sub assemble {
++  my ($mnemonic,$mod,$args)=@_;
++  my $opcode = eval("\$$mnemonic");
++
++    ref($opcode) eq 'CODE' ? &$opcode($mod,$args) : "\t$mnemonic$mod\t$args";
++}
++
++foreach (split("\n",$code)) {
++	s/\`([^\`]*)\`/eval $1/ge;
++	if ($SIZE_T==4) {
++		s/^\s+([a-z]+)([\S]*)\s+([\S]*)/&assemble($1,$2,$3)/e;
++		s/cmpb,\*/comb,/;
++		s/,\*/,/;
++	}
++	s/\bbv\b/bve/	if ($SIZE_T==8);
++	print $_,"\n";
++}
++
++close STDOUT;
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/modes/asm/ghash-s390x.pl b/CryptoPkg/Library/OpensslLib/openssl/crypto/modes/asm/ghash-s390x.pl
+new file mode 100644
+index 0000000..65ffaf9
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/modes/asm/ghash-s390x.pl
+@@ -0,0 +1,267 @@
++#! /usr/bin/env perl
++# Copyright 2010-2016 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
++# in the file LICENSE in the source distribution or at
++# https://www.openssl.org/source/license.html
++
++
++# ====================================================================
++# Written by Andy Polyakov  for the OpenSSL
++# project. The module is, however, dual licensed under OpenSSL and
++# CRYPTOGAMS licenses depending on where you obtain it. For further
++# details see http://www.openssl.org/~appro/cryptogams/.
++# ====================================================================
++
++# September 2010.
++#
++# The module implements "4-bit" GCM GHASH function and underlying
++# single multiplication operation in GF(2^128). "4-bit" means that it
++# uses 256 bytes per-key table [+128 bytes shared table]. Performance
++# was measured to be ~18 cycles per processed byte on z10, which is
++# almost 40% better than gcc-generated code. It should be noted that
++# 18 cycles is worse result than expected: loop is scheduled for 12
++# and the result should be close to 12. In the lack of instruction-
++# level profiling data it's impossible to tell why...
++
++# November 2010.
++#
++# Adapt for -m31 build. If kernel supports what's called "highgprs"
++# feature on Linux [see /proc/cpuinfo], it's possible to use 64-bit
++# instructions and achieve "64-bit" performance even in 31-bit legacy
++# application context. The feature is not specific to any particular
++# processor, as long as it's "z-CPU". Latter implies that the code
++# remains z/Architecture specific. On z990 it was measured to perform
++# 2.8x better than 32-bit code generated by gcc 4.3.
++
++# March 2011.
++#
++# Support for hardware KIMD-GHASH is verified to produce correct
++# result and therefore is engaged. On z196 it was measured to process
++# 8KB buffer ~7 faster than software implementation. It's not as
++# impressive for smaller buffer sizes and for smallest 16-bytes buffer
++# it's actually almost 2 times slower. Which is the reason why
++# KIMD-GHASH is not used in gcm_gmult_4bit.
++
++$flavour = shift;
++
++if ($flavour =~ /3[12]/) {
++	$SIZE_T=4;
++	$g="";
++} else {
++	$SIZE_T=8;
++	$g="g";
++}
++
++while (($output=shift) && ($output!~/\w[\w\-]*\.\w+$/)) {}
++open STDOUT,">$output";
++
++$softonly=0;
++
++$Zhi="%r0";
++$Zlo="%r1";
++
++$Xi="%r2";	# argument block
++$Htbl="%r3";
++$inp="%r4";
++$len="%r5";
++
++$rem0="%r6";	# variables
++$rem1="%r7";
++$nlo="%r8";
++$nhi="%r9";
++$xi="%r10";
++$cnt="%r11";
++$tmp="%r12";
++$x78="%r13";
++$rem_4bit="%r14";
++
++$sp="%r15";
++
++$code.=<<___;
++.text
++
++.globl	gcm_gmult_4bit
++.align	32
++gcm_gmult_4bit:
++___
++$code.=<<___ if(!$softonly && 0);	# hardware is slow for single block...
++	larl	%r1,OPENSSL_s390xcap_P
++	lg	%r0,0(%r1)
++	tmhl	%r0,0x4000	# check for message-security-assist
++	jz	.Lsoft_gmult
++	lghi	%r0,0
++	lg	%r1,24(%r1)	# load second word of kimd capabilities vector
++	tmhh	%r1,0x4000	# check for function 65
++	jz	.Lsoft_gmult
++	stg	%r0,16($sp)	# arrange 16 bytes of zero input
++	stg	%r0,24($sp)
++	lghi	%r0,65		# function 65
++	la	%r1,0($Xi)	# H lies right after Xi in gcm128_context
++	la	$inp,16($sp)
++	lghi	$len,16
++	.long	0xb93e0004	# kimd %r0,$inp
++	brc	1,.-4		# pay attention to "partial completion"
++	br	%r14
++.align	32
++.Lsoft_gmult:
++___
++$code.=<<___;
++	stm${g}	%r6,%r14,6*$SIZE_T($sp)
++
++	aghi	$Xi,-1
++	lghi	$len,1
++	lghi	$x78,`0xf<<3`
++	larl	$rem_4bit,rem_4bit
++
++	lg	$Zlo,8+1($Xi)		# Xi
++	j	.Lgmult_shortcut
++.type	gcm_gmult_4bit,\@function
++.size	gcm_gmult_4bit,(.-gcm_gmult_4bit)
++
++.globl	gcm_ghash_4bit
++.align	32
++gcm_ghash_4bit:
++___
++$code.=<<___ if(!$softonly);
++	larl	%r1,OPENSSL_s390xcap_P
++	lg	%r0,0(%r1)
++	tmhl	%r0,0x4000	# check for message-security-assist
++	jz	.Lsoft_ghash
++	lghi	%r0,0
++	la	%r1,16($sp)
++	.long	0xb93e0004	# kimd %r0,%r4
++	lg	%r1,24($sp)
++	tmhh	%r1,0x4000	# check for function 65
++	jz	.Lsoft_ghash
++	lghi	%r0,65		# function 65
++	la	%r1,0($Xi)	# H lies right after Xi in gcm128_context
++	.long	0xb93e0004	# kimd %r0,$inp
++	brc	1,.-4		# pay attention to "partial completion"
++	br	%r14
++.align	32
++.Lsoft_ghash:
++___
++$code.=<<___ if ($flavour =~ /3[12]/);
++	llgfr	$len,$len
++___
++$code.=<<___;
++	stm${g}	%r6,%r14,6*$SIZE_T($sp)
++
++	aghi	$Xi,-1
++	srlg	$len,$len,4
++	lghi	$x78,`0xf<<3`
++	larl	$rem_4bit,rem_4bit
++
++	lg	$Zlo,8+1($Xi)		# Xi
++	lg	$Zhi,0+1($Xi)
++	lghi	$tmp,0
++.Louter:
++	xg	$Zhi,0($inp)		# Xi ^= inp 
++	xg	$Zlo,8($inp)
++	xgr	$Zhi,$tmp
++	stg	$Zlo,8+1($Xi)
++	stg	$Zhi,0+1($Xi)
++
++.Lgmult_shortcut:
++	lghi	$tmp,0xf0
++	sllg	$nlo,$Zlo,4
++	srlg	$xi,$Zlo,8		# extract second byte
++	ngr	$nlo,$tmp
++	lgr	$nhi,$Zlo
++	lghi	$cnt,14
++	ngr	$nhi,$tmp
++
++	lg	$Zlo,8($nlo,$Htbl)
++	lg	$Zhi,0($nlo,$Htbl)
++
++	sllg	$nlo,$xi,4
++	sllg	$rem0,$Zlo,3
++	ngr	$nlo,$tmp
++	ngr	$rem0,$x78
++	ngr	$xi,$tmp
++
++	sllg	$tmp,$Zhi,60
++	srlg	$Zlo,$Zlo,4
++	srlg	$Zhi,$Zhi,4
++	xg	$Zlo,8($nhi,$Htbl)
++	xg	$Zhi,0($nhi,$Htbl)
++	lgr	$nhi,$xi
++	sllg	$rem1,$Zlo,3
++	xgr	$Zlo,$tmp
++	ngr	$rem1,$x78
++	sllg	$tmp,$Zhi,60
++	j	.Lghash_inner
++.align	16
++.Lghash_inner:
++	srlg	$Zlo,$Zlo,4
++	srlg	$Zhi,$Zhi,4
++	xg	$Zlo,8($nlo,$Htbl)
++	llgc	$xi,0($cnt,$Xi)
++	xg	$Zhi,0($nlo,$Htbl)
++	sllg	$nlo,$xi,4
++	xg	$Zhi,0($rem0,$rem_4bit)
++	nill	$nlo,0xf0
++	sllg	$rem0,$Zlo,3
++	xgr	$Zlo,$tmp
++	ngr	$rem0,$x78
++	nill	$xi,0xf0
++
++	sllg	$tmp,$Zhi,60
++	srlg	$Zlo,$Zlo,4
++	srlg	$Zhi,$Zhi,4
++	xg	$Zlo,8($nhi,$Htbl)
++	xg	$Zhi,0($nhi,$Htbl)
++	lgr	$nhi,$xi
++	xg	$Zhi,0($rem1,$rem_4bit)
++	sllg	$rem1,$Zlo,3
++	xgr	$Zlo,$tmp
++	ngr	$rem1,$x78
++	sllg	$tmp,$Zhi,60
++	brct	$cnt,.Lghash_inner
++
++	srlg	$Zlo,$Zlo,4
++	srlg	$Zhi,$Zhi,4
++	xg	$Zlo,8($nlo,$Htbl)
++	xg	$Zhi,0($nlo,$Htbl)
++	sllg	$xi,$Zlo,3
++	xg	$Zhi,0($rem0,$rem_4bit)
++	xgr	$Zlo,$tmp
++	ngr	$xi,$x78
++
++	sllg	$tmp,$Zhi,60
++	srlg	$Zlo,$Zlo,4
++	srlg	$Zhi,$Zhi,4
++	xg	$Zlo,8($nhi,$Htbl)
++	xg	$Zhi,0($nhi,$Htbl)
++	xgr	$Zlo,$tmp
++	xg	$Zhi,0($rem1,$rem_4bit)
++
++	lg	$tmp,0($xi,$rem_4bit)
++	la	$inp,16($inp)
++	sllg	$tmp,$tmp,4		# correct last rem_4bit[rem]
++	brctg	$len,.Louter
++
++	xgr	$Zhi,$tmp
++	stg	$Zlo,8+1($Xi)
++	stg	$Zhi,0+1($Xi)
++	lm${g}	%r6,%r14,6*$SIZE_T($sp)
++	br	%r14
++.type	gcm_ghash_4bit,\@function
++.size	gcm_ghash_4bit,(.-gcm_ghash_4bit)
++
++.align	64
++rem_4bit:
++	.long	`0x0000<<12`,0,`0x1C20<<12`,0,`0x3840<<12`,0,`0x2460<<12`,0
++	.long	`0x7080<<12`,0,`0x6CA0<<12`,0,`0x48C0<<12`,0,`0x54E0<<12`,0
++	.long	`0xE100<<12`,0,`0xFD20<<12`,0,`0xD940<<12`,0,`0xC560<<12`,0
++	.long	`0x9180<<12`,0,`0x8DA0<<12`,0,`0xA9C0<<12`,0,`0xB5E0<<12`,0
++.type	rem_4bit,\@object
++.size	rem_4bit,(.-rem_4bit)
++.string	"GHASH for s390x, CRYPTOGAMS by "
++___
++
++$code =~ s/\`([^\`]*)\`/eval $1/gem;
++print $code;
++close STDOUT;
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/modes/asm/ghash-sparcv9.pl b/CryptoPkg/Library/OpensslLib/openssl/crypto/modes/asm/ghash-sparcv9.pl
+new file mode 100644
+index 0000000..c4eb3b1
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/modes/asm/ghash-sparcv9.pl
+@@ -0,0 +1,581 @@
++#! /usr/bin/env perl
++# Copyright 2010-2016 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
++# in the file LICENSE in the source distribution or at
++# https://www.openssl.org/source/license.html
++
++
++# ====================================================================
++# Written by Andy Polyakov  for the OpenSSL
++# project. The module is, however, dual licensed under OpenSSL and
++# CRYPTOGAMS licenses depending on where you obtain it. For further
++# details see http://www.openssl.org/~appro/cryptogams/.
++# ====================================================================
++
++# March 2010
++#
++# The module implements "4-bit" GCM GHASH function and underlying
++# single multiplication operation in GF(2^128). "4-bit" means that it
++# uses 256 bytes per-key table [+128 bytes shared table]. Performance
++# results are for streamed GHASH subroutine on UltraSPARC pre-Tx CPU
++# and are expressed in cycles per processed byte, less is better:
++#
++#		gcc 3.3.x	cc 5.2		this assembler
++#
++# 32-bit build	81.4		43.3		12.6	(+546%/+244%)
++# 64-bit build	20.2		21.2		12.6	(+60%/+68%)
++#
++# Here is data collected on UltraSPARC T1 system running Linux:
++#
++#		gcc 4.4.1			this assembler
++#
++# 32-bit build	566				50	(+1000%)
++# 64-bit build	56				50	(+12%)
++#
++# I don't quite understand why difference between 32-bit and 64-bit
++# compiler-generated code is so big. Compilers *were* instructed to
++# generate code for UltraSPARC and should have used 64-bit registers
++# for Z vector (see C code) even in 32-bit build... Oh well, it only
++# means more impressive improvement coefficients for this assembler
++# module;-) Loops are aggressively modulo-scheduled in respect to
++# references to input data and Z.hi updates to achieve 12 cycles
++# timing. To anchor to something else, sha1-sparcv9.pl spends 11.6
++# cycles to process one byte on UltraSPARC pre-Tx CPU and ~24 on T1.
++#
++# October 2012
++#
++# Add VIS3 lookup-table-free implementation using polynomial
++# multiplication xmulx[hi] and extended addition addxc[cc]
++# instructions. 4.52/7.63x improvement on T3/T4 or in absolute
++# terms 7.90/2.14 cycles per byte. On T4 multi-process benchmark
++# saturates at ~15.5x single-process result on 8-core processor,
++# or ~20.5GBps per 2.85GHz socket.
++
++$output=pop;
++open STDOUT,">$output";
++
++$frame="STACK_FRAME";
++$bias="STACK_BIAS";
++
++$Zhi="%o0";	# 64-bit values
++$Zlo="%o1";
++$Thi="%o2";
++$Tlo="%o3";
++$rem="%o4";
++$tmp="%o5";
++
++$nhi="%l0";	# small values and pointers
++$nlo="%l1";
++$xi0="%l2";
++$xi1="%l3";
++$rem_4bit="%l4";
++$remi="%l5";
++$Htblo="%l6";
++$cnt="%l7";
++
++$Xi="%i0";	# input argument block
++$Htbl="%i1";
++$inp="%i2";
++$len="%i3";
++
++$code.=<<___;
++#include "sparc_arch.h"
++
++#ifdef  __arch64__
++.register	%g2,#scratch
++.register	%g3,#scratch
++#endif
++
++.section	".text",#alloc,#execinstr
++
++.align	64
++rem_4bit:
++	.long	`0x0000<<16`,0,`0x1C20<<16`,0,`0x3840<<16`,0,`0x2460<<16`,0
++	.long	`0x7080<<16`,0,`0x6CA0<<16`,0,`0x48C0<<16`,0,`0x54E0<<16`,0
++	.long	`0xE100<<16`,0,`0xFD20<<16`,0,`0xD940<<16`,0,`0xC560<<16`,0
++	.long	`0x9180<<16`,0,`0x8DA0<<16`,0,`0xA9C0<<16`,0,`0xB5E0<<16`,0
++.type	rem_4bit,#object
++.size	rem_4bit,(.-rem_4bit)
++
++.globl	gcm_ghash_4bit
++.align	32
++gcm_ghash_4bit:
++	save	%sp,-$frame,%sp
++	ldub	[$inp+15],$nlo
++	ldub	[$Xi+15],$xi0
++	ldub	[$Xi+14],$xi1
++	add	$len,$inp,$len
++	add	$Htbl,8,$Htblo
++
++1:	call	.+8
++	add	%o7,rem_4bit-1b,$rem_4bit
++
++.Louter:
++	xor	$xi0,$nlo,$nlo
++	and	$nlo,0xf0,$nhi
++	and	$nlo,0x0f,$nlo
++	sll	$nlo,4,$nlo
++	ldx	[$Htblo+$nlo],$Zlo
++	ldx	[$Htbl+$nlo],$Zhi
++
++	ldub	[$inp+14],$nlo
++
++	ldx	[$Htblo+$nhi],$Tlo
++	and	$Zlo,0xf,$remi
++	ldx	[$Htbl+$nhi],$Thi
++	sll	$remi,3,$remi
++	ldx	[$rem_4bit+$remi],$rem
++	srlx	$Zlo,4,$Zlo
++	mov	13,$cnt
++	sllx	$Zhi,60,$tmp
++	xor	$Tlo,$Zlo,$Zlo
++	srlx	$Zhi,4,$Zhi
++	xor	$Zlo,$tmp,$Zlo
++
++	xor	$xi1,$nlo,$nlo
++	and	$Zlo,0xf,$remi
++	and	$nlo,0xf0,$nhi
++	and	$nlo,0x0f,$nlo
++	ba	.Lghash_inner
++	sll	$nlo,4,$nlo
++.align	32
++.Lghash_inner:
++	ldx	[$Htblo+$nlo],$Tlo
++	sll	$remi,3,$remi
++	xor	$Thi,$Zhi,$Zhi
++	ldx	[$Htbl+$nlo],$Thi
++	srlx	$Zlo,4,$Zlo
++	xor	$rem,$Zhi,$Zhi
++	ldx	[$rem_4bit+$remi],$rem
++	sllx	$Zhi,60,$tmp
++	xor	$Tlo,$Zlo,$Zlo
++	ldub	[$inp+$cnt],$nlo
++	srlx	$Zhi,4,$Zhi
++	xor	$Zlo,$tmp,$Zlo
++	ldub	[$Xi+$cnt],$xi1
++	xor	$Thi,$Zhi,$Zhi
++	and	$Zlo,0xf,$remi
++
++	ldx	[$Htblo+$nhi],$Tlo
++	sll	$remi,3,$remi
++	xor	$rem,$Zhi,$Zhi
++	ldx	[$Htbl+$nhi],$Thi
++	srlx	$Zlo,4,$Zlo
++	ldx	[$rem_4bit+$remi],$rem
++	sllx	$Zhi,60,$tmp
++	xor	$xi1,$nlo,$nlo
++	srlx	$Zhi,4,$Zhi
++	and	$nlo,0xf0,$nhi
++	addcc	$cnt,-1,$cnt
++	xor	$Zlo,$tmp,$Zlo
++	and	$nlo,0x0f,$nlo
++	xor	$Tlo,$Zlo,$Zlo
++	sll	$nlo,4,$nlo
++	blu	.Lghash_inner
++	and	$Zlo,0xf,$remi
++
++	ldx	[$Htblo+$nlo],$Tlo
++	sll	$remi,3,$remi
++	xor	$Thi,$Zhi,$Zhi
++	ldx	[$Htbl+$nlo],$Thi
++	srlx	$Zlo,4,$Zlo
++	xor	$rem,$Zhi,$Zhi
++	ldx	[$rem_4bit+$remi],$rem
++	sllx	$Zhi,60,$tmp
++	xor	$Tlo,$Zlo,$Zlo
++	srlx	$Zhi,4,$Zhi
++	xor	$Zlo,$tmp,$Zlo
++	xor	$Thi,$Zhi,$Zhi
++
++	add	$inp,16,$inp
++	cmp	$inp,$len
++	be,pn	SIZE_T_CC,.Ldone
++	and	$Zlo,0xf,$remi
++
++	ldx	[$Htblo+$nhi],$Tlo
++	sll	$remi,3,$remi
++	xor	$rem,$Zhi,$Zhi
++	ldx	[$Htbl+$nhi],$Thi
++	srlx	$Zlo,4,$Zlo
++	ldx	[$rem_4bit+$remi],$rem
++	sllx	$Zhi,60,$tmp
++	xor	$Tlo,$Zlo,$Zlo
++	ldub	[$inp+15],$nlo
++	srlx	$Zhi,4,$Zhi
++	xor	$Zlo,$tmp,$Zlo
++	xor	$Thi,$Zhi,$Zhi
++	stx	$Zlo,[$Xi+8]
++	xor	$rem,$Zhi,$Zhi
++	stx	$Zhi,[$Xi]
++	srl	$Zlo,8,$xi1
++	and	$Zlo,0xff,$xi0
++	ba	.Louter
++	and	$xi1,0xff,$xi1
++.align	32
++.Ldone:
++	ldx	[$Htblo+$nhi],$Tlo
++	sll	$remi,3,$remi
++	xor	$rem,$Zhi,$Zhi
++	ldx	[$Htbl+$nhi],$Thi
++	srlx	$Zlo,4,$Zlo
++	ldx	[$rem_4bit+$remi],$rem
++	sllx	$Zhi,60,$tmp
++	xor	$Tlo,$Zlo,$Zlo
++	srlx	$Zhi,4,$Zhi
++	xor	$Zlo,$tmp,$Zlo
++	xor	$Thi,$Zhi,$Zhi
++	stx	$Zlo,[$Xi+8]
++	xor	$rem,$Zhi,$Zhi
++	stx	$Zhi,[$Xi]
++
++	ret
++	restore
++.type	gcm_ghash_4bit,#function
++.size	gcm_ghash_4bit,(.-gcm_ghash_4bit)
++___
++
++undef $inp;
++undef $len;
++
++$code.=<<___;
++.globl	gcm_gmult_4bit
++.align	32
++gcm_gmult_4bit:
++	save	%sp,-$frame,%sp
++	ldub	[$Xi+15],$nlo
++	add	$Htbl,8,$Htblo
++
++1:	call	.+8
++	add	%o7,rem_4bit-1b,$rem_4bit
++
++	and	$nlo,0xf0,$nhi
++	and	$nlo,0x0f,$nlo
++	sll	$nlo,4,$nlo
++	ldx	[$Htblo+$nlo],$Zlo
++	ldx	[$Htbl+$nlo],$Zhi
++
++	ldub	[$Xi+14],$nlo
++
++	ldx	[$Htblo+$nhi],$Tlo
++	and	$Zlo,0xf,$remi
++	ldx	[$Htbl+$nhi],$Thi
++	sll	$remi,3,$remi
++	ldx	[$rem_4bit+$remi],$rem
++	srlx	$Zlo,4,$Zlo
++	mov	13,$cnt
++	sllx	$Zhi,60,$tmp
++	xor	$Tlo,$Zlo,$Zlo
++	srlx	$Zhi,4,$Zhi
++	xor	$Zlo,$tmp,$Zlo
++
++	and	$Zlo,0xf,$remi
++	and	$nlo,0xf0,$nhi
++	and	$nlo,0x0f,$nlo
++	ba	.Lgmult_inner
++	sll	$nlo,4,$nlo
++.align	32
++.Lgmult_inner:
++	ldx	[$Htblo+$nlo],$Tlo
++	sll	$remi,3,$remi
++	xor	$Thi,$Zhi,$Zhi
++	ldx	[$Htbl+$nlo],$Thi
++	srlx	$Zlo,4,$Zlo
++	xor	$rem,$Zhi,$Zhi
++	ldx	[$rem_4bit+$remi],$rem
++	sllx	$Zhi,60,$tmp
++	xor	$Tlo,$Zlo,$Zlo
++	ldub	[$Xi+$cnt],$nlo
++	srlx	$Zhi,4,$Zhi
++	xor	$Zlo,$tmp,$Zlo
++	xor	$Thi,$Zhi,$Zhi
++	and	$Zlo,0xf,$remi
++
++	ldx	[$Htblo+$nhi],$Tlo
++	sll	$remi,3,$remi
++	xor	$rem,$Zhi,$Zhi
++	ldx	[$Htbl+$nhi],$Thi
++	srlx	$Zlo,4,$Zlo
++	ldx	[$rem_4bit+$remi],$rem
++	sllx	$Zhi,60,$tmp
++	srlx	$Zhi,4,$Zhi
++	and	$nlo,0xf0,$nhi
++	addcc	$cnt,-1,$cnt
++	xor	$Zlo,$tmp,$Zlo
++	and	$nlo,0x0f,$nlo
++	xor	$Tlo,$Zlo,$Zlo
++	sll	$nlo,4,$nlo
++	blu	.Lgmult_inner
++	and	$Zlo,0xf,$remi
++
++	ldx	[$Htblo+$nlo],$Tlo
++	sll	$remi,3,$remi
++	xor	$Thi,$Zhi,$Zhi
++	ldx	[$Htbl+$nlo],$Thi
++	srlx	$Zlo,4,$Zlo
++	xor	$rem,$Zhi,$Zhi
++	ldx	[$rem_4bit+$remi],$rem
++	sllx	$Zhi,60,$tmp
++	xor	$Tlo,$Zlo,$Zlo
++	srlx	$Zhi,4,$Zhi
++	xor	$Zlo,$tmp,$Zlo
++	xor	$Thi,$Zhi,$Zhi
++	and	$Zlo,0xf,$remi
++
++	ldx	[$Htblo+$nhi],$Tlo
++	sll	$remi,3,$remi
++	xor	$rem,$Zhi,$Zhi
++	ldx	[$Htbl+$nhi],$Thi
++	srlx	$Zlo,4,$Zlo
++	ldx	[$rem_4bit+$remi],$rem
++	sllx	$Zhi,60,$tmp
++	xor	$Tlo,$Zlo,$Zlo
++	srlx	$Zhi,4,$Zhi
++	xor	$Zlo,$tmp,$Zlo
++	xor	$Thi,$Zhi,$Zhi
++	stx	$Zlo,[$Xi+8]
++	xor	$rem,$Zhi,$Zhi
++	stx	$Zhi,[$Xi]
++
++	ret
++	restore
++.type	gcm_gmult_4bit,#function
++.size	gcm_gmult_4bit,(.-gcm_gmult_4bit)
++___
++
++{{{
++# Straightforward 128x128-bit multiplication using Karatsuba algorithm
++# followed by pair of 64-bit reductions [with a shortcut in first one,
++# which allowed to break dependency between reductions and remove one
++# multiplication from critical path]. While it might be suboptimal
++# with regard to sheer number of multiplications, other methods [such
++# as aggregate reduction] would require more 64-bit registers, which
++# we don't have in 32-bit application context.
++
++($Xip,$Htable,$inp,$len)=map("%i$_",(0..3));
++
++($Hhl,$Hlo,$Hhi,$Xlo,$Xhi,$xE1,$sqr, $C0,$C1,$C2,$C3,$V)=
++	(map("%o$_",(0..5,7)),map("%g$_",(1..5)));
++
++($shl,$shr)=map("%l$_",(0..7));
++
++# For details regarding "twisted H" see ghash-x86.pl.
++$code.=<<___;
++.globl	gcm_init_vis3
++.align	32
++gcm_init_vis3:
++	save	%sp,-$frame,%sp
++
++	ldx	[%i1+0],$Hhi
++	ldx	[%i1+8],$Hlo
++	mov	0xE1,$Xhi
++	mov	1,$Xlo
++	sllx	$Xhi,57,$Xhi
++	srax	$Hhi,63,$C0		! broadcast carry
++	addcc	$Hlo,$Hlo,$Hlo		! H<<=1
++	addxc	$Hhi,$Hhi,$Hhi
++	and	$C0,$Xlo,$Xlo
++	and	$C0,$Xhi,$Xhi
++	xor	$Xlo,$Hlo,$Hlo
++	xor	$Xhi,$Hhi,$Hhi
++	stx	$Hlo,[%i0+8]		! save twisted H
++	stx	$Hhi,[%i0+0]
++
++	sethi	%hi(0xA0406080),$V
++	sethi	%hi(0x20C0E000),%l0
++	or	$V,%lo(0xA0406080),$V
++	or	%l0,%lo(0x20C0E000),%l0
++	sllx	$V,32,$V
++	or	%l0,$V,$V		! (0xE0·i)&0xff=0xA040608020C0E000
++	stx	$V,[%i0+16]
++
++	ret
++	restore
++.type	gcm_init_vis3,#function
++.size	gcm_init_vis3,.-gcm_init_vis3
++
++.globl	gcm_gmult_vis3
++.align	32
++gcm_gmult_vis3:
++	save	%sp,-$frame,%sp
++
++	ldx	[$Xip+8],$Xlo		! load Xi
++	ldx	[$Xip+0],$Xhi
++	ldx	[$Htable+8],$Hlo	! load twisted H
++	ldx	[$Htable+0],$Hhi
++
++	mov	0xE1,%l7
++	sllx	%l7,57,$xE1		! 57 is not a typo
++	ldx	[$Htable+16],$V		! (0xE0·i)&0xff=0xA040608020C0E000
++
++	xor	$Hhi,$Hlo,$Hhl		! Karatsuba pre-processing
++	xmulx	$Xlo,$Hlo,$C0
++	xor	$Xlo,$Xhi,$C2		! Karatsuba pre-processing
++	xmulx	$C2,$Hhl,$C1
++	xmulxhi	$Xlo,$Hlo,$Xlo
++	xmulxhi	$C2,$Hhl,$C2
++	xmulxhi	$Xhi,$Hhi,$C3
++	xmulx	$Xhi,$Hhi,$Xhi
++
++	sll	$C0,3,$sqr
++	srlx	$V,$sqr,$sqr		! ·0xE0 [implicit &(7<<3)]
++	xor	$C0,$sqr,$sqr
++	sllx	$sqr,57,$sqr		! ($C0·0xE1)<<1<<56 [implicit &0x7f]
++
++	xor	$C0,$C1,$C1		! Karatsuba post-processing
++	xor	$Xlo,$C2,$C2
++	 xor	$sqr,$Xlo,$Xlo		! real destination is $C1
++	xor	$C3,$C2,$C2
++	xor	$Xlo,$C1,$C1
++	xor	$Xhi,$C2,$C2
++	xor	$Xhi,$C1,$C1
++
++	xmulxhi	$C0,$xE1,$Xlo		! ·0xE1<<1<<56
++	 xor	$C0,$C2,$C2
++	xmulx	$C1,$xE1,$C0
++	 xor	$C1,$C3,$C3
++	xmulxhi	$C1,$xE1,$C1
++
++	xor	$Xlo,$C2,$C2
++	xor	$C0,$C2,$C2
++	xor	$C1,$C3,$C3
++
++	stx	$C2,[$Xip+8]		! save Xi
++	stx	$C3,[$Xip+0]
++
++	ret
++	restore
++.type	gcm_gmult_vis3,#function
++.size	gcm_gmult_vis3,.-gcm_gmult_vis3
++
++.globl	gcm_ghash_vis3
++.align	32
++gcm_ghash_vis3:
++	save	%sp,-$frame,%sp
++	nop
++	srln	$len,0,$len		! needed on v8+, "nop" on v9
++
++	ldx	[$Xip+8],$C2		! load Xi
++	ldx	[$Xip+0],$C3
++	ldx	[$Htable+8],$Hlo	! load twisted H
++	ldx	[$Htable+0],$Hhi
++
++	mov	0xE1,%l7
++	sllx	%l7,57,$xE1		! 57 is not a typo
++	ldx	[$Htable+16],$V		! (0xE0·i)&0xff=0xA040608020C0E000
++
++	and	$inp,7,$shl
++	andn	$inp,7,$inp
++	sll	$shl,3,$shl
++	prefetch [$inp+63], 20
++	sub	%g0,$shl,$shr
++
++	xor	$Hhi,$Hlo,$Hhl		! Karatsuba pre-processing
++.Loop:
++	ldx	[$inp+8],$Xlo
++	brz,pt	$shl,1f
++	ldx	[$inp+0],$Xhi
++
++	ldx	[$inp+16],$C1		! align data
++	srlx	$Xlo,$shr,$C0
++	sllx	$Xlo,$shl,$Xlo
++	sllx	$Xhi,$shl,$Xhi
++	srlx	$C1,$shr,$C1
++	or	$C0,$Xhi,$Xhi
++	or	$C1,$Xlo,$Xlo
++1:
++	add	$inp,16,$inp
++	sub	$len,16,$len
++	xor	$C2,$Xlo,$Xlo
++	xor	$C3,$Xhi,$Xhi
++	prefetch [$inp+63], 20
++
++	xmulx	$Xlo,$Hlo,$C0
++	xor	$Xlo,$Xhi,$C2		! Karatsuba pre-processing
++	xmulx	$C2,$Hhl,$C1
++	xmulxhi	$Xlo,$Hlo,$Xlo
++	xmulxhi	$C2,$Hhl,$C2
++	xmulxhi	$Xhi,$Hhi,$C3
++	xmulx	$Xhi,$Hhi,$Xhi
++
++	sll	$C0,3,$sqr
++	srlx	$V,$sqr,$sqr		! ·0xE0 [implicit &(7<<3)]
++	xor	$C0,$sqr,$sqr
++	sllx	$sqr,57,$sqr		! ($C0·0xE1)<<1<<56 [implicit &0x7f]
++
++	xor	$C0,$C1,$C1		! Karatsuba post-processing
++	xor	$Xlo,$C2,$C2
++	 xor	$sqr,$Xlo,$Xlo		! real destination is $C1
++	xor	$C3,$C2,$C2
++	xor	$Xlo,$C1,$C1
++	xor	$Xhi,$C2,$C2
++	xor	$Xhi,$C1,$C1
++
++	xmulxhi	$C0,$xE1,$Xlo		! ·0xE1<<1<<56
++	 xor	$C0,$C2,$C2
++	xmulx	$C1,$xE1,$C0
++	 xor	$C1,$C3,$C3
++	xmulxhi	$C1,$xE1,$C1
++
++	xor	$Xlo,$C2,$C2
++	xor	$C0,$C2,$C2
++	brnz,pt	$len,.Loop
++	xor	$C1,$C3,$C3
++
++	stx	$C2,[$Xip+8]		! save Xi
++	stx	$C3,[$Xip+0]
++
++	ret
++	restore
++.type	gcm_ghash_vis3,#function
++.size	gcm_ghash_vis3,.-gcm_ghash_vis3
++___
++}}}
++$code.=<<___;
++.asciz	"GHASH for SPARCv9/VIS3, CRYPTOGAMS by "
++.align	4
++___
++
++
++# Purpose of these subroutines is to explicitly encode VIS instructions,
++# so that one can compile the module without having to specify VIS
++# extensions on compiler command line, e.g. -xarch=v9 vs. -xarch=v9a.
++# Idea is to reserve for option to produce "universal" binary and let
++# programmer detect if current CPU is VIS capable at run-time.
++sub unvis3 {
++my ($mnemonic,$rs1,$rs2,$rd)=@_;
++my %bias = ( "g" => 0, "o" => 8, "l" => 16, "i" => 24 );
++my ($ref,$opf);
++my %visopf = (	"addxc"		=> 0x011,
++		"addxccc"	=> 0x013,
++		"xmulx"		=> 0x115,
++		"xmulxhi"	=> 0x116	);
++
++    $ref = "$mnemonic\t$rs1,$rs2,$rd";
++
++    if ($opf=$visopf{$mnemonic}) {
++	foreach ($rs1,$rs2,$rd) {
++	    return $ref if (!/%([goli])([0-9])/);
++	    $_=$bias{$1}+$2;
++	}
++
++	return	sprintf ".word\t0x%08x !%s",
++			0x81b00000|$rd<<25|$rs1<<14|$opf<<5|$rs2,
++			$ref;
++    } else {
++	return $ref;
++    }
++}
++
++foreach (split("\n",$code)) {
++	s/\`([^\`]*)\`/eval $1/ge;
++
++	s/\b(xmulx[hi]*|addxc[c]{0,2})\s+(%[goli][0-7]),\s*(%[goli][0-7]),\s*(%[goli][0-7])/
++		&unvis3($1,$2,$3,$4)
++	 /ge;
++
++	print $_,"\n";
++}
++
++close STDOUT;
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/modes/asm/ghash-x86.pl b/CryptoPkg/Library/OpensslLib/openssl/crypto/modes/asm/ghash-x86.pl
+new file mode 100644
+index 0000000..cd84582
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/modes/asm/ghash-x86.pl
+@@ -0,0 +1,1405 @@
++#! /usr/bin/env perl
++# Copyright 2010-2016 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
++# in the file LICENSE in the source distribution or at
++# https://www.openssl.org/source/license.html
++
++#
++# ====================================================================
++# Written by Andy Polyakov  for the OpenSSL
++# project. The module is, however, dual licensed under OpenSSL and
++# CRYPTOGAMS licenses depending on where you obtain it. For further
++# details see http://www.openssl.org/~appro/cryptogams/.
++# ====================================================================
++#
++# March, May, June 2010
++#
++# The module implements "4-bit" GCM GHASH function and underlying
++# single multiplication operation in GF(2^128). "4-bit" means that it
++# uses 256 bytes per-key table [+64/128 bytes fixed table]. It has two
++# code paths: vanilla x86 and vanilla SSE. Former will be executed on
++# 486 and Pentium, latter on all others. SSE GHASH features so called
++# "528B" variant of "4-bit" method utilizing additional 256+16 bytes
++# of per-key storage [+512 bytes shared table]. Performance results
++# are for streamed GHASH subroutine and are expressed in cycles per
++# processed byte, less is better:
++#
++#		gcc 2.95.3(*)	SSE assembler	x86 assembler
++#
++# Pentium	105/111(**)	-		50
++# PIII		68 /75		12.2		24
++# P4		125/125		17.8		84(***)
++# Opteron	66 /70		10.1		30
++# Core2		54 /67		8.4		18
++# Atom		105/105		16.8		53
++# VIA Nano	69 /71		13.0		27
++#
++# (*)	gcc 3.4.x was observed to generate few percent slower code,
++#	which is one of reasons why 2.95.3 results were chosen,
++#	another reason is lack of 3.4.x results for older CPUs;
++#	comparison with SSE results is not completely fair, because C
++#	results are for vanilla "256B" implementation, while
++#	assembler results are for "528B";-)
++# (**)	second number is result for code compiled with -fPIC flag,
++#	which is actually more relevant, because assembler code is
++#	position-independent;
++# (***)	see comment in non-MMX routine for further details;
++#
++# To summarize, it's >2-5 times faster than gcc-generated code. To
++# anchor it to something else SHA1 assembler processes one byte in
++# ~7 cycles on contemporary x86 cores. As for choice of MMX/SSE
++# in particular, see comment at the end of the file...
++
++# May 2010
++#
++# Add PCLMULQDQ version performing at 2.10 cycles per processed byte.
++# The question is how close is it to theoretical limit? The pclmulqdq
++# instruction latency appears to be 14 cycles and there can't be more
++# than 2 of them executing at any given time. This means that single
++# Karatsuba multiplication would take 28 cycles *plus* few cycles for
++# pre- and post-processing. Then multiplication has to be followed by
++# modulo-reduction. Given that aggregated reduction method [see
++# "Carry-less Multiplication and Its Usage for Computing the GCM Mode"
++# white paper by Intel] allows you to perform reduction only once in
++# a while we can assume that asymptotic performance can be estimated
++# as (28+Tmod/Naggr)/16, where Tmod is time to perform reduction
++# and Naggr is the aggregation factor.
++#
++# Before we proceed to this implementation let's have closer look at
++# the best-performing code suggested by Intel in their white paper.
++# By tracing inter-register dependencies Tmod is estimated as ~19
++# cycles and Naggr chosen by Intel is 4, resulting in 2.05 cycles per
++# processed byte. As implied, this is quite optimistic estimate,
++# because it does not account for Karatsuba pre- and post-processing,
++# which for a single multiplication is ~5 cycles. Unfortunately Intel
++# does not provide performance data for GHASH alone. But benchmarking
++# AES_GCM_encrypt ripped out of Fig. 15 of the white paper with aadt
++# alone resulted in 2.46 cycles per byte of out 16KB buffer. Note that
++# the result accounts even for pre-computing of degrees of the hash
++# key H, but its portion is negligible at 16KB buffer size.
++#
++# Moving on to the implementation in question. Tmod is estimated as
++# ~13 cycles and Naggr is 2, giving asymptotic performance of ...
++# 2.16. How is it possible that measured performance is better than
++# optimistic theoretical estimate? There is one thing Intel failed
++# to recognize. By serializing GHASH with CTR in same subroutine
++# former's performance is really limited to above (Tmul + Tmod/Naggr)
++# equation. But if GHASH procedure is detached, the modulo-reduction
++# can be interleaved with Naggr-1 multiplications at instruction level
++# and under ideal conditions even disappear from the equation. So that
++# optimistic theoretical estimate for this implementation is ...
++# 28/16=1.75, and not 2.16. Well, it's probably way too optimistic,
++# at least for such small Naggr. I'd argue that (28+Tproc/Naggr),
++# where Tproc is time required for Karatsuba pre- and post-processing,
++# is more realistic estimate. In this case it gives ... 1.91 cycles.
++# Or in other words, depending on how well we can interleave reduction
++# and one of the two multiplications the performance should be between
++# 1.91 and 2.16. As already mentioned, this implementation processes
++# one byte out of 8KB buffer in 2.10 cycles, while x86_64 counterpart
++# - in 2.02. x86_64 performance is better, because larger register
++# bank allows to interleave reduction and multiplication better.
++#
++# Does it make sense to increase Naggr? To start with it's virtually
++# impossible in 32-bit mode, because of limited register bank
++# capacity. Otherwise improvement has to be weighed agiainst slower
++# setup, as well as code size and complexity increase. As even
++# optimistic estimate doesn't promise 30% performance improvement,
++# there are currently no plans to increase Naggr.
++#
++# Special thanks to David Woodhouse  for
++# providing access to a Westmere-based system on behalf of Intel
++# Open Source Technology Centre.
++
++# January 2010
++#
++# Tweaked to optimize transitions between integer and FP operations
++# on same XMM register, PCLMULQDQ subroutine was measured to process
++# one byte in 2.07 cycles on Sandy Bridge, and in 2.12 - on Westmere.
++# The minor regression on Westmere is outweighed by ~15% improvement
++# on Sandy Bridge. Strangely enough attempt to modify 64-bit code in
++# similar manner resulted in almost 20% degradation on Sandy Bridge,
++# where original 64-bit code processes one byte in 1.95 cycles.
++
++#####################################################################
++# For reference, AMD Bulldozer processes one byte in 1.98 cycles in
++# 32-bit mode and 1.89 in 64-bit.
++
++# February 2013
++#
++# Overhaul: aggregate Karatsuba post-processing, improve ILP in
++# reduction_alg9. Resulting performance is 1.96 cycles per byte on
++# Westmere, 1.95 - on Sandy/Ivy Bridge, 1.76 - on Bulldozer.
++
++$0 =~ m/(.*[\/\\])[^\/\\]+$/; $dir=$1;
++push(@INC,"${dir}","${dir}../../perlasm");
++require "x86asm.pl";
++
++$output=pop;
++open STDOUT,">$output";
++
++&asm_init($ARGV[0],"ghash-x86.pl",$x86only = $ARGV[$#ARGV] eq "386");
++
++$sse2=0;
++for (@ARGV) { $sse2=1 if (/-DOPENSSL_IA32_SSE2/); }
++
++($Zhh,$Zhl,$Zlh,$Zll) = ("ebp","edx","ecx","ebx");
++$inp  = "edi";
++$Htbl = "esi";
++
++$unroll = 0;	# Affects x86 loop. Folded loop performs ~7% worse
++		# than unrolled, which has to be weighted against
++		# 2.5x x86-specific code size reduction.
++
++sub x86_loop {
++    my $off = shift;
++    my $rem = "eax";
++
++	&mov	($Zhh,&DWP(4,$Htbl,$Zll));
++	&mov	($Zhl,&DWP(0,$Htbl,$Zll));
++	&mov	($Zlh,&DWP(12,$Htbl,$Zll));
++	&mov	($Zll,&DWP(8,$Htbl,$Zll));
++	&xor	($rem,$rem);	# avoid partial register stalls on PIII
++
++	# shrd practically kills P4, 2.5x deterioration, but P4 has
++	# MMX code-path to execute. shrd runs tad faster [than twice
++	# the shifts, move's and or's] on pre-MMX Pentium (as well as
++	# PIII and Core2), *but* minimizes code size, spares register
++	# and thus allows to fold the loop...
++	if (!$unroll) {
++	my $cnt = $inp;
++	&mov	($cnt,15);
++	&jmp	(&label("x86_loop"));
++	&set_label("x86_loop",16);
++	    for($i=1;$i<=2;$i++) {
++		&mov	(&LB($rem),&LB($Zll));
++		&shrd	($Zll,$Zlh,4);
++		&and	(&LB($rem),0xf);
++		&shrd	($Zlh,$Zhl,4);
++		&shrd	($Zhl,$Zhh,4);
++		&shr	($Zhh,4);
++		&xor	($Zhh,&DWP($off+16,"esp",$rem,4));
++
++		&mov	(&LB($rem),&BP($off,"esp",$cnt));
++		if ($i&1) {
++			&and	(&LB($rem),0xf0);
++		} else {
++			&shl	(&LB($rem),4);
++		}
++
++		&xor	($Zll,&DWP(8,$Htbl,$rem));
++		&xor	($Zlh,&DWP(12,$Htbl,$rem));
++		&xor	($Zhl,&DWP(0,$Htbl,$rem));
++		&xor	($Zhh,&DWP(4,$Htbl,$rem));
++
++		if ($i&1) {
++			&dec	($cnt);
++			&js	(&label("x86_break"));
++		} else {
++			&jmp	(&label("x86_loop"));
++		}
++	    }
++	&set_label("x86_break",16);
++	} else {
++	    for($i=1;$i<32;$i++) {
++		&comment($i);
++		&mov	(&LB($rem),&LB($Zll));
++		&shrd	($Zll,$Zlh,4);
++		&and	(&LB($rem),0xf);
++		&shrd	($Zlh,$Zhl,4);
++		&shrd	($Zhl,$Zhh,4);
++		&shr	($Zhh,4);
++		&xor	($Zhh,&DWP($off+16,"esp",$rem,4));
++
++		if ($i&1) {
++			&mov	(&LB($rem),&BP($off+15-($i>>1),"esp"));
++			&and	(&LB($rem),0xf0);
++		} else {
++			&mov	(&LB($rem),&BP($off+15-($i>>1),"esp"));
++			&shl	(&LB($rem),4);
++		}
++
++		&xor	($Zll,&DWP(8,$Htbl,$rem));
++		&xor	($Zlh,&DWP(12,$Htbl,$rem));
++		&xor	($Zhl,&DWP(0,$Htbl,$rem));
++		&xor	($Zhh,&DWP(4,$Htbl,$rem));
++	    }
++	}
++	&bswap	($Zll);
++	&bswap	($Zlh);
++	&bswap	($Zhl);
++	if (!$x86only) {
++		&bswap	($Zhh);
++	} else {
++		&mov	("eax",$Zhh);
++		&bswap	("eax");
++		&mov	($Zhh,"eax");
++	}
++}
++
++if ($unroll) {
++    &function_begin_B("_x86_gmult_4bit_inner");
++	&x86_loop(4);
++	&ret	();
++    &function_end_B("_x86_gmult_4bit_inner");
++}
++
++sub deposit_rem_4bit {
++    my $bias = shift;
++
++	&mov	(&DWP($bias+0, "esp"),0x0000<<16);
++	&mov	(&DWP($bias+4, "esp"),0x1C20<<16);
++	&mov	(&DWP($bias+8, "esp"),0x3840<<16);
++	&mov	(&DWP($bias+12,"esp"),0x2460<<16);
++	&mov	(&DWP($bias+16,"esp"),0x7080<<16);
++	&mov	(&DWP($bias+20,"esp"),0x6CA0<<16);
++	&mov	(&DWP($bias+24,"esp"),0x48C0<<16);
++	&mov	(&DWP($bias+28,"esp"),0x54E0<<16);
++	&mov	(&DWP($bias+32,"esp"),0xE100<<16);
++	&mov	(&DWP($bias+36,"esp"),0xFD20<<16);
++	&mov	(&DWP($bias+40,"esp"),0xD940<<16);
++	&mov	(&DWP($bias+44,"esp"),0xC560<<16);
++	&mov	(&DWP($bias+48,"esp"),0x9180<<16);
++	&mov	(&DWP($bias+52,"esp"),0x8DA0<<16);
++	&mov	(&DWP($bias+56,"esp"),0xA9C0<<16);
++	&mov	(&DWP($bias+60,"esp"),0xB5E0<<16);
++}
++
++$suffix = $x86only ? "" : "_x86";
++
++&function_begin("gcm_gmult_4bit".$suffix);
++	&stack_push(16+4+1);			# +1 for stack alignment
++	&mov	($inp,&wparam(0));		# load Xi
++	&mov	($Htbl,&wparam(1));		# load Htable
++
++	&mov	($Zhh,&DWP(0,$inp));		# load Xi[16]
++	&mov	($Zhl,&DWP(4,$inp));
++	&mov	($Zlh,&DWP(8,$inp));
++	&mov	($Zll,&DWP(12,$inp));
++
++	&deposit_rem_4bit(16);
++
++	&mov	(&DWP(0,"esp"),$Zhh);		# copy Xi[16] on stack
++	&mov	(&DWP(4,"esp"),$Zhl);
++	&mov	(&DWP(8,"esp"),$Zlh);
++	&mov	(&DWP(12,"esp"),$Zll);
++	&shr	($Zll,20);
++	&and	($Zll,0xf0);
++
++	if ($unroll) {
++		&call	("_x86_gmult_4bit_inner");
++	} else {
++		&x86_loop(0);
++		&mov	($inp,&wparam(0));
++	}
++
++	&mov	(&DWP(12,$inp),$Zll);
++	&mov	(&DWP(8,$inp),$Zlh);
++	&mov	(&DWP(4,$inp),$Zhl);
++	&mov	(&DWP(0,$inp),$Zhh);
++	&stack_pop(16+4+1);
++&function_end("gcm_gmult_4bit".$suffix);
++
++&function_begin("gcm_ghash_4bit".$suffix);
++	&stack_push(16+4+1);			# +1 for 64-bit alignment
++	&mov	($Zll,&wparam(0));		# load Xi
++	&mov	($Htbl,&wparam(1));		# load Htable
++	&mov	($inp,&wparam(2));		# load in
++	&mov	("ecx",&wparam(3));		# load len
++	&add	("ecx",$inp);
++	&mov	(&wparam(3),"ecx");
++
++	&mov	($Zhh,&DWP(0,$Zll));		# load Xi[16]
++	&mov	($Zhl,&DWP(4,$Zll));
++	&mov	($Zlh,&DWP(8,$Zll));
++	&mov	($Zll,&DWP(12,$Zll));
++
++	&deposit_rem_4bit(16);
++
++    &set_label("x86_outer_loop",16);
++	&xor	($Zll,&DWP(12,$inp));		# xor with input
++	&xor	($Zlh,&DWP(8,$inp));
++	&xor	($Zhl,&DWP(4,$inp));
++	&xor	($Zhh,&DWP(0,$inp));
++	&mov	(&DWP(12,"esp"),$Zll);		# dump it on stack
++	&mov	(&DWP(8,"esp"),$Zlh);
++	&mov	(&DWP(4,"esp"),$Zhl);
++	&mov	(&DWP(0,"esp"),$Zhh);
++
++	&shr	($Zll,20);
++	&and	($Zll,0xf0);
++
++	if ($unroll) {
++		&call	("_x86_gmult_4bit_inner");
++	} else {
++		&x86_loop(0);
++		&mov	($inp,&wparam(2));
++	}
++	&lea	($inp,&DWP(16,$inp));
++	&cmp	($inp,&wparam(3));
++	&mov	(&wparam(2),$inp)	if (!$unroll);
++	&jb	(&label("x86_outer_loop"));
++
++	&mov	($inp,&wparam(0));	# load Xi
++	&mov	(&DWP(12,$inp),$Zll);
++	&mov	(&DWP(8,$inp),$Zlh);
++	&mov	(&DWP(4,$inp),$Zhl);
++	&mov	(&DWP(0,$inp),$Zhh);
++	&stack_pop(16+4+1);
++&function_end("gcm_ghash_4bit".$suffix);
++
++if (!$x86only) {{{
++
++&static_label("rem_4bit");
++
++if (!$sse2) {{	# pure-MMX "May" version...
++
++$S=12;		# shift factor for rem_4bit
++
++&function_begin_B("_mmx_gmult_4bit_inner");
++# MMX version performs 3.5 times better on P4 (see comment in non-MMX
++# routine for further details), 100% better on Opteron, ~70% better
++# on Core2 and PIII... In other words effort is considered to be well
++# spent... Since initial release the loop was unrolled in order to
++# "liberate" register previously used as loop counter. Instead it's
++# used to optimize critical path in 'Z.hi ^= rem_4bit[Z.lo&0xf]'.
++# The path involves move of Z.lo from MMX to integer register,
++# effective address calculation and finally merge of value to Z.hi.
++# Reference to rem_4bit is scheduled so late that I had to >>4
++# rem_4bit elements. This resulted in 20-45% procent improvement
++# on contemporary µ-archs.
++{
++    my $cnt;
++    my $rem_4bit = "eax";
++    my @rem = ($Zhh,$Zll);
++    my $nhi = $Zhl;
++    my $nlo = $Zlh;
++
++    my ($Zlo,$Zhi) = ("mm0","mm1");
++    my $tmp = "mm2";
++
++	&xor	($nlo,$nlo);	# avoid partial register stalls on PIII
++	&mov	($nhi,$Zll);
++	&mov	(&LB($nlo),&LB($nhi));
++	&shl	(&LB($nlo),4);
++	&and	($nhi,0xf0);
++	&movq	($Zlo,&QWP(8,$Htbl,$nlo));
++	&movq	($Zhi,&QWP(0,$Htbl,$nlo));
++	&movd	($rem[0],$Zlo);
++
++	for ($cnt=28;$cnt>=-2;$cnt--) {
++	    my $odd = $cnt&1;
++	    my $nix = $odd ? $nlo : $nhi;
++
++		&shl	(&LB($nlo),4)			if ($odd);
++		&psrlq	($Zlo,4);
++		&movq	($tmp,$Zhi);
++		&psrlq	($Zhi,4);
++		&pxor	($Zlo,&QWP(8,$Htbl,$nix));
++		&mov	(&LB($nlo),&BP($cnt/2,$inp))	if (!$odd && $cnt>=0);
++		&psllq	($tmp,60);
++		&and	($nhi,0xf0)			if ($odd);
++		&pxor	($Zhi,&QWP(0,$rem_4bit,$rem[1],8)) if ($cnt<28);
++		&and	($rem[0],0xf);
++		&pxor	($Zhi,&QWP(0,$Htbl,$nix));
++		&mov	($nhi,$nlo)			if (!$odd && $cnt>=0);
++		&movd	($rem[1],$Zlo);
++		&pxor	($Zlo,$tmp);
++
++		push	(@rem,shift(@rem));		# "rotate" registers
++	}
++
++	&mov	($inp,&DWP(4,$rem_4bit,$rem[1],8));	# last rem_4bit[rem]
++
++	&psrlq	($Zlo,32);	# lower part of Zlo is already there
++	&movd	($Zhl,$Zhi);
++	&psrlq	($Zhi,32);
++	&movd	($Zlh,$Zlo);
++	&movd	($Zhh,$Zhi);
++	&shl	($inp,4);	# compensate for rem_4bit[i] being >>4
++
++	&bswap	($Zll);
++	&bswap	($Zhl);
++	&bswap	($Zlh);
++	&xor	($Zhh,$inp);
++	&bswap	($Zhh);
++
++	&ret	();
++}
++&function_end_B("_mmx_gmult_4bit_inner");
++
++&function_begin("gcm_gmult_4bit_mmx");
++	&mov	($inp,&wparam(0));	# load Xi
++	&mov	($Htbl,&wparam(1));	# load Htable
++
++	&call	(&label("pic_point"));
++	&set_label("pic_point");
++	&blindpop("eax");
++	&lea	("eax",&DWP(&label("rem_4bit")."-".&label("pic_point"),"eax"));
++
++	&movz	($Zll,&BP(15,$inp));
++
++	&call	("_mmx_gmult_4bit_inner");
++
++	&mov	($inp,&wparam(0));	# load Xi
++	&emms	();
++	&mov	(&DWP(12,$inp),$Zll);
++	&mov	(&DWP(4,$inp),$Zhl);
++	&mov	(&DWP(8,$inp),$Zlh);
++	&mov	(&DWP(0,$inp),$Zhh);
++&function_end("gcm_gmult_4bit_mmx");
++
++# Streamed version performs 20% better on P4, 7% on Opteron,
++# 10% on Core2 and PIII...
++&function_begin("gcm_ghash_4bit_mmx");
++	&mov	($Zhh,&wparam(0));	# load Xi
++	&mov	($Htbl,&wparam(1));	# load Htable
++	&mov	($inp,&wparam(2));	# load in
++	&mov	($Zlh,&wparam(3));	# load len
++
++	&call	(&label("pic_point"));
++	&set_label("pic_point");
++	&blindpop("eax");
++	&lea	("eax",&DWP(&label("rem_4bit")."-".&label("pic_point"),"eax"));
++
++	&add	($Zlh,$inp);
++	&mov	(&wparam(3),$Zlh);	# len to point at the end of input
++	&stack_push(4+1);		# +1 for stack alignment
++
++	&mov	($Zll,&DWP(12,$Zhh));	# load Xi[16]
++	&mov	($Zhl,&DWP(4,$Zhh));
++	&mov	($Zlh,&DWP(8,$Zhh));
++	&mov	($Zhh,&DWP(0,$Zhh));
++	&jmp	(&label("mmx_outer_loop"));
++
++    &set_label("mmx_outer_loop",16);
++	&xor	($Zll,&DWP(12,$inp));
++	&xor	($Zhl,&DWP(4,$inp));
++	&xor	($Zlh,&DWP(8,$inp));
++	&xor	($Zhh,&DWP(0,$inp));
++	&mov	(&wparam(2),$inp);
++	&mov	(&DWP(12,"esp"),$Zll);
++	&mov	(&DWP(4,"esp"),$Zhl);
++	&mov	(&DWP(8,"esp"),$Zlh);
++	&mov	(&DWP(0,"esp"),$Zhh);
++
++	&mov	($inp,"esp");
++	&shr	($Zll,24);
++
++	&call	("_mmx_gmult_4bit_inner");
++
++	&mov	($inp,&wparam(2));
++	&lea	($inp,&DWP(16,$inp));
++	&cmp	($inp,&wparam(3));
++	&jb	(&label("mmx_outer_loop"));
++
++	&mov	($inp,&wparam(0));	# load Xi
++	&emms	();
++	&mov	(&DWP(12,$inp),$Zll);
++	&mov	(&DWP(4,$inp),$Zhl);
++	&mov	(&DWP(8,$inp),$Zlh);
++	&mov	(&DWP(0,$inp),$Zhh);
++
++	&stack_pop(4+1);
++&function_end("gcm_ghash_4bit_mmx");
++
++}} else {{	# "June" MMX version...
++		# ... has slower "April" gcm_gmult_4bit_mmx with folded
++		# loop. This is done to conserve code size...
++$S=16;		# shift factor for rem_4bit
++
++sub mmx_loop() {
++# MMX version performs 2.8 times better on P4 (see comment in non-MMX
++# routine for further details), 40% better on Opteron and Core2, 50%
++# better on PIII... In other words effort is considered to be well
++# spent...
++    my $inp = shift;
++    my $rem_4bit = shift;
++    my $cnt = $Zhh;
++    my $nhi = $Zhl;
++    my $nlo = $Zlh;
++    my $rem = $Zll;
++
++    my ($Zlo,$Zhi) = ("mm0","mm1");
++    my $tmp = "mm2";
++
++	&xor	($nlo,$nlo);	# avoid partial register stalls on PIII
++	&mov	($nhi,$Zll);
++	&mov	(&LB($nlo),&LB($nhi));
++	&mov	($cnt,14);
++	&shl	(&LB($nlo),4);
++	&and	($nhi,0xf0);
++	&movq	($Zlo,&QWP(8,$Htbl,$nlo));
++	&movq	($Zhi,&QWP(0,$Htbl,$nlo));
++	&movd	($rem,$Zlo);
++	&jmp	(&label("mmx_loop"));
++
++    &set_label("mmx_loop",16);
++	&psrlq	($Zlo,4);
++	&and	($rem,0xf);
++	&movq	($tmp,$Zhi);
++	&psrlq	($Zhi,4);
++	&pxor	($Zlo,&QWP(8,$Htbl,$nhi));
++	&mov	(&LB($nlo),&BP(0,$inp,$cnt));
++	&psllq	($tmp,60);
++	&pxor	($Zhi,&QWP(0,$rem_4bit,$rem,8));
++	&dec	($cnt);
++	&movd	($rem,$Zlo);
++	&pxor	($Zhi,&QWP(0,$Htbl,$nhi));
++	&mov	($nhi,$nlo);
++	&pxor	($Zlo,$tmp);
++	&js	(&label("mmx_break"));
++
++	&shl	(&LB($nlo),4);
++	&and	($rem,0xf);
++	&psrlq	($Zlo,4);
++	&and	($nhi,0xf0);
++	&movq	($tmp,$Zhi);
++	&psrlq	($Zhi,4);
++	&pxor	($Zlo,&QWP(8,$Htbl,$nlo));
++	&psllq	($tmp,60);
++	&pxor	($Zhi,&QWP(0,$rem_4bit,$rem,8));
++	&movd	($rem,$Zlo);
++	&pxor	($Zhi,&QWP(0,$Htbl,$nlo));
++	&pxor	($Zlo,$tmp);
++	&jmp	(&label("mmx_loop"));
++
++    &set_label("mmx_break",16);
++	&shl	(&LB($nlo),4);
++	&and	($rem,0xf);
++	&psrlq	($Zlo,4);
++	&and	($nhi,0xf0);
++	&movq	($tmp,$Zhi);
++	&psrlq	($Zhi,4);
++	&pxor	($Zlo,&QWP(8,$Htbl,$nlo));
++	&psllq	($tmp,60);
++	&pxor	($Zhi,&QWP(0,$rem_4bit,$rem,8));
++	&movd	($rem,$Zlo);
++	&pxor	($Zhi,&QWP(0,$Htbl,$nlo));
++	&pxor	($Zlo,$tmp);
++
++	&psrlq	($Zlo,4);
++	&and	($rem,0xf);
++	&movq	($tmp,$Zhi);
++	&psrlq	($Zhi,4);
++	&pxor	($Zlo,&QWP(8,$Htbl,$nhi));
++	&psllq	($tmp,60);
++	&pxor	($Zhi,&QWP(0,$rem_4bit,$rem,8));
++	&movd	($rem,$Zlo);
++	&pxor	($Zhi,&QWP(0,$Htbl,$nhi));
++	&pxor	($Zlo,$tmp);
++
++	&psrlq	($Zlo,32);	# lower part of Zlo is already there
++	&movd	($Zhl,$Zhi);
++	&psrlq	($Zhi,32);
++	&movd	($Zlh,$Zlo);
++	&movd	($Zhh,$Zhi);
++
++	&bswap	($Zll);
++	&bswap	($Zhl);
++	&bswap	($Zlh);
++	&bswap	($Zhh);
++}
++
++&function_begin("gcm_gmult_4bit_mmx");
++	&mov	($inp,&wparam(0));	# load Xi
++	&mov	($Htbl,&wparam(1));	# load Htable
++
++	&call	(&label("pic_point"));
++	&set_label("pic_point");
++	&blindpop("eax");
++	&lea	("eax",&DWP(&label("rem_4bit")."-".&label("pic_point"),"eax"));
++
++	&movz	($Zll,&BP(15,$inp));
++
++	&mmx_loop($inp,"eax");
++
++	&emms	();
++	&mov	(&DWP(12,$inp),$Zll);
++	&mov	(&DWP(4,$inp),$Zhl);
++	&mov	(&DWP(8,$inp),$Zlh);
++	&mov	(&DWP(0,$inp),$Zhh);
++&function_end("gcm_gmult_4bit_mmx");
++
++######################################################################
++# Below subroutine is "528B" variant of "4-bit" GCM GHASH function
++# (see gcm128.c for details). It provides further 20-40% performance
++# improvement over above mentioned "May" version.
++
++&static_label("rem_8bit");
++
++&function_begin("gcm_ghash_4bit_mmx");
++{ my ($Zlo,$Zhi) = ("mm7","mm6");
++  my $rem_8bit = "esi";
++  my $Htbl = "ebx";
++
++    # parameter block
++    &mov	("eax",&wparam(0));		# Xi
++    &mov	("ebx",&wparam(1));		# Htable
++    &mov	("ecx",&wparam(2));		# inp
++    &mov	("edx",&wparam(3));		# len
++    &mov	("ebp","esp");			# original %esp
++    &call	(&label("pic_point"));
++    &set_label	("pic_point");
++    &blindpop	($rem_8bit);
++    &lea	($rem_8bit,&DWP(&label("rem_8bit")."-".&label("pic_point"),$rem_8bit));
++
++    &sub	("esp",512+16+16);		# allocate stack frame...
++    &and	("esp",-64);			# ...and align it
++    &sub	("esp",16);			# place for (u8)(H[]<<4)
++
++    &add	("edx","ecx");			# pointer to the end of input
++    &mov	(&DWP(528+16+0,"esp"),"eax");	# save Xi
++    &mov	(&DWP(528+16+8,"esp"),"edx");	# save inp+len
++    &mov	(&DWP(528+16+12,"esp"),"ebp");	# save original %esp
++
++    { my @lo  = ("mm0","mm1","mm2");
++      my @hi  = ("mm3","mm4","mm5");
++      my @tmp = ("mm6","mm7");
++      my ($off1,$off2,$i) = (0,0,);
++
++      &add	($Htbl,128);			# optimize for size
++      &lea	("edi",&DWP(16+128,"esp"));
++      &lea	("ebp",&DWP(16+256+128,"esp"));
++
++      # decompose Htable (low and high parts are kept separately),
++      # generate Htable[]>>4, (u8)(Htable[]<<4), save to stack...
++      for ($i=0;$i<18;$i++) {
++
++	&mov	("edx",&DWP(16*$i+8-128,$Htbl))		if ($i<16);
++	&movq	($lo[0],&QWP(16*$i+8-128,$Htbl))	if ($i<16);
++	&psllq	($tmp[1],60)				if ($i>1);
++	&movq	($hi[0],&QWP(16*$i+0-128,$Htbl))	if ($i<16);
++	&por	($lo[2],$tmp[1])			if ($i>1);
++	&movq	(&QWP($off1-128,"edi"),$lo[1])		if ($i>0 && $i<17);
++	&psrlq	($lo[1],4)				if ($i>0 && $i<17);
++	&movq	(&QWP($off1,"edi"),$hi[1])		if ($i>0 && $i<17);
++	&movq	($tmp[0],$hi[1])			if ($i>0 && $i<17);
++	&movq	(&QWP($off2-128,"ebp"),$lo[2])		if ($i>1);
++	&psrlq	($hi[1],4)				if ($i>0 && $i<17);
++	&movq	(&QWP($off2,"ebp"),$hi[2])		if ($i>1);
++	&shl	("edx",4)				if ($i<16);
++	&mov	(&BP($i,"esp"),&LB("edx"))		if ($i<16);
++
++	unshift	(@lo,pop(@lo));			# "rotate" registers
++	unshift	(@hi,pop(@hi));
++	unshift	(@tmp,pop(@tmp));
++	$off1 += 8	if ($i>0);
++	$off2 += 8	if ($i>1);
++      }
++    }
++
++    &movq	($Zhi,&QWP(0,"eax"));
++    &mov	("ebx",&DWP(8,"eax"));
++    &mov	("edx",&DWP(12,"eax"));		# load Xi
++
++&set_label("outer",16);
++  { my $nlo = "eax";
++    my $dat = "edx";
++    my @nhi = ("edi","ebp");
++    my @rem = ("ebx","ecx");
++    my @red = ("mm0","mm1","mm2");
++    my $tmp = "mm3";
++
++    &xor	($dat,&DWP(12,"ecx"));		# merge input data
++    &xor	("ebx",&DWP(8,"ecx"));
++    &pxor	($Zhi,&QWP(0,"ecx"));
++    &lea	("ecx",&DWP(16,"ecx"));		# inp+=16
++    #&mov	(&DWP(528+12,"esp"),$dat);	# save inp^Xi
++    &mov	(&DWP(528+8,"esp"),"ebx");
++    &movq	(&QWP(528+0,"esp"),$Zhi);
++    &mov	(&DWP(528+16+4,"esp"),"ecx");	# save inp
++
++    &xor	($nlo,$nlo);
++    &rol	($dat,8);
++    &mov	(&LB($nlo),&LB($dat));
++    &mov	($nhi[1],$nlo);
++    &and	(&LB($nlo),0x0f);
++    &shr	($nhi[1],4);
++    &pxor	($red[0],$red[0]);
++    &rol	($dat,8);			# next byte
++    &pxor	($red[1],$red[1]);
++    &pxor	($red[2],$red[2]);
++
++    # Just like in "May" version modulo-schedule for critical path in
++    # 'Z.hi ^= rem_8bit[Z.lo&0xff^((u8)H[nhi]<<4)]<<48'. Final 'pxor'
++    # is scheduled so late that rem_8bit[] has to be shifted *right*
++    # by 16, which is why last argument to pinsrw is 2, which
++    # corresponds to <<32=<<48>>16...
++    for ($j=11,$i=0;$i<15;$i++) {
++
++      if ($i>0) {
++	&pxor	($Zlo,&QWP(16,"esp",$nlo,8));		# Z^=H[nlo]
++	&rol	($dat,8);				# next byte
++	&pxor	($Zhi,&QWP(16+128,"esp",$nlo,8));
++
++	&pxor	($Zlo,$tmp);
++	&pxor	($Zhi,&QWP(16+256+128,"esp",$nhi[0],8));
++	&xor	(&LB($rem[1]),&BP(0,"esp",$nhi[0]));	# rem^(H[nhi]<<4)
++      } else {
++	&movq	($Zlo,&QWP(16,"esp",$nlo,8));
++	&movq	($Zhi,&QWP(16+128,"esp",$nlo,8));
++      }
++
++	&mov	(&LB($nlo),&LB($dat));
++	&mov	($dat,&DWP(528+$j,"esp"))		if (--$j%4==0);
++
++	&movd	($rem[0],$Zlo);
++	&movz	($rem[1],&LB($rem[1]))			if ($i>0);
++	&psrlq	($Zlo,8);				# Z>>=8
++
++	&movq	($tmp,$Zhi);
++	&mov	($nhi[0],$nlo);
++	&psrlq	($Zhi,8);
++
++	&pxor	($Zlo,&QWP(16+256+0,"esp",$nhi[1],8));	# Z^=H[nhi]>>4
++	&and	(&LB($nlo),0x0f);
++	&psllq	($tmp,56);
++
++	&pxor	($Zhi,$red[1])				if ($i>1);
++	&shr	($nhi[0],4);
++	&pinsrw	($red[0],&WP(0,$rem_8bit,$rem[1],2),2)	if ($i>0);
++
++	unshift	(@red,pop(@red));			# "rotate" registers
++	unshift	(@rem,pop(@rem));
++	unshift	(@nhi,pop(@nhi));
++    }
++
++    &pxor	($Zlo,&QWP(16,"esp",$nlo,8));		# Z^=H[nlo]
++    &pxor	($Zhi,&QWP(16+128,"esp",$nlo,8));
++    &xor	(&LB($rem[1]),&BP(0,"esp",$nhi[0]));	# rem^(H[nhi]<<4)
++
++    &pxor	($Zlo,$tmp);
++    &pxor	($Zhi,&QWP(16+256+128,"esp",$nhi[0],8));
++    &movz	($rem[1],&LB($rem[1]));
++
++    &pxor	($red[2],$red[2]);			# clear 2nd word
++    &psllq	($red[1],4);
++
++    &movd	($rem[0],$Zlo);
++    &psrlq	($Zlo,4);				# Z>>=4
++
++    &movq	($tmp,$Zhi);
++    &psrlq	($Zhi,4);
++    &shl	($rem[0],4);				# rem<<4
++
++    &pxor	($Zlo,&QWP(16,"esp",$nhi[1],8));	# Z^=H[nhi]
++    &psllq	($tmp,60);
++    &movz	($rem[0],&LB($rem[0]));
++
++    &pxor	($Zlo,$tmp);
++    &pxor	($Zhi,&QWP(16+128,"esp",$nhi[1],8));
++
++    &pinsrw	($red[0],&WP(0,$rem_8bit,$rem[1],2),2);
++    &pxor	($Zhi,$red[1]);
++
++    &movd	($dat,$Zlo);
++    &pinsrw	($red[2],&WP(0,$rem_8bit,$rem[0],2),3);	# last is <<48
++
++    &psllq	($red[0],12);				# correct by <<16>>4
++    &pxor	($Zhi,$red[0]);
++    &psrlq	($Zlo,32);
++    &pxor	($Zhi,$red[2]);
++
++    &mov	("ecx",&DWP(528+16+4,"esp"));	# restore inp
++    &movd	("ebx",$Zlo);
++    &movq	($tmp,$Zhi);			# 01234567
++    &psllw	($Zhi,8);			# 1.3.5.7.
++    &psrlw	($tmp,8);			# .0.2.4.6
++    &por	($Zhi,$tmp);			# 10325476
++    &bswap	($dat);
++    &pshufw	($Zhi,$Zhi,0b00011011);		# 76543210
++    &bswap	("ebx");
++    
++    &cmp	("ecx",&DWP(528+16+8,"esp"));	# are we done?
++    &jne	(&label("outer"));
++  }
++
++    &mov	("eax",&DWP(528+16+0,"esp"));	# restore Xi
++    &mov	(&DWP(12,"eax"),"edx");
++    &mov	(&DWP(8,"eax"),"ebx");
++    &movq	(&QWP(0,"eax"),$Zhi);
++
++    &mov	("esp",&DWP(528+16+12,"esp"));	# restore original %esp
++    &emms	();
++}
++&function_end("gcm_ghash_4bit_mmx");
++}}
++
++if ($sse2) {{
++######################################################################
++# PCLMULQDQ version.
++
++$Xip="eax";
++$Htbl="edx";
++$const="ecx";
++$inp="esi";
++$len="ebx";
++
++($Xi,$Xhi)=("xmm0","xmm1");	$Hkey="xmm2";
++($T1,$T2,$T3)=("xmm3","xmm4","xmm5");
++($Xn,$Xhn)=("xmm6","xmm7");
++
++&static_label("bswap");
++
++sub clmul64x64_T2 {	# minimal "register" pressure
++my ($Xhi,$Xi,$Hkey,$HK)=@_;
++
++	&movdqa		($Xhi,$Xi);		#
++	&pshufd		($T1,$Xi,0b01001110);
++	&pshufd		($T2,$Hkey,0b01001110)	if (!defined($HK));
++	&pxor		($T1,$Xi);		#
++	&pxor		($T2,$Hkey)		if (!defined($HK));
++			$HK=$T2			if (!defined($HK));
++
++	&pclmulqdq	($Xi,$Hkey,0x00);	#######
++	&pclmulqdq	($Xhi,$Hkey,0x11);	#######
++	&pclmulqdq	($T1,$HK,0x00);		#######
++	&xorps		($T1,$Xi);		#
++	&xorps		($T1,$Xhi);		#
++
++	&movdqa		($T2,$T1);		#
++	&psrldq		($T1,8);
++	&pslldq		($T2,8);		#
++	&pxor		($Xhi,$T1);
++	&pxor		($Xi,$T2);		#
++}
++
++sub clmul64x64_T3 {
++# Even though this subroutine offers visually better ILP, it
++# was empirically found to be a tad slower than above version.
++# At least in gcm_ghash_clmul context. But it's just as well,
++# because loop modulo-scheduling is possible only thanks to
++# minimized "register" pressure...
++my ($Xhi,$Xi,$Hkey)=@_;
++
++	&movdqa		($T1,$Xi);		#
++	&movdqa		($Xhi,$Xi);
++	&pclmulqdq	($Xi,$Hkey,0x00);	#######
++	&pclmulqdq	($Xhi,$Hkey,0x11);	#######
++	&pshufd		($T2,$T1,0b01001110);	#
++	&pshufd		($T3,$Hkey,0b01001110);
++	&pxor		($T2,$T1);		#
++	&pxor		($T3,$Hkey);
++	&pclmulqdq	($T2,$T3,0x00);		#######
++	&pxor		($T2,$Xi);		#
++	&pxor		($T2,$Xhi);		#
++
++	&movdqa		($T3,$T2);		#
++	&psrldq		($T2,8);
++	&pslldq		($T3,8);		#
++	&pxor		($Xhi,$T2);
++	&pxor		($Xi,$T3);		#
++}
++
++if (1) {		# Algorithm 9 with <<1 twist.
++			# Reduction is shorter and uses only two
++			# temporary registers, which makes it better
++			# candidate for interleaving with 64x64
++			# multiplication. Pre-modulo-scheduled loop
++			# was found to be ~20% faster than Algorithm 5
++			# below. Algorithm 9 was therefore chosen for
++			# further optimization...
++
++sub reduction_alg9 {	# 17/11 times faster than Intel version
++my ($Xhi,$Xi) = @_;
++
++	# 1st phase
++	&movdqa		($T2,$Xi);		#
++	&movdqa		($T1,$Xi);
++	&psllq		($Xi,5);
++	&pxor		($T1,$Xi);		#
++	&psllq		($Xi,1);
++	&pxor		($Xi,$T1);		#
++	&psllq		($Xi,57);		#
++	&movdqa		($T1,$Xi);		#
++	&pslldq		($Xi,8);
++	&psrldq		($T1,8);		#	
++	&pxor		($Xi,$T2);
++	&pxor		($Xhi,$T1);		#
++
++	# 2nd phase
++	&movdqa		($T2,$Xi);
++	&psrlq		($Xi,1);
++	&pxor		($Xhi,$T2);		#
++	&pxor		($T2,$Xi);
++	&psrlq		($Xi,5);
++	&pxor		($Xi,$T2);		#
++	&psrlq		($Xi,1);		#
++	&pxor		($Xi,$Xhi)		#
++}
++
++&function_begin_B("gcm_init_clmul");
++	&mov		($Htbl,&wparam(0));
++	&mov		($Xip,&wparam(1));
++
++	&call		(&label("pic"));
++&set_label("pic");
++	&blindpop	($const);
++	&lea		($const,&DWP(&label("bswap")."-".&label("pic"),$const));
++
++	&movdqu		($Hkey,&QWP(0,$Xip));
++	&pshufd		($Hkey,$Hkey,0b01001110);# dword swap
++
++	# <<1 twist
++	&pshufd		($T2,$Hkey,0b11111111);	# broadcast uppermost dword
++	&movdqa		($T1,$Hkey);
++	&psllq		($Hkey,1);
++	&pxor		($T3,$T3);		#
++	&psrlq		($T1,63);
++	&pcmpgtd	($T3,$T2);		# broadcast carry bit
++	&pslldq		($T1,8);
++	&por		($Hkey,$T1);		# H<<=1
++
++	# magic reduction
++	&pand		($T3,&QWP(16,$const));	# 0x1c2_polynomial
++	&pxor		($Hkey,$T3);		# if(carry) H^=0x1c2_polynomial
++
++	# calculate H^2
++	&movdqa		($Xi,$Hkey);
++	&clmul64x64_T2	($Xhi,$Xi,$Hkey);
++	&reduction_alg9	($Xhi,$Xi);
++
++	&pshufd		($T1,$Hkey,0b01001110);
++	&pshufd		($T2,$Xi,0b01001110);
++	&pxor		($T1,$Hkey);		# Karatsuba pre-processing
++	&movdqu		(&QWP(0,$Htbl),$Hkey);	# save H
++	&pxor		($T2,$Xi);		# Karatsuba pre-processing
++	&movdqu		(&QWP(16,$Htbl),$Xi);	# save H^2
++	&palignr	($T2,$T1,8);		# low part is H.lo^H.hi
++	&movdqu		(&QWP(32,$Htbl),$T2);	# save Karatsuba "salt"
++
++	&ret		();
++&function_end_B("gcm_init_clmul");
++
++&function_begin_B("gcm_gmult_clmul");
++	&mov		($Xip,&wparam(0));
++	&mov		($Htbl,&wparam(1));
++
++	&call		(&label("pic"));
++&set_label("pic");
++	&blindpop	($const);
++	&lea		($const,&DWP(&label("bswap")."-".&label("pic"),$const));
++
++	&movdqu		($Xi,&QWP(0,$Xip));
++	&movdqa		($T3,&QWP(0,$const));
++	&movups		($Hkey,&QWP(0,$Htbl));
++	&pshufb		($Xi,$T3);
++	&movups		($T2,&QWP(32,$Htbl));
++
++	&clmul64x64_T2	($Xhi,$Xi,$Hkey,$T2);
++	&reduction_alg9	($Xhi,$Xi);
++
++	&pshufb		($Xi,$T3);
++	&movdqu		(&QWP(0,$Xip),$Xi);
++
++	&ret	();
++&function_end_B("gcm_gmult_clmul");
++
++&function_begin("gcm_ghash_clmul");
++	&mov		($Xip,&wparam(0));
++	&mov		($Htbl,&wparam(1));
++	&mov		($inp,&wparam(2));
++	&mov		($len,&wparam(3));
++
++	&call		(&label("pic"));
++&set_label("pic");
++	&blindpop	($const);
++	&lea		($const,&DWP(&label("bswap")."-".&label("pic"),$const));
++
++	&movdqu		($Xi,&QWP(0,$Xip));
++	&movdqa		($T3,&QWP(0,$const));
++	&movdqu		($Hkey,&QWP(0,$Htbl));
++	&pshufb		($Xi,$T3);
++
++	&sub		($len,0x10);
++	&jz		(&label("odd_tail"));
++
++	#######
++	# Xi+2 =[H*(Ii+1 + Xi+1)] mod P =
++	#	[(H*Ii+1) + (H*Xi+1)] mod P =
++	#	[(H*Ii+1) + H^2*(Ii+Xi)] mod P
++	#
++	&movdqu		($T1,&QWP(0,$inp));	# Ii
++	&movdqu		($Xn,&QWP(16,$inp));	# Ii+1
++	&pshufb		($T1,$T3);
++	&pshufb		($Xn,$T3);
++	&movdqu		($T3,&QWP(32,$Htbl));
++	&pxor		($Xi,$T1);		# Ii+Xi
++
++	&pshufd		($T1,$Xn,0b01001110);	# H*Ii+1
++	&movdqa		($Xhn,$Xn);
++	&pxor		($T1,$Xn);		#
++	&lea		($inp,&DWP(32,$inp));	# i+=2
++
++	&pclmulqdq	($Xn,$Hkey,0x00);	#######
++	&pclmulqdq	($Xhn,$Hkey,0x11);	#######
++	&pclmulqdq	($T1,$T3,0x00);		#######
++	&movups		($Hkey,&QWP(16,$Htbl));	# load H^2
++	&nop		();
++
++	&sub		($len,0x20);
++	&jbe		(&label("even_tail"));
++	&jmp		(&label("mod_loop"));
++
++&set_label("mod_loop",32);
++	&pshufd		($T2,$Xi,0b01001110);	# H^2*(Ii+Xi)
++	&movdqa		($Xhi,$Xi);
++	&pxor		($T2,$Xi);		#
++	&nop		();
++
++	&pclmulqdq	($Xi,$Hkey,0x00);	#######
++	&pclmulqdq	($Xhi,$Hkey,0x11);	#######
++	&pclmulqdq	($T2,$T3,0x10);		#######
++	&movups		($Hkey,&QWP(0,$Htbl));	# load H
++
++	&xorps		($Xi,$Xn);		# (H*Ii+1) + H^2*(Ii+Xi)
++	&movdqa		($T3,&QWP(0,$const));
++	&xorps		($Xhi,$Xhn);
++	 &movdqu	($Xhn,&QWP(0,$inp));	# Ii
++	&pxor		($T1,$Xi);		# aggregated Karatsuba post-processing
++	 &movdqu	($Xn,&QWP(16,$inp));	# Ii+1
++	&pxor		($T1,$Xhi);		#
++
++	 &pshufb	($Xhn,$T3);
++	&pxor		($T2,$T1);		#
++
++	&movdqa		($T1,$T2);		#
++	&psrldq		($T2,8);
++	&pslldq		($T1,8);		#
++	&pxor		($Xhi,$T2);
++	&pxor		($Xi,$T1);		#
++	 &pshufb	($Xn,$T3);
++	 &pxor		($Xhi,$Xhn);		# "Ii+Xi", consume early
++
++	&movdqa		($Xhn,$Xn);		#&clmul64x64_TX	($Xhn,$Xn,$Hkey); H*Ii+1
++	  &movdqa	($T2,$Xi);		#&reduction_alg9($Xhi,$Xi); 1st phase
++	  &movdqa	($T1,$Xi);
++	  &psllq	($Xi,5);
++	  &pxor		($T1,$Xi);		#
++	  &psllq	($Xi,1);
++	  &pxor		($Xi,$T1);		#
++	&pclmulqdq	($Xn,$Hkey,0x00);	#######
++	&movups		($T3,&QWP(32,$Htbl));
++	  &psllq	($Xi,57);		#
++	  &movdqa	($T1,$Xi);		#
++	  &pslldq	($Xi,8);
++	  &psrldq	($T1,8);		#	
++	  &pxor		($Xi,$T2);
++	  &pxor		($Xhi,$T1);		#
++	&pshufd		($T1,$Xhn,0b01001110);
++	  &movdqa	($T2,$Xi);		# 2nd phase
++	  &psrlq	($Xi,1);
++	&pxor		($T1,$Xhn);
++	  &pxor		($Xhi,$T2);		#
++	&pclmulqdq	($Xhn,$Hkey,0x11);	#######
++	&movups		($Hkey,&QWP(16,$Htbl));	# load H^2
++	  &pxor		($T2,$Xi);
++	  &psrlq	($Xi,5);
++	  &pxor		($Xi,$T2);		#
++	  &psrlq	($Xi,1);		#
++	  &pxor		($Xi,$Xhi)		#
++	&pclmulqdq	($T1,$T3,0x00);		#######
++
++	&lea		($inp,&DWP(32,$inp));
++	&sub		($len,0x20);
++	&ja		(&label("mod_loop"));
++
++&set_label("even_tail");
++	&pshufd		($T2,$Xi,0b01001110);	# H^2*(Ii+Xi)
++	&movdqa		($Xhi,$Xi);
++	&pxor		($T2,$Xi);		#
++
++	&pclmulqdq	($Xi,$Hkey,0x00);	#######
++	&pclmulqdq	($Xhi,$Hkey,0x11);	#######
++	&pclmulqdq	($T2,$T3,0x10);		#######
++	&movdqa		($T3,&QWP(0,$const));
++
++	&xorps		($Xi,$Xn);		# (H*Ii+1) + H^2*(Ii+Xi)
++	&xorps		($Xhi,$Xhn);
++	&pxor		($T1,$Xi);		# aggregated Karatsuba post-processing
++	&pxor		($T1,$Xhi);		#
++
++	&pxor		($T2,$T1);		#
++
++	&movdqa		($T1,$T2);		#
++	&psrldq		($T2,8);
++	&pslldq		($T1,8);		#
++	&pxor		($Xhi,$T2);
++	&pxor		($Xi,$T1);		#
++
++	&reduction_alg9	($Xhi,$Xi);
++
++	&test		($len,$len);
++	&jnz		(&label("done"));
++
++	&movups		($Hkey,&QWP(0,$Htbl));	# load H
++&set_label("odd_tail");
++	&movdqu		($T1,&QWP(0,$inp));	# Ii
++	&pshufb		($T1,$T3);
++	&pxor		($Xi,$T1);		# Ii+Xi
++
++	&clmul64x64_T2	($Xhi,$Xi,$Hkey);	# H*(Ii+Xi)
++	&reduction_alg9	($Xhi,$Xi);
++
++&set_label("done");
++	&pshufb		($Xi,$T3);
++	&movdqu		(&QWP(0,$Xip),$Xi);
++&function_end("gcm_ghash_clmul");
++
++} else {		# Algorithm 5. Kept for reference purposes.
++
++sub reduction_alg5 {	# 19/16 times faster than Intel version
++my ($Xhi,$Xi)=@_;
++
++	# <<1
++	&movdqa		($T1,$Xi);		#
++	&movdqa		($T2,$Xhi);
++	&pslld		($Xi,1);
++	&pslld		($Xhi,1);		#
++	&psrld		($T1,31);
++	&psrld		($T2,31);		#
++	&movdqa		($T3,$T1);
++	&pslldq		($T1,4);
++	&psrldq		($T3,12);		#
++	&pslldq		($T2,4);
++	&por		($Xhi,$T3);		#
++	&por		($Xi,$T1);
++	&por		($Xhi,$T2);		#
++
++	# 1st phase
++	&movdqa		($T1,$Xi);
++	&movdqa		($T2,$Xi);
++	&movdqa		($T3,$Xi);		#
++	&pslld		($T1,31);
++	&pslld		($T2,30);
++	&pslld		($Xi,25);		#
++	&pxor		($T1,$T2);
++	&pxor		($T1,$Xi);		#
++	&movdqa		($T2,$T1);		#
++	&pslldq		($T1,12);
++	&psrldq		($T2,4);		#
++	&pxor		($T3,$T1);
++
++	# 2nd phase
++	&pxor		($Xhi,$T3);		#
++	&movdqa		($Xi,$T3);
++	&movdqa		($T1,$T3);
++	&psrld		($Xi,1);		#
++	&psrld		($T1,2);
++	&psrld		($T3,7);		#
++	&pxor		($Xi,$T1);
++	&pxor		($Xhi,$T2);
++	&pxor		($Xi,$T3);		#
++	&pxor		($Xi,$Xhi);		#
++}
++
++&function_begin_B("gcm_init_clmul");
++	&mov		($Htbl,&wparam(0));
++	&mov		($Xip,&wparam(1));
++
++	&call		(&label("pic"));
++&set_label("pic");
++	&blindpop	($const);
++	&lea		($const,&DWP(&label("bswap")."-".&label("pic"),$const));
++
++	&movdqu		($Hkey,&QWP(0,$Xip));
++	&pshufd		($Hkey,$Hkey,0b01001110);# dword swap
++
++	# calculate H^2
++	&movdqa		($Xi,$Hkey);
++	&clmul64x64_T3	($Xhi,$Xi,$Hkey);
++	&reduction_alg5	($Xhi,$Xi);
++
++	&movdqu		(&QWP(0,$Htbl),$Hkey);	# save H
++	&movdqu		(&QWP(16,$Htbl),$Xi);	# save H^2
++
++	&ret		();
++&function_end_B("gcm_init_clmul");
++
++&function_begin_B("gcm_gmult_clmul");
++	&mov		($Xip,&wparam(0));
++	&mov		($Htbl,&wparam(1));
++
++	&call		(&label("pic"));
++&set_label("pic");
++	&blindpop	($const);
++	&lea		($const,&DWP(&label("bswap")."-".&label("pic"),$const));
++
++	&movdqu		($Xi,&QWP(0,$Xip));
++	&movdqa		($Xn,&QWP(0,$const));
++	&movdqu		($Hkey,&QWP(0,$Htbl));
++	&pshufb		($Xi,$Xn);
++
++	&clmul64x64_T3	($Xhi,$Xi,$Hkey);
++	&reduction_alg5	($Xhi,$Xi);
++
++	&pshufb		($Xi,$Xn);
++	&movdqu		(&QWP(0,$Xip),$Xi);
++
++	&ret	();
++&function_end_B("gcm_gmult_clmul");
++
++&function_begin("gcm_ghash_clmul");
++	&mov		($Xip,&wparam(0));
++	&mov		($Htbl,&wparam(1));
++	&mov		($inp,&wparam(2));
++	&mov		($len,&wparam(3));
++
++	&call		(&label("pic"));
++&set_label("pic");
++	&blindpop	($const);
++	&lea		($const,&DWP(&label("bswap")."-".&label("pic"),$const));
++
++	&movdqu		($Xi,&QWP(0,$Xip));
++	&movdqa		($T3,&QWP(0,$const));
++	&movdqu		($Hkey,&QWP(0,$Htbl));
++	&pshufb		($Xi,$T3);
++
++	&sub		($len,0x10);
++	&jz		(&label("odd_tail"));
++
++	#######
++	# Xi+2 =[H*(Ii+1 + Xi+1)] mod P =
++	#	[(H*Ii+1) + (H*Xi+1)] mod P =
++	#	[(H*Ii+1) + H^2*(Ii+Xi)] mod P
++	#
++	&movdqu		($T1,&QWP(0,$inp));	# Ii
++	&movdqu		($Xn,&QWP(16,$inp));	# Ii+1
++	&pshufb		($T1,$T3);
++	&pshufb		($Xn,$T3);
++	&pxor		($Xi,$T1);		# Ii+Xi
++
++	&clmul64x64_T3	($Xhn,$Xn,$Hkey);	# H*Ii+1
++	&movdqu		($Hkey,&QWP(16,$Htbl));	# load H^2
++
++	&sub		($len,0x20);
++	&lea		($inp,&DWP(32,$inp));	# i+=2
++	&jbe		(&label("even_tail"));
++
++&set_label("mod_loop");
++	&clmul64x64_T3	($Xhi,$Xi,$Hkey);	# H^2*(Ii+Xi)
++	&movdqu		($Hkey,&QWP(0,$Htbl));	# load H
++
++	&pxor		($Xi,$Xn);		# (H*Ii+1) + H^2*(Ii+Xi)
++	&pxor		($Xhi,$Xhn);
++
++	&reduction_alg5	($Xhi,$Xi);
++
++	#######
++	&movdqa		($T3,&QWP(0,$const));
++	&movdqu		($T1,&QWP(0,$inp));	# Ii
++	&movdqu		($Xn,&QWP(16,$inp));	# Ii+1
++	&pshufb		($T1,$T3);
++	&pshufb		($Xn,$T3);
++	&pxor		($Xi,$T1);		# Ii+Xi
++
++	&clmul64x64_T3	($Xhn,$Xn,$Hkey);	# H*Ii+1
++	&movdqu		($Hkey,&QWP(16,$Htbl));	# load H^2
++
++	&sub		($len,0x20);
++	&lea		($inp,&DWP(32,$inp));
++	&ja		(&label("mod_loop"));
++
++&set_label("even_tail");
++	&clmul64x64_T3	($Xhi,$Xi,$Hkey);	# H^2*(Ii+Xi)
++
++	&pxor		($Xi,$Xn);		# (H*Ii+1) + H^2*(Ii+Xi)
++	&pxor		($Xhi,$Xhn);
++
++	&reduction_alg5	($Xhi,$Xi);
++
++	&movdqa		($T3,&QWP(0,$const));
++	&test		($len,$len);
++	&jnz		(&label("done"));
++
++	&movdqu		($Hkey,&QWP(0,$Htbl));	# load H
++&set_label("odd_tail");
++	&movdqu		($T1,&QWP(0,$inp));	# Ii
++	&pshufb		($T1,$T3);
++	&pxor		($Xi,$T1);		# Ii+Xi
++
++	&clmul64x64_T3	($Xhi,$Xi,$Hkey);	# H*(Ii+Xi)
++	&reduction_alg5	($Xhi,$Xi);
++
++	&movdqa		($T3,&QWP(0,$const));
++&set_label("done");
++	&pshufb		($Xi,$T3);
++	&movdqu		(&QWP(0,$Xip),$Xi);
++&function_end("gcm_ghash_clmul");
++
++}
++
++&set_label("bswap",64);
++	&data_byte(15,14,13,12,11,10,9,8,7,6,5,4,3,2,1,0);
++	&data_byte(1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0xc2);	# 0x1c2_polynomial
++&set_label("rem_8bit",64);
++	&data_short(0x0000,0x01C2,0x0384,0x0246,0x0708,0x06CA,0x048C,0x054E);
++	&data_short(0x0E10,0x0FD2,0x0D94,0x0C56,0x0918,0x08DA,0x0A9C,0x0B5E);
++	&data_short(0x1C20,0x1DE2,0x1FA4,0x1E66,0x1B28,0x1AEA,0x18AC,0x196E);
++	&data_short(0x1230,0x13F2,0x11B4,0x1076,0x1538,0x14FA,0x16BC,0x177E);
++	&data_short(0x3840,0x3982,0x3BC4,0x3A06,0x3F48,0x3E8A,0x3CCC,0x3D0E);
++	&data_short(0x3650,0x3792,0x35D4,0x3416,0x3158,0x309A,0x32DC,0x331E);
++	&data_short(0x2460,0x25A2,0x27E4,0x2626,0x2368,0x22AA,0x20EC,0x212E);
++	&data_short(0x2A70,0x2BB2,0x29F4,0x2836,0x2D78,0x2CBA,0x2EFC,0x2F3E);
++	&data_short(0x7080,0x7142,0x7304,0x72C6,0x7788,0x764A,0x740C,0x75CE);
++	&data_short(0x7E90,0x7F52,0x7D14,0x7CD6,0x7998,0x785A,0x7A1C,0x7BDE);
++	&data_short(0x6CA0,0x6D62,0x6F24,0x6EE6,0x6BA8,0x6A6A,0x682C,0x69EE);
++	&data_short(0x62B0,0x6372,0x6134,0x60F6,0x65B8,0x647A,0x663C,0x67FE);
++	&data_short(0x48C0,0x4902,0x4B44,0x4A86,0x4FC8,0x4E0A,0x4C4C,0x4D8E);
++	&data_short(0x46D0,0x4712,0x4554,0x4496,0x41D8,0x401A,0x425C,0x439E);
++	&data_short(0x54E0,0x5522,0x5764,0x56A6,0x53E8,0x522A,0x506C,0x51AE);
++	&data_short(0x5AF0,0x5B32,0x5974,0x58B6,0x5DF8,0x5C3A,0x5E7C,0x5FBE);
++	&data_short(0xE100,0xE0C2,0xE284,0xE346,0xE608,0xE7CA,0xE58C,0xE44E);
++	&data_short(0xEF10,0xEED2,0xEC94,0xED56,0xE818,0xE9DA,0xEB9C,0xEA5E);
++	&data_short(0xFD20,0xFCE2,0xFEA4,0xFF66,0xFA28,0xFBEA,0xF9AC,0xF86E);
++	&data_short(0xF330,0xF2F2,0xF0B4,0xF176,0xF438,0xF5FA,0xF7BC,0xF67E);
++	&data_short(0xD940,0xD882,0xDAC4,0xDB06,0xDE48,0xDF8A,0xDDCC,0xDC0E);
++	&data_short(0xD750,0xD692,0xD4D4,0xD516,0xD058,0xD19A,0xD3DC,0xD21E);
++	&data_short(0xC560,0xC4A2,0xC6E4,0xC726,0xC268,0xC3AA,0xC1EC,0xC02E);
++	&data_short(0xCB70,0xCAB2,0xC8F4,0xC936,0xCC78,0xCDBA,0xCFFC,0xCE3E);
++	&data_short(0x9180,0x9042,0x9204,0x93C6,0x9688,0x974A,0x950C,0x94CE);
++	&data_short(0x9F90,0x9E52,0x9C14,0x9DD6,0x9898,0x995A,0x9B1C,0x9ADE);
++	&data_short(0x8DA0,0x8C62,0x8E24,0x8FE6,0x8AA8,0x8B6A,0x892C,0x88EE);
++	&data_short(0x83B0,0x8272,0x8034,0x81F6,0x84B8,0x857A,0x873C,0x86FE);
++	&data_short(0xA9C0,0xA802,0xAA44,0xAB86,0xAEC8,0xAF0A,0xAD4C,0xAC8E);
++	&data_short(0xA7D0,0xA612,0xA454,0xA596,0xA0D8,0xA11A,0xA35C,0xA29E);
++	&data_short(0xB5E0,0xB422,0xB664,0xB7A6,0xB2E8,0xB32A,0xB16C,0xB0AE);
++	&data_short(0xBBF0,0xBA32,0xB874,0xB9B6,0xBCF8,0xBD3A,0xBF7C,0xBEBE);
++}}	# $sse2
++
++&set_label("rem_4bit",64);
++	&data_word(0,0x0000<<$S,0,0x1C20<<$S,0,0x3840<<$S,0,0x2460<<$S);
++	&data_word(0,0x7080<<$S,0,0x6CA0<<$S,0,0x48C0<<$S,0,0x54E0<<$S);
++	&data_word(0,0xE100<<$S,0,0xFD20<<$S,0,0xD940<<$S,0,0xC560<<$S);
++	&data_word(0,0x9180<<$S,0,0x8DA0<<$S,0,0xA9C0<<$S,0,0xB5E0<<$S);
++}}}	# !$x86only
++
++&asciz("GHASH for x86, CRYPTOGAMS by ");
++&asm_finish();
++
++close STDOUT;
++
++# A question was risen about choice of vanilla MMX. Or rather why wasn't
++# SSE2 chosen instead? In addition to the fact that MMX runs on legacy
++# CPUs such as PIII, "4-bit" MMX version was observed to provide better
++# performance than *corresponding* SSE2 one even on contemporary CPUs.
++# SSE2 results were provided by Peter-Michael Hager. He maintains SSE2
++# implementation featuring full range of lookup-table sizes, but with
++# per-invocation lookup table setup. Latter means that table size is
++# chosen depending on how much data is to be hashed in every given call,
++# more data - larger table. Best reported result for Core2 is ~4 cycles
++# per processed byte out of 64KB block. This number accounts even for
++# 64KB table setup overhead. As discussed in gcm128.c we choose to be
++# more conservative in respect to lookup table sizes, but how do the
++# results compare? Minimalistic "256B" MMX version delivers ~11 cycles
++# on same platform. As also discussed in gcm128.c, next in line "8-bit
++# Shoup's" or "4KB" method should deliver twice the performance of
++# "256B" one, in other words not worse than ~6 cycles per byte. It
++# should be also be noted that in SSE2 case improvement can be "super-
++# linear," i.e. more than twice, mostly because >>8 maps to single
++# instruction on SSE2 register. This is unlike "4-bit" case when >>4
++# maps to same amount of instructions in both MMX and SSE2 cases.
++# Bottom line is that switch to SSE2 is considered to be justifiable
++# only in case we choose to implement "8-bit" method...
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/modes/asm/ghash-x86_64.pl b/CryptoPkg/Library/OpensslLib/openssl/crypto/modes/asm/ghash-x86_64.pl
+new file mode 100644
+index 0000000..387e3f8
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/modes/asm/ghash-x86_64.pl
+@@ -0,0 +1,1762 @@
++#! /usr/bin/env perl
++# Copyright 2010-2016 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
++# in the file LICENSE in the source distribution or at
++# https://www.openssl.org/source/license.html
++
++#
++# ====================================================================
++# Written by Andy Polyakov  for the OpenSSL
++# project. The module is, however, dual licensed under OpenSSL and
++# CRYPTOGAMS licenses depending on where you obtain it. For further
++# details see http://www.openssl.org/~appro/cryptogams/.
++# ====================================================================
++#
++# March, June 2010
++#
++# The module implements "4-bit" GCM GHASH function and underlying
++# single multiplication operation in GF(2^128). "4-bit" means that
++# it uses 256 bytes per-key table [+128 bytes shared table]. GHASH
++# function features so called "528B" variant utilizing additional
++# 256+16 bytes of per-key storage [+512 bytes shared table].
++# Performance results are for this streamed GHASH subroutine and are
++# expressed in cycles per processed byte, less is better:
++#
++#		gcc 3.4.x(*)	assembler
++#
++# P4		28.6		14.0		+100%
++# Opteron	19.3		7.7		+150%
++# Core2		17.8		8.1(**)		+120%
++# Atom		31.6		16.8		+88%
++# VIA Nano	21.8		10.1		+115%
++#
++# (*)	comparison is not completely fair, because C results are
++#	for vanilla "256B" implementation, while assembler results
++#	are for "528B";-)
++# (**)	it's mystery [to me] why Core2 result is not same as for
++#	Opteron;
++
++# May 2010
++#
++# Add PCLMULQDQ version performing at 2.02 cycles per processed byte.
++# See ghash-x86.pl for background information and details about coding
++# techniques.
++#
++# Special thanks to David Woodhouse  for
++# providing access to a Westmere-based system on behalf of Intel
++# Open Source Technology Centre.
++
++# December 2012
++#
++# Overhaul: aggregate Karatsuba post-processing, improve ILP in
++# reduction_alg9, increase reduction aggregate factor to 4x. As for
++# the latter. ghash-x86.pl discusses that it makes lesser sense to
++# increase aggregate factor. Then why increase here? Critical path
++# consists of 3 independent pclmulqdq instructions, Karatsuba post-
++# processing and reduction. "On top" of this we lay down aggregated
++# multiplication operations, triplets of independent pclmulqdq's. As
++# issue rate for pclmulqdq is limited, it makes lesser sense to
++# aggregate more multiplications than it takes to perform remaining
++# non-multiplication operations. 2x is near-optimal coefficient for
++# contemporary Intel CPUs (therefore modest improvement coefficient),
++# but not for Bulldozer. Latter is because logical SIMD operations
++# are twice as slow in comparison to Intel, so that critical path is
++# longer. A CPU with higher pclmulqdq issue rate would also benefit
++# from higher aggregate factor...
++#
++# Westmere	1.78(+13%)
++# Sandy Bridge	1.80(+8%)
++# Ivy Bridge	1.80(+7%)
++# Haswell	0.55(+93%) (if system doesn't support AVX)
++# Broadwell	0.45(+110%)(if system doesn't support AVX)
++# Skylake	0.44(+110%)(if system doesn't support AVX)
++# Bulldozer	1.49(+27%)
++# Silvermont	2.88(+13%)
++# Goldmont	1.08(+24%)
++
++# March 2013
++#
++# ... 8x aggregate factor AVX code path is using reduction algorithm
++# suggested by Shay Gueron[1]. Even though contemporary AVX-capable
++# CPUs such as Sandy and Ivy Bridge can execute it, the code performs
++# sub-optimally in comparison to above mentioned version. But thanks
++# to Ilya Albrekht and Max Locktyukhin of Intel Corp. we knew that
++# it performs in 0.41 cycles per byte on Haswell processor, in
++# 0.29 on Broadwell, and in 0.36 on Skylake.
++#
++# [1] http://rt.openssl.org/Ticket/Display.html?id=2900&user=guest&pass=guest
++
++$flavour = shift;
++$output  = shift;
++if ($flavour =~ /\./) { $output = $flavour; undef $flavour; }
++
++$win64=0; $win64=1 if ($flavour =~ /[nm]asm|mingw64/ || $output =~ /\.asm$/);
++
++$0 =~ m/(.*[\/\\])[^\/\\]+$/; $dir=$1;
++( $xlate="${dir}x86_64-xlate.pl" and -f $xlate ) or
++( $xlate="${dir}../../perlasm/x86_64-xlate.pl" and -f $xlate) or
++die "can't locate x86_64-xlate.pl";
++
++if (`$ENV{CC} -Wa,-v -c -o /dev/null -x assembler /dev/null 2>&1`
++		=~ /GNU assembler version ([2-9]\.[0-9]+)/) {
++	$avx = ($1>=2.20) + ($1>=2.22);
++}
++
++if (!$avx && $win64 && ($flavour =~ /nasm/ || $ENV{ASM} =~ /nasm/) &&
++	    `nasm -v 2>&1` =~ /NASM version ([2-9]\.[0-9]+)/) {
++	$avx = ($1>=2.09) + ($1>=2.10);
++}
++
++if (!$avx && $win64 && ($flavour =~ /masm/ || $ENV{ASM} =~ /ml64/) &&
++	    `ml64 2>&1` =~ /Version ([0-9]+)\./) {
++	$avx = ($1>=10) + ($1>=11);
++}
++
++if (!$avx && `$ENV{CC} -v 2>&1` =~ /((?:^clang|LLVM) version|.*based on LLVM) ([3-9]\.[0-9]+)/) {
++	$avx = ($2>=3.0) + ($2>3.0);
++}
++
++open OUT,"| \"$^X\" \"$xlate\" $flavour \"$output\"";
++*STDOUT=*OUT;
++
++$do4xaggr=1;
++
++# common register layout
++$nlo="%rax";
++$nhi="%rbx";
++$Zlo="%r8";
++$Zhi="%r9";
++$tmp="%r10";
++$rem_4bit = "%r11";
++
++$Xi="%rdi";
++$Htbl="%rsi";
++
++# per-function register layout
++$cnt="%rcx";
++$rem="%rdx";
++
++sub LB() { my $r=shift; $r =~ s/%[er]([a-d])x/%\1l/	or
++			$r =~ s/%[er]([sd]i)/%\1l/	or
++			$r =~ s/%[er](bp)/%\1l/		or
++			$r =~ s/%(r[0-9]+)[d]?/%\1b/;   $r; }
++
++sub AUTOLOAD()		# thunk [simplified] 32-bit style perlasm
++{ my $opcode = $AUTOLOAD; $opcode =~ s/.*:://;
++  my $arg = pop;
++    $arg = "\$$arg" if ($arg*1 eq $arg);
++    $code .= "\t$opcode\t".join(',',$arg,reverse @_)."\n";
++}
++
++{ my $N;
++  sub loop() {
++  my $inp = shift;
++
++	$N++;
++$code.=<<___;
++	xor	$nlo,$nlo
++	xor	$nhi,$nhi
++	mov	`&LB("$Zlo")`,`&LB("$nlo")`
++	mov	`&LB("$Zlo")`,`&LB("$nhi")`
++	shl	\$4,`&LB("$nlo")`
++	mov	\$14,$cnt
++	mov	8($Htbl,$nlo),$Zlo
++	mov	($Htbl,$nlo),$Zhi
++	and	\$0xf0,`&LB("$nhi")`
++	mov	$Zlo,$rem
++	jmp	.Loop$N
++
++.align	16
++.Loop$N:
++	shr	\$4,$Zlo
++	and	\$0xf,$rem
++	mov	$Zhi,$tmp
++	mov	($inp,$cnt),`&LB("$nlo")`
++	shr	\$4,$Zhi
++	xor	8($Htbl,$nhi),$Zlo
++	shl	\$60,$tmp
++	xor	($Htbl,$nhi),$Zhi
++	mov	`&LB("$nlo")`,`&LB("$nhi")`
++	xor	($rem_4bit,$rem,8),$Zhi
++	mov	$Zlo,$rem
++	shl	\$4,`&LB("$nlo")`
++	xor	$tmp,$Zlo
++	dec	$cnt
++	js	.Lbreak$N
++
++	shr	\$4,$Zlo
++	and	\$0xf,$rem
++	mov	$Zhi,$tmp
++	shr	\$4,$Zhi
++	xor	8($Htbl,$nlo),$Zlo
++	shl	\$60,$tmp
++	xor	($Htbl,$nlo),$Zhi
++	and	\$0xf0,`&LB("$nhi")`
++	xor	($rem_4bit,$rem,8),$Zhi
++	mov	$Zlo,$rem
++	xor	$tmp,$Zlo
++	jmp	.Loop$N
++
++.align	16
++.Lbreak$N:
++	shr	\$4,$Zlo
++	and	\$0xf,$rem
++	mov	$Zhi,$tmp
++	shr	\$4,$Zhi
++	xor	8($Htbl,$nlo),$Zlo
++	shl	\$60,$tmp
++	xor	($Htbl,$nlo),$Zhi
++	and	\$0xf0,`&LB("$nhi")`
++	xor	($rem_4bit,$rem,8),$Zhi
++	mov	$Zlo,$rem
++	xor	$tmp,$Zlo
++
++	shr	\$4,$Zlo
++	and	\$0xf,$rem
++	mov	$Zhi,$tmp
++	shr	\$4,$Zhi
++	xor	8($Htbl,$nhi),$Zlo
++	shl	\$60,$tmp
++	xor	($Htbl,$nhi),$Zhi
++	xor	$tmp,$Zlo
++	xor	($rem_4bit,$rem,8),$Zhi
++
++	bswap	$Zlo
++	bswap	$Zhi
++___
++}}
++
++$code=<<___;
++.text
++.extern	OPENSSL_ia32cap_P
++
++.globl	gcm_gmult_4bit
++.type	gcm_gmult_4bit,\@function,2
++.align	16
++gcm_gmult_4bit:
++	push	%rbx
++	push	%rbp		# %rbp and %r12 are pushed exclusively in
++	push	%r12		# order to reuse Win64 exception handler...
++.Lgmult_prologue:
++
++	movzb	15($Xi),$Zlo
++	lea	.Lrem_4bit(%rip),$rem_4bit
++___
++	&loop	($Xi);
++$code.=<<___;
++	mov	$Zlo,8($Xi)
++	mov	$Zhi,($Xi)
++
++	mov	16(%rsp),%rbx
++	lea	24(%rsp),%rsp
++.Lgmult_epilogue:
++	ret
++.size	gcm_gmult_4bit,.-gcm_gmult_4bit
++___
++
++# per-function register layout
++$inp="%rdx";
++$len="%rcx";
++$rem_8bit=$rem_4bit;
++
++$code.=<<___;
++.globl	gcm_ghash_4bit
++.type	gcm_ghash_4bit,\@function,4
++.align	16
++gcm_ghash_4bit:
++	push	%rbx
++	push	%rbp
++	push	%r12
++	push	%r13
++	push	%r14
++	push	%r15
++	sub	\$280,%rsp
++.Lghash_prologue:
++	mov	$inp,%r14		# reassign couple of args
++	mov	$len,%r15
++___
++{ my $inp="%r14";
++  my $dat="%edx";
++  my $len="%r15";
++  my @nhi=("%ebx","%ecx");
++  my @rem=("%r12","%r13");
++  my $Hshr4="%rbp";
++
++	&sub	($Htbl,-128);		# size optimization
++	&lea	($Hshr4,"16+128(%rsp)");
++	{ my @lo =($nlo,$nhi);
++          my @hi =($Zlo,$Zhi);
++
++	  &xor	($dat,$dat);
++	  for ($i=0,$j=-2;$i<18;$i++,$j++) {
++	    &mov	("$j(%rsp)",&LB($dat))		if ($i>1);
++	    &or		($lo[0],$tmp)			if ($i>1);
++	    &mov	(&LB($dat),&LB($lo[1]))		if ($i>0 && $i<17);
++	    &shr	($lo[1],4)			if ($i>0 && $i<17);
++	    &mov	($tmp,$hi[1])			if ($i>0 && $i<17);
++	    &shr	($hi[1],4)			if ($i>0 && $i<17);
++	    &mov	("8*$j($Hshr4)",$hi[0])		if ($i>1);
++	    &mov	($hi[0],"16*$i+0-128($Htbl)")	if ($i<16);
++	    &shl	(&LB($dat),4)			if ($i>0 && $i<17);
++	    &mov	("8*$j-128($Hshr4)",$lo[0])	if ($i>1);
++	    &mov	($lo[0],"16*$i+8-128($Htbl)")	if ($i<16);
++	    &shl	($tmp,60)			if ($i>0 && $i<17);
++
++	    push	(@lo,shift(@lo));
++	    push	(@hi,shift(@hi));
++	  }
++	}
++	&add	($Htbl,-128);
++	&mov	($Zlo,"8($Xi)");
++	&mov	($Zhi,"0($Xi)");
++	&add	($len,$inp);		# pointer to the end of data
++	&lea	($rem_8bit,".Lrem_8bit(%rip)");
++	&jmp	(".Louter_loop");
++
++$code.=".align	16\n.Louter_loop:\n";
++	&xor	($Zhi,"($inp)");
++	&mov	("%rdx","8($inp)");
++	&lea	($inp,"16($inp)");
++	&xor	("%rdx",$Zlo);
++	&mov	("($Xi)",$Zhi);
++	&mov	("8($Xi)","%rdx");
++	&shr	("%rdx",32);
++
++	&xor	($nlo,$nlo);
++	&rol	($dat,8);
++	&mov	(&LB($nlo),&LB($dat));
++	&movz	($nhi[0],&LB($dat));
++	&shl	(&LB($nlo),4);
++	&shr	($nhi[0],4);
++
++	for ($j=11,$i=0;$i<15;$i++) {
++	    &rol	($dat,8);
++	    &xor	($Zlo,"8($Htbl,$nlo)")			if ($i>0);
++	    &xor	($Zhi,"($Htbl,$nlo)")			if ($i>0);
++	    &mov	($Zlo,"8($Htbl,$nlo)")			if ($i==0);
++	    &mov	($Zhi,"($Htbl,$nlo)")			if ($i==0);
++
++	    &mov	(&LB($nlo),&LB($dat));
++	    &xor	($Zlo,$tmp)				if ($i>0);
++	    &movzw	($rem[1],"($rem_8bit,$rem[1],2)")	if ($i>0);
++
++	    &movz	($nhi[1],&LB($dat));
++	    &shl	(&LB($nlo),4);
++	    &movzb	($rem[0],"(%rsp,$nhi[0])");
++
++	    &shr	($nhi[1],4)				if ($i<14);
++	    &and	($nhi[1],0xf0)				if ($i==14);
++	    &shl	($rem[1],48)				if ($i>0);
++	    &xor	($rem[0],$Zlo);
++
++	    &mov	($tmp,$Zhi);
++	    &xor	($Zhi,$rem[1])				if ($i>0);
++	    &shr	($Zlo,8);
++
++	    &movz	($rem[0],&LB($rem[0]));
++	    &mov	($dat,"$j($Xi)")			if (--$j%4==0);
++	    &shr	($Zhi,8);
++
++	    &xor	($Zlo,"-128($Hshr4,$nhi[0],8)");
++	    &shl	($tmp,56);
++	    &xor	($Zhi,"($Hshr4,$nhi[0],8)");
++
++	    unshift	(@nhi,pop(@nhi));		# "rotate" registers
++	    unshift	(@rem,pop(@rem));
++	}
++	&movzw	($rem[1],"($rem_8bit,$rem[1],2)");
++	&xor	($Zlo,"8($Htbl,$nlo)");
++	&xor	($Zhi,"($Htbl,$nlo)");
++
++	&shl	($rem[1],48);
++	&xor	($Zlo,$tmp);
++
++	&xor	($Zhi,$rem[1]);
++	&movz	($rem[0],&LB($Zlo));
++	&shr	($Zlo,4);
++
++	&mov	($tmp,$Zhi);
++	&shl	(&LB($rem[0]),4);
++	&shr	($Zhi,4);
++
++	&xor	($Zlo,"8($Htbl,$nhi[0])");
++	&movzw	($rem[0],"($rem_8bit,$rem[0],2)");
++	&shl	($tmp,60);
++
++	&xor	($Zhi,"($Htbl,$nhi[0])");
++	&xor	($Zlo,$tmp);
++	&shl	($rem[0],48);
++
++	&bswap	($Zlo);
++	&xor	($Zhi,$rem[0]);
++
++	&bswap	($Zhi);
++	&cmp	($inp,$len);
++	&jb	(".Louter_loop");
++}
++$code.=<<___;
++	mov	$Zlo,8($Xi)
++	mov	$Zhi,($Xi)
++
++	lea	280(%rsp),%rsi
++	mov	0(%rsi),%r15
++	mov	8(%rsi),%r14
++	mov	16(%rsi),%r13
++	mov	24(%rsi),%r12
++	mov	32(%rsi),%rbp
++	mov	40(%rsi),%rbx
++	lea	48(%rsi),%rsp
++.Lghash_epilogue:
++	ret
++.size	gcm_ghash_4bit,.-gcm_ghash_4bit
++___
++
++######################################################################
++# PCLMULQDQ version.
++
++@_4args=$win64?	("%rcx","%rdx","%r8", "%r9") :	# Win64 order
++		("%rdi","%rsi","%rdx","%rcx");	# Unix order
++
++($Xi,$Xhi)=("%xmm0","%xmm1");	$Hkey="%xmm2";
++($T1,$T2,$T3)=("%xmm3","%xmm4","%xmm5");
++
++sub clmul64x64_T2 {	# minimal register pressure
++my ($Xhi,$Xi,$Hkey,$HK)=@_;
++
++if (!defined($HK)) {	$HK = $T2;
++$code.=<<___;
++	movdqa		$Xi,$Xhi		#
++	pshufd		\$0b01001110,$Xi,$T1
++	pshufd		\$0b01001110,$Hkey,$T2
++	pxor		$Xi,$T1			#
++	pxor		$Hkey,$T2
++___
++} else {
++$code.=<<___;
++	movdqa		$Xi,$Xhi		#
++	pshufd		\$0b01001110,$Xi,$T1
++	pxor		$Xi,$T1			#
++___
++}
++$code.=<<___;
++	pclmulqdq	\$0x00,$Hkey,$Xi	#######
++	pclmulqdq	\$0x11,$Hkey,$Xhi	#######
++	pclmulqdq	\$0x00,$HK,$T1		#######
++	pxor		$Xi,$T1			#
++	pxor		$Xhi,$T1		#
++
++	movdqa		$T1,$T2			#
++	psrldq		\$8,$T1
++	pslldq		\$8,$T2			#
++	pxor		$T1,$Xhi
++	pxor		$T2,$Xi			#
++___
++}
++
++sub reduction_alg9 {	# 17/11 times faster than Intel version
++my ($Xhi,$Xi) = @_;
++
++$code.=<<___;
++	# 1st phase
++	movdqa		$Xi,$T2			#
++	movdqa		$Xi,$T1
++	psllq		\$5,$Xi
++	pxor		$Xi,$T1			#
++	psllq		\$1,$Xi
++	pxor		$T1,$Xi			#
++	psllq		\$57,$Xi		#
++	movdqa		$Xi,$T1			#
++	pslldq		\$8,$Xi
++	psrldq		\$8,$T1			#	
++	pxor		$T2,$Xi
++	pxor		$T1,$Xhi		#
++
++	# 2nd phase
++	movdqa		$Xi,$T2
++	psrlq		\$1,$Xi
++	pxor		$T2,$Xhi		#
++	pxor		$Xi,$T2
++	psrlq		\$5,$Xi
++	pxor		$T2,$Xi			#
++	psrlq		\$1,$Xi			#
++	pxor		$Xhi,$Xi		#
++___
++}
++
++{ my ($Htbl,$Xip)=@_4args;
++  my $HK="%xmm6";
++
++$code.=<<___;
++.globl	gcm_init_clmul
++.type	gcm_init_clmul,\@abi-omnipotent
++.align	16
++gcm_init_clmul:
++.L_init_clmul:
++___
++$code.=<<___ if ($win64);
++.LSEH_begin_gcm_init_clmul:
++	# I can't trust assembler to use specific encoding:-(
++	.byte	0x48,0x83,0xec,0x18		#sub	$0x18,%rsp
++	.byte	0x0f,0x29,0x34,0x24		#movaps	%xmm6,(%rsp)
++___
++$code.=<<___;
++	movdqu		($Xip),$Hkey
++	pshufd		\$0b01001110,$Hkey,$Hkey	# dword swap
++
++	# <<1 twist
++	pshufd		\$0b11111111,$Hkey,$T2	# broadcast uppermost dword
++	movdqa		$Hkey,$T1
++	psllq		\$1,$Hkey
++	pxor		$T3,$T3			#
++	psrlq		\$63,$T1
++	pcmpgtd		$T2,$T3			# broadcast carry bit
++	pslldq		\$8,$T1
++	por		$T1,$Hkey		# H<<=1
++
++	# magic reduction
++	pand		.L0x1c2_polynomial(%rip),$T3
++	pxor		$T3,$Hkey		# if(carry) H^=0x1c2_polynomial
++
++	# calculate H^2
++	pshufd		\$0b01001110,$Hkey,$HK
++	movdqa		$Hkey,$Xi
++	pxor		$Hkey,$HK
++___
++	&clmul64x64_T2	($Xhi,$Xi,$Hkey,$HK);
++	&reduction_alg9	($Xhi,$Xi);
++$code.=<<___;
++	pshufd		\$0b01001110,$Hkey,$T1
++	pshufd		\$0b01001110,$Xi,$T2
++	pxor		$Hkey,$T1		# Karatsuba pre-processing
++	movdqu		$Hkey,0x00($Htbl)	# save H
++	pxor		$Xi,$T2			# Karatsuba pre-processing
++	movdqu		$Xi,0x10($Htbl)		# save H^2
++	palignr		\$8,$T1,$T2		# low part is H.lo^H.hi...
++	movdqu		$T2,0x20($Htbl)		# save Karatsuba "salt"
++___
++if ($do4xaggr) {
++	&clmul64x64_T2	($Xhi,$Xi,$Hkey,$HK);	# H^3
++	&reduction_alg9	($Xhi,$Xi);
++$code.=<<___;
++	movdqa		$Xi,$T3
++___
++	&clmul64x64_T2	($Xhi,$Xi,$Hkey,$HK);	# H^4
++	&reduction_alg9	($Xhi,$Xi);
++$code.=<<___;
++	pshufd		\$0b01001110,$T3,$T1
++	pshufd		\$0b01001110,$Xi,$T2
++	pxor		$T3,$T1			# Karatsuba pre-processing
++	movdqu		$T3,0x30($Htbl)		# save H^3
++	pxor		$Xi,$T2			# Karatsuba pre-processing
++	movdqu		$Xi,0x40($Htbl)		# save H^4
++	palignr		\$8,$T1,$T2		# low part is H^3.lo^H^3.hi...
++	movdqu		$T2,0x50($Htbl)		# save Karatsuba "salt"
++___
++}
++$code.=<<___ if ($win64);
++	movaps	(%rsp),%xmm6
++	lea	0x18(%rsp),%rsp
++.LSEH_end_gcm_init_clmul:
++___
++$code.=<<___;
++	ret
++.size	gcm_init_clmul,.-gcm_init_clmul
++___
++}
++
++{ my ($Xip,$Htbl)=@_4args;
++
++$code.=<<___;
++.globl	gcm_gmult_clmul
++.type	gcm_gmult_clmul,\@abi-omnipotent
++.align	16
++gcm_gmult_clmul:
++.L_gmult_clmul:
++	movdqu		($Xip),$Xi
++	movdqa		.Lbswap_mask(%rip),$T3
++	movdqu		($Htbl),$Hkey
++	movdqu		0x20($Htbl),$T2
++	pshufb		$T3,$Xi
++___
++	&clmul64x64_T2	($Xhi,$Xi,$Hkey,$T2);
++$code.=<<___ if (0 || (&reduction_alg9($Xhi,$Xi)&&0));
++	# experimental alternative. special thing about is that there
++	# no dependency between the two multiplications... 
++	mov		\$`0xE1<<1`,%eax
++	mov		\$0xA040608020C0E000,%r10	# ((7..0)·0xE0)&0xff
++	mov		\$0x07,%r11d
++	movq		%rax,$T1
++	movq		%r10,$T2
++	movq		%r11,$T3		# borrow $T3
++	pand		$Xi,$T3
++	pshufb		$T3,$T2			# ($Xi&7)·0xE0
++	movq		%rax,$T3
++	pclmulqdq	\$0x00,$Xi,$T1		# ·(0xE1<<1)
++	pxor		$Xi,$T2
++	pslldq		\$15,$T2
++	paddd		$T2,$T2			# <<(64+56+1)
++	pxor		$T2,$Xi
++	pclmulqdq	\$0x01,$T3,$Xi
++	movdqa		.Lbswap_mask(%rip),$T3	# reload $T3
++	psrldq		\$1,$T1
++	pxor		$T1,$Xhi
++	pslldq		\$7,$Xi
++	pxor		$Xhi,$Xi
++___
++$code.=<<___;
++	pshufb		$T3,$Xi
++	movdqu		$Xi,($Xip)
++	ret
++.size	gcm_gmult_clmul,.-gcm_gmult_clmul
++___
++}
++
++{ my ($Xip,$Htbl,$inp,$len)=@_4args;
++  my ($Xln,$Xmn,$Xhn,$Hkey2,$HK) = map("%xmm$_",(3..7));
++  my ($T1,$T2,$T3)=map("%xmm$_",(8..10));
++
++$code.=<<___;
++.globl	gcm_ghash_clmul
++.type	gcm_ghash_clmul,\@abi-omnipotent
++.align	32
++gcm_ghash_clmul:
++.L_ghash_clmul:
++___
++$code.=<<___ if ($win64);
++	lea	-0x88(%rsp),%rax
++.LSEH_begin_gcm_ghash_clmul:
++	# I can't trust assembler to use specific encoding:-(
++	.byte	0x48,0x8d,0x60,0xe0		#lea	-0x20(%rax),%rsp
++	.byte	0x0f,0x29,0x70,0xe0		#movaps	%xmm6,-0x20(%rax)
++	.byte	0x0f,0x29,0x78,0xf0		#movaps	%xmm7,-0x10(%rax)
++	.byte	0x44,0x0f,0x29,0x00		#movaps	%xmm8,0(%rax)
++	.byte	0x44,0x0f,0x29,0x48,0x10	#movaps	%xmm9,0x10(%rax)
++	.byte	0x44,0x0f,0x29,0x50,0x20	#movaps	%xmm10,0x20(%rax)
++	.byte	0x44,0x0f,0x29,0x58,0x30	#movaps	%xmm11,0x30(%rax)
++	.byte	0x44,0x0f,0x29,0x60,0x40	#movaps	%xmm12,0x40(%rax)
++	.byte	0x44,0x0f,0x29,0x68,0x50	#movaps	%xmm13,0x50(%rax)
++	.byte	0x44,0x0f,0x29,0x70,0x60	#movaps	%xmm14,0x60(%rax)
++	.byte	0x44,0x0f,0x29,0x78,0x70	#movaps	%xmm15,0x70(%rax)
++___
++$code.=<<___;
++	movdqa		.Lbswap_mask(%rip),$T3
++
++	movdqu		($Xip),$Xi
++	movdqu		($Htbl),$Hkey
++	movdqu		0x20($Htbl),$HK
++	pshufb		$T3,$Xi
++
++	sub		\$0x10,$len
++	jz		.Lodd_tail
++
++	movdqu		0x10($Htbl),$Hkey2
++___
++if ($do4xaggr) {
++my ($Xl,$Xm,$Xh,$Hkey3,$Hkey4)=map("%xmm$_",(11..15));
++
++$code.=<<___;
++	mov		OPENSSL_ia32cap_P+4(%rip),%eax
++	cmp		\$0x30,$len
++	jb		.Lskip4x
++
++	and		\$`1<<26|1<<22`,%eax	# isolate MOVBE+XSAVE
++	cmp		\$`1<<22`,%eax		# check for MOVBE without XSAVE
++	je		.Lskip4x
++
++	sub		\$0x30,$len
++	mov		\$0xA040608020C0E000,%rax	# ((7..0)·0xE0)&0xff
++	movdqu		0x30($Htbl),$Hkey3
++	movdqu		0x40($Htbl),$Hkey4
++
++	#######
++	# Xi+4 =[(H*Ii+3) + (H^2*Ii+2) + (H^3*Ii+1) + H^4*(Ii+Xi)] mod P
++	#
++	movdqu		0x30($inp),$Xln
++	 movdqu		0x20($inp),$Xl
++	pshufb		$T3,$Xln
++	 pshufb		$T3,$Xl
++	movdqa		$Xln,$Xhn
++	pshufd		\$0b01001110,$Xln,$Xmn
++	pxor		$Xln,$Xmn
++	pclmulqdq	\$0x00,$Hkey,$Xln
++	pclmulqdq	\$0x11,$Hkey,$Xhn
++	pclmulqdq	\$0x00,$HK,$Xmn
++
++	movdqa		$Xl,$Xh
++	pshufd		\$0b01001110,$Xl,$Xm
++	pxor		$Xl,$Xm
++	pclmulqdq	\$0x00,$Hkey2,$Xl
++	pclmulqdq	\$0x11,$Hkey2,$Xh
++	pclmulqdq	\$0x10,$HK,$Xm
++	xorps		$Xl,$Xln
++	xorps		$Xh,$Xhn
++	movups		0x50($Htbl),$HK
++	xorps		$Xm,$Xmn
++
++	movdqu		0x10($inp),$Xl
++	 movdqu		0($inp),$T1
++	pshufb		$T3,$Xl
++	 pshufb		$T3,$T1
++	movdqa		$Xl,$Xh
++	pshufd		\$0b01001110,$Xl,$Xm
++	 pxor		$T1,$Xi
++	pxor		$Xl,$Xm
++	pclmulqdq	\$0x00,$Hkey3,$Xl
++	 movdqa		$Xi,$Xhi
++	 pshufd		\$0b01001110,$Xi,$T1
++	 pxor		$Xi,$T1
++	pclmulqdq	\$0x11,$Hkey3,$Xh
++	pclmulqdq	\$0x00,$HK,$Xm
++	xorps		$Xl,$Xln
++	xorps		$Xh,$Xhn
++
++	lea	0x40($inp),$inp
++	sub	\$0x40,$len
++	jc	.Ltail4x
++
++	jmp	.Lmod4_loop
++.align	32
++.Lmod4_loop:
++	pclmulqdq	\$0x00,$Hkey4,$Xi
++	xorps		$Xm,$Xmn
++	 movdqu		0x30($inp),$Xl
++	 pshufb		$T3,$Xl
++	pclmulqdq	\$0x11,$Hkey4,$Xhi
++	xorps		$Xln,$Xi
++	 movdqu		0x20($inp),$Xln
++	 movdqa		$Xl,$Xh
++	pclmulqdq	\$0x10,$HK,$T1
++	 pshufd		\$0b01001110,$Xl,$Xm
++	xorps		$Xhn,$Xhi
++	 pxor		$Xl,$Xm
++	 pshufb		$T3,$Xln
++	movups		0x20($Htbl),$HK
++	xorps		$Xmn,$T1
++	 pclmulqdq	\$0x00,$Hkey,$Xl
++	 pshufd		\$0b01001110,$Xln,$Xmn
++
++	pxor		$Xi,$T1			# aggregated Karatsuba post-processing
++	 movdqa		$Xln,$Xhn
++	pxor		$Xhi,$T1		#
++	 pxor		$Xln,$Xmn
++	movdqa		$T1,$T2			#
++	 pclmulqdq	\$0x11,$Hkey,$Xh
++	pslldq		\$8,$T1
++	psrldq		\$8,$T2			#
++	pxor		$T1,$Xi
++	movdqa		.L7_mask(%rip),$T1
++	pxor		$T2,$Xhi		#
++	movq		%rax,$T2
++
++	pand		$Xi,$T1			# 1st phase
++	pshufb		$T1,$T2			#
++	pxor		$Xi,$T2			#
++	 pclmulqdq	\$0x00,$HK,$Xm
++	psllq		\$57,$T2		#
++	movdqa		$T2,$T1			#
++	pslldq		\$8,$T2
++	 pclmulqdq	\$0x00,$Hkey2,$Xln
++	psrldq		\$8,$T1			#	
++	pxor		$T2,$Xi
++	pxor		$T1,$Xhi		#
++	movdqu		0($inp),$T1
++
++	movdqa		$Xi,$T2			# 2nd phase
++	psrlq		\$1,$Xi
++	 pclmulqdq	\$0x11,$Hkey2,$Xhn
++	 xorps		$Xl,$Xln
++	 movdqu		0x10($inp),$Xl
++	 pshufb		$T3,$Xl
++	 pclmulqdq	\$0x10,$HK,$Xmn
++	 xorps		$Xh,$Xhn
++	 movups		0x50($Htbl),$HK
++	pshufb		$T3,$T1
++	pxor		$T2,$Xhi		#
++	pxor		$Xi,$T2
++	psrlq		\$5,$Xi
++
++	 movdqa		$Xl,$Xh
++	 pxor		$Xm,$Xmn
++	 pshufd		\$0b01001110,$Xl,$Xm
++	pxor		$T2,$Xi			#
++	pxor		$T1,$Xhi
++	 pxor		$Xl,$Xm
++	 pclmulqdq	\$0x00,$Hkey3,$Xl
++	psrlq		\$1,$Xi			#
++	pxor		$Xhi,$Xi		#
++	movdqa		$Xi,$Xhi
++	 pclmulqdq	\$0x11,$Hkey3,$Xh
++	 xorps		$Xl,$Xln
++	pshufd		\$0b01001110,$Xi,$T1
++	pxor		$Xi,$T1
++
++	 pclmulqdq	\$0x00,$HK,$Xm
++	 xorps		$Xh,$Xhn
++
++	lea	0x40($inp),$inp
++	sub	\$0x40,$len
++	jnc	.Lmod4_loop
++
++.Ltail4x:
++	pclmulqdq	\$0x00,$Hkey4,$Xi
++	pclmulqdq	\$0x11,$Hkey4,$Xhi
++	pclmulqdq	\$0x10,$HK,$T1
++	xorps		$Xm,$Xmn
++	xorps		$Xln,$Xi
++	xorps		$Xhn,$Xhi
++	pxor		$Xi,$Xhi		# aggregated Karatsuba post-processing
++	pxor		$Xmn,$T1
++
++	pxor		$Xhi,$T1		#
++	pxor		$Xi,$Xhi
++
++	movdqa		$T1,$T2			#
++	psrldq		\$8,$T1
++	pslldq		\$8,$T2			#
++	pxor		$T1,$Xhi
++	pxor		$T2,$Xi			#
++___
++	&reduction_alg9($Xhi,$Xi);
++$code.=<<___;
++	add	\$0x40,$len
++	jz	.Ldone
++	movdqu	0x20($Htbl),$HK
++	sub	\$0x10,$len
++	jz	.Lodd_tail
++.Lskip4x:
++___
++}
++$code.=<<___;
++	#######
++	# Xi+2 =[H*(Ii+1 + Xi+1)] mod P =
++	#	[(H*Ii+1) + (H*Xi+1)] mod P =
++	#	[(H*Ii+1) + H^2*(Ii+Xi)] mod P
++	#
++	movdqu		($inp),$T1		# Ii
++	movdqu		16($inp),$Xln		# Ii+1
++	pshufb		$T3,$T1
++	pshufb		$T3,$Xln
++	pxor		$T1,$Xi			# Ii+Xi
++
++	movdqa		$Xln,$Xhn
++	pshufd		\$0b01001110,$Xln,$Xmn
++	pxor		$Xln,$Xmn
++	pclmulqdq	\$0x00,$Hkey,$Xln
++	pclmulqdq	\$0x11,$Hkey,$Xhn
++	pclmulqdq	\$0x00,$HK,$Xmn
++
++	lea		32($inp),$inp		# i+=2
++	nop
++	sub		\$0x20,$len
++	jbe		.Leven_tail
++	nop
++	jmp		.Lmod_loop
++
++.align	32
++.Lmod_loop:
++	movdqa		$Xi,$Xhi
++	movdqa		$Xmn,$T1
++	pshufd		\$0b01001110,$Xi,$Xmn	#
++	pxor		$Xi,$Xmn		#
++
++	pclmulqdq	\$0x00,$Hkey2,$Xi
++	pclmulqdq	\$0x11,$Hkey2,$Xhi
++	pclmulqdq	\$0x10,$HK,$Xmn
++
++	pxor		$Xln,$Xi		# (H*Ii+1) + H^2*(Ii+Xi)
++	pxor		$Xhn,$Xhi
++	  movdqu	($inp),$T2		# Ii
++	pxor		$Xi,$T1			# aggregated Karatsuba post-processing
++	  pshufb	$T3,$T2
++	  movdqu	16($inp),$Xln		# Ii+1
++
++	pxor		$Xhi,$T1
++	  pxor		$T2,$Xhi		# "Ii+Xi", consume early
++	pxor		$T1,$Xmn
++	 pshufb		$T3,$Xln
++	movdqa		$Xmn,$T1		#
++	psrldq		\$8,$T1
++	pslldq		\$8,$Xmn		#
++	pxor		$T1,$Xhi
++	pxor		$Xmn,$Xi		#
++
++	movdqa		$Xln,$Xhn		#
++
++	  movdqa	$Xi,$T2			# 1st phase
++	  movdqa	$Xi,$T1
++	  psllq		\$5,$Xi
++	  pxor		$Xi,$T1			#
++	pclmulqdq	\$0x00,$Hkey,$Xln	#######
++	  psllq		\$1,$Xi
++	  pxor		$T1,$Xi			#
++	  psllq		\$57,$Xi		#
++	  movdqa	$Xi,$T1			#
++	  pslldq	\$8,$Xi
++	  psrldq	\$8,$T1			#	
++	  pxor		$T2,$Xi
++	pshufd		\$0b01001110,$Xhn,$Xmn
++	  pxor		$T1,$Xhi		#
++	pxor		$Xhn,$Xmn		#
++
++	  movdqa	$Xi,$T2			# 2nd phase
++	  psrlq		\$1,$Xi
++	pclmulqdq	\$0x11,$Hkey,$Xhn	#######
++	  pxor		$T2,$Xhi		#
++	  pxor		$Xi,$T2
++	  psrlq		\$5,$Xi
++	  pxor		$T2,$Xi			#
++	lea		32($inp),$inp
++	  psrlq		\$1,$Xi			#
++	pclmulqdq	\$0x00,$HK,$Xmn		#######
++	  pxor		$Xhi,$Xi		#
++
++	sub		\$0x20,$len
++	ja		.Lmod_loop
++
++.Leven_tail:
++	 movdqa		$Xi,$Xhi
++	 movdqa		$Xmn,$T1
++	 pshufd		\$0b01001110,$Xi,$Xmn	#
++	 pxor		$Xi,$Xmn		#
++
++	pclmulqdq	\$0x00,$Hkey2,$Xi
++	pclmulqdq	\$0x11,$Hkey2,$Xhi
++	pclmulqdq	\$0x10,$HK,$Xmn
++
++	pxor		$Xln,$Xi		# (H*Ii+1) + H^2*(Ii+Xi)
++	pxor		$Xhn,$Xhi
++	pxor		$Xi,$T1
++	pxor		$Xhi,$T1
++	pxor		$T1,$Xmn
++	movdqa		$Xmn,$T1		#
++	psrldq		\$8,$T1
++	pslldq		\$8,$Xmn		#
++	pxor		$T1,$Xhi
++	pxor		$Xmn,$Xi		#
++___
++	&reduction_alg9	($Xhi,$Xi);
++$code.=<<___;
++	test		$len,$len
++	jnz		.Ldone
++
++.Lodd_tail:
++	movdqu		($inp),$T1		# Ii
++	pshufb		$T3,$T1
++	pxor		$T1,$Xi			# Ii+Xi
++___
++	&clmul64x64_T2	($Xhi,$Xi,$Hkey,$HK);	# H*(Ii+Xi)
++	&reduction_alg9	($Xhi,$Xi);
++$code.=<<___;
++.Ldone:
++	pshufb		$T3,$Xi
++	movdqu		$Xi,($Xip)
++___
++$code.=<<___ if ($win64);
++	movaps	(%rsp),%xmm6
++	movaps	0x10(%rsp),%xmm7
++	movaps	0x20(%rsp),%xmm8
++	movaps	0x30(%rsp),%xmm9
++	movaps	0x40(%rsp),%xmm10
++	movaps	0x50(%rsp),%xmm11
++	movaps	0x60(%rsp),%xmm12
++	movaps	0x70(%rsp),%xmm13
++	movaps	0x80(%rsp),%xmm14
++	movaps	0x90(%rsp),%xmm15
++	lea	0xa8(%rsp),%rsp
++.LSEH_end_gcm_ghash_clmul:
++___
++$code.=<<___;
++	ret
++.size	gcm_ghash_clmul,.-gcm_ghash_clmul
++___
++}
++
++$code.=<<___;
++.globl	gcm_init_avx
++.type	gcm_init_avx,\@abi-omnipotent
++.align	32
++gcm_init_avx:
++___
++if ($avx) {
++my ($Htbl,$Xip)=@_4args;
++my $HK="%xmm6";
++
++$code.=<<___ if ($win64);
++.LSEH_begin_gcm_init_avx:
++	# I can't trust assembler to use specific encoding:-(
++	.byte	0x48,0x83,0xec,0x18		#sub	$0x18,%rsp
++	.byte	0x0f,0x29,0x34,0x24		#movaps	%xmm6,(%rsp)
++___
++$code.=<<___;
++	vzeroupper
++
++	vmovdqu		($Xip),$Hkey
++	vpshufd		\$0b01001110,$Hkey,$Hkey	# dword swap
++
++	# <<1 twist
++	vpshufd		\$0b11111111,$Hkey,$T2	# broadcast uppermost dword
++	vpsrlq		\$63,$Hkey,$T1
++	vpsllq		\$1,$Hkey,$Hkey
++	vpxor		$T3,$T3,$T3		#
++	vpcmpgtd	$T2,$T3,$T3		# broadcast carry bit
++	vpslldq		\$8,$T1,$T1
++	vpor		$T1,$Hkey,$Hkey		# H<<=1
++
++	# magic reduction
++	vpand		.L0x1c2_polynomial(%rip),$T3,$T3
++	vpxor		$T3,$Hkey,$Hkey		# if(carry) H^=0x1c2_polynomial
++
++	vpunpckhqdq	$Hkey,$Hkey,$HK
++	vmovdqa		$Hkey,$Xi
++	vpxor		$Hkey,$HK,$HK
++	mov		\$4,%r10		# up to H^8
++	jmp		.Linit_start_avx
++___
++
++sub clmul64x64_avx {
++my ($Xhi,$Xi,$Hkey,$HK)=@_;
++
++if (!defined($HK)) {	$HK = $T2;
++$code.=<<___;
++	vpunpckhqdq	$Xi,$Xi,$T1
++	vpunpckhqdq	$Hkey,$Hkey,$T2
++	vpxor		$Xi,$T1,$T1		#
++	vpxor		$Hkey,$T2,$T2
++___
++} else {
++$code.=<<___;
++	vpunpckhqdq	$Xi,$Xi,$T1
++	vpxor		$Xi,$T1,$T1		#
++___
++}
++$code.=<<___;
++	vpclmulqdq	\$0x11,$Hkey,$Xi,$Xhi	#######
++	vpclmulqdq	\$0x00,$Hkey,$Xi,$Xi	#######
++	vpclmulqdq	\$0x00,$HK,$T1,$T1	#######
++	vpxor		$Xi,$Xhi,$T2		#
++	vpxor		$T2,$T1,$T1		#
++
++	vpslldq		\$8,$T1,$T2		#
++	vpsrldq		\$8,$T1,$T1
++	vpxor		$T2,$Xi,$Xi		#
++	vpxor		$T1,$Xhi,$Xhi
++___
++}
++
++sub reduction_avx {
++my ($Xhi,$Xi) = @_;
++
++$code.=<<___;
++	vpsllq		\$57,$Xi,$T1		# 1st phase
++	vpsllq		\$62,$Xi,$T2
++	vpxor		$T1,$T2,$T2		#
++	vpsllq		\$63,$Xi,$T1
++	vpxor		$T1,$T2,$T2		#
++	vpslldq		\$8,$T2,$T1		#
++	vpsrldq		\$8,$T2,$T2
++	vpxor		$T1,$Xi,$Xi		#
++	vpxor		$T2,$Xhi,$Xhi
++
++	vpsrlq		\$1,$Xi,$T2		# 2nd phase
++	vpxor		$Xi,$Xhi,$Xhi
++	vpxor		$T2,$Xi,$Xi		#
++	vpsrlq		\$5,$T2,$T2
++	vpxor		$T2,$Xi,$Xi		#
++	vpsrlq		\$1,$Xi,$Xi		#
++	vpxor		$Xhi,$Xi,$Xi		#
++___
++}
++
++$code.=<<___;
++.align	32
++.Linit_loop_avx:
++	vpalignr	\$8,$T1,$T2,$T3		# low part is H.lo^H.hi...
++	vmovdqu		$T3,-0x10($Htbl)	# save Karatsuba "salt"
++___
++	&clmul64x64_avx	($Xhi,$Xi,$Hkey,$HK);	# calculate H^3,5,7
++	&reduction_avx	($Xhi,$Xi);
++$code.=<<___;
++.Linit_start_avx:
++	vmovdqa		$Xi,$T3
++___
++	&clmul64x64_avx	($Xhi,$Xi,$Hkey,$HK);	# calculate H^2,4,6,8
++	&reduction_avx	($Xhi,$Xi);
++$code.=<<___;
++	vpshufd		\$0b01001110,$T3,$T1
++	vpshufd		\$0b01001110,$Xi,$T2
++	vpxor		$T3,$T1,$T1		# Karatsuba pre-processing
++	vmovdqu		$T3,0x00($Htbl)		# save H^1,3,5,7
++	vpxor		$Xi,$T2,$T2		# Karatsuba pre-processing
++	vmovdqu		$Xi,0x10($Htbl)		# save H^2,4,6,8
++	lea		0x30($Htbl),$Htbl
++	sub		\$1,%r10
++	jnz		.Linit_loop_avx
++
++	vpalignr	\$8,$T2,$T1,$T3		# last "salt" is flipped
++	vmovdqu		$T3,-0x10($Htbl)
++
++	vzeroupper
++___
++$code.=<<___ if ($win64);
++	movaps	(%rsp),%xmm6
++	lea	0x18(%rsp),%rsp
++.LSEH_end_gcm_init_avx:
++___
++$code.=<<___;
++	ret
++.size	gcm_init_avx,.-gcm_init_avx
++___
++} else {
++$code.=<<___;
++	jmp	.L_init_clmul
++.size	gcm_init_avx,.-gcm_init_avx
++___
++}
++
++$code.=<<___;
++.globl	gcm_gmult_avx
++.type	gcm_gmult_avx,\@abi-omnipotent
++.align	32
++gcm_gmult_avx:
++	jmp	.L_gmult_clmul
++.size	gcm_gmult_avx,.-gcm_gmult_avx
++___
++
++$code.=<<___;
++.globl	gcm_ghash_avx
++.type	gcm_ghash_avx,\@abi-omnipotent
++.align	32
++gcm_ghash_avx:
++___
++if ($avx) {
++my ($Xip,$Htbl,$inp,$len)=@_4args;
++my ($Xlo,$Xhi,$Xmi,
++    $Zlo,$Zhi,$Zmi,
++    $Hkey,$HK,$T1,$T2,
++    $Xi,$Xo,$Tred,$bswap,$Ii,$Ij) = map("%xmm$_",(0..15));
++
++$code.=<<___ if ($win64);
++	lea	-0x88(%rsp),%rax
++.LSEH_begin_gcm_ghash_avx:
++	# I can't trust assembler to use specific encoding:-(
++	.byte	0x48,0x8d,0x60,0xe0		#lea	-0x20(%rax),%rsp
++	.byte	0x0f,0x29,0x70,0xe0		#movaps	%xmm6,-0x20(%rax)
++	.byte	0x0f,0x29,0x78,0xf0		#movaps	%xmm7,-0x10(%rax)
++	.byte	0x44,0x0f,0x29,0x00		#movaps	%xmm8,0(%rax)
++	.byte	0x44,0x0f,0x29,0x48,0x10	#movaps	%xmm9,0x10(%rax)
++	.byte	0x44,0x0f,0x29,0x50,0x20	#movaps	%xmm10,0x20(%rax)
++	.byte	0x44,0x0f,0x29,0x58,0x30	#movaps	%xmm11,0x30(%rax)
++	.byte	0x44,0x0f,0x29,0x60,0x40	#movaps	%xmm12,0x40(%rax)
++	.byte	0x44,0x0f,0x29,0x68,0x50	#movaps	%xmm13,0x50(%rax)
++	.byte	0x44,0x0f,0x29,0x70,0x60	#movaps	%xmm14,0x60(%rax)
++	.byte	0x44,0x0f,0x29,0x78,0x70	#movaps	%xmm15,0x70(%rax)
++___
++$code.=<<___;
++	vzeroupper
++
++	vmovdqu		($Xip),$Xi		# load $Xi
++	lea		.L0x1c2_polynomial(%rip),%r10
++	lea		0x40($Htbl),$Htbl	# size optimization
++	vmovdqu		.Lbswap_mask(%rip),$bswap
++	vpshufb		$bswap,$Xi,$Xi
++	cmp		\$0x80,$len
++	jb		.Lshort_avx
++	sub		\$0x80,$len
++
++	vmovdqu		0x70($inp),$Ii		# I[7]
++	vmovdqu		0x00-0x40($Htbl),$Hkey	# $Hkey^1
++	vpshufb		$bswap,$Ii,$Ii
++	vmovdqu		0x20-0x40($Htbl),$HK
++
++	vpunpckhqdq	$Ii,$Ii,$T2
++	 vmovdqu	0x60($inp),$Ij		# I[6]
++	vpclmulqdq	\$0x00,$Hkey,$Ii,$Xlo
++	vpxor		$Ii,$T2,$T2
++	 vpshufb	$bswap,$Ij,$Ij
++	vpclmulqdq	\$0x11,$Hkey,$Ii,$Xhi
++	 vmovdqu	0x10-0x40($Htbl),$Hkey	# $Hkey^2
++	 vpunpckhqdq	$Ij,$Ij,$T1
++	 vmovdqu	0x50($inp),$Ii		# I[5]
++	vpclmulqdq	\$0x00,$HK,$T2,$Xmi
++	 vpxor		$Ij,$T1,$T1
++
++	 vpshufb	$bswap,$Ii,$Ii
++	vpclmulqdq	\$0x00,$Hkey,$Ij,$Zlo
++	 vpunpckhqdq	$Ii,$Ii,$T2
++	vpclmulqdq	\$0x11,$Hkey,$Ij,$Zhi
++	 vmovdqu	0x30-0x40($Htbl),$Hkey	# $Hkey^3
++	 vpxor		$Ii,$T2,$T2
++	 vmovdqu	0x40($inp),$Ij		# I[4]
++	vpclmulqdq	\$0x10,$HK,$T1,$Zmi
++	 vmovdqu	0x50-0x40($Htbl),$HK
++
++	 vpshufb	$bswap,$Ij,$Ij
++	vpxor		$Xlo,$Zlo,$Zlo
++	vpclmulqdq	\$0x00,$Hkey,$Ii,$Xlo
++	vpxor		$Xhi,$Zhi,$Zhi
++	 vpunpckhqdq	$Ij,$Ij,$T1
++	vpclmulqdq	\$0x11,$Hkey,$Ii,$Xhi
++	 vmovdqu	0x40-0x40($Htbl),$Hkey	# $Hkey^4
++	vpxor		$Xmi,$Zmi,$Zmi
++	vpclmulqdq	\$0x00,$HK,$T2,$Xmi
++	 vpxor		$Ij,$T1,$T1
++
++	 vmovdqu	0x30($inp),$Ii		# I[3]
++	vpxor		$Zlo,$Xlo,$Xlo
++	vpclmulqdq	\$0x00,$Hkey,$Ij,$Zlo
++	vpxor		$Zhi,$Xhi,$Xhi
++	 vpshufb	$bswap,$Ii,$Ii
++	vpclmulqdq	\$0x11,$Hkey,$Ij,$Zhi
++	 vmovdqu	0x60-0x40($Htbl),$Hkey	# $Hkey^5
++	vpxor		$Zmi,$Xmi,$Xmi
++	 vpunpckhqdq	$Ii,$Ii,$T2
++	vpclmulqdq	\$0x10,$HK,$T1,$Zmi
++	 vmovdqu	0x80-0x40($Htbl),$HK
++	 vpxor		$Ii,$T2,$T2
++
++	 vmovdqu	0x20($inp),$Ij		# I[2]
++	vpxor		$Xlo,$Zlo,$Zlo
++	vpclmulqdq	\$0x00,$Hkey,$Ii,$Xlo
++	vpxor		$Xhi,$Zhi,$Zhi
++	 vpshufb	$bswap,$Ij,$Ij
++	vpclmulqdq	\$0x11,$Hkey,$Ii,$Xhi
++	 vmovdqu	0x70-0x40($Htbl),$Hkey	# $Hkey^6
++	vpxor		$Xmi,$Zmi,$Zmi
++	 vpunpckhqdq	$Ij,$Ij,$T1
++	vpclmulqdq	\$0x00,$HK,$T2,$Xmi
++	 vpxor		$Ij,$T1,$T1
++
++	 vmovdqu	0x10($inp),$Ii		# I[1]
++	vpxor		$Zlo,$Xlo,$Xlo
++	vpclmulqdq	\$0x00,$Hkey,$Ij,$Zlo
++	vpxor		$Zhi,$Xhi,$Xhi
++	 vpshufb	$bswap,$Ii,$Ii
++	vpclmulqdq	\$0x11,$Hkey,$Ij,$Zhi
++	 vmovdqu	0x90-0x40($Htbl),$Hkey	# $Hkey^7
++	vpxor		$Zmi,$Xmi,$Xmi
++	 vpunpckhqdq	$Ii,$Ii,$T2
++	vpclmulqdq	\$0x10,$HK,$T1,$Zmi
++	 vmovdqu	0xb0-0x40($Htbl),$HK
++	 vpxor		$Ii,$T2,$T2
++
++	 vmovdqu	($inp),$Ij		# I[0]
++	vpxor		$Xlo,$Zlo,$Zlo
++	vpclmulqdq	\$0x00,$Hkey,$Ii,$Xlo
++	vpxor		$Xhi,$Zhi,$Zhi
++	 vpshufb	$bswap,$Ij,$Ij
++	vpclmulqdq	\$0x11,$Hkey,$Ii,$Xhi
++	 vmovdqu	0xa0-0x40($Htbl),$Hkey	# $Hkey^8
++	vpxor		$Xmi,$Zmi,$Zmi
++	vpclmulqdq	\$0x10,$HK,$T2,$Xmi
++
++	lea		0x80($inp),$inp
++	cmp		\$0x80,$len
++	jb		.Ltail_avx
++
++	vpxor		$Xi,$Ij,$Ij		# accumulate $Xi
++	sub		\$0x80,$len
++	jmp		.Loop8x_avx
++
++.align	32
++.Loop8x_avx:
++	vpunpckhqdq	$Ij,$Ij,$T1
++	 vmovdqu	0x70($inp),$Ii		# I[7]
++	vpxor		$Xlo,$Zlo,$Zlo
++	vpxor		$Ij,$T1,$T1
++	vpclmulqdq	\$0x00,$Hkey,$Ij,$Xi
++	 vpshufb	$bswap,$Ii,$Ii
++	vpxor		$Xhi,$Zhi,$Zhi
++	vpclmulqdq	\$0x11,$Hkey,$Ij,$Xo
++	 vmovdqu	0x00-0x40($Htbl),$Hkey	# $Hkey^1
++	 vpunpckhqdq	$Ii,$Ii,$T2
++	vpxor		$Xmi,$Zmi,$Zmi
++	vpclmulqdq	\$0x00,$HK,$T1,$Tred
++	 vmovdqu	0x20-0x40($Htbl),$HK
++	 vpxor		$Ii,$T2,$T2
++
++	  vmovdqu	0x60($inp),$Ij		# I[6]
++	 vpclmulqdq	\$0x00,$Hkey,$Ii,$Xlo
++	vpxor		$Zlo,$Xi,$Xi		# collect result
++	  vpshufb	$bswap,$Ij,$Ij
++	 vpclmulqdq	\$0x11,$Hkey,$Ii,$Xhi
++	vxorps		$Zhi,$Xo,$Xo
++	  vmovdqu	0x10-0x40($Htbl),$Hkey	# $Hkey^2
++	 vpunpckhqdq	$Ij,$Ij,$T1
++	 vpclmulqdq	\$0x00,$HK,  $T2,$Xmi
++	vpxor		$Zmi,$Tred,$Tred
++	 vxorps		$Ij,$T1,$T1
++
++	  vmovdqu	0x50($inp),$Ii		# I[5]
++	vpxor		$Xi,$Tred,$Tred		# aggregated Karatsuba post-processing
++	 vpclmulqdq	\$0x00,$Hkey,$Ij,$Zlo
++	vpxor		$Xo,$Tred,$Tred
++	vpslldq		\$8,$Tred,$T2
++	 vpxor		$Xlo,$Zlo,$Zlo
++	 vpclmulqdq	\$0x11,$Hkey,$Ij,$Zhi
++	vpsrldq		\$8,$Tred,$Tred
++	vpxor		$T2, $Xi, $Xi
++	  vmovdqu	0x30-0x40($Htbl),$Hkey	# $Hkey^3
++	  vpshufb	$bswap,$Ii,$Ii
++	vxorps		$Tred,$Xo, $Xo
++	 vpxor		$Xhi,$Zhi,$Zhi
++	 vpunpckhqdq	$Ii,$Ii,$T2
++	 vpclmulqdq	\$0x10,$HK,  $T1,$Zmi
++	  vmovdqu	0x50-0x40($Htbl),$HK
++	 vpxor		$Ii,$T2,$T2
++	 vpxor		$Xmi,$Zmi,$Zmi
++
++	  vmovdqu	0x40($inp),$Ij		# I[4]
++	vpalignr	\$8,$Xi,$Xi,$Tred	# 1st phase
++	 vpclmulqdq	\$0x00,$Hkey,$Ii,$Xlo
++	  vpshufb	$bswap,$Ij,$Ij
++	 vpxor		$Zlo,$Xlo,$Xlo
++	 vpclmulqdq	\$0x11,$Hkey,$Ii,$Xhi
++	  vmovdqu	0x40-0x40($Htbl),$Hkey	# $Hkey^4
++	 vpunpckhqdq	$Ij,$Ij,$T1
++	 vpxor		$Zhi,$Xhi,$Xhi
++	 vpclmulqdq	\$0x00,$HK,  $T2,$Xmi
++	 vxorps		$Ij,$T1,$T1
++	 vpxor		$Zmi,$Xmi,$Xmi
++
++	  vmovdqu	0x30($inp),$Ii		# I[3]
++	vpclmulqdq	\$0x10,(%r10),$Xi,$Xi
++	 vpclmulqdq	\$0x00,$Hkey,$Ij,$Zlo
++	  vpshufb	$bswap,$Ii,$Ii
++	 vpxor		$Xlo,$Zlo,$Zlo
++	 vpclmulqdq	\$0x11,$Hkey,$Ij,$Zhi
++	  vmovdqu	0x60-0x40($Htbl),$Hkey	# $Hkey^5
++	 vpunpckhqdq	$Ii,$Ii,$T2
++	 vpxor		$Xhi,$Zhi,$Zhi
++	 vpclmulqdq	\$0x10,$HK,  $T1,$Zmi
++	  vmovdqu	0x80-0x40($Htbl),$HK
++	 vpxor		$Ii,$T2,$T2
++	 vpxor		$Xmi,$Zmi,$Zmi
++
++	  vmovdqu	0x20($inp),$Ij		# I[2]
++	 vpclmulqdq	\$0x00,$Hkey,$Ii,$Xlo
++	  vpshufb	$bswap,$Ij,$Ij
++	 vpxor		$Zlo,$Xlo,$Xlo
++	 vpclmulqdq	\$0x11,$Hkey,$Ii,$Xhi
++	  vmovdqu	0x70-0x40($Htbl),$Hkey	# $Hkey^6
++	 vpunpckhqdq	$Ij,$Ij,$T1
++	 vpxor		$Zhi,$Xhi,$Xhi
++	 vpclmulqdq	\$0x00,$HK,  $T2,$Xmi
++	 vpxor		$Ij,$T1,$T1
++	 vpxor		$Zmi,$Xmi,$Xmi
++	vxorps		$Tred,$Xi,$Xi
++
++	  vmovdqu	0x10($inp),$Ii		# I[1]
++	vpalignr	\$8,$Xi,$Xi,$Tred	# 2nd phase
++	 vpclmulqdq	\$0x00,$Hkey,$Ij,$Zlo
++	  vpshufb	$bswap,$Ii,$Ii
++	 vpxor		$Xlo,$Zlo,$Zlo
++	 vpclmulqdq	\$0x11,$Hkey,$Ij,$Zhi
++	  vmovdqu	0x90-0x40($Htbl),$Hkey	# $Hkey^7
++	vpclmulqdq	\$0x10,(%r10),$Xi,$Xi
++	vxorps		$Xo,$Tred,$Tred
++	 vpunpckhqdq	$Ii,$Ii,$T2
++	 vpxor		$Xhi,$Zhi,$Zhi
++	 vpclmulqdq	\$0x10,$HK,  $T1,$Zmi
++	  vmovdqu	0xb0-0x40($Htbl),$HK
++	 vpxor		$Ii,$T2,$T2
++	 vpxor		$Xmi,$Zmi,$Zmi
++
++	  vmovdqu	($inp),$Ij		# I[0]
++	 vpclmulqdq	\$0x00,$Hkey,$Ii,$Xlo
++	  vpshufb	$bswap,$Ij,$Ij
++	 vpclmulqdq	\$0x11,$Hkey,$Ii,$Xhi
++	  vmovdqu	0xa0-0x40($Htbl),$Hkey	# $Hkey^8
++	vpxor		$Tred,$Ij,$Ij
++	 vpclmulqdq	\$0x10,$HK,  $T2,$Xmi
++	vpxor		$Xi,$Ij,$Ij		# accumulate $Xi
++
++	lea		0x80($inp),$inp
++	sub		\$0x80,$len
++	jnc		.Loop8x_avx
++
++	add		\$0x80,$len
++	jmp		.Ltail_no_xor_avx
++
++.align	32
++.Lshort_avx:
++	vmovdqu		-0x10($inp,$len),$Ii	# very last word
++	lea		($inp,$len),$inp
++	vmovdqu		0x00-0x40($Htbl),$Hkey	# $Hkey^1
++	vmovdqu		0x20-0x40($Htbl),$HK
++	vpshufb		$bswap,$Ii,$Ij
++
++	vmovdqa		$Xlo,$Zlo		# subtle way to zero $Zlo,
++	vmovdqa		$Xhi,$Zhi		# $Zhi and
++	vmovdqa		$Xmi,$Zmi		# $Zmi
++	sub		\$0x10,$len
++	jz		.Ltail_avx
++
++	vpunpckhqdq	$Ij,$Ij,$T1
++	vpxor		$Xlo,$Zlo,$Zlo
++	vpclmulqdq	\$0x00,$Hkey,$Ij,$Xlo
++	vpxor		$Ij,$T1,$T1
++	 vmovdqu	-0x20($inp),$Ii
++	vpxor		$Xhi,$Zhi,$Zhi
++	vpclmulqdq	\$0x11,$Hkey,$Ij,$Xhi
++	vmovdqu		0x10-0x40($Htbl),$Hkey	# $Hkey^2
++	 vpshufb	$bswap,$Ii,$Ij
++	vpxor		$Xmi,$Zmi,$Zmi
++	vpclmulqdq	\$0x00,$HK,$T1,$Xmi
++	vpsrldq		\$8,$HK,$HK
++	sub		\$0x10,$len
++	jz		.Ltail_avx
++
++	vpunpckhqdq	$Ij,$Ij,$T1
++	vpxor		$Xlo,$Zlo,$Zlo
++	vpclmulqdq	\$0x00,$Hkey,$Ij,$Xlo
++	vpxor		$Ij,$T1,$T1
++	 vmovdqu	-0x30($inp),$Ii
++	vpxor		$Xhi,$Zhi,$Zhi
++	vpclmulqdq	\$0x11,$Hkey,$Ij,$Xhi
++	vmovdqu		0x30-0x40($Htbl),$Hkey	# $Hkey^3
++	 vpshufb	$bswap,$Ii,$Ij
++	vpxor		$Xmi,$Zmi,$Zmi
++	vpclmulqdq	\$0x00,$HK,$T1,$Xmi
++	vmovdqu		0x50-0x40($Htbl),$HK
++	sub		\$0x10,$len
++	jz		.Ltail_avx
++
++	vpunpckhqdq	$Ij,$Ij,$T1
++	vpxor		$Xlo,$Zlo,$Zlo
++	vpclmulqdq	\$0x00,$Hkey,$Ij,$Xlo
++	vpxor		$Ij,$T1,$T1
++	 vmovdqu	-0x40($inp),$Ii
++	vpxor		$Xhi,$Zhi,$Zhi
++	vpclmulqdq	\$0x11,$Hkey,$Ij,$Xhi
++	vmovdqu		0x40-0x40($Htbl),$Hkey	# $Hkey^4
++	 vpshufb	$bswap,$Ii,$Ij
++	vpxor		$Xmi,$Zmi,$Zmi
++	vpclmulqdq	\$0x00,$HK,$T1,$Xmi
++	vpsrldq		\$8,$HK,$HK
++	sub		\$0x10,$len
++	jz		.Ltail_avx
++
++	vpunpckhqdq	$Ij,$Ij,$T1
++	vpxor		$Xlo,$Zlo,$Zlo
++	vpclmulqdq	\$0x00,$Hkey,$Ij,$Xlo
++	vpxor		$Ij,$T1,$T1
++	 vmovdqu	-0x50($inp),$Ii
++	vpxor		$Xhi,$Zhi,$Zhi
++	vpclmulqdq	\$0x11,$Hkey,$Ij,$Xhi
++	vmovdqu		0x60-0x40($Htbl),$Hkey	# $Hkey^5
++	 vpshufb	$bswap,$Ii,$Ij
++	vpxor		$Xmi,$Zmi,$Zmi
++	vpclmulqdq	\$0x00,$HK,$T1,$Xmi
++	vmovdqu		0x80-0x40($Htbl),$HK
++	sub		\$0x10,$len
++	jz		.Ltail_avx
++
++	vpunpckhqdq	$Ij,$Ij,$T1
++	vpxor		$Xlo,$Zlo,$Zlo
++	vpclmulqdq	\$0x00,$Hkey,$Ij,$Xlo
++	vpxor		$Ij,$T1,$T1
++	 vmovdqu	-0x60($inp),$Ii
++	vpxor		$Xhi,$Zhi,$Zhi
++	vpclmulqdq	\$0x11,$Hkey,$Ij,$Xhi
++	vmovdqu		0x70-0x40($Htbl),$Hkey	# $Hkey^6
++	 vpshufb	$bswap,$Ii,$Ij
++	vpxor		$Xmi,$Zmi,$Zmi
++	vpclmulqdq	\$0x00,$HK,$T1,$Xmi
++	vpsrldq		\$8,$HK,$HK
++	sub		\$0x10,$len
++	jz		.Ltail_avx
++
++	vpunpckhqdq	$Ij,$Ij,$T1
++	vpxor		$Xlo,$Zlo,$Zlo
++	vpclmulqdq	\$0x00,$Hkey,$Ij,$Xlo
++	vpxor		$Ij,$T1,$T1
++	 vmovdqu	-0x70($inp),$Ii
++	vpxor		$Xhi,$Zhi,$Zhi
++	vpclmulqdq	\$0x11,$Hkey,$Ij,$Xhi
++	vmovdqu		0x90-0x40($Htbl),$Hkey	# $Hkey^7
++	 vpshufb	$bswap,$Ii,$Ij
++	vpxor		$Xmi,$Zmi,$Zmi
++	vpclmulqdq	\$0x00,$HK,$T1,$Xmi
++	vmovq		0xb8-0x40($Htbl),$HK
++	sub		\$0x10,$len
++	jmp		.Ltail_avx
++
++.align	32
++.Ltail_avx:
++	vpxor		$Xi,$Ij,$Ij		# accumulate $Xi
++.Ltail_no_xor_avx:
++	vpunpckhqdq	$Ij,$Ij,$T1
++	vpxor		$Xlo,$Zlo,$Zlo
++	vpclmulqdq	\$0x00,$Hkey,$Ij,$Xlo
++	vpxor		$Ij,$T1,$T1
++	vpxor		$Xhi,$Zhi,$Zhi
++	vpclmulqdq	\$0x11,$Hkey,$Ij,$Xhi
++	vpxor		$Xmi,$Zmi,$Zmi
++	vpclmulqdq	\$0x00,$HK,$T1,$Xmi
++
++	vmovdqu		(%r10),$Tred
++
++	vpxor		$Xlo,$Zlo,$Xi
++	vpxor		$Xhi,$Zhi,$Xo
++	vpxor		$Xmi,$Zmi,$Zmi
++
++	vpxor		$Xi, $Zmi,$Zmi		# aggregated Karatsuba post-processing
++	vpxor		$Xo, $Zmi,$Zmi
++	vpslldq		\$8, $Zmi,$T2
++	vpsrldq		\$8, $Zmi,$Zmi
++	vpxor		$T2, $Xi, $Xi
++	vpxor		$Zmi,$Xo, $Xo
++
++	vpclmulqdq	\$0x10,$Tred,$Xi,$T2	# 1st phase
++	vpalignr	\$8,$Xi,$Xi,$Xi
++	vpxor		$T2,$Xi,$Xi
++
++	vpclmulqdq	\$0x10,$Tred,$Xi,$T2	# 2nd phase
++	vpalignr	\$8,$Xi,$Xi,$Xi
++	vpxor		$Xo,$Xi,$Xi
++	vpxor		$T2,$Xi,$Xi
++
++	cmp		\$0,$len
++	jne		.Lshort_avx
++
++	vpshufb		$bswap,$Xi,$Xi
++	vmovdqu		$Xi,($Xip)
++	vzeroupper
++___
++$code.=<<___ if ($win64);
++	movaps	(%rsp),%xmm6
++	movaps	0x10(%rsp),%xmm7
++	movaps	0x20(%rsp),%xmm8
++	movaps	0x30(%rsp),%xmm9
++	movaps	0x40(%rsp),%xmm10
++	movaps	0x50(%rsp),%xmm11
++	movaps	0x60(%rsp),%xmm12
++	movaps	0x70(%rsp),%xmm13
++	movaps	0x80(%rsp),%xmm14
++	movaps	0x90(%rsp),%xmm15
++	lea	0xa8(%rsp),%rsp
++.LSEH_end_gcm_ghash_avx:
++___
++$code.=<<___;
++	ret
++.size	gcm_ghash_avx,.-gcm_ghash_avx
++___
++} else {
++$code.=<<___;
++	jmp	.L_ghash_clmul
++.size	gcm_ghash_avx,.-gcm_ghash_avx
++___
++}
++
++$code.=<<___;
++.align	64
++.Lbswap_mask:
++	.byte	15,14,13,12,11,10,9,8,7,6,5,4,3,2,1,0
++.L0x1c2_polynomial:
++	.byte	1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0xc2
++.L7_mask:
++	.long	7,0,7,0
++.L7_mask_poly:
++	.long	7,0,`0xE1<<1`,0
++.align	64
++.type	.Lrem_4bit,\@object
++.Lrem_4bit:
++	.long	0,`0x0000<<16`,0,`0x1C20<<16`,0,`0x3840<<16`,0,`0x2460<<16`
++	.long	0,`0x7080<<16`,0,`0x6CA0<<16`,0,`0x48C0<<16`,0,`0x54E0<<16`
++	.long	0,`0xE100<<16`,0,`0xFD20<<16`,0,`0xD940<<16`,0,`0xC560<<16`
++	.long	0,`0x9180<<16`,0,`0x8DA0<<16`,0,`0xA9C0<<16`,0,`0xB5E0<<16`
++.type	.Lrem_8bit,\@object
++.Lrem_8bit:
++	.value	0x0000,0x01C2,0x0384,0x0246,0x0708,0x06CA,0x048C,0x054E
++	.value	0x0E10,0x0FD2,0x0D94,0x0C56,0x0918,0x08DA,0x0A9C,0x0B5E
++	.value	0x1C20,0x1DE2,0x1FA4,0x1E66,0x1B28,0x1AEA,0x18AC,0x196E
++	.value	0x1230,0x13F2,0x11B4,0x1076,0x1538,0x14FA,0x16BC,0x177E
++	.value	0x3840,0x3982,0x3BC4,0x3A06,0x3F48,0x3E8A,0x3CCC,0x3D0E
++	.value	0x3650,0x3792,0x35D4,0x3416,0x3158,0x309A,0x32DC,0x331E
++	.value	0x2460,0x25A2,0x27E4,0x2626,0x2368,0x22AA,0x20EC,0x212E
++	.value	0x2A70,0x2BB2,0x29F4,0x2836,0x2D78,0x2CBA,0x2EFC,0x2F3E
++	.value	0x7080,0x7142,0x7304,0x72C6,0x7788,0x764A,0x740C,0x75CE
++	.value	0x7E90,0x7F52,0x7D14,0x7CD6,0x7998,0x785A,0x7A1C,0x7BDE
++	.value	0x6CA0,0x6D62,0x6F24,0x6EE6,0x6BA8,0x6A6A,0x682C,0x69EE
++	.value	0x62B0,0x6372,0x6134,0x60F6,0x65B8,0x647A,0x663C,0x67FE
++	.value	0x48C0,0x4902,0x4B44,0x4A86,0x4FC8,0x4E0A,0x4C4C,0x4D8E
++	.value	0x46D0,0x4712,0x4554,0x4496,0x41D8,0x401A,0x425C,0x439E
++	.value	0x54E0,0x5522,0x5764,0x56A6,0x53E8,0x522A,0x506C,0x51AE
++	.value	0x5AF0,0x5B32,0x5974,0x58B6,0x5DF8,0x5C3A,0x5E7C,0x5FBE
++	.value	0xE100,0xE0C2,0xE284,0xE346,0xE608,0xE7CA,0xE58C,0xE44E
++	.value	0xEF10,0xEED2,0xEC94,0xED56,0xE818,0xE9DA,0xEB9C,0xEA5E
++	.value	0xFD20,0xFCE2,0xFEA4,0xFF66,0xFA28,0xFBEA,0xF9AC,0xF86E
++	.value	0xF330,0xF2F2,0xF0B4,0xF176,0xF438,0xF5FA,0xF7BC,0xF67E
++	.value	0xD940,0xD882,0xDAC4,0xDB06,0xDE48,0xDF8A,0xDDCC,0xDC0E
++	.value	0xD750,0xD692,0xD4D4,0xD516,0xD058,0xD19A,0xD3DC,0xD21E
++	.value	0xC560,0xC4A2,0xC6E4,0xC726,0xC268,0xC3AA,0xC1EC,0xC02E
++	.value	0xCB70,0xCAB2,0xC8F4,0xC936,0xCC78,0xCDBA,0xCFFC,0xCE3E
++	.value	0x9180,0x9042,0x9204,0x93C6,0x9688,0x974A,0x950C,0x94CE
++	.value	0x9F90,0x9E52,0x9C14,0x9DD6,0x9898,0x995A,0x9B1C,0x9ADE
++	.value	0x8DA0,0x8C62,0x8E24,0x8FE6,0x8AA8,0x8B6A,0x892C,0x88EE
++	.value	0x83B0,0x8272,0x8034,0x81F6,0x84B8,0x857A,0x873C,0x86FE
++	.value	0xA9C0,0xA802,0xAA44,0xAB86,0xAEC8,0xAF0A,0xAD4C,0xAC8E
++	.value	0xA7D0,0xA612,0xA454,0xA596,0xA0D8,0xA11A,0xA35C,0xA29E
++	.value	0xB5E0,0xB422,0xB664,0xB7A6,0xB2E8,0xB32A,0xB16C,0xB0AE
++	.value	0xBBF0,0xBA32,0xB874,0xB9B6,0xBCF8,0xBD3A,0xBF7C,0xBEBE
++
++.asciz	"GHASH for x86_64, CRYPTOGAMS by "
++.align	64
++___
++
++# EXCEPTION_DISPOSITION handler (EXCEPTION_RECORD *rec,ULONG64 frame,
++#		CONTEXT *context,DISPATCHER_CONTEXT *disp)
++if ($win64) {
++$rec="%rcx";
++$frame="%rdx";
++$context="%r8";
++$disp="%r9";
++
++$code.=<<___;
++.extern	__imp_RtlVirtualUnwind
++.type	se_handler,\@abi-omnipotent
++.align	16
++se_handler:
++	push	%rsi
++	push	%rdi
++	push	%rbx
++	push	%rbp
++	push	%r12
++	push	%r13
++	push	%r14
++	push	%r15
++	pushfq
++	sub	\$64,%rsp
++
++	mov	120($context),%rax	# pull context->Rax
++	mov	248($context),%rbx	# pull context->Rip
++
++	mov	8($disp),%rsi		# disp->ImageBase
++	mov	56($disp),%r11		# disp->HandlerData
++
++	mov	0(%r11),%r10d		# HandlerData[0]
++	lea	(%rsi,%r10),%r10	# prologue label
++	cmp	%r10,%rbx		# context->RipRsp
++
++	mov	4(%r11),%r10d		# HandlerData[1]
++	lea	(%rsi,%r10),%r10	# epilogue label
++	cmp	%r10,%rbx		# context->Rip>=epilogue label
++	jae	.Lin_prologue
++
++	lea	24(%rax),%rax		# adjust "rsp"
++
++	mov	-8(%rax),%rbx
++	mov	-16(%rax),%rbp
++	mov	-24(%rax),%r12
++	mov	%rbx,144($context)	# restore context->Rbx
++	mov	%rbp,160($context)	# restore context->Rbp
++	mov	%r12,216($context)	# restore context->R12
++
++.Lin_prologue:
++	mov	8(%rax),%rdi
++	mov	16(%rax),%rsi
++	mov	%rax,152($context)	# restore context->Rsp
++	mov	%rsi,168($context)	# restore context->Rsi
++	mov	%rdi,176($context)	# restore context->Rdi
++
++	mov	40($disp),%rdi		# disp->ContextRecord
++	mov	$context,%rsi		# context
++	mov	\$`1232/8`,%ecx		# sizeof(CONTEXT)
++	.long	0xa548f3fc		# cld; rep movsq
++
++	mov	$disp,%rsi
++	xor	%rcx,%rcx		# arg1, UNW_FLAG_NHANDLER
++	mov	8(%rsi),%rdx		# arg2, disp->ImageBase
++	mov	0(%rsi),%r8		# arg3, disp->ControlPc
++	mov	16(%rsi),%r9		# arg4, disp->FunctionEntry
++	mov	40(%rsi),%r10		# disp->ContextRecord
++	lea	56(%rsi),%r11		# &disp->HandlerData
++	lea	24(%rsi),%r12		# &disp->EstablisherFrame
++	mov	%r10,32(%rsp)		# arg5
++	mov	%r11,40(%rsp)		# arg6
++	mov	%r12,48(%rsp)		# arg7
++	mov	%rcx,56(%rsp)		# arg8, (NULL)
++	call	*__imp_RtlVirtualUnwind(%rip)
++
++	mov	\$1,%eax		# ExceptionContinueSearch
++	add	\$64,%rsp
++	popfq
++	pop	%r15
++	pop	%r14
++	pop	%r13
++	pop	%r12
++	pop	%rbp
++	pop	%rbx
++	pop	%rdi
++	pop	%rsi
++	ret
++.size	se_handler,.-se_handler
++
++.section	.pdata
++.align	4
++	.rva	.LSEH_begin_gcm_gmult_4bit
++	.rva	.LSEH_end_gcm_gmult_4bit
++	.rva	.LSEH_info_gcm_gmult_4bit
++
++	.rva	.LSEH_begin_gcm_ghash_4bit
++	.rva	.LSEH_end_gcm_ghash_4bit
++	.rva	.LSEH_info_gcm_ghash_4bit
++
++	.rva	.LSEH_begin_gcm_init_clmul
++	.rva	.LSEH_end_gcm_init_clmul
++	.rva	.LSEH_info_gcm_init_clmul
++
++	.rva	.LSEH_begin_gcm_ghash_clmul
++	.rva	.LSEH_end_gcm_ghash_clmul
++	.rva	.LSEH_info_gcm_ghash_clmul
++___
++$code.=<<___	if ($avx);
++	.rva	.LSEH_begin_gcm_init_avx
++	.rva	.LSEH_end_gcm_init_avx
++	.rva	.LSEH_info_gcm_init_clmul
++
++	.rva	.LSEH_begin_gcm_ghash_avx
++	.rva	.LSEH_end_gcm_ghash_avx
++	.rva	.LSEH_info_gcm_ghash_clmul
++___
++$code.=<<___;
++.section	.xdata
++.align	8
++.LSEH_info_gcm_gmult_4bit:
++	.byte	9,0,0,0
++	.rva	se_handler
++	.rva	.Lgmult_prologue,.Lgmult_epilogue	# HandlerData
++.LSEH_info_gcm_ghash_4bit:
++	.byte	9,0,0,0
++	.rva	se_handler
++	.rva	.Lghash_prologue,.Lghash_epilogue	# HandlerData
++.LSEH_info_gcm_init_clmul:
++	.byte	0x01,0x08,0x03,0x00
++	.byte	0x08,0x68,0x00,0x00	#movaps	0x00(rsp),xmm6
++	.byte	0x04,0x22,0x00,0x00	#sub	rsp,0x18
++.LSEH_info_gcm_ghash_clmul:
++	.byte	0x01,0x33,0x16,0x00
++	.byte	0x33,0xf8,0x09,0x00	#movaps 0x90(rsp),xmm15
++	.byte	0x2e,0xe8,0x08,0x00	#movaps 0x80(rsp),xmm14
++	.byte	0x29,0xd8,0x07,0x00	#movaps 0x70(rsp),xmm13
++	.byte	0x24,0xc8,0x06,0x00	#movaps 0x60(rsp),xmm12
++	.byte	0x1f,0xb8,0x05,0x00	#movaps 0x50(rsp),xmm11
++	.byte	0x1a,0xa8,0x04,0x00	#movaps 0x40(rsp),xmm10
++	.byte	0x15,0x98,0x03,0x00	#movaps 0x30(rsp),xmm9
++	.byte	0x10,0x88,0x02,0x00	#movaps 0x20(rsp),xmm8
++	.byte	0x0c,0x78,0x01,0x00	#movaps 0x10(rsp),xmm7
++	.byte	0x08,0x68,0x00,0x00	#movaps 0x00(rsp),xmm6
++	.byte	0x04,0x01,0x15,0x00	#sub	rsp,0xa8
++___
++}
++
++$code =~ s/\`([^\`]*)\`/eval($1)/gem;
++
++print $code;
++
++close STDOUT;
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/modes/asm/ghashp8-ppc.pl b/CryptoPkg/Library/OpensslLib/openssl/crypto/modes/asm/ghashp8-ppc.pl
+new file mode 100755
+index 0000000..f0598cb
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/modes/asm/ghashp8-ppc.pl
+@@ -0,0 +1,670 @@
++#! /usr/bin/env perl
++# Copyright 2014-2016 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
++# in the file LICENSE in the source distribution or at
++# https://www.openssl.org/source/license.html
++
++#
++# ====================================================================
++# Written by Andy Polyakov  for the OpenSSL
++# project. The module is, however, dual licensed under OpenSSL and
++# CRYPTOGAMS licenses depending on where you obtain it. For further
++# details see http://www.openssl.org/~appro/cryptogams/.
++# ====================================================================
++#
++# GHASH for for PowerISA v2.07.
++#
++# July 2014
++#
++# Accurate performance measurements are problematic, because it's
++# always virtualized setup with possibly throttled processor.
++# Relative comparison is therefore more informative. This initial
++# version is ~2.1x slower than hardware-assisted AES-128-CTR, ~12x
++# faster than "4-bit" integer-only compiler-generated 64-bit code.
++# "Initial version" means that there is room for futher improvement.
++
++# May 2016
++#
++# 2x aggregated reduction improves performance by 50% (resulting
++# performance on POWER8 is 1 cycle per processed byte), and 4x
++# aggregated reduction - by 170% or 2.7x (resulting in 0.55 cpb).
++
++$flavour=shift;
++$output =shift;
++
++if ($flavour =~ /64/) {
++	$SIZE_T=8;
++	$LRSAVE=2*$SIZE_T;
++	$STU="stdu";
++	$POP="ld";
++	$PUSH="std";
++	$UCMP="cmpld";
++	$SHRI="srdi";
++} elsif ($flavour =~ /32/) {
++	$SIZE_T=4;
++	$LRSAVE=$SIZE_T;
++	$STU="stwu";
++	$POP="lwz";
++	$PUSH="stw";
++	$UCMP="cmplw";
++	$SHRI="srwi";
++} else { die "nonsense $flavour"; }
++
++$sp="r1";
++$FRAME=6*$SIZE_T+13*16;	# 13*16 is for v20-v31 offload
++
++$0 =~ m/(.*[\/\\])[^\/\\]+$/; $dir=$1;
++( $xlate="${dir}ppc-xlate.pl" and -f $xlate ) or
++( $xlate="${dir}../../perlasm/ppc-xlate.pl" and -f $xlate) or
++die "can't locate ppc-xlate.pl";
++
++open STDOUT,"| $^X $xlate $flavour $output" || die "can't call $xlate: $!";
++
++my ($Xip,$Htbl,$inp,$len)=map("r$_",(3..6));	# argument block
++
++my ($Xl,$Xm,$Xh,$IN)=map("v$_",(0..3));
++my ($zero,$t0,$t1,$t2,$xC2,$H,$Hh,$Hl,$lemask)=map("v$_",(4..12));
++my ($Xl1,$Xm1,$Xh1,$IN1,$H2,$H2h,$H2l)=map("v$_",(13..19));
++my $vrsave="r12";
++
++$code=<<___;
++.machine	"any"
++
++.text
++
++.globl	.gcm_init_p8
++.align	5
++.gcm_init_p8:
++	li		r0,-4096
++	li		r8,0x10
++	mfspr		$vrsave,256
++	li		r9,0x20
++	mtspr		256,r0
++	li		r10,0x30
++	lvx_u		$H,0,r4			# load H
++
++	vspltisb	$xC2,-16		# 0xf0
++	vspltisb	$t0,1			# one
++	vaddubm		$xC2,$xC2,$xC2		# 0xe0
++	vxor		$zero,$zero,$zero
++	vor		$xC2,$xC2,$t0		# 0xe1
++	vsldoi		$xC2,$xC2,$zero,15	# 0xe1...
++	vsldoi		$t1,$zero,$t0,1		# ...1
++	vaddubm		$xC2,$xC2,$xC2		# 0xc2...
++	vspltisb	$t2,7
++	vor		$xC2,$xC2,$t1		# 0xc2....01
++	vspltb		$t1,$H,0		# most significant byte
++	vsl		$H,$H,$t0		# H<<=1
++	vsrab		$t1,$t1,$t2		# broadcast carry bit
++	vand		$t1,$t1,$xC2
++	vxor		$IN,$H,$t1		# twisted H
++
++	vsldoi		$H,$IN,$IN,8		# twist even more ...
++	vsldoi		$xC2,$zero,$xC2,8	# 0xc2.0
++	vsldoi		$Hl,$zero,$H,8		# ... and split
++	vsldoi		$Hh,$H,$zero,8
++
++	stvx_u		$xC2,0,r3		# save pre-computed table
++	stvx_u		$Hl,r8,r3
++	li		r8,0x40
++	stvx_u		$H, r9,r3
++	li		r9,0x50
++	stvx_u		$Hh,r10,r3
++	li		r10,0x60
++
++	vpmsumd		$Xl,$IN,$Hl		# H.lo·H.lo
++	vpmsumd		$Xm,$IN,$H		# H.hi·H.lo+H.lo·H.hi
++	vpmsumd		$Xh,$IN,$Hh		# H.hi·H.hi
++
++	vpmsumd		$t2,$Xl,$xC2		# 1st reduction phase
++
++	vsldoi		$t0,$Xm,$zero,8
++	vsldoi		$t1,$zero,$Xm,8
++	vxor		$Xl,$Xl,$t0
++	vxor		$Xh,$Xh,$t1
++
++	vsldoi		$Xl,$Xl,$Xl,8
++	vxor		$Xl,$Xl,$t2
++
++	vsldoi		$t1,$Xl,$Xl,8		# 2nd reduction phase
++	vpmsumd		$Xl,$Xl,$xC2
++	vxor		$t1,$t1,$Xh
++	vxor		$IN1,$Xl,$t1
++
++	vsldoi		$H2,$IN1,$IN1,8
++	vsldoi		$H2l,$zero,$H2,8
++	vsldoi		$H2h,$H2,$zero,8
++
++	stvx_u		$H2l,r8,r3		# save H^2
++	li		r8,0x70
++	stvx_u		$H2,r9,r3
++	li		r9,0x80
++	stvx_u		$H2h,r10,r3
++	li		r10,0x90
++___
++{
++my ($t4,$t5,$t6) = ($Hl,$H,$Hh);
++$code.=<<___;
++	vpmsumd		$Xl,$IN,$H2l		# H.lo·H^2.lo
++	 vpmsumd	$Xl1,$IN1,$H2l		# H^2.lo·H^2.lo
++	vpmsumd		$Xm,$IN,$H2		# H.hi·H^2.lo+H.lo·H^2.hi
++	 vpmsumd	$Xm1,$IN1,$H2		# H^2.hi·H^2.lo+H^2.lo·H^2.hi
++	vpmsumd		$Xh,$IN,$H2h		# H.hi·H^2.hi
++	 vpmsumd	$Xh1,$IN1,$H2h		# H^2.hi·H^2.hi
++
++	vpmsumd		$t2,$Xl,$xC2		# 1st reduction phase
++	 vpmsumd	$t6,$Xl1,$xC2		# 1st reduction phase
++
++	vsldoi		$t0,$Xm,$zero,8
++	vsldoi		$t1,$zero,$Xm,8
++	 vsldoi		$t4,$Xm1,$zero,8
++	 vsldoi		$t5,$zero,$Xm1,8
++	vxor		$Xl,$Xl,$t0
++	vxor		$Xh,$Xh,$t1
++	 vxor		$Xl1,$Xl1,$t4
++	 vxor		$Xh1,$Xh1,$t5
++
++	vsldoi		$Xl,$Xl,$Xl,8
++	 vsldoi		$Xl1,$Xl1,$Xl1,8
++	vxor		$Xl,$Xl,$t2
++	 vxor		$Xl1,$Xl1,$t6
++
++	vsldoi		$t1,$Xl,$Xl,8		# 2nd reduction phase
++	 vsldoi		$t5,$Xl1,$Xl1,8		# 2nd reduction phase
++	vpmsumd		$Xl,$Xl,$xC2
++	 vpmsumd	$Xl1,$Xl1,$xC2
++	vxor		$t1,$t1,$Xh
++	 vxor		$t5,$t5,$Xh1
++	vxor		$Xl,$Xl,$t1
++	 vxor		$Xl1,$Xl1,$t5
++
++	vsldoi		$H,$Xl,$Xl,8
++	 vsldoi		$H2,$Xl1,$Xl1,8
++	vsldoi		$Hl,$zero,$H,8
++	vsldoi		$Hh,$H,$zero,8
++	 vsldoi		$H2l,$zero,$H2,8
++	 vsldoi		$H2h,$H2,$zero,8
++
++	stvx_u		$Hl,r8,r3		# save H^3
++	li		r8,0xa0
++	stvx_u		$H,r9,r3
++	li		r9,0xb0
++	stvx_u		$Hh,r10,r3
++	li		r10,0xc0
++	 stvx_u		$H2l,r8,r3		# save H^4
++	 stvx_u		$H2,r9,r3
++	 stvx_u		$H2h,r10,r3
++
++	mtspr		256,$vrsave
++	blr
++	.long		0
++	.byte		0,12,0x14,0,0,0,2,0
++	.long		0
++.size	.gcm_init_p8,.-.gcm_init_p8
++___
++}
++$code.=<<___;
++.globl	.gcm_gmult_p8
++.align	5
++.gcm_gmult_p8:
++	lis		r0,0xfff8
++	li		r8,0x10
++	mfspr		$vrsave,256
++	li		r9,0x20
++	mtspr		256,r0
++	li		r10,0x30
++	lvx_u		$IN,0,$Xip		# load Xi
++
++	lvx_u		$Hl,r8,$Htbl		# load pre-computed table
++	 le?lvsl	$lemask,r0,r0
++	lvx_u		$H, r9,$Htbl
++	 le?vspltisb	$t0,0x07
++	lvx_u		$Hh,r10,$Htbl
++	 le?vxor	$lemask,$lemask,$t0
++	lvx_u		$xC2,0,$Htbl
++	 le?vperm	$IN,$IN,$IN,$lemask
++	vxor		$zero,$zero,$zero
++
++	vpmsumd		$Xl,$IN,$Hl		# H.lo·Xi.lo
++	vpmsumd		$Xm,$IN,$H		# H.hi·Xi.lo+H.lo·Xi.hi
++	vpmsumd		$Xh,$IN,$Hh		# H.hi·Xi.hi
++
++	vpmsumd		$t2,$Xl,$xC2		# 1st reduction phase
++
++	vsldoi		$t0,$Xm,$zero,8
++	vsldoi		$t1,$zero,$Xm,8
++	vxor		$Xl,$Xl,$t0
++	vxor		$Xh,$Xh,$t1
++
++	vsldoi		$Xl,$Xl,$Xl,8
++	vxor		$Xl,$Xl,$t2
++
++	vsldoi		$t1,$Xl,$Xl,8		# 2nd reduction phase
++	vpmsumd		$Xl,$Xl,$xC2
++	vxor		$t1,$t1,$Xh
++	vxor		$Xl,$Xl,$t1
++
++	le?vperm	$Xl,$Xl,$Xl,$lemask
++	stvx_u		$Xl,0,$Xip		# write out Xi
++
++	mtspr		256,$vrsave
++	blr
++	.long		0
++	.byte		0,12,0x14,0,0,0,2,0
++	.long		0
++.size	.gcm_gmult_p8,.-.gcm_gmult_p8
++
++.globl	.gcm_ghash_p8
++.align	5
++.gcm_ghash_p8:
++	li		r0,-4096
++	li		r8,0x10
++	mfspr		$vrsave,256
++	li		r9,0x20
++	mtspr		256,r0
++	li		r10,0x30
++	lvx_u		$Xl,0,$Xip		# load Xi
++
++	lvx_u		$Hl,r8,$Htbl		# load pre-computed table
++	li		r8,0x40
++	 le?lvsl	$lemask,r0,r0
++	lvx_u		$H, r9,$Htbl
++	li		r9,0x50
++	 le?vspltisb	$t0,0x07
++	lvx_u		$Hh,r10,$Htbl
++	li		r10,0x60
++	 le?vxor	$lemask,$lemask,$t0
++	lvx_u		$xC2,0,$Htbl
++	 le?vperm	$Xl,$Xl,$Xl,$lemask
++	vxor		$zero,$zero,$zero
++
++	${UCMP}i	$len,64
++	bge		Lgcm_ghash_p8_4x
++
++	lvx_u		$IN,0,$inp
++	addi		$inp,$inp,16
++	subic.		$len,$len,16
++	 le?vperm	$IN,$IN,$IN,$lemask
++	vxor		$IN,$IN,$Xl
++	beq		Lshort
++
++	lvx_u		$H2l,r8,$Htbl		# load H^2
++	li		r8,16
++	lvx_u		$H2, r9,$Htbl
++	add		r9,$inp,$len		# end of input
++	lvx_u		$H2h,r10,$Htbl
++	be?b		Loop_2x
++
++.align	5
++Loop_2x:
++	lvx_u		$IN1,0,$inp
++	le?vperm	$IN1,$IN1,$IN1,$lemask
++
++	 subic		$len,$len,32
++	vpmsumd		$Xl,$IN,$H2l		# H^2.lo·Xi.lo
++	 vpmsumd	$Xl1,$IN1,$Hl		# H.lo·Xi+1.lo
++	 subfe		r0,r0,r0		# borrow?-1:0
++	vpmsumd		$Xm,$IN,$H2		# H^2.hi·Xi.lo+H^2.lo·Xi.hi
++	 vpmsumd	$Xm1,$IN1,$H		# H.hi·Xi+1.lo+H.lo·Xi+1.hi
++	 and		r0,r0,$len
++	vpmsumd		$Xh,$IN,$H2h		# H^2.hi·Xi.hi
++	 vpmsumd	$Xh1,$IN1,$Hh		# H.hi·Xi+1.hi
++	 add		$inp,$inp,r0
++
++	vxor		$Xl,$Xl,$Xl1
++	vxor		$Xm,$Xm,$Xm1
++
++	vpmsumd		$t2,$Xl,$xC2		# 1st reduction phase
++
++	vsldoi		$t0,$Xm,$zero,8
++	vsldoi		$t1,$zero,$Xm,8
++	 vxor		$Xh,$Xh,$Xh1
++	vxor		$Xl,$Xl,$t0
++	vxor		$Xh,$Xh,$t1
++
++	vsldoi		$Xl,$Xl,$Xl,8
++	vxor		$Xl,$Xl,$t2
++	 lvx_u		$IN,r8,$inp
++	 addi		$inp,$inp,32
++
++	vsldoi		$t1,$Xl,$Xl,8		# 2nd reduction phase
++	vpmsumd		$Xl,$Xl,$xC2
++	 le?vperm	$IN,$IN,$IN,$lemask
++	vxor		$t1,$t1,$Xh
++	vxor		$IN,$IN,$t1
++	vxor		$IN,$IN,$Xl
++	$UCMP		r9,$inp
++	bgt		Loop_2x			# done yet?
++
++	cmplwi		$len,0
++	bne		Leven
++
++Lshort:
++	vpmsumd		$Xl,$IN,$Hl		# H.lo·Xi.lo
++	vpmsumd		$Xm,$IN,$H		# H.hi·Xi.lo+H.lo·Xi.hi
++	vpmsumd		$Xh,$IN,$Hh		# H.hi·Xi.hi
++
++	vpmsumd		$t2,$Xl,$xC2		# 1st reduction phase
++
++	vsldoi		$t0,$Xm,$zero,8
++	vsldoi		$t1,$zero,$Xm,8
++	vxor		$Xl,$Xl,$t0
++	vxor		$Xh,$Xh,$t1
++
++	vsldoi		$Xl,$Xl,$Xl,8
++	vxor		$Xl,$Xl,$t2
++
++	vsldoi		$t1,$Xl,$Xl,8		# 2nd reduction phase
++	vpmsumd		$Xl,$Xl,$xC2
++	vxor		$t1,$t1,$Xh
++
++Leven:
++	vxor		$Xl,$Xl,$t1
++	le?vperm	$Xl,$Xl,$Xl,$lemask
++	stvx_u		$Xl,0,$Xip		# write out Xi
++
++	mtspr		256,$vrsave
++	blr
++	.long		0
++	.byte		0,12,0x14,0,0,0,4,0
++	.long		0
++___
++{
++my ($Xl3,$Xm2,$IN2,$H3l,$H3,$H3h,
++    $Xh3,$Xm3,$IN3,$H4l,$H4,$H4h) = map("v$_",(20..31));
++my $IN0=$IN;
++my ($H21l,$H21h,$loperm,$hiperm) = ($Hl,$Hh,$H2l,$H2h);
++
++$code.=<<___;
++.align	5
++.gcm_ghash_p8_4x:
++Lgcm_ghash_p8_4x:
++	$STU		$sp,-$FRAME($sp)
++	li		r10,`15+6*$SIZE_T`
++	li		r11,`31+6*$SIZE_T`
++	stvx		v20,r10,$sp
++	addi		r10,r10,32
++	stvx		v21,r11,$sp
++	addi		r11,r11,32
++	stvx		v22,r10,$sp
++	addi		r10,r10,32
++	stvx		v23,r11,$sp
++	addi		r11,r11,32
++	stvx		v24,r10,$sp
++	addi		r10,r10,32
++	stvx		v25,r11,$sp
++	addi		r11,r11,32
++	stvx		v26,r10,$sp
++	addi		r10,r10,32
++	stvx		v27,r11,$sp
++	addi		r11,r11,32
++	stvx		v28,r10,$sp
++	addi		r10,r10,32
++	stvx		v29,r11,$sp
++	addi		r11,r11,32
++	stvx		v30,r10,$sp
++	li		r10,0x60
++	stvx		v31,r11,$sp
++	li		r0,-1
++	stw		$vrsave,`$FRAME-4`($sp)	# save vrsave
++	mtspr		256,r0			# preserve all AltiVec registers
++
++	lvsl		$t0,0,r8		# 0x0001..0e0f
++	#lvx_u		$H2l,r8,$Htbl		# load H^2
++	li		r8,0x70
++	lvx_u		$H2, r9,$Htbl
++	li		r9,0x80
++	vspltisb	$t1,8			# 0x0808..0808
++	#lvx_u		$H2h,r10,$Htbl
++	li		r10,0x90
++	lvx_u		$H3l,r8,$Htbl		# load H^3
++	li		r8,0xa0
++	lvx_u		$H3, r9,$Htbl
++	li		r9,0xb0
++	lvx_u		$H3h,r10,$Htbl
++	li		r10,0xc0
++	lvx_u		$H4l,r8,$Htbl		# load H^4
++	li		r8,0x10
++	lvx_u		$H4, r9,$Htbl
++	li		r9,0x20
++	lvx_u		$H4h,r10,$Htbl
++	li		r10,0x30
++
++	vsldoi		$t2,$zero,$t1,8		# 0x0000..0808
++	vaddubm		$hiperm,$t0,$t2		# 0x0001..1617
++	vaddubm		$loperm,$t1,$hiperm	# 0x0809..1e1f
++
++	$SHRI		$len,$len,4		# this allows to use sign bit
++						# as carry
++	lvx_u		$IN0,0,$inp		# load input
++	lvx_u		$IN1,r8,$inp
++	subic.		$len,$len,8
++	lvx_u		$IN2,r9,$inp
++	lvx_u		$IN3,r10,$inp
++	addi		$inp,$inp,0x40
++	le?vperm	$IN0,$IN0,$IN0,$lemask
++	le?vperm	$IN1,$IN1,$IN1,$lemask
++	le?vperm	$IN2,$IN2,$IN2,$lemask
++	le?vperm	$IN3,$IN3,$IN3,$lemask
++
++	vxor		$Xh,$IN0,$Xl
++
++	 vpmsumd	$Xl1,$IN1,$H3l
++	 vpmsumd	$Xm1,$IN1,$H3
++	 vpmsumd	$Xh1,$IN1,$H3h
++
++	 vperm		$H21l,$H2,$H,$hiperm
++	 vperm		$t0,$IN2,$IN3,$loperm
++	 vperm		$H21h,$H2,$H,$loperm
++	 vperm		$t1,$IN2,$IN3,$hiperm
++	 vpmsumd	$Xm2,$IN2,$H2		# H^2.lo·Xi+2.hi+H^2.hi·Xi+2.lo
++	 vpmsumd	$Xl3,$t0,$H21l		# H^2.lo·Xi+2.lo+H.lo·Xi+3.lo
++	 vpmsumd	$Xm3,$IN3,$H		# H.hi·Xi+3.lo  +H.lo·Xi+3.hi
++	 vpmsumd	$Xh3,$t1,$H21h		# H^2.hi·Xi+2.hi+H.hi·Xi+3.hi
++
++	 vxor		$Xm2,$Xm2,$Xm1
++	 vxor		$Xl3,$Xl3,$Xl1
++	 vxor		$Xm3,$Xm3,$Xm2
++	 vxor		$Xh3,$Xh3,$Xh1
++
++	blt		Ltail_4x
++
++Loop_4x:
++	lvx_u		$IN0,0,$inp
++	lvx_u		$IN1,r8,$inp
++	subic.		$len,$len,4
++	lvx_u		$IN2,r9,$inp
++	lvx_u		$IN3,r10,$inp
++	addi		$inp,$inp,0x40
++	le?vperm	$IN1,$IN1,$IN1,$lemask
++	le?vperm	$IN2,$IN2,$IN2,$lemask
++	le?vperm	$IN3,$IN3,$IN3,$lemask
++	le?vperm	$IN0,$IN0,$IN0,$lemask
++
++	vpmsumd		$Xl,$Xh,$H4l		# H^4.lo·Xi.lo
++	vpmsumd		$Xm,$Xh,$H4		# H^4.hi·Xi.lo+H^4.lo·Xi.hi
++	vpmsumd		$Xh,$Xh,$H4h		# H^4.hi·Xi.hi
++	 vpmsumd	$Xl1,$IN1,$H3l
++	 vpmsumd	$Xm1,$IN1,$H3
++	 vpmsumd	$Xh1,$IN1,$H3h
++
++	vxor		$Xl,$Xl,$Xl3
++	vxor		$Xm,$Xm,$Xm3
++	vxor		$Xh,$Xh,$Xh3
++	 vperm		$t0,$IN2,$IN3,$loperm
++	 vperm		$t1,$IN2,$IN3,$hiperm
++
++	vpmsumd		$t2,$Xl,$xC2		# 1st reduction phase
++	 vpmsumd	$Xl3,$t0,$H21l		# H.lo·Xi+3.lo  +H^2.lo·Xi+2.lo
++	 vpmsumd	$Xh3,$t1,$H21h		# H.hi·Xi+3.hi  +H^2.hi·Xi+2.hi
++
++	vsldoi		$t0,$Xm,$zero,8
++	vsldoi		$t1,$zero,$Xm,8
++	vxor		$Xl,$Xl,$t0
++	vxor		$Xh,$Xh,$t1
++
++	vsldoi		$Xl,$Xl,$Xl,8
++	vxor		$Xl,$Xl,$t2
++
++	vsldoi		$t1,$Xl,$Xl,8		# 2nd reduction phase
++	 vpmsumd	$Xm2,$IN2,$H2		# H^2.hi·Xi+2.lo+H^2.lo·Xi+2.hi
++	 vpmsumd	$Xm3,$IN3,$H		# H.hi·Xi+3.lo  +H.lo·Xi+3.hi
++	vpmsumd		$Xl,$Xl,$xC2
++
++	 vxor		$Xl3,$Xl3,$Xl1
++	 vxor		$Xh3,$Xh3,$Xh1
++	vxor		$Xh,$Xh,$IN0
++	 vxor		$Xm2,$Xm2,$Xm1
++	vxor		$Xh,$Xh,$t1
++	 vxor		$Xm3,$Xm3,$Xm2
++	vxor		$Xh,$Xh,$Xl
++	bge		Loop_4x
++
++Ltail_4x:
++	vpmsumd		$Xl,$Xh,$H4l		# H^4.lo·Xi.lo
++	vpmsumd		$Xm,$Xh,$H4		# H^4.hi·Xi.lo+H^4.lo·Xi.hi
++	vpmsumd		$Xh,$Xh,$H4h		# H^4.hi·Xi.hi
++
++	vxor		$Xl,$Xl,$Xl3
++	vxor		$Xm,$Xm,$Xm3
++
++	vpmsumd		$t2,$Xl,$xC2		# 1st reduction phase
++
++	vsldoi		$t0,$Xm,$zero,8
++	vsldoi		$t1,$zero,$Xm,8
++	 vxor		$Xh,$Xh,$Xh3
++	vxor		$Xl,$Xl,$t0
++	vxor		$Xh,$Xh,$t1
++
++	vsldoi		$Xl,$Xl,$Xl,8
++	vxor		$Xl,$Xl,$t2
++
++	vsldoi		$t1,$Xl,$Xl,8		# 2nd reduction phase
++	vpmsumd		$Xl,$Xl,$xC2
++	vxor		$t1,$t1,$Xh
++	vxor		$Xl,$Xl,$t1
++
++	addic.		$len,$len,4
++	beq		Ldone_4x
++
++	lvx_u		$IN0,0,$inp
++	${UCMP}i	$len,2
++	li		$len,-4
++	blt		Lone
++	lvx_u		$IN1,r8,$inp
++	beq		Ltwo
++
++Lthree:
++	lvx_u		$IN2,r9,$inp
++	le?vperm	$IN0,$IN0,$IN0,$lemask
++	le?vperm	$IN1,$IN1,$IN1,$lemask
++	le?vperm	$IN2,$IN2,$IN2,$lemask
++
++	vxor		$Xh,$IN0,$Xl
++	vmr		$H4l,$H3l
++	vmr		$H4, $H3
++	vmr		$H4h,$H3h
++
++	vperm		$t0,$IN1,$IN2,$loperm
++	vperm		$t1,$IN1,$IN2,$hiperm
++	vpmsumd		$Xm2,$IN1,$H2		# H^2.lo·Xi+1.hi+H^2.hi·Xi+1.lo
++	vpmsumd		$Xm3,$IN2,$H		# H.hi·Xi+2.lo  +H.lo·Xi+2.hi
++	vpmsumd		$Xl3,$t0,$H21l		# H^2.lo·Xi+1.lo+H.lo·Xi+2.lo
++	vpmsumd		$Xh3,$t1,$H21h		# H^2.hi·Xi+1.hi+H.hi·Xi+2.hi
++
++	vxor		$Xm3,$Xm3,$Xm2
++	b		Ltail_4x
++
++.align	4
++Ltwo:
++	le?vperm	$IN0,$IN0,$IN0,$lemask
++	le?vperm	$IN1,$IN1,$IN1,$lemask
++
++	vxor		$Xh,$IN0,$Xl
++	vperm		$t0,$zero,$IN1,$loperm
++	vperm		$t1,$zero,$IN1,$hiperm
++
++	vsldoi		$H4l,$zero,$H2,8
++	vmr		$H4, $H2
++	vsldoi		$H4h,$H2,$zero,8
++
++	vpmsumd		$Xl3,$t0, $H21l		# H.lo·Xi+1.lo
++	vpmsumd		$Xm3,$IN1,$H		# H.hi·Xi+1.lo+H.lo·Xi+2.hi
++	vpmsumd		$Xh3,$t1, $H21h		# H.hi·Xi+1.hi
++
++	b		Ltail_4x
++
++.align	4
++Lone:
++	le?vperm	$IN0,$IN0,$IN0,$lemask
++
++	vsldoi		$H4l,$zero,$H,8
++	vmr		$H4, $H
++	vsldoi		$H4h,$H,$zero,8
++
++	vxor		$Xh,$IN0,$Xl
++	vxor		$Xl3,$Xl3,$Xl3
++	vxor		$Xm3,$Xm3,$Xm3
++	vxor		$Xh3,$Xh3,$Xh3
++
++	b		Ltail_4x
++
++Ldone_4x:
++	le?vperm	$Xl,$Xl,$Xl,$lemask
++	stvx_u		$Xl,0,$Xip		# write out Xi
++
++	li		r10,`15+6*$SIZE_T`
++	li		r11,`31+6*$SIZE_T`
++	mtspr		256,$vrsave
++	lvx		v20,r10,$sp
++	addi		r10,r10,32
++	lvx		v21,r11,$sp
++	addi		r11,r11,32
++	lvx		v22,r10,$sp
++	addi		r10,r10,32
++	lvx		v23,r11,$sp
++	addi		r11,r11,32
++	lvx		v24,r10,$sp
++	addi		r10,r10,32
++	lvx		v25,r11,$sp
++	addi		r11,r11,32
++	lvx		v26,r10,$sp
++	addi		r10,r10,32
++	lvx		v27,r11,$sp
++	addi		r11,r11,32
++	lvx		v28,r10,$sp
++	addi		r10,r10,32
++	lvx		v29,r11,$sp
++	addi		r11,r11,32
++	lvx		v30,r10,$sp
++	lvx		v31,r11,$sp
++	addi		$sp,$sp,$FRAME
++	blr
++	.long		0
++	.byte		0,12,0x04,0,0x80,0,4,0
++	.long		0
++___
++}
++$code.=<<___;
++.size	.gcm_ghash_p8,.-.gcm_ghash_p8
++
++.asciz  "GHASH for PowerISA 2.07, CRYPTOGAMS by "
++.align  2
++___
++
++foreach (split("\n",$code)) {
++	s/\`([^\`]*)\`/eval $1/geo;
++
++	if ($flavour =~ /le$/o) {	# little-endian
++	    s/le\?//o		or
++	    s/be\?/#be#/o;
++	} else {
++	    s/le\?/#le#/o	or
++	    s/be\?//o;
++	}
++	print $_,"\n";
++}
++
++close STDOUT; # enforce flush
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/modes/asm/ghashv8-armx.pl b/CryptoPkg/Library/OpensslLib/openssl/crypto/modes/asm/ghashv8-armx.pl
+new file mode 100644
+index 0000000..dcd5f59
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/modes/asm/ghashv8-armx.pl
+@@ -0,0 +1,430 @@
++#! /usr/bin/env perl
++# Copyright 2014-2016 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
++# in the file LICENSE in the source distribution or at
++# https://www.openssl.org/source/license.html
++
++#
++# ====================================================================
++# Written by Andy Polyakov  for the OpenSSL
++# project. The module is, however, dual licensed under OpenSSL and
++# CRYPTOGAMS licenses depending on where you obtain it. For further
++# details see http://www.openssl.org/~appro/cryptogams/.
++# ====================================================================
++#
++# GHASH for ARMv8 Crypto Extension, 64-bit polynomial multiplication.
++#
++# June 2014
++#
++# Initial version was developed in tight cooperation with Ard
++# Biesheuvel  from bits-n-pieces from
++# other assembly modules. Just like aesv8-armx.pl this module
++# supports both AArch32 and AArch64 execution modes.
++#
++# July 2014
++#
++# Implement 2x aggregated reduction [see ghash-x86.pl for background
++# information].
++#
++# Current performance in cycles per processed byte:
++#
++#		PMULL[2]	32-bit NEON(*)
++# Apple A7	0.92		5.62
++# Cortex-A53	1.01		8.39
++# Cortex-A57	1.17		7.61
++# Denver	0.71		6.02
++# Mongoose	1.10		8.06
++#
++# (*)	presented for reference/comparison purposes;
++
++$flavour = shift;
++$output  = shift;
++
++$0 =~ m/(.*[\/\\])[^\/\\]+$/; $dir=$1;
++( $xlate="${dir}arm-xlate.pl" and -f $xlate ) or
++( $xlate="${dir}../../perlasm/arm-xlate.pl" and -f $xlate) or
++die "can't locate arm-xlate.pl";
++
++open OUT,"| \"$^X\" $xlate $flavour $output";
++*STDOUT=*OUT;
++
++$Xi="x0";	# argument block
++$Htbl="x1";
++$inp="x2";
++$len="x3";
++
++$inc="x12";
++
++{
++my ($Xl,$Xm,$Xh,$IN)=map("q$_",(0..3));
++my ($t0,$t1,$t2,$xC2,$H,$Hhl,$H2)=map("q$_",(8..14));
++
++$code=<<___;
++#include "arm_arch.h"
++
++.text
++___
++$code.=".arch	armv8-a+crypto\n"	if ($flavour =~ /64/);
++$code.=<<___				if ($flavour !~ /64/);
++.fpu	neon
++.code	32
++#undef	__thumb2__
++___
++
++################################################################################
++# void gcm_init_v8(u128 Htable[16],const u64 H[2]);
++#
++# input:	128-bit H - secret parameter E(K,0^128)
++# output:	precomputed table filled with degrees of twisted H;
++#		H is twisted to handle reverse bitness of GHASH;
++#		only few of 16 slots of Htable[16] are used;
++#		data is opaque to outside world (which allows to
++#		optimize the code independently);
++#
++$code.=<<___;
++.global	gcm_init_v8
++.type	gcm_init_v8,%function
++.align	4
++gcm_init_v8:
++	vld1.64		{$t1},[x1]		@ load input H
++	vmov.i8		$xC2,#0xe1
++	vshl.i64	$xC2,$xC2,#57		@ 0xc2.0
++	vext.8		$IN,$t1,$t1,#8
++	vshr.u64	$t2,$xC2,#63
++	vdup.32		$t1,${t1}[1]
++	vext.8		$t0,$t2,$xC2,#8		@ t0=0xc2....01
++	vshr.u64	$t2,$IN,#63
++	vshr.s32	$t1,$t1,#31		@ broadcast carry bit
++	vand		$t2,$t2,$t0
++	vshl.i64	$IN,$IN,#1
++	vext.8		$t2,$t2,$t2,#8
++	vand		$t0,$t0,$t1
++	vorr		$IN,$IN,$t2		@ H<<<=1
++	veor		$H,$IN,$t0		@ twisted H
++	vst1.64		{$H},[x0],#16		@ store Htable[0]
++
++	@ calculate H^2
++	vext.8		$t0,$H,$H,#8		@ Karatsuba pre-processing
++	vpmull.p64	$Xl,$H,$H
++	veor		$t0,$t0,$H
++	vpmull2.p64	$Xh,$H,$H
++	vpmull.p64	$Xm,$t0,$t0
++
++	vext.8		$t1,$Xl,$Xh,#8		@ Karatsuba post-processing
++	veor		$t2,$Xl,$Xh
++	veor		$Xm,$Xm,$t1
++	veor		$Xm,$Xm,$t2
++	vpmull.p64	$t2,$Xl,$xC2		@ 1st phase
++
++	vmov		$Xh#lo,$Xm#hi		@ Xh|Xm - 256-bit result
++	vmov		$Xm#hi,$Xl#lo		@ Xm is rotated Xl
++	veor		$Xl,$Xm,$t2
++
++	vext.8		$t2,$Xl,$Xl,#8		@ 2nd phase
++	vpmull.p64	$Xl,$Xl,$xC2
++	veor		$t2,$t2,$Xh
++	veor		$H2,$Xl,$t2
++
++	vext.8		$t1,$H2,$H2,#8		@ Karatsuba pre-processing
++	veor		$t1,$t1,$H2
++	vext.8		$Hhl,$t0,$t1,#8		@ pack Karatsuba pre-processed
++	vst1.64		{$Hhl-$H2},[x0]		@ store Htable[1..2]
++
++	ret
++.size	gcm_init_v8,.-gcm_init_v8
++___
++################################################################################
++# void gcm_gmult_v8(u64 Xi[2],const u128 Htable[16]);
++#
++# input:	Xi - current hash value;
++#		Htable - table precomputed in gcm_init_v8;
++# output:	Xi - next hash value Xi;
++#
++$code.=<<___;
++.global	gcm_gmult_v8
++.type	gcm_gmult_v8,%function
++.align	4
++gcm_gmult_v8:
++	vld1.64		{$t1},[$Xi]		@ load Xi
++	vmov.i8		$xC2,#0xe1
++	vld1.64		{$H-$Hhl},[$Htbl]	@ load twisted H, ...
++	vshl.u64	$xC2,$xC2,#57
++#ifndef __ARMEB__
++	vrev64.8	$t1,$t1
++#endif
++	vext.8		$IN,$t1,$t1,#8
++
++	vpmull.p64	$Xl,$H,$IN		@ H.lo·Xi.lo
++	veor		$t1,$t1,$IN		@ Karatsuba pre-processing
++	vpmull2.p64	$Xh,$H,$IN		@ H.hi·Xi.hi
++	vpmull.p64	$Xm,$Hhl,$t1		@ (H.lo+H.hi)·(Xi.lo+Xi.hi)
++
++	vext.8		$t1,$Xl,$Xh,#8		@ Karatsuba post-processing
++	veor		$t2,$Xl,$Xh
++	veor		$Xm,$Xm,$t1
++	veor		$Xm,$Xm,$t2
++	vpmull.p64	$t2,$Xl,$xC2		@ 1st phase of reduction
++
++	vmov		$Xh#lo,$Xm#hi		@ Xh|Xm - 256-bit result
++	vmov		$Xm#hi,$Xl#lo		@ Xm is rotated Xl
++	veor		$Xl,$Xm,$t2
++
++	vext.8		$t2,$Xl,$Xl,#8		@ 2nd phase of reduction
++	vpmull.p64	$Xl,$Xl,$xC2
++	veor		$t2,$t2,$Xh
++	veor		$Xl,$Xl,$t2
++
++#ifndef __ARMEB__
++	vrev64.8	$Xl,$Xl
++#endif
++	vext.8		$Xl,$Xl,$Xl,#8
++	vst1.64		{$Xl},[$Xi]		@ write out Xi
++
++	ret
++.size	gcm_gmult_v8,.-gcm_gmult_v8
++___
++################################################################################
++# void gcm_ghash_v8(u64 Xi[2],const u128 Htable[16],const u8 *inp,size_t len);
++#
++# input:	table precomputed in gcm_init_v8;
++#		current hash value Xi;
++#		pointer to input data;
++#		length of input data in bytes, but divisible by block size;
++# output:	next hash value Xi;
++#
++$code.=<<___;
++.global	gcm_ghash_v8
++.type	gcm_ghash_v8,%function
++.align	4
++gcm_ghash_v8:
++___
++$code.=<<___		if ($flavour !~ /64/);
++	vstmdb		sp!,{d8-d15}		@ 32-bit ABI says so
++___
++$code.=<<___;
++	vld1.64		{$Xl},[$Xi]		@ load [rotated] Xi
++						@ "[rotated]" means that
++						@ loaded value would have
++						@ to be rotated in order to
++						@ make it appear as in
++						@ alorithm specification
++	subs		$len,$len,#32		@ see if $len is 32 or larger
++	mov		$inc,#16		@ $inc is used as post-
++						@ increment for input pointer;
++						@ as loop is modulo-scheduled
++						@ $inc is zeroed just in time
++						@ to preclude oversteping
++						@ inp[len], which means that
++						@ last block[s] are actually
++						@ loaded twice, but last
++						@ copy is not processed
++	vld1.64		{$H-$Hhl},[$Htbl],#32	@ load twisted H, ..., H^2
++	vmov.i8		$xC2,#0xe1
++	vld1.64		{$H2},[$Htbl]
++	cclr		$inc,eq			@ is it time to zero $inc?
++	vext.8		$Xl,$Xl,$Xl,#8		@ rotate Xi
++	vld1.64		{$t0},[$inp],#16	@ load [rotated] I[0]
++	vshl.u64	$xC2,$xC2,#57		@ compose 0xc2.0 constant
++#ifndef __ARMEB__
++	vrev64.8	$t0,$t0
++	vrev64.8	$Xl,$Xl
++#endif
++	vext.8		$IN,$t0,$t0,#8		@ rotate I[0]
++	b.lo		.Lodd_tail_v8		@ $len was less than 32
++___
++{ my ($Xln,$Xmn,$Xhn,$In) = map("q$_",(4..7));
++	#######
++	# Xi+2 =[H*(Ii+1 + Xi+1)] mod P =
++	#	[(H*Ii+1) + (H*Xi+1)] mod P =
++	#	[(H*Ii+1) + H^2*(Ii+Xi)] mod P
++	#
++$code.=<<___;
++	vld1.64		{$t1},[$inp],$inc	@ load [rotated] I[1]
++#ifndef __ARMEB__
++	vrev64.8	$t1,$t1
++#endif
++	vext.8		$In,$t1,$t1,#8
++	veor		$IN,$IN,$Xl		@ I[i]^=Xi
++	vpmull.p64	$Xln,$H,$In		@ H·Ii+1
++	veor		$t1,$t1,$In		@ Karatsuba pre-processing
++	vpmull2.p64	$Xhn,$H,$In
++	b		.Loop_mod2x_v8
++
++.align	4
++.Loop_mod2x_v8:
++	vext.8		$t2,$IN,$IN,#8
++	subs		$len,$len,#32		@ is there more data?
++	vpmull.p64	$Xl,$H2,$IN		@ H^2.lo·Xi.lo
++	cclr		$inc,lo			@ is it time to zero $inc?
++
++	 vpmull.p64	$Xmn,$Hhl,$t1
++	veor		$t2,$t2,$IN		@ Karatsuba pre-processing
++	vpmull2.p64	$Xh,$H2,$IN		@ H^2.hi·Xi.hi
++	veor		$Xl,$Xl,$Xln		@ accumulate
++	vpmull2.p64	$Xm,$Hhl,$t2		@ (H^2.lo+H^2.hi)·(Xi.lo+Xi.hi)
++	 vld1.64	{$t0},[$inp],$inc	@ load [rotated] I[i+2]
++
++	veor		$Xh,$Xh,$Xhn
++	 cclr		$inc,eq			@ is it time to zero $inc?
++	veor		$Xm,$Xm,$Xmn
++
++	vext.8		$t1,$Xl,$Xh,#8		@ Karatsuba post-processing
++	veor		$t2,$Xl,$Xh
++	veor		$Xm,$Xm,$t1
++	 vld1.64	{$t1},[$inp],$inc	@ load [rotated] I[i+3]
++#ifndef __ARMEB__
++	 vrev64.8	$t0,$t0
++#endif
++	veor		$Xm,$Xm,$t2
++	vpmull.p64	$t2,$Xl,$xC2		@ 1st phase of reduction
++
++#ifndef __ARMEB__
++	 vrev64.8	$t1,$t1
++#endif
++	vmov		$Xh#lo,$Xm#hi		@ Xh|Xm - 256-bit result
++	vmov		$Xm#hi,$Xl#lo		@ Xm is rotated Xl
++	 vext.8		$In,$t1,$t1,#8
++	 vext.8		$IN,$t0,$t0,#8
++	veor		$Xl,$Xm,$t2
++	 vpmull.p64	$Xln,$H,$In		@ H·Ii+1
++	veor		$IN,$IN,$Xh		@ accumulate $IN early
++
++	vext.8		$t2,$Xl,$Xl,#8		@ 2nd phase of reduction
++	vpmull.p64	$Xl,$Xl,$xC2
++	veor		$IN,$IN,$t2
++	 veor		$t1,$t1,$In		@ Karatsuba pre-processing
++	veor		$IN,$IN,$Xl
++	 vpmull2.p64	$Xhn,$H,$In
++	b.hs		.Loop_mod2x_v8		@ there was at least 32 more bytes
++
++	veor		$Xh,$Xh,$t2
++	vext.8		$IN,$t0,$t0,#8		@ re-construct $IN
++	adds		$len,$len,#32		@ re-construct $len
++	veor		$Xl,$Xl,$Xh		@ re-construct $Xl
++	b.eq		.Ldone_v8		@ is $len zero?
++___
++}
++$code.=<<___;
++.Lodd_tail_v8:
++	vext.8		$t2,$Xl,$Xl,#8
++	veor		$IN,$IN,$Xl		@ inp^=Xi
++	veor		$t1,$t0,$t2		@ $t1 is rotated inp^Xi
++
++	vpmull.p64	$Xl,$H,$IN		@ H.lo·Xi.lo
++	veor		$t1,$t1,$IN		@ Karatsuba pre-processing
++	vpmull2.p64	$Xh,$H,$IN		@ H.hi·Xi.hi
++	vpmull.p64	$Xm,$Hhl,$t1		@ (H.lo+H.hi)·(Xi.lo+Xi.hi)
++
++	vext.8		$t1,$Xl,$Xh,#8		@ Karatsuba post-processing
++	veor		$t2,$Xl,$Xh
++	veor		$Xm,$Xm,$t1
++	veor		$Xm,$Xm,$t2
++	vpmull.p64	$t2,$Xl,$xC2		@ 1st phase of reduction
++
++	vmov		$Xh#lo,$Xm#hi		@ Xh|Xm - 256-bit result
++	vmov		$Xm#hi,$Xl#lo		@ Xm is rotated Xl
++	veor		$Xl,$Xm,$t2
++
++	vext.8		$t2,$Xl,$Xl,#8		@ 2nd phase of reduction
++	vpmull.p64	$Xl,$Xl,$xC2
++	veor		$t2,$t2,$Xh
++	veor		$Xl,$Xl,$t2
++
++.Ldone_v8:
++#ifndef __ARMEB__
++	vrev64.8	$Xl,$Xl
++#endif
++	vext.8		$Xl,$Xl,$Xl,#8
++	vst1.64		{$Xl},[$Xi]		@ write out Xi
++
++___
++$code.=<<___		if ($flavour !~ /64/);
++	vldmia		sp!,{d8-d15}		@ 32-bit ABI says so
++___
++$code.=<<___;
++	ret
++.size	gcm_ghash_v8,.-gcm_ghash_v8
++___
++}
++$code.=<<___;
++.asciz  "GHASH for ARMv8, CRYPTOGAMS by "
++.align  2
++___
++
++if ($flavour =~ /64/) {			######## 64-bit code
++    sub unvmov {
++	my $arg=shift;
++
++	$arg =~ m/q([0-9]+)#(lo|hi),\s*q([0-9]+)#(lo|hi)/o &&
++	sprintf	"ins	v%d.d[%d],v%d.d[%d]",$1,($2 eq "lo")?0:1,$3,($4 eq "lo")?0:1;
++    }
++    foreach(split("\n",$code)) {
++	s/cclr\s+([wx])([^,]+),\s*([a-z]+)/csel	$1$2,$1zr,$1$2,$3/o	or
++	s/vmov\.i8/movi/o		or	# fix up legacy mnemonics
++	s/vmov\s+(.*)/unvmov($1)/geo	or
++	s/vext\.8/ext/o			or
++	s/vshr\.s/sshr\.s/o		or
++	s/vshr/ushr/o			or
++	s/^(\s+)v/$1/o			or	# strip off v prefix
++	s/\bbx\s+lr\b/ret/o;
++
++	s/\bq([0-9]+)\b/"v".($1<8?$1:$1+8).".16b"/geo;	# old->new registers
++	s/@\s/\/\//o;				# old->new style commentary
++
++	# fix up remainig legacy suffixes
++	s/\.[ui]?8(\s)/$1/o;
++	s/\.[uis]?32//o and s/\.16b/\.4s/go;
++	m/\.p64/o and s/\.16b/\.1q/o;		# 1st pmull argument
++	m/l\.p64/o and s/\.16b/\.1d/go;		# 2nd and 3rd pmull arguments
++	s/\.[uisp]?64//o and s/\.16b/\.2d/go;
++	s/\.[42]([sd])\[([0-3])\]/\.$1\[$2\]/o;
++
++	print $_,"\n";
++    }
++} else {				######## 32-bit code
++    sub unvdup32 {
++	my $arg=shift;
++
++	$arg =~ m/q([0-9]+),\s*q([0-9]+)\[([0-3])\]/o &&
++	sprintf	"vdup.32	q%d,d%d[%d]",$1,2*$2+($3>>1),$3&1;
++    }
++    sub unvpmullp64 {
++	my ($mnemonic,$arg)=@_;
++
++	if ($arg =~ m/q([0-9]+),\s*q([0-9]+),\s*q([0-9]+)/o) {
++	    my $word = 0xf2a00e00|(($1&7)<<13)|(($1&8)<<19)
++				 |(($2&7)<<17)|(($2&8)<<4)
++				 |(($3&7)<<1) |(($3&8)<<2);
++	    $word |= 0x00010001	 if ($mnemonic =~ "2");
++	    # since ARMv7 instructions are always encoded little-endian.
++	    # correct solution is to use .inst directive, but older
++	    # assemblers don't implement it:-(
++	    sprintf ".byte\t0x%02x,0x%02x,0x%02x,0x%02x\t@ %s %s",
++			$word&0xff,($word>>8)&0xff,
++			($word>>16)&0xff,($word>>24)&0xff,
++			$mnemonic,$arg;
++	}
++    }
++
++    foreach(split("\n",$code)) {
++	s/\b[wx]([0-9]+)\b/r$1/go;		# new->old registers
++	s/\bv([0-9])\.[12468]+[bsd]\b/q$1/go;	# new->old registers
++	s/\/\/\s?/@ /o;				# new->old style commentary
++
++	# fix up remainig new-style suffixes
++	s/\],#[0-9]+/]!/o;
++
++	s/cclr\s+([^,]+),\s*([a-z]+)/mov$2	$1,#0/o			or
++	s/vdup\.32\s+(.*)/unvdup32($1)/geo				or
++	s/v?(pmull2?)\.p64\s+(.*)/unvpmullp64($1,$2)/geo		or
++	s/\bq([0-9]+)#(lo|hi)/sprintf "d%d",2*$1+($2 eq "hi")/geo	or
++	s/^(\s+)b\./$1b/o						or
++	s/^(\s+)ret/$1bx\tlr/o;
++
++	print $_,"\n";
++    }
++}
++
++close STDOUT; # enforce flush
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/modes/build.info b/CryptoPkg/Library/OpensslLib/openssl/crypto/modes/build.info
+new file mode 100644
+index 0000000..38195c4
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/modes/build.info
+@@ -0,0 +1,27 @@
++LIBS=../../libcrypto
++SOURCE[../../libcrypto]=\
++        cbc128.c ctr128.c cts128.c cfb128.c ofb128.c gcm128.c \
++        ccm128.c xts128.c wrap128.c ocb128.c \
++        {- $target{modes_asm_src} -}
++
++INCLUDE[gcm128.o]=..
++
++GENERATE[ghash-ia64.s]=asm/ghash-ia64.pl $(CFLAGS) $(LIB_CFLAGS)
++GENERATE[ghash-x86.s]=asm/ghash-x86.pl $(PERLASM_SCHEME) $(CFLAGS) $(LIB_CFLAGS) $(PROCESSOR)
++GENERATE[ghash-x86_64.s]=asm/ghash-x86_64.pl $(PERLASM_SCHEME)
++GENERATE[aesni-gcm-x86_64.s]=asm/aesni-gcm-x86_64.pl $(PERLASM_SCHEME)
++GENERATE[ghash-sparcv9.S]=asm/ghash-sparcv9.pl $(PERLASM_SCHEME)
++INCLUDE[ghash-sparcv9.o]=..
++GENERATE[ghash-alpha.S]=asm/ghash-alpha.pl $(PERLASM_SCHEME)
++GENERATE[ghash-parisc.s]=asm/ghash-parisc.pl $(PERLASM_SCHEME)
++GENERATE[ghashp8-ppc.s]=asm/ghashp8-ppc.pl $(PERLASM_SCHEME)
++GENERATE[ghash-armv4.S]=asm/ghash-armv4.pl $(PERLASM_SCHEME)
++INCLUDE[ghash-armv4.o]=..
++GENERATE[ghashv8-armx.S]=asm/ghashv8-armx.pl $(PERLASM_SCHEME)
++INCLUDE[ghashv8-armx.o]=..
++
++BEGINRAW[Makefile]
++# GNU make "catch all"
++{- $builddir -}/ghash-%.S:	{- $sourcedir -}/asm/ghash-%.pl
++	CC="$(CC)" $(PERL) $< $(PERLASM_SCHEME) $@
++ENDRAW[Makefile]
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/modes/cbc128.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/modes/cbc128.c
+new file mode 100644
+index 0000000..4c9bc85
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/modes/cbc128.c
+@@ -0,0 +1,155 @@
++/*
++ * Copyright 2008-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include "modes_lcl.h"
++#include 
++
++#if !defined(STRICT_ALIGNMENT) && !defined(PEDANTIC)
++# define STRICT_ALIGNMENT 0
++#endif
++
++void CRYPTO_cbc128_encrypt(const unsigned char *in, unsigned char *out,
++                           size_t len, const void *key,
++                           unsigned char ivec[16], block128_f block)
++{
++    size_t n;
++    const unsigned char *iv = ivec;
++
++#if !defined(OPENSSL_SMALL_FOOTPRINT)
++    if (STRICT_ALIGNMENT &&
++        ((size_t)in | (size_t)out | (size_t)ivec) % sizeof(size_t) != 0) {
++        while (len >= 16) {
++            for (n = 0; n < 16; ++n)
++                out[n] = in[n] ^ iv[n];
++            (*block) (out, out, key);
++            iv = out;
++            len -= 16;
++            in += 16;
++            out += 16;
++        }
++    } else {
++        while (len >= 16) {
++            for (n = 0; n < 16; n += sizeof(size_t))
++                *(size_t *)(out + n) =
++                    *(size_t *)(in + n) ^ *(size_t *)(iv + n);
++            (*block) (out, out, key);
++            iv = out;
++            len -= 16;
++            in += 16;
++            out += 16;
++        }
++    }
++#endif
++    while (len) {
++        for (n = 0; n < 16 && n < len; ++n)
++            out[n] = in[n] ^ iv[n];
++        for (; n < 16; ++n)
++            out[n] = iv[n];
++        (*block) (out, out, key);
++        iv = out;
++        if (len <= 16)
++            break;
++        len -= 16;
++        in += 16;
++        out += 16;
++    }
++    memcpy(ivec, iv, 16);
++}
++
++void CRYPTO_cbc128_decrypt(const unsigned char *in, unsigned char *out,
++                           size_t len, const void *key,
++                           unsigned char ivec[16], block128_f block)
++{
++    size_t n;
++    union {
++        size_t t[16 / sizeof(size_t)];
++        unsigned char c[16];
++    } tmp;
++
++#if !defined(OPENSSL_SMALL_FOOTPRINT)
++    if (in != out) {
++        const unsigned char *iv = ivec;
++
++        if (STRICT_ALIGNMENT &&
++            ((size_t)in | (size_t)out | (size_t)ivec) % sizeof(size_t) != 0) {
++            while (len >= 16) {
++                (*block) (in, out, key);
++                for (n = 0; n < 16; ++n)
++                    out[n] ^= iv[n];
++                iv = in;
++                len -= 16;
++                in += 16;
++                out += 16;
++            }
++        } else if (16 % sizeof(size_t) == 0) { /* always true */
++            while (len >= 16) {
++                size_t *out_t = (size_t *)out, *iv_t = (size_t *)iv;
++
++                (*block) (in, out, key);
++                for (n = 0; n < 16 / sizeof(size_t); n++)
++                    out_t[n] ^= iv_t[n];
++                iv = in;
++                len -= 16;
++                in += 16;
++                out += 16;
++            }
++        }
++        memcpy(ivec, iv, 16);
++    } else {
++        if (STRICT_ALIGNMENT &&
++            ((size_t)in | (size_t)out | (size_t)ivec) % sizeof(size_t) != 0) {
++            unsigned char c;
++            while (len >= 16) {
++                (*block) (in, tmp.c, key);
++                for (n = 0; n < 16; ++n) {
++                    c = in[n];
++                    out[n] = tmp.c[n] ^ ivec[n];
++                    ivec[n] = c;
++                }
++                len -= 16;
++                in += 16;
++                out += 16;
++            }
++        } else if (16 % sizeof(size_t) == 0) { /* always true */
++            while (len >= 16) {
++                size_t c, *out_t = (size_t *)out, *ivec_t = (size_t *)ivec;
++                const size_t *in_t = (const size_t *)in;
++
++                (*block) (in, tmp.c, key);
++                for (n = 0; n < 16 / sizeof(size_t); n++) {
++                    c = in_t[n];
++                    out_t[n] = tmp.t[n] ^ ivec_t[n];
++                    ivec_t[n] = c;
++                }
++                len -= 16;
++                in += 16;
++                out += 16;
++            }
++        }
++    }
++#endif
++    while (len) {
++        unsigned char c;
++        (*block) (in, tmp.c, key);
++        for (n = 0; n < 16 && n < len; ++n) {
++            c = in[n];
++            out[n] = tmp.c[n] ^ ivec[n];
++            ivec[n] = c;
++        }
++        if (len <= 16) {
++            for (; n < 16; ++n)
++                ivec[n] = in[n];
++            break;
++        }
++        len -= 16;
++        in += 16;
++        out += 16;
++    }
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/modes/ccm128.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/modes/ccm128.c
+new file mode 100644
+index 0000000..85ce84f
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/modes/ccm128.c
+@@ -0,0 +1,432 @@
++/*
++ * Copyright 2011-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include "modes_lcl.h"
++#include 
++
++/*
++ * First you setup M and L parameters and pass the key schedule. This is
++ * called once per session setup...
++ */
++void CRYPTO_ccm128_init(CCM128_CONTEXT *ctx,
++                        unsigned int M, unsigned int L, void *key,
++                        block128_f block)
++{
++    memset(ctx->nonce.c, 0, sizeof(ctx->nonce.c));
++    ctx->nonce.c[0] = ((u8)(L - 1) & 7) | (u8)(((M - 2) / 2) & 7) << 3;
++    ctx->blocks = 0;
++    ctx->block = block;
++    ctx->key = key;
++}
++
++/* !!! Following interfaces are to be called *once* per packet !!! */
++
++/* Then you setup per-message nonce and pass the length of the message */
++int CRYPTO_ccm128_setiv(CCM128_CONTEXT *ctx,
++                        const unsigned char *nonce, size_t nlen, size_t mlen)
++{
++    unsigned int L = ctx->nonce.c[0] & 7; /* the L parameter */
++
++    if (nlen < (14 - L))
++        return -1;              /* nonce is too short */
++
++    if (sizeof(mlen) == 8 && L >= 3) {
++        ctx->nonce.c[8] = (u8)(mlen >> (56 % (sizeof(mlen) * 8)));
++        ctx->nonce.c[9] = (u8)(mlen >> (48 % (sizeof(mlen) * 8)));
++        ctx->nonce.c[10] = (u8)(mlen >> (40 % (sizeof(mlen) * 8)));
++        ctx->nonce.c[11] = (u8)(mlen >> (32 % (sizeof(mlen) * 8)));
++    } else
++        ctx->nonce.u[1] = 0;
++
++    ctx->nonce.c[12] = (u8)(mlen >> 24);
++    ctx->nonce.c[13] = (u8)(mlen >> 16);
++    ctx->nonce.c[14] = (u8)(mlen >> 8);
++    ctx->nonce.c[15] = (u8)mlen;
++
++    ctx->nonce.c[0] &= ~0x40;   /* clear Adata flag */
++    memcpy(&ctx->nonce.c[1], nonce, 14 - L);
++
++    return 0;
++}
++
++/* Then you pass additional authentication data, this is optional */
++void CRYPTO_ccm128_aad(CCM128_CONTEXT *ctx,
++                       const unsigned char *aad, size_t alen)
++{
++    unsigned int i;
++    block128_f block = ctx->block;
++
++    if (alen == 0)
++        return;
++
++    ctx->nonce.c[0] |= 0x40;    /* set Adata flag */
++    (*block) (ctx->nonce.c, ctx->cmac.c, ctx->key), ctx->blocks++;
++
++    if (alen < (0x10000 - 0x100)) {
++        ctx->cmac.c[0] ^= (u8)(alen >> 8);
++        ctx->cmac.c[1] ^= (u8)alen;
++        i = 2;
++    } else if (sizeof(alen) == 8
++               && alen >= (size_t)1 << (32 % (sizeof(alen) * 8))) {
++        ctx->cmac.c[0] ^= 0xFF;
++        ctx->cmac.c[1] ^= 0xFF;
++        ctx->cmac.c[2] ^= (u8)(alen >> (56 % (sizeof(alen) * 8)));
++        ctx->cmac.c[3] ^= (u8)(alen >> (48 % (sizeof(alen) * 8)));
++        ctx->cmac.c[4] ^= (u8)(alen >> (40 % (sizeof(alen) * 8)));
++        ctx->cmac.c[5] ^= (u8)(alen >> (32 % (sizeof(alen) * 8)));
++        ctx->cmac.c[6] ^= (u8)(alen >> 24);
++        ctx->cmac.c[7] ^= (u8)(alen >> 16);
++        ctx->cmac.c[8] ^= (u8)(alen >> 8);
++        ctx->cmac.c[9] ^= (u8)alen;
++        i = 10;
++    } else {
++        ctx->cmac.c[0] ^= 0xFF;
++        ctx->cmac.c[1] ^= 0xFE;
++        ctx->cmac.c[2] ^= (u8)(alen >> 24);
++        ctx->cmac.c[3] ^= (u8)(alen >> 16);
++        ctx->cmac.c[4] ^= (u8)(alen >> 8);
++        ctx->cmac.c[5] ^= (u8)alen;
++        i = 6;
++    }
++
++    do {
++        for (; i < 16 && alen; ++i, ++aad, --alen)
++            ctx->cmac.c[i] ^= *aad;
++        (*block) (ctx->cmac.c, ctx->cmac.c, ctx->key), ctx->blocks++;
++        i = 0;
++    } while (alen);
++}
++
++/* Finally you encrypt or decrypt the message */
++
++/*
++ * counter part of nonce may not be larger than L*8 bits, L is not larger
++ * than 8, therefore 64-bit counter...
++ */
++static void ctr64_inc(unsigned char *counter)
++{
++    unsigned int n = 8;
++    u8 c;
++
++    counter += 8;
++    do {
++        --n;
++        c = counter[n];
++        ++c;
++        counter[n] = c;
++        if (c)
++            return;
++    } while (n);
++}
++
++int CRYPTO_ccm128_encrypt(CCM128_CONTEXT *ctx,
++                          const unsigned char *inp, unsigned char *out,
++                          size_t len)
++{
++    size_t n;
++    unsigned int i, L;
++    unsigned char flags0 = ctx->nonce.c[0];
++    block128_f block = ctx->block;
++    void *key = ctx->key;
++    union {
++        u64 u[2];
++        u8 c[16];
++    } scratch;
++
++    if (!(flags0 & 0x40))
++        (*block) (ctx->nonce.c, ctx->cmac.c, key), ctx->blocks++;
++
++    ctx->nonce.c[0] = L = flags0 & 7;
++    for (n = 0, i = 15 - L; i < 15; ++i) {
++        n |= ctx->nonce.c[i];
++        ctx->nonce.c[i] = 0;
++        n <<= 8;
++    }
++    n |= ctx->nonce.c[15];      /* reconstructed length */
++    ctx->nonce.c[15] = 1;
++
++    if (n != len)
++        return -1;              /* length mismatch */
++
++    ctx->blocks += ((len + 15) >> 3) | 1;
++    if (ctx->blocks > (U64(1) << 61))
++        return -2;              /* too much data */
++
++    while (len >= 16) {
++#if defined(STRICT_ALIGNMENT)
++        union {
++            u64 u[2];
++            u8 c[16];
++        } temp;
++
++        memcpy(temp.c, inp, 16);
++        ctx->cmac.u[0] ^= temp.u[0];
++        ctx->cmac.u[1] ^= temp.u[1];
++#else
++        ctx->cmac.u[0] ^= ((u64 *)inp)[0];
++        ctx->cmac.u[1] ^= ((u64 *)inp)[1];
++#endif
++        (*block) (ctx->cmac.c, ctx->cmac.c, key);
++        (*block) (ctx->nonce.c, scratch.c, key);
++        ctr64_inc(ctx->nonce.c);
++#if defined(STRICT_ALIGNMENT)
++        temp.u[0] ^= scratch.u[0];
++        temp.u[1] ^= scratch.u[1];
++        memcpy(out, temp.c, 16);
++#else
++        ((u64 *)out)[0] = scratch.u[0] ^ ((u64 *)inp)[0];
++        ((u64 *)out)[1] = scratch.u[1] ^ ((u64 *)inp)[1];
++#endif
++        inp += 16;
++        out += 16;
++        len -= 16;
++    }
++
++    if (len) {
++        for (i = 0; i < len; ++i)
++            ctx->cmac.c[i] ^= inp[i];
++        (*block) (ctx->cmac.c, ctx->cmac.c, key);
++        (*block) (ctx->nonce.c, scratch.c, key);
++        for (i = 0; i < len; ++i)
++            out[i] = scratch.c[i] ^ inp[i];
++    }
++
++    for (i = 15 - L; i < 16; ++i)
++        ctx->nonce.c[i] = 0;
++
++    (*block) (ctx->nonce.c, scratch.c, key);
++    ctx->cmac.u[0] ^= scratch.u[0];
++    ctx->cmac.u[1] ^= scratch.u[1];
++
++    ctx->nonce.c[0] = flags0;
++
++    return 0;
++}
++
++int CRYPTO_ccm128_decrypt(CCM128_CONTEXT *ctx,
++                          const unsigned char *inp, unsigned char *out,
++                          size_t len)
++{
++    size_t n;
++    unsigned int i, L;
++    unsigned char flags0 = ctx->nonce.c[0];
++    block128_f block = ctx->block;
++    void *key = ctx->key;
++    union {
++        u64 u[2];
++        u8 c[16];
++    } scratch;
++
++    if (!(flags0 & 0x40))
++        (*block) (ctx->nonce.c, ctx->cmac.c, key);
++
++    ctx->nonce.c[0] = L = flags0 & 7;
++    for (n = 0, i = 15 - L; i < 15; ++i) {
++        n |= ctx->nonce.c[i];
++        ctx->nonce.c[i] = 0;
++        n <<= 8;
++    }
++    n |= ctx->nonce.c[15];      /* reconstructed length */
++    ctx->nonce.c[15] = 1;
++
++    if (n != len)
++        return -1;
++
++    while (len >= 16) {
++#if defined(STRICT_ALIGNMENT)
++        union {
++            u64 u[2];
++            u8 c[16];
++        } temp;
++#endif
++        (*block) (ctx->nonce.c, scratch.c, key);
++        ctr64_inc(ctx->nonce.c);
++#if defined(STRICT_ALIGNMENT)
++        memcpy(temp.c, inp, 16);
++        ctx->cmac.u[0] ^= (scratch.u[0] ^= temp.u[0]);
++        ctx->cmac.u[1] ^= (scratch.u[1] ^= temp.u[1]);
++        memcpy(out, scratch.c, 16);
++#else
++        ctx->cmac.u[0] ^= (((u64 *)out)[0] = scratch.u[0] ^ ((u64 *)inp)[0]);
++        ctx->cmac.u[1] ^= (((u64 *)out)[1] = scratch.u[1] ^ ((u64 *)inp)[1]);
++#endif
++        (*block) (ctx->cmac.c, ctx->cmac.c, key);
++
++        inp += 16;
++        out += 16;
++        len -= 16;
++    }
++
++    if (len) {
++        (*block) (ctx->nonce.c, scratch.c, key);
++        for (i = 0; i < len; ++i)
++            ctx->cmac.c[i] ^= (out[i] = scratch.c[i] ^ inp[i]);
++        (*block) (ctx->cmac.c, ctx->cmac.c, key);
++    }
++
++    for (i = 15 - L; i < 16; ++i)
++        ctx->nonce.c[i] = 0;
++
++    (*block) (ctx->nonce.c, scratch.c, key);
++    ctx->cmac.u[0] ^= scratch.u[0];
++    ctx->cmac.u[1] ^= scratch.u[1];
++
++    ctx->nonce.c[0] = flags0;
++
++    return 0;
++}
++
++static void ctr64_add(unsigned char *counter, size_t inc)
++{
++    size_t n = 8, val = 0;
++
++    counter += 8;
++    do {
++        --n;
++        val += counter[n] + (inc & 0xff);
++        counter[n] = (unsigned char)val;
++        val >>= 8;              /* carry bit */
++        inc >>= 8;
++    } while (n && (inc || val));
++}
++
++int CRYPTO_ccm128_encrypt_ccm64(CCM128_CONTEXT *ctx,
++                                const unsigned char *inp, unsigned char *out,
++                                size_t len, ccm128_f stream)
++{
++    size_t n;
++    unsigned int i, L;
++    unsigned char flags0 = ctx->nonce.c[0];
++    block128_f block = ctx->block;
++    void *key = ctx->key;
++    union {
++        u64 u[2];
++        u8 c[16];
++    } scratch;
++
++    if (!(flags0 & 0x40))
++        (*block) (ctx->nonce.c, ctx->cmac.c, key), ctx->blocks++;
++
++    ctx->nonce.c[0] = L = flags0 & 7;
++    for (n = 0, i = 15 - L; i < 15; ++i) {
++        n |= ctx->nonce.c[i];
++        ctx->nonce.c[i] = 0;
++        n <<= 8;
++    }
++    n |= ctx->nonce.c[15];      /* reconstructed length */
++    ctx->nonce.c[15] = 1;
++
++    if (n != len)
++        return -1;              /* length mismatch */
++
++    ctx->blocks += ((len + 15) >> 3) | 1;
++    if (ctx->blocks > (U64(1) << 61))
++        return -2;              /* too much data */
++
++    if ((n = len / 16)) {
++        (*stream) (inp, out, n, key, ctx->nonce.c, ctx->cmac.c);
++        n *= 16;
++        inp += n;
++        out += n;
++        len -= n;
++        if (len)
++            ctr64_add(ctx->nonce.c, n / 16);
++    }
++
++    if (len) {
++        for (i = 0; i < len; ++i)
++            ctx->cmac.c[i] ^= inp[i];
++        (*block) (ctx->cmac.c, ctx->cmac.c, key);
++        (*block) (ctx->nonce.c, scratch.c, key);
++        for (i = 0; i < len; ++i)
++            out[i] = scratch.c[i] ^ inp[i];
++    }
++
++    for (i = 15 - L; i < 16; ++i)
++        ctx->nonce.c[i] = 0;
++
++    (*block) (ctx->nonce.c, scratch.c, key);
++    ctx->cmac.u[0] ^= scratch.u[0];
++    ctx->cmac.u[1] ^= scratch.u[1];
++
++    ctx->nonce.c[0] = flags0;
++
++    return 0;
++}
++
++int CRYPTO_ccm128_decrypt_ccm64(CCM128_CONTEXT *ctx,
++                                const unsigned char *inp, unsigned char *out,
++                                size_t len, ccm128_f stream)
++{
++    size_t n;
++    unsigned int i, L;
++    unsigned char flags0 = ctx->nonce.c[0];
++    block128_f block = ctx->block;
++    void *key = ctx->key;
++    union {
++        u64 u[2];
++        u8 c[16];
++    } scratch;
++
++    if (!(flags0 & 0x40))
++        (*block) (ctx->nonce.c, ctx->cmac.c, key);
++
++    ctx->nonce.c[0] = L = flags0 & 7;
++    for (n = 0, i = 15 - L; i < 15; ++i) {
++        n |= ctx->nonce.c[i];
++        ctx->nonce.c[i] = 0;
++        n <<= 8;
++    }
++    n |= ctx->nonce.c[15];      /* reconstructed length */
++    ctx->nonce.c[15] = 1;
++
++    if (n != len)
++        return -1;
++
++    if ((n = len / 16)) {
++        (*stream) (inp, out, n, key, ctx->nonce.c, ctx->cmac.c);
++        n *= 16;
++        inp += n;
++        out += n;
++        len -= n;
++        if (len)
++            ctr64_add(ctx->nonce.c, n / 16);
++    }
++
++    if (len) {
++        (*block) (ctx->nonce.c, scratch.c, key);
++        for (i = 0; i < len; ++i)
++            ctx->cmac.c[i] ^= (out[i] = scratch.c[i] ^ inp[i]);
++        (*block) (ctx->cmac.c, ctx->cmac.c, key);
++    }
++
++    for (i = 15 - L; i < 16; ++i)
++        ctx->nonce.c[i] = 0;
++
++    (*block) (ctx->nonce.c, scratch.c, key);
++    ctx->cmac.u[0] ^= scratch.u[0];
++    ctx->cmac.u[1] ^= scratch.u[1];
++
++    ctx->nonce.c[0] = flags0;
++
++    return 0;
++}
++
++size_t CRYPTO_ccm128_tag(CCM128_CONTEXT *ctx, unsigned char *tag, size_t len)
++{
++    unsigned int M = (ctx->nonce.c[0] >> 3) & 7; /* the M parameter */
++
++    M *= 2;
++    M += 2;
++    if (len < M)
++        return 0;
++    memcpy(tag, ctx->cmac.c, M);
++    return M;
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/modes/cfb128.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/modes/cfb128.c
+new file mode 100644
+index 0000000..e439567
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/modes/cfb128.c
+@@ -0,0 +1,198 @@
++/*
++ * Copyright 2008-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include "modes_lcl.h"
++#include 
++
++/*
++ * The input and output encrypted as though 128bit cfb mode is being used.
++ * The extra state information to record how much of the 128bit block we have
++ * used is contained in *num;
++ */
++void CRYPTO_cfb128_encrypt(const unsigned char *in, unsigned char *out,
++                           size_t len, const void *key,
++                           unsigned char ivec[16], int *num,
++                           int enc, block128_f block)
++{
++    unsigned int n;
++    size_t l = 0;
++
++    n = *num;
++
++    if (enc) {
++#if !defined(OPENSSL_SMALL_FOOTPRINT)
++        if (16 % sizeof(size_t) == 0) { /* always true actually */
++            do {
++                while (n && len) {
++                    *(out++) = ivec[n] ^= *(in++);
++                    --len;
++                    n = (n + 1) % 16;
++                }
++# if defined(STRICT_ALIGNMENT)
++                if (((size_t)in | (size_t)out | (size_t)ivec) %
++                    sizeof(size_t) != 0)
++                    break;
++# endif
++                while (len >= 16) {
++                    (*block) (ivec, ivec, key);
++                    for (; n < 16; n += sizeof(size_t)) {
++                        *(size_t *)(out + n) =
++                            *(size_t *)(ivec + n) ^= *(size_t *)(in + n);
++                    }
++                    len -= 16;
++                    out += 16;
++                    in += 16;
++                    n = 0;
++                }
++                if (len) {
++                    (*block) (ivec, ivec, key);
++                    while (len--) {
++                        out[n] = ivec[n] ^= in[n];
++                        ++n;
++                    }
++                }
++                *num = n;
++                return;
++            } while (0);
++        }
++        /* the rest would be commonly eliminated by x86* compiler */
++#endif
++        while (l < len) {
++            if (n == 0) {
++                (*block) (ivec, ivec, key);
++            }
++            out[l] = ivec[n] ^= in[l];
++            ++l;
++            n = (n + 1) % 16;
++        }
++        *num = n;
++    } else {
++#if !defined(OPENSSL_SMALL_FOOTPRINT)
++        if (16 % sizeof(size_t) == 0) { /* always true actually */
++            do {
++                while (n && len) {
++                    unsigned char c;
++                    *(out++) = ivec[n] ^ (c = *(in++));
++                    ivec[n] = c;
++                    --len;
++                    n = (n + 1) % 16;
++                }
++# if defined(STRICT_ALIGNMENT)
++                if (((size_t)in | (size_t)out | (size_t)ivec) %
++                    sizeof(size_t) != 0)
++                    break;
++# endif
++                while (len >= 16) {
++                    (*block) (ivec, ivec, key);
++                    for (; n < 16; n += sizeof(size_t)) {
++                        size_t t = *(size_t *)(in + n);
++                        *(size_t *)(out + n) = *(size_t *)(ivec + n) ^ t;
++                        *(size_t *)(ivec + n) = t;
++                    }
++                    len -= 16;
++                    out += 16;
++                    in += 16;
++                    n = 0;
++                }
++                if (len) {
++                    (*block) (ivec, ivec, key);
++                    while (len--) {
++                        unsigned char c;
++                        out[n] = ivec[n] ^ (c = in[n]);
++                        ivec[n] = c;
++                        ++n;
++                    }
++                }
++                *num = n;
++                return;
++            } while (0);
++        }
++        /* the rest would be commonly eliminated by x86* compiler */
++#endif
++        while (l < len) {
++            unsigned char c;
++            if (n == 0) {
++                (*block) (ivec, ivec, key);
++            }
++            out[l] = ivec[n] ^ (c = in[l]);
++            ivec[n] = c;
++            ++l;
++            n = (n + 1) % 16;
++        }
++        *num = n;
++    }
++}
++
++/*
++ * This expects a single block of size nbits for both in and out. Note that
++ * it corrupts any extra bits in the last byte of out
++ */
++static void cfbr_encrypt_block(const unsigned char *in, unsigned char *out,
++                               int nbits, const void *key,
++                               unsigned char ivec[16], int enc,
++                               block128_f block)
++{
++    int n, rem, num;
++    unsigned char ovec[16 * 2 + 1]; /* +1 because we dereference (but don't
++                                     * use) one byte off the end */
++
++    if (nbits <= 0 || nbits > 128)
++        return;
++
++    /* fill in the first half of the new IV with the current IV */
++    memcpy(ovec, ivec, 16);
++    /* construct the new IV */
++    (*block) (ivec, ivec, key);
++    num = (nbits + 7) / 8;
++    if (enc)                    /* encrypt the input */
++        for (n = 0; n < num; ++n)
++            out[n] = (ovec[16 + n] = in[n] ^ ivec[n]);
++    else                        /* decrypt the input */
++        for (n = 0; n < num; ++n)
++            out[n] = (ovec[16 + n] = in[n]) ^ ivec[n];
++    /* shift ovec left... */
++    rem = nbits % 8;
++    num = nbits / 8;
++    if (rem == 0)
++        memcpy(ivec, ovec + num, 16);
++    else
++        for (n = 0; n < 16; ++n)
++            ivec[n] = ovec[n + num] << rem | ovec[n + num + 1] >> (8 - rem);
++
++    /* it is not necessary to cleanse ovec, since the IV is not secret */
++}
++
++/* N.B. This expects the input to be packed, MS bit first */
++void CRYPTO_cfb128_1_encrypt(const unsigned char *in, unsigned char *out,
++                             size_t bits, const void *key,
++                             unsigned char ivec[16], int *num,
++                             int enc, block128_f block)
++{
++    size_t n;
++    unsigned char c[1], d[1];
++
++    for (n = 0; n < bits; ++n) {
++        c[0] = (in[n / 8] & (1 << (7 - n % 8))) ? 0x80 : 0;
++        cfbr_encrypt_block(c, d, 1, key, ivec, enc, block);
++        out[n / 8] = (out[n / 8] & ~(1 << (unsigned int)(7 - n % 8))) |
++            ((d[0] & 0x80) >> (unsigned int)(n % 8));
++    }
++}
++
++void CRYPTO_cfb128_8_encrypt(const unsigned char *in, unsigned char *out,
++                             size_t length, const void *key,
++                             unsigned char ivec[16], int *num,
++                             int enc, block128_f block)
++{
++    size_t n;
++
++    for (n = 0; n < length; ++n)
++        cfbr_encrypt_block(&in[n], &out[n], 8, key, ivec, enc, block);
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/modes/ctr128.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/modes/ctr128.c
+new file mode 100644
+index 0000000..03920b4
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/modes/ctr128.c
+@@ -0,0 +1,209 @@
++/*
++ * Copyright 2008-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include "modes_lcl.h"
++#include 
++
++/*
++ * NOTE: the IV/counter CTR mode is big-endian.  The code itself is
++ * endian-neutral.
++ */
++
++/* increment counter (128-bit int) by 1 */
++static void ctr128_inc(unsigned char *counter)
++{
++    u32 n = 16, c = 1;
++
++    do {
++        --n;
++        c += counter[n];
++        counter[n] = (u8)c;
++        c >>= 8;
++    } while (n);
++}
++
++#if !defined(OPENSSL_SMALL_FOOTPRINT)
++static void ctr128_inc_aligned(unsigned char *counter)
++{
++    size_t *data, c, d, n;
++    const union {
++        long one;
++        char little;
++    } is_endian = {
++        1
++    };
++
++    if (is_endian.little || ((size_t)counter % sizeof(size_t)) != 0) {
++        ctr128_inc(counter);
++        return;
++    }
++
++    data = (size_t *)counter;
++    c = 1;
++    n = 16 / sizeof(size_t);
++    do {
++        --n;
++        d = data[n] += c;
++        /* did addition carry? */
++        c = ((d - c) & ~d) >> (sizeof(size_t) * 8 - 1);
++    } while (n);
++}
++#endif
++
++/*
++ * The input encrypted as though 128bit counter mode is being used.  The
++ * extra state information to record how much of the 128bit block we have
++ * used is contained in *num, and the encrypted counter is kept in
++ * ecount_buf.  Both *num and ecount_buf must be initialised with zeros
++ * before the first call to CRYPTO_ctr128_encrypt(). This algorithm assumes
++ * that the counter is in the x lower bits of the IV (ivec), and that the
++ * application has full control over overflow and the rest of the IV.  This
++ * implementation takes NO responsibility for checking that the counter
++ * doesn't overflow into the rest of the IV when incremented.
++ */
++void CRYPTO_ctr128_encrypt(const unsigned char *in, unsigned char *out,
++                           size_t len, const void *key,
++                           unsigned char ivec[16],
++                           unsigned char ecount_buf[16], unsigned int *num,
++                           block128_f block)
++{
++    unsigned int n;
++    size_t l = 0;
++
++    n = *num;
++
++#if !defined(OPENSSL_SMALL_FOOTPRINT)
++    if (16 % sizeof(size_t) == 0) { /* always true actually */
++        do {
++            while (n && len) {
++                *(out++) = *(in++) ^ ecount_buf[n];
++                --len;
++                n = (n + 1) % 16;
++            }
++
++# if defined(STRICT_ALIGNMENT)
++            if (((size_t)in | (size_t)out | (size_t)ecount_buf)
++                % sizeof(size_t) != 0)
++                break;
++# endif
++            while (len >= 16) {
++                (*block) (ivec, ecount_buf, key);
++                ctr128_inc_aligned(ivec);
++                for (n = 0; n < 16; n += sizeof(size_t))
++                    *(size_t *)(out + n) =
++                        *(size_t *)(in + n) ^ *(size_t *)(ecount_buf + n);
++                len -= 16;
++                out += 16;
++                in += 16;
++                n = 0;
++            }
++            if (len) {
++                (*block) (ivec, ecount_buf, key);
++                ctr128_inc_aligned(ivec);
++                while (len--) {
++                    out[n] = in[n] ^ ecount_buf[n];
++                    ++n;
++                }
++            }
++            *num = n;
++            return;
++        } while (0);
++    }
++    /* the rest would be commonly eliminated by x86* compiler */
++#endif
++    while (l < len) {
++        if (n == 0) {
++            (*block) (ivec, ecount_buf, key);
++            ctr128_inc(ivec);
++        }
++        out[l] = in[l] ^ ecount_buf[n];
++        ++l;
++        n = (n + 1) % 16;
++    }
++
++    *num = n;
++}
++
++/* increment upper 96 bits of 128-bit counter by 1 */
++static void ctr96_inc(unsigned char *counter)
++{
++    u32 n = 12, c = 1;
++
++    do {
++        --n;
++        c += counter[n];
++        counter[n] = (u8)c;
++        c >>= 8;
++    } while (n);
++}
++
++void CRYPTO_ctr128_encrypt_ctr32(const unsigned char *in, unsigned char *out,
++                                 size_t len, const void *key,
++                                 unsigned char ivec[16],
++                                 unsigned char ecount_buf[16],
++                                 unsigned int *num, ctr128_f func)
++{
++    unsigned int n, ctr32;
++
++    n = *num;
++
++    while (n && len) {
++        *(out++) = *(in++) ^ ecount_buf[n];
++        --len;
++        n = (n + 1) % 16;
++    }
++
++    ctr32 = GETU32(ivec + 12);
++    while (len >= 16) {
++        size_t blocks = len / 16;
++        /*
++         * 1<<28 is just a not-so-small yet not-so-large number...
++         * Below condition is practically never met, but it has to
++         * be checked for code correctness.
++         */
++        if (sizeof(size_t) > sizeof(unsigned int) && blocks > (1U << 28))
++            blocks = (1U << 28);
++        /*
++         * As (*func) operates on 32-bit counter, caller
++         * has to handle overflow. 'if' below detects the
++         * overflow, which is then handled by limiting the
++         * amount of blocks to the exact overflow point...
++         */
++        ctr32 += (u32)blocks;
++        if (ctr32 < blocks) {
++            blocks -= ctr32;
++            ctr32 = 0;
++        }
++        (*func) (in, out, blocks, key, ivec);
++        /* (*ctr) does not update ivec, caller does: */
++        PUTU32(ivec + 12, ctr32);
++        /* ... overflow was detected, propagate carry. */
++        if (ctr32 == 0)
++            ctr96_inc(ivec);
++        blocks *= 16;
++        len -= blocks;
++        out += blocks;
++        in += blocks;
++    }
++    if (len) {
++        memset(ecount_buf, 0, 16);
++        (*func) (ecount_buf, ecount_buf, 1, key, ivec);
++        ++ctr32;
++        PUTU32(ivec + 12, ctr32);
++        if (ctr32 == 0)
++            ctr96_inc(ivec);
++        while (len--) {
++            out[n] = in[n] ^ ecount_buf[n];
++            ++n;
++        }
++    }
++
++    *num = n;
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/modes/cts128.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/modes/cts128.c
+new file mode 100644
+index 0000000..77ec994
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/modes/cts128.c
+@@ -0,0 +1,523 @@
++/*
++ * Copyright 2008-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include "modes_lcl.h"
++#include 
++
++/*
++ * Trouble with Ciphertext Stealing, CTS, mode is that there is no
++ * common official specification, but couple of cipher/application
++ * specific ones: RFC2040 and RFC3962. Then there is 'Proposal to
++ * Extend CBC Mode By "Ciphertext Stealing"' at NIST site, which
++ * deviates from mentioned RFCs. Most notably it allows input to be
++ * of block length and it doesn't flip the order of the last two
++ * blocks. CTS is being discussed even in ECB context, but it's not
++ * adopted for any known application. This implementation provides
++ * two interfaces: one compliant with above mentioned RFCs and one
++ * compliant with the NIST proposal, both extending CBC mode.
++ */
++
++size_t CRYPTO_cts128_encrypt_block(const unsigned char *in,
++                                   unsigned char *out, size_t len,
++                                   const void *key, unsigned char ivec[16],
++                                   block128_f block)
++{
++    size_t residue, n;
++
++    if (len <= 16)
++        return 0;
++
++    if ((residue = len % 16) == 0)
++        residue = 16;
++
++    len -= residue;
++
++    CRYPTO_cbc128_encrypt(in, out, len, key, ivec, block);
++
++    in += len;
++    out += len;
++
++    for (n = 0; n < residue; ++n)
++        ivec[n] ^= in[n];
++    (*block) (ivec, ivec, key);
++    memcpy(out, out - 16, residue);
++    memcpy(out - 16, ivec, 16);
++
++    return len + residue;
++}
++
++size_t CRYPTO_nistcts128_encrypt_block(const unsigned char *in,
++                                       unsigned char *out, size_t len,
++                                       const void *key,
++                                       unsigned char ivec[16],
++                                       block128_f block)
++{
++    size_t residue, n;
++
++    if (len < 16)
++        return 0;
++
++    residue = len % 16;
++
++    len -= residue;
++
++    CRYPTO_cbc128_encrypt(in, out, len, key, ivec, block);
++
++    if (residue == 0)
++        return len;
++
++    in += len;
++    out += len;
++
++    for (n = 0; n < residue; ++n)
++        ivec[n] ^= in[n];
++    (*block) (ivec, ivec, key);
++    memcpy(out - 16 + residue, ivec, 16);
++
++    return len + residue;
++}
++
++size_t CRYPTO_cts128_encrypt(const unsigned char *in, unsigned char *out,
++                             size_t len, const void *key,
++                             unsigned char ivec[16], cbc128_f cbc)
++{
++    size_t residue;
++    union {
++        size_t align;
++        unsigned char c[16];
++    } tmp;
++
++    if (len <= 16)
++        return 0;
++
++    if ((residue = len % 16) == 0)
++        residue = 16;
++
++    len -= residue;
++
++    (*cbc) (in, out, len, key, ivec, 1);
++
++    in += len;
++    out += len;
++
++#if defined(CBC_HANDLES_TRUNCATED_IO)
++    memcpy(tmp.c, out - 16, 16);
++    (*cbc) (in, out - 16, residue, key, ivec, 1);
++    memcpy(out, tmp.c, residue);
++#else
++    memset(tmp.c, 0, sizeof(tmp));
++    memcpy(tmp.c, in, residue);
++    memcpy(out, out - 16, residue);
++    (*cbc) (tmp.c, out - 16, 16, key, ivec, 1);
++#endif
++    return len + residue;
++}
++
++size_t CRYPTO_nistcts128_encrypt(const unsigned char *in, unsigned char *out,
++                                 size_t len, const void *key,
++                                 unsigned char ivec[16], cbc128_f cbc)
++{
++    size_t residue;
++    union {
++        size_t align;
++        unsigned char c[16];
++    } tmp;
++
++    if (len < 16)
++        return 0;
++
++    residue = len % 16;
++
++    len -= residue;
++
++    (*cbc) (in, out, len, key, ivec, 1);
++
++    if (residue == 0)
++        return len;
++
++    in += len;
++    out += len;
++
++#if defined(CBC_HANDLES_TRUNCATED_IO)
++    (*cbc) (in, out - 16 + residue, residue, key, ivec, 1);
++#else
++    memset(tmp.c, 0, sizeof(tmp));
++    memcpy(tmp.c, in, residue);
++    (*cbc) (tmp.c, out - 16 + residue, 16, key, ivec, 1);
++#endif
++    return len + residue;
++}
++
++size_t CRYPTO_cts128_decrypt_block(const unsigned char *in,
++                                   unsigned char *out, size_t len,
++                                   const void *key, unsigned char ivec[16],
++                                   block128_f block)
++{
++    size_t residue, n;
++    union {
++        size_t align;
++        unsigned char c[32];
++    } tmp;
++
++    if (len <= 16)
++        return 0;
++
++    if ((residue = len % 16) == 0)
++        residue = 16;
++
++    len -= 16 + residue;
++
++    if (len) {
++        CRYPTO_cbc128_decrypt(in, out, len, key, ivec, block);
++        in += len;
++        out += len;
++    }
++
++    (*block) (in, tmp.c + 16, key);
++
++    memcpy(tmp.c, tmp.c + 16, 16);
++    memcpy(tmp.c, in + 16, residue);
++    (*block) (tmp.c, tmp.c, key);
++
++    for (n = 0; n < 16; ++n) {
++        unsigned char c = in[n];
++        out[n] = tmp.c[n] ^ ivec[n];
++        ivec[n] = c;
++    }
++    for (residue += 16; n < residue; ++n)
++        out[n] = tmp.c[n] ^ in[n];
++
++    return 16 + len + residue;
++}
++
++size_t CRYPTO_nistcts128_decrypt_block(const unsigned char *in,
++                                       unsigned char *out, size_t len,
++                                       const void *key,
++                                       unsigned char ivec[16],
++                                       block128_f block)
++{
++    size_t residue, n;
++    union {
++        size_t align;
++        unsigned char c[32];
++    } tmp;
++
++    if (len < 16)
++        return 0;
++
++    residue = len % 16;
++
++    if (residue == 0) {
++        CRYPTO_cbc128_decrypt(in, out, len, key, ivec, block);
++        return len;
++    }
++
++    len -= 16 + residue;
++
++    if (len) {
++        CRYPTO_cbc128_decrypt(in, out, len, key, ivec, block);
++        in += len;
++        out += len;
++    }
++
++    (*block) (in + residue, tmp.c + 16, key);
++
++    memcpy(tmp.c, tmp.c + 16, 16);
++    memcpy(tmp.c, in, residue);
++    (*block) (tmp.c, tmp.c, key);
++
++    for (n = 0; n < 16; ++n) {
++        unsigned char c = in[n];
++        out[n] = tmp.c[n] ^ ivec[n];
++        ivec[n] = in[n + residue];
++        tmp.c[n] = c;
++    }
++    for (residue += 16; n < residue; ++n)
++        out[n] = tmp.c[n] ^ tmp.c[n - 16];
++
++    return 16 + len + residue;
++}
++
++size_t CRYPTO_cts128_decrypt(const unsigned char *in, unsigned char *out,
++                             size_t len, const void *key,
++                             unsigned char ivec[16], cbc128_f cbc)
++{
++    size_t residue;
++    union {
++        size_t align;
++        unsigned char c[32];
++    } tmp;
++
++    if (len <= 16)
++        return 0;
++
++    if ((residue = len % 16) == 0)
++        residue = 16;
++
++    len -= 16 + residue;
++
++    if (len) {
++        (*cbc) (in, out, len, key, ivec, 0);
++        in += len;
++        out += len;
++    }
++
++    memset(tmp.c, 0, sizeof(tmp));
++    /*
++     * this places in[16] at &tmp.c[16] and decrypted block at &tmp.c[0]
++     */
++    (*cbc) (in, tmp.c, 16, key, tmp.c + 16, 0);
++
++    memcpy(tmp.c, in + 16, residue);
++#if defined(CBC_HANDLES_TRUNCATED_IO)
++    (*cbc) (tmp.c, out, 16 + residue, key, ivec, 0);
++#else
++    (*cbc) (tmp.c, tmp.c, 32, key, ivec, 0);
++    memcpy(out, tmp.c, 16 + residue);
++#endif
++    return 16 + len + residue;
++}
++
++size_t CRYPTO_nistcts128_decrypt(const unsigned char *in, unsigned char *out,
++                                 size_t len, const void *key,
++                                 unsigned char ivec[16], cbc128_f cbc)
++{
++    size_t residue;
++    union {
++        size_t align;
++        unsigned char c[32];
++    } tmp;
++
++    if (len < 16)
++        return 0;
++
++    residue = len % 16;
++
++    if (residue == 0) {
++        (*cbc) (in, out, len, key, ivec, 0);
++        return len;
++    }
++
++    len -= 16 + residue;
++
++    if (len) {
++        (*cbc) (in, out, len, key, ivec, 0);
++        in += len;
++        out += len;
++    }
++
++    memset(tmp.c, 0, sizeof(tmp));
++    /*
++     * this places in[16] at &tmp.c[16] and decrypted block at &tmp.c[0]
++     */
++    (*cbc) (in + residue, tmp.c, 16, key, tmp.c + 16, 0);
++
++    memcpy(tmp.c, in, residue);
++#if defined(CBC_HANDLES_TRUNCATED_IO)
++    (*cbc) (tmp.c, out, 16 + residue, key, ivec, 0);
++#else
++    (*cbc) (tmp.c, tmp.c, 32, key, ivec, 0);
++    memcpy(out, tmp.c, 16 + residue);
++#endif
++    return 16 + len + residue;
++}
++
++#if defined(SELFTEST)
++# include 
++# include 
++
++/* test vectors from RFC 3962 */
++static const unsigned char test_key[16] = "chicken teriyaki";
++static const unsigned char test_input[64] =
++    "I would like the" " General Gau's C"
++    "hicken, please, " "and wonton soup.";
++static const unsigned char test_iv[16] =
++    { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
++
++static const unsigned char vector_17[17] = {
++    0xc6, 0x35, 0x35, 0x68, 0xf2, 0xbf, 0x8c, 0xb4,
++    0xd8, 0xa5, 0x80, 0x36, 0x2d, 0xa7, 0xff, 0x7f,
++    0x97
++};
++
++static const unsigned char vector_31[31] = {
++    0xfc, 0x00, 0x78, 0x3e, 0x0e, 0xfd, 0xb2, 0xc1,
++    0xd4, 0x45, 0xd4, 0xc8, 0xef, 0xf7, 0xed, 0x22,
++    0x97, 0x68, 0x72, 0x68, 0xd6, 0xec, 0xcc, 0xc0,
++    0xc0, 0x7b, 0x25, 0xe2, 0x5e, 0xcf, 0xe5
++};
++
++static const unsigned char vector_32[32] = {
++    0x39, 0x31, 0x25, 0x23, 0xa7, 0x86, 0x62, 0xd5,
++    0xbe, 0x7f, 0xcb, 0xcc, 0x98, 0xeb, 0xf5, 0xa8,
++    0x97, 0x68, 0x72, 0x68, 0xd6, 0xec, 0xcc, 0xc0,
++    0xc0, 0x7b, 0x25, 0xe2, 0x5e, 0xcf, 0xe5, 0x84
++};
++
++static const unsigned char vector_47[47] = {
++    0x97, 0x68, 0x72, 0x68, 0xd6, 0xec, 0xcc, 0xc0,
++    0xc0, 0x7b, 0x25, 0xe2, 0x5e, 0xcf, 0xe5, 0x84,
++    0xb3, 0xff, 0xfd, 0x94, 0x0c, 0x16, 0xa1, 0x8c,
++    0x1b, 0x55, 0x49, 0xd2, 0xf8, 0x38, 0x02, 0x9e,
++    0x39, 0x31, 0x25, 0x23, 0xa7, 0x86, 0x62, 0xd5,
++    0xbe, 0x7f, 0xcb, 0xcc, 0x98, 0xeb, 0xf5
++};
++
++static const unsigned char vector_48[48] = {
++    0x97, 0x68, 0x72, 0x68, 0xd6, 0xec, 0xcc, 0xc0,
++    0xc0, 0x7b, 0x25, 0xe2, 0x5e, 0xcf, 0xe5, 0x84,
++    0x9d, 0xad, 0x8b, 0xbb, 0x96, 0xc4, 0xcd, 0xc0,
++    0x3b, 0xc1, 0x03, 0xe1, 0xa1, 0x94, 0xbb, 0xd8,
++    0x39, 0x31, 0x25, 0x23, 0xa7, 0x86, 0x62, 0xd5,
++    0xbe, 0x7f, 0xcb, 0xcc, 0x98, 0xeb, 0xf5, 0xa8
++};
++
++static const unsigned char vector_64[64] = {
++    0x97, 0x68, 0x72, 0x68, 0xd6, 0xec, 0xcc, 0xc0,
++    0xc0, 0x7b, 0x25, 0xe2, 0x5e, 0xcf, 0xe5, 0x84,
++    0x39, 0x31, 0x25, 0x23, 0xa7, 0x86, 0x62, 0xd5,
++    0xbe, 0x7f, 0xcb, 0xcc, 0x98, 0xeb, 0xf5, 0xa8,
++    0x48, 0x07, 0xef, 0xe8, 0x36, 0xee, 0x89, 0xa5,
++    0x26, 0x73, 0x0d, 0xbc, 0x2f, 0x7b, 0xc8, 0x40,
++    0x9d, 0xad, 0x8b, 0xbb, 0x96, 0xc4, 0xcd, 0xc0,
++    0x3b, 0xc1, 0x03, 0xe1, 0xa1, 0x94, 0xbb, 0xd8
++};
++
++static AES_KEY encks, decks;
++
++void test_vector(const unsigned char *vector, size_t len)
++{
++    unsigned char iv[sizeof(test_iv)];
++    unsigned char cleartext[64], ciphertext[64];
++    size_t tail;
++
++    printf("vector_%d\n", len);
++    fflush(stdout);
++
++    if ((tail = len % 16) == 0)
++        tail = 16;
++    tail += 16;
++
++    /* test block-based encryption */
++    memcpy(iv, test_iv, sizeof(test_iv));
++    CRYPTO_cts128_encrypt_block(test_input, ciphertext, len, &encks, iv,
++                                (block128_f) AES_encrypt);
++    if (memcmp(ciphertext, vector, len))
++        fprintf(stderr, "output_%d mismatch\n", len), exit(1);
++    if (memcmp(iv, vector + len - tail, sizeof(iv)))
++        fprintf(stderr, "iv_%d mismatch\n", len), exit(1);
++
++    /* test block-based decryption */
++    memcpy(iv, test_iv, sizeof(test_iv));
++    CRYPTO_cts128_decrypt_block(ciphertext, cleartext, len, &decks, iv,
++                                (block128_f) AES_decrypt);
++    if (memcmp(cleartext, test_input, len))
++        fprintf(stderr, "input_%d mismatch\n", len), exit(2);
++    if (memcmp(iv, vector + len - tail, sizeof(iv)))
++        fprintf(stderr, "iv_%d mismatch\n", len), exit(2);
++
++    /* test streamed encryption */
++    memcpy(iv, test_iv, sizeof(test_iv));
++    CRYPTO_cts128_encrypt(test_input, ciphertext, len, &encks, iv,
++                          (cbc128_f) AES_cbc_encrypt);
++    if (memcmp(ciphertext, vector, len))
++        fprintf(stderr, "output_%d mismatch\n", len), exit(3);
++    if (memcmp(iv, vector + len - tail, sizeof(iv)))
++        fprintf(stderr, "iv_%d mismatch\n", len), exit(3);
++
++    /* test streamed decryption */
++    memcpy(iv, test_iv, sizeof(test_iv));
++    CRYPTO_cts128_decrypt(ciphertext, cleartext, len, &decks, iv,
++                          (cbc128_f) AES_cbc_encrypt);
++    if (memcmp(cleartext, test_input, len))
++        fprintf(stderr, "input_%d mismatch\n", len), exit(4);
++    if (memcmp(iv, vector + len - tail, sizeof(iv)))
++        fprintf(stderr, "iv_%d mismatch\n", len), exit(4);
++}
++
++void test_nistvector(const unsigned char *vector, size_t len)
++{
++    unsigned char iv[sizeof(test_iv)];
++    unsigned char cleartext[64], ciphertext[64], nistvector[64];
++    size_t tail;
++
++    printf("nistvector_%d\n", len);
++    fflush(stdout);
++
++    if ((tail = len % 16) == 0)
++        tail = 16;
++
++    len -= 16 + tail;
++    memcpy(nistvector, vector, len);
++    /* flip two last blocks */
++    memcpy(nistvector + len, vector + len + 16, tail);
++    memcpy(nistvector + len + tail, vector + len, 16);
++    len += 16 + tail;
++    tail = 16;
++
++    /* test block-based encryption */
++    memcpy(iv, test_iv, sizeof(test_iv));
++    CRYPTO_nistcts128_encrypt_block(test_input, ciphertext, len, &encks, iv,
++                                    (block128_f) AES_encrypt);
++    if (memcmp(ciphertext, nistvector, len))
++        fprintf(stderr, "output_%d mismatch\n", len), exit(1);
++    if (memcmp(iv, nistvector + len - tail, sizeof(iv)))
++        fprintf(stderr, "iv_%d mismatch\n", len), exit(1);
++
++    /* test block-based decryption */
++    memcpy(iv, test_iv, sizeof(test_iv));
++    CRYPTO_nistcts128_decrypt_block(ciphertext, cleartext, len, &decks, iv,
++                                    (block128_f) AES_decrypt);
++    if (memcmp(cleartext, test_input, len))
++        fprintf(stderr, "input_%d mismatch\n", len), exit(2);
++    if (memcmp(iv, nistvector + len - tail, sizeof(iv)))
++        fprintf(stderr, "iv_%d mismatch\n", len), exit(2);
++
++    /* test streamed encryption */
++    memcpy(iv, test_iv, sizeof(test_iv));
++    CRYPTO_nistcts128_encrypt(test_input, ciphertext, len, &encks, iv,
++                              (cbc128_f) AES_cbc_encrypt);
++    if (memcmp(ciphertext, nistvector, len))
++        fprintf(stderr, "output_%d mismatch\n", len), exit(3);
++    if (memcmp(iv, nistvector + len - tail, sizeof(iv)))
++        fprintf(stderr, "iv_%d mismatch\n", len), exit(3);
++
++    /* test streamed decryption */
++    memcpy(iv, test_iv, sizeof(test_iv));
++    CRYPTO_nistcts128_decrypt(ciphertext, cleartext, len, &decks, iv,
++                              (cbc128_f) AES_cbc_encrypt);
++    if (memcmp(cleartext, test_input, len))
++        fprintf(stderr, "input_%d mismatch\n", len), exit(4);
++    if (memcmp(iv, nistvector + len - tail, sizeof(iv)))
++        fprintf(stderr, "iv_%d mismatch\n", len), exit(4);
++}
++
++int main()
++{
++    AES_set_encrypt_key(test_key, 128, &encks);
++    AES_set_decrypt_key(test_key, 128, &decks);
++
++    test_vector(vector_17, sizeof(vector_17));
++    test_vector(vector_31, sizeof(vector_31));
++    test_vector(vector_32, sizeof(vector_32));
++    test_vector(vector_47, sizeof(vector_47));
++    test_vector(vector_48, sizeof(vector_48));
++    test_vector(vector_64, sizeof(vector_64));
++
++    test_nistvector(vector_17, sizeof(vector_17));
++    test_nistvector(vector_31, sizeof(vector_31));
++    test_nistvector(vector_32, sizeof(vector_32));
++    test_nistvector(vector_47, sizeof(vector_47));
++    test_nistvector(vector_48, sizeof(vector_48));
++    test_nistvector(vector_64, sizeof(vector_64));
++
++    return 0;
++}
++#endif
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/modes/gcm128.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/modes/gcm128.c
+new file mode 100644
+index 0000000..df9f654
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/modes/gcm128.c
+@@ -0,0 +1,2302 @@
++/*
++ * Copyright 2010-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include "modes_lcl.h"
++#include 
++
++#if defined(BSWAP4) && defined(STRICT_ALIGNMENT)
++/* redefine, because alignment is ensured */
++# undef  GETU32
++# define GETU32(p)       BSWAP4(*(const u32 *)(p))
++# undef  PUTU32
++# define PUTU32(p,v)     *(u32 *)(p) = BSWAP4(v)
++#endif
++
++#define PACK(s)         ((size_t)(s)<<(sizeof(size_t)*8-16))
++#define REDUCE1BIT(V)   do { \
++        if (sizeof(size_t)==8) { \
++                u64 T = U64(0xe100000000000000) & (0-(V.lo&1)); \
++                V.lo  = (V.hi<<63)|(V.lo>>1); \
++                V.hi  = (V.hi>>1 )^T; \
++        } \
++        else { \
++                u32 T = 0xe1000000U & (0-(u32)(V.lo&1)); \
++                V.lo  = (V.hi<<63)|(V.lo>>1); \
++                V.hi  = (V.hi>>1 )^((u64)T<<32); \
++        } \
++} while(0)
++
++/*-
++ * Even though permitted values for TABLE_BITS are 8, 4 and 1, it should
++ * never be set to 8. 8 is effectively reserved for testing purposes.
++ * TABLE_BITS>1 are lookup-table-driven implementations referred to as
++ * "Shoup's" in GCM specification. In other words OpenSSL does not cover
++ * whole spectrum of possible table driven implementations. Why? In
++ * non-"Shoup's" case memory access pattern is segmented in such manner,
++ * that it's trivial to see that cache timing information can reveal
++ * fair portion of intermediate hash value. Given that ciphertext is
++ * always available to attacker, it's possible for him to attempt to
++ * deduce secret parameter H and if successful, tamper with messages
++ * [which is nothing but trivial in CTR mode]. In "Shoup's" case it's
++ * not as trivial, but there is no reason to believe that it's resistant
++ * to cache-timing attack. And the thing about "8-bit" implementation is
++ * that it consumes 16 (sixteen) times more memory, 4KB per individual
++ * key + 1KB shared. Well, on pros side it should be twice as fast as
++ * "4-bit" version. And for gcc-generated x86[_64] code, "8-bit" version
++ * was observed to run ~75% faster, closer to 100% for commercial
++ * compilers... Yet "4-bit" procedure is preferred, because it's
++ * believed to provide better security-performance balance and adequate
++ * all-round performance. "All-round" refers to things like:
++ *
++ * - shorter setup time effectively improves overall timing for
++ *   handling short messages;
++ * - larger table allocation can become unbearable because of VM
++ *   subsystem penalties (for example on Windows large enough free
++ *   results in VM working set trimming, meaning that consequent
++ *   malloc would immediately incur working set expansion);
++ * - larger table has larger cache footprint, which can affect
++ *   performance of other code paths (not necessarily even from same
++ *   thread in Hyper-Threading world);
++ *
++ * Value of 1 is not appropriate for performance reasons.
++ */
++#if     TABLE_BITS==8
++
++static void gcm_init_8bit(u128 Htable[256], u64 H[2])
++{
++    int i, j;
++    u128 V;
++
++    Htable[0].hi = 0;
++    Htable[0].lo = 0;
++    V.hi = H[0];
++    V.lo = H[1];
++
++    for (Htable[128] = V, i = 64; i > 0; i >>= 1) {
++        REDUCE1BIT(V);
++        Htable[i] = V;
++    }
++
++    for (i = 2; i < 256; i <<= 1) {
++        u128 *Hi = Htable + i, H0 = *Hi;
++        for (j = 1; j < i; ++j) {
++            Hi[j].hi = H0.hi ^ Htable[j].hi;
++            Hi[j].lo = H0.lo ^ Htable[j].lo;
++        }
++    }
++}
++
++static void gcm_gmult_8bit(u64 Xi[2], const u128 Htable[256])
++{
++    u128 Z = { 0, 0 };
++    const u8 *xi = (const u8 *)Xi + 15;
++    size_t rem, n = *xi;
++    const union {
++        long one;
++        char little;
++    } is_endian = { 1 };
++    static const size_t rem_8bit[256] = {
++        PACK(0x0000), PACK(0x01C2), PACK(0x0384), PACK(0x0246),
++        PACK(0x0708), PACK(0x06CA), PACK(0x048C), PACK(0x054E),
++        PACK(0x0E10), PACK(0x0FD2), PACK(0x0D94), PACK(0x0C56),
++        PACK(0x0918), PACK(0x08DA), PACK(0x0A9C), PACK(0x0B5E),
++        PACK(0x1C20), PACK(0x1DE2), PACK(0x1FA4), PACK(0x1E66),
++        PACK(0x1B28), PACK(0x1AEA), PACK(0x18AC), PACK(0x196E),
++        PACK(0x1230), PACK(0x13F2), PACK(0x11B4), PACK(0x1076),
++        PACK(0x1538), PACK(0x14FA), PACK(0x16BC), PACK(0x177E),
++        PACK(0x3840), PACK(0x3982), PACK(0x3BC4), PACK(0x3A06),
++        PACK(0x3F48), PACK(0x3E8A), PACK(0x3CCC), PACK(0x3D0E),
++        PACK(0x3650), PACK(0x3792), PACK(0x35D4), PACK(0x3416),
++        PACK(0x3158), PACK(0x309A), PACK(0x32DC), PACK(0x331E),
++        PACK(0x2460), PACK(0x25A2), PACK(0x27E4), PACK(0x2626),
++        PACK(0x2368), PACK(0x22AA), PACK(0x20EC), PACK(0x212E),
++        PACK(0x2A70), PACK(0x2BB2), PACK(0x29F4), PACK(0x2836),
++        PACK(0x2D78), PACK(0x2CBA), PACK(0x2EFC), PACK(0x2F3E),
++        PACK(0x7080), PACK(0x7142), PACK(0x7304), PACK(0x72C6),
++        PACK(0x7788), PACK(0x764A), PACK(0x740C), PACK(0x75CE),
++        PACK(0x7E90), PACK(0x7F52), PACK(0x7D14), PACK(0x7CD6),
++        PACK(0x7998), PACK(0x785A), PACK(0x7A1C), PACK(0x7BDE),
++        PACK(0x6CA0), PACK(0x6D62), PACK(0x6F24), PACK(0x6EE6),
++        PACK(0x6BA8), PACK(0x6A6A), PACK(0x682C), PACK(0x69EE),
++        PACK(0x62B0), PACK(0x6372), PACK(0x6134), PACK(0x60F6),
++        PACK(0x65B8), PACK(0x647A), PACK(0x663C), PACK(0x67FE),
++        PACK(0x48C0), PACK(0x4902), PACK(0x4B44), PACK(0x4A86),
++        PACK(0x4FC8), PACK(0x4E0A), PACK(0x4C4C), PACK(0x4D8E),
++        PACK(0x46D0), PACK(0x4712), PACK(0x4554), PACK(0x4496),
++        PACK(0x41D8), PACK(0x401A), PACK(0x425C), PACK(0x439E),
++        PACK(0x54E0), PACK(0x5522), PACK(0x5764), PACK(0x56A6),
++        PACK(0x53E8), PACK(0x522A), PACK(0x506C), PACK(0x51AE),
++        PACK(0x5AF0), PACK(0x5B32), PACK(0x5974), PACK(0x58B6),
++        PACK(0x5DF8), PACK(0x5C3A), PACK(0x5E7C), PACK(0x5FBE),
++        PACK(0xE100), PACK(0xE0C2), PACK(0xE284), PACK(0xE346),
++        PACK(0xE608), PACK(0xE7CA), PACK(0xE58C), PACK(0xE44E),
++        PACK(0xEF10), PACK(0xEED2), PACK(0xEC94), PACK(0xED56),
++        PACK(0xE818), PACK(0xE9DA), PACK(0xEB9C), PACK(0xEA5E),
++        PACK(0xFD20), PACK(0xFCE2), PACK(0xFEA4), PACK(0xFF66),
++        PACK(0xFA28), PACK(0xFBEA), PACK(0xF9AC), PACK(0xF86E),
++        PACK(0xF330), PACK(0xF2F2), PACK(0xF0B4), PACK(0xF176),
++        PACK(0xF438), PACK(0xF5FA), PACK(0xF7BC), PACK(0xF67E),
++        PACK(0xD940), PACK(0xD882), PACK(0xDAC4), PACK(0xDB06),
++        PACK(0xDE48), PACK(0xDF8A), PACK(0xDDCC), PACK(0xDC0E),
++        PACK(0xD750), PACK(0xD692), PACK(0xD4D4), PACK(0xD516),
++        PACK(0xD058), PACK(0xD19A), PACK(0xD3DC), PACK(0xD21E),
++        PACK(0xC560), PACK(0xC4A2), PACK(0xC6E4), PACK(0xC726),
++        PACK(0xC268), PACK(0xC3AA), PACK(0xC1EC), PACK(0xC02E),
++        PACK(0xCB70), PACK(0xCAB2), PACK(0xC8F4), PACK(0xC936),
++        PACK(0xCC78), PACK(0xCDBA), PACK(0xCFFC), PACK(0xCE3E),
++        PACK(0x9180), PACK(0x9042), PACK(0x9204), PACK(0x93C6),
++        PACK(0x9688), PACK(0x974A), PACK(0x950C), PACK(0x94CE),
++        PACK(0x9F90), PACK(0x9E52), PACK(0x9C14), PACK(0x9DD6),
++        PACK(0x9898), PACK(0x995A), PACK(0x9B1C), PACK(0x9ADE),
++        PACK(0x8DA0), PACK(0x8C62), PACK(0x8E24), PACK(0x8FE6),
++        PACK(0x8AA8), PACK(0x8B6A), PACK(0x892C), PACK(0x88EE),
++        PACK(0x83B0), PACK(0x8272), PACK(0x8034), PACK(0x81F6),
++        PACK(0x84B8), PACK(0x857A), PACK(0x873C), PACK(0x86FE),
++        PACK(0xA9C0), PACK(0xA802), PACK(0xAA44), PACK(0xAB86),
++        PACK(0xAEC8), PACK(0xAF0A), PACK(0xAD4C), PACK(0xAC8E),
++        PACK(0xA7D0), PACK(0xA612), PACK(0xA454), PACK(0xA596),
++        PACK(0xA0D8), PACK(0xA11A), PACK(0xA35C), PACK(0xA29E),
++        PACK(0xB5E0), PACK(0xB422), PACK(0xB664), PACK(0xB7A6),
++        PACK(0xB2E8), PACK(0xB32A), PACK(0xB16C), PACK(0xB0AE),
++        PACK(0xBBF0), PACK(0xBA32), PACK(0xB874), PACK(0xB9B6),
++        PACK(0xBCF8), PACK(0xBD3A), PACK(0xBF7C), PACK(0xBEBE)
++    };
++
++    while (1) {
++        Z.hi ^= Htable[n].hi;
++        Z.lo ^= Htable[n].lo;
++
++        if ((u8 *)Xi == xi)
++            break;
++
++        n = *(--xi);
++
++        rem = (size_t)Z.lo & 0xff;
++        Z.lo = (Z.hi << 56) | (Z.lo >> 8);
++        Z.hi = (Z.hi >> 8);
++        if (sizeof(size_t) == 8)
++            Z.hi ^= rem_8bit[rem];
++        else
++            Z.hi ^= (u64)rem_8bit[rem] << 32;
++    }
++
++    if (is_endian.little) {
++# ifdef BSWAP8
++        Xi[0] = BSWAP8(Z.hi);
++        Xi[1] = BSWAP8(Z.lo);
++# else
++        u8 *p = (u8 *)Xi;
++        u32 v;
++        v = (u32)(Z.hi >> 32);
++        PUTU32(p, v);
++        v = (u32)(Z.hi);
++        PUTU32(p + 4, v);
++        v = (u32)(Z.lo >> 32);
++        PUTU32(p + 8, v);
++        v = (u32)(Z.lo);
++        PUTU32(p + 12, v);
++# endif
++    } else {
++        Xi[0] = Z.hi;
++        Xi[1] = Z.lo;
++    }
++}
++
++# define GCM_MUL(ctx,Xi)   gcm_gmult_8bit(ctx->Xi.u,ctx->Htable)
++
++#elif   TABLE_BITS==4
++
++static void gcm_init_4bit(u128 Htable[16], u64 H[2])
++{
++    u128 V;
++# if defined(OPENSSL_SMALL_FOOTPRINT)
++    int i;
++# endif
++
++    Htable[0].hi = 0;
++    Htable[0].lo = 0;
++    V.hi = H[0];
++    V.lo = H[1];
++
++# if defined(OPENSSL_SMALL_FOOTPRINT)
++    for (Htable[8] = V, i = 4; i > 0; i >>= 1) {
++        REDUCE1BIT(V);
++        Htable[i] = V;
++    }
++
++    for (i = 2; i < 16; i <<= 1) {
++        u128 *Hi = Htable + i;
++        int j;
++        for (V = *Hi, j = 1; j < i; ++j) {
++            Hi[j].hi = V.hi ^ Htable[j].hi;
++            Hi[j].lo = V.lo ^ Htable[j].lo;
++        }
++    }
++# else
++    Htable[8] = V;
++    REDUCE1BIT(V);
++    Htable[4] = V;
++    REDUCE1BIT(V);
++    Htable[2] = V;
++    REDUCE1BIT(V);
++    Htable[1] = V;
++    Htable[3].hi = V.hi ^ Htable[2].hi, Htable[3].lo = V.lo ^ Htable[2].lo;
++    V = Htable[4];
++    Htable[5].hi = V.hi ^ Htable[1].hi, Htable[5].lo = V.lo ^ Htable[1].lo;
++    Htable[6].hi = V.hi ^ Htable[2].hi, Htable[6].lo = V.lo ^ Htable[2].lo;
++    Htable[7].hi = V.hi ^ Htable[3].hi, Htable[7].lo = V.lo ^ Htable[3].lo;
++    V = Htable[8];
++    Htable[9].hi = V.hi ^ Htable[1].hi, Htable[9].lo = V.lo ^ Htable[1].lo;
++    Htable[10].hi = V.hi ^ Htable[2].hi, Htable[10].lo = V.lo ^ Htable[2].lo;
++    Htable[11].hi = V.hi ^ Htable[3].hi, Htable[11].lo = V.lo ^ Htable[3].lo;
++    Htable[12].hi = V.hi ^ Htable[4].hi, Htable[12].lo = V.lo ^ Htable[4].lo;
++    Htable[13].hi = V.hi ^ Htable[5].hi, Htable[13].lo = V.lo ^ Htable[5].lo;
++    Htable[14].hi = V.hi ^ Htable[6].hi, Htable[14].lo = V.lo ^ Htable[6].lo;
++    Htable[15].hi = V.hi ^ Htable[7].hi, Htable[15].lo = V.lo ^ Htable[7].lo;
++# endif
++# if defined(GHASH_ASM) && (defined(__arm__) || defined(__arm))
++    /*
++     * ARM assembler expects specific dword order in Htable.
++     */
++    {
++        int j;
++        const union {
++            long one;
++            char little;
++        } is_endian = { 1 };
++
++        if (is_endian.little)
++            for (j = 0; j < 16; ++j) {
++                V = Htable[j];
++                Htable[j].hi = V.lo;
++                Htable[j].lo = V.hi;
++        } else
++            for (j = 0; j < 16; ++j) {
++                V = Htable[j];
++                Htable[j].hi = V.lo << 32 | V.lo >> 32;
++                Htable[j].lo = V.hi << 32 | V.hi >> 32;
++            }
++    }
++# endif
++}
++
++# ifndef GHASH_ASM
++static const size_t rem_4bit[16] = {
++    PACK(0x0000), PACK(0x1C20), PACK(0x3840), PACK(0x2460),
++    PACK(0x7080), PACK(0x6CA0), PACK(0x48C0), PACK(0x54E0),
++    PACK(0xE100), PACK(0xFD20), PACK(0xD940), PACK(0xC560),
++    PACK(0x9180), PACK(0x8DA0), PACK(0xA9C0), PACK(0xB5E0)
++};
++
++static void gcm_gmult_4bit(u64 Xi[2], const u128 Htable[16])
++{
++    u128 Z;
++    int cnt = 15;
++    size_t rem, nlo, nhi;
++    const union {
++        long one;
++        char little;
++    } is_endian = { 1 };
++
++    nlo = ((const u8 *)Xi)[15];
++    nhi = nlo >> 4;
++    nlo &= 0xf;
++
++    Z.hi = Htable[nlo].hi;
++    Z.lo = Htable[nlo].lo;
++
++    while (1) {
++        rem = (size_t)Z.lo & 0xf;
++        Z.lo = (Z.hi << 60) | (Z.lo >> 4);
++        Z.hi = (Z.hi >> 4);
++        if (sizeof(size_t) == 8)
++            Z.hi ^= rem_4bit[rem];
++        else
++            Z.hi ^= (u64)rem_4bit[rem] << 32;
++
++        Z.hi ^= Htable[nhi].hi;
++        Z.lo ^= Htable[nhi].lo;
++
++        if (--cnt < 0)
++            break;
++
++        nlo = ((const u8 *)Xi)[cnt];
++        nhi = nlo >> 4;
++        nlo &= 0xf;
++
++        rem = (size_t)Z.lo & 0xf;
++        Z.lo = (Z.hi << 60) | (Z.lo >> 4);
++        Z.hi = (Z.hi >> 4);
++        if (sizeof(size_t) == 8)
++            Z.hi ^= rem_4bit[rem];
++        else
++            Z.hi ^= (u64)rem_4bit[rem] << 32;
++
++        Z.hi ^= Htable[nlo].hi;
++        Z.lo ^= Htable[nlo].lo;
++    }
++
++    if (is_endian.little) {
++#  ifdef BSWAP8
++        Xi[0] = BSWAP8(Z.hi);
++        Xi[1] = BSWAP8(Z.lo);
++#  else
++        u8 *p = (u8 *)Xi;
++        u32 v;
++        v = (u32)(Z.hi >> 32);
++        PUTU32(p, v);
++        v = (u32)(Z.hi);
++        PUTU32(p + 4, v);
++        v = (u32)(Z.lo >> 32);
++        PUTU32(p + 8, v);
++        v = (u32)(Z.lo);
++        PUTU32(p + 12, v);
++#  endif
++    } else {
++        Xi[0] = Z.hi;
++        Xi[1] = Z.lo;
++    }
++}
++
++#  if !defined(OPENSSL_SMALL_FOOTPRINT)
++/*
++ * Streamed gcm_mult_4bit, see CRYPTO_gcm128_[en|de]crypt for
++ * details... Compiler-generated code doesn't seem to give any
++ * performance improvement, at least not on x86[_64]. It's here
++ * mostly as reference and a placeholder for possible future
++ * non-trivial optimization[s]...
++ */
++static void gcm_ghash_4bit(u64 Xi[2], const u128 Htable[16],
++                           const u8 *inp, size_t len)
++{
++    u128 Z;
++    int cnt;
++    size_t rem, nlo, nhi;
++    const union {
++        long one;
++        char little;
++    } is_endian = { 1 };
++
++#   if 1
++    do {
++        cnt = 15;
++        nlo = ((const u8 *)Xi)[15];
++        nlo ^= inp[15];
++        nhi = nlo >> 4;
++        nlo &= 0xf;
++
++        Z.hi = Htable[nlo].hi;
++        Z.lo = Htable[nlo].lo;
++
++        while (1) {
++            rem = (size_t)Z.lo & 0xf;
++            Z.lo = (Z.hi << 60) | (Z.lo >> 4);
++            Z.hi = (Z.hi >> 4);
++            if (sizeof(size_t) == 8)
++                Z.hi ^= rem_4bit[rem];
++            else
++                Z.hi ^= (u64)rem_4bit[rem] << 32;
++
++            Z.hi ^= Htable[nhi].hi;
++            Z.lo ^= Htable[nhi].lo;
++
++            if (--cnt < 0)
++                break;
++
++            nlo = ((const u8 *)Xi)[cnt];
++            nlo ^= inp[cnt];
++            nhi = nlo >> 4;
++            nlo &= 0xf;
++
++            rem = (size_t)Z.lo & 0xf;
++            Z.lo = (Z.hi << 60) | (Z.lo >> 4);
++            Z.hi = (Z.hi >> 4);
++            if (sizeof(size_t) == 8)
++                Z.hi ^= rem_4bit[rem];
++            else
++                Z.hi ^= (u64)rem_4bit[rem] << 32;
++
++            Z.hi ^= Htable[nlo].hi;
++            Z.lo ^= Htable[nlo].lo;
++        }
++#   else
++    /*
++     * Extra 256+16 bytes per-key plus 512 bytes shared tables
++     * [should] give ~50% improvement... One could have PACK()-ed
++     * the rem_8bit even here, but the priority is to minimize
++     * cache footprint...
++     */
++    u128 Hshr4[16];             /* Htable shifted right by 4 bits */
++    u8 Hshl4[16];               /* Htable shifted left by 4 bits */
++    static const unsigned short rem_8bit[256] = {
++        0x0000, 0x01C2, 0x0384, 0x0246, 0x0708, 0x06CA, 0x048C, 0x054E,
++        0x0E10, 0x0FD2, 0x0D94, 0x0C56, 0x0918, 0x08DA, 0x0A9C, 0x0B5E,
++        0x1C20, 0x1DE2, 0x1FA4, 0x1E66, 0x1B28, 0x1AEA, 0x18AC, 0x196E,
++        0x1230, 0x13F2, 0x11B4, 0x1076, 0x1538, 0x14FA, 0x16BC, 0x177E,
++        0x3840, 0x3982, 0x3BC4, 0x3A06, 0x3F48, 0x3E8A, 0x3CCC, 0x3D0E,
++        0x3650, 0x3792, 0x35D4, 0x3416, 0x3158, 0x309A, 0x32DC, 0x331E,
++        0x2460, 0x25A2, 0x27E4, 0x2626, 0x2368, 0x22AA, 0x20EC, 0x212E,
++        0x2A70, 0x2BB2, 0x29F4, 0x2836, 0x2D78, 0x2CBA, 0x2EFC, 0x2F3E,
++        0x7080, 0x7142, 0x7304, 0x72C6, 0x7788, 0x764A, 0x740C, 0x75CE,
++        0x7E90, 0x7F52, 0x7D14, 0x7CD6, 0x7998, 0x785A, 0x7A1C, 0x7BDE,
++        0x6CA0, 0x6D62, 0x6F24, 0x6EE6, 0x6BA8, 0x6A6A, 0x682C, 0x69EE,
++        0x62B0, 0x6372, 0x6134, 0x60F6, 0x65B8, 0x647A, 0x663C, 0x67FE,
++        0x48C0, 0x4902, 0x4B44, 0x4A86, 0x4FC8, 0x4E0A, 0x4C4C, 0x4D8E,
++        0x46D0, 0x4712, 0x4554, 0x4496, 0x41D8, 0x401A, 0x425C, 0x439E,
++        0x54E0, 0x5522, 0x5764, 0x56A6, 0x53E8, 0x522A, 0x506C, 0x51AE,
++        0x5AF0, 0x5B32, 0x5974, 0x58B6, 0x5DF8, 0x5C3A, 0x5E7C, 0x5FBE,
++        0xE100, 0xE0C2, 0xE284, 0xE346, 0xE608, 0xE7CA, 0xE58C, 0xE44E,
++        0xEF10, 0xEED2, 0xEC94, 0xED56, 0xE818, 0xE9DA, 0xEB9C, 0xEA5E,
++        0xFD20, 0xFCE2, 0xFEA4, 0xFF66, 0xFA28, 0xFBEA, 0xF9AC, 0xF86E,
++        0xF330, 0xF2F2, 0xF0B4, 0xF176, 0xF438, 0xF5FA, 0xF7BC, 0xF67E,
++        0xD940, 0xD882, 0xDAC4, 0xDB06, 0xDE48, 0xDF8A, 0xDDCC, 0xDC0E,
++        0xD750, 0xD692, 0xD4D4, 0xD516, 0xD058, 0xD19A, 0xD3DC, 0xD21E,
++        0xC560, 0xC4A2, 0xC6E4, 0xC726, 0xC268, 0xC3AA, 0xC1EC, 0xC02E,
++        0xCB70, 0xCAB2, 0xC8F4, 0xC936, 0xCC78, 0xCDBA, 0xCFFC, 0xCE3E,
++        0x9180, 0x9042, 0x9204, 0x93C6, 0x9688, 0x974A, 0x950C, 0x94CE,
++        0x9F90, 0x9E52, 0x9C14, 0x9DD6, 0x9898, 0x995A, 0x9B1C, 0x9ADE,
++        0x8DA0, 0x8C62, 0x8E24, 0x8FE6, 0x8AA8, 0x8B6A, 0x892C, 0x88EE,
++        0x83B0, 0x8272, 0x8034, 0x81F6, 0x84B8, 0x857A, 0x873C, 0x86FE,
++        0xA9C0, 0xA802, 0xAA44, 0xAB86, 0xAEC8, 0xAF0A, 0xAD4C, 0xAC8E,
++        0xA7D0, 0xA612, 0xA454, 0xA596, 0xA0D8, 0xA11A, 0xA35C, 0xA29E,
++        0xB5E0, 0xB422, 0xB664, 0xB7A6, 0xB2E8, 0xB32A, 0xB16C, 0xB0AE,
++        0xBBF0, 0xBA32, 0xB874, 0xB9B6, 0xBCF8, 0xBD3A, 0xBF7C, 0xBEBE
++    };
++    /*
++     * This pre-processing phase slows down procedure by approximately
++     * same time as it makes each loop spin faster. In other words
++     * single block performance is approximately same as straightforward
++     * "4-bit" implementation, and then it goes only faster...
++     */
++    for (cnt = 0; cnt < 16; ++cnt) {
++        Z.hi = Htable[cnt].hi;
++        Z.lo = Htable[cnt].lo;
++        Hshr4[cnt].lo = (Z.hi << 60) | (Z.lo >> 4);
++        Hshr4[cnt].hi = (Z.hi >> 4);
++        Hshl4[cnt] = (u8)(Z.lo << 4);
++    }
++
++    do {
++        for (Z.lo = 0, Z.hi = 0, cnt = 15; cnt; --cnt) {
++            nlo = ((const u8 *)Xi)[cnt];
++            nlo ^= inp[cnt];
++            nhi = nlo >> 4;
++            nlo &= 0xf;
++
++            Z.hi ^= Htable[nlo].hi;
++            Z.lo ^= Htable[nlo].lo;
++
++            rem = (size_t)Z.lo & 0xff;
++
++            Z.lo = (Z.hi << 56) | (Z.lo >> 8);
++            Z.hi = (Z.hi >> 8);
++
++            Z.hi ^= Hshr4[nhi].hi;
++            Z.lo ^= Hshr4[nhi].lo;
++            Z.hi ^= (u64)rem_8bit[rem ^ Hshl4[nhi]] << 48;
++        }
++
++        nlo = ((const u8 *)Xi)[0];
++        nlo ^= inp[0];
++        nhi = nlo >> 4;
++        nlo &= 0xf;
++
++        Z.hi ^= Htable[nlo].hi;
++        Z.lo ^= Htable[nlo].lo;
++
++        rem = (size_t)Z.lo & 0xf;
++
++        Z.lo = (Z.hi << 60) | (Z.lo >> 4);
++        Z.hi = (Z.hi >> 4);
++
++        Z.hi ^= Htable[nhi].hi;
++        Z.lo ^= Htable[nhi].lo;
++        Z.hi ^= ((u64)rem_8bit[rem << 4]) << 48;
++#   endif
++
++        if (is_endian.little) {
++#   ifdef BSWAP8
++            Xi[0] = BSWAP8(Z.hi);
++            Xi[1] = BSWAP8(Z.lo);
++#   else
++            u8 *p = (u8 *)Xi;
++            u32 v;
++            v = (u32)(Z.hi >> 32);
++            PUTU32(p, v);
++            v = (u32)(Z.hi);
++            PUTU32(p + 4, v);
++            v = (u32)(Z.lo >> 32);
++            PUTU32(p + 8, v);
++            v = (u32)(Z.lo);
++            PUTU32(p + 12, v);
++#   endif
++        } else {
++            Xi[0] = Z.hi;
++            Xi[1] = Z.lo;
++        }
++    } while (inp += 16, len -= 16);
++}
++#  endif
++# else
++void gcm_gmult_4bit(u64 Xi[2], const u128 Htable[16]);
++void gcm_ghash_4bit(u64 Xi[2], const u128 Htable[16], const u8 *inp,
++                    size_t len);
++# endif
++
++# define GCM_MUL(ctx,Xi)   gcm_gmult_4bit(ctx->Xi.u,ctx->Htable)
++# if defined(GHASH_ASM) || !defined(OPENSSL_SMALL_FOOTPRINT)
++#  define GHASH(ctx,in,len) gcm_ghash_4bit((ctx)->Xi.u,(ctx)->Htable,in,len)
++/*
++ * GHASH_CHUNK is "stride parameter" missioned to mitigate cache trashing
++ * effect. In other words idea is to hash data while it's still in L1 cache
++ * after encryption pass...
++ */
++#  define GHASH_CHUNK       (3*1024)
++# endif
++
++#else                           /* TABLE_BITS */
++
++static void gcm_gmult_1bit(u64 Xi[2], const u64 H[2])
++{
++    u128 V, Z = { 0, 0 };
++    long X;
++    int i, j;
++    const long *xi = (const long *)Xi;
++    const union {
++        long one;
++        char little;
++    } is_endian = { 1 };
++
++    V.hi = H[0];                /* H is in host byte order, no byte swapping */
++    V.lo = H[1];
++
++    for (j = 0; j < 16 / sizeof(long); ++j) {
++        if (is_endian.little) {
++            if (sizeof(long) == 8) {
++# ifdef BSWAP8
++                X = (long)(BSWAP8(xi[j]));
++# else
++                const u8 *p = (const u8 *)(xi + j);
++                X = (long)((u64)GETU32(p) << 32 | GETU32(p + 4));
++# endif
++            } else {
++                const u8 *p = (const u8 *)(xi + j);
++                X = (long)GETU32(p);
++            }
++        } else
++            X = xi[j];
++
++        for (i = 0; i < 8 * sizeof(long); ++i, X <<= 1) {
++            u64 M = (u64)(X >> (8 * sizeof(long) - 1));
++            Z.hi ^= V.hi & M;
++            Z.lo ^= V.lo & M;
++
++            REDUCE1BIT(V);
++        }
++    }
++
++    if (is_endian.little) {
++# ifdef BSWAP8
++        Xi[0] = BSWAP8(Z.hi);
++        Xi[1] = BSWAP8(Z.lo);
++# else
++        u8 *p = (u8 *)Xi;
++        u32 v;
++        v = (u32)(Z.hi >> 32);
++        PUTU32(p, v);
++        v = (u32)(Z.hi);
++        PUTU32(p + 4, v);
++        v = (u32)(Z.lo >> 32);
++        PUTU32(p + 8, v);
++        v = (u32)(Z.lo);
++        PUTU32(p + 12, v);
++# endif
++    } else {
++        Xi[0] = Z.hi;
++        Xi[1] = Z.lo;
++    }
++}
++
++# define GCM_MUL(ctx,Xi)   gcm_gmult_1bit(ctx->Xi.u,ctx->H.u)
++
++#endif
++
++#if     TABLE_BITS==4 && (defined(GHASH_ASM) || defined(OPENSSL_CPUID_OBJ))
++# if    !defined(I386_ONLY) && \
++        (defined(__i386)        || defined(__i386__)    || \
++         defined(__x86_64)      || defined(__x86_64__)  || \
++         defined(_M_IX86)       || defined(_M_AMD64)    || defined(_M_X64))
++#  define GHASH_ASM_X86_OR_64
++#  define GCM_FUNCREF_4BIT
++extern unsigned int OPENSSL_ia32cap_P[];
++
++void gcm_init_clmul(u128 Htable[16], const u64 Xi[2]);
++void gcm_gmult_clmul(u64 Xi[2], const u128 Htable[16]);
++void gcm_ghash_clmul(u64 Xi[2], const u128 Htable[16], const u8 *inp,
++                     size_t len);
++
++#  if defined(__i386) || defined(__i386__) || defined(_M_IX86)
++#   define gcm_init_avx   gcm_init_clmul
++#   define gcm_gmult_avx  gcm_gmult_clmul
++#   define gcm_ghash_avx  gcm_ghash_clmul
++#  else
++void gcm_init_avx(u128 Htable[16], const u64 Xi[2]);
++void gcm_gmult_avx(u64 Xi[2], const u128 Htable[16]);
++void gcm_ghash_avx(u64 Xi[2], const u128 Htable[16], const u8 *inp,
++                   size_t len);
++#  endif
++
++#  if   defined(__i386) || defined(__i386__) || defined(_M_IX86)
++#   define GHASH_ASM_X86
++void gcm_gmult_4bit_mmx(u64 Xi[2], const u128 Htable[16]);
++void gcm_ghash_4bit_mmx(u64 Xi[2], const u128 Htable[16], const u8 *inp,
++                        size_t len);
++
++void gcm_gmult_4bit_x86(u64 Xi[2], const u128 Htable[16]);
++void gcm_ghash_4bit_x86(u64 Xi[2], const u128 Htable[16], const u8 *inp,
++                        size_t len);
++#  endif
++# elif defined(__arm__) || defined(__arm) || defined(__aarch64__)
++#  include "arm_arch.h"
++#  if __ARM_MAX_ARCH__>=7
++#   define GHASH_ASM_ARM
++#   define GCM_FUNCREF_4BIT
++#   define PMULL_CAPABLE        (OPENSSL_armcap_P & ARMV8_PMULL)
++#   if defined(__arm__) || defined(__arm)
++#    define NEON_CAPABLE        (OPENSSL_armcap_P & ARMV7_NEON)
++#   endif
++void gcm_init_neon(u128 Htable[16], const u64 Xi[2]);
++void gcm_gmult_neon(u64 Xi[2], const u128 Htable[16]);
++void gcm_ghash_neon(u64 Xi[2], const u128 Htable[16], const u8 *inp,
++                    size_t len);
++void gcm_init_v8(u128 Htable[16], const u64 Xi[2]);
++void gcm_gmult_v8(u64 Xi[2], const u128 Htable[16]);
++void gcm_ghash_v8(u64 Xi[2], const u128 Htable[16], const u8 *inp,
++                  size_t len);
++#  endif
++# elif defined(__sparc__) || defined(__sparc)
++#  include "sparc_arch.h"
++#  define GHASH_ASM_SPARC
++#  define GCM_FUNCREF_4BIT
++extern unsigned int OPENSSL_sparcv9cap_P[];
++void gcm_init_vis3(u128 Htable[16], const u64 Xi[2]);
++void gcm_gmult_vis3(u64 Xi[2], const u128 Htable[16]);
++void gcm_ghash_vis3(u64 Xi[2], const u128 Htable[16], const u8 *inp,
++                    size_t len);
++# elif defined(OPENSSL_CPUID_OBJ) && (defined(__powerpc__) || defined(__ppc__) || defined(_ARCH_PPC))
++#  include "ppc_arch.h"
++#  define GHASH_ASM_PPC
++#  define GCM_FUNCREF_4BIT
++void gcm_init_p8(u128 Htable[16], const u64 Xi[2]);
++void gcm_gmult_p8(u64 Xi[2], const u128 Htable[16]);
++void gcm_ghash_p8(u64 Xi[2], const u128 Htable[16], const u8 *inp,
++                  size_t len);
++# endif
++#endif
++
++#ifdef GCM_FUNCREF_4BIT
++# undef  GCM_MUL
++# define GCM_MUL(ctx,Xi)        (*gcm_gmult_p)(ctx->Xi.u,ctx->Htable)
++# ifdef GHASH
++#  undef  GHASH
++#  define GHASH(ctx,in,len)     (*gcm_ghash_p)(ctx->Xi.u,ctx->Htable,in,len)
++# endif
++#endif
++
++void CRYPTO_gcm128_init(GCM128_CONTEXT *ctx, void *key, block128_f block)
++{
++    const union {
++        long one;
++        char little;
++    } is_endian = { 1 };
++
++    memset(ctx, 0, sizeof(*ctx));
++    ctx->block = block;
++    ctx->key = key;
++
++    (*block) (ctx->H.c, ctx->H.c, key);
++
++    if (is_endian.little) {
++        /* H is stored in host byte order */
++#ifdef BSWAP8
++        ctx->H.u[0] = BSWAP8(ctx->H.u[0]);
++        ctx->H.u[1] = BSWAP8(ctx->H.u[1]);
++#else
++        u8 *p = ctx->H.c;
++        u64 hi, lo;
++        hi = (u64)GETU32(p) << 32 | GETU32(p + 4);
++        lo = (u64)GETU32(p + 8) << 32 | GETU32(p + 12);
++        ctx->H.u[0] = hi;
++        ctx->H.u[1] = lo;
++#endif
++    }
++#if     TABLE_BITS==8
++    gcm_init_8bit(ctx->Htable, ctx->H.u);
++#elif   TABLE_BITS==4
++# if    defined(GHASH)
++#  define CTX__GHASH(f) (ctx->ghash = (f))
++# else
++#  define CTX__GHASH(f) (ctx->ghash = NULL)
++# endif
++# if    defined(GHASH_ASM_X86_OR_64)
++#  if   !defined(GHASH_ASM_X86) || defined(OPENSSL_IA32_SSE2)
++    if (OPENSSL_ia32cap_P[0] & (1 << 24) && /* check FXSR bit */
++        OPENSSL_ia32cap_P[1] & (1 << 1)) { /* check PCLMULQDQ bit */
++        if (((OPENSSL_ia32cap_P[1] >> 22) & 0x41) == 0x41) { /* AVX+MOVBE */
++            gcm_init_avx(ctx->Htable, ctx->H.u);
++            ctx->gmult = gcm_gmult_avx;
++            CTX__GHASH(gcm_ghash_avx);
++        } else {
++            gcm_init_clmul(ctx->Htable, ctx->H.u);
++            ctx->gmult = gcm_gmult_clmul;
++            CTX__GHASH(gcm_ghash_clmul);
++        }
++        return;
++    }
++#  endif
++    gcm_init_4bit(ctx->Htable, ctx->H.u);
++#  if   defined(GHASH_ASM_X86)  /* x86 only */
++#   if  defined(OPENSSL_IA32_SSE2)
++    if (OPENSSL_ia32cap_P[0] & (1 << 25)) { /* check SSE bit */
++#   else
++    if (OPENSSL_ia32cap_P[0] & (1 << 23)) { /* check MMX bit */
++#   endif
++        ctx->gmult = gcm_gmult_4bit_mmx;
++        CTX__GHASH(gcm_ghash_4bit_mmx);
++    } else {
++        ctx->gmult = gcm_gmult_4bit_x86;
++        CTX__GHASH(gcm_ghash_4bit_x86);
++    }
++#  else
++    ctx->gmult = gcm_gmult_4bit;
++    CTX__GHASH(gcm_ghash_4bit);
++#  endif
++# elif  defined(GHASH_ASM_ARM)
++#  ifdef PMULL_CAPABLE
++    if (PMULL_CAPABLE) {
++        gcm_init_v8(ctx->Htable, ctx->H.u);
++        ctx->gmult = gcm_gmult_v8;
++        CTX__GHASH(gcm_ghash_v8);
++    } else
++#  endif
++#  ifdef NEON_CAPABLE
++    if (NEON_CAPABLE) {
++        gcm_init_neon(ctx->Htable, ctx->H.u);
++        ctx->gmult = gcm_gmult_neon;
++        CTX__GHASH(gcm_ghash_neon);
++    } else
++#  endif
++    {
++        gcm_init_4bit(ctx->Htable, ctx->H.u);
++        ctx->gmult = gcm_gmult_4bit;
++        CTX__GHASH(gcm_ghash_4bit);
++    }
++# elif  defined(GHASH_ASM_SPARC)
++    if (OPENSSL_sparcv9cap_P[0] & SPARCV9_VIS3) {
++        gcm_init_vis3(ctx->Htable, ctx->H.u);
++        ctx->gmult = gcm_gmult_vis3;
++        CTX__GHASH(gcm_ghash_vis3);
++    } else {
++        gcm_init_4bit(ctx->Htable, ctx->H.u);
++        ctx->gmult = gcm_gmult_4bit;
++        CTX__GHASH(gcm_ghash_4bit);
++    }
++# elif  defined(GHASH_ASM_PPC)
++    if (OPENSSL_ppccap_P & PPC_CRYPTO207) {
++        gcm_init_p8(ctx->Htable, ctx->H.u);
++        ctx->gmult = gcm_gmult_p8;
++        CTX__GHASH(gcm_ghash_p8);
++    } else {
++        gcm_init_4bit(ctx->Htable, ctx->H.u);
++        ctx->gmult = gcm_gmult_4bit;
++        CTX__GHASH(gcm_ghash_4bit);
++    }
++# else
++    gcm_init_4bit(ctx->Htable, ctx->H.u);
++# endif
++# undef CTX__GHASH
++#endif
++}
++
++void CRYPTO_gcm128_setiv(GCM128_CONTEXT *ctx, const unsigned char *iv,
++                         size_t len)
++{
++    const union {
++        long one;
++        char little;
++    } is_endian = { 1 };
++    unsigned int ctr;
++#ifdef GCM_FUNCREF_4BIT
++    void (*gcm_gmult_p) (u64 Xi[2], const u128 Htable[16]) = ctx->gmult;
++#endif
++
++    ctx->Yi.u[0] = 0;
++    ctx->Yi.u[1] = 0;
++    ctx->Xi.u[0] = 0;
++    ctx->Xi.u[1] = 0;
++    ctx->len.u[0] = 0;          /* AAD length */
++    ctx->len.u[1] = 0;          /* message length */
++    ctx->ares = 0;
++    ctx->mres = 0;
++
++    if (len == 12) {
++        memcpy(ctx->Yi.c, iv, 12);
++        ctx->Yi.c[15] = 1;
++        ctr = 1;
++    } else {
++        size_t i;
++        u64 len0 = len;
++
++        while (len >= 16) {
++            for (i = 0; i < 16; ++i)
++                ctx->Yi.c[i] ^= iv[i];
++            GCM_MUL(ctx, Yi);
++            iv += 16;
++            len -= 16;
++        }
++        if (len) {
++            for (i = 0; i < len; ++i)
++                ctx->Yi.c[i] ^= iv[i];
++            GCM_MUL(ctx, Yi);
++        }
++        len0 <<= 3;
++        if (is_endian.little) {
++#ifdef BSWAP8
++            ctx->Yi.u[1] ^= BSWAP8(len0);
++#else
++            ctx->Yi.c[8] ^= (u8)(len0 >> 56);
++            ctx->Yi.c[9] ^= (u8)(len0 >> 48);
++            ctx->Yi.c[10] ^= (u8)(len0 >> 40);
++            ctx->Yi.c[11] ^= (u8)(len0 >> 32);
++            ctx->Yi.c[12] ^= (u8)(len0 >> 24);
++            ctx->Yi.c[13] ^= (u8)(len0 >> 16);
++            ctx->Yi.c[14] ^= (u8)(len0 >> 8);
++            ctx->Yi.c[15] ^= (u8)(len0);
++#endif
++        } else
++            ctx->Yi.u[1] ^= len0;
++
++        GCM_MUL(ctx, Yi);
++
++        if (is_endian.little)
++#ifdef BSWAP4
++            ctr = BSWAP4(ctx->Yi.d[3]);
++#else
++            ctr = GETU32(ctx->Yi.c + 12);
++#endif
++        else
++            ctr = ctx->Yi.d[3];
++    }
++
++    (*ctx->block) (ctx->Yi.c, ctx->EK0.c, ctx->key);
++    ++ctr;
++    if (is_endian.little)
++#ifdef BSWAP4
++        ctx->Yi.d[3] = BSWAP4(ctr);
++#else
++        PUTU32(ctx->Yi.c + 12, ctr);
++#endif
++    else
++        ctx->Yi.d[3] = ctr;
++}
++
++int CRYPTO_gcm128_aad(GCM128_CONTEXT *ctx, const unsigned char *aad,
++                      size_t len)
++{
++    size_t i;
++    unsigned int n;
++    u64 alen = ctx->len.u[0];
++#ifdef GCM_FUNCREF_4BIT
++    void (*gcm_gmult_p) (u64 Xi[2], const u128 Htable[16]) = ctx->gmult;
++# ifdef GHASH
++    void (*gcm_ghash_p) (u64 Xi[2], const u128 Htable[16],
++                         const u8 *inp, size_t len) = ctx->ghash;
++# endif
++#endif
++
++    if (ctx->len.u[1])
++        return -2;
++
++    alen += len;
++    if (alen > (U64(1) << 61) || (sizeof(len) == 8 && alen < len))
++        return -1;
++    ctx->len.u[0] = alen;
++
++    n = ctx->ares;
++    if (n) {
++        while (n && len) {
++            ctx->Xi.c[n] ^= *(aad++);
++            --len;
++            n = (n + 1) % 16;
++        }
++        if (n == 0)
++            GCM_MUL(ctx, Xi);
++        else {
++            ctx->ares = n;
++            return 0;
++        }
++    }
++#ifdef GHASH
++    if ((i = (len & (size_t)-16))) {
++        GHASH(ctx, aad, i);
++        aad += i;
++        len -= i;
++    }
++#else
++    while (len >= 16) {
++        for (i = 0; i < 16; ++i)
++            ctx->Xi.c[i] ^= aad[i];
++        GCM_MUL(ctx, Xi);
++        aad += 16;
++        len -= 16;
++    }
++#endif
++    if (len) {
++        n = (unsigned int)len;
++        for (i = 0; i < len; ++i)
++            ctx->Xi.c[i] ^= aad[i];
++    }
++
++    ctx->ares = n;
++    return 0;
++}
++
++int CRYPTO_gcm128_encrypt(GCM128_CONTEXT *ctx,
++                          const unsigned char *in, unsigned char *out,
++                          size_t len)
++{
++    const union {
++        long one;
++        char little;
++    } is_endian = { 1 };
++    unsigned int n, ctr;
++    size_t i;
++    u64 mlen = ctx->len.u[1];
++    block128_f block = ctx->block;
++    void *key = ctx->key;
++#ifdef GCM_FUNCREF_4BIT
++    void (*gcm_gmult_p) (u64 Xi[2], const u128 Htable[16]) = ctx->gmult;
++# if defined(GHASH) && !defined(OPENSSL_SMALL_FOOTPRINT)
++    void (*gcm_ghash_p) (u64 Xi[2], const u128 Htable[16],
++                         const u8 *inp, size_t len) = ctx->ghash;
++# endif
++#endif
++
++    mlen += len;
++    if (mlen > ((U64(1) << 36) - 32) || (sizeof(len) == 8 && mlen < len))
++        return -1;
++    ctx->len.u[1] = mlen;
++
++    if (ctx->ares) {
++        /* First call to encrypt finalizes GHASH(AAD) */
++        GCM_MUL(ctx, Xi);
++        ctx->ares = 0;
++    }
++
++    if (is_endian.little)
++#ifdef BSWAP4
++        ctr = BSWAP4(ctx->Yi.d[3]);
++#else
++        ctr = GETU32(ctx->Yi.c + 12);
++#endif
++    else
++        ctr = ctx->Yi.d[3];
++
++    n = ctx->mres;
++#if !defined(OPENSSL_SMALL_FOOTPRINT)
++    if (16 % sizeof(size_t) == 0) { /* always true actually */
++        do {
++            if (n) {
++                while (n && len) {
++                    ctx->Xi.c[n] ^= *(out++) = *(in++) ^ ctx->EKi.c[n];
++                    --len;
++                    n = (n + 1) % 16;
++                }
++                if (n == 0)
++                    GCM_MUL(ctx, Xi);
++                else {
++                    ctx->mres = n;
++                    return 0;
++                }
++            }
++# if defined(STRICT_ALIGNMENT)
++            if (((size_t)in | (size_t)out) % sizeof(size_t) != 0)
++                break;
++# endif
++# if defined(GHASH)
++#  if defined(GHASH_CHUNK)
++            while (len >= GHASH_CHUNK) {
++                size_t j = GHASH_CHUNK;
++
++                while (j) {
++                    size_t *out_t = (size_t *)out;
++                    const size_t *in_t = (const size_t *)in;
++
++                    (*block) (ctx->Yi.c, ctx->EKi.c, key);
++                    ++ctr;
++                    if (is_endian.little)
++#   ifdef BSWAP4
++                        ctx->Yi.d[3] = BSWAP4(ctr);
++#   else
++                        PUTU32(ctx->Yi.c + 12, ctr);
++#   endif
++                    else
++                        ctx->Yi.d[3] = ctr;
++                    for (i = 0; i < 16 / sizeof(size_t); ++i)
++                        out_t[i] = in_t[i] ^ ctx->EKi.t[i];
++                    out += 16;
++                    in += 16;
++                    j -= 16;
++                }
++                GHASH(ctx, out - GHASH_CHUNK, GHASH_CHUNK);
++                len -= GHASH_CHUNK;
++            }
++#  endif
++            if ((i = (len & (size_t)-16))) {
++                size_t j = i;
++
++                while (len >= 16) {
++                    size_t *out_t = (size_t *)out;
++                    const size_t *in_t = (const size_t *)in;
++
++                    (*block) (ctx->Yi.c, ctx->EKi.c, key);
++                    ++ctr;
++                    if (is_endian.little)
++#  ifdef BSWAP4
++                        ctx->Yi.d[3] = BSWAP4(ctr);
++#  else
++                        PUTU32(ctx->Yi.c + 12, ctr);
++#  endif
++                    else
++                        ctx->Yi.d[3] = ctr;
++                    for (i = 0; i < 16 / sizeof(size_t); ++i)
++                        out_t[i] = in_t[i] ^ ctx->EKi.t[i];
++                    out += 16;
++                    in += 16;
++                    len -= 16;
++                }
++                GHASH(ctx, out - j, j);
++            }
++# else
++            while (len >= 16) {
++                size_t *out_t = (size_t *)out;
++                const size_t *in_t = (const size_t *)in;
++
++                (*block) (ctx->Yi.c, ctx->EKi.c, key);
++                ++ctr;
++                if (is_endian.little)
++#  ifdef BSWAP4
++                    ctx->Yi.d[3] = BSWAP4(ctr);
++#  else
++                    PUTU32(ctx->Yi.c + 12, ctr);
++#  endif
++                else
++                    ctx->Yi.d[3] = ctr;
++                for (i = 0; i < 16 / sizeof(size_t); ++i)
++                    ctx->Xi.t[i] ^= out_t[i] = in_t[i] ^ ctx->EKi.t[i];
++                GCM_MUL(ctx, Xi);
++                out += 16;
++                in += 16;
++                len -= 16;
++            }
++# endif
++            if (len) {
++                (*block) (ctx->Yi.c, ctx->EKi.c, key);
++                ++ctr;
++                if (is_endian.little)
++# ifdef BSWAP4
++                    ctx->Yi.d[3] = BSWAP4(ctr);
++# else
++                    PUTU32(ctx->Yi.c + 12, ctr);
++# endif
++                else
++                    ctx->Yi.d[3] = ctr;
++                while (len--) {
++                    ctx->Xi.c[n] ^= out[n] = in[n] ^ ctx->EKi.c[n];
++                    ++n;
++                }
++            }
++
++            ctx->mres = n;
++            return 0;
++        } while (0);
++    }
++#endif
++    for (i = 0; i < len; ++i) {
++        if (n == 0) {
++            (*block) (ctx->Yi.c, ctx->EKi.c, key);
++            ++ctr;
++            if (is_endian.little)
++#ifdef BSWAP4
++                ctx->Yi.d[3] = BSWAP4(ctr);
++#else
++                PUTU32(ctx->Yi.c + 12, ctr);
++#endif
++            else
++                ctx->Yi.d[3] = ctr;
++        }
++        ctx->Xi.c[n] ^= out[i] = in[i] ^ ctx->EKi.c[n];
++        n = (n + 1) % 16;
++        if (n == 0)
++            GCM_MUL(ctx, Xi);
++    }
++
++    ctx->mres = n;
++    return 0;
++}
++
++int CRYPTO_gcm128_decrypt(GCM128_CONTEXT *ctx,
++                          const unsigned char *in, unsigned char *out,
++                          size_t len)
++{
++    const union {
++        long one;
++        char little;
++    } is_endian = { 1 };
++    unsigned int n, ctr;
++    size_t i;
++    u64 mlen = ctx->len.u[1];
++    block128_f block = ctx->block;
++    void *key = ctx->key;
++#ifdef GCM_FUNCREF_4BIT
++    void (*gcm_gmult_p) (u64 Xi[2], const u128 Htable[16]) = ctx->gmult;
++# if defined(GHASH) && !defined(OPENSSL_SMALL_FOOTPRINT)
++    void (*gcm_ghash_p) (u64 Xi[2], const u128 Htable[16],
++                         const u8 *inp, size_t len) = ctx->ghash;
++# endif
++#endif
++
++    mlen += len;
++    if (mlen > ((U64(1) << 36) - 32) || (sizeof(len) == 8 && mlen < len))
++        return -1;
++    ctx->len.u[1] = mlen;
++
++    if (ctx->ares) {
++        /* First call to decrypt finalizes GHASH(AAD) */
++        GCM_MUL(ctx, Xi);
++        ctx->ares = 0;
++    }
++
++    if (is_endian.little)
++#ifdef BSWAP4
++        ctr = BSWAP4(ctx->Yi.d[3]);
++#else
++        ctr = GETU32(ctx->Yi.c + 12);
++#endif
++    else
++        ctr = ctx->Yi.d[3];
++
++    n = ctx->mres;
++#if !defined(OPENSSL_SMALL_FOOTPRINT)
++    if (16 % sizeof(size_t) == 0) { /* always true actually */
++        do {
++            if (n) {
++                while (n && len) {
++                    u8 c = *(in++);
++                    *(out++) = c ^ ctx->EKi.c[n];
++                    ctx->Xi.c[n] ^= c;
++                    --len;
++                    n = (n + 1) % 16;
++                }
++                if (n == 0)
++                    GCM_MUL(ctx, Xi);
++                else {
++                    ctx->mres = n;
++                    return 0;
++                }
++            }
++# if defined(STRICT_ALIGNMENT)
++            if (((size_t)in | (size_t)out) % sizeof(size_t) != 0)
++                break;
++# endif
++# if defined(GHASH)
++#  if defined(GHASH_CHUNK)
++            while (len >= GHASH_CHUNK) {
++                size_t j = GHASH_CHUNK;
++
++                GHASH(ctx, in, GHASH_CHUNK);
++                while (j) {
++                    size_t *out_t = (size_t *)out;
++                    const size_t *in_t = (const size_t *)in;
++
++                    (*block) (ctx->Yi.c, ctx->EKi.c, key);
++                    ++ctr;
++                    if (is_endian.little)
++#   ifdef BSWAP4
++                        ctx->Yi.d[3] = BSWAP4(ctr);
++#   else
++                        PUTU32(ctx->Yi.c + 12, ctr);
++#   endif
++                    else
++                        ctx->Yi.d[3] = ctr;
++                    for (i = 0; i < 16 / sizeof(size_t); ++i)
++                        out_t[i] = in_t[i] ^ ctx->EKi.t[i];
++                    out += 16;
++                    in += 16;
++                    j -= 16;
++                }
++                len -= GHASH_CHUNK;
++            }
++#  endif
++            if ((i = (len & (size_t)-16))) {
++                GHASH(ctx, in, i);
++                while (len >= 16) {
++                    size_t *out_t = (size_t *)out;
++                    const size_t *in_t = (const size_t *)in;
++
++                    (*block) (ctx->Yi.c, ctx->EKi.c, key);
++                    ++ctr;
++                    if (is_endian.little)
++#  ifdef BSWAP4
++                        ctx->Yi.d[3] = BSWAP4(ctr);
++#  else
++                        PUTU32(ctx->Yi.c + 12, ctr);
++#  endif
++                    else
++                        ctx->Yi.d[3] = ctr;
++                    for (i = 0; i < 16 / sizeof(size_t); ++i)
++                        out_t[i] = in_t[i] ^ ctx->EKi.t[i];
++                    out += 16;
++                    in += 16;
++                    len -= 16;
++                }
++            }
++# else
++            while (len >= 16) {
++                size_t *out_t = (size_t *)out;
++                const size_t *in_t = (const size_t *)in;
++
++                (*block) (ctx->Yi.c, ctx->EKi.c, key);
++                ++ctr;
++                if (is_endian.little)
++#  ifdef BSWAP4
++                    ctx->Yi.d[3] = BSWAP4(ctr);
++#  else
++                    PUTU32(ctx->Yi.c + 12, ctr);
++#  endif
++                else
++                    ctx->Yi.d[3] = ctr;
++                for (i = 0; i < 16 / sizeof(size_t); ++i) {
++                    size_t c = in[i];
++                    out[i] = c ^ ctx->EKi.t[i];
++                    ctx->Xi.t[i] ^= c;
++                }
++                GCM_MUL(ctx, Xi);
++                out += 16;
++                in += 16;
++                len -= 16;
++            }
++# endif
++            if (len) {
++                (*block) (ctx->Yi.c, ctx->EKi.c, key);
++                ++ctr;
++                if (is_endian.little)
++# ifdef BSWAP4
++                    ctx->Yi.d[3] = BSWAP4(ctr);
++# else
++                    PUTU32(ctx->Yi.c + 12, ctr);
++# endif
++                else
++                    ctx->Yi.d[3] = ctr;
++                while (len--) {
++                    u8 c = in[n];
++                    ctx->Xi.c[n] ^= c;
++                    out[n] = c ^ ctx->EKi.c[n];
++                    ++n;
++                }
++            }
++
++            ctx->mres = n;
++            return 0;
++        } while (0);
++    }
++#endif
++    for (i = 0; i < len; ++i) {
++        u8 c;
++        if (n == 0) {
++            (*block) (ctx->Yi.c, ctx->EKi.c, key);
++            ++ctr;
++            if (is_endian.little)
++#ifdef BSWAP4
++                ctx->Yi.d[3] = BSWAP4(ctr);
++#else
++                PUTU32(ctx->Yi.c + 12, ctr);
++#endif
++            else
++                ctx->Yi.d[3] = ctr;
++        }
++        c = in[i];
++        out[i] = c ^ ctx->EKi.c[n];
++        ctx->Xi.c[n] ^= c;
++        n = (n + 1) % 16;
++        if (n == 0)
++            GCM_MUL(ctx, Xi);
++    }
++
++    ctx->mres = n;
++    return 0;
++}
++
++int CRYPTO_gcm128_encrypt_ctr32(GCM128_CONTEXT *ctx,
++                                const unsigned char *in, unsigned char *out,
++                                size_t len, ctr128_f stream)
++{
++#if defined(OPENSSL_SMALL_FOOTPRINT)
++    return CRYPTO_gcm128_encrypt(ctx, in, out, len);
++#else
++    const union {
++        long one;
++        char little;
++    } is_endian = { 1 };
++    unsigned int n, ctr;
++    size_t i;
++    u64 mlen = ctx->len.u[1];
++    void *key = ctx->key;
++# ifdef GCM_FUNCREF_4BIT
++    void (*gcm_gmult_p) (u64 Xi[2], const u128 Htable[16]) = ctx->gmult;
++#  ifdef GHASH
++    void (*gcm_ghash_p) (u64 Xi[2], const u128 Htable[16],
++                         const u8 *inp, size_t len) = ctx->ghash;
++#  endif
++# endif
++
++    mlen += len;
++    if (mlen > ((U64(1) << 36) - 32) || (sizeof(len) == 8 && mlen < len))
++        return -1;
++    ctx->len.u[1] = mlen;
++
++    if (ctx->ares) {
++        /* First call to encrypt finalizes GHASH(AAD) */
++        GCM_MUL(ctx, Xi);
++        ctx->ares = 0;
++    }
++
++    if (is_endian.little)
++# ifdef BSWAP4
++        ctr = BSWAP4(ctx->Yi.d[3]);
++# else
++        ctr = GETU32(ctx->Yi.c + 12);
++# endif
++    else
++        ctr = ctx->Yi.d[3];
++
++    n = ctx->mres;
++    if (n) {
++        while (n && len) {
++            ctx->Xi.c[n] ^= *(out++) = *(in++) ^ ctx->EKi.c[n];
++            --len;
++            n = (n + 1) % 16;
++        }
++        if (n == 0)
++            GCM_MUL(ctx, Xi);
++        else {
++            ctx->mres = n;
++            return 0;
++        }
++    }
++# if defined(GHASH) && defined(GHASH_CHUNK)
++    while (len >= GHASH_CHUNK) {
++        (*stream) (in, out, GHASH_CHUNK / 16, key, ctx->Yi.c);
++        ctr += GHASH_CHUNK / 16;
++        if (is_endian.little)
++#  ifdef BSWAP4
++            ctx->Yi.d[3] = BSWAP4(ctr);
++#  else
++            PUTU32(ctx->Yi.c + 12, ctr);
++#  endif
++        else
++            ctx->Yi.d[3] = ctr;
++        GHASH(ctx, out, GHASH_CHUNK);
++        out += GHASH_CHUNK;
++        in += GHASH_CHUNK;
++        len -= GHASH_CHUNK;
++    }
++# endif
++    if ((i = (len & (size_t)-16))) {
++        size_t j = i / 16;
++
++        (*stream) (in, out, j, key, ctx->Yi.c);
++        ctr += (unsigned int)j;
++        if (is_endian.little)
++# ifdef BSWAP4
++            ctx->Yi.d[3] = BSWAP4(ctr);
++# else
++            PUTU32(ctx->Yi.c + 12, ctr);
++# endif
++        else
++            ctx->Yi.d[3] = ctr;
++        in += i;
++        len -= i;
++# if defined(GHASH)
++        GHASH(ctx, out, i);
++        out += i;
++# else
++        while (j--) {
++            for (i = 0; i < 16; ++i)
++                ctx->Xi.c[i] ^= out[i];
++            GCM_MUL(ctx, Xi);
++            out += 16;
++        }
++# endif
++    }
++    if (len) {
++        (*ctx->block) (ctx->Yi.c, ctx->EKi.c, key);
++        ++ctr;
++        if (is_endian.little)
++# ifdef BSWAP4
++            ctx->Yi.d[3] = BSWAP4(ctr);
++# else
++            PUTU32(ctx->Yi.c + 12, ctr);
++# endif
++        else
++            ctx->Yi.d[3] = ctr;
++        while (len--) {
++            ctx->Xi.c[n] ^= out[n] = in[n] ^ ctx->EKi.c[n];
++            ++n;
++        }
++    }
++
++    ctx->mres = n;
++    return 0;
++#endif
++}
++
++int CRYPTO_gcm128_decrypt_ctr32(GCM128_CONTEXT *ctx,
++                                const unsigned char *in, unsigned char *out,
++                                size_t len, ctr128_f stream)
++{
++#if defined(OPENSSL_SMALL_FOOTPRINT)
++    return CRYPTO_gcm128_decrypt(ctx, in, out, len);
++#else
++    const union {
++        long one;
++        char little;
++    } is_endian = { 1 };
++    unsigned int n, ctr;
++    size_t i;
++    u64 mlen = ctx->len.u[1];
++    void *key = ctx->key;
++# ifdef GCM_FUNCREF_4BIT
++    void (*gcm_gmult_p) (u64 Xi[2], const u128 Htable[16]) = ctx->gmult;
++#  ifdef GHASH
++    void (*gcm_ghash_p) (u64 Xi[2], const u128 Htable[16],
++                         const u8 *inp, size_t len) = ctx->ghash;
++#  endif
++# endif
++
++    mlen += len;
++    if (mlen > ((U64(1) << 36) - 32) || (sizeof(len) == 8 && mlen < len))
++        return -1;
++    ctx->len.u[1] = mlen;
++
++    if (ctx->ares) {
++        /* First call to decrypt finalizes GHASH(AAD) */
++        GCM_MUL(ctx, Xi);
++        ctx->ares = 0;
++    }
++
++    if (is_endian.little)
++# ifdef BSWAP4
++        ctr = BSWAP4(ctx->Yi.d[3]);
++# else
++        ctr = GETU32(ctx->Yi.c + 12);
++# endif
++    else
++        ctr = ctx->Yi.d[3];
++
++    n = ctx->mres;
++    if (n) {
++        while (n && len) {
++            u8 c = *(in++);
++            *(out++) = c ^ ctx->EKi.c[n];
++            ctx->Xi.c[n] ^= c;
++            --len;
++            n = (n + 1) % 16;
++        }
++        if (n == 0)
++            GCM_MUL(ctx, Xi);
++        else {
++            ctx->mres = n;
++            return 0;
++        }
++    }
++# if defined(GHASH) && defined(GHASH_CHUNK)
++    while (len >= GHASH_CHUNK) {
++        GHASH(ctx, in, GHASH_CHUNK);
++        (*stream) (in, out, GHASH_CHUNK / 16, key, ctx->Yi.c);
++        ctr += GHASH_CHUNK / 16;
++        if (is_endian.little)
++#  ifdef BSWAP4
++            ctx->Yi.d[3] = BSWAP4(ctr);
++#  else
++            PUTU32(ctx->Yi.c + 12, ctr);
++#  endif
++        else
++            ctx->Yi.d[3] = ctr;
++        out += GHASH_CHUNK;
++        in += GHASH_CHUNK;
++        len -= GHASH_CHUNK;
++    }
++# endif
++    if ((i = (len & (size_t)-16))) {
++        size_t j = i / 16;
++
++# if defined(GHASH)
++        GHASH(ctx, in, i);
++# else
++        while (j--) {
++            size_t k;
++            for (k = 0; k < 16; ++k)
++                ctx->Xi.c[k] ^= in[k];
++            GCM_MUL(ctx, Xi);
++            in += 16;
++        }
++        j = i / 16;
++        in -= i;
++# endif
++        (*stream) (in, out, j, key, ctx->Yi.c);
++        ctr += (unsigned int)j;
++        if (is_endian.little)
++# ifdef BSWAP4
++            ctx->Yi.d[3] = BSWAP4(ctr);
++# else
++            PUTU32(ctx->Yi.c + 12, ctr);
++# endif
++        else
++            ctx->Yi.d[3] = ctr;
++        out += i;
++        in += i;
++        len -= i;
++    }
++    if (len) {
++        (*ctx->block) (ctx->Yi.c, ctx->EKi.c, key);
++        ++ctr;
++        if (is_endian.little)
++# ifdef BSWAP4
++            ctx->Yi.d[3] = BSWAP4(ctr);
++# else
++            PUTU32(ctx->Yi.c + 12, ctr);
++# endif
++        else
++            ctx->Yi.d[3] = ctr;
++        while (len--) {
++            u8 c = in[n];
++            ctx->Xi.c[n] ^= c;
++            out[n] = c ^ ctx->EKi.c[n];
++            ++n;
++        }
++    }
++
++    ctx->mres = n;
++    return 0;
++#endif
++}
++
++int CRYPTO_gcm128_finish(GCM128_CONTEXT *ctx, const unsigned char *tag,
++                         size_t len)
++{
++    const union {
++        long one;
++        char little;
++    } is_endian = { 1 };
++    u64 alen = ctx->len.u[0] << 3;
++    u64 clen = ctx->len.u[1] << 3;
++#ifdef GCM_FUNCREF_4BIT
++    void (*gcm_gmult_p) (u64 Xi[2], const u128 Htable[16]) = ctx->gmult;
++#endif
++
++    if (ctx->mres || ctx->ares)
++        GCM_MUL(ctx, Xi);
++
++    if (is_endian.little) {
++#ifdef BSWAP8
++        alen = BSWAP8(alen);
++        clen = BSWAP8(clen);
++#else
++        u8 *p = ctx->len.c;
++
++        ctx->len.u[0] = alen;
++        ctx->len.u[1] = clen;
++
++        alen = (u64)GETU32(p) << 32 | GETU32(p + 4);
++        clen = (u64)GETU32(p + 8) << 32 | GETU32(p + 12);
++#endif
++    }
++
++    ctx->Xi.u[0] ^= alen;
++    ctx->Xi.u[1] ^= clen;
++    GCM_MUL(ctx, Xi);
++
++    ctx->Xi.u[0] ^= ctx->EK0.u[0];
++    ctx->Xi.u[1] ^= ctx->EK0.u[1];
++
++    if (tag && len <= sizeof(ctx->Xi))
++        return CRYPTO_memcmp(ctx->Xi.c, tag, len);
++    else
++        return -1;
++}
++
++void CRYPTO_gcm128_tag(GCM128_CONTEXT *ctx, unsigned char *tag, size_t len)
++{
++    CRYPTO_gcm128_finish(ctx, NULL, 0);
++    memcpy(tag, ctx->Xi.c,
++           len <= sizeof(ctx->Xi.c) ? len : sizeof(ctx->Xi.c));
++}
++
++GCM128_CONTEXT *CRYPTO_gcm128_new(void *key, block128_f block)
++{
++    GCM128_CONTEXT *ret;
++
++    if ((ret = OPENSSL_malloc(sizeof(*ret))) != NULL)
++        CRYPTO_gcm128_init(ret, key, block);
++
++    return ret;
++}
++
++void CRYPTO_gcm128_release(GCM128_CONTEXT *ctx)
++{
++    OPENSSL_clear_free(ctx, sizeof(*ctx));
++}
++
++#if defined(SELFTEST)
++# include 
++# include 
++
++/* Test Case 1 */
++static const u8 K1[16], *P1 = NULL, *A1 = NULL, IV1[12], *C1 = NULL;
++static const u8 T1[] = {
++    0x58, 0xe2, 0xfc, 0xce, 0xfa, 0x7e, 0x30, 0x61,
++    0x36, 0x7f, 0x1d, 0x57, 0xa4, 0xe7, 0x45, 0x5a
++};
++
++/* Test Case 2 */
++# define K2 K1
++# define A2 A1
++# define IV2 IV1
++static const u8 P2[16];
++static const u8 C2[] = {
++    0x03, 0x88, 0xda, 0xce, 0x60, 0xb6, 0xa3, 0x92,
++    0xf3, 0x28, 0xc2, 0xb9, 0x71, 0xb2, 0xfe, 0x78
++};
++
++static const u8 T2[] = {
++    0xab, 0x6e, 0x47, 0xd4, 0x2c, 0xec, 0x13, 0xbd,
++    0xf5, 0x3a, 0x67, 0xb2, 0x12, 0x57, 0xbd, 0xdf
++};
++
++/* Test Case 3 */
++# define A3 A2
++static const u8 K3[] = {
++    0xfe, 0xff, 0xe9, 0x92, 0x86, 0x65, 0x73, 0x1c,
++    0x6d, 0x6a, 0x8f, 0x94, 0x67, 0x30, 0x83, 0x08
++};
++
++static const u8 P3[] = {
++    0xd9, 0x31, 0x32, 0x25, 0xf8, 0x84, 0x06, 0xe5,
++    0xa5, 0x59, 0x09, 0xc5, 0xaf, 0xf5, 0x26, 0x9a,
++    0x86, 0xa7, 0xa9, 0x53, 0x15, 0x34, 0xf7, 0xda,
++    0x2e, 0x4c, 0x30, 0x3d, 0x8a, 0x31, 0x8a, 0x72,
++    0x1c, 0x3c, 0x0c, 0x95, 0x95, 0x68, 0x09, 0x53,
++    0x2f, 0xcf, 0x0e, 0x24, 0x49, 0xa6, 0xb5, 0x25,
++    0xb1, 0x6a, 0xed, 0xf5, 0xaa, 0x0d, 0xe6, 0x57,
++    0xba, 0x63, 0x7b, 0x39, 0x1a, 0xaf, 0xd2, 0x55
++};
++
++static const u8 IV3[] = {
++    0xca, 0xfe, 0xba, 0xbe, 0xfa, 0xce, 0xdb, 0xad,
++    0xde, 0xca, 0xf8, 0x88
++};
++
++static const u8 C3[] = {
++    0x42, 0x83, 0x1e, 0xc2, 0x21, 0x77, 0x74, 0x24,
++    0x4b, 0x72, 0x21, 0xb7, 0x84, 0xd0, 0xd4, 0x9c,
++    0xe3, 0xaa, 0x21, 0x2f, 0x2c, 0x02, 0xa4, 0xe0,
++    0x35, 0xc1, 0x7e, 0x23, 0x29, 0xac, 0xa1, 0x2e,
++    0x21, 0xd5, 0x14, 0xb2, 0x54, 0x66, 0x93, 0x1c,
++    0x7d, 0x8f, 0x6a, 0x5a, 0xac, 0x84, 0xaa, 0x05,
++    0x1b, 0xa3, 0x0b, 0x39, 0x6a, 0x0a, 0xac, 0x97,
++    0x3d, 0x58, 0xe0, 0x91, 0x47, 0x3f, 0x59, 0x85
++};
++
++static const u8 T3[] = {
++    0x4d, 0x5c, 0x2a, 0xf3, 0x27, 0xcd, 0x64, 0xa6,
++    0x2c, 0xf3, 0x5a, 0xbd, 0x2b, 0xa6, 0xfa, 0xb4
++};
++
++/* Test Case 4 */
++# define K4 K3
++# define IV4 IV3
++static const u8 P4[] = {
++    0xd9, 0x31, 0x32, 0x25, 0xf8, 0x84, 0x06, 0xe5,
++    0xa5, 0x59, 0x09, 0xc5, 0xaf, 0xf5, 0x26, 0x9a,
++    0x86, 0xa7, 0xa9, 0x53, 0x15, 0x34, 0xf7, 0xda,
++    0x2e, 0x4c, 0x30, 0x3d, 0x8a, 0x31, 0x8a, 0x72,
++    0x1c, 0x3c, 0x0c, 0x95, 0x95, 0x68, 0x09, 0x53,
++    0x2f, 0xcf, 0x0e, 0x24, 0x49, 0xa6, 0xb5, 0x25,
++    0xb1, 0x6a, 0xed, 0xf5, 0xaa, 0x0d, 0xe6, 0x57,
++    0xba, 0x63, 0x7b, 0x39
++};
++
++static const u8 A4[] = {
++    0xfe, 0xed, 0xfa, 0xce, 0xde, 0xad, 0xbe, 0xef,
++    0xfe, 0xed, 0xfa, 0xce, 0xde, 0xad, 0xbe, 0xef,
++    0xab, 0xad, 0xda, 0xd2
++};
++
++static const u8 C4[] = {
++    0x42, 0x83, 0x1e, 0xc2, 0x21, 0x77, 0x74, 0x24,
++    0x4b, 0x72, 0x21, 0xb7, 0x84, 0xd0, 0xd4, 0x9c,
++    0xe3, 0xaa, 0x21, 0x2f, 0x2c, 0x02, 0xa4, 0xe0,
++    0x35, 0xc1, 0x7e, 0x23, 0x29, 0xac, 0xa1, 0x2e,
++    0x21, 0xd5, 0x14, 0xb2, 0x54, 0x66, 0x93, 0x1c,
++    0x7d, 0x8f, 0x6a, 0x5a, 0xac, 0x84, 0xaa, 0x05,
++    0x1b, 0xa3, 0x0b, 0x39, 0x6a, 0x0a, 0xac, 0x97,
++    0x3d, 0x58, 0xe0, 0x91
++};
++
++static const u8 T4[] = {
++    0x5b, 0xc9, 0x4f, 0xbc, 0x32, 0x21, 0xa5, 0xdb,
++    0x94, 0xfa, 0xe9, 0x5a, 0xe7, 0x12, 0x1a, 0x47
++};
++
++/* Test Case 5 */
++# define K5 K4
++# define P5 P4
++# define A5 A4
++static const u8 IV5[] = {
++    0xca, 0xfe, 0xba, 0xbe, 0xfa, 0xce, 0xdb, 0xad
++};
++
++static const u8 C5[] = {
++    0x61, 0x35, 0x3b, 0x4c, 0x28, 0x06, 0x93, 0x4a,
++    0x77, 0x7f, 0xf5, 0x1f, 0xa2, 0x2a, 0x47, 0x55,
++    0x69, 0x9b, 0x2a, 0x71, 0x4f, 0xcd, 0xc6, 0xf8,
++    0x37, 0x66, 0xe5, 0xf9, 0x7b, 0x6c, 0x74, 0x23,
++    0x73, 0x80, 0x69, 0x00, 0xe4, 0x9f, 0x24, 0xb2,
++    0x2b, 0x09, 0x75, 0x44, 0xd4, 0x89, 0x6b, 0x42,
++    0x49, 0x89, 0xb5, 0xe1, 0xeb, 0xac, 0x0f, 0x07,
++    0xc2, 0x3f, 0x45, 0x98
++};
++
++static const u8 T5[] = {
++    0x36, 0x12, 0xd2, 0xe7, 0x9e, 0x3b, 0x07, 0x85,
++    0x56, 0x1b, 0xe1, 0x4a, 0xac, 0xa2, 0xfc, 0xcb
++};
++
++/* Test Case 6 */
++# define K6 K5
++# define P6 P5
++# define A6 A5
++static const u8 IV6[] = {
++    0x93, 0x13, 0x22, 0x5d, 0xf8, 0x84, 0x06, 0xe5,
++    0x55, 0x90, 0x9c, 0x5a, 0xff, 0x52, 0x69, 0xaa,
++    0x6a, 0x7a, 0x95, 0x38, 0x53, 0x4f, 0x7d, 0xa1,
++    0xe4, 0xc3, 0x03, 0xd2, 0xa3, 0x18, 0xa7, 0x28,
++    0xc3, 0xc0, 0xc9, 0x51, 0x56, 0x80, 0x95, 0x39,
++    0xfc, 0xf0, 0xe2, 0x42, 0x9a, 0x6b, 0x52, 0x54,
++    0x16, 0xae, 0xdb, 0xf5, 0xa0, 0xde, 0x6a, 0x57,
++    0xa6, 0x37, 0xb3, 0x9b
++};
++
++static const u8 C6[] = {
++    0x8c, 0xe2, 0x49, 0x98, 0x62, 0x56, 0x15, 0xb6,
++    0x03, 0xa0, 0x33, 0xac, 0xa1, 0x3f, 0xb8, 0x94,
++    0xbe, 0x91, 0x12, 0xa5, 0xc3, 0xa2, 0x11, 0xa8,
++    0xba, 0x26, 0x2a, 0x3c, 0xca, 0x7e, 0x2c, 0xa7,
++    0x01, 0xe4, 0xa9, 0xa4, 0xfb, 0xa4, 0x3c, 0x90,
++    0xcc, 0xdc, 0xb2, 0x81, 0xd4, 0x8c, 0x7c, 0x6f,
++    0xd6, 0x28, 0x75, 0xd2, 0xac, 0xa4, 0x17, 0x03,
++    0x4c, 0x34, 0xae, 0xe5
++};
++
++static const u8 T6[] = {
++    0x61, 0x9c, 0xc5, 0xae, 0xff, 0xfe, 0x0b, 0xfa,
++    0x46, 0x2a, 0xf4, 0x3c, 0x16, 0x99, 0xd0, 0x50
++};
++
++/* Test Case 7 */
++static const u8 K7[24], *P7 = NULL, *A7 = NULL, IV7[12], *C7 = NULL;
++static const u8 T7[] = {
++    0xcd, 0x33, 0xb2, 0x8a, 0xc7, 0x73, 0xf7, 0x4b,
++    0xa0, 0x0e, 0xd1, 0xf3, 0x12, 0x57, 0x24, 0x35
++};
++
++/* Test Case 8 */
++# define K8 K7
++# define IV8 IV7
++# define A8 A7
++static const u8 P8[16];
++static const u8 C8[] = {
++    0x98, 0xe7, 0x24, 0x7c, 0x07, 0xf0, 0xfe, 0x41,
++    0x1c, 0x26, 0x7e, 0x43, 0x84, 0xb0, 0xf6, 0x00
++};
++
++static const u8 T8[] = {
++    0x2f, 0xf5, 0x8d, 0x80, 0x03, 0x39, 0x27, 0xab,
++    0x8e, 0xf4, 0xd4, 0x58, 0x75, 0x14, 0xf0, 0xfb
++};
++
++/* Test Case 9 */
++# define A9 A8
++static const u8 K9[] = {
++    0xfe, 0xff, 0xe9, 0x92, 0x86, 0x65, 0x73, 0x1c,
++    0x6d, 0x6a, 0x8f, 0x94, 0x67, 0x30, 0x83, 0x08,
++    0xfe, 0xff, 0xe9, 0x92, 0x86, 0x65, 0x73, 0x1c
++};
++
++static const u8 P9[] = {
++    0xd9, 0x31, 0x32, 0x25, 0xf8, 0x84, 0x06, 0xe5,
++    0xa5, 0x59, 0x09, 0xc5, 0xaf, 0xf5, 0x26, 0x9a,
++    0x86, 0xa7, 0xa9, 0x53, 0x15, 0x34, 0xf7, 0xda,
++    0x2e, 0x4c, 0x30, 0x3d, 0x8a, 0x31, 0x8a, 0x72,
++    0x1c, 0x3c, 0x0c, 0x95, 0x95, 0x68, 0x09, 0x53,
++    0x2f, 0xcf, 0x0e, 0x24, 0x49, 0xa6, 0xb5, 0x25,
++    0xb1, 0x6a, 0xed, 0xf5, 0xaa, 0x0d, 0xe6, 0x57,
++    0xba, 0x63, 0x7b, 0x39, 0x1a, 0xaf, 0xd2, 0x55
++};
++
++static const u8 IV9[] = {
++    0xca, 0xfe, 0xba, 0xbe, 0xfa, 0xce, 0xdb, 0xad,
++    0xde, 0xca, 0xf8, 0x88
++};
++
++static const u8 C9[] = {
++    0x39, 0x80, 0xca, 0x0b, 0x3c, 0x00, 0xe8, 0x41,
++    0xeb, 0x06, 0xfa, 0xc4, 0x87, 0x2a, 0x27, 0x57,
++    0x85, 0x9e, 0x1c, 0xea, 0xa6, 0xef, 0xd9, 0x84,
++    0x62, 0x85, 0x93, 0xb4, 0x0c, 0xa1, 0xe1, 0x9c,
++    0x7d, 0x77, 0x3d, 0x00, 0xc1, 0x44, 0xc5, 0x25,
++    0xac, 0x61, 0x9d, 0x18, 0xc8, 0x4a, 0x3f, 0x47,
++    0x18, 0xe2, 0x44, 0x8b, 0x2f, 0xe3, 0x24, 0xd9,
++    0xcc, 0xda, 0x27, 0x10, 0xac, 0xad, 0xe2, 0x56
++};
++
++static const u8 T9[] = {
++    0x99, 0x24, 0xa7, 0xc8, 0x58, 0x73, 0x36, 0xbf,
++    0xb1, 0x18, 0x02, 0x4d, 0xb8, 0x67, 0x4a, 0x14
++};
++
++/* Test Case 10 */
++# define K10 K9
++# define IV10 IV9
++static const u8 P10[] = {
++    0xd9, 0x31, 0x32, 0x25, 0xf8, 0x84, 0x06, 0xe5,
++    0xa5, 0x59, 0x09, 0xc5, 0xaf, 0xf5, 0x26, 0x9a,
++    0x86, 0xa7, 0xa9, 0x53, 0x15, 0x34, 0xf7, 0xda,
++    0x2e, 0x4c, 0x30, 0x3d, 0x8a, 0x31, 0x8a, 0x72,
++    0x1c, 0x3c, 0x0c, 0x95, 0x95, 0x68, 0x09, 0x53,
++    0x2f, 0xcf, 0x0e, 0x24, 0x49, 0xa6, 0xb5, 0x25,
++    0xb1, 0x6a, 0xed, 0xf5, 0xaa, 0x0d, 0xe6, 0x57,
++    0xba, 0x63, 0x7b, 0x39
++};
++
++static const u8 A10[] = {
++    0xfe, 0xed, 0xfa, 0xce, 0xde, 0xad, 0xbe, 0xef,
++    0xfe, 0xed, 0xfa, 0xce, 0xde, 0xad, 0xbe, 0xef,
++    0xab, 0xad, 0xda, 0xd2
++};
++
++static const u8 C10[] = {
++    0x39, 0x80, 0xca, 0x0b, 0x3c, 0x00, 0xe8, 0x41,
++    0xeb, 0x06, 0xfa, 0xc4, 0x87, 0x2a, 0x27, 0x57,
++    0x85, 0x9e, 0x1c, 0xea, 0xa6, 0xef, 0xd9, 0x84,
++    0x62, 0x85, 0x93, 0xb4, 0x0c, 0xa1, 0xe1, 0x9c,
++    0x7d, 0x77, 0x3d, 0x00, 0xc1, 0x44, 0xc5, 0x25,
++    0xac, 0x61, 0x9d, 0x18, 0xc8, 0x4a, 0x3f, 0x47,
++    0x18, 0xe2, 0x44, 0x8b, 0x2f, 0xe3, 0x24, 0xd9,
++    0xcc, 0xda, 0x27, 0x10
++};
++
++static const u8 T10[] = {
++    0x25, 0x19, 0x49, 0x8e, 0x80, 0xf1, 0x47, 0x8f,
++    0x37, 0xba, 0x55, 0xbd, 0x6d, 0x27, 0x61, 0x8c
++};
++
++/* Test Case 11 */
++# define K11 K10
++# define P11 P10
++# define A11 A10
++static const u8 IV11[] = { 0xca, 0xfe, 0xba, 0xbe, 0xfa, 0xce, 0xdb, 0xad };
++
++static const u8 C11[] = {
++    0x0f, 0x10, 0xf5, 0x99, 0xae, 0x14, 0xa1, 0x54,
++    0xed, 0x24, 0xb3, 0x6e, 0x25, 0x32, 0x4d, 0xb8,
++    0xc5, 0x66, 0x63, 0x2e, 0xf2, 0xbb, 0xb3, 0x4f,
++    0x83, 0x47, 0x28, 0x0f, 0xc4, 0x50, 0x70, 0x57,
++    0xfd, 0xdc, 0x29, 0xdf, 0x9a, 0x47, 0x1f, 0x75,
++    0xc6, 0x65, 0x41, 0xd4, 0xd4, 0xda, 0xd1, 0xc9,
++    0xe9, 0x3a, 0x19, 0xa5, 0x8e, 0x8b, 0x47, 0x3f,
++    0xa0, 0xf0, 0x62, 0xf7
++};
++
++static const u8 T11[] = {
++    0x65, 0xdc, 0xc5, 0x7f, 0xcf, 0x62, 0x3a, 0x24,
++    0x09, 0x4f, 0xcc, 0xa4, 0x0d, 0x35, 0x33, 0xf8
++};
++
++/* Test Case 12 */
++# define K12 K11
++# define P12 P11
++# define A12 A11
++static const u8 IV12[] = {
++    0x93, 0x13, 0x22, 0x5d, 0xf8, 0x84, 0x06, 0xe5,
++    0x55, 0x90, 0x9c, 0x5a, 0xff, 0x52, 0x69, 0xaa,
++    0x6a, 0x7a, 0x95, 0x38, 0x53, 0x4f, 0x7d, 0xa1,
++    0xe4, 0xc3, 0x03, 0xd2, 0xa3, 0x18, 0xa7, 0x28,
++    0xc3, 0xc0, 0xc9, 0x51, 0x56, 0x80, 0x95, 0x39,
++    0xfc, 0xf0, 0xe2, 0x42, 0x9a, 0x6b, 0x52, 0x54,
++    0x16, 0xae, 0xdb, 0xf5, 0xa0, 0xde, 0x6a, 0x57,
++    0xa6, 0x37, 0xb3, 0x9b
++};
++
++static const u8 C12[] = {
++    0xd2, 0x7e, 0x88, 0x68, 0x1c, 0xe3, 0x24, 0x3c,
++    0x48, 0x30, 0x16, 0x5a, 0x8f, 0xdc, 0xf9, 0xff,
++    0x1d, 0xe9, 0xa1, 0xd8, 0xe6, 0xb4, 0x47, 0xef,
++    0x6e, 0xf7, 0xb7, 0x98, 0x28, 0x66, 0x6e, 0x45,
++    0x81, 0xe7, 0x90, 0x12, 0xaf, 0x34, 0xdd, 0xd9,
++    0xe2, 0xf0, 0x37, 0x58, 0x9b, 0x29, 0x2d, 0xb3,
++    0xe6, 0x7c, 0x03, 0x67, 0x45, 0xfa, 0x22, 0xe7,
++    0xe9, 0xb7, 0x37, 0x3b
++};
++
++static const u8 T12[] = {
++    0xdc, 0xf5, 0x66, 0xff, 0x29, 0x1c, 0x25, 0xbb,
++    0xb8, 0x56, 0x8f, 0xc3, 0xd3, 0x76, 0xa6, 0xd9
++};
++
++/* Test Case 13 */
++static const u8 K13[32], *P13 = NULL, *A13 = NULL, IV13[12], *C13 = NULL;
++static const u8 T13[] = {
++    0x53, 0x0f, 0x8a, 0xfb, 0xc7, 0x45, 0x36, 0xb9,
++    0xa9, 0x63, 0xb4, 0xf1, 0xc4, 0xcb, 0x73, 0x8b
++};
++
++/* Test Case 14 */
++# define K14 K13
++# define A14 A13
++static const u8 P14[16], IV14[12];
++static const u8 C14[] = {
++    0xce, 0xa7, 0x40, 0x3d, 0x4d, 0x60, 0x6b, 0x6e,
++    0x07, 0x4e, 0xc5, 0xd3, 0xba, 0xf3, 0x9d, 0x18
++};
++
++static const u8 T14[] = {
++    0xd0, 0xd1, 0xc8, 0xa7, 0x99, 0x99, 0x6b, 0xf0,
++    0x26, 0x5b, 0x98, 0xb5, 0xd4, 0x8a, 0xb9, 0x19
++};
++
++/* Test Case 15 */
++# define A15 A14
++static const u8 K15[] = {
++    0xfe, 0xff, 0xe9, 0x92, 0x86, 0x65, 0x73, 0x1c,
++    0x6d, 0x6a, 0x8f, 0x94, 0x67, 0x30, 0x83, 0x08,
++    0xfe, 0xff, 0xe9, 0x92, 0x86, 0x65, 0x73, 0x1c,
++    0x6d, 0x6a, 0x8f, 0x94, 0x67, 0x30, 0x83, 0x08
++};
++
++static const u8 P15[] = {
++    0xd9, 0x31, 0x32, 0x25, 0xf8, 0x84, 0x06, 0xe5,
++    0xa5, 0x59, 0x09, 0xc5, 0xaf, 0xf5, 0x26, 0x9a,
++    0x86, 0xa7, 0xa9, 0x53, 0x15, 0x34, 0xf7, 0xda,
++    0x2e, 0x4c, 0x30, 0x3d, 0x8a, 0x31, 0x8a, 0x72,
++    0x1c, 0x3c, 0x0c, 0x95, 0x95, 0x68, 0x09, 0x53,
++    0x2f, 0xcf, 0x0e, 0x24, 0x49, 0xa6, 0xb5, 0x25,
++    0xb1, 0x6a, 0xed, 0xf5, 0xaa, 0x0d, 0xe6, 0x57,
++    0xba, 0x63, 0x7b, 0x39, 0x1a, 0xaf, 0xd2, 0x55
++};
++
++static const u8 IV15[] = {
++    0xca, 0xfe, 0xba, 0xbe, 0xfa, 0xce, 0xdb, 0xad,
++    0xde, 0xca, 0xf8, 0x88
++};
++
++static const u8 C15[] = {
++    0x52, 0x2d, 0xc1, 0xf0, 0x99, 0x56, 0x7d, 0x07,
++    0xf4, 0x7f, 0x37, 0xa3, 0x2a, 0x84, 0x42, 0x7d,
++    0x64, 0x3a, 0x8c, 0xdc, 0xbf, 0xe5, 0xc0, 0xc9,
++    0x75, 0x98, 0xa2, 0xbd, 0x25, 0x55, 0xd1, 0xaa,
++    0x8c, 0xb0, 0x8e, 0x48, 0x59, 0x0d, 0xbb, 0x3d,
++    0xa7, 0xb0, 0x8b, 0x10, 0x56, 0x82, 0x88, 0x38,
++    0xc5, 0xf6, 0x1e, 0x63, 0x93, 0xba, 0x7a, 0x0a,
++    0xbc, 0xc9, 0xf6, 0x62, 0x89, 0x80, 0x15, 0xad
++};
++
++static const u8 T15[] = {
++    0xb0, 0x94, 0xda, 0xc5, 0xd9, 0x34, 0x71, 0xbd,
++    0xec, 0x1a, 0x50, 0x22, 0x70, 0xe3, 0xcc, 0x6c
++};
++
++/* Test Case 16 */
++# define K16 K15
++# define IV16 IV15
++static const u8 P16[] = {
++    0xd9, 0x31, 0x32, 0x25, 0xf8, 0x84, 0x06, 0xe5,
++    0xa5, 0x59, 0x09, 0xc5, 0xaf, 0xf5, 0x26, 0x9a,
++    0x86, 0xa7, 0xa9, 0x53, 0x15, 0x34, 0xf7, 0xda,
++    0x2e, 0x4c, 0x30, 0x3d, 0x8a, 0x31, 0x8a, 0x72,
++    0x1c, 0x3c, 0x0c, 0x95, 0x95, 0x68, 0x09, 0x53,
++    0x2f, 0xcf, 0x0e, 0x24, 0x49, 0xa6, 0xb5, 0x25,
++    0xb1, 0x6a, 0xed, 0xf5, 0xaa, 0x0d, 0xe6, 0x57,
++    0xba, 0x63, 0x7b, 0x39
++};
++
++static const u8 A16[] = {
++    0xfe, 0xed, 0xfa, 0xce, 0xde, 0xad, 0xbe, 0xef,
++    0xfe, 0xed, 0xfa, 0xce, 0xde, 0xad, 0xbe, 0xef,
++    0xab, 0xad, 0xda, 0xd2
++};
++
++static const u8 C16[] = {
++    0x52, 0x2d, 0xc1, 0xf0, 0x99, 0x56, 0x7d, 0x07,
++    0xf4, 0x7f, 0x37, 0xa3, 0x2a, 0x84, 0x42, 0x7d,
++    0x64, 0x3a, 0x8c, 0xdc, 0xbf, 0xe5, 0xc0, 0xc9,
++    0x75, 0x98, 0xa2, 0xbd, 0x25, 0x55, 0xd1, 0xaa,
++    0x8c, 0xb0, 0x8e, 0x48, 0x59, 0x0d, 0xbb, 0x3d,
++    0xa7, 0xb0, 0x8b, 0x10, 0x56, 0x82, 0x88, 0x38,
++    0xc5, 0xf6, 0x1e, 0x63, 0x93, 0xba, 0x7a, 0x0a,
++    0xbc, 0xc9, 0xf6, 0x62
++};
++
++static const u8 T16[] = {
++    0x76, 0xfc, 0x6e, 0xce, 0x0f, 0x4e, 0x17, 0x68,
++    0xcd, 0xdf, 0x88, 0x53, 0xbb, 0x2d, 0x55, 0x1b
++};
++
++/* Test Case 17 */
++# define K17 K16
++# define P17 P16
++# define A17 A16
++static const u8 IV17[] = { 0xca, 0xfe, 0xba, 0xbe, 0xfa, 0xce, 0xdb, 0xad };
++
++static const u8 C17[] = {
++    0xc3, 0x76, 0x2d, 0xf1, 0xca, 0x78, 0x7d, 0x32,
++    0xae, 0x47, 0xc1, 0x3b, 0xf1, 0x98, 0x44, 0xcb,
++    0xaf, 0x1a, 0xe1, 0x4d, 0x0b, 0x97, 0x6a, 0xfa,
++    0xc5, 0x2f, 0xf7, 0xd7, 0x9b, 0xba, 0x9d, 0xe0,
++    0xfe, 0xb5, 0x82, 0xd3, 0x39, 0x34, 0xa4, 0xf0,
++    0x95, 0x4c, 0xc2, 0x36, 0x3b, 0xc7, 0x3f, 0x78,
++    0x62, 0xac, 0x43, 0x0e, 0x64, 0xab, 0xe4, 0x99,
++    0xf4, 0x7c, 0x9b, 0x1f
++};
++
++static const u8 T17[] = {
++    0x3a, 0x33, 0x7d, 0xbf, 0x46, 0xa7, 0x92, 0xc4,
++    0x5e, 0x45, 0x49, 0x13, 0xfe, 0x2e, 0xa8, 0xf2
++};
++
++/* Test Case 18 */
++# define K18 K17
++# define P18 P17
++# define A18 A17
++static const u8 IV18[] = {
++    0x93, 0x13, 0x22, 0x5d, 0xf8, 0x84, 0x06, 0xe5,
++    0x55, 0x90, 0x9c, 0x5a, 0xff, 0x52, 0x69, 0xaa,
++    0x6a, 0x7a, 0x95, 0x38, 0x53, 0x4f, 0x7d, 0xa1,
++    0xe4, 0xc3, 0x03, 0xd2, 0xa3, 0x18, 0xa7, 0x28,
++    0xc3, 0xc0, 0xc9, 0x51, 0x56, 0x80, 0x95, 0x39,
++    0xfc, 0xf0, 0xe2, 0x42, 0x9a, 0x6b, 0x52, 0x54,
++    0x16, 0xae, 0xdb, 0xf5, 0xa0, 0xde, 0x6a, 0x57,
++    0xa6, 0x37, 0xb3, 0x9b
++};
++
++static const u8 C18[] = {
++    0x5a, 0x8d, 0xef, 0x2f, 0x0c, 0x9e, 0x53, 0xf1,
++    0xf7, 0x5d, 0x78, 0x53, 0x65, 0x9e, 0x2a, 0x20,
++    0xee, 0xb2, 0xb2, 0x2a, 0xaf, 0xde, 0x64, 0x19,
++    0xa0, 0x58, 0xab, 0x4f, 0x6f, 0x74, 0x6b, 0xf4,
++    0x0f, 0xc0, 0xc3, 0xb7, 0x80, 0xf2, 0x44, 0x45,
++    0x2d, 0xa3, 0xeb, 0xf1, 0xc5, 0xd8, 0x2c, 0xde,
++    0xa2, 0x41, 0x89, 0x97, 0x20, 0x0e, 0xf8, 0x2e,
++    0x44, 0xae, 0x7e, 0x3f
++};
++
++static const u8 T18[] = {
++    0xa4, 0x4a, 0x82, 0x66, 0xee, 0x1c, 0x8e, 0xb0,
++    0xc8, 0xb5, 0xd4, 0xcf, 0x5a, 0xe9, 0xf1, 0x9a
++};
++
++/* Test Case 19 */
++# define K19 K1
++# define P19 P1
++# define IV19 IV1
++# define C19 C1
++static const u8 A19[] = {
++    0xd9, 0x31, 0x32, 0x25, 0xf8, 0x84, 0x06, 0xe5,
++    0xa5, 0x59, 0x09, 0xc5, 0xaf, 0xf5, 0x26, 0x9a,
++    0x86, 0xa7, 0xa9, 0x53, 0x15, 0x34, 0xf7, 0xda,
++    0x2e, 0x4c, 0x30, 0x3d, 0x8a, 0x31, 0x8a, 0x72,
++    0x1c, 0x3c, 0x0c, 0x95, 0x95, 0x68, 0x09, 0x53,
++    0x2f, 0xcf, 0x0e, 0x24, 0x49, 0xa6, 0xb5, 0x25,
++    0xb1, 0x6a, 0xed, 0xf5, 0xaa, 0x0d, 0xe6, 0x57,
++    0xba, 0x63, 0x7b, 0x39, 0x1a, 0xaf, 0xd2, 0x55,
++    0x52, 0x2d, 0xc1, 0xf0, 0x99, 0x56, 0x7d, 0x07,
++    0xf4, 0x7f, 0x37, 0xa3, 0x2a, 0x84, 0x42, 0x7d,
++    0x64, 0x3a, 0x8c, 0xdc, 0xbf, 0xe5, 0xc0, 0xc9,
++    0x75, 0x98, 0xa2, 0xbd, 0x25, 0x55, 0xd1, 0xaa,
++    0x8c, 0xb0, 0x8e, 0x48, 0x59, 0x0d, 0xbb, 0x3d,
++    0xa7, 0xb0, 0x8b, 0x10, 0x56, 0x82, 0x88, 0x38,
++    0xc5, 0xf6, 0x1e, 0x63, 0x93, 0xba, 0x7a, 0x0a,
++    0xbc, 0xc9, 0xf6, 0x62, 0x89, 0x80, 0x15, 0xad
++};
++
++static const u8 T19[] = {
++    0x5f, 0xea, 0x79, 0x3a, 0x2d, 0x6f, 0x97, 0x4d,
++    0x37, 0xe6, 0x8e, 0x0c, 0xb8, 0xff, 0x94, 0x92
++};
++
++/* Test Case 20 */
++# define K20 K1
++# define A20 A1
++/* this results in 0xff in counter LSB */
++static const u8 IV20[64] = { 0xff, 0xff, 0xff, 0xff };
++
++static const u8 P20[288];
++static const u8 C20[] = {
++    0x56, 0xb3, 0x37, 0x3c, 0xa9, 0xef, 0x6e, 0x4a,
++    0x2b, 0x64, 0xfe, 0x1e, 0x9a, 0x17, 0xb6, 0x14,
++    0x25, 0xf1, 0x0d, 0x47, 0xa7, 0x5a, 0x5f, 0xce,
++    0x13, 0xef, 0xc6, 0xbc, 0x78, 0x4a, 0xf2, 0x4f,
++    0x41, 0x41, 0xbd, 0xd4, 0x8c, 0xf7, 0xc7, 0x70,
++    0x88, 0x7a, 0xfd, 0x57, 0x3c, 0xca, 0x54, 0x18,
++    0xa9, 0xae, 0xff, 0xcd, 0x7c, 0x5c, 0xed, 0xdf,
++    0xc6, 0xa7, 0x83, 0x97, 0xb9, 0xa8, 0x5b, 0x49,
++    0x9d, 0xa5, 0x58, 0x25, 0x72, 0x67, 0xca, 0xab,
++    0x2a, 0xd0, 0xb2, 0x3c, 0xa4, 0x76, 0xa5, 0x3c,
++    0xb1, 0x7f, 0xb4, 0x1c, 0x4b, 0x8b, 0x47, 0x5c,
++    0xb4, 0xf3, 0xf7, 0x16, 0x50, 0x94, 0xc2, 0x29,
++    0xc9, 0xe8, 0xc4, 0xdc, 0x0a, 0x2a, 0x5f, 0xf1,
++    0x90, 0x3e, 0x50, 0x15, 0x11, 0x22, 0x13, 0x76,
++    0xa1, 0xcd, 0xb8, 0x36, 0x4c, 0x50, 0x61, 0xa2,
++    0x0c, 0xae, 0x74, 0xbc, 0x4a, 0xcd, 0x76, 0xce,
++    0xb0, 0xab, 0xc9, 0xfd, 0x32, 0x17, 0xef, 0x9f,
++    0x8c, 0x90, 0xbe, 0x40, 0x2d, 0xdf, 0x6d, 0x86,
++    0x97, 0xf4, 0xf8, 0x80, 0xdf, 0xf1, 0x5b, 0xfb,
++    0x7a, 0x6b, 0x28, 0x24, 0x1e, 0xc8, 0xfe, 0x18,
++    0x3c, 0x2d, 0x59, 0xe3, 0xf9, 0xdf, 0xff, 0x65,
++    0x3c, 0x71, 0x26, 0xf0, 0xac, 0xb9, 0xe6, 0x42,
++    0x11, 0xf4, 0x2b, 0xae, 0x12, 0xaf, 0x46, 0x2b,
++    0x10, 0x70, 0xbe, 0xf1, 0xab, 0x5e, 0x36, 0x06,
++    0x87, 0x2c, 0xa1, 0x0d, 0xee, 0x15, 0xb3, 0x24,
++    0x9b, 0x1a, 0x1b, 0x95, 0x8f, 0x23, 0x13, 0x4c,
++    0x4b, 0xcc, 0xb7, 0xd0, 0x32, 0x00, 0xbc, 0xe4,
++    0x20, 0xa2, 0xf8, 0xeb, 0x66, 0xdc, 0xf3, 0x64,
++    0x4d, 0x14, 0x23, 0xc1, 0xb5, 0x69, 0x90, 0x03,
++    0xc1, 0x3e, 0xce, 0xf4, 0xbf, 0x38, 0xa3, 0xb6,
++    0x0e, 0xed, 0xc3, 0x40, 0x33, 0xba, 0xc1, 0x90,
++    0x27, 0x83, 0xdc, 0x6d, 0x89, 0xe2, 0xe7, 0x74,
++    0x18, 0x8a, 0x43, 0x9c, 0x7e, 0xbc, 0xc0, 0x67,
++    0x2d, 0xbd, 0xa4, 0xdd, 0xcf, 0xb2, 0x79, 0x46,
++    0x13, 0xb0, 0xbe, 0x41, 0x31, 0x5e, 0xf7, 0x78,
++    0x70, 0x8a, 0x70, 0xee, 0x7d, 0x75, 0x16, 0x5c
++};
++
++static const u8 T20[] = {
++    0x8b, 0x30, 0x7f, 0x6b, 0x33, 0x28, 0x6d, 0x0a,
++    0xb0, 0x26, 0xa9, 0xed, 0x3f, 0xe1, 0xe8, 0x5f
++};
++
++# define TEST_CASE(n)    do {                                    \
++        u8 out[sizeof(P##n)];                                   \
++        AES_set_encrypt_key(K##n,sizeof(K##n)*8,&key);          \
++        CRYPTO_gcm128_init(&ctx,&key,(block128_f)AES_encrypt);  \
++        CRYPTO_gcm128_setiv(&ctx,IV##n,sizeof(IV##n));          \
++        memset(out,0,sizeof(out));                              \
++        if (A##n) CRYPTO_gcm128_aad(&ctx,A##n,sizeof(A##n));    \
++        if (P##n) CRYPTO_gcm128_encrypt(&ctx,P##n,out,sizeof(out));     \
++        if (CRYPTO_gcm128_finish(&ctx,T##n,16) ||               \
++            (C##n && memcmp(out,C##n,sizeof(out))))             \
++                ret++, printf ("encrypt test#%d failed.\n",n);  \
++        CRYPTO_gcm128_setiv(&ctx,IV##n,sizeof(IV##n));          \
++        memset(out,0,sizeof(out));                              \
++        if (A##n) CRYPTO_gcm128_aad(&ctx,A##n,sizeof(A##n));    \
++        if (C##n) CRYPTO_gcm128_decrypt(&ctx,C##n,out,sizeof(out));     \
++        if (CRYPTO_gcm128_finish(&ctx,T##n,16) ||               \
++            (P##n && memcmp(out,P##n,sizeof(out))))             \
++                ret++, printf ("decrypt test#%d failed.\n",n);  \
++        } while(0)
++
++int main()
++{
++    GCM128_CONTEXT ctx;
++    AES_KEY key;
++    int ret = 0;
++
++    TEST_CASE(1);
++    TEST_CASE(2);
++    TEST_CASE(3);
++    TEST_CASE(4);
++    TEST_CASE(5);
++    TEST_CASE(6);
++    TEST_CASE(7);
++    TEST_CASE(8);
++    TEST_CASE(9);
++    TEST_CASE(10);
++    TEST_CASE(11);
++    TEST_CASE(12);
++    TEST_CASE(13);
++    TEST_CASE(14);
++    TEST_CASE(15);
++    TEST_CASE(16);
++    TEST_CASE(17);
++    TEST_CASE(18);
++    TEST_CASE(19);
++    TEST_CASE(20);
++
++# ifdef OPENSSL_CPUID_OBJ
++    {
++        size_t start, stop, gcm_t, ctr_t, OPENSSL_rdtsc();
++        union {
++            u64 u;
++            u8 c[1024];
++        } buf;
++        int i;
++
++        AES_set_encrypt_key(K1, sizeof(K1) * 8, &key);
++        CRYPTO_gcm128_init(&ctx, &key, (block128_f) AES_encrypt);
++        CRYPTO_gcm128_setiv(&ctx, IV1, sizeof(IV1));
++
++        CRYPTO_gcm128_encrypt(&ctx, buf.c, buf.c, sizeof(buf));
++        start = OPENSSL_rdtsc();
++        CRYPTO_gcm128_encrypt(&ctx, buf.c, buf.c, sizeof(buf));
++        gcm_t = OPENSSL_rdtsc() - start;
++
++        CRYPTO_ctr128_encrypt(buf.c, buf.c, sizeof(buf),
++                              &key, ctx.Yi.c, ctx.EKi.c, &ctx.mres,
++                              (block128_f) AES_encrypt);
++        start = OPENSSL_rdtsc();
++        CRYPTO_ctr128_encrypt(buf.c, buf.c, sizeof(buf),
++                              &key, ctx.Yi.c, ctx.EKi.c, &ctx.mres,
++                              (block128_f) AES_encrypt);
++        ctr_t = OPENSSL_rdtsc() - start;
++
++        printf("%.2f-%.2f=%.2f\n",
++               gcm_t / (double)sizeof(buf),
++               ctr_t / (double)sizeof(buf),
++               (gcm_t - ctr_t) / (double)sizeof(buf));
++#  ifdef GHASH
++        {
++            void (*gcm_ghash_p) (u64 Xi[2], const u128 Htable[16],
++                                 const u8 *inp, size_t len) = ctx.ghash;
++
++            GHASH((&ctx), buf.c, sizeof(buf));
++            start = OPENSSL_rdtsc();
++            for (i = 0; i < 100; ++i)
++                GHASH((&ctx), buf.c, sizeof(buf));
++            gcm_t = OPENSSL_rdtsc() - start;
++            printf("%.2f\n", gcm_t / (double)sizeof(buf) / (double)i);
++        }
++#  endif
++    }
++# endif
++
++    return ret;
++}
++#endif
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/modes/modes_lcl.h b/CryptoPkg/Library/OpensslLib/openssl/crypto/modes/modes_lcl.h
+new file mode 100644
+index 0000000..7a1603b
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/modes/modes_lcl.h
+@@ -0,0 +1,185 @@
++/*
++ * Copyright 2010-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++
++#if (defined(_WIN32) || defined(_WIN64)) && !defined(__MINGW32__)
++typedef __int64 i64;
++typedef unsigned __int64 u64;
++# define U64(C) C##UI64
++#elif defined(__arch64__)
++typedef long i64;
++typedef unsigned long u64;
++# define U64(C) C##UL
++#else
++typedef long long i64;
++typedef unsigned long long u64;
++# define U64(C) C##ULL
++#endif
++
++typedef unsigned int u32;
++typedef unsigned char u8;
++
++#define STRICT_ALIGNMENT 1
++#ifndef PEDANTIC
++# if defined(__i386)    || defined(__i386__)    || \
++     defined(__x86_64)  || defined(__x86_64__)  || \
++     defined(_M_IX86)   || defined(_M_AMD64)    || defined(_M_X64) || \
++     defined(__aarch64__)                       || \
++     defined(__s390__)  || defined(__s390x__)
++#  undef STRICT_ALIGNMENT
++# endif
++#endif
++
++#if !defined(PEDANTIC) && !defined(OPENSSL_NO_ASM) && !defined(OPENSSL_NO_INLINE_ASM)
++# if defined(__GNUC__) && __GNUC__>=2
++#  if defined(__x86_64) || defined(__x86_64__)
++#   define BSWAP8(x) ({ u64 ret_=(x);                   \
++                        asm ("bswapq %0"                \
++                        : "+r"(ret_));   ret_;          })
++#   define BSWAP4(x) ({ u32 ret_=(x);                   \
++                        asm ("bswapl %0"                \
++                        : "+r"(ret_));   ret_;          })
++#  elif (defined(__i386) || defined(__i386__)) && !defined(I386_ONLY)
++#   define BSWAP8(x) ({ u32 lo_=(u64)(x)>>32,hi_=(x);   \
++                        asm ("bswapl %0; bswapl %1"     \
++                        : "+r"(hi_),"+r"(lo_));         \
++                        (u64)hi_<<32|lo_;               })
++#   define BSWAP4(x) ({ u32 ret_=(x);                   \
++                        asm ("bswapl %0"                \
++                        : "+r"(ret_));   ret_;          })
++#  elif defined(__aarch64__)
++#   define BSWAP8(x) ({ u64 ret_;                       \
++                        asm ("rev %0,%1"                \
++                        : "=r"(ret_) : "r"(x)); ret_;   })
++#   define BSWAP4(x) ({ u32 ret_;                       \
++                        asm ("rev %w0,%w1"              \
++                        : "=r"(ret_) : "r"(x)); ret_;   })
++#  elif (defined(__arm__) || defined(__arm)) && !defined(STRICT_ALIGNMENT)
++#   define BSWAP8(x) ({ u32 lo_=(u64)(x)>>32,hi_=(x);   \
++                        asm ("rev %0,%0; rev %1,%1"     \
++                        : "+r"(hi_),"+r"(lo_));         \
++                        (u64)hi_<<32|lo_;               })
++#   define BSWAP4(x) ({ u32 ret_;                       \
++                        asm ("rev %0,%1"                \
++                        : "=r"(ret_) : "r"((u32)(x)));  \
++                        ret_;                           })
++#  endif
++# elif defined(_MSC_VER)
++#  if _MSC_VER>=1300
++#   pragma intrinsic(_byteswap_uint64,_byteswap_ulong)
++#   define BSWAP8(x)    _byteswap_uint64((u64)(x))
++#   define BSWAP4(x)    _byteswap_ulong((u32)(x))
++#  elif defined(_M_IX86)
++__inline u32 _bswap4(u32 val)
++{
++_asm mov eax, val _asm bswap eax}
++#   define BSWAP4(x)    _bswap4(x)
++#  endif
++# endif
++#endif
++#if defined(BSWAP4) && !defined(STRICT_ALIGNMENT)
++# define GETU32(p)       BSWAP4(*(const u32 *)(p))
++# define PUTU32(p,v)     *(u32 *)(p) = BSWAP4(v)
++#else
++# define GETU32(p)       ((u32)(p)[0]<<24|(u32)(p)[1]<<16|(u32)(p)[2]<<8|(u32)(p)[3])
++# define PUTU32(p,v)     ((p)[0]=(u8)((v)>>24),(p)[1]=(u8)((v)>>16),(p)[2]=(u8)((v)>>8),(p)[3]=(u8)(v))
++#endif
++/*- GCM definitions */ typedef struct {
++    u64 hi, lo;
++} u128;
++
++#ifdef  TABLE_BITS
++# undef  TABLE_BITS
++#endif
++/*
++ * Even though permitted values for TABLE_BITS are 8, 4 and 1, it should
++ * never be set to 8 [or 1]. For further information see gcm128.c.
++ */
++#define TABLE_BITS 4
++
++struct gcm128_context {
++    /* Following 6 names follow names in GCM specification */
++    union {
++        u64 u[2];
++        u32 d[4];
++        u8 c[16];
++        size_t t[16 / sizeof(size_t)];
++    } Yi, EKi, EK0, len, Xi, H;
++    /*
++     * Relative position of Xi, H and pre-computed Htable is used in some
++     * assembler modules, i.e. don't change the order!
++     */
++#if TABLE_BITS==8
++    u128 Htable[256];
++#else
++    u128 Htable[16];
++    void (*gmult) (u64 Xi[2], const u128 Htable[16]);
++    void (*ghash) (u64 Xi[2], const u128 Htable[16], const u8 *inp,
++                   size_t len);
++#endif
++    unsigned int mres, ares;
++    block128_f block;
++    void *key;
++};
++
++struct xts128_context {
++    void *key1, *key2;
++    block128_f block1, block2;
++};
++
++struct ccm128_context {
++    union {
++        u64 u[2];
++        u8 c[16];
++    } nonce, cmac;
++    u64 blocks;
++    block128_f block;
++    void *key;
++};
++
++#ifndef OPENSSL_NO_OCB
++
++typedef union {
++    u64 a[2];
++    unsigned char c[16];
++} OCB_BLOCK;
++# define ocb_block16_xor(in1,in2,out) \
++    ( (out)->a[0]=(in1)->a[0]^(in2)->a[0], \
++      (out)->a[1]=(in1)->a[1]^(in2)->a[1] )
++# if STRICT_ALIGNMENT
++#  define ocb_block16_xor_misaligned(in1,in2,out) \
++    ocb_block_xor((in1)->c,(in2)->c,16,(out)->c)
++# else
++#  define ocb_block16_xor_misaligned ocb_block16_xor
++# endif
++
++struct ocb128_context {
++    /* Need both encrypt and decrypt key schedules for decryption */
++    block128_f encrypt;
++    block128_f decrypt;
++    void *keyenc;
++    void *keydec;
++    ocb128_f stream;    /* direction dependent */
++    /* Key dependent variables. Can be reused if key remains the same */
++    size_t l_index;
++    size_t max_l_index;
++    OCB_BLOCK l_star;
++    OCB_BLOCK l_dollar;
++    OCB_BLOCK *l;
++    /* Must be reset for each session */
++    u64 blocks_hashed;
++    u64 blocks_processed;
++    OCB_BLOCK tag;
++    OCB_BLOCK offset_aad;
++    OCB_BLOCK sum;
++    OCB_BLOCK offset;
++    OCB_BLOCK checksum;
++};
++#endif                          /* OPENSSL_NO_OCB */
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/modes/ocb128.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/modes/ocb128.c
+new file mode 100644
+index 0000000..c3bd13b
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/modes/ocb128.c
+@@ -0,0 +1,568 @@
++/*
++ * Copyright 2014-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include 
++#include "modes_lcl.h"
++
++#ifndef OPENSSL_NO_OCB
++
++/*
++ * Calculate the number of binary trailing zero's in any given number
++ */
++static u32 ocb_ntz(u64 n)
++{
++    u32 cnt = 0;
++
++    /*
++     * We do a right-to-left simple sequential search. This is surprisingly
++     * efficient as the distribution of trailing zeros is not uniform,
++     * e.g. the number of possible inputs with no trailing zeros is equal to
++     * the number with 1 or more; the number with exactly 1 is equal to the
++     * number with 2 or more, etc. Checking the last two bits covers 75% of
++     * all numbers. Checking the last three covers 87.5%
++     */
++    while (!(n & 1)) {
++        n >>= 1;
++        cnt++;
++    }
++    return cnt;
++}
++
++/*
++ * Shift a block of 16 bytes left by shift bits
++ */
++static void ocb_block_lshift(const unsigned char *in, size_t shift,
++                             unsigned char *out)
++{
++    unsigned char shift_mask;
++    int i;
++    unsigned char mask[15];
++
++    shift_mask = 0xff;
++    shift_mask <<= (8 - shift);
++    for (i = 15; i >= 0; i--) {
++        if (i > 0) {
++            mask[i - 1] = in[i] & shift_mask;
++            mask[i - 1] >>= 8 - shift;
++        }
++        out[i] = in[i] << shift;
++
++        if (i != 15) {
++            out[i] ^= mask[i];
++        }
++    }
++}
++
++/*
++ * Perform a "double" operation as per OCB spec
++ */
++static void ocb_double(OCB_BLOCK *in, OCB_BLOCK *out)
++{
++    unsigned char mask;
++
++    /*
++     * Calculate the mask based on the most significant bit. There are more
++     * efficient ways to do this - but this way is constant time
++     */
++    mask = in->c[0] & 0x80;
++    mask >>= 7;
++    mask *= 135;
++
++    ocb_block_lshift(in->c, 1, out->c);
++
++    out->c[15] ^= mask;
++}
++
++/*
++ * Perform an xor on in1 and in2 - each of len bytes. Store result in out
++ */
++static void ocb_block_xor(const unsigned char *in1,
++                          const unsigned char *in2, size_t len,
++                          unsigned char *out)
++{
++    size_t i;
++    for (i = 0; i < len; i++) {
++        out[i] = in1[i] ^ in2[i];
++    }
++}
++
++/*
++ * Lookup L_index in our lookup table. If we haven't already got it we need to
++ * calculate it
++ */
++static OCB_BLOCK *ocb_lookup_l(OCB128_CONTEXT *ctx, size_t idx)
++{
++    size_t l_index = ctx->l_index;
++
++    if (idx <= l_index) {
++        return ctx->l + idx;
++    }
++
++    /* We don't have it - so calculate it */
++    if (idx >= ctx->max_l_index) {
++        void *tmp_ptr;
++        /*
++         * Each additional entry allows to process almost double as
++         * much data, so that in linear world the table will need to
++         * be expanded with smaller and smaller increments. Originally
++         * it was doubling in size, which was a waste. Growing it
++         * linearly is not formally optimal, but is simpler to implement.
++         * We grow table by minimally required 4*n that would accommodate
++         * the index.
++         */
++        ctx->max_l_index += (idx - ctx->max_l_index + 4) & ~3;
++        tmp_ptr =
++            OPENSSL_realloc(ctx->l, ctx->max_l_index * sizeof(OCB_BLOCK));
++        if (tmp_ptr == NULL) /* prevent ctx->l from being clobbered */
++            return NULL;
++        ctx->l = tmp_ptr;
++    }
++    while (l_index < idx) {
++        ocb_double(ctx->l + l_index, ctx->l + l_index + 1);
++        l_index++;
++    }
++    ctx->l_index = l_index;
++
++    return ctx->l + idx;
++}
++
++/*
++ * Create a new OCB128_CONTEXT
++ */
++OCB128_CONTEXT *CRYPTO_ocb128_new(void *keyenc, void *keydec,
++                                  block128_f encrypt, block128_f decrypt,
++                                  ocb128_f stream)
++{
++    OCB128_CONTEXT *octx;
++    int ret;
++
++    if ((octx = OPENSSL_malloc(sizeof(*octx))) != NULL) {
++        ret = CRYPTO_ocb128_init(octx, keyenc, keydec, encrypt, decrypt,
++                                 stream);
++        if (ret)
++            return octx;
++        OPENSSL_free(octx);
++    }
++
++    return NULL;
++}
++
++/*
++ * Initialise an existing OCB128_CONTEXT
++ */
++int CRYPTO_ocb128_init(OCB128_CONTEXT *ctx, void *keyenc, void *keydec,
++                       block128_f encrypt, block128_f decrypt,
++                       ocb128_f stream)
++{
++    memset(ctx, 0, sizeof(*ctx));
++    ctx->l_index = 0;
++    ctx->max_l_index = 5;
++    ctx->l = OPENSSL_malloc(ctx->max_l_index * 16);
++    if (ctx->l == NULL)
++        return 0;
++
++    /*
++     * We set both the encryption and decryption key schedules - decryption
++     * needs both. Don't really need decryption schedule if only doing
++     * encryption - but it simplifies things to take it anyway
++     */
++    ctx->encrypt = encrypt;
++    ctx->decrypt = decrypt;
++    ctx->stream = stream;
++    ctx->keyenc = keyenc;
++    ctx->keydec = keydec;
++
++    /* L_* = ENCIPHER(K, zeros(128)) */
++    ctx->encrypt(ctx->l_star.c, ctx->l_star.c, ctx->keyenc);
++
++    /* L_$ = double(L_*) */
++    ocb_double(&ctx->l_star, &ctx->l_dollar);
++
++    /* L_0 = double(L_$) */
++    ocb_double(&ctx->l_dollar, ctx->l);
++
++    /* L_{i} = double(L_{i-1}) */
++    ocb_double(ctx->l, ctx->l+1);
++    ocb_double(ctx->l+1, ctx->l+2);
++    ocb_double(ctx->l+2, ctx->l+3);
++    ocb_double(ctx->l+3, ctx->l+4);
++    ctx->l_index = 4;   /* enough to process up to 496 bytes */
++
++    return 1;
++}
++
++/*
++ * Copy an OCB128_CONTEXT object
++ */
++int CRYPTO_ocb128_copy_ctx(OCB128_CONTEXT *dest, OCB128_CONTEXT *src,
++                           void *keyenc, void *keydec)
++{
++    memcpy(dest, src, sizeof(OCB128_CONTEXT));
++    if (keyenc)
++        dest->keyenc = keyenc;
++    if (keydec)
++        dest->keydec = keydec;
++    if (src->l) {
++        dest->l = OPENSSL_malloc(src->max_l_index * 16);
++        if (dest->l == NULL)
++            return 0;
++        memcpy(dest->l, src->l, (src->l_index + 1) * 16);
++    }
++    return 1;
++}
++
++/*
++ * Set the IV to be used for this operation. Must be 1 - 15 bytes.
++ */
++int CRYPTO_ocb128_setiv(OCB128_CONTEXT *ctx, const unsigned char *iv,
++                        size_t len, size_t taglen)
++{
++    unsigned char ktop[16], tmp[16], mask;
++    unsigned char stretch[24], nonce[16];
++    size_t bottom, shift;
++
++    /*
++     * Spec says IV is 120 bits or fewer - it allows non byte aligned lengths.
++     * We don't support this at this stage
++     */
++    if ((len > 15) || (len < 1) || (taglen > 16) || (taglen < 1)) {
++        return -1;
++    }
++
++    /* Nonce = num2str(TAGLEN mod 128,7) || zeros(120-bitlen(N)) || 1 || N */
++    nonce[0] = ((taglen * 8) % 128) << 1;
++    memset(nonce + 1, 0, 15);
++    memcpy(nonce + 16 - len, iv, len);
++    nonce[15 - len] |= 1;
++
++    /* Ktop = ENCIPHER(K, Nonce[1..122] || zeros(6)) */
++    memcpy(tmp, nonce, 16);
++    tmp[15] &= 0xc0;
++    ctx->encrypt(tmp, ktop, ctx->keyenc);
++
++    /* Stretch = Ktop || (Ktop[1..64] xor Ktop[9..72]) */
++    memcpy(stretch, ktop, 16);
++    ocb_block_xor(ktop, ktop + 1, 8, stretch + 16);
++
++    /* bottom = str2num(Nonce[123..128]) */
++    bottom = nonce[15] & 0x3f;
++
++    /* Offset_0 = Stretch[1+bottom..128+bottom] */
++    shift = bottom % 8;
++    ocb_block_lshift(stretch + (bottom / 8), shift, ctx->offset.c);
++    mask = 0xff;
++    mask <<= 8 - shift;
++    ctx->offset.c[15] |=
++        (*(stretch + (bottom / 8) + 16) & mask) >> (8 - shift);
++
++    return 1;
++}
++
++/*
++ * Provide any AAD. This can be called multiple times. Only the final time can
++ * have a partial block
++ */
++int CRYPTO_ocb128_aad(OCB128_CONTEXT *ctx, const unsigned char *aad,
++                      size_t len)
++{
++    u64 i, all_num_blocks;
++    size_t num_blocks, last_len;
++    OCB_BLOCK tmp1;
++    OCB_BLOCK tmp2;
++
++    /* Calculate the number of blocks of AAD provided now, and so far */
++    num_blocks = len / 16;
++    all_num_blocks = num_blocks + ctx->blocks_hashed;
++
++    /* Loop through all full blocks of AAD */
++    for (i = ctx->blocks_hashed + 1; i <= all_num_blocks; i++) {
++        OCB_BLOCK *lookup;
++        OCB_BLOCK *aad_block;
++
++        /* Offset_i = Offset_{i-1} xor L_{ntz(i)} */
++        lookup = ocb_lookup_l(ctx, ocb_ntz(i));
++        if (lookup == NULL)
++            return 0;
++        ocb_block16_xor(&ctx->offset_aad, lookup, &ctx->offset_aad);
++
++        /* Sum_i = Sum_{i-1} xor ENCIPHER(K, A_i xor Offset_i) */
++        aad_block = (OCB_BLOCK *)(aad + ((i - ctx->blocks_hashed - 1) * 16));
++        ocb_block16_xor(&ctx->offset_aad, aad_block, &tmp1);
++        ctx->encrypt(tmp1.c, tmp2.c, ctx->keyenc);
++        ocb_block16_xor(&ctx->sum, &tmp2, &ctx->sum);
++    }
++
++    /*
++     * Check if we have any partial blocks left over. This is only valid in the
++     * last call to this function
++     */
++    last_len = len % 16;
++
++    if (last_len > 0) {
++        /* Offset_* = Offset_m xor L_* */
++        ocb_block16_xor(&ctx->offset_aad, &ctx->l_star, &ctx->offset_aad);
++
++        /* CipherInput = (A_* || 1 || zeros(127-bitlen(A_*))) xor Offset_* */
++        memset(&tmp1, 0, 16);
++        memcpy(&tmp1, aad + (num_blocks * 16), last_len);
++        ((unsigned char *)&tmp1)[last_len] = 0x80;
++        ocb_block16_xor(&ctx->offset_aad, &tmp1, &tmp2);
++
++        /* Sum = Sum_m xor ENCIPHER(K, CipherInput) */
++        ctx->encrypt(tmp2.c, tmp1.c, ctx->keyenc);
++        ocb_block16_xor(&ctx->sum, &tmp1, &ctx->sum);
++    }
++
++    ctx->blocks_hashed = all_num_blocks;
++
++    return 1;
++}
++
++/*
++ * Provide any data to be encrypted. This can be called multiple times. Only
++ * the final time can have a partial block
++ */
++int CRYPTO_ocb128_encrypt(OCB128_CONTEXT *ctx,
++                          const unsigned char *in, unsigned char *out,
++                          size_t len)
++{
++    u64 i, all_num_blocks;
++    size_t num_blocks, last_len;
++    OCB_BLOCK tmp1;
++    OCB_BLOCK tmp2;
++    OCB_BLOCK pad;
++
++    /*
++     * Calculate the number of blocks of data to be encrypted provided now, and
++     * so far
++     */
++    num_blocks = len / 16;
++    all_num_blocks = num_blocks + ctx->blocks_processed;
++
++    if (num_blocks && all_num_blocks == (size_t)all_num_blocks
++        && ctx->stream != NULL) {
++        size_t max_idx = 0, top = (size_t)all_num_blocks;
++
++        /*
++         * See how many L_{i} entries we need to process data at hand
++         * and pre-compute missing entries in the table [if any]...
++         */
++        while (top >>= 1)
++            max_idx++;
++        if (ocb_lookup_l(ctx, max_idx) == NULL)
++            return 0;
++
++        ctx->stream(in, out, num_blocks, ctx->keyenc,
++                    (size_t)ctx->blocks_processed + 1, ctx->offset.c,
++                    (const unsigned char (*)[16])ctx->l, ctx->checksum.c);
++    } else {
++        /* Loop through all full blocks to be encrypted */
++        for (i = ctx->blocks_processed + 1; i <= all_num_blocks; i++) {
++            OCB_BLOCK *lookup;
++            OCB_BLOCK *inblock;
++            OCB_BLOCK *outblock;
++
++            /* Offset_i = Offset_{i-1} xor L_{ntz(i)} */
++            lookup = ocb_lookup_l(ctx, ocb_ntz(i));
++            if (lookup == NULL)
++                return 0;
++            ocb_block16_xor(&ctx->offset, lookup, &ctx->offset);
++
++            /* C_i = Offset_i xor ENCIPHER(K, P_i xor Offset_i) */
++            inblock =
++                (OCB_BLOCK *)(in + ((i - ctx->blocks_processed - 1) * 16));
++            ocb_block16_xor_misaligned(&ctx->offset, inblock, &tmp1);
++            /* Checksum_i = Checksum_{i-1} xor P_i */
++            ocb_block16_xor_misaligned(&ctx->checksum, inblock, &ctx->checksum);
++            ctx->encrypt(tmp1.c, tmp2.c, ctx->keyenc);
++            outblock =
++                (OCB_BLOCK *)(out + ((i - ctx->blocks_processed - 1) * 16));
++            ocb_block16_xor_misaligned(&ctx->offset, &tmp2, outblock);
++        }
++    }
++
++    /*
++     * Check if we have any partial blocks left over. This is only valid in the
++     * last call to this function
++     */
++    last_len = len % 16;
++
++    if (last_len > 0) {
++        /* Offset_* = Offset_m xor L_* */
++        ocb_block16_xor(&ctx->offset, &ctx->l_star, &ctx->offset);
++
++        /* Pad = ENCIPHER(K, Offset_*) */
++        ctx->encrypt(ctx->offset.c, pad.c, ctx->keyenc);
++
++        /* C_* = P_* xor Pad[1..bitlen(P_*)] */
++        ocb_block_xor(in + (len / 16) * 16, (unsigned char *)&pad, last_len,
++                      out + (num_blocks * 16));
++
++        /* Checksum_* = Checksum_m xor (P_* || 1 || zeros(127-bitlen(P_*))) */
++        memset(&tmp1, 0, 16);
++        memcpy(&tmp1, in + (len / 16) * 16, last_len);
++        ((unsigned char *)(&tmp1))[last_len] = 0x80;
++        ocb_block16_xor(&ctx->checksum, &tmp1, &ctx->checksum);
++    }
++
++    ctx->blocks_processed = all_num_blocks;
++
++    return 1;
++}
++
++/*
++ * Provide any data to be decrypted. This can be called multiple times. Only
++ * the final time can have a partial block
++ */
++int CRYPTO_ocb128_decrypt(OCB128_CONTEXT *ctx,
++                          const unsigned char *in, unsigned char *out,
++                          size_t len)
++{
++    u64 i, all_num_blocks;
++    size_t num_blocks, last_len;
++    OCB_BLOCK tmp1;
++    OCB_BLOCK tmp2;
++    OCB_BLOCK pad;
++
++    /*
++     * Calculate the number of blocks of data to be decrypted provided now, and
++     * so far
++     */
++    num_blocks = len / 16;
++    all_num_blocks = num_blocks + ctx->blocks_processed;
++
++    if (num_blocks && all_num_blocks == (size_t)all_num_blocks
++        && ctx->stream != NULL) {
++        size_t max_idx = 0, top = (size_t)all_num_blocks;
++
++        /*
++         * See how many L_{i} entries we need to process data at hand
++         * and pre-compute missing entries in the table [if any]...
++         */
++        while (top >>= 1)
++            max_idx++;
++        if (ocb_lookup_l(ctx, max_idx) == NULL)
++            return 0;
++
++        ctx->stream(in, out, num_blocks, ctx->keydec,
++                    (size_t)ctx->blocks_processed + 1, ctx->offset.c,
++                    (const unsigned char (*)[16])ctx->l, ctx->checksum.c);
++    } else {
++        /* Loop through all full blocks to be decrypted */
++        for (i = ctx->blocks_processed + 1; i <= all_num_blocks; i++) {
++            OCB_BLOCK *inblock;
++            OCB_BLOCK *outblock;
++
++            /* Offset_i = Offset_{i-1} xor L_{ntz(i)} */
++            OCB_BLOCK *lookup = ocb_lookup_l(ctx, ocb_ntz(i));
++            if (lookup == NULL)
++                return 0;
++            ocb_block16_xor(&ctx->offset, lookup, &ctx->offset);
++
++            /* P_i = Offset_i xor DECIPHER(K, C_i xor Offset_i) */
++            inblock =
++                (OCB_BLOCK *)(in + ((i - ctx->blocks_processed - 1) * 16));
++            ocb_block16_xor_misaligned(&ctx->offset, inblock, &tmp1);
++            ctx->decrypt(tmp1.c, tmp2.c, ctx->keydec);
++            outblock =
++                (OCB_BLOCK *)(out + ((i - ctx->blocks_processed - 1) * 16));
++            ocb_block16_xor_misaligned(&ctx->offset, &tmp2, outblock);
++
++            /* Checksum_i = Checksum_{i-1} xor P_i */
++            ocb_block16_xor_misaligned(&ctx->checksum, outblock, &ctx->checksum);
++        }
++    }
++
++    /*
++     * Check if we have any partial blocks left over. This is only valid in the
++     * last call to this function
++     */
++    last_len = len % 16;
++
++    if (last_len > 0) {
++        /* Offset_* = Offset_m xor L_* */
++        ocb_block16_xor(&ctx->offset, &ctx->l_star, &ctx->offset);
++
++        /* Pad = ENCIPHER(K, Offset_*) */
++        ctx->encrypt(ctx->offset.c, pad.c, ctx->keyenc);
++
++        /* P_* = C_* xor Pad[1..bitlen(C_*)] */
++        ocb_block_xor(in + (len / 16) * 16, (unsigned char *)&pad, last_len,
++                      out + (num_blocks * 16));
++
++        /* Checksum_* = Checksum_m xor (P_* || 1 || zeros(127-bitlen(P_*))) */
++        memset(&tmp1, 0, 16);
++        memcpy(&tmp1, out + (len / 16) * 16, last_len);
++        ((unsigned char *)(&tmp1))[last_len] = 0x80;
++        ocb_block16_xor(&ctx->checksum, &tmp1, &ctx->checksum);
++    }
++
++    ctx->blocks_processed = all_num_blocks;
++
++    return 1;
++}
++
++/*
++ * Calculate the tag and verify it against the supplied tag
++ */
++int CRYPTO_ocb128_finish(OCB128_CONTEXT *ctx, const unsigned char *tag,
++                         size_t len)
++{
++    OCB_BLOCK tmp1, tmp2;
++
++    /*
++     * Tag = ENCIPHER(K, Checksum_* xor Offset_* xor L_$) xor HASH(K,A)
++     */
++    ocb_block16_xor(&ctx->checksum, &ctx->offset, &tmp1);
++    ocb_block16_xor(&tmp1, &ctx->l_dollar, &tmp2);
++    ctx->encrypt(tmp2.c, tmp1.c, ctx->keyenc);
++    ocb_block16_xor(&tmp1, &ctx->sum, &ctx->tag);
++
++    if (len > 16 || len < 1) {
++        return -1;
++    }
++
++    /* Compare the tag if we've been given one */
++    if (tag)
++        return CRYPTO_memcmp(&ctx->tag, tag, len);
++    else
++        return -1;
++}
++
++/*
++ * Retrieve the calculated tag
++ */
++int CRYPTO_ocb128_tag(OCB128_CONTEXT *ctx, unsigned char *tag, size_t len)
++{
++    if (len > 16 || len < 1) {
++        return -1;
++    }
++
++    /* Calculate the tag */
++    CRYPTO_ocb128_finish(ctx, NULL, 0);
++
++    /* Copy the tag into the supplied buffer */
++    memcpy(tag, &ctx->tag, len);
++
++    return 1;
++}
++
++/*
++ * Release all resources
++ */
++void CRYPTO_ocb128_cleanup(OCB128_CONTEXT *ctx)
++{
++    if (ctx) {
++        OPENSSL_clear_free(ctx->l, ctx->max_l_index * 16);
++        OPENSSL_cleanse(ctx, sizeof(*ctx));
++    }
++}
++
++#endif                          /* OPENSSL_NO_OCB */
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/modes/ofb128.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/modes/ofb128.c
+new file mode 100644
+index 0000000..8309256
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/modes/ofb128.c
+@@ -0,0 +1,74 @@
++/*
++ * Copyright 2008-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include "modes_lcl.h"
++#include 
++
++/*
++ * The input and output encrypted as though 128bit ofb mode is being used.
++ * The extra state information to record how much of the 128bit block we have
++ * used is contained in *num;
++ */
++void CRYPTO_ofb128_encrypt(const unsigned char *in, unsigned char *out,
++                           size_t len, const void *key,
++                           unsigned char ivec[16], int *num, block128_f block)
++{
++    unsigned int n;
++    size_t l = 0;
++
++    n = *num;
++
++#if !defined(OPENSSL_SMALL_FOOTPRINT)
++    if (16 % sizeof(size_t) == 0) { /* always true actually */
++        do {
++            while (n && len) {
++                *(out++) = *(in++) ^ ivec[n];
++                --len;
++                n = (n + 1) % 16;
++            }
++# if defined(STRICT_ALIGNMENT)
++            if (((size_t)in | (size_t)out | (size_t)ivec) % sizeof(size_t) !=
++                0)
++                break;
++# endif
++            while (len >= 16) {
++                (*block) (ivec, ivec, key);
++                for (; n < 16; n += sizeof(size_t))
++                    *(size_t *)(out + n) =
++                        *(size_t *)(in + n) ^ *(size_t *)(ivec + n);
++                len -= 16;
++                out += 16;
++                in += 16;
++                n = 0;
++            }
++            if (len) {
++                (*block) (ivec, ivec, key);
++                while (len--) {
++                    out[n] = in[n] ^ ivec[n];
++                    ++n;
++                }
++            }
++            *num = n;
++            return;
++        } while (0);
++    }
++    /* the rest would be commonly eliminated by x86* compiler */
++#endif
++    while (l < len) {
++        if (n == 0) {
++            (*block) (ivec, ivec, key);
++        }
++        out[l] = in[l] ^ ivec[n];
++        ++l;
++        n = (n + 1) % 16;
++    }
++
++    *num = n;
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/modes/wrap128.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/modes/wrap128.c
+new file mode 100644
+index 0000000..46809a0
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/modes/wrap128.c
+@@ -0,0 +1,329 @@
++/*
++ * Copyright 2013-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++/**  Beware!
++ *
++ *  Following wrapping modes were designed for AES but this implementation
++ *  allows you to use them for any 128 bit block cipher.
++ */
++
++#include "internal/cryptlib.h"
++#include 
++
++/** RFC 3394 section 2.2.3.1 Default Initial Value */
++static const unsigned char default_iv[] = {
++    0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6,
++};
++
++/** RFC 5649 section 3 Alternative Initial Value 32-bit constant */
++static const unsigned char default_aiv[] = {
++    0xA6, 0x59, 0x59, 0xA6
++};
++
++/** Input size limit: lower than maximum of standards but far larger than
++ *  anything that will be used in practice.
++ */
++#define CRYPTO128_WRAP_MAX (1UL << 31)
++
++/** Wrapping according to RFC 3394 section 2.2.1.
++ *
++ *  @param[in]  key    Key value.
++ *  @param[in]  iv     IV value. Length = 8 bytes. NULL = use default_iv.
++ *  @param[in]  in     Plaintext as n 64-bit blocks, n >= 2.
++ *  @param[in]  inlen  Length of in.
++ *  @param[out] out    Ciphertext. Minimal buffer length = (inlen + 8) bytes.
++ *                     Input and output buffers can overlap if block function
++ *                     supports that.
++ *  @param[in]  block  Block processing function.
++ *  @return            0 if inlen does not consist of n 64-bit blocks, n >= 2.
++ *                     or if inlen > CRYPTO128_WRAP_MAX.
++ *                     Output length if wrapping succeeded.
++ */
++size_t CRYPTO_128_wrap(void *key, const unsigned char *iv,
++                       unsigned char *out,
++                       const unsigned char *in, size_t inlen,
++                       block128_f block)
++{
++    unsigned char *A, B[16], *R;
++    size_t i, j, t;
++    if ((inlen & 0x7) || (inlen < 16) || (inlen > CRYPTO128_WRAP_MAX))
++        return 0;
++    A = B;
++    t = 1;
++    memmove(out + 8, in, inlen);
++    if (!iv)
++        iv = default_iv;
++
++    memcpy(A, iv, 8);
++
++    for (j = 0; j < 6; j++) {
++        R = out + 8;
++        for (i = 0; i < inlen; i += 8, t++, R += 8) {
++            memcpy(B + 8, R, 8);
++            block(B, B, key);
++            A[7] ^= (unsigned char)(t & 0xff);
++            if (t > 0xff) {
++                A[6] ^= (unsigned char)((t >> 8) & 0xff);
++                A[5] ^= (unsigned char)((t >> 16) & 0xff);
++                A[4] ^= (unsigned char)((t >> 24) & 0xff);
++            }
++            memcpy(R, B + 8, 8);
++        }
++    }
++    memcpy(out, A, 8);
++    return inlen + 8;
++}
++
++/** Unwrapping according to RFC 3394 section 2.2.2 steps 1-2.
++ *  The IV check (step 3) is responsibility of the caller.
++ *
++ *  @param[in]  key    Key value.
++ *  @param[out] iv     Unchecked IV value. Minimal buffer length = 8 bytes.
++ *  @param[out] out    Plaintext without IV.
++ *                     Minimal buffer length = (inlen - 8) bytes.
++ *                     Input and output buffers can overlap if block function
++ *                     supports that.
++ *  @param[in]  in     Ciphertext as n 64-bit blocks.
++ *  @param[in]  inlen  Length of in.
++ *  @param[in]  block  Block processing function.
++ *  @return            0 if inlen is out of range [24, CRYPTO128_WRAP_MAX]
++ *                     or if inlen is not a multiple of 8.
++ *                     Output length otherwise.
++ */
++static size_t crypto_128_unwrap_raw(void *key, unsigned char *iv,
++                                    unsigned char *out,
++                                    const unsigned char *in, size_t inlen,
++                                    block128_f block)
++{
++    unsigned char *A, B[16], *R;
++    size_t i, j, t;
++    inlen -= 8;
++    if ((inlen & 0x7) || (inlen < 16) || (inlen > CRYPTO128_WRAP_MAX))
++        return 0;
++    A = B;
++    t = 6 * (inlen >> 3);
++    memcpy(A, in, 8);
++    memmove(out, in + 8, inlen);
++    for (j = 0; j < 6; j++) {
++        R = out + inlen - 8;
++        for (i = 0; i < inlen; i += 8, t--, R -= 8) {
++            A[7] ^= (unsigned char)(t & 0xff);
++            if (t > 0xff) {
++                A[6] ^= (unsigned char)((t >> 8) & 0xff);
++                A[5] ^= (unsigned char)((t >> 16) & 0xff);
++                A[4] ^= (unsigned char)((t >> 24) & 0xff);
++            }
++            memcpy(B + 8, R, 8);
++            block(B, B, key);
++            memcpy(R, B + 8, 8);
++        }
++    }
++    memcpy(iv, A, 8);
++    return inlen;
++}
++
++/** Unwrapping according to RFC 3394 section 2.2.2, including the IV check.
++ *  The first block of plaintext has to match the supplied IV, otherwise an
++ *  error is returned.
++ *
++ *  @param[in]  key    Key value.
++ *  @param[out] iv     IV value to match against. Length = 8 bytes.
++ *                     NULL = use default_iv.
++ *  @param[out] out    Plaintext without IV.
++ *                     Minimal buffer length = (inlen - 8) bytes.
++ *                     Input and output buffers can overlap if block function
++ *                     supports that.
++ *  @param[in]  in     Ciphertext as n 64-bit blocks.
++ *  @param[in]  inlen  Length of in.
++ *  @param[in]  block  Block processing function.
++ *  @return            0 if inlen is out of range [24, CRYPTO128_WRAP_MAX]
++ *                     or if inlen is not a multiple of 8
++ *                     or if IV doesn't match expected value.
++ *                     Output length otherwise.
++ */
++size_t CRYPTO_128_unwrap(void *key, const unsigned char *iv,
++                         unsigned char *out, const unsigned char *in,
++                         size_t inlen, block128_f block)
++{
++    size_t ret;
++    unsigned char got_iv[8];
++
++    ret = crypto_128_unwrap_raw(key, got_iv, out, in, inlen, block);
++    if (ret == 0)
++        return 0;
++
++    if (!iv)
++        iv = default_iv;
++    if (CRYPTO_memcmp(got_iv, iv, 8)) {
++        OPENSSL_cleanse(out, ret);
++        return 0;
++    }
++    return ret;
++}
++
++/** Wrapping according to RFC 5649 section 4.1.
++ *
++ *  @param[in]  key    Key value.
++ *  @param[in]  icv    (Non-standard) IV, 4 bytes. NULL = use default_aiv.
++ *  @param[out] out    Ciphertext. Minimal buffer length = (inlen + 15) bytes.
++ *                     Input and output buffers can overlap if block function
++ *                     supports that.
++ *  @param[in]  in     Plaintext as n 64-bit blocks, n >= 2.
++ *  @param[in]  inlen  Length of in.
++ *  @param[in]  block  Block processing function.
++ *  @return            0 if inlen is out of range [1, CRYPTO128_WRAP_MAX].
++ *                     Output length if wrapping succeeded.
++ */
++size_t CRYPTO_128_wrap_pad(void *key, const unsigned char *icv,
++                           unsigned char *out,
++                           const unsigned char *in, size_t inlen,
++                           block128_f block)
++{
++    /* n: number of 64-bit blocks in the padded key data
++     *
++     * If length of plain text is not a multiple of 8, pad the plain text octet
++     * string on the right with octets of zeros, where final length is the
++     * smallest multiple of 8 that is greater than length of plain text.
++     * If length of plain text is a multiple of 8, then there is no padding. */
++    const size_t blocks_padded = (inlen + 7) / 8; /* CEILING(m/8) */
++    const size_t padded_len = blocks_padded * 8;
++    const size_t padding_len = padded_len - inlen;
++    /* RFC 5649 section 3: Alternative Initial Value */
++    unsigned char aiv[8];
++    int ret;
++
++    /* Section 1: use 32-bit fixed field for plaintext octet length */
++    if (inlen == 0 || inlen >= CRYPTO128_WRAP_MAX)
++        return 0;
++
++    /* Section 3: Alternative Initial Value */
++    if (!icv)
++        memcpy(aiv, default_aiv, 4);
++    else
++        memcpy(aiv, icv, 4);    /* Standard doesn't mention this. */
++
++    aiv[4] = (inlen >> 24) & 0xFF;
++    aiv[5] = (inlen >> 16) & 0xFF;
++    aiv[6] = (inlen >> 8) & 0xFF;
++    aiv[7] = inlen & 0xFF;
++
++    if (padded_len == 8) {
++        /*
++         * Section 4.1 - special case in step 2: If the padded plaintext
++         * contains exactly eight octets, then prepend the AIV and encrypt
++         * the resulting 128-bit block using AES in ECB mode.
++         */
++        memmove(out + 8, in, inlen);
++        memcpy(out, aiv, 8);
++        memset(out + 8 + inlen, 0, padding_len);
++        block(out, out, key);
++        ret = 16;               /* AIV + padded input */
++    } else {
++        memmove(out, in, inlen);
++        memset(out + inlen, 0, padding_len); /* Section 4.1 step 1 */
++        ret = CRYPTO_128_wrap(key, aiv, out, out, padded_len, block);
++    }
++
++    return ret;
++}
++
++/** Unwrapping according to RFC 5649 section 4.2.
++ *
++ *  @param[in]  key    Key value.
++ *  @param[in]  icv    (Non-standard) IV, 4 bytes. NULL = use default_aiv.
++ *  @param[out] out    Plaintext. Minimal buffer length = inlen bytes.
++ *                     Input and output buffers can overlap if block function
++ *                     supports that.
++ *  @param[in]  in     Ciphertext as n 64-bit blocks.
++ *  @param[in]  inlen  Length of in.
++ *  @param[in]  block  Block processing function.
++ *  @return            0 if inlen is out of range [16, CRYPTO128_WRAP_MAX],
++ *                     or if inlen is not a multiple of 8
++ *                     or if IV and message length indicator doesn't match.
++ *                     Output length if unwrapping succeeded and IV matches.
++ */
++size_t CRYPTO_128_unwrap_pad(void *key, const unsigned char *icv,
++                             unsigned char *out,
++                             const unsigned char *in, size_t inlen,
++                             block128_f block)
++{
++    /* n: number of 64-bit blocks in the padded key data */
++    size_t n = inlen / 8 - 1;
++    size_t padded_len;
++    size_t padding_len;
++    size_t ptext_len;
++    /* RFC 5649 section 3: Alternative Initial Value */
++    unsigned char aiv[8];
++    static unsigned char zeros[8] = { 0x0 };
++    size_t ret;
++
++    /* Section 4.2: Ciphertext length has to be (n+1) 64-bit blocks. */
++    if ((inlen & 0x7) != 0 || inlen < 16 || inlen >= CRYPTO128_WRAP_MAX)
++        return 0;
++
++    memmove(out, in, inlen);
++    if (inlen == 16) {
++        /*
++         * Section 4.2 - special case in step 1: When n=1, the ciphertext
++         * contains exactly two 64-bit blocks and they are decrypted as a
++         * single AES block using AES in ECB mode: AIV | P[1] = DEC(K, C[0] |
++         * C[1])
++         */
++        block(out, out, key);
++        memcpy(aiv, out, 8);
++        /* Remove AIV */
++        memmove(out, out + 8, 8);
++        padded_len = 8;
++    } else {
++        padded_len = inlen - 8;
++        ret = crypto_128_unwrap_raw(key, aiv, out, out, inlen, block);
++        if (padded_len != ret) {
++            OPENSSL_cleanse(out, inlen);
++            return 0;
++        }
++    }
++
++    /*
++     * Section 3: AIV checks: Check that MSB(32,A) = A65959A6. Optionally a
++     * user-supplied value can be used (even if standard doesn't mention
++     * this).
++     */
++    if ((!icv && CRYPTO_memcmp(aiv, default_aiv, 4))
++        || (icv && CRYPTO_memcmp(aiv, icv, 4))) {
++        OPENSSL_cleanse(out, inlen);
++        return 0;
++    }
++
++    /*
++     * Check that 8*(n-1) < LSB(32,AIV) <= 8*n. If so, let ptext_len =
++     * LSB(32,AIV).
++     */
++
++    ptext_len =   ((unsigned int)aiv[4] << 24)
++                | ((unsigned int)aiv[5] << 16)
++                | ((unsigned int)aiv[6] <<  8)
++                |  (unsigned int)aiv[7];
++    if (8 * (n - 1) >= ptext_len || ptext_len > 8 * n) {
++        OPENSSL_cleanse(out, inlen);
++        return 0;
++    }
++
++    /*
++     * Check that the rightmost padding_len octets of the output data are
++     * zero.
++     */
++    padding_len = padded_len - ptext_len;
++    if (CRYPTO_memcmp(out + ptext_len, zeros, padding_len) != 0) {
++        OPENSSL_cleanse(out, inlen);
++        return 0;
++    }
++
++    /* Section 4.2 step 3: Remove padding */
++    return ptext_len;
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/modes/xts128.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/modes/xts128.c
+new file mode 100644
+index 0000000..81b1eac
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/modes/xts128.c
+@@ -0,0 +1,157 @@
++/*
++ * Copyright 2011-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include "modes_lcl.h"
++#include 
++
++int CRYPTO_xts128_encrypt(const XTS128_CONTEXT *ctx,
++                          const unsigned char iv[16],
++                          const unsigned char *inp, unsigned char *out,
++                          size_t len, int enc)
++{
++    const union {
++        long one;
++        char little;
++    } is_endian = {
++        1
++    };
++    union {
++        u64 u[2];
++        u32 d[4];
++        u8 c[16];
++    } tweak, scratch;
++    unsigned int i;
++
++    if (len < 16)
++        return -1;
++
++    memcpy(tweak.c, iv, 16);
++
++    (*ctx->block2) (tweak.c, tweak.c, ctx->key2);
++
++    if (!enc && (len % 16))
++        len -= 16;
++
++    while (len >= 16) {
++#if defined(STRICT_ALIGNMENT)
++        memcpy(scratch.c, inp, 16);
++        scratch.u[0] ^= tweak.u[0];
++        scratch.u[1] ^= tweak.u[1];
++#else
++        scratch.u[0] = ((u64 *)inp)[0] ^ tweak.u[0];
++        scratch.u[1] = ((u64 *)inp)[1] ^ tweak.u[1];
++#endif
++        (*ctx->block1) (scratch.c, scratch.c, ctx->key1);
++#if defined(STRICT_ALIGNMENT)
++        scratch.u[0] ^= tweak.u[0];
++        scratch.u[1] ^= tweak.u[1];
++        memcpy(out, scratch.c, 16);
++#else
++        ((u64 *)out)[0] = scratch.u[0] ^= tweak.u[0];
++        ((u64 *)out)[1] = scratch.u[1] ^= tweak.u[1];
++#endif
++        inp += 16;
++        out += 16;
++        len -= 16;
++
++        if (len == 0)
++            return 0;
++
++        if (is_endian.little) {
++            unsigned int carry, res;
++
++            res = 0x87 & (((int)tweak.d[3]) >> 31);
++            carry = (unsigned int)(tweak.u[0] >> 63);
++            tweak.u[0] = (tweak.u[0] << 1) ^ res;
++            tweak.u[1] = (tweak.u[1] << 1) | carry;
++        } else {
++            size_t c;
++
++            for (c = 0, i = 0; i < 16; ++i) {
++                /*
++                 * + substitutes for |, because c is 1 bit
++                 */
++                c += ((size_t)tweak.c[i]) << 1;
++                tweak.c[i] = (u8)c;
++                c = c >> 8;
++            }
++            tweak.c[0] ^= (u8)(0x87 & (0 - c));
++        }
++    }
++    if (enc) {
++        for (i = 0; i < len; ++i) {
++            u8 c = inp[i];
++            out[i] = scratch.c[i];
++            scratch.c[i] = c;
++        }
++        scratch.u[0] ^= tweak.u[0];
++        scratch.u[1] ^= tweak.u[1];
++        (*ctx->block1) (scratch.c, scratch.c, ctx->key1);
++        scratch.u[0] ^= tweak.u[0];
++        scratch.u[1] ^= tweak.u[1];
++        memcpy(out - 16, scratch.c, 16);
++    } else {
++        union {
++            u64 u[2];
++            u8 c[16];
++        } tweak1;
++
++        if (is_endian.little) {
++            unsigned int carry, res;
++
++            res = 0x87 & (((int)tweak.d[3]) >> 31);
++            carry = (unsigned int)(tweak.u[0] >> 63);
++            tweak1.u[0] = (tweak.u[0] << 1) ^ res;
++            tweak1.u[1] = (tweak.u[1] << 1) | carry;
++        } else {
++            size_t c;
++
++            for (c = 0, i = 0; i < 16; ++i) {
++                /*
++                 * + substitutes for |, because c is 1 bit
++                 */
++                c += ((size_t)tweak.c[i]) << 1;
++                tweak1.c[i] = (u8)c;
++                c = c >> 8;
++            }
++            tweak1.c[0] ^= (u8)(0x87 & (0 - c));
++        }
++#if defined(STRICT_ALIGNMENT)
++        memcpy(scratch.c, inp, 16);
++        scratch.u[0] ^= tweak1.u[0];
++        scratch.u[1] ^= tweak1.u[1];
++#else
++        scratch.u[0] = ((u64 *)inp)[0] ^ tweak1.u[0];
++        scratch.u[1] = ((u64 *)inp)[1] ^ tweak1.u[1];
++#endif
++        (*ctx->block1) (scratch.c, scratch.c, ctx->key1);
++        scratch.u[0] ^= tweak1.u[0];
++        scratch.u[1] ^= tweak1.u[1];
++
++        for (i = 0; i < len; ++i) {
++            u8 c = inp[16 + i];
++            out[16 + i] = scratch.c[i];
++            scratch.c[i] = c;
++        }
++        scratch.u[0] ^= tweak.u[0];
++        scratch.u[1] ^= tweak.u[1];
++        (*ctx->block1) (scratch.c, scratch.c, ctx->key1);
++#if defined(STRICT_ALIGNMENT)
++        scratch.u[0] ^= tweak.u[0];
++        scratch.u[1] ^= tweak.u[1];
++        memcpy(out, scratch.c, 16);
++#else
++        ((u64 *)out)[0] = scratch.u[0] ^ tweak.u[0];
++        ((u64 *)out)[1] = scratch.u[1] ^ tweak.u[1];
++#endif
++    }
++
++    return 0;
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/o_dir.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/o_dir.c
+new file mode 100644
+index 0000000..89c8c5c
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/o_dir.c
+@@ -0,0 +1,36 @@
++/*
++ * Copyright 2004-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include 
++
++/*
++ * The routines really come from the Levitte Programming, so to make life
++ * simple, let's just use the raw files and hack the symbols to fit our
++ * namespace.
++ */
++#define LP_DIR_CTX OPENSSL_DIR_CTX
++#define LP_dir_context_st OPENSSL_dir_context_st
++#define LP_find_file OPENSSL_DIR_read
++#define LP_find_file_end OPENSSL_DIR_end
++
++#include "internal/o_dir.h"
++
++#define LPDIR_H
++#if defined OPENSSL_SYS_UNIX || defined DJGPP
++# include "LPdir_unix.c"
++#elif defined OPENSSL_SYS_VMS
++# include "LPdir_vms.c"
++#elif defined OPENSSL_SYS_WIN32
++# include "LPdir_win32.c"
++#elif defined OPENSSL_SYS_WINCE
++# include "LPdir_wince.c"
++#else
++# include "LPdir_nyi.c"
++#endif
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/o_fips.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/o_fips.c
+new file mode 100644
+index 0000000..bf6db65
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/o_fips.c
+@@ -0,0 +1,34 @@
++/*
++ * Copyright 2011-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include "internal/cryptlib.h"
++#ifdef OPENSSL_FIPS
++# include 
++#endif
++
++int FIPS_mode(void)
++{
++#ifdef OPENSSL_FIPS
++    return FIPS_module_mode();
++#else
++    return 0;
++#endif
++}
++
++int FIPS_mode_set(int r)
++{
++#ifdef OPENSSL_FIPS
++    return FIPS_module_mode_set(r);
++#else
++    if (r == 0)
++        return 1;
++    CRYPTOerr(CRYPTO_F_FIPS_MODE_SET, CRYPTO_R_FIPS_MODE_NOT_SUPPORTED);
++    return 0;
++#endif
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/o_fopen.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/o_fopen.c
+new file mode 100644
+index 0000000..a3a0065
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/o_fopen.c
+@@ -0,0 +1,103 @@
++/*
++ * Copyright 2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include "internal/cryptlib.h"
++
++#if !defined(OPENSSL_NO_STDIO)
++
++# include 
++
++FILE *openssl_fopen(const char *filename, const char *mode)
++{
++    FILE *file = NULL;
++# if defined(_WIN32) && defined(CP_UTF8)
++    int sz, len_0 = (int)strlen(filename) + 1;
++    DWORD flags;
++
++    /*
++     * Basically there are three cases to cover: a) filename is
++     * pure ASCII string; b) actual UTF-8 encoded string and
++     * c) locale-ized string, i.e. one containing 8-bit
++     * characters that are meaningful in current system locale.
++     * If filename is pure ASCII or real UTF-8 encoded string,
++     * MultiByteToWideChar succeeds and _wfopen works. If
++     * filename is locale-ized string, chances are that
++     * MultiByteToWideChar fails reporting
++     * ERROR_NO_UNICODE_TRANSLATION, in which case we fall
++     * back to fopen...
++     */
++    if ((sz = MultiByteToWideChar(CP_UTF8, (flags = MB_ERR_INVALID_CHARS),
++                                  filename, len_0, NULL, 0)) > 0 ||
++        (GetLastError() == ERROR_INVALID_FLAGS &&
++         (sz = MultiByteToWideChar(CP_UTF8, (flags = 0),
++                                   filename, len_0, NULL, 0)) > 0)
++        ) {
++        WCHAR wmode[8];
++        WCHAR *wfilename = _alloca(sz * sizeof(WCHAR));
++
++        if (MultiByteToWideChar(CP_UTF8, flags,
++                                filename, len_0, wfilename, sz) &&
++            MultiByteToWideChar(CP_UTF8, 0, mode, strlen(mode) + 1,
++                                wmode, OSSL_NELEM(wmode)) &&
++            (file = _wfopen(wfilename, wmode)) == NULL &&
++            (errno == ENOENT || errno == EBADF)
++            ) {
++            /*
++             * UTF-8 decode succeeded, but no file, filename
++             * could still have been locale-ized...
++             */
++            file = fopen(filename, mode);
++        }
++    } else if (GetLastError() == ERROR_NO_UNICODE_TRANSLATION) {
++        file = fopen(filename, mode);
++    }
++# elif defined(__DJGPP__)
++    {
++        char *newname = NULL;
++
++        if (!HAS_LFN_SUPPORT(filename)) {
++            char *iterator;
++            char lastchar;
++
++            newname = OPENSSL_malloc(strlen(filename) + 1);
++            if (newname == NULL)
++                return NULL;
++
++            for (iterator = newname, lastchar = '\0';
++                *filename; filename++, iterator++) {
++                if (lastchar == '/' && filename[0] == '.'
++                    && filename[1] != '.' && filename[1] != '/') {
++                    /* Leading dots are not permitted in plain DOS. */
++                    *iterator = '_';
++                } else {
++                    *iterator = *filename;
++                }
++                lastchar = *filename;
++            }
++            *iterator = '\0';
++            filename = newname;
++        }
++        file = fopen(filename, mode);
++
++        OPENSSL_free(newname);
++    }
++# else
++    file = fopen(filename, mode);
++# endif
++    return file;
++}
++
++#else
++
++void *openssl_fopen(const char *filename, const char *mode)
++{
++    return NULL;
++}
++
++#endif
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/o_init.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/o_init.c
+new file mode 100644
+index 0000000..2e0c126
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/o_init.c
+@@ -0,0 +1,34 @@
++/*
++ * Copyright 2011-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include 
++#ifdef OPENSSL_FIPS
++# include 
++# include 
++#endif
++
++/*
++ * Perform any essential OpenSSL initialization operations. Currently only
++ * sets FIPS callbacks
++ */
++
++void OPENSSL_init(void)
++{
++    static int done = 0;
++    if (done)
++        return;
++    done = 1;
++#ifdef OPENSSL_FIPS
++    FIPS_set_locking_callbacks(CRYPTO_lock, CRYPTO_add_lock);
++    FIPS_set_error_callbacks(ERR_put_error, ERR_add_error_vdata);
++    FIPS_set_malloc_callbacks(CRYPTO_malloc, CRYPTO_free);
++    RAND_init_fips();
++#endif
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/o_str.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/o_str.c
+new file mode 100644
+index 0000000..beabec0
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/o_str.c
+@@ -0,0 +1,250 @@
++/*
++ * Copyright 2003-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include 
++#include 
++#include 
++#include "internal/cryptlib.h"
++#include "internal/o_str.h"
++
++int OPENSSL_memcmp(const void *v1, const void *v2, size_t n)
++{
++    const unsigned char *c1 = v1, *c2 = v2;
++    int ret = 0;
++
++    while (n && (ret = *c1 - *c2) == 0)
++        n--, c1++, c2++;
++
++    return ret;
++}
++
++char *CRYPTO_strdup(const char *str, const char* file, int line)
++{
++    char *ret;
++    size_t size;
++
++    if (str == NULL)
++        return NULL;
++    size = strlen(str) + 1;
++    ret = CRYPTO_malloc(size, file, line);
++    if (ret != NULL)
++        memcpy(ret, str, size);
++    return ret;
++}
++
++char *CRYPTO_strndup(const char *str, size_t s, const char* file, int line)
++{
++    size_t maxlen;
++    char *ret;
++
++    if (str == NULL)
++        return NULL;
++
++    maxlen = OPENSSL_strnlen(str, s);
++
++    ret = CRYPTO_malloc(maxlen + 1, file, line);
++    if (ret) {
++        memcpy(ret, str, maxlen);
++        ret[maxlen] = '\0';
++    }
++    return ret;
++}
++
++void *CRYPTO_memdup(const void *data, size_t siz, const char* file, int line)
++{
++    void *ret;
++
++    if (data == NULL || siz >= INT_MAX)
++        return NULL;
++
++    ret = CRYPTO_malloc(siz, file, line);
++    if (ret == NULL) {
++        CRYPTOerr(CRYPTO_F_CRYPTO_MEMDUP, ERR_R_MALLOC_FAILURE);
++        return NULL;
++    }
++    return memcpy(ret, data, siz);
++}
++
++size_t OPENSSL_strnlen(const char *str, size_t maxlen)
++{
++    const char *p;
++
++    for (p = str; maxlen-- != 0 && *p != '\0'; ++p) ;
++
++    return p - str;
++}
++
++size_t OPENSSL_strlcpy(char *dst, const char *src, size_t size)
++{
++    size_t l = 0;
++    for (; size > 1 && *src; size--) {
++        *dst++ = *src++;
++        l++;
++    }
++    if (size)
++        *dst = '\0';
++    return l + strlen(src);
++}
++
++size_t OPENSSL_strlcat(char *dst, const char *src, size_t size)
++{
++    size_t l = 0;
++    for (; size > 0 && *dst; size--, dst++)
++        l++;
++    return l + OPENSSL_strlcpy(dst, src, size);
++}
++
++int OPENSSL_hexchar2int(unsigned char c)
++{
++#ifdef CHARSET_EBCDIC
++    c = os_toebcdic[c];
++#endif
++
++    switch (c) {
++    case '0':
++        return 0;
++    case '1':
++        return 1;
++    case '2':
++        return 2;
++    case '3':
++        return 3;
++    case '4':
++          return 4;
++    case '5':
++          return 5;
++    case '6':
++          return 6;
++    case '7':
++          return 7;
++    case '8':
++          return 8;
++    case '9':
++          return 9;
++    case 'a': case 'A':
++          return 0x0A;
++    case 'b': case 'B':
++          return 0x0B;
++    case 'c': case 'C':
++          return 0x0C;
++    case 'd': case 'D':
++          return 0x0D;
++    case 'e': case 'E':
++          return 0x0E;
++    case 'f': case 'F':
++          return 0x0F;
++    }
++    return -1;
++}
++
++/*
++ * Give a string of hex digits convert to a buffer
++ */
++unsigned char *OPENSSL_hexstr2buf(const char *str, long *len)
++{
++    unsigned char *hexbuf, *q;
++    unsigned char ch, cl;
++    int chi, cli;
++    const unsigned char *p;
++    size_t s;
++
++    s = strlen(str);
++    if ((hexbuf = OPENSSL_malloc(s >> 1)) == NULL) {
++        CRYPTOerr(CRYPTO_F_OPENSSL_HEXSTR2BUF, ERR_R_MALLOC_FAILURE);
++        return NULL;
++    }
++    for (p = (const unsigned char *)str, q = hexbuf; *p; ) {
++        ch = *p++;
++        if (ch == ':')
++            continue;
++        cl = *p++;
++        if (!cl) {
++            CRYPTOerr(CRYPTO_F_OPENSSL_HEXSTR2BUF,
++                      CRYPTO_R_ODD_NUMBER_OF_DIGITS);
++            OPENSSL_free(hexbuf);
++            return NULL;
++        }
++        cli = OPENSSL_hexchar2int(cl);
++        chi = OPENSSL_hexchar2int(ch);
++        if (cli < 0 || chi < 0) {
++            OPENSSL_free(hexbuf);
++            CRYPTOerr(CRYPTO_F_OPENSSL_HEXSTR2BUF, CRYPTO_R_ILLEGAL_HEX_DIGIT);
++            return NULL;
++        }
++        *q++ = (unsigned char)((chi << 4) | cli);
++    }
++
++    if (len)
++        *len = q - hexbuf;
++    return hexbuf;
++}
++
++/*
++ * Given a buffer of length 'len' return a OPENSSL_malloc'ed string with its
++ * hex representation @@@ (Contents of buffer are always kept in ASCII, also
++ * on EBCDIC machines)
++ */
++char *OPENSSL_buf2hexstr(const unsigned char *buffer, long len)
++{
++    const static char hexdig[] = "0123456789ABCDEF";
++    char *tmp, *q;
++    const unsigned char *p;
++    int i;
++
++    if (len == 0)
++    {
++        return OPENSSL_zalloc(1);
++    }
++
++    if ((tmp = OPENSSL_malloc(len * 3)) == NULL) {
++        CRYPTOerr(CRYPTO_F_OPENSSL_BUF2HEXSTR, ERR_R_MALLOC_FAILURE);
++        return NULL;
++    }
++    q = tmp;
++    for (i = 0, p = buffer; i < len; i++, p++) {
++        *q++ = hexdig[(*p >> 4) & 0xf];
++        *q++ = hexdig[*p & 0xf];
++        *q++ = ':';
++    }
++    q[-1] = 0;
++#ifdef CHARSET_EBCDIC
++    ebcdic2ascii(tmp, tmp, q - tmp - 1);
++#endif
++
++    return tmp;
++}
++
++int openssl_strerror_r(int errnum, char *buf, size_t buflen)
++{
++#if defined(_MSC_VER) && _MSC_VER>=1400
++    return !strerror_s(buf, buflen, errnum);
++#elif defined(_GNU_SOURCE)
++    return strerror_r(errnum, buf, buflen) != NULL;
++#elif (_POSIX_C_SOURCE >= 200112L || _XOPEN_SOURCE >= 600)
++    /*
++     * We can use "real" strerror_r. The OpenSSL version differs in that it
++     * gives 1 on success and 0 on failure for consistency with other OpenSSL
++     * functions. Real strerror_r does it the other way around
++     */
++    return !strerror_r(errnum, buf, buflen);
++#else
++    char *err;
++    /* Fall back to non-thread safe strerror()...its all we can do */
++    if (buflen < 2)
++        return 0;
++    err = strerror(errnum);
++    /* Can this ever happen? */
++    if (err == NULL)
++        return 0;
++    strncpy(buf, err, buflen - 1);
++    buf[buflen - 1] = '\0';
++    return 1;
++#endif
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/o_time.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/o_time.c
+new file mode 100755
+index 0000000..4b902e0
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/o_time.c
+@@ -0,0 +1,360 @@
++/*
++ * Copyright 2001-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include 
++#include 
++
++#ifdef OPENSSL_SYS_VMS
++# if __CRTL_VER >= 70000000 && \
++     (defined _POSIX_C_SOURCE || !defined _ANSI_C_SOURCE)
++#  define VMS_GMTIME_OK
++# endif
++# ifndef VMS_GMTIME_OK
++#  include 
++#  include 
++#  include 
++#  include 
++#  include 
++#  include 
++# endif                         /* ndef VMS_GMTIME_OK */
++
++
++/*
++ * Needed to pick up the correct definitions and declarations in some of the
++ * DEC C Header Files (*.H).
++ */
++# define __NEW_STARLET 1
++
++# if (defined(__alpha) || defined(__ia64))
++#  include 
++# else
++
++/* VAX */
++typedef struct _ile3 {          /* Copied from ILEDEF.H for Alpha   */
++#  pragma __nomember_alignment
++    unsigned short int ile3$w_length;        /* Length of buffer in bytes */
++    unsigned short int ile3$w_code;          /* Item code value */
++    void *ile3$ps_bufaddr;                   /* Buffer address */
++    unsigned short int *ile3$ps_retlen_addr; /* Address of word for returned length */
++} ILE3;
++# endif   /* alpha || ia64    */
++#endif    /* OPENSSL_SYS_VMS  */
++
++struct tm *OPENSSL_gmtime(const time_t *timer, struct tm *result)
++{
++    struct tm *ts = NULL;
++
++#if defined(OPENSSL_THREADS) && !defined(OPENSSL_SYS_WIN32) && (!defined(OPENSSL_SYS_VMS) || defined(gmtime_r)) && !defined(OPENSSL_SYS_MACOSX)
++    if (gmtime_r(timer, result) == NULL)
++        return NULL;
++    ts = result;
++#elif !defined(OPENSSL_SYS_VMS) || defined(VMS_GMTIME_OK)
++    ts = gmtime(timer);
++    if (ts == NULL)
++        return NULL;
++
++    memcpy(result, ts, sizeof(struct tm));
++    ts = result;
++#endif
++#if defined( OPENSSL_SYS_VMS) && !defined( VMS_GMTIME_OK)
++    if (ts == NULL) {
++        static $DESCRIPTOR(tabnam, "LNM$DCL_LOGICAL");
++        static $DESCRIPTOR(lognam, "SYS$TIMEZONE_DIFFERENTIAL");
++        char logvalue[256];
++        unsigned int reslen = 0;
++# if __INITIAL_POINTER_SIZE == 64
++        ILEB_64 itemlist[2], *pitem;
++# else
++        ILE3 itemlist[2], *pitem;
++# endif
++        int status;
++        time_t t;
++
++
++        /*
++         * Setup an itemlist for the call to $TRNLNM - Translate Logical Name.
++         */
++        pitem = itemlist;
++
++# if __INITIAL_POINTER_SIZE == 64
++        pitem->ileb_64$w_mbo = 1;
++        pitem->ileb_64$w_code = LNM$_STRING;
++        pitem->ileb_64$l_mbmo = -1;
++        pitem->ileb_64$q_length = sizeof (logvalue);
++        pitem->ileb_64$pq_bufaddr = logvalue;
++        pitem->ileb_64$pq_retlen_addr = (unsigned __int64 *) &reslen;
++        pitem++;
++        /* Last item of the item list is null terminated */
++        pitem->ileb_64$q_length = pitem->ileb_64$w_code = 0;
++# else
++        pitem->ile3$w_length = sizeof (logvalue);
++        pitem->ile3$w_code = LNM$_STRING;
++        pitem->ile3$ps_bufaddr = logvalue;
++        pitem->ile3$ps_retlen_addr = (unsigned short int *) &reslen;
++        pitem++;
++        /* Last item of the item list is null terminated */
++        pitem->ile3$w_length = pitem->ile3$w_code = 0;
++# endif
++
++
++        /* Get the value for SYS$TIMEZONE_DIFFERENTIAL */
++        status = sys$trnlnm(0, &tabnam, &lognam, 0, itemlist);
++        if (!(status & 1))
++            return NULL;
++        logvalue[reslen] = '\0';
++
++        t = *timer;
++
++        /* The following is extracted from the DEC C header time.h */
++        /*
++         **  Beginning in OpenVMS Version 7.0 mktime, time, ctime, strftime
++         **  have two implementations.  One implementation is provided
++         **  for compatibility and deals with time in terms of local time,
++         **  the other __utc_* deals with time in terms of UTC.
++         */
++        /*
++         * We use the same conditions as in said time.h to check if we should
++         * assume that t contains local time (and should therefore be
++         * adjusted) or UTC (and should therefore be left untouched).
++         */
++# if __CRTL_VER < 70000000 || defined _VMS_V6_SOURCE
++        /* Get the numerical value of the equivalence string */
++        status = atoi(logvalue);
++
++        /* and use it to move time to GMT */
++        t -= status;
++# endif
++
++        /* then convert the result to the time structure */
++
++        /*
++         * Since there was no gmtime_r() to do this stuff for us, we have to
++         * do it the hard way.
++         */
++        {
++            /*-
++             * The VMS epoch is the astronomical Smithsonian date,
++               if I remember correctly, which is November 17, 1858.
++               Furthermore, time is measure in tenths of microseconds
++               and stored in quadwords (64 bit integers).  unix_epoch
++               below is January 1st 1970 expressed as a VMS time.  The
++               following code was used to get this number:
++
++               #include 
++               #include 
++               #include 
++               #include 
++
++               main()
++               {
++                 unsigned long systime[2];
++                 unsigned short epoch_values[7] =
++                   { 1970, 1, 1, 0, 0, 0, 0 };
++
++                 lib$cvt_vectim(epoch_values, systime);
++
++                 printf("%u %u", systime[0], systime[1]);
++               }
++            */
++            unsigned long unix_epoch[2] = { 1273708544, 8164711 };
++            unsigned long deltatime[2];
++            unsigned long systime[2];
++            struct vms_vectime {
++                short year, month, day, hour, minute, second, centi_second;
++            } time_values;
++            long operation;
++
++            /*
++             * Turn the number of seconds since January 1st 1970 to an
++             * internal delta time. Note that lib$cvt_to_internal_time() will
++             * assume that t is signed, and will therefore break on 32-bit
++             * systems some time in 2038.
++             */
++            operation = LIB$K_DELTA_SECONDS;
++            status = lib$cvt_to_internal_time(&operation, &t, deltatime);
++
++            /*
++             * Add the delta time with the Unix epoch and we have the current
++             * UTC time in internal format
++             */
++            status = lib$add_times(unix_epoch, deltatime, systime);
++
++            /* Turn the internal time into a time vector */
++            status = sys$numtim(&time_values, systime);
++
++            /* Fill in the struct tm with the result */
++            result->tm_sec = time_values.second;
++            result->tm_min = time_values.minute;
++            result->tm_hour = time_values.hour;
++            result->tm_mday = time_values.day;
++            result->tm_mon = time_values.month - 1;
++            result->tm_year = time_values.year - 1900;
++
++            operation = LIB$K_DAY_OF_WEEK;
++            status = lib$cvt_from_internal_time(&operation,
++                                                &result->tm_wday, systime);
++            result->tm_wday %= 7;
++
++            operation = LIB$K_DAY_OF_YEAR;
++            status = lib$cvt_from_internal_time(&operation,
++                                                &result->tm_yday, systime);
++            result->tm_yday--;
++
++            result->tm_isdst = 0; /* There's no way to know... */
++
++            ts = result;
++        }
++    }
++#endif
++    return ts;
++}
++
++/*
++ * Take a tm structure and add an offset to it. This avoids any OS issues
++ * with restricted date types and overflows which cause the year 2038
++ * problem.
++ */
++
++#define SECS_PER_DAY (24 * 60 * 60)
++
++static long date_to_julian(int y, int m, int d);
++static void julian_to_date(long jd, int *y, int *m, int *d);
++static int julian_adj(const struct tm *tm, int off_day, long offset_sec,
++                      long *pday, int *psec);
++
++int OPENSSL_gmtime_adj(struct tm *tm, int off_day, long offset_sec)
++{
++    int time_sec, time_year, time_month, time_day;
++    long time_jd;
++
++    /* Convert time and offset into Julian day and seconds */
++    if (!julian_adj(tm, off_day, offset_sec, &time_jd, &time_sec))
++        return 0;
++
++    /* Convert Julian day back to date */
++
++    julian_to_date(time_jd, &time_year, &time_month, &time_day);
++
++    if (time_year < 1900 || time_year > 9999)
++        return 0;
++
++    /* Update tm structure */
++
++    tm->tm_year = time_year - 1900;
++    tm->tm_mon = time_month - 1;
++    tm->tm_mday = time_day;
++
++    tm->tm_hour = time_sec / 3600;
++    tm->tm_min = (time_sec / 60) % 60;
++    tm->tm_sec = time_sec % 60;
++
++    return 1;
++
++}
++
++int OPENSSL_gmtime_diff(int *pday, int *psec,
++                        const struct tm *from, const struct tm *to)
++{
++    int from_sec, to_sec, diff_sec;
++    long from_jd, to_jd, diff_day;
++    if (!julian_adj(from, 0, 0, &from_jd, &from_sec))
++        return 0;
++    if (!julian_adj(to, 0, 0, &to_jd, &to_sec))
++        return 0;
++    diff_day = to_jd - from_jd;
++    diff_sec = to_sec - from_sec;
++    /* Adjust differences so both positive or both negative */
++    if (diff_day > 0 && diff_sec < 0) {
++        diff_day--;
++        diff_sec += SECS_PER_DAY;
++    }
++    if (diff_day < 0 && diff_sec > 0) {
++        diff_day++;
++        diff_sec -= SECS_PER_DAY;
++    }
++
++    if (pday)
++        *pday = (int)diff_day;
++    if (psec)
++        *psec = diff_sec;
++
++    return 1;
++
++}
++
++/* Convert tm structure and offset into julian day and seconds */
++static int julian_adj(const struct tm *tm, int off_day, long offset_sec,
++                      long *pday, int *psec)
++{
++    int offset_hms, offset_day;
++    long time_jd;
++    int time_year, time_month, time_day;
++    /* split offset into days and day seconds */
++    offset_day = offset_sec / SECS_PER_DAY;
++    /* Avoid sign issues with % operator */
++    offset_hms = offset_sec - (offset_day * SECS_PER_DAY);
++    offset_day += off_day;
++    /* Add current time seconds to offset */
++    offset_hms += tm->tm_hour * 3600 + tm->tm_min * 60 + tm->tm_sec;
++    /* Adjust day seconds if overflow */
++    if (offset_hms >= SECS_PER_DAY) {
++        offset_day++;
++        offset_hms -= SECS_PER_DAY;
++    } else if (offset_hms < 0) {
++        offset_day--;
++        offset_hms += SECS_PER_DAY;
++    }
++
++    /*
++     * Convert date of time structure into a Julian day number.
++     */
++
++    time_year = tm->tm_year + 1900;
++    time_month = tm->tm_mon + 1;
++    time_day = tm->tm_mday;
++
++    time_jd = date_to_julian(time_year, time_month, time_day);
++
++    /* Work out Julian day of new date */
++    time_jd += offset_day;
++
++    if (time_jd < 0)
++        return 0;
++
++    *pday = time_jd;
++    *psec = offset_hms;
++    return 1;
++}
++
++/*
++ * Convert date to and from julian day Uses Fliegel & Van Flandern algorithm
++ */
++static long date_to_julian(int y, int m, int d)
++{
++    return (1461 * (y + 4800 + (m - 14) / 12)) / 4 +
++        (367 * (m - 2 - 12 * ((m - 14) / 12))) / 12 -
++        (3 * ((y + 4900 + (m - 14) / 12) / 100)) / 4 + d - 32075;
++}
++
++static void julian_to_date(long jd, int *y, int *m, int *d)
++{
++    long L = jd + 68569;
++    long n = (4 * L) / 146097;
++    long i, j;
++
++    L = L - (146097 * n + 3) / 4;
++    i = (4000 * (L + 1)) / 1461001;
++    L = L - (1461 * i) / 4 + 31;
++    j = (80 * L) / 2447;
++    *d = L - (2447 * j) / 80;
++    L = j / 11;
++    *m = j + 2 - (12 * L);
++    *y = 100 * (n - 49) + i + L;
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/objects/README b/CryptoPkg/Library/OpensslLib/openssl/crypto/objects/README
+new file mode 100644
+index 0000000..cb1d216
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/objects/README
+@@ -0,0 +1,44 @@
++objects.txt syntax
++------------------
++
++To cover all the naming hacks that were previously in objects.h needed some
++kind of hacks in objects.txt.
++
++The basic syntax for adding an object is as follows:
++
++	1 2 3 4		: shortName	: Long Name
++
++		If Long Name contains only word characters and hyphen-minus
++		(0x2D) or full stop (0x2E) then Long Name is used as basis
++		for the base name in C. Otherwise, the shortName is used.
++
++		The base name (let's call it 'base') will then be used to
++		create the C macros SN_base, LN_base, NID_base and OBJ_base.
++
++		Note that if the base name contains spaces, dashes or periods,
++		those will be converte to underscore.
++
++Then there are some extra commands:
++
++	!Alias foo 1 2 3 4
++
++		This just makes a name foo for an OID.  The C macro
++		OBJ_foo will be created as a result.
++
++	!Cname foo
++
++		This makes sure that the name foo will be used as base name
++		in C.
++
++	!module foo
++	1 2 3 4		: shortName	: Long Name
++	!global
++
++		The !module command was meant to define a kind of modularity.
++		What it does is to make sure the module name is prepended
++		to the base name.  !global turns this off.  This construction
++		is not recursive.
++
++Lines starting with # are treated as comments, as well as any line starting
++with ! and not matching the commands above.
++
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/objects/build.info b/CryptoPkg/Library/OpensslLib/openssl/crypto/objects/build.info
+new file mode 100644
+index 0000000..38e2907
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/objects/build.info
+@@ -0,0 +1,3 @@
++LIBS=../../libcrypto
++SOURCE[../../libcrypto]=\
++        o_names.c obj_dat.c obj_lib.c obj_err.c obj_xref.c
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/objects/o_names.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/objects/o_names.c
+new file mode 100644
+index 0000000..ed98df8
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/objects/o_names.c
+@@ -0,0 +1,370 @@
++/*
++ * Copyright 1998-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include 
++#include 
++
++#include 
++#include 
++#include 
++#include 
++#include 
++#include "obj_lcl.h"
++
++/*
++ * We define this wrapper for two reasons. Firstly, later versions of
++ * DEC C add linkage information to certain functions, which makes it
++ * tricky to use them as values to regular function pointers.
++ * Secondly, in the EDK2 build environment, the strcmp function is
++ * actually an external function (AsciiStrCmp) with the Microsoft ABI,
++ * so we can't transparently assign function pointers to it.
++ * Arguably the latter is a stupidity of the UEFI environment, but
++ * since the wrapper solves the DEC C issue too, let's just use the
++ * same solution.
++ */
++#if defined(OPENSSL_SYS_VMS_DECC) || defined(OPENSSL_SYS_UEFI)
++static int obj_strcmp(const char *a, const char *b)
++{
++    return strcmp(a, b);
++}
++#else
++#define obj_strcmp strcmp
++#endif
++
++/*
++ * I use the ex_data stuff to manage the identifiers for the obj_name_types
++ * that applications may define.  I only really use the free function field.
++ */
++static LHASH_OF(OBJ_NAME) *names_lh = NULL;
++static int names_type_num = OBJ_NAME_TYPE_NUM;
++
++struct name_funcs_st {
++    unsigned long (*hash_func) (const char *name);
++    int (*cmp_func) (const char *a, const char *b);
++    void (*free_func) (const char *, int, const char *);
++};
++
++static STACK_OF(NAME_FUNCS) *name_funcs_stack;
++
++/*
++ * The LHASH callbacks now use the raw "void *" prototypes and do
++ * per-variable casting in the functions. This prevents function pointer
++ * casting without the need for macro-generated wrapper functions.
++ */
++
++static unsigned long obj_name_hash(const OBJ_NAME *a);
++static int obj_name_cmp(const OBJ_NAME *a, const OBJ_NAME *b);
++
++int OBJ_NAME_init(void)
++{
++    if (names_lh != NULL)
++        return (1);
++    CRYPTO_mem_ctrl(CRYPTO_MEM_CHECK_DISABLE);
++    names_lh = lh_OBJ_NAME_new(obj_name_hash, obj_name_cmp);
++    CRYPTO_mem_ctrl(CRYPTO_MEM_CHECK_ENABLE);
++    return (names_lh != NULL);
++}
++
++int OBJ_NAME_new_index(unsigned long (*hash_func) (const char *),
++                       int (*cmp_func) (const char *, const char *),
++                       void (*free_func) (const char *, int, const char *))
++{
++    int ret, i, push;
++    NAME_FUNCS *name_funcs;
++
++    if (name_funcs_stack == NULL) {
++        CRYPTO_mem_ctrl(CRYPTO_MEM_CHECK_DISABLE);
++        name_funcs_stack = sk_NAME_FUNCS_new_null();
++        CRYPTO_mem_ctrl(CRYPTO_MEM_CHECK_ENABLE);
++    }
++    if (name_funcs_stack == NULL) {
++        /* ERROR */
++        return (0);
++    }
++    ret = names_type_num;
++    names_type_num++;
++    for (i = sk_NAME_FUNCS_num(name_funcs_stack); i < names_type_num; i++) {
++        CRYPTO_mem_ctrl(CRYPTO_MEM_CHECK_DISABLE);
++        name_funcs = OPENSSL_zalloc(sizeof(*name_funcs));
++        CRYPTO_mem_ctrl(CRYPTO_MEM_CHECK_ENABLE);
++        if (name_funcs == NULL) {
++            OBJerr(OBJ_F_OBJ_NAME_NEW_INDEX, ERR_R_MALLOC_FAILURE);
++            return (0);
++        }
++        name_funcs->hash_func = OPENSSL_LH_strhash;
++        name_funcs->cmp_func = obj_strcmp;
++        CRYPTO_mem_ctrl(CRYPTO_MEM_CHECK_DISABLE);
++
++        push = sk_NAME_FUNCS_push(name_funcs_stack, name_funcs);
++        CRYPTO_mem_ctrl(CRYPTO_MEM_CHECK_ENABLE);
++
++        if (!push) {
++            OBJerr(OBJ_F_OBJ_NAME_NEW_INDEX, ERR_R_MALLOC_FAILURE);
++            OPENSSL_free(name_funcs);
++            return 0;
++        }
++    }
++    name_funcs = sk_NAME_FUNCS_value(name_funcs_stack, ret);
++    if (hash_func != NULL)
++        name_funcs->hash_func = hash_func;
++    if (cmp_func != NULL)
++        name_funcs->cmp_func = cmp_func;
++    if (free_func != NULL)
++        name_funcs->free_func = free_func;
++    return (ret);
++}
++
++static int obj_name_cmp(const OBJ_NAME *a, const OBJ_NAME *b)
++{
++    int ret;
++
++    ret = a->type - b->type;
++    if (ret == 0) {
++        if ((name_funcs_stack != NULL)
++            && (sk_NAME_FUNCS_num(name_funcs_stack) > a->type)) {
++            ret = sk_NAME_FUNCS_value(name_funcs_stack,
++                                      a->type)->cmp_func(a->name, b->name);
++        } else
++            ret = strcmp(a->name, b->name);
++    }
++    return (ret);
++}
++
++static unsigned long obj_name_hash(const OBJ_NAME *a)
++{
++    unsigned long ret;
++
++    if ((name_funcs_stack != NULL)
++        && (sk_NAME_FUNCS_num(name_funcs_stack) > a->type)) {
++        ret =
++            sk_NAME_FUNCS_value(name_funcs_stack,
++                                a->type)->hash_func(a->name);
++    } else {
++        ret = OPENSSL_LH_strhash(a->name);
++    }
++    ret ^= a->type;
++    return (ret);
++}
++
++const char *OBJ_NAME_get(const char *name, int type)
++{
++    OBJ_NAME on, *ret;
++    int num = 0, alias;
++
++    if (name == NULL)
++        return (NULL);
++    if ((names_lh == NULL) && !OBJ_NAME_init())
++        return (NULL);
++
++    alias = type & OBJ_NAME_ALIAS;
++    type &= ~OBJ_NAME_ALIAS;
++
++    on.name = name;
++    on.type = type;
++
++    for (;;) {
++        ret = lh_OBJ_NAME_retrieve(names_lh, &on);
++        if (ret == NULL)
++            return (NULL);
++        if ((ret->alias) && !alias) {
++            if (++num > 10)
++                return (NULL);
++            on.name = ret->data;
++        } else {
++            return (ret->data);
++        }
++    }
++}
++
++int OBJ_NAME_add(const char *name, int type, const char *data)
++{
++    OBJ_NAME *onp, *ret;
++    int alias;
++
++    if ((names_lh == NULL) && !OBJ_NAME_init())
++        return (0);
++
++    alias = type & OBJ_NAME_ALIAS;
++    type &= ~OBJ_NAME_ALIAS;
++
++    onp = OPENSSL_malloc(sizeof(*onp));
++    if (onp == NULL) {
++        /* ERROR */
++        return 0;
++    }
++
++    onp->name = name;
++    onp->alias = alias;
++    onp->type = type;
++    onp->data = data;
++
++    ret = lh_OBJ_NAME_insert(names_lh, onp);
++    if (ret != NULL) {
++        /* free things */
++        if ((name_funcs_stack != NULL)
++            && (sk_NAME_FUNCS_num(name_funcs_stack) > ret->type)) {
++            /*
++             * XXX: I'm not sure I understand why the free function should
++             * get three arguments... -- Richard Levitte
++             */
++            sk_NAME_FUNCS_value(name_funcs_stack,
++                                ret->type)->free_func(ret->name, ret->type,
++                                                      ret->data);
++        }
++        OPENSSL_free(ret);
++    } else {
++        if (lh_OBJ_NAME_error(names_lh)) {
++            /* ERROR */
++            OPENSSL_free(onp);
++            return 0;
++        }
++    }
++    return 1;
++}
++
++int OBJ_NAME_remove(const char *name, int type)
++{
++    OBJ_NAME on, *ret;
++
++    if (names_lh == NULL)
++        return (0);
++
++    type &= ~OBJ_NAME_ALIAS;
++    on.name = name;
++    on.type = type;
++    ret = lh_OBJ_NAME_delete(names_lh, &on);
++    if (ret != NULL) {
++        /* free things */
++        if ((name_funcs_stack != NULL)
++            && (sk_NAME_FUNCS_num(name_funcs_stack) > ret->type)) {
++            /*
++             * XXX: I'm not sure I understand why the free function should
++             * get three arguments... -- Richard Levitte
++             */
++            sk_NAME_FUNCS_value(name_funcs_stack,
++                                ret->type)->free_func(ret->name, ret->type,
++                                                      ret->data);
++        }
++        OPENSSL_free(ret);
++        return (1);
++    } else
++        return (0);
++}
++
++typedef struct {
++    int type;
++    void (*fn) (const OBJ_NAME *, void *arg);
++    void *arg;
++} OBJ_DOALL;
++
++static void do_all_fn(const OBJ_NAME *name, OBJ_DOALL *d)
++{
++    if (name->type == d->type)
++        d->fn(name, d->arg);
++}
++
++IMPLEMENT_LHASH_DOALL_ARG_CONST(OBJ_NAME, OBJ_DOALL);
++
++void OBJ_NAME_do_all(int type, void (*fn) (const OBJ_NAME *, void *arg),
++                     void *arg)
++{
++    OBJ_DOALL d;
++
++    d.type = type;
++    d.fn = fn;
++    d.arg = arg;
++
++    lh_OBJ_NAME_doall_OBJ_DOALL(names_lh, do_all_fn, &d);
++}
++
++struct doall_sorted {
++    int type;
++    int n;
++    const OBJ_NAME **names;
++};
++
++static void do_all_sorted_fn(const OBJ_NAME *name, void *d_)
++{
++    struct doall_sorted *d = d_;
++
++    if (name->type != d->type)
++        return;
++
++    d->names[d->n++] = name;
++}
++
++static int do_all_sorted_cmp(const void *n1_, const void *n2_)
++{
++    const OBJ_NAME *const *n1 = n1_;
++    const OBJ_NAME *const *n2 = n2_;
++
++    return strcmp((*n1)->name, (*n2)->name);
++}
++
++void OBJ_NAME_do_all_sorted(int type,
++                            void (*fn) (const OBJ_NAME *, void *arg),
++                            void *arg)
++{
++    struct doall_sorted d;
++    int n;
++
++    d.type = type;
++    d.names =
++        OPENSSL_malloc(sizeof(*d.names) * lh_OBJ_NAME_num_items(names_lh));
++    /* Really should return an error if !d.names...but its a void function! */
++    if (d.names != NULL) {
++        d.n = 0;
++        OBJ_NAME_do_all(type, do_all_sorted_fn, &d);
++
++        qsort((void *)d.names, d.n, sizeof(*d.names), do_all_sorted_cmp);
++
++        for (n = 0; n < d.n; ++n)
++            fn(d.names[n], arg);
++
++        OPENSSL_free((void *)d.names);
++    }
++}
++
++static int free_type;
++
++static void names_lh_free_doall(OBJ_NAME *onp)
++{
++    if (onp == NULL)
++        return;
++
++    if (free_type < 0 || free_type == onp->type)
++        OBJ_NAME_remove(onp->name, onp->type);
++}
++
++static void name_funcs_free(NAME_FUNCS *ptr)
++{
++    OPENSSL_free(ptr);
++}
++
++void OBJ_NAME_cleanup(int type)
++{
++    unsigned long down_load;
++
++    if (names_lh == NULL)
++        return;
++
++    free_type = type;
++    down_load = lh_OBJ_NAME_get_down_load(names_lh);
++    lh_OBJ_NAME_set_down_load(names_lh, 0);
++
++    lh_OBJ_NAME_doall(names_lh, names_lh_free_doall);
++    if (type < 0) {
++        lh_OBJ_NAME_free(names_lh);
++        sk_NAME_FUNCS_pop_free(name_funcs_stack, name_funcs_free);
++        names_lh = NULL;
++        name_funcs_stack = NULL;
++    } else
++        lh_OBJ_NAME_set_down_load(names_lh, down_load);
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/objects/obj_dat.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/objects/obj_dat.c
+new file mode 100644
+index 0000000..259851b
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/objects/obj_dat.c
+@@ -0,0 +1,728 @@
++/*
++ * Copyright 1995-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include 
++#include 
++#include "internal/cryptlib.h"
++#include 
++#include 
++#include "internal/objects.h"
++#include 
++#include "internal/asn1_int.h"
++#include "obj_lcl.h"
++
++/* obj_dat.h is generated from objects.h by obj_dat.pl */
++#include "obj_dat.h"
++
++DECLARE_OBJ_BSEARCH_CMP_FN(const ASN1_OBJECT *, unsigned int, sn);
++DECLARE_OBJ_BSEARCH_CMP_FN(const ASN1_OBJECT *, unsigned int, ln);
++DECLARE_OBJ_BSEARCH_CMP_FN(const ASN1_OBJECT *, unsigned int, obj);
++
++#define ADDED_DATA      0
++#define ADDED_SNAME     1
++#define ADDED_LNAME     2
++#define ADDED_NID       3
++
++struct added_obj_st {
++    int type;
++    ASN1_OBJECT *obj;
++};
++
++static int new_nid = NUM_NID;
++static LHASH_OF(ADDED_OBJ) *added = NULL;
++
++static int sn_cmp(const ASN1_OBJECT *const *a, const unsigned int *b)
++{
++    return (strcmp((*a)->sn, nid_objs[*b].sn));
++}
++
++IMPLEMENT_OBJ_BSEARCH_CMP_FN(const ASN1_OBJECT *, unsigned int, sn);
++
++static int ln_cmp(const ASN1_OBJECT *const *a, const unsigned int *b)
++{
++    return (strcmp((*a)->ln, nid_objs[*b].ln));
++}
++
++IMPLEMENT_OBJ_BSEARCH_CMP_FN(const ASN1_OBJECT *, unsigned int, ln);
++
++static unsigned long added_obj_hash(const ADDED_OBJ *ca)
++{
++    const ASN1_OBJECT *a;
++    int i;
++    unsigned long ret = 0;
++    unsigned char *p;
++
++    a = ca->obj;
++    switch (ca->type) {
++    case ADDED_DATA:
++        ret = a->length << 20L;
++        p = (unsigned char *)a->data;
++        for (i = 0; i < a->length; i++)
++            ret ^= p[i] << ((i * 3) % 24);
++        break;
++    case ADDED_SNAME:
++        ret = OPENSSL_LH_strhash(a->sn);
++        break;
++    case ADDED_LNAME:
++        ret = OPENSSL_LH_strhash(a->ln);
++        break;
++    case ADDED_NID:
++        ret = a->nid;
++        break;
++    default:
++        /* abort(); */
++        return 0;
++    }
++    ret &= 0x3fffffffL;
++    ret |= ((unsigned long)ca->type) << 30L;
++    return (ret);
++}
++
++static int added_obj_cmp(const ADDED_OBJ *ca, const ADDED_OBJ *cb)
++{
++    ASN1_OBJECT *a, *b;
++    int i;
++
++    i = ca->type - cb->type;
++    if (i)
++        return (i);
++    a = ca->obj;
++    b = cb->obj;
++    switch (ca->type) {
++    case ADDED_DATA:
++        i = (a->length - b->length);
++        if (i)
++            return (i);
++        return (memcmp(a->data, b->data, (size_t)a->length));
++    case ADDED_SNAME:
++        if (a->sn == NULL)
++            return (-1);
++        else if (b->sn == NULL)
++            return (1);
++        else
++            return (strcmp(a->sn, b->sn));
++    case ADDED_LNAME:
++        if (a->ln == NULL)
++            return (-1);
++        else if (b->ln == NULL)
++            return (1);
++        else
++            return (strcmp(a->ln, b->ln));
++    case ADDED_NID:
++        return (a->nid - b->nid);
++    default:
++        /* abort(); */
++        return 0;
++    }
++}
++
++static int init_added(void)
++{
++    if (added != NULL)
++        return (1);
++    added = lh_ADDED_OBJ_new(added_obj_hash, added_obj_cmp);
++    return (added != NULL);
++}
++
++static void cleanup1_doall(ADDED_OBJ *a)
++{
++    a->obj->nid = 0;
++    a->obj->flags |= ASN1_OBJECT_FLAG_DYNAMIC |
++        ASN1_OBJECT_FLAG_DYNAMIC_STRINGS | ASN1_OBJECT_FLAG_DYNAMIC_DATA;
++}
++
++static void cleanup2_doall(ADDED_OBJ *a)
++{
++    a->obj->nid++;
++}
++
++static void cleanup3_doall(ADDED_OBJ *a)
++{
++    if (--a->obj->nid == 0)
++        ASN1_OBJECT_free(a->obj);
++    OPENSSL_free(a);
++}
++
++void obj_cleanup_int(void)
++{
++    if (added == NULL)
++        return;
++    lh_ADDED_OBJ_set_down_load(added, 0);
++    lh_ADDED_OBJ_doall(added, cleanup1_doall); /* zero counters */
++    lh_ADDED_OBJ_doall(added, cleanup2_doall); /* set counters */
++    lh_ADDED_OBJ_doall(added, cleanup3_doall); /* free objects */
++    lh_ADDED_OBJ_free(added);
++    added = NULL;
++}
++
++int OBJ_new_nid(int num)
++{
++    int i;
++
++    i = new_nid;
++    new_nid += num;
++    return (i);
++}
++
++int OBJ_add_object(const ASN1_OBJECT *obj)
++{
++    ASN1_OBJECT *o;
++    ADDED_OBJ *ao[4] = { NULL, NULL, NULL, NULL }, *aop;
++    int i;
++
++    if (added == NULL)
++        if (!init_added())
++            return (0);
++    if ((o = OBJ_dup(obj)) == NULL)
++        goto err;
++    if ((ao[ADDED_NID] = OPENSSL_malloc(sizeof(*ao[0]))) == NULL)
++        goto err2;
++    if ((o->length != 0) && (obj->data != NULL))
++        if ((ao[ADDED_DATA] = OPENSSL_malloc(sizeof(*ao[0]))) == NULL)
++            goto err2;
++    if (o->sn != NULL)
++        if ((ao[ADDED_SNAME] = OPENSSL_malloc(sizeof(*ao[0]))) == NULL)
++            goto err2;
++    if (o->ln != NULL)
++        if ((ao[ADDED_LNAME] = OPENSSL_malloc(sizeof(*ao[0]))) == NULL)
++            goto err2;
++
++    for (i = ADDED_DATA; i <= ADDED_NID; i++) {
++        if (ao[i] != NULL) {
++            ao[i]->type = i;
++            ao[i]->obj = o;
++            aop = lh_ADDED_OBJ_insert(added, ao[i]);
++            /* memory leak, but should not normally matter */
++            OPENSSL_free(aop);
++        }
++    }
++    o->flags &=
++        ~(ASN1_OBJECT_FLAG_DYNAMIC | ASN1_OBJECT_FLAG_DYNAMIC_STRINGS |
++          ASN1_OBJECT_FLAG_DYNAMIC_DATA);
++
++    return (o->nid);
++ err2:
++    OBJerr(OBJ_F_OBJ_ADD_OBJECT, ERR_R_MALLOC_FAILURE);
++ err:
++    for (i = ADDED_DATA; i <= ADDED_NID; i++)
++        OPENSSL_free(ao[i]);
++    OPENSSL_free(o);
++    return (NID_undef);
++}
++
++ASN1_OBJECT *OBJ_nid2obj(int n)
++{
++    ADDED_OBJ ad, *adp;
++    ASN1_OBJECT ob;
++
++    if ((n >= 0) && (n < NUM_NID)) {
++        if ((n != NID_undef) && (nid_objs[n].nid == NID_undef)) {
++            OBJerr(OBJ_F_OBJ_NID2OBJ, OBJ_R_UNKNOWN_NID);
++            return (NULL);
++        }
++        return ((ASN1_OBJECT *)&(nid_objs[n]));
++    } else if (added == NULL)
++        return (NULL);
++    else {
++        ad.type = ADDED_NID;
++        ad.obj = &ob;
++        ob.nid = n;
++        adp = lh_ADDED_OBJ_retrieve(added, &ad);
++        if (adp != NULL)
++            return (adp->obj);
++        else {
++            OBJerr(OBJ_F_OBJ_NID2OBJ, OBJ_R_UNKNOWN_NID);
++            return (NULL);
++        }
++    }
++}
++
++const char *OBJ_nid2sn(int n)
++{
++    ADDED_OBJ ad, *adp;
++    ASN1_OBJECT ob;
++
++    if ((n >= 0) && (n < NUM_NID)) {
++        if ((n != NID_undef) && (nid_objs[n].nid == NID_undef)) {
++            OBJerr(OBJ_F_OBJ_NID2SN, OBJ_R_UNKNOWN_NID);
++            return (NULL);
++        }
++        return (nid_objs[n].sn);
++    } else if (added == NULL)
++        return (NULL);
++    else {
++        ad.type = ADDED_NID;
++        ad.obj = &ob;
++        ob.nid = n;
++        adp = lh_ADDED_OBJ_retrieve(added, &ad);
++        if (adp != NULL)
++            return (adp->obj->sn);
++        else {
++            OBJerr(OBJ_F_OBJ_NID2SN, OBJ_R_UNKNOWN_NID);
++            return (NULL);
++        }
++    }
++}
++
++const char *OBJ_nid2ln(int n)
++{
++    ADDED_OBJ ad, *adp;
++    ASN1_OBJECT ob;
++
++    if ((n >= 0) && (n < NUM_NID)) {
++        if ((n != NID_undef) && (nid_objs[n].nid == NID_undef)) {
++            OBJerr(OBJ_F_OBJ_NID2LN, OBJ_R_UNKNOWN_NID);
++            return (NULL);
++        }
++        return (nid_objs[n].ln);
++    } else if (added == NULL)
++        return (NULL);
++    else {
++        ad.type = ADDED_NID;
++        ad.obj = &ob;
++        ob.nid = n;
++        adp = lh_ADDED_OBJ_retrieve(added, &ad);
++        if (adp != NULL)
++            return (adp->obj->ln);
++        else {
++            OBJerr(OBJ_F_OBJ_NID2LN, OBJ_R_UNKNOWN_NID);
++            return (NULL);
++        }
++    }
++}
++
++static int obj_cmp(const ASN1_OBJECT *const *ap, const unsigned int *bp)
++{
++    int j;
++    const ASN1_OBJECT *a = *ap;
++    const ASN1_OBJECT *b = &nid_objs[*bp];
++
++    j = (a->length - b->length);
++    if (j)
++        return (j);
++    if (a->length == 0)
++        return 0;
++    return (memcmp(a->data, b->data, a->length));
++}
++
++IMPLEMENT_OBJ_BSEARCH_CMP_FN(const ASN1_OBJECT *, unsigned int, obj);
++
++int OBJ_obj2nid(const ASN1_OBJECT *a)
++{
++    const unsigned int *op;
++    ADDED_OBJ ad, *adp;
++
++    if (a == NULL)
++        return (NID_undef);
++    if (a->nid != 0)
++        return (a->nid);
++
++    if (a->length == 0)
++        return NID_undef;
++
++    if (added != NULL) {
++        ad.type = ADDED_DATA;
++        ad.obj = (ASN1_OBJECT *)a; /* XXX: ugly but harmless */
++        adp = lh_ADDED_OBJ_retrieve(added, &ad);
++        if (adp != NULL)
++            return (adp->obj->nid);
++    }
++    op = OBJ_bsearch_obj(&a, obj_objs, NUM_OBJ);
++    if (op == NULL)
++        return (NID_undef);
++    return (nid_objs[*op].nid);
++}
++
++/*
++ * Convert an object name into an ASN1_OBJECT if "noname" is not set then
++ * search for short and long names first. This will convert the "dotted" form
++ * into an object: unlike OBJ_txt2nid it can be used with any objects, not
++ * just registered ones.
++ */
++
++ASN1_OBJECT *OBJ_txt2obj(const char *s, int no_name)
++{
++    int nid = NID_undef;
++    ASN1_OBJECT *op = NULL;
++    unsigned char *buf;
++    unsigned char *p;
++    const unsigned char *cp;
++    int i, j;
++
++    if (!no_name) {
++        if (((nid = OBJ_sn2nid(s)) != NID_undef) ||
++            ((nid = OBJ_ln2nid(s)) != NID_undef))
++            return OBJ_nid2obj(nid);
++    }
++
++    /* Work out size of content octets */
++    i = a2d_ASN1_OBJECT(NULL, 0, s, -1);
++    if (i <= 0) {
++        /* Don't clear the error */
++        /*
++         * ERR_clear_error();
++         */
++        return NULL;
++    }
++    /* Work out total size */
++    j = ASN1_object_size(0, i, V_ASN1_OBJECT);
++    if (j < 0)
++        return NULL;
++
++    if ((buf = OPENSSL_malloc(j)) == NULL)
++        return NULL;
++
++    p = buf;
++    /* Write out tag+length */
++    ASN1_put_object(&p, 0, i, V_ASN1_OBJECT, V_ASN1_UNIVERSAL);
++    /* Write out contents */
++    a2d_ASN1_OBJECT(p, i, s, -1);
++
++    cp = buf;
++    op = d2i_ASN1_OBJECT(NULL, &cp, j);
++    OPENSSL_free(buf);
++    return op;
++}
++
++int OBJ_obj2txt(char *buf, int buf_len, const ASN1_OBJECT *a, int no_name)
++{
++    int i, n = 0, len, nid, first, use_bn;
++    BIGNUM *bl;
++    unsigned long l;
++    const unsigned char *p;
++    char tbuf[DECIMAL_SIZE(i) + DECIMAL_SIZE(l) + 2];
++
++    /* Ensure that, at every state, |buf| is NUL-terminated. */
++    if (buf && buf_len > 0)
++        buf[0] = '\0';
++
++    if ((a == NULL) || (a->data == NULL))
++        return (0);
++
++    if (!no_name && (nid = OBJ_obj2nid(a)) != NID_undef) {
++        const char *s;
++        s = OBJ_nid2ln(nid);
++        if (s == NULL)
++            s = OBJ_nid2sn(nid);
++        if (s) {
++            if (buf)
++                OPENSSL_strlcpy(buf, s, buf_len);
++            n = strlen(s);
++            return n;
++        }
++    }
++
++    len = a->length;
++    p = a->data;
++
++    first = 1;
++    bl = NULL;
++
++    while (len > 0) {
++        l = 0;
++        use_bn = 0;
++        for (;;) {
++            unsigned char c = *p++;
++            len--;
++            if ((len == 0) && (c & 0x80))
++                goto err;
++            if (use_bn) {
++                if (!BN_add_word(bl, c & 0x7f))
++                    goto err;
++            } else
++                l |= c & 0x7f;
++            if (!(c & 0x80))
++                break;
++            if (!use_bn && (l > (ULONG_MAX >> 7L))) {
++                if (bl == NULL && (bl = BN_new()) == NULL)
++                    goto err;
++                if (!BN_set_word(bl, l))
++                    goto err;
++                use_bn = 1;
++            }
++            if (use_bn) {
++                if (!BN_lshift(bl, bl, 7))
++                    goto err;
++            } else
++                l <<= 7L;
++        }
++
++        if (first) {
++            first = 0;
++            if (l >= 80) {
++                i = 2;
++                if (use_bn) {
++                    if (!BN_sub_word(bl, 80))
++                        goto err;
++                } else
++                    l -= 80;
++            } else {
++                i = (int)(l / 40);
++                l -= (long)(i * 40);
++            }
++            if (buf && (buf_len > 1)) {
++                *buf++ = i + '0';
++                *buf = '\0';
++                buf_len--;
++            }
++            n++;
++        }
++
++        if (use_bn) {
++            char *bndec;
++            bndec = BN_bn2dec(bl);
++            if (!bndec)
++                goto err;
++            i = strlen(bndec);
++            if (buf) {
++                if (buf_len > 1) {
++                    *buf++ = '.';
++                    *buf = '\0';
++                    buf_len--;
++                }
++                OPENSSL_strlcpy(buf, bndec, buf_len);
++                if (i > buf_len) {
++                    buf += buf_len;
++                    buf_len = 0;
++                } else {
++                    buf += i;
++                    buf_len -= i;
++                }
++            }
++            n++;
++            n += i;
++            OPENSSL_free(bndec);
++        } else {
++            BIO_snprintf(tbuf, sizeof tbuf, ".%lu", l);
++            i = strlen(tbuf);
++            if (buf && (buf_len > 0)) {
++                OPENSSL_strlcpy(buf, tbuf, buf_len);
++                if (i > buf_len) {
++                    buf += buf_len;
++                    buf_len = 0;
++                } else {
++                    buf += i;
++                    buf_len -= i;
++                }
++            }
++            n += i;
++            l = 0;
++        }
++    }
++
++    BN_free(bl);
++    return n;
++
++ err:
++    BN_free(bl);
++    return -1;
++}
++
++int OBJ_txt2nid(const char *s)
++{
++    ASN1_OBJECT *obj;
++    int nid;
++    obj = OBJ_txt2obj(s, 0);
++    nid = OBJ_obj2nid(obj);
++    ASN1_OBJECT_free(obj);
++    return nid;
++}
++
++int OBJ_ln2nid(const char *s)
++{
++    ASN1_OBJECT o;
++    const ASN1_OBJECT *oo = &o;
++    ADDED_OBJ ad, *adp;
++    const unsigned int *op;
++
++    o.ln = s;
++    if (added != NULL) {
++        ad.type = ADDED_LNAME;
++        ad.obj = &o;
++        adp = lh_ADDED_OBJ_retrieve(added, &ad);
++        if (adp != NULL)
++            return (adp->obj->nid);
++    }
++    op = OBJ_bsearch_ln(&oo, ln_objs, NUM_LN);
++    if (op == NULL)
++        return (NID_undef);
++    return (nid_objs[*op].nid);
++}
++
++int OBJ_sn2nid(const char *s)
++{
++    ASN1_OBJECT o;
++    const ASN1_OBJECT *oo = &o;
++    ADDED_OBJ ad, *adp;
++    const unsigned int *op;
++
++    o.sn = s;
++    if (added != NULL) {
++        ad.type = ADDED_SNAME;
++        ad.obj = &o;
++        adp = lh_ADDED_OBJ_retrieve(added, &ad);
++        if (adp != NULL)
++            return (adp->obj->nid);
++    }
++    op = OBJ_bsearch_sn(&oo, sn_objs, NUM_SN);
++    if (op == NULL)
++        return (NID_undef);
++    return (nid_objs[*op].nid);
++}
++
++const void *OBJ_bsearch_(const void *key, const void *base, int num, int size,
++                         int (*cmp) (const void *, const void *))
++{
++    return OBJ_bsearch_ex_(key, base, num, size, cmp, 0);
++}
++
++const void *OBJ_bsearch_ex_(const void *key, const void *base_, int num,
++                            int size,
++                            int (*cmp) (const void *, const void *),
++                            int flags)
++{
++    const char *base = base_;
++    int l, h, i = 0, c = 0;
++    const char *p = NULL;
++
++    if (num == 0)
++        return (NULL);
++    l = 0;
++    h = num;
++    while (l < h) {
++        i = (l + h) / 2;
++        p = &(base[i * size]);
++        c = (*cmp) (key, p);
++        if (c < 0)
++            h = i;
++        else if (c > 0)
++            l = i + 1;
++        else
++            break;
++    }
++#ifdef CHARSET_EBCDIC
++    /*
++     * THIS IS A KLUDGE - Because the *_obj is sorted in ASCII order, and I
++     * don't have perl (yet), we revert to a *LINEAR* search when the object
++     * wasn't found in the binary search.
++     */
++    if (c != 0) {
++        for (i = 0; i < num; ++i) {
++            p = &(base[i * size]);
++            c = (*cmp) (key, p);
++            if (c == 0 || (c < 0 && (flags & OBJ_BSEARCH_VALUE_ON_NOMATCH)))
++                return p;
++        }
++    }
++#endif
++    if (c != 0 && !(flags & OBJ_BSEARCH_VALUE_ON_NOMATCH))
++        p = NULL;
++    else if (c == 0 && (flags & OBJ_BSEARCH_FIRST_VALUE_ON_MATCH)) {
++        while (i > 0 && (*cmp) (key, &(base[(i - 1) * size])) == 0)
++            i--;
++        p = &(base[i * size]);
++    }
++    return (p);
++}
++
++int OBJ_create_objects(BIO *in)
++{
++    char buf[512];
++    int i, num = 0;
++    char *o, *s, *l = NULL;
++
++    for (;;) {
++        s = o = NULL;
++        i = BIO_gets(in, buf, 512);
++        if (i <= 0)
++            return (num);
++        buf[i - 1] = '\0';
++        if (!isalnum((unsigned char)buf[0]))
++            return (num);
++        o = s = buf;
++        while (isdigit((unsigned char)*s) || (*s == '.'))
++            s++;
++        if (*s != '\0') {
++            *(s++) = '\0';
++            while (isspace((unsigned char)*s))
++                s++;
++            if (*s == '\0')
++                s = NULL;
++            else {
++                l = s;
++                while ((*l != '\0') && !isspace((unsigned char)*l))
++                    l++;
++                if (*l != '\0') {
++                    *(l++) = '\0';
++                    while (isspace((unsigned char)*l))
++                        l++;
++                    if (*l == '\0')
++                        l = NULL;
++                } else
++                    l = NULL;
++            }
++        } else
++            s = NULL;
++        if ((o == NULL) || (*o == '\0'))
++            return (num);
++        if (!OBJ_create(o, s, l))
++            return (num);
++        num++;
++    }
++    /* return(num); */
++}
++
++int OBJ_create(const char *oid, const char *sn, const char *ln)
++{
++    ASN1_OBJECT *tmpoid = NULL;
++    int ok = 0;
++
++    /* Check to see if short or long name already present */
++    if (OBJ_sn2nid(sn) != NID_undef || OBJ_ln2nid(ln) != NID_undef) {
++        OBJerr(OBJ_F_OBJ_CREATE, OBJ_R_OID_EXISTS);
++        return 0;
++    }
++
++    /* Convert numerical OID string to an ASN1_OBJECT structure */
++    tmpoid = OBJ_txt2obj(oid, 1);
++
++    /* If NID is not NID_undef then object already exists */
++    if (OBJ_obj2nid(tmpoid) != NID_undef) {
++        OBJerr(OBJ_F_OBJ_CREATE, OBJ_R_OID_EXISTS);
++        goto err;
++    }
++
++    tmpoid->nid = OBJ_new_nid(1);
++    tmpoid->sn = (char *)sn;
++    tmpoid->ln = (char *)ln;
++
++    ok = OBJ_add_object(tmpoid);
++
++    tmpoid->sn = NULL;
++    tmpoid->ln = NULL;
++
++ err:
++    ASN1_OBJECT_free(tmpoid);
++    return ok;
++}
++
++size_t OBJ_length(const ASN1_OBJECT *obj)
++{
++    if (obj == NULL)
++        return 0;
++    return obj->length;
++}
++
++const unsigned char *OBJ_get0_data(const ASN1_OBJECT *obj)
++{
++    if (obj == NULL)
++        return NULL;
++    return obj->data;
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/objects/obj_dat.h b/CryptoPkg/Library/OpensslLib/openssl/crypto/objects/obj_dat.h
+new file mode 100644
+index 0000000..e1fc64f
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/objects/obj_dat.h
+@@ -0,0 +1,5101 @@
++/*
++ * WARNING: do not edit!
++ * Generated by crypto/objects/obj_dat.pl
++ *
++ * Copyright 1995-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++/* Serialized OID's */
++static const unsigned char so[6765] = {
++    0x2A,0x86,0x48,0x86,0xF7,0x0D,                 /* [    0] OBJ_rsadsi */
++    0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,            /* [    6] OBJ_pkcs */
++    0x2A,0x86,0x48,0x86,0xF7,0x0D,0x02,0x02,       /* [   13] OBJ_md2 */
++    0x2A,0x86,0x48,0x86,0xF7,0x0D,0x02,0x05,       /* [   21] OBJ_md5 */
++    0x2A,0x86,0x48,0x86,0xF7,0x0D,0x03,0x04,       /* [   29] OBJ_rc4 */
++    0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x01,  /* [   37] OBJ_rsaEncryption */
++    0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x02,  /* [   46] OBJ_md2WithRSAEncryption */
++    0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x04,  /* [   55] OBJ_md5WithRSAEncryption */
++    0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x05,0x01,  /* [   64] OBJ_pbeWithMD2AndDES_CBC */
++    0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x05,0x03,  /* [   73] OBJ_pbeWithMD5AndDES_CBC */
++    0x55,                                          /* [   82] OBJ_X500 */
++    0x55,0x04,                                     /* [   83] OBJ_X509 */
++    0x55,0x04,0x03,                                /* [   85] OBJ_commonName */
++    0x55,0x04,0x06,                                /* [   88] OBJ_countryName */
++    0x55,0x04,0x07,                                /* [   91] OBJ_localityName */
++    0x55,0x04,0x08,                                /* [   94] OBJ_stateOrProvinceName */
++    0x55,0x04,0x0A,                                /* [   97] OBJ_organizationName */
++    0x55,0x04,0x0B,                                /* [  100] OBJ_organizationalUnitName */
++    0x55,0x08,0x01,0x01,                           /* [  103] OBJ_rsa */
++    0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x07,       /* [  107] OBJ_pkcs7 */
++    0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x07,0x01,  /* [  115] OBJ_pkcs7_data */
++    0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x07,0x02,  /* [  124] OBJ_pkcs7_signed */
++    0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x07,0x03,  /* [  133] OBJ_pkcs7_enveloped */
++    0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x07,0x04,  /* [  142] OBJ_pkcs7_signedAndEnveloped */
++    0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x07,0x05,  /* [  151] OBJ_pkcs7_digest */
++    0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x07,0x06,  /* [  160] OBJ_pkcs7_encrypted */
++    0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x03,       /* [  169] OBJ_pkcs3 */
++    0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x03,0x01,  /* [  177] OBJ_dhKeyAgreement */
++    0x2B,0x0E,0x03,0x02,0x06,                      /* [  186] OBJ_des_ecb */
++    0x2B,0x0E,0x03,0x02,0x09,                      /* [  191] OBJ_des_cfb64 */
++    0x2B,0x0E,0x03,0x02,0x07,                      /* [  196] OBJ_des_cbc */
++    0x2B,0x0E,0x03,0x02,0x11,                      /* [  201] OBJ_des_ede_ecb */
++    0x2B,0x06,0x01,0x04,0x01,0x81,0x3C,0x07,0x01,0x01,0x02,  /* [  206] OBJ_idea_cbc */
++    0x2A,0x86,0x48,0x86,0xF7,0x0D,0x03,0x02,       /* [  217] OBJ_rc2_cbc */
++    0x2B,0x0E,0x03,0x02,0x12,                      /* [  225] OBJ_sha */
++    0x2B,0x0E,0x03,0x02,0x0F,                      /* [  230] OBJ_shaWithRSAEncryption */
++    0x2A,0x86,0x48,0x86,0xF7,0x0D,0x03,0x07,       /* [  235] OBJ_des_ede3_cbc */
++    0x2B,0x0E,0x03,0x02,0x08,                      /* [  243] OBJ_des_ofb64 */
++    0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x09,       /* [  248] OBJ_pkcs9 */
++    0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x09,0x01,  /* [  256] OBJ_pkcs9_emailAddress */
++    0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x09,0x02,  /* [  265] OBJ_pkcs9_unstructuredName */
++    0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x09,0x03,  /* [  274] OBJ_pkcs9_contentType */
++    0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x09,0x04,  /* [  283] OBJ_pkcs9_messageDigest */
++    0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x09,0x05,  /* [  292] OBJ_pkcs9_signingTime */
++    0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x09,0x06,  /* [  301] OBJ_pkcs9_countersignature */
++    0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x09,0x07,  /* [  310] OBJ_pkcs9_challengePassword */
++    0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x09,0x08,  /* [  319] OBJ_pkcs9_unstructuredAddress */
++    0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x09,0x09,  /* [  328] OBJ_pkcs9_extCertAttributes */
++    0x60,0x86,0x48,0x01,0x86,0xF8,0x42,            /* [  337] OBJ_netscape */
++    0x60,0x86,0x48,0x01,0x86,0xF8,0x42,0x01,       /* [  344] OBJ_netscape_cert_extension */
++    0x60,0x86,0x48,0x01,0x86,0xF8,0x42,0x02,       /* [  352] OBJ_netscape_data_type */
++    0x2B,0x0E,0x03,0x02,0x1A,                      /* [  360] OBJ_sha1 */
++    0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x05,  /* [  365] OBJ_sha1WithRSAEncryption */
++    0x2B,0x0E,0x03,0x02,0x0D,                      /* [  374] OBJ_dsaWithSHA */
++    0x2B,0x0E,0x03,0x02,0x0C,                      /* [  379] OBJ_dsa_2 */
++    0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x05,0x0B,  /* [  384] OBJ_pbeWithSHA1AndRC2_CBC */
++    0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x05,0x0C,  /* [  393] OBJ_id_pbkdf2 */
++    0x2B,0x0E,0x03,0x02,0x1B,                      /* [  402] OBJ_dsaWithSHA1_2 */
++    0x60,0x86,0x48,0x01,0x86,0xF8,0x42,0x01,0x01,  /* [  407] OBJ_netscape_cert_type */
++    0x60,0x86,0x48,0x01,0x86,0xF8,0x42,0x01,0x02,  /* [  416] OBJ_netscape_base_url */
++    0x60,0x86,0x48,0x01,0x86,0xF8,0x42,0x01,0x03,  /* [  425] OBJ_netscape_revocation_url */
++    0x60,0x86,0x48,0x01,0x86,0xF8,0x42,0x01,0x04,  /* [  434] OBJ_netscape_ca_revocation_url */
++    0x60,0x86,0x48,0x01,0x86,0xF8,0x42,0x01,0x07,  /* [  443] OBJ_netscape_renewal_url */
++    0x60,0x86,0x48,0x01,0x86,0xF8,0x42,0x01,0x08,  /* [  452] OBJ_netscape_ca_policy_url */
++    0x60,0x86,0x48,0x01,0x86,0xF8,0x42,0x01,0x0C,  /* [  461] OBJ_netscape_ssl_server_name */
++    0x60,0x86,0x48,0x01,0x86,0xF8,0x42,0x01,0x0D,  /* [  470] OBJ_netscape_comment */
++    0x60,0x86,0x48,0x01,0x86,0xF8,0x42,0x02,0x05,  /* [  479] OBJ_netscape_cert_sequence */
++    0x55,0x1D,                                     /* [  488] OBJ_id_ce */
++    0x55,0x1D,0x0E,                                /* [  490] OBJ_subject_key_identifier */
++    0x55,0x1D,0x0F,                                /* [  493] OBJ_key_usage */
++    0x55,0x1D,0x10,                                /* [  496] OBJ_private_key_usage_period */
++    0x55,0x1D,0x11,                                /* [  499] OBJ_subject_alt_name */
++    0x55,0x1D,0x12,                                /* [  502] OBJ_issuer_alt_name */
++    0x55,0x1D,0x13,                                /* [  505] OBJ_basic_constraints */
++    0x55,0x1D,0x14,                                /* [  508] OBJ_crl_number */
++    0x55,0x1D,0x20,                                /* [  511] OBJ_certificate_policies */
++    0x55,0x1D,0x23,                                /* [  514] OBJ_authority_key_identifier */
++    0x2B,0x06,0x01,0x04,0x01,0x97,0x55,0x01,0x02,  /* [  517] OBJ_bf_cbc */
++    0x55,0x08,0x03,0x65,                           /* [  526] OBJ_mdc2 */
++    0x55,0x08,0x03,0x64,                           /* [  530] OBJ_mdc2WithRSA */
++    0x55,0x04,0x2A,                                /* [  534] OBJ_givenName */
++    0x55,0x04,0x04,                                /* [  537] OBJ_surname */
++    0x55,0x04,0x2B,                                /* [  540] OBJ_initials */
++    0x09,0x92,0x26,0x89,0x93,0xF2,0x2C,0x64,0x01,0x2C,  /* [  543] OBJ_uniqueIdentifier */
++    0x55,0x1D,0x1F,                                /* [  553] OBJ_crl_distribution_points */
++    0x2B,0x0E,0x03,0x02,0x03,                      /* [  556] OBJ_md5WithRSA */
++    0x55,0x04,0x05,                                /* [  561] OBJ_serialNumber */
++    0x55,0x04,0x0C,                                /* [  564] OBJ_title */
++    0x55,0x04,0x0D,                                /* [  567] OBJ_description */
++    0x2A,0x86,0x48,0x86,0xF6,0x7D,0x07,0x42,0x0A,  /* [  570] OBJ_cast5_cbc */
++    0x2A,0x86,0x48,0x86,0xF6,0x7D,0x07,0x42,0x0C,  /* [  579] OBJ_pbeWithMD5AndCast5_CBC */
++    0x2A,0x86,0x48,0xCE,0x38,0x04,0x03,            /* [  588] OBJ_dsaWithSHA1 */
++    0x2B,0x0E,0x03,0x02,0x1D,                      /* [  595] OBJ_sha1WithRSA */
++    0x2A,0x86,0x48,0xCE,0x38,0x04,0x01,            /* [  600] OBJ_dsa */
++    0x2B,0x24,0x03,0x02,0x01,                      /* [  607] OBJ_ripemd160 */
++    0x2B,0x24,0x03,0x03,0x01,0x02,                 /* [  612] OBJ_ripemd160WithRSA */
++    0x2A,0x86,0x48,0x86,0xF7,0x0D,0x03,0x08,       /* [  618] OBJ_rc5_cbc */
++    0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x09,0x10,0x03,0x08,  /* [  626] OBJ_zlib_compression */
++    0x55,0x1D,0x25,                                /* [  637] OBJ_ext_key_usage */
++    0x2B,0x06,0x01,0x05,0x05,0x07,                 /* [  640] OBJ_id_pkix */
++    0x2B,0x06,0x01,0x05,0x05,0x07,0x03,            /* [  646] OBJ_id_kp */
++    0x2B,0x06,0x01,0x05,0x05,0x07,0x03,0x01,       /* [  653] OBJ_server_auth */
++    0x2B,0x06,0x01,0x05,0x05,0x07,0x03,0x02,       /* [  661] OBJ_client_auth */
++    0x2B,0x06,0x01,0x05,0x05,0x07,0x03,0x03,       /* [  669] OBJ_code_sign */
++    0x2B,0x06,0x01,0x05,0x05,0x07,0x03,0x04,       /* [  677] OBJ_email_protect */
++    0x2B,0x06,0x01,0x05,0x05,0x07,0x03,0x08,       /* [  685] OBJ_time_stamp */
++    0x2B,0x06,0x01,0x04,0x01,0x82,0x37,0x02,0x01,0x15,  /* [  693] OBJ_ms_code_ind */
++    0x2B,0x06,0x01,0x04,0x01,0x82,0x37,0x02,0x01,0x16,  /* [  703] OBJ_ms_code_com */
++    0x2B,0x06,0x01,0x04,0x01,0x82,0x37,0x0A,0x03,0x01,  /* [  713] OBJ_ms_ctl_sign */
++    0x2B,0x06,0x01,0x04,0x01,0x82,0x37,0x0A,0x03,0x03,  /* [  723] OBJ_ms_sgc */
++    0x2B,0x06,0x01,0x04,0x01,0x82,0x37,0x0A,0x03,0x04,  /* [  733] OBJ_ms_efs */
++    0x60,0x86,0x48,0x01,0x86,0xF8,0x42,0x04,0x01,  /* [  743] OBJ_ns_sgc */
++    0x55,0x1D,0x1B,                                /* [  752] OBJ_delta_crl */
++    0x55,0x1D,0x15,                                /* [  755] OBJ_crl_reason */
++    0x55,0x1D,0x18,                                /* [  758] OBJ_invalidity_date */
++    0x2B,0x65,0x01,0x04,0x01,                      /* [  761] OBJ_sxnet */
++    0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x0C,0x01,0x01,  /* [  766] OBJ_pbe_WithSHA1And128BitRC4 */
++    0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x0C,0x01,0x02,  /* [  776] OBJ_pbe_WithSHA1And40BitRC4 */
++    0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x0C,0x01,0x03,  /* [  786] OBJ_pbe_WithSHA1And3_Key_TripleDES_CBC */
++    0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x0C,0x01,0x04,  /* [  796] OBJ_pbe_WithSHA1And2_Key_TripleDES_CBC */
++    0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x0C,0x01,0x05,  /* [  806] OBJ_pbe_WithSHA1And128BitRC2_CBC */
++    0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x0C,0x01,0x06,  /* [  816] OBJ_pbe_WithSHA1And40BitRC2_CBC */
++    0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x0C,0x0A,0x01,0x01,  /* [  826] OBJ_keyBag */
++    0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x0C,0x0A,0x01,0x02,  /* [  837] OBJ_pkcs8ShroudedKeyBag */
++    0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x0C,0x0A,0x01,0x03,  /* [  848] OBJ_certBag */
++    0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x0C,0x0A,0x01,0x04,  /* [  859] OBJ_crlBag */
++    0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x0C,0x0A,0x01,0x05,  /* [  870] OBJ_secretBag */
++    0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x0C,0x0A,0x01,0x06,  /* [  881] OBJ_safeContentsBag */
++    0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x09,0x14,  /* [  892] OBJ_friendlyName */
++    0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x09,0x15,  /* [  901] OBJ_localKeyID */
++    0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x09,0x16,0x01,  /* [  910] OBJ_x509Certificate */
++    0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x09,0x16,0x02,  /* [  920] OBJ_sdsiCertificate */
++    0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x09,0x17,0x01,  /* [  930] OBJ_x509Crl */
++    0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x05,0x0D,  /* [  940] OBJ_pbes2 */
++    0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x05,0x0E,  /* [  949] OBJ_pbmac1 */
++    0x2A,0x86,0x48,0x86,0xF7,0x0D,0x02,0x07,       /* [  958] OBJ_hmacWithSHA1 */
++    0x2B,0x06,0x01,0x05,0x05,0x07,0x02,0x01,       /* [  966] OBJ_id_qt_cps */
++    0x2B,0x06,0x01,0x05,0x05,0x07,0x02,0x02,       /* [  974] OBJ_id_qt_unotice */
++    0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x09,0x0F,  /* [  982] OBJ_SMIMECapabilities */
++    0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x05,0x04,  /* [  991] OBJ_pbeWithMD2AndRC2_CBC */
++    0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x05,0x06,  /* [ 1000] OBJ_pbeWithMD5AndRC2_CBC */
++    0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x05,0x0A,  /* [ 1009] OBJ_pbeWithSHA1AndDES_CBC */
++    0x2B,0x06,0x01,0x04,0x01,0x82,0x37,0x02,0x01,0x0E,  /* [ 1018] OBJ_ms_ext_req */
++    0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x09,0x0E,  /* [ 1028] OBJ_ext_req */
++    0x55,0x04,0x29,                                /* [ 1037] OBJ_name */
++    0x55,0x04,0x2E,                                /* [ 1040] OBJ_dnQualifier */
++    0x2B,0x06,0x01,0x05,0x05,0x07,0x01,            /* [ 1043] OBJ_id_pe */
++    0x2B,0x06,0x01,0x05,0x05,0x07,0x30,            /* [ 1050] OBJ_id_ad */
++    0x2B,0x06,0x01,0x05,0x05,0x07,0x01,0x01,       /* [ 1057] OBJ_info_access */
++    0x2B,0x06,0x01,0x05,0x05,0x07,0x30,0x01,       /* [ 1065] OBJ_ad_OCSP */
++    0x2B,0x06,0x01,0x05,0x05,0x07,0x30,0x02,       /* [ 1073] OBJ_ad_ca_issuers */
++    0x2B,0x06,0x01,0x05,0x05,0x07,0x03,0x09,       /* [ 1081] OBJ_OCSP_sign */
++    0x2A,                                          /* [ 1089] OBJ_member_body */
++    0x2A,0x86,0x48,                                /* [ 1090] OBJ_ISO_US */
++    0x2A,0x86,0x48,0xCE,0x38,                      /* [ 1093] OBJ_X9_57 */
++    0x2A,0x86,0x48,0xCE,0x38,0x04,                 /* [ 1098] OBJ_X9cm */
++    0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,       /* [ 1104] OBJ_pkcs1 */
++    0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x05,       /* [ 1112] OBJ_pkcs5 */
++    0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x09,0x10,  /* [ 1120] OBJ_SMIME */
++    0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x09,0x10,0x00,  /* [ 1129] OBJ_id_smime_mod */
++    0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x09,0x10,0x01,  /* [ 1139] OBJ_id_smime_ct */
++    0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x09,0x10,0x02,  /* [ 1149] OBJ_id_smime_aa */
++    0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x09,0x10,0x03,  /* [ 1159] OBJ_id_smime_alg */
++    0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x09,0x10,0x04,  /* [ 1169] OBJ_id_smime_cd */
++    0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x09,0x10,0x05,  /* [ 1179] OBJ_id_smime_spq */
++    0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x09,0x10,0x06,  /* [ 1189] OBJ_id_smime_cti */
++    0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x09,0x10,0x00,0x01,  /* [ 1199] OBJ_id_smime_mod_cms */
++    0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x09,0x10,0x00,0x02,  /* [ 1210] OBJ_id_smime_mod_ess */
++    0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x09,0x10,0x00,0x03,  /* [ 1221] OBJ_id_smime_mod_oid */
++    0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x09,0x10,0x00,0x04,  /* [ 1232] OBJ_id_smime_mod_msg_v3 */
++    0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x09,0x10,0x00,0x05,  /* [ 1243] OBJ_id_smime_mod_ets_eSignature_88 */
++    0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x09,0x10,0x00,0x06,  /* [ 1254] OBJ_id_smime_mod_ets_eSignature_97 */
++    0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x09,0x10,0x00,0x07,  /* [ 1265] OBJ_id_smime_mod_ets_eSigPolicy_88 */
++    0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x09,0x10,0x00,0x08,  /* [ 1276] OBJ_id_smime_mod_ets_eSigPolicy_97 */
++    0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x09,0x10,0x01,0x01,  /* [ 1287] OBJ_id_smime_ct_receipt */
++    0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x09,0x10,0x01,0x02,  /* [ 1298] OBJ_id_smime_ct_authData */
++    0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x09,0x10,0x01,0x03,  /* [ 1309] OBJ_id_smime_ct_publishCert */
++    0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x09,0x10,0x01,0x04,  /* [ 1320] OBJ_id_smime_ct_TSTInfo */
++    0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x09,0x10,0x01,0x05,  /* [ 1331] OBJ_id_smime_ct_TDTInfo */
++    0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x09,0x10,0x01,0x06,  /* [ 1342] OBJ_id_smime_ct_contentInfo */
++    0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x09,0x10,0x01,0x07,  /* [ 1353] OBJ_id_smime_ct_DVCSRequestData */
++    0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x09,0x10,0x01,0x08,  /* [ 1364] OBJ_id_smime_ct_DVCSResponseData */
++    0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x09,0x10,0x02,0x01,  /* [ 1375] OBJ_id_smime_aa_receiptRequest */
++    0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x09,0x10,0x02,0x02,  /* [ 1386] OBJ_id_smime_aa_securityLabel */
++    0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x09,0x10,0x02,0x03,  /* [ 1397] OBJ_id_smime_aa_mlExpandHistory */
++    0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x09,0x10,0x02,0x04,  /* [ 1408] OBJ_id_smime_aa_contentHint */
++    0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x09,0x10,0x02,0x05,  /* [ 1419] OBJ_id_smime_aa_msgSigDigest */
++    0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x09,0x10,0x02,0x06,  /* [ 1430] OBJ_id_smime_aa_encapContentType */
++    0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x09,0x10,0x02,0x07,  /* [ 1441] OBJ_id_smime_aa_contentIdentifier */
++    0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x09,0x10,0x02,0x08,  /* [ 1452] OBJ_id_smime_aa_macValue */
++    0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x09,0x10,0x02,0x09,  /* [ 1463] OBJ_id_smime_aa_equivalentLabels */
++    0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x09,0x10,0x02,0x0A,  /* [ 1474] OBJ_id_smime_aa_contentReference */
++    0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x09,0x10,0x02,0x0B,  /* [ 1485] OBJ_id_smime_aa_encrypKeyPref */
++    0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x09,0x10,0x02,0x0C,  /* [ 1496] OBJ_id_smime_aa_signingCertificate */
++    0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x09,0x10,0x02,0x0D,  /* [ 1507] OBJ_id_smime_aa_smimeEncryptCerts */
++    0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x09,0x10,0x02,0x0E,  /* [ 1518] OBJ_id_smime_aa_timeStampToken */
++    0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x09,0x10,0x02,0x0F,  /* [ 1529] OBJ_id_smime_aa_ets_sigPolicyId */
++    0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x09,0x10,0x02,0x10,  /* [ 1540] OBJ_id_smime_aa_ets_commitmentType */
++    0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x09,0x10,0x02,0x11,  /* [ 1551] OBJ_id_smime_aa_ets_signerLocation */
++    0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x09,0x10,0x02,0x12,  /* [ 1562] OBJ_id_smime_aa_ets_signerAttr */
++    0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x09,0x10,0x02,0x13,  /* [ 1573] OBJ_id_smime_aa_ets_otherSigCert */
++    0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x09,0x10,0x02,0x14,  /* [ 1584] OBJ_id_smime_aa_ets_contentTimestamp */
++    0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x09,0x10,0x02,0x15,  /* [ 1595] OBJ_id_smime_aa_ets_CertificateRefs */
++    0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x09,0x10,0x02,0x16,  /* [ 1606] OBJ_id_smime_aa_ets_RevocationRefs */
++    0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x09,0x10,0x02,0x17,  /* [ 1617] OBJ_id_smime_aa_ets_certValues */
++    0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x09,0x10,0x02,0x18,  /* [ 1628] OBJ_id_smime_aa_ets_revocationValues */
++    0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x09,0x10,0x02,0x19,  /* [ 1639] OBJ_id_smime_aa_ets_escTimeStamp */
++    0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x09,0x10,0x02,0x1A,  /* [ 1650] OBJ_id_smime_aa_ets_certCRLTimestamp */
++    0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x09,0x10,0x02,0x1B,  /* [ 1661] OBJ_id_smime_aa_ets_archiveTimeStamp */
++    0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x09,0x10,0x02,0x1C,  /* [ 1672] OBJ_id_smime_aa_signatureType */
++    0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x09,0x10,0x02,0x1D,  /* [ 1683] OBJ_id_smime_aa_dvcs_dvc */
++    0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x09,0x10,0x03,0x01,  /* [ 1694] OBJ_id_smime_alg_ESDHwith3DES */
++    0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x09,0x10,0x03,0x02,  /* [ 1705] OBJ_id_smime_alg_ESDHwithRC2 */
++    0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x09,0x10,0x03,0x03,  /* [ 1716] OBJ_id_smime_alg_3DESwrap */
++    0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x09,0x10,0x03,0x04,  /* [ 1727] OBJ_id_smime_alg_RC2wrap */
++    0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x09,0x10,0x03,0x05,  /* [ 1738] OBJ_id_smime_alg_ESDH */
++    0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x09,0x10,0x03,0x06,  /* [ 1749] OBJ_id_smime_alg_CMS3DESwrap */
++    0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x09,0x10,0x03,0x07,  /* [ 1760] OBJ_id_smime_alg_CMSRC2wrap */
++    0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x09,0x10,0x04,0x01,  /* [ 1771] OBJ_id_smime_cd_ldap */
++    0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x09,0x10,0x05,0x01,  /* [ 1782] OBJ_id_smime_spq_ets_sqt_uri */
++    0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x09,0x10,0x05,0x02,  /* [ 1793] OBJ_id_smime_spq_ets_sqt_unotice */
++    0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x09,0x10,0x06,0x01,  /* [ 1804] OBJ_id_smime_cti_ets_proofOfOrigin */
++    0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x09,0x10,0x06,0x02,  /* [ 1815] OBJ_id_smime_cti_ets_proofOfReceipt */
++    0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x09,0x10,0x06,0x03,  /* [ 1826] OBJ_id_smime_cti_ets_proofOfDelivery */
++    0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x09,0x10,0x06,0x04,  /* [ 1837] OBJ_id_smime_cti_ets_proofOfSender */
++    0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x09,0x10,0x06,0x05,  /* [ 1848] OBJ_id_smime_cti_ets_proofOfApproval */
++    0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x09,0x10,0x06,0x06,  /* [ 1859] OBJ_id_smime_cti_ets_proofOfCreation */
++    0x2A,0x86,0x48,0x86,0xF7,0x0D,0x02,0x04,       /* [ 1870] OBJ_md4 */
++    0x2B,0x06,0x01,0x05,0x05,0x07,0x00,            /* [ 1878] OBJ_id_pkix_mod */
++    0x2B,0x06,0x01,0x05,0x05,0x07,0x02,            /* [ 1885] OBJ_id_qt */
++    0x2B,0x06,0x01,0x05,0x05,0x07,0x04,            /* [ 1892] OBJ_id_it */
++    0x2B,0x06,0x01,0x05,0x05,0x07,0x05,            /* [ 1899] OBJ_id_pkip */
++    0x2B,0x06,0x01,0x05,0x05,0x07,0x06,            /* [ 1906] OBJ_id_alg */
++    0x2B,0x06,0x01,0x05,0x05,0x07,0x07,            /* [ 1913] OBJ_id_cmc */
++    0x2B,0x06,0x01,0x05,0x05,0x07,0x08,            /* [ 1920] OBJ_id_on */
++    0x2B,0x06,0x01,0x05,0x05,0x07,0x09,            /* [ 1927] OBJ_id_pda */
++    0x2B,0x06,0x01,0x05,0x05,0x07,0x0A,            /* [ 1934] OBJ_id_aca */
++    0x2B,0x06,0x01,0x05,0x05,0x07,0x0B,            /* [ 1941] OBJ_id_qcs */
++    0x2B,0x06,0x01,0x05,0x05,0x07,0x0C,            /* [ 1948] OBJ_id_cct */
++    0x2B,0x06,0x01,0x05,0x05,0x07,0x00,0x01,       /* [ 1955] OBJ_id_pkix1_explicit_88 */
++    0x2B,0x06,0x01,0x05,0x05,0x07,0x00,0x02,       /* [ 1963] OBJ_id_pkix1_implicit_88 */
++    0x2B,0x06,0x01,0x05,0x05,0x07,0x00,0x03,       /* [ 1971] OBJ_id_pkix1_explicit_93 */
++    0x2B,0x06,0x01,0x05,0x05,0x07,0x00,0x04,       /* [ 1979] OBJ_id_pkix1_implicit_93 */
++    0x2B,0x06,0x01,0x05,0x05,0x07,0x00,0x05,       /* [ 1987] OBJ_id_mod_crmf */
++    0x2B,0x06,0x01,0x05,0x05,0x07,0x00,0x06,       /* [ 1995] OBJ_id_mod_cmc */
++    0x2B,0x06,0x01,0x05,0x05,0x07,0x00,0x07,       /* [ 2003] OBJ_id_mod_kea_profile_88 */
++    0x2B,0x06,0x01,0x05,0x05,0x07,0x00,0x08,       /* [ 2011] OBJ_id_mod_kea_profile_93 */
++    0x2B,0x06,0x01,0x05,0x05,0x07,0x00,0x09,       /* [ 2019] OBJ_id_mod_cmp */
++    0x2B,0x06,0x01,0x05,0x05,0x07,0x00,0x0A,       /* [ 2027] OBJ_id_mod_qualified_cert_88 */
++    0x2B,0x06,0x01,0x05,0x05,0x07,0x00,0x0B,       /* [ 2035] OBJ_id_mod_qualified_cert_93 */
++    0x2B,0x06,0x01,0x05,0x05,0x07,0x00,0x0C,       /* [ 2043] OBJ_id_mod_attribute_cert */
++    0x2B,0x06,0x01,0x05,0x05,0x07,0x00,0x0D,       /* [ 2051] OBJ_id_mod_timestamp_protocol */
++    0x2B,0x06,0x01,0x05,0x05,0x07,0x00,0x0E,       /* [ 2059] OBJ_id_mod_ocsp */
++    0x2B,0x06,0x01,0x05,0x05,0x07,0x00,0x0F,       /* [ 2067] OBJ_id_mod_dvcs */
++    0x2B,0x06,0x01,0x05,0x05,0x07,0x00,0x10,       /* [ 2075] OBJ_id_mod_cmp2000 */
++    0x2B,0x06,0x01,0x05,0x05,0x07,0x01,0x02,       /* [ 2083] OBJ_biometricInfo */
++    0x2B,0x06,0x01,0x05,0x05,0x07,0x01,0x03,       /* [ 2091] OBJ_qcStatements */
++    0x2B,0x06,0x01,0x05,0x05,0x07,0x01,0x04,       /* [ 2099] OBJ_ac_auditEntity */
++    0x2B,0x06,0x01,0x05,0x05,0x07,0x01,0x05,       /* [ 2107] OBJ_ac_targeting */
++    0x2B,0x06,0x01,0x05,0x05,0x07,0x01,0x06,       /* [ 2115] OBJ_aaControls */
++    0x2B,0x06,0x01,0x05,0x05,0x07,0x01,0x07,       /* [ 2123] OBJ_sbgp_ipAddrBlock */
++    0x2B,0x06,0x01,0x05,0x05,0x07,0x01,0x08,       /* [ 2131] OBJ_sbgp_autonomousSysNum */
++    0x2B,0x06,0x01,0x05,0x05,0x07,0x01,0x09,       /* [ 2139] OBJ_sbgp_routerIdentifier */
++    0x2B,0x06,0x01,0x05,0x05,0x07,0x02,0x03,       /* [ 2147] OBJ_textNotice */
++    0x2B,0x06,0x01,0x05,0x05,0x07,0x03,0x05,       /* [ 2155] OBJ_ipsecEndSystem */
++    0x2B,0x06,0x01,0x05,0x05,0x07,0x03,0x06,       /* [ 2163] OBJ_ipsecTunnel */
++    0x2B,0x06,0x01,0x05,0x05,0x07,0x03,0x07,       /* [ 2171] OBJ_ipsecUser */
++    0x2B,0x06,0x01,0x05,0x05,0x07,0x03,0x0A,       /* [ 2179] OBJ_dvcs */
++    0x2B,0x06,0x01,0x05,0x05,0x07,0x04,0x01,       /* [ 2187] OBJ_id_it_caProtEncCert */
++    0x2B,0x06,0x01,0x05,0x05,0x07,0x04,0x02,       /* [ 2195] OBJ_id_it_signKeyPairTypes */
++    0x2B,0x06,0x01,0x05,0x05,0x07,0x04,0x03,       /* [ 2203] OBJ_id_it_encKeyPairTypes */
++    0x2B,0x06,0x01,0x05,0x05,0x07,0x04,0x04,       /* [ 2211] OBJ_id_it_preferredSymmAlg */
++    0x2B,0x06,0x01,0x05,0x05,0x07,0x04,0x05,       /* [ 2219] OBJ_id_it_caKeyUpdateInfo */
++    0x2B,0x06,0x01,0x05,0x05,0x07,0x04,0x06,       /* [ 2227] OBJ_id_it_currentCRL */
++    0x2B,0x06,0x01,0x05,0x05,0x07,0x04,0x07,       /* [ 2235] OBJ_id_it_unsupportedOIDs */
++    0x2B,0x06,0x01,0x05,0x05,0x07,0x04,0x08,       /* [ 2243] OBJ_id_it_subscriptionRequest */
++    0x2B,0x06,0x01,0x05,0x05,0x07,0x04,0x09,       /* [ 2251] OBJ_id_it_subscriptionResponse */
++    0x2B,0x06,0x01,0x05,0x05,0x07,0x04,0x0A,       /* [ 2259] OBJ_id_it_keyPairParamReq */
++    0x2B,0x06,0x01,0x05,0x05,0x07,0x04,0x0B,       /* [ 2267] OBJ_id_it_keyPairParamRep */
++    0x2B,0x06,0x01,0x05,0x05,0x07,0x04,0x0C,       /* [ 2275] OBJ_id_it_revPassphrase */
++    0x2B,0x06,0x01,0x05,0x05,0x07,0x04,0x0D,       /* [ 2283] OBJ_id_it_implicitConfirm */
++    0x2B,0x06,0x01,0x05,0x05,0x07,0x04,0x0E,       /* [ 2291] OBJ_id_it_confirmWaitTime */
++    0x2B,0x06,0x01,0x05,0x05,0x07,0x04,0x0F,       /* [ 2299] OBJ_id_it_origPKIMessage */
++    0x2B,0x06,0x01,0x05,0x05,0x07,0x05,0x01,       /* [ 2307] OBJ_id_regCtrl */
++    0x2B,0x06,0x01,0x05,0x05,0x07,0x05,0x02,       /* [ 2315] OBJ_id_regInfo */
++    0x2B,0x06,0x01,0x05,0x05,0x07,0x05,0x01,0x01,  /* [ 2323] OBJ_id_regCtrl_regToken */
++    0x2B,0x06,0x01,0x05,0x05,0x07,0x05,0x01,0x02,  /* [ 2332] OBJ_id_regCtrl_authenticator */
++    0x2B,0x06,0x01,0x05,0x05,0x07,0x05,0x01,0x03,  /* [ 2341] OBJ_id_regCtrl_pkiPublicationInfo */
++    0x2B,0x06,0x01,0x05,0x05,0x07,0x05,0x01,0x04,  /* [ 2350] OBJ_id_regCtrl_pkiArchiveOptions */
++    0x2B,0x06,0x01,0x05,0x05,0x07,0x05,0x01,0x05,  /* [ 2359] OBJ_id_regCtrl_oldCertID */
++    0x2B,0x06,0x01,0x05,0x05,0x07,0x05,0x01,0x06,  /* [ 2368] OBJ_id_regCtrl_protocolEncrKey */
++    0x2B,0x06,0x01,0x05,0x05,0x07,0x05,0x02,0x01,  /* [ 2377] OBJ_id_regInfo_utf8Pairs */
++    0x2B,0x06,0x01,0x05,0x05,0x07,0x05,0x02,0x02,  /* [ 2386] OBJ_id_regInfo_certReq */
++    0x2B,0x06,0x01,0x05,0x05,0x07,0x06,0x01,       /* [ 2395] OBJ_id_alg_des40 */
++    0x2B,0x06,0x01,0x05,0x05,0x07,0x06,0x02,       /* [ 2403] OBJ_id_alg_noSignature */
++    0x2B,0x06,0x01,0x05,0x05,0x07,0x06,0x03,       /* [ 2411] OBJ_id_alg_dh_sig_hmac_sha1 */
++    0x2B,0x06,0x01,0x05,0x05,0x07,0x06,0x04,       /* [ 2419] OBJ_id_alg_dh_pop */
++    0x2B,0x06,0x01,0x05,0x05,0x07,0x07,0x01,       /* [ 2427] OBJ_id_cmc_statusInfo */
++    0x2B,0x06,0x01,0x05,0x05,0x07,0x07,0x02,       /* [ 2435] OBJ_id_cmc_identification */
++    0x2B,0x06,0x01,0x05,0x05,0x07,0x07,0x03,       /* [ 2443] OBJ_id_cmc_identityProof */
++    0x2B,0x06,0x01,0x05,0x05,0x07,0x07,0x04,       /* [ 2451] OBJ_id_cmc_dataReturn */
++    0x2B,0x06,0x01,0x05,0x05,0x07,0x07,0x05,       /* [ 2459] OBJ_id_cmc_transactionId */
++    0x2B,0x06,0x01,0x05,0x05,0x07,0x07,0x06,       /* [ 2467] OBJ_id_cmc_senderNonce */
++    0x2B,0x06,0x01,0x05,0x05,0x07,0x07,0x07,       /* [ 2475] OBJ_id_cmc_recipientNonce */
++    0x2B,0x06,0x01,0x05,0x05,0x07,0x07,0x08,       /* [ 2483] OBJ_id_cmc_addExtensions */
++    0x2B,0x06,0x01,0x05,0x05,0x07,0x07,0x09,       /* [ 2491] OBJ_id_cmc_encryptedPOP */
++    0x2B,0x06,0x01,0x05,0x05,0x07,0x07,0x0A,       /* [ 2499] OBJ_id_cmc_decryptedPOP */
++    0x2B,0x06,0x01,0x05,0x05,0x07,0x07,0x0B,       /* [ 2507] OBJ_id_cmc_lraPOPWitness */
++    0x2B,0x06,0x01,0x05,0x05,0x07,0x07,0x0F,       /* [ 2515] OBJ_id_cmc_getCert */
++    0x2B,0x06,0x01,0x05,0x05,0x07,0x07,0x10,       /* [ 2523] OBJ_id_cmc_getCRL */
++    0x2B,0x06,0x01,0x05,0x05,0x07,0x07,0x11,       /* [ 2531] OBJ_id_cmc_revokeRequest */
++    0x2B,0x06,0x01,0x05,0x05,0x07,0x07,0x12,       /* [ 2539] OBJ_id_cmc_regInfo */
++    0x2B,0x06,0x01,0x05,0x05,0x07,0x07,0x13,       /* [ 2547] OBJ_id_cmc_responseInfo */
++    0x2B,0x06,0x01,0x05,0x05,0x07,0x07,0x15,       /* [ 2555] OBJ_id_cmc_queryPending */
++    0x2B,0x06,0x01,0x05,0x05,0x07,0x07,0x16,       /* [ 2563] OBJ_id_cmc_popLinkRandom */
++    0x2B,0x06,0x01,0x05,0x05,0x07,0x07,0x17,       /* [ 2571] OBJ_id_cmc_popLinkWitness */
++    0x2B,0x06,0x01,0x05,0x05,0x07,0x07,0x18,       /* [ 2579] OBJ_id_cmc_confirmCertAcceptance */
++    0x2B,0x06,0x01,0x05,0x05,0x07,0x08,0x01,       /* [ 2587] OBJ_id_on_personalData */
++    0x2B,0x06,0x01,0x05,0x05,0x07,0x09,0x01,       /* [ 2595] OBJ_id_pda_dateOfBirth */
++    0x2B,0x06,0x01,0x05,0x05,0x07,0x09,0x02,       /* [ 2603] OBJ_id_pda_placeOfBirth */
++    0x2B,0x06,0x01,0x05,0x05,0x07,0x09,0x03,       /* [ 2611] OBJ_id_pda_gender */
++    0x2B,0x06,0x01,0x05,0x05,0x07,0x09,0x04,       /* [ 2619] OBJ_id_pda_countryOfCitizenship */
++    0x2B,0x06,0x01,0x05,0x05,0x07,0x09,0x05,       /* [ 2627] OBJ_id_pda_countryOfResidence */
++    0x2B,0x06,0x01,0x05,0x05,0x07,0x0A,0x01,       /* [ 2635] OBJ_id_aca_authenticationInfo */
++    0x2B,0x06,0x01,0x05,0x05,0x07,0x0A,0x02,       /* [ 2643] OBJ_id_aca_accessIdentity */
++    0x2B,0x06,0x01,0x05,0x05,0x07,0x0A,0x03,       /* [ 2651] OBJ_id_aca_chargingIdentity */
++    0x2B,0x06,0x01,0x05,0x05,0x07,0x0A,0x04,       /* [ 2659] OBJ_id_aca_group */
++    0x2B,0x06,0x01,0x05,0x05,0x07,0x0A,0x05,       /* [ 2667] OBJ_id_aca_role */
++    0x2B,0x06,0x01,0x05,0x05,0x07,0x0B,0x01,       /* [ 2675] OBJ_id_qcs_pkixQCSyntax_v1 */
++    0x2B,0x06,0x01,0x05,0x05,0x07,0x0C,0x01,       /* [ 2683] OBJ_id_cct_crs */
++    0x2B,0x06,0x01,0x05,0x05,0x07,0x0C,0x02,       /* [ 2691] OBJ_id_cct_PKIData */
++    0x2B,0x06,0x01,0x05,0x05,0x07,0x0C,0x03,       /* [ 2699] OBJ_id_cct_PKIResponse */
++    0x2B,0x06,0x01,0x05,0x05,0x07,0x30,0x03,       /* [ 2707] OBJ_ad_timeStamping */
++    0x2B,0x06,0x01,0x05,0x05,0x07,0x30,0x04,       /* [ 2715] OBJ_ad_dvcs */
++    0x2B,0x06,0x01,0x05,0x05,0x07,0x30,0x01,0x01,  /* [ 2723] OBJ_id_pkix_OCSP_basic */
++    0x2B,0x06,0x01,0x05,0x05,0x07,0x30,0x01,0x02,  /* [ 2732] OBJ_id_pkix_OCSP_Nonce */
++    0x2B,0x06,0x01,0x05,0x05,0x07,0x30,0x01,0x03,  /* [ 2741] OBJ_id_pkix_OCSP_CrlID */
++    0x2B,0x06,0x01,0x05,0x05,0x07,0x30,0x01,0x04,  /* [ 2750] OBJ_id_pkix_OCSP_acceptableResponses */
++    0x2B,0x06,0x01,0x05,0x05,0x07,0x30,0x01,0x05,  /* [ 2759] OBJ_id_pkix_OCSP_noCheck */
++    0x2B,0x06,0x01,0x05,0x05,0x07,0x30,0x01,0x06,  /* [ 2768] OBJ_id_pkix_OCSP_archiveCutoff */
++    0x2B,0x06,0x01,0x05,0x05,0x07,0x30,0x01,0x07,  /* [ 2777] OBJ_id_pkix_OCSP_serviceLocator */
++    0x2B,0x06,0x01,0x05,0x05,0x07,0x30,0x01,0x08,  /* [ 2786] OBJ_id_pkix_OCSP_extendedStatus */
++    0x2B,0x06,0x01,0x05,0x05,0x07,0x30,0x01,0x09,  /* [ 2795] OBJ_id_pkix_OCSP_valid */
++    0x2B,0x06,0x01,0x05,0x05,0x07,0x30,0x01,0x0A,  /* [ 2804] OBJ_id_pkix_OCSP_path */
++    0x2B,0x06,0x01,0x05,0x05,0x07,0x30,0x01,0x0B,  /* [ 2813] OBJ_id_pkix_OCSP_trustRoot */
++    0x2B,0x0E,0x03,0x02,                           /* [ 2822] OBJ_algorithm */
++    0x2B,0x0E,0x03,0x02,0x0B,                      /* [ 2826] OBJ_rsaSignature */
++    0x55,0x08,                                     /* [ 2831] OBJ_X500algorithms */
++    0x2B,                                          /* [ 2833] OBJ_org */
++    0x2B,0x06,                                     /* [ 2834] OBJ_dod */
++    0x2B,0x06,0x01,                                /* [ 2836] OBJ_iana */
++    0x2B,0x06,0x01,0x01,                           /* [ 2839] OBJ_Directory */
++    0x2B,0x06,0x01,0x02,                           /* [ 2843] OBJ_Management */
++    0x2B,0x06,0x01,0x03,                           /* [ 2847] OBJ_Experimental */
++    0x2B,0x06,0x01,0x04,                           /* [ 2851] OBJ_Private */
++    0x2B,0x06,0x01,0x05,                           /* [ 2855] OBJ_Security */
++    0x2B,0x06,0x01,0x06,                           /* [ 2859] OBJ_SNMPv2 */
++    0x2B,0x06,0x01,0x07,                           /* [ 2863] OBJ_Mail */
++    0x2B,0x06,0x01,0x04,0x01,                      /* [ 2867] OBJ_Enterprises */
++    0x2B,0x06,0x01,0x04,0x01,0x8B,0x3A,0x82,0x58,  /* [ 2872] OBJ_dcObject */
++    0x09,0x92,0x26,0x89,0x93,0xF2,0x2C,0x64,0x01,0x19,  /* [ 2881] OBJ_domainComponent */
++    0x09,0x92,0x26,0x89,0x93,0xF2,0x2C,0x64,0x04,0x0D,  /* [ 2891] OBJ_Domain */
++    0x55,0x01,0x05,                                /* [ 2901] OBJ_selected_attribute_types */
++    0x55,0x01,0x05,0x37,                           /* [ 2904] OBJ_clearance */
++    0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x03,  /* [ 2908] OBJ_md4WithRSAEncryption */
++    0x2B,0x06,0x01,0x05,0x05,0x07,0x01,0x0A,       /* [ 2917] OBJ_ac_proxying */
++    0x2B,0x06,0x01,0x05,0x05,0x07,0x01,0x0B,       /* [ 2925] OBJ_sinfo_access */
++    0x2B,0x06,0x01,0x05,0x05,0x07,0x0A,0x06,       /* [ 2933] OBJ_id_aca_encAttrs */
++    0x55,0x04,0x48,                                /* [ 2941] OBJ_role */
++    0x55,0x1D,0x24,                                /* [ 2944] OBJ_policy_constraints */
++    0x55,0x1D,0x37,                                /* [ 2947] OBJ_target_information */
++    0x55,0x1D,0x38,                                /* [ 2950] OBJ_no_rev_avail */
++    0x2A,0x86,0x48,0xCE,0x3D,                      /* [ 2953] OBJ_ansi_X9_62 */
++    0x2A,0x86,0x48,0xCE,0x3D,0x01,0x01,            /* [ 2958] OBJ_X9_62_prime_field */
++    0x2A,0x86,0x48,0xCE,0x3D,0x01,0x02,            /* [ 2965] OBJ_X9_62_characteristic_two_field */
++    0x2A,0x86,0x48,0xCE,0x3D,0x02,0x01,            /* [ 2972] OBJ_X9_62_id_ecPublicKey */
++    0x2A,0x86,0x48,0xCE,0x3D,0x03,0x01,0x01,       /* [ 2979] OBJ_X9_62_prime192v1 */
++    0x2A,0x86,0x48,0xCE,0x3D,0x03,0x01,0x02,       /* [ 2987] OBJ_X9_62_prime192v2 */
++    0x2A,0x86,0x48,0xCE,0x3D,0x03,0x01,0x03,       /* [ 2995] OBJ_X9_62_prime192v3 */
++    0x2A,0x86,0x48,0xCE,0x3D,0x03,0x01,0x04,       /* [ 3003] OBJ_X9_62_prime239v1 */
++    0x2A,0x86,0x48,0xCE,0x3D,0x03,0x01,0x05,       /* [ 3011] OBJ_X9_62_prime239v2 */
++    0x2A,0x86,0x48,0xCE,0x3D,0x03,0x01,0x06,       /* [ 3019] OBJ_X9_62_prime239v3 */
++    0x2A,0x86,0x48,0xCE,0x3D,0x03,0x01,0x07,       /* [ 3027] OBJ_X9_62_prime256v1 */
++    0x2A,0x86,0x48,0xCE,0x3D,0x04,0x01,            /* [ 3035] OBJ_ecdsa_with_SHA1 */
++    0x2B,0x06,0x01,0x04,0x01,0x82,0x37,0x11,0x01,  /* [ 3042] OBJ_ms_csp_name */
++    0x60,0x86,0x48,0x01,0x65,0x03,0x04,0x01,0x01,  /* [ 3051] OBJ_aes_128_ecb */
++    0x60,0x86,0x48,0x01,0x65,0x03,0x04,0x01,0x02,  /* [ 3060] OBJ_aes_128_cbc */
++    0x60,0x86,0x48,0x01,0x65,0x03,0x04,0x01,0x03,  /* [ 3069] OBJ_aes_128_ofb128 */
++    0x60,0x86,0x48,0x01,0x65,0x03,0x04,0x01,0x04,  /* [ 3078] OBJ_aes_128_cfb128 */
++    0x60,0x86,0x48,0x01,0x65,0x03,0x04,0x01,0x15,  /* [ 3087] OBJ_aes_192_ecb */
++    0x60,0x86,0x48,0x01,0x65,0x03,0x04,0x01,0x16,  /* [ 3096] OBJ_aes_192_cbc */
++    0x60,0x86,0x48,0x01,0x65,0x03,0x04,0x01,0x17,  /* [ 3105] OBJ_aes_192_ofb128 */
++    0x60,0x86,0x48,0x01,0x65,0x03,0x04,0x01,0x18,  /* [ 3114] OBJ_aes_192_cfb128 */
++    0x60,0x86,0x48,0x01,0x65,0x03,0x04,0x01,0x29,  /* [ 3123] OBJ_aes_256_ecb */
++    0x60,0x86,0x48,0x01,0x65,0x03,0x04,0x01,0x2A,  /* [ 3132] OBJ_aes_256_cbc */
++    0x60,0x86,0x48,0x01,0x65,0x03,0x04,0x01,0x2B,  /* [ 3141] OBJ_aes_256_ofb128 */
++    0x60,0x86,0x48,0x01,0x65,0x03,0x04,0x01,0x2C,  /* [ 3150] OBJ_aes_256_cfb128 */
++    0x55,0x1D,0x17,                                /* [ 3159] OBJ_hold_instruction_code */
++    0x2A,0x86,0x48,0xCE,0x38,0x02,0x01,            /* [ 3162] OBJ_hold_instruction_none */
++    0x2A,0x86,0x48,0xCE,0x38,0x02,0x02,            /* [ 3169] OBJ_hold_instruction_call_issuer */
++    0x2A,0x86,0x48,0xCE,0x38,0x02,0x03,            /* [ 3176] OBJ_hold_instruction_reject */
++    0x09,                                          /* [ 3183] OBJ_data */
++    0x09,0x92,0x26,                                /* [ 3184] OBJ_pss */
++    0x09,0x92,0x26,0x89,0x93,0xF2,0x2C,            /* [ 3187] OBJ_ucl */
++    0x09,0x92,0x26,0x89,0x93,0xF2,0x2C,0x64,       /* [ 3194] OBJ_pilot */
++    0x09,0x92,0x26,0x89,0x93,0xF2,0x2C,0x64,0x01,  /* [ 3202] OBJ_pilotAttributeType */
++    0x09,0x92,0x26,0x89,0x93,0xF2,0x2C,0x64,0x03,  /* [ 3211] OBJ_pilotAttributeSyntax */
++    0x09,0x92,0x26,0x89,0x93,0xF2,0x2C,0x64,0x04,  /* [ 3220] OBJ_pilotObjectClass */
++    0x09,0x92,0x26,0x89,0x93,0xF2,0x2C,0x64,0x0A,  /* [ 3229] OBJ_pilotGroups */
++    0x09,0x92,0x26,0x89,0x93,0xF2,0x2C,0x64,0x03,0x04,  /* [ 3238] OBJ_iA5StringSyntax */
++    0x09,0x92,0x26,0x89,0x93,0xF2,0x2C,0x64,0x03,0x05,  /* [ 3248] OBJ_caseIgnoreIA5StringSyntax */
++    0x09,0x92,0x26,0x89,0x93,0xF2,0x2C,0x64,0x04,0x03,  /* [ 3258] OBJ_pilotObject */
++    0x09,0x92,0x26,0x89,0x93,0xF2,0x2C,0x64,0x04,0x04,  /* [ 3268] OBJ_pilotPerson */
++    0x09,0x92,0x26,0x89,0x93,0xF2,0x2C,0x64,0x04,0x05,  /* [ 3278] OBJ_account */
++    0x09,0x92,0x26,0x89,0x93,0xF2,0x2C,0x64,0x04,0x06,  /* [ 3288] OBJ_document */
++    0x09,0x92,0x26,0x89,0x93,0xF2,0x2C,0x64,0x04,0x07,  /* [ 3298] OBJ_room */
++    0x09,0x92,0x26,0x89,0x93,0xF2,0x2C,0x64,0x04,0x09,  /* [ 3308] OBJ_documentSeries */
++    0x09,0x92,0x26,0x89,0x93,0xF2,0x2C,0x64,0x04,0x0E,  /* [ 3318] OBJ_rFC822localPart */
++    0x09,0x92,0x26,0x89,0x93,0xF2,0x2C,0x64,0x04,0x0F,  /* [ 3328] OBJ_dNSDomain */
++    0x09,0x92,0x26,0x89,0x93,0xF2,0x2C,0x64,0x04,0x11,  /* [ 3338] OBJ_domainRelatedObject */
++    0x09,0x92,0x26,0x89,0x93,0xF2,0x2C,0x64,0x04,0x12,  /* [ 3348] OBJ_friendlyCountry */
++    0x09,0x92,0x26,0x89,0x93,0xF2,0x2C,0x64,0x04,0x13,  /* [ 3358] OBJ_simpleSecurityObject */
++    0x09,0x92,0x26,0x89,0x93,0xF2,0x2C,0x64,0x04,0x14,  /* [ 3368] OBJ_pilotOrganization */
++    0x09,0x92,0x26,0x89,0x93,0xF2,0x2C,0x64,0x04,0x15,  /* [ 3378] OBJ_pilotDSA */
++    0x09,0x92,0x26,0x89,0x93,0xF2,0x2C,0x64,0x04,0x16,  /* [ 3388] OBJ_qualityLabelledData */
++    0x09,0x92,0x26,0x89,0x93,0xF2,0x2C,0x64,0x01,0x01,  /* [ 3398] OBJ_userId */
++    0x09,0x92,0x26,0x89,0x93,0xF2,0x2C,0x64,0x01,0x02,  /* [ 3408] OBJ_textEncodedORAddress */
++    0x09,0x92,0x26,0x89,0x93,0xF2,0x2C,0x64,0x01,0x03,  /* [ 3418] OBJ_rfc822Mailbox */
++    0x09,0x92,0x26,0x89,0x93,0xF2,0x2C,0x64,0x01,0x04,  /* [ 3428] OBJ_info */
++    0x09,0x92,0x26,0x89,0x93,0xF2,0x2C,0x64,0x01,0x05,  /* [ 3438] OBJ_favouriteDrink */
++    0x09,0x92,0x26,0x89,0x93,0xF2,0x2C,0x64,0x01,0x06,  /* [ 3448] OBJ_roomNumber */
++    0x09,0x92,0x26,0x89,0x93,0xF2,0x2C,0x64,0x01,0x07,  /* [ 3458] OBJ_photo */
++    0x09,0x92,0x26,0x89,0x93,0xF2,0x2C,0x64,0x01,0x08,  /* [ 3468] OBJ_userClass */
++    0x09,0x92,0x26,0x89,0x93,0xF2,0x2C,0x64,0x01,0x09,  /* [ 3478] OBJ_host */
++    0x09,0x92,0x26,0x89,0x93,0xF2,0x2C,0x64,0x01,0x0A,  /* [ 3488] OBJ_manager */
++    0x09,0x92,0x26,0x89,0x93,0xF2,0x2C,0x64,0x01,0x0B,  /* [ 3498] OBJ_documentIdentifier */
++    0x09,0x92,0x26,0x89,0x93,0xF2,0x2C,0x64,0x01,0x0C,  /* [ 3508] OBJ_documentTitle */
++    0x09,0x92,0x26,0x89,0x93,0xF2,0x2C,0x64,0x01,0x0D,  /* [ 3518] OBJ_documentVersion */
++    0x09,0x92,0x26,0x89,0x93,0xF2,0x2C,0x64,0x01,0x0E,  /* [ 3528] OBJ_documentAuthor */
++    0x09,0x92,0x26,0x89,0x93,0xF2,0x2C,0x64,0x01,0x0F,  /* [ 3538] OBJ_documentLocation */
++    0x09,0x92,0x26,0x89,0x93,0xF2,0x2C,0x64,0x01,0x14,  /* [ 3548] OBJ_homeTelephoneNumber */
++    0x09,0x92,0x26,0x89,0x93,0xF2,0x2C,0x64,0x01,0x15,  /* [ 3558] OBJ_secretary */
++    0x09,0x92,0x26,0x89,0x93,0xF2,0x2C,0x64,0x01,0x16,  /* [ 3568] OBJ_otherMailbox */
++    0x09,0x92,0x26,0x89,0x93,0xF2,0x2C,0x64,0x01,0x17,  /* [ 3578] OBJ_lastModifiedTime */
++    0x09,0x92,0x26,0x89,0x93,0xF2,0x2C,0x64,0x01,0x18,  /* [ 3588] OBJ_lastModifiedBy */
++    0x09,0x92,0x26,0x89,0x93,0xF2,0x2C,0x64,0x01,0x1A,  /* [ 3598] OBJ_aRecord */
++    0x09,0x92,0x26,0x89,0x93,0xF2,0x2C,0x64,0x01,0x1B,  /* [ 3608] OBJ_pilotAttributeType27 */
++    0x09,0x92,0x26,0x89,0x93,0xF2,0x2C,0x64,0x01,0x1C,  /* [ 3618] OBJ_mXRecord */
++    0x09,0x92,0x26,0x89,0x93,0xF2,0x2C,0x64,0x01,0x1D,  /* [ 3628] OBJ_nSRecord */
++    0x09,0x92,0x26,0x89,0x93,0xF2,0x2C,0x64,0x01,0x1E,  /* [ 3638] OBJ_sOARecord */
++    0x09,0x92,0x26,0x89,0x93,0xF2,0x2C,0x64,0x01,0x1F,  /* [ 3648] OBJ_cNAMERecord */
++    0x09,0x92,0x26,0x89,0x93,0xF2,0x2C,0x64,0x01,0x25,  /* [ 3658] OBJ_associatedDomain */
++    0x09,0x92,0x26,0x89,0x93,0xF2,0x2C,0x64,0x01,0x26,  /* [ 3668] OBJ_associatedName */
++    0x09,0x92,0x26,0x89,0x93,0xF2,0x2C,0x64,0x01,0x27,  /* [ 3678] OBJ_homePostalAddress */
++    0x09,0x92,0x26,0x89,0x93,0xF2,0x2C,0x64,0x01,0x28,  /* [ 3688] OBJ_personalTitle */
++    0x09,0x92,0x26,0x89,0x93,0xF2,0x2C,0x64,0x01,0x29,  /* [ 3698] OBJ_mobileTelephoneNumber */
++    0x09,0x92,0x26,0x89,0x93,0xF2,0x2C,0x64,0x01,0x2A,  /* [ 3708] OBJ_pagerTelephoneNumber */
++    0x09,0x92,0x26,0x89,0x93,0xF2,0x2C,0x64,0x01,0x2B,  /* [ 3718] OBJ_friendlyCountryName */
++    0x09,0x92,0x26,0x89,0x93,0xF2,0x2C,0x64,0x01,0x2D,  /* [ 3728] OBJ_organizationalStatus */
++    0x09,0x92,0x26,0x89,0x93,0xF2,0x2C,0x64,0x01,0x2E,  /* [ 3738] OBJ_janetMailbox */
++    0x09,0x92,0x26,0x89,0x93,0xF2,0x2C,0x64,0x01,0x2F,  /* [ 3748] OBJ_mailPreferenceOption */
++    0x09,0x92,0x26,0x89,0x93,0xF2,0x2C,0x64,0x01,0x30,  /* [ 3758] OBJ_buildingName */
++    0x09,0x92,0x26,0x89,0x93,0xF2,0x2C,0x64,0x01,0x31,  /* [ 3768] OBJ_dSAQuality */
++    0x09,0x92,0x26,0x89,0x93,0xF2,0x2C,0x64,0x01,0x32,  /* [ 3778] OBJ_singleLevelQuality */
++    0x09,0x92,0x26,0x89,0x93,0xF2,0x2C,0x64,0x01,0x33,  /* [ 3788] OBJ_subtreeMinimumQuality */
++    0x09,0x92,0x26,0x89,0x93,0xF2,0x2C,0x64,0x01,0x34,  /* [ 3798] OBJ_subtreeMaximumQuality */
++    0x09,0x92,0x26,0x89,0x93,0xF2,0x2C,0x64,0x01,0x35,  /* [ 3808] OBJ_personalSignature */
++    0x09,0x92,0x26,0x89,0x93,0xF2,0x2C,0x64,0x01,0x36,  /* [ 3818] OBJ_dITRedirect */
++    0x09,0x92,0x26,0x89,0x93,0xF2,0x2C,0x64,0x01,0x37,  /* [ 3828] OBJ_audio */
++    0x09,0x92,0x26,0x89,0x93,0xF2,0x2C,0x64,0x01,0x38,  /* [ 3838] OBJ_documentPublisher */
++    0x55,0x04,0x2D,                                /* [ 3848] OBJ_x500UniqueIdentifier */
++    0x2B,0x06,0x01,0x07,0x01,                      /* [ 3851] OBJ_mime_mhs */
++    0x2B,0x06,0x01,0x07,0x01,0x01,                 /* [ 3856] OBJ_mime_mhs_headings */
++    0x2B,0x06,0x01,0x07,0x01,0x02,                 /* [ 3862] OBJ_mime_mhs_bodies */
++    0x2B,0x06,0x01,0x07,0x01,0x01,0x01,            /* [ 3868] OBJ_id_hex_partial_message */
++    0x2B,0x06,0x01,0x07,0x01,0x01,0x02,            /* [ 3875] OBJ_id_hex_multipart_message */
++    0x55,0x04,0x2C,                                /* [ 3882] OBJ_generationQualifier */
++    0x55,0x04,0x41,                                /* [ 3885] OBJ_pseudonym */
++    0x67,0x2A,                                     /* [ 3888] OBJ_id_set */
++    0x67,0x2A,0x00,                                /* [ 3890] OBJ_set_ctype */
++    0x67,0x2A,0x01,                                /* [ 3893] OBJ_set_msgExt */
++    0x67,0x2A,0x03,                                /* [ 3896] OBJ_set_attr */
++    0x67,0x2A,0x05,                                /* [ 3899] OBJ_set_policy */
++    0x67,0x2A,0x07,                                /* [ 3902] OBJ_set_certExt */
++    0x67,0x2A,0x08,                                /* [ 3905] OBJ_set_brand */
++    0x67,0x2A,0x00,0x00,                           /* [ 3908] OBJ_setct_PANData */
++    0x67,0x2A,0x00,0x01,                           /* [ 3912] OBJ_setct_PANToken */
++    0x67,0x2A,0x00,0x02,                           /* [ 3916] OBJ_setct_PANOnly */
++    0x67,0x2A,0x00,0x03,                           /* [ 3920] OBJ_setct_OIData */
++    0x67,0x2A,0x00,0x04,                           /* [ 3924] OBJ_setct_PI */
++    0x67,0x2A,0x00,0x05,                           /* [ 3928] OBJ_setct_PIData */
++    0x67,0x2A,0x00,0x06,                           /* [ 3932] OBJ_setct_PIDataUnsigned */
++    0x67,0x2A,0x00,0x07,                           /* [ 3936] OBJ_setct_HODInput */
++    0x67,0x2A,0x00,0x08,                           /* [ 3940] OBJ_setct_AuthResBaggage */
++    0x67,0x2A,0x00,0x09,                           /* [ 3944] OBJ_setct_AuthRevReqBaggage */
++    0x67,0x2A,0x00,0x0A,                           /* [ 3948] OBJ_setct_AuthRevResBaggage */
++    0x67,0x2A,0x00,0x0B,                           /* [ 3952] OBJ_setct_CapTokenSeq */
++    0x67,0x2A,0x00,0x0C,                           /* [ 3956] OBJ_setct_PInitResData */
++    0x67,0x2A,0x00,0x0D,                           /* [ 3960] OBJ_setct_PI_TBS */
++    0x67,0x2A,0x00,0x0E,                           /* [ 3964] OBJ_setct_PResData */
++    0x67,0x2A,0x00,0x10,                           /* [ 3968] OBJ_setct_AuthReqTBS */
++    0x67,0x2A,0x00,0x11,                           /* [ 3972] OBJ_setct_AuthResTBS */
++    0x67,0x2A,0x00,0x12,                           /* [ 3976] OBJ_setct_AuthResTBSX */
++    0x67,0x2A,0x00,0x13,                           /* [ 3980] OBJ_setct_AuthTokenTBS */
++    0x67,0x2A,0x00,0x14,                           /* [ 3984] OBJ_setct_CapTokenData */
++    0x67,0x2A,0x00,0x15,                           /* [ 3988] OBJ_setct_CapTokenTBS */
++    0x67,0x2A,0x00,0x16,                           /* [ 3992] OBJ_setct_AcqCardCodeMsg */
++    0x67,0x2A,0x00,0x17,                           /* [ 3996] OBJ_setct_AuthRevReqTBS */
++    0x67,0x2A,0x00,0x18,                           /* [ 4000] OBJ_setct_AuthRevResData */
++    0x67,0x2A,0x00,0x19,                           /* [ 4004] OBJ_setct_AuthRevResTBS */
++    0x67,0x2A,0x00,0x1A,                           /* [ 4008] OBJ_setct_CapReqTBS */
++    0x67,0x2A,0x00,0x1B,                           /* [ 4012] OBJ_setct_CapReqTBSX */
++    0x67,0x2A,0x00,0x1C,                           /* [ 4016] OBJ_setct_CapResData */
++    0x67,0x2A,0x00,0x1D,                           /* [ 4020] OBJ_setct_CapRevReqTBS */
++    0x67,0x2A,0x00,0x1E,                           /* [ 4024] OBJ_setct_CapRevReqTBSX */
++    0x67,0x2A,0x00,0x1F,                           /* [ 4028] OBJ_setct_CapRevResData */
++    0x67,0x2A,0x00,0x20,                           /* [ 4032] OBJ_setct_CredReqTBS */
++    0x67,0x2A,0x00,0x21,                           /* [ 4036] OBJ_setct_CredReqTBSX */
++    0x67,0x2A,0x00,0x22,                           /* [ 4040] OBJ_setct_CredResData */
++    0x67,0x2A,0x00,0x23,                           /* [ 4044] OBJ_setct_CredRevReqTBS */
++    0x67,0x2A,0x00,0x24,                           /* [ 4048] OBJ_setct_CredRevReqTBSX */
++    0x67,0x2A,0x00,0x25,                           /* [ 4052] OBJ_setct_CredRevResData */
++    0x67,0x2A,0x00,0x26,                           /* [ 4056] OBJ_setct_PCertReqData */
++    0x67,0x2A,0x00,0x27,                           /* [ 4060] OBJ_setct_PCertResTBS */
++    0x67,0x2A,0x00,0x28,                           /* [ 4064] OBJ_setct_BatchAdminReqData */
++    0x67,0x2A,0x00,0x29,                           /* [ 4068] OBJ_setct_BatchAdminResData */
++    0x67,0x2A,0x00,0x2A,                           /* [ 4072] OBJ_setct_CardCInitResTBS */
++    0x67,0x2A,0x00,0x2B,                           /* [ 4076] OBJ_setct_MeAqCInitResTBS */
++    0x67,0x2A,0x00,0x2C,                           /* [ 4080] OBJ_setct_RegFormResTBS */
++    0x67,0x2A,0x00,0x2D,                           /* [ 4084] OBJ_setct_CertReqData */
++    0x67,0x2A,0x00,0x2E,                           /* [ 4088] OBJ_setct_CertReqTBS */
++    0x67,0x2A,0x00,0x2F,                           /* [ 4092] OBJ_setct_CertResData */
++    0x67,0x2A,0x00,0x30,                           /* [ 4096] OBJ_setct_CertInqReqTBS */
++    0x67,0x2A,0x00,0x31,                           /* [ 4100] OBJ_setct_ErrorTBS */
++    0x67,0x2A,0x00,0x32,                           /* [ 4104] OBJ_setct_PIDualSignedTBE */
++    0x67,0x2A,0x00,0x33,                           /* [ 4108] OBJ_setct_PIUnsignedTBE */
++    0x67,0x2A,0x00,0x34,                           /* [ 4112] OBJ_setct_AuthReqTBE */
++    0x67,0x2A,0x00,0x35,                           /* [ 4116] OBJ_setct_AuthResTBE */
++    0x67,0x2A,0x00,0x36,                           /* [ 4120] OBJ_setct_AuthResTBEX */
++    0x67,0x2A,0x00,0x37,                           /* [ 4124] OBJ_setct_AuthTokenTBE */
++    0x67,0x2A,0x00,0x38,                           /* [ 4128] OBJ_setct_CapTokenTBE */
++    0x67,0x2A,0x00,0x39,                           /* [ 4132] OBJ_setct_CapTokenTBEX */
++    0x67,0x2A,0x00,0x3A,                           /* [ 4136] OBJ_setct_AcqCardCodeMsgTBE */
++    0x67,0x2A,0x00,0x3B,                           /* [ 4140] OBJ_setct_AuthRevReqTBE */
++    0x67,0x2A,0x00,0x3C,                           /* [ 4144] OBJ_setct_AuthRevResTBE */
++    0x67,0x2A,0x00,0x3D,                           /* [ 4148] OBJ_setct_AuthRevResTBEB */
++    0x67,0x2A,0x00,0x3E,                           /* [ 4152] OBJ_setct_CapReqTBE */
++    0x67,0x2A,0x00,0x3F,                           /* [ 4156] OBJ_setct_CapReqTBEX */
++    0x67,0x2A,0x00,0x40,                           /* [ 4160] OBJ_setct_CapResTBE */
++    0x67,0x2A,0x00,0x41,                           /* [ 4164] OBJ_setct_CapRevReqTBE */
++    0x67,0x2A,0x00,0x42,                           /* [ 4168] OBJ_setct_CapRevReqTBEX */
++    0x67,0x2A,0x00,0x43,                           /* [ 4172] OBJ_setct_CapRevResTBE */
++    0x67,0x2A,0x00,0x44,                           /* [ 4176] OBJ_setct_CredReqTBE */
++    0x67,0x2A,0x00,0x45,                           /* [ 4180] OBJ_setct_CredReqTBEX */
++    0x67,0x2A,0x00,0x46,                           /* [ 4184] OBJ_setct_CredResTBE */
++    0x67,0x2A,0x00,0x47,                           /* [ 4188] OBJ_setct_CredRevReqTBE */
++    0x67,0x2A,0x00,0x48,                           /* [ 4192] OBJ_setct_CredRevReqTBEX */
++    0x67,0x2A,0x00,0x49,                           /* [ 4196] OBJ_setct_CredRevResTBE */
++    0x67,0x2A,0x00,0x4A,                           /* [ 4200] OBJ_setct_BatchAdminReqTBE */
++    0x67,0x2A,0x00,0x4B,                           /* [ 4204] OBJ_setct_BatchAdminResTBE */
++    0x67,0x2A,0x00,0x4C,                           /* [ 4208] OBJ_setct_RegFormReqTBE */
++    0x67,0x2A,0x00,0x4D,                           /* [ 4212] OBJ_setct_CertReqTBE */
++    0x67,0x2A,0x00,0x4E,                           /* [ 4216] OBJ_setct_CertReqTBEX */
++    0x67,0x2A,0x00,0x4F,                           /* [ 4220] OBJ_setct_CertResTBE */
++    0x67,0x2A,0x00,0x50,                           /* [ 4224] OBJ_setct_CRLNotificationTBS */
++    0x67,0x2A,0x00,0x51,                           /* [ 4228] OBJ_setct_CRLNotificationResTBS */
++    0x67,0x2A,0x00,0x52,                           /* [ 4232] OBJ_setct_BCIDistributionTBS */
++    0x67,0x2A,0x01,0x01,                           /* [ 4236] OBJ_setext_genCrypt */
++    0x67,0x2A,0x01,0x03,                           /* [ 4240] OBJ_setext_miAuth */
++    0x67,0x2A,0x01,0x04,                           /* [ 4244] OBJ_setext_pinSecure */
++    0x67,0x2A,0x01,0x05,                           /* [ 4248] OBJ_setext_pinAny */
++    0x67,0x2A,0x01,0x07,                           /* [ 4252] OBJ_setext_track2 */
++    0x67,0x2A,0x01,0x08,                           /* [ 4256] OBJ_setext_cv */
++    0x67,0x2A,0x05,0x00,                           /* [ 4260] OBJ_set_policy_root */
++    0x67,0x2A,0x07,0x00,                           /* [ 4264] OBJ_setCext_hashedRoot */
++    0x67,0x2A,0x07,0x01,                           /* [ 4268] OBJ_setCext_certType */
++    0x67,0x2A,0x07,0x02,                           /* [ 4272] OBJ_setCext_merchData */
++    0x67,0x2A,0x07,0x03,                           /* [ 4276] OBJ_setCext_cCertRequired */
++    0x67,0x2A,0x07,0x04,                           /* [ 4280] OBJ_setCext_tunneling */
++    0x67,0x2A,0x07,0x05,                           /* [ 4284] OBJ_setCext_setExt */
++    0x67,0x2A,0x07,0x06,                           /* [ 4288] OBJ_setCext_setQualf */
++    0x67,0x2A,0x07,0x07,                           /* [ 4292] OBJ_setCext_PGWYcapabilities */
++    0x67,0x2A,0x07,0x08,                           /* [ 4296] OBJ_setCext_TokenIdentifier */
++    0x67,0x2A,0x07,0x09,                           /* [ 4300] OBJ_setCext_Track2Data */
++    0x67,0x2A,0x07,0x0A,                           /* [ 4304] OBJ_setCext_TokenType */
++    0x67,0x2A,0x07,0x0B,                           /* [ 4308] OBJ_setCext_IssuerCapabilities */
++    0x67,0x2A,0x03,0x00,                           /* [ 4312] OBJ_setAttr_Cert */
++    0x67,0x2A,0x03,0x01,                           /* [ 4316] OBJ_setAttr_PGWYcap */
++    0x67,0x2A,0x03,0x02,                           /* [ 4320] OBJ_setAttr_TokenType */
++    0x67,0x2A,0x03,0x03,                           /* [ 4324] OBJ_setAttr_IssCap */
++    0x67,0x2A,0x03,0x00,0x00,                      /* [ 4328] OBJ_set_rootKeyThumb */
++    0x67,0x2A,0x03,0x00,0x01,                      /* [ 4333] OBJ_set_addPolicy */
++    0x67,0x2A,0x03,0x02,0x01,                      /* [ 4338] OBJ_setAttr_Token_EMV */
++    0x67,0x2A,0x03,0x02,0x02,                      /* [ 4343] OBJ_setAttr_Token_B0Prime */
++    0x67,0x2A,0x03,0x03,0x03,                      /* [ 4348] OBJ_setAttr_IssCap_CVM */
++    0x67,0x2A,0x03,0x03,0x04,                      /* [ 4353] OBJ_setAttr_IssCap_T2 */
++    0x67,0x2A,0x03,0x03,0x05,                      /* [ 4358] OBJ_setAttr_IssCap_Sig */
++    0x67,0x2A,0x03,0x03,0x03,0x01,                 /* [ 4363] OBJ_setAttr_GenCryptgrm */
++    0x67,0x2A,0x03,0x03,0x04,0x01,                 /* [ 4369] OBJ_setAttr_T2Enc */
++    0x67,0x2A,0x03,0x03,0x04,0x02,                 /* [ 4375] OBJ_setAttr_T2cleartxt */
++    0x67,0x2A,0x03,0x03,0x05,0x01,                 /* [ 4381] OBJ_setAttr_TokICCsig */
++    0x67,0x2A,0x03,0x03,0x05,0x02,                 /* [ 4387] OBJ_setAttr_SecDevSig */
++    0x67,0x2A,0x08,0x01,                           /* [ 4393] OBJ_set_brand_IATA_ATA */
++    0x67,0x2A,0x08,0x1E,                           /* [ 4397] OBJ_set_brand_Diners */
++    0x67,0x2A,0x08,0x22,                           /* [ 4401] OBJ_set_brand_AmericanExpress */
++    0x67,0x2A,0x08,0x23,                           /* [ 4405] OBJ_set_brand_JCB */
++    0x67,0x2A,0x08,0x04,                           /* [ 4409] OBJ_set_brand_Visa */
++    0x67,0x2A,0x08,0x05,                           /* [ 4413] OBJ_set_brand_MasterCard */
++    0x67,0x2A,0x08,0xAE,0x7B,                      /* [ 4417] OBJ_set_brand_Novus */
++    0x2A,0x86,0x48,0x86,0xF7,0x0D,0x03,0x0A,       /* [ 4422] OBJ_des_cdmf */
++    0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x06,  /* [ 4430] OBJ_rsaOAEPEncryptionSET */
++    0x67,                                          /* [ 4439] OBJ_international_organizations */
++    0x2B,0x06,0x01,0x04,0x01,0x82,0x37,0x14,0x02,0x02,  /* [ 4440] OBJ_ms_smartcard_login */
++    0x2B,0x06,0x01,0x04,0x01,0x82,0x37,0x14,0x02,0x03,  /* [ 4450] OBJ_ms_upn */
++    0x55,0x04,0x09,                                /* [ 4460] OBJ_streetAddress */
++    0x55,0x04,0x11,                                /* [ 4463] OBJ_postalCode */
++    0x2B,0x06,0x01,0x05,0x05,0x07,0x15,            /* [ 4466] OBJ_id_ppl */
++    0x2B,0x06,0x01,0x05,0x05,0x07,0x01,0x0E,       /* [ 4473] OBJ_proxyCertInfo */
++    0x2B,0x06,0x01,0x05,0x05,0x07,0x15,0x00,       /* [ 4481] OBJ_id_ppl_anyLanguage */
++    0x2B,0x06,0x01,0x05,0x05,0x07,0x15,0x01,       /* [ 4489] OBJ_id_ppl_inheritAll */
++    0x55,0x1D,0x1E,                                /* [ 4497] OBJ_name_constraints */
++    0x2B,0x06,0x01,0x05,0x05,0x07,0x15,0x02,       /* [ 4500] OBJ_Independent */
++    0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x0B,  /* [ 4508] OBJ_sha256WithRSAEncryption */
++    0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x0C,  /* [ 4517] OBJ_sha384WithRSAEncryption */
++    0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x0D,  /* [ 4526] OBJ_sha512WithRSAEncryption */
++    0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x0E,  /* [ 4535] OBJ_sha224WithRSAEncryption */
++    0x60,0x86,0x48,0x01,0x65,0x03,0x04,0x02,0x01,  /* [ 4544] OBJ_sha256 */
++    0x60,0x86,0x48,0x01,0x65,0x03,0x04,0x02,0x02,  /* [ 4553] OBJ_sha384 */
++    0x60,0x86,0x48,0x01,0x65,0x03,0x04,0x02,0x03,  /* [ 4562] OBJ_sha512 */
++    0x60,0x86,0x48,0x01,0x65,0x03,0x04,0x02,0x04,  /* [ 4571] OBJ_sha224 */
++    0x2B,                                          /* [ 4580] OBJ_identified_organization */
++    0x2B,0x81,0x04,                                /* [ 4581] OBJ_certicom_arc */
++    0x67,0x2B,                                     /* [ 4584] OBJ_wap */
++    0x67,0x2B,0x01,                                /* [ 4586] OBJ_wap_wsg */
++    0x2A,0x86,0x48,0xCE,0x3D,0x01,0x02,0x03,       /* [ 4589] OBJ_X9_62_id_characteristic_two_basis */
++    0x2A,0x86,0x48,0xCE,0x3D,0x01,0x02,0x03,0x01,  /* [ 4597] OBJ_X9_62_onBasis */
++    0x2A,0x86,0x48,0xCE,0x3D,0x01,0x02,0x03,0x02,  /* [ 4606] OBJ_X9_62_tpBasis */
++    0x2A,0x86,0x48,0xCE,0x3D,0x01,0x02,0x03,0x03,  /* [ 4615] OBJ_X9_62_ppBasis */
++    0x2A,0x86,0x48,0xCE,0x3D,0x03,0x00,0x01,       /* [ 4624] OBJ_X9_62_c2pnb163v1 */
++    0x2A,0x86,0x48,0xCE,0x3D,0x03,0x00,0x02,       /* [ 4632] OBJ_X9_62_c2pnb163v2 */
++    0x2A,0x86,0x48,0xCE,0x3D,0x03,0x00,0x03,       /* [ 4640] OBJ_X9_62_c2pnb163v3 */
++    0x2A,0x86,0x48,0xCE,0x3D,0x03,0x00,0x04,       /* [ 4648] OBJ_X9_62_c2pnb176v1 */
++    0x2A,0x86,0x48,0xCE,0x3D,0x03,0x00,0x05,       /* [ 4656] OBJ_X9_62_c2tnb191v1 */
++    0x2A,0x86,0x48,0xCE,0x3D,0x03,0x00,0x06,       /* [ 4664] OBJ_X9_62_c2tnb191v2 */
++    0x2A,0x86,0x48,0xCE,0x3D,0x03,0x00,0x07,       /* [ 4672] OBJ_X9_62_c2tnb191v3 */
++    0x2A,0x86,0x48,0xCE,0x3D,0x03,0x00,0x08,       /* [ 4680] OBJ_X9_62_c2onb191v4 */
++    0x2A,0x86,0x48,0xCE,0x3D,0x03,0x00,0x09,       /* [ 4688] OBJ_X9_62_c2onb191v5 */
++    0x2A,0x86,0x48,0xCE,0x3D,0x03,0x00,0x0A,       /* [ 4696] OBJ_X9_62_c2pnb208w1 */
++    0x2A,0x86,0x48,0xCE,0x3D,0x03,0x00,0x0B,       /* [ 4704] OBJ_X9_62_c2tnb239v1 */
++    0x2A,0x86,0x48,0xCE,0x3D,0x03,0x00,0x0C,       /* [ 4712] OBJ_X9_62_c2tnb239v2 */
++    0x2A,0x86,0x48,0xCE,0x3D,0x03,0x00,0x0D,       /* [ 4720] OBJ_X9_62_c2tnb239v3 */
++    0x2A,0x86,0x48,0xCE,0x3D,0x03,0x00,0x0E,       /* [ 4728] OBJ_X9_62_c2onb239v4 */
++    0x2A,0x86,0x48,0xCE,0x3D,0x03,0x00,0x0F,       /* [ 4736] OBJ_X9_62_c2onb239v5 */
++    0x2A,0x86,0x48,0xCE,0x3D,0x03,0x00,0x10,       /* [ 4744] OBJ_X9_62_c2pnb272w1 */
++    0x2A,0x86,0x48,0xCE,0x3D,0x03,0x00,0x11,       /* [ 4752] OBJ_X9_62_c2pnb304w1 */
++    0x2A,0x86,0x48,0xCE,0x3D,0x03,0x00,0x12,       /* [ 4760] OBJ_X9_62_c2tnb359v1 */
++    0x2A,0x86,0x48,0xCE,0x3D,0x03,0x00,0x13,       /* [ 4768] OBJ_X9_62_c2pnb368w1 */
++    0x2A,0x86,0x48,0xCE,0x3D,0x03,0x00,0x14,       /* [ 4776] OBJ_X9_62_c2tnb431r1 */
++    0x2B,0x81,0x04,0x00,0x06,                      /* [ 4784] OBJ_secp112r1 */
++    0x2B,0x81,0x04,0x00,0x07,                      /* [ 4789] OBJ_secp112r2 */
++    0x2B,0x81,0x04,0x00,0x1C,                      /* [ 4794] OBJ_secp128r1 */
++    0x2B,0x81,0x04,0x00,0x1D,                      /* [ 4799] OBJ_secp128r2 */
++    0x2B,0x81,0x04,0x00,0x09,                      /* [ 4804] OBJ_secp160k1 */
++    0x2B,0x81,0x04,0x00,0x08,                      /* [ 4809] OBJ_secp160r1 */
++    0x2B,0x81,0x04,0x00,0x1E,                      /* [ 4814] OBJ_secp160r2 */
++    0x2B,0x81,0x04,0x00,0x1F,                      /* [ 4819] OBJ_secp192k1 */
++    0x2B,0x81,0x04,0x00,0x20,                      /* [ 4824] OBJ_secp224k1 */
++    0x2B,0x81,0x04,0x00,0x21,                      /* [ 4829] OBJ_secp224r1 */
++    0x2B,0x81,0x04,0x00,0x0A,                      /* [ 4834] OBJ_secp256k1 */
++    0x2B,0x81,0x04,0x00,0x22,                      /* [ 4839] OBJ_secp384r1 */
++    0x2B,0x81,0x04,0x00,0x23,                      /* [ 4844] OBJ_secp521r1 */
++    0x2B,0x81,0x04,0x00,0x04,                      /* [ 4849] OBJ_sect113r1 */
++    0x2B,0x81,0x04,0x00,0x05,                      /* [ 4854] OBJ_sect113r2 */
++    0x2B,0x81,0x04,0x00,0x16,                      /* [ 4859] OBJ_sect131r1 */
++    0x2B,0x81,0x04,0x00,0x17,                      /* [ 4864] OBJ_sect131r2 */
++    0x2B,0x81,0x04,0x00,0x01,                      /* [ 4869] OBJ_sect163k1 */
++    0x2B,0x81,0x04,0x00,0x02,                      /* [ 4874] OBJ_sect163r1 */
++    0x2B,0x81,0x04,0x00,0x0F,                      /* [ 4879] OBJ_sect163r2 */
++    0x2B,0x81,0x04,0x00,0x18,                      /* [ 4884] OBJ_sect193r1 */
++    0x2B,0x81,0x04,0x00,0x19,                      /* [ 4889] OBJ_sect193r2 */
++    0x2B,0x81,0x04,0x00,0x1A,                      /* [ 4894] OBJ_sect233k1 */
++    0x2B,0x81,0x04,0x00,0x1B,                      /* [ 4899] OBJ_sect233r1 */
++    0x2B,0x81,0x04,0x00,0x03,                      /* [ 4904] OBJ_sect239k1 */
++    0x2B,0x81,0x04,0x00,0x10,                      /* [ 4909] OBJ_sect283k1 */
++    0x2B,0x81,0x04,0x00,0x11,                      /* [ 4914] OBJ_sect283r1 */
++    0x2B,0x81,0x04,0x00,0x24,                      /* [ 4919] OBJ_sect409k1 */
++    0x2B,0x81,0x04,0x00,0x25,                      /* [ 4924] OBJ_sect409r1 */
++    0x2B,0x81,0x04,0x00,0x26,                      /* [ 4929] OBJ_sect571k1 */
++    0x2B,0x81,0x04,0x00,0x27,                      /* [ 4934] OBJ_sect571r1 */
++    0x67,0x2B,0x01,0x04,0x01,                      /* [ 4939] OBJ_wap_wsg_idm_ecid_wtls1 */
++    0x67,0x2B,0x01,0x04,0x03,                      /* [ 4944] OBJ_wap_wsg_idm_ecid_wtls3 */
++    0x67,0x2B,0x01,0x04,0x04,                      /* [ 4949] OBJ_wap_wsg_idm_ecid_wtls4 */
++    0x67,0x2B,0x01,0x04,0x05,                      /* [ 4954] OBJ_wap_wsg_idm_ecid_wtls5 */
++    0x67,0x2B,0x01,0x04,0x06,                      /* [ 4959] OBJ_wap_wsg_idm_ecid_wtls6 */
++    0x67,0x2B,0x01,0x04,0x07,                      /* [ 4964] OBJ_wap_wsg_idm_ecid_wtls7 */
++    0x67,0x2B,0x01,0x04,0x08,                      /* [ 4969] OBJ_wap_wsg_idm_ecid_wtls8 */
++    0x67,0x2B,0x01,0x04,0x09,                      /* [ 4974] OBJ_wap_wsg_idm_ecid_wtls9 */
++    0x67,0x2B,0x01,0x04,0x0A,                      /* [ 4979] OBJ_wap_wsg_idm_ecid_wtls10 */
++    0x67,0x2B,0x01,0x04,0x0B,                      /* [ 4984] OBJ_wap_wsg_idm_ecid_wtls11 */
++    0x67,0x2B,0x01,0x04,0x0C,                      /* [ 4989] OBJ_wap_wsg_idm_ecid_wtls12 */
++    0x55,0x1D,0x20,0x00,                           /* [ 4994] OBJ_any_policy */
++    0x55,0x1D,0x21,                                /* [ 4998] OBJ_policy_mappings */
++    0x55,0x1D,0x36,                                /* [ 5001] OBJ_inhibit_any_policy */
++    0x2A,0x83,0x08,0x8C,0x9A,0x4B,0x3D,0x01,0x01,0x01,0x02,  /* [ 5004] OBJ_camellia_128_cbc */
++    0x2A,0x83,0x08,0x8C,0x9A,0x4B,0x3D,0x01,0x01,0x01,0x03,  /* [ 5015] OBJ_camellia_192_cbc */
++    0x2A,0x83,0x08,0x8C,0x9A,0x4B,0x3D,0x01,0x01,0x01,0x04,  /* [ 5026] OBJ_camellia_256_cbc */
++    0x03,0xA2,0x31,0x05,0x03,0x01,0x09,0x01,       /* [ 5037] OBJ_camellia_128_ecb */
++    0x03,0xA2,0x31,0x05,0x03,0x01,0x09,0x15,       /* [ 5045] OBJ_camellia_192_ecb */
++    0x03,0xA2,0x31,0x05,0x03,0x01,0x09,0x29,       /* [ 5053] OBJ_camellia_256_ecb */
++    0x03,0xA2,0x31,0x05,0x03,0x01,0x09,0x04,       /* [ 5061] OBJ_camellia_128_cfb128 */
++    0x03,0xA2,0x31,0x05,0x03,0x01,0x09,0x18,       /* [ 5069] OBJ_camellia_192_cfb128 */
++    0x03,0xA2,0x31,0x05,0x03,0x01,0x09,0x2C,       /* [ 5077] OBJ_camellia_256_cfb128 */
++    0x03,0xA2,0x31,0x05,0x03,0x01,0x09,0x03,       /* [ 5085] OBJ_camellia_128_ofb128 */
++    0x03,0xA2,0x31,0x05,0x03,0x01,0x09,0x17,       /* [ 5093] OBJ_camellia_192_ofb128 */
++    0x03,0xA2,0x31,0x05,0x03,0x01,0x09,0x2B,       /* [ 5101] OBJ_camellia_256_ofb128 */
++    0x55,0x1D,0x09,                                /* [ 5109] OBJ_subject_directory_attributes */
++    0x55,0x1D,0x1C,                                /* [ 5112] OBJ_issuing_distribution_point */
++    0x55,0x1D,0x1D,                                /* [ 5115] OBJ_certificate_issuer */
++    0x2A,0x83,0x1A,0x8C,0x9A,0x44,                 /* [ 5118] OBJ_kisa */
++    0x2A,0x83,0x1A,0x8C,0x9A,0x44,0x01,0x03,       /* [ 5124] OBJ_seed_ecb */
++    0x2A,0x83,0x1A,0x8C,0x9A,0x44,0x01,0x04,       /* [ 5132] OBJ_seed_cbc */
++    0x2A,0x83,0x1A,0x8C,0x9A,0x44,0x01,0x06,       /* [ 5140] OBJ_seed_ofb128 */
++    0x2A,0x83,0x1A,0x8C,0x9A,0x44,0x01,0x05,       /* [ 5148] OBJ_seed_cfb128 */
++    0x2B,0x06,0x01,0x05,0x05,0x08,0x01,0x01,       /* [ 5156] OBJ_hmac_md5 */
++    0x2B,0x06,0x01,0x05,0x05,0x08,0x01,0x02,       /* [ 5164] OBJ_hmac_sha1 */
++    0x2A,0x86,0x48,0x86,0xF6,0x7D,0x07,0x42,0x0D,  /* [ 5172] OBJ_id_PasswordBasedMAC */
++    0x2A,0x86,0x48,0x86,0xF6,0x7D,0x07,0x42,0x1E,  /* [ 5181] OBJ_id_DHBasedMac */
++    0x2B,0x06,0x01,0x05,0x05,0x07,0x04,0x10,       /* [ 5190] OBJ_id_it_suppLangTags */
++    0x2B,0x06,0x01,0x05,0x05,0x07,0x30,0x05,       /* [ 5198] OBJ_caRepository */
++    0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x09,0x10,0x01,0x09,  /* [ 5206] OBJ_id_smime_ct_compressedData */
++    0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x09,0x10,0x01,0x1B,  /* [ 5217] OBJ_id_ct_asciiTextWithCRLF */
++    0x60,0x86,0x48,0x01,0x65,0x03,0x04,0x01,0x05,  /* [ 5228] OBJ_id_aes128_wrap */
++    0x60,0x86,0x48,0x01,0x65,0x03,0x04,0x01,0x19,  /* [ 5237] OBJ_id_aes192_wrap */
++    0x60,0x86,0x48,0x01,0x65,0x03,0x04,0x01,0x2D,  /* [ 5246] OBJ_id_aes256_wrap */
++    0x2A,0x86,0x48,0xCE,0x3D,0x04,0x02,            /* [ 5255] OBJ_ecdsa_with_Recommended */
++    0x2A,0x86,0x48,0xCE,0x3D,0x04,0x03,            /* [ 5262] OBJ_ecdsa_with_Specified */
++    0x2A,0x86,0x48,0xCE,0x3D,0x04,0x03,0x01,       /* [ 5269] OBJ_ecdsa_with_SHA224 */
++    0x2A,0x86,0x48,0xCE,0x3D,0x04,0x03,0x02,       /* [ 5277] OBJ_ecdsa_with_SHA256 */
++    0x2A,0x86,0x48,0xCE,0x3D,0x04,0x03,0x03,       /* [ 5285] OBJ_ecdsa_with_SHA384 */
++    0x2A,0x86,0x48,0xCE,0x3D,0x04,0x03,0x04,       /* [ 5293] OBJ_ecdsa_with_SHA512 */
++    0x2A,0x86,0x48,0x86,0xF7,0x0D,0x02,0x06,       /* [ 5301] OBJ_hmacWithMD5 */
++    0x2A,0x86,0x48,0x86,0xF7,0x0D,0x02,0x08,       /* [ 5309] OBJ_hmacWithSHA224 */
++    0x2A,0x86,0x48,0x86,0xF7,0x0D,0x02,0x09,       /* [ 5317] OBJ_hmacWithSHA256 */
++    0x2A,0x86,0x48,0x86,0xF7,0x0D,0x02,0x0A,       /* [ 5325] OBJ_hmacWithSHA384 */
++    0x2A,0x86,0x48,0x86,0xF7,0x0D,0x02,0x0B,       /* [ 5333] OBJ_hmacWithSHA512 */
++    0x60,0x86,0x48,0x01,0x65,0x03,0x04,0x03,0x01,  /* [ 5341] OBJ_dsa_with_SHA224 */
++    0x60,0x86,0x48,0x01,0x65,0x03,0x04,0x03,0x02,  /* [ 5350] OBJ_dsa_with_SHA256 */
++    0x28,0xCF,0x06,0x03,0x00,0x37,                 /* [ 5359] OBJ_whirlpool */
++    0x2A,0x85,0x03,0x02,0x02,                      /* [ 5365] OBJ_cryptopro */
++    0x2A,0x85,0x03,0x02,0x09,                      /* [ 5370] OBJ_cryptocom */
++    0x2A,0x85,0x03,0x02,0x02,0x03,                 /* [ 5375] OBJ_id_GostR3411_94_with_GostR3410_2001 */
++    0x2A,0x85,0x03,0x02,0x02,0x04,                 /* [ 5381] OBJ_id_GostR3411_94_with_GostR3410_94 */
++    0x2A,0x85,0x03,0x02,0x02,0x09,                 /* [ 5387] OBJ_id_GostR3411_94 */
++    0x2A,0x85,0x03,0x02,0x02,0x0A,                 /* [ 5393] OBJ_id_HMACGostR3411_94 */
++    0x2A,0x85,0x03,0x02,0x02,0x13,                 /* [ 5399] OBJ_id_GostR3410_2001 */
++    0x2A,0x85,0x03,0x02,0x02,0x14,                 /* [ 5405] OBJ_id_GostR3410_94 */
++    0x2A,0x85,0x03,0x02,0x02,0x15,                 /* [ 5411] OBJ_id_Gost28147_89 */
++    0x2A,0x85,0x03,0x02,0x02,0x16,                 /* [ 5417] OBJ_id_Gost28147_89_MAC */
++    0x2A,0x85,0x03,0x02,0x02,0x17,                 /* [ 5423] OBJ_id_GostR3411_94_prf */
++    0x2A,0x85,0x03,0x02,0x02,0x62,                 /* [ 5429] OBJ_id_GostR3410_2001DH */
++    0x2A,0x85,0x03,0x02,0x02,0x63,                 /* [ 5435] OBJ_id_GostR3410_94DH */
++    0x2A,0x85,0x03,0x02,0x02,0x0E,0x01,            /* [ 5441] OBJ_id_Gost28147_89_CryptoPro_KeyMeshing */
++    0x2A,0x85,0x03,0x02,0x02,0x0E,0x00,            /* [ 5448] OBJ_id_Gost28147_89_None_KeyMeshing */
++    0x2A,0x85,0x03,0x02,0x02,0x1E,0x00,            /* [ 5455] OBJ_id_GostR3411_94_TestParamSet */
++    0x2A,0x85,0x03,0x02,0x02,0x1E,0x01,            /* [ 5462] OBJ_id_GostR3411_94_CryptoProParamSet */
++    0x2A,0x85,0x03,0x02,0x02,0x1F,0x00,            /* [ 5469] OBJ_id_Gost28147_89_TestParamSet */
++    0x2A,0x85,0x03,0x02,0x02,0x1F,0x01,            /* [ 5476] OBJ_id_Gost28147_89_CryptoPro_A_ParamSet */
++    0x2A,0x85,0x03,0x02,0x02,0x1F,0x02,            /* [ 5483] OBJ_id_Gost28147_89_CryptoPro_B_ParamSet */
++    0x2A,0x85,0x03,0x02,0x02,0x1F,0x03,            /* [ 5490] OBJ_id_Gost28147_89_CryptoPro_C_ParamSet */
++    0x2A,0x85,0x03,0x02,0x02,0x1F,0x04,            /* [ 5497] OBJ_id_Gost28147_89_CryptoPro_D_ParamSet */
++    0x2A,0x85,0x03,0x02,0x02,0x1F,0x05,            /* [ 5504] OBJ_id_Gost28147_89_CryptoPro_Oscar_1_1_ParamSet */
++    0x2A,0x85,0x03,0x02,0x02,0x1F,0x06,            /* [ 5511] OBJ_id_Gost28147_89_CryptoPro_Oscar_1_0_ParamSet */
++    0x2A,0x85,0x03,0x02,0x02,0x1F,0x07,            /* [ 5518] OBJ_id_Gost28147_89_CryptoPro_RIC_1_ParamSet */
++    0x2A,0x85,0x03,0x02,0x02,0x20,0x00,            /* [ 5525] OBJ_id_GostR3410_94_TestParamSet */
++    0x2A,0x85,0x03,0x02,0x02,0x20,0x02,            /* [ 5532] OBJ_id_GostR3410_94_CryptoPro_A_ParamSet */
++    0x2A,0x85,0x03,0x02,0x02,0x20,0x03,            /* [ 5539] OBJ_id_GostR3410_94_CryptoPro_B_ParamSet */
++    0x2A,0x85,0x03,0x02,0x02,0x20,0x04,            /* [ 5546] OBJ_id_GostR3410_94_CryptoPro_C_ParamSet */
++    0x2A,0x85,0x03,0x02,0x02,0x20,0x05,            /* [ 5553] OBJ_id_GostR3410_94_CryptoPro_D_ParamSet */
++    0x2A,0x85,0x03,0x02,0x02,0x21,0x01,            /* [ 5560] OBJ_id_GostR3410_94_CryptoPro_XchA_ParamSet */
++    0x2A,0x85,0x03,0x02,0x02,0x21,0x02,            /* [ 5567] OBJ_id_GostR3410_94_CryptoPro_XchB_ParamSet */
++    0x2A,0x85,0x03,0x02,0x02,0x21,0x03,            /* [ 5574] OBJ_id_GostR3410_94_CryptoPro_XchC_ParamSet */
++    0x2A,0x85,0x03,0x02,0x02,0x23,0x00,            /* [ 5581] OBJ_id_GostR3410_2001_TestParamSet */
++    0x2A,0x85,0x03,0x02,0x02,0x23,0x01,            /* [ 5588] OBJ_id_GostR3410_2001_CryptoPro_A_ParamSet */
++    0x2A,0x85,0x03,0x02,0x02,0x23,0x02,            /* [ 5595] OBJ_id_GostR3410_2001_CryptoPro_B_ParamSet */
++    0x2A,0x85,0x03,0x02,0x02,0x23,0x03,            /* [ 5602] OBJ_id_GostR3410_2001_CryptoPro_C_ParamSet */
++    0x2A,0x85,0x03,0x02,0x02,0x24,0x00,            /* [ 5609] OBJ_id_GostR3410_2001_CryptoPro_XchA_ParamSet */
++    0x2A,0x85,0x03,0x02,0x02,0x24,0x01,            /* [ 5616] OBJ_id_GostR3410_2001_CryptoPro_XchB_ParamSet */
++    0x2A,0x85,0x03,0x02,0x02,0x14,0x01,            /* [ 5623] OBJ_id_GostR3410_94_a */
++    0x2A,0x85,0x03,0x02,0x02,0x14,0x02,            /* [ 5630] OBJ_id_GostR3410_94_aBis */
++    0x2A,0x85,0x03,0x02,0x02,0x14,0x03,            /* [ 5637] OBJ_id_GostR3410_94_b */
++    0x2A,0x85,0x03,0x02,0x02,0x14,0x04,            /* [ 5644] OBJ_id_GostR3410_94_bBis */
++    0x2A,0x85,0x03,0x02,0x09,0x01,0x06,0x01,       /* [ 5651] OBJ_id_Gost28147_89_cc */
++    0x2A,0x85,0x03,0x02,0x09,0x01,0x05,0x03,       /* [ 5659] OBJ_id_GostR3410_94_cc */
++    0x2A,0x85,0x03,0x02,0x09,0x01,0x05,0x04,       /* [ 5667] OBJ_id_GostR3410_2001_cc */
++    0x2A,0x85,0x03,0x02,0x09,0x01,0x03,0x03,       /* [ 5675] OBJ_id_GostR3411_94_with_GostR3410_94_cc */
++    0x2A,0x85,0x03,0x02,0x09,0x01,0x03,0x04,       /* [ 5683] OBJ_id_GostR3411_94_with_GostR3410_2001_cc */
++    0x2A,0x85,0x03,0x02,0x09,0x01,0x08,0x01,       /* [ 5691] OBJ_id_GostR3410_2001_ParamSet_cc */
++    0x2B,0x06,0x01,0x04,0x01,0x82,0x37,0x11,0x02,  /* [ 5699] OBJ_LocalKeySet */
++    0x55,0x1D,0x2E,                                /* [ 5708] OBJ_freshest_crl */
++    0x2B,0x06,0x01,0x05,0x05,0x07,0x08,0x03,       /* [ 5711] OBJ_id_on_permanentIdentifier */
++    0x55,0x04,0x0E,                                /* [ 5719] OBJ_searchGuide */
++    0x55,0x04,0x0F,                                /* [ 5722] OBJ_businessCategory */
++    0x55,0x04,0x10,                                /* [ 5725] OBJ_postalAddress */
++    0x55,0x04,0x12,                                /* [ 5728] OBJ_postOfficeBox */
++    0x55,0x04,0x13,                                /* [ 5731] OBJ_physicalDeliveryOfficeName */
++    0x55,0x04,0x14,                                /* [ 5734] OBJ_telephoneNumber */
++    0x55,0x04,0x15,                                /* [ 5737] OBJ_telexNumber */
++    0x55,0x04,0x16,                                /* [ 5740] OBJ_teletexTerminalIdentifier */
++    0x55,0x04,0x17,                                /* [ 5743] OBJ_facsimileTelephoneNumber */
++    0x55,0x04,0x18,                                /* [ 5746] OBJ_x121Address */
++    0x55,0x04,0x19,                                /* [ 5749] OBJ_internationaliSDNNumber */
++    0x55,0x04,0x1A,                                /* [ 5752] OBJ_registeredAddress */
++    0x55,0x04,0x1B,                                /* [ 5755] OBJ_destinationIndicator */
++    0x55,0x04,0x1C,                                /* [ 5758] OBJ_preferredDeliveryMethod */
++    0x55,0x04,0x1D,                                /* [ 5761] OBJ_presentationAddress */
++    0x55,0x04,0x1E,                                /* [ 5764] OBJ_supportedApplicationContext */
++    0x55,0x04,0x1F,                                /* [ 5767] OBJ_member */
++    0x55,0x04,0x20,                                /* [ 5770] OBJ_owner */
++    0x55,0x04,0x21,                                /* [ 5773] OBJ_roleOccupant */
++    0x55,0x04,0x22,                                /* [ 5776] OBJ_seeAlso */
++    0x55,0x04,0x23,                                /* [ 5779] OBJ_userPassword */
++    0x55,0x04,0x24,                                /* [ 5782] OBJ_userCertificate */
++    0x55,0x04,0x25,                                /* [ 5785] OBJ_cACertificate */
++    0x55,0x04,0x26,                                /* [ 5788] OBJ_authorityRevocationList */
++    0x55,0x04,0x27,                                /* [ 5791] OBJ_certificateRevocationList */
++    0x55,0x04,0x28,                                /* [ 5794] OBJ_crossCertificatePair */
++    0x55,0x04,0x2F,                                /* [ 5797] OBJ_enhancedSearchGuide */
++    0x55,0x04,0x30,                                /* [ 5800] OBJ_protocolInformation */
++    0x55,0x04,0x31,                                /* [ 5803] OBJ_distinguishedName */
++    0x55,0x04,0x32,                                /* [ 5806] OBJ_uniqueMember */
++    0x55,0x04,0x33,                                /* [ 5809] OBJ_houseIdentifier */
++    0x55,0x04,0x34,                                /* [ 5812] OBJ_supportedAlgorithms */
++    0x55,0x04,0x35,                                /* [ 5815] OBJ_deltaRevocationList */
++    0x55,0x04,0x36,                                /* [ 5818] OBJ_dmdName */
++    0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x09,0x10,0x03,0x09,  /* [ 5821] OBJ_id_alg_PWRI_KEK */
++    0x60,0x86,0x48,0x01,0x65,0x03,0x04,0x01,0x06,  /* [ 5832] OBJ_aes_128_gcm */
++    0x60,0x86,0x48,0x01,0x65,0x03,0x04,0x01,0x07,  /* [ 5841] OBJ_aes_128_ccm */
++    0x60,0x86,0x48,0x01,0x65,0x03,0x04,0x01,0x08,  /* [ 5850] OBJ_id_aes128_wrap_pad */
++    0x60,0x86,0x48,0x01,0x65,0x03,0x04,0x01,0x1A,  /* [ 5859] OBJ_aes_192_gcm */
++    0x60,0x86,0x48,0x01,0x65,0x03,0x04,0x01,0x1B,  /* [ 5868] OBJ_aes_192_ccm */
++    0x60,0x86,0x48,0x01,0x65,0x03,0x04,0x01,0x1C,  /* [ 5877] OBJ_id_aes192_wrap_pad */
++    0x60,0x86,0x48,0x01,0x65,0x03,0x04,0x01,0x2E,  /* [ 5886] OBJ_aes_256_gcm */
++    0x60,0x86,0x48,0x01,0x65,0x03,0x04,0x01,0x2F,  /* [ 5895] OBJ_aes_256_ccm */
++    0x60,0x86,0x48,0x01,0x65,0x03,0x04,0x01,0x30,  /* [ 5904] OBJ_id_aes256_wrap_pad */
++    0x2A,0x83,0x08,0x8C,0x9A,0x4B,0x3D,0x01,0x01,0x03,0x02,  /* [ 5913] OBJ_id_camellia128_wrap */
++    0x2A,0x83,0x08,0x8C,0x9A,0x4B,0x3D,0x01,0x01,0x03,0x03,  /* [ 5924] OBJ_id_camellia192_wrap */
++    0x2A,0x83,0x08,0x8C,0x9A,0x4B,0x3D,0x01,0x01,0x03,0x04,  /* [ 5935] OBJ_id_camellia256_wrap */
++    0x55,0x1D,0x25,0x00,                           /* [ 5946] OBJ_anyExtendedKeyUsage */
++    0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x08,  /* [ 5950] OBJ_mgf1 */
++    0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x0A,  /* [ 5959] OBJ_rsassaPss */
++    0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x07,  /* [ 5968] OBJ_rsaesOaep */
++    0x2A,0x86,0x48,0xCE,0x3E,0x02,0x01,            /* [ 5977] OBJ_dhpublicnumber */
++    0x2B,0x24,0x03,0x03,0x02,0x08,0x01,0x01,0x01,  /* [ 5984] OBJ_brainpoolP160r1 */
++    0x2B,0x24,0x03,0x03,0x02,0x08,0x01,0x01,0x02,  /* [ 5993] OBJ_brainpoolP160t1 */
++    0x2B,0x24,0x03,0x03,0x02,0x08,0x01,0x01,0x03,  /* [ 6002] OBJ_brainpoolP192r1 */
++    0x2B,0x24,0x03,0x03,0x02,0x08,0x01,0x01,0x04,  /* [ 6011] OBJ_brainpoolP192t1 */
++    0x2B,0x24,0x03,0x03,0x02,0x08,0x01,0x01,0x05,  /* [ 6020] OBJ_brainpoolP224r1 */
++    0x2B,0x24,0x03,0x03,0x02,0x08,0x01,0x01,0x06,  /* [ 6029] OBJ_brainpoolP224t1 */
++    0x2B,0x24,0x03,0x03,0x02,0x08,0x01,0x01,0x07,  /* [ 6038] OBJ_brainpoolP256r1 */
++    0x2B,0x24,0x03,0x03,0x02,0x08,0x01,0x01,0x08,  /* [ 6047] OBJ_brainpoolP256t1 */
++    0x2B,0x24,0x03,0x03,0x02,0x08,0x01,0x01,0x09,  /* [ 6056] OBJ_brainpoolP320r1 */
++    0x2B,0x24,0x03,0x03,0x02,0x08,0x01,0x01,0x0A,  /* [ 6065] OBJ_brainpoolP320t1 */
++    0x2B,0x24,0x03,0x03,0x02,0x08,0x01,0x01,0x0B,  /* [ 6074] OBJ_brainpoolP384r1 */
++    0x2B,0x24,0x03,0x03,0x02,0x08,0x01,0x01,0x0C,  /* [ 6083] OBJ_brainpoolP384t1 */
++    0x2B,0x24,0x03,0x03,0x02,0x08,0x01,0x01,0x0D,  /* [ 6092] OBJ_brainpoolP512r1 */
++    0x2B,0x24,0x03,0x03,0x02,0x08,0x01,0x01,0x0E,  /* [ 6101] OBJ_brainpoolP512t1 */
++    0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x09,  /* [ 6110] OBJ_pSpecified */
++    0x2B,0x81,0x05,0x10,0x86,0x48,0x3F,0x00,0x02,  /* [ 6119] OBJ_dhSinglePass_stdDH_sha1kdf_scheme */
++    0x2B,0x81,0x04,0x01,0x0B,0x00,                 /* [ 6128] OBJ_dhSinglePass_stdDH_sha224kdf_scheme */
++    0x2B,0x81,0x04,0x01,0x0B,0x01,                 /* [ 6134] OBJ_dhSinglePass_stdDH_sha256kdf_scheme */
++    0x2B,0x81,0x04,0x01,0x0B,0x02,                 /* [ 6140] OBJ_dhSinglePass_stdDH_sha384kdf_scheme */
++    0x2B,0x81,0x04,0x01,0x0B,0x03,                 /* [ 6146] OBJ_dhSinglePass_stdDH_sha512kdf_scheme */
++    0x2B,0x81,0x05,0x10,0x86,0x48,0x3F,0x00,0x03,  /* [ 6152] OBJ_dhSinglePass_cofactorDH_sha1kdf_scheme */
++    0x2B,0x81,0x04,0x01,0x0E,0x00,                 /* [ 6161] OBJ_dhSinglePass_cofactorDH_sha224kdf_scheme */
++    0x2B,0x81,0x04,0x01,0x0E,0x01,                 /* [ 6167] OBJ_dhSinglePass_cofactorDH_sha256kdf_scheme */
++    0x2B,0x81,0x04,0x01,0x0E,0x02,                 /* [ 6173] OBJ_dhSinglePass_cofactorDH_sha384kdf_scheme */
++    0x2B,0x81,0x04,0x01,0x0E,0x03,                 /* [ 6179] OBJ_dhSinglePass_cofactorDH_sha512kdf_scheme */
++    0x2B,0x06,0x01,0x04,0x01,0xD6,0x79,0x02,0x04,0x02,  /* [ 6185] OBJ_ct_precert_scts */
++    0x2B,0x06,0x01,0x04,0x01,0xD6,0x79,0x02,0x04,0x03,  /* [ 6195] OBJ_ct_precert_poison */
++    0x2B,0x06,0x01,0x04,0x01,0xD6,0x79,0x02,0x04,0x04,  /* [ 6205] OBJ_ct_precert_signer */
++    0x2B,0x06,0x01,0x04,0x01,0xD6,0x79,0x02,0x04,0x05,  /* [ 6215] OBJ_ct_cert_scts */
++    0x2B,0x06,0x01,0x04,0x01,0x82,0x37,0x3C,0x02,0x01,0x01,  /* [ 6225] OBJ_jurisdictionLocalityName */
++    0x2B,0x06,0x01,0x04,0x01,0x82,0x37,0x3C,0x02,0x01,0x02,  /* [ 6236] OBJ_jurisdictionStateOrProvinceName */
++    0x2B,0x06,0x01,0x04,0x01,0x82,0x37,0x3C,0x02,0x01,0x03,  /* [ 6247] OBJ_jurisdictionCountryName */
++    0x03,0xA2,0x31,0x05,0x03,0x01,0x09,0x06,       /* [ 6258] OBJ_camellia_128_gcm */
++    0x03,0xA2,0x31,0x05,0x03,0x01,0x09,0x07,       /* [ 6266] OBJ_camellia_128_ccm */
++    0x03,0xA2,0x31,0x05,0x03,0x01,0x09,0x09,       /* [ 6274] OBJ_camellia_128_ctr */
++    0x03,0xA2,0x31,0x05,0x03,0x01,0x09,0x0A,       /* [ 6282] OBJ_camellia_128_cmac */
++    0x03,0xA2,0x31,0x05,0x03,0x01,0x09,0x1A,       /* [ 6290] OBJ_camellia_192_gcm */
++    0x03,0xA2,0x31,0x05,0x03,0x01,0x09,0x1B,       /* [ 6298] OBJ_camellia_192_ccm */
++    0x03,0xA2,0x31,0x05,0x03,0x01,0x09,0x1D,       /* [ 6306] OBJ_camellia_192_ctr */
++    0x03,0xA2,0x31,0x05,0x03,0x01,0x09,0x1E,       /* [ 6314] OBJ_camellia_192_cmac */
++    0x03,0xA2,0x31,0x05,0x03,0x01,0x09,0x2E,       /* [ 6322] OBJ_camellia_256_gcm */
++    0x03,0xA2,0x31,0x05,0x03,0x01,0x09,0x2F,       /* [ 6330] OBJ_camellia_256_ccm */
++    0x03,0xA2,0x31,0x05,0x03,0x01,0x09,0x31,       /* [ 6338] OBJ_camellia_256_ctr */
++    0x03,0xA2,0x31,0x05,0x03,0x01,0x09,0x32,       /* [ 6346] OBJ_camellia_256_cmac */
++    0x2B,0x06,0x01,0x04,0x01,0xDA,0x47,0x04,0x0B,  /* [ 6354] OBJ_id_scrypt */
++    0x2A,0x85,0x03,0x07,0x01,                      /* [ 6363] OBJ_id_tc26 */
++    0x2A,0x85,0x03,0x07,0x01,0x01,                 /* [ 6368] OBJ_id_tc26_algorithms */
++    0x2A,0x85,0x03,0x07,0x01,0x01,0x01,            /* [ 6374] OBJ_id_tc26_sign */
++    0x2A,0x85,0x03,0x07,0x01,0x01,0x01,0x01,       /* [ 6381] OBJ_id_GostR3410_2012_256 */
++    0x2A,0x85,0x03,0x07,0x01,0x01,0x01,0x02,       /* [ 6389] OBJ_id_GostR3410_2012_512 */
++    0x2A,0x85,0x03,0x07,0x01,0x01,0x02,            /* [ 6397] OBJ_id_tc26_digest */
++    0x2A,0x85,0x03,0x07,0x01,0x01,0x02,0x02,       /* [ 6404] OBJ_id_GostR3411_2012_256 */
++    0x2A,0x85,0x03,0x07,0x01,0x01,0x02,0x03,       /* [ 6412] OBJ_id_GostR3411_2012_512 */
++    0x2A,0x85,0x03,0x07,0x01,0x01,0x03,            /* [ 6420] OBJ_id_tc26_signwithdigest */
++    0x2A,0x85,0x03,0x07,0x01,0x01,0x03,0x02,       /* [ 6427] OBJ_id_tc26_signwithdigest_gost3410_2012_256 */
++    0x2A,0x85,0x03,0x07,0x01,0x01,0x03,0x03,       /* [ 6435] OBJ_id_tc26_signwithdigest_gost3410_2012_512 */
++    0x2A,0x85,0x03,0x07,0x01,0x01,0x04,            /* [ 6443] OBJ_id_tc26_mac */
++    0x2A,0x85,0x03,0x07,0x01,0x01,0x04,0x01,       /* [ 6450] OBJ_id_tc26_hmac_gost_3411_2012_256 */
++    0x2A,0x85,0x03,0x07,0x01,0x01,0x04,0x02,       /* [ 6458] OBJ_id_tc26_hmac_gost_3411_2012_512 */
++    0x2A,0x85,0x03,0x07,0x01,0x01,0x05,            /* [ 6466] OBJ_id_tc26_cipher */
++    0x2A,0x85,0x03,0x07,0x01,0x01,0x06,            /* [ 6473] OBJ_id_tc26_agreement */
++    0x2A,0x85,0x03,0x07,0x01,0x01,0x06,0x01,       /* [ 6480] OBJ_id_tc26_agreement_gost_3410_2012_256 */
++    0x2A,0x85,0x03,0x07,0x01,0x01,0x06,0x02,       /* [ 6488] OBJ_id_tc26_agreement_gost_3410_2012_512 */
++    0x2A,0x85,0x03,0x07,0x01,0x02,                 /* [ 6496] OBJ_id_tc26_constants */
++    0x2A,0x85,0x03,0x07,0x01,0x02,0x01,            /* [ 6502] OBJ_id_tc26_sign_constants */
++    0x2A,0x85,0x03,0x07,0x01,0x02,0x01,0x02,       /* [ 6509] OBJ_id_tc26_gost_3410_2012_512_constants */
++    0x2A,0x85,0x03,0x07,0x01,0x02,0x01,0x02,0x00,  /* [ 6517] OBJ_id_tc26_gost_3410_2012_512_paramSetTest */
++    0x2A,0x85,0x03,0x07,0x01,0x02,0x01,0x02,0x01,  /* [ 6526] OBJ_id_tc26_gost_3410_2012_512_paramSetA */
++    0x2A,0x85,0x03,0x07,0x01,0x02,0x01,0x02,0x02,  /* [ 6535] OBJ_id_tc26_gost_3410_2012_512_paramSetB */
++    0x2A,0x85,0x03,0x07,0x01,0x02,0x02,            /* [ 6544] OBJ_id_tc26_digest_constants */
++    0x2A,0x85,0x03,0x07,0x01,0x02,0x05,            /* [ 6551] OBJ_id_tc26_cipher_constants */
++    0x2A,0x85,0x03,0x07,0x01,0x02,0x05,0x01,       /* [ 6558] OBJ_id_tc26_gost_28147_constants */
++    0x2A,0x85,0x03,0x07,0x01,0x02,0x05,0x01,0x01,  /* [ 6566] OBJ_id_tc26_gost_28147_param_Z */
++    0x2A,0x85,0x03,0x03,0x81,0x03,0x01,0x01,       /* [ 6575] OBJ_INN */
++    0x2A,0x85,0x03,0x64,0x01,                      /* [ 6583] OBJ_OGRN */
++    0x2A,0x85,0x03,0x64,0x03,                      /* [ 6588] OBJ_SNILS */
++    0x2A,0x85,0x03,0x64,0x6F,                      /* [ 6593] OBJ_subjectSignTool */
++    0x2A,0x85,0x03,0x64,0x70,                      /* [ 6598] OBJ_issuerSignTool */
++    0x2B,0x06,0x01,0x05,0x05,0x07,0x01,0x18,       /* [ 6603] OBJ_tlsfeature */
++    0x2B,0x06,0x01,0x05,0x05,0x07,0x03,0x11,       /* [ 6611] OBJ_ipsec_IKE */
++    0x2B,0x06,0x01,0x05,0x05,0x07,0x03,0x12,       /* [ 6619] OBJ_capwapAC */
++    0x2B,0x06,0x01,0x05,0x05,0x07,0x03,0x13,       /* [ 6627] OBJ_capwapWTP */
++    0x2B,0x06,0x01,0x05,0x05,0x07,0x03,0x15,       /* [ 6635] OBJ_sshClient */
++    0x2B,0x06,0x01,0x05,0x05,0x07,0x03,0x16,       /* [ 6643] OBJ_sshServer */
++    0x2B,0x06,0x01,0x05,0x05,0x07,0x03,0x17,       /* [ 6651] OBJ_sendRouter */
++    0x2B,0x06,0x01,0x05,0x05,0x07,0x03,0x18,       /* [ 6659] OBJ_sendProxiedRouter */
++    0x2B,0x06,0x01,0x05,0x05,0x07,0x03,0x19,       /* [ 6667] OBJ_sendOwner */
++    0x2B,0x06,0x01,0x05,0x05,0x07,0x03,0x1A,       /* [ 6675] OBJ_sendProxiedOwner */
++    0x2B,0x06,0x01,0x05,0x02,0x03,                 /* [ 6683] OBJ_id_pkinit */
++    0x2B,0x06,0x01,0x05,0x02,0x03,0x04,            /* [ 6689] OBJ_pkInitClientAuth */
++    0x2B,0x06,0x01,0x05,0x02,0x03,0x05,            /* [ 6696] OBJ_pkInitKDC */
++    0x2B,0x65,0x6E,                                /* [ 6703] OBJ_X25519 */
++    0x2B,0x65,0x6F,                                /* [ 6706] OBJ_X448 */
++    0x2B,0x06,0x01,0x04,0x01,0x8D,0x3A,0x0C,0x02,0x01,0x10,  /* [ 6709] OBJ_blake2b512 */
++    0x2B,0x06,0x01,0x04,0x01,0x8D,0x3A,0x0C,0x02,0x02,0x08,  /* [ 6720] OBJ_blake2s256 */
++    0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x09,0x10,0x01,0x13,  /* [ 6731] OBJ_id_smime_ct_contentCollection */
++    0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x09,0x10,0x01,0x17,  /* [ 6742] OBJ_id_smime_ct_authEnvelopedData */
++    0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x09,0x10,0x01,0x1C,  /* [ 6753] OBJ_id_ct_xml */
++};
++
++#define NUM_NID 1061
++static const ASN1_OBJECT nid_objs[NUM_NID] = {
++    {"UNDEF", "undefined", NID_undef},
++    {"rsadsi", "RSA Data Security, Inc.", NID_rsadsi, 6, &so[0]},
++    {"pkcs", "RSA Data Security, Inc. PKCS", NID_pkcs, 7, &so[6]},
++    {"MD2", "md2", NID_md2, 8, &so[13]},
++    {"MD5", "md5", NID_md5, 8, &so[21]},
++    {"RC4", "rc4", NID_rc4, 8, &so[29]},
++    {"rsaEncryption", "rsaEncryption", NID_rsaEncryption, 9, &so[37]},
++    {"RSA-MD2", "md2WithRSAEncryption", NID_md2WithRSAEncryption, 9, &so[46]},
++    {"RSA-MD5", "md5WithRSAEncryption", NID_md5WithRSAEncryption, 9, &so[55]},
++    {"PBE-MD2-DES", "pbeWithMD2AndDES-CBC", NID_pbeWithMD2AndDES_CBC, 9, &so[64]},
++    {"PBE-MD5-DES", "pbeWithMD5AndDES-CBC", NID_pbeWithMD5AndDES_CBC, 9, &so[73]},
++    {"X500", "directory services (X.500)", NID_X500, 1, &so[82]},
++    {"X509", "X509", NID_X509, 2, &so[83]},
++    {"CN", "commonName", NID_commonName, 3, &so[85]},
++    {"C", "countryName", NID_countryName, 3, &so[88]},
++    {"L", "localityName", NID_localityName, 3, &so[91]},
++    {"ST", "stateOrProvinceName", NID_stateOrProvinceName, 3, &so[94]},
++    {"O", "organizationName", NID_organizationName, 3, &so[97]},
++    {"OU", "organizationalUnitName", NID_organizationalUnitName, 3, &so[100]},
++    {"RSA", "rsa", NID_rsa, 4, &so[103]},
++    {"pkcs7", "pkcs7", NID_pkcs7, 8, &so[107]},
++    {"pkcs7-data", "pkcs7-data", NID_pkcs7_data, 9, &so[115]},
++    {"pkcs7-signedData", "pkcs7-signedData", NID_pkcs7_signed, 9, &so[124]},
++    {"pkcs7-envelopedData", "pkcs7-envelopedData", NID_pkcs7_enveloped, 9, &so[133]},
++    {"pkcs7-signedAndEnvelopedData", "pkcs7-signedAndEnvelopedData", NID_pkcs7_signedAndEnveloped, 9, &so[142]},
++    {"pkcs7-digestData", "pkcs7-digestData", NID_pkcs7_digest, 9, &so[151]},
++    {"pkcs7-encryptedData", "pkcs7-encryptedData", NID_pkcs7_encrypted, 9, &so[160]},
++    {"pkcs3", "pkcs3", NID_pkcs3, 8, &so[169]},
++    {"dhKeyAgreement", "dhKeyAgreement", NID_dhKeyAgreement, 9, &so[177]},
++    {"DES-ECB", "des-ecb", NID_des_ecb, 5, &so[186]},
++    {"DES-CFB", "des-cfb", NID_des_cfb64, 5, &so[191]},
++    {"DES-CBC", "des-cbc", NID_des_cbc, 5, &so[196]},
++    {"DES-EDE", "des-ede", NID_des_ede_ecb, 5, &so[201]},
++    {"DES-EDE3", "des-ede3", NID_des_ede3_ecb},
++    {"IDEA-CBC", "idea-cbc", NID_idea_cbc, 11, &so[206]},
++    {"IDEA-CFB", "idea-cfb", NID_idea_cfb64},
++    {"IDEA-ECB", "idea-ecb", NID_idea_ecb},
++    {"RC2-CBC", "rc2-cbc", NID_rc2_cbc, 8, &so[217]},
++    {"RC2-ECB", "rc2-ecb", NID_rc2_ecb},
++    {"RC2-CFB", "rc2-cfb", NID_rc2_cfb64},
++    {"RC2-OFB", "rc2-ofb", NID_rc2_ofb64},
++    {"SHA", "sha", NID_sha, 5, &so[225]},
++    {"RSA-SHA", "shaWithRSAEncryption", NID_shaWithRSAEncryption, 5, &so[230]},
++    {"DES-EDE-CBC", "des-ede-cbc", NID_des_ede_cbc},
++    {"DES-EDE3-CBC", "des-ede3-cbc", NID_des_ede3_cbc, 8, &so[235]},
++    {"DES-OFB", "des-ofb", NID_des_ofb64, 5, &so[243]},
++    {"IDEA-OFB", "idea-ofb", NID_idea_ofb64},
++    {"pkcs9", "pkcs9", NID_pkcs9, 8, &so[248]},
++    {"emailAddress", "emailAddress", NID_pkcs9_emailAddress, 9, &so[256]},
++    {"unstructuredName", "unstructuredName", NID_pkcs9_unstructuredName, 9, &so[265]},
++    {"contentType", "contentType", NID_pkcs9_contentType, 9, &so[274]},
++    {"messageDigest", "messageDigest", NID_pkcs9_messageDigest, 9, &so[283]},
++    {"signingTime", "signingTime", NID_pkcs9_signingTime, 9, &so[292]},
++    {"countersignature", "countersignature", NID_pkcs9_countersignature, 9, &so[301]},
++    {"challengePassword", "challengePassword", NID_pkcs9_challengePassword, 9, &so[310]},
++    {"unstructuredAddress", "unstructuredAddress", NID_pkcs9_unstructuredAddress, 9, &so[319]},
++    {"extendedCertificateAttributes", "extendedCertificateAttributes", NID_pkcs9_extCertAttributes, 9, &so[328]},
++    {"Netscape", "Netscape Communications Corp.", NID_netscape, 7, &so[337]},
++    {"nsCertExt", "Netscape Certificate Extension", NID_netscape_cert_extension, 8, &so[344]},
++    {"nsDataType", "Netscape Data Type", NID_netscape_data_type, 8, &so[352]},
++    {"DES-EDE-CFB", "des-ede-cfb", NID_des_ede_cfb64},
++    {"DES-EDE3-CFB", "des-ede3-cfb", NID_des_ede3_cfb64},
++    {"DES-EDE-OFB", "des-ede-ofb", NID_des_ede_ofb64},
++    {"DES-EDE3-OFB", "des-ede3-ofb", NID_des_ede3_ofb64},
++    {"SHA1", "sha1", NID_sha1, 5, &so[360]},
++    {"RSA-SHA1", "sha1WithRSAEncryption", NID_sha1WithRSAEncryption, 9, &so[365]},
++    {"DSA-SHA", "dsaWithSHA", NID_dsaWithSHA, 5, &so[374]},
++    {"DSA-old", "dsaEncryption-old", NID_dsa_2, 5, &so[379]},
++    {"PBE-SHA1-RC2-64", "pbeWithSHA1AndRC2-CBC", NID_pbeWithSHA1AndRC2_CBC, 9, &so[384]},
++    {"PBKDF2", "PBKDF2", NID_id_pbkdf2, 9, &so[393]},
++    {"DSA-SHA1-old", "dsaWithSHA1-old", NID_dsaWithSHA1_2, 5, &so[402]},
++    {"nsCertType", "Netscape Cert Type", NID_netscape_cert_type, 9, &so[407]},
++    {"nsBaseUrl", "Netscape Base Url", NID_netscape_base_url, 9, &so[416]},
++    {"nsRevocationUrl", "Netscape Revocation Url", NID_netscape_revocation_url, 9, &so[425]},
++    {"nsCaRevocationUrl", "Netscape CA Revocation Url", NID_netscape_ca_revocation_url, 9, &so[434]},
++    {"nsRenewalUrl", "Netscape Renewal Url", NID_netscape_renewal_url, 9, &so[443]},
++    {"nsCaPolicyUrl", "Netscape CA Policy Url", NID_netscape_ca_policy_url, 9, &so[452]},
++    {"nsSslServerName", "Netscape SSL Server Name", NID_netscape_ssl_server_name, 9, &so[461]},
++    {"nsComment", "Netscape Comment", NID_netscape_comment, 9, &so[470]},
++    {"nsCertSequence", "Netscape Certificate Sequence", NID_netscape_cert_sequence, 9, &so[479]},
++    {"DESX-CBC", "desx-cbc", NID_desx_cbc},
++    {"id-ce", "id-ce", NID_id_ce, 2, &so[488]},
++    {"subjectKeyIdentifier", "X509v3 Subject Key Identifier", NID_subject_key_identifier, 3, &so[490]},
++    {"keyUsage", "X509v3 Key Usage", NID_key_usage, 3, &so[493]},
++    {"privateKeyUsagePeriod", "X509v3 Private Key Usage Period", NID_private_key_usage_period, 3, &so[496]},
++    {"subjectAltName", "X509v3 Subject Alternative Name", NID_subject_alt_name, 3, &so[499]},
++    {"issuerAltName", "X509v3 Issuer Alternative Name", NID_issuer_alt_name, 3, &so[502]},
++    {"basicConstraints", "X509v3 Basic Constraints", NID_basic_constraints, 3, &so[505]},
++    {"crlNumber", "X509v3 CRL Number", NID_crl_number, 3, &so[508]},
++    {"certificatePolicies", "X509v3 Certificate Policies", NID_certificate_policies, 3, &so[511]},
++    {"authorityKeyIdentifier", "X509v3 Authority Key Identifier", NID_authority_key_identifier, 3, &so[514]},
++    {"BF-CBC", "bf-cbc", NID_bf_cbc, 9, &so[517]},
++    {"BF-ECB", "bf-ecb", NID_bf_ecb},
++    {"BF-CFB", "bf-cfb", NID_bf_cfb64},
++    {"BF-OFB", "bf-ofb", NID_bf_ofb64},
++    {"MDC2", "mdc2", NID_mdc2, 4, &so[526]},
++    {"RSA-MDC2", "mdc2WithRSA", NID_mdc2WithRSA, 4, &so[530]},
++    {"RC4-40", "rc4-40", NID_rc4_40},
++    {"RC2-40-CBC", "rc2-40-cbc", NID_rc2_40_cbc},
++    {"GN", "givenName", NID_givenName, 3, &so[534]},
++    {"SN", "surname", NID_surname, 3, &so[537]},
++    {"initials", "initials", NID_initials, 3, &so[540]},
++    {"uid", "uniqueIdentifier", NID_uniqueIdentifier, 10, &so[543]},
++    {"crlDistributionPoints", "X509v3 CRL Distribution Points", NID_crl_distribution_points, 3, &so[553]},
++    {"RSA-NP-MD5", "md5WithRSA", NID_md5WithRSA, 5, &so[556]},
++    {"serialNumber", "serialNumber", NID_serialNumber, 3, &so[561]},
++    {"title", "title", NID_title, 3, &so[564]},
++    {"description", "description", NID_description, 3, &so[567]},
++    {"CAST5-CBC", "cast5-cbc", NID_cast5_cbc, 9, &so[570]},
++    {"CAST5-ECB", "cast5-ecb", NID_cast5_ecb},
++    {"CAST5-CFB", "cast5-cfb", NID_cast5_cfb64},
++    {"CAST5-OFB", "cast5-ofb", NID_cast5_ofb64},
++    {"pbeWithMD5AndCast5CBC", "pbeWithMD5AndCast5CBC", NID_pbeWithMD5AndCast5_CBC, 9, &so[579]},
++    {"DSA-SHA1", "dsaWithSHA1", NID_dsaWithSHA1, 7, &so[588]},
++    {"MD5-SHA1", "md5-sha1", NID_md5_sha1},
++    {"RSA-SHA1-2", "sha1WithRSA", NID_sha1WithRSA, 5, &so[595]},
++    {"DSA", "dsaEncryption", NID_dsa, 7, &so[600]},
++    {"RIPEMD160", "ripemd160", NID_ripemd160, 5, &so[607]},
++    { NULL, NULL, NID_undef },
++    {"RSA-RIPEMD160", "ripemd160WithRSA", NID_ripemd160WithRSA, 6, &so[612]},
++    {"RC5-CBC", "rc5-cbc", NID_rc5_cbc, 8, &so[618]},
++    {"RC5-ECB", "rc5-ecb", NID_rc5_ecb},
++    {"RC5-CFB", "rc5-cfb", NID_rc5_cfb64},
++    {"RC5-OFB", "rc5-ofb", NID_rc5_ofb64},
++    { NULL, NULL, NID_undef },
++    {"ZLIB", "zlib compression", NID_zlib_compression, 11, &so[626]},
++    {"extendedKeyUsage", "X509v3 Extended Key Usage", NID_ext_key_usage, 3, &so[637]},
++    {"PKIX", "PKIX", NID_id_pkix, 6, &so[640]},
++    {"id-kp", "id-kp", NID_id_kp, 7, &so[646]},
++    {"serverAuth", "TLS Web Server Authentication", NID_server_auth, 8, &so[653]},
++    {"clientAuth", "TLS Web Client Authentication", NID_client_auth, 8, &so[661]},
++    {"codeSigning", "Code Signing", NID_code_sign, 8, &so[669]},
++    {"emailProtection", "E-mail Protection", NID_email_protect, 8, &so[677]},
++    {"timeStamping", "Time Stamping", NID_time_stamp, 8, &so[685]},
++    {"msCodeInd", "Microsoft Individual Code Signing", NID_ms_code_ind, 10, &so[693]},
++    {"msCodeCom", "Microsoft Commercial Code Signing", NID_ms_code_com, 10, &so[703]},
++    {"msCTLSign", "Microsoft Trust List Signing", NID_ms_ctl_sign, 10, &so[713]},
++    {"msSGC", "Microsoft Server Gated Crypto", NID_ms_sgc, 10, &so[723]},
++    {"msEFS", "Microsoft Encrypted File System", NID_ms_efs, 10, &so[733]},
++    {"nsSGC", "Netscape Server Gated Crypto", NID_ns_sgc, 9, &so[743]},
++    {"deltaCRL", "X509v3 Delta CRL Indicator", NID_delta_crl, 3, &so[752]},
++    {"CRLReason", "X509v3 CRL Reason Code", NID_crl_reason, 3, &so[755]},
++    {"invalidityDate", "Invalidity Date", NID_invalidity_date, 3, &so[758]},
++    {"SXNetID", "Strong Extranet ID", NID_sxnet, 5, &so[761]},
++    {"PBE-SHA1-RC4-128", "pbeWithSHA1And128BitRC4", NID_pbe_WithSHA1And128BitRC4, 10, &so[766]},
++    {"PBE-SHA1-RC4-40", "pbeWithSHA1And40BitRC4", NID_pbe_WithSHA1And40BitRC4, 10, &so[776]},
++    {"PBE-SHA1-3DES", "pbeWithSHA1And3-KeyTripleDES-CBC", NID_pbe_WithSHA1And3_Key_TripleDES_CBC, 10, &so[786]},
++    {"PBE-SHA1-2DES", "pbeWithSHA1And2-KeyTripleDES-CBC", NID_pbe_WithSHA1And2_Key_TripleDES_CBC, 10, &so[796]},
++    {"PBE-SHA1-RC2-128", "pbeWithSHA1And128BitRC2-CBC", NID_pbe_WithSHA1And128BitRC2_CBC, 10, &so[806]},
++    {"PBE-SHA1-RC2-40", "pbeWithSHA1And40BitRC2-CBC", NID_pbe_WithSHA1And40BitRC2_CBC, 10, &so[816]},
++    {"keyBag", "keyBag", NID_keyBag, 11, &so[826]},
++    {"pkcs8ShroudedKeyBag", "pkcs8ShroudedKeyBag", NID_pkcs8ShroudedKeyBag, 11, &so[837]},
++    {"certBag", "certBag", NID_certBag, 11, &so[848]},
++    {"crlBag", "crlBag", NID_crlBag, 11, &so[859]},
++    {"secretBag", "secretBag", NID_secretBag, 11, &so[870]},
++    {"safeContentsBag", "safeContentsBag", NID_safeContentsBag, 11, &so[881]},
++    {"friendlyName", "friendlyName", NID_friendlyName, 9, &so[892]},
++    {"localKeyID", "localKeyID", NID_localKeyID, 9, &so[901]},
++    {"x509Certificate", "x509Certificate", NID_x509Certificate, 10, &so[910]},
++    {"sdsiCertificate", "sdsiCertificate", NID_sdsiCertificate, 10, &so[920]},
++    {"x509Crl", "x509Crl", NID_x509Crl, 10, &so[930]},
++    {"PBES2", "PBES2", NID_pbes2, 9, &so[940]},
++    {"PBMAC1", "PBMAC1", NID_pbmac1, 9, &so[949]},
++    {"hmacWithSHA1", "hmacWithSHA1", NID_hmacWithSHA1, 8, &so[958]},
++    {"id-qt-cps", "Policy Qualifier CPS", NID_id_qt_cps, 8, &so[966]},
++    {"id-qt-unotice", "Policy Qualifier User Notice", NID_id_qt_unotice, 8, &so[974]},
++    {"RC2-64-CBC", "rc2-64-cbc", NID_rc2_64_cbc},
++    {"SMIME-CAPS", "S/MIME Capabilities", NID_SMIMECapabilities, 9, &so[982]},
++    {"PBE-MD2-RC2-64", "pbeWithMD2AndRC2-CBC", NID_pbeWithMD2AndRC2_CBC, 9, &so[991]},
++    {"PBE-MD5-RC2-64", "pbeWithMD5AndRC2-CBC", NID_pbeWithMD5AndRC2_CBC, 9, &so[1000]},
++    {"PBE-SHA1-DES", "pbeWithSHA1AndDES-CBC", NID_pbeWithSHA1AndDES_CBC, 9, &so[1009]},
++    {"msExtReq", "Microsoft Extension Request", NID_ms_ext_req, 10, &so[1018]},
++    {"extReq", "Extension Request", NID_ext_req, 9, &so[1028]},
++    {"name", "name", NID_name, 3, &so[1037]},
++    {"dnQualifier", "dnQualifier", NID_dnQualifier, 3, &so[1040]},
++    {"id-pe", "id-pe", NID_id_pe, 7, &so[1043]},
++    {"id-ad", "id-ad", NID_id_ad, 7, &so[1050]},
++    {"authorityInfoAccess", "Authority Information Access", NID_info_access, 8, &so[1057]},
++    {"OCSP", "OCSP", NID_ad_OCSP, 8, &so[1065]},
++    {"caIssuers", "CA Issuers", NID_ad_ca_issuers, 8, &so[1073]},
++    {"OCSPSigning", "OCSP Signing", NID_OCSP_sign, 8, &so[1081]},
++    {"ISO", "iso", NID_iso},
++    {"member-body", "ISO Member Body", NID_member_body, 1, &so[1089]},
++    {"ISO-US", "ISO US Member Body", NID_ISO_US, 3, &so[1090]},
++    {"X9-57", "X9.57", NID_X9_57, 5, &so[1093]},
++    {"X9cm", "X9.57 CM ?", NID_X9cm, 6, &so[1098]},
++    {"pkcs1", "pkcs1", NID_pkcs1, 8, &so[1104]},
++    {"pkcs5", "pkcs5", NID_pkcs5, 8, &so[1112]},
++    {"SMIME", "S/MIME", NID_SMIME, 9, &so[1120]},
++    {"id-smime-mod", "id-smime-mod", NID_id_smime_mod, 10, &so[1129]},
++    {"id-smime-ct", "id-smime-ct", NID_id_smime_ct, 10, &so[1139]},
++    {"id-smime-aa", "id-smime-aa", NID_id_smime_aa, 10, &so[1149]},
++    {"id-smime-alg", "id-smime-alg", NID_id_smime_alg, 10, &so[1159]},
++    {"id-smime-cd", "id-smime-cd", NID_id_smime_cd, 10, &so[1169]},
++    {"id-smime-spq", "id-smime-spq", NID_id_smime_spq, 10, &so[1179]},
++    {"id-smime-cti", "id-smime-cti", NID_id_smime_cti, 10, &so[1189]},
++    {"id-smime-mod-cms", "id-smime-mod-cms", NID_id_smime_mod_cms, 11, &so[1199]},
++    {"id-smime-mod-ess", "id-smime-mod-ess", NID_id_smime_mod_ess, 11, &so[1210]},
++    {"id-smime-mod-oid", "id-smime-mod-oid", NID_id_smime_mod_oid, 11, &so[1221]},
++    {"id-smime-mod-msg-v3", "id-smime-mod-msg-v3", NID_id_smime_mod_msg_v3, 11, &so[1232]},
++    {"id-smime-mod-ets-eSignature-88", "id-smime-mod-ets-eSignature-88", NID_id_smime_mod_ets_eSignature_88, 11, &so[1243]},
++    {"id-smime-mod-ets-eSignature-97", "id-smime-mod-ets-eSignature-97", NID_id_smime_mod_ets_eSignature_97, 11, &so[1254]},
++    {"id-smime-mod-ets-eSigPolicy-88", "id-smime-mod-ets-eSigPolicy-88", NID_id_smime_mod_ets_eSigPolicy_88, 11, &so[1265]},
++    {"id-smime-mod-ets-eSigPolicy-97", "id-smime-mod-ets-eSigPolicy-97", NID_id_smime_mod_ets_eSigPolicy_97, 11, &so[1276]},
++    {"id-smime-ct-receipt", "id-smime-ct-receipt", NID_id_smime_ct_receipt, 11, &so[1287]},
++    {"id-smime-ct-authData", "id-smime-ct-authData", NID_id_smime_ct_authData, 11, &so[1298]},
++    {"id-smime-ct-publishCert", "id-smime-ct-publishCert", NID_id_smime_ct_publishCert, 11, &so[1309]},
++    {"id-smime-ct-TSTInfo", "id-smime-ct-TSTInfo", NID_id_smime_ct_TSTInfo, 11, &so[1320]},
++    {"id-smime-ct-TDTInfo", "id-smime-ct-TDTInfo", NID_id_smime_ct_TDTInfo, 11, &so[1331]},
++    {"id-smime-ct-contentInfo", "id-smime-ct-contentInfo", NID_id_smime_ct_contentInfo, 11, &so[1342]},
++    {"id-smime-ct-DVCSRequestData", "id-smime-ct-DVCSRequestData", NID_id_smime_ct_DVCSRequestData, 11, &so[1353]},
++    {"id-smime-ct-DVCSResponseData", "id-smime-ct-DVCSResponseData", NID_id_smime_ct_DVCSResponseData, 11, &so[1364]},
++    {"id-smime-aa-receiptRequest", "id-smime-aa-receiptRequest", NID_id_smime_aa_receiptRequest, 11, &so[1375]},
++    {"id-smime-aa-securityLabel", "id-smime-aa-securityLabel", NID_id_smime_aa_securityLabel, 11, &so[1386]},
++    {"id-smime-aa-mlExpandHistory", "id-smime-aa-mlExpandHistory", NID_id_smime_aa_mlExpandHistory, 11, &so[1397]},
++    {"id-smime-aa-contentHint", "id-smime-aa-contentHint", NID_id_smime_aa_contentHint, 11, &so[1408]},
++    {"id-smime-aa-msgSigDigest", "id-smime-aa-msgSigDigest", NID_id_smime_aa_msgSigDigest, 11, &so[1419]},
++    {"id-smime-aa-encapContentType", "id-smime-aa-encapContentType", NID_id_smime_aa_encapContentType, 11, &so[1430]},
++    {"id-smime-aa-contentIdentifier", "id-smime-aa-contentIdentifier", NID_id_smime_aa_contentIdentifier, 11, &so[1441]},
++    {"id-smime-aa-macValue", "id-smime-aa-macValue", NID_id_smime_aa_macValue, 11, &so[1452]},
++    {"id-smime-aa-equivalentLabels", "id-smime-aa-equivalentLabels", NID_id_smime_aa_equivalentLabels, 11, &so[1463]},
++    {"id-smime-aa-contentReference", "id-smime-aa-contentReference", NID_id_smime_aa_contentReference, 11, &so[1474]},
++    {"id-smime-aa-encrypKeyPref", "id-smime-aa-encrypKeyPref", NID_id_smime_aa_encrypKeyPref, 11, &so[1485]},
++    {"id-smime-aa-signingCertificate", "id-smime-aa-signingCertificate", NID_id_smime_aa_signingCertificate, 11, &so[1496]},
++    {"id-smime-aa-smimeEncryptCerts", "id-smime-aa-smimeEncryptCerts", NID_id_smime_aa_smimeEncryptCerts, 11, &so[1507]},
++    {"id-smime-aa-timeStampToken", "id-smime-aa-timeStampToken", NID_id_smime_aa_timeStampToken, 11, &so[1518]},
++    {"id-smime-aa-ets-sigPolicyId", "id-smime-aa-ets-sigPolicyId", NID_id_smime_aa_ets_sigPolicyId, 11, &so[1529]},
++    {"id-smime-aa-ets-commitmentType", "id-smime-aa-ets-commitmentType", NID_id_smime_aa_ets_commitmentType, 11, &so[1540]},
++    {"id-smime-aa-ets-signerLocation", "id-smime-aa-ets-signerLocation", NID_id_smime_aa_ets_signerLocation, 11, &so[1551]},
++    {"id-smime-aa-ets-signerAttr", "id-smime-aa-ets-signerAttr", NID_id_smime_aa_ets_signerAttr, 11, &so[1562]},
++    {"id-smime-aa-ets-otherSigCert", "id-smime-aa-ets-otherSigCert", NID_id_smime_aa_ets_otherSigCert, 11, &so[1573]},
++    {"id-smime-aa-ets-contentTimestamp", "id-smime-aa-ets-contentTimestamp", NID_id_smime_aa_ets_contentTimestamp, 11, &so[1584]},
++    {"id-smime-aa-ets-CertificateRefs", "id-smime-aa-ets-CertificateRefs", NID_id_smime_aa_ets_CertificateRefs, 11, &so[1595]},
++    {"id-smime-aa-ets-RevocationRefs", "id-smime-aa-ets-RevocationRefs", NID_id_smime_aa_ets_RevocationRefs, 11, &so[1606]},
++    {"id-smime-aa-ets-certValues", "id-smime-aa-ets-certValues", NID_id_smime_aa_ets_certValues, 11, &so[1617]},
++    {"id-smime-aa-ets-revocationValues", "id-smime-aa-ets-revocationValues", NID_id_smime_aa_ets_revocationValues, 11, &so[1628]},
++    {"id-smime-aa-ets-escTimeStamp", "id-smime-aa-ets-escTimeStamp", NID_id_smime_aa_ets_escTimeStamp, 11, &so[1639]},
++    {"id-smime-aa-ets-certCRLTimestamp", "id-smime-aa-ets-certCRLTimestamp", NID_id_smime_aa_ets_certCRLTimestamp, 11, &so[1650]},
++    {"id-smime-aa-ets-archiveTimeStamp", "id-smime-aa-ets-archiveTimeStamp", NID_id_smime_aa_ets_archiveTimeStamp, 11, &so[1661]},
++    {"id-smime-aa-signatureType", "id-smime-aa-signatureType", NID_id_smime_aa_signatureType, 11, &so[1672]},
++    {"id-smime-aa-dvcs-dvc", "id-smime-aa-dvcs-dvc", NID_id_smime_aa_dvcs_dvc, 11, &so[1683]},
++    {"id-smime-alg-ESDHwith3DES", "id-smime-alg-ESDHwith3DES", NID_id_smime_alg_ESDHwith3DES, 11, &so[1694]},
++    {"id-smime-alg-ESDHwithRC2", "id-smime-alg-ESDHwithRC2", NID_id_smime_alg_ESDHwithRC2, 11, &so[1705]},
++    {"id-smime-alg-3DESwrap", "id-smime-alg-3DESwrap", NID_id_smime_alg_3DESwrap, 11, &so[1716]},
++    {"id-smime-alg-RC2wrap", "id-smime-alg-RC2wrap", NID_id_smime_alg_RC2wrap, 11, &so[1727]},
++    {"id-smime-alg-ESDH", "id-smime-alg-ESDH", NID_id_smime_alg_ESDH, 11, &so[1738]},
++    {"id-smime-alg-CMS3DESwrap", "id-smime-alg-CMS3DESwrap", NID_id_smime_alg_CMS3DESwrap, 11, &so[1749]},
++    {"id-smime-alg-CMSRC2wrap", "id-smime-alg-CMSRC2wrap", NID_id_smime_alg_CMSRC2wrap, 11, &so[1760]},
++    {"id-smime-cd-ldap", "id-smime-cd-ldap", NID_id_smime_cd_ldap, 11, &so[1771]},
++    {"id-smime-spq-ets-sqt-uri", "id-smime-spq-ets-sqt-uri", NID_id_smime_spq_ets_sqt_uri, 11, &so[1782]},
++    {"id-smime-spq-ets-sqt-unotice", "id-smime-spq-ets-sqt-unotice", NID_id_smime_spq_ets_sqt_unotice, 11, &so[1793]},
++    {"id-smime-cti-ets-proofOfOrigin", "id-smime-cti-ets-proofOfOrigin", NID_id_smime_cti_ets_proofOfOrigin, 11, &so[1804]},
++    {"id-smime-cti-ets-proofOfReceipt", "id-smime-cti-ets-proofOfReceipt", NID_id_smime_cti_ets_proofOfReceipt, 11, &so[1815]},
++    {"id-smime-cti-ets-proofOfDelivery", "id-smime-cti-ets-proofOfDelivery", NID_id_smime_cti_ets_proofOfDelivery, 11, &so[1826]},
++    {"id-smime-cti-ets-proofOfSender", "id-smime-cti-ets-proofOfSender", NID_id_smime_cti_ets_proofOfSender, 11, &so[1837]},
++    {"id-smime-cti-ets-proofOfApproval", "id-smime-cti-ets-proofOfApproval", NID_id_smime_cti_ets_proofOfApproval, 11, &so[1848]},
++    {"id-smime-cti-ets-proofOfCreation", "id-smime-cti-ets-proofOfCreation", NID_id_smime_cti_ets_proofOfCreation, 11, &so[1859]},
++    {"MD4", "md4", NID_md4, 8, &so[1870]},
++    {"id-pkix-mod", "id-pkix-mod", NID_id_pkix_mod, 7, &so[1878]},
++    {"id-qt", "id-qt", NID_id_qt, 7, &so[1885]},
++    {"id-it", "id-it", NID_id_it, 7, &so[1892]},
++    {"id-pkip", "id-pkip", NID_id_pkip, 7, &so[1899]},
++    {"id-alg", "id-alg", NID_id_alg, 7, &so[1906]},
++    {"id-cmc", "id-cmc", NID_id_cmc, 7, &so[1913]},
++    {"id-on", "id-on", NID_id_on, 7, &so[1920]},
++    {"id-pda", "id-pda", NID_id_pda, 7, &so[1927]},
++    {"id-aca", "id-aca", NID_id_aca, 7, &so[1934]},
++    {"id-qcs", "id-qcs", NID_id_qcs, 7, &so[1941]},
++    {"id-cct", "id-cct", NID_id_cct, 7, &so[1948]},
++    {"id-pkix1-explicit-88", "id-pkix1-explicit-88", NID_id_pkix1_explicit_88, 8, &so[1955]},
++    {"id-pkix1-implicit-88", "id-pkix1-implicit-88", NID_id_pkix1_implicit_88, 8, &so[1963]},
++    {"id-pkix1-explicit-93", "id-pkix1-explicit-93", NID_id_pkix1_explicit_93, 8, &so[1971]},
++    {"id-pkix1-implicit-93", "id-pkix1-implicit-93", NID_id_pkix1_implicit_93, 8, &so[1979]},
++    {"id-mod-crmf", "id-mod-crmf", NID_id_mod_crmf, 8, &so[1987]},
++    {"id-mod-cmc", "id-mod-cmc", NID_id_mod_cmc, 8, &so[1995]},
++    {"id-mod-kea-profile-88", "id-mod-kea-profile-88", NID_id_mod_kea_profile_88, 8, &so[2003]},
++    {"id-mod-kea-profile-93", "id-mod-kea-profile-93", NID_id_mod_kea_profile_93, 8, &so[2011]},
++    {"id-mod-cmp", "id-mod-cmp", NID_id_mod_cmp, 8, &so[2019]},
++    {"id-mod-qualified-cert-88", "id-mod-qualified-cert-88", NID_id_mod_qualified_cert_88, 8, &so[2027]},
++    {"id-mod-qualified-cert-93", "id-mod-qualified-cert-93", NID_id_mod_qualified_cert_93, 8, &so[2035]},
++    {"id-mod-attribute-cert", "id-mod-attribute-cert", NID_id_mod_attribute_cert, 8, &so[2043]},
++    {"id-mod-timestamp-protocol", "id-mod-timestamp-protocol", NID_id_mod_timestamp_protocol, 8, &so[2051]},
++    {"id-mod-ocsp", "id-mod-ocsp", NID_id_mod_ocsp, 8, &so[2059]},
++    {"id-mod-dvcs", "id-mod-dvcs", NID_id_mod_dvcs, 8, &so[2067]},
++    {"id-mod-cmp2000", "id-mod-cmp2000", NID_id_mod_cmp2000, 8, &so[2075]},
++    {"biometricInfo", "Biometric Info", NID_biometricInfo, 8, &so[2083]},
++    {"qcStatements", "qcStatements", NID_qcStatements, 8, &so[2091]},
++    {"ac-auditEntity", "ac-auditEntity", NID_ac_auditEntity, 8, &so[2099]},
++    {"ac-targeting", "ac-targeting", NID_ac_targeting, 8, &so[2107]},
++    {"aaControls", "aaControls", NID_aaControls, 8, &so[2115]},
++    {"sbgp-ipAddrBlock", "sbgp-ipAddrBlock", NID_sbgp_ipAddrBlock, 8, &so[2123]},
++    {"sbgp-autonomousSysNum", "sbgp-autonomousSysNum", NID_sbgp_autonomousSysNum, 8, &so[2131]},
++    {"sbgp-routerIdentifier", "sbgp-routerIdentifier", NID_sbgp_routerIdentifier, 8, &so[2139]},
++    {"textNotice", "textNotice", NID_textNotice, 8, &so[2147]},
++    {"ipsecEndSystem", "IPSec End System", NID_ipsecEndSystem, 8, &so[2155]},
++    {"ipsecTunnel", "IPSec Tunnel", NID_ipsecTunnel, 8, &so[2163]},
++    {"ipsecUser", "IPSec User", NID_ipsecUser, 8, &so[2171]},
++    {"DVCS", "dvcs", NID_dvcs, 8, &so[2179]},
++    {"id-it-caProtEncCert", "id-it-caProtEncCert", NID_id_it_caProtEncCert, 8, &so[2187]},
++    {"id-it-signKeyPairTypes", "id-it-signKeyPairTypes", NID_id_it_signKeyPairTypes, 8, &so[2195]},
++    {"id-it-encKeyPairTypes", "id-it-encKeyPairTypes", NID_id_it_encKeyPairTypes, 8, &so[2203]},
++    {"id-it-preferredSymmAlg", "id-it-preferredSymmAlg", NID_id_it_preferredSymmAlg, 8, &so[2211]},
++    {"id-it-caKeyUpdateInfo", "id-it-caKeyUpdateInfo", NID_id_it_caKeyUpdateInfo, 8, &so[2219]},
++    {"id-it-currentCRL", "id-it-currentCRL", NID_id_it_currentCRL, 8, &so[2227]},
++    {"id-it-unsupportedOIDs", "id-it-unsupportedOIDs", NID_id_it_unsupportedOIDs, 8, &so[2235]},
++    {"id-it-subscriptionRequest", "id-it-subscriptionRequest", NID_id_it_subscriptionRequest, 8, &so[2243]},
++    {"id-it-subscriptionResponse", "id-it-subscriptionResponse", NID_id_it_subscriptionResponse, 8, &so[2251]},
++    {"id-it-keyPairParamReq", "id-it-keyPairParamReq", NID_id_it_keyPairParamReq, 8, &so[2259]},
++    {"id-it-keyPairParamRep", "id-it-keyPairParamRep", NID_id_it_keyPairParamRep, 8, &so[2267]},
++    {"id-it-revPassphrase", "id-it-revPassphrase", NID_id_it_revPassphrase, 8, &so[2275]},
++    {"id-it-implicitConfirm", "id-it-implicitConfirm", NID_id_it_implicitConfirm, 8, &so[2283]},
++    {"id-it-confirmWaitTime", "id-it-confirmWaitTime", NID_id_it_confirmWaitTime, 8, &so[2291]},
++    {"id-it-origPKIMessage", "id-it-origPKIMessage", NID_id_it_origPKIMessage, 8, &so[2299]},
++    {"id-regCtrl", "id-regCtrl", NID_id_regCtrl, 8, &so[2307]},
++    {"id-regInfo", "id-regInfo", NID_id_regInfo, 8, &so[2315]},
++    {"id-regCtrl-regToken", "id-regCtrl-regToken", NID_id_regCtrl_regToken, 9, &so[2323]},
++    {"id-regCtrl-authenticator", "id-regCtrl-authenticator", NID_id_regCtrl_authenticator, 9, &so[2332]},
++    {"id-regCtrl-pkiPublicationInfo", "id-regCtrl-pkiPublicationInfo", NID_id_regCtrl_pkiPublicationInfo, 9, &so[2341]},
++    {"id-regCtrl-pkiArchiveOptions", "id-regCtrl-pkiArchiveOptions", NID_id_regCtrl_pkiArchiveOptions, 9, &so[2350]},
++    {"id-regCtrl-oldCertID", "id-regCtrl-oldCertID", NID_id_regCtrl_oldCertID, 9, &so[2359]},
++    {"id-regCtrl-protocolEncrKey", "id-regCtrl-protocolEncrKey", NID_id_regCtrl_protocolEncrKey, 9, &so[2368]},
++    {"id-regInfo-utf8Pairs", "id-regInfo-utf8Pairs", NID_id_regInfo_utf8Pairs, 9, &so[2377]},
++    {"id-regInfo-certReq", "id-regInfo-certReq", NID_id_regInfo_certReq, 9, &so[2386]},
++    {"id-alg-des40", "id-alg-des40", NID_id_alg_des40, 8, &so[2395]},
++    {"id-alg-noSignature", "id-alg-noSignature", NID_id_alg_noSignature, 8, &so[2403]},
++    {"id-alg-dh-sig-hmac-sha1", "id-alg-dh-sig-hmac-sha1", NID_id_alg_dh_sig_hmac_sha1, 8, &so[2411]},
++    {"id-alg-dh-pop", "id-alg-dh-pop", NID_id_alg_dh_pop, 8, &so[2419]},
++    {"id-cmc-statusInfo", "id-cmc-statusInfo", NID_id_cmc_statusInfo, 8, &so[2427]},
++    {"id-cmc-identification", "id-cmc-identification", NID_id_cmc_identification, 8, &so[2435]},
++    {"id-cmc-identityProof", "id-cmc-identityProof", NID_id_cmc_identityProof, 8, &so[2443]},
++    {"id-cmc-dataReturn", "id-cmc-dataReturn", NID_id_cmc_dataReturn, 8, &so[2451]},
++    {"id-cmc-transactionId", "id-cmc-transactionId", NID_id_cmc_transactionId, 8, &so[2459]},
++    {"id-cmc-senderNonce", "id-cmc-senderNonce", NID_id_cmc_senderNonce, 8, &so[2467]},
++    {"id-cmc-recipientNonce", "id-cmc-recipientNonce", NID_id_cmc_recipientNonce, 8, &so[2475]},
++    {"id-cmc-addExtensions", "id-cmc-addExtensions", NID_id_cmc_addExtensions, 8, &so[2483]},
++    {"id-cmc-encryptedPOP", "id-cmc-encryptedPOP", NID_id_cmc_encryptedPOP, 8, &so[2491]},
++    {"id-cmc-decryptedPOP", "id-cmc-decryptedPOP", NID_id_cmc_decryptedPOP, 8, &so[2499]},
++    {"id-cmc-lraPOPWitness", "id-cmc-lraPOPWitness", NID_id_cmc_lraPOPWitness, 8, &so[2507]},
++    {"id-cmc-getCert", "id-cmc-getCert", NID_id_cmc_getCert, 8, &so[2515]},
++    {"id-cmc-getCRL", "id-cmc-getCRL", NID_id_cmc_getCRL, 8, &so[2523]},
++    {"id-cmc-revokeRequest", "id-cmc-revokeRequest", NID_id_cmc_revokeRequest, 8, &so[2531]},
++    {"id-cmc-regInfo", "id-cmc-regInfo", NID_id_cmc_regInfo, 8, &so[2539]},
++    {"id-cmc-responseInfo", "id-cmc-responseInfo", NID_id_cmc_responseInfo, 8, &so[2547]},
++    {"id-cmc-queryPending", "id-cmc-queryPending", NID_id_cmc_queryPending, 8, &so[2555]},
++    {"id-cmc-popLinkRandom", "id-cmc-popLinkRandom", NID_id_cmc_popLinkRandom, 8, &so[2563]},
++    {"id-cmc-popLinkWitness", "id-cmc-popLinkWitness", NID_id_cmc_popLinkWitness, 8, &so[2571]},
++    {"id-cmc-confirmCertAcceptance", "id-cmc-confirmCertAcceptance", NID_id_cmc_confirmCertAcceptance, 8, &so[2579]},
++    {"id-on-personalData", "id-on-personalData", NID_id_on_personalData, 8, &so[2587]},
++    {"id-pda-dateOfBirth", "id-pda-dateOfBirth", NID_id_pda_dateOfBirth, 8, &so[2595]},
++    {"id-pda-placeOfBirth", "id-pda-placeOfBirth", NID_id_pda_placeOfBirth, 8, &so[2603]},
++    { NULL, NULL, NID_undef },
++    {"id-pda-gender", "id-pda-gender", NID_id_pda_gender, 8, &so[2611]},
++    {"id-pda-countryOfCitizenship", "id-pda-countryOfCitizenship", NID_id_pda_countryOfCitizenship, 8, &so[2619]},
++    {"id-pda-countryOfResidence", "id-pda-countryOfResidence", NID_id_pda_countryOfResidence, 8, &so[2627]},
++    {"id-aca-authenticationInfo", "id-aca-authenticationInfo", NID_id_aca_authenticationInfo, 8, &so[2635]},
++    {"id-aca-accessIdentity", "id-aca-accessIdentity", NID_id_aca_accessIdentity, 8, &so[2643]},
++    {"id-aca-chargingIdentity", "id-aca-chargingIdentity", NID_id_aca_chargingIdentity, 8, &so[2651]},
++    {"id-aca-group", "id-aca-group", NID_id_aca_group, 8, &so[2659]},
++    {"id-aca-role", "id-aca-role", NID_id_aca_role, 8, &so[2667]},
++    {"id-qcs-pkixQCSyntax-v1", "id-qcs-pkixQCSyntax-v1", NID_id_qcs_pkixQCSyntax_v1, 8, &so[2675]},
++    {"id-cct-crs", "id-cct-crs", NID_id_cct_crs, 8, &so[2683]},
++    {"id-cct-PKIData", "id-cct-PKIData", NID_id_cct_PKIData, 8, &so[2691]},
++    {"id-cct-PKIResponse", "id-cct-PKIResponse", NID_id_cct_PKIResponse, 8, &so[2699]},
++    {"ad_timestamping", "AD Time Stamping", NID_ad_timeStamping, 8, &so[2707]},
++    {"AD_DVCS", "ad dvcs", NID_ad_dvcs, 8, &so[2715]},
++    {"basicOCSPResponse", "Basic OCSP Response", NID_id_pkix_OCSP_basic, 9, &so[2723]},
++    {"Nonce", "OCSP Nonce", NID_id_pkix_OCSP_Nonce, 9, &so[2732]},
++    {"CrlID", "OCSP CRL ID", NID_id_pkix_OCSP_CrlID, 9, &so[2741]},
++    {"acceptableResponses", "Acceptable OCSP Responses", NID_id_pkix_OCSP_acceptableResponses, 9, &so[2750]},
++    {"noCheck", "OCSP No Check", NID_id_pkix_OCSP_noCheck, 9, &so[2759]},
++    {"archiveCutoff", "OCSP Archive Cutoff", NID_id_pkix_OCSP_archiveCutoff, 9, &so[2768]},
++    {"serviceLocator", "OCSP Service Locator", NID_id_pkix_OCSP_serviceLocator, 9, &so[2777]},
++    {"extendedStatus", "Extended OCSP Status", NID_id_pkix_OCSP_extendedStatus, 9, &so[2786]},
++    {"valid", "valid", NID_id_pkix_OCSP_valid, 9, &so[2795]},
++    {"path", "path", NID_id_pkix_OCSP_path, 9, &so[2804]},
++    {"trustRoot", "Trust Root", NID_id_pkix_OCSP_trustRoot, 9, &so[2813]},
++    {"algorithm", "algorithm", NID_algorithm, 4, &so[2822]},
++    {"rsaSignature", "rsaSignature", NID_rsaSignature, 5, &so[2826]},
++    {"X500algorithms", "directory services - algorithms", NID_X500algorithms, 2, &so[2831]},
++    {"ORG", "org", NID_org, 1, &so[2833]},
++    {"DOD", "dod", NID_dod, 2, &so[2834]},
++    {"IANA", "iana", NID_iana, 3, &so[2836]},
++    {"directory", "Directory", NID_Directory, 4, &so[2839]},
++    {"mgmt", "Management", NID_Management, 4, &so[2843]},
++    {"experimental", "Experimental", NID_Experimental, 4, &so[2847]},
++    {"private", "Private", NID_Private, 4, &so[2851]},
++    {"security", "Security", NID_Security, 4, &so[2855]},
++    {"snmpv2", "SNMPv2", NID_SNMPv2, 4, &so[2859]},
++    {"Mail", "Mail", NID_Mail, 4, &so[2863]},
++    {"enterprises", "Enterprises", NID_Enterprises, 5, &so[2867]},
++    {"dcobject", "dcObject", NID_dcObject, 9, &so[2872]},
++    {"DC", "domainComponent", NID_domainComponent, 10, &so[2881]},
++    {"domain", "Domain", NID_Domain, 10, &so[2891]},
++    {"NULL", "NULL", NID_joint_iso_ccitt},
++    {"selected-attribute-types", "Selected Attribute Types", NID_selected_attribute_types, 3, &so[2901]},
++    {"clearance", "clearance", NID_clearance, 4, &so[2904]},
++    {"RSA-MD4", "md4WithRSAEncryption", NID_md4WithRSAEncryption, 9, &so[2908]},
++    {"ac-proxying", "ac-proxying", NID_ac_proxying, 8, &so[2917]},
++    {"subjectInfoAccess", "Subject Information Access", NID_sinfo_access, 8, &so[2925]},
++    {"id-aca-encAttrs", "id-aca-encAttrs", NID_id_aca_encAttrs, 8, &so[2933]},
++    {"role", "role", NID_role, 3, &so[2941]},
++    {"policyConstraints", "X509v3 Policy Constraints", NID_policy_constraints, 3, &so[2944]},
++    {"targetInformation", "X509v3 AC Targeting", NID_target_information, 3, &so[2947]},
++    {"noRevAvail", "X509v3 No Revocation Available", NID_no_rev_avail, 3, &so[2950]},
++    {"NULL", "NULL", NID_ccitt},
++    {"ansi-X9-62", "ANSI X9.62", NID_ansi_X9_62, 5, &so[2953]},
++    {"prime-field", "prime-field", NID_X9_62_prime_field, 7, &so[2958]},
++    {"characteristic-two-field", "characteristic-two-field", NID_X9_62_characteristic_two_field, 7, &so[2965]},
++    {"id-ecPublicKey", "id-ecPublicKey", NID_X9_62_id_ecPublicKey, 7, &so[2972]},
++    {"prime192v1", "prime192v1", NID_X9_62_prime192v1, 8, &so[2979]},
++    {"prime192v2", "prime192v2", NID_X9_62_prime192v2, 8, &so[2987]},
++    {"prime192v3", "prime192v3", NID_X9_62_prime192v3, 8, &so[2995]},
++    {"prime239v1", "prime239v1", NID_X9_62_prime239v1, 8, &so[3003]},
++    {"prime239v2", "prime239v2", NID_X9_62_prime239v2, 8, &so[3011]},
++    {"prime239v3", "prime239v3", NID_X9_62_prime239v3, 8, &so[3019]},
++    {"prime256v1", "prime256v1", NID_X9_62_prime256v1, 8, &so[3027]},
++    {"ecdsa-with-SHA1", "ecdsa-with-SHA1", NID_ecdsa_with_SHA1, 7, &so[3035]},
++    {"CSPName", "Microsoft CSP Name", NID_ms_csp_name, 9, &so[3042]},
++    {"AES-128-ECB", "aes-128-ecb", NID_aes_128_ecb, 9, &so[3051]},
++    {"AES-128-CBC", "aes-128-cbc", NID_aes_128_cbc, 9, &so[3060]},
++    {"AES-128-OFB", "aes-128-ofb", NID_aes_128_ofb128, 9, &so[3069]},
++    {"AES-128-CFB", "aes-128-cfb", NID_aes_128_cfb128, 9, &so[3078]},
++    {"AES-192-ECB", "aes-192-ecb", NID_aes_192_ecb, 9, &so[3087]},
++    {"AES-192-CBC", "aes-192-cbc", NID_aes_192_cbc, 9, &so[3096]},
++    {"AES-192-OFB", "aes-192-ofb", NID_aes_192_ofb128, 9, &so[3105]},
++    {"AES-192-CFB", "aes-192-cfb", NID_aes_192_cfb128, 9, &so[3114]},
++    {"AES-256-ECB", "aes-256-ecb", NID_aes_256_ecb, 9, &so[3123]},
++    {"AES-256-CBC", "aes-256-cbc", NID_aes_256_cbc, 9, &so[3132]},
++    {"AES-256-OFB", "aes-256-ofb", NID_aes_256_ofb128, 9, &so[3141]},
++    {"AES-256-CFB", "aes-256-cfb", NID_aes_256_cfb128, 9, &so[3150]},
++    {"holdInstructionCode", "Hold Instruction Code", NID_hold_instruction_code, 3, &so[3159]},
++    {"holdInstructionNone", "Hold Instruction None", NID_hold_instruction_none, 7, &so[3162]},
++    {"holdInstructionCallIssuer", "Hold Instruction Call Issuer", NID_hold_instruction_call_issuer, 7, &so[3169]},
++    {"holdInstructionReject", "Hold Instruction Reject", NID_hold_instruction_reject, 7, &so[3176]},
++    {"data", "data", NID_data, 1, &so[3183]},
++    {"pss", "pss", NID_pss, 3, &so[3184]},
++    {"ucl", "ucl", NID_ucl, 7, &so[3187]},
++    {"pilot", "pilot", NID_pilot, 8, &so[3194]},
++    {"pilotAttributeType", "pilotAttributeType", NID_pilotAttributeType, 9, &so[3202]},
++    {"pilotAttributeSyntax", "pilotAttributeSyntax", NID_pilotAttributeSyntax, 9, &so[3211]},
++    {"pilotObjectClass", "pilotObjectClass", NID_pilotObjectClass, 9, &so[3220]},
++    {"pilotGroups", "pilotGroups", NID_pilotGroups, 9, &so[3229]},
++    {"iA5StringSyntax", "iA5StringSyntax", NID_iA5StringSyntax, 10, &so[3238]},
++    {"caseIgnoreIA5StringSyntax", "caseIgnoreIA5StringSyntax", NID_caseIgnoreIA5StringSyntax, 10, &so[3248]},
++    {"pilotObject", "pilotObject", NID_pilotObject, 10, &so[3258]},
++    {"pilotPerson", "pilotPerson", NID_pilotPerson, 10, &so[3268]},
++    {"account", "account", NID_account, 10, &so[3278]},
++    {"document", "document", NID_document, 10, &so[3288]},
++    {"room", "room", NID_room, 10, &so[3298]},
++    {"documentSeries", "documentSeries", NID_documentSeries, 10, &so[3308]},
++    {"rFC822localPart", "rFC822localPart", NID_rFC822localPart, 10, &so[3318]},
++    {"dNSDomain", "dNSDomain", NID_dNSDomain, 10, &so[3328]},
++    {"domainRelatedObject", "domainRelatedObject", NID_domainRelatedObject, 10, &so[3338]},
++    {"friendlyCountry", "friendlyCountry", NID_friendlyCountry, 10, &so[3348]},
++    {"simpleSecurityObject", "simpleSecurityObject", NID_simpleSecurityObject, 10, &so[3358]},
++    {"pilotOrganization", "pilotOrganization", NID_pilotOrganization, 10, &so[3368]},
++    {"pilotDSA", "pilotDSA", NID_pilotDSA, 10, &so[3378]},
++    {"qualityLabelledData", "qualityLabelledData", NID_qualityLabelledData, 10, &so[3388]},
++    {"UID", "userId", NID_userId, 10, &so[3398]},
++    {"textEncodedORAddress", "textEncodedORAddress", NID_textEncodedORAddress, 10, &so[3408]},
++    {"mail", "rfc822Mailbox", NID_rfc822Mailbox, 10, &so[3418]},
++    {"info", "info", NID_info, 10, &so[3428]},
++    {"favouriteDrink", "favouriteDrink", NID_favouriteDrink, 10, &so[3438]},
++    {"roomNumber", "roomNumber", NID_roomNumber, 10, &so[3448]},
++    {"photo", "photo", NID_photo, 10, &so[3458]},
++    {"userClass", "userClass", NID_userClass, 10, &so[3468]},
++    {"host", "host", NID_host, 10, &so[3478]},
++    {"manager", "manager", NID_manager, 10, &so[3488]},
++    {"documentIdentifier", "documentIdentifier", NID_documentIdentifier, 10, &so[3498]},
++    {"documentTitle", "documentTitle", NID_documentTitle, 10, &so[3508]},
++    {"documentVersion", "documentVersion", NID_documentVersion, 10, &so[3518]},
++    {"documentAuthor", "documentAuthor", NID_documentAuthor, 10, &so[3528]},
++    {"documentLocation", "documentLocation", NID_documentLocation, 10, &so[3538]},
++    {"homeTelephoneNumber", "homeTelephoneNumber", NID_homeTelephoneNumber, 10, &so[3548]},
++    {"secretary", "secretary", NID_secretary, 10, &so[3558]},
++    {"otherMailbox", "otherMailbox", NID_otherMailbox, 10, &so[3568]},
++    {"lastModifiedTime", "lastModifiedTime", NID_lastModifiedTime, 10, &so[3578]},
++    {"lastModifiedBy", "lastModifiedBy", NID_lastModifiedBy, 10, &so[3588]},
++    {"aRecord", "aRecord", NID_aRecord, 10, &so[3598]},
++    {"pilotAttributeType27", "pilotAttributeType27", NID_pilotAttributeType27, 10, &so[3608]},
++    {"mXRecord", "mXRecord", NID_mXRecord, 10, &so[3618]},
++    {"nSRecord", "nSRecord", NID_nSRecord, 10, &so[3628]},
++    {"sOARecord", "sOARecord", NID_sOARecord, 10, &so[3638]},
++    {"cNAMERecord", "cNAMERecord", NID_cNAMERecord, 10, &so[3648]},
++    {"associatedDomain", "associatedDomain", NID_associatedDomain, 10, &so[3658]},
++    {"associatedName", "associatedName", NID_associatedName, 10, &so[3668]},
++    {"homePostalAddress", "homePostalAddress", NID_homePostalAddress, 10, &so[3678]},
++    {"personalTitle", "personalTitle", NID_personalTitle, 10, &so[3688]},
++    {"mobileTelephoneNumber", "mobileTelephoneNumber", NID_mobileTelephoneNumber, 10, &so[3698]},
++    {"pagerTelephoneNumber", "pagerTelephoneNumber", NID_pagerTelephoneNumber, 10, &so[3708]},
++    {"friendlyCountryName", "friendlyCountryName", NID_friendlyCountryName, 10, &so[3718]},
++    {"organizationalStatus", "organizationalStatus", NID_organizationalStatus, 10, &so[3728]},
++    {"janetMailbox", "janetMailbox", NID_janetMailbox, 10, &so[3738]},
++    {"mailPreferenceOption", "mailPreferenceOption", NID_mailPreferenceOption, 10, &so[3748]},
++    {"buildingName", "buildingName", NID_buildingName, 10, &so[3758]},
++    {"dSAQuality", "dSAQuality", NID_dSAQuality, 10, &so[3768]},
++    {"singleLevelQuality", "singleLevelQuality", NID_singleLevelQuality, 10, &so[3778]},
++    {"subtreeMinimumQuality", "subtreeMinimumQuality", NID_subtreeMinimumQuality, 10, &so[3788]},
++    {"subtreeMaximumQuality", "subtreeMaximumQuality", NID_subtreeMaximumQuality, 10, &so[3798]},
++    {"personalSignature", "personalSignature", NID_personalSignature, 10, &so[3808]},
++    {"dITRedirect", "dITRedirect", NID_dITRedirect, 10, &so[3818]},
++    {"audio", "audio", NID_audio, 10, &so[3828]},
++    {"documentPublisher", "documentPublisher", NID_documentPublisher, 10, &so[3838]},
++    {"x500UniqueIdentifier", "x500UniqueIdentifier", NID_x500UniqueIdentifier, 3, &so[3848]},
++    {"mime-mhs", "MIME MHS", NID_mime_mhs, 5, &so[3851]},
++    {"mime-mhs-headings", "mime-mhs-headings", NID_mime_mhs_headings, 6, &so[3856]},
++    {"mime-mhs-bodies", "mime-mhs-bodies", NID_mime_mhs_bodies, 6, &so[3862]},
++    {"id-hex-partial-message", "id-hex-partial-message", NID_id_hex_partial_message, 7, &so[3868]},
++    {"id-hex-multipart-message", "id-hex-multipart-message", NID_id_hex_multipart_message, 7, &so[3875]},
++    {"generationQualifier", "generationQualifier", NID_generationQualifier, 3, &so[3882]},
++    {"pseudonym", "pseudonym", NID_pseudonym, 3, &so[3885]},
++    { NULL, NULL, NID_undef },
++    {"id-set", "Secure Electronic Transactions", NID_id_set, 2, &so[3888]},
++    {"set-ctype", "content types", NID_set_ctype, 3, &so[3890]},
++    {"set-msgExt", "message extensions", NID_set_msgExt, 3, &so[3893]},
++    {"set-attr", "set-attr", NID_set_attr, 3, &so[3896]},
++    {"set-policy", "set-policy", NID_set_policy, 3, &so[3899]},
++    {"set-certExt", "certificate extensions", NID_set_certExt, 3, &so[3902]},
++    {"set-brand", "set-brand", NID_set_brand, 3, &so[3905]},
++    {"setct-PANData", "setct-PANData", NID_setct_PANData, 4, &so[3908]},
++    {"setct-PANToken", "setct-PANToken", NID_setct_PANToken, 4, &so[3912]},
++    {"setct-PANOnly", "setct-PANOnly", NID_setct_PANOnly, 4, &so[3916]},
++    {"setct-OIData", "setct-OIData", NID_setct_OIData, 4, &so[3920]},
++    {"setct-PI", "setct-PI", NID_setct_PI, 4, &so[3924]},
++    {"setct-PIData", "setct-PIData", NID_setct_PIData, 4, &so[3928]},
++    {"setct-PIDataUnsigned", "setct-PIDataUnsigned", NID_setct_PIDataUnsigned, 4, &so[3932]},
++    {"setct-HODInput", "setct-HODInput", NID_setct_HODInput, 4, &so[3936]},
++    {"setct-AuthResBaggage", "setct-AuthResBaggage", NID_setct_AuthResBaggage, 4, &so[3940]},
++    {"setct-AuthRevReqBaggage", "setct-AuthRevReqBaggage", NID_setct_AuthRevReqBaggage, 4, &so[3944]},
++    {"setct-AuthRevResBaggage", "setct-AuthRevResBaggage", NID_setct_AuthRevResBaggage, 4, &so[3948]},
++    {"setct-CapTokenSeq", "setct-CapTokenSeq", NID_setct_CapTokenSeq, 4, &so[3952]},
++    {"setct-PInitResData", "setct-PInitResData", NID_setct_PInitResData, 4, &so[3956]},
++    {"setct-PI-TBS", "setct-PI-TBS", NID_setct_PI_TBS, 4, &so[3960]},
++    {"setct-PResData", "setct-PResData", NID_setct_PResData, 4, &so[3964]},
++    {"setct-AuthReqTBS", "setct-AuthReqTBS", NID_setct_AuthReqTBS, 4, &so[3968]},
++    {"setct-AuthResTBS", "setct-AuthResTBS", NID_setct_AuthResTBS, 4, &so[3972]},
++    {"setct-AuthResTBSX", "setct-AuthResTBSX", NID_setct_AuthResTBSX, 4, &so[3976]},
++    {"setct-AuthTokenTBS", "setct-AuthTokenTBS", NID_setct_AuthTokenTBS, 4, &so[3980]},
++    {"setct-CapTokenData", "setct-CapTokenData", NID_setct_CapTokenData, 4, &so[3984]},
++    {"setct-CapTokenTBS", "setct-CapTokenTBS", NID_setct_CapTokenTBS, 4, &so[3988]},
++    {"setct-AcqCardCodeMsg", "setct-AcqCardCodeMsg", NID_setct_AcqCardCodeMsg, 4, &so[3992]},
++    {"setct-AuthRevReqTBS", "setct-AuthRevReqTBS", NID_setct_AuthRevReqTBS, 4, &so[3996]},
++    {"setct-AuthRevResData", "setct-AuthRevResData", NID_setct_AuthRevResData, 4, &so[4000]},
++    {"setct-AuthRevResTBS", "setct-AuthRevResTBS", NID_setct_AuthRevResTBS, 4, &so[4004]},
++    {"setct-CapReqTBS", "setct-CapReqTBS", NID_setct_CapReqTBS, 4, &so[4008]},
++    {"setct-CapReqTBSX", "setct-CapReqTBSX", NID_setct_CapReqTBSX, 4, &so[4012]},
++    {"setct-CapResData", "setct-CapResData", NID_setct_CapResData, 4, &so[4016]},
++    {"setct-CapRevReqTBS", "setct-CapRevReqTBS", NID_setct_CapRevReqTBS, 4, &so[4020]},
++    {"setct-CapRevReqTBSX", "setct-CapRevReqTBSX", NID_setct_CapRevReqTBSX, 4, &so[4024]},
++    {"setct-CapRevResData", "setct-CapRevResData", NID_setct_CapRevResData, 4, &so[4028]},
++    {"setct-CredReqTBS", "setct-CredReqTBS", NID_setct_CredReqTBS, 4, &so[4032]},
++    {"setct-CredReqTBSX", "setct-CredReqTBSX", NID_setct_CredReqTBSX, 4, &so[4036]},
++    {"setct-CredResData", "setct-CredResData", NID_setct_CredResData, 4, &so[4040]},
++    {"setct-CredRevReqTBS", "setct-CredRevReqTBS", NID_setct_CredRevReqTBS, 4, &so[4044]},
++    {"setct-CredRevReqTBSX", "setct-CredRevReqTBSX", NID_setct_CredRevReqTBSX, 4, &so[4048]},
++    {"setct-CredRevResData", "setct-CredRevResData", NID_setct_CredRevResData, 4, &so[4052]},
++    {"setct-PCertReqData", "setct-PCertReqData", NID_setct_PCertReqData, 4, &so[4056]},
++    {"setct-PCertResTBS", "setct-PCertResTBS", NID_setct_PCertResTBS, 4, &so[4060]},
++    {"setct-BatchAdminReqData", "setct-BatchAdminReqData", NID_setct_BatchAdminReqData, 4, &so[4064]},
++    {"setct-BatchAdminResData", "setct-BatchAdminResData", NID_setct_BatchAdminResData, 4, &so[4068]},
++    {"setct-CardCInitResTBS", "setct-CardCInitResTBS", NID_setct_CardCInitResTBS, 4, &so[4072]},
++    {"setct-MeAqCInitResTBS", "setct-MeAqCInitResTBS", NID_setct_MeAqCInitResTBS, 4, &so[4076]},
++    {"setct-RegFormResTBS", "setct-RegFormResTBS", NID_setct_RegFormResTBS, 4, &so[4080]},
++    {"setct-CertReqData", "setct-CertReqData", NID_setct_CertReqData, 4, &so[4084]},
++    {"setct-CertReqTBS", "setct-CertReqTBS", NID_setct_CertReqTBS, 4, &so[4088]},
++    {"setct-CertResData", "setct-CertResData", NID_setct_CertResData, 4, &so[4092]},
++    {"setct-CertInqReqTBS", "setct-CertInqReqTBS", NID_setct_CertInqReqTBS, 4, &so[4096]},
++    {"setct-ErrorTBS", "setct-ErrorTBS", NID_setct_ErrorTBS, 4, &so[4100]},
++    {"setct-PIDualSignedTBE", "setct-PIDualSignedTBE", NID_setct_PIDualSignedTBE, 4, &so[4104]},
++    {"setct-PIUnsignedTBE", "setct-PIUnsignedTBE", NID_setct_PIUnsignedTBE, 4, &so[4108]},
++    {"setct-AuthReqTBE", "setct-AuthReqTBE", NID_setct_AuthReqTBE, 4, &so[4112]},
++    {"setct-AuthResTBE", "setct-AuthResTBE", NID_setct_AuthResTBE, 4, &so[4116]},
++    {"setct-AuthResTBEX", "setct-AuthResTBEX", NID_setct_AuthResTBEX, 4, &so[4120]},
++    {"setct-AuthTokenTBE", "setct-AuthTokenTBE", NID_setct_AuthTokenTBE, 4, &so[4124]},
++    {"setct-CapTokenTBE", "setct-CapTokenTBE", NID_setct_CapTokenTBE, 4, &so[4128]},
++    {"setct-CapTokenTBEX", "setct-CapTokenTBEX", NID_setct_CapTokenTBEX, 4, &so[4132]},
++    {"setct-AcqCardCodeMsgTBE", "setct-AcqCardCodeMsgTBE", NID_setct_AcqCardCodeMsgTBE, 4, &so[4136]},
++    {"setct-AuthRevReqTBE", "setct-AuthRevReqTBE", NID_setct_AuthRevReqTBE, 4, &so[4140]},
++    {"setct-AuthRevResTBE", "setct-AuthRevResTBE", NID_setct_AuthRevResTBE, 4, &so[4144]},
++    {"setct-AuthRevResTBEB", "setct-AuthRevResTBEB", NID_setct_AuthRevResTBEB, 4, &so[4148]},
++    {"setct-CapReqTBE", "setct-CapReqTBE", NID_setct_CapReqTBE, 4, &so[4152]},
++    {"setct-CapReqTBEX", "setct-CapReqTBEX", NID_setct_CapReqTBEX, 4, &so[4156]},
++    {"setct-CapResTBE", "setct-CapResTBE", NID_setct_CapResTBE, 4, &so[4160]},
++    {"setct-CapRevReqTBE", "setct-CapRevReqTBE", NID_setct_CapRevReqTBE, 4, &so[4164]},
++    {"setct-CapRevReqTBEX", "setct-CapRevReqTBEX", NID_setct_CapRevReqTBEX, 4, &so[4168]},
++    {"setct-CapRevResTBE", "setct-CapRevResTBE", NID_setct_CapRevResTBE, 4, &so[4172]},
++    {"setct-CredReqTBE", "setct-CredReqTBE", NID_setct_CredReqTBE, 4, &so[4176]},
++    {"setct-CredReqTBEX", "setct-CredReqTBEX", NID_setct_CredReqTBEX, 4, &so[4180]},
++    {"setct-CredResTBE", "setct-CredResTBE", NID_setct_CredResTBE, 4, &so[4184]},
++    {"setct-CredRevReqTBE", "setct-CredRevReqTBE", NID_setct_CredRevReqTBE, 4, &so[4188]},
++    {"setct-CredRevReqTBEX", "setct-CredRevReqTBEX", NID_setct_CredRevReqTBEX, 4, &so[4192]},
++    {"setct-CredRevResTBE", "setct-CredRevResTBE", NID_setct_CredRevResTBE, 4, &so[4196]},
++    {"setct-BatchAdminReqTBE", "setct-BatchAdminReqTBE", NID_setct_BatchAdminReqTBE, 4, &so[4200]},
++    {"setct-BatchAdminResTBE", "setct-BatchAdminResTBE", NID_setct_BatchAdminResTBE, 4, &so[4204]},
++    {"setct-RegFormReqTBE", "setct-RegFormReqTBE", NID_setct_RegFormReqTBE, 4, &so[4208]},
++    {"setct-CertReqTBE", "setct-CertReqTBE", NID_setct_CertReqTBE, 4, &so[4212]},
++    {"setct-CertReqTBEX", "setct-CertReqTBEX", NID_setct_CertReqTBEX, 4, &so[4216]},
++    {"setct-CertResTBE", "setct-CertResTBE", NID_setct_CertResTBE, 4, &so[4220]},
++    {"setct-CRLNotificationTBS", "setct-CRLNotificationTBS", NID_setct_CRLNotificationTBS, 4, &so[4224]},
++    {"setct-CRLNotificationResTBS", "setct-CRLNotificationResTBS", NID_setct_CRLNotificationResTBS, 4, &so[4228]},
++    {"setct-BCIDistributionTBS", "setct-BCIDistributionTBS", NID_setct_BCIDistributionTBS, 4, &so[4232]},
++    {"setext-genCrypt", "generic cryptogram", NID_setext_genCrypt, 4, &so[4236]},
++    {"setext-miAuth", "merchant initiated auth", NID_setext_miAuth, 4, &so[4240]},
++    {"setext-pinSecure", "setext-pinSecure", NID_setext_pinSecure, 4, &so[4244]},
++    {"setext-pinAny", "setext-pinAny", NID_setext_pinAny, 4, &so[4248]},
++    {"setext-track2", "setext-track2", NID_setext_track2, 4, &so[4252]},
++    {"setext-cv", "additional verification", NID_setext_cv, 4, &so[4256]},
++    {"set-policy-root", "set-policy-root", NID_set_policy_root, 4, &so[4260]},
++    {"setCext-hashedRoot", "setCext-hashedRoot", NID_setCext_hashedRoot, 4, &so[4264]},
++    {"setCext-certType", "setCext-certType", NID_setCext_certType, 4, &so[4268]},
++    {"setCext-merchData", "setCext-merchData", NID_setCext_merchData, 4, &so[4272]},
++    {"setCext-cCertRequired", "setCext-cCertRequired", NID_setCext_cCertRequired, 4, &so[4276]},
++    {"setCext-tunneling", "setCext-tunneling", NID_setCext_tunneling, 4, &so[4280]},
++    {"setCext-setExt", "setCext-setExt", NID_setCext_setExt, 4, &so[4284]},
++    {"setCext-setQualf", "setCext-setQualf", NID_setCext_setQualf, 4, &so[4288]},
++    {"setCext-PGWYcapabilities", "setCext-PGWYcapabilities", NID_setCext_PGWYcapabilities, 4, &so[4292]},
++    {"setCext-TokenIdentifier", "setCext-TokenIdentifier", NID_setCext_TokenIdentifier, 4, &so[4296]},
++    {"setCext-Track2Data", "setCext-Track2Data", NID_setCext_Track2Data, 4, &so[4300]},
++    {"setCext-TokenType", "setCext-TokenType", NID_setCext_TokenType, 4, &so[4304]},
++    {"setCext-IssuerCapabilities", "setCext-IssuerCapabilities", NID_setCext_IssuerCapabilities, 4, &so[4308]},
++    {"setAttr-Cert", "setAttr-Cert", NID_setAttr_Cert, 4, &so[4312]},
++    {"setAttr-PGWYcap", "payment gateway capabilities", NID_setAttr_PGWYcap, 4, &so[4316]},
++    {"setAttr-TokenType", "setAttr-TokenType", NID_setAttr_TokenType, 4, &so[4320]},
++    {"setAttr-IssCap", "issuer capabilities", NID_setAttr_IssCap, 4, &so[4324]},
++    {"set-rootKeyThumb", "set-rootKeyThumb", NID_set_rootKeyThumb, 5, &so[4328]},
++    {"set-addPolicy", "set-addPolicy", NID_set_addPolicy, 5, &so[4333]},
++    {"setAttr-Token-EMV", "setAttr-Token-EMV", NID_setAttr_Token_EMV, 5, &so[4338]},
++    {"setAttr-Token-B0Prime", "setAttr-Token-B0Prime", NID_setAttr_Token_B0Prime, 5, &so[4343]},
++    {"setAttr-IssCap-CVM", "setAttr-IssCap-CVM", NID_setAttr_IssCap_CVM, 5, &so[4348]},
++    {"setAttr-IssCap-T2", "setAttr-IssCap-T2", NID_setAttr_IssCap_T2, 5, &so[4353]},
++    {"setAttr-IssCap-Sig", "setAttr-IssCap-Sig", NID_setAttr_IssCap_Sig, 5, &so[4358]},
++    {"setAttr-GenCryptgrm", "generate cryptogram", NID_setAttr_GenCryptgrm, 6, &so[4363]},
++    {"setAttr-T2Enc", "encrypted track 2", NID_setAttr_T2Enc, 6, &so[4369]},
++    {"setAttr-T2cleartxt", "cleartext track 2", NID_setAttr_T2cleartxt, 6, &so[4375]},
++    {"setAttr-TokICCsig", "ICC or token signature", NID_setAttr_TokICCsig, 6, &so[4381]},
++    {"setAttr-SecDevSig", "secure device signature", NID_setAttr_SecDevSig, 6, &so[4387]},
++    {"set-brand-IATA-ATA", "set-brand-IATA-ATA", NID_set_brand_IATA_ATA, 4, &so[4393]},
++    {"set-brand-Diners", "set-brand-Diners", NID_set_brand_Diners, 4, &so[4397]},
++    {"set-brand-AmericanExpress", "set-brand-AmericanExpress", NID_set_brand_AmericanExpress, 4, &so[4401]},
++    {"set-brand-JCB", "set-brand-JCB", NID_set_brand_JCB, 4, &so[4405]},
++    {"set-brand-Visa", "set-brand-Visa", NID_set_brand_Visa, 4, &so[4409]},
++    {"set-brand-MasterCard", "set-brand-MasterCard", NID_set_brand_MasterCard, 4, &so[4413]},
++    {"set-brand-Novus", "set-brand-Novus", NID_set_brand_Novus, 5, &so[4417]},
++    {"DES-CDMF", "des-cdmf", NID_des_cdmf, 8, &so[4422]},
++    {"rsaOAEPEncryptionSET", "rsaOAEPEncryptionSET", NID_rsaOAEPEncryptionSET, 9, &so[4430]},
++    {"ITU-T", "itu-t", NID_itu_t},
++    {"JOINT-ISO-ITU-T", "joint-iso-itu-t", NID_joint_iso_itu_t},
++    {"international-organizations", "International Organizations", NID_international_organizations, 1, &so[4439]},
++    {"msSmartcardLogin", "Microsoft Smartcardlogin", NID_ms_smartcard_login, 10, &so[4440]},
++    {"msUPN", "Microsoft Universal Principal Name", NID_ms_upn, 10, &so[4450]},
++    {"AES-128-CFB1", "aes-128-cfb1", NID_aes_128_cfb1},
++    {"AES-192-CFB1", "aes-192-cfb1", NID_aes_192_cfb1},
++    {"AES-256-CFB1", "aes-256-cfb1", NID_aes_256_cfb1},
++    {"AES-128-CFB8", "aes-128-cfb8", NID_aes_128_cfb8},
++    {"AES-192-CFB8", "aes-192-cfb8", NID_aes_192_cfb8},
++    {"AES-256-CFB8", "aes-256-cfb8", NID_aes_256_cfb8},
++    {"DES-CFB1", "des-cfb1", NID_des_cfb1},
++    {"DES-CFB8", "des-cfb8", NID_des_cfb8},
++    {"DES-EDE3-CFB1", "des-ede3-cfb1", NID_des_ede3_cfb1},
++    {"DES-EDE3-CFB8", "des-ede3-cfb8", NID_des_ede3_cfb8},
++    {"street", "streetAddress", NID_streetAddress, 3, &so[4460]},
++    {"postalCode", "postalCode", NID_postalCode, 3, &so[4463]},
++    {"id-ppl", "id-ppl", NID_id_ppl, 7, &so[4466]},
++    {"proxyCertInfo", "Proxy Certificate Information", NID_proxyCertInfo, 8, &so[4473]},
++    {"id-ppl-anyLanguage", "Any language", NID_id_ppl_anyLanguage, 8, &so[4481]},
++    {"id-ppl-inheritAll", "Inherit all", NID_id_ppl_inheritAll, 8, &so[4489]},
++    {"nameConstraints", "X509v3 Name Constraints", NID_name_constraints, 3, &so[4497]},
++    {"id-ppl-independent", "Independent", NID_Independent, 8, &so[4500]},
++    {"RSA-SHA256", "sha256WithRSAEncryption", NID_sha256WithRSAEncryption, 9, &so[4508]},
++    {"RSA-SHA384", "sha384WithRSAEncryption", NID_sha384WithRSAEncryption, 9, &so[4517]},
++    {"RSA-SHA512", "sha512WithRSAEncryption", NID_sha512WithRSAEncryption, 9, &so[4526]},
++    {"RSA-SHA224", "sha224WithRSAEncryption", NID_sha224WithRSAEncryption, 9, &so[4535]},
++    {"SHA256", "sha256", NID_sha256, 9, &so[4544]},
++    {"SHA384", "sha384", NID_sha384, 9, &so[4553]},
++    {"SHA512", "sha512", NID_sha512, 9, &so[4562]},
++    {"SHA224", "sha224", NID_sha224, 9, &so[4571]},
++    {"identified-organization", "identified-organization", NID_identified_organization, 1, &so[4580]},
++    {"certicom-arc", "certicom-arc", NID_certicom_arc, 3, &so[4581]},
++    {"wap", "wap", NID_wap, 2, &so[4584]},
++    {"wap-wsg", "wap-wsg", NID_wap_wsg, 3, &so[4586]},
++    {"id-characteristic-two-basis", "id-characteristic-two-basis", NID_X9_62_id_characteristic_two_basis, 8, &so[4589]},
++    {"onBasis", "onBasis", NID_X9_62_onBasis, 9, &so[4597]},
++    {"tpBasis", "tpBasis", NID_X9_62_tpBasis, 9, &so[4606]},
++    {"ppBasis", "ppBasis", NID_X9_62_ppBasis, 9, &so[4615]},
++    {"c2pnb163v1", "c2pnb163v1", NID_X9_62_c2pnb163v1, 8, &so[4624]},
++    {"c2pnb163v2", "c2pnb163v2", NID_X9_62_c2pnb163v2, 8, &so[4632]},
++    {"c2pnb163v3", "c2pnb163v3", NID_X9_62_c2pnb163v3, 8, &so[4640]},
++    {"c2pnb176v1", "c2pnb176v1", NID_X9_62_c2pnb176v1, 8, &so[4648]},
++    {"c2tnb191v1", "c2tnb191v1", NID_X9_62_c2tnb191v1, 8, &so[4656]},
++    {"c2tnb191v2", "c2tnb191v2", NID_X9_62_c2tnb191v2, 8, &so[4664]},
++    {"c2tnb191v3", "c2tnb191v3", NID_X9_62_c2tnb191v3, 8, &so[4672]},
++    {"c2onb191v4", "c2onb191v4", NID_X9_62_c2onb191v4, 8, &so[4680]},
++    {"c2onb191v5", "c2onb191v5", NID_X9_62_c2onb191v5, 8, &so[4688]},
++    {"c2pnb208w1", "c2pnb208w1", NID_X9_62_c2pnb208w1, 8, &so[4696]},
++    {"c2tnb239v1", "c2tnb239v1", NID_X9_62_c2tnb239v1, 8, &so[4704]},
++    {"c2tnb239v2", "c2tnb239v2", NID_X9_62_c2tnb239v2, 8, &so[4712]},
++    {"c2tnb239v3", "c2tnb239v3", NID_X9_62_c2tnb239v3, 8, &so[4720]},
++    {"c2onb239v4", "c2onb239v4", NID_X9_62_c2onb239v4, 8, &so[4728]},
++    {"c2onb239v5", "c2onb239v5", NID_X9_62_c2onb239v5, 8, &so[4736]},
++    {"c2pnb272w1", "c2pnb272w1", NID_X9_62_c2pnb272w1, 8, &so[4744]},
++    {"c2pnb304w1", "c2pnb304w1", NID_X9_62_c2pnb304w1, 8, &so[4752]},
++    {"c2tnb359v1", "c2tnb359v1", NID_X9_62_c2tnb359v1, 8, &so[4760]},
++    {"c2pnb368w1", "c2pnb368w1", NID_X9_62_c2pnb368w1, 8, &so[4768]},
++    {"c2tnb431r1", "c2tnb431r1", NID_X9_62_c2tnb431r1, 8, &so[4776]},
++    {"secp112r1", "secp112r1", NID_secp112r1, 5, &so[4784]},
++    {"secp112r2", "secp112r2", NID_secp112r2, 5, &so[4789]},
++    {"secp128r1", "secp128r1", NID_secp128r1, 5, &so[4794]},
++    {"secp128r2", "secp128r2", NID_secp128r2, 5, &so[4799]},
++    {"secp160k1", "secp160k1", NID_secp160k1, 5, &so[4804]},
++    {"secp160r1", "secp160r1", NID_secp160r1, 5, &so[4809]},
++    {"secp160r2", "secp160r2", NID_secp160r2, 5, &so[4814]},
++    {"secp192k1", "secp192k1", NID_secp192k1, 5, &so[4819]},
++    {"secp224k1", "secp224k1", NID_secp224k1, 5, &so[4824]},
++    {"secp224r1", "secp224r1", NID_secp224r1, 5, &so[4829]},
++    {"secp256k1", "secp256k1", NID_secp256k1, 5, &so[4834]},
++    {"secp384r1", "secp384r1", NID_secp384r1, 5, &so[4839]},
++    {"secp521r1", "secp521r1", NID_secp521r1, 5, &so[4844]},
++    {"sect113r1", "sect113r1", NID_sect113r1, 5, &so[4849]},
++    {"sect113r2", "sect113r2", NID_sect113r2, 5, &so[4854]},
++    {"sect131r1", "sect131r1", NID_sect131r1, 5, &so[4859]},
++    {"sect131r2", "sect131r2", NID_sect131r2, 5, &so[4864]},
++    {"sect163k1", "sect163k1", NID_sect163k1, 5, &so[4869]},
++    {"sect163r1", "sect163r1", NID_sect163r1, 5, &so[4874]},
++    {"sect163r2", "sect163r2", NID_sect163r2, 5, &so[4879]},
++    {"sect193r1", "sect193r1", NID_sect193r1, 5, &so[4884]},
++    {"sect193r2", "sect193r2", NID_sect193r2, 5, &so[4889]},
++    {"sect233k1", "sect233k1", NID_sect233k1, 5, &so[4894]},
++    {"sect233r1", "sect233r1", NID_sect233r1, 5, &so[4899]},
++    {"sect239k1", "sect239k1", NID_sect239k1, 5, &so[4904]},
++    {"sect283k1", "sect283k1", NID_sect283k1, 5, &so[4909]},
++    {"sect283r1", "sect283r1", NID_sect283r1, 5, &so[4914]},
++    {"sect409k1", "sect409k1", NID_sect409k1, 5, &so[4919]},
++    {"sect409r1", "sect409r1", NID_sect409r1, 5, &so[4924]},
++    {"sect571k1", "sect571k1", NID_sect571k1, 5, &so[4929]},
++    {"sect571r1", "sect571r1", NID_sect571r1, 5, &so[4934]},
++    {"wap-wsg-idm-ecid-wtls1", "wap-wsg-idm-ecid-wtls1", NID_wap_wsg_idm_ecid_wtls1, 5, &so[4939]},
++    {"wap-wsg-idm-ecid-wtls3", "wap-wsg-idm-ecid-wtls3", NID_wap_wsg_idm_ecid_wtls3, 5, &so[4944]},
++    {"wap-wsg-idm-ecid-wtls4", "wap-wsg-idm-ecid-wtls4", NID_wap_wsg_idm_ecid_wtls4, 5, &so[4949]},
++    {"wap-wsg-idm-ecid-wtls5", "wap-wsg-idm-ecid-wtls5", NID_wap_wsg_idm_ecid_wtls5, 5, &so[4954]},
++    {"wap-wsg-idm-ecid-wtls6", "wap-wsg-idm-ecid-wtls6", NID_wap_wsg_idm_ecid_wtls6, 5, &so[4959]},
++    {"wap-wsg-idm-ecid-wtls7", "wap-wsg-idm-ecid-wtls7", NID_wap_wsg_idm_ecid_wtls7, 5, &so[4964]},
++    {"wap-wsg-idm-ecid-wtls8", "wap-wsg-idm-ecid-wtls8", NID_wap_wsg_idm_ecid_wtls8, 5, &so[4969]},
++    {"wap-wsg-idm-ecid-wtls9", "wap-wsg-idm-ecid-wtls9", NID_wap_wsg_idm_ecid_wtls9, 5, &so[4974]},
++    {"wap-wsg-idm-ecid-wtls10", "wap-wsg-idm-ecid-wtls10", NID_wap_wsg_idm_ecid_wtls10, 5, &so[4979]},
++    {"wap-wsg-idm-ecid-wtls11", "wap-wsg-idm-ecid-wtls11", NID_wap_wsg_idm_ecid_wtls11, 5, &so[4984]},
++    {"wap-wsg-idm-ecid-wtls12", "wap-wsg-idm-ecid-wtls12", NID_wap_wsg_idm_ecid_wtls12, 5, &so[4989]},
++    {"anyPolicy", "X509v3 Any Policy", NID_any_policy, 4, &so[4994]},
++    {"policyMappings", "X509v3 Policy Mappings", NID_policy_mappings, 3, &so[4998]},
++    {"inhibitAnyPolicy", "X509v3 Inhibit Any Policy", NID_inhibit_any_policy, 3, &so[5001]},
++    {"Oakley-EC2N-3", "ipsec3", NID_ipsec3},
++    {"Oakley-EC2N-4", "ipsec4", NID_ipsec4},
++    {"CAMELLIA-128-CBC", "camellia-128-cbc", NID_camellia_128_cbc, 11, &so[5004]},
++    {"CAMELLIA-192-CBC", "camellia-192-cbc", NID_camellia_192_cbc, 11, &so[5015]},
++    {"CAMELLIA-256-CBC", "camellia-256-cbc", NID_camellia_256_cbc, 11, &so[5026]},
++    {"CAMELLIA-128-ECB", "camellia-128-ecb", NID_camellia_128_ecb, 8, &so[5037]},
++    {"CAMELLIA-192-ECB", "camellia-192-ecb", NID_camellia_192_ecb, 8, &so[5045]},
++    {"CAMELLIA-256-ECB", "camellia-256-ecb", NID_camellia_256_ecb, 8, &so[5053]},
++    {"CAMELLIA-128-CFB", "camellia-128-cfb", NID_camellia_128_cfb128, 8, &so[5061]},
++    {"CAMELLIA-192-CFB", "camellia-192-cfb", NID_camellia_192_cfb128, 8, &so[5069]},
++    {"CAMELLIA-256-CFB", "camellia-256-cfb", NID_camellia_256_cfb128, 8, &so[5077]},
++    {"CAMELLIA-128-CFB1", "camellia-128-cfb1", NID_camellia_128_cfb1},
++    {"CAMELLIA-192-CFB1", "camellia-192-cfb1", NID_camellia_192_cfb1},
++    {"CAMELLIA-256-CFB1", "camellia-256-cfb1", NID_camellia_256_cfb1},
++    {"CAMELLIA-128-CFB8", "camellia-128-cfb8", NID_camellia_128_cfb8},
++    {"CAMELLIA-192-CFB8", "camellia-192-cfb8", NID_camellia_192_cfb8},
++    {"CAMELLIA-256-CFB8", "camellia-256-cfb8", NID_camellia_256_cfb8},
++    {"CAMELLIA-128-OFB", "camellia-128-ofb", NID_camellia_128_ofb128, 8, &so[5085]},
++    {"CAMELLIA-192-OFB", "camellia-192-ofb", NID_camellia_192_ofb128, 8, &so[5093]},
++    {"CAMELLIA-256-OFB", "camellia-256-ofb", NID_camellia_256_ofb128, 8, &so[5101]},
++    {"subjectDirectoryAttributes", "X509v3 Subject Directory Attributes", NID_subject_directory_attributes, 3, &so[5109]},
++    {"issuingDistributionPoint", "X509v3 Issuing Distribution Point", NID_issuing_distribution_point, 3, &so[5112]},
++    {"certificateIssuer", "X509v3 Certificate Issuer", NID_certificate_issuer, 3, &so[5115]},
++    { NULL, NULL, NID_undef },
++    {"KISA", "kisa", NID_kisa, 6, &so[5118]},
++    { NULL, NULL, NID_undef },
++    { NULL, NULL, NID_undef },
++    {"SEED-ECB", "seed-ecb", NID_seed_ecb, 8, &so[5124]},
++    {"SEED-CBC", "seed-cbc", NID_seed_cbc, 8, &so[5132]},
++    {"SEED-OFB", "seed-ofb", NID_seed_ofb128, 8, &so[5140]},
++    {"SEED-CFB", "seed-cfb", NID_seed_cfb128, 8, &so[5148]},
++    {"HMAC-MD5", "hmac-md5", NID_hmac_md5, 8, &so[5156]},
++    {"HMAC-SHA1", "hmac-sha1", NID_hmac_sha1, 8, &so[5164]},
++    {"id-PasswordBasedMAC", "password based MAC", NID_id_PasswordBasedMAC, 9, &so[5172]},
++    {"id-DHBasedMac", "Diffie-Hellman based MAC", NID_id_DHBasedMac, 9, &so[5181]},
++    {"id-it-suppLangTags", "id-it-suppLangTags", NID_id_it_suppLangTags, 8, &so[5190]},
++    {"caRepository", "CA Repository", NID_caRepository, 8, &so[5198]},
++    {"id-smime-ct-compressedData", "id-smime-ct-compressedData", NID_id_smime_ct_compressedData, 11, &so[5206]},
++    {"id-ct-asciiTextWithCRLF", "id-ct-asciiTextWithCRLF", NID_id_ct_asciiTextWithCRLF, 11, &so[5217]},
++    {"id-aes128-wrap", "id-aes128-wrap", NID_id_aes128_wrap, 9, &so[5228]},
++    {"id-aes192-wrap", "id-aes192-wrap", NID_id_aes192_wrap, 9, &so[5237]},
++    {"id-aes256-wrap", "id-aes256-wrap", NID_id_aes256_wrap, 9, &so[5246]},
++    {"ecdsa-with-Recommended", "ecdsa-with-Recommended", NID_ecdsa_with_Recommended, 7, &so[5255]},
++    {"ecdsa-with-Specified", "ecdsa-with-Specified", NID_ecdsa_with_Specified, 7, &so[5262]},
++    {"ecdsa-with-SHA224", "ecdsa-with-SHA224", NID_ecdsa_with_SHA224, 8, &so[5269]},
++    {"ecdsa-with-SHA256", "ecdsa-with-SHA256", NID_ecdsa_with_SHA256, 8, &so[5277]},
++    {"ecdsa-with-SHA384", "ecdsa-with-SHA384", NID_ecdsa_with_SHA384, 8, &so[5285]},
++    {"ecdsa-with-SHA512", "ecdsa-with-SHA512", NID_ecdsa_with_SHA512, 8, &so[5293]},
++    {"hmacWithMD5", "hmacWithMD5", NID_hmacWithMD5, 8, &so[5301]},
++    {"hmacWithSHA224", "hmacWithSHA224", NID_hmacWithSHA224, 8, &so[5309]},
++    {"hmacWithSHA256", "hmacWithSHA256", NID_hmacWithSHA256, 8, &so[5317]},
++    {"hmacWithSHA384", "hmacWithSHA384", NID_hmacWithSHA384, 8, &so[5325]},
++    {"hmacWithSHA512", "hmacWithSHA512", NID_hmacWithSHA512, 8, &so[5333]},
++    {"dsa_with_SHA224", "dsa_with_SHA224", NID_dsa_with_SHA224, 9, &so[5341]},
++    {"dsa_with_SHA256", "dsa_with_SHA256", NID_dsa_with_SHA256, 9, &so[5350]},
++    {"whirlpool", "whirlpool", NID_whirlpool, 6, &so[5359]},
++    {"cryptopro", "cryptopro", NID_cryptopro, 5, &so[5365]},
++    {"cryptocom", "cryptocom", NID_cryptocom, 5, &so[5370]},
++    {"id-GostR3411-94-with-GostR3410-2001", "GOST R 34.11-94 with GOST R 34.10-2001", NID_id_GostR3411_94_with_GostR3410_2001, 6, &so[5375]},
++    {"id-GostR3411-94-with-GostR3410-94", "GOST R 34.11-94 with GOST R 34.10-94", NID_id_GostR3411_94_with_GostR3410_94, 6, &so[5381]},
++    {"md_gost94", "GOST R 34.11-94", NID_id_GostR3411_94, 6, &so[5387]},
++    {"id-HMACGostR3411-94", "HMAC GOST 34.11-94", NID_id_HMACGostR3411_94, 6, &so[5393]},
++    {"gost2001", "GOST R 34.10-2001", NID_id_GostR3410_2001, 6, &so[5399]},
++    {"gost94", "GOST R 34.10-94", NID_id_GostR3410_94, 6, &so[5405]},
++    {"gost89", "GOST 28147-89", NID_id_Gost28147_89, 6, &so[5411]},
++    {"gost89-cnt", "gost89-cnt", NID_gost89_cnt},
++    {"gost-mac", "GOST 28147-89 MAC", NID_id_Gost28147_89_MAC, 6, &so[5417]},
++    {"prf-gostr3411-94", "GOST R 34.11-94 PRF", NID_id_GostR3411_94_prf, 6, &so[5423]},
++    {"id-GostR3410-2001DH", "GOST R 34.10-2001 DH", NID_id_GostR3410_2001DH, 6, &so[5429]},
++    {"id-GostR3410-94DH", "GOST R 34.10-94 DH", NID_id_GostR3410_94DH, 6, &so[5435]},
++    {"id-Gost28147-89-CryptoPro-KeyMeshing", "id-Gost28147-89-CryptoPro-KeyMeshing", NID_id_Gost28147_89_CryptoPro_KeyMeshing, 7, &so[5441]},
++    {"id-Gost28147-89-None-KeyMeshing", "id-Gost28147-89-None-KeyMeshing", NID_id_Gost28147_89_None_KeyMeshing, 7, &so[5448]},
++    {"id-GostR3411-94-TestParamSet", "id-GostR3411-94-TestParamSet", NID_id_GostR3411_94_TestParamSet, 7, &so[5455]},
++    {"id-GostR3411-94-CryptoProParamSet", "id-GostR3411-94-CryptoProParamSet", NID_id_GostR3411_94_CryptoProParamSet, 7, &so[5462]},
++    {"id-Gost28147-89-TestParamSet", "id-Gost28147-89-TestParamSet", NID_id_Gost28147_89_TestParamSet, 7, &so[5469]},
++    {"id-Gost28147-89-CryptoPro-A-ParamSet", "id-Gost28147-89-CryptoPro-A-ParamSet", NID_id_Gost28147_89_CryptoPro_A_ParamSet, 7, &so[5476]},
++    {"id-Gost28147-89-CryptoPro-B-ParamSet", "id-Gost28147-89-CryptoPro-B-ParamSet", NID_id_Gost28147_89_CryptoPro_B_ParamSet, 7, &so[5483]},
++    {"id-Gost28147-89-CryptoPro-C-ParamSet", "id-Gost28147-89-CryptoPro-C-ParamSet", NID_id_Gost28147_89_CryptoPro_C_ParamSet, 7, &so[5490]},
++    {"id-Gost28147-89-CryptoPro-D-ParamSet", "id-Gost28147-89-CryptoPro-D-ParamSet", NID_id_Gost28147_89_CryptoPro_D_ParamSet, 7, &so[5497]},
++    {"id-Gost28147-89-CryptoPro-Oscar-1-1-ParamSet", "id-Gost28147-89-CryptoPro-Oscar-1-1-ParamSet", NID_id_Gost28147_89_CryptoPro_Oscar_1_1_ParamSet, 7, &so[5504]},
++    {"id-Gost28147-89-CryptoPro-Oscar-1-0-ParamSet", "id-Gost28147-89-CryptoPro-Oscar-1-0-ParamSet", NID_id_Gost28147_89_CryptoPro_Oscar_1_0_ParamSet, 7, &so[5511]},
++    {"id-Gost28147-89-CryptoPro-RIC-1-ParamSet", "id-Gost28147-89-CryptoPro-RIC-1-ParamSet", NID_id_Gost28147_89_CryptoPro_RIC_1_ParamSet, 7, &so[5518]},
++    {"id-GostR3410-94-TestParamSet", "id-GostR3410-94-TestParamSet", NID_id_GostR3410_94_TestParamSet, 7, &so[5525]},
++    {"id-GostR3410-94-CryptoPro-A-ParamSet", "id-GostR3410-94-CryptoPro-A-ParamSet", NID_id_GostR3410_94_CryptoPro_A_ParamSet, 7, &so[5532]},
++    {"id-GostR3410-94-CryptoPro-B-ParamSet", "id-GostR3410-94-CryptoPro-B-ParamSet", NID_id_GostR3410_94_CryptoPro_B_ParamSet, 7, &so[5539]},
++    {"id-GostR3410-94-CryptoPro-C-ParamSet", "id-GostR3410-94-CryptoPro-C-ParamSet", NID_id_GostR3410_94_CryptoPro_C_ParamSet, 7, &so[5546]},
++    {"id-GostR3410-94-CryptoPro-D-ParamSet", "id-GostR3410-94-CryptoPro-D-ParamSet", NID_id_GostR3410_94_CryptoPro_D_ParamSet, 7, &so[5553]},
++    {"id-GostR3410-94-CryptoPro-XchA-ParamSet", "id-GostR3410-94-CryptoPro-XchA-ParamSet", NID_id_GostR3410_94_CryptoPro_XchA_ParamSet, 7, &so[5560]},
++    {"id-GostR3410-94-CryptoPro-XchB-ParamSet", "id-GostR3410-94-CryptoPro-XchB-ParamSet", NID_id_GostR3410_94_CryptoPro_XchB_ParamSet, 7, &so[5567]},
++    {"id-GostR3410-94-CryptoPro-XchC-ParamSet", "id-GostR3410-94-CryptoPro-XchC-ParamSet", NID_id_GostR3410_94_CryptoPro_XchC_ParamSet, 7, &so[5574]},
++    {"id-GostR3410-2001-TestParamSet", "id-GostR3410-2001-TestParamSet", NID_id_GostR3410_2001_TestParamSet, 7, &so[5581]},
++    {"id-GostR3410-2001-CryptoPro-A-ParamSet", "id-GostR3410-2001-CryptoPro-A-ParamSet", NID_id_GostR3410_2001_CryptoPro_A_ParamSet, 7, &so[5588]},
++    {"id-GostR3410-2001-CryptoPro-B-ParamSet", "id-GostR3410-2001-CryptoPro-B-ParamSet", NID_id_GostR3410_2001_CryptoPro_B_ParamSet, 7, &so[5595]},
++    {"id-GostR3410-2001-CryptoPro-C-ParamSet", "id-GostR3410-2001-CryptoPro-C-ParamSet", NID_id_GostR3410_2001_CryptoPro_C_ParamSet, 7, &so[5602]},
++    {"id-GostR3410-2001-CryptoPro-XchA-ParamSet", "id-GostR3410-2001-CryptoPro-XchA-ParamSet", NID_id_GostR3410_2001_CryptoPro_XchA_ParamSet, 7, &so[5609]},
++    {"id-GostR3410-2001-CryptoPro-XchB-ParamSet", "id-GostR3410-2001-CryptoPro-XchB-ParamSet", NID_id_GostR3410_2001_CryptoPro_XchB_ParamSet, 7, &so[5616]},
++    {"id-GostR3410-94-a", "id-GostR3410-94-a", NID_id_GostR3410_94_a, 7, &so[5623]},
++    {"id-GostR3410-94-aBis", "id-GostR3410-94-aBis", NID_id_GostR3410_94_aBis, 7, &so[5630]},
++    {"id-GostR3410-94-b", "id-GostR3410-94-b", NID_id_GostR3410_94_b, 7, &so[5637]},
++    {"id-GostR3410-94-bBis", "id-GostR3410-94-bBis", NID_id_GostR3410_94_bBis, 7, &so[5644]},
++    {"id-Gost28147-89-cc", "GOST 28147-89 Cryptocom ParamSet", NID_id_Gost28147_89_cc, 8, &so[5651]},
++    {"gost94cc", "GOST 34.10-94 Cryptocom", NID_id_GostR3410_94_cc, 8, &so[5659]},
++    {"gost2001cc", "GOST 34.10-2001 Cryptocom", NID_id_GostR3410_2001_cc, 8, &so[5667]},
++    {"id-GostR3411-94-with-GostR3410-94-cc", "GOST R 34.11-94 with GOST R 34.10-94 Cryptocom", NID_id_GostR3411_94_with_GostR3410_94_cc, 8, &so[5675]},
++    {"id-GostR3411-94-with-GostR3410-2001-cc", "GOST R 34.11-94 with GOST R 34.10-2001 Cryptocom", NID_id_GostR3411_94_with_GostR3410_2001_cc, 8, &so[5683]},
++    {"id-GostR3410-2001-ParamSet-cc", "GOST R 3410-2001 Parameter Set Cryptocom", NID_id_GostR3410_2001_ParamSet_cc, 8, &so[5691]},
++    {"HMAC", "hmac", NID_hmac},
++    {"LocalKeySet", "Microsoft Local Key set", NID_LocalKeySet, 9, &so[5699]},
++    {"freshestCRL", "X509v3 Freshest CRL", NID_freshest_crl, 3, &so[5708]},
++    {"id-on-permanentIdentifier", "Permanent Identifier", NID_id_on_permanentIdentifier, 8, &so[5711]},
++    {"searchGuide", "searchGuide", NID_searchGuide, 3, &so[5719]},
++    {"businessCategory", "businessCategory", NID_businessCategory, 3, &so[5722]},
++    {"postalAddress", "postalAddress", NID_postalAddress, 3, &so[5725]},
++    {"postOfficeBox", "postOfficeBox", NID_postOfficeBox, 3, &so[5728]},
++    {"physicalDeliveryOfficeName", "physicalDeliveryOfficeName", NID_physicalDeliveryOfficeName, 3, &so[5731]},
++    {"telephoneNumber", "telephoneNumber", NID_telephoneNumber, 3, &so[5734]},
++    {"telexNumber", "telexNumber", NID_telexNumber, 3, &so[5737]},
++    {"teletexTerminalIdentifier", "teletexTerminalIdentifier", NID_teletexTerminalIdentifier, 3, &so[5740]},
++    {"facsimileTelephoneNumber", "facsimileTelephoneNumber", NID_facsimileTelephoneNumber, 3, &so[5743]},
++    {"x121Address", "x121Address", NID_x121Address, 3, &so[5746]},
++    {"internationaliSDNNumber", "internationaliSDNNumber", NID_internationaliSDNNumber, 3, &so[5749]},
++    {"registeredAddress", "registeredAddress", NID_registeredAddress, 3, &so[5752]},
++    {"destinationIndicator", "destinationIndicator", NID_destinationIndicator, 3, &so[5755]},
++    {"preferredDeliveryMethod", "preferredDeliveryMethod", NID_preferredDeliveryMethod, 3, &so[5758]},
++    {"presentationAddress", "presentationAddress", NID_presentationAddress, 3, &so[5761]},
++    {"supportedApplicationContext", "supportedApplicationContext", NID_supportedApplicationContext, 3, &so[5764]},
++    {"member", "member", NID_member, 3, &so[5767]},
++    {"owner", "owner", NID_owner, 3, &so[5770]},
++    {"roleOccupant", "roleOccupant", NID_roleOccupant, 3, &so[5773]},
++    {"seeAlso", "seeAlso", NID_seeAlso, 3, &so[5776]},
++    {"userPassword", "userPassword", NID_userPassword, 3, &so[5779]},
++    {"userCertificate", "userCertificate", NID_userCertificate, 3, &so[5782]},
++    {"cACertificate", "cACertificate", NID_cACertificate, 3, &so[5785]},
++    {"authorityRevocationList", "authorityRevocationList", NID_authorityRevocationList, 3, &so[5788]},
++    {"certificateRevocationList", "certificateRevocationList", NID_certificateRevocationList, 3, &so[5791]},
++    {"crossCertificatePair", "crossCertificatePair", NID_crossCertificatePair, 3, &so[5794]},
++    {"enhancedSearchGuide", "enhancedSearchGuide", NID_enhancedSearchGuide, 3, &so[5797]},
++    {"protocolInformation", "protocolInformation", NID_protocolInformation, 3, &so[5800]},
++    {"distinguishedName", "distinguishedName", NID_distinguishedName, 3, &so[5803]},
++    {"uniqueMember", "uniqueMember", NID_uniqueMember, 3, &so[5806]},
++    {"houseIdentifier", "houseIdentifier", NID_houseIdentifier, 3, &so[5809]},
++    {"supportedAlgorithms", "supportedAlgorithms", NID_supportedAlgorithms, 3, &so[5812]},
++    {"deltaRevocationList", "deltaRevocationList", NID_deltaRevocationList, 3, &so[5815]},
++    {"dmdName", "dmdName", NID_dmdName, 3, &so[5818]},
++    {"id-alg-PWRI-KEK", "id-alg-PWRI-KEK", NID_id_alg_PWRI_KEK, 11, &so[5821]},
++    {"CMAC", "cmac", NID_cmac},
++    {"id-aes128-GCM", "aes-128-gcm", NID_aes_128_gcm, 9, &so[5832]},
++    {"id-aes128-CCM", "aes-128-ccm", NID_aes_128_ccm, 9, &so[5841]},
++    {"id-aes128-wrap-pad", "id-aes128-wrap-pad", NID_id_aes128_wrap_pad, 9, &so[5850]},
++    {"id-aes192-GCM", "aes-192-gcm", NID_aes_192_gcm, 9, &so[5859]},
++    {"id-aes192-CCM", "aes-192-ccm", NID_aes_192_ccm, 9, &so[5868]},
++    {"id-aes192-wrap-pad", "id-aes192-wrap-pad", NID_id_aes192_wrap_pad, 9, &so[5877]},
++    {"id-aes256-GCM", "aes-256-gcm", NID_aes_256_gcm, 9, &so[5886]},
++    {"id-aes256-CCM", "aes-256-ccm", NID_aes_256_ccm, 9, &so[5895]},
++    {"id-aes256-wrap-pad", "id-aes256-wrap-pad", NID_id_aes256_wrap_pad, 9, &so[5904]},
++    {"AES-128-CTR", "aes-128-ctr", NID_aes_128_ctr},
++    {"AES-192-CTR", "aes-192-ctr", NID_aes_192_ctr},
++    {"AES-256-CTR", "aes-256-ctr", NID_aes_256_ctr},
++    {"id-camellia128-wrap", "id-camellia128-wrap", NID_id_camellia128_wrap, 11, &so[5913]},
++    {"id-camellia192-wrap", "id-camellia192-wrap", NID_id_camellia192_wrap, 11, &so[5924]},
++    {"id-camellia256-wrap", "id-camellia256-wrap", NID_id_camellia256_wrap, 11, &so[5935]},
++    {"anyExtendedKeyUsage", "Any Extended Key Usage", NID_anyExtendedKeyUsage, 4, &so[5946]},
++    {"MGF1", "mgf1", NID_mgf1, 9, &so[5950]},
++    {"RSASSA-PSS", "rsassaPss", NID_rsassaPss, 9, &so[5959]},
++    {"AES-128-XTS", "aes-128-xts", NID_aes_128_xts},
++    {"AES-256-XTS", "aes-256-xts", NID_aes_256_xts},
++    {"RC4-HMAC-MD5", "rc4-hmac-md5", NID_rc4_hmac_md5},
++    {"AES-128-CBC-HMAC-SHA1", "aes-128-cbc-hmac-sha1", NID_aes_128_cbc_hmac_sha1},
++    {"AES-192-CBC-HMAC-SHA1", "aes-192-cbc-hmac-sha1", NID_aes_192_cbc_hmac_sha1},
++    {"AES-256-CBC-HMAC-SHA1", "aes-256-cbc-hmac-sha1", NID_aes_256_cbc_hmac_sha1},
++    {"RSAES-OAEP", "rsaesOaep", NID_rsaesOaep, 9, &so[5968]},
++    {"dhpublicnumber", "X9.42 DH", NID_dhpublicnumber, 7, &so[5977]},
++    {"brainpoolP160r1", "brainpoolP160r1", NID_brainpoolP160r1, 9, &so[5984]},
++    {"brainpoolP160t1", "brainpoolP160t1", NID_brainpoolP160t1, 9, &so[5993]},
++    {"brainpoolP192r1", "brainpoolP192r1", NID_brainpoolP192r1, 9, &so[6002]},
++    {"brainpoolP192t1", "brainpoolP192t1", NID_brainpoolP192t1, 9, &so[6011]},
++    {"brainpoolP224r1", "brainpoolP224r1", NID_brainpoolP224r1, 9, &so[6020]},
++    {"brainpoolP224t1", "brainpoolP224t1", NID_brainpoolP224t1, 9, &so[6029]},
++    {"brainpoolP256r1", "brainpoolP256r1", NID_brainpoolP256r1, 9, &so[6038]},
++    {"brainpoolP256t1", "brainpoolP256t1", NID_brainpoolP256t1, 9, &so[6047]},
++    {"brainpoolP320r1", "brainpoolP320r1", NID_brainpoolP320r1, 9, &so[6056]},
++    {"brainpoolP320t1", "brainpoolP320t1", NID_brainpoolP320t1, 9, &so[6065]},
++    {"brainpoolP384r1", "brainpoolP384r1", NID_brainpoolP384r1, 9, &so[6074]},
++    {"brainpoolP384t1", "brainpoolP384t1", NID_brainpoolP384t1, 9, &so[6083]},
++    {"brainpoolP512r1", "brainpoolP512r1", NID_brainpoolP512r1, 9, &so[6092]},
++    {"brainpoolP512t1", "brainpoolP512t1", NID_brainpoolP512t1, 9, &so[6101]},
++    {"PSPECIFIED", "pSpecified", NID_pSpecified, 9, &so[6110]},
++    {"dhSinglePass-stdDH-sha1kdf-scheme", "dhSinglePass-stdDH-sha1kdf-scheme", NID_dhSinglePass_stdDH_sha1kdf_scheme, 9, &so[6119]},
++    {"dhSinglePass-stdDH-sha224kdf-scheme", "dhSinglePass-stdDH-sha224kdf-scheme", NID_dhSinglePass_stdDH_sha224kdf_scheme, 6, &so[6128]},
++    {"dhSinglePass-stdDH-sha256kdf-scheme", "dhSinglePass-stdDH-sha256kdf-scheme", NID_dhSinglePass_stdDH_sha256kdf_scheme, 6, &so[6134]},
++    {"dhSinglePass-stdDH-sha384kdf-scheme", "dhSinglePass-stdDH-sha384kdf-scheme", NID_dhSinglePass_stdDH_sha384kdf_scheme, 6, &so[6140]},
++    {"dhSinglePass-stdDH-sha512kdf-scheme", "dhSinglePass-stdDH-sha512kdf-scheme", NID_dhSinglePass_stdDH_sha512kdf_scheme, 6, &so[6146]},
++    {"dhSinglePass-cofactorDH-sha1kdf-scheme", "dhSinglePass-cofactorDH-sha1kdf-scheme", NID_dhSinglePass_cofactorDH_sha1kdf_scheme, 9, &so[6152]},
++    {"dhSinglePass-cofactorDH-sha224kdf-scheme", "dhSinglePass-cofactorDH-sha224kdf-scheme", NID_dhSinglePass_cofactorDH_sha224kdf_scheme, 6, &so[6161]},
++    {"dhSinglePass-cofactorDH-sha256kdf-scheme", "dhSinglePass-cofactorDH-sha256kdf-scheme", NID_dhSinglePass_cofactorDH_sha256kdf_scheme, 6, &so[6167]},
++    {"dhSinglePass-cofactorDH-sha384kdf-scheme", "dhSinglePass-cofactorDH-sha384kdf-scheme", NID_dhSinglePass_cofactorDH_sha384kdf_scheme, 6, &so[6173]},
++    {"dhSinglePass-cofactorDH-sha512kdf-scheme", "dhSinglePass-cofactorDH-sha512kdf-scheme", NID_dhSinglePass_cofactorDH_sha512kdf_scheme, 6, &so[6179]},
++    {"dh-std-kdf", "dh-std-kdf", NID_dh_std_kdf},
++    {"dh-cofactor-kdf", "dh-cofactor-kdf", NID_dh_cofactor_kdf},
++    {"AES-128-CBC-HMAC-SHA256", "aes-128-cbc-hmac-sha256", NID_aes_128_cbc_hmac_sha256},
++    {"AES-192-CBC-HMAC-SHA256", "aes-192-cbc-hmac-sha256", NID_aes_192_cbc_hmac_sha256},
++    {"AES-256-CBC-HMAC-SHA256", "aes-256-cbc-hmac-sha256", NID_aes_256_cbc_hmac_sha256},
++    {"ct_precert_scts", "CT Precertificate SCTs", NID_ct_precert_scts, 10, &so[6185]},
++    {"ct_precert_poison", "CT Precertificate Poison", NID_ct_precert_poison, 10, &so[6195]},
++    {"ct_precert_signer", "CT Precertificate Signer", NID_ct_precert_signer, 10, &so[6205]},
++    {"ct_cert_scts", "CT Certificate SCTs", NID_ct_cert_scts, 10, &so[6215]},
++    {"jurisdictionL", "jurisdictionLocalityName", NID_jurisdictionLocalityName, 11, &so[6225]},
++    {"jurisdictionST", "jurisdictionStateOrProvinceName", NID_jurisdictionStateOrProvinceName, 11, &so[6236]},
++    {"jurisdictionC", "jurisdictionCountryName", NID_jurisdictionCountryName, 11, &so[6247]},
++    {"AES-128-OCB", "aes-128-ocb", NID_aes_128_ocb},
++    {"AES-192-OCB", "aes-192-ocb", NID_aes_192_ocb},
++    {"AES-256-OCB", "aes-256-ocb", NID_aes_256_ocb},
++    {"CAMELLIA-128-GCM", "camellia-128-gcm", NID_camellia_128_gcm, 8, &so[6258]},
++    {"CAMELLIA-128-CCM", "camellia-128-ccm", NID_camellia_128_ccm, 8, &so[6266]},
++    {"CAMELLIA-128-CTR", "camellia-128-ctr", NID_camellia_128_ctr, 8, &so[6274]},
++    {"CAMELLIA-128-CMAC", "camellia-128-cmac", NID_camellia_128_cmac, 8, &so[6282]},
++    {"CAMELLIA-192-GCM", "camellia-192-gcm", NID_camellia_192_gcm, 8, &so[6290]},
++    {"CAMELLIA-192-CCM", "camellia-192-ccm", NID_camellia_192_ccm, 8, &so[6298]},
++    {"CAMELLIA-192-CTR", "camellia-192-ctr", NID_camellia_192_ctr, 8, &so[6306]},
++    {"CAMELLIA-192-CMAC", "camellia-192-cmac", NID_camellia_192_cmac, 8, &so[6314]},
++    {"CAMELLIA-256-GCM", "camellia-256-gcm", NID_camellia_256_gcm, 8, &so[6322]},
++    {"CAMELLIA-256-CCM", "camellia-256-ccm", NID_camellia_256_ccm, 8, &so[6330]},
++    {"CAMELLIA-256-CTR", "camellia-256-ctr", NID_camellia_256_ctr, 8, &so[6338]},
++    {"CAMELLIA-256-CMAC", "camellia-256-cmac", NID_camellia_256_cmac, 8, &so[6346]},
++    {"id-scrypt", "id-scrypt", NID_id_scrypt, 9, &so[6354]},
++    {"id-tc26", "id-tc26", NID_id_tc26, 5, &so[6363]},
++    {"gost89-cnt-12", "gost89-cnt-12", NID_gost89_cnt_12},
++    {"gost-mac-12", "gost-mac-12", NID_gost_mac_12},
++    {"id-tc26-algorithms", "id-tc26-algorithms", NID_id_tc26_algorithms, 6, &so[6368]},
++    {"id-tc26-sign", "id-tc26-sign", NID_id_tc26_sign, 7, &so[6374]},
++    {"gost2012_256", "GOST R 34.10-2012 with 256 bit modulus", NID_id_GostR3410_2012_256, 8, &so[6381]},
++    {"gost2012_512", "GOST R 34.10-2012 with 512 bit modulus", NID_id_GostR3410_2012_512, 8, &so[6389]},
++    {"id-tc26-digest", "id-tc26-digest", NID_id_tc26_digest, 7, &so[6397]},
++    {"md_gost12_256", "GOST R 34.11-2012 with 256 bit hash", NID_id_GostR3411_2012_256, 8, &so[6404]},
++    {"md_gost12_512", "GOST R 34.11-2012 with 512 bit hash", NID_id_GostR3411_2012_512, 8, &so[6412]},
++    {"id-tc26-signwithdigest", "id-tc26-signwithdigest", NID_id_tc26_signwithdigest, 7, &so[6420]},
++    {"id-tc26-signwithdigest-gost3410-2012-256", "GOST R 34.10-2012 with GOST R 34.11-2012 (256 bit)", NID_id_tc26_signwithdigest_gost3410_2012_256, 8, &so[6427]},
++    {"id-tc26-signwithdigest-gost3410-2012-512", "GOST R 34.10-2012 with GOST R 34.11-2012 (512 bit)", NID_id_tc26_signwithdigest_gost3410_2012_512, 8, &so[6435]},
++    {"id-tc26-mac", "id-tc26-mac", NID_id_tc26_mac, 7, &so[6443]},
++    {"id-tc26-hmac-gost-3411-2012-256", "HMAC GOST 34.11-2012 256 bit", NID_id_tc26_hmac_gost_3411_2012_256, 8, &so[6450]},
++    {"id-tc26-hmac-gost-3411-2012-512", "HMAC GOST 34.11-2012 512 bit", NID_id_tc26_hmac_gost_3411_2012_512, 8, &so[6458]},
++    {"id-tc26-cipher", "id-tc26-cipher", NID_id_tc26_cipher, 7, &so[6466]},
++    {"id-tc26-agreement", "id-tc26-agreement", NID_id_tc26_agreement, 7, &so[6473]},
++    {"id-tc26-agreement-gost-3410-2012-256", "id-tc26-agreement-gost-3410-2012-256", NID_id_tc26_agreement_gost_3410_2012_256, 8, &so[6480]},
++    {"id-tc26-agreement-gost-3410-2012-512", "id-tc26-agreement-gost-3410-2012-512", NID_id_tc26_agreement_gost_3410_2012_512, 8, &so[6488]},
++    {"id-tc26-constants", "id-tc26-constants", NID_id_tc26_constants, 6, &so[6496]},
++    {"id-tc26-sign-constants", "id-tc26-sign-constants", NID_id_tc26_sign_constants, 7, &so[6502]},
++    {"id-tc26-gost-3410-2012-512-constants", "id-tc26-gost-3410-2012-512-constants", NID_id_tc26_gost_3410_2012_512_constants, 8, &so[6509]},
++    {"id-tc26-gost-3410-2012-512-paramSetTest", "GOST R 34.10-2012 (512 bit) testing parameter set", NID_id_tc26_gost_3410_2012_512_paramSetTest, 9, &so[6517]},
++    {"id-tc26-gost-3410-2012-512-paramSetA", "GOST R 34.10-2012 (512 bit) ParamSet A", NID_id_tc26_gost_3410_2012_512_paramSetA, 9, &so[6526]},
++    {"id-tc26-gost-3410-2012-512-paramSetB", "GOST R 34.10-2012 (512 bit) ParamSet B", NID_id_tc26_gost_3410_2012_512_paramSetB, 9, &so[6535]},
++    {"id-tc26-digest-constants", "id-tc26-digest-constants", NID_id_tc26_digest_constants, 7, &so[6544]},
++    {"id-tc26-cipher-constants", "id-tc26-cipher-constants", NID_id_tc26_cipher_constants, 7, &so[6551]},
++    {"id-tc26-gost-28147-constants", "id-tc26-gost-28147-constants", NID_id_tc26_gost_28147_constants, 8, &so[6558]},
++    {"id-tc26-gost-28147-param-Z", "GOST 28147-89 TC26 parameter set", NID_id_tc26_gost_28147_param_Z, 9, &so[6566]},
++    {"INN", "INN", NID_INN, 8, &so[6575]},
++    {"OGRN", "OGRN", NID_OGRN, 5, &so[6583]},
++    {"SNILS", "SNILS", NID_SNILS, 5, &so[6588]},
++    {"subjectSignTool", "Signing Tool of Subject", NID_subjectSignTool, 5, &so[6593]},
++    {"issuerSignTool", "Signing Tool of Issuer", NID_issuerSignTool, 5, &so[6598]},
++    {"gost89-cbc", "gost89-cbc", NID_gost89_cbc},
++    {"gost89-ecb", "gost89-ecb", NID_gost89_ecb},
++    {"gost89-ctr", "gost89-ctr", NID_gost89_ctr},
++    {"grasshopper-ecb", "grasshopper-ecb", NID_grasshopper_ecb},
++    {"grasshopper-ctr", "grasshopper-ctr", NID_grasshopper_ctr},
++    {"grasshopper-ofb", "grasshopper-ofb", NID_grasshopper_ofb},
++    {"grasshopper-cbc", "grasshopper-cbc", NID_grasshopper_cbc},
++    {"grasshopper-cfb", "grasshopper-cfb", NID_grasshopper_cfb},
++    {"grasshopper-mac", "grasshopper-mac", NID_grasshopper_mac},
++    {"ChaCha20-Poly1305", "chacha20-poly1305", NID_chacha20_poly1305},
++    {"ChaCha20", "chacha20", NID_chacha20},
++    {"tlsfeature", "TLS Feature", NID_tlsfeature, 8, &so[6603]},
++    {"TLS1-PRF", "tls1-prf", NID_tls1_prf},
++    {"ipsecIKE", "ipsec Internet Key Exchange", NID_ipsec_IKE, 8, &so[6611]},
++    {"capwapAC", "Ctrl/provision WAP Access", NID_capwapAC, 8, &so[6619]},
++    {"capwapWTP", "Ctrl/Provision WAP Termination", NID_capwapWTP, 8, &so[6627]},
++    {"secureShellClient", "SSH Client", NID_sshClient, 8, &so[6635]},
++    {"secureShellServer", "SSH Server", NID_sshServer, 8, &so[6643]},
++    {"sendRouter", "Send Router", NID_sendRouter, 8, &so[6651]},
++    {"sendProxiedRouter", "Send Proxied Router", NID_sendProxiedRouter, 8, &so[6659]},
++    {"sendOwner", "Send Owner", NID_sendOwner, 8, &so[6667]},
++    {"sendProxiedOwner", "Send Proxied Owner", NID_sendProxiedOwner, 8, &so[6675]},
++    {"id-pkinit", "id-pkinit", NID_id_pkinit, 6, &so[6683]},
++    {"pkInitClientAuth", "PKINIT Client Auth", NID_pkInitClientAuth, 7, &so[6689]},
++    {"pkInitKDC", "Signing KDC Response", NID_pkInitKDC, 7, &so[6696]},
++    {"X25519", "X25519", NID_X25519, 3, &so[6703]},
++    {"X448", "X448", NID_X448, 3, &so[6706]},
++    {"HKDF", "hkdf", NID_hkdf},
++    {"KxRSA", "kx-rsa", NID_kx_rsa},
++    {"KxECDHE", "kx-ecdhe", NID_kx_ecdhe},
++    {"KxDHE", "kx-dhe", NID_kx_dhe},
++    {"KxECDHE-PSK", "kx-ecdhe-psk", NID_kx_ecdhe_psk},
++    {"KxDHE-PSK", "kx-dhe-psk", NID_kx_dhe_psk},
++    {"KxRSA_PSK", "kx-rsa-psk", NID_kx_rsa_psk},
++    {"KxPSK", "kx-psk", NID_kx_psk},
++    {"KxSRP", "kx-srp", NID_kx_srp},
++    {"KxGOST", "kx-gost", NID_kx_gost},
++    {"AuthRSA", "auth-rsa", NID_auth_rsa},
++    {"AuthECDSA", "auth-ecdsa", NID_auth_ecdsa},
++    {"AuthPSK", "auth-psk", NID_auth_psk},
++    {"AuthDSS", "auth-dss", NID_auth_dss},
++    {"AuthGOST01", "auth-gost01", NID_auth_gost01},
++    {"AuthGOST12", "auth-gost12", NID_auth_gost12},
++    {"AuthSRP", "auth-srp", NID_auth_srp},
++    {"AuthNULL", "auth-null", NID_auth_null},
++    { NULL, NULL, NID_undef },
++    { NULL, NULL, NID_undef },
++    {"BLAKE2b512", "blake2b512", NID_blake2b512, 11, &so[6709]},
++    {"BLAKE2s256", "blake2s256", NID_blake2s256, 11, &so[6720]},
++    {"id-smime-ct-contentCollection", "id-smime-ct-contentCollection", NID_id_smime_ct_contentCollection, 11, &so[6731]},
++    {"id-smime-ct-authEnvelopedData", "id-smime-ct-authEnvelopedData", NID_id_smime_ct_authEnvelopedData, 11, &so[6742]},
++    {"id-ct-xml", "id-ct-xml", NID_id_ct_xml, 11, &so[6753]},
++};
++
++#define NUM_SN 1052
++static const unsigned int sn_objs[NUM_SN] = {
++     364,    /* "AD_DVCS" */
++     419,    /* "AES-128-CBC" */
++     916,    /* "AES-128-CBC-HMAC-SHA1" */
++     948,    /* "AES-128-CBC-HMAC-SHA256" */
++     421,    /* "AES-128-CFB" */
++     650,    /* "AES-128-CFB1" */
++     653,    /* "AES-128-CFB8" */
++     904,    /* "AES-128-CTR" */
++     418,    /* "AES-128-ECB" */
++     958,    /* "AES-128-OCB" */
++     420,    /* "AES-128-OFB" */
++     913,    /* "AES-128-XTS" */
++     423,    /* "AES-192-CBC" */
++     917,    /* "AES-192-CBC-HMAC-SHA1" */
++     949,    /* "AES-192-CBC-HMAC-SHA256" */
++     425,    /* "AES-192-CFB" */
++     651,    /* "AES-192-CFB1" */
++     654,    /* "AES-192-CFB8" */
++     905,    /* "AES-192-CTR" */
++     422,    /* "AES-192-ECB" */
++     959,    /* "AES-192-OCB" */
++     424,    /* "AES-192-OFB" */
++     427,    /* "AES-256-CBC" */
++     918,    /* "AES-256-CBC-HMAC-SHA1" */
++     950,    /* "AES-256-CBC-HMAC-SHA256" */
++     429,    /* "AES-256-CFB" */
++     652,    /* "AES-256-CFB1" */
++     655,    /* "AES-256-CFB8" */
++     906,    /* "AES-256-CTR" */
++     426,    /* "AES-256-ECB" */
++     960,    /* "AES-256-OCB" */
++     428,    /* "AES-256-OFB" */
++     914,    /* "AES-256-XTS" */
++    1049,    /* "AuthDSS" */
++    1047,    /* "AuthECDSA" */
++    1050,    /* "AuthGOST01" */
++    1051,    /* "AuthGOST12" */
++    1053,    /* "AuthNULL" */
++    1048,    /* "AuthPSK" */
++    1046,    /* "AuthRSA" */
++    1052,    /* "AuthSRP" */
++      91,    /* "BF-CBC" */
++      93,    /* "BF-CFB" */
++      92,    /* "BF-ECB" */
++      94,    /* "BF-OFB" */
++    1056,    /* "BLAKE2b512" */
++    1057,    /* "BLAKE2s256" */
++      14,    /* "C" */
++     751,    /* "CAMELLIA-128-CBC" */
++     962,    /* "CAMELLIA-128-CCM" */
++     757,    /* "CAMELLIA-128-CFB" */
++     760,    /* "CAMELLIA-128-CFB1" */
++     763,    /* "CAMELLIA-128-CFB8" */
++     964,    /* "CAMELLIA-128-CMAC" */
++     963,    /* "CAMELLIA-128-CTR" */
++     754,    /* "CAMELLIA-128-ECB" */
++     961,    /* "CAMELLIA-128-GCM" */
++     766,    /* "CAMELLIA-128-OFB" */
++     752,    /* "CAMELLIA-192-CBC" */
++     966,    /* "CAMELLIA-192-CCM" */
++     758,    /* "CAMELLIA-192-CFB" */
++     761,    /* "CAMELLIA-192-CFB1" */
++     764,    /* "CAMELLIA-192-CFB8" */
++     968,    /* "CAMELLIA-192-CMAC" */
++     967,    /* "CAMELLIA-192-CTR" */
++     755,    /* "CAMELLIA-192-ECB" */
++     965,    /* "CAMELLIA-192-GCM" */
++     767,    /* "CAMELLIA-192-OFB" */
++     753,    /* "CAMELLIA-256-CBC" */
++     970,    /* "CAMELLIA-256-CCM" */
++     759,    /* "CAMELLIA-256-CFB" */
++     762,    /* "CAMELLIA-256-CFB1" */
++     765,    /* "CAMELLIA-256-CFB8" */
++     972,    /* "CAMELLIA-256-CMAC" */
++     971,    /* "CAMELLIA-256-CTR" */
++     756,    /* "CAMELLIA-256-ECB" */
++     969,    /* "CAMELLIA-256-GCM" */
++     768,    /* "CAMELLIA-256-OFB" */
++     108,    /* "CAST5-CBC" */
++     110,    /* "CAST5-CFB" */
++     109,    /* "CAST5-ECB" */
++     111,    /* "CAST5-OFB" */
++     894,    /* "CMAC" */
++      13,    /* "CN" */
++     141,    /* "CRLReason" */
++     417,    /* "CSPName" */
++    1019,    /* "ChaCha20" */
++    1018,    /* "ChaCha20-Poly1305" */
++     367,    /* "CrlID" */
++     391,    /* "DC" */
++      31,    /* "DES-CBC" */
++     643,    /* "DES-CDMF" */
++      30,    /* "DES-CFB" */
++     656,    /* "DES-CFB1" */
++     657,    /* "DES-CFB8" */
++      29,    /* "DES-ECB" */
++      32,    /* "DES-EDE" */
++      43,    /* "DES-EDE-CBC" */
++      60,    /* "DES-EDE-CFB" */
++      62,    /* "DES-EDE-OFB" */
++      33,    /* "DES-EDE3" */
++      44,    /* "DES-EDE3-CBC" */
++      61,    /* "DES-EDE3-CFB" */
++     658,    /* "DES-EDE3-CFB1" */
++     659,    /* "DES-EDE3-CFB8" */
++      63,    /* "DES-EDE3-OFB" */
++      45,    /* "DES-OFB" */
++      80,    /* "DESX-CBC" */
++     380,    /* "DOD" */
++     116,    /* "DSA" */
++      66,    /* "DSA-SHA" */
++     113,    /* "DSA-SHA1" */
++      70,    /* "DSA-SHA1-old" */
++      67,    /* "DSA-old" */
++     297,    /* "DVCS" */
++      99,    /* "GN" */
++    1036,    /* "HKDF" */
++     855,    /* "HMAC" */
++     780,    /* "HMAC-MD5" */
++     781,    /* "HMAC-SHA1" */
++     381,    /* "IANA" */
++      34,    /* "IDEA-CBC" */
++      35,    /* "IDEA-CFB" */
++      36,    /* "IDEA-ECB" */
++      46,    /* "IDEA-OFB" */
++    1004,    /* "INN" */
++     181,    /* "ISO" */
++     183,    /* "ISO-US" */
++     645,    /* "ITU-T" */
++     646,    /* "JOINT-ISO-ITU-T" */
++     773,    /* "KISA" */
++    1039,    /* "KxDHE" */
++    1041,    /* "KxDHE-PSK" */
++    1038,    /* "KxECDHE" */
++    1040,    /* "KxECDHE-PSK" */
++    1045,    /* "KxGOST" */
++    1043,    /* "KxPSK" */
++    1037,    /* "KxRSA" */
++    1042,    /* "KxRSA_PSK" */
++    1044,    /* "KxSRP" */
++      15,    /* "L" */
++     856,    /* "LocalKeySet" */
++       3,    /* "MD2" */
++     257,    /* "MD4" */
++       4,    /* "MD5" */
++     114,    /* "MD5-SHA1" */
++      95,    /* "MDC2" */
++     911,    /* "MGF1" */
++     388,    /* "Mail" */
++     393,    /* "NULL" */
++     404,    /* "NULL" */
++      57,    /* "Netscape" */
++     366,    /* "Nonce" */
++      17,    /* "O" */
++     178,    /* "OCSP" */
++     180,    /* "OCSPSigning" */
++    1005,    /* "OGRN" */
++     379,    /* "ORG" */
++      18,    /* "OU" */
++     749,    /* "Oakley-EC2N-3" */
++     750,    /* "Oakley-EC2N-4" */
++       9,    /* "PBE-MD2-DES" */
++     168,    /* "PBE-MD2-RC2-64" */
++      10,    /* "PBE-MD5-DES" */
++     169,    /* "PBE-MD5-RC2-64" */
++     147,    /* "PBE-SHA1-2DES" */
++     146,    /* "PBE-SHA1-3DES" */
++     170,    /* "PBE-SHA1-DES" */
++     148,    /* "PBE-SHA1-RC2-128" */
++     149,    /* "PBE-SHA1-RC2-40" */
++      68,    /* "PBE-SHA1-RC2-64" */
++     144,    /* "PBE-SHA1-RC4-128" */
++     145,    /* "PBE-SHA1-RC4-40" */
++     161,    /* "PBES2" */
++      69,    /* "PBKDF2" */
++     162,    /* "PBMAC1" */
++     127,    /* "PKIX" */
++     935,    /* "PSPECIFIED" */
++      98,    /* "RC2-40-CBC" */
++     166,    /* "RC2-64-CBC" */
++      37,    /* "RC2-CBC" */
++      39,    /* "RC2-CFB" */
++      38,    /* "RC2-ECB" */
++      40,    /* "RC2-OFB" */
++       5,    /* "RC4" */
++      97,    /* "RC4-40" */
++     915,    /* "RC4-HMAC-MD5" */
++     120,    /* "RC5-CBC" */
++     122,    /* "RC5-CFB" */
++     121,    /* "RC5-ECB" */
++     123,    /* "RC5-OFB" */
++     117,    /* "RIPEMD160" */
++      19,    /* "RSA" */
++       7,    /* "RSA-MD2" */
++     396,    /* "RSA-MD4" */
++       8,    /* "RSA-MD5" */
++      96,    /* "RSA-MDC2" */
++     104,    /* "RSA-NP-MD5" */
++     119,    /* "RSA-RIPEMD160" */
++      42,    /* "RSA-SHA" */
++      65,    /* "RSA-SHA1" */
++     115,    /* "RSA-SHA1-2" */
++     671,    /* "RSA-SHA224" */
++     668,    /* "RSA-SHA256" */
++     669,    /* "RSA-SHA384" */
++     670,    /* "RSA-SHA512" */
++     919,    /* "RSAES-OAEP" */
++     912,    /* "RSASSA-PSS" */
++     777,    /* "SEED-CBC" */
++     779,    /* "SEED-CFB" */
++     776,    /* "SEED-ECB" */
++     778,    /* "SEED-OFB" */
++      41,    /* "SHA" */
++      64,    /* "SHA1" */
++     675,    /* "SHA224" */
++     672,    /* "SHA256" */
++     673,    /* "SHA384" */
++     674,    /* "SHA512" */
++     188,    /* "SMIME" */
++     167,    /* "SMIME-CAPS" */
++     100,    /* "SN" */
++    1006,    /* "SNILS" */
++      16,    /* "ST" */
++     143,    /* "SXNetID" */
++    1021,    /* "TLS1-PRF" */
++     458,    /* "UID" */
++       0,    /* "UNDEF" */
++    1034,    /* "X25519" */
++    1035,    /* "X448" */
++      11,    /* "X500" */
++     378,    /* "X500algorithms" */
++      12,    /* "X509" */
++     184,    /* "X9-57" */
++     185,    /* "X9cm" */
++     125,    /* "ZLIB" */
++     478,    /* "aRecord" */
++     289,    /* "aaControls" */
++     287,    /* "ac-auditEntity" */
++     397,    /* "ac-proxying" */
++     288,    /* "ac-targeting" */
++     368,    /* "acceptableResponses" */
++     446,    /* "account" */
++     363,    /* "ad_timestamping" */
++     376,    /* "algorithm" */
++     405,    /* "ansi-X9-62" */
++     910,    /* "anyExtendedKeyUsage" */
++     746,    /* "anyPolicy" */
++     370,    /* "archiveCutoff" */
++     484,    /* "associatedDomain" */
++     485,    /* "associatedName" */
++     501,    /* "audio" */
++     177,    /* "authorityInfoAccess" */
++      90,    /* "authorityKeyIdentifier" */
++     882,    /* "authorityRevocationList" */
++      87,    /* "basicConstraints" */
++     365,    /* "basicOCSPResponse" */
++     285,    /* "biometricInfo" */
++     921,    /* "brainpoolP160r1" */
++     922,    /* "brainpoolP160t1" */
++     923,    /* "brainpoolP192r1" */
++     924,    /* "brainpoolP192t1" */
++     925,    /* "brainpoolP224r1" */
++     926,    /* "brainpoolP224t1" */
++     927,    /* "brainpoolP256r1" */
++     928,    /* "brainpoolP256t1" */
++     929,    /* "brainpoolP320r1" */
++     930,    /* "brainpoolP320t1" */
++     931,    /* "brainpoolP384r1" */
++     932,    /* "brainpoolP384t1" */
++     933,    /* "brainpoolP512r1" */
++     934,    /* "brainpoolP512t1" */
++     494,    /* "buildingName" */
++     860,    /* "businessCategory" */
++     691,    /* "c2onb191v4" */
++     692,    /* "c2onb191v5" */
++     697,    /* "c2onb239v4" */
++     698,    /* "c2onb239v5" */
++     684,    /* "c2pnb163v1" */
++     685,    /* "c2pnb163v2" */
++     686,    /* "c2pnb163v3" */
++     687,    /* "c2pnb176v1" */
++     693,    /* "c2pnb208w1" */
++     699,    /* "c2pnb272w1" */
++     700,    /* "c2pnb304w1" */
++     702,    /* "c2pnb368w1" */
++     688,    /* "c2tnb191v1" */
++     689,    /* "c2tnb191v2" */
++     690,    /* "c2tnb191v3" */
++     694,    /* "c2tnb239v1" */
++     695,    /* "c2tnb239v2" */
++     696,    /* "c2tnb239v3" */
++     701,    /* "c2tnb359v1" */
++     703,    /* "c2tnb431r1" */
++     881,    /* "cACertificate" */
++     483,    /* "cNAMERecord" */
++     179,    /* "caIssuers" */
++     785,    /* "caRepository" */
++    1023,    /* "capwapAC" */
++    1024,    /* "capwapWTP" */
++     443,    /* "caseIgnoreIA5StringSyntax" */
++     152,    /* "certBag" */
++     677,    /* "certicom-arc" */
++     771,    /* "certificateIssuer" */
++      89,    /* "certificatePolicies" */
++     883,    /* "certificateRevocationList" */
++      54,    /* "challengePassword" */
++     407,    /* "characteristic-two-field" */
++     395,    /* "clearance" */
++     130,    /* "clientAuth" */
++     131,    /* "codeSigning" */
++      50,    /* "contentType" */
++      53,    /* "countersignature" */
++     153,    /* "crlBag" */
++     103,    /* "crlDistributionPoints" */
++      88,    /* "crlNumber" */
++     884,    /* "crossCertificatePair" */
++     806,    /* "cryptocom" */
++     805,    /* "cryptopro" */
++     954,    /* "ct_cert_scts" */
++     952,    /* "ct_precert_poison" */
++     951,    /* "ct_precert_scts" */
++     953,    /* "ct_precert_signer" */
++     500,    /* "dITRedirect" */
++     451,    /* "dNSDomain" */
++     495,    /* "dSAQuality" */
++     434,    /* "data" */
++     390,    /* "dcobject" */
++     140,    /* "deltaCRL" */
++     891,    /* "deltaRevocationList" */
++     107,    /* "description" */
++     871,    /* "destinationIndicator" */
++     947,    /* "dh-cofactor-kdf" */
++     946,    /* "dh-std-kdf" */
++      28,    /* "dhKeyAgreement" */
++     941,    /* "dhSinglePass-cofactorDH-sha1kdf-scheme" */
++     942,    /* "dhSinglePass-cofactorDH-sha224kdf-scheme" */
++     943,    /* "dhSinglePass-cofactorDH-sha256kdf-scheme" */
++     944,    /* "dhSinglePass-cofactorDH-sha384kdf-scheme" */
++     945,    /* "dhSinglePass-cofactorDH-sha512kdf-scheme" */
++     936,    /* "dhSinglePass-stdDH-sha1kdf-scheme" */
++     937,    /* "dhSinglePass-stdDH-sha224kdf-scheme" */
++     938,    /* "dhSinglePass-stdDH-sha256kdf-scheme" */
++     939,    /* "dhSinglePass-stdDH-sha384kdf-scheme" */
++     940,    /* "dhSinglePass-stdDH-sha512kdf-scheme" */
++     920,    /* "dhpublicnumber" */
++     382,    /* "directory" */
++     887,    /* "distinguishedName" */
++     892,    /* "dmdName" */
++     174,    /* "dnQualifier" */
++     447,    /* "document" */
++     471,    /* "documentAuthor" */
++     468,    /* "documentIdentifier" */
++     472,    /* "documentLocation" */
++     502,    /* "documentPublisher" */
++     449,    /* "documentSeries" */
++     469,    /* "documentTitle" */
++     470,    /* "documentVersion" */
++     392,    /* "domain" */
++     452,    /* "domainRelatedObject" */
++     802,    /* "dsa_with_SHA224" */
++     803,    /* "dsa_with_SHA256" */
++     791,    /* "ecdsa-with-Recommended" */
++     416,    /* "ecdsa-with-SHA1" */
++     793,    /* "ecdsa-with-SHA224" */
++     794,    /* "ecdsa-with-SHA256" */
++     795,    /* "ecdsa-with-SHA384" */
++     796,    /* "ecdsa-with-SHA512" */
++     792,    /* "ecdsa-with-Specified" */
++      48,    /* "emailAddress" */
++     132,    /* "emailProtection" */
++     885,    /* "enhancedSearchGuide" */
++     389,    /* "enterprises" */
++     384,    /* "experimental" */
++     172,    /* "extReq" */
++      56,    /* "extendedCertificateAttributes" */
++     126,    /* "extendedKeyUsage" */
++     372,    /* "extendedStatus" */
++     867,    /* "facsimileTelephoneNumber" */
++     462,    /* "favouriteDrink" */
++     857,    /* "freshestCRL" */
++     453,    /* "friendlyCountry" */
++     490,    /* "friendlyCountryName" */
++     156,    /* "friendlyName" */
++     509,    /* "generationQualifier" */
++     815,    /* "gost-mac" */
++     976,    /* "gost-mac-12" */
++     811,    /* "gost2001" */
++     851,    /* "gost2001cc" */
++     979,    /* "gost2012_256" */
++     980,    /* "gost2012_512" */
++     813,    /* "gost89" */
++    1009,    /* "gost89-cbc" */
++     814,    /* "gost89-cnt" */
++     975,    /* "gost89-cnt-12" */
++    1011,    /* "gost89-ctr" */
++    1010,    /* "gost89-ecb" */
++     812,    /* "gost94" */
++     850,    /* "gost94cc" */
++    1015,    /* "grasshopper-cbc" */
++    1016,    /* "grasshopper-cfb" */
++    1013,    /* "grasshopper-ctr" */
++    1012,    /* "grasshopper-ecb" */
++    1017,    /* "grasshopper-mac" */
++    1014,    /* "grasshopper-ofb" */
++     797,    /* "hmacWithMD5" */
++     163,    /* "hmacWithSHA1" */
++     798,    /* "hmacWithSHA224" */
++     799,    /* "hmacWithSHA256" */
++     800,    /* "hmacWithSHA384" */
++     801,    /* "hmacWithSHA512" */
++     432,    /* "holdInstructionCallIssuer" */
++     430,    /* "holdInstructionCode" */
++     431,    /* "holdInstructionNone" */
++     433,    /* "holdInstructionReject" */
++     486,    /* "homePostalAddress" */
++     473,    /* "homeTelephoneNumber" */
++     466,    /* "host" */
++     889,    /* "houseIdentifier" */
++     442,    /* "iA5StringSyntax" */
++     783,    /* "id-DHBasedMac" */
++     824,    /* "id-Gost28147-89-CryptoPro-A-ParamSet" */
++     825,    /* "id-Gost28147-89-CryptoPro-B-ParamSet" */
++     826,    /* "id-Gost28147-89-CryptoPro-C-ParamSet" */
++     827,    /* "id-Gost28147-89-CryptoPro-D-ParamSet" */
++     819,    /* "id-Gost28147-89-CryptoPro-KeyMeshing" */
++     829,    /* "id-Gost28147-89-CryptoPro-Oscar-1-0-ParamSet" */
++     828,    /* "id-Gost28147-89-CryptoPro-Oscar-1-1-ParamSet" */
++     830,    /* "id-Gost28147-89-CryptoPro-RIC-1-ParamSet" */
++     820,    /* "id-Gost28147-89-None-KeyMeshing" */
++     823,    /* "id-Gost28147-89-TestParamSet" */
++     849,    /* "id-Gost28147-89-cc" */
++     840,    /* "id-GostR3410-2001-CryptoPro-A-ParamSet" */
++     841,    /* "id-GostR3410-2001-CryptoPro-B-ParamSet" */
++     842,    /* "id-GostR3410-2001-CryptoPro-C-ParamSet" */
++     843,    /* "id-GostR3410-2001-CryptoPro-XchA-ParamSet" */
++     844,    /* "id-GostR3410-2001-CryptoPro-XchB-ParamSet" */
++     854,    /* "id-GostR3410-2001-ParamSet-cc" */
++     839,    /* "id-GostR3410-2001-TestParamSet" */
++     817,    /* "id-GostR3410-2001DH" */
++     832,    /* "id-GostR3410-94-CryptoPro-A-ParamSet" */
++     833,    /* "id-GostR3410-94-CryptoPro-B-ParamSet" */
++     834,    /* "id-GostR3410-94-CryptoPro-C-ParamSet" */
++     835,    /* "id-GostR3410-94-CryptoPro-D-ParamSet" */
++     836,    /* "id-GostR3410-94-CryptoPro-XchA-ParamSet" */
++     837,    /* "id-GostR3410-94-CryptoPro-XchB-ParamSet" */
++     838,    /* "id-GostR3410-94-CryptoPro-XchC-ParamSet" */
++     831,    /* "id-GostR3410-94-TestParamSet" */
++     845,    /* "id-GostR3410-94-a" */
++     846,    /* "id-GostR3410-94-aBis" */
++     847,    /* "id-GostR3410-94-b" */
++     848,    /* "id-GostR3410-94-bBis" */
++     818,    /* "id-GostR3410-94DH" */
++     822,    /* "id-GostR3411-94-CryptoProParamSet" */
++     821,    /* "id-GostR3411-94-TestParamSet" */
++     807,    /* "id-GostR3411-94-with-GostR3410-2001" */
++     853,    /* "id-GostR3411-94-with-GostR3410-2001-cc" */
++     808,    /* "id-GostR3411-94-with-GostR3410-94" */
++     852,    /* "id-GostR3411-94-with-GostR3410-94-cc" */
++     810,    /* "id-HMACGostR3411-94" */
++     782,    /* "id-PasswordBasedMAC" */
++     266,    /* "id-aca" */
++     355,    /* "id-aca-accessIdentity" */
++     354,    /* "id-aca-authenticationInfo" */
++     356,    /* "id-aca-chargingIdentity" */
++     399,    /* "id-aca-encAttrs" */
++     357,    /* "id-aca-group" */
++     358,    /* "id-aca-role" */
++     176,    /* "id-ad" */
++     896,    /* "id-aes128-CCM" */
++     895,    /* "id-aes128-GCM" */
++     788,    /* "id-aes128-wrap" */
++     897,    /* "id-aes128-wrap-pad" */
++     899,    /* "id-aes192-CCM" */
++     898,    /* "id-aes192-GCM" */
++     789,    /* "id-aes192-wrap" */
++     900,    /* "id-aes192-wrap-pad" */
++     902,    /* "id-aes256-CCM" */
++     901,    /* "id-aes256-GCM" */
++     790,    /* "id-aes256-wrap" */
++     903,    /* "id-aes256-wrap-pad" */
++     262,    /* "id-alg" */
++     893,    /* "id-alg-PWRI-KEK" */
++     323,    /* "id-alg-des40" */
++     326,    /* "id-alg-dh-pop" */
++     325,    /* "id-alg-dh-sig-hmac-sha1" */
++     324,    /* "id-alg-noSignature" */
++     907,    /* "id-camellia128-wrap" */
++     908,    /* "id-camellia192-wrap" */
++     909,    /* "id-camellia256-wrap" */
++     268,    /* "id-cct" */
++     361,    /* "id-cct-PKIData" */
++     362,    /* "id-cct-PKIResponse" */
++     360,    /* "id-cct-crs" */
++      81,    /* "id-ce" */
++     680,    /* "id-characteristic-two-basis" */
++     263,    /* "id-cmc" */
++     334,    /* "id-cmc-addExtensions" */
++     346,    /* "id-cmc-confirmCertAcceptance" */
++     330,    /* "id-cmc-dataReturn" */
++     336,    /* "id-cmc-decryptedPOP" */
++     335,    /* "id-cmc-encryptedPOP" */
++     339,    /* "id-cmc-getCRL" */
++     338,    /* "id-cmc-getCert" */
++     328,    /* "id-cmc-identification" */
++     329,    /* "id-cmc-identityProof" */
++     337,    /* "id-cmc-lraPOPWitness" */
++     344,    /* "id-cmc-popLinkRandom" */
++     345,    /* "id-cmc-popLinkWitness" */
++     343,    /* "id-cmc-queryPending" */
++     333,    /* "id-cmc-recipientNonce" */
++     341,    /* "id-cmc-regInfo" */
++     342,    /* "id-cmc-responseInfo" */
++     340,    /* "id-cmc-revokeRequest" */
++     332,    /* "id-cmc-senderNonce" */
++     327,    /* "id-cmc-statusInfo" */
++     331,    /* "id-cmc-transactionId" */
++     787,    /* "id-ct-asciiTextWithCRLF" */
++    1060,    /* "id-ct-xml" */
++     408,    /* "id-ecPublicKey" */
++     508,    /* "id-hex-multipart-message" */
++     507,    /* "id-hex-partial-message" */
++     260,    /* "id-it" */
++     302,    /* "id-it-caKeyUpdateInfo" */
++     298,    /* "id-it-caProtEncCert" */
++     311,    /* "id-it-confirmWaitTime" */
++     303,    /* "id-it-currentCRL" */
++     300,    /* "id-it-encKeyPairTypes" */
++     310,    /* "id-it-implicitConfirm" */
++     308,    /* "id-it-keyPairParamRep" */
++     307,    /* "id-it-keyPairParamReq" */
++     312,    /* "id-it-origPKIMessage" */
++     301,    /* "id-it-preferredSymmAlg" */
++     309,    /* "id-it-revPassphrase" */
++     299,    /* "id-it-signKeyPairTypes" */
++     305,    /* "id-it-subscriptionRequest" */
++     306,    /* "id-it-subscriptionResponse" */
++     784,    /* "id-it-suppLangTags" */
++     304,    /* "id-it-unsupportedOIDs" */
++     128,    /* "id-kp" */
++     280,    /* "id-mod-attribute-cert" */
++     274,    /* "id-mod-cmc" */
++     277,    /* "id-mod-cmp" */
++     284,    /* "id-mod-cmp2000" */
++     273,    /* "id-mod-crmf" */
++     283,    /* "id-mod-dvcs" */
++     275,    /* "id-mod-kea-profile-88" */
++     276,    /* "id-mod-kea-profile-93" */
++     282,    /* "id-mod-ocsp" */
++     278,    /* "id-mod-qualified-cert-88" */
++     279,    /* "id-mod-qualified-cert-93" */
++     281,    /* "id-mod-timestamp-protocol" */
++     264,    /* "id-on" */
++     858,    /* "id-on-permanentIdentifier" */
++     347,    /* "id-on-personalData" */
++     265,    /* "id-pda" */
++     352,    /* "id-pda-countryOfCitizenship" */
++     353,    /* "id-pda-countryOfResidence" */
++     348,    /* "id-pda-dateOfBirth" */
++     351,    /* "id-pda-gender" */
++     349,    /* "id-pda-placeOfBirth" */
++     175,    /* "id-pe" */
++    1031,    /* "id-pkinit" */
++     261,    /* "id-pkip" */
++     258,    /* "id-pkix-mod" */
++     269,    /* "id-pkix1-explicit-88" */
++     271,    /* "id-pkix1-explicit-93" */
++     270,    /* "id-pkix1-implicit-88" */
++     272,    /* "id-pkix1-implicit-93" */
++     662,    /* "id-ppl" */
++     664,    /* "id-ppl-anyLanguage" */
++     667,    /* "id-ppl-independent" */
++     665,    /* "id-ppl-inheritAll" */
++     267,    /* "id-qcs" */
++     359,    /* "id-qcs-pkixQCSyntax-v1" */
++     259,    /* "id-qt" */
++     164,    /* "id-qt-cps" */
++     165,    /* "id-qt-unotice" */
++     313,    /* "id-regCtrl" */
++     316,    /* "id-regCtrl-authenticator" */
++     319,    /* "id-regCtrl-oldCertID" */
++     318,    /* "id-regCtrl-pkiArchiveOptions" */
++     317,    /* "id-regCtrl-pkiPublicationInfo" */
++     320,    /* "id-regCtrl-protocolEncrKey" */
++     315,    /* "id-regCtrl-regToken" */
++     314,    /* "id-regInfo" */
++     322,    /* "id-regInfo-certReq" */
++     321,    /* "id-regInfo-utf8Pairs" */
++     973,    /* "id-scrypt" */
++     512,    /* "id-set" */
++     191,    /* "id-smime-aa" */
++     215,    /* "id-smime-aa-contentHint" */
++     218,    /* "id-smime-aa-contentIdentifier" */
++     221,    /* "id-smime-aa-contentReference" */
++     240,    /* "id-smime-aa-dvcs-dvc" */
++     217,    /* "id-smime-aa-encapContentType" */
++     222,    /* "id-smime-aa-encrypKeyPref" */
++     220,    /* "id-smime-aa-equivalentLabels" */
++     232,    /* "id-smime-aa-ets-CertificateRefs" */
++     233,    /* "id-smime-aa-ets-RevocationRefs" */
++     238,    /* "id-smime-aa-ets-archiveTimeStamp" */
++     237,    /* "id-smime-aa-ets-certCRLTimestamp" */
++     234,    /* "id-smime-aa-ets-certValues" */
++     227,    /* "id-smime-aa-ets-commitmentType" */
++     231,    /* "id-smime-aa-ets-contentTimestamp" */
++     236,    /* "id-smime-aa-ets-escTimeStamp" */
++     230,    /* "id-smime-aa-ets-otherSigCert" */
++     235,    /* "id-smime-aa-ets-revocationValues" */
++     226,    /* "id-smime-aa-ets-sigPolicyId" */
++     229,    /* "id-smime-aa-ets-signerAttr" */
++     228,    /* "id-smime-aa-ets-signerLocation" */
++     219,    /* "id-smime-aa-macValue" */
++     214,    /* "id-smime-aa-mlExpandHistory" */
++     216,    /* "id-smime-aa-msgSigDigest" */
++     212,    /* "id-smime-aa-receiptRequest" */
++     213,    /* "id-smime-aa-securityLabel" */
++     239,    /* "id-smime-aa-signatureType" */
++     223,    /* "id-smime-aa-signingCertificate" */
++     224,    /* "id-smime-aa-smimeEncryptCerts" */
++     225,    /* "id-smime-aa-timeStampToken" */
++     192,    /* "id-smime-alg" */
++     243,    /* "id-smime-alg-3DESwrap" */
++     246,    /* "id-smime-alg-CMS3DESwrap" */
++     247,    /* "id-smime-alg-CMSRC2wrap" */
++     245,    /* "id-smime-alg-ESDH" */
++     241,    /* "id-smime-alg-ESDHwith3DES" */
++     242,    /* "id-smime-alg-ESDHwithRC2" */
++     244,    /* "id-smime-alg-RC2wrap" */
++     193,    /* "id-smime-cd" */
++     248,    /* "id-smime-cd-ldap" */
++     190,    /* "id-smime-ct" */
++     210,    /* "id-smime-ct-DVCSRequestData" */
++     211,    /* "id-smime-ct-DVCSResponseData" */
++     208,    /* "id-smime-ct-TDTInfo" */
++     207,    /* "id-smime-ct-TSTInfo" */
++     205,    /* "id-smime-ct-authData" */
++    1059,    /* "id-smime-ct-authEnvelopedData" */
++     786,    /* "id-smime-ct-compressedData" */
++    1058,    /* "id-smime-ct-contentCollection" */
++     209,    /* "id-smime-ct-contentInfo" */
++     206,    /* "id-smime-ct-publishCert" */
++     204,    /* "id-smime-ct-receipt" */
++     195,    /* "id-smime-cti" */
++     255,    /* "id-smime-cti-ets-proofOfApproval" */
++     256,    /* "id-smime-cti-ets-proofOfCreation" */
++     253,    /* "id-smime-cti-ets-proofOfDelivery" */
++     251,    /* "id-smime-cti-ets-proofOfOrigin" */
++     252,    /* "id-smime-cti-ets-proofOfReceipt" */
++     254,    /* "id-smime-cti-ets-proofOfSender" */
++     189,    /* "id-smime-mod" */
++     196,    /* "id-smime-mod-cms" */
++     197,    /* "id-smime-mod-ess" */
++     202,    /* "id-smime-mod-ets-eSigPolicy-88" */
++     203,    /* "id-smime-mod-ets-eSigPolicy-97" */
++     200,    /* "id-smime-mod-ets-eSignature-88" */
++     201,    /* "id-smime-mod-ets-eSignature-97" */
++     199,    /* "id-smime-mod-msg-v3" */
++     198,    /* "id-smime-mod-oid" */
++     194,    /* "id-smime-spq" */
++     250,    /* "id-smime-spq-ets-sqt-unotice" */
++     249,    /* "id-smime-spq-ets-sqt-uri" */
++     974,    /* "id-tc26" */
++     991,    /* "id-tc26-agreement" */
++     992,    /* "id-tc26-agreement-gost-3410-2012-256" */
++     993,    /* "id-tc26-agreement-gost-3410-2012-512" */
++     977,    /* "id-tc26-algorithms" */
++     990,    /* "id-tc26-cipher" */
++    1001,    /* "id-tc26-cipher-constants" */
++     994,    /* "id-tc26-constants" */
++     981,    /* "id-tc26-digest" */
++    1000,    /* "id-tc26-digest-constants" */
++    1002,    /* "id-tc26-gost-28147-constants" */
++    1003,    /* "id-tc26-gost-28147-param-Z" */
++     996,    /* "id-tc26-gost-3410-2012-512-constants" */
++     998,    /* "id-tc26-gost-3410-2012-512-paramSetA" */
++     999,    /* "id-tc26-gost-3410-2012-512-paramSetB" */
++     997,    /* "id-tc26-gost-3410-2012-512-paramSetTest" */
++     988,    /* "id-tc26-hmac-gost-3411-2012-256" */
++     989,    /* "id-tc26-hmac-gost-3411-2012-512" */
++     987,    /* "id-tc26-mac" */
++     978,    /* "id-tc26-sign" */
++     995,    /* "id-tc26-sign-constants" */
++     984,    /* "id-tc26-signwithdigest" */
++     985,    /* "id-tc26-signwithdigest-gost3410-2012-256" */
++     986,    /* "id-tc26-signwithdigest-gost3410-2012-512" */
++     676,    /* "identified-organization" */
++     461,    /* "info" */
++     748,    /* "inhibitAnyPolicy" */
++     101,    /* "initials" */
++     647,    /* "international-organizations" */
++     869,    /* "internationaliSDNNumber" */
++     142,    /* "invalidityDate" */
++     294,    /* "ipsecEndSystem" */
++    1022,    /* "ipsecIKE" */
++     295,    /* "ipsecTunnel" */
++     296,    /* "ipsecUser" */
++      86,    /* "issuerAltName" */
++    1008,    /* "issuerSignTool" */
++     770,    /* "issuingDistributionPoint" */
++     492,    /* "janetMailbox" */
++     957,    /* "jurisdictionC" */
++     955,    /* "jurisdictionL" */
++     956,    /* "jurisdictionST" */
++     150,    /* "keyBag" */
++      83,    /* "keyUsage" */
++     477,    /* "lastModifiedBy" */
++     476,    /* "lastModifiedTime" */
++     157,    /* "localKeyID" */
++     480,    /* "mXRecord" */
++     460,    /* "mail" */
++     493,    /* "mailPreferenceOption" */
++     467,    /* "manager" */
++     982,    /* "md_gost12_256" */
++     983,    /* "md_gost12_512" */
++     809,    /* "md_gost94" */
++     875,    /* "member" */
++     182,    /* "member-body" */
++      51,    /* "messageDigest" */
++     383,    /* "mgmt" */
++     504,    /* "mime-mhs" */
++     506,    /* "mime-mhs-bodies" */
++     505,    /* "mime-mhs-headings" */
++     488,    /* "mobileTelephoneNumber" */
++     136,    /* "msCTLSign" */
++     135,    /* "msCodeCom" */
++     134,    /* "msCodeInd" */
++     138,    /* "msEFS" */
++     171,    /* "msExtReq" */
++     137,    /* "msSGC" */
++     648,    /* "msSmartcardLogin" */
++     649,    /* "msUPN" */
++     481,    /* "nSRecord" */
++     173,    /* "name" */
++     666,    /* "nameConstraints" */
++     369,    /* "noCheck" */
++     403,    /* "noRevAvail" */
++      72,    /* "nsBaseUrl" */
++      76,    /* "nsCaPolicyUrl" */
++      74,    /* "nsCaRevocationUrl" */
++      58,    /* "nsCertExt" */
++      79,    /* "nsCertSequence" */
++      71,    /* "nsCertType" */
++      78,    /* "nsComment" */
++      59,    /* "nsDataType" */
++      75,    /* "nsRenewalUrl" */
++      73,    /* "nsRevocationUrl" */
++     139,    /* "nsSGC" */
++      77,    /* "nsSslServerName" */
++     681,    /* "onBasis" */
++     491,    /* "organizationalStatus" */
++     475,    /* "otherMailbox" */
++     876,    /* "owner" */
++     489,    /* "pagerTelephoneNumber" */
++     374,    /* "path" */
++     112,    /* "pbeWithMD5AndCast5CBC" */
++     499,    /* "personalSignature" */
++     487,    /* "personalTitle" */
++     464,    /* "photo" */
++     863,    /* "physicalDeliveryOfficeName" */
++     437,    /* "pilot" */
++     439,    /* "pilotAttributeSyntax" */
++     438,    /* "pilotAttributeType" */
++     479,    /* "pilotAttributeType27" */
++     456,    /* "pilotDSA" */
++     441,    /* "pilotGroups" */
++     444,    /* "pilotObject" */
++     440,    /* "pilotObjectClass" */
++     455,    /* "pilotOrganization" */
++     445,    /* "pilotPerson" */
++    1032,    /* "pkInitClientAuth" */
++    1033,    /* "pkInitKDC" */
++       2,    /* "pkcs" */
++     186,    /* "pkcs1" */
++      27,    /* "pkcs3" */
++     187,    /* "pkcs5" */
++      20,    /* "pkcs7" */
++      21,    /* "pkcs7-data" */
++      25,    /* "pkcs7-digestData" */
++      26,    /* "pkcs7-encryptedData" */
++      23,    /* "pkcs7-envelopedData" */
++      24,    /* "pkcs7-signedAndEnvelopedData" */
++      22,    /* "pkcs7-signedData" */
++     151,    /* "pkcs8ShroudedKeyBag" */
++      47,    /* "pkcs9" */
++     401,    /* "policyConstraints" */
++     747,    /* "policyMappings" */
++     862,    /* "postOfficeBox" */
++     861,    /* "postalAddress" */
++     661,    /* "postalCode" */
++     683,    /* "ppBasis" */
++     872,    /* "preferredDeliveryMethod" */
++     873,    /* "presentationAddress" */
++     816,    /* "prf-gostr3411-94" */
++     406,    /* "prime-field" */
++     409,    /* "prime192v1" */
++     410,    /* "prime192v2" */
++     411,    /* "prime192v3" */
++     412,    /* "prime239v1" */
++     413,    /* "prime239v2" */
++     414,    /* "prime239v3" */
++     415,    /* "prime256v1" */
++     385,    /* "private" */
++      84,    /* "privateKeyUsagePeriod" */
++     886,    /* "protocolInformation" */
++     663,    /* "proxyCertInfo" */
++     510,    /* "pseudonym" */
++     435,    /* "pss" */
++     286,    /* "qcStatements" */
++     457,    /* "qualityLabelledData" */
++     450,    /* "rFC822localPart" */
++     870,    /* "registeredAddress" */
++     400,    /* "role" */
++     877,    /* "roleOccupant" */
++     448,    /* "room" */
++     463,    /* "roomNumber" */
++       6,    /* "rsaEncryption" */
++     644,    /* "rsaOAEPEncryptionSET" */
++     377,    /* "rsaSignature" */
++       1,    /* "rsadsi" */
++     482,    /* "sOARecord" */
++     155,    /* "safeContentsBag" */
++     291,    /* "sbgp-autonomousSysNum" */
++     290,    /* "sbgp-ipAddrBlock" */
++     292,    /* "sbgp-routerIdentifier" */
++     159,    /* "sdsiCertificate" */
++     859,    /* "searchGuide" */
++     704,    /* "secp112r1" */
++     705,    /* "secp112r2" */
++     706,    /* "secp128r1" */
++     707,    /* "secp128r2" */
++     708,    /* "secp160k1" */
++     709,    /* "secp160r1" */
++     710,    /* "secp160r2" */
++     711,    /* "secp192k1" */
++     712,    /* "secp224k1" */
++     713,    /* "secp224r1" */
++     714,    /* "secp256k1" */
++     715,    /* "secp384r1" */
++     716,    /* "secp521r1" */
++     154,    /* "secretBag" */
++     474,    /* "secretary" */
++     717,    /* "sect113r1" */
++     718,    /* "sect113r2" */
++     719,    /* "sect131r1" */
++     720,    /* "sect131r2" */
++     721,    /* "sect163k1" */
++     722,    /* "sect163r1" */
++     723,    /* "sect163r2" */
++     724,    /* "sect193r1" */
++     725,    /* "sect193r2" */
++     726,    /* "sect233k1" */
++     727,    /* "sect233r1" */
++     728,    /* "sect239k1" */
++     729,    /* "sect283k1" */
++     730,    /* "sect283r1" */
++     731,    /* "sect409k1" */
++     732,    /* "sect409r1" */
++     733,    /* "sect571k1" */
++     734,    /* "sect571r1" */
++    1025,    /* "secureShellClient" */
++    1026,    /* "secureShellServer" */
++     386,    /* "security" */
++     878,    /* "seeAlso" */
++     394,    /* "selected-attribute-types" */
++    1029,    /* "sendOwner" */
++    1030,    /* "sendProxiedOwner" */
++    1028,    /* "sendProxiedRouter" */
++    1027,    /* "sendRouter" */
++     105,    /* "serialNumber" */
++     129,    /* "serverAuth" */
++     371,    /* "serviceLocator" */
++     625,    /* "set-addPolicy" */
++     515,    /* "set-attr" */
++     518,    /* "set-brand" */
++     638,    /* "set-brand-AmericanExpress" */
++     637,    /* "set-brand-Diners" */
++     636,    /* "set-brand-IATA-ATA" */
++     639,    /* "set-brand-JCB" */
++     641,    /* "set-brand-MasterCard" */
++     642,    /* "set-brand-Novus" */
++     640,    /* "set-brand-Visa" */
++     517,    /* "set-certExt" */
++     513,    /* "set-ctype" */
++     514,    /* "set-msgExt" */
++     516,    /* "set-policy" */
++     607,    /* "set-policy-root" */
++     624,    /* "set-rootKeyThumb" */
++     620,    /* "setAttr-Cert" */
++     631,    /* "setAttr-GenCryptgrm" */
++     623,    /* "setAttr-IssCap" */
++     628,    /* "setAttr-IssCap-CVM" */
++     630,    /* "setAttr-IssCap-Sig" */
++     629,    /* "setAttr-IssCap-T2" */
++     621,    /* "setAttr-PGWYcap" */
++     635,    /* "setAttr-SecDevSig" */
++     632,    /* "setAttr-T2Enc" */
++     633,    /* "setAttr-T2cleartxt" */
++     634,    /* "setAttr-TokICCsig" */
++     627,    /* "setAttr-Token-B0Prime" */
++     626,    /* "setAttr-Token-EMV" */
++     622,    /* "setAttr-TokenType" */
++     619,    /* "setCext-IssuerCapabilities" */
++     615,    /* "setCext-PGWYcapabilities" */
++     616,    /* "setCext-TokenIdentifier" */
++     618,    /* "setCext-TokenType" */
++     617,    /* "setCext-Track2Data" */
++     611,    /* "setCext-cCertRequired" */
++     609,    /* "setCext-certType" */
++     608,    /* "setCext-hashedRoot" */
++     610,    /* "setCext-merchData" */
++     613,    /* "setCext-setExt" */
++     614,    /* "setCext-setQualf" */
++     612,    /* "setCext-tunneling" */
++     540,    /* "setct-AcqCardCodeMsg" */
++     576,    /* "setct-AcqCardCodeMsgTBE" */
++     570,    /* "setct-AuthReqTBE" */
++     534,    /* "setct-AuthReqTBS" */
++     527,    /* "setct-AuthResBaggage" */
++     571,    /* "setct-AuthResTBE" */
++     572,    /* "setct-AuthResTBEX" */
++     535,    /* "setct-AuthResTBS" */
++     536,    /* "setct-AuthResTBSX" */
++     528,    /* "setct-AuthRevReqBaggage" */
++     577,    /* "setct-AuthRevReqTBE" */
++     541,    /* "setct-AuthRevReqTBS" */
++     529,    /* "setct-AuthRevResBaggage" */
++     542,    /* "setct-AuthRevResData" */
++     578,    /* "setct-AuthRevResTBE" */
++     579,    /* "setct-AuthRevResTBEB" */
++     543,    /* "setct-AuthRevResTBS" */
++     573,    /* "setct-AuthTokenTBE" */
++     537,    /* "setct-AuthTokenTBS" */
++     600,    /* "setct-BCIDistributionTBS" */
++     558,    /* "setct-BatchAdminReqData" */
++     592,    /* "setct-BatchAdminReqTBE" */
++     559,    /* "setct-BatchAdminResData" */
++     593,    /* "setct-BatchAdminResTBE" */
++     599,    /* "setct-CRLNotificationResTBS" */
++     598,    /* "setct-CRLNotificationTBS" */
++     580,    /* "setct-CapReqTBE" */
++     581,    /* "setct-CapReqTBEX" */
++     544,    /* "setct-CapReqTBS" */
++     545,    /* "setct-CapReqTBSX" */
++     546,    /* "setct-CapResData" */
++     582,    /* "setct-CapResTBE" */
++     583,    /* "setct-CapRevReqTBE" */
++     584,    /* "setct-CapRevReqTBEX" */
++     547,    /* "setct-CapRevReqTBS" */
++     548,    /* "setct-CapRevReqTBSX" */
++     549,    /* "setct-CapRevResData" */
++     585,    /* "setct-CapRevResTBE" */
++     538,    /* "setct-CapTokenData" */
++     530,    /* "setct-CapTokenSeq" */
++     574,    /* "setct-CapTokenTBE" */
++     575,    /* "setct-CapTokenTBEX" */
++     539,    /* "setct-CapTokenTBS" */
++     560,    /* "setct-CardCInitResTBS" */
++     566,    /* "setct-CertInqReqTBS" */
++     563,    /* "setct-CertReqData" */
++     595,    /* "setct-CertReqTBE" */
++     596,    /* "setct-CertReqTBEX" */
++     564,    /* "setct-CertReqTBS" */
++     565,    /* "setct-CertResData" */
++     597,    /* "setct-CertResTBE" */
++     586,    /* "setct-CredReqTBE" */
++     587,    /* "setct-CredReqTBEX" */
++     550,    /* "setct-CredReqTBS" */
++     551,    /* "setct-CredReqTBSX" */
++     552,    /* "setct-CredResData" */
++     588,    /* "setct-CredResTBE" */
++     589,    /* "setct-CredRevReqTBE" */
++     590,    /* "setct-CredRevReqTBEX" */
++     553,    /* "setct-CredRevReqTBS" */
++     554,    /* "setct-CredRevReqTBSX" */
++     555,    /* "setct-CredRevResData" */
++     591,    /* "setct-CredRevResTBE" */
++     567,    /* "setct-ErrorTBS" */
++     526,    /* "setct-HODInput" */
++     561,    /* "setct-MeAqCInitResTBS" */
++     522,    /* "setct-OIData" */
++     519,    /* "setct-PANData" */
++     521,    /* "setct-PANOnly" */
++     520,    /* "setct-PANToken" */
++     556,    /* "setct-PCertReqData" */
++     557,    /* "setct-PCertResTBS" */
++     523,    /* "setct-PI" */
++     532,    /* "setct-PI-TBS" */
++     524,    /* "setct-PIData" */
++     525,    /* "setct-PIDataUnsigned" */
++     568,    /* "setct-PIDualSignedTBE" */
++     569,    /* "setct-PIUnsignedTBE" */
++     531,    /* "setct-PInitResData" */
++     533,    /* "setct-PResData" */
++     594,    /* "setct-RegFormReqTBE" */
++     562,    /* "setct-RegFormResTBS" */
++     606,    /* "setext-cv" */
++     601,    /* "setext-genCrypt" */
++     602,    /* "setext-miAuth" */
++     604,    /* "setext-pinAny" */
++     603,    /* "setext-pinSecure" */
++     605,    /* "setext-track2" */
++      52,    /* "signingTime" */
++     454,    /* "simpleSecurityObject" */
++     496,    /* "singleLevelQuality" */
++     387,    /* "snmpv2" */
++     660,    /* "street" */
++      85,    /* "subjectAltName" */
++     769,    /* "subjectDirectoryAttributes" */
++     398,    /* "subjectInfoAccess" */
++      82,    /* "subjectKeyIdentifier" */
++    1007,    /* "subjectSignTool" */
++     498,    /* "subtreeMaximumQuality" */
++     497,    /* "subtreeMinimumQuality" */
++     890,    /* "supportedAlgorithms" */
++     874,    /* "supportedApplicationContext" */
++     402,    /* "targetInformation" */
++     864,    /* "telephoneNumber" */
++     866,    /* "teletexTerminalIdentifier" */
++     865,    /* "telexNumber" */
++     459,    /* "textEncodedORAddress" */
++     293,    /* "textNotice" */
++     133,    /* "timeStamping" */
++     106,    /* "title" */
++    1020,    /* "tlsfeature" */
++     682,    /* "tpBasis" */
++     375,    /* "trustRoot" */
++     436,    /* "ucl" */
++     102,    /* "uid" */
++     888,    /* "uniqueMember" */
++      55,    /* "unstructuredAddress" */
++      49,    /* "unstructuredName" */
++     880,    /* "userCertificate" */
++     465,    /* "userClass" */
++     879,    /* "userPassword" */
++     373,    /* "valid" */
++     678,    /* "wap" */
++     679,    /* "wap-wsg" */
++     735,    /* "wap-wsg-idm-ecid-wtls1" */
++     743,    /* "wap-wsg-idm-ecid-wtls10" */
++     744,    /* "wap-wsg-idm-ecid-wtls11" */
++     745,    /* "wap-wsg-idm-ecid-wtls12" */
++     736,    /* "wap-wsg-idm-ecid-wtls3" */
++     737,    /* "wap-wsg-idm-ecid-wtls4" */
++     738,    /* "wap-wsg-idm-ecid-wtls5" */
++     739,    /* "wap-wsg-idm-ecid-wtls6" */
++     740,    /* "wap-wsg-idm-ecid-wtls7" */
++     741,    /* "wap-wsg-idm-ecid-wtls8" */
++     742,    /* "wap-wsg-idm-ecid-wtls9" */
++     804,    /* "whirlpool" */
++     868,    /* "x121Address" */
++     503,    /* "x500UniqueIdentifier" */
++     158,    /* "x509Certificate" */
++     160,    /* "x509Crl" */
++};
++
++#define NUM_LN 1052
++static const unsigned int ln_objs[NUM_LN] = {
++     363,    /* "AD Time Stamping" */
++     405,    /* "ANSI X9.62" */
++     368,    /* "Acceptable OCSP Responses" */
++     910,    /* "Any Extended Key Usage" */
++     664,    /* "Any language" */
++     177,    /* "Authority Information Access" */
++     365,    /* "Basic OCSP Response" */
++     285,    /* "Biometric Info" */
++     179,    /* "CA Issuers" */
++     785,    /* "CA Repository" */
++     954,    /* "CT Certificate SCTs" */
++     952,    /* "CT Precertificate Poison" */
++     951,    /* "CT Precertificate SCTs" */
++     953,    /* "CT Precertificate Signer" */
++     131,    /* "Code Signing" */
++    1024,    /* "Ctrl/Provision WAP Termination" */
++    1023,    /* "Ctrl/provision WAP Access" */
++     783,    /* "Diffie-Hellman based MAC" */
++     382,    /* "Directory" */
++     392,    /* "Domain" */
++     132,    /* "E-mail Protection" */
++     389,    /* "Enterprises" */
++     384,    /* "Experimental" */
++     372,    /* "Extended OCSP Status" */
++     172,    /* "Extension Request" */
++     813,    /* "GOST 28147-89" */
++     849,    /* "GOST 28147-89 Cryptocom ParamSet" */
++     815,    /* "GOST 28147-89 MAC" */
++    1003,    /* "GOST 28147-89 TC26 parameter set" */
++     851,    /* "GOST 34.10-2001 Cryptocom" */
++     850,    /* "GOST 34.10-94 Cryptocom" */
++     811,    /* "GOST R 34.10-2001" */
++     817,    /* "GOST R 34.10-2001 DH" */
++     998,    /* "GOST R 34.10-2012 (512 bit) ParamSet A" */
++     999,    /* "GOST R 34.10-2012 (512 bit) ParamSet B" */
++     997,    /* "GOST R 34.10-2012 (512 bit) testing parameter set" */
++     979,    /* "GOST R 34.10-2012 with 256 bit modulus" */
++     980,    /* "GOST R 34.10-2012 with 512 bit modulus" */
++     985,    /* "GOST R 34.10-2012 with GOST R 34.11-2012 (256 bit)" */
++     986,    /* "GOST R 34.10-2012 with GOST R 34.11-2012 (512 bit)" */
++     812,    /* "GOST R 34.10-94" */
++     818,    /* "GOST R 34.10-94 DH" */
++     982,    /* "GOST R 34.11-2012 with 256 bit hash" */
++     983,    /* "GOST R 34.11-2012 with 512 bit hash" */
++     809,    /* "GOST R 34.11-94" */
++     816,    /* "GOST R 34.11-94 PRF" */
++     807,    /* "GOST R 34.11-94 with GOST R 34.10-2001" */
++     853,    /* "GOST R 34.11-94 with GOST R 34.10-2001 Cryptocom" */
++     808,    /* "GOST R 34.11-94 with GOST R 34.10-94" */
++     852,    /* "GOST R 34.11-94 with GOST R 34.10-94 Cryptocom" */
++     854,    /* "GOST R 3410-2001 Parameter Set Cryptocom" */
++     988,    /* "HMAC GOST 34.11-2012 256 bit" */
++     989,    /* "HMAC GOST 34.11-2012 512 bit" */
++     810,    /* "HMAC GOST 34.11-94" */
++     432,    /* "Hold Instruction Call Issuer" */
++     430,    /* "Hold Instruction Code" */
++     431,    /* "Hold Instruction None" */
++     433,    /* "Hold Instruction Reject" */
++     634,    /* "ICC or token signature" */
++    1004,    /* "INN" */
++     294,    /* "IPSec End System" */
++     295,    /* "IPSec Tunnel" */
++     296,    /* "IPSec User" */
++     182,    /* "ISO Member Body" */
++     183,    /* "ISO US Member Body" */
++     667,    /* "Independent" */
++     665,    /* "Inherit all" */
++     647,    /* "International Organizations" */
++     142,    /* "Invalidity Date" */
++     504,    /* "MIME MHS" */
++     388,    /* "Mail" */
++     383,    /* "Management" */
++     417,    /* "Microsoft CSP Name" */
++     135,    /* "Microsoft Commercial Code Signing" */
++     138,    /* "Microsoft Encrypted File System" */
++     171,    /* "Microsoft Extension Request" */
++     134,    /* "Microsoft Individual Code Signing" */
++     856,    /* "Microsoft Local Key set" */
++     137,    /* "Microsoft Server Gated Crypto" */
++     648,    /* "Microsoft Smartcardlogin" */
++     136,    /* "Microsoft Trust List Signing" */
++     649,    /* "Microsoft Universal Principal Name" */
++     393,    /* "NULL" */
++     404,    /* "NULL" */
++      72,    /* "Netscape Base Url" */
++      76,    /* "Netscape CA Policy Url" */
++      74,    /* "Netscape CA Revocation Url" */
++      71,    /* "Netscape Cert Type" */
++      58,    /* "Netscape Certificate Extension" */
++      79,    /* "Netscape Certificate Sequence" */
++      78,    /* "Netscape Comment" */
++      57,    /* "Netscape Communications Corp." */
++      59,    /* "Netscape Data Type" */
++      75,    /* "Netscape Renewal Url" */
++      73,    /* "Netscape Revocation Url" */
++      77,    /* "Netscape SSL Server Name" */
++     139,    /* "Netscape Server Gated Crypto" */
++     178,    /* "OCSP" */
++     370,    /* "OCSP Archive Cutoff" */
++     367,    /* "OCSP CRL ID" */
++     369,    /* "OCSP No Check" */
++     366,    /* "OCSP Nonce" */
++     371,    /* "OCSP Service Locator" */
++     180,    /* "OCSP Signing" */
++    1005,    /* "OGRN" */
++     161,    /* "PBES2" */
++      69,    /* "PBKDF2" */
++     162,    /* "PBMAC1" */
++    1032,    /* "PKINIT Client Auth" */
++     127,    /* "PKIX" */
++     858,    /* "Permanent Identifier" */
++     164,    /* "Policy Qualifier CPS" */
++     165,    /* "Policy Qualifier User Notice" */
++     385,    /* "Private" */
++     663,    /* "Proxy Certificate Information" */
++       1,    /* "RSA Data Security, Inc." */
++       2,    /* "RSA Data Security, Inc. PKCS" */
++     188,    /* "S/MIME" */
++     167,    /* "S/MIME Capabilities" */
++    1006,    /* "SNILS" */
++     387,    /* "SNMPv2" */
++    1025,    /* "SSH Client" */
++    1026,    /* "SSH Server" */
++     512,    /* "Secure Electronic Transactions" */
++     386,    /* "Security" */
++     394,    /* "Selected Attribute Types" */
++    1029,    /* "Send Owner" */
++    1030,    /* "Send Proxied Owner" */
++    1028,    /* "Send Proxied Router" */
++    1027,    /* "Send Router" */
++    1033,    /* "Signing KDC Response" */
++    1008,    /* "Signing Tool of Issuer" */
++    1007,    /* "Signing Tool of Subject" */
++     143,    /* "Strong Extranet ID" */
++     398,    /* "Subject Information Access" */
++    1020,    /* "TLS Feature" */
++     130,    /* "TLS Web Client Authentication" */
++     129,    /* "TLS Web Server Authentication" */
++     133,    /* "Time Stamping" */
++     375,    /* "Trust Root" */
++    1034,    /* "X25519" */
++    1035,    /* "X448" */
++      12,    /* "X509" */
++     402,    /* "X509v3 AC Targeting" */
++     746,    /* "X509v3 Any Policy" */
++      90,    /* "X509v3 Authority Key Identifier" */
++      87,    /* "X509v3 Basic Constraints" */
++     103,    /* "X509v3 CRL Distribution Points" */
++      88,    /* "X509v3 CRL Number" */
++     141,    /* "X509v3 CRL Reason Code" */
++     771,    /* "X509v3 Certificate Issuer" */
++      89,    /* "X509v3 Certificate Policies" */
++     140,    /* "X509v3 Delta CRL Indicator" */
++     126,    /* "X509v3 Extended Key Usage" */
++     857,    /* "X509v3 Freshest CRL" */
++     748,    /* "X509v3 Inhibit Any Policy" */
++      86,    /* "X509v3 Issuer Alternative Name" */
++     770,    /* "X509v3 Issuing Distribution Point" */
++      83,    /* "X509v3 Key Usage" */
++     666,    /* "X509v3 Name Constraints" */
++     403,    /* "X509v3 No Revocation Available" */
++     401,    /* "X509v3 Policy Constraints" */
++     747,    /* "X509v3 Policy Mappings" */
++      84,    /* "X509v3 Private Key Usage Period" */
++      85,    /* "X509v3 Subject Alternative Name" */
++     769,    /* "X509v3 Subject Directory Attributes" */
++      82,    /* "X509v3 Subject Key Identifier" */
++     920,    /* "X9.42 DH" */
++     184,    /* "X9.57" */
++     185,    /* "X9.57 CM ?" */
++     478,    /* "aRecord" */
++     289,    /* "aaControls" */
++     287,    /* "ac-auditEntity" */
++     397,    /* "ac-proxying" */
++     288,    /* "ac-targeting" */
++     446,    /* "account" */
++     364,    /* "ad dvcs" */
++     606,    /* "additional verification" */
++     419,    /* "aes-128-cbc" */
++     916,    /* "aes-128-cbc-hmac-sha1" */
++     948,    /* "aes-128-cbc-hmac-sha256" */
++     896,    /* "aes-128-ccm" */
++     421,    /* "aes-128-cfb" */
++     650,    /* "aes-128-cfb1" */
++     653,    /* "aes-128-cfb8" */
++     904,    /* "aes-128-ctr" */
++     418,    /* "aes-128-ecb" */
++     895,    /* "aes-128-gcm" */
++     958,    /* "aes-128-ocb" */
++     420,    /* "aes-128-ofb" */
++     913,    /* "aes-128-xts" */
++     423,    /* "aes-192-cbc" */
++     917,    /* "aes-192-cbc-hmac-sha1" */
++     949,    /* "aes-192-cbc-hmac-sha256" */
++     899,    /* "aes-192-ccm" */
++     425,    /* "aes-192-cfb" */
++     651,    /* "aes-192-cfb1" */
++     654,    /* "aes-192-cfb8" */
++     905,    /* "aes-192-ctr" */
++     422,    /* "aes-192-ecb" */
++     898,    /* "aes-192-gcm" */
++     959,    /* "aes-192-ocb" */
++     424,    /* "aes-192-ofb" */
++     427,    /* "aes-256-cbc" */
++     918,    /* "aes-256-cbc-hmac-sha1" */
++     950,    /* "aes-256-cbc-hmac-sha256" */
++     902,    /* "aes-256-ccm" */
++     429,    /* "aes-256-cfb" */
++     652,    /* "aes-256-cfb1" */
++     655,    /* "aes-256-cfb8" */
++     906,    /* "aes-256-ctr" */
++     426,    /* "aes-256-ecb" */
++     901,    /* "aes-256-gcm" */
++     960,    /* "aes-256-ocb" */
++     428,    /* "aes-256-ofb" */
++     914,    /* "aes-256-xts" */
++     376,    /* "algorithm" */
++     484,    /* "associatedDomain" */
++     485,    /* "associatedName" */
++     501,    /* "audio" */
++    1049,    /* "auth-dss" */
++    1047,    /* "auth-ecdsa" */
++    1050,    /* "auth-gost01" */
++    1051,    /* "auth-gost12" */
++    1053,    /* "auth-null" */
++    1048,    /* "auth-psk" */
++    1046,    /* "auth-rsa" */
++    1052,    /* "auth-srp" */
++     882,    /* "authorityRevocationList" */
++      91,    /* "bf-cbc" */
++      93,    /* "bf-cfb" */
++      92,    /* "bf-ecb" */
++      94,    /* "bf-ofb" */
++    1056,    /* "blake2b512" */
++    1057,    /* "blake2s256" */
++     921,    /* "brainpoolP160r1" */
++     922,    /* "brainpoolP160t1" */
++     923,    /* "brainpoolP192r1" */
++     924,    /* "brainpoolP192t1" */
++     925,    /* "brainpoolP224r1" */
++     926,    /* "brainpoolP224t1" */
++     927,    /* "brainpoolP256r1" */
++     928,    /* "brainpoolP256t1" */
++     929,    /* "brainpoolP320r1" */
++     930,    /* "brainpoolP320t1" */
++     931,    /* "brainpoolP384r1" */
++     932,    /* "brainpoolP384t1" */
++     933,    /* "brainpoolP512r1" */
++     934,    /* "brainpoolP512t1" */
++     494,    /* "buildingName" */
++     860,    /* "businessCategory" */
++     691,    /* "c2onb191v4" */
++     692,    /* "c2onb191v5" */
++     697,    /* "c2onb239v4" */
++     698,    /* "c2onb239v5" */
++     684,    /* "c2pnb163v1" */
++     685,    /* "c2pnb163v2" */
++     686,    /* "c2pnb163v3" */
++     687,    /* "c2pnb176v1" */
++     693,    /* "c2pnb208w1" */
++     699,    /* "c2pnb272w1" */
++     700,    /* "c2pnb304w1" */
++     702,    /* "c2pnb368w1" */
++     688,    /* "c2tnb191v1" */
++     689,    /* "c2tnb191v2" */
++     690,    /* "c2tnb191v3" */
++     694,    /* "c2tnb239v1" */
++     695,    /* "c2tnb239v2" */
++     696,    /* "c2tnb239v3" */
++     701,    /* "c2tnb359v1" */
++     703,    /* "c2tnb431r1" */
++     881,    /* "cACertificate" */
++     483,    /* "cNAMERecord" */
++     751,    /* "camellia-128-cbc" */
++     962,    /* "camellia-128-ccm" */
++     757,    /* "camellia-128-cfb" */
++     760,    /* "camellia-128-cfb1" */
++     763,    /* "camellia-128-cfb8" */
++     964,    /* "camellia-128-cmac" */
++     963,    /* "camellia-128-ctr" */
++     754,    /* "camellia-128-ecb" */
++     961,    /* "camellia-128-gcm" */
++     766,    /* "camellia-128-ofb" */
++     752,    /* "camellia-192-cbc" */
++     966,    /* "camellia-192-ccm" */
++     758,    /* "camellia-192-cfb" */
++     761,    /* "camellia-192-cfb1" */
++     764,    /* "camellia-192-cfb8" */
++     968,    /* "camellia-192-cmac" */
++     967,    /* "camellia-192-ctr" */
++     755,    /* "camellia-192-ecb" */
++     965,    /* "camellia-192-gcm" */
++     767,    /* "camellia-192-ofb" */
++     753,    /* "camellia-256-cbc" */
++     970,    /* "camellia-256-ccm" */
++     759,    /* "camellia-256-cfb" */
++     762,    /* "camellia-256-cfb1" */
++     765,    /* "camellia-256-cfb8" */
++     972,    /* "camellia-256-cmac" */
++     971,    /* "camellia-256-ctr" */
++     756,    /* "camellia-256-ecb" */
++     969,    /* "camellia-256-gcm" */
++     768,    /* "camellia-256-ofb" */
++     443,    /* "caseIgnoreIA5StringSyntax" */
++     108,    /* "cast5-cbc" */
++     110,    /* "cast5-cfb" */
++     109,    /* "cast5-ecb" */
++     111,    /* "cast5-ofb" */
++     152,    /* "certBag" */
++     677,    /* "certicom-arc" */
++     517,    /* "certificate extensions" */
++     883,    /* "certificateRevocationList" */
++    1019,    /* "chacha20" */
++    1018,    /* "chacha20-poly1305" */
++      54,    /* "challengePassword" */
++     407,    /* "characteristic-two-field" */
++     395,    /* "clearance" */
++     633,    /* "cleartext track 2" */
++     894,    /* "cmac" */
++      13,    /* "commonName" */
++     513,    /* "content types" */
++      50,    /* "contentType" */
++      53,    /* "countersignature" */
++      14,    /* "countryName" */
++     153,    /* "crlBag" */
++     884,    /* "crossCertificatePair" */
++     806,    /* "cryptocom" */
++     805,    /* "cryptopro" */
++     500,    /* "dITRedirect" */
++     451,    /* "dNSDomain" */
++     495,    /* "dSAQuality" */
++     434,    /* "data" */
++     390,    /* "dcObject" */
++     891,    /* "deltaRevocationList" */
++      31,    /* "des-cbc" */
++     643,    /* "des-cdmf" */
++      30,    /* "des-cfb" */
++     656,    /* "des-cfb1" */
++     657,    /* "des-cfb8" */
++      29,    /* "des-ecb" */
++      32,    /* "des-ede" */
++      43,    /* "des-ede-cbc" */
++      60,    /* "des-ede-cfb" */
++      62,    /* "des-ede-ofb" */
++      33,    /* "des-ede3" */
++      44,    /* "des-ede3-cbc" */
++      61,    /* "des-ede3-cfb" */
++     658,    /* "des-ede3-cfb1" */
++     659,    /* "des-ede3-cfb8" */
++      63,    /* "des-ede3-ofb" */
++      45,    /* "des-ofb" */
++     107,    /* "description" */
++     871,    /* "destinationIndicator" */
++      80,    /* "desx-cbc" */
++     947,    /* "dh-cofactor-kdf" */
++     946,    /* "dh-std-kdf" */
++      28,    /* "dhKeyAgreement" */
++     941,    /* "dhSinglePass-cofactorDH-sha1kdf-scheme" */
++     942,    /* "dhSinglePass-cofactorDH-sha224kdf-scheme" */
++     943,    /* "dhSinglePass-cofactorDH-sha256kdf-scheme" */
++     944,    /* "dhSinglePass-cofactorDH-sha384kdf-scheme" */
++     945,    /* "dhSinglePass-cofactorDH-sha512kdf-scheme" */
++     936,    /* "dhSinglePass-stdDH-sha1kdf-scheme" */
++     937,    /* "dhSinglePass-stdDH-sha224kdf-scheme" */
++     938,    /* "dhSinglePass-stdDH-sha256kdf-scheme" */
++     939,    /* "dhSinglePass-stdDH-sha384kdf-scheme" */
++     940,    /* "dhSinglePass-stdDH-sha512kdf-scheme" */
++      11,    /* "directory services (X.500)" */
++     378,    /* "directory services - algorithms" */
++     887,    /* "distinguishedName" */
++     892,    /* "dmdName" */
++     174,    /* "dnQualifier" */
++     447,    /* "document" */
++     471,    /* "documentAuthor" */
++     468,    /* "documentIdentifier" */
++     472,    /* "documentLocation" */
++     502,    /* "documentPublisher" */
++     449,    /* "documentSeries" */
++     469,    /* "documentTitle" */
++     470,    /* "documentVersion" */
++     380,    /* "dod" */
++     391,    /* "domainComponent" */
++     452,    /* "domainRelatedObject" */
++     116,    /* "dsaEncryption" */
++      67,    /* "dsaEncryption-old" */
++      66,    /* "dsaWithSHA" */
++     113,    /* "dsaWithSHA1" */
++      70,    /* "dsaWithSHA1-old" */
++     802,    /* "dsa_with_SHA224" */
++     803,    /* "dsa_with_SHA256" */
++     297,    /* "dvcs" */
++     791,    /* "ecdsa-with-Recommended" */
++     416,    /* "ecdsa-with-SHA1" */
++     793,    /* "ecdsa-with-SHA224" */
++     794,    /* "ecdsa-with-SHA256" */
++     795,    /* "ecdsa-with-SHA384" */
++     796,    /* "ecdsa-with-SHA512" */
++     792,    /* "ecdsa-with-Specified" */
++      48,    /* "emailAddress" */
++     632,    /* "encrypted track 2" */
++     885,    /* "enhancedSearchGuide" */
++      56,    /* "extendedCertificateAttributes" */
++     867,    /* "facsimileTelephoneNumber" */
++     462,    /* "favouriteDrink" */
++     453,    /* "friendlyCountry" */
++     490,    /* "friendlyCountryName" */
++     156,    /* "friendlyName" */
++     631,    /* "generate cryptogram" */
++     509,    /* "generationQualifier" */
++     601,    /* "generic cryptogram" */
++      99,    /* "givenName" */
++     976,    /* "gost-mac-12" */
++    1009,    /* "gost89-cbc" */
++     814,    /* "gost89-cnt" */
++     975,    /* "gost89-cnt-12" */
++    1011,    /* "gost89-ctr" */
++    1010,    /* "gost89-ecb" */
++    1015,    /* "grasshopper-cbc" */
++    1016,    /* "grasshopper-cfb" */
++    1013,    /* "grasshopper-ctr" */
++    1012,    /* "grasshopper-ecb" */
++    1017,    /* "grasshopper-mac" */
++    1014,    /* "grasshopper-ofb" */
++    1036,    /* "hkdf" */
++     855,    /* "hmac" */
++     780,    /* "hmac-md5" */
++     781,    /* "hmac-sha1" */
++     797,    /* "hmacWithMD5" */
++     163,    /* "hmacWithSHA1" */
++     798,    /* "hmacWithSHA224" */
++     799,    /* "hmacWithSHA256" */
++     800,    /* "hmacWithSHA384" */
++     801,    /* "hmacWithSHA512" */
++     486,    /* "homePostalAddress" */
++     473,    /* "homeTelephoneNumber" */
++     466,    /* "host" */
++     889,    /* "houseIdentifier" */
++     442,    /* "iA5StringSyntax" */
++     381,    /* "iana" */
++     824,    /* "id-Gost28147-89-CryptoPro-A-ParamSet" */
++     825,    /* "id-Gost28147-89-CryptoPro-B-ParamSet" */
++     826,    /* "id-Gost28147-89-CryptoPro-C-ParamSet" */
++     827,    /* "id-Gost28147-89-CryptoPro-D-ParamSet" */
++     819,    /* "id-Gost28147-89-CryptoPro-KeyMeshing" */
++     829,    /* "id-Gost28147-89-CryptoPro-Oscar-1-0-ParamSet" */
++     828,    /* "id-Gost28147-89-CryptoPro-Oscar-1-1-ParamSet" */
++     830,    /* "id-Gost28147-89-CryptoPro-RIC-1-ParamSet" */
++     820,    /* "id-Gost28147-89-None-KeyMeshing" */
++     823,    /* "id-Gost28147-89-TestParamSet" */
++     840,    /* "id-GostR3410-2001-CryptoPro-A-ParamSet" */
++     841,    /* "id-GostR3410-2001-CryptoPro-B-ParamSet" */
++     842,    /* "id-GostR3410-2001-CryptoPro-C-ParamSet" */
++     843,    /* "id-GostR3410-2001-CryptoPro-XchA-ParamSet" */
++     844,    /* "id-GostR3410-2001-CryptoPro-XchB-ParamSet" */
++     839,    /* "id-GostR3410-2001-TestParamSet" */
++     832,    /* "id-GostR3410-94-CryptoPro-A-ParamSet" */
++     833,    /* "id-GostR3410-94-CryptoPro-B-ParamSet" */
++     834,    /* "id-GostR3410-94-CryptoPro-C-ParamSet" */
++     835,    /* "id-GostR3410-94-CryptoPro-D-ParamSet" */
++     836,    /* "id-GostR3410-94-CryptoPro-XchA-ParamSet" */
++     837,    /* "id-GostR3410-94-CryptoPro-XchB-ParamSet" */
++     838,    /* "id-GostR3410-94-CryptoPro-XchC-ParamSet" */
++     831,    /* "id-GostR3410-94-TestParamSet" */
++     845,    /* "id-GostR3410-94-a" */
++     846,    /* "id-GostR3410-94-aBis" */
++     847,    /* "id-GostR3410-94-b" */
++     848,    /* "id-GostR3410-94-bBis" */
++     822,    /* "id-GostR3411-94-CryptoProParamSet" */
++     821,    /* "id-GostR3411-94-TestParamSet" */
++     266,    /* "id-aca" */
++     355,    /* "id-aca-accessIdentity" */
++     354,    /* "id-aca-authenticationInfo" */
++     356,    /* "id-aca-chargingIdentity" */
++     399,    /* "id-aca-encAttrs" */
++     357,    /* "id-aca-group" */
++     358,    /* "id-aca-role" */
++     176,    /* "id-ad" */
++     788,    /* "id-aes128-wrap" */
++     897,    /* "id-aes128-wrap-pad" */
++     789,    /* "id-aes192-wrap" */
++     900,    /* "id-aes192-wrap-pad" */
++     790,    /* "id-aes256-wrap" */
++     903,    /* "id-aes256-wrap-pad" */
++     262,    /* "id-alg" */
++     893,    /* "id-alg-PWRI-KEK" */
++     323,    /* "id-alg-des40" */
++     326,    /* "id-alg-dh-pop" */
++     325,    /* "id-alg-dh-sig-hmac-sha1" */
++     324,    /* "id-alg-noSignature" */
++     907,    /* "id-camellia128-wrap" */
++     908,    /* "id-camellia192-wrap" */
++     909,    /* "id-camellia256-wrap" */
++     268,    /* "id-cct" */
++     361,    /* "id-cct-PKIData" */
++     362,    /* "id-cct-PKIResponse" */
++     360,    /* "id-cct-crs" */
++      81,    /* "id-ce" */
++     680,    /* "id-characteristic-two-basis" */
++     263,    /* "id-cmc" */
++     334,    /* "id-cmc-addExtensions" */
++     346,    /* "id-cmc-confirmCertAcceptance" */
++     330,    /* "id-cmc-dataReturn" */
++     336,    /* "id-cmc-decryptedPOP" */
++     335,    /* "id-cmc-encryptedPOP" */
++     339,    /* "id-cmc-getCRL" */
++     338,    /* "id-cmc-getCert" */
++     328,    /* "id-cmc-identification" */
++     329,    /* "id-cmc-identityProof" */
++     337,    /* "id-cmc-lraPOPWitness" */
++     344,    /* "id-cmc-popLinkRandom" */
++     345,    /* "id-cmc-popLinkWitness" */
++     343,    /* "id-cmc-queryPending" */
++     333,    /* "id-cmc-recipientNonce" */
++     341,    /* "id-cmc-regInfo" */
++     342,    /* "id-cmc-responseInfo" */
++     340,    /* "id-cmc-revokeRequest" */
++     332,    /* "id-cmc-senderNonce" */
++     327,    /* "id-cmc-statusInfo" */
++     331,    /* "id-cmc-transactionId" */
++     787,    /* "id-ct-asciiTextWithCRLF" */
++    1060,    /* "id-ct-xml" */
++     408,    /* "id-ecPublicKey" */
++     508,    /* "id-hex-multipart-message" */
++     507,    /* "id-hex-partial-message" */
++     260,    /* "id-it" */
++     302,    /* "id-it-caKeyUpdateInfo" */
++     298,    /* "id-it-caProtEncCert" */
++     311,    /* "id-it-confirmWaitTime" */
++     303,    /* "id-it-currentCRL" */
++     300,    /* "id-it-encKeyPairTypes" */
++     310,    /* "id-it-implicitConfirm" */
++     308,    /* "id-it-keyPairParamRep" */
++     307,    /* "id-it-keyPairParamReq" */
++     312,    /* "id-it-origPKIMessage" */
++     301,    /* "id-it-preferredSymmAlg" */
++     309,    /* "id-it-revPassphrase" */
++     299,    /* "id-it-signKeyPairTypes" */
++     305,    /* "id-it-subscriptionRequest" */
++     306,    /* "id-it-subscriptionResponse" */
++     784,    /* "id-it-suppLangTags" */
++     304,    /* "id-it-unsupportedOIDs" */
++     128,    /* "id-kp" */
++     280,    /* "id-mod-attribute-cert" */
++     274,    /* "id-mod-cmc" */
++     277,    /* "id-mod-cmp" */
++     284,    /* "id-mod-cmp2000" */
++     273,    /* "id-mod-crmf" */
++     283,    /* "id-mod-dvcs" */
++     275,    /* "id-mod-kea-profile-88" */
++     276,    /* "id-mod-kea-profile-93" */
++     282,    /* "id-mod-ocsp" */
++     278,    /* "id-mod-qualified-cert-88" */
++     279,    /* "id-mod-qualified-cert-93" */
++     281,    /* "id-mod-timestamp-protocol" */
++     264,    /* "id-on" */
++     347,    /* "id-on-personalData" */
++     265,    /* "id-pda" */
++     352,    /* "id-pda-countryOfCitizenship" */
++     353,    /* "id-pda-countryOfResidence" */
++     348,    /* "id-pda-dateOfBirth" */
++     351,    /* "id-pda-gender" */
++     349,    /* "id-pda-placeOfBirth" */
++     175,    /* "id-pe" */
++    1031,    /* "id-pkinit" */
++     261,    /* "id-pkip" */
++     258,    /* "id-pkix-mod" */
++     269,    /* "id-pkix1-explicit-88" */
++     271,    /* "id-pkix1-explicit-93" */
++     270,    /* "id-pkix1-implicit-88" */
++     272,    /* "id-pkix1-implicit-93" */
++     662,    /* "id-ppl" */
++     267,    /* "id-qcs" */
++     359,    /* "id-qcs-pkixQCSyntax-v1" */
++     259,    /* "id-qt" */
++     313,    /* "id-regCtrl" */
++     316,    /* "id-regCtrl-authenticator" */
++     319,    /* "id-regCtrl-oldCertID" */
++     318,    /* "id-regCtrl-pkiArchiveOptions" */
++     317,    /* "id-regCtrl-pkiPublicationInfo" */
++     320,    /* "id-regCtrl-protocolEncrKey" */
++     315,    /* "id-regCtrl-regToken" */
++     314,    /* "id-regInfo" */
++     322,    /* "id-regInfo-certReq" */
++     321,    /* "id-regInfo-utf8Pairs" */
++     973,    /* "id-scrypt" */
++     191,    /* "id-smime-aa" */
++     215,    /* "id-smime-aa-contentHint" */
++     218,    /* "id-smime-aa-contentIdentifier" */
++     221,    /* "id-smime-aa-contentReference" */
++     240,    /* "id-smime-aa-dvcs-dvc" */
++     217,    /* "id-smime-aa-encapContentType" */
++     222,    /* "id-smime-aa-encrypKeyPref" */
++     220,    /* "id-smime-aa-equivalentLabels" */
++     232,    /* "id-smime-aa-ets-CertificateRefs" */
++     233,    /* "id-smime-aa-ets-RevocationRefs" */
++     238,    /* "id-smime-aa-ets-archiveTimeStamp" */
++     237,    /* "id-smime-aa-ets-certCRLTimestamp" */
++     234,    /* "id-smime-aa-ets-certValues" */
++     227,    /* "id-smime-aa-ets-commitmentType" */
++     231,    /* "id-smime-aa-ets-contentTimestamp" */
++     236,    /* "id-smime-aa-ets-escTimeStamp" */
++     230,    /* "id-smime-aa-ets-otherSigCert" */
++     235,    /* "id-smime-aa-ets-revocationValues" */
++     226,    /* "id-smime-aa-ets-sigPolicyId" */
++     229,    /* "id-smime-aa-ets-signerAttr" */
++     228,    /* "id-smime-aa-ets-signerLocation" */
++     219,    /* "id-smime-aa-macValue" */
++     214,    /* "id-smime-aa-mlExpandHistory" */
++     216,    /* "id-smime-aa-msgSigDigest" */
++     212,    /* "id-smime-aa-receiptRequest" */
++     213,    /* "id-smime-aa-securityLabel" */
++     239,    /* "id-smime-aa-signatureType" */
++     223,    /* "id-smime-aa-signingCertificate" */
++     224,    /* "id-smime-aa-smimeEncryptCerts" */
++     225,    /* "id-smime-aa-timeStampToken" */
++     192,    /* "id-smime-alg" */
++     243,    /* "id-smime-alg-3DESwrap" */
++     246,    /* "id-smime-alg-CMS3DESwrap" */
++     247,    /* "id-smime-alg-CMSRC2wrap" */
++     245,    /* "id-smime-alg-ESDH" */
++     241,    /* "id-smime-alg-ESDHwith3DES" */
++     242,    /* "id-smime-alg-ESDHwithRC2" */
++     244,    /* "id-smime-alg-RC2wrap" */
++     193,    /* "id-smime-cd" */
++     248,    /* "id-smime-cd-ldap" */
++     190,    /* "id-smime-ct" */
++     210,    /* "id-smime-ct-DVCSRequestData" */
++     211,    /* "id-smime-ct-DVCSResponseData" */
++     208,    /* "id-smime-ct-TDTInfo" */
++     207,    /* "id-smime-ct-TSTInfo" */
++     205,    /* "id-smime-ct-authData" */
++    1059,    /* "id-smime-ct-authEnvelopedData" */
++     786,    /* "id-smime-ct-compressedData" */
++    1058,    /* "id-smime-ct-contentCollection" */
++     209,    /* "id-smime-ct-contentInfo" */
++     206,    /* "id-smime-ct-publishCert" */
++     204,    /* "id-smime-ct-receipt" */
++     195,    /* "id-smime-cti" */
++     255,    /* "id-smime-cti-ets-proofOfApproval" */
++     256,    /* "id-smime-cti-ets-proofOfCreation" */
++     253,    /* "id-smime-cti-ets-proofOfDelivery" */
++     251,    /* "id-smime-cti-ets-proofOfOrigin" */
++     252,    /* "id-smime-cti-ets-proofOfReceipt" */
++     254,    /* "id-smime-cti-ets-proofOfSender" */
++     189,    /* "id-smime-mod" */
++     196,    /* "id-smime-mod-cms" */
++     197,    /* "id-smime-mod-ess" */
++     202,    /* "id-smime-mod-ets-eSigPolicy-88" */
++     203,    /* "id-smime-mod-ets-eSigPolicy-97" */
++     200,    /* "id-smime-mod-ets-eSignature-88" */
++     201,    /* "id-smime-mod-ets-eSignature-97" */
++     199,    /* "id-smime-mod-msg-v3" */
++     198,    /* "id-smime-mod-oid" */
++     194,    /* "id-smime-spq" */
++     250,    /* "id-smime-spq-ets-sqt-unotice" */
++     249,    /* "id-smime-spq-ets-sqt-uri" */
++     974,    /* "id-tc26" */
++     991,    /* "id-tc26-agreement" */
++     992,    /* "id-tc26-agreement-gost-3410-2012-256" */
++     993,    /* "id-tc26-agreement-gost-3410-2012-512" */
++     977,    /* "id-tc26-algorithms" */
++     990,    /* "id-tc26-cipher" */
++    1001,    /* "id-tc26-cipher-constants" */
++     994,    /* "id-tc26-constants" */
++     981,    /* "id-tc26-digest" */
++    1000,    /* "id-tc26-digest-constants" */
++    1002,    /* "id-tc26-gost-28147-constants" */
++     996,    /* "id-tc26-gost-3410-2012-512-constants" */
++     987,    /* "id-tc26-mac" */
++     978,    /* "id-tc26-sign" */
++     995,    /* "id-tc26-sign-constants" */
++     984,    /* "id-tc26-signwithdigest" */
++      34,    /* "idea-cbc" */
++      35,    /* "idea-cfb" */
++      36,    /* "idea-ecb" */
++      46,    /* "idea-ofb" */
++     676,    /* "identified-organization" */
++     461,    /* "info" */
++     101,    /* "initials" */
++     869,    /* "internationaliSDNNumber" */
++    1022,    /* "ipsec Internet Key Exchange" */
++     749,    /* "ipsec3" */
++     750,    /* "ipsec4" */
++     181,    /* "iso" */
++     623,    /* "issuer capabilities" */
++     645,    /* "itu-t" */
++     492,    /* "janetMailbox" */
++     646,    /* "joint-iso-itu-t" */
++     957,    /* "jurisdictionCountryName" */
++     955,    /* "jurisdictionLocalityName" */
++     956,    /* "jurisdictionStateOrProvinceName" */
++     150,    /* "keyBag" */
++     773,    /* "kisa" */
++    1039,    /* "kx-dhe" */
++    1041,    /* "kx-dhe-psk" */
++    1038,    /* "kx-ecdhe" */
++    1040,    /* "kx-ecdhe-psk" */
++    1045,    /* "kx-gost" */
++    1043,    /* "kx-psk" */
++    1037,    /* "kx-rsa" */
++    1042,    /* "kx-rsa-psk" */
++    1044,    /* "kx-srp" */
++     477,    /* "lastModifiedBy" */
++     476,    /* "lastModifiedTime" */
++     157,    /* "localKeyID" */
++      15,    /* "localityName" */
++     480,    /* "mXRecord" */
++     493,    /* "mailPreferenceOption" */
++     467,    /* "manager" */
++       3,    /* "md2" */
++       7,    /* "md2WithRSAEncryption" */
++     257,    /* "md4" */
++     396,    /* "md4WithRSAEncryption" */
++       4,    /* "md5" */
++     114,    /* "md5-sha1" */
++     104,    /* "md5WithRSA" */
++       8,    /* "md5WithRSAEncryption" */
++      95,    /* "mdc2" */
++      96,    /* "mdc2WithRSA" */
++     875,    /* "member" */
++     602,    /* "merchant initiated auth" */
++     514,    /* "message extensions" */
++      51,    /* "messageDigest" */
++     911,    /* "mgf1" */
++     506,    /* "mime-mhs-bodies" */
++     505,    /* "mime-mhs-headings" */
++     488,    /* "mobileTelephoneNumber" */
++     481,    /* "nSRecord" */
++     173,    /* "name" */
++     681,    /* "onBasis" */
++     379,    /* "org" */
++      17,    /* "organizationName" */
++     491,    /* "organizationalStatus" */
++      18,    /* "organizationalUnitName" */
++     475,    /* "otherMailbox" */
++     876,    /* "owner" */
++     935,    /* "pSpecified" */
++     489,    /* "pagerTelephoneNumber" */
++     782,    /* "password based MAC" */
++     374,    /* "path" */
++     621,    /* "payment gateway capabilities" */
++       9,    /* "pbeWithMD2AndDES-CBC" */
++     168,    /* "pbeWithMD2AndRC2-CBC" */
++     112,    /* "pbeWithMD5AndCast5CBC" */
++      10,    /* "pbeWithMD5AndDES-CBC" */
++     169,    /* "pbeWithMD5AndRC2-CBC" */
++     148,    /* "pbeWithSHA1And128BitRC2-CBC" */
++     144,    /* "pbeWithSHA1And128BitRC4" */
++     147,    /* "pbeWithSHA1And2-KeyTripleDES-CBC" */
++     146,    /* "pbeWithSHA1And3-KeyTripleDES-CBC" */
++     149,    /* "pbeWithSHA1And40BitRC2-CBC" */
++     145,    /* "pbeWithSHA1And40BitRC4" */
++     170,    /* "pbeWithSHA1AndDES-CBC" */
++      68,    /* "pbeWithSHA1AndRC2-CBC" */
++     499,    /* "personalSignature" */
++     487,    /* "personalTitle" */
++     464,    /* "photo" */
++     863,    /* "physicalDeliveryOfficeName" */
++     437,    /* "pilot" */
++     439,    /* "pilotAttributeSyntax" */
++     438,    /* "pilotAttributeType" */
++     479,    /* "pilotAttributeType27" */
++     456,    /* "pilotDSA" */
++     441,    /* "pilotGroups" */
++     444,    /* "pilotObject" */
++     440,    /* "pilotObjectClass" */
++     455,    /* "pilotOrganization" */
++     445,    /* "pilotPerson" */
++     186,    /* "pkcs1" */
++      27,    /* "pkcs3" */
++     187,    /* "pkcs5" */
++      20,    /* "pkcs7" */
++      21,    /* "pkcs7-data" */
++      25,    /* "pkcs7-digestData" */
++      26,    /* "pkcs7-encryptedData" */
++      23,    /* "pkcs7-envelopedData" */
++      24,    /* "pkcs7-signedAndEnvelopedData" */
++      22,    /* "pkcs7-signedData" */
++     151,    /* "pkcs8ShroudedKeyBag" */
++      47,    /* "pkcs9" */
++     862,    /* "postOfficeBox" */
++     861,    /* "postalAddress" */
++     661,    /* "postalCode" */
++     683,    /* "ppBasis" */
++     872,    /* "preferredDeliveryMethod" */
++     873,    /* "presentationAddress" */
++     406,    /* "prime-field" */
++     409,    /* "prime192v1" */
++     410,    /* "prime192v2" */
++     411,    /* "prime192v3" */
++     412,    /* "prime239v1" */
++     413,    /* "prime239v2" */
++     414,    /* "prime239v3" */
++     415,    /* "prime256v1" */
++     886,    /* "protocolInformation" */
++     510,    /* "pseudonym" */
++     435,    /* "pss" */
++     286,    /* "qcStatements" */
++     457,    /* "qualityLabelledData" */
++     450,    /* "rFC822localPart" */
++      98,    /* "rc2-40-cbc" */
++     166,    /* "rc2-64-cbc" */
++      37,    /* "rc2-cbc" */
++      39,    /* "rc2-cfb" */
++      38,    /* "rc2-ecb" */
++      40,    /* "rc2-ofb" */
++       5,    /* "rc4" */
++      97,    /* "rc4-40" */
++     915,    /* "rc4-hmac-md5" */
++     120,    /* "rc5-cbc" */
++     122,    /* "rc5-cfb" */
++     121,    /* "rc5-ecb" */
++     123,    /* "rc5-ofb" */
++     870,    /* "registeredAddress" */
++     460,    /* "rfc822Mailbox" */
++     117,    /* "ripemd160" */
++     119,    /* "ripemd160WithRSA" */
++     400,    /* "role" */
++     877,    /* "roleOccupant" */
++     448,    /* "room" */
++     463,    /* "roomNumber" */
++      19,    /* "rsa" */
++       6,    /* "rsaEncryption" */
++     644,    /* "rsaOAEPEncryptionSET" */
++     377,    /* "rsaSignature" */
++     919,    /* "rsaesOaep" */
++     912,    /* "rsassaPss" */
++     482,    /* "sOARecord" */
++     155,    /* "safeContentsBag" */
++     291,    /* "sbgp-autonomousSysNum" */
++     290,    /* "sbgp-ipAddrBlock" */
++     292,    /* "sbgp-routerIdentifier" */
++     159,    /* "sdsiCertificate" */
++     859,    /* "searchGuide" */
++     704,    /* "secp112r1" */
++     705,    /* "secp112r2" */
++     706,    /* "secp128r1" */
++     707,    /* "secp128r2" */
++     708,    /* "secp160k1" */
++     709,    /* "secp160r1" */
++     710,    /* "secp160r2" */
++     711,    /* "secp192k1" */
++     712,    /* "secp224k1" */
++     713,    /* "secp224r1" */
++     714,    /* "secp256k1" */
++     715,    /* "secp384r1" */
++     716,    /* "secp521r1" */
++     154,    /* "secretBag" */
++     474,    /* "secretary" */
++     717,    /* "sect113r1" */
++     718,    /* "sect113r2" */
++     719,    /* "sect131r1" */
++     720,    /* "sect131r2" */
++     721,    /* "sect163k1" */
++     722,    /* "sect163r1" */
++     723,    /* "sect163r2" */
++     724,    /* "sect193r1" */
++     725,    /* "sect193r2" */
++     726,    /* "sect233k1" */
++     727,    /* "sect233r1" */
++     728,    /* "sect239k1" */
++     729,    /* "sect283k1" */
++     730,    /* "sect283r1" */
++     731,    /* "sect409k1" */
++     732,    /* "sect409r1" */
++     733,    /* "sect571k1" */
++     734,    /* "sect571r1" */
++     635,    /* "secure device signature" */
++     878,    /* "seeAlso" */
++     777,    /* "seed-cbc" */
++     779,    /* "seed-cfb" */
++     776,    /* "seed-ecb" */
++     778,    /* "seed-ofb" */
++     105,    /* "serialNumber" */
++     625,    /* "set-addPolicy" */
++     515,    /* "set-attr" */
++     518,    /* "set-brand" */
++     638,    /* "set-brand-AmericanExpress" */
++     637,    /* "set-brand-Diners" */
++     636,    /* "set-brand-IATA-ATA" */
++     639,    /* "set-brand-JCB" */
++     641,    /* "set-brand-MasterCard" */
++     642,    /* "set-brand-Novus" */
++     640,    /* "set-brand-Visa" */
++     516,    /* "set-policy" */
++     607,    /* "set-policy-root" */
++     624,    /* "set-rootKeyThumb" */
++     620,    /* "setAttr-Cert" */
++     628,    /* "setAttr-IssCap-CVM" */
++     630,    /* "setAttr-IssCap-Sig" */
++     629,    /* "setAttr-IssCap-T2" */
++     627,    /* "setAttr-Token-B0Prime" */
++     626,    /* "setAttr-Token-EMV" */
++     622,    /* "setAttr-TokenType" */
++     619,    /* "setCext-IssuerCapabilities" */
++     615,    /* "setCext-PGWYcapabilities" */
++     616,    /* "setCext-TokenIdentifier" */
++     618,    /* "setCext-TokenType" */
++     617,    /* "setCext-Track2Data" */
++     611,    /* "setCext-cCertRequired" */
++     609,    /* "setCext-certType" */
++     608,    /* "setCext-hashedRoot" */
++     610,    /* "setCext-merchData" */
++     613,    /* "setCext-setExt" */
++     614,    /* "setCext-setQualf" */
++     612,    /* "setCext-tunneling" */
++     540,    /* "setct-AcqCardCodeMsg" */
++     576,    /* "setct-AcqCardCodeMsgTBE" */
++     570,    /* "setct-AuthReqTBE" */
++     534,    /* "setct-AuthReqTBS" */
++     527,    /* "setct-AuthResBaggage" */
++     571,    /* "setct-AuthResTBE" */
++     572,    /* "setct-AuthResTBEX" */
++     535,    /* "setct-AuthResTBS" */
++     536,    /* "setct-AuthResTBSX" */
++     528,    /* "setct-AuthRevReqBaggage" */
++     577,    /* "setct-AuthRevReqTBE" */
++     541,    /* "setct-AuthRevReqTBS" */
++     529,    /* "setct-AuthRevResBaggage" */
++     542,    /* "setct-AuthRevResData" */
++     578,    /* "setct-AuthRevResTBE" */
++     579,    /* "setct-AuthRevResTBEB" */
++     543,    /* "setct-AuthRevResTBS" */
++     573,    /* "setct-AuthTokenTBE" */
++     537,    /* "setct-AuthTokenTBS" */
++     600,    /* "setct-BCIDistributionTBS" */
++     558,    /* "setct-BatchAdminReqData" */
++     592,    /* "setct-BatchAdminReqTBE" */
++     559,    /* "setct-BatchAdminResData" */
++     593,    /* "setct-BatchAdminResTBE" */
++     599,    /* "setct-CRLNotificationResTBS" */
++     598,    /* "setct-CRLNotificationTBS" */
++     580,    /* "setct-CapReqTBE" */
++     581,    /* "setct-CapReqTBEX" */
++     544,    /* "setct-CapReqTBS" */
++     545,    /* "setct-CapReqTBSX" */
++     546,    /* "setct-CapResData" */
++     582,    /* "setct-CapResTBE" */
++     583,    /* "setct-CapRevReqTBE" */
++     584,    /* "setct-CapRevReqTBEX" */
++     547,    /* "setct-CapRevReqTBS" */
++     548,    /* "setct-CapRevReqTBSX" */
++     549,    /* "setct-CapRevResData" */
++     585,    /* "setct-CapRevResTBE" */
++     538,    /* "setct-CapTokenData" */
++     530,    /* "setct-CapTokenSeq" */
++     574,    /* "setct-CapTokenTBE" */
++     575,    /* "setct-CapTokenTBEX" */
++     539,    /* "setct-CapTokenTBS" */
++     560,    /* "setct-CardCInitResTBS" */
++     566,    /* "setct-CertInqReqTBS" */
++     563,    /* "setct-CertReqData" */
++     595,    /* "setct-CertReqTBE" */
++     596,    /* "setct-CertReqTBEX" */
++     564,    /* "setct-CertReqTBS" */
++     565,    /* "setct-CertResData" */
++     597,    /* "setct-CertResTBE" */
++     586,    /* "setct-CredReqTBE" */
++     587,    /* "setct-CredReqTBEX" */
++     550,    /* "setct-CredReqTBS" */
++     551,    /* "setct-CredReqTBSX" */
++     552,    /* "setct-CredResData" */
++     588,    /* "setct-CredResTBE" */
++     589,    /* "setct-CredRevReqTBE" */
++     590,    /* "setct-CredRevReqTBEX" */
++     553,    /* "setct-CredRevReqTBS" */
++     554,    /* "setct-CredRevReqTBSX" */
++     555,    /* "setct-CredRevResData" */
++     591,    /* "setct-CredRevResTBE" */
++     567,    /* "setct-ErrorTBS" */
++     526,    /* "setct-HODInput" */
++     561,    /* "setct-MeAqCInitResTBS" */
++     522,    /* "setct-OIData" */
++     519,    /* "setct-PANData" */
++     521,    /* "setct-PANOnly" */
++     520,    /* "setct-PANToken" */
++     556,    /* "setct-PCertReqData" */
++     557,    /* "setct-PCertResTBS" */
++     523,    /* "setct-PI" */
++     532,    /* "setct-PI-TBS" */
++     524,    /* "setct-PIData" */
++     525,    /* "setct-PIDataUnsigned" */
++     568,    /* "setct-PIDualSignedTBE" */
++     569,    /* "setct-PIUnsignedTBE" */
++     531,    /* "setct-PInitResData" */
++     533,    /* "setct-PResData" */
++     594,    /* "setct-RegFormReqTBE" */
++     562,    /* "setct-RegFormResTBS" */
++     604,    /* "setext-pinAny" */
++     603,    /* "setext-pinSecure" */
++     605,    /* "setext-track2" */
++      41,    /* "sha" */
++      64,    /* "sha1" */
++     115,    /* "sha1WithRSA" */
++      65,    /* "sha1WithRSAEncryption" */
++     675,    /* "sha224" */
++     671,    /* "sha224WithRSAEncryption" */
++     672,    /* "sha256" */
++     668,    /* "sha256WithRSAEncryption" */
++     673,    /* "sha384" */
++     669,    /* "sha384WithRSAEncryption" */
++     674,    /* "sha512" */
++     670,    /* "sha512WithRSAEncryption" */
++      42,    /* "shaWithRSAEncryption" */
++      52,    /* "signingTime" */
++     454,    /* "simpleSecurityObject" */
++     496,    /* "singleLevelQuality" */
++      16,    /* "stateOrProvinceName" */
++     660,    /* "streetAddress" */
++     498,    /* "subtreeMaximumQuality" */
++     497,    /* "subtreeMinimumQuality" */
++     890,    /* "supportedAlgorithms" */
++     874,    /* "supportedApplicationContext" */
++     100,    /* "surname" */
++     864,    /* "telephoneNumber" */
++     866,    /* "teletexTerminalIdentifier" */
++     865,    /* "telexNumber" */
++     459,    /* "textEncodedORAddress" */
++     293,    /* "textNotice" */
++     106,    /* "title" */
++    1021,    /* "tls1-prf" */
++     682,    /* "tpBasis" */
++     436,    /* "ucl" */
++       0,    /* "undefined" */
++     102,    /* "uniqueIdentifier" */
++     888,    /* "uniqueMember" */
++      55,    /* "unstructuredAddress" */
++      49,    /* "unstructuredName" */
++     880,    /* "userCertificate" */
++     465,    /* "userClass" */
++     458,    /* "userId" */
++     879,    /* "userPassword" */
++     373,    /* "valid" */
++     678,    /* "wap" */
++     679,    /* "wap-wsg" */
++     735,    /* "wap-wsg-idm-ecid-wtls1" */
++     743,    /* "wap-wsg-idm-ecid-wtls10" */
++     744,    /* "wap-wsg-idm-ecid-wtls11" */
++     745,    /* "wap-wsg-idm-ecid-wtls12" */
++     736,    /* "wap-wsg-idm-ecid-wtls3" */
++     737,    /* "wap-wsg-idm-ecid-wtls4" */
++     738,    /* "wap-wsg-idm-ecid-wtls5" */
++     739,    /* "wap-wsg-idm-ecid-wtls6" */
++     740,    /* "wap-wsg-idm-ecid-wtls7" */
++     741,    /* "wap-wsg-idm-ecid-wtls8" */
++     742,    /* "wap-wsg-idm-ecid-wtls9" */
++     804,    /* "whirlpool" */
++     868,    /* "x121Address" */
++     503,    /* "x500UniqueIdentifier" */
++     158,    /* "x509Certificate" */
++     160,    /* "x509Crl" */
++     125,    /* "zlib compression" */
++};
++
++#define NUM_OBJ 956
++static const unsigned int obj_objs[NUM_OBJ] = {
++       0,    /* OBJ_undef                        0 */
++     181,    /* OBJ_iso                          1 */
++     393,    /* OBJ_joint_iso_ccitt              OBJ_joint_iso_itu_t */
++     404,    /* OBJ_ccitt                        OBJ_itu_t */
++     645,    /* OBJ_itu_t                        0 */
++     646,    /* OBJ_joint_iso_itu_t              2 */
++     434,    /* OBJ_data                         0 9 */
++     182,    /* OBJ_member_body                  1 2 */
++     379,    /* OBJ_org                          1 3 */
++     676,    /* OBJ_identified_organization      1 3 */
++      11,    /* OBJ_X500                         2 5 */
++     647,    /* OBJ_international_organizations  2 23 */
++     380,    /* OBJ_dod                          1 3 6 */
++      12,    /* OBJ_X509                         2 5 4 */
++     378,    /* OBJ_X500algorithms               2 5 8 */
++      81,    /* OBJ_id_ce                        2 5 29 */
++     512,    /* OBJ_id_set                       2 23 42 */
++     678,    /* OBJ_wap                          2 23 43 */
++     435,    /* OBJ_pss                          0 9 2342 */
++     183,    /* OBJ_ISO_US                       1 2 840 */
++     381,    /* OBJ_iana                         1 3 6 1 */
++    1034,    /* OBJ_X25519                       1 3 101 110 */
++    1035,    /* OBJ_X448                         1 3 101 111 */
++     677,    /* OBJ_certicom_arc                 1 3 132 */
++     394,    /* OBJ_selected_attribute_types     2 5 1 5 */
++      13,    /* OBJ_commonName                   2 5 4 3 */
++     100,    /* OBJ_surname                      2 5 4 4 */
++     105,    /* OBJ_serialNumber                 2 5 4 5 */
++      14,    /* OBJ_countryName                  2 5 4 6 */
++      15,    /* OBJ_localityName                 2 5 4 7 */
++      16,    /* OBJ_stateOrProvinceName          2 5 4 8 */
++     660,    /* OBJ_streetAddress                2 5 4 9 */
++      17,    /* OBJ_organizationName             2 5 4 10 */
++      18,    /* OBJ_organizationalUnitName       2 5 4 11 */
++     106,    /* OBJ_title                        2 5 4 12 */
++     107,    /* OBJ_description                  2 5 4 13 */
++     859,    /* OBJ_searchGuide                  2 5 4 14 */
++     860,    /* OBJ_businessCategory             2 5 4 15 */
++     861,    /* OBJ_postalAddress                2 5 4 16 */
++     661,    /* OBJ_postalCode                   2 5 4 17 */
++     862,    /* OBJ_postOfficeBox                2 5 4 18 */
++     863,    /* OBJ_physicalDeliveryOfficeName   2 5 4 19 */
++     864,    /* OBJ_telephoneNumber              2 5 4 20 */
++     865,    /* OBJ_telexNumber                  2 5 4 21 */
++     866,    /* OBJ_teletexTerminalIdentifier    2 5 4 22 */
++     867,    /* OBJ_facsimileTelephoneNumber     2 5 4 23 */
++     868,    /* OBJ_x121Address                  2 5 4 24 */
++     869,    /* OBJ_internationaliSDNNumber      2 5 4 25 */
++     870,    /* OBJ_registeredAddress            2 5 4 26 */
++     871,    /* OBJ_destinationIndicator         2 5 4 27 */
++     872,    /* OBJ_preferredDeliveryMethod      2 5 4 28 */
++     873,    /* OBJ_presentationAddress          2 5 4 29 */
++     874,    /* OBJ_supportedApplicationContext  2 5 4 30 */
++     875,    /* OBJ_member                       2 5 4 31 */
++     876,    /* OBJ_owner                        2 5 4 32 */
++     877,    /* OBJ_roleOccupant                 2 5 4 33 */
++     878,    /* OBJ_seeAlso                      2 5 4 34 */
++     879,    /* OBJ_userPassword                 2 5 4 35 */
++     880,    /* OBJ_userCertificate              2 5 4 36 */
++     881,    /* OBJ_cACertificate                2 5 4 37 */
++     882,    /* OBJ_authorityRevocationList      2 5 4 38 */
++     883,    /* OBJ_certificateRevocationList    2 5 4 39 */
++     884,    /* OBJ_crossCertificatePair         2 5 4 40 */
++     173,    /* OBJ_name                         2 5 4 41 */
++      99,    /* OBJ_givenName                    2 5 4 42 */
++     101,    /* OBJ_initials                     2 5 4 43 */
++     509,    /* OBJ_generationQualifier          2 5 4 44 */
++     503,    /* OBJ_x500UniqueIdentifier         2 5 4 45 */
++     174,    /* OBJ_dnQualifier                  2 5 4 46 */
++     885,    /* OBJ_enhancedSearchGuide          2 5 4 47 */
++     886,    /* OBJ_protocolInformation          2 5 4 48 */
++     887,    /* OBJ_distinguishedName            2 5 4 49 */
++     888,    /* OBJ_uniqueMember                 2 5 4 50 */
++     889,    /* OBJ_houseIdentifier              2 5 4 51 */
++     890,    /* OBJ_supportedAlgorithms          2 5 4 52 */
++     891,    /* OBJ_deltaRevocationList          2 5 4 53 */
++     892,    /* OBJ_dmdName                      2 5 4 54 */
++     510,    /* OBJ_pseudonym                    2 5 4 65 */
++     400,    /* OBJ_role                         2 5 4 72 */
++     769,    /* OBJ_subject_directory_attributes 2 5 29 9 */
++      82,    /* OBJ_subject_key_identifier       2 5 29 14 */
++      83,    /* OBJ_key_usage                    2 5 29 15 */
++      84,    /* OBJ_private_key_usage_period     2 5 29 16 */
++      85,    /* OBJ_subject_alt_name             2 5 29 17 */
++      86,    /* OBJ_issuer_alt_name              2 5 29 18 */
++      87,    /* OBJ_basic_constraints            2 5 29 19 */
++      88,    /* OBJ_crl_number                   2 5 29 20 */
++     141,    /* OBJ_crl_reason                   2 5 29 21 */
++     430,    /* OBJ_hold_instruction_code        2 5 29 23 */
++     142,    /* OBJ_invalidity_date              2 5 29 24 */
++     140,    /* OBJ_delta_crl                    2 5 29 27 */
++     770,    /* OBJ_issuing_distribution_point   2 5 29 28 */
++     771,    /* OBJ_certificate_issuer           2 5 29 29 */
++     666,    /* OBJ_name_constraints             2 5 29 30 */
++     103,    /* OBJ_crl_distribution_points      2 5 29 31 */
++      89,    /* OBJ_certificate_policies         2 5 29 32 */
++     747,    /* OBJ_policy_mappings              2 5 29 33 */
++      90,    /* OBJ_authority_key_identifier     2 5 29 35 */
++     401,    /* OBJ_policy_constraints           2 5 29 36 */
++     126,    /* OBJ_ext_key_usage                2 5 29 37 */
++     857,    /* OBJ_freshest_crl                 2 5 29 46 */
++     748,    /* OBJ_inhibit_any_policy           2 5 29 54 */
++     402,    /* OBJ_target_information           2 5 29 55 */
++     403,    /* OBJ_no_rev_avail                 2 5 29 56 */
++     513,    /* OBJ_set_ctype                    2 23 42 0 */
++     514,    /* OBJ_set_msgExt                   2 23 42 1 */
++     515,    /* OBJ_set_attr                     2 23 42 3 */
++     516,    /* OBJ_set_policy                   2 23 42 5 */
++     517,    /* OBJ_set_certExt                  2 23 42 7 */
++     518,    /* OBJ_set_brand                    2 23 42 8 */
++     679,    /* OBJ_wap_wsg                      2 23 43 1 */
++     382,    /* OBJ_Directory                    1 3 6 1 1 */
++     383,    /* OBJ_Management                   1 3 6 1 2 */
++     384,    /* OBJ_Experimental                 1 3 6 1 3 */
++     385,    /* OBJ_Private                      1 3 6 1 4 */
++     386,    /* OBJ_Security                     1 3 6 1 5 */
++     387,    /* OBJ_SNMPv2                       1 3 6 1 6 */
++     388,    /* OBJ_Mail                         1 3 6 1 7 */
++     376,    /* OBJ_algorithm                    1 3 14 3 2 */
++     395,    /* OBJ_clearance                    2 5 1 5 55 */
++      19,    /* OBJ_rsa                          2 5 8 1 1 */
++      96,    /* OBJ_mdc2WithRSA                  2 5 8 3 100 */
++      95,    /* OBJ_mdc2                         2 5 8 3 101 */
++     746,    /* OBJ_any_policy                   2 5 29 32 0 */
++     910,    /* OBJ_anyExtendedKeyUsage          2 5 29 37 0 */
++     519,    /* OBJ_setct_PANData                2 23 42 0 0 */
++     520,    /* OBJ_setct_PANToken               2 23 42 0 1 */
++     521,    /* OBJ_setct_PANOnly                2 23 42 0 2 */
++     522,    /* OBJ_setct_OIData                 2 23 42 0 3 */
++     523,    /* OBJ_setct_PI                     2 23 42 0 4 */
++     524,    /* OBJ_setct_PIData                 2 23 42 0 5 */
++     525,    /* OBJ_setct_PIDataUnsigned         2 23 42 0 6 */
++     526,    /* OBJ_setct_HODInput               2 23 42 0 7 */
++     527,    /* OBJ_setct_AuthResBaggage         2 23 42 0 8 */
++     528,    /* OBJ_setct_AuthRevReqBaggage      2 23 42 0 9 */
++     529,    /* OBJ_setct_AuthRevResBaggage      2 23 42 0 10 */
++     530,    /* OBJ_setct_CapTokenSeq            2 23 42 0 11 */
++     531,    /* OBJ_setct_PInitResData           2 23 42 0 12 */
++     532,    /* OBJ_setct_PI_TBS                 2 23 42 0 13 */
++     533,    /* OBJ_setct_PResData               2 23 42 0 14 */
++     534,    /* OBJ_setct_AuthReqTBS             2 23 42 0 16 */
++     535,    /* OBJ_setct_AuthResTBS             2 23 42 0 17 */
++     536,    /* OBJ_setct_AuthResTBSX            2 23 42 0 18 */
++     537,    /* OBJ_setct_AuthTokenTBS           2 23 42 0 19 */
++     538,    /* OBJ_setct_CapTokenData           2 23 42 0 20 */
++     539,    /* OBJ_setct_CapTokenTBS            2 23 42 0 21 */
++     540,    /* OBJ_setct_AcqCardCodeMsg         2 23 42 0 22 */
++     541,    /* OBJ_setct_AuthRevReqTBS          2 23 42 0 23 */
++     542,    /* OBJ_setct_AuthRevResData         2 23 42 0 24 */
++     543,    /* OBJ_setct_AuthRevResTBS          2 23 42 0 25 */
++     544,    /* OBJ_setct_CapReqTBS              2 23 42 0 26 */
++     545,    /* OBJ_setct_CapReqTBSX             2 23 42 0 27 */
++     546,    /* OBJ_setct_CapResData             2 23 42 0 28 */
++     547,    /* OBJ_setct_CapRevReqTBS           2 23 42 0 29 */
++     548,    /* OBJ_setct_CapRevReqTBSX          2 23 42 0 30 */
++     549,    /* OBJ_setct_CapRevResData          2 23 42 0 31 */
++     550,    /* OBJ_setct_CredReqTBS             2 23 42 0 32 */
++     551,    /* OBJ_setct_CredReqTBSX            2 23 42 0 33 */
++     552,    /* OBJ_setct_CredResData            2 23 42 0 34 */
++     553,    /* OBJ_setct_CredRevReqTBS          2 23 42 0 35 */
++     554,    /* OBJ_setct_CredRevReqTBSX         2 23 42 0 36 */
++     555,    /* OBJ_setct_CredRevResData         2 23 42 0 37 */
++     556,    /* OBJ_setct_PCertReqData           2 23 42 0 38 */
++     557,    /* OBJ_setct_PCertResTBS            2 23 42 0 39 */
++     558,    /* OBJ_setct_BatchAdminReqData      2 23 42 0 40 */
++     559,    /* OBJ_setct_BatchAdminResData      2 23 42 0 41 */
++     560,    /* OBJ_setct_CardCInitResTBS        2 23 42 0 42 */
++     561,    /* OBJ_setct_MeAqCInitResTBS        2 23 42 0 43 */
++     562,    /* OBJ_setct_RegFormResTBS          2 23 42 0 44 */
++     563,    /* OBJ_setct_CertReqData            2 23 42 0 45 */
++     564,    /* OBJ_setct_CertReqTBS             2 23 42 0 46 */
++     565,    /* OBJ_setct_CertResData            2 23 42 0 47 */
++     566,    /* OBJ_setct_CertInqReqTBS          2 23 42 0 48 */
++     567,    /* OBJ_setct_ErrorTBS               2 23 42 0 49 */
++     568,    /* OBJ_setct_PIDualSignedTBE        2 23 42 0 50 */
++     569,    /* OBJ_setct_PIUnsignedTBE          2 23 42 0 51 */
++     570,    /* OBJ_setct_AuthReqTBE             2 23 42 0 52 */
++     571,    /* OBJ_setct_AuthResTBE             2 23 42 0 53 */
++     572,    /* OBJ_setct_AuthResTBEX            2 23 42 0 54 */
++     573,    /* OBJ_setct_AuthTokenTBE           2 23 42 0 55 */
++     574,    /* OBJ_setct_CapTokenTBE            2 23 42 0 56 */
++     575,    /* OBJ_setct_CapTokenTBEX           2 23 42 0 57 */
++     576,    /* OBJ_setct_AcqCardCodeMsgTBE      2 23 42 0 58 */
++     577,    /* OBJ_setct_AuthRevReqTBE          2 23 42 0 59 */
++     578,    /* OBJ_setct_AuthRevResTBE          2 23 42 0 60 */
++     579,    /* OBJ_setct_AuthRevResTBEB         2 23 42 0 61 */
++     580,    /* OBJ_setct_CapReqTBE              2 23 42 0 62 */
++     581,    /* OBJ_setct_CapReqTBEX             2 23 42 0 63 */
++     582,    /* OBJ_setct_CapResTBE              2 23 42 0 64 */
++     583,    /* OBJ_setct_CapRevReqTBE           2 23 42 0 65 */
++     584,    /* OBJ_setct_CapRevReqTBEX          2 23 42 0 66 */
++     585,    /* OBJ_setct_CapRevResTBE           2 23 42 0 67 */
++     586,    /* OBJ_setct_CredReqTBE             2 23 42 0 68 */
++     587,    /* OBJ_setct_CredReqTBEX            2 23 42 0 69 */
++     588,    /* OBJ_setct_CredResTBE             2 23 42 0 70 */
++     589,    /* OBJ_setct_CredRevReqTBE          2 23 42 0 71 */
++     590,    /* OBJ_setct_CredRevReqTBEX         2 23 42 0 72 */
++     591,    /* OBJ_setct_CredRevResTBE          2 23 42 0 73 */
++     592,    /* OBJ_setct_BatchAdminReqTBE       2 23 42 0 74 */
++     593,    /* OBJ_setct_BatchAdminResTBE       2 23 42 0 75 */
++     594,    /* OBJ_setct_RegFormReqTBE          2 23 42 0 76 */
++     595,    /* OBJ_setct_CertReqTBE             2 23 42 0 77 */
++     596,    /* OBJ_setct_CertReqTBEX            2 23 42 0 78 */
++     597,    /* OBJ_setct_CertResTBE             2 23 42 0 79 */
++     598,    /* OBJ_setct_CRLNotificationTBS     2 23 42 0 80 */
++     599,    /* OBJ_setct_CRLNotificationResTBS  2 23 42 0 81 */
++     600,    /* OBJ_setct_BCIDistributionTBS     2 23 42 0 82 */
++     601,    /* OBJ_setext_genCrypt              2 23 42 1 1 */
++     602,    /* OBJ_setext_miAuth                2 23 42 1 3 */
++     603,    /* OBJ_setext_pinSecure             2 23 42 1 4 */
++     604,    /* OBJ_setext_pinAny                2 23 42 1 5 */
++     605,    /* OBJ_setext_track2                2 23 42 1 7 */
++     606,    /* OBJ_setext_cv                    2 23 42 1 8 */
++     620,    /* OBJ_setAttr_Cert                 2 23 42 3 0 */
++     621,    /* OBJ_setAttr_PGWYcap              2 23 42 3 1 */
++     622,    /* OBJ_setAttr_TokenType            2 23 42 3 2 */
++     623,    /* OBJ_setAttr_IssCap               2 23 42 3 3 */
++     607,    /* OBJ_set_policy_root              2 23 42 5 0 */
++     608,    /* OBJ_setCext_hashedRoot           2 23 42 7 0 */
++     609,    /* OBJ_setCext_certType             2 23 42 7 1 */
++     610,    /* OBJ_setCext_merchData            2 23 42 7 2 */
++     611,    /* OBJ_setCext_cCertRequired        2 23 42 7 3 */
++     612,    /* OBJ_setCext_tunneling            2 23 42 7 4 */
++     613,    /* OBJ_setCext_setExt               2 23 42 7 5 */
++     614,    /* OBJ_setCext_setQualf             2 23 42 7 6 */
++     615,    /* OBJ_setCext_PGWYcapabilities     2 23 42 7 7 */
++     616,    /* OBJ_setCext_TokenIdentifier      2 23 42 7 8 */
++     617,    /* OBJ_setCext_Track2Data           2 23 42 7 9 */
++     618,    /* OBJ_setCext_TokenType            2 23 42 7 10 */
++     619,    /* OBJ_setCext_IssuerCapabilities   2 23 42 7 11 */
++     636,    /* OBJ_set_brand_IATA_ATA           2 23 42 8 1 */
++     640,    /* OBJ_set_brand_Visa               2 23 42 8 4 */
++     641,    /* OBJ_set_brand_MasterCard         2 23 42 8 5 */
++     637,    /* OBJ_set_brand_Diners             2 23 42 8 30 */
++     638,    /* OBJ_set_brand_AmericanExpress    2 23 42 8 34 */
++     639,    /* OBJ_set_brand_JCB                2 23 42 8 35 */
++     805,    /* OBJ_cryptopro                    1 2 643 2 2 */
++     806,    /* OBJ_cryptocom                    1 2 643 2 9 */
++     974,    /* OBJ_id_tc26                      1 2 643 7 1 */
++    1005,    /* OBJ_OGRN                         1 2 643 100 1 */
++    1006,    /* OBJ_SNILS                        1 2 643 100 3 */
++    1007,    /* OBJ_subjectSignTool              1 2 643 100 111 */
++    1008,    /* OBJ_issuerSignTool               1 2 643 100 112 */
++     184,    /* OBJ_X9_57                        1 2 840 10040 */
++     405,    /* OBJ_ansi_X9_62                   1 2 840 10045 */
++     389,    /* OBJ_Enterprises                  1 3 6 1 4 1 */
++     504,    /* OBJ_mime_mhs                     1 3 6 1 7 1 */
++     104,    /* OBJ_md5WithRSA                   1 3 14 3 2 3 */
++      29,    /* OBJ_des_ecb                      1 3 14 3 2 6 */
++      31,    /* OBJ_des_cbc                      1 3 14 3 2 7 */
++      45,    /* OBJ_des_ofb64                    1 3 14 3 2 8 */
++      30,    /* OBJ_des_cfb64                    1 3 14 3 2 9 */
++     377,    /* OBJ_rsaSignature                 1 3 14 3 2 11 */
++      67,    /* OBJ_dsa_2                        1 3 14 3 2 12 */
++      66,    /* OBJ_dsaWithSHA                   1 3 14 3 2 13 */
++      42,    /* OBJ_shaWithRSAEncryption         1 3 14 3 2 15 */
++      32,    /* OBJ_des_ede_ecb                  1 3 14 3 2 17 */
++      41,    /* OBJ_sha                          1 3 14 3 2 18 */
++      64,    /* OBJ_sha1                         1 3 14 3 2 26 */
++      70,    /* OBJ_dsaWithSHA1_2                1 3 14 3 2 27 */
++     115,    /* OBJ_sha1WithRSA                  1 3 14 3 2 29 */
++     117,    /* OBJ_ripemd160                    1 3 36 3 2 1 */
++     143,    /* OBJ_sxnet                        1 3 101 1 4 1 */
++     721,    /* OBJ_sect163k1                    1 3 132 0 1 */
++     722,    /* OBJ_sect163r1                    1 3 132 0 2 */
++     728,    /* OBJ_sect239k1                    1 3 132 0 3 */
++     717,    /* OBJ_sect113r1                    1 3 132 0 4 */
++     718,    /* OBJ_sect113r2                    1 3 132 0 5 */
++     704,    /* OBJ_secp112r1                    1 3 132 0 6 */
++     705,    /* OBJ_secp112r2                    1 3 132 0 7 */
++     709,    /* OBJ_secp160r1                    1 3 132 0 8 */
++     708,    /* OBJ_secp160k1                    1 3 132 0 9 */
++     714,    /* OBJ_secp256k1                    1 3 132 0 10 */
++     723,    /* OBJ_sect163r2                    1 3 132 0 15 */
++     729,    /* OBJ_sect283k1                    1 3 132 0 16 */
++     730,    /* OBJ_sect283r1                    1 3 132 0 17 */
++     719,    /* OBJ_sect131r1                    1 3 132 0 22 */
++     720,    /* OBJ_sect131r2                    1 3 132 0 23 */
++     724,    /* OBJ_sect193r1                    1 3 132 0 24 */
++     725,    /* OBJ_sect193r2                    1 3 132 0 25 */
++     726,    /* OBJ_sect233k1                    1 3 132 0 26 */
++     727,    /* OBJ_sect233r1                    1 3 132 0 27 */
++     706,    /* OBJ_secp128r1                    1 3 132 0 28 */
++     707,    /* OBJ_secp128r2                    1 3 132 0 29 */
++     710,    /* OBJ_secp160r2                    1 3 132 0 30 */
++     711,    /* OBJ_secp192k1                    1 3 132 0 31 */
++     712,    /* OBJ_secp224k1                    1 3 132 0 32 */
++     713,    /* OBJ_secp224r1                    1 3 132 0 33 */
++     715,    /* OBJ_secp384r1                    1 3 132 0 34 */
++     716,    /* OBJ_secp521r1                    1 3 132 0 35 */
++     731,    /* OBJ_sect409k1                    1 3 132 0 36 */
++     732,    /* OBJ_sect409r1                    1 3 132 0 37 */
++     733,    /* OBJ_sect571k1                    1 3 132 0 38 */
++     734,    /* OBJ_sect571r1                    1 3 132 0 39 */
++     624,    /* OBJ_set_rootKeyThumb             2 23 42 3 0 0 */
++     625,    /* OBJ_set_addPolicy                2 23 42 3 0 1 */
++     626,    /* OBJ_setAttr_Token_EMV            2 23 42 3 2 1 */
++     627,    /* OBJ_setAttr_Token_B0Prime        2 23 42 3 2 2 */
++     628,    /* OBJ_setAttr_IssCap_CVM           2 23 42 3 3 3 */
++     629,    /* OBJ_setAttr_IssCap_T2            2 23 42 3 3 4 */
++     630,    /* OBJ_setAttr_IssCap_Sig           2 23 42 3 3 5 */
++     642,    /* OBJ_set_brand_Novus              2 23 42 8 6011 */
++     735,    /* OBJ_wap_wsg_idm_ecid_wtls1       2 23 43 1 4 1 */
++     736,    /* OBJ_wap_wsg_idm_ecid_wtls3       2 23 43 1 4 3 */
++     737,    /* OBJ_wap_wsg_idm_ecid_wtls4       2 23 43 1 4 4 */
++     738,    /* OBJ_wap_wsg_idm_ecid_wtls5       2 23 43 1 4 5 */
++     739,    /* OBJ_wap_wsg_idm_ecid_wtls6       2 23 43 1 4 6 */
++     740,    /* OBJ_wap_wsg_idm_ecid_wtls7       2 23 43 1 4 7 */
++     741,    /* OBJ_wap_wsg_idm_ecid_wtls8       2 23 43 1 4 8 */
++     742,    /* OBJ_wap_wsg_idm_ecid_wtls9       2 23 43 1 4 9 */
++     743,    /* OBJ_wap_wsg_idm_ecid_wtls10      2 23 43 1 4 10 */
++     744,    /* OBJ_wap_wsg_idm_ecid_wtls11      2 23 43 1 4 11 */
++     745,    /* OBJ_wap_wsg_idm_ecid_wtls12      2 23 43 1 4 12 */
++     804,    /* OBJ_whirlpool                    1 0 10118 3 0 55 */
++     773,    /* OBJ_kisa                         1 2 410 200004 */
++     807,    /* OBJ_id_GostR3411_94_with_GostR3410_2001 1 2 643 2 2 3 */
++     808,    /* OBJ_id_GostR3411_94_with_GostR3410_94 1 2 643 2 2 4 */
++     809,    /* OBJ_id_GostR3411_94              1 2 643 2 2 9 */
++     810,    /* OBJ_id_HMACGostR3411_94          1 2 643 2 2 10 */
++     811,    /* OBJ_id_GostR3410_2001            1 2 643 2 2 19 */
++     812,    /* OBJ_id_GostR3410_94              1 2 643 2 2 20 */
++     813,    /* OBJ_id_Gost28147_89              1 2 643 2 2 21 */
++     815,    /* OBJ_id_Gost28147_89_MAC          1 2 643 2 2 22 */
++     816,    /* OBJ_id_GostR3411_94_prf          1 2 643 2 2 23 */
++     817,    /* OBJ_id_GostR3410_2001DH          1 2 643 2 2 98 */
++     818,    /* OBJ_id_GostR3410_94DH            1 2 643 2 2 99 */
++     977,    /* OBJ_id_tc26_algorithms           1 2 643 7 1 1 */
++     994,    /* OBJ_id_tc26_constants            1 2 643 7 1 2 */
++       1,    /* OBJ_rsadsi                       1 2 840 113549 */
++     185,    /* OBJ_X9cm                         1 2 840 10040 4 */
++    1031,    /* OBJ_id_pkinit                    1 3 6 1 5 2 3 */
++     127,    /* OBJ_id_pkix                      1 3 6 1 5 5 7 */
++     505,    /* OBJ_mime_mhs_headings            1 3 6 1 7 1 1 */
++     506,    /* OBJ_mime_mhs_bodies              1 3 6 1 7 1 2 */
++     119,    /* OBJ_ripemd160WithRSA             1 3 36 3 3 1 2 */
++     937,    /* OBJ_dhSinglePass_stdDH_sha224kdf_scheme 1 3 132 1 11 0 */
++     938,    /* OBJ_dhSinglePass_stdDH_sha256kdf_scheme 1 3 132 1 11 1 */
++     939,    /* OBJ_dhSinglePass_stdDH_sha384kdf_scheme 1 3 132 1 11 2 */
++     940,    /* OBJ_dhSinglePass_stdDH_sha512kdf_scheme 1 3 132 1 11 3 */
++     942,    /* OBJ_dhSinglePass_cofactorDH_sha224kdf_scheme 1 3 132 1 14 0 */
++     943,    /* OBJ_dhSinglePass_cofactorDH_sha256kdf_scheme 1 3 132 1 14 1 */
++     944,    /* OBJ_dhSinglePass_cofactorDH_sha384kdf_scheme 1 3 132 1 14 2 */
++     945,    /* OBJ_dhSinglePass_cofactorDH_sha512kdf_scheme 1 3 132 1 14 3 */
++     631,    /* OBJ_setAttr_GenCryptgrm          2 23 42 3 3 3 1 */
++     632,    /* OBJ_setAttr_T2Enc                2 23 42 3 3 4 1 */
++     633,    /* OBJ_setAttr_T2cleartxt           2 23 42 3 3 4 2 */
++     634,    /* OBJ_setAttr_TokICCsig            2 23 42 3 3 5 1 */
++     635,    /* OBJ_setAttr_SecDevSig            2 23 42 3 3 5 2 */
++     436,    /* OBJ_ucl                          0 9 2342 19200300 */
++     820,    /* OBJ_id_Gost28147_89_None_KeyMeshing 1 2 643 2 2 14 0 */
++     819,    /* OBJ_id_Gost28147_89_CryptoPro_KeyMeshing 1 2 643 2 2 14 1 */
++     845,    /* OBJ_id_GostR3410_94_a            1 2 643 2 2 20 1 */
++     846,    /* OBJ_id_GostR3410_94_aBis         1 2 643 2 2 20 2 */
++     847,    /* OBJ_id_GostR3410_94_b            1 2 643 2 2 20 3 */
++     848,    /* OBJ_id_GostR3410_94_bBis         1 2 643 2 2 20 4 */
++     821,    /* OBJ_id_GostR3411_94_TestParamSet 1 2 643 2 2 30 0 */
++     822,    /* OBJ_id_GostR3411_94_CryptoProParamSet 1 2 643 2 2 30 1 */
++     823,    /* OBJ_id_Gost28147_89_TestParamSet 1 2 643 2 2 31 0 */
++     824,    /* OBJ_id_Gost28147_89_CryptoPro_A_ParamSet 1 2 643 2 2 31 1 */
++     825,    /* OBJ_id_Gost28147_89_CryptoPro_B_ParamSet 1 2 643 2 2 31 2 */
++     826,    /* OBJ_id_Gost28147_89_CryptoPro_C_ParamSet 1 2 643 2 2 31 3 */
++     827,    /* OBJ_id_Gost28147_89_CryptoPro_D_ParamSet 1 2 643 2 2 31 4 */
++     828,    /* OBJ_id_Gost28147_89_CryptoPro_Oscar_1_1_ParamSet 1 2 643 2 2 31 5 */
++     829,    /* OBJ_id_Gost28147_89_CryptoPro_Oscar_1_0_ParamSet 1 2 643 2 2 31 6 */
++     830,    /* OBJ_id_Gost28147_89_CryptoPro_RIC_1_ParamSet 1 2 643 2 2 31 7 */
++     831,    /* OBJ_id_GostR3410_94_TestParamSet 1 2 643 2 2 32 0 */
++     832,    /* OBJ_id_GostR3410_94_CryptoPro_A_ParamSet 1 2 643 2 2 32 2 */
++     833,    /* OBJ_id_GostR3410_94_CryptoPro_B_ParamSet 1 2 643 2 2 32 3 */
++     834,    /* OBJ_id_GostR3410_94_CryptoPro_C_ParamSet 1 2 643 2 2 32 4 */
++     835,    /* OBJ_id_GostR3410_94_CryptoPro_D_ParamSet 1 2 643 2 2 32 5 */
++     836,    /* OBJ_id_GostR3410_94_CryptoPro_XchA_ParamSet 1 2 643 2 2 33 1 */
++     837,    /* OBJ_id_GostR3410_94_CryptoPro_XchB_ParamSet 1 2 643 2 2 33 2 */
++     838,    /* OBJ_id_GostR3410_94_CryptoPro_XchC_ParamSet 1 2 643 2 2 33 3 */
++     839,    /* OBJ_id_GostR3410_2001_TestParamSet 1 2 643 2 2 35 0 */
++     840,    /* OBJ_id_GostR3410_2001_CryptoPro_A_ParamSet 1 2 643 2 2 35 1 */
++     841,    /* OBJ_id_GostR3410_2001_CryptoPro_B_ParamSet 1 2 643 2 2 35 2 */
++     842,    /* OBJ_id_GostR3410_2001_CryptoPro_C_ParamSet 1 2 643 2 2 35 3 */
++     843,    /* OBJ_id_GostR3410_2001_CryptoPro_XchA_ParamSet 1 2 643 2 2 36 0 */
++     844,    /* OBJ_id_GostR3410_2001_CryptoPro_XchB_ParamSet 1 2 643 2 2 36 1 */
++     978,    /* OBJ_id_tc26_sign                 1 2 643 7 1 1 1 */
++     981,    /* OBJ_id_tc26_digest               1 2 643 7 1 1 2 */
++     984,    /* OBJ_id_tc26_signwithdigest       1 2 643 7 1 1 3 */
++     987,    /* OBJ_id_tc26_mac                  1 2 643 7 1 1 4 */
++     990,    /* OBJ_id_tc26_cipher               1 2 643 7 1 1 5 */
++     991,    /* OBJ_id_tc26_agreement            1 2 643 7 1 1 6 */
++     995,    /* OBJ_id_tc26_sign_constants       1 2 643 7 1 2 1 */
++    1000,    /* OBJ_id_tc26_digest_constants     1 2 643 7 1 2 2 */
++    1001,    /* OBJ_id_tc26_cipher_constants     1 2 643 7 1 2 5 */
++       2,    /* OBJ_pkcs                         1 2 840 113549 1 */
++     431,    /* OBJ_hold_instruction_none        1 2 840 10040 2 1 */
++     432,    /* OBJ_hold_instruction_call_issuer 1 2 840 10040 2 2 */
++     433,    /* OBJ_hold_instruction_reject      1 2 840 10040 2 3 */
++     116,    /* OBJ_dsa                          1 2 840 10040 4 1 */
++     113,    /* OBJ_dsaWithSHA1                  1 2 840 10040 4 3 */
++     406,    /* OBJ_X9_62_prime_field            1 2 840 10045 1 1 */
++     407,    /* OBJ_X9_62_characteristic_two_field 1 2 840 10045 1 2 */
++     408,    /* OBJ_X9_62_id_ecPublicKey         1 2 840 10045 2 1 */
++     416,    /* OBJ_ecdsa_with_SHA1              1 2 840 10045 4 1 */
++     791,    /* OBJ_ecdsa_with_Recommended       1 2 840 10045 4 2 */
++     792,    /* OBJ_ecdsa_with_Specified         1 2 840 10045 4 3 */
++     920,    /* OBJ_dhpublicnumber               1 2 840 10046 2 1 */
++    1032,    /* OBJ_pkInitClientAuth             1 3 6 1 5 2 3 4 */
++    1033,    /* OBJ_pkInitKDC                    1 3 6 1 5 2 3 5 */
++     258,    /* OBJ_id_pkix_mod                  1 3 6 1 5 5 7 0 */
++     175,    /* OBJ_id_pe                        1 3 6 1 5 5 7 1 */
++     259,    /* OBJ_id_qt                        1 3 6 1 5 5 7 2 */
++     128,    /* OBJ_id_kp                        1 3 6 1 5 5 7 3 */
++     260,    /* OBJ_id_it                        1 3 6 1 5 5 7 4 */
++     261,    /* OBJ_id_pkip                      1 3 6 1 5 5 7 5 */
++     262,    /* OBJ_id_alg                       1 3 6 1 5 5 7 6 */
++     263,    /* OBJ_id_cmc                       1 3 6 1 5 5 7 7 */
++     264,    /* OBJ_id_on                        1 3 6 1 5 5 7 8 */
++     265,    /* OBJ_id_pda                       1 3 6 1 5 5 7 9 */
++     266,    /* OBJ_id_aca                       1 3 6 1 5 5 7 10 */
++     267,    /* OBJ_id_qcs                       1 3 6 1 5 5 7 11 */
++     268,    /* OBJ_id_cct                       1 3 6 1 5 5 7 12 */
++     662,    /* OBJ_id_ppl                       1 3 6 1 5 5 7 21 */
++     176,    /* OBJ_id_ad                        1 3 6 1 5 5 7 48 */
++     507,    /* OBJ_id_hex_partial_message       1 3 6 1 7 1 1 1 */
++     508,    /* OBJ_id_hex_multipart_message     1 3 6 1 7 1 1 2 */
++      57,    /* OBJ_netscape                     2 16 840 1 113730 */
++     754,    /* OBJ_camellia_128_ecb             0 3 4401 5 3 1 9 1 */
++     766,    /* OBJ_camellia_128_ofb128          0 3 4401 5 3 1 9 3 */
++     757,    /* OBJ_camellia_128_cfb128          0 3 4401 5 3 1 9 4 */
++     961,    /* OBJ_camellia_128_gcm             0 3 4401 5 3 1 9 6 */
++     962,    /* OBJ_camellia_128_ccm             0 3 4401 5 3 1 9 7 */
++     963,    /* OBJ_camellia_128_ctr             0 3 4401 5 3 1 9 9 */
++     964,    /* OBJ_camellia_128_cmac            0 3 4401 5 3 1 9 10 */
++     755,    /* OBJ_camellia_192_ecb             0 3 4401 5 3 1 9 21 */
++     767,    /* OBJ_camellia_192_ofb128          0 3 4401 5 3 1 9 23 */
++     758,    /* OBJ_camellia_192_cfb128          0 3 4401 5 3 1 9 24 */
++     965,    /* OBJ_camellia_192_gcm             0 3 4401 5 3 1 9 26 */
++     966,    /* OBJ_camellia_192_ccm             0 3 4401 5 3 1 9 27 */
++     967,    /* OBJ_camellia_192_ctr             0 3 4401 5 3 1 9 29 */
++     968,    /* OBJ_camellia_192_cmac            0 3 4401 5 3 1 9 30 */
++     756,    /* OBJ_camellia_256_ecb             0 3 4401 5 3 1 9 41 */
++     768,    /* OBJ_camellia_256_ofb128          0 3 4401 5 3 1 9 43 */
++     759,    /* OBJ_camellia_256_cfb128          0 3 4401 5 3 1 9 44 */
++     969,    /* OBJ_camellia_256_gcm             0 3 4401 5 3 1 9 46 */
++     970,    /* OBJ_camellia_256_ccm             0 3 4401 5 3 1 9 47 */
++     971,    /* OBJ_camellia_256_ctr             0 3 4401 5 3 1 9 49 */
++     972,    /* OBJ_camellia_256_cmac            0 3 4401 5 3 1 9 50 */
++     437,    /* OBJ_pilot                        0 9 2342 19200300 100 */
++     776,    /* OBJ_seed_ecb                     1 2 410 200004 1 3 */
++     777,    /* OBJ_seed_cbc                     1 2 410 200004 1 4 */
++     779,    /* OBJ_seed_cfb128                  1 2 410 200004 1 5 */
++     778,    /* OBJ_seed_ofb128                  1 2 410 200004 1 6 */
++     852,    /* OBJ_id_GostR3411_94_with_GostR3410_94_cc 1 2 643 2 9 1 3 3 */
++     853,    /* OBJ_id_GostR3411_94_with_GostR3410_2001_cc 1 2 643 2 9 1 3 4 */
++     850,    /* OBJ_id_GostR3410_94_cc           1 2 643 2 9 1 5 3 */
++     851,    /* OBJ_id_GostR3410_2001_cc         1 2 643 2 9 1 5 4 */
++     849,    /* OBJ_id_Gost28147_89_cc           1 2 643 2 9 1 6 1 */
++     854,    /* OBJ_id_GostR3410_2001_ParamSet_cc 1 2 643 2 9 1 8 1 */
++    1004,    /* OBJ_INN                          1 2 643 3 131 1 1 */
++     979,    /* OBJ_id_GostR3410_2012_256        1 2 643 7 1 1 1 1 */
++     980,    /* OBJ_id_GostR3410_2012_512        1 2 643 7 1 1 1 2 */
++     982,    /* OBJ_id_GostR3411_2012_256        1 2 643 7 1 1 2 2 */
++     983,    /* OBJ_id_GostR3411_2012_512        1 2 643 7 1 1 2 3 */
++     985,    /* OBJ_id_tc26_signwithdigest_gost3410_2012_256 1 2 643 7 1 1 3 2 */
++     986,    /* OBJ_id_tc26_signwithdigest_gost3410_2012_512 1 2 643 7 1 1 3 3 */
++     988,    /* OBJ_id_tc26_hmac_gost_3411_2012_256 1 2 643 7 1 1 4 1 */
++     989,    /* OBJ_id_tc26_hmac_gost_3411_2012_512 1 2 643 7 1 1 4 2 */
++     992,    /* OBJ_id_tc26_agreement_gost_3410_2012_256 1 2 643 7 1 1 6 1 */
++     993,    /* OBJ_id_tc26_agreement_gost_3410_2012_512 1 2 643 7 1 1 6 2 */
++     996,    /* OBJ_id_tc26_gost_3410_2012_512_constants 1 2 643 7 1 2 1 2 */
++    1002,    /* OBJ_id_tc26_gost_28147_constants 1 2 643 7 1 2 5 1 */
++     186,    /* OBJ_pkcs1                        1 2 840 113549 1 1 */
++      27,    /* OBJ_pkcs3                        1 2 840 113549 1 3 */
++     187,    /* OBJ_pkcs5                        1 2 840 113549 1 5 */
++      20,    /* OBJ_pkcs7                        1 2 840 113549 1 7 */
++      47,    /* OBJ_pkcs9                        1 2 840 113549 1 9 */
++       3,    /* OBJ_md2                          1 2 840 113549 2 2 */
++     257,    /* OBJ_md4                          1 2 840 113549 2 4 */
++       4,    /* OBJ_md5                          1 2 840 113549 2 5 */
++     797,    /* OBJ_hmacWithMD5                  1 2 840 113549 2 6 */
++     163,    /* OBJ_hmacWithSHA1                 1 2 840 113549 2 7 */
++     798,    /* OBJ_hmacWithSHA224               1 2 840 113549 2 8 */
++     799,    /* OBJ_hmacWithSHA256               1 2 840 113549 2 9 */
++     800,    /* OBJ_hmacWithSHA384               1 2 840 113549 2 10 */
++     801,    /* OBJ_hmacWithSHA512               1 2 840 113549 2 11 */
++      37,    /* OBJ_rc2_cbc                      1 2 840 113549 3 2 */
++       5,    /* OBJ_rc4                          1 2 840 113549 3 4 */
++      44,    /* OBJ_des_ede3_cbc                 1 2 840 113549 3 7 */
++     120,    /* OBJ_rc5_cbc                      1 2 840 113549 3 8 */
++     643,    /* OBJ_des_cdmf                     1 2 840 113549 3 10 */
++     680,    /* OBJ_X9_62_id_characteristic_two_basis 1 2 840 10045 1 2 3 */
++     684,    /* OBJ_X9_62_c2pnb163v1             1 2 840 10045 3 0 1 */
++     685,    /* OBJ_X9_62_c2pnb163v2             1 2 840 10045 3 0 2 */
++     686,    /* OBJ_X9_62_c2pnb163v3             1 2 840 10045 3 0 3 */
++     687,    /* OBJ_X9_62_c2pnb176v1             1 2 840 10045 3 0 4 */
++     688,    /* OBJ_X9_62_c2tnb191v1             1 2 840 10045 3 0 5 */
++     689,    /* OBJ_X9_62_c2tnb191v2             1 2 840 10045 3 0 6 */
++     690,    /* OBJ_X9_62_c2tnb191v3             1 2 840 10045 3 0 7 */
++     691,    /* OBJ_X9_62_c2onb191v4             1 2 840 10045 3 0 8 */
++     692,    /* OBJ_X9_62_c2onb191v5             1 2 840 10045 3 0 9 */
++     693,    /* OBJ_X9_62_c2pnb208w1             1 2 840 10045 3 0 10 */
++     694,    /* OBJ_X9_62_c2tnb239v1             1 2 840 10045 3 0 11 */
++     695,    /* OBJ_X9_62_c2tnb239v2             1 2 840 10045 3 0 12 */
++     696,    /* OBJ_X9_62_c2tnb239v3             1 2 840 10045 3 0 13 */
++     697,    /* OBJ_X9_62_c2onb239v4             1 2 840 10045 3 0 14 */
++     698,    /* OBJ_X9_62_c2onb239v5             1 2 840 10045 3 0 15 */
++     699,    /* OBJ_X9_62_c2pnb272w1             1 2 840 10045 3 0 16 */
++     700,    /* OBJ_X9_62_c2pnb304w1             1 2 840 10045 3 0 17 */
++     701,    /* OBJ_X9_62_c2tnb359v1             1 2 840 10045 3 0 18 */
++     702,    /* OBJ_X9_62_c2pnb368w1             1 2 840 10045 3 0 19 */
++     703,    /* OBJ_X9_62_c2tnb431r1             1 2 840 10045 3 0 20 */
++     409,    /* OBJ_X9_62_prime192v1             1 2 840 10045 3 1 1 */
++     410,    /* OBJ_X9_62_prime192v2             1 2 840 10045 3 1 2 */
++     411,    /* OBJ_X9_62_prime192v3             1 2 840 10045 3 1 3 */
++     412,    /* OBJ_X9_62_prime239v1             1 2 840 10045 3 1 4 */
++     413,    /* OBJ_X9_62_prime239v2             1 2 840 10045 3 1 5 */
++     414,    /* OBJ_X9_62_prime239v3             1 2 840 10045 3 1 6 */
++     415,    /* OBJ_X9_62_prime256v1             1 2 840 10045 3 1 7 */
++     793,    /* OBJ_ecdsa_with_SHA224            1 2 840 10045 4 3 1 */
++     794,    /* OBJ_ecdsa_with_SHA256            1 2 840 10045 4 3 2 */
++     795,    /* OBJ_ecdsa_with_SHA384            1 2 840 10045 4 3 3 */
++     796,    /* OBJ_ecdsa_with_SHA512            1 2 840 10045 4 3 4 */
++     269,    /* OBJ_id_pkix1_explicit_88         1 3 6 1 5 5 7 0 1 */
++     270,    /* OBJ_id_pkix1_implicit_88         1 3 6 1 5 5 7 0 2 */
++     271,    /* OBJ_id_pkix1_explicit_93         1 3 6 1 5 5 7 0 3 */
++     272,    /* OBJ_id_pkix1_implicit_93         1 3 6 1 5 5 7 0 4 */
++     273,    /* OBJ_id_mod_crmf                  1 3 6 1 5 5 7 0 5 */
++     274,    /* OBJ_id_mod_cmc                   1 3 6 1 5 5 7 0 6 */
++     275,    /* OBJ_id_mod_kea_profile_88        1 3 6 1 5 5 7 0 7 */
++     276,    /* OBJ_id_mod_kea_profile_93        1 3 6 1 5 5 7 0 8 */
++     277,    /* OBJ_id_mod_cmp                   1 3 6 1 5 5 7 0 9 */
++     278,    /* OBJ_id_mod_qualified_cert_88     1 3 6 1 5 5 7 0 10 */
++     279,    /* OBJ_id_mod_qualified_cert_93     1 3 6 1 5 5 7 0 11 */
++     280,    /* OBJ_id_mod_attribute_cert        1 3 6 1 5 5 7 0 12 */
++     281,    /* OBJ_id_mod_timestamp_protocol    1 3 6 1 5 5 7 0 13 */
++     282,    /* OBJ_id_mod_ocsp                  1 3 6 1 5 5 7 0 14 */
++     283,    /* OBJ_id_mod_dvcs                  1 3 6 1 5 5 7 0 15 */
++     284,    /* OBJ_id_mod_cmp2000               1 3 6 1 5 5 7 0 16 */
++     177,    /* OBJ_info_access                  1 3 6 1 5 5 7 1 1 */
++     285,    /* OBJ_biometricInfo                1 3 6 1 5 5 7 1 2 */
++     286,    /* OBJ_qcStatements                 1 3 6 1 5 5 7 1 3 */
++     287,    /* OBJ_ac_auditEntity               1 3 6 1 5 5 7 1 4 */
++     288,    /* OBJ_ac_targeting                 1 3 6 1 5 5 7 1 5 */
++     289,    /* OBJ_aaControls                   1 3 6 1 5 5 7 1 6 */
++     290,    /* OBJ_sbgp_ipAddrBlock             1 3 6 1 5 5 7 1 7 */
++     291,    /* OBJ_sbgp_autonomousSysNum        1 3 6 1 5 5 7 1 8 */
++     292,    /* OBJ_sbgp_routerIdentifier        1 3 6 1 5 5 7 1 9 */
++     397,    /* OBJ_ac_proxying                  1 3 6 1 5 5 7 1 10 */
++     398,    /* OBJ_sinfo_access                 1 3 6 1 5 5 7 1 11 */
++     663,    /* OBJ_proxyCertInfo                1 3 6 1 5 5 7 1 14 */
++    1020,    /* OBJ_tlsfeature                   1 3 6 1 5 5 7 1 24 */
++     164,    /* OBJ_id_qt_cps                    1 3 6 1 5 5 7 2 1 */
++     165,    /* OBJ_id_qt_unotice                1 3 6 1 5 5 7 2 2 */
++     293,    /* OBJ_textNotice                   1 3 6 1 5 5 7 2 3 */
++     129,    /* OBJ_server_auth                  1 3 6 1 5 5 7 3 1 */
++     130,    /* OBJ_client_auth                  1 3 6 1 5 5 7 3 2 */
++     131,    /* OBJ_code_sign                    1 3 6 1 5 5 7 3 3 */
++     132,    /* OBJ_email_protect                1 3 6 1 5 5 7 3 4 */
++     294,    /* OBJ_ipsecEndSystem               1 3 6 1 5 5 7 3 5 */
++     295,    /* OBJ_ipsecTunnel                  1 3 6 1 5 5 7 3 6 */
++     296,    /* OBJ_ipsecUser                    1 3 6 1 5 5 7 3 7 */
++     133,    /* OBJ_time_stamp                   1 3 6 1 5 5 7 3 8 */
++     180,    /* OBJ_OCSP_sign                    1 3 6 1 5 5 7 3 9 */
++     297,    /* OBJ_dvcs                         1 3 6 1 5 5 7 3 10 */
++    1022,    /* OBJ_ipsec_IKE                    1 3 6 1 5 5 7 3 17 */
++    1023,    /* OBJ_capwapAC                     1 3 6 1 5 5 7 3 18 */
++    1024,    /* OBJ_capwapWTP                    1 3 6 1 5 5 7 3 19 */
++    1025,    /* OBJ_sshClient                    1 3 6 1 5 5 7 3 21 */
++    1026,    /* OBJ_sshServer                    1 3 6 1 5 5 7 3 22 */
++    1027,    /* OBJ_sendRouter                   1 3 6 1 5 5 7 3 23 */
++    1028,    /* OBJ_sendProxiedRouter            1 3 6 1 5 5 7 3 24 */
++    1029,    /* OBJ_sendOwner                    1 3 6 1 5 5 7 3 25 */
++    1030,    /* OBJ_sendProxiedOwner             1 3 6 1 5 5 7 3 26 */
++     298,    /* OBJ_id_it_caProtEncCert          1 3 6 1 5 5 7 4 1 */
++     299,    /* OBJ_id_it_signKeyPairTypes       1 3 6 1 5 5 7 4 2 */
++     300,    /* OBJ_id_it_encKeyPairTypes        1 3 6 1 5 5 7 4 3 */
++     301,    /* OBJ_id_it_preferredSymmAlg       1 3 6 1 5 5 7 4 4 */
++     302,    /* OBJ_id_it_caKeyUpdateInfo        1 3 6 1 5 5 7 4 5 */
++     303,    /* OBJ_id_it_currentCRL             1 3 6 1 5 5 7 4 6 */
++     304,    /* OBJ_id_it_unsupportedOIDs        1 3 6 1 5 5 7 4 7 */
++     305,    /* OBJ_id_it_subscriptionRequest    1 3 6 1 5 5 7 4 8 */
++     306,    /* OBJ_id_it_subscriptionResponse   1 3 6 1 5 5 7 4 9 */
++     307,    /* OBJ_id_it_keyPairParamReq        1 3 6 1 5 5 7 4 10 */
++     308,    /* OBJ_id_it_keyPairParamRep        1 3 6 1 5 5 7 4 11 */
++     309,    /* OBJ_id_it_revPassphrase          1 3 6 1 5 5 7 4 12 */
++     310,    /* OBJ_id_it_implicitConfirm        1 3 6 1 5 5 7 4 13 */
++     311,    /* OBJ_id_it_confirmWaitTime        1 3 6 1 5 5 7 4 14 */
++     312,    /* OBJ_id_it_origPKIMessage         1 3 6 1 5 5 7 4 15 */
++     784,    /* OBJ_id_it_suppLangTags           1 3 6 1 5 5 7 4 16 */
++     313,    /* OBJ_id_regCtrl                   1 3 6 1 5 5 7 5 1 */
++     314,    /* OBJ_id_regInfo                   1 3 6 1 5 5 7 5 2 */
++     323,    /* OBJ_id_alg_des40                 1 3 6 1 5 5 7 6 1 */
++     324,    /* OBJ_id_alg_noSignature           1 3 6 1 5 5 7 6 2 */
++     325,    /* OBJ_id_alg_dh_sig_hmac_sha1      1 3 6 1 5 5 7 6 3 */
++     326,    /* OBJ_id_alg_dh_pop                1 3 6 1 5 5 7 6 4 */
++     327,    /* OBJ_id_cmc_statusInfo            1 3 6 1 5 5 7 7 1 */
++     328,    /* OBJ_id_cmc_identification        1 3 6 1 5 5 7 7 2 */
++     329,    /* OBJ_id_cmc_identityProof         1 3 6 1 5 5 7 7 3 */
++     330,    /* OBJ_id_cmc_dataReturn            1 3 6 1 5 5 7 7 4 */
++     331,    /* OBJ_id_cmc_transactionId         1 3 6 1 5 5 7 7 5 */
++     332,    /* OBJ_id_cmc_senderNonce           1 3 6 1 5 5 7 7 6 */
++     333,    /* OBJ_id_cmc_recipientNonce        1 3 6 1 5 5 7 7 7 */
++     334,    /* OBJ_id_cmc_addExtensions         1 3 6 1 5 5 7 7 8 */
++     335,    /* OBJ_id_cmc_encryptedPOP          1 3 6 1 5 5 7 7 9 */
++     336,    /* OBJ_id_cmc_decryptedPOP          1 3 6 1 5 5 7 7 10 */
++     337,    /* OBJ_id_cmc_lraPOPWitness         1 3 6 1 5 5 7 7 11 */
++     338,    /* OBJ_id_cmc_getCert               1 3 6 1 5 5 7 7 15 */
++     339,    /* OBJ_id_cmc_getCRL                1 3 6 1 5 5 7 7 16 */
++     340,    /* OBJ_id_cmc_revokeRequest         1 3 6 1 5 5 7 7 17 */
++     341,    /* OBJ_id_cmc_regInfo               1 3 6 1 5 5 7 7 18 */
++     342,    /* OBJ_id_cmc_responseInfo          1 3 6 1 5 5 7 7 19 */
++     343,    /* OBJ_id_cmc_queryPending          1 3 6 1 5 5 7 7 21 */
++     344,    /* OBJ_id_cmc_popLinkRandom         1 3 6 1 5 5 7 7 22 */
++     345,    /* OBJ_id_cmc_popLinkWitness        1 3 6 1 5 5 7 7 23 */
++     346,    /* OBJ_id_cmc_confirmCertAcceptance 1 3 6 1 5 5 7 7 24 */
++     347,    /* OBJ_id_on_personalData           1 3 6 1 5 5 7 8 1 */
++     858,    /* OBJ_id_on_permanentIdentifier    1 3 6 1 5 5 7 8 3 */
++     348,    /* OBJ_id_pda_dateOfBirth           1 3 6 1 5 5 7 9 1 */
++     349,    /* OBJ_id_pda_placeOfBirth          1 3 6 1 5 5 7 9 2 */
++     351,    /* OBJ_id_pda_gender                1 3 6 1 5 5 7 9 3 */
++     352,    /* OBJ_id_pda_countryOfCitizenship  1 3 6 1 5 5 7 9 4 */
++     353,    /* OBJ_id_pda_countryOfResidence    1 3 6 1 5 5 7 9 5 */
++     354,    /* OBJ_id_aca_authenticationInfo    1 3 6 1 5 5 7 10 1 */
++     355,    /* OBJ_id_aca_accessIdentity        1 3 6 1 5 5 7 10 2 */
++     356,    /* OBJ_id_aca_chargingIdentity      1 3 6 1 5 5 7 10 3 */
++     357,    /* OBJ_id_aca_group                 1 3 6 1 5 5 7 10 4 */
++     358,    /* OBJ_id_aca_role                  1 3 6 1 5 5 7 10 5 */
++     399,    /* OBJ_id_aca_encAttrs              1 3 6 1 5 5 7 10 6 */
++     359,    /* OBJ_id_qcs_pkixQCSyntax_v1       1 3 6 1 5 5 7 11 1 */
++     360,    /* OBJ_id_cct_crs                   1 3 6 1 5 5 7 12 1 */
++     361,    /* OBJ_id_cct_PKIData               1 3 6 1 5 5 7 12 2 */
++     362,    /* OBJ_id_cct_PKIResponse           1 3 6 1 5 5 7 12 3 */
++     664,    /* OBJ_id_ppl_anyLanguage           1 3 6 1 5 5 7 21 0 */
++     665,    /* OBJ_id_ppl_inheritAll            1 3 6 1 5 5 7 21 1 */
++     667,    /* OBJ_Independent                  1 3 6 1 5 5 7 21 2 */
++     178,    /* OBJ_ad_OCSP                      1 3 6 1 5 5 7 48 1 */
++     179,    /* OBJ_ad_ca_issuers                1 3 6 1 5 5 7 48 2 */
++     363,    /* OBJ_ad_timeStamping              1 3 6 1 5 5 7 48 3 */
++     364,    /* OBJ_ad_dvcs                      1 3 6 1 5 5 7 48 4 */
++     785,    /* OBJ_caRepository                 1 3 6 1 5 5 7 48 5 */
++     780,    /* OBJ_hmac_md5                     1 3 6 1 5 5 8 1 1 */
++     781,    /* OBJ_hmac_sha1                    1 3 6 1 5 5 8 1 2 */
++      58,    /* OBJ_netscape_cert_extension      2 16 840 1 113730 1 */
++      59,    /* OBJ_netscape_data_type           2 16 840 1 113730 2 */
++     438,    /* OBJ_pilotAttributeType           0 9 2342 19200300 100 1 */
++     439,    /* OBJ_pilotAttributeSyntax         0 9 2342 19200300 100 3 */
++     440,    /* OBJ_pilotObjectClass             0 9 2342 19200300 100 4 */
++     441,    /* OBJ_pilotGroups                  0 9 2342 19200300 100 10 */
++     997,    /* OBJ_id_tc26_gost_3410_2012_512_paramSetTest 1 2 643 7 1 2 1 2 0 */
++     998,    /* OBJ_id_tc26_gost_3410_2012_512_paramSetA 1 2 643 7 1 2 1 2 1 */
++     999,    /* OBJ_id_tc26_gost_3410_2012_512_paramSetB 1 2 643 7 1 2 1 2 2 */
++    1003,    /* OBJ_id_tc26_gost_28147_param_Z   1 2 643 7 1 2 5 1 1 */
++     108,    /* OBJ_cast5_cbc                    1 2 840 113533 7 66 10 */
++     112,    /* OBJ_pbeWithMD5AndCast5_CBC       1 2 840 113533 7 66 12 */
++     782,    /* OBJ_id_PasswordBasedMAC          1 2 840 113533 7 66 13 */
++     783,    /* OBJ_id_DHBasedMac                1 2 840 113533 7 66 30 */
++       6,    /* OBJ_rsaEncryption                1 2 840 113549 1 1 1 */
++       7,    /* OBJ_md2WithRSAEncryption         1 2 840 113549 1 1 2 */
++     396,    /* OBJ_md4WithRSAEncryption         1 2 840 113549 1 1 3 */
++       8,    /* OBJ_md5WithRSAEncryption         1 2 840 113549 1 1 4 */
++      65,    /* OBJ_sha1WithRSAEncryption        1 2 840 113549 1 1 5 */
++     644,    /* OBJ_rsaOAEPEncryptionSET         1 2 840 113549 1 1 6 */
++     919,    /* OBJ_rsaesOaep                    1 2 840 113549 1 1 7 */
++     911,    /* OBJ_mgf1                         1 2 840 113549 1 1 8 */
++     935,    /* OBJ_pSpecified                   1 2 840 113549 1 1 9 */
++     912,    /* OBJ_rsassaPss                    1 2 840 113549 1 1 10 */
++     668,    /* OBJ_sha256WithRSAEncryption      1 2 840 113549 1 1 11 */
++     669,    /* OBJ_sha384WithRSAEncryption      1 2 840 113549 1 1 12 */
++     670,    /* OBJ_sha512WithRSAEncryption      1 2 840 113549 1 1 13 */
++     671,    /* OBJ_sha224WithRSAEncryption      1 2 840 113549 1 1 14 */
++      28,    /* OBJ_dhKeyAgreement               1 2 840 113549 1 3 1 */
++       9,    /* OBJ_pbeWithMD2AndDES_CBC         1 2 840 113549 1 5 1 */
++      10,    /* OBJ_pbeWithMD5AndDES_CBC         1 2 840 113549 1 5 3 */
++     168,    /* OBJ_pbeWithMD2AndRC2_CBC         1 2 840 113549 1 5 4 */
++     169,    /* OBJ_pbeWithMD5AndRC2_CBC         1 2 840 113549 1 5 6 */
++     170,    /* OBJ_pbeWithSHA1AndDES_CBC        1 2 840 113549 1 5 10 */
++      68,    /* OBJ_pbeWithSHA1AndRC2_CBC        1 2 840 113549 1 5 11 */
++      69,    /* OBJ_id_pbkdf2                    1 2 840 113549 1 5 12 */
++     161,    /* OBJ_pbes2                        1 2 840 113549 1 5 13 */
++     162,    /* OBJ_pbmac1                       1 2 840 113549 1 5 14 */
++      21,    /* OBJ_pkcs7_data                   1 2 840 113549 1 7 1 */
++      22,    /* OBJ_pkcs7_signed                 1 2 840 113549 1 7 2 */
++      23,    /* OBJ_pkcs7_enveloped              1 2 840 113549 1 7 3 */
++      24,    /* OBJ_pkcs7_signedAndEnveloped     1 2 840 113549 1 7 4 */
++      25,    /* OBJ_pkcs7_digest                 1 2 840 113549 1 7 5 */
++      26,    /* OBJ_pkcs7_encrypted              1 2 840 113549 1 7 6 */
++      48,    /* OBJ_pkcs9_emailAddress           1 2 840 113549 1 9 1 */
++      49,    /* OBJ_pkcs9_unstructuredName       1 2 840 113549 1 9 2 */
++      50,    /* OBJ_pkcs9_contentType            1 2 840 113549 1 9 3 */
++      51,    /* OBJ_pkcs9_messageDigest          1 2 840 113549 1 9 4 */
++      52,    /* OBJ_pkcs9_signingTime            1 2 840 113549 1 9 5 */
++      53,    /* OBJ_pkcs9_countersignature       1 2 840 113549 1 9 6 */
++      54,    /* OBJ_pkcs9_challengePassword      1 2 840 113549 1 9 7 */
++      55,    /* OBJ_pkcs9_unstructuredAddress    1 2 840 113549 1 9 8 */
++      56,    /* OBJ_pkcs9_extCertAttributes      1 2 840 113549 1 9 9 */
++     172,    /* OBJ_ext_req                      1 2 840 113549 1 9 14 */
++     167,    /* OBJ_SMIMECapabilities            1 2 840 113549 1 9 15 */
++     188,    /* OBJ_SMIME                        1 2 840 113549 1 9 16 */
++     156,    /* OBJ_friendlyName                 1 2 840 113549 1 9 20 */
++     157,    /* OBJ_localKeyID                   1 2 840 113549 1 9 21 */
++     681,    /* OBJ_X9_62_onBasis                1 2 840 10045 1 2 3 1 */
++     682,    /* OBJ_X9_62_tpBasis                1 2 840 10045 1 2 3 2 */
++     683,    /* OBJ_X9_62_ppBasis                1 2 840 10045 1 2 3 3 */
++     417,    /* OBJ_ms_csp_name                  1 3 6 1 4 1 311 17 1 */
++     856,    /* OBJ_LocalKeySet                  1 3 6 1 4 1 311 17 2 */
++     390,    /* OBJ_dcObject                     1 3 6 1 4 1 1466 344 */
++      91,    /* OBJ_bf_cbc                       1 3 6 1 4 1 3029 1 2 */
++     973,    /* OBJ_id_scrypt                    1 3 6 1 4 1 11591 4 11 */
++     315,    /* OBJ_id_regCtrl_regToken          1 3 6 1 5 5 7 5 1 1 */
++     316,    /* OBJ_id_regCtrl_authenticator     1 3 6 1 5 5 7 5 1 2 */
++     317,    /* OBJ_id_regCtrl_pkiPublicationInfo 1 3 6 1 5 5 7 5 1 3 */
++     318,    /* OBJ_id_regCtrl_pkiArchiveOptions 1 3 6 1 5 5 7 5 1 4 */
++     319,    /* OBJ_id_regCtrl_oldCertID         1 3 6 1 5 5 7 5 1 5 */
++     320,    /* OBJ_id_regCtrl_protocolEncrKey   1 3 6 1 5 5 7 5 1 6 */
++     321,    /* OBJ_id_regInfo_utf8Pairs         1 3 6 1 5 5 7 5 2 1 */
++     322,    /* OBJ_id_regInfo_certReq           1 3 6 1 5 5 7 5 2 2 */
++     365,    /* OBJ_id_pkix_OCSP_basic           1 3 6 1 5 5 7 48 1 1 */
++     366,    /* OBJ_id_pkix_OCSP_Nonce           1 3 6 1 5 5 7 48 1 2 */
++     367,    /* OBJ_id_pkix_OCSP_CrlID           1 3 6 1 5 5 7 48 1 3 */
++     368,    /* OBJ_id_pkix_OCSP_acceptableResponses 1 3 6 1 5 5 7 48 1 4 */
++     369,    /* OBJ_id_pkix_OCSP_noCheck         1 3 6 1 5 5 7 48 1 5 */
++     370,    /* OBJ_id_pkix_OCSP_archiveCutoff   1 3 6 1 5 5 7 48 1 6 */
++     371,    /* OBJ_id_pkix_OCSP_serviceLocator  1 3 6 1 5 5 7 48 1 7 */
++     372,    /* OBJ_id_pkix_OCSP_extendedStatus  1 3 6 1 5 5 7 48 1 8 */
++     373,    /* OBJ_id_pkix_OCSP_valid           1 3 6 1 5 5 7 48 1 9 */
++     374,    /* OBJ_id_pkix_OCSP_path            1 3 6 1 5 5 7 48 1 10 */
++     375,    /* OBJ_id_pkix_OCSP_trustRoot       1 3 6 1 5 5 7 48 1 11 */
++     921,    /* OBJ_brainpoolP160r1              1 3 36 3 3 2 8 1 1 1 */
++     922,    /* OBJ_brainpoolP160t1              1 3 36 3 3 2 8 1 1 2 */
++     923,    /* OBJ_brainpoolP192r1              1 3 36 3 3 2 8 1 1 3 */
++     924,    /* OBJ_brainpoolP192t1              1 3 36 3 3 2 8 1 1 4 */
++     925,    /* OBJ_brainpoolP224r1              1 3 36 3 3 2 8 1 1 5 */
++     926,    /* OBJ_brainpoolP224t1              1 3 36 3 3 2 8 1 1 6 */
++     927,    /* OBJ_brainpoolP256r1              1 3 36 3 3 2 8 1 1 7 */
++     928,    /* OBJ_brainpoolP256t1              1 3 36 3 3 2 8 1 1 8 */
++     929,    /* OBJ_brainpoolP320r1              1 3 36 3 3 2 8 1 1 9 */
++     930,    /* OBJ_brainpoolP320t1              1 3 36 3 3 2 8 1 1 10 */
++     931,    /* OBJ_brainpoolP384r1              1 3 36 3 3 2 8 1 1 11 */
++     932,    /* OBJ_brainpoolP384t1              1 3 36 3 3 2 8 1 1 12 */
++     933,    /* OBJ_brainpoolP512r1              1 3 36 3 3 2 8 1 1 13 */
++     934,    /* OBJ_brainpoolP512t1              1 3 36 3 3 2 8 1 1 14 */
++     936,    /* OBJ_dhSinglePass_stdDH_sha1kdf_scheme 1 3 133 16 840 63 0 2 */
++     941,    /* OBJ_dhSinglePass_cofactorDH_sha1kdf_scheme 1 3 133 16 840 63 0 3 */
++     418,    /* OBJ_aes_128_ecb                  2 16 840 1 101 3 4 1 1 */
++     419,    /* OBJ_aes_128_cbc                  2 16 840 1 101 3 4 1 2 */
++     420,    /* OBJ_aes_128_ofb128               2 16 840 1 101 3 4 1 3 */
++     421,    /* OBJ_aes_128_cfb128               2 16 840 1 101 3 4 1 4 */
++     788,    /* OBJ_id_aes128_wrap               2 16 840 1 101 3 4 1 5 */
++     895,    /* OBJ_aes_128_gcm                  2 16 840 1 101 3 4 1 6 */
++     896,    /* OBJ_aes_128_ccm                  2 16 840 1 101 3 4 1 7 */
++     897,    /* OBJ_id_aes128_wrap_pad           2 16 840 1 101 3 4 1 8 */
++     422,    /* OBJ_aes_192_ecb                  2 16 840 1 101 3 4 1 21 */
++     423,    /* OBJ_aes_192_cbc                  2 16 840 1 101 3 4 1 22 */
++     424,    /* OBJ_aes_192_ofb128               2 16 840 1 101 3 4 1 23 */
++     425,    /* OBJ_aes_192_cfb128               2 16 840 1 101 3 4 1 24 */
++     789,    /* OBJ_id_aes192_wrap               2 16 840 1 101 3 4 1 25 */
++     898,    /* OBJ_aes_192_gcm                  2 16 840 1 101 3 4 1 26 */
++     899,    /* OBJ_aes_192_ccm                  2 16 840 1 101 3 4 1 27 */
++     900,    /* OBJ_id_aes192_wrap_pad           2 16 840 1 101 3 4 1 28 */
++     426,    /* OBJ_aes_256_ecb                  2 16 840 1 101 3 4 1 41 */
++     427,    /* OBJ_aes_256_cbc                  2 16 840 1 101 3 4 1 42 */
++     428,    /* OBJ_aes_256_ofb128               2 16 840 1 101 3 4 1 43 */
++     429,    /* OBJ_aes_256_cfb128               2 16 840 1 101 3 4 1 44 */
++     790,    /* OBJ_id_aes256_wrap               2 16 840 1 101 3 4 1 45 */
++     901,    /* OBJ_aes_256_gcm                  2 16 840 1 101 3 4 1 46 */
++     902,    /* OBJ_aes_256_ccm                  2 16 840 1 101 3 4 1 47 */
++     903,    /* OBJ_id_aes256_wrap_pad           2 16 840 1 101 3 4 1 48 */
++     672,    /* OBJ_sha256                       2 16 840 1 101 3 4 2 1 */
++     673,    /* OBJ_sha384                       2 16 840 1 101 3 4 2 2 */
++     674,    /* OBJ_sha512                       2 16 840 1 101 3 4 2 3 */
++     675,    /* OBJ_sha224                       2 16 840 1 101 3 4 2 4 */
++     802,    /* OBJ_dsa_with_SHA224              2 16 840 1 101 3 4 3 1 */
++     803,    /* OBJ_dsa_with_SHA256              2 16 840 1 101 3 4 3 2 */
++      71,    /* OBJ_netscape_cert_type           2 16 840 1 113730 1 1 */
++      72,    /* OBJ_netscape_base_url            2 16 840 1 113730 1 2 */
++      73,    /* OBJ_netscape_revocation_url      2 16 840 1 113730 1 3 */
++      74,    /* OBJ_netscape_ca_revocation_url   2 16 840 1 113730 1 4 */
++      75,    /* OBJ_netscape_renewal_url         2 16 840 1 113730 1 7 */
++      76,    /* OBJ_netscape_ca_policy_url       2 16 840 1 113730 1 8 */
++      77,    /* OBJ_netscape_ssl_server_name     2 16 840 1 113730 1 12 */
++      78,    /* OBJ_netscape_comment             2 16 840 1 113730 1 13 */
++      79,    /* OBJ_netscape_cert_sequence       2 16 840 1 113730 2 5 */
++     139,    /* OBJ_ns_sgc                       2 16 840 1 113730 4 1 */
++     458,    /* OBJ_userId                       0 9 2342 19200300 100 1 1 */
++     459,    /* OBJ_textEncodedORAddress         0 9 2342 19200300 100 1 2 */
++     460,    /* OBJ_rfc822Mailbox                0 9 2342 19200300 100 1 3 */
++     461,    /* OBJ_info                         0 9 2342 19200300 100 1 4 */
++     462,    /* OBJ_favouriteDrink               0 9 2342 19200300 100 1 5 */
++     463,    /* OBJ_roomNumber                   0 9 2342 19200300 100 1 6 */
++     464,    /* OBJ_photo                        0 9 2342 19200300 100 1 7 */
++     465,    /* OBJ_userClass                    0 9 2342 19200300 100 1 8 */
++     466,    /* OBJ_host                         0 9 2342 19200300 100 1 9 */
++     467,    /* OBJ_manager                      0 9 2342 19200300 100 1 10 */
++     468,    /* OBJ_documentIdentifier           0 9 2342 19200300 100 1 11 */
++     469,    /* OBJ_documentTitle                0 9 2342 19200300 100 1 12 */
++     470,    /* OBJ_documentVersion              0 9 2342 19200300 100 1 13 */
++     471,    /* OBJ_documentAuthor               0 9 2342 19200300 100 1 14 */
++     472,    /* OBJ_documentLocation             0 9 2342 19200300 100 1 15 */
++     473,    /* OBJ_homeTelephoneNumber          0 9 2342 19200300 100 1 20 */
++     474,    /* OBJ_secretary                    0 9 2342 19200300 100 1 21 */
++     475,    /* OBJ_otherMailbox                 0 9 2342 19200300 100 1 22 */
++     476,    /* OBJ_lastModifiedTime             0 9 2342 19200300 100 1 23 */
++     477,    /* OBJ_lastModifiedBy               0 9 2342 19200300 100 1 24 */
++     391,    /* OBJ_domainComponent              0 9 2342 19200300 100 1 25 */
++     478,    /* OBJ_aRecord                      0 9 2342 19200300 100 1 26 */
++     479,    /* OBJ_pilotAttributeType27         0 9 2342 19200300 100 1 27 */
++     480,    /* OBJ_mXRecord                     0 9 2342 19200300 100 1 28 */
++     481,    /* OBJ_nSRecord                     0 9 2342 19200300 100 1 29 */
++     482,    /* OBJ_sOARecord                    0 9 2342 19200300 100 1 30 */
++     483,    /* OBJ_cNAMERecord                  0 9 2342 19200300 100 1 31 */
++     484,    /* OBJ_associatedDomain             0 9 2342 19200300 100 1 37 */
++     485,    /* OBJ_associatedName               0 9 2342 19200300 100 1 38 */
++     486,    /* OBJ_homePostalAddress            0 9 2342 19200300 100 1 39 */
++     487,    /* OBJ_personalTitle                0 9 2342 19200300 100 1 40 */
++     488,    /* OBJ_mobileTelephoneNumber        0 9 2342 19200300 100 1 41 */
++     489,    /* OBJ_pagerTelephoneNumber         0 9 2342 19200300 100 1 42 */
++     490,    /* OBJ_friendlyCountryName          0 9 2342 19200300 100 1 43 */
++     102,    /* OBJ_uniqueIdentifier             0 9 2342 19200300 100 1 44 */
++     491,    /* OBJ_organizationalStatus         0 9 2342 19200300 100 1 45 */
++     492,    /* OBJ_janetMailbox                 0 9 2342 19200300 100 1 46 */
++     493,    /* OBJ_mailPreferenceOption         0 9 2342 19200300 100 1 47 */
++     494,    /* OBJ_buildingName                 0 9 2342 19200300 100 1 48 */
++     495,    /* OBJ_dSAQuality                   0 9 2342 19200300 100 1 49 */
++     496,    /* OBJ_singleLevelQuality           0 9 2342 19200300 100 1 50 */
++     497,    /* OBJ_subtreeMinimumQuality        0 9 2342 19200300 100 1 51 */
++     498,    /* OBJ_subtreeMaximumQuality        0 9 2342 19200300 100 1 52 */
++     499,    /* OBJ_personalSignature            0 9 2342 19200300 100 1 53 */
++     500,    /* OBJ_dITRedirect                  0 9 2342 19200300 100 1 54 */
++     501,    /* OBJ_audio                        0 9 2342 19200300 100 1 55 */
++     502,    /* OBJ_documentPublisher            0 9 2342 19200300 100 1 56 */
++     442,    /* OBJ_iA5StringSyntax              0 9 2342 19200300 100 3 4 */
++     443,    /* OBJ_caseIgnoreIA5StringSyntax    0 9 2342 19200300 100 3 5 */
++     444,    /* OBJ_pilotObject                  0 9 2342 19200300 100 4 3 */
++     445,    /* OBJ_pilotPerson                  0 9 2342 19200300 100 4 4 */
++     446,    /* OBJ_account                      0 9 2342 19200300 100 4 5 */
++     447,    /* OBJ_document                     0 9 2342 19200300 100 4 6 */
++     448,    /* OBJ_room                         0 9 2342 19200300 100 4 7 */
++     449,    /* OBJ_documentSeries               0 9 2342 19200300 100 4 9 */
++     392,    /* OBJ_Domain                       0 9 2342 19200300 100 4 13 */
++     450,    /* OBJ_rFC822localPart              0 9 2342 19200300 100 4 14 */
++     451,    /* OBJ_dNSDomain                    0 9 2342 19200300 100 4 15 */
++     452,    /* OBJ_domainRelatedObject          0 9 2342 19200300 100 4 17 */
++     453,    /* OBJ_friendlyCountry              0 9 2342 19200300 100 4 18 */
++     454,    /* OBJ_simpleSecurityObject         0 9 2342 19200300 100 4 19 */
++     455,    /* OBJ_pilotOrganization            0 9 2342 19200300 100 4 20 */
++     456,    /* OBJ_pilotDSA                     0 9 2342 19200300 100 4 21 */
++     457,    /* OBJ_qualityLabelledData          0 9 2342 19200300 100 4 22 */
++     189,    /* OBJ_id_smime_mod                 1 2 840 113549 1 9 16 0 */
++     190,    /* OBJ_id_smime_ct                  1 2 840 113549 1 9 16 1 */
++     191,    /* OBJ_id_smime_aa                  1 2 840 113549 1 9 16 2 */
++     192,    /* OBJ_id_smime_alg                 1 2 840 113549 1 9 16 3 */
++     193,    /* OBJ_id_smime_cd                  1 2 840 113549 1 9 16 4 */
++     194,    /* OBJ_id_smime_spq                 1 2 840 113549 1 9 16 5 */
++     195,    /* OBJ_id_smime_cti                 1 2 840 113549 1 9 16 6 */
++     158,    /* OBJ_x509Certificate              1 2 840 113549 1 9 22 1 */
++     159,    /* OBJ_sdsiCertificate              1 2 840 113549 1 9 22 2 */
++     160,    /* OBJ_x509Crl                      1 2 840 113549 1 9 23 1 */
++     144,    /* OBJ_pbe_WithSHA1And128BitRC4     1 2 840 113549 1 12 1 1 */
++     145,    /* OBJ_pbe_WithSHA1And40BitRC4      1 2 840 113549 1 12 1 2 */
++     146,    /* OBJ_pbe_WithSHA1And3_Key_TripleDES_CBC 1 2 840 113549 1 12 1 3 */
++     147,    /* OBJ_pbe_WithSHA1And2_Key_TripleDES_CBC 1 2 840 113549 1 12 1 4 */
++     148,    /* OBJ_pbe_WithSHA1And128BitRC2_CBC 1 2 840 113549 1 12 1 5 */
++     149,    /* OBJ_pbe_WithSHA1And40BitRC2_CBC  1 2 840 113549 1 12 1 6 */
++     171,    /* OBJ_ms_ext_req                   1 3 6 1 4 1 311 2 1 14 */
++     134,    /* OBJ_ms_code_ind                  1 3 6 1 4 1 311 2 1 21 */
++     135,    /* OBJ_ms_code_com                  1 3 6 1 4 1 311 2 1 22 */
++     136,    /* OBJ_ms_ctl_sign                  1 3 6 1 4 1 311 10 3 1 */
++     137,    /* OBJ_ms_sgc                       1 3 6 1 4 1 311 10 3 3 */
++     138,    /* OBJ_ms_efs                       1 3 6 1 4 1 311 10 3 4 */
++     648,    /* OBJ_ms_smartcard_login           1 3 6 1 4 1 311 20 2 2 */
++     649,    /* OBJ_ms_upn                       1 3 6 1 4 1 311 20 2 3 */
++     951,    /* OBJ_ct_precert_scts              1 3 6 1 4 1 11129 2 4 2 */
++     952,    /* OBJ_ct_precert_poison            1 3 6 1 4 1 11129 2 4 3 */
++     953,    /* OBJ_ct_precert_signer            1 3 6 1 4 1 11129 2 4 4 */
++     954,    /* OBJ_ct_cert_scts                 1 3 6 1 4 1 11129 2 4 5 */
++     751,    /* OBJ_camellia_128_cbc             1 2 392 200011 61 1 1 1 2 */
++     752,    /* OBJ_camellia_192_cbc             1 2 392 200011 61 1 1 1 3 */
++     753,    /* OBJ_camellia_256_cbc             1 2 392 200011 61 1 1 1 4 */
++     907,    /* OBJ_id_camellia128_wrap          1 2 392 200011 61 1 1 3 2 */
++     908,    /* OBJ_id_camellia192_wrap          1 2 392 200011 61 1 1 3 3 */
++     909,    /* OBJ_id_camellia256_wrap          1 2 392 200011 61 1 1 3 4 */
++     196,    /* OBJ_id_smime_mod_cms             1 2 840 113549 1 9 16 0 1 */
++     197,    /* OBJ_id_smime_mod_ess             1 2 840 113549 1 9 16 0 2 */
++     198,    /* OBJ_id_smime_mod_oid             1 2 840 113549 1 9 16 0 3 */
++     199,    /* OBJ_id_smime_mod_msg_v3          1 2 840 113549 1 9 16 0 4 */
++     200,    /* OBJ_id_smime_mod_ets_eSignature_88 1 2 840 113549 1 9 16 0 5 */
++     201,    /* OBJ_id_smime_mod_ets_eSignature_97 1 2 840 113549 1 9 16 0 6 */
++     202,    /* OBJ_id_smime_mod_ets_eSigPolicy_88 1 2 840 113549 1 9 16 0 7 */
++     203,    /* OBJ_id_smime_mod_ets_eSigPolicy_97 1 2 840 113549 1 9 16 0 8 */
++     204,    /* OBJ_id_smime_ct_receipt          1 2 840 113549 1 9 16 1 1 */
++     205,    /* OBJ_id_smime_ct_authData         1 2 840 113549 1 9 16 1 2 */
++     206,    /* OBJ_id_smime_ct_publishCert      1 2 840 113549 1 9 16 1 3 */
++     207,    /* OBJ_id_smime_ct_TSTInfo          1 2 840 113549 1 9 16 1 4 */
++     208,    /* OBJ_id_smime_ct_TDTInfo          1 2 840 113549 1 9 16 1 5 */
++     209,    /* OBJ_id_smime_ct_contentInfo      1 2 840 113549 1 9 16 1 6 */
++     210,    /* OBJ_id_smime_ct_DVCSRequestData  1 2 840 113549 1 9 16 1 7 */
++     211,    /* OBJ_id_smime_ct_DVCSResponseData 1 2 840 113549 1 9 16 1 8 */
++     786,    /* OBJ_id_smime_ct_compressedData   1 2 840 113549 1 9 16 1 9 */
++    1058,    /* OBJ_id_smime_ct_contentCollection 1 2 840 113549 1 9 16 1 19 */
++    1059,    /* OBJ_id_smime_ct_authEnvelopedData 1 2 840 113549 1 9 16 1 23 */
++     787,    /* OBJ_id_ct_asciiTextWithCRLF      1 2 840 113549 1 9 16 1 27 */
++    1060,    /* OBJ_id_ct_xml                    1 2 840 113549 1 9 16 1 28 */
++     212,    /* OBJ_id_smime_aa_receiptRequest   1 2 840 113549 1 9 16 2 1 */
++     213,    /* OBJ_id_smime_aa_securityLabel    1 2 840 113549 1 9 16 2 2 */
++     214,    /* OBJ_id_smime_aa_mlExpandHistory  1 2 840 113549 1 9 16 2 3 */
++     215,    /* OBJ_id_smime_aa_contentHint      1 2 840 113549 1 9 16 2 4 */
++     216,    /* OBJ_id_smime_aa_msgSigDigest     1 2 840 113549 1 9 16 2 5 */
++     217,    /* OBJ_id_smime_aa_encapContentType 1 2 840 113549 1 9 16 2 6 */
++     218,    /* OBJ_id_smime_aa_contentIdentifier 1 2 840 113549 1 9 16 2 7 */
++     219,    /* OBJ_id_smime_aa_macValue         1 2 840 113549 1 9 16 2 8 */
++     220,    /* OBJ_id_smime_aa_equivalentLabels 1 2 840 113549 1 9 16 2 9 */
++     221,    /* OBJ_id_smime_aa_contentReference 1 2 840 113549 1 9 16 2 10 */
++     222,    /* OBJ_id_smime_aa_encrypKeyPref    1 2 840 113549 1 9 16 2 11 */
++     223,    /* OBJ_id_smime_aa_signingCertificate 1 2 840 113549 1 9 16 2 12 */
++     224,    /* OBJ_id_smime_aa_smimeEncryptCerts 1 2 840 113549 1 9 16 2 13 */
++     225,    /* OBJ_id_smime_aa_timeStampToken   1 2 840 113549 1 9 16 2 14 */
++     226,    /* OBJ_id_smime_aa_ets_sigPolicyId  1 2 840 113549 1 9 16 2 15 */
++     227,    /* OBJ_id_smime_aa_ets_commitmentType 1 2 840 113549 1 9 16 2 16 */
++     228,    /* OBJ_id_smime_aa_ets_signerLocation 1 2 840 113549 1 9 16 2 17 */
++     229,    /* OBJ_id_smime_aa_ets_signerAttr   1 2 840 113549 1 9 16 2 18 */
++     230,    /* OBJ_id_smime_aa_ets_otherSigCert 1 2 840 113549 1 9 16 2 19 */
++     231,    /* OBJ_id_smime_aa_ets_contentTimestamp 1 2 840 113549 1 9 16 2 20 */
++     232,    /* OBJ_id_smime_aa_ets_CertificateRefs 1 2 840 113549 1 9 16 2 21 */
++     233,    /* OBJ_id_smime_aa_ets_RevocationRefs 1 2 840 113549 1 9 16 2 22 */
++     234,    /* OBJ_id_smime_aa_ets_certValues   1 2 840 113549 1 9 16 2 23 */
++     235,    /* OBJ_id_smime_aa_ets_revocationValues 1 2 840 113549 1 9 16 2 24 */
++     236,    /* OBJ_id_smime_aa_ets_escTimeStamp 1 2 840 113549 1 9 16 2 25 */
++     237,    /* OBJ_id_smime_aa_ets_certCRLTimestamp 1 2 840 113549 1 9 16 2 26 */
++     238,    /* OBJ_id_smime_aa_ets_archiveTimeStamp 1 2 840 113549 1 9 16 2 27 */
++     239,    /* OBJ_id_smime_aa_signatureType    1 2 840 113549 1 9 16 2 28 */
++     240,    /* OBJ_id_smime_aa_dvcs_dvc         1 2 840 113549 1 9 16 2 29 */
++     241,    /* OBJ_id_smime_alg_ESDHwith3DES    1 2 840 113549 1 9 16 3 1 */
++     242,    /* OBJ_id_smime_alg_ESDHwithRC2     1 2 840 113549 1 9 16 3 2 */
++     243,    /* OBJ_id_smime_alg_3DESwrap        1 2 840 113549 1 9 16 3 3 */
++     244,    /* OBJ_id_smime_alg_RC2wrap         1 2 840 113549 1 9 16 3 4 */
++     245,    /* OBJ_id_smime_alg_ESDH            1 2 840 113549 1 9 16 3 5 */
++     246,    /* OBJ_id_smime_alg_CMS3DESwrap     1 2 840 113549 1 9 16 3 6 */
++     247,    /* OBJ_id_smime_alg_CMSRC2wrap      1 2 840 113549 1 9 16 3 7 */
++     125,    /* OBJ_zlib_compression             1 2 840 113549 1 9 16 3 8 */
++     893,    /* OBJ_id_alg_PWRI_KEK              1 2 840 113549 1 9 16 3 9 */
++     248,    /* OBJ_id_smime_cd_ldap             1 2 840 113549 1 9 16 4 1 */
++     249,    /* OBJ_id_smime_spq_ets_sqt_uri     1 2 840 113549 1 9 16 5 1 */
++     250,    /* OBJ_id_smime_spq_ets_sqt_unotice 1 2 840 113549 1 9 16 5 2 */
++     251,    /* OBJ_id_smime_cti_ets_proofOfOrigin 1 2 840 113549 1 9 16 6 1 */
++     252,    /* OBJ_id_smime_cti_ets_proofOfReceipt 1 2 840 113549 1 9 16 6 2 */
++     253,    /* OBJ_id_smime_cti_ets_proofOfDelivery 1 2 840 113549 1 9 16 6 3 */
++     254,    /* OBJ_id_smime_cti_ets_proofOfSender 1 2 840 113549 1 9 16 6 4 */
++     255,    /* OBJ_id_smime_cti_ets_proofOfApproval 1 2 840 113549 1 9 16 6 5 */
++     256,    /* OBJ_id_smime_cti_ets_proofOfCreation 1 2 840 113549 1 9 16 6 6 */
++     150,    /* OBJ_keyBag                       1 2 840 113549 1 12 10 1 1 */
++     151,    /* OBJ_pkcs8ShroudedKeyBag          1 2 840 113549 1 12 10 1 2 */
++     152,    /* OBJ_certBag                      1 2 840 113549 1 12 10 1 3 */
++     153,    /* OBJ_crlBag                       1 2 840 113549 1 12 10 1 4 */
++     154,    /* OBJ_secretBag                    1 2 840 113549 1 12 10 1 5 */
++     155,    /* OBJ_safeContentsBag              1 2 840 113549 1 12 10 1 6 */
++      34,    /* OBJ_idea_cbc                     1 3 6 1 4 1 188 7 1 1 2 */
++     955,    /* OBJ_jurisdictionLocalityName     1 3 6 1 4 1 311 60 2 1 1 */
++     956,    /* OBJ_jurisdictionStateOrProvinceName 1 3 6 1 4 1 311 60 2 1 2 */
++     957,    /* OBJ_jurisdictionCountryName      1 3 6 1 4 1 311 60 2 1 3 */
++    1056,    /* OBJ_blake2b512                   1 3 6 1 4 1 1722 12 2 1 16 */
++    1057,    /* OBJ_blake2s256                   1 3 6 1 4 1 1722 12 2 2 8 */
++};
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/objects/obj_dat.pl b/CryptoPkg/Library/OpensslLib/openssl/crypto/objects/obj_dat.pl
+new file mode 100644
+index 0000000..1cb3d1c
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/objects/obj_dat.pl
+@@ -0,0 +1,227 @@
++#! /usr/bin/env perl
++# Copyright 1995-2016 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
++# in the file LICENSE in the source distribution or at
++# https://www.openssl.org/source/license.html
++
++use integer;
++use strict;
++use warnings;
++
++# Generate the DER encoding for the given OID.
++sub der_it
++{
++    # Prologue
++    my ($v) = @_;
++    my @a = split(/\s+/, $v);
++    my $ret = pack("C*", $a[0] * 40 + $a[1]);
++    shift @a;
++    shift @a;
++
++    # Loop over rest of bytes; or in 0x80 for multi-byte numbers.
++    my $t;
++    foreach (@a) {
++        my @r = ();
++        $t = 0;
++        while ($_ >= 128) {
++            my $x = $_ % 128;
++            $_ /= 128;
++            push(@r, ($t++ ? 0x80 : 0) | $x);
++        }
++        push(@r, ($t++ ? 0x80 : 0) | $_);
++        $ret .= pack("C*", reverse(@r));
++    }
++    return $ret;
++}
++
++
++# Read input, parse all #define's into OID name and value.
++# Populate %ln and %sn with long and short names (%dupln and %dupsn)
++# are used to watch for duplicates.  Also %nid and %obj get the
++# NID and OBJ entries.
++my %ln;
++my %sn;
++my %dupln;
++my %dupsn;
++my %nid;
++my %obj;
++my %objd;
++open(IN, "$ARGV[0]") || die "Can't open input file $ARGV[0], $!";
++while () {
++    next unless /^\#define\s+(\S+)\s+(.*)$/;
++    my $v = $1;
++    my $d = $2;
++    $d =~ s/^\"//;
++    $d =~ s/\"$//;
++    if ($v =~ /^SN_(.*)$/) {
++        if (defined $dupsn{$d}) {
++            print "WARNING: Duplicate short name \"$d\"\n";
++        } else {
++            $dupsn{$d} = 1;
++        }
++        $sn{$1} = $d;
++    }
++    elsif ($v =~ /^LN_(.*)$/) {
++        if (defined $dupln{$d}) {
++            print "WARNING: Duplicate long name \"$d\"\n";
++        } else {
++            $dupln{$d} = 1;
++        }
++        $ln{$1} = $d;
++    }
++    elsif ($v =~ /^NID_(.*)$/) {
++        $nid{$d} = $1;
++    }
++    elsif ($v =~ /^OBJ_(.*)$/) {
++        $obj{$1} = $v;
++        $objd{$v} = $d;
++    }
++}
++close IN;
++
++# For every value in %obj, recursively expand OBJ_xxx values.  That is:
++#     #define OBJ_iso 1L
++#     #define OBJ_identified_organization OBJ_iso,3L
++# Modify %objd values in-place.  Create an %objn array that has
++my $changed;
++do {
++    $changed = 0;
++    foreach my $k (keys %objd) {
++        $changed = 1 if $objd{$k} =~ s/(OBJ_[^,]+),/$objd{$1},/;
++    }
++} while ($changed);
++
++my @a = sort { $a <=> $b } keys %nid;
++my $n = $a[$#a] + 1;
++my @lvalues = ();
++my $lvalues = 0;
++
++# Scan all defined objects, building up the @out array.
++# %obj_der holds the DER encoding as an array of bytes, and %obj_len
++# holds the length in bytes.
++my @out;
++my %obj_der;
++my %obj_len;
++for (my $i = 0; $i < $n; $i++) {
++    if (!defined $nid{$i}) {
++        push(@out, "    { NULL, NULL, NID_undef },\n");
++        next;
++    }
++
++    my $sn = defined $sn{$nid{$i}} ? "$sn{$nid{$i}}" : "NULL";
++    my $ln = defined $ln{$nid{$i}} ? "$ln{$nid{$i}}" : "NULL";
++    if ($sn eq "NULL") {
++        $sn = $ln;
++        $sn{$nid{$i}} = $ln;
++    }
++    if ($ln eq "NULL") {
++        $ln = $sn;
++        $ln{$nid{$i}} = $sn;
++    }
++
++    my $out = "    {\"$sn\", \"$ln\", NID_$nid{$i}";
++    if (defined $obj{$nid{$i}} && $objd{$obj{$nid{$i}}} =~ /,/) {
++        my $v = $objd{$obj{$nid{$i}}};
++        $v =~ s/L//g;
++        $v =~ s/,/ /g;
++        my $r = &der_it($v);
++        my $z = "";
++        my $length = 0;
++        # Format using fixed-with because we use strcmp later.
++        foreach (unpack("C*",$r)) {
++            $z .= sprintf("0x%02X,", $_);
++            $length++;
++        }
++        $obj_der{$obj{$nid{$i}}} = $z;
++        $obj_len{$obj{$nid{$i}}} = $length;
++
++        push(@lvalues,
++            sprintf("    %-45s  /* [%5d] %s */\n",
++                $z, $lvalues, $obj{$nid{$i}}));
++        $out .= ", $length, &so[$lvalues]";
++        $lvalues += $length;
++    }
++    $out .= "},\n";
++    push(@out, $out);
++}
++
++# Finally ready to generate the output.
++open(OUT, ">$ARGV[1]") || die "Can't open output file $ARGV[1], $!";
++print OUT <<'EOF';
++/*
++ * WARNING: do not edit!
++ * Generated by crypto/objects/obj_dat.pl
++ *
++ * Copyright 1995-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++EOF
++
++print OUT "/* Serialized OID's */\n";
++printf OUT "static const unsigned char so[%d] = {\n", $lvalues + 1;
++print OUT @lvalues;
++print OUT "};\n\n";
++
++printf OUT "#define NUM_NID %d\n", $n;
++printf OUT "static const ASN1_OBJECT nid_objs[NUM_NID] = {\n";
++print OUT @out;
++print  OUT "};\n\n";
++
++{
++    no warnings "uninitialized";
++    @a = grep(defined $sn{$nid{$_}}, 0 .. $n);
++}
++printf OUT "#define NUM_SN %d\n", $#a + 1;
++printf OUT "static const unsigned int sn_objs[NUM_SN] = {\n";
++foreach (sort { $sn{$nid{$a}} cmp $sn{$nid{$b}} } @a) {
++    printf OUT "    %4d,    /* \"$sn{$nid{$_}}\" */\n", $_;
++}
++print  OUT "};\n\n";
++
++{
++    no warnings "uninitialized";
++    @a = grep(defined $ln{$nid{$_}}, 0 .. $n);
++}
++printf OUT "#define NUM_LN %d\n", $#a + 1;
++printf OUT "static const unsigned int ln_objs[NUM_LN] = {\n";
++foreach (sort { $ln{$nid{$a}} cmp $ln{$nid{$b}} } @a) {
++    printf OUT "    %4d,    /* \"$ln{$nid{$_}}\" */\n", $_;
++}
++print  OUT "};\n\n";
++
++{
++    no warnings "uninitialized";
++    @a = grep(defined $obj{$nid{$_}}, 0 .. $n);
++}
++printf OUT "#define NUM_OBJ %d\n", $#a + 1;
++printf OUT "static const unsigned int obj_objs[NUM_OBJ] = {\n";
++
++# Compare DER; prefer shorter; if some length, use the "smaller" encoding.
++sub obj_cmp
++{
++    no warnings "uninitialized";
++    my $A = $obj_len{$obj{$nid{$a}}};
++    my $B = $obj_len{$obj{$nid{$b}}};
++    my $r = $A - $B;
++    return $r if $r != 0;
++
++    $A = $obj_der{$obj{$nid{$a}}};
++    $B = $obj_der{$obj{$nid{$b}}};
++    return $A cmp $B;
++}
++foreach (sort obj_cmp @a) {
++    my $m = $obj{$nid{$_}};
++    my $v = $objd{$m};
++    $v =~ s/L//g;
++    $v =~ s/,/ /g;
++    printf OUT "    %4d,    /* %-32s %s */\n", $_, $m, $v;
++}
++print  OUT "};\n";
++
++close OUT;
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/objects/obj_err.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/objects/obj_err.c
+new file mode 100644
+index 0000000..4677b67
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/objects/obj_err.c
+@@ -0,0 +1,50 @@
++/*
++ * Generated by util/mkerr.pl DO NOT EDIT
++ * Copyright 1995-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include 
++#include 
++
++/* BEGIN ERROR CODES */
++#ifndef OPENSSL_NO_ERR
++
++# define ERR_FUNC(func) ERR_PACK(ERR_LIB_OBJ,func,0)
++# define ERR_REASON(reason) ERR_PACK(ERR_LIB_OBJ,0,reason)
++
++static ERR_STRING_DATA OBJ_str_functs[] = {
++    {ERR_FUNC(OBJ_F_OBJ_ADD_OBJECT), "OBJ_add_object"},
++    {ERR_FUNC(OBJ_F_OBJ_CREATE), "OBJ_create"},
++    {ERR_FUNC(OBJ_F_OBJ_DUP), "OBJ_dup"},
++    {ERR_FUNC(OBJ_F_OBJ_NAME_NEW_INDEX), "OBJ_NAME_new_index"},
++    {ERR_FUNC(OBJ_F_OBJ_NID2LN), "OBJ_nid2ln"},
++    {ERR_FUNC(OBJ_F_OBJ_NID2OBJ), "OBJ_nid2obj"},
++    {ERR_FUNC(OBJ_F_OBJ_NID2SN), "OBJ_nid2sn"},
++    {0, NULL}
++};
++
++static ERR_STRING_DATA OBJ_str_reasons[] = {
++    {ERR_REASON(OBJ_R_OID_EXISTS), "oid exists"},
++    {ERR_REASON(OBJ_R_UNKNOWN_NID), "unknown nid"},
++    {0, NULL}
++};
++
++#endif
++
++int ERR_load_OBJ_strings(void)
++{
++#ifndef OPENSSL_NO_ERR
++
++    if (ERR_func_error_string(OBJ_str_functs[0].error) == NULL) {
++        ERR_load_strings(0, OBJ_str_functs);
++        ERR_load_strings(0, OBJ_str_reasons);
++    }
++#endif
++    return 1;
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/objects/obj_lcl.h b/CryptoPkg/Library/OpensslLib/openssl/crypto/objects/obj_lcl.h
+new file mode 100644
+index 0000000..a417f7c
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/objects/obj_lcl.h
+@@ -0,0 +1,14 @@
++/*
++ * Copyright 2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++typedef struct name_funcs_st NAME_FUNCS;
++DEFINE_STACK_OF(NAME_FUNCS)
++DEFINE_LHASH_OF(OBJ_NAME);
++typedef struct added_obj_st ADDED_OBJ;
++DEFINE_LHASH_OF(ADDED_OBJ);
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/objects/obj_lib.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/objects/obj_lib.c
+new file mode 100644
+index 0000000..33075e6
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/objects/obj_lib.c
+@@ -0,0 +1,66 @@
++/*
++ * Copyright 1995-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include "internal/cryptlib.h"
++#include 
++#include 
++#include 
++#include "internal/asn1_int.h"
++
++ASN1_OBJECT *OBJ_dup(const ASN1_OBJECT *o)
++{
++    ASN1_OBJECT *r;
++
++    if (o == NULL)
++        return NULL;
++    /* If object isn't dynamic it's an internal OID which is never freed */
++    if (!(o->flags & ASN1_OBJECT_FLAG_DYNAMIC))
++        return ((ASN1_OBJECT *)o);
++
++    r = ASN1_OBJECT_new();
++    if (r == NULL) {
++        OBJerr(OBJ_F_OBJ_DUP, ERR_R_ASN1_LIB);
++        return (NULL);
++    }
++
++    /* Set dynamic flags so everything gets freed up on error */
++
++    r->flags = o->flags | (ASN1_OBJECT_FLAG_DYNAMIC |
++                           ASN1_OBJECT_FLAG_DYNAMIC_STRINGS |
++                           ASN1_OBJECT_FLAG_DYNAMIC_DATA);
++
++    if (o->length > 0 && (r->data = OPENSSL_memdup(o->data, o->length)) == NULL)
++        goto err;
++
++    r->length = o->length;
++    r->nid = o->nid;
++
++    if (o->ln != NULL && (r->ln = OPENSSL_strdup(o->ln)) == NULL)
++        goto err;
++
++    if (o->sn != NULL && (r->sn = OPENSSL_strdup(o->sn)) == NULL)
++        goto err;
++
++    return r;
++ err:
++    ASN1_OBJECT_free(r);
++    OBJerr(OBJ_F_OBJ_DUP, ERR_R_MALLOC_FAILURE);
++    return NULL;
++}
++
++int OBJ_cmp(const ASN1_OBJECT *a, const ASN1_OBJECT *b)
++{
++    int ret;
++
++    ret = (a->length - b->length);
++    if (ret)
++        return (ret);
++    return (memcmp(a->data, b->data, a->length));
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/objects/obj_mac.num b/CryptoPkg/Library/OpensslLib/openssl/crypto/objects/obj_mac.num
+new file mode 100644
+index 0000000..a5995a5
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/objects/obj_mac.num
+@@ -0,0 +1,1060 @@
++undef		0
++rsadsi		1
++pkcs		2
++md2		3
++md5		4
++rc4		5
++rsaEncryption		6
++md2WithRSAEncryption		7
++md5WithRSAEncryption		8
++pbeWithMD2AndDES_CBC		9
++pbeWithMD5AndDES_CBC		10
++X500		11
++X509		12
++commonName		13
++countryName		14
++localityName		15
++stateOrProvinceName		16
++organizationName		17
++organizationalUnitName		18
++rsa		19
++pkcs7		20
++pkcs7_data		21
++pkcs7_signed		22
++pkcs7_enveloped		23
++pkcs7_signedAndEnveloped		24
++pkcs7_digest		25
++pkcs7_encrypted		26
++pkcs3		27
++dhKeyAgreement		28
++des_ecb		29
++des_cfb64		30
++des_cbc		31
++des_ede_ecb		32
++des_ede3_ecb		33
++idea_cbc		34
++idea_cfb64		35
++idea_ecb		36
++rc2_cbc		37
++rc2_ecb		38
++rc2_cfb64		39
++rc2_ofb64		40
++sha		41
++shaWithRSAEncryption		42
++des_ede_cbc		43
++des_ede3_cbc		44
++des_ofb64		45
++idea_ofb64		46
++pkcs9		47
++pkcs9_emailAddress		48
++pkcs9_unstructuredName		49
++pkcs9_contentType		50
++pkcs9_messageDigest		51
++pkcs9_signingTime		52
++pkcs9_countersignature		53
++pkcs9_challengePassword		54
++pkcs9_unstructuredAddress		55
++pkcs9_extCertAttributes		56
++netscape		57
++netscape_cert_extension		58
++netscape_data_type		59
++des_ede_cfb64		60
++des_ede3_cfb64		61
++des_ede_ofb64		62
++des_ede3_ofb64		63
++sha1		64
++sha1WithRSAEncryption		65
++dsaWithSHA		66
++dsa_2		67
++pbeWithSHA1AndRC2_CBC		68
++id_pbkdf2		69
++dsaWithSHA1_2		70
++netscape_cert_type		71
++netscape_base_url		72
++netscape_revocation_url		73
++netscape_ca_revocation_url		74
++netscape_renewal_url		75
++netscape_ca_policy_url		76
++netscape_ssl_server_name		77
++netscape_comment		78
++netscape_cert_sequence		79
++desx_cbc		80
++id_ce		81
++subject_key_identifier		82
++key_usage		83
++private_key_usage_period		84
++subject_alt_name		85
++issuer_alt_name		86
++basic_constraints		87
++crl_number		88
++certificate_policies		89
++authority_key_identifier		90
++bf_cbc		91
++bf_ecb		92
++bf_cfb64		93
++bf_ofb64		94
++mdc2		95
++mdc2WithRSA		96
++rc4_40		97
++rc2_40_cbc		98
++givenName		99
++surname		100
++initials		101
++uniqueIdentifier		102
++crl_distribution_points		103
++md5WithRSA		104
++serialNumber		105
++title		106
++description		107
++cast5_cbc		108
++cast5_ecb		109
++cast5_cfb64		110
++cast5_ofb64		111
++pbeWithMD5AndCast5_CBC		112
++dsaWithSHA1		113
++md5_sha1		114
++sha1WithRSA		115
++dsa		116
++ripemd160		117
++ripemd160WithRSA		119
++rc5_cbc		120
++rc5_ecb		121
++rc5_cfb64		122
++rc5_ofb64		123
++rle_compression		124
++zlib_compression		125
++ext_key_usage		126
++id_pkix		127
++id_kp		128
++server_auth		129
++client_auth		130
++code_sign		131
++email_protect		132
++time_stamp		133
++ms_code_ind		134
++ms_code_com		135
++ms_ctl_sign		136
++ms_sgc		137
++ms_efs		138
++ns_sgc		139
++delta_crl		140
++crl_reason		141
++invalidity_date		142
++sxnet		143
++pbe_WithSHA1And128BitRC4		144
++pbe_WithSHA1And40BitRC4		145
++pbe_WithSHA1And3_Key_TripleDES_CBC		146
++pbe_WithSHA1And2_Key_TripleDES_CBC		147
++pbe_WithSHA1And128BitRC2_CBC		148
++pbe_WithSHA1And40BitRC2_CBC		149
++keyBag		150
++pkcs8ShroudedKeyBag		151
++certBag		152
++crlBag		153
++secretBag		154
++safeContentsBag		155
++friendlyName		156
++localKeyID		157
++x509Certificate		158
++sdsiCertificate		159
++x509Crl		160
++pbes2		161
++pbmac1		162
++hmacWithSHA1		163
++id_qt_cps		164
++id_qt_unotice		165
++rc2_64_cbc		166
++SMIMECapabilities		167
++pbeWithMD2AndRC2_CBC		168
++pbeWithMD5AndRC2_CBC		169
++pbeWithSHA1AndDES_CBC		170
++ms_ext_req		171
++ext_req		172
++name		173
++dnQualifier		174
++id_pe		175
++id_ad		176
++info_access		177
++ad_OCSP		178
++ad_ca_issuers		179
++OCSP_sign		180
++iso		181
++member_body		182
++ISO_US		183
++X9_57		184
++X9cm		185
++pkcs1		186
++pkcs5		187
++SMIME		188
++id_smime_mod		189
++id_smime_ct		190
++id_smime_aa		191
++id_smime_alg		192
++id_smime_cd		193
++id_smime_spq		194
++id_smime_cti		195
++id_smime_mod_cms		196
++id_smime_mod_ess		197
++id_smime_mod_oid		198
++id_smime_mod_msg_v3		199
++id_smime_mod_ets_eSignature_88		200
++id_smime_mod_ets_eSignature_97		201
++id_smime_mod_ets_eSigPolicy_88		202
++id_smime_mod_ets_eSigPolicy_97		203
++id_smime_ct_receipt		204
++id_smime_ct_authData		205
++id_smime_ct_publishCert		206
++id_smime_ct_TSTInfo		207
++id_smime_ct_TDTInfo		208
++id_smime_ct_contentInfo		209
++id_smime_ct_DVCSRequestData		210
++id_smime_ct_DVCSResponseData		211
++id_smime_aa_receiptRequest		212
++id_smime_aa_securityLabel		213
++id_smime_aa_mlExpandHistory		214
++id_smime_aa_contentHint		215
++id_smime_aa_msgSigDigest		216
++id_smime_aa_encapContentType		217
++id_smime_aa_contentIdentifier		218
++id_smime_aa_macValue		219
++id_smime_aa_equivalentLabels		220
++id_smime_aa_contentReference		221
++id_smime_aa_encrypKeyPref		222
++id_smime_aa_signingCertificate		223
++id_smime_aa_smimeEncryptCerts		224
++id_smime_aa_timeStampToken		225
++id_smime_aa_ets_sigPolicyId		226
++id_smime_aa_ets_commitmentType		227
++id_smime_aa_ets_signerLocation		228
++id_smime_aa_ets_signerAttr		229
++id_smime_aa_ets_otherSigCert		230
++id_smime_aa_ets_contentTimestamp		231
++id_smime_aa_ets_CertificateRefs		232
++id_smime_aa_ets_RevocationRefs		233
++id_smime_aa_ets_certValues		234
++id_smime_aa_ets_revocationValues		235
++id_smime_aa_ets_escTimeStamp		236
++id_smime_aa_ets_certCRLTimestamp		237
++id_smime_aa_ets_archiveTimeStamp		238
++id_smime_aa_signatureType		239
++id_smime_aa_dvcs_dvc		240
++id_smime_alg_ESDHwith3DES		241
++id_smime_alg_ESDHwithRC2		242
++id_smime_alg_3DESwrap		243
++id_smime_alg_RC2wrap		244
++id_smime_alg_ESDH		245
++id_smime_alg_CMS3DESwrap		246
++id_smime_alg_CMSRC2wrap		247
++id_smime_cd_ldap		248
++id_smime_spq_ets_sqt_uri		249
++id_smime_spq_ets_sqt_unotice		250
++id_smime_cti_ets_proofOfOrigin		251
++id_smime_cti_ets_proofOfReceipt		252
++id_smime_cti_ets_proofOfDelivery		253
++id_smime_cti_ets_proofOfSender		254
++id_smime_cti_ets_proofOfApproval		255
++id_smime_cti_ets_proofOfCreation		256
++md4		257
++id_pkix_mod		258
++id_qt		259
++id_it		260
++id_pkip		261
++id_alg		262
++id_cmc		263
++id_on		264
++id_pda		265
++id_aca		266
++id_qcs		267
++id_cct		268
++id_pkix1_explicit_88		269
++id_pkix1_implicit_88		270
++id_pkix1_explicit_93		271
++id_pkix1_implicit_93		272
++id_mod_crmf		273
++id_mod_cmc		274
++id_mod_kea_profile_88		275
++id_mod_kea_profile_93		276
++id_mod_cmp		277
++id_mod_qualified_cert_88		278
++id_mod_qualified_cert_93		279
++id_mod_attribute_cert		280
++id_mod_timestamp_protocol		281
++id_mod_ocsp		282
++id_mod_dvcs		283
++id_mod_cmp2000		284
++biometricInfo		285
++qcStatements		286
++ac_auditEntity		287
++ac_targeting		288
++aaControls		289
++sbgp_ipAddrBlock		290
++sbgp_autonomousSysNum		291
++sbgp_routerIdentifier		292
++textNotice		293
++ipsecEndSystem		294
++ipsecTunnel		295
++ipsecUser		296
++dvcs		297
++id_it_caProtEncCert		298
++id_it_signKeyPairTypes		299
++id_it_encKeyPairTypes		300
++id_it_preferredSymmAlg		301
++id_it_caKeyUpdateInfo		302
++id_it_currentCRL		303
++id_it_unsupportedOIDs		304
++id_it_subscriptionRequest		305
++id_it_subscriptionResponse		306
++id_it_keyPairParamReq		307
++id_it_keyPairParamRep		308
++id_it_revPassphrase		309
++id_it_implicitConfirm		310
++id_it_confirmWaitTime		311
++id_it_origPKIMessage		312
++id_regCtrl		313
++id_regInfo		314
++id_regCtrl_regToken		315
++id_regCtrl_authenticator		316
++id_regCtrl_pkiPublicationInfo		317
++id_regCtrl_pkiArchiveOptions		318
++id_regCtrl_oldCertID		319
++id_regCtrl_protocolEncrKey		320
++id_regInfo_utf8Pairs		321
++id_regInfo_certReq		322
++id_alg_des40		323
++id_alg_noSignature		324
++id_alg_dh_sig_hmac_sha1		325
++id_alg_dh_pop		326
++id_cmc_statusInfo		327
++id_cmc_identification		328
++id_cmc_identityProof		329
++id_cmc_dataReturn		330
++id_cmc_transactionId		331
++id_cmc_senderNonce		332
++id_cmc_recipientNonce		333
++id_cmc_addExtensions		334
++id_cmc_encryptedPOP		335
++id_cmc_decryptedPOP		336
++id_cmc_lraPOPWitness		337
++id_cmc_getCert		338
++id_cmc_getCRL		339
++id_cmc_revokeRequest		340
++id_cmc_regInfo		341
++id_cmc_responseInfo		342
++id_cmc_queryPending		343
++id_cmc_popLinkRandom		344
++id_cmc_popLinkWitness		345
++id_cmc_confirmCertAcceptance		346
++id_on_personalData		347
++id_pda_dateOfBirth		348
++id_pda_placeOfBirth		349
++id_pda_pseudonym		350
++id_pda_gender		351
++id_pda_countryOfCitizenship		352
++id_pda_countryOfResidence		353
++id_aca_authenticationInfo		354
++id_aca_accessIdentity		355
++id_aca_chargingIdentity		356
++id_aca_group		357
++id_aca_role		358
++id_qcs_pkixQCSyntax_v1		359
++id_cct_crs		360
++id_cct_PKIData		361
++id_cct_PKIResponse		362
++ad_timeStamping		363
++ad_dvcs		364
++id_pkix_OCSP_basic		365
++id_pkix_OCSP_Nonce		366
++id_pkix_OCSP_CrlID		367
++id_pkix_OCSP_acceptableResponses		368
++id_pkix_OCSP_noCheck		369
++id_pkix_OCSP_archiveCutoff		370
++id_pkix_OCSP_serviceLocator		371
++id_pkix_OCSP_extendedStatus		372
++id_pkix_OCSP_valid		373
++id_pkix_OCSP_path		374
++id_pkix_OCSP_trustRoot		375
++algorithm		376
++rsaSignature		377
++X500algorithms		378
++org		379
++dod		380
++iana		381
++Directory		382
++Management		383
++Experimental		384
++Private		385
++Security		386
++SNMPv2		387
++Mail		388
++Enterprises		389
++dcObject		390
++domainComponent		391
++Domain		392
++joint_iso_ccitt		393
++selected_attribute_types		394
++clearance		395
++md4WithRSAEncryption		396
++ac_proxying		397
++sinfo_access		398
++id_aca_encAttrs		399
++role		400
++policy_constraints		401
++target_information		402
++no_rev_avail		403
++ccitt		404
++ansi_X9_62		405
++X9_62_prime_field		406
++X9_62_characteristic_two_field		407
++X9_62_id_ecPublicKey		408
++X9_62_prime192v1		409
++X9_62_prime192v2		410
++X9_62_prime192v3		411
++X9_62_prime239v1		412
++X9_62_prime239v2		413
++X9_62_prime239v3		414
++X9_62_prime256v1		415
++ecdsa_with_SHA1		416
++ms_csp_name		417
++aes_128_ecb		418
++aes_128_cbc		419
++aes_128_ofb128		420
++aes_128_cfb128		421
++aes_192_ecb		422
++aes_192_cbc		423
++aes_192_ofb128		424
++aes_192_cfb128		425
++aes_256_ecb		426
++aes_256_cbc		427
++aes_256_ofb128		428
++aes_256_cfb128		429
++hold_instruction_code		430
++hold_instruction_none		431
++hold_instruction_call_issuer		432
++hold_instruction_reject		433
++data		434
++pss		435
++ucl		436
++pilot		437
++pilotAttributeType		438
++pilotAttributeSyntax		439
++pilotObjectClass		440
++pilotGroups		441
++iA5StringSyntax		442
++caseIgnoreIA5StringSyntax		443
++pilotObject		444
++pilotPerson		445
++account		446
++document		447
++room		448
++documentSeries		449
++rFC822localPart		450
++dNSDomain		451
++domainRelatedObject		452
++friendlyCountry		453
++simpleSecurityObject		454
++pilotOrganization		455
++pilotDSA		456
++qualityLabelledData		457
++userId		458
++textEncodedORAddress		459
++rfc822Mailbox		460
++info		461
++favouriteDrink		462
++roomNumber		463
++photo		464
++userClass		465
++host		466
++manager		467
++documentIdentifier		468
++documentTitle		469
++documentVersion		470
++documentAuthor		471
++documentLocation		472
++homeTelephoneNumber		473
++secretary		474
++otherMailbox		475
++lastModifiedTime		476
++lastModifiedBy		477
++aRecord		478
++pilotAttributeType27		479
++mXRecord		480
++nSRecord		481
++sOARecord		482
++cNAMERecord		483
++associatedDomain		484
++associatedName		485
++homePostalAddress		486
++personalTitle		487
++mobileTelephoneNumber		488
++pagerTelephoneNumber		489
++friendlyCountryName		490
++organizationalStatus		491
++janetMailbox		492
++mailPreferenceOption		493
++buildingName		494
++dSAQuality		495
++singleLevelQuality		496
++subtreeMinimumQuality		497
++subtreeMaximumQuality		498
++personalSignature		499
++dITRedirect		500
++audio		501
++documentPublisher		502
++x500UniqueIdentifier		503
++mime_mhs		504
++mime_mhs_headings		505
++mime_mhs_bodies		506
++id_hex_partial_message		507
++id_hex_multipart_message		508
++generationQualifier		509
++pseudonym		510
++InternationalRA		511
++id_set		512
++set_ctype		513
++set_msgExt		514
++set_attr		515
++set_policy		516
++set_certExt		517
++set_brand		518
++setct_PANData		519
++setct_PANToken		520
++setct_PANOnly		521
++setct_OIData		522
++setct_PI		523
++setct_PIData		524
++setct_PIDataUnsigned		525
++setct_HODInput		526
++setct_AuthResBaggage		527
++setct_AuthRevReqBaggage		528
++setct_AuthRevResBaggage		529
++setct_CapTokenSeq		530
++setct_PInitResData		531
++setct_PI_TBS		532
++setct_PResData		533
++setct_AuthReqTBS		534
++setct_AuthResTBS		535
++setct_AuthResTBSX		536
++setct_AuthTokenTBS		537
++setct_CapTokenData		538
++setct_CapTokenTBS		539
++setct_AcqCardCodeMsg		540
++setct_AuthRevReqTBS		541
++setct_AuthRevResData		542
++setct_AuthRevResTBS		543
++setct_CapReqTBS		544
++setct_CapReqTBSX		545
++setct_CapResData		546
++setct_CapRevReqTBS		547
++setct_CapRevReqTBSX		548
++setct_CapRevResData		549
++setct_CredReqTBS		550
++setct_CredReqTBSX		551
++setct_CredResData		552
++setct_CredRevReqTBS		553
++setct_CredRevReqTBSX		554
++setct_CredRevResData		555
++setct_PCertReqData		556
++setct_PCertResTBS		557
++setct_BatchAdminReqData		558
++setct_BatchAdminResData		559
++setct_CardCInitResTBS		560
++setct_MeAqCInitResTBS		561
++setct_RegFormResTBS		562
++setct_CertReqData		563
++setct_CertReqTBS		564
++setct_CertResData		565
++setct_CertInqReqTBS		566
++setct_ErrorTBS		567
++setct_PIDualSignedTBE		568
++setct_PIUnsignedTBE		569
++setct_AuthReqTBE		570
++setct_AuthResTBE		571
++setct_AuthResTBEX		572
++setct_AuthTokenTBE		573
++setct_CapTokenTBE		574
++setct_CapTokenTBEX		575
++setct_AcqCardCodeMsgTBE		576
++setct_AuthRevReqTBE		577
++setct_AuthRevResTBE		578
++setct_AuthRevResTBEB		579
++setct_CapReqTBE		580
++setct_CapReqTBEX		581
++setct_CapResTBE		582
++setct_CapRevReqTBE		583
++setct_CapRevReqTBEX		584
++setct_CapRevResTBE		585
++setct_CredReqTBE		586
++setct_CredReqTBEX		587
++setct_CredResTBE		588
++setct_CredRevReqTBE		589
++setct_CredRevReqTBEX		590
++setct_CredRevResTBE		591
++setct_BatchAdminReqTBE		592
++setct_BatchAdminResTBE		593
++setct_RegFormReqTBE		594
++setct_CertReqTBE		595
++setct_CertReqTBEX		596
++setct_CertResTBE		597
++setct_CRLNotificationTBS		598
++setct_CRLNotificationResTBS		599
++setct_BCIDistributionTBS		600
++setext_genCrypt		601
++setext_miAuth		602
++setext_pinSecure		603
++setext_pinAny		604
++setext_track2		605
++setext_cv		606
++set_policy_root		607
++setCext_hashedRoot		608
++setCext_certType		609
++setCext_merchData		610
++setCext_cCertRequired		611
++setCext_tunneling		612
++setCext_setExt		613
++setCext_setQualf		614
++setCext_PGWYcapabilities		615
++setCext_TokenIdentifier		616
++setCext_Track2Data		617
++setCext_TokenType		618
++setCext_IssuerCapabilities		619
++setAttr_Cert		620
++setAttr_PGWYcap		621
++setAttr_TokenType		622
++setAttr_IssCap		623
++set_rootKeyThumb		624
++set_addPolicy		625
++setAttr_Token_EMV		626
++setAttr_Token_B0Prime		627
++setAttr_IssCap_CVM		628
++setAttr_IssCap_T2		629
++setAttr_IssCap_Sig		630
++setAttr_GenCryptgrm		631
++setAttr_T2Enc		632
++setAttr_T2cleartxt		633
++setAttr_TokICCsig		634
++setAttr_SecDevSig		635
++set_brand_IATA_ATA		636
++set_brand_Diners		637
++set_brand_AmericanExpress		638
++set_brand_JCB		639
++set_brand_Visa		640
++set_brand_MasterCard		641
++set_brand_Novus		642
++des_cdmf		643
++rsaOAEPEncryptionSET		644
++itu_t		645
++joint_iso_itu_t		646
++international_organizations		647
++ms_smartcard_login		648
++ms_upn		649
++aes_128_cfb1		650
++aes_192_cfb1		651
++aes_256_cfb1		652
++aes_128_cfb8		653
++aes_192_cfb8		654
++aes_256_cfb8		655
++des_cfb1		656
++des_cfb8		657
++des_ede3_cfb1		658
++des_ede3_cfb8		659
++streetAddress		660
++postalCode		661
++id_ppl		662
++proxyCertInfo		663
++id_ppl_anyLanguage		664
++id_ppl_inheritAll		665
++name_constraints		666
++Independent		667
++sha256WithRSAEncryption		668
++sha384WithRSAEncryption		669
++sha512WithRSAEncryption		670
++sha224WithRSAEncryption		671
++sha256		672
++sha384		673
++sha512		674
++sha224		675
++identified_organization		676
++certicom_arc		677
++wap		678
++wap_wsg		679
++X9_62_id_characteristic_two_basis		680
++X9_62_onBasis		681
++X9_62_tpBasis		682
++X9_62_ppBasis		683
++X9_62_c2pnb163v1		684
++X9_62_c2pnb163v2		685
++X9_62_c2pnb163v3		686
++X9_62_c2pnb176v1		687
++X9_62_c2tnb191v1		688
++X9_62_c2tnb191v2		689
++X9_62_c2tnb191v3		690
++X9_62_c2onb191v4		691
++X9_62_c2onb191v5		692
++X9_62_c2pnb208w1		693
++X9_62_c2tnb239v1		694
++X9_62_c2tnb239v2		695
++X9_62_c2tnb239v3		696
++X9_62_c2onb239v4		697
++X9_62_c2onb239v5		698
++X9_62_c2pnb272w1		699
++X9_62_c2pnb304w1		700
++X9_62_c2tnb359v1		701
++X9_62_c2pnb368w1		702
++X9_62_c2tnb431r1		703
++secp112r1		704
++secp112r2		705
++secp128r1		706
++secp128r2		707
++secp160k1		708
++secp160r1		709
++secp160r2		710
++secp192k1		711
++secp224k1		712
++secp224r1		713
++secp256k1		714
++secp384r1		715
++secp521r1		716
++sect113r1		717
++sect113r2		718
++sect131r1		719
++sect131r2		720
++sect163k1		721
++sect163r1		722
++sect163r2		723
++sect193r1		724
++sect193r2		725
++sect233k1		726
++sect233r1		727
++sect239k1		728
++sect283k1		729
++sect283r1		730
++sect409k1		731
++sect409r1		732
++sect571k1		733
++sect571r1		734
++wap_wsg_idm_ecid_wtls1		735
++wap_wsg_idm_ecid_wtls3		736
++wap_wsg_idm_ecid_wtls4		737
++wap_wsg_idm_ecid_wtls5		738
++wap_wsg_idm_ecid_wtls6		739
++wap_wsg_idm_ecid_wtls7		740
++wap_wsg_idm_ecid_wtls8		741
++wap_wsg_idm_ecid_wtls9		742
++wap_wsg_idm_ecid_wtls10		743
++wap_wsg_idm_ecid_wtls11		744
++wap_wsg_idm_ecid_wtls12		745
++any_policy		746
++policy_mappings		747
++inhibit_any_policy		748
++ipsec3		749
++ipsec4		750
++camellia_128_cbc		751
++camellia_192_cbc		752
++camellia_256_cbc		753
++camellia_128_ecb		754
++camellia_192_ecb		755
++camellia_256_ecb		756
++camellia_128_cfb128		757
++camellia_192_cfb128		758
++camellia_256_cfb128		759
++camellia_128_cfb1		760
++camellia_192_cfb1		761
++camellia_256_cfb1		762
++camellia_128_cfb8		763
++camellia_192_cfb8		764
++camellia_256_cfb8		765
++camellia_128_ofb128		766
++camellia_192_ofb128		767
++camellia_256_ofb128		768
++subject_directory_attributes		769
++issuing_distribution_point		770
++certificate_issuer		771
++korea		772
++kisa		773
++kftc		774
++npki_alg		775
++seed_ecb		776
++seed_cbc		777
++seed_ofb128		778
++seed_cfb128		779
++hmac_md5		780
++hmac_sha1		781
++id_PasswordBasedMAC		782
++id_DHBasedMac		783
++id_it_suppLangTags		784
++caRepository		785
++id_smime_ct_compressedData		786
++id_ct_asciiTextWithCRLF		787
++id_aes128_wrap		788
++id_aes192_wrap		789
++id_aes256_wrap		790
++ecdsa_with_Recommended		791
++ecdsa_with_Specified		792
++ecdsa_with_SHA224		793
++ecdsa_with_SHA256		794
++ecdsa_with_SHA384		795
++ecdsa_with_SHA512		796
++hmacWithMD5		797
++hmacWithSHA224		798
++hmacWithSHA256		799
++hmacWithSHA384		800
++hmacWithSHA512		801
++dsa_with_SHA224		802
++dsa_with_SHA256		803
++whirlpool		804
++cryptopro		805
++cryptocom		806
++id_GostR3411_94_with_GostR3410_2001		807
++id_GostR3411_94_with_GostR3410_94		808
++id_GostR3411_94		809
++id_HMACGostR3411_94		810
++id_GostR3410_2001		811
++id_GostR3410_94		812
++id_Gost28147_89		813
++gost89_cnt		814
++id_Gost28147_89_MAC		815
++id_GostR3411_94_prf		816
++id_GostR3410_2001DH		817
++id_GostR3410_94DH		818
++id_Gost28147_89_CryptoPro_KeyMeshing		819
++id_Gost28147_89_None_KeyMeshing		820
++id_GostR3411_94_TestParamSet		821
++id_GostR3411_94_CryptoProParamSet		822
++id_Gost28147_89_TestParamSet		823
++id_Gost28147_89_CryptoPro_A_ParamSet		824
++id_Gost28147_89_CryptoPro_B_ParamSet		825
++id_Gost28147_89_CryptoPro_C_ParamSet		826
++id_Gost28147_89_CryptoPro_D_ParamSet		827
++id_Gost28147_89_CryptoPro_Oscar_1_1_ParamSet		828
++id_Gost28147_89_CryptoPro_Oscar_1_0_ParamSet		829
++id_Gost28147_89_CryptoPro_RIC_1_ParamSet		830
++id_GostR3410_94_TestParamSet		831
++id_GostR3410_94_CryptoPro_A_ParamSet		832
++id_GostR3410_94_CryptoPro_B_ParamSet		833
++id_GostR3410_94_CryptoPro_C_ParamSet		834
++id_GostR3410_94_CryptoPro_D_ParamSet		835
++id_GostR3410_94_CryptoPro_XchA_ParamSet		836
++id_GostR3410_94_CryptoPro_XchB_ParamSet		837
++id_GostR3410_94_CryptoPro_XchC_ParamSet		838
++id_GostR3410_2001_TestParamSet		839
++id_GostR3410_2001_CryptoPro_A_ParamSet		840
++id_GostR3410_2001_CryptoPro_B_ParamSet		841
++id_GostR3410_2001_CryptoPro_C_ParamSet		842
++id_GostR3410_2001_CryptoPro_XchA_ParamSet		843
++id_GostR3410_2001_CryptoPro_XchB_ParamSet		844
++id_GostR3410_94_a		845
++id_GostR3410_94_aBis		846
++id_GostR3410_94_b		847
++id_GostR3410_94_bBis		848
++id_Gost28147_89_cc		849
++id_GostR3410_94_cc		850
++id_GostR3410_2001_cc		851
++id_GostR3411_94_with_GostR3410_94_cc		852
++id_GostR3411_94_with_GostR3410_2001_cc		853
++id_GostR3410_2001_ParamSet_cc		854
++hmac		855
++LocalKeySet		856
++freshest_crl		857
++id_on_permanentIdentifier		858
++searchGuide		859
++businessCategory		860
++postalAddress		861
++postOfficeBox		862
++physicalDeliveryOfficeName		863
++telephoneNumber		864
++telexNumber		865
++teletexTerminalIdentifier		866
++facsimileTelephoneNumber		867
++x121Address		868
++internationaliSDNNumber		869
++registeredAddress		870
++destinationIndicator		871
++preferredDeliveryMethod		872
++presentationAddress		873
++supportedApplicationContext		874
++member		875
++owner		876
++roleOccupant		877
++seeAlso		878
++userPassword		879
++userCertificate		880
++cACertificate		881
++authorityRevocationList		882
++certificateRevocationList		883
++crossCertificatePair		884
++enhancedSearchGuide		885
++protocolInformation		886
++distinguishedName		887
++uniqueMember		888
++houseIdentifier		889
++supportedAlgorithms		890
++deltaRevocationList		891
++dmdName		892
++id_alg_PWRI_KEK		893
++cmac		894
++aes_128_gcm		895
++aes_128_ccm		896
++id_aes128_wrap_pad		897
++aes_192_gcm		898
++aes_192_ccm		899
++id_aes192_wrap_pad		900
++aes_256_gcm		901
++aes_256_ccm		902
++id_aes256_wrap_pad		903
++aes_128_ctr		904
++aes_192_ctr		905
++aes_256_ctr		906
++id_camellia128_wrap		907
++id_camellia192_wrap		908
++id_camellia256_wrap		909
++anyExtendedKeyUsage		910
++mgf1		911
++rsassaPss		912
++aes_128_xts		913
++aes_256_xts		914
++rc4_hmac_md5		915
++aes_128_cbc_hmac_sha1		916
++aes_192_cbc_hmac_sha1		917
++aes_256_cbc_hmac_sha1		918
++rsaesOaep		919
++dhpublicnumber		920
++brainpoolP160r1		921
++brainpoolP160t1		922
++brainpoolP192r1		923
++brainpoolP192t1		924
++brainpoolP224r1		925
++brainpoolP224t1		926
++brainpoolP256r1		927
++brainpoolP256t1		928
++brainpoolP320r1		929
++brainpoolP320t1		930
++brainpoolP384r1		931
++brainpoolP384t1		932
++brainpoolP512r1		933
++brainpoolP512t1		934
++pSpecified		935
++dhSinglePass_stdDH_sha1kdf_scheme		936
++dhSinglePass_stdDH_sha224kdf_scheme		937
++dhSinglePass_stdDH_sha256kdf_scheme		938
++dhSinglePass_stdDH_sha384kdf_scheme		939
++dhSinglePass_stdDH_sha512kdf_scheme		940
++dhSinglePass_cofactorDH_sha1kdf_scheme		941
++dhSinglePass_cofactorDH_sha224kdf_scheme		942
++dhSinglePass_cofactorDH_sha256kdf_scheme		943
++dhSinglePass_cofactorDH_sha384kdf_scheme		944
++dhSinglePass_cofactorDH_sha512kdf_scheme		945
++dh_std_kdf		946
++dh_cofactor_kdf		947
++aes_128_cbc_hmac_sha256		948
++aes_192_cbc_hmac_sha256		949
++aes_256_cbc_hmac_sha256		950
++ct_precert_scts		951
++ct_precert_poison		952
++ct_precert_signer		953
++ct_cert_scts		954
++jurisdictionLocalityName		955
++jurisdictionStateOrProvinceName		956
++jurisdictionCountryName		957
++aes_128_ocb		958
++aes_192_ocb		959
++aes_256_ocb		960
++camellia_128_gcm		961
++camellia_128_ccm		962
++camellia_128_ctr		963
++camellia_128_cmac		964
++camellia_192_gcm		965
++camellia_192_ccm		966
++camellia_192_ctr		967
++camellia_192_cmac		968
++camellia_256_gcm		969
++camellia_256_ccm		970
++camellia_256_ctr		971
++camellia_256_cmac		972
++id_scrypt		973
++id_tc26		974
++gost89_cnt_12		975
++gost_mac_12		976
++id_tc26_algorithms		977
++id_tc26_sign		978
++id_GostR3410_2012_256		979
++id_GostR3410_2012_512		980
++id_tc26_digest		981
++id_GostR3411_2012_256		982
++id_GostR3411_2012_512		983
++id_tc26_signwithdigest		984
++id_tc26_signwithdigest_gost3410_2012_256		985
++id_tc26_signwithdigest_gost3410_2012_512		986
++id_tc26_mac		987
++id_tc26_hmac_gost_3411_2012_256		988
++id_tc26_hmac_gost_3411_2012_512		989
++id_tc26_cipher		990
++id_tc26_agreement		991
++id_tc26_agreement_gost_3410_2012_256		992
++id_tc26_agreement_gost_3410_2012_512		993
++id_tc26_constants		994
++id_tc26_sign_constants		995
++id_tc26_gost_3410_2012_512_constants		996
++id_tc26_gost_3410_2012_512_paramSetTest		997
++id_tc26_gost_3410_2012_512_paramSetA		998
++id_tc26_gost_3410_2012_512_paramSetB		999
++id_tc26_digest_constants		1000
++id_tc26_cipher_constants		1001
++id_tc26_gost_28147_constants		1002
++id_tc26_gost_28147_param_Z		1003
++INN		1004
++OGRN		1005
++SNILS		1006
++subjectSignTool		1007
++issuerSignTool		1008
++gost89_cbc		1009
++gost89_ecb		1010
++gost89_ctr		1011
++grasshopper_ecb		1012
++grasshopper_ctr		1013
++grasshopper_ofb		1014
++grasshopper_cbc		1015
++grasshopper_cfb		1016
++grasshopper_mac		1017
++chacha20_poly1305		1018
++chacha20		1019
++tlsfeature		1020
++tls1_prf		1021
++ipsec_IKE		1022
++capwapAC		1023
++capwapWTP		1024
++sshClient		1025
++sshServer		1026
++sendRouter		1027
++sendProxiedRouter		1028
++sendOwner		1029
++sendProxiedOwner		1030
++id_pkinit		1031
++pkInitClientAuth		1032
++pkInitKDC		1033
++X25519		1034
++X448		1035
++hkdf		1036
++kx_rsa		1037
++kx_ecdhe		1038
++kx_dhe		1039
++kx_ecdhe_psk		1040
++kx_dhe_psk		1041
++kx_rsa_psk		1042
++kx_psk		1043
++kx_srp		1044
++kx_gost		1045
++auth_rsa		1046
++auth_ecdsa		1047
++auth_psk		1048
++auth_dss		1049
++auth_gost01		1050
++auth_gost12		1051
++auth_srp		1052
++auth_null		1053
++fips_none		1054
++fips_140_2		1055
++blake2b512		1056
++blake2s256		1057
++id_smime_ct_contentCollection		1058
++id_smime_ct_authEnvelopedData		1059
++id_ct_xml		1060
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/objects/obj_xref.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/objects/obj_xref.c
+new file mode 100644
+index 0000000..627f5bc
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/objects/obj_xref.c
+@@ -0,0 +1,165 @@
++/*
++ * Copyright 2006-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include "obj_xref.h"
++#include "e_os.h"
++
++static STACK_OF(nid_triple) *sig_app, *sigx_app;
++
++static int sig_cmp(const nid_triple *a, const nid_triple *b)
++{
++    return a->sign_id - b->sign_id;
++}
++
++DECLARE_OBJ_BSEARCH_CMP_FN(nid_triple, nid_triple, sig);
++IMPLEMENT_OBJ_BSEARCH_CMP_FN(nid_triple, nid_triple, sig);
++
++static int sig_sk_cmp(const nid_triple *const *a, const nid_triple *const *b)
++{
++    return (*a)->sign_id - (*b)->sign_id;
++}
++
++DECLARE_OBJ_BSEARCH_CMP_FN(const nid_triple *, const nid_triple *, sigx);
++
++static int sigx_cmp(const nid_triple *const *a, const nid_triple *const *b)
++{
++    int ret;
++    ret = (*a)->hash_id - (*b)->hash_id;
++    if (ret)
++        return ret;
++    return (*a)->pkey_id - (*b)->pkey_id;
++}
++
++IMPLEMENT_OBJ_BSEARCH_CMP_FN(const nid_triple *, const nid_triple *, sigx);
++
++int OBJ_find_sigid_algs(int signid, int *pdig_nid, int *ppkey_nid)
++{
++    nid_triple tmp;
++    const nid_triple *rv = NULL;
++    tmp.sign_id = signid;
++
++    if (sig_app) {
++        int idx = sk_nid_triple_find(sig_app, &tmp);
++        if (idx >= 0)
++            rv = sk_nid_triple_value(sig_app, idx);
++    }
++#ifndef OBJ_XREF_TEST2
++    if (rv == NULL) {
++        rv = OBJ_bsearch_sig(&tmp, sigoid_srt, OSSL_NELEM(sigoid_srt));
++    }
++#endif
++    if (rv == NULL)
++        return 0;
++    if (pdig_nid)
++        *pdig_nid = rv->hash_id;
++    if (ppkey_nid)
++        *ppkey_nid = rv->pkey_id;
++    return 1;
++}
++
++int OBJ_find_sigid_by_algs(int *psignid, int dig_nid, int pkey_nid)
++{
++    nid_triple tmp;
++    const nid_triple *t = &tmp;
++    const nid_triple **rv = NULL;
++
++    tmp.hash_id = dig_nid;
++    tmp.pkey_id = pkey_nid;
++
++    if (sigx_app) {
++        int idx = sk_nid_triple_find(sigx_app, &tmp);
++        if (idx >= 0) {
++            t = sk_nid_triple_value(sigx_app, idx);
++            rv = &t;
++        }
++    }
++#ifndef OBJ_XREF_TEST2
++    if (rv == NULL) {
++        rv = OBJ_bsearch_sigx(&t, sigoid_srt_xref, OSSL_NELEM(sigoid_srt_xref));
++    }
++#endif
++    if (rv == NULL)
++        return 0;
++    if (psignid)
++        *psignid = (*rv)->sign_id;
++    return 1;
++}
++
++int OBJ_add_sigid(int signid, int dig_id, int pkey_id)
++{
++    nid_triple *ntr;
++    if (sig_app == NULL)
++        sig_app = sk_nid_triple_new(sig_sk_cmp);
++    if (sig_app == NULL)
++        return 0;
++    if (sigx_app == NULL)
++        sigx_app = sk_nid_triple_new(sigx_cmp);
++    if (sigx_app == NULL)
++        return 0;
++    ntr = OPENSSL_malloc(sizeof(*ntr));
++    if (ntr == NULL)
++        return 0;
++    ntr->sign_id = signid;
++    ntr->hash_id = dig_id;
++    ntr->pkey_id = pkey_id;
++
++    if (!sk_nid_triple_push(sig_app, ntr)) {
++        OPENSSL_free(ntr);
++        return 0;
++    }
++
++    if (!sk_nid_triple_push(sigx_app, ntr))
++        return 0;
++
++    sk_nid_triple_sort(sig_app);
++    sk_nid_triple_sort(sigx_app);
++
++    return 1;
++}
++
++static void sid_free(nid_triple *tt)
++{
++    OPENSSL_free(tt);
++}
++
++void OBJ_sigid_free(void)
++{
++    sk_nid_triple_pop_free(sig_app, sid_free);
++    sig_app = NULL;
++    sk_nid_triple_free(sigx_app);
++    sigx_app = NULL;
++}
++
++#ifdef OBJ_XREF_TEST
++
++main()
++{
++    int n1, n2, n3;
++
++    int i, rv;
++# ifdef OBJ_XREF_TEST2
++    for (i = 0; i < OSSL_NELEM(sigoid_srt); i++) {
++        OBJ_add_sigid(sigoid_srt[i][0], sigoid_srt[i][1], sigoid_srt[i][2]);
++    }
++# endif
++
++    for (i = 0; i < OSSL_NELEM(sigoid_srt); i++) {
++        n1 = sigoid_srt[i][0];
++        rv = OBJ_find_sigid_algs(n1, &n2, &n3);
++        printf("Forward: %d, %s %s %s\n", rv,
++               OBJ_nid2ln(n1), OBJ_nid2ln(n2), OBJ_nid2ln(n3));
++        n1 = 0;
++        rv = OBJ_find_sigid_by_algs(&n1, n2, n3);
++        printf("Reverse: %d, %s %s %s\n", rv,
++               OBJ_nid2ln(n1), OBJ_nid2ln(n2), OBJ_nid2ln(n3));
++    }
++}
++
++#endif
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/objects/obj_xref.h b/CryptoPkg/Library/OpensslLib/openssl/crypto/objects/obj_xref.h
+new file mode 100644
+index 0000000..d09aa71
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/objects/obj_xref.h
+@@ -0,0 +1,118 @@
++/*
++ * WARNING: do not edit!
++ * Generated by objxref.pl
++ *
++ * Copyright 1998-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++
++typedef struct {
++    int sign_id;
++    int hash_id;
++    int pkey_id;
++} nid_triple;
++
++DEFINE_STACK_OF(nid_triple)
++
++static const nid_triple sigoid_srt[] = {
++    {NID_md2WithRSAEncryption, NID_md2, NID_rsaEncryption},
++    {NID_md5WithRSAEncryption, NID_md5, NID_rsaEncryption},
++    {NID_shaWithRSAEncryption, NID_sha, NID_rsaEncryption},
++    {NID_sha1WithRSAEncryption, NID_sha1, NID_rsaEncryption},
++    {NID_dsaWithSHA, NID_sha, NID_dsa},
++    {NID_dsaWithSHA1_2, NID_sha1, NID_dsa_2},
++    {NID_mdc2WithRSA, NID_mdc2, NID_rsaEncryption},
++    {NID_md5WithRSA, NID_md5, NID_rsa},
++    {NID_dsaWithSHA1, NID_sha1, NID_dsa},
++    {NID_sha1WithRSA, NID_sha1, NID_rsa},
++    {NID_ripemd160WithRSA, NID_ripemd160, NID_rsaEncryption},
++    {NID_md4WithRSAEncryption, NID_md4, NID_rsaEncryption},
++    {NID_ecdsa_with_SHA1, NID_sha1, NID_X9_62_id_ecPublicKey},
++    {NID_sha256WithRSAEncryption, NID_sha256, NID_rsaEncryption},
++    {NID_sha384WithRSAEncryption, NID_sha384, NID_rsaEncryption},
++    {NID_sha512WithRSAEncryption, NID_sha512, NID_rsaEncryption},
++    {NID_sha224WithRSAEncryption, NID_sha224, NID_rsaEncryption},
++    {NID_ecdsa_with_Recommended, NID_undef, NID_X9_62_id_ecPublicKey},
++    {NID_ecdsa_with_Specified, NID_undef, NID_X9_62_id_ecPublicKey},
++    {NID_ecdsa_with_SHA224, NID_sha224, NID_X9_62_id_ecPublicKey},
++    {NID_ecdsa_with_SHA256, NID_sha256, NID_X9_62_id_ecPublicKey},
++    {NID_ecdsa_with_SHA384, NID_sha384, NID_X9_62_id_ecPublicKey},
++    {NID_ecdsa_with_SHA512, NID_sha512, NID_X9_62_id_ecPublicKey},
++    {NID_dsa_with_SHA224, NID_sha224, NID_dsa},
++    {NID_dsa_with_SHA256, NID_sha256, NID_dsa},
++    {NID_id_GostR3411_94_with_GostR3410_2001, NID_id_GostR3411_94,
++     NID_id_GostR3410_2001},
++    {NID_id_GostR3411_94_with_GostR3410_94, NID_id_GostR3411_94,
++     NID_id_GostR3410_94},
++    {NID_id_GostR3411_94_with_GostR3410_94_cc, NID_id_GostR3411_94,
++     NID_id_GostR3410_94_cc},
++    {NID_id_GostR3411_94_with_GostR3410_2001_cc, NID_id_GostR3411_94,
++     NID_id_GostR3410_2001_cc},
++    {NID_rsassaPss, NID_undef, NID_rsaEncryption},
++    {NID_dhSinglePass_stdDH_sha1kdf_scheme, NID_sha1, NID_dh_std_kdf},
++    {NID_dhSinglePass_stdDH_sha224kdf_scheme, NID_sha224, NID_dh_std_kdf},
++    {NID_dhSinglePass_stdDH_sha256kdf_scheme, NID_sha256, NID_dh_std_kdf},
++    {NID_dhSinglePass_stdDH_sha384kdf_scheme, NID_sha384, NID_dh_std_kdf},
++    {NID_dhSinglePass_stdDH_sha512kdf_scheme, NID_sha512, NID_dh_std_kdf},
++    {NID_dhSinglePass_cofactorDH_sha1kdf_scheme, NID_sha1,
++     NID_dh_cofactor_kdf},
++    {NID_dhSinglePass_cofactorDH_sha224kdf_scheme, NID_sha224,
++     NID_dh_cofactor_kdf},
++    {NID_dhSinglePass_cofactorDH_sha256kdf_scheme, NID_sha256,
++     NID_dh_cofactor_kdf},
++    {NID_dhSinglePass_cofactorDH_sha384kdf_scheme, NID_sha384,
++     NID_dh_cofactor_kdf},
++    {NID_dhSinglePass_cofactorDH_sha512kdf_scheme, NID_sha512,
++     NID_dh_cofactor_kdf},
++    {NID_id_tc26_signwithdigest_gost3410_2012_256, NID_id_GostR3411_2012_256,
++     NID_id_GostR3410_2012_256},
++    {NID_id_tc26_signwithdigest_gost3410_2012_512, NID_id_GostR3411_2012_512,
++     NID_id_GostR3410_2012_512},
++};
++
++static const nid_triple *const sigoid_srt_xref[] = {
++    &sigoid_srt[0],
++    &sigoid_srt[1],
++    &sigoid_srt[7],
++    &sigoid_srt[2],
++    &sigoid_srt[4],
++    &sigoid_srt[3],
++    &sigoid_srt[9],
++    &sigoid_srt[5],
++    &sigoid_srt[8],
++    &sigoid_srt[12],
++    &sigoid_srt[30],
++    &sigoid_srt[35],
++    &sigoid_srt[6],
++    &sigoid_srt[10],
++    &sigoid_srt[11],
++    &sigoid_srt[13],
++    &sigoid_srt[24],
++    &sigoid_srt[20],
++    &sigoid_srt[32],
++    &sigoid_srt[37],
++    &sigoid_srt[14],
++    &sigoid_srt[21],
++    &sigoid_srt[33],
++    &sigoid_srt[38],
++    &sigoid_srt[15],
++    &sigoid_srt[22],
++    &sigoid_srt[34],
++    &sigoid_srt[39],
++    &sigoid_srt[16],
++    &sigoid_srt[23],
++    &sigoid_srt[19],
++    &sigoid_srt[31],
++    &sigoid_srt[36],
++    &sigoid_srt[25],
++    &sigoid_srt[26],
++    &sigoid_srt[27],
++    &sigoid_srt[28],
++    &sigoid_srt[40],
++    &sigoid_srt[41],
++};
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/objects/obj_xref.txt b/CryptoPkg/Library/OpensslLib/openssl/crypto/objects/obj_xref.txt
+new file mode 100644
+index 0000000..981103b
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/objects/obj_xref.txt
+@@ -0,0 +1,60 @@
++# OID cross reference table.
++# Links signatures OIDs to their corresponding public key algorithms
++# and digests.
++
++md2WithRSAEncryption	md2	rsaEncryption
++md5WithRSAEncryption	md5	rsaEncryption
++shaWithRSAEncryption	sha	rsaEncryption
++sha1WithRSAEncryption	sha1	rsaEncryption
++md4WithRSAEncryption	md4	rsaEncryption
++sha256WithRSAEncryption sha256	rsaEncryption
++sha384WithRSAEncryption	sha384	rsaEncryption
++sha512WithRSAEncryption	sha512	rsaEncryption
++sha224WithRSAEncryption	sha224	rsaEncryption
++mdc2WithRSA		mdc2	rsaEncryption
++ripemd160WithRSA	ripemd160 rsaEncryption
++# For PSS the digest algorithm can vary and depends on the included
++# AlgorithmIdentifier. The digest "undef" indicates the public key
++# method should handle this explicitly.
++rsassaPss		undef	rsaEncryption
++
++# Alternative deprecated OIDs. By using the older "rsa" OID this
++# type will be recognized by not normally used.
++
++md5WithRSA		md5	rsa
++sha1WithRSA		sha1	rsa
++
++dsaWithSHA		sha	dsa
++dsaWithSHA1		sha1	dsa
++
++dsaWithSHA1_2		sha1	dsa_2
++
++ecdsa_with_SHA1		sha1	X9_62_id_ecPublicKey
++ecdsa_with_SHA224	sha224	X9_62_id_ecPublicKey
++ecdsa_with_SHA256	sha256	X9_62_id_ecPublicKey
++ecdsa_with_SHA384	sha384	X9_62_id_ecPublicKey
++ecdsa_with_SHA512	sha512	X9_62_id_ecPublicKey
++ecdsa_with_Recommended	undef	X9_62_id_ecPublicKey
++ecdsa_with_Specified	undef	X9_62_id_ecPublicKey
++
++dsa_with_SHA224		sha224	dsa
++dsa_with_SHA256		sha256	dsa
++
++id_GostR3411_94_with_GostR3410_2001	id_GostR3411_94 id_GostR3410_2001
++id_GostR3411_94_with_GostR3410_94	id_GostR3411_94 id_GostR3410_94
++id_GostR3411_94_with_GostR3410_94_cc	id_GostR3411_94 id_GostR3410_94_cc
++id_GostR3411_94_with_GostR3410_2001_cc	id_GostR3411_94 id_GostR3410_2001_cc
++id_tc26_signwithdigest_gost3410_2012_256 id_GostR3411_2012_256 id_GostR3410_2012_256
++id_tc26_signwithdigest_gost3410_2012_512 id_GostR3411_2012_512 id_GostR3410_2012_512
++# ECDH KDFs and their corresponding message digests and schemes
++dhSinglePass_stdDH_sha1kdf_scheme		sha1	dh_std_kdf
++dhSinglePass_stdDH_sha224kdf_scheme		sha224	dh_std_kdf
++dhSinglePass_stdDH_sha256kdf_scheme		sha256	dh_std_kdf
++dhSinglePass_stdDH_sha384kdf_scheme		sha384	dh_std_kdf
++dhSinglePass_stdDH_sha512kdf_scheme		sha512	dh_std_kdf
++
++dhSinglePass_cofactorDH_sha1kdf_scheme		sha1	dh_cofactor_kdf
++dhSinglePass_cofactorDH_sha224kdf_scheme	sha224	dh_cofactor_kdf
++dhSinglePass_cofactorDH_sha256kdf_scheme	sha256	dh_cofactor_kdf
++dhSinglePass_cofactorDH_sha384kdf_scheme	sha384	dh_cofactor_kdf
++dhSinglePass_cofactorDH_sha512kdf_scheme	sha512	dh_cofactor_kdf
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/objects/objects.pl b/CryptoPkg/Library/OpensslLib/openssl/crypto/objects/objects.pl
+new file mode 100644
+index 0000000..3b40277
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/objects/objects.pl
+@@ -0,0 +1,193 @@
++#! /usr/bin/env perl
++# Copyright 2000-2016 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
++# in the file LICENSE in the source distribution or at
++# https://www.openssl.org/source/license.html
++
++open (NUMIN,"$ARGV[1]") || die "Can't open number file $ARGV[1]";
++$max_nid=0;
++$o=0;
++while()
++	{
++	s|\R$||;
++	$o++;
++	s/#.*$//;
++	next if /^\s*$/;
++	$_ = 'X'.$_;
++	($Cname,$mynum) = split;
++	$Cname =~ s/^X//;
++	if (defined($nidn{$mynum}))
++		{ die "$ARGV[1]:$o:There's already an object with NID ",$mynum," on line ",$order{$mynum},"\n"; }
++	if (defined($nid{$Cname}))
++		{ die "$ARGV[1]:$o:There's already an object with name ",$Cname," on line ",$order{$nid{$Cname}},"\n"; }
++	$nid{$Cname} = $mynum;
++	$nidn{$mynum} = $Cname;
++	$order{$mynum} = $o;
++	$max_nid = $mynum if $mynum > $max_nid;
++	}
++close NUMIN;
++
++open (IN,"$ARGV[0]") || die "Can't open input file $ARGV[0]";
++$Cname="";
++$o=0;
++while ()
++	{
++	s|\R$||;
++	$o++;
++        if (/^!module\s+(.*)$/)
++		{
++		$module = $1."-";
++		$module =~ s/\./_/g;
++		$module =~ s/-/_/g;
++		}
++        if (/^!global$/)
++		{ $module = ""; }
++	if (/^!Cname\s+(.*)$/)
++		{ $Cname = $1; }
++	if (/^!Alias\s+(.+?)\s+(.*)$/)
++		{
++		$Cname = $module.$1;
++		$myoid = $2;
++		$myoid = &process_oid($myoid);
++		$Cname =~ s/-/_/g;
++		$ordern{$o} = $Cname;
++		$order{$Cname} = $o;
++		$obj{$Cname} = $myoid;
++		$_ = "";
++		$Cname = "";
++		}
++	s/!.*$//;
++	s/#.*$//;
++	next if /^\s*$/;
++	($myoid,$mysn,$myln) = split ':';
++	$mysn =~ s/^\s*//;
++	$mysn =~ s/\s*$//;
++	$myln =~ s/^\s*//;
++	$myln =~ s/\s*$//;
++	$myoid =~ s/^\s*//;
++	$myoid =~ s/\s*$//;
++	if ($myoid ne "")
++		{
++		$myoid = &process_oid($myoid);
++		}
++
++	if ($Cname eq "" && ($myln =~ /^[_A-Za-z][\w.-]*$/ ))
++		{
++		$Cname = $myln;
++		$Cname =~ s/\./_/g;
++		$Cname =~ s/-/_/g;
++		if ($Cname ne "" && defined($ln{$module.$Cname}))
++			{ die "objects.txt:$o:There's already an object with long name ",$ln{$module.$Cname}," on line ",$order{$module.$Cname},"\n"; }
++		}
++	if ($Cname eq "")
++		{
++		$Cname = $mysn;
++		$Cname =~ s/-/_/g;
++		if ($Cname ne "" && defined($sn{$module.$Cname}))
++			{ die "objects.txt:$o:There's already an object with short name ",$sn{$module.$Cname}," on line ",$order{$module.$Cname},"\n"; }
++		}
++	if ($Cname eq "")
++		{
++		$Cname = $myln;
++		$Cname =~ s/-/_/g;
++		$Cname =~ s/\./_/g;
++		$Cname =~ s/ /_/g;
++		if ($Cname ne "" && defined($ln{$module.$Cname}))
++			{ die "objects.txt:$o:There's already an object with long name ",$ln{$module.$Cname}," on line ",$order{$module.$Cname},"\n"; }
++		}
++	$Cname =~ s/\./_/g;
++	$Cname =~ s/-/_/g;
++	$Cname = $module.$Cname;
++	$ordern{$o} = $Cname;
++	$order{$Cname} = $o;
++	$sn{$Cname} = $mysn;
++	$ln{$Cname} = $myln;
++	$obj{$Cname} = $myoid;
++	if (!defined($nid{$Cname}))
++		{
++		$max_nid++;
++		$nid{$Cname} = $max_nid;
++		$nidn{$max_nid} = $Cname;
++print STDERR "Added OID $Cname\n";
++		}
++	$Cname="";
++	}
++close IN;
++
++open (NUMOUT,">$ARGV[1]") || die "Can't open output file $ARGV[1]";
++foreach (sort { $a <=> $b } keys %nidn)
++	{
++	print NUMOUT $nidn{$_},"\t\t",$_,"\n";
++	}
++close NUMOUT;
++
++open (OUT,">$ARGV[2]") || die "Can't open output file $ARGV[2]";
++print OUT <<'EOF';
++/*
++ * WARNING: do not edit!
++ * Generated by crypto/objects/objects.pl
++ *
++ * Copyright 2000-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#define SN_undef                        "UNDEF"
++#define LN_undef                        "undefined"
++#define NID_undef                       0
++#define OBJ_undef                       0L
++EOF
++
++sub expand
++	{
++	my $string = shift;
++
++	1 while $string =~ s/\t+/' ' x (length($&) * 8 - length($`) % 8)/e;
++
++	return $string;
++	}
++
++foreach (sort { $a <=> $b } keys %ordern)
++	{
++	$Cname=$ordern{$_};
++	print OUT "\n";
++	print OUT expand("#define SN_$Cname\t\t\"$sn{$Cname}\"\n") if $sn{$Cname} ne "";
++	print OUT expand("#define LN_$Cname\t\t\"$ln{$Cname}\"\n") if $ln{$Cname} ne "";
++	print OUT expand("#define NID_$Cname\t\t$nid{$Cname}\n") if $nid{$Cname} ne "";
++	print OUT expand("#define OBJ_$Cname\t\t$obj{$Cname}\n") if $obj{$Cname} ne "";
++	}
++
++close OUT;
++
++sub process_oid
++	{
++	local($oid)=@_;
++	local(@a,$oid_pref);
++
++	@a = split(/\s+/,$myoid);
++	$pref_oid = "";
++	$pref_sep = "";
++	if (!($a[0] =~ /^[0-9]+$/))
++		{
++		$a[0] =~ s/-/_/g;
++		if (!defined($obj{$a[0]}))
++			{ die "$ARGV[0]:$o:Undefined identifier ",$a[0],"\n"; }
++		$pref_oid = "OBJ_" . $a[0];
++		$pref_sep = ",";
++		shift @a;
++		}
++	$oids = join('L,',@a) . "L";
++	if ($oids ne "L")
++		{
++		$oids = $pref_oid . $pref_sep . $oids;
++		}
++	else
++		{
++		$oids = $pref_oid;
++		}
++	return($oids);
++	}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/objects/objects.txt b/CryptoPkg/Library/OpensslLib/openssl/crypto/objects/objects.txt
+new file mode 100644
+index 0000000..fc0781d
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/objects/objects.txt
+@@ -0,0 +1,1485 @@
++# CCITT was renamed to ITU-T quite some time ago
++0			: ITU-T			: itu-t
++!Alias ccitt itu-t
++
++1			: ISO			: iso
++
++2			: JOINT-ISO-ITU-T	: joint-iso-itu-t
++!Alias joint-iso-ccitt joint-iso-itu-t
++
++iso 2			: member-body		: ISO Member Body
++
++iso 3			: identified-organization
++
++# HMAC OIDs
++identified-organization 6 1 5 5 8 1 1	: HMAC-MD5	: hmac-md5
++identified-organization 6 1 5 5 8 1 2	: HMAC-SHA1	: hmac-sha1
++
++identified-organization 132	: certicom-arc
++
++joint-iso-itu-t 23	: international-organizations	: International Organizations
++
++international-organizations 43	: wap
++wap 1			: wap-wsg
++
++joint-iso-itu-t 5 1 5	: selected-attribute-types	: Selected Attribute Types
++
++selected-attribute-types 55	: clearance
++
++member-body 840		: ISO-US		: ISO US Member Body
++ISO-US 10040		: X9-57			: X9.57
++X9-57 4			: X9cm			: X9.57 CM ?
++
++!Cname dsa
++X9cm 1			: DSA			: dsaEncryption
++X9cm 3			: DSA-SHA1		: dsaWithSHA1
++
++
++ISO-US 10045		: ansi-X9-62		: ANSI X9.62
++!module X9-62
++!Alias id-fieldType ansi-X9-62 1
++X9-62_id-fieldType 1		: prime-field
++X9-62_id-fieldType 2		: characteristic-two-field
++X9-62_characteristic-two-field 3 : id-characteristic-two-basis
++X9-62_id-characteristic-two-basis 1 : onBasis
++X9-62_id-characteristic-two-basis 2 : tpBasis
++X9-62_id-characteristic-two-basis 3 : ppBasis
++!Alias id-publicKeyType ansi-X9-62 2
++X9-62_id-publicKeyType 1	: id-ecPublicKey
++!Alias ellipticCurve ansi-X9-62 3
++!Alias c-TwoCurve X9-62_ellipticCurve 0
++X9-62_c-TwoCurve 1		: c2pnb163v1
++X9-62_c-TwoCurve 2		: c2pnb163v2
++X9-62_c-TwoCurve 3		: c2pnb163v3
++X9-62_c-TwoCurve 4		: c2pnb176v1
++X9-62_c-TwoCurve 5		: c2tnb191v1
++X9-62_c-TwoCurve 6		: c2tnb191v2
++X9-62_c-TwoCurve 7		: c2tnb191v3
++X9-62_c-TwoCurve 8		: c2onb191v4
++X9-62_c-TwoCurve 9		: c2onb191v5
++X9-62_c-TwoCurve 10		: c2pnb208w1
++X9-62_c-TwoCurve 11		: c2tnb239v1
++X9-62_c-TwoCurve 12		: c2tnb239v2
++X9-62_c-TwoCurve 13		: c2tnb239v3
++X9-62_c-TwoCurve 14		: c2onb239v4
++X9-62_c-TwoCurve 15		: c2onb239v5
++X9-62_c-TwoCurve 16		: c2pnb272w1
++X9-62_c-TwoCurve 17		: c2pnb304w1
++X9-62_c-TwoCurve 18		: c2tnb359v1
++X9-62_c-TwoCurve 19		: c2pnb368w1
++X9-62_c-TwoCurve 20		: c2tnb431r1
++!Alias primeCurve X9-62_ellipticCurve 1
++X9-62_primeCurve 1	 	: prime192v1
++X9-62_primeCurve 2	 	: prime192v2
++X9-62_primeCurve 3	 	: prime192v3
++X9-62_primeCurve 4	 	: prime239v1
++X9-62_primeCurve 5	 	: prime239v2
++X9-62_primeCurve 6	 	: prime239v3
++X9-62_primeCurve 7	 	: prime256v1
++!Alias id-ecSigType ansi-X9-62 4
++!global
++X9-62_id-ecSigType 1		: ecdsa-with-SHA1
++X9-62_id-ecSigType 2		: ecdsa-with-Recommended
++X9-62_id-ecSigType 3		: ecdsa-with-Specified
++ecdsa-with-Specified 1		: ecdsa-with-SHA224
++ecdsa-with-Specified 2		: ecdsa-with-SHA256
++ecdsa-with-Specified 3		: ecdsa-with-SHA384
++ecdsa-with-Specified 4		: ecdsa-with-SHA512
++
++# SECG curve OIDs from "SEC 2: Recommended Elliptic Curve Domain Parameters"
++# (http://www.secg.org/)
++!Alias secg_ellipticCurve certicom-arc 0
++# SECG prime curves OIDs
++secg-ellipticCurve 6		: secp112r1
++secg-ellipticCurve 7		: secp112r2
++secg-ellipticCurve 28		: secp128r1
++secg-ellipticCurve 29		: secp128r2
++secg-ellipticCurve 9		: secp160k1
++secg-ellipticCurve 8		: secp160r1
++secg-ellipticCurve 30		: secp160r2
++secg-ellipticCurve 31		: secp192k1
++# NOTE: the curve secp192r1 is the same as prime192v1 defined above
++#       and is therefore omitted
++secg-ellipticCurve 32		: secp224k1
++secg-ellipticCurve 33		: secp224r1
++secg-ellipticCurve 10		: secp256k1
++# NOTE: the curve secp256r1 is the same as prime256v1 defined above
++#       and is therefore omitted
++secg-ellipticCurve 34		: secp384r1
++secg-ellipticCurve 35		: secp521r1
++# SECG characteristic two curves OIDs
++secg-ellipticCurve 4		: sect113r1
++secg-ellipticCurve 5		: sect113r2
++secg-ellipticCurve 22		: sect131r1
++secg-ellipticCurve 23		: sect131r2
++secg-ellipticCurve 1		: sect163k1
++secg-ellipticCurve 2		: sect163r1
++secg-ellipticCurve 15		: sect163r2
++secg-ellipticCurve 24		: sect193r1
++secg-ellipticCurve 25		: sect193r2
++secg-ellipticCurve 26		: sect233k1
++secg-ellipticCurve 27		: sect233r1
++secg-ellipticCurve 3		: sect239k1
++secg-ellipticCurve 16		: sect283k1
++secg-ellipticCurve 17		: sect283r1
++secg-ellipticCurve 36		: sect409k1
++secg-ellipticCurve 37		: sect409r1
++secg-ellipticCurve 38		: sect571k1
++secg-ellipticCurve 39		: sect571r1
++
++# WAP/TLS curve OIDs (http://www.wapforum.org/)
++!Alias wap-wsg-idm-ecid wap-wsg 4
++wap-wsg-idm-ecid 1	: wap-wsg-idm-ecid-wtls1
++wap-wsg-idm-ecid 3	: wap-wsg-idm-ecid-wtls3
++wap-wsg-idm-ecid 4	: wap-wsg-idm-ecid-wtls4
++wap-wsg-idm-ecid 5	: wap-wsg-idm-ecid-wtls5
++wap-wsg-idm-ecid 6	: wap-wsg-idm-ecid-wtls6
++wap-wsg-idm-ecid 7	: wap-wsg-idm-ecid-wtls7
++wap-wsg-idm-ecid 8	: wap-wsg-idm-ecid-wtls8
++wap-wsg-idm-ecid 9	: wap-wsg-idm-ecid-wtls9
++wap-wsg-idm-ecid 10	: wap-wsg-idm-ecid-wtls10
++wap-wsg-idm-ecid 11	: wap-wsg-idm-ecid-wtls11
++wap-wsg-idm-ecid 12	: wap-wsg-idm-ecid-wtls12
++
++
++ISO-US 113533 7 66 10	: CAST5-CBC		: cast5-cbc
++			: CAST5-ECB		: cast5-ecb
++!Cname cast5-cfb64
++			: CAST5-CFB		: cast5-cfb
++!Cname cast5-ofb64
++			: CAST5-OFB		: cast5-ofb
++!Cname pbeWithMD5AndCast5-CBC
++ISO-US 113533 7 66 12	:			: pbeWithMD5AndCast5CBC
++
++# Macs for CMP and CRMF
++ISO-US 113533 7 66 13	: id-PasswordBasedMAC	: password based MAC
++ISO-US 113533 7 66 30	: id-DHBasedMac		: Diffie-Hellman based MAC
++
++ISO-US 113549		: rsadsi		: RSA Data Security, Inc.
++
++rsadsi 1		: pkcs			: RSA Data Security, Inc. PKCS
++
++pkcs 1			: pkcs1
++pkcs1 1			:			: rsaEncryption
++pkcs1 2			: RSA-MD2		: md2WithRSAEncryption
++pkcs1 3			: RSA-MD4		: md4WithRSAEncryption
++pkcs1 4			: RSA-MD5		: md5WithRSAEncryption
++pkcs1 5			: RSA-SHA1		: sha1WithRSAEncryption
++# According to PKCS #1 version 2.1
++pkcs1 7			: RSAES-OAEP		: rsaesOaep
++pkcs1 8			: MGF1			: mgf1
++pkcs1 9			: PSPECIFIED		: pSpecified
++pkcs1 10		: RSASSA-PSS		: rsassaPss
++
++pkcs1 11		: RSA-SHA256		: sha256WithRSAEncryption
++pkcs1 12		: RSA-SHA384		: sha384WithRSAEncryption
++pkcs1 13		: RSA-SHA512		: sha512WithRSAEncryption
++pkcs1 14		: RSA-SHA224		: sha224WithRSAEncryption
++
++pkcs 3			: pkcs3
++pkcs3 1			:			: dhKeyAgreement
++
++pkcs 5			: pkcs5
++pkcs5 1			: PBE-MD2-DES		: pbeWithMD2AndDES-CBC
++pkcs5 3			: PBE-MD5-DES		: pbeWithMD5AndDES-CBC
++pkcs5 4			: PBE-MD2-RC2-64	: pbeWithMD2AndRC2-CBC
++pkcs5 6			: PBE-MD5-RC2-64	: pbeWithMD5AndRC2-CBC
++pkcs5 10		: PBE-SHA1-DES		: pbeWithSHA1AndDES-CBC
++pkcs5 11		: PBE-SHA1-RC2-64	: pbeWithSHA1AndRC2-CBC
++!Cname id_pbkdf2
++pkcs5 12		:			: PBKDF2
++!Cname pbes2
++pkcs5 13		:			: PBES2
++!Cname pbmac1
++pkcs5 14		:			: PBMAC1
++
++pkcs 7			: pkcs7
++pkcs7 1			:			: pkcs7-data
++!Cname pkcs7-signed
++pkcs7 2			:			: pkcs7-signedData
++!Cname pkcs7-enveloped
++pkcs7 3			:			: pkcs7-envelopedData
++!Cname pkcs7-signedAndEnveloped
++pkcs7 4			:			: pkcs7-signedAndEnvelopedData
++!Cname pkcs7-digest
++pkcs7 5			:			: pkcs7-digestData
++!Cname pkcs7-encrypted
++pkcs7 6			:			: pkcs7-encryptedData
++
++pkcs 9			: pkcs9
++!module pkcs9
++pkcs9 1			: 			: emailAddress
++pkcs9 2			:			: unstructuredName
++pkcs9 3			:			: contentType
++pkcs9 4			:			: messageDigest
++pkcs9 5			:			: signingTime
++pkcs9 6			:			: countersignature
++pkcs9 7			:			: challengePassword
++pkcs9 8			:			: unstructuredAddress
++!Cname extCertAttributes
++pkcs9 9			:			: extendedCertificateAttributes
++!global
++
++!Cname ext-req
++pkcs9 14		: extReq		: Extension Request
++
++!Cname SMIMECapabilities
++pkcs9 15		: SMIME-CAPS		: S/MIME Capabilities
++
++# S/MIME
++!Cname SMIME
++pkcs9 16		: SMIME			: S/MIME
++SMIME 0			: id-smime-mod
++SMIME 1			: id-smime-ct
++SMIME 2			: id-smime-aa
++SMIME 3			: id-smime-alg
++SMIME 4			: id-smime-cd
++SMIME 5			: id-smime-spq
++SMIME 6			: id-smime-cti
++
++# S/MIME Modules
++id-smime-mod 1		: id-smime-mod-cms
++id-smime-mod 2		: id-smime-mod-ess
++id-smime-mod 3		: id-smime-mod-oid
++id-smime-mod 4		: id-smime-mod-msg-v3
++id-smime-mod 5		: id-smime-mod-ets-eSignature-88
++id-smime-mod 6		: id-smime-mod-ets-eSignature-97
++id-smime-mod 7		: id-smime-mod-ets-eSigPolicy-88
++id-smime-mod 8		: id-smime-mod-ets-eSigPolicy-97
++
++# S/MIME Content Types
++id-smime-ct 1		: id-smime-ct-receipt
++id-smime-ct 2		: id-smime-ct-authData
++id-smime-ct 3		: id-smime-ct-publishCert
++id-smime-ct 4		: id-smime-ct-TSTInfo
++id-smime-ct 5		: id-smime-ct-TDTInfo
++id-smime-ct 6		: id-smime-ct-contentInfo
++id-smime-ct 7		: id-smime-ct-DVCSRequestData
++id-smime-ct 8		: id-smime-ct-DVCSResponseData
++id-smime-ct 9		: id-smime-ct-compressedData
++id-smime-ct 19		: id-smime-ct-contentCollection
++id-smime-ct 23		: id-smime-ct-authEnvelopedData
++id-smime-ct 27		: id-ct-asciiTextWithCRLF
++id-smime-ct 28		: id-ct-xml
++
++# S/MIME Attributes
++id-smime-aa 1		: id-smime-aa-receiptRequest
++id-smime-aa 2		: id-smime-aa-securityLabel
++id-smime-aa 3		: id-smime-aa-mlExpandHistory
++id-smime-aa 4		: id-smime-aa-contentHint
++id-smime-aa 5		: id-smime-aa-msgSigDigest
++# obsolete
++id-smime-aa 6		: id-smime-aa-encapContentType
++id-smime-aa 7		: id-smime-aa-contentIdentifier
++# obsolete
++id-smime-aa 8		: id-smime-aa-macValue
++id-smime-aa 9		: id-smime-aa-equivalentLabels
++id-smime-aa 10		: id-smime-aa-contentReference
++id-smime-aa 11		: id-smime-aa-encrypKeyPref
++id-smime-aa 12		: id-smime-aa-signingCertificate
++id-smime-aa 13		: id-smime-aa-smimeEncryptCerts
++id-smime-aa 14		: id-smime-aa-timeStampToken
++id-smime-aa 15		: id-smime-aa-ets-sigPolicyId
++id-smime-aa 16		: id-smime-aa-ets-commitmentType
++id-smime-aa 17		: id-smime-aa-ets-signerLocation
++id-smime-aa 18		: id-smime-aa-ets-signerAttr
++id-smime-aa 19		: id-smime-aa-ets-otherSigCert
++id-smime-aa 20		: id-smime-aa-ets-contentTimestamp
++id-smime-aa 21		: id-smime-aa-ets-CertificateRefs
++id-smime-aa 22		: id-smime-aa-ets-RevocationRefs
++id-smime-aa 23		: id-smime-aa-ets-certValues
++id-smime-aa 24		: id-smime-aa-ets-revocationValues
++id-smime-aa 25		: id-smime-aa-ets-escTimeStamp
++id-smime-aa 26		: id-smime-aa-ets-certCRLTimestamp
++id-smime-aa 27		: id-smime-aa-ets-archiveTimeStamp
++id-smime-aa 28		: id-smime-aa-signatureType
++id-smime-aa 29		: id-smime-aa-dvcs-dvc
++
++# S/MIME Algorithm Identifiers
++# obsolete
++id-smime-alg 1		: id-smime-alg-ESDHwith3DES
++# obsolete
++id-smime-alg 2		: id-smime-alg-ESDHwithRC2
++# obsolete
++id-smime-alg 3		: id-smime-alg-3DESwrap
++# obsolete
++id-smime-alg 4		: id-smime-alg-RC2wrap
++id-smime-alg 5		: id-smime-alg-ESDH
++id-smime-alg 6		: id-smime-alg-CMS3DESwrap
++id-smime-alg 7		: id-smime-alg-CMSRC2wrap
++id-smime-alg 9		: id-alg-PWRI-KEK
++
++# S/MIME Certificate Distribution
++id-smime-cd 1		: id-smime-cd-ldap
++
++# S/MIME Signature Policy Qualifier
++id-smime-spq 1		: id-smime-spq-ets-sqt-uri
++id-smime-spq 2		: id-smime-spq-ets-sqt-unotice
++
++# S/MIME Commitment Type Identifier
++id-smime-cti 1		: id-smime-cti-ets-proofOfOrigin
++id-smime-cti 2		: id-smime-cti-ets-proofOfReceipt
++id-smime-cti 3		: id-smime-cti-ets-proofOfDelivery
++id-smime-cti 4		: id-smime-cti-ets-proofOfSender
++id-smime-cti 5		: id-smime-cti-ets-proofOfApproval
++id-smime-cti 6		: id-smime-cti-ets-proofOfCreation
++
++pkcs9 20		:			: friendlyName
++pkcs9 21		:			: localKeyID
++!Cname ms-csp-name
++1 3 6 1 4 1 311 17 1	: CSPName		: Microsoft CSP Name
++1 3 6 1 4 1 311 17 2	: LocalKeySet		: Microsoft Local Key set
++!Alias certTypes pkcs9 22
++certTypes 1		:			: x509Certificate
++certTypes 2		:			: sdsiCertificate
++!Alias crlTypes pkcs9 23
++crlTypes 1		:			: x509Crl
++
++!Alias pkcs12 pkcs 12
++!Alias pkcs12-pbeids pkcs12 1
++
++!Cname pbe-WithSHA1And128BitRC4
++pkcs12-pbeids 1		: PBE-SHA1-RC4-128	: pbeWithSHA1And128BitRC4
++!Cname pbe-WithSHA1And40BitRC4
++pkcs12-pbeids 2		: PBE-SHA1-RC4-40	: pbeWithSHA1And40BitRC4
++!Cname pbe-WithSHA1And3_Key_TripleDES-CBC
++pkcs12-pbeids 3		: PBE-SHA1-3DES		: pbeWithSHA1And3-KeyTripleDES-CBC
++!Cname pbe-WithSHA1And2_Key_TripleDES-CBC
++pkcs12-pbeids 4		: PBE-SHA1-2DES		: pbeWithSHA1And2-KeyTripleDES-CBC
++!Cname pbe-WithSHA1And128BitRC2-CBC
++pkcs12-pbeids 5		: PBE-SHA1-RC2-128	: pbeWithSHA1And128BitRC2-CBC
++!Cname pbe-WithSHA1And40BitRC2-CBC
++pkcs12-pbeids 6		: PBE-SHA1-RC2-40	: pbeWithSHA1And40BitRC2-CBC
++
++!Alias pkcs12-Version1 pkcs12 10
++!Alias pkcs12-BagIds pkcs12-Version1 1
++pkcs12-BagIds 1		:			: keyBag
++pkcs12-BagIds 2		:			: pkcs8ShroudedKeyBag
++pkcs12-BagIds 3		:			: certBag
++pkcs12-BagIds 4		:			: crlBag
++pkcs12-BagIds 5		:			: secretBag
++pkcs12-BagIds 6		:			: safeContentsBag
++
++rsadsi 2 2		: MD2			: md2
++rsadsi 2 4		: MD4			: md4
++rsadsi 2 5		: MD5			: md5
++			: MD5-SHA1		: md5-sha1
++rsadsi 2 6		:			: hmacWithMD5
++rsadsi 2 7		:			: hmacWithSHA1
++
++# From RFC4231
++rsadsi 2 8		:			: hmacWithSHA224
++rsadsi 2 9		:			: hmacWithSHA256
++rsadsi 2 10		:			: hmacWithSHA384
++rsadsi 2 11		:			: hmacWithSHA512
++
++rsadsi 3 2		: RC2-CBC		: rc2-cbc
++			: RC2-ECB		: rc2-ecb
++!Cname rc2-cfb64
++			: RC2-CFB		: rc2-cfb
++!Cname rc2-ofb64
++			: RC2-OFB		: rc2-ofb
++			: RC2-40-CBC		: rc2-40-cbc
++			: RC2-64-CBC		: rc2-64-cbc
++rsadsi 3 4		: RC4			: rc4
++			: RC4-40		: rc4-40
++rsadsi 3 7		: DES-EDE3-CBC		: des-ede3-cbc
++rsadsi 3 8		: RC5-CBC		: rc5-cbc
++			: RC5-ECB		: rc5-ecb
++!Cname rc5-cfb64
++			: RC5-CFB		: rc5-cfb
++!Cname rc5-ofb64
++			: RC5-OFB		: rc5-ofb
++
++!Cname ms-ext-req
++1 3 6 1 4 1 311 2 1 14	: msExtReq		: Microsoft Extension Request
++!Cname ms-code-ind
++1 3 6 1 4 1 311 2 1 21	: msCodeInd		: Microsoft Individual Code Signing
++!Cname ms-code-com
++1 3 6 1 4 1 311 2 1 22	: msCodeCom		: Microsoft Commercial Code Signing
++!Cname ms-ctl-sign
++1 3 6 1 4 1 311 10 3 1	: msCTLSign		: Microsoft Trust List Signing
++!Cname ms-sgc
++1 3 6 1 4 1 311 10 3 3	: msSGC			: Microsoft Server Gated Crypto
++!Cname ms-efs
++1 3 6 1 4 1 311 10 3 4	: msEFS			: Microsoft Encrypted File System
++!Cname ms-smartcard-login
++1 3 6 1 4 1 311 20 2 2	: msSmartcardLogin	: Microsoft Smartcardlogin
++!Cname ms-upn
++1 3 6 1 4 1 311 20 2 3	: msUPN			: Microsoft Universal Principal Name
++
++1 3 6 1 4 1 188 7 1 1 2	: IDEA-CBC		: idea-cbc
++			: IDEA-ECB		: idea-ecb
++!Cname idea-cfb64
++			: IDEA-CFB		: idea-cfb
++!Cname idea-ofb64
++			: IDEA-OFB		: idea-ofb
++
++1 3 6 1 4 1 3029 1 2	: BF-CBC		: bf-cbc
++			: BF-ECB		: bf-ecb
++!Cname bf-cfb64
++			: BF-CFB		: bf-cfb
++!Cname bf-ofb64
++			: BF-OFB		: bf-ofb
++
++!Cname id-pkix
++1 3 6 1 5 5 7		: PKIX
++
++# PKIX Arcs
++id-pkix 0		: id-pkix-mod
++id-pkix 1		: id-pe
++id-pkix 2		: id-qt
++id-pkix 3		: id-kp
++id-pkix 4		: id-it
++id-pkix 5		: id-pkip
++id-pkix 6		: id-alg
++id-pkix 7		: id-cmc
++id-pkix 8		: id-on
++id-pkix 9		: id-pda
++id-pkix 10		: id-aca
++id-pkix 11		: id-qcs
++id-pkix 12		: id-cct
++id-pkix 21		: id-ppl
++id-pkix 48		: id-ad
++
++# PKIX Modules
++id-pkix-mod 1		: id-pkix1-explicit-88
++id-pkix-mod 2		: id-pkix1-implicit-88
++id-pkix-mod 3		: id-pkix1-explicit-93
++id-pkix-mod 4		: id-pkix1-implicit-93
++id-pkix-mod 5		: id-mod-crmf
++id-pkix-mod 6		: id-mod-cmc
++id-pkix-mod 7		: id-mod-kea-profile-88
++id-pkix-mod 8		: id-mod-kea-profile-93
++id-pkix-mod 9		: id-mod-cmp
++id-pkix-mod 10		: id-mod-qualified-cert-88
++id-pkix-mod 11		: id-mod-qualified-cert-93
++id-pkix-mod 12		: id-mod-attribute-cert
++id-pkix-mod 13		: id-mod-timestamp-protocol
++id-pkix-mod 14		: id-mod-ocsp
++id-pkix-mod 15		: id-mod-dvcs
++id-pkix-mod 16		: id-mod-cmp2000
++
++# PKIX Private Extensions
++!Cname info-access
++id-pe 1			: authorityInfoAccess	: Authority Information Access
++id-pe 2			: biometricInfo		: Biometric Info
++id-pe 3			: qcStatements
++id-pe 4			: ac-auditEntity
++id-pe 5			: ac-targeting
++id-pe 6			: aaControls
++id-pe 7			: sbgp-ipAddrBlock
++id-pe 8			: sbgp-autonomousSysNum
++id-pe 9			: sbgp-routerIdentifier
++id-pe 10		: ac-proxying
++!Cname sinfo-access
++id-pe 11		: subjectInfoAccess	: Subject Information Access
++id-pe 14		: proxyCertInfo		: Proxy Certificate Information
++id-pe 24		: tlsfeature		: TLS Feature
++
++# PKIX policyQualifiers for Internet policy qualifiers
++id-qt 1			: id-qt-cps		: Policy Qualifier CPS
++id-qt 2			: id-qt-unotice		: Policy Qualifier User Notice
++id-qt 3			: textNotice
++
++# PKIX key purpose identifiers
++!Cname server-auth
++id-kp 1			: serverAuth		: TLS Web Server Authentication
++!Cname client-auth
++id-kp 2			: clientAuth		: TLS Web Client Authentication
++!Cname code-sign
++id-kp 3			: codeSigning		: Code Signing
++!Cname email-protect
++id-kp 4			: emailProtection	: E-mail Protection
++id-kp 5			: ipsecEndSystem	: IPSec End System
++id-kp 6			: ipsecTunnel		: IPSec Tunnel
++id-kp 7			: ipsecUser		: IPSec User
++!Cname time-stamp
++id-kp 8			: timeStamping		: Time Stamping
++# From OCSP spec RFC2560
++!Cname OCSP-sign
++id-kp 9			: OCSPSigning		: OCSP Signing
++id-kp 10		: DVCS			: dvcs
++!Cname ipsec-IKE
++id-kp 17                : ipsecIKE              : ipsec Internet Key Exchange
++id-kp 18                : capwapAC              : Ctrl/provision WAP Access
++id-kp 19                : capwapWTP             : Ctrl/Provision WAP Termination
++!Cname sshClient
++id-kp 21                : secureShellClient     : SSH Client
++!Cname sshServer
++id-kp 22                : secureShellServer     : SSH Server
++id-kp 23                : sendRouter            : Send Router
++id-kp 24                : sendProxiedRouter     : Send Proxied Router
++id-kp 25                : sendOwner             : Send Owner
++id-kp 26                : sendProxiedOwner      : Send Proxied Owner
++
++# CMP information types
++id-it 1			: id-it-caProtEncCert
++id-it 2			: id-it-signKeyPairTypes
++id-it 3			: id-it-encKeyPairTypes
++id-it 4			: id-it-preferredSymmAlg
++id-it 5			: id-it-caKeyUpdateInfo
++id-it 6			: id-it-currentCRL
++id-it 7			: id-it-unsupportedOIDs
++# obsolete
++id-it 8			: id-it-subscriptionRequest
++# obsolete
++id-it 9			: id-it-subscriptionResponse
++id-it 10		: id-it-keyPairParamReq
++id-it 11		: id-it-keyPairParamRep
++id-it 12		: id-it-revPassphrase
++id-it 13		: id-it-implicitConfirm
++id-it 14		: id-it-confirmWaitTime
++id-it 15		: id-it-origPKIMessage
++id-it 16		: id-it-suppLangTags
++
++# CRMF registration
++id-pkip 1		: id-regCtrl
++id-pkip 2		: id-regInfo
++
++# CRMF registration controls
++id-regCtrl 1		: id-regCtrl-regToken
++id-regCtrl 2		: id-regCtrl-authenticator
++id-regCtrl 3		: id-regCtrl-pkiPublicationInfo
++id-regCtrl 4		: id-regCtrl-pkiArchiveOptions
++id-regCtrl 5		: id-regCtrl-oldCertID
++id-regCtrl 6		: id-regCtrl-protocolEncrKey
++
++# CRMF registration information
++id-regInfo 1		: id-regInfo-utf8Pairs
++id-regInfo 2		: id-regInfo-certReq
++
++# algorithms
++id-alg 1		: id-alg-des40
++id-alg 2		: id-alg-noSignature
++id-alg 3		: id-alg-dh-sig-hmac-sha1
++id-alg 4		: id-alg-dh-pop
++
++# CMC controls
++id-cmc 1		: id-cmc-statusInfo
++id-cmc 2		: id-cmc-identification
++id-cmc 3		: id-cmc-identityProof
++id-cmc 4		: id-cmc-dataReturn
++id-cmc 5		: id-cmc-transactionId
++id-cmc 6		: id-cmc-senderNonce
++id-cmc 7		: id-cmc-recipientNonce
++id-cmc 8		: id-cmc-addExtensions
++id-cmc 9		: id-cmc-encryptedPOP
++id-cmc 10		: id-cmc-decryptedPOP
++id-cmc 11		: id-cmc-lraPOPWitness
++id-cmc 15		: id-cmc-getCert
++id-cmc 16		: id-cmc-getCRL
++id-cmc 17		: id-cmc-revokeRequest
++id-cmc 18		: id-cmc-regInfo
++id-cmc 19		: id-cmc-responseInfo
++id-cmc 21		: id-cmc-queryPending
++id-cmc 22		: id-cmc-popLinkRandom
++id-cmc 23		: id-cmc-popLinkWitness
++id-cmc 24		: id-cmc-confirmCertAcceptance 
++
++# other names
++id-on 1			: id-on-personalData
++id-on 3			: id-on-permanentIdentifier : Permanent Identifier
++
++# personal data attributes
++id-pda 1		: id-pda-dateOfBirth
++id-pda 2		: id-pda-placeOfBirth
++id-pda 3		: id-pda-gender
++id-pda 4		: id-pda-countryOfCitizenship
++id-pda 5		: id-pda-countryOfResidence
++
++# attribute certificate attributes
++id-aca 1		: id-aca-authenticationInfo
++id-aca 2		: id-aca-accessIdentity
++id-aca 3		: id-aca-chargingIdentity
++id-aca 4		: id-aca-group
++# attention : the following seems to be obsolete, replace by 'role'
++id-aca 5		: id-aca-role
++id-aca 6		: id-aca-encAttrs
++
++# qualified certificate statements
++id-qcs 1		: id-qcs-pkixQCSyntax-v1
++
++# CMC content types
++id-cct 1		: id-cct-crs
++id-cct 2		: id-cct-PKIData
++id-cct 3		: id-cct-PKIResponse
++
++# Predefined Proxy Certificate policy languages
++id-ppl 0		: id-ppl-anyLanguage	: Any language
++id-ppl 1		: id-ppl-inheritAll	: Inherit all
++id-ppl 2		: id-ppl-independent	: Independent
++
++# access descriptors for authority info access extension
++!Cname ad-OCSP
++id-ad 1			: OCSP			: OCSP
++!Cname ad-ca-issuers
++id-ad 2			: caIssuers		: CA Issuers
++!Cname ad-timeStamping
++id-ad 3			: ad_timestamping	: AD Time Stamping
++!Cname ad-dvcs
++id-ad 4			: AD_DVCS		: ad dvcs
++id-ad 5			: caRepository		: CA Repository
++
++
++!Alias id-pkix-OCSP ad-OCSP
++!module id-pkix-OCSP
++!Cname basic
++id-pkix-OCSP 1		: basicOCSPResponse	: Basic OCSP Response
++id-pkix-OCSP 2		: Nonce			: OCSP Nonce
++id-pkix-OCSP 3		: CrlID			: OCSP CRL ID
++id-pkix-OCSP 4		: acceptableResponses	: Acceptable OCSP Responses
++id-pkix-OCSP 5		: noCheck		: OCSP No Check
++id-pkix-OCSP 6		: archiveCutoff		: OCSP Archive Cutoff
++id-pkix-OCSP 7		: serviceLocator	: OCSP Service Locator
++id-pkix-OCSP 8		: extendedStatus	: Extended OCSP Status
++id-pkix-OCSP 9		: valid
++id-pkix-OCSP 10		: path
++id-pkix-OCSP 11		: trustRoot		: Trust Root
++!global
++
++1 3 14 3 2		: algorithm		: algorithm
++algorithm 3		: RSA-NP-MD5		: md5WithRSA
++algorithm 6		: DES-ECB		: des-ecb
++algorithm 7		: DES-CBC		: des-cbc
++!Cname des-ofb64
++algorithm 8		: DES-OFB		: des-ofb
++!Cname des-cfb64
++algorithm 9		: DES-CFB		: des-cfb
++algorithm 11		: rsaSignature
++!Cname dsa-2
++algorithm 12		: DSA-old		: dsaEncryption-old
++algorithm 13		: DSA-SHA		: dsaWithSHA
++algorithm 15		: RSA-SHA		: shaWithRSAEncryption
++!Cname des-ede-ecb
++algorithm 17		: DES-EDE		: des-ede
++!Cname des-ede3-ecb
++			: DES-EDE3		: des-ede3
++			: DES-EDE-CBC		: des-ede-cbc
++!Cname des-ede-cfb64
++			: DES-EDE-CFB		: des-ede-cfb
++!Cname des-ede3-cfb64
++			: DES-EDE3-CFB		: des-ede3-cfb
++!Cname des-ede-ofb64
++			: DES-EDE-OFB		: des-ede-ofb
++!Cname des-ede3-ofb64
++			: DES-EDE3-OFB		: des-ede3-ofb
++			: DESX-CBC		: desx-cbc
++algorithm 18		: SHA			: sha
++algorithm 26		: SHA1			: sha1
++!Cname dsaWithSHA1-2
++algorithm 27		: DSA-SHA1-old		: dsaWithSHA1-old
++algorithm 29		: RSA-SHA1-2		: sha1WithRSA
++
++1 3 36 3 2 1		: RIPEMD160		: ripemd160
++1 3 36 3 3 1 2		: RSA-RIPEMD160		: ripemd160WithRSA
++
++1 3 6 1 4 1 1722 12 2 1 16 : BLAKE2b512        : blake2b512
++1 3 6 1 4 1 1722 12 2 2 8  : BLAKE2s256        : blake2s256
++
++!Cname sxnet
++1 3 101 1 4 1		: SXNetID		: Strong Extranet ID
++
++2 5			: X500			: directory services (X.500)
++
++X500 4			: X509
++X509 3			: CN			: commonName
++X509 4			: SN			: surname
++X509 5			: 			: serialNumber
++X509 6			: C			: countryName
++X509 7			: L			: localityName
++X509 8			: ST			: stateOrProvinceName
++X509 9			: street		: streetAddress
++X509 10			: O			: organizationName
++X509 11			: OU			: organizationalUnitName
++X509 12			: title			: title
++X509 13			: 			: description
++X509 14			: 			: searchGuide
++X509 15			: 			: businessCategory
++X509 16			: 			: postalAddress
++X509 17			: 			: postalCode
++X509 18			: 			: postOfficeBox
++X509 19			: 			: physicalDeliveryOfficeName
++X509 20			: 			: telephoneNumber
++X509 21			: 			: telexNumber
++X509 22			: 			: teletexTerminalIdentifier
++X509 23			: 			: facsimileTelephoneNumber
++X509 24			: 			: x121Address
++X509 25			: 			: internationaliSDNNumber
++X509 26			: 			: registeredAddress
++X509 27			: 			: destinationIndicator
++X509 28			: 			: preferredDeliveryMethod
++X509 29			: 			: presentationAddress
++X509 30			: 			: supportedApplicationContext
++X509 31			: member		:
++X509 32			: owner			:
++X509 33			: 			: roleOccupant
++X509 34			: seeAlso		:
++X509 35			: 			: userPassword
++X509 36			: 			: userCertificate
++X509 37			: 			: cACertificate
++X509 38			: 			: authorityRevocationList
++X509 39			: 			: certificateRevocationList
++X509 40			: 			: crossCertificatePair
++X509 41			: name			: name
++X509 42			: GN			: givenName
++X509 43			: initials		: initials
++X509 44			: 			: generationQualifier
++X509 45			: 			: x500UniqueIdentifier
++X509 46			: dnQualifier		: dnQualifier
++X509 47			: 			: enhancedSearchGuide
++X509 48			: 			: protocolInformation
++X509 49			: 			: distinguishedName
++X509 50			: 			: uniqueMember
++X509 51			: 			: houseIdentifier
++X509 52			: 			: supportedAlgorithms
++X509 53			: 			: deltaRevocationList
++X509 54			: dmdName		:
++X509 65			:			: pseudonym
++X509 72			: role			: role
++
++X500 8			: X500algorithms	: directory services - algorithms
++X500algorithms 1 1	: RSA			: rsa
++X500algorithms 3 100	: RSA-MDC2		: mdc2WithRSA
++X500algorithms 3 101	: MDC2			: mdc2
++
++X500 29			: id-ce
++!Cname subject-directory-attributes
++id-ce 9			: subjectDirectoryAttributes : X509v3 Subject Directory Attributes
++!Cname subject-key-identifier
++id-ce 14		: subjectKeyIdentifier	: X509v3 Subject Key Identifier
++!Cname key-usage
++id-ce 15		: keyUsage		: X509v3 Key Usage
++!Cname private-key-usage-period
++id-ce 16		: privateKeyUsagePeriod	: X509v3 Private Key Usage Period
++!Cname subject-alt-name
++id-ce 17		: subjectAltName	: X509v3 Subject Alternative Name
++!Cname issuer-alt-name
++id-ce 18		: issuerAltName		: X509v3 Issuer Alternative Name
++!Cname basic-constraints
++id-ce 19		: basicConstraints	: X509v3 Basic Constraints
++!Cname crl-number
++id-ce 20		: crlNumber		: X509v3 CRL Number
++!Cname crl-reason
++id-ce 21		: CRLReason		: X509v3 CRL Reason Code
++!Cname invalidity-date
++id-ce 24		: invalidityDate	: Invalidity Date
++!Cname delta-crl
++id-ce 27		: deltaCRL		: X509v3 Delta CRL Indicator
++!Cname issuing-distribution-point
++id-ce 28		: issuingDistributionPoint : X509v3 Issuing Distribution Point
++!Cname certificate-issuer
++id-ce 29		: certificateIssuer	: X509v3 Certificate Issuer
++!Cname name-constraints
++id-ce 30		: nameConstraints	: X509v3 Name Constraints
++!Cname crl-distribution-points
++id-ce 31		: crlDistributionPoints	: X509v3 CRL Distribution Points
++!Cname certificate-policies
++id-ce 32		: certificatePolicies	: X509v3 Certificate Policies
++!Cname any-policy
++certificate-policies 0	: anyPolicy		: X509v3 Any Policy
++!Cname policy-mappings
++id-ce 33		: policyMappings	: X509v3 Policy Mappings
++!Cname authority-key-identifier
++id-ce 35		: authorityKeyIdentifier : X509v3 Authority Key Identifier
++!Cname policy-constraints
++id-ce 36		: policyConstraints	: X509v3 Policy Constraints
++!Cname ext-key-usage
++id-ce 37		: extendedKeyUsage	: X509v3 Extended Key Usage
++!Cname freshest-crl
++id-ce 46		: freshestCRL		: X509v3 Freshest CRL
++!Cname inhibit-any-policy
++id-ce 54		: inhibitAnyPolicy	: X509v3 Inhibit Any Policy
++!Cname target-information
++id-ce 55		: targetInformation	: X509v3 AC Targeting
++!Cname no-rev-avail
++id-ce 56		: noRevAvail		: X509v3 No Revocation Available
++
++# From RFC5280
++ext-key-usage 0		: anyExtendedKeyUsage	: Any Extended Key Usage
++
++
++!Cname netscape
++2 16 840 1 113730	: Netscape		: Netscape Communications Corp.
++!Cname netscape-cert-extension
++netscape 1		: nsCertExt		: Netscape Certificate Extension
++!Cname netscape-data-type
++netscape 2		: nsDataType		: Netscape Data Type
++!Cname netscape-cert-type
++netscape-cert-extension 1 : nsCertType		: Netscape Cert Type
++!Cname netscape-base-url
++netscape-cert-extension 2 : nsBaseUrl		: Netscape Base Url
++!Cname netscape-revocation-url
++netscape-cert-extension 3 : nsRevocationUrl	: Netscape Revocation Url
++!Cname netscape-ca-revocation-url
++netscape-cert-extension 4 : nsCaRevocationUrl	: Netscape CA Revocation Url
++!Cname netscape-renewal-url
++netscape-cert-extension 7 : nsRenewalUrl	: Netscape Renewal Url
++!Cname netscape-ca-policy-url
++netscape-cert-extension 8 : nsCaPolicyUrl	: Netscape CA Policy Url
++!Cname netscape-ssl-server-name
++netscape-cert-extension 12 : nsSslServerName	: Netscape SSL Server Name
++!Cname netscape-comment
++netscape-cert-extension 13 : nsComment		: Netscape Comment
++!Cname netscape-cert-sequence
++netscape-data-type 5	: nsCertSequence	: Netscape Certificate Sequence
++!Cname ns-sgc
++netscape 4 1		: nsSGC			: Netscape Server Gated Crypto
++
++# iso(1)
++iso 3			: ORG			: org
++org 6			: DOD			: dod
++dod 1			: IANA			: iana
++!Alias internet iana
++
++internet 1		: directory		: Directory
++internet 2		: mgmt			: Management
++internet 3		: experimental		: Experimental
++internet 4		: private		: Private
++internet 5		: security		: Security
++internet 6		: snmpv2		: SNMPv2
++# Documents refer to "internet 7" as "mail". This however leads to ambiguities
++# with RFC2798, Section 9.1.3, where "mail" is defined as the short name for
++# rfc822Mailbox. The short name is therefore here left out for a reason.
++# Subclasses of "mail", e.g. "MIME MHS" don't consitute a problem, as
++# references are realized via long name "Mail" (with capital M).
++internet 7		:			: Mail
++
++Private 1		: enterprises		: Enterprises
++
++# RFC 2247
++Enterprises 1466 344	: dcobject		: dcObject
++
++# RFC 1495
++Mail 1			: mime-mhs		: MIME MHS
++mime-mhs 1		: mime-mhs-headings	: mime-mhs-headings
++mime-mhs 2		: mime-mhs-bodies	: mime-mhs-bodies
++mime-mhs-headings 1	: id-hex-partial-message : id-hex-partial-message
++mime-mhs-headings 2	: id-hex-multipart-message : id-hex-multipart-message
++
++# RFC 3274
++!Cname zlib-compression
++id-smime-alg 8		: ZLIB			: zlib compression
++
++# AES aka Rijndael
++
++!Alias csor 2 16 840 1 101 3
++!Alias nistAlgorithms csor 4
++!Alias aes nistAlgorithms 1
++
++aes 1			: AES-128-ECB		: aes-128-ecb
++aes 2			: AES-128-CBC		: aes-128-cbc
++!Cname aes-128-ofb128
++aes 3			: AES-128-OFB		: aes-128-ofb
++!Cname aes-128-cfb128
++aes 4			: AES-128-CFB		: aes-128-cfb
++aes 5			: id-aes128-wrap
++aes 6			: id-aes128-GCM		: aes-128-gcm
++aes 7			: id-aes128-CCM		: aes-128-ccm
++aes 8			: id-aes128-wrap-pad
++
++aes 21			: AES-192-ECB		: aes-192-ecb
++aes 22			: AES-192-CBC		: aes-192-cbc
++!Cname aes-192-ofb128
++aes 23			: AES-192-OFB		: aes-192-ofb
++!Cname aes-192-cfb128
++aes 24			: AES-192-CFB		: aes-192-cfb
++aes 25			: id-aes192-wrap
++aes 26			: id-aes192-GCM		: aes-192-gcm
++aes 27			: id-aes192-CCM		: aes-192-ccm
++aes 28			: id-aes192-wrap-pad
++
++aes 41			: AES-256-ECB		: aes-256-ecb
++aes 42			: AES-256-CBC		: aes-256-cbc
++!Cname aes-256-ofb128
++aes 43			: AES-256-OFB		: aes-256-ofb
++!Cname aes-256-cfb128
++aes 44			: AES-256-CFB		: aes-256-cfb
++aes 45			: id-aes256-wrap
++aes 46			: id-aes256-GCM		: aes-256-gcm
++aes 47			: id-aes256-CCM		: aes-256-ccm
++aes 48			: id-aes256-wrap-pad
++
++# There are no OIDs for these modes...
++
++			: AES-128-CFB1		: aes-128-cfb1
++			: AES-192-CFB1		: aes-192-cfb1
++			: AES-256-CFB1		: aes-256-cfb1
++			: AES-128-CFB8		: aes-128-cfb8
++			: AES-192-CFB8		: aes-192-cfb8
++			: AES-256-CFB8		: aes-256-cfb8
++			: AES-128-CTR		: aes-128-ctr
++			: AES-192-CTR		: aes-192-ctr
++			: AES-256-CTR		: aes-256-ctr
++			: AES-128-OCB		: aes-128-ocb
++			: AES-192-OCB		: aes-192-ocb
++			: AES-256-OCB		: aes-256-ocb
++			: AES-128-XTS		: aes-128-xts
++			: AES-256-XTS		: aes-256-xts
++			: DES-CFB1		: des-cfb1
++			: DES-CFB8		: des-cfb8
++			: DES-EDE3-CFB1		: des-ede3-cfb1
++			: DES-EDE3-CFB8		: des-ede3-cfb8
++
++# OIDs for SHA224, SHA256, SHA385 and SHA512, according to x9.84.
++!Alias nist_hashalgs nistAlgorithms 2
++nist_hashalgs 1		: SHA256		: sha256
++nist_hashalgs 2		: SHA384		: sha384
++nist_hashalgs 3		: SHA512		: sha512
++nist_hashalgs 4		: SHA224		: sha224
++
++# OIDs for dsa-with-sha224 and dsa-with-sha256
++!Alias dsa_with_sha2 nistAlgorithms 3
++dsa_with_sha2 1		: dsa_with_SHA224
++dsa_with_sha2 2		: dsa_with_SHA256
++
++# Hold instruction CRL entry extension
++!Cname hold-instruction-code
++id-ce 23		: holdInstructionCode	: Hold Instruction Code
++!Alias holdInstruction	X9-57 2
++!Cname hold-instruction-none
++holdInstruction 1	: holdInstructionNone	: Hold Instruction None
++!Cname hold-instruction-call-issuer
++holdInstruction 2	: holdInstructionCallIssuer : Hold Instruction Call Issuer
++!Cname hold-instruction-reject
++holdInstruction 3	: holdInstructionReject	: Hold Instruction Reject
++
++# OID's from ITU-T.  Most of this is defined in RFC 1274.  A couple of
++# them are also mentioned in RFC 2247
++itu-t 9			: data
++data 2342		: pss
++pss 19200300		: ucl
++ucl 100			: pilot
++pilot 1			:			: pilotAttributeType
++pilot 3			:			: pilotAttributeSyntax
++pilot 4			:			: pilotObjectClass
++pilot 10		:			: pilotGroups
++pilotAttributeSyntax 4	:			: iA5StringSyntax
++pilotAttributeSyntax 5	:			: caseIgnoreIA5StringSyntax
++pilotObjectClass 3	:			: pilotObject
++pilotObjectClass 4	:			: pilotPerson
++pilotObjectClass 5	: account
++pilotObjectClass 6	: document
++pilotObjectClass 7	: room
++pilotObjectClass 9	:			: documentSeries
++pilotObjectClass 13	: domain		: Domain
++pilotObjectClass 14	:			: rFC822localPart
++pilotObjectClass 15	:			: dNSDomain
++pilotObjectClass 17	:			: domainRelatedObject
++pilotObjectClass 18	:			: friendlyCountry
++pilotObjectClass 19	:			: simpleSecurityObject
++pilotObjectClass 20	:			: pilotOrganization
++pilotObjectClass 21	:			: pilotDSA
++pilotObjectClass 22	:			: qualityLabelledData
++pilotAttributeType 1	: UID			: userId
++pilotAttributeType 2	:			: textEncodedORAddress
++pilotAttributeType 3	: mail			: rfc822Mailbox
++pilotAttributeType 4	: info
++pilotAttributeType 5	:			: favouriteDrink
++pilotAttributeType 6	:			: roomNumber
++pilotAttributeType 7	: photo
++pilotAttributeType 8	:			: userClass
++pilotAttributeType 9	: host
++pilotAttributeType 10	: manager
++pilotAttributeType 11	:			: documentIdentifier
++pilotAttributeType 12	:			: documentTitle
++pilotAttributeType 13	:			: documentVersion
++pilotAttributeType 14	:			: documentAuthor
++pilotAttributeType 15	:			: documentLocation
++pilotAttributeType 20	:			: homeTelephoneNumber
++pilotAttributeType 21	: secretary
++pilotAttributeType 22	:			: otherMailbox
++pilotAttributeType 23	:			: lastModifiedTime
++pilotAttributeType 24	:			: lastModifiedBy
++pilotAttributeType 25	: DC			: domainComponent
++pilotAttributeType 26	:			: aRecord
++pilotAttributeType 27	:			: pilotAttributeType27
++pilotAttributeType 28	:			: mXRecord
++pilotAttributeType 29	:			: nSRecord
++pilotAttributeType 30	:			: sOARecord
++pilotAttributeType 31	:			: cNAMERecord
++pilotAttributeType 37	:			: associatedDomain
++pilotAttributeType 38	:			: associatedName
++pilotAttributeType 39	:			: homePostalAddress
++pilotAttributeType 40	:			: personalTitle
++pilotAttributeType 41	:			: mobileTelephoneNumber
++pilotAttributeType 42	:			: pagerTelephoneNumber
++pilotAttributeType 43	:			: friendlyCountryName
++pilotAttributeType 44	: uid			: uniqueIdentifier
++pilotAttributeType 45	:			: organizationalStatus
++pilotAttributeType 46	:			: janetMailbox
++pilotAttributeType 47	:			: mailPreferenceOption
++pilotAttributeType 48	:			: buildingName
++pilotAttributeType 49	:			: dSAQuality
++pilotAttributeType 50	:			: singleLevelQuality
++pilotAttributeType 51	:			: subtreeMinimumQuality
++pilotAttributeType 52	:			: subtreeMaximumQuality
++pilotAttributeType 53	:			: personalSignature
++pilotAttributeType 54	:			: dITRedirect
++pilotAttributeType 55	: audio
++pilotAttributeType 56	:			: documentPublisher
++
++international-organizations 42	: id-set	: Secure Electronic Transactions
++
++id-set 0		: set-ctype		: content types
++id-set 1		: set-msgExt		: message extensions
++id-set 3		: set-attr
++id-set 5		: set-policy
++id-set 7		: set-certExt		: certificate extensions
++id-set 8		: set-brand
++
++set-ctype 0		: setct-PANData
++set-ctype 1		: setct-PANToken
++set-ctype 2		: setct-PANOnly
++set-ctype 3		: setct-OIData
++set-ctype 4		: setct-PI
++set-ctype 5		: setct-PIData
++set-ctype 6		: setct-PIDataUnsigned
++set-ctype 7		: setct-HODInput
++set-ctype 8		: setct-AuthResBaggage
++set-ctype 9		: setct-AuthRevReqBaggage
++set-ctype 10		: setct-AuthRevResBaggage
++set-ctype 11		: setct-CapTokenSeq
++set-ctype 12		: setct-PInitResData
++set-ctype 13		: setct-PI-TBS
++set-ctype 14		: setct-PResData
++set-ctype 16		: setct-AuthReqTBS
++set-ctype 17		: setct-AuthResTBS
++set-ctype 18		: setct-AuthResTBSX
++set-ctype 19		: setct-AuthTokenTBS
++set-ctype 20		: setct-CapTokenData
++set-ctype 21		: setct-CapTokenTBS
++set-ctype 22		: setct-AcqCardCodeMsg
++set-ctype 23		: setct-AuthRevReqTBS
++set-ctype 24		: setct-AuthRevResData
++set-ctype 25		: setct-AuthRevResTBS
++set-ctype 26		: setct-CapReqTBS
++set-ctype 27		: setct-CapReqTBSX
++set-ctype 28		: setct-CapResData
++set-ctype 29		: setct-CapRevReqTBS
++set-ctype 30		: setct-CapRevReqTBSX
++set-ctype 31		: setct-CapRevResData
++set-ctype 32		: setct-CredReqTBS
++set-ctype 33		: setct-CredReqTBSX
++set-ctype 34		: setct-CredResData
++set-ctype 35		: setct-CredRevReqTBS
++set-ctype 36		: setct-CredRevReqTBSX
++set-ctype 37		: setct-CredRevResData
++set-ctype 38		: setct-PCertReqData
++set-ctype 39		: setct-PCertResTBS
++set-ctype 40		: setct-BatchAdminReqData
++set-ctype 41		: setct-BatchAdminResData
++set-ctype 42		: setct-CardCInitResTBS
++set-ctype 43		: setct-MeAqCInitResTBS
++set-ctype 44		: setct-RegFormResTBS
++set-ctype 45		: setct-CertReqData
++set-ctype 46		: setct-CertReqTBS
++set-ctype 47		: setct-CertResData
++set-ctype 48		: setct-CertInqReqTBS
++set-ctype 49		: setct-ErrorTBS
++set-ctype 50		: setct-PIDualSignedTBE
++set-ctype 51		: setct-PIUnsignedTBE
++set-ctype 52		: setct-AuthReqTBE
++set-ctype 53		: setct-AuthResTBE
++set-ctype 54		: setct-AuthResTBEX
++set-ctype 55		: setct-AuthTokenTBE
++set-ctype 56		: setct-CapTokenTBE
++set-ctype 57		: setct-CapTokenTBEX
++set-ctype 58		: setct-AcqCardCodeMsgTBE
++set-ctype 59		: setct-AuthRevReqTBE
++set-ctype 60		: setct-AuthRevResTBE
++set-ctype 61		: setct-AuthRevResTBEB
++set-ctype 62		: setct-CapReqTBE
++set-ctype 63		: setct-CapReqTBEX
++set-ctype 64		: setct-CapResTBE
++set-ctype 65		: setct-CapRevReqTBE
++set-ctype 66		: setct-CapRevReqTBEX
++set-ctype 67		: setct-CapRevResTBE
++set-ctype 68		: setct-CredReqTBE
++set-ctype 69		: setct-CredReqTBEX
++set-ctype 70		: setct-CredResTBE
++set-ctype 71		: setct-CredRevReqTBE
++set-ctype 72		: setct-CredRevReqTBEX
++set-ctype 73		: setct-CredRevResTBE
++set-ctype 74		: setct-BatchAdminReqTBE
++set-ctype 75		: setct-BatchAdminResTBE
++set-ctype 76		: setct-RegFormReqTBE
++set-ctype 77		: setct-CertReqTBE
++set-ctype 78		: setct-CertReqTBEX
++set-ctype 79		: setct-CertResTBE
++set-ctype 80		: setct-CRLNotificationTBS
++set-ctype 81		: setct-CRLNotificationResTBS
++set-ctype 82		: setct-BCIDistributionTBS
++
++set-msgExt 1		: setext-genCrypt	: generic cryptogram
++set-msgExt 3		: setext-miAuth		: merchant initiated auth
++set-msgExt 4		: setext-pinSecure
++set-msgExt 5		: setext-pinAny
++set-msgExt 7		: setext-track2
++set-msgExt 8		: setext-cv		: additional verification
++
++set-policy 0		: set-policy-root
++
++set-certExt 0		: setCext-hashedRoot
++set-certExt 1		: setCext-certType
++set-certExt 2		: setCext-merchData
++set-certExt 3		: setCext-cCertRequired
++set-certExt 4		: setCext-tunneling
++set-certExt 5		: setCext-setExt
++set-certExt 6		: setCext-setQualf
++set-certExt 7		: setCext-PGWYcapabilities
++set-certExt 8		: setCext-TokenIdentifier
++set-certExt 9		: setCext-Track2Data
++set-certExt 10		: setCext-TokenType
++set-certExt 11		: setCext-IssuerCapabilities
++
++set-attr 0		: setAttr-Cert
++set-attr 1		: setAttr-PGWYcap	: payment gateway capabilities
++set-attr 2		: setAttr-TokenType
++set-attr 3		: setAttr-IssCap	: issuer capabilities
++
++setAttr-Cert 0		: set-rootKeyThumb
++setAttr-Cert 1		: set-addPolicy
++
++setAttr-TokenType 1	: setAttr-Token-EMV
++setAttr-TokenType 2	: setAttr-Token-B0Prime
++
++setAttr-IssCap 3	: setAttr-IssCap-CVM
++setAttr-IssCap 4	: setAttr-IssCap-T2
++setAttr-IssCap 5	: setAttr-IssCap-Sig
++
++setAttr-IssCap-CVM 1	: setAttr-GenCryptgrm	: generate cryptogram
++setAttr-IssCap-T2 1	: setAttr-T2Enc		: encrypted track 2
++setAttr-IssCap-T2 2	: setAttr-T2cleartxt	: cleartext track 2
++
++setAttr-IssCap-Sig 1	: setAttr-TokICCsig	: ICC or token signature
++setAttr-IssCap-Sig 2	: setAttr-SecDevSig	: secure device signature
++
++set-brand 1		: set-brand-IATA-ATA
++set-brand 30		: set-brand-Diners
++set-brand 34		: set-brand-AmericanExpress
++set-brand 35		: set-brand-JCB
++set-brand 4		: set-brand-Visa
++set-brand 5		: set-brand-MasterCard
++set-brand 6011		: set-brand-Novus
++
++rsadsi 3 10		: DES-CDMF		: des-cdmf
++rsadsi 1 1 6		: rsaOAEPEncryptionSET
++
++			: Oakley-EC2N-3		: ipsec3
++			: Oakley-EC2N-4		: ipsec4
++
++iso 0 10118 3 0 55	: whirlpool
++
++# GOST OIDs
++
++member-body 643 2 2	: cryptopro
++member-body 643 2 9	: cryptocom
++member-body 643 7 1	: id-tc26
++
++cryptopro 3		: id-GostR3411-94-with-GostR3410-2001 : GOST R 34.11-94 with GOST R 34.10-2001
++cryptopro 4		: id-GostR3411-94-with-GostR3410-94 : GOST R 34.11-94 with GOST R 34.10-94
++!Cname id-GostR3411-94
++cryptopro 9		: md_gost94		: GOST R 34.11-94
++cryptopro 10		: id-HMACGostR3411-94	: HMAC GOST 34.11-94
++!Cname id-GostR3410-2001
++cryptopro 19		: gost2001	: GOST R 34.10-2001
++!Cname id-GostR3410-94
++cryptopro 20		: gost94	: GOST R 34.10-94
++!Cname id-Gost28147-89
++cryptopro 21		: gost89 		: GOST 28147-89
++			: gost89-cnt
++			: gost89-cnt-12
++			: gost89-cbc
++			: gost89-ecb
++			: gost89-ctr
++!Cname id-Gost28147-89-MAC
++cryptopro 22		: gost-mac	: GOST 28147-89 MAC
++			: gost-mac-12
++!Cname id-GostR3411-94-prf
++cryptopro 23		: prf-gostr3411-94	: GOST R 34.11-94 PRF
++cryptopro 98		: id-GostR3410-2001DH	: GOST R 34.10-2001 DH
++cryptopro 99		: id-GostR3410-94DH	: GOST R 34.10-94 DH
++
++cryptopro 14 1		: id-Gost28147-89-CryptoPro-KeyMeshing
++cryptopro 14 0		: id-Gost28147-89-None-KeyMeshing
++
++# GOST parameter set OIDs
++
++cryptopro 30 0		: id-GostR3411-94-TestParamSet
++cryptopro 30 1		: id-GostR3411-94-CryptoProParamSet
++
++cryptopro 31 0		: id-Gost28147-89-TestParamSet
++cryptopro 31 1		: id-Gost28147-89-CryptoPro-A-ParamSet
++cryptopro 31 2		: id-Gost28147-89-CryptoPro-B-ParamSet
++cryptopro 31 3		: id-Gost28147-89-CryptoPro-C-ParamSet
++cryptopro 31 4		: id-Gost28147-89-CryptoPro-D-ParamSet
++cryptopro 31 5		: id-Gost28147-89-CryptoPro-Oscar-1-1-ParamSet
++cryptopro 31 6		: id-Gost28147-89-CryptoPro-Oscar-1-0-ParamSet
++cryptopro 31 7		: id-Gost28147-89-CryptoPro-RIC-1-ParamSet
++
++cryptopro 32 0		: id-GostR3410-94-TestParamSet
++cryptopro 32 2		: id-GostR3410-94-CryptoPro-A-ParamSet
++cryptopro 32 3		: id-GostR3410-94-CryptoPro-B-ParamSet
++cryptopro 32 4		: id-GostR3410-94-CryptoPro-C-ParamSet
++cryptopro 32 5		: id-GostR3410-94-CryptoPro-D-ParamSet
++
++cryptopro 33 1		: id-GostR3410-94-CryptoPro-XchA-ParamSet
++cryptopro 33 2		: id-GostR3410-94-CryptoPro-XchB-ParamSet
++cryptopro 33 3		: id-GostR3410-94-CryptoPro-XchC-ParamSet
++
++cryptopro 35 0		: id-GostR3410-2001-TestParamSet
++cryptopro 35 1		: id-GostR3410-2001-CryptoPro-A-ParamSet
++cryptopro 35 2		: id-GostR3410-2001-CryptoPro-B-ParamSet
++cryptopro 35 3		: id-GostR3410-2001-CryptoPro-C-ParamSet
++
++cryptopro 36 0		: id-GostR3410-2001-CryptoPro-XchA-ParamSet
++cryptopro 36 1		: id-GostR3410-2001-CryptoPro-XchB-ParamSet
++
++id-GostR3410-94 1	: id-GostR3410-94-a
++id-GostR3410-94 2	: id-GostR3410-94-aBis
++id-GostR3410-94 3	: id-GostR3410-94-b
++id-GostR3410-94 4	: id-GostR3410-94-bBis
++
++# Cryptocom LTD GOST OIDs
++
++cryptocom 1 6 1		: id-Gost28147-89-cc	: GOST 28147-89 Cryptocom ParamSet
++!Cname id-GostR3410-94-cc
++cryptocom 1 5 3		: gost94cc	: GOST 34.10-94 Cryptocom
++!Cname id-GostR3410-2001-cc
++cryptocom 1 5 4		: gost2001cc	: GOST 34.10-2001 Cryptocom
++
++cryptocom 1 3 3		: id-GostR3411-94-with-GostR3410-94-cc : GOST R 34.11-94 with GOST R 34.10-94 Cryptocom
++cryptocom 1 3 4		: id-GostR3411-94-with-GostR3410-2001-cc : GOST R 34.11-94 with GOST R 34.10-2001 Cryptocom
++
++cryptocom 1 8 1		: id-GostR3410-2001-ParamSet-cc : GOST R 3410-2001 Parameter Set Cryptocom
++
++# TC26 GOST OIDs
++
++id-tc26 1 		: id-tc26-algorithms
++id-tc26-algorithms 1	: id-tc26-sign
++!Cname id-GostR3410-2012-256
++id-tc26-sign 1		: gost2012_256: GOST R 34.10-2012 with 256 bit modulus
++!Cname id-GostR3410-2012-512
++id-tc26-sign 2		: gost2012_512: GOST R 34.10-2012 with 512 bit modulus
++
++id-tc26-algorithms 2	: id-tc26-digest
++!Cname id-GostR3411-2012-256
++id-tc26-digest 2	: md_gost12_256: GOST R 34.11-2012 with 256 bit hash
++!Cname id-GostR3411-2012-512
++id-tc26-digest 3	: md_gost12_512: GOST R 34.11-2012 with 512 bit hash
++
++id-tc26-algorithms 3	: id-tc26-signwithdigest
++id-tc26-signwithdigest 2: id-tc26-signwithdigest-gost3410-2012-256: GOST R 34.10-2012 with GOST R 34.11-2012 (256 bit)
++id-tc26-signwithdigest 3: id-tc26-signwithdigest-gost3410-2012-512: GOST R 34.10-2012 with GOST R 34.11-2012 (512 bit)
++
++id-tc26-algorithms 4	: id-tc26-mac
++id-tc26-mac 1		: id-tc26-hmac-gost-3411-2012-256 : HMAC GOST 34.11-2012 256 bit
++id-tc26-mac 2		: id-tc26-hmac-gost-3411-2012-512 : HMAC GOST 34.11-2012 512 bit
++
++id-tc26-algorithms 5	: id-tc26-cipher
++
++id-tc26-algorithms 6	: id-tc26-agreement
++id-tc26-agreement 1	: id-tc26-agreement-gost-3410-2012-256
++id-tc26-agreement 2	: id-tc26-agreement-gost-3410-2012-512
++
++id-tc26 2 		: id-tc26-constants
++
++id-tc26-constants 1	: id-tc26-sign-constants
++id-tc26-sign-constants 2: id-tc26-gost-3410-2012-512-constants
++id-tc26-gost-3410-2012-512-constants 0	: id-tc26-gost-3410-2012-512-paramSetTest: GOST R 34.10-2012 (512 bit) testing parameter set
++id-tc26-gost-3410-2012-512-constants 1	: id-tc26-gost-3410-2012-512-paramSetA: GOST R 34.10-2012 (512 bit) ParamSet A
++id-tc26-gost-3410-2012-512-constants 2	: id-tc26-gost-3410-2012-512-paramSetB: GOST R 34.10-2012 (512 bit) ParamSet B
++
++id-tc26-constants 2     : id-tc26-digest-constants
++id-tc26-constants 5     : id-tc26-cipher-constants
++id-tc26-cipher-constants 1	: id-tc26-gost-28147-constants
++id-tc26-gost-28147-constants 1	: id-tc26-gost-28147-param-Z : GOST 28147-89 TC26 parameter set
++
++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 111	: subjectSignTool	: Signing Tool of Subject
++member-body 643 100 112	: issuerSignTool	: Signing Tool of Issuer
++
++#GOST R34.13-2015 Grasshopper "Kuznechik"
++			: grasshopper-ecb
++			: grasshopper-ctr
++			: grasshopper-ofb
++			: grasshopper-cbc
++			: grasshopper-cfb
++			: grasshopper-mac
++
++# Definitions for Camellia cipher - CBC MODE
++
++1 2 392 200011 61 1 1 1 2 : CAMELLIA-128-CBC		: camellia-128-cbc
++1 2 392 200011 61 1 1 1 3 : CAMELLIA-192-CBC		: camellia-192-cbc
++1 2 392 200011 61 1 1 1 4 : CAMELLIA-256-CBC		: camellia-256-cbc
++1 2 392 200011 61 1 1 3 2 : id-camellia128-wrap
++1 2 392 200011 61 1 1 3 3 : id-camellia192-wrap
++1 2 392 200011 61 1 1 3 4 : id-camellia256-wrap
++
++# Definitions for Camellia cipher - ECB, CFB, OFB MODE
++
++!Alias ntt-ds 0 3 4401 5
++!Alias camellia ntt-ds 3 1 9 
++
++camellia 1		: CAMELLIA-128-ECB		: camellia-128-ecb
++!Cname camellia-128-ofb128
++camellia 3		: CAMELLIA-128-OFB		: camellia-128-ofb
++!Cname camellia-128-cfb128
++camellia 4		: CAMELLIA-128-CFB		: camellia-128-cfb
++camellia 6		: CAMELLIA-128-GCM		: camellia-128-gcm
++camellia 7		: CAMELLIA-128-CCM		: camellia-128-ccm
++camellia 9		: CAMELLIA-128-CTR		: camellia-128-ctr
++camellia 10		: CAMELLIA-128-CMAC		: camellia-128-cmac
++
++camellia 21		: CAMELLIA-192-ECB		: camellia-192-ecb
++!Cname camellia-192-ofb128
++camellia 23		: CAMELLIA-192-OFB		: camellia-192-ofb
++!Cname camellia-192-cfb128
++camellia 24		: CAMELLIA-192-CFB		: camellia-192-cfb
++camellia 26		: CAMELLIA-192-GCM		: camellia-192-gcm
++camellia 27		: CAMELLIA-192-CCM		: camellia-192-ccm
++camellia 29		: CAMELLIA-192-CTR		: camellia-192-ctr
++camellia 30		: CAMELLIA-192-CMAC		: camellia-192-cmac
++
++camellia 41		: CAMELLIA-256-ECB		: camellia-256-ecb
++!Cname camellia-256-ofb128
++camellia 43		: CAMELLIA-256-OFB		: camellia-256-ofb
++!Cname camellia-256-cfb128
++camellia 44		: CAMELLIA-256-CFB		: camellia-256-cfb
++camellia 46		: CAMELLIA-256-GCM		: camellia-256-gcm
++camellia 47		: CAMELLIA-256-CCM		: camellia-256-ccm
++camellia 49		: CAMELLIA-256-CTR		: camellia-256-ctr
++camellia 50		: CAMELLIA-256-CMAC		: camellia-256-cmac
++
++# There are no OIDs for these modes...
++
++			: CAMELLIA-128-CFB1		: camellia-128-cfb1
++			: CAMELLIA-192-CFB1		: camellia-192-cfb1
++			: CAMELLIA-256-CFB1		: camellia-256-cfb1
++			: CAMELLIA-128-CFB8		: camellia-128-cfb8
++			: CAMELLIA-192-CFB8		: camellia-192-cfb8
++			: CAMELLIA-256-CFB8		: camellia-256-cfb8
++
++# Definitions for SEED cipher - ECB, CBC, OFB mode
++
++member-body 410 200004  : KISA          : kisa
++kisa 1 3                : SEED-ECB      : seed-ecb
++kisa 1 4                : SEED-CBC      : seed-cbc
++!Cname seed-cfb128
++kisa 1 5                : SEED-CFB      : seed-cfb
++!Cname seed-ofb128
++kisa 1 6                : SEED-OFB      : seed-ofb
++
++# There is no OID that just denotes "HMAC" oddly enough...
++
++			: HMAC				: hmac
++# Nor CMAC either
++			: CMAC				: cmac
++
++# Synthetic composite ciphersuites
++			: RC4-HMAC-MD5			: rc4-hmac-md5
++			: AES-128-CBC-HMAC-SHA1		: aes-128-cbc-hmac-sha1
++			: AES-192-CBC-HMAC-SHA1		: aes-192-cbc-hmac-sha1
++			: AES-256-CBC-HMAC-SHA1		: aes-256-cbc-hmac-sha1
++			: AES-128-CBC-HMAC-SHA256	: aes-128-cbc-hmac-sha256
++			: AES-192-CBC-HMAC-SHA256	: aes-192-cbc-hmac-sha256
++			: AES-256-CBC-HMAC-SHA256	: aes-256-cbc-hmac-sha256
++			: ChaCha20-Poly1305		: chacha20-poly1305
++			: ChaCha20			: chacha20
++
++ISO-US 10046 2 1	: dhpublicnumber		: X9.42 DH
++
++# RFC 5639 curve OIDs (see http://www.ietf.org/rfc/rfc5639.txt)
++# versionOne OBJECT IDENTIFIER ::= {
++# iso(1) identifified-organization(3) teletrust(36) algorithm(3)
++# signature-algorithm(3) ecSign(2) ecStdCurvesAndGeneration(8)
++# ellipticCurve(1) 1 }
++1 3 36 3 3 2 8 1 1 1 : brainpoolP160r1
++1 3 36 3 3 2 8 1 1 2 : brainpoolP160t1
++1 3 36 3 3 2 8 1 1 3 : brainpoolP192r1
++1 3 36 3 3 2 8 1 1 4 : brainpoolP192t1
++1 3 36 3 3 2 8 1 1 5 : brainpoolP224r1
++1 3 36 3 3 2 8 1 1 6 : brainpoolP224t1
++1 3 36 3 3 2 8 1 1 7 : brainpoolP256r1
++1 3 36 3 3 2 8 1 1 8 : brainpoolP256t1
++1 3 36 3 3 2 8 1 1 9 : brainpoolP320r1
++1 3 36 3 3 2 8 1 1 10 : brainpoolP320t1
++1 3 36 3 3 2 8 1 1 11 : brainpoolP384r1
++1 3 36 3 3 2 8 1 1 12 : brainpoolP384t1
++1 3 36 3 3 2 8 1 1 13 : brainpoolP512r1
++1 3 36 3 3 2 8 1 1 14 : brainpoolP512t1            
++
++# ECDH schemes from RFC5753
++!Alias x9-63-scheme 1 3 133 16 840 63 0
++!Alias secg-scheme certicom-arc 1
++
++x9-63-scheme 2   : dhSinglePass-stdDH-sha1kdf-scheme
++secg-scheme 11 0 : dhSinglePass-stdDH-sha224kdf-scheme
++secg-scheme 11 1 : dhSinglePass-stdDH-sha256kdf-scheme
++secg-scheme 11 2 : dhSinglePass-stdDH-sha384kdf-scheme
++secg-scheme 11 3 : dhSinglePass-stdDH-sha512kdf-scheme
++
++x9-63-scheme 3   : dhSinglePass-cofactorDH-sha1kdf-scheme
++secg-scheme 14 0 : dhSinglePass-cofactorDH-sha224kdf-scheme
++secg-scheme 14 1 : dhSinglePass-cofactorDH-sha256kdf-scheme
++secg-scheme 14 2 : dhSinglePass-cofactorDH-sha384kdf-scheme
++secg-scheme 14 3 : dhSinglePass-cofactorDH-sha512kdf-scheme
++# NIDs for use with lookup tables.
++                 : dh-std-kdf
++                 : dh-cofactor-kdf
++
++# RFC 6962 Extension OIDs (see http://www.ietf.org/rfc/rfc6962.txt)
++1 3 6 1 4 1 11129 2 4 2	: ct_precert_scts		: CT Precertificate SCTs
++1 3 6 1 4 1 11129 2 4 3	: ct_precert_poison		: CT Precertificate Poison
++1 3 6 1 4 1 11129 2 4 4	: ct_precert_signer		: CT Precertificate Signer
++1 3 6 1 4 1 11129 2 4 5	: ct_cert_scts			: CT Certificate SCTs
++
++# CABForum EV SSL Certificate Guidelines
++# (see https://cabforum.org/extended-validation/)
++# OIDs for Subject Jurisdiction of Incorporation or Registration
++1 3 6 1 4 1 311 60 2 1 1	: jurisdictionL		: jurisdictionLocalityName
++1 3 6 1 4 1 311 60 2 1 2	: jurisdictionST	: jurisdictionStateOrProvinceName
++1 3 6 1 4 1 311 60 2 1 3	: jurisdictionC		: jurisdictionCountryName
++
++# SCRYPT algorithm
++1 3 6 1 4 1 11591 4 11		: id-scrypt
++
++# NID for TLS1 PRF
++                            : TLS1-PRF          : tls1-prf
++
++# NID for HKDF
++                            : HKDF              : hkdf
++
++# RFC 4556
++1 3 6 1 5 2 3 : id-pkinit
++id-pkinit 4                     : pkInitClientAuth      : PKINIT Client Auth
++id-pkinit 5                     : pkInitKDC             : Signing KDC Response
++
++# New curves from draft-ietf-curdle-pkix-00
++1 3 101 110 : X25519
++1 3 101 111 : X448
++
++# NIDs for cipher key exchange
++                            : KxRSA        : kx-rsa
++                            : KxECDHE      : kx-ecdhe
++                            : KxDHE        : kx-dhe
++                            : KxECDHE-PSK  : kx-ecdhe-psk
++                            : KxDHE-PSK    : kx-dhe-psk
++                            : KxRSA_PSK    : kx-rsa-psk
++                            : KxPSK        : kx-psk
++                            : KxSRP        : kx-srp
++                            : KxGOST       : kx-gost
++
++# NIDs for cipher authentication
++                            : AuthRSA      : auth-rsa
++                            : AuthECDSA    : auth-ecdsa
++                            : AuthPSK      : auth-psk
++                            : AuthDSS      : auth-dss
++                            : AuthGOST01   : auth-gost01
++                            : AuthGOST12   : auth-gost12
++                            : AuthSRP      : auth-srp
++                            : AuthNULL     : auth-null
++
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/objects/objxref.pl b/CryptoPkg/Library/OpensslLib/openssl/crypto/objects/objxref.pl
+new file mode 100644
+index 0000000..53f9bd6
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/objects/objxref.pl
+@@ -0,0 +1,135 @@
++#! /usr/bin/env perl
++# Copyright 1998-2016 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
++# in the file LICENSE in the source distribution or at
++# https://www.openssl.org/source/license.html
++
++
++use strict;
++
++my %xref_tbl;
++my %oid_tbl;
++
++my ($mac_file, $xref_file) = @ARGV;
++
++open(IN, $mac_file) || die "Can't open $mac_file, $!\n";
++
++# Read in OID nid values for a lookup table.
++
++while ()
++	{
++	s|\R$||;                # Better chomp
++	my ($name, $num) = /^(\S+)\s+(\S+)$/;
++	$oid_tbl{$name} = $num;
++	}
++close IN;
++
++open(IN, $xref_file) || die "Can't open $xref_file, $!\n";
++
++my $ln = 1;
++
++while ()
++	{
++	s|\R$||;                # Better chomp
++	s/#.*$//;
++	next if (/^\S*$/);
++	my ($xr, $p1, $p2) = /^(\S+)\s+(\S+)\s+(\S+)/;
++	check_oid($xr);
++	check_oid($p1);
++	check_oid($p2);
++	$xref_tbl{$xr} = [$p1, $p2, $ln];
++	}
++
++my @xrkeys = keys %xref_tbl;
++
++my @srt1 = sort { $oid_tbl{$a} <=> $oid_tbl{$b}} @xrkeys;
++
++my $i;
++for($i = 0; $i <= $#srt1; $i++)
++	{
++	$xref_tbl{$srt1[$i]}[2] = $i;
++	}
++
++my @srt2 = sort
++	{
++	my$ap1 = $oid_tbl{$xref_tbl{$a}[0]};
++	my$bp1 = $oid_tbl{$xref_tbl{$b}[0]};
++	return $ap1 - $bp1 if ($ap1 != $bp1);
++	my$ap2 = $oid_tbl{$xref_tbl{$a}[1]};
++	my$bp2 = $oid_tbl{$xref_tbl{$b}[1]};
++
++	return $ap2 - $bp2;
++	} @xrkeys;
++
++my $pname = $0;
++$pname =~ s|.*/||;
++
++print <
++#include 
++#include 
++#include "ocsp_lcl.h"
++
++ASN1_SEQUENCE(OCSP_SIGNATURE) = {
++        ASN1_EMBED(OCSP_SIGNATURE, signatureAlgorithm, X509_ALGOR),
++        ASN1_SIMPLE(OCSP_SIGNATURE, signature, ASN1_BIT_STRING),
++        ASN1_EXP_SEQUENCE_OF_OPT(OCSP_SIGNATURE, certs, X509, 0)
++} ASN1_SEQUENCE_END(OCSP_SIGNATURE)
++
++IMPLEMENT_ASN1_FUNCTIONS(OCSP_SIGNATURE)
++
++ASN1_SEQUENCE(OCSP_CERTID) = {
++        ASN1_EMBED(OCSP_CERTID, hashAlgorithm, X509_ALGOR),
++        ASN1_EMBED(OCSP_CERTID, issuerNameHash, ASN1_OCTET_STRING),
++        ASN1_EMBED(OCSP_CERTID, issuerKeyHash, ASN1_OCTET_STRING),
++        ASN1_EMBED(OCSP_CERTID, serialNumber, ASN1_INTEGER)
++} ASN1_SEQUENCE_END(OCSP_CERTID)
++
++IMPLEMENT_ASN1_FUNCTIONS(OCSP_CERTID)
++
++ASN1_SEQUENCE(OCSP_ONEREQ) = {
++        ASN1_SIMPLE(OCSP_ONEREQ, reqCert, OCSP_CERTID),
++        ASN1_EXP_SEQUENCE_OF_OPT(OCSP_ONEREQ, singleRequestExtensions, X509_EXTENSION, 0)
++} ASN1_SEQUENCE_END(OCSP_ONEREQ)
++
++IMPLEMENT_ASN1_FUNCTIONS(OCSP_ONEREQ)
++
++ASN1_SEQUENCE(OCSP_REQINFO) = {
++        ASN1_EXP_OPT(OCSP_REQINFO, version, ASN1_INTEGER, 0),
++        ASN1_EXP_OPT(OCSP_REQINFO, requestorName, GENERAL_NAME, 1),
++        ASN1_SEQUENCE_OF(OCSP_REQINFO, requestList, OCSP_ONEREQ),
++        ASN1_EXP_SEQUENCE_OF_OPT(OCSP_REQINFO, requestExtensions, X509_EXTENSION, 2)
++} ASN1_SEQUENCE_END(OCSP_REQINFO)
++
++IMPLEMENT_ASN1_FUNCTIONS(OCSP_REQINFO)
++
++ASN1_SEQUENCE(OCSP_REQUEST) = {
++        ASN1_EMBED(OCSP_REQUEST, tbsRequest, OCSP_REQINFO),
++        ASN1_EXP_OPT(OCSP_REQUEST, optionalSignature, OCSP_SIGNATURE, 0)
++} ASN1_SEQUENCE_END(OCSP_REQUEST)
++
++IMPLEMENT_ASN1_FUNCTIONS(OCSP_REQUEST)
++
++/* OCSP_RESPONSE templates */
++
++ASN1_SEQUENCE(OCSP_RESPBYTES) = {
++            ASN1_SIMPLE(OCSP_RESPBYTES, responseType, ASN1_OBJECT),
++            ASN1_SIMPLE(OCSP_RESPBYTES, response, ASN1_OCTET_STRING)
++} ASN1_SEQUENCE_END(OCSP_RESPBYTES)
++
++IMPLEMENT_ASN1_FUNCTIONS(OCSP_RESPBYTES)
++
++ASN1_SEQUENCE(OCSP_RESPONSE) = {
++        ASN1_SIMPLE(OCSP_RESPONSE, responseStatus, ASN1_ENUMERATED),
++        ASN1_EXP_OPT(OCSP_RESPONSE, responseBytes, OCSP_RESPBYTES, 0)
++} ASN1_SEQUENCE_END(OCSP_RESPONSE)
++
++IMPLEMENT_ASN1_FUNCTIONS(OCSP_RESPONSE)
++
++ASN1_CHOICE(OCSP_RESPID) = {
++           ASN1_EXP(OCSP_RESPID, value.byName, X509_NAME, 1),
++           ASN1_EXP(OCSP_RESPID, value.byKey, ASN1_OCTET_STRING, 2)
++} ASN1_CHOICE_END(OCSP_RESPID)
++
++IMPLEMENT_ASN1_FUNCTIONS(OCSP_RESPID)
++
++ASN1_SEQUENCE(OCSP_REVOKEDINFO) = {
++        ASN1_SIMPLE(OCSP_REVOKEDINFO, revocationTime, ASN1_GENERALIZEDTIME),
++        ASN1_EXP_OPT(OCSP_REVOKEDINFO, revocationReason, ASN1_ENUMERATED, 0)
++} ASN1_SEQUENCE_END(OCSP_REVOKEDINFO)
++
++IMPLEMENT_ASN1_FUNCTIONS(OCSP_REVOKEDINFO)
++
++ASN1_CHOICE(OCSP_CERTSTATUS) = {
++        ASN1_IMP(OCSP_CERTSTATUS, value.good, ASN1_NULL, 0),
++        ASN1_IMP(OCSP_CERTSTATUS, value.revoked, OCSP_REVOKEDINFO, 1),
++        ASN1_IMP(OCSP_CERTSTATUS, value.unknown, ASN1_NULL, 2)
++} ASN1_CHOICE_END(OCSP_CERTSTATUS)
++
++IMPLEMENT_ASN1_FUNCTIONS(OCSP_CERTSTATUS)
++
++ASN1_SEQUENCE(OCSP_SINGLERESP) = {
++           ASN1_SIMPLE(OCSP_SINGLERESP, certId, OCSP_CERTID),
++           ASN1_SIMPLE(OCSP_SINGLERESP, certStatus, OCSP_CERTSTATUS),
++           ASN1_SIMPLE(OCSP_SINGLERESP, thisUpdate, ASN1_GENERALIZEDTIME),
++           ASN1_EXP_OPT(OCSP_SINGLERESP, nextUpdate, ASN1_GENERALIZEDTIME, 0),
++           ASN1_EXP_SEQUENCE_OF_OPT(OCSP_SINGLERESP, singleExtensions, X509_EXTENSION, 1)
++} ASN1_SEQUENCE_END(OCSP_SINGLERESP)
++
++IMPLEMENT_ASN1_FUNCTIONS(OCSP_SINGLERESP)
++
++ASN1_SEQUENCE(OCSP_RESPDATA) = {
++           ASN1_EXP_OPT(OCSP_RESPDATA, version, ASN1_INTEGER, 0),
++           ASN1_EMBED(OCSP_RESPDATA, responderId, OCSP_RESPID),
++           ASN1_SIMPLE(OCSP_RESPDATA, producedAt, ASN1_GENERALIZEDTIME),
++           ASN1_SEQUENCE_OF(OCSP_RESPDATA, responses, OCSP_SINGLERESP),
++           ASN1_EXP_SEQUENCE_OF_OPT(OCSP_RESPDATA, responseExtensions, X509_EXTENSION, 1)
++} ASN1_SEQUENCE_END(OCSP_RESPDATA)
++
++IMPLEMENT_ASN1_FUNCTIONS(OCSP_RESPDATA)
++
++ASN1_SEQUENCE(OCSP_BASICRESP) = {
++           ASN1_EMBED(OCSP_BASICRESP, tbsResponseData, OCSP_RESPDATA),
++           ASN1_EMBED(OCSP_BASICRESP, signatureAlgorithm, X509_ALGOR),
++           ASN1_SIMPLE(OCSP_BASICRESP, signature, ASN1_BIT_STRING),
++           ASN1_EXP_SEQUENCE_OF_OPT(OCSP_BASICRESP, certs, X509, 0)
++} ASN1_SEQUENCE_END(OCSP_BASICRESP)
++
++IMPLEMENT_ASN1_FUNCTIONS(OCSP_BASICRESP)
++
++ASN1_SEQUENCE(OCSP_CRLID) = {
++           ASN1_EXP_OPT(OCSP_CRLID, crlUrl, ASN1_IA5STRING, 0),
++           ASN1_EXP_OPT(OCSP_CRLID, crlNum, ASN1_INTEGER, 1),
++           ASN1_EXP_OPT(OCSP_CRLID, crlTime, ASN1_GENERALIZEDTIME, 2)
++} ASN1_SEQUENCE_END(OCSP_CRLID)
++
++IMPLEMENT_ASN1_FUNCTIONS(OCSP_CRLID)
++
++ASN1_SEQUENCE(OCSP_SERVICELOC) = {
++        ASN1_SIMPLE(OCSP_SERVICELOC, issuer, X509_NAME),
++        ASN1_SEQUENCE_OF_OPT(OCSP_SERVICELOC, locator, ACCESS_DESCRIPTION)
++} ASN1_SEQUENCE_END(OCSP_SERVICELOC)
++
++IMPLEMENT_ASN1_FUNCTIONS(OCSP_SERVICELOC)
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/ocsp/ocsp_cl.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/ocsp/ocsp_cl.c
+new file mode 100644
+index 0000000..a42b80f
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/ocsp/ocsp_cl.c
+@@ -0,0 +1,365 @@
++/*
++ * Copyright 2001-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include 
++#include "internal/cryptlib.h"
++#include 
++#include 
++#include 
++#include 
++#include 
++#include "ocsp_lcl.h"
++
++/*
++ * Utility functions related to sending OCSP requests and extracting relevant
++ * information from the response.
++ */
++
++/*
++ * Add an OCSP_CERTID to an OCSP request. Return new OCSP_ONEREQ pointer:
++ * useful if we want to add extensions.
++ */
++
++OCSP_ONEREQ *OCSP_request_add0_id(OCSP_REQUEST *req, OCSP_CERTID *cid)
++{
++    OCSP_ONEREQ *one = NULL;
++
++    if ((one = OCSP_ONEREQ_new()) == NULL)
++        return NULL;
++    OCSP_CERTID_free(one->reqCert);
++    one->reqCert = cid;
++    if (req && !sk_OCSP_ONEREQ_push(req->tbsRequest.requestList, one)) {
++        one->reqCert = NULL; /* do not free on error */
++        goto err;
++    }
++    return one;
++ err:
++    OCSP_ONEREQ_free(one);
++    return NULL;
++}
++
++/* Set requestorName from an X509_NAME structure */
++
++int OCSP_request_set1_name(OCSP_REQUEST *req, X509_NAME *nm)
++{
++    GENERAL_NAME *gen;
++
++    gen = GENERAL_NAME_new();
++    if (gen == NULL)
++        return 0;
++    if (!X509_NAME_set(&gen->d.directoryName, nm)) {
++        GENERAL_NAME_free(gen);
++        return 0;
++    }
++    gen->type = GEN_DIRNAME;
++    GENERAL_NAME_free(req->tbsRequest.requestorName);
++    req->tbsRequest.requestorName = gen;
++    return 1;
++}
++
++/* Add a certificate to an OCSP request */
++
++int OCSP_request_add1_cert(OCSP_REQUEST *req, X509 *cert)
++{
++    OCSP_SIGNATURE *sig;
++    if (req->optionalSignature == NULL)
++        req->optionalSignature = OCSP_SIGNATURE_new();
++    sig = req->optionalSignature;
++    if (sig == NULL)
++        return 0;
++    if (cert == NULL)
++        return 1;
++    if (sig->certs == NULL
++        && (sig->certs = sk_X509_new_null()) == NULL)
++        return 0;
++
++    if (!sk_X509_push(sig->certs, cert))
++        return 0;
++    X509_up_ref(cert);
++    return 1;
++}
++
++/*
++ * Sign an OCSP request set the requestorName to the subject name of an
++ * optional signers certificate and include one or more optional certificates
++ * in the request. Behaves like PKCS7_sign().
++ */
++
++int OCSP_request_sign(OCSP_REQUEST *req,
++                      X509 *signer,
++                      EVP_PKEY *key,
++                      const EVP_MD *dgst,
++                      STACK_OF(X509) *certs, unsigned long flags)
++{
++    int i;
++    X509 *x;
++
++    if (!OCSP_request_set1_name(req, X509_get_subject_name(signer)))
++        goto err;
++
++    if ((req->optionalSignature = OCSP_SIGNATURE_new()) == NULL)
++        goto err;
++    if (key) {
++        if (!X509_check_private_key(signer, key)) {
++            OCSPerr(OCSP_F_OCSP_REQUEST_SIGN,
++                    OCSP_R_PRIVATE_KEY_DOES_NOT_MATCH_CERTIFICATE);
++            goto err;
++        }
++        if (!OCSP_REQUEST_sign(req, key, dgst))
++            goto err;
++    }
++
++    if (!(flags & OCSP_NOCERTS)) {
++        if (!OCSP_request_add1_cert(req, signer))
++            goto err;
++        for (i = 0; i < sk_X509_num(certs); i++) {
++            x = sk_X509_value(certs, i);
++            if (!OCSP_request_add1_cert(req, x))
++                goto err;
++        }
++    }
++
++    return 1;
++ err:
++    OCSP_SIGNATURE_free(req->optionalSignature);
++    req->optionalSignature = NULL;
++    return 0;
++}
++
++/* Get response status */
++
++int OCSP_response_status(OCSP_RESPONSE *resp)
++{
++    return ASN1_ENUMERATED_get(resp->responseStatus);
++}
++
++/*
++ * Extract basic response from OCSP_RESPONSE or NULL if no basic response
++ * present.
++ */
++
++OCSP_BASICRESP *OCSP_response_get1_basic(OCSP_RESPONSE *resp)
++{
++    OCSP_RESPBYTES *rb;
++    rb = resp->responseBytes;
++    if (!rb) {
++        OCSPerr(OCSP_F_OCSP_RESPONSE_GET1_BASIC, OCSP_R_NO_RESPONSE_DATA);
++        return NULL;
++    }
++    if (OBJ_obj2nid(rb->responseType) != NID_id_pkix_OCSP_basic) {
++        OCSPerr(OCSP_F_OCSP_RESPONSE_GET1_BASIC, OCSP_R_NOT_BASIC_RESPONSE);
++        return NULL;
++    }
++
++    return ASN1_item_unpack(rb->response, ASN1_ITEM_rptr(OCSP_BASICRESP));
++}
++
++const ASN1_OCTET_STRING *OCSP_resp_get0_signature(const OCSP_BASICRESP *bs)
++{
++    return bs->signature;
++}
++
++/*
++ * Return number of OCSP_SINGLERESP responses present in a basic response.
++ */
++
++int OCSP_resp_count(OCSP_BASICRESP *bs)
++{
++    if (!bs)
++        return -1;
++    return sk_OCSP_SINGLERESP_num(bs->tbsResponseData.responses);
++}
++
++/* Extract an OCSP_SINGLERESP response with a given index */
++
++OCSP_SINGLERESP *OCSP_resp_get0(OCSP_BASICRESP *bs, int idx)
++{
++    if (!bs)
++        return NULL;
++    return sk_OCSP_SINGLERESP_value(bs->tbsResponseData.responses, idx);
++}
++
++const ASN1_GENERALIZEDTIME *OCSP_resp_get0_produced_at(const OCSP_BASICRESP* bs)
++{
++    return bs->tbsResponseData.producedAt;
++}
++
++const STACK_OF(X509) *OCSP_resp_get0_certs(const OCSP_BASICRESP *bs)
++{
++    return bs->certs;
++}
++
++int OCSP_resp_get0_id(const OCSP_BASICRESP *bs,
++                      const ASN1_OCTET_STRING **pid,
++                      const X509_NAME **pname)
++
++{
++    const OCSP_RESPID *rid = &bs->tbsResponseData.responderId;
++    if (rid->type == V_OCSP_RESPID_NAME) {
++        *pname = rid->value.byName;
++        *pid = NULL;
++    } else if (rid->type == V_OCSP_RESPID_KEY) {
++        *pid = rid->value.byKey;
++        *pname = NULL;
++    } else {
++        return 0;
++    }
++    return 1;
++}
++
++/* Look single response matching a given certificate ID */
++
++int OCSP_resp_find(OCSP_BASICRESP *bs, OCSP_CERTID *id, int last)
++{
++    int i;
++    STACK_OF(OCSP_SINGLERESP) *sresp;
++    OCSP_SINGLERESP *single;
++    if (!bs)
++        return -1;
++    if (last < 0)
++        last = 0;
++    else
++        last++;
++    sresp = bs->tbsResponseData.responses;
++    for (i = last; i < sk_OCSP_SINGLERESP_num(sresp); i++) {
++        single = sk_OCSP_SINGLERESP_value(sresp, i);
++        if (!OCSP_id_cmp(id, single->certId))
++            return i;
++    }
++    return -1;
++}
++
++/*
++ * Extract status information from an OCSP_SINGLERESP structure. Note: the
++ * revtime and reason values are only set if the certificate status is
++ * revoked. Returns numerical value of status.
++ */
++
++int OCSP_single_get0_status(OCSP_SINGLERESP *single, int *reason,
++                            ASN1_GENERALIZEDTIME **revtime,
++                            ASN1_GENERALIZEDTIME **thisupd,
++                            ASN1_GENERALIZEDTIME **nextupd)
++{
++    int ret;
++    OCSP_CERTSTATUS *cst;
++    if (!single)
++        return -1;
++    cst = single->certStatus;
++    ret = cst->type;
++    if (ret == V_OCSP_CERTSTATUS_REVOKED) {
++        OCSP_REVOKEDINFO *rev = cst->value.revoked;
++        if (revtime)
++            *revtime = rev->revocationTime;
++        if (reason) {
++            if (rev->revocationReason)
++                *reason = ASN1_ENUMERATED_get(rev->revocationReason);
++            else
++                *reason = -1;
++        }
++    }
++    if (thisupd)
++        *thisupd = single->thisUpdate;
++    if (nextupd)
++        *nextupd = single->nextUpdate;
++    return ret;
++}
++
++/*
++ * This function combines the previous ones: look up a certificate ID and if
++ * found extract status information. Return 0 is successful.
++ */
++
++int OCSP_resp_find_status(OCSP_BASICRESP *bs, OCSP_CERTID *id, int *status,
++                          int *reason,
++                          ASN1_GENERALIZEDTIME **revtime,
++                          ASN1_GENERALIZEDTIME **thisupd,
++                          ASN1_GENERALIZEDTIME **nextupd)
++{
++    int i;
++    OCSP_SINGLERESP *single;
++    i = OCSP_resp_find(bs, id, -1);
++    /* Maybe check for multiple responses and give an error? */
++    if (i < 0)
++        return 0;
++    single = OCSP_resp_get0(bs, i);
++    i = OCSP_single_get0_status(single, reason, revtime, thisupd, nextupd);
++    if (status)
++        *status = i;
++    return 1;
++}
++
++/*
++ * Check validity of thisUpdate and nextUpdate fields. It is possible that
++ * the request will take a few seconds to process and/or the time won't be
++ * totally accurate. Therefore to avoid rejecting otherwise valid time we
++ * allow the times to be within 'nsec' of the current time. Also to avoid
++ * accepting very old responses without a nextUpdate field an optional maxage
++ * parameter specifies the maximum age the thisUpdate field can be.
++ */
++
++int OCSP_check_validity(ASN1_GENERALIZEDTIME *thisupd,
++                        ASN1_GENERALIZEDTIME *nextupd, long nsec, long maxsec)
++{
++    int ret = 1;
++    time_t t_now, t_tmp;
++    time(&t_now);
++    /* Check thisUpdate is valid and not more than nsec in the future */
++    if (!ASN1_GENERALIZEDTIME_check(thisupd)) {
++        OCSPerr(OCSP_F_OCSP_CHECK_VALIDITY, OCSP_R_ERROR_IN_THISUPDATE_FIELD);
++        ret = 0;
++    } else {
++        t_tmp = t_now + nsec;
++        if (X509_cmp_time(thisupd, &t_tmp) > 0) {
++            OCSPerr(OCSP_F_OCSP_CHECK_VALIDITY, OCSP_R_STATUS_NOT_YET_VALID);
++            ret = 0;
++        }
++
++        /*
++         * If maxsec specified check thisUpdate is not more than maxsec in
++         * the past
++         */
++        if (maxsec >= 0) {
++            t_tmp = t_now - maxsec;
++            if (X509_cmp_time(thisupd, &t_tmp) < 0) {
++                OCSPerr(OCSP_F_OCSP_CHECK_VALIDITY, OCSP_R_STATUS_TOO_OLD);
++                ret = 0;
++            }
++        }
++    }
++
++    if (!nextupd)
++        return ret;
++
++    /* Check nextUpdate is valid and not more than nsec in the past */
++    if (!ASN1_GENERALIZEDTIME_check(nextupd)) {
++        OCSPerr(OCSP_F_OCSP_CHECK_VALIDITY, OCSP_R_ERROR_IN_NEXTUPDATE_FIELD);
++        ret = 0;
++    } else {
++        t_tmp = t_now - nsec;
++        if (X509_cmp_time(nextupd, &t_tmp) < 0) {
++            OCSPerr(OCSP_F_OCSP_CHECK_VALIDITY, OCSP_R_STATUS_EXPIRED);
++            ret = 0;
++        }
++    }
++
++    /* Also don't allow nextUpdate to precede thisUpdate */
++    if (ASN1_STRING_cmp(nextupd, thisupd) < 0) {
++        OCSPerr(OCSP_F_OCSP_CHECK_VALIDITY,
++                OCSP_R_NEXTUPDATE_BEFORE_THISUPDATE);
++        ret = 0;
++    }
++
++    return ret;
++}
++
++const OCSP_CERTID *OCSP_SINGLERESP_get0_id(const OCSP_SINGLERESP *single)
++{
++    return single->certId;
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/ocsp/ocsp_err.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/ocsp/ocsp_err.c
+new file mode 100644
+index 0000000..a2d96e9
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/ocsp/ocsp_err.c
+@@ -0,0 +1,91 @@
++/*
++ * Generated by util/mkerr.pl DO NOT EDIT
++ * Copyright 1995-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include 
++#include 
++
++/* BEGIN ERROR CODES */
++#ifndef OPENSSL_NO_ERR
++
++# define ERR_FUNC(func) ERR_PACK(ERR_LIB_OCSP,func,0)
++# define ERR_REASON(reason) ERR_PACK(ERR_LIB_OCSP,0,reason)
++
++static ERR_STRING_DATA OCSP_str_functs[] = {
++    {ERR_FUNC(OCSP_F_D2I_OCSP_NONCE), "d2i_ocsp_nonce"},
++    {ERR_FUNC(OCSP_F_OCSP_BASIC_ADD1_STATUS), "OCSP_basic_add1_status"},
++    {ERR_FUNC(OCSP_F_OCSP_BASIC_SIGN), "OCSP_basic_sign"},
++    {ERR_FUNC(OCSP_F_OCSP_BASIC_VERIFY), "OCSP_basic_verify"},
++    {ERR_FUNC(OCSP_F_OCSP_CERT_ID_NEW), "OCSP_cert_id_new"},
++    {ERR_FUNC(OCSP_F_OCSP_CHECK_DELEGATED), "ocsp_check_delegated"},
++    {ERR_FUNC(OCSP_F_OCSP_CHECK_IDS), "ocsp_check_ids"},
++    {ERR_FUNC(OCSP_F_OCSP_CHECK_ISSUER), "ocsp_check_issuer"},
++    {ERR_FUNC(OCSP_F_OCSP_CHECK_VALIDITY), "OCSP_check_validity"},
++    {ERR_FUNC(OCSP_F_OCSP_MATCH_ISSUERID), "ocsp_match_issuerid"},
++    {ERR_FUNC(OCSP_F_OCSP_PARSE_URL), "OCSP_parse_url"},
++    {ERR_FUNC(OCSP_F_OCSP_REQUEST_SIGN), "OCSP_request_sign"},
++    {ERR_FUNC(OCSP_F_OCSP_REQUEST_VERIFY), "OCSP_request_verify"},
++    {ERR_FUNC(OCSP_F_OCSP_RESPONSE_GET1_BASIC), "OCSP_response_get1_basic"},
++    {ERR_FUNC(OCSP_F_PARSE_HTTP_LINE1), "parse_http_line1"},
++    {0, NULL}
++};
++
++static ERR_STRING_DATA OCSP_str_reasons[] = {
++    {ERR_REASON(OCSP_R_CERTIFICATE_VERIFY_ERROR), "certificate verify error"},
++    {ERR_REASON(OCSP_R_DIGEST_ERR), "digest err"},
++    {ERR_REASON(OCSP_R_ERROR_IN_NEXTUPDATE_FIELD),
++     "error in nextupdate field"},
++    {ERR_REASON(OCSP_R_ERROR_IN_THISUPDATE_FIELD),
++     "error in thisupdate field"},
++    {ERR_REASON(OCSP_R_ERROR_PARSING_URL), "error parsing url"},
++    {ERR_REASON(OCSP_R_MISSING_OCSPSIGNING_USAGE),
++     "missing ocspsigning usage"},
++    {ERR_REASON(OCSP_R_NEXTUPDATE_BEFORE_THISUPDATE),
++     "nextupdate before thisupdate"},
++    {ERR_REASON(OCSP_R_NOT_BASIC_RESPONSE), "not basic response"},
++    {ERR_REASON(OCSP_R_NO_CERTIFICATES_IN_CHAIN), "no certificates in chain"},
++    {ERR_REASON(OCSP_R_NO_RESPONSE_DATA), "no response data"},
++    {ERR_REASON(OCSP_R_NO_REVOKED_TIME), "no revoked time"},
++    {ERR_REASON(OCSP_R_NO_SIGNER_KEY), "no signer key"},
++    {ERR_REASON(OCSP_R_PRIVATE_KEY_DOES_NOT_MATCH_CERTIFICATE),
++     "private key does not match certificate"},
++    {ERR_REASON(OCSP_R_REQUEST_NOT_SIGNED), "request not signed"},
++    {ERR_REASON(OCSP_R_RESPONSE_CONTAINS_NO_REVOCATION_DATA),
++     "response contains no revocation data"},
++    {ERR_REASON(OCSP_R_ROOT_CA_NOT_TRUSTED), "root ca not trusted"},
++    {ERR_REASON(OCSP_R_SERVER_RESPONSE_ERROR), "server response error"},
++    {ERR_REASON(OCSP_R_SERVER_RESPONSE_PARSE_ERROR),
++     "server response parse error"},
++    {ERR_REASON(OCSP_R_SIGNATURE_FAILURE), "signature failure"},
++    {ERR_REASON(OCSP_R_SIGNER_CERTIFICATE_NOT_FOUND),
++     "signer certificate not found"},
++    {ERR_REASON(OCSP_R_STATUS_EXPIRED), "status expired"},
++    {ERR_REASON(OCSP_R_STATUS_NOT_YET_VALID), "status not yet valid"},
++    {ERR_REASON(OCSP_R_STATUS_TOO_OLD), "status too old"},
++    {ERR_REASON(OCSP_R_UNKNOWN_MESSAGE_DIGEST), "unknown message digest"},
++    {ERR_REASON(OCSP_R_UNKNOWN_NID), "unknown nid"},
++    {ERR_REASON(OCSP_R_UNSUPPORTED_REQUESTORNAME_TYPE),
++     "unsupported requestorname type"},
++    {0, NULL}
++};
++
++#endif
++
++int ERR_load_OCSP_strings(void)
++{
++#ifndef OPENSSL_NO_ERR
++
++    if (ERR_func_error_string(OCSP_str_functs[0].error) == NULL) {
++        ERR_load_strings(0, OCSP_str_functs);
++        ERR_load_strings(0, OCSP_str_reasons);
++    }
++#endif
++    return 1;
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/ocsp/ocsp_ext.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/ocsp/ocsp_ext.c
+new file mode 100644
+index 0000000..b829b2e
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/ocsp/ocsp_ext.c
+@@ -0,0 +1,472 @@
++/*
++ * Copyright 2000-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include "internal/cryptlib.h"
++#include 
++#include 
++#include 
++#include "ocsp_lcl.h"
++#include 
++#include 
++
++/* Standard wrapper functions for extensions */
++
++/* OCSP request extensions */
++
++int OCSP_REQUEST_get_ext_count(OCSP_REQUEST *x)
++{
++    return (X509v3_get_ext_count(x->tbsRequest.requestExtensions));
++}
++
++int OCSP_REQUEST_get_ext_by_NID(OCSP_REQUEST *x, int nid, int lastpos)
++{
++    return (X509v3_get_ext_by_NID
++            (x->tbsRequest.requestExtensions, nid, lastpos));
++}
++
++int OCSP_REQUEST_get_ext_by_OBJ(OCSP_REQUEST *x, const ASN1_OBJECT *obj,
++                                int lastpos)
++{
++    return (X509v3_get_ext_by_OBJ
++            (x->tbsRequest.requestExtensions, obj, lastpos));
++}
++
++int OCSP_REQUEST_get_ext_by_critical(OCSP_REQUEST *x, int crit, int lastpos)
++{
++    return (X509v3_get_ext_by_critical
++            (x->tbsRequest.requestExtensions, crit, lastpos));
++}
++
++X509_EXTENSION *OCSP_REQUEST_get_ext(OCSP_REQUEST *x, int loc)
++{
++    return (X509v3_get_ext(x->tbsRequest.requestExtensions, loc));
++}
++
++X509_EXTENSION *OCSP_REQUEST_delete_ext(OCSP_REQUEST *x, int loc)
++{
++    return (X509v3_delete_ext(x->tbsRequest.requestExtensions, loc));
++}
++
++void *OCSP_REQUEST_get1_ext_d2i(OCSP_REQUEST *x, int nid, int *crit, int *idx)
++{
++    return X509V3_get_d2i(x->tbsRequest.requestExtensions, nid, crit, idx);
++}
++
++int OCSP_REQUEST_add1_ext_i2d(OCSP_REQUEST *x, int nid, void *value, int crit,
++                              unsigned long flags)
++{
++    return X509V3_add1_i2d(&x->tbsRequest.requestExtensions, nid, value,
++                           crit, flags);
++}
++
++int OCSP_REQUEST_add_ext(OCSP_REQUEST *x, X509_EXTENSION *ex, int loc)
++{
++    return (X509v3_add_ext(&(x->tbsRequest.requestExtensions), ex, loc) !=
++            NULL);
++}
++
++/* Single extensions */
++
++int OCSP_ONEREQ_get_ext_count(OCSP_ONEREQ *x)
++{
++    return (X509v3_get_ext_count(x->singleRequestExtensions));
++}
++
++int OCSP_ONEREQ_get_ext_by_NID(OCSP_ONEREQ *x, int nid, int lastpos)
++{
++    return (X509v3_get_ext_by_NID(x->singleRequestExtensions, nid, lastpos));
++}
++
++int OCSP_ONEREQ_get_ext_by_OBJ(OCSP_ONEREQ *x, const ASN1_OBJECT *obj,
++                               int lastpos)
++{
++    return (X509v3_get_ext_by_OBJ(x->singleRequestExtensions, obj, lastpos));
++}
++
++int OCSP_ONEREQ_get_ext_by_critical(OCSP_ONEREQ *x, int crit, int lastpos)
++{
++    return (X509v3_get_ext_by_critical
++            (x->singleRequestExtensions, crit, lastpos));
++}
++
++X509_EXTENSION *OCSP_ONEREQ_get_ext(OCSP_ONEREQ *x, int loc)
++{
++    return (X509v3_get_ext(x->singleRequestExtensions, loc));
++}
++
++X509_EXTENSION *OCSP_ONEREQ_delete_ext(OCSP_ONEREQ *x, int loc)
++{
++    return (X509v3_delete_ext(x->singleRequestExtensions, loc));
++}
++
++void *OCSP_ONEREQ_get1_ext_d2i(OCSP_ONEREQ *x, int nid, int *crit, int *idx)
++{
++    return X509V3_get_d2i(x->singleRequestExtensions, nid, crit, idx);
++}
++
++int OCSP_ONEREQ_add1_ext_i2d(OCSP_ONEREQ *x, int nid, void *value, int crit,
++                             unsigned long flags)
++{
++    return X509V3_add1_i2d(&x->singleRequestExtensions, nid, value, crit,
++                           flags);
++}
++
++int OCSP_ONEREQ_add_ext(OCSP_ONEREQ *x, X509_EXTENSION *ex, int loc)
++{
++    return (X509v3_add_ext(&(x->singleRequestExtensions), ex, loc) != NULL);
++}
++
++/* OCSP Basic response */
++
++int OCSP_BASICRESP_get_ext_count(OCSP_BASICRESP *x)
++{
++    return (X509v3_get_ext_count(x->tbsResponseData.responseExtensions));
++}
++
++int OCSP_BASICRESP_get_ext_by_NID(OCSP_BASICRESP *x, int nid, int lastpos)
++{
++    return (X509v3_get_ext_by_NID
++            (x->tbsResponseData.responseExtensions, nid, lastpos));
++}
++
++int OCSP_BASICRESP_get_ext_by_OBJ(OCSP_BASICRESP *x, const ASN1_OBJECT *obj,
++                                  int lastpos)
++{
++    return (X509v3_get_ext_by_OBJ
++            (x->tbsResponseData.responseExtensions, obj, lastpos));
++}
++
++int OCSP_BASICRESP_get_ext_by_critical(OCSP_BASICRESP *x, int crit,
++                                       int lastpos)
++{
++    return (X509v3_get_ext_by_critical
++            (x->tbsResponseData.responseExtensions, crit, lastpos));
++}
++
++X509_EXTENSION *OCSP_BASICRESP_get_ext(OCSP_BASICRESP *x, int loc)
++{
++    return (X509v3_get_ext(x->tbsResponseData.responseExtensions, loc));
++}
++
++X509_EXTENSION *OCSP_BASICRESP_delete_ext(OCSP_BASICRESP *x, int loc)
++{
++    return (X509v3_delete_ext(x->tbsResponseData.responseExtensions, loc));
++}
++
++void *OCSP_BASICRESP_get1_ext_d2i(OCSP_BASICRESP *x, int nid, int *crit,
++                                  int *idx)
++{
++    return X509V3_get_d2i(x->tbsResponseData.responseExtensions, nid, crit,
++                          idx);
++}
++
++int OCSP_BASICRESP_add1_ext_i2d(OCSP_BASICRESP *x, int nid, void *value,
++                                int crit, unsigned long flags)
++{
++    return X509V3_add1_i2d(&x->tbsResponseData.responseExtensions, nid,
++                           value, crit, flags);
++}
++
++int OCSP_BASICRESP_add_ext(OCSP_BASICRESP *x, X509_EXTENSION *ex, int loc)
++{
++    return (X509v3_add_ext(&(x->tbsResponseData.responseExtensions), ex, loc)
++            != NULL);
++}
++
++/* OCSP single response extensions */
++
++int OCSP_SINGLERESP_get_ext_count(OCSP_SINGLERESP *x)
++{
++    return (X509v3_get_ext_count(x->singleExtensions));
++}
++
++int OCSP_SINGLERESP_get_ext_by_NID(OCSP_SINGLERESP *x, int nid, int lastpos)
++{
++    return (X509v3_get_ext_by_NID(x->singleExtensions, nid, lastpos));
++}
++
++int OCSP_SINGLERESP_get_ext_by_OBJ(OCSP_SINGLERESP *x, const ASN1_OBJECT *obj,
++                                   int lastpos)
++{
++    return (X509v3_get_ext_by_OBJ(x->singleExtensions, obj, lastpos));
++}
++
++int OCSP_SINGLERESP_get_ext_by_critical(OCSP_SINGLERESP *x, int crit,
++                                        int lastpos)
++{
++    return (X509v3_get_ext_by_critical(x->singleExtensions, crit, lastpos));
++}
++
++X509_EXTENSION *OCSP_SINGLERESP_get_ext(OCSP_SINGLERESP *x, int loc)
++{
++    return (X509v3_get_ext(x->singleExtensions, loc));
++}
++
++X509_EXTENSION *OCSP_SINGLERESP_delete_ext(OCSP_SINGLERESP *x, int loc)
++{
++    return (X509v3_delete_ext(x->singleExtensions, loc));
++}
++
++void *OCSP_SINGLERESP_get1_ext_d2i(OCSP_SINGLERESP *x, int nid, int *crit,
++                                   int *idx)
++{
++    return X509V3_get_d2i(x->singleExtensions, nid, crit, idx);
++}
++
++int OCSP_SINGLERESP_add1_ext_i2d(OCSP_SINGLERESP *x, int nid, void *value,
++                                 int crit, unsigned long flags)
++{
++    return X509V3_add1_i2d(&x->singleExtensions, nid, value, crit, flags);
++}
++
++int OCSP_SINGLERESP_add_ext(OCSP_SINGLERESP *x, X509_EXTENSION *ex, int loc)
++{
++    return (X509v3_add_ext(&(x->singleExtensions), ex, loc) != NULL);
++}
++
++/* also CRL Entry Extensions */
++
++/* Nonce handling functions */
++
++/*
++ * Add a nonce to an extension stack. A nonce can be specified or if NULL a
++ * random nonce will be generated. Note: OpenSSL 0.9.7d and later create an
++ * OCTET STRING containing the nonce, previous versions used the raw nonce.
++ */
++
++static int ocsp_add1_nonce(STACK_OF(X509_EXTENSION) **exts,
++                           unsigned char *val, int len)
++{
++    unsigned char *tmpval;
++    ASN1_OCTET_STRING os;
++    int ret = 0;
++    if (len <= 0)
++        len = OCSP_DEFAULT_NONCE_LENGTH;
++    /*
++     * Create the OCTET STRING manually by writing out the header and
++     * appending the content octets. This avoids an extra memory allocation
++     * operation in some cases. Applications should *NOT* do this because it
++     * relies on library internals.
++     */
++    os.length = ASN1_object_size(0, len, V_ASN1_OCTET_STRING);
++    if (os.length < 0)
++        return 0;
++
++    os.data = OPENSSL_malloc(os.length);
++    if (os.data == NULL)
++        goto err;
++    tmpval = os.data;
++    ASN1_put_object(&tmpval, 0, len, V_ASN1_OCTET_STRING, V_ASN1_UNIVERSAL);
++    if (val)
++        memcpy(tmpval, val, len);
++    else if (RAND_bytes(tmpval, len) <= 0)
++        goto err;
++    if (!X509V3_add1_i2d(exts, NID_id_pkix_OCSP_Nonce,
++                         &os, 0, X509V3_ADD_REPLACE))
++        goto err;
++    ret = 1;
++ err:
++    OPENSSL_free(os.data);
++    return ret;
++}
++
++/* Add nonce to an OCSP request */
++
++int OCSP_request_add1_nonce(OCSP_REQUEST *req, unsigned char *val, int len)
++{
++    return ocsp_add1_nonce(&req->tbsRequest.requestExtensions, val, len);
++}
++
++/* Same as above but for a response */
++
++int OCSP_basic_add1_nonce(OCSP_BASICRESP *resp, unsigned char *val, int len)
++{
++    return ocsp_add1_nonce(&resp->tbsResponseData.responseExtensions, val,
++                           len);
++}
++
++/*-
++ * Check nonce validity in a request and response.
++ * Return value reflects result:
++ *  1: nonces present and equal.
++ *  2: nonces both absent.
++ *  3: nonce present in response only.
++ *  0: nonces both present and not equal.
++ * -1: nonce in request only.
++ *
++ *  For most responders clients can check return > 0.
++ *  If responder doesn't handle nonces return != 0 may be
++ *  necessary. return == 0 is always an error.
++ */
++
++int OCSP_check_nonce(OCSP_REQUEST *req, OCSP_BASICRESP *bs)
++{
++    /*
++     * Since we are only interested in the presence or absence of
++     * the nonce and comparing its value there is no need to use
++     * the X509V3 routines: this way we can avoid them allocating an
++     * ASN1_OCTET_STRING structure for the value which would be
++     * freed immediately anyway.
++     */
++
++    int req_idx, resp_idx;
++    X509_EXTENSION *req_ext, *resp_ext;
++    req_idx = OCSP_REQUEST_get_ext_by_NID(req, NID_id_pkix_OCSP_Nonce, -1);
++    resp_idx = OCSP_BASICRESP_get_ext_by_NID(bs, NID_id_pkix_OCSP_Nonce, -1);
++    /* Check both absent */
++    if ((req_idx < 0) && (resp_idx < 0))
++        return 2;
++    /* Check in request only */
++    if ((req_idx >= 0) && (resp_idx < 0))
++        return -1;
++    /* Check in response but not request */
++    if ((req_idx < 0) && (resp_idx >= 0))
++        return 3;
++    /*
++     * Otherwise nonce in request and response so retrieve the extensions
++     */
++    req_ext = OCSP_REQUEST_get_ext(req, req_idx);
++    resp_ext = OCSP_BASICRESP_get_ext(bs, resp_idx);
++    if (ASN1_OCTET_STRING_cmp(X509_EXTENSION_get_data(req_ext),
++                              X509_EXTENSION_get_data(resp_ext)))
++        return 0;
++    return 1;
++}
++
++/*
++ * Copy the nonce value (if any) from an OCSP request to a response.
++ */
++
++int OCSP_copy_nonce(OCSP_BASICRESP *resp, OCSP_REQUEST *req)
++{
++    X509_EXTENSION *req_ext;
++    int req_idx;
++    /* Check for nonce in request */
++    req_idx = OCSP_REQUEST_get_ext_by_NID(req, NID_id_pkix_OCSP_Nonce, -1);
++    /* If no nonce that's OK */
++    if (req_idx < 0)
++        return 2;
++    req_ext = OCSP_REQUEST_get_ext(req, req_idx);
++    return OCSP_BASICRESP_add_ext(resp, req_ext, -1);
++}
++
++X509_EXTENSION *OCSP_crlID_new(const char *url, long *n, char *tim)
++{
++    X509_EXTENSION *x = NULL;
++    OCSP_CRLID *cid = NULL;
++
++    if ((cid = OCSP_CRLID_new()) == NULL)
++        goto err;
++    if (url) {
++        if ((cid->crlUrl = ASN1_IA5STRING_new()) == NULL)
++            goto err;
++        if (!(ASN1_STRING_set(cid->crlUrl, url, -1)))
++            goto err;
++    }
++    if (n) {
++        if ((cid->crlNum = ASN1_INTEGER_new()) == NULL)
++            goto err;
++        if (!(ASN1_INTEGER_set(cid->crlNum, *n)))
++            goto err;
++    }
++    if (tim) {
++        if ((cid->crlTime = ASN1_GENERALIZEDTIME_new()) == NULL)
++            goto err;
++        if (!(ASN1_GENERALIZEDTIME_set_string(cid->crlTime, tim)))
++            goto err;
++    }
++    x = X509V3_EXT_i2d(NID_id_pkix_OCSP_CrlID, 0, cid);
++ err:
++    OCSP_CRLID_free(cid);
++    return x;
++}
++
++/*   AcceptableResponses ::= SEQUENCE OF OBJECT IDENTIFIER */
++X509_EXTENSION *OCSP_accept_responses_new(char **oids)
++{
++    int nid;
++    STACK_OF(ASN1_OBJECT) *sk = NULL;
++    ASN1_OBJECT *o = NULL;
++    X509_EXTENSION *x = NULL;
++
++    if ((sk = sk_ASN1_OBJECT_new_null()) == NULL)
++        goto err;
++    while (oids && *oids) {
++        if ((nid = OBJ_txt2nid(*oids)) != NID_undef && (o = OBJ_nid2obj(nid)))
++            sk_ASN1_OBJECT_push(sk, o);
++        oids++;
++    }
++    x = X509V3_EXT_i2d(NID_id_pkix_OCSP_acceptableResponses, 0, sk);
++ err:
++    sk_ASN1_OBJECT_pop_free(sk, ASN1_OBJECT_free);
++    return x;
++}
++
++/*  ArchiveCutoff ::= GeneralizedTime */
++X509_EXTENSION *OCSP_archive_cutoff_new(char *tim)
++{
++    X509_EXTENSION *x = NULL;
++    ASN1_GENERALIZEDTIME *gt = NULL;
++
++    if ((gt = ASN1_GENERALIZEDTIME_new()) == NULL)
++        goto err;
++    if (!(ASN1_GENERALIZEDTIME_set_string(gt, tim)))
++        goto err;
++    x = X509V3_EXT_i2d(NID_id_pkix_OCSP_archiveCutoff, 0, gt);
++ err:
++    ASN1_GENERALIZEDTIME_free(gt);
++    return x;
++}
++
++/*
++ * per ACCESS_DESCRIPTION parameter are oids, of which there are currently
++ * two--NID_ad_ocsp, NID_id_ad_caIssuers--and GeneralName value.  This method
++ * forces NID_ad_ocsp and uniformResourceLocator [6] IA5String.
++ */
++X509_EXTENSION *OCSP_url_svcloc_new(X509_NAME *issuer, const char **urls)
++{
++    X509_EXTENSION *x = NULL;
++    ASN1_IA5STRING *ia5 = NULL;
++    OCSP_SERVICELOC *sloc = NULL;
++    ACCESS_DESCRIPTION *ad = NULL;
++
++    if ((sloc = OCSP_SERVICELOC_new()) == NULL)
++        goto err;
++    if ((sloc->issuer = X509_NAME_dup(issuer)) == NULL)
++        goto err;
++    if (urls && *urls
++        && (sloc->locator = sk_ACCESS_DESCRIPTION_new_null()) == NULL)
++        goto err;
++    while (urls && *urls) {
++        if ((ad = ACCESS_DESCRIPTION_new()) == NULL)
++            goto err;
++        if ((ad->method = OBJ_nid2obj(NID_ad_OCSP)) == NULL)
++            goto err;
++        if ((ad->location = GENERAL_NAME_new()) == NULL)
++            goto err;
++        if ((ia5 = ASN1_IA5STRING_new()) == NULL)
++            goto err;
++        if (!ASN1_STRING_set((ASN1_STRING *)ia5, *urls, -1))
++            goto err;
++        ad->location->type = GEN_URI;
++        ad->location->d.ia5 = ia5;
++        ia5 = NULL;
++        if (!sk_ACCESS_DESCRIPTION_push(sloc->locator, ad))
++            goto err;
++        ad = NULL;
++        urls++;
++    }
++    x = X509V3_EXT_i2d(NID_id_pkix_OCSP_serviceLocator, 0, sloc);
++ err:
++    ASN1_IA5STRING_free(ia5);
++    ACCESS_DESCRIPTION_free(ad);
++    OCSP_SERVICELOC_free(sloc);
++    return x;
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/ocsp/ocsp_ht.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/ocsp/ocsp_ht.c
+new file mode 100644
+index 0000000..680edfa
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/ocsp/ocsp_ht.c
+@@ -0,0 +1,499 @@
++/*
++ * Copyright 2001-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include 
++#include 
++#include 
++#include "e_os.h"
++#include 
++#include 
++#include 
++#include 
++
++/* Stateful OCSP request code, supporting non-blocking I/O */
++
++/* Opaque OCSP request status structure */
++
++struct ocsp_req_ctx_st {
++    int state;                  /* Current I/O state */
++    unsigned char *iobuf;       /* Line buffer */
++    int iobuflen;               /* Line buffer length */
++    BIO *io;                    /* BIO to perform I/O with */
++    BIO *mem;                   /* Memory BIO response is built into */
++    unsigned long asn1_len;     /* ASN1 length of response */
++    unsigned long max_resp_len; /* Maximum length of response */
++};
++
++#define OCSP_MAX_RESP_LENGTH    (100 * 1024)
++#define OCSP_MAX_LINE_LEN       4096;
++
++/* OCSP states */
++
++/* If set no reading should be performed */
++#define OHS_NOREAD              0x1000
++/* Error condition */
++#define OHS_ERROR               (0 | OHS_NOREAD)
++/* First line being read */
++#define OHS_FIRSTLINE           1
++/* MIME headers being read */
++#define OHS_HEADERS             2
++/* OCSP initial header (tag + length) being read */
++#define OHS_ASN1_HEADER         3
++/* OCSP content octets being read */
++#define OHS_ASN1_CONTENT        4
++/* First call: ready to start I/O */
++#define OHS_ASN1_WRITE_INIT     (5 | OHS_NOREAD)
++/* Request being sent */
++#define OHS_ASN1_WRITE          (6 | OHS_NOREAD)
++/* Request being flushed */
++#define OHS_ASN1_FLUSH          (7 | OHS_NOREAD)
++/* Completed */
++#define OHS_DONE                (8 | OHS_NOREAD)
++/* Headers set, no final \r\n included */
++#define OHS_HTTP_HEADER         (9 | OHS_NOREAD)
++
++static int parse_http_line1(char *line);
++
++OCSP_REQ_CTX *OCSP_REQ_CTX_new(BIO *io, int maxline)
++{
++    OCSP_REQ_CTX *rctx = OPENSSL_zalloc(sizeof(*rctx));
++
++    if (rctx == NULL)
++        return NULL;
++    rctx->state = OHS_ERROR;
++    rctx->max_resp_len = OCSP_MAX_RESP_LENGTH;
++    rctx->mem = BIO_new(BIO_s_mem());
++    rctx->io = io;
++    if (maxline > 0)
++        rctx->iobuflen = maxline;
++    else
++        rctx->iobuflen = OCSP_MAX_LINE_LEN;
++    rctx->iobuf = OPENSSL_malloc(rctx->iobuflen);
++    if (rctx->iobuf == NULL || rctx->mem == NULL) {
++        OCSP_REQ_CTX_free(rctx);
++        return NULL;
++    }
++    return rctx;
++}
++
++void OCSP_REQ_CTX_free(OCSP_REQ_CTX *rctx)
++{
++    if (!rctx)
++        return;
++    BIO_free(rctx->mem);
++    OPENSSL_free(rctx->iobuf);
++    OPENSSL_free(rctx);
++}
++
++BIO *OCSP_REQ_CTX_get0_mem_bio(OCSP_REQ_CTX *rctx)
++{
++    return rctx->mem;
++}
++
++void OCSP_set_max_response_length(OCSP_REQ_CTX *rctx, unsigned long len)
++{
++    if (len == 0)
++        rctx->max_resp_len = OCSP_MAX_RESP_LENGTH;
++    else
++        rctx->max_resp_len = len;
++}
++
++int OCSP_REQ_CTX_i2d(OCSP_REQ_CTX *rctx, const ASN1_ITEM *it, ASN1_VALUE *val)
++{
++    static const char req_hdr[] =
++        "Content-Type: application/ocsp-request\r\n"
++        "Content-Length: %d\r\n\r\n";
++    int reqlen = ASN1_item_i2d(val, NULL, it);
++    if (BIO_printf(rctx->mem, req_hdr, reqlen) <= 0)
++        return 0;
++    if (ASN1_item_i2d_bio(it, rctx->mem, val) <= 0)
++        return 0;
++    rctx->state = OHS_ASN1_WRITE_INIT;
++    return 1;
++}
++
++int OCSP_REQ_CTX_nbio_d2i(OCSP_REQ_CTX *rctx,
++                          ASN1_VALUE **pval, const ASN1_ITEM *it)
++{
++    int rv, len;
++    const unsigned char *p;
++
++    rv = OCSP_REQ_CTX_nbio(rctx);
++    if (rv != 1)
++        return rv;
++
++    len = BIO_get_mem_data(rctx->mem, &p);
++    *pval = ASN1_item_d2i(NULL, &p, len, it);
++    if (*pval == NULL) {
++        rctx->state = OHS_ERROR;
++        return 0;
++    }
++    return 1;
++}
++
++int OCSP_REQ_CTX_http(OCSP_REQ_CTX *rctx, const char *op, const char *path)
++{
++    static const char http_hdr[] = "%s %s HTTP/1.0\r\n";
++
++    if (!path)
++        path = "/";
++
++    if (BIO_printf(rctx->mem, http_hdr, op, path) <= 0)
++        return 0;
++    rctx->state = OHS_HTTP_HEADER;
++    return 1;
++}
++
++int OCSP_REQ_CTX_set1_req(OCSP_REQ_CTX *rctx, OCSP_REQUEST *req)
++{
++    return OCSP_REQ_CTX_i2d(rctx, ASN1_ITEM_rptr(OCSP_REQUEST),
++                            (ASN1_VALUE *)req);
++}
++
++int OCSP_REQ_CTX_add1_header(OCSP_REQ_CTX *rctx,
++                             const char *name, const char *value)
++{
++    if (!name)
++        return 0;
++    if (BIO_puts(rctx->mem, name) <= 0)
++        return 0;
++    if (value) {
++        if (BIO_write(rctx->mem, ": ", 2) != 2)
++            return 0;
++        if (BIO_puts(rctx->mem, value) <= 0)
++            return 0;
++    }
++    if (BIO_write(rctx->mem, "\r\n", 2) != 2)
++        return 0;
++    rctx->state = OHS_HTTP_HEADER;
++    return 1;
++}
++
++OCSP_REQ_CTX *OCSP_sendreq_new(BIO *io, const char *path, OCSP_REQUEST *req,
++                               int maxline)
++{
++
++    OCSP_REQ_CTX *rctx = NULL;
++    rctx = OCSP_REQ_CTX_new(io, maxline);
++    if (rctx == NULL)
++        return NULL;
++
++    if (!OCSP_REQ_CTX_http(rctx, "POST", path))
++        goto err;
++
++    if (req && !OCSP_REQ_CTX_set1_req(rctx, req))
++        goto err;
++
++    return rctx;
++
++ err:
++    OCSP_REQ_CTX_free(rctx);
++    return NULL;
++}
++
++/*
++ * Parse the HTTP response. This will look like this: "HTTP/1.0 200 OK". We
++ * need to obtain the numeric code and (optional) informational message.
++ */
++
++static int parse_http_line1(char *line)
++{
++    int retcode;
++    char *p, *q, *r;
++    /* Skip to first white space (passed protocol info) */
++
++    for (p = line; *p && !isspace((unsigned char)*p); p++)
++        continue;
++    if (!*p) {
++        OCSPerr(OCSP_F_PARSE_HTTP_LINE1, OCSP_R_SERVER_RESPONSE_PARSE_ERROR);
++        return 0;
++    }
++
++    /* Skip past white space to start of response code */
++    while (*p && isspace((unsigned char)*p))
++        p++;
++
++    if (!*p) {
++        OCSPerr(OCSP_F_PARSE_HTTP_LINE1, OCSP_R_SERVER_RESPONSE_PARSE_ERROR);
++        return 0;
++    }
++
++    /* Find end of response code: first whitespace after start of code */
++    for (q = p; *q && !isspace((unsigned char)*q); q++)
++        continue;
++
++    if (!*q) {
++        OCSPerr(OCSP_F_PARSE_HTTP_LINE1, OCSP_R_SERVER_RESPONSE_PARSE_ERROR);
++        return 0;
++    }
++
++    /* Set end of response code and start of message */
++    *q++ = 0;
++
++    /* Attempt to parse numeric code */
++    retcode = strtoul(p, &r, 10);
++
++    if (*r)
++        return 0;
++
++    /* Skip over any leading white space in message */
++    while (*q && isspace((unsigned char)*q))
++        q++;
++
++    if (*q) {
++        /*
++         * Finally zap any trailing white space in message (include CRLF)
++         */
++
++        /* We know q has a non white space character so this is OK */
++        for (r = q + strlen(q) - 1; isspace((unsigned char)*r); r--)
++            *r = 0;
++    }
++    if (retcode != 200) {
++        OCSPerr(OCSP_F_PARSE_HTTP_LINE1, OCSP_R_SERVER_RESPONSE_ERROR);
++        if (!*q)
++            ERR_add_error_data(2, "Code=", p);
++        else
++            ERR_add_error_data(4, "Code=", p, ",Reason=", q);
++        return 0;
++    }
++
++    return 1;
++
++}
++
++int OCSP_REQ_CTX_nbio(OCSP_REQ_CTX *rctx)
++{
++    int i, n;
++    const unsigned char *p;
++ next_io:
++    if (!(rctx->state & OHS_NOREAD)) {
++        n = BIO_read(rctx->io, rctx->iobuf, rctx->iobuflen);
++
++        if (n <= 0) {
++            if (BIO_should_retry(rctx->io))
++                return -1;
++            return 0;
++        }
++
++        /* Write data to memory BIO */
++
++        if (BIO_write(rctx->mem, rctx->iobuf, n) != n)
++            return 0;
++    }
++
++    switch (rctx->state) {
++    case OHS_HTTP_HEADER:
++        /* Last operation was adding headers: need a final \r\n */
++        if (BIO_write(rctx->mem, "\r\n", 2) != 2) {
++            rctx->state = OHS_ERROR;
++            return 0;
++        }
++        rctx->state = OHS_ASN1_WRITE_INIT;
++
++    case OHS_ASN1_WRITE_INIT:
++        rctx->asn1_len = BIO_get_mem_data(rctx->mem, NULL);
++        rctx->state = OHS_ASN1_WRITE;
++
++    case OHS_ASN1_WRITE:
++        n = BIO_get_mem_data(rctx->mem, &p);
++
++        i = BIO_write(rctx->io, p + (n - rctx->asn1_len), rctx->asn1_len);
++
++        if (i <= 0) {
++            if (BIO_should_retry(rctx->io))
++                return -1;
++            rctx->state = OHS_ERROR;
++            return 0;
++        }
++
++        rctx->asn1_len -= i;
++
++        if (rctx->asn1_len > 0)
++            goto next_io;
++
++        rctx->state = OHS_ASN1_FLUSH;
++
++        (void)BIO_reset(rctx->mem);
++
++    case OHS_ASN1_FLUSH:
++
++        i = BIO_flush(rctx->io);
++
++        if (i > 0) {
++            rctx->state = OHS_FIRSTLINE;
++            goto next_io;
++        }
++
++        if (BIO_should_retry(rctx->io))
++            return -1;
++
++        rctx->state = OHS_ERROR;
++        return 0;
++
++    case OHS_ERROR:
++        return 0;
++
++    case OHS_FIRSTLINE:
++    case OHS_HEADERS:
++
++        /* Attempt to read a line in */
++
++ next_line:
++        /*
++         * Due to &%^*$" memory BIO behaviour with BIO_gets we have to check
++         * there's a complete line in there before calling BIO_gets or we'll
++         * just get a partial read.
++         */
++        n = BIO_get_mem_data(rctx->mem, &p);
++        if ((n <= 0) || !memchr(p, '\n', n)) {
++            if (n >= rctx->iobuflen) {
++                rctx->state = OHS_ERROR;
++                return 0;
++            }
++            goto next_io;
++        }
++        n = BIO_gets(rctx->mem, (char *)rctx->iobuf, rctx->iobuflen);
++
++        if (n <= 0) {
++            if (BIO_should_retry(rctx->mem))
++                goto next_io;
++            rctx->state = OHS_ERROR;
++            return 0;
++        }
++
++        /* Don't allow excessive lines */
++        if (n == rctx->iobuflen) {
++            rctx->state = OHS_ERROR;
++            return 0;
++        }
++
++        /* First line */
++        if (rctx->state == OHS_FIRSTLINE) {
++            if (parse_http_line1((char *)rctx->iobuf)) {
++                rctx->state = OHS_HEADERS;
++                goto next_line;
++            } else {
++                rctx->state = OHS_ERROR;
++                return 0;
++            }
++        } else {
++            /* Look for blank line: end of headers */
++            for (p = rctx->iobuf; *p; p++) {
++                if ((*p != '\r') && (*p != '\n'))
++                    break;
++            }
++            if (*p)
++                goto next_line;
++
++            rctx->state = OHS_ASN1_HEADER;
++
++        }
++
++        /* Fall thru */
++
++    case OHS_ASN1_HEADER:
++        /*
++         * Now reading ASN1 header: can read at least 2 bytes which is enough
++         * for ASN1 SEQUENCE header and either length field or at least the
++         * length of the length field.
++         */
++        n = BIO_get_mem_data(rctx->mem, &p);
++        if (n < 2)
++            goto next_io;
++
++        /* Check it is an ASN1 SEQUENCE */
++        if (*p++ != (V_ASN1_SEQUENCE | V_ASN1_CONSTRUCTED)) {
++            rctx->state = OHS_ERROR;
++            return 0;
++        }
++
++        /* Check out length field */
++        if (*p & 0x80) {
++            /*
++             * If MSB set on initial length octet we can now always read 6
++             * octets: make sure we have them.
++             */
++            if (n < 6)
++                goto next_io;
++            n = *p & 0x7F;
++            /* Not NDEF or excessive length */
++            if (!n || (n > 4)) {
++                rctx->state = OHS_ERROR;
++                return 0;
++            }
++            p++;
++            rctx->asn1_len = 0;
++            for (i = 0; i < n; i++) {
++                rctx->asn1_len <<= 8;
++                rctx->asn1_len |= *p++;
++            }
++
++            if (rctx->asn1_len > rctx->max_resp_len) {
++                rctx->state = OHS_ERROR;
++                return 0;
++            }
++
++            rctx->asn1_len += n + 2;
++        } else
++            rctx->asn1_len = *p + 2;
++
++        rctx->state = OHS_ASN1_CONTENT;
++
++        /* Fall thru */
++
++    case OHS_ASN1_CONTENT:
++        n = BIO_get_mem_data(rctx->mem, NULL);
++        if (n < (int)rctx->asn1_len)
++            goto next_io;
++
++        rctx->state = OHS_DONE;
++        return 1;
++
++    case OHS_DONE:
++        return 1;
++
++    }
++
++    return 0;
++
++}
++
++int OCSP_sendreq_nbio(OCSP_RESPONSE **presp, OCSP_REQ_CTX *rctx)
++{
++    return OCSP_REQ_CTX_nbio_d2i(rctx,
++                                 (ASN1_VALUE **)presp,
++                                 ASN1_ITEM_rptr(OCSP_RESPONSE));
++}
++
++/* Blocking OCSP request handler: now a special case of non-blocking I/O */
++
++OCSP_RESPONSE *OCSP_sendreq_bio(BIO *b, const char *path, OCSP_REQUEST *req)
++{
++    OCSP_RESPONSE *resp = NULL;
++    OCSP_REQ_CTX *ctx;
++    int rv;
++
++    ctx = OCSP_sendreq_new(b, path, req, -1);
++
++    if (ctx == NULL)
++        return NULL;
++
++    do {
++        rv = OCSP_sendreq_nbio(&resp, ctx);
++    } while ((rv == -1) && BIO_should_retry(b));
++
++    OCSP_REQ_CTX_free(ctx);
++
++    if (rv)
++        return resp;
++
++    return NULL;
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/ocsp/ocsp_lcl.h b/CryptoPkg/Library/OpensslLib/openssl/crypto/ocsp/ocsp_lcl.h
+new file mode 100644
+index 0000000..f93a268
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/ocsp/ocsp_lcl.h
+@@ -0,0 +1,216 @@
++/*
++ * Copyright 2015-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++/*-  CertID ::= SEQUENCE {
++ *       hashAlgorithm            AlgorithmIdentifier,
++ *       issuerNameHash     OCTET STRING, -- Hash of Issuer's DN
++ *       issuerKeyHash      OCTET STRING, -- Hash of Issuers public key (excluding the tag & length fields)
++ *       serialNumber       CertificateSerialNumber }
++ */
++struct ocsp_cert_id_st {
++    X509_ALGOR hashAlgorithm;
++    ASN1_OCTET_STRING issuerNameHash;
++    ASN1_OCTET_STRING issuerKeyHash;
++    ASN1_INTEGER serialNumber;
++};
++
++/*-  Request ::=     SEQUENCE {
++ *       reqCert                    CertID,
++ *       singleRequestExtensions    [0] EXPLICIT Extensions OPTIONAL }
++ */
++struct ocsp_one_request_st {
++    OCSP_CERTID *reqCert;
++    STACK_OF(X509_EXTENSION) *singleRequestExtensions;
++};
++
++/*-  TBSRequest      ::=     SEQUENCE {
++ *       version             [0] EXPLICIT Version DEFAULT v1,
++ *       requestorName       [1] EXPLICIT GeneralName OPTIONAL,
++ *       requestList             SEQUENCE OF Request,
++ *       requestExtensions   [2] EXPLICIT Extensions OPTIONAL }
++ */
++struct ocsp_req_info_st {
++    ASN1_INTEGER *version;
++    GENERAL_NAME *requestorName;
++    STACK_OF(OCSP_ONEREQ) *requestList;
++    STACK_OF(X509_EXTENSION) *requestExtensions;
++};
++
++/*-  Signature       ::=     SEQUENCE {
++ *       signatureAlgorithm   AlgorithmIdentifier,
++ *       signature            BIT STRING,
++ *       certs                [0] EXPLICIT SEQUENCE OF Certificate OPTIONAL }
++ */
++struct ocsp_signature_st {
++    X509_ALGOR signatureAlgorithm;
++    ASN1_BIT_STRING *signature;
++    STACK_OF(X509) *certs;
++};
++
++/*-  OCSPRequest     ::=     SEQUENCE {
++ *       tbsRequest                  TBSRequest,
++ *       optionalSignature   [0]     EXPLICIT Signature OPTIONAL }
++ */
++struct ocsp_request_st {
++    OCSP_REQINFO tbsRequest;
++    OCSP_SIGNATURE *optionalSignature; /* OPTIONAL */
++};
++
++/*-  OCSPResponseStatus ::= ENUMERATED {
++ *       successful            (0),      --Response has valid confirmations
++ *       malformedRequest      (1),      --Illegal confirmation request
++ *       internalError         (2),      --Internal error in issuer
++ *       tryLater              (3),      --Try again later
++ *                                       --(4) is not used
++ *       sigRequired           (5),      --Must sign the request
++ *       unauthorized          (6)       --Request unauthorized
++ *   }
++ */
++
++/*-  ResponseBytes ::=       SEQUENCE {
++ *       responseType   OBJECT IDENTIFIER,
++ *       response       OCTET STRING }
++ */
++struct ocsp_resp_bytes_st {
++    ASN1_OBJECT *responseType;
++    ASN1_OCTET_STRING *response;
++};
++
++/*-  OCSPResponse ::= SEQUENCE {
++ *      responseStatus         OCSPResponseStatus,
++ *      responseBytes          [0] EXPLICIT ResponseBytes OPTIONAL }
++ */
++struct ocsp_response_st {
++    ASN1_ENUMERATED *responseStatus;
++    OCSP_RESPBYTES *responseBytes;
++};
++
++/*-  ResponderID ::= CHOICE {
++ *      byName   [1] Name,
++ *      byKey    [2] KeyHash }
++ */
++struct ocsp_responder_id_st {
++    int type;
++    union {
++        X509_NAME *byName;
++        ASN1_OCTET_STRING *byKey;
++    } value;
++};
++
++/*-  KeyHash ::= OCTET STRING --SHA-1 hash of responder's public key
++ *                            --(excluding the tag and length fields)
++ */
++
++/*-  RevokedInfo ::= SEQUENCE {
++ *       revocationTime              GeneralizedTime,
++ *       revocationReason    [0]     EXPLICIT CRLReason OPTIONAL }
++ */
++struct ocsp_revoked_info_st {
++    ASN1_GENERALIZEDTIME *revocationTime;
++    ASN1_ENUMERATED *revocationReason;
++};
++
++/*-  CertStatus ::= CHOICE {
++ *       good                [0]     IMPLICIT NULL,
++ *       revoked             [1]     IMPLICIT RevokedInfo,
++ *       unknown             [2]     IMPLICIT UnknownInfo }
++ */
++struct ocsp_cert_status_st {
++    int type;
++    union {
++        ASN1_NULL *good;
++        OCSP_REVOKEDINFO *revoked;
++        ASN1_NULL *unknown;
++    } value;
++};
++
++/*-  SingleResponse ::= SEQUENCE {
++ *      certID                       CertID,
++ *      certStatus                   CertStatus,
++ *      thisUpdate                   GeneralizedTime,
++ *      nextUpdate           [0]     EXPLICIT GeneralizedTime OPTIONAL,
++ *      singleExtensions     [1]     EXPLICIT Extensions OPTIONAL }
++ */
++struct ocsp_single_response_st {
++    OCSP_CERTID *certId;
++    OCSP_CERTSTATUS *certStatus;
++    ASN1_GENERALIZEDTIME *thisUpdate;
++    ASN1_GENERALIZEDTIME *nextUpdate;
++    STACK_OF(X509_EXTENSION) *singleExtensions;
++};
++
++/*-  ResponseData ::= SEQUENCE {
++ *      version              [0] EXPLICIT Version DEFAULT v1,
++ *      responderID              ResponderID,
++ *      producedAt               GeneralizedTime,
++ *      responses                SEQUENCE OF SingleResponse,
++ *      responseExtensions   [1] EXPLICIT Extensions OPTIONAL }
++ */
++struct ocsp_response_data_st {
++    ASN1_INTEGER *version;
++    OCSP_RESPID responderId;
++    ASN1_GENERALIZEDTIME *producedAt;
++    STACK_OF(OCSP_SINGLERESP) *responses;
++    STACK_OF(X509_EXTENSION) *responseExtensions;
++};
++
++/*-  BasicOCSPResponse       ::= SEQUENCE {
++ *      tbsResponseData      ResponseData,
++ *      signatureAlgorithm   AlgorithmIdentifier,
++ *      signature            BIT STRING,
++ *      certs                [0] EXPLICIT SEQUENCE OF Certificate OPTIONAL }
++ */
++  /*
++   * Note 1: The value for "signature" is specified in the OCSP rfc2560 as
++   * follows: "The value for the signature SHALL be computed on the hash of
++   * the DER encoding ResponseData." This means that you must hash the
++   * DER-encoded tbsResponseData, and then run it through a crypto-signing
++   * function, which will (at least w/RSA) do a hash-'n'-private-encrypt
++   * operation.  This seems a bit odd, but that's the spec.  Also note that
++   * the data structures do not leave anywhere to independently specify the
++   * algorithm used for the initial hash. So, we look at the
++   * signature-specification algorithm, and try to do something intelligent.
++   * -- Kathy Weinhold, CertCo
++   */
++  /*
++   * Note 2: It seems that the mentioned passage from RFC 2560 (section
++   * 4.2.1) is open for interpretation.  I've done tests against another
++   * responder, and found that it doesn't do the double hashing that the RFC
++   * seems to say one should.  Therefore, all relevant functions take a flag
++   * saying which variant should be used.  -- Richard Levitte, OpenSSL team
++   * and CeloCom
++   */
++struct ocsp_basic_response_st {
++    OCSP_RESPDATA tbsResponseData;
++    X509_ALGOR signatureAlgorithm;
++    ASN1_BIT_STRING *signature;
++    STACK_OF(X509) *certs;
++};
++
++/*-
++ * CrlID ::= SEQUENCE {
++ *     crlUrl               [0]     EXPLICIT IA5String OPTIONAL,
++ *     crlNum               [1]     EXPLICIT INTEGER OPTIONAL,
++ *     crlTime              [2]     EXPLICIT GeneralizedTime OPTIONAL }
++ */
++struct ocsp_crl_id_st {
++    ASN1_IA5STRING *crlUrl;
++    ASN1_INTEGER *crlNum;
++    ASN1_GENERALIZEDTIME *crlTime;
++};
++
++/*-
++ * ServiceLocator ::= SEQUENCE {
++ *      issuer    Name,
++ *      locator   AuthorityInfoAccessSyntax OPTIONAL }
++ */
++struct ocsp_service_locator_st {
++    X509_NAME *issuer;
++    STACK_OF(ACCESS_DESCRIPTION) *locator;
++};
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/ocsp/ocsp_lib.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/ocsp/ocsp_lib.c
+new file mode 100644
+index 0000000..8edd70a
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/ocsp/ocsp_lib.c
+@@ -0,0 +1,222 @@
++/*
++ * Copyright 2000-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include "internal/cryptlib.h"
++#include 
++#include 
++#include 
++#include 
++#include 
++#include "ocsp_lcl.h"
++#include 
++
++/* Convert a certificate and its issuer to an OCSP_CERTID */
++
++OCSP_CERTID *OCSP_cert_to_id(const EVP_MD *dgst, const X509 *subject,
++                             const X509 *issuer)
++{
++    X509_NAME *iname;
++    const ASN1_INTEGER *serial;
++    ASN1_BIT_STRING *ikey;
++    if (!dgst)
++        dgst = EVP_sha1();
++    if (subject) {
++        iname = X509_get_issuer_name(subject);
++        serial = X509_get0_serialNumber(subject);
++    } else {
++        iname = X509_get_subject_name(issuer);
++        serial = NULL;
++    }
++    ikey = X509_get0_pubkey_bitstr(issuer);
++    return OCSP_cert_id_new(dgst, iname, ikey, serial);
++}
++
++OCSP_CERTID *OCSP_cert_id_new(const EVP_MD *dgst,
++                              const X509_NAME *issuerName,
++                              const ASN1_BIT_STRING *issuerKey,
++                              const ASN1_INTEGER *serialNumber)
++{
++    int nid;
++    unsigned int i;
++    X509_ALGOR *alg;
++    OCSP_CERTID *cid = NULL;
++    unsigned char md[EVP_MAX_MD_SIZE];
++
++    if ((cid = OCSP_CERTID_new()) == NULL)
++        goto err;
++
++    alg = &cid->hashAlgorithm;
++    ASN1_OBJECT_free(alg->algorithm);
++    if ((nid = EVP_MD_type(dgst)) == NID_undef) {
++        OCSPerr(OCSP_F_OCSP_CERT_ID_NEW, OCSP_R_UNKNOWN_NID);
++        goto err;
++    }
++    if ((alg->algorithm = OBJ_nid2obj(nid)) == NULL)
++        goto err;
++    if ((alg->parameter = ASN1_TYPE_new()) == NULL)
++        goto err;
++    alg->parameter->type = V_ASN1_NULL;
++
++    if (!X509_NAME_digest(issuerName, dgst, md, &i))
++        goto digerr;
++    if (!(ASN1_OCTET_STRING_set(&cid->issuerNameHash, md, i)))
++        goto err;
++
++    /* Calculate the issuerKey hash, excluding tag and length */
++    if (!EVP_Digest(issuerKey->data, issuerKey->length, md, &i, dgst, NULL))
++        goto err;
++
++    if (!(ASN1_OCTET_STRING_set(&cid->issuerKeyHash, md, i)))
++        goto err;
++
++    if (serialNumber) {
++        if (ASN1_STRING_copy(&cid->serialNumber, serialNumber) == 0)
++            goto err;
++    }
++    return cid;
++ digerr:
++    OCSPerr(OCSP_F_OCSP_CERT_ID_NEW, OCSP_R_DIGEST_ERR);
++ err:
++    OCSP_CERTID_free(cid);
++    return NULL;
++}
++
++int OCSP_id_issuer_cmp(OCSP_CERTID *a, OCSP_CERTID *b)
++{
++    int ret;
++    ret = OBJ_cmp(a->hashAlgorithm.algorithm, b->hashAlgorithm.algorithm);
++    if (ret)
++        return ret;
++    ret = ASN1_OCTET_STRING_cmp(&a->issuerNameHash, &b->issuerNameHash);
++    if (ret)
++        return ret;
++    return ASN1_OCTET_STRING_cmp(&a->issuerKeyHash, &b->issuerKeyHash);
++}
++
++int OCSP_id_cmp(OCSP_CERTID *a, OCSP_CERTID *b)
++{
++    int ret;
++    ret = OCSP_id_issuer_cmp(a, b);
++    if (ret)
++        return ret;
++    return ASN1_INTEGER_cmp(&a->serialNumber, &b->serialNumber);
++}
++
++/*
++ * Parse a URL and split it up into host, port and path components and
++ * whether it is SSL.
++ */
++
++int OCSP_parse_url(const char *url, char **phost, char **pport, char **ppath,
++                   int *pssl)
++{
++    char *p, *buf;
++
++    char *host, *port;
++
++    *phost = NULL;
++    *pport = NULL;
++    *ppath = NULL;
++
++    /* dup the buffer since we are going to mess with it */
++    buf = OPENSSL_strdup(url);
++    if (!buf)
++        goto mem_err;
++
++    /* Check for initial colon */
++    p = strchr(buf, ':');
++
++    if (!p)
++        goto parse_err;
++
++    *(p++) = '\0';
++
++    if (strcmp(buf, "http") == 0) {
++        *pssl = 0;
++        port = "80";
++    } else if (strcmp(buf, "https") == 0) {
++        *pssl = 1;
++        port = "443";
++    } else
++        goto parse_err;
++
++    /* Check for double slash */
++    if ((p[0] != '/') || (p[1] != '/'))
++        goto parse_err;
++
++    p += 2;
++
++    host = p;
++
++    /* Check for trailing part of path */
++
++    p = strchr(p, '/');
++
++    if (!p)
++        *ppath = OPENSSL_strdup("/");
++    else {
++        *ppath = OPENSSL_strdup(p);
++        /* Set start of path to 0 so hostname is valid */
++        *p = '\0';
++    }
++
++    if (!*ppath)
++        goto mem_err;
++
++    p = host;
++    if (host[0] == '[') {
++        /* ipv6 literal */
++        host++;
++        p = strchr(host, ']');
++        if (!p)
++            goto parse_err;
++        *p = '\0';
++        p++;
++    }
++
++    /* Look for optional ':' for port number */
++    if ((p = strchr(p, ':'))) {
++        *p = 0;
++        port = p + 1;
++    }
++
++    *pport = OPENSSL_strdup(port);
++    if (!*pport)
++        goto mem_err;
++
++    *phost = OPENSSL_strdup(host);
++
++    if (!*phost)
++        goto mem_err;
++
++    OPENSSL_free(buf);
++
++    return 1;
++
++ mem_err:
++    OCSPerr(OCSP_F_OCSP_PARSE_URL, ERR_R_MALLOC_FAILURE);
++    goto err;
++
++ parse_err:
++    OCSPerr(OCSP_F_OCSP_PARSE_URL, OCSP_R_ERROR_PARSING_URL);
++
++ err:
++    OPENSSL_free(buf);
++    OPENSSL_free(*ppath);
++    *ppath = NULL;
++    OPENSSL_free(*pport);
++    *pport = NULL;
++    OPENSSL_free(*phost);
++    *phost = NULL;
++    return 0;
++
++}
++
++IMPLEMENT_ASN1_DUP_FUNCTION(OCSP_CERTID)
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/ocsp/ocsp_prn.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/ocsp/ocsp_prn.c
+new file mode 100644
+index 0000000..5605812
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/ocsp/ocsp_prn.c
+@@ -0,0 +1,246 @@
++/*
++ * Copyright 2000-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include 
++#include 
++#include "ocsp_lcl.h"
++#include "internal/cryptlib.h"
++#include 
++
++static int ocsp_certid_print(BIO *bp, OCSP_CERTID *a, int indent)
++{
++    BIO_printf(bp, "%*sCertificate ID:\n", indent, "");
++    indent += 2;
++    BIO_printf(bp, "%*sHash Algorithm: ", indent, "");
++    i2a_ASN1_OBJECT(bp, a->hashAlgorithm.algorithm);
++    BIO_printf(bp, "\n%*sIssuer Name Hash: ", indent, "");
++    i2a_ASN1_STRING(bp, &a->issuerNameHash, 0);
++    BIO_printf(bp, "\n%*sIssuer Key Hash: ", indent, "");
++    i2a_ASN1_STRING(bp, &a->issuerKeyHash, 0);
++    BIO_printf(bp, "\n%*sSerial Number: ", indent, "");
++    i2a_ASN1_INTEGER(bp, &a->serialNumber);
++    BIO_printf(bp, "\n");
++    return 1;
++}
++
++typedef struct {
++    long t;
++    const char *m;
++} OCSP_TBLSTR;
++
++static const char *do_table2string(long s, const OCSP_TBLSTR *ts, size_t len)
++{
++    size_t i;
++    for (i = 0; i < len; i++, ts++)
++        if (ts->t == s)
++            return ts->m;
++    return "(UNKNOWN)";
++}
++
++#define table2string(s, tbl) do_table2string(s, tbl, OSSL_NELEM(tbl))
++
++const char *OCSP_response_status_str(long s)
++{
++    static const OCSP_TBLSTR rstat_tbl[] = {
++        {OCSP_RESPONSE_STATUS_SUCCESSFUL, "successful"},
++        {OCSP_RESPONSE_STATUS_MALFORMEDREQUEST, "malformedrequest"},
++        {OCSP_RESPONSE_STATUS_INTERNALERROR, "internalerror"},
++        {OCSP_RESPONSE_STATUS_TRYLATER, "trylater"},
++        {OCSP_RESPONSE_STATUS_SIGREQUIRED, "sigrequired"},
++        {OCSP_RESPONSE_STATUS_UNAUTHORIZED, "unauthorized"}
++    };
++    return table2string(s, rstat_tbl);
++}
++
++const char *OCSP_cert_status_str(long s)
++{
++    static const OCSP_TBLSTR cstat_tbl[] = {
++        {V_OCSP_CERTSTATUS_GOOD, "good"},
++        {V_OCSP_CERTSTATUS_REVOKED, "revoked"},
++        {V_OCSP_CERTSTATUS_UNKNOWN, "unknown"}
++    };
++    return table2string(s, cstat_tbl);
++}
++
++const char *OCSP_crl_reason_str(long s)
++{
++    static const OCSP_TBLSTR reason_tbl[] = {
++        {OCSP_REVOKED_STATUS_UNSPECIFIED, "unspecified"},
++        {OCSP_REVOKED_STATUS_KEYCOMPROMISE, "keyCompromise"},
++        {OCSP_REVOKED_STATUS_CACOMPROMISE, "cACompromise"},
++        {OCSP_REVOKED_STATUS_AFFILIATIONCHANGED, "affiliationChanged"},
++        {OCSP_REVOKED_STATUS_SUPERSEDED, "superseded"},
++        {OCSP_REVOKED_STATUS_CESSATIONOFOPERATION, "cessationOfOperation"},
++        {OCSP_REVOKED_STATUS_CERTIFICATEHOLD, "certificateHold"},
++        {OCSP_REVOKED_STATUS_REMOVEFROMCRL, "removeFromCRL"}
++    };
++    return table2string(s, reason_tbl);
++}
++
++int OCSP_REQUEST_print(BIO *bp, OCSP_REQUEST *o, unsigned long flags)
++{
++    int i;
++    long l;
++    OCSP_CERTID *cid = NULL;
++    OCSP_ONEREQ *one = NULL;
++    OCSP_REQINFO *inf = &o->tbsRequest;
++    OCSP_SIGNATURE *sig = o->optionalSignature;
++
++    if (BIO_write(bp, "OCSP Request Data:\n", 19) <= 0)
++        goto err;
++    l = ASN1_INTEGER_get(inf->version);
++    if (BIO_printf(bp, "    Version: %lu (0x%lx)", l + 1, l) <= 0)
++        goto err;
++    if (inf->requestorName != NULL) {
++        if (BIO_write(bp, "\n    Requestor Name: ", 21) <= 0)
++            goto err;
++        GENERAL_NAME_print(bp, inf->requestorName);
++    }
++    if (BIO_write(bp, "\n    Requestor List:\n", 21) <= 0)
++        goto err;
++    for (i = 0; i < sk_OCSP_ONEREQ_num(inf->requestList); i++) {
++        one = sk_OCSP_ONEREQ_value(inf->requestList, i);
++        cid = one->reqCert;
++        ocsp_certid_print(bp, cid, 8);
++        if (!X509V3_extensions_print(bp,
++                                     "Request Single Extensions",
++                                     one->singleRequestExtensions, flags, 8))
++            goto err;
++    }
++    if (!X509V3_extensions_print(bp, "Request Extensions",
++                                 inf->requestExtensions, flags, 4))
++        goto err;
++    if (sig) {
++        X509_signature_print(bp, &sig->signatureAlgorithm, sig->signature);
++        for (i = 0; i < sk_X509_num(sig->certs); i++) {
++            X509_print(bp, sk_X509_value(sig->certs, i));
++            PEM_write_bio_X509(bp, sk_X509_value(sig->certs, i));
++        }
++    }
++    return 1;
++ err:
++    return 0;
++}
++
++int OCSP_RESPONSE_print(BIO *bp, OCSP_RESPONSE *o, unsigned long flags)
++{
++    int i, ret = 0;
++    long l;
++    OCSP_CERTID *cid = NULL;
++    OCSP_BASICRESP *br = NULL;
++    OCSP_RESPID *rid = NULL;
++    OCSP_RESPDATA *rd = NULL;
++    OCSP_CERTSTATUS *cst = NULL;
++    OCSP_REVOKEDINFO *rev = NULL;
++    OCSP_SINGLERESP *single = NULL;
++    OCSP_RESPBYTES *rb = o->responseBytes;
++
++    if (BIO_puts(bp, "OCSP Response Data:\n") <= 0)
++        goto err;
++    l = ASN1_ENUMERATED_get(o->responseStatus);
++    if (BIO_printf(bp, "    OCSP Response Status: %s (0x%lx)\n",
++                   OCSP_response_status_str(l), l) <= 0)
++        goto err;
++    if (rb == NULL)
++        return 1;
++    if (BIO_puts(bp, "    Response Type: ") <= 0)
++        goto err;
++    if (i2a_ASN1_OBJECT(bp, rb->responseType) <= 0)
++        goto err;
++    if (OBJ_obj2nid(rb->responseType) != NID_id_pkix_OCSP_basic) {
++        BIO_puts(bp, " (unknown response type)\n");
++        return 1;
++    }
++
++    if ((br = OCSP_response_get1_basic(o)) == NULL)
++        goto err;
++    rd = &br->tbsResponseData;
++    l = ASN1_INTEGER_get(rd->version);
++    if (BIO_printf(bp, "\n    Version: %lu (0x%lx)\n", l + 1, l) <= 0)
++        goto err;
++    if (BIO_puts(bp, "    Responder Id: ") <= 0)
++        goto err;
++
++    rid = &rd->responderId;
++    switch (rid->type) {
++    case V_OCSP_RESPID_NAME:
++        X509_NAME_print_ex(bp, rid->value.byName, 0, XN_FLAG_ONELINE);
++        break;
++    case V_OCSP_RESPID_KEY:
++        i2a_ASN1_STRING(bp, rid->value.byKey, 0);
++        break;
++    }
++
++    if (BIO_printf(bp, "\n    Produced At: ") <= 0)
++        goto err;
++    if (!ASN1_GENERALIZEDTIME_print(bp, rd->producedAt))
++        goto err;
++    if (BIO_printf(bp, "\n    Responses:\n") <= 0)
++        goto err;
++    for (i = 0; i < sk_OCSP_SINGLERESP_num(rd->responses); i++) {
++        if (!sk_OCSP_SINGLERESP_value(rd->responses, i))
++            continue;
++        single = sk_OCSP_SINGLERESP_value(rd->responses, i);
++        cid = single->certId;
++        if (ocsp_certid_print(bp, cid, 4) <= 0)
++            goto err;
++        cst = single->certStatus;
++        if (BIO_printf(bp, "    Cert Status: %s",
++                       OCSP_cert_status_str(cst->type)) <= 0)
++            goto err;
++        if (cst->type == V_OCSP_CERTSTATUS_REVOKED) {
++            rev = cst->value.revoked;
++            if (BIO_printf(bp, "\n    Revocation Time: ") <= 0)
++                goto err;
++            if (!ASN1_GENERALIZEDTIME_print(bp, rev->revocationTime))
++                goto err;
++            if (rev->revocationReason) {
++                l = ASN1_ENUMERATED_get(rev->revocationReason);
++                if (BIO_printf(bp,
++                               "\n    Revocation Reason: %s (0x%lx)",
++                               OCSP_crl_reason_str(l), l) <= 0)
++                    goto err;
++            }
++        }
++        if (BIO_printf(bp, "\n    This Update: ") <= 0)
++            goto err;
++        if (!ASN1_GENERALIZEDTIME_print(bp, single->thisUpdate))
++            goto err;
++        if (single->nextUpdate) {
++            if (BIO_printf(bp, "\n    Next Update: ") <= 0)
++                goto err;
++            if (!ASN1_GENERALIZEDTIME_print(bp, single->nextUpdate))
++                goto err;
++        }
++        if (BIO_write(bp, "\n", 1) <= 0)
++            goto err;
++        if (!X509V3_extensions_print(bp,
++                                     "Response Single Extensions",
++                                     single->singleExtensions, flags, 8))
++            goto err;
++        if (BIO_write(bp, "\n", 1) <= 0)
++            goto err;
++    }
++    if (!X509V3_extensions_print(bp, "Response Extensions",
++                                 rd->responseExtensions, flags, 4))
++        goto err;
++    if (X509_signature_print(bp, &br->signatureAlgorithm, br->signature) <= 0)
++        goto err;
++
++    for (i = 0; i < sk_X509_num(br->certs); i++) {
++        X509_print(bp, sk_X509_value(br->certs, i));
++        PEM_write_bio_X509(bp, sk_X509_value(br->certs, i));
++    }
++
++    ret = 1;
++ err:
++    OCSP_BASICRESP_free(br);
++    return ret;
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/ocsp/ocsp_srv.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/ocsp/ocsp_srv.c
+new file mode 100644
+index 0000000..46a4bf7
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/ocsp/ocsp_srv.c
+@@ -0,0 +1,277 @@
++/*
++ * Copyright 2001-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include "internal/cryptlib.h"
++#include 
++#include 
++#include 
++#include 
++#include 
++#include "ocsp_lcl.h"
++
++/*
++ * Utility functions related to sending OCSP responses and extracting
++ * relevant information from the request.
++ */
++
++int OCSP_request_onereq_count(OCSP_REQUEST *req)
++{
++    return sk_OCSP_ONEREQ_num(req->tbsRequest.requestList);
++}
++
++OCSP_ONEREQ *OCSP_request_onereq_get0(OCSP_REQUEST *req, int i)
++{
++    return sk_OCSP_ONEREQ_value(req->tbsRequest.requestList, i);
++}
++
++OCSP_CERTID *OCSP_onereq_get0_id(OCSP_ONEREQ *one)
++{
++    return one->reqCert;
++}
++
++int OCSP_id_get0_info(ASN1_OCTET_STRING **piNameHash, ASN1_OBJECT **pmd,
++                      ASN1_OCTET_STRING **pikeyHash,
++                      ASN1_INTEGER **pserial, OCSP_CERTID *cid)
++{
++    if (!cid)
++        return 0;
++    if (pmd)
++        *pmd = cid->hashAlgorithm.algorithm;
++    if (piNameHash)
++        *piNameHash = &cid->issuerNameHash;
++    if (pikeyHash)
++        *pikeyHash = &cid->issuerKeyHash;
++    if (pserial)
++        *pserial = &cid->serialNumber;
++    return 1;
++}
++
++int OCSP_request_is_signed(OCSP_REQUEST *req)
++{
++    if (req->optionalSignature)
++        return 1;
++    return 0;
++}
++
++/* Create an OCSP response and encode an optional basic response */
++OCSP_RESPONSE *OCSP_response_create(int status, OCSP_BASICRESP *bs)
++{
++    OCSP_RESPONSE *rsp = NULL;
++
++    if ((rsp = OCSP_RESPONSE_new()) == NULL)
++        goto err;
++    if (!(ASN1_ENUMERATED_set(rsp->responseStatus, status)))
++        goto err;
++    if (!bs)
++        return rsp;
++    if ((rsp->responseBytes = OCSP_RESPBYTES_new()) == NULL)
++        goto err;
++    rsp->responseBytes->responseType = OBJ_nid2obj(NID_id_pkix_OCSP_basic);
++    if (!ASN1_item_pack
++        (bs, ASN1_ITEM_rptr(OCSP_BASICRESP), &rsp->responseBytes->response))
++         goto err;
++    return rsp;
++ err:
++    OCSP_RESPONSE_free(rsp);
++    return NULL;
++}
++
++OCSP_SINGLERESP *OCSP_basic_add1_status(OCSP_BASICRESP *rsp,
++                                        OCSP_CERTID *cid,
++                                        int status, int reason,
++                                        ASN1_TIME *revtime,
++                                        ASN1_TIME *thisupd,
++                                        ASN1_TIME *nextupd)
++{
++    OCSP_SINGLERESP *single = NULL;
++    OCSP_CERTSTATUS *cs;
++    OCSP_REVOKEDINFO *ri;
++
++    if (rsp->tbsResponseData.responses == NULL
++        && (rsp->tbsResponseData.responses
++                = sk_OCSP_SINGLERESP_new_null()) == NULL)
++        goto err;
++
++    if ((single = OCSP_SINGLERESP_new()) == NULL)
++        goto err;
++
++    if (!ASN1_TIME_to_generalizedtime(thisupd, &single->thisUpdate))
++        goto err;
++    if (nextupd &&
++        !ASN1_TIME_to_generalizedtime(nextupd, &single->nextUpdate))
++        goto err;
++
++    OCSP_CERTID_free(single->certId);
++
++    if ((single->certId = OCSP_CERTID_dup(cid)) == NULL)
++        goto err;
++
++    cs = single->certStatus;
++    switch (cs->type = status) {
++    case V_OCSP_CERTSTATUS_REVOKED:
++        if (!revtime) {
++            OCSPerr(OCSP_F_OCSP_BASIC_ADD1_STATUS, OCSP_R_NO_REVOKED_TIME);
++            goto err;
++        }
++        if ((cs->value.revoked = ri = OCSP_REVOKEDINFO_new()) == NULL)
++            goto err;
++        if (!ASN1_TIME_to_generalizedtime(revtime, &ri->revocationTime))
++            goto err;
++        if (reason != OCSP_REVOKED_STATUS_NOSTATUS) {
++            if ((ri->revocationReason = ASN1_ENUMERATED_new()) == NULL)
++                goto err;
++            if (!(ASN1_ENUMERATED_set(ri->revocationReason, reason)))
++                goto err;
++        }
++        break;
++
++    case V_OCSP_CERTSTATUS_GOOD:
++        if ((cs->value.good = ASN1_NULL_new()) == NULL)
++            goto err;
++        break;
++
++    case V_OCSP_CERTSTATUS_UNKNOWN:
++        if ((cs->value.unknown = ASN1_NULL_new()) == NULL)
++            goto err;
++        break;
++
++    default:
++        goto err;
++
++    }
++    if (!(sk_OCSP_SINGLERESP_push(rsp->tbsResponseData.responses, single)))
++        goto err;
++    return single;
++ err:
++    OCSP_SINGLERESP_free(single);
++    return NULL;
++}
++
++/* Add a certificate to an OCSP request */
++
++int OCSP_basic_add1_cert(OCSP_BASICRESP *resp, X509 *cert)
++{
++    if (resp->certs == NULL
++        && (resp->certs = sk_X509_new_null()) == NULL)
++        return 0;
++
++    if (!sk_X509_push(resp->certs, cert))
++        return 0;
++    X509_up_ref(cert);
++    return 1;
++}
++
++int OCSP_basic_sign(OCSP_BASICRESP *brsp,
++                    X509 *signer, EVP_PKEY *key, const EVP_MD *dgst,
++                    STACK_OF(X509) *certs, unsigned long flags)
++{
++    int i;
++    OCSP_RESPID *rid;
++
++    if (!X509_check_private_key(signer, key)) {
++        OCSPerr(OCSP_F_OCSP_BASIC_SIGN,
++                OCSP_R_PRIVATE_KEY_DOES_NOT_MATCH_CERTIFICATE);
++        goto err;
++    }
++
++    if (!(flags & OCSP_NOCERTS)) {
++        if (!OCSP_basic_add1_cert(brsp, signer))
++            goto err;
++        for (i = 0; i < sk_X509_num(certs); i++) {
++            X509 *tmpcert = sk_X509_value(certs, i);
++            if (!OCSP_basic_add1_cert(brsp, tmpcert))
++                goto err;
++        }
++    }
++
++    rid = &brsp->tbsResponseData.responderId;
++    if (flags & OCSP_RESPID_KEY) {
++        if (!OCSP_RESPID_set_by_key(rid, signer))
++            goto err;
++    } else if (!OCSP_RESPID_set_by_name(rid, signer)) {
++        goto err;
++    }
++
++    if (!(flags & OCSP_NOTIME) &&
++        !X509_gmtime_adj(brsp->tbsResponseData.producedAt, 0))
++        goto err;
++
++    /*
++     * Right now, I think that not doing double hashing is the right thing.
++     * -- Richard Levitte
++     */
++
++    if (!OCSP_BASICRESP_sign(brsp, key, dgst, 0))
++        goto err;
++
++    return 1;
++ err:
++    return 0;
++}
++
++int OCSP_RESPID_set_by_name(OCSP_RESPID *respid, X509 *cert)
++{
++    if (!X509_NAME_set(&respid->value.byName, X509_get_subject_name(cert)))
++        return 0;
++
++    respid->type = V_OCSP_RESPID_NAME;
++
++    return 1;
++}
++
++int OCSP_RESPID_set_by_key(OCSP_RESPID *respid, X509 *cert)
++{
++    ASN1_OCTET_STRING *byKey = NULL;
++    unsigned char md[SHA_DIGEST_LENGTH];
++
++    /* RFC2560 requires SHA1 */
++    if (!X509_pubkey_digest(cert, EVP_sha1(), md, NULL))
++        return 0;
++
++    byKey = ASN1_OCTET_STRING_new();
++    if (byKey == NULL)
++        return 0;
++
++    if (!(ASN1_OCTET_STRING_set(byKey, md, SHA_DIGEST_LENGTH))) {
++        ASN1_OCTET_STRING_free(byKey);
++        return 0;
++    }
++
++    respid->type = V_OCSP_RESPID_KEY;
++    respid->value.byKey = byKey;
++
++    return 1;
++}
++
++int OCSP_RESPID_match(OCSP_RESPID *respid, X509 *cert)
++{
++    if (respid->type == V_OCSP_RESPID_KEY) {
++        unsigned char md[SHA_DIGEST_LENGTH];
++
++        if (respid->value.byKey == NULL)
++            return 0;
++
++        /* RFC2560 requires SHA1 */
++        if (!X509_pubkey_digest(cert, EVP_sha1(), md, NULL))
++            return 0;
++
++        return (ASN1_STRING_length(respid->value.byKey) == SHA_DIGEST_LENGTH)
++            && (memcmp(ASN1_STRING_get0_data(respid->value.byKey), md,
++                       SHA_DIGEST_LENGTH) == 0);
++    } else if(respid->type == V_OCSP_RESPID_NAME) {
++        if (respid->value.byName == NULL)
++            return 0;
++
++        return X509_NAME_cmp(respid->value.byName,
++                             X509_get_subject_name(cert)) == 0;
++    }
++
++    return 0;
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/ocsp/ocsp_vfy.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/ocsp/ocsp_vfy.c
+new file mode 100644
+index 0000000..e2cfa6d
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/ocsp/ocsp_vfy.c
+@@ -0,0 +1,424 @@
++/*
++ * Copyright 2001-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include "ocsp_lcl.h"
++#include 
++#include 
++
++static int ocsp_find_signer(X509 **psigner, OCSP_BASICRESP *bs,
++                            STACK_OF(X509) *certs, unsigned long flags);
++static X509 *ocsp_find_signer_sk(STACK_OF(X509) *certs, OCSP_RESPID *id);
++static int ocsp_check_issuer(OCSP_BASICRESP *bs, STACK_OF(X509) *chain);
++static int ocsp_check_ids(STACK_OF(OCSP_SINGLERESP) *sresp,
++                          OCSP_CERTID **ret);
++static int ocsp_match_issuerid(X509 *cert, OCSP_CERTID *cid,
++                               STACK_OF(OCSP_SINGLERESP) *sresp);
++static int ocsp_check_delegated(X509 *x);
++static int ocsp_req_find_signer(X509 **psigner, OCSP_REQUEST *req,
++                                X509_NAME *nm, STACK_OF(X509) *certs,
++                                unsigned long flags);
++
++/* Verify a basic response message */
++
++int OCSP_basic_verify(OCSP_BASICRESP *bs, STACK_OF(X509) *certs,
++                      X509_STORE *st, unsigned long flags)
++{
++    X509 *signer, *x;
++    STACK_OF(X509) *chain = NULL;
++    STACK_OF(X509) *untrusted = NULL;
++    X509_STORE_CTX *ctx = NULL;
++    int i, ret = ocsp_find_signer(&signer, bs, certs, flags);
++
++    if (!ret) {
++        OCSPerr(OCSP_F_OCSP_BASIC_VERIFY,
++                OCSP_R_SIGNER_CERTIFICATE_NOT_FOUND);
++        goto end;
++    }
++    ctx = X509_STORE_CTX_new();
++    if (ctx == NULL) {
++        OCSPerr(OCSP_F_OCSP_BASIC_VERIFY, ERR_R_MALLOC_FAILURE);
++        goto f_err;
++    }
++    if ((ret == 2) && (flags & OCSP_TRUSTOTHER))
++        flags |= OCSP_NOVERIFY;
++    if (!(flags & OCSP_NOSIGS)) {
++        EVP_PKEY *skey;
++        skey = X509_get0_pubkey(signer);
++        if (skey == NULL) {
++            OCSPerr(OCSP_F_OCSP_BASIC_VERIFY, OCSP_R_NO_SIGNER_KEY);
++            goto err;
++        }
++        ret = OCSP_BASICRESP_verify(bs, skey, 0);
++        if (ret <= 0) {
++            OCSPerr(OCSP_F_OCSP_BASIC_VERIFY, OCSP_R_SIGNATURE_FAILURE);
++            goto end;
++        }
++    }
++    if (!(flags & OCSP_NOVERIFY)) {
++        int init_res;
++        if (flags & OCSP_NOCHAIN) {
++            untrusted = NULL;
++        } else if (bs->certs && certs) {
++            untrusted = sk_X509_dup(bs->certs);
++            for (i = 0; i < sk_X509_num(certs); i++) {
++                if (!sk_X509_push(untrusted, sk_X509_value(certs, i))) {
++                    OCSPerr(OCSP_F_OCSP_BASIC_VERIFY, ERR_R_MALLOC_FAILURE);
++                    goto f_err;
++                }
++            }
++        } else {
++            untrusted = bs->certs;
++        }
++        init_res = X509_STORE_CTX_init(ctx, st, signer, untrusted);
++        if (!init_res) {
++            OCSPerr(OCSP_F_OCSP_BASIC_VERIFY, ERR_R_X509_LIB);
++            goto f_err;
++        }
++
++        X509_STORE_CTX_set_purpose(ctx, X509_PURPOSE_OCSP_HELPER);
++        ret = X509_verify_cert(ctx);
++        chain = X509_STORE_CTX_get1_chain(ctx);
++        if (ret <= 0) {
++            i = X509_STORE_CTX_get_error(ctx);
++            OCSPerr(OCSP_F_OCSP_BASIC_VERIFY,
++                    OCSP_R_CERTIFICATE_VERIFY_ERROR);
++            ERR_add_error_data(2, "Verify error:",
++                               X509_verify_cert_error_string(i));
++            goto end;
++        }
++        if (flags & OCSP_NOCHECKS) {
++            ret = 1;
++            goto end;
++        }
++        /*
++         * At this point we have a valid certificate chain need to verify it
++         * against the OCSP issuer criteria.
++         */
++        ret = ocsp_check_issuer(bs, chain);
++
++        /* If fatal error or valid match then finish */
++        if (ret != 0)
++            goto end;
++
++        /*
++         * Easy case: explicitly trusted. Get root CA and check for explicit
++         * trust
++         */
++        if (flags & OCSP_NOEXPLICIT)
++            goto end;
++
++        x = sk_X509_value(chain, sk_X509_num(chain) - 1);
++        if (X509_check_trust(x, NID_OCSP_sign, 0) != X509_TRUST_TRUSTED) {
++            OCSPerr(OCSP_F_OCSP_BASIC_VERIFY, OCSP_R_ROOT_CA_NOT_TRUSTED);
++            goto err;
++        }
++        ret = 1;
++    }
++ end:
++    X509_STORE_CTX_free(ctx);
++    sk_X509_pop_free(chain, X509_free);
++    if (bs->certs && certs)
++        sk_X509_free(untrusted);
++    return ret;
++
++ err:
++    ret = 0;
++    goto end;
++ f_err:
++    ret = -1;
++    goto end;
++}
++
++static int ocsp_find_signer(X509 **psigner, OCSP_BASICRESP *bs,
++                            STACK_OF(X509) *certs, unsigned long flags)
++{
++    X509 *signer;
++    OCSP_RESPID *rid = &bs->tbsResponseData.responderId;
++    if ((signer = ocsp_find_signer_sk(certs, rid))) {
++        *psigner = signer;
++        return 2;
++    }
++    if (!(flags & OCSP_NOINTERN) &&
++        (signer = ocsp_find_signer_sk(bs->certs, rid))) {
++        *psigner = signer;
++        return 1;
++    }
++    /* Maybe lookup from store if by subject name */
++
++    *psigner = NULL;
++    return 0;
++}
++
++static X509 *ocsp_find_signer_sk(STACK_OF(X509) *certs, OCSP_RESPID *id)
++{
++    int i;
++    unsigned char tmphash[SHA_DIGEST_LENGTH], *keyhash;
++    X509 *x;
++
++    /* Easy if lookup by name */
++    if (id->type == V_OCSP_RESPID_NAME)
++        return X509_find_by_subject(certs, id->value.byName);
++
++    /* Lookup by key hash */
++
++    /* If key hash isn't SHA1 length then forget it */
++    if (id->value.byKey->length != SHA_DIGEST_LENGTH)
++        return NULL;
++    keyhash = id->value.byKey->data;
++    /* Calculate hash of each key and compare */
++    for (i = 0; i < sk_X509_num(certs); i++) {
++        x = sk_X509_value(certs, i);
++        X509_pubkey_digest(x, EVP_sha1(), tmphash, NULL);
++        if (!memcmp(keyhash, tmphash, SHA_DIGEST_LENGTH))
++            return x;
++    }
++    return NULL;
++}
++
++static int ocsp_check_issuer(OCSP_BASICRESP *bs, STACK_OF(X509) *chain)
++{
++    STACK_OF(OCSP_SINGLERESP) *sresp;
++    X509 *signer, *sca;
++    OCSP_CERTID *caid = NULL;
++    int i;
++    sresp = bs->tbsResponseData.responses;
++
++    if (sk_X509_num(chain) <= 0) {
++        OCSPerr(OCSP_F_OCSP_CHECK_ISSUER, OCSP_R_NO_CERTIFICATES_IN_CHAIN);
++        return -1;
++    }
++
++    /* See if the issuer IDs match. */
++    i = ocsp_check_ids(sresp, &caid);
++
++    /* If ID mismatch or other error then return */
++    if (i <= 0)
++        return i;
++
++    signer = sk_X509_value(chain, 0);
++    /* Check to see if OCSP responder CA matches request CA */
++    if (sk_X509_num(chain) > 1) {
++        sca = sk_X509_value(chain, 1);
++        i = ocsp_match_issuerid(sca, caid, sresp);
++        if (i < 0)
++            return i;
++        if (i) {
++            /* We have a match, if extensions OK then success */
++            if (ocsp_check_delegated(signer))
++                return 1;
++            return 0;
++        }
++    }
++
++    /* Otherwise check if OCSP request signed directly by request CA */
++    return ocsp_match_issuerid(signer, caid, sresp);
++}
++
++/*
++ * Check the issuer certificate IDs for equality. If there is a mismatch with
++ * the same algorithm then there's no point trying to match any certificates
++ * against the issuer. If the issuer IDs all match then we just need to check
++ * equality against one of them.
++ */
++
++static int ocsp_check_ids(STACK_OF(OCSP_SINGLERESP) *sresp, OCSP_CERTID **ret)
++{
++    OCSP_CERTID *tmpid, *cid;
++    int i, idcount;
++
++    idcount = sk_OCSP_SINGLERESP_num(sresp);
++    if (idcount <= 0) {
++        OCSPerr(OCSP_F_OCSP_CHECK_IDS,
++                OCSP_R_RESPONSE_CONTAINS_NO_REVOCATION_DATA);
++        return -1;
++    }
++
++    cid = sk_OCSP_SINGLERESP_value(sresp, 0)->certId;
++
++    *ret = NULL;
++
++    for (i = 1; i < idcount; i++) {
++        tmpid = sk_OCSP_SINGLERESP_value(sresp, i)->certId;
++        /* Check to see if IDs match */
++        if (OCSP_id_issuer_cmp(cid, tmpid)) {
++            /* If algorithm mismatch let caller deal with it */
++            if (OBJ_cmp(tmpid->hashAlgorithm.algorithm,
++                        cid->hashAlgorithm.algorithm))
++                return 2;
++            /* Else mismatch */
++            return 0;
++        }
++    }
++
++    /* All IDs match: only need to check one ID */
++    *ret = cid;
++    return 1;
++}
++
++static int ocsp_match_issuerid(X509 *cert, OCSP_CERTID *cid,
++                               STACK_OF(OCSP_SINGLERESP) *sresp)
++{
++    /* If only one ID to match then do it */
++    if (cid) {
++        const EVP_MD *dgst;
++        X509_NAME *iname;
++        int mdlen;
++        unsigned char md[EVP_MAX_MD_SIZE];
++        if ((dgst = EVP_get_digestbyobj(cid->hashAlgorithm.algorithm))
++                == NULL) {
++            OCSPerr(OCSP_F_OCSP_MATCH_ISSUERID,
++                    OCSP_R_UNKNOWN_MESSAGE_DIGEST);
++            return -1;
++        }
++
++        mdlen = EVP_MD_size(dgst);
++        if (mdlen < 0)
++            return -1;
++        if ((cid->issuerNameHash.length != mdlen) ||
++            (cid->issuerKeyHash.length != mdlen))
++            return 0;
++        iname = X509_get_subject_name(cert);
++        if (!X509_NAME_digest(iname, dgst, md, NULL))
++            return -1;
++        if (memcmp(md, cid->issuerNameHash.data, mdlen))
++            return 0;
++        X509_pubkey_digest(cert, dgst, md, NULL);
++        if (memcmp(md, cid->issuerKeyHash.data, mdlen))
++            return 0;
++
++        return 1;
++
++    } else {
++        /* We have to match the whole lot */
++        int i, ret;
++        OCSP_CERTID *tmpid;
++        for (i = 0; i < sk_OCSP_SINGLERESP_num(sresp); i++) {
++            tmpid = sk_OCSP_SINGLERESP_value(sresp, i)->certId;
++            ret = ocsp_match_issuerid(cert, tmpid, NULL);
++            if (ret <= 0)
++                return ret;
++        }
++        return 1;
++    }
++
++}
++
++static int ocsp_check_delegated(X509 *x)
++{
++    if ((X509_get_extension_flags(x) & EXFLAG_XKUSAGE)
++        && (X509_get_extended_key_usage(x) & XKU_OCSP_SIGN))
++        return 1;
++    OCSPerr(OCSP_F_OCSP_CHECK_DELEGATED, OCSP_R_MISSING_OCSPSIGNING_USAGE);
++    return 0;
++}
++
++/*
++ * Verify an OCSP request. This is fortunately much easier than OCSP response
++ * verify. Just find the signers certificate and verify it against a given
++ * trust value.
++ */
++
++int OCSP_request_verify(OCSP_REQUEST *req, STACK_OF(X509) *certs,
++                        X509_STORE *store, unsigned long flags)
++{
++    X509 *signer;
++    X509_NAME *nm;
++    GENERAL_NAME *gen;
++    int ret = 0;
++    X509_STORE_CTX *ctx = X509_STORE_CTX_new();
++
++    if (ctx == NULL) {
++        OCSPerr(OCSP_F_OCSP_REQUEST_VERIFY, ERR_R_MALLOC_FAILURE);
++        goto err;
++    }
++
++    if (!req->optionalSignature) {
++        OCSPerr(OCSP_F_OCSP_REQUEST_VERIFY, OCSP_R_REQUEST_NOT_SIGNED);
++        goto err;
++    }
++    gen = req->tbsRequest.requestorName;
++    if (!gen || gen->type != GEN_DIRNAME) {
++        OCSPerr(OCSP_F_OCSP_REQUEST_VERIFY,
++                OCSP_R_UNSUPPORTED_REQUESTORNAME_TYPE);
++        goto err;
++    }
++    nm = gen->d.directoryName;
++    ret = ocsp_req_find_signer(&signer, req, nm, certs, flags);
++    if (ret <= 0) {
++        OCSPerr(OCSP_F_OCSP_REQUEST_VERIFY,
++                OCSP_R_SIGNER_CERTIFICATE_NOT_FOUND);
++        goto err;
++    }
++    if ((ret == 2) && (flags & OCSP_TRUSTOTHER))
++        flags |= OCSP_NOVERIFY;
++    if (!(flags & OCSP_NOSIGS)) {
++        EVP_PKEY *skey;
++        skey = X509_get0_pubkey(signer);
++        ret = OCSP_REQUEST_verify(req, skey);
++        if (ret <= 0) {
++            OCSPerr(OCSP_F_OCSP_REQUEST_VERIFY, OCSP_R_SIGNATURE_FAILURE);
++            goto err;
++        }
++    }
++    if (!(flags & OCSP_NOVERIFY)) {
++        int init_res;
++        if (flags & OCSP_NOCHAIN)
++            init_res = X509_STORE_CTX_init(ctx, store, signer, NULL);
++        else
++            init_res = X509_STORE_CTX_init(ctx, store, signer,
++                                           req->optionalSignature->certs);
++        if (!init_res) {
++            OCSPerr(OCSP_F_OCSP_REQUEST_VERIFY, ERR_R_X509_LIB);
++            goto err;
++        }
++
++        X509_STORE_CTX_set_purpose(ctx, X509_PURPOSE_OCSP_HELPER);
++        X509_STORE_CTX_set_trust(ctx, X509_TRUST_OCSP_REQUEST);
++        ret = X509_verify_cert(ctx);
++        if (ret <= 0) {
++            ret = X509_STORE_CTX_get_error(ctx);
++            OCSPerr(OCSP_F_OCSP_REQUEST_VERIFY,
++                    OCSP_R_CERTIFICATE_VERIFY_ERROR);
++            ERR_add_error_data(2, "Verify error:",
++                               X509_verify_cert_error_string(ret));
++            goto err;
++        }
++    }
++    ret = 1;
++    goto end;
++
++err:
++    ret = 0;
++end:
++    X509_STORE_CTX_free(ctx);
++    return ret;
++
++}
++
++static int ocsp_req_find_signer(X509 **psigner, OCSP_REQUEST *req,
++                                X509_NAME *nm, STACK_OF(X509) *certs,
++                                unsigned long flags)
++{
++    X509 *signer;
++    if (!(flags & OCSP_NOINTERN)) {
++        signer = X509_find_by_subject(req->optionalSignature->certs, nm);
++        if (signer) {
++            *psigner = signer;
++            return 1;
++        }
++    }
++
++    signer = X509_find_by_subject(certs, nm);
++    if (signer) {
++        *psigner = signer;
++        return 2;
++    }
++    return 0;
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/ocsp/v3_ocsp.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/ocsp/v3_ocsp.c
+new file mode 100644
+index 0000000..2d425a8
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/ocsp/v3_ocsp.c
+@@ -0,0 +1,264 @@
++/*
++ * Copyright 2000-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++# include 
++# include "internal/cryptlib.h"
++# include 
++# include 
++# include 
++# include "ocsp_lcl.h"
++# include 
++# include "../x509v3/ext_dat.h"
++
++/*
++ * OCSP extensions and a couple of CRL entry extensions
++ */
++
++static int i2r_ocsp_crlid(const X509V3_EXT_METHOD *method, void *nonce,
++                          BIO *out, int indent);
++static int i2r_ocsp_acutoff(const X509V3_EXT_METHOD *method, void *nonce,
++                            BIO *out, int indent);
++static int i2r_object(const X509V3_EXT_METHOD *method, void *obj, BIO *out,
++                      int indent);
++
++static void *ocsp_nonce_new(void);
++static int i2d_ocsp_nonce(void *a, unsigned char **pp);
++static void *d2i_ocsp_nonce(void *a, const unsigned char **pp, long length);
++static void ocsp_nonce_free(void *a);
++static int i2r_ocsp_nonce(const X509V3_EXT_METHOD *method, void *nonce,
++                          BIO *out, int indent);
++
++static int i2r_ocsp_nocheck(const X509V3_EXT_METHOD *method,
++                            void *nocheck, BIO *out, int indent);
++static void *s2i_ocsp_nocheck(const X509V3_EXT_METHOD *method,
++                              X509V3_CTX *ctx, const char *str);
++static int i2r_ocsp_serviceloc(const X509V3_EXT_METHOD *method, void *in,
++                               BIO *bp, int ind);
++
++const X509V3_EXT_METHOD v3_ocsp_crlid = {
++    NID_id_pkix_OCSP_CrlID, 0, ASN1_ITEM_ref(OCSP_CRLID),
++    0, 0, 0, 0,
++    0, 0,
++    0, 0,
++    i2r_ocsp_crlid, 0,
++    NULL
++};
++
++const X509V3_EXT_METHOD v3_ocsp_acutoff = {
++    NID_id_pkix_OCSP_archiveCutoff, 0, ASN1_ITEM_ref(ASN1_GENERALIZEDTIME),
++    0, 0, 0, 0,
++    0, 0,
++    0, 0,
++    i2r_ocsp_acutoff, 0,
++    NULL
++};
++
++const X509V3_EXT_METHOD v3_crl_invdate = {
++    NID_invalidity_date, 0, ASN1_ITEM_ref(ASN1_GENERALIZEDTIME),
++    0, 0, 0, 0,
++    0, 0,
++    0, 0,
++    i2r_ocsp_acutoff, 0,
++    NULL
++};
++
++const X509V3_EXT_METHOD v3_crl_hold = {
++    NID_hold_instruction_code, 0, ASN1_ITEM_ref(ASN1_OBJECT),
++    0, 0, 0, 0,
++    0, 0,
++    0, 0,
++    i2r_object, 0,
++    NULL
++};
++
++const X509V3_EXT_METHOD v3_ocsp_nonce = {
++    NID_id_pkix_OCSP_Nonce, 0, NULL,
++    ocsp_nonce_new,
++    ocsp_nonce_free,
++    d2i_ocsp_nonce,
++    i2d_ocsp_nonce,
++    0, 0,
++    0, 0,
++    i2r_ocsp_nonce, 0,
++    NULL
++};
++
++const X509V3_EXT_METHOD v3_ocsp_nocheck = {
++    NID_id_pkix_OCSP_noCheck, 0, ASN1_ITEM_ref(ASN1_NULL),
++    0, 0, 0, 0,
++    0, s2i_ocsp_nocheck,
++    0, 0,
++    i2r_ocsp_nocheck, 0,
++    NULL
++};
++
++const X509V3_EXT_METHOD v3_ocsp_serviceloc = {
++    NID_id_pkix_OCSP_serviceLocator, 0, ASN1_ITEM_ref(OCSP_SERVICELOC),
++    0, 0, 0, 0,
++    0, 0,
++    0, 0,
++    i2r_ocsp_serviceloc, 0,
++    NULL
++};
++
++static int i2r_ocsp_crlid(const X509V3_EXT_METHOD *method, void *in, BIO *bp,
++                          int ind)
++{
++    OCSP_CRLID *a = in;
++    if (a->crlUrl) {
++        if (BIO_printf(bp, "%*scrlUrl: ", ind, "") <= 0)
++            goto err;
++        if (!ASN1_STRING_print(bp, (ASN1_STRING *)a->crlUrl))
++            goto err;
++        if (BIO_write(bp, "\n", 1) <= 0)
++            goto err;
++    }
++    if (a->crlNum) {
++        if (BIO_printf(bp, "%*scrlNum: ", ind, "") <= 0)
++            goto err;
++        if (i2a_ASN1_INTEGER(bp, a->crlNum) <= 0)
++            goto err;
++        if (BIO_write(bp, "\n", 1) <= 0)
++            goto err;
++    }
++    if (a->crlTime) {
++        if (BIO_printf(bp, "%*scrlTime: ", ind, "") <= 0)
++            goto err;
++        if (!ASN1_GENERALIZEDTIME_print(bp, a->crlTime))
++            goto err;
++        if (BIO_write(bp, "\n", 1) <= 0)
++            goto err;
++    }
++    return 1;
++ err:
++    return 0;
++}
++
++static int i2r_ocsp_acutoff(const X509V3_EXT_METHOD *method, void *cutoff,
++                            BIO *bp, int ind)
++{
++    if (BIO_printf(bp, "%*s", ind, "") <= 0)
++        return 0;
++    if (!ASN1_GENERALIZEDTIME_print(bp, cutoff))
++        return 0;
++    return 1;
++}
++
++static int i2r_object(const X509V3_EXT_METHOD *method, void *oid, BIO *bp,
++                      int ind)
++{
++    if (BIO_printf(bp, "%*s", ind, "") <= 0)
++        return 0;
++    if (i2a_ASN1_OBJECT(bp, oid) <= 0)
++        return 0;
++    return 1;
++}
++
++/*
++ * OCSP nonce. This is needs special treatment because it doesn't have an
++ * ASN1 encoding at all: it just contains arbitrary data.
++ */
++
++static void *ocsp_nonce_new(void)
++{
++    return ASN1_OCTET_STRING_new();
++}
++
++static int i2d_ocsp_nonce(void *a, unsigned char **pp)
++{
++    ASN1_OCTET_STRING *os = a;
++    if (pp) {
++        memcpy(*pp, os->data, os->length);
++        *pp += os->length;
++    }
++    return os->length;
++}
++
++static void *d2i_ocsp_nonce(void *a, const unsigned char **pp, long length)
++{
++    ASN1_OCTET_STRING *os, **pos;
++    pos = a;
++    if (pos == NULL || *pos == NULL) {
++        os = ASN1_OCTET_STRING_new();
++        if (os == NULL)
++            goto err;
++    } else {
++        os = *pos;
++    }
++    if (!ASN1_OCTET_STRING_set(os, *pp, length))
++        goto err;
++
++    *pp += length;
++
++    if (pos)
++        *pos = os;
++    return os;
++
++ err:
++    if ((pos == NULL) || (*pos != os))
++        ASN1_OCTET_STRING_free(os);
++    OCSPerr(OCSP_F_D2I_OCSP_NONCE, ERR_R_MALLOC_FAILURE);
++    return NULL;
++}
++
++static void ocsp_nonce_free(void *a)
++{
++    ASN1_OCTET_STRING_free(a);
++}
++
++static int i2r_ocsp_nonce(const X509V3_EXT_METHOD *method, void *nonce,
++                          BIO *out, int indent)
++{
++    if (BIO_printf(out, "%*s", indent, "") <= 0)
++        return 0;
++    if (i2a_ASN1_STRING(out, nonce, V_ASN1_OCTET_STRING) <= 0)
++        return 0;
++    return 1;
++}
++
++/* Nocheck is just a single NULL. Don't print anything and always set it */
++
++static int i2r_ocsp_nocheck(const X509V3_EXT_METHOD *method, void *nocheck,
++                            BIO *out, int indent)
++{
++    return 1;
++}
++
++static void *s2i_ocsp_nocheck(const X509V3_EXT_METHOD *method,
++                              X509V3_CTX *ctx, const char *str)
++{
++    return ASN1_NULL_new();
++}
++
++static int i2r_ocsp_serviceloc(const X509V3_EXT_METHOD *method, void *in,
++                               BIO *bp, int ind)
++{
++    int i;
++    OCSP_SERVICELOC *a = in;
++    ACCESS_DESCRIPTION *ad;
++
++    if (BIO_printf(bp, "%*sIssuer: ", ind, "") <= 0)
++        goto err;
++    if (X509_NAME_print_ex(bp, a->issuer, 0, XN_FLAG_ONELINE) <= 0)
++        goto err;
++    for (i = 0; i < sk_ACCESS_DESCRIPTION_num(a->locator); i++) {
++        ad = sk_ACCESS_DESCRIPTION_value(a->locator, i);
++        if (BIO_printf(bp, "\n%*s", (2 * ind), "") <= 0)
++            goto err;
++        if (i2a_ASN1_OBJECT(bp, ad->method) <= 0)
++            goto err;
++        if (BIO_puts(bp, " - ") <= 0)
++            goto err;
++        if (GENERAL_NAME_print(bp, ad->location) <= 0)
++            goto err;
++    }
++    return 1;
++ err:
++    return 0;
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/pariscid.pl b/CryptoPkg/Library/OpensslLib/openssl/crypto/pariscid.pl
+new file mode 100644
+index 0000000..f82e27a
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/pariscid.pl
+@@ -0,0 +1,263 @@
++#! /usr/bin/env perl
++# Copyright 2009-2016 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
++# in the file LICENSE in the source distribution or at
++# https://www.openssl.org/source/license.html
++
++
++$flavour = shift;
++$output = shift;
++open STDOUT,">$output";
++
++if ($flavour =~ /64/) {
++	$LEVEL		="2.0W";
++	$SIZE_T		=8;
++	$ST		="std";
++} else {
++	$LEVEL		="1.1";
++	$SIZE_T		=4;
++	$ST		="stw";
++}
++
++$rp="%r2";
++$sp="%r30";
++$rv="%r28";
++
++$code=<<___;
++	.LEVEL	$LEVEL
++	.SPACE	\$TEXT\$
++	.SUBSPA	\$CODE\$,QUAD=0,ALIGN=8,ACCESS=0x2C,CODE_ONLY
++
++	.EXPORT	OPENSSL_cpuid_setup,ENTRY
++	.ALIGN	8
++OPENSSL_cpuid_setup
++	.PROC
++	.CALLINFO	NO_CALLS
++	.ENTRY
++	bv	($rp)
++	.EXIT
++	nop
++	.PROCEND
++
++	.EXPORT	OPENSSL_rdtsc,ENTRY
++	.ALIGN	8
++OPENSSL_rdtsc
++	.PROC
++	.CALLINFO	NO_CALLS
++	.ENTRY
++	mfctl	%cr16,$rv
++	bv	($rp)
++	.EXIT
++	nop
++	.PROCEND
++
++	.EXPORT	OPENSSL_wipe_cpu,ENTRY
++	.ALIGN	8
++OPENSSL_wipe_cpu
++	.PROC
++	.CALLINFO	NO_CALLS
++	.ENTRY
++	xor		%r0,%r0,%r1
++	fcpy,dbl	%fr0,%fr4
++	xor		%r0,%r0,%r19
++	fcpy,dbl	%fr0,%fr5
++	xor		%r0,%r0,%r20
++	fcpy,dbl	%fr0,%fr6
++	xor		%r0,%r0,%r21
++	fcpy,dbl	%fr0,%fr7
++	xor		%r0,%r0,%r22
++	fcpy,dbl	%fr0,%fr8
++	xor		%r0,%r0,%r23
++	fcpy,dbl	%fr0,%fr9
++	xor		%r0,%r0,%r24
++	fcpy,dbl	%fr0,%fr10
++	xor		%r0,%r0,%r25
++	fcpy,dbl	%fr0,%fr11
++	xor		%r0,%r0,%r26
++	fcpy,dbl	%fr0,%fr22
++	xor		%r0,%r0,%r29
++	fcpy,dbl	%fr0,%fr23
++	xor		%r0,%r0,%r31
++	fcpy,dbl	%fr0,%fr24
++	fcpy,dbl	%fr0,%fr25
++	fcpy,dbl	%fr0,%fr26
++	fcpy,dbl	%fr0,%fr27
++	fcpy,dbl	%fr0,%fr28
++	fcpy,dbl	%fr0,%fr29
++	fcpy,dbl	%fr0,%fr30
++	fcpy,dbl	%fr0,%fr31
++	bv		($rp)
++	.EXIT
++	ldo		0($sp),$rv
++	.PROCEND
++___
++{
++my $inp="%r26";
++my $len="%r25";
++
++$code.=<<___;
++	.EXPORT	OPENSSL_cleanse,ENTRY,ARGW0=GR,ARGW1=GR
++	.ALIGN	8
++OPENSSL_cleanse
++	.PROC
++	.CALLINFO	NO_CALLS
++	.ENTRY
++	cmpib,*=	0,$len,L\$done
++	nop
++	cmpib,*>>=	15,$len,L\$ittle
++	ldi		$SIZE_T-1,%r1
++
++L\$align
++	and,*<>		$inp,%r1,%r28
++	b,n		L\$aligned
++	stb		%r0,0($inp)
++	ldo		-1($len),$len
++	b		L\$align
++	ldo		1($inp),$inp
++
++L\$aligned
++	andcm		$len,%r1,%r28
++L\$ot
++	$ST		%r0,0($inp)
++	addib,*<>	-$SIZE_T,%r28,L\$ot
++	ldo		$SIZE_T($inp),$inp
++
++	and,*<>		$len,%r1,$len
++	b,n		L\$done
++L\$ittle
++	stb		%r0,0($inp)
++	addib,*<>	-1,$len,L\$ittle
++	ldo		1($inp),$inp
++L\$done
++	bv		($rp)
++	.EXIT
++	nop
++	.PROCEND
++___
++}
++{
++my ($in1,$in2,$len)=("%r26","%r25","%r24");
++
++$code.=<<___;
++	.EXPORT	CRYPTO_memcmp,ENTRY,ARGW0=GR,ARGW1=GR,ARGW1=GR
++	.ALIGN	8
++CRYPTO_memcmp
++	.PROC
++	.CALLINFO	NO_CALLS
++	.ENTRY
++	cmpib,*=	0,$len,L\$no_data
++	xor		$rv,$rv,$rv
++
++L\$oop_cmp
++	ldb		0($in1),%r19
++	ldb		0($in2),%r20
++	ldo		1($in1),$in1
++	ldo		1($in2),$in2
++	xor		%r19,%r20,%r29
++	addib,*<>	-1,$len,L\$oop_cmp
++	or		%r29,$rv,$rv
++
++	sub		%r0,$rv,%r29
++	extru		%r29,31,1,$rv
++L\$no_data
++	bv		($rp)
++	.EXIT
++	nop
++	.PROCEND
++___
++}
++{
++my ($out,$cnt,$max)=("%r26","%r25","%r24");
++my ($tick,$lasttick)=("%r23","%r22");
++my ($diff,$lastdiff)=("%r21","%r20");
++
++$code.=<<___;
++	.EXPORT	OPENSSL_instrument_bus,ENTRY,ARGW0=GR,ARGW1=GR
++	.ALIGN	8
++OPENSSL_instrument_bus
++	.PROC
++	.CALLINFO	NO_CALLS
++	.ENTRY
++	copy		$cnt,$rv
++	mfctl		%cr16,$tick
++	copy		$tick,$lasttick
++	ldi		0,$diff
++
++	fdc		0($out)
++	ldw		0($out),$tick
++	add		$diff,$tick,$tick
++	stw		$tick,0($out)
++L\$oop
++	mfctl		%cr16,$tick
++	sub		$tick,$lasttick,$diff
++	copy		$tick,$lasttick
++
++	fdc		0($out)
++	ldw		0($out),$tick
++	add		$diff,$tick,$tick
++	stw		$tick,0($out)
++
++	addib,<>	-1,$cnt,L\$oop
++	addi		4,$out,$out
++
++	bv		($rp)
++	.EXIT
++	sub		$rv,$cnt,$rv
++	.PROCEND
++
++	.EXPORT	OPENSSL_instrument_bus2,ENTRY,ARGW0=GR,ARGW1=GR
++	.ALIGN	8
++OPENSSL_instrument_bus2
++	.PROC
++	.CALLINFO	NO_CALLS
++	.ENTRY
++	copy		$cnt,$rv
++	sub		%r0,$cnt,$cnt
++
++	mfctl		%cr16,$tick
++	copy		$tick,$lasttick
++	ldi		0,$diff
++
++	fdc		0($out)
++	ldw		0($out),$tick
++	add		$diff,$tick,$tick
++	stw		$tick,0($out)
++
++	mfctl		%cr16,$tick
++	sub		$tick,$lasttick,$diff
++	copy		$tick,$lasttick
++L\$oop2
++	copy		$diff,$lastdiff
++	fdc		0($out)
++	ldw		0($out),$tick
++	add		$diff,$tick,$tick
++	stw		$tick,0($out)
++
++	addib,=		-1,$max,L\$done2
++	nop
++
++	mfctl		%cr16,$tick
++	sub		$tick,$lasttick,$diff
++	copy		$tick,$lasttick
++	cmpclr,<>	$lastdiff,$diff,$tick
++	ldi		1,$tick
++
++	ldi		1,%r1
++	xor		%r1,$tick,$tick
++	addb,<>		$tick,$cnt,L\$oop2
++	shladd,l	$tick,2,$out,$out
++L\$done2
++	bv		($rp)
++	.EXIT
++	add		$rv,$cnt,$rv
++	.PROCEND
++___
++}
++$code =~ s/cmpib,\*/comib,/gm	if ($SIZE_T==4);
++$code =~ s/,\*/,/gm		if ($SIZE_T==4);
++$code =~ s/\bbv\b/bve/gm	if ($SIZE_T==8);
++print $code;
++close STDOUT;
++
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/pem/build.info b/CryptoPkg/Library/OpensslLib/openssl/crypto/pem/build.info
+new file mode 100644
+index 0000000..357b328
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/pem/build.info
+@@ -0,0 +1,4 @@
++LIBS=../../libcrypto
++SOURCE[../../libcrypto]=\
++        pem_sign.c pem_info.c pem_lib.c pem_all.c pem_err.c \
++        pem_x509.c pem_xaux.c pem_oth.c pem_pk8.c pem_pkey.c pvkfmt.c
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/pem/pem_all.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/pem/pem_all.c
+new file mode 100644
+index 0000000..0e71813
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/pem/pem_all.c
+@@ -0,0 +1,181 @@
++/*
++ * Copyright 1995-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include "internal/cryptlib.h"
++#include 
++#include 
++#include 
++#include 
++#include 
++#include 
++#include 
++#include 
++
++#ifndef OPENSSL_NO_RSA
++static RSA *pkey_get_rsa(EVP_PKEY *key, RSA **rsa);
++#endif
++#ifndef OPENSSL_NO_DSA
++static DSA *pkey_get_dsa(EVP_PKEY *key, DSA **dsa);
++#endif
++
++#ifndef OPENSSL_NO_EC
++static EC_KEY *pkey_get_eckey(EVP_PKEY *key, EC_KEY **eckey);
++#endif
++
++IMPLEMENT_PEM_rw(X509_REQ, X509_REQ, PEM_STRING_X509_REQ, X509_REQ)
++
++IMPLEMENT_PEM_write(X509_REQ_NEW, X509_REQ, PEM_STRING_X509_REQ_OLD, X509_REQ)
++IMPLEMENT_PEM_rw(X509_CRL, X509_CRL, PEM_STRING_X509_CRL, X509_CRL)
++IMPLEMENT_PEM_rw(PKCS7, PKCS7, PEM_STRING_PKCS7, PKCS7)
++
++IMPLEMENT_PEM_rw(NETSCAPE_CERT_SEQUENCE, NETSCAPE_CERT_SEQUENCE,
++                 PEM_STRING_X509, NETSCAPE_CERT_SEQUENCE)
++#ifndef OPENSSL_NO_RSA
++/*
++ * We treat RSA or DSA private keys as a special case. For private keys we
++ * read in an EVP_PKEY structure with PEM_read_bio_PrivateKey() and extract
++ * the relevant private key: this means can handle "traditional" and PKCS#8
++ * formats transparently.
++ */
++static RSA *pkey_get_rsa(EVP_PKEY *key, RSA **rsa)
++{
++    RSA *rtmp;
++    if (!key)
++        return NULL;
++    rtmp = EVP_PKEY_get1_RSA(key);
++    EVP_PKEY_free(key);
++    if (!rtmp)
++        return NULL;
++    if (rsa) {
++        RSA_free(*rsa);
++        *rsa = rtmp;
++    }
++    return rtmp;
++}
++
++RSA *PEM_read_bio_RSAPrivateKey(BIO *bp, RSA **rsa, pem_password_cb *cb,
++                                void *u)
++{
++    EVP_PKEY *pktmp;
++    pktmp = PEM_read_bio_PrivateKey(bp, NULL, cb, u);
++    return pkey_get_rsa(pktmp, rsa);
++}
++
++# ifndef OPENSSL_NO_STDIO
++
++RSA *PEM_read_RSAPrivateKey(FILE *fp, RSA **rsa, pem_password_cb *cb, void *u)
++{
++    EVP_PKEY *pktmp;
++    pktmp = PEM_read_PrivateKey(fp, NULL, cb, u);
++    return pkey_get_rsa(pktmp, rsa);
++}
++
++# endif
++
++IMPLEMENT_PEM_write_cb_const(RSAPrivateKey, RSA, PEM_STRING_RSA,
++                             RSAPrivateKey)
++
++
++IMPLEMENT_PEM_rw_const(RSAPublicKey, RSA, PEM_STRING_RSA_PUBLIC,
++                       RSAPublicKey) IMPLEMENT_PEM_rw(RSA_PUBKEY, RSA,
++                                                      PEM_STRING_PUBLIC,
++                                                      RSA_PUBKEY)
++#endif
++#ifndef OPENSSL_NO_DSA
++static DSA *pkey_get_dsa(EVP_PKEY *key, DSA **dsa)
++{
++    DSA *dtmp;
++    if (!key)
++        return NULL;
++    dtmp = EVP_PKEY_get1_DSA(key);
++    EVP_PKEY_free(key);
++    if (!dtmp)
++        return NULL;
++    if (dsa) {
++        DSA_free(*dsa);
++        *dsa = dtmp;
++    }
++    return dtmp;
++}
++
++DSA *PEM_read_bio_DSAPrivateKey(BIO *bp, DSA **dsa, pem_password_cb *cb,
++                                void *u)
++{
++    EVP_PKEY *pktmp;
++    pktmp = PEM_read_bio_PrivateKey(bp, NULL, cb, u);
++    return pkey_get_dsa(pktmp, dsa); /* will free pktmp */
++}
++
++IMPLEMENT_PEM_write_cb_const(DSAPrivateKey, DSA, PEM_STRING_DSA,
++                             DSAPrivateKey)
++    IMPLEMENT_PEM_rw(DSA_PUBKEY, DSA, PEM_STRING_PUBLIC, DSA_PUBKEY)
++# ifndef OPENSSL_NO_STDIO
++DSA *PEM_read_DSAPrivateKey(FILE *fp, DSA **dsa, pem_password_cb *cb, void *u)
++{
++    EVP_PKEY *pktmp;
++    pktmp = PEM_read_PrivateKey(fp, NULL, cb, u);
++    return pkey_get_dsa(pktmp, dsa); /* will free pktmp */
++}
++
++# endif
++
++IMPLEMENT_PEM_rw_const(DSAparams, DSA, PEM_STRING_DSAPARAMS, DSAparams)
++#endif
++#ifndef OPENSSL_NO_EC
++static EC_KEY *pkey_get_eckey(EVP_PKEY *key, EC_KEY **eckey)
++{
++    EC_KEY *dtmp;
++    if (!key)
++        return NULL;
++    dtmp = EVP_PKEY_get1_EC_KEY(key);
++    EVP_PKEY_free(key);
++    if (!dtmp)
++        return NULL;
++    if (eckey) {
++        EC_KEY_free(*eckey);
++        *eckey = dtmp;
++    }
++    return dtmp;
++}
++
++EC_KEY *PEM_read_bio_ECPrivateKey(BIO *bp, EC_KEY **key, pem_password_cb *cb,
++                                  void *u)
++{
++    EVP_PKEY *pktmp;
++    pktmp = PEM_read_bio_PrivateKey(bp, NULL, cb, u);
++    return pkey_get_eckey(pktmp, key); /* will free pktmp */
++}
++
++IMPLEMENT_PEM_rw_const(ECPKParameters, EC_GROUP, PEM_STRING_ECPARAMETERS,
++                       ECPKParameters)
++
++
++IMPLEMENT_PEM_write_cb(ECPrivateKey, EC_KEY, PEM_STRING_ECPRIVATEKEY,
++                       ECPrivateKey)
++IMPLEMENT_PEM_rw(EC_PUBKEY, EC_KEY, PEM_STRING_PUBLIC, EC_PUBKEY)
++# ifndef OPENSSL_NO_STDIO
++EC_KEY *PEM_read_ECPrivateKey(FILE *fp, EC_KEY **eckey, pem_password_cb *cb,
++                              void *u)
++{
++    EVP_PKEY *pktmp;
++    pktmp = PEM_read_PrivateKey(fp, NULL, cb, u);
++    return pkey_get_eckey(pktmp, eckey); /* will free pktmp */
++}
++
++# endif
++
++#endif
++
++#ifndef OPENSSL_NO_DH
++
++IMPLEMENT_PEM_write_const(DHparams, DH, PEM_STRING_DHPARAMS, DHparams)
++    IMPLEMENT_PEM_write_const(DHxparams, DH, PEM_STRING_DHXPARAMS, DHxparams)
++#endif
++IMPLEMENT_PEM_rw(PUBKEY, EVP_PKEY, PEM_STRING_PUBLIC, PUBKEY)
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/pem/pem_err.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/pem/pem_err.c
+new file mode 100644
+index 0000000..f36d893
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/pem/pem_err.c
+@@ -0,0 +1,115 @@
++/*
++ * Generated by util/mkerr.pl DO NOT EDIT
++ * Copyright 1995-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include 
++#include 
++
++/* BEGIN ERROR CODES */
++#ifndef OPENSSL_NO_ERR
++
++# define ERR_FUNC(func) ERR_PACK(ERR_LIB_PEM,func,0)
++# define ERR_REASON(reason) ERR_PACK(ERR_LIB_PEM,0,reason)
++
++static ERR_STRING_DATA PEM_str_functs[] = {
++    {ERR_FUNC(PEM_F_B2I_DSS), "b2i_dss"},
++    {ERR_FUNC(PEM_F_B2I_PVK_BIO), "b2i_PVK_bio"},
++    {ERR_FUNC(PEM_F_B2I_RSA), "b2i_rsa"},
++    {ERR_FUNC(PEM_F_CHECK_BITLEN_DSA), "check_bitlen_dsa"},
++    {ERR_FUNC(PEM_F_CHECK_BITLEN_RSA), "check_bitlen_rsa"},
++    {ERR_FUNC(PEM_F_D2I_PKCS8PRIVATEKEY_BIO), "d2i_PKCS8PrivateKey_bio"},
++    {ERR_FUNC(PEM_F_D2I_PKCS8PRIVATEKEY_FP), "d2i_PKCS8PrivateKey_fp"},
++    {ERR_FUNC(PEM_F_DO_B2I), "do_b2i"},
++    {ERR_FUNC(PEM_F_DO_B2I_BIO), "do_b2i_bio"},
++    {ERR_FUNC(PEM_F_DO_BLOB_HEADER), "do_blob_header"},
++    {ERR_FUNC(PEM_F_DO_PK8PKEY), "do_pk8pkey"},
++    {ERR_FUNC(PEM_F_DO_PK8PKEY_FP), "do_pk8pkey_fp"},
++    {ERR_FUNC(PEM_F_DO_PVK_BODY), "do_PVK_body"},
++    {ERR_FUNC(PEM_F_DO_PVK_HEADER), "do_PVK_header"},
++    {ERR_FUNC(PEM_F_I2B_PVK), "i2b_PVK"},
++    {ERR_FUNC(PEM_F_I2B_PVK_BIO), "i2b_PVK_bio"},
++    {ERR_FUNC(PEM_F_LOAD_IV), "load_iv"},
++    {ERR_FUNC(PEM_F_PEM_ASN1_READ), "PEM_ASN1_read"},
++    {ERR_FUNC(PEM_F_PEM_ASN1_READ_BIO), "PEM_ASN1_read_bio"},
++    {ERR_FUNC(PEM_F_PEM_ASN1_WRITE), "PEM_ASN1_write"},
++    {ERR_FUNC(PEM_F_PEM_ASN1_WRITE_BIO), "PEM_ASN1_write_bio"},
++    {ERR_FUNC(PEM_F_PEM_DEF_CALLBACK), "PEM_def_callback"},
++    {ERR_FUNC(PEM_F_PEM_DO_HEADER), "PEM_do_header"},
++    {ERR_FUNC(PEM_F_PEM_GET_EVP_CIPHER_INFO), "PEM_get_EVP_CIPHER_INFO"},
++    {ERR_FUNC(PEM_F_PEM_READ), "PEM_read"},
++    {ERR_FUNC(PEM_F_PEM_READ_BIO), "PEM_read_bio"},
++    {ERR_FUNC(PEM_F_PEM_READ_BIO_DHPARAMS), "PEM_read_bio_DHparams"},
++    {ERR_FUNC(PEM_F_PEM_READ_BIO_PARAMETERS), "PEM_read_bio_Parameters"},
++    {ERR_FUNC(PEM_F_PEM_READ_BIO_PRIVATEKEY), "PEM_read_bio_PrivateKey"},
++    {ERR_FUNC(PEM_F_PEM_READ_DHPARAMS), "PEM_read_DHparams"},
++    {ERR_FUNC(PEM_F_PEM_READ_PRIVATEKEY), "PEM_read_PrivateKey"},
++    {ERR_FUNC(PEM_F_PEM_SIGNFINAL), "PEM_SignFinal"},
++    {ERR_FUNC(PEM_F_PEM_WRITE), "PEM_write"},
++    {ERR_FUNC(PEM_F_PEM_WRITE_BIO), "PEM_write_bio"},
++    {ERR_FUNC(PEM_F_PEM_WRITE_PRIVATEKEY), "PEM_write_PrivateKey"},
++    {ERR_FUNC(PEM_F_PEM_X509_INFO_READ), "PEM_X509_INFO_read"},
++    {ERR_FUNC(PEM_F_PEM_X509_INFO_READ_BIO), "PEM_X509_INFO_read_bio"},
++    {ERR_FUNC(PEM_F_PEM_X509_INFO_WRITE_BIO), "PEM_X509_INFO_write_bio"},
++    {0, NULL}
++};
++
++static ERR_STRING_DATA PEM_str_reasons[] = {
++    {ERR_REASON(PEM_R_BAD_BASE64_DECODE), "bad base64 decode"},
++    {ERR_REASON(PEM_R_BAD_DECRYPT), "bad decrypt"},
++    {ERR_REASON(PEM_R_BAD_END_LINE), "bad end line"},
++    {ERR_REASON(PEM_R_BAD_IV_CHARS), "bad iv chars"},
++    {ERR_REASON(PEM_R_BAD_MAGIC_NUMBER), "bad magic number"},
++    {ERR_REASON(PEM_R_BAD_PASSWORD_READ), "bad password read"},
++    {ERR_REASON(PEM_R_BAD_VERSION_NUMBER), "bad version number"},
++    {ERR_REASON(PEM_R_BIO_WRITE_FAILURE), "bio write failure"},
++    {ERR_REASON(PEM_R_CIPHER_IS_NULL), "cipher is null"},
++    {ERR_REASON(PEM_R_ERROR_CONVERTING_PRIVATE_KEY),
++     "error converting private key"},
++    {ERR_REASON(PEM_R_EXPECTING_PRIVATE_KEY_BLOB),
++     "expecting private key blob"},
++    {ERR_REASON(PEM_R_EXPECTING_PUBLIC_KEY_BLOB),
++     "expecting public key blob"},
++    {ERR_REASON(PEM_R_HEADER_TOO_LONG), "header too long"},
++    {ERR_REASON(PEM_R_INCONSISTENT_HEADER), "inconsistent header"},
++    {ERR_REASON(PEM_R_KEYBLOB_HEADER_PARSE_ERROR),
++     "keyblob header parse error"},
++    {ERR_REASON(PEM_R_KEYBLOB_TOO_SHORT), "keyblob too short"},
++    {ERR_REASON(PEM_R_MISSING_DEK_IV), "missing dek iv"},
++    {ERR_REASON(PEM_R_NOT_DEK_INFO), "not dek info"},
++    {ERR_REASON(PEM_R_NOT_ENCRYPTED), "not encrypted"},
++    {ERR_REASON(PEM_R_NOT_PROC_TYPE), "not proc type"},
++    {ERR_REASON(PEM_R_NO_START_LINE), "no start line"},
++    {ERR_REASON(PEM_R_PROBLEMS_GETTING_PASSWORD),
++     "problems getting password"},
++    {ERR_REASON(PEM_R_PVK_DATA_TOO_SHORT), "pvk data too short"},
++    {ERR_REASON(PEM_R_PVK_TOO_SHORT), "pvk too short"},
++    {ERR_REASON(PEM_R_READ_KEY), "read key"},
++    {ERR_REASON(PEM_R_SHORT_HEADER), "short header"},
++    {ERR_REASON(PEM_R_UNEXPECTED_DEK_IV), "unexpected dek iv"},
++    {ERR_REASON(PEM_R_UNSUPPORTED_CIPHER), "unsupported cipher"},
++    {ERR_REASON(PEM_R_UNSUPPORTED_ENCRYPTION), "unsupported encryption"},
++    {ERR_REASON(PEM_R_UNSUPPORTED_KEY_COMPONENTS),
++     "unsupported key components"},
++    {0, NULL}
++};
++
++#endif
++
++int ERR_load_PEM_strings(void)
++{
++#ifndef OPENSSL_NO_ERR
++
++    if (ERR_func_error_string(PEM_str_functs[0].error) == NULL) {
++        ERR_load_strings(0, PEM_str_functs);
++        ERR_load_strings(0, PEM_str_reasons);
++    }
++#endif
++    return 1;
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/pem/pem_info.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/pem/pem_info.c
+new file mode 100644
+index 0000000..dd493c8
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/pem/pem_info.c
+@@ -0,0 +1,334 @@
++/*
++ * Copyright 1995-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include "internal/cryptlib.h"
++#include 
++#include 
++#include 
++#include 
++#include 
++#include 
++#include 
++
++#ifndef OPENSSL_NO_STDIO
++STACK_OF(X509_INFO) *PEM_X509_INFO_read(FILE *fp, STACK_OF(X509_INFO) *sk,
++                                        pem_password_cb *cb, void *u)
++{
++    BIO *b;
++    STACK_OF(X509_INFO) *ret;
++
++    if ((b = BIO_new(BIO_s_file())) == NULL) {
++        PEMerr(PEM_F_PEM_X509_INFO_READ, ERR_R_BUF_LIB);
++        return (0);
++    }
++    BIO_set_fp(b, fp, BIO_NOCLOSE);
++    ret = PEM_X509_INFO_read_bio(b, sk, cb, u);
++    BIO_free(b);
++    return (ret);
++}
++#endif
++
++STACK_OF(X509_INFO) *PEM_X509_INFO_read_bio(BIO *bp, STACK_OF(X509_INFO) *sk,
++                                            pem_password_cb *cb, void *u)
++{
++    X509_INFO *xi = NULL;
++    char *name = NULL, *header = NULL;
++    void *pp;
++    unsigned char *data = NULL;
++    const unsigned char *p;
++    long len, error = 0;
++    int ok = 0;
++    STACK_OF(X509_INFO) *ret = NULL;
++    unsigned int i, raw, ptype;
++    d2i_of_void *d2i = 0;
++
++    if (sk == NULL) {
++        if ((ret = sk_X509_INFO_new_null()) == NULL) {
++            PEMerr(PEM_F_PEM_X509_INFO_READ_BIO, ERR_R_MALLOC_FAILURE);
++            goto err;
++        }
++    } else
++        ret = sk;
++
++    if ((xi = X509_INFO_new()) == NULL)
++        goto err;
++    for (;;) {
++        raw = 0;
++        ptype = 0;
++        i = PEM_read_bio(bp, &name, &header, &data, &len);
++        if (i == 0) {
++            error = ERR_GET_REASON(ERR_peek_last_error());
++            if (error == PEM_R_NO_START_LINE) {
++                ERR_clear_error();
++                break;
++            }
++            goto err;
++        }
++ start:
++        if ((strcmp(name, PEM_STRING_X509) == 0) ||
++            (strcmp(name, PEM_STRING_X509_OLD) == 0)) {
++            d2i = (D2I_OF(void)) d2i_X509;
++            if (xi->x509 != NULL) {
++                if (!sk_X509_INFO_push(ret, xi))
++                    goto err;
++                if ((xi = X509_INFO_new()) == NULL)
++                    goto err;
++                goto start;
++            }
++            pp = &(xi->x509);
++        } else if ((strcmp(name, PEM_STRING_X509_TRUSTED) == 0)) {
++            d2i = (D2I_OF(void)) d2i_X509_AUX;
++            if (xi->x509 != NULL) {
++                if (!sk_X509_INFO_push(ret, xi))
++                    goto err;
++                if ((xi = X509_INFO_new()) == NULL)
++                    goto err;
++                goto start;
++            }
++            pp = &(xi->x509);
++        } else if (strcmp(name, PEM_STRING_X509_CRL) == 0) {
++            d2i = (D2I_OF(void)) d2i_X509_CRL;
++            if (xi->crl != NULL) {
++                if (!sk_X509_INFO_push(ret, xi))
++                    goto err;
++                if ((xi = X509_INFO_new()) == NULL)
++                    goto err;
++                goto start;
++            }
++            pp = &(xi->crl);
++        } else
++#ifndef OPENSSL_NO_RSA
++        if (strcmp(name, PEM_STRING_RSA) == 0) {
++            d2i = (D2I_OF(void)) d2i_RSAPrivateKey;
++            if (xi->x_pkey != NULL) {
++                if (!sk_X509_INFO_push(ret, xi))
++                    goto err;
++                if ((xi = X509_INFO_new()) == NULL)
++                    goto err;
++                goto start;
++            }
++
++            xi->enc_data = NULL;
++            xi->enc_len = 0;
++
++            xi->x_pkey = X509_PKEY_new();
++            if (xi->x_pkey == NULL)
++                goto err;
++            ptype = EVP_PKEY_RSA;
++            pp = &xi->x_pkey->dec_pkey;
++            if ((int)strlen(header) > 10) /* assume encrypted */
++                raw = 1;
++        } else
++#endif
++#ifndef OPENSSL_NO_DSA
++        if (strcmp(name, PEM_STRING_DSA) == 0) {
++            d2i = (D2I_OF(void)) d2i_DSAPrivateKey;
++            if (xi->x_pkey != NULL) {
++                if (!sk_X509_INFO_push(ret, xi))
++                    goto err;
++                if ((xi = X509_INFO_new()) == NULL)
++                    goto err;
++                goto start;
++            }
++
++            xi->enc_data = NULL;
++            xi->enc_len = 0;
++
++            xi->x_pkey = X509_PKEY_new();
++            if (xi->x_pkey == NULL)
++                goto err;
++            ptype = EVP_PKEY_DSA;
++            pp = &xi->x_pkey->dec_pkey;
++            if ((int)strlen(header) > 10) /* assume encrypted */
++                raw = 1;
++        } else
++#endif
++#ifndef OPENSSL_NO_EC
++        if (strcmp(name, PEM_STRING_ECPRIVATEKEY) == 0) {
++            d2i = (D2I_OF(void)) d2i_ECPrivateKey;
++            if (xi->x_pkey != NULL) {
++                if (!sk_X509_INFO_push(ret, xi))
++                    goto err;
++                if ((xi = X509_INFO_new()) == NULL)
++                    goto err;
++                goto start;
++            }
++
++            xi->enc_data = NULL;
++            xi->enc_len = 0;
++
++            xi->x_pkey = X509_PKEY_new();
++            if (xi->x_pkey == NULL)
++                goto err;
++            ptype = EVP_PKEY_EC;
++            pp = &xi->x_pkey->dec_pkey;
++            if ((int)strlen(header) > 10) /* assume encrypted */
++                raw = 1;
++        } else
++#endif
++        {
++            d2i = NULL;
++            pp = NULL;
++        }
++
++        if (d2i != NULL) {
++            if (!raw) {
++                EVP_CIPHER_INFO cipher;
++
++                if (!PEM_get_EVP_CIPHER_INFO(header, &cipher))
++                    goto err;
++                if (!PEM_do_header(&cipher, data, &len, cb, u))
++                    goto err;
++                p = data;
++                if (ptype) {
++                    if (!d2i_PrivateKey(ptype, pp, &p, len)) {
++                        PEMerr(PEM_F_PEM_X509_INFO_READ_BIO, ERR_R_ASN1_LIB);
++                        goto err;
++                    }
++                } else if (d2i(pp, &p, len) == NULL) {
++                    PEMerr(PEM_F_PEM_X509_INFO_READ_BIO, ERR_R_ASN1_LIB);
++                    goto err;
++                }
++            } else {            /* encrypted RSA data */
++                if (!PEM_get_EVP_CIPHER_INFO(header, &xi->enc_cipher))
++                    goto err;
++                xi->enc_data = (char *)data;
++                xi->enc_len = (int)len;
++                data = NULL;
++            }
++        } else {
++            /* unknown */
++        }
++        OPENSSL_free(name);
++        name = NULL;
++        OPENSSL_free(header);
++        header = NULL;
++        OPENSSL_free(data);
++        data = NULL;
++    }
++
++    /*
++     * if the last one hasn't been pushed yet and there is anything in it
++     * then add it to the stack ...
++     */
++    if ((xi->x509 != NULL) || (xi->crl != NULL) ||
++        (xi->x_pkey != NULL) || (xi->enc_data != NULL)) {
++        if (!sk_X509_INFO_push(ret, xi))
++            goto err;
++        xi = NULL;
++    }
++    ok = 1;
++ err:
++    X509_INFO_free(xi);
++    if (!ok) {
++        for (i = 0; ((int)i) < sk_X509_INFO_num(ret); i++) {
++            xi = sk_X509_INFO_value(ret, i);
++            X509_INFO_free(xi);
++        }
++        if (ret != sk)
++            sk_X509_INFO_free(ret);
++        ret = NULL;
++    }
++
++    OPENSSL_free(name);
++    OPENSSL_free(header);
++    OPENSSL_free(data);
++    return (ret);
++}
++
++/* A TJH addition */
++int PEM_X509_INFO_write_bio(BIO *bp, X509_INFO *xi, EVP_CIPHER *enc,
++                            unsigned char *kstr, int klen,
++                            pem_password_cb *cb, void *u)
++{
++    int i, ret = 0;
++    unsigned char *data = NULL;
++    const char *objstr = NULL;
++    char buf[PEM_BUFSIZE];
++    unsigned char *iv = NULL;
++
++    if (enc != NULL) {
++        objstr = OBJ_nid2sn(EVP_CIPHER_nid(enc));
++        if (objstr == NULL) {
++            PEMerr(PEM_F_PEM_X509_INFO_WRITE_BIO, PEM_R_UNSUPPORTED_CIPHER);
++            goto err;
++        }
++    }
++
++    /*
++     * now for the fun part ... if we have a private key then we have to be
++     * able to handle a not-yet-decrypted key being written out correctly ...
++     * if it is decrypted or it is non-encrypted then we use the base code
++     */
++    if (xi->x_pkey != NULL) {
++        if ((xi->enc_data != NULL) && (xi->enc_len > 0)) {
++            if (enc == NULL) {
++                PEMerr(PEM_F_PEM_X509_INFO_WRITE_BIO, PEM_R_CIPHER_IS_NULL);
++                goto err;
++            }
++
++            /* copy from weirdo names into more normal things */
++            iv = xi->enc_cipher.iv;
++            data = (unsigned char *)xi->enc_data;
++            i = xi->enc_len;
++
++            /*
++             * we take the encryption data from the internal stuff rather
++             * than what the user has passed us ... as we have to match
++             * exactly for some strange reason
++             */
++            objstr = OBJ_nid2sn(EVP_CIPHER_nid(xi->enc_cipher.cipher));
++            if (objstr == NULL) {
++                PEMerr(PEM_F_PEM_X509_INFO_WRITE_BIO,
++                       PEM_R_UNSUPPORTED_CIPHER);
++                goto err;
++            }
++
++            /* create the right magic header stuff */
++            OPENSSL_assert(strlen(objstr) + 23
++                           + 2 * EVP_CIPHER_iv_length(enc) + 13 <=
++                           sizeof buf);
++            buf[0] = '\0';
++            PEM_proc_type(buf, PEM_TYPE_ENCRYPTED);
++            PEM_dek_info(buf, objstr, EVP_CIPHER_iv_length(enc),
++                         (char *)iv);
++
++            /* use the normal code to write things out */
++            i = PEM_write_bio(bp, PEM_STRING_RSA, buf, data, i);
++            if (i <= 0)
++                goto err;
++        } else {
++            /* Add DSA/DH */
++#ifndef OPENSSL_NO_RSA
++            /* normal optionally encrypted stuff */
++            if (PEM_write_bio_RSAPrivateKey(bp,
++                                            EVP_PKEY_get0_RSA(xi->x_pkey->dec_pkey),
++                                            enc, kstr, klen, cb, u) <= 0)
++                goto err;
++#endif
++        }
++    }
++
++    /* if we have a certificate then write it out now */
++    if ((xi->x509 != NULL) && (PEM_write_bio_X509(bp, xi->x509) <= 0))
++        goto err;
++
++    /*
++     * we are ignoring anything else that is loaded into the X509_INFO
++     * structure for the moment ... as I don't need it so I'm not coding it
++     * here and Eric can do it when this makes it into the base library --tjh
++     */
++
++    ret = 1;
++
++ err:
++    OPENSSL_cleanse(buf, PEM_BUFSIZE);
++    return (ret);
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/pem/pem_lib.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/pem/pem_lib.c
+new file mode 100644
+index 0000000..2792593
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/pem/pem_lib.c
+@@ -0,0 +1,857 @@
++/*
++ * Copyright 1995-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include 
++#include 
++#include "internal/cryptlib.h"
++#include 
++#include 
++#include 
++#include 
++#include 
++#include 
++#include 
++#include "internal/asn1_int.h"
++#include 
++#include 
++
++#define MIN_LENGTH      4
++
++static int load_iv(char **fromp, unsigned char *to, int num);
++static int check_pem(const char *nm, const char *name);
++int pem_check_suffix(const char *pem_str, const char *suffix);
++
++int PEM_def_callback(char *buf, int num, int w, void *key)
++{
++#if defined(OPENSSL_NO_STDIO) || defined(OPENSSL_NO_UI)
++    int i;
++#else
++    int i, j;
++    const char *prompt;
++#endif
++
++    if (key) {
++        i = strlen(key);
++        i = (i > num) ? num : i;
++        memcpy(buf, key, i);
++        return i;
++    }
++
++#if defined(OPENSSL_NO_STDIO) || defined(OPENSSL_NO_UI)
++    PEMerr(PEM_F_PEM_DEF_CALLBACK, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
++    return -1;
++#else
++    prompt = EVP_get_pw_prompt();
++    if (prompt == NULL)
++        prompt = "Enter PEM pass phrase:";
++
++    for (;;) {
++        /*
++         * We assume that w == 0 means decryption,
++         * while w == 1 means encryption
++         */
++        int min_len = w ? MIN_LENGTH : 0;
++
++        i = EVP_read_pw_string_min(buf, min_len, num, prompt, w);
++        if (i != 0) {
++            PEMerr(PEM_F_PEM_DEF_CALLBACK, PEM_R_PROBLEMS_GETTING_PASSWORD);
++            memset(buf, 0, (unsigned int)num);
++            return -1;
++        }
++        j = strlen(buf);
++        if (min_len && j < min_len) {
++            fprintf(stderr,
++                    "phrase is too short, needs to be at least %d chars\n",
++                    min_len);
++        } else
++            break;
++    }
++    return j;
++#endif
++}
++
++void PEM_proc_type(char *buf, int type)
++{
++    const char *str;
++
++    if (type == PEM_TYPE_ENCRYPTED)
++        str = "ENCRYPTED";
++    else if (type == PEM_TYPE_MIC_CLEAR)
++        str = "MIC-CLEAR";
++    else if (type == PEM_TYPE_MIC_ONLY)
++        str = "MIC-ONLY";
++    else
++        str = "BAD-TYPE";
++
++    OPENSSL_strlcat(buf, "Proc-Type: 4,", PEM_BUFSIZE);
++    OPENSSL_strlcat(buf, str, PEM_BUFSIZE);
++    OPENSSL_strlcat(buf, "\n", PEM_BUFSIZE);
++}
++
++void PEM_dek_info(char *buf, const char *type, int len, char *str)
++{
++    static const unsigned char map[17] = "0123456789ABCDEF";
++    long i;
++    int j;
++
++    OPENSSL_strlcat(buf, "DEK-Info: ", PEM_BUFSIZE);
++    OPENSSL_strlcat(buf, type, PEM_BUFSIZE);
++    OPENSSL_strlcat(buf, ",", PEM_BUFSIZE);
++    j = strlen(buf);
++    if (j + (len * 2) + 1 > PEM_BUFSIZE)
++        return;
++    for (i = 0; i < len; i++) {
++        buf[j + i * 2] = map[(str[i] >> 4) & 0x0f];
++        buf[j + i * 2 + 1] = map[(str[i]) & 0x0f];
++    }
++    buf[j + i * 2] = '\n';
++    buf[j + i * 2 + 1] = '\0';
++}
++
++#ifndef OPENSSL_NO_STDIO
++void *PEM_ASN1_read(d2i_of_void *d2i, const char *name, FILE *fp, void **x,
++                    pem_password_cb *cb, void *u)
++{
++    BIO *b;
++    void *ret;
++
++    if ((b = BIO_new(BIO_s_file())) == NULL) {
++        PEMerr(PEM_F_PEM_ASN1_READ, ERR_R_BUF_LIB);
++        return (0);
++    }
++    BIO_set_fp(b, fp, BIO_NOCLOSE);
++    ret = PEM_ASN1_read_bio(d2i, name, b, x, cb, u);
++    BIO_free(b);
++    return (ret);
++}
++#endif
++
++static int check_pem(const char *nm, const char *name)
++{
++    /* Normal matching nm and name */
++    if (strcmp(nm, name) == 0)
++        return 1;
++
++    /* Make PEM_STRING_EVP_PKEY match any private key */
++
++    if (strcmp(name, PEM_STRING_EVP_PKEY) == 0) {
++        int slen;
++        const EVP_PKEY_ASN1_METHOD *ameth;
++        if (strcmp(nm, PEM_STRING_PKCS8) == 0)
++            return 1;
++        if (strcmp(nm, PEM_STRING_PKCS8INF) == 0)
++            return 1;
++        slen = pem_check_suffix(nm, "PRIVATE KEY");
++        if (slen > 0) {
++            /*
++             * NB: ENGINE implementations won't contain a deprecated old
++             * private key decode function so don't look for them.
++             */
++            ameth = EVP_PKEY_asn1_find_str(NULL, nm, slen);
++            if (ameth && ameth->old_priv_decode)
++                return 1;
++        }
++        return 0;
++    }
++
++    if (strcmp(name, PEM_STRING_PARAMETERS) == 0) {
++        int slen;
++        const EVP_PKEY_ASN1_METHOD *ameth;
++        slen = pem_check_suffix(nm, "PARAMETERS");
++        if (slen > 0) {
++            ENGINE *e;
++            ameth = EVP_PKEY_asn1_find_str(&e, nm, slen);
++            if (ameth) {
++                int r;
++                if (ameth->param_decode)
++                    r = 1;
++                else
++                    r = 0;
++#ifndef OPENSSL_NO_ENGINE
++                ENGINE_finish(e);
++#endif
++                return r;
++            }
++        }
++        return 0;
++    }
++    /* If reading DH parameters handle X9.42 DH format too */
++    if (strcmp(nm, PEM_STRING_DHXPARAMS) == 0
++        && strcmp(name, PEM_STRING_DHPARAMS) == 0)
++        return 1;
++
++    /* Permit older strings */
++
++    if (strcmp(nm, PEM_STRING_X509_OLD) == 0
++        && strcmp(name, PEM_STRING_X509) == 0)
++        return 1;
++
++    if (strcmp(nm, PEM_STRING_X509_REQ_OLD) == 0
++        && strcmp(name, PEM_STRING_X509_REQ) == 0)
++        return 1;
++
++    /* Allow normal certs to be read as trusted certs */
++    if (strcmp(nm, PEM_STRING_X509) == 0
++        && strcmp(name, PEM_STRING_X509_TRUSTED) == 0)
++        return 1;
++
++    if (strcmp(nm, PEM_STRING_X509_OLD) == 0
++        && strcmp(name, PEM_STRING_X509_TRUSTED) == 0)
++        return 1;
++
++    /* Some CAs use PKCS#7 with CERTIFICATE headers */
++    if (strcmp(nm, PEM_STRING_X509) == 0
++        && strcmp(name, PEM_STRING_PKCS7) == 0)
++        return 1;
++
++    if (strcmp(nm, PEM_STRING_PKCS7_SIGNED) == 0
++        && strcmp(name, PEM_STRING_PKCS7) == 0)
++        return 1;
++
++#ifndef OPENSSL_NO_CMS
++    if (strcmp(nm, PEM_STRING_X509) == 0
++        && strcmp(name, PEM_STRING_CMS) == 0)
++        return 1;
++    /* Allow CMS to be read from PKCS#7 headers */
++    if (strcmp(nm, PEM_STRING_PKCS7) == 0
++        && strcmp(name, PEM_STRING_CMS) == 0)
++        return 1;
++#endif
++
++    return 0;
++}
++
++int PEM_bytes_read_bio(unsigned char **pdata, long *plen, char **pnm,
++                       const char *name, BIO *bp, pem_password_cb *cb,
++                       void *u)
++{
++    EVP_CIPHER_INFO cipher;
++    char *nm = NULL, *header = NULL;
++    unsigned char *data = NULL;
++    long len;
++    int ret = 0;
++
++    for (;;) {
++        if (!PEM_read_bio(bp, &nm, &header, &data, &len)) {
++            if (ERR_GET_REASON(ERR_peek_error()) == PEM_R_NO_START_LINE)
++                ERR_add_error_data(2, "Expecting: ", name);
++            return 0;
++        }
++        if (check_pem(nm, name))
++            break;
++        OPENSSL_free(nm);
++        OPENSSL_free(header);
++        OPENSSL_free(data);
++    }
++    if (!PEM_get_EVP_CIPHER_INFO(header, &cipher))
++        goto err;
++    if (!PEM_do_header(&cipher, data, &len, cb, u))
++        goto err;
++
++    *pdata = data;
++    *plen = len;
++
++    if (pnm)
++        *pnm = nm;
++
++    ret = 1;
++
++ err:
++    if (!ret || !pnm)
++        OPENSSL_free(nm);
++    OPENSSL_free(header);
++    if (!ret)
++        OPENSSL_free(data);
++    return ret;
++}
++
++#ifndef OPENSSL_NO_STDIO
++int PEM_ASN1_write(i2d_of_void *i2d, const char *name, FILE *fp,
++                   void *x, const EVP_CIPHER *enc, unsigned char *kstr,
++                   int klen, pem_password_cb *callback, void *u)
++{
++    BIO *b;
++    int ret;
++
++    if ((b = BIO_new(BIO_s_file())) == NULL) {
++        PEMerr(PEM_F_PEM_ASN1_WRITE, ERR_R_BUF_LIB);
++        return (0);
++    }
++    BIO_set_fp(b, fp, BIO_NOCLOSE);
++    ret = PEM_ASN1_write_bio(i2d, name, b, x, enc, kstr, klen, callback, u);
++    BIO_free(b);
++    return (ret);
++}
++#endif
++
++int PEM_ASN1_write_bio(i2d_of_void *i2d, const char *name, BIO *bp,
++                       void *x, const EVP_CIPHER *enc, unsigned char *kstr,
++                       int klen, pem_password_cb *callback, void *u)
++{
++    EVP_CIPHER_CTX *ctx = NULL;
++    int dsize = 0, i = 0, j = 0, ret = 0;
++    unsigned char *p, *data = NULL;
++    const char *objstr = NULL;
++    char buf[PEM_BUFSIZE];
++    unsigned char key[EVP_MAX_KEY_LENGTH];
++    unsigned char iv[EVP_MAX_IV_LENGTH];
++
++    if (enc != NULL) {
++        objstr = OBJ_nid2sn(EVP_CIPHER_nid(enc));
++        if (objstr == NULL || EVP_CIPHER_iv_length(enc) == 0) {
++            PEMerr(PEM_F_PEM_ASN1_WRITE_BIO, PEM_R_UNSUPPORTED_CIPHER);
++            goto err;
++        }
++    }
++
++    if ((dsize = i2d(x, NULL)) < 0) {
++        PEMerr(PEM_F_PEM_ASN1_WRITE_BIO, ERR_R_ASN1_LIB);
++        dsize = 0;
++        goto err;
++    }
++    /* dzise + 8 bytes are needed */
++    /* actually it needs the cipher block size extra... */
++    data = OPENSSL_malloc((unsigned int)dsize + 20);
++    if (data == NULL) {
++        PEMerr(PEM_F_PEM_ASN1_WRITE_BIO, ERR_R_MALLOC_FAILURE);
++        goto err;
++    }
++    p = data;
++    i = i2d(x, &p);
++
++    if (enc != NULL) {
++        if (kstr == NULL) {
++            if (callback == NULL)
++                klen = PEM_def_callback(buf, PEM_BUFSIZE, 1, u);
++            else
++                klen = (*callback) (buf, PEM_BUFSIZE, 1, u);
++            if (klen <= 0) {
++                PEMerr(PEM_F_PEM_ASN1_WRITE_BIO, PEM_R_READ_KEY);
++                goto err;
++            }
++#ifdef CHARSET_EBCDIC
++            /* Convert the pass phrase from EBCDIC */
++            ebcdic2ascii(buf, buf, klen);
++#endif
++            kstr = (unsigned char *)buf;
++        }
++        RAND_add(data, i, 0);   /* put in the RSA key. */
++        OPENSSL_assert(EVP_CIPHER_iv_length(enc) <= (int)sizeof(iv));
++        if (RAND_bytes(iv, EVP_CIPHER_iv_length(enc)) <= 0) /* Generate a salt */
++            goto err;
++        /*
++         * The 'iv' is used as the iv and as a salt.  It is NOT taken from
++         * the BytesToKey function
++         */
++        if (!EVP_BytesToKey(enc, EVP_md5(), iv, kstr, klen, 1, key, NULL))
++            goto err;
++
++        if (kstr == (unsigned char *)buf)
++            OPENSSL_cleanse(buf, PEM_BUFSIZE);
++
++        OPENSSL_assert(strlen(objstr) + 23 + 2 * EVP_CIPHER_iv_length(enc) + 13
++                       <= sizeof buf);
++
++        buf[0] = '\0';
++        PEM_proc_type(buf, PEM_TYPE_ENCRYPTED);
++        PEM_dek_info(buf, objstr, EVP_CIPHER_iv_length(enc), (char *)iv);
++        /* k=strlen(buf); */
++
++        ret = 1;
++        if ((ctx = EVP_CIPHER_CTX_new()) == NULL
++            || !EVP_EncryptInit_ex(ctx, enc, NULL, key, iv)
++            || !EVP_EncryptUpdate(ctx, data, &j, data, i)
++            || !EVP_EncryptFinal_ex(ctx, &(data[j]), &i))
++            ret = 0;
++        if (ret == 0)
++            goto err;
++        i += j;
++    } else {
++        ret = 1;
++        buf[0] = '\0';
++    }
++    i = PEM_write_bio(bp, name, buf, data, i);
++    if (i <= 0)
++        ret = 0;
++ err:
++    OPENSSL_cleanse(key, sizeof(key));
++    OPENSSL_cleanse(iv, sizeof(iv));
++    EVP_CIPHER_CTX_free(ctx);
++    OPENSSL_cleanse(buf, PEM_BUFSIZE);
++    OPENSSL_clear_free(data, (unsigned int)dsize);
++    return (ret);
++}
++
++int PEM_do_header(EVP_CIPHER_INFO *cipher, unsigned char *data, long *plen,
++                  pem_password_cb *callback, void *u)
++{
++    int ok;
++    int keylen;
++    long len = *plen;
++    int ilen = (int) len;       /* EVP_DecryptUpdate etc. take int lengths */
++    EVP_CIPHER_CTX *ctx;
++    unsigned char key[EVP_MAX_KEY_LENGTH];
++    char buf[PEM_BUFSIZE];
++
++#if LONG_MAX > INT_MAX
++    /* Check that we did not truncate the length */
++    if (len > INT_MAX) {
++        PEMerr(PEM_F_PEM_DO_HEADER, PEM_R_HEADER_TOO_LONG);
++        return 0;
++    }
++#endif
++
++    if (cipher->cipher == NULL)
++        return 1;
++    if (callback == NULL)
++        keylen = PEM_def_callback(buf, PEM_BUFSIZE, 0, u);
++    else
++        keylen = callback(buf, PEM_BUFSIZE, 0, u);
++    if (keylen <= 0) {
++        PEMerr(PEM_F_PEM_DO_HEADER, PEM_R_BAD_PASSWORD_READ);
++        return 0;
++    }
++#ifdef CHARSET_EBCDIC
++    /* Convert the pass phrase from EBCDIC */
++    ebcdic2ascii(buf, buf, keylen);
++#endif
++
++    if (!EVP_BytesToKey(cipher->cipher, EVP_md5(), &(cipher->iv[0]),
++                        (unsigned char *)buf, keylen, 1, key, NULL))
++        return 0;
++
++    ctx = EVP_CIPHER_CTX_new();
++    if (ctx == NULL)
++        return 0;
++
++    ok = EVP_DecryptInit_ex(ctx, cipher->cipher, NULL, key, &(cipher->iv[0]));
++    if (ok)
++        ok = EVP_DecryptUpdate(ctx, data, &ilen, data, ilen);
++    if (ok) {
++        /* Squirrel away the length of data decrypted so far. */
++        *plen = ilen;
++        ok = EVP_DecryptFinal_ex(ctx, &(data[ilen]), &ilen);
++    }
++    if (ok)
++        *plen += ilen;
++    else
++        PEMerr(PEM_F_PEM_DO_HEADER, PEM_R_BAD_DECRYPT);
++
++    EVP_CIPHER_CTX_free(ctx);
++    OPENSSL_cleanse((char *)buf, sizeof(buf));
++    OPENSSL_cleanse((char *)key, sizeof(key));
++    return ok;
++}
++
++/*
++ * This implements a very limited PEM header parser that does not support the
++ * full grammar of rfc1421.  In particular, folded headers are not supported,
++ * nor is additional whitespace.
++ *
++ * A robust implementation would make use of a library that turns the headers
++ * into a BIO from which one folded line is read at a time, and is then split
++ * into a header label and content.  We would then parse the content of the
++ * headers we care about.  This is overkill for just this limited use-case, but
++ * presumably we also parse rfc822-style headers for S/MIME, so a common
++ * abstraction might well be more generally useful.
++ */
++int PEM_get_EVP_CIPHER_INFO(char *header, EVP_CIPHER_INFO *cipher)
++{
++    static const char ProcType[] = "Proc-Type:";
++    static const char ENCRYPTED[] = "ENCRYPTED";
++    static const char DEKInfo[] = "DEK-Info:";
++    const EVP_CIPHER *enc = NULL;
++    int ivlen;
++    char *dekinfostart, c;
++
++    cipher->cipher = NULL;
++    if ((header == NULL) || (*header == '\0') || (*header == '\n'))
++        return 1;
++
++    if (strncmp(header, ProcType, sizeof(ProcType)-1) != 0) {
++        PEMerr(PEM_F_PEM_GET_EVP_CIPHER_INFO, PEM_R_NOT_PROC_TYPE);
++        return 0;
++    }
++    header += sizeof(ProcType)-1;
++    header += strspn(header, " \t");
++
++    if (*header++ != '4' || *header++ != ',')
++        return 0;
++    header += strspn(header, " \t");
++
++    /* We expect "ENCRYPTED" followed by optional white-space + line break */
++    if (strncmp(header, ENCRYPTED, sizeof(ENCRYPTED)-1) != 0 ||
++        strspn(header+sizeof(ENCRYPTED)-1, " \t\r\n") == 0) {
++        PEMerr(PEM_F_PEM_GET_EVP_CIPHER_INFO, PEM_R_NOT_ENCRYPTED);
++        return 0;
++    }
++    header += sizeof(ENCRYPTED)-1;
++    header += strspn(header, " \t\r");
++    if (*header++ != '\n') {
++        PEMerr(PEM_F_PEM_GET_EVP_CIPHER_INFO, PEM_R_SHORT_HEADER);
++        return 0;
++    }
++
++    /*-
++     * https://tools.ietf.org/html/rfc1421#section-4.6.1.3
++     * We expect "DEK-Info: algo[,hex-parameters]"
++     */
++    if (strncmp(header, DEKInfo, sizeof(DEKInfo)-1) != 0) {
++        PEMerr(PEM_F_PEM_GET_EVP_CIPHER_INFO, PEM_R_NOT_DEK_INFO);
++        return 0;
++    }
++    header += sizeof(DEKInfo)-1;
++    header += strspn(header, " \t");
++
++    /*
++     * DEK-INFO is a comma-separated combination of algorithm name and optional
++     * parameters.
++     */
++    dekinfostart = header;
++    header += strcspn(header, " \t,");
++    c = *header;
++    *header = '\0';
++    cipher->cipher = enc = EVP_get_cipherbyname(dekinfostart);
++    *header = c;
++    header += strspn(header, " \t");
++
++    if (enc == NULL) {
++        PEMerr(PEM_F_PEM_GET_EVP_CIPHER_INFO, PEM_R_UNSUPPORTED_ENCRYPTION);
++        return 0;
++    }
++    ivlen = EVP_CIPHER_iv_length(enc);
++    if (ivlen > 0 && *header++ != ',') {
++        PEMerr(PEM_F_PEM_GET_EVP_CIPHER_INFO, PEM_R_MISSING_DEK_IV);
++        return 0;
++    } else if (ivlen == 0 && *header == ',') {
++        PEMerr(PEM_F_PEM_GET_EVP_CIPHER_INFO, PEM_R_UNEXPECTED_DEK_IV);
++        return 0;
++    }
++
++    if (!load_iv(&header, cipher->iv, EVP_CIPHER_iv_length(enc)))
++        return 0;
++
++    return 1;
++}
++
++static int load_iv(char **fromp, unsigned char *to, int num)
++{
++    int v, i;
++    char *from;
++
++    from = *fromp;
++    for (i = 0; i < num; i++)
++        to[i] = 0;
++    num *= 2;
++    for (i = 0; i < num; i++) {
++        v = OPENSSL_hexchar2int(*from);
++        if (v < 0) {
++            PEMerr(PEM_F_LOAD_IV, PEM_R_BAD_IV_CHARS);
++            return (0);
++        }
++        from++;
++        to[i / 2] |= v << (long)((!(i & 1)) * 4);
++    }
++
++    *fromp = from;
++    return (1);
++}
++
++#ifndef OPENSSL_NO_STDIO
++int PEM_write(FILE *fp, const char *name, const char *header,
++              const unsigned char *data, long len)
++{
++    BIO *b;
++    int ret;
++
++    if ((b = BIO_new(BIO_s_file())) == NULL) {
++        PEMerr(PEM_F_PEM_WRITE, ERR_R_BUF_LIB);
++        return (0);
++    }
++    BIO_set_fp(b, fp, BIO_NOCLOSE);
++    ret = PEM_write_bio(b, name, header, data, len);
++    BIO_free(b);
++    return (ret);
++}
++#endif
++
++int PEM_write_bio(BIO *bp, const char *name, const char *header,
++                  const unsigned char *data, long len)
++{
++    int nlen, n, i, j, outl;
++    unsigned char *buf = NULL;
++    EVP_ENCODE_CTX *ctx = EVP_ENCODE_CTX_new();
++    int reason = ERR_R_BUF_LIB;
++
++    if (ctx == NULL) {
++        reason = ERR_R_MALLOC_FAILURE;
++        goto err;
++    }
++
++    EVP_EncodeInit(ctx);
++    nlen = strlen(name);
++
++    if ((BIO_write(bp, "-----BEGIN ", 11) != 11) ||
++        (BIO_write(bp, name, nlen) != nlen) ||
++        (BIO_write(bp, "-----\n", 6) != 6))
++        goto err;
++
++    i = strlen(header);
++    if (i > 0) {
++        if ((BIO_write(bp, header, i) != i) || (BIO_write(bp, "\n", 1) != 1))
++            goto err;
++    }
++
++    buf = OPENSSL_malloc(PEM_BUFSIZE * 8);
++    if (buf == NULL) {
++        reason = ERR_R_MALLOC_FAILURE;
++        goto err;
++    }
++
++    i = j = 0;
++    while (len > 0) {
++        n = (int)((len > (PEM_BUFSIZE * 5)) ? (PEM_BUFSIZE * 5) : len);
++        if (!EVP_EncodeUpdate(ctx, buf, &outl, &(data[j]), n))
++            goto err;
++        if ((outl) && (BIO_write(bp, (char *)buf, outl) != outl))
++            goto err;
++        i += outl;
++        len -= n;
++        j += n;
++    }
++    EVP_EncodeFinal(ctx, buf, &outl);
++    if ((outl > 0) && (BIO_write(bp, (char *)buf, outl) != outl))
++        goto err;
++    if ((BIO_write(bp, "-----END ", 9) != 9) ||
++        (BIO_write(bp, name, nlen) != nlen) ||
++        (BIO_write(bp, "-----\n", 6) != 6))
++        goto err;
++    OPENSSL_clear_free(buf, PEM_BUFSIZE * 8);
++    EVP_ENCODE_CTX_free(ctx);
++    return (i + outl);
++ err:
++    OPENSSL_clear_free(buf, PEM_BUFSIZE * 8);
++    EVP_ENCODE_CTX_free(ctx);
++    PEMerr(PEM_F_PEM_WRITE_BIO, reason);
++    return (0);
++}
++
++#ifndef OPENSSL_NO_STDIO
++int PEM_read(FILE *fp, char **name, char **header, unsigned char **data,
++             long *len)
++{
++    BIO *b;
++    int ret;
++
++    if ((b = BIO_new(BIO_s_file())) == NULL) {
++        PEMerr(PEM_F_PEM_READ, ERR_R_BUF_LIB);
++        return (0);
++    }
++    BIO_set_fp(b, fp, BIO_NOCLOSE);
++    ret = PEM_read_bio(b, name, header, data, len);
++    BIO_free(b);
++    return (ret);
++}
++#endif
++
++int PEM_read_bio(BIO *bp, char **name, char **header, unsigned char **data,
++                 long *len)
++{
++    EVP_ENCODE_CTX *ctx = EVP_ENCODE_CTX_new();
++    int end = 0, i, k, bl = 0, hl = 0, nohead = 0;
++    char buf[256];
++    BUF_MEM *nameB;
++    BUF_MEM *headerB;
++    BUF_MEM *dataB, *tmpB;
++
++    if (ctx == NULL) {
++        PEMerr(PEM_F_PEM_READ_BIO, ERR_R_MALLOC_FAILURE);
++        return (0);
++    }
++
++    nameB = BUF_MEM_new();
++    headerB = BUF_MEM_new();
++    dataB = BUF_MEM_new();
++    if ((nameB == NULL) || (headerB == NULL) || (dataB == NULL)) {
++        goto err;
++    }
++
++    buf[254] = '\0';
++    for (;;) {
++        i = BIO_gets(bp, buf, 254);
++
++        if (i <= 0) {
++            PEMerr(PEM_F_PEM_READ_BIO, PEM_R_NO_START_LINE);
++            goto err;
++        }
++
++        while ((i >= 0) && (buf[i] <= ' '))
++            i--;
++        buf[++i] = '\n';
++        buf[++i] = '\0';
++
++        if (strncmp(buf, "-----BEGIN ", 11) == 0) {
++            i = strlen(&(buf[11]));
++
++            if (strncmp(&(buf[11 + i - 6]), "-----\n", 6) != 0)
++                continue;
++            if (!BUF_MEM_grow(nameB, i + 9)) {
++                PEMerr(PEM_F_PEM_READ_BIO, ERR_R_MALLOC_FAILURE);
++                goto err;
++            }
++            memcpy(nameB->data, &(buf[11]), i - 6);
++            nameB->data[i - 6] = '\0';
++            break;
++        }
++    }
++    hl = 0;
++    if (!BUF_MEM_grow(headerB, 256)) {
++        PEMerr(PEM_F_PEM_READ_BIO, ERR_R_MALLOC_FAILURE);
++        goto err;
++    }
++    headerB->data[0] = '\0';
++    for (;;) {
++        i = BIO_gets(bp, buf, 254);
++        if (i <= 0)
++            break;
++
++        while ((i >= 0) && (buf[i] <= ' '))
++            i--;
++        buf[++i] = '\n';
++        buf[++i] = '\0';
++
++        if (buf[0] == '\n')
++            break;
++        if (!BUF_MEM_grow(headerB, hl + i + 9)) {
++            PEMerr(PEM_F_PEM_READ_BIO, ERR_R_MALLOC_FAILURE);
++            goto err;
++        }
++        if (strncmp(buf, "-----END ", 9) == 0) {
++            nohead = 1;
++            break;
++        }
++        memcpy(&(headerB->data[hl]), buf, i);
++        headerB->data[hl + i] = '\0';
++        hl += i;
++    }
++
++    bl = 0;
++    if (!BUF_MEM_grow(dataB, 1024)) {
++        PEMerr(PEM_F_PEM_READ_BIO, ERR_R_MALLOC_FAILURE);
++        goto err;
++    }
++    dataB->data[0] = '\0';
++    if (!nohead) {
++        for (;;) {
++            i = BIO_gets(bp, buf, 254);
++            if (i <= 0)
++                break;
++
++            while ((i >= 0) && (buf[i] <= ' '))
++                i--;
++            buf[++i] = '\n';
++            buf[++i] = '\0';
++
++            if (i != 65)
++                end = 1;
++            if (strncmp(buf, "-----END ", 9) == 0)
++                break;
++            if (i > 65)
++                break;
++            if (!BUF_MEM_grow_clean(dataB, i + bl + 9)) {
++                PEMerr(PEM_F_PEM_READ_BIO, ERR_R_MALLOC_FAILURE);
++                goto err;
++            }
++            memcpy(&(dataB->data[bl]), buf, i);
++            dataB->data[bl + i] = '\0';
++            bl += i;
++            if (end) {
++                buf[0] = '\0';
++                i = BIO_gets(bp, buf, 254);
++                if (i <= 0)
++                    break;
++
++                while ((i >= 0) && (buf[i] <= ' '))
++                    i--;
++                buf[++i] = '\n';
++                buf[++i] = '\0';
++
++                break;
++            }
++        }
++    } else {
++        tmpB = headerB;
++        headerB = dataB;
++        dataB = tmpB;
++        bl = hl;
++    }
++    i = strlen(nameB->data);
++    if ((strncmp(buf, "-----END ", 9) != 0) ||
++        (strncmp(nameB->data, &(buf[9]), i) != 0) ||
++        (strncmp(&(buf[9 + i]), "-----\n", 6) != 0)) {
++        PEMerr(PEM_F_PEM_READ_BIO, PEM_R_BAD_END_LINE);
++        goto err;
++    }
++
++    EVP_DecodeInit(ctx);
++    i = EVP_DecodeUpdate(ctx,
++                         (unsigned char *)dataB->data, &bl,
++                         (unsigned char *)dataB->data, bl);
++    if (i < 0) {
++        PEMerr(PEM_F_PEM_READ_BIO, PEM_R_BAD_BASE64_DECODE);
++        goto err;
++    }
++    i = EVP_DecodeFinal(ctx, (unsigned char *)&(dataB->data[bl]), &k);
++    if (i < 0) {
++        PEMerr(PEM_F_PEM_READ_BIO, PEM_R_BAD_BASE64_DECODE);
++        goto err;
++    }
++    bl += k;
++
++    if (bl == 0)
++        goto err;
++    *name = nameB->data;
++    *header = headerB->data;
++    *data = (unsigned char *)dataB->data;
++    *len = bl;
++    OPENSSL_free(nameB);
++    OPENSSL_free(headerB);
++    OPENSSL_free(dataB);
++    EVP_ENCODE_CTX_free(ctx);
++    return (1);
++ err:
++    BUF_MEM_free(nameB);
++    BUF_MEM_free(headerB);
++    BUF_MEM_free(dataB);
++    EVP_ENCODE_CTX_free(ctx);
++    return (0);
++}
++
++/*
++ * Check pem string and return prefix length. If for example the pem_str ==
++ * "RSA PRIVATE KEY" and suffix = "PRIVATE KEY" the return value is 3 for the
++ * string "RSA".
++ */
++
++int pem_check_suffix(const char *pem_str, const char *suffix)
++{
++    int pem_len = strlen(pem_str);
++    int suffix_len = strlen(suffix);
++    const char *p;
++    if (suffix_len + 1 >= pem_len)
++        return 0;
++    p = pem_str + pem_len - suffix_len;
++    if (strcmp(p, suffix))
++        return 0;
++    p--;
++    if (*p != ' ')
++        return 0;
++    return p - pem_str;
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/pem/pem_oth.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/pem/pem_oth.c
+new file mode 100644
+index 0000000..cc7a8db
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/pem/pem_oth.c
+@@ -0,0 +1,36 @@
++/*
++ * Copyright 1995-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include "internal/cryptlib.h"
++#include 
++#include 
++#include 
++#include 
++#include 
++
++/* Handle 'other' PEMs: not private keys */
++
++void *PEM_ASN1_read_bio(d2i_of_void *d2i, const char *name, BIO *bp, void **x,
++                        pem_password_cb *cb, void *u)
++{
++    const unsigned char *p = NULL;
++    unsigned char *data = NULL;
++    long len;
++    char *ret = NULL;
++
++    if (!PEM_bytes_read_bio(&data, &len, NULL, name, bp, cb, u))
++        return NULL;
++    p = data;
++    ret = d2i(x, &p, len);
++    if (ret == NULL)
++        PEMerr(PEM_F_PEM_ASN1_READ_BIO, ERR_R_ASN1_LIB);
++    OPENSSL_free(data);
++    return (ret);
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/pem/pem_pk8.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/pem/pem_pk8.c
+new file mode 100644
+index 0000000..993c595
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/pem/pem_pk8.c
+@@ -0,0 +1,213 @@
++/*
++ * Copyright 1995-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include "internal/cryptlib.h"
++#include 
++#include 
++#include 
++#include 
++#include 
++#include 
++
++static int do_pk8pkey(BIO *bp, EVP_PKEY *x, int isder,
++                      int nid, const EVP_CIPHER *enc,
++                      char *kstr, int klen, pem_password_cb *cb, void *u);
++
++#ifndef OPENSSL_NO_STDIO
++static int do_pk8pkey_fp(FILE *bp, EVP_PKEY *x, int isder,
++                         int nid, const EVP_CIPHER *enc,
++                         char *kstr, int klen, pem_password_cb *cb, void *u);
++#endif
++/*
++ * These functions write a private key in PKCS#8 format: it is a "drop in"
++ * replacement for PEM_write_bio_PrivateKey() and friends. As usual if 'enc'
++ * is NULL then it uses the unencrypted private key form. The 'nid' versions
++ * uses PKCS#5 v1.5 PBE algorithms whereas the others use PKCS#5 v2.0.
++ */
++
++int PEM_write_bio_PKCS8PrivateKey_nid(BIO *bp, EVP_PKEY *x, int nid,
++                                      char *kstr, int klen,
++                                      pem_password_cb *cb, void *u)
++{
++    return do_pk8pkey(bp, x, 0, nid, NULL, kstr, klen, cb, u);
++}
++
++int PEM_write_bio_PKCS8PrivateKey(BIO *bp, EVP_PKEY *x, const EVP_CIPHER *enc,
++                                  char *kstr, int klen,
++                                  pem_password_cb *cb, void *u)
++{
++    return do_pk8pkey(bp, x, 0, -1, enc, kstr, klen, cb, u);
++}
++
++int i2d_PKCS8PrivateKey_bio(BIO *bp, EVP_PKEY *x, const EVP_CIPHER *enc,
++                            char *kstr, int klen,
++                            pem_password_cb *cb, void *u)
++{
++    return do_pk8pkey(bp, x, 1, -1, enc, kstr, klen, cb, u);
++}
++
++int i2d_PKCS8PrivateKey_nid_bio(BIO *bp, EVP_PKEY *x, int nid,
++                                char *kstr, int klen,
++                                pem_password_cb *cb, void *u)
++{
++    return do_pk8pkey(bp, x, 1, nid, NULL, kstr, klen, cb, u);
++}
++
++static int do_pk8pkey(BIO *bp, EVP_PKEY *x, int isder, int nid,
++                      const EVP_CIPHER *enc, char *kstr, int klen,
++                      pem_password_cb *cb, void *u)
++{
++    X509_SIG *p8;
++    PKCS8_PRIV_KEY_INFO *p8inf;
++    char buf[PEM_BUFSIZE];
++    int ret;
++
++    if ((p8inf = EVP_PKEY2PKCS8(x)) == NULL) {
++        PEMerr(PEM_F_DO_PK8PKEY, PEM_R_ERROR_CONVERTING_PRIVATE_KEY);
++        return 0;
++    }
++    if (enc || (nid != -1)) {
++        if (!kstr) {
++            if (!cb)
++                klen = PEM_def_callback(buf, PEM_BUFSIZE, 1, u);
++            else
++                klen = cb(buf, PEM_BUFSIZE, 1, u);
++            if (klen <= 0) {
++                PEMerr(PEM_F_DO_PK8PKEY, PEM_R_READ_KEY);
++                PKCS8_PRIV_KEY_INFO_free(p8inf);
++                return 0;
++            }
++
++            kstr = buf;
++        }
++        p8 = PKCS8_encrypt(nid, enc, kstr, klen, NULL, 0, 0, p8inf);
++        if (kstr == buf)
++            OPENSSL_cleanse(buf, klen);
++        PKCS8_PRIV_KEY_INFO_free(p8inf);
++        if (p8 == NULL)
++            return 0;
++        if (isder)
++            ret = i2d_PKCS8_bio(bp, p8);
++        else
++            ret = PEM_write_bio_PKCS8(bp, p8);
++        X509_SIG_free(p8);
++        return ret;
++    } else {
++        if (isder)
++            ret = i2d_PKCS8_PRIV_KEY_INFO_bio(bp, p8inf);
++        else
++            ret = PEM_write_bio_PKCS8_PRIV_KEY_INFO(bp, p8inf);
++        PKCS8_PRIV_KEY_INFO_free(p8inf);
++        return ret;
++    }
++}
++
++EVP_PKEY *d2i_PKCS8PrivateKey_bio(BIO *bp, EVP_PKEY **x, pem_password_cb *cb,
++                                  void *u)
++{
++    PKCS8_PRIV_KEY_INFO *p8inf = NULL;
++    X509_SIG *p8 = NULL;
++    int klen;
++    EVP_PKEY *ret;
++    char psbuf[PEM_BUFSIZE];
++    p8 = d2i_PKCS8_bio(bp, NULL);
++    if (!p8)
++        return NULL;
++    if (cb)
++        klen = cb(psbuf, PEM_BUFSIZE, 0, u);
++    else
++        klen = PEM_def_callback(psbuf, PEM_BUFSIZE, 0, u);
++    if (klen <= 0) {
++        PEMerr(PEM_F_D2I_PKCS8PRIVATEKEY_BIO, PEM_R_BAD_PASSWORD_READ);
++        X509_SIG_free(p8);
++        return NULL;
++    }
++    p8inf = PKCS8_decrypt(p8, psbuf, klen);
++    X509_SIG_free(p8);
++    if (!p8inf)
++        return NULL;
++    ret = EVP_PKCS82PKEY(p8inf);
++    PKCS8_PRIV_KEY_INFO_free(p8inf);
++    if (!ret)
++        return NULL;
++    if (x) {
++        EVP_PKEY_free(*x);
++        *x = ret;
++    }
++    return ret;
++}
++
++#ifndef OPENSSL_NO_STDIO
++
++int i2d_PKCS8PrivateKey_fp(FILE *fp, EVP_PKEY *x, const EVP_CIPHER *enc,
++                           char *kstr, int klen, pem_password_cb *cb, void *u)
++{
++    return do_pk8pkey_fp(fp, x, 1, -1, enc, kstr, klen, cb, u);
++}
++
++int i2d_PKCS8PrivateKey_nid_fp(FILE *fp, EVP_PKEY *x, int nid,
++                               char *kstr, int klen,
++                               pem_password_cb *cb, void *u)
++{
++    return do_pk8pkey_fp(fp, x, 1, nid, NULL, kstr, klen, cb, u);
++}
++
++int PEM_write_PKCS8PrivateKey_nid(FILE *fp, EVP_PKEY *x, int nid,
++                                  char *kstr, int klen,
++                                  pem_password_cb *cb, void *u)
++{
++    return do_pk8pkey_fp(fp, x, 0, nid, NULL, kstr, klen, cb, u);
++}
++
++int PEM_write_PKCS8PrivateKey(FILE *fp, EVP_PKEY *x, const EVP_CIPHER *enc,
++                              char *kstr, int klen, pem_password_cb *cb,
++                              void *u)
++{
++    return do_pk8pkey_fp(fp, x, 0, -1, enc, kstr, klen, cb, u);
++}
++
++static int do_pk8pkey_fp(FILE *fp, EVP_PKEY *x, int isder, int nid,
++                         const EVP_CIPHER *enc, char *kstr, int klen,
++                         pem_password_cb *cb, void *u)
++{
++    BIO *bp;
++    int ret;
++
++    if ((bp = BIO_new_fp(fp, BIO_NOCLOSE)) == NULL) {
++        PEMerr(PEM_F_DO_PK8PKEY_FP, ERR_R_BUF_LIB);
++        return (0);
++    }
++    ret = do_pk8pkey(bp, x, isder, nid, enc, kstr, klen, cb, u);
++    BIO_free(bp);
++    return ret;
++}
++
++EVP_PKEY *d2i_PKCS8PrivateKey_fp(FILE *fp, EVP_PKEY **x, pem_password_cb *cb,
++                                 void *u)
++{
++    BIO *bp;
++    EVP_PKEY *ret;
++
++    if ((bp = BIO_new_fp(fp, BIO_NOCLOSE)) == NULL) {
++        PEMerr(PEM_F_D2I_PKCS8PRIVATEKEY_FP, ERR_R_BUF_LIB);
++        return NULL;
++    }
++    ret = d2i_PKCS8PrivateKey_bio(bp, x, cb, u);
++    BIO_free(bp);
++    return ret;
++}
++
++#endif
++
++IMPLEMENT_PEM_rw(PKCS8, X509_SIG, PEM_STRING_PKCS8, X509_SIG)
++
++
++IMPLEMENT_PEM_rw(PKCS8_PRIV_KEY_INFO, PKCS8_PRIV_KEY_INFO, PEM_STRING_PKCS8INF,
++             PKCS8_PRIV_KEY_INFO)
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/pem/pem_pkey.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/pem/pem_pkey.c
+new file mode 100644
+index 0000000..6308622
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/pem/pem_pkey.c
+@@ -0,0 +1,243 @@
++/*
++ * Copyright 1995-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include "internal/cryptlib.h"
++#include 
++#include 
++#include 
++#include 
++#include 
++#include 
++#include 
++#include 
++#include "internal/asn1_int.h"
++#include "internal/evp_int.h"
++
++int pem_check_suffix(const char *pem_str, const char *suffix);
++
++EVP_PKEY *PEM_read_bio_PrivateKey(BIO *bp, EVP_PKEY **x, pem_password_cb *cb,
++                                  void *u)
++{
++    char *nm = NULL;
++    const unsigned char *p = NULL;
++    unsigned char *data = NULL;
++    long len;
++    int slen;
++    EVP_PKEY *ret = NULL;
++
++    if (!PEM_bytes_read_bio(&data, &len, &nm, PEM_STRING_EVP_PKEY, bp, cb, u))
++        return NULL;
++    p = data;
++
++    if (strcmp(nm, PEM_STRING_PKCS8INF) == 0) {
++        PKCS8_PRIV_KEY_INFO *p8inf;
++        p8inf = d2i_PKCS8_PRIV_KEY_INFO(NULL, &p, len);
++        if (!p8inf)
++            goto p8err;
++        ret = EVP_PKCS82PKEY(p8inf);
++        if (x) {
++            EVP_PKEY_free((EVP_PKEY *)*x);
++            *x = ret;
++        }
++        PKCS8_PRIV_KEY_INFO_free(p8inf);
++    } else if (strcmp(nm, PEM_STRING_PKCS8) == 0) {
++        PKCS8_PRIV_KEY_INFO *p8inf;
++        X509_SIG *p8;
++        int klen;
++        char psbuf[PEM_BUFSIZE];
++        p8 = d2i_X509_SIG(NULL, &p, len);
++        if (!p8)
++            goto p8err;
++        if (cb)
++            klen = cb(psbuf, PEM_BUFSIZE, 0, u);
++        else
++            klen = PEM_def_callback(psbuf, PEM_BUFSIZE, 0, u);
++        if (klen <= 0) {
++            PEMerr(PEM_F_PEM_READ_BIO_PRIVATEKEY, PEM_R_BAD_PASSWORD_READ);
++            X509_SIG_free(p8);
++            goto err;
++        }
++        p8inf = PKCS8_decrypt(p8, psbuf, klen);
++        X509_SIG_free(p8);
++        if (!p8inf)
++            goto p8err;
++        ret = EVP_PKCS82PKEY(p8inf);
++        if (x) {
++            EVP_PKEY_free((EVP_PKEY *)*x);
++            *x = ret;
++        }
++        PKCS8_PRIV_KEY_INFO_free(p8inf);
++    } else if ((slen = pem_check_suffix(nm, "PRIVATE KEY")) > 0) {
++        const EVP_PKEY_ASN1_METHOD *ameth;
++        ameth = EVP_PKEY_asn1_find_str(NULL, nm, slen);
++        if (!ameth || !ameth->old_priv_decode)
++            goto p8err;
++        ret = d2i_PrivateKey(ameth->pkey_id, x, &p, len);
++    }
++ p8err:
++    if (ret == NULL)
++        PEMerr(PEM_F_PEM_READ_BIO_PRIVATEKEY, ERR_R_ASN1_LIB);
++ err:
++    OPENSSL_free(nm);
++    OPENSSL_clear_free(data, len);
++    return (ret);
++}
++
++int PEM_write_bio_PrivateKey(BIO *bp, EVP_PKEY *x, const EVP_CIPHER *enc,
++                             unsigned char *kstr, int klen,
++                             pem_password_cb *cb, void *u)
++{
++    if (x->ameth == NULL || x->ameth->priv_encode != NULL)
++        return PEM_write_bio_PKCS8PrivateKey(bp, x, enc,
++                                             (char *)kstr, klen, cb, u);
++    return PEM_write_bio_PrivateKey_traditional(bp, x, enc, kstr, klen, cb, u);
++}
++
++int PEM_write_bio_PrivateKey_traditional(BIO *bp, EVP_PKEY *x,
++                                         const EVP_CIPHER *enc,
++                                         unsigned char *kstr, int klen,
++                                         pem_password_cb *cb, void *u)
++{
++    char pem_str[80];
++    BIO_snprintf(pem_str, 80, "%s PRIVATE KEY", x->ameth->pem_str);
++    return PEM_ASN1_write_bio((i2d_of_void *)i2d_PrivateKey,
++                              pem_str, bp, x, enc, kstr, klen, cb, u);
++}
++
++EVP_PKEY *PEM_read_bio_Parameters(BIO *bp, EVP_PKEY **x)
++{
++    char *nm = NULL;
++    const unsigned char *p = NULL;
++    unsigned char *data = NULL;
++    long len;
++    int slen;
++    EVP_PKEY *ret = NULL;
++
++    if (!PEM_bytes_read_bio(&data, &len, &nm, PEM_STRING_PARAMETERS,
++                            bp, 0, NULL))
++        return NULL;
++    p = data;
++
++    if ((slen = pem_check_suffix(nm, "PARAMETERS")) > 0) {
++        ret = EVP_PKEY_new();
++        if (ret == NULL)
++            goto err;
++        if (!EVP_PKEY_set_type_str(ret, nm, slen)
++            || !ret->ameth->param_decode
++            || !ret->ameth->param_decode(ret, &p, len)) {
++            EVP_PKEY_free(ret);
++            ret = NULL;
++            goto err;
++        }
++        if (x) {
++            EVP_PKEY_free((EVP_PKEY *)*x);
++            *x = ret;
++        }
++    }
++ err:
++    if (ret == NULL)
++        PEMerr(PEM_F_PEM_READ_BIO_PARAMETERS, ERR_R_ASN1_LIB);
++    OPENSSL_free(nm);
++    OPENSSL_free(data);
++    return (ret);
++}
++
++int PEM_write_bio_Parameters(BIO *bp, EVP_PKEY *x)
++{
++    char pem_str[80];
++    if (!x->ameth || !x->ameth->param_encode)
++        return 0;
++
++    BIO_snprintf(pem_str, 80, "%s PARAMETERS", x->ameth->pem_str);
++    return PEM_ASN1_write_bio((i2d_of_void *)x->ameth->param_encode,
++                              pem_str, bp, x, NULL, NULL, 0, 0, NULL);
++}
++
++#ifndef OPENSSL_NO_STDIO
++EVP_PKEY *PEM_read_PrivateKey(FILE *fp, EVP_PKEY **x, pem_password_cb *cb,
++                              void *u)
++{
++    BIO *b;
++    EVP_PKEY *ret;
++
++    if ((b = BIO_new(BIO_s_file())) == NULL) {
++        PEMerr(PEM_F_PEM_READ_PRIVATEKEY, ERR_R_BUF_LIB);
++        return (0);
++    }
++    BIO_set_fp(b, fp, BIO_NOCLOSE);
++    ret = PEM_read_bio_PrivateKey(b, x, cb, u);
++    BIO_free(b);
++    return (ret);
++}
++
++int PEM_write_PrivateKey(FILE *fp, EVP_PKEY *x, const EVP_CIPHER *enc,
++                         unsigned char *kstr, int klen,
++                         pem_password_cb *cb, void *u)
++{
++    BIO *b;
++    int ret;
++
++    if ((b = BIO_new_fp(fp, BIO_NOCLOSE)) == NULL) {
++        PEMerr(PEM_F_PEM_WRITE_PRIVATEKEY, ERR_R_BUF_LIB);
++        return 0;
++    }
++    ret = PEM_write_bio_PrivateKey(b, x, enc, kstr, klen, cb, u);
++    BIO_free(b);
++    return ret;
++}
++
++#endif
++
++#ifndef OPENSSL_NO_DH
++
++/* Transparently read in PKCS#3 or X9.42 DH parameters */
++
++DH *PEM_read_bio_DHparams(BIO *bp, DH **x, pem_password_cb *cb, void *u)
++{
++    char *nm = NULL;
++    const unsigned char *p = NULL;
++    unsigned char *data = NULL;
++    long len;
++    DH *ret = NULL;
++
++    if (!PEM_bytes_read_bio(&data, &len, &nm, PEM_STRING_DHPARAMS, bp, cb, u))
++        return NULL;
++    p = data;
++
++    if (strcmp(nm, PEM_STRING_DHXPARAMS) == 0)
++        ret = d2i_DHxparams(x, &p, len);
++    else
++        ret = d2i_DHparams(x, &p, len);
++
++    if (ret == NULL)
++        PEMerr(PEM_F_PEM_READ_BIO_DHPARAMS, ERR_R_ASN1_LIB);
++    OPENSSL_free(nm);
++    OPENSSL_free(data);
++    return ret;
++}
++
++# ifndef OPENSSL_NO_STDIO
++DH *PEM_read_DHparams(FILE *fp, DH **x, pem_password_cb *cb, void *u)
++{
++    BIO *b;
++    DH *ret;
++
++    if ((b = BIO_new(BIO_s_file())) == NULL) {
++        PEMerr(PEM_F_PEM_READ_DHPARAMS, ERR_R_BUF_LIB);
++        return (0);
++    }
++    BIO_set_fp(b, fp, BIO_NOCLOSE);
++    ret = PEM_read_bio_DHparams(b, x, cb, u);
++    BIO_free(b);
++    return (ret);
++}
++# endif
++
++#endif
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/pem/pem_sign.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/pem/pem_sign.c
+new file mode 100644
+index 0000000..12ad974
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/pem/pem_sign.c
+@@ -0,0 +1,50 @@
++/*
++ * Copyright 1995-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include "internal/cryptlib.h"
++#include 
++#include 
++#include 
++#include 
++
++int PEM_SignInit(EVP_MD_CTX *ctx, EVP_MD *type)
++{
++    return EVP_DigestInit_ex(ctx, type, NULL);
++}
++
++int PEM_SignUpdate(EVP_MD_CTX *ctx, unsigned char *data, unsigned int count)
++{
++    return EVP_DigestUpdate(ctx, data, count);
++}
++
++int PEM_SignFinal(EVP_MD_CTX *ctx, unsigned char *sigret,
++                  unsigned int *siglen, EVP_PKEY *pkey)
++{
++    unsigned char *m;
++    int i, ret = 0;
++    unsigned int m_len;
++
++    m = OPENSSL_malloc(EVP_PKEY_size(pkey) + 2);
++    if (m == NULL) {
++        PEMerr(PEM_F_PEM_SIGNFINAL, ERR_R_MALLOC_FAILURE);
++        goto err;
++    }
++
++    if (EVP_SignFinal(ctx, m, &m_len, pkey) <= 0)
++        goto err;
++
++    i = EVP_EncodeBlock(sigret, m, m_len);
++    *siglen = i;
++    ret = 1;
++ err:
++    /* ctx has been zeroed by EVP_SignFinal() */
++    OPENSSL_free(m);
++    return (ret);
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/pem/pem_x509.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/pem/pem_x509.c
+new file mode 100644
+index 0000000..3a99756
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/pem/pem_x509.c
+@@ -0,0 +1,18 @@
++/*
++ * Copyright 2001-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include "internal/cryptlib.h"
++#include 
++#include 
++#include 
++#include 
++#include 
++
++IMPLEMENT_PEM_rw(X509, X509, PEM_STRING_X509, X509)
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/pem/pem_xaux.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/pem/pem_xaux.c
+new file mode 100644
+index 0000000..6d7e1db
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/pem/pem_xaux.c
+@@ -0,0 +1,18 @@
++/*
++ * Copyright 2001-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include "internal/cryptlib.h"
++#include 
++#include 
++#include 
++#include 
++#include 
++
++IMPLEMENT_PEM_rw(X509_AUX, X509, PEM_STRING_X509_TRUSTED, X509_AUX)
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/pem/pvkfmt.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/pem/pvkfmt.c
+new file mode 100644
+index 0000000..248704e
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/pem/pvkfmt.c
+@@ -0,0 +1,869 @@
++/*
++ * Copyright 2005-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++/*
++ * Support for PVK format keys and related structures (such a PUBLICKEYBLOB
++ * and PRIVATEKEYBLOB).
++ */
++
++#include "internal/cryptlib.h"
++#include 
++#include 
++#include 
++#if !defined(OPENSSL_NO_RSA) && !defined(OPENSSL_NO_DSA)
++# include 
++# include 
++
++/*
++ * Utility function: read a DWORD (4 byte unsigned integer) in little endian
++ * format
++ */
++
++static unsigned int read_ledword(const unsigned char **in)
++{
++    const unsigned char *p = *in;
++    unsigned int ret;
++    ret = *p++;
++    ret |= (*p++ << 8);
++    ret |= (*p++ << 16);
++    ret |= (*p++ << 24);
++    *in = p;
++    return ret;
++}
++
++/*
++ * Read a BIGNUM in little endian format. The docs say that this should take
++ * up bitlen/8 bytes.
++ */
++
++static int read_lebn(const unsigned char **in, unsigned int nbyte, BIGNUM **r)
++{
++    *r = BN_lebin2bn(*in, nbyte, NULL);
++    if (*r == NULL)
++        return 0;
++    *in += nbyte;
++    return 1;
++}
++
++/* Convert private key blob to EVP_PKEY: RSA and DSA keys supported */
++
++# define MS_PUBLICKEYBLOB        0x6
++# define MS_PRIVATEKEYBLOB       0x7
++# define MS_RSA1MAGIC            0x31415352L
++# define MS_RSA2MAGIC            0x32415352L
++# define MS_DSS1MAGIC            0x31535344L
++# define MS_DSS2MAGIC            0x32535344L
++
++# define MS_KEYALG_RSA_KEYX      0xa400
++# define MS_KEYALG_DSS_SIGN      0x2200
++
++# define MS_KEYTYPE_KEYX         0x1
++# define MS_KEYTYPE_SIGN         0x2
++
++/* Maximum length of a blob after header */
++# define BLOB_MAX_LENGTH          102400
++
++/* The PVK file magic number: seems to spell out "bobsfile", who is Bob? */
++# define MS_PVKMAGIC             0xb0b5f11eL
++/* Salt length for PVK files */
++# define PVK_SALTLEN             0x10
++/* Maximum length in PVK header */
++# define PVK_MAX_KEYLEN          102400
++/* Maximum salt length */
++# define PVK_MAX_SALTLEN         10240
++
++static EVP_PKEY *b2i_rsa(const unsigned char **in,
++                         unsigned int bitlen, int ispub);
++static EVP_PKEY *b2i_dss(const unsigned char **in,
++                         unsigned int bitlen, int ispub);
++
++static int do_blob_header(const unsigned char **in, unsigned int length,
++                          unsigned int *pmagic, unsigned int *pbitlen,
++                          int *pisdss, int *pispub)
++{
++    const unsigned char *p = *in;
++    if (length < 16)
++        return 0;
++    /* bType */
++    if (*p == MS_PUBLICKEYBLOB) {
++        if (*pispub == 0) {
++            PEMerr(PEM_F_DO_BLOB_HEADER, PEM_R_EXPECTING_PRIVATE_KEY_BLOB);
++            return 0;
++        }
++        *pispub = 1;
++    } else if (*p == MS_PRIVATEKEYBLOB) {
++        if (*pispub == 1) {
++            PEMerr(PEM_F_DO_BLOB_HEADER, PEM_R_EXPECTING_PUBLIC_KEY_BLOB);
++            return 0;
++        }
++        *pispub = 0;
++    } else
++        return 0;
++    p++;
++    /* Version */
++    if (*p++ != 0x2) {
++        PEMerr(PEM_F_DO_BLOB_HEADER, PEM_R_BAD_VERSION_NUMBER);
++        return 0;
++    }
++    /* Ignore reserved, aiKeyAlg */
++    p += 6;
++    *pmagic = read_ledword(&p);
++    *pbitlen = read_ledword(&p);
++    *pisdss = 0;
++    switch (*pmagic) {
++
++    case MS_DSS1MAGIC:
++        *pisdss = 1;
++    case MS_RSA1MAGIC:
++        if (*pispub == 0) {
++            PEMerr(PEM_F_DO_BLOB_HEADER, PEM_R_EXPECTING_PRIVATE_KEY_BLOB);
++            return 0;
++        }
++        break;
++
++    case MS_DSS2MAGIC:
++        *pisdss = 1;
++    case MS_RSA2MAGIC:
++        if (*pispub == 1) {
++            PEMerr(PEM_F_DO_BLOB_HEADER, PEM_R_EXPECTING_PUBLIC_KEY_BLOB);
++            return 0;
++        }
++        break;
++
++    default:
++        PEMerr(PEM_F_DO_BLOB_HEADER, PEM_R_BAD_MAGIC_NUMBER);
++        return -1;
++    }
++    *in = p;
++    return 1;
++}
++
++static unsigned int blob_length(unsigned bitlen, int isdss, int ispub)
++{
++    unsigned int nbyte, hnbyte;
++    nbyte = (bitlen + 7) >> 3;
++    hnbyte = (bitlen + 15) >> 4;
++    if (isdss) {
++
++        /*
++         * Expected length: 20 for q + 3 components bitlen each + 24 for seed
++         * structure.
++         */
++        if (ispub)
++            return 44 + 3 * nbyte;
++        /*
++         * Expected length: 20 for q, priv, 2 bitlen components + 24 for seed
++         * structure.
++         */
++        else
++            return 64 + 2 * nbyte;
++    } else {
++        /* Expected length: 4 for 'e' + 'n' */
++        if (ispub)
++            return 4 + nbyte;
++        else
++            /*
++             * Expected length: 4 for 'e' and 7 other components. 2
++             * components are bitlen size, 5 are bitlen/2
++             */
++            return 4 + 2 * nbyte + 5 * hnbyte;
++    }
++
++}
++
++static EVP_PKEY *do_b2i(const unsigned char **in, unsigned int length,
++                        int ispub)
++{
++    const unsigned char *p = *in;
++    unsigned int bitlen, magic;
++    int isdss;
++    if (do_blob_header(&p, length, &magic, &bitlen, &isdss, &ispub) <= 0) {
++        PEMerr(PEM_F_DO_B2I, PEM_R_KEYBLOB_HEADER_PARSE_ERROR);
++        return NULL;
++    }
++    length -= 16;
++    if (length < blob_length(bitlen, isdss, ispub)) {
++        PEMerr(PEM_F_DO_B2I, PEM_R_KEYBLOB_TOO_SHORT);
++        return NULL;
++    }
++    if (isdss)
++        return b2i_dss(&p, bitlen, ispub);
++    else
++        return b2i_rsa(&p, bitlen, ispub);
++}
++
++static EVP_PKEY *do_b2i_bio(BIO *in, int ispub)
++{
++    const unsigned char *p;
++    unsigned char hdr_buf[16], *buf = NULL;
++    unsigned int bitlen, magic, length;
++    int isdss;
++    EVP_PKEY *ret = NULL;
++    if (BIO_read(in, hdr_buf, 16) != 16) {
++        PEMerr(PEM_F_DO_B2I_BIO, PEM_R_KEYBLOB_TOO_SHORT);
++        return NULL;
++    }
++    p = hdr_buf;
++    if (do_blob_header(&p, 16, &magic, &bitlen, &isdss, &ispub) <= 0)
++        return NULL;
++
++    length = blob_length(bitlen, isdss, ispub);
++    if (length > BLOB_MAX_LENGTH) {
++        PEMerr(PEM_F_DO_B2I_BIO, PEM_R_HEADER_TOO_LONG);
++        return NULL;
++    }
++    buf = OPENSSL_malloc(length);
++    if (buf == NULL) {
++        PEMerr(PEM_F_DO_B2I_BIO, ERR_R_MALLOC_FAILURE);
++        goto err;
++    }
++    p = buf;
++    if (BIO_read(in, buf, length) != (int)length) {
++        PEMerr(PEM_F_DO_B2I_BIO, PEM_R_KEYBLOB_TOO_SHORT);
++        goto err;
++    }
++
++    if (isdss)
++        ret = b2i_dss(&p, bitlen, ispub);
++    else
++        ret = b2i_rsa(&p, bitlen, ispub);
++
++ err:
++    OPENSSL_free(buf);
++    return ret;
++}
++
++static EVP_PKEY *b2i_dss(const unsigned char **in,
++                         unsigned int bitlen, int ispub)
++{
++    const unsigned char *p = *in;
++    EVP_PKEY *ret = NULL;
++    DSA *dsa = NULL;
++    BN_CTX *ctx = NULL;
++    unsigned int nbyte;
++    BIGNUM *pbn = NULL, *qbn = NULL, *gbn = NULL, *priv_key = NULL;
++    BIGNUM *pub_key = NULL;
++
++    nbyte = (bitlen + 7) >> 3;
++
++    dsa = DSA_new();
++    ret = EVP_PKEY_new();
++    if (dsa == NULL || ret == NULL)
++        goto memerr;
++    if (!read_lebn(&p, nbyte, &pbn))
++        goto memerr;
++
++    if (!read_lebn(&p, 20, &qbn))
++        goto memerr;
++
++    if (!read_lebn(&p, nbyte, &gbn))
++        goto memerr;
++
++    if (ispub) {
++        if (!read_lebn(&p, nbyte, &pub_key))
++            goto memerr;
++    } else {
++        if (!read_lebn(&p, 20, &priv_key))
++            goto memerr;
++
++        /* Calculate public key */
++        pub_key = BN_new();
++        if (pub_key == NULL)
++            goto memerr;
++        if ((ctx = BN_CTX_new()) == NULL)
++            goto memerr;
++
++        if (!BN_mod_exp(pub_key, gbn, priv_key, pbn, ctx))
++            goto memerr;
++
++        BN_CTX_free(ctx);
++    }
++    if (!DSA_set0_pqg(dsa, pbn, qbn, gbn))
++        goto memerr;
++    pbn = qbn = gbn = NULL;
++    if (!DSA_set0_key(dsa, pub_key, priv_key))
++        goto memerr;
++
++    EVP_PKEY_set1_DSA(ret, dsa);
++    DSA_free(dsa);
++    *in = p;
++    return ret;
++
++ memerr:
++    PEMerr(PEM_F_B2I_DSS, ERR_R_MALLOC_FAILURE);
++    DSA_free(dsa);
++    BN_free(pbn);
++    BN_free(qbn);
++    BN_free(gbn);
++    BN_free(pub_key);
++    BN_free(priv_key);
++    EVP_PKEY_free(ret);
++    BN_CTX_free(ctx);
++    return NULL;
++}
++
++static EVP_PKEY *b2i_rsa(const unsigned char **in,
++                         unsigned int bitlen, int ispub)
++{
++    const unsigned char *pin = *in;
++    EVP_PKEY *ret = NULL;
++    BIGNUM *e = NULL, *n = NULL, *d = NULL;
++    BIGNUM *p = NULL, *q = NULL, *dmp1 = NULL, *dmq1 = NULL, *iqmp = NULL;
++    RSA *rsa = NULL;
++    unsigned int nbyte, hnbyte;
++    nbyte = (bitlen + 7) >> 3;
++    hnbyte = (bitlen + 15) >> 4;
++    rsa = RSA_new();
++    ret = EVP_PKEY_new();
++    if (rsa == NULL || ret == NULL)
++        goto memerr;
++    e = BN_new();
++    if (e == NULL)
++        goto memerr;
++    if (!BN_set_word(e, read_ledword(&pin)))
++        goto memerr;
++    if (!read_lebn(&pin, nbyte, &n))
++        goto memerr;
++    if (!ispub) {
++        if (!read_lebn(&pin, hnbyte, &p))
++            goto memerr;
++        if (!read_lebn(&pin, hnbyte, &q))
++            goto memerr;
++        if (!read_lebn(&pin, hnbyte, &dmp1))
++            goto memerr;
++        if (!read_lebn(&pin, hnbyte, &dmq1))
++            goto memerr;
++        if (!read_lebn(&pin, hnbyte, &iqmp))
++            goto memerr;
++        if (!read_lebn(&pin, nbyte, &d))
++            goto memerr;
++        RSA_set0_factors(rsa, p, q);
++        RSA_set0_crt_params(rsa, dmp1, dmq1, iqmp);
++    }
++    RSA_set0_key(rsa, n, e, d);
++
++    EVP_PKEY_set1_RSA(ret, rsa);
++    RSA_free(rsa);
++    *in = pin;
++    return ret;
++ memerr:
++    PEMerr(PEM_F_B2I_RSA, ERR_R_MALLOC_FAILURE);
++    BN_free(e);
++    BN_free(n);
++    BN_free(p);
++    BN_free(q);
++    BN_free(dmp1);
++    BN_free(dmq1);
++    BN_free(iqmp);
++    BN_free(d);
++    RSA_free(rsa);
++    EVP_PKEY_free(ret);
++    return NULL;
++}
++
++EVP_PKEY *b2i_PrivateKey(const unsigned char **in, long length)
++{
++    return do_b2i(in, length, 0);
++}
++
++EVP_PKEY *b2i_PublicKey(const unsigned char **in, long length)
++{
++    return do_b2i(in, length, 1);
++}
++
++EVP_PKEY *b2i_PrivateKey_bio(BIO *in)
++{
++    return do_b2i_bio(in, 0);
++}
++
++EVP_PKEY *b2i_PublicKey_bio(BIO *in)
++{
++    return do_b2i_bio(in, 1);
++}
++
++static void write_ledword(unsigned char **out, unsigned int dw)
++{
++    unsigned char *p = *out;
++    *p++ = dw & 0xff;
++    *p++ = (dw >> 8) & 0xff;
++    *p++ = (dw >> 16) & 0xff;
++    *p++ = (dw >> 24) & 0xff;
++    *out = p;
++}
++
++static void write_lebn(unsigned char **out, const BIGNUM *bn, int len)
++{
++    BN_bn2lebinpad(bn, *out, len);
++    *out += len;
++}
++
++static int check_bitlen_rsa(RSA *rsa, int ispub, unsigned int *magic);
++static int check_bitlen_dsa(DSA *dsa, int ispub, unsigned int *magic);
++
++static void write_rsa(unsigned char **out, RSA *rsa, int ispub);
++static void write_dsa(unsigned char **out, DSA *dsa, int ispub);
++
++static int do_i2b(unsigned char **out, EVP_PKEY *pk, int ispub)
++{
++    unsigned char *p;
++    unsigned int bitlen, magic = 0, keyalg;
++    int outlen, noinc = 0;
++    int pktype = EVP_PKEY_id(pk);
++    if (pktype == EVP_PKEY_DSA) {
++        bitlen = check_bitlen_dsa(EVP_PKEY_get0_DSA(pk), ispub, &magic);
++        keyalg = MS_KEYALG_DSS_SIGN;
++    } else if (pktype == EVP_PKEY_RSA) {
++        bitlen = check_bitlen_rsa(EVP_PKEY_get0_RSA(pk), ispub, &magic);
++        keyalg = MS_KEYALG_RSA_KEYX;
++    } else
++        return -1;
++    if (bitlen == 0)
++        return -1;
++    outlen = 16 + blob_length(bitlen,
++                              keyalg == MS_KEYALG_DSS_SIGN ? 1 : 0, ispub);
++    if (out == NULL)
++        return outlen;
++    if (*out)
++        p = *out;
++    else {
++        p = OPENSSL_malloc(outlen);
++        if (p == NULL)
++            return -1;
++        *out = p;
++        noinc = 1;
++    }
++    if (ispub)
++        *p++ = MS_PUBLICKEYBLOB;
++    else
++        *p++ = MS_PRIVATEKEYBLOB;
++    *p++ = 0x2;
++    *p++ = 0;
++    *p++ = 0;
++    write_ledword(&p, keyalg);
++    write_ledword(&p, magic);
++    write_ledword(&p, bitlen);
++    if (keyalg == MS_KEYALG_DSS_SIGN)
++        write_dsa(&p, EVP_PKEY_get0_DSA(pk), ispub);
++    else
++        write_rsa(&p, EVP_PKEY_get0_RSA(pk), ispub);
++    if (!noinc)
++        *out += outlen;
++    return outlen;
++}
++
++static int do_i2b_bio(BIO *out, EVP_PKEY *pk, int ispub)
++{
++    unsigned char *tmp = NULL;
++    int outlen, wrlen;
++    outlen = do_i2b(&tmp, pk, ispub);
++    if (outlen < 0)
++        return -1;
++    wrlen = BIO_write(out, tmp, outlen);
++    OPENSSL_free(tmp);
++    if (wrlen == outlen)
++        return outlen;
++    return -1;
++}
++
++static int check_bitlen_dsa(DSA *dsa, int ispub, unsigned int *pmagic)
++{
++    int bitlen;
++    const BIGNUM *p = NULL, *q = NULL, *g = NULL;
++    const BIGNUM *pub_key = NULL, *priv_key = NULL;
++
++    DSA_get0_pqg(dsa, &p, &q, &g);
++    DSA_get0_key(dsa, &pub_key, &priv_key);
++    bitlen = BN_num_bits(p);
++    if ((bitlen & 7) || (BN_num_bits(q) != 160)
++        || (BN_num_bits(g) > bitlen))
++        goto badkey;
++    if (ispub) {
++        if (BN_num_bits(pub_key) > bitlen)
++            goto badkey;
++        *pmagic = MS_DSS1MAGIC;
++    } else {
++        if (BN_num_bits(priv_key) > 160)
++            goto badkey;
++        *pmagic = MS_DSS2MAGIC;
++    }
++
++    return bitlen;
++ badkey:
++    PEMerr(PEM_F_CHECK_BITLEN_DSA, PEM_R_UNSUPPORTED_KEY_COMPONENTS);
++    return 0;
++}
++
++static int check_bitlen_rsa(RSA *rsa, int ispub, unsigned int *pmagic)
++{
++    int nbyte, hnbyte, bitlen;
++    const BIGNUM *e;
++
++    RSA_get0_key(rsa, NULL, &e, NULL);
++    if (BN_num_bits(e) > 32)
++        goto badkey;
++    bitlen = RSA_bits(rsa);
++    nbyte = RSA_size(rsa);
++    hnbyte = (bitlen + 15) >> 4;
++    if (ispub) {
++        *pmagic = MS_RSA1MAGIC;
++        return bitlen;
++    } else {
++        const BIGNUM *d, *p, *q, *iqmp, *dmp1, *dmq1;
++
++        *pmagic = MS_RSA2MAGIC;
++
++        /*
++         * For private key each component must fit within nbyte or hnbyte.
++         */
++        RSA_get0_key(rsa, NULL, NULL, &d);
++        if (BN_num_bytes(d) > nbyte)
++            goto badkey;
++        RSA_get0_factors(rsa, &p, &q);
++        RSA_get0_crt_params(rsa, &dmp1, &dmq1, &iqmp);
++        if ((BN_num_bytes(iqmp) > hnbyte)
++            || (BN_num_bytes(p) > hnbyte)
++            || (BN_num_bytes(q) > hnbyte)
++            || (BN_num_bytes(dmp1) > hnbyte)
++            || (BN_num_bytes(dmq1) > hnbyte))
++            goto badkey;
++    }
++    return bitlen;
++ badkey:
++    PEMerr(PEM_F_CHECK_BITLEN_RSA, PEM_R_UNSUPPORTED_KEY_COMPONENTS);
++    return 0;
++}
++
++static void write_rsa(unsigned char **out, RSA *rsa, int ispub)
++{
++    int nbyte, hnbyte;
++    const BIGNUM *n, *d, *e, *p, *q, *iqmp, *dmp1, *dmq1;
++
++    nbyte = RSA_size(rsa);
++    hnbyte = (RSA_bits(rsa) + 15) >> 4;
++    RSA_get0_key(rsa, &n, &e, &d);
++    write_lebn(out, e, 4);
++    write_lebn(out, n, nbyte);
++    if (ispub)
++        return;
++    RSA_get0_factors(rsa, &p, &q);
++    RSA_get0_crt_params(rsa, &dmp1, &dmq1, &iqmp);
++    write_lebn(out, p, hnbyte);
++    write_lebn(out, q, hnbyte);
++    write_lebn(out, dmp1, hnbyte);
++    write_lebn(out, dmq1, hnbyte);
++    write_lebn(out, iqmp, hnbyte);
++    write_lebn(out, d, nbyte);
++}
++
++static void write_dsa(unsigned char **out, DSA *dsa, int ispub)
++{
++    int nbyte;
++    const BIGNUM *p = NULL, *q = NULL, *g = NULL;
++    const BIGNUM *pub_key = NULL, *priv_key = NULL;
++
++    DSA_get0_pqg(dsa, &p, &q, &g);
++    DSA_get0_key(dsa, &pub_key, &priv_key);
++    nbyte = BN_num_bytes(p);
++    write_lebn(out, p, nbyte);
++    write_lebn(out, q, 20);
++    write_lebn(out, g, nbyte);
++    if (ispub)
++        write_lebn(out, pub_key, nbyte);
++    else
++        write_lebn(out, priv_key, 20);
++    /* Set "invalid" for seed structure values */
++    memset(*out, 0xff, 24);
++    *out += 24;
++    return;
++}
++
++int i2b_PrivateKey_bio(BIO *out, EVP_PKEY *pk)
++{
++    return do_i2b_bio(out, pk, 0);
++}
++
++int i2b_PublicKey_bio(BIO *out, EVP_PKEY *pk)
++{
++    return do_i2b_bio(out, pk, 1);
++}
++
++# ifndef OPENSSL_NO_RC4
++
++static int do_PVK_header(const unsigned char **in, unsigned int length,
++                         int skip_magic,
++                         unsigned int *psaltlen, unsigned int *pkeylen)
++{
++    const unsigned char *p = *in;
++    unsigned int pvk_magic, is_encrypted;
++    if (skip_magic) {
++        if (length < 20) {
++            PEMerr(PEM_F_DO_PVK_HEADER, PEM_R_PVK_TOO_SHORT);
++            return 0;
++        }
++    } else {
++        if (length < 24) {
++            PEMerr(PEM_F_DO_PVK_HEADER, PEM_R_PVK_TOO_SHORT);
++            return 0;
++        }
++        pvk_magic = read_ledword(&p);
++        if (pvk_magic != MS_PVKMAGIC) {
++            PEMerr(PEM_F_DO_PVK_HEADER, PEM_R_BAD_MAGIC_NUMBER);
++            return 0;
++        }
++    }
++    /* Skip reserved */
++    p += 4;
++    /*
++     * keytype =
++     */ read_ledword(&p);
++    is_encrypted = read_ledword(&p);
++    *psaltlen = read_ledword(&p);
++    *pkeylen = read_ledword(&p);
++
++    if (*pkeylen > PVK_MAX_KEYLEN || *psaltlen > PVK_MAX_SALTLEN)
++        return 0;
++
++    if (is_encrypted && !*psaltlen) {
++        PEMerr(PEM_F_DO_PVK_HEADER, PEM_R_INCONSISTENT_HEADER);
++        return 0;
++    }
++
++    *in = p;
++    return 1;
++}
++
++static int derive_pvk_key(unsigned char *key,
++                          const unsigned char *salt, unsigned int saltlen,
++                          const unsigned char *pass, int passlen)
++{
++    EVP_MD_CTX *mctx = EVP_MD_CTX_new();
++    int rv = 1;
++    if (mctx == NULL
++        || !EVP_DigestInit_ex(mctx, EVP_sha1(), NULL)
++        || !EVP_DigestUpdate(mctx, salt, saltlen)
++        || !EVP_DigestUpdate(mctx, pass, passlen)
++        || !EVP_DigestFinal_ex(mctx, key, NULL))
++        rv = 0;
++
++    EVP_MD_CTX_free(mctx);
++    return rv;
++}
++
++static EVP_PKEY *do_PVK_body(const unsigned char **in,
++                             unsigned int saltlen, unsigned int keylen,
++                             pem_password_cb *cb, void *u)
++{
++    EVP_PKEY *ret = NULL;
++    const unsigned char *p = *in;
++    unsigned int magic;
++    unsigned char *enctmp = NULL, *q;
++
++    EVP_CIPHER_CTX *cctx = EVP_CIPHER_CTX_new();
++    if (saltlen) {
++        char psbuf[PEM_BUFSIZE];
++        unsigned char keybuf[20];
++        int enctmplen, inlen;
++        if (cb)
++            inlen = cb(psbuf, PEM_BUFSIZE, 0, u);
++        else
++            inlen = PEM_def_callback(psbuf, PEM_BUFSIZE, 0, u);
++        if (inlen <= 0) {
++            PEMerr(PEM_F_DO_PVK_BODY, PEM_R_BAD_PASSWORD_READ);
++            goto err;
++        }
++        enctmp = OPENSSL_malloc(keylen + 8);
++        if (enctmp == NULL) {
++            PEMerr(PEM_F_DO_PVK_BODY, ERR_R_MALLOC_FAILURE);
++            goto err;
++        }
++        if (!derive_pvk_key(keybuf, p, saltlen,
++                            (unsigned char *)psbuf, inlen))
++            goto err;
++        p += saltlen;
++        /* Copy BLOBHEADER across, decrypt rest */
++        memcpy(enctmp, p, 8);
++        p += 8;
++        if (keylen < 8) {
++            PEMerr(PEM_F_DO_PVK_BODY, PEM_R_PVK_TOO_SHORT);
++            goto err;
++        }
++        inlen = keylen - 8;
++        q = enctmp + 8;
++        if (!EVP_DecryptInit_ex(cctx, EVP_rc4(), NULL, keybuf, NULL))
++            goto err;
++        if (!EVP_DecryptUpdate(cctx, q, &enctmplen, p, inlen))
++            goto err;
++        if (!EVP_DecryptFinal_ex(cctx, q + enctmplen, &enctmplen))
++            goto err;
++        magic = read_ledword((const unsigned char **)&q);
++        if (magic != MS_RSA2MAGIC && magic != MS_DSS2MAGIC) {
++            q = enctmp + 8;
++            memset(keybuf + 5, 0, 11);
++            if (!EVP_DecryptInit_ex(cctx, EVP_rc4(), NULL, keybuf, NULL))
++                goto err;
++            OPENSSL_cleanse(keybuf, 20);
++            if (!EVP_DecryptUpdate(cctx, q, &enctmplen, p, inlen))
++                goto err;
++            if (!EVP_DecryptFinal_ex(cctx, q + enctmplen, &enctmplen))
++                goto err;
++            magic = read_ledword((const unsigned char **)&q);
++            if (magic != MS_RSA2MAGIC && magic != MS_DSS2MAGIC) {
++                PEMerr(PEM_F_DO_PVK_BODY, PEM_R_BAD_DECRYPT);
++                goto err;
++            }
++        } else
++            OPENSSL_cleanse(keybuf, 20);
++        p = enctmp;
++    }
++
++    ret = b2i_PrivateKey(&p, keylen);
++ err:
++    EVP_CIPHER_CTX_free(cctx);
++    OPENSSL_free(enctmp);
++    return ret;
++}
++
++EVP_PKEY *b2i_PVK_bio(BIO *in, pem_password_cb *cb, void *u)
++{
++    unsigned char pvk_hdr[24], *buf = NULL;
++    const unsigned char *p;
++    int buflen;
++    EVP_PKEY *ret = NULL;
++    unsigned int saltlen, keylen;
++    if (BIO_read(in, pvk_hdr, 24) != 24) {
++        PEMerr(PEM_F_B2I_PVK_BIO, PEM_R_PVK_DATA_TOO_SHORT);
++        return NULL;
++    }
++    p = pvk_hdr;
++
++    if (!do_PVK_header(&p, 24, 0, &saltlen, &keylen))
++        return 0;
++    buflen = (int)keylen + saltlen;
++    buf = OPENSSL_malloc(buflen);
++    if (buf == NULL) {
++        PEMerr(PEM_F_B2I_PVK_BIO, ERR_R_MALLOC_FAILURE);
++        return 0;
++    }
++    p = buf;
++    if (BIO_read(in, buf, buflen) != buflen) {
++        PEMerr(PEM_F_B2I_PVK_BIO, PEM_R_PVK_DATA_TOO_SHORT);
++        goto err;
++    }
++    ret = do_PVK_body(&p, saltlen, keylen, cb, u);
++
++ err:
++    OPENSSL_clear_free(buf, buflen);
++    return ret;
++}
++
++static int i2b_PVK(unsigned char **out, EVP_PKEY *pk, int enclevel,
++                   pem_password_cb *cb, void *u)
++{
++    int outlen = 24, pklen;
++    unsigned char *p = NULL, *start = NULL, *salt = NULL;
++    EVP_CIPHER_CTX *cctx = NULL;
++    if (enclevel)
++        outlen += PVK_SALTLEN;
++    pklen = do_i2b(NULL, pk, 0);
++    if (pklen < 0)
++        return -1;
++    outlen += pklen;
++    if (out == NULL)
++        return outlen;
++    if (*out != NULL) {
++        p = *out;
++    } else {
++        start = p = OPENSSL_malloc(outlen);
++        if (p == NULL) {
++            PEMerr(PEM_F_I2B_PVK, ERR_R_MALLOC_FAILURE);
++            return -1;
++        }
++    }
++
++    cctx = EVP_CIPHER_CTX_new();
++    if (cctx == NULL)
++        goto error;
++
++    write_ledword(&p, MS_PVKMAGIC);
++    write_ledword(&p, 0);
++    if (EVP_PKEY_id(pk) == EVP_PKEY_DSA)
++        write_ledword(&p, MS_KEYTYPE_SIGN);
++    else
++        write_ledword(&p, MS_KEYTYPE_KEYX);
++    write_ledword(&p, enclevel ? 1 : 0);
++    write_ledword(&p, enclevel ? PVK_SALTLEN : 0);
++    write_ledword(&p, pklen);
++    if (enclevel) {
++        if (RAND_bytes(p, PVK_SALTLEN) <= 0)
++            goto error;
++        salt = p;
++        p += PVK_SALTLEN;
++    }
++    do_i2b(&p, pk, 0);
++    if (enclevel != 0) {
++        char psbuf[PEM_BUFSIZE];
++        unsigned char keybuf[20];
++        int enctmplen, inlen;
++        if (cb)
++            inlen = cb(psbuf, PEM_BUFSIZE, 1, u);
++        else
++            inlen = PEM_def_callback(psbuf, PEM_BUFSIZE, 1, u);
++        if (inlen <= 0) {
++            PEMerr(PEM_F_I2B_PVK, PEM_R_BAD_PASSWORD_READ);
++            goto error;
++        }
++        if (!derive_pvk_key(keybuf, salt, PVK_SALTLEN,
++                            (unsigned char *)psbuf, inlen))
++            goto error;
++        if (enclevel == 1)
++            memset(keybuf + 5, 0, 11);
++        p = salt + PVK_SALTLEN + 8;
++        if (!EVP_EncryptInit_ex(cctx, EVP_rc4(), NULL, keybuf, NULL))
++            goto error;
++        OPENSSL_cleanse(keybuf, 20);
++        if (!EVP_DecryptUpdate(cctx, p, &enctmplen, p, pklen - 8))
++            goto error;
++        if (!EVP_DecryptFinal_ex(cctx, p + enctmplen, &enctmplen))
++            goto error;
++    }
++
++    EVP_CIPHER_CTX_free(cctx);
++
++    if (*out == NULL)
++        *out = start;
++
++    return outlen;
++
++ error:
++    EVP_CIPHER_CTX_free(cctx);
++    if (*out == NULL)
++        OPENSSL_free(start);
++    return -1;
++}
++
++int i2b_PVK_bio(BIO *out, EVP_PKEY *pk, int enclevel,
++                pem_password_cb *cb, void *u)
++{
++    unsigned char *tmp = NULL;
++    int outlen, wrlen;
++    outlen = i2b_PVK(&tmp, pk, enclevel, cb, u);
++    if (outlen < 0)
++        return -1;
++    wrlen = BIO_write(out, tmp, outlen);
++    OPENSSL_free(tmp);
++    if (wrlen == outlen) {
++        PEMerr(PEM_F_I2B_PVK_BIO, PEM_R_BIO_WRITE_FAILURE);
++        return outlen;
++    }
++    return -1;
++}
++
++# endif
++
++#endif
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/perlasm/README b/CryptoPkg/Library/OpensslLib/openssl/crypto/perlasm/README
+new file mode 100644
+index 0000000..e90bd8e
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/perlasm/README
+@@ -0,0 +1,124 @@
++The perl scripts in this directory are my 'hack' to generate
++multiple different assembler formats via the one original script.
++
++The way to use this library is to start with adding the path to this directory
++and then include it.
++
++push(@INC,"perlasm","../../perlasm");
++require "x86asm.pl";
++
++The first thing we do is setup the file and type of assembler
++
++&asm_init($ARGV[0],$0);
++
++The first argument is the 'type'.  Currently
++'cpp', 'sol', 'a.out', 'elf' or 'win32'.
++Argument 2 is the file name.
++
++The reciprocal function is
++&asm_finish() which should be called at the end.
++
++There are 2 main 'packages'. x86ms.pl, which is the Microsoft assembler,
++and x86unix.pl which is the unix (gas) version.
++
++Functions of interest are:
++&external_label("des_SPtrans");	declare and external variable
++&LB(reg);			Low byte for a register
++&HB(reg);			High byte for a register
++&BP(off,base,index,scale)	Byte pointer addressing
++&DWP(off,base,index,scale)	Word pointer addressing
++&stack_push(num)		Basically a 'sub esp, num*4' with extra
++&stack_pop(num)			inverse of stack_push
++&function_begin(name,extra)	Start a function with pushing of
++				edi, esi, ebx and ebp.  extra is extra win32
++				external info that may be required.
++&function_begin_B(name,extra)	Same as normal function_begin but no pushing.
++&function_end(name)		Call at end of function.
++&function_end_A(name)		Standard pop and ret, for use inside functions
++&function_end_B(name)		Call at end but with poping or 'ret'.
++&swtmp(num)			Address on stack temp word.
++&wparam(num)			Parameter number num, that was push
++				in C convention.  This all works over pushes
++				and pops.
++&comment("hello there")		Put in a comment.
++&label("loop")			Refer to a label, normally a jmp target.
++&set_label("loop")		Set a label at this point.
++&data_word(word)		Put in a word of data.
++
++So how does this all hold together?  Given
++
++int calc(int len, int *data)
++	{
++	int i,j=0;
++
++	for (i=0; i$output" || die "can't open $output: $!";
++
++$flavour = "linux32" if (!$flavour or $flavour eq "void");
++
++my %GLOBALS;
++my $dotinlocallabels=($flavour=~/linux/)?1:0;
++
++################################################################
++# directives which need special treatment on different platforms
++################################################################
++my $arch = sub {
++    if ($flavour =~ /linux/)	{ ".arch\t".join(',',@_); }
++    else			{ ""; }
++};
++my $fpu = sub {
++    if ($flavour =~ /linux/)	{ ".fpu\t".join(',',@_); }
++    else			{ ""; }
++};
++my $hidden = sub {
++    if ($flavour =~ /ios/)	{ ".private_extern\t".join(',',@_); }
++    else			{ ".hidden\t".join(',',@_); }
++};
++my $comm = sub {
++    my @args = split(/,\s*/,shift);
++    my $name = @args[0];
++    my $global = \$GLOBALS{$name};
++    my $ret;
++
++    if ($flavour =~ /ios32/)	{
++	$ret = ".comm\t_$name,@args[1]\n";
++	$ret .= ".non_lazy_symbol_pointer\n";
++	$ret .= "$name:\n";
++	$ret .= ".indirect_symbol\t_$name\n";
++	$ret .= ".long\t0";
++	$name = "_$name";
++    } else			{ $ret = ".comm\t".join(',',@args); }
++
++    $$global = $name;
++    $ret;
++};
++my $globl = sub {
++    my $name = shift;
++    my $global = \$GLOBALS{$name};
++    my $ret;
++
++    SWITCH: for ($flavour) {
++	/ios/		&& do { $name = "_$name";
++				last;
++			      };
++    }
++
++    $ret = ".globl	$name" if (!$ret);
++    $$global = $name;
++    $ret;
++};
++my $global = $globl;
++my $extern = sub {
++    &$globl(@_);
++    return;	# return nothing
++};
++my $type = sub {
++    if ($flavour =~ /linux/)	{ ".type\t".join(',',@_); }
++    elsif ($flavour =~ /ios32/)	{ if (join(',',@_) =~ /(\w+),%function/) {
++					"#ifdef __thumb2__\n".
++					".thumb_func	$1\n".
++					"#endif";
++				  }
++			        }
++    else			{ ""; }
++};
++my $size = sub {
++    if ($flavour =~ /linux/)	{ ".size\t".join(',',@_); }
++    else			{ ""; }
++};
++my $inst = sub {
++    if ($flavour =~ /linux/)    { ".inst\t".join(',',@_); }
++    else                        { ".long\t".join(',',@_); }
++};
++my $asciz = sub {
++    my $line = join(",",@_);
++    if ($line =~ /^"(.*)"$/)
++    {	".byte	" . join(",",unpack("C*",$1),0) . "\n.align	2";	}
++    else
++    {	"";	}
++};
++
++sub range {
++  my ($r,$sfx,$start,$end) = @_;
++
++    join(",",map("$r$_$sfx",($start..$end)));
++}
++
++sub expand_line {
++  my $line = shift;
++  my @ret = ();
++
++    pos($line)=0;
++
++    while ($line =~ m/\G[^@\/\{\"]*/g) {
++	if ($line =~ m/\G(@|\/\/|$)/gc) {
++	    last;
++	}
++	elsif ($line =~ m/\G\{/gc) {
++	    my $saved_pos = pos($line);
++	    $line =~ s/\G([rdqv])([0-9]+)([^\-]*)\-\1([0-9]+)\3/range($1,$3,$2,$4)/e;
++	    pos($line) = $saved_pos;
++	    $line =~ m/\G[^\}]*\}/g;
++	}
++	elsif ($line =~ m/\G\"/gc) {
++	    $line =~ m/\G[^\"]*\"/g;
++	}
++    }
++
++    $line =~ s/\b(\w+)/$GLOBALS{$1} or $1/ge;
++
++    return $line;
++}
++
++while(my $line=<>) {
++
++    if ($line =~ m/^\s*(#|@|\/\/)/)	{ print $line; next; }
++
++    $line =~ s|/\*.*\*/||;	# get rid of C-style comments...
++    $line =~ s|^\s+||;		# ... and skip white spaces in beginning...
++    $line =~ s|\s+$||;		# ... and at the end
++
++    {
++	$line =~ s|[\b\.]L(\w{2,})|L$1|g;	# common denominator for Locallabel
++	$line =~ s|\bL(\w{2,})|\.L$1|g	if ($dotinlocallabels);
++    }
++
++    {
++	$line =~ s|(^[\.\w]+)\:\s*||;
++	my $label = $1;
++	if ($label) {
++	    printf "%s:",($GLOBALS{$label} or $label);
++	}
++    }
++
++    if ($line !~ m/^[#@]/) {
++	$line =~ s|^\s*(\.?)(\S+)\s*||;
++	my $c = $1; $c = "\t" if ($c eq "");
++	my $mnemonic = $2;
++	my $opcode;
++	if ($mnemonic =~ m/([^\.]+)\.([^\.]+)/) {
++	    $opcode = eval("\$$1_$2");
++	} else {
++	    $opcode = eval("\$$mnemonic");
++	}
++
++	my $arg=expand_line($line);
++
++	if (ref($opcode) eq 'CODE') {
++		$line = &$opcode($arg);
++	} elsif ($mnemonic)         {
++		$line = $c.$mnemonic;
++		$line.= "\t$arg" if ($arg ne "");
++	}
++    }
++
++    print $line if ($line);
++    print "\n";
++}
++
++close STDOUT;
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/perlasm/cbc.pl b/CryptoPkg/Library/OpensslLib/openssl/crypto/perlasm/cbc.pl
+new file mode 100644
+index 0000000..ad79b24
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/perlasm/cbc.pl
+@@ -0,0 +1,356 @@
++#! /usr/bin/env perl
++# Copyright 1995-2016 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
++# in the file LICENSE in the source distribution or at
++# https://www.openssl.org/source/license.html
++
++
++# void des_ncbc_encrypt(input, output, length, schedule, ivec, enc)
++# des_cblock (*input);
++# des_cblock (*output);
++# long length;
++# des_key_schedule schedule;
++# des_cblock (*ivec);
++# int enc;
++#
++# calls 
++# des_encrypt((DES_LONG *)tin,schedule,DES_ENCRYPT);
++#
++
++#&cbc("des_ncbc_encrypt","des_encrypt",0);
++#&cbc("BF_cbc_encrypt","BF_encrypt","BF_encrypt",
++#	1,4,5,3,5,-1);
++#&cbc("des_ncbc_encrypt","des_encrypt","des_encrypt",
++#	0,4,5,3,5,-1);
++#&cbc("des_ede3_cbc_encrypt","des_encrypt3","des_decrypt3",
++#	0,6,7,3,4,5);
++#
++# When doing a cipher that needs bigendian order,
++# for encrypt, the iv is kept in bigendian form,
++# while for decrypt, it is kept in little endian.
++sub cbc
++	{
++	local($name,$enc_func,$dec_func,$swap,$iv_off,$enc_off,$p1,$p2,$p3)=@_;
++	# name is the function name
++	# enc_func and dec_func and the functions to call for encrypt/decrypt
++	# swap is true if byte order needs to be reversed
++	# iv_off is parameter number for the iv 
++	# enc_off is parameter number for the encrypt/decrypt flag
++	# p1,p2,p3 are the offsets for parameters to be passed to the
++	# underlying calls.
++
++	&function_begin_B($name,"");
++	&comment("");
++
++	$in="esi";
++	$out="edi";
++	$count="ebp";
++
++	&push("ebp");
++	&push("ebx");
++	&push("esi");
++	&push("edi");
++
++	$data_off=4;
++	$data_off+=4 if ($p1 > 0);
++	$data_off+=4 if ($p2 > 0);
++	$data_off+=4 if ($p3 > 0);
++
++	&mov($count,	&wparam(2));	# length
++
++	&comment("getting iv ptr from parameter $iv_off");
++	&mov("ebx",	&wparam($iv_off));	# Get iv ptr
++
++	&mov($in,	&DWP(0,"ebx","",0));#	iv[0]
++	&mov($out,	&DWP(4,"ebx","",0));#	iv[1]
++
++	&push($out);
++	&push($in);
++	&push($out);	# used in decrypt for iv[1]
++	&push($in);	# used in decrypt for iv[0]
++
++	&mov("ebx",	"esp");		# This is the address of tin[2]
++
++	&mov($in,	&wparam(0));	# in
++	&mov($out,	&wparam(1));	# out
++
++	# We have loaded them all, how lets push things
++	&comment("getting encrypt flag from parameter $enc_off");
++	&mov("ecx",	&wparam($enc_off));	# Get enc flag
++	if ($p3 > 0)
++		{
++		&comment("get and push parameter $p3");
++		if ($enc_off != $p3)
++			{ &mov("eax",	&wparam($p3)); &push("eax"); }
++		else	{ &push("ecx"); }
++		}
++	if ($p2 > 0)
++		{
++		&comment("get and push parameter $p2");
++		if ($enc_off != $p2)
++			{ &mov("eax",	&wparam($p2)); &push("eax"); }
++		else	{ &push("ecx"); }
++		}
++	if ($p1 > 0)
++		{
++		&comment("get and push parameter $p1");
++		if ($enc_off != $p1)
++			{ &mov("eax",	&wparam($p1)); &push("eax"); }
++		else	{ &push("ecx"); }
++		}
++	&push("ebx");		# push data/iv
++
++	&cmp("ecx",0);
++	&jz(&label("decrypt"));
++
++	&and($count,0xfffffff8);
++	&mov("eax",	&DWP($data_off,"esp","",0));	# load iv[0]
++	&mov("ebx",	&DWP($data_off+4,"esp","",0));	# load iv[1]
++
++	&jz(&label("encrypt_finish"));
++
++	#############################################################
++
++	&set_label("encrypt_loop");
++	# encrypt start 
++	# "eax" and "ebx" hold iv (or the last cipher text)
++
++	&mov("ecx",	&DWP(0,$in,"",0));	# load first 4 bytes
++	&mov("edx",	&DWP(4,$in,"",0));	# second 4 bytes
++
++	&xor("eax",	"ecx");
++	&xor("ebx",	"edx");
++
++	&bswap("eax")	if $swap;
++	&bswap("ebx")	if $swap;
++
++	&mov(&DWP($data_off,"esp","",0),	"eax");	# put in array for call
++	&mov(&DWP($data_off+4,"esp","",0),	"ebx");	#
++
++	&call($enc_func);
++
++	&mov("eax",	&DWP($data_off,"esp","",0));
++	&mov("ebx",	&DWP($data_off+4,"esp","",0));
++
++	&bswap("eax")	if $swap;
++	&bswap("ebx")	if $swap;
++
++	&mov(&DWP(0,$out,"",0),"eax");
++	&mov(&DWP(4,$out,"",0),"ebx");
++
++	# eax and ebx are the next iv.
++
++	&add($in,	8);
++	&add($out,	8);
++
++	&sub($count,	8);
++	&jnz(&label("encrypt_loop"));
++
++###################################################################3
++	&set_label("encrypt_finish");
++	&mov($count,	&wparam(2));	# length
++	&and($count,	7);
++	&jz(&label("finish"));
++	&call(&label("PIC_point"));
++&set_label("PIC_point");
++	&blindpop("edx");
++	&lea("ecx",&DWP(&label("cbc_enc_jmp_table")."-".&label("PIC_point"),"edx"));
++	&mov($count,&DWP(0,"ecx",$count,4));
++	&add($count,"edx");
++	&xor("ecx","ecx");
++	&xor("edx","edx");
++	#&mov($count,&DWP(&label("cbc_enc_jmp_table"),"",$count,4));
++	&jmp_ptr($count);
++
++&set_label("ej7");
++	&movb(&HB("edx"),	&BP(6,$in,"",0));
++	&shl("edx",8);
++&set_label("ej6");
++	&movb(&HB("edx"),	&BP(5,$in,"",0));
++&set_label("ej5");
++	&movb(&LB("edx"),	&BP(4,$in,"",0));
++&set_label("ej4");
++	&mov("ecx",		&DWP(0,$in,"",0));
++	&jmp(&label("ejend"));
++&set_label("ej3");
++	&movb(&HB("ecx"),	&BP(2,$in,"",0));
++	&shl("ecx",8);
++&set_label("ej2");
++	&movb(&HB("ecx"),	&BP(1,$in,"",0));
++&set_label("ej1");
++	&movb(&LB("ecx"),	&BP(0,$in,"",0));
++&set_label("ejend");
++
++	&xor("eax",	"ecx");
++	&xor("ebx",	"edx");
++
++	&bswap("eax")	if $swap;
++	&bswap("ebx")	if $swap;
++
++	&mov(&DWP($data_off,"esp","",0),	"eax");	# put in array for call
++	&mov(&DWP($data_off+4,"esp","",0),	"ebx");	#
++
++	&call($enc_func);
++
++	&mov("eax",	&DWP($data_off,"esp","",0));
++	&mov("ebx",	&DWP($data_off+4,"esp","",0));
++
++	&bswap("eax")	if $swap;
++	&bswap("ebx")	if $swap;
++
++	&mov(&DWP(0,$out,"",0),"eax");
++	&mov(&DWP(4,$out,"",0),"ebx");
++
++	&jmp(&label("finish"));
++
++	#############################################################
++	#############################################################
++	&set_label("decrypt",1);
++	# decrypt start 
++	&and($count,0xfffffff8);
++	# The next 2 instructions are only for if the jz is taken
++	&mov("eax",	&DWP($data_off+8,"esp","",0));	# get iv[0]
++	&mov("ebx",	&DWP($data_off+12,"esp","",0));	# get iv[1]
++	&jz(&label("decrypt_finish"));
++
++	&set_label("decrypt_loop");
++	&mov("eax",	&DWP(0,$in,"",0));	# load first 4 bytes
++	&mov("ebx",	&DWP(4,$in,"",0));	# second 4 bytes
++
++	&bswap("eax")	if $swap;
++	&bswap("ebx")	if $swap;
++
++	&mov(&DWP($data_off,"esp","",0),	"eax");	# put back
++	&mov(&DWP($data_off+4,"esp","",0),	"ebx");	#
++
++	&call($dec_func);
++
++	&mov("eax",	&DWP($data_off,"esp","",0));	# get return
++	&mov("ebx",	&DWP($data_off+4,"esp","",0));	#
++
++	&bswap("eax")	if $swap;
++	&bswap("ebx")	if $swap;
++
++	&mov("ecx",	&DWP($data_off+8,"esp","",0));	# get iv[0]
++	&mov("edx",	&DWP($data_off+12,"esp","",0));	# get iv[1]
++
++	&xor("ecx",	"eax");
++	&xor("edx",	"ebx");
++
++	&mov("eax",	&DWP(0,$in,"",0));	# get old cipher text,
++	&mov("ebx",	&DWP(4,$in,"",0));	# next iv actually
++
++	&mov(&DWP(0,$out,"",0),"ecx");
++	&mov(&DWP(4,$out,"",0),"edx");
++
++	&mov(&DWP($data_off+8,"esp","",0),	"eax");	# save iv
++	&mov(&DWP($data_off+12,"esp","",0),	"ebx");	#
++
++	&add($in,	8);
++	&add($out,	8);
++
++	&sub($count,	8);
++	&jnz(&label("decrypt_loop"));
++############################ ENDIT #######################3
++	&set_label("decrypt_finish");
++	&mov($count,	&wparam(2));	# length
++	&and($count,	7);
++	&jz(&label("finish"));
++
++	&mov("eax",	&DWP(0,$in,"",0));	# load first 4 bytes
++	&mov("ebx",	&DWP(4,$in,"",0));	# second 4 bytes
++
++	&bswap("eax")	if $swap;
++	&bswap("ebx")	if $swap;
++
++	&mov(&DWP($data_off,"esp","",0),	"eax");	# put back
++	&mov(&DWP($data_off+4,"esp","",0),	"ebx");	#
++
++	&call($dec_func);
++
++	&mov("eax",	&DWP($data_off,"esp","",0));	# get return
++	&mov("ebx",	&DWP($data_off+4,"esp","",0));	#
++
++	&bswap("eax")	if $swap;
++	&bswap("ebx")	if $swap;
++
++	&mov("ecx",	&DWP($data_off+8,"esp","",0));	# get iv[0]
++	&mov("edx",	&DWP($data_off+12,"esp","",0));	# get iv[1]
++
++	&xor("ecx",	"eax");
++	&xor("edx",	"ebx");
++
++	# this is for when we exit
++	&mov("eax",	&DWP(0,$in,"",0));	# get old cipher text,
++	&mov("ebx",	&DWP(4,$in,"",0));	# next iv actually
++
++&set_label("dj7");
++	&rotr("edx",	16);
++	&movb(&BP(6,$out,"",0),	&LB("edx"));
++	&shr("edx",16);
++&set_label("dj6");
++	&movb(&BP(5,$out,"",0),	&HB("edx"));
++&set_label("dj5");
++	&movb(&BP(4,$out,"",0),	&LB("edx"));
++&set_label("dj4");
++	&mov(&DWP(0,$out,"",0),	"ecx");
++	&jmp(&label("djend"));
++&set_label("dj3");
++	&rotr("ecx",	16);
++	&movb(&BP(2,$out,"",0),	&LB("ecx"));
++	&shl("ecx",16);
++&set_label("dj2");
++	&movb(&BP(1,$in,"",0),	&HB("ecx"));
++&set_label("dj1");
++	&movb(&BP(0,$in,"",0),	&LB("ecx"));
++&set_label("djend");
++
++	# final iv is still in eax:ebx
++	&jmp(&label("finish"));
++
++
++############################ FINISH #######################3
++	&set_label("finish",1);
++	&mov("ecx",	&wparam($iv_off));	# Get iv ptr
++
++	#################################################
++	$total=16+4;
++	$total+=4 if ($p1 > 0);
++	$total+=4 if ($p2 > 0);
++	$total+=4 if ($p3 > 0);
++	&add("esp",$total);
++
++	&mov(&DWP(0,"ecx","",0),	"eax");	# save iv
++	&mov(&DWP(4,"ecx","",0),	"ebx");	# save iv
++
++	&function_end_A($name);
++
++	&align(64);
++	&set_label("cbc_enc_jmp_table");
++	&data_word("0");
++	&data_word(&label("ej1")."-".&label("PIC_point"));
++	&data_word(&label("ej2")."-".&label("PIC_point"));
++	&data_word(&label("ej3")."-".&label("PIC_point"));
++	&data_word(&label("ej4")."-".&label("PIC_point"));
++	&data_word(&label("ej5")."-".&label("PIC_point"));
++	&data_word(&label("ej6")."-".&label("PIC_point"));
++	&data_word(&label("ej7")."-".&label("PIC_point"));
++	# not used
++	#&set_label("cbc_dec_jmp_table",1);
++	#&data_word("0");
++	#&data_word(&label("dj1")."-".&label("PIC_point"));
++	#&data_word(&label("dj2")."-".&label("PIC_point"));
++	#&data_word(&label("dj3")."-".&label("PIC_point"));
++	#&data_word(&label("dj4")."-".&label("PIC_point"));
++	#&data_word(&label("dj5")."-".&label("PIC_point"));
++	#&data_word(&label("dj6")."-".&label("PIC_point"));
++	#&data_word(&label("dj7")."-".&label("PIC_point"));
++	&align(64);
++
++	&function_end_B($name);
++	
++	}
++
++1;
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/perlasm/ppc-xlate.pl b/CryptoPkg/Library/OpensslLib/openssl/crypto/perlasm/ppc-xlate.pl
+new file mode 100755
+index 0000000..2d46e24
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/perlasm/ppc-xlate.pl
+@@ -0,0 +1,265 @@
++#! /usr/bin/env perl
++# Copyright 2006-2016 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
++# in the file LICENSE in the source distribution or at
++# https://www.openssl.org/source/license.html
++
++my $flavour = shift;
++my $output = shift;
++open STDOUT,">$output" || die "can't open $output: $!";
++
++my %GLOBALS;
++my $dotinlocallabels=($flavour=~/linux/)?1:0;
++
++################################################################
++# directives which need special treatment on different platforms
++################################################################
++my $globl = sub {
++    my $junk = shift;
++    my $name = shift;
++    my $global = \$GLOBALS{$name};
++    my $ret;
++
++    $name =~ s|^[\.\_]||;
++ 
++    SWITCH: for ($flavour) {
++	/aix/		&& do { $name = ".$name";
++				last;
++			      };
++	/osx/		&& do { $name = "_$name";
++				last;
++			      };
++	/linux.*(32|64le)/
++			&& do {	$ret .= ".globl	$name\n";
++				$ret .= ".type	$name,\@function";
++				last;
++			      };
++	/linux.*64/	&& do {	$ret .= ".globl	$name\n";
++				$ret .= ".type	$name,\@function\n";
++				$ret .= ".section	\".opd\",\"aw\"\n";
++				$ret .= ".align	3\n";
++				$ret .= "$name:\n";
++				$ret .= ".quad	.$name,.TOC.\@tocbase,0\n";
++				$ret .= ".previous\n";
++
++				$name = ".$name";
++				last;
++			      };
++    }
++
++    $ret = ".globl	$name" if (!$ret);
++    $$global = $name;
++    $ret;
++};
++my $text = sub {
++    my $ret = ($flavour =~ /aix/) ? ".csect\t.text[PR],7" : ".text";
++    $ret = ".abiversion	2\n".$ret	if ($flavour =~ /linux.*64le/);
++    $ret;
++};
++my $machine = sub {
++    my $junk = shift;
++    my $arch = shift;
++    if ($flavour =~ /osx/)
++    {	$arch =~ s/\"//g;
++	$arch = ($flavour=~/64/) ? "ppc970-64" : "ppc970" if ($arch eq "any");
++    }
++    ".machine	$arch";
++};
++my $size = sub {
++    if ($flavour =~ /linux/)
++    {	shift;
++	my $name = shift; $name =~ s|^[\.\_]||;
++	my $ret  = ".size	$name,.-".($flavour=~/64$/?".":"").$name;
++	$ret .= "\n.size	.$name,.-.$name" if ($flavour=~/64$/);
++	$ret;
++    }
++    else
++    {	"";	}
++};
++my $asciz = sub {
++    shift;
++    my $line = join(",",@_);
++    if ($line =~ /^"(.*)"$/)
++    {	".byte	" . join(",",unpack("C*",$1),0) . "\n.align	2";	}
++    else
++    {	"";	}
++};
++my $quad = sub {
++    shift;
++    my @ret;
++    my ($hi,$lo);
++    for (@_) {
++	if (/^0x([0-9a-f]*?)([0-9a-f]{1,8})$/io)
++	{  $hi=$1?"0x$1":"0"; $lo="0x$2";  }
++	elsif (/^([0-9]+)$/o)
++	{  $hi=$1>>32; $lo=$1&0xffffffff;  } # error-prone with 32-bit perl
++	else
++	{  $hi=undef; $lo=$_; }
++
++	if (defined($hi))
++	{  push(@ret,$flavour=~/le$/o?".long\t$lo,$hi":".long\t$hi,$lo");  }
++	else
++	{  push(@ret,".quad	$lo");  }
++    }
++    join("\n",@ret);
++};
++
++################################################################
++# simplified mnemonics not handled by at least one assembler
++################################################################
++my $cmplw = sub {
++    my $f = shift;
++    my $cr = 0; $cr = shift if ($#_>1);
++    # Some out-of-date 32-bit GNU assembler just can't handle cmplw...
++    ($flavour =~ /linux.*32/) ?
++	"	.long	".sprintf "0x%x",31<<26|$cr<<23|$_[0]<<16|$_[1]<<11|64 :
++	"	cmplw	".join(',',$cr,@_);
++};
++my $bdnz = sub {
++    my $f = shift;
++    my $bo = $f=~/[\+\-]/ ? 16+9 : 16;	# optional "to be taken" hint
++    "	bc	$bo,0,".shift;
++} if ($flavour!~/linux/);
++my $bltlr = sub {
++    my $f = shift;
++    my $bo = $f=~/\-/ ? 12+2 : 12;	# optional "not to be taken" hint
++    ($flavour =~ /linux/) ?		# GNU as doesn't allow most recent hints
++	"	.long	".sprintf "0x%x",19<<26|$bo<<21|16<<1 :
++	"	bclr	$bo,0";
++};
++my $bnelr = sub {
++    my $f = shift;
++    my $bo = $f=~/\-/ ? 4+2 : 4;	# optional "not to be taken" hint
++    ($flavour =~ /linux/) ?		# GNU as doesn't allow most recent hints
++	"	.long	".sprintf "0x%x",19<<26|$bo<<21|2<<16|16<<1 :
++	"	bclr	$bo,2";
++};
++my $beqlr = sub {
++    my $f = shift;
++    my $bo = $f=~/-/ ? 12+2 : 12;	# optional "not to be taken" hint
++    ($flavour =~ /linux/) ?		# GNU as doesn't allow most recent hints
++	"	.long	".sprintf "0x%X",19<<26|$bo<<21|2<<16|16<<1 :
++	"	bclr	$bo,2";
++};
++# GNU assembler can't handle extrdi rA,rS,16,48, or when sum of last two
++# arguments is 64, with "operand out of range" error.
++my $extrdi = sub {
++    my ($f,$ra,$rs,$n,$b) = @_;
++    $b = ($b+$n)&63; $n = 64-$n;
++    "	rldicl	$ra,$rs,$b,$n";
++};
++my $vmr = sub {
++    my ($f,$vx,$vy) = @_;
++    "	vor	$vx,$vy,$vy";
++};
++
++# Some ABIs specify vrsave, special-purpose register #256, as reserved
++# for system use.
++my $no_vrsave = ($flavour =~ /aix|linux64le/);
++my $mtspr = sub {
++    my ($f,$idx,$ra) = @_;
++    if ($idx == 256 && $no_vrsave) {
++	"	or	$ra,$ra,$ra";
++    } else {
++	"	mtspr	$idx,$ra";
++    }
++};
++my $mfspr = sub {
++    my ($f,$rd,$idx) = @_;
++    if ($idx == 256 && $no_vrsave) {
++	"	li	$rd,-1";
++    } else {
++	"	mfspr	$rd,$idx";
++    }
++};
++
++# PowerISA 2.06 stuff
++sub vsxmem_op {
++    my ($f, $vrt, $ra, $rb, $op) = @_;
++    "	.long	".sprintf "0x%X",(31<<26)|($vrt<<21)|($ra<<16)|($rb<<11)|($op*2+1);
++}
++# made-up unaligned memory reference AltiVec/VMX instructions
++my $lvx_u	= sub {	vsxmem_op(@_, 844); };	# lxvd2x
++my $stvx_u	= sub {	vsxmem_op(@_, 972); };	# stxvd2x
++my $lvdx_u	= sub {	vsxmem_op(@_, 588); };	# lxsdx
++my $stvdx_u	= sub {	vsxmem_op(@_, 716); };	# stxsdx
++my $lvx_4w	= sub { vsxmem_op(@_, 780); };	# lxvw4x
++my $stvx_4w	= sub { vsxmem_op(@_, 908); };	# stxvw4x
++
++# PowerISA 2.07 stuff
++sub vcrypto_op {
++    my ($f, $vrt, $vra, $vrb, $op) = @_;
++    "	.long	".sprintf "0x%X",(4<<26)|($vrt<<21)|($vra<<16)|($vrb<<11)|$op;
++}
++my $vcipher	= sub { vcrypto_op(@_, 1288); };
++my $vcipherlast	= sub { vcrypto_op(@_, 1289); };
++my $vncipher	= sub { vcrypto_op(@_, 1352); };
++my $vncipherlast= sub { vcrypto_op(@_, 1353); };
++my $vsbox	= sub { vcrypto_op(@_, 0, 1480); };
++my $vshasigmad	= sub { my ($st,$six)=splice(@_,-2); vcrypto_op(@_, $st<<4|$six, 1730); };
++my $vshasigmaw	= sub { my ($st,$six)=splice(@_,-2); vcrypto_op(@_, $st<<4|$six, 1666); };
++my $vpmsumb	= sub { vcrypto_op(@_, 1032); };
++my $vpmsumd	= sub { vcrypto_op(@_, 1224); };
++my $vpmsubh	= sub { vcrypto_op(@_, 1096); };
++my $vpmsumw	= sub { vcrypto_op(@_, 1160); };
++my $vaddudm	= sub { vcrypto_op(@_, 192);  };
++
++my $mtsle	= sub {
++    my ($f, $arg) = @_;
++    "	.long	".sprintf "0x%X",(31<<26)|($arg<<21)|(147*2);
++};
++
++# PowerISA 3.0 stuff
++my $maddhdu = sub {
++    my ($f, $rt, $ra, $rb, $rc) = @_;
++    "	.long	".sprintf "0x%X",(4<<26)|($rt<<21)|($ra<<16)|($rb<<11)|($rc<<6)|49;
++};
++my $maddld = sub {
++    my ($f, $rt, $ra, $rb, $rc) = @_;
++    "	.long	".sprintf "0x%X",(4<<26)|($rt<<21)|($ra<<16)|($rb<<11)|($rc<<6)|51;
++};
++
++my $darn = sub {
++    my ($f, $rt, $l) = @_;
++    "	.long	".sprintf "0x%X",(31<<26)|($rt<<21)|($l<<16)|(755<<1);
++};
++
++while($line=<>) {
++
++    $line =~ s|[#!;].*$||;	# get rid of asm-style comments...
++    $line =~ s|/\*.*\*/||;	# ... and C-style comments...
++    $line =~ s|^\s+||;		# ... and skip white spaces in beginning...
++    $line =~ s|\s+$||;		# ... and at the end
++
++    {
++	$line =~ s|\b\.L(\w+)|L$1|g;	# common denominator for Locallabel
++	$line =~ s|\bL(\w+)|\.L$1|g	if ($dotinlocallabels);
++    }
++
++    {
++	$line =~ s|(^[\.\w]+)\:\s*||;
++	my $label = $1;
++	if ($label) {
++	    printf "%s:",($GLOBALS{$label} or $label);
++	    printf "\n.localentry\t$GLOBALS{$label},0"	if ($GLOBALS{$label} && $flavour =~ /linux.*64le/);
++	}
++    }
++
++    {
++	$line =~ s|^\s*(\.?)(\w+)([\.\+\-]?)\s*||;
++	my $c = $1; $c = "\t" if ($c eq "");
++	my $mnemonic = $2;
++	my $f = $3;
++	my $opcode = eval("\$$mnemonic");
++	$line =~ s/\b(c?[rf]|v|vs)([0-9]+)\b/$2/g if ($c ne "." and $flavour !~ /osx/);
++	if (ref($opcode) eq 'CODE') { $line = &$opcode($f,split(',',$line)); }
++	elsif ($mnemonic)           { $line = $c.$mnemonic.$f."\t".$line; }
++    }
++
++    print $line if ($line);
++    print "\n";
++}
++
++close STDOUT;
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/perlasm/sparcv9_modes.pl b/CryptoPkg/Library/OpensslLib/openssl/crypto/perlasm/sparcv9_modes.pl
+new file mode 100644
+index 0000000..bfdada8
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/perlasm/sparcv9_modes.pl
+@@ -0,0 +1,1702 @@
++#! /usr/bin/env perl
++# Copyright 2012-2016 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
++# in the file LICENSE in the source distribution or at
++# https://www.openssl.org/source/license.html
++
++
++# Specific modes implementations for SPARC Architecture 2011. There
++# is T4 dependency though, an ASI value that is not specified in the
++# Architecture Manual. But as SPARC universe is rather monocultural,
++# we imply that processor capable of executing crypto instructions
++# can handle the ASI in question as well. This means that we ought to
++# keep eyes open when new processors emerge...
++#
++# As for above mentioned ASI. It's so called "block initializing
++# store" which cancels "read" in "read-update-write" on cache lines.
++# This is "cooperative" optimization, as it reduces overall pressure
++# on memory interface. Benefits can't be observed/quantified with
++# usual benchmarks, on the contrary you can notice that single-thread
++# performance for parallelizable modes is ~1.5% worse for largest
++# block sizes [though few percent better for not so long ones]. All
++# this based on suggestions from David Miller.
++
++$::bias="STACK_BIAS";
++$::frame="STACK_FRAME";
++$::size_t_cc="SIZE_T_CC";
++
++sub asm_init {		# to be called with @ARGV as argument
++    for (@_)		{ $::abibits=64 if (/\-m64/ || /\-xarch\=v9/); }
++    if ($::abibits==64)	{ $::bias=2047; $::frame=192; $::size_t_cc="%xcc"; }
++    else		{ $::bias=0;    $::frame=112; $::size_t_cc="%icc"; }
++}
++
++# unified interface
++my ($inp,$out,$len,$key,$ivec)=map("%i$_",(0..5));
++# local variables
++my ($ileft,$iright,$ooff,$omask,$ivoff,$blk_init)=map("%l$_",(0..7));
++
++sub alg_cbc_encrypt_implement {
++my ($alg,$bits) = @_;
++
++$::code.=<<___;
++.globl	${alg}${bits}_t4_cbc_encrypt
++.align	32
++${alg}${bits}_t4_cbc_encrypt:
++	save		%sp, -$::frame, %sp
++	cmp		$len, 0
++	be,pn		$::size_t_cc, .L${bits}_cbc_enc_abort
++	srln		$len, 0, $len		! needed on v8+, "nop" on v9
++	sub		$inp, $out, $blk_init	! $inp!=$out
++___
++$::code.=<<___ if (!$::evp);
++	andcc		$ivec, 7, $ivoff
++	alignaddr	$ivec, %g0, $ivec
++
++	ldd		[$ivec + 0], %f0	! load ivec
++	bz,pt		%icc, 1f
++	ldd		[$ivec + 8], %f2
++	ldd		[$ivec + 16], %f4
++	faligndata	%f0, %f2, %f0
++	faligndata	%f2, %f4, %f2
++1:
++___
++$::code.=<<___ if ($::evp);
++	ld		[$ivec + 0], %f0
++	ld		[$ivec + 4], %f1
++	ld		[$ivec + 8], %f2
++	ld		[$ivec + 12], %f3
++___
++$::code.=<<___;
++	prefetch	[$inp], 20
++	prefetch	[$inp + 63], 20
++	call		_${alg}${bits}_load_enckey
++	and		$inp, 7, $ileft
++	andn		$inp, 7, $inp
++	sll		$ileft, 3, $ileft
++	mov		64, $iright
++	mov		0xff, $omask
++	sub		$iright, $ileft, $iright
++	and		$out, 7, $ooff
++	cmp		$len, 127
++	movrnz		$ooff, 0, $blk_init		! if (	$out&7 ||
++	movleu		$::size_t_cc, 0, $blk_init	!	$len<128 ||
++	brnz,pn		$blk_init, .L${bits}cbc_enc_blk	!	$inp==$out)
++	srl		$omask, $ooff, $omask
++
++	alignaddrl	$out, %g0, $out
++	srlx		$len, 4, $len
++	prefetch	[$out], 22
++
++.L${bits}_cbc_enc_loop:
++	ldx		[$inp + 0], %o0
++	brz,pt		$ileft, 4f
++	ldx		[$inp + 8], %o1
++
++	ldx		[$inp + 16], %o2
++	sllx		%o0, $ileft, %o0
++	srlx		%o1, $iright, %g1
++	sllx		%o1, $ileft, %o1
++	or		%g1, %o0, %o0
++	srlx		%o2, $iright, %o2
++	or		%o2, %o1, %o1
++4:
++	xor		%g4, %o0, %o0		! ^= rk[0]
++	xor		%g5, %o1, %o1
++	movxtod		%o0, %f12
++	movxtod		%o1, %f14
++
++	fxor		%f12, %f0, %f0		! ^= ivec
++	fxor		%f14, %f2, %f2
++	prefetch	[$out + 63], 22
++	prefetch	[$inp + 16+63], 20
++	call		_${alg}${bits}_encrypt_1x
++	add		$inp, 16, $inp
++
++	brnz,pn		$ooff, 2f
++	sub		$len, 1, $len
++		
++	std		%f0, [$out + 0]
++	std		%f2, [$out + 8]
++	brnz,pt		$len, .L${bits}_cbc_enc_loop
++	add		$out, 16, $out
++___
++$::code.=<<___ if ($::evp);
++	st		%f0, [$ivec + 0]
++	st		%f1, [$ivec + 4]
++	st		%f2, [$ivec + 8]
++	st		%f3, [$ivec + 12]
++___
++$::code.=<<___ if (!$::evp);
++	brnz,pn		$ivoff, 3f
++	nop
++
++	std		%f0, [$ivec + 0]	! write out ivec
++	std		%f2, [$ivec + 8]
++___
++$::code.=<<___;
++.L${bits}_cbc_enc_abort:
++	ret
++	restore
++
++.align	16
++2:	ldxa		[$inp]0x82, %o0		! avoid read-after-write hazard
++						! and ~3x deterioration
++						! in inp==out case
++	faligndata	%f0, %f0, %f4		! handle unaligned output
++	faligndata	%f0, %f2, %f6
++	faligndata	%f2, %f2, %f8
++
++	stda		%f4, [$out + $omask]0xc0	! partial store
++	std		%f6, [$out + 8]
++	add		$out, 16, $out
++	orn		%g0, $omask, $omask
++	stda		%f8, [$out + $omask]0xc0	! partial store
++
++	brnz,pt		$len, .L${bits}_cbc_enc_loop+4
++	orn		%g0, $omask, $omask
++___
++$::code.=<<___ if ($::evp);
++	st		%f0, [$ivec + 0]
++	st		%f1, [$ivec + 4]
++	st		%f2, [$ivec + 8]
++	st		%f3, [$ivec + 12]
++___
++$::code.=<<___ if (!$::evp);
++	brnz,pn		$ivoff, 3f
++	nop
++
++	std		%f0, [$ivec + 0]	! write out ivec
++	std		%f2, [$ivec + 8]
++	ret
++	restore
++
++.align	16
++3:	alignaddrl	$ivec, $ivoff, %g0	! handle unaligned ivec
++	mov		0xff, $omask
++	srl		$omask, $ivoff, $omask
++	faligndata	%f0, %f0, %f4
++	faligndata	%f0, %f2, %f6
++	faligndata	%f2, %f2, %f8
++	stda		%f4, [$ivec + $omask]0xc0
++	std		%f6, [$ivec + 8]
++	add		$ivec, 16, $ivec
++	orn		%g0, $omask, $omask
++	stda		%f8, [$ivec + $omask]0xc0
++___
++$::code.=<<___;
++	ret
++	restore
++
++!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
++.align	32
++.L${bits}cbc_enc_blk:
++	add	$out, $len, $blk_init
++	and	$blk_init, 63, $blk_init	! tail
++	sub	$len, $blk_init, $len
++	add	$blk_init, 15, $blk_init	! round up to 16n
++	srlx	$len, 4, $len
++	srl	$blk_init, 4, $blk_init
++
++.L${bits}_cbc_enc_blk_loop:
++	ldx		[$inp + 0], %o0
++	brz,pt		$ileft, 5f
++	ldx		[$inp + 8], %o1
++
++	ldx		[$inp + 16], %o2
++	sllx		%o0, $ileft, %o0
++	srlx		%o1, $iright, %g1
++	sllx		%o1, $ileft, %o1
++	or		%g1, %o0, %o0
++	srlx		%o2, $iright, %o2
++	or		%o2, %o1, %o1
++5:
++	xor		%g4, %o0, %o0		! ^= rk[0]
++	xor		%g5, %o1, %o1
++	movxtod		%o0, %f12
++	movxtod		%o1, %f14
++
++	fxor		%f12, %f0, %f0		! ^= ivec
++	fxor		%f14, %f2, %f2
++	prefetch	[$inp + 16+63], 20
++	call		_${alg}${bits}_encrypt_1x
++	add		$inp, 16, $inp
++	sub		$len, 1, $len
++		
++	stda		%f0, [$out]0xe2		! ASI_BLK_INIT, T4-specific
++	add		$out, 8, $out
++	stda		%f2, [$out]0xe2		! ASI_BLK_INIT, T4-specific
++	brnz,pt		$len, .L${bits}_cbc_enc_blk_loop
++	add		$out, 8, $out
++
++	membar		#StoreLoad|#StoreStore
++	brnz,pt		$blk_init, .L${bits}_cbc_enc_loop
++	mov		$blk_init, $len
++___
++$::code.=<<___ if ($::evp);
++	st		%f0, [$ivec + 0]
++	st		%f1, [$ivec + 4]
++	st		%f2, [$ivec + 8]
++	st		%f3, [$ivec + 12]
++___
++$::code.=<<___ if (!$::evp);
++	brnz,pn		$ivoff, 3b
++	nop
++
++	std		%f0, [$ivec + 0]	! write out ivec
++	std		%f2, [$ivec + 8]
++___
++$::code.=<<___;
++	ret
++	restore
++.type	${alg}${bits}_t4_cbc_encrypt,#function
++.size	${alg}${bits}_t4_cbc_encrypt,.-${alg}${bits}_t4_cbc_encrypt
++___
++}
++
++sub alg_cbc_decrypt_implement {
++my ($alg,$bits) = @_;
++
++$::code.=<<___;
++.globl	${alg}${bits}_t4_cbc_decrypt
++.align	32
++${alg}${bits}_t4_cbc_decrypt:
++	save		%sp, -$::frame, %sp
++	cmp		$len, 0
++	be,pn		$::size_t_cc, .L${bits}_cbc_dec_abort
++	srln		$len, 0, $len		! needed on v8+, "nop" on v9
++	sub		$inp, $out, $blk_init	! $inp!=$out
++___
++$::code.=<<___ if (!$::evp);
++	andcc		$ivec, 7, $ivoff
++	alignaddr	$ivec, %g0, $ivec
++
++	ldd		[$ivec + 0], %f12	! load ivec
++	bz,pt		%icc, 1f
++	ldd		[$ivec + 8], %f14
++	ldd		[$ivec + 16], %f0
++	faligndata	%f12, %f14, %f12
++	faligndata	%f14, %f0, %f14
++1:
++___
++$::code.=<<___ if ($::evp);
++	ld		[$ivec + 0], %f12	! load ivec
++	ld		[$ivec + 4], %f13
++	ld		[$ivec + 8], %f14
++	ld		[$ivec + 12], %f15
++___
++$::code.=<<___;
++	prefetch	[$inp], 20
++	prefetch	[$inp + 63], 20
++	call		_${alg}${bits}_load_deckey
++	and		$inp, 7, $ileft
++	andn		$inp, 7, $inp
++	sll		$ileft, 3, $ileft
++	mov		64, $iright
++	mov		0xff, $omask
++	sub		$iright, $ileft, $iright
++	and		$out, 7, $ooff
++	cmp		$len, 255
++	movrnz		$ooff, 0, $blk_init		! if (	$out&7 ||
++	movleu		$::size_t_cc, 0, $blk_init	!	$len<256 ||
++	brnz,pn		$blk_init, .L${bits}cbc_dec_blk	!	$inp==$out)
++	srl		$omask, $ooff, $omask
++
++	andcc		$len, 16, %g0		! is number of blocks even?
++	srlx		$len, 4, $len
++	alignaddrl	$out, %g0, $out
++	bz		%icc, .L${bits}_cbc_dec_loop2x
++	prefetch	[$out], 22
++.L${bits}_cbc_dec_loop:
++	ldx		[$inp + 0], %o0
++	brz,pt		$ileft, 4f
++	ldx		[$inp + 8], %o1
++
++	ldx		[$inp + 16], %o2
++	sllx		%o0, $ileft, %o0
++	srlx		%o1, $iright, %g1
++	sllx		%o1, $ileft, %o1
++	or		%g1, %o0, %o0
++	srlx		%o2, $iright, %o2
++	or		%o2, %o1, %o1
++4:
++	xor		%g4, %o0, %o2		! ^= rk[0]
++	xor		%g5, %o1, %o3
++	movxtod		%o2, %f0
++	movxtod		%o3, %f2
++
++	prefetch	[$out + 63], 22
++	prefetch	[$inp + 16+63], 20
++	call		_${alg}${bits}_decrypt_1x
++	add		$inp, 16, $inp
++
++	fxor		%f12, %f0, %f0		! ^= ivec
++	fxor		%f14, %f2, %f2
++	movxtod		%o0, %f12
++	movxtod		%o1, %f14
++
++	brnz,pn		$ooff, 2f
++	sub		$len, 1, $len
++		
++	std		%f0, [$out + 0]
++	std		%f2, [$out + 8]
++	brnz,pt		$len, .L${bits}_cbc_dec_loop2x
++	add		$out, 16, $out
++___
++$::code.=<<___ if ($::evp);
++	st		%f12, [$ivec + 0]
++	st		%f13, [$ivec + 4]
++	st		%f14, [$ivec + 8]
++	st		%f15, [$ivec + 12]
++___
++$::code.=<<___ if (!$::evp);
++	brnz,pn		$ivoff, .L${bits}_cbc_dec_unaligned_ivec
++	nop
++
++	std		%f12, [$ivec + 0]	! write out ivec
++	std		%f14, [$ivec + 8]
++___
++$::code.=<<___;
++.L${bits}_cbc_dec_abort:
++	ret
++	restore
++
++.align	16
++2:	ldxa		[$inp]0x82, %o0		! avoid read-after-write hazard
++						! and ~3x deterioration
++						! in inp==out case
++	faligndata	%f0, %f0, %f4		! handle unaligned output
++	faligndata	%f0, %f2, %f6
++	faligndata	%f2, %f2, %f8
++
++	stda		%f4, [$out + $omask]0xc0	! partial store
++	std		%f6, [$out + 8]
++	add		$out, 16, $out
++	orn		%g0, $omask, $omask
++	stda		%f8, [$out + $omask]0xc0	! partial store
++
++	brnz,pt		$len, .L${bits}_cbc_dec_loop2x+4
++	orn		%g0, $omask, $omask
++___
++$::code.=<<___ if ($::evp);
++	st		%f12, [$ivec + 0]
++	st		%f13, [$ivec + 4]
++	st		%f14, [$ivec + 8]
++	st		%f15, [$ivec + 12]
++___
++$::code.=<<___ if (!$::evp);
++	brnz,pn		$ivoff, .L${bits}_cbc_dec_unaligned_ivec
++	nop
++
++	std		%f12, [$ivec + 0]	! write out ivec
++	std		%f14, [$ivec + 8]
++___
++$::code.=<<___;
++	ret
++	restore
++
++!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
++.align	32
++.L${bits}_cbc_dec_loop2x:
++	ldx		[$inp + 0], %o0
++	ldx		[$inp + 8], %o1
++	ldx		[$inp + 16], %o2
++	brz,pt		$ileft, 4f
++	ldx		[$inp + 24], %o3
++
++	ldx		[$inp + 32], %o4
++	sllx		%o0, $ileft, %o0
++	srlx		%o1, $iright, %g1
++	or		%g1, %o0, %o0
++	sllx		%o1, $ileft, %o1
++	srlx		%o2, $iright, %g1
++	or		%g1, %o1, %o1
++	sllx		%o2, $ileft, %o2
++	srlx		%o3, $iright, %g1
++	or		%g1, %o2, %o2
++	sllx		%o3, $ileft, %o3
++	srlx		%o4, $iright, %o4
++	or		%o4, %o3, %o3
++4:
++	xor		%g4, %o0, %o4		! ^= rk[0]
++	xor		%g5, %o1, %o5
++	movxtod		%o4, %f0
++	movxtod		%o5, %f2
++	xor		%g4, %o2, %o4
++	xor		%g5, %o3, %o5
++	movxtod		%o4, %f4
++	movxtod		%o5, %f6
++
++	prefetch	[$out + 63], 22
++	prefetch	[$inp + 32+63], 20
++	call		_${alg}${bits}_decrypt_2x
++	add		$inp, 32, $inp
++
++	movxtod		%o0, %f8
++	movxtod		%o1, %f10
++	fxor		%f12, %f0, %f0		! ^= ivec
++	fxor		%f14, %f2, %f2
++	movxtod		%o2, %f12
++	movxtod		%o3, %f14
++	fxor		%f8, %f4, %f4
++	fxor		%f10, %f6, %f6
++
++	brnz,pn		$ooff, 2f
++	sub		$len, 2, $len
++		
++	std		%f0, [$out + 0]
++	std		%f2, [$out + 8]
++	std		%f4, [$out + 16]
++	std		%f6, [$out + 24]
++	brnz,pt		$len, .L${bits}_cbc_dec_loop2x
++	add		$out, 32, $out
++___
++$::code.=<<___ if ($::evp);
++	st		%f12, [$ivec + 0]
++	st		%f13, [$ivec + 4]
++	st		%f14, [$ivec + 8]
++	st		%f15, [$ivec + 12]
++___
++$::code.=<<___ if (!$::evp);
++	brnz,pn		$ivoff, .L${bits}_cbc_dec_unaligned_ivec
++	nop
++
++	std		%f12, [$ivec + 0]	! write out ivec
++	std		%f14, [$ivec + 8]
++___
++$::code.=<<___;
++	ret
++	restore
++
++.align	16
++2:	ldxa		[$inp]0x82, %o0		! avoid read-after-write hazard
++						! and ~3x deterioration
++						! in inp==out case
++	faligndata	%f0, %f0, %f8		! handle unaligned output
++	faligndata	%f0, %f2, %f0
++	faligndata	%f2, %f4, %f2
++	faligndata	%f4, %f6, %f4
++	faligndata	%f6, %f6, %f6
++	stda		%f8, [$out + $omask]0xc0	! partial store
++	std		%f0, [$out + 8]
++	std		%f2, [$out + 16]
++	std		%f4, [$out + 24]
++	add		$out, 32, $out
++	orn		%g0, $omask, $omask
++	stda		%f6, [$out + $omask]0xc0	! partial store
++
++	brnz,pt		$len, .L${bits}_cbc_dec_loop2x+4
++	orn		%g0, $omask, $omask
++___
++$::code.=<<___ if ($::evp);
++	st		%f12, [$ivec + 0]
++	st		%f13, [$ivec + 4]
++	st		%f14, [$ivec + 8]
++	st		%f15, [$ivec + 12]
++___
++$::code.=<<___ if (!$::evp);
++	brnz,pn		$ivoff, .L${bits}_cbc_dec_unaligned_ivec
++	nop
++
++	std		%f12, [$ivec + 0]	! write out ivec
++	std		%f14, [$ivec + 8]
++	ret
++	restore
++
++.align	16
++.L${bits}_cbc_dec_unaligned_ivec:
++	alignaddrl	$ivec, $ivoff, %g0	! handle unaligned ivec
++	mov		0xff, $omask
++	srl		$omask, $ivoff, $omask
++	faligndata	%f12, %f12, %f0
++	faligndata	%f12, %f14, %f2
++	faligndata	%f14, %f14, %f4
++	stda		%f0, [$ivec + $omask]0xc0
++	std		%f2, [$ivec + 8]
++	add		$ivec, 16, $ivec
++	orn		%g0, $omask, $omask
++	stda		%f4, [$ivec + $omask]0xc0
++___
++$::code.=<<___;
++	ret
++	restore
++
++!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
++.align	32
++.L${bits}cbc_dec_blk:
++	add	$out, $len, $blk_init
++	and	$blk_init, 63, $blk_init	! tail
++	sub	$len, $blk_init, $len
++	add	$blk_init, 15, $blk_init	! round up to 16n
++	srlx	$len, 4, $len
++	srl	$blk_init, 4, $blk_init
++	sub	$len, 1, $len
++	add	$blk_init, 1, $blk_init
++
++.L${bits}_cbc_dec_blk_loop2x:
++	ldx		[$inp + 0], %o0
++	ldx		[$inp + 8], %o1
++	ldx		[$inp + 16], %o2
++	brz,pt		$ileft, 5f
++	ldx		[$inp + 24], %o3
++
++	ldx		[$inp + 32], %o4
++	sllx		%o0, $ileft, %o0
++	srlx		%o1, $iright, %g1
++	or		%g1, %o0, %o0
++	sllx		%o1, $ileft, %o1
++	srlx		%o2, $iright, %g1
++	or		%g1, %o1, %o1
++	sllx		%o2, $ileft, %o2
++	srlx		%o3, $iright, %g1
++	or		%g1, %o2, %o2
++	sllx		%o3, $ileft, %o3
++	srlx		%o4, $iright, %o4
++	or		%o4, %o3, %o3
++5:
++	xor		%g4, %o0, %o4		! ^= rk[0]
++	xor		%g5, %o1, %o5
++	movxtod		%o4, %f0
++	movxtod		%o5, %f2
++	xor		%g4, %o2, %o4
++	xor		%g5, %o3, %o5
++	movxtod		%o4, %f4
++	movxtod		%o5, %f6
++
++	prefetch	[$inp + 32+63], 20
++	call		_${alg}${bits}_decrypt_2x
++	add		$inp, 32, $inp
++	subcc		$len, 2, $len
++
++	movxtod		%o0, %f8
++	movxtod		%o1, %f10
++	fxor		%f12, %f0, %f0		! ^= ivec
++	fxor		%f14, %f2, %f2
++	movxtod		%o2, %f12
++	movxtod		%o3, %f14
++	fxor		%f8, %f4, %f4
++	fxor		%f10, %f6, %f6
++
++	stda		%f0, [$out]0xe2		! ASI_BLK_INIT, T4-specific
++	add		$out, 8, $out
++	stda		%f2, [$out]0xe2		! ASI_BLK_INIT, T4-specific
++	add		$out, 8, $out
++	stda		%f4, [$out]0xe2		! ASI_BLK_INIT, T4-specific
++	add		$out, 8, $out
++	stda		%f6, [$out]0xe2		! ASI_BLK_INIT, T4-specific
++	bgu,pt		$::size_t_cc, .L${bits}_cbc_dec_blk_loop2x
++	add		$out, 8, $out
++
++	add		$blk_init, $len, $len
++	andcc		$len, 1, %g0		! is number of blocks even?
++	membar		#StoreLoad|#StoreStore
++	bnz,pt		%icc, .L${bits}_cbc_dec_loop
++	srl		$len, 0, $len
++	brnz,pn		$len, .L${bits}_cbc_dec_loop2x
++	nop
++___
++$::code.=<<___ if ($::evp);
++	st		%f12, [$ivec + 0]	! write out ivec
++	st		%f13, [$ivec + 4]
++	st		%f14, [$ivec + 8]
++	st		%f15, [$ivec + 12]
++___
++$::code.=<<___ if (!$::evp);
++	brnz,pn		$ivoff, 3b
++	nop
++
++	std		%f12, [$ivec + 0]	! write out ivec
++	std		%f14, [$ivec + 8]
++___
++$::code.=<<___;
++	ret
++	restore
++.type	${alg}${bits}_t4_cbc_decrypt,#function
++.size	${alg}${bits}_t4_cbc_decrypt,.-${alg}${bits}_t4_cbc_decrypt
++___
++}
++
++sub alg_ctr32_implement {
++my ($alg,$bits) = @_;
++
++$::code.=<<___;
++.globl	${alg}${bits}_t4_ctr32_encrypt
++.align	32
++${alg}${bits}_t4_ctr32_encrypt:
++	save		%sp, -$::frame, %sp
++	srln		$len, 0, $len		! needed on v8+, "nop" on v9
++
++	prefetch	[$inp], 20
++	prefetch	[$inp + 63], 20
++	call		_${alg}${bits}_load_enckey
++	sllx		$len, 4, $len
++
++	ld		[$ivec + 0], %l4	! counter
++	ld		[$ivec + 4], %l5
++	ld		[$ivec + 8], %l6
++	ld		[$ivec + 12], %l7
++
++	sllx		%l4, 32, %o5
++	or		%l5, %o5, %o5
++	sllx		%l6, 32, %g1
++	xor		%o5, %g4, %g4		! ^= rk[0]
++	xor		%g1, %g5, %g5
++	movxtod		%g4, %f14		! most significant 64 bits
++
++	sub		$inp, $out, $blk_init	! $inp!=$out
++	and		$inp, 7, $ileft
++	andn		$inp, 7, $inp
++	sll		$ileft, 3, $ileft
++	mov		64, $iright
++	mov		0xff, $omask
++	sub		$iright, $ileft, $iright
++	and		$out, 7, $ooff
++	cmp		$len, 255
++	movrnz		$ooff, 0, $blk_init		! if (	$out&7 ||
++	movleu		$::size_t_cc, 0, $blk_init	!	$len<256 ||
++	brnz,pn		$blk_init, .L${bits}_ctr32_blk	!	$inp==$out)
++	srl		$omask, $ooff, $omask
++
++	andcc		$len, 16, %g0		! is number of blocks even?
++	alignaddrl	$out, %g0, $out
++	bz		%icc, .L${bits}_ctr32_loop2x
++	srlx		$len, 4, $len
++.L${bits}_ctr32_loop:
++	ldx		[$inp + 0], %o0
++	brz,pt		$ileft, 4f
++	ldx		[$inp + 8], %o1
++
++	ldx		[$inp + 16], %o2
++	sllx		%o0, $ileft, %o0
++	srlx		%o1, $iright, %g1
++	sllx		%o1, $ileft, %o1
++	or		%g1, %o0, %o0
++	srlx		%o2, $iright, %o2
++	or		%o2, %o1, %o1
++4:
++	xor		%g5, %l7, %g1		! ^= rk[0]
++	add		%l7, 1, %l7
++	movxtod		%g1, %f2
++	srl		%l7, 0, %l7		! clruw
++	prefetch	[$out + 63], 22
++	prefetch	[$inp + 16+63], 20
++___
++$::code.=<<___ if ($alg eq "aes");
++	aes_eround01	%f16, %f14, %f2, %f4
++	aes_eround23	%f18, %f14, %f2, %f2
++___
++$::code.=<<___ if ($alg eq "cmll");
++	camellia_f	%f16, %f2, %f14, %f2
++	camellia_f	%f18, %f14, %f2, %f0
++___
++$::code.=<<___;
++	call		_${alg}${bits}_encrypt_1x+8
++	add		$inp, 16, $inp
++
++	movxtod		%o0, %f10
++	movxtod		%o1, %f12
++	fxor		%f10, %f0, %f0		! ^= inp
++	fxor		%f12, %f2, %f2
++
++	brnz,pn		$ooff, 2f
++	sub		$len, 1, $len
++		
++	std		%f0, [$out + 0]
++	std		%f2, [$out + 8]
++	brnz,pt		$len, .L${bits}_ctr32_loop2x
++	add		$out, 16, $out
++
++	ret
++	restore
++
++.align	16
++2:	ldxa		[$inp]0x82, %o0		! avoid read-after-write hazard
++						! and ~3x deterioration
++						! in inp==out case
++	faligndata	%f0, %f0, %f4		! handle unaligned output
++	faligndata	%f0, %f2, %f6
++	faligndata	%f2, %f2, %f8
++	stda		%f4, [$out + $omask]0xc0	! partial store
++	std		%f6, [$out + 8]
++	add		$out, 16, $out
++	orn		%g0, $omask, $omask
++	stda		%f8, [$out + $omask]0xc0	! partial store
++
++	brnz,pt		$len, .L${bits}_ctr32_loop2x+4
++	orn		%g0, $omask, $omask
++
++	ret
++	restore
++
++!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
++.align	32
++.L${bits}_ctr32_loop2x:
++	ldx		[$inp + 0], %o0
++	ldx		[$inp + 8], %o1
++	ldx		[$inp + 16], %o2
++	brz,pt		$ileft, 4f
++	ldx		[$inp + 24], %o3
++
++	ldx		[$inp + 32], %o4
++	sllx		%o0, $ileft, %o0
++	srlx		%o1, $iright, %g1
++	or		%g1, %o0, %o0
++	sllx		%o1, $ileft, %o1
++	srlx		%o2, $iright, %g1
++	or		%g1, %o1, %o1
++	sllx		%o2, $ileft, %o2
++	srlx		%o3, $iright, %g1
++	or		%g1, %o2, %o2
++	sllx		%o3, $ileft, %o3
++	srlx		%o4, $iright, %o4
++	or		%o4, %o3, %o3
++4:
++	xor		%g5, %l7, %g1		! ^= rk[0]
++	add		%l7, 1, %l7
++	movxtod		%g1, %f2
++	srl		%l7, 0, %l7		! clruw
++	xor		%g5, %l7, %g1
++	add		%l7, 1, %l7
++	movxtod		%g1, %f6
++	srl		%l7, 0, %l7		! clruw
++	prefetch	[$out + 63], 22
++	prefetch	[$inp + 32+63], 20
++___
++$::code.=<<___ if ($alg eq "aes");
++	aes_eround01	%f16, %f14, %f2, %f8
++	aes_eround23	%f18, %f14, %f2, %f2
++	aes_eround01	%f16, %f14, %f6, %f10
++	aes_eround23	%f18, %f14, %f6, %f6
++___
++$::code.=<<___ if ($alg eq "cmll");
++	camellia_f	%f16, %f2, %f14, %f2
++	camellia_f	%f16, %f6, %f14, %f6
++	camellia_f	%f18, %f14, %f2, %f0
++	camellia_f	%f18, %f14, %f6, %f4
++___
++$::code.=<<___;
++	call		_${alg}${bits}_encrypt_2x+16
++	add		$inp, 32, $inp
++
++	movxtod		%o0, %f8
++	movxtod		%o1, %f10
++	movxtod		%o2, %f12
++	fxor		%f8, %f0, %f0		! ^= inp
++	movxtod		%o3, %f8
++	fxor		%f10, %f2, %f2
++	fxor		%f12, %f4, %f4
++	fxor		%f8, %f6, %f6
++
++	brnz,pn		$ooff, 2f
++	sub		$len, 2, $len
++		
++	std		%f0, [$out + 0]
++	std		%f2, [$out + 8]
++	std		%f4, [$out + 16]
++	std		%f6, [$out + 24]
++	brnz,pt		$len, .L${bits}_ctr32_loop2x
++	add		$out, 32, $out
++
++	ret
++	restore
++
++.align	16
++2:	ldxa		[$inp]0x82, %o0		! avoid read-after-write hazard
++						! and ~3x deterioration
++						! in inp==out case
++	faligndata	%f0, %f0, %f8		! handle unaligned output
++	faligndata	%f0, %f2, %f0
++	faligndata	%f2, %f4, %f2
++	faligndata	%f4, %f6, %f4
++	faligndata	%f6, %f6, %f6
++
++	stda		%f8, [$out + $omask]0xc0	! partial store
++	std		%f0, [$out + 8]
++	std		%f2, [$out + 16]
++	std		%f4, [$out + 24]
++	add		$out, 32, $out
++	orn		%g0, $omask, $omask
++	stda		%f6, [$out + $omask]0xc0	! partial store
++
++	brnz,pt		$len, .L${bits}_ctr32_loop2x+4
++	orn		%g0, $omask, $omask
++
++	ret
++	restore
++
++!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
++.align	32
++.L${bits}_ctr32_blk:
++	add	$out, $len, $blk_init
++	and	$blk_init, 63, $blk_init	! tail
++	sub	$len, $blk_init, $len
++	add	$blk_init, 15, $blk_init	! round up to 16n
++	srlx	$len, 4, $len
++	srl	$blk_init, 4, $blk_init
++	sub	$len, 1, $len
++	add	$blk_init, 1, $blk_init
++
++.L${bits}_ctr32_blk_loop2x:
++	ldx		[$inp + 0], %o0
++	ldx		[$inp + 8], %o1
++	ldx		[$inp + 16], %o2
++	brz,pt		$ileft, 5f
++	ldx		[$inp + 24], %o3
++
++	ldx		[$inp + 32], %o4
++	sllx		%o0, $ileft, %o0
++	srlx		%o1, $iright, %g1
++	or		%g1, %o0, %o0
++	sllx		%o1, $ileft, %o1
++	srlx		%o2, $iright, %g1
++	or		%g1, %o1, %o1
++	sllx		%o2, $ileft, %o2
++	srlx		%o3, $iright, %g1
++	or		%g1, %o2, %o2
++	sllx		%o3, $ileft, %o3
++	srlx		%o4, $iright, %o4
++	or		%o4, %o3, %o3
++5:
++	xor		%g5, %l7, %g1		! ^= rk[0]
++	add		%l7, 1, %l7
++	movxtod		%g1, %f2
++	srl		%l7, 0, %l7		! clruw
++	xor		%g5, %l7, %g1
++	add		%l7, 1, %l7
++	movxtod		%g1, %f6
++	srl		%l7, 0, %l7		! clruw
++	prefetch	[$inp + 32+63], 20
++___
++$::code.=<<___ if ($alg eq "aes");
++	aes_eround01	%f16, %f14, %f2, %f8
++	aes_eround23	%f18, %f14, %f2, %f2
++	aes_eround01	%f16, %f14, %f6, %f10
++	aes_eround23	%f18, %f14, %f6, %f6
++___
++$::code.=<<___ if ($alg eq "cmll");
++	camellia_f	%f16, %f2, %f14, %f2
++	camellia_f	%f16, %f6, %f14, %f6
++	camellia_f	%f18, %f14, %f2, %f0
++	camellia_f	%f18, %f14, %f6, %f4
++___
++$::code.=<<___;
++	call		_${alg}${bits}_encrypt_2x+16
++	add		$inp, 32, $inp
++	subcc		$len, 2, $len
++
++	movxtod		%o0, %f8
++	movxtod		%o1, %f10
++	movxtod		%o2, %f12
++	fxor		%f8, %f0, %f0		! ^= inp
++	movxtod		%o3, %f8
++	fxor		%f10, %f2, %f2
++	fxor		%f12, %f4, %f4
++	fxor		%f8, %f6, %f6
++
++	stda		%f0, [$out]0xe2		! ASI_BLK_INIT, T4-specific
++	add		$out, 8, $out
++	stda		%f2, [$out]0xe2		! ASI_BLK_INIT, T4-specific
++	add		$out, 8, $out
++	stda		%f4, [$out]0xe2		! ASI_BLK_INIT, T4-specific
++	add		$out, 8, $out
++	stda		%f6, [$out]0xe2		! ASI_BLK_INIT, T4-specific
++	bgu,pt		$::size_t_cc, .L${bits}_ctr32_blk_loop2x
++	add		$out, 8, $out
++
++	add		$blk_init, $len, $len
++	andcc		$len, 1, %g0		! is number of blocks even?
++	membar		#StoreLoad|#StoreStore
++	bnz,pt		%icc, .L${bits}_ctr32_loop
++	srl		$len, 0, $len
++	brnz,pn		$len, .L${bits}_ctr32_loop2x
++	nop
++
++	ret
++	restore
++.type	${alg}${bits}_t4_ctr32_encrypt,#function
++.size	${alg}${bits}_t4_ctr32_encrypt,.-${alg}${bits}_t4_ctr32_encrypt
++___
++}
++
++sub alg_xts_implement {
++my ($alg,$bits,$dir) = @_;
++my ($inp,$out,$len,$key1,$key2,$ivec)=map("%i$_",(0..5));
++my $rem=$ivec;
++
++$::code.=<<___;
++.globl	${alg}${bits}_t4_xts_${dir}crypt
++.align	32
++${alg}${bits}_t4_xts_${dir}crypt:
++	save		%sp, -$::frame-16, %sp
++	srln		$len, 0, $len		! needed on v8+, "nop" on v9
++
++	mov		$ivec, %o0
++	add		%fp, $::bias-16, %o1
++	call		${alg}_t4_encrypt
++	mov		$key2, %o2
++
++	add		%fp, $::bias-16, %l7
++	ldxa		[%l7]0x88, %g2
++	add		%fp, $::bias-8, %l7
++	ldxa		[%l7]0x88, %g3		! %g3:%g2 is tweak
++
++	sethi		%hi(0x76543210), %l7
++	or		%l7, %lo(0x76543210), %l7
++	bmask		%l7, %g0, %g0		! byte swap mask
++
++	prefetch	[$inp], 20
++	prefetch	[$inp + 63], 20
++	call		_${alg}${bits}_load_${dir}ckey
++	and		$len, 15,  $rem
++	and		$len, -16, $len
++___
++$code.=<<___ if ($dir eq "de");
++	mov		0, %l7
++	movrnz		$rem, 16,  %l7
++	sub		$len, %l7, $len
++___
++$code.=<<___;
++
++	sub		$inp, $out, $blk_init	! $inp!=$out
++	and		$inp, 7, $ileft
++	andn		$inp, 7, $inp
++	sll		$ileft, 3, $ileft
++	mov		64, $iright
++	mov		0xff, $omask
++	sub		$iright, $ileft, $iright
++	and		$out, 7, $ooff
++	cmp		$len, 255
++	movrnz		$ooff, 0, $blk_init		! if (	$out&7 ||
++	movleu		$::size_t_cc, 0, $blk_init	!	$len<256 ||
++	brnz,pn		$blk_init, .L${bits}_xts_${dir}blk !	$inp==$out)
++	srl		$omask, $ooff, $omask
++
++	andcc		$len, 16, %g0		! is number of blocks even?
++___
++$code.=<<___ if ($dir eq "de");
++	brz,pn		$len, .L${bits}_xts_${dir}steal
++___
++$code.=<<___;
++	alignaddrl	$out, %g0, $out
++	bz		%icc, .L${bits}_xts_${dir}loop2x
++	srlx		$len, 4, $len
++.L${bits}_xts_${dir}loop:
++	ldx		[$inp + 0], %o0
++	brz,pt		$ileft, 4f
++	ldx		[$inp + 8], %o1
++
++	ldx		[$inp + 16], %o2
++	sllx		%o0, $ileft, %o0
++	srlx		%o1, $iright, %g1
++	sllx		%o1, $ileft, %o1
++	or		%g1, %o0, %o0
++	srlx		%o2, $iright, %o2
++	or		%o2, %o1, %o1
++4:
++	movxtod		%g2, %f12
++	movxtod		%g3, %f14
++	bshuffle	%f12, %f12, %f12
++	bshuffle	%f14, %f14, %f14
++
++	xor		%g4, %o0, %o0		! ^= rk[0]
++	xor		%g5, %o1, %o1
++	movxtod		%o0, %f0
++	movxtod		%o1, %f2
++
++	fxor		%f12, %f0, %f0		! ^= tweak[0]
++	fxor		%f14, %f2, %f2
++
++	prefetch	[$out + 63], 22
++	prefetch	[$inp + 16+63], 20
++	call		_${alg}${bits}_${dir}crypt_1x
++	add		$inp, 16, $inp
++
++	fxor		%f12, %f0, %f0		! ^= tweak[0]
++	fxor		%f14, %f2, %f2
++
++	srax		%g3, 63, %l7		! next tweak value
++	addcc		%g2, %g2, %g2
++	and		%l7, 0x87, %l7
++	addxc		%g3, %g3, %g3
++	xor		%l7, %g2, %g2
++
++	brnz,pn		$ooff, 2f
++	sub		$len, 1, $len
++		
++	std		%f0, [$out + 0]
++	std		%f2, [$out + 8]
++	brnz,pt		$len, .L${bits}_xts_${dir}loop2x
++	add		$out, 16, $out
++
++	brnz,pn		$rem, .L${bits}_xts_${dir}steal
++	nop
++
++	ret
++	restore
++
++.align	16
++2:	ldxa		[$inp]0x82, %o0		! avoid read-after-write hazard
++						! and ~3x deterioration
++						! in inp==out case
++	faligndata	%f0, %f0, %f4		! handle unaligned output
++	faligndata	%f0, %f2, %f6
++	faligndata	%f2, %f2, %f8
++	stda		%f4, [$out + $omask]0xc0	! partial store
++	std		%f6, [$out + 8]
++	add		$out, 16, $out
++	orn		%g0, $omask, $omask
++	stda		%f8, [$out + $omask]0xc0	! partial store
++
++	brnz,pt		$len, .L${bits}_xts_${dir}loop2x+4
++	orn		%g0, $omask, $omask
++
++	brnz,pn		$rem, .L${bits}_xts_${dir}steal
++	nop
++
++	ret
++	restore
++
++!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
++.align	32
++.L${bits}_xts_${dir}loop2x:
++	ldx		[$inp + 0], %o0
++	ldx		[$inp + 8], %o1
++	ldx		[$inp + 16], %o2
++	brz,pt		$ileft, 4f
++	ldx		[$inp + 24], %o3
++
++	ldx		[$inp + 32], %o4
++	sllx		%o0, $ileft, %o0
++	srlx		%o1, $iright, %g1
++	or		%g1, %o0, %o0
++	sllx		%o1, $ileft, %o1
++	srlx		%o2, $iright, %g1
++	or		%g1, %o1, %o1
++	sllx		%o2, $ileft, %o2
++	srlx		%o3, $iright, %g1
++	or		%g1, %o2, %o2
++	sllx		%o3, $ileft, %o3
++	srlx		%o4, $iright, %o4
++	or		%o4, %o3, %o3
++4:
++	movxtod		%g2, %f12
++	movxtod		%g3, %f14
++	bshuffle	%f12, %f12, %f12
++	bshuffle	%f14, %f14, %f14
++
++	srax		%g3, 63, %l7		! next tweak value
++	addcc		%g2, %g2, %g2
++	and		%l7, 0x87, %l7
++	addxc		%g3, %g3, %g3
++	xor		%l7, %g2, %g2
++
++	movxtod		%g2, %f8
++	movxtod		%g3, %f10
++	bshuffle	%f8,  %f8,  %f8
++	bshuffle	%f10, %f10, %f10
++
++	xor		%g4, %o0, %o0		! ^= rk[0]
++	xor		%g5, %o1, %o1
++	xor		%g4, %o2, %o2		! ^= rk[0]
++	xor		%g5, %o3, %o3
++	movxtod		%o0, %f0
++	movxtod		%o1, %f2
++	movxtod		%o2, %f4
++	movxtod		%o3, %f6
++
++	fxor		%f12, %f0, %f0		! ^= tweak[0]
++	fxor		%f14, %f2, %f2
++	fxor		%f8,  %f4, %f4		! ^= tweak[0]
++	fxor		%f10, %f6, %f6
++
++	prefetch	[$out + 63], 22
++	prefetch	[$inp + 32+63], 20
++	call		_${alg}${bits}_${dir}crypt_2x
++	add		$inp, 32, $inp
++
++	movxtod		%g2, %f8
++	movxtod		%g3, %f10
++
++	srax		%g3, 63, %l7		! next tweak value
++	addcc		%g2, %g2, %g2
++	and		%l7, 0x87, %l7
++	addxc		%g3, %g3, %g3
++	xor		%l7, %g2, %g2
++
++	bshuffle	%f8,  %f8,  %f8
++	bshuffle	%f10, %f10, %f10
++
++	fxor		%f12, %f0, %f0		! ^= tweak[0]
++	fxor		%f14, %f2, %f2
++	fxor		%f8,  %f4, %f4
++	fxor		%f10, %f6, %f6
++
++	brnz,pn		$ooff, 2f
++	sub		$len, 2, $len
++		
++	std		%f0, [$out + 0]
++	std		%f2, [$out + 8]
++	std		%f4, [$out + 16]
++	std		%f6, [$out + 24]
++	brnz,pt		$len, .L${bits}_xts_${dir}loop2x
++	add		$out, 32, $out
++
++	fsrc2		%f4, %f0
++	fsrc2		%f6, %f2
++	brnz,pn		$rem, .L${bits}_xts_${dir}steal
++	nop
++
++	ret
++	restore
++
++.align	16
++2:	ldxa		[$inp]0x82, %o0		! avoid read-after-write hazard
++						! and ~3x deterioration
++						! in inp==out case
++	faligndata	%f0, %f0, %f8		! handle unaligned output
++	faligndata	%f0, %f2, %f10
++	faligndata	%f2, %f4, %f12
++	faligndata	%f4, %f6, %f14
++	faligndata	%f6, %f6, %f0
++
++	stda		%f8, [$out + $omask]0xc0	! partial store
++	std		%f10, [$out + 8]
++	std		%f12, [$out + 16]
++	std		%f14, [$out + 24]
++	add		$out, 32, $out
++	orn		%g0, $omask, $omask
++	stda		%f0, [$out + $omask]0xc0	! partial store
++
++	brnz,pt		$len, .L${bits}_xts_${dir}loop2x+4
++	orn		%g0, $omask, $omask
++
++	fsrc2		%f4, %f0
++	fsrc2		%f6, %f2
++	brnz,pn		$rem, .L${bits}_xts_${dir}steal
++	nop
++
++	ret
++	restore
++
++!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
++.align	32
++.L${bits}_xts_${dir}blk:
++	add	$out, $len, $blk_init
++	and	$blk_init, 63, $blk_init	! tail
++	sub	$len, $blk_init, $len
++	add	$blk_init, 15, $blk_init	! round up to 16n
++	srlx	$len, 4, $len
++	srl	$blk_init, 4, $blk_init
++	sub	$len, 1, $len
++	add	$blk_init, 1, $blk_init
++
++.L${bits}_xts_${dir}blk2x:
++	ldx		[$inp + 0], %o0
++	ldx		[$inp + 8], %o1
++	ldx		[$inp + 16], %o2
++	brz,pt		$ileft, 5f
++	ldx		[$inp + 24], %o3
++
++	ldx		[$inp + 32], %o4
++	sllx		%o0, $ileft, %o0
++	srlx		%o1, $iright, %g1
++	or		%g1, %o0, %o0
++	sllx		%o1, $ileft, %o1
++	srlx		%o2, $iright, %g1
++	or		%g1, %o1, %o1
++	sllx		%o2, $ileft, %o2
++	srlx		%o3, $iright, %g1
++	or		%g1, %o2, %o2
++	sllx		%o3, $ileft, %o3
++	srlx		%o4, $iright, %o4
++	or		%o4, %o3, %o3
++5:
++	movxtod		%g2, %f12
++	movxtod		%g3, %f14
++	bshuffle	%f12, %f12, %f12
++	bshuffle	%f14, %f14, %f14
++
++	srax		%g3, 63, %l7		! next tweak value
++	addcc		%g2, %g2, %g2
++	and		%l7, 0x87, %l7
++	addxc		%g3, %g3, %g3
++	xor		%l7, %g2, %g2
++
++	movxtod		%g2, %f8
++	movxtod		%g3, %f10
++	bshuffle	%f8,  %f8,  %f8
++	bshuffle	%f10, %f10, %f10
++
++	xor		%g4, %o0, %o0		! ^= rk[0]
++	xor		%g5, %o1, %o1
++	xor		%g4, %o2, %o2		! ^= rk[0]
++	xor		%g5, %o3, %o3
++	movxtod		%o0, %f0
++	movxtod		%o1, %f2
++	movxtod		%o2, %f4
++	movxtod		%o3, %f6
++
++	fxor		%f12, %f0, %f0		! ^= tweak[0]
++	fxor		%f14, %f2, %f2
++	fxor		%f8,  %f4, %f4		! ^= tweak[0]
++	fxor		%f10, %f6, %f6
++
++	prefetch	[$inp + 32+63], 20
++	call		_${alg}${bits}_${dir}crypt_2x
++	add		$inp, 32, $inp
++
++	movxtod		%g2, %f8
++	movxtod		%g3, %f10
++
++	srax		%g3, 63, %l7		! next tweak value
++	addcc		%g2, %g2, %g2
++	and		%l7, 0x87, %l7
++	addxc		%g3, %g3, %g3
++	xor		%l7, %g2, %g2
++
++	bshuffle	%f8,  %f8,  %f8
++	bshuffle	%f10, %f10, %f10
++
++	fxor		%f12, %f0, %f0		! ^= tweak[0]
++	fxor		%f14, %f2, %f2
++	fxor		%f8,  %f4, %f4
++	fxor		%f10, %f6, %f6
++
++	subcc		$len, 2, $len
++	stda		%f0, [$out]0xe2		! ASI_BLK_INIT, T4-specific
++	add		$out, 8, $out
++	stda		%f2, [$out]0xe2		! ASI_BLK_INIT, T4-specific
++	add		$out, 8, $out
++	stda		%f4, [$out]0xe2		! ASI_BLK_INIT, T4-specific
++	add		$out, 8, $out
++	stda		%f6, [$out]0xe2		! ASI_BLK_INIT, T4-specific
++	bgu,pt		$::size_t_cc, .L${bits}_xts_${dir}blk2x
++	add		$out, 8, $out
++
++	add		$blk_init, $len, $len
++	andcc		$len, 1, %g0		! is number of blocks even?
++	membar		#StoreLoad|#StoreStore
++	bnz,pt		%icc, .L${bits}_xts_${dir}loop
++	srl		$len, 0, $len
++	brnz,pn		$len, .L${bits}_xts_${dir}loop2x
++	nop
++
++	fsrc2		%f4, %f0
++	fsrc2		%f6, %f2
++	brnz,pn		$rem, .L${bits}_xts_${dir}steal
++	nop
++
++	ret
++	restore
++!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
++___
++$code.=<<___ if ($dir eq "en");
++.align	32
++.L${bits}_xts_${dir}steal:
++	std		%f0, [%fp + $::bias-16]	! copy of output
++	std		%f2, [%fp + $::bias-8]
++
++	srl		$ileft, 3, $ileft
++	add		%fp, $::bias-16, %l7
++	add		$inp, $ileft, $inp	! original $inp+$len&-15
++	add		$out, $ooff, $out	! original $out+$len&-15
++	mov		0, $ileft
++	nop					! align
++
++.L${bits}_xts_${dir}stealing:
++	ldub		[$inp + $ileft], %o0
++	ldub		[%l7  + $ileft], %o1
++	dec		$rem
++	stb		%o0, [%l7  + $ileft]
++	stb		%o1, [$out + $ileft]
++	brnz		$rem, .L${bits}_xts_${dir}stealing
++	inc		$ileft
++
++	mov		%l7, $inp
++	sub		$out, 16, $out
++	mov		0, $ileft
++	sub		$out, $ooff, $out
++	ba		.L${bits}_xts_${dir}loop	! one more time
++	mov		1, $len				! $rem is 0
++___
++$code.=<<___ if ($dir eq "de");
++.align	32
++.L${bits}_xts_${dir}steal:
++	ldx		[$inp + 0], %o0
++	brz,pt		$ileft, 8f
++	ldx		[$inp + 8], %o1
++
++	ldx		[$inp + 16], %o2
++	sllx		%o0, $ileft, %o0
++	srlx		%o1, $iright, %g1
++	sllx		%o1, $ileft, %o1
++	or		%g1, %o0, %o0
++	srlx		%o2, $iright, %o2
++	or		%o2, %o1, %o1
++8:
++	srax		%g3, 63, %l7		! next tweak value
++	addcc		%g2, %g2, %o2
++	and		%l7, 0x87, %l7
++	addxc		%g3, %g3, %o3
++	xor		%l7, %o2, %o2
++
++	movxtod		%o2, %f12
++	movxtod		%o3, %f14
++	bshuffle	%f12, %f12, %f12
++	bshuffle	%f14, %f14, %f14
++
++	xor		%g4, %o0, %o0		! ^= rk[0]
++	xor		%g5, %o1, %o1
++	movxtod		%o0, %f0
++	movxtod		%o1, %f2
++
++	fxor		%f12, %f0, %f0		! ^= tweak[0]
++	fxor		%f14, %f2, %f2
++
++	call		_${alg}${bits}_${dir}crypt_1x
++	add		$inp, 16, $inp
++
++	fxor		%f12, %f0, %f0		! ^= tweak[0]
++	fxor		%f14, %f2, %f2
++
++	std		%f0, [%fp + $::bias-16]
++	std		%f2, [%fp + $::bias-8]
++
++	srl		$ileft, 3, $ileft
++	add		%fp, $::bias-16, %l7
++	add		$inp, $ileft, $inp	! original $inp+$len&-15
++	add		$out, $ooff, $out	! original $out+$len&-15
++	mov		0, $ileft
++	add		$out, 16, $out
++	nop					! align
++
++.L${bits}_xts_${dir}stealing:
++	ldub		[$inp + $ileft], %o0
++	ldub		[%l7  + $ileft], %o1
++	dec		$rem
++	stb		%o0, [%l7  + $ileft]
++	stb		%o1, [$out + $ileft]
++	brnz		$rem, .L${bits}_xts_${dir}stealing
++	inc		$ileft
++
++	mov		%l7, $inp
++	sub		$out, 16, $out
++	mov		0, $ileft
++	sub		$out, $ooff, $out
++	ba		.L${bits}_xts_${dir}loop	! one more time
++	mov		1, $len				! $rem is 0
++___
++$code.=<<___;
++	ret
++	restore
++.type	${alg}${bits}_t4_xts_${dir}crypt,#function
++.size	${alg}${bits}_t4_xts_${dir}crypt,.-${alg}${bits}_t4_xts_${dir}crypt
++___
++}
++
++# Purpose of these subroutines is to explicitly encode VIS instructions,
++# so that one can compile the module without having to specify VIS
++# extensions on compiler command line, e.g. -xarch=v9 vs. -xarch=v9a.
++# Idea is to reserve for option to produce "universal" binary and let
++# programmer detect if current CPU is VIS capable at run-time.
++sub unvis {
++my ($mnemonic,$rs1,$rs2,$rd)=@_;
++my ($ref,$opf);
++my %visopf = (	"faligndata"	=> 0x048,
++		"bshuffle"	=> 0x04c,
++		"fnot2"		=> 0x066,
++		"fxor"		=> 0x06c,
++		"fsrc2"		=> 0x078	);
++
++    $ref = "$mnemonic\t$rs1,$rs2,$rd";
++
++    if ($opf=$visopf{$mnemonic}) {
++	foreach ($rs1,$rs2,$rd) {
++	    return $ref if (!/%f([0-9]{1,2})/);
++	    $_=$1;
++	    if ($1>=32) {
++		return $ref if ($1&1);
++		# re-encode for upper double register addressing
++		$_=($1|$1>>5)&31;
++	    }
++	}
++
++	return	sprintf ".word\t0x%08x !%s",
++			0x81b00000|$rd<<25|$rs1<<14|$opf<<5|$rs2,
++			$ref;
++    } else {
++	return $ref;
++    }
++}
++
++sub unvis3 {
++my ($mnemonic,$rs1,$rs2,$rd)=@_;
++my %bias = ( "g" => 0, "o" => 8, "l" => 16, "i" => 24 );
++my ($ref,$opf);
++my %visopf = (	"addxc"		=> 0x011,
++		"addxccc"	=> 0x013,
++		"umulxhi"	=> 0x016,
++		"alignaddr"	=> 0x018,
++		"bmask"		=> 0x019,
++		"alignaddrl"	=> 0x01a	);
++
++    $ref = "$mnemonic\t$rs1,$rs2,$rd";
++
++    if ($opf=$visopf{$mnemonic}) {
++	foreach ($rs1,$rs2,$rd) {
++	    return $ref if (!/%([goli])([0-9])/);
++	    $_=$bias{$1}+$2;
++	}
++
++	return	sprintf ".word\t0x%08x !%s",
++			0x81b00000|$rd<<25|$rs1<<14|$opf<<5|$rs2,
++			$ref;
++    } else {
++	return $ref;
++    }
++}
++
++sub unaes_round {	# 4-argument instructions
++my ($mnemonic,$rs1,$rs2,$rs3,$rd)=@_;
++my ($ref,$opf);
++my %aesopf = (	"aes_eround01"	=> 0,
++		"aes_eround23"	=> 1,
++		"aes_dround01"	=> 2,
++		"aes_dround23"	=> 3,
++		"aes_eround01_l"=> 4,
++		"aes_eround23_l"=> 5,
++		"aes_dround01_l"=> 6,
++		"aes_dround23_l"=> 7,
++		"aes_kexpand1"	=> 8	);
++
++    $ref = "$mnemonic\t$rs1,$rs2,$rs3,$rd";
++
++    if (defined($opf=$aesopf{$mnemonic})) {
++	$rs3 = ($rs3 =~ /%f([0-6]*[02468])/) ? (($1|$1>>5)&31) : $rs3;
++	foreach ($rs1,$rs2,$rd) {
++	    return $ref if (!/%f([0-9]{1,2})/);
++	    $_=$1;
++	    if ($1>=32) {
++		return $ref if ($1&1);
++		# re-encode for upper double register addressing
++		$_=($1|$1>>5)&31;
++	    }
++	}
++
++	return	sprintf ".word\t0x%08x !%s",
++			2<<30|$rd<<25|0x19<<19|$rs1<<14|$rs3<<9|$opf<<5|$rs2,
++			$ref;
++    } else {
++	return $ref;
++    }
++}
++
++sub unaes_kexpand {	# 3-argument instructions
++my ($mnemonic,$rs1,$rs2,$rd)=@_;
++my ($ref,$opf);
++my %aesopf = (	"aes_kexpand0"	=> 0x130,
++		"aes_kexpand2"	=> 0x131	);
++
++    $ref = "$mnemonic\t$rs1,$rs2,$rd";
++
++    if (defined($opf=$aesopf{$mnemonic})) {
++	foreach ($rs1,$rs2,$rd) {
++	    return $ref if (!/%f([0-9]{1,2})/);
++	    $_=$1;
++	    if ($1>=32) {
++		return $ref if ($1&1);
++		# re-encode for upper double register addressing
++		$_=($1|$1>>5)&31;
++	    }
++	}
++
++	return	sprintf ".word\t0x%08x !%s",
++			2<<30|$rd<<25|0x36<<19|$rs1<<14|$opf<<5|$rs2,
++			$ref;
++    } else {
++	return $ref;
++    }
++}
++
++sub uncamellia_f {	# 4-argument instructions
++my ($mnemonic,$rs1,$rs2,$rs3,$rd)=@_;
++my ($ref,$opf);
++
++    $ref = "$mnemonic\t$rs1,$rs2,$rs3,$rd";
++
++    if (1) {
++	$rs3 = ($rs3 =~ /%f([0-6]*[02468])/) ? (($1|$1>>5)&31) : $rs3;
++	foreach ($rs1,$rs2,$rd) {
++	    return $ref if (!/%f([0-9]{1,2})/);
++	    $_=$1;
++	    if ($1>=32) {
++		return $ref if ($1&1);
++		# re-encode for upper double register addressing
++		$_=($1|$1>>5)&31;
++	    }
++	}
++
++	return	sprintf ".word\t0x%08x !%s",
++			2<<30|$rd<<25|0x19<<19|$rs1<<14|$rs3<<9|0xc<<5|$rs2,
++			$ref;
++    } else {
++	return $ref;
++    }
++}
++
++sub uncamellia3 {	# 3-argument instructions
++my ($mnemonic,$rs1,$rs2,$rd)=@_;
++my ($ref,$opf);
++my %cmllopf = (	"camellia_fl"	=> 0x13c,
++		"camellia_fli"	=> 0x13d	);
++
++    $ref = "$mnemonic\t$rs1,$rs2,$rd";
++
++    if (defined($opf=$cmllopf{$mnemonic})) {
++	foreach ($rs1,$rs2,$rd) {
++	    return $ref if (!/%f([0-9]{1,2})/);
++	    $_=$1;
++	    if ($1>=32) {
++		return $ref if ($1&1);
++		# re-encode for upper double register addressing
++		$_=($1|$1>>5)&31;
++	    }
++	}
++
++	return	sprintf ".word\t0x%08x !%s",
++			2<<30|$rd<<25|0x36<<19|$rs1<<14|$opf<<5|$rs2,
++			$ref;
++    } else {
++	return $ref;
++    }
++}
++
++sub unmovxtox {		# 2-argument instructions
++my ($mnemonic,$rs,$rd)=@_;
++my %bias = ( "g" => 0, "o" => 8, "l" => 16, "i" => 24, "f" => 0 );
++my ($ref,$opf);
++my %movxopf = (	"movdtox"	=> 0x110,
++		"movstouw"	=> 0x111,
++		"movstosw"	=> 0x113,
++		"movxtod"	=> 0x118,
++		"movwtos"	=> 0x119	);
++
++    $ref = "$mnemonic\t$rs,$rd";
++
++    if (defined($opf=$movxopf{$mnemonic})) {
++	foreach ($rs,$rd) {
++	    return $ref if (!/%([fgoli])([0-9]{1,2})/);
++	    $_=$bias{$1}+$2;
++	    if ($2>=32) {
++		return $ref if ($2&1);
++		# re-encode for upper double register addressing
++		$_=($2|$2>>5)&31;
++	    }
++	}
++
++	return	sprintf ".word\t0x%08x !%s",
++			2<<30|$rd<<25|0x36<<19|$opf<<5|$rs,
++			$ref;
++    } else {
++	return $ref;
++    }
++}
++
++sub undes {
++my ($mnemonic)=shift;
++my @args=@_;
++my ($ref,$opf);
++my %desopf = (	"des_round"	=> 0b1001,
++		"des_ip"	=> 0b100110100,
++		"des_iip"	=> 0b100110101,
++		"des_kexpand"	=> 0b100110110	);
++
++    $ref = "$mnemonic\t".join(",",@_);
++
++    if (defined($opf=$desopf{$mnemonic})) {	# 4-arg
++	if ($mnemonic eq "des_round") {
++	    foreach (@args[0..3]) {
++		return $ref if (!/%f([0-9]{1,2})/);
++		$_=$1;
++		if ($1>=32) {
++		    return $ref if ($1&1);
++		    # re-encode for upper double register addressing
++		    $_=($1|$1>>5)&31;
++		}
++	    }
++	    return  sprintf ".word\t0x%08x !%s",
++			    2<<30|0b011001<<19|$opf<<5|$args[0]<<14|$args[1]|$args[2]<<9|$args[3]<<25,
++			    $ref;
++	} elsif ($mnemonic eq "des_kexpand") {	# 3-arg
++	    foreach (@args[0..2]) {
++		return $ref if (!/(%f)?([0-9]{1,2})/);
++		$_=$2;
++		if ($2>=32) {
++		    return $ref if ($2&1);
++		    # re-encode for upper double register addressing
++		    $_=($2|$2>>5)&31;
++		}
++	    }
++	    return  sprintf ".word\t0x%08x !%s",
++			    2<<30|0b110110<<19|$opf<<5|$args[0]<<14|$args[1]|$args[2]<<25,
++			    $ref;
++	} else {				# 2-arg
++	    foreach (@args[0..1]) {
++		return $ref if (!/%f([0-9]{1,2})/);
++		$_=$1;
++		if ($1>=32) {
++		    return $ref if ($2&1);
++		    # re-encode for upper double register addressing
++		    $_=($1|$1>>5)&31;
++		}
++	    }
++	    return  sprintf ".word\t0x%08x !%s",
++			    2<<30|0b110110<<19|$opf<<5|$args[0]<<14|$args[1]<<25,
++			    $ref;
++	}
++    } else {
++	return $ref;
++    }
++}
++
++sub emit_assembler {
++    foreach (split("\n",$::code)) {
++	s/\`([^\`]*)\`/eval $1/ge;
++
++	s/\b(f[a-z]+2[sd]*)\s+(%f[0-9]{1,2}),\s*(%f[0-9]{1,2})\s*$/$1\t%f0,$2,$3/go;
++
++	s/\b(aes_[edk][^\s]*)\s+(%f[0-9]{1,2}),\s*(%f[0-9]{1,2}),\s*([%fx0-9]+),\s*(%f[0-9]{1,2})/
++		&unaes_round($1,$2,$3,$4,$5)
++	 /geo or
++	s/\b(aes_kexpand[02])\s+(%f[0-9]{1,2}),\s*(%f[0-9]{1,2}),\s*(%f[0-9]{1,2})/
++		&unaes_kexpand($1,$2,$3,$4)
++	 /geo or
++	s/\b(camellia_f)\s+(%f[0-9]{1,2}),\s*(%f[0-9]{1,2}),\s*([%fx0-9]+),\s*(%f[0-9]{1,2})/
++		&uncamellia_f($1,$2,$3,$4,$5)
++	 /geo or
++	s/\b(camellia_[^s]+)\s+(%f[0-9]{1,2}),\s*(%f[0-9]{1,2}),\s*(%f[0-9]{1,2})/
++		&uncamellia3($1,$2,$3,$4)
++	 /geo or
++	s/\b(des_\w+)\s+(%f[0-9]{1,2}),\s*([%fx0-9]+)(?:,\s*(%f[0-9]{1,2})(?:,\s*(%f[0-9]{1,2}))?)?/
++		&undes($1,$2,$3,$4,$5)
++	 /geo or
++	s/\b(mov[ds]to\w+)\s+(%f[0-9]{1,2}),\s*(%[goli][0-7])/
++		&unmovxtox($1,$2,$3)
++	 /geo or
++	s/\b(mov[xw]to[ds])\s+(%[goli][0-7]),\s*(%f[0-9]{1,2})/
++		&unmovxtox($1,$2,$3)
++	 /geo or
++	s/\b([fb][^\s]*)\s+(%f[0-9]{1,2}),\s*(%f[0-9]{1,2}),\s*(%f[0-9]{1,2})/
++		&unvis($1,$2,$3,$4)
++	 /geo or
++	s/\b(umulxhi|bmask|addxc[c]{0,2}|alignaddr[l]*)\s+(%[goli][0-7]),\s*(%[goli][0-7]),\s*(%[goli][0-7])/
++		&unvis3($1,$2,$3,$4)
++	 /geo;
++
++	print $_,"\n";
++    }
++}
++
++1;
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/perlasm/x86_64-xlate.pl b/CryptoPkg/Library/OpensslLib/openssl/crypto/perlasm/x86_64-xlate.pl
+new file mode 100755
+index 0000000..425cd29
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/perlasm/x86_64-xlate.pl
+@@ -0,0 +1,1185 @@
++#! /usr/bin/env perl
++# Copyright 2005-2016 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
++# in the file LICENSE in the source distribution or at
++# https://www.openssl.org/source/license.html
++
++
++# Ascetic x86_64 AT&T to MASM/NASM assembler translator by .
++#
++# Why AT&T to MASM and not vice versa? Several reasons. Because AT&T
++# format is way easier to parse. Because it's simpler to "gear" from
++# Unix ABI to Windows one [see cross-reference "card" at the end of
++# file]. Because Linux targets were available first...
++#
++# In addition the script also "distills" code suitable for GNU
++# assembler, so that it can be compiled with more rigid assemblers,
++# such as Solaris /usr/ccs/bin/as.
++#
++# This translator is not designed to convert *arbitrary* assembler
++# code from AT&T format to MASM one. It's designed to convert just
++# enough to provide for dual-ABI OpenSSL modules development...
++# There *are* limitations and you might have to modify your assembler
++# code or this script to achieve the desired result...
++#
++# Currently recognized limitations:
++#
++# - can't use multiple ops per line;
++#
++# Dual-ABI styling rules.
++#
++# 1. Adhere to Unix register and stack layout [see cross-reference
++#    ABI "card" at the end for explanation].
++# 2. Forget about "red zone," stick to more traditional blended
++#    stack frame allocation. If volatile storage is actually required
++#    that is. If not, just leave the stack as is.
++# 3. Functions tagged with ".type name,@function" get crafted with
++#    unified Win64 prologue and epilogue automatically. If you want
++#    to take care of ABI differences yourself, tag functions as
++#    ".type name,@abi-omnipotent" instead.
++# 4. To optimize the Win64 prologue you can specify number of input
++#    arguments as ".type name,@function,N." Keep in mind that if N is
++#    larger than 6, then you *have to* write "abi-omnipotent" code,
++#    because >6 cases can't be addressed with unified prologue.
++# 5. Name local labels as .L*, do *not* use dynamic labels such as 1:
++#    (sorry about latter).
++# 6. Don't use [or hand-code with .byte] "rep ret." "ret" mnemonic is
++#    required to identify the spots, where to inject Win64 epilogue!
++#    But on the pros, it's then prefixed with rep automatically:-)
++# 7. Stick to explicit ip-relative addressing. If you have to use
++#    GOTPCREL addressing, stick to mov symbol@GOTPCREL(%rip),%r??.
++#    Both are recognized and translated to proper Win64 addressing
++#    modes. To support legacy code a synthetic directive, .picmeup,
++#    is implemented. It puts address of the *next* instruction into
++#    target register, e.g.:
++#
++#		.picmeup	%rax
++#		lea		.Label-.(%rax),%rax
++#
++# 8. In order to provide for structured exception handling unified
++#    Win64 prologue copies %rsp value to %rax. For further details
++#    see SEH paragraph at the end.
++# 9. .init segment is allowed to contain calls to functions only.
++# a. If function accepts more than 4 arguments *and* >4th argument
++#    is declared as non 64-bit value, do clear its upper part.
++
++
++use strict;
++
++my $flavour = shift;
++my $output  = shift;
++if ($flavour =~ /\./) { $output = $flavour; undef $flavour; }
++
++open STDOUT,">$output" || die "can't open $output: $!"
++	if (defined($output));
++
++my $gas=1;	$gas=0 if ($output =~ /\.asm$/);
++my $elf=1;	$elf=0 if (!$gas);
++my $win64=0;
++my $prefix="";
++my $decor=".L";
++
++my $masmref=8 + 50727*2**-32;	# 8.00.50727 shipped with VS2005
++my $masm=0;
++my $PTR=" PTR";
++
++my $nasmref=2.03;
++my $nasm=0;
++
++if    ($flavour eq "mingw64")	{ $gas=1; $elf=0; $win64=1;
++				  $prefix=`echo __USER_LABEL_PREFIX__ | $ENV{CC} -E -P -`;
++				  $prefix =~ s|\R$||; # Better chomp
++				}
++elsif ($flavour eq "macosx")	{ $gas=1; $elf=0; $prefix="_"; $decor="L\$"; }
++elsif ($flavour eq "masm")	{ $gas=0; $elf=0; $masm=$masmref; $win64=1; $decor="\$L\$"; }
++elsif ($flavour eq "nasm")	{ $gas=0; $elf=0; $nasm=$nasmref; $win64=1; $decor="\$L\$"; $PTR=""; }
++elsif (!$gas)
++{   if ($ENV{ASM} =~ m/nasm/ && `nasm -v` =~ m/version ([0-9]+)\.([0-9]+)/i)
++    {	$nasm = $1 + $2*0.01; $PTR="";  }
++    elsif (`ml64 2>&1` =~ m/Version ([0-9]+)\.([0-9]+)(\.([0-9]+))?/)
++    {	$masm = $1 + $2*2**-16 + $4*2**-32;   }
++    die "no assembler found on %PATH" if (!($nasm || $masm));
++    $win64=1;
++    $elf=0;
++    $decor="\$L\$";
++}
++
++my $current_segment;
++my $current_function;
++my %globals;
++
++{ package opcode;	# pick up opcodes
++    sub re {
++	my	($class, $line) = @_;
++	my	$self = {};
++	my	$ret;
++
++	if ($$line =~ /^([a-z][a-z0-9]*)/i) {
++	    bless $self,$class;
++	    $self->{op} = $1;
++	    $ret = $self;
++	    $$line = substr($$line,@+[0]); $$line =~ s/^\s+//;
++
++	    undef $self->{sz};
++	    if ($self->{op} =~ /^(movz)x?([bw]).*/) {	# movz is pain...
++		$self->{op} = $1;
++		$self->{sz} = $2;
++	    } elsif ($self->{op} =~ /call|jmp/) {
++		$self->{sz} = "";
++	    } elsif ($self->{op} =~ /^p/ && $' !~ /^(ush|op|insrw)/) { # SSEn
++		$self->{sz} = "";
++	    } elsif ($self->{op} =~ /^v/) { # VEX
++		$self->{sz} = "";
++	    } elsif ($self->{op} =~ /mov[dq]/ && $$line =~ /%xmm/) {
++		$self->{sz} = "";
++	    } elsif ($self->{op} =~ /([a-z]{3,})([qlwb])$/) {
++		$self->{op} = $1;
++		$self->{sz} = $2;
++	    }
++	}
++	$ret;
++    }
++    sub size {
++	my ($self, $sz) = @_;
++	$self->{sz} = $sz if (defined($sz) && !defined($self->{sz}));
++	$self->{sz};
++    }
++    sub out {
++	my $self = shift;
++	if ($gas) {
++	    if ($self->{op} eq "movz") {	# movz is pain...
++		sprintf "%s%s%s",$self->{op},$self->{sz},shift;
++	    } elsif ($self->{op} =~ /^set/) { 
++		"$self->{op}";
++	    } elsif ($self->{op} eq "ret") {
++		my $epilogue = "";
++		if ($win64 && $current_function->{abi} eq "svr4") {
++		    $epilogue = "movq	8(%rsp),%rdi\n\t" .
++				"movq	16(%rsp),%rsi\n\t";
++		}
++	    	$epilogue . ".byte	0xf3,0xc3";
++	    } elsif ($self->{op} eq "call" && !$elf && $current_segment eq ".init") {
++		".p2align\t3\n\t.quad";
++	    } else {
++		"$self->{op}$self->{sz}";
++	    }
++	} else {
++	    $self->{op} =~ s/^movz/movzx/;
++	    if ($self->{op} eq "ret") {
++		$self->{op} = "";
++		if ($win64 && $current_function->{abi} eq "svr4") {
++		    $self->{op} = "mov	rdi,QWORD$PTR\[8+rsp\]\t;WIN64 epilogue\n\t".
++				  "mov	rsi,QWORD$PTR\[16+rsp\]\n\t";
++	    	}
++		$self->{op} .= "DB\t0F3h,0C3h\t\t;repret";
++	    } elsif ($self->{op} =~ /^(pop|push)f/) {
++		$self->{op} .= $self->{sz};
++	    } elsif ($self->{op} eq "call" && $current_segment eq ".CRT\$XCU") {
++		$self->{op} = "\tDQ";
++	    } 
++	    $self->{op};
++	}
++    }
++    sub mnemonic {
++	my ($self, $op) = @_;
++	$self->{op}=$op if (defined($op));
++	$self->{op};
++    }
++}
++{ package const;	# pick up constants, which start with $
++    sub re {
++	my	($class, $line) = @_;
++	my	$self = {};
++	my	$ret;
++
++	if ($$line =~ /^\$([^,]+)/) {
++	    bless $self, $class;
++	    $self->{value} = $1;
++	    $ret = $self;
++	    $$line = substr($$line,@+[0]); $$line =~ s/^\s+//;
++	}
++	$ret;
++    }
++    sub out {
++    	my $self = shift;
++
++	$self->{value} =~ s/\b(0b[0-1]+)/oct($1)/eig;
++	if ($gas) {
++	    # Solaris /usr/ccs/bin/as can't handle multiplications
++	    # in $self->{value}
++	    my $value = $self->{value};
++	    no warnings;    # oct might complain about overflow, ignore here...
++	    $value =~ s/(?{value} = $value;
++	    }
++	    sprintf "\$%s",$self->{value};
++	} else {
++	    $self->{value} =~ s/0x([0-9a-f]+)/0$1h/ig if ($masm);
++	    sprintf "%s",$self->{value};
++	}
++    }
++}
++{ package ea;		# pick up effective addresses: expr(%reg,%reg,scale)
++    sub re {
++	my	($class, $line, $opcode) = @_;
++	my	$self = {};
++	my	$ret;
++
++	# optional * ----vvv--- appears in indirect jmp/call
++	if ($$line =~ /^(\*?)([^\(,]*)\(([%\w,]+)\)/) {
++	    bless $self, $class;
++	    $self->{asterisk} = $1;
++	    $self->{label} = $2;
++	    ($self->{base},$self->{index},$self->{scale})=split(/,/,$3);
++	    $self->{scale} = 1 if (!defined($self->{scale}));
++	    $ret = $self;
++	    $$line = substr($$line,@+[0]); $$line =~ s/^\s+//;
++
++	    if ($win64 && $self->{label} =~ s/\@GOTPCREL//) {
++		die if ($opcode->mnemonic() ne "mov");
++		$opcode->mnemonic("lea");
++	    }
++	    $self->{base}  =~ s/^%//;
++	    $self->{index} =~ s/^%// if (defined($self->{index}));
++	    $self->{opcode} = $opcode;
++	}
++	$ret;
++    }
++    sub size {}
++    sub out {
++	my ($self, $sz) = @_;
++
++	$self->{label} =~ s/([_a-z][_a-z0-9]*)/$globals{$1} or $1/gei;
++	$self->{label} =~ s/\.L/$decor/g;
++
++	# Silently convert all EAs to 64-bit. This is required for
++	# elder GNU assembler and results in more compact code,
++	# *but* most importantly AES module depends on this feature!
++	$self->{index} =~ s/^[er](.?[0-9xpi])[d]?$/r\1/;
++	$self->{base}  =~ s/^[er](.?[0-9xpi])[d]?$/r\1/;
++
++	# Solaris /usr/ccs/bin/as can't handle multiplications
++	# in $self->{label}...
++	use integer;
++	$self->{label} =~ s/(?{label} =~ s/\b([0-9]+\s*[\*\/\%]\s*[0-9]+)\b/eval($1)/eg;
++
++	# Some assemblers insist on signed presentation of 32-bit
++	# offsets, but sign extension is a tricky business in perl...
++	if ((1<<31)<<1) {
++	    $self->{label} =~ s/\b([0-9]+)\b/$1<<32>>32/eg;
++	} else {
++	    $self->{label} =~ s/\b([0-9]+)\b/$1>>0/eg;
++	}
++
++	if (!$self->{label} && $self->{index} && $self->{scale}==1 &&
++	    $self->{base} =~ /(rbp|r13)/) {
++		$self->{base} = $self->{index}; $self->{index} = $1;
++	}
++
++	if ($gas) {
++	    $self->{label} =~ s/^___imp_/__imp__/   if ($flavour eq "mingw64");
++
++	    if (defined($self->{index})) {
++		sprintf "%s%s(%s,%%%s,%d)",$self->{asterisk},
++					$self->{label},
++					$self->{base}?"%$self->{base}":"",
++					$self->{index},$self->{scale};
++	    } else {
++		sprintf "%s%s(%%%s)",	$self->{asterisk},$self->{label},$self->{base};
++	    }
++	} else {
++	    my %szmap = (	b=>"BYTE$PTR",  w=>"WORD$PTR",
++			l=>"DWORD$PTR", d=>"DWORD$PTR",
++	    		q=>"QWORD$PTR", o=>"OWORD$PTR",
++			x=>"XMMWORD$PTR", y=>"YMMWORD$PTR", z=>"ZMMWORD$PTR" );
++
++	    $self->{label} =~ s/\./\$/g;
++	    $self->{label} =~ s/(?{label} = "($self->{label})" if ($self->{label} =~ /[\*\+\-\/]/);
++
++	    my $mnemonic = $self->{opcode}->mnemonic();
++	    ($self->{asterisk})				&& ($sz="q") ||
++	    ($mnemonic =~ /^v?mov([qd])$/)		&& ($sz=$1)  ||
++	    ($mnemonic =~ /^v?pinsr([qdwb])$/)		&& ($sz=$1)  ||
++	    ($mnemonic =~ /^vpbroadcast([qdwb])$/)	&& ($sz=$1)  ||
++	    ($mnemonic =~ /^v(?!perm)[a-z]+[fi]128$/)	&& ($sz="x");
++
++	    if (defined($self->{index})) {
++		sprintf "%s[%s%s*%d%s]",$szmap{$sz},
++					$self->{label}?"$self->{label}+":"",
++					$self->{index},$self->{scale},
++					$self->{base}?"+$self->{base}":"";
++	    } elsif ($self->{base} eq "rip") {
++		sprintf "%s[%s]",$szmap{$sz},$self->{label};
++	    } else {
++		sprintf "%s[%s%s]",$szmap{$sz},
++					$self->{label}?"$self->{label}+":"",
++					$self->{base};
++	    }
++	}
++    }
++}
++{ package register;	# pick up registers, which start with %.
++    sub re {
++	my	($class, $line, $opcode) = @_;
++	my	$self = {};
++	my	$ret;
++
++	# optional * ----vvv--- appears in indirect jmp/call
++	if ($$line =~ /^(\*?)%(\w+)/) {
++	    bless $self,$class;
++	    $self->{asterisk} = $1;
++	    $self->{value} = $2;
++	    $opcode->size($self->size());
++	    $ret = $self;
++	    $$line = substr($$line,@+[0]); $$line =~ s/^\s+//;
++	}
++	$ret;
++    }
++    sub size {
++	my	$self = shift;
++	my	$ret;
++
++	if    ($self->{value} =~ /^r[\d]+b$/i)	{ $ret="b"; }
++	elsif ($self->{value} =~ /^r[\d]+w$/i)	{ $ret="w"; }
++	elsif ($self->{value} =~ /^r[\d]+d$/i)	{ $ret="l"; }
++	elsif ($self->{value} =~ /^r[\w]+$/i)	{ $ret="q"; }
++	elsif ($self->{value} =~ /^[a-d][hl]$/i){ $ret="b"; }
++	elsif ($self->{value} =~ /^[\w]{2}l$/i)	{ $ret="b"; }
++	elsif ($self->{value} =~ /^[\w]{2}$/i)	{ $ret="w"; }
++	elsif ($self->{value} =~ /^e[a-z]{2}$/i){ $ret="l"; }
++
++	$ret;
++    }
++    sub out {
++    	my $self = shift;
++	if ($gas)	{ sprintf "%s%%%s",$self->{asterisk},$self->{value}; }
++	else		{ $self->{value}; }
++    }
++}
++{ package label;	# pick up labels, which end with :
++    sub re {
++	my	($class, $line) = @_;
++	my	$self = {};
++	my	$ret;
++
++	if ($$line =~ /(^[\.\w]+)\:/) {
++	    bless $self,$class;
++	    $self->{value} = $1;
++	    $ret = $self;
++	    $$line = substr($$line,@+[0]); $$line =~ s/^\s+//;
++
++	    $self->{value} =~ s/^\.L/$decor/;
++	}
++	$ret;
++    }
++    sub out {
++	my $self = shift;
++
++	if ($gas) {
++	    my $func = ($globals{$self->{value}} or $self->{value}) . ":";
++	    if ($win64	&&
++			$current_function->{name} eq $self->{value} &&
++			$current_function->{abi} eq "svr4") {
++		$func .= "\n";
++		$func .= "	movq	%rdi,8(%rsp)\n";
++		$func .= "	movq	%rsi,16(%rsp)\n";
++		$func .= "	movq	%rsp,%rax\n";
++		$func .= "${decor}SEH_begin_$current_function->{name}:\n";
++		my $narg = $current_function->{narg};
++		$narg=6 if (!defined($narg));
++		$func .= "	movq	%rcx,%rdi\n" if ($narg>0);
++		$func .= "	movq	%rdx,%rsi\n" if ($narg>1);
++		$func .= "	movq	%r8,%rdx\n"  if ($narg>2);
++		$func .= "	movq	%r9,%rcx\n"  if ($narg>3);
++		$func .= "	movq	40(%rsp),%r8\n" if ($narg>4);
++		$func .= "	movq	48(%rsp),%r9\n" if ($narg>5);
++	    }
++	    $func;
++	} elsif ($self->{value} ne "$current_function->{name}") {
++	    # Make all labels in masm global.
++	    $self->{value} .= ":" if ($masm);
++	    $self->{value} . ":";
++	} elsif ($win64 && $current_function->{abi} eq "svr4") {
++	    my $func =	"$current_function->{name}" .
++			($nasm ? ":" : "\tPROC $current_function->{scope}") .
++			"\n";
++	    $func .= "	mov	QWORD$PTR\[8+rsp\],rdi\t;WIN64 prologue\n";
++	    $func .= "	mov	QWORD$PTR\[16+rsp\],rsi\n";
++	    $func .= "	mov	rax,rsp\n";
++	    $func .= "${decor}SEH_begin_$current_function->{name}:";
++	    $func .= ":" if ($masm);
++	    $func .= "\n";
++	    my $narg = $current_function->{narg};
++	    $narg=6 if (!defined($narg));
++	    $func .= "	mov	rdi,rcx\n" if ($narg>0);
++	    $func .= "	mov	rsi,rdx\n" if ($narg>1);
++	    $func .= "	mov	rdx,r8\n"  if ($narg>2);
++	    $func .= "	mov	rcx,r9\n"  if ($narg>3);
++	    $func .= "	mov	r8,QWORD$PTR\[40+rsp\]\n" if ($narg>4);
++	    $func .= "	mov	r9,QWORD$PTR\[48+rsp\]\n" if ($narg>5);
++	    $func .= "\n";
++	} else {
++	   "$current_function->{name}".
++			($nasm ? ":" : "\tPROC $current_function->{scope}");
++	}
++    }
++}
++{ package expr;		# pick up expressions
++    sub re {
++	my	($class, $line, $opcode) = @_;
++	my	$self = {};
++	my	$ret;
++
++	if ($$line =~ /(^[^,]+)/) {
++	    bless $self,$class;
++	    $self->{value} = $1;
++	    $ret = $self;
++	    $$line = substr($$line,@+[0]); $$line =~ s/^\s+//;
++
++	    $self->{value} =~ s/\@PLT// if (!$elf);
++	    $self->{value} =~ s/([_a-z][_a-z0-9]*)/$globals{$1} or $1/gei;
++	    $self->{value} =~ s/\.L/$decor/g;
++	    $self->{opcode} = $opcode;
++	}
++	$ret;
++    }
++    sub out {
++	my $self = shift;
++	if ($nasm && $self->{opcode}->mnemonic()=~m/^j(?![re]cxz)/) {
++	    "NEAR ".$self->{value};
++	} else {
++	    $self->{value};
++	}
++    }
++}
++{ package directive;	# pick up directives, which start with .
++    sub re {
++	my	($class, $line) = @_;
++	my	$self = {};
++	my	$ret;
++	my	$dir;
++	my	%opcode =	# lea 2f-1f(%rip),%dst; 1: nop; 2:
++		(	"%rax"=>0x01058d48,	"%rcx"=>0x010d8d48,
++			"%rdx"=>0x01158d48,	"%rbx"=>0x011d8d48,
++			"%rsp"=>0x01258d48,	"%rbp"=>0x012d8d48,
++			"%rsi"=>0x01358d48,	"%rdi"=>0x013d8d48,
++			"%r8" =>0x01058d4c,	"%r9" =>0x010d8d4c,
++			"%r10"=>0x01158d4c,	"%r11"=>0x011d8d4c,
++			"%r12"=>0x01258d4c,	"%r13"=>0x012d8d4c,
++			"%r14"=>0x01358d4c,	"%r15"=>0x013d8d4c	);
++
++	if ($$line =~ /^\s*(\.\w+)/) {
++	    bless $self,$class;
++	    $dir = $1;
++	    $ret = $self;
++	    undef $self->{value};
++	    $$line = substr($$line,@+[0]); $$line =~ s/^\s+//;
++
++	    SWITCH: for ($dir) {
++		/\.picmeup/ && do { if ($$line =~ /(%r[\w]+)/i) {
++			    		$dir="\t.long";
++					$$line=sprintf "0x%x,0x90000000",$opcode{$1};
++				    }
++				    last;
++				  };
++		/\.global|\.globl|\.extern/
++			    && do { $globals{$$line} = $prefix . $$line;
++				    $$line = $globals{$$line} if ($prefix);
++				    last;
++				  };
++		/\.type/    && do { my ($sym,$type,$narg) = split(',',$$line);
++				    if ($type eq "\@function") {
++					undef $current_function;
++					$current_function->{name} = $sym;
++					$current_function->{abi}  = "svr4";
++					$current_function->{narg} = $narg;
++					$current_function->{scope} = defined($globals{$sym})?"PUBLIC":"PRIVATE";
++				    } elsif ($type eq "\@abi-omnipotent") {
++					undef $current_function;
++					$current_function->{name} = $sym;
++					$current_function->{scope} = defined($globals{$sym})?"PUBLIC":"PRIVATE";
++				    }
++				    $$line =~ s/\@abi\-omnipotent/\@function/;
++				    $$line =~ s/\@function.*/\@function/;
++				    last;
++				  };
++		/\.asciz/   && do { if ($$line =~ /^"(.*)"$/) {
++					$dir  = ".byte";
++					$$line = join(",",unpack("C*",$1),0);
++				    }
++				    last;
++				  };
++		/\.rva|\.long|\.quad/
++			    && do { $$line =~ s/([_a-z][_a-z0-9]*)/$globals{$1} or $1/gei;
++				    $$line =~ s/\.L/$decor/g;
++				    last;
++				  };
++	    }
++
++	    if ($gas) {
++		$self->{value} = $dir . "\t" . $$line;
++
++		if ($dir =~ /\.extern/) {
++		    $self->{value} = ""; # swallow extern
++		} elsif (!$elf && $dir =~ /\.type/) {
++		    $self->{value} = "";
++		    $self->{value} = ".def\t" . ($globals{$1} or $1) . ";\t" .
++				(defined($globals{$1})?".scl 2;":".scl 3;") .
++				"\t.type 32;\t.endef"
++				if ($win64 && $$line =~ /([^,]+),\@function/);
++		} elsif (!$elf && $dir =~ /\.size/) {
++		    $self->{value} = "";
++		    if (defined($current_function)) {
++			$self->{value} .= "${decor}SEH_end_$current_function->{name}:"
++				if ($win64 && $current_function->{abi} eq "svr4");
++			undef $current_function;
++		    }
++		} elsif (!$elf && $dir =~ /\.align/) {
++		    $self->{value} = ".p2align\t" . (log($$line)/log(2));
++		} elsif ($dir eq ".section") {
++		    $current_segment=$$line;
++		    if (!$elf && $current_segment eq ".init") {
++			if	($flavour eq "macosx")	{ $self->{value} = ".mod_init_func"; }
++			elsif	($flavour eq "mingw64")	{ $self->{value} = ".section\t.ctors"; }
++		    }
++		} elsif ($dir =~ /\.(text|data)/) {
++		    $current_segment=".$1";
++		} elsif ($dir =~ /\.hidden/) {
++		    if    ($flavour eq "macosx")  { $self->{value} = ".private_extern\t$prefix$$line"; }
++		    elsif ($flavour eq "mingw64") { $self->{value} = ""; }
++		} elsif ($dir =~ /\.comm/) {
++		    $self->{value} = "$dir\t$prefix$$line";
++		    $self->{value} =~ s|,([0-9]+),([0-9]+)$|",$1,".log($2)/log(2)|e if ($flavour eq "macosx");
++		}
++		$$line = "";
++		return $self;
++	    }
++
++	    # non-gas case or nasm/masm
++	    SWITCH: for ($dir) {
++		/\.text/    && do { my $v=undef;
++				    if ($nasm) {
++					$v="section	.text code align=64\n";
++				    } else {
++					$v="$current_segment\tENDS\n" if ($current_segment);
++					$current_segment = ".text\$";
++					$v.="$current_segment\tSEGMENT ";
++					$v.=$masm>=$masmref ? "ALIGN(256)" : "PAGE";
++					$v.=" 'CODE'";
++				    }
++				    $self->{value} = $v;
++				    last;
++				  };
++		/\.data/    && do { my $v=undef;
++				    if ($nasm) {
++					$v="section	.data data align=8\n";
++				    } else {
++					$v="$current_segment\tENDS\n" if ($current_segment);
++					$current_segment = "_DATA";
++					$v.="$current_segment\tSEGMENT";
++				    }
++				    $self->{value} = $v;
++				    last;
++				  };
++		/\.section/ && do { my $v=undef;
++				    $$line =~ s/([^,]*).*/$1/;
++				    $$line = ".CRT\$XCU" if ($$line eq ".init");
++				    if ($nasm) {
++					$v="section	$$line";
++					if ($$line=~/\.([px])data/) {
++					    $v.=" rdata align=";
++					    $v.=$1 eq "p"? 4 : 8;
++					} elsif ($$line=~/\.CRT\$/i) {
++					    $v.=" rdata align=8";
++					}
++				    } else {
++					$v="$current_segment\tENDS\n" if ($current_segment);
++					$v.="$$line\tSEGMENT";
++					if ($$line=~/\.([px])data/) {
++					    $v.=" READONLY";
++					    $v.=" ALIGN(".($1 eq "p" ? 4 : 8).")" if ($masm>=$masmref);
++					} elsif ($$line=~/\.CRT\$/i) {
++					    $v.=" READONLY ";
++					    $v.=$masm>=$masmref ? "ALIGN(8)" : "DWORD";
++					}
++				    }
++				    $current_segment = $$line;
++				    $self->{value} = $v;
++				    last;
++				  };
++		/\.extern/  && do { $self->{value}  = "EXTERN\t".$$line;
++				    $self->{value} .= ":NEAR" if ($masm);
++				    last;
++				  };
++		/\.globl|.global/
++			    && do { $self->{value}  = $masm?"PUBLIC":"global";
++				    $self->{value} .= "\t".$$line;
++				    last;
++				  };
++		/\.size/    && do { if (defined($current_function)) {
++					undef $self->{value};
++					if ($current_function->{abi} eq "svr4") {
++					    $self->{value}="${decor}SEH_end_$current_function->{name}:";
++					    $self->{value}.=":\n" if($masm);
++					}
++					$self->{value}.="$current_function->{name}\tENDP" if($masm && $current_function->{name});
++					undef $current_function;
++				    }
++				    last;
++				  };
++		/\.align/   && do { my $max = ($masm && $masm>=$masmref) ? 256 : 4096;
++				    $self->{value} = "ALIGN\t".($$line>$max?$max:$$line);
++				    last;
++				  };
++		/\.(value|long|rva|quad)/
++			    && do { my $sz  = substr($1,0,1);
++				    my @arr = split(/,\s*/,$$line);
++				    my $last = pop(@arr);
++				    my $conv = sub  {	my $var=shift;
++							$var=~s/^(0b[0-1]+)/oct($1)/eig;
++							$var=~s/^0x([0-9a-f]+)/0$1h/ig if ($masm);
++							if ($sz eq "D" && ($current_segment=~/.[px]data/ || $dir eq ".rva"))
++							{ $var=~s/([_a-z\$\@][_a-z0-9\$\@]*)/$nasm?"$1 wrt ..imagebase":"imagerel $1"/egi; }
++							$var;
++						    };  
++
++				    $sz =~ tr/bvlrq/BWDDQ/;
++				    $self->{value} = "\tD$sz\t";
++				    for (@arr) { $self->{value} .= &$conv($_).","; }
++				    $self->{value} .= &$conv($last);
++				    last;
++				  };
++		/\.byte/    && do { my @str=split(/,\s*/,$$line);
++				    map(s/(0b[0-1]+)/oct($1)/eig,@str);
++				    map(s/0x([0-9a-f]+)/0$1h/ig,@str) if ($masm);	
++				    while ($#str>15) {
++					$self->{value}.="DB\t"
++						.join(",",@str[0..15])."\n";
++					foreach (0..15) { shift @str; }
++				    }
++				    $self->{value}.="DB\t"
++						.join(",",@str) if (@str);
++				    last;
++				  };
++		/\.comm/    && do { my @str=split(/,\s*/,$$line);
++				    my $v=undef;
++				    if ($nasm) {
++					$v.="common	$prefix@str[0] @str[1]";
++				    } else {
++					$v="$current_segment\tENDS\n" if ($current_segment);
++					$current_segment = "_DATA";
++					$v.="$current_segment\tSEGMENT\n";
++					$v.="COMM	@str[0]:DWORD:".@str[1]/4;
++				    }
++				    $self->{value} = $v;
++				    last;
++				  };
++	    }
++	    $$line = "";
++	}
++
++	$ret;
++    }
++    sub out {
++	my $self = shift;
++	$self->{value};
++    }
++}
++
++sub rex {
++ my $opcode=shift;
++ my ($dst,$src,$rex)=@_;
++
++   $rex|=0x04 if($dst>=8);
++   $rex|=0x01 if($src>=8);
++   push @$opcode,($rex|0x40) if ($rex);
++}
++
++# Upon initial x86_64 introduction SSE>2 extensions were not introduced
++# yet. In order not to be bothered by tracing exact assembler versions,
++# but at the same time to provide a bare security minimum of AES-NI, we
++# hard-code some instructions. Extensions past AES-NI on the other hand
++# are traced by examining assembler version in individual perlasm
++# modules...
++
++my %regrm = (	"%eax"=>0, "%ecx"=>1, "%edx"=>2, "%ebx"=>3,
++		"%esp"=>4, "%ebp"=>5, "%esi"=>6, "%edi"=>7	);
++
++my $movq = sub {	# elderly gas can't handle inter-register movq
++  my $arg = shift;
++  my @opcode=(0x66);
++    if ($arg =~ /%xmm([0-9]+),\s*%r(\w+)/) {
++	my ($src,$dst)=($1,$2);
++	if ($dst !~ /[0-9]+/)	{ $dst = $regrm{"%e$dst"}; }
++	rex(\@opcode,$src,$dst,0x8);
++	push @opcode,0x0f,0x7e;
++	push @opcode,0xc0|(($src&7)<<3)|($dst&7);	# ModR/M
++	@opcode;
++    } elsif ($arg =~ /%r(\w+),\s*%xmm([0-9]+)/) {
++	my ($src,$dst)=($2,$1);
++	if ($dst !~ /[0-9]+/)	{ $dst = $regrm{"%e$dst"}; }
++	rex(\@opcode,$src,$dst,0x8);
++	push @opcode,0x0f,0x6e;
++	push @opcode,0xc0|(($src&7)<<3)|($dst&7);	# ModR/M
++	@opcode;
++    } else {
++	();
++    }
++};
++
++my $pextrd = sub {
++    if (shift =~ /\$([0-9]+),\s*%xmm([0-9]+),\s*(%\w+)/) {
++      my @opcode=(0x66);
++	my $imm=$1;
++	my $src=$2;
++	my $dst=$3;
++	if ($dst =~ /%r([0-9]+)d/)	{ $dst = $1; }
++	elsif ($dst =~ /%e/)		{ $dst = $regrm{$dst}; }
++	rex(\@opcode,$src,$dst);
++	push @opcode,0x0f,0x3a,0x16;
++	push @opcode,0xc0|(($src&7)<<3)|($dst&7);	# ModR/M
++	push @opcode,$imm;
++	@opcode;
++    } else {
++	();
++    }
++};
++
++my $pinsrd = sub {
++    if (shift =~ /\$([0-9]+),\s*(%\w+),\s*%xmm([0-9]+)/) {
++      my @opcode=(0x66);
++	my $imm=$1;
++	my $src=$2;
++	my $dst=$3;
++	if ($src =~ /%r([0-9]+)/)	{ $src = $1; }
++	elsif ($src =~ /%e/)		{ $src = $regrm{$src}; }
++	rex(\@opcode,$dst,$src);
++	push @opcode,0x0f,0x3a,0x22;
++	push @opcode,0xc0|(($dst&7)<<3)|($src&7);	# ModR/M
++	push @opcode,$imm;
++	@opcode;
++    } else {
++	();
++    }
++};
++
++my $pshufb = sub {
++    if (shift =~ /%xmm([0-9]+),\s*%xmm([0-9]+)/) {
++      my @opcode=(0x66);
++	rex(\@opcode,$2,$1);
++	push @opcode,0x0f,0x38,0x00;
++	push @opcode,0xc0|($1&7)|(($2&7)<<3);		# ModR/M
++	@opcode;
++    } else {
++	();
++    }
++};
++
++my $palignr = sub {
++    if (shift =~ /\$([0-9]+),\s*%xmm([0-9]+),\s*%xmm([0-9]+)/) {
++      my @opcode=(0x66);
++	rex(\@opcode,$3,$2);
++	push @opcode,0x0f,0x3a,0x0f;
++	push @opcode,0xc0|($2&7)|(($3&7)<<3);		# ModR/M
++	push @opcode,$1;
++	@opcode;
++    } else {
++	();
++    }
++};
++
++my $pclmulqdq = sub {
++    if (shift =~ /\$([x0-9a-f]+),\s*%xmm([0-9]+),\s*%xmm([0-9]+)/) {
++      my @opcode=(0x66);
++	rex(\@opcode,$3,$2);
++	push @opcode,0x0f,0x3a,0x44;
++	push @opcode,0xc0|($2&7)|(($3&7)<<3);		# ModR/M
++	my $c=$1;
++	push @opcode,$c=~/^0/?oct($c):$c;
++	@opcode;
++    } else {
++	();
++    }
++};
++
++my $rdrand = sub {
++    if (shift =~ /%[er](\w+)/) {
++      my @opcode=();
++      my $dst=$1;
++	if ($dst !~ /[0-9]+/) { $dst = $regrm{"%e$dst"}; }
++	rex(\@opcode,0,$dst,8);
++	push @opcode,0x0f,0xc7,0xf0|($dst&7);
++	@opcode;
++    } else {
++	();
++    }
++};
++
++my $rdseed = sub {
++    if (shift =~ /%[er](\w+)/) {
++      my @opcode=();
++      my $dst=$1;
++	if ($dst !~ /[0-9]+/) { $dst = $regrm{"%e$dst"}; }
++	rex(\@opcode,0,$dst,8);
++	push @opcode,0x0f,0xc7,0xf8|($dst&7);
++	@opcode;
++    } else {
++	();
++    }
++};
++
++sub rxb {
++ my $opcode=shift;
++ my ($dst,$src1,$src2,$rxb)=@_;
++
++   $rxb|=0x7<<5;
++   $rxb&=~(0x04<<5) if($dst>=8);
++   $rxb&=~(0x01<<5) if($src1>=8);
++   $rxb&=~(0x02<<5) if($src2>=8);
++   push @$opcode,$rxb;
++}
++
++my $vprotd = sub {
++    if (shift =~ /\$([x0-9a-f]+),\s*%xmm([0-9]+),\s*%xmm([0-9]+)/) {
++      my @opcode=(0x8f);
++	rxb(\@opcode,$3,$2,-1,0x08);
++	push @opcode,0x78,0xc2;
++	push @opcode,0xc0|($2&7)|(($3&7)<<3);		# ModR/M
++	my $c=$1;
++	push @opcode,$c=~/^0/?oct($c):$c;
++	@opcode;
++    } else {
++	();
++    }
++};
++
++my $vprotq = sub {
++    if (shift =~ /\$([x0-9a-f]+),\s*%xmm([0-9]+),\s*%xmm([0-9]+)/) {
++      my @opcode=(0x8f);
++	rxb(\@opcode,$3,$2,-1,0x08);
++	push @opcode,0x78,0xc3;
++	push @opcode,0xc0|($2&7)|(($3&7)<<3);		# ModR/M
++	my $c=$1;
++	push @opcode,$c=~/^0/?oct($c):$c;
++	@opcode;
++    } else {
++	();
++    }
++};
++
++my $endbranch = sub {
++    (0xf3,0x0f,0x1e,0xfa);
++};
++
++if ($nasm) {
++    print <<___;
++default	rel
++%define XMMWORD
++%define YMMWORD
++%define ZMMWORD
++___
++} elsif ($masm) {
++    print <<___;
++OPTION	DOTNAME
++___
++}
++while(defined(my $line=<>)) {
++
++    $line =~ s|\R$||;           # Better chomp
++
++    $line =~ s|[#!].*$||;	# get rid of asm-style comments...
++    $line =~ s|/\*.*\*/||;	# ... and C-style comments...
++    $line =~ s|^\s+||;		# ... and skip white spaces in beginning
++    $line =~ s|\s+$||;		# ... and at the end
++
++    if (my $label=label->re(\$line))	{ print $label->out(); }
++
++    if (my $directive=directive->re(\$line)) {
++	printf "%s",$directive->out();
++    } elsif (my $opcode=opcode->re(\$line)) {
++	my $asm = eval("\$".$opcode->mnemonic());
++	
++	if ((ref($asm) eq 'CODE') && scalar(my @bytes=&$asm($line))) {
++	    print $gas?".byte\t":"DB\t",join(',',@bytes),"\n";
++	    next;
++	}
++
++	my @args;
++	ARGUMENT: while (1) {
++	    my $arg;
++
++	    ($arg=register->re(\$line, $opcode))||
++	    ($arg=const->re(\$line))		||
++	    ($arg=ea->re(\$line, $opcode))	||
++	    ($arg=expr->re(\$line, $opcode))	||
++	    last ARGUMENT;
++
++	    push @args,$arg;
++
++	    last ARGUMENT if ($line !~ /^,/);
++
++	    $line =~ s/^,\s*//;
++	} # ARGUMENT:
++
++	if ($#args>=0) {
++	    my $insn;
++	    my $sz=$opcode->size();
++
++	    if ($gas) {
++		$insn = $opcode->out($#args>=1?$args[$#args]->size():$sz);
++		@args = map($_->out($sz),@args);
++		printf "\t%s\t%s",$insn,join(",",@args);
++	    } else {
++		$insn = $opcode->out();
++		foreach (@args) {
++		    my $arg = $_->out();
++		    # $insn.=$sz compensates for movq, pinsrw, ...
++		    if ($arg =~ /^xmm[0-9]+$/) { $insn.=$sz; $sz="x" if(!$sz); last; }
++		    if ($arg =~ /^ymm[0-9]+$/) { $insn.=$sz; $sz="y" if(!$sz); last; }
++		    if ($arg =~ /^zmm[0-9]+$/) { $insn.=$sz; $sz="z" if(!$sz); last; }
++		    if ($arg =~ /^mm[0-9]+$/)  { $insn.=$sz; $sz="q" if(!$sz); last; }
++		}
++		@args = reverse(@args);
++		undef $sz if ($nasm && $opcode->mnemonic() eq "lea");
++		printf "\t%s\t%s",$insn,join(",",map($_->out($sz),@args));
++	    }
++	} else {
++	    printf "\t%s",$opcode->out();
++	}
++    }
++
++    print $line,"\n";
++}
++
++print "\n$current_segment\tENDS\n"	if ($current_segment && $masm);
++print "END\n"				if ($masm);
++
++close STDOUT;
++
++#################################################
++# Cross-reference x86_64 ABI "card"
++#
++# 		Unix		Win64
++# %rax		*		*
++# %rbx		-		-
++# %rcx		#4		#1
++# %rdx		#3		#2
++# %rsi		#2		-
++# %rdi		#1		-
++# %rbp		-		-
++# %rsp		-		-
++# %r8		#5		#3
++# %r9		#6		#4
++# %r10		*		*
++# %r11		*		*
++# %r12		-		-
++# %r13		-		-
++# %r14		-		-
++# %r15		-		-
++# 
++# (*)	volatile register
++# (-)	preserved by callee
++# (#)	Nth argument, volatile
++#
++# In Unix terms top of stack is argument transfer area for arguments
++# which could not be accommodated in registers. Or in other words 7th
++# [integer] argument resides at 8(%rsp) upon function entry point.
++# 128 bytes above %rsp constitute a "red zone" which is not touched
++# by signal handlers and can be used as temporal storage without
++# allocating a frame.
++#
++# In Win64 terms N*8 bytes on top of stack is argument transfer area,
++# which belongs to/can be overwritten by callee. N is the number of
++# arguments passed to callee, *but* not less than 4! This means that
++# upon function entry point 5th argument resides at 40(%rsp), as well
++# as that 32 bytes from 8(%rsp) can always be used as temporal
++# storage [without allocating a frame]. One can actually argue that
++# one can assume a "red zone" above stack pointer under Win64 as well.
++# Point is that at apparently no occasion Windows kernel would alter
++# the area above user stack pointer in true asynchronous manner...
++#
++# All the above means that if assembler programmer adheres to Unix
++# register and stack layout, but disregards the "red zone" existence,
++# it's possible to use following prologue and epilogue to "gear" from
++# Unix to Win64 ABI in leaf functions with not more than 6 arguments.
++#
++# omnipotent_function:
++# ifdef WIN64
++#	movq	%rdi,8(%rsp)
++#	movq	%rsi,16(%rsp)
++#	movq	%rcx,%rdi	; if 1st argument is actually present
++#	movq	%rdx,%rsi	; if 2nd argument is actually ...
++#	movq	%r8,%rdx	; if 3rd argument is ...
++#	movq	%r9,%rcx	; if 4th argument ...
++#	movq	40(%rsp),%r8	; if 5th ...
++#	movq	48(%rsp),%r9	; if 6th ...
++# endif
++#	...
++# ifdef WIN64
++#	movq	8(%rsp),%rdi
++#	movq	16(%rsp),%rsi
++# endif
++#	ret
++#
++#################################################
++# Win64 SEH, Structured Exception Handling.
++#
++# Unlike on Unix systems(*) lack of Win64 stack unwinding information
++# has undesired side-effect at run-time: if an exception is raised in
++# assembler subroutine such as those in question (basically we're
++# referring to segmentation violations caused by malformed input
++# parameters), the application is briskly terminated without invoking
++# any exception handlers, most notably without generating memory dump
++# or any user notification whatsoever. This poses a problem. It's
++# possible to address it by registering custom language-specific
++# handler that would restore processor context to the state at
++# subroutine entry point and return "exception is not handled, keep
++# unwinding" code. Writing such handler can be a challenge... But it's
++# doable, though requires certain coding convention. Consider following
++# snippet:
++#
++# .type	function,@function
++# function:
++#	movq	%rsp,%rax	# copy rsp to volatile register
++#	pushq	%r15		# save non-volatile registers
++#	pushq	%rbx
++#	pushq	%rbp
++#	movq	%rsp,%r11
++#	subq	%rdi,%r11	# prepare [variable] stack frame
++#	andq	$-64,%r11
++#	movq	%rax,0(%r11)	# check for exceptions
++#	movq	%r11,%rsp	# allocate [variable] stack frame
++#	movq	%rax,0(%rsp)	# save original rsp value
++# magic_point:
++#	...
++#	movq	0(%rsp),%rcx	# pull original rsp value
++#	movq	-24(%rcx),%rbp	# restore non-volatile registers
++#	movq	-16(%rcx),%rbx
++#	movq	-8(%rcx),%r15
++#	movq	%rcx,%rsp	# restore original rsp
++#	ret
++# .size function,.-function
++#
++# The key is that up to magic_point copy of original rsp value remains
++# in chosen volatile register and no non-volatile register, except for
++# rsp, is modified. While past magic_point rsp remains constant till
++# the very end of the function. In this case custom language-specific
++# exception handler would look like this:
++#
++# EXCEPTION_DISPOSITION handler (EXCEPTION_RECORD *rec,ULONG64 frame,
++#		CONTEXT *context,DISPATCHER_CONTEXT *disp)
++# {	ULONG64 *rsp = (ULONG64 *)context->Rax;
++#	if (context->Rip >= magic_point)
++#	{   rsp = ((ULONG64 **)context->Rsp)[0];
++#	    context->Rbp = rsp[-3];
++#	    context->Rbx = rsp[-2];
++#	    context->R15 = rsp[-1];
++#	}
++#	context->Rsp = (ULONG64)rsp;
++#	context->Rdi = rsp[1];
++#	context->Rsi = rsp[2];
++#
++#	memcpy (disp->ContextRecord,context,sizeof(CONTEXT));
++#	RtlVirtualUnwind(UNW_FLAG_NHANDLER,disp->ImageBase,
++#		dips->ControlPc,disp->FunctionEntry,disp->ContextRecord,
++#		&disp->HandlerData,&disp->EstablisherFrame,NULL);
++#	return ExceptionContinueSearch;
++# }
++#
++# It's appropriate to implement this handler in assembler, directly in
++# function's module. In order to do that one has to know members'
++# offsets in CONTEXT and DISPATCHER_CONTEXT structures and some constant
++# values. Here they are:
++#
++#	CONTEXT.Rax				120
++#	CONTEXT.Rcx				128
++#	CONTEXT.Rdx				136
++#	CONTEXT.Rbx				144
++#	CONTEXT.Rsp				152
++#	CONTEXT.Rbp				160
++#	CONTEXT.Rsi				168
++#	CONTEXT.Rdi				176
++#	CONTEXT.R8				184
++#	CONTEXT.R9				192
++#	CONTEXT.R10				200
++#	CONTEXT.R11				208
++#	CONTEXT.R12				216
++#	CONTEXT.R13				224
++#	CONTEXT.R14				232
++#	CONTEXT.R15				240
++#	CONTEXT.Rip				248
++#	CONTEXT.Xmm6				512
++#	sizeof(CONTEXT)				1232
++#	DISPATCHER_CONTEXT.ControlPc		0
++#	DISPATCHER_CONTEXT.ImageBase		8
++#	DISPATCHER_CONTEXT.FunctionEntry	16
++#	DISPATCHER_CONTEXT.EstablisherFrame	24
++#	DISPATCHER_CONTEXT.TargetIp		32
++#	DISPATCHER_CONTEXT.ContextRecord	40
++#	DISPATCHER_CONTEXT.LanguageHandler	48
++#	DISPATCHER_CONTEXT.HandlerData		56
++#	UNW_FLAG_NHANDLER			0
++#	ExceptionContinueSearch			1
++#
++# In order to tie the handler to the function one has to compose
++# couple of structures: one for .xdata segment and one for .pdata.
++#
++# UNWIND_INFO structure for .xdata segment would be
++#
++# function_unwind_info:
++#	.byte	9,0,0,0
++#	.rva	handler
++#
++# This structure designates exception handler for a function with
++# zero-length prologue, no stack frame or frame register.
++#
++# To facilitate composing of .pdata structures, auto-generated "gear"
++# prologue copies rsp value to rax and denotes next instruction with
++# .LSEH_begin_{function_name} label. This essentially defines the SEH
++# styling rule mentioned in the beginning. Position of this label is
++# chosen in such manner that possible exceptions raised in the "gear"
++# prologue would be accounted to caller and unwound from latter's frame.
++# End of function is marked with respective .LSEH_end_{function_name}
++# label. To summarize, .pdata segment would contain
++#
++#	.rva	.LSEH_begin_function
++#	.rva	.LSEH_end_function
++#	.rva	function_unwind_info
++#
++# Reference to function_unwind_info from .xdata segment is the anchor.
++# In case you wonder why references are 32-bit .rvas and not 64-bit
++# .quads. References put into these two segments are required to be
++# *relative* to the base address of the current binary module, a.k.a.
++# image base. No Win64 module, be it .exe or .dll, can be larger than
++# 2GB and thus such relative references can be and are accommodated in
++# 32 bits.
++#
++# Having reviewed the example function code, one can argue that "movq
++# %rsp,%rax" above is redundant. It is not! Keep in mind that on Unix
++# rax would contain an undefined value. If this "offends" you, use
++# another register and refrain from modifying rax till magic_point is
++# reached, i.e. as if it was a non-volatile register. If more registers
++# are required prior [variable] frame setup is completed, note that
++# nobody says that you can have only one "magic point." You can
++# "liberate" non-volatile registers by denoting last stack off-load
++# instruction and reflecting it in finer grade unwind logic in handler.
++# After all, isn't it why it's called *language-specific* handler...
++#
++# Attentive reader can notice that exceptions would be mishandled in
++# auto-generated "gear" epilogue. Well, exception effectively can't
++# occur there, because if memory area used by it was subject to
++# segmentation violation, then it would be raised upon call to the
++# function (and as already mentioned be accounted to caller, which is
++# not a problem). If you're still not comfortable, then define tail
++# "magic point" just prior ret instruction and have handler treat it...
++#
++# (*)	Note that we're talking about run-time, not debug-time. Lack of
++#	unwind information makes debugging hard on both Windows and
++#	Unix. "Unlike" referes to the fact that on Unix signal handler
++#	will always be invoked, core dumped and appropriate exit code
++#	returned to parent (for user notification).
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/perlasm/x86asm.pl b/CryptoPkg/Library/OpensslLib/openssl/crypto/perlasm/x86asm.pl
+new file mode 100644
+index 0000000..1ff46c9
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/perlasm/x86asm.pl
+@@ -0,0 +1,310 @@
++#! /usr/bin/env perl
++# Copyright 1995-2016 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
++# in the file LICENSE in the source distribution or at
++# https://www.openssl.org/source/license.html
++
++
++# require 'x86asm.pl';
++# &asm_init(,"des-586.pl"[,$i386only]);
++# &function_begin("foo");
++# ...
++# &function_end("foo");
++# &asm_finish
++
++$out=();
++$i386=0;
++
++# AUTOLOAD is this context has quite unpleasant side effect, namely
++# that typos in function calls effectively go to assembler output,
++# but on the pros side we don't have to implement one subroutine per
++# each opcode...
++sub ::AUTOLOAD
++{ my $opcode = $AUTOLOAD;
++
++    die "more than 4 arguments passed to $opcode" if ($#_>3);
++
++    $opcode =~ s/.*:://;
++    if    ($opcode =~ /^push/) { $stack+=4; }
++    elsif ($opcode =~ /^pop/)  { $stack-=4; }
++
++    &generic($opcode,@_) or die "undefined subroutine \&$AUTOLOAD";
++}
++
++sub ::emit
++{ my $opcode=shift;
++
++    if ($#_==-1)    { push(@out,"\t$opcode\n");				}
++    else            { push(@out,"\t$opcode\t".join(',',@_)."\n");	}
++}
++
++sub ::LB
++{   $_[0] =~ m/^e?([a-d])x$/o or die "$_[0] does not have a 'low byte'";
++  $1."l";
++}
++sub ::HB
++{   $_[0] =~ m/^e?([a-d])x$/o or die "$_[0] does not have a 'high byte'";
++  $1."h";
++}
++sub ::stack_push{ my $num=$_[0]*4; $stack+=$num; &sub("esp",$num);	}
++sub ::stack_pop	{ my $num=$_[0]*4; $stack-=$num; &add("esp",$num);	}
++sub ::blindpop	{ &pop($_[0]); $stack+=4;				}
++sub ::wparam	{ &DWP($stack+4*$_[0],"esp");				}
++sub ::swtmp	{ &DWP(4*$_[0],"esp");					}
++
++sub ::bswap
++{   if ($i386)	# emulate bswap for i386
++    {	&comment("bswap @_");
++	&xchg(&HB(@_),&LB(@_));
++	&ror (@_,16);
++	&xchg(&HB(@_),&LB(@_));
++    }
++    else
++    {	&generic("bswap",@_);	}
++}
++# These are made-up opcodes introduced over the years essentially
++# by ignorance, just alias them to real ones...
++sub ::movb	{ &mov(@_);	}
++sub ::xorb	{ &xor(@_);	}
++sub ::rotl	{ &rol(@_);	}
++sub ::rotr	{ &ror(@_);	}
++sub ::exch	{ &xchg(@_);	}
++sub ::halt	{ &hlt;		}
++sub ::movz	{ &movzx(@_);	}
++sub ::pushf	{ &pushfd;	}
++sub ::popf	{ &popfd;	}
++
++# 3 argument instructions
++sub ::movq
++{ my($p1,$p2,$optimize)=@_;
++
++    if ($optimize && $p1=~/^mm[0-7]$/ && $p2=~/^mm[0-7]$/)
++    # movq between mmx registers can sink Intel CPUs
++    {	&::pshufw($p1,$p2,0xe4);		}
++    else
++    {	&::generic("movq",@_);			}
++}
++
++# SSE>2 instructions
++my %regrm = (	"eax"=>0, "ecx"=>1, "edx"=>2, "ebx"=>3,
++		"esp"=>4, "ebp"=>5, "esi"=>6, "edi"=>7	);
++sub ::pextrd
++{ my($dst,$src,$imm)=@_;
++    if ("$dst:$src" =~ /(e[a-dsd][ixp]):xmm([0-7])/)
++    {	&::data_byte(0x66,0x0f,0x3a,0x16,0xc0|($2<<3)|$regrm{$1},$imm);	}
++    else
++    {	&::generic("pextrd",@_);		}
++}
++
++sub ::pinsrd
++{ my($dst,$src,$imm)=@_;
++    if ("$dst:$src" =~ /xmm([0-7]):(e[a-dsd][ixp])/)
++    {	&::data_byte(0x66,0x0f,0x3a,0x22,0xc0|($1<<3)|$regrm{$2},$imm);	}
++    else
++    {	&::generic("pinsrd",@_);		}
++}
++
++sub ::pshufb
++{ my($dst,$src)=@_;
++    if ("$dst:$src" =~ /xmm([0-7]):xmm([0-7])/)
++    {	&data_byte(0x66,0x0f,0x38,0x00,0xc0|($1<<3)|$2);	}
++    else
++    {	&::generic("pshufb",@_);		}
++}
++
++sub ::palignr
++{ my($dst,$src,$imm)=@_;
++    if ("$dst:$src" =~ /xmm([0-7]):xmm([0-7])/)
++    {	&::data_byte(0x66,0x0f,0x3a,0x0f,0xc0|($1<<3)|$2,$imm);	}
++    else
++    {	&::generic("palignr",@_);		}
++}
++
++sub ::pclmulqdq
++{ my($dst,$src,$imm)=@_;
++    if ("$dst:$src" =~ /xmm([0-7]):xmm([0-7])/)
++    {	&::data_byte(0x66,0x0f,0x3a,0x44,0xc0|($1<<3)|$2,$imm);	}
++    else
++    {	&::generic("pclmulqdq",@_);		}
++}
++
++sub ::rdrand
++{ my ($dst)=@_;
++    if ($dst =~ /(e[a-dsd][ixp])/)
++    {	&::data_byte(0x0f,0xc7,0xf0|$regrm{$dst});	}
++    else
++    {	&::generic("rdrand",@_);	}
++}
++
++sub ::rdseed
++{ my ($dst)=@_;
++    if ($dst =~ /(e[a-dsd][ixp])/)
++    {	&::data_byte(0x0f,0xc7,0xf8|$regrm{$dst});	}
++    else
++    {	&::generic("rdrand",@_);	}
++}
++
++sub rxb {
++ local *opcode=shift;
++ my ($dst,$src1,$src2,$rxb)=@_;
++
++   $rxb|=0x7<<5;
++   $rxb&=~(0x04<<5) if($dst>=8);
++   $rxb&=~(0x01<<5) if($src1>=8);
++   $rxb&=~(0x02<<5) if($src2>=8);
++   push @opcode,$rxb;
++}
++
++sub ::vprotd
++{ my $args=join(',',@_);
++    if ($args =~ /xmm([0-7]),xmm([0-7]),([x0-9a-f]+)/)
++    { my @opcode=(0x8f);
++	rxb(\@opcode,$1,$2,-1,0x08);
++	push @opcode,0x78,0xc2;
++	push @opcode,0xc0|($2&7)|(($1&7)<<3);		# ModR/M
++	my $c=$3;
++	push @opcode,$c=~/^0/?oct($c):$c;
++	&::data_byte(@opcode);
++    }
++    else
++    {	&::generic("vprotd",@_);	}
++}
++
++sub ::endbranch
++{
++    &::data_byte(0xf3,0x0f,0x1e,0xfb);
++}
++
++# label management
++$lbdecor="L";		# local label decoration, set by package
++$label="000";
++
++sub ::islabel		# see is argument is a known label
++{ my $i;
++    foreach $i (values %label) { return $i if ($i eq $_[0]); }
++  $label{$_[0]};	# can be undef
++}
++
++sub ::label		# instantiate a function-scope label
++{   if (!defined($label{$_[0]}))
++    {	$label{$_[0]}="${lbdecor}${label}${_[0]}"; $label++;   }
++  $label{$_[0]};
++}
++
++sub ::LABEL		# instantiate a file-scope label
++{   $label{$_[0]}=$_[1] if (!defined($label{$_[0]}));
++  $label{$_[0]};
++}
++
++sub ::static_label	{ &::LABEL($_[0],$lbdecor.$_[0]); }
++
++sub ::set_label_B	{ push(@out,"@_:\n"); }
++sub ::set_label
++{ my $label=&::label($_[0]);
++    &::align($_[1]) if ($_[1]>1);
++    &::set_label_B($label);
++  $label;
++}
++
++sub ::wipe_labels	# wipes function-scope labels
++{   foreach $i (keys %label)
++    {	delete $label{$i} if ($label{$i} =~ /^\Q${lbdecor}\E[0-9]{3}/);	}
++}
++
++# subroutine management
++sub ::function_begin
++{   &function_begin_B(@_);
++    $stack=4;
++    &push("ebp");
++    &push("ebx");
++    &push("esi");
++    &push("edi");
++}
++
++sub ::function_end
++{   &pop("edi");
++    &pop("esi");
++    &pop("ebx");
++    &pop("ebp");
++    &ret();
++    &function_end_B(@_);
++    $stack=0;
++    &wipe_labels();
++}
++
++sub ::function_end_A
++{   &pop("edi");
++    &pop("esi");
++    &pop("ebx");
++    &pop("ebp");
++    &ret();
++    $stack+=16;	# readjust esp as if we didn't pop anything
++}
++
++sub ::asciz
++{ my @str=unpack("C*",shift);
++    push @str,0;
++    while ($#str>15) {
++	&data_byte(@str[0..15]);
++	foreach (0..15) { shift @str; }
++    }
++    &data_byte(@str) if (@str);
++}
++
++sub ::asm_finish
++{   &file_end();
++    print @out;
++}
++
++sub ::asm_init
++{ my ($type,$fn,$cpu)=@_;
++
++    $filename=$fn;
++    $i386=$cpu;
++
++    $elf=$cpp=$coff=$aout=$macosx=$win32=$netware=$mwerks=$android=0;
++    if    (($type eq "elf"))
++    {	$elf=1;			require "x86gas.pl";	}
++    elsif (($type eq "elf-1"))
++    {	$elf=-1;		require "x86gas.pl";	}
++    elsif (($type eq "a\.out"))
++    {	$aout=1;		require "x86gas.pl";	}
++    elsif (($type eq "coff" or $type eq "gaswin"))
++    {	$coff=1;		require "x86gas.pl";	}
++    elsif (($type eq "win32n"))
++    {	$win32=1;		require "x86nasm.pl";	}
++    elsif (($type eq "nw-nasm"))
++    {	$netware=1;		require "x86nasm.pl";	}
++    #elsif (($type eq "nw-mwasm"))
++    #{	$netware=1; $mwerks=1;	require "x86nasm.pl";	}
++    elsif (($type eq "win32"))
++    {	$win32=1;		require "x86masm.pl";	}
++    elsif (($type eq "macosx"))
++    {	$aout=1; $macosx=1;	require "x86gas.pl";	}
++    elsif (($type eq "android"))
++    {	$elf=1; $android=1;	require "x86gas.pl";	}
++    else
++    {	print STDERR <<"EOF";
++Pick one target type from
++	elf	- Linux, FreeBSD, Solaris x86, etc.
++	a.out	- DJGPP, elder OpenBSD, etc.
++	coff	- GAS/COFF such as Win32 targets
++	win32n	- Windows 95/Windows NT NASM format
++	nw-nasm - NetWare NASM format
++	macosx	- Mac OS X
++EOF
++	exit(1);
++    }
++
++    $pic=0;
++    for (@ARGV) { $pic=1 if (/\-[fK]PIC/i); }
++
++    $filename =~ s/\.pl$//;
++    &file($filename);
++}
++
++sub ::hidden {}
++
++1;
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/perlasm/x86gas.pl b/CryptoPkg/Library/OpensslLib/openssl/crypto/perlasm/x86gas.pl
+new file mode 100644
+index 0000000..2c8fce0
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/perlasm/x86gas.pl
+@@ -0,0 +1,265 @@
++#! /usr/bin/env perl
++# Copyright 2007-2016 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
++# in the file LICENSE in the source distribution or at
++# https://www.openssl.org/source/license.html
++
++
++package x86gas;
++
++*out=\@::out;
++
++$::lbdecor=$::aout?"L":".L";		# local label decoration
++$nmdecor=($::aout or $::coff)?"_":"";	# external name decoration
++
++$initseg="";
++
++$align=16;
++$align=log($align)/log(2) if ($::aout);
++$com_start="#" if ($::aout or $::coff);
++
++sub opsize()
++{ my $reg=shift;
++    if    ($reg =~ m/^%e/o)		{ "l"; }
++    elsif ($reg =~ m/^%[a-d][hl]$/o)	{ "b"; }
++    elsif ($reg =~ m/^%[yxm]/o)		{ undef; }
++    else				{ "w"; }
++}
++
++# swap arguments;
++# expand opcode with size suffix;
++# prefix numeric constants with $;
++sub ::generic
++{ my($opcode,@arg)=@_;
++  my($suffix,$dst,$src);
++
++    @arg=reverse(@arg);
++
++    for (@arg)
++    {	s/^(\*?)(e?[a-dsixphl]{2})$/$1%$2/o;	# gp registers
++	s/^([xy]?mm[0-7])$/%$1/o;		# xmm/mmx registers
++	s/^(\-?[0-9]+)$/\$$1/o;			# constants
++	s/^(\-?0x[0-9a-f]+)$/\$$1/o;		# constants
++    }
++
++    $dst = $arg[$#arg]		if ($#arg>=0);
++    $src = $arg[$#arg-1]	if ($#arg>=1);
++    if    ($dst =~ m/^%/o)	{ $suffix=&opsize($dst); }
++    elsif ($src =~ m/^%/o)	{ $suffix=&opsize($src); }
++    else			{ $suffix="l";           }
++    undef $suffix if ($dst =~ m/^%[xm]/o || $src =~ m/^%[xm]/o);
++
++    if ($#_==0)				{ &::emit($opcode);		}
++    elsif ($#_==1 && $opcode =~ m/^(call|clflush|j|loop|set)/o)
++					{ &::emit($opcode,@arg);	}
++    else				{ &::emit($opcode.$suffix,@arg);}
++
++  1;
++}
++#
++# opcodes not covered by ::generic above, mostly inconsistent namings...
++#
++sub ::movzx	{ &::movzb(@_);			}
++sub ::pushfd	{ &::pushfl;			}
++sub ::popfd	{ &::popfl;			}
++sub ::cpuid	{ &::emit(".byte\t0x0f,0xa2");	}
++sub ::rdtsc	{ &::emit(".byte\t0x0f,0x31");	}
++
++sub ::call	{ &::emit("call",(&::islabel($_[0]) or "$nmdecor$_[0]")); }
++sub ::call_ptr	{ &::generic("call","*$_[0]");	}
++sub ::jmp_ptr	{ &::generic("jmp","*$_[0]");	}
++
++*::bswap = sub	{ &::emit("bswap","%$_[0]");	} if (!$::i386);
++
++sub ::DWP
++{ my($addr,$reg1,$reg2,$idx)=@_;
++  my $ret="";
++
++    if (!defined($idx) && 1*$reg2) { $idx=$reg2; $reg2=$reg1; undef $reg1; }
++
++    $addr =~ s/^\s+//;
++    # prepend global references with optional underscore
++    $addr =~ s/^([^\+\-0-9][^\+\-]*)/&::islabel($1) or "$nmdecor$1"/ige;
++
++    $reg1 = "%$reg1" if ($reg1);
++    $reg2 = "%$reg2" if ($reg2);
++
++    $ret .= $addr if (($addr ne "") && ($addr ne 0));
++
++    if ($reg2)
++    {	$idx!= 0 or $idx=1;
++	$ret .= "($reg1,$reg2,$idx)";
++    }
++    elsif ($reg1)
++    {	$ret .= "($reg1)";	}
++
++  $ret;
++}
++sub ::QWP	{ &::DWP(@_);	}
++sub ::BP	{ &::DWP(@_);	}
++sub ::WP	{ &::DWP(@_);	}
++sub ::BC	{ @_;		}
++sub ::DWC	{ @_;		}
++
++sub ::file
++{   push(@out,".file\t\"$_[0].s\"\n.text\n");	}
++
++sub ::function_begin_B
++{ my $func=shift;
++  my $global=($func !~ /^_/);
++  my $begin="${::lbdecor}_${func}_begin";
++
++    &::LABEL($func,$global?"$begin":"$nmdecor$func");
++    $func=$nmdecor.$func;
++
++    push(@out,".globl\t$func\n")	if ($global);
++    if ($::coff)
++    {	push(@out,".def\t$func;\t.scl\t".(3-$global).";\t.type\t32;\t.endef\n"); }
++    elsif (($::aout and !$::pic) or $::macosx)
++    { }
++    else
++    {	push(@out,".type	$func,\@function\n"); }
++    push(@out,".align\t$align\n");
++    push(@out,"$func:\n");
++    push(@out,"$begin:\n")		if ($global);
++    $::stack=4;
++}
++
++sub ::function_end_B
++{ my $func=shift;
++    push(@out,".size\t$nmdecor$func,.-".&::LABEL($func)."\n") if ($::elf);
++    $::stack=0;
++    &::wipe_labels();
++}
++
++sub ::comment
++	{
++	if (!defined($com_start) or $::elf)
++		{	# Regarding $::elf above...
++			# GNU and SVR4 as'es use different comment delimiters,
++		push(@out,"\n");	# so we just skip ELF comments...
++		return;
++		}
++	foreach (@_)
++		{
++		if (/^\s*$/)
++			{ push(@out,"\n"); }
++		else
++			{ push(@out,"\t$com_start $_ $com_end\n"); }
++		}
++	}
++
++sub ::external_label
++{   foreach(@_) { &::LABEL($_,$nmdecor.$_); }   }
++
++sub ::public_label
++{   push(@out,".globl\t".&::LABEL($_[0],$nmdecor.$_[0])."\n");   }
++
++sub ::file_end
++{   if ($::macosx)
++    {	if (%non_lazy_ptr)
++    	{   push(@out,".section __IMPORT,__pointers,non_lazy_symbol_pointers\n");
++	    foreach $i (keys %non_lazy_ptr)
++	    {	push(@out,"$non_lazy_ptr{$i}:\n.indirect_symbol\t$i\n.long\t0\n");   }
++	}
++    }
++    if (grep {/\b${nmdecor}OPENSSL_ia32cap_P\b/i} @out) {
++	my $tmp=".comm\t${nmdecor}OPENSSL_ia32cap_P,16";
++	if ($::macosx)	{ push (@out,"$tmp,2\n"); }
++	elsif ($::elf)	{ push (@out,"$tmp,4\n"); }
++	else		{ push (@out,"$tmp\n"); }
++    }
++    push(@out,$initseg) if ($initseg);
++}
++
++sub ::data_byte	{   push(@out,".byte\t".join(',',@_)."\n");   }
++sub ::data_short{   push(@out,".value\t".join(',',@_)."\n");  }
++sub ::data_word {   push(@out,".long\t".join(',',@_)."\n");   }
++
++sub ::align
++{ my $val=$_[0];
++    if ($::aout)
++    {	$val=int(log($val)/log(2));
++	$val.=",0x90";
++    }
++    push(@out,".align\t$val\n");
++}
++
++sub ::picmeup
++{ my($dst,$sym,$base,$reflabel)=@_;
++
++    if (($::pic && ($::elf || $::aout)) || $::macosx)
++    {	if (!defined($base))
++	{   &::call(&::label("PIC_me_up"));
++	    &::set_label("PIC_me_up");
++	    &::blindpop($dst);
++	    $base=$dst;
++	    $reflabel=&::label("PIC_me_up");
++	}
++	if ($::macosx)
++	{   my $indirect=&::static_label("$nmdecor$sym\$non_lazy_ptr");
++	    &::mov($dst,&::DWP("$indirect-$reflabel",$base));
++	    $non_lazy_ptr{"$nmdecor$sym"}=$indirect;
++	}
++	elsif ($sym eq "OPENSSL_ia32cap_P" && $::elf>0)
++	{   &::lea($dst,&::DWP("$sym-$reflabel",$base));   }
++	else
++	{   &::lea($dst,&::DWP("_GLOBAL_OFFSET_TABLE_+[.-$reflabel]",
++			    $base));
++	    &::mov($dst,&::DWP("$sym\@GOT",$dst));
++	}
++    }
++    else
++    {	&::lea($dst,&::DWP($sym));	}
++}
++
++sub ::initseg
++{ my $f=$nmdecor.shift;
++
++    if ($::android)
++    {	$initseg.=<<___;
++.section	.init_array
++.align	4
++.long	$f
++___
++    }
++    elsif ($::elf)
++    {	$initseg.=<<___;
++.section	.init
++	call	$f
++___
++    }
++    elsif ($::coff)
++    {   $initseg.=<<___;	# applies to both Cygwin and Mingw
++.section	.ctors
++.long	$f
++___
++    }
++    elsif ($::macosx)
++    {	$initseg.=<<___;
++.mod_init_func
++.align 2
++.long   $f
++___
++    }
++    elsif ($::aout)
++    {	my $ctor="${nmdecor}_GLOBAL_\$I\$$f";
++	$initseg.=".text\n";
++	$initseg.=".type	$ctor,\@function\n" if ($::pic);
++	$initseg.=<<___;	# OpenBSD way...
++.globl	$ctor
++.align	2
++$ctor:
++	jmp	$f
++___
++    }
++}
++
++sub ::dataseg
++{   push(@out,".data\n");   }
++
++*::hidden = sub { push(@out,".hidden\t$nmdecor$_[0]\n"); } if ($::elf);
++
++1;
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/perlasm/x86masm.pl b/CryptoPkg/Library/OpensslLib/openssl/crypto/perlasm/x86masm.pl
+new file mode 100644
+index 0000000..d352f47
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/perlasm/x86masm.pl
+@@ -0,0 +1,207 @@
++#! /usr/bin/env perl
++# Copyright 2007-2016 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
++# in the file LICENSE in the source distribution or at
++# https://www.openssl.org/source/license.html
++
++
++package x86masm;
++
++*out=\@::out;
++
++$::lbdecor="\$L";	# local label decoration
++$nmdecor="_";		# external name decoration
++
++$initseg="";
++$segment="";
++
++sub ::generic
++{ my ($opcode,@arg)=@_;
++
++    # fix hexadecimal constants
++    for (@arg) { s/(?= 0x02030000\n");
++    push(@out,"safeseh	".&::LABEL($nm,$nmdecor.$nm)."\n");
++    push(@out,"%endif\n");
++}
++
++1;
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/pkcs12/build.info b/CryptoPkg/Library/OpensslLib/openssl/crypto/pkcs12/build.info
+new file mode 100644
+index 0000000..b87299e
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/pkcs12/build.info
+@@ -0,0 +1,5 @@
++LIBS=../../libcrypto
++SOURCE[../../libcrypto]=\
++        p12_add.c p12_asn.c p12_attr.c p12_crpt.c p12_crt.c p12_decr.c \
++        p12_init.c p12_key.c p12_kiss.c p12_mutl.c p12_sbag.c \
++        p12_utl.c p12_npas.c pk12err.c p12_p8d.c p12_p8e.c
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/pkcs12/p12_add.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/pkcs12/p12_add.c
+new file mode 100644
+index 0000000..193ed80
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/pkcs12/p12_add.c
+@@ -0,0 +1,164 @@
++/*
++ * Copyright 1999-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include "internal/cryptlib.h"
++#include 
++#include "p12_lcl.h"
++
++/* Pack an object into an OCTET STRING and turn into a safebag */
++
++PKCS12_SAFEBAG *PKCS12_item_pack_safebag(void *obj, const ASN1_ITEM *it,
++                                         int nid1, int nid2)
++{
++    PKCS12_BAGS *bag;
++    PKCS12_SAFEBAG *safebag;
++
++    if ((bag = PKCS12_BAGS_new()) == NULL) {
++        PKCS12err(PKCS12_F_PKCS12_ITEM_PACK_SAFEBAG, ERR_R_MALLOC_FAILURE);
++        return NULL;
++    }
++    bag->type = OBJ_nid2obj(nid1);
++    if (!ASN1_item_pack(obj, it, &bag->value.octet)) {
++        PKCS12err(PKCS12_F_PKCS12_ITEM_PACK_SAFEBAG, ERR_R_MALLOC_FAILURE);
++        goto err;
++    }
++    if ((safebag = PKCS12_SAFEBAG_new()) == NULL) {
++        PKCS12err(PKCS12_F_PKCS12_ITEM_PACK_SAFEBAG, ERR_R_MALLOC_FAILURE);
++        goto err;
++    }
++    safebag->value.bag = bag;
++    safebag->type = OBJ_nid2obj(nid2);
++    return safebag;
++
++ err:
++    PKCS12_BAGS_free(bag);
++    return NULL;
++}
++
++/* Turn a stack of SAFEBAGS into a PKCS#7 data Contentinfo */
++PKCS7 *PKCS12_pack_p7data(STACK_OF(PKCS12_SAFEBAG) *sk)
++{
++    PKCS7 *p7;
++
++    if ((p7 = PKCS7_new()) == NULL) {
++        PKCS12err(PKCS12_F_PKCS12_PACK_P7DATA, ERR_R_MALLOC_FAILURE);
++        return NULL;
++    }
++    p7->type = OBJ_nid2obj(NID_pkcs7_data);
++    if ((p7->d.data = ASN1_OCTET_STRING_new()) == NULL) {
++        PKCS12err(PKCS12_F_PKCS12_PACK_P7DATA, ERR_R_MALLOC_FAILURE);
++        goto err;
++    }
++
++    if (!ASN1_item_pack(sk, ASN1_ITEM_rptr(PKCS12_SAFEBAGS), &p7->d.data)) {
++        PKCS12err(PKCS12_F_PKCS12_PACK_P7DATA, PKCS12_R_CANT_PACK_STRUCTURE);
++        goto err;
++    }
++    return p7;
++
++ err:
++    PKCS7_free(p7);
++    return NULL;
++}
++
++/* Unpack SAFEBAGS from PKCS#7 data ContentInfo */
++STACK_OF(PKCS12_SAFEBAG) *PKCS12_unpack_p7data(PKCS7 *p7)
++{
++    if (!PKCS7_type_is_data(p7)) {
++        PKCS12err(PKCS12_F_PKCS12_UNPACK_P7DATA,
++                  PKCS12_R_CONTENT_TYPE_NOT_DATA);
++        return NULL;
++    }
++    return ASN1_item_unpack(p7->d.data, ASN1_ITEM_rptr(PKCS12_SAFEBAGS));
++}
++
++/* Turn a stack of SAFEBAGS into a PKCS#7 encrypted data ContentInfo */
++
++PKCS7 *PKCS12_pack_p7encdata(int pbe_nid, const char *pass, int passlen,
++                             unsigned char *salt, int saltlen, int iter,
++                             STACK_OF(PKCS12_SAFEBAG) *bags)
++{
++    PKCS7 *p7;
++    X509_ALGOR *pbe;
++    const EVP_CIPHER *pbe_ciph;
++
++    if ((p7 = PKCS7_new()) == NULL) {
++        PKCS12err(PKCS12_F_PKCS12_PACK_P7ENCDATA, ERR_R_MALLOC_FAILURE);
++        return NULL;
++    }
++    if (!PKCS7_set_type(p7, NID_pkcs7_encrypted)) {
++        PKCS12err(PKCS12_F_PKCS12_PACK_P7ENCDATA,
++                  PKCS12_R_ERROR_SETTING_ENCRYPTED_DATA_TYPE);
++        goto err;
++    }
++
++    pbe_ciph = EVP_get_cipherbynid(pbe_nid);
++
++    if (pbe_ciph)
++        pbe = PKCS5_pbe2_set(pbe_ciph, iter, salt, saltlen);
++    else
++        pbe = PKCS5_pbe_set(pbe_nid, iter, salt, saltlen);
++
++    if (!pbe) {
++        PKCS12err(PKCS12_F_PKCS12_PACK_P7ENCDATA, ERR_R_MALLOC_FAILURE);
++        goto err;
++    }
++    X509_ALGOR_free(p7->d.encrypted->enc_data->algorithm);
++    p7->d.encrypted->enc_data->algorithm = pbe;
++    ASN1_OCTET_STRING_free(p7->d.encrypted->enc_data->enc_data);
++    if (!(p7->d.encrypted->enc_data->enc_data =
++          PKCS12_item_i2d_encrypt(pbe, ASN1_ITEM_rptr(PKCS12_SAFEBAGS), pass,
++                                  passlen, bags, 1))) {
++        PKCS12err(PKCS12_F_PKCS12_PACK_P7ENCDATA, PKCS12_R_ENCRYPT_ERROR);
++        goto err;
++    }
++
++    return p7;
++
++ err:
++    PKCS7_free(p7);
++    return NULL;
++}
++
++STACK_OF(PKCS12_SAFEBAG) *PKCS12_unpack_p7encdata(PKCS7 *p7, const char *pass,
++                                                  int passlen)
++{
++    if (!PKCS7_type_is_encrypted(p7))
++        return NULL;
++    return PKCS12_item_decrypt_d2i(p7->d.encrypted->enc_data->algorithm,
++                                   ASN1_ITEM_rptr(PKCS12_SAFEBAGS),
++                                   pass, passlen,
++                                   p7->d.encrypted->enc_data->enc_data, 1);
++}
++
++PKCS8_PRIV_KEY_INFO *PKCS12_decrypt_skey(const PKCS12_SAFEBAG *bag,
++                                         const char *pass, int passlen)
++{
++    return PKCS8_decrypt(bag->value.shkeybag, pass, passlen);
++}
++
++int PKCS12_pack_authsafes(PKCS12 *p12, STACK_OF(PKCS7) *safes)
++{
++    if (ASN1_item_pack(safes, ASN1_ITEM_rptr(PKCS12_AUTHSAFES),
++                       &p12->authsafes->d.data))
++        return 1;
++    return 0;
++}
++
++STACK_OF(PKCS7) *PKCS12_unpack_authsafes(const PKCS12 *p12)
++{
++    if (!PKCS7_type_is_data(p12->authsafes)) {
++        PKCS12err(PKCS12_F_PKCS12_UNPACK_AUTHSAFES,
++                  PKCS12_R_CONTENT_TYPE_NOT_DATA);
++        return NULL;
++    }
++    return ASN1_item_unpack(p12->authsafes->d.data,
++                            ASN1_ITEM_rptr(PKCS12_AUTHSAFES));
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/pkcs12/p12_asn.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/pkcs12/p12_asn.c
+new file mode 100644
+index 0000000..f2bfe32
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/pkcs12/p12_asn.c
+@@ -0,0 +1,76 @@
++/*
++ * Copyright 2000-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include "internal/cryptlib.h"
++#include 
++#include 
++#include "p12_lcl.h"
++
++/* PKCS#12 ASN1 module */
++
++ASN1_SEQUENCE(PKCS12) = {
++        ASN1_SIMPLE(PKCS12, version, ASN1_INTEGER),
++        ASN1_SIMPLE(PKCS12, authsafes, PKCS7),
++        ASN1_OPT(PKCS12, mac, PKCS12_MAC_DATA)
++} ASN1_SEQUENCE_END(PKCS12)
++
++IMPLEMENT_ASN1_FUNCTIONS(PKCS12)
++
++ASN1_SEQUENCE(PKCS12_MAC_DATA) = {
++        ASN1_SIMPLE(PKCS12_MAC_DATA, dinfo, X509_SIG),
++        ASN1_SIMPLE(PKCS12_MAC_DATA, salt, ASN1_OCTET_STRING),
++        ASN1_OPT(PKCS12_MAC_DATA, iter, ASN1_INTEGER)
++} ASN1_SEQUENCE_END(PKCS12_MAC_DATA)
++
++IMPLEMENT_ASN1_FUNCTIONS(PKCS12_MAC_DATA)
++
++ASN1_ADB_TEMPLATE(bag_default) = ASN1_EXP(PKCS12_BAGS, value.other, ASN1_ANY, 0);
++
++ASN1_ADB(PKCS12_BAGS) = {
++        ADB_ENTRY(NID_x509Certificate, ASN1_EXP(PKCS12_BAGS, value.x509cert, ASN1_OCTET_STRING, 0)),
++        ADB_ENTRY(NID_x509Crl, ASN1_EXP(PKCS12_BAGS, value.x509crl, ASN1_OCTET_STRING, 0)),
++        ADB_ENTRY(NID_sdsiCertificate, ASN1_EXP(PKCS12_BAGS, value.sdsicert, ASN1_IA5STRING, 0)),
++} ASN1_ADB_END(PKCS12_BAGS, 0, type, 0, &bag_default_tt, NULL);
++
++ASN1_SEQUENCE(PKCS12_BAGS) = {
++        ASN1_SIMPLE(PKCS12_BAGS, type, ASN1_OBJECT),
++        ASN1_ADB_OBJECT(PKCS12_BAGS),
++} ASN1_SEQUENCE_END(PKCS12_BAGS)
++
++IMPLEMENT_ASN1_FUNCTIONS(PKCS12_BAGS)
++
++ASN1_ADB_TEMPLATE(safebag_default) = ASN1_EXP(PKCS12_SAFEBAG, value.other, ASN1_ANY, 0);
++
++ASN1_ADB(PKCS12_SAFEBAG) = {
++        ADB_ENTRY(NID_keyBag, ASN1_EXP(PKCS12_SAFEBAG, value.keybag, PKCS8_PRIV_KEY_INFO, 0)),
++        ADB_ENTRY(NID_pkcs8ShroudedKeyBag, ASN1_EXP(PKCS12_SAFEBAG, value.shkeybag, X509_SIG, 0)),
++        ADB_ENTRY(NID_safeContentsBag, ASN1_EXP_SET_OF(PKCS12_SAFEBAG, value.safes, PKCS12_SAFEBAG, 0)),
++        ADB_ENTRY(NID_certBag, ASN1_EXP(PKCS12_SAFEBAG, value.bag, PKCS12_BAGS, 0)),
++        ADB_ENTRY(NID_crlBag, ASN1_EXP(PKCS12_SAFEBAG, value.bag, PKCS12_BAGS, 0)),
++        ADB_ENTRY(NID_secretBag, ASN1_EXP(PKCS12_SAFEBAG, value.bag, PKCS12_BAGS, 0))
++} ASN1_ADB_END(PKCS12_SAFEBAG, 0, type, 0, &safebag_default_tt, NULL);
++
++ASN1_SEQUENCE(PKCS12_SAFEBAG) = {
++        ASN1_SIMPLE(PKCS12_SAFEBAG, type, ASN1_OBJECT),
++        ASN1_ADB_OBJECT(PKCS12_SAFEBAG),
++        ASN1_SET_OF_OPT(PKCS12_SAFEBAG, attrib, X509_ATTRIBUTE)
++} ASN1_SEQUENCE_END(PKCS12_SAFEBAG)
++
++IMPLEMENT_ASN1_FUNCTIONS(PKCS12_SAFEBAG)
++
++/* SEQUENCE OF SafeBag */
++ASN1_ITEM_TEMPLATE(PKCS12_SAFEBAGS) =
++        ASN1_EX_TEMPLATE_TYPE(ASN1_TFLG_SEQUENCE_OF, 0, PKCS12_SAFEBAGS, PKCS12_SAFEBAG)
++ASN1_ITEM_TEMPLATE_END(PKCS12_SAFEBAGS)
++
++/* Authsafes: SEQUENCE OF PKCS7 */
++ASN1_ITEM_TEMPLATE(PKCS12_AUTHSAFES) =
++        ASN1_EX_TEMPLATE_TYPE(ASN1_TFLG_SEQUENCE_OF, 0, PKCS12_AUTHSAFES, PKCS7)
++ASN1_ITEM_TEMPLATE_END(PKCS12_AUTHSAFES)
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/pkcs12/p12_attr.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/pkcs12/p12_attr.c
+new file mode 100644
+index 0000000..c324f50
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/pkcs12/p12_attr.c
+@@ -0,0 +1,103 @@
++/*
++ * Copyright 1999-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include "internal/cryptlib.h"
++#include 
++#include "p12_lcl.h"
++
++/* Add a local keyid to a safebag */
++
++int PKCS12_add_localkeyid(PKCS12_SAFEBAG *bag, unsigned char *name,
++                          int namelen)
++{
++    if (X509at_add1_attr_by_NID(&bag->attrib, NID_localKeyID,
++                                V_ASN1_OCTET_STRING, name, namelen))
++        return 1;
++    else
++        return 0;
++}
++
++/* Add key usage to PKCS#8 structure */
++
++int PKCS8_add_keyusage(PKCS8_PRIV_KEY_INFO *p8, int usage)
++{
++    unsigned char us_val = (unsigned char)usage;
++    return PKCS8_pkey_add1_attr_by_NID(p8, NID_key_usage,
++                                       V_ASN1_BIT_STRING, &us_val, 1);
++}
++
++/* Add a friendlyname to a safebag */
++
++int PKCS12_add_friendlyname_asc(PKCS12_SAFEBAG *bag, const char *name,
++                                int namelen)
++{
++    if (X509at_add1_attr_by_NID(&bag->attrib, NID_friendlyName,
++                                MBSTRING_ASC, (unsigned char *)name, namelen))
++        return 1;
++    else
++        return 0;
++}
++
++int PKCS12_add_friendlyname_utf8(PKCS12_SAFEBAG *bag, const char *name,
++                                int namelen)
++{
++    if (X509at_add1_attr_by_NID(&bag->attrib, NID_friendlyName,
++                                MBSTRING_UTF8, (unsigned char *)name, namelen))
++        return 1;
++    else
++        return 0;
++}
++
++int PKCS12_add_friendlyname_uni(PKCS12_SAFEBAG *bag,
++                                const unsigned char *name, int namelen)
++{
++    if (X509at_add1_attr_by_NID(&bag->attrib, NID_friendlyName,
++                                MBSTRING_BMP, name, namelen))
++        return 1;
++    else
++        return 0;
++}
++
++int PKCS12_add_CSPName_asc(PKCS12_SAFEBAG *bag, const char *name, int namelen)
++{
++    if (X509at_add1_attr_by_NID(&bag->attrib, NID_ms_csp_name,
++                                MBSTRING_ASC, (unsigned char *)name, namelen))
++        return 1;
++    else
++        return 0;
++}
++
++ASN1_TYPE *PKCS12_get_attr_gen(const STACK_OF(X509_ATTRIBUTE) *attrs,
++                               int attr_nid)
++{
++    X509_ATTRIBUTE *attrib;
++    int i;
++    i = X509at_get_attr_by_NID(attrs, attr_nid, -1);
++    attrib = X509at_get_attr(attrs, i);
++    return X509_ATTRIBUTE_get0_type(attrib, 0);
++}
++
++char *PKCS12_get_friendlyname(PKCS12_SAFEBAG *bag)
++{
++    const ASN1_TYPE *atype;
++
++    if ((atype = PKCS12_SAFEBAG_get0_attr(bag, NID_friendlyName)) == NULL)
++        return NULL;
++    if (atype->type != V_ASN1_BMPSTRING)
++        return NULL;
++    return OPENSSL_uni2utf8(atype->value.bmpstring->data,
++                            atype->value.bmpstring->length);
++}
++
++const STACK_OF(X509_ATTRIBUTE) *
++PKCS12_SAFEBAG_get0_attrs(const PKCS12_SAFEBAG *bag)
++{
++    return bag->attrib;
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/pkcs12/p12_crpt.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/pkcs12/p12_crpt.c
+new file mode 100644
+index 0000000..feef9d1
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/pkcs12/p12_crpt.c
+@@ -0,0 +1,70 @@
++/*
++ * Copyright 1999-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include "internal/cryptlib.h"
++#include 
++
++/* PKCS#12 PBE algorithms now in static table */
++
++void PKCS12_PBE_add(void)
++{
++}
++
++int PKCS12_PBE_keyivgen(EVP_CIPHER_CTX *ctx, const char *pass, int passlen,
++                        ASN1_TYPE *param, const EVP_CIPHER *cipher,
++                        const EVP_MD *md, int en_de)
++{
++    PBEPARAM *pbe;
++    int saltlen, iter, ret;
++    unsigned char *salt;
++    unsigned char key[EVP_MAX_KEY_LENGTH], iv[EVP_MAX_IV_LENGTH];
++    int (*pkcs12_key_gen)(const char *pass, int passlen,
++                          unsigned char *salt, int slen,
++                          int id, int iter, int n,
++                          unsigned char *out,
++                          const EVP_MD *md_type);
++
++    pkcs12_key_gen = PKCS12_key_gen_utf8;
++
++    if (cipher == NULL)
++        return 0;
++
++    /* Extract useful info from parameter */
++
++    pbe = ASN1_TYPE_unpack_sequence(ASN1_ITEM_rptr(PBEPARAM), param);
++    if (pbe == NULL) {
++        PKCS12err(PKCS12_F_PKCS12_PBE_KEYIVGEN, PKCS12_R_DECODE_ERROR);
++        return 0;
++    }
++
++    if (!pbe->iter)
++        iter = 1;
++    else
++        iter = ASN1_INTEGER_get(pbe->iter);
++    salt = pbe->salt->data;
++    saltlen = pbe->salt->length;
++    if (!(*pkcs12_key_gen)(pass, passlen, salt, saltlen, PKCS12_KEY_ID,
++                           iter, EVP_CIPHER_key_length(cipher), key, md)) {
++        PKCS12err(PKCS12_F_PKCS12_PBE_KEYIVGEN, PKCS12_R_KEY_GEN_ERROR);
++        PBEPARAM_free(pbe);
++        return 0;
++    }
++    if (!(*pkcs12_key_gen)(pass, passlen, salt, saltlen, PKCS12_IV_ID,
++                           iter, EVP_CIPHER_iv_length(cipher), iv, md)) {
++        PKCS12err(PKCS12_F_PKCS12_PBE_KEYIVGEN, PKCS12_R_IV_GEN_ERROR);
++        PBEPARAM_free(pbe);
++        return 0;
++    }
++    PBEPARAM_free(pbe);
++    ret = EVP_CipherInit_ex(ctx, cipher, NULL, key, iv, en_de);
++    OPENSSL_cleanse(key, EVP_MAX_KEY_LENGTH);
++    OPENSSL_cleanse(iv, EVP_MAX_IV_LENGTH);
++    return ret;
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/pkcs12/p12_crt.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/pkcs12/p12_crt.c
+new file mode 100644
+index 0000000..10cf8dd
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/pkcs12/p12_crt.c
+@@ -0,0 +1,291 @@
++/*
++ * Copyright 1999-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include "internal/cryptlib.h"
++#include 
++#include "p12_lcl.h"
++
++static int pkcs12_add_bag(STACK_OF(PKCS12_SAFEBAG) **pbags,
++                          PKCS12_SAFEBAG *bag);
++
++static int copy_bag_attr(PKCS12_SAFEBAG *bag, EVP_PKEY *pkey, int nid)
++{
++    int idx;
++    X509_ATTRIBUTE *attr;
++    idx = EVP_PKEY_get_attr_by_NID(pkey, nid, -1);
++    if (idx < 0)
++        return 1;
++    attr = EVP_PKEY_get_attr(pkey, idx);
++    if (!X509at_add1_attr(&bag->attrib, attr))
++        return 0;
++    return 1;
++}
++
++PKCS12 *PKCS12_create(const char *pass, const char *name, EVP_PKEY *pkey, X509 *cert,
++                      STACK_OF(X509) *ca, int nid_key, int nid_cert, int iter,
++                      int mac_iter, int keytype)
++{
++    PKCS12 *p12 = NULL;
++    STACK_OF(PKCS7) *safes = NULL;
++    STACK_OF(PKCS12_SAFEBAG) *bags = NULL;
++    PKCS12_SAFEBAG *bag = NULL;
++    int i;
++    unsigned char keyid[EVP_MAX_MD_SIZE];
++    unsigned int keyidlen = 0;
++
++    /* Set defaults */
++    if (!nid_cert)
++#ifdef OPENSSL_NO_RC2
++        nid_cert = NID_pbe_WithSHA1And3_Key_TripleDES_CBC;
++#else
++        nid_cert = NID_pbe_WithSHA1And40BitRC2_CBC;
++#endif
++    if (!nid_key)
++        nid_key = NID_pbe_WithSHA1And3_Key_TripleDES_CBC;
++    if (!iter)
++        iter = PKCS12_DEFAULT_ITER;
++    if (!mac_iter)
++        mac_iter = 1;
++
++    if (!pkey && !cert && !ca) {
++        PKCS12err(PKCS12_F_PKCS12_CREATE, PKCS12_R_INVALID_NULL_ARGUMENT);
++        return NULL;
++    }
++
++    if (pkey && cert) {
++        if (!X509_check_private_key(cert, pkey))
++            return NULL;
++        X509_digest(cert, EVP_sha1(), keyid, &keyidlen);
++    }
++
++    if (cert) {
++        bag = PKCS12_add_cert(&bags, cert);
++        if (name && !PKCS12_add_friendlyname(bag, name, -1))
++            goto err;
++        if (keyidlen && !PKCS12_add_localkeyid(bag, keyid, keyidlen))
++            goto err;
++    }
++
++    /* Add all other certificates */
++    for (i = 0; i < sk_X509_num(ca); i++) {
++        if (!PKCS12_add_cert(&bags, sk_X509_value(ca, i)))
++            goto err;
++    }
++
++    if (bags && !PKCS12_add_safe(&safes, bags, nid_cert, iter, pass))
++        goto err;
++
++    sk_PKCS12_SAFEBAG_pop_free(bags, PKCS12_SAFEBAG_free);
++    bags = NULL;
++
++    if (pkey) {
++        bag = PKCS12_add_key(&bags, pkey, keytype, iter, nid_key, pass);
++
++        if (!bag)
++            goto err;
++
++        if (!copy_bag_attr(bag, pkey, NID_ms_csp_name))
++            goto err;
++        if (!copy_bag_attr(bag, pkey, NID_LocalKeySet))
++            goto err;
++
++        if (name && !PKCS12_add_friendlyname(bag, name, -1))
++            goto err;
++        if (keyidlen && !PKCS12_add_localkeyid(bag, keyid, keyidlen))
++            goto err;
++    }
++
++    if (bags && !PKCS12_add_safe(&safes, bags, -1, 0, NULL))
++        goto err;
++
++    sk_PKCS12_SAFEBAG_pop_free(bags, PKCS12_SAFEBAG_free);
++    bags = NULL;
++
++    p12 = PKCS12_add_safes(safes, 0);
++
++    if (!p12)
++        goto err;
++
++    sk_PKCS7_pop_free(safes, PKCS7_free);
++
++    safes = NULL;
++
++    if ((mac_iter != -1) &&
++        !PKCS12_set_mac(p12, pass, -1, NULL, 0, mac_iter, NULL))
++        goto err;
++
++    return p12;
++
++ err:
++    PKCS12_free(p12);
++    sk_PKCS7_pop_free(safes, PKCS7_free);
++    sk_PKCS12_SAFEBAG_pop_free(bags, PKCS12_SAFEBAG_free);
++    return NULL;
++
++}
++
++PKCS12_SAFEBAG *PKCS12_add_cert(STACK_OF(PKCS12_SAFEBAG) **pbags, X509 *cert)
++{
++    PKCS12_SAFEBAG *bag = NULL;
++    char *name;
++    int namelen = -1;
++    unsigned char *keyid;
++    int keyidlen = -1;
++
++    /* Add user certificate */
++    if ((bag = PKCS12_SAFEBAG_create_cert(cert)) == NULL)
++        goto err;
++
++    /*
++     * Use friendlyName and localKeyID in certificate. (if present)
++     */
++
++    name = (char *)X509_alias_get0(cert, &namelen);
++
++    if (name && !PKCS12_add_friendlyname(bag, name, namelen))
++        goto err;
++
++    keyid = X509_keyid_get0(cert, &keyidlen);
++
++    if (keyid && !PKCS12_add_localkeyid(bag, keyid, keyidlen))
++        goto err;
++
++    if (!pkcs12_add_bag(pbags, bag))
++        goto err;
++
++    return bag;
++
++ err:
++    PKCS12_SAFEBAG_free(bag);
++    return NULL;
++
++}
++
++PKCS12_SAFEBAG *PKCS12_add_key(STACK_OF(PKCS12_SAFEBAG) **pbags,
++                               EVP_PKEY *key, int key_usage, int iter,
++                               int nid_key, const char *pass)
++{
++
++    PKCS12_SAFEBAG *bag = NULL;
++    PKCS8_PRIV_KEY_INFO *p8 = NULL;
++
++    /* Make a PKCS#8 structure */
++    if ((p8 = EVP_PKEY2PKCS8(key)) == NULL)
++        goto err;
++    if (key_usage && !PKCS8_add_keyusage(p8, key_usage))
++        goto err;
++    if (nid_key != -1) {
++        bag = PKCS12_SAFEBAG_create_pkcs8_encrypt(nid_key, pass, -1, NULL, 0,
++                                                  iter, p8);
++        PKCS8_PRIV_KEY_INFO_free(p8);
++    } else
++        bag = PKCS12_SAFEBAG_create0_p8inf(p8);
++
++    if (!bag)
++        goto err;
++
++    if (!pkcs12_add_bag(pbags, bag))
++        goto err;
++
++    return bag;
++
++ err:
++    PKCS12_SAFEBAG_free(bag);
++    return NULL;
++
++}
++
++int PKCS12_add_safe(STACK_OF(PKCS7) **psafes, STACK_OF(PKCS12_SAFEBAG) *bags,
++                    int nid_safe, int iter, const char *pass)
++{
++    PKCS7 *p7 = NULL;
++    int free_safes = 0;
++
++    if (!*psafes) {
++        *psafes = sk_PKCS7_new_null();
++        if (!*psafes)
++            return 0;
++        free_safes = 1;
++    } else
++        free_safes = 0;
++
++    if (nid_safe == 0)
++#ifdef OPENSSL_NO_RC2
++        nid_safe = NID_pbe_WithSHA1And3_Key_TripleDES_CBC;
++#else
++        nid_safe = NID_pbe_WithSHA1And40BitRC2_CBC;
++#endif
++
++    if (nid_safe == -1)
++        p7 = PKCS12_pack_p7data(bags);
++    else
++        p7 = PKCS12_pack_p7encdata(nid_safe, pass, -1, NULL, 0, iter, bags);
++    if (!p7)
++        goto err;
++
++    if (!sk_PKCS7_push(*psafes, p7))
++        goto err;
++
++    return 1;
++
++ err:
++    if (free_safes) {
++        sk_PKCS7_free(*psafes);
++        *psafes = NULL;
++    }
++    PKCS7_free(p7);
++    return 0;
++
++}
++
++static int pkcs12_add_bag(STACK_OF(PKCS12_SAFEBAG) **pbags,
++                          PKCS12_SAFEBAG *bag)
++{
++    int free_bags;
++    if (!pbags)
++        return 1;
++    if (!*pbags) {
++        *pbags = sk_PKCS12_SAFEBAG_new_null();
++        if (!*pbags)
++            return 0;
++        free_bags = 1;
++    } else
++        free_bags = 0;
++
++    if (!sk_PKCS12_SAFEBAG_push(*pbags, bag)) {
++        if (free_bags) {
++            sk_PKCS12_SAFEBAG_free(*pbags);
++            *pbags = NULL;
++        }
++        return 0;
++    }
++
++    return 1;
++
++}
++
++PKCS12 *PKCS12_add_safes(STACK_OF(PKCS7) *safes, int nid_p7)
++{
++    PKCS12 *p12;
++    if (nid_p7 <= 0)
++        nid_p7 = NID_pkcs7_data;
++    p12 = PKCS12_init(nid_p7);
++
++    if (!p12)
++        return NULL;
++
++    if (!PKCS12_pack_authsafes(p12, safes)) {
++        PKCS12_free(p12);
++        return NULL;
++    }
++
++    return p12;
++
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/pkcs12/p12_decr.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/pkcs12/p12_decr.c
+new file mode 100644
+index 0000000..3c86058
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/pkcs12/p12_decr.c
+@@ -0,0 +1,155 @@
++/*
++ * Copyright 1999-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include "internal/cryptlib.h"
++#include 
++
++/* Define this to dump decrypted output to files called DERnnn */
++/*
++ * #define OPENSSL_DEBUG_DECRYPT
++ */
++
++/*
++ * Encrypt/Decrypt a buffer based on password and algor, result in a
++ * OPENSSL_malloc'ed buffer
++ */
++unsigned char *PKCS12_pbe_crypt(const X509_ALGOR *algor,
++                                const char *pass, int passlen,
++                                const unsigned char *in, int inlen,
++                                unsigned char **data, int *datalen, int en_de)
++{
++    unsigned char *out = NULL;
++    int outlen, i;
++    EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new();
++
++    if (ctx == NULL) {
++        PKCS12err(PKCS12_F_PKCS12_PBE_CRYPT, ERR_R_MALLOC_FAILURE);
++        goto err;
++    }
++
++    /* Decrypt data */
++    if (!EVP_PBE_CipherInit(algor->algorithm, pass, passlen,
++                            algor->parameter, ctx, en_de)) {
++        PKCS12err(PKCS12_F_PKCS12_PBE_CRYPT,
++                  PKCS12_R_PKCS12_ALGOR_CIPHERINIT_ERROR);
++        goto err;
++    }
++
++    if ((out = OPENSSL_malloc(inlen + EVP_CIPHER_CTX_block_size(ctx)))
++            == NULL) {
++        PKCS12err(PKCS12_F_PKCS12_PBE_CRYPT, ERR_R_MALLOC_FAILURE);
++        goto err;
++    }
++
++    if (!EVP_CipherUpdate(ctx, out, &i, in, inlen)) {
++        OPENSSL_free(out);
++        out = NULL;
++        PKCS12err(PKCS12_F_PKCS12_PBE_CRYPT, ERR_R_EVP_LIB);
++        goto err;
++    }
++
++    outlen = i;
++    if (!EVP_CipherFinal_ex(ctx, out + i, &i)) {
++        OPENSSL_free(out);
++        out = NULL;
++        PKCS12err(PKCS12_F_PKCS12_PBE_CRYPT,
++                  PKCS12_R_PKCS12_CIPHERFINAL_ERROR);
++        goto err;
++    }
++    outlen += i;
++    if (datalen)
++        *datalen = outlen;
++    if (data)
++        *data = out;
++ err:
++    EVP_CIPHER_CTX_free(ctx);
++    return out;
++
++}
++
++/*
++ * Decrypt an OCTET STRING and decode ASN1 structure if zbuf set zero buffer
++ * after use.
++ */
++
++void *PKCS12_item_decrypt_d2i(const X509_ALGOR *algor, const ASN1_ITEM *it,
++                              const char *pass, int passlen,
++                              const ASN1_OCTET_STRING *oct, int zbuf)
++{
++    unsigned char *out;
++    const unsigned char *p;
++    void *ret;
++    int outlen;
++
++    if (!PKCS12_pbe_crypt(algor, pass, passlen, oct->data, oct->length,
++                          &out, &outlen, 0)) {
++        PKCS12err(PKCS12_F_PKCS12_ITEM_DECRYPT_D2I,
++                  PKCS12_R_PKCS12_PBE_CRYPT_ERROR);
++        return NULL;
++    }
++    p = out;
++#ifdef OPENSSL_DEBUG_DECRYPT
++    {
++        FILE *op;
++
++        char fname[30];
++        static int fnm = 1;
++        sprintf(fname, "DER%d", fnm++);
++        op = fopen(fname, "wb");
++        fwrite(p, 1, outlen, op);
++        fclose(op);
++    }
++#endif
++    ret = ASN1_item_d2i(NULL, &p, outlen, it);
++    if (zbuf)
++        OPENSSL_cleanse(out, outlen);
++    if (!ret)
++        PKCS12err(PKCS12_F_PKCS12_ITEM_DECRYPT_D2I, PKCS12_R_DECODE_ERROR);
++    OPENSSL_free(out);
++    return ret;
++}
++
++/*
++ * Encode ASN1 structure and encrypt, return OCTET STRING if zbuf set zero
++ * encoding.
++ */
++
++ASN1_OCTET_STRING *PKCS12_item_i2d_encrypt(X509_ALGOR *algor,
++                                           const ASN1_ITEM *it,
++                                           const char *pass, int passlen,
++                                           void *obj, int zbuf)
++{
++    ASN1_OCTET_STRING *oct = NULL;
++    unsigned char *in = NULL;
++    int inlen;
++
++    if ((oct = ASN1_OCTET_STRING_new()) == NULL) {
++        PKCS12err(PKCS12_F_PKCS12_ITEM_I2D_ENCRYPT, ERR_R_MALLOC_FAILURE);
++        goto err;
++    }
++    inlen = ASN1_item_i2d(obj, &in, it);
++    if (!in) {
++        PKCS12err(PKCS12_F_PKCS12_ITEM_I2D_ENCRYPT, PKCS12_R_ENCODE_ERROR);
++        goto err;
++    }
++    if (!PKCS12_pbe_crypt(algor, pass, passlen, in, inlen, &oct->data,
++                          &oct->length, 1)) {
++        PKCS12err(PKCS12_F_PKCS12_ITEM_I2D_ENCRYPT, PKCS12_R_ENCRYPT_ERROR);
++        OPENSSL_free(in);
++        goto err;
++    }
++    if (zbuf)
++        OPENSSL_cleanse(in, inlen);
++    OPENSSL_free(in);
++    return oct;
++ err:
++    ASN1_OCTET_STRING_free(oct);
++    return NULL;
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/pkcs12/p12_init.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/pkcs12/p12_init.c
+new file mode 100644
+index 0000000..a78e183
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/pkcs12/p12_init.c
+@@ -0,0 +1,43 @@
++/*
++ * Copyright 1999-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include "internal/cryptlib.h"
++#include 
++#include "p12_lcl.h"
++
++/* Initialise a PKCS12 structure to take data */
++
++PKCS12 *PKCS12_init(int mode)
++{
++    PKCS12 *pkcs12;
++
++    if ((pkcs12 = PKCS12_new()) == NULL) {
++        PKCS12err(PKCS12_F_PKCS12_INIT, ERR_R_MALLOC_FAILURE);
++        return NULL;
++    }
++    ASN1_INTEGER_set(pkcs12->version, 3);
++    pkcs12->authsafes->type = OBJ_nid2obj(mode);
++    switch (mode) {
++    case NID_pkcs7_data:
++        if ((pkcs12->authsafes->d.data = ASN1_OCTET_STRING_new()) == NULL) {
++            PKCS12err(PKCS12_F_PKCS12_INIT, ERR_R_MALLOC_FAILURE);
++            goto err;
++        }
++        break;
++    default:
++        PKCS12err(PKCS12_F_PKCS12_INIT, PKCS12_R_UNSUPPORTED_PKCS12_MODE);
++        goto err;
++    }
++    return pkcs12;
++
++ err:
++    PKCS12_free(pkcs12);
++    return NULL;
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/pkcs12/p12_key.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/pkcs12/p12_key.c
+new file mode 100644
+index 0000000..9c13a45
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/pkcs12/p12_key.c
+@@ -0,0 +1,205 @@
++/*
++ * Copyright 1999-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include "internal/cryptlib.h"
++#include 
++#include 
++
++/* Uncomment out this line to get debugging info about key generation */
++/*
++ * #define OPENSSL_DEBUG_KEYGEN
++ */
++#ifdef OPENSSL_DEBUG_KEYGEN
++# include 
++extern BIO *bio_err;
++void h__dump(unsigned char *p, int len);
++#endif
++
++/* PKCS12 compatible key/IV generation */
++#ifndef min
++# define min(a,b) ((a) < (b) ? (a) : (b))
++#endif
++
++int PKCS12_key_gen_asc(const char *pass, int passlen, unsigned char *salt,
++                       int saltlen, int id, int iter, int n,
++                       unsigned char *out, const EVP_MD *md_type)
++{
++    int ret;
++    unsigned char *unipass;
++    int uniplen;
++
++    if (!pass) {
++        unipass = NULL;
++        uniplen = 0;
++    } else if (!OPENSSL_asc2uni(pass, passlen, &unipass, &uniplen)) {
++        PKCS12err(PKCS12_F_PKCS12_KEY_GEN_ASC, ERR_R_MALLOC_FAILURE);
++        return 0;
++    }
++    ret = PKCS12_key_gen_uni(unipass, uniplen, salt, saltlen,
++                             id, iter, n, out, md_type);
++    if (ret <= 0)
++        return 0;
++    OPENSSL_clear_free(unipass, uniplen);
++    return ret;
++}
++
++int PKCS12_key_gen_utf8(const char *pass, int passlen, unsigned char *salt,
++                        int saltlen, int id, int iter, int n,
++                        unsigned char *out, const EVP_MD *md_type)
++{
++    int ret;
++    unsigned char *unipass;
++    int uniplen;
++
++    if (!pass) {
++        unipass = NULL;
++        uniplen = 0;
++    } else if (!OPENSSL_utf82uni(pass, passlen, &unipass, &uniplen)) {
++        PKCS12err(PKCS12_F_PKCS12_KEY_GEN_UTF8, ERR_R_MALLOC_FAILURE);
++        return 0;
++    }
++    ret = PKCS12_key_gen_uni(unipass, uniplen, salt, saltlen,
++                             id, iter, n, out, md_type);
++    if (ret <= 0)
++        return 0;
++    OPENSSL_clear_free(unipass, uniplen);
++    return ret;
++}
++
++int PKCS12_key_gen_uni(unsigned char *pass, int passlen, unsigned char *salt,
++                       int saltlen, int id, int iter, int n,
++                       unsigned char *out, const EVP_MD *md_type)
++{
++    unsigned char *B = NULL, *D = NULL, *I = NULL, *p = NULL, *Ai = NULL;
++    int Slen, Plen, Ilen, Ijlen;
++    int i, j, u, v;
++    int ret = 0;
++    BIGNUM *Ij = NULL, *Bpl1 = NULL; /* These hold Ij and B + 1 */
++    EVP_MD_CTX *ctx = NULL;
++#ifdef  OPENSSL_DEBUG_KEYGEN
++    unsigned char *tmpout = out;
++    int tmpn = n;
++#endif
++
++    ctx = EVP_MD_CTX_new();
++    if (ctx == NULL)
++        goto err;
++
++#ifdef  OPENSSL_DEBUG_KEYGEN
++    fprintf(stderr, "KEYGEN DEBUG\n");
++    fprintf(stderr, "ID %d, ITER %d\n", id, iter);
++    fprintf(stderr, "Password (length %d):\n", passlen);
++    h__dump(pass, passlen);
++    fprintf(stderr, "Salt (length %d):\n", saltlen);
++    h__dump(salt, saltlen);
++#endif
++    v = EVP_MD_block_size(md_type);
++    u = EVP_MD_size(md_type);
++    if (u < 0 || v <= 0)
++        goto err;
++    D = OPENSSL_malloc(v);
++    Ai = OPENSSL_malloc(u);
++    B = OPENSSL_malloc(v + 1);
++    Slen = v * ((saltlen + v - 1) / v);
++    if (passlen)
++        Plen = v * ((passlen + v - 1) / v);
++    else
++        Plen = 0;
++    Ilen = Slen + Plen;
++    I = OPENSSL_malloc(Ilen);
++    Ij = BN_new();
++    Bpl1 = BN_new();
++    if (D == NULL || Ai == NULL || B == NULL || I == NULL || Ij == NULL
++            || Bpl1 == NULL)
++        goto err;
++    for (i = 0; i < v; i++)
++        D[i] = id;
++    p = I;
++    for (i = 0; i < Slen; i++)
++        *p++ = salt[i % saltlen];
++    for (i = 0; i < Plen; i++)
++        *p++ = pass[i % passlen];
++    for (;;) {
++        if (!EVP_DigestInit_ex(ctx, md_type, NULL)
++            || !EVP_DigestUpdate(ctx, D, v)
++            || !EVP_DigestUpdate(ctx, I, Ilen)
++            || !EVP_DigestFinal_ex(ctx, Ai, NULL))
++            goto err;
++        for (j = 1; j < iter; j++) {
++            if (!EVP_DigestInit_ex(ctx, md_type, NULL)
++                || !EVP_DigestUpdate(ctx, Ai, u)
++                || !EVP_DigestFinal_ex(ctx, Ai, NULL))
++                goto err;
++        }
++        memcpy(out, Ai, min(n, u));
++        if (u >= n) {
++#ifdef OPENSSL_DEBUG_KEYGEN
++            fprintf(stderr, "Output KEY (length %d)\n", tmpn);
++            h__dump(tmpout, tmpn);
++#endif
++            ret = 1;
++            goto end;
++        }
++        n -= u;
++        out += u;
++        for (j = 0; j < v; j++)
++            B[j] = Ai[j % u];
++        /* Work out B + 1 first then can use B as tmp space */
++        if (!BN_bin2bn(B, v, Bpl1))
++            goto err;
++        if (!BN_add_word(Bpl1, 1))
++            goto err;
++        for (j = 0; j < Ilen; j += v) {
++            if (!BN_bin2bn(I + j, v, Ij))
++                goto err;
++            if (!BN_add(Ij, Ij, Bpl1))
++                goto err;
++            if (!BN_bn2bin(Ij, B))
++                goto err;
++            Ijlen = BN_num_bytes(Ij);
++            /* If more than 2^(v*8) - 1 cut off MSB */
++            if (Ijlen > v) {
++                if (!BN_bn2bin(Ij, B))
++                    goto err;
++                memcpy(I + j, B + 1, v);
++#ifndef PKCS12_BROKEN_KEYGEN
++                /* If less than v bytes pad with zeroes */
++            } else if (Ijlen < v) {
++                memset(I + j, 0, v - Ijlen);
++                if (!BN_bn2bin(Ij, I + j + v - Ijlen))
++                    goto err;
++#endif
++            } else if (!BN_bn2bin(Ij, I + j))
++                goto err;
++        }
++    }
++
++ err:
++    PKCS12err(PKCS12_F_PKCS12_KEY_GEN_UNI, ERR_R_MALLOC_FAILURE);
++
++ end:
++    OPENSSL_free(Ai);
++    OPENSSL_free(B);
++    OPENSSL_free(D);
++    OPENSSL_free(I);
++    BN_free(Ij);
++    BN_free(Bpl1);
++    EVP_MD_CTX_free(ctx);
++    return ret;
++}
++
++#ifdef OPENSSL_DEBUG_KEYGEN
++void h__dump(unsigned char *p, int len)
++{
++    for (; len--; p++)
++        fprintf(stderr, "%02X", *p);
++    fprintf(stderr, "\n");
++}
++#endif
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/pkcs12/p12_kiss.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/pkcs12/p12_kiss.c
+new file mode 100644
+index 0000000..62f5d1e
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/pkcs12/p12_kiss.c
+@@ -0,0 +1,245 @@
++/*
++ * Copyright 1999-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include "internal/cryptlib.h"
++#include 
++
++/* Simplified PKCS#12 routines */
++
++static int parse_pk12(PKCS12 *p12, const char *pass, int passlen,
++                      EVP_PKEY **pkey, STACK_OF(X509) *ocerts);
++
++static int parse_bags(const STACK_OF(PKCS12_SAFEBAG) *bags, const char *pass,
++                      int passlen, EVP_PKEY **pkey, STACK_OF(X509) *ocerts);
++
++static int parse_bag(PKCS12_SAFEBAG *bag, const char *pass, int passlen,
++                     EVP_PKEY **pkey, STACK_OF(X509) *ocerts);
++
++/*
++ * Parse and decrypt a PKCS#12 structure returning user key, user cert and
++ * other (CA) certs. Note either ca should be NULL, *ca should be NULL, or it
++ * should point to a valid STACK structure. pkey and cert can be passed
++ * uninitialised.
++ */
++
++int PKCS12_parse(PKCS12 *p12, const char *pass, EVP_PKEY **pkey, X509 **cert,
++                 STACK_OF(X509) **ca)
++{
++    STACK_OF(X509) *ocerts = NULL;
++    X509 *x = NULL;
++    /* Check for NULL PKCS12 structure */
++
++    if (!p12) {
++        PKCS12err(PKCS12_F_PKCS12_PARSE,
++                  PKCS12_R_INVALID_NULL_PKCS12_POINTER);
++        return 0;
++    }
++
++    if (pkey)
++        *pkey = NULL;
++    if (cert)
++        *cert = NULL;
++
++    /* Check the mac */
++
++    /*
++     * If password is zero length or NULL then try verifying both cases to
++     * determine which password is correct. The reason for this is that under
++     * PKCS#12 password based encryption no password and a zero length
++     * password are two different things...
++     */
++
++    if (!pass || !*pass) {
++        if (PKCS12_verify_mac(p12, NULL, 0))
++            pass = NULL;
++        else if (PKCS12_verify_mac(p12, "", 0))
++            pass = "";
++        else {
++            PKCS12err(PKCS12_F_PKCS12_PARSE, PKCS12_R_MAC_VERIFY_FAILURE);
++            goto err;
++        }
++    } else if (!PKCS12_verify_mac(p12, pass, -1)) {
++        PKCS12err(PKCS12_F_PKCS12_PARSE, PKCS12_R_MAC_VERIFY_FAILURE);
++        goto err;
++    }
++
++    /* Allocate stack for other certificates */
++    ocerts = sk_X509_new_null();
++
++    if (!ocerts) {
++        PKCS12err(PKCS12_F_PKCS12_PARSE, ERR_R_MALLOC_FAILURE);
++        return 0;
++    }
++
++    if (!parse_pk12(p12, pass, -1, pkey, ocerts)) {
++        PKCS12err(PKCS12_F_PKCS12_PARSE, PKCS12_R_PARSE_ERROR);
++        goto err;
++    }
++
++    while ((x = sk_X509_pop(ocerts))) {
++        if (pkey && *pkey && cert && !*cert) {
++            ERR_set_mark();
++            if (X509_check_private_key(x, *pkey)) {
++                *cert = x;
++                x = NULL;
++            }
++            ERR_pop_to_mark();
++        }
++
++        if (ca && x) {
++            if (!*ca)
++                *ca = sk_X509_new_null();
++            if (!*ca)
++                goto err;
++            if (!sk_X509_push(*ca, x))
++                goto err;
++            x = NULL;
++        }
++        X509_free(x);
++    }
++
++    sk_X509_pop_free(ocerts, X509_free);
++
++    return 1;
++
++ err:
++
++    if (pkey)
++        EVP_PKEY_free(*pkey);
++    if (cert)
++        X509_free(*cert);
++    X509_free(x);
++    sk_X509_pop_free(ocerts, X509_free);
++    return 0;
++
++}
++
++/* Parse the outer PKCS#12 structure */
++
++static int parse_pk12(PKCS12 *p12, const char *pass, int passlen,
++                      EVP_PKEY **pkey, STACK_OF(X509) *ocerts)
++{
++    STACK_OF(PKCS7) *asafes;
++    STACK_OF(PKCS12_SAFEBAG) *bags;
++    int i, bagnid;
++    PKCS7 *p7;
++
++    if ((asafes = PKCS12_unpack_authsafes(p12)) == NULL)
++        return 0;
++    for (i = 0; i < sk_PKCS7_num(asafes); i++) {
++        p7 = sk_PKCS7_value(asafes, i);
++        bagnid = OBJ_obj2nid(p7->type);
++        if (bagnid == NID_pkcs7_data) {
++            bags = PKCS12_unpack_p7data(p7);
++        } else if (bagnid == NID_pkcs7_encrypted) {
++            bags = PKCS12_unpack_p7encdata(p7, pass, passlen);
++        } else
++            continue;
++        if (!bags) {
++            sk_PKCS7_pop_free(asafes, PKCS7_free);
++            return 0;
++        }
++        if (!parse_bags(bags, pass, passlen, pkey, ocerts)) {
++            sk_PKCS12_SAFEBAG_pop_free(bags, PKCS12_SAFEBAG_free);
++            sk_PKCS7_pop_free(asafes, PKCS7_free);
++            return 0;
++        }
++        sk_PKCS12_SAFEBAG_pop_free(bags, PKCS12_SAFEBAG_free);
++    }
++    sk_PKCS7_pop_free(asafes, PKCS7_free);
++    return 1;
++}
++
++static int parse_bags(const STACK_OF(PKCS12_SAFEBAG) *bags, const char *pass,
++                      int passlen, EVP_PKEY **pkey, STACK_OF(X509) *ocerts)
++{
++    int i;
++    for (i = 0; i < sk_PKCS12_SAFEBAG_num(bags); i++) {
++        if (!parse_bag(sk_PKCS12_SAFEBAG_value(bags, i),
++                       pass, passlen, pkey, ocerts))
++            return 0;
++    }
++    return 1;
++}
++
++static int parse_bag(PKCS12_SAFEBAG *bag, const char *pass, int passlen,
++                     EVP_PKEY **pkey, STACK_OF(X509) *ocerts)
++{
++    PKCS8_PRIV_KEY_INFO *p8;
++    X509 *x509;
++    const ASN1_TYPE *attrib;
++    ASN1_BMPSTRING *fname = NULL;
++    ASN1_OCTET_STRING *lkid = NULL;
++
++    if ((attrib = PKCS12_SAFEBAG_get0_attr(bag, NID_friendlyName)))
++        fname = attrib->value.bmpstring;
++
++    if ((attrib = PKCS12_SAFEBAG_get0_attr(bag, NID_localKeyID)))
++        lkid = attrib->value.octet_string;
++
++    switch (PKCS12_SAFEBAG_get_nid(bag)) {
++    case NID_keyBag:
++        if (!pkey || *pkey)
++            return 1;
++        *pkey = EVP_PKCS82PKEY(PKCS12_SAFEBAG_get0_p8inf(bag));
++        if (*pkey == NULL)
++            return 0;
++        break;
++
++    case NID_pkcs8ShroudedKeyBag:
++        if (!pkey || *pkey)
++            return 1;
++        if ((p8 = PKCS12_decrypt_skey(bag, pass, passlen)) == NULL)
++            return 0;
++        *pkey = EVP_PKCS82PKEY(p8);
++        PKCS8_PRIV_KEY_INFO_free(p8);
++        if (!(*pkey))
++            return 0;
++        break;
++
++    case NID_certBag:
++        if (PKCS12_SAFEBAG_get_bag_nid(bag) != NID_x509Certificate)
++            return 1;
++        if ((x509 = PKCS12_SAFEBAG_get1_cert(bag)) == NULL)
++            return 0;
++        if (lkid && !X509_keyid_set1(x509, lkid->data, lkid->length)) {
++            X509_free(x509);
++            return 0;
++        }
++        if (fname) {
++            int len, r;
++            unsigned char *data;
++            len = ASN1_STRING_to_UTF8(&data, fname);
++            if (len >= 0) {
++                r = X509_alias_set1(x509, data, len);
++                OPENSSL_free(data);
++                if (!r) {
++                    X509_free(x509);
++                    return 0;
++                }
++            }
++        }
++
++        if (!sk_X509_push(ocerts, x509)) {
++            X509_free(x509);
++            return 0;
++        }
++
++        break;
++
++    case NID_safeContentsBag:
++        return parse_bags(PKCS12_SAFEBAG_get0_safes(bag), pass, passlen, pkey,
++                          ocerts);
++
++    default:
++        return 1;
++    }
++    return 1;
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/pkcs12/p12_lcl.h b/CryptoPkg/Library/OpensslLib/openssl/crypto/pkcs12/p12_lcl.h
+new file mode 100644
+index 0000000..0b52f1e
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/pkcs12/p12_lcl.h
+@@ -0,0 +1,43 @@
++/*
++ * Copyright 2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++struct PKCS12_MAC_DATA_st {
++    X509_SIG *dinfo;
++    ASN1_OCTET_STRING *salt;
++    ASN1_INTEGER *iter;         /* defaults to 1 */
++};
++
++struct PKCS12_st {
++    ASN1_INTEGER *version;
++    PKCS12_MAC_DATA *mac;
++    PKCS7 *authsafes;
++};
++
++struct PKCS12_SAFEBAG_st {
++    ASN1_OBJECT *type;
++    union {
++        struct pkcs12_bag_st *bag; /* secret, crl and certbag */
++        struct pkcs8_priv_key_info_st *keybag; /* keybag */
++        X509_SIG *shkeybag;     /* shrouded key bag */
++        STACK_OF(PKCS12_SAFEBAG) *safes;
++        ASN1_TYPE *other;
++    } value;
++    STACK_OF(X509_ATTRIBUTE) *attrib;
++};
++
++struct pkcs12_bag_st {
++    ASN1_OBJECT *type;
++    union {
++        ASN1_OCTET_STRING *x509cert;
++        ASN1_OCTET_STRING *x509crl;
++        ASN1_OCTET_STRING *octet;
++        ASN1_IA5STRING *sdsicert;
++        ASN1_TYPE *other;       /* Secret or other bag */
++    } value;
++};
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/pkcs12/p12_mutl.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/pkcs12/p12_mutl.c
+new file mode 100644
+index 0000000..d6b8919
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/pkcs12/p12_mutl.c
+@@ -0,0 +1,239 @@
++/*
++ * Copyright 1999-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++# include 
++# include "internal/cryptlib.h"
++# include 
++# include 
++# include 
++# include 
++# include "p12_lcl.h"
++
++int PKCS12_mac_present(const PKCS12 *p12)
++{
++    return p12->mac ? 1 : 0;
++}
++
++void PKCS12_get0_mac(const ASN1_OCTET_STRING **pmac,
++                     const X509_ALGOR **pmacalg,
++                     const ASN1_OCTET_STRING **psalt,
++                     const ASN1_INTEGER **piter,
++                     const PKCS12 *p12)
++{
++    if (p12->mac) {
++        X509_SIG_get0(p12->mac->dinfo, pmacalg, pmac);
++        if (psalt)
++            *psalt = p12->mac->salt;
++        if (piter)
++            *piter = p12->mac->iter;
++    } else {
++        if (pmac)
++            *pmac = NULL;
++        if (pmacalg)
++            *pmacalg = NULL;
++        if (psalt)
++            *psalt = NULL;
++        if (piter)
++            *piter = NULL;
++    }
++}
++
++# define TK26_MAC_KEY_LEN 32
++
++static int pkcs12_gen_gost_mac_key(const char *pass, int passlen,
++                                   const unsigned char *salt, int saltlen,
++                                   int iter, int keylen, unsigned char *key,
++                                   const EVP_MD *digest)
++{
++    unsigned char out[96];
++
++    if (keylen != TK26_MAC_KEY_LEN) {
++        return 0;
++    }
++
++    if (!PKCS5_PBKDF2_HMAC(pass, passlen, salt, saltlen, iter,
++                           digest, sizeof(out), out)) {
++        return 0;
++    }
++    memcpy(key, out + sizeof(out) - TK26_MAC_KEY_LEN, TK26_MAC_KEY_LEN);
++    OPENSSL_cleanse(out, sizeof(out));
++    return 1;
++}
++
++/* Generate a MAC */
++static int pkcs12_gen_mac(PKCS12 *p12, const char *pass, int passlen,
++                          unsigned char *mac, unsigned int *maclen,
++                          int (*pkcs12_key_gen)(const char *pass, int passlen,
++                                                unsigned char *salt, int slen,
++                                                int id, int iter, int n,
++                                                unsigned char *out,
++                                                const EVP_MD *md_type))
++{
++    const EVP_MD *md_type;
++    HMAC_CTX *hmac = NULL;
++    unsigned char key[EVP_MAX_MD_SIZE], *salt;
++    int saltlen, iter;
++    int md_size = 0;
++    int md_type_nid;
++    const X509_ALGOR *macalg;
++    const ASN1_OBJECT *macoid;
++
++    if (pkcs12_key_gen == NULL)
++        pkcs12_key_gen = PKCS12_key_gen_utf8;
++
++    if (!PKCS7_type_is_data(p12->authsafes)) {
++        PKCS12err(PKCS12_F_PKCS12_GEN_MAC, PKCS12_R_CONTENT_TYPE_NOT_DATA);
++        return 0;
++    }
++
++    salt = p12->mac->salt->data;
++    saltlen = p12->mac->salt->length;
++    if (!p12->mac->iter)
++        iter = 1;
++    else
++        iter = ASN1_INTEGER_get(p12->mac->iter);
++    X509_SIG_get0(p12->mac->dinfo, &macalg, NULL);
++    X509_ALGOR_get0(&macoid, NULL, NULL, macalg);
++    if ((md_type = EVP_get_digestbyobj(macoid)) == NULL) {
++        PKCS12err(PKCS12_F_PKCS12_GEN_MAC, PKCS12_R_UNKNOWN_DIGEST_ALGORITHM);
++        return 0;
++    }
++    md_size = EVP_MD_size(md_type);
++    md_type_nid = EVP_MD_type(md_type);
++    if (md_size < 0)
++        return 0;
++    if ((md_type_nid == NID_id_GostR3411_94
++         || md_type_nid == NID_id_GostR3411_2012_256
++         || md_type_nid == NID_id_GostR3411_2012_512)
++        && !getenv("LEGACY_GOST_PKCS12")) {
++        md_size = TK26_MAC_KEY_LEN;
++        if (!pkcs12_gen_gost_mac_key(pass, passlen, salt, saltlen, iter,
++                                     md_size, key, md_type)) {
++            PKCS12err(PKCS12_F_PKCS12_GEN_MAC, PKCS12_R_KEY_GEN_ERROR);
++            return 0;
++        }
++    } else
++        if (!(*pkcs12_key_gen)(pass, passlen, salt, saltlen, PKCS12_MAC_ID,
++                               iter, md_size, key, md_type)) {
++        PKCS12err(PKCS12_F_PKCS12_GEN_MAC, PKCS12_R_KEY_GEN_ERROR);
++        return 0;
++    }
++    hmac = HMAC_CTX_new();
++    if (!HMAC_Init_ex(hmac, key, md_size, md_type, NULL)
++        || !HMAC_Update(hmac, p12->authsafes->d.data->data,
++                        p12->authsafes->d.data->length)
++        || !HMAC_Final(hmac, mac, maclen)) {
++        HMAC_CTX_free(hmac);
++        return 0;
++    }
++    HMAC_CTX_free(hmac);
++    return 1;
++}
++
++int PKCS12_gen_mac(PKCS12 *p12, const char *pass, int passlen,
++                   unsigned char *mac, unsigned int *maclen)
++{
++    return pkcs12_gen_mac(p12, pass, passlen, mac, maclen, NULL);
++}
++
++/* Verify the mac */
++int PKCS12_verify_mac(PKCS12 *p12, const char *pass, int passlen)
++{
++    unsigned char mac[EVP_MAX_MD_SIZE];
++    unsigned int maclen;
++    const ASN1_OCTET_STRING *macoct;
++
++    if (p12->mac == NULL) {
++        PKCS12err(PKCS12_F_PKCS12_VERIFY_MAC, PKCS12_R_MAC_ABSENT);
++        return 0;
++    }
++    if (!pkcs12_gen_mac(p12, pass, passlen, mac, &maclen,
++                        PKCS12_key_gen_utf8)) {
++        PKCS12err(PKCS12_F_PKCS12_VERIFY_MAC, PKCS12_R_MAC_GENERATION_ERROR);
++        return 0;
++    }
++    X509_SIG_get0(p12->mac->dinfo, NULL, &macoct);
++    if ((maclen != (unsigned int)ASN1_STRING_length(macoct))
++        || CRYPTO_memcmp(mac, ASN1_STRING_get0_data(macoct), maclen) != 0)
++        return 0;
++
++    return 1;
++}
++
++/* Set a mac */
++
++int PKCS12_set_mac(PKCS12 *p12, const char *pass, int passlen,
++                   unsigned char *salt, int saltlen, int iter,
++                   const EVP_MD *md_type)
++{
++    unsigned char mac[EVP_MAX_MD_SIZE];
++    unsigned int maclen;
++    ASN1_OCTET_STRING *macoct;
++
++    if (!md_type)
++        md_type = EVP_sha1();
++    if (PKCS12_setup_mac(p12, iter, salt, saltlen, md_type) == PKCS12_ERROR) {
++        PKCS12err(PKCS12_F_PKCS12_SET_MAC, PKCS12_R_MAC_SETUP_ERROR);
++        return 0;
++    }
++    /*
++     * Note that output mac is forced to UTF-8...
++     */
++    if (!pkcs12_gen_mac(p12, pass, passlen, mac, &maclen,
++                        PKCS12_key_gen_utf8)) {
++        PKCS12err(PKCS12_F_PKCS12_SET_MAC, PKCS12_R_MAC_GENERATION_ERROR);
++        return 0;
++    }
++    X509_SIG_getm(p12->mac->dinfo, NULL, &macoct);
++    if (!ASN1_OCTET_STRING_set(macoct, mac, maclen)) {
++        PKCS12err(PKCS12_F_PKCS12_SET_MAC, PKCS12_R_MAC_STRING_SET_ERROR);
++        return 0;
++    }
++    return 1;
++}
++
++/* Set up a mac structure */
++int PKCS12_setup_mac(PKCS12 *p12, int iter, unsigned char *salt, int saltlen,
++                     const EVP_MD *md_type)
++{
++    X509_ALGOR *macalg;
++
++    if ((p12->mac = PKCS12_MAC_DATA_new()) == NULL)
++        return PKCS12_ERROR;
++    if (iter > 1) {
++        if ((p12->mac->iter = ASN1_INTEGER_new()) == NULL) {
++            PKCS12err(PKCS12_F_PKCS12_SETUP_MAC, ERR_R_MALLOC_FAILURE);
++            return 0;
++        }
++        if (!ASN1_INTEGER_set(p12->mac->iter, iter)) {
++            PKCS12err(PKCS12_F_PKCS12_SETUP_MAC, ERR_R_MALLOC_FAILURE);
++            return 0;
++        }
++    }
++    if (!saltlen)
++        saltlen = PKCS12_SALT_LEN;
++    if ((p12->mac->salt->data = OPENSSL_malloc(saltlen)) == NULL) {
++        PKCS12err(PKCS12_F_PKCS12_SETUP_MAC, ERR_R_MALLOC_FAILURE);
++        return 0;
++    }
++    p12->mac->salt->length = saltlen;
++    if (!salt) {
++        if (RAND_bytes(p12->mac->salt->data, saltlen) <= 0)
++            return 0;
++    } else
++        memcpy(p12->mac->salt->data, salt, saltlen);
++    X509_SIG_getm(p12->mac->dinfo, &macalg, NULL);
++    if (!X509_ALGOR_set0(macalg, OBJ_nid2obj(EVP_MD_type(md_type)),
++                         V_ASN1_NULL, NULL)) {
++        PKCS12err(PKCS12_F_PKCS12_SETUP_MAC, ERR_R_MALLOC_FAILURE);
++        return 0;
++    }
++
++    return 1;
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/pkcs12/p12_npas.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/pkcs12/p12_npas.c
+new file mode 100644
+index 0000000..0ce75ed
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/pkcs12/p12_npas.c
+@@ -0,0 +1,184 @@
++/*
++ * Copyright 1999-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include 
++#include 
++#include 
++#include 
++#include 
++#include "p12_lcl.h"
++
++/* PKCS#12 password change routine */
++
++static int newpass_p12(PKCS12 *p12, const char *oldpass, const char *newpass);
++static int newpass_bags(STACK_OF(PKCS12_SAFEBAG) *bags, const char *oldpass,
++                        const char *newpass);
++static int newpass_bag(PKCS12_SAFEBAG *bag, const char *oldpass,
++                        const char *newpass);
++static int alg_get(const X509_ALGOR *alg, int *pnid, int *piter,
++                   int *psaltlen);
++
++/*
++ * Change the password on a PKCS#12 structure.
++ */
++
++int PKCS12_newpass(PKCS12 *p12, const char *oldpass, const char *newpass)
++{
++    /* Check for NULL PKCS12 structure */
++
++    if (!p12) {
++        PKCS12err(PKCS12_F_PKCS12_NEWPASS,
++                  PKCS12_R_INVALID_NULL_PKCS12_POINTER);
++        return 0;
++    }
++
++    /* Check the mac */
++
++    if (!PKCS12_verify_mac(p12, oldpass, -1)) {
++        PKCS12err(PKCS12_F_PKCS12_NEWPASS, PKCS12_R_MAC_VERIFY_FAILURE);
++        return 0;
++    }
++
++    if (!newpass_p12(p12, oldpass, newpass)) {
++        PKCS12err(PKCS12_F_PKCS12_NEWPASS, PKCS12_R_PARSE_ERROR);
++        return 0;
++    }
++
++    return 1;
++}
++
++/* Parse the outer PKCS#12 structure */
++
++static int newpass_p12(PKCS12 *p12, const char *oldpass, const char *newpass)
++{
++    STACK_OF(PKCS7) *asafes = NULL, *newsafes = NULL;
++    STACK_OF(PKCS12_SAFEBAG) *bags = NULL;
++    int i, bagnid, pbe_nid = 0, pbe_iter = 0, pbe_saltlen = 0;
++    PKCS7 *p7, *p7new;
++    ASN1_OCTET_STRING *p12_data_tmp = NULL, *macoct = NULL;
++    unsigned char mac[EVP_MAX_MD_SIZE];
++    unsigned int maclen;
++    int rv = 0;
++
++    if ((asafes = PKCS12_unpack_authsafes(p12)) == NULL)
++        goto err;
++    if ((newsafes = sk_PKCS7_new_null()) == NULL)
++        goto err;
++    for (i = 0; i < sk_PKCS7_num(asafes); i++) {
++        p7 = sk_PKCS7_value(asafes, i);
++        bagnid = OBJ_obj2nid(p7->type);
++        if (bagnid == NID_pkcs7_data) {
++            bags = PKCS12_unpack_p7data(p7);
++        } else if (bagnid == NID_pkcs7_encrypted) {
++            bags = PKCS12_unpack_p7encdata(p7, oldpass, -1);
++            if (!alg_get(p7->d.encrypted->enc_data->algorithm,
++                         &pbe_nid, &pbe_iter, &pbe_saltlen))
++                goto err;
++        } else {
++            continue;
++        }
++        if (bags == NULL)
++            goto err;
++        if (!newpass_bags(bags, oldpass, newpass))
++            goto err;
++        /* Repack bag in same form with new password */
++        if (bagnid == NID_pkcs7_data)
++            p7new = PKCS12_pack_p7data(bags);
++        else
++            p7new = PKCS12_pack_p7encdata(pbe_nid, newpass, -1, NULL,
++                                          pbe_saltlen, pbe_iter, bags);
++        if (!p7new || !sk_PKCS7_push(newsafes, p7new))
++            goto err;
++        sk_PKCS12_SAFEBAG_pop_free(bags, PKCS12_SAFEBAG_free);
++        bags = NULL;
++    }
++
++    /* Repack safe: save old safe in case of error */
++
++    p12_data_tmp = p12->authsafes->d.data;
++    if ((p12->authsafes->d.data = ASN1_OCTET_STRING_new()) == NULL)
++        goto err;
++    if (!PKCS12_pack_authsafes(p12, newsafes))
++        goto err;
++
++    if (!PKCS12_gen_mac(p12, newpass, -1, mac, &maclen))
++        goto err;
++    X509_SIG_getm(p12->mac->dinfo, NULL, &macoct);
++    if (!ASN1_OCTET_STRING_set(macoct, mac, maclen))
++        goto err;
++
++    rv = 1;
++
++err:
++    /* Restore old safe if necessary */
++    if (rv == 1) {
++        ASN1_OCTET_STRING_free(p12_data_tmp);
++    } else if (p12_data_tmp != NULL) {
++        ASN1_OCTET_STRING_free(p12->authsafes->d.data);
++        p12->authsafes->d.data = p12_data_tmp;
++    }
++    sk_PKCS12_SAFEBAG_pop_free(bags, PKCS12_SAFEBAG_free);
++    sk_PKCS7_pop_free(asafes, PKCS7_free);
++    sk_PKCS7_pop_free(newsafes, PKCS7_free);
++    return rv;
++}
++
++static int newpass_bags(STACK_OF(PKCS12_SAFEBAG) *bags, const char *oldpass,
++                        const char *newpass)
++{
++    int i;
++    for (i = 0; i < sk_PKCS12_SAFEBAG_num(bags); i++) {
++        if (!newpass_bag(sk_PKCS12_SAFEBAG_value(bags, i), oldpass, newpass))
++            return 0;
++    }
++    return 1;
++}
++
++/* Change password of safebag: only needs handle shrouded keybags */
++
++static int newpass_bag(PKCS12_SAFEBAG *bag, const char *oldpass,
++                       const char *newpass)
++{
++    PKCS8_PRIV_KEY_INFO *p8;
++    X509_SIG *p8new;
++    int p8_nid, p8_saltlen, p8_iter;
++    const X509_ALGOR *shalg;
++
++    if (PKCS12_SAFEBAG_get_nid(bag) != NID_pkcs8ShroudedKeyBag)
++        return 1;
++
++    if ((p8 = PKCS8_decrypt(bag->value.shkeybag, oldpass, -1)) == NULL)
++        return 0;
++    X509_SIG_get0(bag->value.shkeybag, &shalg, NULL);
++    if (!alg_get(shalg, &p8_nid, &p8_iter, &p8_saltlen))
++        return 0;
++    p8new = PKCS8_encrypt(p8_nid, NULL, newpass, -1, NULL, p8_saltlen,
++                          p8_iter, p8);
++    PKCS8_PRIV_KEY_INFO_free(p8);
++    if (p8new == NULL)
++        return 0;
++    X509_SIG_free(bag->value.shkeybag);
++    bag->value.shkeybag = p8new;
++    return 1;
++}
++
++static int alg_get(const X509_ALGOR *alg, int *pnid, int *piter,
++                   int *psaltlen)
++{
++    PBEPARAM *pbe;
++    pbe = ASN1_TYPE_unpack_sequence(ASN1_ITEM_rptr(PBEPARAM), alg->parameter);
++    if (!pbe)
++        return 0;
++    *pnid = OBJ_obj2nid(alg->algorithm);
++    *piter = ASN1_INTEGER_get(pbe->iter);
++    *psaltlen = pbe->salt->length;
++    PBEPARAM_free(pbe);
++    return 1;
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/pkcs12/p12_p8d.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/pkcs12/p12_p8d.c
+new file mode 100644
+index 0000000..d926a77
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/pkcs12/p12_p8d.c
+@@ -0,0 +1,23 @@
++/*
++ * Copyright 2001-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include "internal/cryptlib.h"
++#include 
++
++PKCS8_PRIV_KEY_INFO *PKCS8_decrypt(const X509_SIG *p8, const char *pass,
++                                   int passlen)
++{
++    const X509_ALGOR *dalg;
++    const ASN1_OCTET_STRING *doct;
++    X509_SIG_get0(p8, &dalg, &doct);
++    return PKCS12_item_decrypt_d2i(dalg,
++                                   ASN1_ITEM_rptr(PKCS8_PRIV_KEY_INFO), pass,
++                                   passlen, doct, 1);
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/pkcs12/p12_p8e.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/pkcs12/p12_p8e.c
+new file mode 100644
+index 0000000..86a07e1
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/pkcs12/p12_p8e.c
+@@ -0,0 +1,69 @@
++/*
++ * Copyright 2001-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include "internal/cryptlib.h"
++#include 
++#include "internal/x509_int.h"
++
++X509_SIG *PKCS8_encrypt(int pbe_nid, const EVP_CIPHER *cipher,
++                        const char *pass, int passlen,
++                        unsigned char *salt, int saltlen, int iter,
++                        PKCS8_PRIV_KEY_INFO *p8inf)
++{
++    X509_SIG *p8 = NULL;
++    X509_ALGOR *pbe;
++
++    if (pbe_nid == -1)
++        pbe = PKCS5_pbe2_set(cipher, iter, salt, saltlen);
++    else if (EVP_PBE_find(EVP_PBE_TYPE_PRF, pbe_nid, NULL, NULL, 0))
++        pbe = PKCS5_pbe2_set_iv(cipher, iter, salt, saltlen, NULL, pbe_nid);
++    else {
++        ERR_clear_error();
++        pbe = PKCS5_pbe_set(pbe_nid, iter, salt, saltlen);
++    }
++    if (!pbe) {
++        PKCS12err(PKCS12_F_PKCS8_ENCRYPT, ERR_R_ASN1_LIB);
++        return NULL;
++    }
++    p8 = PKCS8_set0_pbe(pass, passlen, p8inf, pbe);
++    if (p8 == NULL) {
++        X509_ALGOR_free(pbe);
++        return NULL;
++    }
++
++    return p8;
++}
++
++X509_SIG *PKCS8_set0_pbe(const char *pass, int passlen,
++                         PKCS8_PRIV_KEY_INFO *p8inf, X509_ALGOR *pbe)
++{
++    X509_SIG *p8;
++    ASN1_OCTET_STRING *enckey;
++
++    enckey =
++        PKCS12_item_i2d_encrypt(pbe, ASN1_ITEM_rptr(PKCS8_PRIV_KEY_INFO),
++                                pass, passlen, p8inf, 1);
++    if (!enckey) {
++        PKCS12err(PKCS12_F_PKCS8_SET0_PBE, PKCS12_R_ENCRYPT_ERROR);
++        return NULL;
++    }
++
++    p8 = OPENSSL_zalloc(sizeof(*p8));
++
++    if (p8 == NULL) {
++        PKCS12err(PKCS12_F_PKCS8_SET0_PBE, ERR_R_MALLOC_FAILURE);
++        ASN1_OCTET_STRING_free(enckey);
++        return NULL;
++    }
++    p8->algor = pbe;
++    p8->digest = enckey;
++
++    return p8;
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/pkcs12/p12_sbag.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/pkcs12/p12_sbag.c
+new file mode 100644
+index 0000000..4a3d259
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/pkcs12/p12_sbag.c
+@@ -0,0 +1,170 @@
++/*
++ * Copyright 1999-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include "internal/cryptlib.h"
++#include 
++#include "p12_lcl.h"
++
++#if OPENSSL_API_COMPAT < 0x10100000L
++ASN1_TYPE *PKCS12_get_attr(const PKCS12_SAFEBAG *bag, int attr_nid)
++{
++    return PKCS12_get_attr_gen(bag->attrib, attr_nid);
++}
++#endif
++
++const ASN1_TYPE *PKCS12_SAFEBAG_get0_attr(const PKCS12_SAFEBAG *bag,
++                                          int attr_nid)
++{
++    return PKCS12_get_attr_gen(bag->attrib, attr_nid);
++}
++
++ASN1_TYPE *PKCS8_get_attr(PKCS8_PRIV_KEY_INFO *p8, int attr_nid)
++{
++    return PKCS12_get_attr_gen(PKCS8_pkey_get0_attrs(p8), attr_nid);
++}
++
++const PKCS8_PRIV_KEY_INFO *PKCS12_SAFEBAG_get0_p8inf(const PKCS12_SAFEBAG *bag)
++{
++    if (PKCS12_SAFEBAG_get_nid(bag) != NID_keyBag)
++        return NULL;
++    return bag->value.keybag;
++}
++
++const X509_SIG *PKCS12_SAFEBAG_get0_pkcs8(const PKCS12_SAFEBAG *bag)
++{
++    if (OBJ_obj2nid(bag->type) != NID_pkcs8ShroudedKeyBag)
++        return NULL;
++    return bag->value.shkeybag;
++}
++
++const STACK_OF(PKCS12_SAFEBAG) *
++PKCS12_SAFEBAG_get0_safes(const PKCS12_SAFEBAG *bag)
++{
++    if (OBJ_obj2nid(bag->type) != NID_safeContentsBag)
++        return NULL;
++    return bag->value.safes;
++}
++
++const ASN1_OBJECT *PKCS12_SAFEBAG_get0_type(const PKCS12_SAFEBAG *bag)
++{
++    return bag->type;
++}
++
++int PKCS12_SAFEBAG_get_nid(const PKCS12_SAFEBAG *bag)
++{
++    return OBJ_obj2nid(bag->type);
++}
++
++int PKCS12_SAFEBAG_get_bag_nid(const PKCS12_SAFEBAG *bag)
++{
++    int btype = PKCS12_SAFEBAG_get_nid(bag);
++
++    if (btype != NID_certBag && btype != NID_crlBag && btype != NID_secretBag)
++        return -1;
++    return OBJ_obj2nid(bag->value.bag->type);
++}
++
++X509 *PKCS12_SAFEBAG_get1_cert(const PKCS12_SAFEBAG *bag)
++{
++    if (PKCS12_SAFEBAG_get_nid(bag) != NID_certBag)
++        return NULL;
++    if (OBJ_obj2nid(bag->value.bag->type) != NID_x509Certificate)
++        return NULL;
++    return ASN1_item_unpack(bag->value.bag->value.octet,
++                            ASN1_ITEM_rptr(X509));
++}
++
++X509_CRL *PKCS12_SAFEBAG_get1_crl(const PKCS12_SAFEBAG *bag)
++{
++    if (PKCS12_SAFEBAG_get_nid(bag) != NID_crlBag)
++        return NULL;
++    if (OBJ_obj2nid(bag->value.bag->type) != NID_x509Crl)
++        return NULL;
++    return ASN1_item_unpack(bag->value.bag->value.octet,
++                            ASN1_ITEM_rptr(X509_CRL));
++}
++
++PKCS12_SAFEBAG *PKCS12_SAFEBAG_create_cert(X509 *x509)
++{
++    return PKCS12_item_pack_safebag(x509, ASN1_ITEM_rptr(X509),
++                                    NID_x509Certificate, NID_certBag);
++}
++
++PKCS12_SAFEBAG *PKCS12_SAFEBAG_create_crl(X509_CRL *crl)
++{
++    return PKCS12_item_pack_safebag(crl, ASN1_ITEM_rptr(X509_CRL),
++                                    NID_x509Crl, NID_crlBag);
++}
++
++/* Turn PKCS8 object into a keybag */
++
++PKCS12_SAFEBAG *PKCS12_SAFEBAG_create0_p8inf(PKCS8_PRIV_KEY_INFO *p8)
++{
++    PKCS12_SAFEBAG *bag = PKCS12_SAFEBAG_new();
++
++    if (bag == NULL) {
++        PKCS12err(PKCS12_F_PKCS12_SAFEBAG_CREATE0_P8INF, ERR_R_MALLOC_FAILURE);
++        return NULL;
++    }
++    bag->type = OBJ_nid2obj(NID_keyBag);
++    bag->value.keybag = p8;
++    return bag;
++}
++
++/* Turn PKCS8 object into a shrouded keybag */
++
++PKCS12_SAFEBAG *PKCS12_SAFEBAG_create0_pkcs8(X509_SIG *p8)
++{
++    PKCS12_SAFEBAG *bag = PKCS12_SAFEBAG_new();
++
++    /* Set up the safe bag */
++    if (bag == NULL) {
++        PKCS12err(PKCS12_F_PKCS12_SAFEBAG_CREATE0_PKCS8, ERR_R_MALLOC_FAILURE);
++        return NULL;
++    }
++    bag->type = OBJ_nid2obj(NID_pkcs8ShroudedKeyBag);
++    bag->value.shkeybag = p8;
++    return bag;
++}
++
++PKCS12_SAFEBAG *PKCS12_SAFEBAG_create_pkcs8_encrypt(int pbe_nid,
++                                                    const char *pass,
++                                                    int passlen,
++                                                    unsigned char *salt,
++                                                    int saltlen, int iter,
++                                                    PKCS8_PRIV_KEY_INFO *p8inf)
++{
++    PKCS12_SAFEBAG *bag;
++    const EVP_CIPHER *pbe_ciph;
++    X509_SIG *p8;
++
++    pbe_ciph = EVP_get_cipherbynid(pbe_nid);
++
++    if (pbe_ciph)
++        pbe_nid = -1;
++
++    p8 = PKCS8_encrypt(pbe_nid, pbe_ciph, pass, passlen, salt, saltlen, iter,
++                       p8inf);
++
++    if (p8 == NULL) {
++        PKCS12err(PKCS12_F_PKCS12_SAFEBAG_CREATE_PKCS8_ENCRYPT, ERR_R_MALLOC_FAILURE);
++        return NULL;
++    }
++
++    bag = PKCS12_SAFEBAG_create0_pkcs8(p8);
++
++    if (bag == NULL) {
++        PKCS12err(PKCS12_F_PKCS12_SAFEBAG_CREATE_PKCS8_ENCRYPT, ERR_R_MALLOC_FAILURE);
++        X509_SIG_free(p8);
++        return NULL;
++    }
++
++    return bag;
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/pkcs12/p12_utl.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/pkcs12/p12_utl.c
+new file mode 100644
+index 0000000..0701478
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/pkcs12/p12_utl.c
+@@ -0,0 +1,237 @@
++/*
++ * Copyright 1999-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include "internal/cryptlib.h"
++#include 
++
++/* Cheap and nasty Unicode stuff */
++
++unsigned char *OPENSSL_asc2uni(const char *asc, int asclen,
++                               unsigned char **uni, int *unilen)
++{
++    int ulen, i;
++    unsigned char *unitmp;
++
++    if (asclen == -1)
++        asclen = strlen(asc);
++    ulen = asclen * 2 + 2;
++    if ((unitmp = OPENSSL_malloc(ulen)) == NULL)
++        return NULL;
++    for (i = 0; i < ulen - 2; i += 2) {
++        unitmp[i] = 0;
++        unitmp[i + 1] = asc[i >> 1];
++    }
++    /* Make result double null terminated */
++    unitmp[ulen - 2] = 0;
++    unitmp[ulen - 1] = 0;
++    if (unilen)
++        *unilen = ulen;
++    if (uni)
++        *uni = unitmp;
++    return unitmp;
++}
++
++char *OPENSSL_uni2asc(const unsigned char *uni, int unilen)
++{
++    int asclen, i;
++    char *asctmp;
++    /* string must contain an even number of bytes */
++    if (unilen & 1)
++        return NULL;
++    asclen = unilen / 2;
++    /* If no terminating zero allow for one */
++    if (!unilen || uni[unilen - 1])
++        asclen++;
++    uni++;
++    if ((asctmp = OPENSSL_malloc(asclen)) == NULL)
++        return NULL;
++    for (i = 0; i < unilen; i += 2)
++        asctmp[i >> 1] = uni[i];
++    asctmp[asclen - 1] = 0;
++    return asctmp;
++}
++
++/*
++ * OPENSSL_{utf82uni|uni2utf8} perform conversion between UTF-8 and
++ * PKCS#12 BMPString format, which is specified as big-endian UTF-16.
++ * One should keep in mind that even though BMPString is passed as
++ * unsigned char *, it's not the kind of string you can exercise e.g.
++ * strlen on. Caller also has to keep in mind that its length is
++ * expressed not in number of UTF-16 characters, but in number of
++ * bytes the string occupies, and treat it, the length, accordingly.
++ */
++unsigned char *OPENSSL_utf82uni(const char *asc, int asclen,
++                                unsigned char **uni, int *unilen)
++{
++    int ulen, i, j;
++    unsigned char *unitmp, *ret;
++    unsigned long utf32chr = 0;
++
++    if (asclen == -1)
++        asclen = strlen(asc);
++
++    for (ulen = 0, i = 0; i < asclen; i += j) {
++        j = UTF8_getc((const unsigned char *)asc+i, asclen-i, &utf32chr);
++
++        /*
++         * Following condition is somewhat opportunistic is sense that
++         * decoding failure is used as *indirect* indication that input
++         * string might in fact be extended ASCII/ANSI/ISO-8859-X. The
++         * fallback is taken in hope that it would allow to process
++         * files created with previous OpenSSL version, which used the
++         * naive OPENSSL_asc2uni all along. It might be worth noting
++         * that probability of false positive depends on language. In
++         * cases covered by ISO Latin 1 probability is very low, because
++         * any printable non-ASCII alphabet letter followed by another
++         * or any ASCII character will trigger failure and fallback.
++         * In other cases situation can be intensified by the fact that
++         * English letters are not part of alternative keyboard layout,
++         * but even then there should be plenty of pairs that trigger
++         * decoding failure...
++         */
++        if (j < 0)
++	    return OPENSSL_asc2uni(asc, asclen, uni, unilen);
++
++        if (utf32chr > 0x10FFFF)        /* UTF-16 cap */
++	    return NULL;
++
++        if (utf32chr >= 0x10000)        /* pair of UTF-16 characters */
++            ulen += 2*2;
++        else                            /* or just one */
++            ulen += 2;
++    }
++
++    ulen += 2;  /* for trailing UTF16 zero */
++
++    if ((ret = OPENSSL_malloc(ulen)) == NULL)
++        return NULL;
++
++    /* re-run the loop writing down UTF-16 characters in big-endian order */
++    for (unitmp = ret, i = 0; i < asclen; i += j) {
++        j = UTF8_getc((const unsigned char *)asc+i, asclen-i, &utf32chr);
++        if (utf32chr >= 0x10000) {      /* pair if UTF-16 characters */
++            unsigned int hi, lo;
++
++            utf32chr -= 0x10000;
++            hi = 0xD800 + (utf32chr>>10);
++            lo = 0xDC00 + (utf32chr&0x3ff);
++            *unitmp++ = (unsigned char)(hi>>8);
++            *unitmp++ = (unsigned char)(hi);
++            *unitmp++ = (unsigned char)(lo>>8);
++            *unitmp++ = (unsigned char)(lo);
++        } else {                        /* or just one */
++            *unitmp++ = (unsigned char)(utf32chr>>8);
++            *unitmp++ = (unsigned char)(utf32chr);
++        }
++    }
++    /* Make result double null terminated */
++    *unitmp++ = 0;
++    *unitmp++ = 0;
++    if (unilen)
++        *unilen = ulen;
++    if (uni)
++        *uni = ret;
++    return ret;
++}
++
++static int bmp_to_utf8(char *str, const unsigned char *utf16, int len)
++{
++    unsigned long utf32chr;
++
++    if (len == 0) return 0;
++
++    if (len < 2) return -1;
++
++    /* pull UTF-16 character in big-endian order */
++    utf32chr = (utf16[0]<<8) | utf16[1];
++
++    if (utf32chr >= 0xD800 && utf32chr < 0xE000) {   /* two chars */
++        unsigned int lo;
++
++        if (len < 4) return -1;
++
++        utf32chr -= 0xD800;
++        utf32chr <<= 10;
++        lo = (utf16[2]<<8) | utf16[3];
++        if (lo < 0xDC00 || lo >= 0xE000) return -1;
++        utf32chr |= lo-0xDC00;
++        utf32chr += 0x10000;
++    }
++
++    return UTF8_putc((unsigned char *)str, len > 4 ? 4 : len, utf32chr);
++}
++
++char *OPENSSL_uni2utf8(const unsigned char *uni, int unilen)
++{
++    int asclen, i, j;
++    char *asctmp;
++
++    /* string must contain an even number of bytes */
++    if (unilen & 1)
++        return NULL;
++
++    for (asclen = 0, i = 0; i < unilen; ) {
++        j = bmp_to_utf8(NULL, uni+i, unilen-i);
++        /*
++         * falling back to OPENSSL_uni2asc makes lesser sense [than
++         * falling back to OPENSSL_asc2uni in OPENSSL_utf82uni above],
++         * it's done rather to maintain symmetry...
++         */
++        if (j < 0) return OPENSSL_uni2asc(uni, unilen);
++        if (j == 4) i += 4;
++        else        i += 2;
++        asclen += j;
++    }
++
++    /* If no terminating zero allow for one */
++    if (!unilen || (uni[unilen-2]||uni[unilen - 1]))
++        asclen++;
++
++    if ((asctmp = OPENSSL_malloc(asclen)) == NULL)
++        return NULL;
++
++    /* re-run the loop emitting UTF-8 string */
++    for (asclen = 0, i = 0; i < unilen; ) {
++        j = bmp_to_utf8(asctmp+asclen, uni+i, unilen-i);
++        if (j == 4) i += 4;
++        else        i += 2;
++        asclen += j;
++    }
++
++    /* If no terminating zero write one */
++    if (!unilen || (uni[unilen-2]||uni[unilen - 1]))
++        asctmp[asclen] = '\0';
++
++    return asctmp;
++}
++
++int i2d_PKCS12_bio(BIO *bp, PKCS12 *p12)
++{
++    return ASN1_item_i2d_bio(ASN1_ITEM_rptr(PKCS12), bp, p12);
++}
++
++#ifndef OPENSSL_NO_STDIO
++int i2d_PKCS12_fp(FILE *fp, PKCS12 *p12)
++{
++    return ASN1_item_i2d_fp(ASN1_ITEM_rptr(PKCS12), fp, p12);
++}
++#endif
++
++PKCS12 *d2i_PKCS12_bio(BIO *bp, PKCS12 **p12)
++{
++    return ASN1_item_d2i_bio(ASN1_ITEM_rptr(PKCS12), bp, p12);
++}
++
++#ifndef OPENSSL_NO_STDIO
++PKCS12 *d2i_PKCS12_fp(FILE *fp, PKCS12 **p12)
++{
++    return ASN1_item_d2i_fp(ASN1_ITEM_rptr(PKCS12), fp, p12);
++}
++#endif
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/pkcs12/pk12err.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/pkcs12/pk12err.c
+new file mode 100644
+index 0000000..f705084
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/pkcs12/pk12err.c
+@@ -0,0 +1,95 @@
++/*
++ * Generated by util/mkerr.pl DO NOT EDIT
++ * Copyright 1995-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include 
++#include 
++
++/* BEGIN ERROR CODES */
++#ifndef OPENSSL_NO_ERR
++
++# define ERR_FUNC(func) ERR_PACK(ERR_LIB_PKCS12,func,0)
++# define ERR_REASON(reason) ERR_PACK(ERR_LIB_PKCS12,0,reason)
++
++static ERR_STRING_DATA PKCS12_str_functs[] = {
++    {ERR_FUNC(PKCS12_F_PKCS12_CREATE), "PKCS12_create"},
++    {ERR_FUNC(PKCS12_F_PKCS12_GEN_MAC), "PKCS12_gen_mac"},
++    {ERR_FUNC(PKCS12_F_PKCS12_INIT), "PKCS12_init"},
++    {ERR_FUNC(PKCS12_F_PKCS12_ITEM_DECRYPT_D2I), "PKCS12_item_decrypt_d2i"},
++    {ERR_FUNC(PKCS12_F_PKCS12_ITEM_I2D_ENCRYPT), "PKCS12_item_i2d_encrypt"},
++    {ERR_FUNC(PKCS12_F_PKCS12_ITEM_PACK_SAFEBAG), "PKCS12_item_pack_safebag"},
++    {ERR_FUNC(PKCS12_F_PKCS12_KEY_GEN_ASC), "PKCS12_key_gen_asc"},
++    {ERR_FUNC(PKCS12_F_PKCS12_KEY_GEN_UNI), "PKCS12_key_gen_uni"},
++    {ERR_FUNC(PKCS12_F_PKCS12_KEY_GEN_UTF8), "PKCS12_key_gen_utf8"},
++    {ERR_FUNC(PKCS12_F_PKCS12_NEWPASS), "PKCS12_newpass"},
++    {ERR_FUNC(PKCS12_F_PKCS12_PACK_P7DATA), "PKCS12_pack_p7data"},
++    {ERR_FUNC(PKCS12_F_PKCS12_PACK_P7ENCDATA), "PKCS12_pack_p7encdata"},
++    {ERR_FUNC(PKCS12_F_PKCS12_PARSE), "PKCS12_parse"},
++    {ERR_FUNC(PKCS12_F_PKCS12_PBE_CRYPT), "PKCS12_pbe_crypt"},
++    {ERR_FUNC(PKCS12_F_PKCS12_PBE_KEYIVGEN), "PKCS12_PBE_keyivgen"},
++    {ERR_FUNC(PKCS12_F_PKCS12_SAFEBAG_CREATE0_P8INF),
++     "PKCS12_SAFEBAG_create0_p8inf"},
++    {ERR_FUNC(PKCS12_F_PKCS12_SAFEBAG_CREATE0_PKCS8),
++     "PKCS12_SAFEBAG_create0_pkcs8"},
++    {ERR_FUNC(PKCS12_F_PKCS12_SAFEBAG_CREATE_PKCS8_ENCRYPT),
++     "PKCS12_SAFEBAG_create_pkcs8_encrypt"},
++    {ERR_FUNC(PKCS12_F_PKCS12_SETUP_MAC), "PKCS12_setup_mac"},
++    {ERR_FUNC(PKCS12_F_PKCS12_SET_MAC), "PKCS12_set_mac"},
++    {ERR_FUNC(PKCS12_F_PKCS12_UNPACK_AUTHSAFES), "PKCS12_unpack_authsafes"},
++    {ERR_FUNC(PKCS12_F_PKCS12_UNPACK_P7DATA), "PKCS12_unpack_p7data"},
++    {ERR_FUNC(PKCS12_F_PKCS12_VERIFY_MAC), "PKCS12_verify_mac"},
++    {ERR_FUNC(PKCS12_F_PKCS8_ENCRYPT), "PKCS8_encrypt"},
++    {ERR_FUNC(PKCS12_F_PKCS8_SET0_PBE), "PKCS8_set0_pbe"},
++    {0, NULL}
++};
++
++static ERR_STRING_DATA PKCS12_str_reasons[] = {
++    {ERR_REASON(PKCS12_R_CANT_PACK_STRUCTURE), "cant pack structure"},
++    {ERR_REASON(PKCS12_R_CONTENT_TYPE_NOT_DATA), "content type not data"},
++    {ERR_REASON(PKCS12_R_DECODE_ERROR), "decode error"},
++    {ERR_REASON(PKCS12_R_ENCODE_ERROR), "encode error"},
++    {ERR_REASON(PKCS12_R_ENCRYPT_ERROR), "encrypt error"},
++    {ERR_REASON(PKCS12_R_ERROR_SETTING_ENCRYPTED_DATA_TYPE),
++     "error setting encrypted data type"},
++    {ERR_REASON(PKCS12_R_INVALID_NULL_ARGUMENT), "invalid null argument"},
++    {ERR_REASON(PKCS12_R_INVALID_NULL_PKCS12_POINTER),
++     "invalid null pkcs12 pointer"},
++    {ERR_REASON(PKCS12_R_IV_GEN_ERROR), "iv gen error"},
++    {ERR_REASON(PKCS12_R_KEY_GEN_ERROR), "key gen error"},
++    {ERR_REASON(PKCS12_R_MAC_ABSENT), "mac absent"},
++    {ERR_REASON(PKCS12_R_MAC_GENERATION_ERROR), "mac generation error"},
++    {ERR_REASON(PKCS12_R_MAC_SETUP_ERROR), "mac setup error"},
++    {ERR_REASON(PKCS12_R_MAC_STRING_SET_ERROR), "mac string set error"},
++    {ERR_REASON(PKCS12_R_MAC_VERIFY_FAILURE), "mac verify failure"},
++    {ERR_REASON(PKCS12_R_PARSE_ERROR), "parse error"},
++    {ERR_REASON(PKCS12_R_PKCS12_ALGOR_CIPHERINIT_ERROR),
++     "pkcs12 algor cipherinit error"},
++    {ERR_REASON(PKCS12_R_PKCS12_CIPHERFINAL_ERROR),
++     "pkcs12 cipherfinal error"},
++    {ERR_REASON(PKCS12_R_PKCS12_PBE_CRYPT_ERROR), "pkcs12 pbe crypt error"},
++    {ERR_REASON(PKCS12_R_UNKNOWN_DIGEST_ALGORITHM),
++     "unknown digest algorithm"},
++    {ERR_REASON(PKCS12_R_UNSUPPORTED_PKCS12_MODE), "unsupported pkcs12 mode"},
++    {0, NULL}
++};
++
++#endif
++
++int ERR_load_PKCS12_strings(void)
++{
++#ifndef OPENSSL_NO_ERR
++
++    if (ERR_func_error_string(PKCS12_str_functs[0].error) == NULL) {
++        ERR_load_strings(0, PKCS12_str_functs);
++        ERR_load_strings(0, PKCS12_str_reasons);
++    }
++#endif
++    return 1;
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/pkcs7/bio_pk7.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/pkcs7/bio_pk7.c
+new file mode 100644
+index 0000000..29feaa3
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/pkcs7/bio_pk7.c
+@@ -0,0 +1,24 @@
++/*
++ * Copyright 2006-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include 
++#include 
++
++#if !defined(OPENSSL_SYS_VXWORKS)
++# include 
++#endif
++#include 
++
++/* Streaming encode support for PKCS#7 */
++
++BIO *BIO_new_PKCS7(BIO *out, PKCS7 *p7)
++{
++    return BIO_new_NDEF(out, (ASN1_VALUE *)p7, ASN1_ITEM_rptr(PKCS7));
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/pkcs7/build.info b/CryptoPkg/Library/OpensslLib/openssl/crypto/pkcs7/build.info
+new file mode 100644
+index 0000000..2029d53
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/pkcs7/build.info
+@@ -0,0 +1,4 @@
++LIBS=../../libcrypto
++SOURCE[../../libcrypto]=\
++        pk7_asn1.c pk7_lib.c pkcs7err.c pk7_doit.c pk7_smime.c pk7_attr.c \
++        pk7_mime.c bio_pk7.c
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/pkcs7/pk7_asn1.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/pkcs7/pk7_asn1.c
+new file mode 100644
+index 0000000..315e1b8
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/pkcs7/pk7_asn1.c
+@@ -0,0 +1,201 @@
++/*
++ * Copyright 2000-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include "internal/cryptlib.h"
++#include 
++#include 
++#include 
++
++/* PKCS#7 ASN1 module */
++
++/* This is the ANY DEFINED BY table for the top level PKCS#7 structure */
++
++ASN1_ADB_TEMPLATE(p7default) = ASN1_EXP_OPT(PKCS7, d.other, ASN1_ANY, 0);
++
++ASN1_ADB(PKCS7) = {
++        ADB_ENTRY(NID_pkcs7_data, ASN1_NDEF_EXP_OPT(PKCS7, d.data, ASN1_OCTET_STRING_NDEF, 0)),
++        ADB_ENTRY(NID_pkcs7_signed, ASN1_NDEF_EXP_OPT(PKCS7, d.sign, PKCS7_SIGNED, 0)),
++        ADB_ENTRY(NID_pkcs7_enveloped, ASN1_NDEF_EXP_OPT(PKCS7, d.enveloped, PKCS7_ENVELOPE, 0)),
++        ADB_ENTRY(NID_pkcs7_signedAndEnveloped, ASN1_NDEF_EXP_OPT(PKCS7, d.signed_and_enveloped, PKCS7_SIGN_ENVELOPE, 0)),
++        ADB_ENTRY(NID_pkcs7_digest, ASN1_NDEF_EXP_OPT(PKCS7, d.digest, PKCS7_DIGEST, 0)),
++        ADB_ENTRY(NID_pkcs7_encrypted, ASN1_NDEF_EXP_OPT(PKCS7, d.encrypted, PKCS7_ENCRYPT, 0))
++} ASN1_ADB_END(PKCS7, 0, type, 0, &p7default_tt, NULL);
++
++/* PKCS#7 streaming support */
++static int pk7_cb(int operation, ASN1_VALUE **pval, const ASN1_ITEM *it,
++                  void *exarg)
++{
++    ASN1_STREAM_ARG *sarg = exarg;
++    PKCS7 **pp7 = (PKCS7 **)pval;
++
++    switch (operation) {
++
++    case ASN1_OP_STREAM_PRE:
++        if (PKCS7_stream(&sarg->boundary, *pp7) <= 0)
++            return 0;
++    case ASN1_OP_DETACHED_PRE:
++        sarg->ndef_bio = PKCS7_dataInit(*pp7, sarg->out);
++        if (!sarg->ndef_bio)
++            return 0;
++        break;
++
++    case ASN1_OP_STREAM_POST:
++    case ASN1_OP_DETACHED_POST:
++        if (PKCS7_dataFinal(*pp7, sarg->ndef_bio) <= 0)
++            return 0;
++        break;
++
++    }
++    return 1;
++}
++
++ASN1_NDEF_SEQUENCE_cb(PKCS7, pk7_cb) = {
++        ASN1_SIMPLE(PKCS7, type, ASN1_OBJECT),
++        ASN1_ADB_OBJECT(PKCS7)
++}ASN1_NDEF_SEQUENCE_END_cb(PKCS7, PKCS7)
++
++IMPLEMENT_ASN1_FUNCTIONS(PKCS7)
++
++IMPLEMENT_ASN1_NDEF_FUNCTION(PKCS7)
++
++IMPLEMENT_ASN1_DUP_FUNCTION(PKCS7)
++
++ASN1_NDEF_SEQUENCE(PKCS7_SIGNED) = {
++        ASN1_SIMPLE(PKCS7_SIGNED, version, ASN1_INTEGER),
++        ASN1_SET_OF(PKCS7_SIGNED, md_algs, X509_ALGOR),
++        ASN1_SIMPLE(PKCS7_SIGNED, contents, PKCS7),
++        ASN1_IMP_SEQUENCE_OF_OPT(PKCS7_SIGNED, cert, X509, 0),
++        ASN1_IMP_SET_OF_OPT(PKCS7_SIGNED, crl, X509_CRL, 1),
++        ASN1_SET_OF(PKCS7_SIGNED, signer_info, PKCS7_SIGNER_INFO)
++} ASN1_NDEF_SEQUENCE_END(PKCS7_SIGNED)
++
++IMPLEMENT_ASN1_FUNCTIONS(PKCS7_SIGNED)
++
++/* Minor tweak to operation: free up EVP_PKEY */
++static int si_cb(int operation, ASN1_VALUE **pval, const ASN1_ITEM *it,
++                 void *exarg)
++{
++    if (operation == ASN1_OP_FREE_POST) {
++        PKCS7_SIGNER_INFO *si = (PKCS7_SIGNER_INFO *)*pval;
++        EVP_PKEY_free(si->pkey);
++    }
++    return 1;
++}
++
++ASN1_SEQUENCE_cb(PKCS7_SIGNER_INFO, si_cb) = {
++        ASN1_SIMPLE(PKCS7_SIGNER_INFO, version, ASN1_INTEGER),
++        ASN1_SIMPLE(PKCS7_SIGNER_INFO, issuer_and_serial, PKCS7_ISSUER_AND_SERIAL),
++        ASN1_SIMPLE(PKCS7_SIGNER_INFO, digest_alg, X509_ALGOR),
++        /* NB this should be a SET OF but we use a SEQUENCE OF so the
++         * original order * is retained when the structure is reencoded.
++         * Since the attributes are implicitly tagged this will not affect
++         * the encoding.
++         */
++        ASN1_IMP_SEQUENCE_OF_OPT(PKCS7_SIGNER_INFO, auth_attr, X509_ATTRIBUTE, 0),
++        ASN1_SIMPLE(PKCS7_SIGNER_INFO, digest_enc_alg, X509_ALGOR),
++        ASN1_SIMPLE(PKCS7_SIGNER_INFO, enc_digest, ASN1_OCTET_STRING),
++        ASN1_IMP_SET_OF_OPT(PKCS7_SIGNER_INFO, unauth_attr, X509_ATTRIBUTE, 1)
++} ASN1_SEQUENCE_END_cb(PKCS7_SIGNER_INFO, PKCS7_SIGNER_INFO)
++
++IMPLEMENT_ASN1_FUNCTIONS(PKCS7_SIGNER_INFO)
++
++ASN1_SEQUENCE(PKCS7_ISSUER_AND_SERIAL) = {
++        ASN1_SIMPLE(PKCS7_ISSUER_AND_SERIAL, issuer, X509_NAME),
++        ASN1_SIMPLE(PKCS7_ISSUER_AND_SERIAL, serial, ASN1_INTEGER)
++} ASN1_SEQUENCE_END(PKCS7_ISSUER_AND_SERIAL)
++
++IMPLEMENT_ASN1_FUNCTIONS(PKCS7_ISSUER_AND_SERIAL)
++
++ASN1_NDEF_SEQUENCE(PKCS7_ENVELOPE) = {
++        ASN1_SIMPLE(PKCS7_ENVELOPE, version, ASN1_INTEGER),
++        ASN1_SET_OF(PKCS7_ENVELOPE, recipientinfo, PKCS7_RECIP_INFO),
++        ASN1_SIMPLE(PKCS7_ENVELOPE, enc_data, PKCS7_ENC_CONTENT)
++} ASN1_NDEF_SEQUENCE_END(PKCS7_ENVELOPE)
++
++IMPLEMENT_ASN1_FUNCTIONS(PKCS7_ENVELOPE)
++
++/* Minor tweak to operation: free up X509 */
++static int ri_cb(int operation, ASN1_VALUE **pval, const ASN1_ITEM *it,
++                 void *exarg)
++{
++    if (operation == ASN1_OP_FREE_POST) {
++        PKCS7_RECIP_INFO *ri = (PKCS7_RECIP_INFO *)*pval;
++        X509_free(ri->cert);
++    }
++    return 1;
++}
++
++ASN1_SEQUENCE_cb(PKCS7_RECIP_INFO, ri_cb) = {
++        ASN1_SIMPLE(PKCS7_RECIP_INFO, version, ASN1_INTEGER),
++        ASN1_SIMPLE(PKCS7_RECIP_INFO, issuer_and_serial, PKCS7_ISSUER_AND_SERIAL),
++        ASN1_SIMPLE(PKCS7_RECIP_INFO, key_enc_algor, X509_ALGOR),
++        ASN1_SIMPLE(PKCS7_RECIP_INFO, enc_key, ASN1_OCTET_STRING)
++} ASN1_SEQUENCE_END_cb(PKCS7_RECIP_INFO, PKCS7_RECIP_INFO)
++
++IMPLEMENT_ASN1_FUNCTIONS(PKCS7_RECIP_INFO)
++
++ASN1_NDEF_SEQUENCE(PKCS7_ENC_CONTENT) = {
++        ASN1_SIMPLE(PKCS7_ENC_CONTENT, content_type, ASN1_OBJECT),
++        ASN1_SIMPLE(PKCS7_ENC_CONTENT, algorithm, X509_ALGOR),
++        ASN1_IMP_OPT(PKCS7_ENC_CONTENT, enc_data, ASN1_OCTET_STRING_NDEF, 0)
++} ASN1_NDEF_SEQUENCE_END(PKCS7_ENC_CONTENT)
++
++IMPLEMENT_ASN1_FUNCTIONS(PKCS7_ENC_CONTENT)
++
++ASN1_NDEF_SEQUENCE(PKCS7_SIGN_ENVELOPE) = {
++        ASN1_SIMPLE(PKCS7_SIGN_ENVELOPE, version, ASN1_INTEGER),
++        ASN1_SET_OF(PKCS7_SIGN_ENVELOPE, recipientinfo, PKCS7_RECIP_INFO),
++        ASN1_SET_OF(PKCS7_SIGN_ENVELOPE, md_algs, X509_ALGOR),
++        ASN1_SIMPLE(PKCS7_SIGN_ENVELOPE, enc_data, PKCS7_ENC_CONTENT),
++        ASN1_IMP_SET_OF_OPT(PKCS7_SIGN_ENVELOPE, cert, X509, 0),
++        ASN1_IMP_SET_OF_OPT(PKCS7_SIGN_ENVELOPE, crl, X509_CRL, 1),
++        ASN1_SET_OF(PKCS7_SIGN_ENVELOPE, signer_info, PKCS7_SIGNER_INFO)
++} ASN1_NDEF_SEQUENCE_END(PKCS7_SIGN_ENVELOPE)
++
++IMPLEMENT_ASN1_FUNCTIONS(PKCS7_SIGN_ENVELOPE)
++
++ASN1_NDEF_SEQUENCE(PKCS7_ENCRYPT) = {
++        ASN1_SIMPLE(PKCS7_ENCRYPT, version, ASN1_INTEGER),
++        ASN1_SIMPLE(PKCS7_ENCRYPT, enc_data, PKCS7_ENC_CONTENT)
++} ASN1_NDEF_SEQUENCE_END(PKCS7_ENCRYPT)
++
++IMPLEMENT_ASN1_FUNCTIONS(PKCS7_ENCRYPT)
++
++ASN1_NDEF_SEQUENCE(PKCS7_DIGEST) = {
++        ASN1_SIMPLE(PKCS7_DIGEST, version, ASN1_INTEGER),
++        ASN1_SIMPLE(PKCS7_DIGEST, md, X509_ALGOR),
++        ASN1_SIMPLE(PKCS7_DIGEST, contents, PKCS7),
++        ASN1_SIMPLE(PKCS7_DIGEST, digest, ASN1_OCTET_STRING)
++} ASN1_NDEF_SEQUENCE_END(PKCS7_DIGEST)
++
++IMPLEMENT_ASN1_FUNCTIONS(PKCS7_DIGEST)
++
++/* Specials for authenticated attributes */
++
++/*
++ * When signing attributes we want to reorder them to match the sorted
++ * encoding.
++ */
++
++ASN1_ITEM_TEMPLATE(PKCS7_ATTR_SIGN) =
++        ASN1_EX_TEMPLATE_TYPE(ASN1_TFLG_SET_ORDER, 0, PKCS7_ATTRIBUTES, X509_ATTRIBUTE)
++ASN1_ITEM_TEMPLATE_END(PKCS7_ATTR_SIGN)
++
++/*
++ * When verifying attributes we need to use the received order. So we use
++ * SEQUENCE OF and tag it to SET OF
++ */
++
++ASN1_ITEM_TEMPLATE(PKCS7_ATTR_VERIFY) =
++        ASN1_EX_TEMPLATE_TYPE(ASN1_TFLG_SEQUENCE_OF | ASN1_TFLG_IMPTAG | ASN1_TFLG_UNIVERSAL,
++                                V_ASN1_SET, PKCS7_ATTRIBUTES, X509_ATTRIBUTE)
++ASN1_ITEM_TEMPLATE_END(PKCS7_ATTR_VERIFY)
++
++IMPLEMENT_ASN1_PRINT_FUNCTION(PKCS7)
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/pkcs7/pk7_attr.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/pkcs7/pk7_attr.c
+new file mode 100644
+index 0000000..e90bf03
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/pkcs7/pk7_attr.c
+@@ -0,0 +1,121 @@
++/*
++ * Copyright 1999-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include 
++#include 
++#include 
++#include 
++#include 
++#include 
++#include 
++#include 
++
++int PKCS7_add_attrib_smimecap(PKCS7_SIGNER_INFO *si,
++                              STACK_OF(X509_ALGOR) *cap)
++{
++    ASN1_STRING *seq;
++
++    if ((seq = ASN1_STRING_new()) == NULL) {
++        PKCS7err(PKCS7_F_PKCS7_ADD_ATTRIB_SMIMECAP, ERR_R_MALLOC_FAILURE);
++        return 0;
++    }
++    seq->length = ASN1_item_i2d((ASN1_VALUE *)cap, &seq->data,
++                                ASN1_ITEM_rptr(X509_ALGORS));
++    return PKCS7_add_signed_attribute(si, NID_SMIMECapabilities,
++                                      V_ASN1_SEQUENCE, seq);
++}
++
++STACK_OF(X509_ALGOR) *PKCS7_get_smimecap(PKCS7_SIGNER_INFO *si)
++{
++    ASN1_TYPE *cap;
++    const unsigned char *p;
++
++    cap = PKCS7_get_signed_attribute(si, NID_SMIMECapabilities);
++    if (cap == NULL || (cap->type != V_ASN1_SEQUENCE))
++        return NULL;
++    p = cap->value.sequence->data;
++    return (STACK_OF(X509_ALGOR) *)
++        ASN1_item_d2i(NULL, &p, cap->value.sequence->length,
++                      ASN1_ITEM_rptr(X509_ALGORS));
++}
++
++/* Basic smime-capabilities OID and optional integer arg */
++int PKCS7_simple_smimecap(STACK_OF(X509_ALGOR) *sk, int nid, int arg)
++{
++    ASN1_INTEGER *nbit = NULL;
++    X509_ALGOR *alg;
++
++    if ((alg = X509_ALGOR_new()) == NULL) {
++        PKCS7err(PKCS7_F_PKCS7_SIMPLE_SMIMECAP, ERR_R_MALLOC_FAILURE);
++        return 0;
++    }
++    ASN1_OBJECT_free(alg->algorithm);
++    alg->algorithm = OBJ_nid2obj(nid);
++    if (arg > 0) {
++        if ((alg->parameter = ASN1_TYPE_new()) == NULL) {
++            goto err;
++        }
++        if ((nbit = ASN1_INTEGER_new()) == NULL) {
++            goto err;
++        }
++        if (!ASN1_INTEGER_set(nbit, arg)) {
++            goto err;
++        }
++        alg->parameter->value.integer = nbit;
++        alg->parameter->type = V_ASN1_INTEGER;
++        nbit = NULL;
++    }
++    if (!sk_X509_ALGOR_push(sk, alg)) {
++        goto err;
++    }
++    return 1;
++err:
++    PKCS7err(PKCS7_F_PKCS7_SIMPLE_SMIMECAP, ERR_R_MALLOC_FAILURE);
++    ASN1_INTEGER_free(nbit);
++    X509_ALGOR_free(alg);
++    return 0;
++}
++
++int PKCS7_add_attrib_content_type(PKCS7_SIGNER_INFO *si, ASN1_OBJECT *coid)
++{
++    if (PKCS7_get_signed_attribute(si, NID_pkcs9_contentType))
++        return 0;
++    if (!coid)
++        coid = OBJ_nid2obj(NID_pkcs7_data);
++    return PKCS7_add_signed_attribute(si, NID_pkcs9_contentType,
++                                      V_ASN1_OBJECT, coid);
++}
++
++int PKCS7_add0_attrib_signing_time(PKCS7_SIGNER_INFO *si, ASN1_TIME *t)
++{
++    if (t == NULL && (t = X509_gmtime_adj(NULL, 0)) == NULL) {
++        PKCS7err(PKCS7_F_PKCS7_ADD0_ATTRIB_SIGNING_TIME,
++                 ERR_R_MALLOC_FAILURE);
++        return 0;
++    }
++    return PKCS7_add_signed_attribute(si, NID_pkcs9_signingTime,
++                                      V_ASN1_UTCTIME, t);
++}
++
++int PKCS7_add1_attrib_digest(PKCS7_SIGNER_INFO *si,
++                             const unsigned char *md, int mdlen)
++{
++    ASN1_OCTET_STRING *os;
++    os = ASN1_OCTET_STRING_new();
++    if (os == NULL)
++        return 0;
++    if (!ASN1_STRING_set(os, md, mdlen)
++        || !PKCS7_add_signed_attribute(si, NID_pkcs9_messageDigest,
++                                       V_ASN1_OCTET_STRING, os)) {
++        ASN1_OCTET_STRING_free(os);
++        return 0;
++    }
++    return 1;
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/pkcs7/pk7_dgst.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/pkcs7/pk7_dgst.c
+new file mode 100644
+index 0000000..965fb37
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/pkcs7/pk7_dgst.c
+@@ -0,0 +1,15 @@
++/*
++ * Copyright 1995-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include "internal/cryptlib.h"
++#include 
++#include 
++#include 
++#include 
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/pkcs7/pk7_doit.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/pkcs7/pk7_doit.c
+new file mode 100644
+index 0000000..bc6bd30
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/pkcs7/pk7_doit.c
+@@ -0,0 +1,1178 @@
++/*
++ * Copyright 1995-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include "internal/cryptlib.h"
++#include 
++#include 
++#include 
++#include 
++#include 
++
++static int add_attribute(STACK_OF(X509_ATTRIBUTE) **sk, int nid, int atrtype,
++                         void *value);
++static ASN1_TYPE *get_attribute(STACK_OF(X509_ATTRIBUTE) *sk, int nid);
++
++static int PKCS7_type_is_other(PKCS7 *p7)
++{
++    int isOther = 1;
++
++    int nid = OBJ_obj2nid(p7->type);
++
++    switch (nid) {
++    case NID_pkcs7_data:
++    case NID_pkcs7_signed:
++    case NID_pkcs7_enveloped:
++    case NID_pkcs7_signedAndEnveloped:
++    case NID_pkcs7_digest:
++    case NID_pkcs7_encrypted:
++        isOther = 0;
++        break;
++    default:
++        isOther = 1;
++    }
++
++    return isOther;
++
++}
++
++static ASN1_OCTET_STRING *PKCS7_get_octet_string(PKCS7 *p7)
++{
++    if (PKCS7_type_is_data(p7))
++        return p7->d.data;
++    if (PKCS7_type_is_other(p7) && p7->d.other
++        && (p7->d.other->type == V_ASN1_OCTET_STRING))
++        return p7->d.other->value.octet_string;
++    return NULL;
++}
++
++static int PKCS7_bio_add_digest(BIO **pbio, X509_ALGOR *alg)
++{
++    BIO *btmp;
++    const EVP_MD *md;
++    if ((btmp = BIO_new(BIO_f_md())) == NULL) {
++        PKCS7err(PKCS7_F_PKCS7_BIO_ADD_DIGEST, ERR_R_BIO_LIB);
++        goto err;
++    }
++
++    md = EVP_get_digestbyobj(alg->algorithm);
++    if (md == NULL) {
++        PKCS7err(PKCS7_F_PKCS7_BIO_ADD_DIGEST, PKCS7_R_UNKNOWN_DIGEST_TYPE);
++        goto err;
++    }
++
++    BIO_set_md(btmp, md);
++    if (*pbio == NULL)
++        *pbio = btmp;
++    else if (!BIO_push(*pbio, btmp)) {
++        PKCS7err(PKCS7_F_PKCS7_BIO_ADD_DIGEST, ERR_R_BIO_LIB);
++        goto err;
++    }
++    btmp = NULL;
++
++    return 1;
++
++ err:
++    BIO_free(btmp);
++    return 0;
++
++}
++
++static int pkcs7_encode_rinfo(PKCS7_RECIP_INFO *ri,
++                              unsigned char *key, int keylen)
++{
++    EVP_PKEY_CTX *pctx = NULL;
++    EVP_PKEY *pkey = NULL;
++    unsigned char *ek = NULL;
++    int ret = 0;
++    size_t eklen;
++
++    pkey = X509_get0_pubkey(ri->cert);
++
++    if (!pkey)
++        return 0;
++
++    pctx = EVP_PKEY_CTX_new(pkey, NULL);
++    if (!pctx)
++        return 0;
++
++    if (EVP_PKEY_encrypt_init(pctx) <= 0)
++        goto err;
++
++    if (EVP_PKEY_CTX_ctrl(pctx, -1, EVP_PKEY_OP_ENCRYPT,
++                          EVP_PKEY_CTRL_PKCS7_ENCRYPT, 0, ri) <= 0) {
++        PKCS7err(PKCS7_F_PKCS7_ENCODE_RINFO, PKCS7_R_CTRL_ERROR);
++        goto err;
++    }
++
++    if (EVP_PKEY_encrypt(pctx, NULL, &eklen, key, keylen) <= 0)
++        goto err;
++
++    ek = OPENSSL_malloc(eklen);
++
++    if (ek == NULL) {
++        PKCS7err(PKCS7_F_PKCS7_ENCODE_RINFO, ERR_R_MALLOC_FAILURE);
++        goto err;
++    }
++
++    if (EVP_PKEY_encrypt(pctx, ek, &eklen, key, keylen) <= 0)
++        goto err;
++
++    ASN1_STRING_set0(ri->enc_key, ek, eklen);
++    ek = NULL;
++
++    ret = 1;
++
++ err:
++    EVP_PKEY_CTX_free(pctx);
++    OPENSSL_free(ek);
++    return ret;
++
++}
++
++static int pkcs7_decrypt_rinfo(unsigned char **pek, int *peklen,
++                               PKCS7_RECIP_INFO *ri, EVP_PKEY *pkey)
++{
++    EVP_PKEY_CTX *pctx = NULL;
++    unsigned char *ek = NULL;
++    size_t eklen;
++
++    int ret = -1;
++
++    pctx = EVP_PKEY_CTX_new(pkey, NULL);
++    if (!pctx)
++        return -1;
++
++    if (EVP_PKEY_decrypt_init(pctx) <= 0)
++        goto err;
++
++    if (EVP_PKEY_CTX_ctrl(pctx, -1, EVP_PKEY_OP_DECRYPT,
++                          EVP_PKEY_CTRL_PKCS7_DECRYPT, 0, ri) <= 0) {
++        PKCS7err(PKCS7_F_PKCS7_DECRYPT_RINFO, PKCS7_R_CTRL_ERROR);
++        goto err;
++    }
++
++    if (EVP_PKEY_decrypt(pctx, NULL, &eklen,
++                         ri->enc_key->data, ri->enc_key->length) <= 0)
++        goto err;
++
++    ek = OPENSSL_malloc(eklen);
++
++    if (ek == NULL) {
++        PKCS7err(PKCS7_F_PKCS7_DECRYPT_RINFO, ERR_R_MALLOC_FAILURE);
++        goto err;
++    }
++
++    if (EVP_PKEY_decrypt(pctx, ek, &eklen,
++                         ri->enc_key->data, ri->enc_key->length) <= 0) {
++        ret = 0;
++        PKCS7err(PKCS7_F_PKCS7_DECRYPT_RINFO, ERR_R_EVP_LIB);
++        goto err;
++    }
++
++    ret = 1;
++
++    OPENSSL_clear_free(*pek, *peklen);
++    *pek = ek;
++    *peklen = eklen;
++
++ err:
++    EVP_PKEY_CTX_free(pctx);
++    if (!ret)
++        OPENSSL_free(ek);
++
++    return ret;
++}
++
++BIO *PKCS7_dataInit(PKCS7 *p7, BIO *bio)
++{
++    int i;
++    BIO *out = NULL, *btmp = NULL;
++    X509_ALGOR *xa = NULL;
++    const EVP_CIPHER *evp_cipher = NULL;
++    STACK_OF(X509_ALGOR) *md_sk = NULL;
++    STACK_OF(PKCS7_RECIP_INFO) *rsk = NULL;
++    X509_ALGOR *xalg = NULL;
++    PKCS7_RECIP_INFO *ri = NULL;
++    ASN1_OCTET_STRING *os = NULL;
++
++    if (p7 == NULL) {
++        PKCS7err(PKCS7_F_PKCS7_DATAINIT, PKCS7_R_INVALID_NULL_POINTER);
++        return NULL;
++    }
++    /*
++     * The content field in the PKCS7 ContentInfo is optional, but that really
++     * only applies to inner content (precisely, detached signatures).
++     *
++     * When reading content, missing outer content is therefore treated as an
++     * error.
++     *
++     * When creating content, PKCS7_content_new() must be called before
++     * calling this method, so a NULL p7->d is always an error.
++     */
++    if (p7->d.ptr == NULL) {
++        PKCS7err(PKCS7_F_PKCS7_DATAINIT, PKCS7_R_NO_CONTENT);
++        return NULL;
++    }
++
++    i = OBJ_obj2nid(p7->type);
++    p7->state = PKCS7_S_HEADER;
++
++    switch (i) {
++    case NID_pkcs7_signed:
++        md_sk = p7->d.sign->md_algs;
++        os = PKCS7_get_octet_string(p7->d.sign->contents);
++        break;
++    case NID_pkcs7_signedAndEnveloped:
++        rsk = p7->d.signed_and_enveloped->recipientinfo;
++        md_sk = p7->d.signed_and_enveloped->md_algs;
++        xalg = p7->d.signed_and_enveloped->enc_data->algorithm;
++        evp_cipher = p7->d.signed_and_enveloped->enc_data->cipher;
++        if (evp_cipher == NULL) {
++            PKCS7err(PKCS7_F_PKCS7_DATAINIT, PKCS7_R_CIPHER_NOT_INITIALIZED);
++            goto err;
++        }
++        break;
++    case NID_pkcs7_enveloped:
++        rsk = p7->d.enveloped->recipientinfo;
++        xalg = p7->d.enveloped->enc_data->algorithm;
++        evp_cipher = p7->d.enveloped->enc_data->cipher;
++        if (evp_cipher == NULL) {
++            PKCS7err(PKCS7_F_PKCS7_DATAINIT, PKCS7_R_CIPHER_NOT_INITIALIZED);
++            goto err;
++        }
++        break;
++    case NID_pkcs7_digest:
++        xa = p7->d.digest->md;
++        os = PKCS7_get_octet_string(p7->d.digest->contents);
++        break;
++    case NID_pkcs7_data:
++        break;
++    default:
++        PKCS7err(PKCS7_F_PKCS7_DATAINIT, PKCS7_R_UNSUPPORTED_CONTENT_TYPE);
++        goto err;
++    }
++
++    for (i = 0; i < sk_X509_ALGOR_num(md_sk); i++)
++        if (!PKCS7_bio_add_digest(&out, sk_X509_ALGOR_value(md_sk, i)))
++            goto err;
++
++    if (xa && !PKCS7_bio_add_digest(&out, xa))
++        goto err;
++
++    if (evp_cipher != NULL) {
++        unsigned char key[EVP_MAX_KEY_LENGTH];
++        unsigned char iv[EVP_MAX_IV_LENGTH];
++        int keylen, ivlen;
++        EVP_CIPHER_CTX *ctx;
++
++        if ((btmp = BIO_new(BIO_f_cipher())) == NULL) {
++            PKCS7err(PKCS7_F_PKCS7_DATAINIT, ERR_R_BIO_LIB);
++            goto err;
++        }
++        BIO_get_cipher_ctx(btmp, &ctx);
++        keylen = EVP_CIPHER_key_length(evp_cipher);
++        ivlen = EVP_CIPHER_iv_length(evp_cipher);
++        xalg->algorithm = OBJ_nid2obj(EVP_CIPHER_type(evp_cipher));
++        if (ivlen > 0)
++            if (RAND_bytes(iv, ivlen) <= 0)
++                goto err;
++        if (EVP_CipherInit_ex(ctx, evp_cipher, NULL, NULL, NULL, 1) <= 0)
++            goto err;
++        if (EVP_CIPHER_CTX_rand_key(ctx, key) <= 0)
++            goto err;
++        if (EVP_CipherInit_ex(ctx, NULL, NULL, key, iv, 1) <= 0)
++            goto err;
++
++        if (ivlen > 0) {
++            if (xalg->parameter == NULL) {
++                xalg->parameter = ASN1_TYPE_new();
++                if (xalg->parameter == NULL)
++                    goto err;
++            }
++            if (EVP_CIPHER_param_to_asn1(ctx, xalg->parameter) < 0)
++                goto err;
++        }
++
++        /* Lets do the pub key stuff :-) */
++        for (i = 0; i < sk_PKCS7_RECIP_INFO_num(rsk); i++) {
++            ri = sk_PKCS7_RECIP_INFO_value(rsk, i);
++            if (pkcs7_encode_rinfo(ri, key, keylen) <= 0)
++                goto err;
++        }
++        OPENSSL_cleanse(key, keylen);
++
++        if (out == NULL)
++            out = btmp;
++        else
++            BIO_push(out, btmp);
++        btmp = NULL;
++    }
++
++    if (bio == NULL) {
++        if (PKCS7_is_detached(p7))
++            bio = BIO_new(BIO_s_null());
++        else if (os && os->length > 0)
++            bio = BIO_new_mem_buf(os->data, os->length);
++        if (bio == NULL) {
++            bio = BIO_new(BIO_s_mem());
++            if (bio == NULL)
++                goto err;
++            BIO_set_mem_eof_return(bio, 0);
++        }
++    }
++    if (out)
++        BIO_push(out, bio);
++    else
++        out = bio;
++    return out;
++
++ err:
++    BIO_free_all(out);
++    BIO_free_all(btmp);
++    return NULL;
++}
++
++static int pkcs7_cmp_ri(PKCS7_RECIP_INFO *ri, X509 *pcert)
++{
++    int ret;
++    ret = X509_NAME_cmp(ri->issuer_and_serial->issuer,
++                        X509_get_issuer_name(pcert));
++    if (ret)
++        return ret;
++    return ASN1_INTEGER_cmp(X509_get_serialNumber(pcert),
++                            ri->issuer_and_serial->serial);
++}
++
++/* int */
++BIO *PKCS7_dataDecode(PKCS7 *p7, EVP_PKEY *pkey, BIO *in_bio, X509 *pcert)
++{
++    int i, j;
++    BIO *out = NULL, *btmp = NULL, *etmp = NULL, *bio = NULL;
++    X509_ALGOR *xa;
++    ASN1_OCTET_STRING *data_body = NULL;
++    const EVP_MD *evp_md;
++    const EVP_CIPHER *evp_cipher = NULL;
++    EVP_CIPHER_CTX *evp_ctx = NULL;
++    X509_ALGOR *enc_alg = NULL;
++    STACK_OF(X509_ALGOR) *md_sk = NULL;
++    STACK_OF(PKCS7_RECIP_INFO) *rsk = NULL;
++    PKCS7_RECIP_INFO *ri = NULL;
++    unsigned char *ek = NULL, *tkey = NULL;
++    int eklen = 0, tkeylen = 0;
++
++    if (p7 == NULL) {
++        PKCS7err(PKCS7_F_PKCS7_DATADECODE, PKCS7_R_INVALID_NULL_POINTER);
++        return NULL;
++    }
++
++    if (p7->d.ptr == NULL) {
++        PKCS7err(PKCS7_F_PKCS7_DATADECODE, PKCS7_R_NO_CONTENT);
++        return NULL;
++    }
++
++    i = OBJ_obj2nid(p7->type);
++    p7->state = PKCS7_S_HEADER;
++
++    switch (i) {
++    case NID_pkcs7_signed:
++        /*
++         * p7->d.sign->contents is a PKCS7 structure consisting of a contentType
++         * field and optional content.
++         * data_body is NULL if that structure has no (=detached) content
++         * or if the contentType is wrong (i.e., not "data").
++         */
++        data_body = PKCS7_get_octet_string(p7->d.sign->contents);
++        if (!PKCS7_is_detached(p7) && data_body == NULL) {
++            PKCS7err(PKCS7_F_PKCS7_DATADECODE,
++                     PKCS7_R_INVALID_SIGNED_DATA_TYPE);
++            goto err;
++        }
++        md_sk = p7->d.sign->md_algs;
++        break;
++    case NID_pkcs7_signedAndEnveloped:
++        rsk = p7->d.signed_and_enveloped->recipientinfo;
++        md_sk = p7->d.signed_and_enveloped->md_algs;
++        /* data_body is NULL if the optional EncryptedContent is missing. */
++        data_body = p7->d.signed_and_enveloped->enc_data->enc_data;
++        enc_alg = p7->d.signed_and_enveloped->enc_data->algorithm;
++        evp_cipher = EVP_get_cipherbyobj(enc_alg->algorithm);
++        if (evp_cipher == NULL) {
++            PKCS7err(PKCS7_F_PKCS7_DATADECODE,
++                     PKCS7_R_UNSUPPORTED_CIPHER_TYPE);
++            goto err;
++        }
++        break;
++    case NID_pkcs7_enveloped:
++        rsk = p7->d.enveloped->recipientinfo;
++        enc_alg = p7->d.enveloped->enc_data->algorithm;
++        /* data_body is NULL if the optional EncryptedContent is missing. */
++        data_body = p7->d.enveloped->enc_data->enc_data;
++        evp_cipher = EVP_get_cipherbyobj(enc_alg->algorithm);
++        if (evp_cipher == NULL) {
++            PKCS7err(PKCS7_F_PKCS7_DATADECODE,
++                     PKCS7_R_UNSUPPORTED_CIPHER_TYPE);
++            goto err;
++        }
++        break;
++    default:
++        PKCS7err(PKCS7_F_PKCS7_DATADECODE, PKCS7_R_UNSUPPORTED_CONTENT_TYPE);
++        goto err;
++    }
++
++    /* Detached content must be supplied via in_bio instead. */
++    if (data_body == NULL && in_bio == NULL) {
++        PKCS7err(PKCS7_F_PKCS7_DATADECODE, PKCS7_R_NO_CONTENT);
++        goto err;
++    }
++
++    /* We will be checking the signature */
++    if (md_sk != NULL) {
++        for (i = 0; i < sk_X509_ALGOR_num(md_sk); i++) {
++            xa = sk_X509_ALGOR_value(md_sk, i);
++            if ((btmp = BIO_new(BIO_f_md())) == NULL) {
++                PKCS7err(PKCS7_F_PKCS7_DATADECODE, ERR_R_BIO_LIB);
++                goto err;
++            }
++
++            j = OBJ_obj2nid(xa->algorithm);
++            evp_md = EVP_get_digestbynid(j);
++            if (evp_md == NULL) {
++                PKCS7err(PKCS7_F_PKCS7_DATADECODE,
++                         PKCS7_R_UNKNOWN_DIGEST_TYPE);
++                goto err;
++            }
++
++            BIO_set_md(btmp, evp_md);
++            if (out == NULL)
++                out = btmp;
++            else
++                BIO_push(out, btmp);
++            btmp = NULL;
++        }
++    }
++
++    if (evp_cipher != NULL) {
++        if ((etmp = BIO_new(BIO_f_cipher())) == NULL) {
++            PKCS7err(PKCS7_F_PKCS7_DATADECODE, ERR_R_BIO_LIB);
++            goto err;
++        }
++
++        /*
++         * It was encrypted, we need to decrypt the secret key with the
++         * private key
++         */
++
++        /*
++         * Find the recipientInfo which matches the passed certificate (if
++         * any)
++         */
++
++        if (pcert) {
++            for (i = 0; i < sk_PKCS7_RECIP_INFO_num(rsk); i++) {
++                ri = sk_PKCS7_RECIP_INFO_value(rsk, i);
++                if (!pkcs7_cmp_ri(ri, pcert))
++                    break;
++                ri = NULL;
++            }
++            if (ri == NULL) {
++                PKCS7err(PKCS7_F_PKCS7_DATADECODE,
++                         PKCS7_R_NO_RECIPIENT_MATCHES_CERTIFICATE);
++                goto err;
++            }
++        }
++
++        /* If we haven't got a certificate try each ri in turn */
++        if (pcert == NULL) {
++            /*
++             * Always attempt to decrypt all rinfo even after success as a
++             * defence against MMA timing attacks.
++             */
++            for (i = 0; i < sk_PKCS7_RECIP_INFO_num(rsk); i++) {
++                ri = sk_PKCS7_RECIP_INFO_value(rsk, i);
++
++                if (pkcs7_decrypt_rinfo(&ek, &eklen, ri, pkey) < 0)
++                    goto err;
++                ERR_clear_error();
++            }
++        } else {
++            /* Only exit on fatal errors, not decrypt failure */
++            if (pkcs7_decrypt_rinfo(&ek, &eklen, ri, pkey) < 0)
++                goto err;
++            ERR_clear_error();
++        }
++
++        evp_ctx = NULL;
++        BIO_get_cipher_ctx(etmp, &evp_ctx);
++        if (EVP_CipherInit_ex(evp_ctx, evp_cipher, NULL, NULL, NULL, 0) <= 0)
++            goto err;
++        if (EVP_CIPHER_asn1_to_param(evp_ctx, enc_alg->parameter) < 0)
++            goto err;
++        /* Generate random key as MMA defence */
++        tkeylen = EVP_CIPHER_CTX_key_length(evp_ctx);
++        tkey = OPENSSL_malloc(tkeylen);
++        if (tkey == NULL)
++            goto err;
++        if (EVP_CIPHER_CTX_rand_key(evp_ctx, tkey) <= 0)
++            goto err;
++        if (ek == NULL) {
++            ek = tkey;
++            eklen = tkeylen;
++            tkey = NULL;
++        }
++
++        if (eklen != EVP_CIPHER_CTX_key_length(evp_ctx)) {
++            /*
++             * Some S/MIME clients don't use the same key and effective key
++             * length. The key length is determined by the size of the
++             * decrypted RSA key.
++             */
++            if (!EVP_CIPHER_CTX_set_key_length(evp_ctx, eklen)) {
++                /* Use random key as MMA defence */
++                OPENSSL_clear_free(ek, eklen);
++                ek = tkey;
++                eklen = tkeylen;
++                tkey = NULL;
++            }
++        }
++        /* Clear errors so we don't leak information useful in MMA */
++        ERR_clear_error();
++        if (EVP_CipherInit_ex(evp_ctx, NULL, NULL, ek, NULL, 0) <= 0)
++            goto err;
++
++        OPENSSL_clear_free(ek, eklen);
++        ek = NULL;
++        OPENSSL_clear_free(tkey, tkeylen);
++        tkey = NULL;
++
++        if (out == NULL)
++            out = etmp;
++        else
++            BIO_push(out, etmp);
++        etmp = NULL;
++    }
++    if (in_bio != NULL) {
++        bio = in_bio;
++    } else {
++        if (data_body->length > 0)
++            bio = BIO_new_mem_buf(data_body->data, data_body->length);
++        else {
++            bio = BIO_new(BIO_s_mem());
++            if (bio == NULL)
++                goto err;
++            BIO_set_mem_eof_return(bio, 0);
++        }
++        if (bio == NULL)
++            goto err;
++    }
++    BIO_push(out, bio);
++    bio = NULL;
++    return out;
++
++ err:
++    OPENSSL_clear_free(ek, eklen);
++    OPENSSL_clear_free(tkey, tkeylen);
++    BIO_free_all(out);
++    BIO_free_all(btmp);
++    BIO_free_all(etmp);
++    BIO_free_all(bio);
++    return NULL;
++}
++
++static BIO *PKCS7_find_digest(EVP_MD_CTX **pmd, BIO *bio, int nid)
++{
++    for (;;) {
++        bio = BIO_find_type(bio, BIO_TYPE_MD);
++        if (bio == NULL) {
++            PKCS7err(PKCS7_F_PKCS7_FIND_DIGEST,
++                     PKCS7_R_UNABLE_TO_FIND_MESSAGE_DIGEST);
++            return NULL;
++        }
++        BIO_get_md_ctx(bio, pmd);
++        if (*pmd == NULL) {
++            PKCS7err(PKCS7_F_PKCS7_FIND_DIGEST, ERR_R_INTERNAL_ERROR);
++            return NULL;
++        }
++        if (EVP_MD_CTX_type(*pmd) == nid)
++            return bio;
++        bio = BIO_next(bio);
++    }
++    return NULL;
++}
++
++static int do_pkcs7_signed_attrib(PKCS7_SIGNER_INFO *si, EVP_MD_CTX *mctx)
++{
++    unsigned char md_data[EVP_MAX_MD_SIZE];
++    unsigned int md_len;
++
++    /* Add signing time if not already present */
++    if (!PKCS7_get_signed_attribute(si, NID_pkcs9_signingTime)) {
++        if (!PKCS7_add0_attrib_signing_time(si, NULL)) {
++            PKCS7err(PKCS7_F_DO_PKCS7_SIGNED_ATTRIB, ERR_R_MALLOC_FAILURE);
++            return 0;
++        }
++    }
++
++    /* Add digest */
++    if (!EVP_DigestFinal_ex(mctx, md_data, &md_len)) {
++        PKCS7err(PKCS7_F_DO_PKCS7_SIGNED_ATTRIB, ERR_R_EVP_LIB);
++        return 0;
++    }
++    if (!PKCS7_add1_attrib_digest(si, md_data, md_len)) {
++        PKCS7err(PKCS7_F_DO_PKCS7_SIGNED_ATTRIB, ERR_R_MALLOC_FAILURE);
++        return 0;
++    }
++
++    /* Now sign the attributes */
++    if (!PKCS7_SIGNER_INFO_sign(si))
++        return 0;
++
++    return 1;
++}
++
++int PKCS7_dataFinal(PKCS7 *p7, BIO *bio)
++{
++    int ret = 0;
++    int i, j;
++    BIO *btmp;
++    PKCS7_SIGNER_INFO *si;
++    EVP_MD_CTX *mdc, *ctx_tmp;
++    STACK_OF(X509_ATTRIBUTE) *sk;
++    STACK_OF(PKCS7_SIGNER_INFO) *si_sk = NULL;
++    ASN1_OCTET_STRING *os = NULL;
++
++    if (p7 == NULL) {
++        PKCS7err(PKCS7_F_PKCS7_DATAFINAL, PKCS7_R_INVALID_NULL_POINTER);
++        return 0;
++    }
++
++    if (p7->d.ptr == NULL) {
++        PKCS7err(PKCS7_F_PKCS7_DATAFINAL, PKCS7_R_NO_CONTENT);
++        return 0;
++    }
++
++    ctx_tmp = EVP_MD_CTX_new();
++    if (ctx_tmp == NULL) {
++        PKCS7err(PKCS7_F_PKCS7_DATAFINAL, ERR_R_MALLOC_FAILURE);
++        return 0;
++    }
++
++    i = OBJ_obj2nid(p7->type);
++    p7->state = PKCS7_S_HEADER;
++
++    switch (i) {
++    case NID_pkcs7_data:
++        os = p7->d.data;
++        break;
++    case NID_pkcs7_signedAndEnveloped:
++        /* XXXXXXXXXXXXXXXX */
++        si_sk = p7->d.signed_and_enveloped->signer_info;
++        os = p7->d.signed_and_enveloped->enc_data->enc_data;
++        if (os == NULL) {
++            os = ASN1_OCTET_STRING_new();
++            if (os == NULL) {
++                PKCS7err(PKCS7_F_PKCS7_DATAFINAL, ERR_R_MALLOC_FAILURE);
++                goto err;
++            }
++            p7->d.signed_and_enveloped->enc_data->enc_data = os;
++        }
++        break;
++    case NID_pkcs7_enveloped:
++        /* XXXXXXXXXXXXXXXX */
++        os = p7->d.enveloped->enc_data->enc_data;
++        if (os == NULL) {
++            os = ASN1_OCTET_STRING_new();
++            if (os == NULL) {
++                PKCS7err(PKCS7_F_PKCS7_DATAFINAL, ERR_R_MALLOC_FAILURE);
++                goto err;
++            }
++            p7->d.enveloped->enc_data->enc_data = os;
++        }
++        break;
++    case NID_pkcs7_signed:
++        si_sk = p7->d.sign->signer_info;
++        os = PKCS7_get_octet_string(p7->d.sign->contents);
++        /* If detached data then the content is excluded */
++        if (PKCS7_type_is_data(p7->d.sign->contents) && p7->detached) {
++            ASN1_OCTET_STRING_free(os);
++            os = NULL;
++            p7->d.sign->contents->d.data = NULL;
++        }
++        break;
++
++    case NID_pkcs7_digest:
++        os = PKCS7_get_octet_string(p7->d.digest->contents);
++        /* If detached data then the content is excluded */
++        if (PKCS7_type_is_data(p7->d.digest->contents) && p7->detached) {
++            ASN1_OCTET_STRING_free(os);
++            os = NULL;
++            p7->d.digest->contents->d.data = NULL;
++        }
++        break;
++
++    default:
++        PKCS7err(PKCS7_F_PKCS7_DATAFINAL, PKCS7_R_UNSUPPORTED_CONTENT_TYPE);
++        goto err;
++    }
++
++    if (si_sk != NULL) {
++        for (i = 0; i < sk_PKCS7_SIGNER_INFO_num(si_sk); i++) {
++            si = sk_PKCS7_SIGNER_INFO_value(si_sk, i);
++            if (si->pkey == NULL)
++                continue;
++
++            j = OBJ_obj2nid(si->digest_alg->algorithm);
++
++            btmp = bio;
++
++            btmp = PKCS7_find_digest(&mdc, btmp, j);
++
++            if (btmp == NULL)
++                goto err;
++
++            /*
++             * We now have the EVP_MD_CTX, lets do the signing.
++             */
++            if (!EVP_MD_CTX_copy_ex(ctx_tmp, mdc))
++                goto err;
++
++            sk = si->auth_attr;
++
++            /*
++             * If there are attributes, we add the digest attribute and only
++             * sign the attributes
++             */
++            if (sk_X509_ATTRIBUTE_num(sk) > 0) {
++                if (!do_pkcs7_signed_attrib(si, ctx_tmp))
++                    goto err;
++            } else {
++                unsigned char *abuf = NULL;
++                unsigned int abuflen;
++                abuflen = EVP_PKEY_size(si->pkey);
++                abuf = OPENSSL_malloc(abuflen);
++                if (abuf == NULL)
++                    goto err;
++
++                if (!EVP_SignFinal(ctx_tmp, abuf, &abuflen, si->pkey)) {
++                    OPENSSL_free(abuf);
++                    PKCS7err(PKCS7_F_PKCS7_DATAFINAL, ERR_R_EVP_LIB);
++                    goto err;
++                }
++                ASN1_STRING_set0(si->enc_digest, abuf, abuflen);
++            }
++        }
++    } else if (i == NID_pkcs7_digest) {
++        unsigned char md_data[EVP_MAX_MD_SIZE];
++        unsigned int md_len;
++        if (!PKCS7_find_digest(&mdc, bio,
++                               OBJ_obj2nid(p7->d.digest->md->algorithm)))
++            goto err;
++        if (!EVP_DigestFinal_ex(mdc, md_data, &md_len))
++            goto err;
++        if (!ASN1_OCTET_STRING_set(p7->d.digest->digest, md_data, md_len))
++            goto err;
++    }
++
++    if (!PKCS7_is_detached(p7)) {
++        /*
++         * NOTE(emilia): I think we only reach os == NULL here because detached
++         * digested data support is broken.
++         */
++        if (os == NULL)
++            goto err;
++        if (!(os->flags & ASN1_STRING_FLAG_NDEF)) {
++            char *cont;
++            long contlen;
++            btmp = BIO_find_type(bio, BIO_TYPE_MEM);
++            if (btmp == NULL) {
++                PKCS7err(PKCS7_F_PKCS7_DATAFINAL, PKCS7_R_UNABLE_TO_FIND_MEM_BIO);
++                goto err;
++            }
++            contlen = BIO_get_mem_data(btmp, &cont);
++            /*
++             * Mark the BIO read only then we can use its copy of the data
++             * instead of making an extra copy.
++             */
++            BIO_set_flags(btmp, BIO_FLAGS_MEM_RDONLY);
++            BIO_set_mem_eof_return(btmp, 0);
++            ASN1_STRING_set0(os, (unsigned char *)cont, contlen);
++        }
++    }
++    ret = 1;
++ err:
++    EVP_MD_CTX_free(ctx_tmp);
++    return (ret);
++}
++
++int PKCS7_SIGNER_INFO_sign(PKCS7_SIGNER_INFO *si)
++{
++    EVP_MD_CTX *mctx;
++    EVP_PKEY_CTX *pctx;
++    unsigned char *abuf = NULL;
++    int alen;
++    size_t siglen;
++    const EVP_MD *md = NULL;
++
++    md = EVP_get_digestbyobj(si->digest_alg->algorithm);
++    if (md == NULL)
++        return 0;
++
++    mctx = EVP_MD_CTX_new();
++    if (mctx == NULL) {
++        PKCS7err(PKCS7_F_PKCS7_SIGNER_INFO_SIGN, ERR_R_MALLOC_FAILURE);
++        goto err;
++    }
++
++    if (EVP_DigestSignInit(mctx, &pctx, md, NULL, si->pkey) <= 0)
++        goto err;
++
++    if (EVP_PKEY_CTX_ctrl(pctx, -1, EVP_PKEY_OP_SIGN,
++                          EVP_PKEY_CTRL_PKCS7_SIGN, 0, si) <= 0) {
++        PKCS7err(PKCS7_F_PKCS7_SIGNER_INFO_SIGN, PKCS7_R_CTRL_ERROR);
++        goto err;
++    }
++
++    alen = ASN1_item_i2d((ASN1_VALUE *)si->auth_attr, &abuf,
++                         ASN1_ITEM_rptr(PKCS7_ATTR_SIGN));
++    if (!abuf)
++        goto err;
++    if (EVP_DigestSignUpdate(mctx, abuf, alen) <= 0)
++        goto err;
++    OPENSSL_free(abuf);
++    abuf = NULL;
++    if (EVP_DigestSignFinal(mctx, NULL, &siglen) <= 0)
++        goto err;
++    abuf = OPENSSL_malloc(siglen);
++    if (abuf == NULL)
++        goto err;
++    if (EVP_DigestSignFinal(mctx, abuf, &siglen) <= 0)
++        goto err;
++
++    if (EVP_PKEY_CTX_ctrl(pctx, -1, EVP_PKEY_OP_SIGN,
++                          EVP_PKEY_CTRL_PKCS7_SIGN, 1, si) <= 0) {
++        PKCS7err(PKCS7_F_PKCS7_SIGNER_INFO_SIGN, PKCS7_R_CTRL_ERROR);
++        goto err;
++    }
++
++    EVP_MD_CTX_free(mctx);
++
++    ASN1_STRING_set0(si->enc_digest, abuf, siglen);
++
++    return 1;
++
++ err:
++    OPENSSL_free(abuf);
++    EVP_MD_CTX_free(mctx);
++    return 0;
++
++}
++
++int PKCS7_dataVerify(X509_STORE *cert_store, X509_STORE_CTX *ctx, BIO *bio,
++                     PKCS7 *p7, PKCS7_SIGNER_INFO *si)
++{
++    PKCS7_ISSUER_AND_SERIAL *ias;
++    int ret = 0, i;
++    STACK_OF(X509) *cert;
++    X509 *x509;
++
++    if (p7 == NULL) {
++        PKCS7err(PKCS7_F_PKCS7_DATAVERIFY, PKCS7_R_INVALID_NULL_POINTER);
++        return 0;
++    }
++
++    if (p7->d.ptr == NULL) {
++        PKCS7err(PKCS7_F_PKCS7_DATAVERIFY, PKCS7_R_NO_CONTENT);
++        return 0;
++    }
++
++    if (PKCS7_type_is_signed(p7)) {
++        cert = p7->d.sign->cert;
++    } else if (PKCS7_type_is_signedAndEnveloped(p7)) {
++        cert = p7->d.signed_and_enveloped->cert;
++    } else {
++        PKCS7err(PKCS7_F_PKCS7_DATAVERIFY, PKCS7_R_WRONG_PKCS7_TYPE);
++        goto err;
++    }
++    /* XXXXXXXXXXXXXXXXXXXXXXX */
++    ias = si->issuer_and_serial;
++
++    x509 = X509_find_by_issuer_and_serial(cert, ias->issuer, ias->serial);
++
++    /* were we able to find the cert in passed to us */
++    if (x509 == NULL) {
++        PKCS7err(PKCS7_F_PKCS7_DATAVERIFY,
++                 PKCS7_R_UNABLE_TO_FIND_CERTIFICATE);
++        goto err;
++    }
++
++    /* Lets verify */
++    if (!X509_STORE_CTX_init(ctx, cert_store, x509, cert)) {
++        PKCS7err(PKCS7_F_PKCS7_DATAVERIFY, ERR_R_X509_LIB);
++        goto err;
++    }
++    X509_STORE_CTX_set_purpose(ctx, X509_PURPOSE_SMIME_SIGN);
++    i = X509_verify_cert(ctx);
++    if (i <= 0) {
++        PKCS7err(PKCS7_F_PKCS7_DATAVERIFY, ERR_R_X509_LIB);
++        X509_STORE_CTX_cleanup(ctx);
++        goto err;
++    }
++    X509_STORE_CTX_cleanup(ctx);
++
++    return PKCS7_signatureVerify(bio, p7, si, x509);
++ err:
++    return ret;
++}
++
++int PKCS7_signatureVerify(BIO *bio, PKCS7 *p7, PKCS7_SIGNER_INFO *si,
++                          X509 *x509)
++{
++    ASN1_OCTET_STRING *os;
++    EVP_MD_CTX *mdc_tmp, *mdc;
++    int ret = 0, i;
++    int md_type;
++    STACK_OF(X509_ATTRIBUTE) *sk;
++    BIO *btmp;
++    EVP_PKEY *pkey;
++
++    mdc_tmp = EVP_MD_CTX_new();
++    if (mdc_tmp == NULL) {
++        PKCS7err(PKCS7_F_PKCS7_SIGNATUREVERIFY, ERR_R_MALLOC_FAILURE);
++        goto err;
++    }
++
++    if (!PKCS7_type_is_signed(p7) && !PKCS7_type_is_signedAndEnveloped(p7)) {
++        PKCS7err(PKCS7_F_PKCS7_SIGNATUREVERIFY, PKCS7_R_WRONG_PKCS7_TYPE);
++        goto err;
++    }
++
++    md_type = OBJ_obj2nid(si->digest_alg->algorithm);
++
++    btmp = bio;
++    for (;;) {
++        if ((btmp == NULL) ||
++            ((btmp = BIO_find_type(btmp, BIO_TYPE_MD)) == NULL)) {
++            PKCS7err(PKCS7_F_PKCS7_SIGNATUREVERIFY,
++                     PKCS7_R_UNABLE_TO_FIND_MESSAGE_DIGEST);
++            goto err;
++        }
++        BIO_get_md_ctx(btmp, &mdc);
++        if (mdc == NULL) {
++            PKCS7err(PKCS7_F_PKCS7_SIGNATUREVERIFY, ERR_R_INTERNAL_ERROR);
++            goto err;
++        }
++        if (EVP_MD_CTX_type(mdc) == md_type)
++            break;
++        /*
++         * Workaround for some broken clients that put the signature OID
++         * instead of the digest OID in digest_alg->algorithm
++         */
++        if (EVP_MD_pkey_type(EVP_MD_CTX_md(mdc)) == md_type)
++            break;
++        btmp = BIO_next(btmp);
++    }
++
++    /*
++     * mdc is the digest ctx that we want, unless there are attributes, in
++     * which case the digest is the signed attributes
++     */
++    if (!EVP_MD_CTX_copy_ex(mdc_tmp, mdc))
++        goto err;
++
++    sk = si->auth_attr;
++    if ((sk != NULL) && (sk_X509_ATTRIBUTE_num(sk) != 0)) {
++        unsigned char md_dat[EVP_MAX_MD_SIZE], *abuf = NULL;
++        unsigned int md_len;
++        int alen;
++        ASN1_OCTET_STRING *message_digest;
++
++        if (!EVP_DigestFinal_ex(mdc_tmp, md_dat, &md_len))
++            goto err;
++        message_digest = PKCS7_digest_from_attributes(sk);
++        if (!message_digest) {
++            PKCS7err(PKCS7_F_PKCS7_SIGNATUREVERIFY,
++                     PKCS7_R_UNABLE_TO_FIND_MESSAGE_DIGEST);
++            goto err;
++        }
++        if ((message_digest->length != (int)md_len) ||
++            (memcmp(message_digest->data, md_dat, md_len))) {
++            PKCS7err(PKCS7_F_PKCS7_SIGNATUREVERIFY, PKCS7_R_DIGEST_FAILURE);
++            ret = -1;
++            goto err;
++        }
++
++        if (!EVP_VerifyInit_ex(mdc_tmp, EVP_get_digestbynid(md_type), NULL))
++            goto err;
++
++        alen = ASN1_item_i2d((ASN1_VALUE *)sk, &abuf,
++                             ASN1_ITEM_rptr(PKCS7_ATTR_VERIFY));
++        if (alen <= 0) {
++            PKCS7err(PKCS7_F_PKCS7_SIGNATUREVERIFY, ERR_R_ASN1_LIB);
++            ret = -1;
++            goto err;
++        }
++        if (!EVP_VerifyUpdate(mdc_tmp, abuf, alen))
++            goto err;
++
++        OPENSSL_free(abuf);
++    }
++
++    os = si->enc_digest;
++    pkey = X509_get0_pubkey(x509);
++    if (!pkey) {
++        ret = -1;
++        goto err;
++    }
++
++    i = EVP_VerifyFinal(mdc_tmp, os->data, os->length, pkey);
++    if (i <= 0) {
++        PKCS7err(PKCS7_F_PKCS7_SIGNATUREVERIFY, PKCS7_R_SIGNATURE_FAILURE);
++        ret = -1;
++        goto err;
++    }
++    ret = 1;
++ err:
++    EVP_MD_CTX_free(mdc_tmp);
++    return (ret);
++}
++
++PKCS7_ISSUER_AND_SERIAL *PKCS7_get_issuer_and_serial(PKCS7 *p7, int idx)
++{
++    STACK_OF(PKCS7_RECIP_INFO) *rsk;
++    PKCS7_RECIP_INFO *ri;
++    int i;
++
++    i = OBJ_obj2nid(p7->type);
++    if (i != NID_pkcs7_signedAndEnveloped)
++        return NULL;
++    if (p7->d.signed_and_enveloped == NULL)
++        return NULL;
++    rsk = p7->d.signed_and_enveloped->recipientinfo;
++    if (rsk == NULL)
++        return NULL;
++    if (sk_PKCS7_RECIP_INFO_num(rsk) <= idx)
++        return (NULL);
++    ri = sk_PKCS7_RECIP_INFO_value(rsk, idx);
++    return (ri->issuer_and_serial);
++}
++
++ASN1_TYPE *PKCS7_get_signed_attribute(PKCS7_SIGNER_INFO *si, int nid)
++{
++    return (get_attribute(si->auth_attr, nid));
++}
++
++ASN1_TYPE *PKCS7_get_attribute(PKCS7_SIGNER_INFO *si, int nid)
++{
++    return (get_attribute(si->unauth_attr, nid));
++}
++
++static ASN1_TYPE *get_attribute(STACK_OF(X509_ATTRIBUTE) *sk, int nid)
++{
++    int idx;
++    X509_ATTRIBUTE *xa;
++    idx = X509at_get_attr_by_NID(sk, nid, -1);
++    xa = X509at_get_attr(sk, idx);
++    return X509_ATTRIBUTE_get0_type(xa, 0);
++}
++
++ASN1_OCTET_STRING *PKCS7_digest_from_attributes(STACK_OF(X509_ATTRIBUTE) *sk)
++{
++    ASN1_TYPE *astype;
++    if ((astype = get_attribute(sk, NID_pkcs9_messageDigest)) == NULL)
++        return NULL;
++    return astype->value.octet_string;
++}
++
++int PKCS7_set_signed_attributes(PKCS7_SIGNER_INFO *p7si,
++                                STACK_OF(X509_ATTRIBUTE) *sk)
++{
++    int i;
++
++    sk_X509_ATTRIBUTE_pop_free(p7si->auth_attr, X509_ATTRIBUTE_free);
++    p7si->auth_attr = sk_X509_ATTRIBUTE_dup(sk);
++    if (p7si->auth_attr == NULL)
++        return 0;
++    for (i = 0; i < sk_X509_ATTRIBUTE_num(sk); i++) {
++        if ((sk_X509_ATTRIBUTE_set(p7si->auth_attr, i,
++                                   X509_ATTRIBUTE_dup(sk_X509_ATTRIBUTE_value
++                                                      (sk, i))))
++            == NULL)
++            return (0);
++    }
++    return (1);
++}
++
++int PKCS7_set_attributes(PKCS7_SIGNER_INFO *p7si,
++                         STACK_OF(X509_ATTRIBUTE) *sk)
++{
++    int i;
++
++    sk_X509_ATTRIBUTE_pop_free(p7si->unauth_attr, X509_ATTRIBUTE_free);
++    p7si->unauth_attr = sk_X509_ATTRIBUTE_dup(sk);
++    if (p7si->unauth_attr == NULL)
++        return 0;
++    for (i = 0; i < sk_X509_ATTRIBUTE_num(sk); i++) {
++        if ((sk_X509_ATTRIBUTE_set(p7si->unauth_attr, i,
++                                   X509_ATTRIBUTE_dup(sk_X509_ATTRIBUTE_value
++                                                      (sk, i))))
++            == NULL)
++            return (0);
++    }
++    return (1);
++}
++
++int PKCS7_add_signed_attribute(PKCS7_SIGNER_INFO *p7si, int nid, int atrtype,
++                               void *value)
++{
++    return (add_attribute(&(p7si->auth_attr), nid, atrtype, value));
++}
++
++int PKCS7_add_attribute(PKCS7_SIGNER_INFO *p7si, int nid, int atrtype,
++                        void *value)
++{
++    return (add_attribute(&(p7si->unauth_attr), nid, atrtype, value));
++}
++
++static int add_attribute(STACK_OF(X509_ATTRIBUTE) **sk, int nid, int atrtype,
++                         void *value)
++{
++    X509_ATTRIBUTE *attr = NULL;
++
++    if (*sk == NULL) {
++        if ((*sk = sk_X509_ATTRIBUTE_new_null()) == NULL)
++            return 0;
++ new_attrib:
++        if ((attr = X509_ATTRIBUTE_create(nid, atrtype, value)) == NULL)
++            return 0;
++        if (!sk_X509_ATTRIBUTE_push(*sk, attr)) {
++            X509_ATTRIBUTE_free(attr);
++            return 0;
++        }
++    } else {
++        int i;
++
++        for (i = 0; i < sk_X509_ATTRIBUTE_num(*sk); i++) {
++            attr = sk_X509_ATTRIBUTE_value(*sk, i);
++            if (OBJ_obj2nid(X509_ATTRIBUTE_get0_object(attr)) == nid) {
++                X509_ATTRIBUTE_free(attr);
++                attr = X509_ATTRIBUTE_create(nid, atrtype, value);
++                if (attr == NULL)
++                    return 0;
++                if (!sk_X509_ATTRIBUTE_set(*sk, i, attr)) {
++                    X509_ATTRIBUTE_free(attr);
++                    return 0;
++                }
++                goto end;
++            }
++        }
++        goto new_attrib;
++    }
++ end:
++    return (1);
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/pkcs7/pk7_enc.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/pkcs7/pk7_enc.c
+new file mode 100644
+index 0000000..3c59f9c
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/pkcs7/pk7_enc.c
+@@ -0,0 +1,25 @@
++/*
++ * Copyright 1995-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include "internal/cryptlib.h"
++#include 
++#include 
++#include 
++#include 
++
++PKCS7_in_bio(PKCS7 *p7, BIO *in);
++PKCS7_out_bio(PKCS7 *p7, BIO *out);
++
++PKCS7_add_signer(PKCS7 *p7, X509 *cert, EVP_PKEY *key);
++PKCS7_cipher(PKCS7 *p7, EVP_CIPHER *cipher);
++
++PKCS7_Init(PKCS7 *p7);
++PKCS7_Update(PKCS7 *p7);
++PKCS7_Finish(PKCS7 *p7);
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/pkcs7/pk7_lib.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/pkcs7/pk7_lib.c
+new file mode 100644
+index 0000000..69c68cf
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/pkcs7/pk7_lib.c
+@@ -0,0 +1,589 @@
++/*
++ * Copyright 1995-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include "internal/cryptlib.h"
++#include 
++#include 
++#include "internal/asn1_int.h"
++#include "internal/evp_int.h"
++
++long PKCS7_ctrl(PKCS7 *p7, int cmd, long larg, char *parg)
++{
++    int nid;
++    long ret;
++
++    nid = OBJ_obj2nid(p7->type);
++
++    switch (cmd) {
++    /* NOTE(emilia): does not support detached digested data. */
++    case PKCS7_OP_SET_DETACHED_SIGNATURE:
++        if (nid == NID_pkcs7_signed) {
++            ret = p7->detached = (int)larg;
++            if (ret && PKCS7_type_is_data(p7->d.sign->contents)) {
++                ASN1_OCTET_STRING *os;
++                os = p7->d.sign->contents->d.data;
++                ASN1_OCTET_STRING_free(os);
++                p7->d.sign->contents->d.data = NULL;
++            }
++        } else {
++            PKCS7err(PKCS7_F_PKCS7_CTRL,
++                     PKCS7_R_OPERATION_NOT_SUPPORTED_ON_THIS_TYPE);
++            ret = 0;
++        }
++        break;
++    case PKCS7_OP_GET_DETACHED_SIGNATURE:
++        if (nid == NID_pkcs7_signed) {
++            if (!p7->d.sign || !p7->d.sign->contents->d.ptr)
++                ret = 1;
++            else
++                ret = 0;
++
++            p7->detached = ret;
++        } else {
++            PKCS7err(PKCS7_F_PKCS7_CTRL,
++                     PKCS7_R_OPERATION_NOT_SUPPORTED_ON_THIS_TYPE);
++            ret = 0;
++        }
++
++        break;
++    default:
++        PKCS7err(PKCS7_F_PKCS7_CTRL, PKCS7_R_UNKNOWN_OPERATION);
++        ret = 0;
++    }
++    return (ret);
++}
++
++int PKCS7_content_new(PKCS7 *p7, int type)
++{
++    PKCS7 *ret = NULL;
++
++    if ((ret = PKCS7_new()) == NULL)
++        goto err;
++    if (!PKCS7_set_type(ret, type))
++        goto err;
++    if (!PKCS7_set_content(p7, ret))
++        goto err;
++
++    return (1);
++ err:
++    PKCS7_free(ret);
++    return (0);
++}
++
++int PKCS7_set_content(PKCS7 *p7, PKCS7 *p7_data)
++{
++    int i;
++
++    i = OBJ_obj2nid(p7->type);
++    switch (i) {
++    case NID_pkcs7_signed:
++        PKCS7_free(p7->d.sign->contents);
++        p7->d.sign->contents = p7_data;
++        break;
++    case NID_pkcs7_digest:
++        PKCS7_free(p7->d.digest->contents);
++        p7->d.digest->contents = p7_data;
++        break;
++    case NID_pkcs7_data:
++    case NID_pkcs7_enveloped:
++    case NID_pkcs7_signedAndEnveloped:
++    case NID_pkcs7_encrypted:
++    default:
++        PKCS7err(PKCS7_F_PKCS7_SET_CONTENT, PKCS7_R_UNSUPPORTED_CONTENT_TYPE);
++        goto err;
++    }
++    return (1);
++ err:
++    return (0);
++}
++
++int PKCS7_set_type(PKCS7 *p7, int type)
++{
++    ASN1_OBJECT *obj;
++
++    /*
++     * PKCS7_content_free(p7);
++     */
++    obj = OBJ_nid2obj(type);    /* will not fail */
++
++    switch (type) {
++    case NID_pkcs7_signed:
++        p7->type = obj;
++        if ((p7->d.sign = PKCS7_SIGNED_new()) == NULL)
++            goto err;
++        if (!ASN1_INTEGER_set(p7->d.sign->version, 1)) {
++            PKCS7_SIGNED_free(p7->d.sign);
++            p7->d.sign = NULL;
++            goto err;
++        }
++        break;
++    case NID_pkcs7_data:
++        p7->type = obj;
++        if ((p7->d.data = ASN1_OCTET_STRING_new()) == NULL)
++            goto err;
++        break;
++    case NID_pkcs7_signedAndEnveloped:
++        p7->type = obj;
++        if ((p7->d.signed_and_enveloped = PKCS7_SIGN_ENVELOPE_new())
++            == NULL)
++            goto err;
++        ASN1_INTEGER_set(p7->d.signed_and_enveloped->version, 1);
++        if (!ASN1_INTEGER_set(p7->d.signed_and_enveloped->version, 1))
++            goto err;
++        p7->d.signed_and_enveloped->enc_data->content_type
++            = OBJ_nid2obj(NID_pkcs7_data);
++        break;
++    case NID_pkcs7_enveloped:
++        p7->type = obj;
++        if ((p7->d.enveloped = PKCS7_ENVELOPE_new())
++            == NULL)
++            goto err;
++        if (!ASN1_INTEGER_set(p7->d.enveloped->version, 0))
++            goto err;
++        p7->d.enveloped->enc_data->content_type = OBJ_nid2obj(NID_pkcs7_data);
++        break;
++    case NID_pkcs7_encrypted:
++        p7->type = obj;
++        if ((p7->d.encrypted = PKCS7_ENCRYPT_new())
++            == NULL)
++            goto err;
++        if (!ASN1_INTEGER_set(p7->d.encrypted->version, 0))
++            goto err;
++        p7->d.encrypted->enc_data->content_type = OBJ_nid2obj(NID_pkcs7_data);
++        break;
++
++    case NID_pkcs7_digest:
++        p7->type = obj;
++        if ((p7->d.digest = PKCS7_DIGEST_new())
++            == NULL)
++            goto err;
++        if (!ASN1_INTEGER_set(p7->d.digest->version, 0))
++            goto err;
++        break;
++    default:
++        PKCS7err(PKCS7_F_PKCS7_SET_TYPE, PKCS7_R_UNSUPPORTED_CONTENT_TYPE);
++        goto err;
++    }
++    return (1);
++ err:
++    return (0);
++}
++
++int PKCS7_set0_type_other(PKCS7 *p7, int type, ASN1_TYPE *other)
++{
++    p7->type = OBJ_nid2obj(type);
++    p7->d.other = other;
++    return 1;
++}
++
++int PKCS7_add_signer(PKCS7 *p7, PKCS7_SIGNER_INFO *psi)
++{
++    int i, j, nid;
++    X509_ALGOR *alg;
++    STACK_OF(PKCS7_SIGNER_INFO) *signer_sk;
++    STACK_OF(X509_ALGOR) *md_sk;
++
++    i = OBJ_obj2nid(p7->type);
++    switch (i) {
++    case NID_pkcs7_signed:
++        signer_sk = p7->d.sign->signer_info;
++        md_sk = p7->d.sign->md_algs;
++        break;
++    case NID_pkcs7_signedAndEnveloped:
++        signer_sk = p7->d.signed_and_enveloped->signer_info;
++        md_sk = p7->d.signed_and_enveloped->md_algs;
++        break;
++    default:
++        PKCS7err(PKCS7_F_PKCS7_ADD_SIGNER, PKCS7_R_WRONG_CONTENT_TYPE);
++        return (0);
++    }
++
++    nid = OBJ_obj2nid(psi->digest_alg->algorithm);
++
++    /* If the digest is not currently listed, add it */
++    j = 0;
++    for (i = 0; i < sk_X509_ALGOR_num(md_sk); i++) {
++        alg = sk_X509_ALGOR_value(md_sk, i);
++        if (OBJ_obj2nid(alg->algorithm) == nid) {
++            j = 1;
++            break;
++        }
++    }
++    if (!j) {                   /* we need to add another algorithm */
++        if ((alg = X509_ALGOR_new()) == NULL
++            || (alg->parameter = ASN1_TYPE_new()) == NULL) {
++            X509_ALGOR_free(alg);
++            PKCS7err(PKCS7_F_PKCS7_ADD_SIGNER, ERR_R_MALLOC_FAILURE);
++            return (0);
++        }
++        alg->algorithm = OBJ_nid2obj(nid);
++        alg->parameter->type = V_ASN1_NULL;
++        if (!sk_X509_ALGOR_push(md_sk, alg)) {
++            X509_ALGOR_free(alg);
++            return 0;
++        }
++    }
++
++    if (!sk_PKCS7_SIGNER_INFO_push(signer_sk, psi))
++        return 0;
++    return (1);
++}
++
++int PKCS7_add_certificate(PKCS7 *p7, X509 *x509)
++{
++    int i;
++    STACK_OF(X509) **sk;
++
++    i = OBJ_obj2nid(p7->type);
++    switch (i) {
++    case NID_pkcs7_signed:
++        sk = &(p7->d.sign->cert);
++        break;
++    case NID_pkcs7_signedAndEnveloped:
++        sk = &(p7->d.signed_and_enveloped->cert);
++        break;
++    default:
++        PKCS7err(PKCS7_F_PKCS7_ADD_CERTIFICATE, PKCS7_R_WRONG_CONTENT_TYPE);
++        return (0);
++    }
++
++    if (*sk == NULL)
++        *sk = sk_X509_new_null();
++    if (*sk == NULL) {
++        PKCS7err(PKCS7_F_PKCS7_ADD_CERTIFICATE, ERR_R_MALLOC_FAILURE);
++        return 0;
++    }
++    X509_up_ref(x509);
++    if (!sk_X509_push(*sk, x509)) {
++        X509_free(x509);
++        return 0;
++    }
++    return (1);
++}
++
++int PKCS7_add_crl(PKCS7 *p7, X509_CRL *crl)
++{
++    int i;
++    STACK_OF(X509_CRL) **sk;
++
++    i = OBJ_obj2nid(p7->type);
++    switch (i) {
++    case NID_pkcs7_signed:
++        sk = &(p7->d.sign->crl);
++        break;
++    case NID_pkcs7_signedAndEnveloped:
++        sk = &(p7->d.signed_and_enveloped->crl);
++        break;
++    default:
++        PKCS7err(PKCS7_F_PKCS7_ADD_CRL, PKCS7_R_WRONG_CONTENT_TYPE);
++        return (0);
++    }
++
++    if (*sk == NULL)
++        *sk = sk_X509_CRL_new_null();
++    if (*sk == NULL) {
++        PKCS7err(PKCS7_F_PKCS7_ADD_CRL, ERR_R_MALLOC_FAILURE);
++        return 0;
++    }
++
++    X509_CRL_up_ref(crl);
++    if (!sk_X509_CRL_push(*sk, crl)) {
++        X509_CRL_free(crl);
++        return 0;
++    }
++    return (1);
++}
++
++int PKCS7_SIGNER_INFO_set(PKCS7_SIGNER_INFO *p7i, X509 *x509, EVP_PKEY *pkey,
++                          const EVP_MD *dgst)
++{
++    int ret;
++
++    /* We now need to add another PKCS7_SIGNER_INFO entry */
++    if (!ASN1_INTEGER_set(p7i->version, 1))
++        goto err;
++    if (!X509_NAME_set(&p7i->issuer_and_serial->issuer,
++                       X509_get_issuer_name(x509)))
++        goto err;
++
++    /*
++     * because ASN1_INTEGER_set is used to set a 'long' we will do things the
++     * ugly way.
++     */
++    ASN1_INTEGER_free(p7i->issuer_and_serial->serial);
++    if (!(p7i->issuer_and_serial->serial =
++          ASN1_INTEGER_dup(X509_get_serialNumber(x509))))
++        goto err;
++
++    /* lets keep the pkey around for a while */
++    EVP_PKEY_up_ref(pkey);
++    p7i->pkey = pkey;
++
++    /* Set the algorithms */
++
++    X509_ALGOR_set0(p7i->digest_alg, OBJ_nid2obj(EVP_MD_type(dgst)),
++                    V_ASN1_NULL, NULL);
++
++    if (pkey->ameth && pkey->ameth->pkey_ctrl) {
++        ret = pkey->ameth->pkey_ctrl(pkey, ASN1_PKEY_CTRL_PKCS7_SIGN, 0, p7i);
++        if (ret > 0)
++            return 1;
++        if (ret != -2) {
++            PKCS7err(PKCS7_F_PKCS7_SIGNER_INFO_SET,
++                     PKCS7_R_SIGNING_CTRL_FAILURE);
++            return 0;
++        }
++    }
++    PKCS7err(PKCS7_F_PKCS7_SIGNER_INFO_SET,
++             PKCS7_R_SIGNING_NOT_SUPPORTED_FOR_THIS_KEY_TYPE);
++ err:
++    return 0;
++}
++
++PKCS7_SIGNER_INFO *PKCS7_add_signature(PKCS7 *p7, X509 *x509, EVP_PKEY *pkey,
++                                       const EVP_MD *dgst)
++{
++    PKCS7_SIGNER_INFO *si = NULL;
++
++    if (dgst == NULL) {
++        int def_nid;
++        if (EVP_PKEY_get_default_digest_nid(pkey, &def_nid) <= 0)
++            goto err;
++        dgst = EVP_get_digestbynid(def_nid);
++        if (dgst == NULL) {
++            PKCS7err(PKCS7_F_PKCS7_ADD_SIGNATURE, PKCS7_R_NO_DEFAULT_DIGEST);
++            goto err;
++        }
++    }
++
++    if ((si = PKCS7_SIGNER_INFO_new()) == NULL)
++        goto err;
++    if (!PKCS7_SIGNER_INFO_set(si, x509, pkey, dgst))
++        goto err;
++    if (!PKCS7_add_signer(p7, si))
++        goto err;
++    return (si);
++ err:
++    PKCS7_SIGNER_INFO_free(si);
++    return (NULL);
++}
++
++int PKCS7_set_digest(PKCS7 *p7, const EVP_MD *md)
++{
++    if (PKCS7_type_is_digest(p7)) {
++        if ((p7->d.digest->md->parameter = ASN1_TYPE_new()) == NULL) {
++            PKCS7err(PKCS7_F_PKCS7_SET_DIGEST, ERR_R_MALLOC_FAILURE);
++            return 0;
++        }
++        p7->d.digest->md->parameter->type = V_ASN1_NULL;
++        p7->d.digest->md->algorithm = OBJ_nid2obj(EVP_MD_nid(md));
++        return 1;
++    }
++
++    PKCS7err(PKCS7_F_PKCS7_SET_DIGEST, PKCS7_R_WRONG_CONTENT_TYPE);
++    return 1;
++}
++
++STACK_OF(PKCS7_SIGNER_INFO) *PKCS7_get_signer_info(PKCS7 *p7)
++{
++    if (p7 == NULL || p7->d.ptr == NULL)
++        return NULL;
++    if (PKCS7_type_is_signed(p7)) {
++        return (p7->d.sign->signer_info);
++    } else if (PKCS7_type_is_signedAndEnveloped(p7)) {
++        return (p7->d.signed_and_enveloped->signer_info);
++    } else
++        return (NULL);
++}
++
++void PKCS7_SIGNER_INFO_get0_algs(PKCS7_SIGNER_INFO *si, EVP_PKEY **pk,
++                                 X509_ALGOR **pdig, X509_ALGOR **psig)
++{
++    if (pk)
++        *pk = si->pkey;
++    if (pdig)
++        *pdig = si->digest_alg;
++    if (psig)
++        *psig = si->digest_enc_alg;
++}
++
++void PKCS7_RECIP_INFO_get0_alg(PKCS7_RECIP_INFO *ri, X509_ALGOR **penc)
++{
++    if (penc)
++        *penc = ri->key_enc_algor;
++}
++
++PKCS7_RECIP_INFO *PKCS7_add_recipient(PKCS7 *p7, X509 *x509)
++{
++    PKCS7_RECIP_INFO *ri;
++
++    if ((ri = PKCS7_RECIP_INFO_new()) == NULL)
++        goto err;
++    if (!PKCS7_RECIP_INFO_set(ri, x509))
++        goto err;
++    if (!PKCS7_add_recipient_info(p7, ri))
++        goto err;
++    return ri;
++ err:
++    PKCS7_RECIP_INFO_free(ri);
++    return NULL;
++}
++
++int PKCS7_add_recipient_info(PKCS7 *p7, PKCS7_RECIP_INFO *ri)
++{
++    int i;
++    STACK_OF(PKCS7_RECIP_INFO) *sk;
++
++    i = OBJ_obj2nid(p7->type);
++    switch (i) {
++    case NID_pkcs7_signedAndEnveloped:
++        sk = p7->d.signed_and_enveloped->recipientinfo;
++        break;
++    case NID_pkcs7_enveloped:
++        sk = p7->d.enveloped->recipientinfo;
++        break;
++    default:
++        PKCS7err(PKCS7_F_PKCS7_ADD_RECIPIENT_INFO,
++                 PKCS7_R_WRONG_CONTENT_TYPE);
++        return (0);
++    }
++
++    if (!sk_PKCS7_RECIP_INFO_push(sk, ri))
++        return 0;
++    return (1);
++}
++
++int PKCS7_RECIP_INFO_set(PKCS7_RECIP_INFO *p7i, X509 *x509)
++{
++    int ret;
++    EVP_PKEY *pkey = NULL;
++    if (!ASN1_INTEGER_set(p7i->version, 0))
++        return 0;
++    if (!X509_NAME_set(&p7i->issuer_and_serial->issuer,
++                       X509_get_issuer_name(x509)))
++        return 0;
++
++    ASN1_INTEGER_free(p7i->issuer_and_serial->serial);
++    if (!(p7i->issuer_and_serial->serial =
++          ASN1_INTEGER_dup(X509_get_serialNumber(x509))))
++        return 0;
++
++    pkey = X509_get0_pubkey(x509);
++
++    if (!pkey || !pkey->ameth || !pkey->ameth->pkey_ctrl) {
++        PKCS7err(PKCS7_F_PKCS7_RECIP_INFO_SET,
++                 PKCS7_R_ENCRYPTION_NOT_SUPPORTED_FOR_THIS_KEY_TYPE);
++        goto err;
++    }
++
++    ret = pkey->ameth->pkey_ctrl(pkey, ASN1_PKEY_CTRL_PKCS7_ENCRYPT, 0, p7i);
++    if (ret == -2) {
++        PKCS7err(PKCS7_F_PKCS7_RECIP_INFO_SET,
++                 PKCS7_R_ENCRYPTION_NOT_SUPPORTED_FOR_THIS_KEY_TYPE);
++        goto err;
++    }
++    if (ret <= 0) {
++        PKCS7err(PKCS7_F_PKCS7_RECIP_INFO_SET,
++                 PKCS7_R_ENCRYPTION_CTRL_FAILURE);
++        goto err;
++    }
++
++    X509_up_ref(x509);
++    p7i->cert = x509;
++
++    return 1;
++
++ err:
++    return 0;
++}
++
++X509 *PKCS7_cert_from_signer_info(PKCS7 *p7, PKCS7_SIGNER_INFO *si)
++{
++    if (PKCS7_type_is_signed(p7))
++        return (X509_find_by_issuer_and_serial(p7->d.sign->cert,
++                                               si->issuer_and_serial->issuer,
++                                               si->
++                                               issuer_and_serial->serial));
++    else
++        return (NULL);
++}
++
++int PKCS7_set_cipher(PKCS7 *p7, const EVP_CIPHER *cipher)
++{
++    int i;
++    PKCS7_ENC_CONTENT *ec;
++
++    i = OBJ_obj2nid(p7->type);
++    switch (i) {
++    case NID_pkcs7_signedAndEnveloped:
++        ec = p7->d.signed_and_enveloped->enc_data;
++        break;
++    case NID_pkcs7_enveloped:
++        ec = p7->d.enveloped->enc_data;
++        break;
++    default:
++        PKCS7err(PKCS7_F_PKCS7_SET_CIPHER, PKCS7_R_WRONG_CONTENT_TYPE);
++        return (0);
++    }
++
++    /* Check cipher OID exists and has data in it */
++    i = EVP_CIPHER_type(cipher);
++    if (i == NID_undef) {
++        PKCS7err(PKCS7_F_PKCS7_SET_CIPHER,
++                 PKCS7_R_CIPHER_HAS_NO_OBJECT_IDENTIFIER);
++        return (0);
++    }
++
++    ec->cipher = cipher;
++    return 1;
++}
++
++int PKCS7_stream(unsigned char ***boundary, PKCS7 *p7)
++{
++    ASN1_OCTET_STRING *os = NULL;
++
++    switch (OBJ_obj2nid(p7->type)) {
++    case NID_pkcs7_data:
++        os = p7->d.data;
++        break;
++
++    case NID_pkcs7_signedAndEnveloped:
++        os = p7->d.signed_and_enveloped->enc_data->enc_data;
++        if (os == NULL) {
++            os = ASN1_OCTET_STRING_new();
++            p7->d.signed_and_enveloped->enc_data->enc_data = os;
++        }
++        break;
++
++    case NID_pkcs7_enveloped:
++        os = p7->d.enveloped->enc_data->enc_data;
++        if (os == NULL) {
++            os = ASN1_OCTET_STRING_new();
++            p7->d.enveloped->enc_data->enc_data = os;
++        }
++        break;
++
++    case NID_pkcs7_signed:
++        os = p7->d.sign->contents->d.data;
++        break;
++
++    default:
++        os = NULL;
++        break;
++    }
++
++    if (os == NULL)
++        return 0;
++
++    os->flags |= ASN1_STRING_FLAG_NDEF;
++    *boundary = &os->data;
++
++    return 1;
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/pkcs7/pk7_mime.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/pkcs7/pk7_mime.c
+new file mode 100644
+index 0000000..97474cf
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/pkcs7/pk7_mime.c
+@@ -0,0 +1,49 @@
++/*
++ * Copyright 1999-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include 
++#include "internal/cryptlib.h"
++#include 
++#include 
++
++/* PKCS#7 wrappers round generalised stream and MIME routines */
++
++int i2d_PKCS7_bio_stream(BIO *out, PKCS7 *p7, BIO *in, int flags)
++{
++    return i2d_ASN1_bio_stream(out, (ASN1_VALUE *)p7, in, flags,
++                               ASN1_ITEM_rptr(PKCS7));
++}
++
++int PEM_write_bio_PKCS7_stream(BIO *out, PKCS7 *p7, BIO *in, int flags)
++{
++    return PEM_write_bio_ASN1_stream(out, (ASN1_VALUE *)p7, in, flags,
++                                     "PKCS7", ASN1_ITEM_rptr(PKCS7));
++}
++
++int SMIME_write_PKCS7(BIO *bio, PKCS7 *p7, BIO *data, int flags)
++{
++    STACK_OF(X509_ALGOR) *mdalgs;
++    int ctype_nid = OBJ_obj2nid(p7->type);
++    if (ctype_nid == NID_pkcs7_signed)
++        mdalgs = p7->d.sign->md_algs;
++    else
++        mdalgs = NULL;
++
++    flags ^= SMIME_OLDMIME;
++
++    return SMIME_write_ASN1(bio, (ASN1_VALUE *)p7, data, flags,
++                            ctype_nid, NID_undef, mdalgs,
++                            ASN1_ITEM_rptr(PKCS7));
++}
++
++PKCS7 *SMIME_read_PKCS7(BIO *bio, BIO **bcont)
++{
++    return (PKCS7 *)SMIME_read_ASN1(bio, bcont, ASN1_ITEM_rptr(PKCS7));
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/pkcs7/pk7_smime.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/pkcs7/pk7_smime.c
+new file mode 100644
+index 0000000..4418723
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/pkcs7/pk7_smime.c
+@@ -0,0 +1,549 @@
++/*
++ * Copyright 1999-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++/* Simple PKCS#7 processing functions */
++
++#include 
++#include "internal/cryptlib.h"
++#include 
++#include 
++
++
++#define BUFFERSIZE 4096
++
++static int pkcs7_copy_existing_digest(PKCS7 *p7, PKCS7_SIGNER_INFO *si);
++
++PKCS7 *PKCS7_sign(X509 *signcert, EVP_PKEY *pkey, STACK_OF(X509) *certs,
++                  BIO *data, int flags)
++{
++    PKCS7 *p7;
++    int i;
++
++    if ((p7 = PKCS7_new()) == NULL) {
++        PKCS7err(PKCS7_F_PKCS7_SIGN, ERR_R_MALLOC_FAILURE);
++        return NULL;
++    }
++
++    if (!PKCS7_set_type(p7, NID_pkcs7_signed))
++        goto err;
++
++    if (!PKCS7_content_new(p7, NID_pkcs7_data))
++        goto err;
++
++    if (pkey && !PKCS7_sign_add_signer(p7, signcert, pkey, NULL, flags)) {
++        PKCS7err(PKCS7_F_PKCS7_SIGN, PKCS7_R_PKCS7_ADD_SIGNER_ERROR);
++        goto err;
++    }
++
++    if (!(flags & PKCS7_NOCERTS)) {
++        for (i = 0; i < sk_X509_num(certs); i++) {
++            if (!PKCS7_add_certificate(p7, sk_X509_value(certs, i)))
++                goto err;
++        }
++    }
++
++    if (flags & PKCS7_DETACHED)
++        PKCS7_set_detached(p7, 1);
++
++    if (flags & (PKCS7_STREAM | PKCS7_PARTIAL))
++        return p7;
++
++    if (PKCS7_final(p7, data, flags))
++        return p7;
++
++ err:
++    PKCS7_free(p7);
++    return NULL;
++}
++
++int PKCS7_final(PKCS7 *p7, BIO *data, int flags)
++{
++    BIO *p7bio;
++    int ret = 0;
++
++    if ((p7bio = PKCS7_dataInit(p7, NULL)) == NULL) {
++        PKCS7err(PKCS7_F_PKCS7_FINAL, ERR_R_MALLOC_FAILURE);
++        return 0;
++    }
++
++    SMIME_crlf_copy(data, p7bio, flags);
++
++    (void)BIO_flush(p7bio);
++
++    if (!PKCS7_dataFinal(p7, p7bio)) {
++        PKCS7err(PKCS7_F_PKCS7_FINAL, PKCS7_R_PKCS7_DATASIGN);
++        goto err;
++    }
++
++    ret = 1;
++
++ err:
++    BIO_free_all(p7bio);
++
++    return ret;
++
++}
++
++/* Check to see if a cipher exists and if so add S/MIME capabilities */
++
++static int add_cipher_smcap(STACK_OF(X509_ALGOR) *sk, int nid, int arg)
++{
++    if (EVP_get_cipherbynid(nid))
++        return PKCS7_simple_smimecap(sk, nid, arg);
++    return 1;
++}
++
++static int add_digest_smcap(STACK_OF(X509_ALGOR) *sk, int nid, int arg)
++{
++    if (EVP_get_digestbynid(nid))
++        return PKCS7_simple_smimecap(sk, nid, arg);
++    return 1;
++}
++
++PKCS7_SIGNER_INFO *PKCS7_sign_add_signer(PKCS7 *p7, X509 *signcert,
++                                         EVP_PKEY *pkey, const EVP_MD *md,
++                                         int flags)
++{
++    PKCS7_SIGNER_INFO *si = NULL;
++    STACK_OF(X509_ALGOR) *smcap = NULL;
++    if (!X509_check_private_key(signcert, pkey)) {
++        PKCS7err(PKCS7_F_PKCS7_SIGN_ADD_SIGNER,
++                 PKCS7_R_PRIVATE_KEY_DOES_NOT_MATCH_CERTIFICATE);
++        return NULL;
++    }
++
++    if ((si = PKCS7_add_signature(p7, signcert, pkey, md)) == NULL) {
++        PKCS7err(PKCS7_F_PKCS7_SIGN_ADD_SIGNER,
++                 PKCS7_R_PKCS7_ADD_SIGNATURE_ERROR);
++        return NULL;
++    }
++
++    if (!(flags & PKCS7_NOCERTS)) {
++        if (!PKCS7_add_certificate(p7, signcert))
++            goto err;
++    }
++
++    if (!(flags & PKCS7_NOATTR)) {
++        if (!PKCS7_add_attrib_content_type(si, NULL))
++            goto err;
++        /* Add SMIMECapabilities */
++        if (!(flags & PKCS7_NOSMIMECAP)) {
++            if ((smcap = sk_X509_ALGOR_new_null()) == NULL) {
++                PKCS7err(PKCS7_F_PKCS7_SIGN_ADD_SIGNER, ERR_R_MALLOC_FAILURE);
++                goto err;
++            }
++            if (!add_cipher_smcap(smcap, NID_aes_256_cbc, -1)
++                || !add_digest_smcap(smcap, NID_id_GostR3411_2012_256, -1)
++                || !add_digest_smcap(smcap, NID_id_GostR3411_2012_512, -1)
++                || !add_digest_smcap(smcap, NID_id_GostR3411_94, -1)
++                || !add_cipher_smcap(smcap, NID_id_Gost28147_89, -1)
++                || !add_cipher_smcap(smcap, NID_aes_192_cbc, -1)
++                || !add_cipher_smcap(smcap, NID_aes_128_cbc, -1)
++                || !add_cipher_smcap(smcap, NID_des_ede3_cbc, -1)
++                || !add_cipher_smcap(smcap, NID_rc2_cbc, 128)
++                || !add_cipher_smcap(smcap, NID_rc2_cbc, 64)
++                || !add_cipher_smcap(smcap, NID_des_cbc, -1)
++                || !add_cipher_smcap(smcap, NID_rc2_cbc, 40)
++                || !PKCS7_add_attrib_smimecap(si, smcap))
++                goto err;
++            sk_X509_ALGOR_pop_free(smcap, X509_ALGOR_free);
++            smcap = NULL;
++        }
++        if (flags & PKCS7_REUSE_DIGEST) {
++            if (!pkcs7_copy_existing_digest(p7, si))
++                goto err;
++            if (!(flags & PKCS7_PARTIAL) && !PKCS7_SIGNER_INFO_sign(si))
++                goto err;
++        }
++    }
++    return si;
++ err:
++    sk_X509_ALGOR_pop_free(smcap, X509_ALGOR_free);
++    return NULL;
++}
++
++/*
++ * Search for a digest matching SignerInfo digest type and if found copy
++ * across.
++ */
++
++static int pkcs7_copy_existing_digest(PKCS7 *p7, PKCS7_SIGNER_INFO *si)
++{
++    int i;
++    STACK_OF(PKCS7_SIGNER_INFO) *sinfos;
++    PKCS7_SIGNER_INFO *sitmp;
++    ASN1_OCTET_STRING *osdig = NULL;
++    sinfos = PKCS7_get_signer_info(p7);
++    for (i = 0; i < sk_PKCS7_SIGNER_INFO_num(sinfos); i++) {
++        sitmp = sk_PKCS7_SIGNER_INFO_value(sinfos, i);
++        if (si == sitmp)
++            break;
++        if (sk_X509_ATTRIBUTE_num(sitmp->auth_attr) <= 0)
++            continue;
++        if (!OBJ_cmp(si->digest_alg->algorithm, sitmp->digest_alg->algorithm)) {
++            osdig = PKCS7_digest_from_attributes(sitmp->auth_attr);
++            break;
++        }
++
++    }
++
++    if (osdig)
++        return PKCS7_add1_attrib_digest(si, osdig->data, osdig->length);
++
++    PKCS7err(PKCS7_F_PKCS7_COPY_EXISTING_DIGEST,
++             PKCS7_R_NO_MATCHING_DIGEST_TYPE_FOUND);
++    return 0;
++}
++
++int PKCS7_verify(PKCS7 *p7, STACK_OF(X509) *certs, X509_STORE *store,
++                 BIO *indata, BIO *out, int flags)
++{
++    STACK_OF(X509) *signers;
++    X509 *signer;
++    STACK_OF(PKCS7_SIGNER_INFO) *sinfos;
++    PKCS7_SIGNER_INFO *si;
++    X509_STORE_CTX *cert_ctx = NULL;
++    char *buf = NULL;
++    int i, j = 0, k, ret = 0;
++    BIO *p7bio = NULL;
++    BIO *tmpin = NULL, *tmpout = NULL;
++
++    if (!p7) {
++        PKCS7err(PKCS7_F_PKCS7_VERIFY, PKCS7_R_INVALID_NULL_POINTER);
++        return 0;
++    }
++
++    if (!PKCS7_type_is_signed(p7)) {
++        PKCS7err(PKCS7_F_PKCS7_VERIFY, PKCS7_R_WRONG_CONTENT_TYPE);
++        return 0;
++    }
++
++    /* Check for no data and no content: no data to verify signature */
++    if (PKCS7_get_detached(p7) && !indata) {
++        PKCS7err(PKCS7_F_PKCS7_VERIFY, PKCS7_R_NO_CONTENT);
++        return 0;
++    }
++
++    if (flags & PKCS7_NO_DUAL_CONTENT) {
++        /*
++         * This was originally "#if 0" because we thought that only old broken
++         * Netscape did this.  It turns out that Authenticode uses this kind
++         * of "extended" PKCS7 format, and things like UEFI secure boot and
++         * tools like osslsigncode need it.  In Authenticode the verification
++         * process is different, but the existing PKCs7 verification works.
++         */
++        if (!PKCS7_get_detached(p7) && indata) {
++            PKCS7err(PKCS7_F_PKCS7_VERIFY, PKCS7_R_CONTENT_AND_DATA_PRESENT);
++            return 0;
++        }
++    }
++
++    sinfos = PKCS7_get_signer_info(p7);
++
++    if (!sinfos || !sk_PKCS7_SIGNER_INFO_num(sinfos)) {
++        PKCS7err(PKCS7_F_PKCS7_VERIFY, PKCS7_R_NO_SIGNATURES_ON_DATA);
++        return 0;
++    }
++
++    signers = PKCS7_get0_signers(p7, certs, flags);
++    if (!signers)
++        return 0;
++
++    /* Now verify the certificates */
++
++    cert_ctx = X509_STORE_CTX_new();
++    if (cert_ctx == NULL)
++        goto err;
++    if (!(flags & PKCS7_NOVERIFY))
++        for (k = 0; k < sk_X509_num(signers); k++) {
++            signer = sk_X509_value(signers, k);
++            if (!(flags & PKCS7_NOCHAIN)) {
++                if (!X509_STORE_CTX_init(cert_ctx, store, signer,
++                                         p7->d.sign->cert)) {
++                    PKCS7err(PKCS7_F_PKCS7_VERIFY, ERR_R_X509_LIB);
++                    goto err;
++                }
++                X509_STORE_CTX_set_default(cert_ctx, "smime_sign");
++            } else if (!X509_STORE_CTX_init(cert_ctx, store, signer, NULL)) {
++                PKCS7err(PKCS7_F_PKCS7_VERIFY, ERR_R_X509_LIB);
++                goto err;
++            }
++            if (!(flags & PKCS7_NOCRL))
++                X509_STORE_CTX_set0_crls(cert_ctx, p7->d.sign->crl);
++            i = X509_verify_cert(cert_ctx);
++            if (i <= 0)
++                j = X509_STORE_CTX_get_error(cert_ctx);
++            X509_STORE_CTX_cleanup(cert_ctx);
++            if (i <= 0) {
++                PKCS7err(PKCS7_F_PKCS7_VERIFY,
++                         PKCS7_R_CERTIFICATE_VERIFY_ERROR);
++                ERR_add_error_data(2, "Verify error:",
++                                   X509_verify_cert_error_string(j));
++                goto err;
++            }
++            /* Check for revocation status here */
++        }
++
++    /*
++     * Performance optimization: if the content is a memory BIO then store
++     * its contents in a temporary read only memory BIO. This avoids
++     * potentially large numbers of slow copies of data which will occur when
++     * reading from a read write memory BIO when signatures are calculated.
++     */
++
++    if (indata && (BIO_method_type(indata) == BIO_TYPE_MEM)) {
++        char *ptr;
++        long len;
++        len = BIO_get_mem_data(indata, &ptr);
++        tmpin = BIO_new_mem_buf(ptr, len);
++        if (tmpin == NULL) {
++            PKCS7err(PKCS7_F_PKCS7_VERIFY, ERR_R_MALLOC_FAILURE);
++            goto err;
++        }
++    } else
++        tmpin = indata;
++
++    if ((p7bio = PKCS7_dataInit(p7, tmpin)) == NULL)
++        goto err;
++
++    if (flags & PKCS7_TEXT) {
++        if ((tmpout = BIO_new(BIO_s_mem())) == NULL) {
++            PKCS7err(PKCS7_F_PKCS7_VERIFY, ERR_R_MALLOC_FAILURE);
++            goto err;
++        }
++        BIO_set_mem_eof_return(tmpout, 0);
++    } else
++        tmpout = out;
++
++    /* We now have to 'read' from p7bio to calculate digests etc. */
++    if ((buf = OPENSSL_malloc(BUFFERSIZE)) == NULL) {
++        PKCS7err(PKCS7_F_PKCS7_VERIFY, ERR_R_MALLOC_FAILURE);
++        goto err;
++    }
++    for (;;) {
++        i = BIO_read(p7bio, buf, BUFFERSIZE);
++        if (i <= 0)
++            break;
++        if (tmpout)
++            BIO_write(tmpout, buf, i);
++    }
++
++    if (flags & PKCS7_TEXT) {
++        if (!SMIME_text(tmpout, out)) {
++            PKCS7err(PKCS7_F_PKCS7_VERIFY, PKCS7_R_SMIME_TEXT_ERROR);
++            BIO_free(tmpout);
++            goto err;
++        }
++        BIO_free(tmpout);
++    }
++
++    /* Now Verify All Signatures */
++    if (!(flags & PKCS7_NOSIGS))
++        for (i = 0; i < sk_PKCS7_SIGNER_INFO_num(sinfos); i++) {
++            si = sk_PKCS7_SIGNER_INFO_value(sinfos, i);
++            signer = sk_X509_value(signers, i);
++            j = PKCS7_signatureVerify(p7bio, p7, si, signer);
++            if (j <= 0) {
++                PKCS7err(PKCS7_F_PKCS7_VERIFY, PKCS7_R_SIGNATURE_FAILURE);
++                goto err;
++            }
++        }
++
++    ret = 1;
++
++ err:
++    X509_STORE_CTX_free(cert_ctx);
++    OPENSSL_free(buf);
++    if (tmpin == indata) {
++        if (indata)
++            BIO_pop(p7bio);
++    }
++    BIO_free_all(p7bio);
++    sk_X509_free(signers);
++    return ret;
++}
++
++STACK_OF(X509) *PKCS7_get0_signers(PKCS7 *p7, STACK_OF(X509) *certs,
++                                   int flags)
++{
++    STACK_OF(X509) *signers;
++    STACK_OF(PKCS7_SIGNER_INFO) *sinfos;
++    PKCS7_SIGNER_INFO *si;
++    PKCS7_ISSUER_AND_SERIAL *ias;
++    X509 *signer;
++    int i;
++
++    if (!p7) {
++        PKCS7err(PKCS7_F_PKCS7_GET0_SIGNERS, PKCS7_R_INVALID_NULL_POINTER);
++        return NULL;
++    }
++
++    if (!PKCS7_type_is_signed(p7)) {
++        PKCS7err(PKCS7_F_PKCS7_GET0_SIGNERS, PKCS7_R_WRONG_CONTENT_TYPE);
++        return NULL;
++    }
++
++    /* Collect all the signers together */
++
++    sinfos = PKCS7_get_signer_info(p7);
++
++    if (sk_PKCS7_SIGNER_INFO_num(sinfos) <= 0) {
++        PKCS7err(PKCS7_F_PKCS7_GET0_SIGNERS, PKCS7_R_NO_SIGNERS);
++        return 0;
++    }
++
++    if ((signers = sk_X509_new_null()) == NULL) {
++        PKCS7err(PKCS7_F_PKCS7_GET0_SIGNERS, ERR_R_MALLOC_FAILURE);
++        return NULL;
++    }
++
++    for (i = 0; i < sk_PKCS7_SIGNER_INFO_num(sinfos); i++) {
++        si = sk_PKCS7_SIGNER_INFO_value(sinfos, i);
++        ias = si->issuer_and_serial;
++        signer = NULL;
++        /* If any certificates passed they take priority */
++        if (certs)
++            signer = X509_find_by_issuer_and_serial(certs,
++                                                    ias->issuer, ias->serial);
++        if (!signer && !(flags & PKCS7_NOINTERN)
++            && p7->d.sign->cert)
++            signer =
++                X509_find_by_issuer_and_serial(p7->d.sign->cert,
++                                               ias->issuer, ias->serial);
++        if (!signer) {
++            PKCS7err(PKCS7_F_PKCS7_GET0_SIGNERS,
++                     PKCS7_R_SIGNER_CERTIFICATE_NOT_FOUND);
++            sk_X509_free(signers);
++            return 0;
++        }
++
++        if (!sk_X509_push(signers, signer)) {
++            sk_X509_free(signers);
++            return NULL;
++        }
++    }
++    return signers;
++}
++
++/* Build a complete PKCS#7 enveloped data */
++
++PKCS7 *PKCS7_encrypt(STACK_OF(X509) *certs, BIO *in, const EVP_CIPHER *cipher,
++                     int flags)
++{
++    PKCS7 *p7;
++    BIO *p7bio = NULL;
++    int i;
++    X509 *x509;
++    if ((p7 = PKCS7_new()) == NULL) {
++        PKCS7err(PKCS7_F_PKCS7_ENCRYPT, ERR_R_MALLOC_FAILURE);
++        return NULL;
++    }
++
++    if (!PKCS7_set_type(p7, NID_pkcs7_enveloped))
++        goto err;
++    if (!PKCS7_set_cipher(p7, cipher)) {
++        PKCS7err(PKCS7_F_PKCS7_ENCRYPT, PKCS7_R_ERROR_SETTING_CIPHER);
++        goto err;
++    }
++
++    for (i = 0; i < sk_X509_num(certs); i++) {
++        x509 = sk_X509_value(certs, i);
++        if (!PKCS7_add_recipient(p7, x509)) {
++            PKCS7err(PKCS7_F_PKCS7_ENCRYPT, PKCS7_R_ERROR_ADDING_RECIPIENT);
++            goto err;
++        }
++    }
++
++    if (flags & PKCS7_STREAM)
++        return p7;
++
++    if (PKCS7_final(p7, in, flags))
++        return p7;
++
++ err:
++
++    BIO_free_all(p7bio);
++    PKCS7_free(p7);
++    return NULL;
++
++}
++
++int PKCS7_decrypt(PKCS7 *p7, EVP_PKEY *pkey, X509 *cert, BIO *data, int flags)
++{
++    BIO *tmpmem;
++    int ret = 0, i;
++    char *buf = NULL;
++
++    if (!p7) {
++        PKCS7err(PKCS7_F_PKCS7_DECRYPT, PKCS7_R_INVALID_NULL_POINTER);
++        return 0;
++    }
++
++    if (!PKCS7_type_is_enveloped(p7)) {
++        PKCS7err(PKCS7_F_PKCS7_DECRYPT, PKCS7_R_WRONG_CONTENT_TYPE);
++        return 0;
++    }
++
++    if (cert && !X509_check_private_key(cert, pkey)) {
++        PKCS7err(PKCS7_F_PKCS7_DECRYPT,
++                 PKCS7_R_PRIVATE_KEY_DOES_NOT_MATCH_CERTIFICATE);
++        return 0;
++    }
++
++    if ((tmpmem = PKCS7_dataDecode(p7, pkey, NULL, cert)) == NULL) {
++        PKCS7err(PKCS7_F_PKCS7_DECRYPT, PKCS7_R_DECRYPT_ERROR);
++        return 0;
++    }
++
++    if (flags & PKCS7_TEXT) {
++        BIO *tmpbuf, *bread;
++        /* Encrypt BIOs can't do BIO_gets() so add a buffer BIO */
++        if ((tmpbuf = BIO_new(BIO_f_buffer())) == NULL) {
++            PKCS7err(PKCS7_F_PKCS7_DECRYPT, ERR_R_MALLOC_FAILURE);
++            BIO_free_all(tmpmem);
++            return 0;
++        }
++        if ((bread = BIO_push(tmpbuf, tmpmem)) == NULL) {
++            PKCS7err(PKCS7_F_PKCS7_DECRYPT, ERR_R_MALLOC_FAILURE);
++            BIO_free_all(tmpbuf);
++            BIO_free_all(tmpmem);
++            return 0;
++        }
++        ret = SMIME_text(bread, data);
++        if (ret > 0 && BIO_method_type(tmpmem) == BIO_TYPE_CIPHER) {
++            if (!BIO_get_cipher_status(tmpmem))
++                ret = 0;
++        }
++        BIO_free_all(bread);
++        return ret;
++    }
++    if ((buf = OPENSSL_malloc(BUFFERSIZE)) == NULL) {
++        PKCS7err(PKCS7_F_PKCS7_DECRYPT, ERR_R_MALLOC_FAILURE);
++        goto err;
++    }
++    for (;;) {
++        i = BIO_read(tmpmem, buf, BUFFERSIZE);
++        if (i <= 0) {
++            ret = 1;
++            if (BIO_method_type(tmpmem) == BIO_TYPE_CIPHER) {
++                if (!BIO_get_cipher_status(tmpmem))
++                    ret = 0;
++            }
++
++            break;
++        }
++        if (BIO_write(data, buf, i) != i) {
++            break;
++        }
++    }
++err:
++    OPENSSL_free(buf);
++    BIO_free_all(tmpmem);
++    return ret;
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/pkcs7/pkcs7err.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/pkcs7/pkcs7err.c
+new file mode 100644
+index 0000000..d5baa9b
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/pkcs7/pkcs7err.c
+@@ -0,0 +1,131 @@
++/*
++ * Generated by util/mkerr.pl DO NOT EDIT
++ * Copyright 1995-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include 
++#include 
++
++/* BEGIN ERROR CODES */
++#ifndef OPENSSL_NO_ERR
++
++# define ERR_FUNC(func) ERR_PACK(ERR_LIB_PKCS7,func,0)
++# define ERR_REASON(reason) ERR_PACK(ERR_LIB_PKCS7,0,reason)
++
++static ERR_STRING_DATA PKCS7_str_functs[] = {
++    {ERR_FUNC(PKCS7_F_DO_PKCS7_SIGNED_ATTRIB), "do_pkcs7_signed_attrib"},
++    {ERR_FUNC(PKCS7_F_PKCS7_ADD0_ATTRIB_SIGNING_TIME),
++     "PKCS7_add0_attrib_signing_time"},
++    {ERR_FUNC(PKCS7_F_PKCS7_ADD_ATTRIB_SMIMECAP),
++     "PKCS7_add_attrib_smimecap"},
++    {ERR_FUNC(PKCS7_F_PKCS7_ADD_CERTIFICATE), "PKCS7_add_certificate"},
++    {ERR_FUNC(PKCS7_F_PKCS7_ADD_CRL), "PKCS7_add_crl"},
++    {ERR_FUNC(PKCS7_F_PKCS7_ADD_RECIPIENT_INFO), "PKCS7_add_recipient_info"},
++    {ERR_FUNC(PKCS7_F_PKCS7_ADD_SIGNATURE), "PKCS7_add_signature"},
++    {ERR_FUNC(PKCS7_F_PKCS7_ADD_SIGNER), "PKCS7_add_signer"},
++    {ERR_FUNC(PKCS7_F_PKCS7_BIO_ADD_DIGEST), "PKCS7_bio_add_digest"},
++    {ERR_FUNC(PKCS7_F_PKCS7_COPY_EXISTING_DIGEST),
++     "pkcs7_copy_existing_digest"},
++    {ERR_FUNC(PKCS7_F_PKCS7_CTRL), "PKCS7_ctrl"},
++    {ERR_FUNC(PKCS7_F_PKCS7_DATADECODE), "PKCS7_dataDecode"},
++    {ERR_FUNC(PKCS7_F_PKCS7_DATAFINAL), "PKCS7_dataFinal"},
++    {ERR_FUNC(PKCS7_F_PKCS7_DATAINIT), "PKCS7_dataInit"},
++    {ERR_FUNC(PKCS7_F_PKCS7_DATAVERIFY), "PKCS7_dataVerify"},
++    {ERR_FUNC(PKCS7_F_PKCS7_DECRYPT), "PKCS7_decrypt"},
++    {ERR_FUNC(PKCS7_F_PKCS7_DECRYPT_RINFO), "pkcs7_decrypt_rinfo"},
++    {ERR_FUNC(PKCS7_F_PKCS7_ENCODE_RINFO), "pkcs7_encode_rinfo"},
++    {ERR_FUNC(PKCS7_F_PKCS7_ENCRYPT), "PKCS7_encrypt"},
++    {ERR_FUNC(PKCS7_F_PKCS7_FINAL), "PKCS7_final"},
++    {ERR_FUNC(PKCS7_F_PKCS7_FIND_DIGEST), "PKCS7_find_digest"},
++    {ERR_FUNC(PKCS7_F_PKCS7_GET0_SIGNERS), "PKCS7_get0_signers"},
++    {ERR_FUNC(PKCS7_F_PKCS7_RECIP_INFO_SET), "PKCS7_RECIP_INFO_set"},
++    {ERR_FUNC(PKCS7_F_PKCS7_SET_CIPHER), "PKCS7_set_cipher"},
++    {ERR_FUNC(PKCS7_F_PKCS7_SET_CONTENT), "PKCS7_set_content"},
++    {ERR_FUNC(PKCS7_F_PKCS7_SET_DIGEST), "PKCS7_set_digest"},
++    {ERR_FUNC(PKCS7_F_PKCS7_SET_TYPE), "PKCS7_set_type"},
++    {ERR_FUNC(PKCS7_F_PKCS7_SIGN), "PKCS7_sign"},
++    {ERR_FUNC(PKCS7_F_PKCS7_SIGNATUREVERIFY), "PKCS7_signatureVerify"},
++    {ERR_FUNC(PKCS7_F_PKCS7_SIGNER_INFO_SET), "PKCS7_SIGNER_INFO_set"},
++    {ERR_FUNC(PKCS7_F_PKCS7_SIGNER_INFO_SIGN), "PKCS7_SIGNER_INFO_sign"},
++    {ERR_FUNC(PKCS7_F_PKCS7_SIGN_ADD_SIGNER), "PKCS7_sign_add_signer"},
++    {ERR_FUNC(PKCS7_F_PKCS7_SIMPLE_SMIMECAP), "PKCS7_simple_smimecap"},
++    {ERR_FUNC(PKCS7_F_PKCS7_VERIFY), "PKCS7_verify"},
++    {0, NULL}
++};
++
++static ERR_STRING_DATA PKCS7_str_reasons[] = {
++    {ERR_REASON(PKCS7_R_CERTIFICATE_VERIFY_ERROR),
++     "certificate verify error"},
++    {ERR_REASON(PKCS7_R_CIPHER_HAS_NO_OBJECT_IDENTIFIER),
++     "cipher has no object identifier"},
++    {ERR_REASON(PKCS7_R_CIPHER_NOT_INITIALIZED), "cipher not initialized"},
++    {ERR_REASON(PKCS7_R_CONTENT_AND_DATA_PRESENT),
++     "content and data present"},
++    {ERR_REASON(PKCS7_R_CTRL_ERROR), "ctrl error"},
++    {ERR_REASON(PKCS7_R_DECRYPT_ERROR), "decrypt error"},
++    {ERR_REASON(PKCS7_R_DIGEST_FAILURE), "digest failure"},
++    {ERR_REASON(PKCS7_R_ENCRYPTION_CTRL_FAILURE), "encryption ctrl failure"},
++    {ERR_REASON(PKCS7_R_ENCRYPTION_NOT_SUPPORTED_FOR_THIS_KEY_TYPE),
++     "encryption not supported for this key type"},
++    {ERR_REASON(PKCS7_R_ERROR_ADDING_RECIPIENT), "error adding recipient"},
++    {ERR_REASON(PKCS7_R_ERROR_SETTING_CIPHER), "error setting cipher"},
++    {ERR_REASON(PKCS7_R_INVALID_NULL_POINTER), "invalid null pointer"},
++    {ERR_REASON(PKCS7_R_INVALID_SIGNED_DATA_TYPE),
++     "invalid signed data type"},
++    {ERR_REASON(PKCS7_R_NO_CONTENT), "no content"},
++    {ERR_REASON(PKCS7_R_NO_DEFAULT_DIGEST), "no default digest"},
++    {ERR_REASON(PKCS7_R_NO_MATCHING_DIGEST_TYPE_FOUND),
++     "no matching digest type found"},
++    {ERR_REASON(PKCS7_R_NO_RECIPIENT_MATCHES_CERTIFICATE),
++     "no recipient matches certificate"},
++    {ERR_REASON(PKCS7_R_NO_SIGNATURES_ON_DATA), "no signatures on data"},
++    {ERR_REASON(PKCS7_R_NO_SIGNERS), "no signers"},
++    {ERR_REASON(PKCS7_R_OPERATION_NOT_SUPPORTED_ON_THIS_TYPE),
++     "operation not supported on this type"},
++    {ERR_REASON(PKCS7_R_PKCS7_ADD_SIGNATURE_ERROR),
++     "pkcs7 add signature error"},
++    {ERR_REASON(PKCS7_R_PKCS7_ADD_SIGNER_ERROR), "pkcs7 add signer error"},
++    {ERR_REASON(PKCS7_R_PKCS7_DATASIGN), "pkcs7 datasign"},
++    {ERR_REASON(PKCS7_R_PRIVATE_KEY_DOES_NOT_MATCH_CERTIFICATE),
++     "private key does not match certificate"},
++    {ERR_REASON(PKCS7_R_SIGNATURE_FAILURE), "signature failure"},
++    {ERR_REASON(PKCS7_R_SIGNER_CERTIFICATE_NOT_FOUND),
++     "signer certificate not found"},
++    {ERR_REASON(PKCS7_R_SIGNING_CTRL_FAILURE), "signing ctrl failure"},
++    {ERR_REASON(PKCS7_R_SIGNING_NOT_SUPPORTED_FOR_THIS_KEY_TYPE),
++     "signing not supported for this key type"},
++    {ERR_REASON(PKCS7_R_SMIME_TEXT_ERROR), "smime text error"},
++    {ERR_REASON(PKCS7_R_UNABLE_TO_FIND_CERTIFICATE),
++     "unable to find certificate"},
++    {ERR_REASON(PKCS7_R_UNABLE_TO_FIND_MEM_BIO), "unable to find mem bio"},
++    {ERR_REASON(PKCS7_R_UNABLE_TO_FIND_MESSAGE_DIGEST),
++     "unable to find message digest"},
++    {ERR_REASON(PKCS7_R_UNKNOWN_DIGEST_TYPE), "unknown digest type"},
++    {ERR_REASON(PKCS7_R_UNKNOWN_OPERATION), "unknown operation"},
++    {ERR_REASON(PKCS7_R_UNSUPPORTED_CIPHER_TYPE), "unsupported cipher type"},
++    {ERR_REASON(PKCS7_R_UNSUPPORTED_CONTENT_TYPE),
++     "unsupported content type"},
++    {ERR_REASON(PKCS7_R_WRONG_CONTENT_TYPE), "wrong content type"},
++    {ERR_REASON(PKCS7_R_WRONG_PKCS7_TYPE), "wrong pkcs7 type"},
++    {0, NULL}
++};
++
++#endif
++
++int ERR_load_PKCS7_strings(void)
++{
++#ifndef OPENSSL_NO_ERR
++
++    if (ERR_func_error_string(PKCS7_str_functs[0].error) == NULL) {
++        ERR_load_strings(0, PKCS7_str_functs);
++        ERR_load_strings(0, PKCS7_str_reasons);
++    }
++#endif
++    return 1;
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/poly1305/asm/poly1305-armv4.pl b/CryptoPkg/Library/OpensslLib/openssl/crypto/poly1305/asm/poly1305-armv4.pl
+new file mode 100755
+index 0000000..fc899ce
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/poly1305/asm/poly1305-armv4.pl
+@@ -0,0 +1,1252 @@
++#! /usr/bin/env perl
++# Copyright 2016 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
++# in the file LICENSE in the source distribution or at
++# https://www.openssl.org/source/license.html
++
++#
++# ====================================================================
++# Written by Andy Polyakov  for the OpenSSL
++# project. The module is, however, dual licensed under OpenSSL and
++# CRYPTOGAMS licenses depending on where you obtain it. For further
++# details see http://www.openssl.org/~appro/cryptogams/.
++# ====================================================================
++#
++#			IALU(*)/gcc-4.4		NEON
++#
++# ARM11xx(ARMv6)	7.78/+100%		-
++# Cortex-A5		6.35/+130%		3.00
++# Cortex-A8		6.25/+115%		2.36
++# Cortex-A9		5.10/+95%		2.55
++# Cortex-A15		3.85/+85%		1.25(**)
++# Snapdragon S4		5.70/+100%		1.48(**)
++#
++# (*)	this is for -march=armv6, i.e. with bunch of ldrb loading data;
++# (**)	these are trade-off results, they can be improved by ~8% but at
++#	the cost of 15/12% regression on Cortex-A5/A7, it's even possible
++#	to improve Cortex-A9 result, but then A5/A7 loose more than 20%;
++
++$flavour = shift;
++if ($flavour=~/\w[\w\-]*\.\w+$/) { $output=$flavour; undef $flavour; }
++else { while (($output=shift) && ($output!~/\w[\w\-]*\.\w+$/)) {} }
++
++if ($flavour && $flavour ne "void") {
++    $0 =~ m/(.*[\/\\])[^\/\\]+$/; $dir=$1;
++    ( $xlate="${dir}arm-xlate.pl" and -f $xlate ) or
++    ( $xlate="${dir}../../perlasm/arm-xlate.pl" and -f $xlate) or
++    die "can't locate arm-xlate.pl";
++
++    open STDOUT,"| \"$^X\" $xlate $flavour $output";
++} else {
++    open STDOUT,">$output";
++}
++
++($ctx,$inp,$len,$padbit)=map("r$_",(0..3));
++
++$code.=<<___;
++#include "arm_arch.h"
++
++.text
++#if defined(__thumb2__)
++.syntax	unified
++.thumb
++#else
++.code	32
++#endif
++
++.globl	poly1305_emit
++.globl	poly1305_blocks
++.globl	poly1305_init
++.type	poly1305_init,%function
++.align	5
++poly1305_init:
++.Lpoly1305_init:
++	stmdb	sp!,{r4-r11}
++
++	eor	r3,r3,r3
++	cmp	$inp,#0
++	str	r3,[$ctx,#0]		@ zero hash value
++	str	r3,[$ctx,#4]
++	str	r3,[$ctx,#8]
++	str	r3,[$ctx,#12]
++	str	r3,[$ctx,#16]
++	str	r3,[$ctx,#36]		@ is_base2_26
++	add	$ctx,$ctx,#20
++
++#ifdef	__thumb2__
++	it	eq
++#endif
++	moveq	r0,#0
++	beq	.Lno_key
++
++#if	__ARM_MAX_ARCH__>=7
++	adr	r11,.Lpoly1305_init
++	ldr	r12,.LOPENSSL_armcap
++#endif
++	ldrb	r4,[$inp,#0]
++	mov	r10,#0x0fffffff
++	ldrb	r5,[$inp,#1]
++	and	r3,r10,#-4		@ 0x0ffffffc
++	ldrb	r6,[$inp,#2]
++	ldrb	r7,[$inp,#3]
++	orr	r4,r4,r5,lsl#8
++	ldrb	r5,[$inp,#4]
++	orr	r4,r4,r6,lsl#16
++	ldrb	r6,[$inp,#5]
++	orr	r4,r4,r7,lsl#24
++	ldrb	r7,[$inp,#6]
++	and	r4,r4,r10
++
++#if	__ARM_MAX_ARCH__>=7
++	ldr	r12,[r11,r12]		@ OPENSSL_armcap_P
++# ifdef	__APPLE__
++	ldr	r12,[r12]
++# endif
++#endif
++	ldrb	r8,[$inp,#7]
++	orr	r5,r5,r6,lsl#8
++	ldrb	r6,[$inp,#8]
++	orr	r5,r5,r7,lsl#16
++	ldrb	r7,[$inp,#9]
++	orr	r5,r5,r8,lsl#24
++	ldrb	r8,[$inp,#10]
++	and	r5,r5,r3
++
++#if	__ARM_MAX_ARCH__>=7
++	tst	r12,#ARMV7_NEON		@ check for NEON
++# ifdef	__APPLE__
++	adr	r9,poly1305_blocks_neon
++	adr	r11,poly1305_blocks
++#  ifdef __thumb2__
++	it	ne
++#  endif
++	movne	r11,r9
++	adr	r12,poly1305_emit
++	adr	r10,poly1305_emit_neon
++#  ifdef __thumb2__
++	it	ne
++#  endif
++	movne	r12,r10
++# else
++#  ifdef __thumb2__
++	itete	eq
++#  endif
++	addeq	r12,r11,#(poly1305_emit-.Lpoly1305_init)
++	addne	r12,r11,#(poly1305_emit_neon-.Lpoly1305_init)
++	addeq	r11,r11,#(poly1305_blocks-.Lpoly1305_init)
++	addne	r11,r11,#(poly1305_blocks_neon-.Lpoly1305_init)
++# endif
++# ifdef	__thumb2__
++	orr	r12,r12,#1	@ thumb-ify address
++	orr	r11,r11,#1
++# endif
++#endif
++	ldrb	r9,[$inp,#11]
++	orr	r6,r6,r7,lsl#8
++	ldrb	r7,[$inp,#12]
++	orr	r6,r6,r8,lsl#16
++	ldrb	r8,[$inp,#13]
++	orr	r6,r6,r9,lsl#24
++	ldrb	r9,[$inp,#14]
++	and	r6,r6,r3
++
++	ldrb	r10,[$inp,#15]
++	orr	r7,r7,r8,lsl#8
++	str	r4,[$ctx,#0]
++	orr	r7,r7,r9,lsl#16
++	str	r5,[$ctx,#4]
++	orr	r7,r7,r10,lsl#24
++	str	r6,[$ctx,#8]
++	and	r7,r7,r3
++	str	r7,[$ctx,#12]
++#if	__ARM_MAX_ARCH__>=7
++	stmia	r2,{r11,r12}		@ fill functions table
++	mov	r0,#1
++#else
++	mov	r0,#0
++#endif
++.Lno_key:
++	ldmia	sp!,{r4-r11}
++#if	__ARM_ARCH__>=5
++	ret				@ bx	lr
++#else
++	tst	lr,#1
++	moveq	pc,lr			@ be binary compatible with V4, yet
++	bx	lr			@ interoperable with Thumb ISA:-)
++#endif
++.size	poly1305_init,.-poly1305_init
++___
++{
++my ($h0,$h1,$h2,$h3,$h4,$r0,$r1,$r2,$r3)=map("r$_",(4..12));
++my ($s1,$s2,$s3)=($r1,$r2,$r3);
++
++$code.=<<___;
++.type	poly1305_blocks,%function
++.align	5
++poly1305_blocks:
++	stmdb	sp!,{r3-r11,lr}
++
++	ands	$len,$len,#-16
++	beq	.Lno_data
++
++	cmp	$padbit,#0
++	add	$len,$len,$inp		@ end pointer
++	sub	sp,sp,#32
++
++	ldmia	$ctx,{$h0-$r3}		@ load context
++
++	str	$ctx,[sp,#12]		@ offload stuff
++	mov	lr,$inp
++	str	$len,[sp,#16]
++	str	$r1,[sp,#20]
++	str	$r2,[sp,#24]
++	str	$r3,[sp,#28]
++	b	.Loop
++
++.Loop:
++#if __ARM_ARCH__<7
++	ldrb	r0,[lr],#16		@ load input
++# ifdef	__thumb2__
++	it	hi
++# endif
++	addhi	$h4,$h4,#1		@ 1<<128
++	ldrb	r1,[lr,#-15]
++	ldrb	r2,[lr,#-14]
++	ldrb	r3,[lr,#-13]
++	orr	r1,r0,r1,lsl#8
++	ldrb	r0,[lr,#-12]
++	orr	r2,r1,r2,lsl#16
++	ldrb	r1,[lr,#-11]
++	orr	r3,r2,r3,lsl#24
++	ldrb	r2,[lr,#-10]
++	adds	$h0,$h0,r3		@ accumulate input
++
++	ldrb	r3,[lr,#-9]
++	orr	r1,r0,r1,lsl#8
++	ldrb	r0,[lr,#-8]
++	orr	r2,r1,r2,lsl#16
++	ldrb	r1,[lr,#-7]
++	orr	r3,r2,r3,lsl#24
++	ldrb	r2,[lr,#-6]
++	adcs	$h1,$h1,r3
++
++	ldrb	r3,[lr,#-5]
++	orr	r1,r0,r1,lsl#8
++	ldrb	r0,[lr,#-4]
++	orr	r2,r1,r2,lsl#16
++	ldrb	r1,[lr,#-3]
++	orr	r3,r2,r3,lsl#24
++	ldrb	r2,[lr,#-2]
++	adcs	$h2,$h2,r3
++
++	ldrb	r3,[lr,#-1]
++	orr	r1,r0,r1,lsl#8
++	str	lr,[sp,#8]		@ offload input pointer
++	orr	r2,r1,r2,lsl#16
++	add	$s1,$r1,$r1,lsr#2
++	orr	r3,r2,r3,lsl#24
++#else
++	ldr	r0,[lr],#16		@ load input
++# ifdef	__thumb2__
++	it	hi
++# endif
++	addhi	$h4,$h4,#1		@ padbit
++	ldr	r1,[lr,#-12]
++	ldr	r2,[lr,#-8]
++	ldr	r3,[lr,#-4]
++# ifdef	__ARMEB__
++	rev	r0,r0
++	rev	r1,r1
++	rev	r2,r2
++	rev	r3,r3
++# endif
++	adds	$h0,$h0,r0		@ accumulate input
++	str	lr,[sp,#8]		@ offload input pointer
++	adcs	$h1,$h1,r1
++	add	$s1,$r1,$r1,lsr#2
++	adcs	$h2,$h2,r2
++#endif
++	add	$s2,$r2,$r2,lsr#2
++	adcs	$h3,$h3,r3
++	add	$s3,$r3,$r3,lsr#2
++
++	umull	r2,r3,$h1,$r0
++	 adc	$h4,$h4,#0
++	umull	r0,r1,$h0,$r0
++	umlal	r2,r3,$h4,$s1
++	umlal	r0,r1,$h3,$s1
++	ldr	$r1,[sp,#20]		@ reload $r1
++	umlal	r2,r3,$h2,$s3
++	umlal	r0,r1,$h1,$s3
++	umlal	r2,r3,$h3,$s2
++	umlal	r0,r1,$h2,$s2
++	umlal	r2,r3,$h0,$r1
++	str	r0,[sp,#0]		@ future $h0
++	 mul	r0,$s2,$h4
++	ldr	$r2,[sp,#24]		@ reload $r2
++	adds	r2,r2,r1		@ d1+=d0>>32
++	 eor	r1,r1,r1
++	adc	lr,r3,#0		@ future $h2
++	str	r2,[sp,#4]		@ future $h1
++
++	mul	r2,$s3,$h4
++	eor	r3,r3,r3
++	umlal	r0,r1,$h3,$s3
++	ldr	$r3,[sp,#28]		@ reload $r3
++	umlal	r2,r3,$h3,$r0
++	umlal	r0,r1,$h2,$r0
++	umlal	r2,r3,$h2,$r1
++	umlal	r0,r1,$h1,$r1
++	umlal	r2,r3,$h1,$r2
++	umlal	r0,r1,$h0,$r2
++	umlal	r2,r3,$h0,$r3
++	ldr	$h0,[sp,#0]
++	mul	$h4,$r0,$h4
++	ldr	$h1,[sp,#4]
++
++	adds	$h2,lr,r0		@ d2+=d1>>32
++	ldr	lr,[sp,#8]		@ reload input pointer
++	adc	r1,r1,#0
++	adds	$h3,r2,r1		@ d3+=d2>>32
++	ldr	r0,[sp,#16]		@ reload end pointer
++	adc	r3,r3,#0
++	add	$h4,$h4,r3		@ h4+=d3>>32
++
++	and	r1,$h4,#-4
++	and	$h4,$h4,#3
++	add	r1,r1,r1,lsr#2		@ *=5
++	adds	$h0,$h0,r1
++	adcs	$h1,$h1,#0
++	adcs	$h2,$h2,#0
++	adcs	$h3,$h3,#0
++	adc	$h4,$h4,#0
++
++	cmp	r0,lr			@ done yet?
++	bhi	.Loop
++
++	ldr	$ctx,[sp,#12]
++	add	sp,sp,#32
++	stmia	$ctx,{$h0-$h4}		@ store the result
++
++.Lno_data:
++#if	__ARM_ARCH__>=5
++	ldmia	sp!,{r3-r11,pc}
++#else
++	ldmia	sp!,{r3-r11,lr}
++	tst	lr,#1
++	moveq	pc,lr			@ be binary compatible with V4, yet
++	bx	lr			@ interoperable with Thumb ISA:-)
++#endif
++.size	poly1305_blocks,.-poly1305_blocks
++___
++}
++{
++my ($ctx,$mac,$nonce)=map("r$_",(0..2));
++my ($h0,$h1,$h2,$h3,$h4,$g0,$g1,$g2,$g3)=map("r$_",(3..11));
++my $g4=$h4;
++
++$code.=<<___;
++.type	poly1305_emit,%function
++.align	5
++poly1305_emit:
++	stmdb	sp!,{r4-r11}
++.Lpoly1305_emit_enter:
++
++	ldmia	$ctx,{$h0-$h4}
++	adds	$g0,$h0,#5		@ compare to modulus
++	adcs	$g1,$h1,#0
++	adcs	$g2,$h2,#0
++	adcs	$g3,$h3,#0
++	adc	$g4,$h4,#0
++	tst	$g4,#4			@ did it carry/borrow?
++
++#ifdef	__thumb2__
++	it	ne
++#endif
++	movne	$h0,$g0
++	ldr	$g0,[$nonce,#0]
++#ifdef	__thumb2__
++	it	ne
++#endif
++	movne	$h1,$g1
++	ldr	$g1,[$nonce,#4]
++#ifdef	__thumb2__
++	it	ne
++#endif
++	movne	$h2,$g2
++	ldr	$g2,[$nonce,#8]
++#ifdef	__thumb2__
++	it	ne
++#endif
++	movne	$h3,$g3
++	ldr	$g3,[$nonce,#12]
++
++	adds	$h0,$h0,$g0
++	adcs	$h1,$h1,$g1
++	adcs	$h2,$h2,$g2
++	adc	$h3,$h3,$g3
++
++#if __ARM_ARCH__>=7
++# ifdef __ARMEB__
++	rev	$h0,$h0
++	rev	$h1,$h1
++	rev	$h2,$h2
++	rev	$h3,$h3
++# endif
++	str	$h0,[$mac,#0]
++	str	$h1,[$mac,#4]
++	str	$h2,[$mac,#8]
++	str	$h3,[$mac,#12]
++#else
++	strb	$h0,[$mac,#0]
++	mov	$h0,$h0,lsr#8
++	strb	$h1,[$mac,#4]
++	mov	$h1,$h1,lsr#8
++	strb	$h2,[$mac,#8]
++	mov	$h2,$h2,lsr#8
++	strb	$h3,[$mac,#12]
++	mov	$h3,$h3,lsr#8
++
++	strb	$h0,[$mac,#1]
++	mov	$h0,$h0,lsr#8
++	strb	$h1,[$mac,#5]
++	mov	$h1,$h1,lsr#8
++	strb	$h2,[$mac,#9]
++	mov	$h2,$h2,lsr#8
++	strb	$h3,[$mac,#13]
++	mov	$h3,$h3,lsr#8
++
++	strb	$h0,[$mac,#2]
++	mov	$h0,$h0,lsr#8
++	strb	$h1,[$mac,#6]
++	mov	$h1,$h1,lsr#8
++	strb	$h2,[$mac,#10]
++	mov	$h2,$h2,lsr#8
++	strb	$h3,[$mac,#14]
++	mov	$h3,$h3,lsr#8
++
++	strb	$h0,[$mac,#3]
++	strb	$h1,[$mac,#7]
++	strb	$h2,[$mac,#11]
++	strb	$h3,[$mac,#15]
++#endif
++	ldmia	sp!,{r4-r11}
++#if	__ARM_ARCH__>=5
++	ret				@ bx	lr
++#else
++	tst	lr,#1
++	moveq	pc,lr			@ be binary compatible with V4, yet
++	bx	lr			@ interoperable with Thumb ISA:-)
++#endif
++.size	poly1305_emit,.-poly1305_emit
++___
++{
++my ($R0,$R1,$S1,$R2,$S2,$R3,$S3,$R4,$S4) = map("d$_",(0..9));
++my ($D0,$D1,$D2,$D3,$D4, $H0,$H1,$H2,$H3,$H4) = map("q$_",(5..14));
++my ($T0,$T1,$MASK) = map("q$_",(15,4,0));
++
++my ($in2,$zeros,$tbl0,$tbl1) = map("r$_",(4..7));
++
++$code.=<<___;
++#if	__ARM_MAX_ARCH__>=7
++.fpu	neon
++
++.type	poly1305_init_neon,%function
++.align	5
++poly1305_init_neon:
++	ldr	r4,[$ctx,#20]		@ load key base 2^32
++	ldr	r5,[$ctx,#24]
++	ldr	r6,[$ctx,#28]
++	ldr	r7,[$ctx,#32]
++
++	and	r2,r4,#0x03ffffff	@ base 2^32 -> base 2^26
++	mov	r3,r4,lsr#26
++	mov	r4,r5,lsr#20
++	orr	r3,r3,r5,lsl#6
++	mov	r5,r6,lsr#14
++	orr	r4,r4,r6,lsl#12
++	mov	r6,r7,lsr#8
++	orr	r5,r5,r7,lsl#18
++	and	r3,r3,#0x03ffffff
++	and	r4,r4,#0x03ffffff
++	and	r5,r5,#0x03ffffff
++
++	vdup.32	$R0,r2			@ r^1 in both lanes
++	add	r2,r3,r3,lsl#2		@ *5
++	vdup.32	$R1,r3
++	add	r3,r4,r4,lsl#2
++	vdup.32	$S1,r2
++	vdup.32	$R2,r4
++	add	r4,r5,r5,lsl#2
++	vdup.32	$S2,r3
++	vdup.32	$R3,r5
++	add	r5,r6,r6,lsl#2
++	vdup.32	$S3,r4
++	vdup.32	$R4,r6
++	vdup.32	$S4,r5
++
++	mov	$zeros,#2		@ counter
++
++.Lsquare_neon:
++	@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
++	@ d0 = h0*r0 + h4*5*r1 + h3*5*r2 + h2*5*r3 + h1*5*r4
++	@ d1 = h1*r0 + h0*r1   + h4*5*r2 + h3*5*r3 + h2*5*r4
++	@ d2 = h2*r0 + h1*r1   + h0*r2   + h4*5*r3 + h3*5*r4
++	@ d3 = h3*r0 + h2*r1   + h1*r2   + h0*r3   + h4*5*r4
++	@ d4 = h4*r0 + h3*r1   + h2*r2   + h1*r3   + h0*r4
++
++	vmull.u32	$D0,$R0,${R0}[1]
++	vmull.u32	$D1,$R1,${R0}[1]
++	vmull.u32	$D2,$R2,${R0}[1]
++	vmull.u32	$D3,$R3,${R0}[1]
++	vmull.u32	$D4,$R4,${R0}[1]
++
++	vmlal.u32	$D0,$R4,${S1}[1]
++	vmlal.u32	$D1,$R0,${R1}[1]
++	vmlal.u32	$D2,$R1,${R1}[1]
++	vmlal.u32	$D3,$R2,${R1}[1]
++	vmlal.u32	$D4,$R3,${R1}[1]
++
++	vmlal.u32	$D0,$R3,${S2}[1]
++	vmlal.u32	$D1,$R4,${S2}[1]
++	vmlal.u32	$D3,$R1,${R2}[1]
++	vmlal.u32	$D2,$R0,${R2}[1]
++	vmlal.u32	$D4,$R2,${R2}[1]
++
++	vmlal.u32	$D0,$R2,${S3}[1]
++	vmlal.u32	$D3,$R0,${R3}[1]
++	vmlal.u32	$D1,$R3,${S3}[1]
++	vmlal.u32	$D2,$R4,${S3}[1]
++	vmlal.u32	$D4,$R1,${R3}[1]
++
++	vmlal.u32	$D3,$R4,${S4}[1]
++	vmlal.u32	$D0,$R1,${S4}[1]
++	vmlal.u32	$D1,$R2,${S4}[1]
++	vmlal.u32	$D2,$R3,${S4}[1]
++	vmlal.u32	$D4,$R0,${R4}[1]
++
++	@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
++	@ lazy reduction as discussed in "NEON crypto" by D.J. Bernstein
++	@ and P. Schwabe
++	@
++	@ H0>>+H1>>+H2>>+H3>>+H4
++	@ H3>>+H4>>*5+H0>>+H1
++	@
++	@ Trivia.
++	@
++	@ Result of multiplication of n-bit number by m-bit number is
++	@ n+m bits wide. However! Even though 2^n is a n+1-bit number,
++	@ m-bit number multiplied by 2^n is still n+m bits wide.
++	@
++	@ Sum of two n-bit numbers is n+1 bits wide, sum of three - n+2,
++	@ and so is sum of four. Sum of 2^m n-m-bit numbers and n-bit
++	@ one is n+1 bits wide.
++	@
++	@ >>+ denotes Hnext += Hn>>26, Hn &= 0x3ffffff. This means that
++	@ H0, H2, H3 are guaranteed to be 26 bits wide, while H1 and H4
++	@ can be 27. However! In cases when their width exceeds 26 bits
++	@ they are limited by 2^26+2^6. This in turn means that *sum*
++	@ of the products with these values can still be viewed as sum
++	@ of 52-bit numbers as long as the amount of addends is not a
++	@ power of 2. For example,
++	@
++	@ H4 = H4*R0 + H3*R1 + H2*R2 + H1*R3 + H0 * R4,
++	@
++	@ which can't be larger than 5 * (2^26 + 2^6) * (2^26 + 2^6), or
++	@ 5 * (2^52 + 2*2^32 + 2^12), which in turn is smaller than
++	@ 8 * (2^52) or 2^55. However, the value is then multiplied by
++	@ by 5, so we should be looking at 5 * 5 * (2^52 + 2^33 + 2^12),
++	@ which is less than 32 * (2^52) or 2^57. And when processing
++	@ data we are looking at triple as many addends...
++	@
++	@ In key setup procedure pre-reduced H0 is limited by 5*4+1 and
++	@ 5*H4 - by 5*5 52-bit addends, or 57 bits. But when hashing the
++	@ input H0 is limited by (5*4+1)*3 addends, or 58 bits, while
++	@ 5*H4 by 5*5*3, or 59[!] bits. How is this relevant? vmlal.u32
++	@ instruction accepts 2x32-bit input and writes 2x64-bit result.
++	@ This means that result of reduction have to be compressed upon
++	@ loop wrap-around. This can be done in the process of reduction
++	@ to minimize amount of instructions [as well as amount of
++	@ 128-bit instructions, which benefits low-end processors], but
++	@ one has to watch for H2 (which is narrower than H0) and 5*H4
++	@ not being wider than 58 bits, so that result of right shift
++	@ by 26 bits fits in 32 bits. This is also useful on x86,
++	@ because it allows to use paddd in place for paddq, which
++	@ benefits Atom, where paddq is ridiculously slow.
++
++	vshr.u64	$T0,$D3,#26
++	vmovn.i64	$D3#lo,$D3
++	 vshr.u64	$T1,$D0,#26
++	 vmovn.i64	$D0#lo,$D0
++	vadd.i64	$D4,$D4,$T0		@ h3 -> h4
++	vbic.i32	$D3#lo,#0xfc000000	@ &=0x03ffffff
++	 vadd.i64	$D1,$D1,$T1		@ h0 -> h1
++	 vbic.i32	$D0#lo,#0xfc000000
++
++	vshrn.u64	$T0#lo,$D4,#26
++	vmovn.i64	$D4#lo,$D4
++	 vshr.u64	$T1,$D1,#26
++	 vmovn.i64	$D1#lo,$D1
++	 vadd.i64	$D2,$D2,$T1		@ h1 -> h2
++	vbic.i32	$D4#lo,#0xfc000000
++	 vbic.i32	$D1#lo,#0xfc000000
++
++	vadd.i32	$D0#lo,$D0#lo,$T0#lo
++	vshl.u32	$T0#lo,$T0#lo,#2
++	 vshrn.u64	$T1#lo,$D2,#26
++	 vmovn.i64	$D2#lo,$D2
++	vadd.i32	$D0#lo,$D0#lo,$T0#lo	@ h4 -> h0
++	 vadd.i32	$D3#lo,$D3#lo,$T1#lo	@ h2 -> h3
++	 vbic.i32	$D2#lo,#0xfc000000
++
++	vshr.u32	$T0#lo,$D0#lo,#26
++	vbic.i32	$D0#lo,#0xfc000000
++	 vshr.u32	$T1#lo,$D3#lo,#26
++	 vbic.i32	$D3#lo,#0xfc000000
++	vadd.i32	$D1#lo,$D1#lo,$T0#lo	@ h0 -> h1
++	 vadd.i32	$D4#lo,$D4#lo,$T1#lo	@ h3 -> h4
++
++	subs		$zeros,$zeros,#1
++	beq		.Lsquare_break_neon
++
++	add		$tbl0,$ctx,#(48+0*9*4)
++	add		$tbl1,$ctx,#(48+1*9*4)
++
++	vtrn.32		$R0,$D0#lo		@ r^2:r^1
++	vtrn.32		$R2,$D2#lo
++	vtrn.32		$R3,$D3#lo
++	vtrn.32		$R1,$D1#lo
++	vtrn.32		$R4,$D4#lo
++
++	vshl.u32	$S2,$R2,#2		@ *5
++	vshl.u32	$S3,$R3,#2
++	vshl.u32	$S1,$R1,#2
++	vshl.u32	$S4,$R4,#2
++	vadd.i32	$S2,$S2,$R2
++	vadd.i32	$S1,$S1,$R1
++	vadd.i32	$S3,$S3,$R3
++	vadd.i32	$S4,$S4,$R4
++
++	vst4.32		{${R0}[0],${R1}[0],${S1}[0],${R2}[0]},[$tbl0]!
++	vst4.32		{${R0}[1],${R1}[1],${S1}[1],${R2}[1]},[$tbl1]!
++	vst4.32		{${S2}[0],${R3}[0],${S3}[0],${R4}[0]},[$tbl0]!
++	vst4.32		{${S2}[1],${R3}[1],${S3}[1],${R4}[1]},[$tbl1]!
++	vst1.32		{${S4}[0]},[$tbl0,:32]
++	vst1.32		{${S4}[1]},[$tbl1,:32]
++
++	b		.Lsquare_neon
++
++.align	4
++.Lsquare_break_neon:
++	add		$tbl0,$ctx,#(48+2*4*9)
++	add		$tbl1,$ctx,#(48+3*4*9)
++
++	vmov		$R0,$D0#lo		@ r^4:r^3
++	vshl.u32	$S1,$D1#lo,#2		@ *5
++	vmov		$R1,$D1#lo
++	vshl.u32	$S2,$D2#lo,#2
++	vmov		$R2,$D2#lo
++	vshl.u32	$S3,$D3#lo,#2
++	vmov		$R3,$D3#lo
++	vshl.u32	$S4,$D4#lo,#2
++	vmov		$R4,$D4#lo
++	vadd.i32	$S1,$S1,$D1#lo
++	vadd.i32	$S2,$S2,$D2#lo
++	vadd.i32	$S3,$S3,$D3#lo
++	vadd.i32	$S4,$S4,$D4#lo
++
++	vst4.32		{${R0}[0],${R1}[0],${S1}[0],${R2}[0]},[$tbl0]!
++	vst4.32		{${R0}[1],${R1}[1],${S1}[1],${R2}[1]},[$tbl1]!
++	vst4.32		{${S2}[0],${R3}[0],${S3}[0],${R4}[0]},[$tbl0]!
++	vst4.32		{${S2}[1],${R3}[1],${S3}[1],${R4}[1]},[$tbl1]!
++	vst1.32		{${S4}[0]},[$tbl0]
++	vst1.32		{${S4}[1]},[$tbl1]
++
++	ret				@ bx	lr
++.size	poly1305_init_neon,.-poly1305_init_neon
++
++.type	poly1305_blocks_neon,%function
++.align	5
++poly1305_blocks_neon:
++	ldr	ip,[$ctx,#36]		@ is_base2_26
++	ands	$len,$len,#-16
++	beq	.Lno_data_neon
++
++	cmp	$len,#64
++	bhs	.Lenter_neon
++	tst	ip,ip			@ is_base2_26?
++	beq	poly1305_blocks
++
++.Lenter_neon:
++	stmdb	sp!,{r4-r7}
++	vstmdb	sp!,{d8-d15}		@ ABI specification says so
++
++	tst	ip,ip			@ is_base2_26?
++	bne	.Lbase2_26_neon
++
++	stmdb	sp!,{r1-r3,lr}
++	bl	poly1305_init_neon
++
++	ldr	r4,[$ctx,#0]		@ load hash value base 2^32
++	ldr	r5,[$ctx,#4]
++	ldr	r6,[$ctx,#8]
++	ldr	r7,[$ctx,#12]
++	ldr	ip,[$ctx,#16]
++
++	and	r2,r4,#0x03ffffff	@ base 2^32 -> base 2^26
++	mov	r3,r4,lsr#26
++	 veor	$D0#lo,$D0#lo,$D0#lo
++	mov	r4,r5,lsr#20
++	orr	r3,r3,r5,lsl#6
++	 veor	$D1#lo,$D1#lo,$D1#lo
++	mov	r5,r6,lsr#14
++	orr	r4,r4,r6,lsl#12
++	 veor	$D2#lo,$D2#lo,$D2#lo
++	mov	r6,r7,lsr#8
++	orr	r5,r5,r7,lsl#18
++	 veor	$D3#lo,$D3#lo,$D3#lo
++	and	r3,r3,#0x03ffffff
++	orr	r6,r6,ip,lsl#24
++	 veor	$D4#lo,$D4#lo,$D4#lo
++	and	r4,r4,#0x03ffffff
++	mov	r1,#1
++	and	r5,r5,#0x03ffffff
++	str	r1,[$ctx,#36]		@ is_base2_26
++
++	vmov.32	$D0#lo[0],r2
++	vmov.32	$D1#lo[0],r3
++	vmov.32	$D2#lo[0],r4
++	vmov.32	$D3#lo[0],r5
++	vmov.32	$D4#lo[0],r6
++	adr	$zeros,.Lzeros
++
++	ldmia	sp!,{r1-r3,lr}
++	b	.Lbase2_32_neon
++
++.align	4
++.Lbase2_26_neon:
++	@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
++	@ load hash value
++
++	veor		$D0#lo,$D0#lo,$D0#lo
++	veor		$D1#lo,$D1#lo,$D1#lo
++	veor		$D2#lo,$D2#lo,$D2#lo
++	veor		$D3#lo,$D3#lo,$D3#lo
++	veor		$D4#lo,$D4#lo,$D4#lo
++	vld4.32		{$D0#lo[0],$D1#lo[0],$D2#lo[0],$D3#lo[0]},[$ctx]!
++	adr		$zeros,.Lzeros
++	vld1.32		{$D4#lo[0]},[$ctx]
++	sub		$ctx,$ctx,#16		@ rewind
++
++.Lbase2_32_neon:
++	add		$in2,$inp,#32
++	mov		$padbit,$padbit,lsl#24
++	tst		$len,#31
++	beq		.Leven
++
++	vld4.32		{$H0#lo[0],$H1#lo[0],$H2#lo[0],$H3#lo[0]},[$inp]!
++	vmov.32		$H4#lo[0],$padbit
++	sub		$len,$len,#16
++	add		$in2,$inp,#32
++
++# ifdef	__ARMEB__
++	vrev32.8	$H0,$H0
++	vrev32.8	$H3,$H3
++	vrev32.8	$H1,$H1
++	vrev32.8	$H2,$H2
++# endif
++	vsri.u32	$H4#lo,$H3#lo,#8	@ base 2^32 -> base 2^26
++	vshl.u32	$H3#lo,$H3#lo,#18
++
++	vsri.u32	$H3#lo,$H2#lo,#14
++	vshl.u32	$H2#lo,$H2#lo,#12
++	vadd.i32	$H4#hi,$H4#lo,$D4#lo	@ add hash value and move to #hi
++
++	vbic.i32	$H3#lo,#0xfc000000
++	vsri.u32	$H2#lo,$H1#lo,#20
++	vshl.u32	$H1#lo,$H1#lo,#6
++
++	vbic.i32	$H2#lo,#0xfc000000
++	vsri.u32	$H1#lo,$H0#lo,#26
++	vadd.i32	$H3#hi,$H3#lo,$D3#lo
++
++	vbic.i32	$H0#lo,#0xfc000000
++	vbic.i32	$H1#lo,#0xfc000000
++	vadd.i32	$H2#hi,$H2#lo,$D2#lo
++
++	vadd.i32	$H0#hi,$H0#lo,$D0#lo
++	vadd.i32	$H1#hi,$H1#lo,$D1#lo
++
++	mov		$tbl1,$zeros
++	add		$tbl0,$ctx,#48
++
++	cmp		$len,$len
++	b		.Long_tail
++
++.align	4
++.Leven:
++	subs		$len,$len,#64
++	it		lo
++	movlo		$in2,$zeros
++
++	vmov.i32	$H4,#1<<24		@ padbit, yes, always
++	vld4.32		{$H0#lo,$H1#lo,$H2#lo,$H3#lo},[$inp]	@ inp[0:1]
++	add		$inp,$inp,#64
++	vld4.32		{$H0#hi,$H1#hi,$H2#hi,$H3#hi},[$in2]	@ inp[2:3] (or 0)
++	add		$in2,$in2,#64
++	itt		hi
++	addhi		$tbl1,$ctx,#(48+1*9*4)
++	addhi		$tbl0,$ctx,#(48+3*9*4)
++
++# ifdef	__ARMEB__
++	vrev32.8	$H0,$H0
++	vrev32.8	$H3,$H3
++	vrev32.8	$H1,$H1
++	vrev32.8	$H2,$H2
++# endif
++	vsri.u32	$H4,$H3,#8		@ base 2^32 -> base 2^26
++	vshl.u32	$H3,$H3,#18
++
++	vsri.u32	$H3,$H2,#14
++	vshl.u32	$H2,$H2,#12
++
++	vbic.i32	$H3,#0xfc000000
++	vsri.u32	$H2,$H1,#20
++	vshl.u32	$H1,$H1,#6
++
++	vbic.i32	$H2,#0xfc000000
++	vsri.u32	$H1,$H0,#26
++
++	vbic.i32	$H0,#0xfc000000
++	vbic.i32	$H1,#0xfc000000
++
++	bls		.Lskip_loop
++
++	vld4.32		{${R0}[1],${R1}[1],${S1}[1],${R2}[1]},[$tbl1]!	@ load r^2
++	vld4.32		{${R0}[0],${R1}[0],${S1}[0],${R2}[0]},[$tbl0]!	@ load r^4
++	vld4.32		{${S2}[1],${R3}[1],${S3}[1],${R4}[1]},[$tbl1]!
++	vld4.32		{${S2}[0],${R3}[0],${S3}[0],${R4}[0]},[$tbl0]!
++	b		.Loop_neon
++
++.align	5
++.Loop_neon:
++	@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
++	@ ((inp[0]*r^4+inp[2]*r^2+inp[4])*r^4+inp[6]*r^2
++	@ ((inp[1]*r^4+inp[3]*r^2+inp[5])*r^3+inp[7]*r
++	@   \___________________/
++	@ ((inp[0]*r^4+inp[2]*r^2+inp[4])*r^4+inp[6]*r^2+inp[8])*r^2
++	@ ((inp[1]*r^4+inp[3]*r^2+inp[5])*r^4+inp[7]*r^2+inp[9])*r
++	@   \___________________/ \____________________/
++	@
++	@ Note that we start with inp[2:3]*r^2. This is because it
++	@ doesn't depend on reduction in previous iteration.
++	@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
++	@ d4 = h4*r0 + h3*r1   + h2*r2   + h1*r3   + h0*r4
++	@ d3 = h3*r0 + h2*r1   + h1*r2   + h0*r3   + h4*5*r4
++	@ d2 = h2*r0 + h1*r1   + h0*r2   + h4*5*r3 + h3*5*r4
++	@ d1 = h1*r0 + h0*r1   + h4*5*r2 + h3*5*r3 + h2*5*r4
++	@ d0 = h0*r0 + h4*5*r1 + h3*5*r2 + h2*5*r3 + h1*5*r4
++
++	@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
++	@ inp[2:3]*r^2
++
++	vadd.i32	$H2#lo,$H2#lo,$D2#lo	@ accumulate inp[0:1]
++	vmull.u32	$D2,$H2#hi,${R0}[1]
++	vadd.i32	$H0#lo,$H0#lo,$D0#lo
++	vmull.u32	$D0,$H0#hi,${R0}[1]
++	vadd.i32	$H3#lo,$H3#lo,$D3#lo
++	vmull.u32	$D3,$H3#hi,${R0}[1]
++	vmlal.u32	$D2,$H1#hi,${R1}[1]
++	vadd.i32	$H1#lo,$H1#lo,$D1#lo
++	vmull.u32	$D1,$H1#hi,${R0}[1]
++
++	vadd.i32	$H4#lo,$H4#lo,$D4#lo
++	vmull.u32	$D4,$H4#hi,${R0}[1]
++	subs		$len,$len,#64
++	vmlal.u32	$D0,$H4#hi,${S1}[1]
++	it		lo
++	movlo		$in2,$zeros
++	vmlal.u32	$D3,$H2#hi,${R1}[1]
++	vld1.32		${S4}[1],[$tbl1,:32]
++	vmlal.u32	$D1,$H0#hi,${R1}[1]
++	vmlal.u32	$D4,$H3#hi,${R1}[1]
++
++	vmlal.u32	$D0,$H3#hi,${S2}[1]
++	vmlal.u32	$D3,$H1#hi,${R2}[1]
++	vmlal.u32	$D4,$H2#hi,${R2}[1]
++	vmlal.u32	$D1,$H4#hi,${S2}[1]
++	vmlal.u32	$D2,$H0#hi,${R2}[1]
++
++	vmlal.u32	$D3,$H0#hi,${R3}[1]
++	vmlal.u32	$D0,$H2#hi,${S3}[1]
++	vmlal.u32	$D4,$H1#hi,${R3}[1]
++	vmlal.u32	$D1,$H3#hi,${S3}[1]
++	vmlal.u32	$D2,$H4#hi,${S3}[1]
++
++	vmlal.u32	$D3,$H4#hi,${S4}[1]
++	vmlal.u32	$D0,$H1#hi,${S4}[1]
++	vmlal.u32	$D4,$H0#hi,${R4}[1]
++	vmlal.u32	$D1,$H2#hi,${S4}[1]
++	vmlal.u32	$D2,$H3#hi,${S4}[1]
++
++	vld4.32		{$H0#hi,$H1#hi,$H2#hi,$H3#hi},[$in2]	@ inp[2:3] (or 0)
++	add		$in2,$in2,#64
++
++	@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
++	@ (hash+inp[0:1])*r^4 and accumulate
++
++	vmlal.u32	$D3,$H3#lo,${R0}[0]
++	vmlal.u32	$D0,$H0#lo,${R0}[0]
++	vmlal.u32	$D4,$H4#lo,${R0}[0]
++	vmlal.u32	$D1,$H1#lo,${R0}[0]
++	vmlal.u32	$D2,$H2#lo,${R0}[0]
++	vld1.32		${S4}[0],[$tbl0,:32]
++
++	vmlal.u32	$D3,$H2#lo,${R1}[0]
++	vmlal.u32	$D0,$H4#lo,${S1}[0]
++	vmlal.u32	$D4,$H3#lo,${R1}[0]
++	vmlal.u32	$D1,$H0#lo,${R1}[0]
++	vmlal.u32	$D2,$H1#lo,${R1}[0]
++
++	vmlal.u32	$D3,$H1#lo,${R2}[0]
++	vmlal.u32	$D0,$H3#lo,${S2}[0]
++	vmlal.u32	$D4,$H2#lo,${R2}[0]
++	vmlal.u32	$D1,$H4#lo,${S2}[0]
++	vmlal.u32	$D2,$H0#lo,${R2}[0]
++
++	vmlal.u32	$D3,$H0#lo,${R3}[0]
++	vmlal.u32	$D0,$H2#lo,${S3}[0]
++	vmlal.u32	$D4,$H1#lo,${R3}[0]
++	vmlal.u32	$D1,$H3#lo,${S3}[0]
++	vmlal.u32	$D3,$H4#lo,${S4}[0]
++
++	vmlal.u32	$D2,$H4#lo,${S3}[0]
++	vmlal.u32	$D0,$H1#lo,${S4}[0]
++	vmlal.u32	$D4,$H0#lo,${R4}[0]
++	vmov.i32	$H4,#1<<24		@ padbit, yes, always
++	vmlal.u32	$D1,$H2#lo,${S4}[0]
++	vmlal.u32	$D2,$H3#lo,${S4}[0]
++
++	vld4.32		{$H0#lo,$H1#lo,$H2#lo,$H3#lo},[$inp]	@ inp[0:1]
++	add		$inp,$inp,#64
++# ifdef	__ARMEB__
++	vrev32.8	$H0,$H0
++	vrev32.8	$H1,$H1
++	vrev32.8	$H2,$H2
++	vrev32.8	$H3,$H3
++# endif
++
++	@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
++	@ lazy reduction interleaved with base 2^32 -> base 2^26 of
++	@ inp[0:3] previously loaded to $H0-$H3 and smashed to $H0-$H4.
++
++	vshr.u64	$T0,$D3,#26
++	vmovn.i64	$D3#lo,$D3
++	 vshr.u64	$T1,$D0,#26
++	 vmovn.i64	$D0#lo,$D0
++	vadd.i64	$D4,$D4,$T0		@ h3 -> h4
++	vbic.i32	$D3#lo,#0xfc000000
++	  vsri.u32	$H4,$H3,#8		@ base 2^32 -> base 2^26
++	 vadd.i64	$D1,$D1,$T1		@ h0 -> h1
++	  vshl.u32	$H3,$H3,#18
++	 vbic.i32	$D0#lo,#0xfc000000
++
++	vshrn.u64	$T0#lo,$D4,#26
++	vmovn.i64	$D4#lo,$D4
++	 vshr.u64	$T1,$D1,#26
++	 vmovn.i64	$D1#lo,$D1
++	 vadd.i64	$D2,$D2,$T1		@ h1 -> h2
++	  vsri.u32	$H3,$H2,#14
++	vbic.i32	$D4#lo,#0xfc000000
++	  vshl.u32	$H2,$H2,#12
++	 vbic.i32	$D1#lo,#0xfc000000
++
++	vadd.i32	$D0#lo,$D0#lo,$T0#lo
++	vshl.u32	$T0#lo,$T0#lo,#2
++	  vbic.i32	$H3,#0xfc000000
++	 vshrn.u64	$T1#lo,$D2,#26
++	 vmovn.i64	$D2#lo,$D2
++	vaddl.u32	$D0,$D0#lo,$T0#lo	@ h4 -> h0 [widen for a sec]
++	  vsri.u32	$H2,$H1,#20
++	 vadd.i32	$D3#lo,$D3#lo,$T1#lo	@ h2 -> h3
++	  vshl.u32	$H1,$H1,#6
++	 vbic.i32	$D2#lo,#0xfc000000
++	  vbic.i32	$H2,#0xfc000000
++
++	vshrn.u64	$T0#lo,$D0,#26		@ re-narrow
++	vmovn.i64	$D0#lo,$D0
++	  vsri.u32	$H1,$H0,#26
++	  vbic.i32	$H0,#0xfc000000
++	 vshr.u32	$T1#lo,$D3#lo,#26
++	 vbic.i32	$D3#lo,#0xfc000000
++	vbic.i32	$D0#lo,#0xfc000000
++	vadd.i32	$D1#lo,$D1#lo,$T0#lo	@ h0 -> h1
++	 vadd.i32	$D4#lo,$D4#lo,$T1#lo	@ h3 -> h4
++	  vbic.i32	$H1,#0xfc000000
++
++	bhi		.Loop_neon
++
++.Lskip_loop:
++	@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
++	@ multiply (inp[0:1]+hash) or inp[2:3] by r^2:r^1
++
++	add		$tbl1,$ctx,#(48+0*9*4)
++	add		$tbl0,$ctx,#(48+1*9*4)
++	adds		$len,$len,#32
++	it		ne
++	movne		$len,#0
++	bne		.Long_tail
++
++	vadd.i32	$H2#hi,$H2#lo,$D2#lo	@ add hash value and move to #hi
++	vadd.i32	$H0#hi,$H0#lo,$D0#lo
++	vadd.i32	$H3#hi,$H3#lo,$D3#lo
++	vadd.i32	$H1#hi,$H1#lo,$D1#lo
++	vadd.i32	$H4#hi,$H4#lo,$D4#lo
++
++.Long_tail:
++	vld4.32		{${R0}[1],${R1}[1],${S1}[1],${R2}[1]},[$tbl1]!	@ load r^1
++	vld4.32		{${R0}[0],${R1}[0],${S1}[0],${R2}[0]},[$tbl0]!	@ load r^2
++
++	vadd.i32	$H2#lo,$H2#lo,$D2#lo	@ can be redundant
++	vmull.u32	$D2,$H2#hi,$R0
++	vadd.i32	$H0#lo,$H0#lo,$D0#lo
++	vmull.u32	$D0,$H0#hi,$R0
++	vadd.i32	$H3#lo,$H3#lo,$D3#lo
++	vmull.u32	$D3,$H3#hi,$R0
++	vadd.i32	$H1#lo,$H1#lo,$D1#lo
++	vmull.u32	$D1,$H1#hi,$R0
++	vadd.i32	$H4#lo,$H4#lo,$D4#lo
++	vmull.u32	$D4,$H4#hi,$R0
++
++	vmlal.u32	$D0,$H4#hi,$S1
++	vld4.32		{${S2}[1],${R3}[1],${S3}[1],${R4}[1]},[$tbl1]!
++	vmlal.u32	$D3,$H2#hi,$R1
++	vld4.32		{${S2}[0],${R3}[0],${S3}[0],${R4}[0]},[$tbl0]!
++	vmlal.u32	$D1,$H0#hi,$R1
++	vmlal.u32	$D4,$H3#hi,$R1
++	vmlal.u32	$D2,$H1#hi,$R1
++
++	vmlal.u32	$D3,$H1#hi,$R2
++	vld1.32		${S4}[1],[$tbl1,:32]
++	vmlal.u32	$D0,$H3#hi,$S2
++	vld1.32		${S4}[0],[$tbl0,:32]
++	vmlal.u32	$D4,$H2#hi,$R2
++	vmlal.u32	$D1,$H4#hi,$S2
++	vmlal.u32	$D2,$H0#hi,$R2
++
++	vmlal.u32	$D3,$H0#hi,$R3
++	 it		ne
++	 addne		$tbl1,$ctx,#(48+2*9*4)
++	vmlal.u32	$D0,$H2#hi,$S3
++	 it		ne
++	 addne		$tbl0,$ctx,#(48+3*9*4)
++	vmlal.u32	$D4,$H1#hi,$R3
++	vmlal.u32	$D1,$H3#hi,$S3
++	vmlal.u32	$D2,$H4#hi,$S3
++
++	vmlal.u32	$D3,$H4#hi,$S4
++	 vorn		$MASK,$MASK,$MASK	@ all-ones, can be redundant
++	vmlal.u32	$D0,$H1#hi,$S4
++	 vshr.u64	$MASK,$MASK,#38
++	vmlal.u32	$D4,$H0#hi,$R4
++	vmlal.u32	$D1,$H2#hi,$S4
++	vmlal.u32	$D2,$H3#hi,$S4
++
++	beq		.Lshort_tail
++
++	@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
++	@ (hash+inp[0:1])*r^4:r^3 and accumulate
++
++	vld4.32		{${R0}[1],${R1}[1],${S1}[1],${R2}[1]},[$tbl1]!	@ load r^3
++	vld4.32		{${R0}[0],${R1}[0],${S1}[0],${R2}[0]},[$tbl0]!	@ load r^4
++
++	vmlal.u32	$D2,$H2#lo,$R0
++	vmlal.u32	$D0,$H0#lo,$R0
++	vmlal.u32	$D3,$H3#lo,$R0
++	vmlal.u32	$D1,$H1#lo,$R0
++	vmlal.u32	$D4,$H4#lo,$R0
++
++	vmlal.u32	$D0,$H4#lo,$S1
++	vld4.32		{${S2}[1],${R3}[1],${S3}[1],${R4}[1]},[$tbl1]!
++	vmlal.u32	$D3,$H2#lo,$R1
++	vld4.32		{${S2}[0],${R3}[0],${S3}[0],${R4}[0]},[$tbl0]!
++	vmlal.u32	$D1,$H0#lo,$R1
++	vmlal.u32	$D4,$H3#lo,$R1
++	vmlal.u32	$D2,$H1#lo,$R1
++
++	vmlal.u32	$D3,$H1#lo,$R2
++	vld1.32		${S4}[1],[$tbl1,:32]
++	vmlal.u32	$D0,$H3#lo,$S2
++	vld1.32		${S4}[0],[$tbl0,:32]
++	vmlal.u32	$D4,$H2#lo,$R2
++	vmlal.u32	$D1,$H4#lo,$S2
++	vmlal.u32	$D2,$H0#lo,$R2
++
++	vmlal.u32	$D3,$H0#lo,$R3
++	vmlal.u32	$D0,$H2#lo,$S3
++	vmlal.u32	$D4,$H1#lo,$R3
++	vmlal.u32	$D1,$H3#lo,$S3
++	vmlal.u32	$D2,$H4#lo,$S3
++
++	vmlal.u32	$D3,$H4#lo,$S4
++	 vorn		$MASK,$MASK,$MASK	@ all-ones
++	vmlal.u32	$D0,$H1#lo,$S4
++	 vshr.u64	$MASK,$MASK,#38
++	vmlal.u32	$D4,$H0#lo,$R4
++	vmlal.u32	$D1,$H2#lo,$S4
++	vmlal.u32	$D2,$H3#lo,$S4
++
++.Lshort_tail:
++	@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
++	@ horizontal addition
++
++	vadd.i64	$D3#lo,$D3#lo,$D3#hi
++	vadd.i64	$D0#lo,$D0#lo,$D0#hi
++	vadd.i64	$D4#lo,$D4#lo,$D4#hi
++	vadd.i64	$D1#lo,$D1#lo,$D1#hi
++	vadd.i64	$D2#lo,$D2#lo,$D2#hi
++
++	@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
++	@ lazy reduction, but without narrowing
++
++	vshr.u64	$T0,$D3,#26
++	vand.i64	$D3,$D3,$MASK
++	 vshr.u64	$T1,$D0,#26
++	 vand.i64	$D0,$D0,$MASK
++	vadd.i64	$D4,$D4,$T0		@ h3 -> h4
++	 vadd.i64	$D1,$D1,$T1		@ h0 -> h1
++
++	vshr.u64	$T0,$D4,#26
++	vand.i64	$D4,$D4,$MASK
++	 vshr.u64	$T1,$D1,#26
++	 vand.i64	$D1,$D1,$MASK
++	 vadd.i64	$D2,$D2,$T1		@ h1 -> h2
++
++	vadd.i64	$D0,$D0,$T0
++	vshl.u64	$T0,$T0,#2
++	 vshr.u64	$T1,$D2,#26
++	 vand.i64	$D2,$D2,$MASK
++	vadd.i64	$D0,$D0,$T0		@ h4 -> h0
++	 vadd.i64	$D3,$D3,$T1		@ h2 -> h3
++
++	vshr.u64	$T0,$D0,#26
++	vand.i64	$D0,$D0,$MASK
++	 vshr.u64	$T1,$D3,#26
++	 vand.i64	$D3,$D3,$MASK
++	vadd.i64	$D1,$D1,$T0		@ h0 -> h1
++	 vadd.i64	$D4,$D4,$T1		@ h3 -> h4
++
++	cmp		$len,#0
++	bne		.Leven
++
++	@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
++	@ store hash value
++
++	vst4.32		{$D0#lo[0],$D1#lo[0],$D2#lo[0],$D3#lo[0]},[$ctx]!
++	vst1.32		{$D4#lo[0]},[$ctx]
++
++	vldmia	sp!,{d8-d15}			@ epilogue
++	ldmia	sp!,{r4-r7}
++.Lno_data_neon:
++	ret					@ bx	lr
++.size	poly1305_blocks_neon,.-poly1305_blocks_neon
++
++.type	poly1305_emit_neon,%function
++.align	5
++poly1305_emit_neon:
++	ldr	ip,[$ctx,#36]		@ is_base2_26
++
++	stmdb	sp!,{r4-r11}
++
++	tst	ip,ip
++	beq	.Lpoly1305_emit_enter
++
++	ldmia	$ctx,{$h0-$h4}
++	eor	$g0,$g0,$g0
++
++	adds	$h0,$h0,$h1,lsl#26	@ base 2^26 -> base 2^32
++	mov	$h1,$h1,lsr#6
++	adcs	$h1,$h1,$h2,lsl#20
++	mov	$h2,$h2,lsr#12
++	adcs	$h2,$h2,$h3,lsl#14
++	mov	$h3,$h3,lsr#18
++	adcs	$h3,$h3,$h4,lsl#8
++	adc	$h4,$g0,$h4,lsr#24	@ can be partially reduced ...
++
++	and	$g0,$h4,#-4		@ ... so reduce
++	and	$h4,$h3,#3
++	add	$g0,$g0,$g0,lsr#2	@ *= 5
++	adds	$h0,$h0,$g0
++	adcs	$h1,$h1,#0
++	adcs	$h2,$h2,#0
++	adcs	$h3,$h3,#0
++	adc	$h4,$h4,#0
++
++	adds	$g0,$h0,#5		@ compare to modulus
++	adcs	$g1,$h1,#0
++	adcs	$g2,$h2,#0
++	adcs	$g3,$h3,#0
++	adc	$g4,$h4,#0
++	tst	$g4,#4			@ did it carry/borrow?
++
++	it	ne
++	movne	$h0,$g0
++	ldr	$g0,[$nonce,#0]
++	it	ne
++	movne	$h1,$g1
++	ldr	$g1,[$nonce,#4]
++	it	ne
++	movne	$h2,$g2
++	ldr	$g2,[$nonce,#8]
++	it	ne
++	movne	$h3,$g3
++	ldr	$g3,[$nonce,#12]
++
++	adds	$h0,$h0,$g0		@ accumulate nonce
++	adcs	$h1,$h1,$g1
++	adcs	$h2,$h2,$g2
++	adc	$h3,$h3,$g3
++
++# ifdef __ARMEB__
++	rev	$h0,$h0
++	rev	$h1,$h1
++	rev	$h2,$h2
++	rev	$h3,$h3
++# endif
++	str	$h0,[$mac,#0]		@ store the result
++	str	$h1,[$mac,#4]
++	str	$h2,[$mac,#8]
++	str	$h3,[$mac,#12]
++
++	ldmia	sp!,{r4-r11}
++	ret				@ bx	lr
++.size	poly1305_emit_neon,.-poly1305_emit_neon
++
++.align	5
++.Lzeros:
++.long	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
++.LOPENSSL_armcap:
++.word	OPENSSL_armcap_P-.Lpoly1305_init
++#endif
++___
++}	}
++$code.=<<___;
++.asciz	"Poly1305 for ARMv4/NEON, CRYPTOGAMS by "
++.align	2
++#if	__ARM_MAX_ARCH__>=7
++.comm   OPENSSL_armcap_P,4,4
++#endif
++___
++
++foreach (split("\n",$code)) {
++	s/\`([^\`]*)\`/eval $1/geo;
++
++	s/\bq([0-9]+)#(lo|hi)/sprintf "d%d",2*$1+($2 eq "hi")/geo	or
++	s/\bret\b/bx	lr/go						or
++	s/\bbx\s+lr\b/.word\t0xe12fff1e/go;	# make it possible to compile with -march=armv4
++
++	print $_,"\n";
++}
++close STDOUT; # enforce flush
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/poly1305/asm/poly1305-armv8.pl b/CryptoPkg/Library/OpensslLib/openssl/crypto/poly1305/asm/poly1305-armv8.pl
+new file mode 100755
+index 0000000..607696c
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/poly1305/asm/poly1305-armv8.pl
+@@ -0,0 +1,939 @@
++#! /usr/bin/env perl
++# Copyright 2016 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
++# in the file LICENSE in the source distribution or at
++# https://www.openssl.org/source/license.html
++
++#
++# ====================================================================
++# Written by Andy Polyakov  for the OpenSSL
++# project. The module is, however, dual licensed under OpenSSL and
++# CRYPTOGAMS licenses depending on where you obtain it. For further
++# details see http://www.openssl.org/~appro/cryptogams/.
++# ====================================================================
++#
++# This module implements Poly1305 hash for ARMv8.
++#
++# June 2015
++#
++# Numbers are cycles per processed byte with poly1305_blocks alone.
++#
++#		IALU/gcc-4.9	NEON
++#
++# Apple A7	1.86/+5%	0.72
++# Cortex-A53	2.69/+58%	1.47
++# Cortex-A57	2.70/+7%	1.14
++# Denver	1.64/+50%	1.18(*)
++# X-Gene	2.13/+68%	2.27
++# Mongoose	1.77/+75%	1.12
++#
++# (*)	estimate based on resources availability is less than 1.0,
++#	i.e. measured result is worse than expected, presumably binary
++#	translator is not almighty;
++
++$flavour=shift;
++$output=shift;
++
++$0 =~ m/(.*[\/\\])[^\/\\]+$/; $dir=$1;
++( $xlate="${dir}arm-xlate.pl" and -f $xlate ) or
++( $xlate="${dir}../../perlasm/arm-xlate.pl" and -f $xlate) or
++die "can't locate arm-xlate.pl";
++
++open OUT,"| \"$^X\" $xlate $flavour $output";
++*STDOUT=*OUT;
++
++my ($ctx,$inp,$len,$padbit) = map("x$_",(0..3));
++my ($mac,$nonce)=($inp,$len);
++
++my ($h0,$h1,$h2,$r0,$r1,$s1,$t0,$t1,$d0,$d1,$d2) = map("x$_",(4..14));
++
++$code.=<<___;
++#include "arm_arch.h"
++
++.text
++
++// forward "declarations" are required for Apple
++.extern	OPENSSL_armcap_P
++.globl	poly1305_blocks
++.globl	poly1305_emit
++
++.globl	poly1305_init
++.type	poly1305_init,%function
++.align	5
++poly1305_init:
++	cmp	$inp,xzr
++	stp	xzr,xzr,[$ctx]		// zero hash value
++	stp	xzr,xzr,[$ctx,#16]	// [along with is_base2_26]
++
++	csel	x0,xzr,x0,eq
++	b.eq	.Lno_key
++
++#ifdef	__ILP32__
++	ldrsw	$t1,.LOPENSSL_armcap_P
++#else
++	ldr	$t1,.LOPENSSL_armcap_P
++#endif
++	adr	$t0,.LOPENSSL_armcap_P
++
++	ldp	$r0,$r1,[$inp]		// load key
++	mov	$s1,#0xfffffffc0fffffff
++	movk	$s1,#0x0fff,lsl#48
++	ldr	w17,[$t0,$t1]
++#ifdef	__ARMEB__
++	rev	$r0,$r0			// flip bytes
++	rev	$r1,$r1
++#endif
++	and	$r0,$r0,$s1		// &=0ffffffc0fffffff
++	and	$s1,$s1,#-4
++	and	$r1,$r1,$s1		// &=0ffffffc0ffffffc
++	stp	$r0,$r1,[$ctx,#32]	// save key value
++
++	tst	w17,#ARMV7_NEON
++
++	adr	$d0,poly1305_blocks
++	adr	$r0,poly1305_blocks_neon
++	adr	$d1,poly1305_emit
++	adr	$r1,poly1305_emit_neon
++
++	csel	$d0,$d0,$r0,eq
++	csel	$d1,$d1,$r1,eq
++
++	stp	$d0,$d1,[$len]
++
++	mov	x0,#1
++.Lno_key:
++	ret
++.size	poly1305_init,.-poly1305_init
++
++.type	poly1305_blocks,%function
++.align	5
++poly1305_blocks:
++	ands	$len,$len,#-16
++	b.eq	.Lno_data
++
++	ldp	$h0,$h1,[$ctx]		// load hash value
++	ldp	$r0,$r1,[$ctx,#32]	// load key value
++	ldr	$h2,[$ctx,#16]
++	add	$s1,$r1,$r1,lsr#2	// s1 = r1 + (r1 >> 2)
++	b	.Loop
++
++.align	5
++.Loop:
++	ldp	$t0,$t1,[$inp],#16	// load input
++	sub	$len,$len,#16
++#ifdef	__ARMEB__
++	rev	$t0,$t0
++	rev	$t1,$t1
++#endif
++	adds	$h0,$h0,$t0		// accumulate input
++	adcs	$h1,$h1,$t1
++
++	mul	$d0,$h0,$r0		// h0*r0
++	adc	$h2,$h2,$padbit
++	umulh	$d1,$h0,$r0
++
++	mul	$t0,$h1,$s1		// h1*5*r1
++	umulh	$t1,$h1,$s1
++
++	adds	$d0,$d0,$t0
++	mul	$t0,$h0,$r1		// h0*r1
++	adc	$d1,$d1,$t1
++	umulh	$d2,$h0,$r1
++
++	adds	$d1,$d1,$t0
++	mul	$t0,$h1,$r0		// h1*r0
++	adc	$d2,$d2,xzr
++	umulh	$t1,$h1,$r0
++
++	adds	$d1,$d1,$t0
++	mul	$t0,$h2,$s1		// h2*5*r1
++	adc	$d2,$d2,$t1
++	mul	$t1,$h2,$r0		// h2*r0
++
++	adds	$d1,$d1,$t0
++	adc	$d2,$d2,$t1
++
++	and	$t0,$d2,#-4		// final reduction
++	and	$h2,$d2,#3
++	add	$t0,$t0,$d2,lsr#2
++	adds	$h0,$d0,$t0
++	adcs	$h1,$d1,xzr
++	adc	$h2,$h2,xzr
++
++	cbnz	$len,.Loop
++
++	stp	$h0,$h1,[$ctx]		// store hash value
++	str	$h2,[$ctx,#16]
++
++.Lno_data:
++	ret
++.size	poly1305_blocks,.-poly1305_blocks
++
++.type	poly1305_emit,%function
++.align	5
++poly1305_emit:
++	ldp	$h0,$h1,[$ctx]		// load hash base 2^64
++	ldr	$h2,[$ctx,#16]
++	ldp	$t0,$t1,[$nonce]	// load nonce
++
++	adds	$d0,$h0,#5		// compare to modulus
++	adcs	$d1,$h1,xzr
++	adc	$d2,$h2,xzr
++
++	tst	$d2,#-4			// see if it's carried/borrowed
++
++	csel	$h0,$h0,$d0,eq
++	csel	$h1,$h1,$d1,eq
++
++#ifdef	__ARMEB__
++	ror	$t0,$t0,#32		// flip nonce words
++	ror	$t1,$t1,#32
++#endif
++	adds	$h0,$h0,$t0		// accumulate nonce
++	adc	$h1,$h1,$t1
++#ifdef	__ARMEB__
++	rev	$h0,$h0			// flip output bytes
++	rev	$h1,$h1
++#endif
++	stp	$h0,$h1,[$mac]		// write result
++
++	ret
++.size	poly1305_emit,.-poly1305_emit
++___
++my ($R0,$R1,$S1,$R2,$S2,$R3,$S3,$R4,$S4) = map("v$_.4s",(0..8));
++my ($IN01_0,$IN01_1,$IN01_2,$IN01_3,$IN01_4) = map("v$_.2s",(9..13));
++my ($IN23_0,$IN23_1,$IN23_2,$IN23_3,$IN23_4) = map("v$_.2s",(14..18));
++my ($ACC0,$ACC1,$ACC2,$ACC3,$ACC4) = map("v$_.2d",(19..23));
++my ($H0,$H1,$H2,$H3,$H4) = map("v$_.2s",(24..28));
++my ($T0,$T1,$MASK) = map("v$_",(29..31));
++
++my ($in2,$zeros)=("x16","x17");
++my $is_base2_26 = $zeros;		# borrow
++
++$code.=<<___;
++.type	poly1305_mult,%function
++.align	5
++poly1305_mult:
++	mul	$d0,$h0,$r0		// h0*r0
++	umulh	$d1,$h0,$r0
++
++	mul	$t0,$h1,$s1		// h1*5*r1
++	umulh	$t1,$h1,$s1
++
++	adds	$d0,$d0,$t0
++	mul	$t0,$h0,$r1		// h0*r1
++	adc	$d1,$d1,$t1
++	umulh	$d2,$h0,$r1
++
++	adds	$d1,$d1,$t0
++	mul	$t0,$h1,$r0		// h1*r0
++	adc	$d2,$d2,xzr
++	umulh	$t1,$h1,$r0
++
++	adds	$d1,$d1,$t0
++	mul	$t0,$h2,$s1		// h2*5*r1
++	adc	$d2,$d2,$t1
++	mul	$t1,$h2,$r0		// h2*r0
++
++	adds	$d1,$d1,$t0
++	adc	$d2,$d2,$t1
++
++	and	$t0,$d2,#-4		// final reduction
++	and	$h2,$d2,#3
++	add	$t0,$t0,$d2,lsr#2
++	adds	$h0,$d0,$t0
++	adcs	$h1,$d1,xzr
++	adc	$h2,$h2,xzr
++
++	ret
++.size	poly1305_mult,.-poly1305_mult
++
++.type	poly1305_splat,%function
++.align	5
++poly1305_splat:
++	and	x12,$h0,#0x03ffffff	// base 2^64 -> base 2^26
++	ubfx	x13,$h0,#26,#26
++	extr	x14,$h1,$h0,#52
++	and	x14,x14,#0x03ffffff
++	ubfx	x15,$h1,#14,#26
++	extr	x16,$h2,$h1,#40
++
++	str	w12,[$ctx,#16*0]	// r0
++	add	w12,w13,w13,lsl#2	// r1*5
++	str	w13,[$ctx,#16*1]	// r1
++	add	w13,w14,w14,lsl#2	// r2*5
++	str	w12,[$ctx,#16*2]	// s1
++	str	w14,[$ctx,#16*3]	// r2
++	add	w14,w15,w15,lsl#2	// r3*5
++	str	w13,[$ctx,#16*4]	// s2
++	str	w15,[$ctx,#16*5]	// r3
++	add	w15,w16,w16,lsl#2	// r4*5
++	str	w14,[$ctx,#16*6]	// s3
++	str	w16,[$ctx,#16*7]	// r4
++	str	w15,[$ctx,#16*8]	// s4
++
++	ret
++.size	poly1305_splat,.-poly1305_splat
++
++.type	poly1305_blocks_neon,%function
++.align	5
++poly1305_blocks_neon:
++	ldr	$is_base2_26,[$ctx,#24]
++	cmp	$len,#128
++	b.hs	.Lblocks_neon
++	cbz	$is_base2_26,poly1305_blocks
++
++.Lblocks_neon:
++	stp	x29,x30,[sp,#-80]!
++	add	x29,sp,#0
++
++	ands	$len,$len,#-16
++	b.eq	.Lno_data_neon
++
++	cbz	$is_base2_26,.Lbase2_64_neon
++
++	ldp	w10,w11,[$ctx]		// load hash value base 2^26
++	ldp	w12,w13,[$ctx,#8]
++	ldr	w14,[$ctx,#16]
++
++	tst	$len,#31
++	b.eq	.Leven_neon
++
++	ldp	$r0,$r1,[$ctx,#32]	// load key value
++
++	add	$h0,x10,x11,lsl#26	// base 2^26 -> base 2^64
++	lsr	$h1,x12,#12
++	adds	$h0,$h0,x12,lsl#52
++	add	$h1,$h1,x13,lsl#14
++	adc	$h1,$h1,xzr
++	lsr	$h2,x14,#24
++	adds	$h1,$h1,x14,lsl#40
++	adc	$d2,$h2,xzr		// can be partially reduced...
++
++	ldp	$d0,$d1,[$inp],#16	// load input
++	sub	$len,$len,#16
++	add	$s1,$r1,$r1,lsr#2	// s1 = r1 + (r1 >> 2)
++
++	and	$t0,$d2,#-4		// ... so reduce
++	and	$h2,$d2,#3
++	add	$t0,$t0,$d2,lsr#2
++	adds	$h0,$h0,$t0
++	adcs	$h1,$h1,xzr
++	adc	$h2,$h2,xzr
++
++#ifdef	__ARMEB__
++	rev	$d0,$d0
++	rev	$d1,$d1
++#endif
++	adds	$h0,$h0,$d0		// accumulate input
++	adcs	$h1,$h1,$d1
++	adc	$h2,$h2,$padbit
++
++	bl	poly1305_mult
++	ldr	x30,[sp,#8]
++
++	cbz	$padbit,.Lstore_base2_64_neon
++
++	and	x10,$h0,#0x03ffffff	// base 2^64 -> base 2^26
++	ubfx	x11,$h0,#26,#26
++	extr	x12,$h1,$h0,#52
++	and	x12,x12,#0x03ffffff
++	ubfx	x13,$h1,#14,#26
++	extr	x14,$h2,$h1,#40
++
++	cbnz	$len,.Leven_neon
++
++	stp	w10,w11,[$ctx]		// store hash value base 2^26
++	stp	w12,w13,[$ctx,#8]
++	str	w14,[$ctx,#16]
++	b	.Lno_data_neon
++
++.align	4
++.Lstore_base2_64_neon:
++	stp	$h0,$h1,[$ctx]		// store hash value base 2^64
++	stp	$h2,xzr,[$ctx,#16]	// note that is_base2_26 is zeroed
++	b	.Lno_data_neon
++
++.align	4
++.Lbase2_64_neon:
++	ldp	$r0,$r1,[$ctx,#32]	// load key value
++
++	ldp	$h0,$h1,[$ctx]		// load hash value base 2^64
++	ldr	$h2,[$ctx,#16]
++
++	tst	$len,#31
++	b.eq	.Linit_neon
++
++	ldp	$d0,$d1,[$inp],#16	// load input
++	sub	$len,$len,#16
++	add	$s1,$r1,$r1,lsr#2	// s1 = r1 + (r1 >> 2)
++#ifdef	__ARMEB__
++	rev	$d0,$d0
++	rev	$d1,$d1
++#endif
++	adds	$h0,$h0,$d0		// accumulate input
++	adcs	$h1,$h1,$d1
++	adc	$h2,$h2,$padbit
++
++	bl	poly1305_mult
++
++.Linit_neon:
++	and	x10,$h0,#0x03ffffff	// base 2^64 -> base 2^26
++	ubfx	x11,$h0,#26,#26
++	extr	x12,$h1,$h0,#52
++	and	x12,x12,#0x03ffffff
++	ubfx	x13,$h1,#14,#26
++	extr	x14,$h2,$h1,#40
++
++	stp	d8,d9,[sp,#16]		// meet ABI requirements
++	stp	d10,d11,[sp,#32]
++	stp	d12,d13,[sp,#48]
++	stp	d14,d15,[sp,#64]
++
++	fmov	${H0},x10
++	fmov	${H1},x11
++	fmov	${H2},x12
++	fmov	${H3},x13
++	fmov	${H4},x14
++
++	////////////////////////////////// initialize r^n table
++	mov	$h0,$r0			// r^1
++	add	$s1,$r1,$r1,lsr#2	// s1 = r1 + (r1 >> 2)
++	mov	$h1,$r1
++	mov	$h2,xzr
++	add	$ctx,$ctx,#48+12
++	bl	poly1305_splat
++
++	bl	poly1305_mult		// r^2
++	sub	$ctx,$ctx,#4
++	bl	poly1305_splat
++
++	bl	poly1305_mult		// r^3
++	sub	$ctx,$ctx,#4
++	bl	poly1305_splat
++
++	bl	poly1305_mult		// r^4
++	sub	$ctx,$ctx,#4
++	bl	poly1305_splat
++	ldr	x30,[sp,#8]
++
++	add	$in2,$inp,#32
++	adr	$zeros,.Lzeros
++	subs	$len,$len,#64
++	csel	$in2,$zeros,$in2,lo
++
++	mov	x4,#1
++	str	x4,[$ctx,#-24]		// set is_base2_26
++	sub	$ctx,$ctx,#48		// restore original $ctx
++	b	.Ldo_neon
++
++.align	4
++.Leven_neon:
++	add	$in2,$inp,#32
++	adr	$zeros,.Lzeros
++	subs	$len,$len,#64
++	csel	$in2,$zeros,$in2,lo
++
++	stp	d8,d9,[sp,#16]		// meet ABI requirements
++	stp	d10,d11,[sp,#32]
++	stp	d12,d13,[sp,#48]
++	stp	d14,d15,[sp,#64]
++
++	fmov	${H0},x10
++	fmov	${H1},x11
++	fmov	${H2},x12
++	fmov	${H3},x13
++	fmov	${H4},x14
++
++.Ldo_neon:
++	ldp	x8,x12,[$in2],#16	// inp[2:3] (or zero)
++	ldp	x9,x13,[$in2],#48
++
++	lsl	$padbit,$padbit,#24
++	add	x15,$ctx,#48
++
++#ifdef	__ARMEB__
++	rev	x8,x8
++	rev	x12,x12
++	rev	x9,x9
++	rev	x13,x13
++#endif
++	and	x4,x8,#0x03ffffff	// base 2^64 -> base 2^26
++	and	x5,x9,#0x03ffffff
++	ubfx	x6,x8,#26,#26
++	ubfx	x7,x9,#26,#26
++	add	x4,x4,x5,lsl#32		// bfi	x4,x5,#32,#32
++	extr	x8,x12,x8,#52
++	extr	x9,x13,x9,#52
++	add	x6,x6,x7,lsl#32		// bfi	x6,x7,#32,#32
++	fmov	$IN23_0,x4
++	and	x8,x8,#0x03ffffff
++	and	x9,x9,#0x03ffffff
++	ubfx	x10,x12,#14,#26
++	ubfx	x11,x13,#14,#26
++	add	x12,$padbit,x12,lsr#40
++	add	x13,$padbit,x13,lsr#40
++	add	x8,x8,x9,lsl#32		// bfi	x8,x9,#32,#32
++	fmov	$IN23_1,x6
++	add	x10,x10,x11,lsl#32	// bfi	x10,x11,#32,#32
++	add	x12,x12,x13,lsl#32	// bfi	x12,x13,#32,#32
++	fmov	$IN23_2,x8
++	fmov	$IN23_3,x10
++	fmov	$IN23_4,x12
++
++	ldp	x8,x12,[$inp],#16	// inp[0:1]
++	ldp	x9,x13,[$inp],#48
++
++	ld1	{$R0,$R1,$S1,$R2},[x15],#64
++	ld1	{$S2,$R3,$S3,$R4},[x15],#64
++	ld1	{$S4},[x15]
++
++#ifdef	__ARMEB__
++	rev	x8,x8
++	rev	x12,x12
++	rev	x9,x9
++	rev	x13,x13
++#endif
++	and	x4,x8,#0x03ffffff	// base 2^64 -> base 2^26
++	and	x5,x9,#0x03ffffff
++	ubfx	x6,x8,#26,#26
++	ubfx	x7,x9,#26,#26
++	add	x4,x4,x5,lsl#32		// bfi	x4,x5,#32,#32
++	extr	x8,x12,x8,#52
++	extr	x9,x13,x9,#52
++	add	x6,x6,x7,lsl#32		// bfi	x6,x7,#32,#32
++	fmov	$IN01_0,x4
++	and	x8,x8,#0x03ffffff
++	and	x9,x9,#0x03ffffff
++	ubfx	x10,x12,#14,#26
++	ubfx	x11,x13,#14,#26
++	add	x12,$padbit,x12,lsr#40
++	add	x13,$padbit,x13,lsr#40
++	add	x8,x8,x9,lsl#32		// bfi	x8,x9,#32,#32
++	fmov	$IN01_1,x6
++	add	x10,x10,x11,lsl#32	// bfi	x10,x11,#32,#32
++	add	x12,x12,x13,lsl#32	// bfi	x12,x13,#32,#32
++	movi	$MASK.2d,#-1
++	fmov	$IN01_2,x8
++	fmov	$IN01_3,x10
++	fmov	$IN01_4,x12
++	ushr	$MASK.2d,$MASK.2d,#38
++
++	b.ls	.Lskip_loop
++
++.align	4
++.Loop_neon:
++	////////////////////////////////////////////////////////////////
++	// ((inp[0]*r^4+inp[2]*r^2+inp[4])*r^4+inp[6]*r^2
++	// ((inp[1]*r^4+inp[3]*r^2+inp[5])*r^3+inp[7]*r
++	//   \___________________/
++	// ((inp[0]*r^4+inp[2]*r^2+inp[4])*r^4+inp[6]*r^2+inp[8])*r^2
++	// ((inp[1]*r^4+inp[3]*r^2+inp[5])*r^4+inp[7]*r^2+inp[9])*r
++	//   \___________________/ \____________________/
++	//
++	// Note that we start with inp[2:3]*r^2. This is because it
++	// doesn't depend on reduction in previous iteration.
++	////////////////////////////////////////////////////////////////
++	// d4 = h0*r4 + h1*r3   + h2*r2   + h3*r1   + h4*r0
++	// d3 = h0*r3 + h1*r2   + h2*r1   + h3*r0   + h4*5*r4
++	// d2 = h0*r2 + h1*r1   + h2*r0   + h3*5*r4 + h4*5*r3
++	// d1 = h0*r1 + h1*r0   + h2*5*r4 + h3*5*r3 + h4*5*r2
++	// d0 = h0*r0 + h1*5*r4 + h2*5*r3 + h3*5*r2 + h4*5*r1
++
++	subs	$len,$len,#64
++	umull	$ACC4,$IN23_0,${R4}[2]
++	csel	$in2,$zeros,$in2,lo
++	umull	$ACC3,$IN23_0,${R3}[2]
++	umull	$ACC2,$IN23_0,${R2}[2]
++	 ldp	x8,x12,[$in2],#16	// inp[2:3] (or zero)
++	umull	$ACC1,$IN23_0,${R1}[2]
++	 ldp	x9,x13,[$in2],#48
++	umull	$ACC0,$IN23_0,${R0}[2]
++#ifdef	__ARMEB__
++	 rev	x8,x8
++	 rev	x12,x12
++	 rev	x9,x9
++	 rev	x13,x13
++#endif
++
++	umlal	$ACC4,$IN23_1,${R3}[2]
++	 and	x4,x8,#0x03ffffff	// base 2^64 -> base 2^26
++	umlal	$ACC3,$IN23_1,${R2}[2]
++	 and	x5,x9,#0x03ffffff
++	umlal	$ACC2,$IN23_1,${R1}[2]
++	 ubfx	x6,x8,#26,#26
++	umlal	$ACC1,$IN23_1,${R0}[2]
++	 ubfx	x7,x9,#26,#26
++	umlal	$ACC0,$IN23_1,${S4}[2]
++	 add	x4,x4,x5,lsl#32		// bfi	x4,x5,#32,#32
++
++	umlal	$ACC4,$IN23_2,${R2}[2]
++	 extr	x8,x12,x8,#52
++	umlal	$ACC3,$IN23_2,${R1}[2]
++	 extr	x9,x13,x9,#52
++	umlal	$ACC2,$IN23_2,${R0}[2]
++	 add	x6,x6,x7,lsl#32		// bfi	x6,x7,#32,#32
++	umlal	$ACC1,$IN23_2,${S4}[2]
++	 fmov	$IN23_0,x4
++	umlal	$ACC0,$IN23_2,${S3}[2]
++	 and	x8,x8,#0x03ffffff
++
++	umlal	$ACC4,$IN23_3,${R1}[2]
++	 and	x9,x9,#0x03ffffff
++	umlal	$ACC3,$IN23_3,${R0}[2]
++	 ubfx	x10,x12,#14,#26
++	umlal	$ACC2,$IN23_3,${S4}[2]
++	 ubfx	x11,x13,#14,#26
++	umlal	$ACC1,$IN23_3,${S3}[2]
++	 add	x8,x8,x9,lsl#32		// bfi	x8,x9,#32,#32
++	umlal	$ACC0,$IN23_3,${S2}[2]
++	 fmov	$IN23_1,x6
++
++	add	$IN01_2,$IN01_2,$H2
++	 add	x12,$padbit,x12,lsr#40
++	umlal	$ACC4,$IN23_4,${R0}[2]
++	 add	x13,$padbit,x13,lsr#40
++	umlal	$ACC3,$IN23_4,${S4}[2]
++	 add	x10,x10,x11,lsl#32	// bfi	x10,x11,#32,#32
++	umlal	$ACC2,$IN23_4,${S3}[2]
++	 add	x12,x12,x13,lsl#32	// bfi	x12,x13,#32,#32
++	umlal	$ACC1,$IN23_4,${S2}[2]
++	 fmov	$IN23_2,x8
++	umlal	$ACC0,$IN23_4,${S1}[2]
++	 fmov	$IN23_3,x10
++
++	////////////////////////////////////////////////////////////////
++	// (hash+inp[0:1])*r^4 and accumulate
++
++	add	$IN01_0,$IN01_0,$H0
++	 fmov	$IN23_4,x12
++	umlal	$ACC3,$IN01_2,${R1}[0]
++	 ldp	x8,x12,[$inp],#16	// inp[0:1]
++	umlal	$ACC0,$IN01_2,${S3}[0]
++	 ldp	x9,x13,[$inp],#48
++	umlal	$ACC4,$IN01_2,${R2}[0]
++	umlal	$ACC1,$IN01_2,${S4}[0]
++	umlal	$ACC2,$IN01_2,${R0}[0]
++#ifdef	__ARMEB__
++	 rev	x8,x8
++	 rev	x12,x12
++	 rev	x9,x9
++	 rev	x13,x13
++#endif
++
++	add	$IN01_1,$IN01_1,$H1
++	umlal	$ACC3,$IN01_0,${R3}[0]
++	umlal	$ACC4,$IN01_0,${R4}[0]
++	 and	x4,x8,#0x03ffffff	// base 2^64 -> base 2^26
++	umlal	$ACC2,$IN01_0,${R2}[0]
++	 and	x5,x9,#0x03ffffff
++	umlal	$ACC0,$IN01_0,${R0}[0]
++	 ubfx	x6,x8,#26,#26
++	umlal	$ACC1,$IN01_0,${R1}[0]
++	 ubfx	x7,x9,#26,#26
++
++	add	$IN01_3,$IN01_3,$H3
++	 add	x4,x4,x5,lsl#32		// bfi	x4,x5,#32,#32
++	umlal	$ACC3,$IN01_1,${R2}[0]
++	 extr	x8,x12,x8,#52
++	umlal	$ACC4,$IN01_1,${R3}[0]
++	 extr	x9,x13,x9,#52
++	umlal	$ACC0,$IN01_1,${S4}[0]
++	 add	x6,x6,x7,lsl#32		// bfi	x6,x7,#32,#32
++	umlal	$ACC2,$IN01_1,${R1}[0]
++	 fmov	$IN01_0,x4
++	umlal	$ACC1,$IN01_1,${R0}[0]
++	 and	x8,x8,#0x03ffffff
++
++	add	$IN01_4,$IN01_4,$H4
++	 and	x9,x9,#0x03ffffff
++	umlal	$ACC3,$IN01_3,${R0}[0]
++	 ubfx	x10,x12,#14,#26
++	umlal	$ACC0,$IN01_3,${S2}[0]
++	 ubfx	x11,x13,#14,#26
++	umlal	$ACC4,$IN01_3,${R1}[0]
++	 add	x8,x8,x9,lsl#32		// bfi	x8,x9,#32,#32
++	umlal	$ACC1,$IN01_3,${S3}[0]
++	 fmov	$IN01_1,x6
++	umlal	$ACC2,$IN01_3,${S4}[0]
++	 add	x12,$padbit,x12,lsr#40
++
++	umlal	$ACC3,$IN01_4,${S4}[0]
++	 add	x13,$padbit,x13,lsr#40
++	umlal	$ACC0,$IN01_4,${S1}[0]
++	 add	x10,x10,x11,lsl#32	// bfi	x10,x11,#32,#32
++	umlal	$ACC4,$IN01_4,${R0}[0]
++	 add	x12,x12,x13,lsl#32	// bfi	x12,x13,#32,#32
++	umlal	$ACC1,$IN01_4,${S2}[0]
++	 fmov	$IN01_2,x8
++	umlal	$ACC2,$IN01_4,${S3}[0]
++	 fmov	$IN01_3,x10
++	 fmov	$IN01_4,x12
++
++	/////////////////////////////////////////////////////////////////
++	// lazy reduction as discussed in "NEON crypto" by D.J. Bernstein
++	// and P. Schwabe
++	//
++	// [see discussion in poly1305-armv4 module]
++
++	ushr	$T0.2d,$ACC3,#26
++	xtn	$H3,$ACC3
++	 ushr	$T1.2d,$ACC0,#26
++	 and	$ACC0,$ACC0,$MASK.2d
++	add	$ACC4,$ACC4,$T0.2d	// h3 -> h4
++	bic	$H3,#0xfc,lsl#24	// &=0x03ffffff
++	 add	$ACC1,$ACC1,$T1.2d	// h0 -> h1
++
++	ushr	$T0.2d,$ACC4,#26
++	xtn	$H4,$ACC4
++	 ushr	$T1.2d,$ACC1,#26
++	 xtn	$H1,$ACC1
++	bic	$H4,#0xfc,lsl#24
++	 add	$ACC2,$ACC2,$T1.2d	// h1 -> h2
++
++	add	$ACC0,$ACC0,$T0.2d
++	shl	$T0.2d,$T0.2d,#2
++	 shrn	$T1.2s,$ACC2,#26
++	 xtn	$H2,$ACC2
++	add	$ACC0,$ACC0,$T0.2d	// h4 -> h0
++	 bic	$H1,#0xfc,lsl#24
++	 add	$H3,$H3,$T1.2s		// h2 -> h3
++	 bic	$H2,#0xfc,lsl#24
++
++	shrn	$T0.2s,$ACC0,#26
++	xtn	$H0,$ACC0
++	 ushr	$T1.2s,$H3,#26
++	 bic	$H3,#0xfc,lsl#24
++	 bic	$H0,#0xfc,lsl#24
++	add	$H1,$H1,$T0.2s		// h0 -> h1
++	 add	$H4,$H4,$T1.2s		// h3 -> h4
++
++	b.hi	.Loop_neon
++
++.Lskip_loop:
++	dup	$IN23_2,${IN23_2}[0]
++	add	$IN01_2,$IN01_2,$H2
++
++	////////////////////////////////////////////////////////////////
++	// multiply (inp[0:1]+hash) or inp[2:3] by r^2:r^1
++
++	adds	$len,$len,#32
++	b.ne	.Long_tail
++
++	dup	$IN23_2,${IN01_2}[0]
++	add	$IN23_0,$IN01_0,$H0
++	add	$IN23_3,$IN01_3,$H3
++	add	$IN23_1,$IN01_1,$H1
++	add	$IN23_4,$IN01_4,$H4
++
++.Long_tail:
++	dup	$IN23_0,${IN23_0}[0]
++	umull2	$ACC0,$IN23_2,${S3}
++	umull2	$ACC3,$IN23_2,${R1}
++	umull2	$ACC4,$IN23_2,${R2}
++	umull2	$ACC2,$IN23_2,${R0}
++	umull2	$ACC1,$IN23_2,${S4}
++
++	dup	$IN23_1,${IN23_1}[0]
++	umlal2	$ACC0,$IN23_0,${R0}
++	umlal2	$ACC2,$IN23_0,${R2}
++	umlal2	$ACC3,$IN23_0,${R3}
++	umlal2	$ACC4,$IN23_0,${R4}
++	umlal2	$ACC1,$IN23_0,${R1}
++
++	dup	$IN23_3,${IN23_3}[0]
++	umlal2	$ACC0,$IN23_1,${S4}
++	umlal2	$ACC3,$IN23_1,${R2}
++	umlal2	$ACC2,$IN23_1,${R1}
++	umlal2	$ACC4,$IN23_1,${R3}
++	umlal2	$ACC1,$IN23_1,${R0}
++
++	dup	$IN23_4,${IN23_4}[0]
++	umlal2	$ACC3,$IN23_3,${R0}
++	umlal2	$ACC4,$IN23_3,${R1}
++	umlal2	$ACC0,$IN23_3,${S2}
++	umlal2	$ACC1,$IN23_3,${S3}
++	umlal2	$ACC2,$IN23_3,${S4}
++
++	umlal2	$ACC3,$IN23_4,${S4}
++	umlal2	$ACC0,$IN23_4,${S1}
++	umlal2	$ACC4,$IN23_4,${R0}
++	umlal2	$ACC1,$IN23_4,${S2}
++	umlal2	$ACC2,$IN23_4,${S3}
++
++	b.eq	.Lshort_tail
++
++	////////////////////////////////////////////////////////////////
++	// (hash+inp[0:1])*r^4:r^3 and accumulate
++
++	add	$IN01_0,$IN01_0,$H0
++	umlal	$ACC3,$IN01_2,${R1}
++	umlal	$ACC0,$IN01_2,${S3}
++	umlal	$ACC4,$IN01_2,${R2}
++	umlal	$ACC1,$IN01_2,${S4}
++	umlal	$ACC2,$IN01_2,${R0}
++
++	add	$IN01_1,$IN01_1,$H1
++	umlal	$ACC3,$IN01_0,${R3}
++	umlal	$ACC0,$IN01_0,${R0}
++	umlal	$ACC4,$IN01_0,${R4}
++	umlal	$ACC1,$IN01_0,${R1}
++	umlal	$ACC2,$IN01_0,${R2}
++
++	add	$IN01_3,$IN01_3,$H3
++	umlal	$ACC3,$IN01_1,${R2}
++	umlal	$ACC0,$IN01_1,${S4}
++	umlal	$ACC4,$IN01_1,${R3}
++	umlal	$ACC1,$IN01_1,${R0}
++	umlal	$ACC2,$IN01_1,${R1}
++
++	add	$IN01_4,$IN01_4,$H4
++	umlal	$ACC3,$IN01_3,${R0}
++	umlal	$ACC0,$IN01_3,${S2}
++	umlal	$ACC4,$IN01_3,${R1}
++	umlal	$ACC1,$IN01_3,${S3}
++	umlal	$ACC2,$IN01_3,${S4}
++
++	umlal	$ACC3,$IN01_4,${S4}
++	umlal	$ACC0,$IN01_4,${S1}
++	umlal	$ACC4,$IN01_4,${R0}
++	umlal	$ACC1,$IN01_4,${S2}
++	umlal	$ACC2,$IN01_4,${S3}
++
++.Lshort_tail:
++	////////////////////////////////////////////////////////////////
++	// horizontal add
++
++	addp	$ACC3,$ACC3,$ACC3
++	 ldp	d8,d9,[sp,#16]		// meet ABI requirements
++	addp	$ACC0,$ACC0,$ACC0
++	 ldp	d10,d11,[sp,#32]
++	addp	$ACC4,$ACC4,$ACC4
++	 ldp	d12,d13,[sp,#48]
++	addp	$ACC1,$ACC1,$ACC1
++	 ldp	d14,d15,[sp,#64]
++	addp	$ACC2,$ACC2,$ACC2
++
++	////////////////////////////////////////////////////////////////
++	// lazy reduction, but without narrowing
++
++	ushr	$T0.2d,$ACC3,#26
++	and	$ACC3,$ACC3,$MASK.2d
++	 ushr	$T1.2d,$ACC0,#26
++	 and	$ACC0,$ACC0,$MASK.2d
++
++	add	$ACC4,$ACC4,$T0.2d	// h3 -> h4
++	 add	$ACC1,$ACC1,$T1.2d	// h0 -> h1
++
++	ushr	$T0.2d,$ACC4,#26
++	and	$ACC4,$ACC4,$MASK.2d
++	 ushr	$T1.2d,$ACC1,#26
++	 and	$ACC1,$ACC1,$MASK.2d
++	 add	$ACC2,$ACC2,$T1.2d	// h1 -> h2
++
++	add	$ACC0,$ACC0,$T0.2d
++	shl	$T0.2d,$T0.2d,#2
++	 ushr	$T1.2d,$ACC2,#26
++	 and	$ACC2,$ACC2,$MASK.2d
++	add	$ACC0,$ACC0,$T0.2d	// h4 -> h0
++	 add	$ACC3,$ACC3,$T1.2d	// h2 -> h3
++
++	ushr	$T0.2d,$ACC0,#26
++	and	$ACC0,$ACC0,$MASK.2d
++	 ushr	$T1.2d,$ACC3,#26
++	 and	$ACC3,$ACC3,$MASK.2d
++	add	$ACC1,$ACC1,$T0.2d	// h0 -> h1
++	 add	$ACC4,$ACC4,$T1.2d	// h3 -> h4
++
++	////////////////////////////////////////////////////////////////
++	// write the result, can be partially reduced
++
++	st4	{$ACC0,$ACC1,$ACC2,$ACC3}[0],[$ctx],#16
++	st1	{$ACC4}[0],[$ctx]
++
++.Lno_data_neon:
++	ldr	x29,[sp],#80
++	ret
++.size	poly1305_blocks_neon,.-poly1305_blocks_neon
++
++.type	poly1305_emit_neon,%function
++.align	5
++poly1305_emit_neon:
++	ldr	$is_base2_26,[$ctx,#24]
++	cbz	$is_base2_26,poly1305_emit
++
++	ldp	w10,w11,[$ctx]		// load hash value base 2^26
++	ldp	w12,w13,[$ctx,#8]
++	ldr	w14,[$ctx,#16]
++
++	add	$h0,x10,x11,lsl#26	// base 2^26 -> base 2^64
++	lsr	$h1,x12,#12
++	adds	$h0,$h0,x12,lsl#52
++	add	$h1,$h1,x13,lsl#14
++	adc	$h1,$h1,xzr
++	lsr	$h2,x14,#24
++	adds	$h1,$h1,x14,lsl#40
++	adc	$h2,$h2,xzr		// can be partially reduced...
++
++	ldp	$t0,$t1,[$nonce]	// load nonce
++
++	and	$d0,$h2,#-4		// ... so reduce
++	add	$d0,$d0,$h2,lsr#2
++	and	$h2,$h2,#3
++	adds	$h0,$h0,$d0
++	adcs	$h1,$h1,xzr
++	adc	$h2,$h2,xzr
++
++	adds	$d0,$h0,#5		// compare to modulus
++	adcs	$d1,$h1,xzr
++	adc	$d2,$h2,xzr
++
++	tst	$d2,#-4			// see if it's carried/borrowed
++
++	csel	$h0,$h0,$d0,eq
++	csel	$h1,$h1,$d1,eq
++
++#ifdef	__ARMEB__
++	ror	$t0,$t0,#32		// flip nonce words
++	ror	$t1,$t1,#32
++#endif
++	adds	$h0,$h0,$t0		// accumulate nonce
++	adc	$h1,$h1,$t1
++#ifdef	__ARMEB__
++	rev	$h0,$h0			// flip output bytes
++	rev	$h1,$h1
++#endif
++	stp	$h0,$h1,[$mac]		// write result
++
++	ret
++.size	poly1305_emit_neon,.-poly1305_emit_neon
++
++.align	5
++.Lzeros:
++.long	0,0,0,0,0,0,0,0
++.LOPENSSL_armcap_P:
++#ifdef	__ILP32__
++.long	OPENSSL_armcap_P-.
++#else
++.quad	OPENSSL_armcap_P-.
++#endif
++.asciz	"Poly1305 for ARMv8, CRYPTOGAMS by "
++.align	2
++___
++
++foreach (split("\n",$code)) {
++	s/\b(shrn\s+v[0-9]+)\.[24]d/$1.2s/			or
++	s/\b(fmov\s+)v([0-9]+)[^,]*,\s*x([0-9]+)/$1d$2,x$3/	or
++	(m/\bdup\b/ and (s/\.[24]s/.2d/g or 1))			or
++	(m/\b(eor|and)/ and (s/\.[248][sdh]/.16b/g or 1))	or
++	(m/\bum(ul|la)l\b/ and (s/\.4s/.2s/g or 1))		or
++	(m/\bum(ul|la)l2\b/ and (s/\.2s/.4s/g or 1))		or
++	(m/\bst[1-4]\s+{[^}]+}\[/ and (s/\.[24]d/.s/g or 1));
++
++	s/\.[124]([sd])\[/.$1\[/;
++
++	print $_,"\n";
++}
++close STDOUT;
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/poly1305/asm/poly1305-c64xplus.pl b/CryptoPkg/Library/OpensslLib/openssl/crypto/poly1305/asm/poly1305-c64xplus.pl
+new file mode 100755
+index 0000000..93fef37
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/poly1305/asm/poly1305-c64xplus.pl
+@@ -0,0 +1,331 @@
++#! /usr/bin/env perl
++# Copyright 2016 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
++# in the file LICENSE in the source distribution or at
++# https://www.openssl.org/source/license.html
++
++#
++# ====================================================================
++# Written by Andy Polyakov  for the OpenSSL
++# project. The module is, however, dual licensed under OpenSSL and
++# CRYPTOGAMS licenses depending on where you obtain it. For further
++# details see http://www.openssl.org/~appro/cryptogams/.
++# ====================================================================
++#
++# Poly1305 hash for C64x+.
++#
++# October 2015
++#
++# Performance is [incredible for a 32-bit processor] 1.82 cycles per
++# processed byte. Comparison to compiler-generated code is problematic,
++# because results were observed to vary from 2.1 to 7.6 cpb depending
++# on compiler's ability to inline small functions. Compiler also
++# disables interrupts for some reason, thus making interrupt response
++# time dependent on input length. This module on the other hand is free
++# from such limitation.
++
++$output=pop;
++open STDOUT,">$output";
++
++($CTXA,$INPB,$LEN,$PADBIT)=("A4","B4","A6","B6");
++($H0,$H1,$H2,$H3,$H4,$H4a)=("A8","B8","A10","B10","B2",$LEN);
++($D0,$D1,$D2,$D3)=         ("A9","B9","A11","B11");
++($R0,$R1,$R2,$R3,$S1,$S2,$S3,$S3b)=("A0","B0","A1","B1","A12","B12","A13","B13");
++($THREE,$R0b,$S2a)=("B7","B5","A5");
++
++$code.=<<___;
++	.text
++
++	.if	.ASSEMBLER_VERSION<7000000
++	.asg	0,__TI_EABI__
++	.endif
++	.if	__TI_EABI__
++	.asg	poly1305_init,_poly1305_init
++	.asg	poly1305_blocks,_poly1305_blocks
++	.asg	poly1305_emit,_poly1305_emit
++	.endif
++
++	.asg	B3,RA
++	.asg	A15,FP
++	.asg	B15,SP
++
++	.if	.LITTLE_ENDIAN
++	.asg	MV,SWAP2
++	.asg	MV.L,SWAP4
++	.endif
++
++	.global	_poly1305_init
++_poly1305_init:
++	.asmfunc
++	LDNDW	*${INPB}[0],B17:B16	; load key material
++	LDNDW	*${INPB}[1],A17:A16
++
++||	ZERO	B9:B8
++||	MVK	-1,B0
++	STDW	B9:B8,*${CTXA}[0]	; initialize h1:h0
++||	SHRU	B0,4,B0			; 0x0fffffff
++||	MVK	-4,B1
++	STDW	B9:B8,*${CTXA}[1]	; initialize h3:h2
++||	AND	B0,B1,B1		; 0x0ffffffc
++	STW	B8,*${CTXA}[4]		; initialize h4
++
++	.if	.BIG_ENDIAN
++	SWAP2	B16,B17
++||	SWAP2	B17,B16
++	SWAP2	A16,A17
++||	SWAP2	A17,A16
++	SWAP4	B16,B16
++||	SWAP4	A16,A16
++	SWAP4	B17,B17
++||	SWAP4	A17,A17
++	.endif
++
++	AND	B16,B0,B20		; r0 = key[0] & 0x0fffffff
++||	AND	B17,B1,B22		; r1 = key[1] & 0x0ffffffc
++||	EXTU	B17,4,6,B16		; r1>>2
++	AND	A16,B1,B21		; r2 = key[2] & 0x0ffffffc
++||	AND	A17,B1,A23		; r3 = key[3] & 0x0ffffffc
++||	BNOP	RA
++	SHRU	B21,2,B18
++||	ADD	B22,B16,B16		; s1 = r1 + r1>>2
++
++	STDW	B21:B20,*${CTXA}[3]	; save r2:r0
++||	ADD	B21,B18,B18		; s2 = r2 + r2>>2
++||	SHRU	A23,2,B17
++||	MV	A23,B23
++	STDW	B23:B22,*${CTXA}[4]	; save r3:r1
++||	ADD	B23,B17,B19		; s3 = r3 + r3>>2
++||	ADD	B23,B17,B17		; s3 = r3 + r3>>2
++	STDW	B17:B16,*${CTXA}[5]	; save s3:s1
++	STDW	B19:B18,*${CTXA}[6]	; save s3:s2
++||	ZERO	A4			; return 0
++	.endasmfunc
++
++	.global	_poly1305_blocks
++	.align	32
++_poly1305_blocks:
++	.asmfunc	stack_usage(40)
++	SHRU	$LEN,4,A2		; A2 is loop counter, number of blocks
++  [!A2]	BNOP	RA			; no data
++|| [A2]	STW	FP,*SP--(40)		; save frame pointer and alloca(40)
++|| [A2]	MV	SP,FP
++   [A2]	STDW	B13:B12,*SP[4]		; ABI says so
++|| [A2]	MV	$CTXA,$S3b		; borrow $S3b
++   [A2]	STDW	B11:B10,*SP[3]
++|| [A2]	STDW	A13:A12,*FP[-3]
++   [A2]	STDW	A11:A10,*FP[-4]
++
++|| [A2]	LDDW	*${S3b}[0],B25:B24	; load h1:h0
++   [A2]	LDNW	*${INPB}++[4],$D0	; load inp[0]
++   [A2]	LDNW	*${INPB}[-3],$D1	; load inp[1]
++
++	LDDW	*${CTXA}[1],B29:B28	; load h3:h2, B28 is h2
++	LDNW	*${INPB}[-2],$D2	; load inp[2]
++	LDNW	*${INPB}[-1],$D3	; load inp[3]
++
++	LDDW	*${CTXA}[3],$R2:$R0	; load r2:r0
++||	LDDW	*${S3b}[4],$R3:$R1	; load r3:r1
++||	SWAP2	$D0,$D0
++
++	LDDW	*${CTXA}[5],$S3:$S1	; load s3:s1
++||	LDDW	*${S3b}[6],$S3b:$S2	; load s3:s2
++||	SWAP4	$D0,$D0
++||	SWAP2	$D1,$D1
++
++	ADDU	$D0,B24,$D0:$H0		; h0+=inp[0]
++||	ADD	$D0,B24,B27		; B-copy of h0+inp[0]
++||	SWAP4	$D1,$D1
++	ADDU	$D1,B25,$D1:$H1		; h1+=inp[1]
++||	MVK	3,$THREE
++||	SWAP2	$D2,$D2
++	LDW	*${CTXA}[4],$H4		; load h4
++||	SWAP4	$D2,$D2
++||	MV	B29,B30			; B30 is h3
++	MV	$R0,$R0b
++
++loop?:
++	MPY32U	$H0,$R0,A17:A16
++||	MPY32U	B27,$R1,B17:B16		; MPY32U	$H0,$R1,B17:B16
++||	ADDU	$D0,$D1:$H1,B25:B24	; ADDU		$D0,$D1:$H1,$D1:$H1
++||	ADDU	$D2,B28,$D2:$H2		; h2+=inp[2]
++||	SWAP2	$D3,$D3
++	MPY32U	$H0,$R2,A19:A18
++||	MPY32U	B27,$R3,B19:B18		; MPY32U	$H0,$R3,B19:B18
++||	ADD	$D0,$H1,A24		; A-copy of B24
++||	SWAP4	$D3,$D3
++|| [A2]	SUB	A2,1,A2			; decrement loop counter
++
++	MPY32U	A24,$S3,A21:A20		; MPY32U	$H1,$S3,A21:A20
++||	MPY32U	B24,$R0b,B21:B20	; MPY32U	$H1,$R0,B21:B20
++||	ADDU	B25,$D2:$H2,$D2:$H2	; ADDU		$D1,$D2:$H2,$D2:$H2
++||	ADDU	$D3,B30,$D3:$H3		; h3+=inp[3]
++||	ADD	B25,$H2,B25		; B-copy of $H2
++	MPY32U	A24,$R1,A23:A22		; MPY32U	$H1,$R1,A23:A22
++||	MPY32U	B24,$R2,B23:B22		; MPY32U	$H1,$R2,B23:B22
++
++	MPY32U	$H2,$S2,A25:A24
++||	MPY32U	B25,$S3b,B25:B24	; MPY32U	$H2,$S3,B25:B24
++||	ADDU	$D2,$D3:$H3,$D3:$H3
++||	ADD	$PADBIT,$H4,$H4		; h4+=padbit
++	MPY32U	$H2,$R0,A27:A26
++||	MPY32U	$H2,$R1,B27:B26
++||	ADD	$D3,$H4,$H4
++||	MV	$S2,$S2a
++
++	MPY32U	$H3,$S1,A29:A28
++||	MPY32U	$H3,$S2,B29:B28
++||	ADD	A21,A17,A21		; start accumulating "d3:d0"
++||	ADD	B21,B17,B21
++||	ADDU	A20,A16,A17:A16
++||	ADDU	B20,B16,B17:B16
++|| [A2]	LDNW	*${INPB}++[4],$D0	; load inp[0]
++	MPY32U	$H3,$S3,A31:A30
++||	MPY32U	$H3,$R0b,B31:B30
++||	ADD	A23,A19,A23
++||	ADD	B23,B19,B23
++||	ADDU	A22,A18,A19:A18
++||	ADDU	B22,B18,B19:B18
++|| [A2]	LDNW	*${INPB}[-3],$D1	; load inp[1]
++
++	MPY32	$H4,$S1,B20
++||	MPY32	$H4,$S2a,A20
++||	ADD	A25,A21,A21
++||	ADD	B25,B21,B21
++||	ADDU	A24,A17:A16,A17:A16
++||	ADDU	B24,B17:B16,B17:B16
++|| [A2]	LDNW	*${INPB}[-2],$D2	; load inp[2]
++	MPY32	$H4,$S3b,B22
++||	ADD	A27,A23,A23
++||	ADD	B27,B23,B23
++||	ADDU	A26,A19:A18,A19:A18
++||	ADDU	B26,B19:B18,B19:B18
++|| [A2]	LDNW	*${INPB}[-1],$D3	; load inp[3]
++
++	MPY32	$H4,$R0b,$H4
++||	ADD	A29,A21,A21		; final hi("d0")
++||	ADD	B29,B21,B21		; final hi("d1")
++||	ADDU	A28,A17:A16,A17:A16	; final lo("d0")
++||	ADDU	B28,B17:B16,B17:B16
++	ADD	A31,A23,A23		; final hi("d2")
++||	ADD	B31,B23,B23		; final hi("d3")
++||	ADDU	A30,A19:A18,A19:A18
++||	ADDU	B30,B19:B18,B19:B18
++	ADDU	B20,B17:B16,B17:B16	; final lo("d1")
++||	ADDU	A20,A19:A18,A19:A18	; final lo("d2")
++	ADDU	B22,B19:B18,B19:B18	; final lo("d3")
++
++||	ADD	A17,A21,A21		; "flatten" "d3:d0"
++	MV	A19,B29			; move to avoid cross-path stalls
++	ADDU	A21,B17:B16,B27:B26	; B26 is h1
++	ADD	B21,B27,B27
++||	DMV	B29,A18,B29:B28		; move to avoid cross-path stalls
++	ADDU	B27,B29:B28,B29:B28	; B28 is h2
++|| [A2]	SWAP2	$D0,$D0
++	ADD	A23,B29,B29
++|| [A2]	SWAP4	$D0,$D0
++	ADDU	B29,B19:B18,B31:B30	; B30 is h3
++	ADD	B23,B31,B31
++||	MV	A16,B24			; B24 is h0
++|| [A2]	SWAP2	$D1,$D1
++	ADD	B31,$H4,$H4
++|| [A2]	SWAP4	$D1,$D1
++
++	SHRU	$H4,2,B16		; last reduction step
++||	AND	$H4,$THREE,$H4
++	ADDAW	B16,B16,B16		; 5*(h4>>2)
++|| [A2]	BNOP	loop?
++
++	ADDU	B24,B16,B25:B24		; B24 is h0
++|| [A2]	SWAP2	$D2,$D2
++	ADDU	B26,B25,B27:B26		; B26 is h1
++|| [A2]	SWAP4	$D2,$D2
++	ADDU	B28,B27,B29:B28		; B28 is h2
++|| [A2]	ADDU	$D0,B24,$D0:$H0		; h0+=inp[0]
++|| [A2]	ADD	$D0,B24,B27		; B-copy of h0+inp[0]
++	ADDU	B30,B29,B31:B30		; B30 is h3
++	ADD	B31,$H4,$H4
++|| [A2]	ADDU	$D1,B26,$D1:$H1		; h1+=inp[1]
++;;===== branch to loop? is taken here
++
++	LDDW	*FP[-4],A11:A10		; ABI says so
++	LDDW	*FP[-3],A13:A12
++||	LDDW	*SP[3],B11:B10
++	LDDW	*SP[4],B13:B12
++||	MV	B26,B25
++||	BNOP	RA
++	LDW	*++SP(40),FP		; restore frame pointer
++||	MV	B30,B29
++	STDW	B25:B24,*${CTXA}[0]	; save h1:h0
++	STDW	B29:B28,*${CTXA}[1]	; save h3:h2
++	STW	$H4,*${CTXA}[4]		; save h4
++	NOP	1
++	.endasmfunc
++___
++{
++my ($MAC,$NONCEA,$NONCEB)=($INPB,$LEN,$PADBIT);
++
++$code.=<<___;
++	.global	_poly1305_emit
++	.align	32
++_poly1305_emit:
++	.asmfunc
++	LDDW	*${CTXA}[0],A17:A16	; load h1:h0
++	LDDW	*${CTXA}[1],A19:A18	; load h3:h2
++	LDW	*${CTXA}[4],A20		; load h4
++	MV	$NONCEA,$NONCEB
++
++	MVK	5,A22			; compare to modulus
++	ADDU	A16,A22,A23:A22
++||	LDW	*${NONCEA}[0],A8
++||	LDW	*${NONCEB}[1],B8
++	ADDU	A17,A23,A25:A24
++||	LDW	*${NONCEA}[2],A9
++||	LDW	*${NONCEB}[3],B9
++	ADDU	A19,A25,A27:A26
++	ADDU	A19,A27,A29:A28
++	ADD	A20,A29,A29
++
++	SHRU	A29,2,A2		; check for overflow in 130-th bit
++
++   [A2]	MV	A22,A16			; select
++|| [A2]	MV	A24,A17
++   [A2]	MV	A26,A18
++|| [A2]	MV	A28,A19
++
++||	ADDU	A8,A16,A23:A22		; accumulate nonce
++	ADDU	B8,A17,A25:A24
++||	SWAP2	A22,A22
++	ADDU	A23,A25:A24,A25:A24
++	ADDU	A9,A18,A27:A26
++||	SWAP2	A24,A24
++	ADDU	A25,A27:A26,A27:A26
++||	ADD	B9,A19,A28
++	ADD	A27,A28,A28
++||	SWAP2	A26,A26
++
++	.if	.BIG_ENDIAN
++	SWAP2	A28,A28
++||	SWAP4	A22,A22
++||	SWAP4	A24,B24
++	SWAP4	A26,A26
++	SWAP4	A28,A28
++||	MV	B24,A24
++	.endif
++
++	BNOP	RA,1
++	STNW	A22,*${MAC}[0]		; write the result
++	STNW	A24,*${MAC}[1]
++	STNW	A26,*${MAC}[2]
++	STNW	A28,*${MAC}[3]
++	.endasmfunc
++___
++}
++$code.=<<___;
++	.sect	.const
++	.cstring "Poly1305 for C64x+, CRYPTOGAMS by "
++	.align	4
++___
++
++print $code;
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/poly1305/asm/poly1305-mips.pl b/CryptoPkg/Library/OpensslLib/openssl/crypto/poly1305/asm/poly1305-mips.pl
+new file mode 100755
+index 0000000..d2b3e90
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/poly1305/asm/poly1305-mips.pl
+@@ -0,0 +1,425 @@
++#! /usr/bin/env perl
++# Copyright 2016 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
++# in the file LICENSE in the source distribution or at
++# https://www.openssl.org/source/license.html
++
++
++# ====================================================================
++# Written by Andy Polyakov  for the OpenSSL
++# project. The module is, however, dual licensed under OpenSSL and
++# CRYPTOGAMS licenses depending on where you obtain it. For further
++# details see http://www.openssl.org/~appro/cryptogams/.
++# ====================================================================
++
++# Poly1305 hash for MIPS64.
++#
++# May 2016
++#
++# Numbers are cycles per processed byte with poly1305_blocks alone.
++#
++#		IALU/gcc
++# R1x000	5.64/+120%	(big-endian)
++# Octeon II	3.80/+280%	(little-endian)
++
++######################################################################
++# There is a number of MIPS ABI in use, O32 and N32/64 are most
++# widely used. Then there is a new contender: NUBI. It appears that if
++# one picks the latter, it's possible to arrange code in ABI neutral
++# manner. Therefore let's stick to NUBI register layout:
++#
++($zero,$at,$t0,$t1,$t2)=map("\$$_",(0..2,24,25));
++($a0,$a1,$a2,$a3,$a4,$a5,$a6,$a7)=map("\$$_",(4..11));
++($s0,$s1,$s2,$s3,$s4,$s5,$s6,$s7,$s8,$s9,$s10,$s11)=map("\$$_",(12..23));
++($gp,$tp,$sp,$fp,$ra)=map("\$$_",(3,28..31));
++#
++# The return value is placed in $a0. Following coding rules facilitate
++# interoperability:
++#
++# - never ever touch $tp, "thread pointer", former $gp [o32 can be
++#   excluded from the rule, because it's specified volatile];
++# - copy return value to $t0, former $v0 [or to $a0 if you're adapting
++#   old code];
++# - on O32 populate $a4-$a7 with 'lw $aN,4*N($sp)' if necessary;
++#
++# For reference here is register layout for N32/64 MIPS ABIs:
++#
++# ($zero,$at,$v0,$v1)=map("\$$_",(0..3));
++# ($a0,$a1,$a2,$a3,$a4,$a5,$a6,$a7)=map("\$$_",(4..11));
++# ($t0,$t1,$t2,$t3,$t8,$t9)=map("\$$_",(12..15,24,25));
++# ($s0,$s1,$s2,$s3,$s4,$s5,$s6,$s7)=map("\$$_",(16..23));
++# ($gp,$sp,$fp,$ra)=map("\$$_",(28..31));
++#
++# 
++#
++######################################################################
++
++$flavour = shift || "o32"; # supported flavours are o32,n32,64,nubi32,nubi64
++
++die "MIPS64 only" unless ($flavour =~ /64|n32/i);
++
++$v0 = ($flavour =~ /nubi/i) ? $a0 : $t0;
++$SAVED_REGS_MASK = ($flavour =~ /nubi/i) ? "0x0003f000" : "0x00030000";
++
++($ctx,$inp,$len,$padbit) = ($a0,$a1,$a2,$a3);
++($in0,$in1,$tmp0,$tmp1,$tmp2,$tmp3,$tmp4) = ($a4,$a5,$a6,$a7,$at,$t0,$t1);
++
++$code.=<<___;
++#ifdef MIPSEB
++# define MSB 0
++# define LSB 7
++#else
++# define MSB 7
++# define LSB 0
++#endif
++
++.text
++.set	noat
++.set	noreorder
++
++.align	5
++.globl	poly1305_init
++.ent	poly1305_init
++poly1305_init:
++	.frame	$sp,0,$ra
++	.set	reorder
++
++	sd	$zero,0($ctx)
++	sd	$zero,8($ctx)
++	sd	$zero,16($ctx)
++
++	beqz	$inp,.Lno_key
++
++	ldl	$in0,0+MSB($inp)
++	ldl	$in1,8+MSB($inp)
++	ldr	$in0,0+LSB($inp)
++	ldr	$in1,8+LSB($inp)
++#ifdef	MIPSEB
++# if defined(_MIPS_ARCH_MIPS64R2)
++	dsbh	$in0,$in0		# byte swap
++	 dsbh	$in1,$in1
++	dshd	$in0,$in0
++	 dshd	$in1,$in1
++# else
++	ori	$tmp0,$zero,0xFF
++	dsll	$tmp2,$tmp0,32
++	or	$tmp0,$tmp2		# 0x000000FF000000FF
++
++	and	$tmp1,$in0,$tmp0	# byte swap
++	 and	$tmp3,$in1,$tmp0
++	dsrl	$tmp2,$in0,24
++	 dsrl	$tmp4,$in1,24
++	dsll	$tmp1,24
++	 dsll	$tmp3,24
++	and	$tmp2,$tmp0
++	 and	$tmp4,$tmp0
++	dsll	$tmp0,8			# 0x0000FF000000FF00
++	or	$tmp1,$tmp2
++	 or	$tmp3,$tmp4
++	and	$tmp2,$in0,$tmp0
++	 and	$tmp4,$in1,$tmp0
++	dsrl	$in0,8
++	 dsrl	$in1,8
++	dsll	$tmp2,8
++	 dsll	$tmp4,8
++	and	$in0,$tmp0
++	 and	$in1,$tmp0
++	or	$tmp1,$tmp2
++	 or	$tmp3,$tmp4
++	or	$in0,$tmp1
++	 or	$in1,$tmp3
++	dsrl	$tmp1,$in0,32
++	 dsrl	$tmp3,$in1,32
++	dsll	$in0,32
++	 dsll	$in1,32
++	or	$in0,$tmp1
++	 or	$in1,$tmp3
++# endif
++#endif
++	li	$tmp0,1
++	dsll	$tmp0,32
++	daddiu	$tmp0,-63
++	dsll	$tmp0,28
++	daddiu	$tmp0,-1		# 0ffffffc0fffffff
++
++	and	$in0,$tmp0
++	daddiu	$tmp0,-3		# 0ffffffc0ffffffc
++	and	$in1,$tmp0
++
++	sd	$in0,24($ctx)
++	dsrl	$tmp0,$in1,2
++	sd	$in1,32($ctx)
++	daddu	$tmp0,$in1		# s1 = r1 + (r1 >> 2)
++	sd	$tmp0,40($ctx)
++
++.Lno_key:
++	li	$v0,0			# return 0
++	jr	$ra
++.end	poly1305_init
++___
++{
++my ($h0,$h1,$h2,$r0,$r1,$s1,$d0,$d1,$d2) =
++   ($s0,$s1,$s2,$s3,$s4,$s5,$in0,$in1,$t2);
++
++$code.=<<___;
++.align	5
++.globl	poly1305_blocks
++.ent	poly1305_blocks
++poly1305_blocks:
++	.set	noreorder
++	dsrl	$len,4			# number of complete blocks
++	bnez	$len,poly1305_blocks_internal
++	nop
++	jr	$ra
++	nop
++.end	poly1305_blocks
++
++.align	5
++.ent	poly1305_blocks_internal
++poly1305_blocks_internal:
++	.frame	$sp,6*8,$ra
++	.mask	$SAVED_REGS_MASK,-8
++	.set	noreorder
++	dsub	$sp,6*8
++	sd	$s5,40($sp)
++	sd	$s4,32($sp)
++___
++$code.=<<___ if ($flavour =~ /nubi/i);	# optimize non-nubi prologue
++	sd	$s3,24($sp)
++	sd	$s2,16($sp)
++	sd	$s1,8($sp)
++	sd	$s0,0($sp)
++___
++$code.=<<___;
++	.set	reorder
++
++	ld	$h0,0($ctx)		# load hash value
++	ld	$h1,8($ctx)
++	ld	$h2,16($ctx)
++
++	ld	$r0,24($ctx)		# load key
++	ld	$r1,32($ctx)
++	ld	$s1,40($ctx)
++
++.Loop:
++	ldl	$in0,0+MSB($inp)	# load input
++	ldl	$in1,8+MSB($inp)
++	ldr	$in0,0+LSB($inp)
++	daddiu	$len,-1
++	ldr	$in1,8+LSB($inp)
++	daddiu	$inp,16
++#ifdef	MIPSEB
++# if defined(_MIPS_ARCH_MIPS64R2)
++	dsbh	$in0,$in0		# byte swap
++	 dsbh	$in1,$in1
++	dshd	$in0,$in0
++	 dshd	$in1,$in1
++# else
++	ori	$tmp0,$zero,0xFF
++	dsll	$tmp2,$tmp0,32
++	or	$tmp0,$tmp2		# 0x000000FF000000FF
++
++	and	$tmp1,$in0,$tmp0	# byte swap
++	 and	$tmp3,$in1,$tmp0
++	dsrl	$tmp2,$in0,24
++	 dsrl	$tmp4,$in1,24
++	dsll	$tmp1,24
++	 dsll	$tmp3,24
++	and	$tmp2,$tmp0
++	 and	$tmp4,$tmp0
++	dsll	$tmp0,8			# 0x0000FF000000FF00
++	or	$tmp1,$tmp2
++	 or	$tmp3,$tmp4
++	and	$tmp2,$in0,$tmp0
++	 and	$tmp4,$in1,$tmp0
++	dsrl	$in0,8
++	 dsrl	$in1,8
++	dsll	$tmp2,8
++	 dsll	$tmp4,8
++	and	$in0,$tmp0
++	 and	$in1,$tmp0
++	or	$tmp1,$tmp2
++	 or	$tmp3,$tmp4
++	or	$in0,$tmp1
++	 or	$in1,$tmp3
++	dsrl	$tmp1,$in0,32
++	 dsrl	$tmp3,$in1,32
++	dsll	$in0,32
++	 dsll	$in1,32
++	or	$in0,$tmp1
++	 or	$in1,$tmp3
++# endif
++#endif
++	daddu	$h0,$in0		# accumulate input
++	daddu	$h1,$in1
++	sltu	$tmp0,$h0,$in0
++	sltu	$tmp1,$h1,$in1
++	daddu	$h1,$tmp0
++
++	dmultu	$r0,$h0			# h0*r0
++	 daddu	$h2,$padbit
++	 sltu	$tmp0,$h1,$tmp0
++	mflo	$d0
++	mfhi	$d1
++
++	dmultu	$s1,$h1			# h1*5*r1
++	 daddu	$tmp0,$tmp1
++	 daddu	$h2,$tmp0
++	mflo	$tmp0
++	mfhi	$tmp1
++
++	dmultu	$r1,$h0			# h0*r1
++	 daddu	$d0,$tmp0
++	 daddu	$d1,$tmp1
++	mflo	$tmp2
++	mfhi	$d2
++	 sltu	$tmp0,$d0,$tmp0
++	 daddu	$d1,$tmp0
++
++	dmultu	$r0,$h1			# h1*r0
++	 daddu	$d1,$tmp2
++	 sltu	$tmp2,$d1,$tmp2
++	mflo	$tmp0
++	mfhi	$tmp1
++	 daddu	$d2,$tmp2
++
++	dmultu	$s1,$h2			# h2*5*r1
++	 daddu	$d1,$tmp0
++	 daddu	$d2,$tmp1
++	mflo	$tmp2
++
++	dmultu	$r0,$h2			# h2*r0
++	 sltu	$tmp0,$d1,$tmp0
++	 daddu	$d2,$tmp0
++	mflo	$tmp3
++
++	daddu	$d1,$tmp2
++	daddu	$d2,$tmp3
++	sltu	$tmp2,$d1,$tmp2
++	daddu	$d2,$tmp2
++
++	li	$tmp0,-4		# final reduction
++	and	$tmp0,$d2
++	dsrl	$tmp1,$d2,2
++	andi	$h2,$d2,3
++	daddu	$tmp0,$tmp1
++	daddu	$h0,$d0,$tmp0
++	sltu	$tmp0,$h0,$tmp0
++	daddu	$h1,$d1,$tmp0
++	sltu	$tmp0,$h1,$tmp0
++	daddu	$h2,$h2,$tmp0
++
++	bnez	$len,.Loop
++
++	sd	$h0,0($ctx)		# store hash value
++	sd	$h1,8($ctx)
++	sd	$h2,16($ctx)
++
++	.set	noreorder
++	ld	$s5,40($sp)		# epilogue
++	ld	$s4,32($sp)
++___
++$code.=<<___ if ($flavour =~ /nubi/i);	# optimize non-nubi epilogue
++	ld	$s3,24($sp)
++	ld	$s2,16($sp)
++	ld	$s1,8($sp)
++	ld	$s0,0($sp)
++___
++$code.=<<___;
++	jr	$ra
++	dadd	$sp,6*8
++.end	poly1305_blocks_internal
++___
++}
++{
++my ($ctx,$mac,$nonce) = ($a0,$a1,$a2);
++
++$code.=<<___;
++.align	5
++.globl	poly1305_emit
++.ent	poly1305_emit
++poly1305_emit:
++	.frame	$sp,0,$ra
++	.set	reorder
++
++	ld	$tmp0,0($ctx)
++	ld	$tmp1,8($ctx)
++	ld	$tmp2,16($ctx)
++
++	daddiu	$in0,$tmp0,5		# compare to modulus
++	sltiu	$tmp3,$in0,5
++	daddu	$in1,$tmp1,$tmp3
++	sltu	$tmp3,$in1,$tmp3
++	daddu	$tmp2,$tmp2,$tmp3
++
++	dsrl	$tmp2,2			# see if it carried/borrowed
++	dsubu	$tmp2,$zero,$tmp2
++	nor	$tmp3,$zero,$tmp2
++
++	and	$in0,$tmp2
++	and	$tmp0,$tmp3
++	and	$in1,$tmp2
++	and	$tmp1,$tmp3
++	or	$in0,$tmp0
++	or	$in1,$tmp1
++
++	lwu	$tmp0,0($nonce)		# load nonce
++	lwu	$tmp1,4($nonce)
++	lwu	$tmp2,8($nonce)
++	lwu	$tmp3,12($nonce)
++	dsll	$tmp1,32
++	dsll	$tmp3,32
++	or	$tmp0,$tmp1
++	or	$tmp2,$tmp3
++
++	daddu	$in0,$tmp0		# accumulate nonce
++	daddu	$in1,$tmp2
++	sltu	$tmp0,$in0,$tmp0
++	daddu	$in1,$tmp0
++
++	dsrl	$tmp0,$in0,8		# write mac value
++	dsrl	$tmp1,$in0,16
++	dsrl	$tmp2,$in0,24
++	sb	$in0,0($mac)
++	dsrl	$tmp3,$in0,32
++	sb	$tmp0,1($mac)
++	dsrl	$tmp0,$in0,40
++	sb	$tmp1,2($mac)
++	dsrl	$tmp1,$in0,48
++	sb	$tmp2,3($mac)
++	dsrl	$tmp2,$in0,56
++	sb	$tmp3,4($mac)
++	dsrl	$tmp3,$in1,8
++	sb	$tmp0,5($mac)
++	dsrl	$tmp0,$in1,16
++	sb	$tmp1,6($mac)
++	dsrl	$tmp1,$in1,24
++	sb	$tmp2,7($mac)
++
++	sb	$in1,8($mac)
++	dsrl	$tmp2,$in1,32
++	sb	$tmp3,9($mac)
++	dsrl	$tmp3,$in1,40
++	sb	$tmp0,10($mac)
++	dsrl	$tmp0,$in1,48
++	sb	$tmp1,11($mac)
++	dsrl	$tmp1,$in1,56
++	sb	$tmp2,12($mac)
++	sb	$tmp3,13($mac)
++	sb	$tmp0,14($mac)
++	sb	$tmp1,15($mac)
++
++	jr	$ra
++.end	poly1305_emit
++.rdata
++.asciiz	"Poly1305 for MIPS64, CRYPTOGAMS by "
++.align	2
++___
++}
++
++$output=pop and open STDOUT,">$output";
++print $code;
++close STDOUT;
++
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/poly1305/asm/poly1305-ppc.pl b/CryptoPkg/Library/OpensslLib/openssl/crypto/poly1305/asm/poly1305-ppc.pl
+new file mode 100755
+index 0000000..ab65910
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/poly1305/asm/poly1305-ppc.pl
+@@ -0,0 +1,644 @@
++#! /usr/bin/env perl
++# Copyright 2016 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
++# in the file LICENSE in the source distribution or at
++# https://www.openssl.org/source/license.html
++
++#
++# ====================================================================
++# Written by Andy Polyakov  for the OpenSSL
++# project. The module is, however, dual licensed under OpenSSL and
++# CRYPTOGAMS licenses depending on where you obtain it. For further
++# details see http://www.openssl.org/~appro/cryptogams/.
++# ====================================================================
++#
++# This module implements Poly1305 hash for PowerPC.
++#
++# June 2015
++#
++# Numbers are cycles per processed byte with poly1305_blocks alone,
++# and improvement coefficients relative to gcc-generated code.
++#
++#			-m32		-m64
++#
++# Freescale e300	14.8/+80%	-
++# PPC74x0		7.60/+60%	-
++# PPC970		7.00/+114%	3.51/+205%
++# POWER7		3.75/+260%	1.93/+100%
++# POWER8		-		2.03/+200%
++#
++# Do we need floating-point implementation for PPC? Results presented
++# in poly1305_ieee754.c are tricky to compare to, because they are for
++# compiler-generated code. On the other hand it's known that floating-
++# point performance can be dominated by FPU latency, which means that
++# there is limit even for ideally optimized (and even vectorized) code.
++# And this limit is estimated to be higher than above -m64 results. Or
++# in other words floating-point implementation can be meaningful to
++# consider only in 32-bit application context. We probably have to
++# recognize that 32-bit builds are getting less popular on high-end
++# systems and therefore tend to target embedded ones, which might not
++# even have FPU...
++#
++# On side note, Power ISA 2.07 enables vector base 2^26 implementation,
++# and POWER8 might have capacity to break 1.0 cycle per byte barrier...
++
++$flavour = shift;
++
++if ($flavour =~ /64/) {
++	$SIZE_T	=8;
++	$LRSAVE	=2*$SIZE_T;
++	$UCMP	="cmpld";
++	$STU	="stdu";
++	$POP	="ld";
++	$PUSH	="std";
++} elsif ($flavour =~ /32/) {
++	$SIZE_T	=4;
++	$LRSAVE	=$SIZE_T;
++	$UCMP	="cmplw";
++	$STU	="stwu";
++	$POP	="lwz";
++	$PUSH	="stw";
++} else { die "nonsense $flavour"; }
++
++# Define endianness based on flavour
++# i.e.: linux64le
++$LITTLE_ENDIAN = ($flavour=~/le$/) ? $SIZE_T : 0;
++
++$0 =~ m/(.*[\/\\])[^\/\\]+$/; $dir=$1;
++( $xlate="${dir}ppc-xlate.pl" and -f $xlate ) or
++( $xlate="${dir}../../perlasm/ppc-xlate.pl" and -f $xlate) or
++die "can't locate ppc-xlate.pl";
++
++open STDOUT,"| $^X $xlate $flavour ".shift || die "can't call $xlate: $!";
++
++$FRAME=24*$SIZE_T;
++
++$sp="r1";
++my ($ctx,$inp,$len,$padbit) = map("r$_",(3..6));
++my ($mac,$nonce)=($inp,$len);
++my $mask = "r0";
++
++$code=<<___;
++.machine	"any"
++.text
++___
++							if ($flavour =~ /64/) {
++###############################################################################
++# base 2^64 implementation
++
++my ($h0,$h1,$h2,$d0,$d1,$d2, $r0,$r1,$s1, $t0,$t1) = map("r$_",(7..12,27..31));
++
++$code.=<<___;
++.globl	.poly1305_init_int
++.align	4
++.poly1305_init_int:
++	xor	r0,r0,r0
++	std	r0,0($ctx)		# zero hash value
++	std	r0,8($ctx)
++	std	r0,16($ctx)
++
++	$UCMP	$inp,r0
++	beq-	Lno_key
++___
++$code.=<<___	if ($LITTLE_ENDIAN);
++	ld	$d0,0($inp)		# load key material
++	ld	$d1,8($inp)
++___
++$code.=<<___	if (!$LITTLE_ENDIAN);
++	li	$h0,4
++	lwbrx	$d0,0,$inp		# load key material
++	li	$d1,8
++	lwbrx	$h0,$h0,$inp
++	li	$h1,12
++	lwbrx	$d1,$d1,$inp
++	lwbrx	$h1,$h1,$inp
++	insrdi	$d0,$h0,32,0
++	insrdi	$d1,$h1,32,0
++___
++$code.=<<___;
++	lis	$h1,0xfff		# 0x0fff0000
++	ori	$h1,$h1,0xfffc		# 0x0ffffffc
++	insrdi	$h1,$h1,32,0		# 0x0ffffffc0ffffffc
++	ori	$h0,$h1,3		# 0x0ffffffc0fffffff
++
++	and	$d0,$d0,$h0
++	and	$d1,$d1,$h1
++
++	std	$d0,32($ctx)		# store key
++	std	$d1,40($ctx)
++
++Lno_key:
++	xor	r3,r3,r3
++	blr
++	.long	0
++	.byte	0,12,0x14,0,0,0,2,0
++.size	.poly1305_init_int,.-.poly1305_init_int
++
++.globl	.poly1305_blocks
++.align	4
++.poly1305_blocks:
++	srdi.	$len,$len,4
++	beq-	Labort
++
++	$STU	$sp,-$FRAME($sp)
++	mflr	r0
++	$PUSH	r27,`$FRAME-$SIZE_T*5`($sp)
++	$PUSH	r28,`$FRAME-$SIZE_T*4`($sp)
++	$PUSH	r29,`$FRAME-$SIZE_T*3`($sp)
++	$PUSH	r30,`$FRAME-$SIZE_T*2`($sp)
++	$PUSH	r31,`$FRAME-$SIZE_T*1`($sp)
++	$PUSH	r0,`$FRAME+$LRSAVE`($sp)
++
++	ld	$r0,32($ctx)		# load key
++	ld	$r1,40($ctx)
++
++	ld	$h0,0($ctx)		# load hash value
++	ld	$h1,8($ctx)
++	ld	$h2,16($ctx)
++
++	srdi	$s1,$r1,2
++	mtctr	$len
++	add	$s1,$s1,$r1		# s1 = r1 + r1>>2
++	li	$mask,3
++	b	Loop
++
++.align	4
++Loop:
++___
++$code.=<<___	if ($LITTLE_ENDIAN);
++	ld	$t0,0($inp)		# load input
++	ld	$t1,8($inp)
++___
++$code.=<<___	if (!$LITTLE_ENDIAN);
++	li	$d0,4
++	lwbrx	$t0,0,$inp		# load input
++	li	$t1,8
++	lwbrx	$d0,$d0,$inp
++	li	$d1,12
++	lwbrx	$t1,$t1,$inp
++	lwbrx	$d1,$d1,$inp
++	insrdi	$t0,$d0,32,0
++	insrdi	$t1,$d1,32,0
++___
++$code.=<<___;
++	addi	$inp,$inp,16
++
++	addc	$h0,$h0,$t0		# accumulate input
++	adde	$h1,$h1,$t1
++
++	mulld	$d0,$h0,$r0		# h0*r0
++	mulhdu	$d1,$h0,$r0
++	adde	$h2,$h2,$padbit
++
++	mulld	$t0,$h1,$s1		# h1*5*r1
++	mulhdu	$t1,$h1,$s1
++	addc	$d0,$d0,$t0
++	adde	$d1,$d1,$t1
++
++	mulld	$t0,$h0,$r1		# h0*r1
++	mulhdu	$d2,$h0,$r1
++	addc	$d1,$d1,$t0
++	addze	$d2,$d2
++
++	mulld	$t0,$h1,$r0		# h1*r0
++	mulhdu	$t1,$h1,$r0
++	addc	$d1,$d1,$t0
++	adde	$d2,$d2,$t1
++
++	mulld	$t0,$h2,$s1		# h2*5*r1
++	mulld	$t1,$h2,$r0		# h2*r0
++	addc	$d1,$d1,$t0
++	adde	$d2,$d2,$t1
++
++	andc	$t0,$d2,$mask		# final reduction step
++	and	$h2,$d2,$mask
++	srdi	$t1,$t0,2
++	add	$t0,$t0,$t1
++	addc	$h0,$d0,$t0
++	addze	$h1,$d1
++	addze	$h2,$h2
++
++	bdnz	Loop
++
++	std	$h0,0($ctx)		# store hash value
++	std	$h1,8($ctx)
++	std	$h2,16($ctx)
++
++	$POP	r27,`$FRAME-$SIZE_T*5`($sp)
++	$POP	r28,`$FRAME-$SIZE_T*4`($sp)
++	$POP	r29,`$FRAME-$SIZE_T*3`($sp)
++	$POP	r30,`$FRAME-$SIZE_T*2`($sp)
++	$POP	r31,`$FRAME-$SIZE_T*1`($sp)
++	addi	$sp,$sp,$FRAME
++Labort:
++	blr
++	.long	0
++	.byte	0,12,4,1,0x80,5,4,0
++.size	.poly1305_blocks,.-.poly1305_blocks
++
++.globl	.poly1305_emit
++.align	4
++.poly1305_emit:
++	ld	$h0,0($ctx)		# load hash
++	ld	$h1,8($ctx)
++	ld	$h2,16($ctx)
++	ld	$padbit,0($nonce)	# load nonce
++	ld	$nonce,8($nonce)
++
++	addic	$d0,$h0,5		# compare to modulus
++	addze	$d1,$h1
++	addze	$d2,$h2
++
++	srdi	$mask,$d2,2		# did it carry/borrow?
++	neg	$mask,$mask
++
++	andc	$h0,$h0,$mask
++	and	$d0,$d0,$mask
++	andc	$h1,$h1,$mask
++	and	$d1,$d1,$mask
++	or	$h0,$h0,$d0
++	or	$h1,$h1,$d1
++___
++$code.=<<___	if (!$LITTLE_ENDIAN);
++	rotldi	$padbit,$padbit,32	# flip nonce words
++	rotldi	$nonce,$nonce,32
++___
++$code.=<<___;
++	addc	$h0,$h0,$padbit		# accumulate nonce
++	adde	$h1,$h1,$nonce
++___
++$code.=<<___	if ($LITTLE_ENDIAN);
++	std	$h0,0($mac)		# write result
++	std	$h1,8($mac)
++___
++$code.=<<___	if (!$LITTLE_ENDIAN);
++	extrdi	r0,$h0,32,0
++	li	$d0,4
++	stwbrx	$h0,0,$mac		# write result
++	extrdi	$h0,$h1,32,0
++	li	$d1,8
++	stwbrx	r0,$d0,$mac
++	li	$d2,12
++	stwbrx	$h1,$d1,$mac
++	stwbrx	$h0,$d2,$mac
++___
++$code.=<<___;
++	blr
++	.long	0
++	.byte	0,12,0x14,0,0,0,3,0
++.size	.poly1305_emit,.-.poly1305_emit
++___
++							} else {
++###############################################################################
++# base 2^32 implementation
++
++my ($h0,$h1,$h2,$h3,$h4, $r0,$r1,$r2,$r3, $s1,$s2,$s3,
++    $t0,$t1,$t2,$t3, $D0,$D1,$D2,$D3, $d0,$d1,$d2,$d3
++   ) = map("r$_",(7..12,14..31));
++
++$code.=<<___;
++.globl	.poly1305_init_int
++.align	4
++.poly1305_init_int:
++	xor	r0,r0,r0
++	stw	r0,0($ctx)		# zero hash value
++	stw	r0,4($ctx)
++	stw	r0,8($ctx)
++	stw	r0,12($ctx)
++	stw	r0,16($ctx)
++
++	$UCMP	$inp,r0
++	beq-	Lno_key
++___
++$code.=<<___	if ($LITTLE_ENDIAN);
++	lw	$h0,0($inp)		# load key material
++	lw	$h1,4($inp)
++	lw	$h2,8($inp)
++	lw	$h3,12($inp)
++___
++$code.=<<___	if (!$LITTLE_ENDIAN);
++	li	$h1,4
++	lwbrx	$h0,0,$inp		# load key material
++	li	$h2,8
++	lwbrx	$h1,$h1,$inp
++	li	$h3,12
++	lwbrx	$h2,$h2,$inp
++	lwbrx	$h3,$h3,$inp
++___
++$code.=<<___;
++	lis	$mask,0xf000		# 0xf0000000
++	li	$r0,-4
++	andc	$r0,$r0,$mask		# 0x0ffffffc
++
++	andc	$h0,$h0,$mask
++	and	$h1,$h1,$r0
++	and	$h2,$h2,$r0
++	and	$h3,$h3,$r0
++
++	stw	$h0,32($ctx)		# store key
++	stw	$h1,36($ctx)
++	stw	$h2,40($ctx)
++	stw	$h3,44($ctx)
++
++Lno_key:
++	xor	r3,r3,r3
++	blr
++	.long	0
++	.byte	0,12,0x14,0,0,0,2,0
++.size	.poly1305_init_int,.-.poly1305_init_int
++
++.globl	.poly1305_blocks
++.align	4
++.poly1305_blocks:
++	srwi.	$len,$len,4
++	beq-	Labort
++
++	$STU	$sp,-$FRAME($sp)
++	mflr	r0
++	$PUSH	r14,`$FRAME-$SIZE_T*18`($sp)
++	$PUSH	r15,`$FRAME-$SIZE_T*17`($sp)
++	$PUSH	r16,`$FRAME-$SIZE_T*16`($sp)
++	$PUSH	r17,`$FRAME-$SIZE_T*15`($sp)
++	$PUSH	r18,`$FRAME-$SIZE_T*14`($sp)
++	$PUSH	r19,`$FRAME-$SIZE_T*13`($sp)
++	$PUSH	r20,`$FRAME-$SIZE_T*12`($sp)
++	$PUSH	r21,`$FRAME-$SIZE_T*11`($sp)
++	$PUSH	r22,`$FRAME-$SIZE_T*10`($sp)
++	$PUSH	r23,`$FRAME-$SIZE_T*9`($sp)
++	$PUSH	r24,`$FRAME-$SIZE_T*8`($sp)
++	$PUSH	r25,`$FRAME-$SIZE_T*7`($sp)
++	$PUSH	r26,`$FRAME-$SIZE_T*6`($sp)
++	$PUSH	r27,`$FRAME-$SIZE_T*5`($sp)
++	$PUSH	r28,`$FRAME-$SIZE_T*4`($sp)
++	$PUSH	r29,`$FRAME-$SIZE_T*3`($sp)
++	$PUSH	r30,`$FRAME-$SIZE_T*2`($sp)
++	$PUSH	r31,`$FRAME-$SIZE_T*1`($sp)
++	$PUSH	r0,`$FRAME+$LRSAVE`($sp)
++
++	lwz	$r0,32($ctx)		# load key
++	lwz	$r1,36($ctx)
++	lwz	$r2,40($ctx)
++	lwz	$r3,44($ctx)
++
++	lwz	$h0,0($ctx)		# load hash value
++	lwz	$h1,4($ctx)
++	lwz	$h2,8($ctx)
++	lwz	$h3,12($ctx)
++	lwz	$h4,16($ctx)
++
++	srwi	$s1,$r1,2
++	srwi	$s2,$r2,2
++	srwi	$s3,$r3,2
++	add	$s1,$s1,$r1		# si = ri + ri>>2
++	add	$s2,$s2,$r2
++	add	$s3,$s3,$r3
++	mtctr	$len
++	li	$mask,3
++	b	Loop
++
++.align	4
++Loop:
++___
++$code.=<<___	if ($LITTLE_ENDIAN);
++	lwz	$d0,0($inp)		# load input
++	lwz	$d1,4($inp)
++	lwz	$d2,8($inp)
++	lwz	$d3,12($inp)
++___
++$code.=<<___	if (!$LITTLE_ENDIAN);
++	li	$d1,4
++	lwbrx	$d0,0,$inp		# load input
++	li	$d2,8
++	lwbrx	$d1,$d1,$inp
++	li	$d3,12
++	lwbrx	$d2,$d2,$inp
++	lwbrx	$d3,$d3,$inp
++___
++$code.=<<___;
++	addi	$inp,$inp,16
++
++	addc	$h0,$h0,$d0		# accumulate input
++	adde	$h1,$h1,$d1
++	adde	$h2,$h2,$d2
++
++	mullw	$d0,$h0,$r0		# h0*r0
++	mulhwu	$D0,$h0,$r0
++
++	mullw	$d1,$h0,$r1		# h0*r1
++	mulhwu	$D1,$h0,$r1
++
++	mullw	$d2,$h0,$r2		# h0*r2
++	mulhwu	$D2,$h0,$r2
++
++	 adde	$h3,$h3,$d3
++	 adde	$h4,$h4,$padbit
++
++	mullw	$d3,$h0,$r3		# h0*r3
++	mulhwu	$D3,$h0,$r3
++
++	mullw	$t0,$h1,$s3		# h1*s3
++	mulhwu	$t1,$h1,$s3
++
++	mullw	$t2,$h1,$r0		# h1*r0
++	mulhwu	$t3,$h1,$r0
++	 addc	$d0,$d0,$t0
++	 adde	$D0,$D0,$t1
++
++	mullw	$t0,$h1,$r1		# h1*r1
++	mulhwu	$t1,$h1,$r1
++	 addc	$d1,$d1,$t2
++	 adde	$D1,$D1,$t3
++
++	mullw	$t2,$h1,$r2		# h1*r2
++	mulhwu	$t3,$h1,$r2
++	 addc	$d2,$d2,$t0
++	 adde	$D2,$D2,$t1
++
++	mullw	$t0,$h2,$s2		# h2*s2
++	mulhwu	$t1,$h2,$s2
++	 addc	$d3,$d3,$t2
++	 adde	$D3,$D3,$t3
++
++	mullw	$t2,$h2,$s3		# h2*s3
++	mulhwu	$t3,$h2,$s3
++	 addc	$d0,$d0,$t0
++	 adde	$D0,$D0,$t1
++
++	mullw	$t0,$h2,$r0		# h2*r0
++	mulhwu	$t1,$h2,$r0
++	 addc	$d1,$d1,$t2
++	 adde	$D1,$D1,$t3
++
++	mullw	$t2,$h2,$r1		# h2*r1
++	mulhwu	$t3,$h2,$r1
++	 addc	$d2,$d2,$t0
++	 adde	$D2,$D2,$t1
++
++	mullw	$t0,$h3,$s1		# h3*s1
++	mulhwu	$t1,$h3,$s1
++	 addc	$d3,$d3,$t2
++	 adde	$D3,$D3,$t3
++
++	mullw	$t2,$h3,$s2		# h3*s2
++	mulhwu	$t3,$h3,$s2
++	 addc	$d0,$d0,$t0
++	 adde	$D0,$D0,$t1
++
++	mullw	$t0,$h3,$s3		# h3*s3
++	mulhwu	$t1,$h3,$s3
++	 addc	$d1,$d1,$t2
++	 adde	$D1,$D1,$t3
++
++	mullw	$t2,$h3,$r0		# h3*r0
++	mulhwu	$t3,$h3,$r0
++	 addc	$d2,$d2,$t0
++	 adde	$D2,$D2,$t1
++
++	mullw	$t0,$h4,$s1		# h4*s1
++	 addc	$d3,$d3,$t2
++	 adde	$D3,$D3,$t3
++	addc	$d1,$d1,$t0
++
++	mullw	$t1,$h4,$s2		# h4*s2
++	 addze	$D1,$D1
++	addc	$d2,$d2,$t1
++	addze	$D2,$D2
++
++	mullw	$t2,$h4,$s3		# h4*s3
++	addc	$d3,$d3,$t2
++	addze	$D3,$D3
++
++	mullw	$h4,$h4,$r0		# h4*r0
++
++	addc	$h1,$d1,$D0
++	adde	$h2,$d2,$D1
++	adde	$h3,$d3,$D2
++	adde	$h4,$h4,$D3
++
++	andc	$D0,$h4,$mask		# final reduction step
++	and	$h4,$h4,$mask
++	srwi	$D1,$D0,2
++	add	$D0,$D0,$D1
++	addc	$h0,$d0,$D0
++	addze	$h1,$h1
++	addze	$h2,$h2
++	addze	$h3,$h3
++	addze	$h4,$h4
++
++	bdnz	Loop
++
++	stw	$h0,0($ctx)		# store hash value
++	stw	$h1,4($ctx)
++	stw	$h2,8($ctx)
++	stw	$h3,12($ctx)
++	stw	$h4,16($ctx)
++
++	$POP	r14,`$FRAME-$SIZE_T*18`($sp)
++	$POP	r15,`$FRAME-$SIZE_T*17`($sp)
++	$POP	r16,`$FRAME-$SIZE_T*16`($sp)
++	$POP	r17,`$FRAME-$SIZE_T*15`($sp)
++	$POP	r18,`$FRAME-$SIZE_T*14`($sp)
++	$POP	r19,`$FRAME-$SIZE_T*13`($sp)
++	$POP	r20,`$FRAME-$SIZE_T*12`($sp)
++	$POP	r21,`$FRAME-$SIZE_T*11`($sp)
++	$POP	r22,`$FRAME-$SIZE_T*10`($sp)
++	$POP	r23,`$FRAME-$SIZE_T*9`($sp)
++	$POP	r24,`$FRAME-$SIZE_T*8`($sp)
++	$POP	r25,`$FRAME-$SIZE_T*7`($sp)
++	$POP	r26,`$FRAME-$SIZE_T*6`($sp)
++	$POP	r27,`$FRAME-$SIZE_T*5`($sp)
++	$POP	r28,`$FRAME-$SIZE_T*4`($sp)
++	$POP	r29,`$FRAME-$SIZE_T*3`($sp)
++	$POP	r30,`$FRAME-$SIZE_T*2`($sp)
++	$POP	r31,`$FRAME-$SIZE_T*1`($sp)
++	addi	$sp,$sp,$FRAME
++Labort:
++	blr
++	.long	0
++	.byte	0,12,4,1,0x80,18,4,0
++.size	.poly1305_blocks,.-.poly1305_blocks
++
++.globl	.poly1305_emit
++.align	4
++.poly1305_emit:
++	$STU	$sp,-$FRAME($sp)
++	mflr	r0
++	$PUSH	r28,`$FRAME-$SIZE_T*4`($sp)
++	$PUSH	r29,`$FRAME-$SIZE_T*3`($sp)
++	$PUSH	r30,`$FRAME-$SIZE_T*2`($sp)
++	$PUSH	r31,`$FRAME-$SIZE_T*1`($sp)
++	$PUSH	r0,`$FRAME+$LRSAVE`($sp)
++
++	lwz	$h0,0($ctx)		# load hash
++	lwz	$h1,4($ctx)
++	lwz	$h2,8($ctx)
++	lwz	$h3,12($ctx)
++	lwz	$h4,16($ctx)
++
++	addic	$d0,$h0,5		# compare to modulus
++	addze	$d1,$h1
++	addze	$d2,$h2
++	addze	$d3,$h3
++	addze	$mask,$h4
++
++	srwi	$mask,$mask,2		# did it carry/borrow?
++	neg	$mask,$mask
++
++	andc	$h0,$h0,$mask
++	and	$d0,$d0,$mask
++	andc	$h1,$h1,$mask
++	and	$d1,$d1,$mask
++	or	$h0,$h0,$d0
++	lwz	$d0,0($nonce)		# load nonce
++	andc	$h2,$h2,$mask
++	and	$d2,$d2,$mask
++	or	$h1,$h1,$d1
++	lwz	$d1,4($nonce)
++	andc	$h3,$h3,$mask
++	and	$d3,$d3,$mask
++	or	$h2,$h2,$d2
++	lwz	$d2,8($nonce)
++	or	$h3,$h3,$d3
++	lwz	$d3,12($nonce)
++
++	addc	$h0,$h0,$d0		# accumulate nonce
++	adde	$h1,$h1,$d1
++	adde	$h2,$h2,$d2
++	adde	$h3,$h3,$d3
++___
++$code.=<<___	if ($LITTLE_ENDIAN);
++	stw	$h0,0($mac)		# write result
++	stw	$h1,4($mac)
++	stw	$h2,8($mac)
++	stw	$h3,12($mac)
++___
++$code.=<<___	if (!$LITTLE_ENDIAN);
++	li	$d1,4
++	stwbrx	$h0,0,$mac		# write result
++	li	$d2,8
++	stwbrx	$h1,$d1,$mac
++	li	$d3,12
++	stwbrx	$h2,$d2,$mac
++	stwbrx	$h3,$d3,$mac
++___
++$code.=<<___;
++	$POP	r28,`$FRAME-$SIZE_T*4`($sp)
++	$POP	r29,`$FRAME-$SIZE_T*3`($sp)
++	$POP	r30,`$FRAME-$SIZE_T*2`($sp)
++	$POP	r31,`$FRAME-$SIZE_T*1`($sp)
++	addi	$sp,$sp,$FRAME
++	blr
++	.long	0
++	.byte	0,12,4,1,0x80,4,3,0
++.size	.poly1305_emit,.-.poly1305_emit
++___
++							}
++$code.=<<___;
++.asciz	"Poly1305 for PPC, CRYPTOGAMS by "
++___
++
++$code =~ s/\`([^\`]*)\`/eval $1/gem;
++print $code;
++close STDOUT;
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/poly1305/asm/poly1305-ppcfp.pl b/CryptoPkg/Library/OpensslLib/openssl/crypto/poly1305/asm/poly1305-ppcfp.pl
+new file mode 100755
+index 0000000..49f70a8
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/poly1305/asm/poly1305-ppcfp.pl
+@@ -0,0 +1,739 @@
++#! /usr/bin/env perl
++# Copyright 2016 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
++# in the file LICENSE in the source distribution or at
++# https://www.openssl.org/source/license.html
++
++#
++# ====================================================================
++# Written by Andy Polyakov  for the OpenSSL
++# project. The module is, however, dual licensed under OpenSSL and
++# CRYPTOGAMS licenses depending on where you obtain it. For further
++# details see http://www.openssl.org/~appro/cryptogams/.
++# ====================================================================
++#
++# This module implements Poly1305 hash for PowerPC FPU.
++#
++# June 2015
++#
++# Numbers are cycles per processed byte with poly1305_blocks alone,
++# and improvement coefficients relative to gcc-generated code.
++#
++# Freescale e300	9.78/+30%
++# PPC74x0		6.92/+50%
++# PPC970		6.03/+80%
++# POWER7		3.50/+30%
++# POWER8		3.75/+10%
++
++$flavour = shift;
++
++if ($flavour =~ /64/) {
++	$SIZE_T	=8;
++	$LRSAVE	=2*$SIZE_T;
++	$UCMP	="cmpld";
++	$STU	="stdu";
++	$POP	="ld";
++	$PUSH	="std";
++} elsif ($flavour =~ /32/) {
++	$SIZE_T	=4;
++	$LRSAVE	=$SIZE_T;
++	$UCMP	="cmplw";
++	$STU	="stwu";
++	$POP	="lwz";
++	$PUSH	="stw";
++} else { die "nonsense $flavour"; }
++
++$LITTLE_ENDIAN = ($flavour=~/le$/) ? 4 : 0;
++
++$LWXLE = $LITTLE_ENDIAN ? "lwzx" : "lwbrx";
++
++$0 =~ m/(.*[\/\\])[^\/\\]+$/; $dir=$1;
++( $xlate="${dir}ppc-xlate.pl" and -f $xlate ) or
++( $xlate="${dir}../../perlasm/ppc-xlate.pl" and -f $xlate) or
++die "can't locate ppc-xlate.pl";
++
++open STDOUT,"| $^X $xlate $flavour ".shift || die "can't call $xlate: $!";
++
++$LOCALS=6*$SIZE_T;
++$FRAME=$LOCALS+6*8+18*8;
++
++my $sp="r1";
++
++my ($ctx,$inp,$len,$padbit) = map("r$_",(3..6));
++my ($in0,$in1,$in2,$in3,$i1,$i2,$i3) = map("r$_",(7..12,6));
++
++my ($h0lo,$h0hi,$h1lo,$h1hi,$h2lo,$h2hi,$h3lo,$h3hi,
++    $two0,$two32,$two64,$two96,$two130,$five_two130,
++    $r0lo,$r0hi,$r1lo,$r1hi,$r2lo,$r2hi,
++    $s2lo,$s2hi,$s3lo,$s3hi,
++    $c0lo,$c0hi,$c1lo,$c1hi,$c2lo,$c2hi,$c3lo,$c3hi) = map("f$_",(0..31));
++# borrowings
++my ($r3lo,$r3hi,$s1lo,$s1hi) = ($c0lo,$c0hi,$c1lo,$c1hi);
++my ($x0,$x1,$x2,$x3) = ($c2lo,$c2hi,$c3lo,$c3hi);
++my ($y0,$y1,$y2,$y3) = ($c3lo,$c3hi,$c1lo,$c1hi);
++
++$code.=<<___;
++.machine	"any"
++.text
++
++.globl	.poly1305_init_fpu
++.align	6
++.poly1305_init_fpu:
++	$STU	$sp,-$LOCALS($sp)		# minimal frame
++	mflr	$padbit
++	$PUSH	$padbit,`$LOCALS+$LRSAVE`($sp)
++
++	bl	LPICmeup
++
++	xor	r0,r0,r0
++	mtlr	$padbit				# restore lr
++
++	lfd	$two0,8*0($len)			# load constants
++	lfd	$two32,8*1($len)
++	lfd	$two64,8*2($len)
++	lfd	$two96,8*3($len)
++	lfd	$two130,8*4($len)
++	lfd	$five_two130,8*5($len)
++
++	stfd	$two0,8*0($ctx)			# initial hash value, biased 0
++	stfd	$two32,8*1($ctx)
++	stfd	$two64,8*2($ctx)
++	stfd	$two96,8*3($ctx)
++
++	$UCMP	$inp,r0
++	beq-	Lno_key
++
++	lfd	$h3lo,8*13($len)		# new fpscr
++	mffs	$h3hi				# old fpscr
++
++	stfd	$two0,8*4($ctx)			# key "template"
++	stfd	$two32,8*5($ctx)
++	stfd	$two64,8*6($ctx)
++	stfd	$two96,8*7($ctx)
++
++	li	$in1,4
++	li	$in2,8
++	li	$in3,12
++	$LWXLE	$in0,0,$inp			# load key
++	$LWXLE	$in1,$in1,$inp
++	$LWXLE	$in2,$in2,$inp
++	$LWXLE	$in3,$in3,$inp
++
++	lis	$i1,0xf000			#   0xf0000000
++	ori	$i2,$i1,3			#   0xf0000003
++	andc	$in0,$in0,$i1			# &=0x0fffffff
++	andc	$in1,$in1,$i2			# &=0x0ffffffc
++	andc	$in2,$in2,$i2
++	andc	$in3,$in3,$i2
++
++	stw	$in0,`8*4+(4^$LITTLE_ENDIAN)`($ctx)	# fill "template"
++	stw	$in1,`8*5+(4^$LITTLE_ENDIAN)`($ctx)
++	stw	$in2,`8*6+(4^$LITTLE_ENDIAN)`($ctx)
++	stw	$in3,`8*7+(4^$LITTLE_ENDIAN)`($ctx)
++
++	mtfsf	255,$h3lo			# fpscr
++	stfd	$two0,8*18($ctx)		# copy constants to context
++	stfd	$two32,8*19($ctx)
++	stfd	$two64,8*20($ctx)
++	stfd	$two96,8*21($ctx)
++	stfd	$two130,8*22($ctx)
++	stfd	$five_two130,8*23($ctx)
++
++	lfd	$h0lo,8*4($ctx)			# load [biased] key
++	lfd	$h1lo,8*5($ctx)
++	lfd	$h2lo,8*6($ctx)
++	lfd	$h3lo,8*7($ctx)
++
++	fsub	$h0lo,$h0lo,$two0		# r0
++	fsub	$h1lo,$h1lo,$two32		# r1
++	fsub	$h2lo,$h2lo,$two64		# r2
++	fsub	$h3lo,$h3lo,$two96		# r3
++
++	lfd	$two0,8*6($len)			# more constants
++	lfd	$two32,8*7($len)
++	lfd	$two64,8*8($len)
++	lfd	$two96,8*9($len)
++
++	fmul	$h1hi,$h1lo,$five_two130	# s1
++	fmul	$h2hi,$h2lo,$five_two130	# s2
++	 stfd	$h3hi,8*15($ctx)		# borrow slot for original fpscr
++	fmul	$h3hi,$h3lo,$five_two130	# s3
++
++	fadd	$h0hi,$h0lo,$two0
++	 stfd	$h1hi,8*12($ctx)		# put aside for now
++	fadd	$h1hi,$h1lo,$two32
++	 stfd	$h2hi,8*13($ctx)
++	fadd	$h2hi,$h2lo,$two64
++	 stfd	$h3hi,8*14($ctx)
++	fadd	$h3hi,$h3lo,$two96
++
++	fsub	$h0hi,$h0hi,$two0
++	fsub	$h1hi,$h1hi,$two32
++	fsub	$h2hi,$h2hi,$two64
++	fsub	$h3hi,$h3hi,$two96
++
++	lfd	$two0,8*10($len)		# more constants
++	lfd	$two32,8*11($len)
++	lfd	$two64,8*12($len)
++
++	fsub	$h0lo,$h0lo,$h0hi
++	fsub	$h1lo,$h1lo,$h1hi
++	fsub	$h2lo,$h2lo,$h2hi
++	fsub	$h3lo,$h3lo,$h3hi
++
++	stfd	$h0hi,8*5($ctx)			# r0hi
++	stfd	$h1hi,8*7($ctx)			# r1hi
++	stfd	$h2hi,8*9($ctx)			# r2hi
++	stfd	$h3hi,8*11($ctx)		# r3hi
++
++	stfd	$h0lo,8*4($ctx)			# r0lo
++	stfd	$h1lo,8*6($ctx)			# r1lo
++	stfd	$h2lo,8*8($ctx)			# r2lo
++	stfd	$h3lo,8*10($ctx)		# r3lo
++
++	lfd	$h1lo,8*12($ctx)		# s1
++	lfd	$h2lo,8*13($ctx)		# s2
++	lfd	$h3lo,8*14($ctx)		# s3
++	lfd	$h0lo,8*15($ctx)		# pull original fpscr
++
++	fadd	$h1hi,$h1lo,$two0
++	fadd	$h2hi,$h2lo,$two32
++	fadd	$h3hi,$h3lo,$two64
++
++	fsub	$h1hi,$h1hi,$two0
++	fsub	$h2hi,$h2hi,$two32
++	fsub	$h3hi,$h3hi,$two64
++
++	fsub	$h1lo,$h1lo,$h1hi
++	fsub	$h2lo,$h2lo,$h2hi
++	fsub	$h3lo,$h3lo,$h3hi
++
++	stfd	$h1hi,8*13($ctx)		# s1hi
++	stfd	$h2hi,8*15($ctx)		# s2hi
++	stfd	$h3hi,8*17($ctx)		# s3hi
++
++	stfd	$h1lo,8*12($ctx)		# s1lo
++	stfd	$h2lo,8*14($ctx)		# s2lo
++	stfd	$h3lo,8*16($ctx)		# s3lo
++
++	mtfsf	255,$h0lo			# restore fpscr
++Lno_key:
++	xor	r3,r3,r3
++	addi	$sp,$sp,$LOCALS
++	blr
++	.long	0
++	.byte	0,12,4,1,0x80,0,2,0
++.size	.poly1305_init_fpu,.-.poly1305_init_fpu
++
++.globl	.poly1305_blocks_fpu
++.align	4
++.poly1305_blocks_fpu:
++	srwi.	$len,$len,4
++	beq-	Labort
++
++	$STU	$sp,-$FRAME($sp)
++	mflr	r0
++	stfd	f14,`$FRAME-8*18`($sp)
++	stfd	f15,`$FRAME-8*17`($sp)
++	stfd	f16,`$FRAME-8*16`($sp)
++	stfd	f17,`$FRAME-8*15`($sp)
++	stfd	f18,`$FRAME-8*14`($sp)
++	stfd	f19,`$FRAME-8*13`($sp)
++	stfd	f20,`$FRAME-8*12`($sp)
++	stfd	f21,`$FRAME-8*11`($sp)
++	stfd	f22,`$FRAME-8*10`($sp)
++	stfd	f23,`$FRAME-8*9`($sp)
++	stfd	f24,`$FRAME-8*8`($sp)
++	stfd	f25,`$FRAME-8*7`($sp)
++	stfd	f26,`$FRAME-8*6`($sp)
++	stfd	f27,`$FRAME-8*5`($sp)
++	stfd	f28,`$FRAME-8*4`($sp)
++	stfd	f29,`$FRAME-8*3`($sp)
++	stfd	f30,`$FRAME-8*2`($sp)
++	stfd	f31,`$FRAME-8*1`($sp)
++	$PUSH	r0,`$FRAME+$LRSAVE`($sp)
++
++	xor	r0,r0,r0
++	li	$in3,1
++	mtctr	$len
++	neg	$len,$len
++	stw	r0,`$LOCALS+8*4+(0^$LITTLE_ENDIAN)`($sp)
++	stw	$in3,`$LOCALS+8*4+(4^$LITTLE_ENDIAN)`($sp)
++
++	lfd	$two0,8*18($ctx)		# load constants
++	lfd	$two32,8*19($ctx)
++	lfd	$two64,8*20($ctx)
++	lfd	$two96,8*21($ctx)
++	lfd	$two130,8*22($ctx)
++	lfd	$five_two130,8*23($ctx)
++
++	lfd	$h0lo,8*0($ctx)			# load [biased] hash value
++	lfd	$h1lo,8*1($ctx)
++	lfd	$h2lo,8*2($ctx)
++	lfd	$h3lo,8*3($ctx)
++
++	stfd	$two0,`$LOCALS+8*0`($sp)	# input "template"
++	oris	$in3,$padbit,`(1023+52+96)<<4`
++	stfd	$two32,`$LOCALS+8*1`($sp)
++	stfd	$two64,`$LOCALS+8*2`($sp)
++	stw	$in3,`$LOCALS+8*3+(0^$LITTLE_ENDIAN)`($sp)
++
++	li	$i1,4
++	li	$i2,8
++	li	$i3,12
++	$LWXLE	$in0,0,$inp			# load input
++	$LWXLE	$in1,$i1,$inp
++	$LWXLE	$in2,$i2,$inp
++	$LWXLE	$in3,$i3,$inp
++	addi	$inp,$inp,16
++
++	stw	$in0,`$LOCALS+8*0+(4^$LITTLE_ENDIAN)`($sp)	# fill "template"
++	stw	$in1,`$LOCALS+8*1+(4^$LITTLE_ENDIAN)`($sp)
++	stw	$in2,`$LOCALS+8*2+(4^$LITTLE_ENDIAN)`($sp)
++	stw	$in3,`$LOCALS+8*3+(4^$LITTLE_ENDIAN)`($sp)
++
++	mffs	$x0				# original fpscr
++	lfd	$x1,`$LOCALS+8*4`($sp)		# new fpscr
++	lfd	$r0lo,8*4($ctx)			# load key
++	lfd	$r0hi,8*5($ctx)
++	lfd	$r1lo,8*6($ctx)
++	lfd	$r1hi,8*7($ctx)
++	lfd	$r2lo,8*8($ctx)
++	lfd	$r2hi,8*9($ctx)
++	lfd	$r3lo,8*10($ctx)
++	lfd	$r3hi,8*11($ctx)
++	lfd	$s1lo,8*12($ctx)
++	lfd	$s1hi,8*13($ctx)
++	lfd	$s2lo,8*14($ctx)
++	lfd	$s2hi,8*15($ctx)
++	lfd	$s3lo,8*16($ctx)
++	lfd	$s3hi,8*17($ctx)
++
++	stfd	$x0,`$LOCALS+8*4`($sp)		# save original fpscr
++	mtfsf	255,$x1
++
++	addic	$len,$len,1
++	addze	r0,r0
++	slwi.	r0,r0,4
++	sub	$inp,$inp,r0			# conditional rewind
++
++	lfd	$x0,`$LOCALS+8*0`($sp)
++	lfd	$x1,`$LOCALS+8*1`($sp)
++	lfd	$x2,`$LOCALS+8*2`($sp)
++	lfd	$x3,`$LOCALS+8*3`($sp)
++
++	fsub	$h0lo,$h0lo,$two0		# de-bias hash value
++	 $LWXLE	$in0,0,$inp			# modulo-scheduled input load
++	fsub	$h1lo,$h1lo,$two32
++	 $LWXLE	$in1,$i1,$inp
++	fsub	$h2lo,$h2lo,$two64
++	 $LWXLE	$in2,$i2,$inp
++	fsub	$h3lo,$h3lo,$two96
++	 $LWXLE	$in3,$i3,$inp
++
++	fsub	$x0,$x0,$two0			# de-bias input
++	 addi	$inp,$inp,16
++	fsub	$x1,$x1,$two32
++	fsub	$x2,$x2,$two64
++	fsub	$x3,$x3,$two96
++
++	fadd	$x0,$x0,$h0lo			# accumulate input
++	 stw	$in0,`$LOCALS+8*0+(4^$LITTLE_ENDIAN)`($sp)
++	fadd	$x1,$x1,$h1lo
++	 stw	$in1,`$LOCALS+8*1+(4^$LITTLE_ENDIAN)`($sp)
++	fadd	$x2,$x2,$h2lo
++	 stw	$in2,`$LOCALS+8*2+(4^$LITTLE_ENDIAN)`($sp)
++	fadd	$x3,$x3,$h3lo
++	 stw	$in3,`$LOCALS+8*3+(4^$LITTLE_ENDIAN)`($sp)
++
++	b	Lentry
++
++.align	4
++Loop:
++	fsub	$y0,$y0,$two0			# de-bias input
++	 addic	$len,$len,1
++	fsub	$y1,$y1,$two32
++	 addze	r0,r0
++	fsub	$y2,$y2,$two64
++	 slwi.	r0,r0,4
++	fsub	$y3,$y3,$two96
++	 sub	$inp,$inp,r0			# conditional rewind
++
++	fadd	$h0lo,$h0lo,$y0			# accumulate input
++	fadd	$h0hi,$h0hi,$y1
++	fadd	$h2lo,$h2lo,$y2
++	fadd	$h2hi,$h2hi,$y3
++
++	######################################### base 2^48 -> base 2^32
++	fadd	$c1lo,$h1lo,$two64
++	 $LWXLE	$in0,0,$inp			# modulo-scheduled input load
++	fadd	$c1hi,$h1hi,$two64
++	 $LWXLE	$in1,$i1,$inp
++	fadd	$c3lo,$h3lo,$two130
++	 $LWXLE	$in2,$i2,$inp
++	fadd	$c3hi,$h3hi,$two130
++	 $LWXLE	$in3,$i3,$inp
++	fadd	$c0lo,$h0lo,$two32
++	 addi	$inp,$inp,16
++	fadd	$c0hi,$h0hi,$two32
++	fadd	$c2lo,$h2lo,$two96
++	fadd	$c2hi,$h2hi,$two96
++
++	fsub	$c1lo,$c1lo,$two64
++	 stw	$in0,`$LOCALS+8*0+(4^$LITTLE_ENDIAN)`($sp)	# fill "template"
++	fsub	$c1hi,$c1hi,$two64
++	 stw	$in1,`$LOCALS+8*1+(4^$LITTLE_ENDIAN)`($sp)
++	fsub	$c3lo,$c3lo,$two130
++	 stw	$in2,`$LOCALS+8*2+(4^$LITTLE_ENDIAN)`($sp)
++	fsub	$c3hi,$c3hi,$two130
++	 stw	$in3,`$LOCALS+8*3+(4^$LITTLE_ENDIAN)`($sp)
++	fsub	$c0lo,$c0lo,$two32
++	fsub	$c0hi,$c0hi,$two32
++	fsub	$c2lo,$c2lo,$two96
++	fsub	$c2hi,$c2hi,$two96
++
++	fsub	$h1lo,$h1lo,$c1lo
++	fsub	$h1hi,$h1hi,$c1hi
++	fsub	$h3lo,$h3lo,$c3lo
++	fsub	$h3hi,$h3hi,$c3hi
++	fsub	$h2lo,$h2lo,$c2lo
++	fsub	$h2hi,$h2hi,$c2hi
++	fsub	$h0lo,$h0lo,$c0lo
++	fsub	$h0hi,$h0hi,$c0hi
++
++	fadd	$h1lo,$h1lo,$c0lo
++	fadd	$h1hi,$h1hi,$c0hi
++	fadd	$h3lo,$h3lo,$c2lo
++	fadd	$h3hi,$h3hi,$c2hi
++	fadd	$h2lo,$h2lo,$c1lo
++	fadd	$h2hi,$h2hi,$c1hi
++	fmadd	$h0lo,$c3lo,$five_two130,$h0lo
++	fmadd	$h0hi,$c3hi,$five_two130,$h0hi
++
++	fadd	$x1,$h1lo,$h1hi
++	 lfd	$s1lo,8*12($ctx)		# reload constants
++	fadd	$x3,$h3lo,$h3hi
++	 lfd	$s1hi,8*13($ctx)
++	fadd	$x2,$h2lo,$h2hi
++	 lfd	$r3lo,8*10($ctx)
++	fadd	$x0,$h0lo,$h0hi
++	 lfd	$r3hi,8*11($ctx)
++Lentry:
++	fmul	$h0lo,$s3lo,$x1
++	fmul	$h0hi,$s3hi,$x1
++	fmul	$h2lo,$r1lo,$x1
++	fmul	$h2hi,$r1hi,$x1
++	fmul	$h1lo,$r0lo,$x1
++	fmul	$h1hi,$r0hi,$x1
++	fmul	$h3lo,$r2lo,$x1
++	fmul	$h3hi,$r2hi,$x1
++
++	fmadd	$h0lo,$s1lo,$x3,$h0lo
++	fmadd	$h0hi,$s1hi,$x3,$h0hi
++	fmadd	$h2lo,$s3lo,$x3,$h2lo
++	fmadd	$h2hi,$s3hi,$x3,$h2hi
++	fmadd	$h1lo,$s2lo,$x3,$h1lo
++	fmadd	$h1hi,$s2hi,$x3,$h1hi
++	fmadd	$h3lo,$r0lo,$x3,$h3lo
++	fmadd	$h3hi,$r0hi,$x3,$h3hi
++
++	fmadd	$h0lo,$s2lo,$x2,$h0lo
++	fmadd	$h0hi,$s2hi,$x2,$h0hi
++	fmadd	$h2lo,$r0lo,$x2,$h2lo
++	fmadd	$h2hi,$r0hi,$x2,$h2hi
++	fmadd	$h1lo,$s3lo,$x2,$h1lo
++	fmadd	$h1hi,$s3hi,$x2,$h1hi
++	fmadd	$h3lo,$r1lo,$x2,$h3lo
++	fmadd	$h3hi,$r1hi,$x2,$h3hi
++
++	fmadd	$h0lo,$r0lo,$x0,$h0lo
++	 lfd	$y0,`$LOCALS+8*0`($sp)		# load [biased] input
++	fmadd	$h0hi,$r0hi,$x0,$h0hi
++	 lfd	$y1,`$LOCALS+8*1`($sp)
++	fmadd	$h2lo,$r2lo,$x0,$h2lo
++	 lfd	$y2,`$LOCALS+8*2`($sp)
++	fmadd	$h2hi,$r2hi,$x0,$h2hi
++	 lfd	$y3,`$LOCALS+8*3`($sp)
++	fmadd	$h1lo,$r1lo,$x0,$h1lo
++	fmadd	$h1hi,$r1hi,$x0,$h1hi
++	fmadd	$h3lo,$r3lo,$x0,$h3lo
++	fmadd	$h3hi,$r3hi,$x0,$h3hi
++
++	bdnz	Loop
++
++	######################################### base 2^48 -> base 2^32
++	fadd	$c0lo,$h0lo,$two32
++	fadd	$c0hi,$h0hi,$two32
++	fadd	$c2lo,$h2lo,$two96
++	fadd	$c2hi,$h2hi,$two96
++	fadd	$c1lo,$h1lo,$two64
++	fadd	$c1hi,$h1hi,$two64
++	fadd	$c3lo,$h3lo,$two130
++	fadd	$c3hi,$h3hi,$two130
++
++	fsub	$c0lo,$c0lo,$two32
++	fsub	$c0hi,$c0hi,$two32
++	fsub	$c2lo,$c2lo,$two96
++	fsub	$c2hi,$c2hi,$two96
++	fsub	$c1lo,$c1lo,$two64
++	fsub	$c1hi,$c1hi,$two64
++	fsub	$c3lo,$c3lo,$two130
++	fsub	$c3hi,$c3hi,$two130
++
++	fsub	$h1lo,$h1lo,$c1lo
++	fsub	$h1hi,$h1hi,$c1hi
++	fsub	$h3lo,$h3lo,$c3lo
++	fsub	$h3hi,$h3hi,$c3hi
++	fsub	$h2lo,$h2lo,$c2lo
++	fsub	$h2hi,$h2hi,$c2hi
++	fsub	$h0lo,$h0lo,$c0lo
++	fsub	$h0hi,$h0hi,$c0hi
++
++	fadd	$h1lo,$h1lo,$c0lo
++	fadd	$h1hi,$h1hi,$c0hi
++	fadd	$h3lo,$h3lo,$c2lo
++	fadd	$h3hi,$h3hi,$c2hi
++	fadd	$h2lo,$h2lo,$c1lo
++	fadd	$h2hi,$h2hi,$c1hi
++	fmadd	$h0lo,$c3lo,$five_two130,$h0lo
++	fmadd	$h0hi,$c3hi,$five_two130,$h0hi
++
++	fadd	$x1,$h1lo,$h1hi
++	fadd	$x3,$h3lo,$h3hi
++	fadd	$x2,$h2lo,$h2hi
++	fadd	$x0,$h0lo,$h0hi
++
++	lfd	$h0lo,`$LOCALS+8*4`($sp)	# pull saved fpscr
++	fadd	$x1,$x1,$two32			# bias
++	fadd	$x3,$x3,$two96
++	fadd	$x2,$x2,$two64
++	fadd	$x0,$x0,$two0
++
++	stfd	$x1,8*1($ctx)			# store [biased] hash value
++	stfd	$x3,8*3($ctx)
++	stfd	$x2,8*2($ctx)
++	stfd	$x0,8*0($ctx)
++
++	mtfsf	255,$h0lo			# restore original fpscr
++	lfd	f14,`$FRAME-8*18`($sp)
++	lfd	f15,`$FRAME-8*17`($sp)
++	lfd	f16,`$FRAME-8*16`($sp)
++	lfd	f17,`$FRAME-8*15`($sp)
++	lfd	f18,`$FRAME-8*14`($sp)
++	lfd	f19,`$FRAME-8*13`($sp)
++	lfd	f20,`$FRAME-8*12`($sp)
++	lfd	f21,`$FRAME-8*11`($sp)
++	lfd	f22,`$FRAME-8*10`($sp)
++	lfd	f23,`$FRAME-8*9`($sp)
++	lfd	f24,`$FRAME-8*8`($sp)
++	lfd	f25,`$FRAME-8*7`($sp)
++	lfd	f26,`$FRAME-8*6`($sp)
++	lfd	f27,`$FRAME-8*5`($sp)
++	lfd	f28,`$FRAME-8*4`($sp)
++	lfd	f29,`$FRAME-8*3`($sp)
++	lfd	f30,`$FRAME-8*2`($sp)
++	lfd	f31,`$FRAME-8*1`($sp)
++	addi	$sp,$sp,$FRAME
++Labort:
++	blr
++	.long	0
++	.byte	0,12,4,1,0x80,0,4,0
++.size	.poly1305_blocks_fpu,.-.poly1305_blocks_fpu
++___
++{
++my ($mac,$nonce)=($inp,$len);
++
++my ($h0,$h1,$h2,$h3,$h4, $d0,$d1,$d2,$d3
++   ) = map("r$_",(7..11,28..31));
++my $mask = "r0";
++my $FRAME = (6+4)*$SIZE_T;
++
++$code.=<<___;
++.globl	.poly1305_emit_fpu
++.align	4
++.poly1305_emit_fpu:
++	$STU	$sp,-$FRAME($sp)
++	mflr	r0
++	$PUSH	r28,`$FRAME-$SIZE_T*4`($sp)
++	$PUSH	r29,`$FRAME-$SIZE_T*3`($sp)
++	$PUSH	r30,`$FRAME-$SIZE_T*2`($sp)
++	$PUSH	r31,`$FRAME-$SIZE_T*1`($sp)
++	$PUSH	r0,`$FRAME+$LRSAVE`($sp)
++
++	lwz	$d0,`8*0+(0^$LITTLE_ENDIAN)`($ctx)	# load hash
++	lwz	$h0,`8*0+(4^$LITTLE_ENDIAN)`($ctx)
++	lwz	$d1,`8*1+(0^$LITTLE_ENDIAN)`($ctx)
++	lwz	$h1,`8*1+(4^$LITTLE_ENDIAN)`($ctx)
++	lwz	$d2,`8*2+(0^$LITTLE_ENDIAN)`($ctx)
++	lwz	$h2,`8*2+(4^$LITTLE_ENDIAN)`($ctx)
++	lwz	$d3,`8*3+(0^$LITTLE_ENDIAN)`($ctx)
++	lwz	$h3,`8*3+(4^$LITTLE_ENDIAN)`($ctx)
++
++	lis	$mask,0xfff0
++	andc	$d0,$d0,$mask			# mask exponent
++	andc	$d1,$d1,$mask
++	andc	$d2,$d2,$mask
++	andc	$d3,$d3,$mask			# can be partially reduced...
++	li	$mask,3
++
++	srwi	$padbit,$d3,2			# ... so reduce
++	and	$h4,$d3,$mask
++	andc	$d3,$d3,$mask
++	add	$d3,$d3,$padbit
++___
++						if ($SIZE_T==4) {
++$code.=<<___;
++	addc	$h0,$h0,$d3
++	adde	$h1,$h1,$d0
++	adde	$h2,$h2,$d1
++	adde	$h3,$h3,$d2
++	addze	$h4,$h4
++
++	addic	$d0,$h0,5			# compare to modulus
++	addze	$d1,$h1
++	addze	$d2,$h2
++	addze	$d3,$h3
++	addze	$mask,$h4
++
++	srwi	$mask,$mask,2			# did it carry/borrow?
++	neg	$mask,$mask
++	srawi	$mask,$mask,31			# mask
++
++	andc	$h0,$h0,$mask
++	and	$d0,$d0,$mask
++	andc	$h1,$h1,$mask
++	and	$d1,$d1,$mask
++	or	$h0,$h0,$d0
++	lwz	$d0,0($nonce)			# load nonce
++	andc	$h2,$h2,$mask
++	and	$d2,$d2,$mask
++	or	$h1,$h1,$d1
++	lwz	$d1,4($nonce)
++	andc	$h3,$h3,$mask
++	and	$d3,$d3,$mask
++	or	$h2,$h2,$d2
++	lwz	$d2,8($nonce)
++	or	$h3,$h3,$d3
++	lwz	$d3,12($nonce)
++
++	addc	$h0,$h0,$d0			# accumulate nonce
++	adde	$h1,$h1,$d1
++	adde	$h2,$h2,$d2
++	adde	$h3,$h3,$d3
++___
++						} else {
++$code.=<<___;
++	add	$h0,$h0,$d3
++	add	$h1,$h1,$d0
++	add	$h2,$h2,$d1
++	add	$h3,$h3,$d2
++
++	srdi	$d0,$h0,32
++	add	$h1,$h1,$d0
++	srdi	$d1,$h1,32
++	add	$h2,$h2,$d1
++	srdi	$d2,$h2,32
++	add	$h3,$h3,$d2
++	srdi	$d3,$h3,32
++	add	$h4,$h4,$d3
++
++	insrdi	$h0,$h1,32,0
++	insrdi	$h2,$h3,32,0
++
++	addic	$d0,$h0,5			# compare to modulus
++	addze	$d1,$h2
++	addze	$d2,$h4
++
++	srdi	$mask,$d2,2			# did it carry/borrow?
++	neg	$mask,$mask
++	sradi	$mask,$mask,63			# mask
++	ld	$d2,0($nonce)			# load nonce
++	ld	$d3,8($nonce)
++
++	andc	$h0,$h0,$mask
++	and	$d0,$d0,$mask
++	andc	$h2,$h2,$mask
++	and	$d1,$d1,$mask
++	or	$h0,$h0,$d0
++	or	$h2,$h2,$d1
++___
++$code.=<<___	if (!$LITTLE_ENDIAN);
++	rotldi	$d2,$d2,32			# flip nonce words
++	rotldi	$d3,$d3,32
++___
++$code.=<<___;
++	addc	$h0,$h0,$d2			# accumulate nonce
++	adde	$h2,$h2,$d3
++
++	srdi	$h1,$h0,32
++	srdi	$h3,$h2,32
++___
++						}
++$code.=<<___	if ($LITTLE_ENDIAN);
++	stw	$h0,0($mac)			# write result
++	stw	$h1,4($mac)
++	stw	$h2,8($mac)
++	stw	$h3,12($mac)
++___
++$code.=<<___	if (!$LITTLE_ENDIAN);
++	li	$d1,4
++	stwbrx	$h0,0,$mac			# write result
++	li	$d2,8
++	stwbrx	$h1,$d1,$mac
++	li	$d3,12
++	stwbrx	$h2,$d2,$mac
++	stwbrx	$h3,$d3,$mac
++___
++$code.=<<___;
++	$POP	r28,`$FRAME-$SIZE_T*4`($sp)
++	$POP	r29,`$FRAME-$SIZE_T*3`($sp)
++	$POP	r30,`$FRAME-$SIZE_T*2`($sp)
++	$POP	r31,`$FRAME-$SIZE_T*1`($sp)
++	addi	$sp,$sp,$FRAME
++	blr
++	.long	0
++	.byte	0,12,4,1,0x80,4,3,0
++.size	.poly1305_emit_fpu,.-.poly1305_emit_fpu
++___
++}
++# Ugly hack here, because PPC assembler syntax seem to vary too
++# much from platforms to platform...
++$code.=<<___;
++.align	6
++LPICmeup:
++	mflr	r0
++	bcl	20,31,\$+4
++	mflr	$len	# vvvvvv "distance" between . and 1st data entry
++	addi	$len,$len,`64-8`	# borrow $len
++	mtlr	r0
++	blr
++	.long	0
++	.byte	0,12,0x14,0,0,0,0,0
++	.space	`64-9*4`
++
++.quad	0x4330000000000000		# 2^(52+0)
++.quad	0x4530000000000000		# 2^(52+32)
++.quad	0x4730000000000000		# 2^(52+64)
++.quad	0x4930000000000000		# 2^(52+96)
++.quad	0x4b50000000000000		# 2^(52+130)
++
++.quad	0x37f4000000000000		# 5/2^130
++
++.quad	0x4430000000000000		# 2^(52+16+0)
++.quad	0x4630000000000000		# 2^(52+16+32)
++.quad	0x4830000000000000		# 2^(52+16+64)
++.quad	0x4a30000000000000		# 2^(52+16+96)
++.quad	0x3e30000000000000		# 2^(52+16+0-96)
++.quad	0x4030000000000000		# 2^(52+16+32-96)
++.quad	0x4230000000000000		# 2^(52+16+64-96)
++
++.quad	0x0000000000000001		# fpscr: truncate, no exceptions
++.asciz	"Poly1305 for PPC FPU, CRYPTOGAMS by "
++.align	4
++___
++
++$code =~ s/\`([^\`]*)\`/eval $1/gem;
++print $code;
++close STDOUT;
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/poly1305/asm/poly1305-s390x.pl b/CryptoPkg/Library/OpensslLib/openssl/crypto/poly1305/asm/poly1305-s390x.pl
+new file mode 100755
+index 0000000..82d757d
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/poly1305/asm/poly1305-s390x.pl
+@@ -0,0 +1,227 @@
++#! /usr/bin/env perl
++# Copyright 2016 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
++# in the file LICENSE in the source distribution or at
++# https://www.openssl.org/source/license.html
++
++#
++# ====================================================================
++# Written by Andy Polyakov  for the OpenSSL
++# project. The module is, however, dual licensed under OpenSSL and
++# CRYPTOGAMS licenses depending on where you obtain it. For further
++# details see http://www.openssl.org/~appro/cryptogams/.
++# ====================================================================
++#
++# This module implements Poly1305 hash for s390x.
++#
++# June 2015
++#
++# ~6.6/2.3 cpb on z10/z196+, >2x improvement over compiler-generated
++# code. For older compiler improvement coefficient is >3x, because
++# then base 2^64 and base 2^32 implementations are compared.
++#
++# On side note, z13 enables vector base 2^26 implementation...
++
++$flavour = shift;
++
++if ($flavour =~ /3[12]/) {
++	$SIZE_T=4;
++	$g="";
++} else {
++	$SIZE_T=8;
++	$g="g";
++}
++
++while (($output=shift) && ($output!~/\w[\w\-]*\.\w+$/)) {}
++open STDOUT,">$output";
++
++$sp="%r15";
++
++my ($ctx,$inp,$len,$padbit) = map("%r$_",(2..5));
++
++$code.=<<___;
++.text
++
++.globl	poly1305_init
++.type	poly1305_init,\@function
++.align	16
++poly1305_init:
++	lghi	%r0,0
++	lghi	%r1,-1
++	stg	%r0,0($ctx)		# zero hash value
++	stg	%r0,8($ctx)
++	stg	%r0,16($ctx)
++
++	cl${g}r	$inp,%r0
++	je	.Lno_key
++
++	lrvg	%r4,0($inp)		# load little-endian key
++	lrvg	%r5,8($inp)
++
++	nihl	%r1,0xffc0		# 0xffffffc0ffffffff
++	srlg	%r0,%r1,4		# 0x0ffffffc0fffffff
++	srlg	%r1,%r1,4
++	nill	%r1,0xfffc		# 0x0ffffffc0ffffffc
++
++	ngr	%r4,%r0
++	ngr	%r5,%r1
++
++	stg	%r4,32($ctx)
++	stg	%r5,40($ctx)
++
++.Lno_key:
++	lghi	%r2,0
++	br	%r14
++.size	poly1305_init,.-poly1305_init
++___
++{
++my ($d0hi,$d0lo,$d1hi,$d1lo,$t0,$h0,$t1,$h1,$h2) = map("%r$_",(6..14));
++my ($r0,$r1,$s1) = map("%r$_",(0..2));
++
++$code.=<<___;
++.globl	poly1305_blocks
++.type	poly1305_blocks,\@function
++.align	16
++poly1305_blocks:
++	srl${g}	$len,4			# fixed-up in 64-bit build
++	lghi	%r0,0
++	cl${g}r	$len,%r0
++	je	.Lno_data
++
++	stm${g}	%r6,%r14,`6*$SIZE_T`($sp)
++
++	llgfr   $padbit,$padbit		# clear upper half, much needed with
++					# non-64-bit ABI
++	lg	$r0,32($ctx)		# load key
++	lg	$r1,40($ctx)
++
++	lg	$h0,0($ctx)		# load hash value
++	lg	$h1,8($ctx)
++	lg	$h2,16($ctx)
++
++	st$g	$ctx,`2*$SIZE_T`($sp)	# off-load $ctx
++	srlg	$s1,$r1,2
++	algr	$s1,$r1			# s1 = r1 + r1>>2
++	j	.Loop
++
++.align	16
++.Loop:
++	lrvg	$d0lo,0($inp)		# load little-endian input
++	lrvg	$d1lo,8($inp)
++	la	$inp,16($inp)
++
++	algr	$d0lo,$h0		# accumulate input
++	alcgr	$d1lo,$h1
++
++	lgr	$h0,$d0lo
++	mlgr	$d0hi,$r0		# h0*r0	  -> $d0hi:$d0lo
++	lgr	$h1,$d1lo
++	mlgr	$d1hi,$s1		# h1*5*r1 -> $d1hi:$d1lo
++
++	mlgr	$t0,$r1			# h0*r1   -> $t0:$h0
++	mlgr	$t1,$r0			# h1*r0   -> $t1:$h1
++	alcgr	$h2,$padbit
++
++	algr	$d0lo,$d1lo
++	lgr	$d1lo,$h2
++	alcgr	$d0hi,$d1hi
++	lghi	$d1hi,0
++
++	algr	$h1,$h0
++	alcgr	$t1,$t0
++
++	msgr	$d1lo,$s1		# h2*s1
++	msgr	$h2,$r0			# h2*r0
++
++	algr	$h1,$d1lo
++	alcgr	$t1,$d1hi		# $d1hi is zero
++
++	algr	$h1,$d0hi
++	alcgr	$h2,$t1
++
++	lghi	$h0,-4			# final reduction step
++	ngr	$h0,$h2
++	srlg	$t0,$h2,2
++	algr	$h0,$t0
++	lghi	$t1,3
++	ngr	$h2,$t1
++
++	algr	$h0,$d0lo
++	alcgr	$h1,$d1hi		# $d1hi is still zero
++	alcgr	$h2,$d1hi		# $d1hi is still zero
++
++	brct$g	$len,.Loop
++
++	l$g	$ctx,`2*$SIZE_T`($sp)	# restore $ctx
++
++	stg	$h0,0($ctx)		# store hash value
++	stg	$h1,8($ctx)
++	stg	$h2,16($ctx)
++
++	lm${g}	%r6,%r14,`6*$SIZE_T`($sp)
++.Lno_data:
++	br	%r14
++.size	poly1305_blocks,.-poly1305_blocks
++___
++}
++{
++my ($mac,$nonce)=($inp,$len);
++my ($h0,$h1,$h2,$d0,$d1)=map("%r$_",(5..9));
++
++$code.=<<___;
++.globl	poly1305_emit
++.type	poly1305_emit,\@function
++.align	16
++poly1305_emit:
++	stm${g}	%r6,%r9,`6*$SIZE_T`($sp)
++
++	lg	$h0,0($ctx)
++	lg	$h1,8($ctx)
++	lg	$h2,16($ctx)
++
++	lghi	%r0,5
++	lghi	%r1,0
++	lgr	$d0,$h0
++	lgr	$d1,$h1
++
++	algr	$h0,%r0			# compare to modulus
++	alcgr	$h1,%r1
++	alcgr	$h2,%r1
++
++	srlg	$h2,$h2,2		# did it borrow/carry?
++	slgr	%r1,$h2			# 0-$h2>>2
++	lg	$h2,0($nonce)		# load nonce
++	lghi	%r0,-1
++	lg	$ctx,8($nonce)
++	xgr	%r0,%r1			# ~%r1
++
++	ngr	$h0,%r1
++	ngr	$d0,%r0
++	ngr	$h1,%r1
++	ngr	$d1,%r0
++	ogr	$h0,$d0
++	rllg	$d0,$h2,32		# flip nonce words
++	ogr	$h1,$d1
++	rllg	$d1,$ctx,32
++
++	algr	$h0,$d0			# accumulate nonce
++	alcgr	$h1,$d1
++
++	strvg	$h0,0($mac)		# write little-endian result
++	strvg	$h1,8($mac)
++
++	lm${g}	%r6,%r9,`6*$SIZE_T`($sp)
++	br	%r14
++.size	poly1305_emit,.-poly1305_emit
++
++.string	"Poly1305 for s390x, CRYPTOGAMS by "
++___
++}
++
++$code =~ s/\`([^\`]*)\`/eval $1/gem;
++$code =~ s/\b(srlg\s+)(%r[0-9]+\s*,)\s*([0-9]+)/$1$2$2$3/gm;
++
++print $code;
++close STDOUT;
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/poly1305/asm/poly1305-sparcv9.pl b/CryptoPkg/Library/OpensslLib/openssl/crypto/poly1305/asm/poly1305-sparcv9.pl
+new file mode 100755
+index 0000000..0bdd048
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/poly1305/asm/poly1305-sparcv9.pl
+@@ -0,0 +1,1120 @@
++#! /usr/bin/env perl
++# Copyright 2016 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
++# in the file LICENSE in the source distribution or at
++# https://www.openssl.org/source/license.html
++
++#
++# ====================================================================
++# Written by Andy Polyakov  for the OpenSSL
++# project. The module is, however, dual licensed under OpenSSL and
++# CRYPTOGAMS licenses depending on where you obtain it. For further
++# details see http://www.openssl.org/~appro/cryptogams/.
++# ====================================================================
++#
++# This module implements Poly1305 hash for SPARCv9, vanilla, as well
++# as VIS3 and FMA extensions.
++#
++# May, August 2015
++#
++# Numbers are cycles per processed byte with poly1305_blocks alone.
++#
++#			IALU(*)		FMA
++#
++# UltraSPARC III	12.3(**)
++# SPARC T3		7.92
++# SPARC T4		1.70(***)	6.55
++# SPARC64 X		5.60		3.64
++#
++# (*)	Comparison to compiler-generated code is really problematic,
++#	because latter's performance varies too much depending on too
++#	many variables. For example, one can measure from 5x to 15x
++#	improvement on T4 for gcc-4.6. Well, in T4 case it's a bit
++#	unfair comparison, because compiler doesn't use VIS3, but
++#	given same initial conditions coefficient varies from 3x to 9x.
++# (**)	Pre-III performance should be even worse; floating-point
++#	performance for UltraSPARC I-IV on the other hand is reported
++#	to be 4.25 for hand-coded assembly, but they are just too old
++#	to care about.
++# (***)	Multi-process benchmark saturates at ~12.5x single-process
++#	result on 8-core processor, or ~21GBps per 2.85GHz socket.
++
++my $output = pop;
++open STDOUT,">$output";
++
++my ($ctx,$inp,$len,$padbit,$shl,$shr)	= map("%i$_",(0..5));
++my ($r0,$r1,$r2,$r3,$s1,$s2,$s3,$h4)	= map("%l$_",(0..7));
++my ($h0,$h1,$h2,$h3, $t0,$t1,$t2)	= map("%o$_",(0..5,7));
++my ($d0,$d1,$d2,$d3)			= map("%g$_",(1..4));
++
++my $output = pop;
++open STDOUT,">$stdout";
++
++$code.=<<___;
++#include "sparc_arch.h"
++
++#ifdef	__arch64__
++.register	%g2,#scratch
++.register	%g3,#scratch
++# define	STPTR	stx
++# define	SIZE_T	8
++#else
++# define	STPTR	st
++# define	SIZE_T	4
++#endif
++#define	LOCALS	(STACK_BIAS+STACK_FRAME)
++
++.section	".text",#alloc,#execinstr
++
++#ifdef __PIC__
++SPARC_PIC_THUNK(%g1)
++#endif
++
++.globl	poly1305_init
++.align	32
++poly1305_init:
++	save	%sp,-STACK_FRAME-16,%sp
++	nop
++
++	SPARC_LOAD_ADDRESS(OPENSSL_sparcv9cap_P,%g1)
++	ld	[%g1],%g1
++
++	and	%g1,SPARCV9_FMADD|SPARCV9_VIS3,%g1
++	cmp	%g1,SPARCV9_FMADD
++	be	.Lpoly1305_init_fma
++	nop
++
++	stx	%g0,[$ctx+0]
++	stx	%g0,[$ctx+8]		! zero hash value
++	brz,pn	$inp,.Lno_key
++	stx	%g0,[$ctx+16]
++
++	and	$inp,7,$shr		! alignment factor
++	andn	$inp,7,$inp
++	sll	$shr,3,$shr		! *8
++	neg	$shr,$shl
++
++	sethi	%hi(0x0ffffffc),$t0
++	set	8,$h1
++	or	$t0,%lo(0x0ffffffc),$t0
++	set	16,$h2
++	sllx	$t0,32,$t1
++	or	$t0,$t1,$t1		! 0x0ffffffc0ffffffc
++	or	$t1,3,$t0		! 0x0ffffffc0fffffff
++
++	ldxa	[$inp+%g0]0x88,$h0	! load little-endian key
++	brz,pt	$shr,.Lkey_aligned
++	ldxa	[$inp+$h1]0x88,$h1
++
++	ldxa	[$inp+$h2]0x88,$h2
++	srlx	$h0,$shr,$h0
++	sllx	$h1,$shl,$t2
++	srlx	$h1,$shr,$h1
++	or	$t2,$h0,$h0
++	sllx	$h2,$shl,$h2
++	or	$h2,$h1,$h1
++
++.Lkey_aligned:
++	and	$t0,$h0,$h0
++	and	$t1,$h1,$h1
++	stx	$h0,[$ctx+32+0]		! store key
++	stx	$h1,[$ctx+32+8]
++
++	andcc	%g1,SPARCV9_VIS3,%g0
++	be	.Lno_key
++	nop
++
++1:	call	.+8
++	add	%o7,poly1305_blocks_vis3-1b,%o7
++
++	add	%o7,poly1305_emit-poly1305_blocks_vis3,%o5
++	STPTR	%o7,[%i2]
++	STPTR	%o5,[%i2+SIZE_T]
++
++	ret
++	restore	%g0,1,%o0		! return 1
++
++.Lno_key:
++	ret
++	restore	%g0,%g0,%o0		! return 0
++.type	poly1305_init,#function
++.size	poly1305_init,.-poly1305_init
++
++.globl	poly1305_blocks
++.align	32
++poly1305_blocks:
++	save	%sp,-STACK_FRAME,%sp
++	srln	$len,4,$len
++
++	brz,pn	$len,.Lno_data
++	nop
++
++	ld	[$ctx+32+0],$r1		! load key
++	ld	[$ctx+32+4],$r0
++	ld	[$ctx+32+8],$r3
++	ld	[$ctx+32+12],$r2
++
++	ld	[$ctx+0],$h1		! load hash value
++	ld	[$ctx+4],$h0
++	ld	[$ctx+8],$h3
++	ld	[$ctx+12],$h2
++	ld	[$ctx+16],$h4
++
++	and	$inp,7,$shr		! alignment factor
++	andn	$inp,7,$inp
++	set	8,$d1
++	sll	$shr,3,$shr		! *8
++	set	16,$d2
++	neg	$shr,$shl
++
++	srl	$r1,2,$s1
++	srl	$r2,2,$s2
++	add	$r1,$s1,$s1
++	srl	$r3,2,$s3
++	add	$r2,$s2,$s2
++	add	$r3,$s3,$s3
++
++.Loop:
++	ldxa	[$inp+%g0]0x88,$d0	! load little-endian input
++	brz,pt	$shr,.Linp_aligned
++	ldxa	[$inp+$d1]0x88,$d1
++
++	ldxa	[$inp+$d2]0x88,$d2
++	srlx	$d0,$shr,$d0
++	sllx	$d1,$shl,$t1
++	srlx	$d1,$shr,$d1
++	or	$t1,$d0,$d0
++	sllx	$d2,$shl,$d2
++	or	$d2,$d1,$d1
++
++.Linp_aligned:
++	srlx	$d0,32,$t0
++	addcc	$d0,$h0,$h0		! accumulate input
++	srlx	$d1,32,$t1
++	addccc	$t0,$h1,$h1
++	addccc	$d1,$h2,$h2
++	addccc	$t1,$h3,$h3
++	addc	$padbit,$h4,$h4
++
++	umul	$r0,$h0,$d0
++	umul	$r1,$h0,$d1
++	umul	$r2,$h0,$d2
++	umul	$r3,$h0,$d3
++	 sub	$len,1,$len
++	 add	$inp,16,$inp
++
++	umul	$s3,$h1,$t0
++	umul	$r0,$h1,$t1
++	umul	$r1,$h1,$t2
++	add	$t0,$d0,$d0
++	add	$t1,$d1,$d1
++	umul	$r2,$h1,$t0
++	add	$t2,$d2,$d2
++	add	$t0,$d3,$d3
++
++	umul	$s2,$h2,$t1
++	umul	$s3,$h2,$t2
++	umul	$r0,$h2,$t0
++	add	$t1,$d0,$d0
++	add	$t2,$d1,$d1
++	umul	$r1,$h2,$t1
++	add	$t0,$d2,$d2
++	add	$t1,$d3,$d3
++
++	umul	$s1,$h3,$t2
++	umul	$s2,$h3,$t0
++	umul	$s3,$h3,$t1
++	add	$t2,$d0,$d0
++	add	$t0,$d1,$d1
++	umul	$r0,$h3,$t2
++	add	$t1,$d2,$d2
++	add	$t2,$d3,$d3
++
++	umul	$s1,$h4,$t0
++	umul	$s2,$h4,$t1
++	umul	$s3,$h4,$t2
++	umul	$r0,$h4,$h4
++	add	$t0,$d1,$d1
++	add	$t1,$d2,$d2
++	srlx	$d0,32,$h1
++	add	$t2,$d3,$d3
++	srlx	$d1,32,$h2
++
++	addcc	$d1,$h1,$h1
++	srlx	$d2,32,$h3
++	 set	8,$d1
++	addccc	$d2,$h2,$h2
++	srlx	$d3,32,$t0
++	 set	16,$d2
++	addccc	$d3,$h3,$h3
++	addc	$t0,$h4,$h4
++
++	srl	$h4,2,$t0		! final reduction step
++	andn	$h4,3,$t1
++	and	$h4,3,$h4
++	add	$t1,$t0,$t0
++
++	addcc	$t0,$d0,$h0
++	addccc	%g0,$h1,$h1
++	addccc	%g0,$h2,$h2
++	addccc	%g0,$h3,$h3
++	brnz,pt	$len,.Loop
++	addc	%g0,$h4,$h4
++
++	st	$h1,[$ctx+0]		! store hash value
++	st	$h0,[$ctx+4]
++	st	$h3,[$ctx+8]
++	st	$h2,[$ctx+12]
++	st	$h4,[$ctx+16]
++
++.Lno_data:
++	ret
++	restore
++.type	poly1305_blocks,#function
++.size	poly1305_blocks,.-poly1305_blocks
++___
++########################################################################
++# VIS3 has umulxhi and addxc...
++{
++my ($H0,$H1,$H2,$R0,$R1,$S1,$T1) = map("%o$_",(0..5,7));
++my ($D0,$D1,$D2,$T0) = map("%g$_",(1..4));
++
++$code.=<<___;
++.align	32
++poly1305_blocks_vis3:
++	save	%sp,-STACK_FRAME,%sp
++	srln	$len,4,$len
++
++	brz,pn	$len,.Lno_data
++	nop
++
++	ldx	[$ctx+32+0],$R0		! load key
++	ldx	[$ctx+32+8],$R1
++
++	ldx	[$ctx+0],$H0		! load hash value
++	ldx	[$ctx+8],$H1
++	ld	[$ctx+16],$H2
++
++	and	$inp,7,$shr		! alignment factor
++	andn	$inp,7,$inp
++	set	8,$r1
++	sll	$shr,3,$shr		! *8
++	set	16,$r2
++	neg	$shr,$shl
++
++	srlx	$R1,2,$S1
++	b	.Loop_vis3
++	add	$R1,$S1,$S1
++
++.Loop_vis3:
++	ldxa	[$inp+%g0]0x88,$D0	! load little-endian input
++	brz,pt	$shr,.Linp_aligned_vis3
++	ldxa	[$inp+$r1]0x88,$D1
++
++	ldxa	[$inp+$r2]0x88,$D2
++	srlx	$D0,$shr,$D0
++	sllx	$D1,$shl,$T1
++	srlx	$D1,$shr,$D1
++	or	$T1,$D0,$D0
++	sllx	$D2,$shl,$D2
++	or	$D2,$D1,$D1
++
++.Linp_aligned_vis3:
++	addcc	$D0,$H0,$H0		! accumulate input
++	 sub	$len,1,$len
++	addxccc	$D1,$H1,$H1
++	 add	$inp,16,$inp
++
++	mulx	$R0,$H0,$D0		! r0*h0
++	addxc	$padbit,$H2,$H2
++	umulxhi	$R0,$H0,$D1
++	mulx	$S1,$H1,$T0		! s1*h1
++	umulxhi	$S1,$H1,$T1
++	addcc	$T0,$D0,$D0
++	mulx	$R1,$H0,$T0		! r1*h0
++	addxc	$T1,$D1,$D1
++	umulxhi	$R1,$H0,$D2
++	addcc	$T0,$D1,$D1
++	mulx	$R0,$H1,$T0		! r0*h1
++	addxc	%g0,$D2,$D2
++	umulxhi	$R0,$H1,$T1
++	addcc	$T0,$D1,$D1
++	mulx	$S1,$H2,$T0		! s1*h2
++	addxc	$T1,$D2,$D2
++	mulx	$R0,$H2,$T1		! r0*h2
++	addcc	$T0,$D1,$D1
++	addxc	$T1,$D2,$D2
++
++	srlx	$D2,2,$T0		! final reduction step
++	andn	$D2,3,$T1
++	and	$D2,3,$H2
++	add	$T1,$T0,$T0
++
++	addcc	$T0,$D0,$H0
++	addxccc	%g0,$D1,$H1
++	brnz,pt	$len,.Loop_vis3
++	addxc	%g0,$H2,$H2
++
++	stx	$H0,[$ctx+0]		! store hash value
++	stx	$H1,[$ctx+8]
++	st	$H2,[$ctx+16]
++
++	ret
++	restore
++.type	poly1305_blocks_vis3,#function
++.size	poly1305_blocks_vis3,.-poly1305_blocks_vis3
++___
++}
++my ($mac,$nonce) = ($inp,$len);
++
++$code.=<<___;
++.globl	poly1305_emit
++.align	32
++poly1305_emit:
++	save	%sp,-STACK_FRAME,%sp
++
++	ld	[$ctx+0],$h1		! load hash value
++	ld	[$ctx+4],$h0
++	ld	[$ctx+8],$h3
++	ld	[$ctx+12],$h2
++	ld	[$ctx+16],$h4
++
++	addcc	$h0,5,$r0		! compare to modulus
++	addccc	$h1,0,$r1
++	addccc	$h2,0,$r2
++	addccc	$h3,0,$r3
++	addc	$h4,0,$h4
++	andcc	$h4,4,%g0		! did it carry/borrow?
++
++	movnz	%icc,$r0,$h0
++	ld	[$nonce+0],$r0		! load nonce
++	movnz	%icc,$r1,$h1
++	ld	[$nonce+4],$r1
++	movnz	%icc,$r2,$h2
++	ld	[$nonce+8],$r2
++	movnz	%icc,$r3,$h3
++	ld	[$nonce+12],$r3
++
++	addcc	$r0,$h0,$h0		! accumulate nonce
++	addccc	$r1,$h1,$h1
++	addccc	$r2,$h2,$h2
++	addc	$r3,$h3,$h3
++
++	srl	$h0,8,$r0
++	stb	$h0,[$mac+0]		! store little-endian result
++	srl	$h0,16,$r1
++	stb	$r0,[$mac+1]
++	srl	$h0,24,$r2
++	stb	$r1,[$mac+2]
++	stb	$r2,[$mac+3]
++
++	srl	$h1,8,$r0
++	stb	$h1,[$mac+4]
++	srl	$h1,16,$r1
++	stb	$r0,[$mac+5]
++	srl	$h1,24,$r2
++	stb	$r1,[$mac+6]
++	stb	$r2,[$mac+7]
++
++	srl	$h2,8,$r0
++	stb	$h2,[$mac+8]
++	srl	$h2,16,$r1
++	stb	$r0,[$mac+9]
++	srl	$h2,24,$r2
++	stb	$r1,[$mac+10]
++	stb	$r2,[$mac+11]
++
++	srl	$h3,8,$r0
++	stb	$h3,[$mac+12]
++	srl	$h3,16,$r1
++	stb	$r0,[$mac+13]
++	srl	$h3,24,$r2
++	stb	$r1,[$mac+14]
++	stb	$r2,[$mac+15]
++
++	ret
++	restore
++.type	poly1305_emit,#function
++.size	poly1305_emit,.-poly1305_emit
++___
++
++{
++my ($ctx,$inp,$len,$padbit) = map("%i$_",(0..3));
++my ($in0,$in1,$in2,$in3,$in4) = map("%o$_",(0..4));
++my ($i1,$step,$shr,$shl) = map("%l$_",(0..7));
++my $i2=$step;
++
++my ($h0lo,$h0hi,$h1lo,$h1hi,$h2lo,$h2hi,$h3lo,$h3hi,
++    $two0,$two32,$two64,$two96,$two130,$five_two130,
++    $r0lo,$r0hi,$r1lo,$r1hi,$r2lo,$r2hi,
++    $s2lo,$s2hi,$s3lo,$s3hi,
++    $c0lo,$c0hi,$c1lo,$c1hi,$c2lo,$c2hi,$c3lo,$c3hi) = map("%f".2*$_,(0..31));
++# borrowings
++my ($r3lo,$r3hi,$s1lo,$s1hi) = ($c0lo,$c0hi,$c1lo,$c1hi);
++my ($x0,$x1,$x2,$x3) = ($c2lo,$c2hi,$c3lo,$c3hi);
++my ($y0,$y1,$y2,$y3) = ($c1lo,$c1hi,$c3hi,$c3lo);
++
++$code.=<<___;
++.align	32
++poly1305_init_fma:
++	save	%sp,-STACK_FRAME-16,%sp
++	nop
++
++.Lpoly1305_init_fma:
++1:	call	.+8
++	add	%o7,.Lconsts_fma-1b,%o7
++
++	ldd	[%o7+8*0],$two0			! load constants
++	ldd	[%o7+8*1],$two32
++	ldd	[%o7+8*2],$two64
++	ldd	[%o7+8*3],$two96
++	ldd	[%o7+8*5],$five_two130
++
++	std	$two0,[$ctx+8*0]		! initial hash value, biased 0
++	std	$two32,[$ctx+8*1]
++	std	$two64,[$ctx+8*2]
++	std	$two96,[$ctx+8*3]
++
++	brz,pn	$inp,.Lno_key_fma
++	nop
++
++	stx	%fsr,[%sp+LOCALS]		! save original %fsr
++	ldx	[%o7+8*6],%fsr			! load new %fsr
++
++	std	$two0,[$ctx+8*4] 		! key "template"
++	std	$two32,[$ctx+8*5]
++	std	$two64,[$ctx+8*6]
++	std	$two96,[$ctx+8*7]
++
++	and	$inp,7,$shr
++	andn	$inp,7,$inp			! align pointer
++	mov	8,$i1
++	sll	$shr,3,$shr
++	mov	16,$i2
++	neg	$shr,$shl
++
++	ldxa	[$inp+%g0]0x88,$in0		! load little-endian key
++	ldxa	[$inp+$i1]0x88,$in2
++
++	brz	$shr,.Lkey_aligned_fma
++	sethi	%hi(0xf0000000),$i1		!   0xf0000000
++
++	ldxa	[$inp+$i2]0x88,$in4
++
++	srlx	$in0,$shr,$in0			! align data
++	sllx	$in2,$shl,$in1
++	srlx	$in2,$shr,$in2
++	or	$in1,$in0,$in0
++	sllx	$in4,$shl,$in3
++	or	$in3,$in2,$in2
++
++.Lkey_aligned_fma:
++	or	$i1,3,$i2			!   0xf0000003
++	srlx	$in0,32,$in1
++	andn	$in0,$i1,$in0			! &=0x0fffffff
++	andn	$in1,$i2,$in1			! &=0x0ffffffc
++	srlx	$in2,32,$in3
++	andn	$in2,$i2,$in2
++	andn	$in3,$i2,$in3
++
++	st	$in0,[$ctx+`8*4+4`]		! fill "template"
++	st	$in1,[$ctx+`8*5+4`]
++	st	$in2,[$ctx+`8*6+4`]
++	st	$in3,[$ctx+`8*7+4`]
++
++	ldd	[$ctx+8*4],$h0lo 		! load [biased] key
++	ldd	[$ctx+8*5],$h1lo
++	ldd	[$ctx+8*6],$h2lo
++	ldd	[$ctx+8*7],$h3lo
++
++	fsubd	$h0lo,$two0, $h0lo		! r0
++	 ldd	[%o7+8*7],$two0 		! more constants
++	fsubd	$h1lo,$two32,$h1lo		! r1
++	 ldd	[%o7+8*8],$two32
++	fsubd	$h2lo,$two64,$h2lo		! r2
++	 ldd	[%o7+8*9],$two64
++	fsubd	$h3lo,$two96,$h3lo		! r3
++	 ldd	[%o7+8*10],$two96
++
++	fmuld	$five_two130,$h1lo,$s1lo	! s1
++	fmuld	$five_two130,$h2lo,$s2lo	! s2
++	fmuld	$five_two130,$h3lo,$s3lo	! s3
++
++	faddd	$h0lo,$two0, $h0hi
++	faddd	$h1lo,$two32,$h1hi
++	faddd	$h2lo,$two64,$h2hi
++	faddd	$h3lo,$two96,$h3hi
++
++	fsubd	$h0hi,$two0, $h0hi
++	 ldd	[%o7+8*11],$two0		! more constants
++	fsubd	$h1hi,$two32,$h1hi
++	 ldd	[%o7+8*12],$two32
++	fsubd	$h2hi,$two64,$h2hi
++	 ldd	[%o7+8*13],$two64
++	fsubd	$h3hi,$two96,$h3hi
++
++	fsubd	$h0lo,$h0hi,$h0lo
++	 std	$h0hi,[$ctx+8*5] 		! r0hi
++	fsubd	$h1lo,$h1hi,$h1lo
++	 std	$h1hi,[$ctx+8*7] 		! r1hi
++	fsubd	$h2lo,$h2hi,$h2lo
++	 std	$h2hi,[$ctx+8*9] 		! r2hi
++	fsubd	$h3lo,$h3hi,$h3lo
++	 std	$h3hi,[$ctx+8*11]		! r3hi
++
++	faddd	$s1lo,$two0, $s1hi
++	faddd	$s2lo,$two32,$s2hi
++	faddd	$s3lo,$two64,$s3hi
++
++	fsubd	$s1hi,$two0, $s1hi
++	fsubd	$s2hi,$two32,$s2hi
++	fsubd	$s3hi,$two64,$s3hi
++
++	fsubd	$s1lo,$s1hi,$s1lo
++	fsubd	$s2lo,$s2hi,$s2lo
++	fsubd	$s3lo,$s3hi,$s3lo
++
++	ldx	[%sp+LOCALS],%fsr		! restore %fsr
++
++	std	$h0lo,[$ctx+8*4] 		! r0lo
++	std	$h1lo,[$ctx+8*6] 		! r1lo
++	std	$h2lo,[$ctx+8*8] 		! r2lo
++	std	$h3lo,[$ctx+8*10]		! r3lo
++
++	std	$s1hi,[$ctx+8*13]
++	std	$s2hi,[$ctx+8*15]
++	std	$s3hi,[$ctx+8*17]
++
++	std	$s1lo,[$ctx+8*12]
++	std	$s2lo,[$ctx+8*14]
++	std	$s3lo,[$ctx+8*16]
++
++	add	%o7,poly1305_blocks_fma-.Lconsts_fma,%o0
++	add	%o7,poly1305_emit_fma-.Lconsts_fma,%o1
++	STPTR	%o0,[%i2]
++	STPTR	%o1,[%i2+SIZE_T]
++
++	ret
++	restore	%g0,1,%o0			! return 1
++
++.Lno_key_fma:
++	ret
++	restore	%g0,%g0,%o0			! return 0
++.type	poly1305_init_fma,#function
++.size	poly1305_init_fma,.-poly1305_init_fma
++
++.align	32
++poly1305_blocks_fma:
++	save	%sp,-STACK_FRAME-48,%sp
++	srln	$len,4,$len
++
++	brz,pn	$len,.Labort
++	sub	$len,1,$len
++
++1:	call	.+8
++	add	%o7,.Lconsts_fma-1b,%o7
++
++	ldd	[%o7+8*0],$two0			! load constants
++	ldd	[%o7+8*1],$two32
++	ldd	[%o7+8*2],$two64
++	ldd	[%o7+8*3],$two96
++	ldd	[%o7+8*4],$two130
++	ldd	[%o7+8*5],$five_two130
++
++	ldd	[$ctx+8*0],$h0lo 		! load [biased] hash value
++	ldd	[$ctx+8*1],$h1lo
++	ldd	[$ctx+8*2],$h2lo
++	ldd	[$ctx+8*3],$h3lo
++
++	std	$two0,[%sp+LOCALS+8*0]		! input "template"
++	sethi	%hi((1023+52+96)<<20),$in3
++	std	$two32,[%sp+LOCALS+8*1]
++	or	$padbit,$in3,$in3
++	std	$two64,[%sp+LOCALS+8*2]
++	st	$in3,[%sp+LOCALS+8*3]
++
++	and	$inp,7,$shr
++	andn	$inp,7,$inp			! align pointer
++	mov	8,$i1
++	sll	$shr,3,$shr
++	mov	16,$step
++	neg	$shr,$shl
++
++	ldxa	[$inp+%g0]0x88,$in0		! load little-endian input
++	brz	$shr,.Linp_aligned_fma
++	ldxa	[$inp+$i1]0x88,$in2
++
++	ldxa	[$inp+$step]0x88,$in4
++	add	$inp,8,$inp
++
++	srlx	$in0,$shr,$in0			! align data
++	sllx	$in2,$shl,$in1
++	srlx	$in2,$shr,$in2
++	or	$in1,$in0,$in0
++	sllx	$in4,$shl,$in3
++	srlx	$in4,$shr,$in4			! pre-shift
++	or	$in3,$in2,$in2
++
++.Linp_aligned_fma:
++	srlx	$in0,32,$in1
++	movrz	$len,0,$step
++	srlx	$in2,32,$in3
++	add	$step,$inp,$inp			! conditional advance
++
++	st	$in0,[%sp+LOCALS+8*0+4]		! fill "template"
++	st	$in1,[%sp+LOCALS+8*1+4]
++	st	$in2,[%sp+LOCALS+8*2+4]
++	st	$in3,[%sp+LOCALS+8*3+4]
++
++	ldd	[$ctx+8*4],$r0lo 		! load key
++	ldd	[$ctx+8*5],$r0hi
++	ldd	[$ctx+8*6],$r1lo
++	ldd	[$ctx+8*7],$r1hi
++	ldd	[$ctx+8*8],$r2lo
++	ldd	[$ctx+8*9],$r2hi
++	ldd	[$ctx+8*10],$r3lo
++	ldd	[$ctx+8*11],$r3hi
++	ldd	[$ctx+8*12],$s1lo
++	ldd	[$ctx+8*13],$s1hi
++	ldd	[$ctx+8*14],$s2lo
++	ldd	[$ctx+8*15],$s2hi
++	ldd	[$ctx+8*16],$s3lo
++	ldd	[$ctx+8*17],$s3hi
++
++	stx	%fsr,[%sp+LOCALS+8*4]		! save original %fsr
++	ldx	[%o7+8*6],%fsr			! load new %fsr
++
++	subcc	$len,1,$len
++	movrz	$len,0,$step
++
++	ldd	[%sp+LOCALS+8*0],$x0		! load biased input
++	ldd	[%sp+LOCALS+8*1],$x1
++	ldd	[%sp+LOCALS+8*2],$x2
++	ldd	[%sp+LOCALS+8*3],$x3
++
++	fsubd	$h0lo,$two0, $h0lo		! de-bias hash value
++	fsubd	$h1lo,$two32,$h1lo
++	 ldxa	[$inp+%g0]0x88,$in0		! modulo-scheduled input load
++	fsubd	$h2lo,$two64,$h2lo
++	fsubd	$h3lo,$two96,$h3lo
++	 ldxa	[$inp+$i1]0x88,$in2
++
++	fsubd	$x0,$two0, $x0  		! de-bias input
++	fsubd	$x1,$two32,$x1
++	fsubd	$x2,$two64,$x2
++	fsubd	$x3,$two96,$x3
++
++	brz	$shr,.Linp_aligned_fma2
++	add	$step,$inp,$inp			! conditional advance
++
++	sllx	$in0,$shl,$in1			! align data
++	srlx	$in0,$shr,$in3
++	or	$in1,$in4,$in0
++	sllx	$in2,$shl,$in1
++	srlx	$in2,$shr,$in4			! pre-shift
++	or	$in3,$in1,$in2
++.Linp_aligned_fma2:
++	srlx	$in0,32,$in1
++	srlx	$in2,32,$in3
++
++	faddd	$h0lo,$x0,$x0			! accumulate input
++	 stw	$in0,[%sp+LOCALS+8*0+4]
++	faddd	$h1lo,$x1,$x1
++	 stw	$in1,[%sp+LOCALS+8*1+4]
++	faddd	$h2lo,$x2,$x2
++	 stw	$in2,[%sp+LOCALS+8*2+4]
++	faddd	$h3lo,$x3,$x3
++	 stw	$in3,[%sp+LOCALS+8*3+4]
++
++	b	.Lentry_fma
++	nop
++
++.align	16
++.Loop_fma:
++	ldxa	[$inp+%g0]0x88,$in0		! modulo-scheduled input load
++	ldxa	[$inp+$i1]0x88,$in2
++	movrz	$len,0,$step
++
++	faddd	$y0,$h0lo,$h0lo 		! accumulate input
++	faddd	$y1,$h0hi,$h0hi
++	faddd	$y2,$h2lo,$h2lo
++	faddd	$y3,$h2hi,$h2hi
++
++	brz,pn	$shr,.Linp_aligned_fma3
++	add	$step,$inp,$inp			! conditional advance
++
++	sllx	$in0,$shl,$in1			! align data
++	srlx	$in0,$shr,$in3
++	or	$in1,$in4,$in0
++	sllx	$in2,$shl,$in1
++	srlx	$in2,$shr,$in4			! pre-shift
++	or	$in3,$in1,$in2
++
++.Linp_aligned_fma3:
++	!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! base 2^48 -> base 2^32
++	faddd	$two64,$h1lo,$c1lo
++	 srlx	$in0,32,$in1
++	faddd	$two64,$h1hi,$c1hi
++	 srlx	$in2,32,$in3
++	faddd	$two130,$h3lo,$c3lo
++	 st	$in0,[%sp+LOCALS+8*0+4]		! fill "template"
++	faddd	$two130,$h3hi,$c3hi
++	 st	$in1,[%sp+LOCALS+8*1+4]
++	faddd	$two32,$h0lo,$c0lo
++	 st	$in2,[%sp+LOCALS+8*2+4]
++	faddd	$two32,$h0hi,$c0hi
++	 st	$in3,[%sp+LOCALS+8*3+4]
++	faddd	$two96,$h2lo,$c2lo
++	faddd	$two96,$h2hi,$c2hi
++
++	fsubd	$c1lo,$two64,$c1lo
++	fsubd	$c1hi,$two64,$c1hi
++	fsubd	$c3lo,$two130,$c3lo
++	fsubd	$c3hi,$two130,$c3hi
++	fsubd	$c0lo,$two32,$c0lo
++	fsubd	$c0hi,$two32,$c0hi
++	fsubd	$c2lo,$two96,$c2lo
++	fsubd	$c2hi,$two96,$c2hi
++
++	fsubd	$h1lo,$c1lo,$h1lo
++	fsubd	$h1hi,$c1hi,$h1hi
++	fsubd	$h3lo,$c3lo,$h3lo
++	fsubd	$h3hi,$c3hi,$h3hi
++	fsubd	$h2lo,$c2lo,$h2lo
++	fsubd	$h2hi,$c2hi,$h2hi
++	fsubd	$h0lo,$c0lo,$h0lo
++	fsubd	$h0hi,$c0hi,$h0hi
++
++	faddd	$h1lo,$c0lo,$h1lo
++	faddd	$h1hi,$c0hi,$h1hi
++	faddd	$h3lo,$c2lo,$h3lo
++	faddd	$h3hi,$c2hi,$h3hi
++	faddd	$h2lo,$c1lo,$h2lo
++	faddd	$h2hi,$c1hi,$h2hi
++	fmaddd	$five_two130,$c3lo,$h0lo,$h0lo
++	fmaddd	$five_two130,$c3hi,$h0hi,$h0hi
++
++	faddd	$h1lo,$h1hi,$x1
++	 ldd	[$ctx+8*12],$s1lo		! reload constants
++	faddd	$h3lo,$h3hi,$x3
++	 ldd	[$ctx+8*13],$s1hi
++	faddd	$h2lo,$h2hi,$x2
++	 ldd	[$ctx+8*10],$r3lo
++	faddd	$h0lo,$h0hi,$x0
++	 ldd	[$ctx+8*11],$r3hi
++
++.Lentry_fma:
++	fmuld	$x1,$s3lo,$h0lo
++	fmuld	$x1,$s3hi,$h0hi
++	fmuld	$x1,$r1lo,$h2lo
++	fmuld	$x1,$r1hi,$h2hi
++	fmuld	$x1,$r0lo,$h1lo
++	fmuld	$x1,$r0hi,$h1hi
++	fmuld	$x1,$r2lo,$h3lo
++	fmuld	$x1,$r2hi,$h3hi
++
++	fmaddd	$x3,$s1lo,$h0lo,$h0lo
++	fmaddd	$x3,$s1hi,$h0hi,$h0hi
++	fmaddd	$x3,$s3lo,$h2lo,$h2lo
++	fmaddd	$x3,$s3hi,$h2hi,$h2hi
++	fmaddd	$x3,$s2lo,$h1lo,$h1lo
++	fmaddd	$x3,$s2hi,$h1hi,$h1hi
++	fmaddd	$x3,$r0lo,$h3lo,$h3lo
++	fmaddd	$x3,$r0hi,$h3hi,$h3hi
++
++	fmaddd	$x2,$s2lo,$h0lo,$h0lo
++	fmaddd	$x2,$s2hi,$h0hi,$h0hi
++	fmaddd	$x2,$r0lo,$h2lo,$h2lo
++	fmaddd	$x2,$r0hi,$h2hi,$h2hi
++	fmaddd	$x2,$s3lo,$h1lo,$h1lo
++	 ldd	[%sp+LOCALS+8*0],$y0		! load [biased] input
++	fmaddd	$x2,$s3hi,$h1hi,$h1hi
++	 ldd	[%sp+LOCALS+8*1],$y1
++	fmaddd	$x2,$r1lo,$h3lo,$h3lo
++	 ldd	[%sp+LOCALS+8*2],$y2
++	fmaddd	$x2,$r1hi,$h3hi,$h3hi
++	 ldd	[%sp+LOCALS+8*3],$y3
++
++	fmaddd	$x0,$r0lo,$h0lo,$h0lo
++	 fsubd	$y0,$two0, $y0  		! de-bias input
++	fmaddd	$x0,$r0hi,$h0hi,$h0hi
++	 fsubd	$y1,$two32,$y1
++	fmaddd	$x0,$r2lo,$h2lo,$h2lo
++	 fsubd	$y2,$two64,$y2
++	fmaddd	$x0,$r2hi,$h2hi,$h2hi
++	 fsubd	$y3,$two96,$y3
++	fmaddd	$x0,$r1lo,$h1lo,$h1lo
++	fmaddd	$x0,$r1hi,$h1hi,$h1hi
++	fmaddd	$x0,$r3lo,$h3lo,$h3lo
++	fmaddd	$x0,$r3hi,$h3hi,$h3hi
++
++	bcc	SIZE_T_CC,.Loop_fma
++	subcc	$len,1,$len
++
++	!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! base 2^48 -> base 2^32
++	faddd	$h0lo,$two32,$c0lo
++	faddd	$h0hi,$two32,$c0hi
++	faddd	$h2lo,$two96,$c2lo
++	faddd	$h2hi,$two96,$c2hi
++	faddd	$h1lo,$two64,$c1lo
++	faddd	$h1hi,$two64,$c1hi
++	faddd	$h3lo,$two130,$c3lo
++	faddd	$h3hi,$two130,$c3hi
++
++	fsubd	$c0lo,$two32,$c0lo
++	fsubd	$c0hi,$two32,$c0hi
++	fsubd	$c2lo,$two96,$c2lo
++	fsubd	$c2hi,$two96,$c2hi
++	fsubd	$c1lo,$two64,$c1lo
++	fsubd	$c1hi,$two64,$c1hi
++	fsubd	$c3lo,$two130,$c3lo
++	fsubd	$c3hi,$two130,$c3hi
++
++	fsubd	$h1lo,$c1lo,$h1lo
++	fsubd	$h1hi,$c1hi,$h1hi
++	fsubd	$h3lo,$c3lo,$h3lo
++	fsubd	$h3hi,$c3hi,$h3hi
++	fsubd	$h2lo,$c2lo,$h2lo
++	fsubd	$h2hi,$c2hi,$h2hi
++	fsubd	$h0lo,$c0lo,$h0lo
++	fsubd	$h0hi,$c0hi,$h0hi
++
++	faddd	$h1lo,$c0lo,$h1lo
++	faddd	$h1hi,$c0hi,$h1hi
++	faddd	$h3lo,$c2lo,$h3lo
++	faddd	$h3hi,$c2hi,$h3hi
++	faddd	$h2lo,$c1lo,$h2lo
++	faddd	$h2hi,$c1hi,$h2hi
++	fmaddd	$five_two130,$c3lo,$h0lo,$h0lo
++	fmaddd	$five_two130,$c3hi,$h0hi,$h0hi
++
++	faddd	$h1lo,$h1hi,$x1
++	faddd	$h3lo,$h3hi,$x3
++	faddd	$h2lo,$h2hi,$x2
++	faddd	$h0lo,$h0hi,$x0
++
++	faddd	$x1,$two32,$x1  		! bias
++	faddd	$x3,$two96,$x3
++	faddd	$x2,$two64,$x2
++	faddd	$x0,$two0, $x0
++
++	ldx	[%sp+LOCALS+8*4],%fsr		! restore saved %fsr
++
++	std	$x1,[$ctx+8*1]			! store [biased] hash value
++	std	$x3,[$ctx+8*3]
++	std	$x2,[$ctx+8*2]
++	std	$x0,[$ctx+8*0]
++
++.Labort:
++	ret
++	restore
++.type	poly1305_blocks_fma,#function
++.size	poly1305_blocks_fma,.-poly1305_blocks_fma
++___
++{
++my ($mac,$nonce)=($inp,$len);
++
++my ($h0,$h1,$h2,$h3,$h4, $d0,$d1,$d2,$d3, $mask
++   ) = (map("%l$_",(0..5)),map("%o$_",(0..4)));
++
++$code.=<<___;
++.align	32
++poly1305_emit_fma:
++	save	%sp,-STACK_FRAME,%sp
++
++	ld	[$ctx+8*0+0],$d0		! load hash
++	ld	[$ctx+8*0+4],$h0
++	ld	[$ctx+8*1+0],$d1
++	ld	[$ctx+8*1+4],$h1
++	ld	[$ctx+8*2+0],$d2
++	ld	[$ctx+8*2+4],$h2
++	ld	[$ctx+8*3+0],$d3
++	ld	[$ctx+8*3+4],$h3
++
++	sethi	%hi(0xfff00000),$mask
++	andn	$d0,$mask,$d0			! mask exponent
++	andn	$d1,$mask,$d1
++	andn	$d2,$mask,$d2
++	andn	$d3,$mask,$d3			! can be partially reduced...
++	mov	3,$mask
++
++	srl	$d3,2,$padbit			! ... so reduce
++	and	$d3,$mask,$h4
++	andn	$d3,$mask,$d3
++	add	$padbit,$d3,$d3
++
++	addcc	$d3,$h0,$h0
++	addccc	$d0,$h1,$h1
++	addccc	$d1,$h2,$h2
++	addccc	$d2,$h3,$h3
++	addc	%g0,$h4,$h4
++
++	addcc	$h0,5,$d0			! compare to modulus
++	addccc	$h1,0,$d1
++	addccc	$h2,0,$d2
++	addccc	$h3,0,$d3
++	addc	$h4,0,$mask
++
++	srl	$mask,2,$mask			! did it carry/borrow?
++	neg	$mask,$mask
++	sra	$mask,31,$mask			! mask
++
++	andn	$h0,$mask,$h0
++	and	$d0,$mask,$d0
++	andn	$h1,$mask,$h1
++	and	$d1,$mask,$d1
++	or	$d0,$h0,$h0
++	ld	[$nonce+0],$d0			! load nonce
++	andn	$h2,$mask,$h2
++	and	$d2,$mask,$d2
++	or	$d1,$h1,$h1
++	ld	[$nonce+4],$d1
++	andn	$h3,$mask,$h3
++	and	$d3,$mask,$d3
++	or	$d2,$h2,$h2
++	ld	[$nonce+8],$d2
++	or	$d3,$h3,$h3
++	ld	[$nonce+12],$d3
++
++	addcc	$d0,$h0,$h0			! accumulate nonce
++	addccc	$d1,$h1,$h1
++	addccc	$d2,$h2,$h2
++	addc	$d3,$h3,$h3
++
++	stb	$h0,[$mac+0]			! write little-endian result
++	srl	$h0,8,$h0
++	stb	$h1,[$mac+4]
++	srl	$h1,8,$h1
++	stb	$h2,[$mac+8]
++	srl	$h2,8,$h2
++	stb	$h3,[$mac+12]
++	srl	$h3,8,$h3
++
++	stb	$h0,[$mac+1]
++	srl	$h0,8,$h0
++	stb	$h1,[$mac+5]
++	srl	$h1,8,$h1
++	stb	$h2,[$mac+9]
++	srl	$h2,8,$h2
++	stb	$h3,[$mac+13]
++	srl	$h3,8,$h3
++
++	stb	$h0,[$mac+2]
++	srl	$h0,8,$h0
++	stb	$h1,[$mac+6]
++	srl	$h1,8,$h1
++	stb	$h2,[$mac+10]
++	srl	$h2,8,$h2
++	stb	$h3,[$mac+14]
++	srl	$h3,8,$h3
++
++	stb	$h0,[$mac+3]
++	stb	$h1,[$mac+7]
++	stb	$h2,[$mac+11]
++	stb	$h3,[$mac+15]
++
++	ret
++	restore
++.type	poly1305_emit_fma,#function
++.size	poly1305_emit_fma,.-poly1305_emit_fma
++___
++}
++
++$code.=<<___;
++.align	64
++.Lconsts_fma:
++.word	0x43300000,0x00000000		! 2^(52+0)
++.word	0x45300000,0x00000000		! 2^(52+32)
++.word	0x47300000,0x00000000		! 2^(52+64)
++.word	0x49300000,0x00000000		! 2^(52+96)
++.word	0x4b500000,0x00000000		! 2^(52+130)
++
++.word	0x37f40000,0x00000000		! 5/2^130
++.word	0,1<<30				! fsr: truncate, no exceptions
++
++.word	0x44300000,0x00000000		! 2^(52+16+0)
++.word	0x46300000,0x00000000		! 2^(52+16+32)
++.word	0x48300000,0x00000000		! 2^(52+16+64)
++.word	0x4a300000,0x00000000		! 2^(52+16+96)
++.word	0x3e300000,0x00000000		! 2^(52+16+0-96)
++.word	0x40300000,0x00000000		! 2^(52+16+32-96)
++.word	0x42300000,0x00000000		! 2^(52+16+64-96)
++.asciz	"Poly1305 for SPARCv9/VIS3/FMA, CRYPTOGAMS by "
++.align	4
++___
++}
++
++# Purpose of these subroutines is to explicitly encode VIS instructions,
++# so that one can compile the module without having to specify VIS
++# extensions on compiler command line, e.g. -xarch=v9 vs. -xarch=v9a.
++# Idea is to reserve for option to produce "universal" binary and let
++# programmer detect if current CPU is VIS capable at run-time.
++sub unvis3 {
++my ($mnemonic,$rs1,$rs2,$rd)=@_;
++my %bias = ( "g" => 0, "o" => 8, "l" => 16, "i" => 24 );
++my ($ref,$opf);
++my %visopf = (	"addxc"		=> 0x011,
++		"addxccc"	=> 0x013,
++		"umulxhi"	=> 0x016	);
++
++    $ref = "$mnemonic\t$rs1,$rs2,$rd";
++
++    if ($opf=$visopf{$mnemonic}) {
++	foreach ($rs1,$rs2,$rd) {
++	    return $ref if (!/%([goli])([0-9])/);
++	    $_=$bias{$1}+$2;
++	}
++
++	return	sprintf ".word\t0x%08x !%s",
++			0x81b00000|$rd<<25|$rs1<<14|$opf<<5|$rs2,
++			$ref;
++    } else {
++	return $ref;
++    }
++}
++
++sub unfma {
++my ($mnemonic,$rs1,$rs2,$rs3,$rd)=@_;
++my ($ref,$opf);
++my %fmaopf = (	"fmadds"	=> 0x1,
++		"fmaddd"	=> 0x2,
++		"fmsubs"	=> 0x5,
++		"fmsubd"	=> 0x6		);
++
++    $ref = "$mnemonic\t$rs1,$rs2,$rs3,$rd";
++
++    if ($opf=$fmaopf{$mnemonic}) {
++	foreach ($rs1,$rs2,$rs3,$rd) {
++	    return $ref if (!/%f([0-9]{1,2})/);
++	    $_=$1;
++	    if ($1>=32) {
++		return $ref if ($1&1);
++		# re-encode for upper double register addressing
++		$_=($1|$1>>5)&31;
++	    }
++	}
++
++	return	sprintf ".word\t0x%08x !%s",
++			0x81b80000|$rd<<25|$rs1<<14|$rs3<<9|$opf<<5|$rs2,
++			$ref;
++    } else {
++	return $ref;
++    }
++}
++
++foreach (split("\n",$code)) {
++	s/\`([^\`]*)\`/eval $1/ge;
++
++	s/\b(umulxhi|addxc[c]{0,2})\s+(%[goli][0-7]),\s*(%[goli][0-7]),\s*(%[goli][0-7])/
++		&unvis3($1,$2,$3,$4)
++	 /ge	or
++	s/\b(fmadd[sd])\s+(%f[0-9]+),\s*(%f[0-9]+),\s*(%f[0-9]+),\s*(%f[0-9]+)/
++		&unfma($1,$2,$3,$4,$5)
++	 /ge;
++
++	print $_,"\n";
++}
++
++close STDOUT;
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/poly1305/asm/poly1305-x86.pl b/CryptoPkg/Library/OpensslLib/openssl/crypto/poly1305/asm/poly1305-x86.pl
+new file mode 100755
+index 0000000..ab24dfc
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/poly1305/asm/poly1305-x86.pl
+@@ -0,0 +1,1814 @@
++#! /usr/bin/env perl
++# Copyright 2016 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
++# in the file LICENSE in the source distribution or at
++# https://www.openssl.org/source/license.html
++
++#
++# ====================================================================
++# Written by Andy Polyakov  for the OpenSSL
++# project. The module is, however, dual licensed under OpenSSL and
++# CRYPTOGAMS licenses depending on where you obtain it. For further
++# details see http://www.openssl.org/~appro/cryptogams/.
++# ====================================================================
++#
++# This module implements Poly1305 hash for x86.
++#
++# April 2015
++#
++# Numbers are cycles per processed byte with poly1305_blocks alone,
++# measured with rdtsc at fixed clock frequency.
++#
++#		IALU/gcc-3.4(*)	SSE2(**)	AVX2
++# Pentium	15.7/+80%	-
++# PIII		6.21/+90%	-
++# P4		19.8/+40%	3.24
++# Core 2	4.85/+90%	1.80
++# Westmere	4.58/+100%	1.43
++# Sandy Bridge	3.90/+100%	1.36
++# Haswell	3.88/+70%	1.18		0.72
++# Silvermont	11.0/+40%	4.80
++# Goldmont	4.10/+200%	2.10
++# VIA Nano	6.71/+90%	2.47
++# Sledgehammer	3.51/+180%	4.27
++# Bulldozer	4.53/+140%	1.31
++#
++# (*)	gcc 4.8 for some reason generated worse code;
++# (**)	besides SSE2 there are floating-point and AVX options; FP
++#	is deemed unnecessary, because pre-SSE2 processor are too
++#	old to care about, while it's not the fastest option on
++#	SSE2-capable ones; AVX is omitted, because it doesn't give
++#	a lot of improvement, 5-10% depending on processor;
++
++$0 =~ m/(.*[\/\\])[^\/\\]+$/; $dir=$1;
++push(@INC,"${dir}","${dir}../../perlasm");
++require "x86asm.pl";
++
++$output=pop;
++open STDOUT,">$output";
++
++&asm_init($ARGV[0],"poly1305-x86.pl",$ARGV[$#ARGV] eq "386");
++
++$sse2=$avx=0;
++for (@ARGV) { $sse2=1 if (/-DOPENSSL_IA32_SSE2/); }
++
++if ($sse2) {
++	&static_label("const_sse2");
++	&static_label("enter_blocks");
++	&static_label("enter_emit");
++	&external_label("OPENSSL_ia32cap_P");
++
++	if (`$ENV{CC} -Wa,-v -c -o /dev/null -x assembler /dev/null 2>&1`
++			=~ /GNU assembler version ([2-9]\.[0-9]+)/) {
++		$avx = ($1>=2.19) + ($1>=2.22);
++	}
++
++	if (!$avx && $ARGV[0] eq "win32n" &&
++	   `nasm -v 2>&1` =~ /NASM version ([2-9]\.[0-9]+)/) {
++	$avx = ($1>=2.09) + ($1>=2.10);
++	}
++
++	if (!$avx && `$ENV{CC} -v 2>&1` =~ /(^clang version|based on LLVM) ([3-9]\.[0-9]+)/) {
++		$avx = ($2>=3.0) + ($2>3.0);
++	}
++}
++
++########################################################################
++# Layout of opaque area is following.
++#
++#	unsigned __int32 h[5];		# current hash value base 2^32
++#	unsigned __int32 pad;		# is_base2_26 in vector context
++#	unsigned __int32 r[4];		# key value base 2^32
++
++&align(64);
++&function_begin("poly1305_init");
++	&mov	("edi",&wparam(0));		# context
++	&mov	("esi",&wparam(1));		# key
++	&mov	("ebp",&wparam(2));		# function table
++
++	&xor	("eax","eax");
++	&mov	(&DWP(4*0,"edi"),"eax");	# zero hash value
++	&mov	(&DWP(4*1,"edi"),"eax");
++	&mov	(&DWP(4*2,"edi"),"eax");
++	&mov	(&DWP(4*3,"edi"),"eax");
++	&mov	(&DWP(4*4,"edi"),"eax");
++	&mov	(&DWP(4*5,"edi"),"eax");	# is_base2_26
++
++	&cmp	("esi",0);
++	&je	(&label("nokey"));
++
++    if ($sse2) {
++	&call	(&label("pic_point"));
++    &set_label("pic_point");
++	&blindpop("ebx");
++
++	&lea	("eax",&DWP("poly1305_blocks-".&label("pic_point"),"ebx"));
++	&lea	("edx",&DWP("poly1305_emit-".&label("pic_point"),"ebx"));
++
++	&picmeup("edi","OPENSSL_ia32cap_P","ebx",&label("pic_point"));
++	&mov	("ecx",&DWP(0,"edi"));
++	&and	("ecx",1<<26|1<<24);
++	&cmp	("ecx",1<<26|1<<24);		# SSE2 and XMM?
++	&jne	(&label("no_sse2"));
++
++	&lea	("eax",&DWP("_poly1305_blocks_sse2-".&label("pic_point"),"ebx"));
++	&lea	("edx",&DWP("_poly1305_emit_sse2-".&label("pic_point"),"ebx"));
++
++      if ($avx>1) {
++	&mov	("ecx",&DWP(8,"edi"));
++	&test	("ecx",1<<5);			# AVX2?
++	&jz	(&label("no_sse2"));
++
++	&lea	("eax",&DWP("_poly1305_blocks_avx2-".&label("pic_point"),"ebx"));
++      }
++    &set_label("no_sse2");
++	&mov	("edi",&wparam(0));		# reload context
++	&mov	(&DWP(0,"ebp"),"eax");		# fill function table
++	&mov	(&DWP(4,"ebp"),"edx");
++    }
++
++	&mov	("eax",&DWP(4*0,"esi"));	# load input key
++	&mov	("ebx",&DWP(4*1,"esi"));
++	&mov	("ecx",&DWP(4*2,"esi"));
++	&mov	("edx",&DWP(4*3,"esi"));
++	&and	("eax",0x0fffffff);
++	&and	("ebx",0x0ffffffc);
++	&and	("ecx",0x0ffffffc);
++	&and	("edx",0x0ffffffc);
++	&mov	(&DWP(4*6,"edi"),"eax");
++	&mov	(&DWP(4*7,"edi"),"ebx");
++	&mov	(&DWP(4*8,"edi"),"ecx");
++	&mov	(&DWP(4*9,"edi"),"edx");
++
++	&mov	("eax",$sse2);
++&set_label("nokey");
++&function_end("poly1305_init");
++
++($h0,$h1,$h2,$h3,$h4,
++ $d0,$d1,$d2,$d3,
++ $r0,$r1,$r2,$r3,
++     $s1,$s2,$s3)=map(4*$_,(0..15));
++
++&function_begin("poly1305_blocks");
++	&mov	("edi",&wparam(0));		# ctx
++	&mov	("esi",&wparam(1));		# inp
++	&mov	("ecx",&wparam(2));		# len
++&set_label("enter_blocks");
++	&and	("ecx",-15);
++	&jz	(&label("nodata"));
++
++	&stack_push(16);
++	&mov	("eax",&DWP(4*6,"edi"));	# r0
++	&mov	("ebx",&DWP(4*7,"edi"));	# r1
++	 &lea	("ebp",&DWP(0,"esi","ecx"));	# end of input
++	&mov	("ecx",&DWP(4*8,"edi"));	# r2
++	&mov	("edx",&DWP(4*9,"edi"));	# r3
++
++	&mov	(&wparam(2),"ebp");
++	&mov	("ebp","esi");
++
++	&mov	(&DWP($r0,"esp"),"eax");	# r0
++	&mov	("eax","ebx");
++	&shr	("eax",2);
++	&mov	(&DWP($r1,"esp"),"ebx");	# r1
++	&add	("eax","ebx");			# s1
++	&mov	("ebx","ecx");
++	&shr	("ebx",2);
++	&mov	(&DWP($r2,"esp"),"ecx");	# r2
++	&add	("ebx","ecx");			# s2
++	&mov	("ecx","edx");
++	&shr	("ecx",2);
++	&mov	(&DWP($r3,"esp"),"edx");	# r3
++	&add	("ecx","edx");			# s3
++	&mov	(&DWP($s1,"esp"),"eax");	# s1
++	&mov	(&DWP($s2,"esp"),"ebx");	# s2
++	&mov	(&DWP($s3,"esp"),"ecx");	# s3
++
++	&mov	("eax",&DWP(4*0,"edi"));	# load hash value
++	&mov	("ebx",&DWP(4*1,"edi"));
++	&mov	("ecx",&DWP(4*2,"edi"));
++	&mov	("esi",&DWP(4*3,"edi"));
++	&mov	("edi",&DWP(4*4,"edi"));
++	&jmp	(&label("loop"));
++
++&set_label("loop",32);
++	&add	("eax",&DWP(4*0,"ebp"));	# accumulate input
++	&adc	("ebx",&DWP(4*1,"ebp"));
++	&adc	("ecx",&DWP(4*2,"ebp"));
++	&adc	("esi",&DWP(4*3,"ebp"));
++	&lea	("ebp",&DWP(4*4,"ebp"));
++	&adc	("edi",&wparam(3));		# padbit
++
++	&mov	(&DWP($h0,"esp"),"eax");	# put aside hash[+inp]
++	&mov	(&DWP($h3,"esp"),"esi");
++
++	&mul	(&DWP($r0,"esp"));		# h0*r0
++	 &mov	(&DWP($h4,"esp"),"edi");
++	&mov	("edi","eax");
++	&mov	("eax","ebx");			# h1
++	&mov	("esi","edx");
++	&mul	(&DWP($s3,"esp"));		# h1*s3
++	&add	("edi","eax");
++	&mov	("eax","ecx");			# h2
++	&adc	("esi","edx");
++	&mul	(&DWP($s2,"esp"));		# h2*s2
++	&add	("edi","eax");
++	&mov	("eax",&DWP($h3,"esp"));
++	&adc	("esi","edx");
++	&mul	(&DWP($s1,"esp"));		# h3*s1
++	&add	("edi","eax");
++	 &mov	("eax",&DWP($h0,"esp"));
++	&adc	("esi","edx");
++
++	&mul	(&DWP($r1,"esp"));		# h0*r1
++	 &mov	(&DWP($d0,"esp"),"edi");
++	&xor	("edi","edi");
++	&add	("esi","eax");
++	&mov	("eax","ebx");			# h1
++	&adc	("edi","edx");
++	&mul	(&DWP($r0,"esp"));		# h1*r0
++	&add	("esi","eax");
++	&mov	("eax","ecx");			# h2
++	&adc	("edi","edx");
++	&mul	(&DWP($s3,"esp"));		# h2*s3
++	&add	("esi","eax");
++	&mov	("eax",&DWP($h3,"esp"));
++	&adc	("edi","edx");
++	&mul	(&DWP($s2,"esp"));		# h3*s2
++	&add	("esi","eax");
++	&mov	("eax",&DWP($h4,"esp"));
++	&adc	("edi","edx");
++	&imul	("eax",&DWP($s1,"esp"));	# h4*s1
++	&add	("esi","eax");
++	 &mov	("eax",&DWP($h0,"esp"));
++	&adc	("edi",0);
++
++	&mul	(&DWP($r2,"esp"));		# h0*r2
++	 &mov	(&DWP($d1,"esp"),"esi");
++	&xor	("esi","esi");
++	&add	("edi","eax");
++	&mov	("eax","ebx");			# h1
++	&adc	("esi","edx");
++	&mul	(&DWP($r1,"esp"));		# h1*r1
++	&add	("edi","eax");
++	&mov	("eax","ecx");			# h2
++	&adc	("esi","edx");
++	&mul	(&DWP($r0,"esp"));		# h2*r0
++	&add	("edi","eax");
++	&mov	("eax",&DWP($h3,"esp"));
++	&adc	("esi","edx");
++	&mul	(&DWP($s3,"esp"));		# h3*s3
++	&add	("edi","eax");
++	&mov	("eax",&DWP($h4,"esp"));
++	&adc	("esi","edx");
++	&imul	("eax",&DWP($s2,"esp"));	# h4*s2
++	&add	("edi","eax");
++	 &mov	("eax",&DWP($h0,"esp"));
++	&adc	("esi",0);
++
++	&mul	(&DWP($r3,"esp"));		# h0*r3
++	 &mov	(&DWP($d2,"esp"),"edi");
++	&xor	("edi","edi");
++	&add	("esi","eax");
++	&mov	("eax","ebx");			# h1
++	&adc	("edi","edx");
++	&mul	(&DWP($r2,"esp"));		# h1*r2
++	&add	("esi","eax");
++	&mov	("eax","ecx");			# h2
++	&adc	("edi","edx");
++	&mul	(&DWP($r1,"esp"));		# h2*r1
++	&add	("esi","eax");
++	&mov	("eax",&DWP($h3,"esp"));
++	&adc	("edi","edx");
++	&mul	(&DWP($r0,"esp"));		# h3*r0
++	&add	("esi","eax");
++	 &mov	("ecx",&DWP($h4,"esp"));
++	&adc	("edi","edx");
++
++	&mov	("edx","ecx");
++	&imul	("ecx",&DWP($s3,"esp"));	# h4*s3
++	&add	("esi","ecx");
++	 &mov	("eax",&DWP($d0,"esp"));
++	&adc	("edi",0);
++
++	&imul	("edx",&DWP($r0,"esp"));	# h4*r0
++	&add	("edx","edi");
++
++	&mov	("ebx",&DWP($d1,"esp"));
++	&mov	("ecx",&DWP($d2,"esp"));
++
++	&mov	("edi","edx");			# last reduction step
++	&shr	("edx",2);
++	&and	("edi",3);
++	&lea	("edx",&DWP(0,"edx","edx",4));	# *5
++	&add	("eax","edx");
++	&adc	("ebx",0);
++	&adc	("ecx",0);
++	&adc	("esi",0);
++	&adc	("edi",0);
++
++	&cmp	("ebp",&wparam(2));		# done yet?
++	&jne	(&label("loop"));
++
++	&mov	("edx",&wparam(0));		# ctx
++	&stack_pop(16);
++	&mov	(&DWP(4*0,"edx"),"eax");	# store hash value
++	&mov	(&DWP(4*1,"edx"),"ebx");
++	&mov	(&DWP(4*2,"edx"),"ecx");
++	&mov	(&DWP(4*3,"edx"),"esi");
++	&mov	(&DWP(4*4,"edx"),"edi");
++&set_label("nodata");
++&function_end("poly1305_blocks");
++
++&function_begin("poly1305_emit");
++	&mov	("ebp",&wparam(0));		# context
++&set_label("enter_emit");
++	&mov	("edi",&wparam(1));		# output
++	&mov	("eax",&DWP(4*0,"ebp"));	# load hash value
++	&mov	("ebx",&DWP(4*1,"ebp"));
++	&mov	("ecx",&DWP(4*2,"ebp"));
++	&mov	("edx",&DWP(4*3,"ebp"));
++	&mov	("esi",&DWP(4*4,"ebp"));
++
++	&add	("eax",5);			# compare to modulus
++	&adc	("ebx",0);
++	&adc	("ecx",0);
++	&adc	("edx",0);
++	&adc	("esi",0);
++	&shr	("esi",2);			# did it carry/borrow?
++	&neg	("esi");			# do we choose hash-modulus?
++
++	&and	("eax","esi");
++	&and	("ebx","esi");
++	&and	("ecx","esi");
++	&and	("edx","esi");
++	&mov	(&DWP(4*0,"edi"),"eax");
++	&mov	(&DWP(4*1,"edi"),"ebx");
++	&mov	(&DWP(4*2,"edi"),"ecx");
++	&mov	(&DWP(4*3,"edi"),"edx");
++
++	¬	("esi");			# or original hash value?
++	&mov	("eax",&DWP(4*0,"ebp"));
++	&mov	("ebx",&DWP(4*1,"ebp"));
++	&mov	("ecx",&DWP(4*2,"ebp"));
++	&mov	("edx",&DWP(4*3,"ebp"));
++	&mov	("ebp",&wparam(2));
++	&and	("eax","esi");
++	&and	("ebx","esi");
++	&and	("ecx","esi");
++	&and	("edx","esi");
++	&or	("eax",&DWP(4*0,"edi"));
++	&or	("ebx",&DWP(4*1,"edi"));
++	&or	("ecx",&DWP(4*2,"edi"));
++	&or	("edx",&DWP(4*3,"edi"));
++
++	&add	("eax",&DWP(4*0,"ebp"));	# accumulate key
++	&adc	("ebx",&DWP(4*1,"ebp"));
++	&adc	("ecx",&DWP(4*2,"ebp"));
++	&adc	("edx",&DWP(4*3,"ebp"));
++
++	&mov	(&DWP(4*0,"edi"),"eax");
++	&mov	(&DWP(4*1,"edi"),"ebx");
++	&mov	(&DWP(4*2,"edi"),"ecx");
++	&mov	(&DWP(4*3,"edi"),"edx");
++&function_end("poly1305_emit");
++
++if ($sse2) {
++########################################################################
++# Layout of opaque area is following.
++#
++#	unsigned __int32 h[5];		# current hash value base 2^26
++#	unsigned __int32 is_base2_26;
++#	unsigned __int32 r[4];		# key value base 2^32
++#	unsigned __int32 pad[2];
++#	struct { unsigned __int32 r^4, r^3, r^2, r^1; } r[9];
++#
++# where r^n are base 2^26 digits of degrees of multiplier key. There are
++# 5 digits, but last four are interleaved with multiples of 5, totalling
++# in 9 elements: r0, r1, 5*r1, r2, 5*r2, r3, 5*r3, r4, 5*r4.
++
++my ($D0,$D1,$D2,$D3,$D4,$T0,$T1,$T2)=map("xmm$_",(0..7));
++my $MASK=$T2;	# borrow and keep in mind
++
++&align	(32);
++&function_begin_B("_poly1305_init_sse2");
++	&movdqu		($D4,&QWP(4*6,"edi"));		# key base 2^32
++	&lea		("edi",&DWP(16*3,"edi"));	# size optimization
++	&mov		("ebp","esp");
++	&sub		("esp",16*(9+5));
++	&and		("esp",-16);
++
++	#&pand		($D4,&QWP(96,"ebx"));		# magic mask
++	&movq		($MASK,&QWP(64,"ebx"));
++
++	&movdqa		($D0,$D4);
++	&movdqa		($D1,$D4);
++	&movdqa		($D2,$D4);
++
++	&pand		($D0,$MASK);			# -> base 2^26
++	&psrlq		($D1,26);
++	&psrldq		($D2,6);
++	&pand		($D1,$MASK);
++	&movdqa		($D3,$D2);
++	&psrlq		($D2,4)
++	&psrlq		($D3,30);
++	&pand		($D2,$MASK);
++	&pand		($D3,$MASK);
++	&psrldq		($D4,13);
++
++	&lea		("edx",&DWP(16*9,"esp"));	# size optimization
++	&mov		("ecx",2);
++&set_label("square");
++	&movdqa		(&QWP(16*0,"esp"),$D0);
++	&movdqa		(&QWP(16*1,"esp"),$D1);
++	&movdqa		(&QWP(16*2,"esp"),$D2);
++	&movdqa		(&QWP(16*3,"esp"),$D3);
++	&movdqa		(&QWP(16*4,"esp"),$D4);
++
++	&movdqa		($T1,$D1);
++	&movdqa		($T0,$D2);
++	&pslld		($T1,2);
++	&pslld		($T0,2);
++	&paddd		($T1,$D1);			# *5
++	&paddd		($T0,$D2);			# *5
++	&movdqa		(&QWP(16*5,"esp"),$T1);
++	&movdqa		(&QWP(16*6,"esp"),$T0);
++	&movdqa		($T1,$D3);
++	&movdqa		($T0,$D4);
++	&pslld		($T1,2);
++	&pslld		($T0,2);
++	&paddd		($T1,$D3);			# *5
++	&paddd		($T0,$D4);			# *5
++	&movdqa		(&QWP(16*7,"esp"),$T1);
++	&movdqa		(&QWP(16*8,"esp"),$T0);
++
++	&pshufd		($T1,$D0,0b01000100);
++	&movdqa		($T0,$D1);
++	&pshufd		($D1,$D1,0b01000100);
++	&pshufd		($D2,$D2,0b01000100);
++	&pshufd		($D3,$D3,0b01000100);
++	&pshufd		($D4,$D4,0b01000100);
++	&movdqa		(&QWP(16*0,"edx"),$T1);
++	&movdqa		(&QWP(16*1,"edx"),$D1);
++	&movdqa		(&QWP(16*2,"edx"),$D2);
++	&movdqa		(&QWP(16*3,"edx"),$D3);
++	&movdqa		(&QWP(16*4,"edx"),$D4);
++
++	################################################################
++	# d4 = h4*r0 + h3*r1   + h2*r2   + h1*r3   + h0*r4
++	# d3 = h3*r0 + h2*r1   + h1*r2   + h0*r3   + h4*5*r4
++	# d2 = h2*r0 + h1*r1   + h0*r2   + h4*5*r3 + h3*5*r4
++	# d1 = h1*r0 + h0*r1   + h4*5*r2 + h3*5*r3 + h2*5*r4
++	# d0 = h0*r0 + h4*5*r1 + h3*5*r2 + h2*5*r3 + h1*5*r4
++
++	&pmuludq	($D4,$D0);			# h4*r0
++	&pmuludq	($D3,$D0);			# h3*r0
++	&pmuludq	($D2,$D0);			# h2*r0
++	&pmuludq	($D1,$D0);			# h1*r0
++	&pmuludq	($D0,$T1);			# h0*r0
++
++sub pmuladd {
++my $load = shift;
++my $base = shift; $base = "esp" if (!defined($base));
++
++	################################################################
++	# As for choice to "rotate" $T0-$T2 in order to move paddq
++	# past next multiplication. While it makes code harder to read
++	# and doesn't have significant effect on most processors, it
++	# makes a lot of difference on Atom, up to 30% improvement.
++
++	&movdqa		($T1,$T0);
++	&pmuludq	($T0,&QWP(16*3,$base));		# r1*h3
++	&movdqa		($T2,$T1);
++	&pmuludq	($T1,&QWP(16*2,$base));		# r1*h2
++	&paddq		($D4,$T0);
++	&movdqa		($T0,$T2);
++	&pmuludq	($T2,&QWP(16*1,$base));		# r1*h1
++	&paddq		($D3,$T1);
++	&$load		($T1,5);			# s1
++	&pmuludq	($T0,&QWP(16*0,$base));		# r1*h0
++	&paddq		($D2,$T2);
++	&pmuludq	($T1,&QWP(16*4,$base));		# s1*h4
++	 &$load		($T2,2);			# r2^n
++	&paddq		($D1,$T0);
++
++	&movdqa		($T0,$T2);
++	&pmuludq	($T2,&QWP(16*2,$base));		# r2*h2
++	 &paddq		($D0,$T1);
++	&movdqa		($T1,$T0);
++	&pmuludq	($T0,&QWP(16*1,$base));		# r2*h1
++	&paddq		($D4,$T2);
++	&$load		($T2,6);			# s2^n
++	&pmuludq	($T1,&QWP(16*0,$base));		# r2*h0
++	&paddq		($D3,$T0);
++	&movdqa		($T0,$T2);
++	&pmuludq	($T2,&QWP(16*4,$base));		# s2*h4
++	&paddq		($D2,$T1);
++	&pmuludq	($T0,&QWP(16*3,$base));		# s2*h3
++	 &$load		($T1,3);			# r3^n
++	&paddq		($D1,$T2);
++
++	&movdqa		($T2,$T1);
++	&pmuludq	($T1,&QWP(16*1,$base));		# r3*h1
++	 &paddq		($D0,$T0);
++	&$load		($T0,7);			# s3^n
++	&pmuludq	($T2,&QWP(16*0,$base));		# r3*h0
++	&paddq		($D4,$T1);
++	&movdqa		($T1,$T0);
++	&pmuludq	($T0,&QWP(16*4,$base));		# s3*h4
++	&paddq		($D3,$T2);
++	&movdqa		($T2,$T1);
++	&pmuludq	($T1,&QWP(16*3,$base));		# s3*h3
++	&paddq		($D2,$T0);
++	&pmuludq	($T2,&QWP(16*2,$base));		# s3*h2
++	 &$load		($T0,4);			# r4^n
++	&paddq		($D1,$T1);
++
++	&$load		($T1,8);			# s4^n
++	&pmuludq	($T0,&QWP(16*0,$base));		# r4*h0
++	 &paddq		($D0,$T2);
++	&movdqa		($T2,$T1);
++	&pmuludq	($T1,&QWP(16*4,$base));		# s4*h4
++	&paddq		($D4,$T0);
++	&movdqa		($T0,$T2);
++	&pmuludq	($T2,&QWP(16*1,$base));		# s4*h1
++	&paddq		($D3,$T1);
++	&movdqa		($T1,$T0);
++	&pmuludq	($T0,&QWP(16*2,$base));		# s4*h2
++	&paddq		($D0,$T2);
++	&pmuludq	($T1,&QWP(16*3,$base));		# s4*h3
++	 &movdqa	($MASK,&QWP(64,"ebx"));
++	&paddq		($D1,$T0);
++	&paddq		($D2,$T1);
++}
++	&pmuladd	(sub {	my ($reg,$i)=@_;
++				&movdqa ($reg,&QWP(16*$i,"esp"));
++			     },"edx");
++
++sub lazy_reduction {
++my $extra = shift;
++
++	################################################################
++	# lazy reduction as discussed in "NEON crypto" by D.J. Bernstein
++	# and P. Schwabe
++	#
++	# [(*) see discussion in poly1305-armv4 module]
++
++	 &movdqa	($T0,$D3);
++	 &pand		($D3,$MASK);
++	 &psrlq		($T0,26);
++	 &$extra	()				if (defined($extra));
++	 &paddq		($T0,$D4);			# h3 -> h4
++	&movdqa		($T1,$D0);
++	&pand		($D0,$MASK);
++	&psrlq		($T1,26);
++	 &movdqa	($D4,$T0);
++	&paddq		($T1,$D1);			# h0 -> h1
++	 &psrlq		($T0,26);
++	 &pand		($D4,$MASK);
++	&movdqa		($D1,$T1);
++	&psrlq		($T1,26);
++	 &paddd		($D0,$T0);			# favour paddd when
++							# possible, because
++							# paddq is "broken"
++							# on Atom
++	 &psllq		($T0,2);
++	&paddq		($T1,$D2);			# h1 -> h2
++	 &paddq		($T0,$D0);			# h4 -> h0 (*)
++	&pand		($D1,$MASK);
++	&movdqa		($D2,$T1);
++	&psrlq		($T1,26);
++	&pand		($D2,$MASK);
++	&paddd		($T1,$D3);			# h2 -> h3
++	 &movdqa	($D0,$T0);
++	 &psrlq		($T0,26);
++	&movdqa		($D3,$T1);
++	&psrlq		($T1,26);
++	 &pand		($D0,$MASK);
++	 &paddd		($D1,$T0);			# h0 -> h1
++	&pand		($D3,$MASK);
++	&paddd		($D4,$T1);			# h3 -> h4
++}
++	&lazy_reduction	();
++
++	&dec		("ecx");
++	&jz		(&label("square_break"));
++
++	&punpcklqdq	($D0,&QWP(16*0,"esp"));		# 0:r^1:0:r^2
++	&punpcklqdq	($D1,&QWP(16*1,"esp"));
++	&punpcklqdq	($D2,&QWP(16*2,"esp"));
++	&punpcklqdq	($D3,&QWP(16*3,"esp"));
++	&punpcklqdq	($D4,&QWP(16*4,"esp"));
++	&jmp		(&label("square"));
++
++&set_label("square_break");
++	&psllq		($D0,32);			# -> r^3:0:r^4:0
++	&psllq		($D1,32);
++	&psllq		($D2,32);
++	&psllq		($D3,32);
++	&psllq		($D4,32);
++	&por		($D0,&QWP(16*0,"esp"));		# r^3:r^1:r^4:r^2
++	&por		($D1,&QWP(16*1,"esp"));
++	&por		($D2,&QWP(16*2,"esp"));
++	&por		($D3,&QWP(16*3,"esp"));
++	&por		($D4,&QWP(16*4,"esp"));
++
++	&pshufd		($D0,$D0,0b10001101);		# -> r^1:r^2:r^3:r^4
++	&pshufd		($D1,$D1,0b10001101);
++	&pshufd		($D2,$D2,0b10001101);
++	&pshufd		($D3,$D3,0b10001101);
++	&pshufd		($D4,$D4,0b10001101);
++
++	&movdqu		(&QWP(16*0,"edi"),$D0);		# save the table
++	&movdqu		(&QWP(16*1,"edi"),$D1);
++	&movdqu		(&QWP(16*2,"edi"),$D2);
++	&movdqu		(&QWP(16*3,"edi"),$D3);
++	&movdqu		(&QWP(16*4,"edi"),$D4);
++
++	&movdqa		($T1,$D1);
++	&movdqa		($T0,$D2);
++	&pslld		($T1,2);
++	&pslld		($T0,2);
++	&paddd		($T1,$D1);			# *5
++	&paddd		($T0,$D2);			# *5
++	&movdqu		(&QWP(16*5,"edi"),$T1);
++	&movdqu		(&QWP(16*6,"edi"),$T0);
++	&movdqa		($T1,$D3);
++	&movdqa		($T0,$D4);
++	&pslld		($T1,2);
++	&pslld		($T0,2);
++	&paddd		($T1,$D3);			# *5
++	&paddd		($T0,$D4);			# *5
++	&movdqu		(&QWP(16*7,"edi"),$T1);
++	&movdqu		(&QWP(16*8,"edi"),$T0);
++
++	&mov		("esp","ebp");
++	&lea		("edi",&DWP(-16*3,"edi"));	# size de-optimization
++	&ret		();
++&function_end_B("_poly1305_init_sse2");
++
++&align	(32);
++&function_begin("_poly1305_blocks_sse2");
++	&mov	("edi",&wparam(0));			# ctx
++	&mov	("esi",&wparam(1));			# inp
++	&mov	("ecx",&wparam(2));			# len
++
++	&mov	("eax",&DWP(4*5,"edi"));		# is_base2_26
++	&and	("ecx",-16);
++	&jz	(&label("nodata"));
++	&cmp	("ecx",64);
++	&jae	(&label("enter_sse2"));
++	&test	("eax","eax");				# is_base2_26?
++	&jz	(&label("enter_blocks"));
++
++&set_label("enter_sse2",16);
++	&call	(&label("pic_point"));
++&set_label("pic_point");
++	&blindpop("ebx");
++	&lea	("ebx",&DWP(&label("const_sse2")."-".&label("pic_point"),"ebx"));
++
++	&test	("eax","eax");				# is_base2_26?
++	&jnz	(&label("base2_26"));
++
++	&call	("_poly1305_init_sse2");
++
++	################################################# base 2^32 -> base 2^26
++	&mov	("eax",&DWP(0,"edi"));
++	&mov	("ecx",&DWP(3,"edi"));
++	&mov	("edx",&DWP(6,"edi"));
++	&mov	("esi",&DWP(9,"edi"));
++	&mov	("ebp",&DWP(13,"edi"));
++	&mov	(&DWP(4*5,"edi"),1);			# is_base2_26
++
++	&shr	("ecx",2);
++	&and	("eax",0x3ffffff);
++	&shr	("edx",4);
++	&and	("ecx",0x3ffffff);
++	&shr	("esi",6);
++	&and	("edx",0x3ffffff);
++
++	&movd	($D0,"eax");
++	&movd	($D1,"ecx");
++	&movd	($D2,"edx");
++	&movd	($D3,"esi");
++	&movd	($D4,"ebp");
++
++	&mov	("esi",&wparam(1));			# [reload] inp
++	&mov	("ecx",&wparam(2));			# [reload] len
++	&jmp	(&label("base2_32"));
++
++&set_label("base2_26",16);
++	&movd	($D0,&DWP(4*0,"edi"));			# load hash value
++	&movd	($D1,&DWP(4*1,"edi"));
++	&movd	($D2,&DWP(4*2,"edi"));
++	&movd	($D3,&DWP(4*3,"edi"));
++	&movd	($D4,&DWP(4*4,"edi"));
++	&movdqa	($MASK,&QWP(64,"ebx"));
++
++&set_label("base2_32");
++	&mov	("eax",&wparam(3));			# padbit
++	&mov	("ebp","esp");
++
++	&sub	("esp",16*(5+5+5+9+9));
++	&and	("esp",-16);
++
++	&lea	("edi",&DWP(16*3,"edi"));		# size optimization
++	&shl	("eax",24);				# padbit
++
++	&test	("ecx",31);
++	&jz	(&label("even"));
++
++	################################################################
++	# process single block, with SSE2, because it's still faster
++	# even though half of result is discarded
++
++	&movdqu		($T1,&QWP(0,"esi"));		# input
++	&lea		("esi",&DWP(16,"esi"));
++
++	&movdqa		($T0,$T1);			# -> base 2^26 ...
++	&pand		($T1,$MASK);
++	&paddd		($D0,$T1);			# ... and accumuate
++
++	&movdqa		($T1,$T0);
++	&psrlq		($T0,26);
++	&psrldq		($T1,6);
++	&pand		($T0,$MASK);
++	&paddd		($D1,$T0);
++
++	&movdqa		($T0,$T1);
++	&psrlq		($T1,4);
++	&pand		($T1,$MASK);
++	&paddd		($D2,$T1);
++
++	&movdqa		($T1,$T0);
++	&psrlq		($T0,30);
++	&pand		($T0,$MASK);
++	&psrldq		($T1,7);
++	&paddd		($D3,$T0);
++
++	&movd		($T0,"eax");			# padbit
++	&paddd		($D4,$T1);
++	 &movd		($T1,&DWP(16*0+12,"edi"));	# r0
++	&paddd		($D4,$T0);
++
++	&movdqa		(&QWP(16*0,"esp"),$D0);
++	&movdqa		(&QWP(16*1,"esp"),$D1);
++	&movdqa		(&QWP(16*2,"esp"),$D2);
++	&movdqa		(&QWP(16*3,"esp"),$D3);
++	&movdqa		(&QWP(16*4,"esp"),$D4);
++
++	################################################################
++	# d4 = h4*r0 + h3*r1   + h2*r2   + h1*r3   + h0*r4
++	# d3 = h3*r0 + h2*r1   + h1*r2   + h0*r3   + h4*5*r4
++	# d2 = h2*r0 + h1*r1   + h0*r2   + h4*5*r3 + h3*5*r4
++	# d1 = h1*r0 + h0*r1   + h4*5*r2 + h3*5*r3 + h2*5*r4
++	# d0 = h0*r0 + h4*5*r1 + h3*5*r2 + h2*5*r3 + h1*5*r4
++
++	&pmuludq	($D0,$T1);			# h4*r0
++	&pmuludq	($D1,$T1);			# h3*r0
++	&pmuludq	($D2,$T1);			# h2*r0
++	 &movd		($T0,&DWP(16*1+12,"edi"));	# r1
++	&pmuludq	($D3,$T1);			# h1*r0
++	&pmuludq	($D4,$T1);			# h0*r0
++
++	&pmuladd	(sub {	my ($reg,$i)=@_;
++				&movd ($reg,&DWP(16*$i+12,"edi"));
++			     });
++
++	&lazy_reduction	();
++
++	&sub		("ecx",16);
++	&jz		(&label("done"));
++
++&set_label("even");
++	&lea		("edx",&DWP(16*(5+5+5+9),"esp"));# size optimization
++	&lea		("eax",&DWP(-16*2,"esi"));
++	&sub		("ecx",64);
++
++	################################################################
++	# expand and copy pre-calculated table to stack
++
++	&movdqu		($T0,&QWP(16*0,"edi"));		# r^1:r^2:r^3:r^4
++	&pshufd		($T1,$T0,0b01000100);		# duplicate r^3:r^4
++	&cmovb		("esi","eax");
++	&pshufd		($T0,$T0,0b11101110);		# duplicate r^1:r^2
++	&movdqa		(&QWP(16*0,"edx"),$T1);
++	&lea		("eax",&DWP(16*10,"esp"));
++	&movdqu		($T1,&QWP(16*1,"edi"));
++	&movdqa		(&QWP(16*(0-9),"edx"),$T0);
++	&pshufd		($T0,$T1,0b01000100);
++	&pshufd		($T1,$T1,0b11101110);
++	&movdqa		(&QWP(16*1,"edx"),$T0);
++	&movdqu		($T0,&QWP(16*2,"edi"));
++	&movdqa		(&QWP(16*(1-9),"edx"),$T1);
++	&pshufd		($T1,$T0,0b01000100);
++	&pshufd		($T0,$T0,0b11101110);
++	&movdqa		(&QWP(16*2,"edx"),$T1);
++	&movdqu		($T1,&QWP(16*3,"edi"));
++	&movdqa		(&QWP(16*(2-9),"edx"),$T0);
++	&pshufd		($T0,$T1,0b01000100);
++	&pshufd		($T1,$T1,0b11101110);
++	&movdqa		(&QWP(16*3,"edx"),$T0);
++	&movdqu		($T0,&QWP(16*4,"edi"));
++	&movdqa		(&QWP(16*(3-9),"edx"),$T1);
++	&pshufd		($T1,$T0,0b01000100);
++	&pshufd		($T0,$T0,0b11101110);
++	&movdqa		(&QWP(16*4,"edx"),$T1);
++	&movdqu		($T1,&QWP(16*5,"edi"));
++	&movdqa		(&QWP(16*(4-9),"edx"),$T0);
++	&pshufd		($T0,$T1,0b01000100);
++	&pshufd		($T1,$T1,0b11101110);
++	&movdqa		(&QWP(16*5,"edx"),$T0);
++	&movdqu		($T0,&QWP(16*6,"edi"));
++	&movdqa		(&QWP(16*(5-9),"edx"),$T1);
++	&pshufd		($T1,$T0,0b01000100);
++	&pshufd		($T0,$T0,0b11101110);
++	&movdqa		(&QWP(16*6,"edx"),$T1);
++	&movdqu		($T1,&QWP(16*7,"edi"));
++	&movdqa		(&QWP(16*(6-9),"edx"),$T0);
++	&pshufd		($T0,$T1,0b01000100);
++	&pshufd		($T1,$T1,0b11101110);
++	&movdqa		(&QWP(16*7,"edx"),$T0);
++	&movdqu		($T0,&QWP(16*8,"edi"));
++	&movdqa		(&QWP(16*(7-9),"edx"),$T1);
++	&pshufd		($T1,$T0,0b01000100);
++	&pshufd		($T0,$T0,0b11101110);
++	&movdqa		(&QWP(16*8,"edx"),$T1);
++	&movdqa		(&QWP(16*(8-9),"edx"),$T0);
++
++sub load_input {
++my ($inpbase,$offbase)=@_;
++
++	&movdqu		($T0,&QWP($inpbase+0,"esi"));	# load input
++	&movdqu		($T1,&QWP($inpbase+16,"esi"));
++	&lea		("esi",&DWP(16*2,"esi"));
++
++	&movdqa		(&QWP($offbase+16*2,"esp"),$D2);
++	&movdqa		(&QWP($offbase+16*3,"esp"),$D3);
++	&movdqa		(&QWP($offbase+16*4,"esp"),$D4);
++
++	&movdqa		($D2,$T0);			# splat input
++	&movdqa		($D3,$T1);
++	&psrldq		($D2,6);
++	&psrldq		($D3,6);
++	&movdqa		($D4,$T0);
++	&punpcklqdq	($D2,$D3);			# 2:3
++	&punpckhqdq	($D4,$T1);			# 4
++	&punpcklqdq	($T0,$T1);			# 0:1
++
++	&movdqa		($D3,$D2);
++	&psrlq		($D2,4);
++	&psrlq		($D3,30);
++	&movdqa		($T1,$T0);
++	&psrlq		($D4,40);			# 4
++	&psrlq		($T1,26);
++	&pand		($T0,$MASK);			# 0
++	&pand		($T1,$MASK);			# 1
++	&pand		($D2,$MASK);			# 2
++	&pand		($D3,$MASK);			# 3
++	&por		($D4,&QWP(0,"ebx"));		# padbit, yes, always
++
++	&movdqa		(&QWP($offbase+16*0,"esp"),$D0)	if ($offbase);
++	&movdqa		(&QWP($offbase+16*1,"esp"),$D1)	if ($offbase);
++}
++	&load_input	(16*2,16*5);
++
++	&jbe		(&label("skip_loop"));
++	&jmp		(&label("loop"));
++
++&set_label("loop",32);
++	################################################################
++	# ((inp[0]*r^4+inp[2]*r^2+inp[4])*r^4+inp[6]*r^2
++	# ((inp[1]*r^4+inp[3]*r^2+inp[5])*r^3+inp[7]*r
++	#   \___________________/
++	# ((inp[0]*r^4+inp[2]*r^2+inp[4])*r^4+inp[6]*r^2+inp[8])*r^2
++	# ((inp[1]*r^4+inp[3]*r^2+inp[5])*r^4+inp[7]*r^2+inp[9])*r
++	#   \___________________/ \____________________/
++	################################################################
++
++	&movdqa		($T2,&QWP(16*(0-9),"edx"));	# r0^2
++	&movdqa		(&QWP(16*1,"eax"),$T1);
++	&movdqa		(&QWP(16*2,"eax"),$D2);
++	&movdqa		(&QWP(16*3,"eax"),$D3);
++	&movdqa		(&QWP(16*4,"eax"),$D4);
++
++	################################################################
++	# d4 = h4*r0 + h0*r4   + h1*r3   + h2*r2   + h3*r1
++	# d3 = h3*r0 + h0*r3   + h1*r2   + h2*r1   + h4*5*r4
++	# d2 = h2*r0 + h0*r2   + h1*r1   + h3*5*r4 + h4*5*r3
++	# d1 = h1*r0 + h0*r1   + h2*5*r4 + h3*5*r3 + h4*5*r2
++	# d0 = h0*r0 + h1*5*r4 + h2*5*r3 + h3*5*r2 + h4*5*r1
++
++	&movdqa		($D1,$T0);
++	&pmuludq	($T0,$T2);			# h0*r0
++	&movdqa		($D0,$T1);
++	&pmuludq	($T1,$T2);			# h1*r0
++	&pmuludq	($D2,$T2);			# h2*r0
++	&pmuludq	($D3,$T2);			# h3*r0
++	&pmuludq	($D4,$T2);			# h4*r0
++
++sub pmuladd_alt {
++my $addr = shift;
++
++	&pmuludq	($D0,&$addr(8));		# h1*s4
++	&movdqa		($T2,$D1);
++	&pmuludq	($D1,&$addr(1));		# h0*r1
++	&paddq		($D0,$T0);
++	&movdqa		($T0,$T2);
++	&pmuludq	($T2,&$addr(2));		# h0*r2
++	&paddq		($D1,$T1);
++	&movdqa		($T1,$T0);
++	&pmuludq	($T0,&$addr(3));		# h0*r3
++	&paddq		($D2,$T2);
++	 &movdqa	($T2,&QWP(16*1,"eax"));		# pull h1
++	&pmuludq	($T1,&$addr(4));		# h0*r4
++	&paddq		($D3,$T0);
++
++	&movdqa		($T0,$T2);
++	&pmuludq	($T2,&$addr(1));		# h1*r1
++	 &paddq		($D4,$T1);
++	&movdqa		($T1,$T0);
++	&pmuludq	($T0,&$addr(2));		# h1*r2
++	&paddq		($D2,$T2);
++	&movdqa		($T2,&QWP(16*2,"eax"));		# pull h2
++	&pmuludq	($T1,&$addr(3));		# h1*r3
++	&paddq		($D3,$T0);
++	&movdqa		($T0,$T2);
++	&pmuludq	($T2,&$addr(7));		# h2*s3
++	&paddq		($D4,$T1);
++	&movdqa		($T1,$T0);
++	&pmuludq	($T0,&$addr(8));		# h2*s4
++	&paddq		($D0,$T2);
++
++	&movdqa		($T2,$T1);
++	&pmuludq	($T1,&$addr(1));		# h2*r1
++	 &paddq		($D1,$T0);
++	&movdqa		($T0,&QWP(16*3,"eax"));		# pull h3
++	&pmuludq	($T2,&$addr(2));		# h2*r2
++	&paddq		($D3,$T1);
++	&movdqa		($T1,$T0);
++	&pmuludq	($T0,&$addr(6));		# h3*s2
++	&paddq		($D4,$T2);
++	&movdqa		($T2,$T1);
++	&pmuludq	($T1,&$addr(7));		# h3*s3
++	&paddq		($D0,$T0);
++	&movdqa		($T0,$T2);
++	&pmuludq	($T2,&$addr(8));		# h3*s4
++	&paddq		($D1,$T1);
++
++	&movdqa		($T1,&QWP(16*4,"eax"));		# pull h4
++	&pmuludq	($T0,&$addr(1));		# h3*r1
++	 &paddq		($D2,$T2);
++	&movdqa		($T2,$T1);
++	&pmuludq	($T1,&$addr(8));		# h4*s4
++	&paddq		($D4,$T0);
++	&movdqa		($T0,$T2);
++	&pmuludq	($T2,&$addr(5));		# h4*s1
++	&paddq		($D3,$T1);
++	&movdqa		($T1,$T0);
++	&pmuludq	($T0,&$addr(6));		# h4*s2
++	&paddq		($D0,$T2);
++	 &movdqa	($MASK,&QWP(64,"ebx"));
++	&pmuludq	($T1,&$addr(7));		# h4*s3
++	&paddq		($D1,$T0);
++	&paddq		($D2,$T1);
++}
++	&pmuladd_alt	(sub {	my $i=shift; &QWP(16*($i-9),"edx");	});
++
++	&load_input	(-16*2,0);
++	&lea		("eax",&DWP(-16*2,"esi"));
++	&sub		("ecx",64);
++
++	&paddd		($T0,&QWP(16*(5+0),"esp"));	# add hash value
++	&paddd		($T1,&QWP(16*(5+1),"esp"));
++	&paddd		($D2,&QWP(16*(5+2),"esp"));
++	&paddd		($D3,&QWP(16*(5+3),"esp"));
++	&paddd		($D4,&QWP(16*(5+4),"esp"));
++
++	&cmovb		("esi","eax");
++	&lea		("eax",&DWP(16*10,"esp"));
++
++	&movdqa		($T2,&QWP(16*0,"edx"));		# r0^4
++	&movdqa		(&QWP(16*1,"esp"),$D1);
++	&movdqa		(&QWP(16*1,"eax"),$T1);
++	&movdqa		(&QWP(16*2,"eax"),$D2);
++	&movdqa		(&QWP(16*3,"eax"),$D3);
++	&movdqa		(&QWP(16*4,"eax"),$D4);
++
++	################################################################
++	# d4 += h4*r0 + h0*r4   + h1*r3   + h2*r2   + h3*r1
++	# d3 += h3*r0 + h0*r3   + h1*r2   + h2*r1   + h4*5*r4
++	# d2 += h2*r0 + h0*r2   + h1*r1   + h3*5*r4 + h4*5*r3
++	# d1 += h1*r0 + h0*r1   + h2*5*r4 + h3*5*r3 + h4*5*r2
++	# d0 += h0*r0 + h1*5*r4 + h2*5*r3 + h3*5*r2 + h4*5*r1
++
++	&movdqa		($D1,$T0);
++	&pmuludq	($T0,$T2);			# h0*r0
++	&paddq		($T0,$D0);
++	&movdqa		($D0,$T1);
++	&pmuludq	($T1,$T2);			# h1*r0
++	&pmuludq	($D2,$T2);			# h2*r0
++	&pmuludq	($D3,$T2);			# h3*r0
++	&pmuludq	($D4,$T2);			# h4*r0
++
++	&paddq		($T1,&QWP(16*1,"esp"));
++	&paddq		($D2,&QWP(16*2,"esp"));
++	&paddq		($D3,&QWP(16*3,"esp"));
++	&paddq		($D4,&QWP(16*4,"esp"));
++
++	&pmuladd_alt	(sub {	my $i=shift; &QWP(16*$i,"edx");	});
++
++	&lazy_reduction	();
++
++	&load_input	(16*2,16*5);
++
++	&ja		(&label("loop"));
++
++&set_label("skip_loop");
++	################################################################
++	# multiply (inp[0:1]+hash) or inp[2:3] by r^2:r^1
++
++	 &pshufd	($T2,&QWP(16*(0-9),"edx"),0x10);# r0^n
++	&add		("ecx",32);
++	&jnz		(&label("long_tail"));
++
++	&paddd		($T0,$D0);			# add hash value
++	&paddd		($T1,$D1);
++	&paddd		($D2,&QWP(16*7,"esp"));
++	&paddd		($D3,&QWP(16*8,"esp"));
++	&paddd		($D4,&QWP(16*9,"esp"));
++
++&set_label("long_tail");
++
++	&movdqa		(&QWP(16*0,"eax"),$T0);
++	&movdqa		(&QWP(16*1,"eax"),$T1);
++	&movdqa		(&QWP(16*2,"eax"),$D2);
++	&movdqa		(&QWP(16*3,"eax"),$D3);
++	&movdqa		(&QWP(16*4,"eax"),$D4);
++
++	################################################################
++	# d4 = h4*r0 + h3*r1   + h2*r2   + h1*r3   + h0*r4
++	# d3 = h3*r0 + h2*r1   + h1*r2   + h0*r3   + h4*5*r4
++	# d2 = h2*r0 + h1*r1   + h0*r2   + h4*5*r3 + h3*5*r4
++	# d1 = h1*r0 + h0*r1   + h4*5*r2 + h3*5*r3 + h2*5*r4
++	# d0 = h0*r0 + h4*5*r1 + h3*5*r2 + h2*5*r3 + h1*5*r4
++
++	&pmuludq	($T0,$T2);			# h0*r0
++	&pmuludq	($T1,$T2);			# h1*r0
++	&pmuludq	($D2,$T2);			# h2*r0
++	&movdqa		($D0,$T0);
++	 &pshufd	($T0,&QWP(16*(1-9),"edx"),0x10);# r1^n
++	&pmuludq	($D3,$T2);			# h3*r0
++	&movdqa		($D1,$T1);
++	&pmuludq	($D4,$T2);			# h4*r0
++
++	&pmuladd	(sub {	my ($reg,$i)=@_;
++				&pshufd ($reg,&QWP(16*($i-9),"edx"),0x10);
++			     },"eax");
++
++	&jz		(&label("short_tail"));
++
++	&load_input	(-16*2,0);
++
++	 &pshufd	($T2,&QWP(16*0,"edx"),0x10);	# r0^n
++	&paddd		($T0,&QWP(16*5,"esp"));		# add hash value
++	&paddd		($T1,&QWP(16*6,"esp"));
++	&paddd		($D2,&QWP(16*7,"esp"));
++	&paddd		($D3,&QWP(16*8,"esp"));
++	&paddd		($D4,&QWP(16*9,"esp"));
++
++	################################################################
++	# multiply inp[0:1] by r^4:r^3 and accumulate
++
++	&movdqa		(&QWP(16*0,"esp"),$T0);
++	&pmuludq	($T0,$T2);			# h0*r0
++	&movdqa		(&QWP(16*1,"esp"),$T1);
++	&pmuludq	($T1,$T2);			# h1*r0
++	&paddq		($D0,$T0);
++	&movdqa		($T0,$D2);
++	&pmuludq	($D2,$T2);			# h2*r0
++	&paddq		($D1,$T1);
++	&movdqa		($T1,$D3);
++	&pmuludq	($D3,$T2);			# h3*r0
++	&paddq		($D2,&QWP(16*2,"esp"));
++	&movdqa		(&QWP(16*2,"esp"),$T0);
++	 &pshufd	($T0,&QWP(16*1,"edx"),0x10);	# r1^n
++	&paddq		($D3,&QWP(16*3,"esp"));
++	&movdqa		(&QWP(16*3,"esp"),$T1);
++	&movdqa		($T1,$D4);
++	&pmuludq	($D4,$T2);			# h4*r0
++	&paddq		($D4,&QWP(16*4,"esp"));
++	&movdqa		(&QWP(16*4,"esp"),$T1);
++
++	&pmuladd	(sub {	my ($reg,$i)=@_;
++				&pshufd ($reg,&QWP(16*$i,"edx"),0x10);
++			     });
++
++&set_label("short_tail");
++
++	################################################################
++	# horizontal addition
++
++	&pshufd		($T1,$D4,0b01001110);
++	&pshufd		($T0,$D3,0b01001110);
++	&paddq		($D4,$T1);
++	&paddq		($D3,$T0);
++	&pshufd		($T1,$D0,0b01001110);
++	&pshufd		($T0,$D1,0b01001110);
++	&paddq		($D0,$T1);
++	&paddq		($D1,$T0);
++	&pshufd		($T1,$D2,0b01001110);
++	#&paddq		($D2,$T1);
++
++	&lazy_reduction	(sub { &paddq ($D2,$T1) });
++
++&set_label("done");
++	&movd		(&DWP(-16*3+4*0,"edi"),$D0);	# store hash value
++	&movd		(&DWP(-16*3+4*1,"edi"),$D1);
++	&movd		(&DWP(-16*3+4*2,"edi"),$D2);
++	&movd		(&DWP(-16*3+4*3,"edi"),$D3);
++	&movd		(&DWP(-16*3+4*4,"edi"),$D4);
++	&mov	("esp","ebp");
++&set_label("nodata");
++&function_end("_poly1305_blocks_sse2");
++
++&align	(32);
++&function_begin("_poly1305_emit_sse2");
++	&mov	("ebp",&wparam(0));		# context
++
++	&cmp	(&DWP(4*5,"ebp"),0);		# is_base2_26?
++	&je	(&label("enter_emit"));
++
++	&mov	("eax",&DWP(4*0,"ebp"));	# load hash value
++	&mov	("edi",&DWP(4*1,"ebp"));
++	&mov	("ecx",&DWP(4*2,"ebp"));
++	&mov	("edx",&DWP(4*3,"ebp"));
++	&mov	("esi",&DWP(4*4,"ebp"));
++
++	&mov	("ebx","edi");			# base 2^26 -> base 2^32
++	&shl	("edi",26);
++	&shr	("ebx",6);
++	&add	("eax","edi");
++	&mov	("edi","ecx");
++	&adc	("ebx",0);
++
++	&shl	("edi",20);
++	&shr	("ecx",12);
++	&add	("ebx","edi");
++	&mov	("edi","edx");
++	&adc	("ecx",0);
++
++	&shl	("edi",14);
++	&shr	("edx",18);
++	&add	("ecx","edi");
++	&mov	("edi","esi");
++	&adc	("edx",0);
++
++	&shl	("edi",8);
++	&shr	("esi",24);
++	&add	("edx","edi");
++	&adc	("esi",0);			# can be partially reduced
++
++	&mov	("edi","esi");			# final reduction
++	&and	("esi",3);
++	&shr	("edi",2);
++	&lea	("ebp",&DWP(0,"edi","edi",4));	# *5
++	 &mov	("edi",&wparam(1));		# output
++	&add	("eax","ebp");
++	 &mov	("ebp",&wparam(2));		# key
++	&adc	("ebx",0);
++	&adc	("ecx",0);
++	&adc	("edx",0);
++	&adc	("esi",0);
++
++	&movd	($D0,"eax");			# offload original hash value
++	&add	("eax",5);			# compare to modulus
++	&movd	($D1,"ebx");
++	&adc	("ebx",0);
++	&movd	($D2,"ecx");
++	&adc	("ecx",0);
++	&movd	($D3,"edx");
++	&adc	("edx",0);
++	&adc	("esi",0);
++	&shr	("esi",2);			# did it carry/borrow?
++
++	&neg	("esi");			# do we choose (hash-modulus) ...
++	&and	("eax","esi");
++	&and	("ebx","esi");
++	&and	("ecx","esi");
++	&and	("edx","esi");
++	&mov	(&DWP(4*0,"edi"),"eax");
++	&movd	("eax",$D0);
++	&mov	(&DWP(4*1,"edi"),"ebx");
++	&movd	("ebx",$D1);
++	&mov	(&DWP(4*2,"edi"),"ecx");
++	&movd	("ecx",$D2);
++	&mov	(&DWP(4*3,"edi"),"edx");
++	&movd	("edx",$D3);
++
++	¬	("esi");			# ... or original hash value?
++	&and	("eax","esi");
++	&and	("ebx","esi");
++	&or	("eax",&DWP(4*0,"edi"));
++	&and	("ecx","esi");
++	&or	("ebx",&DWP(4*1,"edi"));
++	&and	("edx","esi");
++	&or	("ecx",&DWP(4*2,"edi"));
++	&or	("edx",&DWP(4*3,"edi"));
++
++	&add	("eax",&DWP(4*0,"ebp"));	# accumulate key
++	&adc	("ebx",&DWP(4*1,"ebp"));
++	&mov	(&DWP(4*0,"edi"),"eax");
++	&adc	("ecx",&DWP(4*2,"ebp"));
++	&mov	(&DWP(4*1,"edi"),"ebx");
++	&adc	("edx",&DWP(4*3,"ebp"));
++	&mov	(&DWP(4*2,"edi"),"ecx");
++	&mov	(&DWP(4*3,"edi"),"edx");
++&function_end("_poly1305_emit_sse2");
++
++if ($avx>1) {
++########################################################################
++# Note that poly1305_init_avx2 operates on %xmm, I could have used
++# poly1305_init_sse2...
++
++&align	(32);
++&function_begin_B("_poly1305_init_avx2");
++	&vmovdqu	($D4,&QWP(4*6,"edi"));		# key base 2^32
++	&lea		("edi",&DWP(16*3,"edi"));	# size optimization
++	&mov		("ebp","esp");
++	&sub		("esp",16*(9+5));
++	&and		("esp",-16);
++
++	#&vpand		($D4,$D4,&QWP(96,"ebx"));	# magic mask
++	&vmovdqa	($MASK,&QWP(64,"ebx"));
++
++	&vpand		($D0,$D4,$MASK);		# -> base 2^26
++	&vpsrlq		($D1,$D4,26);
++	&vpsrldq	($D3,$D4,6);
++	&vpand		($D1,$D1,$MASK);
++	&vpsrlq		($D2,$D3,4)
++	&vpsrlq		($D3,$D3,30);
++	&vpand		($D2,$D2,$MASK);
++	&vpand		($D3,$D3,$MASK);
++	&vpsrldq	($D4,$D4,13);
++
++	&lea		("edx",&DWP(16*9,"esp"));	# size optimization
++	&mov		("ecx",2);
++&set_label("square");
++	&vmovdqa	(&QWP(16*0,"esp"),$D0);
++	&vmovdqa	(&QWP(16*1,"esp"),$D1);
++	&vmovdqa	(&QWP(16*2,"esp"),$D2);
++	&vmovdqa	(&QWP(16*3,"esp"),$D3);
++	&vmovdqa	(&QWP(16*4,"esp"),$D4);
++
++	&vpslld		($T1,$D1,2);
++	&vpslld		($T0,$D2,2);
++	&vpaddd		($T1,$T1,$D1);			# *5
++	&vpaddd		($T0,$T0,$D2);			# *5
++	&vmovdqa	(&QWP(16*5,"esp"),$T1);
++	&vmovdqa	(&QWP(16*6,"esp"),$T0);
++	&vpslld		($T1,$D3,2);
++	&vpslld		($T0,$D4,2);
++	&vpaddd		($T1,$T1,$D3);			# *5
++	&vpaddd		($T0,$T0,$D4);			# *5
++	&vmovdqa	(&QWP(16*7,"esp"),$T1);
++	&vmovdqa	(&QWP(16*8,"esp"),$T0);
++
++	&vpshufd	($T0,$D0,0b01000100);
++	&vmovdqa	($T1,$D1);
++	&vpshufd	($D1,$D1,0b01000100);
++	&vpshufd	($D2,$D2,0b01000100);
++	&vpshufd	($D3,$D3,0b01000100);
++	&vpshufd	($D4,$D4,0b01000100);
++	&vmovdqa	(&QWP(16*0,"edx"),$T0);
++	&vmovdqa	(&QWP(16*1,"edx"),$D1);
++	&vmovdqa	(&QWP(16*2,"edx"),$D2);
++	&vmovdqa	(&QWP(16*3,"edx"),$D3);
++	&vmovdqa	(&QWP(16*4,"edx"),$D4);
++
++	################################################################
++	# d4 = h4*r0 + h3*r1   + h2*r2   + h1*r3   + h0*r4
++	# d3 = h3*r0 + h2*r1   + h1*r2   + h0*r3   + h4*5*r4
++	# d2 = h2*r0 + h1*r1   + h0*r2   + h4*5*r3 + h3*5*r4
++	# d1 = h1*r0 + h0*r1   + h4*5*r2 + h3*5*r3 + h2*5*r4
++	# d0 = h0*r0 + h4*5*r1 + h3*5*r2 + h2*5*r3 + h1*5*r4
++
++	&vpmuludq	($D4,$D4,$D0);			# h4*r0
++	&vpmuludq	($D3,$D3,$D0);			# h3*r0
++	&vpmuludq	($D2,$D2,$D0);			# h2*r0
++	&vpmuludq	($D1,$D1,$D0);			# h1*r0
++	&vpmuludq	($D0,$T0,$D0);			# h0*r0
++
++	&vpmuludq	($T0,$T1,&QWP(16*3,"edx"));	# r1*h3
++	&vpaddq		($D4,$D4,$T0);
++	&vpmuludq	($T2,$T1,&QWP(16*2,"edx"));	# r1*h2
++	&vpaddq		($D3,$D3,$T2);
++	&vpmuludq	($T0,$T1,&QWP(16*1,"edx"));	# r1*h1
++	&vpaddq		($D2,$D2,$T0);
++	&vmovdqa	($T2,&QWP(16*5,"esp"));		# s1
++	&vpmuludq	($T1,$T1,&QWP(16*0,"edx"));	# r1*h0
++	&vpaddq		($D1,$D1,$T1);
++	 &vmovdqa	($T0,&QWP(16*2,"esp"));		# r2
++	&vpmuludq	($T2,$T2,&QWP(16*4,"edx"));	# s1*h4
++	&vpaddq		($D0,$D0,$T2);
++
++	&vpmuludq	($T1,$T0,&QWP(16*2,"edx"));	# r2*h2
++	&vpaddq		($D4,$D4,$T1);
++	&vpmuludq	($T2,$T0,&QWP(16*1,"edx"));	# r2*h1
++	&vpaddq		($D3,$D3,$T2);
++	&vmovdqa	($T1,&QWP(16*6,"esp"));		# s2
++	&vpmuludq	($T0,$T0,&QWP(16*0,"edx"));	# r2*h0
++	&vpaddq		($D2,$D2,$T0);
++	&vpmuludq	($T2,$T1,&QWP(16*4,"edx"));	# s2*h4
++	&vpaddq		($D1,$D1,$T2);
++	 &vmovdqa	($T0,&QWP(16*3,"esp"));		# r3
++	&vpmuludq	($T1,$T1,&QWP(16*3,"edx"));	# s2*h3
++	&vpaddq		($D0,$D0,$T1);
++
++	&vpmuludq	($T2,$T0,&QWP(16*1,"edx"));	# r3*h1
++	&vpaddq		($D4,$D4,$T2);
++	&vmovdqa	($T1,&QWP(16*7,"esp"));		# s3
++	&vpmuludq	($T0,$T0,&QWP(16*0,"edx"));	# r3*h0
++	&vpaddq		($D3,$D3,$T0);
++	&vpmuludq	($T2,$T1,&QWP(16*4,"edx"));	# s3*h4
++	&vpaddq		($D2,$D2,$T2);
++	&vpmuludq	($T0,$T1,&QWP(16*3,"edx"));	# s3*h3
++	&vpaddq		($D1,$D1,$T0);
++	 &vmovdqa	($T2,&QWP(16*4,"esp"));		# r4
++	&vpmuludq	($T1,$T1,&QWP(16*2,"edx"));	# s3*h2
++	&vpaddq		($D0,$D0,$T1);
++
++	&vmovdqa	($T0,&QWP(16*8,"esp"));		# s4
++	&vpmuludq	($T2,$T2,&QWP(16*0,"edx"));	# r4*h0
++	&vpaddq		($D4,$D4,$T2);
++	&vpmuludq	($T1,$T0,&QWP(16*4,"edx"));	# s4*h4
++	&vpaddq		($D3,$D3,$T1);
++	&vpmuludq	($T2,$T0,&QWP(16*1,"edx"));	# s4*h1
++	&vpaddq		($D0,$D0,$T2);
++	&vpmuludq	($T1,$T0,&QWP(16*2,"edx"));	# s4*h2
++	&vpaddq		($D1,$D1,$T1);
++	 &vmovdqa	($MASK,&QWP(64,"ebx"));
++	&vpmuludq	($T0,$T0,&QWP(16*3,"edx"));	# s4*h3
++	&vpaddq		($D2,$D2,$T0);
++
++	################################################################
++	# lazy reduction
++	 &vpsrlq	($T0,$D3,26);
++	 &vpand		($D3,$D3,$MASK);
++	&vpsrlq		($T1,$D0,26);
++	&vpand		($D0,$D0,$MASK);
++	 &vpaddq	($D4,$D4,$T0);			# h3 -> h4
++	&vpaddq		($D1,$D1,$T1);			# h0 -> h1
++	 &vpsrlq	($T0,$D4,26);
++	 &vpand		($D4,$D4,$MASK);
++	&vpsrlq		($T1,$D1,26);
++	&vpand		($D1,$D1,$MASK);
++	&vpaddq		($D2,$D2,$T1);			# h1 -> h2
++	 &vpaddd	($D0,$D0,$T0);
++	 &vpsllq	($T0,$T0,2);
++	&vpsrlq		($T1,$D2,26);
++	&vpand		($D2,$D2,$MASK);
++	 &vpaddd	($D0,$D0,$T0);			# h4 -> h0
++	&vpaddd		($D3,$D3,$T1);			# h2 -> h3
++	&vpsrlq		($T1,$D3,26);
++	 &vpsrlq	($T0,$D0,26);
++	 &vpand		($D0,$D0,$MASK);
++	&vpand		($D3,$D3,$MASK);
++	 &vpaddd	($D1,$D1,$T0);			# h0 -> h1
++	&vpaddd		($D4,$D4,$T1);			# h3 -> h4
++
++	&dec		("ecx");
++	&jz		(&label("square_break"));
++
++	&vpunpcklqdq	($D0,$D0,&QWP(16*0,"esp"));	# 0:r^1:0:r^2
++	&vpunpcklqdq	($D1,$D1,&QWP(16*1,"esp"));
++	&vpunpcklqdq	($D2,$D2,&QWP(16*2,"esp"));
++	&vpunpcklqdq	($D3,$D3,&QWP(16*3,"esp"));
++	&vpunpcklqdq	($D4,$D4,&QWP(16*4,"esp"));
++	&jmp		(&label("square"));
++
++&set_label("square_break");
++	&vpsllq		($D0,$D0,32);			# -> r^3:0:r^4:0
++	&vpsllq		($D1,$D1,32);
++	&vpsllq		($D2,$D2,32);
++	&vpsllq		($D3,$D3,32);
++	&vpsllq		($D4,$D4,32);
++	&vpor		($D0,$D0,&QWP(16*0,"esp"));	# r^3:r^1:r^4:r^2
++	&vpor		($D1,$D1,&QWP(16*1,"esp"));
++	&vpor		($D2,$D2,&QWP(16*2,"esp"));
++	&vpor		($D3,$D3,&QWP(16*3,"esp"));
++	&vpor		($D4,$D4,&QWP(16*4,"esp"));
++
++	&vpshufd	($D0,$D0,0b10001101);		# -> r^1:r^2:r^3:r^4
++	&vpshufd	($D1,$D1,0b10001101);
++	&vpshufd	($D2,$D2,0b10001101);
++	&vpshufd	($D3,$D3,0b10001101);
++	&vpshufd	($D4,$D4,0b10001101);
++
++	&vmovdqu	(&QWP(16*0,"edi"),$D0);		# save the table
++	&vmovdqu	(&QWP(16*1,"edi"),$D1);
++	&vmovdqu	(&QWP(16*2,"edi"),$D2);
++	&vmovdqu	(&QWP(16*3,"edi"),$D3);
++	&vmovdqu	(&QWP(16*4,"edi"),$D4);
++
++	&vpslld		($T1,$D1,2);
++	&vpslld		($T0,$D2,2);
++	&vpaddd		($T1,$T1,$D1);			# *5
++	&vpaddd		($T0,$T0,$D2);			# *5
++	&vmovdqu	(&QWP(16*5,"edi"),$T1);
++	&vmovdqu	(&QWP(16*6,"edi"),$T0);
++	&vpslld		($T1,$D3,2);
++	&vpslld		($T0,$D4,2);
++	&vpaddd		($T1,$T1,$D3);			# *5
++	&vpaddd		($T0,$T0,$D4);			# *5
++	&vmovdqu	(&QWP(16*7,"edi"),$T1);
++	&vmovdqu	(&QWP(16*8,"edi"),$T0);
++
++	&mov		("esp","ebp");
++	&lea		("edi",&DWP(-16*3,"edi"));	# size de-optimization
++	&ret		();
++&function_end_B("_poly1305_init_avx2");
++
++########################################################################
++# now it's time to switch to %ymm
++
++my ($D0,$D1,$D2,$D3,$D4,$T0,$T1,$T2)=map("ymm$_",(0..7));
++my $MASK=$T2;
++
++sub X { my $reg=shift; $reg=~s/^ymm/xmm/; $reg; }
++
++&align	(32);
++&function_begin("_poly1305_blocks_avx2");
++	&mov	("edi",&wparam(0));			# ctx
++	&mov	("esi",&wparam(1));			# inp
++	&mov	("ecx",&wparam(2));			# len
++
++	&mov	("eax",&DWP(4*5,"edi"));		# is_base2_26
++	&and	("ecx",-16);
++	&jz	(&label("nodata"));
++	&cmp	("ecx",64);
++	&jae	(&label("enter_avx2"));
++	&test	("eax","eax");				# is_base2_26?
++	&jz	(&label("enter_blocks"));
++
++&set_label("enter_avx2");
++	&vzeroupper	();
++
++	&call	(&label("pic_point"));
++&set_label("pic_point");
++	&blindpop("ebx");
++	&lea	("ebx",&DWP(&label("const_sse2")."-".&label("pic_point"),"ebx"));
++
++	&test	("eax","eax");				# is_base2_26?
++	&jnz	(&label("base2_26"));
++
++	&call	("_poly1305_init_avx2");
++
++	################################################# base 2^32 -> base 2^26
++	&mov	("eax",&DWP(0,"edi"));
++	&mov	("ecx",&DWP(3,"edi"));
++	&mov	("edx",&DWP(6,"edi"));
++	&mov	("esi",&DWP(9,"edi"));
++	&mov	("ebp",&DWP(13,"edi"));
++
++	&shr	("ecx",2);
++	&and	("eax",0x3ffffff);
++	&shr	("edx",4);
++	&and	("ecx",0x3ffffff);
++	&shr	("esi",6);
++	&and	("edx",0x3ffffff);
++
++	&mov	(&DWP(4*0,"edi"),"eax");
++	&mov	(&DWP(4*1,"edi"),"ecx");
++	&mov	(&DWP(4*2,"edi"),"edx");
++	&mov	(&DWP(4*3,"edi"),"esi");
++	&mov	(&DWP(4*4,"edi"),"ebp");
++	&mov	(&DWP(4*5,"edi"),1);			# is_base2_26
++
++	&mov	("esi",&wparam(1));			# [reload] inp
++	&mov	("ecx",&wparam(2));			# [reload] len
++
++&set_label("base2_26");
++	&mov	("eax",&wparam(3));			# padbit
++	&mov	("ebp","esp");
++
++	&sub	("esp",32*(5+9));
++	&and	("esp",-512);				# ensure that frame
++							# doesn't cross page
++							# boundary, which is
++							# essential for
++							# misaligned 32-byte
++							# loads
++
++	################################################################
++        # expand and copy pre-calculated table to stack
++
++	&vmovdqu	(&X($D0),&QWP(16*(3+0),"edi"));
++	&lea		("edx",&DWP(32*5+128,"esp"));	# +128 size optimization
++	&vmovdqu	(&X($D1),&QWP(16*(3+1),"edi"));
++	&vmovdqu	(&X($D2),&QWP(16*(3+2),"edi"));
++	&vmovdqu	(&X($D3),&QWP(16*(3+3),"edi"));
++	&vmovdqu	(&X($D4),&QWP(16*(3+4),"edi"));
++	&lea		("edi",&DWP(16*3,"edi"));	# size optimization
++	&vpermq		($D0,$D0,0b01000000);		# 00001234 -> 12343434
++	&vpermq		($D1,$D1,0b01000000);
++	&vpermq		($D2,$D2,0b01000000);
++	&vpermq		($D3,$D3,0b01000000);
++	&vpermq		($D4,$D4,0b01000000);
++	&vpshufd	($D0,$D0,0b11001000);		# 12343434 -> 14243444
++	&vpshufd	($D1,$D1,0b11001000);
++	&vpshufd	($D2,$D2,0b11001000);
++	&vpshufd	($D3,$D3,0b11001000);
++	&vpshufd	($D4,$D4,0b11001000);
++	&vmovdqa	(&QWP(32*0-128,"edx"),$D0);
++	&vmovdqu	(&X($D0),&QWP(16*5,"edi"));
++	&vmovdqa	(&QWP(32*1-128,"edx"),$D1);
++	&vmovdqu	(&X($D1),&QWP(16*6,"edi"));
++	&vmovdqa	(&QWP(32*2-128,"edx"),$D2);
++	&vmovdqu	(&X($D2),&QWP(16*7,"edi"));
++	&vmovdqa	(&QWP(32*3-128,"edx"),$D3);
++	&vmovdqu	(&X($D3),&QWP(16*8,"edi"));
++	&vmovdqa	(&QWP(32*4-128,"edx"),$D4);
++	&vpermq		($D0,$D0,0b01000000);
++	&vpermq		($D1,$D1,0b01000000);
++	&vpermq		($D2,$D2,0b01000000);
++	&vpermq		($D3,$D3,0b01000000);
++	&vpshufd	($D0,$D0,0b11001000);
++	&vpshufd	($D1,$D1,0b11001000);
++	&vpshufd	($D2,$D2,0b11001000);
++	&vpshufd	($D3,$D3,0b11001000);
++	&vmovdqa	(&QWP(32*5-128,"edx"),$D0);
++	&vmovd		(&X($D0),&DWP(-16*3+4*0,"edi"));# load hash value
++	&vmovdqa	(&QWP(32*6-128,"edx"),$D1);
++	&vmovd		(&X($D1),&DWP(-16*3+4*1,"edi"));
++	&vmovdqa	(&QWP(32*7-128,"edx"),$D2);
++	&vmovd		(&X($D2),&DWP(-16*3+4*2,"edi"));
++	&vmovdqa	(&QWP(32*8-128,"edx"),$D3);
++	&vmovd		(&X($D3),&DWP(-16*3+4*3,"edi"));
++	&vmovd		(&X($D4),&DWP(-16*3+4*4,"edi"));
++	&vmovdqa	($MASK,&QWP(64,"ebx"));
++	&neg		("eax");			# padbit
++
++	&test		("ecx",63);
++	&jz		(&label("even"));
++
++	&mov		("edx","ecx");
++	&and		("ecx",-64);
++	&and		("edx",63);
++
++	&vmovdqu	(&X($T0),&QWP(16*0,"esi"));
++	&cmp		("edx",32);
++	&jb		(&label("one"));
++
++	&vmovdqu	(&X($T1),&QWP(16*1,"esi"));
++	&je		(&label("two"));
++
++	&vinserti128	($T0,$T0,&QWP(16*2,"esi"),1);
++	&lea		("esi",&DWP(16*3,"esi"));
++	&lea		("ebx",&DWP(8,"ebx"));		# three padbits
++	&lea		("edx",&DWP(32*5+128+8,"esp"));	# --:r^1:r^2:r^3 (*)
++	&jmp		(&label("tail"));
++
++&set_label("two");
++	&lea		("esi",&DWP(16*2,"esi"));
++	&lea		("ebx",&DWP(16,"ebx"));		# two padbits
++	&lea		("edx",&DWP(32*5+128+16,"esp"));# --:--:r^1:r^2 (*)
++	&jmp		(&label("tail"));
++
++&set_label("one");
++	&lea		("esi",&DWP(16*1,"esi"));
++	&vpxor		($T1,$T1,$T1);
++	&lea		("ebx",&DWP(32,"ebx","eax",8));	# one or no padbits
++	&lea		("edx",&DWP(32*5+128+24,"esp"));# --:--:--:r^1 (*)
++	&jmp		(&label("tail"));
++
++# (*)	spots marked with '--' are data from next table entry, but they
++#	are multiplied by 0 and therefore rendered insignificant
++
++&set_label("even",32);
++	&vmovdqu	(&X($T0),&QWP(16*0,"esi"));	# load input
++	&vmovdqu	(&X($T1),&QWP(16*1,"esi"));
++	&vinserti128	($T0,$T0,&QWP(16*2,"esi"),1);
++	&vinserti128	($T1,$T1,&QWP(16*3,"esi"),1);
++	&lea		("esi",&DWP(16*4,"esi"));
++	&sub		("ecx",64);
++	&jz		(&label("tail"));
++
++&set_label("loop");
++	################################################################
++	# ((inp[0]*r^4+r[4])*r^4+r[8])*r^4
++	# ((inp[1]*r^4+r[5])*r^4+r[9])*r^3
++	# ((inp[2]*r^4+r[6])*r^4+r[10])*r^2
++	# ((inp[3]*r^4+r[7])*r^4+r[11])*r^1
++	#   \________/ \_______/
++	################################################################
++
++sub vsplat_input {
++	&vmovdqa	(&QWP(32*2,"esp"),$D2);
++	&vpsrldq	($D2,$T0,6);			# splat input
++	&vmovdqa	(&QWP(32*0,"esp"),$D0);
++	&vpsrldq	($D0,$T1,6);
++	&vmovdqa	(&QWP(32*1,"esp"),$D1);
++	&vpunpckhqdq	($D1,$T0,$T1);			# 4
++	&vpunpcklqdq	($T0,$T0,$T1);			# 0:1
++	&vpunpcklqdq	($D2,$D2,$D0);			# 2:3
++
++	&vpsrlq		($D0,$D2,30);
++	&vpsrlq		($D2,$D2,4);
++	&vpsrlq		($T1,$T0,26);
++	&vpsrlq		($D1,$D1,40);			# 4
++	&vpand		($D2,$D2,$MASK);		# 2
++	&vpand		($T0,$T0,$MASK);		# 0
++	&vpand		($T1,$T1,$MASK);		# 1
++	&vpand		($D0,$D0,$MASK);		# 3 (*)
++	&vpor		($D1,$D1,&QWP(0,"ebx"));	# padbit, yes, always
++
++	# (*)	note that output is counterintuitive, inp[3:4] is
++	#	returned in $D1-2, while $D3-4 are preserved;
++}
++	&vsplat_input	();
++
++sub vpmuladd {
++my $addr = shift;
++
++	&vpaddq		($D2,$D2,&QWP(32*2,"esp"));	# add hash value
++	&vpaddq		($T0,$T0,&QWP(32*0,"esp"));
++	&vpaddq		($T1,$T1,&QWP(32*1,"esp"));
++	&vpaddq		($D0,$D0,$D3);
++	&vpaddq		($D1,$D1,$D4);
++
++	################################################################
++	# d3 = h2*r1   + h0*r3 + h1*r2   + h3*r0   + h4*5*r4
++	# d4 = h2*r2   + h0*r4 + h1*r3   + h3*r1   + h4*r0
++	# d0 = h2*5*r3 + h0*r0 + h1*5*r4 + h3*5*r2 + h4*5*r1
++	# d1 = h2*5*r4 + h0*r1 + h1*r0   + h3*5*r3 + h4*5*r2
++	# d2 = h2*r0   + h0*r2 + h1*r1   + h3*5*r4 + h4*5*r3
++
++	&vpmuludq	($D3,$D2,&$addr(1));		# d3 = h2*r1
++	 &vmovdqa	(QWP(32*1,"esp"),$T1);
++	&vpmuludq	($D4,$D2,&$addr(2));		# d4 = h2*r2
++	 &vmovdqa	(QWP(32*3,"esp"),$D0);
++	&vpmuludq	($D0,$D2,&$addr(7));		# d0 = h2*s3
++	 &vmovdqa	(QWP(32*4,"esp"),$D1);
++	&vpmuludq	($D1,$D2,&$addr(8));		# d1 = h2*s4
++	&vpmuludq	($D2,$D2,&$addr(0));		# d2 = h2*r0
++
++	&vpmuludq	($T2,$T0,&$addr(3));		# h0*r3
++	&vpaddq		($D3,$D3,$T2);			# d3 += h0*r3
++	&vpmuludq	($T1,$T0,&$addr(4));		# h0*r4
++	&vpaddq		($D4,$D4,$T1);			# d4 + h0*r4
++	&vpmuludq	($T2,$T0,&$addr(0));		# h0*r0
++	&vpaddq		($D0,$D0,$T2);			# d0 + h0*r0
++	 &vmovdqa	($T2,&QWP(32*1,"esp"));		# h1
++	&vpmuludq	($T1,$T0,&$addr(1));		# h0*r1
++	&vpaddq		($D1,$D1,$T1);			# d1 += h0*r1
++	&vpmuludq	($T0,$T0,&$addr(2));		# h0*r2
++	&vpaddq		($D2,$D2,$T0);			# d2 += h0*r2
++
++	&vpmuludq	($T1,$T2,&$addr(2));		# h1*r2
++	&vpaddq		($D3,$D3,$T1);			# d3 += h1*r2
++	&vpmuludq	($T0,$T2,&$addr(3));		# h1*r3
++	&vpaddq		($D4,$D4,$T0);			# d4 += h1*r3
++	&vpmuludq	($T1,$T2,&$addr(8));		# h1*s4
++	&vpaddq		($D0,$D0,$T1);			# d0 += h1*s4
++	 &vmovdqa	($T1,&QWP(32*3,"esp"));		# h3
++	&vpmuludq	($T0,$T2,&$addr(0));		# h1*r0
++	&vpaddq		($D1,$D1,$T0);			# d1 += h1*r0
++	&vpmuludq	($T2,$T2,&$addr(1));		# h1*r1
++	&vpaddq		($D2,$D2,$T2);			# d2 += h1*r1
++
++	&vpmuludq	($T0,$T1,&$addr(0));		# h3*r0
++	&vpaddq		($D3,$D3,$T0);			# d3 += h3*r0
++	&vpmuludq	($T2,$T1,&$addr(1));		# h3*r1
++	&vpaddq		($D4,$D4,$T2);			# d4 += h3*r1
++	&vpmuludq	($T0,$T1,&$addr(6));		# h3*s2
++	&vpaddq		($D0,$D0,$T0);			# d0 += h3*s2
++	 &vmovdqa	($T0,&QWP(32*4,"esp"));		# h4
++	&vpmuludq	($T2,$T1,&$addr(7));		# h3*s3
++	&vpaddq		($D1,$D1,$T2);			# d1+= h3*s3
++	&vpmuludq	($T1,$T1,&$addr(8));		# h3*s4
++	&vpaddq		($D2,$D2,$T1);			# d2 += h3*s4
++
++	&vpmuludq	($T2,$T0,&$addr(8));		# h4*s4
++	&vpaddq		($D3,$D3,$T2);			# d3 += h4*s4
++	&vpmuludq	($T1,$T0,&$addr(5));		# h4*s1
++	&vpaddq		($D0,$D0,$T1);			# d0 += h4*s1
++	&vpmuludq	($T2,$T0,&$addr(0));		# h4*r0
++	&vpaddq		($D4,$D4,$T2);			# d4 += h4*r0
++	 &vmovdqa	($MASK,&QWP(64,"ebx"));
++	&vpmuludq	($T1,$T0,&$addr(6));		# h4*s2
++	&vpaddq		($D1,$D1,$T1);			# d1 += h4*s2
++	&vpmuludq	($T0,$T0,&$addr(7));		# h4*s3
++	&vpaddq		($D2,$D2,$T0);			# d2 += h4*s3
++}
++	&vpmuladd	(sub {	my $i=shift; &QWP(32*$i-128,"edx");	});
++
++sub vlazy_reduction {
++	################################################################
++	# lazy reduction
++
++	 &vpsrlq	($T0,$D3,26);
++	 &vpand		($D3,$D3,$MASK);
++	&vpsrlq		($T1,$D0,26);
++	&vpand		($D0,$D0,$MASK);
++	 &vpaddq	($D4,$D4,$T0);			# h3 -> h4
++	&vpaddq		($D1,$D1,$T1);			# h0 -> h1
++	 &vpsrlq	($T0,$D4,26);
++	 &vpand		($D4,$D4,$MASK);
++	&vpsrlq		($T1,$D1,26);
++	&vpand		($D1,$D1,$MASK);
++	&vpaddq		($D2,$D2,$T1);			# h1 -> h2
++	 &vpaddq	($D0,$D0,$T0);
++	 &vpsllq	($T0,$T0,2);
++	&vpsrlq		($T1,$D2,26);
++	&vpand		($D2,$D2,$MASK);
++	 &vpaddq	($D0,$D0,$T0);			# h4 -> h0
++	&vpaddq		($D3,$D3,$T1);			# h2 -> h3
++	&vpsrlq		($T1,$D3,26);
++	 &vpsrlq	($T0,$D0,26);
++	 &vpand		($D0,$D0,$MASK);
++	&vpand		($D3,$D3,$MASK);
++	 &vpaddq	($D1,$D1,$T0);			# h0 -> h1
++	&vpaddq		($D4,$D4,$T1);			# h3 -> h4
++}
++	&vlazy_reduction();
++
++	&vmovdqu	(&X($T0),&QWP(16*0,"esi"));	# load input
++	&vmovdqu	(&X($T1),&QWP(16*1,"esi"));
++	&vinserti128	($T0,$T0,&QWP(16*2,"esi"),1);
++	&vinserti128	($T1,$T1,&QWP(16*3,"esi"),1);
++	&lea		("esi",&DWP(16*4,"esi"));
++	&sub		("ecx",64);
++	&jnz		(&label("loop"));
++
++&set_label("tail");
++	&vsplat_input	();
++	&and		("ebx",-64);			# restore pointer
++
++	&vpmuladd	(sub {	my $i=shift; &QWP(4+32*$i-128,"edx");	});
++
++	################################################################
++	# horizontal addition
++
++	&vpsrldq	($T0,$D4,8);
++	&vpsrldq	($T1,$D3,8);
++	&vpaddq		($D4,$D4,$T0);
++	&vpsrldq	($T0,$D0,8);
++	&vpaddq		($D3,$D3,$T1);
++	&vpsrldq	($T1,$D1,8);
++	&vpaddq		($D0,$D0,$T0);
++	&vpsrldq	($T0,$D2,8);
++	&vpaddq		($D1,$D1,$T1);
++	&vpermq		($T1,$D4,2);			# keep folding
++	&vpaddq		($D2,$D2,$T0);
++	&vpermq		($T0,$D3,2);
++	&vpaddq		($D4,$D4,$T1);
++	&vpermq		($T1,$D0,2);
++	&vpaddq		($D3,$D3,$T0);
++	&vpermq		($T0,$D1,2);
++	&vpaddq		($D0,$D0,$T1);
++	&vpermq		($T1,$D2,2);
++	&vpaddq		($D1,$D1,$T0);
++	&vpaddq		($D2,$D2,$T1);
++
++	&vlazy_reduction();
++
++	&cmp		("ecx",0);
++	&je		(&label("done"));
++
++	################################################################
++	# clear all but single word
++
++	&vpshufd	(&X($D0),&X($D0),0b11111100);
++	&lea		("edx",&DWP(32*5+128,"esp"));	# restore pointer
++	&vpshufd	(&X($D1),&X($D1),0b11111100);
++	&vpshufd	(&X($D2),&X($D2),0b11111100);
++	&vpshufd	(&X($D3),&X($D3),0b11111100);
++	&vpshufd	(&X($D4),&X($D4),0b11111100);
++	&jmp		(&label("even"));
++
++&set_label("done",16);
++	&vmovd		(&DWP(-16*3+4*0,"edi"),&X($D0));# store hash value
++	&vmovd		(&DWP(-16*3+4*1,"edi"),&X($D1));
++	&vmovd		(&DWP(-16*3+4*2,"edi"),&X($D2));
++	&vmovd		(&DWP(-16*3+4*3,"edi"),&X($D3));
++	&vmovd		(&DWP(-16*3+4*4,"edi"),&X($D4));
++	&vzeroupper	();
++	&mov	("esp","ebp");
++&set_label("nodata");
++&function_end("_poly1305_blocks_avx2");
++}
++&set_label("const_sse2",64);
++	&data_word(1<<24,0,	1<<24,0,	1<<24,0,	1<<24,0);
++	&data_word(0,0,		0,0,		0,0,		0,0);
++	&data_word(0x03ffffff,0,0x03ffffff,0,	0x03ffffff,0,	0x03ffffff,0);
++	&data_word(0x0fffffff,0x0ffffffc,0x0ffffffc,0x0ffffffc);
++}
++&asciz	("Poly1305 for x86, CRYPTOGAMS by ");
++&align	(4);
++
++&asm_finish();
++
++close STDOUT;
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/poly1305/asm/poly1305-x86_64.pl b/CryptoPkg/Library/OpensslLib/openssl/crypto/poly1305/asm/poly1305-x86_64.pl
+new file mode 100755
+index 0000000..4c22ded
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/poly1305/asm/poly1305-x86_64.pl
+@@ -0,0 +1,2268 @@
++#! /usr/bin/env perl
++# Copyright 2016 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
++# in the file LICENSE in the source distribution or at
++# https://www.openssl.org/source/license.html
++
++#
++# ====================================================================
++# Written by Andy Polyakov  for the OpenSSL
++# project. The module is, however, dual licensed under OpenSSL and
++# CRYPTOGAMS licenses depending on where you obtain it. For further
++# details see http://www.openssl.org/~appro/cryptogams/.
++# ====================================================================
++#
++# This module implements Poly1305 hash for x86_64.
++#
++# March 2015
++#
++# Numbers are cycles per processed byte with poly1305_blocks alone,
++# measured with rdtsc at fixed clock frequency.
++#
++#		IALU/gcc-4.8(*)	AVX(**)		AVX2
++# P4		4.46/+120%	-
++# Core 2	2.41/+90%	-
++# Westmere	1.88/+120%	-
++# Sandy Bridge	1.39/+140%	1.10
++# Haswell	1.14/+175%	1.11		0.65
++# Skylake	1.13/+120%	0.96		0.51
++# Silvermont	2.83/+95%	-
++# Goldmont	1.70/+180%	-
++# VIA Nano	1.82/+150%	-
++# Sledgehammer	1.38/+160%	-
++# Bulldozer	2.30/+130%	0.97
++#
++# (*)	improvement coefficients relative to clang are more modest and
++#	are ~50% on most processors, in both cases we are comparing to
++#	__int128 code;
++# (**)	SSE2 implementation was attempted, but among non-AVX processors
++#	it was faster than integer-only code only on older Intel P4 and
++#	Core processors, 50-30%, less newer processor is, but slower on
++#	contemporary ones, for example almost 2x slower on Atom, and as
++#	former are naturally disappearing, SSE2 is deemed unnecessary;
++
++$flavour = shift;
++$output  = shift;
++if ($flavour =~ /\./) { $output = $flavour; undef $flavour; }
++
++$win64=0; $win64=1 if ($flavour =~ /[nm]asm|mingw64/ || $output =~ /\.asm$/);
++
++$0 =~ m/(.*[\/\\])[^\/\\]+$/; $dir=$1;
++( $xlate="${dir}x86_64-xlate.pl" and -f $xlate ) or
++( $xlate="${dir}../../perlasm/x86_64-xlate.pl" and -f $xlate) or
++die "can't locate x86_64-xlate.pl";
++
++if (`$ENV{CC} -Wa,-v -c -o /dev/null -x assembler /dev/null 2>&1`
++		=~ /GNU assembler version ([2-9]\.[0-9]+)/) {
++	$avx = ($1>=2.19) + ($1>=2.22);
++}
++
++if (!$avx && $win64 && ($flavour =~ /nasm/ || $ENV{ASM} =~ /nasm/) &&
++	   `nasm -v 2>&1` =~ /NASM version ([2-9]\.[0-9]+)/) {
++	$avx = ($1>=2.09) + ($1>=2.10);
++}
++
++if (!$avx && $win64 && ($flavour =~ /masm/ || $ENV{ASM} =~ /ml64/) &&
++	   `ml64 2>&1` =~ /Version ([0-9]+)\./) {
++	$avx = ($1>=10) + ($1>=12);
++}
++
++if (!$avx && `$ENV{CC} -v 2>&1` =~ /((?:^clang|LLVM) version|.*based on LLVM) ([3-9]\.[0-9]+)/) {
++	$avx = ($2>=3.0) + ($2>3.0);
++}
++
++open OUT,"| \"$^X\" \"$xlate\" $flavour \"$output\"";
++*STDOUT=*OUT;
++
++my ($ctx,$inp,$len,$padbit)=("%rdi","%rsi","%rdx","%rcx");
++my ($mac,$nonce)=($inp,$len);	# *_emit arguments
++my ($d1,$d2,$d3, $r0,$r1,$s1)=map("%r$_",(8..13));
++my ($h0,$h1,$h2)=("%r14","%rbx","%rbp");
++
++sub poly1305_iteration {
++# input:	copy of $r1 in %rax, $h0-$h2, $r0-$r1
++# output:	$h0-$h2 *= $r0-$r1
++$code.=<<___;
++	mulq	$h0			# h0*r1
++	mov	%rax,$d2
++	 mov	$r0,%rax
++	mov	%rdx,$d3
++
++	mulq	$h0			# h0*r0
++	mov	%rax,$h0		# future $h0
++	 mov	$r0,%rax
++	mov	%rdx,$d1
++
++	mulq	$h1			# h1*r0
++	add	%rax,$d2
++	 mov	$s1,%rax
++	adc	%rdx,$d3
++
++	mulq	$h1			# h1*s1
++	 mov	$h2,$h1			# borrow $h1
++	add	%rax,$h0
++	adc	%rdx,$d1
++
++	imulq	$s1,$h1			# h2*s1
++	add	$h1,$d2
++	 mov	$d1,$h1
++	adc	\$0,$d3
++
++	imulq	$r0,$h2			# h2*r0
++	add	$d2,$h1
++	mov	\$-4,%rax		# mask value
++	adc	$h2,$d3
++
++	and	$d3,%rax		# last reduction step
++	mov	$d3,$h2
++	shr	\$2,$d3
++	and	\$3,$h2
++	add	$d3,%rax
++	add	%rax,$h0
++	adc	\$0,$h1
++	adc	\$0,$h2
++___
++}
++
++########################################################################
++# Layout of opaque area is following.
++#
++#	unsigned __int64 h[3];		# current hash value base 2^64
++#	unsigned __int64 r[2];		# key value base 2^64
++
++$code.=<<___;
++.text
++
++.extern	OPENSSL_ia32cap_P
++
++.globl	poly1305_init
++.hidden	poly1305_init
++.globl	poly1305_blocks
++.hidden	poly1305_blocks
++.globl	poly1305_emit
++.hidden	poly1305_emit
++
++.type	poly1305_init,\@function,3
++.align	32
++poly1305_init:
++	xor	%rax,%rax
++	mov	%rax,0($ctx)		# initialize hash value
++	mov	%rax,8($ctx)
++	mov	%rax,16($ctx)
++
++	cmp	\$0,$inp
++	je	.Lno_key
++
++	lea	poly1305_blocks(%rip),%r10
++	lea	poly1305_emit(%rip),%r11
++___
++$code.=<<___	if ($avx);
++	mov	OPENSSL_ia32cap_P+4(%rip),%r9
++	lea	poly1305_blocks_avx(%rip),%rax
++	lea	poly1305_emit_avx(%rip),%rcx
++	bt	\$`60-32`,%r9		# AVX?
++	cmovc	%rax,%r10
++	cmovc	%rcx,%r11
++___
++$code.=<<___	if ($avx>1);
++	lea	poly1305_blocks_avx2(%rip),%rax
++	bt	\$`5+32`,%r9		# AVX2?
++	cmovc	%rax,%r10
++___
++$code.=<<___;
++	mov	\$0x0ffffffc0fffffff,%rax
++	mov	\$0x0ffffffc0ffffffc,%rcx
++	and	0($inp),%rax
++	and	8($inp),%rcx
++	mov	%rax,24($ctx)
++	mov	%rcx,32($ctx)
++___
++$code.=<<___	if ($flavour !~ /elf32/);
++	mov	%r10,0(%rdx)
++	mov	%r11,8(%rdx)
++___
++$code.=<<___	if ($flavour =~ /elf32/);
++	mov	%r10d,0(%rdx)
++	mov	%r11d,4(%rdx)
++___
++$code.=<<___;
++	mov	\$1,%eax
++.Lno_key:
++	ret
++.size	poly1305_init,.-poly1305_init
++
++.type	poly1305_blocks,\@function,4
++.align	32
++poly1305_blocks:
++.Lblocks:
++	shr	\$4,$len
++	jz	.Lno_data		# too short
++
++	push	%rbx
++	push	%rbp
++	push	%r12
++	push	%r13
++	push	%r14
++	push	%r15
++.Lblocks_body:
++
++	mov	$len,%r15		# reassign $len
++
++	mov	24($ctx),$r0		# load r
++	mov	32($ctx),$s1
++
++	mov	0($ctx),$h0		# load hash value
++	mov	8($ctx),$h1
++	mov	16($ctx),$h2
++
++	mov	$s1,$r1
++	shr	\$2,$s1
++	mov	$r1,%rax
++	add	$r1,$s1			# s1 = r1 + (r1 >> 2)
++	jmp	.Loop
++
++.align	32
++.Loop:
++	add	0($inp),$h0		# accumulate input
++	adc	8($inp),$h1
++	lea	16($inp),$inp
++	adc	$padbit,$h2
++___
++	&poly1305_iteration();
++$code.=<<___;
++	mov	$r1,%rax
++	dec	%r15			# len-=16
++	jnz	.Loop
++
++	mov	$h0,0($ctx)		# store hash value
++	mov	$h1,8($ctx)
++	mov	$h2,16($ctx)
++
++	mov	0(%rsp),%r15
++	mov	8(%rsp),%r14
++	mov	16(%rsp),%r13
++	mov	24(%rsp),%r12
++	mov	32(%rsp),%rbp
++	mov	40(%rsp),%rbx
++	lea	48(%rsp),%rsp
++.Lno_data:
++.Lblocks_epilogue:
++	ret
++.size	poly1305_blocks,.-poly1305_blocks
++
++.type	poly1305_emit,\@function,3
++.align	32
++poly1305_emit:
++.Lemit:
++	mov	0($ctx),%r8	# load hash value
++	mov	8($ctx),%r9
++	mov	16($ctx),%r10
++
++	mov	%r8,%rax
++	add	\$5,%r8		# compare to modulus
++	mov	%r9,%rcx
++	adc	\$0,%r9
++	adc	\$0,%r10
++	shr	\$2,%r10	# did 130-bit value overfow?
++	cmovnz	%r8,%rax
++	cmovnz	%r9,%rcx
++
++	add	0($nonce),%rax	# accumulate nonce
++	adc	8($nonce),%rcx
++	mov	%rax,0($mac)	# write result
++	mov	%rcx,8($mac)
++
++	ret
++.size	poly1305_emit,.-poly1305_emit
++___
++if ($avx) {
++
++########################################################################
++# Layout of opaque area is following.
++#
++#	unsigned __int32 h[5];		# current hash value base 2^26
++#	unsigned __int32 is_base2_26;
++#	unsigned __int64 r[2];		# key value base 2^64
++#	unsigned __int64 pad;
++#	struct { unsigned __int32 r^2, r^1, r^4, r^3; } r[9];
++#
++# where r^n are base 2^26 digits of degrees of multiplier key. There are
++# 5 digits, but last four are interleaved with multiples of 5, totalling
++# in 9 elements: r0, r1, 5*r1, r2, 5*r2, r3, 5*r3, r4, 5*r4.
++
++my ($H0,$H1,$H2,$H3,$H4, $T0,$T1,$T2,$T3,$T4, $D0,$D1,$D2,$D3,$D4, $MASK) =
++    map("%xmm$_",(0..15));
++
++$code.=<<___;
++.type	__poly1305_block,\@abi-omnipotent
++.align	32
++__poly1305_block:
++___
++	&poly1305_iteration();
++$code.=<<___;
++	ret
++.size	__poly1305_block,.-__poly1305_block
++
++.type	__poly1305_init_avx,\@abi-omnipotent
++.align	32
++__poly1305_init_avx:
++	mov	$r0,$h0
++	mov	$r1,$h1
++	xor	$h2,$h2
++
++	lea	48+64($ctx),$ctx	# size optimization
++
++	mov	$r1,%rax
++	call	__poly1305_block	# r^2
++
++	mov	\$0x3ffffff,%eax	# save interleaved r^2 and r base 2^26
++	mov	\$0x3ffffff,%edx
++	mov	$h0,$d1
++	and	$h0#d,%eax
++	mov	$r0,$d2
++	and	$r0#d,%edx
++	mov	%eax,`16*0+0-64`($ctx)
++	shr	\$26,$d1
++	mov	%edx,`16*0+4-64`($ctx)
++	shr	\$26,$d2
++
++	mov	\$0x3ffffff,%eax
++	mov	\$0x3ffffff,%edx
++	and	$d1#d,%eax
++	and	$d2#d,%edx
++	mov	%eax,`16*1+0-64`($ctx)
++	lea	(%rax,%rax,4),%eax	# *5
++	mov	%edx,`16*1+4-64`($ctx)
++	lea	(%rdx,%rdx,4),%edx	# *5
++	mov	%eax,`16*2+0-64`($ctx)
++	shr	\$26,$d1
++	mov	%edx,`16*2+4-64`($ctx)
++	shr	\$26,$d2
++
++	mov	$h1,%rax
++	mov	$r1,%rdx
++	shl	\$12,%rax
++	shl	\$12,%rdx
++	or	$d1,%rax
++	or	$d2,%rdx
++	and	\$0x3ffffff,%eax
++	and	\$0x3ffffff,%edx
++	mov	%eax,`16*3+0-64`($ctx)
++	lea	(%rax,%rax,4),%eax	# *5
++	mov	%edx,`16*3+4-64`($ctx)
++	lea	(%rdx,%rdx,4),%edx	# *5
++	mov	%eax,`16*4+0-64`($ctx)
++	mov	$h1,$d1
++	mov	%edx,`16*4+4-64`($ctx)
++	mov	$r1,$d2
++
++	mov	\$0x3ffffff,%eax
++	mov	\$0x3ffffff,%edx
++	shr	\$14,$d1
++	shr	\$14,$d2
++	and	$d1#d,%eax
++	and	$d2#d,%edx
++	mov	%eax,`16*5+0-64`($ctx)
++	lea	(%rax,%rax,4),%eax	# *5
++	mov	%edx,`16*5+4-64`($ctx)
++	lea	(%rdx,%rdx,4),%edx	# *5
++	mov	%eax,`16*6+0-64`($ctx)
++	shr	\$26,$d1
++	mov	%edx,`16*6+4-64`($ctx)
++	shr	\$26,$d2
++
++	mov	$h2,%rax
++	shl	\$24,%rax
++	or	%rax,$d1
++	mov	$d1#d,`16*7+0-64`($ctx)
++	lea	($d1,$d1,4),$d1		# *5
++	mov	$d2#d,`16*7+4-64`($ctx)
++	lea	($d2,$d2,4),$d2		# *5
++	mov	$d1#d,`16*8+0-64`($ctx)
++	mov	$d2#d,`16*8+4-64`($ctx)
++
++	mov	$r1,%rax
++	call	__poly1305_block	# r^3
++
++	mov	\$0x3ffffff,%eax	# save r^3 base 2^26
++	mov	$h0,$d1
++	and	$h0#d,%eax
++	shr	\$26,$d1
++	mov	%eax,`16*0+12-64`($ctx)
++
++	mov	\$0x3ffffff,%edx
++	and	$d1#d,%edx
++	mov	%edx,`16*1+12-64`($ctx)
++	lea	(%rdx,%rdx,4),%edx	# *5
++	shr	\$26,$d1
++	mov	%edx,`16*2+12-64`($ctx)
++
++	mov	$h1,%rax
++	shl	\$12,%rax
++	or	$d1,%rax
++	and	\$0x3ffffff,%eax
++	mov	%eax,`16*3+12-64`($ctx)
++	lea	(%rax,%rax,4),%eax	# *5
++	mov	$h1,$d1
++	mov	%eax,`16*4+12-64`($ctx)
++
++	mov	\$0x3ffffff,%edx
++	shr	\$14,$d1
++	and	$d1#d,%edx
++	mov	%edx,`16*5+12-64`($ctx)
++	lea	(%rdx,%rdx,4),%edx	# *5
++	shr	\$26,$d1
++	mov	%edx,`16*6+12-64`($ctx)
++
++	mov	$h2,%rax
++	shl	\$24,%rax
++	or	%rax,$d1
++	mov	$d1#d,`16*7+12-64`($ctx)
++	lea	($d1,$d1,4),$d1		# *5
++	mov	$d1#d,`16*8+12-64`($ctx)
++
++	mov	$r1,%rax
++	call	__poly1305_block	# r^4
++
++	mov	\$0x3ffffff,%eax	# save r^4 base 2^26
++	mov	$h0,$d1
++	and	$h0#d,%eax
++	shr	\$26,$d1
++	mov	%eax,`16*0+8-64`($ctx)
++
++	mov	\$0x3ffffff,%edx
++	and	$d1#d,%edx
++	mov	%edx,`16*1+8-64`($ctx)
++	lea	(%rdx,%rdx,4),%edx	# *5
++	shr	\$26,$d1
++	mov	%edx,`16*2+8-64`($ctx)
++
++	mov	$h1,%rax
++	shl	\$12,%rax
++	or	$d1,%rax
++	and	\$0x3ffffff,%eax
++	mov	%eax,`16*3+8-64`($ctx)
++	lea	(%rax,%rax,4),%eax	# *5
++	mov	$h1,$d1
++	mov	%eax,`16*4+8-64`($ctx)
++
++	mov	\$0x3ffffff,%edx
++	shr	\$14,$d1
++	and	$d1#d,%edx
++	mov	%edx,`16*5+8-64`($ctx)
++	lea	(%rdx,%rdx,4),%edx	# *5
++	shr	\$26,$d1
++	mov	%edx,`16*6+8-64`($ctx)
++
++	mov	$h2,%rax
++	shl	\$24,%rax
++	or	%rax,$d1
++	mov	$d1#d,`16*7+8-64`($ctx)
++	lea	($d1,$d1,4),$d1		# *5
++	mov	$d1#d,`16*8+8-64`($ctx)
++
++	lea	-48-64($ctx),$ctx	# size [de-]optimization
++	ret
++.size	__poly1305_init_avx,.-__poly1305_init_avx
++
++.type	poly1305_blocks_avx,\@function,4
++.align	32
++poly1305_blocks_avx:
++	mov	20($ctx),%r8d		# is_base2_26
++	cmp	\$128,$len
++	jae	.Lblocks_avx
++	test	%r8d,%r8d
++	jz	.Lblocks
++
++.Lblocks_avx:
++	and	\$-16,$len
++	jz	.Lno_data_avx
++
++	vzeroupper
++
++	test	%r8d,%r8d
++	jz	.Lbase2_64_avx
++
++	test	\$31,$len
++	jz	.Leven_avx
++
++	push	%rbx
++	push	%rbp
++	push	%r12
++	push	%r13
++	push	%r14
++	push	%r15
++.Lblocks_avx_body:
++
++	mov	$len,%r15		# reassign $len
++
++	mov	0($ctx),$d1		# load hash value
++	mov	8($ctx),$d2
++	mov	16($ctx),$h2#d
++
++	mov	24($ctx),$r0		# load r
++	mov	32($ctx),$s1
++
++	################################# base 2^26 -> base 2^64
++	mov	$d1#d,$h0#d
++	and	\$`-1*(1<<31)`,$d1
++	mov	$d2,$r1			# borrow $r1
++	mov	$d2#d,$h1#d
++	and	\$`-1*(1<<31)`,$d2
++
++	shr	\$6,$d1
++	shl	\$52,$r1
++	add	$d1,$h0
++	shr	\$12,$h1
++	shr	\$18,$d2
++	add	$r1,$h0
++	adc	$d2,$h1
++
++	mov	$h2,$d1
++	shl	\$40,$d1
++	shr	\$24,$h2
++	add	$d1,$h1
++	adc	\$0,$h2			# can be partially reduced...
++
++	mov	\$-4,$d2		# ... so reduce
++	mov	$h2,$d1
++	and	$h2,$d2
++	shr	\$2,$d1
++	and	\$3,$h2
++	add	$d2,$d1			# =*5
++	add	$d1,$h0
++	adc	\$0,$h1
++	adc	\$0,$h2
++
++	mov	$s1,$r1
++	mov	$s1,%rax
++	shr	\$2,$s1
++	add	$r1,$s1			# s1 = r1 + (r1 >> 2)
++
++	add	0($inp),$h0		# accumulate input
++	adc	8($inp),$h1
++	lea	16($inp),$inp
++	adc	$padbit,$h2
++
++	call	__poly1305_block
++
++	test	$padbit,$padbit		# if $padbit is zero,
++	jz	.Lstore_base2_64_avx	# store hash in base 2^64 format
++
++	################################# base 2^64 -> base 2^26
++	mov	$h0,%rax
++	mov	$h0,%rdx
++	shr	\$52,$h0
++	mov	$h1,$r0
++	mov	$h1,$r1
++	shr	\$26,%rdx
++	and	\$0x3ffffff,%rax	# h[0]
++	shl	\$12,$r0
++	and	\$0x3ffffff,%rdx	# h[1]
++	shr	\$14,$h1
++	or	$r0,$h0
++	shl	\$24,$h2
++	and	\$0x3ffffff,$h0		# h[2]
++	shr	\$40,$r1
++	and	\$0x3ffffff,$h1		# h[3]
++	or	$r1,$h2			# h[4]
++
++	sub	\$16,%r15
++	jz	.Lstore_base2_26_avx
++
++	vmovd	%rax#d,$H0
++	vmovd	%rdx#d,$H1
++	vmovd	$h0#d,$H2
++	vmovd	$h1#d,$H3
++	vmovd	$h2#d,$H4
++	jmp	.Lproceed_avx
++
++.align	32
++.Lstore_base2_64_avx:
++	mov	$h0,0($ctx)
++	mov	$h1,8($ctx)
++	mov	$h2,16($ctx)		# note that is_base2_26 is zeroed
++	jmp	.Ldone_avx
++
++.align	16
++.Lstore_base2_26_avx:
++	mov	%rax#d,0($ctx)		# store hash value base 2^26
++	mov	%rdx#d,4($ctx)
++	mov	$h0#d,8($ctx)
++	mov	$h1#d,12($ctx)
++	mov	$h2#d,16($ctx)
++.align	16
++.Ldone_avx:
++	mov	0(%rsp),%r15
++	mov	8(%rsp),%r14
++	mov	16(%rsp),%r13
++	mov	24(%rsp),%r12
++	mov	32(%rsp),%rbp
++	mov	40(%rsp),%rbx
++	lea	48(%rsp),%rsp
++.Lno_data_avx:
++.Lblocks_avx_epilogue:
++	ret
++
++.align	32
++.Lbase2_64_avx:
++	push	%rbx
++	push	%rbp
++	push	%r12
++	push	%r13
++	push	%r14
++	push	%r15
++.Lbase2_64_avx_body:
++
++	mov	$len,%r15		# reassign $len
++
++	mov	24($ctx),$r0		# load r
++	mov	32($ctx),$s1
++
++	mov	0($ctx),$h0		# load hash value
++	mov	8($ctx),$h1
++	mov	16($ctx),$h2#d
++
++	mov	$s1,$r1
++	mov	$s1,%rax
++	shr	\$2,$s1
++	add	$r1,$s1			# s1 = r1 + (r1 >> 2)
++
++	test	\$31,$len
++	jz	.Linit_avx
++
++	add	0($inp),$h0		# accumulate input
++	adc	8($inp),$h1
++	lea	16($inp),$inp
++	adc	$padbit,$h2
++	sub	\$16,%r15
++
++	call	__poly1305_block
++
++.Linit_avx:
++	################################# base 2^64 -> base 2^26
++	mov	$h0,%rax
++	mov	$h0,%rdx
++	shr	\$52,$h0
++	mov	$h1,$d1
++	mov	$h1,$d2
++	shr	\$26,%rdx
++	and	\$0x3ffffff,%rax	# h[0]
++	shl	\$12,$d1
++	and	\$0x3ffffff,%rdx	# h[1]
++	shr	\$14,$h1
++	or	$d1,$h0
++	shl	\$24,$h2
++	and	\$0x3ffffff,$h0		# h[2]
++	shr	\$40,$d2
++	and	\$0x3ffffff,$h1		# h[3]
++	or	$d2,$h2			# h[4]
++
++	vmovd	%rax#d,$H0
++	vmovd	%rdx#d,$H1
++	vmovd	$h0#d,$H2
++	vmovd	$h1#d,$H3
++	vmovd	$h2#d,$H4
++	movl	\$1,20($ctx)		# set is_base2_26
++
++	call	__poly1305_init_avx
++
++.Lproceed_avx:
++	mov	%r15,$len
++
++	mov	0(%rsp),%r15
++	mov	8(%rsp),%r14
++	mov	16(%rsp),%r13
++	mov	24(%rsp),%r12
++	mov	32(%rsp),%rbp
++	mov	40(%rsp),%rbx
++	lea	48(%rsp),%rax
++	lea	48(%rsp),%rsp
++.Lbase2_64_avx_epilogue:
++	jmp	.Ldo_avx
++
++.align	32
++.Leven_avx:
++	vmovd		4*0($ctx),$H0		# load hash value
++	vmovd		4*1($ctx),$H1
++	vmovd		4*2($ctx),$H2
++	vmovd		4*3($ctx),$H3
++	vmovd		4*4($ctx),$H4
++
++.Ldo_avx:
++___
++$code.=<<___	if (!$win64);
++	lea		-0x58(%rsp),%r11
++	sub		\$0x178,%rsp
++___
++$code.=<<___	if ($win64);
++	lea		-0xf8(%rsp),%r11
++	sub		\$0x218,%rsp
++	vmovdqa		%xmm6,0x50(%r11)
++	vmovdqa		%xmm7,0x60(%r11)
++	vmovdqa		%xmm8,0x70(%r11)
++	vmovdqa		%xmm9,0x80(%r11)
++	vmovdqa		%xmm10,0x90(%r11)
++	vmovdqa		%xmm11,0xa0(%r11)
++	vmovdqa		%xmm12,0xb0(%r11)
++	vmovdqa		%xmm13,0xc0(%r11)
++	vmovdqa		%xmm14,0xd0(%r11)
++	vmovdqa		%xmm15,0xe0(%r11)
++.Ldo_avx_body:
++___
++$code.=<<___;
++	sub		\$64,$len
++	lea		-32($inp),%rax
++	cmovc		%rax,$inp
++
++	vmovdqu		`16*3`($ctx),$D4	# preload r0^2
++	lea		`16*3+64`($ctx),$ctx	# size optimization
++	lea		.Lconst(%rip),%rcx
++
++	################################################################
++	# load input
++	vmovdqu		16*2($inp),$T0
++	vmovdqu		16*3($inp),$T1
++	vmovdqa		64(%rcx),$MASK		# .Lmask26
++
++	vpsrldq		\$6,$T0,$T2		# splat input
++	vpsrldq		\$6,$T1,$T3
++	vpunpckhqdq	$T1,$T0,$T4		# 4
++	vpunpcklqdq	$T1,$T0,$T0		# 0:1
++	vpunpcklqdq	$T3,$T2,$T3		# 2:3
++
++	vpsrlq		\$40,$T4,$T4		# 4
++	vpsrlq		\$26,$T0,$T1
++	vpand		$MASK,$T0,$T0		# 0
++	vpsrlq		\$4,$T3,$T2
++	vpand		$MASK,$T1,$T1		# 1
++	vpsrlq		\$30,$T3,$T3
++	vpand		$MASK,$T2,$T2		# 2
++	vpand		$MASK,$T3,$T3		# 3
++	vpor		32(%rcx),$T4,$T4	# padbit, yes, always
++
++	jbe		.Lskip_loop_avx
++
++	# expand and copy pre-calculated table to stack
++	vmovdqu		`16*1-64`($ctx),$D1
++	vmovdqu		`16*2-64`($ctx),$D2
++	vpshufd		\$0xEE,$D4,$D3		# 34xx -> 3434
++	vpshufd		\$0x44,$D4,$D0		# xx12 -> 1212
++	vmovdqa		$D3,-0x90(%r11)
++	vmovdqa		$D0,0x00(%rsp)
++	vpshufd		\$0xEE,$D1,$D4
++	vmovdqu		`16*3-64`($ctx),$D0
++	vpshufd		\$0x44,$D1,$D1
++	vmovdqa		$D4,-0x80(%r11)
++	vmovdqa		$D1,0x10(%rsp)
++	vpshufd		\$0xEE,$D2,$D3
++	vmovdqu		`16*4-64`($ctx),$D1
++	vpshufd		\$0x44,$D2,$D2
++	vmovdqa		$D3,-0x70(%r11)
++	vmovdqa		$D2,0x20(%rsp)
++	vpshufd		\$0xEE,$D0,$D4
++	vmovdqu		`16*5-64`($ctx),$D2
++	vpshufd		\$0x44,$D0,$D0
++	vmovdqa		$D4,-0x60(%r11)
++	vmovdqa		$D0,0x30(%rsp)
++	vpshufd		\$0xEE,$D1,$D3
++	vmovdqu		`16*6-64`($ctx),$D0
++	vpshufd		\$0x44,$D1,$D1
++	vmovdqa		$D3,-0x50(%r11)
++	vmovdqa		$D1,0x40(%rsp)
++	vpshufd		\$0xEE,$D2,$D4
++	vmovdqu		`16*7-64`($ctx),$D1
++	vpshufd		\$0x44,$D2,$D2
++	vmovdqa		$D4,-0x40(%r11)
++	vmovdqa		$D2,0x50(%rsp)
++	vpshufd		\$0xEE,$D0,$D3
++	vmovdqu		`16*8-64`($ctx),$D2
++	vpshufd		\$0x44,$D0,$D0
++	vmovdqa		$D3,-0x30(%r11)
++	vmovdqa		$D0,0x60(%rsp)
++	vpshufd		\$0xEE,$D1,$D4
++	vpshufd		\$0x44,$D1,$D1
++	vmovdqa		$D4,-0x20(%r11)
++	vmovdqa		$D1,0x70(%rsp)
++	vpshufd		\$0xEE,$D2,$D3
++	 vmovdqa	0x00(%rsp),$D4		# preload r0^2
++	vpshufd		\$0x44,$D2,$D2
++	vmovdqa		$D3,-0x10(%r11)
++	vmovdqa		$D2,0x80(%rsp)
++
++	jmp		.Loop_avx
++
++.align	32
++.Loop_avx:
++	################################################################
++	# ((inp[0]*r^4+inp[2]*r^2+inp[4])*r^4+inp[6]*r^2
++	# ((inp[1]*r^4+inp[3]*r^2+inp[5])*r^3+inp[7]*r
++	#   \___________________/
++	# ((inp[0]*r^4+inp[2]*r^2+inp[4])*r^4+inp[6]*r^2+inp[8])*r^2
++	# ((inp[1]*r^4+inp[3]*r^2+inp[5])*r^4+inp[7]*r^2+inp[9])*r
++	#   \___________________/ \____________________/
++	#
++	# Note that we start with inp[2:3]*r^2. This is because it
++	# doesn't depend on reduction in previous iteration.
++	################################################################
++	# d4 = h4*r0 + h3*r1   + h2*r2   + h1*r3   + h0*r4
++	# d3 = h3*r0 + h2*r1   + h1*r2   + h0*r3   + h4*5*r4
++	# d2 = h2*r0 + h1*r1   + h0*r2   + h4*5*r3 + h3*5*r4
++	# d1 = h1*r0 + h0*r1   + h4*5*r2 + h3*5*r3 + h2*5*r4
++	# d0 = h0*r0 + h4*5*r1 + h3*5*r2 + h2*5*r3 + h1*5*r4
++	#
++	# though note that $Tx and $Hx are "reversed" in this section,
++	# and $D4 is preloaded with r0^2...
++
++	vpmuludq	$T0,$D4,$D0		# d0 = h0*r0
++	vpmuludq	$T1,$D4,$D1		# d1 = h1*r0
++	  vmovdqa	$H2,0x20(%r11)				# offload hash
++	vpmuludq	$T2,$D4,$D2		# d3 = h2*r0
++	 vmovdqa	0x10(%rsp),$H2		# r1^2
++	vpmuludq	$T3,$D4,$D3		# d3 = h3*r0
++	vpmuludq	$T4,$D4,$D4		# d4 = h4*r0
++
++	  vmovdqa	$H0,0x00(%r11)				#
++	vpmuludq	0x20(%rsp),$T4,$H0	# h4*s1
++	  vmovdqa	$H1,0x10(%r11)				#
++	vpmuludq	$T3,$H2,$H1		# h3*r1
++	vpaddq		$H0,$D0,$D0		# d0 += h4*s1
++	vpaddq		$H1,$D4,$D4		# d4 += h3*r1
++	  vmovdqa	$H3,0x30(%r11)				#
++	vpmuludq	$T2,$H2,$H0		# h2*r1
++	vpmuludq	$T1,$H2,$H1		# h1*r1
++	vpaddq		$H0,$D3,$D3		# d3 += h2*r1
++	 vmovdqa	0x30(%rsp),$H3		# r2^2
++	vpaddq		$H1,$D2,$D2		# d2 += h1*r1
++	  vmovdqa	$H4,0x40(%r11)				#
++	vpmuludq	$T0,$H2,$H2		# h0*r1
++	 vpmuludq	$T2,$H3,$H0		# h2*r2
++	vpaddq		$H2,$D1,$D1		# d1 += h0*r1
++
++	 vmovdqa	0x40(%rsp),$H4		# s2^2
++	vpaddq		$H0,$D4,$D4		# d4 += h2*r2
++	vpmuludq	$T1,$H3,$H1		# h1*r2
++	vpmuludq	$T0,$H3,$H3		# h0*r2
++	vpaddq		$H1,$D3,$D3		# d3 += h1*r2
++	 vmovdqa	0x50(%rsp),$H2		# r3^2
++	vpaddq		$H3,$D2,$D2		# d2 += h0*r2
++	vpmuludq	$T4,$H4,$H0		# h4*s2
++	vpmuludq	$T3,$H4,$H4		# h3*s2
++	vpaddq		$H0,$D1,$D1		# d1 += h4*s2
++	 vmovdqa	0x60(%rsp),$H3		# s3^2
++	vpaddq		$H4,$D0,$D0		# d0 += h3*s2
++
++	 vmovdqa	0x80(%rsp),$H4		# s4^2
++	vpmuludq	$T1,$H2,$H1		# h1*r3
++	vpmuludq	$T0,$H2,$H2		# h0*r3
++	vpaddq		$H1,$D4,$D4		# d4 += h1*r3
++	vpaddq		$H2,$D3,$D3		# d3 += h0*r3
++	vpmuludq	$T4,$H3,$H0		# h4*s3
++	vpmuludq	$T3,$H3,$H1		# h3*s3
++	vpaddq		$H0,$D2,$D2		# d2 += h4*s3
++	 vmovdqu	16*0($inp),$H0				# load input
++	vpaddq		$H1,$D1,$D1		# d1 += h3*s3
++	vpmuludq	$T2,$H3,$H3		# h2*s3
++	 vpmuludq	$T2,$H4,$T2		# h2*s4
++	vpaddq		$H3,$D0,$D0		# d0 += h2*s3
++
++	 vmovdqu	16*1($inp),$H1				#
++	vpaddq		$T2,$D1,$D1		# d1 += h2*s4
++	vpmuludq	$T3,$H4,$T3		# h3*s4
++	vpmuludq	$T4,$H4,$T4		# h4*s4
++	 vpsrldq	\$6,$H0,$H2				# splat input
++	vpaddq		$T3,$D2,$D2		# d2 += h3*s4
++	vpaddq		$T4,$D3,$D3		# d3 += h4*s4
++	 vpsrldq	\$6,$H1,$H3				#
++	vpmuludq	0x70(%rsp),$T0,$T4	# h0*r4
++	vpmuludq	$T1,$H4,$T0		# h1*s4
++	 vpunpckhqdq	$H1,$H0,$H4		# 4
++	vpaddq		$T4,$D4,$D4		# d4 += h0*r4
++	 vmovdqa	-0x90(%r11),$T4		# r0^4
++	vpaddq		$T0,$D0,$D0		# d0 += h1*s4
++
++	vpunpcklqdq	$H1,$H0,$H0		# 0:1
++	vpunpcklqdq	$H3,$H2,$H3		# 2:3
++
++	#vpsrlq		\$40,$H4,$H4		# 4
++	vpsrldq		\$`40/8`,$H4,$H4	# 4
++	vpsrlq		\$26,$H0,$H1
++	vpand		$MASK,$H0,$H0		# 0
++	vpsrlq		\$4,$H3,$H2
++	vpand		$MASK,$H1,$H1		# 1
++	vpand		0(%rcx),$H4,$H4		# .Lmask24
++	vpsrlq		\$30,$H3,$H3
++	vpand		$MASK,$H2,$H2		# 2
++	vpand		$MASK,$H3,$H3		# 3
++	vpor		32(%rcx),$H4,$H4	# padbit, yes, always
++
++	vpaddq		0x00(%r11),$H0,$H0	# add hash value
++	vpaddq		0x10(%r11),$H1,$H1
++	vpaddq		0x20(%r11),$H2,$H2
++	vpaddq		0x30(%r11),$H3,$H3
++	vpaddq		0x40(%r11),$H4,$H4
++
++	lea		16*2($inp),%rax
++	lea		16*4($inp),$inp
++	sub		\$64,$len
++	cmovc		%rax,$inp
++
++	################################################################
++	# Now we accumulate (inp[0:1]+hash)*r^4
++	################################################################
++	# d4 = h4*r0 + h3*r1   + h2*r2   + h1*r3   + h0*r4
++	# d3 = h3*r0 + h2*r1   + h1*r2   + h0*r3   + h4*5*r4
++	# d2 = h2*r0 + h1*r1   + h0*r2   + h4*5*r3 + h3*5*r4
++	# d1 = h1*r0 + h0*r1   + h4*5*r2 + h3*5*r3 + h2*5*r4
++	# d0 = h0*r0 + h4*5*r1 + h3*5*r2 + h2*5*r3 + h1*5*r4
++
++	vpmuludq	$H0,$T4,$T0		# h0*r0
++	vpmuludq	$H1,$T4,$T1		# h1*r0
++	vpaddq		$T0,$D0,$D0
++	vpaddq		$T1,$D1,$D1
++	 vmovdqa	-0x80(%r11),$T2		# r1^4
++	vpmuludq	$H2,$T4,$T0		# h2*r0
++	vpmuludq	$H3,$T4,$T1		# h3*r0
++	vpaddq		$T0,$D2,$D2
++	vpaddq		$T1,$D3,$D3
++	vpmuludq	$H4,$T4,$T4		# h4*r0
++	 vpmuludq	-0x70(%r11),$H4,$T0	# h4*s1
++	vpaddq		$T4,$D4,$D4
++
++	vpaddq		$T0,$D0,$D0		# d0 += h4*s1
++	vpmuludq	$H2,$T2,$T1		# h2*r1
++	vpmuludq	$H3,$T2,$T0		# h3*r1
++	vpaddq		$T1,$D3,$D3		# d3 += h2*r1
++	 vmovdqa	-0x60(%r11),$T3		# r2^4
++	vpaddq		$T0,$D4,$D4		# d4 += h3*r1
++	vpmuludq	$H1,$T2,$T1		# h1*r1
++	vpmuludq	$H0,$T2,$T2		# h0*r1
++	vpaddq		$T1,$D2,$D2		# d2 += h1*r1
++	vpaddq		$T2,$D1,$D1		# d1 += h0*r1
++
++	 vmovdqa	-0x50(%r11),$T4		# s2^4
++	vpmuludq	$H2,$T3,$T0		# h2*r2
++	vpmuludq	$H1,$T3,$T1		# h1*r2
++	vpaddq		$T0,$D4,$D4		# d4 += h2*r2
++	vpaddq		$T1,$D3,$D3		# d3 += h1*r2
++	 vmovdqa	-0x40(%r11),$T2		# r3^4
++	vpmuludq	$H0,$T3,$T3		# h0*r2
++	vpmuludq	$H4,$T4,$T0		# h4*s2
++	vpaddq		$T3,$D2,$D2		# d2 += h0*r2
++	vpaddq		$T0,$D1,$D1		# d1 += h4*s2
++	 vmovdqa	-0x30(%r11),$T3		# s3^4
++	vpmuludq	$H3,$T4,$T4		# h3*s2
++	 vpmuludq	$H1,$T2,$T1		# h1*r3
++	vpaddq		$T4,$D0,$D0		# d0 += h3*s2
++
++	 vmovdqa	-0x10(%r11),$T4		# s4^4
++	vpaddq		$T1,$D4,$D4		# d4 += h1*r3
++	vpmuludq	$H0,$T2,$T2		# h0*r3
++	vpmuludq	$H4,$T3,$T0		# h4*s3
++	vpaddq		$T2,$D3,$D3		# d3 += h0*r3
++	vpaddq		$T0,$D2,$D2		# d2 += h4*s3
++	 vmovdqu	16*2($inp),$T0				# load input
++	vpmuludq	$H3,$T3,$T2		# h3*s3
++	vpmuludq	$H2,$T3,$T3		# h2*s3
++	vpaddq		$T2,$D1,$D1		# d1 += h3*s3
++	 vmovdqu	16*3($inp),$T1				#
++	vpaddq		$T3,$D0,$D0		# d0 += h2*s3
++
++	vpmuludq	$H2,$T4,$H2		# h2*s4
++	vpmuludq	$H3,$T4,$H3		# h3*s4
++	 vpsrldq	\$6,$T0,$T2				# splat input
++	vpaddq		$H2,$D1,$D1		# d1 += h2*s4
++	vpmuludq	$H4,$T4,$H4		# h4*s4
++	 vpsrldq	\$6,$T1,$T3				#
++	vpaddq		$H3,$D2,$H2		# h2 = d2 + h3*s4
++	vpaddq		$H4,$D3,$H3		# h3 = d3 + h4*s4
++	vpmuludq	-0x20(%r11),$H0,$H4	# h0*r4
++	vpmuludq	$H1,$T4,$H0
++	 vpunpckhqdq	$T1,$T0,$T4		# 4
++	vpaddq		$H4,$D4,$H4		# h4 = d4 + h0*r4
++	vpaddq		$H0,$D0,$H0		# h0 = d0 + h1*s4
++
++	vpunpcklqdq	$T1,$T0,$T0		# 0:1
++	vpunpcklqdq	$T3,$T2,$T3		# 2:3
++
++	#vpsrlq		\$40,$T4,$T4		# 4
++	vpsrldq		\$`40/8`,$T4,$T4	# 4
++	vpsrlq		\$26,$T0,$T1
++	 vmovdqa	0x00(%rsp),$D4		# preload r0^2
++	vpand		$MASK,$T0,$T0		# 0
++	vpsrlq		\$4,$T3,$T2
++	vpand		$MASK,$T1,$T1		# 1
++	vpand		0(%rcx),$T4,$T4		# .Lmask24
++	vpsrlq		\$30,$T3,$T3
++	vpand		$MASK,$T2,$T2		# 2
++	vpand		$MASK,$T3,$T3		# 3
++	vpor		32(%rcx),$T4,$T4	# padbit, yes, always
++
++	################################################################
++	# lazy reduction as discussed in "NEON crypto" by D.J. Bernstein
++	# and P. Schwabe
++
++	vpsrlq		\$26,$H3,$D3
++	vpand		$MASK,$H3,$H3
++	vpaddq		$D3,$H4,$H4		# h3 -> h4
++
++	vpsrlq		\$26,$H0,$D0
++	vpand		$MASK,$H0,$H0
++	vpaddq		$D0,$D1,$H1		# h0 -> h1
++
++	vpsrlq		\$26,$H4,$D0
++	vpand		$MASK,$H4,$H4
++
++	vpsrlq		\$26,$H1,$D1
++	vpand		$MASK,$H1,$H1
++	vpaddq		$D1,$H2,$H2		# h1 -> h2
++
++	vpaddq		$D0,$H0,$H0
++	vpsllq		\$2,$D0,$D0
++	vpaddq		$D0,$H0,$H0		# h4 -> h0
++
++	vpsrlq		\$26,$H2,$D2
++	vpand		$MASK,$H2,$H2
++	vpaddq		$D2,$H3,$H3		# h2 -> h3
++
++	vpsrlq		\$26,$H0,$D0
++	vpand		$MASK,$H0,$H0
++	vpaddq		$D0,$H1,$H1		# h0 -> h1
++
++	vpsrlq		\$26,$H3,$D3
++	vpand		$MASK,$H3,$H3
++	vpaddq		$D3,$H4,$H4		# h3 -> h4
++
++	ja		.Loop_avx
++
++.Lskip_loop_avx:
++	################################################################
++	# multiply (inp[0:1]+hash) or inp[2:3] by r^2:r^1
++
++	vpshufd		\$0x10,$D4,$D4		# r0^n, xx12 -> x1x2
++	add		\$32,$len
++	jnz		.Long_tail_avx
++
++	vpaddq		$H2,$T2,$T2
++	vpaddq		$H0,$T0,$T0
++	vpaddq		$H1,$T1,$T1
++	vpaddq		$H3,$T3,$T3
++	vpaddq		$H4,$T4,$T4
++
++.Long_tail_avx:
++	vmovdqa		$H2,0x20(%r11)
++	vmovdqa		$H0,0x00(%r11)
++	vmovdqa		$H1,0x10(%r11)
++	vmovdqa		$H3,0x30(%r11)
++	vmovdqa		$H4,0x40(%r11)
++
++	# d4 = h4*r0 + h3*r1   + h2*r2   + h1*r3   + h0*r4
++	# d3 = h3*r0 + h2*r1   + h1*r2   + h0*r3   + h4*5*r4
++	# d2 = h2*r0 + h1*r1   + h0*r2   + h4*5*r3 + h3*5*r4
++	# d1 = h1*r0 + h0*r1   + h4*5*r2 + h3*5*r3 + h2*5*r4
++	# d0 = h0*r0 + h4*5*r1 + h3*5*r2 + h2*5*r3 + h1*5*r4
++
++	vpmuludq	$T2,$D4,$D2		# d2 = h2*r0
++	vpmuludq	$T0,$D4,$D0		# d0 = h0*r0
++	 vpshufd	\$0x10,`16*1-64`($ctx),$H2		# r1^n
++	vpmuludq	$T1,$D4,$D1		# d1 = h1*r0
++	vpmuludq	$T3,$D4,$D3		# d3 = h3*r0
++	vpmuludq	$T4,$D4,$D4		# d4 = h4*r0
++
++	vpmuludq	$T3,$H2,$H0		# h3*r1
++	vpaddq		$H0,$D4,$D4		# d4 += h3*r1
++	 vpshufd	\$0x10,`16*2-64`($ctx),$H3		# s1^n
++	vpmuludq	$T2,$H2,$H1		# h2*r1
++	vpaddq		$H1,$D3,$D3		# d3 += h2*r1
++	 vpshufd	\$0x10,`16*3-64`($ctx),$H4		# r2^n
++	vpmuludq	$T1,$H2,$H0		# h1*r1
++	vpaddq		$H0,$D2,$D2		# d2 += h1*r1
++	vpmuludq	$T0,$H2,$H2		# h0*r1
++	vpaddq		$H2,$D1,$D1		# d1 += h0*r1
++	vpmuludq	$T4,$H3,$H3		# h4*s1
++	vpaddq		$H3,$D0,$D0		# d0 += h4*s1
++
++	 vpshufd	\$0x10,`16*4-64`($ctx),$H2		# s2^n
++	vpmuludq	$T2,$H4,$H1		# h2*r2
++	vpaddq		$H1,$D4,$D4		# d4 += h2*r2
++	vpmuludq	$T1,$H4,$H0		# h1*r2
++	vpaddq		$H0,$D3,$D3		# d3 += h1*r2
++	 vpshufd	\$0x10,`16*5-64`($ctx),$H3		# r3^n
++	vpmuludq	$T0,$H4,$H4		# h0*r2
++	vpaddq		$H4,$D2,$D2		# d2 += h0*r2
++	vpmuludq	$T4,$H2,$H1		# h4*s2
++	vpaddq		$H1,$D1,$D1		# d1 += h4*s2
++	 vpshufd	\$0x10,`16*6-64`($ctx),$H4		# s3^n
++	vpmuludq	$T3,$H2,$H2		# h3*s2
++	vpaddq		$H2,$D0,$D0		# d0 += h3*s2
++
++	vpmuludq	$T1,$H3,$H0		# h1*r3
++	vpaddq		$H0,$D4,$D4		# d4 += h1*r3
++	vpmuludq	$T0,$H3,$H3		# h0*r3
++	vpaddq		$H3,$D3,$D3		# d3 += h0*r3
++	 vpshufd	\$0x10,`16*7-64`($ctx),$H2		# r4^n
++	vpmuludq	$T4,$H4,$H1		# h4*s3
++	vpaddq		$H1,$D2,$D2		# d2 += h4*s3
++	 vpshufd	\$0x10,`16*8-64`($ctx),$H3		# s4^n
++	vpmuludq	$T3,$H4,$H0		# h3*s3
++	vpaddq		$H0,$D1,$D1		# d1 += h3*s3
++	vpmuludq	$T2,$H4,$H4		# h2*s3
++	vpaddq		$H4,$D0,$D0		# d0 += h2*s3
++
++	vpmuludq	$T0,$H2,$H2		# h0*r4
++	vpaddq		$H2,$D4,$D4		# h4 = d4 + h0*r4
++	vpmuludq	$T4,$H3,$H1		# h4*s4
++	vpaddq		$H1,$D3,$D3		# h3 = d3 + h4*s4
++	vpmuludq	$T3,$H3,$H0		# h3*s4
++	vpaddq		$H0,$D2,$D2		# h2 = d2 + h3*s4
++	vpmuludq	$T2,$H3,$H1		# h2*s4
++	vpaddq		$H1,$D1,$D1		# h1 = d1 + h2*s4
++	vpmuludq	$T1,$H3,$H3		# h1*s4
++	vpaddq		$H3,$D0,$D0		# h0 = d0 + h1*s4
++
++	jz		.Lshort_tail_avx
++
++	vmovdqu		16*0($inp),$H0		# load input
++	vmovdqu		16*1($inp),$H1
++
++	vpsrldq		\$6,$H0,$H2		# splat input
++	vpsrldq		\$6,$H1,$H3
++	vpunpckhqdq	$H1,$H0,$H4		# 4
++	vpunpcklqdq	$H1,$H0,$H0		# 0:1
++	vpunpcklqdq	$H3,$H2,$H3		# 2:3
++
++	vpsrlq		\$40,$H4,$H4		# 4
++	vpsrlq		\$26,$H0,$H1
++	vpand		$MASK,$H0,$H0		# 0
++	vpsrlq		\$4,$H3,$H2
++	vpand		$MASK,$H1,$H1		# 1
++	vpsrlq		\$30,$H3,$H3
++	vpand		$MASK,$H2,$H2		# 2
++	vpand		$MASK,$H3,$H3		# 3
++	vpor		32(%rcx),$H4,$H4	# padbit, yes, always
++
++	vpshufd		\$0x32,`16*0-64`($ctx),$T4	# r0^n, 34xx -> x3x4
++	vpaddq		0x00(%r11),$H0,$H0
++	vpaddq		0x10(%r11),$H1,$H1
++	vpaddq		0x20(%r11),$H2,$H2
++	vpaddq		0x30(%r11),$H3,$H3
++	vpaddq		0x40(%r11),$H4,$H4
++
++	################################################################
++	# multiply (inp[0:1]+hash) by r^4:r^3 and accumulate
++
++	vpmuludq	$H0,$T4,$T0		# h0*r0
++	vpaddq		$T0,$D0,$D0		# d0 += h0*r0
++	vpmuludq	$H1,$T4,$T1		# h1*r0
++	vpaddq		$T1,$D1,$D1		# d1 += h1*r0
++	vpmuludq	$H2,$T4,$T0		# h2*r0
++	vpaddq		$T0,$D2,$D2		# d2 += h2*r0
++	 vpshufd	\$0x32,`16*1-64`($ctx),$T2		# r1^n
++	vpmuludq	$H3,$T4,$T1		# h3*r0
++	vpaddq		$T1,$D3,$D3		# d3 += h3*r0
++	vpmuludq	$H4,$T4,$T4		# h4*r0
++	vpaddq		$T4,$D4,$D4		# d4 += h4*r0
++
++	vpmuludq	$H3,$T2,$T0		# h3*r1
++	vpaddq		$T0,$D4,$D4		# d4 += h3*r1
++	 vpshufd	\$0x32,`16*2-64`($ctx),$T3		# s1
++	vpmuludq	$H2,$T2,$T1		# h2*r1
++	vpaddq		$T1,$D3,$D3		# d3 += h2*r1
++	 vpshufd	\$0x32,`16*3-64`($ctx),$T4		# r2
++	vpmuludq	$H1,$T2,$T0		# h1*r1
++	vpaddq		$T0,$D2,$D2		# d2 += h1*r1
++	vpmuludq	$H0,$T2,$T2		# h0*r1
++	vpaddq		$T2,$D1,$D1		# d1 += h0*r1
++	vpmuludq	$H4,$T3,$T3		# h4*s1
++	vpaddq		$T3,$D0,$D0		# d0 += h4*s1
++
++	 vpshufd	\$0x32,`16*4-64`($ctx),$T2		# s2
++	vpmuludq	$H2,$T4,$T1		# h2*r2
++	vpaddq		$T1,$D4,$D4		# d4 += h2*r2
++	vpmuludq	$H1,$T4,$T0		# h1*r2
++	vpaddq		$T0,$D3,$D3		# d3 += h1*r2
++	 vpshufd	\$0x32,`16*5-64`($ctx),$T3		# r3
++	vpmuludq	$H0,$T4,$T4		# h0*r2
++	vpaddq		$T4,$D2,$D2		# d2 += h0*r2
++	vpmuludq	$H4,$T2,$T1		# h4*s2
++	vpaddq		$T1,$D1,$D1		# d1 += h4*s2
++	 vpshufd	\$0x32,`16*6-64`($ctx),$T4		# s3
++	vpmuludq	$H3,$T2,$T2		# h3*s2
++	vpaddq		$T2,$D0,$D0		# d0 += h3*s2
++
++	vpmuludq	$H1,$T3,$T0		# h1*r3
++	vpaddq		$T0,$D4,$D4		# d4 += h1*r3
++	vpmuludq	$H0,$T3,$T3		# h0*r3
++	vpaddq		$T3,$D3,$D3		# d3 += h0*r3
++	 vpshufd	\$0x32,`16*7-64`($ctx),$T2		# r4
++	vpmuludq	$H4,$T4,$T1		# h4*s3
++	vpaddq		$T1,$D2,$D2		# d2 += h4*s3
++	 vpshufd	\$0x32,`16*8-64`($ctx),$T3		# s4
++	vpmuludq	$H3,$T4,$T0		# h3*s3
++	vpaddq		$T0,$D1,$D1		# d1 += h3*s3
++	vpmuludq	$H2,$T4,$T4		# h2*s3
++	vpaddq		$T4,$D0,$D0		# d0 += h2*s3
++
++	vpmuludq	$H0,$T2,$T2		# h0*r4
++	vpaddq		$T2,$D4,$D4		# d4 += h0*r4
++	vpmuludq	$H4,$T3,$T1		# h4*s4
++	vpaddq		$T1,$D3,$D3		# d3 += h4*s4
++	vpmuludq	$H3,$T3,$T0		# h3*s4
++	vpaddq		$T0,$D2,$D2		# d2 += h3*s4
++	vpmuludq	$H2,$T3,$T1		# h2*s4
++	vpaddq		$T1,$D1,$D1		# d1 += h2*s4
++	vpmuludq	$H1,$T3,$T3		# h1*s4
++	vpaddq		$T3,$D0,$D0		# d0 += h1*s4
++
++.Lshort_tail_avx:
++	################################################################
++	# horizontal addition
++
++	vpsrldq		\$8,$D4,$T4
++	vpsrldq		\$8,$D3,$T3
++	vpsrldq		\$8,$D1,$T1
++	vpsrldq		\$8,$D0,$T0
++	vpsrldq		\$8,$D2,$T2
++	vpaddq		$T3,$D3,$D3
++	vpaddq		$T4,$D4,$D4
++	vpaddq		$T0,$D0,$D0
++	vpaddq		$T1,$D1,$D1
++	vpaddq		$T2,$D2,$D2
++
++	################################################################
++	# lazy reduction
++
++	vpsrlq		\$26,$D3,$H3
++	vpand		$MASK,$D3,$D3
++	vpaddq		$H3,$D4,$D4		# h3 -> h4
++
++	vpsrlq		\$26,$D0,$H0
++	vpand		$MASK,$D0,$D0
++	vpaddq		$H0,$D1,$D1		# h0 -> h1
++
++	vpsrlq		\$26,$D4,$H4
++	vpand		$MASK,$D4,$D4
++
++	vpsrlq		\$26,$D1,$H1
++	vpand		$MASK,$D1,$D1
++	vpaddq		$H1,$D2,$D2		# h1 -> h2
++
++	vpaddq		$H4,$D0,$D0
++	vpsllq		\$2,$H4,$H4
++	vpaddq		$H4,$D0,$D0		# h4 -> h0
++
++	vpsrlq		\$26,$D2,$H2
++	vpand		$MASK,$D2,$D2
++	vpaddq		$H2,$D3,$D3		# h2 -> h3
++
++	vpsrlq		\$26,$D0,$H0
++	vpand		$MASK,$D0,$D0
++	vpaddq		$H0,$D1,$D1		# h0 -> h1
++
++	vpsrlq		\$26,$D3,$H3
++	vpand		$MASK,$D3,$D3
++	vpaddq		$H3,$D4,$D4		# h3 -> h4
++
++	vmovd		$D0,`4*0-48-64`($ctx)	# save partially reduced
++	vmovd		$D1,`4*1-48-64`($ctx)
++	vmovd		$D2,`4*2-48-64`($ctx)
++	vmovd		$D3,`4*3-48-64`($ctx)
++	vmovd		$D4,`4*4-48-64`($ctx)
++___
++$code.=<<___	if ($win64);
++	vmovdqa		0x50(%r11),%xmm6
++	vmovdqa		0x60(%r11),%xmm7
++	vmovdqa		0x70(%r11),%xmm8
++	vmovdqa		0x80(%r11),%xmm9
++	vmovdqa		0x90(%r11),%xmm10
++	vmovdqa		0xa0(%r11),%xmm11
++	vmovdqa		0xb0(%r11),%xmm12
++	vmovdqa		0xc0(%r11),%xmm13
++	vmovdqa		0xd0(%r11),%xmm14
++	vmovdqa		0xe0(%r11),%xmm15
++	lea		0xf8(%r11),%rsp
++.Ldo_avx_epilogue:
++___
++$code.=<<___	if (!$win64);
++	lea		0x58(%r11),%rsp
++___
++$code.=<<___;
++	vzeroupper
++	ret
++.size	poly1305_blocks_avx,.-poly1305_blocks_avx
++
++.type	poly1305_emit_avx,\@function,3
++.align	32
++poly1305_emit_avx:
++	cmpl	\$0,20($ctx)	# is_base2_26?
++	je	.Lemit
++
++	mov	0($ctx),%eax	# load hash value base 2^26
++	mov	4($ctx),%ecx
++	mov	8($ctx),%r8d
++	mov	12($ctx),%r11d
++	mov	16($ctx),%r10d
++
++	shl	\$26,%rcx	# base 2^26 -> base 2^64
++	mov	%r8,%r9
++	shl	\$52,%r8
++	add	%rcx,%rax
++	shr	\$12,%r9
++	add	%rax,%r8	# h0
++	adc	\$0,%r9
++
++	shl	\$14,%r11
++	mov	%r10,%rax
++	shr	\$24,%r10
++	add	%r11,%r9
++	shl	\$40,%rax
++	add	%rax,%r9	# h1
++	adc	\$0,%r10	# h2
++
++	mov	%r10,%rax	# could be partially reduced, so reduce
++	mov	%r10,%rcx
++	and	\$3,%r10
++	shr	\$2,%rax
++	and	\$-4,%rcx
++	add	%rcx,%rax
++	add	%rax,%r8
++	adc	\$0,%r9
++	adc	\$0,%r10
++
++	mov	%r8,%rax
++	add	\$5,%r8		# compare to modulus
++	mov	%r9,%rcx
++	adc	\$0,%r9
++	adc	\$0,%r10
++	shr	\$2,%r10	# did 130-bit value overfow?
++	cmovnz	%r8,%rax
++	cmovnz	%r9,%rcx
++
++	add	0($nonce),%rax	# accumulate nonce
++	adc	8($nonce),%rcx
++	mov	%rax,0($mac)	# write result
++	mov	%rcx,8($mac)
++
++	ret
++.size	poly1305_emit_avx,.-poly1305_emit_avx
++___
++
++if ($avx>1) {
++my ($H0,$H1,$H2,$H3,$H4, $MASK, $T4,$T0,$T1,$T2,$T3, $D0,$D1,$D2,$D3,$D4) =
++    map("%ymm$_",(0..15));
++my $S4=$MASK;
++
++$code.=<<___;
++.type	poly1305_blocks_avx2,\@function,4
++.align	32
++poly1305_blocks_avx2:
++	mov	20($ctx),%r8d		# is_base2_26
++	cmp	\$128,$len
++	jae	.Lblocks_avx2
++	test	%r8d,%r8d
++	jz	.Lblocks
++
++.Lblocks_avx2:
++	and	\$-16,$len
++	jz	.Lno_data_avx2
++
++	vzeroupper
++
++	test	%r8d,%r8d
++	jz	.Lbase2_64_avx2
++
++	test	\$63,$len
++	jz	.Leven_avx2
++
++	push	%rbx
++	push	%rbp
++	push	%r12
++	push	%r13
++	push	%r14
++	push	%r15
++.Lblocks_avx2_body:
++
++	mov	$len,%r15		# reassign $len
++
++	mov	0($ctx),$d1		# load hash value
++	mov	8($ctx),$d2
++	mov	16($ctx),$h2#d
++
++	mov	24($ctx),$r0		# load r
++	mov	32($ctx),$s1
++
++	################################# base 2^26 -> base 2^64
++	mov	$d1#d,$h0#d
++	and	\$`-1*(1<<31)`,$d1
++	mov	$d2,$r1			# borrow $r1
++	mov	$d2#d,$h1#d
++	and	\$`-1*(1<<31)`,$d2
++
++	shr	\$6,$d1
++	shl	\$52,$r1
++	add	$d1,$h0
++	shr	\$12,$h1
++	shr	\$18,$d2
++	add	$r1,$h0
++	adc	$d2,$h1
++
++	mov	$h2,$d1
++	shl	\$40,$d1
++	shr	\$24,$h2
++	add	$d1,$h1
++	adc	\$0,$h2			# can be partially reduced...
++
++	mov	\$-4,$d2		# ... so reduce
++	mov	$h2,$d1
++	and	$h2,$d2
++	shr	\$2,$d1
++	and	\$3,$h2
++	add	$d2,$d1			# =*5
++	add	$d1,$h0
++	adc	\$0,$h1
++	adc	\$0,$h2
++
++	mov	$s1,$r1
++	mov	$s1,%rax
++	shr	\$2,$s1
++	add	$r1,$s1			# s1 = r1 + (r1 >> 2)
++
++.Lbase2_26_pre_avx2:
++	add	0($inp),$h0		# accumulate input
++	adc	8($inp),$h1
++	lea	16($inp),$inp
++	adc	$padbit,$h2
++	sub	\$16,%r15
++
++	call	__poly1305_block
++	mov	$r1,%rax
++
++	test	\$63,%r15
++	jnz	.Lbase2_26_pre_avx2
++
++	test	$padbit,$padbit		# if $padbit is zero,
++	jz	.Lstore_base2_64_avx2	# store hash in base 2^64 format
++
++	################################# base 2^64 -> base 2^26
++	mov	$h0,%rax
++	mov	$h0,%rdx
++	shr	\$52,$h0
++	mov	$h1,$r0
++	mov	$h1,$r1
++	shr	\$26,%rdx
++	and	\$0x3ffffff,%rax	# h[0]
++	shl	\$12,$r0
++	and	\$0x3ffffff,%rdx	# h[1]
++	shr	\$14,$h1
++	or	$r0,$h0
++	shl	\$24,$h2
++	and	\$0x3ffffff,$h0		# h[2]
++	shr	\$40,$r1
++	and	\$0x3ffffff,$h1		# h[3]
++	or	$r1,$h2			# h[4]
++
++	test	%r15,%r15
++	jz	.Lstore_base2_26_avx2
++
++	vmovd	%rax#d,%x#$H0
++	vmovd	%rdx#d,%x#$H1
++	vmovd	$h0#d,%x#$H2
++	vmovd	$h1#d,%x#$H3
++	vmovd	$h2#d,%x#$H4
++	jmp	.Lproceed_avx2
++
++.align	32
++.Lstore_base2_64_avx2:
++	mov	$h0,0($ctx)
++	mov	$h1,8($ctx)
++	mov	$h2,16($ctx)		# note that is_base2_26 is zeroed
++	jmp	.Ldone_avx2
++
++.align	16
++.Lstore_base2_26_avx2:
++	mov	%rax#d,0($ctx)		# store hash value base 2^26
++	mov	%rdx#d,4($ctx)
++	mov	$h0#d,8($ctx)
++	mov	$h1#d,12($ctx)
++	mov	$h2#d,16($ctx)
++.align	16
++.Ldone_avx2:
++	mov	0(%rsp),%r15
++	mov	8(%rsp),%r14
++	mov	16(%rsp),%r13
++	mov	24(%rsp),%r12
++	mov	32(%rsp),%rbp
++	mov	40(%rsp),%rbx
++	lea	48(%rsp),%rsp
++.Lno_data_avx2:
++.Lblocks_avx2_epilogue:
++	ret
++
++.align	32
++.Lbase2_64_avx2:
++	push	%rbx
++	push	%rbp
++	push	%r12
++	push	%r13
++	push	%r14
++	push	%r15
++.Lbase2_64_avx2_body:
++
++	mov	$len,%r15		# reassign $len
++
++	mov	24($ctx),$r0		# load r
++	mov	32($ctx),$s1
++
++	mov	0($ctx),$h0		# load hash value
++	mov	8($ctx),$h1
++	mov	16($ctx),$h2#d
++
++	mov	$s1,$r1
++	mov	$s1,%rax
++	shr	\$2,$s1
++	add	$r1,$s1			# s1 = r1 + (r1 >> 2)
++
++	test	\$63,$len
++	jz	.Linit_avx2
++
++.Lbase2_64_pre_avx2:
++	add	0($inp),$h0		# accumulate input
++	adc	8($inp),$h1
++	lea	16($inp),$inp
++	adc	$padbit,$h2
++	sub	\$16,%r15
++
++	call	__poly1305_block
++	mov	$r1,%rax
++
++	test	\$63,%r15
++	jnz	.Lbase2_64_pre_avx2
++
++.Linit_avx2:
++	################################# base 2^64 -> base 2^26
++	mov	$h0,%rax
++	mov	$h0,%rdx
++	shr	\$52,$h0
++	mov	$h1,$d1
++	mov	$h1,$d2
++	shr	\$26,%rdx
++	and	\$0x3ffffff,%rax	# h[0]
++	shl	\$12,$d1
++	and	\$0x3ffffff,%rdx	# h[1]
++	shr	\$14,$h1
++	or	$d1,$h0
++	shl	\$24,$h2
++	and	\$0x3ffffff,$h0		# h[2]
++	shr	\$40,$d2
++	and	\$0x3ffffff,$h1		# h[3]
++	or	$d2,$h2			# h[4]
++
++	vmovd	%rax#d,%x#$H0
++	vmovd	%rdx#d,%x#$H1
++	vmovd	$h0#d,%x#$H2
++	vmovd	$h1#d,%x#$H3
++	vmovd	$h2#d,%x#$H4
++	movl	\$1,20($ctx)		# set is_base2_26
++
++	call	__poly1305_init_avx
++
++.Lproceed_avx2:
++	mov	%r15,$len
++
++	mov	0(%rsp),%r15
++	mov	8(%rsp),%r14
++	mov	16(%rsp),%r13
++	mov	24(%rsp),%r12
++	mov	32(%rsp),%rbp
++	mov	40(%rsp),%rbx
++	lea	48(%rsp),%rax
++	lea	48(%rsp),%rsp
++.Lbase2_64_avx2_epilogue:
++	jmp	.Ldo_avx2
++
++.align	32
++.Leven_avx2:
++	vmovd		4*0($ctx),%x#$H0	# load hash value base 2^26
++	vmovd		4*1($ctx),%x#$H1
++	vmovd		4*2($ctx),%x#$H2
++	vmovd		4*3($ctx),%x#$H3
++	vmovd		4*4($ctx),%x#$H4
++
++.Ldo_avx2:
++___
++$code.=<<___	if (!$win64);
++	lea		-8(%rsp),%r11
++	sub		\$0x128,%rsp
++___
++$code.=<<___	if ($win64);
++	lea		-0xf8(%rsp),%r11
++	sub		\$0x1c8,%rsp
++	vmovdqa		%xmm6,0x50(%r11)
++	vmovdqa		%xmm7,0x60(%r11)
++	vmovdqa		%xmm8,0x70(%r11)
++	vmovdqa		%xmm9,0x80(%r11)
++	vmovdqa		%xmm10,0x90(%r11)
++	vmovdqa		%xmm11,0xa0(%r11)
++	vmovdqa		%xmm12,0xb0(%r11)
++	vmovdqa		%xmm13,0xc0(%r11)
++	vmovdqa		%xmm14,0xd0(%r11)
++	vmovdqa		%xmm15,0xe0(%r11)
++.Ldo_avx2_body:
++___
++$code.=<<___;
++	lea		48+64($ctx),$ctx	# size optimization
++	lea		.Lconst(%rip),%rcx
++
++	# expand and copy pre-calculated table to stack
++	vmovdqu		`16*0-64`($ctx),%x#$T2
++	and		\$-512,%rsp
++	vmovdqu		`16*1-64`($ctx),%x#$T3
++	vmovdqu		`16*2-64`($ctx),%x#$T4
++	vmovdqu		`16*3-64`($ctx),%x#$D0
++	vmovdqu		`16*4-64`($ctx),%x#$D1
++	vmovdqu		`16*5-64`($ctx),%x#$D2
++	vmovdqu		`16*6-64`($ctx),%x#$D3
++	vpermq		\$0x15,$T2,$T2		# 00003412 -> 12343434
++	vmovdqu		`16*7-64`($ctx),%x#$D4
++	vpermq		\$0x15,$T3,$T3
++	vpshufd		\$0xc8,$T2,$T2		# 12343434 -> 14243444
++	vmovdqu		`16*8-64`($ctx),%x#$MASK
++	vpermq		\$0x15,$T4,$T4
++	vpshufd		\$0xc8,$T3,$T3
++	vmovdqa		$T2,0x00(%rsp)
++	vpermq		\$0x15,$D0,$D0
++	vpshufd		\$0xc8,$T4,$T4
++	vmovdqa		$T3,0x20(%rsp)
++	vpermq		\$0x15,$D1,$D1
++	vpshufd		\$0xc8,$D0,$D0
++	vmovdqa		$T4,0x40(%rsp)
++	vpermq		\$0x15,$D2,$D2
++	vpshufd		\$0xc8,$D1,$D1
++	vmovdqa		$D0,0x60(%rsp)
++	vpermq		\$0x15,$D3,$D3
++	vpshufd		\$0xc8,$D2,$D2
++	vmovdqa		$D1,0x80(%rsp)
++	vpermq		\$0x15,$D4,$D4
++	vpshufd		\$0xc8,$D3,$D3
++	vmovdqa		$D2,0xa0(%rsp)
++	vpermq		\$0x15,$MASK,$MASK
++	vpshufd		\$0xc8,$D4,$D4
++	vmovdqa		$D3,0xc0(%rsp)
++	vpshufd		\$0xc8,$MASK,$MASK
++	vmovdqa		$D4,0xe0(%rsp)
++	vmovdqa		$MASK,0x100(%rsp)
++	vmovdqa		64(%rcx),$MASK		# .Lmask26
++
++	################################################################
++	# load input
++	vmovdqu		16*0($inp),%x#$T0
++	vmovdqu		16*1($inp),%x#$T1
++	vinserti128	\$1,16*2($inp),$T0,$T0
++	vinserti128	\$1,16*3($inp),$T1,$T1
++	lea		16*4($inp),$inp
++
++	vpsrldq		\$6,$T0,$T2		# splat input
++	vpsrldq		\$6,$T1,$T3
++	vpunpckhqdq	$T1,$T0,$T4		# 4
++	vpunpcklqdq	$T3,$T2,$T2		# 2:3
++	vpunpcklqdq	$T1,$T0,$T0		# 0:1
++
++	vpsrlq		\$30,$T2,$T3
++	vpsrlq		\$4,$T2,$T2
++	vpsrlq		\$26,$T0,$T1
++	vpsrlq		\$40,$T4,$T4		# 4
++	vpand		$MASK,$T2,$T2		# 2
++	vpand		$MASK,$T0,$T0		# 0
++	vpand		$MASK,$T1,$T1		# 1
++	vpand		$MASK,$T3,$T3		# 3
++	vpor		32(%rcx),$T4,$T4	# padbit, yes, always
++
++	lea		0x90(%rsp),%rax		# size optimization
++	vpaddq		$H2,$T2,$H2		# accumulate input
++	sub		\$64,$len
++	jz		.Ltail_avx2
++	jmp		.Loop_avx2
++
++.align	32
++.Loop_avx2:
++	################################################################
++	# ((inp[0]*r^4+r[4])*r^4+r[8])*r^4
++	# ((inp[1]*r^4+r[5])*r^4+r[9])*r^3
++	# ((inp[2]*r^4+r[6])*r^4+r[10])*r^2
++	# ((inp[3]*r^4+r[7])*r^4+r[11])*r^1
++	#   \________/\________/
++	################################################################
++	#vpaddq		$H2,$T2,$H2		# accumulate input
++	vpaddq		$H0,$T0,$H0
++	vmovdqa		`32*0`(%rsp),$T0	# r0^4
++	vpaddq		$H1,$T1,$H1
++	vmovdqa		`32*1`(%rsp),$T1	# r1^4
++	vpaddq		$H3,$T3,$H3
++	vmovdqa		`32*3`(%rsp),$T2	# r2^4
++	vpaddq		$H4,$T4,$H4
++	vmovdqa		`32*6-0x90`(%rax),$T3	# s3^4
++	vmovdqa		`32*8-0x90`(%rax),$S4	# s4^4
++
++	# d4 = h4*r0 + h3*r1   + h2*r2   + h1*r3   + h0*r4
++	# d3 = h3*r0 + h2*r1   + h1*r2   + h0*r3   + h4*5*r4
++	# d2 = h2*r0 + h1*r1   + h0*r2   + h4*5*r3 + h3*5*r4
++	# d1 = h1*r0 + h0*r1   + h4*5*r2 + h3*5*r3 + h2*5*r4
++	# d0 = h0*r0 + h4*5*r1 + h3*5*r2 + h2*5*r3 + h1*5*r4
++	#
++	# however, as h2 is "chronologically" first one available pull
++	# corresponding operations up, so it's
++	#
++	# d4 = h2*r2   + h4*r0 + h3*r1             + h1*r3   + h0*r4
++	# d3 = h2*r1   + h3*r0           + h1*r2   + h0*r3   + h4*5*r4
++	# d2 = h2*r0           + h1*r1   + h0*r2   + h4*5*r3 + h3*5*r4
++	# d1 = h2*5*r4 + h1*r0 + h0*r1   + h4*5*r2 + h3*5*r3
++	# d0 = h2*5*r3 + h0*r0 + h4*5*r1 + h3*5*r2           + h1*5*r4
++
++	vpmuludq	$H2,$T0,$D2		# d2 = h2*r0
++	vpmuludq	$H2,$T1,$D3		# d3 = h2*r1
++	vpmuludq	$H2,$T2,$D4		# d4 = h2*r2
++	vpmuludq	$H2,$T3,$D0		# d0 = h2*s3
++	vpmuludq	$H2,$S4,$D1		# d1 = h2*s4
++
++	vpmuludq	$H0,$T1,$T4		# h0*r1
++	vpmuludq	$H1,$T1,$H2		# h1*r1, borrow $H2 as temp
++	vpaddq		$T4,$D1,$D1		# d1 += h0*r1
++	vpaddq		$H2,$D2,$D2		# d2 += h1*r1
++	vpmuludq	$H3,$T1,$T4		# h3*r1
++	vpmuludq	`32*2`(%rsp),$H4,$H2	# h4*s1
++	vpaddq		$T4,$D4,$D4		# d4 += h3*r1
++	vpaddq		$H2,$D0,$D0		# d0 += h4*s1
++	 vmovdqa	`32*4-0x90`(%rax),$T1	# s2
++
++	vpmuludq	$H0,$T0,$T4		# h0*r0
++	vpmuludq	$H1,$T0,$H2		# h1*r0
++	vpaddq		$T4,$D0,$D0		# d0 += h0*r0
++	vpaddq		$H2,$D1,$D1		# d1 += h1*r0
++	vpmuludq	$H3,$T0,$T4		# h3*r0
++	vpmuludq	$H4,$T0,$H2		# h4*r0
++	 vmovdqu	16*0($inp),%x#$T0	# load input
++	vpaddq		$T4,$D3,$D3		# d3 += h3*r0
++	vpaddq		$H2,$D4,$D4		# d4 += h4*r0
++	 vinserti128	\$1,16*2($inp),$T0,$T0
++
++	vpmuludq	$H3,$T1,$T4		# h3*s2
++	vpmuludq	$H4,$T1,$H2		# h4*s2
++	 vmovdqu	16*1($inp),%x#$T1
++	vpaddq		$T4,$D0,$D0		# d0 += h3*s2
++	vpaddq		$H2,$D1,$D1		# d1 += h4*s2
++	 vmovdqa	`32*5-0x90`(%rax),$H2	# r3
++	vpmuludq	$H1,$T2,$T4		# h1*r2
++	vpmuludq	$H0,$T2,$T2		# h0*r2
++	vpaddq		$T4,$D3,$D3		# d3 += h1*r2
++	vpaddq		$T2,$D2,$D2		# d2 += h0*r2
++	 vinserti128	\$1,16*3($inp),$T1,$T1
++	 lea		16*4($inp),$inp
++
++	vpmuludq	$H1,$H2,$T4		# h1*r3
++	vpmuludq	$H0,$H2,$H2		# h0*r3
++	 vpsrldq	\$6,$T0,$T2		# splat input
++	vpaddq		$T4,$D4,$D4		# d4 += h1*r3
++	vpaddq		$H2,$D3,$D3		# d3 += h0*r3
++	vpmuludq	$H3,$T3,$T4		# h3*s3
++	vpmuludq	$H4,$T3,$H2		# h4*s3
++	 vpsrldq	\$6,$T1,$T3
++	vpaddq		$T4,$D1,$D1		# d1 += h3*s3
++	vpaddq		$H2,$D2,$D2		# d2 += h4*s3
++	 vpunpckhqdq	$T1,$T0,$T4		# 4
++
++	vpmuludq	$H3,$S4,$H3		# h3*s4
++	vpmuludq	$H4,$S4,$H4		# h4*s4
++	 vpunpcklqdq	$T1,$T0,$T0		# 0:1
++	vpaddq		$H3,$D2,$H2		# h2 = d2 + h3*r4
++	vpaddq		$H4,$D3,$H3		# h3 = d3 + h4*r4
++	 vpunpcklqdq	$T3,$T2,$T3		# 2:3
++	vpmuludq	`32*7-0x90`(%rax),$H0,$H4	# h0*r4
++	vpmuludq	$H1,$S4,$H0		# h1*s4
++	vmovdqa		64(%rcx),$MASK		# .Lmask26
++	vpaddq		$H4,$D4,$H4		# h4 = d4 + h0*r4
++	vpaddq		$H0,$D0,$H0		# h0 = d0 + h1*s4
++
++	################################################################
++	# lazy reduction (interleaved with tail of input splat)
++
++	vpsrlq		\$26,$H3,$D3
++	vpand		$MASK,$H3,$H3
++	vpaddq		$D3,$H4,$H4		# h3 -> h4
++
++	vpsrlq		\$26,$H0,$D0
++	vpand		$MASK,$H0,$H0
++	vpaddq		$D0,$D1,$H1		# h0 -> h1
++
++	vpsrlq		\$26,$H4,$D4
++	vpand		$MASK,$H4,$H4
++
++	 vpsrlq		\$4,$T3,$T2
++
++	vpsrlq		\$26,$H1,$D1
++	vpand		$MASK,$H1,$H1
++	vpaddq		$D1,$H2,$H2		# h1 -> h2
++
++	vpaddq		$D4,$H0,$H0
++	vpsllq		\$2,$D4,$D4
++	vpaddq		$D4,$H0,$H0		# h4 -> h0
++
++	 vpand		$MASK,$T2,$T2		# 2
++	 vpsrlq		\$26,$T0,$T1
++
++	vpsrlq		\$26,$H2,$D2
++	vpand		$MASK,$H2,$H2
++	vpaddq		$D2,$H3,$H3		# h2 -> h3
++
++	 vpaddq		$T2,$H2,$H2		# modulo-scheduled
++	 vpsrlq		\$30,$T3,$T3
++
++	vpsrlq		\$26,$H0,$D0
++	vpand		$MASK,$H0,$H0
++	vpaddq		$D0,$H1,$H1		# h0 -> h1
++
++	 vpsrlq		\$40,$T4,$T4		# 4
++
++	vpsrlq		\$26,$H3,$D3
++	vpand		$MASK,$H3,$H3
++	vpaddq		$D3,$H4,$H4		# h3 -> h4
++
++	 vpand		$MASK,$T0,$T0		# 0
++	 vpand		$MASK,$T1,$T1		# 1
++	 vpand		$MASK,$T3,$T3		# 3
++	 vpor		32(%rcx),$T4,$T4	# padbit, yes, always
++
++	sub		\$64,$len
++	jnz		.Loop_avx2
++
++	.byte		0x66,0x90
++.Ltail_avx2:
++	################################################################
++	# while above multiplications were by r^4 in all lanes, in last
++	# iteration we multiply least significant lane by r^4 and most
++	# significant one by r, so copy of above except that references
++	# to the precomputed table are displaced by 4...
++
++	#vpaddq		$H2,$T2,$H2		# accumulate input
++	vpaddq		$H0,$T0,$H0
++	vmovdqu		`32*0+4`(%rsp),$T0	# r0^4
++	vpaddq		$H1,$T1,$H1
++	vmovdqu		`32*1+4`(%rsp),$T1	# r1^4
++	vpaddq		$H3,$T3,$H3
++	vmovdqu		`32*3+4`(%rsp),$T2	# r2^4
++	vpaddq		$H4,$T4,$H4
++	vmovdqu		`32*6+4-0x90`(%rax),$T3	# s3^4
++	vmovdqu		`32*8+4-0x90`(%rax),$S4	# s4^4
++
++	vpmuludq	$H2,$T0,$D2		# d2 = h2*r0
++	vpmuludq	$H2,$T1,$D3		# d3 = h2*r1
++	vpmuludq	$H2,$T2,$D4		# d4 = h2*r2
++	vpmuludq	$H2,$T3,$D0		# d0 = h2*s3
++	vpmuludq	$H2,$S4,$D1		# d1 = h2*s4
++
++	vpmuludq	$H0,$T1,$T4		# h0*r1
++	vpmuludq	$H1,$T1,$H2		# h1*r1
++	vpaddq		$T4,$D1,$D1		# d1 += h0*r1
++	vpaddq		$H2,$D2,$D2		# d2 += h1*r1
++	vpmuludq	$H3,$T1,$T4		# h3*r1
++	vpmuludq	`32*2+4`(%rsp),$H4,$H2	# h4*s1
++	vpaddq		$T4,$D4,$D4		# d4 += h3*r1
++	vpaddq		$H2,$D0,$D0		# d0 += h4*s1
++
++	vpmuludq	$H0,$T0,$T4		# h0*r0
++	vpmuludq	$H1,$T0,$H2		# h1*r0
++	vpaddq		$T4,$D0,$D0		# d0 += h0*r0
++	 vmovdqu	`32*4+4-0x90`(%rax),$T1	# s2
++	vpaddq		$H2,$D1,$D1		# d1 += h1*r0
++	vpmuludq	$H3,$T0,$T4		# h3*r0
++	vpmuludq	$H4,$T0,$H2		# h4*r0
++	vpaddq		$T4,$D3,$D3		# d3 += h3*r0
++	vpaddq		$H2,$D4,$D4		# d4 += h4*r0
++
++	vpmuludq	$H3,$T1,$T4		# h3*s2
++	vpmuludq	$H4,$T1,$H2		# h4*s2
++	vpaddq		$T4,$D0,$D0		# d0 += h3*s2
++	vpaddq		$H2,$D1,$D1		# d1 += h4*s2
++	 vmovdqu	`32*5+4-0x90`(%rax),$H2	# r3
++	vpmuludq	$H1,$T2,$T4		# h1*r2
++	vpmuludq	$H0,$T2,$T2		# h0*r2
++	vpaddq		$T4,$D3,$D3		# d3 += h1*r2
++	vpaddq		$T2,$D2,$D2		# d2 += h0*r2
++
++	vpmuludq	$H1,$H2,$T4		# h1*r3
++	vpmuludq	$H0,$H2,$H2		# h0*r3
++	vpaddq		$T4,$D4,$D4		# d4 += h1*r3
++	vpaddq		$H2,$D3,$D3		# d3 += h0*r3
++	vpmuludq	$H3,$T3,$T4		# h3*s3
++	vpmuludq	$H4,$T3,$H2		# h4*s3
++	vpaddq		$T4,$D1,$D1		# d1 += h3*s3
++	vpaddq		$H2,$D2,$D2		# d2 += h4*s3
++
++	vpmuludq	$H3,$S4,$H3		# h3*s4
++	vpmuludq	$H4,$S4,$H4		# h4*s4
++	vpaddq		$H3,$D2,$H2		# h2 = d2 + h3*r4
++	vpaddq		$H4,$D3,$H3		# h3 = d3 + h4*r4
++	vpmuludq	`32*7+4-0x90`(%rax),$H0,$H4		# h0*r4
++	vpmuludq	$H1,$S4,$H0		# h1*s4
++	vmovdqa		64(%rcx),$MASK		# .Lmask26
++	vpaddq		$H4,$D4,$H4		# h4 = d4 + h0*r4
++	vpaddq		$H0,$D0,$H0		# h0 = d0 + h1*s4
++
++	################################################################
++	# horizontal addition
++
++	vpsrldq		\$8,$D1,$T1
++	vpsrldq		\$8,$H2,$T2
++	vpsrldq		\$8,$H3,$T3
++	vpsrldq		\$8,$H4,$T4
++	vpsrldq		\$8,$H0,$T0
++	vpaddq		$T1,$D1,$D1
++	vpaddq		$T2,$H2,$H2
++	vpaddq		$T3,$H3,$H3
++	vpaddq		$T4,$H4,$H4
++	vpaddq		$T0,$H0,$H0
++
++	vpermq		\$0x2,$H3,$T3
++	vpermq		\$0x2,$H4,$T4
++	vpermq		\$0x2,$H0,$T0
++	vpermq		\$0x2,$D1,$T1
++	vpermq		\$0x2,$H2,$T2
++	vpaddq		$T3,$H3,$H3
++	vpaddq		$T4,$H4,$H4
++	vpaddq		$T0,$H0,$H0
++	vpaddq		$T1,$D1,$D1
++	vpaddq		$T2,$H2,$H2
++
++	################################################################
++	# lazy reduction
++
++	vpsrlq		\$26,$H3,$D3
++	vpand		$MASK,$H3,$H3
++	vpaddq		$D3,$H4,$H4		# h3 -> h4
++
++	vpsrlq		\$26,$H0,$D0
++	vpand		$MASK,$H0,$H0
++	vpaddq		$D0,$D1,$H1		# h0 -> h1
++
++	vpsrlq		\$26,$H4,$D4
++	vpand		$MASK,$H4,$H4
++
++	vpsrlq		\$26,$H1,$D1
++	vpand		$MASK,$H1,$H1
++	vpaddq		$D1,$H2,$H2		# h1 -> h2
++
++	vpaddq		$D4,$H0,$H0
++	vpsllq		\$2,$D4,$D4
++	vpaddq		$D4,$H0,$H0		# h4 -> h0
++
++	vpsrlq		\$26,$H2,$D2
++	vpand		$MASK,$H2,$H2
++	vpaddq		$D2,$H3,$H3		# h2 -> h3
++
++	vpsrlq		\$26,$H0,$D0
++	vpand		$MASK,$H0,$H0
++	vpaddq		$D0,$H1,$H1		# h0 -> h1
++
++	vpsrlq		\$26,$H3,$D3
++	vpand		$MASK,$H3,$H3
++	vpaddq		$D3,$H4,$H4		# h3 -> h4
++
++	vmovd		%x#$H0,`4*0-48-64`($ctx)# save partially reduced
++	vmovd		%x#$H1,`4*1-48-64`($ctx)
++	vmovd		%x#$H2,`4*2-48-64`($ctx)
++	vmovd		%x#$H3,`4*3-48-64`($ctx)
++	vmovd		%x#$H4,`4*4-48-64`($ctx)
++___
++$code.=<<___	if ($win64);
++	vmovdqa		0x50(%r11),%xmm6
++	vmovdqa		0x60(%r11),%xmm7
++	vmovdqa		0x70(%r11),%xmm8
++	vmovdqa		0x80(%r11),%xmm9
++	vmovdqa		0x90(%r11),%xmm10
++	vmovdqa		0xa0(%r11),%xmm11
++	vmovdqa		0xb0(%r11),%xmm12
++	vmovdqa		0xc0(%r11),%xmm13
++	vmovdqa		0xd0(%r11),%xmm14
++	vmovdqa		0xe0(%r11),%xmm15
++	lea		0xf8(%r11),%rsp
++.Ldo_avx2_epilogue:
++___
++$code.=<<___	if (!$win64);
++	lea		8(%r11),%rsp
++___
++$code.=<<___;
++	vzeroupper
++	ret
++.size	poly1305_blocks_avx2,.-poly1305_blocks_avx2
++___
++}
++$code.=<<___;
++.align	64
++.Lconst:
++.Lmask24:
++.long	0x0ffffff,0,0x0ffffff,0,0x0ffffff,0,0x0ffffff,0
++.L129:
++.long	`1<<24`,0,`1<<24`,0,`1<<24`,0,`1<<24`,0
++.Lmask26:
++.long	0x3ffffff,0,0x3ffffff,0,0x3ffffff,0,0x3ffffff,0
++.Lfive:
++.long	5,0,5,0,5,0,5,0
++___
++}
++
++$code.=<<___;
++.asciz	"Poly1305 for x86_64, CRYPTOGAMS by "
++.align	16
++___
++
++# EXCEPTION_DISPOSITION handler (EXCEPTION_RECORD *rec,ULONG64 frame,
++#		CONTEXT *context,DISPATCHER_CONTEXT *disp)
++if ($win64) {
++$rec="%rcx";
++$frame="%rdx";
++$context="%r8";
++$disp="%r9";
++
++$code.=<<___;
++.extern	__imp_RtlVirtualUnwind
++.type	se_handler,\@abi-omnipotent
++.align	16
++se_handler:
++	push	%rsi
++	push	%rdi
++	push	%rbx
++	push	%rbp
++	push	%r12
++	push	%r13
++	push	%r14
++	push	%r15
++	pushfq
++	sub	\$64,%rsp
++
++	mov	120($context),%rax	# pull context->Rax
++	mov	248($context),%rbx	# pull context->Rip
++
++	mov	8($disp),%rsi		# disp->ImageBase
++	mov	56($disp),%r11		# disp->HandlerData
++
++	mov	0(%r11),%r10d		# HandlerData[0]
++	lea	(%rsi,%r10),%r10	# prologue label
++	cmp	%r10,%rbx		# context->Rip<.Lprologue
++	jb	.Lcommon_seh_tail
++
++	mov	152($context),%rax	# pull context->Rsp
++
++	mov	4(%r11),%r10d		# HandlerData[1]
++	lea	(%rsi,%r10),%r10	# epilogue label
++	cmp	%r10,%rbx		# context->Rip>=.Lepilogue
++	jae	.Lcommon_seh_tail
++
++	lea	48(%rax),%rax
++
++	mov	-8(%rax),%rbx
++	mov	-16(%rax),%rbp
++	mov	-24(%rax),%r12
++	mov	-32(%rax),%r13
++	mov	-40(%rax),%r14
++	mov	-48(%rax),%r15
++	mov	%rbx,144($context)	# restore context->Rbx
++	mov	%rbp,160($context)	# restore context->Rbp
++	mov	%r12,216($context)	# restore context->R12
++	mov	%r13,224($context)	# restore context->R13
++	mov	%r14,232($context)	# restore context->R14
++	mov	%r15,240($context)	# restore context->R14
++
++	jmp	.Lcommon_seh_tail
++.size	se_handler,.-se_handler
++
++.type	avx_handler,\@abi-omnipotent
++.align	16
++avx_handler:
++	push	%rsi
++	push	%rdi
++	push	%rbx
++	push	%rbp
++	push	%r12
++	push	%r13
++	push	%r14
++	push	%r15
++	pushfq
++	sub	\$64,%rsp
++
++	mov	120($context),%rax	# pull context->Rax
++	mov	248($context),%rbx	# pull context->Rip
++
++	mov	8($disp),%rsi		# disp->ImageBase
++	mov	56($disp),%r11		# disp->HandlerData
++
++	mov	0(%r11),%r10d		# HandlerData[0]
++	lea	(%rsi,%r10),%r10	# prologue label
++	cmp	%r10,%rbx		# context->RipRsp
++
++	mov	4(%r11),%r10d		# HandlerData[1]
++	lea	(%rsi,%r10),%r10	# epilogue label
++	cmp	%r10,%rbx		# context->Rip>=epilogue label
++	jae	.Lcommon_seh_tail
++
++	mov	208($context),%rax	# pull context->R11
++
++	lea	0x50(%rax),%rsi
++	lea	0xf8(%rax),%rax
++	lea	512($context),%rdi	# &context.Xmm6
++	mov	\$20,%ecx
++	.long	0xa548f3fc		# cld; rep movsq
++
++.Lcommon_seh_tail:
++	mov	8(%rax),%rdi
++	mov	16(%rax),%rsi
++	mov	%rax,152($context)	# restore context->Rsp
++	mov	%rsi,168($context)	# restore context->Rsi
++	mov	%rdi,176($context)	# restore context->Rdi
++
++	mov	40($disp),%rdi		# disp->ContextRecord
++	mov	$context,%rsi		# context
++	mov	\$154,%ecx		# sizeof(CONTEXT)
++	.long	0xa548f3fc		# cld; rep movsq
++
++	mov	$disp,%rsi
++	xor	%rcx,%rcx		# arg1, UNW_FLAG_NHANDLER
++	mov	8(%rsi),%rdx		# arg2, disp->ImageBase
++	mov	0(%rsi),%r8		# arg3, disp->ControlPc
++	mov	16(%rsi),%r9		# arg4, disp->FunctionEntry
++	mov	40(%rsi),%r10		# disp->ContextRecord
++	lea	56(%rsi),%r11		# &disp->HandlerData
++	lea	24(%rsi),%r12		# &disp->EstablisherFrame
++	mov	%r10,32(%rsp)		# arg5
++	mov	%r11,40(%rsp)		# arg6
++	mov	%r12,48(%rsp)		# arg7
++	mov	%rcx,56(%rsp)		# arg8, (NULL)
++	call	*__imp_RtlVirtualUnwind(%rip)
++
++	mov	\$1,%eax		# ExceptionContinueSearch
++	add	\$64,%rsp
++	popfq
++	pop	%r15
++	pop	%r14
++	pop	%r13
++	pop	%r12
++	pop	%rbp
++	pop	%rbx
++	pop	%rdi
++	pop	%rsi
++	ret
++.size	avx_handler,.-avx_handler
++
++.section	.pdata
++.align	4
++	.rva	.LSEH_begin_poly1305_init
++	.rva	.LSEH_end_poly1305_init
++	.rva	.LSEH_info_poly1305_init
++
++	.rva	.LSEH_begin_poly1305_blocks
++	.rva	.LSEH_end_poly1305_blocks
++	.rva	.LSEH_info_poly1305_blocks
++
++	.rva	.LSEH_begin_poly1305_emit
++	.rva	.LSEH_end_poly1305_emit
++	.rva	.LSEH_info_poly1305_emit
++___
++$code.=<<___ if ($avx);
++	.rva	.LSEH_begin_poly1305_blocks_avx
++	.rva	.Lbase2_64_avx
++	.rva	.LSEH_info_poly1305_blocks_avx_1
++
++	.rva	.Lbase2_64_avx
++	.rva	.Leven_avx
++	.rva	.LSEH_info_poly1305_blocks_avx_2
++
++	.rva	.Leven_avx
++	.rva	.LSEH_end_poly1305_blocks_avx
++	.rva	.LSEH_info_poly1305_blocks_avx_3
++
++	.rva	.LSEH_begin_poly1305_emit_avx
++	.rva	.LSEH_end_poly1305_emit_avx
++	.rva	.LSEH_info_poly1305_emit_avx
++___
++$code.=<<___ if ($avx>1);
++	.rva	.LSEH_begin_poly1305_blocks_avx2
++	.rva	.Lbase2_64_avx2
++	.rva	.LSEH_info_poly1305_blocks_avx2_1
++
++	.rva	.Lbase2_64_avx2
++	.rva	.Leven_avx2
++	.rva	.LSEH_info_poly1305_blocks_avx2_2
++
++	.rva	.Leven_avx2
++	.rva	.LSEH_end_poly1305_blocks_avx2
++	.rva	.LSEH_info_poly1305_blocks_avx2_3
++___
++$code.=<<___;
++.section	.xdata
++.align	8
++.LSEH_info_poly1305_init:
++	.byte	9,0,0,0
++	.rva	se_handler
++	.rva	.LSEH_begin_poly1305_init,.LSEH_begin_poly1305_init
++
++.LSEH_info_poly1305_blocks:
++	.byte	9,0,0,0
++	.rva	se_handler
++	.rva	.Lblocks_body,.Lblocks_epilogue
++
++.LSEH_info_poly1305_emit:
++	.byte	9,0,0,0
++	.rva	se_handler
++	.rva	.LSEH_begin_poly1305_emit,.LSEH_begin_poly1305_emit
++___
++$code.=<<___ if ($avx);
++.LSEH_info_poly1305_blocks_avx_1:
++	.byte	9,0,0,0
++	.rva	se_handler
++	.rva	.Lblocks_avx_body,.Lblocks_avx_epilogue		# HandlerData[]
++
++.LSEH_info_poly1305_blocks_avx_2:
++	.byte	9,0,0,0
++	.rva	se_handler
++	.rva	.Lbase2_64_avx_body,.Lbase2_64_avx_epilogue	# HandlerData[]
++
++.LSEH_info_poly1305_blocks_avx_3:
++	.byte	9,0,0,0
++	.rva	avx_handler
++	.rva	.Ldo_avx_body,.Ldo_avx_epilogue			# HandlerData[]
++
++.LSEH_info_poly1305_emit_avx:
++	.byte	9,0,0,0
++	.rva	se_handler
++	.rva	.LSEH_begin_poly1305_emit_avx,.LSEH_begin_poly1305_emit_avx
++___
++$code.=<<___ if ($avx>1);
++.LSEH_info_poly1305_blocks_avx2_1:
++	.byte	9,0,0,0
++	.rva	se_handler
++	.rva	.Lblocks_avx2_body,.Lblocks_avx2_epilogue	# HandlerData[]
++
++.LSEH_info_poly1305_blocks_avx2_2:
++	.byte	9,0,0,0
++	.rva	se_handler
++	.rva	.Lbase2_64_avx2_body,.Lbase2_64_avx2_epilogue	# HandlerData[]
++
++.LSEH_info_poly1305_blocks_avx2_3:
++	.byte	9,0,0,0
++	.rva	avx_handler
++	.rva	.Ldo_avx2_body,.Ldo_avx2_epilogue		# HandlerData[]
++___
++}
++
++foreach (split('\n',$code)) {
++	s/\`([^\`]*)\`/eval($1)/ge;
++	s/%r([a-z]+)#d/%e$1/g;
++	s/%r([0-9]+)#d/%r$1d/g;
++	s/%x#%y/%x/g;
++
++	print $_,"\n";
++}
++close STDOUT;
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/poly1305/build.info b/CryptoPkg/Library/OpensslLib/openssl/crypto/poly1305/build.info
+new file mode 100644
+index 0000000..d575f5a
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/poly1305/build.info
+@@ -0,0 +1,20 @@
++LIBS=../../libcrypto
++SOURCE[../../libcrypto]=\
++        poly1305.c {- $target{poly1305_asm_src} -}
++
++GENERATE[poly1305-sparcv9.S]=asm/poly1305-sparcv9.pl $(PERLASM_SCHEME)
++INCLUDE[poly1305-sparcv9.o]=..
++GENERATE[poly1305-x86.s]=asm/poly1305-x86.pl $(PERLASM_SCHEME) $(CFLAGS) $(LIB_CFLAGS) $(PROCESSOR)
++GENERATE[poly1305-x86_64.s]=asm/poly1305-x86_64.pl $(PERLASM_SCHEME)
++GENERATE[poly1305-ppc.s]=asm/poly1305-ppc.pl $(PERLASM_SCHEME)
++GENERATE[poly1305-ppcfp.s]=asm/poly1305-ppcfp.pl $(PERLASM_SCHEME)
++GENERATE[poly1305-armv4.S]=asm/poly1305-armv4.pl $(PERLASM_SCHEME)
++INCLUDE[poly1305-armv4.o]=..
++GENERATE[poly1305-armv8.S]=asm/poly1305-armv8.pl $(PERLASM_SCHEME)
++INCLUDE[poly1305-armv8.o]=..
++GENERATE[poly1305-mips.S]=asm/poly1305-mips.pl $(PERLASM_SCHEME)
++
++BEGINRAW[Makefile(unix)]
++{- $builddir -}/poly1305-%.S:	{- $sourcedir -}/asm/poly1305-%.pl
++	CC="$(CC)" $(PERL) $< $(PERLASM_SCHEME) $@
++ENDRAW[Makefile(unix)]
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/poly1305/poly1305.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/poly1305/poly1305.c
+new file mode 100644
+index 0000000..eec4d67
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/poly1305/poly1305.c
+@@ -0,0 +1,1037 @@
++/*
++ * Copyright 2015-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include 
++#include 
++
++#include "internal/poly1305.h"
++
++typedef void (*poly1305_blocks_f) (void *ctx, const unsigned char *inp,
++                                   size_t len, unsigned int padbit);
++typedef void (*poly1305_emit_f) (void *ctx, unsigned char mac[16],
++                                 const unsigned int nonce[4]);
++
++struct poly1305_context {
++    double opaque[24];  /* large enough to hold internal state, declared
++                         * 'double' to ensure at least 64-bit invariant
++                         * alignment across all platforms and
++                         * configurations */
++    unsigned int nonce[4];
++    unsigned char data[POLY1305_BLOCK_SIZE];
++    size_t num;
++    struct {
++        poly1305_blocks_f blocks;
++        poly1305_emit_f emit;
++    } func;
++};
++
++size_t Poly1305_ctx_size ()
++{
++    return sizeof(struct poly1305_context);
++}
++
++/* pick 32-bit unsigned integer in little endian order */
++static unsigned int U8TOU32(const unsigned char *p)
++{
++    return (((unsigned int)(p[0] & 0xff)) |
++            ((unsigned int)(p[1] & 0xff) << 8) |
++            ((unsigned int)(p[2] & 0xff) << 16) |
++            ((unsigned int)(p[3] & 0xff) << 24));
++}
++
++/*
++ * Implementations can be classified by amount of significant bits in
++ * words making up the multi-precision value, or in other words radix
++ * or base of numerical representation, e.g. base 2^64, base 2^32,
++ * base 2^26. Complementary characteristic is how wide is the result of
++ * multiplication of pair of digits, e.g. it would take 128 bits to
++ * accommodate multiplication result in base 2^64 case. These are used
++ * interchangeably. To describe implementation that is. But interface
++ * is designed to isolate this so that low-level primitives implemented
++ * in assembly can be self-contained/self-coherent.
++ */
++#ifndef POLY1305_ASM
++/*
++ * Even though there is __int128 reference implementation targeting
++ * 64-bit platforms provided below, it's not obvious that it's optimal
++ * choice for every one of them. Depending on instruction set overall
++ * amount of instructions can be comparable to one in __int64
++ * implementation. Amount of multiplication instructions would be lower,
++ * but not necessarily overall. And in out-of-order execution context,
++ * it is the latter that can be crucial...
++ *
++ * On related note. Poly1305 author, D. J. Bernstein, discusses and
++ * provides floating-point implementations of the algorithm in question.
++ * It made a lot of sense by the time of introduction, because most
++ * then-modern processors didn't have pipelined integer multiplier.
++ * [Not to mention that some had non-constant timing for integer
++ * multiplications.] Floating-point instructions on the other hand could
++ * be issued every cycle, which allowed to achieve better performance.
++ * Nowadays, with SIMD and/or out-or-order execution, shared or
++ * even emulated FPU, it's more complicated, and floating-point
++ * implementation is not necessarily optimal choice in every situation,
++ * rather contrary...
++ *
++ *                                              
++ */
++
++typedef unsigned int u32;
++
++/*
++ * poly1305_blocks processes a multiple of POLY1305_BLOCK_SIZE blocks
++ * of |inp| no longer than |len|. Behaviour for |len| not divisible by
++ * block size is unspecified in general case, even though in reference
++ * implementation the trailing chunk is simply ignored. Per algorithm
++ * specification, every input block, complete or last partial, is to be
++ * padded with a bit past most significant byte. The latter kind is then
++ * padded with zeros till block size. This last partial block padding
++ * is caller(*)'s responsibility, and because of this the last partial
++ * block is always processed with separate call with |len| set to
++ * POLY1305_BLOCK_SIZE and |padbit| to 0. In all other cases |padbit|
++ * should be set to 1 to perform implicit padding with 128th bit.
++ * poly1305_blocks does not actually check for this constraint though,
++ * it's caller(*)'s responsibility to comply.
++ *
++ * (*)  In the context "caller" is not application code, but higher
++ *      level Poly1305_* from this very module, so that quirks are
++ *      handled locally.
++ */
++static void
++poly1305_blocks(void *ctx, const unsigned char *inp, size_t len, u32 padbit);
++
++/*
++ * Type-agnostic "rip-off" from constant_time_locl.h
++ */
++# define CONSTANT_TIME_CARRY(a,b) ( \
++         (a ^ ((a ^ b) | ((a - b) ^ b))) >> (sizeof(a) * 8 - 1) \
++         )
++
++# if !defined(PEDANTIC) && \
++     (defined(__SIZEOF_INT128__) && __SIZEOF_INT128__==16) && \
++     (defined(__SIZEOF_LONG__) && __SIZEOF_LONG__==8)
++
++typedef unsigned long u64;
++typedef unsigned __int128 u128;
++
++typedef struct {
++    u64 h[3];
++    u64 r[2];
++} poly1305_internal;
++
++/* pick 32-bit unsigned integer in little endian order */
++static u64 U8TOU64(const unsigned char *p)
++{
++    return (((u64)(p[0] & 0xff)) |
++            ((u64)(p[1] & 0xff) << 8) |
++            ((u64)(p[2] & 0xff) << 16) |
++            ((u64)(p[3] & 0xff) << 24) |
++            ((u64)(p[4] & 0xff) << 32) |
++            ((u64)(p[5] & 0xff) << 40) |
++            ((u64)(p[6] & 0xff) << 48) |
++            ((u64)(p[7] & 0xff) << 56));
++}
++
++/* store a 32-bit unsigned integer in little endian */
++static void U64TO8(unsigned char *p, u64 v)
++{
++    p[0] = (unsigned char)((v) & 0xff);
++    p[1] = (unsigned char)((v >> 8) & 0xff);
++    p[2] = (unsigned char)((v >> 16) & 0xff);
++    p[3] = (unsigned char)((v >> 24) & 0xff);
++    p[4] = (unsigned char)((v >> 32) & 0xff);
++    p[5] = (unsigned char)((v >> 40) & 0xff);
++    p[6] = (unsigned char)((v >> 48) & 0xff);
++    p[7] = (unsigned char)((v >> 56) & 0xff);
++}
++
++static void poly1305_init(void *ctx, const unsigned char key[16])
++{
++    poly1305_internal *st = (poly1305_internal *) ctx;
++
++    /* h = 0 */
++    st->h[0] = 0;
++    st->h[1] = 0;
++    st->h[2] = 0;
++
++    /* r &= 0xffffffc0ffffffc0ffffffc0fffffff */
++    st->r[0] = U8TOU64(&key[0]) & 0x0ffffffc0fffffff;
++    st->r[1] = U8TOU64(&key[8]) & 0x0ffffffc0ffffffc;
++}
++
++static void
++poly1305_blocks(void *ctx, const unsigned char *inp, size_t len, u32 padbit)
++{
++    poly1305_internal *st = (poly1305_internal *)ctx;
++    u64 r0, r1;
++    u64 s1;
++    u64 h0, h1, h2, c;
++    u128 d0, d1;
++
++    r0 = st->r[0];
++    r1 = st->r[1];
++
++    s1 = r1 + (r1 >> 2);
++
++    h0 = st->h[0];
++    h1 = st->h[1];
++    h2 = st->h[2];
++
++    while (len >= POLY1305_BLOCK_SIZE) {
++        /* h += m[i] */
++        h0 = (u64)(d0 = (u128)h0 + U8TOU64(inp + 0));
++        h1 = (u64)(d1 = (u128)h1 + (d0 >> 64) + U8TOU64(inp + 8));
++        /*
++         * padbit can be zero only when original len was
++         * POLY1306_BLOCK_SIZE, but we don't check
++         */
++        h2 += (u64)(d1 >> 64) + padbit;
++
++        /* h *= r "%" p, where "%" stands for "partial remainder" */
++        d0 = ((u128)h0 * r0) +
++             ((u128)h1 * s1);
++        d1 = ((u128)h0 * r1) +
++             ((u128)h1 * r0) +
++             (h2 * s1);
++        h2 = (h2 * r0);
++
++        /* last reduction step: */
++        /* a) h2:h0 = h2<<128 + d1<<64 + d0 */
++        h0 = (u64)d0;
++        h1 = (u64)(d1 += d0 >> 64);
++        h2 += (u64)(d1 >> 64);
++        /* b) (h2:h0 += (h2:h0>>130) * 5) %= 2^130 */
++        c = (h2 >> 2) + (h2 & ~3UL);
++        h2 &= 3;
++        h0 += c;
++        h1 += (c = CONSTANT_TIME_CARRY(h0,c));
++        h2 += CONSTANT_TIME_CARRY(h1,c);
++        /*
++         * Occasional overflows to 3rd bit of h2 are taken care of
++         * "naturally". If after this point we end up at the top of
++         * this loop, then the overflow bit will be accounted for
++         * in next iteration. If we end up in poly1305_emit, then
++         * comparison to modulus below will still count as "carry
++         * into 131st bit", so that properly reduced value will be
++         * picked in conditional move.
++         */
++
++        inp += POLY1305_BLOCK_SIZE;
++        len -= POLY1305_BLOCK_SIZE;
++    }
++
++    st->h[0] = h0;
++    st->h[1] = h1;
++    st->h[2] = h2;
++}
++
++static void poly1305_emit(void *ctx, unsigned char mac[16],
++                          const u32 nonce[4])
++{
++    poly1305_internal *st = (poly1305_internal *) ctx;
++    u64 h0, h1, h2;
++    u64 g0, g1, g2;
++    u128 t;
++    u64 mask;
++
++    h0 = st->h[0];
++    h1 = st->h[1];
++    h2 = st->h[2];
++
++    /* compare to modulus by computing h + -p */
++    g0 = (u64)(t = (u128)h0 + 5);
++    g1 = (u64)(t = (u128)h1 + (t >> 64));
++    g2 = h2 + (u64)(t >> 64);
++
++    /* if there was carry into 131st bit, h1:h0 = g1:g0 */
++    mask = 0 - (g2 >> 2);
++    g0 &= mask;
++    g1 &= mask;
++    mask = ~mask;
++    h0 = (h0 & mask) | g0;
++    h1 = (h1 & mask) | g1;
++
++    /* mac = (h + nonce) % (2^128) */
++    h0 = (u64)(t = (u128)h0 + nonce[0] + ((u64)nonce[1]<<32));
++    h1 = (u64)(t = (u128)h1 + nonce[2] + ((u64)nonce[3]<<32) + (t >> 64));
++
++    U64TO8(mac + 0, h0);
++    U64TO8(mac + 8, h1);
++}
++
++# else
++
++#  if defined(_WIN32) && !defined(__MINGW32__)
++typedef unsigned __int64 u64;
++#  elif defined(__arch64__)
++typedef unsigned long u64;
++#  else
++typedef unsigned long long u64;
++#  endif
++
++typedef struct {
++    u32 h[5];
++    u32 r[4];
++} poly1305_internal;
++
++/* store a 32-bit unsigned integer in little endian */
++static void U32TO8(unsigned char *p, unsigned int v)
++{
++    p[0] = (unsigned char)((v) & 0xff);
++    p[1] = (unsigned char)((v >> 8) & 0xff);
++    p[2] = (unsigned char)((v >> 16) & 0xff);
++    p[3] = (unsigned char)((v >> 24) & 0xff);
++}
++
++static void poly1305_init(void *ctx, const unsigned char key[16])
++{
++    poly1305_internal *st = (poly1305_internal *) ctx;
++
++    /* h = 0 */
++    st->h[0] = 0;
++    st->h[1] = 0;
++    st->h[2] = 0;
++    st->h[3] = 0;
++    st->h[4] = 0;
++
++    /* r &= 0xffffffc0ffffffc0ffffffc0fffffff */
++    st->r[0] = U8TOU32(&key[0]) & 0x0fffffff;
++    st->r[1] = U8TOU32(&key[4]) & 0x0ffffffc;
++    st->r[2] = U8TOU32(&key[8]) & 0x0ffffffc;
++    st->r[3] = U8TOU32(&key[12]) & 0x0ffffffc;
++}
++
++static void
++poly1305_blocks(void *ctx, const unsigned char *inp, size_t len, u32 padbit)
++{
++    poly1305_internal *st = (poly1305_internal *)ctx;
++    u32 r0, r1, r2, r3;
++    u32 s1, s2, s3;
++    u32 h0, h1, h2, h3, h4, c;
++    u64 d0, d1, d2, d3;
++
++    r0 = st->r[0];
++    r1 = st->r[1];
++    r2 = st->r[2];
++    r3 = st->r[3];
++
++    s1 = r1 + (r1 >> 2);
++    s2 = r2 + (r2 >> 2);
++    s3 = r3 + (r3 >> 2);
++
++    h0 = st->h[0];
++    h1 = st->h[1];
++    h2 = st->h[2];
++    h3 = st->h[3];
++    h4 = st->h[4];
++
++    while (len >= POLY1305_BLOCK_SIZE) {
++        /* h += m[i] */
++        h0 = (u32)(d0 = (u64)h0 + U8TOU32(inp + 0));
++        h1 = (u32)(d1 = (u64)h1 + (d0 >> 32) + U8TOU32(inp + 4));
++        h2 = (u32)(d2 = (u64)h2 + (d1 >> 32) + U8TOU32(inp + 8));
++        h3 = (u32)(d3 = (u64)h3 + (d2 >> 32) + U8TOU32(inp + 12));
++        h4 += (u32)(d3 >> 32) + padbit;
++
++        /* h *= r "%" p, where "%" stands for "partial remainder" */
++        d0 = ((u64)h0 * r0) +
++             ((u64)h1 * s3) +
++             ((u64)h2 * s2) +
++             ((u64)h3 * s1);
++        d1 = ((u64)h0 * r1) +
++             ((u64)h1 * r0) +
++             ((u64)h2 * s3) +
++             ((u64)h3 * s2) +
++             (h4 * s1);
++        d2 = ((u64)h0 * r2) +
++             ((u64)h1 * r1) +
++             ((u64)h2 * r0) +
++             ((u64)h3 * s3) +
++             (h4 * s2);
++        d3 = ((u64)h0 * r3) +
++             ((u64)h1 * r2) +
++             ((u64)h2 * r1) +
++             ((u64)h3 * r0) +
++             (h4 * s3);
++        h4 = (h4 * r0);
++
++        /* last reduction step: */
++        /* a) h4:h0 = h4<<128 + d3<<96 + d2<<64 + d1<<32 + d0 */
++        h0 = (u32)d0;
++        h1 = (u32)(d1 += d0 >> 32);
++        h2 = (u32)(d2 += d1 >> 32);
++        h3 = (u32)(d3 += d2 >> 32);
++        h4 += (u32)(d3 >> 32);
++        /* b) (h4:h0 += (h4:h0>>130) * 5) %= 2^130 */
++        c = (h4 >> 2) + (h4 & ~3U);
++        h4 &= 3;
++        h0 += c;
++        h1 += (c = CONSTANT_TIME_CARRY(h0,c));
++        h2 += (c = CONSTANT_TIME_CARRY(h1,c));
++        h3 += (c = CONSTANT_TIME_CARRY(h2,c));
++        h4 += CONSTANT_TIME_CARRY(h3,c);
++        /*
++         * Occasional overflows to 3rd bit of h4 are taken care of
++         * "naturally". If after this point we end up at the top of
++         * this loop, then the overflow bit will be accounted for
++         * in next iteration. If we end up in poly1305_emit, then
++         * comparison to modulus below will still count as "carry
++         * into 131st bit", so that properly reduced value will be
++         * picked in conditional move.
++         */
++
++        inp += POLY1305_BLOCK_SIZE;
++        len -= POLY1305_BLOCK_SIZE;
++    }
++
++    st->h[0] = h0;
++    st->h[1] = h1;
++    st->h[2] = h2;
++    st->h[3] = h3;
++    st->h[4] = h4;
++}
++
++static void poly1305_emit(void *ctx, unsigned char mac[16],
++                          const u32 nonce[4])
++{
++    poly1305_internal *st = (poly1305_internal *) ctx;
++    u32 h0, h1, h2, h3, h4;
++    u32 g0, g1, g2, g3, g4;
++    u64 t;
++    u32 mask;
++
++    h0 = st->h[0];
++    h1 = st->h[1];
++    h2 = st->h[2];
++    h3 = st->h[3];
++    h4 = st->h[4];
++
++    /* compare to modulus by computing h + -p */
++    g0 = (u32)(t = (u64)h0 + 5);
++    g1 = (u32)(t = (u64)h1 + (t >> 32));
++    g2 = (u32)(t = (u64)h2 + (t >> 32));
++    g3 = (u32)(t = (u64)h3 + (t >> 32));
++    g4 = h4 + (u32)(t >> 32);
++
++    /* if there was carry into 131st bit, h3:h0 = g3:g0 */
++    mask = 0 - (g4 >> 2);
++    g0 &= mask;
++    g1 &= mask;
++    g2 &= mask;
++    g3 &= mask;
++    mask = ~mask;
++    h0 = (h0 & mask) | g0;
++    h1 = (h1 & mask) | g1;
++    h2 = (h2 & mask) | g2;
++    h3 = (h3 & mask) | g3;
++
++    /* mac = (h + nonce) % (2^128) */
++    h0 = (u32)(t = (u64)h0 + nonce[0]);
++    h1 = (u32)(t = (u64)h1 + (t >> 32) + nonce[1]);
++    h2 = (u32)(t = (u64)h2 + (t >> 32) + nonce[2]);
++    h3 = (u32)(t = (u64)h3 + (t >> 32) + nonce[3]);
++
++    U32TO8(mac + 0, h0);
++    U32TO8(mac + 4, h1);
++    U32TO8(mac + 8, h2);
++    U32TO8(mac + 12, h3);
++}
++# endif
++#else
++int poly1305_init(void *ctx, const unsigned char key[16], void *func);
++void poly1305_blocks(void *ctx, const unsigned char *inp, size_t len,
++                     unsigned int padbit);
++void poly1305_emit(void *ctx, unsigned char mac[16],
++                   const unsigned int nonce[4]);
++#endif
++
++void Poly1305_Init(POLY1305 *ctx, const unsigned char key[32])
++{
++    ctx->nonce[0] = U8TOU32(&key[16]);
++    ctx->nonce[1] = U8TOU32(&key[20]);
++    ctx->nonce[2] = U8TOU32(&key[24]);
++    ctx->nonce[3] = U8TOU32(&key[28]);
++
++#ifndef POLY1305_ASM
++    poly1305_init(ctx->opaque, key);
++#else
++    /*
++     * Unlike reference poly1305_init assembly counterpart is expected
++     * to return a value: non-zero if it initializes ctx->func, and zero
++     * otherwise. Latter is to simplify assembly in cases when there no
++     * multiple code paths to switch between.
++     */
++    if (!poly1305_init(ctx->opaque, key, &ctx->func)) {
++        ctx->func.blocks = poly1305_blocks;
++        ctx->func.emit = poly1305_emit;
++    }
++#endif
++
++    ctx->num = 0;
++
++}
++
++#ifdef POLY1305_ASM
++/*
++ * This "eclipses" poly1305_blocks and poly1305_emit, but it's
++ * conscious choice imposed by -Wshadow compiler warnings.
++ */
++# define poly1305_blocks (*poly1305_blocks_p)
++# define poly1305_emit   (*poly1305_emit_p)
++#endif
++
++void Poly1305_Update(POLY1305 *ctx, const unsigned char *inp, size_t len)
++{
++#ifdef POLY1305_ASM
++    /*
++     * As documented, poly1305_blocks is never called with input
++     * longer than single block and padbit argument set to 0. This
++     * property is fluently used in assembly modules to optimize
++     * padbit handling on loop boundary.
++     */
++    poly1305_blocks_f poly1305_blocks_p = ctx->func.blocks;
++#endif
++    size_t rem, num;
++
++    if ((num = ctx->num)) {
++        rem = POLY1305_BLOCK_SIZE - num;
++        if (len >= rem) {
++            memcpy(ctx->data + num, inp, rem);
++            poly1305_blocks(ctx->opaque, ctx->data, POLY1305_BLOCK_SIZE, 1);
++            inp += rem;
++            len -= rem;
++        } else {
++            /* Still not enough data to process a block. */
++            memcpy(ctx->data + num, inp, len);
++            ctx->num = num + len;
++            return;
++        }
++    }
++
++    rem = len % POLY1305_BLOCK_SIZE;
++    len -= rem;
++
++    if (len >= POLY1305_BLOCK_SIZE) {
++        poly1305_blocks(ctx->opaque, inp, len, 1);
++        inp += len;
++    }
++
++    if (rem)
++        memcpy(ctx->data, inp, rem);
++
++    ctx->num = rem;
++}
++
++void Poly1305_Final(POLY1305 *ctx, unsigned char mac[16])
++{
++#ifdef POLY1305_ASM
++    poly1305_blocks_f poly1305_blocks_p = ctx->func.blocks;
++    poly1305_emit_f poly1305_emit_p = ctx->func.emit;
++#endif
++    size_t num;
++
++    if ((num = ctx->num)) {
++        ctx->data[num++] = 1;   /* pad bit */
++        while (num < POLY1305_BLOCK_SIZE)
++            ctx->data[num++] = 0;
++        poly1305_blocks(ctx->opaque, ctx->data, POLY1305_BLOCK_SIZE, 0);
++    }
++
++    poly1305_emit(ctx->opaque, mac, ctx->nonce);
++
++    /* zero out the state */
++    OPENSSL_cleanse(ctx, sizeof(*ctx));
++}
++
++#ifdef SELFTEST
++#include 
++
++struct poly1305_test {
++    const char *inputhex;
++    const char *keyhex;
++    const char *outhex;
++};
++
++static const struct poly1305_test poly1305_tests[] = {
++    /*
++     * RFC7539
++     */
++    {
++     "43727970746f6772617068696320466f72756d2052657365617263682047726f"
++     "7570",
++     "85d6be7857556d337f4452fe42d506a8""0103808afb0db2fd4abff6af4149f51b",
++     "a8061dc1305136c6c22b8baf0c0127a9"
++    },
++    /*
++     * test vectors from "The Poly1305-AES message-authentication code"
++     */
++    {
++     "f3f6",
++     "851fc40c3467ac0be05cc20404f3f700""580b3b0f9447bb1e69d095b5928b6dbc",
++     "f4c633c3044fc145f84f335cb81953de"
++    },
++    {
++     "",
++     "a0f3080000f46400d0c7e9076c834403""dd3fab2251f11ac759f0887129cc2ee7",
++     "dd3fab2251f11ac759f0887129cc2ee7"
++    },
++    {
++     "663cea190ffb83d89593f3f476b6bc24d7e679107ea26adb8caf6652d0656136",
++     "48443d0bb0d21109c89a100b5ce2c208""83149c69b561dd88298a1798b10716ef",
++     "0ee1c16bb73f0f4fd19881753c01cdbe"
++    },
++    {
++     "ab0812724a7f1e342742cbed374d94d136c6b8795d45b3819830f2c04491faf0"
++     "990c62e48b8018b2c3e4a0fa3134cb67fa83e158c994d961c4cb21095c1bf9",
++     "12976a08c4426d0ce8a82407c4f48207""80f8c20aa71202d1e29179cbcb555a57",
++     "5154ad0d2cb26e01274fc51148491f1b"
++    },
++    /*
++     * self-generated vectors exercise "significant" lengths, such that
++     * are handled by different code paths
++     */
++    {
++     "ab0812724a7f1e342742cbed374d94d136c6b8795d45b3819830f2c04491faf0"
++     "990c62e48b8018b2c3e4a0fa3134cb67fa83e158c994d961c4cb21095c1bf9af",
++     "12976a08c4426d0ce8a82407c4f48207""80f8c20aa71202d1e29179cbcb555a57",
++     "812059a5da198637cac7c4a631bee466"
++    },
++    {
++     "ab0812724a7f1e342742cbed374d94d136c6b8795d45b3819830f2c04491faf0"
++     "990c62e48b8018b2c3e4a0fa3134cb67",
++     "12976a08c4426d0ce8a82407c4f48207""80f8c20aa71202d1e29179cbcb555a57",
++     "5b88d7f6228b11e2e28579a5c0c1f761"
++    },
++    {
++     "ab0812724a7f1e342742cbed374d94d136c6b8795d45b3819830f2c04491faf0"
++     "990c62e48b8018b2c3e4a0fa3134cb67fa83e158c994d961c4cb21095c1bf9af"
++     "663cea190ffb83d89593f3f476b6bc24d7e679107ea26adb8caf6652d0656136",
++     "12976a08c4426d0ce8a82407c4f48207""80f8c20aa71202d1e29179cbcb555a57",
++     "bbb613b2b6d753ba07395b916aaece15"
++    },
++    {
++     "ab0812724a7f1e342742cbed374d94d136c6b8795d45b3819830f2c04491faf0"
++     "990c62e48b8018b2c3e4a0fa3134cb67fa83e158c994d961c4cb21095c1bf9af"
++     "48443d0bb0d21109c89a100b5ce2c20883149c69b561dd88298a1798b10716ef"
++     "663cea190ffb83d89593f3f476b6bc24",
++     "12976a08c4426d0ce8a82407c4f48207""80f8c20aa71202d1e29179cbcb555a57",
++     "c794d7057d1778c4bbee0a39b3d97342"
++    },
++    {
++     "ab0812724a7f1e342742cbed374d94d136c6b8795d45b3819830f2c04491faf0"
++     "990c62e48b8018b2c3e4a0fa3134cb67fa83e158c994d961c4cb21095c1bf9af"
++     "48443d0bb0d21109c89a100b5ce2c20883149c69b561dd88298a1798b10716ef"
++     "663cea190ffb83d89593f3f476b6bc24d7e679107ea26adb8caf6652d0656136",
++     "12976a08c4426d0ce8a82407c4f48207""80f8c20aa71202d1e29179cbcb555a57",
++     "ffbcb9b371423152d7fca5ad042fbaa9"
++    },
++    {
++     "ab0812724a7f1e342742cbed374d94d136c6b8795d45b3819830f2c04491faf0"
++     "990c62e48b8018b2c3e4a0fa3134cb67fa83e158c994d961c4cb21095c1bf9af"
++     "48443d0bb0d21109c89a100b5ce2c20883149c69b561dd88298a1798b10716ef"
++     "663cea190ffb83d89593f3f476b6bc24d7e679107ea26adb8caf6652d0656136"
++     "812059a5da198637cac7c4a631bee466",
++     "12976a08c4426d0ce8a82407c4f48207""80f8c20aa71202d1e29179cbcb555a57",
++     "069ed6b8ef0f207b3e243bb1019fe632"
++    },
++    {
++     "ab0812724a7f1e342742cbed374d94d136c6b8795d45b3819830f2c04491faf0"
++     "990c62e48b8018b2c3e4a0fa3134cb67fa83e158c994d961c4cb21095c1bf9af"
++     "48443d0bb0d21109c89a100b5ce2c20883149c69b561dd88298a1798b10716ef"
++     "663cea190ffb83d89593f3f476b6bc24d7e679107ea26adb8caf6652d0656136"
++     "812059a5da198637cac7c4a631bee4665b88d7f6228b11e2e28579a5c0c1f761",
++     "12976a08c4426d0ce8a82407c4f48207""80f8c20aa71202d1e29179cbcb555a57",
++     "cca339d9a45fa2368c2c68b3a4179133"
++    },
++    {
++     "ab0812724a7f1e342742cbed374d94d136c6b8795d45b3819830f2c04491faf0"
++     "990c62e48b8018b2c3e4a0fa3134cb67fa83e158c994d961c4cb21095c1bf9af"
++     "48443d0bb0d21109c89a100b5ce2c20883149c69b561dd88298a1798b10716ef"
++     "663cea190ffb83d89593f3f476b6bc24d7e679107ea26adb8caf6652d0656136"
++     "812059a5da198637cac7c4a631bee4665b88d7f6228b11e2e28579a5c0c1f761"
++     "ab0812724a7f1e342742cbed374d94d136c6b8795d45b3819830f2c04491faf0"
++     "990c62e48b8018b2c3e4a0fa3134cb67fa83e158c994d961c4cb21095c1bf9af"
++     "48443d0bb0d21109c89a100b5ce2c20883149c69b561dd88298a1798b10716ef"
++     "663cea190ffb83d89593f3f476b6bc24d7e679107ea26adb8caf6652d0656136",
++     "12976a08c4426d0ce8a82407c4f48207""80f8c20aa71202d1e29179cbcb555a57",
++     "53f6e828a2f0fe0ee815bf0bd5841a34"
++    },
++    {
++     "ab0812724a7f1e342742cbed374d94d136c6b8795d45b3819830f2c04491faf0"
++     "990c62e48b8018b2c3e4a0fa3134cb67fa83e158c994d961c4cb21095c1bf9af"
++     "48443d0bb0d21109c89a100b5ce2c20883149c69b561dd88298a1798b10716ef"
++     "663cea190ffb83d89593f3f476b6bc24d7e679107ea26adb8caf6652d0656136"
++     "812059a5da198637cac7c4a631bee4665b88d7f6228b11e2e28579a5c0c1f761"
++     "ab0812724a7f1e342742cbed374d94d136c6b8795d45b3819830f2c04491faf0"
++     "990c62e48b8018b2c3e4a0fa3134cb67fa83e158c994d961c4cb21095c1bf9af"
++     "48443d0bb0d21109c89a100b5ce2c20883149c69b561dd88298a1798b10716ef"
++     "663cea190ffb83d89593f3f476b6bc24d7e679107ea26adb8caf6652d0656136"
++     "812059a5da198637cac7c4a631bee4665b88d7f6228b11e2e28579a5c0c1f761",
++     "12976a08c4426d0ce8a82407c4f48207""80f8c20aa71202d1e29179cbcb555a57",
++     "b846d44e9bbd53cedffbfbb6b7fa4933"
++    },
++    /*
++     * 4th power of the key spills to 131th bit in SIMD key setup
++     */
++    {
++     "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
++     "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
++     "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
++     "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
++     "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
++     "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
++     "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
++     "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
++     "ad628107e8351d0f2c231a05dc4a4106""00000000000000000000000000000000",
++     "07145a4c02fe5fa32036de68fabe9066"
++    },
++    {
++    /*
++     * poly1305_ieee754.c failed this in final stage
++     */
++     "842364e156336c0998b933a6237726180d9e3fdcbde4cd5d17080fc3beb49614"
++     "d7122c037463ff104d73f19c12704628d417c4c54a3fe30d3c3d7714382d43b0"
++     "382a50a5dee54be844b076e8df88201a1cd43b90eb21643fa96f39b518aa8340"
++     "c942ff3c31baf7c9bdbf0f31ae3fa096bf8c63030609829fe72e179824890bc8"
++     "e08c315c1cce2a83144dbbff09f74e3efc770b54d0984a8f19b14719e6363564"
++     "1d6b1eedf63efbf080e1783d32445412114c20de0b837a0dfa33d6b82825fff4"
++     "4c9a70ea54ce47f07df698e6b03323b53079364a5fc3e9dd034392bdde86dccd"
++     "da94321c5e44060489336cb65bf3989c36f7282c2f5d2b882c171e74",
++     "95d5c005503e510d8cd0aa072c4a4d06""6eabc52d11653df47fbf63ab198bcc26",
++     "f248312e578d9d58f8b7bb4d19105431"
++    },
++    /*
++     * AVX2 in poly1305-x86.pl failed this with 176+32 split
++     */
++    {
++    "248ac31085b6c2adaaa38259a0d7192c5c35d1bb4ef39ad94c38d1c82479e2dd"
++    "2159a077024b0589bc8a20101b506f0a1ad0bbab76e83a83f1b94be6beae74e8"
++    "74cab692c5963a75436b776121ec9f62399a3e66b2d22707dae81933b6277f3c"
++    "8516bcbe26dbbd86f373103d7cf4cad1888c952118fbfbd0d7b4bedc4ae4936a"
++    "ff91157e7aa47c54442ea78d6ac251d324a0fbe49d89cc3521b66d16e9c66a37"
++    "09894e4eb0a4eedc4ae19468e66b81f2"
++    "71351b1d921ea551047abcc6b87a901fde7db79fa1818c11336dbc07244a40eb",
++    "000102030405060708090a0b0c0d0e0f""00000000000000000000000000000000",
++    "bc939bc5281480fa99c6d68c258ec42f"
++    },
++    /*
++     * test vectors from Google
++     */
++    {
++     "",
++     "c8afaac331ee372cd6082de134943b17""4710130e9f6fea8d72293850a667d86c",
++     "4710130e9f6fea8d72293850a667d86c",
++    },
++    {
++     "48656c6c6f20776f726c6421",
++     "746869732069732033322d6279746520""6b657920666f7220506f6c7931333035",
++     "a6f745008f81c916a20dcc74eef2b2f0"
++    },
++    {
++     "0000000000000000000000000000000000000000000000000000000000000000",
++     "746869732069732033322d6279746520""6b657920666f7220506f6c7931333035",
++     "49ec78090e481ec6c26b33b91ccc0307"
++    },
++    {
++     "89dab80b7717c1db5db437860a3f70218e93e1b8f461fb677f16f35f6f87e2a9"
++     "1c99bc3a47ace47640cc95c345be5ecca5a3523c35cc01893af0b64a62033427"
++     "0372ec12482d1b1e363561698a578b359803495bb4e2ef1930b17a5190b580f1"
++     "41300df30adbeca28f6427a8bc1a999fd51c554a017d095d8c3e3127daf9f595",
++     "2d773be37adb1e4d683bf0075e79c4ee""037918535a7f99ccb7040fb5f5f43aea",
++     "c85d15ed44c378d6b00e23064c7bcd51"
++    },
++    {
++     "000000000000000b1703030200000000"
++     "06db1f1f368d696a810a349c0c714c9a5e7850c2407d721acded95e018d7a852"
++     "66a6e1289cdb4aeb18da5ac8a2b0026d24a59ad485227f3eaedbb2e7e35e1c66"
++     "cd60f9abf716dcc9ac42682dd7dab287a7024c4eefc321cc0574e16793e37cec"
++     "03c5bda42b54c114a80b57af26416c7be742005e20855c73e21dc8e2edc9d435"
++     "cb6f6059280011c270b71570051c1c9b3052126620bc1e2730fa066c7a509d53"
++     "c60e5ae1b40aa6e39e49669228c90eecb4a50db32a50bc49e90b4f4b359a1dfd"
++     "11749cd3867fcf2fb7bb6cd4738f6a4ad6f7ca5058f7618845af9f020f6c3b96"
++     "7b8f4cd4a91e2813b507ae66f2d35c18284f7292186062e10fd5510d18775351"
++     "ef334e7634ab4743f5b68f49adcab384d3fd75f7390f4006ef2a295c8c7a076a"
++     "d54546cd25d2107fbe1436c840924aaebe5b370893cd63d1325b8616fc481088"
++     "6bc152c53221b6df373119393255ee72bcaa880174f1717f9184fa91646f17a2"
++     "4ac55d16bfddca9581a92eda479201f0edbf633600d6066d1ab36d5d2415d713"
++     "51bbcd608a25108d25641992c1f26c531cf9f90203bc4cc19f5927d834b0a471"
++     "16d3884bbb164b8ec883d1ac832e56b3918a98601a08d171881541d594db399c"
++     "6ae6151221745aec814c45b0b05b565436fd6f137aa10a0c0b643761dbd6f9a9"
++     "dcb99b1a6e690854ce0769cde39761d82fcdec15f0d92d7d8e94ade8eb83fbe0",
++     "99e5822dd4173c995e3dae0ddefb9774""3fde3b080134b39f76e9bf8d0e88d546",
++     "2637408fe13086ea73f971e3425e2820"
++    },
++    /*
++     * test vectors from Hanno Böck
++     */
++    {
++     "cccccccccccccccccccccccccccccccccccccccccccccccccc80cccccccccccc"
++     "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccecccccc"
++     "ccccccccccccccccccccccccccccccc5cccccccccccccccccccccccccccccccc"
++     "cccccccccce3cccccccccccccccccccccccccccccccccccccccccccccccccccc"
++     "ccccccccaccccccccccccccccccccce6cccccccccc000000afcccccccccccccc"
++     "ccccfffffff50000000000000000000000000000000000000000000000000000"
++     "00ffffffe7000000000000000000000000000000000000000000000000000000"
++     "0000000000000000000000000000000000000000000000000000719205a8521d"
++     "fc",
++     "7f1b0264000000000000000000000000""0000000000000000cccccccccccccccc",
++     "8559b876eceed66eb37798c0457baff9"
++    },
++    {
++     "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa0000000000"
++     "00000000800264",
++     "e0001600000000000000000000000000""0000aaaaaaaaaaaaaaaaaaaaaaaaaaaa",
++     "00bd1258978e205444c9aaaa82006fed"
++    },
++    {
++     "02fc",
++     "0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c""0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c",
++     "06120c0c0c0c0c0c0c0c0c0c0c0c0c0c"
++    },
++    {
++     "7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b"
++     "7b7b7b7b7b7b7a7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b"
++     "7b7b5c7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b"
++     "7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b6e7b007b7b7b7b7b7b7b7b7b"
++     "7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7a7b7b7b7b7b7b7b7b7b7b7b7b"
++     "7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b5c7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b"
++     "7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b"
++     "7b6e7b001300000000b300000000000000000000000000000000000000000000"
++     "f20000000000000000000000000000000000002000efff000900000000000000"
++     "0000000000100000000009000000640000000000000000000000001300000000"
++     "b300000000000000000000000000000000000000000000f20000000000000000"
++     "000000000000000000002000efff00090000000000000000007a000010000000"
++     "000900000064000000000000000000000000000000000000000000000000fc",
++     "00ff0000000000000000000000000000""00000000001e00000000000000007b7b",
++     "33205bbf9e9f8f7212ab9e2ab9b7e4a5"
++    },
++    {
++     "7777777777777777777777777777777777777777777777777777777777777777"
++     "7777777777777777777777777777777777777777777777777777777777777777"
++     "777777777777777777777777ffffffe9e9acacacacacacacacacacac0000acac"
++     "ec0100acacac2caca2acacacacacacacacacacac64f2",
++     "0000007f0000007f0100002000000000""0000cf77777777777777777777777777",
++     "02ee7c8c546ddeb1a467e4c3981158b9"
++    },
++    /*
++     * test vectors from Andrew Moon
++     */
++    {   /* nacl */
++     "8e993b9f48681273c29650ba32fc76ce48332ea7164d96a4476fb8c531a1186a"
++     "c0dfc17c98dce87b4da7f011ec48c97271d2c20f9b928fe2270d6fb863d51738"
++     "b48eeee314a7cc8ab932164548e526ae90224368517acfeabd6bb3732bc0e9da"
++     "99832b61ca01b6de56244a9e88d5f9b37973f622a43d14a6599b1f654cb45a74"
++     "e355a5",
++     "eea6a7251c1e72916d11c2cb214d3c25""2539121d8e234e652d651fa4c8cff880",
++     "f3ffc7703f9400e52a7dfb4b3d3305d9"
++    },
++    {   /* wrap 2^130-5 */
++     "ffffffffffffffffffffffffffffffff",
++     "02000000000000000000000000000000""00000000000000000000000000000000",
++     "03000000000000000000000000000000"
++    },
++    {   /* wrap 2^128 */
++     "02000000000000000000000000000000",
++     "02000000000000000000000000000000""ffffffffffffffffffffffffffffffff",
++     "03000000000000000000000000000000"
++    },
++    {   /* limb carry */
++     "fffffffffffffffffffffffffffffffff0ffffffffffffffffffffffffffffff"
++     "11000000000000000000000000000000",
++     "01000000000000000000000000000000""00000000000000000000000000000000",
++     "05000000000000000000000000000000"
++    },
++    {   /* 2^130-5 */
++     "fffffffffffffffffffffffffffffffffbfefefefefefefefefefefefefefefe"
++     "01010101010101010101010101010101",
++     "01000000000000000000000000000000""00000000000000000000000000000000",
++     "00000000000000000000000000000000"
++    },
++    {   /* 2^130-6 */
++     "fdffffffffffffffffffffffffffffff",
++     "02000000000000000000000000000000""00000000000000000000000000000000",
++     "faffffffffffffffffffffffffffffff"
++    },
++    {   /* 5*H+L reduction intermediate */
++     "e33594d7505e43b900000000000000003394d7505e4379cd0100000000000000"
++     "0000000000000000000000000000000001000000000000000000000000000000",
++     "01000000000000000400000000000000""00000000000000000000000000000000",
++     "14000000000000005500000000000000"
++    },
++    {   /* 5*H+L reduction final */
++     "e33594d7505e43b900000000000000003394d7505e4379cd0100000000000000"
++     "00000000000000000000000000000000",
++     "01000000000000000400000000000000""00000000000000000000000000000000",
++     "13000000000000000000000000000000"
++    }
++};
++
++static unsigned char hex_digit(char h)
++{
++    int i = OPENSSL_hexchar2int(h);
++
++    if (i < 0)
++        abort();
++    return i;
++}
++
++static void hex_decode(unsigned char *out, const char *hex)
++{
++    size_t j = 0;
++
++    while (*hex != 0) {
++        unsigned char v = hex_digit(*hex++);
++        v <<= 4;
++        v |= hex_digit(*hex++);
++        out[j++] = v;
++    }
++}
++
++static void hexdump(unsigned char *a, size_t len)
++{
++    size_t i;
++
++    for (i = 0; i < len; i++)
++        printf("%02x", a[i]);
++}
++
++int main()
++{
++    static const unsigned num_tests =
++        sizeof(poly1305_tests) / sizeof(struct poly1305_test);
++    unsigned i;
++    unsigned char key[32], out[16], expected[16];
++    POLY1305 poly1305;
++
++    for (i = 0; i < num_tests; i++) {
++        const struct poly1305_test *test = &poly1305_tests[i];
++        unsigned char *in;
++        size_t inlen = strlen(test->inputhex);
++
++        if (strlen(test->keyhex) != sizeof(key) * 2 ||
++            strlen(test->outhex) != sizeof(out) * 2 || (inlen & 1) == 1)
++            return 1;
++
++        inlen /= 2;
++
++        hex_decode(key, test->keyhex);
++        hex_decode(expected, test->outhex);
++
++        in = malloc(inlen);
++
++        hex_decode(in, test->inputhex);
++
++        Poly1305_Init(&poly1305, key);
++        Poly1305_Update(&poly1305, in, inlen);
++        Poly1305_Final(&poly1305, out);
++
++        if (memcmp(out, expected, sizeof(expected)) != 0) {
++            printf("Poly1305 test #%d failed.\n", i);
++            printf("got:      ");
++            hexdump(out, sizeof(out));
++            printf("\nexpected: ");
++            hexdump(expected, sizeof(expected));
++            printf("\n");
++            return 1;
++        }
++
++        if (inlen > 16) {
++            Poly1305_Init(&poly1305, key);
++            Poly1305_Update(&poly1305, in, 1);
++            Poly1305_Update(&poly1305, in+1, inlen-1);
++            Poly1305_Final(&poly1305, out);
++
++            if (memcmp(out, expected, sizeof(expected)) != 0) {
++                printf("Poly1305 test #%d/1+(N-1) failed.\n", i);
++                printf("got:      ");
++                hexdump(out, sizeof(out));
++                printf("\nexpected: ");
++                hexdump(expected, sizeof(expected));
++                printf("\n");
++                return 1;
++            }
++        }
++
++        if (inlen > 32) {
++            size_t half = inlen / 2;
++
++            Poly1305_Init(&poly1305, key);
++            Poly1305_Update(&poly1305, in, half);
++            Poly1305_Update(&poly1305, in+half, inlen-half);
++            Poly1305_Final(&poly1305, out);
++
++            if (memcmp(out, expected, sizeof(expected)) != 0) {
++                printf("Poly1305 test #%d/2 failed.\n", i);
++                printf("got:      ");
++                hexdump(out, sizeof(out));
++                printf("\nexpected: ");
++                hexdump(expected, sizeof(expected));
++                printf("\n");
++                return 1;
++            }
++
++            for (half = 16; half < inlen; half += 16) {
++                Poly1305_Init(&poly1305, key);
++                Poly1305_Update(&poly1305, in, half);
++                Poly1305_Update(&poly1305, in+half, inlen-half);
++                Poly1305_Final(&poly1305, out);
++
++                if (memcmp(out, expected, sizeof(expected)) != 0) {
++                    printf("Poly1305 test #%d/%d+%d failed.\n",
++                                           i, half, inlen-half);
++                    printf("got:      ");
++                    hexdump(out, sizeof(out));
++                    printf("\nexpected: ");
++                    hexdump(expected, sizeof(expected));
++                    printf("\n");
++                    return 1;
++                }
++            }
++        }
++
++        free(in);
++    }
++
++    printf("PASS\n");
++
++# ifdef OPENSSL_CPUID_OBJ
++    {
++        unsigned char buf[8192];
++        unsigned long long stopwatch;
++        unsigned long long OPENSSL_rdtsc();
++
++        memset (buf,0x55,sizeof(buf));
++        memset (key,0xAA,sizeof(key));
++
++        Poly1305_Init(&poly1305, key);
++
++        for (i=0;i<100000;i++)
++            Poly1305_Update(&poly1305,buf,sizeof(buf));
++
++        stopwatch = OPENSSL_rdtsc();
++        for (i=0;i<10000;i++)
++            Poly1305_Update(&poly1305,buf,sizeof(buf));
++        stopwatch = OPENSSL_rdtsc() - stopwatch;
++
++        printf("%g\n",stopwatch/(double)(i*sizeof(buf)));
++
++        stopwatch = OPENSSL_rdtsc();
++        for (i=0;i<10000;i++) {
++            Poly1305_Init(&poly1305, key);
++            Poly1305_Update(&poly1305,buf,16);
++            Poly1305_Final(&poly1305,buf);
++        }
++        stopwatch = OPENSSL_rdtsc() - stopwatch;
++
++        printf("%g\n",stopwatch/(double)(i));
++    }
++# endif
++    return 0;
++}
++#endif
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/poly1305/poly1305_ieee754.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/poly1305/poly1305_ieee754.c
+new file mode 100644
+index 0000000..08a5b58
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/poly1305/poly1305_ieee754.c
+@@ -0,0 +1,472 @@
++/*
++ * Copyright 2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++/*
++ * This module is meant to be used as template for non-x87 floating-
++ * point assembly modules. The template itself is x86_64-specific
++ * though, as it was debugged on x86_64. So that implementor would
++ * have to recognize platform-specific parts, UxTOy and inline asm,
++ * and act accordingly.
++ *
++ * Huh? x86_64-specific code as template for non-x87? Note seven, which
++ * is not a typo, but reference to 80-bit precision. This module on the
++ * other hand relies on 64-bit precision operations, which are default
++ * for x86_64 code. And since we are at it, just for sense of it,
++ * large-block performance in cycles per processed byte for *this* code
++ * is:
++ *			gcc-4.8		icc-15.0	clang-3.4(*)
++ *
++ * Westmere		4.96		5.09		4.37
++ * Sandy Bridge		4.95		4.90		4.17
++ * Haswell		4.92		4.87		3.78
++ * Bulldozer		4.67		4.49		4.68
++ * VIA Nano		7.07		7.05		5.98
++ * Silvermont		10.6		9.61		12.6
++ *
++ * (*)	clang managed to discover parallelism and deployed SIMD;
++ *
++ * And for range of other platforms with unspecified gcc versions:
++ *
++ * Freescale e300	12.5
++ * PPC74x0		10.8
++ * POWER6		4.92
++ * POWER7		4.50
++ * POWER8		4.10
++ *
++ * z10			11.2
++ * z196+		7.30
++ *
++ * UltraSPARC III	16.0
++ * SPARC T4		16.1
++ */
++
++#if !(defined(__GNUC__) && __GNUC__>=2)
++# error "this is gcc-specific template"
++#endif
++
++#include 
++
++typedef unsigned char u8;
++typedef unsigned int u32;
++typedef unsigned long long u64;
++typedef union { double d; u64 u; } elem64;
++
++#define TWO(p)		((double)(1ULL<<(p)))
++#define TWO0		TWO(0)
++#define TWO32		TWO(32)
++#define TWO64		(TWO32*TWO(32))
++#define TWO96		(TWO64*TWO(32))
++#define TWO130		(TWO96*TWO(34))
++
++#define EXP(p)		((1023ULL+(p))<<52)
++
++#if defined(__x86_64__) || (defined(__PPC__) && defined(__LITTLE_ENDIAN__))
++# define U8TOU32(p)	(*(const u32 *)(p))
++# define U32TO8(p,v)	(*(u32 *)(p) = (v))
++#elif defined(__PPC__)
++# define U8TOU32(p)	({u32 ret; asm ("lwbrx	%0,0,%1":"=r"(ret):"b"(p)); ret; })
++# define U32TO8(p,v)	asm ("stwbrx %0,0,%1"::"r"(v),"b"(p):"memory")
++#elif defined(__s390x__)
++# define U8TOU32(p)	({u32 ret; asm ("lrv	%0,%1":"=d"(ret):"m"(*(u32 *)(p))); ret; })
++# define U32TO8(p,v)	asm ("strv	%1,%0":"=m"(*(u32 *)(p)):"d"(v))
++#endif
++
++#ifndef U8TOU32
++# define U8TOU32(p)	((u32)(p)[0]     | (u32)(p)[1]<<8 | \
++			 (u32)(p)[2]<<16 | (u32)(p)[3]<<24  )
++#endif
++#ifndef U32TO8
++# define U32TO8(p,v)	((p)[0] = (u8)(v),       (p)[1] = (u8)((v)>>8), \
++			 (p)[2] = (u8)((v)>>16), (p)[3] = (u8)((v)>>24) )
++#endif
++
++typedef struct {
++    elem64 h[4];
++    double r[8];
++    double s[6];
++} poly1305_internal;
++
++/* "round toward zero (truncate), mask all exceptions" */
++#if defined(__x86_64__)
++static const u32 mxcsr = 0x7f80;
++#elif defined(__PPC__)
++static const u64 one = 1;
++#elif defined(__s390x__)
++static const u32 fpc = 1;
++#elif defined(__sparc__)
++static const u64 fsr = 1ULL<<30;
++#else
++#error "unrecognized platform"
++#endif
++
++int poly1305_init(void *ctx, const unsigned char key[16])
++{
++    poly1305_internal *st = (poly1305_internal *) ctx;
++    elem64 r0, r1, r2, r3;
++
++    /* h = 0, biased */
++#if 0
++    st->h[0].d = TWO(52)*TWO0;
++    st->h[1].d = TWO(52)*TWO32;
++    st->h[2].d = TWO(52)*TWO64;
++    st->h[3].d = TWO(52)*TWO96;
++#else
++    st->h[0].u = EXP(52+0);
++    st->h[1].u = EXP(52+32);
++    st->h[2].u = EXP(52+64);
++    st->h[3].u = EXP(52+96);
++#endif
++
++    if (key) {
++        /*
++         * set "truncate" rounding mode
++         */
++#if defined(__x86_64__)
++        u32 mxcsr_orig;
++
++        asm volatile ("stmxcsr	%0":"=m"(mxcsr_orig));
++        asm volatile ("ldmxcsr	%0"::"m"(mxcsr));
++#elif defined(__PPC__)
++        double fpscr_orig, fpscr = *(double *)&one;
++
++        asm volatile ("mffs	%0":"=f"(fpscr_orig));
++        asm volatile ("mtfsf	255,%0"::"f"(fpscr));
++#elif defined(__s390x__)
++        u32 fpc_orig;
++
++        asm volatile ("stfpc	%0":"=m"(fpc_orig));
++        asm volatile ("lfpc	%0"::"m"(fpc));
++#elif defined(__sparc__)
++        u64 fsr_orig;
++
++        asm volatile ("stx	%%fsr,%0":"=m"(fsr_orig));
++        asm volatile ("ldx	%0,%%fsr"::"m"(fsr));
++#endif
++
++        /* r &= 0xffffffc0ffffffc0ffffffc0fffffff */
++        r0.u = EXP(52+0)  | (U8TOU32(&key[0])  & 0x0fffffff);
++        r1.u = EXP(52+32) | (U8TOU32(&key[4])  & 0x0ffffffc);
++        r2.u = EXP(52+64) | (U8TOU32(&key[8])  & 0x0ffffffc);
++        r3.u = EXP(52+96) | (U8TOU32(&key[12]) & 0x0ffffffc);
++
++        st->r[0] = r0.d - TWO(52)*TWO0;
++        st->r[2] = r1.d - TWO(52)*TWO32;
++        st->r[4] = r2.d - TWO(52)*TWO64;
++        st->r[6] = r3.d - TWO(52)*TWO96;
++
++        st->s[0] = st->r[2] * (5.0/TWO130);
++        st->s[2] = st->r[4] * (5.0/TWO130);
++        st->s[4] = st->r[6] * (5.0/TWO130);
++
++        /*
++         * base 2^32 -> base 2^16
++         */
++        st->r[1] = (st->r[0] + TWO(52)*TWO(16)*TWO0) -
++                               TWO(52)*TWO(16)*TWO0;
++        st->r[0] -= st->r[1];
++
++        st->r[3] = (st->r[2] + TWO(52)*TWO(16)*TWO32) -
++                               TWO(52)*TWO(16)*TWO32;
++        st->r[2] -= st->r[3];
++
++        st->r[5] = (st->r[4] + TWO(52)*TWO(16)*TWO64) -
++                               TWO(52)*TWO(16)*TWO64;
++        st->r[4] -= st->r[5];
++
++        st->r[7] = (st->r[6] + TWO(52)*TWO(16)*TWO96) -
++                               TWO(52)*TWO(16)*TWO96;
++        st->r[6] -= st->r[7];
++
++        st->s[1] = (st->s[0] + TWO(52)*TWO(16)*TWO0/TWO96) -
++                               TWO(52)*TWO(16)*TWO0/TWO96;
++        st->s[0] -= st->s[1];
++
++        st->s[3] = (st->s[2] + TWO(52)*TWO(16)*TWO32/TWO96) -
++                               TWO(52)*TWO(16)*TWO32/TWO96;
++        st->s[2] -= st->s[3];
++
++        st->s[5] = (st->s[4] + TWO(52)*TWO(16)*TWO64/TWO96) -
++                               TWO(52)*TWO(16)*TWO64/TWO96;
++        st->s[4] -= st->s[5];
++
++        /*
++         * restore original FPU control register
++         */
++#if defined(__x86_64__)
++        asm volatile ("ldmxcsr	%0"::"m"(mxcsr_orig));
++#elif defined(__PPC__)
++        asm volatile ("mtfsf	255,%0"::"f"(fpscr_orig));
++#elif defined(__s390x__)
++        asm volatile ("lfpc	%0"::"m"(fpc_orig));
++#elif defined(__sparc__)
++        asm volatile ("ldx	%0,%%fsr"::"m"(fsr_orig));
++#endif
++    }
++
++    return 0;
++}
++
++void poly1305_blocks(void *ctx, const unsigned char *inp, size_t len,
++                     int padbit)
++{
++    poly1305_internal *st = (poly1305_internal *)ctx;
++    elem64 in0, in1, in2, in3;
++    u64 pad = (u64)padbit<<32;
++
++    double x0, x1, x2, x3;
++    double h0lo, h0hi, h1lo, h1hi, h2lo, h2hi, h3lo, h3hi;
++    double c0lo, c0hi, c1lo, c1hi, c2lo, c2hi, c3lo, c3hi;
++
++    const double r0lo = st->r[0];
++    const double r0hi = st->r[1];
++    const double r1lo = st->r[2];
++    const double r1hi = st->r[3];
++    const double r2lo = st->r[4];
++    const double r2hi = st->r[5];
++    const double r3lo = st->r[6];
++    const double r3hi = st->r[7];
++
++    const double s1lo = st->s[0];
++    const double s1hi = st->s[1];
++    const double s2lo = st->s[2];
++    const double s2hi = st->s[3];
++    const double s3lo = st->s[4];
++    const double s3hi = st->s[5];
++
++    /*
++     * set "truncate" rounding mode
++     */
++#if defined(__x86_64__)
++    u32 mxcsr_orig;
++
++    asm volatile ("stmxcsr	%0":"=m"(mxcsr_orig));
++    asm volatile ("ldmxcsr	%0"::"m"(mxcsr));
++#elif defined(__PPC__)
++    double fpscr_orig, fpscr = *(double *)&one;
++
++    asm volatile ("mffs		%0":"=f"(fpscr_orig));
++    asm volatile ("mtfsf	255,%0"::"f"(fpscr));
++#elif defined(__s390x__)
++    u32 fpc_orig;
++
++    asm volatile ("stfpc	%0":"=m"(fpc_orig));
++    asm volatile ("lfpc		%0"::"m"(fpc));
++#elif defined(__sparc__)
++    u64 fsr_orig;
++
++    asm volatile ("stx		%%fsr,%0":"=m"(fsr_orig));
++    asm volatile ("ldx		%0,%%fsr"::"m"(fsr));
++#endif
++
++    /*
++     * load base 2^32 and de-bias
++     */
++    h0lo = st->h[0].d - TWO(52)*TWO0;
++    h1lo = st->h[1].d - TWO(52)*TWO32;
++    h2lo = st->h[2].d - TWO(52)*TWO64;
++    h3lo = st->h[3].d - TWO(52)*TWO96;
++
++#ifdef __clang__
++    h0hi = 0;
++    h1hi = 0;
++    h2hi = 0;
++    h3hi = 0;
++#else
++    in0.u = EXP(52+0)  | U8TOU32(&inp[0]);
++    in1.u = EXP(52+32) | U8TOU32(&inp[4]);
++    in2.u = EXP(52+64) | U8TOU32(&inp[8]);
++    in3.u = EXP(52+96) | U8TOU32(&inp[12]) | pad;
++
++    x0 = in0.d - TWO(52)*TWO0;
++    x1 = in1.d - TWO(52)*TWO32;
++    x2 = in2.d - TWO(52)*TWO64;
++    x3 = in3.d - TWO(52)*TWO96;
++
++    x0 += h0lo;
++    x1 += h1lo;
++    x2 += h2lo;
++    x3 += h3lo;
++
++    goto fast_entry;
++#endif
++
++    do {
++        in0.u = EXP(52+0)  | U8TOU32(&inp[0]);
++        in1.u = EXP(52+32) | U8TOU32(&inp[4]);
++        in2.u = EXP(52+64) | U8TOU32(&inp[8]);
++        in3.u = EXP(52+96) | U8TOU32(&inp[12]) | pad;
++
++        x0 = in0.d - TWO(52)*TWO0;
++        x1 = in1.d - TWO(52)*TWO32;
++        x2 = in2.d - TWO(52)*TWO64;
++        x3 = in3.d - TWO(52)*TWO96;
++
++        /*
++         * note that there are multiple ways to accumulate input, e.g.
++         * one can as well accumulate to h0lo-h1lo-h1hi-h2hi...
++         */
++        h0lo += x0;
++        h0hi += x1;
++        h2lo += x2;
++        h2hi += x3;
++
++        /*
++         * carries that cross 32n-bit (and 130-bit) boundaries
++         */
++        c0lo = (h0lo + TWO(52)*TWO32)  - TWO(52)*TWO32;
++        c1lo = (h1lo + TWO(52)*TWO64)  - TWO(52)*TWO64;
++        c2lo = (h2lo + TWO(52)*TWO96)  - TWO(52)*TWO96;
++        c3lo = (h3lo + TWO(52)*TWO130) - TWO(52)*TWO130;
++
++        c0hi = (h0hi + TWO(52)*TWO32)  - TWO(52)*TWO32;
++        c1hi = (h1hi + TWO(52)*TWO64)  - TWO(52)*TWO64;
++        c2hi = (h2hi + TWO(52)*TWO96)  - TWO(52)*TWO96;
++        c3hi = (h3hi + TWO(52)*TWO130) - TWO(52)*TWO130;
++
++        /*
++         * base 2^48 -> base 2^32 with last reduction step
++         */
++        x1 =  (h1lo - c1lo) + c0lo;
++        x2 =  (h2lo - c2lo) + c1lo;
++        x3 =  (h3lo - c3lo) + c2lo;
++        x0 =  (h0lo - c0lo) + c3lo * (5.0/TWO130);
++
++        x1 += (h1hi - c1hi) + c0hi;
++        x2 += (h2hi - c2hi) + c1hi;
++        x3 += (h3hi - c3hi) + c2hi;
++        x0 += (h0hi - c0hi) + c3hi * (5.0/TWO130);
++
++#ifndef __clang__
++    fast_entry:
++#endif
++	/*
++	 * base 2^32 * base 2^16 = base 2^48
++	 */
++        h0lo = s3lo * x1 + s2lo * x2 + s1lo * x3 + r0lo * x0;
++        h1lo = r0lo * x1 + s3lo * x2 + s2lo * x3 + r1lo * x0;
++        h2lo = r1lo * x1 + r0lo * x2 + s3lo * x3 + r2lo * x0;
++        h3lo = r2lo * x1 + r1lo * x2 + r0lo * x3 + r3lo * x0;
++
++        h0hi = s3hi * x1 + s2hi * x2 + s1hi * x3 + r0hi * x0;
++        h1hi = r0hi * x1 + s3hi * x2 + s2hi * x3 + r1hi * x0;
++        h2hi = r1hi * x1 + r0hi * x2 + s3hi * x3 + r2hi * x0;
++        h3hi = r2hi * x1 + r1hi * x2 + r0hi * x3 + r3hi * x0;
++
++        inp += 16;
++        len -= 16;
++
++    } while (len >= 16);
++
++    /*
++     * carries that cross 32n-bit (and 130-bit) boundaries
++     */
++    c0lo = (h0lo + TWO(52)*TWO32)  - TWO(52)*TWO32;
++    c1lo = (h1lo + TWO(52)*TWO64)  - TWO(52)*TWO64;
++    c2lo = (h2lo + TWO(52)*TWO96)  - TWO(52)*TWO96;
++    c3lo = (h3lo + TWO(52)*TWO130) - TWO(52)*TWO130;
++
++    c0hi = (h0hi + TWO(52)*TWO32)  - TWO(52)*TWO32;
++    c1hi = (h1hi + TWO(52)*TWO64)  - TWO(52)*TWO64;
++    c2hi = (h2hi + TWO(52)*TWO96)  - TWO(52)*TWO96;
++    c3hi = (h3hi + TWO(52)*TWO130) - TWO(52)*TWO130;
++
++    /*
++     * base 2^48 -> base 2^32 with last reduction step
++     */
++    x1 =  (h1lo - c1lo) + c0lo;
++    x2 =  (h2lo - c2lo) + c1lo;
++    x3 =  (h3lo - c3lo) + c2lo;
++    x0 =  (h0lo - c0lo) + c3lo * (5.0/TWO130);
++
++    x1 += (h1hi - c1hi) + c0hi;
++    x2 += (h2hi - c2hi) + c1hi;
++    x3 += (h3hi - c3hi) + c2hi;
++    x0 += (h0hi - c0hi) + c3hi * (5.0/TWO130);
++
++    /*
++     * store base 2^32, with bias
++     */
++    st->h[1].d = x1 + TWO(52)*TWO32;
++    st->h[2].d = x2 + TWO(52)*TWO64;
++    st->h[3].d = x3 + TWO(52)*TWO96;
++    st->h[0].d = x0 + TWO(52)*TWO0;
++
++    /*
++     * restore original FPU control register
++     */
++#if defined(__x86_64__)
++    asm volatile ("ldmxcsr	%0"::"m"(mxcsr_orig));
++#elif defined(__PPC__)
++    asm volatile ("mtfsf	255,%0"::"f"(fpscr_orig));
++#elif defined(__s390x__)
++    asm volatile ("lfpc		%0"::"m"(fpc_orig));
++#elif defined(__sparc__)
++    asm volatile ("ldx		%0,%%fsr"::"m"(fsr_orig));
++#endif
++}
++
++void poly1305_emit(void *ctx, unsigned char mac[16], const u32 nonce[4])
++{
++    poly1305_internal *st = (poly1305_internal *) ctx;
++    u64 h0, h1, h2, h3, h4;
++    u32 g0, g1, g2, g3, g4;
++    u64 t;
++    u32 mask;
++
++    /*
++     * thanks to bias masking exponent gives integer result
++     */
++    h0 = st->h[0].u & 0x000fffffffffffffULL;
++    h1 = st->h[1].u & 0x000fffffffffffffULL;
++    h2 = st->h[2].u & 0x000fffffffffffffULL;
++    h3 = st->h[3].u & 0x000fffffffffffffULL;
++
++    /*
++     * can be partially reduced, so reduce...
++     */
++    h4 = h3>>32; h3 &= 0xffffffffU;
++    g4 = h4&-4;
++    h4 &= 3;
++    g4 += g4>>2;
++
++    h0 += g4;
++    h1 += h0>>32; h0 &= 0xffffffffU;
++    h2 += h1>>32; h1 &= 0xffffffffU;
++    h3 += h2>>32; h2 &= 0xffffffffU;
++
++    /* compute h + -p */
++    g0 = (u32)(t = h0 + 5);
++    g1 = (u32)(t = h1 + (t >> 32));
++    g2 = (u32)(t = h2 + (t >> 32));
++    g3 = (u32)(t = h3 + (t >> 32));
++    g4 = h4 + (u32)(t >> 32);
++
++    /* if there was carry, select g0-g3 */
++    mask = 0 - (g4 >> 2);
++    g0 &= mask;
++    g1 &= mask;
++    g2 &= mask;
++    g3 &= mask;
++    mask = ~mask;
++    g0 |= (h0 & mask);
++    g1 |= (h1 & mask);
++    g2 |= (h2 & mask);
++    g3 |= (h3 & mask);
++
++    /* mac = (h + nonce) % (2^128) */
++    g0 = (u32)(t = (u64)g0 + nonce[0]);
++    g1 = (u32)(t = (u64)g1 + (t >> 32) + nonce[1]);
++    g2 = (u32)(t = (u64)g2 + (t >> 32) + nonce[2]);
++    g3 = (u32)(t = (u64)g3 + (t >> 32) + nonce[3]);
++
++    U32TO8(mac + 0, g0);
++    U32TO8(mac + 4, g1);
++    U32TO8(mac + 8, g2);
++    U32TO8(mac + 12, g3);
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/ppc_arch.h b/CryptoPkg/Library/OpensslLib/openssl/crypto/ppc_arch.h
+new file mode 100644
+index 0000000..65cf96f
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/ppc_arch.h
+@@ -0,0 +1,26 @@
++/*
++ * Copyright 2014-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#ifndef HEADER_PPC_ARCH_H
++# define HEADER_PPC_ARCH_H
++
++extern unsigned int OPENSSL_ppccap_P;
++
++/*
++ * Flags' usage can appear ambiguous, because they are set rather
++ * to reflect OpenSSL performance preferences than actual processor
++ * capabilities.
++ */
++# define PPC_FPU64       (1<<0)
++# define PPC_ALTIVEC     (1<<1)
++# define PPC_CRYPTO207   (1<<2)
++# define PPC_FPU         (1<<3)
++# define PPC_MADD300     (1<<4)
++
++#endif
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/ppccap.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/ppccap.c
+new file mode 100644
+index 0000000..ef38b17
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/ppccap.c
+@@ -0,0 +1,317 @@
++/*
++ * Copyright 2009-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include 
++#include 
++#include 
++#include 
++#include 
++#if defined(__linux) || defined(_AIX)
++# include 
++#endif
++#if defined(_AIX53)     /* defined even on post-5.3 */
++# include 
++# if !defined(__power_set)
++#  define __power_set(a) (_system_configuration.implementation & (a))
++# endif
++#endif
++#include 
++#include 
++
++#include "ppc_arch.h"
++
++unsigned int OPENSSL_ppccap_P = 0;
++
++static sigset_t all_masked;
++
++#ifdef OPENSSL_BN_ASM_MONT
++int bn_mul_mont(BN_ULONG *rp, const BN_ULONG *ap, const BN_ULONG *bp,
++                const BN_ULONG *np, const BN_ULONG *n0, int num)
++{
++    int bn_mul_mont_fpu64(BN_ULONG *rp, const BN_ULONG *ap,
++                          const BN_ULONG *bp, const BN_ULONG *np,
++                          const BN_ULONG *n0, int num);
++    int bn_mul_mont_int(BN_ULONG *rp, const BN_ULONG *ap, const BN_ULONG *bp,
++                        const BN_ULONG *np, const BN_ULONG *n0, int num);
++
++    if (sizeof(size_t) == 4) {
++# if 1 || (defined(__APPLE__) && defined(__MACH__))
++        if (num >= 8 && (num & 3) == 0 && (OPENSSL_ppccap_P & PPC_FPU64))
++            return bn_mul_mont_fpu64(rp, ap, bp, np, n0, num);
++# else
++        /*
++         * boundary of 32 was experimentally determined on Linux 2.6.22,
++         * might have to be adjusted on AIX...
++         */
++        if (num >= 32 && (num & 3) == 0 && (OPENSSL_ppccap_P & PPC_FPU64)) {
++            sigset_t oset;
++            int ret;
++
++            sigprocmask(SIG_SETMASK, &all_masked, &oset);
++            ret = bn_mul_mont_fpu64(rp, ap, bp, np, n0, num);
++            sigprocmask(SIG_SETMASK, &oset, NULL);
++
++            return ret;
++        }
++# endif
++    } else if ((OPENSSL_ppccap_P & PPC_FPU64))
++        /*
++         * this is a "must" on POWER6, but run-time detection is not
++         * implemented yet...
++         */
++        return bn_mul_mont_fpu64(rp, ap, bp, np, n0, num);
++
++    return bn_mul_mont_int(rp, ap, bp, np, n0, num);
++}
++#endif
++
++void sha256_block_p8(void *ctx, const void *inp, size_t len);
++void sha256_block_ppc(void *ctx, const void *inp, size_t len);
++void sha256_block_data_order(void *ctx, const void *inp, size_t len)
++{
++    OPENSSL_ppccap_P & PPC_CRYPTO207 ? sha256_block_p8(ctx, inp, len) :
++        sha256_block_ppc(ctx, inp, len);
++}
++
++void sha512_block_p8(void *ctx, const void *inp, size_t len);
++void sha512_block_ppc(void *ctx, const void *inp, size_t len);
++void sha512_block_data_order(void *ctx, const void *inp, size_t len)
++{
++    OPENSSL_ppccap_P & PPC_CRYPTO207 ? sha512_block_p8(ctx, inp, len) :
++        sha512_block_ppc(ctx, inp, len);
++}
++
++#ifndef OPENSSL_NO_CHACHA
++void ChaCha20_ctr32_int(unsigned char *out, const unsigned char *inp,
++                        size_t len, const unsigned int key[8],
++                        const unsigned int counter[4]);
++void ChaCha20_ctr32_vmx(unsigned char *out, const unsigned char *inp,
++                        size_t len, const unsigned int key[8],
++                        const unsigned int counter[4]);
++void ChaCha20_ctr32(unsigned char *out, const unsigned char *inp,
++                    size_t len, const unsigned int key[8],
++                    const unsigned int counter[4])
++{
++    OPENSSL_ppccap_P & PPC_ALTIVEC
++        ? ChaCha20_ctr32_vmx(out, inp, len, key, counter)
++        : ChaCha20_ctr32_int(out, inp, len, key, counter);
++}
++#endif
++
++#ifndef OPENSSL_NO_POLY1305
++void poly1305_init_int(void *ctx, const unsigned char key[16]);
++void poly1305_blocks(void *ctx, const unsigned char *inp, size_t len,
++                         unsigned int padbit);
++void poly1305_emit(void *ctx, unsigned char mac[16],
++                       const unsigned int nonce[4]);
++void poly1305_init_fpu(void *ctx, const unsigned char key[16]);
++void poly1305_blocks_fpu(void *ctx, const unsigned char *inp, size_t len,
++                         unsigned int padbit);
++void poly1305_emit_fpu(void *ctx, unsigned char mac[16],
++                       const unsigned int nonce[4]);
++int poly1305_init(void *ctx, const unsigned char key[16], void *func[2])
++{
++    if (sizeof(size_t) == 4 && (OPENSSL_ppccap_P & PPC_FPU)) {
++        poly1305_init_fpu(ctx, key);
++        func[0] = poly1305_blocks_fpu;
++        func[1] = poly1305_emit_fpu;
++    } else {
++        poly1305_init_int(ctx, key);
++        func[0] = poly1305_blocks;
++        func[1] = poly1305_emit;
++    }
++    return 1;
++}
++#endif
++
++static sigjmp_buf ill_jmp;
++static void ill_handler(int sig)
++{
++    siglongjmp(ill_jmp, sig);
++}
++
++void OPENSSL_fpu_probe(void);
++void OPENSSL_ppc64_probe(void);
++void OPENSSL_altivec_probe(void);
++void OPENSSL_crypto207_probe(void);
++void OPENSSL_madd300_probe(void);
++
++/*
++ * Use a weak reference to getauxval() so we can use it if it is available
++ * but don't break the build if it is not. Note that this is *link-time*
++ * feature detection, not *run-time*. In other words if we link with
++ * symbol present, it's expected to be present even at run-time.
++ */
++#if defined(__GNUC__) && __GNUC__>=2 && defined(__ELF__)
++extern unsigned long getauxval(unsigned long type) __attribute__ ((weak));
++#else
++static unsigned long (*getauxval) (unsigned long) = NULL;
++#endif
++
++/* I wish  was universally available */
++#define HWCAP                   16      /* AT_HWCAP */
++#define HWCAP_PPC64             (1U << 30)
++#define HWCAP_ALTIVEC           (1U << 28)
++#define HWCAP_FPU               (1U << 27)
++#define HWCAP_POWER6_EXT        (1U << 9)
++#define HWCAP_VSX               (1U << 7)
++
++#define HWCAP2                  26      /* AT_HWCAP2 */
++#define HWCAP_VEC_CRYPTO        (1U << 25)
++#define HWCAP_ARCH_3_00         (1U << 23)
++
++# if defined(__GNUC__) && __GNUC__>=2
++__attribute__ ((constructor))
++# endif
++void OPENSSL_cpuid_setup(void)
++{
++    char *e;
++    struct sigaction ill_oact, ill_act;
++    sigset_t oset;
++    static int trigger = 0;
++
++    if (trigger)
++        return;
++    trigger = 1;
++
++    if ((e = getenv("OPENSSL_ppccap"))) {
++        OPENSSL_ppccap_P = strtoul(e, NULL, 0);
++        return;
++    }
++
++    OPENSSL_ppccap_P = 0;
++
++#if defined(_AIX)
++    OPENSSL_ppccap_P |= PPC_FPU;
++
++    if (sizeof(size_t) == 4) {
++        struct utsname uts;
++# if defined(_SC_AIX_KERNEL_BITMODE)
++        if (sysconf(_SC_AIX_KERNEL_BITMODE) != 64)
++            return;
++# endif
++        if (uname(&uts) != 0 || atoi(uts.version) < 6)
++            return;
++    }
++
++# if defined(__power_set)
++    /*
++     * Value used in __power_set is a single-bit 1<
++#include 
++
++#include "e_os.h"
++
++#if !(defined(OPENSSL_SYS_WIN32) || defined(OPENSSL_SYS_VXWORKS) || defined(OPENSSL_SYS_DSPBIOS))
++# include 
++#endif
++#if defined(OPENSSL_SYS_VXWORKS)
++# include 
++#endif
++
++#include 
++#include 
++#include 
++#include 
++#include "rand_lcl.h"
++
++#include 
++
++#include 
++
++#ifdef OPENSSL_FIPS
++# include 
++#endif
++
++#ifdef BN_DEBUG
++# define PREDICT
++#endif
++
++/* #define PREDICT      1 */
++
++#define STATE_SIZE      1023
++static size_t state_num = 0, state_index = 0;
++static unsigned char state[STATE_SIZE + MD_DIGEST_LENGTH];
++static unsigned char md[MD_DIGEST_LENGTH];
++static long md_count[2] = { 0, 0 };
++
++static double entropy = 0;
++static int initialized = 0;
++
++static CRYPTO_RWLOCK *rand_lock = NULL;
++static CRYPTO_RWLOCK *rand_tmp_lock = NULL;
++static CRYPTO_ONCE rand_lock_init = CRYPTO_ONCE_STATIC_INIT;
++
++/* May be set only when a thread holds rand_lock (to prevent double locking) */
++static unsigned int crypto_lock_rand = 0;
++/* access to locking_threadid is synchronized by rand_tmp_lock */
++/* valid iff crypto_lock_rand is set */
++static CRYPTO_THREAD_ID locking_threadid;
++
++#ifdef PREDICT
++int rand_predictable = 0;
++#endif
++
++static int rand_hw_seed(EVP_MD_CTX *ctx);
++
++static void rand_cleanup(void);
++static int rand_seed(const void *buf, int num);
++static int rand_add(const void *buf, int num, double add_entropy);
++static int rand_bytes(unsigned char *buf, int num, int pseudo);
++static int rand_nopseudo_bytes(unsigned char *buf, int num);
++#if OPENSSL_API_COMPAT < 0x10100000L
++static int rand_pseudo_bytes(unsigned char *buf, int num);
++#endif
++static int rand_status(void);
++
++static RAND_METHOD rand_meth = {
++    rand_seed,
++    rand_nopseudo_bytes,
++    rand_cleanup,
++    rand_add,
++#if OPENSSL_API_COMPAT < 0x10100000L
++    rand_pseudo_bytes,
++#else
++    NULL,
++#endif
++    rand_status
++};
++
++DEFINE_RUN_ONCE_STATIC(do_rand_lock_init)
++{
++    OPENSSL_init_crypto(0, NULL);
++    rand_lock = CRYPTO_THREAD_lock_new();
++    rand_tmp_lock = CRYPTO_THREAD_lock_new();
++    return rand_lock != NULL && rand_tmp_lock != NULL;
++}
++
++RAND_METHOD *RAND_OpenSSL(void)
++{
++    return (&rand_meth);
++}
++
++static void rand_cleanup(void)
++{
++    OPENSSL_cleanse(state, sizeof(state));
++    state_num = 0;
++    state_index = 0;
++    OPENSSL_cleanse(md, MD_DIGEST_LENGTH);
++    md_count[0] = 0;
++    md_count[1] = 0;
++    entropy = 0;
++    initialized = 0;
++    CRYPTO_THREAD_lock_free(rand_lock);
++    CRYPTO_THREAD_lock_free(rand_tmp_lock);
++}
++
++static int rand_add(const void *buf, int num, double add)
++{
++    int i, j, k, st_idx;
++    long md_c[2];
++    unsigned char local_md[MD_DIGEST_LENGTH];
++    EVP_MD_CTX *m;
++    int do_not_lock;
++    int rv = 0;
++
++    if (!num)
++        return 1;
++
++    /*
++     * (Based on the rand(3) manpage)
++     *
++     * The input is chopped up into units of 20 bytes (or less for
++     * the last block).  Each of these blocks is run through the hash
++     * function as follows:  The data passed to the hash function
++     * is the current 'md', the same number of bytes from the 'state'
++     * (the location determined by in incremented looping index) as
++     * the current 'block', the new key data 'block', and 'count'
++     * (which is incremented after each use).
++     * The result of this is kept in 'md' and also xored into the
++     * 'state' at the same locations that were used as input into the
++     * hash function.
++     */
++
++    m = EVP_MD_CTX_new();
++    if (m == NULL)
++        goto err;
++
++    if (!RUN_ONCE(&rand_lock_init, do_rand_lock_init))
++        goto err;
++
++    /* check if we already have the lock */
++    if (crypto_lock_rand) {
++        CRYPTO_THREAD_ID cur = CRYPTO_THREAD_get_current_id();
++        CRYPTO_THREAD_read_lock(rand_tmp_lock);
++        do_not_lock = CRYPTO_THREAD_compare_id(locking_threadid, cur);
++        CRYPTO_THREAD_unlock(rand_tmp_lock);
++    } else
++        do_not_lock = 0;
++
++    if (!do_not_lock)
++        CRYPTO_THREAD_write_lock(rand_lock);
++    st_idx = state_index;
++
++    /*
++     * use our own copies of the counters so that even if a concurrent thread
++     * seeds with exactly the same data and uses the same subarray there's
++     * _some_ difference
++     */
++    md_c[0] = md_count[0];
++    md_c[1] = md_count[1];
++
++    memcpy(local_md, md, sizeof md);
++
++    /* state_index <= state_num <= STATE_SIZE */
++    state_index += num;
++    if (state_index >= STATE_SIZE) {
++        state_index %= STATE_SIZE;
++        state_num = STATE_SIZE;
++    } else if (state_num < STATE_SIZE) {
++        if (state_index > state_num)
++            state_num = state_index;
++    }
++    /* state_index <= state_num <= STATE_SIZE */
++
++    /*
++     * state[st_idx], ..., state[(st_idx + num - 1) % STATE_SIZE] are what we
++     * will use now, but other threads may use them as well
++     */
++
++    md_count[1] += (num / MD_DIGEST_LENGTH) + (num % MD_DIGEST_LENGTH > 0);
++
++    if (!do_not_lock)
++        CRYPTO_THREAD_unlock(rand_lock);
++
++    for (i = 0; i < num; i += MD_DIGEST_LENGTH) {
++        j = (num - i);
++        j = (j > MD_DIGEST_LENGTH) ? MD_DIGEST_LENGTH : j;
++
++        if (!MD_Init(m))
++            goto err;
++        if (!MD_Update(m, local_md, MD_DIGEST_LENGTH))
++            goto err;
++        k = (st_idx + j) - STATE_SIZE;
++        if (k > 0) {
++            if (!MD_Update(m, &(state[st_idx]), j - k))
++                goto err;
++            if (!MD_Update(m, &(state[0]), k))
++                goto err;
++        } else if (!MD_Update(m, &(state[st_idx]), j))
++            goto err;
++
++        /* DO NOT REMOVE THE FOLLOWING CALL TO MD_Update()! */
++        if (!MD_Update(m, buf, j))
++            goto err;
++        /*
++         * We know that line may cause programs such as purify and valgrind
++         * to complain about use of uninitialized data.  The problem is not,
++         * it's with the caller.  Removing that line will make sure you get
++         * really bad randomness and thereby other problems such as very
++         * insecure keys.
++         */
++
++        if (!MD_Update(m, (unsigned char *)&(md_c[0]), sizeof(md_c)))
++            goto err;
++        if (!MD_Final(m, local_md))
++            goto err;
++        md_c[1]++;
++
++        buf = (const char *)buf + j;
++
++        for (k = 0; k < j; k++) {
++            /*
++             * Parallel threads may interfere with this, but always each byte
++             * of the new state is the XOR of some previous value of its and
++             * local_md (intermediate values may be lost). Alway using locking
++             * could hurt performance more than necessary given that
++             * conflicts occur only when the total seeding is longer than the
++             * random state.
++             */
++            state[st_idx++] ^= local_md[k];
++            if (st_idx >= STATE_SIZE)
++                st_idx = 0;
++        }
++    }
++
++    if (!do_not_lock)
++        CRYPTO_THREAD_write_lock(rand_lock);
++    /*
++     * Don't just copy back local_md into md -- this could mean that other
++     * thread's seeding remains without effect (except for the incremented
++     * counter).  By XORing it we keep at least as much entropy as fits into
++     * md.
++     */
++    for (k = 0; k < (int)sizeof(md); k++) {
++        md[k] ^= local_md[k];
++    }
++    if (entropy < ENTROPY_NEEDED) /* stop counting when we have enough */
++        entropy += add;
++    if (!do_not_lock)
++        CRYPTO_THREAD_unlock(rand_lock);
++
++    rv = 1;
++ err:
++    EVP_MD_CTX_free(m);
++    return rv;
++}
++
++static int rand_seed(const void *buf, int num)
++{
++    return rand_add(buf, num, (double)num);
++}
++
++static int rand_bytes(unsigned char *buf, int num, int pseudo)
++{
++    static volatile int stirred_pool = 0;
++    int i, j, k;
++    size_t num_ceil, st_idx, st_num;
++    int ok;
++    long md_c[2];
++    unsigned char local_md[MD_DIGEST_LENGTH];
++    EVP_MD_CTX *m;
++#ifndef GETPID_IS_MEANINGLESS
++    pid_t curr_pid = getpid();
++#endif
++    time_t curr_time = time(NULL);
++    int do_stir_pool = 0;
++/* time value for various platforms */
++#ifdef OPENSSL_SYS_WIN32
++    FILETIME tv;
++# ifdef _WIN32_WCE
++    SYSTEMTIME t;
++    GetSystemTime(&t);
++    SystemTimeToFileTime(&t, &tv);
++# else
++    GetSystemTimeAsFileTime(&tv);
++# endif
++#elif defined(OPENSSL_SYS_VXWORKS)
++    struct timespec tv;
++    clock_gettime(CLOCK_REALTIME, &ts);
++#elif defined(OPENSSL_SYS_DSPBIOS)
++    unsigned long long tv, OPENSSL_rdtsc();
++    tv = OPENSSL_rdtsc();
++#else
++    struct timeval tv;
++    gettimeofday(&tv, NULL);
++#endif
++
++#ifdef PREDICT
++    if (rand_predictable) {
++        static unsigned char val = 0;
++
++        for (i = 0; i < num; i++)
++            buf[i] = val++;
++        return (1);
++    }
++#endif
++
++    if (num <= 0)
++        return 1;
++
++    m = EVP_MD_CTX_new();
++    if (m == NULL)
++        goto err_mem;
++
++    /* round upwards to multiple of MD_DIGEST_LENGTH/2 */
++    num_ceil =
++        (1 + (num - 1) / (MD_DIGEST_LENGTH / 2)) * (MD_DIGEST_LENGTH / 2);
++
++    /*
++     * (Based on the rand(3) manpage:)
++     *
++     * For each group of 10 bytes (or less), we do the following:
++     *
++     * Input into the hash function the local 'md' (which is initialized from
++     * the global 'md' before any bytes are generated), the bytes that are to
++     * be overwritten by the random bytes, and bytes from the 'state'
++     * (incrementing looping index). From this digest output (which is kept
++     * in 'md'), the top (up to) 10 bytes are returned to the caller and the
++     * bottom 10 bytes are xored into the 'state'.
++     *
++     * Finally, after we have finished 'num' random bytes for the
++     * caller, 'count' (which is incremented) and the local and global 'md'
++     * are fed into the hash function and the results are kept in the
++     * global 'md'.
++     */
++
++    if (!RUN_ONCE(&rand_lock_init, do_rand_lock_init))
++        goto err_mem;
++
++    CRYPTO_THREAD_write_lock(rand_lock);
++    /*
++     * We could end up in an async engine while holding this lock so ensure
++     * we don't pause and cause a deadlock
++     */
++    ASYNC_block_pause();
++
++    /* prevent rand_bytes() from trying to obtain the lock again */
++    CRYPTO_THREAD_write_lock(rand_tmp_lock);
++    locking_threadid = CRYPTO_THREAD_get_current_id();
++    CRYPTO_THREAD_unlock(rand_tmp_lock);
++    crypto_lock_rand = 1;
++
++    if (!initialized) {
++        RAND_poll();
++        initialized = 1;
++    }
++
++    if (!stirred_pool)
++        do_stir_pool = 1;
++
++    ok = (entropy >= ENTROPY_NEEDED);
++    if (!ok) {
++        /*
++         * If the PRNG state is not yet unpredictable, then seeing the PRNG
++         * output may help attackers to determine the new state; thus we have
++         * to decrease the entropy estimate. Once we've had enough initial
++         * seeding we don't bother to adjust the entropy count, though,
++         * because we're not ambitious to provide *information-theoretic*
++         * randomness. NOTE: This approach fails if the program forks before
++         * we have enough entropy. Entropy should be collected in a separate
++         * input pool and be transferred to the output pool only when the
++         * entropy limit has been reached.
++         */
++        entropy -= num;
++        if (entropy < 0)
++            entropy = 0;
++    }
++
++    if (do_stir_pool) {
++        /*
++         * In the output function only half of 'md' remains secret, so we
++         * better make sure that the required entropy gets 'evenly
++         * distributed' through 'state', our randomness pool. The input
++         * function (rand_add) chains all of 'md', which makes it more
++         * suitable for this purpose.
++         */
++
++        int n = STATE_SIZE;     /* so that the complete pool gets accessed */
++        while (n > 0) {
++#if MD_DIGEST_LENGTH > 20
++# error "Please adjust DUMMY_SEED."
++#endif
++#define DUMMY_SEED "...................." /* at least MD_DIGEST_LENGTH */
++            /*
++             * Note that the seed does not matter, it's just that
++             * rand_add expects to have something to hash.
++             */
++            rand_add(DUMMY_SEED, MD_DIGEST_LENGTH, 0.0);
++            n -= MD_DIGEST_LENGTH;
++        }
++        if (ok)
++            stirred_pool = 1;
++    }
++
++    st_idx = state_index;
++    st_num = state_num;
++    md_c[0] = md_count[0];
++    md_c[1] = md_count[1];
++    memcpy(local_md, md, sizeof md);
++
++    state_index += num_ceil;
++    if (state_index > state_num)
++        state_index %= state_num;
++
++    /*
++     * state[st_idx], ..., state[(st_idx + num_ceil - 1) % st_num] are now
++     * ours (but other threads may use them too)
++     */
++
++    md_count[0] += 1;
++
++    /* before unlocking, we must clear 'crypto_lock_rand' */
++    crypto_lock_rand = 0;
++    ASYNC_unblock_pause();
++    CRYPTO_THREAD_unlock(rand_lock);
++
++    while (num > 0) {
++        /* num_ceil -= MD_DIGEST_LENGTH/2 */
++        j = (num >= MD_DIGEST_LENGTH / 2) ? MD_DIGEST_LENGTH / 2 : num;
++        num -= j;
++        if (!MD_Init(m))
++            goto err;
++#ifndef GETPID_IS_MEANINGLESS
++        if (curr_pid) {         /* just in the first iteration to save time */
++            if (!MD_Update(m, (unsigned char *)&curr_pid, sizeof curr_pid))
++                goto err;
++            curr_pid = 0;
++        }
++#endif
++        if (curr_time) {        /* just in the first iteration to save time */
++            if (!MD_Update(m, (unsigned char *)&curr_time, sizeof curr_time))
++                goto err;
++            if (!MD_Update(m, (unsigned char *)&tv, sizeof tv))
++                goto err;
++            curr_time = 0;
++            if (!rand_hw_seed(m))
++                goto err;
++        }
++        if (!MD_Update(m, local_md, MD_DIGEST_LENGTH))
++            goto err;
++        if (!MD_Update(m, (unsigned char *)&(md_c[0]), sizeof(md_c)))
++            goto err;
++
++        k = (st_idx + MD_DIGEST_LENGTH / 2) - st_num;
++        if (k > 0) {
++            if (!MD_Update(m, &(state[st_idx]), MD_DIGEST_LENGTH / 2 - k))
++                goto err;
++            if (!MD_Update(m, &(state[0]), k))
++                goto err;
++        } else if (!MD_Update(m, &(state[st_idx]), MD_DIGEST_LENGTH / 2))
++            goto err;
++        if (!MD_Final(m, local_md))
++            goto err;
++
++        for (i = 0; i < MD_DIGEST_LENGTH / 2; i++) {
++            /* may compete with other threads */
++            state[st_idx++] ^= local_md[i];
++            if (st_idx >= st_num)
++                st_idx = 0;
++            if (i < j)
++                *(buf++) = local_md[i + MD_DIGEST_LENGTH / 2];
++        }
++    }
++
++    if (!MD_Init(m)
++        || !MD_Update(m, (unsigned char *)&(md_c[0]), sizeof(md_c))
++        || !MD_Update(m, local_md, MD_DIGEST_LENGTH))
++        goto err;
++    CRYPTO_THREAD_write_lock(rand_lock);
++    /*
++     * Prevent deadlocks if we end up in an async engine
++     */
++    ASYNC_block_pause();
++    if (!MD_Update(m, md, MD_DIGEST_LENGTH) || !MD_Final(m, md)) {
++        CRYPTO_THREAD_unlock(rand_lock);
++        goto err;
++    }
++    ASYNC_unblock_pause();
++    CRYPTO_THREAD_unlock(rand_lock);
++
++    EVP_MD_CTX_free(m);
++    if (ok)
++        return (1);
++    else if (pseudo)
++        return 0;
++    else {
++        RANDerr(RAND_F_RAND_BYTES, RAND_R_PRNG_NOT_SEEDED);
++        ERR_add_error_data(1, "You need to read the OpenSSL FAQ, "
++                           "https://www.openssl.org/docs/faq.html");
++        return (0);
++    }
++ err:
++    RANDerr(RAND_F_RAND_BYTES, ERR_R_EVP_LIB);
++    EVP_MD_CTX_free(m);
++    return 0;
++ err_mem:
++    RANDerr(RAND_F_RAND_BYTES, ERR_R_MALLOC_FAILURE);
++    EVP_MD_CTX_free(m);
++    return 0;
++
++}
++
++static int rand_nopseudo_bytes(unsigned char *buf, int num)
++{
++    return rand_bytes(buf, num, 0);
++}
++
++#if OPENSSL_API_COMPAT < 0x10100000L
++/*
++ * pseudo-random bytes that are guaranteed to be unique but not unpredictable
++ */
++static int rand_pseudo_bytes(unsigned char *buf, int num)
++{
++    return rand_bytes(buf, num, 1);
++}
++#endif
++
++static int rand_status(void)
++{
++    CRYPTO_THREAD_ID cur;
++    int ret;
++    int do_not_lock;
++
++    if (!RUN_ONCE(&rand_lock_init, do_rand_lock_init))
++        return 0;
++
++    cur = CRYPTO_THREAD_get_current_id();
++    /*
++     * check if we already have the lock (could happen if a RAND_poll()
++     * implementation calls RAND_status())
++     */
++    if (crypto_lock_rand) {
++        CRYPTO_THREAD_read_lock(rand_tmp_lock);
++        do_not_lock = CRYPTO_THREAD_compare_id(locking_threadid, cur);
++        CRYPTO_THREAD_unlock(rand_tmp_lock);
++    } else
++        do_not_lock = 0;
++
++    if (!do_not_lock) {
++        CRYPTO_THREAD_write_lock(rand_lock);
++        /*
++         * Prevent deadlocks in case we end up in an async engine
++         */
++        ASYNC_block_pause();
++
++        /*
++         * prevent rand_bytes() from trying to obtain the lock again
++         */
++        CRYPTO_THREAD_write_lock(rand_tmp_lock);
++        locking_threadid = cur;
++        CRYPTO_THREAD_unlock(rand_tmp_lock);
++        crypto_lock_rand = 1;
++    }
++
++    if (!initialized) {
++        RAND_poll();
++        initialized = 1;
++    }
++
++    ret = entropy >= ENTROPY_NEEDED;
++
++    if (!do_not_lock) {
++        /* before unlocking, we must clear 'crypto_lock_rand' */
++        crypto_lock_rand = 0;
++
++        ASYNC_unblock_pause();
++        CRYPTO_THREAD_unlock(rand_lock);
++    }
++
++    return ret;
++}
++
++/*
++ * rand_hw_seed: get seed data from any available hardware RNG. only
++ * currently supports rdrand.
++ */
++
++/* Adapted from eng_rdrand.c */
++
++#if (defined(__i386)   || defined(__i386__)   || defined(_M_IX86) || \
++     defined(__x86_64) || defined(__x86_64__) || \
++     defined(_M_AMD64) || defined (_M_X64)) && defined(OPENSSL_CPUID_OBJ) \
++     && !defined(OPENSSL_NO_RDRAND)
++
++# define RDRAND_CALLS    4
++
++size_t OPENSSL_ia32_rdrand(void);
++extern unsigned int OPENSSL_ia32cap_P[];
++
++static int rand_hw_seed(EVP_MD_CTX *ctx)
++{
++    int i;
++    if (!(OPENSSL_ia32cap_P[1] & (1 << (62 - 32))))
++        return 1;
++    for (i = 0; i < RDRAND_CALLS; i++) {
++        size_t rnd;
++        rnd = OPENSSL_ia32_rdrand();
++        if (rnd == 0)
++            return 1;
++        if (!MD_Update(ctx, (unsigned char *)&rnd, sizeof(size_t)))
++            return 0;
++    }
++    return 1;
++}
++
++/* XOR an existing buffer with random data */
++
++void rand_hw_xor(unsigned char *buf, size_t num)
++{
++    size_t rnd;
++    if (!(OPENSSL_ia32cap_P[1] & (1 << (62 - 32))))
++        return;
++    while (num >= sizeof(size_t)) {
++        rnd = OPENSSL_ia32_rdrand();
++        if (rnd == 0)
++            return;
++        *((size_t *)buf) ^= rnd;
++        buf += sizeof(size_t);
++        num -= sizeof(size_t);
++    }
++    if (num) {
++        rnd = OPENSSL_ia32_rdrand();
++        if (rnd == 0)
++            return;
++        while (num) {
++            *buf ^= rnd & 0xff;
++            rnd >>= 8;
++            buf++;
++            num--;
++        }
++    }
++}
++
++#else
++
++static int rand_hw_seed(EVP_MD_CTX *ctx)
++{
++    return 1;
++}
++
++void rand_hw_xor(unsigned char *buf, size_t num)
++{
++    return;
++}
++
++#endif
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/rand/rand_egd.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/rand/rand_egd.c
+new file mode 100644
+index 0000000..dd58b21
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/rand/rand_egd.c
+@@ -0,0 +1,249 @@
++/*
++ * Copyright 2000-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#ifdef OPENSSL_NO_EGD
++NON_EMPTY_TRANSLATION_UNIT
++#else
++
++# include 
++# include 
++# include 
++
++/*-
++ * Query the EGD .
++ *
++ * This module supplies three routines:
++ *
++ * RAND_query_egd_bytes(path, buf, bytes)
++ *   will actually query "bytes" bytes of entropy form the egd-socket located
++ *   at path and will write them to buf (if supplied) or will directly feed
++ *   it to RAND_seed() if buf==NULL.
++ *   The number of bytes is not limited by the maximum chunk size of EGD,
++ *   which is 255 bytes. If more than 255 bytes are wanted, several chunks
++ *   of entropy bytes are requested. The connection is left open until the
++ *   query is competed.
++ *   RAND_query_egd_bytes() returns with
++ *     -1  if an error occurred during connection or communication.
++ *     num the number of bytes read from the EGD socket. This number is either
++ *         the number of bytes requested or smaller, if the EGD pool is
++ *         drained and the daemon signals that the pool is empty.
++ *   This routine does not touch any RAND_status(). This is necessary, since
++ *   PRNG functions may call it during initialization.
++ *
++ * RAND_egd_bytes(path, bytes) will query "bytes" bytes and have them
++ *   used to seed the PRNG.
++ *   RAND_egd_bytes() is a wrapper for RAND_query_egd_bytes() with buf=NULL.
++ *   Unlike RAND_query_egd_bytes(), RAND_status() is used to test the
++ *   seed status so that the return value can reflect the seed state:
++ *     -1  if an error occurred during connection or communication _or_
++ *         if the PRNG has still not received the required seeding.
++ *     num the number of bytes read from the EGD socket. This number is either
++ *         the number of bytes requested or smaller, if the EGD pool is
++ *         drained and the daemon signals that the pool is empty.
++ *
++ * RAND_egd(path) will query 255 bytes and use the bytes retrieved to seed
++ *   the PRNG.
++ *   RAND_egd() is a wrapper for RAND_egd_bytes() with numbytes=255.
++ */
++
++# if defined(OPENSSL_SYS_WIN32) || defined(OPENSSL_SYS_VMS) || defined(OPENSSL_SYS_MSDOS) || defined(OPENSSL_SYS_VXWORKS) || defined(OPENSSL_SYS_VOS) || defined(OPENSSL_SYS_UEFI)
++int RAND_query_egd_bytes(const char *path, unsigned char *buf, int bytes)
++{
++    return (-1);
++}
++
++int RAND_egd(const char *path)
++{
++    return (-1);
++}
++
++int RAND_egd_bytes(const char *path, int bytes)
++{
++    return (-1);
++}
++# else
++#  include 
++#  include OPENSSL_UNISTD
++#  include 
++#  include 
++#  include 
++#  ifndef NO_SYS_UN_H
++#   ifdef OPENSSL_SYS_VXWORKS
++#    include 
++#   else
++#    include 
++#   endif
++#  else
++struct sockaddr_un {
++    short sun_family;           /* AF_UNIX */
++    char sun_path[108];         /* path name (gag) */
++};
++#  endif                         /* NO_SYS_UN_H */
++#  include 
++#  include 
++
++int RAND_query_egd_bytes(const char *path, unsigned char *buf, int bytes)
++{
++    int ret = 0;
++    struct sockaddr_un addr;
++    int len, num, numbytes;
++    int fd = -1;
++    int success;
++    unsigned char egdbuf[2], tempbuf[255], *retrievebuf;
++
++    memset(&addr, 0, sizeof(addr));
++    addr.sun_family = AF_UNIX;
++    if (strlen(path) >= sizeof(addr.sun_path))
++        return (-1);
++    OPENSSL_strlcpy(addr.sun_path, path, sizeof addr.sun_path);
++    len = offsetof(struct sockaddr_un, sun_path) + strlen(path);
++    fd = socket(AF_UNIX, SOCK_STREAM, 0);
++    if (fd == -1)
++        return (-1);
++    success = 0;
++    while (!success) {
++        if (connect(fd, (struct sockaddr *)&addr, len) == 0)
++            success = 1;
++        else {
++            switch (errno) {
++#  ifdef EINTR
++            case EINTR:
++#  endif
++#  ifdef EAGAIN
++            case EAGAIN:
++#  endif
++#  ifdef EINPROGRESS
++            case EINPROGRESS:
++#  endif
++#  ifdef EALREADY
++            case EALREADY:
++#  endif
++                /* No error, try again */
++                break;
++#  ifdef EISCONN
++            case EISCONN:
++                success = 1;
++                break;
++#  endif
++            default:
++                ret = -1;
++                goto err;       /* failure */
++            }
++        }
++    }
++
++    while (bytes > 0) {
++        egdbuf[0] = 1;
++        egdbuf[1] = bytes < 255 ? bytes : 255;
++        numbytes = 0;
++        while (numbytes != 2) {
++            num = write(fd, egdbuf + numbytes, 2 - numbytes);
++            if (num >= 0)
++                numbytes += num;
++            else {
++                switch (errno) {
++#  ifdef EINTR
++                case EINTR:
++#  endif
++#  ifdef EAGAIN
++                case EAGAIN:
++#  endif
++                    /* No error, try again */
++                    break;
++                default:
++                    ret = -1;
++                    goto err;   /* failure */
++                }
++            }
++        }
++        numbytes = 0;
++        while (numbytes != 1) {
++            num = read(fd, egdbuf, 1);
++            if (num == 0)
++                goto err;       /* descriptor closed */
++            else if (num > 0)
++                numbytes += num;
++            else {
++                switch (errno) {
++#  ifdef EINTR
++                case EINTR:
++#  endif
++#  ifdef EAGAIN
++                case EAGAIN:
++#  endif
++                    /* No error, try again */
++                    break;
++                default:
++                    ret = -1;
++                    goto err;   /* failure */
++                }
++            }
++        }
++        if (egdbuf[0] == 0)
++            goto err;
++        if (buf)
++            retrievebuf = buf + ret;
++        else
++            retrievebuf = tempbuf;
++        numbytes = 0;
++        while (numbytes != egdbuf[0]) {
++            num = read(fd, retrievebuf + numbytes, egdbuf[0] - numbytes);
++            if (num == 0)
++                goto err;       /* descriptor closed */
++            else if (num > 0)
++                numbytes += num;
++            else {
++                switch (errno) {
++#  ifdef EINTR
++                case EINTR:
++#  endif
++#  ifdef EAGAIN
++                case EAGAIN:
++#  endif
++                    /* No error, try again */
++                    break;
++                default:
++                    ret = -1;
++                    goto err;   /* failure */
++                }
++            }
++        }
++        ret += egdbuf[0];
++        bytes -= egdbuf[0];
++        if (!buf)
++            RAND_seed(tempbuf, egdbuf[0]);
++    }
++ err:
++    if (fd != -1)
++        close(fd);
++    return (ret);
++}
++
++int RAND_egd_bytes(const char *path, int bytes)
++{
++    int num, ret = -1;
++
++    num = RAND_query_egd_bytes(path, NULL, bytes);
++    if (num < 0)
++        goto err;
++    if (RAND_status() == 1)
++        ret = num;
++ err:
++    return (ret);
++}
++
++int RAND_egd(const char *path)
++{
++    return (RAND_egd_bytes(path, 255));
++}
++
++# endif
++
++#endif
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/rand/rand_err.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/rand/rand_err.c
+new file mode 100644
+index 0000000..5543126
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/rand/rand_err.c
+@@ -0,0 +1,43 @@
++/*
++ * Generated by util/mkerr.pl DO NOT EDIT
++ * Copyright 1995-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include 
++#include 
++
++/* BEGIN ERROR CODES */
++#ifndef OPENSSL_NO_ERR
++
++# define ERR_FUNC(func) ERR_PACK(ERR_LIB_RAND,func,0)
++# define ERR_REASON(reason) ERR_PACK(ERR_LIB_RAND,0,reason)
++
++static ERR_STRING_DATA RAND_str_functs[] = {
++    {ERR_FUNC(RAND_F_RAND_BYTES), "RAND_bytes"},
++    {0, NULL}
++};
++
++static ERR_STRING_DATA RAND_str_reasons[] = {
++    {ERR_REASON(RAND_R_PRNG_NOT_SEEDED), "PRNG not seeded"},
++    {0, NULL}
++};
++
++#endif
++
++int ERR_load_RAND_strings(void)
++{
++#ifndef OPENSSL_NO_ERR
++
++    if (ERR_func_error_string(RAND_str_functs[0].error) == NULL) {
++        ERR_load_strings(0, RAND_str_functs);
++        ERR_load_strings(0, RAND_str_reasons);
++    }
++#endif
++    return 1;
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/rand/rand_lcl.h b/CryptoPkg/Library/OpensslLib/openssl/crypto/rand/rand_lcl.h
+new file mode 100644
+index 0000000..d98c90e
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/rand/rand_lcl.h
+@@ -0,0 +1,46 @@
++/*
++ * Copyright 1995-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#ifndef HEADER_RAND_LCL_H
++# define HEADER_RAND_LCL_H
++
++# define ENTROPY_NEEDED 32      /* require 256 bits = 32 bytes of randomness */
++
++# if !defined(USE_MD5_RAND) && !defined(USE_SHA1_RAND) && !defined(USE_MDC2_RAND) && !defined(USE_MD2_RAND)
++#  define USE_SHA1_RAND
++# endif
++
++# include 
++# define MD_Update(a,b,c)        EVP_DigestUpdate(a,b,c)
++# define MD_Final(a,b)           EVP_DigestFinal_ex(a,b,NULL)
++# if defined(USE_MD5_RAND)
++#  include 
++#  define MD_DIGEST_LENGTH        MD5_DIGEST_LENGTH
++#  define MD_Init(a)              EVP_DigestInit_ex(a,EVP_md5(), NULL)
++#  define MD(a,b,c)               EVP_Digest(a,b,c,NULL,EVP_md5(), NULL)
++# elif defined(USE_SHA1_RAND)
++#  include 
++#  define MD_DIGEST_LENGTH        SHA_DIGEST_LENGTH
++#  define MD_Init(a)              EVP_DigestInit_ex(a,EVP_sha1(), NULL)
++#  define MD(a,b,c)               EVP_Digest(a,b,c,NULL,EVP_sha1(), NULL)
++# elif defined(USE_MDC2_RAND)
++#  include 
++#  define MD_DIGEST_LENGTH        MDC2_DIGEST_LENGTH
++#  define MD_Init(a)              EVP_DigestInit_ex(a,EVP_mdc2(), NULL)
++#  define MD(a,b,c)               EVP_Digest(a,b,c,NULL,EVP_mdc2(), NULL)
++# elif defined(USE_MD2_RAND)
++#  include 
++#  define MD_DIGEST_LENGTH        MD2_DIGEST_LENGTH
++#  define MD_Init(a)              EVP_DigestInit_ex(a,EVP_md2(), NULL)
++#  define MD(a,b,c)               EVP_Digest(a,b,c,NULL,EVP_md2(), NULL)
++# endif
++
++void rand_hw_xor(unsigned char *buf, size_t num);
++
++#endif
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/rand/rand_lib.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/rand/rand_lib.c
+new file mode 100644
+index 0000000..2387126
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/rand/rand_lib.c
+@@ -0,0 +1,126 @@
++/*
++ * Copyright 1995-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include 
++#include "internal/cryptlib.h"
++#include 
++#include "internal/rand.h"
++
++#include 
++
++#ifdef OPENSSL_FIPS
++# include 
++# include 
++#endif
++
++#ifndef OPENSSL_NO_ENGINE
++/* non-NULL if default_RAND_meth is ENGINE-provided */
++static ENGINE *funct_ref = NULL;
++#endif
++static const RAND_METHOD *default_RAND_meth = NULL;
++
++int RAND_set_rand_method(const RAND_METHOD *meth)
++{
++#ifndef OPENSSL_NO_ENGINE
++    ENGINE_finish(funct_ref);
++    funct_ref = NULL;
++#endif
++    default_RAND_meth = meth;
++    return 1;
++}
++
++const RAND_METHOD *RAND_get_rand_method(void)
++{
++    if (!default_RAND_meth) {
++#ifndef OPENSSL_NO_ENGINE
++        ENGINE *e = ENGINE_get_default_RAND();
++        if (e) {
++            default_RAND_meth = ENGINE_get_RAND(e);
++            if (default_RAND_meth == NULL) {
++                ENGINE_finish(e);
++                e = NULL;
++            }
++        }
++        if (e)
++            funct_ref = e;
++        else
++#endif
++            default_RAND_meth = RAND_OpenSSL();
++    }
++    return default_RAND_meth;
++}
++
++#ifndef OPENSSL_NO_ENGINE
++int RAND_set_rand_engine(ENGINE *engine)
++{
++    const RAND_METHOD *tmp_meth = NULL;
++    if (engine) {
++        if (!ENGINE_init(engine))
++            return 0;
++        tmp_meth = ENGINE_get_RAND(engine);
++        if (tmp_meth == NULL) {
++            ENGINE_finish(engine);
++            return 0;
++        }
++    }
++    /* This function releases any prior ENGINE so call it first */
++    RAND_set_rand_method(tmp_meth);
++    funct_ref = engine;
++    return 1;
++}
++#endif
++
++void rand_cleanup_int(void)
++{
++    const RAND_METHOD *meth = RAND_get_rand_method();
++    if (meth && meth->cleanup)
++        meth->cleanup();
++    RAND_set_rand_method(NULL);
++}
++
++void RAND_seed(const void *buf, int num)
++{
++    const RAND_METHOD *meth = RAND_get_rand_method();
++    if (meth && meth->seed)
++        meth->seed(buf, num);
++}
++
++void RAND_add(const void *buf, int num, double entropy)
++{
++    const RAND_METHOD *meth = RAND_get_rand_method();
++    if (meth && meth->add)
++        meth->add(buf, num, entropy);
++}
++
++int RAND_bytes(unsigned char *buf, int num)
++{
++    const RAND_METHOD *meth = RAND_get_rand_method();
++    if (meth && meth->bytes)
++        return meth->bytes(buf, num);
++    return (-1);
++}
++
++#if OPENSSL_API_COMPAT < 0x10100000L
++int RAND_pseudo_bytes(unsigned char *buf, int num)
++{
++    const RAND_METHOD *meth = RAND_get_rand_method();
++    if (meth && meth->pseudorand)
++        return meth->pseudorand(buf, num);
++    return (-1);
++}
++#endif
++
++int RAND_status(void)
++{
++    const RAND_METHOD *meth = RAND_get_rand_method();
++    if (meth && meth->status)
++        return meth->status();
++    return 0;
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/rand/rand_unix.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/rand/rand_unix.c
+new file mode 100644
+index 0000000..ecba2dc
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/rand/rand_unix.c
+@@ -0,0 +1,324 @@
++/*
++ * Copyright 1995-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++
++#define USE_SOCKETS
++#include "e_os.h"
++#include "internal/cryptlib.h"
++#include 
++#include "rand_lcl.h"
++
++#if !(defined(OPENSSL_SYS_WINDOWS) || defined(OPENSSL_SYS_WIN32) || defined(OPENSSL_SYS_VMS) || defined(OPENSSL_SYS_VXWORKS) || defined(OPENSSL_SYS_UEFI))
++
++# include 
++# include 
++# include 
++# include 
++# include 
++# include 
++# include 
++# if defined(OPENSSL_SYS_LINUX) /* should actually be available virtually
++                                 * everywhere */
++#  include 
++# endif
++# include 
++# ifndef FD_SETSIZE
++#  define FD_SETSIZE (8*sizeof(fd_set))
++# endif
++
++# if defined(OPENSSL_SYS_VOS)
++
++/*
++ * The following algorithm repeatedly samples the real-time clock (RTC) to
++ * generate a sequence of unpredictable data.  The algorithm relies upon the
++ * uneven execution speed of the code (due to factors such as cache misses,
++ * interrupts, bus activity, and scheduling) and upon the rather large
++ * relative difference between the speed of the clock and the rate at which
++ * it can be read.
++ *
++ * If this code is ported to an environment where execution speed is more
++ * constant or where the RTC ticks at a much slower rate, or the clock can be
++ * read with fewer instructions, it is likely that the results would be far
++ * more predictable.
++ *
++ * As a precaution, we generate 4 times the minimum required amount of seed
++ * data.
++ */
++
++int RAND_poll(void)
++{
++    short int code;
++    gid_t curr_gid;
++    pid_t curr_pid;
++    uid_t curr_uid;
++    int i, k;
++    struct timespec ts;
++    unsigned char v;
++
++#  ifdef OPENSSL_SYS_VOS_HPPA
++    long duration;
++    extern void s$sleep(long *_duration, short int *_code);
++#  else
++#   ifdef OPENSSL_SYS_VOS_IA32
++    long long duration;
++    extern void s$sleep2(long long *_duration, short int *_code);
++#   else
++#    error "Unsupported Platform."
++#   endif                       /* OPENSSL_SYS_VOS_IA32 */
++#  endif                        /* OPENSSL_SYS_VOS_HPPA */
++
++    /*
++     * Seed with the gid, pid, and uid, to ensure *some* variation between
++     * different processes.
++     */
++
++    curr_gid = getgid();
++    RAND_add(&curr_gid, sizeof curr_gid, 1);
++    curr_gid = 0;
++
++    curr_pid = getpid();
++    RAND_add(&curr_pid, sizeof curr_pid, 1);
++    curr_pid = 0;
++
++    curr_uid = getuid();
++    RAND_add(&curr_uid, sizeof curr_uid, 1);
++    curr_uid = 0;
++
++    for (i = 0; i < (ENTROPY_NEEDED * 4); i++) {
++        /*
++         * burn some cpu; hope for interrupts, cache collisions, bus
++         * interference, etc.
++         */
++        for (k = 0; k < 99; k++)
++            ts.tv_nsec = random();
++
++#  ifdef OPENSSL_SYS_VOS_HPPA
++        /* sleep for 1/1024 of a second (976 us).  */
++        duration = 1;
++        s$sleep(&duration, &code);
++#  else
++#   ifdef OPENSSL_SYS_VOS_IA32
++        /* sleep for 1/65536 of a second (15 us).  */
++        duration = 1;
++        s$sleep2(&duration, &code);
++#   endif                       /* OPENSSL_SYS_VOS_IA32 */
++#  endif                        /* OPENSSL_SYS_VOS_HPPA */
++
++        /* get wall clock time.  */
++        clock_gettime(CLOCK_REALTIME, &ts);
++
++        /* take 8 bits */
++        v = (unsigned char)(ts.tv_nsec % 256);
++        RAND_add(&v, sizeof v, 1);
++        v = 0;
++    }
++    return 1;
++}
++# elif defined __OpenBSD__
++int RAND_poll(void)
++{
++    u_int32_t rnd = 0, i;
++    unsigned char buf[ENTROPY_NEEDED];
++
++    for (i = 0; i < sizeof(buf); i++) {
++        if (i % 4 == 0)
++            rnd = arc4random();
++        buf[i] = rnd;
++        rnd >>= 8;
++    }
++    RAND_add(buf, sizeof(buf), ENTROPY_NEEDED);
++    OPENSSL_cleanse(buf, sizeof(buf));
++
++    return 1;
++}
++# else                          /* !defined(__OpenBSD__) */
++int RAND_poll(void)
++{
++    unsigned long l;
++    pid_t curr_pid = getpid();
++#  if defined(DEVRANDOM) || (!defined(OPENSS_NO_EGD) && defined(DEVRANDOM_EGD))
++    unsigned char tmpbuf[ENTROPY_NEEDED];
++    int n = 0;
++#  endif
++#  ifdef DEVRANDOM
++    static const char *randomfiles[] = { DEVRANDOM };
++    struct stat randomstats[OSSL_NELEM(randomfiles)];
++    int fd;
++    unsigned int i;
++#  endif
++#  if !defined(OPENSSL_NO_EGD) && defined(DEVRANDOM_EGD)
++    static const char *egdsockets[] = { DEVRANDOM_EGD, NULL };
++    const char **egdsocket = NULL;
++#  endif
++
++#  ifdef DEVRANDOM
++    memset(randomstats, 0, sizeof(randomstats));
++    /*
++     * Use a random entropy pool device. Linux, FreeBSD and OpenBSD have
++     * this. Use /dev/urandom if you can as /dev/random may block if it runs
++     * out of random entries.
++     */
++
++    for (i = 0; (i < OSSL_NELEM(randomfiles)) && (n < ENTROPY_NEEDED); i++) {
++        if ((fd = open(randomfiles[i], O_RDONLY
++#   ifdef O_NONBLOCK
++                       | O_NONBLOCK
++#   endif
++#   ifdef O_BINARY
++                       | O_BINARY
++#   endif
++#   ifdef O_NOCTTY              /* If it happens to be a TTY (god forbid), do
++                                 * not make it our controlling tty */
++                       | O_NOCTTY
++#   endif
++             )) >= 0) {
++            int usec = 10 * 1000; /* spend 10ms on each file */
++            int r;
++            unsigned int j;
++            struct stat *st = &randomstats[i];
++
++            /*
++             * Avoid using same input... Used to be O_NOFOLLOW above, but
++             * it's not universally appropriate...
++             */
++            if (fstat(fd, st) != 0) {
++                close(fd);
++                continue;
++            }
++            for (j = 0; j < i; j++) {
++                if (randomstats[j].st_ino == st->st_ino &&
++                    randomstats[j].st_dev == st->st_dev)
++                    break;
++            }
++            if (j < i) {
++                close(fd);
++                continue;
++            }
++
++            do {
++                int try_read = 0;
++
++#   if defined(OPENSSL_SYS_LINUX)
++                /* use poll() */
++                struct pollfd pset;
++
++                pset.fd = fd;
++                pset.events = POLLIN;
++                pset.revents = 0;
++
++                if (poll(&pset, 1, usec / 1000) < 0)
++                    usec = 0;
++                else
++                    try_read = (pset.revents & POLLIN) != 0;
++
++#   else
++                /* use select() */
++                fd_set fset;
++                struct timeval t;
++
++                t.tv_sec = 0;
++                t.tv_usec = usec;
++
++                if (FD_SETSIZE > 0 && (unsigned)fd >= FD_SETSIZE) {
++                    /*
++                     * can't use select, so just try to read once anyway
++                     */
++                    try_read = 1;
++                } else {
++                    FD_ZERO(&fset);
++                    FD_SET(fd, &fset);
++
++                    if (select(fd + 1, &fset, NULL, NULL, &t) >= 0) {
++                        usec = t.tv_usec;
++                        if (FD_ISSET(fd, &fset))
++                            try_read = 1;
++                    } else
++                        usec = 0;
++                }
++#   endif
++
++                if (try_read) {
++                    r = read(fd, (unsigned char *)tmpbuf + n,
++                             ENTROPY_NEEDED - n);
++                    if (r > 0)
++                        n += r;
++                } else
++                    r = -1;
++
++                /*
++                 * Some Unixen will update t in select(), some won't.  For
++                 * those who won't, or if we didn't use select() in the first
++                 * place, give up here, otherwise, we will do this once again
++                 * for the remaining time.
++                 */
++                if (usec == 10 * 1000)
++                    usec = 0;
++            }
++            while ((r > 0 ||
++                    (errno == EINTR || errno == EAGAIN)) && usec != 0
++                   && n < ENTROPY_NEEDED);
++
++            close(fd);
++        }
++    }
++#  endif                        /* defined(DEVRANDOM) */
++
++#  if !defined(OPENSSL_NO_EGD) && defined(DEVRANDOM_EGD)
++    /*
++     * Use an EGD socket to read entropy from an EGD or PRNGD entropy
++     * collecting daemon.
++     */
++
++    for (egdsocket = egdsockets; *egdsocket && n < ENTROPY_NEEDED;
++         egdsocket++) {
++        int r;
++
++        r = RAND_query_egd_bytes(*egdsocket, (unsigned char *)tmpbuf + n,
++                                 ENTROPY_NEEDED - n);
++        if (r > 0)
++            n += r;
++    }
++#  endif                        /* defined(DEVRANDOM_EGD) */
++
++#  if defined(DEVRANDOM) || (!defined(OPENSSL_NO_EGD) && defined(DEVRANDOM_EGD))
++    if (n > 0) {
++        RAND_add(tmpbuf, sizeof tmpbuf, (double)n);
++        OPENSSL_cleanse(tmpbuf, n);
++    }
++#  endif
++
++    /* put in some default random data, we need more than just this */
++    l = curr_pid;
++    RAND_add(&l, sizeof(l), 0.0);
++    l = getuid();
++    RAND_add(&l, sizeof(l), 0.0);
++
++    l = time(NULL);
++    RAND_add(&l, sizeof(l), 0.0);
++
++#  if defined(DEVRANDOM) || (!defined(OPENSSL_NO_EGD) && defined(DEVRANDOM_EGD))
++    return 1;
++#  else
++    return 0;
++#  endif
++}
++
++# endif                         /* defined(__OpenBSD__) */
++#endif                          /* !(defined(OPENSSL_SYS_WINDOWS) ||
++                                 * defined(OPENSSL_SYS_WIN32) ||
++                                 * defined(OPENSSL_SYS_VMS) ||
++                                 * defined(OPENSSL_SYS_VXWORKS) */
++
++#if defined(OPENSSL_SYS_VXWORKS) || defined(OPENSSL_SYS_UEFI)
++int RAND_poll(void)
++{
++    return 0;
++}
++#endif
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/rand/rand_vms.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/rand/rand_vms.c
+new file mode 100644
+index 0000000..9c462dd
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/rand/rand_vms.c
+@@ -0,0 +1,133 @@
++/*
++ * Copyright 2001-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++/*
++ * Modified by VMS Software, Inc (2016)
++ *    Eliminate looping through all processes (performance)
++ *    Add additional randomizations using rand() function
++ */
++
++#include 
++#include "rand_lcl.h"
++
++#if defined(OPENSSL_SYS_VMS)
++# include 
++# include 
++# include 
++# include 
++# include 
++# ifdef __DECC
++#  pragma message disable DOLLARID
++# endif
++
++/*
++ * Use 32-bit pointers almost everywhere.  Define the type to which to cast a
++ * pointer passed to an external function.
++ */
++# if __INITIAL_POINTER_SIZE == 64
++#  define PTR_T __void_ptr64
++#  pragma pointer_size save
++#  pragma pointer_size 32
++# else                          /* __INITIAL_POINTER_SIZE == 64 */
++#  define PTR_T void *
++# endif                         /* __INITIAL_POINTER_SIZE == 64 [else] */
++
++static struct items_data_st {
++    short length, code;         /* length is number of bytes */
++} items_data[] = {
++    {4, JPI$_BUFIO},
++    {4, JPI$_CPUTIM},
++    {4, JPI$_DIRIO},
++    {4, JPI$_IMAGECOUNT},
++    {8, JPI$_LAST_LOGIN_I},
++    {8, JPI$_LOGINTIM},
++    {4, JPI$_PAGEFLTS},
++    {4, JPI$_PID},
++    {4, JPI$_PPGCNT},
++    {4, JPI$_WSPEAK},
++    {4, JPI$_FINALEXC},
++    {0, 0}                      /* zero terminated */
++};
++
++int RAND_poll(void)
++{
++
++    /* determine the number of items in the JPI array */
++
++    struct items_data_st item_entry;
++    int item_entry_count = sizeof(items_data)/sizeof(item_entry);
++
++    /* Create the JPI itemlist array to hold item_data content */
++
++    struct {
++        short length, code;
++        int *buffer;
++        int *retlen;
++    } item[item_entry_count], *pitem; /* number of entries in items_data */
++
++    struct items_data_st *pitems_data;
++    int data_buffer[(item_entry_count*2)+4]; /* 8 bytes per entry max */
++    int iosb[2];
++    int sys_time[2];
++    int *ptr;
++    int i, j ;
++    int tmp_length   = 0;
++    int total_length = 0;
++
++    pitems_data = items_data;
++    pitem = item;
++
++
++    /* Setup itemlist for GETJPI */
++    while (pitems_data->length) {
++        pitem->length = pitems_data->length;
++        pitem->code   = pitems_data->code;
++        pitem->buffer = &data_buffer[total_length];
++        pitem->retlen = 0;
++        /* total_length is in longwords */
++        total_length += pitems_data->length/4;
++        pitems_data++;
++        pitem ++;
++    }
++    pitem->length = pitem->code = 0;
++
++    /* Fill data_buffer with various info bits from this process */
++    /* and twist that data to seed the SSL random number init    */
++
++    if (sys$getjpiw(EFN$C_ENF, NULL, NULL, item, &iosb, 0, 0) == SS$_NORMAL) {
++        for (i = 0; i < total_length; i++) {
++            sys$gettim((struct _generic_64 *)&sys_time[0]);
++            srand(sys_time[0] * data_buffer[0] * data_buffer[1] + i);
++
++            if (i == (total_length - 1)) { /* for JPI$_FINALEXC */
++                ptr = &data_buffer[i];
++                for (j = 0; j < 4; j++) {
++                    data_buffer[i + j] = ptr[j];
++                    /* OK to use rand() just to scramble the seed */
++                    data_buffer[i + j] ^= (sys_time[0] ^ rand());
++                    tmp_length++;
++                }
++            } else {
++                /* OK to use rand() just to scramble the seed */
++                data_buffer[i] ^= (sys_time[0] ^ rand());
++            }
++        }
++
++        total_length += (tmp_length - 1);
++
++        /* size of seed is total_length*4 bytes (64bytes) */
++        RAND_add((PTR_T) data_buffer, total_length*4, total_length * 2);
++    } else {
++        return 0;
++    }
++
++    return 1;
++}
++
++#endif
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/rand/rand_win.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/rand/rand_win.c
+new file mode 100644
+index 0000000..1be0ed3
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/rand/rand_win.c
+@@ -0,0 +1,135 @@
++/*
++ * Copyright 1995-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include "internal/cryptlib.h"
++#include 
++#include "rand_lcl.h"
++
++#if defined(OPENSSL_SYS_WINDOWS) || defined(OPENSSL_SYS_WIN32)
++# include 
++/* On Windows 7 or higher use BCrypt instead of the legacy CryptoAPI */
++# if defined(_MSC_VER) && defined(_WIN32_WINNT) && _WIN32_WINNT>=0x0601
++#  define RAND_WINDOWS_USE_BCRYPT
++# endif
++
++# ifdef RAND_WINDOWS_USE_BCRYPT
++#  include 
++#  pragma comment(lib, "bcrypt.lib")
++#  ifndef STATUS_SUCCESS
++#   define STATUS_SUCCESS ((NTSTATUS)0x00000000L)
++#  endif
++# else
++#  include 
++/*
++ * Intel hardware RNG CSP -- available from
++ * http://developer.intel.com/design/security/rng/redist_license.htm
++ */
++#  define PROV_INTEL_SEC 22
++#  define INTEL_DEF_PROV L"Intel Hardware Cryptographic Service Provider"
++# endif
++
++static void readtimer(void);
++
++int RAND_poll(void)
++{
++    MEMORYSTATUS mst;
++# ifndef RAND_WINDOWS_USE_BCRYPT
++    HCRYPTPROV hProvider;
++# endif
++    DWORD w;
++    BYTE buf[64];
++
++# ifdef RAND_WINDOWS_USE_BCRYPT
++    if (BCryptGenRandom(NULL, buf, (ULONG)sizeof(buf), BCRYPT_USE_SYSTEM_PREFERRED_RNG) == STATUS_SUCCESS) {
++        RAND_add(buf, sizeof(buf), sizeof(buf));
++    }
++# else
++    /* poll the CryptoAPI PRNG */
++    /* The CryptoAPI returns sizeof(buf) bytes of randomness */
++    if (CryptAcquireContextW(&hProvider, NULL, NULL, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT | CRYPT_SILENT)) {
++        if (CryptGenRandom(hProvider, (DWORD)sizeof(buf), buf) != 0) {
++            RAND_add(buf, sizeof(buf), sizeof(buf));
++        }
++        CryptReleaseContext(hProvider, 0);
++    }
++
++    /* poll the Pentium PRG with CryptoAPI */
++    if (CryptAcquireContextW(&hProvider, NULL, INTEL_DEF_PROV, PROV_INTEL_SEC, CRYPT_VERIFYCONTEXT | CRYPT_SILENT)) {
++        if (CryptGenRandom(hProvider, (DWORD)sizeof(buf), buf) != 0) {
++            RAND_add(buf, sizeof(buf), sizeof(buf));
++        }
++        CryptReleaseContext(hProvider, 0);
++    }
++# endif
++
++    /* timer data */
++    readtimer();
++
++    /* memory usage statistics */
++    GlobalMemoryStatus(&mst);
++    RAND_add(&mst, sizeof(mst), 1);
++
++    /* process ID */
++    w = GetCurrentProcessId();
++    RAND_add(&w, sizeof(w), 1);
++
++    return (1);
++}
++
++#if OPENSSL_API_COMPAT < 0x10100000L
++int RAND_event(UINT iMsg, WPARAM wParam, LPARAM lParam)
++{
++    RAND_poll();
++    return RAND_status();
++}
++
++void RAND_screen(void)
++{
++    RAND_poll();
++}
++#endif
++
++/* feed timing information to the PRNG */
++static void readtimer(void)
++{
++    DWORD w;
++    LARGE_INTEGER l;
++    static int have_perfc = 1;
++# if defined(_MSC_VER) && defined(_M_X86)
++    static int have_tsc = 1;
++    DWORD cyclecount;
++
++    if (have_tsc) {
++        __try {
++            __asm {
++            _emit 0x0f _emit 0x31 mov cyclecount, eax}
++            RAND_add(&cyclecount, sizeof(cyclecount), 1);
++        }
++        __except(EXCEPTION_EXECUTE_HANDLER) {
++            have_tsc = 0;
++        }
++    }
++# else
++#  define have_tsc 0
++# endif
++
++    if (have_perfc) {
++        if (QueryPerformanceCounter(&l) == 0)
++            have_perfc = 0;
++        else
++            RAND_add(&l, sizeof(l), 0);
++    }
++
++    if (!have_tsc && !have_perfc) {
++        w = GetTickCount();
++        RAND_add(&w, sizeof(w), 0);
++    }
++}
++
++#endif
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/rand/randfile.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/rand/randfile.c
+new file mode 100644
+index 0000000..15fa9dc
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/rand/randfile.c
+@@ -0,0 +1,366 @@
++/*
++ * Copyright 1995-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include "internal/cryptlib.h"
++
++#include 
++#include 
++#include 
++#include 
++
++#include 
++#include 
++#include 
++
++#ifdef OPENSSL_SYS_VMS
++# include 
++#endif
++#ifndef NO_SYS_TYPES_H
++# include 
++#endif
++#ifndef OPENSSL_NO_POSIX_IO
++# include 
++# include 
++/*
++ * Following should not be needed, and we could have been stricter
++ * and demand S_IS*. But some systems just don't comply... Formally
++ * below macros are "anatomically incorrect", because normally they
++ * would look like ((m) & MASK == TYPE), but since MASK availability
++ * is as questionable, we settle for this poor-man fallback...
++ */
++# if !defined(S_ISBLK)
++#  if defined(_S_IFBLK)
++#   define S_ISBLK(m) ((m) & _S_IFBLK)
++#  elif defined(S_IFBLK)
++#   define S_ISBLK(m) ((m) & S_IFBLK)
++#  elif defined(_WIN32)
++#   define S_ISBLK(m) 0 /* no concept of block devices on Windows */
++#  endif
++# endif
++# if !defined(S_ISCHR)
++#  if defined(_S_IFCHR)
++#   define S_ISCHR(m) ((m) & _S_IFCHR)
++#  elif defined(S_IFCHR)
++#   define S_ISCHR(m) ((m) & S_IFCHR)
++#  endif
++# endif
++#endif
++
++#ifdef _WIN32
++# define stat    _stat
++# define chmod   _chmod
++# define open    _open
++# define fdopen  _fdopen
++# define fstat   _fstat
++# define fileno  _fileno
++#endif
++
++#undef BUFSIZE
++#define BUFSIZE 1024
++#define RAND_DATA 1024
++
++#ifdef OPENSSL_SYS_VMS
++/*
++ * Misc hacks needed for specific cases.
++ *
++ * __FILE_ptr32 is a type provided by DEC C headers (types.h specifically)
++ * to make sure the FILE* is a 32-bit pointer no matter what.  We know that
++ * stdio function return this type (a study of stdio.h proves it).
++ * Additionally, we create a similar char pointer type for the sake of
++ * vms_setbuf below.
++ */
++# if __INITIAL_POINTER_SIZE == 64
++#  pragma pointer_size save
++#  pragma pointer_size 32
++typedef char *char_ptr32;
++#  pragma pointer_size restore
++/*
++ * On VMS, setbuf() will only take 32-bit pointers, and a compilation
++ * with /POINTER_SIZE=64 will give off a MAYLOSEDATA2 warning here.
++ * Since we know that the FILE* really is a 32-bit pointer expanded to
++ * 64 bits, we also know it's safe to convert it back to a 32-bit pointer.
++ * As for the buffer parameter, we only use NULL here, so that passes as
++ * well...
++ */
++#  define setbuf(fp,buf) (setbuf)((__FILE_ptr32)(fp), (char_ptr32)(buf))
++# endif
++
++/*
++ * This declaration is a nasty hack to get around vms' extension to fopen for
++ * passing in sharing options being disabled by /STANDARD=ANSI89
++ */
++static __FILE_ptr32 (*const vms_fopen)(const char *, const char *, ...) =
++      (__FILE_ptr32 (*)(const char *, const char *, ...))fopen;
++# define VMS_OPEN_ATTRS "shr=get,put,upd,del","ctx=bin,stm","rfm=stm","rat=none","mrs=0"
++
++# define openssl_fopen(fname,mode) vms_fopen((fname), (mode), VMS_OPEN_ATTRS)
++#endif
++
++#define RFILE ".rnd"
++
++/*
++ * Note that these functions are intended for seed files only. Entropy
++ * devices and EGD sockets are handled in rand_unix.c
++ */
++
++int RAND_load_file(const char *file, long bytes)
++{
++    /*-
++     * If bytes >= 0, read up to 'bytes' bytes.
++     * if bytes == -1, read complete file.
++     */
++
++    unsigned char buf[BUFSIZE];
++#ifndef OPENSSL_NO_POSIX_IO
++    struct stat sb;
++#endif
++    int i, ret = 0, n;
++    FILE *in = NULL;
++
++    if (file == NULL)
++        return 0;
++
++    if (bytes == 0)
++        return ret;
++
++    in = openssl_fopen(file, "rb");
++    if (in == NULL)
++        goto err;
++
++#ifndef OPENSSL_NO_POSIX_IO
++    /*
++     * struct stat can have padding and unused fields that may not be
++     * initialized in the call to stat(). We need to clear the entire
++     * structure before calling RAND_add() to avoid complaints from
++     * applications such as Valgrind.
++     */
++    memset(&sb, 0, sizeof(sb));
++    if (fstat(fileno(in), &sb) < 0)
++        goto err;
++    RAND_add(&sb, sizeof(sb), 0.0);
++
++# if defined(S_ISBLK) && defined(S_ISCHR)
++    if (S_ISBLK(sb.st_mode) || S_ISCHR(sb.st_mode)) {
++        /*
++         * this file is a device. we don't want read an infinite number of
++         * bytes from a random device, nor do we want to use buffered I/O
++         * because we will waste system entropy.
++         */
++        bytes = (bytes == -1) ? 2048 : bytes; /* ok, is 2048 enough? */
++        setbuf(in, NULL); /* don't do buffered reads */
++    }
++# endif
++#endif
++    for (;;) {
++        if (bytes > 0)
++            n = (bytes < BUFSIZE) ? (int)bytes : BUFSIZE;
++        else
++            n = BUFSIZE;
++        i = fread(buf, 1, n, in);
++        if (i <= 0)
++            break;
++
++        RAND_add(buf, i, (double)i);
++        ret += i;
++        if (bytes > 0) {
++            bytes -= n;
++            if (bytes <= 0)
++                break;
++        }
++    }
++    OPENSSL_cleanse(buf, BUFSIZE);
++ err:
++    if (in != NULL)
++        fclose(in);
++    return ret;
++}
++
++int RAND_write_file(const char *file)
++{
++    unsigned char buf[BUFSIZE];
++    int i, ret = 0, rand_err = 0;
++    FILE *out = NULL;
++    int n;
++#ifndef OPENSSL_NO_POSIX_IO
++    struct stat sb;
++
++# if defined(S_ISBLK) && defined(S_ISCHR)
++# ifdef _WIN32
++    /*
++     * Check for |file| being a driver as "ASCII-safe" on Windows,
++     * because driver paths are always ASCII.
++     */
++# endif
++    i = stat(file, &sb);
++    if (i != -1) {
++        if (S_ISBLK(sb.st_mode) || S_ISCHR(sb.st_mode)) {
++            /*
++             * this file is a device. we don't write back to it. we
++             * "succeed" on the assumption this is some sort of random
++             * device. Otherwise attempting to write to and chmod the device
++             * causes problems.
++             */
++            return 1;
++        }
++    }
++# endif
++#endif
++
++#if defined(O_CREAT) && !defined(OPENSSL_NO_POSIX_IO) && \
++    !defined(OPENSSL_SYS_VMS) && !defined(OPENSSL_SYS_WINDOWS)
++    {
++# ifndef O_BINARY
++#  define O_BINARY 0
++# endif
++        /*
++         * chmod(..., 0600) is too late to protect the file, permissions
++         * should be restrictive from the start
++         */
++        int fd = open(file, O_WRONLY | O_CREAT | O_BINARY, 0600);
++        if (fd != -1)
++            out = fdopen(fd, "wb");
++    }
++#endif
++
++#ifdef OPENSSL_SYS_VMS
++    /*
++     * VMS NOTE: Prior versions of this routine created a _new_ version of
++     * the rand file for each call into this routine, then deleted all
++     * existing versions named ;-1, and finally renamed the current version
++     * as ';1'. Under concurrent usage, this resulted in an RMS race
++     * condition in rename() which could orphan files (see vms message help
++     * for RMS$_REENT). With the fopen() calls below, openssl/VMS now shares
++     * the top-level version of the rand file. Note that there may still be
++     * conditions where the top-level rand file is locked. If so, this code
++     * will then create a new version of the rand file. Without the delete
++     * and rename code, this can result in ascending file versions that stop
++     * at version 32767, and this routine will then return an error. The
++     * remedy for this is to recode the calling application to avoid
++     * concurrent use of the rand file, or synchronize usage at the
++     * application level. Also consider whether or not you NEED a persistent
++     * rand file in a concurrent use situation.
++     */
++
++    out = openssl_fopen(file, "rb+");
++#endif
++    if (out == NULL)
++        out = openssl_fopen(file, "wb");
++    if (out == NULL)
++        goto err;
++
++#if !defined(NO_CHMOD) && !defined(OPENSSL_NO_POSIX_IO)
++    chmod(file, 0600);
++#endif
++    n = RAND_DATA;
++    for (;;) {
++        i = (n > BUFSIZE) ? BUFSIZE : n;
++        n -= BUFSIZE;
++        if (RAND_bytes(buf, i) <= 0)
++            rand_err = 1;
++        i = fwrite(buf, 1, i, out);
++        if (i <= 0) {
++            ret = 0;
++            break;
++        }
++        ret += i;
++        if (n <= 0)
++            break;
++    }
++
++    fclose(out);
++    OPENSSL_cleanse(buf, BUFSIZE);
++ err:
++    return (rand_err ? -1 : ret);
++}
++
++const char *RAND_file_name(char *buf, size_t size)
++{
++    char *s = NULL;
++    int use_randfile = 1;
++#ifdef __OpenBSD__
++    struct stat sb;
++#endif
++
++#if defined(_WIN32) && defined(CP_UTF8)
++    DWORD len;
++    WCHAR *var, *val;
++
++    if ((var = L"RANDFILE",
++         len = GetEnvironmentVariableW(var, NULL, 0)) == 0
++        && (var = L"HOME", use_randfile = 0,
++            len = GetEnvironmentVariableW(var, NULL, 0)) == 0
++        && (var = L"USERPROFILE",
++            len = GetEnvironmentVariableW(var, NULL, 0)) == 0) {
++        var = L"SYSTEMROOT",
++        len = GetEnvironmentVariableW(var, NULL, 0);
++    }
++
++    if (len != 0) {
++        int sz;
++
++        val = _alloca(len * sizeof(WCHAR));
++
++        if (GetEnvironmentVariableW(var, val, len) < len
++            && (sz = WideCharToMultiByte(CP_UTF8, 0, val, -1, NULL, 0,
++                                         NULL, NULL)) != 0) {
++            s = _alloca(sz);
++            if (WideCharToMultiByte(CP_UTF8, 0, val, -1, s, sz,
++                                    NULL, NULL) == 0)
++                s = NULL;
++        }
++    }
++#else
++    if (OPENSSL_issetugid() != 0) {
++        use_randfile = 0;
++    } else {
++        s = getenv("RANDFILE");
++        if (s == NULL || *s == '\0') {
++            use_randfile = 0;
++            s = getenv("HOME");
++        }
++    }
++#endif
++#ifdef DEFAULT_HOME
++    if (!use_randfile && s == NULL) {
++        s = DEFAULT_HOME;
++    }
++#endif
++    if (s != NULL && *s) {
++        size_t len = strlen(s);
++
++        if (use_randfile && len + 1 < size) {
++            if (OPENSSL_strlcpy(buf, s, size) >= size)
++                return NULL;
++        } else if (len + strlen(RFILE) + 2 < size) {
++            OPENSSL_strlcpy(buf, s, size);
++#ifndef OPENSSL_SYS_VMS
++            OPENSSL_strlcat(buf, "/", size);
++#endif
++            OPENSSL_strlcat(buf, RFILE, size);
++        }
++    } else {
++        buf[0] = '\0';      /* no file name */
++    }
++
++#ifdef __OpenBSD__
++    /*
++     * given that all random loads just fail if the file can't be seen on a
++     * stat, we stat the file we're returning, if it fails, use /dev/arandom
++     * instead. this allows the user to use their own source for good random
++     * data, but defaults to something hopefully decent if that isn't
++     * available.
++     */
++
++    if (!buf[0] || stat(buf, &sb) == -1)
++        if (OPENSSL_strlcpy(buf, "/dev/arandom", size) >= size) {
++            return NULL;
++        }
++#endif
++    return buf[0] ? buf : NULL;
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/rc2/build.info b/CryptoPkg/Library/OpensslLib/openssl/crypto/rc2/build.info
+new file mode 100644
+index 0000000..47a3fd0
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/rc2/build.info
+@@ -0,0 +1,3 @@
++LIBS=../../libcrypto
++SOURCE[../../libcrypto]=\
++        rc2_ecb.c rc2_skey.c rc2_cbc.c rc2cfb64.c rc2ofb64.c
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/rc2/rc2_cbc.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/rc2/rc2_cbc.c
+new file mode 100644
+index 0000000..2b59353
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/rc2/rc2_cbc.c
+@@ -0,0 +1,179 @@
++/*
++ * Copyright 1995-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include "rc2_locl.h"
++
++void RC2_cbc_encrypt(const unsigned char *in, unsigned char *out, long length,
++                     RC2_KEY *ks, unsigned char *iv, int encrypt)
++{
++    register unsigned long tin0, tin1;
++    register unsigned long tout0, tout1, xor0, xor1;
++    register long l = length;
++    unsigned long tin[2];
++
++    if (encrypt) {
++        c2l(iv, tout0);
++        c2l(iv, tout1);
++        iv -= 8;
++        for (l -= 8; l >= 0; l -= 8) {
++            c2l(in, tin0);
++            c2l(in, tin1);
++            tin0 ^= tout0;
++            tin1 ^= tout1;
++            tin[0] = tin0;
++            tin[1] = tin1;
++            RC2_encrypt(tin, ks);
++            tout0 = tin[0];
++            l2c(tout0, out);
++            tout1 = tin[1];
++            l2c(tout1, out);
++        }
++        if (l != -8) {
++            c2ln(in, tin0, tin1, l + 8);
++            tin0 ^= tout0;
++            tin1 ^= tout1;
++            tin[0] = tin0;
++            tin[1] = tin1;
++            RC2_encrypt(tin, ks);
++            tout0 = tin[0];
++            l2c(tout0, out);
++            tout1 = tin[1];
++            l2c(tout1, out);
++        }
++        l2c(tout0, iv);
++        l2c(tout1, iv);
++    } else {
++        c2l(iv, xor0);
++        c2l(iv, xor1);
++        iv -= 8;
++        for (l -= 8; l >= 0; l -= 8) {
++            c2l(in, tin0);
++            tin[0] = tin0;
++            c2l(in, tin1);
++            tin[1] = tin1;
++            RC2_decrypt(tin, ks);
++            tout0 = tin[0] ^ xor0;
++            tout1 = tin[1] ^ xor1;
++            l2c(tout0, out);
++            l2c(tout1, out);
++            xor0 = tin0;
++            xor1 = tin1;
++        }
++        if (l != -8) {
++            c2l(in, tin0);
++            tin[0] = tin0;
++            c2l(in, tin1);
++            tin[1] = tin1;
++            RC2_decrypt(tin, ks);
++            tout0 = tin[0] ^ xor0;
++            tout1 = tin[1] ^ xor1;
++            l2cn(tout0, tout1, out, l + 8);
++            xor0 = tin0;
++            xor1 = tin1;
++        }
++        l2c(xor0, iv);
++        l2c(xor1, iv);
++    }
++    tin0 = tin1 = tout0 = tout1 = xor0 = xor1 = 0;
++    tin[0] = tin[1] = 0;
++}
++
++void RC2_encrypt(unsigned long *d, RC2_KEY *key)
++{
++    int i, n;
++    register RC2_INT *p0, *p1;
++    register RC2_INT x0, x1, x2, x3, t;
++    unsigned long l;
++
++    l = d[0];
++    x0 = (RC2_INT) l & 0xffff;
++    x1 = (RC2_INT) (l >> 16L);
++    l = d[1];
++    x2 = (RC2_INT) l & 0xffff;
++    x3 = (RC2_INT) (l >> 16L);
++
++    n = 3;
++    i = 5;
++
++    p0 = p1 = &(key->data[0]);
++    for (;;) {
++        t = (x0 + (x1 & ~x3) + (x2 & x3) + *(p0++)) & 0xffff;
++        x0 = (t << 1) | (t >> 15);
++        t = (x1 + (x2 & ~x0) + (x3 & x0) + *(p0++)) & 0xffff;
++        x1 = (t << 2) | (t >> 14);
++        t = (x2 + (x3 & ~x1) + (x0 & x1) + *(p0++)) & 0xffff;
++        x2 = (t << 3) | (t >> 13);
++        t = (x3 + (x0 & ~x2) + (x1 & x2) + *(p0++)) & 0xffff;
++        x3 = (t << 5) | (t >> 11);
++
++        if (--i == 0) {
++            if (--n == 0)
++                break;
++            i = (n == 2) ? 6 : 5;
++
++            x0 += p1[x3 & 0x3f];
++            x1 += p1[x0 & 0x3f];
++            x2 += p1[x1 & 0x3f];
++            x3 += p1[x2 & 0x3f];
++        }
++    }
++
++    d[0] =
++        (unsigned long)(x0 & 0xffff) | ((unsigned long)(x1 & 0xffff) << 16L);
++    d[1] =
++        (unsigned long)(x2 & 0xffff) | ((unsigned long)(x3 & 0xffff) << 16L);
++}
++
++void RC2_decrypt(unsigned long *d, RC2_KEY *key)
++{
++    int i, n;
++    register RC2_INT *p0, *p1;
++    register RC2_INT x0, x1, x2, x3, t;
++    unsigned long l;
++
++    l = d[0];
++    x0 = (RC2_INT) l & 0xffff;
++    x1 = (RC2_INT) (l >> 16L);
++    l = d[1];
++    x2 = (RC2_INT) l & 0xffff;
++    x3 = (RC2_INT) (l >> 16L);
++
++    n = 3;
++    i = 5;
++
++    p0 = &(key->data[63]);
++    p1 = &(key->data[0]);
++    for (;;) {
++        t = ((x3 << 11) | (x3 >> 5)) & 0xffff;
++        x3 = (t - (x0 & ~x2) - (x1 & x2) - *(p0--)) & 0xffff;
++        t = ((x2 << 13) | (x2 >> 3)) & 0xffff;
++        x2 = (t - (x3 & ~x1) - (x0 & x1) - *(p0--)) & 0xffff;
++        t = ((x1 << 14) | (x1 >> 2)) & 0xffff;
++        x1 = (t - (x2 & ~x0) - (x3 & x0) - *(p0--)) & 0xffff;
++        t = ((x0 << 15) | (x0 >> 1)) & 0xffff;
++        x0 = (t - (x1 & ~x3) - (x2 & x3) - *(p0--)) & 0xffff;
++
++        if (--i == 0) {
++            if (--n == 0)
++                break;
++            i = (n == 2) ? 6 : 5;
++
++            x3 = (x3 - p1[x2 & 0x3f]) & 0xffff;
++            x2 = (x2 - p1[x1 & 0x3f]) & 0xffff;
++            x1 = (x1 - p1[x0 & 0x3f]) & 0xffff;
++            x0 = (x0 - p1[x3 & 0x3f]) & 0xffff;
++        }
++    }
++
++    d[0] =
++        (unsigned long)(x0 & 0xffff) | ((unsigned long)(x1 & 0xffff) << 16L);
++    d[1] =
++        (unsigned long)(x2 & 0xffff) | ((unsigned long)(x3 & 0xffff) << 16L);
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/rc2/rc2_ecb.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/rc2/rc2_ecb.c
+new file mode 100644
+index 0000000..b87931f
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/rc2/rc2_ecb.c
+@@ -0,0 +1,41 @@
++/*
++ * Copyright 1995-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include "rc2_locl.h"
++#include 
++
++/*-
++ * RC2 as implemented frm a posting from
++ * Newsgroups: sci.crypt
++ * Sender: pgut01@cs.auckland.ac.nz (Peter Gutmann)
++ * Subject: Specification for Ron Rivests Cipher No.2
++ * Message-ID: <4fk39f$f70@net.auckland.ac.nz>
++ * Date: 11 Feb 1996 06:45:03 GMT
++ */
++
++void RC2_ecb_encrypt(const unsigned char *in, unsigned char *out, RC2_KEY *ks,
++                     int encrypt)
++{
++    unsigned long l, d[2];
++
++    c2l(in, l);
++    d[0] = l;
++    c2l(in, l);
++    d[1] = l;
++    if (encrypt)
++        RC2_encrypt(d, ks);
++    else
++        RC2_decrypt(d, ks);
++    l = d[0];
++    l2c(l, out);
++    l = d[1];
++    l2c(l, out);
++    l = d[0] = d[1] = 0;
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/rc2/rc2_locl.h b/CryptoPkg/Library/OpensslLib/openssl/crypto/rc2/rc2_locl.h
+new file mode 100644
+index 0000000..a9a57d6
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/rc2/rc2_locl.h
+@@ -0,0 +1,106 @@
++/*
++ * Copyright 1995-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#undef c2l
++#define c2l(c,l)        (l =((unsigned long)(*((c)++)))    , \
++                         l|=((unsigned long)(*((c)++)))<< 8L, \
++                         l|=((unsigned long)(*((c)++)))<<16L, \
++                         l|=((unsigned long)(*((c)++)))<<24L)
++
++/* NOTE - c is not incremented as per c2l */
++#undef c2ln
++#define c2ln(c,l1,l2,n) { \
++                        c+=n; \
++                        l1=l2=0; \
++                        switch (n) { \
++                        case 8: l2 =((unsigned long)(*(--(c))))<<24L; \
++                        case 7: l2|=((unsigned long)(*(--(c))))<<16L; \
++                        case 6: l2|=((unsigned long)(*(--(c))))<< 8L; \
++                        case 5: l2|=((unsigned long)(*(--(c))));     \
++                        case 4: l1 =((unsigned long)(*(--(c))))<<24L; \
++                        case 3: l1|=((unsigned long)(*(--(c))))<<16L; \
++                        case 2: l1|=((unsigned long)(*(--(c))))<< 8L; \
++                        case 1: l1|=((unsigned long)(*(--(c))));     \
++                                } \
++                        }
++
++#undef l2c
++#define l2c(l,c)        (*((c)++)=(unsigned char)(((l)     )&0xff), \
++                         *((c)++)=(unsigned char)(((l)>> 8L)&0xff), \
++                         *((c)++)=(unsigned char)(((l)>>16L)&0xff), \
++                         *((c)++)=(unsigned char)(((l)>>24L)&0xff))
++
++/* NOTE - c is not incremented as per l2c */
++#undef l2cn
++#define l2cn(l1,l2,c,n) { \
++                        c+=n; \
++                        switch (n) { \
++                        case 8: *(--(c))=(unsigned char)(((l2)>>24L)&0xff); \
++                        case 7: *(--(c))=(unsigned char)(((l2)>>16L)&0xff); \
++                        case 6: *(--(c))=(unsigned char)(((l2)>> 8L)&0xff); \
++                        case 5: *(--(c))=(unsigned char)(((l2)     )&0xff); \
++                        case 4: *(--(c))=(unsigned char)(((l1)>>24L)&0xff); \
++                        case 3: *(--(c))=(unsigned char)(((l1)>>16L)&0xff); \
++                        case 2: *(--(c))=(unsigned char)(((l1)>> 8L)&0xff); \
++                        case 1: *(--(c))=(unsigned char)(((l1)     )&0xff); \
++                                } \
++                        }
++
++/* NOTE - c is not incremented as per n2l */
++#define n2ln(c,l1,l2,n) { \
++                        c+=n; \
++                        l1=l2=0; \
++                        switch (n) { \
++                        case 8: l2 =((unsigned long)(*(--(c))))    ; \
++                        case 7: l2|=((unsigned long)(*(--(c))))<< 8; \
++                        case 6: l2|=((unsigned long)(*(--(c))))<<16; \
++                        case 5: l2|=((unsigned long)(*(--(c))))<<24; \
++                        case 4: l1 =((unsigned long)(*(--(c))))    ; \
++                        case 3: l1|=((unsigned long)(*(--(c))))<< 8; \
++                        case 2: l1|=((unsigned long)(*(--(c))))<<16; \
++                        case 1: l1|=((unsigned long)(*(--(c))))<<24; \
++                                } \
++                        }
++
++/* NOTE - c is not incremented as per l2n */
++#define l2nn(l1,l2,c,n) { \
++                        c+=n; \
++                        switch (n) { \
++                        case 8: *(--(c))=(unsigned char)(((l2)    )&0xff); \
++                        case 7: *(--(c))=(unsigned char)(((l2)>> 8)&0xff); \
++                        case 6: *(--(c))=(unsigned char)(((l2)>>16)&0xff); \
++                        case 5: *(--(c))=(unsigned char)(((l2)>>24)&0xff); \
++                        case 4: *(--(c))=(unsigned char)(((l1)    )&0xff); \
++                        case 3: *(--(c))=(unsigned char)(((l1)>> 8)&0xff); \
++                        case 2: *(--(c))=(unsigned char)(((l1)>>16)&0xff); \
++                        case 1: *(--(c))=(unsigned char)(((l1)>>24)&0xff); \
++                                } \
++                        }
++
++#undef n2l
++#define n2l(c,l)        (l =((unsigned long)(*((c)++)))<<24L, \
++                         l|=((unsigned long)(*((c)++)))<<16L, \
++                         l|=((unsigned long)(*((c)++)))<< 8L, \
++                         l|=((unsigned long)(*((c)++))))
++
++#undef l2n
++#define l2n(l,c)        (*((c)++)=(unsigned char)(((l)>>24L)&0xff), \
++                         *((c)++)=(unsigned char)(((l)>>16L)&0xff), \
++                         *((c)++)=(unsigned char)(((l)>> 8L)&0xff), \
++                         *((c)++)=(unsigned char)(((l)     )&0xff))
++
++#define C_RC2(n) \
++        t=(x0+(x1& ~x3)+(x2&x3)+ *(p0++))&0xffff; \
++        x0=(t<<1)|(t>>15); \
++        t=(x1+(x2& ~x0)+(x3&x0)+ *(p0++))&0xffff; \
++        x1=(t<<2)|(t>>14); \
++        t=(x2+(x3& ~x1)+(x0&x1)+ *(p0++))&0xffff; \
++        x2=(t<<3)|(t>>13); \
++        t=(x3+(x0& ~x2)+(x1&x2)+ *(p0++))&0xffff; \
++        x3=(t<<5)|(t>>11);
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/rc2/rc2_skey.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/rc2/rc2_skey.c
+new file mode 100644
+index 0000000..55d8ba3
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/rc2/rc2_skey.c
+@@ -0,0 +1,98 @@
++/*
++ * Copyright 1995-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include "rc2_locl.h"
++
++static const unsigned char key_table[256] = {
++    0xd9, 0x78, 0xf9, 0xc4, 0x19, 0xdd, 0xb5, 0xed, 0x28, 0xe9, 0xfd, 0x79,
++    0x4a, 0xa0, 0xd8, 0x9d, 0xc6, 0x7e, 0x37, 0x83, 0x2b, 0x76, 0x53, 0x8e,
++    0x62, 0x4c, 0x64, 0x88, 0x44, 0x8b, 0xfb, 0xa2, 0x17, 0x9a, 0x59, 0xf5,
++    0x87, 0xb3, 0x4f, 0x13, 0x61, 0x45, 0x6d, 0x8d, 0x09, 0x81, 0x7d, 0x32,
++    0xbd, 0x8f, 0x40, 0xeb, 0x86, 0xb7, 0x7b, 0x0b, 0xf0, 0x95, 0x21, 0x22,
++    0x5c, 0x6b, 0x4e, 0x82, 0x54, 0xd6, 0x65, 0x93, 0xce, 0x60, 0xb2, 0x1c,
++    0x73, 0x56, 0xc0, 0x14, 0xa7, 0x8c, 0xf1, 0xdc, 0x12, 0x75, 0xca, 0x1f,
++    0x3b, 0xbe, 0xe4, 0xd1, 0x42, 0x3d, 0xd4, 0x30, 0xa3, 0x3c, 0xb6, 0x26,
++    0x6f, 0xbf, 0x0e, 0xda, 0x46, 0x69, 0x07, 0x57, 0x27, 0xf2, 0x1d, 0x9b,
++    0xbc, 0x94, 0x43, 0x03, 0xf8, 0x11, 0xc7, 0xf6, 0x90, 0xef, 0x3e, 0xe7,
++    0x06, 0xc3, 0xd5, 0x2f, 0xc8, 0x66, 0x1e, 0xd7, 0x08, 0xe8, 0xea, 0xde,
++    0x80, 0x52, 0xee, 0xf7, 0x84, 0xaa, 0x72, 0xac, 0x35, 0x4d, 0x6a, 0x2a,
++    0x96, 0x1a, 0xd2, 0x71, 0x5a, 0x15, 0x49, 0x74, 0x4b, 0x9f, 0xd0, 0x5e,
++    0x04, 0x18, 0xa4, 0xec, 0xc2, 0xe0, 0x41, 0x6e, 0x0f, 0x51, 0xcb, 0xcc,
++    0x24, 0x91, 0xaf, 0x50, 0xa1, 0xf4, 0x70, 0x39, 0x99, 0x7c, 0x3a, 0x85,
++    0x23, 0xb8, 0xb4, 0x7a, 0xfc, 0x02, 0x36, 0x5b, 0x25, 0x55, 0x97, 0x31,
++    0x2d, 0x5d, 0xfa, 0x98, 0xe3, 0x8a, 0x92, 0xae, 0x05, 0xdf, 0x29, 0x10,
++    0x67, 0x6c, 0xba, 0xc9, 0xd3, 0x00, 0xe6, 0xcf, 0xe1, 0x9e, 0xa8, 0x2c,
++    0x63, 0x16, 0x01, 0x3f, 0x58, 0xe2, 0x89, 0xa9, 0x0d, 0x38, 0x34, 0x1b,
++    0xab, 0x33, 0xff, 0xb0, 0xbb, 0x48, 0x0c, 0x5f, 0xb9, 0xb1, 0xcd, 0x2e,
++    0xc5, 0xf3, 0xdb, 0x47, 0xe5, 0xa5, 0x9c, 0x77, 0x0a, 0xa6, 0x20, 0x68,
++    0xfe, 0x7f, 0xc1, 0xad,
++};
++
++#if defined(_MSC_VER) && defined(_ARM_)
++# pragma optimize("g",off)
++#endif
++
++/*
++ * It has come to my attention that there are 2 versions of the RC2 key
++ * schedule.  One which is normal, and anther which has a hook to use a
++ * reduced key length. BSAFE uses the 'retarded' version.  What I previously
++ * shipped is the same as specifying 1024 for the 'bits' parameter.  Bsafe
++ * uses a version where the bits parameter is the same as len*8
++ */
++void RC2_set_key(RC2_KEY *key, int len, const unsigned char *data, int bits)
++{
++    int i, j;
++    unsigned char *k;
++    RC2_INT *ki;
++    unsigned int c, d;
++
++    k = (unsigned char *)&(key->data[0]);
++    *k = 0;                     /* for if there is a zero length key */
++
++    if (len > 128)
++        len = 128;
++    if (bits <= 0)
++        bits = 1024;
++    if (bits > 1024)
++        bits = 1024;
++
++    for (i = 0; i < len; i++)
++        k[i] = data[i];
++
++    /* expand table */
++    d = k[len - 1];
++    j = 0;
++    for (i = len; i < 128; i++, j++) {
++        d = key_table[(k[j] + d) & 0xff];
++        k[i] = d;
++    }
++
++    /* hmm.... key reduction to 'bits' bits */
++
++    j = (bits + 7) >> 3;
++    i = 128 - j;
++    c = (0xff >> (-bits & 0x07));
++
++    d = key_table[k[i] & c];
++    k[i] = d;
++    while (i--) {
++        d = key_table[k[i + j] ^ d];
++        k[i] = d;
++    }
++
++    /* copy from bytes into RC2_INT's */
++    ki = &(key->data[63]);
++    for (i = 127; i >= 0; i -= 2)
++        *(ki--) = ((k[i] << 8) | k[i - 1]) & 0xffff;
++}
++
++#if defined(_MSC_VER)
++# pragma optimize("",on)
++#endif
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/rc2/rc2cfb64.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/rc2/rc2cfb64.c
+new file mode 100644
+index 0000000..e11093d
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/rc2/rc2cfb64.c
+@@ -0,0 +1,74 @@
++/*
++ * Copyright 1995-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include "rc2_locl.h"
++
++/*
++ * The input and output encrypted as though 64bit cfb mode is being used.
++ * The extra state information to record how much of the 64bit block we have
++ * used is contained in *num;
++ */
++
++void RC2_cfb64_encrypt(const unsigned char *in, unsigned char *out,
++                       long length, RC2_KEY *schedule, unsigned char *ivec,
++                       int *num, int encrypt)
++{
++    register unsigned long v0, v1, t;
++    register int n = *num;
++    register long l = length;
++    unsigned long ti[2];
++    unsigned char *iv, c, cc;
++
++    iv = (unsigned char *)ivec;
++    if (encrypt) {
++        while (l--) {
++            if (n == 0) {
++                c2l(iv, v0);
++                ti[0] = v0;
++                c2l(iv, v1);
++                ti[1] = v1;
++                RC2_encrypt((unsigned long *)ti, schedule);
++                iv = (unsigned char *)ivec;
++                t = ti[0];
++                l2c(t, iv);
++                t = ti[1];
++                l2c(t, iv);
++                iv = (unsigned char *)ivec;
++            }
++            c = *(in++) ^ iv[n];
++            *(out++) = c;
++            iv[n] = c;
++            n = (n + 1) & 0x07;
++        }
++    } else {
++        while (l--) {
++            if (n == 0) {
++                c2l(iv, v0);
++                ti[0] = v0;
++                c2l(iv, v1);
++                ti[1] = v1;
++                RC2_encrypt((unsigned long *)ti, schedule);
++                iv = (unsigned char *)ivec;
++                t = ti[0];
++                l2c(t, iv);
++                t = ti[1];
++                l2c(t, iv);
++                iv = (unsigned char *)ivec;
++            }
++            cc = *(in++);
++            c = iv[n];
++            iv[n] = cc;
++            *(out++) = c ^ cc;
++            n = (n + 1) & 0x07;
++        }
++    }
++    v0 = v1 = ti[0] = ti[1] = t = c = cc = 0;
++    *num = n;
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/rc2/rc2ofb64.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/rc2/rc2ofb64.c
+new file mode 100644
+index 0000000..d610278
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/rc2/rc2ofb64.c
+@@ -0,0 +1,61 @@
++/*
++ * Copyright 1995-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include "rc2_locl.h"
++
++/*
++ * The input and output encrypted as though 64bit ofb mode is being used.
++ * The extra state information to record how much of the 64bit block we have
++ * used is contained in *num;
++ */
++void RC2_ofb64_encrypt(const unsigned char *in, unsigned char *out,
++                       long length, RC2_KEY *schedule, unsigned char *ivec,
++                       int *num)
++{
++    register unsigned long v0, v1, t;
++    register int n = *num;
++    register long l = length;
++    unsigned char d[8];
++    register char *dp;
++    unsigned long ti[2];
++    unsigned char *iv;
++    int save = 0;
++
++    iv = (unsigned char *)ivec;
++    c2l(iv, v0);
++    c2l(iv, v1);
++    ti[0] = v0;
++    ti[1] = v1;
++    dp = (char *)d;
++    l2c(v0, dp);
++    l2c(v1, dp);
++    while (l--) {
++        if (n == 0) {
++            RC2_encrypt((unsigned long *)ti, schedule);
++            dp = (char *)d;
++            t = ti[0];
++            l2c(t, dp);
++            t = ti[1];
++            l2c(t, dp);
++            save++;
++        }
++        *(out++) = *(in++) ^ d[n];
++        n = (n + 1) & 0x07;
++    }
++    if (save) {
++        v0 = ti[0];
++        v1 = ti[1];
++        iv = (unsigned char *)ivec;
++        l2c(v0, iv);
++        l2c(v1, iv);
++    }
++    t = v0 = v1 = ti[0] = ti[1] = 0;
++    *num = n;
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/rc2/tab.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/rc2/tab.c
+new file mode 100644
+index 0000000..bc95dc4
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/rc2/tab.c
+@@ -0,0 +1,93 @@
++/*
++ * Copyright 1998-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++
++unsigned char ebits_to_num[256] = {
++    0xbd, 0x56, 0xea, 0xf2, 0xa2, 0xf1, 0xac, 0x2a,
++    0xb0, 0x93, 0xd1, 0x9c, 0x1b, 0x33, 0xfd, 0xd0,
++    0x30, 0x04, 0xb6, 0xdc, 0x7d, 0xdf, 0x32, 0x4b,
++    0xf7, 0xcb, 0x45, 0x9b, 0x31, 0xbb, 0x21, 0x5a,
++    0x41, 0x9f, 0xe1, 0xd9, 0x4a, 0x4d, 0x9e, 0xda,
++    0xa0, 0x68, 0x2c, 0xc3, 0x27, 0x5f, 0x80, 0x36,
++    0x3e, 0xee, 0xfb, 0x95, 0x1a, 0xfe, 0xce, 0xa8,
++    0x34, 0xa9, 0x13, 0xf0, 0xa6, 0x3f, 0xd8, 0x0c,
++    0x78, 0x24, 0xaf, 0x23, 0x52, 0xc1, 0x67, 0x17,
++    0xf5, 0x66, 0x90, 0xe7, 0xe8, 0x07, 0xb8, 0x60,
++    0x48, 0xe6, 0x1e, 0x53, 0xf3, 0x92, 0xa4, 0x72,
++    0x8c, 0x08, 0x15, 0x6e, 0x86, 0x00, 0x84, 0xfa,
++    0xf4, 0x7f, 0x8a, 0x42, 0x19, 0xf6, 0xdb, 0xcd,
++    0x14, 0x8d, 0x50, 0x12, 0xba, 0x3c, 0x06, 0x4e,
++    0xec, 0xb3, 0x35, 0x11, 0xa1, 0x88, 0x8e, 0x2b,
++    0x94, 0x99, 0xb7, 0x71, 0x74, 0xd3, 0xe4, 0xbf,
++    0x3a, 0xde, 0x96, 0x0e, 0xbc, 0x0a, 0xed, 0x77,
++    0xfc, 0x37, 0x6b, 0x03, 0x79, 0x89, 0x62, 0xc6,
++    0xd7, 0xc0, 0xd2, 0x7c, 0x6a, 0x8b, 0x22, 0xa3,
++    0x5b, 0x05, 0x5d, 0x02, 0x75, 0xd5, 0x61, 0xe3,
++    0x18, 0x8f, 0x55, 0x51, 0xad, 0x1f, 0x0b, 0x5e,
++    0x85, 0xe5, 0xc2, 0x57, 0x63, 0xca, 0x3d, 0x6c,
++    0xb4, 0xc5, 0xcc, 0x70, 0xb2, 0x91, 0x59, 0x0d,
++    0x47, 0x20, 0xc8, 0x4f, 0x58, 0xe0, 0x01, 0xe2,
++    0x16, 0x38, 0xc4, 0x6f, 0x3b, 0x0f, 0x65, 0x46,
++    0xbe, 0x7e, 0x2d, 0x7b, 0x82, 0xf9, 0x40, 0xb5,
++    0x1d, 0x73, 0xf8, 0xeb, 0x26, 0xc7, 0x87, 0x97,
++    0x25, 0x54, 0xb1, 0x28, 0xaa, 0x98, 0x9d, 0xa5,
++    0x64, 0x6d, 0x7a, 0xd4, 0x10, 0x81, 0x44, 0xef,
++    0x49, 0xd6, 0xae, 0x2e, 0xdd, 0x76, 0x5c, 0x2f,
++    0xa7, 0x1c, 0xc9, 0x09, 0x69, 0x9a, 0x83, 0xcf,
++    0x29, 0x39, 0xb9, 0xe9, 0x4c, 0xff, 0x43, 0xab,
++};
++
++unsigned char num_to_ebits[256] = {
++    0x5d, 0xbe, 0x9b, 0x8b, 0x11, 0x99, 0x6e, 0x4d,
++    0x59, 0xf3, 0x85, 0xa6, 0x3f, 0xb7, 0x83, 0xc5,
++    0xe4, 0x73, 0x6b, 0x3a, 0x68, 0x5a, 0xc0, 0x47,
++    0xa0, 0x64, 0x34, 0x0c, 0xf1, 0xd0, 0x52, 0xa5,
++    0xb9, 0x1e, 0x96, 0x43, 0x41, 0xd8, 0xd4, 0x2c,
++    0xdb, 0xf8, 0x07, 0x77, 0x2a, 0xca, 0xeb, 0xef,
++    0x10, 0x1c, 0x16, 0x0d, 0x38, 0x72, 0x2f, 0x89,
++    0xc1, 0xf9, 0x80, 0xc4, 0x6d, 0xae, 0x30, 0x3d,
++    0xce, 0x20, 0x63, 0xfe, 0xe6, 0x1a, 0xc7, 0xb8,
++    0x50, 0xe8, 0x24, 0x17, 0xfc, 0x25, 0x6f, 0xbb,
++    0x6a, 0xa3, 0x44, 0x53, 0xd9, 0xa2, 0x01, 0xab,
++    0xbc, 0xb6, 0x1f, 0x98, 0xee, 0x9a, 0xa7, 0x2d,
++    0x4f, 0x9e, 0x8e, 0xac, 0xe0, 0xc6, 0x49, 0x46,
++    0x29, 0xf4, 0x94, 0x8a, 0xaf, 0xe1, 0x5b, 0xc3,
++    0xb3, 0x7b, 0x57, 0xd1, 0x7c, 0x9c, 0xed, 0x87,
++    0x40, 0x8c, 0xe2, 0xcb, 0x93, 0x14, 0xc9, 0x61,
++    0x2e, 0xe5, 0xcc, 0xf6, 0x5e, 0xa8, 0x5c, 0xd6,
++    0x75, 0x8d, 0x62, 0x95, 0x58, 0x69, 0x76, 0xa1,
++    0x4a, 0xb5, 0x55, 0x09, 0x78, 0x33, 0x82, 0xd7,
++    0xdd, 0x79, 0xf5, 0x1b, 0x0b, 0xde, 0x26, 0x21,
++    0x28, 0x74, 0x04, 0x97, 0x56, 0xdf, 0x3c, 0xf0,
++    0x37, 0x39, 0xdc, 0xff, 0x06, 0xa4, 0xea, 0x42,
++    0x08, 0xda, 0xb4, 0x71, 0xb0, 0xcf, 0x12, 0x7a,
++    0x4e, 0xfa, 0x6c, 0x1d, 0x84, 0x00, 0xc8, 0x7f,
++    0x91, 0x45, 0xaa, 0x2b, 0xc2, 0xb1, 0x8f, 0xd5,
++    0xba, 0xf2, 0xad, 0x19, 0xb2, 0x67, 0x36, 0xf7,
++    0x0f, 0x0a, 0x92, 0x7d, 0xe3, 0x9d, 0xe9, 0x90,
++    0x3e, 0x23, 0x27, 0x66, 0x13, 0xec, 0x81, 0x15,
++    0xbd, 0x22, 0xbf, 0x9f, 0x7e, 0xa9, 0x51, 0x4b,
++    0x4c, 0xfb, 0x02, 0xd3, 0x70, 0x86, 0x31, 0xe7,
++    0x3b, 0x05, 0x03, 0x54, 0x60, 0x48, 0x65, 0x18,
++    0xd2, 0xcd, 0x5f, 0x32, 0x88, 0x0e, 0x35, 0xfd,
++};
++
++main()
++{
++    int i, j;
++
++    for (i = 0; i < 256; i++) {
++        for (j = 0; j < 256; j++)
++            if (ebits_to_num[j] == i) {
++                printf("0x%02x,", j);
++                break;
++            }
++    }
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/rc4/asm/rc4-586.pl b/CryptoPkg/Library/OpensslLib/openssl/crypto/rc4/asm/rc4-586.pl
+new file mode 100644
+index 0000000..7d6f97c
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/rc4/asm/rc4-586.pl
+@@ -0,0 +1,428 @@
++#! /usr/bin/env perl
++# Copyright 1998-2016 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
++# in the file LICENSE in the source distribution or at
++# https://www.openssl.org/source/license.html
++
++
++# ====================================================================
++# [Re]written by Andy Polyakov  for the OpenSSL
++# project. The module is, however, dual licensed under OpenSSL and
++# CRYPTOGAMS licenses depending on where you obtain it. For further
++# details see http://www.openssl.org/~appro/cryptogams/.
++# ====================================================================
++
++# At some point it became apparent that the original SSLeay RC4
++# assembler implementation performs suboptimally on latest IA-32
++# microarchitectures. After re-tuning performance has changed as
++# following:
++#
++# Pentium	-10%
++# Pentium III	+12%
++# AMD		+50%(*)
++# P4		+250%(**)
++#
++# (*)	This number is actually a trade-off:-) It's possible to
++#	achieve	+72%, but at the cost of -48% off PIII performance.
++#	In other words code performing further 13% faster on AMD
++#	would perform almost 2 times slower on Intel PIII...
++#	For reference! This code delivers ~80% of rc4-amd64.pl
++#	performance on the same Opteron machine.
++# (**)	This number requires compressed key schedule set up by
++#	RC4_set_key [see commentary below for further details].
++#
++#					
++
++# May 2011
++#
++# Optimize for Core2 and Westmere [and incidentally Opteron]. Current
++# performance in cycles per processed byte (less is better) and
++# improvement relative to previous version of this module is:
++#
++# Pentium	10.2			# original numbers
++# Pentium III	7.8(*)
++# Intel P4	7.5
++#
++# Opteron	6.1/+20%		# new MMX numbers
++# Core2		5.3/+67%(**)
++# Westmere	5.1/+94%(**)
++# Sandy Bridge	5.0/+8%
++# Atom		12.6/+6%
++# VIA Nano	6.4/+9%
++# Ivy Bridge	4.9/±0%
++# Bulldozer	4.9/+15%
++#
++# (*)	PIII can actually deliver 6.6 cycles per byte with MMX code,
++#	but this specific code performs poorly on Core2. And vice
++#	versa, below MMX/SSE code delivering 5.8/7.1 on Core2 performs
++#	poorly on PIII, at 8.0/14.5:-( As PIII is not a "hot" CPU
++#	[anymore], I chose to discard PIII-specific code path and opt
++#	for original IALU-only code, which is why MMX/SSE code path
++#	is guarded by SSE2 bit (see below), not MMX/SSE.
++# (**)	Performance vs. block size on Core2 and Westmere had a maximum
++#	at ... 64 bytes block size. And it was quite a maximum, 40-60%
++#	in comparison to largest 8KB block size. Above improvement
++#	coefficients are for the largest block size.
++
++$0 =~ m/(.*[\/\\])[^\/\\]+$/; $dir=$1;
++push(@INC,"${dir}","${dir}../../perlasm");
++require "x86asm.pl";
++
++$output=pop;
++open STDOUT,">$output";
++
++&asm_init($ARGV[0],"rc4-586.pl",$x86only = $ARGV[$#ARGV] eq "386");
++
++$xx="eax";
++$yy="ebx";
++$tx="ecx";
++$ty="edx";
++$inp="esi";
++$out="ebp";
++$dat="edi";
++
++sub RC4_loop {
++  my $i=shift;
++  my $func = ($i==0)?*mov:*or;
++
++	&add	(&LB($yy),&LB($tx));
++	&mov	($ty,&DWP(0,$dat,$yy,4));
++	&mov	(&DWP(0,$dat,$yy,4),$tx);
++	&mov	(&DWP(0,$dat,$xx,4),$ty);
++	&add	($ty,$tx);
++	&inc	(&LB($xx));
++	&and	($ty,0xff);
++	&ror	($out,8)	if ($i!=0);
++	if ($i<3) {
++	  &mov	($tx,&DWP(0,$dat,$xx,4));
++	} else {
++	  &mov	($tx,&wparam(3));	# reload [re-biased] out
++	}
++	&$func	($out,&DWP(0,$dat,$ty,4));
++}
++
++if ($alt=0) {
++  # >20% faster on Atom and Sandy Bridge[!], 8% faster on Opteron,
++  # but ~40% slower on Core2 and Westmere... Attempt to add movz
++  # brings down Opteron by 25%, Atom and Sandy Bridge by 15%, yet
++  # on Core2 with movz it's almost 20% slower than below alternative
++  # code... Yes, it's a total mess...
++  my @XX=($xx,$out);
++  $RC4_loop_mmx = sub {		# SSE actually...
++    my $i=shift;
++    my $j=$i<=0?0:$i>>1;
++    my $mm=$i<=0?"mm0":"mm".($i&1);
++
++	&add	(&LB($yy),&LB($tx));
++	&lea	(@XX[1],&DWP(1,@XX[0]));
++	&pxor	("mm2","mm0")				if ($i==0);
++	&psllq	("mm1",8)				if ($i==0);
++	&and	(@XX[1],0xff);
++	&pxor	("mm0","mm0")				if ($i<=0);
++	&mov	($ty,&DWP(0,$dat,$yy,4));
++	&mov	(&DWP(0,$dat,$yy,4),$tx);
++	&pxor	("mm1","mm2")				if ($i==0);
++	&mov	(&DWP(0,$dat,$XX[0],4),$ty);
++	&add	(&LB($ty),&LB($tx));
++	&movd	(@XX[0],"mm7")				if ($i==0);
++	&mov	($tx,&DWP(0,$dat,@XX[1],4));
++	&pxor	("mm1","mm1")				if ($i==1);
++	&movq	("mm2",&QWP(0,$inp))			if ($i==1);
++	&movq	(&QWP(-8,(@XX[0],$inp)),"mm1")		if ($i==0);
++	&pinsrw	($mm,&DWP(0,$dat,$ty,4),$j);
++
++	push	(@XX,shift(@XX))			if ($i>=0);
++  }
++} else {
++  # Using pinsrw here improves performane on Intel CPUs by 2-3%, but
++  # brings down AMD by 7%...
++  $RC4_loop_mmx = sub {
++    my $i=shift;
++
++	&add	(&LB($yy),&LB($tx));
++	&psllq	("mm1",8*(($i-1)&7))			if (abs($i)!=1);
++	&mov	($ty,&DWP(0,$dat,$yy,4));
++	&mov	(&DWP(0,$dat,$yy,4),$tx);
++	&mov	(&DWP(0,$dat,$xx,4),$ty);
++	&inc	($xx);
++	&add	($ty,$tx);
++	&movz	($xx,&LB($xx));				# (*)
++	&movz	($ty,&LB($ty));				# (*)
++	&pxor	("mm2",$i==1?"mm0":"mm1")		if ($i>=0);
++	&movq	("mm0",&QWP(0,$inp))			if ($i<=0);
++	&movq	(&QWP(-8,($out,$inp)),"mm2")		if ($i==0);
++	&mov	($tx,&DWP(0,$dat,$xx,4));
++	&movd	($i>0?"mm1":"mm2",&DWP(0,$dat,$ty,4));
++
++	# (*)	This is the key to Core2 and Westmere performance.
++	#	Without movz out-of-order execution logic confuses
++	#	itself and fails to reorder loads and stores. Problem
++	#	appears to be fixed in Sandy Bridge...
++  }
++}
++
++&external_label("OPENSSL_ia32cap_P");
++
++# void RC4(RC4_KEY *key,size_t len,const unsigned char *inp,unsigned char *out);
++&function_begin("RC4");
++	&mov	($dat,&wparam(0));	# load key schedule pointer
++	&mov	($ty, &wparam(1));	# load len
++	&mov	($inp,&wparam(2));	# load inp
++	&mov	($out,&wparam(3));	# load out
++
++	&xor	($xx,$xx);		# avoid partial register stalls
++	&xor	($yy,$yy);
++
++	&cmp	($ty,0);		# safety net
++	&je	(&label("abort"));
++
++	&mov	(&LB($xx),&BP(0,$dat));	# load key->x
++	&mov	(&LB($yy),&BP(4,$dat));	# load key->y
++	&add	($dat,8);
++
++	&lea	($tx,&DWP(0,$inp,$ty));
++	&sub	($out,$inp);		# re-bias out
++	&mov	(&wparam(1),$tx);	# save input+len
++
++	&inc	(&LB($xx));
++
++	# detect compressed key schedule...
++	&cmp	(&DWP(256,$dat),-1);
++	&je	(&label("RC4_CHAR"));
++
++	&mov	($tx,&DWP(0,$dat,$xx,4));
++
++	&and	($ty,-4);		# how many 4-byte chunks?
++	&jz	(&label("loop1"));
++
++	&mov	(&wparam(3),$out);	# $out as accumulator in these loops
++					if ($x86only) {
++	&jmp	(&label("go4loop4"));
++					} else {
++	&test	($ty,-8);
++	&jz	(&label("go4loop4"));
++
++	&picmeup($out,"OPENSSL_ia32cap_P");
++	&bt	(&DWP(0,$out),26);	# check SSE2 bit [could have been MMX]
++	&jnc	(&label("go4loop4"));
++
++	&mov	($out,&wparam(3))	if (!$alt);
++	&movd	("mm7",&wparam(3))	if ($alt);
++	&and	($ty,-8);
++	&lea	($ty,&DWP(-8,$inp,$ty));
++	&mov	(&DWP(-4,$dat),$ty);	# save input+(len/8)*8-8
++
++	&$RC4_loop_mmx(-1);
++	&jmp(&label("loop_mmx_enter"));
++
++	&set_label("loop_mmx",16);
++		&$RC4_loop_mmx(0);
++	&set_label("loop_mmx_enter");
++		for 	($i=1;$i<8;$i++) { &$RC4_loop_mmx($i); }
++		&mov	($ty,$yy);
++		&xor	($yy,$yy);		# this is second key to Core2
++		&mov	(&LB($yy),&LB($ty));	# and Westmere performance...
++		&cmp	($inp,&DWP(-4,$dat));
++		&lea	($inp,&DWP(8,$inp));
++	&jb	(&label("loop_mmx"));
++
++    if ($alt) {
++	&movd	($out,"mm7");
++	&pxor	("mm2","mm0");
++	&psllq	("mm1",8);
++	&pxor	("mm1","mm2");
++	&movq	(&QWP(-8,$out,$inp),"mm1");
++    } else {
++	&psllq	("mm1",56);
++	&pxor	("mm2","mm1");
++	&movq	(&QWP(-8,$out,$inp),"mm2");
++    }
++	&emms	();
++
++	&cmp	($inp,&wparam(1));	# compare to input+len
++	&je	(&label("done"));
++	&jmp	(&label("loop1"));
++					}
++
++&set_label("go4loop4",16);
++	&lea	($ty,&DWP(-4,$inp,$ty));
++	&mov	(&wparam(2),$ty);	# save input+(len/4)*4-4
++
++	&set_label("loop4");
++		for ($i=0;$i<4;$i++) { RC4_loop($i); }
++		&ror	($out,8);
++		&xor	($out,&DWP(0,$inp));
++		&cmp	($inp,&wparam(2));	# compare to input+(len/4)*4-4
++		&mov	(&DWP(0,$tx,$inp),$out);# $tx holds re-biased out here
++		&lea	($inp,&DWP(4,$inp));
++		&mov	($tx,&DWP(0,$dat,$xx,4));
++	&jb	(&label("loop4"));
++
++	&cmp	($inp,&wparam(1));	# compare to input+len
++	&je	(&label("done"));
++	&mov	($out,&wparam(3));	# restore $out
++
++	&set_label("loop1",16);
++		&add	(&LB($yy),&LB($tx));
++		&mov	($ty,&DWP(0,$dat,$yy,4));
++		&mov	(&DWP(0,$dat,$yy,4),$tx);
++		&mov	(&DWP(0,$dat,$xx,4),$ty);
++		&add	($ty,$tx);
++		&inc	(&LB($xx));
++		&and	($ty,0xff);
++		&mov	($ty,&DWP(0,$dat,$ty,4));
++		&xor	(&LB($ty),&BP(0,$inp));
++		&lea	($inp,&DWP(1,$inp));
++		&mov	($tx,&DWP(0,$dat,$xx,4));
++		&cmp	($inp,&wparam(1));	# compare to input+len
++		&mov	(&BP(-1,$out,$inp),&LB($ty));
++	&jb	(&label("loop1"));
++
++	&jmp	(&label("done"));
++
++# this is essentially Intel P4 specific codepath...
++&set_label("RC4_CHAR",16);
++	&movz	($tx,&BP(0,$dat,$xx));
++	# strangely enough unrolled loop performs over 20% slower...
++	&set_label("cloop1");
++		&add	(&LB($yy),&LB($tx));
++		&movz	($ty,&BP(0,$dat,$yy));
++		&mov	(&BP(0,$dat,$yy),&LB($tx));
++		&mov	(&BP(0,$dat,$xx),&LB($ty));
++		&add	(&LB($ty),&LB($tx));
++		&movz	($ty,&BP(0,$dat,$ty));
++		&add	(&LB($xx),1);
++		&xor	(&LB($ty),&BP(0,$inp));
++		&lea	($inp,&DWP(1,$inp));
++		&movz	($tx,&BP(0,$dat,$xx));
++		&cmp	($inp,&wparam(1));
++		&mov	(&BP(-1,$out,$inp),&LB($ty));
++	&jb	(&label("cloop1"));
++
++&set_label("done");
++	&dec	(&LB($xx));
++	&mov	(&DWP(-4,$dat),$yy);		# save key->y
++	&mov	(&BP(-8,$dat),&LB($xx));	# save key->x
++&set_label("abort");
++&function_end("RC4");
++
++########################################################################
++
++$inp="esi";
++$out="edi";
++$idi="ebp";
++$ido="ecx";
++$idx="edx";
++
++# void RC4_set_key(RC4_KEY *key,int len,const unsigned char *data);
++&function_begin("RC4_set_key");
++	&mov	($out,&wparam(0));		# load key
++	&mov	($idi,&wparam(1));		# load len
++	&mov	($inp,&wparam(2));		# load data
++	&picmeup($idx,"OPENSSL_ia32cap_P");
++
++	&lea	($out,&DWP(2*4,$out));		# &key->data
++	&lea	($inp,&DWP(0,$inp,$idi));	# $inp to point at the end
++	&neg	($idi);
++	&xor	("eax","eax");
++	&mov	(&DWP(-4,$out),$idi);		# borrow key->y
++
++	&bt	(&DWP(0,$idx),20);		# check for bit#20
++	&jc	(&label("c1stloop"));
++
++&set_label("w1stloop",16);
++	&mov	(&DWP(0,$out,"eax",4),"eax");	# key->data[i]=i;
++	&add	(&LB("eax"),1);			# i++;
++	&jnc	(&label("w1stloop"));
++
++	&xor	($ido,$ido);
++	&xor	($idx,$idx);
++
++&set_label("w2ndloop",16);
++	&mov	("eax",&DWP(0,$out,$ido,4));
++	&add	(&LB($idx),&BP(0,$inp,$idi));
++	&add	(&LB($idx),&LB("eax"));
++	&add	($idi,1);
++	&mov	("ebx",&DWP(0,$out,$idx,4));
++	&jnz	(&label("wnowrap"));
++	  &mov	($idi,&DWP(-4,$out));
++	&set_label("wnowrap");
++	&mov	(&DWP(0,$out,$idx,4),"eax");
++	&mov	(&DWP(0,$out,$ido,4),"ebx");
++	&add	(&LB($ido),1);
++	&jnc	(&label("w2ndloop"));
++&jmp	(&label("exit"));
++
++# Unlike all other x86 [and x86_64] implementations, Intel P4 core
++# [including EM64T] was found to perform poorly with above "32-bit" key
++# schedule, a.k.a. RC4_INT. Performance improvement for IA-32 hand-coded
++# assembler turned out to be 3.5x if re-coded for compressed 8-bit one,
++# a.k.a. RC4_CHAR! It's however inappropriate to just switch to 8-bit
++# schedule for x86[_64], because non-P4 implementations suffer from
++# significant performance losses then, e.g. PIII exhibits >2x
++# deterioration, and so does Opteron. In order to assure optimal
++# all-round performance, we detect P4 at run-time and set up compressed
++# key schedule, which is recognized by RC4 procedure.
++
++&set_label("c1stloop",16);
++	&mov	(&BP(0,$out,"eax"),&LB("eax"));	# key->data[i]=i;
++	&add	(&LB("eax"),1);			# i++;
++	&jnc	(&label("c1stloop"));
++
++	&xor	($ido,$ido);
++	&xor	($idx,$idx);
++	&xor	("ebx","ebx");
++
++&set_label("c2ndloop",16);
++	&mov	(&LB("eax"),&BP(0,$out,$ido));
++	&add	(&LB($idx),&BP(0,$inp,$idi));
++	&add	(&LB($idx),&LB("eax"));
++	&add	($idi,1);
++	&mov	(&LB("ebx"),&BP(0,$out,$idx));
++	&jnz	(&label("cnowrap"));
++	  &mov	($idi,&DWP(-4,$out));
++	&set_label("cnowrap");
++	&mov	(&BP(0,$out,$idx),&LB("eax"));
++	&mov	(&BP(0,$out,$ido),&LB("ebx"));
++	&add	(&LB($ido),1);
++	&jnc	(&label("c2ndloop"));
++
++	&mov	(&DWP(256,$out),-1);		# mark schedule as compressed
++
++&set_label("exit");
++	&xor	("eax","eax");
++	&mov	(&DWP(-8,$out),"eax");		# key->x=0;
++	&mov	(&DWP(-4,$out),"eax");		# key->y=0;
++&function_end("RC4_set_key");
++
++# const char *RC4_options(void);
++&function_begin_B("RC4_options");
++	&call	(&label("pic_point"));
++&set_label("pic_point");
++	&blindpop("eax");
++	&lea	("eax",&DWP(&label("opts")."-".&label("pic_point"),"eax"));
++	&picmeup("edx","OPENSSL_ia32cap_P");
++	&mov	("edx",&DWP(0,"edx"));
++	&bt	("edx",20);
++	&jc	(&label("1xchar"));
++	&bt	("edx",26);
++	&jnc	(&label("ret"));
++	&add	("eax",25);
++	&ret	();
++&set_label("1xchar");
++	&add	("eax",12);
++&set_label("ret");
++	&ret	();
++&set_label("opts",64);
++&asciz	("rc4(4x,int)");
++&asciz	("rc4(1x,char)");
++&asciz	("rc4(8x,mmx)");
++&asciz	("RC4 for x86, CRYPTOGAMS by ");
++&align	(64);
++&function_end_B("RC4_options");
++
++&asm_finish();
++
++close STDOUT;
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/rc4/asm/rc4-c64xplus.pl b/CryptoPkg/Library/OpensslLib/openssl/crypto/rc4/asm/rc4-c64xplus.pl
+new file mode 100644
+index 0000000..daed75c
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/rc4/asm/rc4-c64xplus.pl
+@@ -0,0 +1,190 @@
++#! /usr/bin/env perl
++# Copyright 2014-2016 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
++# in the file LICENSE in the source distribution or at
++# https://www.openssl.org/source/license.html
++
++#
++# ====================================================================
++# Written by Andy Polyakov  for the OpenSSL
++# project. The module is, however, dual licensed under OpenSSL and
++# CRYPTOGAMS licenses depending on where you obtain it. For further
++# details see http://www.openssl.org/~appro/cryptogams/.
++# ====================================================================
++#
++# RC4 for C64x+.
++#
++# April 2014
++#
++# RC4 subroutine processes one byte in 7.0 cycles, which is 3x faster
++# than TI CGT-generated code. Loop is scheduled in such way that
++# there is only one reference to memory in each cycle. This is done
++# to avoid L1D memory banking conflicts, see SPRU871 TI publication
++# for further details. Otherwise it should be possible to schedule
++# the loop for iteration interval of 6...
++
++($KEY,$LEN,$INP,$OUT)=("A4","B4","A6","B6");
++
++($KEYA,$XX,$TY,$xx,$ONE,$ret)=map("A$_",(5,7,8,9,1,2));
++($KEYB,$YY,$TX,$tx,$SUM,$dat)=map("B$_",(5,7,8,9,1,2));
++
++$code.=<<___;
++	.text
++
++	.if	.ASSEMBLER_VERSION<7000000
++	.asg	0,__TI_EABI__
++	.endif
++	.if	__TI_EABI__
++	.nocmp
++	.asg	RC4,_RC4
++	.asg	RC4_set_key,_RC4_set_key
++	.asg	RC4_options,_RC4_options
++	.endif
++
++	.global	_RC4
++	.align	16
++_RC4:
++	.asmfunc
++	MV	$LEN,B0
++  [!B0]	BNOP	B3			; if (len==0) return;
++||[B0]	ADD	$KEY,2,$KEYA
++||[B0]	ADD	$KEY,2,$KEYB
++  [B0]	MVK	1,$ONE
++||[B0]	LDBU	*${KEYA}[-2],$XX	; key->x
++  [B0]	LDBU	*${KEYB}[-1],$YY	; key->y
++||	NOP	4
++
++	ADD4	$ONE,$XX,$XX
++	LDBU	*${KEYA}[$XX],$TX
++||	MVC	$LEN,ILC
++	NOP	4
++;;==================================================
++	SPLOOP	7
++||	ADD4	$TX,$YY,$YY
++
++	LDBU	*${KEYB}[$YY],$TY
++||	MVD	$XX,$xx
++||	ADD4	$ONE,$XX,$XX
++	LDBU	*${KEYA}[$XX],$tx
++	CMPEQ	$YY,$XX,B0
++||	NOP	3
++	STB	$TX,*${KEYB}[$YY]
++||[B0]	ADD4	$TX,$YY,$YY
++	STB	$TY,*${KEYA}[$xx]
++||[!B0]	ADD4	$tx,$YY,$YY
++||[!B0]	MVD	$tx,$TX
++	ADD4	$TY,$TX,$SUM		; [0,0] $TX is not replaced by $tx yet!
++||	NOP	2
++	LDBU	*$INP++,$dat
++||	NOP	2
++	LDBU	*${KEYB}[$SUM],$ret
++||	NOP	5
++	XOR.L	$dat,$ret,$ret
++	SPKERNEL
++||	STB	$ret,*$OUT++
++;;==================================================
++	SUB4	$XX,$ONE,$XX
++||	NOP	5
++	STB	$XX,*${KEYA}[-2]	; key->x
++||	SUB4	$YY,$TX,$YY
++||	BNOP	B3	
++	STB	$YY,*${KEYB}[-1]	; key->y
++||	NOP	5
++	.endasmfunc
++
++	.global	_RC4_set_key
++	.align	16
++_RC4_set_key:
++	.asmfunc
++	.if	.BIG_ENDIAN
++	MVK	0x00000404,$ONE
++||	MVK	0x00000203,B0
++	MVKH	0x04040000,$ONE
++||	MVKH	0x00010000,B0
++	.else
++	MVK	0x00000404,$ONE
++||	MVK	0x00000100,B0
++	MVKH	0x04040000,$ONE
++||	MVKH	0x03020000,B0
++	.endif
++	ADD	$KEY,2,$KEYA
++||	ADD	$KEY,2,$KEYB
++||	ADD	$INP,$LEN,$ret		; end of input
++	LDBU	*${INP}++,$dat
++||	MVK	0,$TX
++	STH	$TX,*${KEY}++		; key->x=key->y=0
++||	MV	B0,A0
++||	MVK	64-4,B0
++
++;;==================================================
++	SPLOOPD	1
++||	MVC	B0,ILC
++
++	STNW	A0,*${KEY}++
++||	ADD4	$ONE,A0,A0
++	SPKERNEL
++;;==================================================
++
++	MVK	0,$YY
++||	MVK	0,$XX
++	MVK	1,$ONE
++||	MVK	256-1,B0
++
++;;==================================================
++	SPLOOPD	8
++||	MVC	B0,ILC
++
++	ADD4	$dat,$YY,$YY
++||	CMPEQ	$INP,$ret,A0		; end of input?
++	LDBU	*${KEYB}[$YY],$TY
++||	MVD	$XX,$xx
++||	ADD4	$ONE,$XX,$XX
++	LDBU	*${KEYA}[$XX],$tx
++||[A0]	SUB	$INP,$LEN,$INP		; rewind
++	LDBU	*${INP}++,$dat
++||	CMPEQ	$YY,$XX,B0
++||	NOP	3
++	STB	$TX,*${KEYB}[$YY]
++||[B0]	ADD4	$TX,$YY,$YY
++	STB	$TY,*${KEYA}[$xx]
++||[!B0]	ADD4	$tx,$YY,$YY
++||[!B0]	MV	$tx,$TX
++	SPKERNEL
++;;==================================================
++
++	BNOP	B3,5
++	.endasmfunc
++
++	.global	_RC4_options
++	.align	16
++_RC4_options:
++_rc4_options:
++	.asmfunc
++	BNOP	B3,1
++	ADDKPC	_rc4_options,B4
++	.if	__TI_EABI__
++	MVKL	\$PCR_OFFSET(rc4_options,_rc4_options),A4
++	MVKH	\$PCR_OFFSET(rc4_options,_rc4_options),A4
++	.else
++	MVKL	(rc4_options-_rc4_options),A4
++	MVKH	(rc4_options-_rc4_options),A4
++	.endif
++	ADD	B4,A4,A4
++	.endasmfunc
++
++	.if	__TI_EABI__
++	.sect	".text:rc4_options.const"
++	.else
++	.sect	".const:rc4_options"
++	.endif
++	.align	4
++rc4_options:
++	.cstring "rc4(sploop,char)"
++	.cstring "RC4 for C64+, CRYPTOGAMS by "
++	.align	4
++___
++
++print $code;
++close STDOUT;
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/rc4/asm/rc4-ia64.pl b/CryptoPkg/Library/OpensslLib/openssl/crypto/rc4/asm/rc4-ia64.pl
+new file mode 100644
+index 0000000..5e8f5f5
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/rc4/asm/rc4-ia64.pl
+@@ -0,0 +1,767 @@
++#! /usr/bin/env perl
++# Copyright 2005-2016 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
++# in the file LICENSE in the source distribution or at
++# https://www.openssl.org/source/license.html
++
++#
++# ====================================================================
++# Written by David Mosberger  based on the
++# Itanium optimized Crypto code which was released by HP Labs at
++# http://www.hpl.hp.com/research/linux/crypto/.
++#
++# Copyright (c) 2005 Hewlett-Packard Development Company, L.P.
++#
++# Permission is hereby granted, free of charge, to any person obtaining
++# a copy of this software and associated documentation files (the
++# "Software"), to deal in the Software without restriction, including
++# without limitation the rights to use, copy, modify, merge, publish,
++# distribute, sublicense, and/or sell copies of the Software, and to
++# permit persons to whom the Software is furnished to do so, subject to
++# the following conditions:
++#
++# The above copyright notice and this permission notice shall be
++# included in all copies or substantial portions of the Software.
++
++# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
++# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
++# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
++# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
++# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
++# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
++# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.  */
++
++
++
++# This is a little helper program which generates a software-pipelined
++# for RC4 encryption.  The basic algorithm looks like this:
++#
++#   for (counter = 0; counter < len; ++counter)
++#     {
++#       in = inp[counter];
++#       SI = S[I];
++#       J = (SI + J) & 0xff;
++#       SJ = S[J];
++#       T = (SI + SJ) & 0xff;
++#       S[I] = SJ, S[J] = SI;
++#       ST = S[T];
++#       outp[counter] = in ^ ST;
++#       I = (I + 1) & 0xff;
++#     }
++#
++# Pipelining this loop isn't easy, because the stores to the S[] array
++# need to be observed in the right order.  The loop generated by the
++# code below has the following pipeline diagram:
++#
++#      cycle
++#     | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |10 |11 |12 |13 |14 |15 |16 |17 |
++# iter
++#   1: xxx LDI xxx xxx xxx LDJ xxx SWP xxx LDT xxx xxx
++#   2:             xxx LDI xxx xxx xxx LDJ xxx SWP xxx LDT xxx xxx
++#   3:                         xxx LDI xxx xxx xxx LDJ xxx SWP xxx LDT xxx xxx
++#
++#   where:
++# 	LDI = load of S[I]
++# 	LDJ = load of S[J]
++# 	SWP = swap of S[I] and S[J]
++# 	LDT = load of S[T]
++#
++# Note that in the above diagram, the major trouble-spot is that LDI
++# of the 2nd iteration is performed BEFORE the SWP of the first
++# iteration.  Fortunately, this is easy to detect (I of the 1st
++# iteration will be equal to J of the 2nd iteration) and when this
++# happens, we simply forward the proper value from the 1st iteration
++# to the 2nd one.  The proper value in this case is simply the value
++# of S[I] from the first iteration (thanks to the fact that SWP
++# simply swaps the contents of S[I] and S[J]).
++#
++# Another potential trouble-spot is in cycle 7, where SWP of the 1st
++# iteration issues at the same time as the LDI of the 3rd iteration.
++# However, thanks to IA-64 execution semantics, this can be taken
++# care of simply by placing LDI later in the instruction-group than
++# SWP.  IA-64 CPUs will automatically forward the value if they
++# detect that the SWP and LDI are accessing the same memory-location.
++
++# The core-loop that can be pipelined then looks like this (annotated
++# with McKinley/Madison issue port & latency numbers, assuming L1
++# cache hits for the most part):
++
++# operation:	    instruction:		    issue-ports:  latency
++# ------------------  -----------------------------   ------------- -------
++
++# Data = *inp++       ld1 data = [inp], 1             M0-M1         1 cyc     c0
++#                     shladd Iptr = I, KeyTable, 3    M0-M3, I0, I1 1 cyc
++# I = (I + 1) & 0xff  padd1 nextI = I, one            M0-M3, I0, I1 3 cyc
++#                     ;;
++# SI = S[I]           ld8 SI = [Iptr]                 M0-M1         1 cyc     c1 * after SWAP!
++#                     ;;
++#                     cmp.eq.unc pBypass = I, J                                  * after J is valid!
++# J = SI + J          add J = J, SI                   M0-M3, I0, I1 1 cyc     c2
++#                     (pBypass) br.cond.spnt Bypass
++#                     ;;
++# ---------------------------------------------------------------------------------------
++# J = J & 0xff        zxt1 J = J                      I0, I1, 1 cyc           c3
++#                     ;;
++#                     shladd Jptr = J, KeyTable, 3    M0-M3, I0, I1 1 cyc     c4
++#                     ;;
++# SJ = S[J]           ld8 SJ = [Jptr]                 M0-M1         1 cyc     c5
++#                     ;;
++# ---------------------------------------------------------------------------------------
++# T = (SI + SJ)       add T = SI, SJ                  M0-M3, I0, I1 1 cyc     c6
++#                     ;;
++# T = T & 0xff        zxt1 T = T                      I0, I1        1 cyc
++# S[I] = SJ           st8 [Iptr] = SJ                 M2-M3                   c7
++# S[J] = SI           st8 [Jptr] = SI                 M2-M3
++#                     ;;
++#                     shladd Tptr = T, KeyTable, 3    M0-M3, I0, I1 1 cyc     c8
++#                     ;;
++# ---------------------------------------------------------------------------------------
++# T = S[T]            ld8 T = [Tptr]                  M0-M1         1 cyc     c9
++#                     ;;
++# data ^= T           xor data = data, T              M0-M3, I0, I1 1 cyc     c10
++#                     ;;
++# *out++ = Data ^ T   dep word = word, data, 8, POS   I0, I1        1 cyc     c11
++#                     ;;
++# ---------------------------------------------------------------------------------------
++
++# There are several points worth making here:
++
++#   - Note that due to the bypass/forwarding-path, the first two
++#     phases of the loop are strangly mingled together.  In
++#     particular, note that the first stage of the pipeline is
++#     using the value of "J", as calculated by the second stage.
++#   - Each bundle-pair will have exactly 6 instructions.
++#   - Pipelined, the loop can execute in 3 cycles/iteration and
++#     4 stages.  However, McKinley/Madison can issue "st1" to
++#     the same bank at a rate of at most one per 4 cycles.  Thus,
++#     instead of storing each byte, we accumulate them in a word
++#     and then write them back at once with a single "st8" (this
++#     implies that the setup code needs to ensure that the output
++#     buffer is properly aligned, if need be, by encoding the
++#     first few bytes separately).
++#   - There is no space for a "br.ctop" instruction.  For this
++#     reason we can't use module-loop support in IA-64 and have
++#     to do a traditional, purely software-pipelined loop.
++#   - We can't replace any of the remaining "add/zxt1" pairs with
++#     "padd1" because the latency for that instruction is too high
++#     and would push the loop to the point where more bypasses
++#     would be needed, which we don't have space for.
++#   - The above loop runs at around 3.26 cycles/byte, or roughly
++#     440 MByte/sec on a 1.5GHz Madison.  This is well below the
++#     system bus bandwidth and hence with judicious use of
++#     "lfetch" this loop can run at (almost) peak speed even when
++#     the input and output data reside in memory.  The
++#     max. latency that can be tolerated is (PREFETCH_DISTANCE *
++#     L2_LINE_SIZE * 3 cyc), or about 384 cycles assuming (at
++#     least) 1-ahead prefetching of 128 byte cache-lines.  Note
++#     that we do NOT prefetch into L1, since that would only
++#     interfere with the S[] table values stored there.  This is
++#     acceptable because there is a 10 cycle latency between
++#     load and first use of the input data.
++#   - We use a branch to out-of-line bypass-code of cycle-pressure:
++#     we calculate the next J, check for the need to activate the
++#     bypass path, and activate the bypass path ALL IN THE SAME
++#     CYCLE.  If we didn't have these constraints, we could do
++#     the bypass with a simple conditional move instruction.
++#     Fortunately, the bypass paths get activated relatively
++#     infrequently, so the extra branches don't cost all that much
++#     (about 0.04 cycles/byte, measured on a 16396 byte file with
++#     random input data).
++#
++
++$output = pop;
++open STDOUT,">$output";
++
++$phases = 4;		# number of stages/phases in the pipelined-loop
++$unroll_count = 6;	# number of times we unrolled it
++$pComI = (1 << 0);
++$pComJ = (1 << 1);
++$pComT = (1 << 2);
++$pOut  = (1 << 3);
++
++$NData = 4;
++$NIP = 3;
++$NJP = 2;
++$NI = 2;
++$NSI = 3;
++$NSJ = 2;
++$NT = 2;
++$NOutWord = 2;
++
++#
++# $threshold is the minimum length before we attempt to use the
++# big software-pipelined loop.  It MUST be greater-or-equal
++# to:
++#  		PHASES * (UNROLL_COUNT + 1) + 7
++#
++# The "+ 7" comes from the fact we may have to encode up to
++#   7 bytes separately before the output pointer is aligned.
++#
++$threshold = (3 * ($phases * ($unroll_count + 1)) + 7);
++
++sub I {
++    local *code = shift;
++    local $format = shift;
++    $code .= sprintf ("\t\t".$format."\n", @_);
++}
++
++sub P {
++    local *code = shift;
++    local $format = shift;
++    $code .= sprintf ($format."\n", @_);
++}
++
++sub STOP {
++    local *code = shift;
++    $code .=<<___;
++		;;
++___
++}
++
++sub emit_body {
++    local *c = shift;
++    local *bypass = shift;
++    local ($iteration, $p) = @_;
++
++    local $i0 = $iteration;
++    local $i1 = $iteration - 1;
++    local $i2 = $iteration - 2;
++    local $i3 = $iteration - 3;
++    local $iw0 = ($iteration - 3) / 8;
++    local $iw1 = ($iteration > 3) ? ($iteration - 4) / 8 : 1;
++    local $byte_num = ($iteration - 3) % 8;
++    local $label = $iteration + 1;
++    local $pAny = ($p & 0xf) == 0xf;
++    local $pByp = (($p & $pComI) && ($iteration > 0));
++
++    $c.=<<___;
++//////////////////////////////////////////////////
++___
++
++    if (($p & 0xf) == 0) {
++	$c.="#ifdef HOST_IS_BIG_ENDIAN\n";
++	&I(\$c,"shr.u	OutWord[%u] = OutWord[%u], 32;;",
++				$iw1 % $NOutWord, $iw1 % $NOutWord);
++	$c.="#endif\n";
++	&I(\$c, "st4 [OutPtr] = OutWord[%u], 4", $iw1 % $NOutWord);
++	return;
++    }
++
++    # Cycle 0
++    &I(\$c, "{ .mmi")					      if ($pAny);
++    &I(\$c, "ld1    Data[%u] = [InPtr], 1", $i0 % $NData)     if ($p & $pComI);
++    &I(\$c, "padd1  I[%u] = One, I[%u]", $i0 % $NI, $i1 % $NI)if ($p & $pComI);
++    &I(\$c, "zxt1   J = J")				      if ($p & $pComJ);
++    &I(\$c, "}")					      if ($pAny);
++    &I(\$c, "{ .mmi")					      if ($pAny);
++    &I(\$c, "LKEY   T[%u] = [T[%u]]", $i1 % $NT, $i1 % $NT)   if ($p & $pOut);
++    &I(\$c, "add    T[%u] = SI[%u], SJ[%u]",
++       $i0 % $NT, $i2 % $NSI, $i1 % $NSJ)		      if ($p & $pComT);
++    &I(\$c, "KEYADDR(IPr[%u], I[%u])", $i0 % $NIP, $i1 % $NI) if ($p & $pComI);
++    &I(\$c, "}")					      if ($pAny);
++    &STOP(\$c);
++
++    # Cycle 1
++    &I(\$c, "{ .mmi")					      if ($pAny);
++    &I(\$c, "SKEY   [IPr[%u]] = SJ[%u]", $i2 % $NIP, $i1%$NSJ)if ($p & $pComT);
++    &I(\$c, "SKEY   [JP[%u]] = SI[%u]", $i1 % $NJP, $i2%$NSI) if ($p & $pComT);
++    &I(\$c, "zxt1   T[%u] = T[%u]", $i0 % $NT, $i0 % $NT)     if ($p & $pComT);
++    &I(\$c, "}")					      if ($pAny);
++    &I(\$c, "{ .mmi")					      if ($pAny);
++    &I(\$c, "LKEY   SI[%u] = [IPr[%u]]", $i0 % $NSI, $i0%$NIP)if ($p & $pComI);
++    &I(\$c, "KEYADDR(JP[%u], J)", $i0 % $NJP)		      if ($p & $pComJ);
++    &I(\$c, "xor    Data[%u] = Data[%u], T[%u]",
++       $i3 % $NData, $i3 % $NData, $i1 % $NT)		      if ($p & $pOut);
++    &I(\$c, "}")					      if ($pAny);
++    &STOP(\$c);
++
++    # Cycle 2
++    &I(\$c, "{ .mmi")					      if ($pAny);
++    &I(\$c, "LKEY   SJ[%u] = [JP[%u]]", $i0 % $NSJ, $i0%$NJP) if ($p & $pComJ);
++    &I(\$c, "cmp.eq pBypass, p0 = I[%u], J", $i1 % $NI)	      if ($pByp);
++    &I(\$c, "dep OutWord[%u] = Data[%u], OutWord[%u], BYTE_POS(%u), 8",
++       $iw0%$NOutWord, $i3%$NData, $iw1%$NOutWord, $byte_num) if ($p & $pOut);
++    &I(\$c, "}")					      if ($pAny);
++    &I(\$c, "{ .mmb")					      if ($pAny);
++    &I(\$c, "add    J = J, SI[%u]", $i0 % $NSI)		      if ($p & $pComI);
++    &I(\$c, "KEYADDR(T[%u], T[%u])", $i0 % $NT, $i0 % $NT)    if ($p & $pComT);
++    &P(\$c, "(pBypass)\tbr.cond.spnt.many .rc4Bypass%u",$label)if ($pByp);
++    &I(\$c, "}") if ($pAny);
++    &STOP(\$c);
++
++    &P(\$c, ".rc4Resume%u:", $label)			      if ($pByp);
++    if ($byte_num == 0 && $iteration >= $phases) {
++	&I(\$c, "st8 [OutPtr] = OutWord[%u], 8",
++	   $iw1 % $NOutWord)				      if ($p & $pOut);
++	if ($iteration == (1 + $unroll_count) * $phases - 1) {
++	    if ($unroll_count == 6) {
++		&I(\$c, "mov OutWord[%u] = OutWord[%u]",
++		   $iw1 % $NOutWord, $iw0 % $NOutWord);
++	    }
++	    &I(\$c, "lfetch.nt1 [InPrefetch], %u",
++	       $unroll_count * $phases);
++	    &I(\$c, "lfetch.excl.nt1 [OutPrefetch], %u",
++	       $unroll_count * $phases);
++	    &I(\$c, "br.cloop.sptk.few .rc4Loop");
++	}
++    }
++
++    if ($pByp) {
++	&P(\$bypass, ".rc4Bypass%u:", $label);
++	&I(\$bypass, "sub J = J, SI[%u]", $i0 % $NSI);
++	&I(\$bypass, "nop 0");
++	&I(\$bypass, "nop 0");
++	&I(\$bypass, ";;");
++	&I(\$bypass, "add J = J, SI[%u]", $i1 % $NSI);
++	&I(\$bypass, "mov SI[%u] = SI[%u]", $i0 % $NSI, $i1 % $NSI);
++	&I(\$bypass, "br.sptk.many .rc4Resume%u\n", $label);
++	&I(\$bypass, ";;");
++    }
++}
++
++$code=<<___;
++.ident \"rc4-ia64.s, version 3.0\"
++.ident \"Copyright (c) 2005 Hewlett-Packard Development Company, L.P.\"
++
++#define LCSave		r8
++#define PRSave		r9
++
++/* Inputs become invalid once rotation begins!  */
++
++#define StateTable	in0
++#define DataLen		in1
++#define InputBuffer	in2
++#define OutputBuffer	in3
++
++#define KTable		r14
++#define J		r15
++#define InPtr		r16
++#define OutPtr		r17
++#define InPrefetch	r18
++#define OutPrefetch	r19
++#define One		r20
++#define LoopCount	r21
++#define Remainder	r22
++#define IFinal		r23
++#define EndPtr		r24
++
++#define tmp0		r25
++#define tmp1		r26
++
++#define pBypass		p6
++#define pDone		p7
++#define pSmall		p8
++#define pAligned	p9
++#define pUnaligned	p10
++
++#define pComputeI	pPhase[0]
++#define pComputeJ	pPhase[1]
++#define pComputeT	pPhase[2]
++#define pOutput		pPhase[3]
++
++#define RetVal		r8
++#define L_OK		p7
++#define L_NOK		p8
++
++#define	_NINPUTS	4
++#define	_NOUTPUT	0
++
++#define	_NROTATE	24
++#define	_NLOCALS	(_NROTATE - _NINPUTS - _NOUTPUT)
++
++#ifndef SZ
++# define SZ	4	// this must be set to sizeof(RC4_INT)
++#endif
++
++#if SZ == 1
++# define LKEY			ld1
++# define SKEY			st1
++# define KEYADDR(dst, i)	add dst = i, KTable
++#elif SZ == 2
++# define LKEY			ld2
++# define SKEY			st2
++# define KEYADDR(dst, i)	shladd dst = i, 1, KTable
++#elif SZ == 4
++# define LKEY			ld4
++# define SKEY			st4
++# define KEYADDR(dst, i)	shladd dst = i, 2, KTable
++#else
++# define LKEY			ld8
++# define SKEY			st8
++# define KEYADDR(dst, i)	shladd dst = i, 3, KTable
++#endif
++
++#if defined(_HPUX_SOURCE) && !defined(_LP64)
++# define ADDP	addp4
++#else
++# define ADDP	add
++#endif
++
++/* Define a macro for the bit number of the n-th byte: */
++
++#if defined(_HPUX_SOURCE) || defined(B_ENDIAN)
++# define HOST_IS_BIG_ENDIAN
++# define BYTE_POS(n)	(56 - (8 * (n)))
++#else
++# define BYTE_POS(n)	(8 * (n))
++#endif
++
++/*
++   We must perform the first phase of the pipeline explicitly since
++   we will always load from the stable the first time. The br.cexit
++   will never be taken since regardless of the number of bytes because
++   the epilogue count is 4.
++*/
++/* MODSCHED_RC4 macro was split to _PROLOGUE and _LOOP, because HP-UX
++   assembler failed on original macro with syntax error.  */
++#define MODSCHED_RC4_PROLOGUE						   \\
++	{								   \\
++				ld1		Data[0] = [InPtr], 1;	   \\
++				add		IFinal = 1, I[1];	   \\
++				KEYADDR(IPr[0], I[1]);			   \\
++	} ;;								   \\
++	{								   \\
++				LKEY		SI[0] = [IPr[0]];	   \\
++				mov		pr.rot = 0x10000;	   \\
++				mov		ar.ec = 4;		   \\
++	} ;;								   \\
++	{								   \\
++				add		J = J, SI[0];		   \\
++				zxt1		I[0] = IFinal;		   \\
++				br.cexit.spnt.few .+16; /* never taken */  \\
++	} ;;
++#define MODSCHED_RC4_LOOP(label)					   \\
++label:									   \\
++	{	.mmi;							   \\
++		(pComputeI)	ld1		Data[0] = [InPtr], 1;	   \\
++		(pComputeI)	add		IFinal = 1, I[1];	   \\
++		(pComputeJ)	zxt1		J = J;			   \\
++	}{	.mmi;							   \\
++		(pOutput)	LKEY		T[1] = [T[1]];		   \\
++		(pComputeT)	add		T[0] = SI[2], SJ[1];	   \\
++		(pComputeI)	KEYADDR(IPr[0], I[1]);			   \\
++	} ;;								   \\
++	{	.mmi;							   \\
++		(pComputeT)	SKEY		[IPr[2]] = SJ[1];	   \\
++		(pComputeT)	SKEY		[JP[1]] = SI[2];	   \\
++		(pComputeT)	zxt1		T[0] = T[0];		   \\
++	}{	.mmi;							   \\
++		(pComputeI)	LKEY		SI[0] = [IPr[0]];	   \\
++		(pComputeJ)	KEYADDR(JP[0], J);			   \\
++		(pComputeI)	cmp.eq.unc	pBypass, p0 = I[1], J;	   \\
++	} ;;								   \\
++	{	.mmi;							   \\
++		(pComputeJ)	LKEY		SJ[0] = [JP[0]];	   \\
++		(pOutput)	xor		Data[3] = Data[3], T[1];   \\
++				nop		0x0;			   \\
++	}{	.mmi;							   \\
++		(pComputeT)	KEYADDR(T[0], T[0]);			   \\
++		(pBypass)	mov		SI[0] = SI[1];		   \\
++		(pComputeI)	zxt1		I[0] = IFinal;		   \\
++	} ;;								   \\
++	{	.mmb;							   \\
++		(pOutput)	st1		[OutPtr] = Data[3], 1;	   \\
++		(pComputeI)	add		J = J, SI[0];		   \\
++				br.ctop.sptk.few label;			   \\
++	} ;;
++
++	.text
++
++	.align	32
++
++	.type	RC4, \@function
++	.global	RC4
++
++	.proc	RC4
++	.prologue
++
++RC4:
++	{
++	  	.mmi
++		alloc	r2 = ar.pfs, _NINPUTS, _NLOCALS, _NOUTPUT, _NROTATE
++
++		.rotr Data[4], I[2], IPr[3], SI[3], JP[2], SJ[2], T[2], \\
++		      OutWord[2]
++		.rotp pPhase[4]
++
++		ADDP		InPrefetch = 0, InputBuffer
++		ADDP		KTable = 0, StateTable
++	}
++	{
++		.mmi
++		ADDP		InPtr = 0, InputBuffer
++		ADDP		OutPtr = 0, OutputBuffer
++		mov		RetVal = r0
++	}
++	;;
++	{
++		.mmi
++		lfetch.nt1	[InPrefetch], 0x80
++		ADDP		OutPrefetch = 0, OutputBuffer
++	}
++	{               // Return 0 if the input length is nonsensical
++        	.mib
++		ADDP		StateTable = 0, StateTable
++        	cmp.ge.unc  	L_NOK, L_OK = r0, DataLen
++	(L_NOK) br.ret.sptk.few rp
++	}
++	;;
++	{
++        	.mib
++        	cmp.eq.or  	L_NOK, L_OK = r0, InPtr
++        	cmp.eq.or  	L_NOK, L_OK = r0, OutPtr
++		nop		0x0
++	}
++	{
++		.mib
++        	cmp.eq.or  	L_NOK, L_OK = r0, StateTable
++		nop		0x0
++	(L_NOK) br.ret.sptk.few rp
++	}
++	;;
++		LKEY		I[1] = [KTable], SZ
++/* Prefetch the state-table. It contains 256 elements of size SZ */
++
++#if SZ == 1
++		ADDP		tmp0 = 1*128, StateTable
++#elif SZ == 2
++		ADDP		tmp0 = 3*128, StateTable
++		ADDP		tmp1 = 2*128, StateTable
++#elif SZ == 4
++		ADDP		tmp0 = 7*128, StateTable
++		ADDP		tmp1 = 6*128, StateTable
++#elif SZ == 8
++		ADDP		tmp0 = 15*128, StateTable
++		ADDP		tmp1 = 14*128, StateTable
++#endif
++		;;
++#if SZ >= 8
++		lfetch.fault.nt1		[tmp0], -256	// 15
++		lfetch.fault.nt1		[tmp1], -256;;
++		lfetch.fault.nt1		[tmp0], -256	// 13
++		lfetch.fault.nt1		[tmp1], -256;;
++		lfetch.fault.nt1		[tmp0], -256	// 11
++		lfetch.fault.nt1		[tmp1], -256;;
++		lfetch.fault.nt1		[tmp0], -256	//  9
++		lfetch.fault.nt1		[tmp1], -256;;
++#endif
++#if SZ >= 4
++		lfetch.fault.nt1		[tmp0], -256	//  7
++		lfetch.fault.nt1		[tmp1], -256;;
++		lfetch.fault.nt1		[tmp0], -256	//  5
++		lfetch.fault.nt1		[tmp1], -256;;
++#endif
++#if SZ >= 2
++		lfetch.fault.nt1		[tmp0], -256	//  3
++		lfetch.fault.nt1		[tmp1], -256;;
++#endif
++	{
++		.mii
++		lfetch.fault.nt1		[tmp0]		//  1
++		add		I[1]=1,I[1];;
++		zxt1		I[1]=I[1]
++	}
++	{
++		.mmi
++		lfetch.nt1	[InPrefetch], 0x80
++		lfetch.excl.nt1	[OutPrefetch], 0x80
++		.save		pr, PRSave
++		mov		PRSave = pr
++	} ;;
++	{
++		.mmi
++		lfetch.excl.nt1	[OutPrefetch], 0x80
++		LKEY		J = [KTable], SZ
++		ADDP		EndPtr = DataLen, InPtr
++	}  ;;
++	{
++		.mmi
++		ADDP		EndPtr = -1, EndPtr	// Make it point to
++							// last data byte.
++		mov		One = 1
++		.save		ar.lc, LCSave
++		mov		LCSave = ar.lc
++		.body
++	} ;;
++	{
++		.mmb
++		sub		Remainder = 0, OutPtr
++		cmp.gtu		pSmall, p0 = $threshold, DataLen
++(pSmall)	br.cond.dpnt	.rc4Remainder		// Data too small for
++							// big loop.
++	} ;;
++	{
++		.mmi
++		and		Remainder = 0x7, Remainder
++		;;
++		cmp.eq		pAligned, pUnaligned = Remainder, r0
++		nop		0x0
++	} ;;
++	{
++		.mmb
++.pred.rel	"mutex",pUnaligned,pAligned
++(pUnaligned)	add		Remainder = -1, Remainder
++(pAligned)	sub		Remainder = EndPtr, InPtr
++(pAligned)	br.cond.dptk.many .rc4Aligned
++	} ;;
++	{
++		.mmi
++		nop		0x0
++		nop		0x0
++		mov.i		ar.lc = Remainder
++	}
++
++/* Do the initial few bytes via the compact, modulo-scheduled loop
++   until the output pointer is 8-byte-aligned.  */
++
++		MODSCHED_RC4_PROLOGUE
++		MODSCHED_RC4_LOOP(.RC4AlignLoop)
++
++	{
++		.mib
++		sub		Remainder = EndPtr, InPtr
++		zxt1		IFinal = IFinal
++		clrrrb				// Clear CFM.rrb.pr so
++		;;				// next "mov pr.rot = N"
++						// does the right thing.
++	}
++	{
++		.mmi
++		mov		I[1] = IFinal
++		nop		0x0
++		nop		0x0
++	} ;;
++
++
++.rc4Aligned:
++
++/*
++   Unrolled loop count = (Remainder - ($unroll_count+1)*$phases)/($unroll_count*$phases)
++ */
++
++	{
++		.mlx
++		add	LoopCount = 1 - ($unroll_count + 1)*$phases, Remainder
++		movl		Remainder = 0xaaaaaaaaaaaaaaab
++	} ;;
++	{
++		.mmi
++		setf.sig	f6 = LoopCount		// M2, M3	6 cyc
++		setf.sig	f7 = Remainder		// M2, M3	6 cyc
++		nop		0x0
++	} ;;
++	{
++		.mfb
++		nop		0x0
++		xmpy.hu		f6 = f6, f7
++		nop		0x0
++	} ;;
++	{
++		.mmi
++		getf.sig	LoopCount = f6;;	// M2		5 cyc
++		nop		0x0
++		shr.u		LoopCount = LoopCount, 4
++	} ;;
++	{
++		.mmi
++		nop		0x0
++		nop		0x0
++		mov.i		ar.lc = LoopCount
++	} ;;
++
++/* Now comes the unrolled loop: */
++
++.rc4Prologue:
++___
++
++$iteration = 0;
++
++# Generate the prologue:
++$predicates = 1;
++for ($i = 0; $i < $phases; ++$i) {
++    &emit_body (\$code, \$bypass, $iteration++, $predicates);
++    $predicates = ($predicates << 1) | 1;
++}
++
++$code.=<<___;
++.rc4Loop:
++___
++
++# Generate the body:
++for ($i = 0; $i < $unroll_count*$phases; ++$i) {
++    &emit_body (\$code, \$bypass, $iteration++, $predicates);
++}
++
++$code.=<<___;
++.rc4Epilogue:
++___
++
++# Generate the epilogue:
++for ($i = 0; $i < $phases; ++$i) {
++    $predicates <<= 1;
++    &emit_body (\$code, \$bypass, $iteration++, $predicates);
++}
++
++$code.=<<___;
++	{
++		.mmi
++		lfetch.nt1	[EndPtr]	// fetch line with last byte
++		mov		IFinal = I[1]
++		nop		0x0
++	}
++
++.rc4Remainder:
++	{
++		.mmi
++		sub		Remainder = EndPtr, InPtr	// Calculate
++								// # of bytes
++								// left - 1
++		nop		0x0
++		nop		0x0
++	} ;;
++	{
++		.mib
++		cmp.eq		pDone, p0 = -1, Remainder // done already?
++		mov.i		ar.lc = Remainder
++(pDone)		br.cond.dptk.few .rc4Complete
++	}
++
++/* Do the remaining bytes via the compact, modulo-scheduled loop */
++
++		MODSCHED_RC4_PROLOGUE
++		MODSCHED_RC4_LOOP(.RC4RestLoop)
++
++.rc4Complete:
++	{
++		.mmi
++		add		KTable = -SZ, KTable
++		add		IFinal = -1, IFinal
++		mov		ar.lc = LCSave
++	} ;;
++	{
++		.mii
++		SKEY		[KTable] = J,-SZ
++		zxt1		IFinal = IFinal
++		mov		pr = PRSave, 0x1FFFF
++	} ;;
++	{
++		.mib
++		SKEY		[KTable] = IFinal
++		add		RetVal = 1, r0
++		br.ret.sptk.few	rp
++	} ;;
++___
++
++# Last but not least, emit the code for the bypass-code of the unrolled loop:
++
++$code.=$bypass;
++
++$code.=<<___;
++	.endp RC4
++___
++
++print $code;
++
++close STDOUT;
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/rc4/asm/rc4-md5-x86_64.pl b/CryptoPkg/Library/OpensslLib/openssl/crypto/rc4/asm/rc4-md5-x86_64.pl
+new file mode 100644
+index 0000000..890161b
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/rc4/asm/rc4-md5-x86_64.pl
+@@ -0,0 +1,645 @@
++#! /usr/bin/env perl
++# Copyright 2011-2016 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
++# in the file LICENSE in the source distribution or at
++# https://www.openssl.org/source/license.html
++
++#
++# ====================================================================
++# Written by Andy Polyakov  for the OpenSSL
++# project. The module is, however, dual licensed under OpenSSL and
++# CRYPTOGAMS licenses depending on where you obtain it. For further
++# details see http://www.openssl.org/~appro/cryptogams/.
++# ====================================================================
++
++# June 2011
++#
++# This is RC4+MD5 "stitch" implementation. The idea, as spelled in
++# http://download.intel.com/design/intarch/papers/323686.pdf, is that
++# since both algorithms exhibit instruction-level parallelism, ILP,
++# below theoretical maximum, interleaving them would allow to utilize
++# processor resources better and achieve better performance. RC4
++# instruction sequence is virtually identical to rc4-x86_64.pl, which
++# is heavily based on submission by Maxim Perminov, Maxim Locktyukhin
++# and Jim Guilford of Intel. MD5 is fresh implementation aiming to
++# minimize register usage, which was used as "main thread" with RC4
++# weaved into it, one RC4 round per one MD5 round. In addition to the
++# stiched subroutine the script can generate standalone replacement
++# md5_block_asm_data_order and RC4. Below are performance numbers in
++# cycles per processed byte, less is better, for these the standalone
++# subroutines, sum of them, and stitched one:
++#
++#		RC4	MD5	RC4+MD5	stitch	gain
++# Opteron	6.5(*)	5.4	11.9	7.0	+70%(*)
++# Core2		6.5	5.8	12.3	7.7	+60%
++# Westmere	4.3	5.2	9.5	7.0	+36%
++# Sandy Bridge	4.2	5.5	9.7	6.8	+43%
++# Ivy Bridge	4.1	5.2	9.3	6.0	+54%
++# Haswell	4.0	5.0	9.0	5.7	+60%
++# Skylake	6.3(**)	5.0	11.3	5.3	+110%
++# Atom		9.3	6.5	15.8	11.1	+42%
++# VIA Nano	6.3	5.4	11.7	8.6	+37%
++# Bulldozer	4.5	5.4	9.9	7.7	+29%
++#
++# (*)	rc4-x86_64.pl delivers 5.3 on Opteron, so real improvement
++#	is +53%...
++# (**)	unidentified anomaly;
++
++my ($rc4,$md5)=(1,1);	# what to generate?
++my $D="#" if (!$md5);	# if set to "#", MD5 is stitched into RC4(),
++			# but its result is discarded. Idea here is
++			# to be able to use 'openssl speed rc4' for
++			# benchmarking the stitched subroutine... 
++
++my $flavour = shift;
++my $output  = shift;
++if ($flavour =~ /\./) { $output = $flavour; undef $flavour; }
++
++my $win64=0; $win64=1 if ($flavour =~ /[nm]asm|mingw64/ || $output =~ /\.asm$/);
++
++$0 =~ m/(.*[\/\\])[^\/\\]+$/; my $dir=$1; my $xlate;
++( $xlate="${dir}x86_64-xlate.pl" and -f $xlate ) or
++( $xlate="${dir}../../perlasm/x86_64-xlate.pl" and -f $xlate) or
++die "can't locate x86_64-xlate.pl";
++
++open OUT,"| \"$^X\" \"$xlate\" $flavour \"$output\"";
++*STDOUT=*OUT;
++
++my ($dat,$in0,$out,$ctx,$inp,$len, $func,$nargs);
++
++if ($rc4 && !$md5) {
++  ($dat,$len,$in0,$out) = ("%rdi","%rsi","%rdx","%rcx");
++  $func="RC4";				$nargs=4;
++} elsif ($md5 && !$rc4) {
++  ($ctx,$inp,$len) = ("%rdi","%rsi","%rdx");
++  $func="md5_block_asm_data_order";	$nargs=3;
++} else {
++  ($dat,$in0,$out,$ctx,$inp,$len) = ("%rdi","%rsi","%rdx","%rcx","%r8","%r9");
++  $func="rc4_md5_enc";			$nargs=6;
++  # void rc4_md5_enc(
++  #		RC4_KEY *key,		#
++  #		const void *in0,	# RC4 input
++  #		void *out,		# RC4 output
++  #		MD5_CTX *ctx,		#
++  #		const void *inp,	# MD5 input
++  #		size_t len);		# number of 64-byte blocks
++}
++
++my @K=(	0xd76aa478,0xe8c7b756,0x242070db,0xc1bdceee,
++	0xf57c0faf,0x4787c62a,0xa8304613,0xfd469501,
++	0x698098d8,0x8b44f7af,0xffff5bb1,0x895cd7be,
++	0x6b901122,0xfd987193,0xa679438e,0x49b40821,
++
++	0xf61e2562,0xc040b340,0x265e5a51,0xe9b6c7aa,
++	0xd62f105d,0x02441453,0xd8a1e681,0xe7d3fbc8,
++	0x21e1cde6,0xc33707d6,0xf4d50d87,0x455a14ed,
++	0xa9e3e905,0xfcefa3f8,0x676f02d9,0x8d2a4c8a,
++
++	0xfffa3942,0x8771f681,0x6d9d6122,0xfde5380c,
++	0xa4beea44,0x4bdecfa9,0xf6bb4b60,0xbebfbc70,
++	0x289b7ec6,0xeaa127fa,0xd4ef3085,0x04881d05,
++	0xd9d4d039,0xe6db99e5,0x1fa27cf8,0xc4ac5665,
++
++	0xf4292244,0x432aff97,0xab9423a7,0xfc93a039,
++	0x655b59c3,0x8f0ccc92,0xffeff47d,0x85845dd1,
++	0x6fa87e4f,0xfe2ce6e0,0xa3014314,0x4e0811a1,
++	0xf7537e82,0xbd3af235,0x2ad7d2bb,0xeb86d391	);
++
++my @V=("%r8d","%r9d","%r10d","%r11d");	# MD5 registers
++my $tmp="%r12d";
++
++my @XX=("%rbp","%rsi");			# RC4 registers
++my @TX=("%rax","%rbx");
++my $YY="%rcx";
++my $TY="%rdx";
++
++my $MOD=32;				# 16, 32 or 64
++
++$code.=<<___;
++.text
++.align 16
++
++.globl	$func
++.type	$func,\@function,$nargs
++$func:
++	cmp	\$0,$len
++	je	.Labort
++	push	%rbx
++	push	%rbp
++	push	%r12
++	push	%r13
++	push	%r14
++	push	%r15
++	sub	\$40,%rsp
++.Lbody:
++___
++if ($rc4) {
++$code.=<<___;
++$D#md5#	mov	$ctx,%r11		# reassign arguments
++	mov	$len,%r12
++	mov	$in0,%r13
++	mov	$out,%r14
++$D#md5#	mov	$inp,%r15
++___
++    $ctx="%r11"	if ($md5);		# reassign arguments
++    $len="%r12";
++    $in0="%r13";
++    $out="%r14";
++    $inp="%r15"	if ($md5);
++    $inp=$in0	if (!$md5);
++$code.=<<___;
++	xor	$XX[0],$XX[0]
++	xor	$YY,$YY
++
++	lea	8($dat),$dat
++	mov	-8($dat),$XX[0]#b
++	mov	-4($dat),$YY#b
++
++	inc	$XX[0]#b
++	sub	$in0,$out
++	movl	($dat,$XX[0],4),$TX[0]#d
++___
++$code.=<<___ if (!$md5);
++	xor	$TX[1],$TX[1]
++	test	\$-128,$len
++	jz	.Loop1
++	sub	$XX[0],$TX[1]
++	and	\$`$MOD-1`,$TX[1]
++	jz	.Loop${MOD}_is_hot
++	sub	$TX[1],$len
++.Loop${MOD}_warmup:
++	add	$TX[0]#b,$YY#b
++	movl	($dat,$YY,4),$TY#d
++	movl	$TX[0]#d,($dat,$YY,4)
++	movl	$TY#d,($dat,$XX[0],4)
++	add	$TY#b,$TX[0]#b
++	inc	$XX[0]#b
++	movl	($dat,$TX[0],4),$TY#d
++	movl	($dat,$XX[0],4),$TX[0]#d
++	xorb	($in0),$TY#b
++	movb	$TY#b,($out,$in0)
++	lea	1($in0),$in0
++	dec	$TX[1]
++	jnz	.Loop${MOD}_warmup
++
++	mov	$YY,$TX[1]
++	xor	$YY,$YY
++	mov	$TX[1]#b,$YY#b
++
++.Loop${MOD}_is_hot:
++	mov	$len,32(%rsp)		# save original $len
++	shr	\$6,$len		# number of 64-byte blocks
++___
++  if ($D && !$md5) {			# stitch in dummy MD5
++    $md5=1;
++    $ctx="%r11";
++    $inp="%r15";
++    $code.=<<___;
++	mov	%rsp,$ctx
++	mov	$in0,$inp
++___
++  }
++}
++$code.=<<___;
++#rc4#	add	$TX[0]#b,$YY#b
++#rc4#	lea	($dat,$XX[0],4),$XX[1]
++	shl	\$6,$len
++	add	$inp,$len		# pointer to the end of input
++	mov	$len,16(%rsp)
++
++#md5#	mov	$ctx,24(%rsp)		# save pointer to MD5_CTX
++#md5#	mov	0*4($ctx),$V[0]		# load current hash value from MD5_CTX
++#md5#	mov	1*4($ctx),$V[1]
++#md5#	mov	2*4($ctx),$V[2]
++#md5#	mov	3*4($ctx),$V[3]
++	jmp	.Loop
++
++.align	16
++.Loop:
++#md5#	mov	$V[0],0*4(%rsp)		# put aside current hash value
++#md5#	mov	$V[1],1*4(%rsp)
++#md5#	mov	$V[2],2*4(%rsp)
++#md5#	mov	$V[3],$tmp		# forward reference
++#md5#	mov	$V[3],3*4(%rsp)
++___
++
++sub R0 {
++  my ($i,$a,$b,$c,$d)=@_;
++  my @rot0=(7,12,17,22);
++  my $j=$i%16;
++  my $k=$i%$MOD;
++  my $xmm="%xmm".($j&1);
++    $code.="	movdqu	($in0),%xmm2\n"		if ($rc4 && $j==15);
++    $code.="	add	\$$MOD,$XX[0]#b\n"	if ($rc4 && $j==15 && $k==$MOD-1);
++    $code.="	pxor	$xmm,$xmm\n"		if ($rc4 && $j<=1);
++    $code.=<<___;
++#rc4#	movl	($dat,$YY,4),$TY#d
++#md5#	xor	$c,$tmp
++#rc4#	movl	$TX[0]#d,($dat,$YY,4)
++#md5#	and	$b,$tmp
++#md5#	add	4*`$j`($inp),$a
++#rc4#	add	$TY#b,$TX[0]#b
++#rc4#	movl	`4*(($k+1)%$MOD)`(`$k==$MOD-1?"$dat,$XX[0],4":"$XX[1]"`),$TX[1]#d
++#md5#	add	\$$K[$i],$a
++#md5#	xor	$d,$tmp
++#rc4#	movz	$TX[0]#b,$TX[0]#d
++#rc4#	movl	$TY#d,4*$k($XX[1])
++#md5#	add	$tmp,$a
++#rc4#	add	$TX[1]#b,$YY#b
++#md5#	rol	\$$rot0[$j%4],$a
++#md5#	mov	`$j==15?"$b":"$c"`,$tmp		# forward reference
++#rc4#	pinsrw	\$`($j>>1)&7`,($dat,$TX[0],4),$xmm\n
++#md5#	add	$b,$a
++___
++    $code.=<<___ if ($rc4 && $j==15 && $k==$MOD-1);
++	mov	$YY,$XX[1]
++	xor	$YY,$YY				# keyword to partial register
++	mov	$XX[1]#b,$YY#b
++	lea	($dat,$XX[0],4),$XX[1]
++___
++    $code.=<<___ if ($rc4 && $j==15);
++	psllq	\$8,%xmm1
++	pxor	%xmm0,%xmm2
++	pxor	%xmm1,%xmm2
++___
++}
++sub R1 {
++  my ($i,$a,$b,$c,$d)=@_;
++  my @rot1=(5,9,14,20);
++  my $j=$i%16;
++  my $k=$i%$MOD;
++  my $xmm="%xmm".($j&1);
++    $code.="	movdqu	16($in0),%xmm3\n"	if ($rc4 && $j==15);
++    $code.="	add	\$$MOD,$XX[0]#b\n"	if ($rc4 && $j==15 && $k==$MOD-1);
++    $code.="	pxor	$xmm,$xmm\n"		if ($rc4 && $j<=1);
++    $code.=<<___;
++#rc4#	movl	($dat,$YY,4),$TY#d
++#md5#	xor	$b,$tmp
++#rc4#	movl	$TX[0]#d,($dat,$YY,4)
++#md5#	and	$d,$tmp
++#md5#	add	4*`((1+5*$j)%16)`($inp),$a
++#rc4#	add	$TY#b,$TX[0]#b
++#rc4#	movl	`4*(($k+1)%$MOD)`(`$k==$MOD-1?"$dat,$XX[0],4":"$XX[1]"`),$TX[1]#d
++#md5#	add	\$$K[$i],$a
++#md5#	xor	$c,$tmp
++#rc4#	movz	$TX[0]#b,$TX[0]#d
++#rc4#	movl	$TY#d,4*$k($XX[1])
++#md5#	add	$tmp,$a
++#rc4#	add	$TX[1]#b,$YY#b
++#md5#	rol	\$$rot1[$j%4],$a
++#md5#	mov	`$j==15?"$c":"$b"`,$tmp		# forward reference
++#rc4#	pinsrw	\$`($j>>1)&7`,($dat,$TX[0],4),$xmm\n
++#md5#	add	$b,$a
++___
++    $code.=<<___ if ($rc4 && $j==15 && $k==$MOD-1);
++	mov	$YY,$XX[1]
++	xor	$YY,$YY				# keyword to partial register
++	mov	$XX[1]#b,$YY#b
++	lea	($dat,$XX[0],4),$XX[1]
++___
++    $code.=<<___ if ($rc4 && $j==15);
++	psllq	\$8,%xmm1
++	pxor	%xmm0,%xmm3
++	pxor	%xmm1,%xmm3
++___
++}
++sub R2 {
++  my ($i,$a,$b,$c,$d)=@_;
++  my @rot2=(4,11,16,23);
++  my $j=$i%16;
++  my $k=$i%$MOD;
++  my $xmm="%xmm".($j&1);
++    $code.="	movdqu	32($in0),%xmm4\n"	if ($rc4 && $j==15);
++    $code.="	add	\$$MOD,$XX[0]#b\n"	if ($rc4 && $j==15 && $k==$MOD-1);
++    $code.="	pxor	$xmm,$xmm\n"		if ($rc4 && $j<=1);
++    $code.=<<___;
++#rc4#	movl	($dat,$YY,4),$TY#d
++#md5#	xor	$c,$tmp
++#rc4#	movl	$TX[0]#d,($dat,$YY,4)
++#md5#	xor	$b,$tmp
++#md5#	add	4*`((5+3*$j)%16)`($inp),$a
++#rc4#	add	$TY#b,$TX[0]#b
++#rc4#	movl	`4*(($k+1)%$MOD)`(`$k==$MOD-1?"$dat,$XX[0],4":"$XX[1]"`),$TX[1]#d
++#md5#	add	\$$K[$i],$a
++#rc4#	movz	$TX[0]#b,$TX[0]#d
++#md5#	add	$tmp,$a
++#rc4#	movl	$TY#d,4*$k($XX[1])
++#rc4#	add	$TX[1]#b,$YY#b
++#md5#	rol	\$$rot2[$j%4],$a
++#md5#	mov	`$j==15?"\\\$-1":"$c"`,$tmp	# forward reference
++#rc4#	pinsrw	\$`($j>>1)&7`,($dat,$TX[0],4),$xmm\n
++#md5#	add	$b,$a
++___
++    $code.=<<___ if ($rc4 && $j==15 && $k==$MOD-1);
++	mov	$YY,$XX[1]
++	xor	$YY,$YY				# keyword to partial register
++	mov	$XX[1]#b,$YY#b
++	lea	($dat,$XX[0],4),$XX[1]
++___
++    $code.=<<___ if ($rc4 && $j==15);
++	psllq	\$8,%xmm1
++	pxor	%xmm0,%xmm4
++	pxor	%xmm1,%xmm4
++___
++}
++sub R3 {
++  my ($i,$a,$b,$c,$d)=@_;
++  my @rot3=(6,10,15,21);
++  my $j=$i%16;
++  my $k=$i%$MOD;
++  my $xmm="%xmm".($j&1);
++    $code.="	movdqu	48($in0),%xmm5\n"	if ($rc4 && $j==15);
++    $code.="	add	\$$MOD,$XX[0]#b\n"	if ($rc4 && $j==15 && $k==$MOD-1);
++    $code.="	pxor	$xmm,$xmm\n"		if ($rc4 && $j<=1);
++    $code.=<<___;
++#rc4#	movl	($dat,$YY,4),$TY#d
++#md5#	xor	$d,$tmp
++#rc4#	movl	$TX[0]#d,($dat,$YY,4)
++#md5#	or	$b,$tmp
++#md5#	add	4*`((7*$j)%16)`($inp),$a
++#rc4#	add	$TY#b,$TX[0]#b
++#rc4#	movl	`4*(($k+1)%$MOD)`(`$k==$MOD-1?"$dat,$XX[0],4":"$XX[1]"`),$TX[1]#d
++#md5#	add	\$$K[$i],$a
++#rc4#	movz	$TX[0]#b,$TX[0]#d
++#md5#	xor	$c,$tmp
++#rc4#	movl	$TY#d,4*$k($XX[1])
++#md5#	add	$tmp,$a
++#rc4#	add	$TX[1]#b,$YY#b
++#md5#	rol	\$$rot3[$j%4],$a
++#md5#	mov	\$-1,$tmp			# forward reference
++#rc4#	pinsrw	\$`($j>>1)&7`,($dat,$TX[0],4),$xmm\n
++#md5#	add	$b,$a
++___
++    $code.=<<___ if ($rc4 && $j==15);
++	mov	$XX[0],$XX[1]
++	xor	$XX[0],$XX[0]			# keyword to partial register
++	mov	$XX[1]#b,$XX[0]#b
++	mov	$YY,$XX[1]
++	xor	$YY,$YY				# keyword to partial register
++	mov	$XX[1]#b,$YY#b
++	lea	($dat,$XX[0],4),$XX[1]
++	psllq	\$8,%xmm1
++	pxor	%xmm0,%xmm5
++	pxor	%xmm1,%xmm5
++___
++}
++
++my $i=0;
++for(;$i<16;$i++) { R0($i,@V); unshift(@V,pop(@V)); push(@TX,shift(@TX)); }
++for(;$i<32;$i++) { R1($i,@V); unshift(@V,pop(@V)); push(@TX,shift(@TX)); }
++for(;$i<48;$i++) { R2($i,@V); unshift(@V,pop(@V)); push(@TX,shift(@TX)); }
++for(;$i<64;$i++) { R3($i,@V); unshift(@V,pop(@V)); push(@TX,shift(@TX)); }
++
++$code.=<<___;
++#md5#	add	0*4(%rsp),$V[0]		# accumulate hash value
++#md5#	add	1*4(%rsp),$V[1]
++#md5#	add	2*4(%rsp),$V[2]
++#md5#	add	3*4(%rsp),$V[3]
++
++#rc4#	movdqu	%xmm2,($out,$in0)	# write RC4 output
++#rc4#	movdqu	%xmm3,16($out,$in0)
++#rc4#	movdqu	%xmm4,32($out,$in0)
++#rc4#	movdqu	%xmm5,48($out,$in0)
++#md5#	lea	64($inp),$inp
++#rc4#	lea	64($in0),$in0
++	cmp	16(%rsp),$inp		# are we done?
++	jb	.Loop
++
++#md5#	mov	24(%rsp),$len		# restore pointer to MD5_CTX
++#rc4#	sub	$TX[0]#b,$YY#b		# correct $YY
++#md5#	mov	$V[0],0*4($len)		# write MD5_CTX
++#md5#	mov	$V[1],1*4($len)
++#md5#	mov	$V[2],2*4($len)
++#md5#	mov	$V[3],3*4($len)
++___
++$code.=<<___ if ($rc4 && (!$md5 || $D));
++	mov	32(%rsp),$len		# restore original $len
++	and	\$63,$len		# remaining bytes
++	jnz	.Loop1
++	jmp	.Ldone
++	
++.align	16
++.Loop1:
++	add	$TX[0]#b,$YY#b
++	movl	($dat,$YY,4),$TY#d
++	movl	$TX[0]#d,($dat,$YY,4)
++	movl	$TY#d,($dat,$XX[0],4)
++	add	$TY#b,$TX[0]#b
++	inc	$XX[0]#b
++	movl	($dat,$TX[0],4),$TY#d
++	movl	($dat,$XX[0],4),$TX[0]#d
++	xorb	($in0),$TY#b
++	movb	$TY#b,($out,$in0)
++	lea	1($in0),$in0
++	dec	$len
++	jnz	.Loop1
++
++.Ldone:
++___
++$code.=<<___;
++#rc4#	sub	\$1,$XX[0]#b
++#rc4#	movl	$XX[0]#d,-8($dat)
++#rc4#	movl	$YY#d,-4($dat)
++
++	mov	40(%rsp),%r15
++	mov	48(%rsp),%r14
++	mov	56(%rsp),%r13
++	mov	64(%rsp),%r12
++	mov	72(%rsp),%rbp
++	mov	80(%rsp),%rbx
++	lea	88(%rsp),%rsp
++.Lepilogue:
++.Labort:
++	ret
++.size $func,.-$func
++___
++
++if ($rc4 && $D) {	# sole purpose of this section is to provide
++			# option to use the generated module as drop-in
++			# replacement for rc4-x86_64.pl for debugging
++			# and testing purposes...
++my ($idx,$ido)=("%r8","%r9");
++my ($dat,$len,$inp)=("%rdi","%rsi","%rdx");
++
++$code.=<<___;
++.globl	RC4_set_key
++.type	RC4_set_key,\@function,3
++.align	16
++RC4_set_key:
++	lea	8($dat),$dat
++	lea	($inp,$len),$inp
++	neg	$len
++	mov	$len,%rcx
++	xor	%eax,%eax
++	xor	$ido,$ido
++	xor	%r10,%r10
++	xor	%r11,%r11
++	jmp	.Lw1stloop
++
++.align	16
++.Lw1stloop:
++	mov	%eax,($dat,%rax,4)
++	add	\$1,%al
++	jnc	.Lw1stloop
++
++	xor	$ido,$ido
++	xor	$idx,$idx
++.align	16
++.Lw2ndloop:
++	mov	($dat,$ido,4),%r10d
++	add	($inp,$len,1),$idx#b
++	add	%r10b,$idx#b
++	add	\$1,$len
++	mov	($dat,$idx,4),%r11d
++	cmovz	%rcx,$len
++	mov	%r10d,($dat,$idx,4)
++	mov	%r11d,($dat,$ido,4)
++	add	\$1,$ido#b
++	jnc	.Lw2ndloop
++
++	xor	%eax,%eax
++	mov	%eax,-8($dat)
++	mov	%eax,-4($dat)
++	ret
++.size	RC4_set_key,.-RC4_set_key
++
++.globl	RC4_options
++.type	RC4_options,\@abi-omnipotent
++.align	16
++RC4_options:
++	lea	.Lopts(%rip),%rax
++	ret
++.align	64
++.Lopts:
++.asciz	"rc4(64x,int)"
++.align	64
++.size	RC4_options,.-RC4_options
++___
++}
++# EXCEPTION_DISPOSITION handler (EXCEPTION_RECORD *rec,ULONG64 frame,
++#		CONTEXT *context,DISPATCHER_CONTEXT *disp)
++if ($win64) {
++my $rec="%rcx";
++my $frame="%rdx";
++my $context="%r8";
++my $disp="%r9";
++
++$code.=<<___;
++.extern	__imp_RtlVirtualUnwind
++.type	se_handler,\@abi-omnipotent
++.align	16
++se_handler:
++	push	%rsi
++	push	%rdi
++	push	%rbx
++	push	%rbp
++	push	%r12
++	push	%r13
++	push	%r14
++	push	%r15
++	pushfq
++	sub	\$64,%rsp
++
++	mov	120($context),%rax	# pull context->Rax
++	mov	248($context),%rbx	# pull context->Rip
++
++	lea	.Lbody(%rip),%r10
++	cmp	%r10,%rbx		# context->Rip<.Lbody
++	jb	.Lin_prologue
++
++	mov	152($context),%rax	# pull context->Rsp
++
++	lea	.Lepilogue(%rip),%r10
++	cmp	%r10,%rbx		# context->Rip>=.Lepilogue
++	jae	.Lin_prologue
++
++	mov	40(%rax),%r15
++	mov	48(%rax),%r14
++	mov	56(%rax),%r13
++	mov	64(%rax),%r12
++	mov	72(%rax),%rbp
++	mov	80(%rax),%rbx
++	lea	88(%rax),%rax
++
++	mov	%rbx,144($context)	# restore context->Rbx
++	mov	%rbp,160($context)	# restore context->Rbp
++	mov	%r12,216($context)	# restore context->R12
++	mov	%r13,224($context)	# restore context->R12
++	mov	%r14,232($context)	# restore context->R14
++	mov	%r15,240($context)	# restore context->R15
++
++.Lin_prologue:
++	mov	8(%rax),%rdi
++	mov	16(%rax),%rsi
++	mov	%rax,152($context)	# restore context->Rsp
++	mov	%rsi,168($context)	# restore context->Rsi
++	mov	%rdi,176($context)	# restore context->Rdi
++
++	mov	40($disp),%rdi		# disp->ContextRecord
++	mov	$context,%rsi		# context
++	mov	\$154,%ecx		# sizeof(CONTEXT)
++	.long	0xa548f3fc		# cld; rep movsq
++
++	mov	$disp,%rsi
++	xor	%rcx,%rcx		# arg1, UNW_FLAG_NHANDLER
++	mov	8(%rsi),%rdx		# arg2, disp->ImageBase
++	mov	0(%rsi),%r8		# arg3, disp->ControlPc
++	mov	16(%rsi),%r9		# arg4, disp->FunctionEntry
++	mov	40(%rsi),%r10		# disp->ContextRecord
++	lea	56(%rsi),%r11		# &disp->HandlerData
++	lea	24(%rsi),%r12		# &disp->EstablisherFrame
++	mov	%r10,32(%rsp)		# arg5
++	mov	%r11,40(%rsp)		# arg6
++	mov	%r12,48(%rsp)		# arg7
++	mov	%rcx,56(%rsp)		# arg8, (NULL)
++	call	*__imp_RtlVirtualUnwind(%rip)
++
++	mov	\$1,%eax		# ExceptionContinueSearch
++	add	\$64,%rsp
++	popfq
++	pop	%r15
++	pop	%r14
++	pop	%r13
++	pop	%r12
++	pop	%rbp
++	pop	%rbx
++	pop	%rdi
++	pop	%rsi
++	ret
++.size	se_handler,.-se_handler
++
++.section	.pdata
++.align	4
++	.rva	.LSEH_begin_$func
++	.rva	.LSEH_end_$func
++	.rva	.LSEH_info_$func
++
++.section	.xdata
++.align	8
++.LSEH_info_$func:
++	.byte	9,0,0,0
++	.rva	se_handler
++___
++}
++
++sub reg_part {
++my ($reg,$conv)=@_;
++    if ($reg =~ /%r[0-9]+/)     { $reg .= $conv; }
++    elsif ($conv eq "b")        { $reg =~ s/%[er]([^x]+)x?/%$1l/;       }
++    elsif ($conv eq "w")        { $reg =~ s/%[er](.+)/%$1/;             }
++    elsif ($conv eq "d")        { $reg =~ s/%[er](.+)/%e$1/;            }
++    return $reg;
++}
++
++$code =~ s/(%[a-z0-9]+)#([bwd])/reg_part($1,$2)/gem;
++$code =~ s/\`([^\`]*)\`/eval $1/gem;
++$code =~ s/pinsrw\s+\$0,/movd	/gm;
++
++$code =~ s/#md5#//gm	if ($md5);
++$code =~ s/#rc4#//gm	if ($rc4);
++
++print $code;
++
++close STDOUT;
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/rc4/asm/rc4-parisc.pl b/CryptoPkg/Library/OpensslLib/openssl/crypto/rc4/asm/rc4-parisc.pl
+new file mode 100644
+index 0000000..006b6b0
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/rc4/asm/rc4-parisc.pl
+@@ -0,0 +1,321 @@
++#! /usr/bin/env perl
++# Copyright 2009-2016 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
++# in the file LICENSE in the source distribution or at
++# https://www.openssl.org/source/license.html
++
++
++# ====================================================================
++# Written by Andy Polyakov  for the OpenSSL
++# project. The module is, however, dual licensed under OpenSSL and
++# CRYPTOGAMS licenses depending on where you obtain it. For further
++# details see http://www.openssl.org/~appro/cryptogams/.
++# ====================================================================
++
++# RC4 for PA-RISC.
++
++# June 2009.
++#
++# Performance is 33% better than gcc 3.2 generated code on PA-7100LC.
++# For reference, [4x] unrolled loop is >40% faster than folded one.
++# It's possible to unroll loop 8 times on PA-RISC 2.0, but improvement
++# is believed to be not sufficient to justify the effort...
++#
++# Special thanks to polarhome.com for providing HP-UX account.
++
++$0 =~ m/(.*[\/\\])[^\/\\]+$/; $dir=$1;
++
++$flavour = shift;
++$output = shift;
++open STDOUT,">$output";
++
++if ($flavour =~ /64/) {
++	$LEVEL		="2.0W";
++	$SIZE_T		=8;
++	$FRAME_MARKER	=80;
++	$SAVED_RP	=16;
++	$PUSH		="std";
++	$PUSHMA		="std,ma";
++	$POP		="ldd";
++	$POPMB		="ldd,mb";
++} else {
++	$LEVEL		="1.0";
++	$SIZE_T		=4;
++	$FRAME_MARKER	=48;
++	$SAVED_RP	=20;
++	$PUSH		="stw";
++	$PUSHMA		="stwm";
++	$POP		="ldw";
++	$POPMB		="ldwm";
++}
++
++$FRAME=4*$SIZE_T+$FRAME_MARKER;	# 4 saved regs + frame marker
++				#                [+ argument transfer]
++$SZ=1;				# defaults to RC4_CHAR
++if (open CONF,"<${dir}../../opensslconf.h") {
++    while() {
++	if (m/#\s*define\s+RC4_INT\s+(.*)/) {
++	    $SZ = ($1=~/char$/) ? 1 : 4;
++	    last;
++	}
++    }
++    close CONF;
++}
++
++if ($SZ==1) {	# RC4_CHAR
++    $LD="ldb";
++    $LDX="ldbx";
++    $MKX="addl";
++    $ST="stb";
++} else {	# RC4_INT (~5% faster than RC4_CHAR on PA-7100LC)
++    $LD="ldw";
++    $LDX="ldwx,s";
++    $MKX="sh2addl";
++    $ST="stw";
++}
++
++$key="%r26";
++$len="%r25";
++$inp="%r24";
++$out="%r23";
++
++@XX=("%r19","%r20");
++@TX=("%r21","%r22");
++$YY="%r28";
++$TY="%r29";
++
++$acc="%r1";
++$ix="%r2";
++$iy="%r3";
++$dat0="%r4";
++$dat1="%r5";
++$rem="%r6";
++$mask="%r31";
++
++sub unrolledloopbody {
++for ($i=0;$i<4;$i++) {
++$code.=<<___;
++	ldo	1($XX[0]),$XX[1]
++	`sprintf("$LDX	%$TY(%$key),%$dat1") if ($i>0)`	
++	and	$mask,$XX[1],$XX[1]
++	$LDX	$YY($key),$TY
++	$MKX	$YY,$key,$ix
++	$LDX	$XX[1]($key),$TX[1]
++	$MKX	$XX[0],$key,$iy
++	$ST	$TX[0],0($ix)
++	comclr,<> $XX[1],$YY,%r0	; conditional
++	copy	$TX[0],$TX[1]		; move
++	`sprintf("%sdep	%$dat1,%d,8,%$acc",$i==1?"z":"",8*($i-1)+7) if ($i>0)`
++	$ST	$TY,0($iy)
++	addl	$TX[0],$TY,$TY
++	addl	$TX[1],$YY,$YY
++	and	$mask,$TY,$TY
++	and	$mask,$YY,$YY
++___
++push(@TX,shift(@TX)); push(@XX,shift(@XX));	# "rotate" registers
++} }
++
++sub foldedloop {
++my ($label,$count)=@_;
++$code.=<<___;
++$label
++	$MKX	$YY,$key,$iy
++	$LDX	$YY($key),$TY
++	$MKX	$XX[0],$key,$ix
++	$ST	$TX[0],0($iy)
++	ldo	1($XX[0]),$XX[0]
++	$ST	$TY,0($ix)
++	addl	$TX[0],$TY,$TY
++	ldbx	$inp($out),$dat1
++	and	$mask,$TY,$TY
++	and	$mask,$XX[0],$XX[0]
++	$LDX	$TY($key),$acc
++	$LDX	$XX[0]($key),$TX[0]
++	ldo	1($out),$out
++	xor	$dat1,$acc,$acc
++	addl	$TX[0],$YY,$YY
++	stb	$acc,-1($out)
++	addib,<> -1,$count,$label	; $count is always small
++	and	$mask,$YY,$YY
++___
++}
++
++$code=<<___;
++	.LEVEL	$LEVEL
++	.SPACE	\$TEXT\$
++	.SUBSPA	\$CODE\$,QUAD=0,ALIGN=8,ACCESS=0x2C,CODE_ONLY
++
++	.EXPORT	RC4,ENTRY,ARGW0=GR,ARGW1=GR,ARGW2=GR,ARGW3=GR
++RC4
++	.PROC
++	.CALLINFO	FRAME=`$FRAME-4*$SIZE_T`,NO_CALLS,SAVE_RP,ENTRY_GR=6
++	.ENTRY
++	$PUSH	%r2,-$SAVED_RP(%sp)	; standard prologue
++	$PUSHMA	%r3,$FRAME(%sp)
++	$PUSH	%r4,`-$FRAME+1*$SIZE_T`(%sp)
++	$PUSH	%r5,`-$FRAME+2*$SIZE_T`(%sp)
++	$PUSH	%r6,`-$FRAME+3*$SIZE_T`(%sp)
++
++	cmpib,*= 0,$len,L\$abort
++	sub	$inp,$out,$inp		; distance between $inp and $out
++
++	$LD	`0*$SZ`($key),$XX[0]
++	$LD	`1*$SZ`($key),$YY
++	ldo	`2*$SZ`($key),$key
++
++	ldi	0xff,$mask
++	ldi	3,$dat0		
++
++	ldo	1($XX[0]),$XX[0]	; warm up loop
++	and	$mask,$XX[0],$XX[0]
++	$LDX	$XX[0]($key),$TX[0]
++	addl	$TX[0],$YY,$YY
++	cmpib,*>>= 6,$len,L\$oop1	; is $len large enough to bother?
++	and	$mask,$YY,$YY
++
++	and,<>	$out,$dat0,$rem		; is $out aligned?
++	b	L\$alignedout
++	subi	4,$rem,$rem
++	sub	$len,$rem,$len
++___
++&foldedloop("L\$alignout",$rem);	# process till $out is aligned
++
++$code.=<<___;
++L\$alignedout				; $len is at least 4 here
++	and,<>	$inp,$dat0,$acc		; is $inp aligned?
++	b	L\$oop4
++	sub	$inp,$acc,$rem		; align $inp
++
++	sh3addl	$acc,%r0,$acc
++	subi	32,$acc,$acc
++	mtctl	$acc,%cr11		; load %sar with vshd align factor
++	ldwx	$rem($out),$dat0
++	ldo	4($rem),$rem
++L\$oop4misalignedinp
++___
++&unrolledloopbody();
++$code.=<<___;
++	$LDX	$TY($key),$ix
++	ldwx	$rem($out),$dat1
++	ldo	-4($len),$len
++	or	$ix,$acc,$acc		; last piece, no need to dep
++	vshd	$dat0,$dat1,$iy		; align data
++	copy	$dat1,$dat0
++	xor	$iy,$acc,$acc
++	stw	$acc,0($out)
++	cmpib,*<< 3,$len,L\$oop4misalignedinp
++	ldo	4($out),$out
++	cmpib,*= 0,$len,L\$done
++	nop
++	b	L\$oop1
++	nop
++
++	.ALIGN	8
++L\$oop4
++___
++&unrolledloopbody();
++$code.=<<___;
++	$LDX	$TY($key),$ix
++	ldwx	$inp($out),$dat0
++	ldo	-4($len),$len
++	or	$ix,$acc,$acc		; last piece, no need to dep
++	xor	$dat0,$acc,$acc
++	stw	$acc,0($out)
++	cmpib,*<< 3,$len,L\$oop4
++	ldo	4($out),$out
++	cmpib,*= 0,$len,L\$done
++	nop
++___
++&foldedloop("L\$oop1",$len);
++$code.=<<___;
++L\$done
++	$POP	`-$FRAME-$SAVED_RP`(%sp),%r2
++	ldo	-1($XX[0]),$XX[0]	; chill out loop
++	sub	$YY,$TX[0],$YY
++	and	$mask,$XX[0],$XX[0]
++	and	$mask,$YY,$YY
++	$ST	$XX[0],`-2*$SZ`($key)
++	$ST	$YY,`-1*$SZ`($key)
++	$POP	`-$FRAME+1*$SIZE_T`(%sp),%r4
++	$POP	`-$FRAME+2*$SIZE_T`(%sp),%r5
++	$POP	`-$FRAME+3*$SIZE_T`(%sp),%r6
++L\$abort
++	bv	(%r2)
++	.EXIT
++	$POPMB	-$FRAME(%sp),%r3
++	.PROCEND
++___
++
++$code.=<<___;
++
++	.EXPORT	RC4_set_key,ENTRY,ARGW0=GR,ARGW1=GR,ARGW2=GR
++	.ALIGN	8
++RC4_set_key
++	.PROC
++	.CALLINFO	NO_CALLS
++	.ENTRY
++	$ST	%r0,`0*$SZ`($key)
++	$ST	%r0,`1*$SZ`($key)
++	ldo	`2*$SZ`($key),$key
++	copy	%r0,@XX[0]
++L\$1st
++	$ST	@XX[0],0($key)
++	ldo	1(@XX[0]),@XX[0]
++	bb,>=	@XX[0],`31-8`,L\$1st	; @XX[0]<256
++	ldo	$SZ($key),$key
++
++	ldo	`-256*$SZ`($key),$key	; rewind $key
++	addl	$len,$inp,$inp		; $inp to point at the end
++	sub	%r0,$len,%r23		; inverse index
++	copy	%r0,@XX[0]
++	copy	%r0,@XX[1]
++	ldi	0xff,$mask
++
++L\$2nd
++	$LDX	@XX[0]($key),@TX[0]
++	ldbx	%r23($inp),@TX[1]
++	addi,nuv 1,%r23,%r23		; increment and conditional
++	sub	%r0,$len,%r23		; inverse index
++	addl	@TX[0],@XX[1],@XX[1]
++	addl	@TX[1],@XX[1],@XX[1]
++	and	$mask,@XX[1],@XX[1]
++	$MKX	@XX[0],$key,$TY
++	$LDX	@XX[1]($key),@TX[1]
++	$MKX	@XX[1],$key,$YY
++	ldo	1(@XX[0]),@XX[0]
++	$ST	@TX[0],0($YY)
++	bb,>=	@XX[0],`31-8`,L\$2nd	; @XX[0]<256
++	$ST	@TX[1],0($TY)
++
++	bv,n	(%r2)
++	.EXIT
++	nop
++	.PROCEND
++
++	.EXPORT	RC4_options,ENTRY
++	.ALIGN	8
++RC4_options
++	.PROC
++	.CALLINFO	NO_CALLS
++	.ENTRY
++	blr	%r0,%r28
++	ldi	3,%r1
++L\$pic
++	andcm	%r28,%r1,%r28
++	bv	(%r2)
++	.EXIT
++	ldo	L\$opts-L\$pic(%r28),%r28
++	.PROCEND
++	.ALIGN	8
++L\$opts
++	.STRINGZ "rc4(4x,`$SZ==1?"char":"int"`)"
++	.STRINGZ "RC4 for PA-RISC, CRYPTOGAMS by "
++___
++$code =~ s/\`([^\`]*)\`/eval $1/gem;
++$code =~ s/cmpib,\*/comib,/gm	if ($SIZE_T==4);
++$code =~ s/\bbv\b/bve/gm	if ($SIZE_T==8);
++
++print $code;
++close STDOUT;
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/rc4/asm/rc4-s390x.pl b/CryptoPkg/Library/OpensslLib/openssl/crypto/rc4/asm/rc4-s390x.pl
+new file mode 100644
+index 0000000..5589503
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/rc4/asm/rc4-s390x.pl
+@@ -0,0 +1,241 @@
++#! /usr/bin/env perl
++# Copyright 2009-2016 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
++# in the file LICENSE in the source distribution or at
++# https://www.openssl.org/source/license.html
++
++#
++# ====================================================================
++# Written by Andy Polyakov  for the OpenSSL
++# project. The module is, however, dual licensed under OpenSSL and
++# CRYPTOGAMS licenses depending on where you obtain it. For further
++# details see http://www.openssl.org/~appro/cryptogams/.
++# ====================================================================
++#
++# February 2009
++#
++# Performance is 2x of gcc 3.4.6 on z10. Coding "secret" is to
++# "cluster" Address Generation Interlocks, so that one pipeline stall
++# resolves several dependencies.
++
++# November 2010.
++#
++# Adapt for -m31 build. If kernel supports what's called "highgprs"
++# feature on Linux [see /proc/cpuinfo], it's possible to use 64-bit
++# instructions and achieve "64-bit" performance even in 31-bit legacy
++# application context. The feature is not specific to any particular
++# processor, as long as it's "z-CPU". Latter implies that the code
++# remains z/Architecture specific. On z990 it was measured to perform
++# 50% better than code generated by gcc 4.3.
++
++$flavour = shift;
++
++if ($flavour =~ /3[12]/) {
++	$SIZE_T=4;
++	$g="";
++} else {
++	$SIZE_T=8;
++	$g="g";
++}
++
++while (($output=shift) && ($output!~/\w[\w\-]*\.\w+$/)) {}
++open STDOUT,">$output";
++
++$rp="%r14";
++$sp="%r15";
++$code=<<___;
++.text
++
++___
++
++# void RC4(RC4_KEY *key,size_t len,const void *inp,void *out)
++{
++$acc="%r0";
++$cnt="%r1";
++$key="%r2";
++$len="%r3";
++$inp="%r4";
++$out="%r5";
++
++@XX=("%r6","%r7");
++@TX=("%r8","%r9");
++$YY="%r10";
++$TY="%r11";
++
++$code.=<<___;
++.globl	RC4
++.type	RC4,\@function
++.align	64
++RC4:
++	stm${g}	%r6,%r11,6*$SIZE_T($sp)
++___
++$code.=<<___ if ($flavour =~ /3[12]/);
++	llgfr	$len,$len
++___
++$code.=<<___;
++	llgc	$XX[0],0($key)
++	llgc	$YY,1($key)
++	la	$XX[0],1($XX[0])
++	nill	$XX[0],0xff
++	srlg	$cnt,$len,3
++	ltgr	$cnt,$cnt
++	llgc	$TX[0],2($XX[0],$key)
++	jz	.Lshort
++	j	.Loop8
++
++.align	64
++.Loop8:
++___
++for ($i=0;$i<8;$i++) {
++$code.=<<___;
++	la	$YY,0($YY,$TX[0])	# $i
++	nill	$YY,255
++	la	$XX[1],1($XX[0])
++	nill	$XX[1],255
++___
++$code.=<<___ if ($i==1);
++	llgc	$acc,2($TY,$key)
++___
++$code.=<<___ if ($i>1);
++	sllg	$acc,$acc,8
++	ic	$acc,2($TY,$key)
++___
++$code.=<<___;
++	llgc	$TY,2($YY,$key)
++	stc	$TX[0],2($YY,$key)
++	llgc	$TX[1],2($XX[1],$key)
++	stc	$TY,2($XX[0],$key)
++	cr	$XX[1],$YY
++	jne	.Lcmov$i
++	la	$TX[1],0($TX[0])
++.Lcmov$i:
++	la	$TY,0($TY,$TX[0])
++	nill	$TY,255
++___
++push(@TX,shift(@TX)); push(@XX,shift(@XX));     # "rotate" registers
++}
++
++$code.=<<___;
++	lg	$TX[1],0($inp)
++	sllg	$acc,$acc,8
++	la	$inp,8($inp)
++	ic	$acc,2($TY,$key)
++	xgr	$acc,$TX[1]
++	stg	$acc,0($out)
++	la	$out,8($out)
++	brctg	$cnt,.Loop8
++
++.Lshort:
++	lghi	$acc,7
++	ngr	$len,$acc
++	jz	.Lexit
++	j	.Loop1
++
++.align	16
++.Loop1:
++	la	$YY,0($YY,$TX[0])
++	nill	$YY,255
++	llgc	$TY,2($YY,$key)
++	stc	$TX[0],2($YY,$key)
++	stc	$TY,2($XX[0],$key)
++	ar	$TY,$TX[0]
++	ahi	$XX[0],1
++	nill	$TY,255
++	nill	$XX[0],255
++	llgc	$acc,0($inp)
++	la	$inp,1($inp)
++	llgc	$TY,2($TY,$key)
++	llgc	$TX[0],2($XX[0],$key)
++	xr	$acc,$TY
++	stc	$acc,0($out)
++	la	$out,1($out)
++	brct	$len,.Loop1
++
++.Lexit:
++	ahi	$XX[0],-1
++	stc	$XX[0],0($key)
++	stc	$YY,1($key)
++	lm${g}	%r6,%r11,6*$SIZE_T($sp)
++	br	$rp
++.size	RC4,.-RC4
++.string	"RC4 for s390x, CRYPTOGAMS by "
++
++___
++}
++
++# void RC4_set_key(RC4_KEY *key,unsigned int len,const void *inp)
++{
++$cnt="%r0";
++$idx="%r1";
++$key="%r2";
++$len="%r3";
++$inp="%r4";
++$acc="%r5";
++$dat="%r6";
++$ikey="%r7";
++$iinp="%r8";
++
++$code.=<<___;
++.globl	RC4_set_key
++.type	RC4_set_key,\@function
++.align	64
++RC4_set_key:
++	stm${g}	%r6,%r8,6*$SIZE_T($sp)
++	lhi	$cnt,256
++	la	$idx,0(%r0)
++	sth	$idx,0($key)
++.align	4
++.L1stloop:
++	stc	$idx,2($idx,$key)
++	la	$idx,1($idx)
++	brct	$cnt,.L1stloop
++
++	lghi	$ikey,-256
++	lr	$cnt,$len
++	la	$iinp,0(%r0)
++	la	$idx,0(%r0)
++.align	16
++.L2ndloop:
++	llgc	$acc,2+256($ikey,$key)
++	llgc	$dat,0($iinp,$inp)
++	la	$idx,0($idx,$acc)
++	la	$ikey,1($ikey)
++	la	$idx,0($idx,$dat)
++	nill	$idx,255
++	la	$iinp,1($iinp)
++	tml	$ikey,255
++	llgc	$dat,2($idx,$key)
++	stc	$dat,2+256-1($ikey,$key)
++	stc	$acc,2($idx,$key)
++	jz	.Ldone
++	brct	$cnt,.L2ndloop
++	lr	$cnt,$len
++	la	$iinp,0(%r0)
++	j	.L2ndloop
++.Ldone:
++	lm${g}	%r6,%r8,6*$SIZE_T($sp)
++	br	$rp
++.size	RC4_set_key,.-RC4_set_key
++
++___
++}
++
++# const char *RC4_options()
++$code.=<<___;
++.globl	RC4_options
++.type	RC4_options,\@function
++.align	16
++RC4_options:
++	larl	%r2,.Loptions
++	br	%r14
++.size	RC4_options,.-RC4_options
++.section	.rodata
++.Loptions:
++.align	8
++.string	"rc4(8x,char)"
++___
++
++print $code;
++close STDOUT;	# force flush
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/rc4/asm/rc4-x86_64.pl b/CryptoPkg/Library/OpensslLib/openssl/crypto/rc4/asm/rc4-x86_64.pl
+new file mode 100755
+index 0000000..aaed2b1
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/rc4/asm/rc4-x86_64.pl
+@@ -0,0 +1,687 @@
++#! /usr/bin/env perl
++# Copyright 2005-2016 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
++# in the file LICENSE in the source distribution or at
++# https://www.openssl.org/source/license.html
++
++#
++# ====================================================================
++# Written by Andy Polyakov  for the OpenSSL
++# project. The module is, however, dual licensed under OpenSSL and
++# CRYPTOGAMS licenses depending on where you obtain it. For further
++# details see http://www.openssl.org/~appro/cryptogams/.
++# ====================================================================
++#
++# July 2004
++#
++# 2.22x RC4 tune-up:-) It should be noted though that my hand [as in
++# "hand-coded assembler"] doesn't stand for the whole improvement
++# coefficient. It turned out that eliminating RC4_CHAR from config
++# line results in ~40% improvement (yes, even for C implementation).
++# Presumably it has everything to do with AMD cache architecture and
++# RAW or whatever penalties. Once again! The module *requires* config
++# line *without* RC4_CHAR! As for coding "secret," I bet on partial
++# register arithmetics. For example instead of 'inc %r8; and $255,%r8'
++# I simply 'inc %r8b'. Even though optimization manual discourages
++# to operate on partial registers, it turned out to be the best bet.
++# At least for AMD... How IA32E would perform remains to be seen...
++
++# November 2004
++#
++# As was shown by Marc Bevand reordering of couple of load operations
++# results in even higher performance gain of 3.3x:-) At least on
++# Opteron... For reference, 1x in this case is RC4_CHAR C-code
++# compiled with gcc 3.3.2, which performs at ~54MBps per 1GHz clock.
++# Latter means that if you want to *estimate* what to expect from
++# *your* Opteron, then multiply 54 by 3.3 and clock frequency in GHz.
++
++# November 2004
++#
++# Intel P4 EM64T core was found to run the AMD64 code really slow...
++# The only way to achieve comparable performance on P4 was to keep
++# RC4_CHAR. Kind of ironic, huh? As it's apparently impossible to
++# compose blended code, which would perform even within 30% marginal
++# on either AMD and Intel platforms, I implement both cases. See
++# rc4_skey.c for further details...
++
++# April 2005
++#
++# P4 EM64T core appears to be "allergic" to 64-bit inc/dec. Replacing 
++# those with add/sub results in 50% performance improvement of folded
++# loop...
++
++# May 2005
++#
++# As was shown by Zou Nanhai loop unrolling can improve Intel EM64T
++# performance by >30% [unlike P4 32-bit case that is]. But this is
++# provided that loads are reordered even more aggressively! Both code
++# paths, AMD64 and EM64T, reorder loads in essentially same manner
++# as my IA-64 implementation. On Opteron this resulted in modest 5%
++# improvement [I had to test it], while final Intel P4 performance
++# achieves respectful 432MBps on 2.8GHz processor now. For reference.
++# If executed on Xeon, current RC4_CHAR code-path is 2.7x faster than
++# RC4_INT code-path. While if executed on Opteron, it's only 25%
++# slower than the RC4_INT one [meaning that if CPU µ-arch detection
++# is not implemented, then this final RC4_CHAR code-path should be
++# preferred, as it provides better *all-round* performance].
++
++# March 2007
++#
++# Intel Core2 was observed to perform poorly on both code paths:-( It
++# apparently suffers from some kind of partial register stall, which
++# occurs in 64-bit mode only [as virtually identical 32-bit loop was
++# observed to outperform 64-bit one by almost 50%]. Adding two movzb to
++# cloop1 boosts its performance by 80%! This loop appears to be optimal
++# fit for Core2 and therefore the code was modified to skip cloop8 on
++# this CPU.
++
++# May 2010
++#
++# Intel Westmere was observed to perform suboptimally. Adding yet
++# another movzb to cloop1 improved performance by almost 50%! Core2
++# performance is improved too, but nominally...
++
++# May 2011
++#
++# The only code path that was not modified is P4-specific one. Non-P4
++# Intel code path optimization is heavily based on submission by Maxim
++# Perminov, Maxim Locktyukhin and Jim Guilford of Intel. I've used
++# some of the ideas even in attempt to optmize the original RC4_INT
++# code path... Current performance in cycles per processed byte (less
++# is better) and improvement coefficients relative to previous
++# version of this module are:
++#
++# Opteron	5.3/+0%(*)
++# P4		6.5
++# Core2		6.2/+15%(**)
++# Westmere	4.2/+60%
++# Sandy Bridge	4.2/+120%
++# Atom		9.3/+80%
++# VIA Nano	6.4/+4%
++# Ivy Bridge	4.1/+30%
++# Bulldozer	4.5/+30%(*)
++#
++# (*)	But corresponding loop has less instructions, which should have
++#	positive effect on upcoming Bulldozer, which has one less ALU.
++#	For reference, Intel code runs at 6.8 cpb rate on Opteron.
++# (**)	Note that Core2 result is ~15% lower than corresponding result
++#	for 32-bit code, meaning that it's possible to improve it,
++#	but more than likely at the cost of the others (see rc4-586.pl
++#	to get the idea)...
++
++$flavour = shift;
++$output  = shift;
++if ($flavour =~ /\./) { $output = $flavour; undef $flavour; }
++
++$win64=0; $win64=1 if ($flavour =~ /[nm]asm|mingw64/ || $output =~ /\.asm$/);
++
++$0 =~ m/(.*[\/\\])[^\/\\]+$/; $dir=$1;
++( $xlate="${dir}x86_64-xlate.pl" and -f $xlate ) or
++( $xlate="${dir}../../perlasm/x86_64-xlate.pl" and -f $xlate) or
++die "can't locate x86_64-xlate.pl";
++
++open OUT,"| \"$^X\" \"$xlate\" $flavour \"$output\"";
++*STDOUT=*OUT;
++
++$dat="%rdi";	    # arg1
++$len="%rsi";	    # arg2
++$inp="%rdx";	    # arg3
++$out="%rcx";	    # arg4
++
++{
++$code=<<___;
++.text
++.extern	OPENSSL_ia32cap_P
++
++.globl	RC4
++.type	RC4,\@function,4
++.align	16
++RC4:	or	$len,$len
++	jne	.Lentry
++	ret
++.Lentry:
++	push	%rbx
++	push	%r12
++	push	%r13
++.Lprologue:
++	mov	$len,%r11
++	mov	$inp,%r12
++	mov	$out,%r13
++___
++my $len="%r11";		# reassign input arguments
++my $inp="%r12";
++my $out="%r13";
++
++my @XX=("%r10","%rsi");
++my @TX=("%rax","%rbx");
++my $YY="%rcx";
++my $TY="%rdx";
++
++$code.=<<___;
++	xor	$XX[0],$XX[0]
++	xor	$YY,$YY
++
++	lea	8($dat),$dat
++	mov	-8($dat),$XX[0]#b
++	mov	-4($dat),$YY#b
++	cmpl	\$-1,256($dat)
++	je	.LRC4_CHAR
++	mov	OPENSSL_ia32cap_P(%rip),%r8d
++	xor	$TX[1],$TX[1]
++	inc	$XX[0]#b
++	sub	$XX[0],$TX[1]
++	sub	$inp,$out
++	movl	($dat,$XX[0],4),$TX[0]#d
++	test	\$-16,$len
++	jz	.Lloop1
++	bt	\$30,%r8d	# Intel CPU?
++	jc	.Lintel
++	and	\$7,$TX[1]
++	lea	1($XX[0]),$XX[1]
++	jz	.Loop8
++	sub	$TX[1],$len
++.Loop8_warmup:
++	add	$TX[0]#b,$YY#b
++	movl	($dat,$YY,4),$TY#d
++	movl	$TX[0]#d,($dat,$YY,4)
++	movl	$TY#d,($dat,$XX[0],4)
++	add	$TY#b,$TX[0]#b
++	inc	$XX[0]#b
++	movl	($dat,$TX[0],4),$TY#d
++	movl	($dat,$XX[0],4),$TX[0]#d
++	xorb	($inp),$TY#b
++	movb	$TY#b,($out,$inp)
++	lea	1($inp),$inp
++	dec	$TX[1]
++	jnz	.Loop8_warmup
++
++	lea	1($XX[0]),$XX[1]
++	jmp	.Loop8
++.align	16
++.Loop8:
++___
++for ($i=0;$i<8;$i++) {
++$code.=<<___ if ($i==7);
++	add	\$8,$XX[1]#b
++___
++$code.=<<___;
++	add	$TX[0]#b,$YY#b
++	movl	($dat,$YY,4),$TY#d
++	movl	$TX[0]#d,($dat,$YY,4)
++	movl	`4*($i==7?-1:$i)`($dat,$XX[1],4),$TX[1]#d
++	ror	\$8,%r8				# ror is redundant when $i=0
++	movl	$TY#d,4*$i($dat,$XX[0],4)
++	add	$TX[0]#b,$TY#b
++	movb	($dat,$TY,4),%r8b
++___
++push(@TX,shift(@TX)); #push(@XX,shift(@XX));	# "rotate" registers
++}
++$code.=<<___;
++	add	\$8,$XX[0]#b
++	ror	\$8,%r8
++	sub	\$8,$len
++
++	xor	($inp),%r8
++	mov	%r8,($out,$inp)
++	lea	8($inp),$inp
++
++	test	\$-8,$len
++	jnz	.Loop8
++	cmp	\$0,$len
++	jne	.Lloop1
++	jmp	.Lexit
++
++.align	16
++.Lintel:
++	test	\$-32,$len
++	jz	.Lloop1
++	and	\$15,$TX[1]
++	jz	.Loop16_is_hot
++	sub	$TX[1],$len
++.Loop16_warmup:
++	add	$TX[0]#b,$YY#b
++	movl	($dat,$YY,4),$TY#d
++	movl	$TX[0]#d,($dat,$YY,4)
++	movl	$TY#d,($dat,$XX[0],4)
++	add	$TY#b,$TX[0]#b
++	inc	$XX[0]#b
++	movl	($dat,$TX[0],4),$TY#d
++	movl	($dat,$XX[0],4),$TX[0]#d
++	xorb	($inp),$TY#b
++	movb	$TY#b,($out,$inp)
++	lea	1($inp),$inp
++	dec	$TX[1]
++	jnz	.Loop16_warmup
++
++	mov	$YY,$TX[1]
++	xor	$YY,$YY
++	mov	$TX[1]#b,$YY#b
++
++.Loop16_is_hot:
++	lea	($dat,$XX[0],4),$XX[1]
++___
++sub RC4_loop {
++  my $i=shift;
++  my $j=$i<0?0:$i;
++  my $xmm="%xmm".($j&1);
++
++    $code.="	add	\$16,$XX[0]#b\n"		if ($i==15);
++    $code.="	movdqu	($inp),%xmm2\n"			if ($i==15);
++    $code.="	add	$TX[0]#b,$YY#b\n"		if ($i<=0);
++    $code.="	movl	($dat,$YY,4),$TY#d\n";
++    $code.="	pxor	%xmm0,%xmm2\n"			if ($i==0);
++    $code.="	psllq	\$8,%xmm1\n"			if ($i==0);
++    $code.="	pxor	$xmm,$xmm\n"			if ($i<=1);
++    $code.="	movl	$TX[0]#d,($dat,$YY,4)\n";
++    $code.="	add	$TY#b,$TX[0]#b\n";
++    $code.="	movl	`4*($j+1)`($XX[1]),$TX[1]#d\n"	if ($i<15);
++    $code.="	movz	$TX[0]#b,$TX[0]#d\n";
++    $code.="	movl	$TY#d,4*$j($XX[1])\n";
++    $code.="	pxor	%xmm1,%xmm2\n"			if ($i==0);
++    $code.="	lea	($dat,$XX[0],4),$XX[1]\n"	if ($i==15);
++    $code.="	add	$TX[1]#b,$YY#b\n"		if ($i<15);
++    $code.="	pinsrw	\$`($j>>1)&7`,($dat,$TX[0],4),$xmm\n";
++    $code.="	movdqu	%xmm2,($out,$inp)\n"		if ($i==0);
++    $code.="	lea	16($inp),$inp\n"		if ($i==0);
++    $code.="	movl	($XX[1]),$TX[1]#d\n"		if ($i==15);
++}
++	RC4_loop(-1);
++$code.=<<___;
++	jmp	.Loop16_enter
++.align	16
++.Loop16:
++___
++
++for ($i=0;$i<16;$i++) {
++    $code.=".Loop16_enter:\n"		if ($i==1);
++	RC4_loop($i);
++	push(@TX,shift(@TX)); 		# "rotate" registers
++}
++$code.=<<___;
++	mov	$YY,$TX[1]
++	xor	$YY,$YY			# keyword to partial register
++	sub	\$16,$len
++	mov	$TX[1]#b,$YY#b
++	test	\$-16,$len
++	jnz	.Loop16
++
++	psllq	\$8,%xmm1
++	pxor	%xmm0,%xmm2
++	pxor	%xmm1,%xmm2
++	movdqu	%xmm2,($out,$inp)
++	lea	16($inp),$inp
++
++	cmp	\$0,$len
++	jne	.Lloop1
++	jmp	.Lexit
++
++.align	16
++.Lloop1:
++	add	$TX[0]#b,$YY#b
++	movl	($dat,$YY,4),$TY#d
++	movl	$TX[0]#d,($dat,$YY,4)
++	movl	$TY#d,($dat,$XX[0],4)
++	add	$TY#b,$TX[0]#b
++	inc	$XX[0]#b
++	movl	($dat,$TX[0],4),$TY#d
++	movl	($dat,$XX[0],4),$TX[0]#d
++	xorb	($inp),$TY#b
++	movb	$TY#b,($out,$inp)
++	lea	1($inp),$inp
++	dec	$len
++	jnz	.Lloop1
++	jmp	.Lexit
++
++.align	16
++.LRC4_CHAR:
++	add	\$1,$XX[0]#b
++	movzb	($dat,$XX[0]),$TX[0]#d
++	test	\$-8,$len
++	jz	.Lcloop1
++	jmp	.Lcloop8
++.align	16
++.Lcloop8:
++	mov	($inp),%r8d
++	mov	4($inp),%r9d
++___
++# unroll 2x4-wise, because 64-bit rotates kill Intel P4...
++for ($i=0;$i<4;$i++) {
++$code.=<<___;
++	add	$TX[0]#b,$YY#b
++	lea	1($XX[0]),$XX[1]
++	movzb	($dat,$YY),$TY#d
++	movzb	$XX[1]#b,$XX[1]#d
++	movzb	($dat,$XX[1]),$TX[1]#d
++	movb	$TX[0]#b,($dat,$YY)
++	cmp	$XX[1],$YY
++	movb	$TY#b,($dat,$XX[0])
++	jne	.Lcmov$i			# Intel cmov is sloooow...
++	mov	$TX[0],$TX[1]
++.Lcmov$i:
++	add	$TX[0]#b,$TY#b
++	xor	($dat,$TY),%r8b
++	ror	\$8,%r8d
++___
++push(@TX,shift(@TX)); push(@XX,shift(@XX));	# "rotate" registers
++}
++for ($i=4;$i<8;$i++) {
++$code.=<<___;
++	add	$TX[0]#b,$YY#b
++	lea	1($XX[0]),$XX[1]
++	movzb	($dat,$YY),$TY#d
++	movzb	$XX[1]#b,$XX[1]#d
++	movzb	($dat,$XX[1]),$TX[1]#d
++	movb	$TX[0]#b,($dat,$YY)
++	cmp	$XX[1],$YY
++	movb	$TY#b,($dat,$XX[0])
++	jne	.Lcmov$i			# Intel cmov is sloooow...
++	mov	$TX[0],$TX[1]
++.Lcmov$i:
++	add	$TX[0]#b,$TY#b
++	xor	($dat,$TY),%r9b
++	ror	\$8,%r9d
++___
++push(@TX,shift(@TX)); push(@XX,shift(@XX));	# "rotate" registers
++}
++$code.=<<___;
++	lea	-8($len),$len
++	mov	%r8d,($out)
++	lea	8($inp),$inp
++	mov	%r9d,4($out)
++	lea	8($out),$out
++
++	test	\$-8,$len
++	jnz	.Lcloop8
++	cmp	\$0,$len
++	jne	.Lcloop1
++	jmp	.Lexit
++___
++$code.=<<___;
++.align	16
++.Lcloop1:
++	add	$TX[0]#b,$YY#b
++	movzb	$YY#b,$YY#d
++	movzb	($dat,$YY),$TY#d
++	movb	$TX[0]#b,($dat,$YY)
++	movb	$TY#b,($dat,$XX[0])
++	add	$TX[0]#b,$TY#b
++	add	\$1,$XX[0]#b
++	movzb	$TY#b,$TY#d
++	movzb	$XX[0]#b,$XX[0]#d
++	movzb	($dat,$TY),$TY#d
++	movzb	($dat,$XX[0]),$TX[0]#d
++	xorb	($inp),$TY#b
++	lea	1($inp),$inp
++	movb	$TY#b,($out)
++	lea	1($out),$out
++	sub	\$1,$len
++	jnz	.Lcloop1
++	jmp	.Lexit
++
++.align	16
++.Lexit:
++	sub	\$1,$XX[0]#b
++	movl	$XX[0]#d,-8($dat)
++	movl	$YY#d,-4($dat)
++
++	mov	(%rsp),%r13
++	mov	8(%rsp),%r12
++	mov	16(%rsp),%rbx
++	add	\$24,%rsp
++.Lepilogue:
++	ret
++.size	RC4,.-RC4
++___
++}
++
++$idx="%r8";
++$ido="%r9";
++
++$code.=<<___;
++.globl	RC4_set_key
++.type	RC4_set_key,\@function,3
++.align	16
++RC4_set_key:
++	lea	8($dat),$dat
++	lea	($inp,$len),$inp
++	neg	$len
++	mov	$len,%rcx
++	xor	%eax,%eax
++	xor	$ido,$ido
++	xor	%r10,%r10
++	xor	%r11,%r11
++
++	mov	OPENSSL_ia32cap_P(%rip),$idx#d
++	bt	\$20,$idx#d	# RC4_CHAR?
++	jc	.Lc1stloop
++	jmp	.Lw1stloop
++
++.align	16
++.Lw1stloop:
++	mov	%eax,($dat,%rax,4)
++	add	\$1,%al
++	jnc	.Lw1stloop
++
++	xor	$ido,$ido
++	xor	$idx,$idx
++.align	16
++.Lw2ndloop:
++	mov	($dat,$ido,4),%r10d
++	add	($inp,$len,1),$idx#b
++	add	%r10b,$idx#b
++	add	\$1,$len
++	mov	($dat,$idx,4),%r11d
++	cmovz	%rcx,$len
++	mov	%r10d,($dat,$idx,4)
++	mov	%r11d,($dat,$ido,4)
++	add	\$1,$ido#b
++	jnc	.Lw2ndloop
++	jmp	.Lexit_key
++
++.align	16
++.Lc1stloop:
++	mov	%al,($dat,%rax)
++	add	\$1,%al
++	jnc	.Lc1stloop
++
++	xor	$ido,$ido
++	xor	$idx,$idx
++.align	16
++.Lc2ndloop:
++	mov	($dat,$ido),%r10b
++	add	($inp,$len),$idx#b
++	add	%r10b,$idx#b
++	add	\$1,$len
++	mov	($dat,$idx),%r11b
++	jnz	.Lcnowrap
++	mov	%rcx,$len
++.Lcnowrap:
++	mov	%r10b,($dat,$idx)
++	mov	%r11b,($dat,$ido)
++	add	\$1,$ido#b
++	jnc	.Lc2ndloop
++	movl	\$-1,256($dat)
++
++.align	16
++.Lexit_key:
++	xor	%eax,%eax
++	mov	%eax,-8($dat)
++	mov	%eax,-4($dat)
++	ret
++.size	RC4_set_key,.-RC4_set_key
++
++.globl	RC4_options
++.type	RC4_options,\@abi-omnipotent
++.align	16
++RC4_options:
++	lea	.Lopts(%rip),%rax
++	mov	OPENSSL_ia32cap_P(%rip),%edx
++	bt	\$20,%edx
++	jc	.L8xchar
++	bt	\$30,%edx
++	jnc	.Ldone
++	add	\$25,%rax
++	ret
++.L8xchar:
++	add	\$12,%rax
++.Ldone:
++	ret
++.align	64
++.Lopts:
++.asciz	"rc4(8x,int)"
++.asciz	"rc4(8x,char)"
++.asciz	"rc4(16x,int)"
++.asciz	"RC4 for x86_64, CRYPTOGAMS by "
++.align	64
++.size	RC4_options,.-RC4_options
++___
++
++# EXCEPTION_DISPOSITION handler (EXCEPTION_RECORD *rec,ULONG64 frame,
++#		CONTEXT *context,DISPATCHER_CONTEXT *disp)
++if ($win64) {
++$rec="%rcx";
++$frame="%rdx";
++$context="%r8";
++$disp="%r9";
++
++$code.=<<___;
++.extern	__imp_RtlVirtualUnwind
++.type	stream_se_handler,\@abi-omnipotent
++.align	16
++stream_se_handler:
++	push	%rsi
++	push	%rdi
++	push	%rbx
++	push	%rbp
++	push	%r12
++	push	%r13
++	push	%r14
++	push	%r15
++	pushfq
++	sub	\$64,%rsp
++
++	mov	120($context),%rax	# pull context->Rax
++	mov	248($context),%rbx	# pull context->Rip
++
++	lea	.Lprologue(%rip),%r10
++	cmp	%r10,%rbx		# context->RipRsp
++
++	lea	.Lepilogue(%rip),%r10
++	cmp	%r10,%rbx		# context->Rip>=epilogue label
++	jae	.Lin_prologue
++
++	lea	24(%rax),%rax
++
++	mov	-8(%rax),%rbx
++	mov	-16(%rax),%r12
++	mov	-24(%rax),%r13
++	mov	%rbx,144($context)	# restore context->Rbx
++	mov	%r12,216($context)	# restore context->R12
++	mov	%r13,224($context)	# restore context->R13
++
++.Lin_prologue:
++	mov	8(%rax),%rdi
++	mov	16(%rax),%rsi
++	mov	%rax,152($context)	# restore context->Rsp
++	mov	%rsi,168($context)	# restore context->Rsi
++	mov	%rdi,176($context)	# restore context->Rdi
++
++	jmp	.Lcommon_seh_exit
++.size	stream_se_handler,.-stream_se_handler
++
++.type	key_se_handler,\@abi-omnipotent
++.align	16
++key_se_handler:
++	push	%rsi
++	push	%rdi
++	push	%rbx
++	push	%rbp
++	push	%r12
++	push	%r13
++	push	%r14
++	push	%r15
++	pushfq
++	sub	\$64,%rsp
++
++	mov	152($context),%rax	# pull context->Rsp
++	mov	8(%rax),%rdi
++	mov	16(%rax),%rsi
++	mov	%rsi,168($context)	# restore context->Rsi
++	mov	%rdi,176($context)	# restore context->Rdi
++
++.Lcommon_seh_exit:
++
++	mov	40($disp),%rdi		# disp->ContextRecord
++	mov	$context,%rsi		# context
++	mov	\$154,%ecx		# sizeof(CONTEXT)
++	.long	0xa548f3fc		# cld; rep movsq
++
++	mov	$disp,%rsi
++	xor	%rcx,%rcx		# arg1, UNW_FLAG_NHANDLER
++	mov	8(%rsi),%rdx		# arg2, disp->ImageBase
++	mov	0(%rsi),%r8		# arg3, disp->ControlPc
++	mov	16(%rsi),%r9		# arg4, disp->FunctionEntry
++	mov	40(%rsi),%r10		# disp->ContextRecord
++	lea	56(%rsi),%r11		# &disp->HandlerData
++	lea	24(%rsi),%r12		# &disp->EstablisherFrame
++	mov	%r10,32(%rsp)		# arg5
++	mov	%r11,40(%rsp)		# arg6
++	mov	%r12,48(%rsp)		# arg7
++	mov	%rcx,56(%rsp)		# arg8, (NULL)
++	call	*__imp_RtlVirtualUnwind(%rip)
++
++	mov	\$1,%eax		# ExceptionContinueSearch
++	add	\$64,%rsp
++	popfq
++	pop	%r15
++	pop	%r14
++	pop	%r13
++	pop	%r12
++	pop	%rbp
++	pop	%rbx
++	pop	%rdi
++	pop	%rsi
++	ret
++.size	key_se_handler,.-key_se_handler
++
++.section	.pdata
++.align	4
++	.rva	.LSEH_begin_RC4
++	.rva	.LSEH_end_RC4
++	.rva	.LSEH_info_RC4
++
++	.rva	.LSEH_begin_RC4_set_key
++	.rva	.LSEH_end_RC4_set_key
++	.rva	.LSEH_info_RC4_set_key
++
++.section	.xdata
++.align	8
++.LSEH_info_RC4:
++	.byte	9,0,0,0
++	.rva	stream_se_handler
++.LSEH_info_RC4_set_key:
++	.byte	9,0,0,0
++	.rva	key_se_handler
++___
++}
++
++sub reg_part {
++my ($reg,$conv)=@_;
++    if ($reg =~ /%r[0-9]+/)	{ $reg .= $conv; }
++    elsif ($conv eq "b")	{ $reg =~ s/%[er]([^x]+)x?/%$1l/;	}
++    elsif ($conv eq "w")	{ $reg =~ s/%[er](.+)/%$1/;		}
++    elsif ($conv eq "d")	{ $reg =~ s/%[er](.+)/%e$1/;		}
++    return $reg;
++}
++
++$code =~ s/(%[a-z0-9]+)#([bwd])/reg_part($1,$2)/gem;
++$code =~ s/\`([^\`]*)\`/eval $1/gem;
++
++print $code;
++
++close STDOUT;
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/rc4/build.info b/CryptoPkg/Library/OpensslLib/openssl/crypto/rc4/build.info
+new file mode 100644
+index 0000000..6c48889
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/rc4/build.info
+@@ -0,0 +1,33 @@
++LIBS=../../libcrypto
++SOURCE[../../libcrypto]=\
++        {- $target{rc4_asm_src} -}
++
++GENERATE[rc4-586.s]=asm/rc4-586.pl $(PERLASM_SCHEME) $(CFLAGS) $(LIB_CFLAGS) $(PROCESSOR)
++DEPEND[rc4-586.s]=../perlasm/x86asm.pl
++
++GENERATE[rc4-x86_64.s]=asm/rc4-x86_64.pl $(PERLASM_SCHEME)
++GENERATE[rc4-md5-x86_64.s]=asm/rc4-md5-x86_64.pl $(PERLASM_SCHEME)
++
++GENERATE[rc4-parisc.s]=asm/rc4-parisc.pl $(PERLASM_SCHEME)
++
++BEGINRAW[makefile(windows)]
++{- $builddir -}\rc4-ia64.asm: {- $sourcedir -}\asm\rc4-ia64.pl
++	$(PERL) {- $sourcedir -}\asm\rc4-ia64.pl $@.S
++	$(CC) -DSZ=4 -EP $@.S > $@.i && move /Y $@.i $@
++	del /Q $@.S
++ENDRAW[makefile(windows)]
++
++BEGINRAW[Makefile]
++{- $builddir -}/rc4-ia64.s: {- $sourcedir -}/asm/rc4-ia64.pl
++	@(trap "rm $@.*" INT 0; \
++	  $(PERL) $< $(CFLAGS) $(LIB_CFLAGS) $@.S; \
++	  case `awk '/^#define RC4_INT/{print$$NF}' $(BLDDIR)/include/openssl/opensslconf.h` in \
++	  int)	set -x; $(CC) $(CFLAGS) $(LIB_CFLAGS) -DSZ=4 -E $@.S > $@.i && mv -f $@.i $@;; \
++	  char)	set -x; $(CC) $(CFLAGS) $(LIB_CFLAGS) -DSZ=1 -E $@.S > $@.i && mv -f $@.i $@;; \
++	  *)	exit 1 ;; \
++	  esac )
++
++# GNU make "catch all"
++{- $builddir -}/rc4-%.s:	{- $sourcedir -}/asm/rc4-%.pl
++	CC="$(CC)" $(PERL) $< $(PERLASM_SCHEME) $@
++ENDRAW[Makefile]
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/rc4/rc4_enc.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/rc4/rc4_enc.c
+new file mode 100644
+index 0000000..be11bad
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/rc4/rc4_enc.c
+@@ -0,0 +1,86 @@
++/*
++ * Copyright 1995-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include "rc4_locl.h"
++
++/*-
++ * RC4 as implemented from a posting from
++ * Newsgroups: sci.crypt
++ * From: sterndark@netcom.com (David Sterndark)
++ * Subject: RC4 Algorithm revealed.
++ * Message-ID: 
++ * Date: Wed, 14 Sep 1994 06:35:31 GMT
++ */
++
++void RC4(RC4_KEY *key, size_t len, const unsigned char *indata,
++         unsigned char *outdata)
++{
++    register RC4_INT *d;
++    register RC4_INT x, y, tx, ty;
++    size_t i;
++
++    x = key->x;
++    y = key->y;
++    d = key->data;
++
++#define LOOP(in,out) \
++                x=((x+1)&0xff); \
++                tx=d[x]; \
++                y=(tx+y)&0xff; \
++                d[x]=ty=d[y]; \
++                d[y]=tx; \
++                (out) = d[(tx+ty)&0xff]^ (in);
++
++    i = len >> 3;
++    if (i) {
++        for (;;) {
++            LOOP(indata[0], outdata[0]);
++            LOOP(indata[1], outdata[1]);
++            LOOP(indata[2], outdata[2]);
++            LOOP(indata[3], outdata[3]);
++            LOOP(indata[4], outdata[4]);
++            LOOP(indata[5], outdata[5]);
++            LOOP(indata[6], outdata[6]);
++            LOOP(indata[7], outdata[7]);
++            indata += 8;
++            outdata += 8;
++            if (--i == 0)
++                break;
++        }
++    }
++    i = len & 0x07;
++    if (i) {
++        for (;;) {
++            LOOP(indata[0], outdata[0]);
++            if (--i == 0)
++                break;
++            LOOP(indata[1], outdata[1]);
++            if (--i == 0)
++                break;
++            LOOP(indata[2], outdata[2]);
++            if (--i == 0)
++                break;
++            LOOP(indata[3], outdata[3]);
++            if (--i == 0)
++                break;
++            LOOP(indata[4], outdata[4]);
++            if (--i == 0)
++                break;
++            LOOP(indata[5], outdata[5]);
++            if (--i == 0)
++                break;
++            LOOP(indata[6], outdata[6]);
++            if (--i == 0)
++                break;
++        }
++    }
++    key->x = x;
++    key->y = y;
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/rc4/rc4_locl.h b/CryptoPkg/Library/OpensslLib/openssl/crypto/rc4/rc4_locl.h
+new file mode 100644
+index 0000000..4380add
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/rc4/rc4_locl.h
+@@ -0,0 +1,16 @@
++/*
++ * Copyright 1998-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#ifndef HEADER_RC4_LOCL_H
++# define HEADER_RC4_LOCL_H
++
++# include 
++# include "internal/cryptlib.h"
++
++#endif
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/rc4/rc4_skey.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/rc4/rc4_skey.c
+new file mode 100644
+index 0000000..16f81a4
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/rc4/rc4_skey.c
+@@ -0,0 +1,58 @@
++/*
++ * Copyright 1995-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include "rc4_locl.h"
++#include 
++
++const char *RC4_options(void)
++{
++    if (sizeof(RC4_INT) == 1)
++        return ("rc4(char)");
++    else
++        return ("rc4(int)");
++}
++
++/*-
++ * RC4 as implemented from a posting from
++ * Newsgroups: sci.crypt
++ * From: sterndark@netcom.com (David Sterndark)
++ * Subject: RC4 Algorithm revealed.
++ * Message-ID: 
++ * Date: Wed, 14 Sep 1994 06:35:31 GMT
++ */
++
++void RC4_set_key(RC4_KEY *key, int len, const unsigned char *data)
++{
++    register RC4_INT tmp;
++    register int id1, id2;
++    register RC4_INT *d;
++    unsigned int i;
++
++    d = &(key->data[0]);
++    key->x = 0;
++    key->y = 0;
++    id1 = id2 = 0;
++
++#define SK_LOOP(d,n) { \
++                tmp=d[(n)]; \
++                id2 = (data[id1] + tmp + id2) & 0xff; \
++                if (++id1 == len) id1=0; \
++                d[(n)]=d[id2]; \
++                d[id2]=tmp; }
++
++    for (i = 0; i < 256; i++)
++        d[i] = i;
++    for (i = 0; i < 256; i += 4) {
++        SK_LOOP(d, i + 0);
++        SK_LOOP(d, i + 1);
++        SK_LOOP(d, i + 2);
++        SK_LOOP(d, i + 3);
++    }
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/rc5/asm/rc5-586.pl b/CryptoPkg/Library/OpensslLib/openssl/crypto/rc5/asm/rc5-586.pl
+new file mode 100644
+index 0000000..e3e1c64
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/rc5/asm/rc5-586.pl
+@@ -0,0 +1,122 @@
++#! /usr/bin/env perl
++# Copyright 1995-2016 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
++# in the file LICENSE in the source distribution or at
++# https://www.openssl.org/source/license.html
++
++
++$0 =~ m/(.*[\/\\])[^\/\\]+$/; $dir=$1;
++push(@INC,"${dir}","${dir}../../perlasm");
++require "x86asm.pl";
++require "cbc.pl";
++
++$output = pop;
++open STDOUT,">$output";
++
++&asm_init($ARGV[0],"rc5-586.pl");
++
++$RC5_MAX_ROUNDS=16;
++$RC5_32_OFF=($RC5_MAX_ROUNDS+2)*4;
++$A="edi";
++$B="esi";
++$S="ebp";
++$tmp1="eax";
++$r="ebx";
++$tmpc="ecx";
++$tmp4="edx";
++
++&RC5_32_encrypt("RC5_32_encrypt",1);
++&RC5_32_encrypt("RC5_32_decrypt",0);
++&cbc("RC5_32_cbc_encrypt","RC5_32_encrypt","RC5_32_decrypt",0,4,5,3,-1,-1);
++&asm_finish();
++
++close STDOUT;
++
++sub RC5_32_encrypt
++	{
++	local($name,$enc)=@_;
++
++	&function_begin_B($name,"");
++
++	&comment("");
++
++	&push("ebp");
++	 &push("esi");
++	&push("edi");
++	 &mov($tmp4,&wparam(0));
++	&mov($S,&wparam(1));
++
++	&comment("Load the 2 words");
++	 &mov($A,&DWP(0,$tmp4,"",0));
++	&mov($B,&DWP(4,$tmp4,"",0));
++
++	&push($r);
++	 &mov($r,	&DWP(0,$S,"",0));
++
++	# encrypting part
++
++	if ($enc)
++		{
++		 &add($A,	&DWP(4+0,$S,"",0));
++		&add($B,	&DWP(4+4,$S,"",0));
++
++		for ($i=0; $i<$RC5_MAX_ROUNDS; $i++)
++			{
++			 &xor($A,	$B);
++			&mov($tmp1,	&DWP(12+$i*8,$S,"",0));
++			 &mov($tmpc,	$B);
++			&rotl($A,	&LB("ecx"));
++			&add($A,	$tmp1);
++
++			 &xor($B,	$A);
++			&mov($tmp1,	&DWP(16+$i*8,$S,"",0));
++			 &mov($tmpc,	$A);
++			&rotl($B,	&LB("ecx"));
++			&add($B,	$tmp1);
++			if (($i == 7) || ($i == 11))
++				{
++			 &cmp($r,	$i+1);
++			&je(&label("rc5_exit"));
++				}
++			}
++		}
++	else
++		{
++		 &cmp($r,	12);
++		&je(&label("rc5_dec_12"));
++		 &cmp($r,	8);
++		&je(&label("rc5_dec_8"));
++		for ($i=$RC5_MAX_ROUNDS; $i > 0; $i--)
++			{
++			&set_label("rc5_dec_$i") if ($i == 12) || ($i == 8);
++			 &mov($tmp1,	&DWP($i*8+8,$S,"",0));
++			&sub($B,	$tmp1);
++			 &mov($tmpc,	$A);
++			&rotr($B,	&LB("ecx"));
++			&xor($B,	$A);
++
++			 &mov($tmp1,	&DWP($i*8+4,$S,"",0));
++			&sub($A,	$tmp1);
++			 &mov($tmpc,	$B);
++			&rotr($A,	&LB("ecx"));
++			&xor($A,	$B);
++			}
++		 &sub($B,	&DWP(4+4,$S,"",0));
++		&sub($A,	&DWP(4+0,$S,"",0));
++		}
++
++	&set_label("rc5_exit");
++	 &mov(&DWP(0,$tmp4,"",0),$A);
++	&mov(&DWP(4,$tmp4,"",0),$B);
++
++	 &pop("ebx");
++	&pop("edi");
++	 &pop("esi");
++	&pop("ebp");
++	 &ret();
++	&function_end_B($name);
++	}
++
++
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/rc5/build.info b/CryptoPkg/Library/OpensslLib/openssl/crypto/rc5/build.info
+new file mode 100644
+index 0000000..baf8a0e
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/rc5/build.info
+@@ -0,0 +1,6 @@
++LIBS=../../libcrypto
++SOURCE[../../libcrypto]=\
++        rc5_skey.c rc5_ecb.c {- $target{rc5_asm_src} -} rc5cfb64.c rc5ofb64.c
++
++GENERATE[rc5-586.s]=asm/rc5-586.pl $(PERLASM_SCHEME) $(CFLAGS) $(LIB_CFLAGS)
++DEPEND[rc5-586.s]=../perlasm/x86asm.pl ../perlasm/cbc.pl
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/rc5/rc5_ecb.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/rc5/rc5_ecb.c
+new file mode 100644
+index 0000000..c32f38e
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/rc5/rc5_ecb.c
+@@ -0,0 +1,32 @@
++/*
++ * Copyright 1995-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include "rc5_locl.h"
++#include 
++
++void RC5_32_ecb_encrypt(const unsigned char *in, unsigned char *out,
++                        RC5_32_KEY *ks, int encrypt)
++{
++    unsigned long l, d[2];
++
++    c2l(in, l);
++    d[0] = l;
++    c2l(in, l);
++    d[1] = l;
++    if (encrypt)
++        RC5_32_encrypt(d, ks);
++    else
++        RC5_32_decrypt(d, ks);
++    l = d[0];
++    l2c(l, out);
++    l = d[1];
++    l2c(l, out);
++    l = d[0] = d[1] = 0;
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/rc5/rc5_enc.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/rc5/rc5_enc.c
+new file mode 100644
+index 0000000..58631de
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/rc5/rc5_enc.c
+@@ -0,0 +1,160 @@
++/*
++ * Copyright 1995-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include 
++#include "rc5_locl.h"
++
++void RC5_32_cbc_encrypt(const unsigned char *in, unsigned char *out,
++                        long length, RC5_32_KEY *ks, unsigned char *iv,
++                        int encrypt)
++{
++    register unsigned long tin0, tin1;
++    register unsigned long tout0, tout1, xor0, xor1;
++    register long l = length;
++    unsigned long tin[2];
++
++    if (encrypt) {
++        c2l(iv, tout0);
++        c2l(iv, tout1);
++        iv -= 8;
++        for (l -= 8; l >= 0; l -= 8) {
++            c2l(in, tin0);
++            c2l(in, tin1);
++            tin0 ^= tout0;
++            tin1 ^= tout1;
++            tin[0] = tin0;
++            tin[1] = tin1;
++            RC5_32_encrypt(tin, ks);
++            tout0 = tin[0];
++            l2c(tout0, out);
++            tout1 = tin[1];
++            l2c(tout1, out);
++        }
++        if (l != -8) {
++            c2ln(in, tin0, tin1, l + 8);
++            tin0 ^= tout0;
++            tin1 ^= tout1;
++            tin[0] = tin0;
++            tin[1] = tin1;
++            RC5_32_encrypt(tin, ks);
++            tout0 = tin[0];
++            l2c(tout0, out);
++            tout1 = tin[1];
++            l2c(tout1, out);
++        }
++        l2c(tout0, iv);
++        l2c(tout1, iv);
++    } else {
++        c2l(iv, xor0);
++        c2l(iv, xor1);
++        iv -= 8;
++        for (l -= 8; l >= 0; l -= 8) {
++            c2l(in, tin0);
++            tin[0] = tin0;
++            c2l(in, tin1);
++            tin[1] = tin1;
++            RC5_32_decrypt(tin, ks);
++            tout0 = tin[0] ^ xor0;
++            tout1 = tin[1] ^ xor1;
++            l2c(tout0, out);
++            l2c(tout1, out);
++            xor0 = tin0;
++            xor1 = tin1;
++        }
++        if (l != -8) {
++            c2l(in, tin0);
++            tin[0] = tin0;
++            c2l(in, tin1);
++            tin[1] = tin1;
++            RC5_32_decrypt(tin, ks);
++            tout0 = tin[0] ^ xor0;
++            tout1 = tin[1] ^ xor1;
++            l2cn(tout0, tout1, out, l + 8);
++            xor0 = tin0;
++            xor1 = tin1;
++        }
++        l2c(xor0, iv);
++        l2c(xor1, iv);
++    }
++    tin0 = tin1 = tout0 = tout1 = xor0 = xor1 = 0;
++    tin[0] = tin[1] = 0;
++}
++
++void RC5_32_encrypt(unsigned long *d, RC5_32_KEY *key)
++{
++    RC5_32_INT a, b, *s;
++
++    s = key->data;
++
++    a = d[0] + s[0];
++    b = d[1] + s[1];
++    E_RC5_32(a, b, s, 2);
++    E_RC5_32(a, b, s, 4);
++    E_RC5_32(a, b, s, 6);
++    E_RC5_32(a, b, s, 8);
++    E_RC5_32(a, b, s, 10);
++    E_RC5_32(a, b, s, 12);
++    E_RC5_32(a, b, s, 14);
++    E_RC5_32(a, b, s, 16);
++    if (key->rounds == 12) {
++        E_RC5_32(a, b, s, 18);
++        E_RC5_32(a, b, s, 20);
++        E_RC5_32(a, b, s, 22);
++        E_RC5_32(a, b, s, 24);
++    } else if (key->rounds == 16) {
++        /* Do a full expansion to avoid a jump */
++        E_RC5_32(a, b, s, 18);
++        E_RC5_32(a, b, s, 20);
++        E_RC5_32(a, b, s, 22);
++        E_RC5_32(a, b, s, 24);
++        E_RC5_32(a, b, s, 26);
++        E_RC5_32(a, b, s, 28);
++        E_RC5_32(a, b, s, 30);
++        E_RC5_32(a, b, s, 32);
++    }
++    d[0] = a;
++    d[1] = b;
++}
++
++void RC5_32_decrypt(unsigned long *d, RC5_32_KEY *key)
++{
++    RC5_32_INT a, b, *s;
++
++    s = key->data;
++
++    a = d[0];
++    b = d[1];
++    if (key->rounds == 16) {
++        D_RC5_32(a, b, s, 32);
++        D_RC5_32(a, b, s, 30);
++        D_RC5_32(a, b, s, 28);
++        D_RC5_32(a, b, s, 26);
++        /* Do a full expansion to avoid a jump */
++        D_RC5_32(a, b, s, 24);
++        D_RC5_32(a, b, s, 22);
++        D_RC5_32(a, b, s, 20);
++        D_RC5_32(a, b, s, 18);
++    } else if (key->rounds == 12) {
++        D_RC5_32(a, b, s, 24);
++        D_RC5_32(a, b, s, 22);
++        D_RC5_32(a, b, s, 20);
++        D_RC5_32(a, b, s, 18);
++    }
++    D_RC5_32(a, b, s, 16);
++    D_RC5_32(a, b, s, 14);
++    D_RC5_32(a, b, s, 12);
++    D_RC5_32(a, b, s, 10);
++    D_RC5_32(a, b, s, 8);
++    D_RC5_32(a, b, s, 6);
++    D_RC5_32(a, b, s, 4);
++    D_RC5_32(a, b, s, 2);
++    d[0] = a - s[0];
++    d[1] = b - s[1];
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/rc5/rc5_locl.h b/CryptoPkg/Library/OpensslLib/openssl/crypto/rc5/rc5_locl.h
+new file mode 100644
+index 0000000..33a709b
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/rc5/rc5_locl.h
+@@ -0,0 +1,158 @@
++/*
++ * Copyright 1995-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++
++#undef c2l
++#define c2l(c,l)        (l =((unsigned long)(*((c)++)))    , \
++                         l|=((unsigned long)(*((c)++)))<< 8L, \
++                         l|=((unsigned long)(*((c)++)))<<16L, \
++                         l|=((unsigned long)(*((c)++)))<<24L)
++
++/* NOTE - c is not incremented as per c2l */
++#undef c2ln
++#define c2ln(c,l1,l2,n) { \
++                        c+=n; \
++                        l1=l2=0; \
++                        switch (n) { \
++                        case 8: l2 =((unsigned long)(*(--(c))))<<24L; \
++                        case 7: l2|=((unsigned long)(*(--(c))))<<16L; \
++                        case 6: l2|=((unsigned long)(*(--(c))))<< 8L; \
++                        case 5: l2|=((unsigned long)(*(--(c))));     \
++                        case 4: l1 =((unsigned long)(*(--(c))))<<24L; \
++                        case 3: l1|=((unsigned long)(*(--(c))))<<16L; \
++                        case 2: l1|=((unsigned long)(*(--(c))))<< 8L; \
++                        case 1: l1|=((unsigned long)(*(--(c))));     \
++                                } \
++                        }
++
++#undef l2c
++#define l2c(l,c)        (*((c)++)=(unsigned char)(((l)     )&0xff), \
++                         *((c)++)=(unsigned char)(((l)>> 8L)&0xff), \
++                         *((c)++)=(unsigned char)(((l)>>16L)&0xff), \
++                         *((c)++)=(unsigned char)(((l)>>24L)&0xff))
++
++/* NOTE - c is not incremented as per l2c */
++#undef l2cn
++#define l2cn(l1,l2,c,n) { \
++                        c+=n; \
++                        switch (n) { \
++                        case 8: *(--(c))=(unsigned char)(((l2)>>24L)&0xff); \
++                        case 7: *(--(c))=(unsigned char)(((l2)>>16L)&0xff); \
++                        case 6: *(--(c))=(unsigned char)(((l2)>> 8L)&0xff); \
++                        case 5: *(--(c))=(unsigned char)(((l2)     )&0xff); \
++                        case 4: *(--(c))=(unsigned char)(((l1)>>24L)&0xff); \
++                        case 3: *(--(c))=(unsigned char)(((l1)>>16L)&0xff); \
++                        case 2: *(--(c))=(unsigned char)(((l1)>> 8L)&0xff); \
++                        case 1: *(--(c))=(unsigned char)(((l1)     )&0xff); \
++                                } \
++                        }
++
++/* NOTE - c is not incremented as per n2l */
++#define n2ln(c,l1,l2,n) { \
++                        c+=n; \
++                        l1=l2=0; \
++                        switch (n) { \
++                        case 8: l2 =((unsigned long)(*(--(c))))    ; \
++                        case 7: l2|=((unsigned long)(*(--(c))))<< 8; \
++                        case 6: l2|=((unsigned long)(*(--(c))))<<16; \
++                        case 5: l2|=((unsigned long)(*(--(c))))<<24; \
++                        case 4: l1 =((unsigned long)(*(--(c))))    ; \
++                        case 3: l1|=((unsigned long)(*(--(c))))<< 8; \
++                        case 2: l1|=((unsigned long)(*(--(c))))<<16; \
++                        case 1: l1|=((unsigned long)(*(--(c))))<<24; \
++                                } \
++                        }
++
++/* NOTE - c is not incremented as per l2n */
++#define l2nn(l1,l2,c,n) { \
++                        c+=n; \
++                        switch (n) { \
++                        case 8: *(--(c))=(unsigned char)(((l2)    )&0xff); \
++                        case 7: *(--(c))=(unsigned char)(((l2)>> 8)&0xff); \
++                        case 6: *(--(c))=(unsigned char)(((l2)>>16)&0xff); \
++                        case 5: *(--(c))=(unsigned char)(((l2)>>24)&0xff); \
++                        case 4: *(--(c))=(unsigned char)(((l1)    )&0xff); \
++                        case 3: *(--(c))=(unsigned char)(((l1)>> 8)&0xff); \
++                        case 2: *(--(c))=(unsigned char)(((l1)>>16)&0xff); \
++                        case 1: *(--(c))=(unsigned char)(((l1)>>24)&0xff); \
++                                } \
++                        }
++
++#undef n2l
++#define n2l(c,l)        (l =((unsigned long)(*((c)++)))<<24L, \
++                         l|=((unsigned long)(*((c)++)))<<16L, \
++                         l|=((unsigned long)(*((c)++)))<< 8L, \
++                         l|=((unsigned long)(*((c)++))))
++
++#undef l2n
++#define l2n(l,c)        (*((c)++)=(unsigned char)(((l)>>24L)&0xff), \
++                         *((c)++)=(unsigned char)(((l)>>16L)&0xff), \
++                         *((c)++)=(unsigned char)(((l)>> 8L)&0xff), \
++                         *((c)++)=(unsigned char)(((l)     )&0xff))
++
++#if (defined(OPENSSL_SYS_WIN32) && defined(_MSC_VER))
++# define ROTATE_l32(a,n)     _lrotl(a,n)
++# define ROTATE_r32(a,n)     _lrotr(a,n)
++#elif defined(__ICC)
++# define ROTATE_l32(a,n)     _rotl(a,n)
++# define ROTATE_r32(a,n)     _rotr(a,n)
++#elif defined(__GNUC__) && __GNUC__>=2 && !defined(__STRICT_ANSI__) && !defined(OPENSSL_NO_ASM) && !defined(OPENSSL_NO_INLINE_ASM) && !defined(PEDANTIC)
++# if defined(__i386) || defined(__i386__) || defined(__x86_64) || defined(__x86_64__)
++#  define ROTATE_l32(a,n)       ({ register unsigned int ret;   \
++                                        asm ("roll %%cl,%0"     \
++                                                : "=r"(ret)     \
++                                                : "c"(n),"0"((unsigned int)(a)) \
++                                                : "cc");        \
++                                        ret;                    \
++                                })
++#  define ROTATE_r32(a,n)       ({ register unsigned int ret;   \
++                                        asm ("rorl %%cl,%0"     \
++                                                : "=r"(ret)     \
++                                                : "c"(n),"0"((unsigned int)(a)) \
++                                                : "cc");        \
++                                        ret;                    \
++                                })
++# endif
++#endif
++#ifndef ROTATE_l32
++# define ROTATE_l32(a,n)     (((a)<<(n&0x1f))|(((a)&0xffffffff)>>((32-n)&0x1f)))
++#endif
++#ifndef ROTATE_r32
++# define ROTATE_r32(a,n)     (((a)<<((32-n)&0x1f))|(((a)&0xffffffff)>>(n&0x1f)))
++#endif
++
++#define RC5_32_MASK     0xffffffffL
++
++#define RC5_16_P        0xB7E1
++#define RC5_16_Q        0x9E37
++#define RC5_32_P        0xB7E15163L
++#define RC5_32_Q        0x9E3779B9L
++#define RC5_64_P        0xB7E151628AED2A6BLL
++#define RC5_64_Q        0x9E3779B97F4A7C15LL
++
++#define E_RC5_32(a,b,s,n) \
++        a^=b; \
++        a=ROTATE_l32(a,b); \
++        a+=s[n]; \
++        a&=RC5_32_MASK; \
++        b^=a; \
++        b=ROTATE_l32(b,a); \
++        b+=s[n+1]; \
++        b&=RC5_32_MASK;
++
++#define D_RC5_32(a,b,s,n) \
++        b-=s[n+1]; \
++        b&=RC5_32_MASK; \
++        b=ROTATE_r32(b,a); \
++        b^=a; \
++        a-=s[n]; \
++        a&=RC5_32_MASK; \
++        a=ROTATE_r32(a,b); \
++        a^=b;
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/rc5/rc5_skey.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/rc5/rc5_skey.c
+new file mode 100644
+index 0000000..943a784
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/rc5/rc5_skey.c
+@@ -0,0 +1,61 @@
++/*
++ * Copyright 1995-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include "rc5_locl.h"
++
++void RC5_32_set_key(RC5_32_KEY *key, int len, const unsigned char *data,
++                    int rounds)
++{
++    RC5_32_INT L[64], l, ll, A, B, *S, k;
++    int i, j, m, c, t, ii, jj;
++
++    if ((rounds != RC5_16_ROUNDS) &&
++        (rounds != RC5_12_ROUNDS) && (rounds != RC5_8_ROUNDS))
++        rounds = RC5_16_ROUNDS;
++
++    key->rounds = rounds;
++    S = &(key->data[0]);
++    j = 0;
++    for (i = 0; i <= (len - 8); i += 8) {
++        c2l(data, l);
++        L[j++] = l;
++        c2l(data, l);
++        L[j++] = l;
++    }
++    ii = len - i;
++    if (ii) {
++        k = len & 0x07;
++        c2ln(data, l, ll, k);
++        L[j + 0] = l;
++        L[j + 1] = ll;
++    }
++
++    c = (len + 3) / 4;
++    t = (rounds + 1) * 2;
++    S[0] = RC5_32_P;
++    for (i = 1; i < t; i++)
++        S[i] = (S[i - 1] + RC5_32_Q) & RC5_32_MASK;
++
++    j = (t > c) ? t : c;
++    j *= 3;
++    ii = jj = 0;
++    A = B = 0;
++    for (i = 0; i < j; i++) {
++        k = (S[ii] + A + B) & RC5_32_MASK;
++        A = S[ii] = ROTATE_l32(k, 3);
++        m = (int)(A + B);
++        k = (L[jj] + A + B) & RC5_32_MASK;
++        B = L[jj] = ROTATE_l32(k, m);
++        if (++ii >= t)
++            ii = 0;
++        if (++jj >= c)
++            jj = 0;
++    }
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/rc5/rc5cfb64.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/rc5/rc5cfb64.c
+new file mode 100644
+index 0000000..9a8aa6b
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/rc5/rc5cfb64.c
+@@ -0,0 +1,74 @@
++/*
++ * Copyright 1995-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include "rc5_locl.h"
++
++/*
++ * The input and output encrypted as though 64bit cfb mode is being used.
++ * The extra state information to record how much of the 64bit block we have
++ * used is contained in *num;
++ */
++
++void RC5_32_cfb64_encrypt(const unsigned char *in, unsigned char *out,
++                          long length, RC5_32_KEY *schedule,
++                          unsigned char *ivec, int *num, int encrypt)
++{
++    register unsigned long v0, v1, t;
++    register int n = *num;
++    register long l = length;
++    unsigned long ti[2];
++    unsigned char *iv, c, cc;
++
++    iv = (unsigned char *)ivec;
++    if (encrypt) {
++        while (l--) {
++            if (n == 0) {
++                c2l(iv, v0);
++                ti[0] = v0;
++                c2l(iv, v1);
++                ti[1] = v1;
++                RC5_32_encrypt((unsigned long *)ti, schedule);
++                iv = (unsigned char *)ivec;
++                t = ti[0];
++                l2c(t, iv);
++                t = ti[1];
++                l2c(t, iv);
++                iv = (unsigned char *)ivec;
++            }
++            c = *(in++) ^ iv[n];
++            *(out++) = c;
++            iv[n] = c;
++            n = (n + 1) & 0x07;
++        }
++    } else {
++        while (l--) {
++            if (n == 0) {
++                c2l(iv, v0);
++                ti[0] = v0;
++                c2l(iv, v1);
++                ti[1] = v1;
++                RC5_32_encrypt((unsigned long *)ti, schedule);
++                iv = (unsigned char *)ivec;
++                t = ti[0];
++                l2c(t, iv);
++                t = ti[1];
++                l2c(t, iv);
++                iv = (unsigned char *)ivec;
++            }
++            cc = *(in++);
++            c = iv[n];
++            iv[n] = cc;
++            *(out++) = c ^ cc;
++            n = (n + 1) & 0x07;
++        }
++    }
++    v0 = v1 = ti[0] = ti[1] = t = c = cc = 0;
++    *num = n;
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/rc5/rc5ofb64.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/rc5/rc5ofb64.c
+new file mode 100644
+index 0000000..3a41d77
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/rc5/rc5ofb64.c
+@@ -0,0 +1,61 @@
++/*
++ * Copyright 1995-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include "rc5_locl.h"
++
++/*
++ * The input and output encrypted as though 64bit ofb mode is being used.
++ * The extra state information to record how much of the 64bit block we have
++ * used is contained in *num;
++ */
++void RC5_32_ofb64_encrypt(const unsigned char *in, unsigned char *out,
++                          long length, RC5_32_KEY *schedule,
++                          unsigned char *ivec, int *num)
++{
++    register unsigned long v0, v1, t;
++    register int n = *num;
++    register long l = length;
++    unsigned char d[8];
++    register char *dp;
++    unsigned long ti[2];
++    unsigned char *iv;
++    int save = 0;
++
++    iv = (unsigned char *)ivec;
++    c2l(iv, v0);
++    c2l(iv, v1);
++    ti[0] = v0;
++    ti[1] = v1;
++    dp = (char *)d;
++    l2c(v0, dp);
++    l2c(v1, dp);
++    while (l--) {
++        if (n == 0) {
++            RC5_32_encrypt((unsigned long *)ti, schedule);
++            dp = (char *)d;
++            t = ti[0];
++            l2c(t, dp);
++            t = ti[1];
++            l2c(t, dp);
++            save++;
++        }
++        *(out++) = *(in++) ^ d[n];
++        n = (n + 1) & 0x07;
++    }
++    if (save) {
++        v0 = ti[0];
++        v1 = ti[1];
++        iv = (unsigned char *)ivec;
++        l2c(v0, iv);
++        l2c(v1, iv);
++    }
++    t = v0 = v1 = ti[0] = ti[1] = 0;
++    *num = n;
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/ripemd/asm/rmd-586.pl b/CryptoPkg/Library/OpensslLib/openssl/crypto/ripemd/asm/rmd-586.pl
+new file mode 100644
+index 0000000..544c496
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/ripemd/asm/rmd-586.pl
+@@ -0,0 +1,603 @@
++#! /usr/bin/env perl
++# Copyright 1995-2016 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
++# in the file LICENSE in the source distribution or at
++# https://www.openssl.org/source/license.html
++
++
++# Normal is the
++# ripemd160_block_asm_data_order(RIPEMD160_CTX *c, ULONG *X,int blocks);
++
++$normal=0;
++
++$0 =~ m/(.*[\/\\])[^\/\\]+$/; $dir=$1;
++push(@INC,"${dir}","${dir}../../perlasm");
++require "x86asm.pl";
++
++$output=pop;
++open STDOUT,">$output";
++
++&asm_init($ARGV[0],$0);
++
++$A="ecx";
++$B="esi";
++$C="edi";
++$D="ebx";
++$E="ebp";
++$tmp1="eax";
++$tmp2="edx";
++
++$KL1=0x5A827999;
++$KL2=0x6ED9EBA1;
++$KL3=0x8F1BBCDC;
++$KL4=0xA953FD4E;
++$KR0=0x50A28BE6;
++$KR1=0x5C4DD124; 
++$KR2=0x6D703EF3;
++$KR3=0x7A6D76E9;
++
++
++@wl=(	 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14,15,
++	 7, 4,13, 1,10, 6,15, 3,12, 0, 9, 5, 2,14,11, 8,
++	 3,10,14, 4, 9,15, 8, 1, 2, 7, 0, 6,13,11, 5,12,
++	 1, 9,11,10, 0, 8,12, 4,13, 3, 7,15,14, 5, 6, 2,
++	 4, 0, 5, 9, 7,12, 2,10,14, 1, 3, 8,11, 6,15,13,
++	 );
++
++@wr=(	 5,14, 7, 0, 9, 2,11, 4,13, 6,15, 8, 1,10, 3,12,
++	 6,11, 3, 7, 0,13, 5,10,14,15, 8,12, 4, 9, 1, 2,
++	15, 5, 1, 3, 7,14, 6, 9,11, 8,12, 2,10, 0, 4,13,
++	 8, 6, 4, 1, 3,11,15, 0, 5,12, 2,13, 9, 7,10,14,
++	12,15,10, 4, 1, 5, 8, 7, 6, 2,13,14, 0, 3, 9,11,
++	);
++
++@sl=(	11,14,15,12, 5, 8, 7, 9,11,13,14,15, 6, 7, 9, 8,
++	 7, 6, 8,13,11, 9, 7,15, 7,12,15, 9,11, 7,13,12,
++	11,13, 6, 7,14, 9,13,15,14, 8,13, 6, 5,12, 7, 5,
++	11,12,14,15,14,15, 9, 8, 9,14, 5, 6, 8, 6, 5,12,
++	 9,15, 5,11, 6, 8,13,12, 5,12,13,14,11, 8, 5, 6,
++	 );
++
++@sr=(	 8, 9, 9,11,13,15,15, 5, 7, 7, 8,11,14,14,12, 6,
++	 9,13,15, 7,12, 8, 9,11, 7, 7,12, 7, 6,15,13,11,
++	 9, 7,15,11, 8, 6, 6,14,12,13, 5,14,13,13, 7, 5,
++	15, 5, 8,11,14,14, 6,14, 6, 9,12, 9,12, 5,15, 8,
++	 8, 5,12, 9,12, 5,14, 6, 8,13, 6, 5,15,13,11,11,
++ 	);
++
++&ripemd160_block("ripemd160_block_asm_data_order");
++&asm_finish();
++
++close STDOUT;
++
++sub Xv
++	{
++	local($n)=@_;
++	return(&swtmp($n));
++	# tmp on stack
++	}
++
++sub Np
++	{
++	local($p)=@_;
++	local(%n)=($A,$E,$B,$A,$C,$B,$D,$C,$E,$D);
++	return($n{$p});
++	}
++
++sub RIP1
++	{
++	local($a,$b,$c,$d,$e,$pos,$s,$o,$pos2)=@_;
++
++	&comment($p++);
++	if ($p & 1)
++		{
++	 #&mov($tmp1,	$c) if $o == -1;
++	&xor($tmp1,	$d) if $o == -1;
++	 &mov($tmp2,	&Xv($pos));
++	&xor($tmp1,	$b);
++	 &add($a,	$tmp2);
++	&rotl($c,	10);
++	&add($a,	$tmp1);
++	 &mov($tmp1,	&Np($c));	# NEXT
++	 # XXX
++	&rotl($a,	$s);
++	&add($a,	$e);
++		}
++	else
++		{
++	 &xor($tmp1,	$d);
++	&mov($tmp2,	&Xv($pos));
++	 &xor($tmp1,	$b);
++	&add($a,	$tmp1);
++	 &mov($tmp1,	&Np($c)) if $o <= 0;
++	 &mov($tmp1,	-1) if $o == 1;
++	 # XXX if $o == 2;
++	&rotl($c,	10);
++	&add($a,	$tmp2);
++	 &xor($tmp1,	&Np($d)) if $o <= 0;
++	 &mov($tmp2,	&Xv($pos2)) if $o == 1;
++	 &mov($tmp2,	&wparam(0)) if $o == 2;
++	&rotl($a,	$s);
++	&add($a,	$e);
++		}
++	}
++
++sub RIP2
++	{
++	local($a,$b,$c,$d,$e,$pos,$pos2,$s,$K,$o)=@_;
++
++# XXXXXX
++	&comment($p++);
++	if ($p & 1)
++		{
++#	 &mov($tmp2,	&Xv($pos)) if $o < -1;
++#	&mov($tmp1,	-1) if $o < -1;
++
++	 &add($a,	$tmp2);
++	&mov($tmp2,	$c);
++	 &sub($tmp1,	$b);
++	&and($tmp2,	$b);
++	 &and($tmp1,	$d);
++	&or($tmp2,	$tmp1);
++	 &mov($tmp1,	&Xv($pos2)) if $o <= 0; # XXXXXXXXXXXXXX
++	 # XXX
++	&rotl($c,	10);
++	&lea($a,	&DWP($K,$a,$tmp2,1));
++	 &mov($tmp2,	-1) if $o <= 0;
++	 # XXX
++	&rotl($a,	$s);
++	&add($a,	$e);
++		}
++	else
++		{
++	 # XXX
++	 &add($a,	$tmp1);
++	&mov($tmp1,	$c);
++	 &sub($tmp2,	$b);
++	&and($tmp1,	$b);
++	 &and($tmp2,	$d);
++	if ($o != 2)
++		{
++	&or($tmp1,	$tmp2);
++	 &mov($tmp2,	&Xv($pos2)) if $o <= 0;
++	 &mov($tmp2,	-1) if $o == 1;
++	&rotl($c,	10);
++	&lea($a,	&DWP($K,$a,$tmp1,1));
++	 &mov($tmp1,	-1) if $o <= 0;
++	 &sub($tmp2,	&Np($c)) if $o == 1;
++		} else {
++	&or($tmp2,	$tmp1);
++	 &mov($tmp1,	&Np($c));
++	&rotl($c,	10);
++	&lea($a,	&DWP($K,$a,$tmp2,1));
++	 &xor($tmp1,	&Np($d));
++		}
++	&rotl($a,	$s);
++	&add($a,	$e);
++		}
++	}
++
++sub RIP3
++	{
++	local($a,$b,$c,$d,$e,$pos,$s,$K,$o,$pos2)=@_;
++
++	&comment($p++);
++	if ($p & 1)
++		{
++#	 &mov($tmp2,	-1) if $o < -1;
++#	&sub($tmp2,	$c) if $o < -1;
++	 &mov($tmp1,	&Xv($pos));
++	&or($tmp2,	$b);
++	 &add($a,	$tmp1);
++	&xor($tmp2,	$d);
++	 &mov($tmp1,	-1) if $o <= 0;		# NEXT
++	 # XXX
++	&rotl($c,	10);
++	&lea($a,	&DWP($K,$a,$tmp2,1));
++	 &sub($tmp1,	&Np($c)) if $o <= 0;	# NEXT
++	 # XXX
++	&rotl($a,	$s);
++	&add($a,	$e);
++		}
++	else
++		{
++	 &mov($tmp2,	&Xv($pos));
++	&or($tmp1,	$b);
++	 &add($a,	$tmp2);
++	&xor($tmp1,	$d);
++	 &mov($tmp2,	-1) if $o <= 0;		# NEXT
++	 &mov($tmp2,	-1) if $o == 1;
++	 &mov($tmp2,	&Xv($pos2)) if $o == 2;
++	&rotl($c,	10);
++	&lea($a,	&DWP($K,$a,$tmp1,1));
++	 &sub($tmp2,	&Np($c)) if $o <= 0;	# NEXT
++	 &mov($tmp1,	&Np($d)) if $o == 1;
++	 &mov($tmp1,	-1) if $o == 2;
++	&rotl($a,	$s);
++	&add($a,	$e);
++		}
++	}
++
++sub RIP4
++	{
++	local($a,$b,$c,$d,$e,$pos,$s,$K,$o)=@_;
++
++	&comment($p++);
++	if ($p & 1)
++		{
++#	 &mov($tmp2,	-1) if $o == -2;
++#	&mov($tmp1,	$d) if $o == -2;
++	 &sub($tmp2,	$d);
++	&and($tmp1,	$b);
++	 &and($tmp2,	$c);
++	&or($tmp2,	$tmp1);
++	 &mov($tmp1,	&Xv($pos));
++	&rotl($c,	10);
++	&lea($a,	&DWP($K,$a,$tmp2));
++	 &mov($tmp2,	-1) unless $o > 0;	# NEXT
++	 # XXX
++	&add($a,	$tmp1);
++	 &mov($tmp1,	&Np($d)) unless $o > 0; # NEXT
++	 # XXX
++	&rotl($a,	$s);
++	&add($a,	$e);
++		}
++	else
++		{
++	 &sub($tmp2,	$d);
++	&and($tmp1,	$b);
++	 &and($tmp2,	$c);
++	&or($tmp2,	$tmp1);
++	 &mov($tmp1,	&Xv($pos));
++	&rotl($c,	10);
++	&lea($a,	&DWP($K,$a,$tmp2));
++	 &mov($tmp2,	-1) if $o == 0;	# NEXT
++	 &mov($tmp2,	-1) if $o == 1;
++	 &mov($tmp2,	-1) if $o == 2;
++	 # XXX
++	&add($a,	$tmp1);
++	 &mov($tmp1,	&Np($d)) if $o == 0;	# NEXT
++	 &sub($tmp2,	&Np($d)) if $o == 1;
++	 &sub($tmp2,	&Np($c)) if $o == 2;
++	 # XXX
++	&rotl($a,	$s);
++	&add($a,	$e);
++		}
++	}
++
++sub RIP5
++	{
++	local($a,$b,$c,$d,$e,$pos,$s,$K,$o)=@_;
++
++	&comment($p++);
++	if ($p & 1)
++		{
++	 &mov($tmp2,	-1) if $o == -2;
++	&sub($tmp2,	$d) if $o == -2;
++	 &mov($tmp1,	&Xv($pos));
++	&or($tmp2,	$c);
++	 &add($a,	$tmp1);
++	&xor($tmp2,	$b);
++	 &mov($tmp1,	-1) if $o <= 0;
++	 # XXX
++	&rotl($c,	10);
++	&lea($a,	&DWP($K,$a,$tmp2,1));
++	 &sub($tmp1,	&Np($d)) if $o <= 0;
++	 # XXX
++	&rotl($a,	$s);
++	&add($a,	$e);
++		}
++	else
++		{
++	 &mov($tmp2,	&Xv($pos));
++	&or($tmp1,	$c);
++	 &add($a,	$tmp2);
++	&xor($tmp1,	$b);
++	 &mov($tmp2,	-1) if $o <= 0;
++	 &mov($tmp2,	&wparam(0)) if $o == 1;	# Middle code
++	 &mov($tmp2,	-1) if $o == 2;
++	&rotl($c,	10);
++	&lea($a,	&DWP($K,$a,$tmp1,1));
++	 &sub($tmp2,	&Np($d)) if $o <= 0;
++	 &mov(&swtmp(16),	$A) if $o == 1;
++	 &mov($tmp1,	&Np($d)) if $o == 2;
++	&rotl($a,	$s);
++	&add($a,	$e);
++		}
++	}
++
++sub ripemd160_block
++	{
++	local($name)=@_;
++
++	&function_begin_B($name,"",3);
++
++	# parameter 1 is the RIPEMD160_CTX structure.
++	# A	0
++	# B	4
++	# C	8
++	# D 	12
++	# E 	16
++
++	&mov($tmp2,	&wparam(0));
++	 &mov($tmp1,	&wparam(1));
++	&push("esi");
++	 &mov($A,	&DWP( 0,$tmp2,"",0));
++	&push("edi");
++	 &mov($B,	&DWP( 4,$tmp2,"",0));
++	&push("ebp");
++	 &mov($C,	&DWP( 8,$tmp2,"",0));
++	&push("ebx");
++	 &stack_push(16+5+6);
++			  # Special comment about the figure of 6.
++			  # Idea is to pad the current frame so
++			  # that the top of the stack gets fairly
++			  # aligned. Well, as you realize it would
++			  # always depend on how the frame below is
++			  # aligned. The good news are that gcc-2.95
++			  # and later does keep first argument at
++			  # least double-wise aligned.
++			  #			
++
++	&set_label("start") unless $normal;
++	&comment("");
++
++	# &mov($tmp1,	&wparam(1)); # Done at end of loop
++	# &mov($tmp2,	&wparam(0)); # Done at end of loop
++
++	for ($z=0; $z<16; $z+=2)
++		{
++		&mov($D,		&DWP( $z*4,$tmp1,"",0));
++		 &mov($E,		&DWP( ($z+1)*4,$tmp1,"",0));
++		&mov(&swtmp($z),	$D);
++		 &mov(&swtmp($z+1),	$E);
++		}
++	&mov($tmp1,	$C);
++	 &mov($D,	&DWP(12,$tmp2,"",0));
++	&mov($E,	&DWP(16,$tmp2,"",0));
++
++	&RIP1($A,$B,$C,$D,$E,$wl[ 0],$sl[ 0],-1);
++	&RIP1($E,$A,$B,$C,$D,$wl[ 1],$sl[ 1],0);
++	&RIP1($D,$E,$A,$B,$C,$wl[ 2],$sl[ 2],0);
++	&RIP1($C,$D,$E,$A,$B,$wl[ 3],$sl[ 3],0);
++	&RIP1($B,$C,$D,$E,$A,$wl[ 4],$sl[ 4],0);
++	&RIP1($A,$B,$C,$D,$E,$wl[ 5],$sl[ 5],0);
++	&RIP1($E,$A,$B,$C,$D,$wl[ 6],$sl[ 6],0);
++	&RIP1($D,$E,$A,$B,$C,$wl[ 7],$sl[ 7],0);
++	&RIP1($C,$D,$E,$A,$B,$wl[ 8],$sl[ 8],0);
++	&RIP1($B,$C,$D,$E,$A,$wl[ 9],$sl[ 9],0);
++	&RIP1($A,$B,$C,$D,$E,$wl[10],$sl[10],0);
++	&RIP1($E,$A,$B,$C,$D,$wl[11],$sl[11],0);
++	&RIP1($D,$E,$A,$B,$C,$wl[12],$sl[12],0);
++	&RIP1($C,$D,$E,$A,$B,$wl[13],$sl[13],0);
++	&RIP1($B,$C,$D,$E,$A,$wl[14],$sl[14],0);
++	&RIP1($A,$B,$C,$D,$E,$wl[15],$sl[15],1,$wl[16]);
++
++	&RIP2($E,$A,$B,$C,$D,$wl[16],$wl[17],$sl[16],$KL1,-1);
++	&RIP2($D,$E,$A,$B,$C,$wl[17],$wl[18],$sl[17],$KL1,0);
++	&RIP2($C,$D,$E,$A,$B,$wl[18],$wl[19],$sl[18],$KL1,0);
++	&RIP2($B,$C,$D,$E,$A,$wl[19],$wl[20],$sl[19],$KL1,0);
++	&RIP2($A,$B,$C,$D,$E,$wl[20],$wl[21],$sl[20],$KL1,0);
++	&RIP2($E,$A,$B,$C,$D,$wl[21],$wl[22],$sl[21],$KL1,0);
++	&RIP2($D,$E,$A,$B,$C,$wl[22],$wl[23],$sl[22],$KL1,0);
++	&RIP2($C,$D,$E,$A,$B,$wl[23],$wl[24],$sl[23],$KL1,0);
++	&RIP2($B,$C,$D,$E,$A,$wl[24],$wl[25],$sl[24],$KL1,0);
++	&RIP2($A,$B,$C,$D,$E,$wl[25],$wl[26],$sl[25],$KL1,0);
++	&RIP2($E,$A,$B,$C,$D,$wl[26],$wl[27],$sl[26],$KL1,0);
++	&RIP2($D,$E,$A,$B,$C,$wl[27],$wl[28],$sl[27],$KL1,0);
++	&RIP2($C,$D,$E,$A,$B,$wl[28],$wl[29],$sl[28],$KL1,0);
++	&RIP2($B,$C,$D,$E,$A,$wl[29],$wl[30],$sl[29],$KL1,0);
++	&RIP2($A,$B,$C,$D,$E,$wl[30],$wl[31],$sl[30],$KL1,0);
++	&RIP2($E,$A,$B,$C,$D,$wl[31],$wl[32],$sl[31],$KL1,1);
++
++	&RIP3($D,$E,$A,$B,$C,$wl[32],$sl[32],$KL2,-1);
++	&RIP3($C,$D,$E,$A,$B,$wl[33],$sl[33],$KL2,0);
++	&RIP3($B,$C,$D,$E,$A,$wl[34],$sl[34],$KL2,0);
++	&RIP3($A,$B,$C,$D,$E,$wl[35],$sl[35],$KL2,0);
++	&RIP3($E,$A,$B,$C,$D,$wl[36],$sl[36],$KL2,0);
++	&RIP3($D,$E,$A,$B,$C,$wl[37],$sl[37],$KL2,0);
++	&RIP3($C,$D,$E,$A,$B,$wl[38],$sl[38],$KL2,0);
++	&RIP3($B,$C,$D,$E,$A,$wl[39],$sl[39],$KL2,0);
++	&RIP3($A,$B,$C,$D,$E,$wl[40],$sl[40],$KL2,0);
++	&RIP3($E,$A,$B,$C,$D,$wl[41],$sl[41],$KL2,0);
++	&RIP3($D,$E,$A,$B,$C,$wl[42],$sl[42],$KL2,0);
++	&RIP3($C,$D,$E,$A,$B,$wl[43],$sl[43],$KL2,0);
++	&RIP3($B,$C,$D,$E,$A,$wl[44],$sl[44],$KL2,0);
++	&RIP3($A,$B,$C,$D,$E,$wl[45],$sl[45],$KL2,0);
++	&RIP3($E,$A,$B,$C,$D,$wl[46],$sl[46],$KL2,0);
++	&RIP3($D,$E,$A,$B,$C,$wl[47],$sl[47],$KL2,1);
++
++	&RIP4($C,$D,$E,$A,$B,$wl[48],$sl[48],$KL3,-1);
++	&RIP4($B,$C,$D,$E,$A,$wl[49],$sl[49],$KL3,0);
++	&RIP4($A,$B,$C,$D,$E,$wl[50],$sl[50],$KL3,0);
++	&RIP4($E,$A,$B,$C,$D,$wl[51],$sl[51],$KL3,0);
++	&RIP4($D,$E,$A,$B,$C,$wl[52],$sl[52],$KL3,0);
++	&RIP4($C,$D,$E,$A,$B,$wl[53],$sl[53],$KL3,0);
++	&RIP4($B,$C,$D,$E,$A,$wl[54],$sl[54],$KL3,0);
++	&RIP4($A,$B,$C,$D,$E,$wl[55],$sl[55],$KL3,0);
++	&RIP4($E,$A,$B,$C,$D,$wl[56],$sl[56],$KL3,0);
++	&RIP4($D,$E,$A,$B,$C,$wl[57],$sl[57],$KL3,0);
++	&RIP4($C,$D,$E,$A,$B,$wl[58],$sl[58],$KL3,0);
++	&RIP4($B,$C,$D,$E,$A,$wl[59],$sl[59],$KL3,0);
++	&RIP4($A,$B,$C,$D,$E,$wl[60],$sl[60],$KL3,0);
++	&RIP4($E,$A,$B,$C,$D,$wl[61],$sl[61],$KL3,0);
++	&RIP4($D,$E,$A,$B,$C,$wl[62],$sl[62],$KL3,0);
++	&RIP4($C,$D,$E,$A,$B,$wl[63],$sl[63],$KL3,1);
++
++	&RIP5($B,$C,$D,$E,$A,$wl[64],$sl[64],$KL4,-1);
++	&RIP5($A,$B,$C,$D,$E,$wl[65],$sl[65],$KL4,0);
++	&RIP5($E,$A,$B,$C,$D,$wl[66],$sl[66],$KL4,0);
++	&RIP5($D,$E,$A,$B,$C,$wl[67],$sl[67],$KL4,0);
++	&RIP5($C,$D,$E,$A,$B,$wl[68],$sl[68],$KL4,0);
++	&RIP5($B,$C,$D,$E,$A,$wl[69],$sl[69],$KL4,0);
++	&RIP5($A,$B,$C,$D,$E,$wl[70],$sl[70],$KL4,0);
++	&RIP5($E,$A,$B,$C,$D,$wl[71],$sl[71],$KL4,0);
++	&RIP5($D,$E,$A,$B,$C,$wl[72],$sl[72],$KL4,0);
++	&RIP5($C,$D,$E,$A,$B,$wl[73],$sl[73],$KL4,0);
++	&RIP5($B,$C,$D,$E,$A,$wl[74],$sl[74],$KL4,0);
++	&RIP5($A,$B,$C,$D,$E,$wl[75],$sl[75],$KL4,0);
++	&RIP5($E,$A,$B,$C,$D,$wl[76],$sl[76],$KL4,0);
++	&RIP5($D,$E,$A,$B,$C,$wl[77],$sl[77],$KL4,0);
++	&RIP5($C,$D,$E,$A,$B,$wl[78],$sl[78],$KL4,0);
++	&RIP5($B,$C,$D,$E,$A,$wl[79],$sl[79],$KL4,1);
++
++	# &mov($tmp2,	&wparam(0)); # moved into last RIP5
++	# &mov(&swtmp(16),	$A);
++	 &mov($A,	&DWP( 0,$tmp2,"",0));
++	&mov(&swtmp(16+1),	$B);
++	 &mov(&swtmp(16+2),	$C);
++	&mov($B,	&DWP( 4,$tmp2,"",0));
++	 &mov(&swtmp(16+3),	$D);
++	&mov($C,	&DWP( 8,$tmp2,"",0));
++	 &mov(&swtmp(16+4),	$E);
++	&mov($D,	&DWP(12,$tmp2,"",0));
++	 &mov($E,	&DWP(16,$tmp2,"",0));
++
++	&RIP5($A,$B,$C,$D,$E,$wr[ 0],$sr[ 0],$KR0,-2);
++	&RIP5($E,$A,$B,$C,$D,$wr[ 1],$sr[ 1],$KR0,0);
++	&RIP5($D,$E,$A,$B,$C,$wr[ 2],$sr[ 2],$KR0,0);
++	&RIP5($C,$D,$E,$A,$B,$wr[ 3],$sr[ 3],$KR0,0);
++	&RIP5($B,$C,$D,$E,$A,$wr[ 4],$sr[ 4],$KR0,0);
++	&RIP5($A,$B,$C,$D,$E,$wr[ 5],$sr[ 5],$KR0,0);
++	&RIP5($E,$A,$B,$C,$D,$wr[ 6],$sr[ 6],$KR0,0);
++	&RIP5($D,$E,$A,$B,$C,$wr[ 7],$sr[ 7],$KR0,0);
++	&RIP5($C,$D,$E,$A,$B,$wr[ 8],$sr[ 8],$KR0,0);
++	&RIP5($B,$C,$D,$E,$A,$wr[ 9],$sr[ 9],$KR0,0);
++	&RIP5($A,$B,$C,$D,$E,$wr[10],$sr[10],$KR0,0);
++	&RIP5($E,$A,$B,$C,$D,$wr[11],$sr[11],$KR0,0);
++	&RIP5($D,$E,$A,$B,$C,$wr[12],$sr[12],$KR0,0);
++	&RIP5($C,$D,$E,$A,$B,$wr[13],$sr[13],$KR0,0);
++	&RIP5($B,$C,$D,$E,$A,$wr[14],$sr[14],$KR0,0);
++	&RIP5($A,$B,$C,$D,$E,$wr[15],$sr[15],$KR0,2);
++
++	&RIP4($E,$A,$B,$C,$D,$wr[16],$sr[16],$KR1,-2);
++	&RIP4($D,$E,$A,$B,$C,$wr[17],$sr[17],$KR1,0);
++	&RIP4($C,$D,$E,$A,$B,$wr[18],$sr[18],$KR1,0);
++	&RIP4($B,$C,$D,$E,$A,$wr[19],$sr[19],$KR1,0);
++	&RIP4($A,$B,$C,$D,$E,$wr[20],$sr[20],$KR1,0);
++	&RIP4($E,$A,$B,$C,$D,$wr[21],$sr[21],$KR1,0);
++	&RIP4($D,$E,$A,$B,$C,$wr[22],$sr[22],$KR1,0);
++	&RIP4($C,$D,$E,$A,$B,$wr[23],$sr[23],$KR1,0);
++	&RIP4($B,$C,$D,$E,$A,$wr[24],$sr[24],$KR1,0);
++	&RIP4($A,$B,$C,$D,$E,$wr[25],$sr[25],$KR1,0);
++	&RIP4($E,$A,$B,$C,$D,$wr[26],$sr[26],$KR1,0);
++	&RIP4($D,$E,$A,$B,$C,$wr[27],$sr[27],$KR1,0);
++	&RIP4($C,$D,$E,$A,$B,$wr[28],$sr[28],$KR1,0);
++	&RIP4($B,$C,$D,$E,$A,$wr[29],$sr[29],$KR1,0);
++	&RIP4($A,$B,$C,$D,$E,$wr[30],$sr[30],$KR1,0);
++	&RIP4($E,$A,$B,$C,$D,$wr[31],$sr[31],$KR1,2);
++
++	&RIP3($D,$E,$A,$B,$C,$wr[32],$sr[32],$KR2,-2);
++	&RIP3($C,$D,$E,$A,$B,$wr[33],$sr[33],$KR2,0);
++	&RIP3($B,$C,$D,$E,$A,$wr[34],$sr[34],$KR2,0);
++	&RIP3($A,$B,$C,$D,$E,$wr[35],$sr[35],$KR2,0);
++	&RIP3($E,$A,$B,$C,$D,$wr[36],$sr[36],$KR2,0);
++	&RIP3($D,$E,$A,$B,$C,$wr[37],$sr[37],$KR2,0);
++	&RIP3($C,$D,$E,$A,$B,$wr[38],$sr[38],$KR2,0);
++	&RIP3($B,$C,$D,$E,$A,$wr[39],$sr[39],$KR2,0);
++	&RIP3($A,$B,$C,$D,$E,$wr[40],$sr[40],$KR2,0);
++	&RIP3($E,$A,$B,$C,$D,$wr[41],$sr[41],$KR2,0);
++	&RIP3($D,$E,$A,$B,$C,$wr[42],$sr[42],$KR2,0);
++	&RIP3($C,$D,$E,$A,$B,$wr[43],$sr[43],$KR2,0);
++	&RIP3($B,$C,$D,$E,$A,$wr[44],$sr[44],$KR2,0);
++	&RIP3($A,$B,$C,$D,$E,$wr[45],$sr[45],$KR2,0);
++	&RIP3($E,$A,$B,$C,$D,$wr[46],$sr[46],$KR2,0);
++	&RIP3($D,$E,$A,$B,$C,$wr[47],$sr[47],$KR2,2,$wr[48]);
++
++	&RIP2($C,$D,$E,$A,$B,$wr[48],$wr[49],$sr[48],$KR3,-2);
++	&RIP2($B,$C,$D,$E,$A,$wr[49],$wr[50],$sr[49],$KR3,0);
++	&RIP2($A,$B,$C,$D,$E,$wr[50],$wr[51],$sr[50],$KR3,0);
++	&RIP2($E,$A,$B,$C,$D,$wr[51],$wr[52],$sr[51],$KR3,0);
++	&RIP2($D,$E,$A,$B,$C,$wr[52],$wr[53],$sr[52],$KR3,0);
++	&RIP2($C,$D,$E,$A,$B,$wr[53],$wr[54],$sr[53],$KR3,0);
++	&RIP2($B,$C,$D,$E,$A,$wr[54],$wr[55],$sr[54],$KR3,0);
++	&RIP2($A,$B,$C,$D,$E,$wr[55],$wr[56],$sr[55],$KR3,0);
++	&RIP2($E,$A,$B,$C,$D,$wr[56],$wr[57],$sr[56],$KR3,0);
++	&RIP2($D,$E,$A,$B,$C,$wr[57],$wr[58],$sr[57],$KR3,0);
++	&RIP2($C,$D,$E,$A,$B,$wr[58],$wr[59],$sr[58],$KR3,0);
++	&RIP2($B,$C,$D,$E,$A,$wr[59],$wr[60],$sr[59],$KR3,0);
++	&RIP2($A,$B,$C,$D,$E,$wr[60],$wr[61],$sr[60],$KR3,0);
++	&RIP2($E,$A,$B,$C,$D,$wr[61],$wr[62],$sr[61],$KR3,0);
++	&RIP2($D,$E,$A,$B,$C,$wr[62],$wr[63],$sr[62],$KR3,0);
++	&RIP2($C,$D,$E,$A,$B,$wr[63],$wr[64],$sr[63],$KR3,2);
++
++	&RIP1($B,$C,$D,$E,$A,$wr[64],$sr[64],-2);
++	&RIP1($A,$B,$C,$D,$E,$wr[65],$sr[65],0);
++	&RIP1($E,$A,$B,$C,$D,$wr[66],$sr[66],0);
++	&RIP1($D,$E,$A,$B,$C,$wr[67],$sr[67],0);
++	&RIP1($C,$D,$E,$A,$B,$wr[68],$sr[68],0);
++	&RIP1($B,$C,$D,$E,$A,$wr[69],$sr[69],0);
++	&RIP1($A,$B,$C,$D,$E,$wr[70],$sr[70],0);
++	&RIP1($E,$A,$B,$C,$D,$wr[71],$sr[71],0);
++	&RIP1($D,$E,$A,$B,$C,$wr[72],$sr[72],0);
++	&RIP1($C,$D,$E,$A,$B,$wr[73],$sr[73],0);
++	&RIP1($B,$C,$D,$E,$A,$wr[74],$sr[74],0);
++	&RIP1($A,$B,$C,$D,$E,$wr[75],$sr[75],0);
++	&RIP1($E,$A,$B,$C,$D,$wr[76],$sr[76],0);
++	&RIP1($D,$E,$A,$B,$C,$wr[77],$sr[77],0);
++	&RIP1($C,$D,$E,$A,$B,$wr[78],$sr[78],0);
++	&RIP1($B,$C,$D,$E,$A,$wr[79],$sr[79],2);
++
++	# &mov($tmp2,	&wparam(0)); # Moved into last round
++
++	 &mov($tmp1,	&DWP( 4,$tmp2,"",0));	# ctx->B
++ 	&add($D,	$tmp1);	
++	 &mov($tmp1,	&swtmp(16+2));		# $c
++	&add($D,	$tmp1);
++
++	 &mov($tmp1,	&DWP( 8,$tmp2,"",0));	# ctx->C
++	&add($E,	$tmp1);	
++	 &mov($tmp1,	&swtmp(16+3));		# $d
++	&add($E,	$tmp1);
++
++	 &mov($tmp1,	&DWP(12,$tmp2,"",0));	# ctx->D
++	&add($A,	$tmp1);	
++	 &mov($tmp1,	&swtmp(16+4));		# $e
++	&add($A,	$tmp1);
++
++
++	 &mov($tmp1,	&DWP(16,$tmp2,"",0));	# ctx->E
++	&add($B,	$tmp1);	
++	 &mov($tmp1,	&swtmp(16+0));		# $a
++	&add($B,	$tmp1);
++
++	 &mov($tmp1,	&DWP( 0,$tmp2,"",0));	# ctx->A
++	&add($C,	$tmp1);	
++	 &mov($tmp1,	&swtmp(16+1));		# $b
++	&add($C,	$tmp1);
++
++	 &mov($tmp1,	&wparam(2));
++
++	&mov(&DWP( 0,$tmp2,"",0),	$D);
++	 &mov(&DWP( 4,$tmp2,"",0),	$E);
++	&mov(&DWP( 8,$tmp2,"",0),	$A);
++	 &sub($tmp1,1);
++	&mov(&DWP(12,$tmp2,"",0),	$B);
++	 &mov(&DWP(16,$tmp2,"",0),	$C);
++
++	&jle(&label("get_out"));
++
++	&mov(&wparam(2),$tmp1);
++	 &mov($C,	$A);
++	&mov($tmp1,	&wparam(1));
++	 &mov($A,	$D);
++	&add($tmp1,	64);
++	 &mov($B,	$E);
++	&mov(&wparam(1),$tmp1);
++
++	&jmp(&label("start"));
++
++	&set_label("get_out");
++
++	&stack_pop(16+5+6);
++
++	&pop("ebx");
++	&pop("ebp");
++	&pop("edi");
++	&pop("esi");
++	&ret();
++	&function_end_B($name);
++	}
++
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/ripemd/build.info b/CryptoPkg/Library/OpensslLib/openssl/crypto/ripemd/build.info
+new file mode 100644
+index 0000000..c45050c
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/ripemd/build.info
+@@ -0,0 +1,6 @@
++LIBS=../../libcrypto
++SOURCE[../../libcrypto]=\
++        rmd_dgst.c rmd_one.c {- $target{rmd160_asm_src} -}
++
++GENERATE[rmd-586.s]=asm/rmd-586.pl $(PERLASM_SCHEME) $(CFLAGS) $(LIB_CFLAGS)
++DEPEND[rmd-586.s]=../perlasm/x86asm.pl
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/ripemd/rmd_dgst.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/ripemd/rmd_dgst.c
+new file mode 100644
+index 0000000..a1670c7
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/ripemd/rmd_dgst.c
+@@ -0,0 +1,282 @@
++/*
++ * Copyright 1995-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include "rmd_locl.h"
++#include 
++
++#ifdef RMD160_ASM
++void ripemd160_block_x86(RIPEMD160_CTX *c, unsigned long *p, size_t num);
++# define ripemd160_block ripemd160_block_x86
++#else
++void ripemd160_block(RIPEMD160_CTX *c, unsigned long *p, size_t num);
++#endif
++
++int RIPEMD160_Init(RIPEMD160_CTX *c)
++{
++    memset(c, 0, sizeof(*c));
++    c->A = RIPEMD160_A;
++    c->B = RIPEMD160_B;
++    c->C = RIPEMD160_C;
++    c->D = RIPEMD160_D;
++    c->E = RIPEMD160_E;
++    return 1;
++}
++
++#ifndef ripemd160_block_data_order
++# ifdef X
++#  undef X
++# endif
++void ripemd160_block_data_order(RIPEMD160_CTX *ctx, const void *p, size_t num)
++{
++    const unsigned char *data = p;
++    register unsigned MD32_REG_T A, B, C, D, E;
++    unsigned MD32_REG_T a, b, c, d, e, l;
++# ifndef MD32_XARRAY
++    /* See comment in crypto/sha/sha_locl.h for details. */
++    unsigned MD32_REG_T XX0, XX1, XX2, XX3, XX4, XX5, XX6, XX7,
++        XX8, XX9, XX10, XX11, XX12, XX13, XX14, XX15;
++#  define X(i)   XX##i
++# else
++    RIPEMD160_LONG XX[16];
++#  define X(i)   XX[i]
++# endif
++
++    for (; num--;) {
++
++        A = ctx->A;
++        B = ctx->B;
++        C = ctx->C;
++        D = ctx->D;
++        E = ctx->E;
++
++        (void)HOST_c2l(data, l);
++        X(0) = l;
++        (void)HOST_c2l(data, l);
++        X(1) = l;
++        RIP1(A, B, C, D, E, WL00, SL00);
++        (void)HOST_c2l(data, l);
++        X(2) = l;
++        RIP1(E, A, B, C, D, WL01, SL01);
++        (void)HOST_c2l(data, l);
++        X(3) = l;
++        RIP1(D, E, A, B, C, WL02, SL02);
++        (void)HOST_c2l(data, l);
++        X(4) = l;
++        RIP1(C, D, E, A, B, WL03, SL03);
++        (void)HOST_c2l(data, l);
++        X(5) = l;
++        RIP1(B, C, D, E, A, WL04, SL04);
++        (void)HOST_c2l(data, l);
++        X(6) = l;
++        RIP1(A, B, C, D, E, WL05, SL05);
++        (void)HOST_c2l(data, l);
++        X(7) = l;
++        RIP1(E, A, B, C, D, WL06, SL06);
++        (void)HOST_c2l(data, l);
++        X(8) = l;
++        RIP1(D, E, A, B, C, WL07, SL07);
++        (void)HOST_c2l(data, l);
++        X(9) = l;
++        RIP1(C, D, E, A, B, WL08, SL08);
++        (void)HOST_c2l(data, l);
++        X(10) = l;
++        RIP1(B, C, D, E, A, WL09, SL09);
++        (void)HOST_c2l(data, l);
++        X(11) = l;
++        RIP1(A, B, C, D, E, WL10, SL10);
++        (void)HOST_c2l(data, l);
++        X(12) = l;
++        RIP1(E, A, B, C, D, WL11, SL11);
++        (void)HOST_c2l(data, l);
++        X(13) = l;
++        RIP1(D, E, A, B, C, WL12, SL12);
++        (void)HOST_c2l(data, l);
++        X(14) = l;
++        RIP1(C, D, E, A, B, WL13, SL13);
++        (void)HOST_c2l(data, l);
++        X(15) = l;
++        RIP1(B, C, D, E, A, WL14, SL14);
++        RIP1(A, B, C, D, E, WL15, SL15);
++
++        RIP2(E, A, B, C, D, WL16, SL16, KL1);
++        RIP2(D, E, A, B, C, WL17, SL17, KL1);
++        RIP2(C, D, E, A, B, WL18, SL18, KL1);
++        RIP2(B, C, D, E, A, WL19, SL19, KL1);
++        RIP2(A, B, C, D, E, WL20, SL20, KL1);
++        RIP2(E, A, B, C, D, WL21, SL21, KL1);
++        RIP2(D, E, A, B, C, WL22, SL22, KL1);
++        RIP2(C, D, E, A, B, WL23, SL23, KL1);
++        RIP2(B, C, D, E, A, WL24, SL24, KL1);
++        RIP2(A, B, C, D, E, WL25, SL25, KL1);
++        RIP2(E, A, B, C, D, WL26, SL26, KL1);
++        RIP2(D, E, A, B, C, WL27, SL27, KL1);
++        RIP2(C, D, E, A, B, WL28, SL28, KL1);
++        RIP2(B, C, D, E, A, WL29, SL29, KL1);
++        RIP2(A, B, C, D, E, WL30, SL30, KL1);
++        RIP2(E, A, B, C, D, WL31, SL31, KL1);
++
++        RIP3(D, E, A, B, C, WL32, SL32, KL2);
++        RIP3(C, D, E, A, B, WL33, SL33, KL2);
++        RIP3(B, C, D, E, A, WL34, SL34, KL2);
++        RIP3(A, B, C, D, E, WL35, SL35, KL2);
++        RIP3(E, A, B, C, D, WL36, SL36, KL2);
++        RIP3(D, E, A, B, C, WL37, SL37, KL2);
++        RIP3(C, D, E, A, B, WL38, SL38, KL2);
++        RIP3(B, C, D, E, A, WL39, SL39, KL2);
++        RIP3(A, B, C, D, E, WL40, SL40, KL2);
++        RIP3(E, A, B, C, D, WL41, SL41, KL2);
++        RIP3(D, E, A, B, C, WL42, SL42, KL2);
++        RIP3(C, D, E, A, B, WL43, SL43, KL2);
++        RIP3(B, C, D, E, A, WL44, SL44, KL2);
++        RIP3(A, B, C, D, E, WL45, SL45, KL2);
++        RIP3(E, A, B, C, D, WL46, SL46, KL2);
++        RIP3(D, E, A, B, C, WL47, SL47, KL2);
++
++        RIP4(C, D, E, A, B, WL48, SL48, KL3);
++        RIP4(B, C, D, E, A, WL49, SL49, KL3);
++        RIP4(A, B, C, D, E, WL50, SL50, KL3);
++        RIP4(E, A, B, C, D, WL51, SL51, KL3);
++        RIP4(D, E, A, B, C, WL52, SL52, KL3);
++        RIP4(C, D, E, A, B, WL53, SL53, KL3);
++        RIP4(B, C, D, E, A, WL54, SL54, KL3);
++        RIP4(A, B, C, D, E, WL55, SL55, KL3);
++        RIP4(E, A, B, C, D, WL56, SL56, KL3);
++        RIP4(D, E, A, B, C, WL57, SL57, KL3);
++        RIP4(C, D, E, A, B, WL58, SL58, KL3);
++        RIP4(B, C, D, E, A, WL59, SL59, KL3);
++        RIP4(A, B, C, D, E, WL60, SL60, KL3);
++        RIP4(E, A, B, C, D, WL61, SL61, KL3);
++        RIP4(D, E, A, B, C, WL62, SL62, KL3);
++        RIP4(C, D, E, A, B, WL63, SL63, KL3);
++
++        RIP5(B, C, D, E, A, WL64, SL64, KL4);
++        RIP5(A, B, C, D, E, WL65, SL65, KL4);
++        RIP5(E, A, B, C, D, WL66, SL66, KL4);
++        RIP5(D, E, A, B, C, WL67, SL67, KL4);
++        RIP5(C, D, E, A, B, WL68, SL68, KL4);
++        RIP5(B, C, D, E, A, WL69, SL69, KL4);
++        RIP5(A, B, C, D, E, WL70, SL70, KL4);
++        RIP5(E, A, B, C, D, WL71, SL71, KL4);
++        RIP5(D, E, A, B, C, WL72, SL72, KL4);
++        RIP5(C, D, E, A, B, WL73, SL73, KL4);
++        RIP5(B, C, D, E, A, WL74, SL74, KL4);
++        RIP5(A, B, C, D, E, WL75, SL75, KL4);
++        RIP5(E, A, B, C, D, WL76, SL76, KL4);
++        RIP5(D, E, A, B, C, WL77, SL77, KL4);
++        RIP5(C, D, E, A, B, WL78, SL78, KL4);
++        RIP5(B, C, D, E, A, WL79, SL79, KL4);
++
++        a = A;
++        b = B;
++        c = C;
++        d = D;
++        e = E;
++        /* Do other half */
++        A = ctx->A;
++        B = ctx->B;
++        C = ctx->C;
++        D = ctx->D;
++        E = ctx->E;
++
++        RIP5(A, B, C, D, E, WR00, SR00, KR0);
++        RIP5(E, A, B, C, D, WR01, SR01, KR0);
++        RIP5(D, E, A, B, C, WR02, SR02, KR0);
++        RIP5(C, D, E, A, B, WR03, SR03, KR0);
++        RIP5(B, C, D, E, A, WR04, SR04, KR0);
++        RIP5(A, B, C, D, E, WR05, SR05, KR0);
++        RIP5(E, A, B, C, D, WR06, SR06, KR0);
++        RIP5(D, E, A, B, C, WR07, SR07, KR0);
++        RIP5(C, D, E, A, B, WR08, SR08, KR0);
++        RIP5(B, C, D, E, A, WR09, SR09, KR0);
++        RIP5(A, B, C, D, E, WR10, SR10, KR0);
++        RIP5(E, A, B, C, D, WR11, SR11, KR0);
++        RIP5(D, E, A, B, C, WR12, SR12, KR0);
++        RIP5(C, D, E, A, B, WR13, SR13, KR0);
++        RIP5(B, C, D, E, A, WR14, SR14, KR0);
++        RIP5(A, B, C, D, E, WR15, SR15, KR0);
++
++        RIP4(E, A, B, C, D, WR16, SR16, KR1);
++        RIP4(D, E, A, B, C, WR17, SR17, KR1);
++        RIP4(C, D, E, A, B, WR18, SR18, KR1);
++        RIP4(B, C, D, E, A, WR19, SR19, KR1);
++        RIP4(A, B, C, D, E, WR20, SR20, KR1);
++        RIP4(E, A, B, C, D, WR21, SR21, KR1);
++        RIP4(D, E, A, B, C, WR22, SR22, KR1);
++        RIP4(C, D, E, A, B, WR23, SR23, KR1);
++        RIP4(B, C, D, E, A, WR24, SR24, KR1);
++        RIP4(A, B, C, D, E, WR25, SR25, KR1);
++        RIP4(E, A, B, C, D, WR26, SR26, KR1);
++        RIP4(D, E, A, B, C, WR27, SR27, KR1);
++        RIP4(C, D, E, A, B, WR28, SR28, KR1);
++        RIP4(B, C, D, E, A, WR29, SR29, KR1);
++        RIP4(A, B, C, D, E, WR30, SR30, KR1);
++        RIP4(E, A, B, C, D, WR31, SR31, KR1);
++
++        RIP3(D, E, A, B, C, WR32, SR32, KR2);
++        RIP3(C, D, E, A, B, WR33, SR33, KR2);
++        RIP3(B, C, D, E, A, WR34, SR34, KR2);
++        RIP3(A, B, C, D, E, WR35, SR35, KR2);
++        RIP3(E, A, B, C, D, WR36, SR36, KR2);
++        RIP3(D, E, A, B, C, WR37, SR37, KR2);
++        RIP3(C, D, E, A, B, WR38, SR38, KR2);
++        RIP3(B, C, D, E, A, WR39, SR39, KR2);
++        RIP3(A, B, C, D, E, WR40, SR40, KR2);
++        RIP3(E, A, B, C, D, WR41, SR41, KR2);
++        RIP3(D, E, A, B, C, WR42, SR42, KR2);
++        RIP3(C, D, E, A, B, WR43, SR43, KR2);
++        RIP3(B, C, D, E, A, WR44, SR44, KR2);
++        RIP3(A, B, C, D, E, WR45, SR45, KR2);
++        RIP3(E, A, B, C, D, WR46, SR46, KR2);
++        RIP3(D, E, A, B, C, WR47, SR47, KR2);
++
++        RIP2(C, D, E, A, B, WR48, SR48, KR3);
++        RIP2(B, C, D, E, A, WR49, SR49, KR3);
++        RIP2(A, B, C, D, E, WR50, SR50, KR3);
++        RIP2(E, A, B, C, D, WR51, SR51, KR3);
++        RIP2(D, E, A, B, C, WR52, SR52, KR3);
++        RIP2(C, D, E, A, B, WR53, SR53, KR3);
++        RIP2(B, C, D, E, A, WR54, SR54, KR3);
++        RIP2(A, B, C, D, E, WR55, SR55, KR3);
++        RIP2(E, A, B, C, D, WR56, SR56, KR3);
++        RIP2(D, E, A, B, C, WR57, SR57, KR3);
++        RIP2(C, D, E, A, B, WR58, SR58, KR3);
++        RIP2(B, C, D, E, A, WR59, SR59, KR3);
++        RIP2(A, B, C, D, E, WR60, SR60, KR3);
++        RIP2(E, A, B, C, D, WR61, SR61, KR3);
++        RIP2(D, E, A, B, C, WR62, SR62, KR3);
++        RIP2(C, D, E, A, B, WR63, SR63, KR3);
++
++        RIP1(B, C, D, E, A, WR64, SR64);
++        RIP1(A, B, C, D, E, WR65, SR65);
++        RIP1(E, A, B, C, D, WR66, SR66);
++        RIP1(D, E, A, B, C, WR67, SR67);
++        RIP1(C, D, E, A, B, WR68, SR68);
++        RIP1(B, C, D, E, A, WR69, SR69);
++        RIP1(A, B, C, D, E, WR70, SR70);
++        RIP1(E, A, B, C, D, WR71, SR71);
++        RIP1(D, E, A, B, C, WR72, SR72);
++        RIP1(C, D, E, A, B, WR73, SR73);
++        RIP1(B, C, D, E, A, WR74, SR74);
++        RIP1(A, B, C, D, E, WR75, SR75);
++        RIP1(E, A, B, C, D, WR76, SR76);
++        RIP1(D, E, A, B, C, WR77, SR77);
++        RIP1(C, D, E, A, B, WR78, SR78);
++        RIP1(B, C, D, E, A, WR79, SR79);
++
++        D = ctx->B + c + D;
++        ctx->B = ctx->C + d + E;
++        ctx->C = ctx->D + e + A;
++        ctx->D = ctx->E + a + B;
++        ctx->E = ctx->A + b + C;
++        ctx->A = D;
++
++    }
++}
++#endif
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/ripemd/rmd_locl.h b/CryptoPkg/Library/OpensslLib/openssl/crypto/ripemd/rmd_locl.h
+new file mode 100644
+index 0000000..9c5ba15
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/ripemd/rmd_locl.h
+@@ -0,0 +1,88 @@
++/*
++ * Copyright 1995-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include 
++#include 
++#include 
++
++/*
++ * DO EXAMINE COMMENTS IN crypto/md5/md5_locl.h & crypto/md5/md5_dgst.c
++ * FOR EXPLANATIONS ON FOLLOWING "CODE."
++ *                                      
++ */
++#ifdef RMD160_ASM
++# if defined(__i386) || defined(__i386__) || defined(_M_IX86)
++#  define ripemd160_block_data_order ripemd160_block_asm_data_order
++# endif
++#endif
++
++void ripemd160_block_data_order(RIPEMD160_CTX *c, const void *p, size_t num);
++
++#define DATA_ORDER_IS_LITTLE_ENDIAN
++
++#define HASH_LONG               RIPEMD160_LONG
++#define HASH_CTX                RIPEMD160_CTX
++#define HASH_CBLOCK             RIPEMD160_CBLOCK
++#define HASH_UPDATE             RIPEMD160_Update
++#define HASH_TRANSFORM          RIPEMD160_Transform
++#define HASH_FINAL              RIPEMD160_Final
++#define HASH_MAKE_STRING(c,s)   do {    \
++        unsigned long ll;               \
++        ll=(c)->A; (void)HOST_l2c(ll,(s));      \
++        ll=(c)->B; (void)HOST_l2c(ll,(s));      \
++        ll=(c)->C; (void)HOST_l2c(ll,(s));      \
++        ll=(c)->D; (void)HOST_l2c(ll,(s));      \
++        ll=(c)->E; (void)HOST_l2c(ll,(s));      \
++        } while (0)
++#define HASH_BLOCK_DATA_ORDER   ripemd160_block_data_order
++
++#include "internal/md32_common.h"
++
++/*
++ * Transformed F2 and F4 are courtesy of Wei Dai 
++ */
++#define F1(x,y,z)       ((x) ^ (y) ^ (z))
++#define F2(x,y,z)       ((((y) ^ (z)) & (x)) ^ (z))
++#define F3(x,y,z)       (((~(y)) | (x)) ^ (z))
++#define F4(x,y,z)       ((((x) ^ (y)) & (z)) ^ (y))
++#define F5(x,y,z)       (((~(z)) | (y)) ^ (x))
++
++#define RIPEMD160_A     0x67452301L
++#define RIPEMD160_B     0xEFCDAB89L
++#define RIPEMD160_C     0x98BADCFEL
++#define RIPEMD160_D     0x10325476L
++#define RIPEMD160_E     0xC3D2E1F0L
++
++#include "rmdconst.h"
++
++#define RIP1(a,b,c,d,e,w,s) { \
++        a+=F1(b,c,d)+X(w); \
++        a=ROTATE(a,s)+e; \
++        c=ROTATE(c,10); }
++
++#define RIP2(a,b,c,d,e,w,s,K) { \
++        a+=F2(b,c,d)+X(w)+K; \
++        a=ROTATE(a,s)+e; \
++        c=ROTATE(c,10); }
++
++#define RIP3(a,b,c,d,e,w,s,K) { \
++        a+=F3(b,c,d)+X(w)+K; \
++        a=ROTATE(a,s)+e; \
++        c=ROTATE(c,10); }
++
++#define RIP4(a,b,c,d,e,w,s,K) { \
++        a+=F4(b,c,d)+X(w)+K; \
++        a=ROTATE(a,s)+e; \
++        c=ROTATE(c,10); }
++
++#define RIP5(a,b,c,d,e,w,s,K) { \
++        a+=F5(b,c,d)+X(w)+K; \
++        a=ROTATE(a,s)+e; \
++        c=ROTATE(c,10); }
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/ripemd/rmd_one.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/ripemd/rmd_one.c
+new file mode 100644
+index 0000000..c3193bd
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/ripemd/rmd_one.c
+@@ -0,0 +1,28 @@
++/*
++ * Copyright 1995-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include 
++#include 
++#include 
++
++unsigned char *RIPEMD160(const unsigned char *d, size_t n, unsigned char *md)
++{
++    RIPEMD160_CTX c;
++    static unsigned char m[RIPEMD160_DIGEST_LENGTH];
++
++    if (md == NULL)
++        md = m;
++    if (!RIPEMD160_Init(&c))
++        return NULL;
++    RIPEMD160_Update(&c, d, n);
++    RIPEMD160_Final(md, &c);
++    OPENSSL_cleanse(&c, sizeof(c)); /* security consideration */
++    return (md);
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/ripemd/rmdconst.h b/CryptoPkg/Library/OpensslLib/openssl/crypto/ripemd/rmdconst.h
+new file mode 100644
+index 0000000..b810132
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/ripemd/rmdconst.h
+@@ -0,0 +1,350 @@
++/*
++ * Copyright 1995-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#define KL0 0x00000000L
++#define KL1 0x5A827999L
++#define KL2 0x6ED9EBA1L
++#define KL3 0x8F1BBCDCL
++#define KL4 0xA953FD4EL
++
++#define KR0 0x50A28BE6L
++#define KR1 0x5C4DD124L
++#define KR2 0x6D703EF3L
++#define KR3 0x7A6D76E9L
++#define KR4 0x00000000L
++
++#define WL00  0
++#define SL00 11
++#define WL01  1
++#define SL01 14
++#define WL02  2
++#define SL02 15
++#define WL03  3
++#define SL03 12
++#define WL04  4
++#define SL04  5
++#define WL05  5
++#define SL05  8
++#define WL06  6
++#define SL06  7
++#define WL07  7
++#define SL07  9
++#define WL08  8
++#define SL08 11
++#define WL09  9
++#define SL09 13
++#define WL10 10
++#define SL10 14
++#define WL11 11
++#define SL11 15
++#define WL12 12
++#define SL12  6
++#define WL13 13
++#define SL13  7
++#define WL14 14
++#define SL14  9
++#define WL15 15
++#define SL15  8
++
++#define WL16  7
++#define SL16  7
++#define WL17  4
++#define SL17  6
++#define WL18 13
++#define SL18  8
++#define WL19  1
++#define SL19 13
++#define WL20 10
++#define SL20 11
++#define WL21  6
++#define SL21  9
++#define WL22 15
++#define SL22  7
++#define WL23  3
++#define SL23 15
++#define WL24 12
++#define SL24  7
++#define WL25  0
++#define SL25 12
++#define WL26  9
++#define SL26 15
++#define WL27  5
++#define SL27  9
++#define WL28  2
++#define SL28 11
++#define WL29 14
++#define SL29  7
++#define WL30 11
++#define SL30 13
++#define WL31  8
++#define SL31 12
++
++#define WL32  3
++#define SL32 11
++#define WL33 10
++#define SL33 13
++#define WL34 14
++#define SL34  6
++#define WL35  4
++#define SL35  7
++#define WL36  9
++#define SL36 14
++#define WL37 15
++#define SL37  9
++#define WL38  8
++#define SL38 13
++#define WL39  1
++#define SL39 15
++#define WL40  2
++#define SL40 14
++#define WL41  7
++#define SL41  8
++#define WL42  0
++#define SL42 13
++#define WL43  6
++#define SL43  6
++#define WL44 13
++#define SL44  5
++#define WL45 11
++#define SL45 12
++#define WL46  5
++#define SL46  7
++#define WL47 12
++#define SL47  5
++
++#define WL48  1
++#define SL48 11
++#define WL49  9
++#define SL49 12
++#define WL50 11
++#define SL50 14
++#define WL51 10
++#define SL51 15
++#define WL52  0
++#define SL52 14
++#define WL53  8
++#define SL53 15
++#define WL54 12
++#define SL54  9
++#define WL55  4
++#define SL55  8
++#define WL56 13
++#define SL56  9
++#define WL57  3
++#define SL57 14
++#define WL58  7
++#define SL58  5
++#define WL59 15
++#define SL59  6
++#define WL60 14
++#define SL60  8
++#define WL61  5
++#define SL61  6
++#define WL62  6
++#define SL62  5
++#define WL63  2
++#define SL63 12
++
++#define WL64  4
++#define SL64  9
++#define WL65  0
++#define SL65 15
++#define WL66  5
++#define SL66  5
++#define WL67  9
++#define SL67 11
++#define WL68  7
++#define SL68  6
++#define WL69 12
++#define SL69  8
++#define WL70  2
++#define SL70 13
++#define WL71 10
++#define SL71 12
++#define WL72 14
++#define SL72  5
++#define WL73  1
++#define SL73 12
++#define WL74  3
++#define SL74 13
++#define WL75  8
++#define SL75 14
++#define WL76 11
++#define SL76 11
++#define WL77  6
++#define SL77  8
++#define WL78 15
++#define SL78  5
++#define WL79 13
++#define SL79  6
++
++#define WR00  5
++#define SR00  8
++#define WR01 14
++#define SR01  9
++#define WR02  7
++#define SR02  9
++#define WR03  0
++#define SR03 11
++#define WR04  9
++#define SR04 13
++#define WR05  2
++#define SR05 15
++#define WR06 11
++#define SR06 15
++#define WR07  4
++#define SR07  5
++#define WR08 13
++#define SR08  7
++#define WR09  6
++#define SR09  7
++#define WR10 15
++#define SR10  8
++#define WR11  8
++#define SR11 11
++#define WR12  1
++#define SR12 14
++#define WR13 10
++#define SR13 14
++#define WR14  3
++#define SR14 12
++#define WR15 12
++#define SR15  6
++
++#define WR16  6
++#define SR16  9
++#define WR17 11
++#define SR17 13
++#define WR18  3
++#define SR18 15
++#define WR19  7
++#define SR19  7
++#define WR20  0
++#define SR20 12
++#define WR21 13
++#define SR21  8
++#define WR22  5
++#define SR22  9
++#define WR23 10
++#define SR23 11
++#define WR24 14
++#define SR24  7
++#define WR25 15
++#define SR25  7
++#define WR26  8
++#define SR26 12
++#define WR27 12
++#define SR27  7
++#define WR28  4
++#define SR28  6
++#define WR29  9
++#define SR29 15
++#define WR30  1
++#define SR30 13
++#define WR31  2
++#define SR31 11
++
++#define WR32 15
++#define SR32  9
++#define WR33  5
++#define SR33  7
++#define WR34  1
++#define SR34 15
++#define WR35  3
++#define SR35 11
++#define WR36  7
++#define SR36  8
++#define WR37 14
++#define SR37  6
++#define WR38  6
++#define SR38  6
++#define WR39  9
++#define SR39 14
++#define WR40 11
++#define SR40 12
++#define WR41  8
++#define SR41 13
++#define WR42 12
++#define SR42  5
++#define WR43  2
++#define SR43 14
++#define WR44 10
++#define SR44 13
++#define WR45  0
++#define SR45 13
++#define WR46  4
++#define SR46  7
++#define WR47 13
++#define SR47  5
++
++#define WR48  8
++#define SR48 15
++#define WR49  6
++#define SR49  5
++#define WR50  4
++#define SR50  8
++#define WR51  1
++#define SR51 11
++#define WR52  3
++#define SR52 14
++#define WR53 11
++#define SR53 14
++#define WR54 15
++#define SR54  6
++#define WR55  0
++#define SR55 14
++#define WR56  5
++#define SR56  6
++#define WR57 12
++#define SR57  9
++#define WR58  2
++#define SR58 12
++#define WR59 13
++#define SR59  9
++#define WR60  9
++#define SR60 12
++#define WR61  7
++#define SR61  5
++#define WR62 10
++#define SR62 15
++#define WR63 14
++#define SR63  8
++
++#define WR64 12
++#define SR64  8
++#define WR65 15
++#define SR65  5
++#define WR66 10
++#define SR66 12
++#define WR67  4
++#define SR67  9
++#define WR68  1
++#define SR68 12
++#define WR69  5
++#define SR69  5
++#define WR70  8
++#define SR70 14
++#define WR71  7
++#define SR71  6
++#define WR72  6
++#define SR72  8
++#define WR73  2
++#define SR73 13
++#define WR74 13
++#define SR74  6
++#define WR75 14
++#define SR75  5
++#define WR76  0
++#define SR76 15
++#define WR77  3
++#define SR77 13
++#define WR78  9
++#define SR78 11
++#define WR79 11
++#define SR79 11
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/rsa/build.info b/CryptoPkg/Library/OpensslLib/openssl/crypto/rsa/build.info
+new file mode 100644
+index 0000000..39b7464
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/rsa/build.info
+@@ -0,0 +1,6 @@
++LIBS=../../libcrypto
++SOURCE[../../libcrypto]=\
++        rsa_ossl.c rsa_gen.c rsa_lib.c rsa_sign.c rsa_saos.c rsa_err.c \
++        rsa_pk1.c rsa_ssl.c rsa_none.c rsa_oaep.c rsa_chk.c rsa_null.c \
++        rsa_pss.c rsa_x931.c rsa_asn1.c rsa_depr.c rsa_ameth.c rsa_prn.c \
++        rsa_pmeth.c rsa_crpt.c rsa_x931g.c rsa_meth.c
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/rsa/rsa_ameth.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/rsa/rsa_ameth.c
+new file mode 100644
+index 0000000..5694140
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/rsa/rsa_ameth.c
+@@ -0,0 +1,866 @@
++/*
++ * Copyright 2006-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include "internal/cryptlib.h"
++#include 
++#include 
++#include 
++#include 
++#include "internal/asn1_int.h"
++#include "internal/evp_int.h"
++#include "rsa_locl.h"
++
++#ifndef OPENSSL_NO_CMS
++static int rsa_cms_sign(CMS_SignerInfo *si);
++static int rsa_cms_verify(CMS_SignerInfo *si);
++static int rsa_cms_decrypt(CMS_RecipientInfo *ri);
++static int rsa_cms_encrypt(CMS_RecipientInfo *ri);
++#endif
++
++static int rsa_pub_encode(X509_PUBKEY *pk, const EVP_PKEY *pkey)
++{
++    unsigned char *penc = NULL;
++    int penclen;
++    penclen = i2d_RSAPublicKey(pkey->pkey.rsa, &penc);
++    if (penclen <= 0)
++        return 0;
++    if (X509_PUBKEY_set0_param(pk, OBJ_nid2obj(EVP_PKEY_RSA),
++                               V_ASN1_NULL, NULL, penc, penclen))
++        return 1;
++
++    OPENSSL_free(penc);
++    return 0;
++}
++
++static int rsa_pub_decode(EVP_PKEY *pkey, X509_PUBKEY *pubkey)
++{
++    const unsigned char *p;
++    int pklen;
++    RSA *rsa = NULL;
++
++    if (!X509_PUBKEY_get0_param(NULL, &p, &pklen, NULL, pubkey))
++        return 0;
++    if ((rsa = d2i_RSAPublicKey(NULL, &p, pklen)) == NULL) {
++        RSAerr(RSA_F_RSA_PUB_DECODE, ERR_R_RSA_LIB);
++        return 0;
++    }
++    EVP_PKEY_assign_RSA(pkey, rsa);
++    return 1;
++}
++
++static int rsa_pub_cmp(const EVP_PKEY *a, const EVP_PKEY *b)
++{
++    if (BN_cmp(b->pkey.rsa->n, a->pkey.rsa->n) != 0
++        || BN_cmp(b->pkey.rsa->e, a->pkey.rsa->e) != 0)
++        return 0;
++    return 1;
++}
++
++static int old_rsa_priv_decode(EVP_PKEY *pkey,
++                               const unsigned char **pder, int derlen)
++{
++    RSA *rsa;
++
++    if ((rsa = d2i_RSAPrivateKey(NULL, pder, derlen)) == NULL) {
++        RSAerr(RSA_F_OLD_RSA_PRIV_DECODE, ERR_R_RSA_LIB);
++        return 0;
++    }
++    EVP_PKEY_assign_RSA(pkey, rsa);
++    return 1;
++}
++
++static int old_rsa_priv_encode(const EVP_PKEY *pkey, unsigned char **pder)
++{
++    return i2d_RSAPrivateKey(pkey->pkey.rsa, pder);
++}
++
++static int rsa_priv_encode(PKCS8_PRIV_KEY_INFO *p8, const EVP_PKEY *pkey)
++{
++    unsigned char *rk = NULL;
++    int rklen;
++    rklen = i2d_RSAPrivateKey(pkey->pkey.rsa, &rk);
++
++    if (rklen <= 0) {
++        RSAerr(RSA_F_RSA_PRIV_ENCODE, ERR_R_MALLOC_FAILURE);
++        return 0;
++    }
++
++    if (!PKCS8_pkey_set0(p8, OBJ_nid2obj(NID_rsaEncryption), 0,
++                         V_ASN1_NULL, NULL, rk, rklen)) {
++        RSAerr(RSA_F_RSA_PRIV_ENCODE, ERR_R_MALLOC_FAILURE);
++        return 0;
++    }
++
++    return 1;
++}
++
++static int rsa_priv_decode(EVP_PKEY *pkey, const PKCS8_PRIV_KEY_INFO *p8)
++{
++    const unsigned char *p;
++    int pklen;
++    if (!PKCS8_pkey_get0(NULL, &p, &pklen, NULL, p8))
++        return 0;
++    return old_rsa_priv_decode(pkey, &p, pklen);
++}
++
++static int int_rsa_size(const EVP_PKEY *pkey)
++{
++    return RSA_size(pkey->pkey.rsa);
++}
++
++static int rsa_bits(const EVP_PKEY *pkey)
++{
++    return BN_num_bits(pkey->pkey.rsa->n);
++}
++
++static int rsa_security_bits(const EVP_PKEY *pkey)
++{
++    return RSA_security_bits(pkey->pkey.rsa);
++}
++
++static void int_rsa_free(EVP_PKEY *pkey)
++{
++    RSA_free(pkey->pkey.rsa);
++}
++
++static int do_rsa_print(BIO *bp, const RSA *x, int off, int priv)
++{
++    char *str;
++    const char *s;
++    int ret = 0, mod_len = 0;
++
++    if (x->n != NULL)
++        mod_len = BN_num_bits(x->n);
++
++    if (!BIO_indent(bp, off, 128))
++        goto err;
++
++    if (priv && x->d) {
++        if (BIO_printf(bp, "Private-Key: (%d bit)\n", mod_len) <= 0)
++            goto err;
++        str = "modulus:";
++        s = "publicExponent:";
++    } else {
++        if (BIO_printf(bp, "Public-Key: (%d bit)\n", mod_len) <= 0)
++            goto err;
++        str = "Modulus:";
++        s = "Exponent:";
++    }
++    if (!ASN1_bn_print(bp, str, x->n, NULL, off))
++        goto err;
++    if (!ASN1_bn_print(bp, s, x->e, NULL, off))
++        goto err;
++    if (priv) {
++        if (!ASN1_bn_print(bp, "privateExponent:", x->d, NULL, off))
++            goto err;
++        if (!ASN1_bn_print(bp, "prime1:", x->p, NULL, off))
++            goto err;
++        if (!ASN1_bn_print(bp, "prime2:", x->q, NULL, off))
++            goto err;
++        if (!ASN1_bn_print(bp, "exponent1:", x->dmp1, NULL, off))
++            goto err;
++        if (!ASN1_bn_print(bp, "exponent2:", x->dmq1, NULL, off))
++            goto err;
++        if (!ASN1_bn_print(bp, "coefficient:", x->iqmp, NULL, off))
++            goto err;
++    }
++    ret = 1;
++ err:
++    return (ret);
++}
++
++static int rsa_pub_print(BIO *bp, const EVP_PKEY *pkey, int indent,
++                         ASN1_PCTX *ctx)
++{
++    return do_rsa_print(bp, pkey->pkey.rsa, indent, 0);
++}
++
++static int rsa_priv_print(BIO *bp, const EVP_PKEY *pkey, int indent,
++                          ASN1_PCTX *ctx)
++{
++    return do_rsa_print(bp, pkey->pkey.rsa, indent, 1);
++}
++
++/* Given an MGF1 Algorithm ID decode to an Algorithm Identifier */
++static X509_ALGOR *rsa_mgf1_decode(X509_ALGOR *alg)
++{
++    if (alg == NULL)
++        return NULL;
++    if (OBJ_obj2nid(alg->algorithm) != NID_mgf1)
++        return NULL;
++    return ASN1_TYPE_unpack_sequence(ASN1_ITEM_rptr(X509_ALGOR),
++                                     alg->parameter);
++}
++
++static RSA_PSS_PARAMS *rsa_pss_decode(const X509_ALGOR *alg,
++                                      X509_ALGOR **pmaskHash)
++{
++    RSA_PSS_PARAMS *pss;
++
++    *pmaskHash = NULL;
++
++    pss = ASN1_TYPE_unpack_sequence(ASN1_ITEM_rptr(RSA_PSS_PARAMS),
++                                    alg->parameter);
++
++    if (!pss)
++        return NULL;
++
++    *pmaskHash = rsa_mgf1_decode(pss->maskGenAlgorithm);
++
++    return pss;
++}
++
++static int rsa_pss_param_print(BIO *bp, RSA_PSS_PARAMS *pss,
++                               X509_ALGOR *maskHash, int indent)
++{
++    int rv = 0;
++    if (!pss) {
++        if (BIO_puts(bp, " (INVALID PSS PARAMETERS)\n") <= 0)
++            return 0;
++        return 1;
++    }
++    if (BIO_puts(bp, "\n") <= 0)
++        goto err;
++    if (!BIO_indent(bp, indent, 128))
++        goto err;
++    if (BIO_puts(bp, "Hash Algorithm: ") <= 0)
++        goto err;
++
++    if (pss->hashAlgorithm) {
++        if (i2a_ASN1_OBJECT(bp, pss->hashAlgorithm->algorithm) <= 0)
++            goto err;
++    } else if (BIO_puts(bp, "sha1 (default)") <= 0)
++        goto err;
++
++    if (BIO_puts(bp, "\n") <= 0)
++        goto err;
++
++    if (!BIO_indent(bp, indent, 128))
++        goto err;
++
++    if (BIO_puts(bp, "Mask Algorithm: ") <= 0)
++        goto err;
++    if (pss->maskGenAlgorithm) {
++        if (i2a_ASN1_OBJECT(bp, pss->maskGenAlgorithm->algorithm) <= 0)
++            goto err;
++        if (BIO_puts(bp, " with ") <= 0)
++            goto err;
++        if (maskHash) {
++            if (i2a_ASN1_OBJECT(bp, maskHash->algorithm) <= 0)
++                goto err;
++        } else if (BIO_puts(bp, "INVALID") <= 0)
++            goto err;
++    } else if (BIO_puts(bp, "mgf1 with sha1 (default)") <= 0)
++        goto err;
++    BIO_puts(bp, "\n");
++
++    if (!BIO_indent(bp, indent, 128))
++        goto err;
++    if (BIO_puts(bp, "Salt Length: 0x") <= 0)
++        goto err;
++    if (pss->saltLength) {
++        if (i2a_ASN1_INTEGER(bp, pss->saltLength) <= 0)
++            goto err;
++    } else if (BIO_puts(bp, "14 (default)") <= 0)
++        goto err;
++    BIO_puts(bp, "\n");
++
++    if (!BIO_indent(bp, indent, 128))
++        goto err;
++    if (BIO_puts(bp, "Trailer Field: 0x") <= 0)
++        goto err;
++    if (pss->trailerField) {
++        if (i2a_ASN1_INTEGER(bp, pss->trailerField) <= 0)
++            goto err;
++    } else if (BIO_puts(bp, "BC (default)") <= 0)
++        goto err;
++    BIO_puts(bp, "\n");
++
++    rv = 1;
++
++ err:
++    return rv;
++
++}
++
++static int rsa_sig_print(BIO *bp, const X509_ALGOR *sigalg,
++                         const ASN1_STRING *sig, int indent, ASN1_PCTX *pctx)
++{
++    if (OBJ_obj2nid(sigalg->algorithm) == NID_rsassaPss) {
++        int rv;
++        RSA_PSS_PARAMS *pss;
++        X509_ALGOR *maskHash;
++        pss = rsa_pss_decode(sigalg, &maskHash);
++        rv = rsa_pss_param_print(bp, pss, maskHash, indent);
++        RSA_PSS_PARAMS_free(pss);
++        X509_ALGOR_free(maskHash);
++        if (!rv)
++            return 0;
++    } else if (!sig && BIO_puts(bp, "\n") <= 0)
++        return 0;
++    if (sig)
++        return X509_signature_dump(bp, sig, indent);
++    return 1;
++}
++
++static int rsa_pkey_ctrl(EVP_PKEY *pkey, int op, long arg1, void *arg2)
++{
++    X509_ALGOR *alg = NULL;
++    switch (op) {
++
++    case ASN1_PKEY_CTRL_PKCS7_SIGN:
++        if (arg1 == 0)
++            PKCS7_SIGNER_INFO_get0_algs(arg2, NULL, NULL, &alg);
++        break;
++
++    case ASN1_PKEY_CTRL_PKCS7_ENCRYPT:
++        if (arg1 == 0)
++            PKCS7_RECIP_INFO_get0_alg(arg2, &alg);
++        break;
++#ifndef OPENSSL_NO_CMS
++    case ASN1_PKEY_CTRL_CMS_SIGN:
++        if (arg1 == 0)
++            return rsa_cms_sign(arg2);
++        else if (arg1 == 1)
++            return rsa_cms_verify(arg2);
++        break;
++
++    case ASN1_PKEY_CTRL_CMS_ENVELOPE:
++        if (arg1 == 0)
++            return rsa_cms_encrypt(arg2);
++        else if (arg1 == 1)
++            return rsa_cms_decrypt(arg2);
++        break;
++
++    case ASN1_PKEY_CTRL_CMS_RI_TYPE:
++        *(int *)arg2 = CMS_RECIPINFO_TRANS;
++        return 1;
++#endif
++
++    case ASN1_PKEY_CTRL_DEFAULT_MD_NID:
++        *(int *)arg2 = NID_sha256;
++        return 1;
++
++    default:
++        return -2;
++
++    }
++
++    if (alg)
++        X509_ALGOR_set0(alg, OBJ_nid2obj(NID_rsaEncryption), V_ASN1_NULL, 0);
++
++    return 1;
++
++}
++
++/* allocate and set algorithm ID from EVP_MD, default SHA1 */
++static int rsa_md_to_algor(X509_ALGOR **palg, const EVP_MD *md)
++{
++    if (EVP_MD_type(md) == NID_sha1)
++        return 1;
++    *palg = X509_ALGOR_new();
++    if (*palg == NULL)
++        return 0;
++    X509_ALGOR_set_md(*palg, md);
++    return 1;
++}
++
++/* Allocate and set MGF1 algorithm ID from EVP_MD */
++static int rsa_md_to_mgf1(X509_ALGOR **palg, const EVP_MD *mgf1md)
++{
++    X509_ALGOR *algtmp = NULL;
++    ASN1_STRING *stmp = NULL;
++    *palg = NULL;
++    if (EVP_MD_type(mgf1md) == NID_sha1)
++        return 1;
++    /* need to embed algorithm ID inside another */
++    if (!rsa_md_to_algor(&algtmp, mgf1md))
++        goto err;
++    if (!ASN1_item_pack(algtmp, ASN1_ITEM_rptr(X509_ALGOR), &stmp))
++         goto err;
++    *palg = X509_ALGOR_new();
++    if (*palg == NULL)
++        goto err;
++    X509_ALGOR_set0(*palg, OBJ_nid2obj(NID_mgf1), V_ASN1_SEQUENCE, stmp);
++    stmp = NULL;
++ err:
++    ASN1_STRING_free(stmp);
++    X509_ALGOR_free(algtmp);
++    if (*palg)
++        return 1;
++    return 0;
++}
++
++/* convert algorithm ID to EVP_MD, default SHA1 */
++static const EVP_MD *rsa_algor_to_md(X509_ALGOR *alg)
++{
++    const EVP_MD *md;
++    if (!alg)
++        return EVP_sha1();
++    md = EVP_get_digestbyobj(alg->algorithm);
++    if (md == NULL)
++        RSAerr(RSA_F_RSA_ALGOR_TO_MD, RSA_R_UNKNOWN_DIGEST);
++    return md;
++}
++
++/* convert MGF1 algorithm ID to EVP_MD, default SHA1 */
++static const EVP_MD *rsa_mgf1_to_md(X509_ALGOR *alg, X509_ALGOR *maskHash)
++{
++    const EVP_MD *md;
++    if (!alg)
++        return EVP_sha1();
++    /* Check mask and lookup mask hash algorithm */
++    if (OBJ_obj2nid(alg->algorithm) != NID_mgf1) {
++        RSAerr(RSA_F_RSA_MGF1_TO_MD, RSA_R_UNSUPPORTED_MASK_ALGORITHM);
++        return NULL;
++    }
++    if (!maskHash) {
++        RSAerr(RSA_F_RSA_MGF1_TO_MD, RSA_R_UNSUPPORTED_MASK_PARAMETER);
++        return NULL;
++    }
++    md = EVP_get_digestbyobj(maskHash->algorithm);
++    if (md == NULL) {
++        RSAerr(RSA_F_RSA_MGF1_TO_MD, RSA_R_UNKNOWN_MASK_DIGEST);
++        return NULL;
++    }
++    return md;
++}
++
++/*
++ * Convert EVP_PKEY_CTX is PSS mode into corresponding algorithm parameter,
++ * suitable for setting an AlgorithmIdentifier.
++ */
++
++static ASN1_STRING *rsa_ctx_to_pss(EVP_PKEY_CTX *pkctx)
++{
++    const EVP_MD *sigmd, *mgf1md;
++    RSA_PSS_PARAMS *pss = NULL;
++    ASN1_STRING *os = NULL;
++    EVP_PKEY *pk = EVP_PKEY_CTX_get0_pkey(pkctx);
++    int saltlen, rv = 0;
++    if (EVP_PKEY_CTX_get_signature_md(pkctx, &sigmd) <= 0)
++        goto err;
++    if (EVP_PKEY_CTX_get_rsa_mgf1_md(pkctx, &mgf1md) <= 0)
++        goto err;
++    if (!EVP_PKEY_CTX_get_rsa_pss_saltlen(pkctx, &saltlen))
++        goto err;
++    if (saltlen == -1)
++        saltlen = EVP_MD_size(sigmd);
++    else if (saltlen == -2) {
++        saltlen = EVP_PKEY_size(pk) - EVP_MD_size(sigmd) - 2;
++        if (((EVP_PKEY_bits(pk) - 1) & 0x7) == 0)
++            saltlen--;
++    }
++    pss = RSA_PSS_PARAMS_new();
++    if (pss == NULL)
++        goto err;
++    if (saltlen != 20) {
++        pss->saltLength = ASN1_INTEGER_new();
++        if (pss->saltLength == NULL)
++            goto err;
++        if (!ASN1_INTEGER_set(pss->saltLength, saltlen))
++            goto err;
++    }
++    if (!rsa_md_to_algor(&pss->hashAlgorithm, sigmd))
++        goto err;
++    if (!rsa_md_to_mgf1(&pss->maskGenAlgorithm, mgf1md))
++        goto err;
++    /* Finally create string with pss parameter encoding. */
++    if (!ASN1_item_pack(pss, ASN1_ITEM_rptr(RSA_PSS_PARAMS), &os))
++         goto err;
++    rv = 1;
++ err:
++    RSA_PSS_PARAMS_free(pss);
++    if (rv)
++        return os;
++    ASN1_STRING_free(os);
++    return NULL;
++}
++
++/*
++ * From PSS AlgorithmIdentifier set public key parameters. If pkey isn't NULL
++ * then the EVP_MD_CTX is setup and initialised. If it is NULL parameters are
++ * passed to pkctx instead.
++ */
++
++static int rsa_pss_to_ctx(EVP_MD_CTX *ctx, EVP_PKEY_CTX *pkctx,
++                          X509_ALGOR *sigalg, EVP_PKEY *pkey)
++{
++    int rv = -1;
++    int saltlen;
++    const EVP_MD *mgf1md = NULL, *md = NULL;
++    RSA_PSS_PARAMS *pss;
++    X509_ALGOR *maskHash;
++    /* Sanity check: make sure it is PSS */
++    if (OBJ_obj2nid(sigalg->algorithm) != NID_rsassaPss) {
++        RSAerr(RSA_F_RSA_PSS_TO_CTX, RSA_R_UNSUPPORTED_SIGNATURE_TYPE);
++        return -1;
++    }
++    /* Decode PSS parameters */
++    pss = rsa_pss_decode(sigalg, &maskHash);
++
++    if (pss == NULL) {
++        RSAerr(RSA_F_RSA_PSS_TO_CTX, RSA_R_INVALID_PSS_PARAMETERS);
++        goto err;
++    }
++    mgf1md = rsa_mgf1_to_md(pss->maskGenAlgorithm, maskHash);
++    if (!mgf1md)
++        goto err;
++    md = rsa_algor_to_md(pss->hashAlgorithm);
++    if (!md)
++        goto err;
++
++    if (pss->saltLength) {
++        saltlen = ASN1_INTEGER_get(pss->saltLength);
++
++        /*
++         * Could perform more salt length sanity checks but the main RSA
++         * routines will trap other invalid values anyway.
++         */
++        if (saltlen < 0) {
++            RSAerr(RSA_F_RSA_PSS_TO_CTX, RSA_R_INVALID_SALT_LENGTH);
++            goto err;
++        }
++    } else
++        saltlen = 20;
++
++    /*
++     * low-level routines support only trailer field 0xbc (value 1) and
++     * PKCS#1 says we should reject any other value anyway.
++     */
++    if (pss->trailerField && ASN1_INTEGER_get(pss->trailerField) != 1) {
++        RSAerr(RSA_F_RSA_PSS_TO_CTX, RSA_R_INVALID_TRAILER);
++        goto err;
++    }
++
++    /* We have all parameters now set up context */
++
++    if (pkey) {
++        if (!EVP_DigestVerifyInit(ctx, &pkctx, md, NULL, pkey))
++            goto err;
++    } else {
++        const EVP_MD *checkmd;
++        if (EVP_PKEY_CTX_get_signature_md(pkctx, &checkmd) <= 0)
++            goto err;
++        if (EVP_MD_type(md) != EVP_MD_type(checkmd)) {
++            RSAerr(RSA_F_RSA_PSS_TO_CTX, RSA_R_DIGEST_DOES_NOT_MATCH);
++            goto err;
++        }
++    }
++
++    if (EVP_PKEY_CTX_set_rsa_padding(pkctx, RSA_PKCS1_PSS_PADDING) <= 0)
++        goto err;
++
++    if (EVP_PKEY_CTX_set_rsa_pss_saltlen(pkctx, saltlen) <= 0)
++        goto err;
++
++    if (EVP_PKEY_CTX_set_rsa_mgf1_md(pkctx, mgf1md) <= 0)
++        goto err;
++    /* Carry on */
++    rv = 1;
++
++ err:
++    RSA_PSS_PARAMS_free(pss);
++    X509_ALGOR_free(maskHash);
++    return rv;
++}
++
++#ifndef OPENSSL_NO_CMS
++static int rsa_cms_verify(CMS_SignerInfo *si)
++{
++    int nid, nid2;
++    X509_ALGOR *alg;
++    EVP_PKEY_CTX *pkctx = CMS_SignerInfo_get0_pkey_ctx(si);
++    CMS_SignerInfo_get0_algs(si, NULL, NULL, NULL, &alg);
++    nid = OBJ_obj2nid(alg->algorithm);
++    if (nid == NID_rsaEncryption)
++        return 1;
++    if (nid == NID_rsassaPss)
++        return rsa_pss_to_ctx(NULL, pkctx, alg, NULL);
++    /* Workaround for some implementation that use a signature OID */
++    if (OBJ_find_sigid_algs(nid, NULL, &nid2)) {
++        if (nid2 == NID_rsaEncryption)
++            return 1;
++    }
++    return 0;
++}
++#endif
++
++/*
++ * Customised RSA item verification routine. This is called when a signature
++ * is encountered requiring special handling. We currently only handle PSS.
++ */
++
++static int rsa_item_verify(EVP_MD_CTX *ctx, const ASN1_ITEM *it, void *asn,
++                           X509_ALGOR *sigalg, ASN1_BIT_STRING *sig,
++                           EVP_PKEY *pkey)
++{
++    /* Sanity check: make sure it is PSS */
++    if (OBJ_obj2nid(sigalg->algorithm) != NID_rsassaPss) {
++        RSAerr(RSA_F_RSA_ITEM_VERIFY, RSA_R_UNSUPPORTED_SIGNATURE_TYPE);
++        return -1;
++    }
++    if (rsa_pss_to_ctx(ctx, NULL, sigalg, pkey) > 0) {
++        /* Carry on */
++        return 2;
++    }
++    return -1;
++}
++
++#ifndef OPENSSL_NO_CMS
++static int rsa_cms_sign(CMS_SignerInfo *si)
++{
++    int pad_mode = RSA_PKCS1_PADDING;
++    X509_ALGOR *alg;
++    EVP_PKEY_CTX *pkctx = CMS_SignerInfo_get0_pkey_ctx(si);
++    ASN1_STRING *os = NULL;
++    CMS_SignerInfo_get0_algs(si, NULL, NULL, NULL, &alg);
++    if (pkctx) {
++        if (EVP_PKEY_CTX_get_rsa_padding(pkctx, &pad_mode) <= 0)
++            return 0;
++    }
++    if (pad_mode == RSA_PKCS1_PADDING) {
++        X509_ALGOR_set0(alg, OBJ_nid2obj(NID_rsaEncryption), V_ASN1_NULL, 0);
++        return 1;
++    }
++    /* We don't support it */
++    if (pad_mode != RSA_PKCS1_PSS_PADDING)
++        return 0;
++    os = rsa_ctx_to_pss(pkctx);
++    if (!os)
++        return 0;
++    X509_ALGOR_set0(alg, OBJ_nid2obj(NID_rsassaPss), V_ASN1_SEQUENCE, os);
++    return 1;
++}
++#endif
++
++static int rsa_item_sign(EVP_MD_CTX *ctx, const ASN1_ITEM *it, void *asn,
++                         X509_ALGOR *alg1, X509_ALGOR *alg2,
++                         ASN1_BIT_STRING *sig)
++{
++    int pad_mode;
++    EVP_PKEY_CTX *pkctx = EVP_MD_CTX_pkey_ctx(ctx);
++    if (EVP_PKEY_CTX_get_rsa_padding(pkctx, &pad_mode) <= 0)
++        return 0;
++    if (pad_mode == RSA_PKCS1_PADDING)
++        return 2;
++    if (pad_mode == RSA_PKCS1_PSS_PADDING) {
++        ASN1_STRING *os1 = NULL;
++        os1 = rsa_ctx_to_pss(pkctx);
++        if (!os1)
++            return 0;
++        /* Duplicate parameters if we have to */
++        if (alg2) {
++            ASN1_STRING *os2 = ASN1_STRING_dup(os1);
++            if (!os2) {
++                ASN1_STRING_free(os1);
++                return 0;
++            }
++            X509_ALGOR_set0(alg2, OBJ_nid2obj(NID_rsassaPss),
++                            V_ASN1_SEQUENCE, os2);
++        }
++        X509_ALGOR_set0(alg1, OBJ_nid2obj(NID_rsassaPss),
++                        V_ASN1_SEQUENCE, os1);
++        return 3;
++    }
++    return 2;
++}
++
++#ifndef OPENSSL_NO_CMS
++static RSA_OAEP_PARAMS *rsa_oaep_decode(const X509_ALGOR *alg,
++                                        X509_ALGOR **pmaskHash)
++{
++    RSA_OAEP_PARAMS *pss;
++
++    *pmaskHash = NULL;
++
++    pss = ASN1_TYPE_unpack_sequence(ASN1_ITEM_rptr(RSA_OAEP_PARAMS),
++                                    alg->parameter);
++
++    if (!pss)
++        return NULL;
++
++    *pmaskHash = rsa_mgf1_decode(pss->maskGenFunc);
++
++    return pss;
++}
++
++static int rsa_cms_decrypt(CMS_RecipientInfo *ri)
++{
++    EVP_PKEY_CTX *pkctx;
++    X509_ALGOR *cmsalg;
++    int nid;
++    int rv = -1;
++    unsigned char *label = NULL;
++    int labellen = 0;
++    const EVP_MD *mgf1md = NULL, *md = NULL;
++    RSA_OAEP_PARAMS *oaep;
++    X509_ALGOR *maskHash;
++    pkctx = CMS_RecipientInfo_get0_pkey_ctx(ri);
++    if (!pkctx)
++        return 0;
++    if (!CMS_RecipientInfo_ktri_get0_algs(ri, NULL, NULL, &cmsalg))
++        return -1;
++    nid = OBJ_obj2nid(cmsalg->algorithm);
++    if (nid == NID_rsaEncryption)
++        return 1;
++    if (nid != NID_rsaesOaep) {
++        RSAerr(RSA_F_RSA_CMS_DECRYPT, RSA_R_UNSUPPORTED_ENCRYPTION_TYPE);
++        return -1;
++    }
++    /* Decode OAEP parameters */
++    oaep = rsa_oaep_decode(cmsalg, &maskHash);
++
++    if (oaep == NULL) {
++        RSAerr(RSA_F_RSA_CMS_DECRYPT, RSA_R_INVALID_OAEP_PARAMETERS);
++        goto err;
++    }
++
++    mgf1md = rsa_mgf1_to_md(oaep->maskGenFunc, maskHash);
++    if (!mgf1md)
++        goto err;
++    md = rsa_algor_to_md(oaep->hashFunc);
++    if (!md)
++        goto err;
++
++    if (oaep->pSourceFunc) {
++        X509_ALGOR *plab = oaep->pSourceFunc;
++        if (OBJ_obj2nid(plab->algorithm) != NID_pSpecified) {
++            RSAerr(RSA_F_RSA_CMS_DECRYPT, RSA_R_UNSUPPORTED_LABEL_SOURCE);
++            goto err;
++        }
++        if (plab->parameter->type != V_ASN1_OCTET_STRING) {
++            RSAerr(RSA_F_RSA_CMS_DECRYPT, RSA_R_INVALID_LABEL);
++            goto err;
++        }
++
++        label = plab->parameter->value.octet_string->data;
++        /* Stop label being freed when OAEP parameters are freed */
++        plab->parameter->value.octet_string->data = NULL;
++        labellen = plab->parameter->value.octet_string->length;
++    }
++
++    if (EVP_PKEY_CTX_set_rsa_padding(pkctx, RSA_PKCS1_OAEP_PADDING) <= 0)
++        goto err;
++    if (EVP_PKEY_CTX_set_rsa_oaep_md(pkctx, md) <= 0)
++        goto err;
++    if (EVP_PKEY_CTX_set_rsa_mgf1_md(pkctx, mgf1md) <= 0)
++        goto err;
++    if (EVP_PKEY_CTX_set0_rsa_oaep_label(pkctx, label, labellen) <= 0)
++        goto err;
++    /* Carry on */
++    rv = 1;
++
++ err:
++    RSA_OAEP_PARAMS_free(oaep);
++    X509_ALGOR_free(maskHash);
++    return rv;
++}
++
++static int rsa_cms_encrypt(CMS_RecipientInfo *ri)
++{
++    const EVP_MD *md, *mgf1md;
++    RSA_OAEP_PARAMS *oaep = NULL;
++    ASN1_STRING *os = NULL;
++    X509_ALGOR *alg;
++    EVP_PKEY_CTX *pkctx = CMS_RecipientInfo_get0_pkey_ctx(ri);
++    int pad_mode = RSA_PKCS1_PADDING, rv = 0, labellen;
++    unsigned char *label;
++    CMS_RecipientInfo_ktri_get0_algs(ri, NULL, NULL, &alg);
++    if (pkctx) {
++        if (EVP_PKEY_CTX_get_rsa_padding(pkctx, &pad_mode) <= 0)
++            return 0;
++    }
++    if (pad_mode == RSA_PKCS1_PADDING) {
++        X509_ALGOR_set0(alg, OBJ_nid2obj(NID_rsaEncryption), V_ASN1_NULL, 0);
++        return 1;
++    }
++    /* Not supported */
++    if (pad_mode != RSA_PKCS1_OAEP_PADDING)
++        return 0;
++    if (EVP_PKEY_CTX_get_rsa_oaep_md(pkctx, &md) <= 0)
++        goto err;
++    if (EVP_PKEY_CTX_get_rsa_mgf1_md(pkctx, &mgf1md) <= 0)
++        goto err;
++    labellen = EVP_PKEY_CTX_get0_rsa_oaep_label(pkctx, &label);
++    if (labellen < 0)
++        goto err;
++    oaep = RSA_OAEP_PARAMS_new();
++    if (oaep == NULL)
++        goto err;
++    if (!rsa_md_to_algor(&oaep->hashFunc, md))
++        goto err;
++    if (!rsa_md_to_mgf1(&oaep->maskGenFunc, mgf1md))
++        goto err;
++    if (labellen > 0) {
++        ASN1_OCTET_STRING *los;
++        oaep->pSourceFunc = X509_ALGOR_new();
++        if (oaep->pSourceFunc == NULL)
++            goto err;
++        los = ASN1_OCTET_STRING_new();
++        if (los == NULL)
++            goto err;
++        if (!ASN1_OCTET_STRING_set(los, label, labellen)) {
++            ASN1_OCTET_STRING_free(los);
++            goto err;
++        }
++        X509_ALGOR_set0(oaep->pSourceFunc, OBJ_nid2obj(NID_pSpecified),
++                        V_ASN1_OCTET_STRING, los);
++    }
++    /* create string with pss parameter encoding. */
++    if (!ASN1_item_pack(oaep, ASN1_ITEM_rptr(RSA_OAEP_PARAMS), &os))
++         goto err;
++    X509_ALGOR_set0(alg, OBJ_nid2obj(NID_rsaesOaep), V_ASN1_SEQUENCE, os);
++    os = NULL;
++    rv = 1;
++ err:
++    RSA_OAEP_PARAMS_free(oaep);
++    ASN1_STRING_free(os);
++    return rv;
++}
++#endif
++
++const EVP_PKEY_ASN1_METHOD rsa_asn1_meths[2] = {
++    {
++     EVP_PKEY_RSA,
++     EVP_PKEY_RSA,
++     ASN1_PKEY_SIGPARAM_NULL,
++
++     "RSA",
++     "OpenSSL RSA method",
++
++     rsa_pub_decode,
++     rsa_pub_encode,
++     rsa_pub_cmp,
++     rsa_pub_print,
++
++     rsa_priv_decode,
++     rsa_priv_encode,
++     rsa_priv_print,
++
++     int_rsa_size,
++     rsa_bits,
++     rsa_security_bits,
++
++     0, 0, 0, 0, 0, 0,
++
++     rsa_sig_print,
++     int_rsa_free,
++     rsa_pkey_ctrl,
++     old_rsa_priv_decode,
++     old_rsa_priv_encode,
++     rsa_item_verify,
++     rsa_item_sign},
++
++    {
++     EVP_PKEY_RSA2,
++     EVP_PKEY_RSA,
++     ASN1_PKEY_ALIAS}
++};
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/rsa/rsa_asn1.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/rsa/rsa_asn1.c
+new file mode 100644
+index 0000000..20f8ebf
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/rsa/rsa_asn1.c
+@@ -0,0 +1,81 @@
++/*
++ * Copyright 2000-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include "internal/cryptlib.h"
++#include 
++#include 
++#include 
++#include "rsa_locl.h"
++
++/* Override the default free and new methods */
++static int rsa_cb(int operation, ASN1_VALUE **pval, const ASN1_ITEM *it,
++                  void *exarg)
++{
++    if (operation == ASN1_OP_NEW_PRE) {
++        *pval = (ASN1_VALUE *)RSA_new();
++        if (*pval != NULL)
++            return 2;
++        return 0;
++    } else if (operation == ASN1_OP_FREE_PRE) {
++        RSA_free((RSA *)*pval);
++        *pval = NULL;
++        return 2;
++    }
++    return 1;
++}
++
++ASN1_SEQUENCE_cb(RSAPrivateKey, rsa_cb) = {
++        ASN1_SIMPLE(RSA, version, LONG),
++        ASN1_SIMPLE(RSA, n, BIGNUM),
++        ASN1_SIMPLE(RSA, e, BIGNUM),
++        ASN1_SIMPLE(RSA, d, CBIGNUM),
++        ASN1_SIMPLE(RSA, p, CBIGNUM),
++        ASN1_SIMPLE(RSA, q, CBIGNUM),
++        ASN1_SIMPLE(RSA, dmp1, CBIGNUM),
++        ASN1_SIMPLE(RSA, dmq1, CBIGNUM),
++        ASN1_SIMPLE(RSA, iqmp, CBIGNUM)
++} ASN1_SEQUENCE_END_cb(RSA, RSAPrivateKey)
++
++
++ASN1_SEQUENCE_cb(RSAPublicKey, rsa_cb) = {
++        ASN1_SIMPLE(RSA, n, BIGNUM),
++        ASN1_SIMPLE(RSA, e, BIGNUM),
++} ASN1_SEQUENCE_END_cb(RSA, RSAPublicKey)
++
++ASN1_SEQUENCE(RSA_PSS_PARAMS) = {
++        ASN1_EXP_OPT(RSA_PSS_PARAMS, hashAlgorithm, X509_ALGOR,0),
++        ASN1_EXP_OPT(RSA_PSS_PARAMS, maskGenAlgorithm, X509_ALGOR,1),
++        ASN1_EXP_OPT(RSA_PSS_PARAMS, saltLength, ASN1_INTEGER,2),
++        ASN1_EXP_OPT(RSA_PSS_PARAMS, trailerField, ASN1_INTEGER,3)
++} ASN1_SEQUENCE_END(RSA_PSS_PARAMS)
++
++IMPLEMENT_ASN1_FUNCTIONS(RSA_PSS_PARAMS)
++
++ASN1_SEQUENCE(RSA_OAEP_PARAMS) = {
++        ASN1_EXP_OPT(RSA_OAEP_PARAMS, hashFunc, X509_ALGOR, 0),
++        ASN1_EXP_OPT(RSA_OAEP_PARAMS, maskGenFunc, X509_ALGOR, 1),
++        ASN1_EXP_OPT(RSA_OAEP_PARAMS, pSourceFunc, X509_ALGOR, 2),
++} ASN1_SEQUENCE_END(RSA_OAEP_PARAMS)
++
++IMPLEMENT_ASN1_FUNCTIONS(RSA_OAEP_PARAMS)
++
++IMPLEMENT_ASN1_ENCODE_FUNCTIONS_const_fname(RSA, RSAPrivateKey, RSAPrivateKey)
++
++IMPLEMENT_ASN1_ENCODE_FUNCTIONS_const_fname(RSA, RSAPublicKey, RSAPublicKey)
++
++RSA *RSAPublicKey_dup(RSA *rsa)
++{
++    return ASN1_item_dup(ASN1_ITEM_rptr(RSAPublicKey), rsa);
++}
++
++RSA *RSAPrivateKey_dup(RSA *rsa)
++{
++    return ASN1_item_dup(ASN1_ITEM_rptr(RSAPrivateKey), rsa);
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/rsa/rsa_chk.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/rsa/rsa_chk.c
+new file mode 100644
+index 0000000..00260fb
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/rsa/rsa_chk.c
+@@ -0,0 +1,156 @@
++/*
++ * Copyright 1999-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include 
++#include "rsa_locl.h"
++
++int RSA_check_key(const RSA *key)
++{
++    return RSA_check_key_ex(key, NULL);
++}
++
++int RSA_check_key_ex(const RSA *key, BN_GENCB *cb)
++{
++    BIGNUM *i, *j, *k, *l, *m;
++    BN_CTX *ctx;
++    int ret = 1;
++
++    if (key->p == NULL || key->q == NULL || key->n == NULL
++            || key->e == NULL || key->d == NULL) {
++        RSAerr(RSA_F_RSA_CHECK_KEY_EX, RSA_R_VALUE_MISSING);
++        return 0;
++    }
++
++    i = BN_new();
++    j = BN_new();
++    k = BN_new();
++    l = BN_new();
++    m = BN_new();
++    ctx = BN_CTX_new();
++    if (i == NULL || j == NULL || k == NULL || l == NULL
++            || m == NULL || ctx == NULL) {
++        ret = -1;
++        RSAerr(RSA_F_RSA_CHECK_KEY_EX, ERR_R_MALLOC_FAILURE);
++        goto err;
++    }
++
++    if (BN_is_one(key->e)) {
++        ret = 0;
++        RSAerr(RSA_F_RSA_CHECK_KEY_EX, RSA_R_BAD_E_VALUE);
++    }
++    if (!BN_is_odd(key->e)) {
++        ret = 0;
++        RSAerr(RSA_F_RSA_CHECK_KEY_EX, RSA_R_BAD_E_VALUE);
++    }
++
++    /* p prime? */
++    if (BN_is_prime_ex(key->p, BN_prime_checks, NULL, cb) != 1) {
++        ret = 0;
++        RSAerr(RSA_F_RSA_CHECK_KEY_EX, RSA_R_P_NOT_PRIME);
++    }
++
++    /* q prime? */
++    if (BN_is_prime_ex(key->q, BN_prime_checks, NULL, cb) != 1) {
++        ret = 0;
++        RSAerr(RSA_F_RSA_CHECK_KEY_EX, RSA_R_Q_NOT_PRIME);
++    }
++
++    /* n = p*q? */
++    if (!BN_mul(i, key->p, key->q, ctx)) {
++        ret = -1;
++        goto err;
++    }
++    if (BN_cmp(i, key->n) != 0) {
++        ret = 0;
++        RSAerr(RSA_F_RSA_CHECK_KEY_EX, RSA_R_N_DOES_NOT_EQUAL_P_Q);
++    }
++
++    /* d*e = 1  mod lcm(p-1,q-1)? */
++    if (!BN_sub(i, key->p, BN_value_one())) {
++        ret = -1;
++        goto err;
++    }
++    if (!BN_sub(j, key->q, BN_value_one())) {
++        ret = -1;
++        goto err;
++    }
++
++    /* now compute k = lcm(i,j) */
++    if (!BN_mul(l, i, j, ctx)) {
++        ret = -1;
++        goto err;
++    }
++    if (!BN_gcd(m, i, j, ctx)) {
++        ret = -1;
++        goto err;
++    }
++    if (!BN_div(k, NULL, l, m, ctx)) { /* remainder is 0 */
++        ret = -1;
++        goto err;
++    }
++    if (!BN_mod_mul(i, key->d, key->e, k, ctx)) {
++        ret = -1;
++        goto err;
++    }
++
++    if (!BN_is_one(i)) {
++        ret = 0;
++        RSAerr(RSA_F_RSA_CHECK_KEY_EX, RSA_R_D_E_NOT_CONGRUENT_TO_1);
++    }
++
++    if (key->dmp1 != NULL && key->dmq1 != NULL && key->iqmp != NULL) {
++        /* dmp1 = d mod (p-1)? */
++        if (!BN_sub(i, key->p, BN_value_one())) {
++            ret = -1;
++            goto err;
++        }
++        if (!BN_mod(j, key->d, i, ctx)) {
++            ret = -1;
++            goto err;
++        }
++        if (BN_cmp(j, key->dmp1) != 0) {
++            ret = 0;
++            RSAerr(RSA_F_RSA_CHECK_KEY_EX, RSA_R_DMP1_NOT_CONGRUENT_TO_D);
++        }
++
++        /* dmq1 = d mod (q-1)? */
++        if (!BN_sub(i, key->q, BN_value_one())) {
++            ret = -1;
++            goto err;
++        }
++        if (!BN_mod(j, key->d, i, ctx)) {
++            ret = -1;
++            goto err;
++        }
++        if (BN_cmp(j, key->dmq1) != 0) {
++            ret = 0;
++            RSAerr(RSA_F_RSA_CHECK_KEY_EX, RSA_R_DMQ1_NOT_CONGRUENT_TO_D);
++        }
++
++        /* iqmp = q^-1 mod p? */
++        if (!BN_mod_inverse(i, key->q, key->p, ctx)) {
++            ret = -1;
++            goto err;
++        }
++        if (BN_cmp(i, key->iqmp) != 0) {
++            ret = 0;
++            RSAerr(RSA_F_RSA_CHECK_KEY_EX, RSA_R_IQMP_NOT_INVERSE_OF_Q);
++        }
++    }
++
++ err:
++    BN_free(i);
++    BN_free(j);
++    BN_free(k);
++    BN_free(l);
++    BN_free(m);
++    BN_CTX_free(ctx);
++    return ret;
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/rsa/rsa_crpt.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/rsa/rsa_crpt.c
+new file mode 100644
+index 0000000..9cd733b
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/rsa/rsa_crpt.c
+@@ -0,0 +1,178 @@
++/*
++ * Copyright 1995-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include 
++#include "internal/cryptlib.h"
++#include 
++#include "internal/bn_int.h"
++#include 
++#include "rsa_locl.h"
++
++int RSA_bits(const RSA *r)
++{
++    return (BN_num_bits(r->n));
++}
++
++int RSA_size(const RSA *r)
++{
++    return (BN_num_bytes(r->n));
++}
++
++int RSA_public_encrypt(int flen, const unsigned char *from, unsigned char *to,
++                       RSA *rsa, int padding)
++{
++    return (rsa->meth->rsa_pub_enc(flen, from, to, rsa, padding));
++}
++
++int RSA_private_encrypt(int flen, const unsigned char *from,
++                        unsigned char *to, RSA *rsa, int padding)
++{
++    return (rsa->meth->rsa_priv_enc(flen, from, to, rsa, padding));
++}
++
++int RSA_private_decrypt(int flen, const unsigned char *from,
++                        unsigned char *to, RSA *rsa, int padding)
++{
++    return (rsa->meth->rsa_priv_dec(flen, from, to, rsa, padding));
++}
++
++int RSA_public_decrypt(int flen, const unsigned char *from, unsigned char *to,
++                       RSA *rsa, int padding)
++{
++    return (rsa->meth->rsa_pub_dec(flen, from, to, rsa, padding));
++}
++
++int RSA_flags(const RSA *r)
++{
++    return ((r == NULL) ? 0 : r->meth->flags);
++}
++
++void RSA_blinding_off(RSA *rsa)
++{
++    BN_BLINDING_free(rsa->blinding);
++    rsa->blinding = NULL;
++    rsa->flags &= ~RSA_FLAG_BLINDING;
++    rsa->flags |= RSA_FLAG_NO_BLINDING;
++}
++
++int RSA_blinding_on(RSA *rsa, BN_CTX *ctx)
++{
++    int ret = 0;
++
++    if (rsa->blinding != NULL)
++        RSA_blinding_off(rsa);
++
++    rsa->blinding = RSA_setup_blinding(rsa, ctx);
++    if (rsa->blinding == NULL)
++        goto err;
++
++    rsa->flags |= RSA_FLAG_BLINDING;
++    rsa->flags &= ~RSA_FLAG_NO_BLINDING;
++    ret = 1;
++ err:
++    return (ret);
++}
++
++static BIGNUM *rsa_get_public_exp(const BIGNUM *d, const BIGNUM *p,
++                                  const BIGNUM *q, BN_CTX *ctx)
++{
++    BIGNUM *ret = NULL, *r0, *r1, *r2;
++
++    if (d == NULL || p == NULL || q == NULL)
++        return NULL;
++
++    BN_CTX_start(ctx);
++    r0 = BN_CTX_get(ctx);
++    r1 = BN_CTX_get(ctx);
++    r2 = BN_CTX_get(ctx);
++    if (r2 == NULL)
++        goto err;
++
++    if (!BN_sub(r1, p, BN_value_one()))
++        goto err;
++    if (!BN_sub(r2, q, BN_value_one()))
++        goto err;
++    if (!BN_mul(r0, r1, r2, ctx))
++        goto err;
++
++    ret = BN_mod_inverse(NULL, d, r0, ctx);
++ err:
++    BN_CTX_end(ctx);
++    return ret;
++}
++
++BN_BLINDING *RSA_setup_blinding(RSA *rsa, BN_CTX *in_ctx)
++{
++    BIGNUM *e;
++    BN_CTX *ctx;
++    BN_BLINDING *ret = NULL;
++
++    if (in_ctx == NULL) {
++        if ((ctx = BN_CTX_new()) == NULL)
++            return 0;
++    } else
++        ctx = in_ctx;
++
++    BN_CTX_start(ctx);
++    e = BN_CTX_get(ctx);
++    if (e == NULL) {
++        RSAerr(RSA_F_RSA_SETUP_BLINDING, ERR_R_MALLOC_FAILURE);
++        goto err;
++    }
++
++    if (rsa->e == NULL) {
++        e = rsa_get_public_exp(rsa->d, rsa->p, rsa->q, ctx);
++        if (e == NULL) {
++            RSAerr(RSA_F_RSA_SETUP_BLINDING, RSA_R_NO_PUBLIC_EXPONENT);
++            goto err;
++        }
++    } else
++        e = rsa->e;
++
++    if ((RAND_status() == 0) && rsa->d != NULL
++        && bn_get_words(rsa->d) != NULL) {
++        /*
++         * if PRNG is not properly seeded, resort to secret exponent as
++         * unpredictable seed
++         */
++        RAND_add(bn_get_words(rsa->d), bn_get_dmax(rsa->d) * sizeof(BN_ULONG),
++                 0.0);
++    }
++
++    {
++        BIGNUM *n = BN_new();
++
++        if (n == NULL) {
++            RSAerr(RSA_F_RSA_SETUP_BLINDING, ERR_R_MALLOC_FAILURE);
++            goto err;
++        }
++        BN_with_flags(n, rsa->n, BN_FLG_CONSTTIME);
++
++        ret = BN_BLINDING_create_param(NULL, e, n, ctx, rsa->meth->bn_mod_exp,
++                                       rsa->_method_mod_n);
++        /* We MUST free n before any further use of rsa->n */
++        BN_free(n);
++    }
++    if (ret == NULL) {
++        RSAerr(RSA_F_RSA_SETUP_BLINDING, ERR_R_BN_LIB);
++        goto err;
++    }
++
++    BN_BLINDING_set_current_thread(ret);
++
++ err:
++    BN_CTX_end(ctx);
++    if (ctx != in_ctx)
++        BN_CTX_free(ctx);
++    if (e != rsa->e)
++        BN_free(e);
++
++    return ret;
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/rsa/rsa_depr.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/rsa/rsa_depr.c
+new file mode 100644
+index 0000000..21e0562
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/rsa/rsa_depr.c
+@@ -0,0 +1,61 @@
++/*
++ * Copyright 2002-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++/*
++ * NB: This file contains deprecated functions (compatibility wrappers to the
++ * "new" versions).
++ */
++
++#include 
++#if OPENSSL_API_COMPAT >= 0x00908000L
++NON_EMPTY_TRANSLATION_UNIT
++
++#else
++
++# include 
++# include 
++# include "internal/cryptlib.h"
++# include 
++# include 
++
++RSA *RSA_generate_key(int bits, unsigned long e_value,
++                      void (*callback) (int, int, void *), void *cb_arg)
++{
++    int i;
++    BN_GENCB *cb = BN_GENCB_new();
++    RSA *rsa = RSA_new();
++    BIGNUM *e = BN_new();
++
++    if (cb == NULL || rsa == NULL || e == NULL)
++        goto err;
++
++    /*
++     * The problem is when building with 8, 16, or 32 BN_ULONG, unsigned long
++     * can be larger
++     */
++    for (i = 0; i < (int)sizeof(unsigned long) * 8; i++) {
++        if (e_value & (1UL << i))
++            if (BN_set_bit(e, i) == 0)
++                goto err;
++    }
++
++    BN_GENCB_set_old(cb, callback, cb_arg);
++
++    if (RSA_generate_key_ex(rsa, bits, e, cb)) {
++        BN_free(e);
++        BN_GENCB_free(cb);
++        return rsa;
++    }
++ err:
++    BN_free(e);
++    RSA_free(rsa);
++    BN_GENCB_free(cb);
++    return 0;
++}
++#endif
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/rsa/rsa_err.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/rsa/rsa_err.c
+new file mode 100644
+index 0000000..bf54095
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/rsa/rsa_err.c
+@@ -0,0 +1,185 @@
++/*
++ * Generated by util/mkerr.pl DO NOT EDIT
++ * Copyright 1995-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include 
++#include 
++
++/* BEGIN ERROR CODES */
++#ifndef OPENSSL_NO_ERR
++
++# define ERR_FUNC(func) ERR_PACK(ERR_LIB_RSA,func,0)
++# define ERR_REASON(reason) ERR_PACK(ERR_LIB_RSA,0,reason)
++
++static ERR_STRING_DATA RSA_str_functs[] = {
++    {ERR_FUNC(RSA_F_CHECK_PADDING_MD), "check_padding_md"},
++    {ERR_FUNC(RSA_F_ENCODE_PKCS1), "encode_pkcs1"},
++    {ERR_FUNC(RSA_F_INT_RSA_VERIFY), "int_rsa_verify"},
++    {ERR_FUNC(RSA_F_OLD_RSA_PRIV_DECODE), "old_rsa_priv_decode"},
++    {ERR_FUNC(RSA_F_PKEY_RSA_CTRL), "pkey_rsa_ctrl"},
++    {ERR_FUNC(RSA_F_PKEY_RSA_CTRL_STR), "pkey_rsa_ctrl_str"},
++    {ERR_FUNC(RSA_F_PKEY_RSA_SIGN), "pkey_rsa_sign"},
++    {ERR_FUNC(RSA_F_PKEY_RSA_VERIFY), "pkey_rsa_verify"},
++    {ERR_FUNC(RSA_F_PKEY_RSA_VERIFYRECOVER), "pkey_rsa_verifyrecover"},
++    {ERR_FUNC(RSA_F_RSA_ALGOR_TO_MD), "rsa_algor_to_md"},
++    {ERR_FUNC(RSA_F_RSA_BUILTIN_KEYGEN), "rsa_builtin_keygen"},
++    {ERR_FUNC(RSA_F_RSA_CHECK_KEY), "RSA_check_key"},
++    {ERR_FUNC(RSA_F_RSA_CHECK_KEY_EX), "RSA_check_key_ex"},
++    {ERR_FUNC(RSA_F_RSA_CMS_DECRYPT), "rsa_cms_decrypt"},
++    {ERR_FUNC(RSA_F_RSA_ITEM_VERIFY), "rsa_item_verify"},
++    {ERR_FUNC(RSA_F_RSA_METH_DUP), "RSA_meth_dup"},
++    {ERR_FUNC(RSA_F_RSA_METH_NEW), "RSA_meth_new"},
++    {ERR_FUNC(RSA_F_RSA_METH_SET1_NAME), "RSA_meth_set1_name"},
++    {ERR_FUNC(RSA_F_RSA_MGF1_TO_MD), "rsa_mgf1_to_md"},
++    {ERR_FUNC(RSA_F_RSA_NEW_METHOD), "RSA_new_method"},
++    {ERR_FUNC(RSA_F_RSA_NULL), "RSA_NULL"},
++    {ERR_FUNC(RSA_F_RSA_NULL_PRIVATE_DECRYPT), "RSA_null_private_decrypt"},
++    {ERR_FUNC(RSA_F_RSA_NULL_PRIVATE_ENCRYPT), "RSA_null_private_encrypt"},
++    {ERR_FUNC(RSA_F_RSA_NULL_PUBLIC_DECRYPT), "RSA_null_public_decrypt"},
++    {ERR_FUNC(RSA_F_RSA_NULL_PUBLIC_ENCRYPT), "RSA_null_public_encrypt"},
++    {ERR_FUNC(RSA_F_RSA_OSSL_PRIVATE_DECRYPT), "rsa_ossl_private_decrypt"},
++    {ERR_FUNC(RSA_F_RSA_OSSL_PRIVATE_ENCRYPT), "rsa_ossl_private_encrypt"},
++    {ERR_FUNC(RSA_F_RSA_OSSL_PUBLIC_DECRYPT), "rsa_ossl_public_decrypt"},
++    {ERR_FUNC(RSA_F_RSA_OSSL_PUBLIC_ENCRYPT), "rsa_ossl_public_encrypt"},
++    {ERR_FUNC(RSA_F_RSA_PADDING_ADD_NONE), "RSA_padding_add_none"},
++    {ERR_FUNC(RSA_F_RSA_PADDING_ADD_PKCS1_OAEP),
++     "RSA_padding_add_PKCS1_OAEP"},
++    {ERR_FUNC(RSA_F_RSA_PADDING_ADD_PKCS1_OAEP_MGF1),
++     "RSA_padding_add_PKCS1_OAEP_mgf1"},
++    {ERR_FUNC(RSA_F_RSA_PADDING_ADD_PKCS1_PSS), "RSA_padding_add_PKCS1_PSS"},
++    {ERR_FUNC(RSA_F_RSA_PADDING_ADD_PKCS1_PSS_MGF1),
++     "RSA_padding_add_PKCS1_PSS_mgf1"},
++    {ERR_FUNC(RSA_F_RSA_PADDING_ADD_PKCS1_TYPE_1),
++     "RSA_padding_add_PKCS1_type_1"},
++    {ERR_FUNC(RSA_F_RSA_PADDING_ADD_PKCS1_TYPE_2),
++     "RSA_padding_add_PKCS1_type_2"},
++    {ERR_FUNC(RSA_F_RSA_PADDING_ADD_SSLV23), "RSA_padding_add_SSLv23"},
++    {ERR_FUNC(RSA_F_RSA_PADDING_ADD_X931), "RSA_padding_add_X931"},
++    {ERR_FUNC(RSA_F_RSA_PADDING_CHECK_NONE), "RSA_padding_check_none"},
++    {ERR_FUNC(RSA_F_RSA_PADDING_CHECK_PKCS1_OAEP),
++     "RSA_padding_check_PKCS1_OAEP"},
++    {ERR_FUNC(RSA_F_RSA_PADDING_CHECK_PKCS1_OAEP_MGF1),
++     "RSA_padding_check_PKCS1_OAEP_mgf1"},
++    {ERR_FUNC(RSA_F_RSA_PADDING_CHECK_PKCS1_TYPE_1),
++     "RSA_padding_check_PKCS1_type_1"},
++    {ERR_FUNC(RSA_F_RSA_PADDING_CHECK_PKCS1_TYPE_2),
++     "RSA_padding_check_PKCS1_type_2"},
++    {ERR_FUNC(RSA_F_RSA_PADDING_CHECK_SSLV23), "RSA_padding_check_SSLv23"},
++    {ERR_FUNC(RSA_F_RSA_PADDING_CHECK_X931), "RSA_padding_check_X931"},
++    {ERR_FUNC(RSA_F_RSA_PRINT), "RSA_print"},
++    {ERR_FUNC(RSA_F_RSA_PRINT_FP), "RSA_print_fp"},
++    {ERR_FUNC(RSA_F_RSA_PRIV_ENCODE), "rsa_priv_encode"},
++    {ERR_FUNC(RSA_F_RSA_PSS_TO_CTX), "rsa_pss_to_ctx"},
++    {ERR_FUNC(RSA_F_RSA_PUB_DECODE), "rsa_pub_decode"},
++    {ERR_FUNC(RSA_F_RSA_SETUP_BLINDING), "RSA_setup_blinding"},
++    {ERR_FUNC(RSA_F_RSA_SIGN), "RSA_sign"},
++    {ERR_FUNC(RSA_F_RSA_SIGN_ASN1_OCTET_STRING),
++     "RSA_sign_ASN1_OCTET_STRING"},
++    {ERR_FUNC(RSA_F_RSA_VERIFY), "RSA_verify"},
++    {ERR_FUNC(RSA_F_RSA_VERIFY_ASN1_OCTET_STRING),
++     "RSA_verify_ASN1_OCTET_STRING"},
++    {ERR_FUNC(RSA_F_RSA_VERIFY_PKCS1_PSS_MGF1), "RSA_verify_PKCS1_PSS_mgf1"},
++    {0, NULL}
++};
++
++static ERR_STRING_DATA RSA_str_reasons[] = {
++    {ERR_REASON(RSA_R_ALGORITHM_MISMATCH), "algorithm mismatch"},
++    {ERR_REASON(RSA_R_BAD_E_VALUE), "bad e value"},
++    {ERR_REASON(RSA_R_BAD_FIXED_HEADER_DECRYPT), "bad fixed header decrypt"},
++    {ERR_REASON(RSA_R_BAD_PAD_BYTE_COUNT), "bad pad byte count"},
++    {ERR_REASON(RSA_R_BAD_SIGNATURE), "bad signature"},
++    {ERR_REASON(RSA_R_BLOCK_TYPE_IS_NOT_01), "block type is not 01"},
++    {ERR_REASON(RSA_R_BLOCK_TYPE_IS_NOT_02), "block type is not 02"},
++    {ERR_REASON(RSA_R_DATA_GREATER_THAN_MOD_LEN),
++     "data greater than mod len"},
++    {ERR_REASON(RSA_R_DATA_TOO_LARGE), "data too large"},
++    {ERR_REASON(RSA_R_DATA_TOO_LARGE_FOR_KEY_SIZE),
++     "data too large for key size"},
++    {ERR_REASON(RSA_R_DATA_TOO_LARGE_FOR_MODULUS),
++     "data too large for modulus"},
++    {ERR_REASON(RSA_R_DATA_TOO_SMALL), "data too small"},
++    {ERR_REASON(RSA_R_DATA_TOO_SMALL_FOR_KEY_SIZE),
++     "data too small for key size"},
++    {ERR_REASON(RSA_R_DIGEST_DOES_NOT_MATCH), "digest does not match"},
++    {ERR_REASON(RSA_R_DIGEST_TOO_BIG_FOR_RSA_KEY),
++     "digest too big for rsa key"},
++    {ERR_REASON(RSA_R_DMP1_NOT_CONGRUENT_TO_D), "dmp1 not congruent to d"},
++    {ERR_REASON(RSA_R_DMQ1_NOT_CONGRUENT_TO_D), "dmq1 not congruent to d"},
++    {ERR_REASON(RSA_R_D_E_NOT_CONGRUENT_TO_1), "d e not congruent to 1"},
++    {ERR_REASON(RSA_R_FIRST_OCTET_INVALID), "first octet invalid"},
++    {ERR_REASON(RSA_R_ILLEGAL_OR_UNSUPPORTED_PADDING_MODE),
++     "illegal or unsupported padding mode"},
++    {ERR_REASON(RSA_R_INVALID_DIGEST), "invalid digest"},
++    {ERR_REASON(RSA_R_INVALID_DIGEST_LENGTH), "invalid digest length"},
++    {ERR_REASON(RSA_R_INVALID_HEADER), "invalid header"},
++    {ERR_REASON(RSA_R_INVALID_LABEL), "invalid label"},
++    {ERR_REASON(RSA_R_INVALID_MESSAGE_LENGTH), "invalid message length"},
++    {ERR_REASON(RSA_R_INVALID_MGF1_MD), "invalid mgf1 md"},
++    {ERR_REASON(RSA_R_INVALID_OAEP_PARAMETERS), "invalid oaep parameters"},
++    {ERR_REASON(RSA_R_INVALID_PADDING), "invalid padding"},
++    {ERR_REASON(RSA_R_INVALID_PADDING_MODE), "invalid padding mode"},
++    {ERR_REASON(RSA_R_INVALID_PSS_PARAMETERS), "invalid pss parameters"},
++    {ERR_REASON(RSA_R_INVALID_PSS_SALTLEN), "invalid pss saltlen"},
++    {ERR_REASON(RSA_R_INVALID_SALT_LENGTH), "invalid salt length"},
++    {ERR_REASON(RSA_R_INVALID_TRAILER), "invalid trailer"},
++    {ERR_REASON(RSA_R_INVALID_X931_DIGEST), "invalid x931 digest"},
++    {ERR_REASON(RSA_R_IQMP_NOT_INVERSE_OF_Q), "iqmp not inverse of q"},
++    {ERR_REASON(RSA_R_KEY_SIZE_TOO_SMALL), "key size too small"},
++    {ERR_REASON(RSA_R_LAST_OCTET_INVALID), "last octet invalid"},
++    {ERR_REASON(RSA_R_MODULUS_TOO_LARGE), "modulus too large"},
++    {ERR_REASON(RSA_R_NO_PUBLIC_EXPONENT), "no public exponent"},
++    {ERR_REASON(RSA_R_NULL_BEFORE_BLOCK_MISSING),
++     "null before block missing"},
++    {ERR_REASON(RSA_R_N_DOES_NOT_EQUAL_P_Q), "n does not equal p q"},
++    {ERR_REASON(RSA_R_OAEP_DECODING_ERROR), "oaep decoding error"},
++    {ERR_REASON(RSA_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE),
++     "operation not supported for this keytype"},
++    {ERR_REASON(RSA_R_PADDING_CHECK_FAILED), "padding check failed"},
++    {ERR_REASON(RSA_R_PKCS_DECODING_ERROR), "pkcs decoding error"},
++    {ERR_REASON(RSA_R_P_NOT_PRIME), "p not prime"},
++    {ERR_REASON(RSA_R_Q_NOT_PRIME), "q not prime"},
++    {ERR_REASON(RSA_R_RSA_OPERATIONS_NOT_SUPPORTED),
++     "rsa operations not supported"},
++    {ERR_REASON(RSA_R_SLEN_CHECK_FAILED), "salt length check failed"},
++    {ERR_REASON(RSA_R_SLEN_RECOVERY_FAILED), "salt length recovery failed"},
++    {ERR_REASON(RSA_R_SSLV3_ROLLBACK_ATTACK), "sslv3 rollback attack"},
++    {ERR_REASON(RSA_R_THE_ASN1_OBJECT_IDENTIFIER_IS_NOT_KNOWN_FOR_THIS_MD),
++     "the asn1 object identifier is not known for this md"},
++    {ERR_REASON(RSA_R_UNKNOWN_ALGORITHM_TYPE), "unknown algorithm type"},
++    {ERR_REASON(RSA_R_UNKNOWN_DIGEST), "unknown digest"},
++    {ERR_REASON(RSA_R_UNKNOWN_MASK_DIGEST), "unknown mask digest"},
++    {ERR_REASON(RSA_R_UNKNOWN_PADDING_TYPE), "unknown padding type"},
++    {ERR_REASON(RSA_R_UNSUPPORTED_ENCRYPTION_TYPE),
++     "unsupported encryption type"},
++    {ERR_REASON(RSA_R_UNSUPPORTED_LABEL_SOURCE), "unsupported label source"},
++    {ERR_REASON(RSA_R_UNSUPPORTED_MASK_ALGORITHM),
++     "unsupported mask algorithm"},
++    {ERR_REASON(RSA_R_UNSUPPORTED_MASK_PARAMETER),
++     "unsupported mask parameter"},
++    {ERR_REASON(RSA_R_UNSUPPORTED_SIGNATURE_TYPE),
++     "unsupported signature type"},
++    {ERR_REASON(RSA_R_VALUE_MISSING), "value missing"},
++    {ERR_REASON(RSA_R_WRONG_SIGNATURE_LENGTH), "wrong signature length"},
++    {0, NULL}
++};
++
++#endif
++
++int ERR_load_RSA_strings(void)
++{
++#ifndef OPENSSL_NO_ERR
++
++    if (ERR_func_error_string(RSA_str_functs[0].error) == NULL) {
++        ERR_load_strings(0, RSA_str_functs);
++        ERR_load_strings(0, RSA_str_reasons);
++    }
++#endif
++    return 1;
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/rsa/rsa_gen.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/rsa/rsa_gen.c
+new file mode 100644
+index 0000000..0d1d56b
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/rsa/rsa_gen.c
+@@ -0,0 +1,199 @@
++/*
++ * Copyright 1995-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++/*
++ * NB: these functions have been "upgraded", the deprecated versions (which
++ * are compatibility wrappers using these functions) are in rsa_depr.c. -
++ * Geoff
++ */
++
++#include 
++#include 
++#include "internal/cryptlib.h"
++#include 
++#include "rsa_locl.h"
++
++static int rsa_builtin_keygen(RSA *rsa, int bits, BIGNUM *e_value,
++                              BN_GENCB *cb);
++
++/*
++ * NB: this wrapper would normally be placed in rsa_lib.c and the static
++ * implementation would probably be in rsa_eay.c. Nonetheless, is kept here
++ * so that we don't introduce a new linker dependency. Eg. any application
++ * that wasn't previously linking object code related to key-generation won't
++ * have to now just because key-generation is part of RSA_METHOD.
++ */
++int RSA_generate_key_ex(RSA *rsa, int bits, BIGNUM *e_value, BN_GENCB *cb)
++{
++    if (rsa->meth->rsa_keygen)
++        return rsa->meth->rsa_keygen(rsa, bits, e_value, cb);
++    return rsa_builtin_keygen(rsa, bits, e_value, cb);
++}
++
++static int rsa_builtin_keygen(RSA *rsa, int bits, BIGNUM *e_value,
++                              BN_GENCB *cb)
++{
++    BIGNUM *r0 = NULL, *r1 = NULL, *r2 = NULL, *r3 = NULL, *tmp;
++    int bitsp, bitsq, ok = -1, n = 0;
++    BN_CTX *ctx = NULL;
++
++    ctx = BN_CTX_new();
++    if (ctx == NULL)
++        goto err;
++    BN_CTX_start(ctx);
++    r0 = BN_CTX_get(ctx);
++    r1 = BN_CTX_get(ctx);
++    r2 = BN_CTX_get(ctx);
++    r3 = BN_CTX_get(ctx);
++    if (r3 == NULL)
++        goto err;
++
++    bitsp = (bits + 1) / 2;
++    bitsq = bits - bitsp;
++
++    /* We need the RSA components non-NULL */
++    if (!rsa->n && ((rsa->n = BN_new()) == NULL))
++        goto err;
++    if (!rsa->d && ((rsa->d = BN_secure_new()) == NULL))
++        goto err;
++    if (!rsa->e && ((rsa->e = BN_new()) == NULL))
++        goto err;
++    if (!rsa->p && ((rsa->p = BN_secure_new()) == NULL))
++        goto err;
++    if (!rsa->q && ((rsa->q = BN_secure_new()) == NULL))
++        goto err;
++    if (!rsa->dmp1 && ((rsa->dmp1 = BN_secure_new()) == NULL))
++        goto err;
++    if (!rsa->dmq1 && ((rsa->dmq1 = BN_secure_new()) == NULL))
++        goto err;
++    if (!rsa->iqmp && ((rsa->iqmp = BN_secure_new()) == NULL))
++        goto err;
++
++    if (BN_copy(rsa->e, e_value) == NULL)
++        goto err;
++
++    /* generate p and q */
++    for (;;) {
++        if (!BN_generate_prime_ex(rsa->p, bitsp, 0, NULL, NULL, cb))
++            goto err;
++        if (!BN_sub(r2, rsa->p, BN_value_one()))
++            goto err;
++        if (!BN_gcd(r1, r2, rsa->e, ctx))
++            goto err;
++        if (BN_is_one(r1))
++            break;
++        if (!BN_GENCB_call(cb, 2, n++))
++            goto err;
++    }
++    if (!BN_GENCB_call(cb, 3, 0))
++        goto err;
++    for (;;) {
++        /*
++         * When generating ridiculously small keys, we can get stuck
++         * continually regenerating the same prime values. Check for this and
++         * bail if it happens 3 times.
++         */
++        unsigned int degenerate = 0;
++        do {
++            if (!BN_generate_prime_ex(rsa->q, bitsq, 0, NULL, NULL, cb))
++                goto err;
++        } while ((BN_cmp(rsa->p, rsa->q) == 0) && (++degenerate < 3));
++        if (degenerate == 3) {
++            ok = 0;             /* we set our own err */
++            RSAerr(RSA_F_RSA_BUILTIN_KEYGEN, RSA_R_KEY_SIZE_TOO_SMALL);
++            goto err;
++        }
++        if (!BN_sub(r2, rsa->q, BN_value_one()))
++            goto err;
++        if (!BN_gcd(r1, r2, rsa->e, ctx))
++            goto err;
++        if (BN_is_one(r1))
++            break;
++        if (!BN_GENCB_call(cb, 2, n++))
++            goto err;
++    }
++    if (!BN_GENCB_call(cb, 3, 1))
++        goto err;
++    if (BN_cmp(rsa->p, rsa->q) < 0) {
++        tmp = rsa->p;
++        rsa->p = rsa->q;
++        rsa->q = tmp;
++    }
++
++    /* calculate n */
++    if (!BN_mul(rsa->n, rsa->p, rsa->q, ctx))
++        goto err;
++
++    /* calculate d */
++    if (!BN_sub(r1, rsa->p, BN_value_one()))
++        goto err;               /* p-1 */
++    if (!BN_sub(r2, rsa->q, BN_value_one()))
++        goto err;               /* q-1 */
++    if (!BN_mul(r0, r1, r2, ctx))
++        goto err;               /* (p-1)(q-1) */
++    {
++        BIGNUM *pr0 = BN_new();
++
++        if (pr0 == NULL)
++            goto err;
++        BN_with_flags(pr0, r0, BN_FLG_CONSTTIME);
++        if (!BN_mod_inverse(rsa->d, rsa->e, pr0, ctx)) {
++            BN_free(pr0);
++            goto err;               /* d */
++        }
++        /* We MUST free pr0 before any further use of r0 */
++        BN_free(pr0);
++    }
++
++    {
++        BIGNUM *d = BN_new();
++
++        if (d == NULL)
++            goto err;
++        BN_with_flags(d, rsa->d, BN_FLG_CONSTTIME);
++
++        if (   /* calculate d mod (p-1) */
++               !BN_mod(rsa->dmp1, d, r1, ctx)
++               /* calculate d mod (q-1) */
++            || !BN_mod(rsa->dmq1, d, r2, ctx)) {
++            BN_free(d);
++            goto err;
++        }
++        /* We MUST free d before any further use of rsa->d */
++        BN_free(d);
++    }
++
++    {
++        BIGNUM *p = BN_new();
++
++        if (p == NULL)
++            goto err;
++        BN_with_flags(p, rsa->p, BN_FLG_CONSTTIME);
++
++        /* calculate inverse of q mod p */
++        if (!BN_mod_inverse(rsa->iqmp, rsa->q, p, ctx)) {
++            BN_free(p);
++            goto err;
++        }
++        /* We MUST free p before any further use of rsa->p */
++        BN_free(p);
++    }
++
++    ok = 1;
++ err:
++    if (ok == -1) {
++        RSAerr(RSA_F_RSA_BUILTIN_KEYGEN, ERR_LIB_BN);
++        ok = 0;
++    }
++    if (ctx != NULL)
++        BN_CTX_end(ctx);
++    BN_CTX_free(ctx);
++
++    return ok;
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/rsa/rsa_lib.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/rsa/rsa_lib.c
+new file mode 100644
+index 0000000..48e9100
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/rsa/rsa_lib.c
+@@ -0,0 +1,310 @@
++/*
++ * Copyright 1995-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include 
++#include "internal/cryptlib.h"
++#include 
++#include "internal/bn_int.h"
++#include 
++#include "rsa_locl.h"
++
++static const RSA_METHOD *default_RSA_meth = NULL;
++
++RSA *RSA_new(void)
++{
++    RSA *r = RSA_new_method(NULL);
++
++    return r;
++}
++
++void RSA_set_default_method(const RSA_METHOD *meth)
++{
++    default_RSA_meth = meth;
++}
++
++const RSA_METHOD *RSA_get_default_method(void)
++{
++    if (default_RSA_meth == NULL) {
++#ifdef RSA_NULL
++        default_RSA_meth = RSA_null_method();
++#else
++        default_RSA_meth = RSA_PKCS1_OpenSSL();
++#endif
++    }
++
++    return default_RSA_meth;
++}
++
++const RSA_METHOD *RSA_get_method(const RSA *rsa)
++{
++    return rsa->meth;
++}
++
++int RSA_set_method(RSA *rsa, const RSA_METHOD *meth)
++{
++    /*
++     * NB: The caller is specifically setting a method, so it's not up to us
++     * to deal with which ENGINE it comes from.
++     */
++    const RSA_METHOD *mtmp;
++    mtmp = rsa->meth;
++    if (mtmp->finish)
++        mtmp->finish(rsa);
++#ifndef OPENSSL_NO_ENGINE
++    ENGINE_finish(rsa->engine);
++    rsa->engine = NULL;
++#endif
++    rsa->meth = meth;
++    if (meth->init)
++        meth->init(rsa);
++    return 1;
++}
++
++RSA *RSA_new_method(ENGINE *engine)
++{
++    RSA *ret = OPENSSL_zalloc(sizeof(*ret));
++
++    if (ret == NULL) {
++        RSAerr(RSA_F_RSA_NEW_METHOD, ERR_R_MALLOC_FAILURE);
++        return NULL;
++    }
++
++    ret->references = 1;
++    ret->lock = CRYPTO_THREAD_lock_new();
++    if (ret->lock == NULL) {
++        RSAerr(RSA_F_RSA_NEW_METHOD, ERR_R_MALLOC_FAILURE);
++        OPENSSL_free(ret);
++        return NULL;
++    }
++
++    ret->meth = RSA_get_default_method();
++#ifndef OPENSSL_NO_ENGINE
++    ret->flags = ret->meth->flags & ~RSA_FLAG_NON_FIPS_ALLOW;
++    if (engine) {
++        if (!ENGINE_init(engine)) {
++            RSAerr(RSA_F_RSA_NEW_METHOD, ERR_R_ENGINE_LIB);
++            goto err;
++        }
++        ret->engine = engine;
++    } else
++        ret->engine = ENGINE_get_default_RSA();
++    if (ret->engine) {
++        ret->meth = ENGINE_get_RSA(ret->engine);
++        if (ret->meth == NULL) {
++            RSAerr(RSA_F_RSA_NEW_METHOD, ERR_R_ENGINE_LIB);
++            goto err;
++        }
++    }
++#endif
++
++    ret->flags = ret->meth->flags & ~RSA_FLAG_NON_FIPS_ALLOW;
++    if (!CRYPTO_new_ex_data(CRYPTO_EX_INDEX_RSA, ret, &ret->ex_data)) {
++        goto err;
++    }
++
++    if ((ret->meth->init != NULL) && !ret->meth->init(ret)) {
++        RSAerr(RSA_F_RSA_NEW_METHOD, ERR_R_INIT_FAIL);
++        goto err;
++    }
++
++    return ret;
++
++err:
++    RSA_free(ret);
++    return NULL;
++}
++
++void RSA_free(RSA *r)
++{
++    int i;
++
++    if (r == NULL)
++        return;
++
++    CRYPTO_atomic_add(&r->references, -1, &i, r->lock);
++    REF_PRINT_COUNT("RSA", r);
++    if (i > 0)
++        return;
++    REF_ASSERT_ISNT(i < 0);
++
++    if (r->meth->finish)
++        r->meth->finish(r);
++#ifndef OPENSSL_NO_ENGINE
++    ENGINE_finish(r->engine);
++#endif
++
++    CRYPTO_free_ex_data(CRYPTO_EX_INDEX_RSA, r, &r->ex_data);
++
++    CRYPTO_THREAD_lock_free(r->lock);
++
++    BN_clear_free(r->n);
++    BN_clear_free(r->e);
++    BN_clear_free(r->d);
++    BN_clear_free(r->p);
++    BN_clear_free(r->q);
++    BN_clear_free(r->dmp1);
++    BN_clear_free(r->dmq1);
++    BN_clear_free(r->iqmp);
++    BN_BLINDING_free(r->blinding);
++    BN_BLINDING_free(r->mt_blinding);
++    OPENSSL_free(r->bignum_data);
++    OPENSSL_free(r);
++}
++
++int RSA_up_ref(RSA *r)
++{
++    int i;
++
++    if (CRYPTO_atomic_add(&r->references, 1, &i, r->lock) <= 0)
++        return 0;
++
++    REF_PRINT_COUNT("RSA", r);
++    REF_ASSERT_ISNT(i < 2);
++    return ((i > 1) ? 1 : 0);
++}
++
++int RSA_set_ex_data(RSA *r, int idx, void *arg)
++{
++    return (CRYPTO_set_ex_data(&r->ex_data, idx, arg));
++}
++
++void *RSA_get_ex_data(const RSA *r, int idx)
++{
++    return (CRYPTO_get_ex_data(&r->ex_data, idx));
++}
++
++int RSA_security_bits(const RSA *rsa)
++{
++    return BN_security_bits(BN_num_bits(rsa->n), -1);
++}
++
++int RSA_set0_key(RSA *r, BIGNUM *n, BIGNUM *e, BIGNUM *d)
++{
++    /* If the fields n and e in r are NULL, the corresponding input
++     * parameters MUST be non-NULL for n and e.  d may be
++     * left NULL (in case only the public key is used).
++     */
++    if ((r->n == NULL && n == NULL)
++        || (r->e == NULL && e == NULL))
++        return 0;
++
++    if (n != NULL) {
++        BN_free(r->n);
++        r->n = n;
++    }
++    if (e != NULL) {
++        BN_free(r->e);
++        r->e = e;
++    }
++    if (d != NULL) {
++        BN_free(r->d);
++        r->d = d;
++    }
++
++    return 1;
++}
++
++int RSA_set0_factors(RSA *r, BIGNUM *p, BIGNUM *q)
++{
++    /* If the fields p and q in r are NULL, the corresponding input
++     * parameters MUST be non-NULL.
++     */
++    if ((r->p == NULL && p == NULL)
++        || (r->q == NULL && q == NULL))
++        return 0;
++
++    if (p != NULL) {
++        BN_free(r->p);
++        r->p = p;
++    }
++    if (q != NULL) {
++        BN_free(r->q);
++        r->q = q;
++    }
++
++    return 1;
++}
++
++int RSA_set0_crt_params(RSA *r, BIGNUM *dmp1, BIGNUM *dmq1, BIGNUM *iqmp)
++{
++    /* If the fields dmp1, dmq1 and iqmp in r are NULL, the corresponding input
++     * parameters MUST be non-NULL.
++     */
++    if ((r->dmp1 == NULL && dmp1 == NULL)
++        || (r->dmq1 == NULL && dmq1 == NULL)
++        || (r->iqmp == NULL && iqmp == NULL))
++        return 0;
++
++    if (dmp1 != NULL) {
++        BN_free(r->dmp1);
++        r->dmp1 = dmp1;
++    }
++    if (dmq1 != NULL) {
++        BN_free(r->dmq1);
++        r->dmq1 = dmq1;
++    }
++    if (iqmp != NULL) {
++        BN_free(r->iqmp);
++        r->iqmp = iqmp;
++    }
++
++    return 1;
++}
++
++void RSA_get0_key(const RSA *r,
++                  const BIGNUM **n, const BIGNUM **e, const BIGNUM **d)
++{
++    if (n != NULL)
++        *n = r->n;
++    if (e != NULL)
++        *e = r->e;
++    if (d != NULL)
++        *d = r->d;
++}
++
++void RSA_get0_factors(const RSA *r, const BIGNUM **p, const BIGNUM **q)
++{
++    if (p != NULL)
++        *p = r->p;
++    if (q != NULL)
++        *q = r->q;
++}
++
++void RSA_get0_crt_params(const RSA *r,
++                         const BIGNUM **dmp1, const BIGNUM **dmq1,
++                         const BIGNUM **iqmp)
++{
++    if (dmp1 != NULL)
++        *dmp1 = r->dmp1;
++    if (dmq1 != NULL)
++        *dmq1 = r->dmq1;
++    if (iqmp != NULL)
++        *iqmp = r->iqmp;
++}
++
++void RSA_clear_flags(RSA *r, int flags)
++{
++    r->flags &= ~flags;
++}
++
++int RSA_test_flags(const RSA *r, int flags)
++{
++    return r->flags & flags;
++}
++
++void RSA_set_flags(RSA *r, int flags)
++{
++    r->flags |= flags;
++}
++
++ENGINE *RSA_get0_engine(const RSA *r)
++{
++    return r->engine;
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/rsa/rsa_locl.h b/CryptoPkg/Library/OpensslLib/openssl/crypto/rsa/rsa_locl.h
+new file mode 100644
+index 0000000..5d16aa6
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/rsa/rsa_locl.h
+@@ -0,0 +1,96 @@
++/*
++ * Copyright 2006-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++
++struct rsa_st {
++    /*
++     * The first parameter is used to pickup errors where this is passed
++     * instead of aEVP_PKEY, it is set to 0
++     */
++    int pad;
++    long version;
++    const RSA_METHOD *meth;
++    /* functional reference if 'meth' is ENGINE-provided */
++    ENGINE *engine;
++    BIGNUM *n;
++    BIGNUM *e;
++    BIGNUM *d;
++    BIGNUM *p;
++    BIGNUM *q;
++    BIGNUM *dmp1;
++    BIGNUM *dmq1;
++    BIGNUM *iqmp;
++    /* be careful using this if the RSA structure is shared */
++    CRYPTO_EX_DATA ex_data;
++    int references;
++    int flags;
++    /* Used to cache montgomery values */
++    BN_MONT_CTX *_method_mod_n;
++    BN_MONT_CTX *_method_mod_p;
++    BN_MONT_CTX *_method_mod_q;
++    /*
++     * all BIGNUM values are actually in the following data, if it is not
++     * NULL
++     */
++    char *bignum_data;
++    BN_BLINDING *blinding;
++    BN_BLINDING *mt_blinding;
++    CRYPTO_RWLOCK *lock;
++};
++
++struct rsa_meth_st {
++    char *name;
++    int (*rsa_pub_enc) (int flen, const unsigned char *from,
++                        unsigned char *to, RSA *rsa, int padding);
++    int (*rsa_pub_dec) (int flen, const unsigned char *from,
++                        unsigned char *to, RSA *rsa, int padding);
++    int (*rsa_priv_enc) (int flen, const unsigned char *from,
++                         unsigned char *to, RSA *rsa, int padding);
++    int (*rsa_priv_dec) (int flen, const unsigned char *from,
++                         unsigned char *to, RSA *rsa, int padding);
++    /* Can be null */
++    int (*rsa_mod_exp) (BIGNUM *r0, const BIGNUM *I, RSA *rsa, BN_CTX *ctx);
++    /* Can be null */
++    int (*bn_mod_exp) (BIGNUM *r, const BIGNUM *a, const BIGNUM *p,
++                       const BIGNUM *m, BN_CTX *ctx, BN_MONT_CTX *m_ctx);
++    /* called at new */
++    int (*init) (RSA *rsa);
++    /* called at free */
++    int (*finish) (RSA *rsa);
++    /* RSA_METHOD_FLAG_* things */
++    int flags;
++    /* may be needed! */
++    char *app_data;
++    /*
++     * New sign and verify functions: some libraries don't allow arbitrary
++     * data to be signed/verified: this allows them to be used. Note: for
++     * this to work the RSA_public_decrypt() and RSA_private_encrypt() should
++     * *NOT* be used RSA_sign(), RSA_verify() should be used instead.
++     */
++    int (*rsa_sign) (int type,
++                     const unsigned char *m, unsigned int m_length,
++                     unsigned char *sigret, unsigned int *siglen,
++                     const RSA *rsa);
++    int (*rsa_verify) (int dtype, const unsigned char *m,
++                       unsigned int m_length, const unsigned char *sigbuf,
++                       unsigned int siglen, const RSA *rsa);
++    /*
++     * If this callback is NULL, the builtin software RSA key-gen will be
++     * used. This is for behavioural compatibility whilst the code gets
++     * rewired, but one day it would be nice to assume there are no such
++     * things as "builtin software" implementations.
++     */
++    int (*rsa_keygen) (RSA *rsa, int bits, BIGNUM *e, BN_GENCB *cb);
++};
++
++extern int int_rsa_verify(int dtype, const unsigned char *m,
++                          unsigned int m_len, unsigned char *rm,
++                          size_t *prm_len, const unsigned char *sigbuf,
++                          size_t siglen, RSA *rsa);
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/rsa/rsa_meth.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/rsa/rsa_meth.c
+new file mode 100644
+index 0000000..9480abd
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/rsa/rsa_meth.c
+@@ -0,0 +1,273 @@
++/*
++ * Copyright 2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include "rsa_locl.h"
++#include 
++
++RSA_METHOD *RSA_meth_new(const char *name, int flags)
++{
++    RSA_METHOD *meth = OPENSSL_zalloc(sizeof(*meth));
++
++    if (meth != NULL) {
++        meth->flags = flags;
++
++        meth->name = OPENSSL_strdup(name);
++        if (meth->name != NULL)
++            return meth;
++
++        OPENSSL_free(meth);
++    }
++
++    RSAerr(RSA_F_RSA_METH_NEW, ERR_R_MALLOC_FAILURE);
++    return NULL;
++}
++
++void RSA_meth_free(RSA_METHOD *meth)
++{
++    if (meth != NULL) {
++        OPENSSL_free(meth->name);
++        OPENSSL_free(meth);
++    }
++}
++
++RSA_METHOD *RSA_meth_dup(const RSA_METHOD *meth)
++{
++    RSA_METHOD *ret = OPENSSL_malloc(sizeof(*ret));
++
++    if (ret != NULL) {
++        memcpy(ret, meth, sizeof(*meth));
++
++        ret->name = OPENSSL_strdup(meth->name);
++        if (ret->name != NULL)
++            return ret;
++
++        OPENSSL_free(ret);
++    }
++
++    RSAerr(RSA_F_RSA_METH_DUP, ERR_R_MALLOC_FAILURE);
++    return NULL;
++}
++
++const char *RSA_meth_get0_name(const RSA_METHOD *meth)
++{
++    return meth->name;
++}
++
++int RSA_meth_set1_name(RSA_METHOD *meth, const char *name)
++{
++    char *tmpname = OPENSSL_strdup(name);
++
++    if (tmpname == NULL) {
++        RSAerr(RSA_F_RSA_METH_SET1_NAME, ERR_R_MALLOC_FAILURE);
++        return 0;
++    }
++
++    OPENSSL_free(meth->name);
++    meth->name = tmpname;
++
++    return 1;
++}
++
++int RSA_meth_get_flags(RSA_METHOD *meth)
++{
++    return meth->flags;
++}
++
++int RSA_meth_set_flags(RSA_METHOD *meth, int flags)
++{
++    meth->flags = flags;
++    return 1;
++}
++
++void *RSA_meth_get0_app_data(const RSA_METHOD *meth)
++{
++    return meth->app_data;
++}
++
++int RSA_meth_set0_app_data(RSA_METHOD *meth, void *app_data)
++{
++    meth->app_data = app_data;
++    return 1;
++}
++
++int (*RSA_meth_get_pub_enc(const RSA_METHOD *meth))
++    (int flen, const unsigned char *from,
++     unsigned char *to, RSA *rsa, int padding)
++{
++    return meth->rsa_pub_enc;
++}
++
++int RSA_meth_set_pub_enc(RSA_METHOD *meth,
++                         int (*pub_enc) (int flen, const unsigned char *from,
++                                         unsigned char *to, RSA *rsa,
++                                         int padding))
++{
++    meth->rsa_pub_enc = pub_enc;
++    return 1;
++}
++
++int (*RSA_meth_get_pub_dec(const RSA_METHOD *meth))
++    (int flen, const unsigned char *from,
++     unsigned char *to, RSA *rsa, int padding)
++{
++    return meth->rsa_pub_dec;
++}
++
++int RSA_meth_set_pub_dec(RSA_METHOD *meth,
++                         int (*pub_dec) (int flen, const unsigned char *from,
++                                         unsigned char *to, RSA *rsa,
++                                         int padding))
++{
++    meth->rsa_pub_dec = pub_dec;
++    return 1;
++}
++
++int (*RSA_meth_get_priv_enc(const RSA_METHOD *meth))
++    (int flen, const unsigned char *from,
++     unsigned char *to, RSA *rsa, int padding)
++{
++    return meth->rsa_priv_enc;
++}
++
++int RSA_meth_set_priv_enc(RSA_METHOD *meth,
++                          int (*priv_enc) (int flen, const unsigned char *from,
++                                           unsigned char *to, RSA *rsa,
++                                           int padding))
++{
++    meth->rsa_priv_enc = priv_enc;
++    return 1;
++}
++
++int (*RSA_meth_get_priv_dec(const RSA_METHOD *meth))
++    (int flen, const unsigned char *from,
++     unsigned char *to, RSA *rsa, int padding)
++{
++    return meth->rsa_priv_dec;
++}
++
++int RSA_meth_set_priv_dec(RSA_METHOD *meth,
++                          int (*priv_dec) (int flen, const unsigned char *from,
++                                           unsigned char *to, RSA *rsa,
++                                           int padding))
++{
++    meth->rsa_priv_dec = priv_dec;
++    return 1;
++}
++
++    /* Can be null */
++int (*RSA_meth_get_mod_exp(const RSA_METHOD *meth))
++    (BIGNUM *r0, const BIGNUM *I, RSA *rsa, BN_CTX *ctx)
++{
++    return meth->rsa_mod_exp;
++}
++
++int RSA_meth_set_mod_exp(RSA_METHOD *meth,
++                         int (*mod_exp) (BIGNUM *r0, const BIGNUM *I, RSA *rsa,
++                                         BN_CTX *ctx))
++{
++    meth->rsa_mod_exp = mod_exp;
++    return 1;
++}
++
++    /* Can be null */
++int (*RSA_meth_get_bn_mod_exp(const RSA_METHOD *meth))
++    (BIGNUM *r, const BIGNUM *a, const BIGNUM *p,
++     const BIGNUM *m, BN_CTX *ctx, BN_MONT_CTX *m_ctx)
++{
++    return meth->bn_mod_exp;
++}
++
++int RSA_meth_set_bn_mod_exp(RSA_METHOD *meth,
++                            int (*bn_mod_exp) (BIGNUM *r,
++                                               const BIGNUM *a,
++                                               const BIGNUM *p,
++                                               const BIGNUM *m,
++                                               BN_CTX *ctx,
++                                               BN_MONT_CTX *m_ctx))
++{
++    meth->bn_mod_exp = bn_mod_exp;
++    return 1;
++}
++
++    /* called at new */
++int (*RSA_meth_get_init(const RSA_METHOD *meth)) (RSA *rsa)
++{
++    return meth->init;
++}
++
++int RSA_meth_set_init(RSA_METHOD *meth, int (*init) (RSA *rsa))
++{
++    meth->init = init;
++    return 1;
++}
++
++    /* called at free */
++int (*RSA_meth_get_finish(const RSA_METHOD *meth)) (RSA *rsa)
++{
++    return meth->finish;
++}
++
++int RSA_meth_set_finish(RSA_METHOD *meth, int (*finish) (RSA *rsa))
++{
++    meth->finish = finish;
++    return 1;
++}
++
++int (*RSA_meth_get_sign(const RSA_METHOD *meth))
++    (int type,
++     const unsigned char *m, unsigned int m_length,
++     unsigned char *sigret, unsigned int *siglen,
++     const RSA *rsa)
++{
++    return meth->rsa_sign;
++}
++
++int RSA_meth_set_sign(RSA_METHOD *meth,
++                      int (*sign) (int type, const unsigned char *m,
++                                   unsigned int m_length,
++                                   unsigned char *sigret, unsigned int *siglen,
++                                   const RSA *rsa))
++{
++    meth->rsa_sign = sign;
++    return 1;
++}
++
++int (*RSA_meth_get_verify(const RSA_METHOD *meth))
++    (int dtype, const unsigned char *m,
++     unsigned int m_length, const unsigned char *sigbuf,
++     unsigned int siglen, const RSA *rsa)
++{
++    return meth->rsa_verify;
++}
++
++int RSA_meth_set_verify(RSA_METHOD *meth,
++                        int (*verify) (int dtype, const unsigned char *m,
++                                       unsigned int m_length,
++                                       const unsigned char *sigbuf,
++                                       unsigned int siglen, const RSA *rsa))
++{
++    meth->rsa_verify = verify;
++    return 1;
++}
++
++int (*RSA_meth_get_keygen(const RSA_METHOD *meth))
++    (RSA *rsa, int bits, BIGNUM *e, BN_GENCB *cb)
++{
++    return meth->rsa_keygen;
++}
++
++int RSA_meth_set_keygen(RSA_METHOD *meth,
++                        int (*keygen) (RSA *rsa, int bits, BIGNUM *e,
++                                       BN_GENCB *cb))
++{
++    meth->rsa_keygen = keygen;
++    return 1;
++}
++
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/rsa/rsa_none.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/rsa/rsa_none.c
+new file mode 100644
+index 0000000..b78756d
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/rsa/rsa_none.c
+@@ -0,0 +1,43 @@
++/*
++ * Copyright 1995-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include "internal/cryptlib.h"
++#include 
++#include 
++
++int RSA_padding_add_none(unsigned char *to, int tlen,
++                         const unsigned char *from, int flen)
++{
++    if (flen > tlen) {
++        RSAerr(RSA_F_RSA_PADDING_ADD_NONE, RSA_R_DATA_TOO_LARGE_FOR_KEY_SIZE);
++        return (0);
++    }
++
++    if (flen < tlen) {
++        RSAerr(RSA_F_RSA_PADDING_ADD_NONE, RSA_R_DATA_TOO_SMALL_FOR_KEY_SIZE);
++        return (0);
++    }
++
++    memcpy(to, from, (unsigned int)flen);
++    return (1);
++}
++
++int RSA_padding_check_none(unsigned char *to, int tlen,
++                           const unsigned char *from, int flen, int num)
++{
++
++    if (flen > tlen) {
++        RSAerr(RSA_F_RSA_PADDING_CHECK_NONE, RSA_R_DATA_TOO_LARGE);
++        return (-1);
++    }
++
++    memset(to, 0, tlen - flen);
++    memcpy(to + tlen - flen, from, flen);
++    return (tlen);
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/rsa/rsa_null.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/rsa/rsa_null.c
+new file mode 100644
+index 0000000..d339494
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/rsa/rsa_null.c
+@@ -0,0 +1,93 @@
++/*
++ * Copyright 1999-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include "internal/cryptlib.h"
++#include 
++#include "rsa_locl.h"
++
++/*
++ * This is a dummy RSA implementation that just returns errors when called.
++ * It is designed to allow some RSA functions to work while stopping those
++ * covered by the RSA patent. That is RSA, encryption, decryption, signing
++ * and verify is not allowed but RSA key generation, key checking and other
++ * operations (like storing RSA keys) are permitted.
++ */
++
++static int RSA_null_public_encrypt(int flen, const unsigned char *from,
++                                   unsigned char *to, RSA *rsa, int padding);
++static int RSA_null_private_encrypt(int flen, const unsigned char *from,
++                                    unsigned char *to, RSA *rsa, int padding);
++static int RSA_null_public_decrypt(int flen, const unsigned char *from,
++                                   unsigned char *to, RSA *rsa, int padding);
++static int RSA_null_private_decrypt(int flen, const unsigned char *from,
++                                    unsigned char *to, RSA *rsa, int padding);
++static int RSA_null_init(RSA *rsa);
++static int RSA_null_finish(RSA *rsa);
++static RSA_METHOD rsa_null_meth = {
++    "Null RSA",
++    RSA_null_public_encrypt,
++    RSA_null_public_decrypt,
++    RSA_null_private_encrypt,
++    RSA_null_private_decrypt,
++    NULL,
++    NULL,
++    RSA_null_init,
++    RSA_null_finish,
++    0,
++    NULL,
++    NULL,
++    NULL,
++    NULL
++};
++
++const RSA_METHOD *RSA_null_method(void)
++{
++    return (&rsa_null_meth);
++}
++
++static int RSA_null_public_encrypt(int flen, const unsigned char *from,
++                                   unsigned char *to, RSA *rsa, int padding)
++{
++    RSAerr(RSA_F_RSA_NULL_PUBLIC_ENCRYPT, RSA_R_RSA_OPERATIONS_NOT_SUPPORTED);
++    return -1;
++}
++
++static int RSA_null_private_encrypt(int flen, const unsigned char *from,
++                                    unsigned char *to, RSA *rsa, int padding)
++{
++    RSAerr(RSA_F_RSA_NULL_PRIVATE_ENCRYPT,
++           RSA_R_RSA_OPERATIONS_NOT_SUPPORTED);
++    return -1;
++}
++
++static int RSA_null_private_decrypt(int flen, const unsigned char *from,
++                                    unsigned char *to, RSA *rsa, int padding)
++{
++    RSAerr(RSA_F_RSA_NULL_PRIVATE_DECRYPT,
++           RSA_R_RSA_OPERATIONS_NOT_SUPPORTED);
++    return -1;
++}
++
++static int RSA_null_public_decrypt(int flen, const unsigned char *from,
++                                   unsigned char *to, RSA *rsa, int padding)
++{
++    RSAerr(RSA_F_RSA_NULL_PUBLIC_DECRYPT, RSA_R_RSA_OPERATIONS_NOT_SUPPORTED);
++    return -1;
++}
++
++static int RSA_null_init(RSA *rsa)
++{
++    return (1);
++}
++
++static int RSA_null_finish(RSA *rsa)
++{
++    return (1);
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/rsa/rsa_oaep.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/rsa/rsa_oaep.c
+new file mode 100644
+index 0000000..868104f
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/rsa/rsa_oaep.c
+@@ -0,0 +1,286 @@
++/*
++ * Copyright 1999-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++/* EME-OAEP as defined in RFC 2437 (PKCS #1 v2.0) */
++
++/*
++ * See Victor Shoup, "OAEP reconsidered," Nov. 2000,  for problems with the security
++ * proof for the original OAEP scheme, which EME-OAEP is based on. A new
++ * proof can be found in E. Fujisaki, T. Okamoto, D. Pointcheval, J. Stern,
++ * "RSA-OEAP is Still Alive!", Dec. 2000, . The new proof has stronger requirements
++ * for the underlying permutation: "partial-one-wayness" instead of
++ * one-wayness.  For the RSA function, this is an equivalent notion.
++ */
++
++#include "internal/constant_time_locl.h"
++
++#include 
++#include "internal/cryptlib.h"
++#include 
++#include 
++#include 
++#include 
++#include "rsa_locl.h"
++
++int RSA_padding_add_PKCS1_OAEP(unsigned char *to, int tlen,
++                               const unsigned char *from, int flen,
++                               const unsigned char *param, int plen)
++{
++    return RSA_padding_add_PKCS1_OAEP_mgf1(to, tlen, from, flen,
++                                           param, plen, NULL, NULL);
++}
++
++int RSA_padding_add_PKCS1_OAEP_mgf1(unsigned char *to, int tlen,
++                                    const unsigned char *from, int flen,
++                                    const unsigned char *param, int plen,
++                                    const EVP_MD *md, const EVP_MD *mgf1md)
++{
++    int i, emlen = tlen - 1;
++    unsigned char *db, *seed;
++    unsigned char *dbmask, seedmask[EVP_MAX_MD_SIZE];
++    int mdlen;
++
++    if (md == NULL)
++        md = EVP_sha1();
++    if (mgf1md == NULL)
++        mgf1md = md;
++
++    mdlen = EVP_MD_size(md);
++
++    if (flen > emlen - 2 * mdlen - 1) {
++        RSAerr(RSA_F_RSA_PADDING_ADD_PKCS1_OAEP_MGF1,
++               RSA_R_DATA_TOO_LARGE_FOR_KEY_SIZE);
++        return 0;
++    }
++
++    if (emlen < 2 * mdlen + 1) {
++        RSAerr(RSA_F_RSA_PADDING_ADD_PKCS1_OAEP_MGF1,
++               RSA_R_KEY_SIZE_TOO_SMALL);
++        return 0;
++    }
++
++    to[0] = 0;
++    seed = to + 1;
++    db = to + mdlen + 1;
++
++    if (!EVP_Digest((void *)param, plen, db, NULL, md, NULL))
++        return 0;
++    memset(db + mdlen, 0, emlen - flen - 2 * mdlen - 1);
++    db[emlen - flen - mdlen - 1] = 0x01;
++    memcpy(db + emlen - flen - mdlen, from, (unsigned int)flen);
++    if (RAND_bytes(seed, mdlen) <= 0)
++        return 0;
++#ifdef PKCS_TESTVECT
++    memcpy(seed,
++           "\xaa\xfd\x12\xf6\x59\xca\xe6\x34\x89\xb4\x79\xe5\x07\x6d\xde\xc2\xf0\x6c\xb5\x8f",
++           20);
++#endif
++
++    dbmask = OPENSSL_malloc(emlen - mdlen);
++    if (dbmask == NULL) {
++        RSAerr(RSA_F_RSA_PADDING_ADD_PKCS1_OAEP_MGF1, ERR_R_MALLOC_FAILURE);
++        return 0;
++    }
++
++    if (PKCS1_MGF1(dbmask, emlen - mdlen, seed, mdlen, mgf1md) < 0)
++        goto err;
++    for (i = 0; i < emlen - mdlen; i++)
++        db[i] ^= dbmask[i];
++
++    if (PKCS1_MGF1(seedmask, mdlen, db, emlen - mdlen, mgf1md) < 0)
++        goto err;
++    for (i = 0; i < mdlen; i++)
++        seed[i] ^= seedmask[i];
++
++    OPENSSL_free(dbmask);
++    return 1;
++
++ err:
++    OPENSSL_free(dbmask);
++    return 0;
++}
++
++int RSA_padding_check_PKCS1_OAEP(unsigned char *to, int tlen,
++                                 const unsigned char *from, int flen, int num,
++                                 const unsigned char *param, int plen)
++{
++    return RSA_padding_check_PKCS1_OAEP_mgf1(to, tlen, from, flen, num,
++                                             param, plen, NULL, NULL);
++}
++
++int RSA_padding_check_PKCS1_OAEP_mgf1(unsigned char *to, int tlen,
++                                      const unsigned char *from, int flen,
++                                      int num, const unsigned char *param,
++                                      int plen, const EVP_MD *md,
++                                      const EVP_MD *mgf1md)
++{
++    int i, dblen, mlen = -1, one_index = 0, msg_index;
++    unsigned int good, found_one_byte;
++    const unsigned char *maskedseed, *maskeddb;
++    /*
++     * |em| is the encoded message, zero-padded to exactly |num| bytes: em =
++     * Y || maskedSeed || maskedDB
++     */
++    unsigned char *db = NULL, *em = NULL, seed[EVP_MAX_MD_SIZE],
++        phash[EVP_MAX_MD_SIZE];
++    int mdlen;
++
++    if (md == NULL)
++        md = EVP_sha1();
++    if (mgf1md == NULL)
++        mgf1md = md;
++
++    mdlen = EVP_MD_size(md);
++
++    if (tlen <= 0 || flen <= 0)
++        return -1;
++    /*
++     * |num| is the length of the modulus; |flen| is the length of the
++     * encoded message. Therefore, for any |from| that was obtained by
++     * decrypting a ciphertext, we must have |flen| <= |num|. Similarly,
++     * num < 2 * mdlen + 2 must hold for the modulus irrespective of
++     * the ciphertext, see PKCS #1 v2.2, section 7.1.2.
++     * This does not leak any side-channel information.
++     */
++    if (num < flen || num < 2 * mdlen + 2)
++        goto decoding_err;
++
++    dblen = num - mdlen - 1;
++    db = OPENSSL_malloc(dblen);
++    em = OPENSSL_malloc(num);
++    if (db == NULL || em == NULL) {
++        RSAerr(RSA_F_RSA_PADDING_CHECK_PKCS1_OAEP_MGF1, ERR_R_MALLOC_FAILURE);
++        goto cleanup;
++    }
++
++    /*
++     * Always do this zero-padding copy (even when num == flen) to avoid
++     * leaking that information. The copy still leaks some side-channel
++     * information, but it's impossible to have a fixed  memory access
++     * pattern since we can't read out of the bounds of |from|.
++     *
++     * TODO(emilia): Consider porting BN_bn2bin_padded from BoringSSL.
++     */
++    memset(em, 0, num);
++    memcpy(em + num - flen, from, flen);
++
++    /*
++     * The first byte must be zero, however we must not leak if this is
++     * true. See James H. Manger, "A Chosen Ciphertext  Attack on RSA
++     * Optimal Asymmetric Encryption Padding (OAEP) [...]", CRYPTO 2001).
++     */
++    good = constant_time_is_zero(em[0]);
++
++    maskedseed = em + 1;
++    maskeddb = em + 1 + mdlen;
++
++    if (PKCS1_MGF1(seed, mdlen, maskeddb, dblen, mgf1md))
++        goto cleanup;
++    for (i = 0; i < mdlen; i++)
++        seed[i] ^= maskedseed[i];
++
++    if (PKCS1_MGF1(db, dblen, seed, mdlen, mgf1md))
++        goto cleanup;
++    for (i = 0; i < dblen; i++)
++        db[i] ^= maskeddb[i];
++
++    if (!EVP_Digest((void *)param, plen, phash, NULL, md, NULL))
++        goto cleanup;
++
++    good &= constant_time_is_zero(CRYPTO_memcmp(db, phash, mdlen));
++
++    found_one_byte = 0;
++    for (i = mdlen; i < dblen; i++) {
++        /*
++         * Padding consists of a number of 0-bytes, followed by a 1.
++         */
++        unsigned int equals1 = constant_time_eq(db[i], 1);
++        unsigned int equals0 = constant_time_is_zero(db[i]);
++        one_index = constant_time_select_int(~found_one_byte & equals1,
++                                             i, one_index);
++        found_one_byte |= equals1;
++        good &= (found_one_byte | equals0);
++    }
++
++    good &= found_one_byte;
++
++    /*
++     * At this point |good| is zero unless the plaintext was valid,
++     * so plaintext-awareness ensures timing side-channels are no longer a
++     * concern.
++     */
++    if (!good)
++        goto decoding_err;
++
++    msg_index = one_index + 1;
++    mlen = dblen - msg_index;
++
++    if (tlen < mlen) {
++        RSAerr(RSA_F_RSA_PADDING_CHECK_PKCS1_OAEP_MGF1, RSA_R_DATA_TOO_LARGE);
++        mlen = -1;
++    } else {
++        memcpy(to, db + msg_index, mlen);
++        goto cleanup;
++    }
++
++ decoding_err:
++    /*
++     * To avoid chosen ciphertext attacks, the error message should not
++     * reveal which kind of decoding error happened.
++     */
++    RSAerr(RSA_F_RSA_PADDING_CHECK_PKCS1_OAEP_MGF1,
++           RSA_R_OAEP_DECODING_ERROR);
++ cleanup:
++    OPENSSL_free(db);
++    OPENSSL_free(em);
++    return mlen;
++}
++
++int PKCS1_MGF1(unsigned char *mask, long len,
++               const unsigned char *seed, long seedlen, const EVP_MD *dgst)
++{
++    long i, outlen = 0;
++    unsigned char cnt[4];
++    EVP_MD_CTX *c = EVP_MD_CTX_new();
++    unsigned char md[EVP_MAX_MD_SIZE];
++    int mdlen;
++    int rv = -1;
++
++    if (c == NULL)
++        goto err;
++    mdlen = EVP_MD_size(dgst);
++    if (mdlen < 0)
++        goto err;
++    for (i = 0; outlen < len; i++) {
++        cnt[0] = (unsigned char)((i >> 24) & 255);
++        cnt[1] = (unsigned char)((i >> 16) & 255);
++        cnt[2] = (unsigned char)((i >> 8)) & 255;
++        cnt[3] = (unsigned char)(i & 255);
++        if (!EVP_DigestInit_ex(c, dgst, NULL)
++            || !EVP_DigestUpdate(c, seed, seedlen)
++            || !EVP_DigestUpdate(c, cnt, 4))
++            goto err;
++        if (outlen + mdlen <= len) {
++            if (!EVP_DigestFinal_ex(c, mask + outlen, NULL))
++                goto err;
++            outlen += mdlen;
++        } else {
++            if (!EVP_DigestFinal_ex(c, md, NULL))
++                goto err;
++            memcpy(mask + outlen, md, len - outlen);
++            outlen = len;
++        }
++    }
++    rv = 0;
++ err:
++    EVP_MD_CTX_free(c);
++    return rv;
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/rsa/rsa_ossl.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/rsa/rsa_ossl.c
+new file mode 100644
+index 0000000..7826066
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/rsa/rsa_ossl.c
+@@ -0,0 +1,790 @@
++/*
++ * Copyright 1995-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include "internal/cryptlib.h"
++#include "internal/bn_int.h"
++#include "rsa_locl.h"
++
++#ifndef RSA_NULL
++
++static int rsa_ossl_public_encrypt(int flen, const unsigned char *from,
++                                  unsigned char *to, RSA *rsa, int padding);
++static int rsa_ossl_private_encrypt(int flen, const unsigned char *from,
++                                   unsigned char *to, RSA *rsa, int padding);
++static int rsa_ossl_public_decrypt(int flen, const unsigned char *from,
++                                  unsigned char *to, RSA *rsa, int padding);
++static int rsa_ossl_private_decrypt(int flen, const unsigned char *from,
++                                   unsigned char *to, RSA *rsa, int padding);
++static int rsa_ossl_mod_exp(BIGNUM *r0, const BIGNUM *i, RSA *rsa,
++                           BN_CTX *ctx);
++static int rsa_ossl_init(RSA *rsa);
++static int rsa_ossl_finish(RSA *rsa);
++static RSA_METHOD rsa_pkcs1_ossl_meth = {
++    "OpenSSL PKCS#1 RSA (from Eric Young)",
++    rsa_ossl_public_encrypt,
++    rsa_ossl_public_decrypt,     /* signature verification */
++    rsa_ossl_private_encrypt,    /* signing */
++    rsa_ossl_private_decrypt,
++    rsa_ossl_mod_exp,
++    BN_mod_exp_mont,            /* XXX probably we should not use Montgomery
++                                 * if e == 3 */
++    rsa_ossl_init,
++    rsa_ossl_finish,
++    RSA_FLAG_FIPS_METHOD,       /* flags */
++    NULL,
++    0,                          /* rsa_sign */
++    0,                          /* rsa_verify */
++    NULL                        /* rsa_keygen */
++};
++
++const RSA_METHOD *RSA_PKCS1_OpenSSL(void)
++{
++    return &rsa_pkcs1_ossl_meth;
++}
++
++static int rsa_ossl_public_encrypt(int flen, const unsigned char *from,
++                                  unsigned char *to, RSA *rsa, int padding)
++{
++    BIGNUM *f, *ret;
++    int i, j, k, num = 0, r = -1;
++    unsigned char *buf = NULL;
++    BN_CTX *ctx = NULL;
++
++    if (BN_num_bits(rsa->n) > OPENSSL_RSA_MAX_MODULUS_BITS) {
++        RSAerr(RSA_F_RSA_OSSL_PUBLIC_ENCRYPT, RSA_R_MODULUS_TOO_LARGE);
++        return -1;
++    }
++
++    if (BN_ucmp(rsa->n, rsa->e) <= 0) {
++        RSAerr(RSA_F_RSA_OSSL_PUBLIC_ENCRYPT, RSA_R_BAD_E_VALUE);
++        return -1;
++    }
++
++    /* for large moduli, enforce exponent limit */
++    if (BN_num_bits(rsa->n) > OPENSSL_RSA_SMALL_MODULUS_BITS) {
++        if (BN_num_bits(rsa->e) > OPENSSL_RSA_MAX_PUBEXP_BITS) {
++            RSAerr(RSA_F_RSA_OSSL_PUBLIC_ENCRYPT, RSA_R_BAD_E_VALUE);
++            return -1;
++        }
++    }
++
++    if ((ctx = BN_CTX_new()) == NULL)
++        goto err;
++    BN_CTX_start(ctx);
++    f = BN_CTX_get(ctx);
++    ret = BN_CTX_get(ctx);
++    num = BN_num_bytes(rsa->n);
++    buf = OPENSSL_malloc(num);
++    if (f == NULL || ret == NULL || buf == NULL) {
++        RSAerr(RSA_F_RSA_OSSL_PUBLIC_ENCRYPT, ERR_R_MALLOC_FAILURE);
++        goto err;
++    }
++
++    switch (padding) {
++    case RSA_PKCS1_PADDING:
++        i = RSA_padding_add_PKCS1_type_2(buf, num, from, flen);
++        break;
++    case RSA_PKCS1_OAEP_PADDING:
++        i = RSA_padding_add_PKCS1_OAEP(buf, num, from, flen, NULL, 0);
++        break;
++    case RSA_SSLV23_PADDING:
++        i = RSA_padding_add_SSLv23(buf, num, from, flen);
++        break;
++    case RSA_NO_PADDING:
++        i = RSA_padding_add_none(buf, num, from, flen);
++        break;
++    default:
++        RSAerr(RSA_F_RSA_OSSL_PUBLIC_ENCRYPT, RSA_R_UNKNOWN_PADDING_TYPE);
++        goto err;
++    }
++    if (i <= 0)
++        goto err;
++
++    if (BN_bin2bn(buf, num, f) == NULL)
++        goto err;
++
++    if (BN_ucmp(f, rsa->n) >= 0) {
++        /* usually the padding functions would catch this */
++        RSAerr(RSA_F_RSA_OSSL_PUBLIC_ENCRYPT,
++               RSA_R_DATA_TOO_LARGE_FOR_MODULUS);
++        goto err;
++    }
++
++    if (rsa->flags & RSA_FLAG_CACHE_PUBLIC)
++        if (!BN_MONT_CTX_set_locked
++            (&rsa->_method_mod_n, rsa->lock, rsa->n, ctx))
++            goto err;
++
++    if (!rsa->meth->bn_mod_exp(ret, f, rsa->e, rsa->n, ctx,
++                               rsa->_method_mod_n))
++        goto err;
++
++    /*
++     * put in leading 0 bytes if the number is less than the length of the
++     * modulus
++     */
++    j = BN_num_bytes(ret);
++    i = BN_bn2bin(ret, &(to[num - j]));
++    for (k = 0; k < (num - i); k++)
++        to[k] = 0;
++
++    r = num;
++ err:
++    if (ctx != NULL)
++        BN_CTX_end(ctx);
++    BN_CTX_free(ctx);
++    OPENSSL_clear_free(buf, num);
++    return (r);
++}
++
++static BN_BLINDING *rsa_get_blinding(RSA *rsa, int *local, BN_CTX *ctx)
++{
++    BN_BLINDING *ret;
++
++    CRYPTO_THREAD_write_lock(rsa->lock);
++
++    if (rsa->blinding == NULL) {
++        rsa->blinding = RSA_setup_blinding(rsa, ctx);
++    }
++
++    ret = rsa->blinding;
++    if (ret == NULL)
++        goto err;
++
++    if (BN_BLINDING_is_current_thread(ret)) {
++        /* rsa->blinding is ours! */
++
++        *local = 1;
++    } else {
++        /* resort to rsa->mt_blinding instead */
++
++        /*
++         * instructs rsa_blinding_convert(), rsa_blinding_invert() that the
++         * BN_BLINDING is shared, meaning that accesses require locks, and
++         * that the blinding factor must be stored outside the BN_BLINDING
++         */
++        *local = 0;
++
++        if (rsa->mt_blinding == NULL) {
++            rsa->mt_blinding = RSA_setup_blinding(rsa, ctx);
++        }
++        ret = rsa->mt_blinding;
++    }
++
++ err:
++    CRYPTO_THREAD_unlock(rsa->lock);
++    return ret;
++}
++
++static int rsa_blinding_convert(BN_BLINDING *b, BIGNUM *f, BIGNUM *unblind,
++                                BN_CTX *ctx)
++{
++    if (unblind == NULL)
++        /*
++         * Local blinding: store the unblinding factor in BN_BLINDING.
++         */
++        return BN_BLINDING_convert_ex(f, NULL, b, ctx);
++    else {
++        /*
++         * Shared blinding: store the unblinding factor outside BN_BLINDING.
++         */
++        int ret;
++
++        BN_BLINDING_lock(b);
++        ret = BN_BLINDING_convert_ex(f, unblind, b, ctx);
++        BN_BLINDING_unlock(b);
++
++        return ret;
++    }
++}
++
++static int rsa_blinding_invert(BN_BLINDING *b, BIGNUM *f, BIGNUM *unblind,
++                               BN_CTX *ctx)
++{
++    /*
++     * For local blinding, unblind is set to NULL, and BN_BLINDING_invert_ex
++     * will use the unblinding factor stored in BN_BLINDING. If BN_BLINDING
++     * is shared between threads, unblind must be non-null:
++     * BN_BLINDING_invert_ex will then use the local unblinding factor, and
++     * will only read the modulus from BN_BLINDING. In both cases it's safe
++     * to access the blinding without a lock.
++     */
++    return BN_BLINDING_invert_ex(f, unblind, b, ctx);
++}
++
++/* signing */
++static int rsa_ossl_private_encrypt(int flen, const unsigned char *from,
++                                   unsigned char *to, RSA *rsa, int padding)
++{
++    BIGNUM *f, *ret, *res;
++    int i, j, k, num = 0, r = -1;
++    unsigned char *buf = NULL;
++    BN_CTX *ctx = NULL;
++    int local_blinding = 0;
++    /*
++     * Used only if the blinding structure is shared. A non-NULL unblind
++     * instructs rsa_blinding_convert() and rsa_blinding_invert() to store
++     * the unblinding factor outside the blinding structure.
++     */
++    BIGNUM *unblind = NULL;
++    BN_BLINDING *blinding = NULL;
++
++    if ((ctx = BN_CTX_new()) == NULL)
++        goto err;
++    BN_CTX_start(ctx);
++    f = BN_CTX_get(ctx);
++    ret = BN_CTX_get(ctx);
++    num = BN_num_bytes(rsa->n);
++    buf = OPENSSL_malloc(num);
++    if (f == NULL || ret == NULL || buf == NULL) {
++        RSAerr(RSA_F_RSA_OSSL_PRIVATE_ENCRYPT, ERR_R_MALLOC_FAILURE);
++        goto err;
++    }
++
++    switch (padding) {
++    case RSA_PKCS1_PADDING:
++        i = RSA_padding_add_PKCS1_type_1(buf, num, from, flen);
++        break;
++    case RSA_X931_PADDING:
++        i = RSA_padding_add_X931(buf, num, from, flen);
++        break;
++    case RSA_NO_PADDING:
++        i = RSA_padding_add_none(buf, num, from, flen);
++        break;
++    case RSA_SSLV23_PADDING:
++    default:
++        RSAerr(RSA_F_RSA_OSSL_PRIVATE_ENCRYPT, RSA_R_UNKNOWN_PADDING_TYPE);
++        goto err;
++    }
++    if (i <= 0)
++        goto err;
++
++    if (BN_bin2bn(buf, num, f) == NULL)
++        goto err;
++
++    if (BN_ucmp(f, rsa->n) >= 0) {
++        /* usually the padding functions would catch this */
++        RSAerr(RSA_F_RSA_OSSL_PRIVATE_ENCRYPT,
++               RSA_R_DATA_TOO_LARGE_FOR_MODULUS);
++        goto err;
++    }
++
++    if (!(rsa->flags & RSA_FLAG_NO_BLINDING)) {
++        blinding = rsa_get_blinding(rsa, &local_blinding, ctx);
++        if (blinding == NULL) {
++            RSAerr(RSA_F_RSA_OSSL_PRIVATE_ENCRYPT, ERR_R_INTERNAL_ERROR);
++            goto err;
++        }
++    }
++
++    if (blinding != NULL) {
++        if (!local_blinding && ((unblind = BN_CTX_get(ctx)) == NULL)) {
++            RSAerr(RSA_F_RSA_OSSL_PRIVATE_ENCRYPT, ERR_R_MALLOC_FAILURE);
++            goto err;
++        }
++        if (!rsa_blinding_convert(blinding, f, unblind, ctx))
++            goto err;
++    }
++
++    if ((rsa->flags & RSA_FLAG_EXT_PKEY) ||
++        ((rsa->p != NULL) &&
++         (rsa->q != NULL) &&
++         (rsa->dmp1 != NULL) && (rsa->dmq1 != NULL) && (rsa->iqmp != NULL))) {
++        if (!rsa->meth->rsa_mod_exp(ret, f, rsa, ctx))
++            goto err;
++    } else {
++        BIGNUM *d = BN_new();
++        if (d == NULL) {
++            RSAerr(RSA_F_RSA_OSSL_PRIVATE_ENCRYPT, ERR_R_MALLOC_FAILURE);
++            goto err;
++        }
++        BN_with_flags(d, rsa->d, BN_FLG_CONSTTIME);
++
++        if (rsa->flags & RSA_FLAG_CACHE_PUBLIC)
++            if (!BN_MONT_CTX_set_locked
++                (&rsa->_method_mod_n, rsa->lock, rsa->n, ctx)) {
++                BN_free(d);
++                goto err;
++            }
++
++        if (!rsa->meth->bn_mod_exp(ret, f, d, rsa->n, ctx,
++                                   rsa->_method_mod_n)) {
++            BN_free(d);
++            goto err;
++        }
++        /* We MUST free d before any further use of rsa->d */
++        BN_free(d);
++    }
++
++    if (blinding)
++        if (!rsa_blinding_invert(blinding, ret, unblind, ctx))
++            goto err;
++
++    if (padding == RSA_X931_PADDING) {
++        BN_sub(f, rsa->n, ret);
++        if (BN_cmp(ret, f) > 0)
++            res = f;
++        else
++            res = ret;
++    } else
++        res = ret;
++
++    /*
++     * put in leading 0 bytes if the number is less than the length of the
++     * modulus
++     */
++    j = BN_num_bytes(res);
++    i = BN_bn2bin(res, &(to[num - j]));
++    for (k = 0; k < (num - i); k++)
++        to[k] = 0;
++
++    r = num;
++ err:
++    if (ctx != NULL)
++        BN_CTX_end(ctx);
++    BN_CTX_free(ctx);
++    OPENSSL_clear_free(buf, num);
++    return (r);
++}
++
++static int rsa_ossl_private_decrypt(int flen, const unsigned char *from,
++                                   unsigned char *to, RSA *rsa, int padding)
++{
++    BIGNUM *f, *ret;
++    int j, num = 0, r = -1;
++    unsigned char *p;
++    unsigned char *buf = NULL;
++    BN_CTX *ctx = NULL;
++    int local_blinding = 0;
++    /*
++     * Used only if the blinding structure is shared. A non-NULL unblind
++     * instructs rsa_blinding_convert() and rsa_blinding_invert() to store
++     * the unblinding factor outside the blinding structure.
++     */
++    BIGNUM *unblind = NULL;
++    BN_BLINDING *blinding = NULL;
++
++    if ((ctx = BN_CTX_new()) == NULL)
++        goto err;
++    BN_CTX_start(ctx);
++    f = BN_CTX_get(ctx);
++    ret = BN_CTX_get(ctx);
++    num = BN_num_bytes(rsa->n);
++    buf = OPENSSL_malloc(num);
++    if (f == NULL || ret == NULL || buf == NULL) {
++        RSAerr(RSA_F_RSA_OSSL_PRIVATE_DECRYPT, ERR_R_MALLOC_FAILURE);
++        goto err;
++    }
++
++    /*
++     * This check was for equality but PGP does evil things and chops off the
++     * top '0' bytes
++     */
++    if (flen > num) {
++        RSAerr(RSA_F_RSA_OSSL_PRIVATE_DECRYPT,
++               RSA_R_DATA_GREATER_THAN_MOD_LEN);
++        goto err;
++    }
++
++    /* make data into a big number */
++    if (BN_bin2bn(from, (int)flen, f) == NULL)
++        goto err;
++
++    if (BN_ucmp(f, rsa->n) >= 0) {
++        RSAerr(RSA_F_RSA_OSSL_PRIVATE_DECRYPT,
++               RSA_R_DATA_TOO_LARGE_FOR_MODULUS);
++        goto err;
++    }
++
++    if (!(rsa->flags & RSA_FLAG_NO_BLINDING)) {
++        blinding = rsa_get_blinding(rsa, &local_blinding, ctx);
++        if (blinding == NULL) {
++            RSAerr(RSA_F_RSA_OSSL_PRIVATE_DECRYPT, ERR_R_INTERNAL_ERROR);
++            goto err;
++        }
++    }
++
++    if (blinding != NULL) {
++        if (!local_blinding && ((unblind = BN_CTX_get(ctx)) == NULL)) {
++            RSAerr(RSA_F_RSA_OSSL_PRIVATE_DECRYPT, ERR_R_MALLOC_FAILURE);
++            goto err;
++        }
++        if (!rsa_blinding_convert(blinding, f, unblind, ctx))
++            goto err;
++    }
++
++    /* do the decrypt */
++    if ((rsa->flags & RSA_FLAG_EXT_PKEY) ||
++        ((rsa->p != NULL) &&
++         (rsa->q != NULL) &&
++         (rsa->dmp1 != NULL) && (rsa->dmq1 != NULL) && (rsa->iqmp != NULL))) {
++        if (!rsa->meth->rsa_mod_exp(ret, f, rsa, ctx))
++            goto err;
++    } else {
++        BIGNUM *d = BN_new();
++        if (d == NULL) {
++            RSAerr(RSA_F_RSA_OSSL_PRIVATE_DECRYPT, ERR_R_MALLOC_FAILURE);
++            goto err;
++        }
++        BN_with_flags(d, rsa->d, BN_FLG_CONSTTIME);
++
++        if (rsa->flags & RSA_FLAG_CACHE_PUBLIC)
++            if (!BN_MONT_CTX_set_locked
++                (&rsa->_method_mod_n, rsa->lock, rsa->n, ctx)) {
++                BN_free(d);
++                goto err;
++            }
++        if (!rsa->meth->bn_mod_exp(ret, f, d, rsa->n, ctx,
++                                   rsa->_method_mod_n)) {
++            BN_free(d);
++            goto err;
++        }
++        /* We MUST free d before any further use of rsa->d */
++        BN_free(d);
++    }
++
++    if (blinding)
++        if (!rsa_blinding_invert(blinding, ret, unblind, ctx))
++            goto err;
++
++    p = buf;
++    j = BN_bn2bin(ret, p);      /* j is only used with no-padding mode */
++
++    switch (padding) {
++    case RSA_PKCS1_PADDING:
++        r = RSA_padding_check_PKCS1_type_2(to, num, buf, j, num);
++        break;
++    case RSA_PKCS1_OAEP_PADDING:
++        r = RSA_padding_check_PKCS1_OAEP(to, num, buf, j, num, NULL, 0);
++        break;
++    case RSA_SSLV23_PADDING:
++        r = RSA_padding_check_SSLv23(to, num, buf, j, num);
++        break;
++    case RSA_NO_PADDING:
++        r = RSA_padding_check_none(to, num, buf, j, num);
++        break;
++    default:
++        RSAerr(RSA_F_RSA_OSSL_PRIVATE_DECRYPT, RSA_R_UNKNOWN_PADDING_TYPE);
++        goto err;
++    }
++    if (r < 0)
++        RSAerr(RSA_F_RSA_OSSL_PRIVATE_DECRYPT, RSA_R_PADDING_CHECK_FAILED);
++
++ err:
++    if (ctx != NULL)
++        BN_CTX_end(ctx);
++    BN_CTX_free(ctx);
++    OPENSSL_clear_free(buf, num);
++    return (r);
++}
++
++/* signature verification */
++static int rsa_ossl_public_decrypt(int flen, const unsigned char *from,
++                                  unsigned char *to, RSA *rsa, int padding)
++{
++    BIGNUM *f, *ret;
++    int i, num = 0, r = -1;
++    unsigned char *p;
++    unsigned char *buf = NULL;
++    BN_CTX *ctx = NULL;
++
++    if (BN_num_bits(rsa->n) > OPENSSL_RSA_MAX_MODULUS_BITS) {
++        RSAerr(RSA_F_RSA_OSSL_PUBLIC_DECRYPT, RSA_R_MODULUS_TOO_LARGE);
++        return -1;
++    }
++
++    if (BN_ucmp(rsa->n, rsa->e) <= 0) {
++        RSAerr(RSA_F_RSA_OSSL_PUBLIC_DECRYPT, RSA_R_BAD_E_VALUE);
++        return -1;
++    }
++
++    /* for large moduli, enforce exponent limit */
++    if (BN_num_bits(rsa->n) > OPENSSL_RSA_SMALL_MODULUS_BITS) {
++        if (BN_num_bits(rsa->e) > OPENSSL_RSA_MAX_PUBEXP_BITS) {
++            RSAerr(RSA_F_RSA_OSSL_PUBLIC_DECRYPT, RSA_R_BAD_E_VALUE);
++            return -1;
++        }
++    }
++
++    if ((ctx = BN_CTX_new()) == NULL)
++        goto err;
++    BN_CTX_start(ctx);
++    f = BN_CTX_get(ctx);
++    ret = BN_CTX_get(ctx);
++    num = BN_num_bytes(rsa->n);
++    buf = OPENSSL_malloc(num);
++    if (f == NULL || ret == NULL || buf == NULL) {
++        RSAerr(RSA_F_RSA_OSSL_PUBLIC_DECRYPT, ERR_R_MALLOC_FAILURE);
++        goto err;
++    }
++
++    /*
++     * This check was for equality but PGP does evil things and chops off the
++     * top '0' bytes
++     */
++    if (flen > num) {
++        RSAerr(RSA_F_RSA_OSSL_PUBLIC_DECRYPT, RSA_R_DATA_GREATER_THAN_MOD_LEN);
++        goto err;
++    }
++
++    if (BN_bin2bn(from, flen, f) == NULL)
++        goto err;
++
++    if (BN_ucmp(f, rsa->n) >= 0) {
++        RSAerr(RSA_F_RSA_OSSL_PUBLIC_DECRYPT,
++               RSA_R_DATA_TOO_LARGE_FOR_MODULUS);
++        goto err;
++    }
++
++    if (rsa->flags & RSA_FLAG_CACHE_PUBLIC)
++        if (!BN_MONT_CTX_set_locked
++            (&rsa->_method_mod_n, rsa->lock, rsa->n, ctx))
++            goto err;
++
++    if (!rsa->meth->bn_mod_exp(ret, f, rsa->e, rsa->n, ctx,
++                               rsa->_method_mod_n))
++        goto err;
++
++    if ((padding == RSA_X931_PADDING) && ((bn_get_words(ret)[0] & 0xf) != 12))
++        if (!BN_sub(ret, rsa->n, ret))
++            goto err;
++
++    p = buf;
++    i = BN_bn2bin(ret, p);
++
++    switch (padding) {
++    case RSA_PKCS1_PADDING:
++        r = RSA_padding_check_PKCS1_type_1(to, num, buf, i, num);
++        break;
++    case RSA_X931_PADDING:
++        r = RSA_padding_check_X931(to, num, buf, i, num);
++        break;
++    case RSA_NO_PADDING:
++        r = RSA_padding_check_none(to, num, buf, i, num);
++        break;
++    default:
++        RSAerr(RSA_F_RSA_OSSL_PUBLIC_DECRYPT, RSA_R_UNKNOWN_PADDING_TYPE);
++        goto err;
++    }
++    if (r < 0)
++        RSAerr(RSA_F_RSA_OSSL_PUBLIC_DECRYPT, RSA_R_PADDING_CHECK_FAILED);
++
++ err:
++    if (ctx != NULL)
++        BN_CTX_end(ctx);
++    BN_CTX_free(ctx);
++    OPENSSL_clear_free(buf, num);
++    return (r);
++}
++
++static int rsa_ossl_mod_exp(BIGNUM *r0, const BIGNUM *I, RSA *rsa, BN_CTX *ctx)
++{
++    BIGNUM *r1, *m1, *vrfy;
++    int ret = 0;
++
++    BN_CTX_start(ctx);
++
++    r1 = BN_CTX_get(ctx);
++    m1 = BN_CTX_get(ctx);
++    vrfy = BN_CTX_get(ctx);
++
++    {
++        BIGNUM *p = BN_new(), *q = BN_new();
++
++        /*
++         * Make sure BN_mod_inverse in Montgomery initialization uses the
++         * BN_FLG_CONSTTIME flag
++         */
++        if (p == NULL || q == NULL) {
++            BN_free(p);
++            BN_free(q);
++            goto err;
++        }
++        BN_with_flags(p, rsa->p, BN_FLG_CONSTTIME);
++        BN_with_flags(q, rsa->q, BN_FLG_CONSTTIME);
++
++        if (rsa->flags & RSA_FLAG_CACHE_PRIVATE) {
++            if (!BN_MONT_CTX_set_locked
++                (&rsa->_method_mod_p, rsa->lock, p, ctx)
++                || !BN_MONT_CTX_set_locked(&rsa->_method_mod_q,
++                                           rsa->lock, q, ctx)) {
++                BN_free(p);
++                BN_free(q);
++                goto err;
++            }
++        }
++        /*
++         * We MUST free p and q before any further use of rsa->p and rsa->q
++         */
++        BN_free(p);
++        BN_free(q);
++    }
++
++    if (rsa->flags & RSA_FLAG_CACHE_PUBLIC)
++        if (!BN_MONT_CTX_set_locked
++            (&rsa->_method_mod_n, rsa->lock, rsa->n, ctx))
++            goto err;
++
++    /* compute I mod q */
++    {
++        BIGNUM *c = BN_new();
++        if (c == NULL)
++            goto err;
++        BN_with_flags(c, I, BN_FLG_CONSTTIME);
++
++        if (!BN_mod(r1, c, rsa->q, ctx)) {
++            BN_free(c);
++            goto err;
++        }
++
++        {
++            BIGNUM *dmq1 = BN_new();
++            if (dmq1 == NULL) {
++                BN_free(c);
++                goto err;
++            }
++            BN_with_flags(dmq1, rsa->dmq1, BN_FLG_CONSTTIME);
++
++            /* compute r1^dmq1 mod q */
++            if (!rsa->meth->bn_mod_exp(m1, r1, dmq1, rsa->q, ctx,
++                rsa->_method_mod_q)) {
++                BN_free(c);
++                BN_free(dmq1);
++                goto err;
++            }
++            /* We MUST free dmq1 before any further use of rsa->dmq1 */
++            BN_free(dmq1);
++        }
++
++        /* compute I mod p */
++        if (!BN_mod(r1, c, rsa->p, ctx)) {
++            BN_free(c);
++            goto err;
++        }
++        /* We MUST free c before any further use of I */
++        BN_free(c);
++    }
++
++    {
++        BIGNUM *dmp1 = BN_new();
++        if (dmp1 == NULL)
++            goto err;
++        BN_with_flags(dmp1, rsa->dmp1, BN_FLG_CONSTTIME);
++
++        /* compute r1^dmp1 mod p */
++        if (!rsa->meth->bn_mod_exp(r0, r1, dmp1, rsa->p, ctx,
++                                   rsa->_method_mod_p)) {
++            BN_free(dmp1);
++            goto err;
++        }
++        /* We MUST free dmp1 before any further use of rsa->dmp1 */
++        BN_free(dmp1);
++    }
++
++    if (!BN_sub(r0, r0, m1))
++        goto err;
++    /*
++     * This will help stop the size of r0 increasing, which does affect the
++     * multiply if it optimised for a power of 2 size
++     */
++    if (BN_is_negative(r0))
++        if (!BN_add(r0, r0, rsa->p))
++            goto err;
++
++    if (!BN_mul(r1, r0, rsa->iqmp, ctx))
++        goto err;
++
++    {
++        BIGNUM *pr1 = BN_new();
++        if (pr1 == NULL)
++            goto err;
++        BN_with_flags(pr1, r1, BN_FLG_CONSTTIME);
++
++        if (!BN_mod(r0, pr1, rsa->p, ctx)) {
++            BN_free(pr1);
++            goto err;
++        }
++        /* We MUST free pr1 before any further use of r1 */
++        BN_free(pr1);
++    }
++
++    /*
++     * If p < q it is occasionally possible for the correction of adding 'p'
++     * if r0 is negative above to leave the result still negative. This can
++     * break the private key operations: the following second correction
++     * should *always* correct this rare occurrence. This will *never* happen
++     * with OpenSSL generated keys because they ensure p > q [steve]
++     */
++    if (BN_is_negative(r0))
++        if (!BN_add(r0, r0, rsa->p))
++            goto err;
++    if (!BN_mul(r1, r0, rsa->q, ctx))
++        goto err;
++    if (!BN_add(r0, r1, m1))
++        goto err;
++
++    if (rsa->e && rsa->n) {
++        if (!rsa->meth->bn_mod_exp(vrfy, r0, rsa->e, rsa->n, ctx,
++                                   rsa->_method_mod_n))
++            goto err;
++        /*
++         * If 'I' was greater than (or equal to) rsa->n, the operation will
++         * be equivalent to using 'I mod n'. However, the result of the
++         * verify will *always* be less than 'n' so we don't check for
++         * absolute equality, just congruency.
++         */
++        if (!BN_sub(vrfy, vrfy, I))
++            goto err;
++        if (!BN_mod(vrfy, vrfy, rsa->n, ctx))
++            goto err;
++        if (BN_is_negative(vrfy))
++            if (!BN_add(vrfy, vrfy, rsa->n))
++                goto err;
++        if (!BN_is_zero(vrfy)) {
++            /*
++             * 'I' and 'vrfy' aren't congruent mod n. Don't leak
++             * miscalculated CRT output, just do a raw (slower) mod_exp and
++             * return that instead.
++             */
++
++            BIGNUM *d = BN_new();
++            if (d == NULL)
++                goto err;
++            BN_with_flags(d, rsa->d, BN_FLG_CONSTTIME);
++
++            if (!rsa->meth->bn_mod_exp(r0, I, d, rsa->n, ctx,
++                                       rsa->_method_mod_n)) {
++                BN_free(d);
++                goto err;
++            }
++            /* We MUST free d before any further use of rsa->d */
++            BN_free(d);
++        }
++    }
++    ret = 1;
++ err:
++    BN_CTX_end(ctx);
++    return (ret);
++}
++
++static int rsa_ossl_init(RSA *rsa)
++{
++    rsa->flags |= RSA_FLAG_CACHE_PUBLIC | RSA_FLAG_CACHE_PRIVATE;
++    return (1);
++}
++
++static int rsa_ossl_finish(RSA *rsa)
++{
++    BN_MONT_CTX_free(rsa->_method_mod_n);
++    BN_MONT_CTX_free(rsa->_method_mod_p);
++    BN_MONT_CTX_free(rsa->_method_mod_q);
++    return (1);
++}
++
++#endif
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/rsa/rsa_pk1.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/rsa/rsa_pk1.c
+new file mode 100644
+index 0000000..efb16a0
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/rsa/rsa_pk1.c
+@@ -0,0 +1,245 @@
++/*
++ * Copyright 1995-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include "internal/constant_time_locl.h"
++
++#include 
++#include "internal/cryptlib.h"
++#include 
++#include 
++#include 
++
++int RSA_padding_add_PKCS1_type_1(unsigned char *to, int tlen,
++                                 const unsigned char *from, int flen)
++{
++    int j;
++    unsigned char *p;
++
++    if (flen > (tlen - RSA_PKCS1_PADDING_SIZE)) {
++        RSAerr(RSA_F_RSA_PADDING_ADD_PKCS1_TYPE_1,
++               RSA_R_DATA_TOO_LARGE_FOR_KEY_SIZE);
++        return (0);
++    }
++
++    p = (unsigned char *)to;
++
++    *(p++) = 0;
++    *(p++) = 1;                 /* Private Key BT (Block Type) */
++
++    /* pad out with 0xff data */
++    j = tlen - 3 - flen;
++    memset(p, 0xff, j);
++    p += j;
++    *(p++) = '\0';
++    memcpy(p, from, (unsigned int)flen);
++    return (1);
++}
++
++int RSA_padding_check_PKCS1_type_1(unsigned char *to, int tlen,
++                                   const unsigned char *from, int flen,
++                                   int num)
++{
++    int i, j;
++    const unsigned char *p;
++
++    p = from;
++
++    /*
++     * The format is
++     * 00 || 01 || PS || 00 || D
++     * PS - padding string, at least 8 bytes of FF
++     * D  - data.
++     */
++
++    if (num < 11)
++        return -1;
++
++    /* Accept inputs with and without the leading 0-byte. */
++    if (num == flen) {
++        if ((*p++) != 0x00) {
++            RSAerr(RSA_F_RSA_PADDING_CHECK_PKCS1_TYPE_1,
++                   RSA_R_INVALID_PADDING);
++            return -1;
++        }
++        flen--;
++    }
++
++    if ((num != (flen + 1)) || (*(p++) != 0x01)) {
++        RSAerr(RSA_F_RSA_PADDING_CHECK_PKCS1_TYPE_1,
++               RSA_R_BLOCK_TYPE_IS_NOT_01);
++        return (-1);
++    }
++
++    /* scan over padding data */
++    j = flen - 1;               /* one for type. */
++    for (i = 0; i < j; i++) {
++        if (*p != 0xff) {       /* should decrypt to 0xff */
++            if (*p == 0) {
++                p++;
++                break;
++            } else {
++                RSAerr(RSA_F_RSA_PADDING_CHECK_PKCS1_TYPE_1,
++                       RSA_R_BAD_FIXED_HEADER_DECRYPT);
++                return (-1);
++            }
++        }
++        p++;
++    }
++
++    if (i == j) {
++        RSAerr(RSA_F_RSA_PADDING_CHECK_PKCS1_TYPE_1,
++               RSA_R_NULL_BEFORE_BLOCK_MISSING);
++        return (-1);
++    }
++
++    if (i < 8) {
++        RSAerr(RSA_F_RSA_PADDING_CHECK_PKCS1_TYPE_1,
++               RSA_R_BAD_PAD_BYTE_COUNT);
++        return (-1);
++    }
++    i++;                        /* Skip over the '\0' */
++    j -= i;
++    if (j > tlen) {
++        RSAerr(RSA_F_RSA_PADDING_CHECK_PKCS1_TYPE_1, RSA_R_DATA_TOO_LARGE);
++        return (-1);
++    }
++    memcpy(to, p, (unsigned int)j);
++
++    return (j);
++}
++
++int RSA_padding_add_PKCS1_type_2(unsigned char *to, int tlen,
++                                 const unsigned char *from, int flen)
++{
++    int i, j;
++    unsigned char *p;
++
++    if (flen > (tlen - 11)) {
++        RSAerr(RSA_F_RSA_PADDING_ADD_PKCS1_TYPE_2,
++               RSA_R_DATA_TOO_LARGE_FOR_KEY_SIZE);
++        return (0);
++    }
++
++    p = (unsigned char *)to;
++
++    *(p++) = 0;
++    *(p++) = 2;                 /* Public Key BT (Block Type) */
++
++    /* pad out with non-zero random data */
++    j = tlen - 3 - flen;
++
++    if (RAND_bytes(p, j) <= 0)
++        return (0);
++    for (i = 0; i < j; i++) {
++        if (*p == '\0')
++            do {
++                if (RAND_bytes(p, 1) <= 0)
++                    return (0);
++            } while (*p == '\0');
++        p++;
++    }
++
++    *(p++) = '\0';
++
++    memcpy(p, from, (unsigned int)flen);
++    return (1);
++}
++
++int RSA_padding_check_PKCS1_type_2(unsigned char *to, int tlen,
++                                   const unsigned char *from, int flen,
++                                   int num)
++{
++    int i;
++    /* |em| is the encoded message, zero-padded to exactly |num| bytes */
++    unsigned char *em = NULL;
++    unsigned int good, found_zero_byte;
++    int zero_index = 0, msg_index, mlen = -1;
++
++    if (tlen < 0 || flen < 0)
++        return -1;
++
++    /*
++     * PKCS#1 v1.5 decryption. See "PKCS #1 v2.2: RSA Cryptography Standard",
++     * section 7.2.2.
++     */
++
++    if (flen > num)
++        goto err;
++
++    if (num < 11)
++        goto err;
++
++    em = OPENSSL_zalloc(num);
++    if (em == NULL) {
++        RSAerr(RSA_F_RSA_PADDING_CHECK_PKCS1_TYPE_2, ERR_R_MALLOC_FAILURE);
++        return -1;
++    }
++    /*
++     * Always do this zero-padding copy (even when num == flen) to avoid
++     * leaking that information. The copy still leaks some side-channel
++     * information, but it's impossible to have a fixed memory access
++     * pattern since we can't read out of the bounds of |from|.
++     *
++     * TODO(emilia): Consider porting BN_bn2bin_padded from BoringSSL.
++     */
++    memcpy(em + num - flen, from, flen);
++
++    good = constant_time_is_zero(em[0]);
++    good &= constant_time_eq(em[1], 2);
++
++    found_zero_byte = 0;
++    for (i = 2; i < num; i++) {
++        unsigned int equals0 = constant_time_is_zero(em[i]);
++        zero_index =
++            constant_time_select_int(~found_zero_byte & equals0, i,
++                                     zero_index);
++        found_zero_byte |= equals0;
++    }
++
++    /*
++     * PS must be at least 8 bytes long, and it starts two bytes into |em|.
++     * If we never found a 0-byte, then |zero_index| is 0 and the check
++     * also fails.
++     */
++    good &= constant_time_ge((unsigned int)(zero_index), 2 + 8);
++
++    /*
++     * Skip the zero byte. This is incorrect if we never found a zero-byte
++     * but in this case we also do not copy the message out.
++     */
++    msg_index = zero_index + 1;
++    mlen = num - msg_index;
++
++    /*
++     * For good measure, do this check in constant time as well; it could
++     * leak something if |tlen| was assuming valid padding.
++     */
++    good &= constant_time_ge((unsigned int)(tlen), (unsigned int)(mlen));
++
++    /*
++     * We can't continue in constant-time because we need to copy the result
++     * and we cannot fake its length. This unavoidably leaks timing
++     * information at the API boundary.
++     * TODO(emilia): this could be addressed at the call site,
++     * see BoringSSL commit 0aa0767340baf925bda4804882aab0cb974b2d26.
++     */
++    if (!good) {
++        mlen = -1;
++        goto err;
++    }
++
++    memcpy(to, em + msg_index, mlen);
++
++ err:
++    OPENSSL_free(em);
++    if (mlen == -1)
++        RSAerr(RSA_F_RSA_PADDING_CHECK_PKCS1_TYPE_2,
++               RSA_R_PKCS_DECODING_ERROR);
++    return mlen;
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/rsa/rsa_pmeth.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/rsa/rsa_pmeth.c
+new file mode 100644
+index 0000000..db4fb0f
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/rsa/rsa_pmeth.c
+@@ -0,0 +1,673 @@
++/*
++ * Copyright 2006-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include "internal/cryptlib.h"
++#include 
++#include 
++#include 
++#include 
++#include 
++#include 
++#include 
++#include "internal/evp_int.h"
++#include "rsa_locl.h"
++
++/* RSA pkey context structure */
++
++typedef struct {
++    /* Key gen parameters */
++    int nbits;
++    BIGNUM *pub_exp;
++    /* Keygen callback info */
++    int gentmp[2];
++    /* RSA padding mode */
++    int pad_mode;
++    /* message digest */
++    const EVP_MD *md;
++    /* message digest for MGF1 */
++    const EVP_MD *mgf1md;
++    /* PSS salt length */
++    int saltlen;
++    /* Temp buffer */
++    unsigned char *tbuf;
++    /* OAEP label */
++    unsigned char *oaep_label;
++    size_t oaep_labellen;
++} RSA_PKEY_CTX;
++
++static int pkey_rsa_init(EVP_PKEY_CTX *ctx)
++{
++    RSA_PKEY_CTX *rctx;
++    rctx = OPENSSL_zalloc(sizeof(*rctx));
++    if (rctx == NULL)
++        return 0;
++    rctx->nbits = 1024;
++    rctx->pad_mode = RSA_PKCS1_PADDING;
++    rctx->saltlen = -2;
++    ctx->data = rctx;
++    ctx->keygen_info = rctx->gentmp;
++    ctx->keygen_info_count = 2;
++
++    return 1;
++}
++
++static int pkey_rsa_copy(EVP_PKEY_CTX *dst, EVP_PKEY_CTX *src)
++{
++    RSA_PKEY_CTX *dctx, *sctx;
++    if (!pkey_rsa_init(dst))
++        return 0;
++    sctx = src->data;
++    dctx = dst->data;
++    dctx->nbits = sctx->nbits;
++    if (sctx->pub_exp) {
++        dctx->pub_exp = BN_dup(sctx->pub_exp);
++        if (!dctx->pub_exp)
++            return 0;
++    }
++    dctx->pad_mode = sctx->pad_mode;
++    dctx->md = sctx->md;
++    dctx->mgf1md = sctx->mgf1md;
++    if (sctx->oaep_label) {
++        OPENSSL_free(dctx->oaep_label);
++        dctx->oaep_label = OPENSSL_memdup(sctx->oaep_label, sctx->oaep_labellen);
++        if (!dctx->oaep_label)
++            return 0;
++        dctx->oaep_labellen = sctx->oaep_labellen;
++    }
++    return 1;
++}
++
++static int setup_tbuf(RSA_PKEY_CTX *ctx, EVP_PKEY_CTX *pk)
++{
++    if (ctx->tbuf)
++        return 1;
++    ctx->tbuf = OPENSSL_malloc(EVP_PKEY_size(pk->pkey));
++    if (ctx->tbuf == NULL)
++        return 0;
++    return 1;
++}
++
++static void pkey_rsa_cleanup(EVP_PKEY_CTX *ctx)
++{
++    RSA_PKEY_CTX *rctx = ctx->data;
++    if (rctx) {
++        BN_free(rctx->pub_exp);
++        OPENSSL_free(rctx->tbuf);
++        OPENSSL_free(rctx->oaep_label);
++        OPENSSL_free(rctx);
++    }
++}
++
++static int pkey_rsa_sign(EVP_PKEY_CTX *ctx, unsigned char *sig,
++                         size_t *siglen, const unsigned char *tbs,
++                         size_t tbslen)
++{
++    int ret;
++    RSA_PKEY_CTX *rctx = ctx->data;
++    RSA *rsa = ctx->pkey->pkey.rsa;
++
++    if (rctx->md) {
++        if (tbslen != (size_t)EVP_MD_size(rctx->md)) {
++            RSAerr(RSA_F_PKEY_RSA_SIGN, RSA_R_INVALID_DIGEST_LENGTH);
++            return -1;
++        }
++
++        if (EVP_MD_type(rctx->md) == NID_mdc2) {
++            unsigned int sltmp;
++            if (rctx->pad_mode != RSA_PKCS1_PADDING)
++                return -1;
++            ret = RSA_sign_ASN1_OCTET_STRING(0,
++                                             tbs, tbslen, sig, &sltmp, rsa);
++
++            if (ret <= 0)
++                return ret;
++            ret = sltmp;
++        } else if (rctx->pad_mode == RSA_X931_PADDING) {
++            if ((size_t)EVP_PKEY_size(ctx->pkey) < tbslen + 1) {
++                RSAerr(RSA_F_PKEY_RSA_SIGN, RSA_R_KEY_SIZE_TOO_SMALL);
++                return -1;
++            }
++            if (!setup_tbuf(rctx, ctx)) {
++                RSAerr(RSA_F_PKEY_RSA_SIGN, ERR_R_MALLOC_FAILURE);
++                return -1;
++            }
++            memcpy(rctx->tbuf, tbs, tbslen);
++            rctx->tbuf[tbslen] = RSA_X931_hash_id(EVP_MD_type(rctx->md));
++            ret = RSA_private_encrypt(tbslen + 1, rctx->tbuf,
++                                      sig, rsa, RSA_X931_PADDING);
++        } else if (rctx->pad_mode == RSA_PKCS1_PADDING) {
++            unsigned int sltmp;
++            ret = RSA_sign(EVP_MD_type(rctx->md),
++                           tbs, tbslen, sig, &sltmp, rsa);
++            if (ret <= 0)
++                return ret;
++            ret = sltmp;
++        } else if (rctx->pad_mode == RSA_PKCS1_PSS_PADDING) {
++            if (!setup_tbuf(rctx, ctx))
++                return -1;
++            if (!RSA_padding_add_PKCS1_PSS_mgf1(rsa,
++                                                rctx->tbuf, tbs,
++                                                rctx->md, rctx->mgf1md,
++                                                rctx->saltlen))
++                return -1;
++            ret = RSA_private_encrypt(RSA_size(rsa), rctx->tbuf,
++                                      sig, rsa, RSA_NO_PADDING);
++        } else
++            return -1;
++    } else
++        ret = RSA_private_encrypt(tbslen, tbs, sig, ctx->pkey->pkey.rsa,
++                                  rctx->pad_mode);
++    if (ret < 0)
++        return ret;
++    *siglen = ret;
++    return 1;
++}
++
++static int pkey_rsa_verifyrecover(EVP_PKEY_CTX *ctx,
++                                  unsigned char *rout, size_t *routlen,
++                                  const unsigned char *sig, size_t siglen)
++{
++    int ret;
++    RSA_PKEY_CTX *rctx = ctx->data;
++
++    if (rctx->md) {
++        if (rctx->pad_mode == RSA_X931_PADDING) {
++            if (!setup_tbuf(rctx, ctx))
++                return -1;
++            ret = RSA_public_decrypt(siglen, sig,
++                                     rctx->tbuf, ctx->pkey->pkey.rsa,
++                                     RSA_X931_PADDING);
++            if (ret < 1)
++                return 0;
++            ret--;
++            if (rctx->tbuf[ret] != RSA_X931_hash_id(EVP_MD_type(rctx->md))) {
++                RSAerr(RSA_F_PKEY_RSA_VERIFYRECOVER,
++                       RSA_R_ALGORITHM_MISMATCH);
++                return 0;
++            }
++            if (ret != EVP_MD_size(rctx->md)) {
++                RSAerr(RSA_F_PKEY_RSA_VERIFYRECOVER,
++                       RSA_R_INVALID_DIGEST_LENGTH);
++                return 0;
++            }
++            if (rout)
++                memcpy(rout, rctx->tbuf, ret);
++        } else if (rctx->pad_mode == RSA_PKCS1_PADDING) {
++            size_t sltmp;
++            ret = int_rsa_verify(EVP_MD_type(rctx->md),
++                                 NULL, 0, rout, &sltmp,
++                                 sig, siglen, ctx->pkey->pkey.rsa);
++            if (ret <= 0)
++                return 0;
++            ret = sltmp;
++        } else
++            return -1;
++    } else
++        ret = RSA_public_decrypt(siglen, sig, rout, ctx->pkey->pkey.rsa,
++                                 rctx->pad_mode);
++    if (ret < 0)
++        return ret;
++    *routlen = ret;
++    return 1;
++}
++
++static int pkey_rsa_verify(EVP_PKEY_CTX *ctx,
++                           const unsigned char *sig, size_t siglen,
++                           const unsigned char *tbs, size_t tbslen)
++{
++    RSA_PKEY_CTX *rctx = ctx->data;
++    RSA *rsa = ctx->pkey->pkey.rsa;
++    size_t rslen;
++    if (rctx->md) {
++        if (rctx->pad_mode == RSA_PKCS1_PADDING)
++            return RSA_verify(EVP_MD_type(rctx->md), tbs, tbslen,
++                              sig, siglen, rsa);
++        if (tbslen != (size_t)EVP_MD_size(rctx->md)) {
++            RSAerr(RSA_F_PKEY_RSA_VERIFY, RSA_R_INVALID_DIGEST_LENGTH);
++            return -1;
++        }
++        if (rctx->pad_mode == RSA_X931_PADDING) {
++            if (pkey_rsa_verifyrecover(ctx, NULL, &rslen, sig, siglen) <= 0)
++                return 0;
++        } else if (rctx->pad_mode == RSA_PKCS1_PSS_PADDING) {
++            int ret;
++            if (!setup_tbuf(rctx, ctx))
++                return -1;
++            ret = RSA_public_decrypt(siglen, sig, rctx->tbuf,
++                                     rsa, RSA_NO_PADDING);
++            if (ret <= 0)
++                return 0;
++            ret = RSA_verify_PKCS1_PSS_mgf1(rsa, tbs,
++                                            rctx->md, rctx->mgf1md,
++                                            rctx->tbuf, rctx->saltlen);
++            if (ret <= 0)
++                return 0;
++            return 1;
++        } else
++            return -1;
++    } else {
++        if (!setup_tbuf(rctx, ctx))
++            return -1;
++        rslen = RSA_public_decrypt(siglen, sig, rctx->tbuf,
++                                   rsa, rctx->pad_mode);
++        if (rslen == 0)
++            return 0;
++    }
++
++    if ((rslen != tbslen) || memcmp(tbs, rctx->tbuf, rslen))
++        return 0;
++
++    return 1;
++
++}
++
++static int pkey_rsa_encrypt(EVP_PKEY_CTX *ctx,
++                            unsigned char *out, size_t *outlen,
++                            const unsigned char *in, size_t inlen)
++{
++    int ret;
++    RSA_PKEY_CTX *rctx = ctx->data;
++    if (rctx->pad_mode == RSA_PKCS1_OAEP_PADDING) {
++        int klen = RSA_size(ctx->pkey->pkey.rsa);
++        if (!setup_tbuf(rctx, ctx))
++            return -1;
++        if (!RSA_padding_add_PKCS1_OAEP_mgf1(rctx->tbuf, klen,
++                                             in, inlen,
++                                             rctx->oaep_label,
++                                             rctx->oaep_labellen,
++                                             rctx->md, rctx->mgf1md))
++            return -1;
++        ret = RSA_public_encrypt(klen, rctx->tbuf, out,
++                                 ctx->pkey->pkey.rsa, RSA_NO_PADDING);
++    } else
++        ret = RSA_public_encrypt(inlen, in, out, ctx->pkey->pkey.rsa,
++                                 rctx->pad_mode);
++    if (ret < 0)
++        return ret;
++    *outlen = ret;
++    return 1;
++}
++
++static int pkey_rsa_decrypt(EVP_PKEY_CTX *ctx,
++                            unsigned char *out, size_t *outlen,
++                            const unsigned char *in, size_t inlen)
++{
++    int ret;
++    RSA_PKEY_CTX *rctx = ctx->data;
++    if (rctx->pad_mode == RSA_PKCS1_OAEP_PADDING) {
++        int i;
++        if (!setup_tbuf(rctx, ctx))
++            return -1;
++        ret = RSA_private_decrypt(inlen, in, rctx->tbuf,
++                                  ctx->pkey->pkey.rsa, RSA_NO_PADDING);
++        if (ret <= 0)
++            return ret;
++        for (i = 0; i < ret; i++) {
++            if (rctx->tbuf[i])
++                break;
++        }
++        ret = RSA_padding_check_PKCS1_OAEP_mgf1(out, ret, rctx->tbuf + i,
++                                                ret - i, ret,
++                                                rctx->oaep_label,
++                                                rctx->oaep_labellen,
++                                                rctx->md, rctx->mgf1md);
++    } else
++        ret = RSA_private_decrypt(inlen, in, out, ctx->pkey->pkey.rsa,
++                                  rctx->pad_mode);
++    if (ret < 0)
++        return ret;
++    *outlen = ret;
++    return 1;
++}
++
++static int check_padding_md(const EVP_MD *md, int padding)
++{
++    int mdnid;
++    if (!md)
++        return 1;
++
++    mdnid = EVP_MD_type(md);
++
++    if (padding == RSA_NO_PADDING) {
++        RSAerr(RSA_F_CHECK_PADDING_MD, RSA_R_INVALID_PADDING_MODE);
++        return 0;
++    }
++
++    if (padding == RSA_X931_PADDING) {
++        if (RSA_X931_hash_id(mdnid) == -1) {
++            RSAerr(RSA_F_CHECK_PADDING_MD, RSA_R_INVALID_X931_DIGEST);
++            return 0;
++        }
++    } else {
++        switch(mdnid) {
++        /* List of all supported RSA digests */
++        case NID_sha1:
++        case NID_sha224:
++        case NID_sha256:
++        case NID_sha384:
++        case NID_sha512:
++        case NID_md5:
++        case NID_md5_sha1:
++        case NID_md2:
++        case NID_md4:
++        case NID_mdc2:
++        case NID_ripemd160:
++            return 1;
++
++        default:
++            RSAerr(RSA_F_CHECK_PADDING_MD, RSA_R_INVALID_DIGEST);
++            return 0;
++
++        }
++    }
++
++    return 1;
++}
++
++static int pkey_rsa_ctrl(EVP_PKEY_CTX *ctx, int type, int p1, void *p2)
++{
++    RSA_PKEY_CTX *rctx = ctx->data;
++    switch (type) {
++    case EVP_PKEY_CTRL_RSA_PADDING:
++        if ((p1 >= RSA_PKCS1_PADDING) && (p1 <= RSA_PKCS1_PSS_PADDING)) {
++            if (!check_padding_md(rctx->md, p1))
++                return 0;
++            if (p1 == RSA_PKCS1_PSS_PADDING) {
++                if (!(ctx->operation &
++                      (EVP_PKEY_OP_SIGN | EVP_PKEY_OP_VERIFY)))
++                    goto bad_pad;
++                if (!rctx->md)
++                    rctx->md = EVP_sha1();
++            }
++            if (p1 == RSA_PKCS1_OAEP_PADDING) {
++                if (!(ctx->operation & EVP_PKEY_OP_TYPE_CRYPT))
++                    goto bad_pad;
++                if (!rctx->md)
++                    rctx->md = EVP_sha1();
++            }
++            rctx->pad_mode = p1;
++            return 1;
++        }
++ bad_pad:
++        RSAerr(RSA_F_PKEY_RSA_CTRL,
++               RSA_R_ILLEGAL_OR_UNSUPPORTED_PADDING_MODE);
++        return -2;
++
++    case EVP_PKEY_CTRL_GET_RSA_PADDING:
++        *(int *)p2 = rctx->pad_mode;
++        return 1;
++
++    case EVP_PKEY_CTRL_RSA_PSS_SALTLEN:
++    case EVP_PKEY_CTRL_GET_RSA_PSS_SALTLEN:
++        if (rctx->pad_mode != RSA_PKCS1_PSS_PADDING) {
++            RSAerr(RSA_F_PKEY_RSA_CTRL, RSA_R_INVALID_PSS_SALTLEN);
++            return -2;
++        }
++        if (type == EVP_PKEY_CTRL_GET_RSA_PSS_SALTLEN)
++            *(int *)p2 = rctx->saltlen;
++        else {
++            if (p1 < -2)
++                return -2;
++            rctx->saltlen = p1;
++        }
++        return 1;
++
++    case EVP_PKEY_CTRL_RSA_KEYGEN_BITS:
++        if (p1 < 512) {
++            RSAerr(RSA_F_PKEY_RSA_CTRL, RSA_R_KEY_SIZE_TOO_SMALL);
++            return -2;
++        }
++        rctx->nbits = p1;
++        return 1;
++
++    case EVP_PKEY_CTRL_RSA_KEYGEN_PUBEXP:
++        if (p2 == NULL || !BN_is_odd((BIGNUM *)p2) || BN_is_one((BIGNUM *)p2)) {
++            RSAerr(RSA_F_PKEY_RSA_CTRL, RSA_R_BAD_E_VALUE);
++            return -2;
++        }
++        BN_free(rctx->pub_exp);
++        rctx->pub_exp = p2;
++        return 1;
++
++    case EVP_PKEY_CTRL_RSA_OAEP_MD:
++    case EVP_PKEY_CTRL_GET_RSA_OAEP_MD:
++        if (rctx->pad_mode != RSA_PKCS1_OAEP_PADDING) {
++            RSAerr(RSA_F_PKEY_RSA_CTRL, RSA_R_INVALID_PADDING_MODE);
++            return -2;
++        }
++        if (type == EVP_PKEY_CTRL_GET_RSA_OAEP_MD)
++            *(const EVP_MD **)p2 = rctx->md;
++        else
++            rctx->md = p2;
++        return 1;
++
++    case EVP_PKEY_CTRL_MD:
++        if (!check_padding_md(p2, rctx->pad_mode))
++            return 0;
++        rctx->md = p2;
++        return 1;
++
++    case EVP_PKEY_CTRL_GET_MD:
++        *(const EVP_MD **)p2 = rctx->md;
++        return 1;
++
++    case EVP_PKEY_CTRL_RSA_MGF1_MD:
++    case EVP_PKEY_CTRL_GET_RSA_MGF1_MD:
++        if (rctx->pad_mode != RSA_PKCS1_PSS_PADDING
++            && rctx->pad_mode != RSA_PKCS1_OAEP_PADDING) {
++            RSAerr(RSA_F_PKEY_RSA_CTRL, RSA_R_INVALID_MGF1_MD);
++            return -2;
++        }
++        if (type == EVP_PKEY_CTRL_GET_RSA_MGF1_MD) {
++            if (rctx->mgf1md)
++                *(const EVP_MD **)p2 = rctx->mgf1md;
++            else
++                *(const EVP_MD **)p2 = rctx->md;
++        } else
++            rctx->mgf1md = p2;
++        return 1;
++
++    case EVP_PKEY_CTRL_RSA_OAEP_LABEL:
++        if (rctx->pad_mode != RSA_PKCS1_OAEP_PADDING) {
++            RSAerr(RSA_F_PKEY_RSA_CTRL, RSA_R_INVALID_PADDING_MODE);
++            return -2;
++        }
++        OPENSSL_free(rctx->oaep_label);
++        if (p2 && p1 > 0) {
++            rctx->oaep_label = p2;
++            rctx->oaep_labellen = p1;
++        } else {
++            rctx->oaep_label = NULL;
++            rctx->oaep_labellen = 0;
++        }
++        return 1;
++
++    case EVP_PKEY_CTRL_GET_RSA_OAEP_LABEL:
++        if (rctx->pad_mode != RSA_PKCS1_OAEP_PADDING) {
++            RSAerr(RSA_F_PKEY_RSA_CTRL, RSA_R_INVALID_PADDING_MODE);
++            return -2;
++        }
++        *(unsigned char **)p2 = rctx->oaep_label;
++        return rctx->oaep_labellen;
++
++    case EVP_PKEY_CTRL_DIGESTINIT:
++    case EVP_PKEY_CTRL_PKCS7_ENCRYPT:
++    case EVP_PKEY_CTRL_PKCS7_DECRYPT:
++    case EVP_PKEY_CTRL_PKCS7_SIGN:
++        return 1;
++#ifndef OPENSSL_NO_CMS
++    case EVP_PKEY_CTRL_CMS_DECRYPT:
++    case EVP_PKEY_CTRL_CMS_ENCRYPT:
++    case EVP_PKEY_CTRL_CMS_SIGN:
++        return 1;
++#endif
++    case EVP_PKEY_CTRL_PEER_KEY:
++        RSAerr(RSA_F_PKEY_RSA_CTRL,
++               RSA_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE);
++        return -2;
++
++    default:
++        return -2;
++
++    }
++}
++
++static int pkey_rsa_ctrl_str(EVP_PKEY_CTX *ctx,
++                             const char *type, const char *value)
++{
++    if (!value) {
++        RSAerr(RSA_F_PKEY_RSA_CTRL_STR, RSA_R_VALUE_MISSING);
++        return 0;
++    }
++    if (strcmp(type, "rsa_padding_mode") == 0) {
++        int pm;
++        if (strcmp(value, "pkcs1") == 0)
++            pm = RSA_PKCS1_PADDING;
++        else if (strcmp(value, "sslv23") == 0)
++            pm = RSA_SSLV23_PADDING;
++        else if (strcmp(value, "none") == 0)
++            pm = RSA_NO_PADDING;
++        else if (strcmp(value, "oeap") == 0)
++            pm = RSA_PKCS1_OAEP_PADDING;
++        else if (strcmp(value, "oaep") == 0)
++            pm = RSA_PKCS1_OAEP_PADDING;
++        else if (strcmp(value, "x931") == 0)
++            pm = RSA_X931_PADDING;
++        else if (strcmp(value, "pss") == 0)
++            pm = RSA_PKCS1_PSS_PADDING;
++        else {
++            RSAerr(RSA_F_PKEY_RSA_CTRL_STR, RSA_R_UNKNOWN_PADDING_TYPE);
++            return -2;
++        }
++        return EVP_PKEY_CTX_set_rsa_padding(ctx, pm);
++    }
++
++    if (strcmp(type, "rsa_pss_saltlen") == 0) {
++        int saltlen;
++        saltlen = atoi(value);
++        return EVP_PKEY_CTX_set_rsa_pss_saltlen(ctx, saltlen);
++    }
++
++    if (strcmp(type, "rsa_keygen_bits") == 0) {
++        int nbits;
++        nbits = atoi(value);
++        return EVP_PKEY_CTX_set_rsa_keygen_bits(ctx, nbits);
++    }
++
++    if (strcmp(type, "rsa_keygen_pubexp") == 0) {
++        int ret;
++        BIGNUM *pubexp = NULL;
++        if (!BN_asc2bn(&pubexp, value))
++            return 0;
++        ret = EVP_PKEY_CTX_set_rsa_keygen_pubexp(ctx, pubexp);
++        if (ret <= 0)
++            BN_free(pubexp);
++        return ret;
++    }
++
++    if (strcmp(type, "rsa_mgf1_md") == 0) {
++        const EVP_MD *md;
++        if ((md = EVP_get_digestbyname(value)) == NULL) {
++            RSAerr(RSA_F_PKEY_RSA_CTRL_STR, RSA_R_INVALID_DIGEST);
++            return 0;
++        }
++        return EVP_PKEY_CTX_set_rsa_mgf1_md(ctx, md);
++    }
++
++    if (strcmp(type, "rsa_oaep_md") == 0) {
++        const EVP_MD *md;
++        if ((md = EVP_get_digestbyname(value)) == NULL) {
++            RSAerr(RSA_F_PKEY_RSA_CTRL_STR, RSA_R_INVALID_DIGEST);
++            return 0;
++        }
++        return EVP_PKEY_CTX_set_rsa_oaep_md(ctx, md);
++    }
++    if (strcmp(type, "rsa_oaep_label") == 0) {
++        unsigned char *lab;
++        long lablen;
++        int ret;
++        lab = OPENSSL_hexstr2buf(value, &lablen);
++        if (!lab)
++            return 0;
++        ret = EVP_PKEY_CTX_set0_rsa_oaep_label(ctx, lab, lablen);
++        if (ret <= 0)
++            OPENSSL_free(lab);
++        return ret;
++    }
++
++    return -2;
++}
++
++static int pkey_rsa_keygen(EVP_PKEY_CTX *ctx, EVP_PKEY *pkey)
++{
++    RSA *rsa = NULL;
++    RSA_PKEY_CTX *rctx = ctx->data;
++    BN_GENCB *pcb;
++    int ret;
++    if (rctx->pub_exp == NULL) {
++        rctx->pub_exp = BN_new();
++        if (rctx->pub_exp == NULL || !BN_set_word(rctx->pub_exp, RSA_F4))
++            return 0;
++    }
++    rsa = RSA_new();
++    if (rsa == NULL)
++        return 0;
++    if (ctx->pkey_gencb) {
++        pcb = BN_GENCB_new();
++        if (pcb == NULL) {
++            RSA_free(rsa);
++            return 0;
++        }
++        evp_pkey_set_cb_translate(pcb, ctx);
++    } else
++        pcb = NULL;
++    ret = RSA_generate_key_ex(rsa, rctx->nbits, rctx->pub_exp, pcb);
++    BN_GENCB_free(pcb);
++    if (ret > 0)
++        EVP_PKEY_assign_RSA(pkey, rsa);
++    else
++        RSA_free(rsa);
++    return ret;
++}
++
++const EVP_PKEY_METHOD rsa_pkey_meth = {
++    EVP_PKEY_RSA,
++    EVP_PKEY_FLAG_AUTOARGLEN,
++    pkey_rsa_init,
++    pkey_rsa_copy,
++    pkey_rsa_cleanup,
++
++    0, 0,
++
++    0,
++    pkey_rsa_keygen,
++
++    0,
++    pkey_rsa_sign,
++
++    0,
++    pkey_rsa_verify,
++
++    0,
++    pkey_rsa_verifyrecover,
++
++    0, 0, 0, 0,
++
++    0,
++    pkey_rsa_encrypt,
++
++    0,
++    pkey_rsa_decrypt,
++
++    0, 0,
++
++    pkey_rsa_ctrl,
++    pkey_rsa_ctrl_str
++};
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/rsa/rsa_prn.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/rsa/rsa_prn.c
+new file mode 100644
+index 0000000..5e6c599
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/rsa/rsa_prn.c
+@@ -0,0 +1,42 @@
++/*
++ * Copyright 2006-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include "internal/cryptlib.h"
++#include 
++#include 
++
++#ifndef OPENSSL_NO_STDIO
++int RSA_print_fp(FILE *fp, const RSA *x, int off)
++{
++    BIO *b;
++    int ret;
++
++    if ((b = BIO_new(BIO_s_file())) == NULL) {
++        RSAerr(RSA_F_RSA_PRINT_FP, ERR_R_BUF_LIB);
++        return (0);
++    }
++    BIO_set_fp(b, fp, BIO_NOCLOSE);
++    ret = RSA_print(b, x, off);
++    BIO_free(b);
++    return (ret);
++}
++#endif
++
++int RSA_print(BIO *bp, const RSA *x, int off)
++{
++    EVP_PKEY *pk;
++    int ret;
++    pk = EVP_PKEY_new();
++    if (pk == NULL || !EVP_PKEY_set1_RSA(pk, (RSA *)x))
++        return 0;
++    ret = EVP_PKEY_print_private(bp, pk, off, NULL);
++    EVP_PKEY_free(pk);
++    return ret;
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/rsa/rsa_pss.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/rsa/rsa_pss.c
+new file mode 100644
+index 0000000..0ec63b2
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/rsa/rsa_pss.c
+@@ -0,0 +1,244 @@
++/*
++ * Copyright 2005-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include "internal/cryptlib.h"
++#include 
++#include 
++#include 
++#include 
++#include 
++#include "rsa_locl.h"
++
++static const unsigned char zeroes[] = { 0, 0, 0, 0, 0, 0, 0, 0 };
++
++#if defined(_MSC_VER) && defined(_ARM_)
++# pragma optimize("g", off)
++#endif
++
++int RSA_verify_PKCS1_PSS(RSA *rsa, const unsigned char *mHash,
++                         const EVP_MD *Hash, const unsigned char *EM,
++                         int sLen)
++{
++    return RSA_verify_PKCS1_PSS_mgf1(rsa, mHash, Hash, NULL, EM, sLen);
++}
++
++int RSA_verify_PKCS1_PSS_mgf1(RSA *rsa, const unsigned char *mHash,
++                              const EVP_MD *Hash, const EVP_MD *mgf1Hash,
++                              const unsigned char *EM, int sLen)
++{
++    int i;
++    int ret = 0;
++    int hLen, maskedDBLen, MSBits, emLen;
++    const unsigned char *H;
++    unsigned char *DB = NULL;
++    EVP_MD_CTX *ctx = EVP_MD_CTX_new();
++    unsigned char H_[EVP_MAX_MD_SIZE];
++
++
++    if (ctx == NULL)
++        goto err;
++
++    if (mgf1Hash == NULL)
++        mgf1Hash = Hash;
++
++    hLen = EVP_MD_size(Hash);
++    if (hLen < 0)
++        goto err;
++    /*-
++     * Negative sLen has special meanings:
++     *      -1      sLen == hLen
++     *      -2      salt length is autorecovered from signature
++     *      -N      reserved
++     */
++    if (sLen == -1)
++        sLen = hLen;
++    else if (sLen == -2)
++        sLen = -2;
++    else if (sLen < -2) {
++        RSAerr(RSA_F_RSA_VERIFY_PKCS1_PSS_MGF1, RSA_R_SLEN_CHECK_FAILED);
++        goto err;
++    }
++
++    MSBits = (BN_num_bits(rsa->n) - 1) & 0x7;
++    emLen = RSA_size(rsa);
++    if (EM[0] & (0xFF << MSBits)) {
++        RSAerr(RSA_F_RSA_VERIFY_PKCS1_PSS_MGF1, RSA_R_FIRST_OCTET_INVALID);
++        goto err;
++    }
++    if (MSBits == 0) {
++        EM++;
++        emLen--;
++    }
++    if (emLen < (hLen + sLen + 2)) { /* sLen can be small negative */
++        RSAerr(RSA_F_RSA_VERIFY_PKCS1_PSS_MGF1, RSA_R_DATA_TOO_LARGE);
++        goto err;
++    }
++    if (EM[emLen - 1] != 0xbc) {
++        RSAerr(RSA_F_RSA_VERIFY_PKCS1_PSS_MGF1, RSA_R_LAST_OCTET_INVALID);
++        goto err;
++    }
++    maskedDBLen = emLen - hLen - 1;
++    H = EM + maskedDBLen;
++    DB = OPENSSL_malloc(maskedDBLen);
++    if (DB == NULL) {
++        RSAerr(RSA_F_RSA_VERIFY_PKCS1_PSS_MGF1, ERR_R_MALLOC_FAILURE);
++        goto err;
++    }
++    if (PKCS1_MGF1(DB, maskedDBLen, H, hLen, mgf1Hash) < 0)
++        goto err;
++    for (i = 0; i < maskedDBLen; i++)
++        DB[i] ^= EM[i];
++    if (MSBits)
++        DB[0] &= 0xFF >> (8 - MSBits);
++    for (i = 0; DB[i] == 0 && i < (maskedDBLen - 1); i++) ;
++    if (DB[i++] != 0x1) {
++        RSAerr(RSA_F_RSA_VERIFY_PKCS1_PSS_MGF1, RSA_R_SLEN_RECOVERY_FAILED);
++        goto err;
++    }
++    if (sLen >= 0 && (maskedDBLen - i) != sLen) {
++        RSAerr(RSA_F_RSA_VERIFY_PKCS1_PSS_MGF1, RSA_R_SLEN_CHECK_FAILED);
++        goto err;
++    }
++    if (!EVP_DigestInit_ex(ctx, Hash, NULL)
++        || !EVP_DigestUpdate(ctx, zeroes, sizeof zeroes)
++        || !EVP_DigestUpdate(ctx, mHash, hLen))
++        goto err;
++    if (maskedDBLen - i) {
++        if (!EVP_DigestUpdate(ctx, DB + i, maskedDBLen - i))
++            goto err;
++    }
++    if (!EVP_DigestFinal_ex(ctx, H_, NULL))
++        goto err;
++    if (memcmp(H_, H, hLen)) {
++        RSAerr(RSA_F_RSA_VERIFY_PKCS1_PSS_MGF1, RSA_R_BAD_SIGNATURE);
++        ret = 0;
++    } else
++        ret = 1;
++
++ err:
++    OPENSSL_free(DB);
++    EVP_MD_CTX_free(ctx);
++
++    return ret;
++
++}
++
++int RSA_padding_add_PKCS1_PSS(RSA *rsa, unsigned char *EM,
++                              const unsigned char *mHash,
++                              const EVP_MD *Hash, int sLen)
++{
++    return RSA_padding_add_PKCS1_PSS_mgf1(rsa, EM, mHash, Hash, NULL, sLen);
++}
++
++int RSA_padding_add_PKCS1_PSS_mgf1(RSA *rsa, unsigned char *EM,
++                                   const unsigned char *mHash,
++                                   const EVP_MD *Hash, const EVP_MD *mgf1Hash,
++                                   int sLen)
++{
++    int i;
++    int ret = 0;
++    int hLen, maskedDBLen, MSBits, emLen;
++    unsigned char *H, *salt = NULL, *p;
++    EVP_MD_CTX *ctx = NULL;
++
++    if (mgf1Hash == NULL)
++        mgf1Hash = Hash;
++
++    hLen = EVP_MD_size(Hash);
++    if (hLen < 0)
++        goto err;
++    /*-
++     * Negative sLen has special meanings:
++     *      -1      sLen == hLen
++     *      -2      salt length is maximized
++     *      -N      reserved
++     */
++    if (sLen == -1)
++        sLen = hLen;
++    else if (sLen == -2)
++        sLen = -2;
++    else if (sLen < -2) {
++        RSAerr(RSA_F_RSA_PADDING_ADD_PKCS1_PSS_MGF1, RSA_R_SLEN_CHECK_FAILED);
++        goto err;
++    }
++
++    MSBits = (BN_num_bits(rsa->n) - 1) & 0x7;
++    emLen = RSA_size(rsa);
++    if (MSBits == 0) {
++        *EM++ = 0;
++        emLen--;
++    }
++    if (sLen == -2) {
++        sLen = emLen - hLen - 2;
++    } else if (emLen < (hLen + sLen + 2)) {
++        RSAerr(RSA_F_RSA_PADDING_ADD_PKCS1_PSS_MGF1,
++               RSA_R_DATA_TOO_LARGE_FOR_KEY_SIZE);
++        goto err;
++    }
++    if (sLen > 0) {
++        salt = OPENSSL_malloc(sLen);
++        if (salt == NULL) {
++            RSAerr(RSA_F_RSA_PADDING_ADD_PKCS1_PSS_MGF1,
++                   ERR_R_MALLOC_FAILURE);
++            goto err;
++        }
++        if (RAND_bytes(salt, sLen) <= 0)
++            goto err;
++    }
++    maskedDBLen = emLen - hLen - 1;
++    H = EM + maskedDBLen;
++    ctx = EVP_MD_CTX_new();
++    if (ctx == NULL)
++        goto err;
++    if (!EVP_DigestInit_ex(ctx, Hash, NULL)
++        || !EVP_DigestUpdate(ctx, zeroes, sizeof zeroes)
++        || !EVP_DigestUpdate(ctx, mHash, hLen))
++        goto err;
++    if (sLen && !EVP_DigestUpdate(ctx, salt, sLen))
++        goto err;
++    if (!EVP_DigestFinal_ex(ctx, H, NULL))
++        goto err;
++
++    /* Generate dbMask in place then perform XOR on it */
++    if (PKCS1_MGF1(EM, maskedDBLen, H, hLen, mgf1Hash))
++        goto err;
++
++    p = EM;
++
++    /*
++     * Initial PS XORs with all zeroes which is a NOP so just update pointer.
++     * Note from a test above this value is guaranteed to be non-negative.
++     */
++    p += emLen - sLen - hLen - 2;
++    *p++ ^= 0x1;
++    if (sLen > 0) {
++        for (i = 0; i < sLen; i++)
++            *p++ ^= salt[i];
++    }
++    if (MSBits)
++        EM[0] &= 0xFF >> (8 - MSBits);
++
++    /* H is already in place so just set final 0xbc */
++
++    EM[emLen - 1] = 0xbc;
++
++    ret = 1;
++
++ err:
++    EVP_MD_CTX_free(ctx);
++    OPENSSL_free(salt);
++
++    return ret;
++
++}
++
++#if defined(_MSC_VER)
++# pragma optimize("",on)
++#endif
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/rsa/rsa_saos.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/rsa/rsa_saos.c
+new file mode 100644
+index 0000000..9e5fff4
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/rsa/rsa_saos.c
+@@ -0,0 +1,94 @@
++/*
++ * Copyright 1995-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include "internal/cryptlib.h"
++#include 
++#include 
++#include 
++#include 
++
++int RSA_sign_ASN1_OCTET_STRING(int type,
++                               const unsigned char *m, unsigned int m_len,
++                               unsigned char *sigret, unsigned int *siglen,
++                               RSA *rsa)
++{
++    ASN1_OCTET_STRING sig;
++    int i, j, ret = 1;
++    unsigned char *p, *s;
++
++    sig.type = V_ASN1_OCTET_STRING;
++    sig.length = m_len;
++    sig.data = (unsigned char *)m;
++
++    i = i2d_ASN1_OCTET_STRING(&sig, NULL);
++    j = RSA_size(rsa);
++    if (i > (j - RSA_PKCS1_PADDING_SIZE)) {
++        RSAerr(RSA_F_RSA_SIGN_ASN1_OCTET_STRING,
++               RSA_R_DIGEST_TOO_BIG_FOR_RSA_KEY);
++        return (0);
++    }
++    s = OPENSSL_malloc((unsigned int)j + 1);
++    if (s == NULL) {
++        RSAerr(RSA_F_RSA_SIGN_ASN1_OCTET_STRING, ERR_R_MALLOC_FAILURE);
++        return (0);
++    }
++    p = s;
++    i2d_ASN1_OCTET_STRING(&sig, &p);
++    i = RSA_private_encrypt(i, s, sigret, rsa, RSA_PKCS1_PADDING);
++    if (i <= 0)
++        ret = 0;
++    else
++        *siglen = i;
++
++    OPENSSL_clear_free(s, (unsigned int)j + 1);
++    return (ret);
++}
++
++int RSA_verify_ASN1_OCTET_STRING(int dtype,
++                                 const unsigned char *m,
++                                 unsigned int m_len, unsigned char *sigbuf,
++                                 unsigned int siglen, RSA *rsa)
++{
++    int i, ret = 0;
++    unsigned char *s;
++    const unsigned char *p;
++    ASN1_OCTET_STRING *sig = NULL;
++
++    if (siglen != (unsigned int)RSA_size(rsa)) {
++        RSAerr(RSA_F_RSA_VERIFY_ASN1_OCTET_STRING,
++               RSA_R_WRONG_SIGNATURE_LENGTH);
++        return (0);
++    }
++
++    s = OPENSSL_malloc((unsigned int)siglen);
++    if (s == NULL) {
++        RSAerr(RSA_F_RSA_VERIFY_ASN1_OCTET_STRING, ERR_R_MALLOC_FAILURE);
++        goto err;
++    }
++    i = RSA_public_decrypt((int)siglen, sigbuf, s, rsa, RSA_PKCS1_PADDING);
++
++    if (i <= 0)
++        goto err;
++
++    p = s;
++    sig = d2i_ASN1_OCTET_STRING(NULL, &p, (long)i);
++    if (sig == NULL)
++        goto err;
++
++    if (((unsigned int)sig->length != m_len) ||
++        (memcmp(m, sig->data, m_len) != 0)) {
++        RSAerr(RSA_F_RSA_VERIFY_ASN1_OCTET_STRING, RSA_R_BAD_SIGNATURE);
++    } else
++        ret = 1;
++ err:
++    ASN1_OCTET_STRING_free(sig);
++    OPENSSL_clear_free(s, (unsigned int)siglen);
++    return (ret);
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/rsa/rsa_sign.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/rsa/rsa_sign.c
+new file mode 100644
+index 0000000..952d24f
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/rsa/rsa_sign.c
+@@ -0,0 +1,248 @@
++/*
++ * Copyright 1995-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include "internal/cryptlib.h"
++#include 
++#include 
++#include 
++#include 
++#include "internal/x509_int.h"
++#include "rsa_locl.h"
++
++/* Size of an SSL signature: MD5+SHA1 */
++#define SSL_SIG_LENGTH  36
++
++/*
++ * encode_pkcs1 encodes a DigestInfo prefix of hash |type| and digest |m|, as
++ * described in EMSA-PKCS1-v1_5-ENCODE, RFC 3447 section 9.2 step 2. This
++ * encodes the DigestInfo (T and tLen) but does not add the padding.
++ *
++ * On success, it returns one and sets |*out| to a newly allocated buffer
++ * containing the result and |*out_len| to its length. The caller must free
++ * |*out| with |OPENSSL_free|. Otherwise, it returns zero.
++ */
++static int encode_pkcs1(unsigned char **out, int *out_len, int type,
++                        const unsigned char *m, unsigned int m_len)
++{
++    X509_SIG sig;
++    X509_ALGOR algor;
++    ASN1_TYPE parameter;
++    ASN1_OCTET_STRING digest;
++    uint8_t *der = NULL;
++    int len;
++
++    sig.algor = &algor;
++    sig.algor->algorithm = OBJ_nid2obj(type);
++    if (sig.algor->algorithm == NULL) {
++        RSAerr(RSA_F_ENCODE_PKCS1, RSA_R_UNKNOWN_ALGORITHM_TYPE);
++        return 0;
++    }
++    if (OBJ_length(sig.algor->algorithm) == 0) {
++        RSAerr(RSA_F_ENCODE_PKCS1,
++               RSA_R_THE_ASN1_OBJECT_IDENTIFIER_IS_NOT_KNOWN_FOR_THIS_MD);
++        return 0;
++    }
++    parameter.type = V_ASN1_NULL;
++    parameter.value.ptr = NULL;
++    sig.algor->parameter = ¶meter;
++
++    sig.digest = &digest;
++    sig.digest->data = (unsigned char *)m;
++    sig.digest->length = m_len;
++
++    len = i2d_X509_SIG(&sig, &der);
++    if (len < 0)
++        return 0;
++
++    *out = der;
++    *out_len = len;
++    return 1;
++}
++
++int RSA_sign(int type, const unsigned char *m, unsigned int m_len,
++             unsigned char *sigret, unsigned int *siglen, RSA *rsa)
++{
++    int encrypt_len, encoded_len = 0, ret = 0;
++    unsigned char *tmps = NULL;
++    const unsigned char *encoded = NULL;
++
++    if (rsa->meth->rsa_sign) {
++        return rsa->meth->rsa_sign(type, m, m_len, sigret, siglen, rsa);
++    }
++
++    /* Compute the encoded digest. */
++    if (type == NID_md5_sha1) {
++        /*
++         * NID_md5_sha1 corresponds to the MD5/SHA1 combination in TLS 1.1 and
++         * earlier. It has no DigestInfo wrapper but otherwise is
++         * RSASSA-PKCS1-v1_5.
++         */
++        if (m_len != SSL_SIG_LENGTH) {
++            RSAerr(RSA_F_RSA_SIGN, RSA_R_INVALID_MESSAGE_LENGTH);
++            return 0;
++        }
++        encoded_len = SSL_SIG_LENGTH;
++        encoded = m;
++    } else {
++        if (!encode_pkcs1(&tmps, &encoded_len, type, m, m_len))
++            goto err;
++        encoded = tmps;
++    }
++
++    if (encoded_len > RSA_size(rsa) - RSA_PKCS1_PADDING_SIZE) {
++        RSAerr(RSA_F_RSA_SIGN, RSA_R_DIGEST_TOO_BIG_FOR_RSA_KEY);
++        goto err;
++    }
++    encrypt_len = RSA_private_encrypt(encoded_len, encoded, sigret, rsa,
++                                      RSA_PKCS1_PADDING);
++    if (encrypt_len <= 0)
++        goto err;
++
++    *siglen = encrypt_len;
++    ret = 1;
++
++err:
++    OPENSSL_clear_free(tmps, (size_t)encoded_len);
++    return ret;
++}
++
++/*
++ * int_rsa_verify verifies an RSA signature in |sigbuf| using |rsa|. It may be
++ * called in two modes. If |rm| is NULL, it verifies the signature for digest
++ * |m|. Otherwise, it recovers the digest from the signature, writing the digest
++ * to |rm| and the length to |*prm_len|. |type| is the NID of the digest
++ * algorithm to use. It returns one on successful verification and zero
++ * otherwise.
++ */
++int int_rsa_verify(int type, const unsigned char *m, unsigned int m_len,
++                   unsigned char *rm, size_t *prm_len,
++                   const unsigned char *sigbuf, size_t siglen, RSA *rsa)
++{
++    int decrypt_len, ret = 0, encoded_len = 0;
++    unsigned char *decrypt_buf = NULL, *encoded = NULL;
++
++    if (siglen != (size_t)RSA_size(rsa)) {
++        RSAerr(RSA_F_INT_RSA_VERIFY, RSA_R_WRONG_SIGNATURE_LENGTH);
++        return 0;
++    }
++
++    /* Recover the encoded digest. */
++    decrypt_buf = OPENSSL_malloc(siglen);
++    if (decrypt_buf == NULL) {
++        RSAerr(RSA_F_INT_RSA_VERIFY, ERR_R_MALLOC_FAILURE);
++        goto err;
++    }
++
++    decrypt_len = RSA_public_decrypt((int)siglen, sigbuf, decrypt_buf, rsa,
++                                     RSA_PKCS1_PADDING);
++    if (decrypt_len <= 0)
++        goto err;
++
++    if (type == NID_md5_sha1) {
++        /*
++         * NID_md5_sha1 corresponds to the MD5/SHA1 combination in TLS 1.1 and
++         * earlier. It has no DigestInfo wrapper but otherwise is
++         * RSASSA-PKCS1-v1_5.
++         */
++        if (decrypt_len != SSL_SIG_LENGTH) {
++            RSAerr(RSA_F_INT_RSA_VERIFY, RSA_R_BAD_SIGNATURE);
++            goto err;
++        }
++
++        if (rm != NULL) {
++            memcpy(rm, decrypt_buf, SSL_SIG_LENGTH);
++            *prm_len = SSL_SIG_LENGTH;
++        } else {
++            if (m_len != SSL_SIG_LENGTH) {
++                RSAerr(RSA_F_INT_RSA_VERIFY, RSA_R_INVALID_MESSAGE_LENGTH);
++                goto err;
++            }
++
++            if (memcmp(decrypt_buf, m, SSL_SIG_LENGTH) != 0) {
++                RSAerr(RSA_F_INT_RSA_VERIFY, RSA_R_BAD_SIGNATURE);
++                goto err;
++            }
++        }
++    } else if (type == NID_mdc2 && decrypt_len == 2 + 16
++               && decrypt_buf[0] == 0x04 && decrypt_buf[1] == 0x10) {
++        /*
++         * Oddball MDC2 case: signature can be OCTET STRING. check for correct
++         * tag and length octets.
++         */
++        if (rm != NULL) {
++            memcpy(rm, decrypt_buf + 2, 16);
++            *prm_len = 16;
++        } else {
++            if (m_len != 16) {
++                RSAerr(RSA_F_INT_RSA_VERIFY, RSA_R_INVALID_MESSAGE_LENGTH);
++                goto err;
++            }
++
++            if (memcmp(m, decrypt_buf + 2, 16) != 0) {
++                RSAerr(RSA_F_INT_RSA_VERIFY, RSA_R_BAD_SIGNATURE);
++                goto err;
++            }
++        }
++    } else {
++        /*
++         * If recovering the digest, extract a digest-sized output from the end
++         * of |decrypt_buf| for |encode_pkcs1|, then compare the decryption
++         * output as in a standard verification.
++         */
++        if (rm != NULL) {
++            const EVP_MD *md = EVP_get_digestbynid(type);
++            if (md == NULL) {
++                RSAerr(RSA_F_INT_RSA_VERIFY, RSA_R_UNKNOWN_ALGORITHM_TYPE);
++                goto err;
++            }
++
++            m_len = EVP_MD_size(md);
++            if (m_len > (size_t)decrypt_len) {
++                RSAerr(RSA_F_INT_RSA_VERIFY, RSA_R_INVALID_DIGEST_LENGTH);
++                goto err;
++            }
++            m = decrypt_buf + decrypt_len - m_len;
++        }
++
++        /* Construct the encoded digest and ensure it matches. */
++        if (!encode_pkcs1(&encoded, &encoded_len, type, m, m_len))
++            goto err;
++
++        if (encoded_len != decrypt_len
++            || memcmp(encoded, decrypt_buf, encoded_len) != 0) {
++            RSAerr(RSA_F_INT_RSA_VERIFY, RSA_R_BAD_SIGNATURE);
++            goto err;
++        }
++
++        /* Output the recovered digest. */
++        if (rm != NULL) {
++            memcpy(rm, m, m_len);
++            *prm_len = m_len;
++        }
++    }
++
++    ret = 1;
++
++err:
++    OPENSSL_clear_free(encoded, (size_t)encoded_len);
++    OPENSSL_clear_free(decrypt_buf, siglen);
++    return ret;
++}
++
++int RSA_verify(int type, const unsigned char *m, unsigned int m_len,
++               const unsigned char *sigbuf, unsigned int siglen, RSA *rsa)
++{
++
++    if (rsa->meth->rsa_verify) {
++        return rsa->meth->rsa_verify(type, m, m_len, sigbuf, siglen, rsa);
++    }
++
++    return int_rsa_verify(type, m, m_len, NULL, NULL, sigbuf, siglen, rsa);
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/rsa/rsa_ssl.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/rsa/rsa_ssl.c
+new file mode 100644
+index 0000000..9ef6b80
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/rsa/rsa_ssl.c
+@@ -0,0 +1,100 @@
++/*
++ * Copyright 1995-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include "internal/cryptlib.h"
++#include 
++#include 
++#include 
++
++int RSA_padding_add_SSLv23(unsigned char *to, int tlen,
++                           const unsigned char *from, int flen)
++{
++    int i, j;
++    unsigned char *p;
++
++    if (flen > (tlen - 11)) {
++        RSAerr(RSA_F_RSA_PADDING_ADD_SSLV23,
++               RSA_R_DATA_TOO_LARGE_FOR_KEY_SIZE);
++        return (0);
++    }
++
++    p = (unsigned char *)to;
++
++    *(p++) = 0;
++    *(p++) = 2;                 /* Public Key BT (Block Type) */
++
++    /* pad out with non-zero random data */
++    j = tlen - 3 - 8 - flen;
++
++    if (RAND_bytes(p, j) <= 0)
++        return (0);
++    for (i = 0; i < j; i++) {
++        if (*p == '\0')
++            do {
++                if (RAND_bytes(p, 1) <= 0)
++                    return (0);
++            } while (*p == '\0');
++        p++;
++    }
++
++    memset(p, 3, 8);
++    p += 8;
++    *(p++) = '\0';
++
++    memcpy(p, from, (unsigned int)flen);
++    return (1);
++}
++
++int RSA_padding_check_SSLv23(unsigned char *to, int tlen,
++                             const unsigned char *from, int flen, int num)
++{
++    int i, j, k;
++    const unsigned char *p;
++
++    p = from;
++    if (flen < 10) {
++        RSAerr(RSA_F_RSA_PADDING_CHECK_SSLV23, RSA_R_DATA_TOO_SMALL);
++        return (-1);
++    }
++    if ((num != (flen + 1)) || (*(p++) != 02)) {
++        RSAerr(RSA_F_RSA_PADDING_CHECK_SSLV23, RSA_R_BLOCK_TYPE_IS_NOT_02);
++        return (-1);
++    }
++
++    /* scan over padding data */
++    j = flen - 1;               /* one for type */
++    for (i = 0; i < j; i++)
++        if (*(p++) == 0)
++            break;
++
++    if ((i == j) || (i < 8)) {
++        RSAerr(RSA_F_RSA_PADDING_CHECK_SSLV23,
++               RSA_R_NULL_BEFORE_BLOCK_MISSING);
++        return (-1);
++    }
++    for (k = -9; k < -1; k++) {
++        if (p[k] != 0x03)
++            break;
++    }
++    if (k == -1) {
++        RSAerr(RSA_F_RSA_PADDING_CHECK_SSLV23, RSA_R_SSLV3_ROLLBACK_ATTACK);
++        return (-1);
++    }
++
++    i++;                        /* Skip over the '\0' */
++    j -= i;
++    if (j > tlen) {
++        RSAerr(RSA_F_RSA_PADDING_CHECK_SSLV23, RSA_R_DATA_TOO_LARGE);
++        return (-1);
++    }
++    memcpy(to, p, (unsigned int)j);
++
++    return (j);
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/rsa/rsa_x931.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/rsa/rsa_x931.c
+new file mode 100644
+index 0000000..b9301f3
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/rsa/rsa_x931.c
+@@ -0,0 +1,116 @@
++/*
++ * Copyright 2005-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include "internal/cryptlib.h"
++#include 
++#include 
++#include 
++
++int RSA_padding_add_X931(unsigned char *to, int tlen,
++                         const unsigned char *from, int flen)
++{
++    int j;
++    unsigned char *p;
++
++    /*
++     * Absolute minimum amount of padding is 1 header nibble, 1 padding
++     * nibble and 2 trailer bytes: but 1 hash if is already in 'from'.
++     */
++
++    j = tlen - flen - 2;
++
++    if (j < 0) {
++        RSAerr(RSA_F_RSA_PADDING_ADD_X931, RSA_R_DATA_TOO_LARGE_FOR_KEY_SIZE);
++        return -1;
++    }
++
++    p = (unsigned char *)to;
++
++    /* If no padding start and end nibbles are in one byte */
++    if (j == 0)
++        *p++ = 0x6A;
++    else {
++        *p++ = 0x6B;
++        if (j > 1) {
++            memset(p, 0xBB, j - 1);
++            p += j - 1;
++        }
++        *p++ = 0xBA;
++    }
++    memcpy(p, from, (unsigned int)flen);
++    p += flen;
++    *p = 0xCC;
++    return (1);
++}
++
++int RSA_padding_check_X931(unsigned char *to, int tlen,
++                           const unsigned char *from, int flen, int num)
++{
++    int i = 0, j;
++    const unsigned char *p;
++
++    p = from;
++    if ((num != flen) || ((*p != 0x6A) && (*p != 0x6B))) {
++        RSAerr(RSA_F_RSA_PADDING_CHECK_X931, RSA_R_INVALID_HEADER);
++        return -1;
++    }
++
++    if (*p++ == 0x6B) {
++        j = flen - 3;
++        for (i = 0; i < j; i++) {
++            unsigned char c = *p++;
++            if (c == 0xBA)
++                break;
++            if (c != 0xBB) {
++                RSAerr(RSA_F_RSA_PADDING_CHECK_X931, RSA_R_INVALID_PADDING);
++                return -1;
++            }
++        }
++
++        j -= i;
++
++        if (i == 0) {
++            RSAerr(RSA_F_RSA_PADDING_CHECK_X931, RSA_R_INVALID_PADDING);
++            return -1;
++        }
++
++    } else
++        j = flen - 2;
++
++    if (p[j] != 0xCC) {
++        RSAerr(RSA_F_RSA_PADDING_CHECK_X931, RSA_R_INVALID_TRAILER);
++        return -1;
++    }
++
++    memcpy(to, p, (unsigned int)j);
++
++    return (j);
++}
++
++/* Translate between X931 hash ids and NIDs */
++
++int RSA_X931_hash_id(int nid)
++{
++    switch (nid) {
++    case NID_sha1:
++        return 0x33;
++
++    case NID_sha256:
++        return 0x34;
++
++    case NID_sha384:
++        return 0x36;
++
++    case NID_sha512:
++        return 0x35;
++
++    }
++    return -1;
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/rsa/rsa_x931g.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/rsa/rsa_x931g.c
+new file mode 100644
+index 0000000..9dd993f
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/rsa/rsa_x931g.c
+@@ -0,0 +1,195 @@
++/*
++ * Copyright 1995-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include 
++#include 
++#include 
++#include 
++#include "rsa_locl.h"
++
++/* X9.31 RSA key derivation and generation */
++
++int RSA_X931_derive_ex(RSA *rsa, BIGNUM *p1, BIGNUM *p2, BIGNUM *q1,
++                       BIGNUM *q2, const BIGNUM *Xp1, const BIGNUM *Xp2,
++                       const BIGNUM *Xp, const BIGNUM *Xq1, const BIGNUM *Xq2,
++                       const BIGNUM *Xq, const BIGNUM *e, BN_GENCB *cb)
++{
++    BIGNUM *r0 = NULL, *r1 = NULL, *r2 = NULL, *r3 = NULL;
++    BN_CTX *ctx = NULL, *ctx2 = NULL;
++    int ret = 0;
++
++    if (!rsa)
++        goto err;
++
++    ctx = BN_CTX_new();
++    if (ctx == NULL)
++        goto err;
++    BN_CTX_start(ctx);
++
++    r0 = BN_CTX_get(ctx);
++    r1 = BN_CTX_get(ctx);
++    r2 = BN_CTX_get(ctx);
++    r3 = BN_CTX_get(ctx);
++
++    if (r3 == NULL)
++        goto err;
++    if (!rsa->e) {
++        rsa->e = BN_dup(e);
++        if (!rsa->e)
++            goto err;
++    } else
++        e = rsa->e;
++
++    /*
++     * If not all parameters present only calculate what we can. This allows
++     * test programs to output selective parameters.
++     */
++
++    if (Xp && rsa->p == NULL) {
++        rsa->p = BN_new();
++        if (rsa->p == NULL)
++            goto err;
++
++        if (!BN_X931_derive_prime_ex(rsa->p, p1, p2,
++                                     Xp, Xp1, Xp2, e, ctx, cb))
++            goto err;
++    }
++
++    if (Xq && rsa->q == NULL) {
++        rsa->q = BN_new();
++        if (rsa->q == NULL)
++            goto err;
++        if (!BN_X931_derive_prime_ex(rsa->q, q1, q2,
++                                     Xq, Xq1, Xq2, e, ctx, cb))
++            goto err;
++    }
++
++    if (rsa->p == NULL || rsa->q == NULL) {
++        BN_CTX_end(ctx);
++        BN_CTX_free(ctx);
++        return 2;
++    }
++
++    /*
++     * Since both primes are set we can now calculate all remaining
++     * components.
++     */
++
++    /* calculate n */
++    rsa->n = BN_new();
++    if (rsa->n == NULL)
++        goto err;
++    if (!BN_mul(rsa->n, rsa->p, rsa->q, ctx))
++        goto err;
++
++    /* calculate d */
++    if (!BN_sub(r1, rsa->p, BN_value_one()))
++        goto err;               /* p-1 */
++    if (!BN_sub(r2, rsa->q, BN_value_one()))
++        goto err;               /* q-1 */
++    if (!BN_mul(r0, r1, r2, ctx))
++        goto err;               /* (p-1)(q-1) */
++
++    if (!BN_gcd(r3, r1, r2, ctx))
++        goto err;
++
++    if (!BN_div(r0, NULL, r0, r3, ctx))
++        goto err;               /* LCM((p-1)(q-1)) */
++
++    ctx2 = BN_CTX_new();
++    if (ctx2 == NULL)
++        goto err;
++
++    rsa->d = BN_mod_inverse(NULL, rsa->e, r0, ctx2); /* d */
++    if (rsa->d == NULL)
++        goto err;
++
++    /* calculate d mod (p-1) */
++    rsa->dmp1 = BN_new();
++    if (rsa->dmp1 == NULL)
++        goto err;
++    if (!BN_mod(rsa->dmp1, rsa->d, r1, ctx))
++        goto err;
++
++    /* calculate d mod (q-1) */
++    rsa->dmq1 = BN_new();
++    if (rsa->dmq1 == NULL)
++        goto err;
++    if (!BN_mod(rsa->dmq1, rsa->d, r2, ctx))
++        goto err;
++
++    /* calculate inverse of q mod p */
++    rsa->iqmp = BN_mod_inverse(NULL, rsa->q, rsa->p, ctx2);
++
++    ret = 1;
++ err:
++    if (ctx)
++        BN_CTX_end(ctx);
++    BN_CTX_free(ctx);
++    BN_CTX_free(ctx2);
++
++    return ret;
++
++}
++
++int RSA_X931_generate_key_ex(RSA *rsa, int bits, const BIGNUM *e,
++                             BN_GENCB *cb)
++{
++    int ok = 0;
++    BIGNUM *Xp = NULL, *Xq = NULL;
++    BN_CTX *ctx = NULL;
++
++    ctx = BN_CTX_new();
++    if (ctx == NULL)
++        goto error;
++
++    BN_CTX_start(ctx);
++    Xp = BN_CTX_get(ctx);
++    Xq = BN_CTX_get(ctx);
++    if (!BN_X931_generate_Xpq(Xp, Xq, bits, ctx))
++        goto error;
++
++    rsa->p = BN_new();
++    rsa->q = BN_new();
++    if (rsa->p == NULL || rsa->q == NULL)
++        goto error;
++
++    /* Generate two primes from Xp, Xq */
++
++    if (!BN_X931_generate_prime_ex(rsa->p, NULL, NULL, NULL, NULL, Xp,
++                                   e, ctx, cb))
++        goto error;
++
++    if (!BN_X931_generate_prime_ex(rsa->q, NULL, NULL, NULL, NULL, Xq,
++                                   e, ctx, cb))
++        goto error;
++
++    /*
++     * Since rsa->p and rsa->q are valid this call will just derive remaining
++     * RSA components.
++     */
++
++    if (!RSA_X931_derive_ex(rsa, NULL, NULL, NULL, NULL,
++                            NULL, NULL, NULL, NULL, NULL, NULL, e, cb))
++        goto error;
++
++    ok = 1;
++
++ error:
++    if (ctx)
++        BN_CTX_end(ctx);
++    BN_CTX_free(ctx);
++
++    if (ok)
++        return 1;
++
++    return 0;
++
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/s390xcap.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/s390xcap.c
+new file mode 100644
+index 0000000..675f2ec
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/s390xcap.c
+@@ -0,0 +1,50 @@
++/*
++ * Copyright 2010-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include 
++#include 
++#include 
++#include 
++
++extern unsigned long OPENSSL_s390xcap_P[];
++
++static sigjmp_buf ill_jmp;
++static void ill_handler(int sig)
++{
++    siglongjmp(ill_jmp, sig);
++}
++
++unsigned long OPENSSL_s390x_facilities(void);
++
++void OPENSSL_cpuid_setup(void)
++{
++    sigset_t oset;
++    struct sigaction ill_act, oact;
++
++    if (OPENSSL_s390xcap_P[0])
++        return;
++
++    OPENSSL_s390xcap_P[0] = 1UL << (8 * sizeof(unsigned long) - 1);
++
++    memset(&ill_act, 0, sizeof(ill_act));
++    ill_act.sa_handler = ill_handler;
++    sigfillset(&ill_act.sa_mask);
++    sigdelset(&ill_act.sa_mask, SIGILL);
++    sigdelset(&ill_act.sa_mask, SIGTRAP);
++    sigprocmask(SIG_SETMASK, &ill_act.sa_mask, &oset);
++    sigaction(SIGILL, &ill_act, &oact);
++
++    /* protection against missing store-facility-list-extended */
++    if (sigsetjmp(ill_jmp, 1) == 0)
++        OPENSSL_s390x_facilities();
++
++    sigaction(SIGILL, &oact, NULL);
++    sigprocmask(SIG_SETMASK, &oset, NULL);
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/s390xcpuid.S b/CryptoPkg/Library/OpensslLib/openssl/crypto/s390xcpuid.S
+new file mode 100644
+index 0000000..8859e9e
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/s390xcpuid.S
+@@ -0,0 +1,180 @@
++.text
++// Copyright 2009-2016 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
++// in the file LICENSE in the source distribution or at
++// https://www.openssl.org/source/license.html
++
++.globl	OPENSSL_s390x_facilities
++.type	OPENSSL_s390x_facilities,@function
++.align	16
++OPENSSL_s390x_facilities:
++	lghi	%r0,0
++	larl	%r4,OPENSSL_s390xcap_P
++	stg	%r0,8(%r4)	# wipe capability vectors
++	stg	%r0,16(%r4)
++	stg	%r0,24(%r4)
++	stg	%r0,32(%r4)
++	stg	%r0,40(%r4)
++	stg	%r0,48(%r4)
++	stg	%r0,56(%r4)
++	stg	%r0,64(%r4)
++	stg	%r0,72(%r4)
++
++	.long	0xb2b04000	# stfle	0(%r4)
++	brc	8,.Ldone
++	lghi	%r0,1
++	.long	0xb2b04000	# stfle 0(%r4)
++.Ldone:
++	lmg	%r2,%r3,0(%r4)
++	tmhl	%r2,0x4000	# check for message-security-assist
++	jz	.Lret
++
++	lghi	%r0,0		# query kimd capabilities
++	la	%r1,16(%r4)
++	.long	0xb93e0002	# kimd %r0,%r2
++
++	lghi	%r0,0		# query km capability vector
++	la	%r1,32(%r4)
++	.long	0xb92e0042	# km %r4,%r2
++
++	lghi	%r0,0		# query kmc capability vector
++	la	%r1,48(%r4)
++	.long	0xb92f0042	# kmc %r4,%r2
++
++	tmhh	%r3,0x0004	# check for message-security-assist-4
++	jz	.Lret
++
++	lghi	%r0,0		# query kmctr capability vector
++	la	%r1,64(%r4)
++	.long	0xb92d2042	# kmctr %r4,%r2,%r2
++
++.Lret:
++	br	%r14
++.size	OPENSSL_s390x_facilities,.-OPENSSL_s390x_facilities
++
++.globl	OPENSSL_rdtsc
++.type	OPENSSL_rdtsc,@function
++.align	16
++OPENSSL_rdtsc:
++	stck	16(%r15)
++	lg	%r2,16(%r15)
++	br	%r14
++.size	OPENSSL_rdtsc,.-OPENSSL_rdtsc
++
++.globl	OPENSSL_atomic_add
++.type	OPENSSL_atomic_add,@function
++.align	16
++OPENSSL_atomic_add:
++	l	%r1,0(%r2)
++.Lspin:	lr	%r0,%r1
++	ar	%r0,%r3
++	cs	%r1,%r0,0(%r2)
++	brc	4,.Lspin
++	lgfr	%r2,%r0		# OpenSSL expects the new value
++	br	%r14
++.size	OPENSSL_atomic_add,.-OPENSSL_atomic_add
++
++.globl	OPENSSL_wipe_cpu
++.type	OPENSSL_wipe_cpu,@function
++.align	16
++OPENSSL_wipe_cpu:
++	xgr	%r0,%r0
++	xgr	%r1,%r1
++	lgr	%r2,%r15
++	xgr	%r3,%r3
++	xgr	%r4,%r4
++	lzdr	%f0
++	lzdr	%f1
++	lzdr	%f2
++	lzdr	%f3
++	lzdr	%f4
++	lzdr	%f5
++	lzdr	%f6
++	lzdr	%f7
++	br	%r14
++.size	OPENSSL_wipe_cpu,.-OPENSSL_wipe_cpu
++
++.globl	OPENSSL_cleanse
++.type	OPENSSL_cleanse,@function
++.align	16
++OPENSSL_cleanse:
++#if !defined(__s390x__) && !defined(__s390x)
++	llgfr	%r3,%r3
++#endif
++	lghi	%r4,15
++	lghi	%r0,0
++	clgr	%r3,%r4
++	jh	.Lot
++	clgr	%r3,%r0
++	bcr	8,%r14
++.Little:
++	stc	%r0,0(%r2)
++	la	%r2,1(%r2)
++	brctg	%r3,.Little
++	br	%r14
++.align	4
++.Lot:	tmll	%r2,7
++	jz	.Laligned
++	stc	%r0,0(%r2)
++	la	%r2,1(%r2)
++	brctg	%r3,.Lot
++.Laligned:
++	srlg	%r4,%r3,3
++.Loop:	stg	%r0,0(%r2)
++	la	%r2,8(%r2)
++	brctg	%r4,.Loop
++	lghi	%r4,7
++	ngr	%r3,%r4
++	jnz	.Little
++	br	%r14
++.size	OPENSSL_cleanse,.-OPENSSL_cleanse
++
++.globl	CRYPTO_memcmp
++.type	CRYPTO_memcmp,@function
++.align	16
++CRYPTO_memcmp:
++#if !defined(__s390x__) && !defined(__s390x)
++	llgfr	%r4,%r4
++#endif
++	lghi	%r5,0
++	clgr	%r4,%r5
++	je	.Lno_data
++
++.Loop_cmp:
++	llgc	%r0,0(%r2)
++	la	%r2,1(%r2)
++	llgc	%r1,0(%r3)
++	la	%r3,1(%r3)
++	xr	%r1,%r0
++	or	%r5,%r1
++	brctg	%r4,.Loop_cmp
++
++	lnr	%r5,%r5
++	srl	%r5,31
++.Lno_data:
++	lgr	%r2,%r5
++	br	%r14
++.size	CRYPTO_memcmp,.-CRYPTO_memcmp
++
++.globl	OPENSSL_instrument_bus
++.type	OPENSSL_instrument_bus,@function
++.align	16
++OPENSSL_instrument_bus:
++	lghi	%r2,0
++	br	%r14
++.size	OPENSSL_instrument_bus,.-OPENSSL_instrument_bus
++
++.globl	OPENSSL_instrument_bus2
++.type	OPENSSL_instrument_bus2,@function
++.align	16
++OPENSSL_instrument_bus2:
++	lghi	%r2,0
++	br	%r14
++.size	OPENSSL_instrument_bus2,.-OPENSSL_instrument_bus2
++
++.section	.init
++	brasl	%r14,OPENSSL_cpuid_setup
++
++.comm	OPENSSL_s390xcap_P,80,8
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/seed/build.info b/CryptoPkg/Library/OpensslLib/openssl/crypto/seed/build.info
+new file mode 100644
+index 0000000..abdcbca
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/seed/build.info
+@@ -0,0 +1,2 @@
++LIBS=../../libcrypto
++SOURCE[../../libcrypto]=seed.c seed_ecb.c seed_cbc.c seed_cfb.c seed_ofb.c
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/seed/seed.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/seed/seed.c
+new file mode 100644
+index 0000000..c1e9285
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/seed/seed.c
+@@ -0,0 +1,590 @@
++/*
++ * Copyright 2007-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++/*
++ * Copyright (c) 2007 KISA(Korea Information Security Agency). 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. Neither the name of author nor the names of its contributors may
++ *    be used to endorse or promote products derived from this software
++ *    without specific prior written permission.
++ *
++ * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND
++ * ANY EXPRESS 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 AUTHOR OR 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.
++ *
++ */
++#ifndef OPENSSL_NO_SEED
++
++# include 
++# include 
++# include 
++# ifdef WIN32
++#  include 
++# endif
++
++# include 
++# include "seed_locl.h"
++
++# ifdef SS                      /* can get defined on Solaris by inclusion of
++                                 *  */
++#  undef SS
++# endif
++
++# if !defined(OPENSSL_SMALL_FOOTPRINT)
++
++#  define G_FUNC(v)       \
++        SS[0][(unsigned char)      (v) & 0xff] ^ \
++        SS[1][(unsigned char) ((v)>>8) & 0xff] ^ \
++        SS[2][(unsigned char)((v)>>16) & 0xff] ^ \
++        SS[3][(unsigned char)((v)>>24) & 0xff]
++
++static const seed_word SS[4][256] = {
++    { 0x2989a1a8, 0x05858184, 0x16c6d2d4, 0x13c3d3d0,
++      0x14445054, 0x1d0d111c, 0x2c8ca0ac, 0x25052124,
++      0x1d4d515c, 0x03434340, 0x18081018, 0x1e0e121c,
++      0x11415150, 0x3cccf0fc, 0x0acac2c8, 0x23436360,
++      0x28082028, 0x04444044, 0x20002020, 0x1d8d919c,
++      0x20c0e0e0, 0x22c2e2e0, 0x08c8c0c8, 0x17071314,
++      0x2585a1a4, 0x0f8f838c, 0x03030300, 0x3b4b7378,
++      0x3b8bb3b8, 0x13031310, 0x12c2d2d0, 0x2ecee2ec,
++      0x30407070, 0x0c8c808c, 0x3f0f333c, 0x2888a0a8,
++      0x32023230, 0x1dcdd1dc, 0x36c6f2f4, 0x34447074,
++      0x2ccce0ec, 0x15859194, 0x0b0b0308, 0x17475354,
++      0x1c4c505c, 0x1b4b5358, 0x3d8db1bc, 0x01010100,
++      0x24042024, 0x1c0c101c, 0x33437370, 0x18889098,
++      0x10001010, 0x0cccc0cc, 0x32c2f2f0, 0x19c9d1d8,
++      0x2c0c202c, 0x27c7e3e4, 0x32427270, 0x03838380,
++      0x1b8b9398, 0x11c1d1d0, 0x06868284, 0x09c9c1c8,
++      0x20406060, 0x10405050, 0x2383a3a0, 0x2bcbe3e8,
++      0x0d0d010c, 0x3686b2b4, 0x1e8e929c, 0x0f4f434c,
++      0x3787b3b4, 0x1a4a5258, 0x06c6c2c4, 0x38487078,
++      0x2686a2a4, 0x12021210, 0x2f8fa3ac, 0x15c5d1d4,
++      0x21416160, 0x03c3c3c0, 0x3484b0b4, 0x01414140,
++      0x12425250, 0x3d4d717c, 0x0d8d818c, 0x08080008,
++      0x1f0f131c, 0x19899198, 0x00000000, 0x19091118,
++      0x04040004, 0x13435350, 0x37c7f3f4, 0x21c1e1e0,
++      0x3dcdf1fc, 0x36467274, 0x2f0f232c, 0x27072324,
++      0x3080b0b0, 0x0b8b8388, 0x0e0e020c, 0x2b8ba3a8,
++      0x2282a2a0, 0x2e4e626c, 0x13839390, 0x0d4d414c,
++      0x29496168, 0x3c4c707c, 0x09090108, 0x0a0a0208,
++      0x3f8fb3bc, 0x2fcfe3ec, 0x33c3f3f0, 0x05c5c1c4,
++      0x07878384, 0x14041014, 0x3ecef2fc, 0x24446064,
++      0x1eced2dc, 0x2e0e222c, 0x0b4b4348, 0x1a0a1218,
++      0x06060204, 0x21012120, 0x2b4b6368, 0x26466264,
++      0x02020200, 0x35c5f1f4, 0x12829290, 0x0a8a8288,
++      0x0c0c000c, 0x3383b3b0, 0x3e4e727c, 0x10c0d0d0,
++      0x3a4a7278, 0x07474344, 0x16869294, 0x25c5e1e4,
++      0x26062224, 0x00808080, 0x2d8da1ac, 0x1fcfd3dc,
++      0x2181a1a0, 0x30003030, 0x37073334, 0x2e8ea2ac,
++      0x36063234, 0x15051114, 0x22022220, 0x38083038,
++      0x34c4f0f4, 0x2787a3a4, 0x05454144, 0x0c4c404c,
++      0x01818180, 0x29c9e1e8, 0x04848084, 0x17879394,
++      0x35053134, 0x0bcbc3c8, 0x0ecec2cc, 0x3c0c303c,
++      0x31417170, 0x11011110, 0x07c7c3c4, 0x09898188,
++      0x35457174, 0x3bcbf3f8, 0x1acad2d8, 0x38c8f0f8,
++      0x14849094, 0x19495158, 0x02828280, 0x04c4c0c4,
++      0x3fcff3fc, 0x09494148, 0x39093138, 0x27476364,
++      0x00c0c0c0, 0x0fcfc3cc, 0x17c7d3d4, 0x3888b0b8,
++      0x0f0f030c, 0x0e8e828c, 0x02424240, 0x23032320,
++      0x11819190, 0x2c4c606c, 0x1bcbd3d8, 0x2484a0a4,
++      0x34043034, 0x31c1f1f0, 0x08484048, 0x02c2c2c0,
++      0x2f4f636c, 0x3d0d313c, 0x2d0d212c, 0x00404040,
++      0x3e8eb2bc, 0x3e0e323c, 0x3c8cb0bc, 0x01c1c1c0,
++      0x2a8aa2a8, 0x3a8ab2b8, 0x0e4e424c, 0x15455154,
++      0x3b0b3338, 0x1cccd0dc, 0x28486068, 0x3f4f737c,
++      0x1c8c909c, 0x18c8d0d8, 0x0a4a4248, 0x16465254,
++      0x37477374, 0x2080a0a0, 0x2dcde1ec, 0x06464244,
++      0x3585b1b4, 0x2b0b2328, 0x25456164, 0x3acaf2f8,
++      0x23c3e3e0, 0x3989b1b8, 0x3181b1b0, 0x1f8f939c,
++      0x1e4e525c, 0x39c9f1f8, 0x26c6e2e4, 0x3282b2b0,
++      0x31013130, 0x2acae2e8, 0x2d4d616c, 0x1f4f535c,
++      0x24c4e0e4, 0x30c0f0f0, 0x0dcdc1cc, 0x08888088,
++      0x16061214, 0x3a0a3238, 0x18485058, 0x14c4d0d4,
++      0x22426260, 0x29092128, 0x07070304, 0x33033330,
++      0x28c8e0e8, 0x1b0b1318, 0x05050104, 0x39497178,
++      0x10809090, 0x2a4a6268, 0x2a0a2228, 0x1a8a9298
++    },
++    { 0x38380830, 0xe828c8e0, 0x2c2d0d21, 0xa42686a2,
++      0xcc0fcfc3, 0xdc1eced2, 0xb03383b3, 0xb83888b0,
++      0xac2f8fa3, 0x60204060, 0x54154551, 0xc407c7c3,
++      0x44044440, 0x6c2f4f63, 0x682b4b63, 0x581b4b53,
++      0xc003c3c3, 0x60224262, 0x30330333, 0xb43585b1,
++      0x28290921, 0xa02080a0, 0xe022c2e2, 0xa42787a3,
++      0xd013c3d3, 0x90118191, 0x10110111, 0x04060602,
++      0x1c1c0c10, 0xbc3c8cb0, 0x34360632, 0x480b4b43,
++      0xec2fcfe3, 0x88088880, 0x6c2c4c60, 0xa82888a0,
++      0x14170713, 0xc404c4c0, 0x14160612, 0xf434c4f0,
++      0xc002c2c2, 0x44054541, 0xe021c1e1, 0xd416c6d2,
++      0x3c3f0f33, 0x3c3d0d31, 0x8c0e8e82, 0x98188890,
++      0x28280820, 0x4c0e4e42, 0xf436c6f2, 0x3c3e0e32,
++      0xa42585a1, 0xf839c9f1, 0x0c0d0d01, 0xdc1fcfd3,
++      0xd818c8d0, 0x282b0b23, 0x64264662, 0x783a4a72,
++      0x24270723, 0x2c2f0f23, 0xf031c1f1, 0x70324272,
++      0x40024242, 0xd414c4d0, 0x40014141, 0xc000c0c0,
++      0x70334373, 0x64274763, 0xac2c8ca0, 0x880b8b83,
++      0xf437c7f3, 0xac2d8da1, 0x80008080, 0x1c1f0f13,
++      0xc80acac2, 0x2c2c0c20, 0xa82a8aa2, 0x34340430,
++      0xd012c2d2, 0x080b0b03, 0xec2ecee2, 0xe829c9e1,
++      0x5c1d4d51, 0x94148490, 0x18180810, 0xf838c8f0,
++      0x54174753, 0xac2e8ea2, 0x08080800, 0xc405c5c1,
++      0x10130313, 0xcc0dcdc1, 0x84068682, 0xb83989b1,
++      0xfc3fcff3, 0x7c3d4d71, 0xc001c1c1, 0x30310131,
++      0xf435c5f1, 0x880a8a82, 0x682a4a62, 0xb03181b1,
++      0xd011c1d1, 0x20200020, 0xd417c7d3, 0x00020202,
++      0x20220222, 0x04040400, 0x68284860, 0x70314171,
++      0x04070703, 0xd81bcbd3, 0x9c1d8d91, 0x98198991,
++      0x60214161, 0xbc3e8eb2, 0xe426c6e2, 0x58194951,
++      0xdc1dcdd1, 0x50114151, 0x90108090, 0xdc1cccd0,
++      0x981a8a92, 0xa02383a3, 0xa82b8ba3, 0xd010c0d0,
++      0x80018181, 0x0c0f0f03, 0x44074743, 0x181a0a12,
++      0xe023c3e3, 0xec2ccce0, 0x8c0d8d81, 0xbc3f8fb3,
++      0x94168692, 0x783b4b73, 0x5c1c4c50, 0xa02282a2,
++      0xa02181a1, 0x60234363, 0x20230323, 0x4c0d4d41,
++      0xc808c8c0, 0x9c1e8e92, 0x9c1c8c90, 0x383a0a32,
++      0x0c0c0c00, 0x2c2e0e22, 0xb83a8ab2, 0x6c2e4e62,
++      0x9c1f8f93, 0x581a4a52, 0xf032c2f2, 0x90128292,
++      0xf033c3f3, 0x48094941, 0x78384870, 0xcc0cccc0,
++      0x14150511, 0xf83bcbf3, 0x70304070, 0x74354571,
++      0x7c3f4f73, 0x34350531, 0x10100010, 0x00030303,
++      0x64244460, 0x6c2d4d61, 0xc406c6c2, 0x74344470,
++      0xd415c5d1, 0xb43484b0, 0xe82acae2, 0x08090901,
++      0x74364672, 0x18190911, 0xfc3ecef2, 0x40004040,
++      0x10120212, 0xe020c0e0, 0xbc3d8db1, 0x04050501,
++      0xf83acaf2, 0x00010101, 0xf030c0f0, 0x282a0a22,
++      0x5c1e4e52, 0xa82989a1, 0x54164652, 0x40034343,
++      0x84058581, 0x14140410, 0x88098981, 0x981b8b93,
++      0xb03080b0, 0xe425c5e1, 0x48084840, 0x78394971,
++      0x94178793, 0xfc3cccf0, 0x1c1e0e12, 0x80028282,
++      0x20210121, 0x8c0c8c80, 0x181b0b13, 0x5c1f4f53,
++      0x74374773, 0x54144450, 0xb03282b2, 0x1c1d0d11,
++      0x24250521, 0x4c0f4f43, 0x00000000, 0x44064642,
++      0xec2dcde1, 0x58184850, 0x50124252, 0xe82bcbe3,
++      0x7c3e4e72, 0xd81acad2, 0xc809c9c1, 0xfc3dcdf1,
++      0x30300030, 0x94158591, 0x64254561, 0x3c3c0c30,
++      0xb43686b2, 0xe424c4e0, 0xb83b8bb3, 0x7c3c4c70,
++      0x0c0e0e02, 0x50104050, 0x38390931, 0x24260622,
++      0x30320232, 0x84048480, 0x68294961, 0x90138393,
++      0x34370733, 0xe427c7e3, 0x24240420, 0xa42484a0,
++      0xc80bcbc3, 0x50134353, 0x080a0a02, 0x84078783,
++      0xd819c9d1, 0x4c0c4c40, 0x80038383, 0x8c0f8f83,
++      0xcc0ecec2, 0x383b0b33, 0x480a4a42, 0xb43787b3
++    },
++    { 0xa1a82989, 0x81840585, 0xd2d416c6, 0xd3d013c3,
++      0x50541444, 0x111c1d0d, 0xa0ac2c8c, 0x21242505,
++      0x515c1d4d, 0x43400343, 0x10181808, 0x121c1e0e,
++      0x51501141, 0xf0fc3ccc, 0xc2c80aca, 0x63602343,
++      0x20282808, 0x40440444, 0x20202000, 0x919c1d8d,
++      0xe0e020c0, 0xe2e022c2, 0xc0c808c8, 0x13141707,
++      0xa1a42585, 0x838c0f8f, 0x03000303, 0x73783b4b,
++      0xb3b83b8b, 0x13101303, 0xd2d012c2, 0xe2ec2ece,
++      0x70703040, 0x808c0c8c, 0x333c3f0f, 0xa0a82888,
++      0x32303202, 0xd1dc1dcd, 0xf2f436c6, 0x70743444,
++      0xe0ec2ccc, 0x91941585, 0x03080b0b, 0x53541747,
++      0x505c1c4c, 0x53581b4b, 0xb1bc3d8d, 0x01000101,
++      0x20242404, 0x101c1c0c, 0x73703343, 0x90981888,
++      0x10101000, 0xc0cc0ccc, 0xf2f032c2, 0xd1d819c9,
++      0x202c2c0c, 0xe3e427c7, 0x72703242, 0x83800383,
++      0x93981b8b, 0xd1d011c1, 0x82840686, 0xc1c809c9,
++      0x60602040, 0x50501040, 0xa3a02383, 0xe3e82bcb,
++      0x010c0d0d, 0xb2b43686, 0x929c1e8e, 0x434c0f4f,
++      0xb3b43787, 0x52581a4a, 0xc2c406c6, 0x70783848,
++      0xa2a42686, 0x12101202, 0xa3ac2f8f, 0xd1d415c5,
++      0x61602141, 0xc3c003c3, 0xb0b43484, 0x41400141,
++      0x52501242, 0x717c3d4d, 0x818c0d8d, 0x00080808,
++      0x131c1f0f, 0x91981989, 0x00000000, 0x11181909,
++      0x00040404, 0x53501343, 0xf3f437c7, 0xe1e021c1,
++      0xf1fc3dcd, 0x72743646, 0x232c2f0f, 0x23242707,
++      0xb0b03080, 0x83880b8b, 0x020c0e0e, 0xa3a82b8b,
++      0xa2a02282, 0x626c2e4e, 0x93901383, 0x414c0d4d,
++      0x61682949, 0x707c3c4c, 0x01080909, 0x02080a0a,
++      0xb3bc3f8f, 0xe3ec2fcf, 0xf3f033c3, 0xc1c405c5,
++      0x83840787, 0x10141404, 0xf2fc3ece, 0x60642444,
++      0xd2dc1ece, 0x222c2e0e, 0x43480b4b, 0x12181a0a,
++      0x02040606, 0x21202101, 0x63682b4b, 0x62642646,
++      0x02000202, 0xf1f435c5, 0x92901282, 0x82880a8a,
++      0x000c0c0c, 0xb3b03383, 0x727c3e4e, 0xd0d010c0,
++      0x72783a4a, 0x43440747, 0x92941686, 0xe1e425c5,
++      0x22242606, 0x80800080, 0xa1ac2d8d, 0xd3dc1fcf,
++      0xa1a02181, 0x30303000, 0x33343707, 0xa2ac2e8e,
++      0x32343606, 0x11141505, 0x22202202, 0x30383808,
++      0xf0f434c4, 0xa3a42787, 0x41440545, 0x404c0c4c,
++      0x81800181, 0xe1e829c9, 0x80840484, 0x93941787,
++      0x31343505, 0xc3c80bcb, 0xc2cc0ece, 0x303c3c0c,
++      0x71703141, 0x11101101, 0xc3c407c7, 0x81880989,
++      0x71743545, 0xf3f83bcb, 0xd2d81aca, 0xf0f838c8,
++      0x90941484, 0x51581949, 0x82800282, 0xc0c404c4,
++      0xf3fc3fcf, 0x41480949, 0x31383909, 0x63642747,
++      0xc0c000c0, 0xc3cc0fcf, 0xd3d417c7, 0xb0b83888,
++      0x030c0f0f, 0x828c0e8e, 0x42400242, 0x23202303,
++      0x91901181, 0x606c2c4c, 0xd3d81bcb, 0xa0a42484,
++      0x30343404, 0xf1f031c1, 0x40480848, 0xc2c002c2,
++      0x636c2f4f, 0x313c3d0d, 0x212c2d0d, 0x40400040,
++      0xb2bc3e8e, 0x323c3e0e, 0xb0bc3c8c, 0xc1c001c1,
++      0xa2a82a8a, 0xb2b83a8a, 0x424c0e4e, 0x51541545,
++      0x33383b0b, 0xd0dc1ccc, 0x60682848, 0x737c3f4f,
++      0x909c1c8c, 0xd0d818c8, 0x42480a4a, 0x52541646,
++      0x73743747, 0xa0a02080, 0xe1ec2dcd, 0x42440646,
++      0xb1b43585, 0x23282b0b, 0x61642545, 0xf2f83aca,
++      0xe3e023c3, 0xb1b83989, 0xb1b03181, 0x939c1f8f,
++      0x525c1e4e, 0xf1f839c9, 0xe2e426c6, 0xb2b03282,
++      0x31303101, 0xe2e82aca, 0x616c2d4d, 0x535c1f4f,
++      0xe0e424c4, 0xf0f030c0, 0xc1cc0dcd, 0x80880888,
++      0x12141606, 0x32383a0a, 0x50581848, 0xd0d414c4,
++      0x62602242, 0x21282909, 0x03040707, 0x33303303,
++      0xe0e828c8, 0x13181b0b, 0x01040505, 0x71783949,
++      0x90901080, 0x62682a4a, 0x22282a0a, 0x92981a8a
++    },
++    { 0x08303838, 0xc8e0e828, 0x0d212c2d, 0x86a2a426,
++      0xcfc3cc0f, 0xced2dc1e, 0x83b3b033, 0x88b0b838,
++      0x8fa3ac2f, 0x40606020, 0x45515415, 0xc7c3c407,
++      0x44404404, 0x4f636c2f, 0x4b63682b, 0x4b53581b,
++      0xc3c3c003, 0x42626022, 0x03333033, 0x85b1b435,
++      0x09212829, 0x80a0a020, 0xc2e2e022, 0x87a3a427,
++      0xc3d3d013, 0x81919011, 0x01111011, 0x06020406,
++      0x0c101c1c, 0x8cb0bc3c, 0x06323436, 0x4b43480b,
++      0xcfe3ec2f, 0x88808808, 0x4c606c2c, 0x88a0a828,
++      0x07131417, 0xc4c0c404, 0x06121416, 0xc4f0f434,
++      0xc2c2c002, 0x45414405, 0xc1e1e021, 0xc6d2d416,
++      0x0f333c3f, 0x0d313c3d, 0x8e828c0e, 0x88909818,
++      0x08202828, 0x4e424c0e, 0xc6f2f436, 0x0e323c3e,
++      0x85a1a425, 0xc9f1f839, 0x0d010c0d, 0xcfd3dc1f,
++      0xc8d0d818, 0x0b23282b, 0x46626426, 0x4a72783a,
++      0x07232427, 0x0f232c2f, 0xc1f1f031, 0x42727032,
++      0x42424002, 0xc4d0d414, 0x41414001, 0xc0c0c000,
++      0x43737033, 0x47636427, 0x8ca0ac2c, 0x8b83880b,
++      0xc7f3f437, 0x8da1ac2d, 0x80808000, 0x0f131c1f,
++      0xcac2c80a, 0x0c202c2c, 0x8aa2a82a, 0x04303434,
++      0xc2d2d012, 0x0b03080b, 0xcee2ec2e, 0xc9e1e829,
++      0x4d515c1d, 0x84909414, 0x08101818, 0xc8f0f838,
++      0x47535417, 0x8ea2ac2e, 0x08000808, 0xc5c1c405,
++      0x03131013, 0xcdc1cc0d, 0x86828406, 0x89b1b839,
++      0xcff3fc3f, 0x4d717c3d, 0xc1c1c001, 0x01313031,
++      0xc5f1f435, 0x8a82880a, 0x4a62682a, 0x81b1b031,
++      0xc1d1d011, 0x00202020, 0xc7d3d417, 0x02020002,
++      0x02222022, 0x04000404, 0x48606828, 0x41717031,
++      0x07030407, 0xcbd3d81b, 0x8d919c1d, 0x89919819,
++      0x41616021, 0x8eb2bc3e, 0xc6e2e426, 0x49515819,
++      0xcdd1dc1d, 0x41515011, 0x80909010, 0xccd0dc1c,
++      0x8a92981a, 0x83a3a023, 0x8ba3a82b, 0xc0d0d010,
++      0x81818001, 0x0f030c0f, 0x47434407, 0x0a12181a,
++      0xc3e3e023, 0xcce0ec2c, 0x8d818c0d, 0x8fb3bc3f,
++      0x86929416, 0x4b73783b, 0x4c505c1c, 0x82a2a022,
++      0x81a1a021, 0x43636023, 0x03232023, 0x4d414c0d,
++      0xc8c0c808, 0x8e929c1e, 0x8c909c1c, 0x0a32383a,
++      0x0c000c0c, 0x0e222c2e, 0x8ab2b83a, 0x4e626c2e,
++      0x8f939c1f, 0x4a52581a, 0xc2f2f032, 0x82929012,
++      0xc3f3f033, 0x49414809, 0x48707838, 0xccc0cc0c,
++      0x05111415, 0xcbf3f83b, 0x40707030, 0x45717435,
++      0x4f737c3f, 0x05313435, 0x00101010, 0x03030003,
++      0x44606424, 0x4d616c2d, 0xc6c2c406, 0x44707434,
++      0xc5d1d415, 0x84b0b434, 0xcae2e82a, 0x09010809,
++      0x46727436, 0x09111819, 0xcef2fc3e, 0x40404000,
++      0x02121012, 0xc0e0e020, 0x8db1bc3d, 0x05010405,
++      0xcaf2f83a, 0x01010001, 0xc0f0f030, 0x0a22282a,
++      0x4e525c1e, 0x89a1a829, 0x46525416, 0x43434003,
++      0x85818405, 0x04101414, 0x89818809, 0x8b93981b,
++      0x80b0b030, 0xc5e1e425, 0x48404808, 0x49717839,
++      0x87939417, 0xccf0fc3c, 0x0e121c1e, 0x82828002,
++      0x01212021, 0x8c808c0c, 0x0b13181b, 0x4f535c1f,
++      0x47737437, 0x44505414, 0x82b2b032, 0x0d111c1d,
++      0x05212425, 0x4f434c0f, 0x00000000, 0x46424406,
++      0xcde1ec2d, 0x48505818, 0x42525012, 0xcbe3e82b,
++      0x4e727c3e, 0xcad2d81a, 0xc9c1c809, 0xcdf1fc3d,
++      0x00303030, 0x85919415, 0x45616425, 0x0c303c3c,
++      0x86b2b436, 0xc4e0e424, 0x8bb3b83b, 0x4c707c3c,
++      0x0e020c0e, 0x40505010, 0x09313839, 0x06222426,
++      0x02323032, 0x84808404, 0x49616829, 0x83939013,
++      0x07333437, 0xc7e3e427, 0x04202424, 0x84a0a424,
++      0xcbc3c80b, 0x43535013, 0x0a02080a, 0x87838407,
++      0xc9d1d819, 0x4c404c0c, 0x83838003, 0x8f838c0f,
++      0xcec2cc0e, 0x0b33383b, 0x4a42480a, 0x87b3b437
++    }
++};
++
++#else
++
++/* on x86_64 >5x size reduction at 40% performance penalty */
++static const unsigned char SEED_Sbox[2][256] = {
++{
++      0xA9, 0x85, 0xD6, 0xD3, 0x54, 0x1D, 0xAC, 0x25,
++      0x5D, 0x43, 0x18, 0x1E, 0x51, 0xFC, 0xCA, 0x63,
++      0x28, 0x44, 0x20, 0x9D, 0xE0, 0xE2, 0xC8, 0x17,
++      0xA5, 0x8F, 0x03, 0x7B, 0xBB, 0x13, 0xD2, 0xEE,
++      0x70, 0x8C, 0x3F, 0xA8, 0x32, 0xDD, 0xF6, 0x74,
++      0xEC, 0x95, 0x0B, 0x57, 0x5C, 0x5B, 0xBD, 0x01,
++      0x24, 0x1C, 0x73, 0x98, 0x10, 0xCC, 0xF2, 0xD9,
++      0x2C, 0xE7, 0x72, 0x83, 0x9B, 0xD1, 0x86, 0xC9,
++      0x60, 0x50, 0xA3, 0xEB, 0x0D, 0xB6, 0x9E, 0x4F,
++      0xB7, 0x5A, 0xC6, 0x78, 0xA6, 0x12, 0xAF, 0xD5,
++      0x61, 0xC3, 0xB4, 0x41, 0x52, 0x7D, 0x8D, 0x08,
++      0x1F, 0x99, 0x00, 0x19, 0x04, 0x53, 0xF7, 0xE1,
++      0xFD, 0x76, 0x2F, 0x27, 0xB0, 0x8B, 0x0E, 0xAB,
++      0xA2, 0x6E, 0x93, 0x4D, 0x69, 0x7C, 0x09, 0x0A,
++      0xBF, 0xEF, 0xF3, 0xC5, 0x87, 0x14, 0xFE, 0x64,
++      0xDE, 0x2E, 0x4B, 0x1A, 0x06, 0x21, 0x6B, 0x66,
++      0x02, 0xF5, 0x92, 0x8A, 0x0C, 0xB3, 0x7E, 0xD0,
++      0x7A, 0x47, 0x96, 0xE5, 0x26, 0x80, 0xAD, 0xDF,
++      0xA1, 0x30, 0x37, 0xAE, 0x36, 0x15, 0x22, 0x38,
++      0xF4, 0xA7, 0x45, 0x4C, 0x81, 0xE9, 0x84, 0x97,
++      0x35, 0xCB, 0xCE, 0x3C, 0x71, 0x11, 0xC7, 0x89,
++      0x75, 0xFB, 0xDA, 0xF8, 0x94, 0x59, 0x82, 0xC4,
++      0xFF, 0x49, 0x39, 0x67, 0xC0, 0xCF, 0xD7, 0xB8,
++      0x0F, 0x8E, 0x42, 0x23, 0x91, 0x6C, 0xDB, 0xA4,
++      0x34, 0xF1, 0x48, 0xC2, 0x6F, 0x3D, 0x2D, 0x40,
++      0xBE, 0x3E, 0xBC, 0xC1, 0xAA, 0xBA, 0x4E, 0x55,
++      0x3B, 0xDC, 0x68, 0x7F, 0x9C, 0xD8, 0x4A, 0x56,
++      0x77, 0xA0, 0xED, 0x46, 0xB5, 0x2B, 0x65, 0xFA,
++      0xE3, 0xB9, 0xB1, 0x9F, 0x5E, 0xF9, 0xE6, 0xB2,
++      0x31, 0xEA, 0x6D, 0x5F, 0xE4, 0xF0, 0xCD, 0x88,
++      0x16, 0x3A, 0x58, 0xD4, 0x62, 0x29, 0x07, 0x33,
++      0xE8, 0x1B, 0x05, 0x79, 0x90, 0x6A, 0x2A, 0x9A
++    },
++    {
++      0x38, 0xE8, 0x2D, 0xA6, 0xCF, 0xDE, 0xB3, 0xB8,
++      0xAF, 0x60, 0x55, 0xC7, 0x44, 0x6F, 0x6B, 0x5B,
++      0xC3, 0x62, 0x33, 0xB5, 0x29, 0xA0, 0xE2, 0xA7,
++      0xD3, 0x91, 0x11, 0x06, 0x1C, 0xBC, 0x36, 0x4B,
++      0xEF, 0x88, 0x6C, 0xA8, 0x17, 0xC4, 0x16, 0xF4,
++      0xC2, 0x45, 0xE1, 0xD6, 0x3F, 0x3D, 0x8E, 0x98,
++      0x28, 0x4E, 0xF6, 0x3E, 0xA5, 0xF9, 0x0D, 0xDF,
++      0xD8, 0x2B, 0x66, 0x7A, 0x27, 0x2F, 0xF1, 0x72,
++      0x42, 0xD4, 0x41, 0xC0, 0x73, 0x67, 0xAC, 0x8B,
++      0xF7, 0xAD, 0x80, 0x1F, 0xCA, 0x2C, 0xAA, 0x34,
++      0xD2, 0x0B, 0xEE, 0xE9, 0x5D, 0x94, 0x18, 0xF8,
++      0x57, 0xAE, 0x08, 0xC5, 0x13, 0xCD, 0x86, 0xB9,
++      0xFF, 0x7D, 0xC1, 0x31, 0xF5, 0x8A, 0x6A, 0xB1,
++      0xD1, 0x20, 0xD7, 0x02, 0x22, 0x04, 0x68, 0x71,
++      0x07, 0xDB, 0x9D, 0x99, 0x61, 0xBE, 0xE6, 0x59,
++      0xDD, 0x51, 0x90, 0xDC, 0x9A, 0xA3, 0xAB, 0xD0,
++      0x81, 0x0F, 0x47, 0x1A, 0xE3, 0xEC, 0x8D, 0xBF,
++      0x96, 0x7B, 0x5C, 0xA2, 0xA1, 0x63, 0x23, 0x4D,
++      0xC8, 0x9E, 0x9C, 0x3A, 0x0C, 0x2E, 0xBA, 0x6E,
++      0x9F, 0x5A, 0xF2, 0x92, 0xF3, 0x49, 0x78, 0xCC,
++      0x15, 0xFB, 0x70, 0x75, 0x7F, 0x35, 0x10, 0x03,
++      0x64, 0x6D, 0xC6, 0x74, 0xD5, 0xB4, 0xEA, 0x09,
++      0x76, 0x19, 0xFE, 0x40, 0x12, 0xE0, 0xBD, 0x05,
++      0xFA, 0x01, 0xF0, 0x2A, 0x5E, 0xA9, 0x56, 0x43,
++      0x85, 0x14, 0x89, 0x9B, 0xB0, 0xE5, 0x48, 0x79,
++      0x97, 0xFC, 0x1E, 0x82, 0x21, 0x8C, 0x1B, 0x5F,
++      0x77, 0x54, 0xB2, 0x1D, 0x25, 0x4F, 0x00, 0x46,
++      0xED, 0x58, 0x52, 0xEB, 0x7E, 0xDA, 0xC9, 0xFD,
++      0x30, 0x95, 0x65, 0x3C, 0xB6, 0xE4, 0xBB, 0x7C,
++      0x0E, 0x50, 0x39, 0x26, 0x32, 0x84, 0x69, 0x93,
++      0x37, 0xE7, 0x24, 0xA4, 0xCB, 0x53, 0x0A, 0x87,
++      0xD9, 0x4C, 0x83, 0x8F, 0xCE, 0x3B, 0x4A, 0xB7
++    }
++};
++
++static unsigned int G_FUNC(unsigned int v)
++{
++    unsigned int s0, s1, s2, s3, ret;
++
++    s0 = SEED_Sbox[0][(unsigned char)      (v) & 0xff];
++    s1 = SEED_Sbox[1][(unsigned char)((v)>> 8) & 0xff];
++    s2 = SEED_Sbox[0][(unsigned char)((v)>>16) & 0xff];
++    s3 = SEED_Sbox[1][(unsigned char)((v)>>24) & 0xff];
++
++    ret  = ((s0 & 0xFC) ^ (s1 & 0xF3) ^ (s2 & 0xCF) ^ (s3 & 0x3F));
++    ret |= ((s0 & 0xF3) ^ (s1 & 0xCF) ^ (s2 & 0x3F) ^ (s3 & 0xFC)) << 8;
++    ret |= ((s0 & 0xCF) ^ (s1 & 0x3F) ^ (s2 & 0xFC) ^ (s3 & 0xF3)) << 16;
++    ret |= ((s0 & 0x3F) ^ (s1 & 0xFC) ^ (s2 & 0xF3) ^ (s3 & 0xCF)) << 24;
++
++    return ret;
++}
++# endif
++
++/* key schedule constants - golden ratio */
++# define KC0     0x9e3779b9
++# define KC1     0x3c6ef373
++# define KC2     0x78dde6e6
++# define KC3     0xf1bbcdcc
++# define KC4     0xe3779b99
++# define KC5     0xc6ef3733
++# define KC6     0x8dde6e67
++# define KC7     0x1bbcdccf
++# define KC8     0x3779b99e
++# define KC9     0x6ef3733c
++# define KC10    0xdde6e678
++# define KC11    0xbbcdccf1
++# define KC12    0x779b99e3
++# define KC13    0xef3733c6
++# define KC14    0xde6e678d
++# define KC15    0xbcdccf1b
++
++# if defined(OPENSSL_SMALL_FOOTPRINT)
++static const seed_word KC[] = {
++    KC0, KC1, KC2, KC3, KC4, KC5, KC6, KC7,
++    KC8, KC9, KC10, KC11, KC12, KC13, KC14, KC15
++};
++# endif
++
++void SEED_set_key(const unsigned char rawkey[SEED_KEY_LENGTH],
++                  SEED_KEY_SCHEDULE *ks)
++{
++    seed_word x1, x2, x3, x4;
++    seed_word t0, t1;
++
++    char2word(rawkey, x1);
++    char2word(rawkey + 4, x2);
++    char2word(rawkey + 8, x3);
++    char2word(rawkey + 12, x4);
++
++    t0 = (x1 + x3 - KC0) & 0xffffffff;
++    t1 = (x2 - x4 + KC0) & 0xffffffff;
++    KEYUPDATE_TEMP(t0, t1, &ks->data[0]);
++    KEYSCHEDULE_UPDATE1(t0, t1, x1, x2, x3, x4, KC1);
++    KEYUPDATE_TEMP(t0, t1, &ks->data[2]);
++
++# if !defined(OPENSSL_SMALL_FOOTPRINT)
++    KEYSCHEDULE_UPDATE0(t0, t1, x1, x2, x3, x4, KC2);
++    KEYUPDATE_TEMP(t0, t1, &ks->data[4]);
++    KEYSCHEDULE_UPDATE1(t0, t1, x1, x2, x3, x4, KC3);
++    KEYUPDATE_TEMP(t0, t1, &ks->data[6]);
++    KEYSCHEDULE_UPDATE0(t0, t1, x1, x2, x3, x4, KC4);
++    KEYUPDATE_TEMP(t0, t1, &ks->data[8]);
++    KEYSCHEDULE_UPDATE1(t0, t1, x1, x2, x3, x4, KC5);
++    KEYUPDATE_TEMP(t0, t1, &ks->data[10]);
++    KEYSCHEDULE_UPDATE0(t0, t1, x1, x2, x3, x4, KC6);
++    KEYUPDATE_TEMP(t0, t1, &ks->data[12]);
++    KEYSCHEDULE_UPDATE1(t0, t1, x1, x2, x3, x4, KC7);
++    KEYUPDATE_TEMP(t0, t1, &ks->data[14]);
++    KEYSCHEDULE_UPDATE0(t0, t1, x1, x2, x3, x4, KC8);
++    KEYUPDATE_TEMP(t0, t1, &ks->data[16]);
++    KEYSCHEDULE_UPDATE1(t0, t1, x1, x2, x3, x4, KC9);
++    KEYUPDATE_TEMP(t0, t1, &ks->data[18]);
++    KEYSCHEDULE_UPDATE0(t0, t1, x1, x2, x3, x4, KC10);
++    KEYUPDATE_TEMP(t0, t1, &ks->data[20]);
++    KEYSCHEDULE_UPDATE1(t0, t1, x1, x2, x3, x4, KC11);
++    KEYUPDATE_TEMP(t0, t1, &ks->data[22]);
++    KEYSCHEDULE_UPDATE0(t0, t1, x1, x2, x3, x4, KC12);
++    KEYUPDATE_TEMP(t0, t1, &ks->data[24]);
++    KEYSCHEDULE_UPDATE1(t0, t1, x1, x2, x3, x4, KC13);
++    KEYUPDATE_TEMP(t0, t1, &ks->data[26]);
++    KEYSCHEDULE_UPDATE0(t0, t1, x1, x2, x3, x4, KC14);
++    KEYUPDATE_TEMP(t0, t1, &ks->data[28]);
++    KEYSCHEDULE_UPDATE1(t0, t1, x1, x2, x3, x4, KC15);
++    KEYUPDATE_TEMP(t0, t1, &ks->data[30]);
++# else
++    {
++        int i;
++        for (i = 2; i < 16; i += 2) {
++            KEYSCHEDULE_UPDATE0(t0, t1, x1, x2, x3, x4, KC[i]);
++            KEYUPDATE_TEMP(t0, t1, &ks->data[i * 2]);
++            KEYSCHEDULE_UPDATE1(t0, t1, x1, x2, x3, x4, KC[i + 1]);
++            KEYUPDATE_TEMP(t0, t1, &ks->data[i * 2 + 2]);
++        }
++    }
++# endif
++}
++
++void SEED_encrypt(const unsigned char s[SEED_BLOCK_SIZE],
++                  unsigned char d[SEED_BLOCK_SIZE],
++                  const SEED_KEY_SCHEDULE *ks)
++{
++    seed_word x1, x2, x3, x4;
++    seed_word t0, t1;
++
++    char2word(s, x1);
++    char2word(s + 4, x2);
++    char2word(s + 8, x3);
++    char2word(s + 12, x4);
++
++# if !defined(OPENSSL_SMALL_FOOTPRINT)
++    E_SEED(t0, t1, x1, x2, x3, x4, 0);
++    E_SEED(t0, t1, x3, x4, x1, x2, 2);
++    E_SEED(t0, t1, x1, x2, x3, x4, 4);
++    E_SEED(t0, t1, x3, x4, x1, x2, 6);
++    E_SEED(t0, t1, x1, x2, x3, x4, 8);
++    E_SEED(t0, t1, x3, x4, x1, x2, 10);
++    E_SEED(t0, t1, x1, x2, x3, x4, 12);
++    E_SEED(t0, t1, x3, x4, x1, x2, 14);
++    E_SEED(t0, t1, x1, x2, x3, x4, 16);
++    E_SEED(t0, t1, x3, x4, x1, x2, 18);
++    E_SEED(t0, t1, x1, x2, x3, x4, 20);
++    E_SEED(t0, t1, x3, x4, x1, x2, 22);
++    E_SEED(t0, t1, x1, x2, x3, x4, 24);
++    E_SEED(t0, t1, x3, x4, x1, x2, 26);
++    E_SEED(t0, t1, x1, x2, x3, x4, 28);
++    E_SEED(t0, t1, x3, x4, x1, x2, 30);
++# else
++    {
++        int i;
++        for (i = 0; i < 30; i += 4) {
++            E_SEED(t0, t1, x1, x2, x3, x4, i);
++            E_SEED(t0, t1, x3, x4, x1, x2, i + 2);
++        }
++    }
++# endif
++
++    word2char(x3, d);
++    word2char(x4, d + 4);
++    word2char(x1, d + 8);
++    word2char(x2, d + 12);
++}
++
++void SEED_decrypt(const unsigned char s[SEED_BLOCK_SIZE],
++                  unsigned char d[SEED_BLOCK_SIZE],
++                  const SEED_KEY_SCHEDULE *ks)
++{
++    seed_word x1, x2, x3, x4;
++    seed_word t0, t1;
++
++    char2word(s, x1);
++    char2word(s + 4, x2);
++    char2word(s + 8, x3);
++    char2word(s + 12, x4);
++
++# if !defined(OPENSSL_SMALL_FOOTPRINT)
++    E_SEED(t0, t1, x1, x2, x3, x4, 30);
++    E_SEED(t0, t1, x3, x4, x1, x2, 28);
++    E_SEED(t0, t1, x1, x2, x3, x4, 26);
++    E_SEED(t0, t1, x3, x4, x1, x2, 24);
++    E_SEED(t0, t1, x1, x2, x3, x4, 22);
++    E_SEED(t0, t1, x3, x4, x1, x2, 20);
++    E_SEED(t0, t1, x1, x2, x3, x4, 18);
++    E_SEED(t0, t1, x3, x4, x1, x2, 16);
++    E_SEED(t0, t1, x1, x2, x3, x4, 14);
++    E_SEED(t0, t1, x3, x4, x1, x2, 12);
++    E_SEED(t0, t1, x1, x2, x3, x4, 10);
++    E_SEED(t0, t1, x3, x4, x1, x2, 8);
++    E_SEED(t0, t1, x1, x2, x3, x4, 6);
++    E_SEED(t0, t1, x3, x4, x1, x2, 4);
++    E_SEED(t0, t1, x1, x2, x3, x4, 2);
++    E_SEED(t0, t1, x3, x4, x1, x2, 0);
++# else
++    {
++        int i;
++        for (i = 30; i > 0; i -= 4) {
++            E_SEED(t0, t1, x1, x2, x3, x4, i);
++            E_SEED(t0, t1, x3, x4, x1, x2, i - 2);
++
++        }
++    }
++# endif
++
++    word2char(x3, d);
++    word2char(x4, d + 4);
++    word2char(x1, d + 8);
++    word2char(x2, d + 12);
++}
++
++#endif                          /* OPENSSL_NO_SEED */
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/seed/seed_cbc.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/seed/seed_cbc.c
+new file mode 100644
+index 0000000..c9a4fe2
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/seed/seed_cbc.c
+@@ -0,0 +1,23 @@
++/*
++ * Copyright 2007-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include 
++
++void SEED_cbc_encrypt(const unsigned char *in, unsigned char *out,
++                      size_t len, const SEED_KEY_SCHEDULE *ks,
++                      unsigned char ivec[SEED_BLOCK_SIZE], int enc)
++{
++    if (enc)
++        CRYPTO_cbc128_encrypt(in, out, len, ks, ivec,
++                              (block128_f) SEED_encrypt);
++    else
++        CRYPTO_cbc128_decrypt(in, out, len, ks, ivec,
++                              (block128_f) SEED_decrypt);
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/seed/seed_cfb.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/seed/seed_cfb.c
+new file mode 100644
+index 0000000..2aee1ff
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/seed/seed_cfb.c
+@@ -0,0 +1,20 @@
++/*
++ * Copyright 2007-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include 
++
++void SEED_cfb128_encrypt(const unsigned char *in, unsigned char *out,
++                         size_t len, const SEED_KEY_SCHEDULE *ks,
++                         unsigned char ivec[SEED_BLOCK_SIZE], int *num,
++                         int enc)
++{
++    CRYPTO_cfb128_encrypt(in, out, len, ks, ivec, num, enc,
++                          (block128_f) SEED_encrypt);
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/seed/seed_ecb.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/seed/seed_ecb.c
+new file mode 100644
+index 0000000..b6e301c
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/seed/seed_ecb.c
+@@ -0,0 +1,19 @@
++/*
++ * Copyright 2007-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++
++void SEED_ecb_encrypt(const unsigned char *in, unsigned char *out,
++                      const SEED_KEY_SCHEDULE *ks, int enc)
++{
++    if (enc)
++        SEED_encrypt(in, out, ks);
++    else
++        SEED_decrypt(in, out, ks);
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/seed/seed_locl.h b/CryptoPkg/Library/OpensslLib/openssl/crypto/seed/seed_locl.h
+new file mode 100644
+index 0000000..d4a03fc
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/seed/seed_locl.h
+@@ -0,0 +1,120 @@
++/*
++ * Copyright 2007-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++/*
++ * Copyright (c) 2007 KISA(Korea Information Security Agency). 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. Neither the name of author nor the names of its contributors may
++ *    be used to endorse or promote products derived from this software
++ *    without specific prior written permission.
++ *
++ * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND
++ * ANY EXPRESS 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 AUTHOR OR 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.
++ *
++ */
++#ifndef HEADER_SEED_LOCL_H
++# define HEADER_SEED_LOCL_H
++
++# include "openssl/e_os2.h"
++# include 
++
++# ifdef SEED_LONG               /* need 32-bit type */
++typedef unsigned long seed_word;
++# else
++typedef unsigned int seed_word;
++# endif
++
++
++#ifdef  __cplusplus
++extern "C" {
++#endif
++
++# define char2word(c, i)  \
++        (i) = ((((seed_word)(c)[0]) << 24) | (((seed_word)(c)[1]) << 16) | (((seed_word)(c)[2]) << 8) | ((seed_word)(c)[3]))
++
++# define word2char(l, c)  \
++        *((c)+0) = (unsigned char)((l)>>24) & 0xff; \
++        *((c)+1) = (unsigned char)((l)>>16) & 0xff; \
++        *((c)+2) = (unsigned char)((l)>> 8) & 0xff; \
++        *((c)+3) = (unsigned char)((l))     & 0xff
++
++# define KEYSCHEDULE_UPDATE0(T0, T1, X1, X2, X3, X4, KC)  \
++        (T0) = (X3);                                     \
++        (X3) = (((X3)<<8) ^ ((X4)>>24)) & 0xffffffff;    \
++        (X4) = (((X4)<<8) ^ ((T0)>>24)) & 0xffffffff;    \
++        (T0) = ((X1) + (X3) - (KC))     & 0xffffffff;    \
++        (T1) = ((X2) + (KC) - (X4))     & 0xffffffff
++
++# define KEYSCHEDULE_UPDATE1(T0, T1, X1, X2, X3, X4, KC)  \
++        (T0) = (X1);                                     \
++        (X1) = (((X1)>>8) ^ ((X2)<<24)) & 0xffffffff;    \
++        (X2) = (((X2)>>8) ^ ((T0)<<24)) & 0xffffffff;    \
++        (T0) = ((X1) + (X3) - (KC))     & 0xffffffff;     \
++        (T1) = ((X2) + (KC) - (X4))     & 0xffffffff
++
++# define KEYUPDATE_TEMP(T0, T1, K)   \
++        (K)[0] = G_FUNC((T0));      \
++        (K)[1] = G_FUNC((T1))
++
++# define XOR_SEEDBLOCK(DST, SRC)      \
++        ((DST))[0] ^= ((SRC))[0];    \
++        ((DST))[1] ^= ((SRC))[1];    \
++        ((DST))[2] ^= ((SRC))[2];    \
++        ((DST))[3] ^= ((SRC))[3]
++
++# define MOV_SEEDBLOCK(DST, SRC)      \
++        ((DST))[0] = ((SRC))[0];     \
++        ((DST))[1] = ((SRC))[1];     \
++        ((DST))[2] = ((SRC))[2];     \
++        ((DST))[3] = ((SRC))[3]
++
++# define CHAR2WORD(C, I)              \
++        char2word((C),    (I)[0]);    \
++        char2word((C+4),  (I)[1]);    \
++        char2word((C+8),  (I)[2]);    \
++        char2word((C+12), (I)[3])
++
++# define WORD2CHAR(I, C)              \
++        word2char((I)[0], (C));       \
++        word2char((I)[1], (C+4));     \
++        word2char((I)[2], (C+8));     \
++        word2char((I)[3], (C+12))
++
++# define E_SEED(T0, T1, X1, X2, X3, X4, rbase)   \
++        (T0) = (X3) ^ (ks->data)[(rbase)];       \
++        (T1) = (X4) ^ (ks->data)[(rbase)+1];     \
++        (T1) ^= (T0);                            \
++        (T1) = G_FUNC((T1));                     \
++        (T0) = ((T0) + (T1)) & 0xffffffff;       \
++        (T0) = G_FUNC((T0));                     \
++        (T1) = ((T1) + (T0)) & 0xffffffff;       \
++        (T1) = G_FUNC((T1));                     \
++        (T0) = ((T0) + (T1)) & 0xffffffff;       \
++        (X1) ^= (T0);                            \
++        (X2) ^= (T1)
++
++#ifdef  __cplusplus
++}
++#endif
++
++#endif                          /* HEADER_SEED_LOCL_H */
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/seed/seed_ofb.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/seed/seed_ofb.c
+new file mode 100644
+index 0000000..b455540
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/seed/seed_ofb.c
+@@ -0,0 +1,19 @@
++/*
++ * Copyright 2007-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include 
++
++void SEED_ofb128_encrypt(const unsigned char *in, unsigned char *out,
++                         size_t len, const SEED_KEY_SCHEDULE *ks,
++                         unsigned char ivec[SEED_BLOCK_SIZE], int *num)
++{
++    CRYPTO_ofb128_encrypt(in, out, len, ks, ivec, num,
++                          (block128_f) SEED_encrypt);
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/sha/asm/sha1-586.pl b/CryptoPkg/Library/OpensslLib/openssl/crypto/sha/asm/sha1-586.pl
+new file mode 100644
+index 0000000..0efed70
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/sha/asm/sha1-586.pl
+@@ -0,0 +1,1488 @@
++#! /usr/bin/env perl
++# Copyright 1998-2016 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
++# in the file LICENSE in the source distribution or at
++# https://www.openssl.org/source/license.html
++
++
++# ====================================================================
++# [Re]written by Andy Polyakov  for the OpenSSL
++# project. The module is, however, dual licensed under OpenSSL and
++# CRYPTOGAMS licenses depending on where you obtain it. For further
++# details see http://www.openssl.org/~appro/cryptogams/.
++# ====================================================================
++
++# "[Re]written" was achieved in two major overhauls. In 2004 BODY_*
++# functions were re-implemented to address P4 performance issue [see
++# commentary below], and in 2006 the rest was rewritten in order to
++# gain freedom to liberate licensing terms.
++
++# January, September 2004.
++#
++# It was noted that Intel IA-32 C compiler generates code which
++# performs ~30% *faster* on P4 CPU than original *hand-coded*
++# SHA1 assembler implementation. To address this problem (and
++# prove that humans are still better than machines:-), the
++# original code was overhauled, which resulted in following
++# performance changes:
++#
++#		compared with original	compared with Intel cc
++#		assembler impl.		generated code
++# Pentium	-16%			+48%
++# PIII/AMD	+8%			+16%
++# P4		+85%(!)			+45%
++#
++# As you can see Pentium came out as looser:-( Yet I reckoned that
++# improvement on P4 outweights the loss and incorporate this
++# re-tuned code to 0.9.7 and later.
++# ----------------------------------------------------------------
++#					
++
++# August 2009.
++#
++# George Spelvin has tipped that F_40_59(b,c,d) can be rewritten as
++# '(c&d) + (b&(c^d))', which allows to accumulate partial results
++# and lighten "pressure" on scratch registers. This resulted in
++# >12% performance improvement on contemporary AMD cores (with no
++# degradation on other CPUs:-). Also, the code was revised to maximize
++# "distance" between instructions producing input to 'lea' instruction
++# and the 'lea' instruction itself, which is essential for Intel Atom
++# core and resulted in ~15% improvement.
++
++# October 2010.
++#
++# Add SSSE3, Supplemental[!] SSE3, implementation. The idea behind it
++# is to offload message schedule denoted by Wt in NIST specification,
++# or Xupdate in OpenSSL source, to SIMD unit. The idea is not novel,
++# and in SSE2 context was first explored by Dean Gaudet in 2004, see
++# http://arctic.org/~dean/crypto/sha1.html. Since then several things
++# have changed that made it interesting again:
++#
++# a) XMM units became faster and wider;
++# b) instruction set became more versatile;
++# c) an important observation was made by Max Locktykhin, which made
++#    it possible to reduce amount of instructions required to perform
++#    the operation in question, for further details see
++#    http://software.intel.com/en-us/articles/improving-the-performance-of-the-secure-hash-algorithm-1/.
++
++# April 2011.
++#
++# Add AVX code path, probably most controversial... The thing is that
++# switch to AVX alone improves performance by as little as 4% in
++# comparison to SSSE3 code path. But below result doesn't look like
++# 4% improvement... Trouble is that Sandy Bridge decodes 'ro[rl]' as
++# pair of µ-ops, and it's the additional µ-ops, two per round, that
++# make it run slower than Core2 and Westmere. But 'sh[rl]d' is decoded
++# as single µ-op by Sandy Bridge and it's replacing 'ro[rl]' with
++# equivalent 'sh[rl]d' that is responsible for the impressive 5.1
++# cycles per processed byte. But 'sh[rl]d' is not something that used
++# to be fast, nor does it appear to be fast in upcoming Bulldozer
++# [according to its optimization manual]. Which is why AVX code path
++# is guarded by *both* AVX and synthetic bit denoting Intel CPUs.
++# One can argue that it's unfair to AMD, but without 'sh[rl]d' it
++# makes no sense to keep the AVX code path. If somebody feels that
++# strongly, it's probably more appropriate to discuss possibility of
++# using vector rotate XOP on AMD...
++
++# March 2014.
++#
++# Add support for Intel SHA Extensions.
++
++######################################################################
++# Current performance is summarized in following table. Numbers are
++# CPU clock cycles spent to process single byte (less is better).
++#
++#		x86		SSSE3		AVX
++# Pentium	15.7		-
++# PIII		11.5		-
++# P4		10.6		-
++# AMD K8	7.1		-
++# Core2		7.3		6.0/+22%	-
++# Westmere	7.3		5.5/+33%	-
++# Sandy Bridge	8.8		6.2/+40%	5.1(**)/+73%
++# Ivy Bridge	7.2		4.8/+51%	4.7(**)/+53%
++# Haswell	6.5		4.3/+51%	4.1(**)/+58%
++# Bulldozer	11.6		6.0/+92%
++# VIA Nano	10.6		7.5/+41%
++# Atom		12.5		9.3(*)/+35%
++# Silvermont	14.5		9.9(*)/+46%
++#
++# (*)	Loop is 1056 instructions long and expected result is ~8.25.
++#	The discrepancy is because of front-end limitations, so
++#	called MS-ROM penalties, and on Silvermont even rotate's
++#	limited parallelism.
++#
++# (**)	As per above comment, the result is for AVX *plus* sh[rl]d.
++
++$0 =~ m/(.*[\/\\])[^\/\\]+$/; $dir=$1;
++push(@INC,"${dir}","${dir}../../perlasm");
++require "x86asm.pl";
++
++$output=pop;
++open STDOUT,">$output";
++
++&asm_init($ARGV[0],"sha1-586.pl",$ARGV[$#ARGV] eq "386");
++
++$xmm=$ymm=0;
++for (@ARGV) { $xmm=1 if (/-DOPENSSL_IA32_SSE2/); }
++
++$ymm=1 if ($xmm &&
++		`$ENV{CC} -Wa,-v -c -o /dev/null -x assembler /dev/null 2>&1`
++			=~ /GNU assembler version ([2-9]\.[0-9]+)/ &&
++		$1>=2.19);	# first version supporting AVX
++
++$ymm=1 if ($xmm && !$ymm && $ARGV[0] eq "win32n" && 
++		`nasm -v 2>&1` =~ /NASM version ([2-9]\.[0-9]+)/ &&
++		$1>=2.03);	# first version supporting AVX
++
++$ymm=1 if ($xmm && !$ymm && $ARGV[0] eq "win32" &&
++		`ml 2>&1` =~ /Version ([0-9]+)\./ &&
++		$1>=10);	# first version supporting AVX
++
++$ymm=1 if ($xmm && !$ymm && `$ENV{CC} -v 2>&1` =~ /(^clang version|based on LLVM) ([3-9]\.[0-9]+)/ &&
++		$2>=3.0);	# first version supporting AVX
++
++$shaext=$xmm;	### set to zero if compiling for 1.0.1
++
++&external_label("OPENSSL_ia32cap_P") if ($xmm);
++
++
++$A="eax";
++$B="ebx";
++$C="ecx";
++$D="edx";
++$E="edi";
++$T="esi";
++$tmp1="ebp";
++
++@V=($A,$B,$C,$D,$E,$T);
++
++$alt=0;	# 1 denotes alternative IALU implementation, which performs
++	# 8% *worse* on P4, same on Westmere and Atom, 2% better on
++	# Sandy Bridge...
++
++sub BODY_00_15
++	{
++	local($n,$a,$b,$c,$d,$e,$f)=@_;
++
++	&comment("00_15 $n");
++
++	&mov($f,$c);			# f to hold F_00_19(b,c,d)
++	 if ($n==0)  { &mov($tmp1,$a); }
++	 else        { &mov($a,$tmp1); }
++	&rotl($tmp1,5);			# tmp1=ROTATE(a,5)
++	 &xor($f,$d);
++	&add($tmp1,$e);			# tmp1+=e;
++	 &mov($e,&swtmp($n%16));	# e becomes volatile and is loaded
++	 				# with xi, also note that e becomes
++					# f in next round...
++	&and($f,$b);
++	&rotr($b,2);			# b=ROTATE(b,30)
++	 &xor($f,$d);			# f holds F_00_19(b,c,d)
++	&lea($tmp1,&DWP(0x5a827999,$tmp1,$e));	# tmp1+=K_00_19+xi
++
++	if ($n==15) { &mov($e,&swtmp(($n+1)%16));# pre-fetch f for next round
++		      &add($f,$tmp1); }	# f+=tmp1
++	else        { &add($tmp1,$f); }	# f becomes a in next round
++	&mov($tmp1,$a)			if ($alt && $n==15);
++	}
++
++sub BODY_16_19
++	{
++	local($n,$a,$b,$c,$d,$e,$f)=@_;
++
++	&comment("16_19 $n");
++
++if ($alt) {
++	&xor($c,$d);
++	 &xor($f,&swtmp(($n+2)%16));	# f to hold Xupdate(xi,xa,xb,xc,xd)
++	&and($tmp1,$c);			# tmp1 to hold F_00_19(b,c,d), b&=c^d
++	 &xor($f,&swtmp(($n+8)%16));
++	&xor($tmp1,$d);			# tmp1=F_00_19(b,c,d)
++	 &xor($f,&swtmp(($n+13)%16));	# f holds xa^xb^xc^xd
++	&rotl($f,1);			# f=ROTATE(f,1)
++	 &add($e,$tmp1);		# e+=F_00_19(b,c,d)
++	&xor($c,$d);			# restore $c
++	 &mov($tmp1,$a);		# b in next round
++	&rotr($b,$n==16?2:7);		# b=ROTATE(b,30)
++	 &mov(&swtmp($n%16),$f);	# xi=f
++	&rotl($a,5);			# ROTATE(a,5)
++	 &lea($f,&DWP(0x5a827999,$f,$e));# f+=F_00_19(b,c,d)+e
++	&mov($e,&swtmp(($n+1)%16));	# pre-fetch f for next round
++	 &add($f,$a);			# f+=ROTATE(a,5)
++} else {
++	&mov($tmp1,$c);			# tmp1 to hold F_00_19(b,c,d)
++	 &xor($f,&swtmp(($n+2)%16));	# f to hold Xupdate(xi,xa,xb,xc,xd)
++	&xor($tmp1,$d);
++	 &xor($f,&swtmp(($n+8)%16));
++	&and($tmp1,$b);
++	 &xor($f,&swtmp(($n+13)%16));	# f holds xa^xb^xc^xd
++	&rotl($f,1);			# f=ROTATE(f,1)
++	 &xor($tmp1,$d);		# tmp1=F_00_19(b,c,d)
++	&add($e,$tmp1);			# e+=F_00_19(b,c,d)
++	 &mov($tmp1,$a);
++	&rotr($b,2);			# b=ROTATE(b,30)
++	 &mov(&swtmp($n%16),$f);	# xi=f
++	&rotl($tmp1,5);			# ROTATE(a,5)
++	 &lea($f,&DWP(0x5a827999,$f,$e));# f+=F_00_19(b,c,d)+e
++	&mov($e,&swtmp(($n+1)%16));	# pre-fetch f for next round
++	 &add($f,$tmp1);		# f+=ROTATE(a,5)
++}
++	}
++
++sub BODY_20_39
++	{
++	local($n,$a,$b,$c,$d,$e,$f)=@_;
++	local $K=($n<40)?0x6ed9eba1:0xca62c1d6;
++
++	&comment("20_39 $n");
++
++if ($alt) {
++	&xor($tmp1,$c);			# tmp1 to hold F_20_39(b,c,d), b^=c
++	 &xor($f,&swtmp(($n+2)%16));	# f to hold Xupdate(xi,xa,xb,xc,xd)
++	&xor($tmp1,$d);			# tmp1 holds F_20_39(b,c,d)
++	 &xor($f,&swtmp(($n+8)%16));
++	&add($e,$tmp1);			# e+=F_20_39(b,c,d)
++	 &xor($f,&swtmp(($n+13)%16));	# f holds xa^xb^xc^xd
++	&rotl($f,1);			# f=ROTATE(f,1)
++	 &mov($tmp1,$a);		# b in next round
++	&rotr($b,7);			# b=ROTATE(b,30)
++	 &mov(&swtmp($n%16),$f)		if($n<77);# xi=f
++	&rotl($a,5);			# ROTATE(a,5)
++	 &xor($b,$c)			if($n==39);# warm up for BODY_40_59
++	&and($tmp1,$b)			if($n==39);
++	 &lea($f,&DWP($K,$f,$e));	# f+=e+K_XX_YY
++	&mov($e,&swtmp(($n+1)%16))	if($n<79);# pre-fetch f for next round
++	 &add($f,$a);			# f+=ROTATE(a,5)
++	&rotr($a,5)			if ($n==79);
++} else {
++	&mov($tmp1,$b);			# tmp1 to hold F_20_39(b,c,d)
++	 &xor($f,&swtmp(($n+2)%16));	# f to hold Xupdate(xi,xa,xb,xc,xd)
++	&xor($tmp1,$c);
++	 &xor($f,&swtmp(($n+8)%16));
++	&xor($tmp1,$d);			# tmp1 holds F_20_39(b,c,d)
++	 &xor($f,&swtmp(($n+13)%16));	# f holds xa^xb^xc^xd
++	&rotl($f,1);			# f=ROTATE(f,1)
++	 &add($e,$tmp1);		# e+=F_20_39(b,c,d)
++	&rotr($b,2);			# b=ROTATE(b,30)
++	 &mov($tmp1,$a);
++	&rotl($tmp1,5);			# ROTATE(a,5)
++	 &mov(&swtmp($n%16),$f) if($n<77);# xi=f
++	&lea($f,&DWP($K,$f,$e));	# f+=e+K_XX_YY
++	 &mov($e,&swtmp(($n+1)%16)) if($n<79);# pre-fetch f for next round
++	&add($f,$tmp1);			# f+=ROTATE(a,5)
++}
++	}
++
++sub BODY_40_59
++	{
++	local($n,$a,$b,$c,$d,$e,$f)=@_;
++
++	&comment("40_59 $n");
++
++if ($alt) {
++	&add($e,$tmp1);			# e+=b&(c^d)
++	 &xor($f,&swtmp(($n+2)%16));	# f to hold Xupdate(xi,xa,xb,xc,xd)
++	&mov($tmp1,$d);
++	 &xor($f,&swtmp(($n+8)%16));
++	&xor($c,$d);			# restore $c
++	 &xor($f,&swtmp(($n+13)%16));	# f holds xa^xb^xc^xd
++	&rotl($f,1);			# f=ROTATE(f,1)
++	 &and($tmp1,$c);
++	&rotr($b,7);			# b=ROTATE(b,30)
++	 &add($e,$tmp1);		# e+=c&d
++	&mov($tmp1,$a);			# b in next round
++	 &mov(&swtmp($n%16),$f);	# xi=f
++	&rotl($a,5);			# ROTATE(a,5)
++	 &xor($b,$c)			if ($n<59);
++	&and($tmp1,$b)			if ($n<59);# tmp1 to hold F_40_59(b,c,d)
++	 &lea($f,&DWP(0x8f1bbcdc,$f,$e));# f+=K_40_59+e+(b&(c^d))
++	&mov($e,&swtmp(($n+1)%16));	# pre-fetch f for next round
++	 &add($f,$a);			# f+=ROTATE(a,5)
++} else {
++	&mov($tmp1,$c);			# tmp1 to hold F_40_59(b,c,d)
++	 &xor($f,&swtmp(($n+2)%16));	# f to hold Xupdate(xi,xa,xb,xc,xd)
++	&xor($tmp1,$d);
++	 &xor($f,&swtmp(($n+8)%16));
++	&and($tmp1,$b);
++	 &xor($f,&swtmp(($n+13)%16));	# f holds xa^xb^xc^xd
++	&rotl($f,1);			# f=ROTATE(f,1)
++	 &add($tmp1,$e);		# b&(c^d)+=e
++	&rotr($b,2);			# b=ROTATE(b,30)
++	 &mov($e,$a);			# e becomes volatile
++	&rotl($e,5);			# ROTATE(a,5)
++	 &mov(&swtmp($n%16),$f);	# xi=f
++	&lea($f,&DWP(0x8f1bbcdc,$f,$tmp1));# f+=K_40_59+e+(b&(c^d))
++	 &mov($tmp1,$c);
++	&add($f,$e);			# f+=ROTATE(a,5)
++	 &and($tmp1,$d);
++	&mov($e,&swtmp(($n+1)%16));	# pre-fetch f for next round
++	 &add($f,$tmp1);		# f+=c&d
++}
++	}
++
++&function_begin("sha1_block_data_order");
++if ($xmm) {
++  &static_label("shaext_shortcut")	if ($shaext);
++  &static_label("ssse3_shortcut");
++  &static_label("avx_shortcut")		if ($ymm);
++  &static_label("K_XX_XX");
++
++	&call	(&label("pic_point"));	# make it PIC!
++  &set_label("pic_point");
++	&blindpop($tmp1);
++	&picmeup($T,"OPENSSL_ia32cap_P",$tmp1,&label("pic_point"));
++	&lea	($tmp1,&DWP(&label("K_XX_XX")."-".&label("pic_point"),$tmp1));
++
++	&mov	($A,&DWP(0,$T));
++	&mov	($D,&DWP(4,$T));
++	&test	($D,1<<9);		# check SSSE3 bit
++	&jz	(&label("x86"));
++	&mov	($C,&DWP(8,$T));
++	&test	($A,1<<24);		# check FXSR bit
++	&jz	(&label("x86"));
++	if ($shaext) {
++		&test	($C,1<<29);		# check SHA bit
++		&jnz	(&label("shaext_shortcut"));
++	}
++	if ($ymm) {
++		&and	($D,1<<28);		# mask AVX bit
++		&and	($A,1<<30);		# mask "Intel CPU" bit
++		&or	($A,$D);
++		&cmp	($A,1<<28|1<<30);
++		&je	(&label("avx_shortcut"));
++	}
++	&jmp	(&label("ssse3_shortcut"));
++  &set_label("x86",16);
++}
++	&mov($tmp1,&wparam(0));	# SHA_CTX *c
++	&mov($T,&wparam(1));	# const void *input
++	&mov($A,&wparam(2));	# size_t num
++	&stack_push(16+3);	# allocate X[16]
++	&shl($A,6);
++	&add($A,$T);
++	&mov(&wparam(2),$A);	# pointer beyond the end of input
++	&mov($E,&DWP(16,$tmp1));# pre-load E
++	&jmp(&label("loop"));
++
++&set_label("loop",16);
++
++	# copy input chunk to X, but reversing byte order!
++	for ($i=0; $i<16; $i+=4)
++		{
++		&mov($A,&DWP(4*($i+0),$T));
++		&mov($B,&DWP(4*($i+1),$T));
++		&mov($C,&DWP(4*($i+2),$T));
++		&mov($D,&DWP(4*($i+3),$T));
++		&bswap($A);
++		&bswap($B);
++		&bswap($C);
++		&bswap($D);
++		&mov(&swtmp($i+0),$A);
++		&mov(&swtmp($i+1),$B);
++		&mov(&swtmp($i+2),$C);
++		&mov(&swtmp($i+3),$D);
++		}
++	&mov(&wparam(1),$T);	# redundant in 1st spin
++
++	&mov($A,&DWP(0,$tmp1));	# load SHA_CTX
++	&mov($B,&DWP(4,$tmp1));
++	&mov($C,&DWP(8,$tmp1));
++	&mov($D,&DWP(12,$tmp1));
++	# E is pre-loaded
++
++	for($i=0;$i<16;$i++)	{ &BODY_00_15($i,@V); unshift(@V,pop(@V)); }
++	for(;$i<20;$i++)	{ &BODY_16_19($i,@V); unshift(@V,pop(@V)); }
++	for(;$i<40;$i++)	{ &BODY_20_39($i,@V); unshift(@V,pop(@V)); }
++	for(;$i<60;$i++)	{ &BODY_40_59($i,@V); unshift(@V,pop(@V)); }
++	for(;$i<80;$i++)	{ &BODY_20_39($i,@V); unshift(@V,pop(@V)); }
++
++	(($V[5] eq $D) and ($V[0] eq $E)) or die;	# double-check
++
++	&mov($tmp1,&wparam(0));	# re-load SHA_CTX*
++	&mov($D,&wparam(1));	# D is last "T" and is discarded
++
++	&add($E,&DWP(0,$tmp1));	# E is last "A"...
++	&add($T,&DWP(4,$tmp1));
++	&add($A,&DWP(8,$tmp1));
++	&add($B,&DWP(12,$tmp1));
++	&add($C,&DWP(16,$tmp1));
++
++	&mov(&DWP(0,$tmp1),$E);	# update SHA_CTX
++	 &add($D,64);		# advance input pointer
++	&mov(&DWP(4,$tmp1),$T);
++	 &cmp($D,&wparam(2));	# have we reached the end yet?
++	&mov(&DWP(8,$tmp1),$A);
++	 &mov($E,$C);		# C is last "E" which needs to be "pre-loaded"
++	&mov(&DWP(12,$tmp1),$B);
++	 &mov($T,$D);		# input pointer
++	&mov(&DWP(16,$tmp1),$C);
++	&jb(&label("loop"));
++
++	&stack_pop(16+3);
++&function_end("sha1_block_data_order");
++
++if ($xmm) {
++if ($shaext) {
++######################################################################
++# Intel SHA Extensions implementation of SHA1 update function.
++#
++my ($ctx,$inp,$num)=("edi","esi","ecx");
++my ($ABCD,$E,$E_,$BSWAP)=map("xmm$_",(0..3));
++my @MSG=map("xmm$_",(4..7));
++
++sub sha1rnds4 {
++ my ($dst,$src,$imm)=@_;
++    if ("$dst:$src" =~ /xmm([0-7]):xmm([0-7])/)
++    {	&data_byte(0x0f,0x3a,0xcc,0xc0|($1<<3)|$2,$imm);	}
++}
++sub sha1op38 {
++ my ($opcodelet,$dst,$src)=@_;
++    if ("$dst:$src" =~ /xmm([0-7]):xmm([0-7])/)
++    {	&data_byte(0x0f,0x38,$opcodelet,0xc0|($1<<3)|$2);	}
++}
++sub sha1nexte	{ sha1op38(0xc8,@_); }
++sub sha1msg1	{ sha1op38(0xc9,@_); }
++sub sha1msg2	{ sha1op38(0xca,@_); }
++
++&function_begin("_sha1_block_data_order_shaext");
++	&call	(&label("pic_point"));	# make it PIC!
++	&set_label("pic_point");
++	&blindpop($tmp1);
++	&lea	($tmp1,&DWP(&label("K_XX_XX")."-".&label("pic_point"),$tmp1));
++&set_label("shaext_shortcut");
++	&mov	($ctx,&wparam(0));
++	&mov	("ebx","esp");
++	&mov	($inp,&wparam(1));
++	&mov	($num,&wparam(2));
++	&sub	("esp",32);
++
++	&movdqu	($ABCD,&QWP(0,$ctx));
++	&movd	($E,&DWP(16,$ctx));
++	&and	("esp",-32);
++	&movdqa	($BSWAP,&QWP(0x50,$tmp1));	# byte-n-word swap
++
++	&movdqu	(@MSG[0],&QWP(0,$inp));
++	&pshufd	($ABCD,$ABCD,0b00011011);	# flip word order
++	&movdqu	(@MSG[1],&QWP(0x10,$inp));
++	&pshufd	($E,$E,0b00011011);		# flip word order
++	&movdqu	(@MSG[2],&QWP(0x20,$inp));
++	&pshufb	(@MSG[0],$BSWAP);
++	&movdqu	(@MSG[3],&QWP(0x30,$inp));
++	&pshufb	(@MSG[1],$BSWAP);
++	&pshufb	(@MSG[2],$BSWAP);
++	&pshufb	(@MSG[3],$BSWAP);
++	&jmp	(&label("loop_shaext"));
++
++&set_label("loop_shaext",16);
++	&dec		($num);
++	&lea		("eax",&DWP(0x40,$inp));
++	&movdqa		(&QWP(0,"esp"),$E);	# offload $E
++	&paddd		($E,@MSG[0]);
++	&cmovne		($inp,"eax");
++	&movdqa		(&QWP(16,"esp"),$ABCD);	# offload $ABCD
++
++for($i=0;$i<20-4;$i+=2) {
++	&sha1msg1	(@MSG[0],@MSG[1]);
++	&movdqa		($E_,$ABCD);
++	&sha1rnds4	($ABCD,$E,int($i/5));	# 0-3...
++	&sha1nexte	($E_,@MSG[1]);
++	&pxor		(@MSG[0],@MSG[2]);
++	&sha1msg1	(@MSG[1],@MSG[2]);
++	&sha1msg2	(@MSG[0],@MSG[3]);
++
++	&movdqa		($E,$ABCD);
++	&sha1rnds4	($ABCD,$E_,int(($i+1)/5));
++	&sha1nexte	($E,@MSG[2]);
++	&pxor		(@MSG[1],@MSG[3]);
++	&sha1msg2	(@MSG[1],@MSG[0]);
++
++	push(@MSG,shift(@MSG));	push(@MSG,shift(@MSG));
++}
++	&movdqu		(@MSG[0],&QWP(0,$inp));
++	&movdqa		($E_,$ABCD);
++	&sha1rnds4	($ABCD,$E,3);		# 64-67
++	&sha1nexte	($E_,@MSG[1]);
++	&movdqu		(@MSG[1],&QWP(0x10,$inp));
++	&pshufb		(@MSG[0],$BSWAP);
++
++	&movdqa		($E,$ABCD);
++	&sha1rnds4	($ABCD,$E_,3);		# 68-71
++	&sha1nexte	($E,@MSG[2]);
++	&movdqu		(@MSG[2],&QWP(0x20,$inp));
++	&pshufb		(@MSG[1],$BSWAP);
++
++	&movdqa		($E_,$ABCD);
++	&sha1rnds4	($ABCD,$E,3);		# 72-75
++	&sha1nexte	($E_,@MSG[3]);
++	&movdqu		(@MSG[3],&QWP(0x30,$inp));
++	&pshufb		(@MSG[2],$BSWAP);
++
++	&movdqa		($E,$ABCD);
++	&sha1rnds4	($ABCD,$E_,3);		# 76-79
++	&movdqa		($E_,&QWP(0,"esp"));
++	&pshufb		(@MSG[3],$BSWAP);
++	&sha1nexte	($E,$E_);
++	&paddd		($ABCD,&QWP(16,"esp"));
++
++	&jnz		(&label("loop_shaext"));
++
++	&pshufd	($ABCD,$ABCD,0b00011011);
++	&pshufd	($E,$E,0b00011011);
++	&movdqu	(&QWP(0,$ctx),$ABCD)
++	&movd	(&DWP(16,$ctx),$E);
++	&mov	("esp","ebx");
++&function_end("_sha1_block_data_order_shaext");
++}
++######################################################################
++# The SSSE3 implementation.
++#
++# %xmm[0-7] are used as ring @X[] buffer containing quadruples of last
++# 32 elements of the message schedule or Xupdate outputs. First 4
++# quadruples are simply byte-swapped input, next 4 are calculated
++# according to method originally suggested by Dean Gaudet (modulo
++# being implemented in SSSE3). Once 8 quadruples or 32 elements are
++# collected, it switches to routine proposed by Max Locktyukhin.
++#
++# Calculations inevitably require temporary reqisters, and there are
++# no %xmm registers left to spare. For this reason part of the ring
++# buffer, X[2..4] to be specific, is offloaded to 3 quadriples ring
++# buffer on the stack. Keep in mind that X[2] is alias X[-6], X[3] -
++# X[-5], and X[4] - X[-4]...
++#
++# Another notable optimization is aggressive stack frame compression
++# aiming to minimize amount of 9-byte instructions...
++#
++# Yet another notable optimization is "jumping" $B variable. It means
++# that there is no register permanently allocated for $B value. This
++# allowed to eliminate one instruction from body_20_39...
++#
++my $Xi=4;			# 4xSIMD Xupdate round, start pre-seeded
++my @X=map("xmm$_",(4..7,0..3));	# pre-seeded for $Xi=4
++my @V=($A,$B,$C,$D,$E);
++my $j=0;			# hash round
++my $rx=0;
++my @T=($T,$tmp1);
++my $inp;
++
++my $_rol=sub { &rol(@_) };
++my $_ror=sub { &ror(@_) };
++
++&function_begin("_sha1_block_data_order_ssse3");
++	&call	(&label("pic_point"));	# make it PIC!
++	&set_label("pic_point");
++	&blindpop($tmp1);
++	&lea	($tmp1,&DWP(&label("K_XX_XX")."-".&label("pic_point"),$tmp1));
++&set_label("ssse3_shortcut");
++
++	&movdqa	(@X[3],&QWP(0,$tmp1));		# K_00_19
++	&movdqa	(@X[4],&QWP(16,$tmp1));		# K_20_39
++	&movdqa	(@X[5],&QWP(32,$tmp1));		# K_40_59
++	&movdqa	(@X[6],&QWP(48,$tmp1));		# K_60_79
++	&movdqa	(@X[2],&QWP(64,$tmp1));		# pbswap mask
++
++	&mov	($E,&wparam(0));		# load argument block
++	&mov	($inp=@T[1],&wparam(1));
++	&mov	($D,&wparam(2));
++	&mov	(@T[0],"esp");
++
++	# stack frame layout
++	#
++	# +0	X[0]+K	X[1]+K	X[2]+K	X[3]+K	# XMM->IALU xfer area
++	#	X[4]+K	X[5]+K	X[6]+K	X[7]+K
++	#	X[8]+K	X[9]+K	X[10]+K	X[11]+K
++	#	X[12]+K	X[13]+K	X[14]+K	X[15]+K
++	#
++	# +64	X[0]	X[1]	X[2]	X[3]	# XMM->XMM backtrace area
++	#	X[4]	X[5]	X[6]	X[7]
++	#	X[8]	X[9]	X[10]	X[11]	# even borrowed for K_00_19
++	#
++	# +112	K_20_39	K_20_39	K_20_39	K_20_39	# constants
++	#	K_40_59	K_40_59	K_40_59	K_40_59
++	#	K_60_79	K_60_79	K_60_79	K_60_79
++	#	K_00_19	K_00_19	K_00_19	K_00_19
++	#	pbswap mask
++	#
++	# +192	ctx				# argument block
++	# +196	inp
++	# +200	end
++	# +204	esp
++	&sub	("esp",208);
++	&and	("esp",-64);
++
++	&movdqa	(&QWP(112+0,"esp"),@X[4]);	# copy constants
++	&movdqa	(&QWP(112+16,"esp"),@X[5]);
++	&movdqa	(&QWP(112+32,"esp"),@X[6]);
++	&shl	($D,6);				# len*64
++	&movdqa	(&QWP(112+48,"esp"),@X[3]);
++	&add	($D,$inp);			# end of input
++	&movdqa	(&QWP(112+64,"esp"),@X[2]);
++	&add	($inp,64);
++	&mov	(&DWP(192+0,"esp"),$E);		# save argument block
++	&mov	(&DWP(192+4,"esp"),$inp);
++	&mov	(&DWP(192+8,"esp"),$D);
++	&mov	(&DWP(192+12,"esp"),@T[0]);	# save original %esp
++
++	&mov	($A,&DWP(0,$E));		# load context
++	&mov	($B,&DWP(4,$E));
++	&mov	($C,&DWP(8,$E));
++	&mov	($D,&DWP(12,$E));
++	&mov	($E,&DWP(16,$E));
++	&mov	(@T[0],$B);			# magic seed
++
++	&movdqu	(@X[-4&7],&QWP(-64,$inp));	# load input to %xmm[0-3]
++	&movdqu	(@X[-3&7],&QWP(-48,$inp));
++	&movdqu	(@X[-2&7],&QWP(-32,$inp));
++	&movdqu	(@X[-1&7],&QWP(-16,$inp));
++	&pshufb	(@X[-4&7],@X[2]);		# byte swap
++	&pshufb	(@X[-3&7],@X[2]);
++	&pshufb	(@X[-2&7],@X[2]);
++	&movdqa	(&QWP(112-16,"esp"),@X[3]);	# borrow last backtrace slot
++	&pshufb	(@X[-1&7],@X[2]);
++	&paddd	(@X[-4&7],@X[3]);		# add K_00_19
++	&paddd	(@X[-3&7],@X[3]);
++	&paddd	(@X[-2&7],@X[3]);
++	&movdqa	(&QWP(0,"esp"),@X[-4&7]);	# X[]+K xfer to IALU
++	&psubd	(@X[-4&7],@X[3]);		# restore X[]
++	&movdqa	(&QWP(0+16,"esp"),@X[-3&7]);
++	&psubd	(@X[-3&7],@X[3]);
++	&movdqa	(&QWP(0+32,"esp"),@X[-2&7]);
++	&mov	(@T[1],$C);
++	&psubd	(@X[-2&7],@X[3]);
++	&xor	(@T[1],$D);
++	&pshufd	(@X[0],@X[-4&7],0xee);		# was &movdqa	(@X[0],@X[-3&7]);
++	&and	(@T[0],@T[1]);
++	&jmp	(&label("loop"));
++
++######################################################################
++# SSE instruction sequence is first broken to groups of indepentent
++# instructions, independent in respect to their inputs and shifter
++# (not all architectures have more than one). Then IALU instructions
++# are "knitted in" between the SSE groups. Distance is maintained for
++# SSE latency of 2 in hope that it fits better upcoming AMD Bulldozer
++# [which allegedly also implements SSSE3]...
++#
++# Temporary registers usage. X[2] is volatile at the entry and at the
++# end is restored from backtrace ring buffer. X[3] is expected to
++# contain current K_XX_XX constant and is used to caclulate X[-1]+K
++# from previous round, it becomes volatile the moment the value is
++# saved to stack for transfer to IALU. X[4] becomes volatile whenever
++# X[-4] is accumulated and offloaded to backtrace ring buffer, at the
++# end it is loaded with next K_XX_XX [which becomes X[3] in next
++# round]...
++#
++sub Xupdate_ssse3_16_31()		# recall that $Xi starts wtih 4
++{ use integer;
++  my $body = shift;
++  my @insns = (&$body,&$body,&$body,&$body);	# 40 instructions
++  my ($a,$b,$c,$d,$e);
++
++	 eval(shift(@insns));		# ror
++	 eval(shift(@insns));
++	 eval(shift(@insns));
++	&punpcklqdq(@X[0],@X[-3&7]);	# compose "X[-14]" in "X[0]", was &palignr(@X[0],@X[-4&7],8);
++	&movdqa	(@X[2],@X[-1&7]);
++	 eval(shift(@insns));
++	 eval(shift(@insns));
++
++	  &paddd	(@X[3],@X[-1&7]);
++	  &movdqa	(&QWP(64+16*(($Xi-4)%3),"esp"),@X[-4&7]);# save X[] to backtrace buffer
++	 eval(shift(@insns));		# rol
++	 eval(shift(@insns));
++	&psrldq	(@X[2],4);		# "X[-3]", 3 dwords
++	 eval(shift(@insns));
++	 eval(shift(@insns));
++	&pxor	(@X[0],@X[-4&7]);	# "X[0]"^="X[-16]"
++	 eval(shift(@insns));
++	 eval(shift(@insns));		# ror
++
++	&pxor	(@X[2],@X[-2&7]);	# "X[-3]"^"X[-8]"
++	 eval(shift(@insns));
++	 eval(shift(@insns));
++	 eval(shift(@insns));
++
++	&pxor	(@X[0],@X[2]);		# "X[0]"^="X[-3]"^"X[-8]"
++	 eval(shift(@insns));
++	 eval(shift(@insns));		# rol
++	  &movdqa	(&QWP(0+16*(($Xi-1)&3),"esp"),@X[3]);	# X[]+K xfer to IALU
++	 eval(shift(@insns));
++	 eval(shift(@insns));
++
++	&movdqa	(@X[4],@X[0]);
++	 eval(shift(@insns));
++	 eval(shift(@insns));
++	 eval(shift(@insns));		# ror
++	&movdqa (@X[2],@X[0]);
++	 eval(shift(@insns));
++
++	&pslldq	(@X[4],12);		# "X[0]"<<96, extract one dword
++	&paddd	(@X[0],@X[0]);
++	 eval(shift(@insns));
++	 eval(shift(@insns));
++
++	&psrld	(@X[2],31);
++	 eval(shift(@insns));
++	 eval(shift(@insns));		# rol
++	&movdqa	(@X[3],@X[4]);
++	 eval(shift(@insns));
++	 eval(shift(@insns));
++	 eval(shift(@insns));
++
++	&psrld	(@X[4],30);
++	 eval(shift(@insns));
++	 eval(shift(@insns));		# ror
++	&por	(@X[0],@X[2]);		# "X[0]"<<<=1
++	 eval(shift(@insns));
++	  &movdqa	(@X[2],&QWP(64+16*(($Xi-6)%3),"esp")) if ($Xi>5);	# restore X[] from backtrace buffer
++	 eval(shift(@insns));
++	 eval(shift(@insns));
++
++	&pslld	(@X[3],2);
++	 eval(shift(@insns));
++	 eval(shift(@insns));		# rol
++	&pxor   (@X[0],@X[4]);
++	  &movdqa	(@X[4],&QWP(112-16+16*(($Xi)/5),"esp"));	# K_XX_XX
++	 eval(shift(@insns));
++	 eval(shift(@insns));
++
++	&pxor	(@X[0],@X[3]);		# "X[0]"^=("X[0]"<<96)<<<2
++	  &pshufd	(@X[1],@X[-3&7],0xee)	if ($Xi<7);	# was &movdqa	(@X[1],@X[-2&7])
++	  &pshufd	(@X[3],@X[-1&7],0xee)	if ($Xi==7);
++	 eval(shift(@insns));
++	 eval(shift(@insns));
++
++	 foreach (@insns) { eval; }	# remaining instructions [if any]
++
++  $Xi++;	push(@X,shift(@X));	# "rotate" X[]
++}
++
++sub Xupdate_ssse3_32_79()
++{ use integer;
++  my $body = shift;
++  my @insns = (&$body,&$body,&$body,&$body);	# 32 to 44 instructions
++  my ($a,$b,$c,$d,$e);
++
++	 eval(shift(@insns));		# body_20_39
++	&pxor	(@X[0],@X[-4&7]);	# "X[0]"="X[-32]"^"X[-16]"
++	&punpcklqdq(@X[2],@X[-1&7]);	# compose "X[-6]", was &palignr(@X[2],@X[-2&7],8)
++	 eval(shift(@insns));
++	 eval(shift(@insns));
++	 eval(shift(@insns));		# rol
++
++	&pxor	(@X[0],@X[-7&7]);	# "X[0]"^="X[-28]"
++	  &movdqa	(&QWP(64+16*(($Xi-4)%3),"esp"),@X[-4&7]);	# save X[] to backtrace buffer
++	 eval(shift(@insns));
++	 eval(shift(@insns));
++	 eval(shift(@insns))		if (@insns[0] =~ /_rol/);
++	 if ($Xi%5) {
++	  &movdqa	(@X[4],@X[3]);	# "perpetuate" K_XX_XX...
++	 } else {			# ... or load next one
++	  &movdqa	(@X[4],&QWP(112-16+16*($Xi/5),"esp"));
++	 }
++	 eval(shift(@insns));		# ror
++	  &paddd	(@X[3],@X[-1&7]);
++	 eval(shift(@insns));
++
++	&pxor	(@X[0],@X[2]);		# "X[0]"^="X[-6]"
++	 eval(shift(@insns));		# body_20_39
++	 eval(shift(@insns));
++	 eval(shift(@insns));
++	 eval(shift(@insns));		# rol
++
++	&movdqa	(@X[2],@X[0]);
++	  &movdqa	(&QWP(0+16*(($Xi-1)&3),"esp"),@X[3]);	# X[]+K xfer to IALU
++	 eval(shift(@insns));
++	 eval(shift(@insns));
++	 eval(shift(@insns));		# ror
++	 eval(shift(@insns));
++	 eval(shift(@insns))		if (@insns[0] =~ /_rol/);
++
++	&pslld	(@X[0],2);
++	 eval(shift(@insns));		# body_20_39
++	 eval(shift(@insns));
++	&psrld	(@X[2],30);
++	 eval(shift(@insns));
++	 eval(shift(@insns));		# rol
++	 eval(shift(@insns));
++	 eval(shift(@insns));
++	 eval(shift(@insns));		# ror
++	 eval(shift(@insns));
++	 eval(shift(@insns))		if (@insns[1] =~ /_rol/);
++	 eval(shift(@insns))		if (@insns[0] =~ /_rol/);
++
++	&por	(@X[0],@X[2]);		# "X[0]"<<<=2
++	 eval(shift(@insns));		# body_20_39
++	 eval(shift(@insns));
++	  &movdqa	(@X[2],&QWP(64+16*(($Xi-6)%3),"esp")) if($Xi<19);	# restore X[] from backtrace buffer
++	 eval(shift(@insns));
++	 eval(shift(@insns));		# rol
++	 eval(shift(@insns));
++	 eval(shift(@insns));
++	 eval(shift(@insns));		# ror
++	  &pshufd	(@X[3],@X[-1],0xee)	if ($Xi<19);	# was &movdqa	(@X[3],@X[0])
++	 eval(shift(@insns));
++
++	 foreach (@insns) { eval; }	# remaining instructions
++
++  $Xi++;	push(@X,shift(@X));	# "rotate" X[]
++}
++
++sub Xuplast_ssse3_80()
++{ use integer;
++  my $body = shift;
++  my @insns = (&$body,&$body,&$body,&$body);	# 32 instructions
++  my ($a,$b,$c,$d,$e);
++
++	 eval(shift(@insns));
++	 eval(shift(@insns));
++	 eval(shift(@insns));
++	 eval(shift(@insns));
++	 eval(shift(@insns));
++	 eval(shift(@insns));
++	 eval(shift(@insns));
++	  &paddd	(@X[3],@X[-1&7]);
++	 eval(shift(@insns));
++	 eval(shift(@insns));
++	 eval(shift(@insns));
++	 eval(shift(@insns));
++
++	  &movdqa	(&QWP(0+16*(($Xi-1)&3),"esp"),@X[3]);	# X[]+K xfer IALU
++
++	 foreach (@insns) { eval; }		# remaining instructions
++
++	&mov	($inp=@T[1],&DWP(192+4,"esp"));
++	&cmp	($inp,&DWP(192+8,"esp"));
++	&je	(&label("done"));
++
++	&movdqa	(@X[3],&QWP(112+48,"esp"));	# K_00_19
++	&movdqa	(@X[2],&QWP(112+64,"esp"));	# pbswap mask
++	&movdqu	(@X[-4&7],&QWP(0,$inp));	# load input
++	&movdqu	(@X[-3&7],&QWP(16,$inp));
++	&movdqu	(@X[-2&7],&QWP(32,$inp));
++	&movdqu	(@X[-1&7],&QWP(48,$inp));
++	&add	($inp,64);
++	&pshufb	(@X[-4&7],@X[2]);		# byte swap
++	&mov	(&DWP(192+4,"esp"),$inp);
++	&movdqa	(&QWP(112-16,"esp"),@X[3]);	# borrow last backtrace slot
++
++  $Xi=0;
++}
++
++sub Xloop_ssse3()
++{ use integer;
++  my $body = shift;
++  my @insns = (&$body,&$body,&$body,&$body);	# 32 instructions
++  my ($a,$b,$c,$d,$e);
++
++	 eval(shift(@insns));
++	 eval(shift(@insns));
++	 eval(shift(@insns));
++	 eval(shift(@insns));
++	 eval(shift(@insns));
++	 eval(shift(@insns));
++	 eval(shift(@insns));
++	&pshufb	(@X[($Xi-3)&7],@X[2]);
++	 eval(shift(@insns));
++	 eval(shift(@insns));
++	 eval(shift(@insns));
++	 eval(shift(@insns));
++	&paddd	(@X[($Xi-4)&7],@X[3]);
++	 eval(shift(@insns));
++	 eval(shift(@insns));
++	 eval(shift(@insns));
++	 eval(shift(@insns));
++	&movdqa	(&QWP(0+16*$Xi,"esp"),@X[($Xi-4)&7]);	# X[]+K xfer to IALU
++	 eval(shift(@insns));
++	 eval(shift(@insns));
++	 eval(shift(@insns));
++	 eval(shift(@insns));
++	&psubd	(@X[($Xi-4)&7],@X[3]);
++
++	foreach (@insns) { eval; }
++  $Xi++;
++}
++
++sub Xtail_ssse3()
++{ use integer;
++  my $body = shift;
++  my @insns = (&$body,&$body,&$body,&$body);	# 32 instructions
++  my ($a,$b,$c,$d,$e);
++
++	foreach (@insns) { eval; }
++}
++
++sub body_00_19 () {	# ((c^d)&b)^d
++	# on start @T[0]=(c^d)&b
++	return &body_20_39()	if ($rx==19);	$rx++;
++	(
++	'($a,$b,$c,$d,$e)=@V;'.
++	'&$_ror	($b,$j?7:2);',	# $b>>>2
++	'&xor	(@T[0],$d);',
++	'&mov	(@T[1],$a);',	# $b in next round
++
++	'&add	($e,&DWP(4*($j&15),"esp"));',	# X[]+K xfer
++	'&xor	($b,$c);',	# $c^$d for next round
++
++	'&$_rol	($a,5);',
++	'&add	($e,@T[0]);',
++	'&and	(@T[1],$b);',	# ($b&($c^$d)) for next round
++
++	'&xor	($b,$c);',	# restore $b
++	'&add	($e,$a);'	.'$j++; unshift(@V,pop(@V)); unshift(@T,pop(@T));'
++	);
++}
++
++sub body_20_39 () {	# b^d^c
++	# on entry @T[0]=b^d
++	return &body_40_59()	if ($rx==39);	$rx++;
++	(
++	'($a,$b,$c,$d,$e)=@V;'.
++	'&add	($e,&DWP(4*($j&15),"esp"));',	# X[]+K xfer
++	'&xor	(@T[0],$d)	if($j==19);'.
++	'&xor	(@T[0],$c)	if($j> 19);',	# ($b^$d^$c)
++	'&mov	(@T[1],$a);',	# $b in next round
++
++	'&$_rol	($a,5);',
++	'&add	($e,@T[0]);',
++	'&xor	(@T[1],$c)	if ($j< 79);',	# $b^$d for next round
++
++	'&$_ror	($b,7);',	# $b>>>2
++	'&add	($e,$a);'	.'$j++; unshift(@V,pop(@V)); unshift(@T,pop(@T));'
++	);
++}
++
++sub body_40_59 () {	# ((b^c)&(c^d))^c
++	# on entry @T[0]=(b^c), (c^=d)
++	$rx++;
++	(
++	'($a,$b,$c,$d,$e)=@V;'.
++	'&add	($e,&DWP(4*($j&15),"esp"));',	# X[]+K xfer
++	'&and	(@T[0],$c)	if ($j>=40);',	# (b^c)&(c^d)
++	'&xor	($c,$d)		if ($j>=40);',	# restore $c
++
++	'&$_ror	($b,7);',	# $b>>>2
++	'&mov	(@T[1],$a);',	# $b for next round
++	'&xor	(@T[0],$c);',
++
++	'&$_rol	($a,5);',
++	'&add	($e,@T[0]);',
++	'&xor	(@T[1],$c)	if ($j==59);'.
++	'&xor	(@T[1],$b)	if ($j< 59);',	# b^c for next round
++
++	'&xor	($b,$c)		if ($j< 59);',	# c^d for next round
++	'&add	($e,$a);'	.'$j++; unshift(@V,pop(@V)); unshift(@T,pop(@T));'
++	);
++}
++######
++sub bodyx_00_19 () {	# ((c^d)&b)^d
++	# on start @T[0]=(b&c)^(~b&d), $e+=X[]+K
++	return &bodyx_20_39()	if ($rx==19);	$rx++;
++	(
++	'($a,$b,$c,$d,$e)=@V;'.
++
++	'&rorx	($b,$b,2)			if ($j==0);'.	# $b>>>2
++	'&rorx	($b,@T[1],7)			if ($j!=0);',	# $b>>>2
++	'&lea	($e,&DWP(0,$e,@T[0]));',
++	'&rorx	(@T[0],$a,5);',
++
++	'&andn	(@T[1],$a,$c);',
++	'&and	($a,$b)',
++	'&add	($d,&DWP(4*(($j+1)&15),"esp"));',	# X[]+K xfer
++
++	'&xor	(@T[1],$a)',
++	'&add	($e,@T[0]);'	.'$j++; unshift(@V,pop(@V)); unshift(@T,pop(@T));'
++	);
++}
++
++sub bodyx_20_39 () {	# b^d^c
++	# on start $b=b^c^d
++	return &bodyx_40_59()	if ($rx==39);	$rx++;
++	(
++	'($a,$b,$c,$d,$e)=@V;'.
++
++	'&add	($e,($j==19?@T[0]:$b))',
++	'&rorx	($b,@T[1],7);',	# $b>>>2
++	'&rorx	(@T[0],$a,5);',
++
++	'&xor	($a,$b)				if ($j<79);',
++	'&add	($d,&DWP(4*(($j+1)&15),"esp"))	if ($j<79);',	# X[]+K xfer
++	'&xor	($a,$c)				if ($j<79);',
++	'&add	($e,@T[0]);'	.'$j++; unshift(@V,pop(@V)); unshift(@T,pop(@T));'
++	);
++}
++
++sub bodyx_40_59 () {	# ((b^c)&(c^d))^c
++	# on start $b=((b^c)&(c^d))^c
++	return &bodyx_20_39()	if ($rx==59);	$rx++;
++	(
++	'($a,$b,$c,$d,$e)=@V;'.
++
++	'&rorx	(@T[0],$a,5)',
++	'&lea	($e,&DWP(0,$e,$b))',
++	'&rorx	($b,@T[1],7)',	# $b>>>2
++	'&add	($d,&DWP(4*(($j+1)&15),"esp"))',	# X[]+K xfer
++
++	'&mov	(@T[1],$c)',
++	'&xor	($a,$b)',	# b^c for next round
++	'&xor	(@T[1],$b)',	# c^d for next round
++
++	'&and	($a,@T[1])',
++	'&add	($e,@T[0])',
++	'&xor	($a,$b)'	.'$j++; unshift(@V,pop(@V)); unshift(@T,pop(@T));'
++	);
++}
++
++&set_label("loop",16);
++	&Xupdate_ssse3_16_31(\&body_00_19);
++	&Xupdate_ssse3_16_31(\&body_00_19);
++	&Xupdate_ssse3_16_31(\&body_00_19);
++	&Xupdate_ssse3_16_31(\&body_00_19);
++	&Xupdate_ssse3_32_79(\&body_00_19);
++	&Xupdate_ssse3_32_79(\&body_20_39);
++	&Xupdate_ssse3_32_79(\&body_20_39);
++	&Xupdate_ssse3_32_79(\&body_20_39);
++	&Xupdate_ssse3_32_79(\&body_20_39);
++	&Xupdate_ssse3_32_79(\&body_20_39);
++	&Xupdate_ssse3_32_79(\&body_40_59);
++	&Xupdate_ssse3_32_79(\&body_40_59);
++	&Xupdate_ssse3_32_79(\&body_40_59);
++	&Xupdate_ssse3_32_79(\&body_40_59);
++	&Xupdate_ssse3_32_79(\&body_40_59);
++	&Xupdate_ssse3_32_79(\&body_20_39);
++	&Xuplast_ssse3_80(\&body_20_39);	# can jump to "done"
++
++				$saved_j=$j; @saved_V=@V;
++
++	&Xloop_ssse3(\&body_20_39);
++	&Xloop_ssse3(\&body_20_39);
++	&Xloop_ssse3(\&body_20_39);
++
++	&mov	(@T[1],&DWP(192,"esp"));	# update context
++	&add	($A,&DWP(0,@T[1]));
++	&add	(@T[0],&DWP(4,@T[1]));		# $b
++	&add	($C,&DWP(8,@T[1]));
++	&mov	(&DWP(0,@T[1]),$A);
++	&add	($D,&DWP(12,@T[1]));
++	&mov	(&DWP(4,@T[1]),@T[0]);
++	&add	($E,&DWP(16,@T[1]));
++	&mov	(&DWP(8,@T[1]),$C);
++	&mov	($B,$C);
++	&mov	(&DWP(12,@T[1]),$D);
++	&xor	($B,$D);
++	&mov	(&DWP(16,@T[1]),$E);
++	&mov	(@T[1],@T[0]);
++	&pshufd	(@X[0],@X[-4&7],0xee);		# was &movdqa	(@X[0],@X[-3&7]);
++	&and	(@T[0],$B);
++	&mov	($B,$T[1]);
++
++	&jmp	(&label("loop"));
++
++&set_label("done",16);		$j=$saved_j; @V=@saved_V;
++
++	&Xtail_ssse3(\&body_20_39);
++	&Xtail_ssse3(\&body_20_39);
++	&Xtail_ssse3(\&body_20_39);
++
++	&mov	(@T[1],&DWP(192,"esp"));	# update context
++	&add	($A,&DWP(0,@T[1]));
++	&mov	("esp",&DWP(192+12,"esp"));	# restore %esp
++	&add	(@T[0],&DWP(4,@T[1]));		# $b
++	&add	($C,&DWP(8,@T[1]));
++	&mov	(&DWP(0,@T[1]),$A);
++	&add	($D,&DWP(12,@T[1]));
++	&mov	(&DWP(4,@T[1]),@T[0]);
++	&add	($E,&DWP(16,@T[1]));
++	&mov	(&DWP(8,@T[1]),$C);
++	&mov	(&DWP(12,@T[1]),$D);
++	&mov	(&DWP(16,@T[1]),$E);
++
++&function_end("_sha1_block_data_order_ssse3");
++
++$rx=0;	# reset
++
++if ($ymm) {
++my $Xi=4;			# 4xSIMD Xupdate round, start pre-seeded
++my @X=map("xmm$_",(4..7,0..3));	# pre-seeded for $Xi=4
++my @V=($A,$B,$C,$D,$E);
++my $j=0;			# hash round
++my @T=($T,$tmp1);
++my $inp;
++
++my $_rol=sub { &shld(@_[0],@_) };
++my $_ror=sub { &shrd(@_[0],@_) };
++
++&function_begin("_sha1_block_data_order_avx");
++	&call	(&label("pic_point"));	# make it PIC!
++	&set_label("pic_point");
++	&blindpop($tmp1);
++	&lea	($tmp1,&DWP(&label("K_XX_XX")."-".&label("pic_point"),$tmp1));
++&set_label("avx_shortcut");
++	&vzeroall();
++
++	&vmovdqa(@X[3],&QWP(0,$tmp1));		# K_00_19
++	&vmovdqa(@X[4],&QWP(16,$tmp1));		# K_20_39
++	&vmovdqa(@X[5],&QWP(32,$tmp1));		# K_40_59
++	&vmovdqa(@X[6],&QWP(48,$tmp1));		# K_60_79
++	&vmovdqa(@X[2],&QWP(64,$tmp1));		# pbswap mask
++
++	&mov	($E,&wparam(0));		# load argument block
++	&mov	($inp=@T[1],&wparam(1));
++	&mov	($D,&wparam(2));
++	&mov	(@T[0],"esp");
++
++	# stack frame layout
++	#
++	# +0	X[0]+K	X[1]+K	X[2]+K	X[3]+K	# XMM->IALU xfer area
++	#	X[4]+K	X[5]+K	X[6]+K	X[7]+K
++	#	X[8]+K	X[9]+K	X[10]+K	X[11]+K
++	#	X[12]+K	X[13]+K	X[14]+K	X[15]+K
++	#
++	# +64	X[0]	X[1]	X[2]	X[3]	# XMM->XMM backtrace area
++	#	X[4]	X[5]	X[6]	X[7]
++	#	X[8]	X[9]	X[10]	X[11]	# even borrowed for K_00_19
++	#
++	# +112	K_20_39	K_20_39	K_20_39	K_20_39	# constants
++	#	K_40_59	K_40_59	K_40_59	K_40_59
++	#	K_60_79	K_60_79	K_60_79	K_60_79
++	#	K_00_19	K_00_19	K_00_19	K_00_19
++	#	pbswap mask
++	#
++	# +192	ctx				# argument block
++	# +196	inp
++	# +200	end
++	# +204	esp
++	&sub	("esp",208);
++	&and	("esp",-64);
++
++	&vmovdqa(&QWP(112+0,"esp"),@X[4]);	# copy constants
++	&vmovdqa(&QWP(112+16,"esp"),@X[5]);
++	&vmovdqa(&QWP(112+32,"esp"),@X[6]);
++	&shl	($D,6);				# len*64
++	&vmovdqa(&QWP(112+48,"esp"),@X[3]);
++	&add	($D,$inp);			# end of input
++	&vmovdqa(&QWP(112+64,"esp"),@X[2]);
++	&add	($inp,64);
++	&mov	(&DWP(192+0,"esp"),$E);		# save argument block
++	&mov	(&DWP(192+4,"esp"),$inp);
++	&mov	(&DWP(192+8,"esp"),$D);
++	&mov	(&DWP(192+12,"esp"),@T[0]);	# save original %esp
++
++	&mov	($A,&DWP(0,$E));		# load context
++	&mov	($B,&DWP(4,$E));
++	&mov	($C,&DWP(8,$E));
++	&mov	($D,&DWP(12,$E));
++	&mov	($E,&DWP(16,$E));
++	&mov	(@T[0],$B);			# magic seed
++
++	&vmovdqu(@X[-4&7],&QWP(-64,$inp));	# load input to %xmm[0-3]
++	&vmovdqu(@X[-3&7],&QWP(-48,$inp));
++	&vmovdqu(@X[-2&7],&QWP(-32,$inp));
++	&vmovdqu(@X[-1&7],&QWP(-16,$inp));
++	&vpshufb(@X[-4&7],@X[-4&7],@X[2]);	# byte swap
++	&vpshufb(@X[-3&7],@X[-3&7],@X[2]);
++	&vpshufb(@X[-2&7],@X[-2&7],@X[2]);
++	&vmovdqa(&QWP(112-16,"esp"),@X[3]);	# borrow last backtrace slot
++	&vpshufb(@X[-1&7],@X[-1&7],@X[2]);
++	&vpaddd	(@X[0],@X[-4&7],@X[3]);		# add K_00_19
++	&vpaddd	(@X[1],@X[-3&7],@X[3]);
++	&vpaddd	(@X[2],@X[-2&7],@X[3]);
++	&vmovdqa(&QWP(0,"esp"),@X[0]);		# X[]+K xfer to IALU
++	&mov	(@T[1],$C);
++	&vmovdqa(&QWP(0+16,"esp"),@X[1]);
++	&xor	(@T[1],$D);
++	&vmovdqa(&QWP(0+32,"esp"),@X[2]);
++	&and	(@T[0],@T[1]);
++	&jmp	(&label("loop"));
++
++sub Xupdate_avx_16_31()		# recall that $Xi starts wtih 4
++{ use integer;
++  my $body = shift;
++  my @insns = (&$body,&$body,&$body,&$body);	# 40 instructions
++  my ($a,$b,$c,$d,$e);
++
++	 eval(shift(@insns));
++	 eval(shift(@insns));
++	&vpalignr(@X[0],@X[-3&7],@X[-4&7],8);	# compose "X[-14]" in "X[0]"
++	 eval(shift(@insns));
++	 eval(shift(@insns));
++
++	  &vpaddd	(@X[3],@X[3],@X[-1&7]);
++	  &vmovdqa	(&QWP(64+16*(($Xi-4)%3),"esp"),@X[-4&7]);# save X[] to backtrace buffer
++	 eval(shift(@insns));
++	 eval(shift(@insns));
++	&vpsrldq(@X[2],@X[-1&7],4);		# "X[-3]", 3 dwords
++	 eval(shift(@insns));
++	 eval(shift(@insns));
++	&vpxor	(@X[0],@X[0],@X[-4&7]);		# "X[0]"^="X[-16]"
++	 eval(shift(@insns));
++	 eval(shift(@insns));
++
++	&vpxor	(@X[2],@X[2],@X[-2&7]);		# "X[-3]"^"X[-8]"
++	 eval(shift(@insns));
++	 eval(shift(@insns));
++	  &vmovdqa	(&QWP(0+16*(($Xi-1)&3),"esp"),@X[3]);	# X[]+K xfer to IALU
++	 eval(shift(@insns));
++	 eval(shift(@insns));
++
++	&vpxor	(@X[0],@X[0],@X[2]);		# "X[0]"^="X[-3]"^"X[-8]"
++	 eval(shift(@insns));
++	 eval(shift(@insns));
++	 eval(shift(@insns));
++	 eval(shift(@insns));
++
++	&vpsrld	(@X[2],@X[0],31);
++	 eval(shift(@insns));
++	 eval(shift(@insns));
++	 eval(shift(@insns));
++	 eval(shift(@insns));
++
++	&vpslldq(@X[4],@X[0],12);		# "X[0]"<<96, extract one dword
++	&vpaddd	(@X[0],@X[0],@X[0]);
++	 eval(shift(@insns));
++	 eval(shift(@insns));
++	 eval(shift(@insns));
++	 eval(shift(@insns));
++
++	&vpsrld	(@X[3],@X[4],30);
++	&vpor	(@X[0],@X[0],@X[2]);		# "X[0]"<<<=1
++	 eval(shift(@insns));
++	 eval(shift(@insns));
++	 eval(shift(@insns));
++	 eval(shift(@insns));
++
++	&vpslld	(@X[4],@X[4],2);
++	  &vmovdqa	(@X[2],&QWP(64+16*(($Xi-6)%3),"esp")) if ($Xi>5);	# restore X[] from backtrace buffer
++	 eval(shift(@insns));
++	 eval(shift(@insns));
++	&vpxor	(@X[0],@X[0],@X[3]);
++	 eval(shift(@insns));
++	 eval(shift(@insns));
++	 eval(shift(@insns));
++	 eval(shift(@insns));
++
++	&vpxor	(@X[0],@X[0],@X[4]);		# "X[0]"^=("X[0]"<<96)<<<2
++	 eval(shift(@insns));
++	 eval(shift(@insns));
++	  &vmovdqa	(@X[4],&QWP(112-16+16*(($Xi)/5),"esp"));	# K_XX_XX
++	 eval(shift(@insns));
++	 eval(shift(@insns));
++
++	 foreach (@insns) { eval; }	# remaining instructions [if any]
++
++  $Xi++;	push(@X,shift(@X));	# "rotate" X[]
++}
++
++sub Xupdate_avx_32_79()
++{ use integer;
++  my $body = shift;
++  my @insns = (&$body,&$body,&$body,&$body);	# 32 to 44 instructions
++  my ($a,$b,$c,$d,$e);
++
++	&vpalignr(@X[2],@X[-1&7],@X[-2&7],8);	# compose "X[-6]"
++	&vpxor	(@X[0],@X[0],@X[-4&7]);	# "X[0]"="X[-32]"^"X[-16]"
++	 eval(shift(@insns));		# body_20_39
++	 eval(shift(@insns));
++	 eval(shift(@insns));
++	 eval(shift(@insns));		# rol
++
++	&vpxor	(@X[0],@X[0],@X[-7&7]);	# "X[0]"^="X[-28]"
++	  &vmovdqa	(&QWP(64+16*(($Xi-4)%3),"esp"),@X[-4&7]);	# save X[] to backtrace buffer
++	 eval(shift(@insns));
++	 eval(shift(@insns));
++	 if ($Xi%5) {
++	  &vmovdqa	(@X[4],@X[3]);	# "perpetuate" K_XX_XX...
++	 } else {			# ... or load next one
++	  &vmovdqa	(@X[4],&QWP(112-16+16*($Xi/5),"esp"));
++	 }
++	  &vpaddd	(@X[3],@X[3],@X[-1&7]);
++	 eval(shift(@insns));		# ror
++	 eval(shift(@insns));
++
++	&vpxor	(@X[0],@X[0],@X[2]);		# "X[0]"^="X[-6]"
++	 eval(shift(@insns));		# body_20_39
++	 eval(shift(@insns));
++	 eval(shift(@insns));
++	 eval(shift(@insns));		# rol
++
++	&vpsrld	(@X[2],@X[0],30);
++	  &vmovdqa	(&QWP(0+16*(($Xi-1)&3),"esp"),@X[3]);	# X[]+K xfer to IALU
++	 eval(shift(@insns));
++	 eval(shift(@insns));
++	 eval(shift(@insns));		# ror
++	 eval(shift(@insns));
++
++	&vpslld	(@X[0],@X[0],2);
++	 eval(shift(@insns));		# body_20_39
++	 eval(shift(@insns));
++	 eval(shift(@insns));
++	 eval(shift(@insns));		# rol
++	 eval(shift(@insns));
++	 eval(shift(@insns));
++	 eval(shift(@insns));		# ror
++	 eval(shift(@insns));
++
++	&vpor	(@X[0],@X[0],@X[2]);	# "X[0]"<<<=2
++	 eval(shift(@insns));		# body_20_39
++	 eval(shift(@insns));
++	  &vmovdqa	(@X[2],&QWP(64+16*(($Xi-6)%3),"esp")) if($Xi<19);	# restore X[] from backtrace buffer
++	 eval(shift(@insns));
++	 eval(shift(@insns));		# rol
++	 eval(shift(@insns));
++	 eval(shift(@insns));
++	 eval(shift(@insns));		# ror
++	 eval(shift(@insns));
++
++	 foreach (@insns) { eval; }	# remaining instructions
++
++  $Xi++;	push(@X,shift(@X));	# "rotate" X[]
++}
++
++sub Xuplast_avx_80()
++{ use integer;
++  my $body = shift;
++  my @insns = (&$body,&$body,&$body,&$body);	# 32 instructions
++  my ($a,$b,$c,$d,$e);
++
++	 eval(shift(@insns));
++	  &vpaddd	(@X[3],@X[3],@X[-1&7]);
++	 eval(shift(@insns));
++	 eval(shift(@insns));
++	 eval(shift(@insns));
++	 eval(shift(@insns));
++
++	  &vmovdqa	(&QWP(0+16*(($Xi-1)&3),"esp"),@X[3]);	# X[]+K xfer IALU
++
++	 foreach (@insns) { eval; }		# remaining instructions
++
++	&mov	($inp=@T[1],&DWP(192+4,"esp"));
++	&cmp	($inp,&DWP(192+8,"esp"));
++	&je	(&label("done"));
++
++	&vmovdqa(@X[3],&QWP(112+48,"esp"));	# K_00_19
++	&vmovdqa(@X[2],&QWP(112+64,"esp"));	# pbswap mask
++	&vmovdqu(@X[-4&7],&QWP(0,$inp));	# load input
++	&vmovdqu(@X[-3&7],&QWP(16,$inp));
++	&vmovdqu(@X[-2&7],&QWP(32,$inp));
++	&vmovdqu(@X[-1&7],&QWP(48,$inp));
++	&add	($inp,64);
++	&vpshufb(@X[-4&7],@X[-4&7],@X[2]);		# byte swap
++	&mov	(&DWP(192+4,"esp"),$inp);
++	&vmovdqa(&QWP(112-16,"esp"),@X[3]);	# borrow last backtrace slot
++
++  $Xi=0;
++}
++
++sub Xloop_avx()
++{ use integer;
++  my $body = shift;
++  my @insns = (&$body,&$body,&$body,&$body);	# 32 instructions
++  my ($a,$b,$c,$d,$e);
++
++	 eval(shift(@insns));
++	 eval(shift(@insns));
++	&vpshufb	(@X[($Xi-3)&7],@X[($Xi-3)&7],@X[2]);
++	 eval(shift(@insns));
++	 eval(shift(@insns));
++	&vpaddd	(@X[$Xi&7],@X[($Xi-4)&7],@X[3]);
++	 eval(shift(@insns));
++	 eval(shift(@insns));
++	 eval(shift(@insns));
++	 eval(shift(@insns));
++	&vmovdqa	(&QWP(0+16*$Xi,"esp"),@X[$Xi&7]);	# X[]+K xfer to IALU
++	 eval(shift(@insns));
++	 eval(shift(@insns));
++
++	foreach (@insns) { eval; }
++  $Xi++;
++}
++
++sub Xtail_avx()
++{ use integer;
++  my $body = shift;
++  my @insns = (&$body,&$body,&$body,&$body);	# 32 instructions
++  my ($a,$b,$c,$d,$e);
++
++	foreach (@insns) { eval; }
++}
++
++&set_label("loop",16);
++	&Xupdate_avx_16_31(\&body_00_19);
++	&Xupdate_avx_16_31(\&body_00_19);
++	&Xupdate_avx_16_31(\&body_00_19);
++	&Xupdate_avx_16_31(\&body_00_19);
++	&Xupdate_avx_32_79(\&body_00_19);
++	&Xupdate_avx_32_79(\&body_20_39);
++	&Xupdate_avx_32_79(\&body_20_39);
++	&Xupdate_avx_32_79(\&body_20_39);
++	&Xupdate_avx_32_79(\&body_20_39);
++	&Xupdate_avx_32_79(\&body_20_39);
++	&Xupdate_avx_32_79(\&body_40_59);
++	&Xupdate_avx_32_79(\&body_40_59);
++	&Xupdate_avx_32_79(\&body_40_59);
++	&Xupdate_avx_32_79(\&body_40_59);
++	&Xupdate_avx_32_79(\&body_40_59);
++	&Xupdate_avx_32_79(\&body_20_39);
++	&Xuplast_avx_80(\&body_20_39);	# can jump to "done"
++
++				$saved_j=$j; @saved_V=@V;
++
++	&Xloop_avx(\&body_20_39);
++	&Xloop_avx(\&body_20_39);
++	&Xloop_avx(\&body_20_39);
++
++	&mov	(@T[1],&DWP(192,"esp"));	# update context
++	&add	($A,&DWP(0,@T[1]));
++	&add	(@T[0],&DWP(4,@T[1]));		# $b
++	&add	($C,&DWP(8,@T[1]));
++	&mov	(&DWP(0,@T[1]),$A);
++	&add	($D,&DWP(12,@T[1]));
++	&mov	(&DWP(4,@T[1]),@T[0]);
++	&add	($E,&DWP(16,@T[1]));
++	&mov	($B,$C);
++	&mov	(&DWP(8,@T[1]),$C);
++	&xor	($B,$D);
++	&mov	(&DWP(12,@T[1]),$D);
++	&mov	(&DWP(16,@T[1]),$E);
++	&mov	(@T[1],@T[0]);
++	&and	(@T[0],$B);
++	&mov	($B,@T[1]);
++
++	&jmp	(&label("loop"));
++
++&set_label("done",16);		$j=$saved_j; @V=@saved_V;
++
++	&Xtail_avx(\&body_20_39);
++	&Xtail_avx(\&body_20_39);
++	&Xtail_avx(\&body_20_39);
++
++	&vzeroall();
++
++	&mov	(@T[1],&DWP(192,"esp"));	# update context
++	&add	($A,&DWP(0,@T[1]));
++	&mov	("esp",&DWP(192+12,"esp"));	# restore %esp
++	&add	(@T[0],&DWP(4,@T[1]));		# $b
++	&add	($C,&DWP(8,@T[1]));
++	&mov	(&DWP(0,@T[1]),$A);
++	&add	($D,&DWP(12,@T[1]));
++	&mov	(&DWP(4,@T[1]),@T[0]);
++	&add	($E,&DWP(16,@T[1]));
++	&mov	(&DWP(8,@T[1]),$C);
++	&mov	(&DWP(12,@T[1]),$D);
++	&mov	(&DWP(16,@T[1]),$E);
++&function_end("_sha1_block_data_order_avx");
++}
++&set_label("K_XX_XX",64);
++&data_word(0x5a827999,0x5a827999,0x5a827999,0x5a827999);	# K_00_19
++&data_word(0x6ed9eba1,0x6ed9eba1,0x6ed9eba1,0x6ed9eba1);	# K_20_39
++&data_word(0x8f1bbcdc,0x8f1bbcdc,0x8f1bbcdc,0x8f1bbcdc);	# K_40_59
++&data_word(0xca62c1d6,0xca62c1d6,0xca62c1d6,0xca62c1d6);	# K_60_79
++&data_word(0x00010203,0x04050607,0x08090a0b,0x0c0d0e0f);	# pbswap mask
++&data_byte(0xf,0xe,0xd,0xc,0xb,0xa,0x9,0x8,0x7,0x6,0x5,0x4,0x3,0x2,0x1,0x0);
++}
++&asciz("SHA1 block transform for x86, CRYPTOGAMS by ");
++
++&asm_finish();
++
++close STDOUT;
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/sha/asm/sha1-alpha.pl b/CryptoPkg/Library/OpensslLib/openssl/crypto/sha/asm/sha1-alpha.pl
+new file mode 100644
+index 0000000..4124958
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/sha/asm/sha1-alpha.pl
+@@ -0,0 +1,329 @@
++#! /usr/bin/env perl
++# Copyright 2009-2016 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
++# in the file LICENSE in the source distribution or at
++# https://www.openssl.org/source/license.html
++
++
++# ====================================================================
++# Written by Andy Polyakov  for the OpenSSL
++# project. The module is, however, dual licensed under OpenSSL and
++# CRYPTOGAMS licenses depending on where you obtain it. For further
++# details see http://www.openssl.org/~appro/cryptogams/.
++# ====================================================================
++
++# SHA1 block procedure for Alpha.
++
++# On 21264 performance is 33% better than code generated by vendor
++# compiler, and 75% better than GCC [3.4], and in absolute terms is
++# 8.7 cycles per processed byte. Implementation features vectorized
++# byte swap, but not Xupdate.
++
++@X=(	"\$0",	"\$1",	"\$2",	"\$3",	"\$4",	"\$5",	"\$6",	"\$7",
++	"\$8",	"\$9",	"\$10",	"\$11",	"\$12",	"\$13",	"\$14",	"\$15");
++$ctx="a0";	# $16
++$inp="a1";
++$num="a2";
++$A="a3";
++$B="a4";	# 20
++$C="a5";
++$D="t8";
++$E="t9";	@V=($A,$B,$C,$D,$E);
++$t0="t10";	# 24
++$t1="t11";
++$t2="ra";
++$t3="t12";
++$K="AT";	# 28
++
++sub BODY_00_19 {
++my ($i,$a,$b,$c,$d,$e)=@_;
++my $j=$i+1;
++$code.=<<___ if ($i==0);
++	ldq_u	@X[0],0+0($inp)
++	ldq_u	@X[1],0+7($inp)
++___
++$code.=<<___ if (!($i&1) && $i<14);
++	ldq_u	@X[$i+2],($i+2)*4+0($inp)
++	ldq_u	@X[$i+3],($i+2)*4+7($inp)
++___
++$code.=<<___ if (!($i&1) && $i<15);
++	extql	@X[$i],$inp,@X[$i]
++	extqh	@X[$i+1],$inp,@X[$i+1]
++
++	or	@X[$i+1],@X[$i],@X[$i]	# pair of 32-bit values are fetched
++
++	srl	@X[$i],24,$t0		# vectorized byte swap
++	srl	@X[$i],8,$t2
++
++	sll	@X[$i],8,$t3
++	sll	@X[$i],24,@X[$i]
++	zapnot	$t0,0x11,$t0
++	zapnot	$t2,0x22,$t2
++
++	zapnot	@X[$i],0x88,@X[$i]
++	or	$t0,$t2,$t0
++	zapnot	$t3,0x44,$t3
++	sll	$a,5,$t1
++
++	or	@X[$i],$t0,@X[$i]
++	addl	$K,$e,$e
++	and	$b,$c,$t2
++	zapnot	$a,0xf,$a
++
++	or	@X[$i],$t3,@X[$i]
++	srl	$a,27,$t0
++	bic	$d,$b,$t3
++	sll	$b,30,$b
++
++	extll	@X[$i],4,@X[$i+1]	# extract upper half
++	or	$t2,$t3,$t2
++	addl	@X[$i],$e,$e
++
++	addl	$t1,$e,$e
++	srl	$b,32,$t3
++	zapnot	@X[$i],0xf,@X[$i]
++
++	addl	$t0,$e,$e
++	addl	$t2,$e,$e
++	or	$t3,$b,$b
++___
++$code.=<<___ if (($i&1) && $i<15);
++	sll	$a,5,$t1
++	addl	$K,$e,$e
++	and	$b,$c,$t2
++	zapnot	$a,0xf,$a
++
++	srl	$a,27,$t0
++	addl	@X[$i%16],$e,$e
++	bic	$d,$b,$t3
++	sll	$b,30,$b
++
++	or	$t2,$t3,$t2
++	addl	$t1,$e,$e
++	srl	$b,32,$t3
++	zapnot	@X[$i],0xf,@X[$i]
++
++	addl	$t0,$e,$e
++	addl	$t2,$e,$e
++	or	$t3,$b,$b
++___
++$code.=<<___ if ($i>=15);	# with forward Xupdate
++	sll	$a,5,$t1
++	addl	$K,$e,$e
++	and	$b,$c,$t2
++	xor	@X[($j+2)%16],@X[$j%16],@X[$j%16]
++
++	zapnot	$a,0xf,$a
++	addl	@X[$i%16],$e,$e
++	bic	$d,$b,$t3
++	xor	@X[($j+8)%16],@X[$j%16],@X[$j%16]
++
++	srl	$a,27,$t0
++	addl	$t1,$e,$e
++	or	$t2,$t3,$t2
++	xor	@X[($j+13)%16],@X[$j%16],@X[$j%16]
++
++	sll	$b,30,$b
++	addl	$t0,$e,$e
++	srl	@X[$j%16],31,$t1
++
++	addl	$t2,$e,$e
++	srl	$b,32,$t3
++	addl	@X[$j%16],@X[$j%16],@X[$j%16]
++
++	or	$t3,$b,$b
++	zapnot	@X[$i%16],0xf,@X[$i%16]
++	or	$t1,@X[$j%16],@X[$j%16]
++___
++}
++
++sub BODY_20_39 {
++my ($i,$a,$b,$c,$d,$e)=@_;
++my $j=$i+1;
++$code.=<<___ if ($i<79);	# with forward Xupdate
++	sll	$a,5,$t1
++	addl	$K,$e,$e
++	zapnot	$a,0xf,$a
++	xor	@X[($j+2)%16],@X[$j%16],@X[$j%16]
++
++	sll	$b,30,$t3
++	addl	$t1,$e,$e
++	xor	$b,$c,$t2
++	xor	@X[($j+8)%16],@X[$j%16],@X[$j%16]
++
++	srl	$b,2,$b
++	addl	@X[$i%16],$e,$e
++	xor	$d,$t2,$t2
++	xor	@X[($j+13)%16],@X[$j%16],@X[$j%16]
++
++	srl	@X[$j%16],31,$t1
++	addl	$t2,$e,$e
++	srl	$a,27,$t0
++	addl	@X[$j%16],@X[$j%16],@X[$j%16]
++
++	or	$t3,$b,$b
++	addl	$t0,$e,$e
++	or	$t1,@X[$j%16],@X[$j%16]
++___
++$code.=<<___ if ($i<77);
++	zapnot	@X[$i%16],0xf,@X[$i%16]
++___
++$code.=<<___ if ($i==79);	# with context fetch
++	sll	$a,5,$t1
++	addl	$K,$e,$e
++	zapnot	$a,0xf,$a
++	ldl	@X[0],0($ctx)
++
++	sll	$b,30,$t3
++	addl	$t1,$e,$e
++	xor	$b,$c,$t2
++	ldl	@X[1],4($ctx)
++
++	srl	$b,2,$b
++	addl	@X[$i%16],$e,$e
++	xor	$d,$t2,$t2
++	ldl	@X[2],8($ctx)
++
++	srl	$a,27,$t0
++	addl	$t2,$e,$e
++	ldl	@X[3],12($ctx)
++
++	or	$t3,$b,$b
++	addl	$t0,$e,$e
++	ldl	@X[4],16($ctx)
++___
++}
++
++sub BODY_40_59 {
++my ($i,$a,$b,$c,$d,$e)=@_;
++my $j=$i+1;
++$code.=<<___;	# with forward Xupdate
++	sll	$a,5,$t1
++	addl	$K,$e,$e
++	zapnot	$a,0xf,$a
++	xor	@X[($j+2)%16],@X[$j%16],@X[$j%16]
++
++	srl	$a,27,$t0
++	and	$b,$c,$t2
++	and	$b,$d,$t3
++	xor	@X[($j+8)%16],@X[$j%16],@X[$j%16]
++
++	sll	$b,30,$b
++	addl	$t1,$e,$e
++	xor	@X[($j+13)%16],@X[$j%16],@X[$j%16]
++
++	srl	@X[$j%16],31,$t1
++	addl	$t0,$e,$e
++	or	$t2,$t3,$t2
++	and	$c,$d,$t3
++
++	or	$t2,$t3,$t2
++	srl	$b,32,$t3
++	addl	@X[$i%16],$e,$e
++	addl	@X[$j%16],@X[$j%16],@X[$j%16]
++
++	or	$t3,$b,$b
++	addl	$t2,$e,$e
++	or	$t1,@X[$j%16],@X[$j%16]
++	zapnot	@X[$i%16],0xf,@X[$i%16]
++___
++}
++
++$code=<<___;
++#ifdef __linux__
++#include 
++#else
++#include 
++#include 
++#endif
++
++.text
++
++.set	noat
++.set	noreorder
++.globl	sha1_block_data_order
++.align	5
++.ent	sha1_block_data_order
++sha1_block_data_order:
++	lda	sp,-64(sp)
++	stq	ra,0(sp)
++	stq	s0,8(sp)
++	stq	s1,16(sp)
++	stq	s2,24(sp)
++	stq	s3,32(sp)
++	stq	s4,40(sp)
++	stq	s5,48(sp)
++	stq	fp,56(sp)
++	.mask	0x0400fe00,-64
++	.frame	sp,64,ra
++	.prologue 0
++
++	ldl	$A,0($ctx)
++	ldl	$B,4($ctx)
++	sll	$num,6,$num
++	ldl	$C,8($ctx)
++	ldl	$D,12($ctx)
++	ldl	$E,16($ctx)
++	addq	$inp,$num,$num
++
++.Lloop:
++	.set	noreorder
++	ldah	$K,23170(zero)
++	zapnot	$B,0xf,$B
++	lda	$K,31129($K)	# K_00_19
++___
++for ($i=0;$i<20;$i++) { &BODY_00_19($i,@V); unshift(@V,pop(@V)); }
++
++$code.=<<___;
++	ldah	$K,28378(zero)
++	lda	$K,-5215($K)	# K_20_39
++___
++for (;$i<40;$i++) { &BODY_20_39($i,@V); unshift(@V,pop(@V)); }
++
++$code.=<<___;
++	ldah	$K,-28900(zero)
++	lda	$K,-17188($K)	# K_40_59
++___
++for (;$i<60;$i++) { &BODY_40_59($i,@V); unshift(@V,pop(@V)); }
++
++$code.=<<___;
++	ldah	$K,-13725(zero)
++	lda	$K,-15914($K)	# K_60_79
++___
++for (;$i<80;$i++) { &BODY_20_39($i,@V); unshift(@V,pop(@V)); }
++
++$code.=<<___;
++	addl	@X[0],$A,$A
++	addl	@X[1],$B,$B
++	addl	@X[2],$C,$C
++	addl	@X[3],$D,$D
++	addl	@X[4],$E,$E
++	stl	$A,0($ctx)
++	stl	$B,4($ctx)
++	addq	$inp,64,$inp
++	stl	$C,8($ctx)
++	stl	$D,12($ctx)
++	stl	$E,16($ctx)
++	cmpult	$inp,$num,$t1
++	bne	$t1,.Lloop
++
++	.set	noreorder
++	ldq	ra,0(sp)
++	ldq	s0,8(sp)
++	ldq	s1,16(sp)
++	ldq	s2,24(sp)
++	ldq	s3,32(sp)
++	ldq	s4,40(sp)
++	ldq	s5,48(sp)
++	ldq	fp,56(sp)
++	lda	sp,64(sp)
++	ret	(ra)
++.end	sha1_block_data_order
++.ascii	"SHA1 block transform for Alpha, CRYPTOGAMS by "
++.align	2
++___
++$output=pop and open STDOUT,">$output";
++print $code;
++close STDOUT;
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/sha/asm/sha1-armv4-large.pl b/CryptoPkg/Library/OpensslLib/openssl/crypto/sha/asm/sha1-armv4-large.pl
+new file mode 100644
+index 0000000..7ff5bfb
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/sha/asm/sha1-armv4-large.pl
+@@ -0,0 +1,742 @@
++#! /usr/bin/env perl
++# Copyright 2007-2016 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
++# in the file LICENSE in the source distribution or at
++# https://www.openssl.org/source/license.html
++
++
++# ====================================================================
++# Written by Andy Polyakov  for the OpenSSL
++# project. The module is, however, dual licensed under OpenSSL and
++# CRYPTOGAMS licenses depending on where you obtain it. For further
++# details see http://www.openssl.org/~appro/cryptogams/.
++# ====================================================================
++
++# sha1_block procedure for ARMv4.
++#
++# January 2007.
++
++# Size/performance trade-off
++# ====================================================================
++# impl		size in bytes	comp cycles[*]	measured performance
++# ====================================================================
++# thumb		304		3212		4420
++# armv4-small	392/+29%	1958/+64%	2250/+96%
++# armv4-compact	740/+89%	1552/+26%	1840/+22%
++# armv4-large	1420/+92%	1307/+19%	1370/+34%[***]
++# full unroll	~5100/+260%	~1260/+4%	~1300/+5%
++# ====================================================================
++# thumb		= same as 'small' but in Thumb instructions[**] and
++#		  with recurring code in two private functions;
++# small		= detached Xload/update, loops are folded;
++# compact	= detached Xload/update, 5x unroll;
++# large		= interleaved Xload/update, 5x unroll;
++# full unroll	= interleaved Xload/update, full unroll, estimated[!];
++#
++# [*]	Manually counted instructions in "grand" loop body. Measured
++#	performance is affected by prologue and epilogue overhead,
++#	i-cache availability, branch penalties, etc.
++# [**]	While each Thumb instruction is twice smaller, they are not as
++#	diverse as ARM ones: e.g., there are only two arithmetic
++#	instructions with 3 arguments, no [fixed] rotate, addressing
++#	modes are limited. As result it takes more instructions to do
++#	the same job in Thumb, therefore the code is never twice as
++#	small and always slower.
++# [***]	which is also ~35% better than compiler generated code. Dual-
++#	issue Cortex A8 core was measured to process input block in
++#	~990 cycles.
++
++# August 2010.
++#
++# Rescheduling for dual-issue pipeline resulted in 13% improvement on
++# Cortex A8 core and in absolute terms ~870 cycles per input block
++# [or 13.6 cycles per byte].
++
++# February 2011.
++#
++# Profiler-assisted and platform-specific optimization resulted in 10%
++# improvement on Cortex A8 core and 12.2 cycles per byte.
++
++# September 2013.
++#
++# Add NEON implementation (see sha1-586.pl for background info). On
++# Cortex A8 it was measured to process one byte in 6.7 cycles or >80%
++# faster than integer-only code. Because [fully unrolled] NEON code
++# is ~2.5x larger and there are some redundant instructions executed
++# when processing last block, improvement is not as big for smallest
++# blocks, only ~30%. Snapdragon S4 is a tad faster, 6.4 cycles per
++# byte, which is also >80% faster than integer-only code. Cortex-A15
++# is even faster spending 5.6 cycles per byte outperforming integer-
++# only code by factor of 2.
++
++# May 2014.
++#
++# Add ARMv8 code path performing at 2.35 cpb on Apple A7.
++
++$flavour = shift;
++if ($flavour=~/\w[\w\-]*\.\w+$/) { $output=$flavour; undef $flavour; }
++else { while (($output=shift) && ($output!~/\w[\w\-]*\.\w+$/)) {} }
++
++if ($flavour && $flavour ne "void") {
++    $0 =~ m/(.*[\/\\])[^\/\\]+$/; $dir=$1;
++    ( $xlate="${dir}arm-xlate.pl" and -f $xlate ) or
++    ( $xlate="${dir}../../perlasm/arm-xlate.pl" and -f $xlate) or
++    die "can't locate arm-xlate.pl";
++
++    open STDOUT,"| \"$^X\" $xlate $flavour $output";
++} else {
++    open STDOUT,">$output";
++}
++
++$ctx="r0";
++$inp="r1";
++$len="r2";
++$a="r3";
++$b="r4";
++$c="r5";
++$d="r6";
++$e="r7";
++$K="r8";
++$t0="r9";
++$t1="r10";
++$t2="r11";
++$t3="r12";
++$Xi="r14";
++@V=($a,$b,$c,$d,$e);
++
++sub Xupdate {
++my ($a,$b,$c,$d,$e,$opt1,$opt2)=@_;
++$code.=<<___;
++	ldr	$t0,[$Xi,#15*4]
++	ldr	$t1,[$Xi,#13*4]
++	ldr	$t2,[$Xi,#7*4]
++	add	$e,$K,$e,ror#2			@ E+=K_xx_xx
++	ldr	$t3,[$Xi,#2*4]
++	eor	$t0,$t0,$t1
++	eor	$t2,$t2,$t3			@ 1 cycle stall
++	eor	$t1,$c,$d			@ F_xx_xx
++	mov	$t0,$t0,ror#31
++	add	$e,$e,$a,ror#27			@ E+=ROR(A,27)
++	eor	$t0,$t0,$t2,ror#31
++	str	$t0,[$Xi,#-4]!
++	$opt1					@ F_xx_xx
++	$opt2					@ F_xx_xx
++	add	$e,$e,$t0			@ E+=X[i]
++___
++}
++
++sub BODY_00_15 {
++my ($a,$b,$c,$d,$e)=@_;
++$code.=<<___;
++#if __ARM_ARCH__<7
++	ldrb	$t1,[$inp,#2]
++	ldrb	$t0,[$inp,#3]
++	ldrb	$t2,[$inp,#1]
++	add	$e,$K,$e,ror#2			@ E+=K_00_19
++	ldrb	$t3,[$inp],#4
++	orr	$t0,$t0,$t1,lsl#8
++	eor	$t1,$c,$d			@ F_xx_xx
++	orr	$t0,$t0,$t2,lsl#16
++	add	$e,$e,$a,ror#27			@ E+=ROR(A,27)
++	orr	$t0,$t0,$t3,lsl#24
++#else
++	ldr	$t0,[$inp],#4			@ handles unaligned
++	add	$e,$K,$e,ror#2			@ E+=K_00_19
++	eor	$t1,$c,$d			@ F_xx_xx
++	add	$e,$e,$a,ror#27			@ E+=ROR(A,27)
++#ifdef __ARMEL__
++	rev	$t0,$t0				@ byte swap
++#endif
++#endif
++	and	$t1,$b,$t1,ror#2
++	add	$e,$e,$t0			@ E+=X[i]
++	eor	$t1,$t1,$d,ror#2		@ F_00_19(B,C,D)
++	str	$t0,[$Xi,#-4]!
++	add	$e,$e,$t1			@ E+=F_00_19(B,C,D)
++___
++}
++
++sub BODY_16_19 {
++my ($a,$b,$c,$d,$e)=@_;
++	&Xupdate(@_,"and $t1,$b,$t1,ror#2");
++$code.=<<___;
++	eor	$t1,$t1,$d,ror#2		@ F_00_19(B,C,D)
++	add	$e,$e,$t1			@ E+=F_00_19(B,C,D)
++___
++}
++
++sub BODY_20_39 {
++my ($a,$b,$c,$d,$e)=@_;
++	&Xupdate(@_,"eor $t1,$b,$t1,ror#2");
++$code.=<<___;
++	add	$e,$e,$t1			@ E+=F_20_39(B,C,D)
++___
++}
++
++sub BODY_40_59 {
++my ($a,$b,$c,$d,$e)=@_;
++	&Xupdate(@_,"and $t1,$b,$t1,ror#2","and $t2,$c,$d");
++$code.=<<___;
++	add	$e,$e,$t1			@ E+=F_40_59(B,C,D)
++	add	$e,$e,$t2,ror#2
++___
++}
++
++$code=<<___;
++#include "arm_arch.h"
++
++.text
++#if defined(__thumb2__)
++.syntax	unified
++.thumb
++#else
++.code	32
++#endif
++
++.global	sha1_block_data_order
++.type	sha1_block_data_order,%function
++
++.align	5
++sha1_block_data_order:
++#if __ARM_MAX_ARCH__>=7
++.Lsha1_block:
++	adr	r3,.Lsha1_block
++	ldr	r12,.LOPENSSL_armcap
++	ldr	r12,[r3,r12]		@ OPENSSL_armcap_P
++#ifdef	__APPLE__
++	ldr	r12,[r12]
++#endif
++	tst	r12,#ARMV8_SHA1
++	bne	.LARMv8
++	tst	r12,#ARMV7_NEON
++	bne	.LNEON
++#endif
++	stmdb	sp!,{r4-r12,lr}
++	add	$len,$inp,$len,lsl#6	@ $len to point at the end of $inp
++	ldmia	$ctx,{$a,$b,$c,$d,$e}
++.Lloop:
++	ldr	$K,.LK_00_19
++	mov	$Xi,sp
++	sub	sp,sp,#15*4
++	mov	$c,$c,ror#30
++	mov	$d,$d,ror#30
++	mov	$e,$e,ror#30		@ [6]
++.L_00_15:
++___
++for($i=0;$i<5;$i++) {
++	&BODY_00_15(@V);	unshift(@V,pop(@V));
++}
++$code.=<<___;
++#if defined(__thumb2__)
++	mov	$t3,sp
++	teq	$Xi,$t3
++#else
++	teq	$Xi,sp
++#endif
++	bne	.L_00_15		@ [((11+4)*5+2)*3]
++	sub	sp,sp,#25*4
++___
++	&BODY_00_15(@V);	unshift(@V,pop(@V));
++	&BODY_16_19(@V);	unshift(@V,pop(@V));
++	&BODY_16_19(@V);	unshift(@V,pop(@V));
++	&BODY_16_19(@V);	unshift(@V,pop(@V));
++	&BODY_16_19(@V);	unshift(@V,pop(@V));
++$code.=<<___;
++
++	ldr	$K,.LK_20_39		@ [+15+16*4]
++	cmn	sp,#0			@ [+3], clear carry to denote 20_39
++.L_20_39_or_60_79:
++___
++for($i=0;$i<5;$i++) {
++	&BODY_20_39(@V);	unshift(@V,pop(@V));
++}
++$code.=<<___;
++#if defined(__thumb2__)
++	mov	$t3,sp
++	teq	$Xi,$t3
++#else
++	teq	$Xi,sp			@ preserve carry
++#endif
++	bne	.L_20_39_or_60_79	@ [+((12+3)*5+2)*4]
++	bcs	.L_done			@ [+((12+3)*5+2)*4], spare 300 bytes
++
++	ldr	$K,.LK_40_59
++	sub	sp,sp,#20*4		@ [+2]
++.L_40_59:
++___
++for($i=0;$i<5;$i++) {
++	&BODY_40_59(@V);	unshift(@V,pop(@V));
++}
++$code.=<<___;
++#if defined(__thumb2__)
++	mov	$t3,sp
++	teq	$Xi,$t3
++#else
++	teq	$Xi,sp
++#endif
++	bne	.L_40_59		@ [+((12+5)*5+2)*4]
++
++	ldr	$K,.LK_60_79
++	sub	sp,sp,#20*4
++	cmp	sp,#0			@ set carry to denote 60_79
++	b	.L_20_39_or_60_79	@ [+4], spare 300 bytes
++.L_done:
++	add	sp,sp,#80*4		@ "deallocate" stack frame
++	ldmia	$ctx,{$K,$t0,$t1,$t2,$t3}
++	add	$a,$K,$a
++	add	$b,$t0,$b
++	add	$c,$t1,$c,ror#2
++	add	$d,$t2,$d,ror#2
++	add	$e,$t3,$e,ror#2
++	stmia	$ctx,{$a,$b,$c,$d,$e}
++	teq	$inp,$len
++	bne	.Lloop			@ [+18], total 1307
++
++#if __ARM_ARCH__>=5
++	ldmia	sp!,{r4-r12,pc}
++#else
++	ldmia	sp!,{r4-r12,lr}
++	tst	lr,#1
++	moveq	pc,lr			@ be binary compatible with V4, yet
++	bx	lr			@ interoperable with Thumb ISA:-)
++#endif
++.size	sha1_block_data_order,.-sha1_block_data_order
++
++.align	5
++.LK_00_19:	.word	0x5a827999
++.LK_20_39:	.word	0x6ed9eba1
++.LK_40_59:	.word	0x8f1bbcdc
++.LK_60_79:	.word	0xca62c1d6
++#if __ARM_MAX_ARCH__>=7
++.LOPENSSL_armcap:
++.word	OPENSSL_armcap_P-.Lsha1_block
++#endif
++.asciz	"SHA1 block transform for ARMv4/NEON/ARMv8, CRYPTOGAMS by "
++.align	5
++___
++#####################################################################
++# NEON stuff
++#
++{{{
++my @V=($a,$b,$c,$d,$e);
++my ($K_XX_XX,$Ki,$t0,$t1,$Xfer,$saved_sp)=map("r$_",(8..12,14));
++my $Xi=4;
++my @X=map("q$_",(8..11,0..3));
++my @Tx=("q12","q13");
++my ($K,$zero)=("q14","q15");
++my $j=0;
++
++sub AUTOLOAD()          # thunk [simplified] x86-style perlasm
++{ my $opcode = $AUTOLOAD; $opcode =~ s/.*:://; $opcode =~ s/_/\./;
++  my $arg = pop;
++    $arg = "#$arg" if ($arg*1 eq $arg);
++    $code .= "\t$opcode\t".join(',',@_,$arg)."\n";
++}
++
++sub body_00_19 () {
++	(
++	'($a,$b,$c,$d,$e)=@V;'.		# '$code.="@ $j\n";'.
++	'&bic	($t0,$d,$b)',
++	'&add	($e,$e,$Ki)',		# e+=X[i]+K
++	'&and	($t1,$c,$b)',
++	'&ldr	($Ki,sprintf "[sp,#%d]",4*(($j+1)&15))',
++	'&add	($e,$e,$a,"ror#27")',	# e+=ROR(A,27)
++	'&eor	($t1,$t1,$t0)',		# F_00_19
++	'&mov	($b,$b,"ror#2")',	# b=ROR(b,2)
++	'&add	($e,$e,$t1);'.		# e+=F_00_19
++	'$j++;	unshift(@V,pop(@V));'
++	)
++}
++sub body_20_39 () {
++	(
++	'($a,$b,$c,$d,$e)=@V;'.		# '$code.="@ $j\n";'.
++	'&eor	($t0,$b,$d)',
++	'&add	($e,$e,$Ki)',		# e+=X[i]+K
++	'&ldr	($Ki,sprintf "[sp,#%d]",4*(($j+1)&15)) if ($j<79)',
++	'&eor	($t1,$t0,$c)',		# F_20_39
++	'&add	($e,$e,$a,"ror#27")',	# e+=ROR(A,27)
++	'&mov	($b,$b,"ror#2")',	# b=ROR(b,2)
++	'&add	($e,$e,$t1);'.		# e+=F_20_39
++	'$j++;	unshift(@V,pop(@V));'
++	)
++}
++sub body_40_59 () {
++	(
++	'($a,$b,$c,$d,$e)=@V;'.		# '$code.="@ $j\n";'.
++	'&add	($e,$e,$Ki)',		# e+=X[i]+K
++	'&and	($t0,$c,$d)',
++	'&ldr	($Ki,sprintf "[sp,#%d]",4*(($j+1)&15))',
++	'&add	($e,$e,$a,"ror#27")',	# e+=ROR(A,27)
++	'&eor	($t1,$c,$d)',
++	'&add	($e,$e,$t0)',
++	'&and	($t1,$t1,$b)',
++	'&mov	($b,$b,"ror#2")',	# b=ROR(b,2)
++	'&add	($e,$e,$t1);'.		# e+=F_40_59
++	'$j++;	unshift(@V,pop(@V));'
++	)
++}
++
++sub Xupdate_16_31 ()
++{ use integer;
++  my $body = shift;
++  my @insns = (&$body,&$body,&$body,&$body);
++  my ($a,$b,$c,$d,$e);
++
++	&vext_8		(@X[0],@X[-4&7],@X[-3&7],8);	# compose "X[-14]" in "X[0]"
++	 eval(shift(@insns));
++	 eval(shift(@insns));
++	 eval(shift(@insns));
++	  &vadd_i32	(@Tx[1],@X[-1&7],$K);
++	 eval(shift(@insns));
++	  &vld1_32	("{$K\[]}","[$K_XX_XX,:32]!")	if ($Xi%5==0);
++	 eval(shift(@insns));
++	&vext_8		(@Tx[0],@X[-1&7],$zero,4);	# "X[-3]", 3 words
++	 eval(shift(@insns));
++	 eval(shift(@insns));
++	 eval(shift(@insns));
++	&veor		(@X[0],@X[0],@X[-4&7]);		# "X[0]"^="X[-16]"
++	 eval(shift(@insns));
++	 eval(shift(@insns));
++	&veor		(@Tx[0],@Tx[0],@X[-2&7]);	# "X[-3]"^"X[-8]"
++	 eval(shift(@insns));
++	 eval(shift(@insns));
++	&veor		(@Tx[0],@Tx[0],@X[0]);		# "X[0]"^="X[-3]"^"X[-8]
++	 eval(shift(@insns));
++	 eval(shift(@insns));
++	  &vst1_32	("{@Tx[1]}","[$Xfer,:128]!");	# X[]+K xfer
++	  &sub		($Xfer,$Xfer,64)		if ($Xi%4==0);
++	 eval(shift(@insns));
++	 eval(shift(@insns));
++	&vext_8		(@Tx[1],$zero,@Tx[0],4);	# "X[0]"<<96, extract one dword
++	 eval(shift(@insns));
++	 eval(shift(@insns));
++	&vadd_i32	(@X[0],@Tx[0],@Tx[0]);
++	 eval(shift(@insns));
++	 eval(shift(@insns));
++	&vsri_32	(@X[0],@Tx[0],31);		# "X[0]"<<<=1
++	 eval(shift(@insns));
++	 eval(shift(@insns));
++	 eval(shift(@insns));
++	&vshr_u32	(@Tx[0],@Tx[1],30);
++	 eval(shift(@insns));
++	 eval(shift(@insns));
++	&vshl_u32	(@Tx[1],@Tx[1],2);
++	 eval(shift(@insns));
++	 eval(shift(@insns));
++	&veor		(@X[0],@X[0],@Tx[0]);
++	 eval(shift(@insns));
++	 eval(shift(@insns));
++	&veor		(@X[0],@X[0],@Tx[1]);		# "X[0]"^=("X[0]">>96)<<<2
++
++	foreach (@insns) { eval; }	# remaining instructions [if any]
++
++  $Xi++;	push(@X,shift(@X));	# "rotate" X[]
++}
++
++sub Xupdate_32_79 ()
++{ use integer;
++  my $body = shift;
++  my @insns = (&$body,&$body,&$body,&$body);
++  my ($a,$b,$c,$d,$e);
++
++	&vext_8		(@Tx[0],@X[-2&7],@X[-1&7],8);	# compose "X[-6]"
++	 eval(shift(@insns));
++	 eval(shift(@insns));
++	 eval(shift(@insns));
++	&veor		(@X[0],@X[0],@X[-4&7]);		# "X[0]"="X[-32]"^"X[-16]"
++	 eval(shift(@insns));
++	 eval(shift(@insns));
++	&veor		(@X[0],@X[0],@X[-7&7]);		# "X[0]"^="X[-28]"
++	 eval(shift(@insns));
++	 eval(shift(@insns));
++	  &vadd_i32	(@Tx[1],@X[-1&7],$K);
++	 eval(shift(@insns));
++	  &vld1_32	("{$K\[]}","[$K_XX_XX,:32]!")	if ($Xi%5==0);
++	 eval(shift(@insns));
++	&veor		(@Tx[0],@Tx[0],@X[0]);		# "X[-6]"^="X[0]"
++	 eval(shift(@insns));
++	 eval(shift(@insns));
++	&vshr_u32	(@X[0],@Tx[0],30);
++	 eval(shift(@insns));
++	 eval(shift(@insns));
++	  &vst1_32	("{@Tx[1]}","[$Xfer,:128]!");	# X[]+K xfer
++	  &sub		($Xfer,$Xfer,64)		if ($Xi%4==0);
++	 eval(shift(@insns));
++	 eval(shift(@insns));
++	&vsli_32	(@X[0],@Tx[0],2);		# "X[0]"="X[-6]"<<<2
++
++	foreach (@insns) { eval; }	# remaining instructions [if any]
++
++  $Xi++;	push(@X,shift(@X));	# "rotate" X[]
++}
++
++sub Xuplast_80 ()
++{ use integer;
++  my $body = shift;
++  my @insns = (&$body,&$body,&$body,&$body);
++  my ($a,$b,$c,$d,$e);
++
++	&vadd_i32	(@Tx[1],@X[-1&7],$K);
++	 eval(shift(@insns));
++	 eval(shift(@insns));
++	&vst1_32	("{@Tx[1]}","[$Xfer,:128]!");
++	&sub		($Xfer,$Xfer,64);
++
++	&teq		($inp,$len);
++	&sub		($K_XX_XX,$K_XX_XX,16);	# rewind $K_XX_XX
++	&it		("eq");
++	&subeq		($inp,$inp,64);		# reload last block to avoid SEGV
++	&vld1_8		("{@X[-4&7]-@X[-3&7]}","[$inp]!");
++	 eval(shift(@insns));
++	 eval(shift(@insns));
++	&vld1_8		("{@X[-2&7]-@X[-1&7]}","[$inp]!");
++	 eval(shift(@insns));
++	 eval(shift(@insns));
++	&vld1_32	("{$K\[]}","[$K_XX_XX,:32]!");	# load K_00_19
++	 eval(shift(@insns));
++	 eval(shift(@insns));
++	&vrev32_8	(@X[-4&7],@X[-4&7]);
++
++	foreach (@insns) { eval; }		# remaining instructions
++
++   $Xi=0;
++}
++
++sub Xloop()
++{ use integer;
++  my $body = shift;
++  my @insns = (&$body,&$body,&$body,&$body);
++  my ($a,$b,$c,$d,$e);
++
++	&vrev32_8	(@X[($Xi-3)&7],@X[($Xi-3)&7]);
++	 eval(shift(@insns));
++	 eval(shift(@insns));
++	&vadd_i32	(@X[$Xi&7],@X[($Xi-4)&7],$K);
++	 eval(shift(@insns));
++	 eval(shift(@insns));
++	&vst1_32	("{@X[$Xi&7]}","[$Xfer,:128]!");# X[]+K xfer to IALU
++
++	foreach (@insns) { eval; }
++
++  $Xi++;
++}
++
++$code.=<<___;
++#if __ARM_MAX_ARCH__>=7
++.arch	armv7-a
++.fpu	neon
++
++.type	sha1_block_data_order_neon,%function
++.align	4
++sha1_block_data_order_neon:
++.LNEON:
++	stmdb	sp!,{r4-r12,lr}
++	add	$len,$inp,$len,lsl#6	@ $len to point at the end of $inp
++	@ dmb				@ errata #451034 on early Cortex A8
++	@ vstmdb	sp!,{d8-d15}	@ ABI specification says so
++	mov	$saved_sp,sp
++	sub	$Xfer,sp,#64
++	adr	$K_XX_XX,.LK_00_19
++	bic	$Xfer,$Xfer,#15		@ align for 128-bit stores
++
++	ldmia	$ctx,{$a,$b,$c,$d,$e}	@ load context
++	mov	sp,$Xfer		@ alloca
++
++	vld1.8		{@X[-4&7]-@X[-3&7]},[$inp]!	@ handles unaligned
++	veor		$zero,$zero,$zero
++	vld1.8		{@X[-2&7]-@X[-1&7]},[$inp]!
++	vld1.32		{${K}\[]},[$K_XX_XX,:32]!	@ load K_00_19
++	vrev32.8	@X[-4&7],@X[-4&7]		@ yes, even on
++	vrev32.8	@X[-3&7],@X[-3&7]		@ big-endian...
++	vrev32.8	@X[-2&7],@X[-2&7]
++	vadd.i32	@X[0],@X[-4&7],$K
++	vrev32.8	@X[-1&7],@X[-1&7]
++	vadd.i32	@X[1],@X[-3&7],$K
++	vst1.32		{@X[0]},[$Xfer,:128]!
++	vadd.i32	@X[2],@X[-2&7],$K
++	vst1.32		{@X[1]},[$Xfer,:128]!
++	vst1.32		{@X[2]},[$Xfer,:128]!
++	ldr		$Ki,[sp]			@ big RAW stall
++
++.Loop_neon:
++___
++	&Xupdate_16_31(\&body_00_19);
++	&Xupdate_16_31(\&body_00_19);
++	&Xupdate_16_31(\&body_00_19);
++	&Xupdate_16_31(\&body_00_19);
++	&Xupdate_32_79(\&body_00_19);
++	&Xupdate_32_79(\&body_20_39);
++	&Xupdate_32_79(\&body_20_39);
++	&Xupdate_32_79(\&body_20_39);
++	&Xupdate_32_79(\&body_20_39);
++	&Xupdate_32_79(\&body_20_39);
++	&Xupdate_32_79(\&body_40_59);
++	&Xupdate_32_79(\&body_40_59);
++	&Xupdate_32_79(\&body_40_59);
++	&Xupdate_32_79(\&body_40_59);
++	&Xupdate_32_79(\&body_40_59);
++	&Xupdate_32_79(\&body_20_39);
++	&Xuplast_80(\&body_20_39);
++	&Xloop(\&body_20_39);
++	&Xloop(\&body_20_39);
++	&Xloop(\&body_20_39);
++$code.=<<___;
++	ldmia	$ctx,{$Ki,$t0,$t1,$Xfer}	@ accumulate context
++	add	$a,$a,$Ki
++	ldr	$Ki,[$ctx,#16]
++	add	$b,$b,$t0
++	add	$c,$c,$t1
++	add	$d,$d,$Xfer
++	it	eq
++	moveq	sp,$saved_sp
++	add	$e,$e,$Ki
++	it	ne
++	ldrne	$Ki,[sp]
++	stmia	$ctx,{$a,$b,$c,$d,$e}
++	itt	ne
++	addne	$Xfer,sp,#3*16
++	bne	.Loop_neon
++
++	@ vldmia	sp!,{d8-d15}
++	ldmia	sp!,{r4-r12,pc}
++.size	sha1_block_data_order_neon,.-sha1_block_data_order_neon
++#endif
++___
++}}}
++#####################################################################
++# ARMv8 stuff
++#
++{{{
++my ($ABCD,$E,$E0,$E1)=map("q$_",(0..3));
++my @MSG=map("q$_",(4..7));
++my @Kxx=map("q$_",(8..11));
++my ($W0,$W1,$ABCD_SAVE)=map("q$_",(12..14));
++
++$code.=<<___;
++#if __ARM_MAX_ARCH__>=7
++
++# if defined(__thumb2__)
++#  define INST(a,b,c,d)	.byte	c,d|0xf,a,b
++# else
++#  define INST(a,b,c,d)	.byte	a,b,c,d|0x10
++# endif
++
++.type	sha1_block_data_order_armv8,%function
++.align	5
++sha1_block_data_order_armv8:
++.LARMv8:
++	vstmdb	sp!,{d8-d15}		@ ABI specification says so
++
++	veor	$E,$E,$E
++	adr	r3,.LK_00_19
++	vld1.32	{$ABCD},[$ctx]!
++	vld1.32	{$E\[0]},[$ctx]
++	sub	$ctx,$ctx,#16
++	vld1.32	{@Kxx[0]\[]},[r3,:32]!
++	vld1.32	{@Kxx[1]\[]},[r3,:32]!
++	vld1.32	{@Kxx[2]\[]},[r3,:32]!
++	vld1.32	{@Kxx[3]\[]},[r3,:32]
++
++.Loop_v8:
++	vld1.8		{@MSG[0]-@MSG[1]},[$inp]!
++	vld1.8		{@MSG[2]-@MSG[3]},[$inp]!
++	vrev32.8	@MSG[0],@MSG[0]
++	vrev32.8	@MSG[1],@MSG[1]
++
++	vadd.i32	$W0,@Kxx[0],@MSG[0]
++	vrev32.8	@MSG[2],@MSG[2]
++	vmov		$ABCD_SAVE,$ABCD	@ offload
++	subs		$len,$len,#1
++
++	vadd.i32	$W1,@Kxx[0],@MSG[1]
++	vrev32.8	@MSG[3],@MSG[3]
++	sha1h		$E1,$ABCD		@ 0
++	sha1c		$ABCD,$E,$W0
++	vadd.i32	$W0,@Kxx[$j],@MSG[2]
++	sha1su0		@MSG[0],@MSG[1],@MSG[2]
++___
++for ($j=0,$i=1;$i<20-3;$i++) {
++my $f=("c","p","m","p")[$i/5];
++$code.=<<___;
++	sha1h		$E0,$ABCD		@ $i
++	sha1$f		$ABCD,$E1,$W1
++	vadd.i32	$W1,@Kxx[$j],@MSG[3]
++	sha1su1		@MSG[0],@MSG[3]
++___
++$code.=<<___ if ($i<20-4);
++	sha1su0		@MSG[1],@MSG[2],@MSG[3]
++___
++	($E0,$E1)=($E1,$E0);	($W0,$W1)=($W1,$W0);
++	push(@MSG,shift(@MSG));	$j++ if ((($i+3)%5)==0);
++}
++$code.=<<___;
++	sha1h		$E0,$ABCD		@ $i
++	sha1p		$ABCD,$E1,$W1
++	vadd.i32	$W1,@Kxx[$j],@MSG[3]
++
++	sha1h		$E1,$ABCD		@ 18
++	sha1p		$ABCD,$E0,$W0
++
++	sha1h		$E0,$ABCD		@ 19
++	sha1p		$ABCD,$E1,$W1
++
++	vadd.i32	$E,$E,$E0
++	vadd.i32	$ABCD,$ABCD,$ABCD_SAVE
++	bne		.Loop_v8
++
++	vst1.32		{$ABCD},[$ctx]!
++	vst1.32		{$E\[0]},[$ctx]
++
++	vldmia	sp!,{d8-d15}
++	ret					@ bx lr
++.size	sha1_block_data_order_armv8,.-sha1_block_data_order_armv8
++#endif
++___
++}}}
++$code.=<<___;
++#if __ARM_MAX_ARCH__>=7
++.comm	OPENSSL_armcap_P,4,4
++#endif
++___
++
++{   my  %opcode = (
++	"sha1c"		=> 0xf2000c40,	"sha1p"		=> 0xf2100c40,
++	"sha1m"		=> 0xf2200c40,	"sha1su0"	=> 0xf2300c40,
++	"sha1h"		=> 0xf3b902c0,	"sha1su1"	=> 0xf3ba0380	);
++
++    sub unsha1 {
++	my ($mnemonic,$arg)=@_;
++
++	if ($arg =~ m/q([0-9]+)(?:,\s*q([0-9]+))?,\s*q([0-9]+)/o) {
++	    my $word = $opcode{$mnemonic}|(($1&7)<<13)|(($1&8)<<19)
++					 |(($2&7)<<17)|(($2&8)<<4)
++					 |(($3&7)<<1) |(($3&8)<<2);
++	    # since ARMv7 instructions are always encoded little-endian.
++	    # correct solution is to use .inst directive, but older
++	    # assemblers don't implement it:-(
++
++	    # this fix-up provides Thumb encoding in conjunction with INST
++	    $word &= ~0x10000000 if (($word & 0x0f000000) == 0x02000000);
++	    sprintf "INST(0x%02x,0x%02x,0x%02x,0x%02x)\t@ %s %s",
++			$word&0xff,($word>>8)&0xff,
++			($word>>16)&0xff,($word>>24)&0xff,
++			$mnemonic,$arg;
++	}
++    }
++}
++
++foreach (split($/,$code)) {
++	s/{q([0-9]+)\[\]}/sprintf "{d%d[],d%d[]}",2*$1,2*$1+1/eo	or
++	s/{q([0-9]+)\[0\]}/sprintf "{d%d[0]}",2*$1/eo;
++
++	s/\b(sha1\w+)\s+(q.*)/unsha1($1,$2)/geo;
++
++	s/\bret\b/bx	lr/o		or
++	s/\bbx\s+lr\b/.word\t0xe12fff1e/o;	# make it possible to compile with -march=armv4
++
++	print $_,$/;
++}
++
++close STDOUT; # enforce flush
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/sha/asm/sha1-armv8.pl b/CryptoPkg/Library/OpensslLib/openssl/crypto/sha/asm/sha1-armv8.pl
+new file mode 100644
+index 0000000..84a00bf
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/sha/asm/sha1-armv8.pl
+@@ -0,0 +1,363 @@
++#! /usr/bin/env perl
++# Copyright 2014-2016 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
++# in the file LICENSE in the source distribution or at
++# https://www.openssl.org/source/license.html
++
++#
++# ====================================================================
++# Written by Andy Polyakov  for the OpenSSL
++# project. The module is, however, dual licensed under OpenSSL and
++# CRYPTOGAMS licenses depending on where you obtain it. For further
++# details see http://www.openssl.org/~appro/cryptogams/.
++# ====================================================================
++#
++# SHA1 for ARMv8.
++#
++# Performance in cycles per processed byte and improvement coefficient
++# over code generated with "default" compiler:
++#
++#		hardware-assisted	software(*)
++# Apple A7	2.31			4.13 (+14%)
++# Cortex-A53	2.24			8.03 (+97%)
++# Cortex-A57	2.35			7.88 (+74%)
++# Denver	2.13			3.97 (+0%)(**)
++# X-Gene				8.80 (+200%)
++# Mongoose	2.05			6.50 (+160%)
++#
++# (*)	Software results are presented mostly for reference purposes.
++# (**)	Keep in mind that Denver relies on binary translation, which
++#	optimizes compiler output at run-time.
++
++$flavour = shift;
++$output  = shift;
++
++$0 =~ m/(.*[\/\\])[^\/\\]+$/; $dir=$1;
++( $xlate="${dir}arm-xlate.pl" and -f $xlate ) or
++( $xlate="${dir}../../perlasm/arm-xlate.pl" and -f $xlate) or
++die "can't locate arm-xlate.pl";
++
++open OUT,"| \"$^X\" $xlate $flavour $output";
++*STDOUT=*OUT;
++
++($ctx,$inp,$num)=("x0","x1","x2");
++@Xw=map("w$_",(3..17,19));
++@Xx=map("x$_",(3..17,19));
++@V=($A,$B,$C,$D,$E)=map("w$_",(20..24));
++($t0,$t1,$t2,$K)=map("w$_",(25..28));
++
++
++sub BODY_00_19 {
++my ($i,$a,$b,$c,$d,$e)=@_;
++my $j=($i+2)&15;
++
++$code.=<<___ if ($i<15 && !($i&1));
++	lsr	@Xx[$i+1],@Xx[$i],#32
++___
++$code.=<<___ if ($i<14 && !($i&1));
++	ldr	@Xx[$i+2],[$inp,#`($i+2)*4-64`]
++___
++$code.=<<___ if ($i<14 && ($i&1));
++#ifdef	__ARMEB__
++	ror	@Xx[$i+1],@Xx[$i+1],#32
++#else
++	rev32	@Xx[$i+1],@Xx[$i+1]
++#endif
++___
++$code.=<<___ if ($i<14);
++	bic	$t0,$d,$b
++	and	$t1,$c,$b
++	ror	$t2,$a,#27
++	add	$d,$d,$K		// future e+=K
++	orr	$t0,$t0,$t1
++	add	$e,$e,$t2		// e+=rot(a,5)
++	ror	$b,$b,#2
++	add	$d,$d,@Xw[($i+1)&15]	// future e+=X[i]
++	add	$e,$e,$t0		// e+=F(b,c,d)
++___
++$code.=<<___ if ($i==19);
++	movz	$K,#0xeba1
++	movk	$K,#0x6ed9,lsl#16
++___
++$code.=<<___ if ($i>=14);
++	 eor	@Xw[$j],@Xw[$j],@Xw[($j+2)&15]
++	bic	$t0,$d,$b
++	and	$t1,$c,$b
++	ror	$t2,$a,#27
++	 eor	@Xw[$j],@Xw[$j],@Xw[($j+8)&15]
++	add	$d,$d,$K		// future e+=K
++	orr	$t0,$t0,$t1
++	add	$e,$e,$t2		// e+=rot(a,5)
++	 eor	@Xw[$j],@Xw[$j],@Xw[($j+13)&15]
++	ror	$b,$b,#2
++	add	$d,$d,@Xw[($i+1)&15]	// future e+=X[i]
++	add	$e,$e,$t0		// e+=F(b,c,d)
++	 ror	@Xw[$j],@Xw[$j],#31
++___
++}
++
++sub BODY_40_59 {
++my ($i,$a,$b,$c,$d,$e)=@_;
++my $j=($i+2)&15;
++
++$code.=<<___ if ($i==59);
++	movz	$K,#0xc1d6
++	movk	$K,#0xca62,lsl#16
++___
++$code.=<<___;
++	orr	$t0,$b,$c
++	and	$t1,$b,$c
++	 eor	@Xw[$j],@Xw[$j],@Xw[($j+2)&15]
++	ror	$t2,$a,#27
++	and	$t0,$t0,$d
++	add	$d,$d,$K		// future e+=K
++	 eor	@Xw[$j],@Xw[$j],@Xw[($j+8)&15]
++	add	$e,$e,$t2		// e+=rot(a,5)
++	orr	$t0,$t0,$t1
++	ror	$b,$b,#2
++	 eor	@Xw[$j],@Xw[$j],@Xw[($j+13)&15]
++	add	$d,$d,@Xw[($i+1)&15]	// future e+=X[i]
++	add	$e,$e,$t0		// e+=F(b,c,d)
++	 ror	@Xw[$j],@Xw[$j],#31
++___
++}
++
++sub BODY_20_39 {
++my ($i,$a,$b,$c,$d,$e)=@_;
++my $j=($i+2)&15;
++
++$code.=<<___ if ($i==39);
++	movz	$K,#0xbcdc
++	movk	$K,#0x8f1b,lsl#16
++___
++$code.=<<___ if ($i<78);
++	 eor	@Xw[$j],@Xw[$j],@Xw[($j+2)&15]
++	eor	$t0,$d,$b
++	ror	$t2,$a,#27
++	add	$d,$d,$K		// future e+=K
++	 eor	@Xw[$j],@Xw[$j],@Xw[($j+8)&15]
++	eor	$t0,$t0,$c
++	add	$e,$e,$t2		// e+=rot(a,5)
++	ror	$b,$b,#2
++	 eor	@Xw[$j],@Xw[$j],@Xw[($j+13)&15]
++	add	$d,$d,@Xw[($i+1)&15]	// future e+=X[i]
++	add	$e,$e,$t0		// e+=F(b,c,d)
++	 ror	@Xw[$j],@Xw[$j],#31
++___
++$code.=<<___ if ($i==78);
++	ldp	@Xw[1],@Xw[2],[$ctx]
++	eor	$t0,$d,$b
++	ror	$t2,$a,#27
++	add	$d,$d,$K		// future e+=K
++	eor	$t0,$t0,$c
++	add	$e,$e,$t2		// e+=rot(a,5)
++	ror	$b,$b,#2
++	add	$d,$d,@Xw[($i+1)&15]	// future e+=X[i]
++	add	$e,$e,$t0		// e+=F(b,c,d)
++___
++$code.=<<___ if ($i==79);
++	ldp	@Xw[3],@Xw[4],[$ctx,#8]
++	eor	$t0,$d,$b
++	ror	$t2,$a,#27
++	eor	$t0,$t0,$c
++	add	$e,$e,$t2		// e+=rot(a,5)
++	ror	$b,$b,#2
++	ldr	@Xw[5],[$ctx,#16]
++	add	$e,$e,$t0		// e+=F(b,c,d)
++___
++}
++
++$code.=<<___;
++#include "arm_arch.h"
++
++.text
++
++.extern	OPENSSL_armcap_P
++.globl	sha1_block_data_order
++.type	sha1_block_data_order,%function
++.align	6
++sha1_block_data_order:
++#ifdef	__ILP32__
++	ldrsw	x16,.LOPENSSL_armcap_P
++#else
++	ldr	x16,.LOPENSSL_armcap_P
++#endif
++	adr	x17,.LOPENSSL_armcap_P
++	add	x16,x16,x17
++	ldr	w16,[x16]
++	tst	w16,#ARMV8_SHA1
++	b.ne	.Lv8_entry
++
++	stp	x29,x30,[sp,#-96]!
++	add	x29,sp,#0
++	stp	x19,x20,[sp,#16]
++	stp	x21,x22,[sp,#32]
++	stp	x23,x24,[sp,#48]
++	stp	x25,x26,[sp,#64]
++	stp	x27,x28,[sp,#80]
++
++	ldp	$A,$B,[$ctx]
++	ldp	$C,$D,[$ctx,#8]
++	ldr	$E,[$ctx,#16]
++
++.Loop:
++	ldr	@Xx[0],[$inp],#64
++	movz	$K,#0x7999
++	sub	$num,$num,#1
++	movk	$K,#0x5a82,lsl#16
++#ifdef	__ARMEB__
++	ror	$Xx[0],@Xx[0],#32
++#else
++	rev32	@Xx[0],@Xx[0]
++#endif
++	add	$E,$E,$K		// warm it up
++	add	$E,$E,@Xw[0]
++___
++for($i=0;$i<20;$i++)	{ &BODY_00_19($i,@V); unshift(@V,pop(@V)); }
++for(;$i<40;$i++)	{ &BODY_20_39($i,@V); unshift(@V,pop(@V)); }
++for(;$i<60;$i++)	{ &BODY_40_59($i,@V); unshift(@V,pop(@V)); }
++for(;$i<80;$i++)	{ &BODY_20_39($i,@V); unshift(@V,pop(@V)); }
++$code.=<<___;
++	add	$B,$B,@Xw[2]
++	add	$C,$C,@Xw[3]
++	add	$A,$A,@Xw[1]
++	add	$D,$D,@Xw[4]
++	add	$E,$E,@Xw[5]
++	stp	$A,$B,[$ctx]
++	stp	$C,$D,[$ctx,#8]
++	str	$E,[$ctx,#16]
++	cbnz	$num,.Loop
++
++	ldp	x19,x20,[sp,#16]
++	ldp	x21,x22,[sp,#32]
++	ldp	x23,x24,[sp,#48]
++	ldp	x25,x26,[sp,#64]
++	ldp	x27,x28,[sp,#80]
++	ldr	x29,[sp],#96
++	ret
++.size	sha1_block_data_order,.-sha1_block_data_order
++___
++{{{
++my ($ABCD,$E,$E0,$E1)=map("v$_.16b",(0..3));
++my @MSG=map("v$_.16b",(4..7));
++my @Kxx=map("v$_.4s",(16..19));
++my ($W0,$W1)=("v20.4s","v21.4s");
++my $ABCD_SAVE="v22.16b";
++
++$code.=<<___;
++.type	sha1_block_armv8,%function
++.align	6
++sha1_block_armv8:
++.Lv8_entry:
++	stp	x29,x30,[sp,#-16]!
++	add	x29,sp,#0
++
++	adr	x4,.Lconst
++	eor	$E,$E,$E
++	ld1.32	{$ABCD},[$ctx],#16
++	ld1.32	{$E}[0],[$ctx]
++	sub	$ctx,$ctx,#16
++	ld1.32	{@Kxx[0]-@Kxx[3]},[x4]
++
++.Loop_hw:
++	ld1	{@MSG[0]-@MSG[3]},[$inp],#64
++	sub	$num,$num,#1
++	rev32	@MSG[0],@MSG[0]
++	rev32	@MSG[1],@MSG[1]
++
++	add.i32	$W0,@Kxx[0],@MSG[0]
++	rev32	@MSG[2],@MSG[2]
++	orr	$ABCD_SAVE,$ABCD,$ABCD	// offload
++
++	add.i32	$W1,@Kxx[0],@MSG[1]
++	rev32	@MSG[3],@MSG[3]
++	sha1h	$E1,$ABCD
++	sha1c	$ABCD,$E,$W0		// 0
++	add.i32	$W0,@Kxx[$j],@MSG[2]
++	sha1su0	@MSG[0],@MSG[1],@MSG[2]
++___
++for ($j=0,$i=1;$i<20-3;$i++) {
++my $f=("c","p","m","p")[$i/5];
++$code.=<<___;
++	sha1h	$E0,$ABCD		// $i
++	sha1$f	$ABCD,$E1,$W1
++	add.i32	$W1,@Kxx[$j],@MSG[3]
++	sha1su1	@MSG[0],@MSG[3]
++___
++$code.=<<___ if ($i<20-4);
++	sha1su0	@MSG[1],@MSG[2],@MSG[3]
++___
++	($E0,$E1)=($E1,$E0);		($W0,$W1)=($W1,$W0);
++	push(@MSG,shift(@MSG));		$j++ if ((($i+3)%5)==0);
++}
++$code.=<<___;
++	sha1h	$E0,$ABCD		// $i
++	sha1p	$ABCD,$E1,$W1
++	add.i32	$W1,@Kxx[$j],@MSG[3]
++
++	sha1h	$E1,$ABCD		// 18
++	sha1p	$ABCD,$E0,$W0
++
++	sha1h	$E0,$ABCD		// 19
++	sha1p	$ABCD,$E1,$W1
++
++	add.i32	$E,$E,$E0
++	add.i32	$ABCD,$ABCD,$ABCD_SAVE
++
++	cbnz	$num,.Loop_hw
++
++	st1.32	{$ABCD},[$ctx],#16
++	st1.32	{$E}[0],[$ctx]
++
++	ldr	x29,[sp],#16
++	ret
++.size	sha1_block_armv8,.-sha1_block_armv8
++.align	6
++.Lconst:
++.long	0x5a827999,0x5a827999,0x5a827999,0x5a827999	//K_00_19
++.long	0x6ed9eba1,0x6ed9eba1,0x6ed9eba1,0x6ed9eba1	//K_20_39
++.long	0x8f1bbcdc,0x8f1bbcdc,0x8f1bbcdc,0x8f1bbcdc	//K_40_59
++.long	0xca62c1d6,0xca62c1d6,0xca62c1d6,0xca62c1d6	//K_60_79
++.LOPENSSL_armcap_P:
++#ifdef	__ILP32__
++.long	OPENSSL_armcap_P-.
++#else
++.quad	OPENSSL_armcap_P-.
++#endif
++.asciz	"SHA1 block transform for ARMv8, CRYPTOGAMS by "
++.align	2
++.comm	OPENSSL_armcap_P,4,4
++___
++}}}
++
++{   my	%opcode = (
++	"sha1c"		=> 0x5e000000,	"sha1p"		=> 0x5e001000,
++	"sha1m"		=> 0x5e002000,	"sha1su0"	=> 0x5e003000,
++	"sha1h"		=> 0x5e280800,	"sha1su1"	=> 0x5e281800	);
++
++    sub unsha1 {
++	my ($mnemonic,$arg)=@_;
++
++	$arg =~ m/[qv]([0-9]+)[^,]*,\s*[qv]([0-9]+)[^,]*(?:,\s*[qv]([0-9]+))?/o
++	&&
++	sprintf ".inst\t0x%08x\t//%s %s",
++			$opcode{$mnemonic}|$1|($2<<5)|($3<<16),
++			$mnemonic,$arg;
++    }
++}
++
++foreach(split("\n",$code)) {
++
++	s/\`([^\`]*)\`/eval($1)/geo;
++
++	s/\b(sha1\w+)\s+([qv].*)/unsha1($1,$2)/geo;
++
++	s/\.\w?32\b//o		and s/\.16b/\.4s/go;
++	m/(ld|st)1[^\[]+\[0\]/o	and s/\.4s/\.s/go;
++
++	print $_,"\n";
++}
++
++close STDOUT;
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/sha/asm/sha1-c64xplus.pl b/CryptoPkg/Library/OpensslLib/openssl/crypto/sha/asm/sha1-c64xplus.pl
+new file mode 100644
+index 0000000..4db2bcb
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/sha/asm/sha1-c64xplus.pl
+@@ -0,0 +1,337 @@
++#! /usr/bin/env perl
++# Copyright 2012-2016 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
++# in the file LICENSE in the source distribution or at
++# https://www.openssl.org/source/license.html
++
++#
++# ====================================================================
++# Written by Andy Polyakov  for the OpenSSL
++# project. The module is, however, dual licensed under OpenSSL and
++# CRYPTOGAMS licenses depending on where you obtain it. For further
++# details see http://www.openssl.org/~appro/cryptogams/.
++# ====================================================================
++#
++# SHA1 for C64x+.
++#
++# November 2011
++#
++# If compared to compiler-generated code with similar characteristics,
++# i.e. compiled with OPENSSL_SMALL_FOOTPRINT and utilizing SPLOOPs,
++# this implementation is 25% smaller and >2x faster. In absolute terms
++# performance is (quite impressive) ~6.5 cycles per processed byte.
++# Fully unrolled assembler would be ~5x larger and is likely to be
++# ~15% faster. It would be free from references to intermediate ring
++# buffer, but put more pressure on L1P [both because the code would be
++# larger and won't be using SPLOOP buffer]. There are no plans to
++# realize fully unrolled variant though...
++#
++# !!! Note that this module uses AMR, which means that all interrupt
++# service routines are expected to preserve it and for own well-being
++# zero it upon entry.
++
++while (($output=shift) && ($output!~/\w[\w\-]*\.\w+$/)) {}
++open STDOUT,">$output";
++
++($CTX,$INP,$NUM) = ("A4","B4","A6");		# arguments
++
++($A,$B,$C,$D,$E, $Arot,$F,$F0,$T,$K) = map("A$_",(16..20, 21..25));
++($X0,$X2,$X8,$X13) = ("A26","B26","A27","B27");
++($TX0,$TX1,$TX2,$TX3) = map("B$_",(28..31));
++($XPA,$XPB) = ("A5","B5");			# X circular buffer
++($Actx,$Bctx,$Cctx,$Dctx,$Ectx) = map("A$_",(3,6..9));	# zaps $NUM
++
++$code=<<___;
++	.text
++
++	.if	.ASSEMBLER_VERSION<7000000
++	.asg	0,__TI_EABI__
++	.endif
++	.if	__TI_EABI__
++	.asg	sha1_block_data_order,_sha1_block_data_order
++	.endif
++
++	.asg	B3,RA
++	.asg	A15,FP
++	.asg	B15,SP
++
++	.if	.BIG_ENDIAN
++	.asg	MV,SWAP2
++	.asg	MV,SWAP4
++	.endif
++
++	.global	_sha1_block_data_order
++_sha1_block_data_order:
++	.asmfunc stack_usage(64)
++	MV	$NUM,A0			; reassign $NUM
++||	MVK	-64,B0
++  [!A0]	BNOP	RA			; if ($NUM==0) return;
++|| [A0]	STW	FP,*SP--[16]		; save frame pointer and alloca(64)
++|| [A0]	MV	SP,FP
++   [A0]	LDW	*${CTX}[0],$A		; load A-E...
++|| [A0]	AND	B0,SP,SP		; align stack at 64 bytes
++   [A0]	LDW	*${CTX}[1],$B
++|| [A0]	SUBAW	SP,2,SP			; reserve two words above buffer
++   [A0]	LDW	*${CTX}[2],$C
++|| [A0]	MVK	0x00404,B0
++   [A0]	LDW	*${CTX}[3],$D
++|| [A0]	MVKH	0x50000,B0		; 0x050404, 64 bytes for $XP[AB]
++   [A0]	LDW	*${CTX}[4],$E
++|| [A0]	MVC	B0,AMR			; setup circular addressing
++	LDNW	*${INP}++,$TX1		; pre-fetch input
++	NOP	1
++
++loop?:
++	MVK	0x00007999,$K
++||	ADDAW	SP,2,$XPA
++||	SUB	A0,1,A0
++||	MVK	13,B0
++	MVKH	0x5a820000,$K		; K_00_19
++||	ADDAW	SP,2,$XPB
++||	MV	$A,$Actx
++||	MV	$B,$Bctx
++;;==================================================
++	SPLOOPD	5			; BODY_00_13
++||	MV	$C,$Cctx
++||	MV	$D,$Dctx
++||	MV	$E,$Ectx
++||	MVC	B0,ILC
++
++	ROTL	$A,5,$Arot
++||	AND	$C,$B,$F
++||	ANDN	$D,$B,$F0
++||	ADD	$K,$E,$T		; T=E+K
++
++	XOR	$F0,$F,$F		; F_00_19(B,C,D)
++||	MV	$D,$E			; E=D
++||	MV	$C,$D			; D=C
++||	SWAP2	$TX1,$TX2
++||	LDNW	*${INP}++,$TX1
++
++	ADD	$F,$T,$T		; T+=F_00_19(B,C,D)
++||	ROTL	$B,30,$C		; C=ROL(B,30)
++||	SWAP4	$TX2,$TX3		; byte swap
++
++	ADD	$Arot,$T,$T		; T+=ROL(A,5)
++||	MV	$A,$B			; B=A
++
++	ADD	$TX3,$T,$A		; A=T+Xi
++||	STW	$TX3,*${XPB}++
++	SPKERNEL
++;;==================================================
++	ROTL	$A,5,$Arot		; BODY_14
++||	AND	$C,$B,$F
++||	ANDN	$D,$B,$F0
++||	ADD	$K,$E,$T		; T=E+K
++
++	XOR	$F0,$F,$F		; F_00_19(B,C,D)
++||	MV	$D,$E			; E=D
++||	MV	$C,$D			; D=C
++||	SWAP2	$TX1,$TX2
++||	LDNW	*${INP}++,$TX1
++
++	ADD	$F,$T,$T		; T+=F_00_19(B,C,D)
++||	ROTL	$B,30,$C		; C=ROL(B,30)
++||	SWAP4	$TX2,$TX2		; byte swap
++||	LDW	*${XPA}++,$X0		; fetches from X ring buffer are
++||	LDW	*${XPB}[4],$X2		; 2 iterations ahead
++
++	ADD	$Arot,$T,$T		; T+=ROL(A,5)
++||	MV	$A,$B			; B=A
++||	LDW	*${XPA}[7],$X8
++||	MV	$TX3,$X13		; ||	LDW	*${XPB}[15],$X13
++||	MV	$TX2,$TX3
++
++	ADD	$TX2,$T,$A		; A=T+Xi
++||	STW	$TX2,*${XPB}++
++;;==================================================
++	ROTL	$A,5,$Arot		; BODY_15
++||	AND	$C,$B,$F
++||	ANDN	$D,$B,$F0
++||	ADD	$K,$E,$T		; T=E+K
++
++	XOR	$F0,$F,$F		; F_00_19(B,C,D)
++||	MV	$D,$E			; E=D
++||	MV	$C,$D			; D=C
++||	SWAP2	$TX1,$TX2
++
++	ADD	$F,$T,$T		; T+=F_00_19(B,C,D)
++||	ROTL	$B,30,$C		; C=ROL(B,30)
++||	SWAP4	$TX2,$TX2		; byte swap
++||	XOR	$X0,$X2,$TX0		; Xupdate XORs are 1 iteration ahead
++||	LDW	*${XPA}++,$X0
++||	LDW	*${XPB}[4],$X2
++
++	ADD	$Arot,$T,$T		; T+=ROL(A,5)
++||	MV	$A,$B			; B=A
++||	XOR	$X8,$X13,$TX1
++||	LDW	*${XPA}[7],$X8
++||	MV	$TX3,$X13		; ||	LDW	*${XPB}[15],$X13
++||	MV	$TX2,$TX3
++
++	ADD	$TX2,$T,$A		; A=T+Xi
++||	STW	$TX2,*${XPB}++
++||	XOR	$TX0,$TX1,$TX1
++||	MVK	3,B0
++;;==================================================
++	SPLOOPD	5			; BODY_16_19
++||	MVC	B0,ILC
++
++	ROTL	$A,5,$Arot
++||	AND	$C,$B,$F
++||	ANDN	$D,$B,$F0
++||	ADD	$K,$E,$T		; T=E+K
++||	ROTL	$TX1,1,$TX2		; Xupdate output
++
++	XOR	$F0,$F,$F		; F_00_19(B,C,D)
++||	MV	$D,$E			; E=D
++||	MV	$C,$D			; D=C
++
++	ADD	$F,$T,$T		; T+=F_00_19(B,C,D)
++||	ROTL	$B,30,$C		; C=ROL(B,30)
++||	XOR	$X0,$X2,$TX0
++||	LDW	*${XPA}++,$X0
++||	LDW	*${XPB}[4],$X2
++
++	ADD	$Arot,$T,$T		; T+=ROL(A,5)
++||	MV	$A,$B			; B=A
++||	XOR	$X8,$X13,$TX1
++||	LDW	*${XPA}[7],$X8
++||	MV	$TX3,$X13		; ||	LDW	*${XPB}[15],$X13
++||	MV	$TX2,$TX3
++
++	ADD	$TX2,$T,$A		; A=T+Xi
++||	STW	$TX2,*${XPB}++
++||	XOR	$TX0,$TX1,$TX1
++	SPKERNEL
++
++	MVK	0xffffeba1,$K
++||	MVK	19,B0
++	MVKH	0x6ed90000,$K		; K_20_39
++___
++sub BODY_20_39 {
++$code.=<<___;
++;;==================================================
++	SPLOOPD	5			; BODY_20_39
++||	MVC	B0,ILC
++
++	ROTL	$A,5,$Arot
++||	XOR	$B,$C,$F
++||	ADD	$K,$E,$T		; T=E+K
++||	ROTL	$TX1,1,$TX2		; Xupdate output
++
++	XOR	$D,$F,$F		; F_20_39(B,C,D)
++||	MV	$D,$E			; E=D
++||	MV	$C,$D			; D=C
++
++	ADD	$F,$T,$T		; T+=F_20_39(B,C,D)
++||	ROTL	$B,30,$C		; C=ROL(B,30)
++||	XOR	$X0,$X2,$TX0
++||	LDW	*${XPA}++,$X0
++||	LDW	*${XPB}[4],$X2
++
++	ADD	$Arot,$T,$T		; T+=ROL(A,5)
++||	MV	$A,$B			; B=A
++||	XOR	$X8,$X13,$TX1
++||	LDW	*${XPA}[7],$X8
++||	MV	$TX3,$X13		; ||	LDW	*${XPB}[15],$X13
++||	MV	$TX2,$TX3
++
++	ADD	$TX2,$T,$A		; A=T+Xi
++||	STW	$TX2,*${XPB}++		; last one is redundant
++||	XOR	$TX0,$TX1,$TX1
++	SPKERNEL
++___
++$code.=<<___ if (!shift);
++	MVK	0xffffbcdc,$K
++	MVKH	0x8f1b0000,$K		; K_40_59
++___
++}	&BODY_20_39();
++$code.=<<___;
++;;==================================================
++	SPLOOPD	5			; BODY_40_59
++||	MVC	B0,ILC
++||	AND	$B,$C,$F
++||	AND	$B,$D,$F0
++
++	ROTL	$A,5,$Arot
++||	XOR	$F0,$F,$F
++||	AND	$C,$D,$F0
++||	ADD	$K,$E,$T		; T=E+K
++||	ROTL	$TX1,1,$TX2		; Xupdate output
++
++	XOR	$F0,$F,$F		; F_40_59(B,C,D)
++||	MV	$D,$E			; E=D
++||	MV	$C,$D			; D=C
++
++	ADD	$F,$T,$T		; T+=F_40_59(B,C,D)
++||	ROTL	$B,30,$C		; C=ROL(B,30)
++||	XOR	$X0,$X2,$TX0
++||	LDW	*${XPA}++,$X0
++||	LDW	*${XPB}[4],$X2
++
++	ADD	$Arot,$T,$T		; T+=ROL(A,5)
++||	MV	$A,$B			; B=A
++||	XOR	$X8,$X13,$TX1
++||	LDW	*${XPA}[7],$X8
++||	MV	$TX3,$X13		; ||	LDW	*${XPB}[15],$X13
++||	MV	$TX2,$TX3
++
++	ADD	$TX2,$T,$A		; A=T+Xi
++||	STW	$TX2,*${XPB}++
++||	XOR	$TX0,$TX1,$TX1
++||	AND	$B,$C,$F
++||	AND	$B,$D,$F0
++	SPKERNEL
++
++	MVK	0xffffc1d6,$K
++||	MVK	18,B0
++	MVKH	0xca620000,$K		; K_60_79
++___
++	&BODY_20_39(-1);		# BODY_60_78
++$code.=<<___;
++;;==================================================
++   [A0]	B	loop?
++||	ROTL	$A,5,$Arot		; BODY_79
++||	XOR	$B,$C,$F
++||	ROTL	$TX1,1,$TX2		; Xupdate output
++
++   [A0]	LDNW	*${INP}++,$TX1		; pre-fetch input
++||	ADD	$K,$E,$T		; T=E+K
++||	XOR	$D,$F,$F		; F_20_39(B,C,D)
++
++	ADD	$F,$T,$T		; T+=F_20_39(B,C,D)
++||	ADD	$Ectx,$D,$E		; E=D,E+=Ectx
++||	ADD	$Dctx,$C,$D		; D=C,D+=Dctx
++||	ROTL	$B,30,$C		; C=ROL(B,30)
++
++	ADD	$Arot,$T,$T		; T+=ROL(A,5)
++||	ADD	$Bctx,$A,$B		; B=A,B+=Bctx
++
++	ADD	$TX2,$T,$A		; A=T+Xi
++
++	ADD	$Actx,$A,$A		; A+=Actx
++||	ADD	$Cctx,$C,$C		; C+=Cctx
++;; end of loop?
++
++	BNOP	RA			; return
++||	MV	FP,SP			; restore stack pointer
++||	LDW	*FP[0],FP		; restore frame pointer
++	STW	$A,*${CTX}[0]		; emit A-E...
++||	MVK	0,B0
++	STW	$B,*${CTX}[1]
++||	MVC	B0,AMR			; clear AMR
++	STW	$C,*${CTX}[2]
++	STW	$D,*${CTX}[3]
++	STW	$E,*${CTX}[4]
++	.endasmfunc
++
++	.sect	.const
++	.cstring "SHA1 block transform for C64x+, CRYPTOGAMS by "
++	.align	4
++___
++
++print $code;
++close STDOUT;
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/sha/asm/sha1-ia64.pl b/CryptoPkg/Library/OpensslLib/openssl/crypto/sha/asm/sha1-ia64.pl
+new file mode 100644
+index 0000000..dec21f9
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/sha/asm/sha1-ia64.pl
+@@ -0,0 +1,314 @@
++#! /usr/bin/env perl
++# Copyright 2004-2016 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
++# in the file LICENSE in the source distribution or at
++# https://www.openssl.org/source/license.html
++
++#
++# ====================================================================
++# Written by Andy Polyakov  for the OpenSSL
++# project. The module is, however, dual licensed under OpenSSL and
++# CRYPTOGAMS licenses depending on where you obtain it. For further
++# details see http://www.openssl.org/~appro/cryptogams/.
++# ====================================================================
++#
++# Eternal question is what's wrong with compiler generated code? The
++# trick is that it's possible to reduce the number of shifts required
++# to perform rotations by maintaining copy of 32-bit value in upper
++# bits of 64-bit register. Just follow mux2 and shrp instructions...
++# Performance under big-endian OS such as HP-UX is 179MBps*1GHz, which
++# is >50% better than HP C and >2x better than gcc.
++
++$output = pop;
++
++$code=<<___;
++.ident  \"sha1-ia64.s, version 1.3\"
++.ident  \"IA-64 ISA artwork by Andy Polyakov \"
++.explicit
++
++___
++
++
++if ($^O eq "hpux") {
++    $ADDP="addp4";
++    for (@ARGV) { $ADDP="add" if (/[\+DD|\-mlp]64/); }
++} else { $ADDP="add"; }
++
++#$human=1;
++if ($human) {	# useful for visual code auditing...
++	($A,$B,$C,$D,$E)   = ("A","B","C","D","E");
++	($h0,$h1,$h2,$h3,$h4) = ("h0","h1","h2","h3","h4");
++	($K_00_19, $K_20_39, $K_40_59, $K_60_79) =
++	    (	"K_00_19","K_20_39","K_40_59","K_60_79"	);
++	@X= (	"X0", "X1", "X2", "X3", "X4", "X5", "X6", "X7",
++		"X8", "X9","X10","X11","X12","X13","X14","X15"	);
++}
++else {
++	($A,$B,$C,$D,$E)   =    ("loc0","loc1","loc2","loc3","loc4");
++	($h0,$h1,$h2,$h3,$h4) = ("loc5","loc6","loc7","loc8","loc9");
++	($K_00_19, $K_20_39, $K_40_59, $K_60_79) =
++	    (	"r14", "r15", "loc10", "loc11"	);
++	@X= (	"r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23",
++		"r24", "r25", "r26", "r27", "r28", "r29", "r30", "r31"	);
++}
++
++sub BODY_00_15 {
++local	*code=shift;
++my	($i,$a,$b,$c,$d,$e)=@_;
++my	$j=$i+1;
++my	$Xn=@X[$j%16];
++
++$code.=<<___ if ($i==0);
++{ .mmi;	ld1	$X[$i]=[inp],2		    // MSB
++	ld1	tmp2=[tmp3],2		};;
++{ .mmi;	ld1	tmp0=[inp],2
++	ld1	tmp4=[tmp3],2		    // LSB
++	dep	$X[$i]=$X[$i],tmp2,8,8	};;
++___
++if ($i<15) {
++	$code.=<<___;
++{ .mmi;	ld1	$Xn=[inp],2		    // forward Xload
++	nop.m	0x0
++	dep	tmp1=tmp0,tmp4,8,8	};;
++{ .mmi;	ld1	tmp2=[tmp3],2		    // forward Xload
++	and	tmp4=$c,$b
++	dep	$X[$i]=$X[$i],tmp1,16,16} //;;
++{ .mmi;	add	$e=$e,$K_00_19		    // e+=K_00_19
++	andcm	tmp1=$d,$b
++	dep.z	tmp5=$a,5,27		};; // a<<5
++{ .mmi;	add	$e=$e,$X[$i]		    // e+=Xload
++	or	tmp4=tmp4,tmp1		    // F_00_19(b,c,d)=(b&c)|(~b&d)
++	extr.u	tmp1=$a,27,5		};; // a>>27
++{ .mmi;	ld1	tmp0=[inp],2		    // forward Xload
++	add	$e=$e,tmp4		    // e+=F_00_19(b,c,d)
++	shrp	$b=tmp6,tmp6,2		}   // b=ROTATE(b,30)
++{ .mmi;	ld1	tmp4=[tmp3],2		    // forward Xload
++	or	tmp5=tmp1,tmp5		    // ROTATE(a,5)
++	mux2	tmp6=$a,0x44		};; // see b in next iteration
++{ .mii;	add	$e=$e,tmp5		    // e+=ROTATE(a,5)
++	dep	$Xn=$Xn,tmp2,8,8	    // forward Xload
++	mux2	$X[$i]=$X[$i],0x44	} //;;
++
++___
++	}
++else	{
++	$code.=<<___;
++{ .mii;	and	tmp3=$c,$b
++	dep	tmp1=tmp0,tmp4,8,8;;
++	dep	$X[$i]=$X[$i],tmp1,16,16} //;;
++{ .mmi;	add	$e=$e,$K_00_19		    // e+=K_00_19
++	andcm	tmp1=$d,$b
++	dep.z	tmp5=$a,5,27		};; // a<<5
++{ .mmi;	add	$e=$e,$X[$i]		    // e+=Xupdate
++	or	tmp4=tmp3,tmp1		    // F_00_19(b,c,d)=(b&c)|(~b&d)
++	extr.u	tmp1=$a,27,5		}   // a>>27
++{ .mmi;	xor	$Xn=$Xn,$X[($j+2)%16]	    // forward Xupdate
++	xor	tmp3=$X[($j+8)%16],$X[($j+13)%16] // forward Xupdate
++	nop.i	0			};;
++{ .mmi;	add	$e=$e,tmp4		    // e+=F_00_19(b,c,d)
++	xor	$Xn=$Xn,tmp3		    // forward Xupdate
++	shrp	$b=tmp6,tmp6,2		}   // b=ROTATE(b,30)
++{ .mmi; or	tmp1=tmp1,tmp5		    // ROTATE(a,5)
++	mux2	tmp6=$a,0x44		};; // see b in next iteration
++{ .mii;	add	$e=$e,tmp1		    // e+=ROTATE(a,5)
++	shrp	$Xn=$Xn,$Xn,31		    // ROTATE(x[0]^x[2]^x[8]^x[13],1)
++	mux2	$X[$i]=$X[$i],0x44	};;
++
++___
++	}
++}
++
++sub BODY_16_19 {
++local	*code=shift;
++my	($i,$a,$b,$c,$d,$e)=@_;
++my	$j=$i+1;
++my	$Xn=@X[$j%16];
++
++$code.=<<___;
++{ .mib;	add	$e=$e,$K_00_19		    // e+=K_00_19
++	dep.z	tmp5=$a,5,27		}   // a<<5
++{ .mib;	andcm	tmp1=$d,$b
++	and	tmp0=$c,$b		};;
++{ .mmi;	add	$e=$e,$X[$i%16]		    // e+=Xupdate
++	or	tmp0=tmp0,tmp1		    // F_00_19(b,c,d)=(b&c)|(~b&d)
++	extr.u	tmp1=$a,27,5		}   // a>>27
++{ .mmi;	xor	$Xn=$Xn,$X[($j+2)%16]	    // forward Xupdate
++	xor	tmp3=$X[($j+8)%16],$X[($j+13)%16]	// forward Xupdate
++	nop.i	0			};;
++{ .mmi;	add	$e=$e,tmp0		    // f+=F_00_19(b,c,d)
++	xor	$Xn=$Xn,tmp3		    // forward Xupdate
++	shrp	$b=tmp6,tmp6,2		}   // b=ROTATE(b,30)
++{ .mmi;	or	tmp1=tmp1,tmp5		    // ROTATE(a,5)
++	mux2	tmp6=$a,0x44		};; // see b in next iteration
++{ .mii;	add	$e=$e,tmp1		    // e+=ROTATE(a,5)
++	shrp	$Xn=$Xn,$Xn,31		    // ROTATE(x[0]^x[2]^x[8]^x[13],1)
++	nop.i	0			};;
++
++___
++}
++
++sub BODY_20_39 {
++local	*code=shift;
++my	($i,$a,$b,$c,$d,$e,$Konst)=@_;
++	$Konst = $K_20_39 if (!defined($Konst));
++my	$j=$i+1;
++my	$Xn=@X[$j%16];
++
++if ($i<79) {
++$code.=<<___;
++{ .mib;	add	$e=$e,$Konst		    // e+=K_XX_XX
++	dep.z	tmp5=$a,5,27		}   // a<<5
++{ .mib;	xor	tmp0=$c,$b
++	xor	$Xn=$Xn,$X[($j+2)%16]	};; // forward Xupdate
++{ .mib;	add	$e=$e,$X[$i%16]		    // e+=Xupdate
++	extr.u	tmp1=$a,27,5		}   // a>>27
++{ .mib;	xor	tmp0=tmp0,$d		    // F_20_39(b,c,d)=b^c^d
++	xor	$Xn=$Xn,$X[($j+8)%16]	};; // forward Xupdate
++{ .mmi;	add	$e=$e,tmp0		    // e+=F_20_39(b,c,d)
++	xor	$Xn=$Xn,$X[($j+13)%16]	    // forward Xupdate
++	shrp	$b=tmp6,tmp6,2		}   // b=ROTATE(b,30)
++{ .mmi;	or	tmp1=tmp1,tmp5		    // ROTATE(a,5)
++	mux2	tmp6=$a,0x44		};; // see b in next iteration
++{ .mii;	add	$e=$e,tmp1		    // e+=ROTATE(a,5)
++	shrp	$Xn=$Xn,$Xn,31		    // ROTATE(x[0]^x[2]^x[8]^x[13],1)
++	nop.i	0			};;
++
++___
++}
++else {
++$code.=<<___;
++{ .mib;	add	$e=$e,$Konst		    // e+=K_60_79
++	dep.z	tmp5=$a,5,27		}   // a<<5
++{ .mib;	xor	tmp0=$c,$b
++	add	$h1=$h1,$a		};; // wrap up
++{ .mib;	add	$e=$e,$X[$i%16]		    // e+=Xupdate
++	extr.u	tmp1=$a,27,5		}   // a>>27
++{ .mib;	xor	tmp0=tmp0,$d		    // F_20_39(b,c,d)=b^c^d
++	add	$h3=$h3,$c		};; // wrap up
++{ .mmi;	add	$e=$e,tmp0		    // e+=F_20_39(b,c,d)
++	or	tmp1=tmp1,tmp5		    // ROTATE(a,5)
++	shrp	$b=tmp6,tmp6,2		};; // b=ROTATE(b,30) ;;?
++{ .mmi;	add	$e=$e,tmp1		    // e+=ROTATE(a,5)
++	add	tmp3=1,inp		    // used in unaligned codepath
++	add	$h4=$h4,$d		};; // wrap up
++
++___
++}
++}
++
++sub BODY_40_59 {
++local	*code=shift;
++my	($i,$a,$b,$c,$d,$e)=@_;
++my	$j=$i+1;
++my	$Xn=@X[$j%16];
++
++$code.=<<___;
++{ .mib;	add	$e=$e,$K_40_59		    // e+=K_40_59
++	dep.z	tmp5=$a,5,27		}   // a<<5
++{ .mib;	and	tmp1=$c,$d
++	xor	tmp0=$c,$d		};;
++{ .mmi;	add	$e=$e,$X[$i%16]		    // e+=Xupdate
++	add	tmp5=tmp5,tmp1		    // a<<5+(c&d)
++	extr.u	tmp1=$a,27,5		}   // a>>27
++{ .mmi;	and	tmp0=tmp0,$b
++	xor	$Xn=$Xn,$X[($j+2)%16]	    // forward Xupdate
++	xor	tmp3=$X[($j+8)%16],$X[($j+13)%16] };;	// forward Xupdate
++{ .mmi;	add	$e=$e,tmp0		    // e+=b&(c^d)
++	add	tmp5=tmp5,tmp1		    // ROTATE(a,5)+(c&d)
++	shrp	$b=tmp6,tmp6,2		}   // b=ROTATE(b,30)
++{ .mmi;	xor	$Xn=$Xn,tmp3
++	mux2	tmp6=$a,0x44		};; // see b in next iteration
++{ .mii;	add	$e=$e,tmp5		    // e+=ROTATE(a,5)+(c&d)
++	shrp	$Xn=$Xn,$Xn,31		    // ROTATE(x[0]^x[2]^x[8]^x[13],1)
++	nop.i	0x0			};;
++
++___
++}
++sub BODY_60_79	{ &BODY_20_39(@_,$K_60_79); }
++
++$code.=<<___;
++.text
++
++tmp0=r8;
++tmp1=r9;
++tmp2=r10;
++tmp3=r11;
++ctx=r32;	// in0
++inp=r33;	// in1
++
++// void sha1_block_data_order(SHA_CTX *c,const void *p,size_t num);
++.global	sha1_block_data_order#
++.proc	sha1_block_data_order#
++.align	32
++sha1_block_data_order:
++	.prologue
++{ .mmi;	alloc	tmp1=ar.pfs,3,14,0,0
++	$ADDP	tmp0=4,ctx
++	.save	ar.lc,r3
++	mov	r3=ar.lc		}
++{ .mmi;	$ADDP	ctx=0,ctx
++	$ADDP	inp=0,inp
++	mov	r2=pr			};;
++tmp4=in2;
++tmp5=loc12;
++tmp6=loc13;
++	.body
++{ .mlx;	ld4	$h0=[ctx],8
++	movl	$K_00_19=0x5a827999	}
++{ .mlx;	ld4	$h1=[tmp0],8
++	movl	$K_20_39=0x6ed9eba1	};;
++{ .mlx;	ld4	$h2=[ctx],8
++	movl	$K_40_59=0x8f1bbcdc	}
++{ .mlx;	ld4	$h3=[tmp0]
++	movl	$K_60_79=0xca62c1d6	};;
++{ .mmi;	ld4	$h4=[ctx],-16
++	add	in2=-1,in2		    // adjust num for ar.lc
++	mov	ar.ec=1			};;
++{ .mmi;	nop.m	0
++	add	tmp3=1,inp
++	mov	ar.lc=in2		};; // brp.loop.imp: too far
++
++.Ldtop:
++{ .mmi;	mov	$A=$h0
++	mov	$B=$h1
++	mux2	tmp6=$h1,0x44		}
++{ .mmi;	mov	$C=$h2
++	mov	$D=$h3
++	mov	$E=$h4			};;
++
++___
++
++{ my $i;
++  my @V=($A,$B,$C,$D,$E);
++
++	for($i=0;$i<16;$i++)	{ &BODY_00_15(\$code,$i,@V); unshift(@V,pop(@V)); }
++	for(;$i<20;$i++)	{ &BODY_16_19(\$code,$i,@V); unshift(@V,pop(@V)); }
++	for(;$i<40;$i++)	{ &BODY_20_39(\$code,$i,@V); unshift(@V,pop(@V)); }
++	for(;$i<60;$i++)	{ &BODY_40_59(\$code,$i,@V); unshift(@V,pop(@V)); }
++	for(;$i<80;$i++)	{ &BODY_60_79(\$code,$i,@V); unshift(@V,pop(@V)); }
++
++	(($V[0] eq $A) and ($V[4] eq $E)) or die;	# double-check
++}
++
++$code.=<<___;
++{ .mmb;	add	$h0=$h0,$A
++	add	$h2=$h2,$C
++	br.ctop.dptk.many	.Ldtop	};;
++.Ldend:
++{ .mmi;	add	tmp0=4,ctx
++	mov	ar.lc=r3		};;
++{ .mmi;	st4	[ctx]=$h0,8
++	st4	[tmp0]=$h1,8		};;
++{ .mmi;	st4	[ctx]=$h2,8
++	st4	[tmp0]=$h3		};;
++{ .mib;	st4	[ctx]=$h4,-16
++	mov	pr=r2,0x1ffff
++	br.ret.sptk.many	b0	};;
++.endp	sha1_block_data_order#
++stringz	"SHA1 block transform for IA64, CRYPTOGAMS by "
++___
++
++open STDOUT,">$output" if $output;
++print $code;
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/sha/asm/sha1-mb-x86_64.pl b/CryptoPkg/Library/OpensslLib/openssl/crypto/sha/asm/sha1-mb-x86_64.pl
+new file mode 100644
+index 0000000..51c73c0
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/sha/asm/sha1-mb-x86_64.pl
+@@ -0,0 +1,1582 @@
++#! /usr/bin/env perl
++# Copyright 2013-2016 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
++# in the file LICENSE in the source distribution or at
++# https://www.openssl.org/source/license.html
++
++
++# ====================================================================
++# Written by Andy Polyakov  for the OpenSSL
++# project. The module is, however, dual licensed under OpenSSL and
++# CRYPTOGAMS licenses depending on where you obtain it. For further
++# details see http://www.openssl.org/~appro/cryptogams/.
++# ====================================================================
++
++# Multi-buffer SHA1 procedure processes n buffers in parallel by
++# placing buffer data to designated lane of SIMD register. n is
++# naturally limited to 4 on pre-AVX2 processors and to 8 on
++# AVX2-capable processors such as Haswell.
++#
++#		this	+aesni(i)	sha1	aesni-sha1	gain(iv)
++# -------------------------------------------------------------------
++# Westmere(ii)	10.7/n	+1.28=3.96(n=4)	5.30	6.66		+68%
++# Atom(ii)	18.1/n	+3.93=8.46(n=4)	9.37	12.8		+51%
++# Sandy Bridge	(8.16	+5.15=13.3)/n	4.99	5.98		+80%
++# Ivy Bridge	(8.08	+5.14=13.2)/n	4.60	5.54		+68%
++# Haswell(iii)	(8.96	+5.00=14.0)/n	3.57	4.55		+160%
++# Skylake	(8.70	+5.00=13.7)/n	3.64	4.20		+145%
++# Bulldozer	(9.76	+5.76=15.5)/n	5.95	6.37		+64%
++#
++# (i)	multi-block CBC encrypt with 128-bit key;
++# (ii)	(HASH+AES)/n does not apply to Westmere for n>3 and Atom,
++#	because of lower AES-NI instruction throughput;
++# (iii)	"this" is for n=8, when we gather twice as much data, result
++#	for n=4 is 8.00+4.44=12.4;
++# (iv)	presented improvement coefficients are asymptotic limits and
++#	in real-life application are somewhat lower, e.g. for 2KB
++#	fragments they range from 30% to 100% (on Haswell);
++
++$flavour = shift;
++$output  = shift;
++if ($flavour =~ /\./) { $output = $flavour; undef $flavour; }
++
++$win64=0; $win64=1 if ($flavour =~ /[nm]asm|mingw64/ || $output =~ /\.asm$/);
++
++$0 =~ m/(.*[\/\\])[^\/\\]+$/; $dir=$1;
++( $xlate="${dir}x86_64-xlate.pl" and -f $xlate ) or
++( $xlate="${dir}../../perlasm/x86_64-xlate.pl" and -f $xlate) or
++die "can't locate x86_64-xlate.pl";
++
++$avx=0;
++
++if (`$ENV{CC} -Wa,-v -c -o /dev/null -x assembler /dev/null 2>&1`
++		=~ /GNU assembler version ([2-9]\.[0-9]+)/) {
++	$avx = ($1>=2.19) + ($1>=2.22);
++}
++
++if (!$avx && $win64 && ($flavour =~ /nasm/ || $ENV{ASM} =~ /nasm/) &&
++	   `nasm -v 2>&1` =~ /NASM version ([2-9]\.[0-9]+)/) {
++	$avx = ($1>=2.09) + ($1>=2.10);
++}
++
++if (!$avx && $win64 && ($flavour =~ /masm/ || $ENV{ASM} =~ /ml64/) &&
++	   `ml64 2>&1` =~ /Version ([0-9]+)\./) {
++	$avx = ($1>=10) + ($1>=11);
++}
++
++if (!$avx && `$ENV{CC} -v 2>&1` =~ /((?:^clang|LLVM) version|.*based on LLVM) ([3-9]\.[0-9]+)/) {
++	$avx = ($2>=3.0) + ($2>3.0);
++}
++
++open OUT,"| \"$^X\" \"$xlate\" $flavour \"$output\"";
++*STDOUT=*OUT;
++
++# void sha1_multi_block (
++#     struct {	unsigned int A[8];
++#		unsigned int B[8];
++#		unsigned int C[8];
++#		unsigned int D[8];
++#		unsigned int E[8];	} *ctx,
++#     struct {	void *ptr; int blocks;	} inp[8],
++#     int num);		/* 1 or 2 */
++#
++$ctx="%rdi";	# 1st arg
++$inp="%rsi";	# 2nd arg
++$num="%edx";
++@ptr=map("%r$_",(8..11));
++$Tbl="%rbp";
++
++@V=($A,$B,$C,$D,$E)=map("%xmm$_",(0..4));
++($t0,$t1,$t2,$t3,$tx)=map("%xmm$_",(5..9));
++@Xi=map("%xmm$_",(10..14));
++$K="%xmm15";
++
++if (1) {
++    # Atom-specific optimization aiming to eliminate pshufb with high
++    # registers [and thus get rid of 48 cycles accumulated penalty] 
++    @Xi=map("%xmm$_",(0..4));
++    ($tx,$t0,$t1,$t2,$t3)=map("%xmm$_",(5..9));
++    @V=($A,$B,$C,$D,$E)=map("%xmm$_",(10..14));
++}
++
++$REG_SZ=16;
++
++sub Xi_off {
++my $off = shift;
++
++    $off %= 16; $off *= $REG_SZ;
++    $off<256 ? "$off-128(%rax)" : "$off-256-128(%rbx)";
++}
++
++sub BODY_00_19 {
++my ($i,$a,$b,$c,$d,$e)=@_;
++my $j=$i+1;
++my $k=$i+2;
++
++# Loads are performed 2+3/4 iterations in advance. 3/4 means that out
++# of 4 words you would expect to be loaded per given iteration one is
++# spilled to next iteration. In other words indices in four input
++# streams are distributed as following:
++#
++# $i==0:	0,0,0,0,1,1,1,1,2,2,2,
++# $i==1:	2,3,3,3,
++# $i==2:	3,4,4,4,
++# ...
++# $i==13:	14,15,15,15,
++# $i==14:	15
++# 
++# Then at $i==15 Xupdate is applied one iteration in advance...
++$code.=<<___ if ($i==0);
++	movd		(@ptr[0]),@Xi[0]
++	 lea		`16*4`(@ptr[0]),@ptr[0]
++	movd		(@ptr[1]),@Xi[2]	# borrow @Xi[2]
++	 lea		`16*4`(@ptr[1]),@ptr[1]
++	movd		(@ptr[2]),@Xi[3]	# borrow @Xi[3]
++	 lea		`16*4`(@ptr[2]),@ptr[2]
++	movd		(@ptr[3]),@Xi[4]	# borrow @Xi[4]
++	 lea		`16*4`(@ptr[3]),@ptr[3]
++	punpckldq	@Xi[3],@Xi[0]
++	 movd		`4*$j-16*4`(@ptr[0]),@Xi[1]
++	punpckldq	@Xi[4],@Xi[2]
++	 movd		`4*$j-16*4`(@ptr[1]),$t3
++	punpckldq	@Xi[2],@Xi[0]
++	 movd		`4*$j-16*4`(@ptr[2]),$t2
++	pshufb		$tx,@Xi[0]
++___
++$code.=<<___ if ($i<14);			# just load input
++	 movd		`4*$j-16*4`(@ptr[3]),$t1
++	 punpckldq	$t2,@Xi[1]
++	movdqa	$a,$t2
++	paddd	$K,$e				# e+=K_00_19
++	 punpckldq	$t1,$t3
++	movdqa	$b,$t1
++	movdqa	$b,$t0
++	pslld	\$5,$t2
++	pandn	$d,$t1
++	pand	$c,$t0
++	 punpckldq	$t3,@Xi[1]
++	movdqa	$a,$t3
++
++	movdqa	@Xi[0],`&Xi_off($i)`
++	paddd	@Xi[0],$e			# e+=X[i]
++	 movd		`4*$k-16*4`(@ptr[0]),@Xi[2]
++	psrld	\$27,$t3
++	pxor	$t1,$t0				# Ch(b,c,d)
++	movdqa	$b,$t1
++
++	por	$t3,$t2				# rol(a,5)
++	 movd		`4*$k-16*4`(@ptr[1]),$t3
++	pslld	\$30,$t1
++	paddd	$t0,$e				# e+=Ch(b,c,d)
++
++	psrld	\$2,$b
++	paddd	$t2,$e				# e+=rol(a,5)
++	 pshufb	$tx,@Xi[1]
++	 movd		`4*$k-16*4`(@ptr[2]),$t2
++	por	$t1,$b				# b=rol(b,30)
++___
++$code.=<<___ if ($i==14);			# just load input
++	 movd		`4*$j-16*4`(@ptr[3]),$t1
++	 punpckldq	$t2,@Xi[1]
++	movdqa	$a,$t2
++	paddd	$K,$e				# e+=K_00_19
++	 punpckldq	$t1,$t3
++	movdqa	$b,$t1
++	movdqa	$b,$t0
++	pslld	\$5,$t2
++	 prefetcht0	63(@ptr[0])
++	pandn	$d,$t1
++	pand	$c,$t0
++	 punpckldq	$t3,@Xi[1]
++	movdqa	$a,$t3
++
++	movdqa	@Xi[0],`&Xi_off($i)`
++	paddd	@Xi[0],$e			# e+=X[i]
++	psrld	\$27,$t3
++	pxor	$t1,$t0				# Ch(b,c,d)
++	movdqa	$b,$t1
++	 prefetcht0	63(@ptr[1])
++
++	por	$t3,$t2				# rol(a,5)
++	pslld	\$30,$t1
++	paddd	$t0,$e				# e+=Ch(b,c,d)
++	 prefetcht0	63(@ptr[2])
++
++	psrld	\$2,$b
++	paddd	$t2,$e				# e+=rol(a,5)
++	 pshufb	$tx,@Xi[1]
++	 prefetcht0	63(@ptr[3])
++	por	$t1,$b				# b=rol(b,30)
++___
++$code.=<<___ if ($i>=13 && $i<15);
++	movdqa	`&Xi_off($j+2)`,@Xi[3]		# preload "X[2]"
++___
++$code.=<<___ if ($i>=15);			# apply Xupdate
++	pxor	@Xi[-2],@Xi[1]			# "X[13]"
++	movdqa	`&Xi_off($j+2)`,@Xi[3]		# "X[2]"
++
++	movdqa	$a,$t2
++	 pxor	`&Xi_off($j+8)`,@Xi[1]
++	paddd	$K,$e				# e+=K_00_19
++	movdqa	$b,$t1
++	pslld	\$5,$t2
++	 pxor	@Xi[3],@Xi[1]
++	movdqa	$b,$t0
++	pandn	$d,$t1
++	 movdqa	@Xi[1],$tx
++	pand	$c,$t0
++	movdqa	$a,$t3
++	 psrld	\$31,$tx
++	 paddd	@Xi[1],@Xi[1]
++
++	movdqa	@Xi[0],`&Xi_off($i)`
++	paddd	@Xi[0],$e			# e+=X[i]
++	psrld	\$27,$t3
++	pxor	$t1,$t0				# Ch(b,c,d)
++
++	movdqa	$b,$t1
++	por	$t3,$t2				# rol(a,5)
++	pslld	\$30,$t1
++	paddd	$t0,$e				# e+=Ch(b,c,d)
++
++	psrld	\$2,$b
++	paddd	$t2,$e				# e+=rol(a,5)
++	 por	$tx,@Xi[1]			# rol	\$1,@Xi[1]
++	por	$t1,$b				# b=rol(b,30)
++___
++push(@Xi,shift(@Xi));
++}
++
++sub BODY_20_39 {
++my ($i,$a,$b,$c,$d,$e)=@_;
++my $j=$i+1;
++
++$code.=<<___ if ($i<79);
++	pxor	@Xi[-2],@Xi[1]			# "X[13]"
++	movdqa	`&Xi_off($j+2)`,@Xi[3]		# "X[2]"
++
++	movdqa	$a,$t2
++	movdqa	$d,$t0
++	 pxor	`&Xi_off($j+8)`,@Xi[1]
++	paddd	$K,$e				# e+=K_20_39
++	pslld	\$5,$t2
++	pxor	$b,$t0
++
++	movdqa	$a,$t3
++___
++$code.=<<___ if ($i<72);
++	movdqa	@Xi[0],`&Xi_off($i)`
++___
++$code.=<<___ if ($i<79);
++	paddd	@Xi[0],$e			# e+=X[i]
++	 pxor	@Xi[3],@Xi[1]
++	psrld	\$27,$t3
++	pxor	$c,$t0				# Parity(b,c,d)
++	movdqa	$b,$t1
++
++	pslld	\$30,$t1
++	 movdqa	@Xi[1],$tx
++	por	$t3,$t2				# rol(a,5)
++	 psrld	\$31,$tx
++	paddd	$t0,$e				# e+=Parity(b,c,d)
++	 paddd	@Xi[1],@Xi[1]
++
++	psrld	\$2,$b
++	paddd	$t2,$e				# e+=rol(a,5)
++	 por	$tx,@Xi[1]			# rol(@Xi[1],1)
++	por	$t1,$b				# b=rol(b,30)
++___
++$code.=<<___ if ($i==79);
++	movdqa	$a,$t2
++	paddd	$K,$e				# e+=K_20_39
++	movdqa	$d,$t0
++	pslld	\$5,$t2
++	pxor	$b,$t0
++
++	movdqa	$a,$t3
++	paddd	@Xi[0],$e			# e+=X[i]
++	psrld	\$27,$t3
++	movdqa	$b,$t1
++	pxor	$c,$t0				# Parity(b,c,d)
++
++	pslld	\$30,$t1
++	por	$t3,$t2				# rol(a,5)
++	paddd	$t0,$e				# e+=Parity(b,c,d)
++
++	psrld	\$2,$b
++	paddd	$t2,$e				# e+=rol(a,5)
++	por	$t1,$b				# b=rol(b,30)
++___
++push(@Xi,shift(@Xi));
++}
++
++sub BODY_40_59 {
++my ($i,$a,$b,$c,$d,$e)=@_;
++my $j=$i+1;
++
++$code.=<<___;
++	pxor	@Xi[-2],@Xi[1]			# "X[13]"
++	movdqa	`&Xi_off($j+2)`,@Xi[3]		# "X[2]"
++
++	movdqa	$a,$t2
++	movdqa	$d,$t1
++	 pxor	`&Xi_off($j+8)`,@Xi[1]
++	pxor	@Xi[3],@Xi[1]
++	paddd	$K,$e				# e+=K_40_59
++	pslld	\$5,$t2
++	movdqa	$a,$t3
++	pand	$c,$t1
++
++	movdqa	$d,$t0
++	 movdqa	@Xi[1],$tx
++	psrld	\$27,$t3
++	paddd	$t1,$e
++	pxor	$c,$t0
++
++	movdqa	@Xi[0],`&Xi_off($i)`
++	paddd	@Xi[0],$e			# e+=X[i]
++	por	$t3,$t2				# rol(a,5)
++	 psrld	\$31,$tx
++	pand	$b,$t0
++	movdqa	$b,$t1
++
++	pslld	\$30,$t1
++	 paddd	@Xi[1],@Xi[1]
++	paddd	$t0,$e				# e+=Maj(b,d,c)
++
++	psrld	\$2,$b
++	paddd	$t2,$e				# e+=rol(a,5)
++	 por	$tx,@Xi[1]			# rol(@X[1],1)
++	por	$t1,$b				# b=rol(b,30)
++___
++push(@Xi,shift(@Xi));
++}
++
++$code.=<<___;
++.text
++
++.extern	OPENSSL_ia32cap_P
++
++.globl	sha1_multi_block
++.type	sha1_multi_block,\@function,3
++.align	32
++sha1_multi_block:
++	mov	OPENSSL_ia32cap_P+4(%rip),%rcx
++	bt	\$61,%rcx			# check SHA bit
++	jc	_shaext_shortcut
++___
++$code.=<<___ if ($avx);
++	test	\$`1<<28`,%ecx
++	jnz	_avx_shortcut
++___
++$code.=<<___;
++	mov	%rsp,%rax
++	push	%rbx
++	push	%rbp
++___
++$code.=<<___ if ($win64);
++	lea	-0xa8(%rsp),%rsp
++	movaps	%xmm6,(%rsp)
++	movaps	%xmm7,0x10(%rsp)
++	movaps	%xmm8,0x20(%rsp)
++	movaps	%xmm9,0x30(%rsp)
++	movaps	%xmm10,-0x78(%rax)
++	movaps	%xmm11,-0x68(%rax)
++	movaps	%xmm12,-0x58(%rax)
++	movaps	%xmm13,-0x48(%rax)
++	movaps	%xmm14,-0x38(%rax)
++	movaps	%xmm15,-0x28(%rax)
++___
++$code.=<<___;
++	sub	\$`$REG_SZ*18`,%rsp
++	and	\$-256,%rsp
++	mov	%rax,`$REG_SZ*17`(%rsp)		# original %rsp
++.Lbody:
++	lea	K_XX_XX(%rip),$Tbl
++	lea	`$REG_SZ*16`(%rsp),%rbx
++
++.Loop_grande:
++	mov	$num,`$REG_SZ*17+8`(%rsp)	# original $num
++	xor	$num,$num
++___
++for($i=0;$i<4;$i++) {
++    $code.=<<___;
++	mov	`16*$i+0`($inp),@ptr[$i]	# input pointer
++	mov	`16*$i+8`($inp),%ecx		# number of blocks
++	cmp	$num,%ecx
++	cmovg	%ecx,$num			# find maximum
++	test	%ecx,%ecx
++	mov	%ecx,`4*$i`(%rbx)		# initialize counters
++	cmovle	$Tbl,@ptr[$i]			# cancel input
++___
++}
++$code.=<<___;
++	test	$num,$num
++	jz	.Ldone
++
++	movdqu	0x00($ctx),$A			# load context
++	 lea	128(%rsp),%rax
++	movdqu	0x20($ctx),$B
++	movdqu	0x40($ctx),$C
++	movdqu	0x60($ctx),$D
++	movdqu	0x80($ctx),$E
++	movdqa	0x60($Tbl),$tx			# pbswap_mask
++	movdqa	-0x20($Tbl),$K			# K_00_19
++	jmp	.Loop
++
++.align	32
++.Loop:
++___
++for($i=0;$i<20;$i++)	{ &BODY_00_19($i,@V); unshift(@V,pop(@V)); }
++$code.="	movdqa	0x00($Tbl),$K\n";	# K_20_39
++for(;$i<40;$i++)	{ &BODY_20_39($i,@V); unshift(@V,pop(@V)); }
++$code.="	movdqa	0x20($Tbl),$K\n";	# K_40_59
++for(;$i<60;$i++)	{ &BODY_40_59($i,@V); unshift(@V,pop(@V)); }
++$code.="	movdqa	0x40($Tbl),$K\n";	# K_60_79
++for(;$i<80;$i++)	{ &BODY_20_39($i,@V); unshift(@V,pop(@V)); }
++$code.=<<___;
++	movdqa	(%rbx),@Xi[0]			# pull counters
++	mov	\$1,%ecx
++	cmp	4*0(%rbx),%ecx			# examinte counters
++	pxor	$t2,$t2
++	cmovge	$Tbl,@ptr[0]			# cancel input
++	cmp	4*1(%rbx),%ecx
++	movdqa	@Xi[0],@Xi[1]
++	cmovge	$Tbl,@ptr[1]
++	cmp	4*2(%rbx),%ecx
++	pcmpgtd	$t2,@Xi[1]			# mask value
++	cmovge	$Tbl,@ptr[2]
++	cmp	4*3(%rbx),%ecx
++	paddd	@Xi[1],@Xi[0]			# counters--
++	cmovge	$Tbl,@ptr[3]
++
++	movdqu	0x00($ctx),$t0
++	pand	@Xi[1],$A
++	movdqu	0x20($ctx),$t1
++	pand	@Xi[1],$B
++	paddd	$t0,$A
++	movdqu	0x40($ctx),$t2
++	pand	@Xi[1],$C
++	paddd	$t1,$B
++	movdqu	0x60($ctx),$t3
++	pand	@Xi[1],$D
++	paddd	$t2,$C
++	movdqu	0x80($ctx),$tx
++	pand	@Xi[1],$E
++	movdqu	$A,0x00($ctx)
++	paddd	$t3,$D
++	movdqu	$B,0x20($ctx)
++	paddd	$tx,$E
++	movdqu	$C,0x40($ctx)
++	movdqu	$D,0x60($ctx)
++	movdqu	$E,0x80($ctx)
++
++	movdqa	@Xi[0],(%rbx)			# save counters
++	movdqa	0x60($Tbl),$tx			# pbswap_mask
++	movdqa	-0x20($Tbl),$K			# K_00_19
++	dec	$num
++	jnz	.Loop
++
++	mov	`$REG_SZ*17+8`(%rsp),$num
++	lea	$REG_SZ($ctx),$ctx
++	lea	`16*$REG_SZ/4`($inp),$inp
++	dec	$num
++	jnz	.Loop_grande
++
++.Ldone:
++	mov	`$REG_SZ*17`(%rsp),%rax		# original %rsp
++___
++$code.=<<___ if ($win64);
++	movaps	-0xb8(%rax),%xmm6
++	movaps	-0xa8(%rax),%xmm7
++	movaps	-0x98(%rax),%xmm8
++	movaps	-0x88(%rax),%xmm9
++	movaps	-0x78(%rax),%xmm10
++	movaps	-0x68(%rax),%xmm11
++	movaps	-0x58(%rax),%xmm12
++	movaps	-0x48(%rax),%xmm13
++	movaps	-0x38(%rax),%xmm14
++	movaps	-0x28(%rax),%xmm15
++___
++$code.=<<___;
++	mov	-16(%rax),%rbp
++	mov	-8(%rax),%rbx
++	lea	(%rax),%rsp
++.Lepilogue:
++	ret
++.size	sha1_multi_block,.-sha1_multi_block
++___
++						{{{
++my ($ABCD0,$E0,$E0_,$BSWAP,$ABCD1,$E1,$E1_)=map("%xmm$_",(0..3,8..10));
++my @MSG0=map("%xmm$_",(4..7));
++my @MSG1=map("%xmm$_",(11..14));
++
++$code.=<<___;
++.type	sha1_multi_block_shaext,\@function,3
++.align	32
++sha1_multi_block_shaext:
++_shaext_shortcut:
++	mov	%rsp,%rax
++	push	%rbx
++	push	%rbp
++___
++$code.=<<___ if ($win64);
++	lea	-0xa8(%rsp),%rsp
++	movaps	%xmm6,(%rsp)
++	movaps	%xmm7,0x10(%rsp)
++	movaps	%xmm8,0x20(%rsp)
++	movaps	%xmm9,0x30(%rsp)
++	movaps	%xmm10,-0x78(%rax)
++	movaps	%xmm11,-0x68(%rax)
++	movaps	%xmm12,-0x58(%rax)
++	movaps	%xmm13,-0x48(%rax)
++	movaps	%xmm14,-0x38(%rax)
++	movaps	%xmm15,-0x28(%rax)
++___
++$code.=<<___;
++	sub	\$`$REG_SZ*18`,%rsp
++	shl	\$1,$num			# we process pair at a time
++	and	\$-256,%rsp
++	lea	0x40($ctx),$ctx			# size optimization
++	mov	%rax,`$REG_SZ*17`(%rsp)		# original %rsp
++.Lbody_shaext:
++	lea	`$REG_SZ*16`(%rsp),%rbx
++	movdqa	K_XX_XX+0x80(%rip),$BSWAP	# byte-n-word swap
++
++.Loop_grande_shaext:
++	mov	$num,`$REG_SZ*17+8`(%rsp)	# original $num
++	xor	$num,$num
++___
++for($i=0;$i<2;$i++) {
++    $code.=<<___;
++	mov	`16*$i+0`($inp),@ptr[$i]	# input pointer
++	mov	`16*$i+8`($inp),%ecx		# number of blocks
++	cmp	$num,%ecx
++	cmovg	%ecx,$num			# find maximum
++	test	%ecx,%ecx
++	mov	%ecx,`4*$i`(%rbx)		# initialize counters
++	cmovle	%rsp,@ptr[$i]			# cancel input
++___
++}
++$code.=<<___;
++	test	$num,$num
++	jz	.Ldone_shaext
++
++	movq		0x00-0x40($ctx),$ABCD0	# a1.a0
++	movq		0x20-0x40($ctx),@MSG0[0]# b1.b0
++	movq		0x40-0x40($ctx),@MSG0[1]# c1.c0
++	movq		0x60-0x40($ctx),@MSG0[2]# d1.d0
++	movq		0x80-0x40($ctx),@MSG0[3]# e1.e0
++
++	punpckldq	@MSG0[0],$ABCD0		# b1.a1.b0.a0
++	punpckldq	@MSG0[2],@MSG0[1]	# d1.c1.d0.c0
++
++	movdqa		$ABCD0,$ABCD1
++	punpcklqdq	@MSG0[1],$ABCD0		# d0.c0.b0.a0
++	punpckhqdq	@MSG0[1],$ABCD1		# d1.c1.b1.a1
++
++	pshufd		\$0b00111111,@MSG0[3],$E0
++	pshufd		\$0b01111111,@MSG0[3],$E1
++	pshufd		\$0b00011011,$ABCD0,$ABCD0
++	pshufd		\$0b00011011,$ABCD1,$ABCD1
++	jmp		.Loop_shaext
++
++.align	32
++.Loop_shaext:
++	movdqu		0x00(@ptr[0]),@MSG0[0]
++	 movdqu		0x00(@ptr[1]),@MSG1[0]
++	movdqu		0x10(@ptr[0]),@MSG0[1]
++	 movdqu		0x10(@ptr[1]),@MSG1[1]
++	movdqu		0x20(@ptr[0]),@MSG0[2]
++	pshufb		$BSWAP,@MSG0[0]
++	 movdqu		0x20(@ptr[1]),@MSG1[2]
++	 pshufb		$BSWAP,@MSG1[0]
++	movdqu		0x30(@ptr[0]),@MSG0[3]
++	lea		0x40(@ptr[0]),@ptr[0]
++	pshufb		$BSWAP,@MSG0[1]
++	 movdqu		0x30(@ptr[1]),@MSG1[3]
++	 lea		0x40(@ptr[1]),@ptr[1]
++	 pshufb		$BSWAP,@MSG1[1]
++
++	movdqa		$E0,0x50(%rsp)		# offload
++	paddd		@MSG0[0],$E0
++	 movdqa		$E1,0x70(%rsp)
++	 paddd		@MSG1[0],$E1
++	movdqa		$ABCD0,0x40(%rsp)	# offload
++	movdqa		$ABCD0,$E0_
++	 movdqa		$ABCD1,0x60(%rsp)
++	 movdqa		$ABCD1,$E1_
++	sha1rnds4	\$0,$E0,$ABCD0		# 0-3
++	sha1nexte	@MSG0[1],$E0_
++	 sha1rnds4	\$0,$E1,$ABCD1		# 0-3
++	 sha1nexte	@MSG1[1],$E1_
++	pshufb		$BSWAP,@MSG0[2]
++	prefetcht0	127(@ptr[0])
++	sha1msg1	@MSG0[1],@MSG0[0]
++	 pshufb		$BSWAP,@MSG1[2]
++	 prefetcht0	127(@ptr[1])
++	 sha1msg1	@MSG1[1],@MSG1[0]
++
++	pshufb		$BSWAP,@MSG0[3]
++	movdqa		$ABCD0,$E0
++	 pshufb		$BSWAP,@MSG1[3]
++	 movdqa		$ABCD1,$E1
++	sha1rnds4	\$0,$E0_,$ABCD0		# 4-7
++	sha1nexte	@MSG0[2],$E0
++	 sha1rnds4	\$0,$E1_,$ABCD1		# 4-7
++	 sha1nexte	@MSG1[2],$E1
++	pxor		@MSG0[2],@MSG0[0]
++	sha1msg1	@MSG0[2],@MSG0[1]
++	 pxor		@MSG1[2],@MSG1[0]
++	 sha1msg1	@MSG1[2],@MSG1[1]
++___
++for($i=2;$i<20-4;$i++) {
++$code.=<<___;
++	movdqa		$ABCD0,$E0_
++	 movdqa		$ABCD1,$E1_
++	sha1rnds4	\$`int($i/5)`,$E0,$ABCD0	# 8-11
++	sha1nexte	@MSG0[3],$E0_
++	 sha1rnds4	\$`int($i/5)`,$E1,$ABCD1	# 8-11
++	 sha1nexte	@MSG1[3],$E1_
++	sha1msg2	@MSG0[3],@MSG0[0]
++	 sha1msg2	@MSG1[3],@MSG1[0]
++	pxor		@MSG0[3],@MSG0[1]
++	sha1msg1	@MSG0[3],@MSG0[2]
++	 pxor		@MSG1[3],@MSG1[1]
++	 sha1msg1	@MSG1[3],@MSG1[2]
++___
++	($E0,$E0_)=($E0_,$E0);		($E1,$E1_)=($E1_,$E1);
++	push(@MSG0,shift(@MSG0));	push(@MSG1,shift(@MSG1));
++}
++$code.=<<___;
++	movdqa		$ABCD0,$E0_
++	 movdqa		$ABCD1,$E1_
++	sha1rnds4	\$3,$E0,$ABCD0		# 64-67
++	sha1nexte	@MSG0[3],$E0_
++	 sha1rnds4	\$3,$E1,$ABCD1		# 64-67
++	 sha1nexte	@MSG1[3],$E1_
++	sha1msg2	@MSG0[3],@MSG0[0]
++	 sha1msg2	@MSG1[3],@MSG1[0]
++	pxor		@MSG0[3],@MSG0[1]
++	 pxor		@MSG1[3],@MSG1[1]
++
++	mov		\$1,%ecx
++	pxor		@MSG0[2],@MSG0[2]	# zero
++	cmp		4*0(%rbx),%ecx		# examine counters
++	cmovge		%rsp,@ptr[0]		# cancel input
++
++	movdqa		$ABCD0,$E0
++	 movdqa		$ABCD1,$E1
++	sha1rnds4	\$3,$E0_,$ABCD0		# 68-71
++	sha1nexte	@MSG0[0],$E0
++	 sha1rnds4	\$3,$E1_,$ABCD1		# 68-71
++	 sha1nexte	@MSG1[0],$E1
++	sha1msg2	@MSG0[0],@MSG0[1]
++	 sha1msg2	@MSG1[0],@MSG1[1]
++
++	cmp		4*1(%rbx),%ecx
++	cmovge		%rsp,@ptr[1]
++	movq		(%rbx),@MSG0[0]		# pull counters
++
++	movdqa		$ABCD0,$E0_
++	 movdqa		$ABCD1,$E1_
++	sha1rnds4	\$3,$E0,$ABCD0		# 72-75
++	sha1nexte	@MSG0[1],$E0_
++	 sha1rnds4	\$3,$E1,$ABCD1		# 72-75
++	 sha1nexte	@MSG1[1],$E1_
++
++	pshufd		\$0x00,@MSG0[0],@MSG1[2]
++	pshufd		\$0x55,@MSG0[0],@MSG1[3]
++	movdqa		@MSG0[0],@MSG0[1]
++	pcmpgtd		@MSG0[2],@MSG1[2]
++	pcmpgtd		@MSG0[2],@MSG1[3]
++
++	movdqa		$ABCD0,$E0
++	 movdqa		$ABCD1,$E1
++	sha1rnds4	\$3,$E0_,$ABCD0		# 76-79
++	sha1nexte	$MSG0[2],$E0
++	 sha1rnds4	\$3,$E1_,$ABCD1		# 76-79
++	 sha1nexte	$MSG0[2],$E1
++
++	pcmpgtd		@MSG0[2],@MSG0[1]	# counter mask
++	pand		@MSG1[2],$ABCD0
++	pand		@MSG1[2],$E0
++	 pand		@MSG1[3],$ABCD1
++	 pand		@MSG1[3],$E1
++	paddd		@MSG0[1],@MSG0[0]	# counters--
++
++	paddd		0x40(%rsp),$ABCD0
++	paddd		0x50(%rsp),$E0
++	 paddd		0x60(%rsp),$ABCD1
++	 paddd		0x70(%rsp),$E1
++
++	movq		@MSG0[0],(%rbx)		# save counters
++	dec		$num
++	jnz		.Loop_shaext
++
++	mov		`$REG_SZ*17+8`(%rsp),$num
++
++	pshufd		\$0b00011011,$ABCD0,$ABCD0
++	pshufd		\$0b00011011,$ABCD1,$ABCD1
++
++	movdqa		$ABCD0,@MSG0[0]
++	punpckldq	$ABCD1,$ABCD0		# b1.b0.a1.a0
++	punpckhdq	$ABCD1,@MSG0[0]		# d1.d0.c1.c0
++	punpckhdq	$E1,$E0			# e1.e0.xx.xx
++	movq		$ABCD0,0x00-0x40($ctx)	# a1.a0
++	psrldq		\$8,$ABCD0
++	movq		@MSG0[0],0x40-0x40($ctx)# c1.c0
++	psrldq		\$8,@MSG0[0]
++	movq		$ABCD0,0x20-0x40($ctx)	# b1.b0
++	psrldq		\$8,$E0
++	movq		@MSG0[0],0x60-0x40($ctx)# d1.d0
++	movq		$E0,0x80-0x40($ctx)	# e1.e0
++
++	lea	`$REG_SZ/2`($ctx),$ctx
++	lea	`16*2`($inp),$inp
++	dec	$num
++	jnz	.Loop_grande_shaext
++
++.Ldone_shaext:
++	#mov	`$REG_SZ*17`(%rsp),%rax		# original %rsp
++___
++$code.=<<___ if ($win64);
++	movaps	-0xb8(%rax),%xmm6
++	movaps	-0xa8(%rax),%xmm7
++	movaps	-0x98(%rax),%xmm8
++	movaps	-0x88(%rax),%xmm9
++	movaps	-0x78(%rax),%xmm10
++	movaps	-0x68(%rax),%xmm11
++	movaps	-0x58(%rax),%xmm12
++	movaps	-0x48(%rax),%xmm13
++	movaps	-0x38(%rax),%xmm14
++	movaps	-0x28(%rax),%xmm15
++___
++$code.=<<___;
++	mov	-16(%rax),%rbp
++	mov	-8(%rax),%rbx
++	lea	(%rax),%rsp
++.Lepilogue_shaext:
++	ret
++.size	sha1_multi_block_shaext,.-sha1_multi_block_shaext
++___
++						}}}
++
++						if ($avx) {{{
++sub BODY_00_19_avx {
++my ($i,$a,$b,$c,$d,$e)=@_;
++my $j=$i+1;
++my $k=$i+2;
++my $vpack = $REG_SZ==16 ? "vpunpckldq" : "vinserti128";
++my $ptr_n = $REG_SZ==16 ? @ptr[1] : @ptr[4];
++
++$code.=<<___ if ($i==0 && $REG_SZ==16);
++	vmovd		(@ptr[0]),@Xi[0]
++	 lea		`16*4`(@ptr[0]),@ptr[0]
++	vmovd		(@ptr[1]),@Xi[2]	# borrow Xi[2]
++	 lea		`16*4`(@ptr[1]),@ptr[1]
++	vpinsrd		\$1,(@ptr[2]),@Xi[0],@Xi[0]
++	 lea		`16*4`(@ptr[2]),@ptr[2]
++	vpinsrd		\$1,(@ptr[3]),@Xi[2],@Xi[2]
++	 lea		`16*4`(@ptr[3]),@ptr[3]
++	 vmovd		`4*$j-16*4`(@ptr[0]),@Xi[1]
++	vpunpckldq	@Xi[2],@Xi[0],@Xi[0]
++	 vmovd		`4*$j-16*4`($ptr_n),$t3
++	vpshufb		$tx,@Xi[0],@Xi[0]
++___
++$code.=<<___ if ($i<15 && $REG_SZ==16);		# just load input
++	 vpinsrd	\$1,`4*$j-16*4`(@ptr[2]),@Xi[1],@Xi[1]
++	 vpinsrd	\$1,`4*$j-16*4`(@ptr[3]),$t3,$t3
++___
++$code.=<<___ if ($i==0 && $REG_SZ==32);
++	vmovd		(@ptr[0]),@Xi[0]
++	 lea		`16*4`(@ptr[0]),@ptr[0]
++	vmovd		(@ptr[4]),@Xi[2]	# borrow Xi[2]
++	 lea		`16*4`(@ptr[4]),@ptr[4]
++	vmovd		(@ptr[1]),$t2
++	 lea		`16*4`(@ptr[1]),@ptr[1]
++	vmovd		(@ptr[5]),$t1
++	 lea		`16*4`(@ptr[5]),@ptr[5]
++	vpinsrd		\$1,(@ptr[2]),@Xi[0],@Xi[0]
++	 lea		`16*4`(@ptr[2]),@ptr[2]
++	vpinsrd		\$1,(@ptr[6]),@Xi[2],@Xi[2]
++	 lea		`16*4`(@ptr[6]),@ptr[6]
++	vpinsrd		\$1,(@ptr[3]),$t2,$t2
++	 lea		`16*4`(@ptr[3]),@ptr[3]
++	vpunpckldq	$t2,@Xi[0],@Xi[0]
++	vpinsrd		\$1,(@ptr[7]),$t1,$t1
++	 lea		`16*4`(@ptr[7]),@ptr[7]
++	vpunpckldq	$t1,@Xi[2],@Xi[2]
++	 vmovd		`4*$j-16*4`(@ptr[0]),@Xi[1]
++	vinserti128	@Xi[2],@Xi[0],@Xi[0]
++	 vmovd		`4*$j-16*4`($ptr_n),$t3
++	vpshufb		$tx,@Xi[0],@Xi[0]
++___
++$code.=<<___ if ($i<15 && $REG_SZ==32);		# just load input
++	 vmovd		`4*$j-16*4`(@ptr[1]),$t2
++	 vmovd		`4*$j-16*4`(@ptr[5]),$t1
++	 vpinsrd	\$1,`4*$j-16*4`(@ptr[2]),@Xi[1],@Xi[1]
++	 vpinsrd	\$1,`4*$j-16*4`(@ptr[6]),$t3,$t3
++	 vpinsrd	\$1,`4*$j-16*4`(@ptr[3]),$t2,$t2
++	 vpunpckldq	$t2,@Xi[1],@Xi[1]
++	 vpinsrd	\$1,`4*$j-16*4`(@ptr[7]),$t1,$t1
++	 vpunpckldq	$t1,$t3,$t3
++___
++$code.=<<___ if ($i<14);
++	vpaddd	$K,$e,$e			# e+=K_00_19
++	vpslld	\$5,$a,$t2
++	vpandn	$d,$b,$t1
++	vpand	$c,$b,$t0
++
++	vmovdqa	@Xi[0],`&Xi_off($i)`
++	vpaddd	@Xi[0],$e,$e			# e+=X[i]
++	 $vpack		$t3,@Xi[1],@Xi[1]
++	vpsrld	\$27,$a,$t3
++	vpxor	$t1,$t0,$t0			# Ch(b,c,d)
++	 vmovd		`4*$k-16*4`(@ptr[0]),@Xi[2]
++
++	vpslld	\$30,$b,$t1
++	vpor	$t3,$t2,$t2			# rol(a,5)
++	 vmovd		`4*$k-16*4`($ptr_n),$t3
++	vpaddd	$t0,$e,$e			# e+=Ch(b,c,d)
++
++	vpsrld	\$2,$b,$b
++	vpaddd	$t2,$e,$e			# e+=rol(a,5)
++	 vpshufb	$tx,@Xi[1],@Xi[1]
++	vpor	$t1,$b,$b			# b=rol(b,30)
++___
++$code.=<<___ if ($i==14);
++	vpaddd	$K,$e,$e			# e+=K_00_19
++	 prefetcht0	63(@ptr[0])
++	vpslld	\$5,$a,$t2
++	vpandn	$d,$b,$t1
++	vpand	$c,$b,$t0
++
++	vmovdqa	@Xi[0],`&Xi_off($i)`
++	vpaddd	@Xi[0],$e,$e			# e+=X[i]
++	 $vpack		$t3,@Xi[1],@Xi[1]
++	vpsrld	\$27,$a,$t3
++	 prefetcht0	63(@ptr[1])
++	vpxor	$t1,$t0,$t0			# Ch(b,c,d)
++
++	vpslld	\$30,$b,$t1
++	vpor	$t3,$t2,$t2			# rol(a,5)
++	 prefetcht0	63(@ptr[2])
++	vpaddd	$t0,$e,$e			# e+=Ch(b,c,d)
++
++	vpsrld	\$2,$b,$b
++	vpaddd	$t2,$e,$e			# e+=rol(a,5)
++	 prefetcht0	63(@ptr[3])
++	 vpshufb	$tx,@Xi[1],@Xi[1]
++	vpor	$t1,$b,$b			# b=rol(b,30)
++___
++$code.=<<___ if ($i>=13 && $i<15);
++	vmovdqa	`&Xi_off($j+2)`,@Xi[3]		# preload "X[2]"
++___
++$code.=<<___ if ($i>=15);			# apply Xupdate
++	vpxor	@Xi[-2],@Xi[1],@Xi[1]		# "X[13]"
++	vmovdqa	`&Xi_off($j+2)`,@Xi[3]		# "X[2]"
++
++	vpaddd	$K,$e,$e			# e+=K_00_19
++	vpslld	\$5,$a,$t2
++	vpandn	$d,$b,$t1
++	 `"prefetcht0	63(@ptr[4])"		if ($i==15 && $REG_SZ==32)`
++	vpand	$c,$b,$t0
++
++	vmovdqa	@Xi[0],`&Xi_off($i)`
++	vpaddd	@Xi[0],$e,$e			# e+=X[i]
++	 vpxor	`&Xi_off($j+8)`,@Xi[1],@Xi[1]
++	vpsrld	\$27,$a,$t3
++	vpxor	$t1,$t0,$t0			# Ch(b,c,d)
++	 vpxor	@Xi[3],@Xi[1],@Xi[1]
++	 `"prefetcht0	63(@ptr[5])"		if ($i==15 && $REG_SZ==32)`
++
++	vpslld	\$30,$b,$t1
++	vpor	$t3,$t2,$t2			# rol(a,5)
++	vpaddd	$t0,$e,$e			# e+=Ch(b,c,d)
++	 `"prefetcht0	63(@ptr[6])"		if ($i==15 && $REG_SZ==32)`
++	 vpsrld	\$31,@Xi[1],$tx
++	 vpaddd	@Xi[1],@Xi[1],@Xi[1]
++
++	vpsrld	\$2,$b,$b
++	 `"prefetcht0	63(@ptr[7])"		if ($i==15 && $REG_SZ==32)`
++	vpaddd	$t2,$e,$e			# e+=rol(a,5)
++	 vpor	$tx,@Xi[1],@Xi[1]		# rol	\$1,@Xi[1]
++	vpor	$t1,$b,$b			# b=rol(b,30)
++___
++push(@Xi,shift(@Xi));
++}
++
++sub BODY_20_39_avx {
++my ($i,$a,$b,$c,$d,$e)=@_;
++my $j=$i+1;
++
++$code.=<<___ if ($i<79);
++	vpxor	@Xi[-2],@Xi[1],@Xi[1]		# "X[13]"
++	vmovdqa	`&Xi_off($j+2)`,@Xi[3]		# "X[2]"
++
++	vpslld	\$5,$a,$t2
++	vpaddd	$K,$e,$e			# e+=K_20_39
++	vpxor	$b,$d,$t0
++___
++$code.=<<___ if ($i<72);
++	vmovdqa	@Xi[0],`&Xi_off($i)`
++___
++$code.=<<___ if ($i<79);
++	vpaddd	@Xi[0],$e,$e			# e+=X[i]
++	 vpxor	`&Xi_off($j+8)`,@Xi[1],@Xi[1]
++	vpsrld	\$27,$a,$t3
++	vpxor	$c,$t0,$t0			# Parity(b,c,d)
++	 vpxor	@Xi[3],@Xi[1],@Xi[1]
++
++	vpslld	\$30,$b,$t1
++	vpor	$t3,$t2,$t2			# rol(a,5)
++	vpaddd	$t0,$e,$e			# e+=Parity(b,c,d)
++	 vpsrld	\$31,@Xi[1],$tx
++	 vpaddd	@Xi[1],@Xi[1],@Xi[1]
++
++	vpsrld	\$2,$b,$b
++	vpaddd	$t2,$e,$e			# e+=rol(a,5)
++	 vpor	$tx,@Xi[1],@Xi[1]		# rol(@Xi[1],1)
++	vpor	$t1,$b,$b			# b=rol(b,30)
++___
++$code.=<<___ if ($i==79);
++	vpslld	\$5,$a,$t2
++	vpaddd	$K,$e,$e			# e+=K_20_39
++	vpxor	$b,$d,$t0
++
++	vpsrld	\$27,$a,$t3
++	vpaddd	@Xi[0],$e,$e			# e+=X[i]
++	vpxor	$c,$t0,$t0			# Parity(b,c,d)
++
++	vpslld	\$30,$b,$t1
++	vpor	$t3,$t2,$t2			# rol(a,5)
++	vpaddd	$t0,$e,$e			# e+=Parity(b,c,d)
++
++	vpsrld	\$2,$b,$b
++	vpaddd	$t2,$e,$e			# e+=rol(a,5)
++	vpor	$t1,$b,$b			# b=rol(b,30)
++___
++push(@Xi,shift(@Xi));
++}
++
++sub BODY_40_59_avx {
++my ($i,$a,$b,$c,$d,$e)=@_;
++my $j=$i+1;
++
++$code.=<<___;
++	vpxor	@Xi[-2],@Xi[1],@Xi[1]		# "X[13]"
++	vmovdqa	`&Xi_off($j+2)`,@Xi[3]		# "X[2]"
++
++	vpaddd	$K,$e,$e			# e+=K_40_59
++	vpslld	\$5,$a,$t2
++	vpand	$c,$d,$t1
++	 vpxor	`&Xi_off($j+8)`,@Xi[1],@Xi[1]
++
++	vpaddd	$t1,$e,$e
++	vpsrld	\$27,$a,$t3
++	vpxor	$c,$d,$t0
++	 vpxor	@Xi[3],@Xi[1],@Xi[1]
++
++	vmovdqu	@Xi[0],`&Xi_off($i)`
++	vpaddd	@Xi[0],$e,$e			# e+=X[i]
++	vpor	$t3,$t2,$t2			# rol(a,5)
++	 vpsrld	\$31,@Xi[1],$tx
++	vpand	$b,$t0,$t0
++	 vpaddd	@Xi[1],@Xi[1],@Xi[1]
++
++	vpslld	\$30,$b,$t1
++	vpaddd	$t0,$e,$e			# e+=Maj(b,d,c)
++
++	vpsrld	\$2,$b,$b
++	vpaddd	$t2,$e,$e			# e+=rol(a,5)
++	 vpor	$tx,@Xi[1],@Xi[1]		# rol(@X[1],1)
++	vpor	$t1,$b,$b			# b=rol(b,30)
++___
++push(@Xi,shift(@Xi));
++}
++
++$code.=<<___;
++.type	sha1_multi_block_avx,\@function,3
++.align	32
++sha1_multi_block_avx:
++_avx_shortcut:
++___
++$code.=<<___ if ($avx>1);
++	shr	\$32,%rcx
++	cmp	\$2,$num
++	jb	.Lavx
++	test	\$`1<<5`,%ecx
++	jnz	_avx2_shortcut
++	jmp	.Lavx
++.align	32
++.Lavx:
++___
++$code.=<<___;
++	mov	%rsp,%rax
++	push	%rbx
++	push	%rbp
++___
++$code.=<<___ if ($win64);
++	lea	-0xa8(%rsp),%rsp
++	movaps	%xmm6,(%rsp)
++	movaps	%xmm7,0x10(%rsp)
++	movaps	%xmm8,0x20(%rsp)
++	movaps	%xmm9,0x30(%rsp)
++	movaps	%xmm10,-0x78(%rax)
++	movaps	%xmm11,-0x68(%rax)
++	movaps	%xmm12,-0x58(%rax)
++	movaps	%xmm13,-0x48(%rax)
++	movaps	%xmm14,-0x38(%rax)
++	movaps	%xmm15,-0x28(%rax)
++___
++$code.=<<___;
++	sub	\$`$REG_SZ*18`, %rsp
++	and	\$-256,%rsp
++	mov	%rax,`$REG_SZ*17`(%rsp)		# original %rsp
++.Lbody_avx:
++	lea	K_XX_XX(%rip),$Tbl
++	lea	`$REG_SZ*16`(%rsp),%rbx
++
++	vzeroupper
++.Loop_grande_avx:
++	mov	$num,`$REG_SZ*17+8`(%rsp)	# original $num
++	xor	$num,$num
++___
++for($i=0;$i<4;$i++) {
++    $code.=<<___;
++	mov	`16*$i+0`($inp),@ptr[$i]	# input pointer
++	mov	`16*$i+8`($inp),%ecx		# number of blocks
++	cmp	$num,%ecx
++	cmovg	%ecx,$num			# find maximum
++	test	%ecx,%ecx
++	mov	%ecx,`4*$i`(%rbx)		# initialize counters
++	cmovle	$Tbl,@ptr[$i]			# cancel input
++___
++}
++$code.=<<___;
++	test	$num,$num
++	jz	.Ldone_avx
++
++	vmovdqu	0x00($ctx),$A			# load context
++	 lea	128(%rsp),%rax
++	vmovdqu	0x20($ctx),$B
++	vmovdqu	0x40($ctx),$C
++	vmovdqu	0x60($ctx),$D
++	vmovdqu	0x80($ctx),$E
++	vmovdqu	0x60($Tbl),$tx			# pbswap_mask
++	jmp	.Loop_avx
++
++.align	32
++.Loop_avx:
++___
++$code.="	vmovdqa	-0x20($Tbl),$K\n";	# K_00_19
++for($i=0;$i<20;$i++)	{ &BODY_00_19_avx($i,@V); unshift(@V,pop(@V)); }
++$code.="	vmovdqa	0x00($Tbl),$K\n";	# K_20_39
++for(;$i<40;$i++)	{ &BODY_20_39_avx($i,@V); unshift(@V,pop(@V)); }
++$code.="	vmovdqa	0x20($Tbl),$K\n";	# K_40_59
++for(;$i<60;$i++)	{ &BODY_40_59_avx($i,@V); unshift(@V,pop(@V)); }
++$code.="	vmovdqa	0x40($Tbl),$K\n";	# K_60_79
++for(;$i<80;$i++)	{ &BODY_20_39_avx($i,@V); unshift(@V,pop(@V)); }
++$code.=<<___;
++	mov	\$1,%ecx
++___
++for($i=0;$i<4;$i++) {
++    $code.=<<___;
++	cmp	`4*$i`(%rbx),%ecx		# examine counters
++	cmovge	$Tbl,@ptr[$i]			# cancel input
++___
++}
++$code.=<<___;
++	vmovdqu	(%rbx),$t0			# pull counters
++	vpxor	$t2,$t2,$t2
++	vmovdqa	$t0,$t1
++	vpcmpgtd $t2,$t1,$t1			# mask value
++	vpaddd	$t1,$t0,$t0			# counters--
++
++	vpand	$t1,$A,$A
++	vpand	$t1,$B,$B
++	vpaddd	0x00($ctx),$A,$A
++	vpand	$t1,$C,$C
++	vpaddd	0x20($ctx),$B,$B
++	vpand	$t1,$D,$D
++	vpaddd	0x40($ctx),$C,$C
++	vpand	$t1,$E,$E
++	vpaddd	0x60($ctx),$D,$D
++	vpaddd	0x80($ctx),$E,$E
++	vmovdqu	$A,0x00($ctx)
++	vmovdqu	$B,0x20($ctx)
++	vmovdqu	$C,0x40($ctx)
++	vmovdqu	$D,0x60($ctx)
++	vmovdqu	$E,0x80($ctx)
++
++	vmovdqu	$t0,(%rbx)			# save counters
++	vmovdqu	0x60($Tbl),$tx			# pbswap_mask
++	dec	$num
++	jnz	.Loop_avx
++
++	mov	`$REG_SZ*17+8`(%rsp),$num
++	lea	$REG_SZ($ctx),$ctx
++	lea	`16*$REG_SZ/4`($inp),$inp
++	dec	$num
++	jnz	.Loop_grande_avx
++
++.Ldone_avx:
++	mov	`$REG_SZ*17`(%rsp),%rax		# original %rsp
++	vzeroupper
++___
++$code.=<<___ if ($win64);
++	movaps	-0xb8(%rax),%xmm6
++	movaps	-0xa8(%rax),%xmm7
++	movaps	-0x98(%rax),%xmm8
++	movaps	-0x88(%rax),%xmm9
++	movaps	-0x78(%rax),%xmm10
++	movaps	-0x68(%rax),%xmm11
++	movaps	-0x58(%rax),%xmm12
++	movaps	-0x48(%rax),%xmm13
++	movaps	-0x38(%rax),%xmm14
++	movaps	-0x28(%rax),%xmm15
++___
++$code.=<<___;
++	mov	-16(%rax),%rbp
++	mov	-8(%rax),%rbx
++	lea	(%rax),%rsp
++.Lepilogue_avx:
++	ret
++.size	sha1_multi_block_avx,.-sha1_multi_block_avx
++___
++
++						if ($avx>1) {
++$code =~ s/\`([^\`]*)\`/eval $1/gem;
++
++$REG_SZ=32;
++
++@ptr=map("%r$_",(12..15,8..11));
++
++@V=($A,$B,$C,$D,$E)=map("%ymm$_",(0..4));
++($t0,$t1,$t2,$t3,$tx)=map("%ymm$_",(5..9));
++@Xi=map("%ymm$_",(10..14));
++$K="%ymm15";
++
++$code.=<<___;
++.type	sha1_multi_block_avx2,\@function,3
++.align	32
++sha1_multi_block_avx2:
++_avx2_shortcut:
++	mov	%rsp,%rax
++	push	%rbx
++	push	%rbp
++	push	%r12
++	push	%r13
++	push	%r14
++	push	%r15
++___
++$code.=<<___ if ($win64);
++	lea	-0xa8(%rsp),%rsp
++	movaps	%xmm6,(%rsp)
++	movaps	%xmm7,0x10(%rsp)
++	movaps	%xmm8,0x20(%rsp)
++	movaps	%xmm9,0x30(%rsp)
++	movaps	%xmm10,0x40(%rsp)
++	movaps	%xmm11,0x50(%rsp)
++	movaps	%xmm12,-0x78(%rax)
++	movaps	%xmm13,-0x68(%rax)
++	movaps	%xmm14,-0x58(%rax)
++	movaps	%xmm15,-0x48(%rax)
++___
++$code.=<<___;
++	sub	\$`$REG_SZ*18`, %rsp
++	and	\$-256,%rsp
++	mov	%rax,`$REG_SZ*17`(%rsp)		# original %rsp
++.Lbody_avx2:
++	lea	K_XX_XX(%rip),$Tbl
++	shr	\$1,$num
++
++	vzeroupper
++.Loop_grande_avx2:
++	mov	$num,`$REG_SZ*17+8`(%rsp)	# original $num
++	xor	$num,$num
++	lea	`$REG_SZ*16`(%rsp),%rbx
++___
++for($i=0;$i<8;$i++) {
++    $code.=<<___;
++	mov	`16*$i+0`($inp),@ptr[$i]	# input pointer
++	mov	`16*$i+8`($inp),%ecx		# number of blocks
++	cmp	$num,%ecx
++	cmovg	%ecx,$num			# find maximum
++	test	%ecx,%ecx
++	mov	%ecx,`4*$i`(%rbx)		# initialize counters
++	cmovle	$Tbl,@ptr[$i]			# cancel input
++___
++}
++$code.=<<___;
++	vmovdqu	0x00($ctx),$A			# load context
++	 lea	128(%rsp),%rax
++	vmovdqu	0x20($ctx),$B
++	 lea	256+128(%rsp),%rbx
++	vmovdqu	0x40($ctx),$C
++	vmovdqu	0x60($ctx),$D
++	vmovdqu	0x80($ctx),$E
++	vmovdqu	0x60($Tbl),$tx			# pbswap_mask
++	jmp	.Loop_avx2
++
++.align	32
++.Loop_avx2:
++___
++$code.="	vmovdqa	-0x20($Tbl),$K\n";	# K_00_19
++for($i=0;$i<20;$i++)	{ &BODY_00_19_avx($i,@V); unshift(@V,pop(@V)); }
++$code.="	vmovdqa	0x00($Tbl),$K\n";	# K_20_39
++for(;$i<40;$i++)	{ &BODY_20_39_avx($i,@V); unshift(@V,pop(@V)); }
++$code.="	vmovdqa	0x20($Tbl),$K\n";	# K_40_59
++for(;$i<60;$i++)	{ &BODY_40_59_avx($i,@V); unshift(@V,pop(@V)); }
++$code.="	vmovdqa	0x40($Tbl),$K\n";	# K_60_79
++for(;$i<80;$i++)	{ &BODY_20_39_avx($i,@V); unshift(@V,pop(@V)); }
++$code.=<<___;
++	mov	\$1,%ecx
++	lea	`$REG_SZ*16`(%rsp),%rbx
++___
++for($i=0;$i<8;$i++) {
++    $code.=<<___;
++	cmp	`4*$i`(%rbx),%ecx		# examine counters
++	cmovge	$Tbl,@ptr[$i]			# cancel input
++___
++}
++$code.=<<___;
++	vmovdqu	(%rbx),$t0		# pull counters
++	vpxor	$t2,$t2,$t2
++	vmovdqa	$t0,$t1
++	vpcmpgtd $t2,$t1,$t1			# mask value
++	vpaddd	$t1,$t0,$t0			# counters--
++
++	vpand	$t1,$A,$A
++	vpand	$t1,$B,$B
++	vpaddd	0x00($ctx),$A,$A
++	vpand	$t1,$C,$C
++	vpaddd	0x20($ctx),$B,$B
++	vpand	$t1,$D,$D
++	vpaddd	0x40($ctx),$C,$C
++	vpand	$t1,$E,$E
++	vpaddd	0x60($ctx),$D,$D
++	vpaddd	0x80($ctx),$E,$E
++	vmovdqu	$A,0x00($ctx)
++	vmovdqu	$B,0x20($ctx)
++	vmovdqu	$C,0x40($ctx)
++	vmovdqu	$D,0x60($ctx)
++	vmovdqu	$E,0x80($ctx)
++
++	vmovdqu	$t0,(%rbx)			# save counters
++	lea	256+128(%rsp),%rbx
++	vmovdqu	0x60($Tbl),$tx			# pbswap_mask
++	dec	$num
++	jnz	.Loop_avx2
++
++	#mov	`$REG_SZ*17+8`(%rsp),$num
++	#lea	$REG_SZ($ctx),$ctx
++	#lea	`16*$REG_SZ/4`($inp),$inp
++	#dec	$num
++	#jnz	.Loop_grande_avx2
++
++.Ldone_avx2:
++	mov	`$REG_SZ*17`(%rsp),%rax		# original %rsp
++	vzeroupper
++___
++$code.=<<___ if ($win64);
++	movaps	-0xd8(%rax),%xmm6
++	movaps	-0xc8(%rax),%xmm7
++	movaps	-0xb8(%rax),%xmm8
++	movaps	-0xa8(%rax),%xmm9
++	movaps	-0x98(%rax),%xmm10
++	movaps	-0x88(%rax),%xmm11
++	movaps	-0x78(%rax),%xmm12
++	movaps	-0x68(%rax),%xmm13
++	movaps	-0x58(%rax),%xmm14
++	movaps	-0x48(%rax),%xmm15
++___
++$code.=<<___;
++	mov	-48(%rax),%r15
++	mov	-40(%rax),%r14
++	mov	-32(%rax),%r13
++	mov	-24(%rax),%r12
++	mov	-16(%rax),%rbp
++	mov	-8(%rax),%rbx
++	lea	(%rax),%rsp
++.Lepilogue_avx2:
++	ret
++.size	sha1_multi_block_avx2,.-sha1_multi_block_avx2
++___
++						}	}}}
++$code.=<<___;
++
++.align	256
++	.long	0x5a827999,0x5a827999,0x5a827999,0x5a827999	# K_00_19
++	.long	0x5a827999,0x5a827999,0x5a827999,0x5a827999	# K_00_19
++K_XX_XX:
++	.long	0x6ed9eba1,0x6ed9eba1,0x6ed9eba1,0x6ed9eba1	# K_20_39
++	.long	0x6ed9eba1,0x6ed9eba1,0x6ed9eba1,0x6ed9eba1	# K_20_39
++	.long	0x8f1bbcdc,0x8f1bbcdc,0x8f1bbcdc,0x8f1bbcdc	# K_40_59
++	.long	0x8f1bbcdc,0x8f1bbcdc,0x8f1bbcdc,0x8f1bbcdc	# K_40_59
++	.long	0xca62c1d6,0xca62c1d6,0xca62c1d6,0xca62c1d6	# K_60_79
++	.long	0xca62c1d6,0xca62c1d6,0xca62c1d6,0xca62c1d6	# K_60_79
++	.long	0x00010203,0x04050607,0x08090a0b,0x0c0d0e0f	# pbswap
++	.long	0x00010203,0x04050607,0x08090a0b,0x0c0d0e0f	# pbswap
++	.byte	0xf,0xe,0xd,0xc,0xb,0xa,0x9,0x8,0x7,0x6,0x5,0x4,0x3,0x2,0x1,0x0
++	.asciz	"SHA1 multi-block transform for x86_64, CRYPTOGAMS by "
++___
++
++if ($win64) {
++# EXCEPTION_DISPOSITION handler (EXCEPTION_RECORD *rec,ULONG64 frame,
++#		CONTEXT *context,DISPATCHER_CONTEXT *disp)
++$rec="%rcx";
++$frame="%rdx";
++$context="%r8";
++$disp="%r9";
++
++$code.=<<___;
++.extern	__imp_RtlVirtualUnwind
++.type	se_handler,\@abi-omnipotent
++.align	16
++se_handler:
++	push	%rsi
++	push	%rdi
++	push	%rbx
++	push	%rbp
++	push	%r12
++	push	%r13
++	push	%r14
++	push	%r15
++	pushfq
++	sub	\$64,%rsp
++
++	mov	120($context),%rax	# pull context->Rax
++	mov	248($context),%rbx	# pull context->Rip
++
++	mov	8($disp),%rsi		# disp->ImageBase
++	mov	56($disp),%r11		# disp->HandlerData
++
++	mov	0(%r11),%r10d		# HandlerData[0]
++	lea	(%rsi,%r10),%r10	# end of prologue label
++	cmp	%r10,%rbx		# context->Rip<.Lbody
++	jb	.Lin_prologue
++
++	mov	152($context),%rax	# pull context->Rsp
++
++	mov	4(%r11),%r10d		# HandlerData[1]
++	lea	(%rsi,%r10),%r10	# epilogue label
++	cmp	%r10,%rbx		# context->Rip>=.Lepilogue
++	jae	.Lin_prologue
++
++	mov	`16*17`(%rax),%rax	# pull saved stack pointer
++
++	mov	-8(%rax),%rbx
++	mov	-16(%rax),%rbp
++	mov	%rbx,144($context)	# restore context->Rbx
++	mov	%rbp,160($context)	# restore context->Rbp
++
++	lea	-24-10*16(%rax),%rsi
++	lea	512($context),%rdi	# &context.Xmm6
++	mov	\$20,%ecx
++	.long	0xa548f3fc		# cld; rep movsq
++
++.Lin_prologue:
++	mov	8(%rax),%rdi
++	mov	16(%rax),%rsi
++	mov	%rax,152($context)	# restore context->Rsp
++	mov	%rsi,168($context)	# restore context->Rsi
++	mov	%rdi,176($context)	# restore context->Rdi
++
++	mov	40($disp),%rdi		# disp->ContextRecord
++	mov	$context,%rsi		# context
++	mov	\$154,%ecx		# sizeof(CONTEXT)
++	.long	0xa548f3fc		# cld; rep movsq
++
++	mov	$disp,%rsi
++	xor	%rcx,%rcx		# arg1, UNW_FLAG_NHANDLER
++	mov	8(%rsi),%rdx		# arg2, disp->ImageBase
++	mov	0(%rsi),%r8		# arg3, disp->ControlPc
++	mov	16(%rsi),%r9		# arg4, disp->FunctionEntry
++	mov	40(%rsi),%r10		# disp->ContextRecord
++	lea	56(%rsi),%r11		# &disp->HandlerData
++	lea	24(%rsi),%r12		# &disp->EstablisherFrame
++	mov	%r10,32(%rsp)		# arg5
++	mov	%r11,40(%rsp)		# arg6
++	mov	%r12,48(%rsp)		# arg7
++	mov	%rcx,56(%rsp)		# arg8, (NULL)
++	call	*__imp_RtlVirtualUnwind(%rip)
++
++	mov	\$1,%eax		# ExceptionContinueSearch
++	add	\$64,%rsp
++	popfq
++	pop	%r15
++	pop	%r14
++	pop	%r13
++	pop	%r12
++	pop	%rbp
++	pop	%rbx
++	pop	%rdi
++	pop	%rsi
++	ret
++.size	se_handler,.-se_handler
++___
++$code.=<<___ if ($avx>1);
++.type	avx2_handler,\@abi-omnipotent
++.align	16
++avx2_handler:
++	push	%rsi
++	push	%rdi
++	push	%rbx
++	push	%rbp
++	push	%r12
++	push	%r13
++	push	%r14
++	push	%r15
++	pushfq
++	sub	\$64,%rsp
++
++	mov	120($context),%rax	# pull context->Rax
++	mov	248($context),%rbx	# pull context->Rip
++
++	mov	8($disp),%rsi		# disp->ImageBase
++	mov	56($disp),%r11		# disp->HandlerData
++
++	mov	0(%r11),%r10d		# HandlerData[0]
++	lea	(%rsi,%r10),%r10	# end of prologue label
++	cmp	%r10,%rbx		# context->RipRsp
++
++	mov	4(%r11),%r10d		# HandlerData[1]
++	lea	(%rsi,%r10),%r10	# epilogue label
++	cmp	%r10,%rbx		# context->Rip>=epilogue label
++	jae	.Lin_prologue
++
++	mov	`32*17`($context),%rax	# pull saved stack pointer
++
++	mov	-8(%rax),%rbx
++	mov	-16(%rax),%rbp
++	mov	-24(%rax),%r12
++	mov	-32(%rax),%r13
++	mov	-40(%rax),%r14
++	mov	-48(%rax),%r15
++	mov	%rbx,144($context)	# restore context->Rbx
++	mov	%rbp,160($context)	# restore context->Rbp
++	mov	%r12,216($context)	# restore cotnext->R12
++	mov	%r13,224($context)	# restore cotnext->R13
++	mov	%r14,232($context)	# restore cotnext->R14
++	mov	%r15,240($context)	# restore cotnext->R15
++
++	lea	-56-10*16(%rax),%rsi
++	lea	512($context),%rdi	# &context.Xmm6
++	mov	\$20,%ecx
++	.long	0xa548f3fc		# cld; rep movsq
++
++	jmp	.Lin_prologue
++.size	avx2_handler,.-avx2_handler
++___
++$code.=<<___;
++.section	.pdata
++.align	4
++	.rva	.LSEH_begin_sha1_multi_block
++	.rva	.LSEH_end_sha1_multi_block
++	.rva	.LSEH_info_sha1_multi_block
++	.rva	.LSEH_begin_sha1_multi_block_shaext
++	.rva	.LSEH_end_sha1_multi_block_shaext
++	.rva	.LSEH_info_sha1_multi_block_shaext
++___
++$code.=<<___ if ($avx);
++	.rva	.LSEH_begin_sha1_multi_block_avx
++	.rva	.LSEH_end_sha1_multi_block_avx
++	.rva	.LSEH_info_sha1_multi_block_avx
++___
++$code.=<<___ if ($avx>1);
++	.rva	.LSEH_begin_sha1_multi_block_avx2
++	.rva	.LSEH_end_sha1_multi_block_avx2
++	.rva	.LSEH_info_sha1_multi_block_avx2
++___
++$code.=<<___;
++.section	.xdata
++.align	8
++.LSEH_info_sha1_multi_block:
++	.byte	9,0,0,0
++	.rva	se_handler
++	.rva	.Lbody,.Lepilogue			# HandlerData[]
++.LSEH_info_sha1_multi_block_shaext:
++	.byte	9,0,0,0
++	.rva	se_handler
++	.rva	.Lbody_shaext,.Lepilogue_shaext	# HandlerData[]
++___
++$code.=<<___ if ($avx);
++.LSEH_info_sha1_multi_block_avx:
++	.byte	9,0,0,0
++	.rva	se_handler
++	.rva	.Lbody_avx,.Lepilogue_avx		# HandlerData[]
++___
++$code.=<<___ if ($avx>1);
++.LSEH_info_sha1_multi_block_avx2:
++	.byte	9,0,0,0
++	.rva	avx2_handler
++	.rva	.Lbody_avx2,.Lepilogue_avx2		# HandlerData[]
++___
++}
++####################################################################
++
++sub rex {
++  local *opcode=shift;
++  my ($dst,$src)=@_;
++  my $rex=0;
++
++    $rex|=0x04			if ($dst>=8);
++    $rex|=0x01			if ($src>=8);
++    unshift @opcode,$rex|0x40	if ($rex);
++}
++
++sub sha1rnds4 {
++    if (@_[0] =~ /\$([x0-9a-f]+),\s*%xmm([0-9]+),\s*%xmm([0-9]+)/) {
++      my @opcode=(0x0f,0x3a,0xcc);
++	rex(\@opcode,$3,$2);
++	push @opcode,0xc0|($2&7)|(($3&7)<<3);		# ModR/M
++	my $c=$1;
++	push @opcode,$c=~/^0/?oct($c):$c;
++	return ".byte\t".join(',',@opcode);
++    } else {
++	return "sha1rnds4\t".@_[0];
++    }
++}
++
++sub sha1op38 {
++    my $instr = shift;
++    my %opcodelet = (
++		"sha1nexte" => 0xc8,
++  		"sha1msg1"  => 0xc9,
++		"sha1msg2"  => 0xca	);
++
++    if (defined($opcodelet{$instr}) && @_[0] =~ /%xmm([0-9]+),\s*%xmm([0-9]+)/) {
++      my @opcode=(0x0f,0x38);
++	rex(\@opcode,$2,$1);
++	push @opcode,$opcodelet{$instr};
++	push @opcode,0xc0|($1&7)|(($2&7)<<3);		# ModR/M
++	return ".byte\t".join(',',@opcode);
++    } else {
++	return $instr."\t".@_[0];
++    }
++}
++
++foreach (split("\n",$code)) {
++	s/\`([^\`]*)\`/eval($1)/ge;
++
++	s/\b(sha1rnds4)\s+(.*)/sha1rnds4($2)/geo		or
++	s/\b(sha1[^\s]*)\s+(.*)/sha1op38($1,$2)/geo		or
++
++	s/\b(vmov[dq])\b(.+)%ymm([0-9]+)/$1$2%xmm$3/go		or
++	s/\b(vmovdqu)\b(.+)%x%ymm([0-9]+)/$1$2%xmm$3/go		or
++	s/\b(vpinsr[qd])\b(.+)%ymm([0-9]+),%ymm([0-9]+)/$1$2%xmm$3,%xmm$4/go	or
++	s/\b(vpextr[qd])\b(.+)%ymm([0-9]+)/$1$2%xmm$3/go	or
++	s/\b(vinserti128)\b(\s+)%ymm/$1$2\$1,%xmm/go		or
++	s/\b(vpbroadcast[qd]\s+)%ymm([0-9]+)/$1%xmm$2/go;
++
++	print $_,"\n";
++}
++
++close STDOUT;
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/sha/asm/sha1-mips.pl b/CryptoPkg/Library/OpensslLib/openssl/crypto/sha/asm/sha1-mips.pl
+new file mode 100644
+index 0000000..882f973
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/sha/asm/sha1-mips.pl
+@@ -0,0 +1,457 @@
++#! /usr/bin/env perl
++# Copyright 2009-2016 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
++# in the file LICENSE in the source distribution or at
++# https://www.openssl.org/source/license.html
++
++
++# ====================================================================
++# Written by Andy Polyakov  for the OpenSSL
++# project. The module is, however, dual licensed under OpenSSL and
++# CRYPTOGAMS licenses depending on where you obtain it. For further
++# details see http://www.openssl.org/~appro/cryptogams/.
++# ====================================================================
++
++# SHA1 block procedure for MIPS.
++
++# Performance improvement is 30% on unaligned input. The "secret" is
++# to deploy lwl/lwr pair to load unaligned input. One could have
++# vectorized Xupdate on MIPSIII/IV, but the goal was to code MIPS32-
++# compatible subroutine. There is room for minor optimization on
++# little-endian platforms...
++
++# September 2012.
++#
++# Add MIPS32r2 code (>25% less instructions).
++
++######################################################################
++# There is a number of MIPS ABI in use, O32 and N32/64 are most
++# widely used. Then there is a new contender: NUBI. It appears that if
++# one picks the latter, it's possible to arrange code in ABI neutral
++# manner. Therefore let's stick to NUBI register layout:
++#
++($zero,$at,$t0,$t1,$t2)=map("\$$_",(0..2,24,25));
++($a0,$a1,$a2,$a3,$a4,$a5,$a6,$a7)=map("\$$_",(4..11));
++($s0,$s1,$s2,$s3,$s4,$s5,$s6,$s7,$s8,$s9,$s10,$s11)=map("\$$_",(12..23));
++($gp,$tp,$sp,$fp,$ra)=map("\$$_",(3,28..31));
++#
++# The return value is placed in $a0. Following coding rules facilitate
++# interoperability:
++#
++# - never ever touch $tp, "thread pointer", former $gp;
++# - copy return value to $t0, former $v0 [or to $a0 if you're adapting
++#   old code];
++# - on O32 populate $a4-$a7 with 'lw $aN,4*N($sp)' if necessary;
++#
++# For reference here is register layout for N32/64 MIPS ABIs:
++#
++# ($zero,$at,$v0,$v1)=map("\$$_",(0..3));
++# ($a0,$a1,$a2,$a3,$a4,$a5,$a6,$a7)=map("\$$_",(4..11));
++# ($t0,$t1,$t2,$t3,$t8,$t9)=map("\$$_",(12..15,24,25));
++# ($s0,$s1,$s2,$s3,$s4,$s5,$s6,$s7)=map("\$$_",(16..23));
++# ($gp,$sp,$fp,$ra)=map("\$$_",(28..31));
++#
++$flavour = shift || "o32"; # supported flavours are o32,n32,64,nubi32,nubi64
++
++if ($flavour =~ /64|n32/i) {
++	$PTR_ADD="dadd";	# incidentally works even on n32
++	$PTR_SUB="dsub";	# incidentally works even on n32
++	$REG_S="sd";
++	$REG_L="ld";
++	$PTR_SLL="dsll";	# incidentally works even on n32
++	$SZREG=8;
++} else {
++	$PTR_ADD="add";
++	$PTR_SUB="sub";
++	$REG_S="sw";
++	$REG_L="lw";
++	$PTR_SLL="sll";
++	$SZREG=4;
++}
++#
++# 
++#
++######################################################################
++
++$big_endian=(`echo MIPSEL | $ENV{CC} -E -`=~/MIPSEL/)?1:0 if ($ENV{CC});
++
++for (@ARGV) {	$output=$_ if (/\w[\w\-]*\.\w+$/);   }
++open STDOUT,">$output";
++
++if (!defined($big_endian))
++            {   $big_endian=(unpack('L',pack('N',1))==1);   }
++
++# offsets of the Most and Least Significant Bytes
++$MSB=$big_endian?0:3;
++$LSB=3&~$MSB;
++
++@X=map("\$$_",(8..23));	# a4-a7,s0-s11
++
++$ctx=$a0;
++$inp=$a1;
++$num=$a2;
++$A="\$1";
++$B="\$2";
++$C="\$3";
++$D="\$7";
++$E="\$24";	@V=($A,$B,$C,$D,$E);
++$t0="\$25";
++$t1=$num;	# $num is offloaded to stack
++$t2="\$30";	# fp
++$K="\$31";	# ra
++
++sub BODY_00_14 {
++my ($i,$a,$b,$c,$d,$e)=@_;
++my $j=$i+1;
++$code.=<<___	if (!$big_endian);
++#if defined(_MIPS_ARCH_MIPS32R2) || defined(_MIPS_ARCH_MIPS64R2)
++	wsbh	@X[$i],@X[$i]	# byte swap($i)
++	rotr	@X[$i],@X[$i],16
++#else
++	srl	$t0,@X[$i],24	# byte swap($i)
++	srl	$t1,@X[$i],8
++	andi	$t2,@X[$i],0xFF00
++	sll	@X[$i],@X[$i],24
++	andi	$t1,0xFF00
++	sll	$t2,$t2,8
++	or	@X[$i],$t0
++	or	$t1,$t2
++	or	@X[$i],$t1
++#endif
++___
++$code.=<<___;
++#if defined(_MIPS_ARCH_MIPS32R2) || defined(_MIPS_ARCH_MIPS64R2)
++	addu	$e,$K		# $i
++	xor	$t0,$c,$d
++	rotr	$t1,$a,27
++	 lwl	@X[$j],$j*4+$MSB($inp)
++	and	$t0,$b
++	addu	$e,$t1
++	 lwr	@X[$j],$j*4+$LSB($inp)
++	xor	$t0,$d
++	addu	$e,@X[$i]
++	rotr	$b,$b,2
++	addu	$e,$t0
++#else
++	 lwl	@X[$j],$j*4+$MSB($inp)
++	sll	$t0,$a,5	# $i
++	addu	$e,$K
++	 lwr	@X[$j],$j*4+$LSB($inp)
++	srl	$t1,$a,27
++	addu	$e,$t0
++	xor	$t0,$c,$d
++	addu	$e,$t1
++	sll	$t2,$b,30
++	and	$t0,$b
++	srl	$b,$b,2
++	xor	$t0,$d
++	addu	$e,@X[$i]
++	or	$b,$t2
++	addu	$e,$t0
++#endif
++___
++}
++
++sub BODY_15_19 {
++my ($i,$a,$b,$c,$d,$e)=@_;
++my $j=$i+1;
++
++$code.=<<___	if (!$big_endian && $i==15);
++#if defined(_MIPS_ARCH_MIPS32R2) || defined(_MIPS_ARCH_MIPS64R2)
++	wsbh	@X[$i],@X[$i]	# byte swap($i)
++	rotr	@X[$i],@X[$i],16
++#else
++	srl	$t0,@X[$i],24	# byte swap($i)
++	srl	$t1,@X[$i],8
++	andi	$t2,@X[$i],0xFF00
++	sll	@X[$i],@X[$i],24
++	andi	$t1,0xFF00
++	sll	$t2,$t2,8
++	or	@X[$i],$t0
++	or	@X[$i],$t1
++	or	@X[$i],$t2
++#endif
++___
++$code.=<<___;
++#if defined(_MIPS_ARCH_MIPS32R2) || defined(_MIPS_ARCH_MIPS64R2)
++	addu	$e,$K		# $i
++	 xor	@X[$j%16],@X[($j+2)%16]
++	xor	$t0,$c,$d
++	rotr	$t1,$a,27
++	 xor	@X[$j%16],@X[($j+8)%16]
++	and	$t0,$b
++	addu	$e,$t1
++	 xor	@X[$j%16],@X[($j+13)%16]
++	xor	$t0,$d
++	addu	$e,@X[$i%16]
++	 rotr	@X[$j%16],@X[$j%16],31
++	rotr	$b,$b,2
++	addu	$e,$t0
++#else
++	 xor	@X[$j%16],@X[($j+2)%16]
++	sll	$t0,$a,5	# $i
++	addu	$e,$K
++	srl	$t1,$a,27
++	addu	$e,$t0
++	 xor	@X[$j%16],@X[($j+8)%16]
++	xor	$t0,$c,$d
++	addu	$e,$t1
++	 xor	@X[$j%16],@X[($j+13)%16]
++	sll	$t2,$b,30
++	and	$t0,$b
++	 srl	$t1,@X[$j%16],31
++	 addu	@X[$j%16],@X[$j%16]
++	srl	$b,$b,2
++	xor	$t0,$d
++	 or	@X[$j%16],$t1
++	addu	$e,@X[$i%16]
++	or	$b,$t2
++	addu	$e,$t0
++#endif
++___
++}
++
++sub BODY_20_39 {
++my ($i,$a,$b,$c,$d,$e)=@_;
++my $j=$i+1;
++$code.=<<___ if ($i<79);
++#if defined(_MIPS_ARCH_MIPS32R2) || defined(_MIPS_ARCH_MIPS64R2)
++	 xor	@X[$j%16],@X[($j+2)%16]
++	addu	$e,$K		# $i
++	rotr	$t1,$a,27
++	 xor	@X[$j%16],@X[($j+8)%16]
++	xor	$t0,$c,$d
++	addu	$e,$t1
++	 xor	@X[$j%16],@X[($j+13)%16]
++	xor	$t0,$b
++	addu	$e,@X[$i%16]
++	 rotr	@X[$j%16],@X[$j%16],31
++	rotr	$b,$b,2
++	addu	$e,$t0
++#else
++	 xor	@X[$j%16],@X[($j+2)%16]
++	sll	$t0,$a,5	# $i
++	addu	$e,$K
++	srl	$t1,$a,27
++	addu	$e,$t0
++	 xor	@X[$j%16],@X[($j+8)%16]
++	xor	$t0,$c,$d
++	addu	$e,$t1
++	 xor	@X[$j%16],@X[($j+13)%16]
++	sll	$t2,$b,30
++	xor	$t0,$b
++	 srl	$t1,@X[$j%16],31
++	 addu	@X[$j%16],@X[$j%16]
++	srl	$b,$b,2
++	addu	$e,@X[$i%16]
++	 or	@X[$j%16],$t1
++	or	$b,$t2
++	addu	$e,$t0
++#endif
++___
++$code.=<<___ if ($i==79);
++#if defined(_MIPS_ARCH_MIPS32R2) || defined(_MIPS_ARCH_MIPS64R2)
++	 lw	@X[0],0($ctx)
++	addu	$e,$K		# $i
++	 lw	@X[1],4($ctx)
++	rotr	$t1,$a,27
++	 lw	@X[2],8($ctx)
++	xor	$t0,$c,$d
++	addu	$e,$t1
++	 lw	@X[3],12($ctx)
++	xor	$t0,$b
++	addu	$e,@X[$i%16]
++	 lw	@X[4],16($ctx)
++	rotr	$b,$b,2
++	addu	$e,$t0
++#else
++	 lw	@X[0],0($ctx)
++	sll	$t0,$a,5	# $i
++	addu	$e,$K
++	 lw	@X[1],4($ctx)
++	srl	$t1,$a,27
++	addu	$e,$t0
++	 lw	@X[2],8($ctx)
++	xor	$t0,$c,$d
++	addu	$e,$t1
++	 lw	@X[3],12($ctx)
++	sll	$t2,$b,30
++	xor	$t0,$b
++	 lw	@X[4],16($ctx)
++	srl	$b,$b,2
++	addu	$e,@X[$i%16]
++	or	$b,$t2
++	addu	$e,$t0
++#endif
++___
++}
++
++sub BODY_40_59 {
++my ($i,$a,$b,$c,$d,$e)=@_;
++my $j=$i+1;
++$code.=<<___ if ($i<79);
++#if defined(_MIPS_ARCH_MIPS32R2) || defined(_MIPS_ARCH_MIPS64R2)
++	addu	$e,$K		# $i
++	and	$t0,$c,$d
++	 xor	@X[$j%16],@X[($j+2)%16]
++	rotr	$t1,$a,27
++	addu	$e,$t0
++	 xor	@X[$j%16],@X[($j+8)%16]
++	xor	$t0,$c,$d
++	addu	$e,$t1
++	 xor	@X[$j%16],@X[($j+13)%16]
++	and	$t0,$b
++	addu	$e,@X[$i%16]
++	 rotr	@X[$j%16],@X[$j%16],31
++	rotr	$b,$b,2
++	addu	$e,$t0
++#else
++	 xor	@X[$j%16],@X[($j+2)%16]
++	sll	$t0,$a,5	# $i
++	addu	$e,$K
++	srl	$t1,$a,27
++	addu	$e,$t0
++	 xor	@X[$j%16],@X[($j+8)%16]
++	and	$t0,$c,$d
++	addu	$e,$t1
++	 xor	@X[$j%16],@X[($j+13)%16]
++	sll	$t2,$b,30
++	addu	$e,$t0
++	 srl	$t1,@X[$j%16],31
++	xor	$t0,$c,$d
++	 addu	@X[$j%16],@X[$j%16]
++	and	$t0,$b
++	srl	$b,$b,2
++	 or	@X[$j%16],$t1
++	addu	$e,@X[$i%16]
++	or	$b,$t2
++	addu	$e,$t0
++#endif
++___
++}
++
++$FRAMESIZE=16;	# large enough to accommodate NUBI saved registers
++$SAVED_REGS_MASK = ($flavour =~ /nubi/i) ? "0xc0fff008" : "0xc0ff0000";
++
++$code=<<___;
++#ifdef OPENSSL_FIPSCANISTER
++# include 
++#endif
++
++#if defined(__mips_smartmips) && !defined(_MIPS_ARCH_MIPS32R2)
++#define _MIPS_ARCH_MIPS32R2
++#endif
++
++.text
++
++.set	noat
++.set	noreorder
++.align	5
++.globl	sha1_block_data_order
++.ent	sha1_block_data_order
++sha1_block_data_order:
++	.frame	$sp,$FRAMESIZE*$SZREG,$ra
++	.mask	$SAVED_REGS_MASK,-$SZREG
++	.set	noreorder
++	$PTR_SUB $sp,$FRAMESIZE*$SZREG
++	$REG_S	$ra,($FRAMESIZE-1)*$SZREG($sp)
++	$REG_S	$fp,($FRAMESIZE-2)*$SZREG($sp)
++	$REG_S	$s11,($FRAMESIZE-3)*$SZREG($sp)
++	$REG_S	$s10,($FRAMESIZE-4)*$SZREG($sp)
++	$REG_S	$s9,($FRAMESIZE-5)*$SZREG($sp)
++	$REG_S	$s8,($FRAMESIZE-6)*$SZREG($sp)
++	$REG_S	$s7,($FRAMESIZE-7)*$SZREG($sp)
++	$REG_S	$s6,($FRAMESIZE-8)*$SZREG($sp)
++	$REG_S	$s5,($FRAMESIZE-9)*$SZREG($sp)
++	$REG_S	$s4,($FRAMESIZE-10)*$SZREG($sp)
++___
++$code.=<<___ if ($flavour =~ /nubi/i);	# optimize non-nubi prologue
++	$REG_S	$s3,($FRAMESIZE-11)*$SZREG($sp)
++	$REG_S	$s2,($FRAMESIZE-12)*$SZREG($sp)
++	$REG_S	$s1,($FRAMESIZE-13)*$SZREG($sp)
++	$REG_S	$s0,($FRAMESIZE-14)*$SZREG($sp)
++	$REG_S	$gp,($FRAMESIZE-15)*$SZREG($sp)
++___
++$code.=<<___;
++	$PTR_SLL $num,6
++	$PTR_ADD $num,$inp
++	$REG_S	$num,0($sp)
++	lw	$A,0($ctx)
++	lw	$B,4($ctx)
++	lw	$C,8($ctx)
++	lw	$D,12($ctx)
++	b	.Loop
++	lw	$E,16($ctx)
++.align	4
++.Loop:
++	.set	reorder
++	lwl	@X[0],$MSB($inp)
++	lui	$K,0x5a82
++	lwr	@X[0],$LSB($inp)
++	ori	$K,0x7999	# K_00_19
++___
++for ($i=0;$i<15;$i++)	{ &BODY_00_14($i,@V); unshift(@V,pop(@V)); }
++for (;$i<20;$i++)	{ &BODY_15_19($i,@V); unshift(@V,pop(@V)); }
++$code.=<<___;
++	lui	$K,0x6ed9
++	ori	$K,0xeba1	# K_20_39
++___
++for (;$i<40;$i++)	{ &BODY_20_39($i,@V); unshift(@V,pop(@V)); }
++$code.=<<___;
++	lui	$K,0x8f1b
++	ori	$K,0xbcdc	# K_40_59
++___
++for (;$i<60;$i++)	{ &BODY_40_59($i,@V); unshift(@V,pop(@V)); }
++$code.=<<___;
++	lui	$K,0xca62
++	ori	$K,0xc1d6	# K_60_79
++___
++for (;$i<80;$i++)	{ &BODY_20_39($i,@V); unshift(@V,pop(@V)); }
++$code.=<<___;
++	$PTR_ADD $inp,64
++	$REG_L	$num,0($sp)
++
++	addu	$A,$X[0]
++	addu	$B,$X[1]
++	sw	$A,0($ctx)
++	addu	$C,$X[2]
++	addu	$D,$X[3]
++	sw	$B,4($ctx)
++	addu	$E,$X[4]
++	sw	$C,8($ctx)
++	sw	$D,12($ctx)
++	sw	$E,16($ctx)
++	.set	noreorder
++	bne	$inp,$num,.Loop
++	nop
++
++	.set	noreorder
++	$REG_L	$ra,($FRAMESIZE-1)*$SZREG($sp)
++	$REG_L	$fp,($FRAMESIZE-2)*$SZREG($sp)
++	$REG_L	$s11,($FRAMESIZE-3)*$SZREG($sp)
++	$REG_L	$s10,($FRAMESIZE-4)*$SZREG($sp)
++	$REG_L	$s9,($FRAMESIZE-5)*$SZREG($sp)
++	$REG_L	$s8,($FRAMESIZE-6)*$SZREG($sp)
++	$REG_L	$s7,($FRAMESIZE-7)*$SZREG($sp)
++	$REG_L	$s6,($FRAMESIZE-8)*$SZREG($sp)
++	$REG_L	$s5,($FRAMESIZE-9)*$SZREG($sp)
++	$REG_L	$s4,($FRAMESIZE-10)*$SZREG($sp)
++___
++$code.=<<___ if ($flavour =~ /nubi/i);
++	$REG_L	$s3,($FRAMESIZE-11)*$SZREG($sp)
++	$REG_L	$s2,($FRAMESIZE-12)*$SZREG($sp)
++	$REG_L	$s1,($FRAMESIZE-13)*$SZREG($sp)
++	$REG_L	$s0,($FRAMESIZE-14)*$SZREG($sp)
++	$REG_L	$gp,($FRAMESIZE-15)*$SZREG($sp)
++___
++$code.=<<___;
++	jr	$ra
++	$PTR_ADD $sp,$FRAMESIZE*$SZREG
++.end	sha1_block_data_order
++.rdata
++.asciiz	"SHA1 for MIPS, CRYPTOGAMS by "
++___
++print $code;
++close STDOUT;
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/sha/asm/sha1-parisc.pl b/CryptoPkg/Library/OpensslLib/openssl/crypto/sha/asm/sha1-parisc.pl
+new file mode 100644
+index 0000000..a85d126
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/sha/asm/sha1-parisc.pl
+@@ -0,0 +1,267 @@
++#! /usr/bin/env perl
++# Copyright 2009-2016 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
++# in the file LICENSE in the source distribution or at
++# https://www.openssl.org/source/license.html
++
++
++# ====================================================================
++# Written by Andy Polyakov  for the OpenSSL
++# project. The module is, however, dual licensed under OpenSSL and
++# CRYPTOGAMS licenses depending on where you obtain it. For further
++# details see http://www.openssl.org/~appro/cryptogams/.
++# ====================================================================
++
++# SHA1 block procedure for PA-RISC.
++
++# June 2009.
++#
++# On PA-7100LC performance is >30% better than gcc 3.2 generated code
++# for aligned input and >50% better for unaligned. Compared to vendor
++# compiler on PA-8600 it's almost 60% faster in 64-bit build and just
++# few percent faster in 32-bit one (this for aligned input, data for
++# unaligned input is not available).
++#
++# Special thanks to polarhome.com for providing HP-UX account.
++
++$flavour = shift;
++$output = shift;
++open STDOUT,">$output";
++
++if ($flavour =~ /64/) {
++	$LEVEL		="2.0W";
++	$SIZE_T		=8;
++	$FRAME_MARKER	=80;
++	$SAVED_RP	=16;
++	$PUSH		="std";
++	$PUSHMA		="std,ma";
++	$POP		="ldd";
++	$POPMB		="ldd,mb";
++} else {
++	$LEVEL		="1.0";
++	$SIZE_T		=4;
++	$FRAME_MARKER	=48;
++	$SAVED_RP	=20;
++	$PUSH		="stw";
++	$PUSHMA		="stwm";
++	$POP		="ldw";
++	$POPMB		="ldwm";
++}
++
++$FRAME=14*$SIZE_T+$FRAME_MARKER;# 14 saved regs + frame marker
++				#                 [+ argument transfer]
++$ctx="%r26";		# arg0
++$inp="%r25";		# arg1
++$num="%r24";		# arg2
++
++$t0="%r28";
++$t1="%r29";
++$K="%r31";
++
++@X=("%r1", "%r2", "%r3", "%r4", "%r5", "%r6", "%r7", "%r8",
++    "%r9", "%r10","%r11","%r12","%r13","%r14","%r15","%r16",$t0);
++
++@V=($A,$B,$C,$D,$E)=("%r19","%r20","%r21","%r22","%r23");
++
++sub BODY_00_19 {
++my ($i,$a,$b,$c,$d,$e)=@_;
++my $j=$i+1;
++$code.=<<___ if ($i<15);
++	addl	$K,$e,$e	; $i
++	shd	$a,$a,27,$t1
++	addl	@X[$i],$e,$e
++	and	$c,$b,$t0
++	addl	$t1,$e,$e
++	andcm	$d,$b,$t1
++	shd	$b,$b,2,$b
++	or	$t1,$t0,$t0
++	addl	$t0,$e,$e
++___
++$code.=<<___ if ($i>=15);	# with forward Xupdate
++	addl	$K,$e,$e	; $i
++	shd	$a,$a,27,$t1
++	xor	@X[($j+2)%16],@X[$j%16],@X[$j%16]
++	addl	@X[$i%16],$e,$e
++	and	$c,$b,$t0
++	xor	@X[($j+8)%16],@X[$j%16],@X[$j%16]
++	addl	$t1,$e,$e
++	andcm	$d,$b,$t1
++	shd	$b,$b,2,$b
++	or	$t1,$t0,$t0
++	xor	@X[($j+13)%16],@X[$j%16],@X[$j%16]
++	add	$t0,$e,$e
++	shd	@X[$j%16],@X[$j%16],31,@X[$j%16]
++___
++}
++
++sub BODY_20_39 {
++my ($i,$a,$b,$c,$d,$e)=@_;
++my $j=$i+1;
++$code.=<<___ if ($i<79);
++	xor	@X[($j+2)%16],@X[$j%16],@X[$j%16]	; $i
++	addl	$K,$e,$e
++	shd	$a,$a,27,$t1
++	xor	@X[($j+8)%16],@X[$j%16],@X[$j%16]
++	addl	@X[$i%16],$e,$e
++	xor	$b,$c,$t0
++	xor	@X[($j+13)%16],@X[$j%16],@X[$j%16]
++	addl	$t1,$e,$e
++	shd	$b,$b,2,$b
++	xor	$d,$t0,$t0
++	shd	@X[$j%16],@X[$j%16],31,@X[$j%16]
++	addl	$t0,$e,$e
++___
++$code.=<<___ if ($i==79);	# with context load
++	ldw	0($ctx),@X[0]	; $i
++	addl	$K,$e,$e
++	shd	$a,$a,27,$t1
++	ldw	4($ctx),@X[1]
++	addl	@X[$i%16],$e,$e
++	xor	$b,$c,$t0
++	ldw	8($ctx),@X[2]
++	addl	$t1,$e,$e
++	shd	$b,$b,2,$b
++	xor	$d,$t0,$t0
++	ldw	12($ctx),@X[3]
++	addl	$t0,$e,$e
++	ldw	16($ctx),@X[4]
++___
++}
++
++sub BODY_40_59 {
++my ($i,$a,$b,$c,$d,$e)=@_;
++my $j=$i+1;
++$code.=<<___;
++	shd	$a,$a,27,$t1	; $i
++	addl	$K,$e,$e
++	xor	@X[($j+2)%16],@X[$j%16],@X[$j%16]
++	xor	$d,$c,$t0
++	addl	@X[$i%16],$e,$e
++	xor	@X[($j+8)%16],@X[$j%16],@X[$j%16]
++	and	$b,$t0,$t0
++	addl	$t1,$e,$e
++	shd	$b,$b,2,$b
++	xor	@X[($j+13)%16],@X[$j%16],@X[$j%16]
++	addl	$t0,$e,$e
++	and	$d,$c,$t1
++	shd	@X[$j%16],@X[$j%16],31,@X[$j%16]
++	addl	$t1,$e,$e
++___
++}
++
++$code=<<___;
++	.LEVEL	$LEVEL
++	.SPACE	\$TEXT\$
++	.SUBSPA	\$CODE\$,QUAD=0,ALIGN=8,ACCESS=0x2C,CODE_ONLY
++
++	.EXPORT	sha1_block_data_order,ENTRY,ARGW0=GR,ARGW1=GR,ARGW2=GR
++sha1_block_data_order
++	.PROC
++	.CALLINFO	FRAME=`$FRAME-14*$SIZE_T`,NO_CALLS,SAVE_RP,ENTRY_GR=16
++	.ENTRY
++	$PUSH	%r2,-$SAVED_RP(%sp)	; standard prologue
++	$PUSHMA	%r3,$FRAME(%sp)
++	$PUSH	%r4,`-$FRAME+1*$SIZE_T`(%sp)
++	$PUSH	%r5,`-$FRAME+2*$SIZE_T`(%sp)
++	$PUSH	%r6,`-$FRAME+3*$SIZE_T`(%sp)
++	$PUSH	%r7,`-$FRAME+4*$SIZE_T`(%sp)
++	$PUSH	%r8,`-$FRAME+5*$SIZE_T`(%sp)
++	$PUSH	%r9,`-$FRAME+6*$SIZE_T`(%sp)
++	$PUSH	%r10,`-$FRAME+7*$SIZE_T`(%sp)
++	$PUSH	%r11,`-$FRAME+8*$SIZE_T`(%sp)
++	$PUSH	%r12,`-$FRAME+9*$SIZE_T`(%sp)
++	$PUSH	%r13,`-$FRAME+10*$SIZE_T`(%sp)
++	$PUSH	%r14,`-$FRAME+11*$SIZE_T`(%sp)
++	$PUSH	%r15,`-$FRAME+12*$SIZE_T`(%sp)
++	$PUSH	%r16,`-$FRAME+13*$SIZE_T`(%sp)
++
++	ldw	0($ctx),$A
++	ldw	4($ctx),$B
++	ldw	8($ctx),$C
++	ldw	12($ctx),$D
++	ldw	16($ctx),$E
++
++	extru	$inp,31,2,$t0		; t0=inp&3;
++	sh3addl	$t0,%r0,$t0		; t0*=8;
++	subi	32,$t0,$t0		; t0=32-t0;
++	mtctl	$t0,%cr11		; %sar=t0;
++
++L\$oop
++	ldi	3,$t0
++	andcm	$inp,$t0,$t0		; 64-bit neutral
++___
++	for ($i=0;$i<15;$i++) {		# load input block
++	$code.="\tldw	`4*$i`($t0),@X[$i]\n";		}
++$code.=<<___;
++	cmpb,*=	$inp,$t0,L\$aligned
++	ldw	60($t0),@X[15]
++	ldw	64($t0),@X[16]
++___
++	for ($i=0;$i<16;$i++) {		# align input
++	$code.="\tvshd	@X[$i],@X[$i+1],@X[$i]\n";	}
++$code.=<<___;
++L\$aligned
++	ldil	L'0x5a827000,$K		; K_00_19
++	ldo	0x999($K),$K
++___
++for ($i=0;$i<20;$i++)   { &BODY_00_19($i,@V); unshift(@V,pop(@V)); }
++$code.=<<___;
++	ldil	L'0x6ed9e000,$K		; K_20_39
++	ldo	0xba1($K),$K
++___
++
++for (;$i<40;$i++)       { &BODY_20_39($i,@V); unshift(@V,pop(@V)); }
++$code.=<<___;
++	ldil	L'0x8f1bb000,$K		; K_40_59
++	ldo	0xcdc($K),$K
++___
++
++for (;$i<60;$i++)       { &BODY_40_59($i,@V); unshift(@V,pop(@V)); }
++$code.=<<___;
++	ldil	L'0xca62c000,$K		; K_60_79
++	ldo	0x1d6($K),$K
++___
++for (;$i<80;$i++)       { &BODY_20_39($i,@V); unshift(@V,pop(@V)); }
++
++$code.=<<___;
++	addl	@X[0],$A,$A
++	addl	@X[1],$B,$B
++	addl	@X[2],$C,$C
++	addl	@X[3],$D,$D
++	addl	@X[4],$E,$E
++	stw	$A,0($ctx)
++	stw	$B,4($ctx)
++	stw	$C,8($ctx)
++	stw	$D,12($ctx)
++	stw	$E,16($ctx)
++	addib,*<> -1,$num,L\$oop
++	ldo	64($inp),$inp
++
++	$POP	`-$FRAME-$SAVED_RP`(%sp),%r2	; standard epilogue
++	$POP	`-$FRAME+1*$SIZE_T`(%sp),%r4
++	$POP	`-$FRAME+2*$SIZE_T`(%sp),%r5
++	$POP	`-$FRAME+3*$SIZE_T`(%sp),%r6
++	$POP	`-$FRAME+4*$SIZE_T`(%sp),%r7
++	$POP	`-$FRAME+5*$SIZE_T`(%sp),%r8
++	$POP	`-$FRAME+6*$SIZE_T`(%sp),%r9
++	$POP	`-$FRAME+7*$SIZE_T`(%sp),%r10
++	$POP	`-$FRAME+8*$SIZE_T`(%sp),%r11
++	$POP	`-$FRAME+9*$SIZE_T`(%sp),%r12
++	$POP	`-$FRAME+10*$SIZE_T`(%sp),%r13
++	$POP	`-$FRAME+11*$SIZE_T`(%sp),%r14
++	$POP	`-$FRAME+12*$SIZE_T`(%sp),%r15
++	$POP	`-$FRAME+13*$SIZE_T`(%sp),%r16
++	bv	(%r2)
++	.EXIT
++	$POPMB	-$FRAME(%sp),%r3
++	.PROCEND
++	.STRINGZ "SHA1 block transform for PA-RISC, CRYPTOGAMS by "
++___
++
++$code =~ s/\`([^\`]*)\`/eval $1/gem;
++$code =~ s/,\*/,/gm		if ($SIZE_T==4);
++$code =~ s/\bbv\b/bve/gm	if ($SIZE_T==8);
++print $code;
++close STDOUT;
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/sha/asm/sha1-ppc.pl b/CryptoPkg/Library/OpensslLib/openssl/crypto/sha/asm/sha1-ppc.pl
+new file mode 100755
+index 0000000..add5a9e
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/sha/asm/sha1-ppc.pl
+@@ -0,0 +1,351 @@
++#! /usr/bin/env perl
++# Copyright 2006-2016 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
++# in the file LICENSE in the source distribution or at
++# https://www.openssl.org/source/license.html
++
++
++# ====================================================================
++# Written by Andy Polyakov  for the OpenSSL
++# project. The module is, however, dual licensed under OpenSSL and
++# CRYPTOGAMS licenses depending on where you obtain it. For further
++# details see http://www.openssl.org/~appro/cryptogams/.
++# ====================================================================
++
++# I let hardware handle unaligned input(*), except on page boundaries
++# (see below for details). Otherwise straightforward implementation
++# with X vector in register bank.
++#
++# (*) this means that this module is inappropriate for PPC403? Does
++#     anybody know if pre-POWER3 can sustain unaligned load?
++
++# 			-m64	-m32
++# ----------------------------------
++# PPC970,gcc-4.0.0	+76%	+59%
++# Power6,xlc-7		+68%	+33%
++
++$flavour = shift;
++
++if ($flavour =~ /64/) {
++	$SIZE_T	=8;
++	$LRSAVE	=2*$SIZE_T;
++	$UCMP	="cmpld";
++	$STU	="stdu";
++	$POP	="ld";
++	$PUSH	="std";
++} elsif ($flavour =~ /32/) {
++	$SIZE_T	=4;
++	$LRSAVE	=$SIZE_T;
++	$UCMP	="cmplw";
++	$STU	="stwu";
++	$POP	="lwz";
++	$PUSH	="stw";
++} else { die "nonsense $flavour"; }
++
++# Define endianness based on flavour
++# i.e.: linux64le
++$LITTLE_ENDIAN = ($flavour=~/le$/) ? $SIZE_T : 0;
++
++$0 =~ m/(.*[\/\\])[^\/\\]+$/; $dir=$1;
++( $xlate="${dir}ppc-xlate.pl" and -f $xlate ) or
++( $xlate="${dir}../../perlasm/ppc-xlate.pl" and -f $xlate) or
++die "can't locate ppc-xlate.pl";
++
++open STDOUT,"| $^X $xlate $flavour ".shift || die "can't call $xlate: $!";
++
++$FRAME=24*$SIZE_T+64;
++$LOCALS=6*$SIZE_T;
++
++$K  ="r0";
++$sp ="r1";
++$toc="r2";
++$ctx="r3";
++$inp="r4";
++$num="r5";
++$t0 ="r15";
++$t1 ="r6";
++
++$A  ="r7";
++$B  ="r8";
++$C  ="r9";
++$D  ="r10";
++$E  ="r11";
++$T  ="r12";
++
++@V=($A,$B,$C,$D,$E,$T);
++@X=("r16","r17","r18","r19","r20","r21","r22","r23",
++    "r24","r25","r26","r27","r28","r29","r30","r31");
++
++sub loadbe {
++my ($dst, $src, $temp_reg) = @_;
++$code.=<<___ if (!$LITTLE_ENDIAN);
++	lwz	$dst,$src
++___
++$code.=<<___ if ($LITTLE_ENDIAN);
++	lwz	$temp_reg,$src
++	rotlwi	$dst,$temp_reg,8
++	rlwimi	$dst,$temp_reg,24,0,7
++	rlwimi	$dst,$temp_reg,24,16,23
++___
++}
++
++sub BODY_00_19 {
++my ($i,$a,$b,$c,$d,$e,$f)=@_;
++my $j=$i+1;
++
++	# Since the last value of $f is discarded, we can use
++	# it as a temp reg to swap byte-order when needed.
++	loadbe("@X[$i]","`$i*4`($inp)",$f) if ($i==0);
++	loadbe("@X[$j]","`$j*4`($inp)",$f) if ($i<15);
++$code.=<<___ if ($i<15);
++	add	$f,$K,$e
++	rotlwi	$e,$a,5
++	add	$f,$f,@X[$i]
++	and	$t0,$c,$b
++	add	$f,$f,$e
++	andc	$t1,$d,$b
++	rotlwi	$b,$b,30
++	or	$t0,$t0,$t1
++	add	$f,$f,$t0
++___
++$code.=<<___ if ($i>=15);
++	add	$f,$K,$e
++	rotlwi	$e,$a,5
++	xor	@X[$j%16],@X[$j%16],@X[($j+2)%16]
++	add	$f,$f,@X[$i%16]
++	and	$t0,$c,$b
++	xor	@X[$j%16],@X[$j%16],@X[($j+8)%16]
++	add	$f,$f,$e
++	andc	$t1,$d,$b
++	rotlwi	$b,$b,30
++	or	$t0,$t0,$t1
++	xor	@X[$j%16],@X[$j%16],@X[($j+13)%16]
++	add	$f,$f,$t0
++	rotlwi	@X[$j%16],@X[$j%16],1
++___
++}
++
++sub BODY_20_39 {
++my ($i,$a,$b,$c,$d,$e,$f)=@_;
++my $j=$i+1;
++$code.=<<___ if ($i<79);
++	add	$f,$K,$e
++	xor	$t0,$b,$d
++	rotlwi	$e,$a,5
++	xor	@X[$j%16],@X[$j%16],@X[($j+2)%16]
++	add	$f,$f,@X[$i%16]
++	xor	$t0,$t0,$c
++	xor	@X[$j%16],@X[$j%16],@X[($j+8)%16]
++	add	$f,$f,$t0
++	rotlwi	$b,$b,30
++	xor	@X[$j%16],@X[$j%16],@X[($j+13)%16]
++	add	$f,$f,$e
++	rotlwi	@X[$j%16],@X[$j%16],1
++___
++$code.=<<___ if ($i==79);
++	add	$f,$K,$e
++	xor	$t0,$b,$d
++	rotlwi	$e,$a,5
++	lwz	r16,0($ctx)
++	add	$f,$f,@X[$i%16]
++	xor	$t0,$t0,$c
++	lwz	r17,4($ctx)
++	add	$f,$f,$t0
++	rotlwi	$b,$b,30
++	lwz	r18,8($ctx)
++	lwz	r19,12($ctx)
++	add	$f,$f,$e
++	lwz	r20,16($ctx)
++___
++}
++
++sub BODY_40_59 {
++my ($i,$a,$b,$c,$d,$e,$f)=@_;
++my $j=$i+1;
++$code.=<<___;
++	add	$f,$K,$e
++	rotlwi	$e,$a,5
++	xor	@X[$j%16],@X[$j%16],@X[($j+2)%16]
++	add	$f,$f,@X[$i%16]
++	and	$t0,$b,$c
++	xor	@X[$j%16],@X[$j%16],@X[($j+8)%16]
++	add	$f,$f,$e
++	or	$t1,$b,$c
++	rotlwi	$b,$b,30
++	xor	@X[$j%16],@X[$j%16],@X[($j+13)%16]
++	and	$t1,$t1,$d
++	or	$t0,$t0,$t1
++	rotlwi	@X[$j%16],@X[$j%16],1
++	add	$f,$f,$t0
++___
++}
++
++$code=<<___;
++.machine	"any"
++.text
++
++.globl	.sha1_block_data_order
++.align	4
++.sha1_block_data_order:
++	$STU	$sp,-$FRAME($sp)
++	mflr	r0
++	$PUSH	r15,`$FRAME-$SIZE_T*17`($sp)
++	$PUSH	r16,`$FRAME-$SIZE_T*16`($sp)
++	$PUSH	r17,`$FRAME-$SIZE_T*15`($sp)
++	$PUSH	r18,`$FRAME-$SIZE_T*14`($sp)
++	$PUSH	r19,`$FRAME-$SIZE_T*13`($sp)
++	$PUSH	r20,`$FRAME-$SIZE_T*12`($sp)
++	$PUSH	r21,`$FRAME-$SIZE_T*11`($sp)
++	$PUSH	r22,`$FRAME-$SIZE_T*10`($sp)
++	$PUSH	r23,`$FRAME-$SIZE_T*9`($sp)
++	$PUSH	r24,`$FRAME-$SIZE_T*8`($sp)
++	$PUSH	r25,`$FRAME-$SIZE_T*7`($sp)
++	$PUSH	r26,`$FRAME-$SIZE_T*6`($sp)
++	$PUSH	r27,`$FRAME-$SIZE_T*5`($sp)
++	$PUSH	r28,`$FRAME-$SIZE_T*4`($sp)
++	$PUSH	r29,`$FRAME-$SIZE_T*3`($sp)
++	$PUSH	r30,`$FRAME-$SIZE_T*2`($sp)
++	$PUSH	r31,`$FRAME-$SIZE_T*1`($sp)
++	$PUSH	r0,`$FRAME+$LRSAVE`($sp)
++	lwz	$A,0($ctx)
++	lwz	$B,4($ctx)
++	lwz	$C,8($ctx)
++	lwz	$D,12($ctx)
++	lwz	$E,16($ctx)
++	andi.	r0,$inp,3
++	bne	Lunaligned
++Laligned:
++	mtctr	$num
++	bl	Lsha1_block_private
++	b	Ldone
++
++; PowerPC specification allows an implementation to be ill-behaved
++; upon unaligned access which crosses page boundary. "Better safe
++; than sorry" principle makes me treat it specially. But I don't
++; look for particular offending word, but rather for 64-byte input
++; block which crosses the boundary. Once found that block is aligned
++; and hashed separately...
++.align	4
++Lunaligned:
++	subfic	$t1,$inp,4096
++	andi.	$t1,$t1,4095	; distance to closest page boundary
++	srwi.	$t1,$t1,6	; t1/=64
++	beq	Lcross_page
++	$UCMP	$num,$t1
++	ble	Laligned	; didn't cross the page boundary
++	mtctr	$t1
++	subfc	$num,$t1,$num
++	bl	Lsha1_block_private
++Lcross_page:
++	li	$t1,16
++	mtctr	$t1
++	addi	r20,$sp,$LOCALS	; spot within the frame
++Lmemcpy:
++	lbz	r16,0($inp)
++	lbz	r17,1($inp)
++	lbz	r18,2($inp)
++	lbz	r19,3($inp)
++	addi	$inp,$inp,4
++	stb	r16,0(r20)
++	stb	r17,1(r20)
++	stb	r18,2(r20)
++	stb	r19,3(r20)
++	addi	r20,r20,4
++	bdnz	Lmemcpy
++
++	$PUSH	$inp,`$FRAME-$SIZE_T*18`($sp)
++	li	$t1,1
++	addi	$inp,$sp,$LOCALS
++	mtctr	$t1
++	bl	Lsha1_block_private
++	$POP	$inp,`$FRAME-$SIZE_T*18`($sp)
++	addic.	$num,$num,-1
++	bne	Lunaligned
++
++Ldone:
++	$POP	r0,`$FRAME+$LRSAVE`($sp)
++	$POP	r15,`$FRAME-$SIZE_T*17`($sp)
++	$POP	r16,`$FRAME-$SIZE_T*16`($sp)
++	$POP	r17,`$FRAME-$SIZE_T*15`($sp)
++	$POP	r18,`$FRAME-$SIZE_T*14`($sp)
++	$POP	r19,`$FRAME-$SIZE_T*13`($sp)
++	$POP	r20,`$FRAME-$SIZE_T*12`($sp)
++	$POP	r21,`$FRAME-$SIZE_T*11`($sp)
++	$POP	r22,`$FRAME-$SIZE_T*10`($sp)
++	$POP	r23,`$FRAME-$SIZE_T*9`($sp)
++	$POP	r24,`$FRAME-$SIZE_T*8`($sp)
++	$POP	r25,`$FRAME-$SIZE_T*7`($sp)
++	$POP	r26,`$FRAME-$SIZE_T*6`($sp)
++	$POP	r27,`$FRAME-$SIZE_T*5`($sp)
++	$POP	r28,`$FRAME-$SIZE_T*4`($sp)
++	$POP	r29,`$FRAME-$SIZE_T*3`($sp)
++	$POP	r30,`$FRAME-$SIZE_T*2`($sp)
++	$POP	r31,`$FRAME-$SIZE_T*1`($sp)
++	mtlr	r0
++	addi	$sp,$sp,$FRAME
++	blr
++	.long	0
++	.byte	0,12,4,1,0x80,18,3,0
++	.long	0
++___
++
++# This is private block function, which uses tailored calling
++# interface, namely upon entry SHA_CTX is pre-loaded to given
++# registers and counter register contains amount of chunks to
++# digest...
++$code.=<<___;
++.align	4
++Lsha1_block_private:
++___
++$code.=<<___;	# load K_00_19
++	lis	$K,0x5a82
++	ori	$K,$K,0x7999
++___
++for($i=0;$i<20;$i++)	{ &BODY_00_19($i,@V); unshift(@V,pop(@V)); }
++$code.=<<___;	# load K_20_39
++	lis	$K,0x6ed9
++	ori	$K,$K,0xeba1
++___
++for(;$i<40;$i++)	{ &BODY_20_39($i,@V); unshift(@V,pop(@V)); }
++$code.=<<___;	# load K_40_59
++	lis	$K,0x8f1b
++	ori	$K,$K,0xbcdc
++___
++for(;$i<60;$i++)	{ &BODY_40_59($i,@V); unshift(@V,pop(@V)); }
++$code.=<<___;	# load K_60_79
++	lis	$K,0xca62
++	ori	$K,$K,0xc1d6
++___
++for(;$i<80;$i++)	{ &BODY_20_39($i,@V); unshift(@V,pop(@V)); }
++$code.=<<___;
++	add	r16,r16,$E
++	add	r17,r17,$T
++	add	r18,r18,$A
++	add	r19,r19,$B
++	add	r20,r20,$C
++	stw	r16,0($ctx)
++	mr	$A,r16
++	stw	r17,4($ctx)
++	mr	$B,r17
++	stw	r18,8($ctx)
++	mr	$C,r18
++	stw	r19,12($ctx)
++	mr	$D,r19
++	stw	r20,16($ctx)
++	mr	$E,r20
++	addi	$inp,$inp,`16*4`
++	bdnz	Lsha1_block_private
++	blr
++	.long	0
++	.byte	0,12,0x14,0,0,0,0,0
++.size	.sha1_block_data_order,.-.sha1_block_data_order
++___
++$code.=<<___;
++.asciz	"SHA1 block transform for PPC, CRYPTOGAMS by "
++___
++
++$code =~ s/\`([^\`]*)\`/eval $1/gem;
++print $code;
++close STDOUT;
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/sha/asm/sha1-s390x.pl b/CryptoPkg/Library/OpensslLib/openssl/crypto/sha/asm/sha1-s390x.pl
+new file mode 100644
+index 0000000..b19606c
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/sha/asm/sha1-s390x.pl
+@@ -0,0 +1,251 @@
++#! /usr/bin/env perl
++# Copyright 2007-2016 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
++# in the file LICENSE in the source distribution or at
++# https://www.openssl.org/source/license.html
++
++
++# ====================================================================
++# Written by Andy Polyakov  for the OpenSSL
++# project. The module is, however, dual licensed under OpenSSL and
++# CRYPTOGAMS licenses depending on where you obtain it. For further
++# details see http://www.openssl.org/~appro/cryptogams/.
++# ====================================================================
++
++# SHA1 block procedure for s390x.
++
++# April 2007.
++#
++# Performance is >30% better than gcc 3.3 generated code. But the real
++# twist is that SHA1 hardware support is detected and utilized. In
++# which case performance can reach further >4.5x for larger chunks.
++
++# January 2009.
++#
++# Optimize Xupdate for amount of memory references and reschedule
++# instructions to favour dual-issue z10 pipeline. On z10 hardware is
++# "only" ~2.3x faster than software.
++
++# November 2010.
++#
++# Adapt for -m31 build. If kernel supports what's called "highgprs"
++# feature on Linux [see /proc/cpuinfo], it's possible to use 64-bit
++# instructions and achieve "64-bit" performance even in 31-bit legacy
++# application context. The feature is not specific to any particular
++# processor, as long as it's "z-CPU". Latter implies that the code
++# remains z/Architecture specific. On z990 it was measured to perform
++# 23% better than code generated by gcc 4.3.
++
++$kimdfunc=1;	# magic function code for kimd instruction
++
++$flavour = shift;
++
++if ($flavour =~ /3[12]/) {
++	$SIZE_T=4;
++	$g="";
++} else {
++	$SIZE_T=8;
++	$g="g";
++}
++
++while (($output=shift) && ($output!~/\w[\w\-]*\.\w+$/)) {}
++open STDOUT,">$output";
++
++$K_00_39="%r0"; $K=$K_00_39;
++$K_40_79="%r1";
++$ctx="%r2";	$prefetch="%r2";
++$inp="%r3";
++$len="%r4";
++
++$A="%r5";
++$B="%r6";
++$C="%r7";
++$D="%r8";
++$E="%r9";	@V=($A,$B,$C,$D,$E);
++$t0="%r10";
++$t1="%r11";
++@X=("%r12","%r13","%r14");
++$sp="%r15";
++
++$stdframe=16*$SIZE_T+4*8;
++$frame=$stdframe+16*4;
++
++sub Xupdate {
++my $i=shift;
++
++$code.=<<___ if ($i==15);
++	lg	$prefetch,$stdframe($sp)	### Xupdate(16) warm-up
++	lr	$X[0],$X[2]
++___
++return if ($i&1);	# Xupdate is vectorized and executed every 2nd cycle
++$code.=<<___ if ($i<16);
++	lg	$X[0],`$i*4`($inp)	### Xload($i)
++	rllg	$X[1],$X[0],32
++___
++$code.=<<___ if ($i>=16);
++	xgr	$X[0],$prefetch		### Xupdate($i)
++	lg	$prefetch,`$stdframe+4*(($i+2)%16)`($sp)
++	xg	$X[0],`$stdframe+4*(($i+8)%16)`($sp)
++	xgr	$X[0],$prefetch
++	rll	$X[0],$X[0],1
++	rllg	$X[1],$X[0],32
++	rll	$X[1],$X[1],1
++	rllg	$X[0],$X[1],32
++	lr	$X[2],$X[1]		# feedback
++___
++$code.=<<___ if ($i<=70);
++	stg	$X[0],`$stdframe+4*($i%16)`($sp)
++___
++unshift(@X,pop(@X));
++}
++
++sub BODY_00_19 {
++my ($i,$a,$b,$c,$d,$e)=@_;
++my $xi=$X[1];
++
++	&Xupdate($i);
++$code.=<<___;
++	alr	$e,$K		### $i
++	rll	$t1,$a,5
++	lr	$t0,$d
++	xr	$t0,$c
++	alr	$e,$t1
++	nr	$t0,$b
++	alr	$e,$xi
++	xr	$t0,$d
++	rll	$b,$b,30
++	alr	$e,$t0
++___
++}
++
++sub BODY_20_39 {
++my ($i,$a,$b,$c,$d,$e)=@_;
++my $xi=$X[1];
++
++	&Xupdate($i);
++$code.=<<___;
++	alr	$e,$K		### $i
++	rll	$t1,$a,5
++	lr	$t0,$b
++	alr	$e,$t1
++	xr	$t0,$c
++	alr	$e,$xi
++	xr	$t0,$d
++	rll	$b,$b,30
++	alr	$e,$t0
++___
++}
++
++sub BODY_40_59 {
++my ($i,$a,$b,$c,$d,$e)=@_;
++my $xi=$X[1];
++
++	&Xupdate($i);
++$code.=<<___;
++	alr	$e,$K		### $i
++	rll	$t1,$a,5
++	lr	$t0,$b
++	alr	$e,$t1
++	or	$t0,$c
++	lr	$t1,$b
++	nr	$t0,$d
++	nr	$t1,$c
++	alr	$e,$xi
++	or	$t0,$t1
++	rll	$b,$b,30
++	alr	$e,$t0
++___
++}
++
++$code.=<<___;
++.text
++.align	64
++.type	Ktable,\@object
++Ktable: .long	0x5a827999,0x6ed9eba1,0x8f1bbcdc,0xca62c1d6
++	.skip	48	#.long	0,0,0,0,0,0,0,0,0,0,0,0
++.size	Ktable,.-Ktable
++.globl	sha1_block_data_order
++.type	sha1_block_data_order,\@function
++sha1_block_data_order:
++___
++$code.=<<___ if ($kimdfunc);
++	larl	%r1,OPENSSL_s390xcap_P
++	lg	%r0,0(%r1)
++	tmhl	%r0,0x4000	# check for message-security assist
++	jz	.Lsoftware
++	lg	%r0,16(%r1)	# check kimd capabilities
++	tmhh	%r0,`0x8000>>$kimdfunc`
++	jz	.Lsoftware
++	lghi	%r0,$kimdfunc
++	lgr	%r1,$ctx
++	lgr	%r2,$inp
++	sllg	%r3,$len,6
++	.long	0xb93e0002	# kimd %r0,%r2
++	brc	1,.-4		# pay attention to "partial completion"
++	br	%r14
++.align	16
++.Lsoftware:
++___
++$code.=<<___;
++	lghi	%r1,-$frame
++	st${g}	$ctx,`2*$SIZE_T`($sp)
++	stm${g}	%r6,%r15,`6*$SIZE_T`($sp)
++	lgr	%r0,$sp
++	la	$sp,0(%r1,$sp)
++	st${g}	%r0,0($sp)
++
++	larl	$t0,Ktable
++	llgf	$A,0($ctx)
++	llgf	$B,4($ctx)
++	llgf	$C,8($ctx)
++	llgf	$D,12($ctx)
++	llgf	$E,16($ctx)
++
++	lg	$K_00_39,0($t0)
++	lg	$K_40_79,8($t0)
++
++.Lloop:
++	rllg	$K_00_39,$K_00_39,32
++___
++for ($i=0;$i<20;$i++)	{ &BODY_00_19($i,@V); unshift(@V,pop(@V)); }
++$code.=<<___;
++	rllg	$K_00_39,$K_00_39,32
++___
++for (;$i<40;$i++)	{ &BODY_20_39($i,@V); unshift(@V,pop(@V)); }
++$code.=<<___;	$K=$K_40_79;
++	rllg	$K_40_79,$K_40_79,32
++___
++for (;$i<60;$i++)	{ &BODY_40_59($i,@V); unshift(@V,pop(@V)); }
++$code.=<<___;
++	rllg	$K_40_79,$K_40_79,32
++___
++for (;$i<80;$i++)	{ &BODY_20_39($i,@V); unshift(@V,pop(@V)); }
++$code.=<<___;
++
++	l${g}	$ctx,`$frame+2*$SIZE_T`($sp)
++	la	$inp,64($inp)
++	al	$A,0($ctx)
++	al	$B,4($ctx)
++	al	$C,8($ctx)
++	al	$D,12($ctx)
++	al	$E,16($ctx)
++	st	$A,0($ctx)
++	st	$B,4($ctx)
++	st	$C,8($ctx)
++	st	$D,12($ctx)
++	st	$E,16($ctx)
++	brct${g} $len,.Lloop
++
++	lm${g}	%r6,%r15,`$frame+6*$SIZE_T`($sp)
++	br	%r14
++.size	sha1_block_data_order,.-sha1_block_data_order
++.string	"SHA1 block transform for s390x, CRYPTOGAMS by "
++.comm	OPENSSL_s390xcap_P,80,8
++___
++
++$code =~ s/\`([^\`]*)\`/eval $1/gem;
++
++print $code;
++close STDOUT;
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/sha/asm/sha1-sparcv9.pl b/CryptoPkg/Library/OpensslLib/openssl/crypto/sha/asm/sha1-sparcv9.pl
+new file mode 100644
+index 0000000..7437ff4
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/sha/asm/sha1-sparcv9.pl
+@@ -0,0 +1,434 @@
++#! /usr/bin/env perl
++# Copyright 2007-2016 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
++# in the file LICENSE in the source distribution or at
++# https://www.openssl.org/source/license.html
++
++
++# ====================================================================
++# Written by Andy Polyakov  for the OpenSSL
++# project. The module is, however, dual licensed under OpenSSL and
++# CRYPTOGAMS licenses depending on where you obtain it. For further
++# details see http://www.openssl.org/~appro/cryptogams/.
++#
++# Hardware SPARC T4 support by David S. Miller .
++# ====================================================================
++
++# Performance improvement is not really impressive on pre-T1 CPU: +8%
++# over Sun C and +25% over gcc [3.3]. While on T1, a.k.a. Niagara, it
++# turned to be 40% faster than 64-bit code generated by Sun C 5.8 and
++# >2x than 64-bit code generated by gcc 3.4. And there is a gimmick.
++# X[16] vector is packed to 8 64-bit registers and as result nothing
++# is spilled on stack. In addition input data is loaded in compact
++# instruction sequence, thus minimizing the window when the code is
++# subject to [inter-thread] cache-thrashing hazard. The goal is to
++# ensure scalability on UltraSPARC T1, or rather to avoid decay when
++# amount of active threads exceeds the number of physical cores.
++
++# SPARC T4 SHA1 hardware achieves 3.72 cycles per byte, which is 3.1x
++# faster than software. Multi-process benchmark saturates at 11x
++# single-process result on 8-core processor, or ~9GBps per 2.85GHz
++# socket.
++
++$output=pop;
++open STDOUT,">$output";
++
++@X=("%o0","%o1","%o2","%o3","%o4","%o5","%g1","%o7");
++$rot1m="%g2";
++$tmp64="%g3";
++$Xi="%g4";
++$A="%l0";
++$B="%l1";
++$C="%l2";
++$D="%l3";
++$E="%l4";
++@V=($A,$B,$C,$D,$E);
++$K_00_19="%l5";
++$K_20_39="%l6";
++$K_40_59="%l7";
++$K_60_79="%g5";
++@K=($K_00_19,$K_20_39,$K_40_59,$K_60_79);
++
++$ctx="%i0";
++$inp="%i1";
++$len="%i2";
++$tmp0="%i3";
++$tmp1="%i4";
++$tmp2="%i5";
++
++sub BODY_00_15 {
++my ($i,$a,$b,$c,$d,$e)=@_;
++my $xi=($i&1)?@X[($i/2)%8]:$Xi;
++
++$code.=<<___;
++	sll	$a,5,$tmp0		!! $i
++	add	@K[$i/20],$e,$e
++	srl	$a,27,$tmp1
++	add	$tmp0,$e,$e
++	and	$c,$b,$tmp0
++	add	$tmp1,$e,$e
++	sll	$b,30,$tmp2
++	andn	$d,$b,$tmp1
++	srl	$b,2,$b
++	or	$tmp1,$tmp0,$tmp1
++	or	$tmp2,$b,$b
++	add	$xi,$e,$e
++___
++if ($i&1 && $i<15) {
++	$code.=
++	"	srlx	@X[(($i+1)/2)%8],32,$Xi\n";
++}
++$code.=<<___;
++	add	$tmp1,$e,$e
++___
++}
++
++sub Xupdate {
++my ($i,$a,$b,$c,$d,$e)=@_;
++my $j=$i/2;
++
++if ($i&1) {
++$code.=<<___;
++	sll	$a,5,$tmp0		!! $i
++	add	@K[$i/20],$e,$e
++	srl	$a,27,$tmp1
++___
++} else {
++$code.=<<___;
++	sllx	@X[($j+6)%8],32,$Xi	! Xupdate($i)
++	xor	@X[($j+1)%8],@X[$j%8],@X[$j%8]
++	srlx	@X[($j+7)%8],32,$tmp1
++	xor	@X[($j+4)%8],@X[$j%8],@X[$j%8]
++	sll	$a,5,$tmp0		!! $i
++	or	$tmp1,$Xi,$Xi
++	add	@K[$i/20],$e,$e		!!
++	xor	$Xi,@X[$j%8],@X[$j%8]
++	srlx	@X[$j%8],31,$Xi
++	add	@X[$j%8],@X[$j%8],@X[$j%8]
++	and	$Xi,$rot1m,$Xi
++	andn	@X[$j%8],$rot1m,@X[$j%8]
++	srl	$a,27,$tmp1		!!
++	or	$Xi,@X[$j%8],@X[$j%8]
++___
++}
++}
++
++sub BODY_16_19 {
++my ($i,$a,$b,$c,$d,$e)=@_;
++
++	&Xupdate(@_);
++    if ($i&1) {
++	$xi=@X[($i/2)%8];
++    } else {
++	$xi=$Xi;
++	$code.="\tsrlx	@X[($i/2)%8],32,$xi\n";
++    }
++$code.=<<___;
++	add	$tmp0,$e,$e		!!
++	and	$c,$b,$tmp0
++	add	$tmp1,$e,$e
++	sll	$b,30,$tmp2
++	add	$xi,$e,$e
++	andn	$d,$b,$tmp1
++	srl	$b,2,$b
++	or	$tmp1,$tmp0,$tmp1
++	or	$tmp2,$b,$b
++	add	$tmp1,$e,$e
++___
++}
++
++sub BODY_20_39 {
++my ($i,$a,$b,$c,$d,$e)=@_;
++my $xi;
++	&Xupdate(@_);
++    if ($i&1) {
++	$xi=@X[($i/2)%8];
++    } else {
++	$xi=$Xi;
++	$code.="\tsrlx	@X[($i/2)%8],32,$xi\n";
++    }
++$code.=<<___;
++	add	$tmp0,$e,$e		!!
++	xor	$c,$b,$tmp0
++	add	$tmp1,$e,$e
++	sll	$b,30,$tmp2
++	xor	$d,$tmp0,$tmp1
++	srl	$b,2,$b
++	add	$tmp1,$e,$e
++	or	$tmp2,$b,$b
++	add	$xi,$e,$e
++___
++}
++
++sub BODY_40_59 {
++my ($i,$a,$b,$c,$d,$e)=@_;
++my $xi;
++	&Xupdate(@_);
++    if ($i&1) {
++	$xi=@X[($i/2)%8];
++    } else {
++	$xi=$Xi;
++	$code.="\tsrlx	@X[($i/2)%8],32,$xi\n";
++    }
++$code.=<<___;
++	add	$tmp0,$e,$e		!!
++	and	$c,$b,$tmp0
++	add	$tmp1,$e,$e
++	sll	$b,30,$tmp2
++	or	$c,$b,$tmp1
++	srl	$b,2,$b
++	and	$d,$tmp1,$tmp1
++	add	$xi,$e,$e
++	or	$tmp1,$tmp0,$tmp1
++	or	$tmp2,$b,$b
++	add	$tmp1,$e,$e
++___
++}
++
++$code.=<<___;
++#include "sparc_arch.h"
++
++#ifdef __arch64__
++.register	%g2,#scratch
++.register	%g3,#scratch
++#endif
++
++.section	".text",#alloc,#execinstr
++
++#ifdef __PIC__
++SPARC_PIC_THUNK(%g1)
++#endif
++
++.align	32
++.globl	sha1_block_data_order
++sha1_block_data_order:
++	SPARC_LOAD_ADDRESS_LEAF(OPENSSL_sparcv9cap_P,%g1,%g5)
++	ld	[%g1+4],%g1		! OPENSSL_sparcv9cap_P[1]
++
++	andcc	%g1, CFR_SHA1, %g0
++	be	.Lsoftware
++	nop
++
++	ld	[%o0 + 0x00], %f0	! load context
++	ld	[%o0 + 0x04], %f1
++	ld	[%o0 + 0x08], %f2
++	andcc	%o1, 0x7, %g0
++	ld	[%o0 + 0x0c], %f3
++	bne,pn	%icc, .Lhwunaligned
++	 ld	[%o0 + 0x10], %f4
++
++.Lhw_loop:
++	ldd	[%o1 + 0x00], %f8
++	ldd	[%o1 + 0x08], %f10
++	ldd	[%o1 + 0x10], %f12
++	ldd	[%o1 + 0x18], %f14
++	ldd	[%o1 + 0x20], %f16
++	ldd	[%o1 + 0x28], %f18
++	ldd	[%o1 + 0x30], %f20
++	subcc	%o2, 1, %o2		! done yet? 
++	ldd	[%o1 + 0x38], %f22
++	add	%o1, 0x40, %o1
++	prefetch [%o1 + 63], 20
++
++	.word	0x81b02820		! SHA1
++
++	bne,pt	SIZE_T_CC, .Lhw_loop
++	nop
++
++.Lhwfinish:
++	st	%f0, [%o0 + 0x00]	! store context
++	st	%f1, [%o0 + 0x04]
++	st	%f2, [%o0 + 0x08]
++	st	%f3, [%o0 + 0x0c]
++	retl
++	st	%f4, [%o0 + 0x10]
++
++.align	8
++.Lhwunaligned:
++	alignaddr %o1, %g0, %o1
++
++	ldd	[%o1 + 0x00], %f10
++.Lhwunaligned_loop:
++	ldd	[%o1 + 0x08], %f12
++	ldd	[%o1 + 0x10], %f14
++	ldd	[%o1 + 0x18], %f16
++	ldd	[%o1 + 0x20], %f18
++	ldd	[%o1 + 0x28], %f20
++	ldd	[%o1 + 0x30], %f22
++	ldd	[%o1 + 0x38], %f24
++	subcc	%o2, 1, %o2		! done yet?
++	ldd	[%o1 + 0x40], %f26
++	add	%o1, 0x40, %o1
++	prefetch [%o1 + 63], 20
++
++	faligndata %f10, %f12, %f8
++	faligndata %f12, %f14, %f10
++	faligndata %f14, %f16, %f12
++	faligndata %f16, %f18, %f14
++	faligndata %f18, %f20, %f16
++	faligndata %f20, %f22, %f18
++	faligndata %f22, %f24, %f20
++	faligndata %f24, %f26, %f22
++
++	.word	0x81b02820		! SHA1
++
++	bne,pt	SIZE_T_CC, .Lhwunaligned_loop
++	for	%f26, %f26, %f10	! %f10=%f26
++
++	ba	.Lhwfinish
++	nop
++
++.align	16
++.Lsoftware:
++	save	%sp,-STACK_FRAME,%sp
++	sllx	$len,6,$len
++	add	$inp,$len,$len
++
++	or	%g0,1,$rot1m
++	sllx	$rot1m,32,$rot1m
++	or	$rot1m,1,$rot1m
++
++	ld	[$ctx+0],$A
++	ld	[$ctx+4],$B
++	ld	[$ctx+8],$C
++	ld	[$ctx+12],$D
++	ld	[$ctx+16],$E
++	andn	$inp,7,$tmp0
++
++	sethi	%hi(0x5a827999),$K_00_19
++	or	$K_00_19,%lo(0x5a827999),$K_00_19
++	sethi	%hi(0x6ed9eba1),$K_20_39
++	or	$K_20_39,%lo(0x6ed9eba1),$K_20_39
++	sethi	%hi(0x8f1bbcdc),$K_40_59
++	or	$K_40_59,%lo(0x8f1bbcdc),$K_40_59
++	sethi	%hi(0xca62c1d6),$K_60_79
++	or	$K_60_79,%lo(0xca62c1d6),$K_60_79
++
++.Lloop:
++	ldx	[$tmp0+0],@X[0]
++	ldx	[$tmp0+16],@X[2]
++	ldx	[$tmp0+32],@X[4]
++	ldx	[$tmp0+48],@X[6]
++	and	$inp,7,$tmp1
++	ldx	[$tmp0+8],@X[1]
++	sll	$tmp1,3,$tmp1
++	ldx	[$tmp0+24],@X[3]
++	subcc	%g0,$tmp1,$tmp2	! should be 64-$tmp1, but -$tmp1 works too
++	ldx	[$tmp0+40],@X[5]
++	bz,pt	%icc,.Laligned
++	ldx	[$tmp0+56],@X[7]
++
++	sllx	@X[0],$tmp1,@X[0]
++	ldx	[$tmp0+64],$tmp64
++___
++for($i=0;$i<7;$i++)
++{   $code.=<<___;
++	srlx	@X[$i+1],$tmp2,$Xi
++	sllx	@X[$i+1],$tmp1,@X[$i+1]
++	or	$Xi,@X[$i],@X[$i]
++___
++}
++$code.=<<___;
++	srlx	$tmp64,$tmp2,$tmp64
++	or	$tmp64,@X[7],@X[7]
++.Laligned:
++	srlx	@X[0],32,$Xi
++___
++for ($i=0;$i<16;$i++)	{ &BODY_00_15($i,@V); unshift(@V,pop(@V)); }
++for (;$i<20;$i++)	{ &BODY_16_19($i,@V); unshift(@V,pop(@V)); }
++for (;$i<40;$i++)	{ &BODY_20_39($i,@V); unshift(@V,pop(@V)); }
++for (;$i<60;$i++)	{ &BODY_40_59($i,@V); unshift(@V,pop(@V)); }
++for (;$i<80;$i++)	{ &BODY_20_39($i,@V); unshift(@V,pop(@V)); }
++$code.=<<___;
++
++	ld	[$ctx+0],@X[0]
++	ld	[$ctx+4],@X[1]
++	ld	[$ctx+8],@X[2]
++	ld	[$ctx+12],@X[3]
++	add	$inp,64,$inp
++	ld	[$ctx+16],@X[4]
++	cmp	$inp,$len
++
++	add	$A,@X[0],$A
++	st	$A,[$ctx+0]
++	add	$B,@X[1],$B
++	st	$B,[$ctx+4]
++	add	$C,@X[2],$C
++	st	$C,[$ctx+8]
++	add	$D,@X[3],$D
++	st	$D,[$ctx+12]
++	add	$E,@X[4],$E
++	st	$E,[$ctx+16]
++
++	bne	SIZE_T_CC,.Lloop
++	andn	$inp,7,$tmp0
++
++	ret
++	restore
++.type	sha1_block_data_order,#function
++.size	sha1_block_data_order,(.-sha1_block_data_order)
++.asciz	"SHA1 block transform for SPARCv9, CRYPTOGAMS by "
++.align	4
++___
++
++# Purpose of these subroutines is to explicitly encode VIS instructions,
++# so that one can compile the module without having to specify VIS
++# extensions on compiler command line, e.g. -xarch=v9 vs. -xarch=v9a.
++# Idea is to reserve for option to produce "universal" binary and let
++# programmer detect if current CPU is VIS capable at run-time.
++sub unvis {
++my ($mnemonic,$rs1,$rs2,$rd)=@_;
++my $ref,$opf;
++my %visopf = (	"faligndata"	=> 0x048,
++		"for"		=> 0x07c	);
++
++    $ref = "$mnemonic\t$rs1,$rs2,$rd";
++
++    if ($opf=$visopf{$mnemonic}) {
++	foreach ($rs1,$rs2,$rd) {
++	    return $ref if (!/%f([0-9]{1,2})/);
++	    $_=$1;
++	    if ($1>=32) {
++		return $ref if ($1&1);
++		# re-encode for upper double register addressing
++		$_=($1|$1>>5)&31;
++	    }
++	}
++
++	return	sprintf ".word\t0x%08x !%s",
++			0x81b00000|$rd<<25|$rs1<<14|$opf<<5|$rs2,
++			$ref;
++    } else {
++	return $ref;
++    }
++}
++sub unalignaddr {
++my ($mnemonic,$rs1,$rs2,$rd)=@_;
++my %bias = ( "g" => 0, "o" => 8, "l" => 16, "i" => 24 );
++my $ref="$mnemonic\t$rs1,$rs2,$rd";
++
++    foreach ($rs1,$rs2,$rd) {
++	if (/%([goli])([0-7])/)	{ $_=$bias{$1}+$2; }
++	else			{ return $ref; }
++    }
++    return  sprintf ".word\t0x%08x !%s",
++		    0x81b00300|$rd<<25|$rs1<<14|$rs2,
++		    $ref;
++}
++
++foreach (split("\n",$code)) {
++	s/\`([^\`]*)\`/eval $1/ge;
++
++	s/\b(f[^\s]*)\s+(%f[0-9]{1,2}),\s*(%f[0-9]{1,2}),\s*(%f[0-9]{1,2})/
++		&unvis($1,$2,$3,$4)
++	 /ge;
++	s/\b(alignaddr)\s+(%[goli][0-7]),\s*(%[goli][0-7]),\s*(%[goli][0-7])/
++		&unalignaddr($1,$2,$3,$4)
++	 /ge;
++
++	print $_,"\n";
++}
++
++close STDOUT;
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/sha/asm/sha1-sparcv9a.pl b/CryptoPkg/Library/OpensslLib/openssl/crypto/sha/asm/sha1-sparcv9a.pl
+new file mode 100644
+index 0000000..f9ed563
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/sha/asm/sha1-sparcv9a.pl
+@@ -0,0 +1,608 @@
++#! /usr/bin/env perl
++# Copyright 2009-2016 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
++# in the file LICENSE in the source distribution or at
++# https://www.openssl.org/source/license.html
++
++
++# ====================================================================
++# Written by Andy Polyakov  for the OpenSSL
++# project. The module is, however, dual licensed under OpenSSL and
++# CRYPTOGAMS licenses depending on where you obtain it. For further
++# details see http://www.openssl.org/~appro/cryptogams/.
++# ====================================================================
++
++# January 2009
++#
++# Provided that UltraSPARC VIS instructions are pipe-lined(*) and
++# pairable(*) with IALU ones, offloading of Xupdate to the UltraSPARC
++# Graphic Unit would make it possible to achieve higher instruction-
++# level parallelism, ILP, and thus higher performance. It should be
++# explicitly noted that ILP is the keyword, and it means that this
++# code would be unsuitable for cores like UltraSPARC-Tx. The idea is
++# not really novel, Sun had VIS-powered implementation for a while.
++# Unlike Sun's implementation this one can process multiple unaligned
++# input blocks, and as such works as drop-in replacement for OpenSSL
++# sha1_block_data_order. Performance improvement was measured to be
++# 40% over pure IALU sha1-sparcv9.pl on UltraSPARC-IIi, but 12% on
++# UltraSPARC-III. See below for discussion...
++#
++# The module does not present direct interest for OpenSSL, because
++# it doesn't provide better performance on contemporary SPARCv9 CPUs,
++# UltraSPARC-Tx and SPARC64-V[II] to be specific. Those who feel they
++# absolutely must score on UltraSPARC-I-IV can simply replace
++# crypto/sha/asm/sha1-sparcv9.pl with this module.
++#
++# (*)	"Pipe-lined" means that even if it takes several cycles to
++#	complete, next instruction using same functional unit [but not
++#	depending on the result of the current instruction] can start
++#	execution without having to wait for the unit. "Pairable"
++#	means that two [or more] independent instructions can be
++#	issued at the very same time.
++
++$bits=32;
++for (@ARGV)	{ $bits=64 if (/\-m64/ || /\-xarch\=v9/); }
++if ($bits==64)	{ $bias=2047; $frame=192; }
++else		{ $bias=0;    $frame=112; }
++
++$output=shift;
++open STDOUT,">$output";
++
++$ctx="%i0";
++$inp="%i1";
++$len="%i2";
++$tmp0="%i3";
++$tmp1="%i4";
++$tmp2="%i5";
++$tmp3="%g5";
++
++$base="%g1";
++$align="%g4";
++$Xfer="%o5";
++$nXfer=$tmp3;
++$Xi="%o7";
++
++$A="%l0";
++$B="%l1";
++$C="%l2";
++$D="%l3";
++$E="%l4";
++@V=($A,$B,$C,$D,$E);
++
++$Actx="%o0";
++$Bctx="%o1";
++$Cctx="%o2";
++$Dctx="%o3";
++$Ectx="%o4";
++
++$fmul="%f32";
++$VK_00_19="%f34";
++$VK_20_39="%f36";
++$VK_40_59="%f38";
++$VK_60_79="%f40";
++@VK=($VK_00_19,$VK_20_39,$VK_40_59,$VK_60_79);
++@X=("%f0", "%f1", "%f2", "%f3", "%f4", "%f5", "%f6", "%f7",
++    "%f8", "%f9","%f10","%f11","%f12","%f13","%f14","%f15","%f16");
++
++# This is reference 2x-parallelized VIS-powered Xupdate procedure. It
++# covers even K_NN_MM addition...
++sub Xupdate {
++my ($i)=@_;
++my $K=@VK[($i+16)/20];
++my $j=($i+16)%16;
++
++#	[ provided that GSR.alignaddr_offset is 5, $mul contains
++#	  0x100ULL<<32|0x100 value and K_NN_MM are pre-loaded to
++#	  chosen registers... ]
++$code.=<<___;
++	fxors		@X[($j+13)%16],@X[$j],@X[$j]	!-1/-1/-1:X[0]^=X[13]
++	fxors		@X[($j+14)%16],@X[$j+1],@X[$j+1]! 0/ 0/ 0:X[1]^=X[14]
++	fxor		@X[($j+2)%16],@X[($j+8)%16],%f18! 1/ 1/ 1:Tmp=X[2,3]^X[8,9]
++	fxor		%f18,@X[$j],@X[$j]		! 2/ 4/ 3:X[0,1]^=X[2,3]^X[8,9]
++	faligndata	@X[$j],@X[$j],%f18		! 3/ 7/ 5:Tmp=X[0,1]>>>24
++	fpadd32		@X[$j],@X[$j],@X[$j]		! 4/ 8/ 6:X[0,1]<<=1
++	fmul8ulx16	%f18,$fmul,%f18			! 5/10/ 7:Tmp>>=7, Tmp&=1
++	![fxors		%f15,%f2,%f2]
++	for		%f18,@X[$j],@X[$j]		! 8/14/10:X[0,1]|=Tmp
++	![fxors		%f0,%f3,%f3]			!10/17/12:X[0] dependency
++	fpadd32		$K,@X[$j],%f20
++	std		%f20,[$Xfer+`4*$j`]
++___
++# The numbers delimited with slash are the earliest possible dispatch
++# cycles for given instruction assuming 1 cycle latency for simple VIS
++# instructions, such as on UltraSPARC-I&II, 3 cycles latency, such as
++# on UltraSPARC-III&IV, and 2 cycles latency(*), respectively. Being
++# 2x-parallelized the procedure is "worth" 5, 8.5 or 6 ticks per SHA1
++# round. As [long as] FPU/VIS instructions are perfectly pairable with
++# IALU ones, the round timing is defined by the maximum between VIS
++# and IALU timings. The latter varies from round to round and averages
++# out at 6.25 ticks. This means that USI&II should operate at IALU
++# rate, while USIII&IV - at VIS rate. This explains why performance
++# improvement varies among processors. Well, given that pure IALU
++# sha1-sparcv9.pl module exhibits virtually uniform performance of
++# ~9.3 cycles per SHA1 round. Timings mentioned above are theoretical
++# lower limits. Real-life performance was measured to be 6.6 cycles
++# per SHA1 round on USIIi and 8.3 on USIII. The latter is lower than
++# half-round VIS timing, because there are 16 Xupdate-free rounds,
++# which "push down" average theoretical timing to 8 cycles...
++
++# (*)	SPARC64-V[II] was originally believed to have 2 cycles VIS
++#	latency. Well, it might have, but it doesn't have dedicated
++#	VIS-unit. Instead, VIS instructions are executed by other
++#	functional units, ones used here - by IALU. This doesn't
++#	improve effective ILP...
++}
++
++# The reference Xupdate procedure is then "strained" over *pairs* of
++# BODY_NN_MM and kind of modulo-scheduled in respect to X[n]^=X[n+13]
++# and K_NN_MM addition. It's "running" 15 rounds ahead, which leaves
++# plenty of room to amortize for read-after-write hazard, as well as
++# to fetch and align input for the next spin. The VIS instructions are
++# scheduled for latency of 2 cycles, because there are not enough IALU
++# instructions to schedule for latency of 3, while scheduling for 1
++# would give no gain on USI&II anyway.
++
++sub BODY_00_19 {
++my ($i,$a,$b,$c,$d,$e)=@_;
++my $j=$i&~1;
++my $k=($j+16+2)%16;	# ahead reference
++my $l=($j+16-2)%16;	# behind reference
++my $K=@VK[($j+16-2)/20];
++
++$j=($j+16)%16;
++
++$code.=<<___ if (!($i&1));
++	sll		$a,5,$tmp0			!! $i
++	and		$c,$b,$tmp3
++	ld		[$Xfer+`4*($i%16)`],$Xi
++	 fxors		@X[($j+14)%16],@X[$j+1],@X[$j+1]! 0/ 0/ 0:X[1]^=X[14]
++	srl		$a,27,$tmp1
++	add		$tmp0,$e,$e
++	 fxor		@X[($j+2)%16],@X[($j+8)%16],%f18! 1/ 1/ 1:Tmp=X[2,3]^X[8,9]
++	sll		$b,30,$tmp2
++	add		$tmp1,$e,$e
++	andn		$d,$b,$tmp1
++	add		$Xi,$e,$e
++	 fxor		%f18,@X[$j],@X[$j]		! 2/ 4/ 3:X[0,1]^=X[2,3]^X[8,9]
++	srl		$b,2,$b
++	or		$tmp1,$tmp3,$tmp1
++	or		$tmp2,$b,$b
++	add		$tmp1,$e,$e
++	 faligndata	@X[$j],@X[$j],%f18		! 3/ 7/ 5:Tmp=X[0,1]>>>24
++___
++$code.=<<___ if ($i&1);
++	sll		$a,5,$tmp0			!! $i
++	and		$c,$b,$tmp3
++	ld		[$Xfer+`4*($i%16)`],$Xi
++	 fpadd32	@X[$j],@X[$j],@X[$j]		! 4/ 8/ 6:X[0,1]<<=1
++	srl		$a,27,$tmp1
++	add		$tmp0,$e,$e
++	 fmul8ulx16	%f18,$fmul,%f18			! 5/10/ 7:Tmp>>=7, Tmp&=1
++	sll		$b,30,$tmp2
++	add		$tmp1,$e,$e
++	 fpadd32	$K,@X[$l],%f20			!
++	andn		$d,$b,$tmp1
++	add		$Xi,$e,$e
++	 fxors		@X[($k+13)%16],@X[$k],@X[$k]	!-1/-1/-1:X[0]^=X[13]
++	srl		$b,2,$b
++	or		$tmp1,$tmp3,$tmp1
++	 fxor		%f18,@X[$j],@X[$j]		! 8/14/10:X[0,1]|=Tmp
++	or		$tmp2,$b,$b
++	add		$tmp1,$e,$e
++___
++$code.=<<___ if ($i&1 && $i>=2);
++	 std		%f20,[$Xfer+`4*$l`]		!
++___
++}
++
++sub BODY_20_39 {
++my ($i,$a,$b,$c,$d,$e)=@_;
++my $j=$i&~1;
++my $k=($j+16+2)%16;	# ahead reference
++my $l=($j+16-2)%16;	# behind reference
++my $K=@VK[($j+16-2)/20];
++
++$j=($j+16)%16;
++
++$code.=<<___ if (!($i&1) && $i<64);
++	sll		$a,5,$tmp0			!! $i
++	ld		[$Xfer+`4*($i%16)`],$Xi
++	 fxors		@X[($j+14)%16],@X[$j+1],@X[$j+1]! 0/ 0/ 0:X[1]^=X[14]
++	srl		$a,27,$tmp1
++	add		$tmp0,$e,$e
++	 fxor		@X[($j+2)%16],@X[($j+8)%16],%f18! 1/ 1/ 1:Tmp=X[2,3]^X[8,9]
++	xor		$c,$b,$tmp0
++	add		$tmp1,$e,$e
++	sll		$b,30,$tmp2
++	xor		$d,$tmp0,$tmp1
++	 fxor		%f18,@X[$j],@X[$j]		! 2/ 4/ 3:X[0,1]^=X[2,3]^X[8,9]
++	srl		$b,2,$b
++	add		$tmp1,$e,$e
++	or		$tmp2,$b,$b
++	add		$Xi,$e,$e
++	 faligndata	@X[$j],@X[$j],%f18		! 3/ 7/ 5:Tmp=X[0,1]>>>24
++___
++$code.=<<___ if ($i&1 && $i<64);
++	sll		$a,5,$tmp0			!! $i
++	ld		[$Xfer+`4*($i%16)`],$Xi
++	 fpadd32	@X[$j],@X[$j],@X[$j]		! 4/ 8/ 6:X[0,1]<<=1
++	srl		$a,27,$tmp1
++	add		$tmp0,$e,$e
++	 fmul8ulx16	%f18,$fmul,%f18			! 5/10/ 7:Tmp>>=7, Tmp&=1
++	xor		$c,$b,$tmp0
++	add		$tmp1,$e,$e
++	 fpadd32	$K,@X[$l],%f20			!
++	sll		$b,30,$tmp2
++	xor		$d,$tmp0,$tmp1
++	 fxors		@X[($k+13)%16],@X[$k],@X[$k]	!-1/-1/-1:X[0]^=X[13]
++	srl		$b,2,$b
++	add		$tmp1,$e,$e
++	 fxor		%f18,@X[$j],@X[$j]		! 8/14/10:X[0,1]|=Tmp
++	or		$tmp2,$b,$b
++	add		$Xi,$e,$e
++	 std		%f20,[$Xfer+`4*$l`]		!
++___
++$code.=<<___ if ($i==64);
++	sll		$a,5,$tmp0			!! $i
++	ld		[$Xfer+`4*($i%16)`],$Xi
++	 fpadd32	$K,@X[$l],%f20
++	srl		$a,27,$tmp1
++	add		$tmp0,$e,$e
++	xor		$c,$b,$tmp0
++	add		$tmp1,$e,$e
++	sll		$b,30,$tmp2
++	xor		$d,$tmp0,$tmp1
++	 std		%f20,[$Xfer+`4*$l`]
++	srl		$b,2,$b
++	add		$tmp1,$e,$e
++	or		$tmp2,$b,$b
++	add		$Xi,$e,$e
++___
++$code.=<<___ if ($i>64);
++	sll		$a,5,$tmp0			!! $i
++	ld		[$Xfer+`4*($i%16)`],$Xi
++	srl		$a,27,$tmp1
++	add		$tmp0,$e,$e
++	xor		$c,$b,$tmp0
++	add		$tmp1,$e,$e
++	sll		$b,30,$tmp2
++	xor		$d,$tmp0,$tmp1
++	srl		$b,2,$b
++	add		$tmp1,$e,$e
++	or		$tmp2,$b,$b
++	add		$Xi,$e,$e
++___
++}
++
++sub BODY_40_59 {
++my ($i,$a,$b,$c,$d,$e)=@_;
++my $j=$i&~1;
++my $k=($j+16+2)%16;	# ahead reference
++my $l=($j+16-2)%16;	# behind reference
++my $K=@VK[($j+16-2)/20];
++
++$j=($j+16)%16;
++
++$code.=<<___ if (!($i&1));
++	sll		$a,5,$tmp0			!! $i
++	ld		[$Xfer+`4*($i%16)`],$Xi
++	 fxors		@X[($j+14)%16],@X[$j+1],@X[$j+1]! 0/ 0/ 0:X[1]^=X[14]
++	srl		$a,27,$tmp1
++	add		$tmp0,$e,$e
++	 fxor		@X[($j+2)%16],@X[($j+8)%16],%f18! 1/ 1/ 1:Tmp=X[2,3]^X[8,9]
++	and		$c,$b,$tmp0
++	add		$tmp1,$e,$e
++	sll		$b,30,$tmp2
++	or		$c,$b,$tmp1
++	 fxor		%f18,@X[$j],@X[$j]		! 2/ 4/ 3:X[0,1]^=X[2,3]^X[8,9]
++	srl		$b,2,$b
++	and		$d,$tmp1,$tmp1
++	add		$Xi,$e,$e
++	or		$tmp1,$tmp0,$tmp1
++	 faligndata	@X[$j],@X[$j],%f18		! 3/ 7/ 5:Tmp=X[0,1]>>>24
++	or		$tmp2,$b,$b
++	add		$tmp1,$e,$e
++	 fpadd32	@X[$j],@X[$j],@X[$j]		! 4/ 8/ 6:X[0,1]<<=1
++___
++$code.=<<___ if ($i&1);
++	sll		$a,5,$tmp0			!! $i
++	ld		[$Xfer+`4*($i%16)`],$Xi
++	srl		$a,27,$tmp1
++	add		$tmp0,$e,$e
++	 fmul8ulx16	%f18,$fmul,%f18			! 5/10/ 7:Tmp>>=7, Tmp&=1
++	and		$c,$b,$tmp0
++	add		$tmp1,$e,$e
++	 fpadd32	$K,@X[$l],%f20			!
++	sll		$b,30,$tmp2
++	or		$c,$b,$tmp1
++	 fxors		@X[($k+13)%16],@X[$k],@X[$k]	!-1/-1/-1:X[0]^=X[13]
++	srl		$b,2,$b
++	and		$d,$tmp1,$tmp1
++	 fxor		%f18,@X[$j],@X[$j]		! 8/14/10:X[0,1]|=Tmp
++	add		$Xi,$e,$e
++	or		$tmp1,$tmp0,$tmp1
++	or		$tmp2,$b,$b
++	add		$tmp1,$e,$e
++	 std		%f20,[$Xfer+`4*$l`]		!
++___
++}
++
++# If there is more data to process, then we pre-fetch the data for
++# next iteration in last ten rounds...
++sub BODY_70_79 {
++my ($i,$a,$b,$c,$d,$e)=@_;
++my $j=$i&~1;
++my $m=($i%8)*2;
++
++$j=($j+16)%16;
++
++$code.=<<___ if ($i==70);
++	sll		$a,5,$tmp0			!! $i
++	ld		[$Xfer+`4*($i%16)`],$Xi
++	srl		$a,27,$tmp1
++	add		$tmp0,$e,$e
++	 ldd		[$inp+64],@X[0]
++	xor		$c,$b,$tmp0
++	add		$tmp1,$e,$e
++	sll		$b,30,$tmp2
++	xor		$d,$tmp0,$tmp1
++	srl		$b,2,$b
++	add		$tmp1,$e,$e
++	or		$tmp2,$b,$b
++	add		$Xi,$e,$e
++
++	and		$inp,-64,$nXfer
++	inc		64,$inp
++	and		$nXfer,255,$nXfer
++	alignaddr	%g0,$align,%g0
++	add		$base,$nXfer,$nXfer
++___
++$code.=<<___ if ($i==71);
++	sll		$a,5,$tmp0			!! $i
++	ld		[$Xfer+`4*($i%16)`],$Xi
++	srl		$a,27,$tmp1
++	add		$tmp0,$e,$e
++	xor		$c,$b,$tmp0
++	add		$tmp1,$e,$e
++	sll		$b,30,$tmp2
++	xor		$d,$tmp0,$tmp1
++	srl		$b,2,$b
++	add		$tmp1,$e,$e
++	or		$tmp2,$b,$b
++	add		$Xi,$e,$e
++___
++$code.=<<___ if ($i>=72);
++	 faligndata	@X[$m],@X[$m+2],@X[$m]
++	sll		$a,5,$tmp0			!! $i
++	ld		[$Xfer+`4*($i%16)`],$Xi
++	srl		$a,27,$tmp1
++	add		$tmp0,$e,$e
++	xor		$c,$b,$tmp0
++	add		$tmp1,$e,$e
++	 fpadd32	$VK_00_19,@X[$m],%f20
++	sll		$b,30,$tmp2
++	xor		$d,$tmp0,$tmp1
++	srl		$b,2,$b
++	add		$tmp1,$e,$e
++	or		$tmp2,$b,$b
++	add		$Xi,$e,$e
++___
++$code.=<<___ if ($i<77);
++	 ldd		[$inp+`8*($i+1-70)`],@X[2*($i+1-70)]
++___
++$code.=<<___ if ($i==77);	# redundant if $inp was aligned
++	 add		$align,63,$tmp0
++	 and		$tmp0,-8,$tmp0
++	 ldd		[$inp+$tmp0],@X[16]
++___
++$code.=<<___ if ($i>=72);
++	 std		%f20,[$nXfer+`4*$m`]
++___
++}
++
++$code.=<<___;
++.section	".text",#alloc,#execinstr
++
++.align	64
++vis_const:
++.long	0x5a827999,0x5a827999	! K_00_19
++.long	0x6ed9eba1,0x6ed9eba1	! K_20_39
++.long	0x8f1bbcdc,0x8f1bbcdc	! K_40_59
++.long	0xca62c1d6,0xca62c1d6	! K_60_79
++.long	0x00000100,0x00000100
++.align	64
++.type	vis_const,#object
++.size	vis_const,(.-vis_const)
++
++.globl	sha1_block_data_order
++sha1_block_data_order:
++	save	%sp,-$frame,%sp
++	add	%fp,$bias-256,$base
++
++1:	call	.+8
++	add	%o7,vis_const-1b,$tmp0
++
++	ldd	[$tmp0+0],$VK_00_19
++	ldd	[$tmp0+8],$VK_20_39
++	ldd	[$tmp0+16],$VK_40_59
++	ldd	[$tmp0+24],$VK_60_79
++	ldd	[$tmp0+32],$fmul
++
++	ld	[$ctx+0],$Actx
++	and	$base,-256,$base
++	ld	[$ctx+4],$Bctx
++	sub	$base,$bias+$frame,%sp
++	ld	[$ctx+8],$Cctx
++	and	$inp,7,$align
++	ld	[$ctx+12],$Dctx
++	and	$inp,-8,$inp
++	ld	[$ctx+16],$Ectx
++
++	! X[16] is maintained in FP register bank
++	alignaddr	%g0,$align,%g0
++	ldd		[$inp+0],@X[0]
++	sub		$inp,-64,$Xfer
++	ldd		[$inp+8],@X[2]
++	and		$Xfer,-64,$Xfer
++	ldd		[$inp+16],@X[4]
++	and		$Xfer,255,$Xfer
++	ldd		[$inp+24],@X[6]
++	add		$base,$Xfer,$Xfer
++	ldd		[$inp+32],@X[8]
++	ldd		[$inp+40],@X[10]
++	ldd		[$inp+48],@X[12]
++	brz,pt		$align,.Laligned
++	ldd		[$inp+56],@X[14]
++
++	ldd		[$inp+64],@X[16]
++	faligndata	@X[0],@X[2],@X[0]
++	faligndata	@X[2],@X[4],@X[2]
++	faligndata	@X[4],@X[6],@X[4]
++	faligndata	@X[6],@X[8],@X[6]
++	faligndata	@X[8],@X[10],@X[8]
++	faligndata	@X[10],@X[12],@X[10]
++	faligndata	@X[12],@X[14],@X[12]
++	faligndata	@X[14],@X[16],@X[14]
++
++.Laligned:
++	mov		5,$tmp0
++	dec		1,$len
++	alignaddr	%g0,$tmp0,%g0
++	fpadd32		$VK_00_19,@X[0],%f16
++	fpadd32		$VK_00_19,@X[2],%f18
++	fpadd32		$VK_00_19,@X[4],%f20
++	fpadd32		$VK_00_19,@X[6],%f22
++	fpadd32		$VK_00_19,@X[8],%f24
++	fpadd32		$VK_00_19,@X[10],%f26
++	fpadd32		$VK_00_19,@X[12],%f28
++	fpadd32		$VK_00_19,@X[14],%f30
++	std		%f16,[$Xfer+0]
++	mov		$Actx,$A
++	std		%f18,[$Xfer+8]
++	mov		$Bctx,$B
++	std		%f20,[$Xfer+16]
++	mov		$Cctx,$C
++	std		%f22,[$Xfer+24]
++	mov		$Dctx,$D
++	std		%f24,[$Xfer+32]
++	mov		$Ectx,$E
++	std		%f26,[$Xfer+40]
++	fxors		@X[13],@X[0],@X[0]
++	std		%f28,[$Xfer+48]
++	ba		.Loop
++	std		%f30,[$Xfer+56]
++.align	32
++.Loop:
++___
++for ($i=0;$i<20;$i++)	{ &BODY_00_19($i,@V); unshift(@V,pop(@V)); }
++for (;$i<40;$i++)	{ &BODY_20_39($i,@V); unshift(@V,pop(@V)); }
++for (;$i<60;$i++)	{ &BODY_40_59($i,@V); unshift(@V,pop(@V)); }
++for (;$i<70;$i++)	{ &BODY_20_39($i,@V); unshift(@V,pop(@V)); }
++$code.=<<___;
++	tst		$len
++	bz,pn		`$bits==32?"%icc":"%xcc"`,.Ltail
++	nop
++___
++for (;$i<80;$i++)	{ &BODY_70_79($i,@V); unshift(@V,pop(@V)); }
++$code.=<<___;
++	add		$A,$Actx,$Actx
++	add		$B,$Bctx,$Bctx
++	add		$C,$Cctx,$Cctx
++	add		$D,$Dctx,$Dctx
++	add		$E,$Ectx,$Ectx
++	mov		5,$tmp0
++	fxors		@X[13],@X[0],@X[0]
++	mov		$Actx,$A
++	mov		$Bctx,$B
++	mov		$Cctx,$C
++	mov		$Dctx,$D
++	mov		$Ectx,$E
++	alignaddr	%g0,$tmp0,%g0	
++	dec		1,$len
++	ba		.Loop
++	mov		$nXfer,$Xfer
++
++.align	32
++.Ltail:
++___
++for($i=70;$i<80;$i++)	{ &BODY_20_39($i,@V); unshift(@V,pop(@V)); }
++$code.=<<___;
++	add	$A,$Actx,$Actx
++	add	$B,$Bctx,$Bctx
++	add	$C,$Cctx,$Cctx
++	add	$D,$Dctx,$Dctx
++	add	$E,$Ectx,$Ectx
++
++	st	$Actx,[$ctx+0]
++	st	$Bctx,[$ctx+4]
++	st	$Cctx,[$ctx+8]
++	st	$Dctx,[$ctx+12]
++	st	$Ectx,[$ctx+16]
++
++	ret
++	restore
++.type	sha1_block_data_order,#function
++.size	sha1_block_data_order,(.-sha1_block_data_order)
++.asciz	"SHA1 block transform for SPARCv9a, CRYPTOGAMS by "
++.align	4
++___
++
++# Purpose of these subroutines is to explicitly encode VIS instructions,
++# so that one can compile the module without having to specify VIS
++# extensions on compiler command line, e.g. -xarch=v9 vs. -xarch=v9a.
++# Idea is to reserve for option to produce "universal" binary and let
++# programmer detect if current CPU is VIS capable at run-time.
++sub unvis {
++my ($mnemonic,$rs1,$rs2,$rd)=@_;
++my ($ref,$opf);
++my %visopf = (	"fmul8ulx16"	=> 0x037,
++		"faligndata"	=> 0x048,
++		"fpadd32"	=> 0x052,
++		"fxor"		=> 0x06c,
++		"fxors"		=> 0x06d	);
++
++    $ref = "$mnemonic\t$rs1,$rs2,$rd";
++
++    if ($opf=$visopf{$mnemonic}) {
++	foreach ($rs1,$rs2,$rd) {
++	    return $ref if (!/%f([0-9]{1,2})/);
++	    $_=$1;
++	    if ($1>=32) {
++		return $ref if ($1&1);
++		# re-encode for upper double register addressing
++		$_=($1|$1>>5)&31;
++	    }
++	}
++
++	return	sprintf ".word\t0x%08x !%s",
++			0x81b00000|$rd<<25|$rs1<<14|$opf<<5|$rs2,
++			$ref;
++    } else {
++	return $ref;
++    }
++}
++sub unalignaddr {
++my ($mnemonic,$rs1,$rs2,$rd)=@_;
++my %bias = ( "g" => 0, "o" => 8, "l" => 16, "i" => 24 );
++my $ref="$mnemonic\t$rs1,$rs2,$rd";
++
++    foreach ($rs1,$rs2,$rd) {
++	if (/%([goli])([0-7])/)	{ $_=$bias{$1}+$2; }
++	else			{ return $ref; }
++    }
++    return  sprintf ".word\t0x%08x !%s",
++		    0x81b00300|$rd<<25|$rs1<<14|$rs2,
++		    $ref;
++}
++
++$code =~ s/\`([^\`]*)\`/eval $1/gem;
++$code =~ s/\b(f[^\s]*)\s+(%f[0-9]{1,2}),(%f[0-9]{1,2}),(%f[0-9]{1,2})/
++		&unvis($1,$2,$3,$4)
++	  /gem;
++$code =~ s/\b(alignaddr)\s+(%[goli][0-7]),(%[goli][0-7]),(%[goli][0-7])/
++		&unalignaddr($1,$2,$3,$4)
++	  /gem;
++print $code;
++close STDOUT;
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/sha/asm/sha1-thumb.pl b/CryptoPkg/Library/OpensslLib/openssl/crypto/sha/asm/sha1-thumb.pl
+new file mode 100644
+index 0000000..661fd9f
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/sha/asm/sha1-thumb.pl
+@@ -0,0 +1,266 @@
++#! /usr/bin/env perl
++# Copyright 2007-2016 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
++# in the file LICENSE in the source distribution or at
++# https://www.openssl.org/source/license.html
++
++
++# ====================================================================
++# Written by Andy Polyakov  for the OpenSSL
++# project. The module is, however, dual licensed under OpenSSL and
++# CRYPTOGAMS licenses depending on where you obtain it. For further
++# details see http://www.openssl.org/~appro/cryptogams/.
++# ====================================================================
++
++# sha1_block for Thumb.
++#
++# January 2007.
++#
++# The code does not present direct interest to OpenSSL, because of low
++# performance. Its purpose is to establish _size_ benchmark. Pretty
++# useless one I must say, because 30% or 88 bytes larger ARMv4 code
++# [avialable on demand] is almost _twice_ as fast. It should also be
++# noted that in-lining of .Lcommon and .Lrotate improves performance
++# by over 40%, while code increases by only 10% or 32 bytes. But once
++# again, the goal was to establish _size_ benchmark, not performance.
++
++$output=shift;
++open STDOUT,">$output";
++
++$inline=0;
++#$cheat_on_binutils=1;
++
++$t0="r0";
++$t1="r1";
++$t2="r2";
++$a="r3";
++$b="r4";
++$c="r5";
++$d="r6";
++$e="r7";
++$K="r8";	# "upper" registers can be used in add/sub and mov insns
++$ctx="r9";
++$inp="r10";
++$len="r11";
++$Xi="r12";
++
++sub common {
++<<___;
++	sub	$t0,#4
++	ldr	$t1,[$t0]
++	add	$e,$K			@ E+=K_xx_xx
++	lsl	$t2,$a,#5
++	add	$t2,$e
++	lsr	$e,$a,#27
++	add	$t2,$e			@ E+=ROR(A,27)
++	add	$t2,$t1			@ E+=X[i]
++___
++}
++sub rotate {
++<<___;
++	mov	$e,$d			@ E=D
++	mov	$d,$c			@ D=C
++	lsl	$c,$b,#30
++	lsr	$b,$b,#2
++	orr	$c,$b			@ C=ROR(B,2)
++	mov	$b,$a			@ B=A
++	add	$a,$t2,$t1		@ A=E+F_xx_xx(B,C,D)
++___
++}
++
++sub BODY_00_19 {
++$code.=$inline?&common():"\tbl	.Lcommon\n";
++$code.=<<___;
++	mov	$t1,$c
++	eor	$t1,$d
++	and	$t1,$b
++	eor	$t1,$d			@ F_00_19(B,C,D)
++___
++$code.=$inline?&rotate():"\tbl	.Lrotate\n";
++}
++
++sub BODY_20_39 {
++$code.=$inline?&common():"\tbl	.Lcommon\n";
++$code.=<<___;
++	mov	$t1,$b
++	eor	$t1,$c
++	eor	$t1,$d			@ F_20_39(B,C,D)
++___
++$code.=$inline?&rotate():"\tbl	.Lrotate\n";
++}
++
++sub BODY_40_59 {
++$code.=$inline?&common():"\tbl	.Lcommon\n";
++$code.=<<___;
++	mov	$t1,$b
++	and	$t1,$c
++	mov	$e,$b
++	orr	$e,$c
++	and	$e,$d
++	orr	$t1,$e			@ F_40_59(B,C,D)
++___
++$code.=$inline?&rotate():"\tbl	.Lrotate\n";
++}
++
++$code=<<___;
++.text
++.code	16
++
++.global	sha1_block_data_order
++.type	sha1_block_data_order,%function
++
++.align	2
++sha1_block_data_order:
++___
++if ($cheat_on_binutils) {
++$code.=<<___;
++.code	32
++	add	r3,pc,#1
++	bx	r3			@ switch to Thumb ISA
++.code	16
++___
++}
++$code.=<<___;
++	push	{r4-r7}
++	mov	r3,r8
++	mov	r4,r9
++	mov	r5,r10
++	mov	r6,r11
++	mov	r7,r12
++	push	{r3-r7,lr}
++	lsl	r2,#6
++	mov	$ctx,r0			@ save context
++	mov	$inp,r1			@ save inp
++	mov	$len,r2			@ save len
++	add	$len,$inp		@ $len to point at inp end
++
++.Lloop:
++	mov	$Xi,sp
++	mov	$t2,sp
++	sub	$t2,#16*4		@ [3]
++.LXload:
++	ldrb	$a,[$t1,#0]		@ $t1 is r1 and holds inp
++	ldrb	$b,[$t1,#1]
++	ldrb	$c,[$t1,#2]
++	ldrb	$d,[$t1,#3]
++	lsl	$a,#24
++	lsl	$b,#16
++	lsl	$c,#8
++	orr	$a,$b
++	orr	$a,$c
++	orr	$a,$d
++	add	$t1,#4
++	push	{$a}
++	cmp	sp,$t2
++	bne	.LXload			@ [+14*16]
++
++	mov	$inp,$t1		@ update $inp
++	sub	$t2,#32*4
++	sub	$t2,#32*4
++	mov	$e,#31			@ [+4]
++.LXupdate:
++	ldr	$a,[sp,#15*4]
++	ldr	$b,[sp,#13*4]
++	ldr	$c,[sp,#7*4]
++	ldr	$d,[sp,#2*4]
++	eor	$a,$b
++	eor	$a,$c
++	eor	$a,$d
++	ror	$a,$e
++	push	{$a}
++	cmp	sp,$t2
++	bne	.LXupdate		@ [+(11+1)*64]
++
++	ldmia	$t0!,{$a,$b,$c,$d,$e}	@ $t0 is r0 and holds ctx
++	mov	$t0,$Xi
++
++	ldr	$t2,.LK_00_19
++	mov	$t1,$t0
++	sub	$t1,#20*4
++	mov	$Xi,$t1
++	mov	$K,$t2			@ [+7+4]
++.L_00_19:
++___
++	&BODY_00_19();
++$code.=<<___;
++	cmp	$Xi,$t0
++	bne	.L_00_19		@ [+(2+9+4+2+8+2)*20]
++
++	ldr	$t2,.LK_20_39
++	mov	$t1,$t0
++	sub	$t1,#20*4
++	mov	$Xi,$t1
++	mov	$K,$t2			@ [+5]
++.L_20_39_or_60_79:
++___
++	&BODY_20_39();
++$code.=<<___;
++	cmp	$Xi,$t0
++	bne	.L_20_39_or_60_79	@ [+(2+9+3+2+8+2)*20*2]
++	cmp	sp,$t0
++	beq	.Ldone			@ [+2]
++
++	ldr	$t2,.LK_40_59
++	mov	$t1,$t0
++	sub	$t1,#20*4
++	mov	$Xi,$t1
++	mov	$K,$t2			@ [+5]
++.L_40_59:
++___
++	&BODY_40_59();
++$code.=<<___;
++	cmp	$Xi,$t0
++	bne	.L_40_59		@ [+(2+9+6+2+8+2)*20]
++
++	ldr	$t2,.LK_60_79
++	mov	$Xi,sp
++	mov	$K,$t2
++	b	.L_20_39_or_60_79	@ [+4]
++.Ldone:
++	mov	$t0,$ctx
++	ldr	$t1,[$t0,#0]
++	ldr	$t2,[$t0,#4]
++	add	$a,$t1
++	ldr	$t1,[$t0,#8]
++	add	$b,$t2
++	ldr	$t2,[$t0,#12]
++	add	$c,$t1
++	ldr	$t1,[$t0,#16]
++	add	$d,$t2
++	add	$e,$t1
++	stmia	$t0!,{$a,$b,$c,$d,$e}	@ [+20]
++
++	add	sp,#80*4		@ deallocate stack frame
++	mov	$t0,$ctx		@ restore ctx
++	mov	$t1,$inp		@ restore inp
++	cmp	$t1,$len
++	beq	.Lexit
++	b	.Lloop			@ [+6] total 3212 cycles
++.Lexit:
++	pop	{r2-r7}
++	mov	r8,r2
++	mov	r9,r3
++	mov	r10,r4
++	mov	r11,r5
++	mov	r12,r6
++	mov	lr,r7
++	pop	{r4-r7}
++	bx	lr
++.align	2
++___
++$code.=".Lcommon:\n".&common()."\tmov	pc,lr\n" if (!$inline);
++$code.=".Lrotate:\n".&rotate()."\tmov	pc,lr\n" if (!$inline);
++$code.=<<___;
++.align	2
++.LK_00_19:	.word	0x5a827999
++.LK_20_39:	.word	0x6ed9eba1
++.LK_40_59:	.word	0x8f1bbcdc
++.LK_60_79:	.word	0xca62c1d6
++.size	sha1_block_data_order,.-sha1_block_data_order
++.asciz	"SHA1 block transform for Thumb, CRYPTOGAMS by "
++___
++
++print $code;
++close STDOUT; # enforce flush
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/sha/asm/sha1-x86_64.pl b/CryptoPkg/Library/OpensslLib/openssl/crypto/sha/asm/sha1-x86_64.pl
+new file mode 100755
+index 0000000..e11c6e4
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/sha/asm/sha1-x86_64.pl
+@@ -0,0 +1,2077 @@
++#! /usr/bin/env perl
++# Copyright 2006-2016 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
++# in the file LICENSE in the source distribution or at
++# https://www.openssl.org/source/license.html
++
++#
++# ====================================================================
++# Written by Andy Polyakov  for the OpenSSL
++# project. The module is, however, dual licensed under OpenSSL and
++# CRYPTOGAMS licenses depending on where you obtain it. For further
++# details see http://www.openssl.org/~appro/cryptogams/.
++# ====================================================================
++#
++# sha1_block procedure for x86_64.
++#
++# It was brought to my attention that on EM64T compiler-generated code
++# was far behind 32-bit assembler implementation. This is unlike on
++# Opteron where compiler-generated code was only 15% behind 32-bit
++# assembler, which originally made it hard to motivate the effort.
++# There was suggestion to mechanically translate 32-bit code, but I
++# dismissed it, reasoning that x86_64 offers enough register bank
++# capacity to fully utilize SHA-1 parallelism. Therefore this fresh
++# implementation:-) However! While 64-bit code does perform better
++# on Opteron, I failed to beat 32-bit assembler on EM64T core. Well,
++# x86_64 does offer larger *addressable* bank, but out-of-order core
++# reaches for even more registers through dynamic aliasing, and EM64T
++# core must have managed to run-time optimize even 32-bit code just as
++# good as 64-bit one. Performance improvement is summarized in the
++# following table:
++#
++#		gcc 3.4		32-bit asm	cycles/byte
++# Opteron	+45%		+20%		6.8
++# Xeon P4	+65%		+0%		9.9
++# Core2		+60%		+10%		7.0
++
++# August 2009.
++#
++# The code was revised to minimize code size and to maximize
++# "distance" between instructions producing input to 'lea'
++# instruction and the 'lea' instruction itself, which is essential
++# for Intel Atom core.
++
++# October 2010.
++#
++# Add SSSE3, Supplemental[!] SSE3, implementation. The idea behind it
++# is to offload message schedule denoted by Wt in NIST specification,
++# or Xupdate in OpenSSL source, to SIMD unit. See sha1-586.pl module
++# for background and implementation details. The only difference from
++# 32-bit code is that 64-bit code doesn't have to spill @X[] elements
++# to free temporary registers.
++
++# April 2011.
++#
++# Add AVX code path. See sha1-586.pl for further information.
++
++# May 2013.
++#
++# Add AVX2+BMI code path. Initial attempt (utilizing BMI instructions
++# and loading pair of consecutive blocks to 256-bit %ymm registers)
++# did not provide impressive performance improvement till a crucial
++# hint regarding the number of Xupdate iterations to pre-compute in
++# advance was provided by Ilya Albrekht of Intel Corp.
++
++# March 2014.
++#
++# Add support for Intel SHA Extensions.
++
++######################################################################
++# Current performance is summarized in following table. Numbers are
++# CPU clock cycles spent to process single byte (less is better).
++#
++#		x86_64		SSSE3		AVX[2]
++# P4		9.05		-
++# Opteron	6.26		-
++# Core2		6.55		6.05/+8%	-
++# Westmere	6.73		5.30/+27%	-
++# Sandy Bridge	7.70		6.10/+26%	4.99/+54%
++# Ivy Bridge	6.06		4.67/+30%	4.60/+32%
++# Haswell	5.45		4.15/+31%	3.57/+53%
++# Skylake	5.18		4.06/+28%	3.54/+46%
++# Bulldozer	9.11		5.95/+53%
++# VIA Nano	9.32		7.15/+30%
++# Atom		10.3		9.17/+12%
++# Silvermont	13.1(*)		9.37/+40%
++# Goldmont	8.13		6.42/+27%	1.70/+380%(**)
++#
++# (*)	obviously suboptimal result, nothing was done about it,
++#	because SSSE3 code is compiled unconditionally;
++# (**)	SHAEXT result
++
++$flavour = shift;
++$output  = shift;
++if ($flavour =~ /\./) { $output = $flavour; undef $flavour; }
++
++$win64=0; $win64=1 if ($flavour =~ /[nm]asm|mingw64/ || $output =~ /\.asm$/);
++
++$0 =~ m/(.*[\/\\])[^\/\\]+$/; $dir=$1;
++( $xlate="${dir}x86_64-xlate.pl" and -f $xlate ) or
++( $xlate="${dir}../../perlasm/x86_64-xlate.pl" and -f $xlate) or
++die "can't locate x86_64-xlate.pl";
++
++if (`$ENV{CC} -Wa,-v -c -o /dev/null -x assembler /dev/null 2>&1`
++		=~ /GNU assembler version ([2-9]\.[0-9]+)/) {
++	$avx = ($1>=2.19) + ($1>=2.22);
++}
++
++if (!$avx && $win64 && ($flavour =~ /nasm/ || $ENV{ASM} =~ /nasm/) &&
++	   `nasm -v 2>&1` =~ /NASM version ([2-9]\.[0-9]+)/) {
++	$avx = ($1>=2.09) + ($1>=2.10);
++}
++
++if (!$avx && $win64 && ($flavour =~ /masm/ || $ENV{ASM} =~ /ml64/) &&
++	   `ml64 2>&1` =~ /Version ([0-9]+)\./) {
++	$avx = ($1>=10) + ($1>=11);
++}
++
++if (!$avx && `$ENV{CC} -v 2>&1` =~ /((?:^clang|LLVM) version|.*based on LLVM) ([2-9]\.[0-9]+)/) {
++	$avx = ($2>=3.0) + ($2>3.0);
++}
++
++$shaext=1;	### set to zero if compiling for 1.0.1
++$avx=1		if (!$shaext && $avx);
++
++open OUT,"| \"$^X\" \"$xlate\" $flavour \"$output\"";
++*STDOUT=*OUT;
++
++$ctx="%rdi";	# 1st arg
++$inp="%rsi";	# 2nd arg
++$num="%rdx";	# 3rd arg
++
++# reassign arguments in order to produce more compact code
++$ctx="%r8";
++$inp="%r9";
++$num="%r10";
++
++$t0="%eax";
++$t1="%ebx";
++$t2="%ecx";
++@xi=("%edx","%ebp","%r14d");
++$A="%esi";
++$B="%edi";
++$C="%r11d";
++$D="%r12d";
++$E="%r13d";
++
++@V=($A,$B,$C,$D,$E);
++
++sub BODY_00_19 {
++my ($i,$a,$b,$c,$d,$e)=@_;
++my $j=$i+1;
++$code.=<<___ if ($i==0);
++	mov	`4*$i`($inp),$xi[0]
++	bswap	$xi[0]
++___
++$code.=<<___ if ($i<15);
++	mov	`4*$j`($inp),$xi[1]
++	mov	$d,$t0
++	mov	$xi[0],`4*$i`(%rsp)
++	mov	$a,$t2
++	bswap	$xi[1]
++	xor	$c,$t0
++	rol	\$5,$t2
++	and	$b,$t0
++	lea	0x5a827999($xi[0],$e),$e
++	add	$t2,$e
++	xor	$d,$t0
++	rol	\$30,$b
++	add	$t0,$e
++___
++$code.=<<___ if ($i>=15);
++	xor	`4*($j%16)`(%rsp),$xi[1]
++	mov	$d,$t0
++	mov	$xi[0],`4*($i%16)`(%rsp)
++	mov	$a,$t2
++	xor	`4*(($j+2)%16)`(%rsp),$xi[1]
++	xor	$c,$t0
++	rol	\$5,$t2
++	xor	`4*(($j+8)%16)`(%rsp),$xi[1]
++	and	$b,$t0
++	lea	0x5a827999($xi[0],$e),$e
++	rol	\$30,$b
++	xor	$d,$t0
++	add	$t2,$e
++	rol	\$1,$xi[1]
++	add	$t0,$e
++___
++push(@xi,shift(@xi));
++}
++
++sub BODY_20_39 {
++my ($i,$a,$b,$c,$d,$e)=@_;
++my $j=$i+1;
++my $K=($i<40)?0x6ed9eba1:0xca62c1d6;
++$code.=<<___ if ($i<79);
++	xor	`4*($j%16)`(%rsp),$xi[1]
++	mov	$b,$t0
++	`"mov	$xi[0],".4*($i%16)."(%rsp)"	if ($i<72)`
++	mov	$a,$t2
++	xor	`4*(($j+2)%16)`(%rsp),$xi[1]
++	xor	$d,$t0
++	rol	\$5,$t2
++	xor	`4*(($j+8)%16)`(%rsp),$xi[1]
++	lea	$K($xi[0],$e),$e
++	xor	$c,$t0
++	add	$t2,$e
++	rol	\$30,$b
++	add	$t0,$e
++	rol	\$1,$xi[1]
++___
++$code.=<<___ if ($i==79);
++	mov	$b,$t0
++	mov	$a,$t2
++	xor	$d,$t0
++	lea	$K($xi[0],$e),$e
++	rol	\$5,$t2
++	xor	$c,$t0
++	add	$t2,$e
++	rol	\$30,$b
++	add	$t0,$e
++___
++push(@xi,shift(@xi));
++}
++
++sub BODY_40_59 {
++my ($i,$a,$b,$c,$d,$e)=@_;
++my $j=$i+1;
++$code.=<<___;
++	xor	`4*($j%16)`(%rsp),$xi[1]
++	mov	$d,$t0
++	mov	$xi[0],`4*($i%16)`(%rsp)
++	mov	$d,$t1
++	xor	`4*(($j+2)%16)`(%rsp),$xi[1]
++	and	$c,$t0
++	mov	$a,$t2
++	xor	`4*(($j+8)%16)`(%rsp),$xi[1]
++	lea	0x8f1bbcdc($xi[0],$e),$e
++	xor	$c,$t1
++	rol	\$5,$t2
++	add	$t0,$e
++	rol	\$1,$xi[1]
++	and	$b,$t1
++	add	$t2,$e
++	rol	\$30,$b
++	add	$t1,$e
++___
++push(@xi,shift(@xi));
++}
++
++$code.=<<___;
++.text
++.extern	OPENSSL_ia32cap_P
++
++.globl	sha1_block_data_order
++.type	sha1_block_data_order,\@function,3
++.align	16
++sha1_block_data_order:
++	mov	OPENSSL_ia32cap_P+0(%rip),%r9d
++	mov	OPENSSL_ia32cap_P+4(%rip),%r8d
++	mov	OPENSSL_ia32cap_P+8(%rip),%r10d
++	test	\$`1<<9`,%r8d		# check SSSE3 bit
++	jz	.Lialu
++___
++$code.=<<___ if ($shaext);
++	test	\$`1<<29`,%r10d		# check SHA bit	
++	jnz	_shaext_shortcut
++___
++$code.=<<___ if ($avx>1);
++	and	\$`1<<3|1<<5|1<<8`,%r10d	# check AVX2+BMI1+BMI2
++	cmp	\$`1<<3|1<<5|1<<8`,%r10d
++	je	_avx2_shortcut
++___
++$code.=<<___ if ($avx);
++	and	\$`1<<28`,%r8d		# mask AVX bit
++	and	\$`1<<30`,%r9d		# mask "Intel CPU" bit
++	or	%r9d,%r8d
++	cmp	\$`1<<28|1<<30`,%r8d
++	je	_avx_shortcut
++___
++$code.=<<___;
++	jmp	_ssse3_shortcut
++
++.align	16
++.Lialu:
++	mov	%rsp,%rax
++	push	%rbx
++	push	%rbp
++	push	%r12
++	push	%r13
++	push	%r14
++	mov	%rdi,$ctx	# reassigned argument
++	sub	\$`8+16*4`,%rsp
++	mov	%rsi,$inp	# reassigned argument
++	and	\$-64,%rsp
++	mov	%rdx,$num	# reassigned argument
++	mov	%rax,`16*4`(%rsp)
++.Lprologue:
++
++	mov	0($ctx),$A
++	mov	4($ctx),$B
++	mov	8($ctx),$C
++	mov	12($ctx),$D
++	mov	16($ctx),$E
++	jmp	.Lloop
++
++.align	16
++.Lloop:
++___
++for($i=0;$i<20;$i++)	{ &BODY_00_19($i,@V); unshift(@V,pop(@V)); }
++for(;$i<40;$i++)	{ &BODY_20_39($i,@V); unshift(@V,pop(@V)); }
++for(;$i<60;$i++)	{ &BODY_40_59($i,@V); unshift(@V,pop(@V)); }
++for(;$i<80;$i++)	{ &BODY_20_39($i,@V); unshift(@V,pop(@V)); }
++$code.=<<___;
++	add	0($ctx),$A
++	add	4($ctx),$B
++	add	8($ctx),$C
++	add	12($ctx),$D
++	add	16($ctx),$E
++	mov	$A,0($ctx)
++	mov	$B,4($ctx)
++	mov	$C,8($ctx)
++	mov	$D,12($ctx)
++	mov	$E,16($ctx)
++
++	sub	\$1,$num
++	lea	`16*4`($inp),$inp
++	jnz	.Lloop
++
++	mov	`16*4`(%rsp),%rsi
++	mov	-40(%rsi),%r14
++	mov	-32(%rsi),%r13
++	mov	-24(%rsi),%r12
++	mov	-16(%rsi),%rbp
++	mov	-8(%rsi),%rbx
++	lea	(%rsi),%rsp
++.Lepilogue:
++	ret
++.size	sha1_block_data_order,.-sha1_block_data_order
++___
++if ($shaext) {{{
++######################################################################
++# Intel SHA Extensions implementation of SHA1 update function.
++#
++my ($ctx,$inp,$num)=("%rdi","%rsi","%rdx");
++my ($ABCD,$E,$E_,$BSWAP,$ABCD_SAVE,$E_SAVE)=map("%xmm$_",(0..3,8,9));
++my @MSG=map("%xmm$_",(4..7));
++
++$code.=<<___;
++.type	sha1_block_data_order_shaext,\@function,3
++.align	32
++sha1_block_data_order_shaext:
++_shaext_shortcut:
++___
++$code.=<<___ if ($win64);
++	lea	`-8-4*16`(%rsp),%rsp
++	movaps	%xmm6,-8-4*16(%rax)
++	movaps	%xmm7,-8-3*16(%rax)
++	movaps	%xmm8,-8-2*16(%rax)
++	movaps	%xmm9,-8-1*16(%rax)
++.Lprologue_shaext:
++___
++$code.=<<___;
++	movdqu	($ctx),$ABCD
++	movd	16($ctx),$E
++	movdqa	K_XX_XX+0xa0(%rip),$BSWAP	# byte-n-word swap
++
++	movdqu	($inp),@MSG[0]
++	pshufd	\$0b00011011,$ABCD,$ABCD	# flip word order
++	movdqu	0x10($inp),@MSG[1]
++	pshufd	\$0b00011011,$E,$E		# flip word order
++	movdqu	0x20($inp),@MSG[2]
++	pshufb	$BSWAP,@MSG[0]
++	movdqu	0x30($inp),@MSG[3]
++	pshufb	$BSWAP,@MSG[1]
++	pshufb	$BSWAP,@MSG[2]
++	movdqa	$E,$E_SAVE			# offload $E
++	pshufb	$BSWAP,@MSG[3]
++	jmp	.Loop_shaext
++
++.align	16
++.Loop_shaext:
++	dec		$num
++	lea		0x40($inp),%r8		# next input block
++	paddd		@MSG[0],$E
++	cmovne		%r8,$inp
++	movdqa		$ABCD,$ABCD_SAVE	# offload $ABCD
++___
++for($i=0;$i<20-4;$i+=2) {
++$code.=<<___;
++	sha1msg1	@MSG[1],@MSG[0]
++	movdqa		$ABCD,$E_
++	sha1rnds4	\$`int($i/5)`,$E,$ABCD	# 0-3...
++	sha1nexte	@MSG[1],$E_
++	pxor		@MSG[2],@MSG[0]
++	sha1msg1	@MSG[2],@MSG[1]
++	sha1msg2	@MSG[3],@MSG[0]
++
++	movdqa		$ABCD,$E
++	sha1rnds4	\$`int(($i+1)/5)`,$E_,$ABCD
++	sha1nexte	@MSG[2],$E
++	pxor		@MSG[3],@MSG[1]
++	sha1msg2	@MSG[0],@MSG[1]
++___
++	push(@MSG,shift(@MSG));	push(@MSG,shift(@MSG));
++}
++$code.=<<___;
++	movdqu		($inp),@MSG[0]
++	movdqa		$ABCD,$E_
++	sha1rnds4	\$3,$E,$ABCD		# 64-67
++	sha1nexte	@MSG[1],$E_
++	movdqu		0x10($inp),@MSG[1]
++	pshufb		$BSWAP,@MSG[0]
++
++	movdqa		$ABCD,$E
++	sha1rnds4	\$3,$E_,$ABCD		# 68-71
++	sha1nexte	@MSG[2],$E
++	movdqu		0x20($inp),@MSG[2]
++	pshufb		$BSWAP,@MSG[1]
++
++	movdqa		$ABCD,$E_
++	sha1rnds4	\$3,$E,$ABCD		# 72-75
++	sha1nexte	@MSG[3],$E_
++	movdqu		0x30($inp),@MSG[3]
++	pshufb		$BSWAP,@MSG[2]
++
++	movdqa		$ABCD,$E
++	sha1rnds4	\$3,$E_,$ABCD		# 76-79
++	sha1nexte	$E_SAVE,$E
++	pshufb		$BSWAP,@MSG[3]
++
++	paddd		$ABCD_SAVE,$ABCD
++	movdqa		$E,$E_SAVE		# offload $E
++
++	jnz		.Loop_shaext
++
++	pshufd	\$0b00011011,$ABCD,$ABCD
++	pshufd	\$0b00011011,$E,$E
++	movdqu	$ABCD,($ctx)
++	movd	$E,16($ctx)
++___
++$code.=<<___ if ($win64);
++	movaps	-8-4*16(%rax),%xmm6
++	movaps	-8-3*16(%rax),%xmm7
++	movaps	-8-2*16(%rax),%xmm8
++	movaps	-8-1*16(%rax),%xmm9
++	mov	%rax,%rsp
++.Lepilogue_shaext:
++___
++$code.=<<___;
++	ret
++.size	sha1_block_data_order_shaext,.-sha1_block_data_order_shaext
++___
++}}}
++{{{
++my $Xi=4;
++my @X=map("%xmm$_",(4..7,0..3));
++my @Tx=map("%xmm$_",(8..10));
++my $Kx="%xmm11";
++my @V=($A,$B,$C,$D,$E)=("%eax","%ebx","%ecx","%edx","%ebp");	# size optimization
++my @T=("%esi","%edi");
++my $j=0;
++my $rx=0;
++my $K_XX_XX="%r11";
++
++my $_rol=sub { &rol(@_) };
++my $_ror=sub { &ror(@_) };
++
++{ my $sn;
++sub align32() {
++  ++$sn;
++$code.=<<___;
++	jmp	.Lalign32_$sn	# see "Decoded ICache" in manual
++.align	32
++.Lalign32_$sn:
++___
++}
++}
++
++$code.=<<___;
++.type	sha1_block_data_order_ssse3,\@function,3
++.align	16
++sha1_block_data_order_ssse3:
++_ssse3_shortcut:
++	mov	%rsp,%rax
++	push	%rbx
++	push	%rbp
++	push	%r12
++	push	%r13		# redundant, done to share Win64 SE handler
++	push	%r14
++	lea	`-64-($win64?6*16:0)`(%rsp),%rsp
++___
++$code.=<<___ if ($win64);
++	movaps	%xmm6,-40-6*16(%rax)
++	movaps	%xmm7,-40-5*16(%rax)
++	movaps	%xmm8,-40-4*16(%rax)
++	movaps	%xmm9,-40-3*16(%rax)
++	movaps	%xmm10,-40-2*16(%rax)
++	movaps	%xmm11,-40-1*16(%rax)
++.Lprologue_ssse3:
++___
++$code.=<<___;
++	mov	%rax,%r14	# original %rsp
++	and	\$-64,%rsp
++	mov	%rdi,$ctx	# reassigned argument
++	mov	%rsi,$inp	# reassigned argument
++	mov	%rdx,$num	# reassigned argument
++
++	shl	\$6,$num
++	add	$inp,$num
++	lea	K_XX_XX+64(%rip),$K_XX_XX
++
++	mov	0($ctx),$A		# load context
++	mov	4($ctx),$B
++	mov	8($ctx),$C
++	mov	12($ctx),$D
++	mov	$B,@T[0]		# magic seed
++	mov	16($ctx),$E
++	mov	$C,@T[1]
++	xor	$D,@T[1]
++	and	@T[1],@T[0]
++
++	movdqa	64($K_XX_XX),@X[2]	# pbswap mask
++	movdqa	-64($K_XX_XX),@Tx[1]	# K_00_19
++	movdqu	0($inp),@X[-4&7]	# load input to %xmm[0-3]
++	movdqu	16($inp),@X[-3&7]
++	movdqu	32($inp),@X[-2&7]
++	movdqu	48($inp),@X[-1&7]
++	pshufb	@X[2],@X[-4&7]		# byte swap
++	pshufb	@X[2],@X[-3&7]
++	pshufb	@X[2],@X[-2&7]
++	add	\$64,$inp
++	paddd	@Tx[1],@X[-4&7]		# add K_00_19
++	pshufb	@X[2],@X[-1&7]
++	paddd	@Tx[1],@X[-3&7]
++	paddd	@Tx[1],@X[-2&7]
++	movdqa	@X[-4&7],0(%rsp)	# X[]+K xfer to IALU
++	psubd	@Tx[1],@X[-4&7]		# restore X[]
++	movdqa	@X[-3&7],16(%rsp)
++	psubd	@Tx[1],@X[-3&7]
++	movdqa	@X[-2&7],32(%rsp)
++	psubd	@Tx[1],@X[-2&7]
++	jmp	.Loop_ssse3
++___
++
++sub AUTOLOAD()		# thunk [simplified] 32-bit style perlasm
++{ my $opcode = $AUTOLOAD; $opcode =~ s/.*:://;
++  my $arg = pop;
++    $arg = "\$$arg" if ($arg*1 eq $arg);
++    $code .= "\t$opcode\t".join(',',$arg,reverse @_)."\n";
++}
++
++sub Xupdate_ssse3_16_31()		# recall that $Xi starts wtih 4
++{ use integer;
++  my $body = shift;
++  my @insns = (&$body,&$body,&$body,&$body);	# 40 instructions
++  my ($a,$b,$c,$d,$e);
++
++	 eval(shift(@insns));		# ror
++	&pshufd	(@X[0],@X[-4&7],0xee);	# was &movdqa	(@X[0],@X[-3&7]);
++	 eval(shift(@insns));
++	&movdqa	(@Tx[0],@X[-1&7]);
++	  &paddd	(@Tx[1],@X[-1&7]);
++	 eval(shift(@insns));
++	 eval(shift(@insns));
++
++	&punpcklqdq(@X[0],@X[-3&7]);	# compose "X[-14]" in "X[0]", was &palignr(@X[0],@X[-4&7],8);
++	 eval(shift(@insns));
++	 eval(shift(@insns));		# rol
++	 eval(shift(@insns));
++	&psrldq	(@Tx[0],4);		# "X[-3]", 3 dwords
++	 eval(shift(@insns));
++	 eval(shift(@insns));
++
++	&pxor	(@X[0],@X[-4&7]);	# "X[0]"^="X[-16]"
++	 eval(shift(@insns));
++	 eval(shift(@insns));		# ror
++	&pxor	(@Tx[0],@X[-2&7]);	# "X[-3]"^"X[-8]"
++	 eval(shift(@insns));
++	 eval(shift(@insns));
++	 eval(shift(@insns));
++
++	&pxor	(@X[0],@Tx[0]);		# "X[0]"^="X[-3]"^"X[-8]"
++	 eval(shift(@insns));
++	 eval(shift(@insns));		# rol
++	  &movdqa	(eval(16*(($Xi-1)&3))."(%rsp)",@Tx[1]);	# X[]+K xfer to IALU
++	 eval(shift(@insns));
++	 eval(shift(@insns));
++
++	&movdqa	(@Tx[2],@X[0]);
++	 eval(shift(@insns));
++	 eval(shift(@insns));
++	 eval(shift(@insns));		# ror
++	&movdqa	(@Tx[0],@X[0]);
++	 eval(shift(@insns));
++
++	&pslldq	(@Tx[2],12);		# "X[0]"<<96, extract one dword
++	&paddd	(@X[0],@X[0]);
++	 eval(shift(@insns));
++	 eval(shift(@insns));
++
++	&psrld	(@Tx[0],31);
++	 eval(shift(@insns));
++	 eval(shift(@insns));		# rol
++	 eval(shift(@insns));
++	&movdqa	(@Tx[1],@Tx[2]);
++	 eval(shift(@insns));
++	 eval(shift(@insns));
++
++	&psrld	(@Tx[2],30);
++	 eval(shift(@insns));
++	 eval(shift(@insns));		# ror
++	&por	(@X[0],@Tx[0]);		# "X[0]"<<<=1
++	 eval(shift(@insns));
++	 eval(shift(@insns));
++	 eval(shift(@insns));
++
++	&pslld	(@Tx[1],2);
++	&pxor	(@X[0],@Tx[2]);
++	 eval(shift(@insns));
++	  &movdqa	(@Tx[2],eval(2*16*(($Xi)/5)-64)."($K_XX_XX)");	# K_XX_XX
++	 eval(shift(@insns));		# rol
++	 eval(shift(@insns));
++	 eval(shift(@insns));
++
++	&pxor	(@X[0],@Tx[1]);		# "X[0]"^=("X[0]">>96)<<<2
++	&pshufd (@Tx[1],@X[-1&7],0xee)	if ($Xi==7);	# was &movdqa	(@Tx[0],@X[-1&7]) in Xupdate_ssse3_32_79
++
++	 foreach (@insns) { eval; }	# remaining instructions [if any]
++
++  $Xi++;	push(@X,shift(@X));	# "rotate" X[]
++		push(@Tx,shift(@Tx));
++}
++
++sub Xupdate_ssse3_32_79()
++{ use integer;
++  my $body = shift;
++  my @insns = (&$body,&$body,&$body,&$body);	# 32 to 44 instructions
++  my ($a,$b,$c,$d,$e);
++
++	 eval(shift(@insns))		if ($Xi==8);
++	&pxor	(@X[0],@X[-4&7]);	# "X[0]"="X[-32]"^"X[-16]"
++	 eval(shift(@insns))		if ($Xi==8);
++	 eval(shift(@insns));		# body_20_39
++	 eval(shift(@insns));
++	 eval(shift(@insns))		if (@insns[1] =~ /_ror/);
++	 eval(shift(@insns))		if (@insns[0] =~ /_ror/);
++	&punpcklqdq(@Tx[0],@X[-1&7]);	# compose "X[-6]", was &palignr(@Tx[0],@X[-2&7],8);
++	 eval(shift(@insns));
++	 eval(shift(@insns));		# rol
++
++	&pxor	(@X[0],@X[-7&7]);	# "X[0]"^="X[-28]"
++	 eval(shift(@insns));
++	 eval(shift(@insns));
++	if ($Xi%5) {
++	  &movdqa	(@Tx[2],@Tx[1]);# "perpetuate" K_XX_XX...
++	} else {			# ... or load next one
++	  &movdqa	(@Tx[2],eval(2*16*($Xi/5)-64)."($K_XX_XX)");
++	}
++	 eval(shift(@insns));		# ror
++	  &paddd	(@Tx[1],@X[-1&7]);
++	 eval(shift(@insns));
++
++	&pxor	(@X[0],@Tx[0]);		# "X[0]"^="X[-6]"
++	 eval(shift(@insns));		# body_20_39
++	 eval(shift(@insns));
++	 eval(shift(@insns));
++	 eval(shift(@insns));		# rol
++	 eval(shift(@insns))		if (@insns[0] =~ /_ror/);
++
++	&movdqa	(@Tx[0],@X[0]);
++	 eval(shift(@insns));
++	 eval(shift(@insns));
++	  &movdqa	(eval(16*(($Xi-1)&3))."(%rsp)",@Tx[1]);	# X[]+K xfer to IALU
++	 eval(shift(@insns));		# ror
++	 eval(shift(@insns));
++	 eval(shift(@insns));		# body_20_39
++
++	&pslld	(@X[0],2);
++	 eval(shift(@insns));
++	 eval(shift(@insns));
++	&psrld	(@Tx[0],30);
++	 eval(shift(@insns))		if (@insns[0] =~ /_rol/);# rol
++	 eval(shift(@insns));
++	 eval(shift(@insns));
++	 eval(shift(@insns));		# ror
++
++	&por	(@X[0],@Tx[0]);		# "X[0]"<<<=2
++	 eval(shift(@insns));
++	 eval(shift(@insns));		# body_20_39
++	 eval(shift(@insns))		if (@insns[1] =~ /_rol/);
++	 eval(shift(@insns))		if (@insns[0] =~ /_rol/);
++	  &pshufd(@Tx[1],@X[-1&7],0xee)	if ($Xi<19);	# was &movdqa	(@Tx[1],@X[0])
++	 eval(shift(@insns));
++	 eval(shift(@insns));		# rol
++	 eval(shift(@insns));
++	 eval(shift(@insns));
++	 eval(shift(@insns));		# rol
++	 eval(shift(@insns));
++
++	 foreach (@insns) { eval; }	# remaining instructions
++
++  $Xi++;	push(@X,shift(@X));	# "rotate" X[]
++		push(@Tx,shift(@Tx));
++}
++
++sub Xuplast_ssse3_80()
++{ use integer;
++  my $body = shift;
++  my @insns = (&$body,&$body,&$body,&$body);	# 32 instructions
++  my ($a,$b,$c,$d,$e);
++
++	 eval(shift(@insns));
++	 eval(shift(@insns));
++	 eval(shift(@insns));
++	 eval(shift(@insns));
++	  &paddd	(@Tx[1],@X[-1&7]);
++	 eval(shift(@insns));
++	 eval(shift(@insns));
++
++	  &movdqa	(eval(16*(($Xi-1)&3))."(%rsp)",@Tx[1]);	# X[]+K xfer IALU
++
++	 foreach (@insns) { eval; }		# remaining instructions
++
++	&cmp	($inp,$num);
++	&je	(".Ldone_ssse3");
++
++	unshift(@Tx,pop(@Tx));
++
++	&movdqa	(@X[2],"64($K_XX_XX)");		# pbswap mask
++	&movdqa	(@Tx[1],"-64($K_XX_XX)");	# K_00_19
++	&movdqu	(@X[-4&7],"0($inp)");		# load input
++	&movdqu	(@X[-3&7],"16($inp)");
++	&movdqu	(@X[-2&7],"32($inp)");
++	&movdqu	(@X[-1&7],"48($inp)");
++	&pshufb	(@X[-4&7],@X[2]);		# byte swap
++	&add	($inp,64);
++
++  $Xi=0;
++}
++
++sub Xloop_ssse3()
++{ use integer;
++  my $body = shift;
++  my @insns = (&$body,&$body,&$body,&$body);	# 32 instructions
++  my ($a,$b,$c,$d,$e);
++
++	 eval(shift(@insns));
++	 eval(shift(@insns));
++	 eval(shift(@insns));
++	&pshufb	(@X[($Xi-3)&7],@X[2]);
++	 eval(shift(@insns));
++	 eval(shift(@insns));
++	 eval(shift(@insns));
++	 eval(shift(@insns));
++	&paddd	(@X[($Xi-4)&7],@Tx[1]);
++	 eval(shift(@insns));
++	 eval(shift(@insns));
++	 eval(shift(@insns));
++	 eval(shift(@insns));
++	&movdqa	(eval(16*$Xi)."(%rsp)",@X[($Xi-4)&7]);	# X[]+K xfer to IALU
++	 eval(shift(@insns));
++	 eval(shift(@insns));
++	 eval(shift(@insns));
++	 eval(shift(@insns));
++	&psubd	(@X[($Xi-4)&7],@Tx[1]);
++
++	foreach (@insns) { eval; }
++  $Xi++;
++}
++
++sub Xtail_ssse3()
++{ use integer;
++  my $body = shift;
++  my @insns = (&$body,&$body,&$body,&$body);	# 32 instructions
++  my ($a,$b,$c,$d,$e);
++
++	foreach (@insns) { eval; }
++}
++
++sub body_00_19 () {	# ((c^d)&b)^d
++	# on start @T[0]=(c^d)&b
++	return &body_20_39() if ($rx==19); $rx++;
++	(
++	'($a,$b,$c,$d,$e)=@V;'.
++	'&$_ror	($b,$j?7:2)',	# $b>>>2
++	'&xor	(@T[0],$d)',
++	'&mov	(@T[1],$a)',	# $b for next round
++
++	'&add	($e,eval(4*($j&15))."(%rsp)")',	# X[]+K xfer
++	'&xor	($b,$c)',	# $c^$d for next round
++
++	'&$_rol	($a,5)',
++	'&add	($e,@T[0])',
++	'&and	(@T[1],$b)',	# ($b&($c^$d)) for next round
++
++	'&xor	($b,$c)',	# restore $b
++	'&add	($e,$a);'	.'$j++; unshift(@V,pop(@V)); unshift(@T,pop(@T));'
++	);
++}
++
++sub body_20_39 () {	# b^d^c
++	# on entry @T[0]=b^d
++	return &body_40_59() if ($rx==39); $rx++;
++	(
++	'($a,$b,$c,$d,$e)=@V;'.
++	'&add	($e,eval(4*($j&15))."(%rsp)")',	# X[]+K xfer
++	'&xor	(@T[0],$d)	if($j==19);'.
++	'&xor	(@T[0],$c)	if($j> 19)',	# ($b^$d^$c)
++	'&mov	(@T[1],$a)',	# $b for next round
++
++	'&$_rol	($a,5)',
++	'&add	($e,@T[0])',
++	'&xor	(@T[1],$c)	if ($j< 79)',	# $b^$d for next round
++
++	'&$_ror	($b,7)',	# $b>>>2
++	'&add	($e,$a);'	.'$j++; unshift(@V,pop(@V)); unshift(@T,pop(@T));'
++	);
++}
++
++sub body_40_59 () {	# ((b^c)&(c^d))^c
++	# on entry @T[0]=(b^c), (c^=d)
++	$rx++;
++	(
++	'($a,$b,$c,$d,$e)=@V;'.
++	'&add	($e,eval(4*($j&15))."(%rsp)")',	# X[]+K xfer
++	'&and	(@T[0],$c)	if ($j>=40)',	# (b^c)&(c^d)
++	'&xor	($c,$d)		if ($j>=40)',	# restore $c
++
++	'&$_ror	($b,7)',	# $b>>>2
++	'&mov	(@T[1],$a)',	# $b for next round
++	'&xor	(@T[0],$c)',
++
++	'&$_rol	($a,5)',
++	'&add	($e,@T[0])',
++	'&xor	(@T[1],$c)	if ($j==59);'.
++	'&xor	(@T[1],$b)	if ($j< 59)',	# b^c for next round
++
++	'&xor	($b,$c)		if ($j< 59)',	# c^d for next round
++	'&add	($e,$a);'	.'$j++; unshift(@V,pop(@V)); unshift(@T,pop(@T));'
++	);
++}
++$code.=<<___;
++.align	16
++.Loop_ssse3:
++___
++	&Xupdate_ssse3_16_31(\&body_00_19);
++	&Xupdate_ssse3_16_31(\&body_00_19);
++	&Xupdate_ssse3_16_31(\&body_00_19);
++	&Xupdate_ssse3_16_31(\&body_00_19);
++	&Xupdate_ssse3_32_79(\&body_00_19);
++	&Xupdate_ssse3_32_79(\&body_20_39);
++	&Xupdate_ssse3_32_79(\&body_20_39);
++	&Xupdate_ssse3_32_79(\&body_20_39);
++	&Xupdate_ssse3_32_79(\&body_20_39);
++	&Xupdate_ssse3_32_79(\&body_20_39);
++	&Xupdate_ssse3_32_79(\&body_40_59);
++	&Xupdate_ssse3_32_79(\&body_40_59);
++	&Xupdate_ssse3_32_79(\&body_40_59);
++	&Xupdate_ssse3_32_79(\&body_40_59);
++	&Xupdate_ssse3_32_79(\&body_40_59);
++	&Xupdate_ssse3_32_79(\&body_20_39);
++	&Xuplast_ssse3_80(\&body_20_39);	# can jump to "done"
++
++				$saved_j=$j; @saved_V=@V;
++
++	&Xloop_ssse3(\&body_20_39);
++	&Xloop_ssse3(\&body_20_39);
++	&Xloop_ssse3(\&body_20_39);
++
++$code.=<<___;
++	add	0($ctx),$A			# update context
++	add	4($ctx),@T[0]
++	add	8($ctx),$C
++	add	12($ctx),$D
++	mov	$A,0($ctx)
++	add	16($ctx),$E
++	mov	@T[0],4($ctx)
++	mov	@T[0],$B			# magic seed
++	mov	$C,8($ctx)
++	mov	$C,@T[1]
++	mov	$D,12($ctx)
++	xor	$D,@T[1]
++	mov	$E,16($ctx)
++	and	@T[1],@T[0]
++	jmp	.Loop_ssse3
++
++.align	16
++.Ldone_ssse3:
++___
++				$j=$saved_j; @V=@saved_V;
++
++	&Xtail_ssse3(\&body_20_39);
++	&Xtail_ssse3(\&body_20_39);
++	&Xtail_ssse3(\&body_20_39);
++
++$code.=<<___;
++	add	0($ctx),$A			# update context
++	add	4($ctx),@T[0]
++	add	8($ctx),$C
++	mov	$A,0($ctx)
++	add	12($ctx),$D
++	mov	@T[0],4($ctx)
++	add	16($ctx),$E
++	mov	$C,8($ctx)
++	mov	$D,12($ctx)
++	mov	$E,16($ctx)
++___
++$code.=<<___ if ($win64);
++	movaps	-40-6*16(%r14),%xmm6
++	movaps	-40-5*16(%r14),%xmm7
++	movaps	-40-4*16(%r14),%xmm8
++	movaps	-40-3*16(%r14),%xmm9
++	movaps	-40-2*16(%r14),%xmm10
++	movaps	-40-1*16(%r14),%xmm11
++___
++$code.=<<___;
++	lea	(%r14),%rsi
++	mov	-40(%rsi),%r14
++	mov	-32(%rsi),%r13
++	mov	-24(%rsi),%r12
++	mov	-16(%rsi),%rbp
++	mov	-8(%rsi),%rbx
++	lea	(%rsi),%rsp
++.Lepilogue_ssse3:
++	ret
++.size	sha1_block_data_order_ssse3,.-sha1_block_data_order_ssse3
++___
++
++if ($avx) {
++$Xi=4;				# reset variables
++@X=map("%xmm$_",(4..7,0..3));
++@Tx=map("%xmm$_",(8..10));
++$j=0;
++$rx=0;
++
++my $done_avx_label=".Ldone_avx";
++
++my $_rol=sub { &shld(@_[0],@_) };
++my $_ror=sub { &shrd(@_[0],@_) };
++
++$code.=<<___;
++.type	sha1_block_data_order_avx,\@function,3
++.align	16
++sha1_block_data_order_avx:
++_avx_shortcut:
++	mov	%rsp,%rax
++	push	%rbx
++	push	%rbp
++	push	%r12
++	push	%r13		# redundant, done to share Win64 SE handler
++	push	%r14
++	lea	`-64-($win64?6*16:0)`(%rsp),%rsp
++	vzeroupper
++___
++$code.=<<___ if ($win64);
++	vmovaps	%xmm6,-40-6*16(%rax)
++	vmovaps	%xmm7,-40-5*16(%rax)
++	vmovaps	%xmm8,-40-4*16(%rax)
++	vmovaps	%xmm9,-40-3*16(%rax)
++	vmovaps	%xmm10,-40-2*16(%rax)
++	vmovaps	%xmm11,-40-1*16(%rax)
++.Lprologue_avx:
++___
++$code.=<<___;
++	mov	%rax,%r14	# original %rsp
++	and	\$-64,%rsp
++	mov	%rdi,$ctx	# reassigned argument
++	mov	%rsi,$inp	# reassigned argument
++	mov	%rdx,$num	# reassigned argument
++
++	shl	\$6,$num
++	add	$inp,$num
++	lea	K_XX_XX+64(%rip),$K_XX_XX
++
++	mov	0($ctx),$A		# load context
++	mov	4($ctx),$B
++	mov	8($ctx),$C
++	mov	12($ctx),$D
++	mov	$B,@T[0]		# magic seed
++	mov	16($ctx),$E
++	mov	$C,@T[1]
++	xor	$D,@T[1]
++	and	@T[1],@T[0]
++
++	vmovdqa	64($K_XX_XX),@X[2]	# pbswap mask
++	vmovdqa	-64($K_XX_XX),$Kx	# K_00_19
++	vmovdqu	0($inp),@X[-4&7]	# load input to %xmm[0-3]
++	vmovdqu	16($inp),@X[-3&7]
++	vmovdqu	32($inp),@X[-2&7]
++	vmovdqu	48($inp),@X[-1&7]
++	vpshufb	@X[2],@X[-4&7],@X[-4&7]	# byte swap
++	add	\$64,$inp
++	vpshufb	@X[2],@X[-3&7],@X[-3&7]
++	vpshufb	@X[2],@X[-2&7],@X[-2&7]
++	vpshufb	@X[2],@X[-1&7],@X[-1&7]
++	vpaddd	$Kx,@X[-4&7],@X[0]	# add K_00_19
++	vpaddd	$Kx,@X[-3&7],@X[1]
++	vpaddd	$Kx,@X[-2&7],@X[2]
++	vmovdqa	@X[0],0(%rsp)		# X[]+K xfer to IALU
++	vmovdqa	@X[1],16(%rsp)
++	vmovdqa	@X[2],32(%rsp)
++	jmp	.Loop_avx
++___
++
++sub Xupdate_avx_16_31()		# recall that $Xi starts wtih 4
++{ use integer;
++  my $body = shift;
++  my @insns = (&$body,&$body,&$body,&$body);	# 40 instructions
++  my ($a,$b,$c,$d,$e);
++
++	 eval(shift(@insns));
++	 eval(shift(@insns));
++	&vpalignr(@X[0],@X[-3&7],@X[-4&7],8);	# compose "X[-14]" in "X[0]"
++	 eval(shift(@insns));
++	 eval(shift(@insns));
++
++	  &vpaddd	(@Tx[1],$Kx,@X[-1&7]);
++	 eval(shift(@insns));
++	 eval(shift(@insns));
++	&vpsrldq(@Tx[0],@X[-1&7],4);		# "X[-3]", 3 dwords
++	 eval(shift(@insns));
++	 eval(shift(@insns));
++	&vpxor	(@X[0],@X[0],@X[-4&7]);		# "X[0]"^="X[-16]"
++	 eval(shift(@insns));
++	 eval(shift(@insns));
++
++	&vpxor	(@Tx[0],@Tx[0],@X[-2&7]);	# "X[-3]"^"X[-8]"
++	 eval(shift(@insns));
++	 eval(shift(@insns));
++	 eval(shift(@insns));
++	 eval(shift(@insns));
++
++	&vpxor	(@X[0],@X[0],@Tx[0]);		# "X[0]"^="X[-3]"^"X[-8]"
++	 eval(shift(@insns));
++	 eval(shift(@insns));
++	  &vmovdqa	(eval(16*(($Xi-1)&3))."(%rsp)",@Tx[1]);	# X[]+K xfer to IALU
++	 eval(shift(@insns));
++	 eval(shift(@insns));
++
++	&vpsrld	(@Tx[0],@X[0],31);
++	 eval(shift(@insns));
++	 eval(shift(@insns));
++	 eval(shift(@insns));
++	 eval(shift(@insns));
++
++	&vpslldq(@Tx[2],@X[0],12);		# "X[0]"<<96, extract one dword
++	&vpaddd	(@X[0],@X[0],@X[0]);
++	 eval(shift(@insns));
++	 eval(shift(@insns));
++	 eval(shift(@insns));
++	 eval(shift(@insns));
++
++	&vpsrld	(@Tx[1],@Tx[2],30);
++	&vpor	(@X[0],@X[0],@Tx[0]);		# "X[0]"<<<=1
++	 eval(shift(@insns));
++	 eval(shift(@insns));
++	 eval(shift(@insns));
++	 eval(shift(@insns));
++
++	&vpslld	(@Tx[2],@Tx[2],2);
++	&vpxor	(@X[0],@X[0],@Tx[1]);
++	 eval(shift(@insns));
++	 eval(shift(@insns));
++	 eval(shift(@insns));
++	 eval(shift(@insns));
++
++	&vpxor	(@X[0],@X[0],@Tx[2]);		# "X[0]"^=("X[0]">>96)<<<2
++	 eval(shift(@insns));
++	 eval(shift(@insns));
++	  &vmovdqa	($Kx,eval(2*16*(($Xi)/5)-64)."($K_XX_XX)")	if ($Xi%5==0);	# K_XX_XX
++	 eval(shift(@insns));
++	 eval(shift(@insns));
++
++
++	 foreach (@insns) { eval; }	# remaining instructions [if any]
++
++  $Xi++;	push(@X,shift(@X));	# "rotate" X[]
++}
++
++sub Xupdate_avx_32_79()
++{ use integer;
++  my $body = shift;
++  my @insns = (&$body,&$body,&$body,&$body);	# 32 to 44 instructions
++  my ($a,$b,$c,$d,$e);
++
++	&vpalignr(@Tx[0],@X[-1&7],@X[-2&7],8);	# compose "X[-6]"
++	&vpxor	(@X[0],@X[0],@X[-4&7]);		# "X[0]"="X[-32]"^"X[-16]"
++	 eval(shift(@insns));		# body_20_39
++	 eval(shift(@insns));
++	 eval(shift(@insns));
++	 eval(shift(@insns));		# rol
++
++	&vpxor	(@X[0],@X[0],@X[-7&7]);		# "X[0]"^="X[-28]"
++	 eval(shift(@insns));
++	 eval(shift(@insns))	if (@insns[0] !~ /&ro[rl]/);
++	  &vpaddd	(@Tx[1],$Kx,@X[-1&7]);
++	  &vmovdqa	($Kx,eval(2*16*($Xi/5)-64)."($K_XX_XX)")	if ($Xi%5==0);
++	 eval(shift(@insns));		# ror
++	 eval(shift(@insns));
++
++	&vpxor	(@X[0],@X[0],@Tx[0]);		# "X[0]"^="X[-6]"
++	 eval(shift(@insns));		# body_20_39
++	 eval(shift(@insns));
++	 eval(shift(@insns));
++	 eval(shift(@insns));		# rol
++
++	&vpsrld	(@Tx[0],@X[0],30);
++	  &vmovdqa	(eval(16*(($Xi-1)&3))."(%rsp)",@Tx[1]);	# X[]+K xfer to IALU
++	 eval(shift(@insns));
++	 eval(shift(@insns));
++	 eval(shift(@insns));		# ror
++	 eval(shift(@insns));
++
++	&vpslld	(@X[0],@X[0],2);
++	 eval(shift(@insns));		# body_20_39
++	 eval(shift(@insns));
++	 eval(shift(@insns));
++	 eval(shift(@insns));		# rol
++	 eval(shift(@insns));
++	 eval(shift(@insns));
++	 eval(shift(@insns));		# ror
++	 eval(shift(@insns));
++
++	&vpor	(@X[0],@X[0],@Tx[0]);		# "X[0]"<<<=2
++	 eval(shift(@insns));		# body_20_39
++	 eval(shift(@insns));
++	 eval(shift(@insns));
++	 eval(shift(@insns));		# rol
++	 eval(shift(@insns));
++	 eval(shift(@insns));
++	 eval(shift(@insns));		# rol
++	 eval(shift(@insns));
++
++	 foreach (@insns) { eval; }	# remaining instructions
++
++  $Xi++;	push(@X,shift(@X));	# "rotate" X[]
++}
++
++sub Xuplast_avx_80()
++{ use integer;
++  my $body = shift;
++  my @insns = (&$body,&$body,&$body,&$body);	# 32 instructions
++  my ($a,$b,$c,$d,$e);
++
++	 eval(shift(@insns));
++	  &vpaddd	(@Tx[1],$Kx,@X[-1&7]);
++	 eval(shift(@insns));
++	 eval(shift(@insns));
++	 eval(shift(@insns));
++	 eval(shift(@insns));
++
++	  &vmovdqa	(eval(16*(($Xi-1)&3))."(%rsp)",@Tx[1]);	# X[]+K xfer IALU
++
++	 foreach (@insns) { eval; }		# remaining instructions
++
++	&cmp	($inp,$num);
++	&je	($done_avx_label);
++
++	&vmovdqa(@X[2],"64($K_XX_XX)");		# pbswap mask
++	&vmovdqa($Kx,"-64($K_XX_XX)");		# K_00_19
++	&vmovdqu(@X[-4&7],"0($inp)");		# load input
++	&vmovdqu(@X[-3&7],"16($inp)");
++	&vmovdqu(@X[-2&7],"32($inp)");
++	&vmovdqu(@X[-1&7],"48($inp)");
++	&vpshufb(@X[-4&7],@X[-4&7],@X[2]);	# byte swap
++	&add	($inp,64);
++
++  $Xi=0;
++}
++
++sub Xloop_avx()
++{ use integer;
++  my $body = shift;
++  my @insns = (&$body,&$body,&$body,&$body);	# 32 instructions
++  my ($a,$b,$c,$d,$e);
++
++	 eval(shift(@insns));
++	 eval(shift(@insns));
++	&vpshufb(@X[($Xi-3)&7],@X[($Xi-3)&7],@X[2]);
++	 eval(shift(@insns));
++	 eval(shift(@insns));
++	&vpaddd	(@X[$Xi&7],@X[($Xi-4)&7],$Kx);
++	 eval(shift(@insns));
++	 eval(shift(@insns));
++	 eval(shift(@insns));
++	 eval(shift(@insns));
++	&vmovdqa(eval(16*$Xi)."(%rsp)",@X[$Xi&7]);	# X[]+K xfer to IALU
++	 eval(shift(@insns));
++	 eval(shift(@insns));
++
++	foreach (@insns) { eval; }
++  $Xi++;
++}
++
++sub Xtail_avx()
++{ use integer;
++  my $body = shift;
++  my @insns = (&$body,&$body,&$body,&$body);	# 32 instructions
++  my ($a,$b,$c,$d,$e);
++
++	foreach (@insns) { eval; }
++}
++
++$code.=<<___;
++.align	16
++.Loop_avx:
++___
++	&Xupdate_avx_16_31(\&body_00_19);
++	&Xupdate_avx_16_31(\&body_00_19);
++	&Xupdate_avx_16_31(\&body_00_19);
++	&Xupdate_avx_16_31(\&body_00_19);
++	&Xupdate_avx_32_79(\&body_00_19);
++	&Xupdate_avx_32_79(\&body_20_39);
++	&Xupdate_avx_32_79(\&body_20_39);
++	&Xupdate_avx_32_79(\&body_20_39);
++	&Xupdate_avx_32_79(\&body_20_39);
++	&Xupdate_avx_32_79(\&body_20_39);
++	&Xupdate_avx_32_79(\&body_40_59);
++	&Xupdate_avx_32_79(\&body_40_59);
++	&Xupdate_avx_32_79(\&body_40_59);
++	&Xupdate_avx_32_79(\&body_40_59);
++	&Xupdate_avx_32_79(\&body_40_59);
++	&Xupdate_avx_32_79(\&body_20_39);
++	&Xuplast_avx_80(\&body_20_39);	# can jump to "done"
++
++				$saved_j=$j; @saved_V=@V;
++
++	&Xloop_avx(\&body_20_39);
++	&Xloop_avx(\&body_20_39);
++	&Xloop_avx(\&body_20_39);
++
++$code.=<<___;
++	add	0($ctx),$A			# update context
++	add	4($ctx),@T[0]
++	add	8($ctx),$C
++	add	12($ctx),$D
++	mov	$A,0($ctx)
++	add	16($ctx),$E
++	mov	@T[0],4($ctx)
++	mov	@T[0],$B			# magic seed
++	mov	$C,8($ctx)
++	mov	$C,@T[1]
++	mov	$D,12($ctx)
++	xor	$D,@T[1]
++	mov	$E,16($ctx)
++	and	@T[1],@T[0]
++	jmp	.Loop_avx
++
++.align	16
++$done_avx_label:
++___
++				$j=$saved_j; @V=@saved_V;
++
++	&Xtail_avx(\&body_20_39);
++	&Xtail_avx(\&body_20_39);
++	&Xtail_avx(\&body_20_39);
++
++$code.=<<___;
++	vzeroupper
++
++	add	0($ctx),$A			# update context
++	add	4($ctx),@T[0]
++	add	8($ctx),$C
++	mov	$A,0($ctx)
++	add	12($ctx),$D
++	mov	@T[0],4($ctx)
++	add	16($ctx),$E
++	mov	$C,8($ctx)
++	mov	$D,12($ctx)
++	mov	$E,16($ctx)
++___
++$code.=<<___ if ($win64);
++	movaps	-40-6*16(%r14),%xmm6
++	movaps	-40-5*16(%r14),%xmm7
++	movaps	-40-4*16(%r14),%xmm8
++	movaps	-40-3*16(%r14),%xmm9
++	movaps	-40-2*16(%r14),%xmm10
++	movaps	-40-1*16(%r14),%xmm11
++___
++$code.=<<___;
++	lea	(%r14),%rsi
++	mov	-40(%rsi),%r14
++	mov	-32(%rsi),%r13
++	mov	-24(%rsi),%r12
++	mov	-16(%rsi),%rbp
++	mov	-8(%rsi),%rbx
++	lea	(%rsi),%rsp
++.Lepilogue_avx:
++	ret
++.size	sha1_block_data_order_avx,.-sha1_block_data_order_avx
++___
++
++if ($avx>1) {
++use integer;
++$Xi=4;					# reset variables
++@X=map("%ymm$_",(4..7,0..3));
++@Tx=map("%ymm$_",(8..10));
++$Kx="%ymm11";
++$j=0;
++
++my @ROTX=("%eax","%ebp","%ebx","%ecx","%edx","%esi");
++my ($a5,$t0)=("%r12d","%edi");
++
++my ($A,$F,$B,$C,$D,$E)=@ROTX;
++my $rx=0;
++my $frame="%r13";
++
++$code.=<<___;
++.type	sha1_block_data_order_avx2,\@function,3
++.align	16
++sha1_block_data_order_avx2:
++_avx2_shortcut:
++	mov	%rsp,%rax
++	push	%rbx
++	push	%rbp
++	push	%r12
++	push	%r13
++	push	%r14
++	vzeroupper
++___
++$code.=<<___ if ($win64);
++	lea	-6*16(%rsp),%rsp
++	vmovaps	%xmm6,-40-6*16(%rax)
++	vmovaps	%xmm7,-40-5*16(%rax)
++	vmovaps	%xmm8,-40-4*16(%rax)
++	vmovaps	%xmm9,-40-3*16(%rax)
++	vmovaps	%xmm10,-40-2*16(%rax)
++	vmovaps	%xmm11,-40-1*16(%rax)
++.Lprologue_avx2:
++___
++$code.=<<___;
++	mov	%rax,%r14		# original %rsp
++	mov	%rdi,$ctx		# reassigned argument
++	mov	%rsi,$inp		# reassigned argument
++	mov	%rdx,$num		# reassigned argument
++
++	lea	-640(%rsp),%rsp
++	shl	\$6,$num
++	 lea	64($inp),$frame
++	and	\$-128,%rsp
++	add	$inp,$num
++	lea	K_XX_XX+64(%rip),$K_XX_XX
++
++	mov	0($ctx),$A		# load context
++	 cmp	$num,$frame
++	 cmovae	$inp,$frame		# next or same block
++	mov	4($ctx),$F
++	mov	8($ctx),$C
++	mov	12($ctx),$D
++	mov	16($ctx),$E
++	vmovdqu	64($K_XX_XX),@X[2]	# pbswap mask
++
++	vmovdqu		($inp),%xmm0
++	vmovdqu		16($inp),%xmm1
++	vmovdqu		32($inp),%xmm2
++	vmovdqu		48($inp),%xmm3
++	lea		64($inp),$inp
++	vinserti128	\$1,($frame),@X[-4&7],@X[-4&7]
++	vinserti128	\$1,16($frame),@X[-3&7],@X[-3&7]
++	vpshufb		@X[2],@X[-4&7],@X[-4&7]
++	vinserti128	\$1,32($frame),@X[-2&7],@X[-2&7]
++	vpshufb		@X[2],@X[-3&7],@X[-3&7]
++	vinserti128	\$1,48($frame),@X[-1&7],@X[-1&7]
++	vpshufb		@X[2],@X[-2&7],@X[-2&7]
++	vmovdqu		-64($K_XX_XX),$Kx	# K_00_19
++	vpshufb		@X[2],@X[-1&7],@X[-1&7]
++
++	vpaddd	$Kx,@X[-4&7],@X[0]	# add K_00_19
++	vpaddd	$Kx,@X[-3&7],@X[1]
++	vmovdqu	@X[0],0(%rsp)		# X[]+K xfer to IALU
++	vpaddd	$Kx,@X[-2&7],@X[2]
++	vmovdqu	@X[1],32(%rsp)
++	vpaddd	$Kx,@X[-1&7],@X[3]
++	vmovdqu	@X[2],64(%rsp)
++	vmovdqu	@X[3],96(%rsp)
++___
++for (;$Xi<8;$Xi++) {	# Xupdate_avx2_16_31
++    use integer;
++
++	&vpalignr(@X[0],@X[-3&7],@X[-4&7],8);	# compose "X[-14]" in "X[0]"
++	&vpsrldq(@Tx[0],@X[-1&7],4);		# "X[-3]", 3 dwords
++	&vpxor	(@X[0],@X[0],@X[-4&7]);		# "X[0]"^="X[-16]"
++	&vpxor	(@Tx[0],@Tx[0],@X[-2&7]);	# "X[-3]"^"X[-8]"
++	&vpxor	(@X[0],@X[0],@Tx[0]);		# "X[0]"^="X[-3]"^"X[-8]"
++	&vpsrld	(@Tx[0],@X[0],31);
++	&vmovdqu($Kx,eval(2*16*(($Xi)/5)-64)."($K_XX_XX)")	if ($Xi%5==0);	# K_XX_XX
++	&vpslldq(@Tx[2],@X[0],12);		# "X[0]"<<96, extract one dword
++	&vpaddd	(@X[0],@X[0],@X[0]);
++	&vpsrld	(@Tx[1],@Tx[2],30);
++	&vpor	(@X[0],@X[0],@Tx[0]);		# "X[0]"<<<=1
++	&vpslld	(@Tx[2],@Tx[2],2);
++	&vpxor	(@X[0],@X[0],@Tx[1]);
++	&vpxor	(@X[0],@X[0],@Tx[2]);		# "X[0]"^=("X[0]">>96)<<<2
++	&vpaddd	(@Tx[1],@X[0],$Kx);
++	&vmovdqu("32*$Xi(%rsp)",@Tx[1]);	# X[]+K xfer to IALU
++
++	push(@X,shift(@X));	# "rotate" X[]
++}
++$code.=<<___;
++	lea	128(%rsp),$frame
++	jmp	.Loop_avx2
++.align	32
++.Loop_avx2:
++	rorx	\$2,$F,$B
++	andn	$D,$F,$t0
++	and	$C,$F
++	xor	$t0,$F
++___
++sub bodyx_00_19 () {	# 8 instructions, 3 cycles critical path
++	# at start $f=(b&c)^(~b&d), $b>>>=2
++	return &bodyx_20_39() if ($rx==19); $rx++;
++	(
++	'($a,$f,$b,$c,$d,$e)=@ROTX;'.
++
++	'&add	($e,((32*($j/4)+4*($j%4))%256-128)."($frame)");'.	# e+=X[i]+K
++	 '&lea	($frame,"256($frame)")	if ($j%32==31);',
++	'&andn	($t0,$a,$c)',			# ~b&d for next round
++
++	'&add	($e,$f)',			# e+=(b&c)^(~b&d)
++	'&rorx	($a5,$a,27)',			# a<<<5
++	'&rorx	($f,$a,2)',			# b>>>2 for next round
++	'&and	($a,$b)',			# b&c for next round
++
++	'&add	($e,$a5)',			# e+=a<<<5
++	'&xor	($a,$t0);'.			# f=(b&c)^(~b&d) for next round
++
++	'unshift(@ROTX,pop(@ROTX)); $j++;'
++	)
++}
++
++sub bodyx_20_39 () {	# 7 instructions, 2 cycles critical path
++	# on entry $f=b^c^d, $b>>>=2
++	return &bodyx_40_59() if ($rx==39); $rx++;
++	(
++	'($a,$f,$b,$c,$d,$e)=@ROTX;'.
++
++	'&add	($e,((32*($j/4)+4*($j%4))%256-128)."($frame)");'.	# e+=X[i]+K
++	 '&lea	($frame,"256($frame)")	if ($j%32==31);',
++
++	'&lea	($e,"($e,$f)")',		# e+=b^c^d
++	'&rorx	($a5,$a,27)',			# a<<<5
++	'&rorx	($f,$a,2)	if ($j<79)',	# b>>>2 in next round
++	'&xor	($a,$b)		if ($j<79)',	# b^c for next round
++
++	'&add	($e,$a5)',			# e+=a<<<5
++	'&xor	($a,$c)		if ($j<79);'.	# f=b^c^d for next round
++
++	'unshift(@ROTX,pop(@ROTX)); $j++;'
++	)
++}
++
++sub bodyx_40_59 () {	# 10 instructions, 3 cycles critical path
++	# on entry $f=((b^c)&(c^d)), $b>>>=2
++	$rx++;
++	(
++	'($a,$f,$b,$c,$d,$e)=@ROTX;'.
++
++	'&add	($e,((32*($j/4)+4*($j%4))%256-128)."($frame)");'.	# e+=X[i]+K
++	 '&lea	($frame,"256($frame)")	if ($j%32==31);',
++	'&xor	($f,$c)		if ($j>39)',	# (b^c)&(c^d)^c
++	'&mov	($t0,$b)	if ($j<59)',	# count on zero latency
++	'&xor	($t0,$c)	if ($j<59)',	# c^d for next round
++
++	'&lea	($e,"($e,$f)")',		# e+=(b^c)&(c^d)^c
++	'&rorx	($a5,$a,27)',			# a<<<5
++	'&rorx	($f,$a,2)',			# b>>>2 in next round
++	'&xor	($a,$b)',			# b^c for next round
++
++	'&add	($e,$a5)',			# e+=a<<<5
++	'&and	($a,$t0)	if ($j< 59);'.	# f=(b^c)&(c^d) for next round
++	'&xor	($a,$c)		if ($j==59);'.	# f=b^c^d for next round
++
++	'unshift(@ROTX,pop(@ROTX)); $j++;'
++	)
++}
++
++sub Xupdate_avx2_16_31()		# recall that $Xi starts wtih 4
++{ use integer;
++  my $body = shift;
++  my @insns = (&$body,&$body,&$body,&$body,&$body);	# 35 instructions
++  my ($a,$b,$c,$d,$e);
++
++	&vpalignr(@X[0],@X[-3&7],@X[-4&7],8);	# compose "X[-14]" in "X[0]"
++	 eval(shift(@insns));
++	 eval(shift(@insns));
++	 eval(shift(@insns));
++	 eval(shift(@insns));
++
++	&vpsrldq(@Tx[0],@X[-1&7],4);		# "X[-3]", 3 dwords
++	 eval(shift(@insns));
++	 eval(shift(@insns));
++	 eval(shift(@insns));
++
++	&vpxor	(@X[0],@X[0],@X[-4&7]);		# "X[0]"^="X[-16]"
++	&vpxor	(@Tx[0],@Tx[0],@X[-2&7]);	# "X[-3]"^"X[-8]"
++	 eval(shift(@insns));
++	 eval(shift(@insns));
++
++	&vpxor	(@X[0],@X[0],@Tx[0]);		# "X[0]"^="X[-3]"^"X[-8]"
++	 eval(shift(@insns));
++	 eval(shift(@insns));
++	 eval(shift(@insns));
++	 eval(shift(@insns));
++
++	&vpsrld	(@Tx[0],@X[0],31);
++	&vmovdqu($Kx,eval(2*16*(($Xi)/5)-64)."($K_XX_XX)")	if ($Xi%5==0);	# K_XX_XX
++	 eval(shift(@insns));
++	 eval(shift(@insns));
++	 eval(shift(@insns));
++
++	&vpslldq(@Tx[2],@X[0],12);		# "X[0]"<<96, extract one dword
++	&vpaddd	(@X[0],@X[0],@X[0]);
++	 eval(shift(@insns));
++	 eval(shift(@insns));
++
++	&vpsrld	(@Tx[1],@Tx[2],30);
++	&vpor	(@X[0],@X[0],@Tx[0]);		# "X[0]"<<<=1
++	 eval(shift(@insns));
++	 eval(shift(@insns));
++
++	&vpslld	(@Tx[2],@Tx[2],2);
++	&vpxor	(@X[0],@X[0],@Tx[1]);
++	 eval(shift(@insns));
++	 eval(shift(@insns));
++
++	&vpxor	(@X[0],@X[0],@Tx[2]);		# "X[0]"^=("X[0]">>96)<<<2
++	 eval(shift(@insns));
++	 eval(shift(@insns));
++	 eval(shift(@insns));
++
++	&vpaddd	(@Tx[1],@X[0],$Kx);
++	 eval(shift(@insns));
++	 eval(shift(@insns));
++	 eval(shift(@insns));
++	&vmovdqu(eval(32*($Xi))."(%rsp)",@Tx[1]);	# X[]+K xfer to IALU
++
++	 foreach (@insns) { eval; }	# remaining instructions [if any]
++
++	$Xi++;
++	push(@X,shift(@X));	# "rotate" X[]
++}
++
++sub Xupdate_avx2_32_79()
++{ use integer;
++  my $body = shift;
++  my @insns = (&$body,&$body,&$body,&$body,&$body);	# 35 to 50 instructions
++  my ($a,$b,$c,$d,$e);
++
++	&vpalignr(@Tx[0],@X[-1&7],@X[-2&7],8);	# compose "X[-6]"
++	&vpxor	(@X[0],@X[0],@X[-4&7]);		# "X[0]"="X[-32]"^"X[-16]"
++	 eval(shift(@insns));
++	 eval(shift(@insns));
++
++	&vpxor	(@X[0],@X[0],@X[-7&7]);		# "X[0]"^="X[-28]"
++	&vmovdqu($Kx,eval(2*16*($Xi/5)-64)."($K_XX_XX)")	if ($Xi%5==0);
++	 eval(shift(@insns));
++	 eval(shift(@insns));
++	 eval(shift(@insns));
++
++	&vpxor	(@X[0],@X[0],@Tx[0]);		# "X[0]"^="X[-6]"
++	 eval(shift(@insns));
++	 eval(shift(@insns));
++	 eval(shift(@insns));
++
++	&vpsrld	(@Tx[0],@X[0],30);
++	&vpslld	(@X[0],@X[0],2);
++	 eval(shift(@insns));
++	 eval(shift(@insns));
++	 eval(shift(@insns));
++
++	#&vpslld	(@X[0],@X[0],2);
++	 eval(shift(@insns));
++	 eval(shift(@insns));
++	 eval(shift(@insns));
++
++	&vpor	(@X[0],@X[0],@Tx[0]);		# "X[0]"<<<=2
++	 eval(shift(@insns));
++	 eval(shift(@insns));
++	 eval(shift(@insns));
++	 eval(shift(@insns));
++
++	&vpaddd	(@Tx[1],@X[0],$Kx);
++	 eval(shift(@insns));
++	 eval(shift(@insns));
++	 eval(shift(@insns));
++	 eval(shift(@insns));
++
++	&vmovdqu("32*$Xi(%rsp)",@Tx[1]);	# X[]+K xfer to IALU
++
++	 foreach (@insns) { eval; }	# remaining instructions
++
++	$Xi++;
++	push(@X,shift(@X));	# "rotate" X[]
++}
++
++sub Xloop_avx2()
++{ use integer;
++  my $body = shift;
++  my @insns = (&$body,&$body,&$body,&$body,&$body);	# 32 instructions
++  my ($a,$b,$c,$d,$e);
++
++	 foreach (@insns) { eval; }
++}
++
++	&align32();
++	&Xupdate_avx2_32_79(\&bodyx_00_19);
++	&Xupdate_avx2_32_79(\&bodyx_00_19);
++	&Xupdate_avx2_32_79(\&bodyx_00_19);
++	&Xupdate_avx2_32_79(\&bodyx_00_19);
++
++	&Xupdate_avx2_32_79(\&bodyx_20_39);
++	&Xupdate_avx2_32_79(\&bodyx_20_39);
++	&Xupdate_avx2_32_79(\&bodyx_20_39);
++	&Xupdate_avx2_32_79(\&bodyx_20_39);
++
++	&align32();
++	&Xupdate_avx2_32_79(\&bodyx_40_59);
++	&Xupdate_avx2_32_79(\&bodyx_40_59);
++	&Xupdate_avx2_32_79(\&bodyx_40_59);
++	&Xupdate_avx2_32_79(\&bodyx_40_59);
++
++	&Xloop_avx2(\&bodyx_20_39);
++	&Xloop_avx2(\&bodyx_20_39);
++	&Xloop_avx2(\&bodyx_20_39);
++	&Xloop_avx2(\&bodyx_20_39);
++
++$code.=<<___;
++	lea	128($inp),$frame
++	lea	128($inp),%rdi			# borrow $t0
++	cmp	$num,$frame
++	cmovae	$inp,$frame			# next or previous block
++
++	# output is d-e-[a]-f-b-c => A=d,F=e,C=f,D=b,E=c
++	add	0($ctx),@ROTX[0]		# update context
++	add	4($ctx),@ROTX[1]
++	add	8($ctx),@ROTX[3]
++	mov	@ROTX[0],0($ctx)
++	add	12($ctx),@ROTX[4]
++	mov	@ROTX[1],4($ctx)
++	 mov	@ROTX[0],$A			# A=d
++	add	16($ctx),@ROTX[5]
++	 mov	@ROTX[3],$a5
++	mov	@ROTX[3],8($ctx)
++	 mov	@ROTX[4],$D			# D=b
++	 #xchg	@ROTX[5],$F			# F=c, C=f
++	mov	@ROTX[4],12($ctx)
++	 mov	@ROTX[1],$F			# F=e
++	mov	@ROTX[5],16($ctx)
++	#mov	$F,16($ctx)
++	 mov	@ROTX[5],$E			# E=c
++	 mov	$a5,$C				# C=f
++	 #xchg	$F,$E				# E=c, F=e
++
++	cmp	$num,$inp
++	je	.Ldone_avx2
++___
++
++$Xi=4;				# reset variables
++@X=map("%ymm$_",(4..7,0..3));
++
++$code.=<<___;
++	vmovdqu	64($K_XX_XX),@X[2]		# pbswap mask
++	cmp	$num,%rdi			# borrowed $t0
++	ja	.Last_avx2
++
++	vmovdqu		-64(%rdi),%xmm0		# low part of @X[-4&7]
++	vmovdqu		-48(%rdi),%xmm1
++	vmovdqu		-32(%rdi),%xmm2
++	vmovdqu		-16(%rdi),%xmm3
++	vinserti128	\$1,0($frame),@X[-4&7],@X[-4&7]
++	vinserti128	\$1,16($frame),@X[-3&7],@X[-3&7]
++	vinserti128	\$1,32($frame),@X[-2&7],@X[-2&7]
++	vinserti128	\$1,48($frame),@X[-1&7],@X[-1&7]
++	jmp	.Last_avx2
++
++.align	32
++.Last_avx2:
++	lea	128+16(%rsp),$frame
++	rorx	\$2,$F,$B
++	andn	$D,$F,$t0
++	and	$C,$F
++	xor	$t0,$F
++	sub	\$-128,$inp
++___
++	$rx=$j=0;	@ROTX=($A,$F,$B,$C,$D,$E);
++
++	&Xloop_avx2	(\&bodyx_00_19);
++	&Xloop_avx2	(\&bodyx_00_19);
++	&Xloop_avx2	(\&bodyx_00_19);
++	&Xloop_avx2	(\&bodyx_00_19);
++
++	&Xloop_avx2	(\&bodyx_20_39);
++	  &vmovdqu	($Kx,"-64($K_XX_XX)");		# K_00_19
++	  &vpshufb	(@X[-4&7],@X[-4&7],@X[2]);	# byte swap
++	&Xloop_avx2	(\&bodyx_20_39);
++	  &vpshufb	(@X[-3&7],@X[-3&7],@X[2]);
++	  &vpaddd	(@Tx[0],@X[-4&7],$Kx);		# add K_00_19
++	&Xloop_avx2	(\&bodyx_20_39);
++	  &vmovdqu	("0(%rsp)",@Tx[0]);
++	  &vpshufb	(@X[-2&7],@X[-2&7],@X[2]);
++	  &vpaddd	(@Tx[1],@X[-3&7],$Kx);
++	&Xloop_avx2	(\&bodyx_20_39);
++	  &vmovdqu	("32(%rsp)",@Tx[1]);
++	  &vpshufb	(@X[-1&7],@X[-1&7],@X[2]);
++	  &vpaddd	(@X[2],@X[-2&7],$Kx);
++
++	&Xloop_avx2	(\&bodyx_40_59);
++	&align32	();
++	  &vmovdqu	("64(%rsp)",@X[2]);
++	  &vpaddd	(@X[3],@X[-1&7],$Kx);
++	&Xloop_avx2	(\&bodyx_40_59);
++	  &vmovdqu	("96(%rsp)",@X[3]);
++	&Xloop_avx2	(\&bodyx_40_59);
++	&Xupdate_avx2_16_31(\&bodyx_40_59);
++
++	&Xupdate_avx2_16_31(\&bodyx_20_39);
++	&Xupdate_avx2_16_31(\&bodyx_20_39);
++	&Xupdate_avx2_16_31(\&bodyx_20_39);
++	&Xloop_avx2	(\&bodyx_20_39);
++
++$code.=<<___;
++	lea	128(%rsp),$frame
++
++	# output is d-e-[a]-f-b-c => A=d,F=e,C=f,D=b,E=c
++	add	0($ctx),@ROTX[0]		# update context
++	add	4($ctx),@ROTX[1]
++	add	8($ctx),@ROTX[3]
++	mov	@ROTX[0],0($ctx)
++	add	12($ctx),@ROTX[4]
++	mov	@ROTX[1],4($ctx)
++	 mov	@ROTX[0],$A			# A=d
++	add	16($ctx),@ROTX[5]
++	 mov	@ROTX[3],$a5
++	mov	@ROTX[3],8($ctx)
++	 mov	@ROTX[4],$D			# D=b
++	 #xchg	@ROTX[5],$F			# F=c, C=f
++	mov	@ROTX[4],12($ctx)
++	 mov	@ROTX[1],$F			# F=e
++	mov	@ROTX[5],16($ctx)
++	#mov	$F,16($ctx)
++	 mov	@ROTX[5],$E			# E=c
++	 mov	$a5,$C				# C=f
++	 #xchg	$F,$E				# E=c, F=e
++
++	cmp	$num,$inp
++	jbe	.Loop_avx2
++
++.Ldone_avx2:
++	vzeroupper
++___
++$code.=<<___ if ($win64);
++	movaps	-40-6*16(%r14),%xmm6
++	movaps	-40-5*16(%r14),%xmm7
++	movaps	-40-4*16(%r14),%xmm8
++	movaps	-40-3*16(%r14),%xmm9
++	movaps	-40-2*16(%r14),%xmm10
++	movaps	-40-1*16(%r14),%xmm11
++___
++$code.=<<___;
++	lea	(%r14),%rsi
++	mov	-40(%rsi),%r14
++	mov	-32(%rsi),%r13
++	mov	-24(%rsi),%r12
++	mov	-16(%rsi),%rbp
++	mov	-8(%rsi),%rbx
++	lea	(%rsi),%rsp
++.Lepilogue_avx2:
++	ret
++.size	sha1_block_data_order_avx2,.-sha1_block_data_order_avx2
++___
++}
++}
++$code.=<<___;
++.align	64
++K_XX_XX:
++.long	0x5a827999,0x5a827999,0x5a827999,0x5a827999	# K_00_19
++.long	0x5a827999,0x5a827999,0x5a827999,0x5a827999	# K_00_19
++.long	0x6ed9eba1,0x6ed9eba1,0x6ed9eba1,0x6ed9eba1	# K_20_39
++.long	0x6ed9eba1,0x6ed9eba1,0x6ed9eba1,0x6ed9eba1	# K_20_39
++.long	0x8f1bbcdc,0x8f1bbcdc,0x8f1bbcdc,0x8f1bbcdc	# K_40_59
++.long	0x8f1bbcdc,0x8f1bbcdc,0x8f1bbcdc,0x8f1bbcdc	# K_40_59
++.long	0xca62c1d6,0xca62c1d6,0xca62c1d6,0xca62c1d6	# K_60_79
++.long	0xca62c1d6,0xca62c1d6,0xca62c1d6,0xca62c1d6	# K_60_79
++.long	0x00010203,0x04050607,0x08090a0b,0x0c0d0e0f	# pbswap mask
++.long	0x00010203,0x04050607,0x08090a0b,0x0c0d0e0f	# pbswap mask
++.byte	0xf,0xe,0xd,0xc,0xb,0xa,0x9,0x8,0x7,0x6,0x5,0x4,0x3,0x2,0x1,0x0
++___
++}}}
++$code.=<<___;
++.asciz	"SHA1 block transform for x86_64, CRYPTOGAMS by "
++.align	64
++___
++
++# EXCEPTION_DISPOSITION handler (EXCEPTION_RECORD *rec,ULONG64 frame,
++#		CONTEXT *context,DISPATCHER_CONTEXT *disp)
++if ($win64) {
++$rec="%rcx";
++$frame="%rdx";
++$context="%r8";
++$disp="%r9";
++
++$code.=<<___;
++.extern	__imp_RtlVirtualUnwind
++.type	se_handler,\@abi-omnipotent
++.align	16
++se_handler:
++	push	%rsi
++	push	%rdi
++	push	%rbx
++	push	%rbp
++	push	%r12
++	push	%r13
++	push	%r14
++	push	%r15
++	pushfq
++	sub	\$64,%rsp
++
++	mov	120($context),%rax	# pull context->Rax
++	mov	248($context),%rbx	# pull context->Rip
++
++	lea	.Lprologue(%rip),%r10
++	cmp	%r10,%rbx		# context->Rip<.Lprologue
++	jb	.Lcommon_seh_tail
++
++	mov	152($context),%rax	# pull context->Rsp
++
++	lea	.Lepilogue(%rip),%r10
++	cmp	%r10,%rbx		# context->Rip>=.Lepilogue
++	jae	.Lcommon_seh_tail
++
++	mov	`16*4`(%rax),%rax	# pull saved stack pointer
++
++	mov	-8(%rax),%rbx
++	mov	-16(%rax),%rbp
++	mov	-24(%rax),%r12
++	mov	-32(%rax),%r13
++	mov	-40(%rax),%r14
++	mov	%rbx,144($context)	# restore context->Rbx
++	mov	%rbp,160($context)	# restore context->Rbp
++	mov	%r12,216($context)	# restore context->R12
++	mov	%r13,224($context)	# restore context->R13
++	mov	%r14,232($context)	# restore context->R14
++
++	jmp	.Lcommon_seh_tail
++.size	se_handler,.-se_handler
++___
++
++$code.=<<___ if ($shaext);
++.type	shaext_handler,\@abi-omnipotent
++.align	16
++shaext_handler:
++	push	%rsi
++	push	%rdi
++	push	%rbx
++	push	%rbp
++	push	%r12
++	push	%r13
++	push	%r14
++	push	%r15
++	pushfq
++	sub	\$64,%rsp
++
++	mov	120($context),%rax	# pull context->Rax
++	mov	248($context),%rbx	# pull context->Rip
++
++	lea	.Lprologue_shaext(%rip),%r10
++	cmp	%r10,%rbx		# context->Rip<.Lprologue
++	jb	.Lcommon_seh_tail
++
++	lea	.Lepilogue_shaext(%rip),%r10
++	cmp	%r10,%rbx		# context->Rip>=.Lepilogue
++	jae	.Lcommon_seh_tail
++
++	lea	-8-4*16(%rax),%rsi
++	lea	512($context),%rdi	# &context.Xmm6
++	mov	\$8,%ecx
++	.long	0xa548f3fc		# cld; rep movsq
++
++	jmp	.Lcommon_seh_tail
++.size	shaext_handler,.-shaext_handler
++___
++
++$code.=<<___;
++.type	ssse3_handler,\@abi-omnipotent
++.align	16
++ssse3_handler:
++	push	%rsi
++	push	%rdi
++	push	%rbx
++	push	%rbp
++	push	%r12
++	push	%r13
++	push	%r14
++	push	%r15
++	pushfq
++	sub	\$64,%rsp
++
++	mov	120($context),%rax	# pull context->Rax
++	mov	248($context),%rbx	# pull context->Rip
++
++	mov	8($disp),%rsi		# disp->ImageBase
++	mov	56($disp),%r11		# disp->HandlerData
++
++	mov	0(%r11),%r10d		# HandlerData[0]
++	lea	(%rsi,%r10),%r10	# prologue label
++	cmp	%r10,%rbx		# context->RipRsp
++
++	mov	4(%r11),%r10d		# HandlerData[1]
++	lea	(%rsi,%r10),%r10	# epilogue label
++	cmp	%r10,%rbx		# context->Rip>=epilogue label
++	jae	.Lcommon_seh_tail
++
++	mov	232($context),%rax	# pull context->R14
++
++	lea	-40-6*16(%rax),%rsi
++	lea	512($context),%rdi	# &context.Xmm6
++	mov	\$12,%ecx
++	.long	0xa548f3fc		# cld; rep movsq
++
++	mov	-8(%rax),%rbx
++	mov	-16(%rax),%rbp
++	mov	-24(%rax),%r12
++	mov	-32(%rax),%r13
++	mov	-40(%rax),%r14
++	mov	%rbx,144($context)	# restore context->Rbx
++	mov	%rbp,160($context)	# restore context->Rbp
++	mov	%r12,216($context)	# restore cotnext->R12
++	mov	%r13,224($context)	# restore cotnext->R13
++	mov	%r14,232($context)	# restore cotnext->R14
++
++.Lcommon_seh_tail:
++	mov	8(%rax),%rdi
++	mov	16(%rax),%rsi
++	mov	%rax,152($context)	# restore context->Rsp
++	mov	%rsi,168($context)	# restore context->Rsi
++	mov	%rdi,176($context)	# restore context->Rdi
++
++	mov	40($disp),%rdi		# disp->ContextRecord
++	mov	$context,%rsi		# context
++	mov	\$154,%ecx		# sizeof(CONTEXT)
++	.long	0xa548f3fc		# cld; rep movsq
++
++	mov	$disp,%rsi
++	xor	%rcx,%rcx		# arg1, UNW_FLAG_NHANDLER
++	mov	8(%rsi),%rdx		# arg2, disp->ImageBase
++	mov	0(%rsi),%r8		# arg3, disp->ControlPc
++	mov	16(%rsi),%r9		# arg4, disp->FunctionEntry
++	mov	40(%rsi),%r10		# disp->ContextRecord
++	lea	56(%rsi),%r11		# &disp->HandlerData
++	lea	24(%rsi),%r12		# &disp->EstablisherFrame
++	mov	%r10,32(%rsp)		# arg5
++	mov	%r11,40(%rsp)		# arg6
++	mov	%r12,48(%rsp)		# arg7
++	mov	%rcx,56(%rsp)		# arg8, (NULL)
++	call	*__imp_RtlVirtualUnwind(%rip)
++
++	mov	\$1,%eax		# ExceptionContinueSearch
++	add	\$64,%rsp
++	popfq
++	pop	%r15
++	pop	%r14
++	pop	%r13
++	pop	%r12
++	pop	%rbp
++	pop	%rbx
++	pop	%rdi
++	pop	%rsi
++	ret
++.size	ssse3_handler,.-ssse3_handler
++
++.section	.pdata
++.align	4
++	.rva	.LSEH_begin_sha1_block_data_order
++	.rva	.LSEH_end_sha1_block_data_order
++	.rva	.LSEH_info_sha1_block_data_order
++___
++$code.=<<___ if ($shaext);
++	.rva	.LSEH_begin_sha1_block_data_order_shaext
++	.rva	.LSEH_end_sha1_block_data_order_shaext
++	.rva	.LSEH_info_sha1_block_data_order_shaext
++___
++$code.=<<___;
++	.rva	.LSEH_begin_sha1_block_data_order_ssse3
++	.rva	.LSEH_end_sha1_block_data_order_ssse3
++	.rva	.LSEH_info_sha1_block_data_order_ssse3
++___
++$code.=<<___ if ($avx);
++	.rva	.LSEH_begin_sha1_block_data_order_avx
++	.rva	.LSEH_end_sha1_block_data_order_avx
++	.rva	.LSEH_info_sha1_block_data_order_avx
++___
++$code.=<<___ if ($avx>1);
++	.rva	.LSEH_begin_sha1_block_data_order_avx2
++	.rva	.LSEH_end_sha1_block_data_order_avx2
++	.rva	.LSEH_info_sha1_block_data_order_avx2
++___
++$code.=<<___;
++.section	.xdata
++.align	8
++.LSEH_info_sha1_block_data_order:
++	.byte	9,0,0,0
++	.rva	se_handler
++___
++$code.=<<___ if ($shaext);
++.LSEH_info_sha1_block_data_order_shaext:
++	.byte	9,0,0,0
++	.rva	shaext_handler
++___
++$code.=<<___;
++.LSEH_info_sha1_block_data_order_ssse3:
++	.byte	9,0,0,0
++	.rva	ssse3_handler
++	.rva	.Lprologue_ssse3,.Lepilogue_ssse3	# HandlerData[]
++___
++$code.=<<___ if ($avx);
++.LSEH_info_sha1_block_data_order_avx:
++	.byte	9,0,0,0
++	.rva	ssse3_handler
++	.rva	.Lprologue_avx,.Lepilogue_avx		# HandlerData[]
++___
++$code.=<<___ if ($avx>1);
++.LSEH_info_sha1_block_data_order_avx2:
++	.byte	9,0,0,0
++	.rva	ssse3_handler
++	.rva	.Lprologue_avx2,.Lepilogue_avx2		# HandlerData[]
++___
++}
++
++####################################################################
++
++sub sha1rnds4 {
++    if (@_[0] =~ /\$([x0-9a-f]+),\s*%xmm([0-7]),\s*%xmm([0-7])/) {
++      my @opcode=(0x0f,0x3a,0xcc);
++	push @opcode,0xc0|($2&7)|(($3&7)<<3);		# ModR/M
++	my $c=$1;
++	push @opcode,$c=~/^0/?oct($c):$c;
++	return ".byte\t".join(',',@opcode);
++    } else {
++	return "sha1rnds4\t".@_[0];
++    }
++}
++
++sub sha1op38 {
++    my $instr = shift;
++    my %opcodelet = (
++		"sha1nexte" => 0xc8,
++  		"sha1msg1"  => 0xc9,
++		"sha1msg2"  => 0xca	);
++
++    if (defined($opcodelet{$instr}) && @_[0] =~ /%xmm([0-9]+),\s*%xmm([0-9]+)/) {
++      my @opcode=(0x0f,0x38);
++      my $rex=0;
++	$rex|=0x04			if ($2>=8);
++	$rex|=0x01			if ($1>=8);
++	unshift @opcode,0x40|$rex	if ($rex);
++	push @opcode,$opcodelet{$instr};
++	push @opcode,0xc0|($1&7)|(($2&7)<<3);		# ModR/M
++	return ".byte\t".join(',',@opcode);
++    } else {
++	return $instr."\t".@_[0];
++    }
++}
++
++foreach (split("\n",$code)) {
++	s/\`([^\`]*)\`/eval $1/geo;
++
++	s/\b(sha1rnds4)\s+(.*)/sha1rnds4($2)/geo	or
++	s/\b(sha1[^\s]*)\s+(.*)/sha1op38($1,$2)/geo;
++
++	print $_,"\n";
++}
++close STDOUT;
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/sha/asm/sha256-586.pl b/CryptoPkg/Library/OpensslLib/openssl/crypto/sha/asm/sha256-586.pl
+new file mode 100644
+index 0000000..6af1d84
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/sha/asm/sha256-586.pl
+@@ -0,0 +1,1293 @@
++#! /usr/bin/env perl
++# Copyright 2007-2016 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
++# in the file LICENSE in the source distribution or at
++# https://www.openssl.org/source/license.html
++
++#
++# ====================================================================
++# Written by Andy Polyakov  for the OpenSSL
++# project. The module is, however, dual licensed under OpenSSL and
++# CRYPTOGAMS licenses depending on where you obtain it. For further
++# details see http://www.openssl.org/~appro/cryptogams/.
++# ====================================================================
++#
++# SHA256 block transform for x86. September 2007.
++#
++# Performance improvement over compiler generated code varies from
++# 10% to 40% [see below]. Not very impressive on some µ-archs, but
++# it's 5 times smaller and optimizies amount of writes.
++#
++# May 2012.
++#
++# Optimization including two of Pavel Semjanov's ideas, alternative
++# Maj and full unroll, resulted in ~20-25% improvement on most CPUs,
++# ~7% on Pentium, ~40% on Atom. As fully unrolled loop body is almost
++# 15x larger, 8KB vs. 560B, it's fired only for longer inputs. But not
++# on P4, where it kills performance, nor Sandy Bridge, where folded
++# loop is approximately as fast...
++#
++# June 2012.
++#
++# Add AMD XOP-specific code path, >30% improvement on Bulldozer over
++# May version, >60% over original. Add AVX+shrd code path, >25%
++# improvement on Sandy Bridge over May version, 60% over original.
++#
++# May 2013.
++#
++# Replace AMD XOP code path with SSSE3 to cover more processors.
++# (Biggest improvement coefficient is on upcoming Atom Silvermont,
++# not shown.) Add AVX+BMI code path.
++#
++# March 2014.
++#
++# Add support for Intel SHA Extensions.
++#
++# Performance in clock cycles per processed byte (less is better):
++#
++#		gcc	icc	x86 asm(*)	SIMD	x86_64 asm(**)	
++# Pentium	46	57	40/38		-	-
++# PIII		36	33	27/24		-	-
++# P4		41	38	28		-	17.3
++# AMD K8	27	25	19/15.5		-	14.9
++# Core2		26	23	18/15.6		14.3	13.8
++# Westmere	27	-	19/15.7		13.4	12.3
++# Sandy Bridge	25	-	15.9		12.4	11.6
++# Ivy Bridge	24	-	15.0		11.4	10.3
++# Haswell	22	-	13.9		9.46	7.80
++# Bulldozer	36	-	27/22		17.0	13.6
++# VIA Nano	36	-	25/22		16.8	16.5
++# Atom		50	-	30/25		21.9	18.9
++# Silvermont	40	-	34/31		22.9	20.6
++#
++# (*)	numbers after slash are for unrolled loop, where applicable;
++# (**)	x86_64 assembly performance is presented for reference
++#	purposes, results are best-available;
++
++$0 =~ m/(.*[\/\\])[^\/\\]+$/; $dir=$1;
++push(@INC,"${dir}","${dir}../../perlasm");
++require "x86asm.pl";
++
++$output=pop;
++open STDOUT,">$output";
++
++&asm_init($ARGV[0],"sha512-586.pl",$ARGV[$#ARGV] eq "386");
++
++$xmm=$avx=0;
++for (@ARGV) { $xmm=1 if (/-DOPENSSL_IA32_SSE2/); }
++
++if ($xmm &&	`$ENV{CC} -Wa,-v -c -o /dev/null -x assembler /dev/null 2>&1`
++			=~ /GNU assembler version ([2-9]\.[0-9]+)/) {
++	$avx = ($1>=2.19) + ($1>=2.22);
++}
++
++if ($xmm && !$avx && $ARGV[0] eq "win32n" &&
++		`nasm -v 2>&1` =~ /NASM version ([2-9]\.[0-9]+)/) {
++	$avx = ($1>=2.03) + ($1>=2.10);
++}
++
++if ($xmm && !$avx && $ARGV[0] eq "win32" &&
++		`ml 2>&1` =~ /Version ([0-9]+)\./) {
++	$avx = ($1>=10) + ($1>=11);
++}
++
++if ($xmm && !$avx && `$ENV{CC} -v 2>&1` =~ /(^clang version|based on LLVM) ([3-9]\.[0-9]+)/) {
++	$avx = ($2>=3.0) + ($2>3.0);
++}
++
++$shaext=$xmm;	### set to zero if compiling for 1.0.1
++
++$unroll_after = 64*4;	# If pre-evicted from L1P cache first spin of
++			# fully unrolled loop was measured to run about
++			# 3-4x slower. If slowdown coefficient is N and
++			# unrolled loop is m times faster, then you break
++			# even at (N-1)/(m-1) blocks. Then it needs to be
++			# adjusted for probability of code being evicted,
++			# code size/cache size=1/4. Typical m is 1.15...
++
++$A="eax";
++$E="edx";
++$T="ebx";
++$Aoff=&DWP(4,"esp");
++$Boff=&DWP(8,"esp");
++$Coff=&DWP(12,"esp");
++$Doff=&DWP(16,"esp");
++$Eoff=&DWP(20,"esp");
++$Foff=&DWP(24,"esp");
++$Goff=&DWP(28,"esp");
++$Hoff=&DWP(32,"esp");
++$Xoff=&DWP(36,"esp");
++$K256="ebp";
++
++sub BODY_16_63() {
++	&mov	($T,"ecx");			# "ecx" is preloaded
++	 &mov	("esi",&DWP(4*(9+15+16-14),"esp"));
++	&ror	("ecx",18-7);
++	 &mov	("edi","esi");
++	&ror	("esi",19-17);
++	 &xor	("ecx",$T);
++	 &shr	($T,3);
++	&ror	("ecx",7);
++	 &xor	("esi","edi");
++	 &xor	($T,"ecx");			# T = sigma0(X[-15])
++	&ror	("esi",17);
++	 &add	($T,&DWP(4*(9+15+16),"esp"));	# T += X[-16]
++	&shr	("edi",10);
++	 &add	($T,&DWP(4*(9+15+16-9),"esp"));	# T += X[-7]
++	#&xor	("edi","esi")			# sigma1(X[-2])
++	# &add	($T,"edi");			# T += sigma1(X[-2])
++	# &mov	(&DWP(4*(9+15),"esp"),$T);	# save X[0]
++
++	&BODY_00_15(1);
++}
++sub BODY_00_15() {
++    my $in_16_63=shift;
++
++	&mov	("ecx",$E);
++	 &xor	("edi","esi")			if ($in_16_63);	# sigma1(X[-2])
++	 &mov	("esi",$Foff);
++	&ror	("ecx",25-11);
++	 &add	($T,"edi")			if ($in_16_63);	# T += sigma1(X[-2])
++	 &mov	("edi",$Goff);
++	&xor	("ecx",$E);
++	 &xor	("esi","edi");
++	 &mov	($T,&DWP(4*(9+15),"esp"))	if (!$in_16_63);
++	 &mov	(&DWP(4*(9+15),"esp"),$T)	if ($in_16_63);	# save X[0]
++	&ror	("ecx",11-6);
++	 &and	("esi",$E);
++	 &mov	($Eoff,$E);		# modulo-scheduled
++	&xor	($E,"ecx");
++	 &add	($T,$Hoff);		# T += h
++	 &xor	("esi","edi");		# Ch(e,f,g)
++	&ror	($E,6);			# Sigma1(e)
++	 &mov	("ecx",$A);
++	 &add	($T,"esi");		# T += Ch(e,f,g)
++
++	&ror	("ecx",22-13);
++	 &add	($T,$E);		# T += Sigma1(e)
++	 &mov	("edi",$Boff);
++	&xor	("ecx",$A);
++	 &mov	($Aoff,$A);		# modulo-scheduled
++	 &lea	("esp",&DWP(-4,"esp"));
++	&ror	("ecx",13-2);
++	 &mov	("esi",&DWP(0,$K256));
++	&xor	("ecx",$A);
++	 &mov	($E,$Eoff);		# e in next iteration, d in this one
++	 &xor	($A,"edi");		# a ^= b
++	&ror	("ecx",2);		# Sigma0(a)
++
++	 &add	($T,"esi");		# T+= K[i]
++	 &mov	(&DWP(0,"esp"),$A);	# (b^c) in next round
++	&add	($E,$T);		# d += T
++	 &and	($A,&DWP(4,"esp"));	# a &= (b^c)
++	&add	($T,"ecx");		# T += Sigma0(a)
++	 &xor	($A,"edi");		# h = Maj(a,b,c) = Ch(a^b,c,b)
++	 &mov	("ecx",&DWP(4*(9+15+16-1),"esp"))	if ($in_16_63);	# preload T
++	&add	($K256,4);
++	 &add	($A,$T);		# h += T
++}
++
++&external_label("OPENSSL_ia32cap_P")		if (!$i386);
++
++&function_begin("sha256_block_data_order");
++	&mov	("esi",wparam(0));	# ctx
++	&mov	("edi",wparam(1));	# inp
++	&mov	("eax",wparam(2));	# num
++	&mov	("ebx","esp");		# saved sp
++
++	&call	(&label("pic_point"));	# make it PIC!
++&set_label("pic_point");
++	&blindpop($K256);
++	&lea	($K256,&DWP(&label("K256")."-".&label("pic_point"),$K256));
++
++	&sub	("esp",16);
++	&and	("esp",-64);
++
++	&shl	("eax",6);
++	&add	("eax","edi");
++	&mov	(&DWP(0,"esp"),"esi");	# ctx
++	&mov	(&DWP(4,"esp"),"edi");	# inp
++	&mov	(&DWP(8,"esp"),"eax");	# inp+num*128
++	&mov	(&DWP(12,"esp"),"ebx");	# saved sp
++						if (!$i386 && $xmm) {
++	&picmeup("edx","OPENSSL_ia32cap_P",$K256,&label("K256"));
++	&mov	("ecx",&DWP(0,"edx"));
++	&mov	("ebx",&DWP(4,"edx"));
++	&test	("ecx",1<<20);		# check for P4
++	&jnz	(&label("loop"));
++	&mov	("edx",&DWP(8,"edx"))	if ($xmm);
++	&test	("ecx",1<<24);		# check for FXSR
++	&jz	($unroll_after?&label("no_xmm"):&label("loop"));
++	&and	("ecx",1<<30);		# mask "Intel CPU" bit
++	&and	("ebx",1<<28|1<<9);	# mask AVX and SSSE3 bits
++	&test	("edx",1<<29)		if ($shaext);	# check for SHA
++	&jnz	(&label("shaext"))	if ($shaext);
++	&or	("ecx","ebx");
++	&and	("ecx",1<<28|1<<30);
++	&cmp	("ecx",1<<28|1<<30);
++					if ($xmm) {
++	&je	(&label("AVX"))		if ($avx);
++	&test	("ebx",1<<9);		# check for SSSE3
++	&jnz	(&label("SSSE3"));
++					} else {
++	&je	(&label("loop_shrd"));
++					}
++						if ($unroll_after) {
++&set_label("no_xmm");
++	&sub	("eax","edi");
++	&cmp	("eax",$unroll_after);
++	&jae	(&label("unrolled"));
++						} }
++	&jmp	(&label("loop"));
++
++sub COMPACT_LOOP() {
++my $suffix=shift;
++
++&set_label("loop$suffix",$suffix?32:16);
++    # copy input block to stack reversing byte and dword order
++    for($i=0;$i<4;$i++) {
++	&mov	("eax",&DWP($i*16+0,"edi"));
++	&mov	("ebx",&DWP($i*16+4,"edi"));
++	&mov	("ecx",&DWP($i*16+8,"edi"));
++	&bswap	("eax");
++	&mov	("edx",&DWP($i*16+12,"edi"));
++	&bswap	("ebx");
++	&push	("eax");
++	&bswap	("ecx");
++	&push	("ebx");
++	&bswap	("edx");
++	&push	("ecx");
++	&push	("edx");
++    }
++	&add	("edi",64);
++	&lea	("esp",&DWP(-4*9,"esp"));# place for A,B,C,D,E,F,G,H
++	&mov	(&DWP(4*(9+16)+4,"esp"),"edi");
++
++	# copy ctx->h[0-7] to A,B,C,D,E,F,G,H on stack
++	&mov	($A,&DWP(0,"esi"));
++	&mov	("ebx",&DWP(4,"esi"));
++	&mov	("ecx",&DWP(8,"esi"));
++	&mov	("edi",&DWP(12,"esi"));
++	# &mov	($Aoff,$A);
++	&mov	($Boff,"ebx");
++	&xor	("ebx","ecx");
++	&mov	($Coff,"ecx");
++	&mov	($Doff,"edi");
++	&mov	(&DWP(0,"esp"),"ebx");	# magic
++	&mov	($E,&DWP(16,"esi"));	
++	&mov	("ebx",&DWP(20,"esi"));
++	&mov	("ecx",&DWP(24,"esi"));
++	&mov	("edi",&DWP(28,"esi"));
++	# &mov	($Eoff,$E);
++	&mov	($Foff,"ebx");
++	&mov	($Goff,"ecx");
++	&mov	($Hoff,"edi");
++
++&set_label("00_15$suffix",16);
++
++	&BODY_00_15();
++
++	&cmp	("esi",0xc19bf174);
++	&jne	(&label("00_15$suffix"));
++
++	&mov	("ecx",&DWP(4*(9+15+16-1),"esp"));	# preloaded in BODY_00_15(1)
++	&jmp	(&label("16_63$suffix"));
++
++&set_label("16_63$suffix",16);
++
++	&BODY_16_63();
++
++	&cmp	("esi",0xc67178f2);
++	&jne	(&label("16_63$suffix"));
++
++	&mov	("esi",&DWP(4*(9+16+64)+0,"esp"));#ctx
++	# &mov	($A,$Aoff);
++	&mov	("ebx",$Boff);
++	# &mov	("edi",$Coff);
++	&mov	("ecx",$Doff);
++	&add	($A,&DWP(0,"esi"));
++	&add	("ebx",&DWP(4,"esi"));
++	&add	("edi",&DWP(8,"esi"));
++	&add	("ecx",&DWP(12,"esi"));
++	&mov	(&DWP(0,"esi"),$A);
++	&mov	(&DWP(4,"esi"),"ebx");
++	&mov	(&DWP(8,"esi"),"edi");
++	&mov	(&DWP(12,"esi"),"ecx");
++	# &mov	($E,$Eoff);
++	&mov	("eax",$Foff);
++	&mov	("ebx",$Goff);
++	&mov	("ecx",$Hoff);
++	&mov	("edi",&DWP(4*(9+16+64)+4,"esp"));#inp
++	&add	($E,&DWP(16,"esi"));
++	&add	("eax",&DWP(20,"esi"));
++	&add	("ebx",&DWP(24,"esi"));
++	&add	("ecx",&DWP(28,"esi"));
++	&mov	(&DWP(16,"esi"),$E);
++	&mov	(&DWP(20,"esi"),"eax");
++	&mov	(&DWP(24,"esi"),"ebx");
++	&mov	(&DWP(28,"esi"),"ecx");
++
++	&lea	("esp",&DWP(4*(9+16+64),"esp"));# destroy frame
++	&sub	($K256,4*64);			# rewind K
++
++	&cmp	("edi",&DWP(8,"esp"));		# are we done yet?
++	&jb	(&label("loop$suffix"));
++}
++	&COMPACT_LOOP();
++	&mov	("esp",&DWP(12,"esp"));		# restore sp
++&function_end_A();
++						if (!$i386 && !$xmm) {
++	# ~20% improvement on Sandy Bridge
++	local *ror = sub { &shrd(@_[0],@_) };
++	&COMPACT_LOOP("_shrd");
++	&mov	("esp",&DWP(12,"esp"));		# restore sp
++&function_end_A();
++						}
++
++&set_label("K256",64);	# Yes! I keep it in the code segment!
++@K256=(	0x428a2f98,0x71374491,0xb5c0fbcf,0xe9b5dba5,
++	0x3956c25b,0x59f111f1,0x923f82a4,0xab1c5ed5,
++	0xd807aa98,0x12835b01,0x243185be,0x550c7dc3,
++	0x72be5d74,0x80deb1fe,0x9bdc06a7,0xc19bf174,
++	0xe49b69c1,0xefbe4786,0x0fc19dc6,0x240ca1cc,
++	0x2de92c6f,0x4a7484aa,0x5cb0a9dc,0x76f988da,
++	0x983e5152,0xa831c66d,0xb00327c8,0xbf597fc7,
++	0xc6e00bf3,0xd5a79147,0x06ca6351,0x14292967,
++	0x27b70a85,0x2e1b2138,0x4d2c6dfc,0x53380d13,
++	0x650a7354,0x766a0abb,0x81c2c92e,0x92722c85,
++	0xa2bfe8a1,0xa81a664b,0xc24b8b70,0xc76c51a3,
++	0xd192e819,0xd6990624,0xf40e3585,0x106aa070,
++	0x19a4c116,0x1e376c08,0x2748774c,0x34b0bcb5,
++	0x391c0cb3,0x4ed8aa4a,0x5b9cca4f,0x682e6ff3,
++	0x748f82ee,0x78a5636f,0x84c87814,0x8cc70208,
++	0x90befffa,0xa4506ceb,0xbef9a3f7,0xc67178f2	);
++&data_word(@K256);
++&data_word(0x00010203,0x04050607,0x08090a0b,0x0c0d0e0f);	# byte swap mask
++&asciz("SHA256 block transform for x86, CRYPTOGAMS by ");
++
++($a,$b,$c,$d,$e,$f,$g,$h)=(0..7);	# offsets
++sub off { &DWP(4*(((shift)-$i)&7),"esp"); }
++
++if (!$i386 && $unroll_after) {
++my @AH=($A,$K256);
++
++&set_label("unrolled",16);
++	&lea	("esp",&DWP(-96,"esp"));
++	# copy ctx->h[0-7] to A,B,C,D,E,F,G,H on stack
++	&mov	($AH[0],&DWP(0,"esi"));
++	&mov	($AH[1],&DWP(4,"esi"));
++	&mov	("ecx",&DWP(8,"esi"));
++	&mov	("ebx",&DWP(12,"esi"));
++	#&mov	(&DWP(0,"esp"),$AH[0]);
++	&mov	(&DWP(4,"esp"),$AH[1]);
++	&xor	($AH[1],"ecx");		# magic
++	&mov	(&DWP(8,"esp"),"ecx");
++	&mov	(&DWP(12,"esp"),"ebx");
++	&mov	($E,&DWP(16,"esi"));	
++	&mov	("ebx",&DWP(20,"esi"));
++	&mov	("ecx",&DWP(24,"esi"));
++	&mov	("esi",&DWP(28,"esi"));
++	#&mov	(&DWP(16,"esp"),$E);
++	&mov	(&DWP(20,"esp"),"ebx");
++	&mov	(&DWP(24,"esp"),"ecx");
++	&mov	(&DWP(28,"esp"),"esi");
++	&jmp	(&label("grand_loop"));
++
++&set_label("grand_loop",16);
++    # copy input block to stack reversing byte order
++    for($i=0;$i<5;$i++) {
++	&mov	("ebx",&DWP(12*$i+0,"edi"));
++	&mov	("ecx",&DWP(12*$i+4,"edi"));
++	&bswap	("ebx");
++	&mov	("esi",&DWP(12*$i+8,"edi"));
++	&bswap	("ecx");
++	&mov	(&DWP(32+12*$i+0,"esp"),"ebx");
++	&bswap	("esi");
++	&mov	(&DWP(32+12*$i+4,"esp"),"ecx");
++	&mov	(&DWP(32+12*$i+8,"esp"),"esi");
++    }
++	&mov	("ebx",&DWP($i*12,"edi"));
++	&add	("edi",64);
++	&bswap	("ebx");
++	&mov	(&DWP(96+4,"esp"),"edi");
++	&mov	(&DWP(32+12*$i,"esp"),"ebx");
++
++    my ($t1,$t2) = ("ecx","esi");
++
++    for ($i=0;$i<64;$i++) {
++
++      if ($i>=16) {
++	&mov	($T,$t1);			# $t1 is preloaded
++	# &mov	($t2,&DWP(32+4*(($i+14)&15),"esp"));
++	&ror	($t1,18-7);
++	 &mov	("edi",$t2);
++	&ror	($t2,19-17);
++	 &xor	($t1,$T);
++	 &shr	($T,3);
++	&ror	($t1,7);
++	 &xor	($t2,"edi");
++	 &xor	($T,$t1);			# T = sigma0(X[-15])
++	&ror	($t2,17);
++	 &add	($T,&DWP(32+4*($i&15),"esp"));	# T += X[-16]
++	&shr	("edi",10);
++	 &add	($T,&DWP(32+4*(($i+9)&15),"esp"));	# T += X[-7]
++	#&xor	("edi",$t2)			# sigma1(X[-2])
++	# &add	($T,"edi");			# T += sigma1(X[-2])
++	# &mov	(&DWP(4*(9+15),"esp"),$T);	# save X[0]
++      }
++	&mov	($t1,$E);
++	 &xor	("edi",$t2)			if ($i>=16);	# sigma1(X[-2])
++	 &mov	($t2,&off($f));
++	&ror	($E,25-11);
++	 &add	($T,"edi")			if ($i>=16);	# T += sigma1(X[-2])
++	 &mov	("edi",&off($g));
++	&xor	($E,$t1);
++	 &mov	($T,&DWP(32+4*($i&15),"esp"))	if ($i<16);	# X[i]
++	 &mov	(&DWP(32+4*($i&15),"esp"),$T)	if ($i>=16 && $i<62);	# save X[0]
++	 &xor	($t2,"edi");
++	&ror	($E,11-6);
++	 &and	($t2,$t1);
++	 &mov	(&off($e),$t1);		# save $E, modulo-scheduled
++	&xor	($E,$t1);
++	 &add	($T,&off($h));		# T += h
++	 &xor	("edi",$t2);		# Ch(e,f,g)
++	&ror	($E,6);			# Sigma1(e)
++	 &mov	($t1,$AH[0]);
++	 &add	($T,"edi");		# T += Ch(e,f,g)
++
++	&ror	($t1,22-13);
++	 &mov	($t2,$AH[0]);
++	 &mov	("edi",&off($b));
++	&xor	($t1,$AH[0]);
++	 &mov	(&off($a),$AH[0]);	# save $A, modulo-scheduled
++	 &xor	($AH[0],"edi");		# a ^= b, (b^c) in next round
++	&ror	($t1,13-2);
++	 &and	($AH[1],$AH[0]);	# (b^c) &= (a^b)
++	 &lea	($E,&DWP(@K256[$i],$T,$E));	# T += Sigma1(1)+K[i]
++	&xor	($t1,$t2);
++	 &xor	($AH[1],"edi");		# h = Maj(a,b,c) = Ch(a^b,c,b)
++	 &mov	($t2,&DWP(32+4*(($i+2)&15),"esp"))	if ($i>=15 && $i<63);
++	&ror	($t1,2);		# Sigma0(a)
++
++	 &add	($AH[1],$E);		# h += T
++	 &add	($E,&off($d));		# d += T
++	&add	($AH[1],$t1);		# h += Sigma0(a)
++	 &mov	($t1,&DWP(32+4*(($i+15)&15),"esp"))	if ($i>=15 && $i<63);
++
++	@AH = reverse(@AH);		# rotate(a,h)
++	($t1,$t2) = ($t2,$t1);		# rotate(t1,t2)
++    }
++	&mov	("esi",&DWP(96,"esp"));	#ctx
++					#&mov	($AH[0],&DWP(0,"esp"));
++	&xor	($AH[1],"edi");		#&mov	($AH[1],&DWP(4,"esp"));
++					#&mov	("edi", &DWP(8,"esp"));
++	&mov	("ecx",&DWP(12,"esp"));
++	&add	($AH[0],&DWP(0,"esi"));
++	&add	($AH[1],&DWP(4,"esi"));
++	&add	("edi",&DWP(8,"esi"));
++	&add	("ecx",&DWP(12,"esi"));
++	&mov	(&DWP(0,"esi"),$AH[0]);
++	&mov	(&DWP(4,"esi"),$AH[1]);
++	&mov	(&DWP(8,"esi"),"edi");
++	&mov	(&DWP(12,"esi"),"ecx");
++	 #&mov	(&DWP(0,"esp"),$AH[0]);
++	 &mov	(&DWP(4,"esp"),$AH[1]);
++	 &xor	($AH[1],"edi");		# magic
++	 &mov	(&DWP(8,"esp"),"edi");
++	 &mov	(&DWP(12,"esp"),"ecx");
++	#&mov	($E,&DWP(16,"esp"));
++	&mov	("edi",&DWP(20,"esp"));
++	&mov	("ebx",&DWP(24,"esp"));
++	&mov	("ecx",&DWP(28,"esp"));
++	&add	($E,&DWP(16,"esi"));
++	&add	("edi",&DWP(20,"esi"));
++	&add	("ebx",&DWP(24,"esi"));
++	&add	("ecx",&DWP(28,"esi"));
++	&mov	(&DWP(16,"esi"),$E);
++	&mov	(&DWP(20,"esi"),"edi");
++	&mov	(&DWP(24,"esi"),"ebx");
++	&mov	(&DWP(28,"esi"),"ecx");
++	 #&mov	(&DWP(16,"esp"),$E);
++	 &mov	(&DWP(20,"esp"),"edi");
++	&mov	("edi",&DWP(96+4,"esp"));	# inp
++	 &mov	(&DWP(24,"esp"),"ebx");
++	 &mov	(&DWP(28,"esp"),"ecx");
++
++	&cmp	("edi",&DWP(96+8,"esp"));	# are we done yet?
++	&jb	(&label("grand_loop"));
++
++	&mov	("esp",&DWP(96+12,"esp"));	# restore sp
++&function_end_A();
++}
++						if (!$i386 && $xmm) {{{
++if ($shaext) {
++######################################################################
++# Intel SHA Extensions implementation of SHA256 update function.
++#
++my ($ctx,$inp,$end)=("esi","edi","eax");
++my ($Wi,$ABEF,$CDGH,$TMP)=map("xmm$_",(0..2,7));
++my @MSG=map("xmm$_",(3..6));
++
++sub sha256op38 {
++ my ($opcodelet,$dst,$src)=@_;
++    if ("$dst:$src" =~ /xmm([0-7]):xmm([0-7])/)
++    {	&data_byte(0x0f,0x38,$opcodelet,0xc0|($1<<3)|$2);	}
++}
++sub sha256rnds2	{ sha256op38(0xcb,@_); }
++sub sha256msg1	{ sha256op38(0xcc,@_); }
++sub sha256msg2	{ sha256op38(0xcd,@_); }
++
++&set_label("shaext",32);
++	&sub		("esp",32);
++
++	&movdqu		($ABEF,&QWP(0,$ctx));		# DCBA
++	&lea		($K256,&DWP(0x80,$K256));
++	&movdqu		($CDGH,&QWP(16,$ctx));		# HGFE
++	&movdqa		($TMP,&QWP(0x100-0x80,$K256));	# byte swap mask
++
++	&pshufd		($Wi,$ABEF,0x1b);		# ABCD
++	&pshufd		($ABEF,$ABEF,0xb1);		# CDAB
++	&pshufd		($CDGH,$CDGH,0x1b);		# EFGH
++	&palignr	($ABEF,$CDGH,8);		# ABEF
++	&punpcklqdq	($CDGH,$Wi);			# CDGH
++	&jmp		(&label("loop_shaext"));
++
++&set_label("loop_shaext",16);
++	&movdqu		(@MSG[0],&QWP(0,$inp));
++	&movdqu		(@MSG[1],&QWP(0x10,$inp));
++	&movdqu		(@MSG[2],&QWP(0x20,$inp));
++	&pshufb		(@MSG[0],$TMP);
++	&movdqu		(@MSG[3],&QWP(0x30,$inp));
++	&movdqa		(&QWP(16,"esp"),$CDGH);		# offload
++
++	&movdqa		($Wi,&QWP(0*16-0x80,$K256));
++	&paddd		($Wi,@MSG[0]);
++	&pshufb		(@MSG[1],$TMP);
++	&sha256rnds2	($CDGH,$ABEF);			# 0-3
++	&pshufd		($Wi,$Wi,0x0e);
++	&nop		();
++	&movdqa		(&QWP(0,"esp"),$ABEF);		# offload
++	&sha256rnds2	($ABEF,$CDGH);
++
++	&movdqa		($Wi,&QWP(1*16-0x80,$K256));
++	&paddd		($Wi,@MSG[1]);
++	&pshufb		(@MSG[2],$TMP);
++	&sha256rnds2	($CDGH,$ABEF);			# 4-7
++	&pshufd		($Wi,$Wi,0x0e);
++	&lea		($inp,&DWP(0x40,$inp));
++	&sha256msg1	(@MSG[0],@MSG[1]);
++	&sha256rnds2	($ABEF,$CDGH);
++
++	&movdqa		($Wi,&QWP(2*16-0x80,$K256));
++	&paddd		($Wi,@MSG[2]);
++	&pshufb		(@MSG[3],$TMP);
++	&sha256rnds2	($CDGH,$ABEF);			# 8-11
++	&pshufd		($Wi,$Wi,0x0e);
++	&movdqa		($TMP,@MSG[3]);
++	&palignr	($TMP,@MSG[2],4);
++	&nop		();
++	&paddd		(@MSG[0],$TMP);
++	&sha256msg1	(@MSG[1],@MSG[2]);
++	&sha256rnds2	($ABEF,$CDGH);
++
++	&movdqa		($Wi,&QWP(3*16-0x80,$K256));
++	&paddd		($Wi,@MSG[3]);
++	&sha256msg2	(@MSG[0],@MSG[3]);
++	&sha256rnds2	($CDGH,$ABEF);			# 12-15
++	&pshufd		($Wi,$Wi,0x0e);
++	&movdqa		($TMP,@MSG[0]);
++	&palignr	($TMP,@MSG[3],4);
++	&nop		();
++	&paddd		(@MSG[1],$TMP);
++	&sha256msg1	(@MSG[2],@MSG[3]);
++	&sha256rnds2	($ABEF,$CDGH);
++
++for($i=4;$i<16-3;$i++) {
++	&movdqa		($Wi,&QWP($i*16-0x80,$K256));
++	&paddd		($Wi,@MSG[0]);
++	&sha256msg2	(@MSG[1],@MSG[0]);
++	&sha256rnds2	($CDGH,$ABEF);			# 16-19...
++	&pshufd		($Wi,$Wi,0x0e);
++	&movdqa		($TMP,@MSG[1]);
++	&palignr	($TMP,@MSG[0],4);
++	&nop		();
++	&paddd		(@MSG[2],$TMP);
++	&sha256msg1	(@MSG[3],@MSG[0]);
++	&sha256rnds2	($ABEF,$CDGH);
++
++	push(@MSG,shift(@MSG));
++}
++	&movdqa		($Wi,&QWP(13*16-0x80,$K256));
++	&paddd		($Wi,@MSG[0]);
++	&sha256msg2	(@MSG[1],@MSG[0]);
++	&sha256rnds2	($CDGH,$ABEF);			# 52-55
++	&pshufd		($Wi,$Wi,0x0e);
++	&movdqa		($TMP,@MSG[1])
++	&palignr	($TMP,@MSG[0],4);
++	&sha256rnds2	($ABEF,$CDGH);
++	&paddd		(@MSG[2],$TMP);
++
++	&movdqa		($Wi,&QWP(14*16-0x80,$K256));
++	&paddd		($Wi,@MSG[1]);
++	&sha256rnds2	($CDGH,$ABEF);			# 56-59
++	&pshufd		($Wi,$Wi,0x0e);
++	&sha256msg2	(@MSG[2],@MSG[1]);
++	&movdqa		($TMP,&QWP(0x100-0x80,$K256));	# byte swap mask
++	&sha256rnds2	($ABEF,$CDGH);
++
++	&movdqa		($Wi,&QWP(15*16-0x80,$K256));
++	&paddd		($Wi,@MSG[2]);
++	&nop		();
++	&sha256rnds2	($CDGH,$ABEF);			# 60-63
++	&pshufd		($Wi,$Wi,0x0e);
++	&cmp		($end,$inp);
++	&nop		();
++	&sha256rnds2	($ABEF,$CDGH);
++
++	&paddd		($CDGH,&QWP(16,"esp"));
++	&paddd		($ABEF,&QWP(0,"esp"));
++	&jnz		(&label("loop_shaext"));
++
++	&pshufd		($CDGH,$CDGH,0xb1);		# DCHG
++	&pshufd		($TMP,$ABEF,0x1b);		# FEBA
++	&pshufd		($ABEF,$ABEF,0xb1);		# BAFE
++	&punpckhqdq	($ABEF,$CDGH);			# DCBA
++	&palignr	($CDGH,$TMP,8);			# HGFE
++
++	&mov		("esp",&DWP(32+12,"esp"));
++	&movdqu		(&QWP(0,$ctx),$ABEF);
++	&movdqu		(&QWP(16,$ctx),$CDGH);
++&function_end_A();
++}
++
++my @X = map("xmm$_",(0..3));
++my ($t0,$t1,$t2,$t3) = map("xmm$_",(4..7));
++my @AH = ($A,$T);
++
++&set_label("SSSE3",32);
++	&lea	("esp",&DWP(-96,"esp"));
++	# copy ctx->h[0-7] to A,B,C,D,E,F,G,H on stack
++	&mov	($AH[0],&DWP(0,"esi"));
++	&mov	($AH[1],&DWP(4,"esi"));
++	&mov	("ecx",&DWP(8,"esi"));
++	&mov	("edi",&DWP(12,"esi"));
++	#&mov	(&DWP(0,"esp"),$AH[0]);
++	&mov	(&DWP(4,"esp"),$AH[1]);
++	&xor	($AH[1],"ecx");			# magic
++	&mov	(&DWP(8,"esp"),"ecx");
++	&mov	(&DWP(12,"esp"),"edi");
++	&mov	($E,&DWP(16,"esi"));
++	&mov	("edi",&DWP(20,"esi"));
++	&mov	("ecx",&DWP(24,"esi"));
++	&mov	("esi",&DWP(28,"esi"));
++	#&mov	(&DWP(16,"esp"),$E);
++	&mov	(&DWP(20,"esp"),"edi");
++	&mov	("edi",&DWP(96+4,"esp"));	# inp
++	&mov	(&DWP(24,"esp"),"ecx");
++	&mov	(&DWP(28,"esp"),"esi");
++	&movdqa	($t3,&QWP(256,$K256));
++	&jmp	(&label("grand_ssse3"));
++
++&set_label("grand_ssse3",16);
++	# load input, reverse byte order, add K256[0..15], save to stack
++	&movdqu	(@X[0],&QWP(0,"edi"));
++	&movdqu	(@X[1],&QWP(16,"edi"));
++	&movdqu	(@X[2],&QWP(32,"edi"));
++	&movdqu	(@X[3],&QWP(48,"edi"));
++	&add	("edi",64);
++	&pshufb	(@X[0],$t3);
++	&mov	(&DWP(96+4,"esp"),"edi");
++	&pshufb	(@X[1],$t3);
++	&movdqa	($t0,&QWP(0,$K256));
++	&pshufb	(@X[2],$t3);
++	&movdqa	($t1,&QWP(16,$K256));
++	&paddd	($t0,@X[0]);
++	&pshufb	(@X[3],$t3);
++	&movdqa	($t2,&QWP(32,$K256));
++	&paddd	($t1,@X[1]);
++	&movdqa	($t3,&QWP(48,$K256));
++	&movdqa	(&QWP(32+0,"esp"),$t0);
++	&paddd	($t2,@X[2]);
++	&movdqa	(&QWP(32+16,"esp"),$t1);
++	&paddd	($t3,@X[3]);
++	&movdqa	(&QWP(32+32,"esp"),$t2);
++	&movdqa	(&QWP(32+48,"esp"),$t3);
++	&jmp	(&label("ssse3_00_47"));
++
++&set_label("ssse3_00_47",16);
++	&add		($K256,64);
++
++sub SSSE3_00_47 () {
++my $j = shift;
++my $body = shift;
++my @X = @_;
++my @insns = (&$body,&$body,&$body,&$body);	# 120 instructions
++
++	  eval(shift(@insns));
++	&movdqa		($t0,@X[1]);
++	  eval(shift(@insns));			# @
++	  eval(shift(@insns));
++	&movdqa		($t3,@X[3]);
++	  eval(shift(@insns));
++	  eval(shift(@insns));
++	&palignr	($t0,@X[0],4);		# X[1..4]
++	  eval(shift(@insns));
++	  eval(shift(@insns));			# @
++	  eval(shift(@insns));
++	 &palignr	($t3,@X[2],4);		# X[9..12]
++	  eval(shift(@insns));
++	  eval(shift(@insns));
++	  eval(shift(@insns));
++	&movdqa		($t1,$t0);
++	  eval(shift(@insns));			# @
++	  eval(shift(@insns));
++	&movdqa		($t2,$t0);
++	  eval(shift(@insns));
++	  eval(shift(@insns));
++	&psrld		($t0,3);
++	  eval(shift(@insns));
++	  eval(shift(@insns));			# @
++	 &paddd		(@X[0],$t3);		# X[0..3] += X[9..12]
++	  eval(shift(@insns));
++	  eval(shift(@insns));
++	&psrld		($t2,7);
++	  eval(shift(@insns));
++	  eval(shift(@insns));
++	  eval(shift(@insns));			# @
++	  eval(shift(@insns));
++	 &pshufd	($t3,@X[3],0b11111010);	# X[14..15]
++	  eval(shift(@insns));
++	  eval(shift(@insns));
++	&pslld		($t1,32-18);
++	  eval(shift(@insns));
++	  eval(shift(@insns));			# @
++	&pxor		($t0,$t2);
++	  eval(shift(@insns));
++	  eval(shift(@insns));
++	&psrld		($t2,18-7);
++	  eval(shift(@insns));
++	  eval(shift(@insns));
++	  eval(shift(@insns));			# @
++	&pxor		($t0,$t1);
++	  eval(shift(@insns));
++	  eval(shift(@insns));
++	&pslld		($t1,18-7);
++	  eval(shift(@insns));
++	  eval(shift(@insns));
++	  eval(shift(@insns));			# @
++	&pxor		($t0,$t2);
++	  eval(shift(@insns));
++	  eval(shift(@insns));
++	 &movdqa	($t2,$t3);
++	  eval(shift(@insns));
++	  eval(shift(@insns));
++	  eval(shift(@insns));			# @
++	&pxor		($t0,$t1);		# sigma0(X[1..4])
++	  eval(shift(@insns));
++	  eval(shift(@insns));
++	 &psrld		($t3,10);
++	  eval(shift(@insns));
++	  eval(shift(@insns));
++	  eval(shift(@insns));			# @
++	&paddd		(@X[0],$t0);		# X[0..3] += sigma0(X[1..4])
++	  eval(shift(@insns));
++	  eval(shift(@insns));
++	 &psrlq		($t2,17);
++	  eval(shift(@insns));
++	  eval(shift(@insns));
++	  eval(shift(@insns));			# @
++	 &pxor		($t3,$t2);
++	  eval(shift(@insns));
++	  eval(shift(@insns));
++	 &psrlq		($t2,19-17);
++	  eval(shift(@insns));
++	  eval(shift(@insns));
++	  eval(shift(@insns));			# @
++	 &pxor		($t3,$t2);
++	  eval(shift(@insns));
++	  eval(shift(@insns));
++	 &pshufd	($t3,$t3,0b10000000);
++	  eval(shift(@insns));
++	  eval(shift(@insns));
++	  eval(shift(@insns));			# @
++	  eval(shift(@insns));
++	  eval(shift(@insns));
++	  eval(shift(@insns));
++	  eval(shift(@insns));
++	  eval(shift(@insns));			# @
++	  eval(shift(@insns));
++	 &psrldq	($t3,8);
++	  eval(shift(@insns));
++	  eval(shift(@insns));
++	  eval(shift(@insns));
++	&paddd		(@X[0],$t3);		# X[0..1] += sigma1(X[14..15])
++	  eval(shift(@insns));			# @
++	  eval(shift(@insns));
++	  eval(shift(@insns));
++	  eval(shift(@insns));
++	  eval(shift(@insns));
++	  eval(shift(@insns));			# @
++	  eval(shift(@insns));
++	 &pshufd	($t3,@X[0],0b01010000);	# X[16..17]
++	  eval(shift(@insns));
++	  eval(shift(@insns));
++	  eval(shift(@insns));
++	 &movdqa	($t2,$t3);
++	  eval(shift(@insns));			# @
++	 &psrld		($t3,10);
++	  eval(shift(@insns));
++	 &psrlq		($t2,17);
++	  eval(shift(@insns));
++	  eval(shift(@insns));
++	  eval(shift(@insns));
++	  eval(shift(@insns));			# @
++	 &pxor		($t3,$t2);
++	  eval(shift(@insns));
++	  eval(shift(@insns));
++	 &psrlq		($t2,19-17);
++	  eval(shift(@insns));
++	  eval(shift(@insns));
++	  eval(shift(@insns));			# @
++	 &pxor		($t3,$t2);
++	  eval(shift(@insns));
++	  eval(shift(@insns));
++	  eval(shift(@insns));
++	 &pshufd	($t3,$t3,0b00001000);
++	  eval(shift(@insns));
++	  eval(shift(@insns));			# @
++	&movdqa		($t2,&QWP(16*$j,$K256));
++	  eval(shift(@insns));
++	  eval(shift(@insns));
++	 &pslldq	($t3,8);
++	  eval(shift(@insns));
++	  eval(shift(@insns));
++	  eval(shift(@insns));			# @
++	  eval(shift(@insns));
++	  eval(shift(@insns));
++	  eval(shift(@insns));
++	  eval(shift(@insns));
++	  eval(shift(@insns));			# @
++	&paddd		(@X[0],$t3);		# X[2..3] += sigma1(X[16..17])
++	  eval(shift(@insns));
++	  eval(shift(@insns));
++	  eval(shift(@insns));
++	  eval(shift(@insns));
++	&paddd		($t2,@X[0]);
++	  eval(shift(@insns));			# @
++
++	foreach (@insns) { eval; }		# remaining instructions
++
++	&movdqa		(&QWP(32+16*$j,"esp"),$t2);
++}
++
++sub body_00_15 () {
++	(
++	'&mov	("ecx",$E);',
++	'&ror	($E,25-11);',
++	 '&mov	("esi",&off($f));',
++	'&xor	($E,"ecx");',
++	 '&mov	("edi",&off($g));',
++	 '&xor	("esi","edi");',
++	'&ror	($E,11-6);',
++	 '&and	("esi","ecx");',
++	 '&mov	(&off($e),"ecx");',	# save $E, modulo-scheduled
++	'&xor	($E,"ecx");',
++	 '&xor	("edi","esi");',	# Ch(e,f,g)
++	'&ror	($E,6);',		# T = Sigma1(e)
++	 '&mov	("ecx",$AH[0]);',
++	 '&add	($E,"edi");',		# T += Ch(e,f,g)
++	 '&mov	("edi",&off($b));',
++	'&mov	("esi",$AH[0]);',
++
++	'&ror	("ecx",22-13);',
++	 '&mov	(&off($a),$AH[0]);',	# save $A, modulo-scheduled
++	'&xor	("ecx",$AH[0]);',
++	 '&xor	($AH[0],"edi");',	# a ^= b, (b^c) in next round
++	 '&add	($E,&off($h));',	# T += h
++	'&ror	("ecx",13-2);',
++	 '&and	($AH[1],$AH[0]);',	# (b^c) &= (a^b)
++	'&xor	("ecx","esi");',
++	 '&add	($E,&DWP(32+4*($i&15),"esp"));',	# T += K[i]+X[i]
++	 '&xor	($AH[1],"edi");',	# h = Maj(a,b,c) = Ch(a^b,c,b)
++	'&ror	("ecx",2);',		# Sigma0(a)
++
++	 '&add	($AH[1],$E);',		# h += T
++	 '&add	($E,&off($d));',	# d += T
++	'&add	($AH[1],"ecx");'.	# h += Sigma0(a)
++
++	'@AH = reverse(@AH); $i++;'	# rotate(a,h)
++	);
++}
++
++    for ($i=0,$j=0; $j<4; $j++) {
++	&SSSE3_00_47($j,\&body_00_15,@X);
++	push(@X,shift(@X));		# rotate(@X)
++    }
++	&cmp	(&DWP(16*$j,$K256),0x00010203);
++	&jne	(&label("ssse3_00_47"));
++
++    for ($i=0; $i<16; ) {
++	foreach(body_00_15()) { eval; }
++    }
++
++	&mov	("esi",&DWP(96,"esp"));	#ctx
++					#&mov	($AH[0],&DWP(0,"esp"));
++	&xor	($AH[1],"edi");		#&mov	($AH[1],&DWP(4,"esp"));
++					#&mov	("edi", &DWP(8,"esp"));
++	&mov	("ecx",&DWP(12,"esp"));
++	&add	($AH[0],&DWP(0,"esi"));
++	&add	($AH[1],&DWP(4,"esi"));
++	&add	("edi",&DWP(8,"esi"));
++	&add	("ecx",&DWP(12,"esi"));
++	&mov	(&DWP(0,"esi"),$AH[0]);
++	&mov	(&DWP(4,"esi"),$AH[1]);
++	&mov	(&DWP(8,"esi"),"edi");
++	&mov	(&DWP(12,"esi"),"ecx");
++	 #&mov	(&DWP(0,"esp"),$AH[0]);
++	 &mov	(&DWP(4,"esp"),$AH[1]);
++	 &xor	($AH[1],"edi");			# magic
++	 &mov	(&DWP(8,"esp"),"edi");
++	 &mov	(&DWP(12,"esp"),"ecx");
++	#&mov	($E,&DWP(16,"esp"));
++	&mov	("edi",&DWP(20,"esp"));
++	&mov	("ecx",&DWP(24,"esp"));
++	&add	($E,&DWP(16,"esi"));
++	&add	("edi",&DWP(20,"esi"));
++	&add	("ecx",&DWP(24,"esi"));
++	&mov	(&DWP(16,"esi"),$E);
++	&mov	(&DWP(20,"esi"),"edi");
++	 &mov	(&DWP(20,"esp"),"edi");
++	&mov	("edi",&DWP(28,"esp"));
++	&mov	(&DWP(24,"esi"),"ecx");
++	 #&mov	(&DWP(16,"esp"),$E);
++	&add	("edi",&DWP(28,"esi"));
++	 &mov	(&DWP(24,"esp"),"ecx");
++	&mov	(&DWP(28,"esi"),"edi");
++	 &mov	(&DWP(28,"esp"),"edi");
++	&mov	("edi",&DWP(96+4,"esp"));	# inp
++
++	&movdqa	($t3,&QWP(64,$K256));
++	&sub	($K256,3*64);			# rewind K
++	&cmp	("edi",&DWP(96+8,"esp"));	# are we done yet?
++	&jb	(&label("grand_ssse3"));
++
++	&mov	("esp",&DWP(96+12,"esp"));	# restore sp
++&function_end_A();
++						if ($avx) {
++&set_label("AVX",32);
++						if ($avx>1) {
++	&and	("edx",1<<8|1<<3);		# check for BMI2+BMI1
++	&cmp	("edx",1<<8|1<<3);
++	&je	(&label("AVX_BMI"));
++						}
++	&lea	("esp",&DWP(-96,"esp"));
++	&vzeroall	();
++	# copy ctx->h[0-7] to A,B,C,D,E,F,G,H on stack
++	&mov	($AH[0],&DWP(0,"esi"));
++	&mov	($AH[1],&DWP(4,"esi"));
++	&mov	("ecx",&DWP(8,"esi"));
++	&mov	("edi",&DWP(12,"esi"));
++	#&mov	(&DWP(0,"esp"),$AH[0]);
++	&mov	(&DWP(4,"esp"),$AH[1]);
++	&xor	($AH[1],"ecx");			# magic
++	&mov	(&DWP(8,"esp"),"ecx");
++	&mov	(&DWP(12,"esp"),"edi");
++	&mov	($E,&DWP(16,"esi"));
++	&mov	("edi",&DWP(20,"esi"));
++	&mov	("ecx",&DWP(24,"esi"));
++	&mov	("esi",&DWP(28,"esi"));
++	#&mov	(&DWP(16,"esp"),$E);
++	&mov	(&DWP(20,"esp"),"edi");
++	&mov	("edi",&DWP(96+4,"esp"));	# inp
++	&mov	(&DWP(24,"esp"),"ecx");
++	&mov	(&DWP(28,"esp"),"esi");
++	&vmovdqa	($t3,&QWP(256,$K256));
++	&jmp	(&label("grand_avx"));
++
++&set_label("grand_avx",32);
++	# load input, reverse byte order, add K256[0..15], save to stack
++	&vmovdqu	(@X[0],&QWP(0,"edi"));
++	&vmovdqu	(@X[1],&QWP(16,"edi"));
++	&vmovdqu	(@X[2],&QWP(32,"edi"));
++	&vmovdqu	(@X[3],&QWP(48,"edi"));
++	&add		("edi",64);
++	&vpshufb	(@X[0],@X[0],$t3);
++	&mov		(&DWP(96+4,"esp"),"edi");
++	&vpshufb	(@X[1],@X[1],$t3);
++	&vpshufb	(@X[2],@X[2],$t3);
++	&vpaddd		($t0,@X[0],&QWP(0,$K256));
++	&vpshufb	(@X[3],@X[3],$t3);
++	&vpaddd		($t1,@X[1],&QWP(16,$K256));
++	&vpaddd		($t2,@X[2],&QWP(32,$K256));
++	&vpaddd		($t3,@X[3],&QWP(48,$K256));
++	&vmovdqa	(&QWP(32+0,"esp"),$t0);
++	&vmovdqa	(&QWP(32+16,"esp"),$t1);
++	&vmovdqa	(&QWP(32+32,"esp"),$t2);
++	&vmovdqa	(&QWP(32+48,"esp"),$t3);
++	&jmp		(&label("avx_00_47"));
++
++&set_label("avx_00_47",16);
++	&add		($K256,64);
++
++sub Xupdate_AVX () {
++	(
++	'&vpalignr	($t0,@X[1],@X[0],4);',	# X[1..4]
++	 '&vpalignr	($t3,@X[3],@X[2],4);',	# X[9..12]
++	'&vpsrld	($t2,$t0,7);',
++	 '&vpaddd	(@X[0],@X[0],$t3);',	# X[0..3] += X[9..16]
++	'&vpsrld	($t3,$t0,3);',
++	'&vpslld	($t1,$t0,14);',
++	'&vpxor		($t0,$t3,$t2);',
++	 '&vpshufd	($t3,@X[3],0b11111010)',# X[14..15]
++	'&vpsrld	($t2,$t2,18-7);',
++	'&vpxor		($t0,$t0,$t1);',
++	'&vpslld	($t1,$t1,25-14);',
++	'&vpxor		($t0,$t0,$t2);',
++	 '&vpsrld	($t2,$t3,10);',
++	'&vpxor		($t0,$t0,$t1);',	# sigma0(X[1..4])
++	 '&vpsrlq	($t1,$t3,17);',
++	'&vpaddd	(@X[0],@X[0],$t0);',	# X[0..3] += sigma0(X[1..4])
++	 '&vpxor	($t2,$t2,$t1);',
++	 '&vpsrlq	($t3,$t3,19);',
++	 '&vpxor	($t2,$t2,$t3);',	# sigma1(X[14..15]
++	 '&vpshufd	($t3,$t2,0b10000100);',
++	'&vpsrldq	($t3,$t3,8);',
++	'&vpaddd	(@X[0],@X[0],$t3);',	# X[0..1] += sigma1(X[14..15])
++	 '&vpshufd	($t3,@X[0],0b01010000)',# X[16..17]
++	 '&vpsrld	($t2,$t3,10);',
++	 '&vpsrlq	($t1,$t3,17);',
++	 '&vpxor	($t2,$t2,$t1);',
++	 '&vpsrlq	($t3,$t3,19);',
++	 '&vpxor	($t2,$t2,$t3);',	# sigma1(X[16..17]
++	 '&vpshufd	($t3,$t2,0b11101000);',
++	'&vpslldq	($t3,$t3,8);',
++	'&vpaddd	(@X[0],@X[0],$t3);'	# X[2..3] += sigma1(X[16..17])
++	);
++}
++
++local *ror = sub { &shrd(@_[0],@_) };
++sub AVX_00_47 () {
++my $j = shift;
++my $body = shift;
++my @X = @_;
++my @insns = (&$body,&$body,&$body,&$body);	# 120 instructions
++my $insn;
++
++	foreach (Xupdate_AVX()) {		# 31 instructions
++	    eval;
++	    eval(shift(@insns));
++	    eval(shift(@insns));
++	    eval($insn = shift(@insns));
++	    eval(shift(@insns)) if ($insn =~ /rorx/ && @insns[0] =~ /rorx/);
++	}
++	&vpaddd		($t2,@X[0],&QWP(16*$j,$K256));
++	foreach (@insns) { eval; }		# remaining instructions
++	&vmovdqa	(&QWP(32+16*$j,"esp"),$t2);
++}
++
++    for ($i=0,$j=0; $j<4; $j++) {
++	&AVX_00_47($j,\&body_00_15,@X);
++	push(@X,shift(@X));		# rotate(@X)
++    }
++	&cmp	(&DWP(16*$j,$K256),0x00010203);
++	&jne	(&label("avx_00_47"));
++
++    for ($i=0; $i<16; ) {
++	foreach(body_00_15()) { eval; }
++    }
++
++	&mov	("esi",&DWP(96,"esp"));	#ctx
++					#&mov	($AH[0],&DWP(0,"esp"));
++	&xor	($AH[1],"edi");		#&mov	($AH[1],&DWP(4,"esp"));
++					#&mov	("edi", &DWP(8,"esp"));
++	&mov	("ecx",&DWP(12,"esp"));
++	&add	($AH[0],&DWP(0,"esi"));
++	&add	($AH[1],&DWP(4,"esi"));
++	&add	("edi",&DWP(8,"esi"));
++	&add	("ecx",&DWP(12,"esi"));
++	&mov	(&DWP(0,"esi"),$AH[0]);
++	&mov	(&DWP(4,"esi"),$AH[1]);
++	&mov	(&DWP(8,"esi"),"edi");
++	&mov	(&DWP(12,"esi"),"ecx");
++	 #&mov	(&DWP(0,"esp"),$AH[0]);
++	 &mov	(&DWP(4,"esp"),$AH[1]);
++	 &xor	($AH[1],"edi");			# magic
++	 &mov	(&DWP(8,"esp"),"edi");
++	 &mov	(&DWP(12,"esp"),"ecx");
++	#&mov	($E,&DWP(16,"esp"));
++	&mov	("edi",&DWP(20,"esp"));
++	&mov	("ecx",&DWP(24,"esp"));
++	&add	($E,&DWP(16,"esi"));
++	&add	("edi",&DWP(20,"esi"));
++	&add	("ecx",&DWP(24,"esi"));
++	&mov	(&DWP(16,"esi"),$E);
++	&mov	(&DWP(20,"esi"),"edi");
++	 &mov	(&DWP(20,"esp"),"edi");
++	&mov	("edi",&DWP(28,"esp"));
++	&mov	(&DWP(24,"esi"),"ecx");
++	 #&mov	(&DWP(16,"esp"),$E);
++	&add	("edi",&DWP(28,"esi"));
++	 &mov	(&DWP(24,"esp"),"ecx");
++	&mov	(&DWP(28,"esi"),"edi");
++	 &mov	(&DWP(28,"esp"),"edi");
++	&mov	("edi",&DWP(96+4,"esp"));	# inp
++
++	&vmovdqa	($t3,&QWP(64,$K256));
++	&sub	($K256,3*64);			# rewind K
++	&cmp	("edi",&DWP(96+8,"esp"));	# are we done yet?
++	&jb	(&label("grand_avx"));
++
++	&mov	("esp",&DWP(96+12,"esp"));	# restore sp
++	&vzeroall	();
++&function_end_A();
++						if ($avx>1) {
++sub bodyx_00_15 () {			# +10%
++	(
++	'&rorx	("ecx",$E,6)',
++	'&rorx	("esi",$E,11)',
++	 '&mov	(&off($e),$E)',		# save $E, modulo-scheduled
++	'&rorx	("edi",$E,25)',
++	'&xor	("ecx","esi")',
++	 '&andn	("esi",$E,&off($g))',
++	'&xor	("ecx","edi")',		# Sigma1(e)
++	 '&and	($E,&off($f))',
++	 '&mov	(&off($a),$AH[0]);',	# save $A, modulo-scheduled
++	 '&or	($E,"esi")',		# T = Ch(e,f,g)
++
++	'&rorx	("edi",$AH[0],2)',
++	'&rorx	("esi",$AH[0],13)',
++	 '&lea	($E,&DWP(0,$E,"ecx"))',	# T += Sigma1(e)
++	'&rorx	("ecx",$AH[0],22)',
++	'&xor	("esi","edi")',
++	 '&mov	("edi",&off($b))',
++	'&xor	("ecx","esi")',		# Sigma0(a)
++
++	 '&xor	($AH[0],"edi")',	# a ^= b, (b^c) in next round
++	 '&add	($E,&off($h))',		# T += h
++	 '&and	($AH[1],$AH[0])',	# (b^c) &= (a^b)
++	 '&add	($E,&DWP(32+4*($i&15),"esp"))',	# T += K[i]+X[i]
++	 '&xor	($AH[1],"edi")',	# h = Maj(a,b,c) = Ch(a^b,c,b)
++
++	 '&add	("ecx",$E)',		# h += T
++	 '&add	($E,&off($d))',		# d += T
++	'&lea	($AH[1],&DWP(0,$AH[1],"ecx"));'.	# h += Sigma0(a)
++
++	'@AH = reverse(@AH); $i++;'	# rotate(a,h)
++	);
++}
++
++&set_label("AVX_BMI",32);
++	&lea	("esp",&DWP(-96,"esp"));
++	&vzeroall	();
++	# copy ctx->h[0-7] to A,B,C,D,E,F,G,H on stack
++	&mov	($AH[0],&DWP(0,"esi"));
++	&mov	($AH[1],&DWP(4,"esi"));
++	&mov	("ecx",&DWP(8,"esi"));
++	&mov	("edi",&DWP(12,"esi"));
++	#&mov	(&DWP(0,"esp"),$AH[0]);
++	&mov	(&DWP(4,"esp"),$AH[1]);
++	&xor	($AH[1],"ecx");			# magic
++	&mov	(&DWP(8,"esp"),"ecx");
++	&mov	(&DWP(12,"esp"),"edi");
++	&mov	($E,&DWP(16,"esi"));
++	&mov	("edi",&DWP(20,"esi"));
++	&mov	("ecx",&DWP(24,"esi"));
++	&mov	("esi",&DWP(28,"esi"));
++	#&mov	(&DWP(16,"esp"),$E);
++	&mov	(&DWP(20,"esp"),"edi");
++	&mov	("edi",&DWP(96+4,"esp"));	# inp
++	&mov	(&DWP(24,"esp"),"ecx");
++	&mov	(&DWP(28,"esp"),"esi");
++	&vmovdqa	($t3,&QWP(256,$K256));
++	&jmp	(&label("grand_avx_bmi"));
++
++&set_label("grand_avx_bmi",32);
++	# load input, reverse byte order, add K256[0..15], save to stack
++	&vmovdqu	(@X[0],&QWP(0,"edi"));
++	&vmovdqu	(@X[1],&QWP(16,"edi"));
++	&vmovdqu	(@X[2],&QWP(32,"edi"));
++	&vmovdqu	(@X[3],&QWP(48,"edi"));
++	&add		("edi",64);
++	&vpshufb	(@X[0],@X[0],$t3);
++	&mov		(&DWP(96+4,"esp"),"edi");
++	&vpshufb	(@X[1],@X[1],$t3);
++	&vpshufb	(@X[2],@X[2],$t3);
++	&vpaddd		($t0,@X[0],&QWP(0,$K256));
++	&vpshufb	(@X[3],@X[3],$t3);
++	&vpaddd		($t1,@X[1],&QWP(16,$K256));
++	&vpaddd		($t2,@X[2],&QWP(32,$K256));
++	&vpaddd		($t3,@X[3],&QWP(48,$K256));
++	&vmovdqa	(&QWP(32+0,"esp"),$t0);
++	&vmovdqa	(&QWP(32+16,"esp"),$t1);
++	&vmovdqa	(&QWP(32+32,"esp"),$t2);
++	&vmovdqa	(&QWP(32+48,"esp"),$t3);
++	&jmp		(&label("avx_bmi_00_47"));
++
++&set_label("avx_bmi_00_47",16);
++	&add		($K256,64);
++
++    for ($i=0,$j=0; $j<4; $j++) {
++	&AVX_00_47($j,\&bodyx_00_15,@X);
++	push(@X,shift(@X));		# rotate(@X)
++    }
++	&cmp	(&DWP(16*$j,$K256),0x00010203);
++	&jne	(&label("avx_bmi_00_47"));
++
++    for ($i=0; $i<16; ) {
++	foreach(bodyx_00_15()) { eval; }
++    }
++
++	&mov	("esi",&DWP(96,"esp"));	#ctx
++					#&mov	($AH[0],&DWP(0,"esp"));
++	&xor	($AH[1],"edi");		#&mov	($AH[1],&DWP(4,"esp"));
++					#&mov	("edi", &DWP(8,"esp"));
++	&mov	("ecx",&DWP(12,"esp"));
++	&add	($AH[0],&DWP(0,"esi"));
++	&add	($AH[1],&DWP(4,"esi"));
++	&add	("edi",&DWP(8,"esi"));
++	&add	("ecx",&DWP(12,"esi"));
++	&mov	(&DWP(0,"esi"),$AH[0]);
++	&mov	(&DWP(4,"esi"),$AH[1]);
++	&mov	(&DWP(8,"esi"),"edi");
++	&mov	(&DWP(12,"esi"),"ecx");
++	 #&mov	(&DWP(0,"esp"),$AH[0]);
++	 &mov	(&DWP(4,"esp"),$AH[1]);
++	 &xor	($AH[1],"edi");			# magic
++	 &mov	(&DWP(8,"esp"),"edi");
++	 &mov	(&DWP(12,"esp"),"ecx");
++	#&mov	($E,&DWP(16,"esp"));
++	&mov	("edi",&DWP(20,"esp"));
++	&mov	("ecx",&DWP(24,"esp"));
++	&add	($E,&DWP(16,"esi"));
++	&add	("edi",&DWP(20,"esi"));
++	&add	("ecx",&DWP(24,"esi"));
++	&mov	(&DWP(16,"esi"),$E);
++	&mov	(&DWP(20,"esi"),"edi");
++	 &mov	(&DWP(20,"esp"),"edi");
++	&mov	("edi",&DWP(28,"esp"));
++	&mov	(&DWP(24,"esi"),"ecx");
++	 #&mov	(&DWP(16,"esp"),$E);
++	&add	("edi",&DWP(28,"esi"));
++	 &mov	(&DWP(24,"esp"),"ecx");
++	&mov	(&DWP(28,"esi"),"edi");
++	 &mov	(&DWP(28,"esp"),"edi");
++	&mov	("edi",&DWP(96+4,"esp"));	# inp
++
++	&vmovdqa	($t3,&QWP(64,$K256));
++	&sub	($K256,3*64);			# rewind K
++	&cmp	("edi",&DWP(96+8,"esp"));	# are we done yet?
++	&jb	(&label("grand_avx_bmi"));
++
++	&mov	("esp",&DWP(96+12,"esp"));	# restore sp
++	&vzeroall	();
++&function_end_A();
++						}
++						}
++						}}}
++&function_end_B("sha256_block_data_order");
++
++&asm_finish();
++
++close STDOUT;
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/sha/asm/sha256-armv4.pl b/CryptoPkg/Library/OpensslLib/openssl/crypto/sha/asm/sha256-armv4.pl
+new file mode 100644
+index 0000000..55d30cb
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/sha/asm/sha256-armv4.pl
+@@ -0,0 +1,732 @@
++#! /usr/bin/env perl
++# Copyright 2007-2016 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
++# in the file LICENSE in the source distribution or at
++# https://www.openssl.org/source/license.html
++
++
++# ====================================================================
++# Written by Andy Polyakov  for the OpenSSL
++# project. The module is, however, dual licensed under OpenSSL and
++# CRYPTOGAMS licenses depending on where you obtain it. For further
++# details see http://www.openssl.org/~appro/cryptogams/.
++#
++# Permission to use under GPL terms is granted.
++# ====================================================================
++
++# SHA256 block procedure for ARMv4. May 2007.
++
++# Performance is ~2x better than gcc 3.4 generated code and in "abso-
++# lute" terms is ~2250 cycles per 64-byte block or ~35 cycles per
++# byte [on single-issue Xscale PXA250 core].
++
++# July 2010.
++#
++# Rescheduling for dual-issue pipeline resulted in 22% improvement on
++# Cortex A8 core and ~20 cycles per processed byte.
++
++# February 2011.
++#
++# Profiler-assisted and platform-specific optimization resulted in 16%
++# improvement on Cortex A8 core and ~15.4 cycles per processed byte.
++
++# September 2013.
++#
++# Add NEON implementation. On Cortex A8 it was measured to process one
++# byte in 12.5 cycles or 23% faster than integer-only code. Snapdragon
++# S4 does it in 12.5 cycles too, but it's 50% faster than integer-only
++# code (meaning that latter performs sub-optimally, nothing was done
++# about it).
++
++# May 2014.
++#
++# Add ARMv8 code path performing at 2.0 cpb on Apple A7.
++
++$flavour = shift;
++if ($flavour=~/\w[\w\-]*\.\w+$/) { $output=$flavour; undef $flavour; }
++else { while (($output=shift) && ($output!~/\w[\w\-]*\.\w+$/)) {} }
++
++if ($flavour && $flavour ne "void") {
++    $0 =~ m/(.*[\/\\])[^\/\\]+$/; $dir=$1;
++    ( $xlate="${dir}arm-xlate.pl" and -f $xlate ) or
++    ( $xlate="${dir}../../perlasm/arm-xlate.pl" and -f $xlate) or
++    die "can't locate arm-xlate.pl";
++
++    open STDOUT,"| \"$^X\" $xlate $flavour $output";
++} else {
++    open STDOUT,">$output";
++}
++
++$ctx="r0";	$t0="r0";
++$inp="r1";	$t4="r1";
++$len="r2";	$t1="r2";
++$T1="r3";	$t3="r3";
++$A="r4";
++$B="r5";
++$C="r6";
++$D="r7";
++$E="r8";
++$F="r9";
++$G="r10";
++$H="r11";
++@V=($A,$B,$C,$D,$E,$F,$G,$H);
++$t2="r12";
++$Ktbl="r14";
++
++@Sigma0=( 2,13,22);
++@Sigma1=( 6,11,25);
++@sigma0=( 7,18, 3);
++@sigma1=(17,19,10);
++
++sub BODY_00_15 {
++my ($i,$a,$b,$c,$d,$e,$f,$g,$h) = @_;
++
++$code.=<<___ if ($i<16);
++#if __ARM_ARCH__>=7
++	@ ldr	$t1,[$inp],#4			@ $i
++# if $i==15
++	str	$inp,[sp,#17*4]			@ make room for $t4
++# endif
++	eor	$t0,$e,$e,ror#`$Sigma1[1]-$Sigma1[0]`
++	add	$a,$a,$t2			@ h+=Maj(a,b,c) from the past
++	eor	$t0,$t0,$e,ror#`$Sigma1[2]-$Sigma1[0]`	@ Sigma1(e)
++# ifndef __ARMEB__
++	rev	$t1,$t1
++# endif
++#else
++	@ ldrb	$t1,[$inp,#3]			@ $i
++	add	$a,$a,$t2			@ h+=Maj(a,b,c) from the past
++	ldrb	$t2,[$inp,#2]
++	ldrb	$t0,[$inp,#1]
++	orr	$t1,$t1,$t2,lsl#8
++	ldrb	$t2,[$inp],#4
++	orr	$t1,$t1,$t0,lsl#16
++# if $i==15
++	str	$inp,[sp,#17*4]			@ make room for $t4
++# endif
++	eor	$t0,$e,$e,ror#`$Sigma1[1]-$Sigma1[0]`
++	orr	$t1,$t1,$t2,lsl#24
++	eor	$t0,$t0,$e,ror#`$Sigma1[2]-$Sigma1[0]`	@ Sigma1(e)
++#endif
++___
++$code.=<<___;
++	ldr	$t2,[$Ktbl],#4			@ *K256++
++	add	$h,$h,$t1			@ h+=X[i]
++	str	$t1,[sp,#`$i%16`*4]
++	eor	$t1,$f,$g
++	add	$h,$h,$t0,ror#$Sigma1[0]	@ h+=Sigma1(e)
++	and	$t1,$t1,$e
++	add	$h,$h,$t2			@ h+=K256[i]
++	eor	$t1,$t1,$g			@ Ch(e,f,g)
++	eor	$t0,$a,$a,ror#`$Sigma0[1]-$Sigma0[0]`
++	add	$h,$h,$t1			@ h+=Ch(e,f,g)
++#if $i==31
++	and	$t2,$t2,#0xff
++	cmp	$t2,#0xf2			@ done?
++#endif
++#if $i<15
++# if __ARM_ARCH__>=7
++	ldr	$t1,[$inp],#4			@ prefetch
++# else
++	ldrb	$t1,[$inp,#3]
++# endif
++	eor	$t2,$a,$b			@ a^b, b^c in next round
++#else
++	ldr	$t1,[sp,#`($i+2)%16`*4]		@ from future BODY_16_xx
++	eor	$t2,$a,$b			@ a^b, b^c in next round
++	ldr	$t4,[sp,#`($i+15)%16`*4]	@ from future BODY_16_xx
++#endif
++	eor	$t0,$t0,$a,ror#`$Sigma0[2]-$Sigma0[0]`	@ Sigma0(a)
++	and	$t3,$t3,$t2			@ (b^c)&=(a^b)
++	add	$d,$d,$h			@ d+=h
++	eor	$t3,$t3,$b			@ Maj(a,b,c)
++	add	$h,$h,$t0,ror#$Sigma0[0]	@ h+=Sigma0(a)
++	@ add	$h,$h,$t3			@ h+=Maj(a,b,c)
++___
++	($t2,$t3)=($t3,$t2);
++}
++
++sub BODY_16_XX {
++my ($i,$a,$b,$c,$d,$e,$f,$g,$h) = @_;
++
++$code.=<<___;
++	@ ldr	$t1,[sp,#`($i+1)%16`*4]		@ $i
++	@ ldr	$t4,[sp,#`($i+14)%16`*4]
++	mov	$t0,$t1,ror#$sigma0[0]
++	add	$a,$a,$t2			@ h+=Maj(a,b,c) from the past
++	mov	$t2,$t4,ror#$sigma1[0]
++	eor	$t0,$t0,$t1,ror#$sigma0[1]
++	eor	$t2,$t2,$t4,ror#$sigma1[1]
++	eor	$t0,$t0,$t1,lsr#$sigma0[2]	@ sigma0(X[i+1])
++	ldr	$t1,[sp,#`($i+0)%16`*4]
++	eor	$t2,$t2,$t4,lsr#$sigma1[2]	@ sigma1(X[i+14])
++	ldr	$t4,[sp,#`($i+9)%16`*4]
++
++	add	$t2,$t2,$t0
++	eor	$t0,$e,$e,ror#`$Sigma1[1]-$Sigma1[0]`	@ from BODY_00_15
++	add	$t1,$t1,$t2
++	eor	$t0,$t0,$e,ror#`$Sigma1[2]-$Sigma1[0]`	@ Sigma1(e)
++	add	$t1,$t1,$t4			@ X[i]
++___
++	&BODY_00_15(@_);
++}
++
++$code=<<___;
++#ifndef __KERNEL__
++# include "arm_arch.h"
++#else
++# define __ARM_ARCH__ __LINUX_ARM_ARCH__
++# define __ARM_MAX_ARCH__ 7
++#endif
++
++.text
++#if defined(__thumb2__)
++.syntax unified
++.thumb
++#else
++.code   32
++#endif
++
++.type	K256,%object
++.align	5
++K256:
++.word	0x428a2f98,0x71374491,0xb5c0fbcf,0xe9b5dba5
++.word	0x3956c25b,0x59f111f1,0x923f82a4,0xab1c5ed5
++.word	0xd807aa98,0x12835b01,0x243185be,0x550c7dc3
++.word	0x72be5d74,0x80deb1fe,0x9bdc06a7,0xc19bf174
++.word	0xe49b69c1,0xefbe4786,0x0fc19dc6,0x240ca1cc
++.word	0x2de92c6f,0x4a7484aa,0x5cb0a9dc,0x76f988da
++.word	0x983e5152,0xa831c66d,0xb00327c8,0xbf597fc7
++.word	0xc6e00bf3,0xd5a79147,0x06ca6351,0x14292967
++.word	0x27b70a85,0x2e1b2138,0x4d2c6dfc,0x53380d13
++.word	0x650a7354,0x766a0abb,0x81c2c92e,0x92722c85
++.word	0xa2bfe8a1,0xa81a664b,0xc24b8b70,0xc76c51a3
++.word	0xd192e819,0xd6990624,0xf40e3585,0x106aa070
++.word	0x19a4c116,0x1e376c08,0x2748774c,0x34b0bcb5
++.word	0x391c0cb3,0x4ed8aa4a,0x5b9cca4f,0x682e6ff3
++.word	0x748f82ee,0x78a5636f,0x84c87814,0x8cc70208
++.word	0x90befffa,0xa4506ceb,0xbef9a3f7,0xc67178f2
++.size	K256,.-K256
++.word	0				@ terminator
++#if __ARM_MAX_ARCH__>=7 && !defined(__KERNEL__)
++.LOPENSSL_armcap:
++.word	OPENSSL_armcap_P-.Lsha256_block_data_order
++#endif
++.align	5
++
++.global	sha256_block_data_order
++.type	sha256_block_data_order,%function
++sha256_block_data_order:
++.Lsha256_block_data_order:
++#if __ARM_ARCH__<7 && !defined(__thumb2__)
++	sub	r3,pc,#8		@ sha256_block_data_order
++#else
++	adr	r3,.Lsha256_block_data_order
++#endif
++#if __ARM_MAX_ARCH__>=7 && !defined(__KERNEL__)
++	ldr	r12,.LOPENSSL_armcap
++	ldr	r12,[r3,r12]		@ OPENSSL_armcap_P
++#ifdef	__APPLE__
++	ldr	r12,[r12]
++#endif
++	tst	r12,#ARMV8_SHA256
++	bne	.LARMv8
++	tst	r12,#ARMV7_NEON
++	bne	.LNEON
++#endif
++	add	$len,$inp,$len,lsl#6	@ len to point at the end of inp
++	stmdb	sp!,{$ctx,$inp,$len,r4-r11,lr}
++	ldmia	$ctx,{$A,$B,$C,$D,$E,$F,$G,$H}
++	sub	$Ktbl,r3,#256+32	@ K256
++	sub	sp,sp,#16*4		@ alloca(X[16])
++.Loop:
++# if __ARM_ARCH__>=7
++	ldr	$t1,[$inp],#4
++# else
++	ldrb	$t1,[$inp,#3]
++# endif
++	eor	$t3,$B,$C		@ magic
++	eor	$t2,$t2,$t2
++___
++for($i=0;$i<16;$i++)	{ &BODY_00_15($i,@V); unshift(@V,pop(@V)); }
++$code.=".Lrounds_16_xx:\n";
++for (;$i<32;$i++)	{ &BODY_16_XX($i,@V); unshift(@V,pop(@V)); }
++$code.=<<___;
++#if __ARM_ARCH__>=7
++	ite	eq			@ Thumb2 thing, sanity check in ARM
++#endif
++	ldreq	$t3,[sp,#16*4]		@ pull ctx
++	bne	.Lrounds_16_xx
++
++	add	$A,$A,$t2		@ h+=Maj(a,b,c) from the past
++	ldr	$t0,[$t3,#0]
++	ldr	$t1,[$t3,#4]
++	ldr	$t2,[$t3,#8]
++	add	$A,$A,$t0
++	ldr	$t0,[$t3,#12]
++	add	$B,$B,$t1
++	ldr	$t1,[$t3,#16]
++	add	$C,$C,$t2
++	ldr	$t2,[$t3,#20]
++	add	$D,$D,$t0
++	ldr	$t0,[$t3,#24]
++	add	$E,$E,$t1
++	ldr	$t1,[$t3,#28]
++	add	$F,$F,$t2
++	ldr	$inp,[sp,#17*4]		@ pull inp
++	ldr	$t2,[sp,#18*4]		@ pull inp+len
++	add	$G,$G,$t0
++	add	$H,$H,$t1
++	stmia	$t3,{$A,$B,$C,$D,$E,$F,$G,$H}
++	cmp	$inp,$t2
++	sub	$Ktbl,$Ktbl,#256	@ rewind Ktbl
++	bne	.Loop
++
++	add	sp,sp,#`16+3`*4	@ destroy frame
++#if __ARM_ARCH__>=5
++	ldmia	sp!,{r4-r11,pc}
++#else
++	ldmia	sp!,{r4-r11,lr}
++	tst	lr,#1
++	moveq	pc,lr			@ be binary compatible with V4, yet
++	bx	lr			@ interoperable with Thumb ISA:-)
++#endif
++.size	sha256_block_data_order,.-sha256_block_data_order
++___
++######################################################################
++# NEON stuff
++#
++{{{
++my @X=map("q$_",(0..3));
++my ($T0,$T1,$T2,$T3,$T4,$T5)=("q8","q9","q10","q11","d24","d25");
++my $Xfer=$t4;
++my $j=0;
++
++sub Dlo()   { shift=~m|q([1]?[0-9])|?"d".($1*2):"";     }
++sub Dhi()   { shift=~m|q([1]?[0-9])|?"d".($1*2+1):"";   }
++
++sub AUTOLOAD()          # thunk [simplified] x86-style perlasm
++{ my $opcode = $AUTOLOAD; $opcode =~ s/.*:://; $opcode =~ s/_/\./;
++  my $arg = pop;
++    $arg = "#$arg" if ($arg*1 eq $arg);
++    $code .= "\t$opcode\t".join(',',@_,$arg)."\n";
++}
++
++sub Xupdate()
++{ use integer;
++  my $body = shift;
++  my @insns = (&$body,&$body,&$body,&$body);
++  my ($a,$b,$c,$d,$e,$f,$g,$h);
++
++	&vext_8		($T0,@X[0],@X[1],4);	# X[1..4]
++	 eval(shift(@insns));
++	 eval(shift(@insns));
++	 eval(shift(@insns));
++	&vext_8		($T1,@X[2],@X[3],4);	# X[9..12]
++	 eval(shift(@insns));
++	 eval(shift(@insns));
++	 eval(shift(@insns));
++	&vshr_u32	($T2,$T0,$sigma0[0]);
++	 eval(shift(@insns));
++	 eval(shift(@insns));
++	&vadd_i32	(@X[0],@X[0],$T1);	# X[0..3] += X[9..12]
++	 eval(shift(@insns));
++	 eval(shift(@insns));
++	&vshr_u32	($T1,$T0,$sigma0[2]);
++	 eval(shift(@insns));
++	 eval(shift(@insns));
++	&vsli_32	($T2,$T0,32-$sigma0[0]);
++	 eval(shift(@insns));
++	 eval(shift(@insns));
++	&vshr_u32	($T3,$T0,$sigma0[1]);
++	 eval(shift(@insns));
++	 eval(shift(@insns));
++	&veor		($T1,$T1,$T2);
++	 eval(shift(@insns));
++	 eval(shift(@insns));
++	&vsli_32	($T3,$T0,32-$sigma0[1]);
++	 eval(shift(@insns));
++	 eval(shift(@insns));
++	  &vshr_u32	($T4,&Dhi(@X[3]),$sigma1[0]);
++	 eval(shift(@insns));
++	 eval(shift(@insns));
++	&veor		($T1,$T1,$T3);		# sigma0(X[1..4])
++	 eval(shift(@insns));
++	 eval(shift(@insns));
++	  &vsli_32	($T4,&Dhi(@X[3]),32-$sigma1[0]);
++	 eval(shift(@insns));
++	 eval(shift(@insns));
++	  &vshr_u32	($T5,&Dhi(@X[3]),$sigma1[2]);
++	 eval(shift(@insns));
++	 eval(shift(@insns));
++	&vadd_i32	(@X[0],@X[0],$T1);	# X[0..3] += sigma0(X[1..4])
++	 eval(shift(@insns));
++	 eval(shift(@insns));
++	  &veor		($T5,$T5,$T4);
++	 eval(shift(@insns));
++	 eval(shift(@insns));
++	  &vshr_u32	($T4,&Dhi(@X[3]),$sigma1[1]);
++	 eval(shift(@insns));
++	 eval(shift(@insns));
++	  &vsli_32	($T4,&Dhi(@X[3]),32-$sigma1[1]);
++	 eval(shift(@insns));
++	 eval(shift(@insns));
++	  &veor		($T5,$T5,$T4);		# sigma1(X[14..15])
++	 eval(shift(@insns));
++	 eval(shift(@insns));
++	&vadd_i32	(&Dlo(@X[0]),&Dlo(@X[0]),$T5);# X[0..1] += sigma1(X[14..15])
++	 eval(shift(@insns));
++	 eval(shift(@insns));
++	  &vshr_u32	($T4,&Dlo(@X[0]),$sigma1[0]);
++	 eval(shift(@insns));
++	 eval(shift(@insns));
++	  &vsli_32	($T4,&Dlo(@X[0]),32-$sigma1[0]);
++	 eval(shift(@insns));
++	 eval(shift(@insns));
++	  &vshr_u32	($T5,&Dlo(@X[0]),$sigma1[2]);
++	 eval(shift(@insns));
++	 eval(shift(@insns));
++	  &veor		($T5,$T5,$T4);
++	 eval(shift(@insns));
++	 eval(shift(@insns));
++	  &vshr_u32	($T4,&Dlo(@X[0]),$sigma1[1]);
++	 eval(shift(@insns));
++	 eval(shift(@insns));
++	&vld1_32	("{$T0}","[$Ktbl,:128]!");
++	 eval(shift(@insns));
++	 eval(shift(@insns));
++	  &vsli_32	($T4,&Dlo(@X[0]),32-$sigma1[1]);
++	 eval(shift(@insns));
++	 eval(shift(@insns));
++	  &veor		($T5,$T5,$T4);		# sigma1(X[16..17])
++	 eval(shift(@insns));
++	 eval(shift(@insns));
++	&vadd_i32	(&Dhi(@X[0]),&Dhi(@X[0]),$T5);# X[2..3] += sigma1(X[16..17])
++	 eval(shift(@insns));
++	 eval(shift(@insns));
++	&vadd_i32	($T0,$T0,@X[0]);
++	 while($#insns>=2) { eval(shift(@insns)); }
++	&vst1_32	("{$T0}","[$Xfer,:128]!");
++	 eval(shift(@insns));
++	 eval(shift(@insns));
++
++	push(@X,shift(@X));		# "rotate" X[]
++}
++
++sub Xpreload()
++{ use integer;
++  my $body = shift;
++  my @insns = (&$body,&$body,&$body,&$body);
++  my ($a,$b,$c,$d,$e,$f,$g,$h);
++
++	 eval(shift(@insns));
++	 eval(shift(@insns));
++	 eval(shift(@insns));
++	 eval(shift(@insns));
++	&vld1_32	("{$T0}","[$Ktbl,:128]!");
++	 eval(shift(@insns));
++	 eval(shift(@insns));
++	 eval(shift(@insns));
++	 eval(shift(@insns));
++	&vrev32_8	(@X[0],@X[0]);
++	 eval(shift(@insns));
++	 eval(shift(@insns));
++	 eval(shift(@insns));
++	 eval(shift(@insns));
++	&vadd_i32	($T0,$T0,@X[0]);
++	 foreach (@insns) { eval; }	# remaining instructions
++	&vst1_32	("{$T0}","[$Xfer,:128]!");
++
++	push(@X,shift(@X));		# "rotate" X[]
++}
++
++sub body_00_15 () {
++	(
++	'($a,$b,$c,$d,$e,$f,$g,$h)=@V;'.
++	'&add	($h,$h,$t1)',			# h+=X[i]+K[i]
++	'&eor	($t1,$f,$g)',
++	'&eor	($t0,$e,$e,"ror#".($Sigma1[1]-$Sigma1[0]))',
++	'&add	($a,$a,$t2)',			# h+=Maj(a,b,c) from the past
++	'&and	($t1,$t1,$e)',
++	'&eor	($t2,$t0,$e,"ror#".($Sigma1[2]-$Sigma1[0]))',	# Sigma1(e)
++	'&eor	($t0,$a,$a,"ror#".($Sigma0[1]-$Sigma0[0]))',
++	'&eor	($t1,$t1,$g)',			# Ch(e,f,g)
++	'&add	($h,$h,$t2,"ror#$Sigma1[0]")',	# h+=Sigma1(e)
++	'&eor	($t2,$a,$b)',			# a^b, b^c in next round
++	'&eor	($t0,$t0,$a,"ror#".($Sigma0[2]-$Sigma0[0]))',	# Sigma0(a)
++	'&add	($h,$h,$t1)',			# h+=Ch(e,f,g)
++	'&ldr	($t1,sprintf "[sp,#%d]",4*(($j+1)&15))	if (($j&15)!=15);'.
++	'&ldr	($t1,"[$Ktbl]")				if ($j==15);'.
++	'&ldr	($t1,"[sp,#64]")			if ($j==31)',
++	'&and	($t3,$t3,$t2)',			# (b^c)&=(a^b)
++	'&add	($d,$d,$h)',			# d+=h
++	'&add	($h,$h,$t0,"ror#$Sigma0[0]");'.	# h+=Sigma0(a)
++	'&eor	($t3,$t3,$b)',			# Maj(a,b,c)
++	'$j++;	unshift(@V,pop(@V)); ($t2,$t3)=($t3,$t2);'
++	)
++}
++
++$code.=<<___;
++#if __ARM_MAX_ARCH__>=7
++.arch	armv7-a
++.fpu	neon
++
++.global	sha256_block_data_order_neon
++.type	sha256_block_data_order_neon,%function
++.align	5
++.skip	16
++sha256_block_data_order_neon:
++.LNEON:
++	stmdb	sp!,{r4-r12,lr}
++
++	sub	$H,sp,#16*4+16
++	adr	$Ktbl,K256
++	bic	$H,$H,#15		@ align for 128-bit stores
++	mov	$t2,sp
++	mov	sp,$H			@ alloca
++	add	$len,$inp,$len,lsl#6	@ len to point at the end of inp
++
++	vld1.8		{@X[0]},[$inp]!
++	vld1.8		{@X[1]},[$inp]!
++	vld1.8		{@X[2]},[$inp]!
++	vld1.8		{@X[3]},[$inp]!
++	vld1.32		{$T0},[$Ktbl,:128]!
++	vld1.32		{$T1},[$Ktbl,:128]!
++	vld1.32		{$T2},[$Ktbl,:128]!
++	vld1.32		{$T3},[$Ktbl,:128]!
++	vrev32.8	@X[0],@X[0]		@ yes, even on
++	str		$ctx,[sp,#64]
++	vrev32.8	@X[1],@X[1]		@ big-endian
++	str		$inp,[sp,#68]
++	mov		$Xfer,sp
++	vrev32.8	@X[2],@X[2]
++	str		$len,[sp,#72]
++	vrev32.8	@X[3],@X[3]
++	str		$t2,[sp,#76]		@ save original sp
++	vadd.i32	$T0,$T0,@X[0]
++	vadd.i32	$T1,$T1,@X[1]
++	vst1.32		{$T0},[$Xfer,:128]!
++	vadd.i32	$T2,$T2,@X[2]
++	vst1.32		{$T1},[$Xfer,:128]!
++	vadd.i32	$T3,$T3,@X[3]
++	vst1.32		{$T2},[$Xfer,:128]!
++	vst1.32		{$T3},[$Xfer,:128]!
++
++	ldmia		$ctx,{$A-$H}
++	sub		$Xfer,$Xfer,#64
++	ldr		$t1,[sp,#0]
++	eor		$t2,$t2,$t2
++	eor		$t3,$B,$C
++	b		.L_00_48
++
++.align	4
++.L_00_48:
++___
++	&Xupdate(\&body_00_15);
++	&Xupdate(\&body_00_15);
++	&Xupdate(\&body_00_15);
++	&Xupdate(\&body_00_15);
++$code.=<<___;
++	teq	$t1,#0				@ check for K256 terminator
++	ldr	$t1,[sp,#0]
++	sub	$Xfer,$Xfer,#64
++	bne	.L_00_48
++
++	ldr		$inp,[sp,#68]
++	ldr		$t0,[sp,#72]
++	sub		$Ktbl,$Ktbl,#256	@ rewind $Ktbl
++	teq		$inp,$t0
++	it		eq
++	subeq		$inp,$inp,#64		@ avoid SEGV
++	vld1.8		{@X[0]},[$inp]!		@ load next input block
++	vld1.8		{@X[1]},[$inp]!
++	vld1.8		{@X[2]},[$inp]!
++	vld1.8		{@X[3]},[$inp]!
++	it		ne
++	strne		$inp,[sp,#68]
++	mov		$Xfer,sp
++___
++	&Xpreload(\&body_00_15);
++	&Xpreload(\&body_00_15);
++	&Xpreload(\&body_00_15);
++	&Xpreload(\&body_00_15);
++$code.=<<___;
++	ldr	$t0,[$t1,#0]
++	add	$A,$A,$t2			@ h+=Maj(a,b,c) from the past
++	ldr	$t2,[$t1,#4]
++	ldr	$t3,[$t1,#8]
++	ldr	$t4,[$t1,#12]
++	add	$A,$A,$t0			@ accumulate
++	ldr	$t0,[$t1,#16]
++	add	$B,$B,$t2
++	ldr	$t2,[$t1,#20]
++	add	$C,$C,$t3
++	ldr	$t3,[$t1,#24]
++	add	$D,$D,$t4
++	ldr	$t4,[$t1,#28]
++	add	$E,$E,$t0
++	str	$A,[$t1],#4
++	add	$F,$F,$t2
++	str	$B,[$t1],#4
++	add	$G,$G,$t3
++	str	$C,[$t1],#4
++	add	$H,$H,$t4
++	str	$D,[$t1],#4
++	stmia	$t1,{$E-$H}
++
++	ittte	ne
++	movne	$Xfer,sp
++	ldrne	$t1,[sp,#0]
++	eorne	$t2,$t2,$t2
++	ldreq	sp,[sp,#76]			@ restore original sp
++	itt	ne
++	eorne	$t3,$B,$C
++	bne	.L_00_48
++
++	ldmia	sp!,{r4-r12,pc}
++.size	sha256_block_data_order_neon,.-sha256_block_data_order_neon
++#endif
++___
++}}}
++######################################################################
++# ARMv8 stuff
++#
++{{{
++my ($ABCD,$EFGH,$abcd)=map("q$_",(0..2));
++my @MSG=map("q$_",(8..11));
++my ($W0,$W1,$ABCD_SAVE,$EFGH_SAVE)=map("q$_",(12..15));
++my $Ktbl="r3";
++
++$code.=<<___;
++#if __ARM_MAX_ARCH__>=7 && !defined(__KERNEL__)
++
++# if defined(__thumb2__)
++#  define INST(a,b,c,d)	.byte	c,d|0xc,a,b
++# else
++#  define INST(a,b,c,d)	.byte	a,b,c,d
++# endif
++
++.type	sha256_block_data_order_armv8,%function
++.align	5
++sha256_block_data_order_armv8:
++.LARMv8:
++	vld1.32	{$ABCD,$EFGH},[$ctx]
++	sub	$Ktbl,$Ktbl,#256+32
++	add	$len,$inp,$len,lsl#6	@ len to point at the end of inp
++	b	.Loop_v8
++
++.align	4
++.Loop_v8:
++	vld1.8		{@MSG[0]-@MSG[1]},[$inp]!
++	vld1.8		{@MSG[2]-@MSG[3]},[$inp]!
++	vld1.32		{$W0},[$Ktbl]!
++	vrev32.8	@MSG[0],@MSG[0]
++	vrev32.8	@MSG[1],@MSG[1]
++	vrev32.8	@MSG[2],@MSG[2]
++	vrev32.8	@MSG[3],@MSG[3]
++	vmov		$ABCD_SAVE,$ABCD	@ offload
++	vmov		$EFGH_SAVE,$EFGH
++	teq		$inp,$len
++___
++for($i=0;$i<12;$i++) {
++$code.=<<___;
++	vld1.32		{$W1},[$Ktbl]!
++	vadd.i32	$W0,$W0,@MSG[0]
++	sha256su0	@MSG[0],@MSG[1]
++	vmov		$abcd,$ABCD
++	sha256h		$ABCD,$EFGH,$W0
++	sha256h2	$EFGH,$abcd,$W0
++	sha256su1	@MSG[0],@MSG[2],@MSG[3]
++___
++	($W0,$W1)=($W1,$W0);	push(@MSG,shift(@MSG));
++}
++$code.=<<___;
++	vld1.32		{$W1},[$Ktbl]!
++	vadd.i32	$W0,$W0,@MSG[0]
++	vmov		$abcd,$ABCD
++	sha256h		$ABCD,$EFGH,$W0
++	sha256h2	$EFGH,$abcd,$W0
++
++	vld1.32		{$W0},[$Ktbl]!
++	vadd.i32	$W1,$W1,@MSG[1]
++	vmov		$abcd,$ABCD
++	sha256h		$ABCD,$EFGH,$W1
++	sha256h2	$EFGH,$abcd,$W1
++
++	vld1.32		{$W1},[$Ktbl]
++	vadd.i32	$W0,$W0,@MSG[2]
++	sub		$Ktbl,$Ktbl,#256-16	@ rewind
++	vmov		$abcd,$ABCD
++	sha256h		$ABCD,$EFGH,$W0
++	sha256h2	$EFGH,$abcd,$W0
++
++	vadd.i32	$W1,$W1,@MSG[3]
++	vmov		$abcd,$ABCD
++	sha256h		$ABCD,$EFGH,$W1
++	sha256h2	$EFGH,$abcd,$W1
++
++	vadd.i32	$ABCD,$ABCD,$ABCD_SAVE
++	vadd.i32	$EFGH,$EFGH,$EFGH_SAVE
++	it		ne
++	bne		.Loop_v8
++
++	vst1.32		{$ABCD,$EFGH},[$ctx]
++
++	ret		@ bx lr
++.size	sha256_block_data_order_armv8,.-sha256_block_data_order_armv8
++#endif
++___
++}}}
++$code.=<<___;
++.asciz  "SHA256 block transform for ARMv4/NEON/ARMv8, CRYPTOGAMS by "
++.align	2
++#if __ARM_MAX_ARCH__>=7 && !defined(__KERNEL__)
++.comm   OPENSSL_armcap_P,4,4
++#endif
++___
++
++open SELF,$0;
++while() {
++	next if (/^#!/);
++	last if (!s/^#/@/ and !/^$/);
++	print;
++}
++close SELF;
++
++{   my  %opcode = (
++	"sha256h"	=> 0xf3000c40,	"sha256h2"	=> 0xf3100c40,
++	"sha256su0"	=> 0xf3ba03c0,	"sha256su1"	=> 0xf3200c40	);
++
++    sub unsha256 {
++	my ($mnemonic,$arg)=@_;
++
++	if ($arg =~ m/q([0-9]+)(?:,\s*q([0-9]+))?,\s*q([0-9]+)/o) {
++	    my $word = $opcode{$mnemonic}|(($1&7)<<13)|(($1&8)<<19)
++					 |(($2&7)<<17)|(($2&8)<<4)
++					 |(($3&7)<<1) |(($3&8)<<2);
++	    # since ARMv7 instructions are always encoded little-endian.
++	    # correct solution is to use .inst directive, but older
++	    # assemblers don't implement it:-(
++	    sprintf "INST(0x%02x,0x%02x,0x%02x,0x%02x)\t@ %s %s",
++			$word&0xff,($word>>8)&0xff,
++			($word>>16)&0xff,($word>>24)&0xff,
++			$mnemonic,$arg;
++	}
++    }
++}
++
++foreach (split($/,$code)) {
++
++	s/\`([^\`]*)\`/eval $1/geo;
++
++	s/\b(sha256\w+)\s+(q.*)/unsha256($1,$2)/geo;
++
++	s/\bret\b/bx	lr/go		or
++	s/\bbx\s+lr\b/.word\t0xe12fff1e/go;	# make it possible to compile with -march=armv4
++
++	print $_,"\n";
++}
++
++close STDOUT; # enforce flush
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/sha/asm/sha256-c64xplus.pl b/CryptoPkg/Library/OpensslLib/openssl/crypto/sha/asm/sha256-c64xplus.pl
+new file mode 100644
+index 0000000..3ab7d9b
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/sha/asm/sha256-c64xplus.pl
+@@ -0,0 +1,320 @@
++#! /usr/bin/env perl
++# Copyright 2012-2016 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
++# in the file LICENSE in the source distribution or at
++# https://www.openssl.org/source/license.html
++
++#
++# ====================================================================
++# Written by Andy Polyakov  for the OpenSSL
++# project. The module is, however, dual licensed under OpenSSL and
++# CRYPTOGAMS licenses depending on where you obtain it. For further
++# details see http://www.openssl.org/~appro/cryptogams/.
++# ====================================================================
++#
++# SHA256 for C64x+.
++#
++# January 2012
++#
++# Performance is just below 10 cycles per processed byte, which is
++# almost 40% faster than compiler-generated code. Unroll is unlikely
++# to give more than ~8% improvement...
++#
++# !!! Note that this module uses AMR, which means that all interrupt
++# service routines are expected to preserve it and for own well-being
++# zero it upon entry.
++
++while (($output=shift) && ($output!~/\w[\w\-]*\.\w+$/)) {}
++open STDOUT,">$output";
++
++($CTXA,$INP,$NUM) = ("A4","B4","A6");            # arguments
++ $K256="A3";
++
++($A,$Actx,$B,$Bctx,$C,$Cctx,$D,$Dctx,$T2,$S0,$s1,$t0a,$t1a,$t2a,$X9,$X14)
++	=map("A$_",(16..31));
++($E,$Ectx,$F,$Fctx,$G,$Gctx,$H,$Hctx,$T1,$S1,$s0,$t0e,$t1e,$t2e,$X1,$X15)
++	=map("B$_",(16..31));
++
++($Xia,$Xib)=("A5","B5");			# circular/ring buffer
++ $CTXB=$t2e;
++
++($Xn,$X0,$K)=("B7","B8","B9");
++($Maj,$Ch)=($T2,"B6");
++
++$code.=<<___;
++	.text
++
++	.if	.ASSEMBLER_VERSION<7000000
++	.asg	0,__TI_EABI__
++	.endif
++	.if	__TI_EABI__
++	.nocmp
++	.asg	sha256_block_data_order,_sha256_block_data_order
++	.endif
++
++	.asg	B3,RA
++	.asg	A15,FP
++	.asg	B15,SP
++
++	.if	.BIG_ENDIAN
++	.asg	SWAP2,MV
++	.asg	SWAP4,MV
++	.endif
++
++	.global	_sha256_block_data_order
++_sha256_block_data_order:
++__sha256_block:
++	.asmfunc stack_usage(64)
++	MV	$NUM,A0				; reassign $NUM
++||	MVK	-64,B0
++  [!A0]	BNOP	RA				; if ($NUM==0) return;
++|| [A0]	STW	FP,*SP--[16]			; save frame pointer and alloca(64)
++|| [A0]	MV	SP,FP
++   [A0]	ADDKPC	__sha256_block,B2
++|| [A0]	AND	B0,SP,SP			; align stack at 64 bytes
++	.if	__TI_EABI__
++   [A0]	MVK	0x00404,B1
++|| [A0]	MVKL	\$PCR_OFFSET(K256,__sha256_block),$K256
++   [A0]	MVKH	0x50000,B1
++|| [A0]	MVKH	\$PCR_OFFSET(K256,__sha256_block),$K256
++	.else
++   [A0]	MVK	0x00404,B1
++|| [A0]	MVKL	(K256-__sha256_block),$K256
++   [A0]	MVKH	0x50000,B1
++|| [A0]	MVKH	(K256-__sha256_block),$K256
++	.endif
++   [A0]	MVC	B1,AMR				; setup circular addressing
++|| [A0]	MV	SP,$Xia
++   [A0]	MV	SP,$Xib
++|| [A0]	ADD	B2,$K256,$K256
++|| [A0]	MV	$CTXA,$CTXB
++|| [A0]	SUBAW	SP,2,SP				; reserve two words above buffer
++	LDW	*${CTXA}[0],$A			; load ctx
++||	LDW	*${CTXB}[4],$E
++	LDW	*${CTXA}[1],$B
++||	LDW	*${CTXB}[5],$F
++	LDW	*${CTXA}[2],$C
++||	LDW	*${CTXB}[6],$G
++	LDW	*${CTXA}[3],$D
++||	LDW	*${CTXB}[7],$H
++
++	LDNW	*$INP++,$Xn			; pre-fetch input
++	LDW	*$K256++,$K			; pre-fetch K256[0]
++	MVK	14,B0				; loop counters
++	MVK	47,B1
++||	ADDAW	$Xia,9,$Xia
++outerloop?:
++	SUB	A0,1,A0
++||	MV	$A,$Actx
++||	MV	$E,$Ectx
++||	MVD	$B,$Bctx
++||	MVD	$F,$Fctx
++	MV	$C,$Cctx
++||	MV	$G,$Gctx
++||	MVD	$D,$Dctx
++||	MVD	$H,$Hctx
++||	SWAP4	$Xn,$X0
++
++	SPLOOPD	8				; BODY_00_14
++||	MVC	B0,ILC
++||	SWAP2	$X0,$X0
++
++	LDNW	*$INP++,$Xn
++||	ROTL	$A,30,$S0
++||	OR	$A,$B,$Maj
++||	AND	$A,$B,$t2a
++||	ROTL	$E,26,$S1
++||	AND	$F,$E,$Ch
++||	ANDN	$G,$E,$t2e
++	ROTL	$A,19,$t0a
++||	AND	$C,$Maj,$Maj
++||	ROTL	$E,21,$t0e
++||	XOR	$t2e,$Ch,$Ch			; Ch(e,f,g) = (e&f)^(~e&g)
++	ROTL	$A,10,$t1a
++||	OR	$t2a,$Maj,$Maj			; Maj(a,b,c) = ((a|b)&c)|(a&b)
++||	ROTL	$E,7,$t1e
++||	ADD	$K,$H,$T1			; T1 = h + K256[i]
++	ADD	$X0,$T1,$T1			; T1 += X[i];
++||	STW	$X0,*$Xib++
++||	XOR	$t0a,$S0,$S0
++||	XOR	$t0e,$S1,$S1
++	XOR	$t1a,$S0,$S0			; Sigma0(a)
++||	XOR	$t1e,$S1,$S1			; Sigma1(e)
++||	LDW	*$K256++,$K			; pre-fetch K256[i+1]
++||	ADD	$Ch,$T1,$T1			; T1 += Ch(e,f,g)
++	ADD	$S1,$T1,$T1			; T1 += Sigma1(e)
++||	ADD	$S0,$Maj,$T2			; T2 = Sigma0(a) + Maj(a,b,c)
++||	ROTL	$G,0,$H				; h = g
++||	MV	$F,$G				; g = f
++||	MV	$X0,$X14
++||	SWAP4	$Xn,$X0
++	SWAP2	$X0,$X0
++||	MV	$E,$F				; f = e
++||	ADD	$D,$T1,$E			; e = d + T1
++||	MV	$C,$D				; d = c
++	MV	$B,$C				; c = b
++||	MV	$A,$B				; b = a
++||	ADD	$T1,$T2,$A			; a = T1 + T2
++	SPKERNEL
++
++	ROTL	$A,30,$S0			; BODY_15
++||	OR	$A,$B,$Maj
++||	AND	$A,$B,$t2a
++||	ROTL	$E,26,$S1
++||	AND	$F,$E,$Ch
++||	ANDN	$G,$E,$t2e
++||	LDW	*${Xib}[1],$Xn			; modulo-scheduled
++	ROTL	$A,19,$t0a
++||	AND	$C,$Maj,$Maj
++||	ROTL	$E,21,$t0e
++||	XOR	$t2e,$Ch,$Ch			; Ch(e,f,g) = (e&f)^(~e&g)
++||	LDW	*${Xib}[2],$X1			; modulo-scheduled
++	ROTL	$A,10,$t1a
++||	OR	$t2a,$Maj,$Maj			; Maj(a,b,c) = ((a|b)&c)|(a&b)
++||	ROTL	$E,7,$t1e
++||	ADD	$K,$H,$T1			; T1 = h + K256[i]
++	ADD	$X0,$T1,$T1			; T1 += X[i];
++||	STW	$X0,*$Xib++
++||	XOR	$t0a,$S0,$S0
++||	XOR	$t0e,$S1,$S1
++	XOR	$t1a,$S0,$S0			; Sigma0(a)
++||	XOR	$t1e,$S1,$S1			; Sigma1(e)
++||	LDW	*$K256++,$K			; pre-fetch K256[i+1]
++||	ADD	$Ch,$T1,$T1			; T1 += Ch(e,f,g)
++	ADD	$S1,$T1,$T1			; T1 += Sigma1(e)
++||	ADD	$S0,$Maj,$T2			; T2 = Sigma0(a) + Maj(a,b,c)
++||	ROTL	$G,0,$H				; h = g
++||	MV	$F,$G				; g = f
++||	MV	$X0,$X15
++	MV	$E,$F				; f = e
++||	ADD	$D,$T1,$E			; e = d + T1
++||	MV	$C,$D				; d = c
++||	MV	$Xn,$X0				; modulo-scheduled
++||	LDW	*$Xia,$X9			; modulo-scheduled
++||	ROTL	$X1,25,$t0e			; modulo-scheduled
++||	ROTL	$X14,15,$t0a			; modulo-scheduled
++	SHRU	$X1,3,$s0			; modulo-scheduled
++||	SHRU	$X14,10,$s1			; modulo-scheduled
++||	ROTL	$B,0,$C				; c = b
++||	MV	$A,$B				; b = a
++||	ADD	$T1,$T2,$A			; a = T1 + T2
++
++	SPLOOPD	10				; BODY_16_63
++||	MVC	B1,ILC
++||	ROTL	$X1,14,$t1e			; modulo-scheduled
++||	ROTL	$X14,13,$t1a			; modulo-scheduled
++
++	XOR	$t0e,$s0,$s0
++||	XOR	$t0a,$s1,$s1
++||	MV	$X15,$X14
++||	MV	$X1,$Xn
++	XOR	$t1e,$s0,$s0			; sigma0(X[i+1])
++||	XOR	$t1a,$s1,$s1			; sigma1(X[i+14])
++||	LDW	*${Xib}[2],$X1			; module-scheduled
++	ROTL	$A,30,$S0
++||	OR	$A,$B,$Maj
++||	AND	$A,$B,$t2a
++||	ROTL	$E,26,$S1
++||	AND	$F,$E,$Ch
++||	ANDN	$G,$E,$t2e
++||	ADD	$X9,$X0,$X0			; X[i] += X[i+9]
++	ROTL	$A,19,$t0a
++||	AND	$C,$Maj,$Maj
++||	ROTL	$E,21,$t0e
++||	XOR	$t2e,$Ch,$Ch			; Ch(e,f,g) = (e&f)^(~e&g)
++||	ADD	$s0,$X0,$X0			; X[i] += sigma1(X[i+1])
++	ROTL	$A,10,$t1a
++||	OR	$t2a,$Maj,$Maj			; Maj(a,b,c) = ((a|b)&c)|(a&b)
++||	ROTL	$E,7,$t1e
++||	ADD	$H,$K,$T1			; T1 = h + K256[i]
++||	ADD	$s1,$X0,$X0			; X[i] += sigma1(X[i+14])
++	XOR	$t0a,$S0,$S0
++||	XOR	$t0e,$S1,$S1
++||	ADD	$X0,$T1,$T1			; T1 += X[i]
++||	STW	$X0,*$Xib++
++	XOR	$t1a,$S0,$S0			; Sigma0(a)
++||	XOR	$t1e,$S1,$S1			; Sigma1(e)
++||	ADD	$Ch,$T1,$T1			; T1 += Ch(e,f,g)
++||	MV	$X0,$X15
++||	ROTL	$G,0,$H				; h = g
++||	LDW	*$K256++,$K			; pre-fetch K256[i+1]
++	ADD	$S1,$T1,$T1			; T1 += Sigma1(e)
++||	ADD	$S0,$Maj,$T2			; T2 = Sigma0(a) + Maj(a,b,c)
++||	MV	$F,$G				; g = f
++||	MV	$Xn,$X0				; modulo-scheduled
++||	LDW	*++$Xia,$X9			; modulo-scheduled
++||	ROTL	$X1,25,$t0e			; module-scheduled
++||	ROTL	$X14,15,$t0a			; modulo-scheduled
++	ROTL	$X1,14,$t1e			; modulo-scheduled
++||	ROTL	$X14,13,$t1a			; modulo-scheduled
++||	MV	$E,$F				; f = e
++||	ADD	$D,$T1,$E			; e = d + T1
++||	MV	$C,$D				; d = c
++||	MV	$B,$C				; c = b
++	MV	$A,$B				; b = a
++||	ADD	$T1,$T2,$A			; a = T1 + T2
++||	SHRU	$X1,3,$s0			; modulo-scheduled
++||	SHRU	$X14,10,$s1			; modulo-scheduled
++	SPKERNEL
++
++   [A0]	B	outerloop?
++|| [A0]	LDNW	*$INP++,$Xn			; pre-fetch input
++|| [A0]	ADDK	-260,$K256			; rewind K256
++||	ADD	$Actx,$A,$A			; accumulate ctx
++||	ADD	$Ectx,$E,$E
++||	ADD	$Bctx,$B,$B
++	ADD	$Fctx,$F,$F
++||	ADD	$Cctx,$C,$C
++||	ADD	$Gctx,$G,$G
++||	ADD	$Dctx,$D,$D
++||	ADD	$Hctx,$H,$H
++|| [A0]	LDW	*$K256++,$K			; pre-fetch K256[0]
++
++  [!A0]	BNOP	RA
++||[!A0]	MV	$CTXA,$CTXB
++  [!A0]	MV	FP,SP				; restore stack pointer
++||[!A0]	LDW	*FP[0],FP			; restore frame pointer
++  [!A0]	STW	$A,*${CTXA}[0]  		; save ctx
++||[!A0]	STW	$E,*${CTXB}[4]
++||[!A0]	MVK	0,B0
++  [!A0]	STW	$B,*${CTXA}[1]
++||[!A0]	STW	$F,*${CTXB}[5]
++||[!A0]	MVC	B0,AMR				; clear AMR
++	STW	$C,*${CTXA}[2]
++||	STW	$G,*${CTXB}[6]
++	STW	$D,*${CTXA}[3]
++||	STW	$H,*${CTXB}[7]
++	.endasmfunc
++
++	.if	__TI_EABI__
++	.sect	".text:sha_asm.const"
++	.else
++	.sect	".const:sha_asm"
++	.endif
++	.align	128
++K256:
++	.uword	0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5
++	.uword	0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5
++	.uword	0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3
++	.uword	0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174
++	.uword	0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc
++	.uword	0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da
++	.uword	0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7
++	.uword	0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967
++	.uword	0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13
++	.uword	0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85
++	.uword	0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3
++	.uword	0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070
++	.uword	0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5
++	.uword	0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3
++	.uword	0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208
++	.uword	0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2
++	.cstring "SHA256 block transform for C64x+, CRYPTOGAMS by "
++	.align	4
++
++___
++
++print $code;
++close STDOUT;
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/sha/asm/sha256-mb-x86_64.pl b/CryptoPkg/Library/OpensslLib/openssl/crypto/sha/asm/sha256-mb-x86_64.pl
+new file mode 100644
+index 0000000..fbcd29f
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/sha/asm/sha256-mb-x86_64.pl
+@@ -0,0 +1,1568 @@
++#! /usr/bin/env perl
++# Copyright 2013-2016 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
++# in the file LICENSE in the source distribution or at
++# https://www.openssl.org/source/license.html
++
++
++# ====================================================================
++# Written by Andy Polyakov  for the OpenSSL
++# project. The module is, however, dual licensed under OpenSSL and
++# CRYPTOGAMS licenses depending on where you obtain it. For further
++# details see http://www.openssl.org/~appro/cryptogams/.
++# ====================================================================
++
++# Multi-buffer SHA256 procedure processes n buffers in parallel by
++# placing buffer data to designated lane of SIMD register. n is
++# naturally limited to 4 on pre-AVX2 processors and to 8 on
++# AVX2-capable processors such as Haswell.
++#
++#		this	+aesni(i)	sha256	aesni-sha256	gain(iv)
++# -------------------------------------------------------------------
++# Westmere(ii)	23.3/n	+1.28=7.11(n=4)	12.3	+3.75=16.1	+126%
++# Atom(ii)	38.7/n	+3.93=13.6(n=4)	20.8	+5.69=26.5	+95%
++# Sandy Bridge	(20.5	+5.15=25.7)/n	11.6	13.0		+103%
++# Ivy Bridge	(20.4	+5.14=25.5)/n	10.3	11.6		+82%
++# Haswell(iii)	(21.0	+5.00=26.0)/n	7.80	8.79		+170%
++# Skylake	(18.9	+5.00=23.9)/n	7.70	8.17		+170%
++# Bulldozer	(21.6	+5.76=27.4)/n	13.6	13.7		+100%
++#
++# (i)	multi-block CBC encrypt with 128-bit key;
++# (ii)	(HASH+AES)/n does not apply to Westmere for n>3 and Atom,
++#	because of lower AES-NI instruction throughput, nor is there
++#	AES-NI-SHA256 stitch for these processors;
++# (iii)	"this" is for n=8, when we gather twice as much data, result
++#	for n=4 is 20.3+4.44=24.7;
++# (iv)	presented improvement coefficients are asymptotic limits and
++#	in real-life application are somewhat lower, e.g. for 2KB 
++#	fragments they range from 75% to 130% (on Haswell);
++
++$flavour = shift;
++$output  = shift;
++if ($flavour =~ /\./) { $output = $flavour; undef $flavour; }
++
++$win64=0; $win64=1 if ($flavour =~ /[nm]asm|mingw64/ || $output =~ /\.asm$/);
++
++$0 =~ m/(.*[\/\\])[^\/\\]+$/; $dir=$1;
++( $xlate="${dir}x86_64-xlate.pl" and -f $xlate ) or
++( $xlate="${dir}../../perlasm/x86_64-xlate.pl" and -f $xlate) or
++die "can't locate x86_64-xlate.pl";
++
++$avx=0;
++
++if (`$ENV{CC} -Wa,-v -c -o /dev/null -x assembler /dev/null 2>&1`
++		=~ /GNU assembler version ([2-9]\.[0-9]+)/) {
++	$avx = ($1>=2.19) + ($1>=2.22);
++}
++
++if (!$avx && $win64 && ($flavour =~ /nasm/ || $ENV{ASM} =~ /nasm/) &&
++	   `nasm -v 2>&1` =~ /NASM version ([2-9]\.[0-9]+)/) {
++	$avx = ($1>=2.09) + ($1>=2.10);
++}
++
++if (!$avx && $win64 && ($flavour =~ /masm/ || $ENV{ASM} =~ /ml64/) &&
++	   `ml64 2>&1` =~ /Version ([0-9]+)\./) {
++	$avx = ($1>=10) + ($1>=11);
++}
++
++if (!$avx && `$ENV{CC} -v 2>&1` =~ /((?:^clang|LLVM) version|.*based on LLVM) ([3-9]\.[0-9]+)/) {
++	$avx = ($2>=3.0) + ($2>3.0);
++}
++
++open OUT,"| \"$^X\" \"$xlate\" $flavour \"$output\"";
++*STDOUT=*OUT;
++
++# void sha256_multi_block (
++#     struct {	unsigned int A[8];
++#		unsigned int B[8];
++#		unsigned int C[8];
++#		unsigned int D[8];
++#		unsigned int E[8];
++#		unsigned int F[8];
++#		unsigned int G[8];
++#		unsigned int H[8];	} *ctx,
++#     struct {	void *ptr; int blocks;	} inp[8],
++#     int num);		/* 1 or 2 */
++#
++$ctx="%rdi";	# 1st arg
++$inp="%rsi";	# 2nd arg
++$num="%edx";	# 3rd arg
++@ptr=map("%r$_",(8..11));
++$Tbl="%rbp";
++
++@V=($A,$B,$C,$D,$E,$F,$G,$H)=map("%xmm$_",(8..15));
++($t1,$t2,$t3,$axb,$bxc,$Xi,$Xn,$sigma)=map("%xmm$_",(0..7));
++
++$REG_SZ=16;
++
++sub Xi_off {
++my $off = shift;
++
++    $off %= 16; $off *= $REG_SZ;
++    $off<256 ? "$off-128(%rax)" : "$off-256-128(%rbx)";
++}
++
++sub ROUND_00_15 {
++my ($i,$a,$b,$c,$d,$e,$f,$g,$h)=@_;
++
++$code.=<<___ if ($i<15);
++	movd		`4*$i`(@ptr[0]),$Xi
++	movd		`4*$i`(@ptr[1]),$t1
++	movd		`4*$i`(@ptr[2]),$t2
++	movd		`4*$i`(@ptr[3]),$t3
++	punpckldq	$t2,$Xi
++	punpckldq	$t3,$t1
++	punpckldq	$t1,$Xi
++___
++$code.=<<___ if ($i==15);
++	movd		`4*$i`(@ptr[0]),$Xi
++	 lea		`16*4`(@ptr[0]),@ptr[0]
++	movd		`4*$i`(@ptr[1]),$t1
++	 lea		`16*4`(@ptr[1]),@ptr[1]
++	movd		`4*$i`(@ptr[2]),$t2
++	 lea		`16*4`(@ptr[2]),@ptr[2]
++	movd		`4*$i`(@ptr[3]),$t3
++	 lea		`16*4`(@ptr[3]),@ptr[3]
++	punpckldq	$t2,$Xi
++	punpckldq	$t3,$t1
++	punpckldq	$t1,$Xi
++___
++$code.=<<___;
++	movdqa	$e,$sigma
++	`"pshufb	$Xn,$Xi"		if ($i<=15 && ($i&1)==0)`
++	movdqa	$e,$t3
++	`"pshufb	$Xn,$Xi"		if ($i<=15 && ($i&1)==1)`
++	psrld	\$6,$sigma
++	movdqa	$e,$t2
++	pslld	\$7,$t3
++	movdqa	$Xi,`&Xi_off($i)`
++	 paddd	$h,$Xi				# Xi+=h
++
++	psrld	\$11,$t2
++	pxor	$t3,$sigma
++	pslld	\$21-7,$t3
++	 paddd	`32*($i%8)-128`($Tbl),$Xi	# Xi+=K[round]
++	pxor	$t2,$sigma
++
++	psrld	\$25-11,$t2
++	 movdqa	$e,$t1
++	 `"prefetcht0	63(@ptr[0])"		if ($i==15)`
++	pxor	$t3,$sigma
++	 movdqa	$e,$axb				# borrow $axb
++	pslld	\$26-21,$t3
++	 pandn	$g,$t1
++	 pand	$f,$axb
++	pxor	$t2,$sigma
++
++	 `"prefetcht0	63(@ptr[1])"		if ($i==15)`
++	movdqa	$a,$t2
++	pxor	$t3,$sigma			# Sigma1(e)
++	movdqa	$a,$t3
++	psrld	\$2,$t2
++	paddd	$sigma,$Xi			# Xi+=Sigma1(e)
++	 pxor	$axb,$t1			# Ch(e,f,g)
++	 movdqa	$b,$axb
++	movdqa	$a,$sigma
++	pslld	\$10,$t3
++	 pxor	$a,$axb				# a^b, b^c in next round
++
++	 `"prefetcht0	63(@ptr[2])"		if ($i==15)`
++	psrld	\$13,$sigma
++	pxor	$t3,$t2
++	 paddd	$t1,$Xi				# Xi+=Ch(e,f,g)
++	pslld	\$19-10,$t3
++	 pand	$axb,$bxc
++	pxor	$sigma,$t2
++
++	 `"prefetcht0	63(@ptr[3])"		if ($i==15)`
++	psrld	\$22-13,$sigma
++	pxor	$t3,$t2
++	 movdqa	$b,$h
++	pslld	\$30-19,$t3
++	pxor	$t2,$sigma
++	 pxor	$bxc,$h				# h=Maj(a,b,c)=Ch(a^b,c,b)
++	 paddd	$Xi,$d				# d+=Xi
++	pxor	$t3,$sigma			# Sigma0(a)
++
++	paddd	$Xi,$h				# h+=Xi
++	paddd	$sigma,$h			# h+=Sigma0(a)
++___
++$code.=<<___ if (($i%8)==7);
++	lea	`32*8`($Tbl),$Tbl
++___
++	($axb,$bxc)=($bxc,$axb);
++}
++
++sub ROUND_16_XX {
++my $i=shift;
++
++$code.=<<___;
++	movdqa	`&Xi_off($i+1)`,$Xn
++	paddd	`&Xi_off($i+9)`,$Xi		# Xi+=X[i+9]
++
++	movdqa	$Xn,$sigma
++	movdqa	$Xn,$t2
++	psrld	\$3,$sigma
++	movdqa	$Xn,$t3
++
++	psrld	\$7,$t2
++	movdqa	`&Xi_off($i+14)`,$t1
++	pslld	\$14,$t3
++	pxor	$t2,$sigma
++	psrld	\$18-7,$t2
++	movdqa	$t1,$axb			# borrow $axb
++	pxor	$t3,$sigma
++	pslld	\$25-14,$t3
++	pxor	$t2,$sigma
++	psrld	\$10,$t1
++	movdqa	$axb,$t2
++
++	psrld	\$17,$axb
++	pxor	$t3,$sigma			# sigma0(X[i+1])
++	pslld	\$13,$t2
++	 paddd	$sigma,$Xi			# Xi+=sigma0(e)
++	pxor	$axb,$t1
++	psrld	\$19-17,$axb
++	pxor	$t2,$t1
++	pslld	\$15-13,$t2
++	pxor	$axb,$t1
++	pxor	$t2,$t1				# sigma0(X[i+14])
++	paddd	$t1,$Xi				# Xi+=sigma1(X[i+14])
++___
++	&ROUND_00_15($i,@_);
++	($Xi,$Xn)=($Xn,$Xi);
++}
++
++$code.=<<___;
++.text
++
++.extern	OPENSSL_ia32cap_P
++
++.globl	sha256_multi_block
++.type	sha256_multi_block,\@function,3
++.align	32
++sha256_multi_block:
++	mov	OPENSSL_ia32cap_P+4(%rip),%rcx
++	bt	\$61,%rcx			# check SHA bit
++	jc	_shaext_shortcut
++___
++$code.=<<___ if ($avx);
++	test	\$`1<<28`,%ecx
++	jnz	_avx_shortcut
++___
++$code.=<<___;
++	mov	%rsp,%rax
++	push	%rbx
++	push	%rbp
++___
++$code.=<<___ if ($win64);
++	lea	-0xa8(%rsp),%rsp
++	movaps	%xmm6,(%rsp)
++	movaps	%xmm7,0x10(%rsp)
++	movaps	%xmm8,0x20(%rsp)
++	movaps	%xmm9,0x30(%rsp)
++	movaps	%xmm10,-0x78(%rax)
++	movaps	%xmm11,-0x68(%rax)
++	movaps	%xmm12,-0x58(%rax)
++	movaps	%xmm13,-0x48(%rax)
++	movaps	%xmm14,-0x38(%rax)
++	movaps	%xmm15,-0x28(%rax)
++___
++$code.=<<___;
++	sub	\$`$REG_SZ*18`, %rsp
++	and	\$-256,%rsp
++	mov	%rax,`$REG_SZ*17`(%rsp)		# original %rsp
++.Lbody:
++	lea	K256+128(%rip),$Tbl
++	lea	`$REG_SZ*16`(%rsp),%rbx
++	lea	0x80($ctx),$ctx			# size optimization
++
++.Loop_grande:
++	mov	$num,`$REG_SZ*17+8`(%rsp)	# original $num
++	xor	$num,$num
++___
++for($i=0;$i<4;$i++) {
++    $code.=<<___;
++	mov	`16*$i+0`($inp),@ptr[$i]	# input pointer
++	mov	`16*$i+8`($inp),%ecx		# number of blocks
++	cmp	$num,%ecx
++	cmovg	%ecx,$num			# find maximum
++	test	%ecx,%ecx
++	mov	%ecx,`4*$i`(%rbx)		# initialize counters
++	cmovle	$Tbl,@ptr[$i]			# cancel input
++___
++}
++$code.=<<___;
++	test	$num,$num
++	jz	.Ldone
++
++	movdqu	0x00-0x80($ctx),$A		# load context
++	 lea	128(%rsp),%rax
++	movdqu	0x20-0x80($ctx),$B
++	movdqu	0x40-0x80($ctx),$C
++	movdqu	0x60-0x80($ctx),$D
++	movdqu	0x80-0x80($ctx),$E
++	movdqu	0xa0-0x80($ctx),$F
++	movdqu	0xc0-0x80($ctx),$G
++	movdqu	0xe0-0x80($ctx),$H
++	movdqu	.Lpbswap(%rip),$Xn
++	jmp	.Loop
++
++.align	32
++.Loop:
++	movdqa	$C,$bxc
++	pxor	$B,$bxc				# magic seed
++___
++for($i=0;$i<16;$i++)	{ &ROUND_00_15($i,@V); unshift(@V,pop(@V)); }
++$code.=<<___;
++	movdqu	`&Xi_off($i)`,$Xi
++	mov	\$3,%ecx
++	jmp	.Loop_16_xx
++.align	32
++.Loop_16_xx:
++___
++for(;$i<32;$i++)	{ &ROUND_16_XX($i,@V); unshift(@V,pop(@V)); }
++$code.=<<___;
++	dec	%ecx
++	jnz	.Loop_16_xx
++
++	mov	\$1,%ecx
++	lea	K256+128(%rip),$Tbl
++
++	movdqa	(%rbx),$sigma			# pull counters
++	cmp	4*0(%rbx),%ecx			# examine counters
++	pxor	$t1,$t1
++	cmovge	$Tbl,@ptr[0]			# cancel input
++	cmp	4*1(%rbx),%ecx
++	movdqa	$sigma,$Xn
++	cmovge	$Tbl,@ptr[1]
++	cmp	4*2(%rbx),%ecx
++	pcmpgtd	$t1,$Xn				# mask value
++	cmovge	$Tbl,@ptr[2]
++	cmp	4*3(%rbx),%ecx
++	paddd	$Xn,$sigma			# counters--
++	cmovge	$Tbl,@ptr[3]
++
++	movdqu	0x00-0x80($ctx),$t1
++	pand	$Xn,$A
++	movdqu	0x20-0x80($ctx),$t2
++	pand	$Xn,$B
++	movdqu	0x40-0x80($ctx),$t3
++	pand	$Xn,$C
++	movdqu	0x60-0x80($ctx),$Xi
++	pand	$Xn,$D
++	paddd	$t1,$A
++	movdqu	0x80-0x80($ctx),$t1
++	pand	$Xn,$E
++	paddd	$t2,$B
++	movdqu	0xa0-0x80($ctx),$t2
++	pand	$Xn,$F
++	paddd	$t3,$C
++	movdqu	0xc0-0x80($ctx),$t3
++	pand	$Xn,$G
++	paddd	$Xi,$D
++	movdqu	0xe0-0x80($ctx),$Xi
++	pand	$Xn,$H
++	paddd	$t1,$E
++	paddd	$t2,$F
++	movdqu	$A,0x00-0x80($ctx)
++	paddd	$t3,$G
++	movdqu	$B,0x20-0x80($ctx)
++	paddd	$Xi,$H
++	movdqu	$C,0x40-0x80($ctx)
++	movdqu	$D,0x60-0x80($ctx)
++	movdqu	$E,0x80-0x80($ctx)
++	movdqu	$F,0xa0-0x80($ctx)
++	movdqu	$G,0xc0-0x80($ctx)
++	movdqu	$H,0xe0-0x80($ctx)
++
++	movdqa	$sigma,(%rbx)			# save counters
++	movdqa	.Lpbswap(%rip),$Xn
++	dec	$num
++	jnz	.Loop
++
++	mov	`$REG_SZ*17+8`(%rsp),$num
++	lea	$REG_SZ($ctx),$ctx
++	lea	`16*$REG_SZ/4`($inp),$inp
++	dec	$num
++	jnz	.Loop_grande
++
++.Ldone:
++	mov	`$REG_SZ*17`(%rsp),%rax		# original %rsp
++___
++$code.=<<___ if ($win64);
++	movaps	-0xb8(%rax),%xmm6
++	movaps	-0xa8(%rax),%xmm7
++	movaps	-0x98(%rax),%xmm8
++	movaps	-0x88(%rax),%xmm9
++	movaps	-0x78(%rax),%xmm10
++	movaps	-0x68(%rax),%xmm11
++	movaps	-0x58(%rax),%xmm12
++	movaps	-0x48(%rax),%xmm13
++	movaps	-0x38(%rax),%xmm14
++	movaps	-0x28(%rax),%xmm15
++___
++$code.=<<___;
++	mov	-16(%rax),%rbp
++	mov	-8(%rax),%rbx
++	lea	(%rax),%rsp
++.Lepilogue:
++	ret
++.size	sha256_multi_block,.-sha256_multi_block
++___
++						{{{
++my ($Wi,$TMP0,$TMP1,$TMPx,$ABEF0,$CDGH0,$ABEF1,$CDGH1)=map("%xmm$_",(0..3,12..15));
++my @MSG0=map("%xmm$_",(4..7));
++my @MSG1=map("%xmm$_",(8..11));
++
++$code.=<<___;
++.type	sha256_multi_block_shaext,\@function,3
++.align	32
++sha256_multi_block_shaext:
++_shaext_shortcut:
++	mov	%rsp,%rax
++	push	%rbx
++	push	%rbp
++___
++$code.=<<___ if ($win64);
++	lea	-0xa8(%rsp),%rsp
++	movaps	%xmm6,(%rsp)
++	movaps	%xmm7,0x10(%rsp)
++	movaps	%xmm8,0x20(%rsp)
++	movaps	%xmm9,0x30(%rsp)
++	movaps	%xmm10,-0x78(%rax)
++	movaps	%xmm11,-0x68(%rax)
++	movaps	%xmm12,-0x58(%rax)
++	movaps	%xmm13,-0x48(%rax)
++	movaps	%xmm14,-0x38(%rax)
++	movaps	%xmm15,-0x28(%rax)
++___
++$code.=<<___;
++	sub	\$`$REG_SZ*18`,%rsp
++	shl	\$1,$num			# we process pair at a time
++	and	\$-256,%rsp
++	lea	0x80($ctx),$ctx			# size optimization
++	mov	%rax,`$REG_SZ*17`(%rsp)		# original %rsp
++.Lbody_shaext:
++	lea	`$REG_SZ*16`(%rsp),%rbx
++	lea	K256_shaext+0x80(%rip),$Tbl
++
++.Loop_grande_shaext:
++	mov	$num,`$REG_SZ*17+8`(%rsp)	# original $num
++	xor	$num,$num
++___
++for($i=0;$i<2;$i++) {
++    $code.=<<___;
++	mov	`16*$i+0`($inp),@ptr[$i]	# input pointer
++	mov	`16*$i+8`($inp),%ecx		# number of blocks
++	cmp	$num,%ecx
++	cmovg	%ecx,$num			# find maximum
++	test	%ecx,%ecx
++	mov	%ecx,`4*$i`(%rbx)		# initialize counters
++	cmovle	%rsp,@ptr[$i]			# cancel input
++___
++}
++$code.=<<___;
++	test	$num,$num
++	jz	.Ldone_shaext
++
++	movq		0x00-0x80($ctx),$ABEF0		# A1.A0
++	movq		0x20-0x80($ctx),@MSG0[0]	# B1.B0
++	movq		0x40-0x80($ctx),$CDGH0		# C1.C0
++	movq		0x60-0x80($ctx),@MSG0[1]	# D1.D0
++	movq		0x80-0x80($ctx),@MSG1[0]	# E1.E0
++	movq		0xa0-0x80($ctx),@MSG1[1]	# F1.F0
++	movq		0xc0-0x80($ctx),@MSG1[2]	# G1.G0
++	movq		0xe0-0x80($ctx),@MSG1[3]	# H1.H0
++
++	punpckldq	@MSG0[0],$ABEF0			# B1.A1.B0.A0
++	punpckldq	@MSG0[1],$CDGH0			# D1.C1.D0.C0
++	punpckldq	@MSG1[1],@MSG1[0]		# F1.E1.F0.E0
++	punpckldq	@MSG1[3],@MSG1[2]		# H1.G1.H0.G0
++	movdqa		K256_shaext-0x10(%rip),$TMPx	# byte swap
++
++	movdqa		$ABEF0,$ABEF1
++	movdqa		$CDGH0,$CDGH1
++	punpcklqdq	@MSG1[0],$ABEF0			# F0.E0.B0.A0
++	punpcklqdq	@MSG1[2],$CDGH0			# H0.G0.D0.C0
++	punpckhqdq	@MSG1[0],$ABEF1			# F1.E1.B1.A1
++	punpckhqdq	@MSG1[2],$CDGH1			# H1.G1.D1.C1
++
++	pshufd		\$0b00011011,$ABEF0,$ABEF0
++	pshufd		\$0b00011011,$CDGH0,$CDGH0
++	pshufd		\$0b00011011,$ABEF1,$ABEF1
++	pshufd		\$0b00011011,$CDGH1,$CDGH1
++	jmp		.Loop_shaext
++
++.align	32
++.Loop_shaext:
++	movdqu		0x00(@ptr[0]),@MSG0[0]
++	 movdqu		0x00(@ptr[1]),@MSG1[0]
++	movdqu		0x10(@ptr[0]),@MSG0[1]
++	 movdqu		0x10(@ptr[1]),@MSG1[1]
++	movdqu		0x20(@ptr[0]),@MSG0[2]
++	pshufb		$TMPx,@MSG0[0]
++	 movdqu		0x20(@ptr[1]),@MSG1[2]
++	 pshufb		$TMPx,@MSG1[0]
++	movdqu		0x30(@ptr[0]),@MSG0[3]
++	lea		0x40(@ptr[0]),@ptr[0]
++	 movdqu		0x30(@ptr[1]),@MSG1[3]
++	 lea		0x40(@ptr[1]),@ptr[1]
++
++	movdqa		0*16-0x80($Tbl),$Wi
++	pshufb		$TMPx,@MSG0[1]
++	paddd		@MSG0[0],$Wi
++	pxor		$ABEF0,@MSG0[0]		# black magic
++	movdqa		$Wi,$TMP0
++	 movdqa		0*16-0x80($Tbl),$TMP1
++	 pshufb		$TMPx,@MSG1[1]
++	 paddd		@MSG1[0],$TMP1
++	movdqa		$CDGH0,0x50(%rsp)	# offload
++	sha256rnds2	$ABEF0,$CDGH0		# 0-3
++	 pxor		$ABEF1,@MSG1[0]		# black magic
++	 movdqa		$TMP1,$Wi
++	 movdqa		$CDGH1,0x70(%rsp)
++	 sha256rnds2	$ABEF1,$CDGH1		# 0-3
++	pshufd		\$0x0e,$TMP0,$Wi
++	pxor		$ABEF0,@MSG0[0]		# black magic
++	movdqa		$ABEF0,0x40(%rsp)	# offload
++	sha256rnds2	$CDGH0,$ABEF0
++	 pshufd		\$0x0e,$TMP1,$Wi
++	 pxor		$ABEF1,@MSG1[0]		# black magic
++	 movdqa		$ABEF1,0x60(%rsp)
++	movdqa		1*16-0x80($Tbl),$TMP0
++	paddd		@MSG0[1],$TMP0
++	pshufb		$TMPx,@MSG0[2]
++	 sha256rnds2	$CDGH1,$ABEF1
++
++	movdqa		$TMP0,$Wi
++	 movdqa		1*16-0x80($Tbl),$TMP1
++	 paddd		@MSG1[1],$TMP1
++	sha256rnds2	$ABEF0,$CDGH0		# 4-7
++	 movdqa		$TMP1,$Wi
++	prefetcht0	127(@ptr[0])
++	pshufb		$TMPx,@MSG0[3]
++	 pshufb		$TMPx,@MSG1[2]
++	 prefetcht0	127(@ptr[1])
++	 sha256rnds2	$ABEF1,$CDGH1		# 4-7
++	pshufd		\$0x0e,$TMP0,$Wi
++	 pshufb		$TMPx,@MSG1[3]
++	sha256msg1	@MSG0[1],@MSG0[0]
++	sha256rnds2	$CDGH0,$ABEF0
++	 pshufd		\$0x0e,$TMP1,$Wi
++	movdqa		2*16-0x80($Tbl),$TMP0
++	paddd		@MSG0[2],$TMP0
++	 sha256rnds2	$CDGH1,$ABEF1
++
++	movdqa		$TMP0,$Wi
++	 movdqa		2*16-0x80($Tbl),$TMP1
++	 paddd		@MSG1[2],$TMP1
++	sha256rnds2	$ABEF0,$CDGH0		# 8-11
++	 sha256msg1	@MSG1[1],@MSG1[0]
++	 movdqa		$TMP1,$Wi
++	movdqa		@MSG0[3],$TMPx
++	 sha256rnds2	$ABEF1,$CDGH1		# 8-11
++	pshufd		\$0x0e,$TMP0,$Wi
++	palignr		\$4,@MSG0[2],$TMPx
++	paddd		$TMPx,@MSG0[0]
++	 movdqa		@MSG1[3],$TMPx
++	 palignr	\$4,@MSG1[2],$TMPx
++	sha256msg1	@MSG0[2],@MSG0[1]
++	sha256rnds2	$CDGH0,$ABEF0
++	 pshufd		\$0x0e,$TMP1,$Wi
++	movdqa		3*16-0x80($Tbl),$TMP0
++	paddd		@MSG0[3],$TMP0
++	 sha256rnds2	$CDGH1,$ABEF1
++	 sha256msg1	@MSG1[2],@MSG1[1]
++
++	movdqa		$TMP0,$Wi
++	 movdqa		3*16-0x80($Tbl),$TMP1
++	 paddd		$TMPx,@MSG1[0]
++	 paddd		@MSG1[3],$TMP1
++	sha256msg2	@MSG0[3],@MSG0[0]
++	sha256rnds2	$ABEF0,$CDGH0		# 12-15
++	 movdqa		$TMP1,$Wi
++	movdqa		@MSG0[0],$TMPx
++	palignr		\$4,@MSG0[3],$TMPx
++	 sha256rnds2	$ABEF1,$CDGH1		# 12-15
++	 sha256msg2	@MSG1[3],@MSG1[0]
++	pshufd		\$0x0e,$TMP0,$Wi
++	paddd		$TMPx,@MSG0[1]
++	 movdqa		@MSG1[0],$TMPx
++	 palignr	\$4,@MSG1[3],$TMPx
++	sha256msg1	@MSG0[3],@MSG0[2]
++	sha256rnds2	$CDGH0,$ABEF0
++	 pshufd		\$0x0e,$TMP1,$Wi
++	movdqa		4*16-0x80($Tbl),$TMP0
++	paddd		@MSG0[0],$TMP0
++	 sha256rnds2	$CDGH1,$ABEF1
++	 sha256msg1	@MSG1[3],@MSG1[2]
++___
++for($i=4;$i<16-3;$i++) {
++$code.=<<___;
++	movdqa		$TMP0,$Wi
++	 movdqa		$i*16-0x80($Tbl),$TMP1
++	 paddd		$TMPx,@MSG1[1]
++	 paddd		@MSG1[0],$TMP1
++	sha256msg2	@MSG0[0],@MSG0[1]
++	sha256rnds2	$ABEF0,$CDGH0		# 16-19...
++	 movdqa		$TMP1,$Wi
++	movdqa		@MSG0[1],$TMPx
++	palignr		\$4,@MSG0[0],$TMPx
++	 sha256rnds2	$ABEF1,$CDGH1		# 16-19...
++	 sha256msg2	@MSG1[0],@MSG1[1]
++	pshufd		\$0x0e,$TMP0,$Wi
++	paddd		$TMPx,@MSG0[2]
++	 movdqa		@MSG1[1],$TMPx
++	 palignr	\$4,@MSG1[0],$TMPx
++	sha256msg1	@MSG0[0],@MSG0[3]
++	sha256rnds2	$CDGH0,$ABEF0
++	 pshufd		\$0x0e,$TMP1,$Wi
++	movdqa		`($i+1)*16`-0x80($Tbl),$TMP0
++	paddd		@MSG0[1],$TMP0
++	 sha256rnds2	$CDGH1,$ABEF1
++	 sha256msg1	@MSG1[0],@MSG1[3]
++___
++	push(@MSG0,shift(@MSG0));	push(@MSG1,shift(@MSG1));
++}
++$code.=<<___;
++	movdqa		$TMP0,$Wi
++	 movdqa		13*16-0x80($Tbl),$TMP1
++	 paddd		$TMPx,@MSG1[1]
++	 paddd		@MSG1[0],$TMP1
++	sha256msg2	@MSG0[0],@MSG0[1]
++	sha256rnds2	$ABEF0,$CDGH0		# 52-55
++	 movdqa		$TMP1,$Wi
++	movdqa		@MSG0[1],$TMPx
++	palignr		\$4,@MSG0[0],$TMPx
++	 sha256rnds2	$ABEF1,$CDGH1		# 52-55
++	 sha256msg2	@MSG1[0],@MSG1[1]
++	pshufd		\$0x0e,$TMP0,$Wi
++	paddd		$TMPx,@MSG0[2]
++	 movdqa		@MSG1[1],$TMPx
++	 palignr	\$4,@MSG1[0],$TMPx
++	nop
++	sha256rnds2	$CDGH0,$ABEF0
++	 pshufd		\$0x0e,$TMP1,$Wi
++	movdqa		14*16-0x80($Tbl),$TMP0
++	paddd		@MSG0[1],$TMP0
++	 sha256rnds2	$CDGH1,$ABEF1
++
++	movdqa		$TMP0,$Wi
++	 movdqa		14*16-0x80($Tbl),$TMP1
++	 paddd		$TMPx,@MSG1[2]
++	 paddd		@MSG1[1],$TMP1
++	sha256msg2	@MSG0[1],@MSG0[2]
++	nop
++	sha256rnds2	$ABEF0,$CDGH0		# 56-59
++	 movdqa		$TMP1,$Wi
++	  mov		\$1,%ecx
++	  pxor		@MSG0[1],@MSG0[1]	# zero
++	 sha256rnds2	$ABEF1,$CDGH1		# 56-59
++	 sha256msg2	@MSG1[1],@MSG1[2]
++	pshufd		\$0x0e,$TMP0,$Wi
++	movdqa		15*16-0x80($Tbl),$TMP0
++	paddd		@MSG0[2],$TMP0
++	  movq		(%rbx),@MSG0[2]		# pull counters
++	  nop
++	sha256rnds2	$CDGH0,$ABEF0
++	 pshufd		\$0x0e,$TMP1,$Wi
++	 movdqa		15*16-0x80($Tbl),$TMP1
++	 paddd		@MSG1[2],$TMP1
++	 sha256rnds2	$CDGH1,$ABEF1
++
++	movdqa		$TMP0,$Wi
++	  cmp		4*0(%rbx),%ecx		# examine counters
++	  cmovge	%rsp,@ptr[0]		# cancel input
++	  cmp		4*1(%rbx),%ecx
++	  cmovge	%rsp,@ptr[1]
++	  pshufd	\$0x00,@MSG0[2],@MSG1[0]
++	sha256rnds2	$ABEF0,$CDGH0		# 60-63
++	 movdqa		$TMP1,$Wi
++	  pshufd	\$0x55,@MSG0[2],@MSG1[1]
++	  movdqa	@MSG0[2],@MSG1[2]
++	 sha256rnds2	$ABEF1,$CDGH1		# 60-63
++	pshufd		\$0x0e,$TMP0,$Wi
++	  pcmpgtd	@MSG0[1],@MSG1[0]
++	  pcmpgtd	@MSG0[1],@MSG1[1]
++	sha256rnds2	$CDGH0,$ABEF0
++	 pshufd		\$0x0e,$TMP1,$Wi
++	  pcmpgtd	@MSG0[1],@MSG1[2]	# counter mask
++	  movdqa	K256_shaext-0x10(%rip),$TMPx
++	 sha256rnds2	$CDGH1,$ABEF1
++
++	pand		@MSG1[0],$CDGH0
++	 pand		@MSG1[1],$CDGH1
++	pand		@MSG1[0],$ABEF0
++	 pand		@MSG1[1],$ABEF1
++	paddd		@MSG0[2],@MSG1[2]	# counters--
++
++	paddd		0x50(%rsp),$CDGH0
++	 paddd		0x70(%rsp),$CDGH1
++	paddd		0x40(%rsp),$ABEF0
++	 paddd		0x60(%rsp),$ABEF1
++
++	movq		@MSG1[2],(%rbx)		# save counters
++	dec		$num
++	jnz		.Loop_shaext
++
++	mov		`$REG_SZ*17+8`(%rsp),$num
++
++	pshufd		\$0b00011011,$ABEF0,$ABEF0
++	pshufd		\$0b00011011,$CDGH0,$CDGH0
++	pshufd		\$0b00011011,$ABEF1,$ABEF1
++	pshufd		\$0b00011011,$CDGH1,$CDGH1
++
++	movdqa		$ABEF0,@MSG0[0]
++	movdqa		$CDGH0,@MSG0[1]
++	punpckldq	$ABEF1,$ABEF0			# B1.B0.A1.A0
++	punpckhdq	$ABEF1,@MSG0[0]			# F1.F0.E1.E0
++	punpckldq	$CDGH1,$CDGH0			# D1.D0.C1.C0
++	punpckhdq	$CDGH1,@MSG0[1]			# H1.H0.G1.G0
++
++	movq		$ABEF0,0x00-0x80($ctx)		# A1.A0
++	psrldq		\$8,$ABEF0
++	movq		@MSG0[0],0x80-0x80($ctx)	# E1.E0
++	psrldq		\$8,@MSG0[0]
++	movq		$ABEF0,0x20-0x80($ctx)		# B1.B0
++	movq		@MSG0[0],0xa0-0x80($ctx)	# F1.F0
++
++	movq		$CDGH0,0x40-0x80($ctx)		# C1.C0
++	psrldq		\$8,$CDGH0
++	movq		@MSG0[1],0xc0-0x80($ctx)	# G1.G0
++	psrldq		\$8,@MSG0[1]
++	movq		$CDGH0,0x60-0x80($ctx)		# D1.D0
++	movq		@MSG0[1],0xe0-0x80($ctx)	# H1.H0
++
++	lea	`$REG_SZ/2`($ctx),$ctx
++	lea	`16*2`($inp),$inp
++	dec	$num
++	jnz	.Loop_grande_shaext
++
++.Ldone_shaext:
++	#mov	`$REG_SZ*17`(%rsp),%rax		# original %rsp
++___
++$code.=<<___ if ($win64);
++	movaps	-0xb8(%rax),%xmm6
++	movaps	-0xa8(%rax),%xmm7
++	movaps	-0x98(%rax),%xmm8
++	movaps	-0x88(%rax),%xmm9
++	movaps	-0x78(%rax),%xmm10
++	movaps	-0x68(%rax),%xmm11
++	movaps	-0x58(%rax),%xmm12
++	movaps	-0x48(%rax),%xmm13
++	movaps	-0x38(%rax),%xmm14
++	movaps	-0x28(%rax),%xmm15
++___
++$code.=<<___;
++	mov	-16(%rax),%rbp
++	mov	-8(%rax),%rbx
++	lea	(%rax),%rsp
++.Lepilogue_shaext:
++	ret
++.size	sha256_multi_block_shaext,.-sha256_multi_block_shaext
++___
++						}}}
++						if ($avx) {{{
++sub ROUND_00_15_avx {
++my ($i,$a,$b,$c,$d,$e,$f,$g,$h)=@_;
++
++$code.=<<___ if ($i<15 && $REG_SZ==16);
++	vmovd		`4*$i`(@ptr[0]),$Xi
++	vmovd		`4*$i`(@ptr[1]),$t1
++	vpinsrd		\$1,`4*$i`(@ptr[2]),$Xi,$Xi
++	vpinsrd		\$1,`4*$i`(@ptr[3]),$t1,$t1
++	vpunpckldq	$t1,$Xi,$Xi
++	vpshufb		$Xn,$Xi,$Xi
++___
++$code.=<<___ if ($i==15 && $REG_SZ==16);
++	vmovd		`4*$i`(@ptr[0]),$Xi
++	 lea		`16*4`(@ptr[0]),@ptr[0]
++	vmovd		`4*$i`(@ptr[1]),$t1
++	 lea		`16*4`(@ptr[1]),@ptr[1]
++	vpinsrd		\$1,`4*$i`(@ptr[2]),$Xi,$Xi
++	 lea		`16*4`(@ptr[2]),@ptr[2]
++	vpinsrd		\$1,`4*$i`(@ptr[3]),$t1,$t1
++	 lea		`16*4`(@ptr[3]),@ptr[3]
++	vpunpckldq	$t1,$Xi,$Xi
++	vpshufb		$Xn,$Xi,$Xi
++___
++$code.=<<___ if ($i<15 && $REG_SZ==32);
++	vmovd		`4*$i`(@ptr[0]),$Xi
++	vmovd		`4*$i`(@ptr[4]),$t1
++	vmovd		`4*$i`(@ptr[1]),$t2
++	vmovd		`4*$i`(@ptr[5]),$t3
++	vpinsrd		\$1,`4*$i`(@ptr[2]),$Xi,$Xi
++	vpinsrd		\$1,`4*$i`(@ptr[6]),$t1,$t1
++	vpinsrd		\$1,`4*$i`(@ptr[3]),$t2,$t2
++	vpunpckldq	$t2,$Xi,$Xi
++	vpinsrd		\$1,`4*$i`(@ptr[7]),$t3,$t3
++	vpunpckldq	$t3,$t1,$t1
++	vinserti128	$t1,$Xi,$Xi
++	vpshufb		$Xn,$Xi,$Xi
++___
++$code.=<<___ if ($i==15 && $REG_SZ==32);
++	vmovd		`4*$i`(@ptr[0]),$Xi
++	 lea		`16*4`(@ptr[0]),@ptr[0]
++	vmovd		`4*$i`(@ptr[4]),$t1
++	 lea		`16*4`(@ptr[4]),@ptr[4]
++	vmovd		`4*$i`(@ptr[1]),$t2
++	 lea		`16*4`(@ptr[1]),@ptr[1]
++	vmovd		`4*$i`(@ptr[5]),$t3
++	 lea		`16*4`(@ptr[5]),@ptr[5]
++	vpinsrd		\$1,`4*$i`(@ptr[2]),$Xi,$Xi
++	 lea		`16*4`(@ptr[2]),@ptr[2]
++	vpinsrd		\$1,`4*$i`(@ptr[6]),$t1,$t1
++	 lea		`16*4`(@ptr[6]),@ptr[6]
++	vpinsrd		\$1,`4*$i`(@ptr[3]),$t2,$t2
++	 lea		`16*4`(@ptr[3]),@ptr[3]
++	vpunpckldq	$t2,$Xi,$Xi
++	vpinsrd		\$1,`4*$i`(@ptr[7]),$t3,$t3
++	 lea		`16*4`(@ptr[7]),@ptr[7]
++	vpunpckldq	$t3,$t1,$t1
++	vinserti128	$t1,$Xi,$Xi
++	vpshufb		$Xn,$Xi,$Xi
++___
++$code.=<<___;
++	vpsrld	\$6,$e,$sigma
++	vpslld	\$26,$e,$t3
++	vmovdqu	$Xi,`&Xi_off($i)`
++	 vpaddd	$h,$Xi,$Xi			# Xi+=h
++
++	vpsrld	\$11,$e,$t2
++	vpxor	$t3,$sigma,$sigma
++	vpslld	\$21,$e,$t3
++	 vpaddd	`32*($i%8)-128`($Tbl),$Xi,$Xi	# Xi+=K[round]
++	vpxor	$t2,$sigma,$sigma
++
++	vpsrld	\$25,$e,$t2
++	vpxor	$t3,$sigma,$sigma
++	 `"prefetcht0	63(@ptr[0])"		if ($i==15)`
++	vpslld	\$7,$e,$t3
++	 vpandn	$g,$e,$t1
++	 vpand	$f,$e,$axb			# borrow $axb
++	 `"prefetcht0	63(@ptr[1])"		if ($i==15)`
++	vpxor	$t2,$sigma,$sigma
++
++	vpsrld	\$2,$a,$h			# borrow $h
++	vpxor	$t3,$sigma,$sigma		# Sigma1(e)
++	 `"prefetcht0	63(@ptr[2])"		if ($i==15)`
++	vpslld	\$30,$a,$t2
++	 vpxor	$axb,$t1,$t1			# Ch(e,f,g)
++	 vpxor	$a,$b,$axb			# a^b, b^c in next round
++	 `"prefetcht0	63(@ptr[3])"		if ($i==15)`
++	vpxor	$t2,$h,$h
++	vpaddd	$sigma,$Xi,$Xi			# Xi+=Sigma1(e)
++
++	vpsrld	\$13,$a,$t2
++	 `"prefetcht0	63(@ptr[4])"		if ($i==15 && $REG_SZ==32)`
++	vpslld	\$19,$a,$t3
++	 vpaddd	$t1,$Xi,$Xi			# Xi+=Ch(e,f,g)
++	 vpand	$axb,$bxc,$bxc
++	 `"prefetcht0	63(@ptr[5])"		if ($i==15 && $REG_SZ==32)`
++	vpxor	$t2,$h,$sigma
++
++	vpsrld	\$22,$a,$t2
++	vpxor	$t3,$sigma,$sigma
++	 `"prefetcht0	63(@ptr[6])"		if ($i==15 && $REG_SZ==32)`
++	vpslld	\$10,$a,$t3
++	 vpxor	$bxc,$b,$h			# h=Maj(a,b,c)=Ch(a^b,c,b)
++	 vpaddd	$Xi,$d,$d			# d+=Xi
++	 `"prefetcht0	63(@ptr[7])"		if ($i==15 && $REG_SZ==32)`
++	vpxor	$t2,$sigma,$sigma
++	vpxor	$t3,$sigma,$sigma		# Sigma0(a)
++
++	vpaddd	$Xi,$h,$h			# h+=Xi
++	vpaddd	$sigma,$h,$h			# h+=Sigma0(a)
++___
++$code.=<<___ if (($i%8)==7);
++	add	\$`32*8`,$Tbl
++___
++	($axb,$bxc)=($bxc,$axb);
++}
++
++sub ROUND_16_XX_avx {
++my $i=shift;
++
++$code.=<<___;
++	vmovdqu	`&Xi_off($i+1)`,$Xn
++	vpaddd	`&Xi_off($i+9)`,$Xi,$Xi		# Xi+=X[i+9]
++
++	vpsrld	\$3,$Xn,$sigma
++	vpsrld	\$7,$Xn,$t2
++	vpslld	\$25,$Xn,$t3
++	vpxor	$t2,$sigma,$sigma
++	vpsrld	\$18,$Xn,$t2
++	vpxor	$t3,$sigma,$sigma
++	vpslld	\$14,$Xn,$t3
++	vmovdqu	`&Xi_off($i+14)`,$t1
++	vpsrld	\$10,$t1,$axb			# borrow $axb
++
++	vpxor	$t2,$sigma,$sigma
++	vpsrld	\$17,$t1,$t2
++	vpxor	$t3,$sigma,$sigma		# sigma0(X[i+1])
++	vpslld	\$15,$t1,$t3
++	 vpaddd	$sigma,$Xi,$Xi			# Xi+=sigma0(e)
++	vpxor	$t2,$axb,$sigma
++	vpsrld	\$19,$t1,$t2
++	vpxor	$t3,$sigma,$sigma
++	vpslld	\$13,$t1,$t3
++	vpxor	$t2,$sigma,$sigma
++	vpxor	$t3,$sigma,$sigma		# sigma0(X[i+14])
++	vpaddd	$sigma,$Xi,$Xi			# Xi+=sigma1(X[i+14])
++___
++	&ROUND_00_15_avx($i,@_);
++	($Xi,$Xn)=($Xn,$Xi);
++}
++
++$code.=<<___;
++.type	sha256_multi_block_avx,\@function,3
++.align	32
++sha256_multi_block_avx:
++_avx_shortcut:
++___
++$code.=<<___ if ($avx>1);
++	shr	\$32,%rcx
++	cmp	\$2,$num
++	jb	.Lavx
++	test	\$`1<<5`,%ecx
++	jnz	_avx2_shortcut
++	jmp	.Lavx
++.align	32
++.Lavx:
++___
++$code.=<<___;
++	mov	%rsp,%rax
++	push	%rbx
++	push	%rbp
++___
++$code.=<<___ if ($win64);
++	lea	-0xa8(%rsp),%rsp
++	movaps	%xmm6,(%rsp)
++	movaps	%xmm7,0x10(%rsp)
++	movaps	%xmm8,0x20(%rsp)
++	movaps	%xmm9,0x30(%rsp)
++	movaps	%xmm10,-0x78(%rax)
++	movaps	%xmm11,-0x68(%rax)
++	movaps	%xmm12,-0x58(%rax)
++	movaps	%xmm13,-0x48(%rax)
++	movaps	%xmm14,-0x38(%rax)
++	movaps	%xmm15,-0x28(%rax)
++___
++$code.=<<___;
++	sub	\$`$REG_SZ*18`, %rsp
++	and	\$-256,%rsp
++	mov	%rax,`$REG_SZ*17`(%rsp)		# original %rsp
++.Lbody_avx:
++	lea	K256+128(%rip),$Tbl
++	lea	`$REG_SZ*16`(%rsp),%rbx
++	lea	0x80($ctx),$ctx			# size optimization
++
++.Loop_grande_avx:
++	mov	$num,`$REG_SZ*17+8`(%rsp)	# original $num
++	xor	$num,$num
++___
++for($i=0;$i<4;$i++) {
++    $code.=<<___;
++	mov	`16*$i+0`($inp),@ptr[$i]	# input pointer
++	mov	`16*$i+8`($inp),%ecx		# number of blocks
++	cmp	$num,%ecx
++	cmovg	%ecx,$num			# find maximum
++	test	%ecx,%ecx
++	mov	%ecx,`4*$i`(%rbx)		# initialize counters
++	cmovle	$Tbl,@ptr[$i]			# cancel input
++___
++}
++$code.=<<___;
++	test	$num,$num
++	jz	.Ldone_avx
++
++	vmovdqu	0x00-0x80($ctx),$A		# load context
++	 lea	128(%rsp),%rax
++	vmovdqu	0x20-0x80($ctx),$B
++	vmovdqu	0x40-0x80($ctx),$C
++	vmovdqu	0x60-0x80($ctx),$D
++	vmovdqu	0x80-0x80($ctx),$E
++	vmovdqu	0xa0-0x80($ctx),$F
++	vmovdqu	0xc0-0x80($ctx),$G
++	vmovdqu	0xe0-0x80($ctx),$H
++	vmovdqu	.Lpbswap(%rip),$Xn
++	jmp	.Loop_avx
++
++.align	32
++.Loop_avx:
++	vpxor	$B,$C,$bxc			# magic seed
++___
++for($i=0;$i<16;$i++)	{ &ROUND_00_15_avx($i,@V); unshift(@V,pop(@V)); }
++$code.=<<___;
++	vmovdqu	`&Xi_off($i)`,$Xi
++	mov	\$3,%ecx
++	jmp	.Loop_16_xx_avx
++.align	32
++.Loop_16_xx_avx:
++___
++for(;$i<32;$i++)	{ &ROUND_16_XX_avx($i,@V); unshift(@V,pop(@V)); }
++$code.=<<___;
++	dec	%ecx
++	jnz	.Loop_16_xx_avx
++
++	mov	\$1,%ecx
++	lea	K256+128(%rip),$Tbl
++___
++for($i=0;$i<4;$i++) {
++    $code.=<<___;
++	cmp	`4*$i`(%rbx),%ecx		# examine counters
++	cmovge	$Tbl,@ptr[$i]			# cancel input
++___
++}
++$code.=<<___;
++	vmovdqa	(%rbx),$sigma			# pull counters
++	vpxor	$t1,$t1,$t1
++	vmovdqa	$sigma,$Xn
++	vpcmpgtd $t1,$Xn,$Xn			# mask value
++	vpaddd	$Xn,$sigma,$sigma		# counters--
++
++	vmovdqu	0x00-0x80($ctx),$t1
++	vpand	$Xn,$A,$A
++	vmovdqu	0x20-0x80($ctx),$t2
++	vpand	$Xn,$B,$B
++	vmovdqu	0x40-0x80($ctx),$t3
++	vpand	$Xn,$C,$C
++	vmovdqu	0x60-0x80($ctx),$Xi
++	vpand	$Xn,$D,$D
++	vpaddd	$t1,$A,$A
++	vmovdqu	0x80-0x80($ctx),$t1
++	vpand	$Xn,$E,$E
++	vpaddd	$t2,$B,$B
++	vmovdqu	0xa0-0x80($ctx),$t2
++	vpand	$Xn,$F,$F
++	vpaddd	$t3,$C,$C
++	vmovdqu	0xc0-0x80($ctx),$t3
++	vpand	$Xn,$G,$G
++	vpaddd	$Xi,$D,$D
++	vmovdqu	0xe0-0x80($ctx),$Xi
++	vpand	$Xn,$H,$H
++	vpaddd	$t1,$E,$E
++	vpaddd	$t2,$F,$F
++	vmovdqu	$A,0x00-0x80($ctx)
++	vpaddd	$t3,$G,$G
++	vmovdqu	$B,0x20-0x80($ctx)
++	vpaddd	$Xi,$H,$H
++	vmovdqu	$C,0x40-0x80($ctx)
++	vmovdqu	$D,0x60-0x80($ctx)
++	vmovdqu	$E,0x80-0x80($ctx)
++	vmovdqu	$F,0xa0-0x80($ctx)
++	vmovdqu	$G,0xc0-0x80($ctx)
++	vmovdqu	$H,0xe0-0x80($ctx)
++
++	vmovdqu	$sigma,(%rbx)			# save counters
++	vmovdqu	.Lpbswap(%rip),$Xn
++	dec	$num
++	jnz	.Loop_avx
++
++	mov	`$REG_SZ*17+8`(%rsp),$num
++	lea	$REG_SZ($ctx),$ctx
++	lea	`16*$REG_SZ/4`($inp),$inp
++	dec	$num
++	jnz	.Loop_grande_avx
++
++.Ldone_avx:
++	mov	`$REG_SZ*17`(%rsp),%rax		# original %rsp
++	vzeroupper
++___
++$code.=<<___ if ($win64);
++	movaps	-0xb8(%rax),%xmm6
++	movaps	-0xa8(%rax),%xmm7
++	movaps	-0x98(%rax),%xmm8
++	movaps	-0x88(%rax),%xmm9
++	movaps	-0x78(%rax),%xmm10
++	movaps	-0x68(%rax),%xmm11
++	movaps	-0x58(%rax),%xmm12
++	movaps	-0x48(%rax),%xmm13
++	movaps	-0x38(%rax),%xmm14
++	movaps	-0x28(%rax),%xmm15
++___
++$code.=<<___;
++	mov	-16(%rax),%rbp
++	mov	-8(%rax),%rbx
++	lea	(%rax),%rsp
++.Lepilogue_avx:
++	ret
++.size	sha256_multi_block_avx,.-sha256_multi_block_avx
++___
++						if ($avx>1) {
++$code =~ s/\`([^\`]*)\`/eval $1/gem;
++
++$REG_SZ=32;
++@ptr=map("%r$_",(12..15,8..11));
++
++@V=($A,$B,$C,$D,$E,$F,$G,$H)=map("%ymm$_",(8..15));
++($t1,$t2,$t3,$axb,$bxc,$Xi,$Xn,$sigma)=map("%ymm$_",(0..7));
++
++$code.=<<___;
++.type	sha256_multi_block_avx2,\@function,3
++.align	32
++sha256_multi_block_avx2:
++_avx2_shortcut:
++	mov	%rsp,%rax
++	push	%rbx
++	push	%rbp
++	push	%r12
++	push	%r13
++	push	%r14
++	push	%r15
++___
++$code.=<<___ if ($win64);
++	lea	-0xa8(%rsp),%rsp
++	movaps	%xmm6,(%rsp)
++	movaps	%xmm7,0x10(%rsp)
++	movaps	%xmm8,0x20(%rsp)
++	movaps	%xmm9,0x30(%rsp)
++	movaps	%xmm10,0x40(%rsp)
++	movaps	%xmm11,0x50(%rsp)
++	movaps	%xmm12,-0x78(%rax)
++	movaps	%xmm13,-0x68(%rax)
++	movaps	%xmm14,-0x58(%rax)
++	movaps	%xmm15,-0x48(%rax)
++___
++$code.=<<___;
++	sub	\$`$REG_SZ*18`, %rsp
++	and	\$-256,%rsp
++	mov	%rax,`$REG_SZ*17`(%rsp)		# original %rsp
++.Lbody_avx2:
++	lea	K256+128(%rip),$Tbl
++	lea	0x80($ctx),$ctx			# size optimization
++
++.Loop_grande_avx2:
++	mov	$num,`$REG_SZ*17+8`(%rsp)	# original $num
++	xor	$num,$num
++	lea	`$REG_SZ*16`(%rsp),%rbx
++___
++for($i=0;$i<8;$i++) {
++    $code.=<<___;
++	mov	`16*$i+0`($inp),@ptr[$i]	# input pointer
++	mov	`16*$i+8`($inp),%ecx		# number of blocks
++	cmp	$num,%ecx
++	cmovg	%ecx,$num			# find maximum
++	test	%ecx,%ecx
++	mov	%ecx,`4*$i`(%rbx)		# initialize counters
++	cmovle	$Tbl,@ptr[$i]			# cancel input
++___
++}
++$code.=<<___;
++	vmovdqu	0x00-0x80($ctx),$A		# load context
++	 lea	128(%rsp),%rax
++	vmovdqu	0x20-0x80($ctx),$B
++	 lea	256+128(%rsp),%rbx
++	vmovdqu	0x40-0x80($ctx),$C
++	vmovdqu	0x60-0x80($ctx),$D
++	vmovdqu	0x80-0x80($ctx),$E
++	vmovdqu	0xa0-0x80($ctx),$F
++	vmovdqu	0xc0-0x80($ctx),$G
++	vmovdqu	0xe0-0x80($ctx),$H
++	vmovdqu	.Lpbswap(%rip),$Xn
++	jmp	.Loop_avx2
++
++.align	32
++.Loop_avx2:
++	vpxor	$B,$C,$bxc			# magic seed
++___
++for($i=0;$i<16;$i++)	{ &ROUND_00_15_avx($i,@V); unshift(@V,pop(@V)); }
++$code.=<<___;
++	vmovdqu	`&Xi_off($i)`,$Xi
++	mov	\$3,%ecx
++	jmp	.Loop_16_xx_avx2
++.align	32
++.Loop_16_xx_avx2:
++___
++for(;$i<32;$i++)	{ &ROUND_16_XX_avx($i,@V); unshift(@V,pop(@V)); }
++$code.=<<___;
++	dec	%ecx
++	jnz	.Loop_16_xx_avx2
++
++	mov	\$1,%ecx
++	lea	`$REG_SZ*16`(%rsp),%rbx
++	lea	K256+128(%rip),$Tbl
++___
++for($i=0;$i<8;$i++) {
++    $code.=<<___;
++	cmp	`4*$i`(%rbx),%ecx		# examine counters
++	cmovge	$Tbl,@ptr[$i]			# cancel input
++___
++}
++$code.=<<___;
++	vmovdqa	(%rbx),$sigma			# pull counters
++	vpxor	$t1,$t1,$t1
++	vmovdqa	$sigma,$Xn
++	vpcmpgtd $t1,$Xn,$Xn			# mask value
++	vpaddd	$Xn,$sigma,$sigma		# counters--
++
++	vmovdqu	0x00-0x80($ctx),$t1
++	vpand	$Xn,$A,$A
++	vmovdqu	0x20-0x80($ctx),$t2
++	vpand	$Xn,$B,$B
++	vmovdqu	0x40-0x80($ctx),$t3
++	vpand	$Xn,$C,$C
++	vmovdqu	0x60-0x80($ctx),$Xi
++	vpand	$Xn,$D,$D
++	vpaddd	$t1,$A,$A
++	vmovdqu	0x80-0x80($ctx),$t1
++	vpand	$Xn,$E,$E
++	vpaddd	$t2,$B,$B
++	vmovdqu	0xa0-0x80($ctx),$t2
++	vpand	$Xn,$F,$F
++	vpaddd	$t3,$C,$C
++	vmovdqu	0xc0-0x80($ctx),$t3
++	vpand	$Xn,$G,$G
++	vpaddd	$Xi,$D,$D
++	vmovdqu	0xe0-0x80($ctx),$Xi
++	vpand	$Xn,$H,$H
++	vpaddd	$t1,$E,$E
++	vpaddd	$t2,$F,$F
++	vmovdqu	$A,0x00-0x80($ctx)
++	vpaddd	$t3,$G,$G
++	vmovdqu	$B,0x20-0x80($ctx)
++	vpaddd	$Xi,$H,$H
++	vmovdqu	$C,0x40-0x80($ctx)
++	vmovdqu	$D,0x60-0x80($ctx)
++	vmovdqu	$E,0x80-0x80($ctx)
++	vmovdqu	$F,0xa0-0x80($ctx)
++	vmovdqu	$G,0xc0-0x80($ctx)
++	vmovdqu	$H,0xe0-0x80($ctx)
++
++	vmovdqu	$sigma,(%rbx)			# save counters
++	lea	256+128(%rsp),%rbx
++	vmovdqu	.Lpbswap(%rip),$Xn
++	dec	$num
++	jnz	.Loop_avx2
++
++	#mov	`$REG_SZ*17+8`(%rsp),$num
++	#lea	$REG_SZ($ctx),$ctx
++	#lea	`16*$REG_SZ/4`($inp),$inp
++	#dec	$num
++	#jnz	.Loop_grande_avx2
++
++.Ldone_avx2:
++	mov	`$REG_SZ*17`(%rsp),%rax		# original %rsp
++	vzeroupper
++___
++$code.=<<___ if ($win64);
++	movaps	-0xd8(%rax),%xmm6
++	movaps	-0xc8(%rax),%xmm7
++	movaps	-0xb8(%rax),%xmm8
++	movaps	-0xa8(%rax),%xmm9
++	movaps	-0x98(%rax),%xmm10
++	movaps	-0x88(%rax),%xmm11
++	movaps	-0x78(%rax),%xmm12
++	movaps	-0x68(%rax),%xmm13
++	movaps	-0x58(%rax),%xmm14
++	movaps	-0x48(%rax),%xmm15
++___
++$code.=<<___;
++	mov	-48(%rax),%r15
++	mov	-40(%rax),%r14
++	mov	-32(%rax),%r13
++	mov	-24(%rax),%r12
++	mov	-16(%rax),%rbp
++	mov	-8(%rax),%rbx
++	lea	(%rax),%rsp
++.Lepilogue_avx2:
++	ret
++.size	sha256_multi_block_avx2,.-sha256_multi_block_avx2
++___
++					}	}}}
++$code.=<<___;
++.align	256
++K256:
++___
++sub TABLE {
++    foreach (@_) {
++	$code.=<<___;
++	.long	$_,$_,$_,$_
++	.long	$_,$_,$_,$_
++___
++    }
++}
++&TABLE(	0x428a2f98,0x71374491,0xb5c0fbcf,0xe9b5dba5,
++	0x3956c25b,0x59f111f1,0x923f82a4,0xab1c5ed5,
++	0xd807aa98,0x12835b01,0x243185be,0x550c7dc3,
++	0x72be5d74,0x80deb1fe,0x9bdc06a7,0xc19bf174,
++	0xe49b69c1,0xefbe4786,0x0fc19dc6,0x240ca1cc,
++	0x2de92c6f,0x4a7484aa,0x5cb0a9dc,0x76f988da,
++	0x983e5152,0xa831c66d,0xb00327c8,0xbf597fc7,
++	0xc6e00bf3,0xd5a79147,0x06ca6351,0x14292967,
++	0x27b70a85,0x2e1b2138,0x4d2c6dfc,0x53380d13,
++	0x650a7354,0x766a0abb,0x81c2c92e,0x92722c85,
++	0xa2bfe8a1,0xa81a664b,0xc24b8b70,0xc76c51a3,
++	0xd192e819,0xd6990624,0xf40e3585,0x106aa070,
++	0x19a4c116,0x1e376c08,0x2748774c,0x34b0bcb5,
++	0x391c0cb3,0x4ed8aa4a,0x5b9cca4f,0x682e6ff3,
++	0x748f82ee,0x78a5636f,0x84c87814,0x8cc70208,
++	0x90befffa,0xa4506ceb,0xbef9a3f7,0xc67178f2 );
++$code.=<<___;
++.Lpbswap:
++	.long	0x00010203,0x04050607,0x08090a0b,0x0c0d0e0f	# pbswap
++	.long	0x00010203,0x04050607,0x08090a0b,0x0c0d0e0f	# pbswap
++K256_shaext:
++	.long	0x428a2f98,0x71374491,0xb5c0fbcf,0xe9b5dba5
++	.long	0x3956c25b,0x59f111f1,0x923f82a4,0xab1c5ed5
++	.long	0xd807aa98,0x12835b01,0x243185be,0x550c7dc3
++	.long	0x72be5d74,0x80deb1fe,0x9bdc06a7,0xc19bf174
++	.long	0xe49b69c1,0xefbe4786,0x0fc19dc6,0x240ca1cc
++	.long	0x2de92c6f,0x4a7484aa,0x5cb0a9dc,0x76f988da
++	.long	0x983e5152,0xa831c66d,0xb00327c8,0xbf597fc7
++	.long	0xc6e00bf3,0xd5a79147,0x06ca6351,0x14292967
++	.long	0x27b70a85,0x2e1b2138,0x4d2c6dfc,0x53380d13
++	.long	0x650a7354,0x766a0abb,0x81c2c92e,0x92722c85
++	.long	0xa2bfe8a1,0xa81a664b,0xc24b8b70,0xc76c51a3
++	.long	0xd192e819,0xd6990624,0xf40e3585,0x106aa070
++	.long	0x19a4c116,0x1e376c08,0x2748774c,0x34b0bcb5
++	.long	0x391c0cb3,0x4ed8aa4a,0x5b9cca4f,0x682e6ff3
++	.long	0x748f82ee,0x78a5636f,0x84c87814,0x8cc70208
++	.long	0x90befffa,0xa4506ceb,0xbef9a3f7,0xc67178f2
++	.asciz	"SHA256 multi-block transform for x86_64, CRYPTOGAMS by "
++___
++
++if ($win64) {
++# EXCEPTION_DISPOSITION handler (EXCEPTION_RECORD *rec,ULONG64 frame,
++#		CONTEXT *context,DISPATCHER_CONTEXT *disp)
++$rec="%rcx";
++$frame="%rdx";
++$context="%r8";
++$disp="%r9";
++
++$code.=<<___;
++.extern	__imp_RtlVirtualUnwind
++.type	se_handler,\@abi-omnipotent
++.align	16
++se_handler:
++	push	%rsi
++	push	%rdi
++	push	%rbx
++	push	%rbp
++	push	%r12
++	push	%r13
++	push	%r14
++	push	%r15
++	pushfq
++	sub	\$64,%rsp
++
++	mov	120($context),%rax	# pull context->Rax
++	mov	248($context),%rbx	# pull context->Rip
++
++	mov	8($disp),%rsi		# disp->ImageBase
++	mov	56($disp),%r11		# disp->HandlerData
++
++	mov	0(%r11),%r10d		# HandlerData[0]
++	lea	(%rsi,%r10),%r10	# end of prologue label
++	cmp	%r10,%rbx		# context->Rip<.Lbody
++	jb	.Lin_prologue
++
++	mov	152($context),%rax	# pull context->Rsp
++
++	mov	4(%r11),%r10d		# HandlerData[1]
++	lea	(%rsi,%r10),%r10	# epilogue label
++	cmp	%r10,%rbx		# context->Rip>=.Lepilogue
++	jae	.Lin_prologue
++
++	mov	`16*17`(%rax),%rax	# pull saved stack pointer
++
++	mov	-8(%rax),%rbx
++	mov	-16(%rax),%rbp
++	mov	%rbx,144($context)	# restore context->Rbx
++	mov	%rbp,160($context)	# restore context->Rbp
++
++	lea	-24-10*16(%rax),%rsi
++	lea	512($context),%rdi	# &context.Xmm6
++	mov	\$20,%ecx
++	.long	0xa548f3fc		# cld; rep movsq
++
++.Lin_prologue:
++	mov	8(%rax),%rdi
++	mov	16(%rax),%rsi
++	mov	%rax,152($context)	# restore context->Rsp
++	mov	%rsi,168($context)	# restore context->Rsi
++	mov	%rdi,176($context)	# restore context->Rdi
++
++	mov	40($disp),%rdi		# disp->ContextRecord
++	mov	$context,%rsi		# context
++	mov	\$154,%ecx		# sizeof(CONTEXT)
++	.long	0xa548f3fc		# cld; rep movsq
++
++	mov	$disp,%rsi
++	xor	%rcx,%rcx		# arg1, UNW_FLAG_NHANDLER
++	mov	8(%rsi),%rdx		# arg2, disp->ImageBase
++	mov	0(%rsi),%r8		# arg3, disp->ControlPc
++	mov	16(%rsi),%r9		# arg4, disp->FunctionEntry
++	mov	40(%rsi),%r10		# disp->ContextRecord
++	lea	56(%rsi),%r11		# &disp->HandlerData
++	lea	24(%rsi),%r12		# &disp->EstablisherFrame
++	mov	%r10,32(%rsp)		# arg5
++	mov	%r11,40(%rsp)		# arg6
++	mov	%r12,48(%rsp)		# arg7
++	mov	%rcx,56(%rsp)		# arg8, (NULL)
++	call	*__imp_RtlVirtualUnwind(%rip)
++
++	mov	\$1,%eax		# ExceptionContinueSearch
++	add	\$64,%rsp
++	popfq
++	pop	%r15
++	pop	%r14
++	pop	%r13
++	pop	%r12
++	pop	%rbp
++	pop	%rbx
++	pop	%rdi
++	pop	%rsi
++	ret
++.size	se_handler,.-se_handler
++___
++$code.=<<___ if ($avx>1);
++.type	avx2_handler,\@abi-omnipotent
++.align	16
++avx2_handler:
++	push	%rsi
++	push	%rdi
++	push	%rbx
++	push	%rbp
++	push	%r12
++	push	%r13
++	push	%r14
++	push	%r15
++	pushfq
++	sub	\$64,%rsp
++
++	mov	120($context),%rax	# pull context->Rax
++	mov	248($context),%rbx	# pull context->Rip
++
++	mov	8($disp),%rsi		# disp->ImageBase
++	mov	56($disp),%r11		# disp->HandlerData
++
++	mov	0(%r11),%r10d		# HandlerData[0]
++	lea	(%rsi,%r10),%r10	# end of prologue label
++	cmp	%r10,%rbx		# context->RipRsp
++
++	mov	4(%r11),%r10d		# HandlerData[1]
++	lea	(%rsi,%r10),%r10	# epilogue label
++	cmp	%r10,%rbx		# context->Rip>=epilogue label
++	jae	.Lin_prologue
++
++	mov	`32*17`($context),%rax	# pull saved stack pointer
++
++	mov	-8(%rax),%rbx
++	mov	-16(%rax),%rbp
++	mov	-24(%rax),%r12
++	mov	-32(%rax),%r13
++	mov	-40(%rax),%r14
++	mov	-48(%rax),%r15
++	mov	%rbx,144($context)	# restore context->Rbx
++	mov	%rbp,160($context)	# restore context->Rbp
++	mov	%r12,216($context)	# restore cotnext->R12
++	mov	%r13,224($context)	# restore cotnext->R13
++	mov	%r14,232($context)	# restore cotnext->R14
++	mov	%r15,240($context)	# restore cotnext->R15
++
++	lea	-56-10*16(%rax),%rsi
++	lea	512($context),%rdi	# &context.Xmm6
++	mov	\$20,%ecx
++	.long	0xa548f3fc		# cld; rep movsq
++
++	jmp	.Lin_prologue
++.size	avx2_handler,.-avx2_handler
++___
++$code.=<<___;
++.section	.pdata
++.align	4
++	.rva	.LSEH_begin_sha256_multi_block
++	.rva	.LSEH_end_sha256_multi_block
++	.rva	.LSEH_info_sha256_multi_block
++	.rva	.LSEH_begin_sha256_multi_block_shaext
++	.rva	.LSEH_end_sha256_multi_block_shaext
++	.rva	.LSEH_info_sha256_multi_block_shaext
++___
++$code.=<<___ if ($avx);
++	.rva	.LSEH_begin_sha256_multi_block_avx
++	.rva	.LSEH_end_sha256_multi_block_avx
++	.rva	.LSEH_info_sha256_multi_block_avx
++___
++$code.=<<___ if ($avx>1);
++	.rva	.LSEH_begin_sha256_multi_block_avx2
++	.rva	.LSEH_end_sha256_multi_block_avx2
++	.rva	.LSEH_info_sha256_multi_block_avx2
++___
++$code.=<<___;
++.section	.xdata
++.align	8
++.LSEH_info_sha256_multi_block:
++	.byte	9,0,0,0
++	.rva	se_handler
++	.rva	.Lbody,.Lepilogue			# HandlerData[]
++.LSEH_info_sha256_multi_block_shaext:
++	.byte	9,0,0,0
++	.rva	se_handler
++	.rva	.Lbody_shaext,.Lepilogue_shaext		# HandlerData[]
++___
++$code.=<<___ if ($avx);
++.LSEH_info_sha256_multi_block_avx:
++	.byte	9,0,0,0
++	.rva	se_handler
++	.rva	.Lbody_avx,.Lepilogue_avx		# HandlerData[]
++___
++$code.=<<___ if ($avx>1);
++.LSEH_info_sha256_multi_block_avx2:
++	.byte	9,0,0,0
++	.rva	avx2_handler
++	.rva	.Lbody_avx2,.Lepilogue_avx2		# HandlerData[]
++___
++}
++####################################################################
++
++sub rex {
++  local *opcode=shift;
++  my ($dst,$src)=@_;
++  my $rex=0;
++
++    $rex|=0x04			if ($dst>=8);
++    $rex|=0x01			if ($src>=8);
++    unshift @opcode,$rex|0x40	if ($rex);
++}
++
++sub sha256op38 {
++    my $instr = shift;
++    my %opcodelet = (
++		"sha256rnds2" => 0xcb,
++  		"sha256msg1"  => 0xcc,
++		"sha256msg2"  => 0xcd	);
++
++    if (defined($opcodelet{$instr}) && @_[0] =~ /%xmm([0-9]+),\s*%xmm([0-9]+)/) {
++      my @opcode=(0x0f,0x38);
++	rex(\@opcode,$2,$1);
++	push @opcode,$opcodelet{$instr};
++	push @opcode,0xc0|($1&7)|(($2&7)<<3);		# ModR/M
++	return ".byte\t".join(',',@opcode);
++    } else {
++	return $instr."\t".@_[0];
++    }
++}
++
++foreach (split("\n",$code)) {
++	s/\`([^\`]*)\`/eval($1)/ge;
++
++	s/\b(sha256[^\s]*)\s+(.*)/sha256op38($1,$2)/geo		or
++
++	s/\b(vmov[dq])\b(.+)%ymm([0-9]+)/$1$2%xmm$3/go		or
++	s/\b(vmovdqu)\b(.+)%x%ymm([0-9]+)/$1$2%xmm$3/go		or
++	s/\b(vpinsr[qd])\b(.+)%ymm([0-9]+),%ymm([0-9]+)/$1$2%xmm$3,%xmm$4/go	or
++	s/\b(vpextr[qd])\b(.+)%ymm([0-9]+)/$1$2%xmm$3/go	or
++	s/\b(vinserti128)\b(\s+)%ymm/$1$2\$1,%xmm/go		or
++	s/\b(vpbroadcast[qd]\s+)%ymm([0-9]+)/$1%xmm$2/go;
++
++	print $_,"\n";
++}
++
++close STDOUT;
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/sha/asm/sha512-586.pl b/CryptoPkg/Library/OpensslLib/openssl/crypto/sha/asm/sha512-586.pl
+new file mode 100644
+index 0000000..3873934
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/sha/asm/sha512-586.pl
+@@ -0,0 +1,924 @@
++#! /usr/bin/env perl
++# Copyright 2007-2016 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
++# in the file LICENSE in the source distribution or at
++# https://www.openssl.org/source/license.html
++
++#
++# ====================================================================
++# Written by Andy Polyakov  for the OpenSSL
++# project. The module is, however, dual licensed under OpenSSL and
++# CRYPTOGAMS licenses depending on where you obtain it. For further
++# details see http://www.openssl.org/~appro/cryptogams/.
++# ====================================================================
++#
++# SHA512 block transform for x86. September 2007.
++#
++# May 2013.
++#
++# Add SSSE3 code path, 20-25% improvement [over original SSE2 code].
++#
++# Performance in clock cycles per processed byte (less is better):
++#
++#		gcc	icc	x86 asm	SIMD(*)	x86_64(**)
++# Pentium	100	97	61	-	-
++# PIII		75	77	56	-	-
++# P4		116	95	82	34.6	30.8
++# AMD K8	54	55	36	20.7	9.57
++# Core2		66	57	40	15.9	9.97
++# Westmere	70	-	38	12.2	9.58
++# Sandy Bridge	58	-	35	11.9	11.2
++# Ivy Bridge	50	-	33	11.5	8.17
++# Haswell	46	-	29	11.3	7.66
++# Bulldozer	121	-	50	14.0	13.5
++# VIA Nano	91	-	52	33	14.7
++# Atom		126	-	68	48(***)	14.7
++# Silvermont	97	-	58	42(***)	17.5
++# Goldmont	80	-	48	19.5	12.0
++#
++# (*)	whichever best applicable.
++# (**)	x86_64 assembler performance is presented for reference
++#	purposes, the results are for integer-only code.
++# (***)	paddq is increadibly slow on Atom.
++#
++# IALU code-path is optimized for elder Pentiums. On vanilla Pentium
++# performance improvement over compiler generated code reaches ~60%,
++# while on PIII - ~35%. On newer µ-archs improvement varies from 15%
++# to 50%, but it's less important as they are expected to execute SSE2
++# code-path, which is commonly ~2-3x faster [than compiler generated
++# code]. SSE2 code-path is as fast as original sha512-sse2.pl, even
++# though it does not use 128-bit operations. The latter means that
++# SSE2-aware kernel is no longer required to execute the code. Another
++# difference is that new code optimizes amount of writes, but at the
++# cost of increased data cache "footprint" by 1/2KB.
++
++$0 =~ m/(.*[\/\\])[^\/\\]+$/; $dir=$1;
++push(@INC,"${dir}","${dir}../../perlasm");
++require "x86asm.pl";
++
++$output=pop;
++open STDOUT,">$output";
++
++&asm_init($ARGV[0],"sha512-586.pl",$ARGV[$#ARGV] eq "386");
++
++$sse2=0;
++for (@ARGV) { $sse2=1 if (/-DOPENSSL_IA32_SSE2/); }
++
++&external_label("OPENSSL_ia32cap_P") if ($sse2);
++
++$Tlo=&DWP(0,"esp");	$Thi=&DWP(4,"esp");
++$Alo=&DWP(8,"esp");	$Ahi=&DWP(8+4,"esp");
++$Blo=&DWP(16,"esp");	$Bhi=&DWP(16+4,"esp");
++$Clo=&DWP(24,"esp");	$Chi=&DWP(24+4,"esp");
++$Dlo=&DWP(32,"esp");	$Dhi=&DWP(32+4,"esp");
++$Elo=&DWP(40,"esp");	$Ehi=&DWP(40+4,"esp");
++$Flo=&DWP(48,"esp");	$Fhi=&DWP(48+4,"esp");
++$Glo=&DWP(56,"esp");	$Ghi=&DWP(56+4,"esp");
++$Hlo=&DWP(64,"esp");	$Hhi=&DWP(64+4,"esp");
++$K512="ebp";
++
++$Asse2=&QWP(0,"esp");
++$Bsse2=&QWP(8,"esp");
++$Csse2=&QWP(16,"esp");
++$Dsse2=&QWP(24,"esp");
++$Esse2=&QWP(32,"esp");
++$Fsse2=&QWP(40,"esp");
++$Gsse2=&QWP(48,"esp");
++$Hsse2=&QWP(56,"esp");
++
++$A="mm0";	# B-D and
++$E="mm4";	# F-H are commonly loaded to respectively mm1-mm3 and
++		# mm5-mm7, but it's done on on-demand basis...
++$BxC="mm2";	# ... except for B^C
++
++sub BODY_00_15_sse2 {
++    my $phase=shift;
++
++	#&movq	("mm5",$Fsse2);			# load f
++	#&movq	("mm6",$Gsse2);			# load g
++
++	&movq	("mm1",$E);			# %mm1 is sliding right
++	 &pxor	("mm5","mm6");			# f^=g
++	&psrlq	("mm1",14);
++	 &movq	($Esse2,$E);			# modulo-scheduled save e
++	 &pand	("mm5",$E);			# f&=e
++	&psllq	($E,23);			# $E is sliding left
++	 &movq	($A,"mm3")			if ($phase<2);
++	 &movq	(&QWP(8*9,"esp"),"mm7")		# save X[i]
++	&movq	("mm3","mm1");			# %mm3 is T1
++	 &psrlq	("mm1",4);
++	 &pxor	("mm5","mm6");			# Ch(e,f,g)
++	&pxor	("mm3",$E);
++	 &psllq	($E,23);
++	&pxor	("mm3","mm1");
++	 &movq	($Asse2,$A);			# modulo-scheduled save a
++	 &paddq	("mm7","mm5");			# X[i]+=Ch(e,f,g)
++	&pxor	("mm3",$E);
++	 &psrlq	("mm1",23);
++	 &paddq	("mm7",$Hsse2);			# X[i]+=h
++	&pxor	("mm3","mm1");
++	 &psllq	($E,4);
++	 &paddq	("mm7",QWP(0,$K512));		# X[i]+=K512[i]
++	&pxor	("mm3",$E);			# T1=Sigma1_512(e)
++
++	 &movq	($E,$Dsse2);			# e = load d, e in next round
++	&paddq	("mm3","mm7");			# T1+=X[i]
++	 &movq	("mm5",$A);			# %mm5 is sliding right
++	 &psrlq	("mm5",28);
++	&paddq	($E,"mm3");			# d += T1
++	 &movq	("mm6",$A);			# %mm6 is sliding left
++	 &movq	("mm7","mm5");
++	 &psllq	("mm6",25);
++	&movq	("mm1",$Bsse2);			# load b
++	 &psrlq	("mm5",6);
++	 &pxor	("mm7","mm6");
++	&sub	("esp",8);
++	 &psllq	("mm6",5);
++	 &pxor	("mm7","mm5");
++	&pxor	($A,"mm1");			# a^b, b^c in next round
++	 &psrlq	("mm5",5);
++	 &pxor	("mm7","mm6");
++	&pand	($BxC,$A);			# (b^c)&(a^b)
++	 &psllq	("mm6",6);
++	 &pxor	("mm7","mm5");
++	&pxor	($BxC,"mm1");			# [h=]Maj(a,b,c)
++	 &pxor	("mm6","mm7");			# Sigma0_512(a)
++	 &movq	("mm7",&QWP(8*(9+16-1),"esp"))	if ($phase!=0);	# pre-fetch
++	 &movq	("mm5",$Fsse2)			if ($phase==0);	# load f
++
++    if ($phase>1) {
++	&paddq	($BxC,"mm6");			# h+=Sigma0(a)
++	 &add	($K512,8);
++	#&paddq	($BxC,"mm3");			# h+=T1
++
++	($A,$BxC) = ($BxC,$A);			# rotate registers
++    } else {
++	&paddq	("mm3",$BxC);			# T1+=Maj(a,b,c)
++	 &movq	($BxC,$A);
++	 &add	($K512,8);
++	&paddq	("mm3","mm6");			# T1+=Sigma0(a)
++	 &movq	("mm6",$Gsse2)			if ($phase==0);	# load g
++	#&movq	($A,"mm3");			# h=T1
++    }
++}
++
++sub BODY_00_15_x86 {
++	#define Sigma1(x)	(ROTR((x),14) ^ ROTR((x),18)  ^ ROTR((x),41))
++	#	LO		lo>>14^hi<<18 ^ lo>>18^hi<<14 ^ hi>>9^lo<<23
++	#	HI		hi>>14^lo<<18 ^ hi>>18^lo<<14 ^ lo>>9^hi<<23
++	&mov	("ecx",$Elo);
++	&mov	("edx",$Ehi);
++	&mov	("esi","ecx");
++
++	&shr	("ecx",9);	# lo>>9
++	&mov	("edi","edx");
++	&shr	("edx",9);	# hi>>9
++	&mov	("ebx","ecx");
++	&shl	("esi",14);	# lo<<14
++	&mov	("eax","edx");
++	&shl	("edi",14);	# hi<<14
++	&xor	("ebx","esi");
++
++	&shr	("ecx",14-9);	# lo>>14
++	&xor	("eax","edi");
++	&shr	("edx",14-9);	# hi>>14
++	&xor	("eax","ecx");
++	&shl	("esi",18-14);	# lo<<18
++	&xor	("ebx","edx");
++	&shl	("edi",18-14);	# hi<<18
++	&xor	("ebx","esi");
++
++	&shr	("ecx",18-14);	# lo>>18
++	&xor	("eax","edi");
++	&shr	("edx",18-14);	# hi>>18
++	&xor	("eax","ecx");
++	&shl	("esi",23-18);	# lo<<23
++	&xor	("ebx","edx");
++	&shl	("edi",23-18);	# hi<<23
++	&xor	("eax","esi");
++	&xor	("ebx","edi");			# T1 = Sigma1(e)
++
++	&mov	("ecx",$Flo);
++	&mov	("edx",$Fhi);
++	&mov	("esi",$Glo);
++	&mov	("edi",$Ghi);
++	 &add	("eax",$Hlo);
++	 &adc	("ebx",$Hhi);			# T1 += h
++	&xor	("ecx","esi");
++	&xor	("edx","edi");
++	&and	("ecx",$Elo);
++	&and	("edx",$Ehi);
++	 &add	("eax",&DWP(8*(9+15)+0,"esp"));
++	 &adc	("ebx",&DWP(8*(9+15)+4,"esp"));	# T1 += X[0]
++	&xor	("ecx","esi");
++	&xor	("edx","edi");			# Ch(e,f,g) = (f^g)&e)^g
++
++	&mov	("esi",&DWP(0,$K512));
++	&mov	("edi",&DWP(4,$K512));		# K[i]
++	&add	("eax","ecx");
++	&adc	("ebx","edx");			# T1 += Ch(e,f,g)
++	&mov	("ecx",$Dlo);
++	&mov	("edx",$Dhi);
++	&add	("eax","esi");
++	&adc	("ebx","edi");			# T1 += K[i]
++	&mov	($Tlo,"eax");
++	&mov	($Thi,"ebx");			# put T1 away
++	&add	("eax","ecx");
++	&adc	("ebx","edx");			# d += T1
++
++	#define Sigma0(x)	(ROTR((x),28) ^ ROTR((x),34) ^ ROTR((x),39))
++	#	LO		lo>>28^hi<<4  ^ hi>>2^lo<<30 ^ hi>>7^lo<<25
++	#	HI		hi>>28^lo<<4  ^ lo>>2^hi<<30 ^ lo>>7^hi<<25
++	&mov	("ecx",$Alo);
++	&mov	("edx",$Ahi);
++	&mov	($Dlo,"eax");
++	&mov	($Dhi,"ebx");
++	&mov	("esi","ecx");
++
++	&shr	("ecx",2);	# lo>>2
++	&mov	("edi","edx");
++	&shr	("edx",2);	# hi>>2
++	&mov	("ebx","ecx");
++	&shl	("esi",4);	# lo<<4
++	&mov	("eax","edx");
++	&shl	("edi",4);	# hi<<4
++	&xor	("ebx","esi");
++
++	&shr	("ecx",7-2);	# lo>>7
++	&xor	("eax","edi");
++	&shr	("edx",7-2);	# hi>>7
++	&xor	("ebx","ecx");
++	&shl	("esi",25-4);	# lo<<25
++	&xor	("eax","edx");
++	&shl	("edi",25-4);	# hi<<25
++	&xor	("eax","esi");
++
++	&shr	("ecx",28-7);	# lo>>28
++	&xor	("ebx","edi");
++	&shr	("edx",28-7);	# hi>>28
++	&xor	("eax","ecx");
++	&shl	("esi",30-25);	# lo<<30
++	&xor	("ebx","edx");
++	&shl	("edi",30-25);	# hi<<30
++	&xor	("eax","esi");
++	&xor	("ebx","edi");			# Sigma0(a)
++
++	&mov	("ecx",$Alo);
++	&mov	("edx",$Ahi);
++	&mov	("esi",$Blo);
++	&mov	("edi",$Bhi);
++	&add	("eax",$Tlo);
++	&adc	("ebx",$Thi);			# T1 = Sigma0(a)+T1
++	&or	("ecx","esi");
++	&or	("edx","edi");
++	&and	("ecx",$Clo);
++	&and	("edx",$Chi);
++	&and	("esi",$Alo);
++	&and	("edi",$Ahi);
++	&or	("ecx","esi");
++	&or	("edx","edi");			# Maj(a,b,c) = ((a|b)&c)|(a&b)
++
++	&add	("eax","ecx");
++	&adc	("ebx","edx");			# T1 += Maj(a,b,c)
++	&mov	($Tlo,"eax");
++	&mov	($Thi,"ebx");
++
++	&mov	(&LB("edx"),&BP(0,$K512));	# pre-fetch LSB of *K
++	&sub	("esp",8);
++	&lea	($K512,&DWP(8,$K512));		# K++
++}
++
++
++&function_begin("sha512_block_data_order");
++	&mov	("esi",wparam(0));	# ctx
++	&mov	("edi",wparam(1));	# inp
++	&mov	("eax",wparam(2));	# num
++	&mov	("ebx","esp");		# saved sp
++
++	&call	(&label("pic_point"));	# make it PIC!
++&set_label("pic_point");
++	&blindpop($K512);
++	&lea	($K512,&DWP(&label("K512")."-".&label("pic_point"),$K512));
++
++	&sub	("esp",16);
++	&and	("esp",-64);
++
++	&shl	("eax",7);
++	&add	("eax","edi");
++	&mov	(&DWP(0,"esp"),"esi");	# ctx
++	&mov	(&DWP(4,"esp"),"edi");	# inp
++	&mov	(&DWP(8,"esp"),"eax");	# inp+num*128
++	&mov	(&DWP(12,"esp"),"ebx");	# saved sp
++
++if ($sse2) {
++	&picmeup("edx","OPENSSL_ia32cap_P",$K512,&label("K512"));
++	&mov	("ecx",&DWP(0,"edx"));
++	&test	("ecx",1<<26);
++	&jz	(&label("loop_x86"));
++
++	&mov	("edx",&DWP(4,"edx"));
++
++	# load ctx->h[0-7]
++	&movq	($A,&QWP(0,"esi"));
++	 &and	("ecx",1<<24);		# XMM registers availability
++	&movq	("mm1",&QWP(8,"esi"));
++	 &and	("edx",1<<9);		# SSSE3 bit
++	&movq	($BxC,&QWP(16,"esi"));
++	 &or	("ecx","edx");
++	&movq	("mm3",&QWP(24,"esi"));
++	&movq	($E,&QWP(32,"esi"));
++	&movq	("mm5",&QWP(40,"esi"));
++	&movq	("mm6",&QWP(48,"esi"));
++	&movq	("mm7",&QWP(56,"esi"));
++	&cmp	("ecx",1<<24|1<<9);
++	&je	(&label("SSSE3"));
++	&sub	("esp",8*10);
++	&jmp	(&label("loop_sse2"));
++
++&set_label("loop_sse2",16);
++	#&movq	($Asse2,$A);
++	&movq	($Bsse2,"mm1");
++	&movq	($Csse2,$BxC);
++	&movq	($Dsse2,"mm3");
++	#&movq	($Esse2,$E);
++	&movq	($Fsse2,"mm5");
++	&movq	($Gsse2,"mm6");
++	&pxor	($BxC,"mm1");			# magic
++	&movq	($Hsse2,"mm7");
++	&movq	("mm3",$A);			# magic
++
++	&mov	("eax",&DWP(0,"edi"));
++	&mov	("ebx",&DWP(4,"edi"));
++	&add	("edi",8);
++	&mov	("edx",15);			# counter
++	&bswap	("eax");
++	&bswap	("ebx");
++	&jmp	(&label("00_14_sse2"));
++
++&set_label("00_14_sse2",16);
++	&movd	("mm1","eax");
++	&mov	("eax",&DWP(0,"edi"));
++	&movd	("mm7","ebx");
++	&mov	("ebx",&DWP(4,"edi"));
++	&add	("edi",8);
++	&bswap	("eax");
++	&bswap	("ebx");
++	&punpckldq("mm7","mm1");
++
++	&BODY_00_15_sse2();
++
++	&dec	("edx");
++	&jnz	(&label("00_14_sse2"));
++
++	&movd	("mm1","eax");
++	&movd	("mm7","ebx");
++	&punpckldq("mm7","mm1");
++
++	&BODY_00_15_sse2(1);
++
++	&pxor	($A,$A);			# A is in %mm3
++	&mov	("edx",32);			# counter
++	&jmp	(&label("16_79_sse2"));
++
++&set_label("16_79_sse2",16);
++    for ($j=0;$j<2;$j++) {			# 2x unroll
++	#&movq	("mm7",&QWP(8*(9+16-1),"esp"));	# prefetched in BODY_00_15 
++	&movq	("mm5",&QWP(8*(9+16-14),"esp"));
++	&movq	("mm1","mm7");
++	&psrlq	("mm7",1);
++	 &movq	("mm6","mm5");
++	 &psrlq	("mm5",6);
++	&psllq	("mm1",56);
++	 &paddq	($A,"mm3");			# from BODY_00_15
++	 &movq	("mm3","mm7");
++	&psrlq	("mm7",7-1);
++	 &pxor	("mm3","mm1");
++	 &psllq	("mm1",63-56);
++	&pxor	("mm3","mm7");
++	 &psrlq	("mm7",8-7);
++	&pxor	("mm3","mm1");
++	 &movq	("mm1","mm5");
++	 &psrlq	("mm5",19-6);
++	&pxor	("mm7","mm3");			# sigma0
++
++	 &psllq	("mm6",3);
++	 &pxor	("mm1","mm5");
++	&paddq	("mm7",&QWP(8*(9+16),"esp"));
++	 &pxor	("mm1","mm6");
++	 &psrlq	("mm5",61-19);
++	&paddq	("mm7",&QWP(8*(9+16-9),"esp"));
++	 &pxor	("mm1","mm5");
++	 &psllq	("mm6",45-3);
++	&movq	("mm5",$Fsse2);			# load f
++	 &pxor	("mm1","mm6");			# sigma1
++	&movq	("mm6",$Gsse2);			# load g
++
++	&paddq	("mm7","mm1");			# X[i]
++	#&movq	(&QWP(8*9,"esp"),"mm7");	# moved to BODY_00_15
++
++	&BODY_00_15_sse2(2);
++    }
++	&dec	("edx");
++	&jnz	(&label("16_79_sse2"));
++
++	#&movq	($A,$Asse2);
++	&paddq	($A,"mm3");			# from BODY_00_15
++	&movq	("mm1",$Bsse2);
++	#&movq	($BxC,$Csse2);
++	&movq	("mm3",$Dsse2);
++	#&movq	($E,$Esse2);
++	&movq	("mm5",$Fsse2);
++	&movq	("mm6",$Gsse2);
++	&movq	("mm7",$Hsse2);
++
++	&pxor	($BxC,"mm1");			# de-magic
++	&paddq	($A,&QWP(0,"esi"));
++	&paddq	("mm1",&QWP(8,"esi"));
++	&paddq	($BxC,&QWP(16,"esi"));
++	&paddq	("mm3",&QWP(24,"esi"));
++	&paddq	($E,&QWP(32,"esi"));
++	&paddq	("mm5",&QWP(40,"esi"));
++	&paddq	("mm6",&QWP(48,"esi"));
++	&paddq	("mm7",&QWP(56,"esi"));
++
++	&mov	("eax",8*80);
++	&movq	(&QWP(0,"esi"),$A);
++	&movq	(&QWP(8,"esi"),"mm1");
++	&movq	(&QWP(16,"esi"),$BxC);
++	&movq	(&QWP(24,"esi"),"mm3");
++	&movq	(&QWP(32,"esi"),$E);
++	&movq	(&QWP(40,"esi"),"mm5");
++	&movq	(&QWP(48,"esi"),"mm6");
++	&movq	(&QWP(56,"esi"),"mm7");
++
++	&lea	("esp",&DWP(0,"esp","eax"));	# destroy frame
++	&sub	($K512,"eax");			# rewind K
++
++	&cmp	("edi",&DWP(8*10+8,"esp"));	# are we done yet?
++	&jb	(&label("loop_sse2"));
++
++	&mov	("esp",&DWP(8*10+12,"esp"));	# restore sp
++	&emms	();
++&function_end_A();
++
++&set_label("SSSE3",32);
++{ my ($cnt,$frame)=("ecx","edx");
++  my @X=map("xmm$_",(0..7));
++  my $j;
++  my $i=0;
++
++	&lea	($frame,&DWP(-64,"esp"));
++	&sub	("esp",256);
++
++	# fixed stack frame layout
++	#
++	# +0	A B C D E F G H		# backing store
++	# +64	X[0]+K[i] .. X[15]+K[i]	# XMM->MM xfer area
++	# +192				# XMM off-load ring buffer
++	# +256				# saved parameters
++
++	&movdqa		(@X[1],&QWP(80*8,$K512));		# byte swap mask
++	&movdqu		(@X[0],&QWP(0,"edi"));
++	&pshufb		(@X[0],@X[1]);
++    for ($j=0;$j<8;$j++) {
++	&movdqa		(&QWP(16*(($j-1)%4),$frame),@X[3])	if ($j>4); # off-load
++	&movdqa		(@X[3],&QWP(16*($j%8),$K512));
++	&movdqa		(@X[2],@X[1])				if ($j<7); # perpetuate byte swap mask
++	&movdqu		(@X[1],&QWP(16*($j+1),"edi"))		if ($j<7); # next input
++	&movdqa		(@X[1],&QWP(16*(($j+1)%4),$frame))	if ($j==7);# restore @X[0]
++	&paddq		(@X[3],@X[0]);
++	&pshufb		(@X[1],@X[2])				if ($j<7);
++	&movdqa		(&QWP(16*($j%8)-128,$frame),@X[3]);	# xfer X[i]+K[i]
++
++	push(@X,shift(@X));					# rotate(@X)
++    }
++	#&jmp		(&label("loop_ssse3"));
++	&nop		();
++
++&set_label("loop_ssse3",32);
++	&movdqa		(@X[2],&QWP(16*(($j+1)%4),$frame));	# pre-restore @X[1]
++	&movdqa		(&QWP(16*(($j-1)%4),$frame),@X[3]);	# off-load @X[3]
++	&lea		($K512,&DWP(16*8,$K512));
++
++	#&movq	($Asse2,$A);			# off-load A-H
++	&movq	($Bsse2,"mm1");
++	 &mov	("ebx","edi");
++	&movq	($Csse2,$BxC);
++	 &lea	("edi",&DWP(128,"edi"));	# advance input
++	&movq	($Dsse2,"mm3");
++	 &cmp	("edi","eax");
++	#&movq	($Esse2,$E);
++	&movq	($Fsse2,"mm5");
++	 &cmovb	("ebx","edi");
++	&movq	($Gsse2,"mm6");
++	 &mov	("ecx",4);			# loop counter
++	&pxor	($BxC,"mm1");			# magic
++	&movq	($Hsse2,"mm7");
++	&pxor	("mm3","mm3");			# magic
++
++	&jmp		(&label("00_47_ssse3"));
++
++sub BODY_00_15_ssse3 {		# "phase-less" copy of BODY_00_15_sse2
++	(
++	'&movq	("mm1",$E)',				# %mm1 is sliding right
++	'&movq	("mm7",&QWP(((-8*$i)%128)-128,$frame))',# X[i]+K[i]
++	 '&pxor	("mm5","mm6")',				# f^=g
++	'&psrlq	("mm1",14)',
++	 '&movq	(&QWP(8*($i+4)%64,"esp"),$E)',		# modulo-scheduled save e
++	 '&pand	("mm5",$E)',				# f&=e
++	'&psllq	($E,23)',				# $E is sliding left
++	'&paddq	($A,"mm3")',				# [h+=Maj(a,b,c)]
++	'&movq	("mm3","mm1")',				# %mm3 is T1
++	 '&psrlq("mm1",4)',
++	 '&pxor	("mm5","mm6")',				# Ch(e,f,g)
++	'&pxor	("mm3",$E)',
++	 '&psllq($E,23)',
++	'&pxor	("mm3","mm1")',
++	 '&movq	(&QWP(8*$i%64,"esp"),$A)',		# modulo-scheduled save a
++	 '&paddq("mm7","mm5")',				# X[i]+=Ch(e,f,g)
++	'&pxor	("mm3",$E)',
++	 '&psrlq("mm1",23)',
++	 '&paddq("mm7",&QWP(8*($i+7)%64,"esp"))',	# X[i]+=h
++	'&pxor	("mm3","mm1")',
++	 '&psllq($E,4)',
++	'&pxor	("mm3",$E)',				# T1=Sigma1_512(e)
++
++	 '&movq	($E,&QWP(8*($i+3)%64,"esp"))',		# e = load d, e in next round
++	'&paddq	("mm3","mm7")',				# T1+=X[i]
++	 '&movq	("mm5",$A)',				# %mm5 is sliding right
++	 '&psrlq("mm5",28)',
++	'&paddq	($E,"mm3")',				# d += T1
++	 '&movq	("mm6",$A)',				# %mm6 is sliding left
++	 '&movq	("mm7","mm5")',
++	 '&psllq("mm6",25)',
++	'&movq	("mm1",&QWP(8*($i+1)%64,"esp"))',	# load b
++	 '&psrlq("mm5",6)',
++	 '&pxor	("mm7","mm6")',
++	 '&psllq("mm6",5)',
++	 '&pxor	("mm7","mm5")',
++	'&pxor	($A,"mm1")',				# a^b, b^c in next round
++	 '&psrlq("mm5",5)',
++	 '&pxor	("mm7","mm6")',
++	'&pand	($BxC,$A)',				# (b^c)&(a^b)
++	 '&psllq("mm6",6)',
++	 '&pxor	("mm7","mm5")',
++	'&pxor	($BxC,"mm1")',				# [h=]Maj(a,b,c)
++	 '&pxor	("mm6","mm7")',				# Sigma0_512(a)
++	 '&movq	("mm5",&QWP(8*($i+5-1)%64,"esp"))',	# pre-load f
++	'&paddq	($BxC,"mm6")',				# h+=Sigma0(a)
++	 '&movq	("mm6",&QWP(8*($i+6-1)%64,"esp"))',	# pre-load g
++
++	'($A,$BxC) = ($BxC,$A); $i--;'
++	);
++}
++
++&set_label("00_47_ssse3",32);
++
++    for(;$j<16;$j++) {
++	my ($t0,$t2,$t1)=@X[2..4];
++	my @insns = (&BODY_00_15_ssse3(),&BODY_00_15_ssse3());
++
++	&movdqa		($t2,@X[5]);
++	&movdqa		(@X[1],$t0);			# restore @X[1]
++	&palignr	($t0,@X[0],8);			# X[1..2]
++	&movdqa		(&QWP(16*($j%4),$frame),@X[4]);	# off-load @X[4]
++	 &palignr	($t2,@X[4],8);			# X[9..10]
++
++	&movdqa		($t1,$t0);
++	&psrlq		($t0,7);
++	 &paddq		(@X[0],$t2);			# X[0..1] += X[9..10]
++	&movdqa		($t2,$t1);
++	&psrlq		($t1,1);
++	&psllq		($t2,64-8);
++	&pxor		($t0,$t1);
++	&psrlq		($t1,8-1);
++	&pxor		($t0,$t2);
++	&psllq		($t2,8-1);
++	&pxor		($t0,$t1);
++	 &movdqa	($t1,@X[7]);
++	&pxor		($t0,$t2);			# sigma0(X[1..2])
++	 &movdqa	($t2,@X[7]);
++	 &psrlq		($t1,6);
++	&paddq		(@X[0],$t0);			# X[0..1] += sigma0(X[1..2])
++
++	&movdqa		($t0,@X[7]);
++	&psrlq		($t2,19);
++	&psllq		($t0,64-61);
++	&pxor		($t1,$t2);
++	&psrlq		($t2,61-19);
++	&pxor		($t1,$t0);
++	&psllq		($t0,61-19);
++	&pxor		($t1,$t2);
++	&movdqa		($t2,&QWP(16*(($j+2)%4),$frame));# pre-restore @X[1]
++	&pxor		($t1,$t0);			# sigma0(X[1..2])
++	&movdqa		($t0,&QWP(16*($j%8),$K512));
++	 eval(shift(@insns));
++	&paddq		(@X[0],$t1);			# X[0..1] += sigma0(X[14..15])
++	 eval(shift(@insns));
++	 eval(shift(@insns));
++	 eval(shift(@insns));
++	 eval(shift(@insns));
++	&paddq		($t0,@X[0]);
++	 foreach(@insns) { eval; }
++	&movdqa		(&QWP(16*($j%8)-128,$frame),$t0);# xfer X[i]+K[i]
++
++	push(@X,shift(@X));				# rotate(@X)
++    }
++	&lea		($K512,&DWP(16*8,$K512));
++	&dec		("ecx");
++	&jnz		(&label("00_47_ssse3"));
++
++	&movdqa		(@X[1],&QWP(0,$K512));		# byte swap mask
++	&lea		($K512,&DWP(-80*8,$K512));	# rewind
++	&movdqu		(@X[0],&QWP(0,"ebx"));
++	&pshufb		(@X[0],@X[1]);
++
++    for ($j=0;$j<8;$j++) {	# load next or same block
++	my @insns = (&BODY_00_15_ssse3(),&BODY_00_15_ssse3());
++
++	&movdqa		(&QWP(16*(($j-1)%4),$frame),@X[3])	if ($j>4); # off-load
++	&movdqa		(@X[3],&QWP(16*($j%8),$K512));
++	&movdqa		(@X[2],@X[1])				if ($j<7); # perpetuate byte swap mask
++	&movdqu		(@X[1],&QWP(16*($j+1),"ebx"))		if ($j<7); # next input
++	&movdqa		(@X[1],&QWP(16*(($j+1)%4),$frame))	if ($j==7);# restore @X[0]
++	&paddq		(@X[3],@X[0]);
++	&pshufb		(@X[1],@X[2])				if ($j<7);
++	 foreach(@insns) { eval; }
++	&movdqa		(&QWP(16*($j%8)-128,$frame),@X[3]);# xfer X[i]+K[i]
++
++	push(@X,shift(@X));				# rotate(@X)
++    }
++
++	#&movq	($A,$Asse2);			# load A-H
++	&movq	("mm1",$Bsse2);
++	&paddq	($A,"mm3");			# from BODY_00_15
++	#&movq	($BxC,$Csse2);
++	&movq	("mm3",$Dsse2);
++	#&movq	($E,$Esse2);
++	#&movq	("mm5",$Fsse2);
++	#&movq	("mm6",$Gsse2);
++	&movq	("mm7",$Hsse2);
++
++	&pxor	($BxC,"mm1");			# de-magic
++	&paddq	($A,&QWP(0,"esi"));
++	&paddq	("mm1",&QWP(8,"esi"));
++	&paddq	($BxC,&QWP(16,"esi"));
++	&paddq	("mm3",&QWP(24,"esi"));
++	&paddq	($E,&QWP(32,"esi"));
++	&paddq	("mm5",&QWP(40,"esi"));
++	&paddq	("mm6",&QWP(48,"esi"));
++	&paddq	("mm7",&QWP(56,"esi"));
++
++	&movq	(&QWP(0,"esi"),$A);
++	&movq	(&QWP(8,"esi"),"mm1");
++	&movq	(&QWP(16,"esi"),$BxC);
++	&movq	(&QWP(24,"esi"),"mm3");
++	&movq	(&QWP(32,"esi"),$E);
++	&movq	(&QWP(40,"esi"),"mm5");
++	&movq	(&QWP(48,"esi"),"mm6");
++	&movq	(&QWP(56,"esi"),"mm7");
++
++    	&cmp	("edi","eax")			# are we done yet?
++	&jb	(&label("loop_ssse3"));
++
++	&mov	("esp",&DWP(64+12,$frame));	# restore sp
++	&emms	();
++}
++&function_end_A();
++}
++&set_label("loop_x86",16);
++    # copy input block to stack reversing byte and qword order
++    for ($i=0;$i<8;$i++) {
++	&mov	("eax",&DWP($i*16+0,"edi"));
++	&mov	("ebx",&DWP($i*16+4,"edi"));
++	&mov	("ecx",&DWP($i*16+8,"edi"));
++	&mov	("edx",&DWP($i*16+12,"edi"));
++	&bswap	("eax");
++	&bswap	("ebx");
++	&bswap	("ecx");
++	&bswap	("edx");
++	&push	("eax");
++	&push	("ebx");
++	&push	("ecx");
++	&push	("edx");
++    }
++	&add	("edi",128);
++	&sub	("esp",9*8);		# place for T,A,B,C,D,E,F,G,H
++	&mov	(&DWP(8*(9+16)+4,"esp"),"edi");
++
++	# copy ctx->h[0-7] to A,B,C,D,E,F,G,H on stack
++	&lea	("edi",&DWP(8,"esp"));
++	&mov	("ecx",16);
++	&data_word(0xA5F3F689);		# rep movsd
++
++&set_label("00_15_x86",16);
++	&BODY_00_15_x86();
++
++	&cmp	(&LB("edx"),0x94);
++	&jne	(&label("00_15_x86"));
++
++&set_label("16_79_x86",16);
++	#define sigma0(x)	(ROTR((x),1)  ^ ROTR((x),8)  ^ ((x)>>7))
++	#	LO		lo>>1^hi<<31  ^ lo>>8^hi<<24 ^ lo>>7^hi<<25
++	#	HI		hi>>1^lo<<31  ^ hi>>8^lo<<24 ^ hi>>7
++	&mov	("ecx",&DWP(8*(9+15+16-1)+0,"esp"));
++	&mov	("edx",&DWP(8*(9+15+16-1)+4,"esp"));
++	&mov	("esi","ecx");
++
++	&shr	("ecx",1);	# lo>>1
++	&mov	("edi","edx");
++	&shr	("edx",1);	# hi>>1
++	&mov	("eax","ecx");
++	&shl	("esi",24);	# lo<<24
++	&mov	("ebx","edx");
++	&shl	("edi",24);	# hi<<24
++	&xor	("ebx","esi");
++
++	&shr	("ecx",7-1);	# lo>>7
++	&xor	("eax","edi");
++	&shr	("edx",7-1);	# hi>>7
++	&xor	("eax","ecx");
++	&shl	("esi",31-24);	# lo<<31
++	&xor	("ebx","edx");
++	&shl	("edi",25-24);	# hi<<25
++	&xor	("ebx","esi");
++
++	&shr	("ecx",8-7);	# lo>>8
++	&xor	("eax","edi");
++	&shr	("edx",8-7);	# hi>>8
++	&xor	("eax","ecx");
++	&shl	("edi",31-25);	# hi<<31
++	&xor	("ebx","edx");
++	&xor	("eax","edi");			# T1 = sigma0(X[-15])
++
++	&mov	(&DWP(0,"esp"),"eax");
++	&mov	(&DWP(4,"esp"),"ebx");		# put T1 away
++
++	#define sigma1(x)	(ROTR((x),19) ^ ROTR((x),61) ^ ((x)>>6))
++	#	LO		lo>>19^hi<<13 ^ hi>>29^lo<<3 ^ lo>>6^hi<<26
++	#	HI		hi>>19^lo<<13 ^ lo>>29^hi<<3 ^ hi>>6
++	&mov	("ecx",&DWP(8*(9+15+16-14)+0,"esp"));
++	&mov	("edx",&DWP(8*(9+15+16-14)+4,"esp"));
++	&mov	("esi","ecx");
++
++	&shr	("ecx",6);	# lo>>6
++	&mov	("edi","edx");
++	&shr	("edx",6);	# hi>>6
++	&mov	("eax","ecx");
++	&shl	("esi",3);	# lo<<3
++	&mov	("ebx","edx");
++	&shl	("edi",3);	# hi<<3
++	&xor	("eax","esi");
++
++	&shr	("ecx",19-6);	# lo>>19
++	&xor	("ebx","edi");
++	&shr	("edx",19-6);	# hi>>19
++	&xor	("eax","ecx");
++	&shl	("esi",13-3);	# lo<<13
++	&xor	("ebx","edx");
++	&shl	("edi",13-3);	# hi<<13
++	&xor	("ebx","esi");
++
++	&shr	("ecx",29-19);	# lo>>29
++	&xor	("eax","edi");
++	&shr	("edx",29-19);	# hi>>29
++	&xor	("ebx","ecx");
++	&shl	("edi",26-13);	# hi<<26
++	&xor	("eax","edx");
++	&xor	("eax","edi");			# sigma1(X[-2])
++
++	&mov	("ecx",&DWP(8*(9+15+16)+0,"esp"));
++	&mov	("edx",&DWP(8*(9+15+16)+4,"esp"));
++	&add	("eax",&DWP(0,"esp"));
++	&adc	("ebx",&DWP(4,"esp"));		# T1 = sigma1(X[-2])+T1
++	&mov	("esi",&DWP(8*(9+15+16-9)+0,"esp"));
++	&mov	("edi",&DWP(8*(9+15+16-9)+4,"esp"));
++	&add	("eax","ecx");
++	&adc	("ebx","edx");			# T1 += X[-16]
++	&add	("eax","esi");
++	&adc	("ebx","edi");			# T1 += X[-7]
++	&mov	(&DWP(8*(9+15)+0,"esp"),"eax");
++	&mov	(&DWP(8*(9+15)+4,"esp"),"ebx");	# save X[0]
++
++	&BODY_00_15_x86();
++
++	&cmp	(&LB("edx"),0x17);
++	&jne	(&label("16_79_x86"));
++
++	&mov	("esi",&DWP(8*(9+16+80)+0,"esp"));# ctx
++	&mov	("edi",&DWP(8*(9+16+80)+4,"esp"));# inp
++    for($i=0;$i<4;$i++) {
++	&mov	("eax",&DWP($i*16+0,"esi"));
++	&mov	("ebx",&DWP($i*16+4,"esi"));
++	&mov	("ecx",&DWP($i*16+8,"esi"));
++	&mov	("edx",&DWP($i*16+12,"esi"));
++	&add	("eax",&DWP(8+($i*16)+0,"esp"));
++	&adc	("ebx",&DWP(8+($i*16)+4,"esp"));
++	&mov	(&DWP($i*16+0,"esi"),"eax");
++	&mov	(&DWP($i*16+4,"esi"),"ebx");
++	&add	("ecx",&DWP(8+($i*16)+8,"esp"));
++	&adc	("edx",&DWP(8+($i*16)+12,"esp"));
++	&mov	(&DWP($i*16+8,"esi"),"ecx");
++	&mov	(&DWP($i*16+12,"esi"),"edx");
++    }
++	&add	("esp",8*(9+16+80));		# destroy frame
++	&sub	($K512,8*80);			# rewind K
++
++	&cmp	("edi",&DWP(8,"esp"));		# are we done yet?
++	&jb	(&label("loop_x86"));
++
++	&mov	("esp",&DWP(12,"esp"));		# restore sp
++&function_end_A();
++
++&set_label("K512",64);	# Yes! I keep it in the code segment!
++	&data_word(0xd728ae22,0x428a2f98);	# u64
++	&data_word(0x23ef65cd,0x71374491);	# u64
++	&data_word(0xec4d3b2f,0xb5c0fbcf);	# u64
++	&data_word(0x8189dbbc,0xe9b5dba5);	# u64
++	&data_word(0xf348b538,0x3956c25b);	# u64
++	&data_word(0xb605d019,0x59f111f1);	# u64
++	&data_word(0xaf194f9b,0x923f82a4);	# u64
++	&data_word(0xda6d8118,0xab1c5ed5);	# u64
++	&data_word(0xa3030242,0xd807aa98);	# u64
++	&data_word(0x45706fbe,0x12835b01);	# u64
++	&data_word(0x4ee4b28c,0x243185be);	# u64
++	&data_word(0xd5ffb4e2,0x550c7dc3);	# u64
++	&data_word(0xf27b896f,0x72be5d74);	# u64
++	&data_word(0x3b1696b1,0x80deb1fe);	# u64
++	&data_word(0x25c71235,0x9bdc06a7);	# u64
++	&data_word(0xcf692694,0xc19bf174);	# u64
++	&data_word(0x9ef14ad2,0xe49b69c1);	# u64
++	&data_word(0x384f25e3,0xefbe4786);	# u64
++	&data_word(0x8b8cd5b5,0x0fc19dc6);	# u64
++	&data_word(0x77ac9c65,0x240ca1cc);	# u64
++	&data_word(0x592b0275,0x2de92c6f);	# u64
++	&data_word(0x6ea6e483,0x4a7484aa);	# u64
++	&data_word(0xbd41fbd4,0x5cb0a9dc);	# u64
++	&data_word(0x831153b5,0x76f988da);	# u64
++	&data_word(0xee66dfab,0x983e5152);	# u64
++	&data_word(0x2db43210,0xa831c66d);	# u64
++	&data_word(0x98fb213f,0xb00327c8);	# u64
++	&data_word(0xbeef0ee4,0xbf597fc7);	# u64
++	&data_word(0x3da88fc2,0xc6e00bf3);	# u64
++	&data_word(0x930aa725,0xd5a79147);	# u64
++	&data_word(0xe003826f,0x06ca6351);	# u64
++	&data_word(0x0a0e6e70,0x14292967);	# u64
++	&data_word(0x46d22ffc,0x27b70a85);	# u64
++	&data_word(0x5c26c926,0x2e1b2138);	# u64
++	&data_word(0x5ac42aed,0x4d2c6dfc);	# u64
++	&data_word(0x9d95b3df,0x53380d13);	# u64
++	&data_word(0x8baf63de,0x650a7354);	# u64
++	&data_word(0x3c77b2a8,0x766a0abb);	# u64
++	&data_word(0x47edaee6,0x81c2c92e);	# u64
++	&data_word(0x1482353b,0x92722c85);	# u64
++	&data_word(0x4cf10364,0xa2bfe8a1);	# u64
++	&data_word(0xbc423001,0xa81a664b);	# u64
++	&data_word(0xd0f89791,0xc24b8b70);	# u64
++	&data_word(0x0654be30,0xc76c51a3);	# u64
++	&data_word(0xd6ef5218,0xd192e819);	# u64
++	&data_word(0x5565a910,0xd6990624);	# u64
++	&data_word(0x5771202a,0xf40e3585);	# u64
++	&data_word(0x32bbd1b8,0x106aa070);	# u64
++	&data_word(0xb8d2d0c8,0x19a4c116);	# u64
++	&data_word(0x5141ab53,0x1e376c08);	# u64
++	&data_word(0xdf8eeb99,0x2748774c);	# u64
++	&data_word(0xe19b48a8,0x34b0bcb5);	# u64
++	&data_word(0xc5c95a63,0x391c0cb3);	# u64
++	&data_word(0xe3418acb,0x4ed8aa4a);	# u64
++	&data_word(0x7763e373,0x5b9cca4f);	# u64
++	&data_word(0xd6b2b8a3,0x682e6ff3);	# u64
++	&data_word(0x5defb2fc,0x748f82ee);	# u64
++	&data_word(0x43172f60,0x78a5636f);	# u64
++	&data_word(0xa1f0ab72,0x84c87814);	# u64
++	&data_word(0x1a6439ec,0x8cc70208);	# u64
++	&data_word(0x23631e28,0x90befffa);	# u64
++	&data_word(0xde82bde9,0xa4506ceb);	# u64
++	&data_word(0xb2c67915,0xbef9a3f7);	# u64
++	&data_word(0xe372532b,0xc67178f2);	# u64
++	&data_word(0xea26619c,0xca273ece);	# u64
++	&data_word(0x21c0c207,0xd186b8c7);	# u64
++	&data_word(0xcde0eb1e,0xeada7dd6);	# u64
++	&data_word(0xee6ed178,0xf57d4f7f);	# u64
++	&data_word(0x72176fba,0x06f067aa);	# u64
++	&data_word(0xa2c898a6,0x0a637dc5);	# u64
++	&data_word(0xbef90dae,0x113f9804);	# u64
++	&data_word(0x131c471b,0x1b710b35);	# u64
++	&data_word(0x23047d84,0x28db77f5);	# u64
++	&data_word(0x40c72493,0x32caab7b);	# u64
++	&data_word(0x15c9bebc,0x3c9ebe0a);	# u64
++	&data_word(0x9c100d4c,0x431d67c4);	# u64
++	&data_word(0xcb3e42b6,0x4cc5d4be);	# u64
++	&data_word(0xfc657e2a,0x597f299c);	# u64
++	&data_word(0x3ad6faec,0x5fcb6fab);	# u64
++	&data_word(0x4a475817,0x6c44198c);	# u64
++
++	&data_word(0x04050607,0x00010203);	# byte swap
++	&data_word(0x0c0d0e0f,0x08090a0b);	# mask
++&function_end_B("sha512_block_data_order");
++&asciz("SHA512 block transform for x86, CRYPTOGAMS by ");
++
++&asm_finish();
++
++close STDOUT;
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/sha/asm/sha512-armv4.pl b/CryptoPkg/Library/OpensslLib/openssl/crypto/sha/asm/sha512-armv4.pl
+new file mode 100644
+index 0000000..22b5a9d
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/sha/asm/sha512-armv4.pl
+@@ -0,0 +1,668 @@
++#! /usr/bin/env perl
++# Copyright 2007-2016 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
++# in the file LICENSE in the source distribution or at
++# https://www.openssl.org/source/license.html
++
++
++# ====================================================================
++# Written by Andy Polyakov  for the OpenSSL
++# project. The module is, however, dual licensed under OpenSSL and
++# CRYPTOGAMS licenses depending on where you obtain it. For further
++# details see http://www.openssl.org/~appro/cryptogams/.
++#
++# Permission to use under GPL terms is granted.
++# ====================================================================
++
++# SHA512 block procedure for ARMv4. September 2007.
++
++# This code is ~4.5 (four and a half) times faster than code generated
++# by gcc 3.4 and it spends ~72 clock cycles per byte [on single-issue
++# Xscale PXA250 core].
++#
++# July 2010.
++#
++# Rescheduling for dual-issue pipeline resulted in 6% improvement on
++# Cortex A8 core and ~40 cycles per processed byte.
++
++# February 2011.
++#
++# Profiler-assisted and platform-specific optimization resulted in 7%
++# improvement on Coxtex A8 core and ~38 cycles per byte.
++
++# March 2011.
++#
++# Add NEON implementation. On Cortex A8 it was measured to process
++# one byte in 23.3 cycles or ~60% faster than integer-only code.
++
++# August 2012.
++#
++# Improve NEON performance by 12% on Snapdragon S4. In absolute
++# terms it's 22.6 cycles per byte, which is disappointing result.
++# Technical writers asserted that 3-way S4 pipeline can sustain
++# multiple NEON instructions per cycle, but dual NEON issue could
++# not be observed, see http://www.openssl.org/~appro/Snapdragon-S4.html
++# for further details. On side note Cortex-A15 processes one byte in
++# 16 cycles.
++
++# Byte order [in]dependence. =========================================
++#
++# Originally caller was expected to maintain specific *dword* order in
++# h[0-7], namely with most significant dword at *lower* address, which
++# was reflected in below two parameters as 0 and 4. Now caller is
++# expected to maintain native byte order for whole 64-bit values.
++$hi="HI";
++$lo="LO";
++# ====================================================================
++
++$flavour = shift;
++if ($flavour=~/\w[\w\-]*\.\w+$/) { $output=$flavour; undef $flavour; }
++else { while (($output=shift) && ($output!~/\w[\w\-]*\.\w+$/)) {} }
++
++if ($flavour && $flavour ne "void") {
++    $0 =~ m/(.*[\/\\])[^\/\\]+$/; $dir=$1;
++    ( $xlate="${dir}arm-xlate.pl" and -f $xlate ) or
++    ( $xlate="${dir}../../perlasm/arm-xlate.pl" and -f $xlate) or
++    die "can't locate arm-xlate.pl";
++
++    open STDOUT,"| \"$^X\" $xlate $flavour $output";
++} else {
++    open STDOUT,">$output";
++}
++
++$ctx="r0";	# parameter block
++$inp="r1";
++$len="r2";
++
++$Tlo="r3";
++$Thi="r4";
++$Alo="r5";
++$Ahi="r6";
++$Elo="r7";
++$Ehi="r8";
++$t0="r9";
++$t1="r10";
++$t2="r11";
++$t3="r12";
++############	r13 is stack pointer
++$Ktbl="r14";
++############	r15 is program counter
++
++$Aoff=8*0;
++$Boff=8*1;
++$Coff=8*2;
++$Doff=8*3;
++$Eoff=8*4;
++$Foff=8*5;
++$Goff=8*6;
++$Hoff=8*7;
++$Xoff=8*8;
++
++sub BODY_00_15() {
++my $magic = shift;
++$code.=<<___;
++	@ Sigma1(x)	(ROTR((x),14) ^ ROTR((x),18)  ^ ROTR((x),41))
++	@ LO		lo>>14^hi<<18 ^ lo>>18^hi<<14 ^ hi>>9^lo<<23
++	@ HI		hi>>14^lo<<18 ^ hi>>18^lo<<14 ^ lo>>9^hi<<23
++	mov	$t0,$Elo,lsr#14
++	str	$Tlo,[sp,#$Xoff+0]
++	mov	$t1,$Ehi,lsr#14
++	str	$Thi,[sp,#$Xoff+4]
++	eor	$t0,$t0,$Ehi,lsl#18
++	ldr	$t2,[sp,#$Hoff+0]	@ h.lo
++	eor	$t1,$t1,$Elo,lsl#18
++	ldr	$t3,[sp,#$Hoff+4]	@ h.hi
++	eor	$t0,$t0,$Elo,lsr#18
++	eor	$t1,$t1,$Ehi,lsr#18
++	eor	$t0,$t0,$Ehi,lsl#14
++	eor	$t1,$t1,$Elo,lsl#14
++	eor	$t0,$t0,$Ehi,lsr#9
++	eor	$t1,$t1,$Elo,lsr#9
++	eor	$t0,$t0,$Elo,lsl#23
++	eor	$t1,$t1,$Ehi,lsl#23	@ Sigma1(e)
++	adds	$Tlo,$Tlo,$t0
++	ldr	$t0,[sp,#$Foff+0]	@ f.lo
++	adc	$Thi,$Thi,$t1		@ T += Sigma1(e)
++	ldr	$t1,[sp,#$Foff+4]	@ f.hi
++	adds	$Tlo,$Tlo,$t2
++	ldr	$t2,[sp,#$Goff+0]	@ g.lo
++	adc	$Thi,$Thi,$t3		@ T += h
++	ldr	$t3,[sp,#$Goff+4]	@ g.hi
++
++	eor	$t0,$t0,$t2
++	str	$Elo,[sp,#$Eoff+0]
++	eor	$t1,$t1,$t3
++	str	$Ehi,[sp,#$Eoff+4]
++	and	$t0,$t0,$Elo
++	str	$Alo,[sp,#$Aoff+0]
++	and	$t1,$t1,$Ehi
++	str	$Ahi,[sp,#$Aoff+4]
++	eor	$t0,$t0,$t2
++	ldr	$t2,[$Ktbl,#$lo]	@ K[i].lo
++	eor	$t1,$t1,$t3		@ Ch(e,f,g)
++	ldr	$t3,[$Ktbl,#$hi]	@ K[i].hi
++
++	adds	$Tlo,$Tlo,$t0
++	ldr	$Elo,[sp,#$Doff+0]	@ d.lo
++	adc	$Thi,$Thi,$t1		@ T += Ch(e,f,g)
++	ldr	$Ehi,[sp,#$Doff+4]	@ d.hi
++	adds	$Tlo,$Tlo,$t2
++	and	$t0,$t2,#0xff
++	adc	$Thi,$Thi,$t3		@ T += K[i]
++	adds	$Elo,$Elo,$Tlo
++	ldr	$t2,[sp,#$Boff+0]	@ b.lo
++	adc	$Ehi,$Ehi,$Thi		@ d += T
++	teq	$t0,#$magic
++
++	ldr	$t3,[sp,#$Coff+0]	@ c.lo
++#if __ARM_ARCH__>=7
++	it	eq			@ Thumb2 thing, sanity check in ARM
++#endif
++	orreq	$Ktbl,$Ktbl,#1
++	@ Sigma0(x)	(ROTR((x),28) ^ ROTR((x),34) ^ ROTR((x),39))
++	@ LO		lo>>28^hi<<4  ^ hi>>2^lo<<30 ^ hi>>7^lo<<25
++	@ HI		hi>>28^lo<<4  ^ lo>>2^hi<<30 ^ lo>>7^hi<<25
++	mov	$t0,$Alo,lsr#28
++	mov	$t1,$Ahi,lsr#28
++	eor	$t0,$t0,$Ahi,lsl#4
++	eor	$t1,$t1,$Alo,lsl#4
++	eor	$t0,$t0,$Ahi,lsr#2
++	eor	$t1,$t1,$Alo,lsr#2
++	eor	$t0,$t0,$Alo,lsl#30
++	eor	$t1,$t1,$Ahi,lsl#30
++	eor	$t0,$t0,$Ahi,lsr#7
++	eor	$t1,$t1,$Alo,lsr#7
++	eor	$t0,$t0,$Alo,lsl#25
++	eor	$t1,$t1,$Ahi,lsl#25	@ Sigma0(a)
++	adds	$Tlo,$Tlo,$t0
++	and	$t0,$Alo,$t2
++	adc	$Thi,$Thi,$t1		@ T += Sigma0(a)
++
++	ldr	$t1,[sp,#$Boff+4]	@ b.hi
++	orr	$Alo,$Alo,$t2
++	ldr	$t2,[sp,#$Coff+4]	@ c.hi
++	and	$Alo,$Alo,$t3
++	and	$t3,$Ahi,$t1
++	orr	$Ahi,$Ahi,$t1
++	orr	$Alo,$Alo,$t0		@ Maj(a,b,c).lo
++	and	$Ahi,$Ahi,$t2
++	adds	$Alo,$Alo,$Tlo
++	orr	$Ahi,$Ahi,$t3		@ Maj(a,b,c).hi
++	sub	sp,sp,#8
++	adc	$Ahi,$Ahi,$Thi		@ h += T
++	tst	$Ktbl,#1
++	add	$Ktbl,$Ktbl,#8
++___
++}
++$code=<<___;
++#ifndef __KERNEL__
++# include "arm_arch.h"
++# define VFP_ABI_PUSH	vstmdb	sp!,{d8-d15}
++# define VFP_ABI_POP	vldmia	sp!,{d8-d15}
++#else
++# define __ARM_ARCH__ __LINUX_ARM_ARCH__
++# define __ARM_MAX_ARCH__ 7
++# define VFP_ABI_PUSH
++# define VFP_ABI_POP
++#endif
++
++#ifdef __ARMEL__
++# define LO 0
++# define HI 4
++# define WORD64(hi0,lo0,hi1,lo1)	.word	lo0,hi0, lo1,hi1
++#else
++# define HI 0
++# define LO 4
++# define WORD64(hi0,lo0,hi1,lo1)	.word	hi0,lo0, hi1,lo1
++#endif
++
++.text
++#if defined(__thumb2__)
++.syntax unified
++.thumb
++# define adrl adr
++#else
++.code	32
++#endif
++
++.type	K512,%object
++.align	5
++K512:
++WORD64(0x428a2f98,0xd728ae22, 0x71374491,0x23ef65cd)
++WORD64(0xb5c0fbcf,0xec4d3b2f, 0xe9b5dba5,0x8189dbbc)
++WORD64(0x3956c25b,0xf348b538, 0x59f111f1,0xb605d019)
++WORD64(0x923f82a4,0xaf194f9b, 0xab1c5ed5,0xda6d8118)
++WORD64(0xd807aa98,0xa3030242, 0x12835b01,0x45706fbe)
++WORD64(0x243185be,0x4ee4b28c, 0x550c7dc3,0xd5ffb4e2)
++WORD64(0x72be5d74,0xf27b896f, 0x80deb1fe,0x3b1696b1)
++WORD64(0x9bdc06a7,0x25c71235, 0xc19bf174,0xcf692694)
++WORD64(0xe49b69c1,0x9ef14ad2, 0xefbe4786,0x384f25e3)
++WORD64(0x0fc19dc6,0x8b8cd5b5, 0x240ca1cc,0x77ac9c65)
++WORD64(0x2de92c6f,0x592b0275, 0x4a7484aa,0x6ea6e483)
++WORD64(0x5cb0a9dc,0xbd41fbd4, 0x76f988da,0x831153b5)
++WORD64(0x983e5152,0xee66dfab, 0xa831c66d,0x2db43210)
++WORD64(0xb00327c8,0x98fb213f, 0xbf597fc7,0xbeef0ee4)
++WORD64(0xc6e00bf3,0x3da88fc2, 0xd5a79147,0x930aa725)
++WORD64(0x06ca6351,0xe003826f, 0x14292967,0x0a0e6e70)
++WORD64(0x27b70a85,0x46d22ffc, 0x2e1b2138,0x5c26c926)
++WORD64(0x4d2c6dfc,0x5ac42aed, 0x53380d13,0x9d95b3df)
++WORD64(0x650a7354,0x8baf63de, 0x766a0abb,0x3c77b2a8)
++WORD64(0x81c2c92e,0x47edaee6, 0x92722c85,0x1482353b)
++WORD64(0xa2bfe8a1,0x4cf10364, 0xa81a664b,0xbc423001)
++WORD64(0xc24b8b70,0xd0f89791, 0xc76c51a3,0x0654be30)
++WORD64(0xd192e819,0xd6ef5218, 0xd6990624,0x5565a910)
++WORD64(0xf40e3585,0x5771202a, 0x106aa070,0x32bbd1b8)
++WORD64(0x19a4c116,0xb8d2d0c8, 0x1e376c08,0x5141ab53)
++WORD64(0x2748774c,0xdf8eeb99, 0x34b0bcb5,0xe19b48a8)
++WORD64(0x391c0cb3,0xc5c95a63, 0x4ed8aa4a,0xe3418acb)
++WORD64(0x5b9cca4f,0x7763e373, 0x682e6ff3,0xd6b2b8a3)
++WORD64(0x748f82ee,0x5defb2fc, 0x78a5636f,0x43172f60)
++WORD64(0x84c87814,0xa1f0ab72, 0x8cc70208,0x1a6439ec)
++WORD64(0x90befffa,0x23631e28, 0xa4506ceb,0xde82bde9)
++WORD64(0xbef9a3f7,0xb2c67915, 0xc67178f2,0xe372532b)
++WORD64(0xca273ece,0xea26619c, 0xd186b8c7,0x21c0c207)
++WORD64(0xeada7dd6,0xcde0eb1e, 0xf57d4f7f,0xee6ed178)
++WORD64(0x06f067aa,0x72176fba, 0x0a637dc5,0xa2c898a6)
++WORD64(0x113f9804,0xbef90dae, 0x1b710b35,0x131c471b)
++WORD64(0x28db77f5,0x23047d84, 0x32caab7b,0x40c72493)
++WORD64(0x3c9ebe0a,0x15c9bebc, 0x431d67c4,0x9c100d4c)
++WORD64(0x4cc5d4be,0xcb3e42b6, 0x597f299c,0xfc657e2a)
++WORD64(0x5fcb6fab,0x3ad6faec, 0x6c44198c,0x4a475817)
++.size	K512,.-K512
++#if __ARM_MAX_ARCH__>=7 && !defined(__KERNEL__)
++.LOPENSSL_armcap:
++.word	OPENSSL_armcap_P-.Lsha512_block_data_order
++.skip	32-4
++#else
++.skip	32
++#endif
++
++.global	sha512_block_data_order
++.type	sha512_block_data_order,%function
++sha512_block_data_order:
++.Lsha512_block_data_order:
++#if __ARM_ARCH__<7 && !defined(__thumb2__)
++	sub	r3,pc,#8		@ sha512_block_data_order
++#else
++	adr	r3,.Lsha512_block_data_order
++#endif
++#if __ARM_MAX_ARCH__>=7 && !defined(__KERNEL__)
++	ldr	r12,.LOPENSSL_armcap
++	ldr	r12,[r3,r12]		@ OPENSSL_armcap_P
++#ifdef	__APPLE__
++	ldr	r12,[r12]
++#endif
++	tst	r12,#ARMV7_NEON
++	bne	.LNEON
++#endif
++	add	$len,$inp,$len,lsl#7	@ len to point at the end of inp
++	stmdb	sp!,{r4-r12,lr}
++	sub	$Ktbl,r3,#672		@ K512
++	sub	sp,sp,#9*8
++
++	ldr	$Elo,[$ctx,#$Eoff+$lo]
++	ldr	$Ehi,[$ctx,#$Eoff+$hi]
++	ldr	$t0, [$ctx,#$Goff+$lo]
++	ldr	$t1, [$ctx,#$Goff+$hi]
++	ldr	$t2, [$ctx,#$Hoff+$lo]
++	ldr	$t3, [$ctx,#$Hoff+$hi]
++.Loop:
++	str	$t0, [sp,#$Goff+0]
++	str	$t1, [sp,#$Goff+4]
++	str	$t2, [sp,#$Hoff+0]
++	str	$t3, [sp,#$Hoff+4]
++	ldr	$Alo,[$ctx,#$Aoff+$lo]
++	ldr	$Ahi,[$ctx,#$Aoff+$hi]
++	ldr	$Tlo,[$ctx,#$Boff+$lo]
++	ldr	$Thi,[$ctx,#$Boff+$hi]
++	ldr	$t0, [$ctx,#$Coff+$lo]
++	ldr	$t1, [$ctx,#$Coff+$hi]
++	ldr	$t2, [$ctx,#$Doff+$lo]
++	ldr	$t3, [$ctx,#$Doff+$hi]
++	str	$Tlo,[sp,#$Boff+0]
++	str	$Thi,[sp,#$Boff+4]
++	str	$t0, [sp,#$Coff+0]
++	str	$t1, [sp,#$Coff+4]
++	str	$t2, [sp,#$Doff+0]
++	str	$t3, [sp,#$Doff+4]
++	ldr	$Tlo,[$ctx,#$Foff+$lo]
++	ldr	$Thi,[$ctx,#$Foff+$hi]
++	str	$Tlo,[sp,#$Foff+0]
++	str	$Thi,[sp,#$Foff+4]
++
++.L00_15:
++#if __ARM_ARCH__<7
++	ldrb	$Tlo,[$inp,#7]
++	ldrb	$t0, [$inp,#6]
++	ldrb	$t1, [$inp,#5]
++	ldrb	$t2, [$inp,#4]
++	ldrb	$Thi,[$inp,#3]
++	ldrb	$t3, [$inp,#2]
++	orr	$Tlo,$Tlo,$t0,lsl#8
++	ldrb	$t0, [$inp,#1]
++	orr	$Tlo,$Tlo,$t1,lsl#16
++	ldrb	$t1, [$inp],#8
++	orr	$Tlo,$Tlo,$t2,lsl#24
++	orr	$Thi,$Thi,$t3,lsl#8
++	orr	$Thi,$Thi,$t0,lsl#16
++	orr	$Thi,$Thi,$t1,lsl#24
++#else
++	ldr	$Tlo,[$inp,#4]
++	ldr	$Thi,[$inp],#8
++#ifdef __ARMEL__
++	rev	$Tlo,$Tlo
++	rev	$Thi,$Thi
++#endif
++#endif
++___
++	&BODY_00_15(0x94);
++$code.=<<___;
++	tst	$Ktbl,#1
++	beq	.L00_15
++	ldr	$t0,[sp,#`$Xoff+8*(16-1)`+0]
++	ldr	$t1,[sp,#`$Xoff+8*(16-1)`+4]
++	bic	$Ktbl,$Ktbl,#1
++.L16_79:
++	@ sigma0(x)	(ROTR((x),1)  ^ ROTR((x),8)  ^ ((x)>>7))
++	@ LO		lo>>1^hi<<31  ^ lo>>8^hi<<24 ^ lo>>7^hi<<25
++	@ HI		hi>>1^lo<<31  ^ hi>>8^lo<<24 ^ hi>>7
++	mov	$Tlo,$t0,lsr#1
++	ldr	$t2,[sp,#`$Xoff+8*(16-14)`+0]
++	mov	$Thi,$t1,lsr#1
++	ldr	$t3,[sp,#`$Xoff+8*(16-14)`+4]
++	eor	$Tlo,$Tlo,$t1,lsl#31
++	eor	$Thi,$Thi,$t0,lsl#31
++	eor	$Tlo,$Tlo,$t0,lsr#8
++	eor	$Thi,$Thi,$t1,lsr#8
++	eor	$Tlo,$Tlo,$t1,lsl#24
++	eor	$Thi,$Thi,$t0,lsl#24
++	eor	$Tlo,$Tlo,$t0,lsr#7
++	eor	$Thi,$Thi,$t1,lsr#7
++	eor	$Tlo,$Tlo,$t1,lsl#25
++
++	@ sigma1(x)	(ROTR((x),19) ^ ROTR((x),61) ^ ((x)>>6))
++	@ LO		lo>>19^hi<<13 ^ hi>>29^lo<<3 ^ lo>>6^hi<<26
++	@ HI		hi>>19^lo<<13 ^ lo>>29^hi<<3 ^ hi>>6
++	mov	$t0,$t2,lsr#19
++	mov	$t1,$t3,lsr#19
++	eor	$t0,$t0,$t3,lsl#13
++	eor	$t1,$t1,$t2,lsl#13
++	eor	$t0,$t0,$t3,lsr#29
++	eor	$t1,$t1,$t2,lsr#29
++	eor	$t0,$t0,$t2,lsl#3
++	eor	$t1,$t1,$t3,lsl#3
++	eor	$t0,$t0,$t2,lsr#6
++	eor	$t1,$t1,$t3,lsr#6
++	ldr	$t2,[sp,#`$Xoff+8*(16-9)`+0]
++	eor	$t0,$t0,$t3,lsl#26
++
++	ldr	$t3,[sp,#`$Xoff+8*(16-9)`+4]
++	adds	$Tlo,$Tlo,$t0
++	ldr	$t0,[sp,#`$Xoff+8*16`+0]
++	adc	$Thi,$Thi,$t1
++
++	ldr	$t1,[sp,#`$Xoff+8*16`+4]
++	adds	$Tlo,$Tlo,$t2
++	adc	$Thi,$Thi,$t3
++	adds	$Tlo,$Tlo,$t0
++	adc	$Thi,$Thi,$t1
++___
++	&BODY_00_15(0x17);
++$code.=<<___;
++#if __ARM_ARCH__>=7
++	ittt	eq			@ Thumb2 thing, sanity check in ARM
++#endif
++	ldreq	$t0,[sp,#`$Xoff+8*(16-1)`+0]
++	ldreq	$t1,[sp,#`$Xoff+8*(16-1)`+4]
++	beq	.L16_79
++	bic	$Ktbl,$Ktbl,#1
++
++	ldr	$Tlo,[sp,#$Boff+0]
++	ldr	$Thi,[sp,#$Boff+4]
++	ldr	$t0, [$ctx,#$Aoff+$lo]
++	ldr	$t1, [$ctx,#$Aoff+$hi]
++	ldr	$t2, [$ctx,#$Boff+$lo]
++	ldr	$t3, [$ctx,#$Boff+$hi]
++	adds	$t0,$Alo,$t0
++	str	$t0, [$ctx,#$Aoff+$lo]
++	adc	$t1,$Ahi,$t1
++	str	$t1, [$ctx,#$Aoff+$hi]
++	adds	$t2,$Tlo,$t2
++	str	$t2, [$ctx,#$Boff+$lo]
++	adc	$t3,$Thi,$t3
++	str	$t3, [$ctx,#$Boff+$hi]
++
++	ldr	$Alo,[sp,#$Coff+0]
++	ldr	$Ahi,[sp,#$Coff+4]
++	ldr	$Tlo,[sp,#$Doff+0]
++	ldr	$Thi,[sp,#$Doff+4]
++	ldr	$t0, [$ctx,#$Coff+$lo]
++	ldr	$t1, [$ctx,#$Coff+$hi]
++	ldr	$t2, [$ctx,#$Doff+$lo]
++	ldr	$t3, [$ctx,#$Doff+$hi]
++	adds	$t0,$Alo,$t0
++	str	$t0, [$ctx,#$Coff+$lo]
++	adc	$t1,$Ahi,$t1
++	str	$t1, [$ctx,#$Coff+$hi]
++	adds	$t2,$Tlo,$t2
++	str	$t2, [$ctx,#$Doff+$lo]
++	adc	$t3,$Thi,$t3
++	str	$t3, [$ctx,#$Doff+$hi]
++
++	ldr	$Tlo,[sp,#$Foff+0]
++	ldr	$Thi,[sp,#$Foff+4]
++	ldr	$t0, [$ctx,#$Eoff+$lo]
++	ldr	$t1, [$ctx,#$Eoff+$hi]
++	ldr	$t2, [$ctx,#$Foff+$lo]
++	ldr	$t3, [$ctx,#$Foff+$hi]
++	adds	$Elo,$Elo,$t0
++	str	$Elo,[$ctx,#$Eoff+$lo]
++	adc	$Ehi,$Ehi,$t1
++	str	$Ehi,[$ctx,#$Eoff+$hi]
++	adds	$t2,$Tlo,$t2
++	str	$t2, [$ctx,#$Foff+$lo]
++	adc	$t3,$Thi,$t3
++	str	$t3, [$ctx,#$Foff+$hi]
++
++	ldr	$Alo,[sp,#$Goff+0]
++	ldr	$Ahi,[sp,#$Goff+4]
++	ldr	$Tlo,[sp,#$Hoff+0]
++	ldr	$Thi,[sp,#$Hoff+4]
++	ldr	$t0, [$ctx,#$Goff+$lo]
++	ldr	$t1, [$ctx,#$Goff+$hi]
++	ldr	$t2, [$ctx,#$Hoff+$lo]
++	ldr	$t3, [$ctx,#$Hoff+$hi]
++	adds	$t0,$Alo,$t0
++	str	$t0, [$ctx,#$Goff+$lo]
++	adc	$t1,$Ahi,$t1
++	str	$t1, [$ctx,#$Goff+$hi]
++	adds	$t2,$Tlo,$t2
++	str	$t2, [$ctx,#$Hoff+$lo]
++	adc	$t3,$Thi,$t3
++	str	$t3, [$ctx,#$Hoff+$hi]
++
++	add	sp,sp,#640
++	sub	$Ktbl,$Ktbl,#640
++
++	teq	$inp,$len
++	bne	.Loop
++
++	add	sp,sp,#8*9		@ destroy frame
++#if __ARM_ARCH__>=5
++	ldmia	sp!,{r4-r12,pc}
++#else
++	ldmia	sp!,{r4-r12,lr}
++	tst	lr,#1
++	moveq	pc,lr			@ be binary compatible with V4, yet
++	bx	lr			@ interoperable with Thumb ISA:-)
++#endif
++.size	sha512_block_data_order,.-sha512_block_data_order
++___
++
++{
++my @Sigma0=(28,34,39);
++my @Sigma1=(14,18,41);
++my @sigma0=(1, 8, 7);
++my @sigma1=(19,61,6);
++
++my $Ktbl="r3";
++my $cnt="r12";	# volatile register known as ip, intra-procedure-call scratch
++
++my @X=map("d$_",(0..15));
++my @V=($A,$B,$C,$D,$E,$F,$G,$H)=map("d$_",(16..23));
++
++sub NEON_00_15() {
++my $i=shift;
++my ($a,$b,$c,$d,$e,$f,$g,$h)=@_;
++my ($t0,$t1,$t2,$T1,$K,$Ch,$Maj)=map("d$_",(24..31));	# temps
++
++$code.=<<___ if ($i<16 || $i&1);
++	vshr.u64	$t0,$e,#@Sigma1[0]	@ $i
++#if $i<16
++	vld1.64		{@X[$i%16]},[$inp]!	@ handles unaligned
++#endif
++	vshr.u64	$t1,$e,#@Sigma1[1]
++#if $i>0
++	 vadd.i64	$a,$Maj			@ h+=Maj from the past
++#endif
++	vshr.u64	$t2,$e,#@Sigma1[2]
++___
++$code.=<<___;
++	vld1.64		{$K},[$Ktbl,:64]!	@ K[i++]
++	vsli.64		$t0,$e,#`64-@Sigma1[0]`
++	vsli.64		$t1,$e,#`64-@Sigma1[1]`
++	vmov		$Ch,$e
++	vsli.64		$t2,$e,#`64-@Sigma1[2]`
++#if $i<16 && defined(__ARMEL__)
++	vrev64.8	@X[$i],@X[$i]
++#endif
++	veor		$t1,$t0
++	vbsl		$Ch,$f,$g		@ Ch(e,f,g)
++	vshr.u64	$t0,$a,#@Sigma0[0]
++	veor		$t2,$t1			@ Sigma1(e)
++	vadd.i64	$T1,$Ch,$h
++	vshr.u64	$t1,$a,#@Sigma0[1]
++	vsli.64		$t0,$a,#`64-@Sigma0[0]`
++	vadd.i64	$T1,$t2
++	vshr.u64	$t2,$a,#@Sigma0[2]
++	vadd.i64	$K,@X[$i%16]
++	vsli.64		$t1,$a,#`64-@Sigma0[1]`
++	veor		$Maj,$a,$b
++	vsli.64		$t2,$a,#`64-@Sigma0[2]`
++	veor		$h,$t0,$t1
++	vadd.i64	$T1,$K
++	vbsl		$Maj,$c,$b		@ Maj(a,b,c)
++	veor		$h,$t2			@ Sigma0(a)
++	vadd.i64	$d,$T1
++	vadd.i64	$Maj,$T1
++	@ vadd.i64	$h,$Maj
++___
++}
++
++sub NEON_16_79() {
++my $i=shift;
++
++if ($i&1)	{ &NEON_00_15($i,@_); return; }
++
++# 2x-vectorized, therefore runs every 2nd round
++my @X=map("q$_",(0..7));			# view @X as 128-bit vector
++my ($t0,$t1,$s0,$s1) = map("q$_",(12..15));	# temps
++my ($d0,$d1,$d2) = map("d$_",(24..26));		# temps from NEON_00_15
++my $e=@_[4];					# $e from NEON_00_15
++$i /= 2;
++$code.=<<___;
++	vshr.u64	$t0,@X[($i+7)%8],#@sigma1[0]
++	vshr.u64	$t1,@X[($i+7)%8],#@sigma1[1]
++	 vadd.i64	@_[0],d30			@ h+=Maj from the past
++	vshr.u64	$s1,@X[($i+7)%8],#@sigma1[2]
++	vsli.64		$t0,@X[($i+7)%8],#`64-@sigma1[0]`
++	vext.8		$s0,@X[$i%8],@X[($i+1)%8],#8	@ X[i+1]
++	vsli.64		$t1,@X[($i+7)%8],#`64-@sigma1[1]`
++	veor		$s1,$t0
++	vshr.u64	$t0,$s0,#@sigma0[0]
++	veor		$s1,$t1				@ sigma1(X[i+14])
++	vshr.u64	$t1,$s0,#@sigma0[1]
++	vadd.i64	@X[$i%8],$s1
++	vshr.u64	$s1,$s0,#@sigma0[2]
++	vsli.64		$t0,$s0,#`64-@sigma0[0]`
++	vsli.64		$t1,$s0,#`64-@sigma0[1]`
++	vext.8		$s0,@X[($i+4)%8],@X[($i+5)%8],#8	@ X[i+9]
++	veor		$s1,$t0
++	vshr.u64	$d0,$e,#@Sigma1[0]		@ from NEON_00_15
++	vadd.i64	@X[$i%8],$s0
++	vshr.u64	$d1,$e,#@Sigma1[1]		@ from NEON_00_15
++	veor		$s1,$t1				@ sigma0(X[i+1])
++	vshr.u64	$d2,$e,#@Sigma1[2]		@ from NEON_00_15
++	vadd.i64	@X[$i%8],$s1
++___
++	&NEON_00_15(2*$i,@_);
++}
++
++$code.=<<___;
++#if __ARM_MAX_ARCH__>=7
++.arch	armv7-a
++.fpu	neon
++
++.global	sha512_block_data_order_neon
++.type	sha512_block_data_order_neon,%function
++.align	4
++sha512_block_data_order_neon:
++.LNEON:
++	dmb				@ errata #451034 on early Cortex A8
++	add	$len,$inp,$len,lsl#7	@ len to point at the end of inp
++	adr	$Ktbl,K512
++	VFP_ABI_PUSH
++	vldmia	$ctx,{$A-$H}		@ load context
++.Loop_neon:
++___
++for($i=0;$i<16;$i++)	{ &NEON_00_15($i,@V); unshift(@V,pop(@V)); }
++$code.=<<___;
++	mov		$cnt,#4
++.L16_79_neon:
++	subs		$cnt,#1
++___
++for(;$i<32;$i++)	{ &NEON_16_79($i,@V); unshift(@V,pop(@V)); }
++$code.=<<___;
++	bne		.L16_79_neon
++
++	 vadd.i64	$A,d30		@ h+=Maj from the past
++	vldmia		$ctx,{d24-d31}	@ load context to temp
++	vadd.i64	q8,q12		@ vectorized accumulate
++	vadd.i64	q9,q13
++	vadd.i64	q10,q14
++	vadd.i64	q11,q15
++	vstmia		$ctx,{$A-$H}	@ save context
++	teq		$inp,$len
++	sub		$Ktbl,#640	@ rewind K512
++	bne		.Loop_neon
++
++	VFP_ABI_POP
++	ret				@ bx lr
++.size	sha512_block_data_order_neon,.-sha512_block_data_order_neon
++#endif
++___
++}
++$code.=<<___;
++.asciz	"SHA512 block transform for ARMv4/NEON, CRYPTOGAMS by "
++.align	2
++#if __ARM_MAX_ARCH__>=7 && !defined(__KERNEL__)
++.comm	OPENSSL_armcap_P,4,4
++#endif
++___
++
++$code =~ s/\`([^\`]*)\`/eval $1/gem;
++$code =~ s/\bbx\s+lr\b/.word\t0xe12fff1e/gm;	# make it possible to compile with -march=armv4
++$code =~ s/\bret\b/bx	lr/gm;
++
++open SELF,$0;
++while() {
++	next if (/^#!/);
++	last if (!s/^#/@/ and !/^$/);
++	print;
++}
++close SELF;
++
++print $code;
++close STDOUT; # enforce flush
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/sha/asm/sha512-armv8.pl b/CryptoPkg/Library/OpensslLib/openssl/crypto/sha/asm/sha512-armv8.pl
+new file mode 100644
+index 0000000..c1aaf77
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/sha/asm/sha512-armv8.pl
+@@ -0,0 +1,446 @@
++#! /usr/bin/env perl
++# Copyright 2014-2016 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
++# in the file LICENSE in the source distribution or at
++# https://www.openssl.org/source/license.html
++
++#
++# ====================================================================
++# Written by Andy Polyakov  for the OpenSSL
++# project. The module is, however, dual licensed under OpenSSL and
++# CRYPTOGAMS licenses depending on where you obtain it. For further
++# details see http://www.openssl.org/~appro/cryptogams/.
++# ====================================================================
++#
++# SHA256/512 for ARMv8.
++#
++# Performance in cycles per processed byte and improvement coefficient
++# over code generated with "default" compiler:
++#
++#		SHA256-hw	SHA256(*)	SHA512
++# Apple A7	1.97		10.5 (+33%)	6.73 (-1%(**))
++# Cortex-A53	2.38		15.5 (+115%)	10.0 (+150%(***))
++# Cortex-A57	2.31		11.6 (+86%)	7.51 (+260%(***))
++# Denver	2.01		10.5 (+26%)	6.70 (+8%)
++# X-Gene			20.0 (+100%)	12.8 (+300%(***))
++# Mongoose	2.36		13.0 (+50%)	8.36 (+33%)
++# 
++# (*)	Software SHA256 results are of lesser relevance, presented
++#	mostly for informational purposes.
++# (**)	The result is a trade-off: it's possible to improve it by
++#	10% (or by 1 cycle per round), but at the cost of 20% loss
++#	on Cortex-A53 (or by 4 cycles per round).
++# (***)	Super-impressive coefficients over gcc-generated code are
++#	indication of some compiler "pathology", most notably code
++#	generated with -mgeneral-regs-only is significanty faster
++#	and the gap is only 40-90%.
++
++$flavour=shift;
++$output=shift;
++
++$0 =~ m/(.*[\/\\])[^\/\\]+$/; $dir=$1;
++( $xlate="${dir}arm-xlate.pl" and -f $xlate ) or
++( $xlate="${dir}../../perlasm/arm-xlate.pl" and -f $xlate) or
++die "can't locate arm-xlate.pl";
++
++open OUT,"| \"$^X\" $xlate $flavour $output";
++*STDOUT=*OUT;
++
++if ($output =~ /512/) {
++	$BITS=512;
++	$SZ=8;
++	@Sigma0=(28,34,39);
++	@Sigma1=(14,18,41);
++	@sigma0=(1,  8, 7);
++	@sigma1=(19,61, 6);
++	$rounds=80;
++	$reg_t="x";
++} else {
++	$BITS=256;
++	$SZ=4;
++	@Sigma0=( 2,13,22);
++	@Sigma1=( 6,11,25);
++	@sigma0=( 7,18, 3);
++	@sigma1=(17,19,10);
++	$rounds=64;
++	$reg_t="w";
++}
++
++$func="sha${BITS}_block_data_order";
++
++($ctx,$inp,$num,$Ktbl)=map("x$_",(0..2,30));
++
++@X=map("$reg_t$_",(3..15,0..2));
++@V=($A,$B,$C,$D,$E,$F,$G,$H)=map("$reg_t$_",(20..27));
++($t0,$t1,$t2,$t3)=map("$reg_t$_",(16,17,19,28));
++
++sub BODY_00_xx {
++my ($i,$a,$b,$c,$d,$e,$f,$g,$h)=@_;
++my $j=($i+1)&15;
++my ($T0,$T1,$T2)=(@X[($i-8)&15],@X[($i-9)&15],@X[($i-10)&15]);
++   $T0=@X[$i+3] if ($i<11);
++
++$code.=<<___	if ($i<16);
++#ifndef	__ARMEB__
++	rev	@X[$i],@X[$i]			// $i
++#endif
++___
++$code.=<<___	if ($i<13 && ($i&1));
++	ldp	@X[$i+1],@X[$i+2],[$inp],#2*$SZ
++___
++$code.=<<___	if ($i==13);
++	ldp	@X[14],@X[15],[$inp]
++___
++$code.=<<___	if ($i>=14);
++	ldr	@X[($i-11)&15],[sp,#`$SZ*(($i-11)%4)`]
++___
++$code.=<<___	if ($i>0 && $i<16);
++	add	$a,$a,$t1			// h+=Sigma0(a)
++___
++$code.=<<___	if ($i>=11);
++	str	@X[($i-8)&15],[sp,#`$SZ*(($i-8)%4)`]
++___
++# While ARMv8 specifies merged rotate-n-logical operation such as
++# 'eor x,y,z,ror#n', it was found to negatively affect performance
++# on Apple A7. The reason seems to be that it requires even 'y' to
++# be available earlier. This means that such merged instruction is
++# not necessarily best choice on critical path... On the other hand
++# Cortex-A5x handles merged instructions much better than disjoint
++# rotate and logical... See (**) footnote above.
++$code.=<<___	if ($i<15);
++	ror	$t0,$e,#$Sigma1[0]
++	add	$h,$h,$t2			// h+=K[i]
++	eor	$T0,$e,$e,ror#`$Sigma1[2]-$Sigma1[1]`
++	and	$t1,$f,$e
++	bic	$t2,$g,$e
++	add	$h,$h,@X[$i&15]			// h+=X[i]
++	orr	$t1,$t1,$t2			// Ch(e,f,g)
++	eor	$t2,$a,$b			// a^b, b^c in next round
++	eor	$t0,$t0,$T0,ror#$Sigma1[1]	// Sigma1(e)
++	ror	$T0,$a,#$Sigma0[0]
++	add	$h,$h,$t1			// h+=Ch(e,f,g)
++	eor	$t1,$a,$a,ror#`$Sigma0[2]-$Sigma0[1]`
++	add	$h,$h,$t0			// h+=Sigma1(e)
++	and	$t3,$t3,$t2			// (b^c)&=(a^b)
++	add	$d,$d,$h			// d+=h
++	eor	$t3,$t3,$b			// Maj(a,b,c)
++	eor	$t1,$T0,$t1,ror#$Sigma0[1]	// Sigma0(a)
++	add	$h,$h,$t3			// h+=Maj(a,b,c)
++	ldr	$t3,[$Ktbl],#$SZ		// *K++, $t2 in next round
++	//add	$h,$h,$t1			// h+=Sigma0(a)
++___
++$code.=<<___	if ($i>=15);
++	ror	$t0,$e,#$Sigma1[0]
++	add	$h,$h,$t2			// h+=K[i]
++	ror	$T1,@X[($j+1)&15],#$sigma0[0]
++	and	$t1,$f,$e
++	ror	$T2,@X[($j+14)&15],#$sigma1[0]
++	bic	$t2,$g,$e
++	ror	$T0,$a,#$Sigma0[0]
++	add	$h,$h,@X[$i&15]			// h+=X[i]
++	eor	$t0,$t0,$e,ror#$Sigma1[1]
++	eor	$T1,$T1,@X[($j+1)&15],ror#$sigma0[1]
++	orr	$t1,$t1,$t2			// Ch(e,f,g)
++	eor	$t2,$a,$b			// a^b, b^c in next round
++	eor	$t0,$t0,$e,ror#$Sigma1[2]	// Sigma1(e)
++	eor	$T0,$T0,$a,ror#$Sigma0[1]
++	add	$h,$h,$t1			// h+=Ch(e,f,g)
++	and	$t3,$t3,$t2			// (b^c)&=(a^b)
++	eor	$T2,$T2,@X[($j+14)&15],ror#$sigma1[1]
++	eor	$T1,$T1,@X[($j+1)&15],lsr#$sigma0[2]	// sigma0(X[i+1])
++	add	$h,$h,$t0			// h+=Sigma1(e)
++	eor	$t3,$t3,$b			// Maj(a,b,c)
++	eor	$t1,$T0,$a,ror#$Sigma0[2]	// Sigma0(a)
++	eor	$T2,$T2,@X[($j+14)&15],lsr#$sigma1[2]	// sigma1(X[i+14])
++	add	@X[$j],@X[$j],@X[($j+9)&15]
++	add	$d,$d,$h			// d+=h
++	add	$h,$h,$t3			// h+=Maj(a,b,c)
++	ldr	$t3,[$Ktbl],#$SZ		// *K++, $t2 in next round
++	add	@X[$j],@X[$j],$T1
++	add	$h,$h,$t1			// h+=Sigma0(a)
++	add	@X[$j],@X[$j],$T2
++___
++	($t2,$t3)=($t3,$t2);
++}
++
++$code.=<<___;
++#include "arm_arch.h"
++
++.text
++
++.extern	OPENSSL_armcap_P
++.globl	$func
++.type	$func,%function
++.align	6
++$func:
++___
++$code.=<<___	if ($SZ==4);
++#ifdef	__ILP32__
++	ldrsw	x16,.LOPENSSL_armcap_P
++#else
++	ldr	x16,.LOPENSSL_armcap_P
++#endif
++	adr	x17,.LOPENSSL_armcap_P
++	add	x16,x16,x17
++	ldr	w16,[x16]
++	tst	w16,#ARMV8_SHA256
++	b.ne	.Lv8_entry
++___
++$code.=<<___;
++	stp	x29,x30,[sp,#-128]!
++	add	x29,sp,#0
++
++	stp	x19,x20,[sp,#16]
++	stp	x21,x22,[sp,#32]
++	stp	x23,x24,[sp,#48]
++	stp	x25,x26,[sp,#64]
++	stp	x27,x28,[sp,#80]
++	sub	sp,sp,#4*$SZ
++
++	ldp	$A,$B,[$ctx]				// load context
++	ldp	$C,$D,[$ctx,#2*$SZ]
++	ldp	$E,$F,[$ctx,#4*$SZ]
++	add	$num,$inp,$num,lsl#`log(16*$SZ)/log(2)`	// end of input
++	ldp	$G,$H,[$ctx,#6*$SZ]
++	adr	$Ktbl,.LK$BITS
++	stp	$ctx,$num,[x29,#96]
++
++.Loop:
++	ldp	@X[0],@X[1],[$inp],#2*$SZ
++	ldr	$t2,[$Ktbl],#$SZ			// *K++
++	eor	$t3,$B,$C				// magic seed
++	str	$inp,[x29,#112]
++___
++for ($i=0;$i<16;$i++)	{ &BODY_00_xx($i,@V); unshift(@V,pop(@V)); }
++$code.=".Loop_16_xx:\n";
++for (;$i<32;$i++)	{ &BODY_00_xx($i,@V); unshift(@V,pop(@V)); }
++$code.=<<___;
++	cbnz	$t2,.Loop_16_xx
++
++	ldp	$ctx,$num,[x29,#96]
++	ldr	$inp,[x29,#112]
++	sub	$Ktbl,$Ktbl,#`$SZ*($rounds+1)`		// rewind
++
++	ldp	@X[0],@X[1],[$ctx]
++	ldp	@X[2],@X[3],[$ctx,#2*$SZ]
++	add	$inp,$inp,#14*$SZ			// advance input pointer
++	ldp	@X[4],@X[5],[$ctx,#4*$SZ]
++	add	$A,$A,@X[0]
++	ldp	@X[6],@X[7],[$ctx,#6*$SZ]
++	add	$B,$B,@X[1]
++	add	$C,$C,@X[2]
++	add	$D,$D,@X[3]
++	stp	$A,$B,[$ctx]
++	add	$E,$E,@X[4]
++	add	$F,$F,@X[5]
++	stp	$C,$D,[$ctx,#2*$SZ]
++	add	$G,$G,@X[6]
++	add	$H,$H,@X[7]
++	cmp	$inp,$num
++	stp	$E,$F,[$ctx,#4*$SZ]
++	stp	$G,$H,[$ctx,#6*$SZ]
++	b.ne	.Loop
++
++	ldp	x19,x20,[x29,#16]
++	add	sp,sp,#4*$SZ
++	ldp	x21,x22,[x29,#32]
++	ldp	x23,x24,[x29,#48]
++	ldp	x25,x26,[x29,#64]
++	ldp	x27,x28,[x29,#80]
++	ldp	x29,x30,[sp],#128
++	ret
++.size	$func,.-$func
++
++.align	6
++.type	.LK$BITS,%object
++.LK$BITS:
++___
++$code.=<<___ if ($SZ==8);
++	.quad	0x428a2f98d728ae22,0x7137449123ef65cd
++	.quad	0xb5c0fbcfec4d3b2f,0xe9b5dba58189dbbc
++	.quad	0x3956c25bf348b538,0x59f111f1b605d019
++	.quad	0x923f82a4af194f9b,0xab1c5ed5da6d8118
++	.quad	0xd807aa98a3030242,0x12835b0145706fbe
++	.quad	0x243185be4ee4b28c,0x550c7dc3d5ffb4e2
++	.quad	0x72be5d74f27b896f,0x80deb1fe3b1696b1
++	.quad	0x9bdc06a725c71235,0xc19bf174cf692694
++	.quad	0xe49b69c19ef14ad2,0xefbe4786384f25e3
++	.quad	0x0fc19dc68b8cd5b5,0x240ca1cc77ac9c65
++	.quad	0x2de92c6f592b0275,0x4a7484aa6ea6e483
++	.quad	0x5cb0a9dcbd41fbd4,0x76f988da831153b5
++	.quad	0x983e5152ee66dfab,0xa831c66d2db43210
++	.quad	0xb00327c898fb213f,0xbf597fc7beef0ee4
++	.quad	0xc6e00bf33da88fc2,0xd5a79147930aa725
++	.quad	0x06ca6351e003826f,0x142929670a0e6e70
++	.quad	0x27b70a8546d22ffc,0x2e1b21385c26c926
++	.quad	0x4d2c6dfc5ac42aed,0x53380d139d95b3df
++	.quad	0x650a73548baf63de,0x766a0abb3c77b2a8
++	.quad	0x81c2c92e47edaee6,0x92722c851482353b
++	.quad	0xa2bfe8a14cf10364,0xa81a664bbc423001
++	.quad	0xc24b8b70d0f89791,0xc76c51a30654be30
++	.quad	0xd192e819d6ef5218,0xd69906245565a910
++	.quad	0xf40e35855771202a,0x106aa07032bbd1b8
++	.quad	0x19a4c116b8d2d0c8,0x1e376c085141ab53
++	.quad	0x2748774cdf8eeb99,0x34b0bcb5e19b48a8
++	.quad	0x391c0cb3c5c95a63,0x4ed8aa4ae3418acb
++	.quad	0x5b9cca4f7763e373,0x682e6ff3d6b2b8a3
++	.quad	0x748f82ee5defb2fc,0x78a5636f43172f60
++	.quad	0x84c87814a1f0ab72,0x8cc702081a6439ec
++	.quad	0x90befffa23631e28,0xa4506cebde82bde9
++	.quad	0xbef9a3f7b2c67915,0xc67178f2e372532b
++	.quad	0xca273eceea26619c,0xd186b8c721c0c207
++	.quad	0xeada7dd6cde0eb1e,0xf57d4f7fee6ed178
++	.quad	0x06f067aa72176fba,0x0a637dc5a2c898a6
++	.quad	0x113f9804bef90dae,0x1b710b35131c471b
++	.quad	0x28db77f523047d84,0x32caab7b40c72493
++	.quad	0x3c9ebe0a15c9bebc,0x431d67c49c100d4c
++	.quad	0x4cc5d4becb3e42b6,0x597f299cfc657e2a
++	.quad	0x5fcb6fab3ad6faec,0x6c44198c4a475817
++	.quad	0	// terminator
++___
++$code.=<<___ if ($SZ==4);
++	.long	0x428a2f98,0x71374491,0xb5c0fbcf,0xe9b5dba5
++	.long	0x3956c25b,0x59f111f1,0x923f82a4,0xab1c5ed5
++	.long	0xd807aa98,0x12835b01,0x243185be,0x550c7dc3
++	.long	0x72be5d74,0x80deb1fe,0x9bdc06a7,0xc19bf174
++	.long	0xe49b69c1,0xefbe4786,0x0fc19dc6,0x240ca1cc
++	.long	0x2de92c6f,0x4a7484aa,0x5cb0a9dc,0x76f988da
++	.long	0x983e5152,0xa831c66d,0xb00327c8,0xbf597fc7
++	.long	0xc6e00bf3,0xd5a79147,0x06ca6351,0x14292967
++	.long	0x27b70a85,0x2e1b2138,0x4d2c6dfc,0x53380d13
++	.long	0x650a7354,0x766a0abb,0x81c2c92e,0x92722c85
++	.long	0xa2bfe8a1,0xa81a664b,0xc24b8b70,0xc76c51a3
++	.long	0xd192e819,0xd6990624,0xf40e3585,0x106aa070
++	.long	0x19a4c116,0x1e376c08,0x2748774c,0x34b0bcb5
++	.long	0x391c0cb3,0x4ed8aa4a,0x5b9cca4f,0x682e6ff3
++	.long	0x748f82ee,0x78a5636f,0x84c87814,0x8cc70208
++	.long	0x90befffa,0xa4506ceb,0xbef9a3f7,0xc67178f2
++	.long	0	//terminator
++___
++$code.=<<___;
++.size	.LK$BITS,.-.LK$BITS
++.align	3
++.LOPENSSL_armcap_P:
++#ifdef	__ILP32__
++	.long	OPENSSL_armcap_P-.
++#else
++	.quad	OPENSSL_armcap_P-.
++#endif
++.asciz	"SHA$BITS block transform for ARMv8, CRYPTOGAMS by "
++.align	2
++___
++
++if ($SZ==4) {
++my $Ktbl="x3";
++
++my ($ABCD,$EFGH,$abcd)=map("v$_.16b",(0..2));
++my @MSG=map("v$_.16b",(4..7));
++my ($W0,$W1)=("v16.4s","v17.4s");
++my ($ABCD_SAVE,$EFGH_SAVE)=("v18.16b","v19.16b");
++
++$code.=<<___;
++.type	sha256_block_armv8,%function
++.align	6
++sha256_block_armv8:
++.Lv8_entry:
++	stp		x29,x30,[sp,#-16]!
++	add		x29,sp,#0
++
++	ld1.32		{$ABCD,$EFGH},[$ctx]
++	adr		$Ktbl,.LK256
++
++.Loop_hw:
++	ld1		{@MSG[0]-@MSG[3]},[$inp],#64
++	sub		$num,$num,#1
++	ld1.32		{$W0},[$Ktbl],#16
++	rev32		@MSG[0],@MSG[0]
++	rev32		@MSG[1],@MSG[1]
++	rev32		@MSG[2],@MSG[2]
++	rev32		@MSG[3],@MSG[3]
++	orr		$ABCD_SAVE,$ABCD,$ABCD		// offload
++	orr		$EFGH_SAVE,$EFGH,$EFGH
++___
++for($i=0;$i<12;$i++) {
++$code.=<<___;
++	ld1.32		{$W1},[$Ktbl],#16
++	add.i32		$W0,$W0,@MSG[0]
++	sha256su0	@MSG[0],@MSG[1]
++	orr		$abcd,$ABCD,$ABCD
++	sha256h		$ABCD,$EFGH,$W0
++	sha256h2	$EFGH,$abcd,$W0
++	sha256su1	@MSG[0],@MSG[2],@MSG[3]
++___
++	($W0,$W1)=($W1,$W0);	push(@MSG,shift(@MSG));
++}
++$code.=<<___;
++	ld1.32		{$W1},[$Ktbl],#16
++	add.i32		$W0,$W0,@MSG[0]
++	orr		$abcd,$ABCD,$ABCD
++	sha256h		$ABCD,$EFGH,$W0
++	sha256h2	$EFGH,$abcd,$W0
++
++	ld1.32		{$W0},[$Ktbl],#16
++	add.i32		$W1,$W1,@MSG[1]
++	orr		$abcd,$ABCD,$ABCD
++	sha256h		$ABCD,$EFGH,$W1
++	sha256h2	$EFGH,$abcd,$W1
++
++	ld1.32		{$W1},[$Ktbl]
++	add.i32		$W0,$W0,@MSG[2]
++	sub		$Ktbl,$Ktbl,#$rounds*$SZ-16	// rewind
++	orr		$abcd,$ABCD,$ABCD
++	sha256h		$ABCD,$EFGH,$W0
++	sha256h2	$EFGH,$abcd,$W0
++
++	add.i32		$W1,$W1,@MSG[3]
++	orr		$abcd,$ABCD,$ABCD
++	sha256h		$ABCD,$EFGH,$W1
++	sha256h2	$EFGH,$abcd,$W1
++
++	add.i32		$ABCD,$ABCD,$ABCD_SAVE
++	add.i32		$EFGH,$EFGH,$EFGH_SAVE
++
++	cbnz		$num,.Loop_hw
++
++	st1.32		{$ABCD,$EFGH},[$ctx]
++
++	ldr		x29,[sp],#16
++	ret
++.size	sha256_block_armv8,.-sha256_block_armv8
++___
++}
++
++$code.=<<___;
++.comm	OPENSSL_armcap_P,4,4
++___
++
++{   my  %opcode = (
++	"sha256h"	=> 0x5e004000,	"sha256h2"	=> 0x5e005000,
++	"sha256su0"	=> 0x5e282800,	"sha256su1"	=> 0x5e006000	);
++
++    sub unsha256 {
++	my ($mnemonic,$arg)=@_;
++
++	$arg =~ m/[qv]([0-9]+)[^,]*,\s*[qv]([0-9]+)[^,]*(?:,\s*[qv]([0-9]+))?/o
++	&&
++	sprintf ".inst\t0x%08x\t//%s %s",
++			$opcode{$mnemonic}|$1|($2<<5)|($3<<16),
++			$mnemonic,$arg;
++    }
++}
++
++foreach(split("\n",$code)) {
++
++	s/\`([^\`]*)\`/eval($1)/geo;
++
++	s/\b(sha256\w+)\s+([qv].*)/unsha256($1,$2)/geo;
++
++	s/\.\w?32\b//o		and s/\.16b/\.4s/go;
++	m/(ld|st)1[^\[]+\[0\]/o	and s/\.4s/\.s/go;
++
++	print $_,"\n";
++}
++
++close STDOUT;
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/sha/asm/sha512-c64xplus.pl b/CryptoPkg/Library/OpensslLib/openssl/crypto/sha/asm/sha512-c64xplus.pl
+new file mode 100644
+index 0000000..9ebfc92
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/sha/asm/sha512-c64xplus.pl
+@@ -0,0 +1,438 @@
++#! /usr/bin/env perl
++# Copyright 2012-2016 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
++# in the file LICENSE in the source distribution or at
++# https://www.openssl.org/source/license.html
++
++#
++# ====================================================================
++# Written by Andy Polyakov  for the OpenSSL
++# project. The module is, however, dual licensed under OpenSSL and
++# CRYPTOGAMS licenses depending on where you obtain it. For further
++# details see http://www.openssl.org/~appro/cryptogams/.
++# ====================================================================
++#
++# SHA512 for C64x+.
++#
++# January 2012
++#
++# Performance is 19 cycles per processed byte. Compared to block
++# transform function from sha512.c compiled with cl6x with -mv6400+
++# -o2 -DOPENSSL_SMALL_FOOTPRINT it's almost 7x faster and 2x smaller.
++# Loop unroll won't make it, this implementation, any faster, because
++# it's effectively dominated by SHRU||SHL pairs and you can't schedule
++# more of them.
++#
++# !!! Note that this module uses AMR, which means that all interrupt
++# service routines are expected to preserve it and for own well-being
++# zero it upon entry.
++
++while (($output=shift) && ($output!~/\w[\w\-]*\.\w+$/)) {}
++open STDOUT,">$output";
++
++($CTXA,$INP,$NUM) = ("A4","B4","A6");            # arguments
++ $K512="A3";
++
++($Ahi,$Actxhi,$Bhi,$Bctxhi,$Chi,$Cctxhi,$Dhi,$Dctxhi,
++ $Ehi,$Ectxhi,$Fhi,$Fctxhi,$Ghi,$Gctxhi,$Hhi,$Hctxhi)=map("A$_",(16..31));
++($Alo,$Actxlo,$Blo,$Bctxlo,$Clo,$Cctxlo,$Dlo,$Dctxlo,
++ $Elo,$Ectxlo,$Flo,$Fctxlo,$Glo,$Gctxlo,$Hlo,$Hctxlo)=map("B$_",(16..31));
++
++($S1hi,$CHhi,$S0hi,$t0hi)=map("A$_",(10..13));
++($S1lo,$CHlo,$S0lo,$t0lo)=map("B$_",(10..13));
++($T1hi,         $T2hi)=         ("A6","A7");
++($T1lo,$T1carry,$T2lo,$T2carry)=("B6","B7","B8","B9");
++($Khi,$Klo)=("A9","A8");
++($MAJhi,$MAJlo)=($T2hi,$T2lo);
++($t1hi,$t1lo)=($Khi,"B2");
++ $CTXB=$t1lo;
++
++($Xihi,$Xilo)=("A5","B5");			# circular/ring buffer
++
++$code.=<<___;
++	.text
++
++	.if	.ASSEMBLER_VERSION<7000000
++	.asg	0,__TI_EABI__
++	.endif
++	.if	__TI_EABI__
++	.nocmp
++	.asg	sha512_block_data_order,_sha512_block_data_order
++	.endif
++
++	.asg	B3,RA
++	.asg	A15,FP
++	.asg	B15,SP
++
++	.if	.BIG_ENDIAN
++	.asg	$Khi,KHI
++	.asg	$Klo,KLO
++	.else
++	.asg	$Khi,KLO
++	.asg	$Klo,KHI
++	.endif
++
++	.global	_sha512_block_data_order
++_sha512_block_data_order:
++__sha512_block:
++	.asmfunc stack_usage(40+128)
++	MV	$NUM,A0				; reassign $NUM
++||	MVK	-128,B0
++  [!A0]	BNOP	RA				; if ($NUM==0) return;
++|| [A0]	STW	FP,*SP--(40)			; save frame pointer
++|| [A0]	MV	SP,FP
++   [A0]	STDW	B13:B12,*SP[4]
++|| [A0]	MVK	0x00404,B1
++   [A0]	STDW	B11:B10,*SP[3]
++|| [A0]	STDW	A13:A12,*FP[-3]
++|| [A0]	MVKH	0x60000,B1
++   [A0]	STDW	A11:A10,*SP[1]
++|| [A0]	MVC	B1,AMR				; setup circular addressing
++|| [A0]	ADD	B0,SP,SP			; alloca(128)
++	.if	__TI_EABI__
++   [A0]	AND	B0,SP,SP			; align stack at 128 bytes
++|| [A0]	ADDKPC	__sha512_block,B1
++|| [A0]	MVKL	\$PCR_OFFSET(K512,__sha512_block),$K512
++   [A0]	MVKH	\$PCR_OFFSET(K512,__sha512_block),$K512
++|| [A0]	SUBAW	SP,2,SP				; reserve two words above buffer
++	.else
++   [A0]	AND	B0,SP,SP			; align stack at 128 bytes
++|| [A0]	ADDKPC	__sha512_block,B1
++|| [A0]	MVKL	(K512-__sha512_block),$K512
++   [A0]	MVKH	(K512-__sha512_block),$K512
++|| [A0]	SUBAW	SP,2,SP				; reserve two words above buffer
++	.endif
++	ADDAW	SP,3,$Xilo
++	ADDAW	SP,2,$Xihi
++
++||	MV	$CTXA,$CTXB
++	LDW	*${CTXA}[0^.LITTLE_ENDIAN],$Ahi	; load ctx
++||	LDW	*${CTXB}[1^.LITTLE_ENDIAN],$Alo
++||	ADD	B1,$K512,$K512
++	LDW	*${CTXA}[2^.LITTLE_ENDIAN],$Bhi
++||	LDW	*${CTXB}[3^.LITTLE_ENDIAN],$Blo
++	LDW	*${CTXA}[4^.LITTLE_ENDIAN],$Chi
++||	LDW	*${CTXB}[5^.LITTLE_ENDIAN],$Clo
++	LDW	*${CTXA}[6^.LITTLE_ENDIAN],$Dhi
++||	LDW	*${CTXB}[7^.LITTLE_ENDIAN],$Dlo
++	LDW	*${CTXA}[8^.LITTLE_ENDIAN],$Ehi
++||	LDW	*${CTXB}[9^.LITTLE_ENDIAN],$Elo
++	LDW	*${CTXA}[10^.LITTLE_ENDIAN],$Fhi
++||	LDW	*${CTXB}[11^.LITTLE_ENDIAN],$Flo
++	LDW	*${CTXA}[12^.LITTLE_ENDIAN],$Ghi
++||	LDW	*${CTXB}[13^.LITTLE_ENDIAN],$Glo
++	LDW	*${CTXA}[14^.LITTLE_ENDIAN],$Hhi
++||	LDW	*${CTXB}[15^.LITTLE_ENDIAN],$Hlo
++
++	LDNDW	*$INP++,B11:B10			; pre-fetch input
++	LDDW	*$K512++,$Khi:$Klo		; pre-fetch K512[0]
++outerloop?:
++	MVK	15,B0				; loop counters
++||	MVK	64,B1
++||	SUB	A0,1,A0
++	MV	$Ahi,$Actxhi
++||	MV	$Alo,$Actxlo
++||	MV	$Bhi,$Bctxhi
++||	MV	$Blo,$Bctxlo
++||	MV	$Chi,$Cctxhi
++||	MV	$Clo,$Cctxlo
++||	MVD	$Dhi,$Dctxhi
++||	MVD	$Dlo,$Dctxlo
++	MV	$Ehi,$Ectxhi
++||	MV	$Elo,$Ectxlo
++||	MV	$Fhi,$Fctxhi
++||	MV	$Flo,$Fctxlo
++||	MV	$Ghi,$Gctxhi
++||	MV	$Glo,$Gctxlo
++||	MVD	$Hhi,$Hctxhi
++||	MVD	$Hlo,$Hctxlo
++loop0_15?:
++	.if	.BIG_ENDIAN
++	MV	B11,$T1hi
++||	MV	B10,$T1lo
++	.else
++	SWAP4	B10,$T1hi
++||	SWAP4	B11,$T1lo
++	SWAP2	$T1hi,$T1hi
++||	SWAP2	$T1lo,$T1lo
++	.endif
++loop16_79?:
++	STW	$T1hi,*$Xihi++[2]
++||	STW	$T1lo,*$Xilo++[2]			; X[i] = T1
++||	ADD	$Hhi,$T1hi,$T1hi
++||	ADDU	$Hlo,$T1lo,$T1carry:$T1lo		; T1 += h
++||	SHRU	$Ehi,14,$S1hi
++||	SHL	$Ehi,32-14,$S1lo
++	XOR	$Fhi,$Ghi,$CHhi
++||	XOR	$Flo,$Glo,$CHlo
++||	ADD	KHI,$T1hi,$T1hi
++||	ADDU	KLO,$T1carry:$T1lo,$T1carry:$T1lo	; T1 += K512[i]
++||	SHRU	$Elo,14,$t0lo
++||	SHL	$Elo,32-14,$t0hi
++	XOR	$t0hi,$S1hi,$S1hi
++||	XOR	$t0lo,$S1lo,$S1lo
++||	AND	$Ehi,$CHhi,$CHhi
++||	AND	$Elo,$CHlo,$CHlo
++||	ROTL	$Ghi,0,$Hhi
++||	ROTL	$Glo,0,$Hlo				; h = g
++||	SHRU	$Ehi,18,$t0hi
++||	SHL	$Ehi,32-18,$t0lo
++	XOR	$t0hi,$S1hi,$S1hi
++||	XOR	$t0lo,$S1lo,$S1lo
++||	XOR	$Ghi,$CHhi,$CHhi
++||	XOR	$Glo,$CHlo,$CHlo			; Ch(e,f,g) = ((f^g)&e)^g
++||	ROTL	$Fhi,0,$Ghi
++||	ROTL	$Flo,0,$Glo				; g = f
++||	SHRU	$Elo,18,$t0lo
++||	SHL	$Elo,32-18,$t0hi
++	XOR	$t0hi,$S1hi,$S1hi
++||	XOR	$t0lo,$S1lo,$S1lo
++||	OR	$Ahi,$Bhi,$MAJhi
++||	OR	$Alo,$Blo,$MAJlo
++||	ROTL	$Ehi,0,$Fhi
++||	ROTL	$Elo,0,$Flo				; f = e
++||	SHRU	$Ehi,41-32,$t0lo
++||	SHL	$Ehi,64-41,$t0hi
++	XOR	$t0hi,$S1hi,$S1hi
++||	XOR	$t0lo,$S1lo,$S1lo
++||	AND	$Chi,$MAJhi,$MAJhi
++||	AND	$Clo,$MAJlo,$MAJlo
++||	ROTL	$Dhi,0,$Ehi
++||	ROTL	$Dlo,0,$Elo				; e = d
++||	SHRU	$Elo,41-32,$t0hi
++||	SHL	$Elo,64-41,$t0lo
++	XOR	$t0hi,$S1hi,$S1hi
++||	XOR	$t0lo,$S1lo,$S1lo			; Sigma1(e)
++||	AND	$Ahi,$Bhi,$t1hi
++||	AND	$Alo,$Blo,$t1lo
++||	ROTL	$Chi,0,$Dhi
++||	ROTL	$Clo,0,$Dlo				; d = c
++||	SHRU	$Ahi,28,$S0hi
++||	SHL	$Ahi,32-28,$S0lo
++	OR	$t1hi,$MAJhi,$MAJhi
++||	OR	$t1lo,$MAJlo,$MAJlo			; Maj(a,b,c) = ((a|b)&c)|(a&b)
++||	ADD	$CHhi,$T1hi,$T1hi
++||	ADDU	$CHlo,$T1carry:$T1lo,$T1carry:$T1lo	; T1 += Ch(e,f,g)
++||	ROTL	$Bhi,0,$Chi
++||	ROTL	$Blo,0,$Clo				; c = b
++||	SHRU	$Alo,28,$t0lo
++||	SHL	$Alo,32-28,$t0hi
++	XOR	$t0hi,$S0hi,$S0hi
++||	XOR	$t0lo,$S0lo,$S0lo
++||	ADD	$S1hi,$T1hi,$T1hi
++||	ADDU	$S1lo,$T1carry:$T1lo,$T1carry:$T1lo	; T1 += Sigma1(e)
++||	ROTL	$Ahi,0,$Bhi
++||	ROTL	$Alo,0,$Blo				; b = a
++||	SHRU	$Ahi,34-32,$t0lo
++||	SHL	$Ahi,64-34,$t0hi
++	XOR	$t0hi,$S0hi,$S0hi
++||	XOR	$t0lo,$S0lo,$S0lo
++||	ADD	$MAJhi,$T1hi,$T2hi
++||	ADDU	$MAJlo,$T1carry:$T1lo,$T2carry:$T2lo	; T2 = T1+Maj(a,b,c)
++||	SHRU	$Alo,34-32,$t0hi
++||	SHL	$Alo,64-34,$t0lo
++	XOR	$t0hi,$S0hi,$S0hi
++||	XOR	$t0lo,$S0lo,$S0lo
++||	ADD	$Ehi,$T1hi,$T1hi
++||	ADDU	$Elo,$T1carry:$T1lo,$T1carry:$T1lo	; T1 += e
++|| [B0]	BNOP	loop0_15?
++||	SHRU	$Ahi,39-32,$t0lo
++||	SHL	$Ahi,64-39,$t0hi
++	XOR	$t0hi,$S0hi,$S0hi
++||	XOR	$t0lo,$S0lo,$S0lo
++|| [B0]	LDNDW	*$INP++,B11:B10				; pre-fetch input
++||[!B1]	BNOP	break?
++||	SHRU	$Alo,39-32,$t0hi
++||	SHL	$Alo,64-39,$t0lo
++	XOR	$t0hi,$S0hi,$S0hi
++||	XOR	$t0lo,$S0lo,$S0lo			; Sigma0(a)
++||	ADD	$T1carry,$T1hi,$Ehi
++||	MV	$T1lo,$Elo				; e = T1
++||[!B0]	LDW	*${Xihi}[28],$T1hi
++||[!B0]	LDW	*${Xilo}[28],$T1lo			; X[i+14]
++	ADD	$S0hi,$T2hi,$T2hi
++||	ADDU	$S0lo,$T2carry:$T2lo,$T2carry:$T2lo	; T2 += Sigma0(a)
++|| [B1]	LDDW	*$K512++,$Khi:$Klo			; pre-fetch K512[i]
++	NOP						; avoid cross-path stall
++	ADD	$T2carry,$T2hi,$Ahi
++||	MV	$T2lo,$Alo				; a = T2
++|| [B0]	SUB	B0,1,B0
++;;===== branch to loop00_15? is taken here
++	NOP
++;;===== branch to break? is taken here
++	LDW	*${Xihi}[2],$T2hi
++||	LDW	*${Xilo}[2],$T2lo			; X[i+1]
++||	SHRU	$T1hi,19,$S1hi
++||	SHL	$T1hi,32-19,$S1lo
++	SHRU	$T1lo,19,$t0lo
++||	SHL	$T1lo,32-19,$t0hi
++	XOR	$t0hi,$S1hi,$S1hi
++||	XOR	$t0lo,$S1lo,$S1lo
++||	SHRU	$T1hi,61-32,$t0lo
++||	SHL	$T1hi,64-61,$t0hi
++	XOR	$t0hi,$S1hi,$S1hi
++||	XOR	$t0lo,$S1lo,$S1lo
++||	SHRU	$T1lo,61-32,$t0hi
++||	SHL	$T1lo,64-61,$t0lo
++	XOR	$t0hi,$S1hi,$S1hi
++||	XOR	$t0lo,$S1lo,$S1lo
++||	SHRU	$T1hi,6,$t0hi
++||	SHL	$T1hi,32-6,$t0lo
++	XOR	$t0hi,$S1hi,$S1hi
++||	XOR	$t0lo,$S1lo,$S1lo
++||	SHRU	$T1lo,6,$t0lo
++||	LDW	*${Xihi}[18],$T1hi
++||	LDW	*${Xilo}[18],$T1lo			; X[i+9]
++	XOR	$t0lo,$S1lo,$S1lo			; sigma1(Xi[i+14])
++
++||	LDW	*${Xihi}[0],$CHhi
++||	LDW	*${Xilo}[0],$CHlo			; X[i]
++||	SHRU	$T2hi,1,$S0hi
++||	SHL	$T2hi,32-1,$S0lo
++	SHRU	$T2lo,1,$t0lo
++||	SHL	$T2lo,32-1,$t0hi
++	XOR	$t0hi,$S0hi,$S0hi
++||	XOR	$t0lo,$S0lo,$S0lo
++||	SHRU	$T2hi,8,$t0hi
++||	SHL	$T2hi,32-8,$t0lo
++	XOR	$t0hi,$S0hi,$S0hi
++||	XOR	$t0lo,$S0lo,$S0lo
++||	SHRU	$T2lo,8,$t0lo
++||	SHL	$T2lo,32-8,$t0hi
++	XOR	$t0hi,$S0hi,$S0hi
++||	XOR	$t0lo,$S0lo,$S0lo
++||	ADD	$S1hi,$T1hi,$T1hi
++||	ADDU	$S1lo,$T1lo,$T1carry:$T1lo		; T1 = X[i+9]+sigma1()
++|| [B1]	BNOP	loop16_79?
++||	SHRU	$T2hi,7,$t0hi
++||	SHL	$T2hi,32-7,$t0lo
++	XOR	$t0hi,$S0hi,$S0hi
++||	XOR	$t0lo,$S0lo,$S0lo
++||	ADD	$CHhi,$T1hi,$T1hi
++||	ADDU	$CHlo,$T1carry:$T1lo,$T1carry:$T1lo	; T1 += X[i]
++||	SHRU	$T2lo,7,$t0lo
++	XOR	$t0lo,$S0lo,$S0lo			; sigma0(Xi[i+1]
++
++	ADD	$S0hi,$T1hi,$T1hi
++||	ADDU	$S0lo,$T1carry:$T1lo,$T1carry:$T1lo	; T1 += sigma0()
++|| [B1]	SUB	B1,1,B1
++	NOP						; avoid cross-path stall
++	ADD	$T1carry,$T1hi,$T1hi
++;;===== branch to loop16_79? is taken here
++
++break?:
++	ADD	$Ahi,$Actxhi,$Ahi		; accumulate ctx
++||	ADDU	$Alo,$Actxlo,$Actxlo:$Alo
++|| [A0]	LDNDW	*$INP++,B11:B10			; pre-fetch input
++|| [A0]	ADDK	-640,$K512			; rewind pointer to K512
++	ADD	$Bhi,$Bctxhi,$Bhi
++||	ADDU	$Blo,$Bctxlo,$Bctxlo:$Blo
++|| [A0]	LDDW	*$K512++,$Khi:$Klo		; pre-fetch K512[0]
++	ADD	$Chi,$Cctxhi,$Chi
++||	ADDU	$Clo,$Cctxlo,$Cctxlo:$Clo
++||	ADD	$Actxlo,$Ahi,$Ahi
++||[!A0]	MV	$CTXA,$CTXB
++	ADD	$Dhi,$Dctxhi,$Dhi
++||	ADDU	$Dlo,$Dctxlo,$Dctxlo:$Dlo
++||	ADD	$Bctxlo,$Bhi,$Bhi
++||[!A0]	STW	$Ahi,*${CTXA}[0^.LITTLE_ENDIAN]	; save ctx
++||[!A0]	STW	$Alo,*${CTXB}[1^.LITTLE_ENDIAN]
++	ADD	$Ehi,$Ectxhi,$Ehi
++||	ADDU	$Elo,$Ectxlo,$Ectxlo:$Elo
++||	ADD	$Cctxlo,$Chi,$Chi
++|| [A0]	BNOP	outerloop?
++||[!A0]	STW	$Bhi,*${CTXA}[2^.LITTLE_ENDIAN]
++||[!A0]	STW	$Blo,*${CTXB}[3^.LITTLE_ENDIAN]
++	ADD	$Fhi,$Fctxhi,$Fhi
++||	ADDU	$Flo,$Fctxlo,$Fctxlo:$Flo
++||	ADD	$Dctxlo,$Dhi,$Dhi
++||[!A0]	STW	$Chi,*${CTXA}[4^.LITTLE_ENDIAN]
++||[!A0]	STW	$Clo,*${CTXB}[5^.LITTLE_ENDIAN]
++	ADD	$Ghi,$Gctxhi,$Ghi
++||	ADDU	$Glo,$Gctxlo,$Gctxlo:$Glo
++||	ADD	$Ectxlo,$Ehi,$Ehi
++||[!A0]	STW	$Dhi,*${CTXA}[6^.LITTLE_ENDIAN]
++||[!A0]	STW	$Dlo,*${CTXB}[7^.LITTLE_ENDIAN]
++	ADD	$Hhi,$Hctxhi,$Hhi
++||	ADDU	$Hlo,$Hctxlo,$Hctxlo:$Hlo
++||	ADD	$Fctxlo,$Fhi,$Fhi
++||[!A0]	STW	$Ehi,*${CTXA}[8^.LITTLE_ENDIAN]
++||[!A0]	STW	$Elo,*${CTXB}[9^.LITTLE_ENDIAN]
++	ADD	$Gctxlo,$Ghi,$Ghi
++||[!A0]	STW	$Fhi,*${CTXA}[10^.LITTLE_ENDIAN]
++||[!A0]	STW	$Flo,*${CTXB}[11^.LITTLE_ENDIAN]
++	ADD	$Hctxlo,$Hhi,$Hhi
++||[!A0]	STW	$Ghi,*${CTXA}[12^.LITTLE_ENDIAN]
++||[!A0]	STW	$Glo,*${CTXB}[13^.LITTLE_ENDIAN]
++;;===== branch to outerloop? is taken here
++
++	STW	$Hhi,*${CTXA}[14^.LITTLE_ENDIAN]
++||	STW	$Hlo,*${CTXB}[15^.LITTLE_ENDIAN]
++||	MVK	-40,B0
++	ADD	FP,B0,SP			; destroy circular buffer
++||	LDDW	*FP[-4],A11:A10
++	LDDW	*SP[2],A13:A12
++||	LDDW	*FP[-2],B11:B10
++	LDDW	*SP[4],B13:B12
++||	BNOP	RA
++	LDW	*++SP(40),FP			; restore frame pointer
++	MVK	0,B0
++	MVC	B0,AMR				; clear AMR
++	NOP	2				; wait till FP is committed
++	.endasmfunc
++
++	.if	__TI_EABI__
++	.sect	".text:sha_asm.const"
++	.else
++	.sect	".const:sha_asm"
++	.endif
++	.align	128
++K512:
++	.uword	0x428a2f98,0xd728ae22, 0x71374491,0x23ef65cd
++	.uword	0xb5c0fbcf,0xec4d3b2f, 0xe9b5dba5,0x8189dbbc
++	.uword	0x3956c25b,0xf348b538, 0x59f111f1,0xb605d019
++	.uword	0x923f82a4,0xaf194f9b, 0xab1c5ed5,0xda6d8118
++	.uword	0xd807aa98,0xa3030242, 0x12835b01,0x45706fbe
++	.uword	0x243185be,0x4ee4b28c, 0x550c7dc3,0xd5ffb4e2
++	.uword	0x72be5d74,0xf27b896f, 0x80deb1fe,0x3b1696b1
++	.uword	0x9bdc06a7,0x25c71235, 0xc19bf174,0xcf692694
++	.uword	0xe49b69c1,0x9ef14ad2, 0xefbe4786,0x384f25e3
++	.uword	0x0fc19dc6,0x8b8cd5b5, 0x240ca1cc,0x77ac9c65
++	.uword	0x2de92c6f,0x592b0275, 0x4a7484aa,0x6ea6e483
++	.uword	0x5cb0a9dc,0xbd41fbd4, 0x76f988da,0x831153b5
++	.uword	0x983e5152,0xee66dfab, 0xa831c66d,0x2db43210
++	.uword	0xb00327c8,0x98fb213f, 0xbf597fc7,0xbeef0ee4
++	.uword	0xc6e00bf3,0x3da88fc2, 0xd5a79147,0x930aa725
++	.uword	0x06ca6351,0xe003826f, 0x14292967,0x0a0e6e70
++	.uword	0x27b70a85,0x46d22ffc, 0x2e1b2138,0x5c26c926
++	.uword	0x4d2c6dfc,0x5ac42aed, 0x53380d13,0x9d95b3df
++	.uword	0x650a7354,0x8baf63de, 0x766a0abb,0x3c77b2a8
++	.uword	0x81c2c92e,0x47edaee6, 0x92722c85,0x1482353b
++	.uword	0xa2bfe8a1,0x4cf10364, 0xa81a664b,0xbc423001
++	.uword	0xc24b8b70,0xd0f89791, 0xc76c51a3,0x0654be30
++	.uword	0xd192e819,0xd6ef5218, 0xd6990624,0x5565a910
++	.uword	0xf40e3585,0x5771202a, 0x106aa070,0x32bbd1b8
++	.uword	0x19a4c116,0xb8d2d0c8, 0x1e376c08,0x5141ab53
++	.uword	0x2748774c,0xdf8eeb99, 0x34b0bcb5,0xe19b48a8
++	.uword	0x391c0cb3,0xc5c95a63, 0x4ed8aa4a,0xe3418acb
++	.uword	0x5b9cca4f,0x7763e373, 0x682e6ff3,0xd6b2b8a3
++	.uword	0x748f82ee,0x5defb2fc, 0x78a5636f,0x43172f60
++	.uword	0x84c87814,0xa1f0ab72, 0x8cc70208,0x1a6439ec
++	.uword	0x90befffa,0x23631e28, 0xa4506ceb,0xde82bde9
++	.uword	0xbef9a3f7,0xb2c67915, 0xc67178f2,0xe372532b
++	.uword	0xca273ece,0xea26619c, 0xd186b8c7,0x21c0c207
++	.uword	0xeada7dd6,0xcde0eb1e, 0xf57d4f7f,0xee6ed178
++	.uword	0x06f067aa,0x72176fba, 0x0a637dc5,0xa2c898a6
++	.uword	0x113f9804,0xbef90dae, 0x1b710b35,0x131c471b
++	.uword	0x28db77f5,0x23047d84, 0x32caab7b,0x40c72493
++	.uword	0x3c9ebe0a,0x15c9bebc, 0x431d67c4,0x9c100d4c
++	.uword	0x4cc5d4be,0xcb3e42b6, 0x597f299c,0xfc657e2a
++	.uword	0x5fcb6fab,0x3ad6faec, 0x6c44198c,0x4a475817
++	.cstring "SHA512 block transform for C64x+, CRYPTOGAMS by "
++	.align	4
++___
++
++print $code;
++close STDOUT;
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/sha/asm/sha512-ia64.pl b/CryptoPkg/Library/OpensslLib/openssl/crypto/sha/asm/sha512-ia64.pl
+new file mode 100755
+index 0000000..356a46a
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/sha/asm/sha512-ia64.pl
+@@ -0,0 +1,692 @@
++#! /usr/bin/env perl
++# Copyright 2004-2016 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
++# in the file LICENSE in the source distribution or at
++# https://www.openssl.org/source/license.html
++
++#
++# ====================================================================
++# Written by Andy Polyakov  for the OpenSSL
++# project. The module is, however, dual licensed under OpenSSL and
++# CRYPTOGAMS licenses depending on where you obtain it. For further
++# details see http://www.openssl.org/~appro/cryptogams/.
++# ====================================================================
++#
++# SHA256/512_Transform for Itanium.
++#
++# sha512_block runs in 1003 cycles on Itanium 2, which is almost 50%
++# faster than gcc and >60%(!) faster than code generated by HP-UX
++# compiler (yes, HP-UX is generating slower code, because unlike gcc,
++# it failed to deploy "shift right pair," 'shrp' instruction, which
++# substitutes for 64-bit rotate).
++#
++# 924 cycles long sha256_block outperforms gcc by over factor of 2(!)
++# and HP-UX compiler - by >40% (yes, gcc won sha512_block, but lost
++# this one big time). Note that "formally" 924 is about 100 cycles
++# too much. I mean it's 64 32-bit rounds vs. 80 virtually identical
++# 64-bit ones and 1003*64/80 gives 802. Extra cycles, 2 per round,
++# are spent on extra work to provide for 32-bit rotations. 32-bit
++# rotations are still handled by 'shrp' instruction and for this
++# reason lower 32 bits are deposited to upper half of 64-bit register
++# prior 'shrp' issue. And in order to minimize the amount of such
++# operations, X[16] values are *maintained* with copies of lower
++# halves in upper halves, which is why you'll spot such instructions
++# as custom 'mux2', "parallel 32-bit add," 'padd4' and "parallel
++# 32-bit unsigned right shift," 'pshr4.u' instructions here.
++#
++# Rules of engagement.
++#
++# There is only one integer shifter meaning that if I have two rotate,
++# deposit or extract instructions in adjacent bundles, they shall
++# split [at run-time if they have to]. But note that variable and
++# parallel shifts are performed by multi-media ALU and *are* pairable
++# with rotates [and alike]. On the backside MMALU is rather slow: it
++# takes 2 extra cycles before the result of integer operation is
++# available *to* MMALU and 2(*) extra cycles before the result of MM
++# operation is available "back" *to* integer ALU, not to mention that
++# MMALU itself has 2 cycles latency. However! I explicitly scheduled
++# these MM instructions to avoid MM stalls, so that all these extra
++# latencies get "hidden" in instruction-level parallelism.
++#
++# (*) 2 cycles on Itanium 1 and 1 cycle on Itanium 2. But I schedule
++#     for 2 in order to provide for best *overall* performance,
++#     because on Itanium 1 stall on MM result is accompanied by
++#     pipeline flush, which takes 6 cycles:-(
++#
++# June 2012
++#
++# Improve performance by 15-20%. Note about "rules of engagement"
++# above. Contemporary cores are equipped with additional shifter,
++# so that they should perform even better than below, presumably
++# by ~10%.
++#
++######################################################################
++# Current performance in cycles per processed byte for Itanium 2
++# pre-9000 series [little-endian] system:
++#
++# SHA1(*)	5.7
++# SHA256	12.6
++# SHA512	6.7
++#
++# (*) SHA1 result is presented purely for reference purposes.
++#
++# To generate code, pass the file name with either 256 or 512 in its
++# name and compiler flags.
++
++$output=pop;
++
++if ($output =~ /512.*\.[s|asm]/) {
++	$SZ=8;
++	$BITS=8*$SZ;
++	$LDW="ld8";
++	$STW="st8";
++	$ADD="add";
++	$SHRU="shr.u";
++	$TABLE="K512";
++	$func="sha512_block_data_order";
++	@Sigma0=(28,34,39);
++	@Sigma1=(14,18,41);
++	@sigma0=(1,  8, 7);
++	@sigma1=(19,61, 6);
++	$rounds=80;
++} elsif ($output =~ /256.*\.[s|asm]/) {
++	$SZ=4;
++	$BITS=8*$SZ;
++	$LDW="ld4";
++	$STW="st4";
++	$ADD="padd4";
++	$SHRU="pshr4.u";
++	$TABLE="K256";
++	$func="sha256_block_data_order";
++	@Sigma0=( 2,13,22);
++	@Sigma1=( 6,11,25);
++	@sigma0=( 7,18, 3);
++	@sigma1=(17,19,10);
++	$rounds=64;
++} else { die "nonsense $output"; }
++
++open STDOUT,">$output" || die "can't open $output: $!";
++
++if ($^O eq "hpux") {
++    $ADDP="addp4";
++    for (@ARGV) { $ADDP="add" if (/[\+DD|\-mlp]64/); }
++} else { $ADDP="add"; }
++for (@ARGV)  {	$big_endian=1 if (/\-DB_ENDIAN/);
++		$big_endian=0 if (/\-DL_ENDIAN/);  }
++if (!defined($big_endian))
++             {	$big_endian=(unpack('L',pack('N',1))==1);  }
++
++$code=<<___;
++.ident  \"$output, version 2.0\"
++.ident  \"IA-64 ISA artwork by Andy Polyakov \"
++.explicit
++.text
++
++pfssave=r2;
++lcsave=r3;
++prsave=r14;
++K=r15;
++A_=r16; B_=r17; C_=r18; D_=r19;
++E_=r20; F_=r21; G_=r22; H_=r23;
++T1=r24;	T2=r25;
++s0=r26;	s1=r27;	t0=r28;	t1=r29;
++Ktbl=r30;
++ctx=r31;	// 1st arg
++input=r56;	// 2nd arg
++num=r57;	// 3rd arg
++sgm0=r58;	sgm1=r59;	// small constants
++
++// void $func (SHA_CTX *ctx, const void *in,size_t num[,int host])
++.global	$func#
++.proc	$func#
++.align	32
++.skip	16
++$func:
++	.prologue
++	.save	ar.pfs,pfssave
++{ .mmi;	alloc	pfssave=ar.pfs,3,25,0,24
++	$ADDP	ctx=0,r32		// 1st arg
++	.save	ar.lc,lcsave
++	mov	lcsave=ar.lc	}
++{ .mmi;	$ADDP	input=0,r33		// 2nd arg
++	mov	num=r34			// 3rd arg
++	.save	pr,prsave
++	mov	prsave=pr	};;
++
++	.body
++{ .mib;	add	r8=0*$SZ,ctx
++	add	r9=1*$SZ,ctx	}
++{ .mib;	add	r10=2*$SZ,ctx
++	add	r11=3*$SZ,ctx	};;
++
++// load A-H
++.Lpic_point:
++{ .mmi;	$LDW	A_=[r8],4*$SZ
++	$LDW	B_=[r9],4*$SZ
++	mov	Ktbl=ip		}
++{ .mmi;	$LDW	C_=[r10],4*$SZ
++	$LDW	D_=[r11],4*$SZ
++	mov	sgm0=$sigma0[2]	};;
++{ .mmi;	$LDW	E_=[r8]
++	$LDW	F_=[r9]
++	add	Ktbl=($TABLE#-.Lpic_point),Ktbl		}
++{ .mmi;	$LDW	G_=[r10]
++	$LDW	H_=[r11]
++	cmp.ne	p0,p16=0,r0	};;
++___
++$code.=<<___ if ($BITS==64);
++{ .mii;	and	r8=7,input
++	and	input=~7,input;;
++	cmp.eq	p9,p0=1,r8	}
++{ .mmi;	cmp.eq	p10,p0=2,r8
++	cmp.eq	p11,p0=3,r8
++	cmp.eq	p12,p0=4,r8	}
++{ .mmi;	cmp.eq	p13,p0=5,r8
++	cmp.eq	p14,p0=6,r8
++	cmp.eq	p15,p0=7,r8	};;
++___
++$code.=<<___;
++.L_outer:
++.rotr	R[8],X[16]
++A=R[0]; B=R[1]; C=R[2]; D=R[3]; E=R[4]; F=R[5]; G=R[6]; H=R[7]
++{ .mmi;	ld1	X[15]=[input],$SZ		// eliminated in sha512
++	mov	A=A_
++	mov	ar.lc=14	}
++{ .mmi;	mov	B=B_
++	mov	C=C_
++	mov	D=D_		}
++{ .mmi;	mov	E=E_
++	mov	F=F_
++	mov	ar.ec=2		};;
++{ .mmi;	mov	G=G_
++	mov	H=H_
++	mov	sgm1=$sigma1[2]	}
++{ .mib;	mov	r8=0
++	add	r9=1-$SZ,input
++	brp.loop.imp	.L_first16,.L_first16_end-16	};;
++___
++$t0="A", $t1="E", $code.=<<___ if ($BITS==64);
++// in sha512 case I load whole X[16] at once and take care of alignment...
++{ .mmi;	add	r8=1*$SZ,input
++	add	r9=2*$SZ,input
++	add	r10=3*$SZ,input		};;
++{ .mmb;	$LDW	X[15]=[input],4*$SZ
++	$LDW	X[14]=[r8],4*$SZ
++(p9)	br.cond.dpnt.many	.L1byte	};;
++{ .mmb;	$LDW	X[13]=[r9],4*$SZ
++	$LDW	X[12]=[r10],4*$SZ
++(p10)	br.cond.dpnt.many	.L2byte	};;
++{ .mmb;	$LDW	X[11]=[input],4*$SZ
++	$LDW	X[10]=[r8],4*$SZ
++(p11)	br.cond.dpnt.many	.L3byte	};;
++{ .mmb;	$LDW	X[ 9]=[r9],4*$SZ
++	$LDW	X[ 8]=[r10],4*$SZ
++(p12)	br.cond.dpnt.many	.L4byte	};;
++{ .mmb;	$LDW	X[ 7]=[input],4*$SZ
++	$LDW	X[ 6]=[r8],4*$SZ
++(p13)	br.cond.dpnt.many	.L5byte	};;
++{ .mmb;	$LDW	X[ 5]=[r9],4*$SZ
++	$LDW	X[ 4]=[r10],4*$SZ
++(p14)	br.cond.dpnt.many	.L6byte	};;
++{ .mmb;	$LDW	X[ 3]=[input],4*$SZ
++	$LDW	X[ 2]=[r8],4*$SZ
++(p15)	br.cond.dpnt.many	.L7byte	};;
++{ .mmb;	$LDW	X[ 1]=[r9],4*$SZ
++	$LDW	X[ 0]=[r10],4*$SZ	}
++{ .mib;	mov	r8=0
++	mux1	X[15]=X[15],\@rev		// eliminated on big-endian
++	br.many	.L_first16		};;
++.L1byte:
++{ .mmi;	$LDW	X[13]=[r9],4*$SZ
++	$LDW	X[12]=[r10],4*$SZ
++	shrp	X[15]=X[15],X[14],56	};;
++{ .mmi;	$LDW	X[11]=[input],4*$SZ
++	$LDW	X[10]=[r8],4*$SZ
++	shrp	X[14]=X[14],X[13],56	}
++{ .mmi;	$LDW	X[ 9]=[r9],4*$SZ
++	$LDW	X[ 8]=[r10],4*$SZ
++	shrp	X[13]=X[13],X[12],56	};;
++{ .mmi;	$LDW	X[ 7]=[input],4*$SZ
++	$LDW	X[ 6]=[r8],4*$SZ
++	shrp	X[12]=X[12],X[11],56	}
++{ .mmi;	$LDW	X[ 5]=[r9],4*$SZ
++	$LDW	X[ 4]=[r10],4*$SZ
++	shrp	X[11]=X[11],X[10],56	};;
++{ .mmi;	$LDW	X[ 3]=[input],4*$SZ
++	$LDW	X[ 2]=[r8],4*$SZ
++	shrp	X[10]=X[10],X[ 9],56	}
++{ .mmi;	$LDW	X[ 1]=[r9],4*$SZ
++	$LDW	X[ 0]=[r10],4*$SZ
++	shrp	X[ 9]=X[ 9],X[ 8],56	};;
++{ .mii;	$LDW	T1=[input]
++	shrp	X[ 8]=X[ 8],X[ 7],56
++	shrp	X[ 7]=X[ 7],X[ 6],56	}
++{ .mii;	shrp	X[ 6]=X[ 6],X[ 5],56
++	shrp	X[ 5]=X[ 5],X[ 4],56	};;
++{ .mii;	shrp	X[ 4]=X[ 4],X[ 3],56
++	shrp	X[ 3]=X[ 3],X[ 2],56	}
++{ .mii;	shrp	X[ 2]=X[ 2],X[ 1],56
++	shrp	X[ 1]=X[ 1],X[ 0],56	}
++{ .mib;	shrp	X[ 0]=X[ 0],T1,56	}
++{ .mib;	mov	r8=0
++	mux1	X[15]=X[15],\@rev		// eliminated on big-endian
++	br.many	.L_first16		};;
++.L2byte:
++{ .mmi;	$LDW	X[11]=[input],4*$SZ
++	$LDW	X[10]=[r8],4*$SZ
++	shrp	X[15]=X[15],X[14],48	}
++{ .mmi;	$LDW	X[ 9]=[r9],4*$SZ
++	$LDW	X[ 8]=[r10],4*$SZ
++	shrp	X[14]=X[14],X[13],48	};;
++{ .mmi;	$LDW	X[ 7]=[input],4*$SZ
++	$LDW	X[ 6]=[r8],4*$SZ
++	shrp	X[13]=X[13],X[12],48	}
++{ .mmi;	$LDW	X[ 5]=[r9],4*$SZ
++	$LDW	X[ 4]=[r10],4*$SZ
++	shrp	X[12]=X[12],X[11],48	};;
++{ .mmi;	$LDW	X[ 3]=[input],4*$SZ
++	$LDW	X[ 2]=[r8],4*$SZ
++	shrp	X[11]=X[11],X[10],48	}
++{ .mmi;	$LDW	X[ 1]=[r9],4*$SZ
++	$LDW	X[ 0]=[r10],4*$SZ
++	shrp	X[10]=X[10],X[ 9],48	};;
++{ .mii;	$LDW	T1=[input]
++	shrp	X[ 9]=X[ 9],X[ 8],48
++	shrp	X[ 8]=X[ 8],X[ 7],48	}
++{ .mii;	shrp	X[ 7]=X[ 7],X[ 6],48
++	shrp	X[ 6]=X[ 6],X[ 5],48	};;
++{ .mii;	shrp	X[ 5]=X[ 5],X[ 4],48
++	shrp	X[ 4]=X[ 4],X[ 3],48	}
++{ .mii;	shrp	X[ 3]=X[ 3],X[ 2],48
++	shrp	X[ 2]=X[ 2],X[ 1],48	}
++{ .mii;	shrp	X[ 1]=X[ 1],X[ 0],48
++	shrp	X[ 0]=X[ 0],T1,48	}
++{ .mib;	mov	r8=0
++	mux1	X[15]=X[15],\@rev		// eliminated on big-endian
++	br.many	.L_first16		};;
++.L3byte:
++{ .mmi;	$LDW	X[ 9]=[r9],4*$SZ
++	$LDW	X[ 8]=[r10],4*$SZ
++	shrp	X[15]=X[15],X[14],40	};;
++{ .mmi;	$LDW	X[ 7]=[input],4*$SZ
++	$LDW	X[ 6]=[r8],4*$SZ
++	shrp	X[14]=X[14],X[13],40	}
++{ .mmi;	$LDW	X[ 5]=[r9],4*$SZ
++	$LDW	X[ 4]=[r10],4*$SZ
++	shrp	X[13]=X[13],X[12],40	};;
++{ .mmi;	$LDW	X[ 3]=[input],4*$SZ
++	$LDW	X[ 2]=[r8],4*$SZ
++	shrp	X[12]=X[12],X[11],40	}
++{ .mmi;	$LDW	X[ 1]=[r9],4*$SZ
++	$LDW	X[ 0]=[r10],4*$SZ
++	shrp	X[11]=X[11],X[10],40	};;
++{ .mii;	$LDW	T1=[input]
++	shrp	X[10]=X[10],X[ 9],40
++	shrp	X[ 9]=X[ 9],X[ 8],40	}
++{ .mii;	shrp	X[ 8]=X[ 8],X[ 7],40
++	shrp	X[ 7]=X[ 7],X[ 6],40	};;
++{ .mii;	shrp	X[ 6]=X[ 6],X[ 5],40
++	shrp	X[ 5]=X[ 5],X[ 4],40	}
++{ .mii;	shrp	X[ 4]=X[ 4],X[ 3],40
++	shrp	X[ 3]=X[ 3],X[ 2],40	}
++{ .mii;	shrp	X[ 2]=X[ 2],X[ 1],40
++	shrp	X[ 1]=X[ 1],X[ 0],40	}
++{ .mib;	shrp	X[ 0]=X[ 0],T1,40	}
++{ .mib;	mov	r8=0
++	mux1	X[15]=X[15],\@rev		// eliminated on big-endian
++	br.many	.L_first16		};;
++.L4byte:
++{ .mmi;	$LDW	X[ 7]=[input],4*$SZ
++	$LDW	X[ 6]=[r8],4*$SZ
++	shrp	X[15]=X[15],X[14],32	}
++{ .mmi;	$LDW	X[ 5]=[r9],4*$SZ
++	$LDW	X[ 4]=[r10],4*$SZ
++	shrp	X[14]=X[14],X[13],32	};;
++{ .mmi;	$LDW	X[ 3]=[input],4*$SZ
++	$LDW	X[ 2]=[r8],4*$SZ
++	shrp	X[13]=X[13],X[12],32	}
++{ .mmi;	$LDW	X[ 1]=[r9],4*$SZ
++	$LDW	X[ 0]=[r10],4*$SZ
++	shrp	X[12]=X[12],X[11],32	};;
++{ .mii;	$LDW	T1=[input]
++	shrp	X[11]=X[11],X[10],32
++	shrp	X[10]=X[10],X[ 9],32	}
++{ .mii;	shrp	X[ 9]=X[ 9],X[ 8],32
++	shrp	X[ 8]=X[ 8],X[ 7],32	};;
++{ .mii;	shrp	X[ 7]=X[ 7],X[ 6],32
++	shrp	X[ 6]=X[ 6],X[ 5],32	}
++{ .mii;	shrp	X[ 5]=X[ 5],X[ 4],32
++	shrp	X[ 4]=X[ 4],X[ 3],32	}
++{ .mii;	shrp	X[ 3]=X[ 3],X[ 2],32
++	shrp	X[ 2]=X[ 2],X[ 1],32	}
++{ .mii;	shrp	X[ 1]=X[ 1],X[ 0],32
++	shrp	X[ 0]=X[ 0],T1,32	}
++{ .mib;	mov	r8=0
++	mux1	X[15]=X[15],\@rev		// eliminated on big-endian
++	br.many	.L_first16		};;
++.L5byte:
++{ .mmi;	$LDW	X[ 5]=[r9],4*$SZ
++	$LDW	X[ 4]=[r10],4*$SZ
++	shrp	X[15]=X[15],X[14],24	};;
++{ .mmi;	$LDW	X[ 3]=[input],4*$SZ
++	$LDW	X[ 2]=[r8],4*$SZ
++	shrp	X[14]=X[14],X[13],24	}
++{ .mmi;	$LDW	X[ 1]=[r9],4*$SZ
++	$LDW	X[ 0]=[r10],4*$SZ
++	shrp	X[13]=X[13],X[12],24	};;
++{ .mii;	$LDW	T1=[input]
++	shrp	X[12]=X[12],X[11],24
++	shrp	X[11]=X[11],X[10],24	}
++{ .mii;	shrp	X[10]=X[10],X[ 9],24
++	shrp	X[ 9]=X[ 9],X[ 8],24	};;
++{ .mii;	shrp	X[ 8]=X[ 8],X[ 7],24
++	shrp	X[ 7]=X[ 7],X[ 6],24	}
++{ .mii;	shrp	X[ 6]=X[ 6],X[ 5],24
++	shrp	X[ 5]=X[ 5],X[ 4],24	}
++{ .mii;	shrp	X[ 4]=X[ 4],X[ 3],24
++	shrp	X[ 3]=X[ 3],X[ 2],24	}
++{ .mii;	shrp	X[ 2]=X[ 2],X[ 1],24
++	shrp	X[ 1]=X[ 1],X[ 0],24	}
++{ .mib;	shrp	X[ 0]=X[ 0],T1,24	}
++{ .mib;	mov	r8=0
++	mux1	X[15]=X[15],\@rev		// eliminated on big-endian
++	br.many	.L_first16		};;
++.L6byte:
++{ .mmi;	$LDW	X[ 3]=[input],4*$SZ
++	$LDW	X[ 2]=[r8],4*$SZ
++	shrp	X[15]=X[15],X[14],16	}
++{ .mmi;	$LDW	X[ 1]=[r9],4*$SZ
++	$LDW	X[ 0]=[r10],4*$SZ
++	shrp	X[14]=X[14],X[13],16	};;
++{ .mii;	$LDW	T1=[input]
++	shrp	X[13]=X[13],X[12],16
++	shrp	X[12]=X[12],X[11],16	}
++{ .mii;	shrp	X[11]=X[11],X[10],16
++	shrp	X[10]=X[10],X[ 9],16	};;
++{ .mii;	shrp	X[ 9]=X[ 9],X[ 8],16
++	shrp	X[ 8]=X[ 8],X[ 7],16	}
++{ .mii;	shrp	X[ 7]=X[ 7],X[ 6],16
++	shrp	X[ 6]=X[ 6],X[ 5],16	}
++{ .mii;	shrp	X[ 5]=X[ 5],X[ 4],16
++	shrp	X[ 4]=X[ 4],X[ 3],16	}
++{ .mii;	shrp	X[ 3]=X[ 3],X[ 2],16
++	shrp	X[ 2]=X[ 2],X[ 1],16	}
++{ .mii;	shrp	X[ 1]=X[ 1],X[ 0],16
++	shrp	X[ 0]=X[ 0],T1,16	}
++{ .mib;	mov	r8=0
++	mux1	X[15]=X[15],\@rev		// eliminated on big-endian
++	br.many	.L_first16		};;
++.L7byte:
++{ .mmi;	$LDW	X[ 1]=[r9],4*$SZ
++	$LDW	X[ 0]=[r10],4*$SZ
++	shrp	X[15]=X[15],X[14],8	};;
++{ .mii;	$LDW	T1=[input]
++	shrp	X[14]=X[14],X[13],8
++	shrp	X[13]=X[13],X[12],8	}
++{ .mii;	shrp	X[12]=X[12],X[11],8
++	shrp	X[11]=X[11],X[10],8	};;
++{ .mii;	shrp	X[10]=X[10],X[ 9],8
++	shrp	X[ 9]=X[ 9],X[ 8],8	}
++{ .mii;	shrp	X[ 8]=X[ 8],X[ 7],8
++	shrp	X[ 7]=X[ 7],X[ 6],8	}
++{ .mii;	shrp	X[ 6]=X[ 6],X[ 5],8
++	shrp	X[ 5]=X[ 5],X[ 4],8	}
++{ .mii;	shrp	X[ 4]=X[ 4],X[ 3],8
++	shrp	X[ 3]=X[ 3],X[ 2],8	}
++{ .mii;	shrp	X[ 2]=X[ 2],X[ 1],8
++	shrp	X[ 1]=X[ 1],X[ 0],8	}
++{ .mib;	shrp	X[ 0]=X[ 0],T1,8	}
++{ .mib;	mov	r8=0
++	mux1	X[15]=X[15],\@rev	};;	// eliminated on big-endian
++
++.align	32
++.L_first16:
++{ .mmi;		$LDW	K=[Ktbl],$SZ
++		add	A=A,r8			// H+=Sigma(0) from the past
++		_rotr	r10=$t1,$Sigma1[0]  }	// ROTR(e,14)
++{ .mmi;		and	T1=F,E
++		andcm	r8=G,E
++	(p16)	mux1	X[14]=X[14],\@rev   };;	// eliminated on big-endian
++{ .mmi;		and	T2=A,B
++		and	r9=A,C
++		_rotr	r11=$t1,$Sigma1[1]  }	// ROTR(e,41)
++{ .mmi;		xor	T1=T1,r8		// T1=((e & f) ^ (~e & g))
++		and	r8=B,C		    };;
++___
++$t0="t0", $t1="t1", $code.=<<___ if ($BITS==32);
++.align	32
++.L_first16:
++{ .mmi;		add	A=A,r8			// H+=Sigma(0) from the past
++		add	r10=2-$SZ,input
++		add	r11=3-$SZ,input	};;
++{ .mmi;		ld1	r9=[r9]
++		ld1	r10=[r10]
++		dep.z	$t1=E,32,32	}
++{ .mmi;		ld1	r11=[r11]
++		$LDW	K=[Ktbl],$SZ
++		zxt4	E=E		};;
++{ .mii;		or	$t1=$t1,E
++		dep	X[15]=X[15],r9,8,8
++		mux2	$t0=A,0x44	};;	// copy lower half to upper
++{ .mmi;		and	T1=F,E
++		andcm	r8=G,E
++		dep	r11=r10,r11,8,8	};;
++{ .mmi;		and	T2=A,B
++		and	r9=A,C
++		dep	X[15]=X[15],r11,16,16	};;
++{ .mmi;	(p16)	ld1	X[15-1]=[input],$SZ	// prefetch
++		xor	T1=T1,r8		// T1=((e & f) ^ (~e & g))
++		_rotr	r10=$t1,$Sigma1[0] }	// ROTR(e,14)
++{ .mmi;		and	r8=B,C
++		_rotr	r11=$t1,$Sigma1[1] };;	// ROTR(e,18)
++___
++$code.=<<___;
++{ .mmi;		add	T1=T1,H			// T1=Ch(e,f,g)+h
++		xor	r10=r10,r11
++		_rotr	r11=$t1,$Sigma1[2]  }	// ROTR(e,41)
++{ .mmi;		xor	T2=T2,r9
++		add	K=K,X[15]	    };;
++{ .mmi;		add	T1=T1,K			// T1+=K[i]+X[i]
++		xor	T2=T2,r8		// T2=((a & b) ^ (a & c) ^ (b & c))
++		_rotr	r8=$t0,$Sigma0[0]   }	// ROTR(a,28)
++{ .mmi;		xor	r11=r11,r10		// Sigma1(e)
++		_rotr	r9=$t0,$Sigma0[1]   };;	// ROTR(a,34)
++{ .mmi;		add	T1=T1,r11		// T+=Sigma1(e)
++		xor	r8=r8,r9
++		_rotr	r9=$t0,$Sigma0[2]   };;	// ROTR(a,39)
++{ .mmi;		xor	r8=r8,r9		// Sigma0(a)
++		add	D=D,T1
++		mux2	H=X[15],0x44	    }	// mov H=X[15] in sha512
++{ .mib;	(p16)	add	r9=1-$SZ,input		// not used in sha512
++		add	X[15]=T1,T2		// H=T1+Maj(a,b,c)
++	br.ctop.sptk	.L_first16	    };;
++.L_first16_end:
++
++{ .mib;	mov	ar.lc=$rounds-17
++	brp.loop.imp	.L_rest,.L_rest_end-16		}
++{ .mib;	mov	ar.ec=1
++	br.many	.L_rest			};;
++
++.align	32
++.L_rest:
++{ .mmi;		$LDW	K=[Ktbl],$SZ
++		add	A=A,r8			// H+=Sigma0(a) from the past
++		_rotr	r8=X[15-1],$sigma0[0] }	// ROTR(s0,1)
++{ .mmi; 	add	X[15]=X[15],X[15-9]	// X[i&0xF]+=X[(i+9)&0xF]
++		$SHRU	s0=X[15-1],sgm0	    };;	// s0=X[(i+1)&0xF]>>7
++{ .mib;		and	T1=F,E
++		_rotr	r9=X[15-1],$sigma0[1] }	// ROTR(s0,8)
++{ .mib;		andcm	r10=G,E
++		$SHRU	s1=X[15-14],sgm1    };;	// s1=X[(i+14)&0xF]>>6
++// Pair of mmi; splits on Itanium 1 and prevents pipeline flush
++// upon $SHRU output usage
++{ .mmi;		xor	T1=T1,r10		// T1=((e & f) ^ (~e & g))
++		xor	r9=r8,r9
++		_rotr	r10=X[15-14],$sigma1[0] }// ROTR(s1,19)
++{ .mmi;		and	T2=A,B
++		and	r8=A,C
++		_rotr	r11=X[15-14],$sigma1[1] };;// ROTR(s1,61)
++___
++$t0="t0", $t1="t1", $code.=<<___ if ($BITS==32);
++{ .mib;		xor	s0=s0,r9		// s0=sigma0(X[(i+1)&0xF])
++		dep.z	$t1=E,32,32	    }
++{ .mib;		xor	r10=r11,r10
++		zxt4	E=E		    };;
++{ .mii;		xor	s1=s1,r10		// s1=sigma1(X[(i+14)&0xF])
++		shrp	r9=E,$t1,32+$Sigma1[0]	// ROTR(e,14)
++		mux2	$t0=A,0x44	    };;	// copy lower half to upper
++// Pair of mmi; splits on Itanium 1 and prevents pipeline flush
++// upon mux2 output usage
++{ .mmi;		xor	T2=T2,r8
++		shrp	r8=E,$t1,32+$Sigma1[1]}	// ROTR(e,18)
++{ .mmi;		and	r10=B,C
++		add	T1=T1,H			// T1=Ch(e,f,g)+h
++		or	$t1=$t1,E   	    };;
++___
++$t0="A", $t1="E", $code.=<<___ if ($BITS==64);
++{ .mib;		xor	s0=s0,r9		// s0=sigma0(X[(i+1)&0xF])
++		_rotr	r9=$t1,$Sigma1[0]   }	// ROTR(e,14)
++{ .mib;		xor	r10=r11,r10
++		xor	T2=T2,r8	    };;
++{ .mib;		xor	s1=s1,r10		// s1=sigma1(X[(i+14)&0xF])
++		_rotr	r8=$t1,$Sigma1[1]   }	// ROTR(e,18)
++{ .mib;		and	r10=B,C
++		add	T1=T1,H		    };;	// T1+=H
++___
++$code.=<<___;
++{ .mib;		xor	r9=r9,r8
++		_rotr	r8=$t1,$Sigma1[2]   }	// ROTR(e,41)
++{ .mib;		xor	T2=T2,r10		// T2=((a & b) ^ (a & c) ^ (b & c))
++		add	X[15]=X[15],s0	    };;	// X[i]+=sigma0(X[i+1])
++{ .mmi;		xor	r9=r9,r8		// Sigma1(e)
++		add	X[15]=X[15],s1		// X[i]+=sigma0(X[i+14])
++		_rotr	r8=$t0,$Sigma0[0]   };;	// ROTR(a,28)
++{ .mmi;		add	K=K,X[15]
++		add	T1=T1,r9		// T1+=Sigma1(e)
++		_rotr	r9=$t0,$Sigma0[1]   };;	// ROTR(a,34)
++{ .mmi;		add	T1=T1,K			// T1+=K[i]+X[i]
++		xor	r8=r8,r9
++		_rotr	r9=$t0,$Sigma0[2]   };;	// ROTR(a,39)
++{ .mib;		add	D=D,T1
++		mux2	H=X[15],0x44	    }	// mov H=X[15] in sha512
++{ .mib;		xor	r8=r8,r9		// Sigma0(a)
++		add	X[15]=T1,T2		// H=T1+Maj(a,b,c)
++	br.ctop.sptk	.L_rest		    };;
++.L_rest_end:
++
++{ .mmi;	add	A=A,r8			};;	// H+=Sigma0(a) from the past
++{ .mmi;	add	A_=A_,A
++	add	B_=B_,B
++	add	C_=C_,C			}
++{ .mmi;	add	D_=D_,D
++	add	E_=E_,E
++	cmp.ltu	p16,p0=1,num		};;
++{ .mmi;	add	F_=F_,F
++	add	G_=G_,G
++	add	H_=H_,H			}
++{ .mmb;	add	Ktbl=-$SZ*$rounds,Ktbl
++(p16)	add	num=-1,num
++(p16)	br.dptk.many	.L_outer	};;
++
++{ .mib;	add	r8=0*$SZ,ctx
++	add	r9=1*$SZ,ctx		}
++{ .mib;	add	r10=2*$SZ,ctx
++	add	r11=3*$SZ,ctx		};;
++{ .mmi;	$STW	[r8]=A_,4*$SZ
++	$STW	[r9]=B_,4*$SZ
++	mov	ar.lc=lcsave		}
++{ .mmi;	$STW	[r10]=C_,4*$SZ
++	$STW	[r11]=D_,4*$SZ
++	mov	pr=prsave,0x1ffff	};;
++{ .mmb;	$STW	[r8]=E_
++	$STW	[r9]=F_			}
++{ .mmb;	$STW	[r10]=G_
++	$STW	[r11]=H_
++	br.ret.sptk.many	b0	};;
++.endp	$func#
++___
++
++foreach(split($/,$code)) {
++    s/\`([^\`]*)\`/eval $1/gem;
++    s/_rotr(\s+)([^=]+)=([^,]+),([0-9]+)/shrp$1$2=$3,$3,$4/gm;
++    if ($BITS==64) {
++	s/mux2(\s+)([^=]+)=([^,]+),\S+/mov$1 $2=$3/gm;
++	s/mux1(\s+)\S+/nop.i$1 0x0/gm	if ($big_endian);
++	s/(shrp\s+X\[[^=]+)=([^,]+),([^,]+),([1-9]+)/$1=$3,$2,64-$4/gm
++    						if (!$big_endian);
++	s/ld1(\s+)X\[\S+/nop.m$1 0x0/gm;
++    }
++
++    print $_,"\n";
++}
++
++print<<___ if ($BITS==32);
++.align	64
++.type	K256#,\@object
++K256:	data4	0x428a2f98,0x71374491,0xb5c0fbcf,0xe9b5dba5
++	data4	0x3956c25b,0x59f111f1,0x923f82a4,0xab1c5ed5
++	data4	0xd807aa98,0x12835b01,0x243185be,0x550c7dc3
++	data4	0x72be5d74,0x80deb1fe,0x9bdc06a7,0xc19bf174
++	data4	0xe49b69c1,0xefbe4786,0x0fc19dc6,0x240ca1cc
++	data4	0x2de92c6f,0x4a7484aa,0x5cb0a9dc,0x76f988da
++	data4	0x983e5152,0xa831c66d,0xb00327c8,0xbf597fc7
++	data4	0xc6e00bf3,0xd5a79147,0x06ca6351,0x14292967
++	data4	0x27b70a85,0x2e1b2138,0x4d2c6dfc,0x53380d13
++	data4	0x650a7354,0x766a0abb,0x81c2c92e,0x92722c85
++	data4	0xa2bfe8a1,0xa81a664b,0xc24b8b70,0xc76c51a3
++	data4	0xd192e819,0xd6990624,0xf40e3585,0x106aa070
++	data4	0x19a4c116,0x1e376c08,0x2748774c,0x34b0bcb5
++	data4	0x391c0cb3,0x4ed8aa4a,0x5b9cca4f,0x682e6ff3
++	data4	0x748f82ee,0x78a5636f,0x84c87814,0x8cc70208
++	data4	0x90befffa,0xa4506ceb,0xbef9a3f7,0xc67178f2
++.size	K256#,$SZ*$rounds
++stringz	"SHA256 block transform for IA64, CRYPTOGAMS by "
++___
++print<<___ if ($BITS==64);
++.align	64
++.type	K512#,\@object
++K512:	data8	0x428a2f98d728ae22,0x7137449123ef65cd
++	data8	0xb5c0fbcfec4d3b2f,0xe9b5dba58189dbbc
++	data8	0x3956c25bf348b538,0x59f111f1b605d019
++	data8	0x923f82a4af194f9b,0xab1c5ed5da6d8118
++	data8	0xd807aa98a3030242,0x12835b0145706fbe
++	data8	0x243185be4ee4b28c,0x550c7dc3d5ffb4e2
++	data8	0x72be5d74f27b896f,0x80deb1fe3b1696b1
++	data8	0x9bdc06a725c71235,0xc19bf174cf692694
++	data8	0xe49b69c19ef14ad2,0xefbe4786384f25e3
++	data8	0x0fc19dc68b8cd5b5,0x240ca1cc77ac9c65
++	data8	0x2de92c6f592b0275,0x4a7484aa6ea6e483
++	data8	0x5cb0a9dcbd41fbd4,0x76f988da831153b5
++	data8	0x983e5152ee66dfab,0xa831c66d2db43210
++	data8	0xb00327c898fb213f,0xbf597fc7beef0ee4
++	data8	0xc6e00bf33da88fc2,0xd5a79147930aa725
++	data8	0x06ca6351e003826f,0x142929670a0e6e70
++	data8	0x27b70a8546d22ffc,0x2e1b21385c26c926
++	data8	0x4d2c6dfc5ac42aed,0x53380d139d95b3df
++	data8	0x650a73548baf63de,0x766a0abb3c77b2a8
++	data8	0x81c2c92e47edaee6,0x92722c851482353b
++	data8	0xa2bfe8a14cf10364,0xa81a664bbc423001
++	data8	0xc24b8b70d0f89791,0xc76c51a30654be30
++	data8	0xd192e819d6ef5218,0xd69906245565a910
++	data8	0xf40e35855771202a,0x106aa07032bbd1b8
++	data8	0x19a4c116b8d2d0c8,0x1e376c085141ab53
++	data8	0x2748774cdf8eeb99,0x34b0bcb5e19b48a8
++	data8	0x391c0cb3c5c95a63,0x4ed8aa4ae3418acb
++	data8	0x5b9cca4f7763e373,0x682e6ff3d6b2b8a3
++	data8	0x748f82ee5defb2fc,0x78a5636f43172f60
++	data8	0x84c87814a1f0ab72,0x8cc702081a6439ec
++	data8	0x90befffa23631e28,0xa4506cebde82bde9
++	data8	0xbef9a3f7b2c67915,0xc67178f2e372532b
++	data8	0xca273eceea26619c,0xd186b8c721c0c207
++	data8	0xeada7dd6cde0eb1e,0xf57d4f7fee6ed178
++	data8	0x06f067aa72176fba,0x0a637dc5a2c898a6
++	data8	0x113f9804bef90dae,0x1b710b35131c471b
++	data8	0x28db77f523047d84,0x32caab7b40c72493
++	data8	0x3c9ebe0a15c9bebc,0x431d67c49c100d4c
++	data8	0x4cc5d4becb3e42b6,0x597f299cfc657e2a
++	data8	0x5fcb6fab3ad6faec,0x6c44198c4a475817
++.size	K512#,$SZ*$rounds
++stringz	"SHA512 block transform for IA64, CRYPTOGAMS by "
++___
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/sha/asm/sha512-mips.pl b/CryptoPkg/Library/OpensslLib/openssl/crypto/sha/asm/sha512-mips.pl
+new file mode 100644
+index 0000000..5c2d23f
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/sha/asm/sha512-mips.pl
+@@ -0,0 +1,519 @@
++#! /usr/bin/env perl
++# Copyright 2010-2016 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
++# in the file LICENSE in the source distribution or at
++# https://www.openssl.org/source/license.html
++
++
++# ====================================================================
++# Written by Andy Polyakov  for the OpenSSL
++# project. The module is, however, dual licensed under OpenSSL and
++# CRYPTOGAMS licenses depending on where you obtain it. For further
++# details see http://www.openssl.org/~appro/cryptogams/.
++# ====================================================================
++
++# SHA2 block procedures for MIPS.
++
++# October 2010.
++#
++# SHA256 performance improvement on MIPS R5000 CPU is ~27% over gcc-
++# generated code in o32 build and ~55% in n32/64 build. SHA512 [which
++# for now can only be compiled for MIPS64 ISA] improvement is modest
++# ~17%, but it comes for free, because it's same instruction sequence.
++# Improvement coefficients are for aligned input.
++
++# September 2012.
++#
++# Add MIPS[32|64]R2 code (>25% less instructions).
++
++######################################################################
++# There is a number of MIPS ABI in use, O32 and N32/64 are most
++# widely used. Then there is a new contender: NUBI. It appears that if
++# one picks the latter, it's possible to arrange code in ABI neutral
++# manner. Therefore let's stick to NUBI register layout:
++#
++($zero,$at,$t0,$t1,$t2)=map("\$$_",(0..2,24,25));
++($a0,$a1,$a2,$a3,$a4,$a5,$a6,$a7)=map("\$$_",(4..11));
++($s0,$s1,$s2,$s3,$s4,$s5,$s6,$s7,$s8,$s9,$s10,$s11)=map("\$$_",(12..23));
++($gp,$tp,$sp,$fp,$ra)=map("\$$_",(3,28..31));
++#
++# The return value is placed in $a0. Following coding rules facilitate
++# interoperability:
++#
++# - never ever touch $tp, "thread pointer", former $gp [o32 can be
++#   excluded from the rule, because it's specified volatile];
++# - copy return value to $t0, former $v0 [or to $a0 if you're adapting
++#   old code];
++# - on O32 populate $a4-$a7 with 'lw $aN,4*N($sp)' if necessary;
++#
++# For reference here is register layout for N32/64 MIPS ABIs:
++#
++# ($zero,$at,$v0,$v1)=map("\$$_",(0..3));
++# ($a0,$a1,$a2,$a3,$a4,$a5,$a6,$a7)=map("\$$_",(4..11));
++# ($t0,$t1,$t2,$t3,$t8,$t9)=map("\$$_",(12..15,24,25));
++# ($s0,$s1,$s2,$s3,$s4,$s5,$s6,$s7)=map("\$$_",(16..23));
++# ($gp,$sp,$fp,$ra)=map("\$$_",(28..31));
++#
++$flavour = shift || "o32"; # supported flavours are o32,n32,64,nubi32,nubi64
++
++if ($flavour =~ /64|n32/i) {
++	$PTR_LA="dla";
++	$PTR_ADD="dadd";	# incidentally works even on n32
++	$PTR_SUB="dsub";	# incidentally works even on n32
++	$REG_S="sd";
++	$REG_L="ld";
++	$PTR_SLL="dsll";	# incidentally works even on n32
++	$SZREG=8;
++} else {
++	$PTR_LA="la";
++	$PTR_ADD="add";
++	$PTR_SUB="sub";
++	$REG_S="sw";
++	$REG_L="lw";
++	$PTR_SLL="sll";
++	$SZREG=4;
++}
++$pf = ($flavour =~ /nubi/i) ? $t0 : $t2;
++#
++# 
++#
++######################################################################
++
++$big_endian=(`echo MIPSEL | $ENV{CC} -E -`=~/MIPSEL/)?1:0 if ($ENV{CC});
++
++for (@ARGV) {	$output=$_ if (/\w[\w\-]*\.\w+$/);	}
++open STDOUT,">$output";
++
++if (!defined($big_endian)) { $big_endian=(unpack('L',pack('N',1))==1); }
++
++if ($output =~ /512/) {
++	$label="512";
++	$SZ=8;
++	$LD="ld";		# load from memory
++	$ST="sd";		# store to memory
++	$SLL="dsll";		# shift left logical
++	$SRL="dsrl";		# shift right logical
++	$ADDU="daddu";
++	$ROTR="drotr";
++	@Sigma0=(28,34,39);
++	@Sigma1=(14,18,41);
++	@sigma0=( 7, 1, 8);	# right shift first
++	@sigma1=( 6,19,61);	# right shift first
++	$lastK=0x817;
++	$rounds=80;
++} else {
++	$label="256";
++	$SZ=4;
++	$LD="lw";		# load from memory
++	$ST="sw";		# store to memory
++	$SLL="sll";		# shift left logical
++	$SRL="srl";		# shift right logical
++	$ADDU="addu";
++	$ROTR="rotr";
++	@Sigma0=( 2,13,22);
++	@Sigma1=( 6,11,25);
++	@sigma0=( 3, 7,18);	# right shift first
++	@sigma1=(10,17,19);	# right shift first
++	$lastK=0x8f2;
++	$rounds=64;
++}
++
++$MSB = $big_endian ? 0 : ($SZ-1);
++$LSB = ($SZ-1)&~$MSB;
++
++@V=($A,$B,$C,$D,$E,$F,$G,$H)=map("\$$_",(1,2,3,7,24,25,30,31));
++@X=map("\$$_",(8..23));
++
++$ctx=$a0;
++$inp=$a1;
++$len=$a2;	$Ktbl=$len;
++
++sub BODY_00_15 {
++my ($i,$a,$b,$c,$d,$e,$f,$g,$h)=@_;
++my ($T1,$tmp0,$tmp1,$tmp2)=(@X[4],@X[5],@X[6],@X[7]);
++
++$code.=<<___ if ($i<15);
++	${LD}l	@X[1],`($i+1)*$SZ+$MSB`($inp)
++	${LD}r	@X[1],`($i+1)*$SZ+$LSB`($inp)
++___
++$code.=<<___	if (!$big_endian && $i<16 && $SZ==4);
++#if defined(_MIPS_ARCH_MIPS32R2) || defined(_MIPS_ARCH_MIPS64R2)
++	wsbh	@X[0],@X[0]		# byte swap($i)
++	rotr	@X[0],@X[0],16
++#else
++	srl	$tmp0,@X[0],24		# byte swap($i)
++	srl	$tmp1,@X[0],8
++	andi	$tmp2,@X[0],0xFF00
++	sll	@X[0],@X[0],24
++	andi	$tmp1,0xFF00
++	sll	$tmp2,$tmp2,8
++	or	@X[0],$tmp0
++	or	$tmp1,$tmp2
++	or	@X[0],$tmp1
++#endif
++___
++$code.=<<___	if (!$big_endian && $i<16 && $SZ==8);
++#if defined(_MIPS_ARCH_MIPS64R2)
++	dsbh	@X[0],@X[0]		# byte swap($i)
++	dshd	@X[0],@X[0]
++#else
++	ori	$tmp0,$zero,0xFF
++	dsll	$tmp2,$tmp0,32
++	or	$tmp0,$tmp2		# 0x000000FF000000FF
++	and	$tmp1,@X[0],$tmp0	# byte swap($i)
++	dsrl	$tmp2,@X[0],24
++	dsll	$tmp1,24
++	and	$tmp2,$tmp0
++	dsll	$tmp0,8			# 0x0000FF000000FF00
++	or	$tmp1,$tmp2
++	and	$tmp2,@X[0],$tmp0
++	dsrl	@X[0],8
++	dsll	$tmp2,8
++	and	@X[0],$tmp0
++	or	$tmp1,$tmp2
++	or	@X[0],$tmp1
++	dsrl	$tmp1,@X[0],32
++	dsll	@X[0],32
++	or	@X[0],$tmp1
++#endif
++___
++$code.=<<___;
++#if defined(_MIPS_ARCH_MIPS32R2) || defined(_MIPS_ARCH_MIPS64R2)
++	xor	$tmp2,$f,$g			# $i
++	$ROTR	$tmp0,$e,@Sigma1[0]
++	$ADDU	$T1,$X[0],$h
++	$ROTR	$tmp1,$e,@Sigma1[1]
++	and	$tmp2,$e
++	$ROTR	$h,$e,@Sigma1[2]
++	xor	$tmp0,$tmp1
++	$ROTR	$tmp1,$a,@Sigma0[0]
++	xor	$tmp2,$g			# Ch(e,f,g)
++	xor	$tmp0,$h			# Sigma1(e)
++
++	$ROTR	$h,$a,@Sigma0[1]
++	$ADDU	$T1,$tmp2
++	$LD	$tmp2,`$i*$SZ`($Ktbl)		# K[$i]
++	xor	$h,$tmp1
++	$ROTR	$tmp1,$a,@Sigma0[2]
++	$ADDU	$T1,$tmp0
++	and	$tmp0,$b,$c
++	xor	$h,$tmp1			# Sigma0(a)
++	xor	$tmp1,$b,$c
++#else
++	$ADDU	$T1,$X[0],$h			# $i
++	$SRL	$h,$e,@Sigma1[0]
++	xor	$tmp2,$f,$g
++	$SLL	$tmp1,$e,`$SZ*8-@Sigma1[2]`
++	and	$tmp2,$e
++	$SRL	$tmp0,$e,@Sigma1[1]
++	xor	$h,$tmp1
++	$SLL	$tmp1,$e,`$SZ*8-@Sigma1[1]`
++	xor	$h,$tmp0
++	$SRL	$tmp0,$e,@Sigma1[2]
++	xor	$h,$tmp1
++	$SLL	$tmp1,$e,`$SZ*8-@Sigma1[0]`
++	xor	$h,$tmp0
++	xor	$tmp2,$g			# Ch(e,f,g)
++	xor	$tmp0,$tmp1,$h			# Sigma1(e)
++
++	$SRL	$h,$a,@Sigma0[0]
++	$ADDU	$T1,$tmp2
++	$LD	$tmp2,`$i*$SZ`($Ktbl)		# K[$i]
++	$SLL	$tmp1,$a,`$SZ*8-@Sigma0[2]`
++	$ADDU	$T1,$tmp0
++	$SRL	$tmp0,$a,@Sigma0[1]
++	xor	$h,$tmp1
++	$SLL	$tmp1,$a,`$SZ*8-@Sigma0[1]`
++	xor	$h,$tmp0
++	$SRL	$tmp0,$a,@Sigma0[2]
++	xor	$h,$tmp1
++	$SLL	$tmp1,$a,`$SZ*8-@Sigma0[0]`
++	xor	$h,$tmp0
++	and	$tmp0,$b,$c
++	xor	$h,$tmp1			# Sigma0(a)
++	xor	$tmp1,$b,$c
++#endif
++	$ST	@X[0],`($i%16)*$SZ`($sp)	# offload to ring buffer
++	$ADDU	$h,$tmp0
++	and	$tmp1,$a
++	$ADDU	$T1,$tmp2			# +=K[$i]
++	$ADDU	$h,$tmp1			# +=Maj(a,b,c)
++	$ADDU	$d,$T1
++	$ADDU	$h,$T1
++___
++$code.=<<___ if ($i>=13);
++	$LD	@X[3],`(($i+3)%16)*$SZ`($sp)	# prefetch from ring buffer
++___
++}
++
++sub BODY_16_XX {
++my $i=@_[0];
++my ($tmp0,$tmp1,$tmp2,$tmp3)=(@X[4],@X[5],@X[6],@X[7]);
++
++$code.=<<___;
++#if defined(_MIPS_ARCH_MIPS32R2) || defined(_MIPS_ARCH_MIPS64R2)
++	$SRL	$tmp2,@X[1],@sigma0[0]		# Xupdate($i)
++	$ROTR	$tmp0,@X[1],@sigma0[1]
++	$ADDU	@X[0],@X[9]			# +=X[i+9]
++	xor	$tmp2,$tmp0
++	$ROTR	$tmp0,@X[1],@sigma0[2]
++
++	$SRL	$tmp3,@X[14],@sigma1[0]
++	$ROTR	$tmp1,@X[14],@sigma1[1]
++	xor	$tmp2,$tmp0			# sigma0(X[i+1])
++	$ROTR	$tmp0,@X[14],@sigma1[2]
++	xor	$tmp3,$tmp1
++	$ADDU	@X[0],$tmp2
++#else
++	$SRL	$tmp2,@X[1],@sigma0[0]		# Xupdate($i)
++	$ADDU	@X[0],@X[9]			# +=X[i+9]
++	$SLL	$tmp1,@X[1],`$SZ*8-@sigma0[2]`
++	$SRL	$tmp0,@X[1],@sigma0[1]
++	xor	$tmp2,$tmp1
++	$SLL	$tmp1,`@sigma0[2]-@sigma0[1]`
++	xor	$tmp2,$tmp0
++	$SRL	$tmp0,@X[1],@sigma0[2]
++	xor	$tmp2,$tmp1
++
++	$SRL	$tmp3,@X[14],@sigma1[0]
++	xor	$tmp2,$tmp0			# sigma0(X[i+1])
++	$SLL	$tmp1,@X[14],`$SZ*8-@sigma1[2]`
++	$ADDU	@X[0],$tmp2
++	$SRL	$tmp0,@X[14],@sigma1[1]
++	xor	$tmp3,$tmp1
++	$SLL	$tmp1,`@sigma1[2]-@sigma1[1]`
++	xor	$tmp3,$tmp0
++	$SRL	$tmp0,@X[14],@sigma1[2]
++	xor	$tmp3,$tmp1
++#endif
++	xor	$tmp3,$tmp0			# sigma1(X[i+14])
++	$ADDU	@X[0],$tmp3
++___
++	&BODY_00_15(@_);
++}
++
++$FRAMESIZE=16*$SZ+16*$SZREG;
++$SAVED_REGS_MASK = ($flavour =~ /nubi/i) ? "0xc0fff008" : "0xc0ff0000";
++
++$code.=<<___;
++#ifdef OPENSSL_FIPSCANISTER
++# include 
++#endif
++
++#if defined(__mips_smartmips) && !defined(_MIPS_ARCH_MIPS32R2)
++#define _MIPS_ARCH_MIPS32R2
++#endif
++
++.text
++.set	noat
++#if !defined(__mips_eabi) && (!defined(__vxworks) || defined(__pic__))
++.option	pic2
++#endif
++
++.align	5
++.globl	sha${label}_block_data_order
++.ent	sha${label}_block_data_order
++sha${label}_block_data_order:
++	.frame	$sp,$FRAMESIZE,$ra
++	.mask	$SAVED_REGS_MASK,-$SZREG
++	.set	noreorder
++___
++$code.=<<___ if ($flavour =~ /o32/i);	# o32 PIC-ification
++	.cpload	$pf
++___
++$code.=<<___;
++	$PTR_SUB $sp,$FRAMESIZE
++	$REG_S	$ra,$FRAMESIZE-1*$SZREG($sp)
++	$REG_S	$fp,$FRAMESIZE-2*$SZREG($sp)
++	$REG_S	$s11,$FRAMESIZE-3*$SZREG($sp)
++	$REG_S	$s10,$FRAMESIZE-4*$SZREG($sp)
++	$REG_S	$s9,$FRAMESIZE-5*$SZREG($sp)
++	$REG_S	$s8,$FRAMESIZE-6*$SZREG($sp)
++	$REG_S	$s7,$FRAMESIZE-7*$SZREG($sp)
++	$REG_S	$s6,$FRAMESIZE-8*$SZREG($sp)
++	$REG_S	$s5,$FRAMESIZE-9*$SZREG($sp)
++	$REG_S	$s4,$FRAMESIZE-10*$SZREG($sp)
++___
++$code.=<<___ if ($flavour =~ /nubi/i);	# optimize non-nubi prologue
++	$REG_S	$s3,$FRAMESIZE-11*$SZREG($sp)
++	$REG_S	$s2,$FRAMESIZE-12*$SZREG($sp)
++	$REG_S	$s1,$FRAMESIZE-13*$SZREG($sp)
++	$REG_S	$s0,$FRAMESIZE-14*$SZREG($sp)
++	$REG_S	$gp,$FRAMESIZE-15*$SZREG($sp)
++___
++$code.=<<___;
++	$PTR_SLL @X[15],$len,`log(16*$SZ)/log(2)`
++___
++$code.=<<___ if ($flavour !~ /o32/i);	# non-o32 PIC-ification
++	.cplocal	$Ktbl
++	.cpsetup	$pf,$zero,sha${label}_block_data_order
++___
++$code.=<<___;
++	.set	reorder
++	$PTR_LA	$Ktbl,K${label}		# PIC-ified 'load address'
++
++	$LD	$A,0*$SZ($ctx)		# load context
++	$LD	$B,1*$SZ($ctx)
++	$LD	$C,2*$SZ($ctx)
++	$LD	$D,3*$SZ($ctx)
++	$LD	$E,4*$SZ($ctx)
++	$LD	$F,5*$SZ($ctx)
++	$LD	$G,6*$SZ($ctx)
++	$LD	$H,7*$SZ($ctx)
++
++	$PTR_ADD @X[15],$inp		# pointer to the end of input
++	$REG_S	@X[15],16*$SZ($sp)
++	b	.Loop
++
++.align	5
++.Loop:
++	${LD}l	@X[0],$MSB($inp)
++	${LD}r	@X[0],$LSB($inp)
++___
++for ($i=0;$i<16;$i++)
++{ &BODY_00_15($i,@V); unshift(@V,pop(@V)); push(@X,shift(@X)); }
++$code.=<<___;
++	b	.L16_xx
++.align	4
++.L16_xx:
++___
++for (;$i<32;$i++)
++{ &BODY_16_XX($i,@V); unshift(@V,pop(@V)); push(@X,shift(@X)); }
++$code.=<<___;
++	and	@X[6],0xfff
++	li	@X[7],$lastK
++	.set	noreorder
++	bne	@X[6],@X[7],.L16_xx
++	$PTR_ADD $Ktbl,16*$SZ		# Ktbl+=16
++
++	$REG_L	@X[15],16*$SZ($sp)	# restore pointer to the end of input
++	$LD	@X[0],0*$SZ($ctx)
++	$LD	@X[1],1*$SZ($ctx)
++	$LD	@X[2],2*$SZ($ctx)
++	$PTR_ADD $inp,16*$SZ
++	$LD	@X[3],3*$SZ($ctx)
++	$ADDU	$A,@X[0]
++	$LD	@X[4],4*$SZ($ctx)
++	$ADDU	$B,@X[1]
++	$LD	@X[5],5*$SZ($ctx)
++	$ADDU	$C,@X[2]
++	$LD	@X[6],6*$SZ($ctx)
++	$ADDU	$D,@X[3]
++	$LD	@X[7],7*$SZ($ctx)
++	$ADDU	$E,@X[4]
++	$ST	$A,0*$SZ($ctx)
++	$ADDU	$F,@X[5]
++	$ST	$B,1*$SZ($ctx)
++	$ADDU	$G,@X[6]
++	$ST	$C,2*$SZ($ctx)
++	$ADDU	$H,@X[7]
++	$ST	$D,3*$SZ($ctx)
++	$ST	$E,4*$SZ($ctx)
++	$ST	$F,5*$SZ($ctx)
++	$ST	$G,6*$SZ($ctx)
++	$ST	$H,7*$SZ($ctx)
++
++	bne	$inp,@X[15],.Loop
++	$PTR_SUB $Ktbl,`($rounds-16)*$SZ`	# rewind $Ktbl
++
++	$REG_L	$ra,$FRAMESIZE-1*$SZREG($sp)
++	$REG_L	$fp,$FRAMESIZE-2*$SZREG($sp)
++	$REG_L	$s11,$FRAMESIZE-3*$SZREG($sp)
++	$REG_L	$s10,$FRAMESIZE-4*$SZREG($sp)
++	$REG_L	$s9,$FRAMESIZE-5*$SZREG($sp)
++	$REG_L	$s8,$FRAMESIZE-6*$SZREG($sp)
++	$REG_L	$s7,$FRAMESIZE-7*$SZREG($sp)
++	$REG_L	$s6,$FRAMESIZE-8*$SZREG($sp)
++	$REG_L	$s5,$FRAMESIZE-9*$SZREG($sp)
++	$REG_L	$s4,$FRAMESIZE-10*$SZREG($sp)
++___
++$code.=<<___ if ($flavour =~ /nubi/i);
++	$REG_L	$s3,$FRAMESIZE-11*$SZREG($sp)
++	$REG_L	$s2,$FRAMESIZE-12*$SZREG($sp)
++	$REG_L	$s1,$FRAMESIZE-13*$SZREG($sp)
++	$REG_L	$s0,$FRAMESIZE-14*$SZREG($sp)
++	$REG_L	$gp,$FRAMESIZE-15*$SZREG($sp)
++___
++$code.=<<___;
++	jr	$ra
++	$PTR_ADD $sp,$FRAMESIZE
++.end	sha${label}_block_data_order
++
++.rdata
++.align	5
++K${label}:
++___
++if ($SZ==4) {
++$code.=<<___;
++	.word	0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5
++	.word	0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5
++	.word	0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3
++	.word	0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174
++	.word	0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc
++	.word	0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da
++	.word	0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7
++	.word	0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967
++	.word	0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13
++	.word	0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85
++	.word	0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3
++	.word	0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070
++	.word	0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5
++	.word	0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3
++	.word	0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208
++	.word	0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2
++___
++} else {
++$code.=<<___;
++	.dword	0x428a2f98d728ae22, 0x7137449123ef65cd
++	.dword	0xb5c0fbcfec4d3b2f, 0xe9b5dba58189dbbc
++	.dword	0x3956c25bf348b538, 0x59f111f1b605d019
++	.dword	0x923f82a4af194f9b, 0xab1c5ed5da6d8118
++	.dword	0xd807aa98a3030242, 0x12835b0145706fbe
++	.dword	0x243185be4ee4b28c, 0x550c7dc3d5ffb4e2
++	.dword	0x72be5d74f27b896f, 0x80deb1fe3b1696b1
++	.dword	0x9bdc06a725c71235, 0xc19bf174cf692694
++	.dword	0xe49b69c19ef14ad2, 0xefbe4786384f25e3
++	.dword	0x0fc19dc68b8cd5b5, 0x240ca1cc77ac9c65
++	.dword	0x2de92c6f592b0275, 0x4a7484aa6ea6e483
++	.dword	0x5cb0a9dcbd41fbd4, 0x76f988da831153b5
++	.dword	0x983e5152ee66dfab, 0xa831c66d2db43210
++	.dword	0xb00327c898fb213f, 0xbf597fc7beef0ee4
++	.dword	0xc6e00bf33da88fc2, 0xd5a79147930aa725
++	.dword	0x06ca6351e003826f, 0x142929670a0e6e70
++	.dword	0x27b70a8546d22ffc, 0x2e1b21385c26c926
++	.dword	0x4d2c6dfc5ac42aed, 0x53380d139d95b3df
++	.dword	0x650a73548baf63de, 0x766a0abb3c77b2a8
++	.dword	0x81c2c92e47edaee6, 0x92722c851482353b
++	.dword	0xa2bfe8a14cf10364, 0xa81a664bbc423001
++	.dword	0xc24b8b70d0f89791, 0xc76c51a30654be30
++	.dword	0xd192e819d6ef5218, 0xd69906245565a910
++	.dword	0xf40e35855771202a, 0x106aa07032bbd1b8
++	.dword	0x19a4c116b8d2d0c8, 0x1e376c085141ab53
++	.dword	0x2748774cdf8eeb99, 0x34b0bcb5e19b48a8
++	.dword	0x391c0cb3c5c95a63, 0x4ed8aa4ae3418acb
++	.dword	0x5b9cca4f7763e373, 0x682e6ff3d6b2b8a3
++	.dword	0x748f82ee5defb2fc, 0x78a5636f43172f60
++	.dword	0x84c87814a1f0ab72, 0x8cc702081a6439ec
++	.dword	0x90befffa23631e28, 0xa4506cebde82bde9
++	.dword	0xbef9a3f7b2c67915, 0xc67178f2e372532b
++	.dword	0xca273eceea26619c, 0xd186b8c721c0c207
++	.dword	0xeada7dd6cde0eb1e, 0xf57d4f7fee6ed178
++	.dword	0x06f067aa72176fba, 0x0a637dc5a2c898a6
++	.dword	0x113f9804bef90dae, 0x1b710b35131c471b
++	.dword	0x28db77f523047d84, 0x32caab7b40c72493
++	.dword	0x3c9ebe0a15c9bebc, 0x431d67c49c100d4c
++	.dword	0x4cc5d4becb3e42b6, 0x597f299cfc657e2a
++	.dword	0x5fcb6fab3ad6faec, 0x6c44198c4a475817
++___
++}
++$code.=<<___;
++.asciiz	"SHA${label} for MIPS, CRYPTOGAMS by "
++.align	5
++
++___
++
++$code =~ s/\`([^\`]*)\`/eval $1/gem;
++print $code;
++close STDOUT;
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/sha/asm/sha512-parisc.pl b/CryptoPkg/Library/OpensslLib/openssl/crypto/sha/asm/sha512-parisc.pl
+new file mode 100755
+index 0000000..fcb6157
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/sha/asm/sha512-parisc.pl
+@@ -0,0 +1,800 @@
++#! /usr/bin/env perl
++# Copyright 2009-2016 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
++# in the file LICENSE in the source distribution or at
++# https://www.openssl.org/source/license.html
++
++
++# ====================================================================
++# Written by Andy Polyakov  for the OpenSSL
++# project. The module is, however, dual licensed under OpenSSL and
++# CRYPTOGAMS licenses depending on where you obtain it. For further
++# details see http://www.openssl.org/~appro/cryptogams/.
++# ====================================================================
++
++# SHA256/512 block procedure for PA-RISC.
++
++# June 2009.
++#
++# SHA256 performance is >75% better than gcc 3.2 generated code on
++# PA-7100LC. Compared to code generated by vendor compiler this
++# implementation is almost 70% faster in 64-bit build, but delivers
++# virtually same performance in 32-bit build on PA-8600.
++#
++# SHA512 performance is >2.9x better than gcc 3.2 generated code on
++# PA-7100LC, PA-RISC 1.1 processor. Then implementation detects if the
++# code is executed on PA-RISC 2.0 processor and switches to 64-bit
++# code path delivering adequate performance even in "blended" 32-bit
++# build. Though 64-bit code is not any faster than code generated by
++# vendor compiler on PA-8600...
++#
++# Special thanks to polarhome.com for providing HP-UX account.
++
++$flavour = shift;
++$output = shift;
++open STDOUT,">$output";
++
++if ($flavour =~ /64/) {
++	$LEVEL		="2.0W";
++	$SIZE_T		=8;
++	$FRAME_MARKER	=80;
++	$SAVED_RP	=16;
++	$PUSH		="std";
++	$PUSHMA		="std,ma";
++	$POP		="ldd";
++	$POPMB		="ldd,mb";
++} else {
++	$LEVEL		="1.0";
++	$SIZE_T		=4;
++	$FRAME_MARKER	=48;
++	$SAVED_RP	=20;
++	$PUSH		="stw";
++	$PUSHMA		="stwm";
++	$POP		="ldw";
++	$POPMB		="ldwm";
++}
++
++if ($output =~ /512/) {
++	$func="sha512_block_data_order";
++	$SZ=8;
++	@Sigma0=(28,34,39);
++	@Sigma1=(14,18,41);
++	@sigma0=(1,  8, 7);
++	@sigma1=(19,61, 6);
++	$rounds=80;
++	$LAST10BITS=0x017;
++	$LD="ldd";
++	$LDM="ldd,ma";
++	$ST="std";
++} else {
++	$func="sha256_block_data_order";
++	$SZ=4;
++	@Sigma0=( 2,13,22);
++	@Sigma1=( 6,11,25);
++	@sigma0=( 7,18, 3);
++	@sigma1=(17,19,10);
++	$rounds=64;
++	$LAST10BITS=0x0f2;
++	$LD="ldw";
++	$LDM="ldwm";
++	$ST="stw";
++}
++
++$FRAME=16*$SIZE_T+$FRAME_MARKER;# 16 saved regs + frame marker
++				#                 [+ argument transfer]
++$XOFF=16*$SZ+32;		# local variables
++$FRAME+=$XOFF;
++$XOFF+=$FRAME_MARKER;		# distance between %sp and local variables
++
++$ctx="%r26";	# zapped by $a0
++$inp="%r25";	# zapped by $a1
++$num="%r24";	# zapped by $t0
++
++$a0 ="%r26";
++$a1 ="%r25";
++$t0 ="%r24";
++$t1 ="%r29";
++$Tbl="%r31";
++
++@V=($A,$B,$C,$D,$E,$F,$G,$H)=("%r17","%r18","%r19","%r20","%r21","%r22","%r23","%r28");
++
++@X=("%r1", "%r2", "%r3", "%r4", "%r5", "%r6", "%r7", "%r8",
++    "%r9", "%r10","%r11","%r12","%r13","%r14","%r15","%r16",$inp);
++
++sub ROUND_00_15 {
++my ($i,$a,$b,$c,$d,$e,$f,$g,$h)=@_;
++$code.=<<___;
++	_ror	$e,$Sigma1[0],$a0
++	and	$f,$e,$t0
++	_ror	$e,$Sigma1[1],$a1
++	addl	$t1,$h,$h
++	andcm	$g,$e,$t1
++	xor	$a1,$a0,$a0
++	_ror	$a1,`$Sigma1[2]-$Sigma1[1]`,$a1
++	or	$t0,$t1,$t1		; Ch(e,f,g)
++	addl	@X[$i%16],$h,$h
++	xor	$a0,$a1,$a1		; Sigma1(e)
++	addl	$t1,$h,$h
++	_ror	$a,$Sigma0[0],$a0
++	addl	$a1,$h,$h
++
++	_ror	$a,$Sigma0[1],$a1
++	and	$a,$b,$t0
++	and	$a,$c,$t1
++	xor	$a1,$a0,$a0
++	_ror	$a1,`$Sigma0[2]-$Sigma0[1]`,$a1
++	xor	$t1,$t0,$t0
++	and	$b,$c,$t1
++	xor	$a0,$a1,$a1		; Sigma0(a)
++	addl	$h,$d,$d
++	xor	$t1,$t0,$t0		; Maj(a,b,c)
++	`"$LDM	$SZ($Tbl),$t1" if ($i<15)`
++	addl	$a1,$h,$h
++	addl	$t0,$h,$h
++
++___
++}
++
++sub ROUND_16_xx {
++my ($i,$a,$b,$c,$d,$e,$f,$g,$h)=@_;
++$i-=16;
++$code.=<<___;
++	_ror	@X[($i+1)%16],$sigma0[0],$a0
++	_ror	@X[($i+1)%16],$sigma0[1],$a1
++	addl	@X[($i+9)%16],@X[$i],@X[$i]
++	_ror	@X[($i+14)%16],$sigma1[0],$t0
++	_ror	@X[($i+14)%16],$sigma1[1],$t1
++	xor	$a1,$a0,$a0
++	_shr	@X[($i+1)%16],$sigma0[2],$a1
++	xor	$t1,$t0,$t0
++	_shr	@X[($i+14)%16],$sigma1[2],$t1
++	xor	$a1,$a0,$a0		; sigma0(X[(i+1)&0x0f])
++	xor	$t1,$t0,$t0		; sigma1(X[(i+14)&0x0f])
++	$LDM	$SZ($Tbl),$t1
++	addl	$a0,@X[$i],@X[$i]
++	addl	$t0,@X[$i],@X[$i]
++___
++$code.=<<___ if ($i==15);
++	extru	$t1,31,10,$a1
++	comiclr,<> $LAST10BITS,$a1,%r0
++	ldo	1($Tbl),$Tbl		; signal end of $Tbl
++___
++&ROUND_00_15($i+16,$a,$b,$c,$d,$e,$f,$g,$h);
++}
++
++$code=<<___;
++	.LEVEL	$LEVEL
++	.SPACE	\$TEXT\$
++	.SUBSPA	\$CODE\$,QUAD=0,ALIGN=8,ACCESS=0x2C,CODE_ONLY
++
++	.ALIGN	64
++L\$table
++___
++$code.=<<___ if ($SZ==8);
++	.WORD	0x428a2f98,0xd728ae22,0x71374491,0x23ef65cd
++	.WORD	0xb5c0fbcf,0xec4d3b2f,0xe9b5dba5,0x8189dbbc
++	.WORD	0x3956c25b,0xf348b538,0x59f111f1,0xb605d019
++	.WORD	0x923f82a4,0xaf194f9b,0xab1c5ed5,0xda6d8118
++	.WORD	0xd807aa98,0xa3030242,0x12835b01,0x45706fbe
++	.WORD	0x243185be,0x4ee4b28c,0x550c7dc3,0xd5ffb4e2
++	.WORD	0x72be5d74,0xf27b896f,0x80deb1fe,0x3b1696b1
++	.WORD	0x9bdc06a7,0x25c71235,0xc19bf174,0xcf692694
++	.WORD	0xe49b69c1,0x9ef14ad2,0xefbe4786,0x384f25e3
++	.WORD	0x0fc19dc6,0x8b8cd5b5,0x240ca1cc,0x77ac9c65
++	.WORD	0x2de92c6f,0x592b0275,0x4a7484aa,0x6ea6e483
++	.WORD	0x5cb0a9dc,0xbd41fbd4,0x76f988da,0x831153b5
++	.WORD	0x983e5152,0xee66dfab,0xa831c66d,0x2db43210
++	.WORD	0xb00327c8,0x98fb213f,0xbf597fc7,0xbeef0ee4
++	.WORD	0xc6e00bf3,0x3da88fc2,0xd5a79147,0x930aa725
++	.WORD	0x06ca6351,0xe003826f,0x14292967,0x0a0e6e70
++	.WORD	0x27b70a85,0x46d22ffc,0x2e1b2138,0x5c26c926
++	.WORD	0x4d2c6dfc,0x5ac42aed,0x53380d13,0x9d95b3df
++	.WORD	0x650a7354,0x8baf63de,0x766a0abb,0x3c77b2a8
++	.WORD	0x81c2c92e,0x47edaee6,0x92722c85,0x1482353b
++	.WORD	0xa2bfe8a1,0x4cf10364,0xa81a664b,0xbc423001
++	.WORD	0xc24b8b70,0xd0f89791,0xc76c51a3,0x0654be30
++	.WORD	0xd192e819,0xd6ef5218,0xd6990624,0x5565a910
++	.WORD	0xf40e3585,0x5771202a,0x106aa070,0x32bbd1b8
++	.WORD	0x19a4c116,0xb8d2d0c8,0x1e376c08,0x5141ab53
++	.WORD	0x2748774c,0xdf8eeb99,0x34b0bcb5,0xe19b48a8
++	.WORD	0x391c0cb3,0xc5c95a63,0x4ed8aa4a,0xe3418acb
++	.WORD	0x5b9cca4f,0x7763e373,0x682e6ff3,0xd6b2b8a3
++	.WORD	0x748f82ee,0x5defb2fc,0x78a5636f,0x43172f60
++	.WORD	0x84c87814,0xa1f0ab72,0x8cc70208,0x1a6439ec
++	.WORD	0x90befffa,0x23631e28,0xa4506ceb,0xde82bde9
++	.WORD	0xbef9a3f7,0xb2c67915,0xc67178f2,0xe372532b
++	.WORD	0xca273ece,0xea26619c,0xd186b8c7,0x21c0c207
++	.WORD	0xeada7dd6,0xcde0eb1e,0xf57d4f7f,0xee6ed178
++	.WORD	0x06f067aa,0x72176fba,0x0a637dc5,0xa2c898a6
++	.WORD	0x113f9804,0xbef90dae,0x1b710b35,0x131c471b
++	.WORD	0x28db77f5,0x23047d84,0x32caab7b,0x40c72493
++	.WORD	0x3c9ebe0a,0x15c9bebc,0x431d67c4,0x9c100d4c
++	.WORD	0x4cc5d4be,0xcb3e42b6,0x597f299c,0xfc657e2a
++	.WORD	0x5fcb6fab,0x3ad6faec,0x6c44198c,0x4a475817
++___
++$code.=<<___ if ($SZ==4);
++	.WORD	0x428a2f98,0x71374491,0xb5c0fbcf,0xe9b5dba5
++	.WORD	0x3956c25b,0x59f111f1,0x923f82a4,0xab1c5ed5
++	.WORD	0xd807aa98,0x12835b01,0x243185be,0x550c7dc3
++	.WORD	0x72be5d74,0x80deb1fe,0x9bdc06a7,0xc19bf174
++	.WORD	0xe49b69c1,0xefbe4786,0x0fc19dc6,0x240ca1cc
++	.WORD	0x2de92c6f,0x4a7484aa,0x5cb0a9dc,0x76f988da
++	.WORD	0x983e5152,0xa831c66d,0xb00327c8,0xbf597fc7
++	.WORD	0xc6e00bf3,0xd5a79147,0x06ca6351,0x14292967
++	.WORD	0x27b70a85,0x2e1b2138,0x4d2c6dfc,0x53380d13
++	.WORD	0x650a7354,0x766a0abb,0x81c2c92e,0x92722c85
++	.WORD	0xa2bfe8a1,0xa81a664b,0xc24b8b70,0xc76c51a3
++	.WORD	0xd192e819,0xd6990624,0xf40e3585,0x106aa070
++	.WORD	0x19a4c116,0x1e376c08,0x2748774c,0x34b0bcb5
++	.WORD	0x391c0cb3,0x4ed8aa4a,0x5b9cca4f,0x682e6ff3
++	.WORD	0x748f82ee,0x78a5636f,0x84c87814,0x8cc70208
++	.WORD	0x90befffa,0xa4506ceb,0xbef9a3f7,0xc67178f2
++___
++$code.=<<___;
++
++	.EXPORT	$func,ENTRY,ARGW0=GR,ARGW1=GR,ARGW2=GR
++	.ALIGN	64
++$func
++	.PROC
++	.CALLINFO	FRAME=`$FRAME-16*$SIZE_T`,NO_CALLS,SAVE_RP,ENTRY_GR=18
++	.ENTRY
++	$PUSH	%r2,-$SAVED_RP(%sp)	; standard prologue
++	$PUSHMA	%r3,$FRAME(%sp)
++	$PUSH	%r4,`-$FRAME+1*$SIZE_T`(%sp)
++	$PUSH	%r5,`-$FRAME+2*$SIZE_T`(%sp)
++	$PUSH	%r6,`-$FRAME+3*$SIZE_T`(%sp)
++	$PUSH	%r7,`-$FRAME+4*$SIZE_T`(%sp)
++	$PUSH	%r8,`-$FRAME+5*$SIZE_T`(%sp)
++	$PUSH	%r9,`-$FRAME+6*$SIZE_T`(%sp)
++	$PUSH	%r10,`-$FRAME+7*$SIZE_T`(%sp)
++	$PUSH	%r11,`-$FRAME+8*$SIZE_T`(%sp)
++	$PUSH	%r12,`-$FRAME+9*$SIZE_T`(%sp)
++	$PUSH	%r13,`-$FRAME+10*$SIZE_T`(%sp)
++	$PUSH	%r14,`-$FRAME+11*$SIZE_T`(%sp)
++	$PUSH	%r15,`-$FRAME+12*$SIZE_T`(%sp)
++	$PUSH	%r16,`-$FRAME+13*$SIZE_T`(%sp)
++	$PUSH	%r17,`-$FRAME+14*$SIZE_T`(%sp)
++	$PUSH	%r18,`-$FRAME+15*$SIZE_T`(%sp)
++
++	_shl	$num,`log(16*$SZ)/log(2)`,$num
++	addl	$inp,$num,$num		; $num to point at the end of $inp
++
++	$PUSH	$num,`-$FRAME_MARKER-4*$SIZE_T`(%sp)	; save arguments
++	$PUSH	$inp,`-$FRAME_MARKER-3*$SIZE_T`(%sp)
++	$PUSH	$ctx,`-$FRAME_MARKER-2*$SIZE_T`(%sp)
++
++	blr	%r0,$Tbl
++	ldi	3,$t1
++L\$pic
++	andcm	$Tbl,$t1,$Tbl		; wipe privilege level
++	ldo	L\$table-L\$pic($Tbl),$Tbl
++___
++$code.=<<___ if ($SZ==8 && $SIZE_T==4);
++	ldi	31,$t1
++	mtctl	$t1,%cr11
++	extrd,u,*= $t1,%sar,1,$t1	; executes on PA-RISC 1.0
++	b	L\$parisc1
++	nop
++___
++$code.=<<___;
++	$LD	`0*$SZ`($ctx),$A	; load context
++	$LD	`1*$SZ`($ctx),$B
++	$LD	`2*$SZ`($ctx),$C
++	$LD	`3*$SZ`($ctx),$D
++	$LD	`4*$SZ`($ctx),$E
++	$LD	`5*$SZ`($ctx),$F
++	$LD	`6*$SZ`($ctx),$G
++	$LD	`7*$SZ`($ctx),$H
++
++	extru	$inp,31,`log($SZ)/log(2)`,$t0
++	sh3addl	$t0,%r0,$t0
++	subi	`8*$SZ`,$t0,$t0
++	mtctl	$t0,%cr11		; load %sar with align factor
++
++L\$oop
++	ldi	`$SZ-1`,$t0
++	$LDM	$SZ($Tbl),$t1
++	andcm	$inp,$t0,$t0		; align $inp
++___
++	for ($i=0;$i<15;$i++) {		# load input block
++	$code.="\t$LD	`$SZ*$i`($t0),@X[$i]\n";		}
++$code.=<<___;
++	cmpb,*=	$inp,$t0,L\$aligned
++	$LD	`$SZ*15`($t0),@X[15]
++	$LD	`$SZ*16`($t0),@X[16]
++___
++	for ($i=0;$i<16;$i++) {		# align data
++	$code.="\t_align	@X[$i],@X[$i+1],@X[$i]\n";	}
++$code.=<<___;
++L\$aligned
++	nop	; otherwise /usr/ccs/bin/as is confused by below .WORD
++___
++
++for($i=0;$i<16;$i++)	{ &ROUND_00_15($i,@V); unshift(@V,pop(@V)); }
++$code.=<<___;
++L\$rounds
++	nop	; otherwise /usr/ccs/bin/as is confused by below .WORD
++___
++for(;$i<32;$i++)	{ &ROUND_16_xx($i,@V); unshift(@V,pop(@V)); }
++$code.=<<___;
++	bb,>=	$Tbl,31,L\$rounds	; end of $Tbl signalled?
++	nop
++
++	$POP	`-$FRAME_MARKER-2*$SIZE_T`(%sp),$ctx	; restore arguments
++	$POP	`-$FRAME_MARKER-3*$SIZE_T`(%sp),$inp
++	$POP	`-$FRAME_MARKER-4*$SIZE_T`(%sp),$num
++	ldo	`-$rounds*$SZ-1`($Tbl),$Tbl		; rewind $Tbl
++
++	$LD	`0*$SZ`($ctx),@X[0]	; load context
++	$LD	`1*$SZ`($ctx),@X[1]
++	$LD	`2*$SZ`($ctx),@X[2]
++	$LD	`3*$SZ`($ctx),@X[3]
++	$LD	`4*$SZ`($ctx),@X[4]
++	$LD	`5*$SZ`($ctx),@X[5]
++	addl	@X[0],$A,$A
++	$LD	`6*$SZ`($ctx),@X[6]
++	addl	@X[1],$B,$B
++	$LD	`7*$SZ`($ctx),@X[7]
++	ldo	`16*$SZ`($inp),$inp	; advance $inp
++
++	$ST	$A,`0*$SZ`($ctx)	; save context
++	addl	@X[2],$C,$C
++	$ST	$B,`1*$SZ`($ctx)
++	addl	@X[3],$D,$D
++	$ST	$C,`2*$SZ`($ctx)
++	addl	@X[4],$E,$E
++	$ST	$D,`3*$SZ`($ctx)
++	addl	@X[5],$F,$F
++	$ST	$E,`4*$SZ`($ctx)
++	addl	@X[6],$G,$G
++	$ST	$F,`5*$SZ`($ctx)
++	addl	@X[7],$H,$H
++	$ST	$G,`6*$SZ`($ctx)
++	$ST	$H,`7*$SZ`($ctx)
++
++	cmpb,*<>,n $inp,$num,L\$oop
++	$PUSH	$inp,`-$FRAME_MARKER-3*$SIZE_T`(%sp)	; save $inp
++___
++if ($SZ==8 && $SIZE_T==4)	# SHA512 for 32-bit PA-RISC 1.0
++{{
++$code.=<<___;
++	b	L\$done
++	nop
++
++	.ALIGN	64
++L\$parisc1
++___
++
++@V=(  $Ahi,  $Alo,  $Bhi,  $Blo,  $Chi,  $Clo,  $Dhi,  $Dlo,
++      $Ehi,  $Elo,  $Fhi,  $Flo,  $Ghi,  $Glo,  $Hhi,  $Hlo) = 
++   ( "%r1", "%r2", "%r3", "%r4", "%r5", "%r6", "%r7", "%r8",
++     "%r9","%r10","%r11","%r12","%r13","%r14","%r15","%r16");
++$a0 ="%r17";
++$a1 ="%r18";
++$a2 ="%r19";
++$a3 ="%r20";
++$t0 ="%r21";
++$t1 ="%r22";
++$t2 ="%r28";
++$t3 ="%r29";
++$Tbl="%r31";
++
++@X=("%r23","%r24","%r25","%r26");	# zaps $num,$inp,$ctx
++
++sub ROUND_00_15_pa1 {
++my ($i,$ahi,$alo,$bhi,$blo,$chi,$clo,$dhi,$dlo,
++       $ehi,$elo,$fhi,$flo,$ghi,$glo,$hhi,$hlo,$flag)=@_;
++my ($Xhi,$Xlo,$Xnhi,$Xnlo) = @X;
++
++$code.=<<___ if (!$flag);
++	ldw	`-$XOFF+8*(($i+1)%16)`(%sp),$Xnhi
++	ldw	`-$XOFF+8*(($i+1)%16)+4`(%sp),$Xnlo	; load X[i+1]
++___
++$code.=<<___;
++	shd	$ehi,$elo,$Sigma1[0],$t0
++	 add	$Xlo,$hlo,$hlo
++	shd	$elo,$ehi,$Sigma1[0],$t1
++	 addc	$Xhi,$hhi,$hhi		; h += X[i]
++	shd	$ehi,$elo,$Sigma1[1],$t2
++	 ldwm	8($Tbl),$Xhi
++	shd	$elo,$ehi,$Sigma1[1],$t3
++	 ldw	-4($Tbl),$Xlo		; load K[i]
++	xor	$t2,$t0,$t0
++	xor	$t3,$t1,$t1
++	 and	$flo,$elo,$a0
++	 and	$fhi,$ehi,$a1
++	shd	$ehi,$elo,$Sigma1[2],$t2
++	 andcm	$glo,$elo,$a2
++	shd	$elo,$ehi,$Sigma1[2],$t3
++	 andcm	$ghi,$ehi,$a3
++	xor	$t2,$t0,$t0
++	xor	$t3,$t1,$t1		; Sigma1(e)
++	add	$Xlo,$hlo,$hlo
++	 xor	$a2,$a0,$a0
++	addc	$Xhi,$hhi,$hhi		; h += K[i]
++	 xor	$a3,$a1,$a1		; Ch(e,f,g)
++
++	 add	$t0,$hlo,$hlo
++	shd	$ahi,$alo,$Sigma0[0],$t0
++	 addc	$t1,$hhi,$hhi		; h += Sigma1(e)
++	shd	$alo,$ahi,$Sigma0[0],$t1	
++	 add	$a0,$hlo,$hlo
++	shd	$ahi,$alo,$Sigma0[1],$t2
++	 addc	$a1,$hhi,$hhi		; h += Ch(e,f,g)
++	shd	$alo,$ahi,$Sigma0[1],$t3
++
++	xor	$t2,$t0,$t0
++	xor	$t3,$t1,$t1
++	shd	$ahi,$alo,$Sigma0[2],$t2
++	and	$alo,$blo,$a0
++	shd	$alo,$ahi,$Sigma0[2],$t3
++	and	$ahi,$bhi,$a1
++	xor	$t2,$t0,$t0
++	xor	$t3,$t1,$t1		; Sigma0(a)
++
++	and	$alo,$clo,$a2
++	and	$ahi,$chi,$a3
++	xor	$a2,$a0,$a0
++	 add	$hlo,$dlo,$dlo
++	xor	$a3,$a1,$a1
++	 addc	$hhi,$dhi,$dhi		; d += h
++	and	$blo,$clo,$a2
++	 add	$t0,$hlo,$hlo
++	and	$bhi,$chi,$a3
++	 addc	$t1,$hhi,$hhi		; h += Sigma0(a)
++	xor	$a2,$a0,$a0
++	 add	$a0,$hlo,$hlo
++	xor	$a3,$a1,$a1		; Maj(a,b,c)
++	 addc	$a1,$hhi,$hhi		; h += Maj(a,b,c)
++
++___
++$code.=<<___ if ($i==15 && $flag);
++	extru	$Xlo,31,10,$Xlo
++	comiclr,= $LAST10BITS,$Xlo,%r0
++	b	L\$rounds_pa1
++	nop
++___
++push(@X,shift(@X)); push(@X,shift(@X));
++}
++
++sub ROUND_16_xx_pa1 {
++my ($Xhi,$Xlo,$Xnhi,$Xnlo) = @X;
++my ($i)=shift;
++$i-=16;
++$code.=<<___;
++	ldw	`-$XOFF+8*(($i+1)%16)`(%sp),$Xnhi
++	ldw	`-$XOFF+8*(($i+1)%16)+4`(%sp),$Xnlo	; load X[i+1]
++	ldw	`-$XOFF+8*(($i+9)%16)`(%sp),$a1
++	ldw	`-$XOFF+8*(($i+9)%16)+4`(%sp),$a0	; load X[i+9]
++	ldw	`-$XOFF+8*(($i+14)%16)`(%sp),$a3
++	ldw	`-$XOFF+8*(($i+14)%16)+4`(%sp),$a2	; load X[i+14]
++	shd	$Xnhi,$Xnlo,$sigma0[0],$t0
++	shd	$Xnlo,$Xnhi,$sigma0[0],$t1
++	 add	$a0,$Xlo,$Xlo
++	shd	$Xnhi,$Xnlo,$sigma0[1],$t2
++	 addc	$a1,$Xhi,$Xhi
++	shd	$Xnlo,$Xnhi,$sigma0[1],$t3
++	xor	$t2,$t0,$t0
++	shd	$Xnhi,$Xnlo,$sigma0[2],$t2
++	xor	$t3,$t1,$t1
++	extru	$Xnhi,`31-$sigma0[2]`,`32-$sigma0[2]`,$t3
++	xor	$t2,$t0,$t0
++	 shd	$a3,$a2,$sigma1[0],$a0
++	xor	$t3,$t1,$t1		; sigma0(X[i+1)&0x0f])
++	 shd	$a2,$a3,$sigma1[0],$a1
++	add	$t0,$Xlo,$Xlo
++	 shd	$a3,$a2,$sigma1[1],$t2
++	addc	$t1,$Xhi,$Xhi
++	 shd	$a2,$a3,$sigma1[1],$t3
++	xor	$t2,$a0,$a0
++	shd	$a3,$a2,$sigma1[2],$t2
++	xor	$t3,$a1,$a1
++	extru	$a3,`31-$sigma1[2]`,`32-$sigma1[2]`,$t3
++	xor	$t2,$a0,$a0
++	xor	$t3,$a1,$a1		; sigma0(X[i+14)&0x0f])
++	add	$a0,$Xlo,$Xlo
++	addc	$a1,$Xhi,$Xhi
++
++	stw	$Xhi,`-$XOFF+8*($i%16)`(%sp)
++	stw	$Xlo,`-$XOFF+8*($i%16)+4`(%sp)
++___
++&ROUND_00_15_pa1($i,@_,1);
++}
++$code.=<<___;
++	ldw	`0*4`($ctx),$Ahi		; load context
++	ldw	`1*4`($ctx),$Alo
++	ldw	`2*4`($ctx),$Bhi
++	ldw	`3*4`($ctx),$Blo
++	ldw	`4*4`($ctx),$Chi
++	ldw	`5*4`($ctx),$Clo
++	ldw	`6*4`($ctx),$Dhi
++	ldw	`7*4`($ctx),$Dlo
++	ldw	`8*4`($ctx),$Ehi
++	ldw	`9*4`($ctx),$Elo
++	ldw	`10*4`($ctx),$Fhi
++	ldw	`11*4`($ctx),$Flo
++	ldw	`12*4`($ctx),$Ghi
++	ldw	`13*4`($ctx),$Glo
++	ldw	`14*4`($ctx),$Hhi
++	ldw	`15*4`($ctx),$Hlo
++
++	extru	$inp,31,2,$t0
++	sh3addl	$t0,%r0,$t0
++	subi	32,$t0,$t0
++	mtctl	$t0,%cr11		; load %sar with align factor
++
++L\$oop_pa1
++	extru	$inp,31,2,$a3
++	comib,=	0,$a3,L\$aligned_pa1
++	sub	$inp,$a3,$inp
++
++	ldw	`0*4`($inp),$X[0]
++	ldw	`1*4`($inp),$X[1]
++	ldw	`2*4`($inp),$t2
++	ldw	`3*4`($inp),$t3
++	ldw	`4*4`($inp),$a0
++	ldw	`5*4`($inp),$a1
++	ldw	`6*4`($inp),$a2
++	ldw	`7*4`($inp),$a3
++	vshd	$X[0],$X[1],$X[0]
++	vshd	$X[1],$t2,$X[1]
++	stw	$X[0],`-$XOFF+0*4`(%sp)
++	ldw	`8*4`($inp),$t0
++	vshd	$t2,$t3,$t2
++	stw	$X[1],`-$XOFF+1*4`(%sp)
++	ldw	`9*4`($inp),$t1
++	vshd	$t3,$a0,$t3
++___
++{
++my @t=($t2,$t3,$a0,$a1,$a2,$a3,$t0,$t1);
++for ($i=2;$i<=(128/4-8);$i++) {
++$code.=<<___;
++	stw	$t[0],`-$XOFF+$i*4`(%sp)
++	ldw	`(8+$i)*4`($inp),$t[0]
++	vshd	$t[1],$t[2],$t[1]
++___
++push(@t,shift(@t));
++}
++for (;$i<(128/4-1);$i++) {
++$code.=<<___;
++	stw	$t[0],`-$XOFF+$i*4`(%sp)
++	vshd	$t[1],$t[2],$t[1]
++___
++push(@t,shift(@t));
++}
++$code.=<<___;
++	b	L\$collected_pa1
++	stw	$t[0],`-$XOFF+$i*4`(%sp)
++
++___
++}
++$code.=<<___;
++L\$aligned_pa1
++	ldw	`0*4`($inp),$X[0]
++	ldw	`1*4`($inp),$X[1]
++	ldw	`2*4`($inp),$t2
++	ldw	`3*4`($inp),$t3
++	ldw	`4*4`($inp),$a0
++	ldw	`5*4`($inp),$a1
++	ldw	`6*4`($inp),$a2
++	ldw	`7*4`($inp),$a3
++	stw	$X[0],`-$XOFF+0*4`(%sp)
++	ldw	`8*4`($inp),$t0
++	stw	$X[1],`-$XOFF+1*4`(%sp)
++	ldw	`9*4`($inp),$t1
++___
++{
++my @t=($t2,$t3,$a0,$a1,$a2,$a3,$t0,$t1);
++for ($i=2;$i<(128/4-8);$i++) {
++$code.=<<___;
++	stw	$t[0],`-$XOFF+$i*4`(%sp)
++	ldw	`(8+$i)*4`($inp),$t[0]
++___
++push(@t,shift(@t));
++}
++for (;$i<128/4;$i++) {
++$code.=<<___;
++	stw	$t[0],`-$XOFF+$i*4`(%sp)
++___
++push(@t,shift(@t));
++}
++$code.="L\$collected_pa1\n";
++}
++
++for($i=0;$i<16;$i++)	{ &ROUND_00_15_pa1($i,@V); unshift(@V,pop(@V)); unshift(@V,pop(@V)); }
++$code.="L\$rounds_pa1\n";
++for(;$i<32;$i++)	{ &ROUND_16_xx_pa1($i,@V); unshift(@V,pop(@V)); unshift(@V,pop(@V)); }
++
++$code.=<<___;
++	$POP	`-$FRAME_MARKER-2*$SIZE_T`(%sp),$ctx	; restore arguments
++	$POP	`-$FRAME_MARKER-3*$SIZE_T`(%sp),$inp
++	$POP	`-$FRAME_MARKER-4*$SIZE_T`(%sp),$num
++	ldo	`-$rounds*$SZ`($Tbl),$Tbl		; rewind $Tbl
++
++	ldw	`0*4`($ctx),$t1		; update context
++	ldw	`1*4`($ctx),$t0
++	ldw	`2*4`($ctx),$t3
++	ldw	`3*4`($ctx),$t2
++	ldw	`4*4`($ctx),$a1
++	ldw	`5*4`($ctx),$a0
++	ldw	`6*4`($ctx),$a3
++	add	$t0,$Alo,$Alo
++	ldw	`7*4`($ctx),$a2
++	addc	$t1,$Ahi,$Ahi
++	ldw	`8*4`($ctx),$t1
++	add	$t2,$Blo,$Blo
++	ldw	`9*4`($ctx),$t0
++	addc	$t3,$Bhi,$Bhi
++	ldw	`10*4`($ctx),$t3
++	add	$a0,$Clo,$Clo
++	ldw	`11*4`($ctx),$t2
++	addc	$a1,$Chi,$Chi
++	ldw	`12*4`($ctx),$a1
++	add	$a2,$Dlo,$Dlo
++	ldw	`13*4`($ctx),$a0
++	addc	$a3,$Dhi,$Dhi
++	ldw	`14*4`($ctx),$a3
++	add	$t0,$Elo,$Elo
++	ldw	`15*4`($ctx),$a2
++	addc	$t1,$Ehi,$Ehi
++	stw	$Ahi,`0*4`($ctx)
++	add	$t2,$Flo,$Flo
++	stw	$Alo,`1*4`($ctx)
++	addc	$t3,$Fhi,$Fhi
++	stw	$Bhi,`2*4`($ctx)
++	add	$a0,$Glo,$Glo
++	stw	$Blo,`3*4`($ctx)
++	addc	$a1,$Ghi,$Ghi
++	stw	$Chi,`4*4`($ctx)
++	add	$a2,$Hlo,$Hlo
++	stw	$Clo,`5*4`($ctx)
++	addc	$a3,$Hhi,$Hhi
++	stw	$Dhi,`6*4`($ctx)
++	ldo	`16*$SZ`($inp),$inp	; advance $inp
++	stw	$Dlo,`7*4`($ctx)
++	stw	$Ehi,`8*4`($ctx)
++	stw	$Elo,`9*4`($ctx)
++	stw	$Fhi,`10*4`($ctx)
++	stw	$Flo,`11*4`($ctx)
++	stw	$Ghi,`12*4`($ctx)
++	stw	$Glo,`13*4`($ctx)
++	stw	$Hhi,`14*4`($ctx)
++	comb,=	$inp,$num,L\$done
++	stw	$Hlo,`15*4`($ctx)
++	b	L\$oop_pa1
++	$PUSH	$inp,`-$FRAME_MARKER-3*$SIZE_T`(%sp)	; save $inp
++L\$done
++___
++}}
++$code.=<<___;
++	$POP	`-$FRAME-$SAVED_RP`(%sp),%r2		; standard epilogue
++	$POP	`-$FRAME+1*$SIZE_T`(%sp),%r4
++	$POP	`-$FRAME+2*$SIZE_T`(%sp),%r5
++	$POP	`-$FRAME+3*$SIZE_T`(%sp),%r6
++	$POP	`-$FRAME+4*$SIZE_T`(%sp),%r7
++	$POP	`-$FRAME+5*$SIZE_T`(%sp),%r8
++	$POP	`-$FRAME+6*$SIZE_T`(%sp),%r9
++	$POP	`-$FRAME+7*$SIZE_T`(%sp),%r10
++	$POP	`-$FRAME+8*$SIZE_T`(%sp),%r11
++	$POP	`-$FRAME+9*$SIZE_T`(%sp),%r12
++	$POP	`-$FRAME+10*$SIZE_T`(%sp),%r13
++	$POP	`-$FRAME+11*$SIZE_T`(%sp),%r14
++	$POP	`-$FRAME+12*$SIZE_T`(%sp),%r15
++	$POP	`-$FRAME+13*$SIZE_T`(%sp),%r16
++	$POP	`-$FRAME+14*$SIZE_T`(%sp),%r17
++	$POP	`-$FRAME+15*$SIZE_T`(%sp),%r18
++	bv	(%r2)
++	.EXIT
++	$POPMB	-$FRAME(%sp),%r3
++	.PROCEND
++	.STRINGZ "SHA`64*$SZ` block transform for PA-RISC, CRYPTOGAMS by "
++___
++
++# Explicitly encode PA-RISC 2.0 instructions used in this module, so
++# that it can be compiled with .LEVEL 1.0. It should be noted that I
++# wouldn't have to do this, if GNU assembler understood .ALLOW 2.0
++# directive...
++
++my $ldd = sub {
++  my ($mod,$args) = @_;
++  my $orig = "ldd$mod\t$args";
++
++    if ($args =~ /(\-?[0-9]+)\(%r([0-9]+)\),%r([0-9]+)/) # format 3 suffices
++    {	my $opcode=(0x14<<26)|($2<<21)|($3<<16)|(($1&0x1FF8)<<1)|(($1>>13)&1);
++	$opcode|=(1<<3) if ($mod =~ /^,m/);
++	$opcode|=(1<<2) if ($mod =~ /^,mb/);
++	sprintf "\t.WORD\t0x%08x\t; %s",$opcode,$orig;
++    }
++    else { "\t".$orig; }
++};
++
++my $std = sub {
++  my ($mod,$args) = @_;
++  my $orig = "std$mod\t$args";
++
++    if ($args =~ /%r([0-9]+),(\-?[0-9]+)\(%r([0-9]+)\)/) # format 3 suffices
++    {	my $opcode=(0x1c<<26)|($3<<21)|($1<<16)|(($2&0x1FF8)<<1)|(($2>>13)&1);
++	sprintf "\t.WORD\t0x%08x\t; %s",$opcode,$orig;
++    }
++    else { "\t".$orig; }
++};
++
++my $extrd = sub {
++  my ($mod,$args) = @_;
++  my $orig = "extrd$mod\t$args";
++
++    # I only have ",u" completer, it's implicitly encoded...
++    if ($args =~ /%r([0-9]+),([0-9]+),([0-9]+),%r([0-9]+)/)	# format 15
++    {	my $opcode=(0x36<<26)|($1<<21)|($4<<16);
++	my $len=32-$3;
++	$opcode |= (($2&0x20)<<6)|(($2&0x1f)<<5);		# encode pos
++	$opcode |= (($len&0x20)<<7)|($len&0x1f);		# encode len
++	sprintf "\t.WORD\t0x%08x\t; %s",$opcode,$orig;
++    }
++    elsif ($args =~ /%r([0-9]+),%sar,([0-9]+),%r([0-9]+)/)	# format 12
++    {	my $opcode=(0x34<<26)|($1<<21)|($3<<16)|(2<<11)|(1<<9);
++	my $len=32-$2;
++	$opcode |= (($len&0x20)<<3)|($len&0x1f);		# encode len
++	$opcode |= (1<<13) if ($mod =~ /,\**=/);
++	sprintf "\t.WORD\t0x%08x\t; %s",$opcode,$orig;
++    }
++    else { "\t".$orig; }
++};
++
++my $shrpd = sub {
++  my ($mod,$args) = @_;
++  my $orig = "shrpd$mod\t$args";
++
++    if ($args =~ /%r([0-9]+),%r([0-9]+),([0-9]+),%r([0-9]+)/)	# format 14
++    {	my $opcode=(0x34<<26)|($2<<21)|($1<<16)|(1<<10)|$4;
++	my $cpos=63-$3;
++	$opcode |= (($cpos&0x20)<<6)|(($cpos&0x1f)<<5);		# encode sa
++	sprintf "\t.WORD\t0x%08x\t; %s",$opcode,$orig;
++    }
++    elsif ($args =~ /%r([0-9]+),%r([0-9]+),%sar,%r([0-9]+)/)	# format 11
++    {	sprintf "\t.WORD\t0x%08x\t; %s",
++		(0x34<<26)|($2<<21)|($1<<16)|(1<<9)|$3,$orig;
++    }
++    else { "\t".$orig; }
++};
++
++sub assemble {
++  my ($mnemonic,$mod,$args)=@_;
++  my $opcode = eval("\$$mnemonic");
++
++    ref($opcode) eq 'CODE' ? &$opcode($mod,$args) : "\t$mnemonic$mod\t$args";
++}
++
++foreach (split("\n",$code)) {
++	s/\`([^\`]*)\`/eval $1/ge;
++
++	s/shd\s+(%r[0-9]+),(%r[0-9]+),([0-9]+)/
++		$3>31 ? sprintf("shd\t%$2,%$1,%d",$3-32)	# rotation for >=32
++		:       sprintf("shd\t%$1,%$2,%d",$3)/e			or
++	# translate made up instructons: _ror, _shr, _align, _shl
++	s/_ror(\s+)(%r[0-9]+),/
++		($SZ==4 ? "shd" : "shrpd")."$1$2,$2,"/e			or
++
++	s/_shr(\s+%r[0-9]+),([0-9]+),/
++		$SZ==4 ? sprintf("extru%s,%d,%d,",$1,31-$2,32-$2)
++		:        sprintf("extrd,u%s,%d,%d,",$1,63-$2,64-$2)/e	or
++
++	s/_align(\s+%r[0-9]+,%r[0-9]+),/
++		($SZ==4 ? "vshd$1," : "shrpd$1,%sar,")/e		or
++
++	s/_shl(\s+%r[0-9]+),([0-9]+),/
++		$SIZE_T==4 ? sprintf("zdep%s,%d,%d,",$1,31-$2,32-$2)
++		:            sprintf("depd,z%s,%d,%d,",$1,63-$2,64-$2)/e;
++
++	s/^\s+([a-z]+)([\S]*)\s+([\S]*)/&assemble($1,$2,$3)/e if ($SIZE_T==4);
++
++	s/cmpb,\*/comb,/ if ($SIZE_T==4);
++
++	s/\bbv\b/bve/    if ($SIZE_T==8);
++
++	print $_,"\n";
++}
++
++close STDOUT;
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/sha/asm/sha512-ppc.pl b/CryptoPkg/Library/OpensslLib/openssl/crypto/sha/asm/sha512-ppc.pl
+new file mode 100755
+index 0000000..fe95b01
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/sha/asm/sha512-ppc.pl
+@@ -0,0 +1,799 @@
++#! /usr/bin/env perl
++# Copyright 2006-2016 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
++# in the file LICENSE in the source distribution or at
++# https://www.openssl.org/source/license.html
++
++
++# ====================================================================
++# Written by Andy Polyakov  for the OpenSSL
++# project. The module is, however, dual licensed under OpenSSL and
++# CRYPTOGAMS licenses depending on where you obtain it. For further
++# details see http://www.openssl.org/~appro/cryptogams/.
++# ====================================================================
++
++# I let hardware handle unaligned input, except on page boundaries
++# (see below for details). Otherwise straightforward implementation
++# with X vector in register bank.
++
++#			sha256		|	sha512
++# 			-m64	-m32	|	-m64	-m32
++# --------------------------------------+-----------------------
++# PPC970,gcc-4.0.0	+50%	+38%	|	+40%	+410%(*)
++# Power6,xlc-7		+150%	+90%	|	+100%	+430%(*)
++#
++# (*)	64-bit code in 32-bit application context, which actually is
++#	on TODO list. It should be noted that for safe deployment in
++#	32-bit *mutli-threaded* context asyncronous signals should be
++#	blocked upon entry to SHA512 block routine. This is because
++#	32-bit signaling procedure invalidates upper halves of GPRs.
++#	Context switch procedure preserves them, but not signaling:-(
++
++# Second version is true multi-thread safe. Trouble with the original
++# version was that it was using thread local storage pointer register.
++# Well, it scrupulously preserved it, but the problem would arise the
++# moment asynchronous signal was delivered and signal handler would
++# dereference the TLS pointer. While it's never the case in openssl
++# application or test suite, we have to respect this scenario and not
++# use TLS pointer register. Alternative would be to require caller to
++# block signals prior calling this routine. For the record, in 32-bit
++# context R2 serves as TLS pointer, while in 64-bit context - R13.
++
++$flavour=shift;
++$output =shift;
++
++if ($flavour =~ /64/) {
++	$SIZE_T=8;
++	$LRSAVE=2*$SIZE_T;
++	$STU="stdu";
++	$UCMP="cmpld";
++	$SHL="sldi";
++	$POP="ld";
++	$PUSH="std";
++} elsif ($flavour =~ /32/) {
++	$SIZE_T=4;
++	$LRSAVE=$SIZE_T;
++	$STU="stwu";
++	$UCMP="cmplw";
++	$SHL="slwi";
++	$POP="lwz";
++	$PUSH="stw";
++} else { die "nonsense $flavour"; }
++
++$LITTLE_ENDIAN = ($flavour=~/le$/) ? $SIZE_T : 0;
++
++$0 =~ m/(.*[\/\\])[^\/\\]+$/; $dir=$1;
++( $xlate="${dir}ppc-xlate.pl" and -f $xlate ) or
++( $xlate="${dir}../../perlasm/ppc-xlate.pl" and -f $xlate) or
++die "can't locate ppc-xlate.pl";
++
++open STDOUT,"| $^X $xlate $flavour $output" || die "can't call $xlate: $!";
++
++if ($output =~ /512/) {
++	$func="sha512_block_ppc";
++	$SZ=8;
++	@Sigma0=(28,34,39);
++	@Sigma1=(14,18,41);
++	@sigma0=(1,  8, 7);
++	@sigma1=(19,61, 6);
++	$rounds=80;
++	$LD="ld";
++	$ST="std";
++	$ROR="rotrdi";
++	$SHR="srdi";
++} else {
++	$func="sha256_block_ppc";
++	$SZ=4;
++	@Sigma0=( 2,13,22);
++	@Sigma1=( 6,11,25);
++	@sigma0=( 7,18, 3);
++	@sigma1=(17,19,10);
++	$rounds=64;
++	$LD="lwz";
++	$ST="stw";
++	$ROR="rotrwi";
++	$SHR="srwi";
++}
++
++$FRAME=32*$SIZE_T+16*$SZ;
++$LOCALS=6*$SIZE_T;
++
++$sp ="r1";
++$toc="r2";
++$ctx="r3";	# zapped by $a0
++$inp="r4";	# zapped by $a1
++$num="r5";	# zapped by $t0
++
++$T  ="r0";
++$a0 ="r3";
++$a1 ="r4";
++$t0 ="r5";
++$t1 ="r6";
++$Tbl="r7";
++
++$A  ="r8";
++$B  ="r9";
++$C  ="r10";
++$D  ="r11";
++$E  ="r12";
++$F  =$t1;	$t1 = "r0";	# stay away from "r13";
++$G  ="r14";
++$H  ="r15";
++
++@V=($A,$B,$C,$D,$E,$F,$G,$H);
++@X=("r16","r17","r18","r19","r20","r21","r22","r23",
++    "r24","r25","r26","r27","r28","r29","r30","r31");
++
++$inp="r31" if($SZ==4 || $SIZE_T==8);	# reassigned $inp! aliases with @X[15]
++
++sub ROUND_00_15 {
++my ($i,$a,$b,$c,$d,$e,$f,$g,$h)=@_;
++$code.=<<___;
++	$ROR	$a0,$e,$Sigma1[0]
++	$ROR	$a1,$e,$Sigma1[1]
++	and	$t0,$f,$e
++	xor	$a0,$a0,$a1
++	add	$h,$h,$t1
++	andc	$t1,$g,$e
++	$ROR	$a1,$a1,`$Sigma1[2]-$Sigma1[1]`
++	or	$t0,$t0,$t1		; Ch(e,f,g)
++	add	$h,$h,@X[$i%16]
++	xor	$a0,$a0,$a1		; Sigma1(e)
++	add	$h,$h,$t0
++	add	$h,$h,$a0
++
++	$ROR	$a0,$a,$Sigma0[0]
++	$ROR	$a1,$a,$Sigma0[1]
++	and	$t0,$a,$b
++	and	$t1,$a,$c
++	xor	$a0,$a0,$a1
++	$ROR	$a1,$a1,`$Sigma0[2]-$Sigma0[1]`
++	xor	$t0,$t0,$t1
++	and	$t1,$b,$c
++	xor	$a0,$a0,$a1		; Sigma0(a)
++	add	$d,$d,$h
++	xor	$t0,$t0,$t1		; Maj(a,b,c)
++___
++$code.=<<___ if ($i<15);
++	$LD	$t1,`($i+1)*$SZ`($Tbl)
++___
++$code.=<<___;
++	add	$h,$h,$a0
++	add	$h,$h,$t0
++
++___
++}
++
++sub ROUND_16_xx {
++my ($i,$a,$b,$c,$d,$e,$f,$g,$h)=@_;
++$i-=16;
++$code.=<<___;
++	$ROR	$a0,@X[($i+1)%16],$sigma0[0]
++	$ROR	$a1,@X[($i+1)%16],$sigma0[1]
++	$ROR	$t0,@X[($i+14)%16],$sigma1[0]
++	$ROR	$t1,@X[($i+14)%16],$sigma1[1]
++	xor	$a0,$a0,$a1
++	$SHR	$a1,@X[($i+1)%16],$sigma0[2]
++	xor	$t0,$t0,$t1
++	$SHR	$t1,@X[($i+14)%16],$sigma1[2]
++	add	@X[$i],@X[$i],@X[($i+9)%16]
++	xor	$a0,$a0,$a1		; sigma0(X[(i+1)&0x0f])
++	xor	$t0,$t0,$t1		; sigma1(X[(i+14)&0x0f])
++	$LD	$t1,`$i*$SZ`($Tbl)
++	add	@X[$i],@X[$i],$a0
++	add	@X[$i],@X[$i],$t0
++___
++&ROUND_00_15($i+16,$a,$b,$c,$d,$e,$f,$g,$h);
++}
++
++$code=<<___;
++.machine	"any"
++.text
++
++.globl	$func
++.align	6
++$func:
++	$STU	$sp,-$FRAME($sp)
++	mflr	r0
++	$SHL	$num,$num,`log(16*$SZ)/log(2)`
++
++	$PUSH	$ctx,`$FRAME-$SIZE_T*22`($sp)
++
++	$PUSH	r14,`$FRAME-$SIZE_T*18`($sp)
++	$PUSH	r15,`$FRAME-$SIZE_T*17`($sp)
++	$PUSH	r16,`$FRAME-$SIZE_T*16`($sp)
++	$PUSH	r17,`$FRAME-$SIZE_T*15`($sp)
++	$PUSH	r18,`$FRAME-$SIZE_T*14`($sp)
++	$PUSH	r19,`$FRAME-$SIZE_T*13`($sp)
++	$PUSH	r20,`$FRAME-$SIZE_T*12`($sp)
++	$PUSH	r21,`$FRAME-$SIZE_T*11`($sp)
++	$PUSH	r22,`$FRAME-$SIZE_T*10`($sp)
++	$PUSH	r23,`$FRAME-$SIZE_T*9`($sp)
++	$PUSH	r24,`$FRAME-$SIZE_T*8`($sp)
++	$PUSH	r25,`$FRAME-$SIZE_T*7`($sp)
++	$PUSH	r26,`$FRAME-$SIZE_T*6`($sp)
++	$PUSH	r27,`$FRAME-$SIZE_T*5`($sp)
++	$PUSH	r28,`$FRAME-$SIZE_T*4`($sp)
++	$PUSH	r29,`$FRAME-$SIZE_T*3`($sp)
++	$PUSH	r30,`$FRAME-$SIZE_T*2`($sp)
++	$PUSH	r31,`$FRAME-$SIZE_T*1`($sp)
++	$PUSH	r0,`$FRAME+$LRSAVE`($sp)
++___
++
++if ($SZ==4 || $SIZE_T==8) {
++$code.=<<___;
++	$LD	$A,`0*$SZ`($ctx)
++	mr	$inp,r4				; incarnate $inp
++	$LD	$B,`1*$SZ`($ctx)
++	$LD	$C,`2*$SZ`($ctx)
++	$LD	$D,`3*$SZ`($ctx)
++	$LD	$E,`4*$SZ`($ctx)
++	$LD	$F,`5*$SZ`($ctx)
++	$LD	$G,`6*$SZ`($ctx)
++	$LD	$H,`7*$SZ`($ctx)
++___
++} else {
++  for ($i=16;$i<32;$i++) {
++    $code.=<<___;
++	lwz	r$i,`$LITTLE_ENDIAN^(4*($i-16))`($ctx)
++___
++  }
++}
++
++$code.=<<___;
++	bl	LPICmeup
++LPICedup:
++	andi.	r0,$inp,3
++	bne	Lunaligned
++Laligned:
++	add	$num,$inp,$num
++	$PUSH	$num,`$FRAME-$SIZE_T*24`($sp)	; end pointer
++	$PUSH	$inp,`$FRAME-$SIZE_T*23`($sp)	; inp pointer
++	bl	Lsha2_block_private
++	b	Ldone
++
++; PowerPC specification allows an implementation to be ill-behaved
++; upon unaligned access which crosses page boundary. "Better safe
++; than sorry" principle makes me treat it specially. But I don't
++; look for particular offending word, but rather for the input
++; block which crosses the boundary. Once found that block is aligned
++; and hashed separately...
++.align	4
++Lunaligned:
++	subfic	$t1,$inp,4096
++	andi.	$t1,$t1,`4096-16*$SZ`	; distance to closest page boundary
++	beq	Lcross_page
++	$UCMP	$num,$t1
++	ble	Laligned		; didn't cross the page boundary
++	subfc	$num,$t1,$num
++	add	$t1,$inp,$t1
++	$PUSH	$num,`$FRAME-$SIZE_T*25`($sp)	; save real remaining num
++	$PUSH	$t1,`$FRAME-$SIZE_T*24`($sp)	; intermediate end pointer
++	$PUSH	$inp,`$FRAME-$SIZE_T*23`($sp)	; inp pointer
++	bl	Lsha2_block_private
++	; $inp equals to the intermediate end pointer here
++	$POP	$num,`$FRAME-$SIZE_T*25`($sp)	; restore real remaining num
++Lcross_page:
++	li	$t1,`16*$SZ/4`
++	mtctr	$t1
++___
++if ($SZ==4 || $SIZE_T==8) {
++$code.=<<___;
++	addi	r20,$sp,$LOCALS			; aligned spot below the frame
++Lmemcpy:
++	lbz	r16,0($inp)
++	lbz	r17,1($inp)
++	lbz	r18,2($inp)
++	lbz	r19,3($inp)
++	addi	$inp,$inp,4
++	stb	r16,0(r20)
++	stb	r17,1(r20)
++	stb	r18,2(r20)
++	stb	r19,3(r20)
++	addi	r20,r20,4
++	bdnz	Lmemcpy
++___
++} else {
++$code.=<<___;
++	addi	r12,$sp,$LOCALS			; aligned spot below the frame
++Lmemcpy:
++	lbz	r8,0($inp)
++	lbz	r9,1($inp)
++	lbz	r10,2($inp)
++	lbz	r11,3($inp)
++	addi	$inp,$inp,4
++	stb	r8,0(r12)
++	stb	r9,1(r12)
++	stb	r10,2(r12)
++	stb	r11,3(r12)
++	addi	r12,r12,4
++	bdnz	Lmemcpy
++___
++}
++
++$code.=<<___;
++	$PUSH	$inp,`$FRAME-$SIZE_T*26`($sp)	; save real inp
++	addi	$t1,$sp,`$LOCALS+16*$SZ`	; fictitious end pointer
++	addi	$inp,$sp,$LOCALS		; fictitious inp pointer
++	$PUSH	$num,`$FRAME-$SIZE_T*25`($sp)	; save real num
++	$PUSH	$t1,`$FRAME-$SIZE_T*24`($sp)	; end pointer
++	$PUSH	$inp,`$FRAME-$SIZE_T*23`($sp)	; inp pointer
++	bl	Lsha2_block_private
++	$POP	$inp,`$FRAME-$SIZE_T*26`($sp)	; restore real inp
++	$POP	$num,`$FRAME-$SIZE_T*25`($sp)	; restore real num
++	addic.	$num,$num,`-16*$SZ`		; num--
++	bne	Lunaligned
++
++Ldone:
++	$POP	r0,`$FRAME+$LRSAVE`($sp)
++	$POP	r14,`$FRAME-$SIZE_T*18`($sp)
++	$POP	r15,`$FRAME-$SIZE_T*17`($sp)
++	$POP	r16,`$FRAME-$SIZE_T*16`($sp)
++	$POP	r17,`$FRAME-$SIZE_T*15`($sp)
++	$POP	r18,`$FRAME-$SIZE_T*14`($sp)
++	$POP	r19,`$FRAME-$SIZE_T*13`($sp)
++	$POP	r20,`$FRAME-$SIZE_T*12`($sp)
++	$POP	r21,`$FRAME-$SIZE_T*11`($sp)
++	$POP	r22,`$FRAME-$SIZE_T*10`($sp)
++	$POP	r23,`$FRAME-$SIZE_T*9`($sp)
++	$POP	r24,`$FRAME-$SIZE_T*8`($sp)
++	$POP	r25,`$FRAME-$SIZE_T*7`($sp)
++	$POP	r26,`$FRAME-$SIZE_T*6`($sp)
++	$POP	r27,`$FRAME-$SIZE_T*5`($sp)
++	$POP	r28,`$FRAME-$SIZE_T*4`($sp)
++	$POP	r29,`$FRAME-$SIZE_T*3`($sp)
++	$POP	r30,`$FRAME-$SIZE_T*2`($sp)
++	$POP	r31,`$FRAME-$SIZE_T*1`($sp)
++	mtlr	r0
++	addi	$sp,$sp,$FRAME
++	blr
++	.long	0
++	.byte	0,12,4,1,0x80,18,3,0
++	.long	0
++___
++
++if ($SZ==4 || $SIZE_T==8) {
++$code.=<<___;
++.align	4
++Lsha2_block_private:
++	$LD	$t1,0($Tbl)
++___
++for($i=0;$i<16;$i++) {
++$code.=<<___ if ($SZ==4 && !$LITTLE_ENDIAN);
++	lwz	@X[$i],`$i*$SZ`($inp)
++___
++$code.=<<___ if ($SZ==4 && $LITTLE_ENDIAN);
++	lwz	$a0,`$i*$SZ`($inp)
++	rotlwi	@X[$i],$a0,8
++	rlwimi	@X[$i],$a0,24,0,7
++	rlwimi	@X[$i],$a0,24,16,23
++___
++# 64-bit loads are split to 2x32-bit ones, as CPU can't handle
++# unaligned 64-bit loads, only 32-bit ones...
++$code.=<<___ if ($SZ==8 && !$LITTLE_ENDIAN);
++	lwz	$t0,`$i*$SZ`($inp)
++	lwz	@X[$i],`$i*$SZ+4`($inp)
++	insrdi	@X[$i],$t0,32,0
++___
++$code.=<<___ if ($SZ==8 && $LITTLE_ENDIAN);
++	lwz	$a0,`$i*$SZ`($inp)
++	 lwz	$a1,`$i*$SZ+4`($inp)
++	rotlwi	$t0,$a0,8
++	 rotlwi	@X[$i],$a1,8
++	rlwimi	$t0,$a0,24,0,7
++	 rlwimi	@X[$i],$a1,24,0,7
++	rlwimi	$t0,$a0,24,16,23
++	 rlwimi	@X[$i],$a1,24,16,23
++	insrdi	@X[$i],$t0,32,0
++___
++	&ROUND_00_15($i,@V);
++	unshift(@V,pop(@V));
++}
++$code.=<<___;
++	li	$t0,`$rounds/16-1`
++	mtctr	$t0
++.align	4
++Lrounds:
++	addi	$Tbl,$Tbl,`16*$SZ`
++___
++for(;$i<32;$i++) {
++	&ROUND_16_xx($i,@V);
++	unshift(@V,pop(@V));
++}
++$code.=<<___;
++	bdnz	Lrounds
++
++	$POP	$ctx,`$FRAME-$SIZE_T*22`($sp)
++	$POP	$inp,`$FRAME-$SIZE_T*23`($sp)	; inp pointer
++	$POP	$num,`$FRAME-$SIZE_T*24`($sp)	; end pointer
++	subi	$Tbl,$Tbl,`($rounds-16)*$SZ`	; rewind Tbl
++
++	$LD	r16,`0*$SZ`($ctx)
++	$LD	r17,`1*$SZ`($ctx)
++	$LD	r18,`2*$SZ`($ctx)
++	$LD	r19,`3*$SZ`($ctx)
++	$LD	r20,`4*$SZ`($ctx)
++	$LD	r21,`5*$SZ`($ctx)
++	$LD	r22,`6*$SZ`($ctx)
++	addi	$inp,$inp,`16*$SZ`		; advance inp
++	$LD	r23,`7*$SZ`($ctx)
++	add	$A,$A,r16
++	add	$B,$B,r17
++	$PUSH	$inp,`$FRAME-$SIZE_T*23`($sp)
++	add	$C,$C,r18
++	$ST	$A,`0*$SZ`($ctx)
++	add	$D,$D,r19
++	$ST	$B,`1*$SZ`($ctx)
++	add	$E,$E,r20
++	$ST	$C,`2*$SZ`($ctx)
++	add	$F,$F,r21
++	$ST	$D,`3*$SZ`($ctx)
++	add	$G,$G,r22
++	$ST	$E,`4*$SZ`($ctx)
++	add	$H,$H,r23
++	$ST	$F,`5*$SZ`($ctx)
++	$ST	$G,`6*$SZ`($ctx)
++	$UCMP	$inp,$num
++	$ST	$H,`7*$SZ`($ctx)
++	bne	Lsha2_block_private
++	blr
++	.long	0
++	.byte	0,12,0x14,0,0,0,0,0
++.size	$func,.-$func
++___
++} else {
++########################################################################
++# SHA512 for PPC32, X vector is off-loaded to stack...
++#
++#			|	sha512
++#			|	-m32
++# ----------------------+-----------------------
++# PPC74x0,gcc-4.0.1	|	+48%
++# POWER6,gcc-4.4.6	|	+124%(*)
++# POWER7,gcc-4.4.6	|	+79%(*)
++# e300,gcc-4.1.0	|	+167%
++#
++# (*)	~1/3 of -m64 result [and ~20% better than -m32 code generated
++#	by xlc-12.1]
++
++my $XOFF=$LOCALS;
++
++my @V=map("r$_",(16..31));	# A..H
++
++my ($s0,$s1,$t0,$t1,$t2,$t3,$a0,$a1,$a2,$a3)=map("r$_",(0,5,6,8..12,14,15));
++my ($x0,$x1)=("r3","r4");	# zaps $ctx and $inp
++
++sub ROUND_00_15_ppc32 {
++my ($i,	$ahi,$alo,$bhi,$blo,$chi,$clo,$dhi,$dlo,
++	$ehi,$elo,$fhi,$flo,$ghi,$glo,$hhi,$hlo)=@_;
++
++$code.=<<___;
++	lwz	$t2,`$SZ*($i%16)+($LITTLE_ENDIAN^4)`($Tbl)
++	 xor	$a0,$flo,$glo
++	lwz	$t3,`$SZ*($i%16)+($LITTLE_ENDIAN^0)`($Tbl)
++	 xor	$a1,$fhi,$ghi
++	addc	$hlo,$hlo,$t0			; h+=x[i]
++	stw	$t0,`$XOFF+0+$SZ*($i%16)`($sp)	; save x[i]
++
++	srwi	$s0,$elo,$Sigma1[0]
++	srwi	$s1,$ehi,$Sigma1[0]
++	 and	$a0,$a0,$elo
++	adde	$hhi,$hhi,$t1
++	 and	$a1,$a1,$ehi
++	stw	$t1,`$XOFF+4+$SZ*($i%16)`($sp)
++	srwi	$t0,$elo,$Sigma1[1]
++	srwi	$t1,$ehi,$Sigma1[1]
++	 addc	$hlo,$hlo,$t2			; h+=K512[i]
++	insrwi	$s0,$ehi,$Sigma1[0],0
++	insrwi	$s1,$elo,$Sigma1[0],0
++	 xor	$a0,$a0,$glo			; Ch(e,f,g)
++	 adde	$hhi,$hhi,$t3
++	 xor	$a1,$a1,$ghi
++	insrwi	$t0,$ehi,$Sigma1[1],0
++	insrwi	$t1,$elo,$Sigma1[1],0
++	 addc	$hlo,$hlo,$a0			; h+=Ch(e,f,g)
++	srwi	$t2,$ehi,$Sigma1[2]-32
++	srwi	$t3,$elo,$Sigma1[2]-32
++	xor	$s0,$s0,$t0
++	xor	$s1,$s1,$t1
++	insrwi	$t2,$elo,$Sigma1[2]-32,0
++	insrwi	$t3,$ehi,$Sigma1[2]-32,0
++	 xor	$a0,$alo,$blo			; a^b, b^c in next round
++	 adde	$hhi,$hhi,$a1
++	 xor	$a1,$ahi,$bhi
++	xor	$s0,$s0,$t2			; Sigma1(e)
++	xor	$s1,$s1,$t3
++
++	srwi	$t0,$alo,$Sigma0[0]
++	 and	$a2,$a2,$a0
++	 addc	$hlo,$hlo,$s0			; h+=Sigma1(e)
++	 and	$a3,$a3,$a1
++	srwi	$t1,$ahi,$Sigma0[0]
++	srwi	$s0,$ahi,$Sigma0[1]-32
++	 adde	$hhi,$hhi,$s1
++	srwi	$s1,$alo,$Sigma0[1]-32
++	insrwi	$t0,$ahi,$Sigma0[0],0
++	insrwi	$t1,$alo,$Sigma0[0],0
++	 xor	$a2,$a2,$blo			; Maj(a,b,c)
++	 addc	$dlo,$dlo,$hlo			; d+=h
++	 xor	$a3,$a3,$bhi
++	insrwi	$s0,$alo,$Sigma0[1]-32,0
++	insrwi	$s1,$ahi,$Sigma0[1]-32,0
++	 adde	$dhi,$dhi,$hhi
++	srwi	$t2,$ahi,$Sigma0[2]-32
++	srwi	$t3,$alo,$Sigma0[2]-32
++	xor	$s0,$s0,$t0
++	 addc	$hlo,$hlo,$a2			; h+=Maj(a,b,c)
++	xor	$s1,$s1,$t1
++	insrwi	$t2,$alo,$Sigma0[2]-32,0
++	insrwi	$t3,$ahi,$Sigma0[2]-32,0
++	 adde	$hhi,$hhi,$a3
++___
++$code.=<<___ if ($i>=15);
++	lwz	$t0,`$XOFF+0+$SZ*(($i+2)%16)`($sp)
++	lwz	$t1,`$XOFF+4+$SZ*(($i+2)%16)`($sp)
++___
++$code.=<<___ if ($i<15 && !$LITTLE_ENDIAN);
++	lwz	$t1,`$SZ*($i+1)+0`($inp)
++	lwz	$t0,`$SZ*($i+1)+4`($inp)
++___
++$code.=<<___ if ($i<15 && $LITTLE_ENDIAN);
++	lwz	$a2,`$SZ*($i+1)+0`($inp)
++	 lwz	$a3,`$SZ*($i+1)+4`($inp)
++	rotlwi	$t1,$a2,8
++	 rotlwi	$t0,$a3,8
++	rlwimi	$t1,$a2,24,0,7
++	 rlwimi	$t0,$a3,24,0,7
++	rlwimi	$t1,$a2,24,16,23
++	 rlwimi	$t0,$a3,24,16,23
++___
++$code.=<<___;
++	xor	$s0,$s0,$t2			; Sigma0(a)
++	xor	$s1,$s1,$t3
++	addc	$hlo,$hlo,$s0			; h+=Sigma0(a)
++	adde	$hhi,$hhi,$s1
++___
++$code.=<<___ if ($i==15);
++	lwz	$x0,`$XOFF+0+$SZ*(($i+1)%16)`($sp)
++	lwz	$x1,`$XOFF+4+$SZ*(($i+1)%16)`($sp)
++___
++}
++sub ROUND_16_xx_ppc32 {
++my ($i,	$ahi,$alo,$bhi,$blo,$chi,$clo,$dhi,$dlo,
++	$ehi,$elo,$fhi,$flo,$ghi,$glo,$hhi,$hlo)=@_;
++
++$code.=<<___;
++	srwi	$s0,$t0,$sigma0[0]
++	srwi	$s1,$t1,$sigma0[0]
++	srwi	$t2,$t0,$sigma0[1]
++	srwi	$t3,$t1,$sigma0[1]
++	insrwi	$s0,$t1,$sigma0[0],0
++	insrwi	$s1,$t0,$sigma0[0],0
++	srwi	$a0,$t0,$sigma0[2]
++	insrwi	$t2,$t1,$sigma0[1],0
++	insrwi	$t3,$t0,$sigma0[1],0
++	insrwi	$a0,$t1,$sigma0[2],0
++	xor	$s0,$s0,$t2
++	 lwz	$t2,`$XOFF+0+$SZ*(($i+14)%16)`($sp)
++	srwi	$a1,$t1,$sigma0[2]
++	xor	$s1,$s1,$t3
++	 lwz	$t3,`$XOFF+4+$SZ*(($i+14)%16)`($sp)
++	xor	$a0,$a0,$s0
++	 srwi	$s0,$t2,$sigma1[0]
++	xor	$a1,$a1,$s1
++	 srwi	$s1,$t3,$sigma1[0]
++	addc	$x0,$x0,$a0			; x[i]+=sigma0(x[i+1])
++	 srwi	$a0,$t3,$sigma1[1]-32
++	insrwi	$s0,$t3,$sigma1[0],0
++	insrwi	$s1,$t2,$sigma1[0],0
++	adde	$x1,$x1,$a1
++	 srwi	$a1,$t2,$sigma1[1]-32
++
++	insrwi	$a0,$t2,$sigma1[1]-32,0
++	srwi	$t2,$t2,$sigma1[2]
++	insrwi	$a1,$t3,$sigma1[1]-32,0
++	insrwi	$t2,$t3,$sigma1[2],0
++	xor	$s0,$s0,$a0
++	 lwz	$a0,`$XOFF+0+$SZ*(($i+9)%16)`($sp)
++	srwi	$t3,$t3,$sigma1[2]
++	xor	$s1,$s1,$a1
++	 lwz	$a1,`$XOFF+4+$SZ*(($i+9)%16)`($sp)
++	xor	$s0,$s0,$t2
++	 addc	$x0,$x0,$a0			; x[i]+=x[i+9]
++	xor	$s1,$s1,$t3
++	 adde	$x1,$x1,$a1
++	addc	$x0,$x0,$s0			; x[i]+=sigma1(x[i+14])
++	adde	$x1,$x1,$s1
++___
++	($t0,$t1,$x0,$x1) = ($x0,$x1,$t0,$t1);
++	&ROUND_00_15_ppc32(@_);
++}
++
++$code.=<<___;
++.align	4
++Lsha2_block_private:
++___
++$code.=<<___ if (!$LITTLE_ENDIAN);
++	lwz	$t1,0($inp)
++	xor	$a2,@V[3],@V[5]		; B^C, magic seed
++	lwz	$t0,4($inp)
++	xor	$a3,@V[2],@V[4]
++___
++$code.=<<___ if ($LITTLE_ENDIAN);
++	lwz	$a1,0($inp)
++	xor	$a2,@V[3],@V[5]		; B^C, magic seed
++	lwz	$a0,4($inp)
++	xor	$a3,@V[2],@V[4]
++	rotlwi	$t1,$a1,8
++	 rotlwi	$t0,$a0,8
++	rlwimi	$t1,$a1,24,0,7
++	 rlwimi	$t0,$a0,24,0,7
++	rlwimi	$t1,$a1,24,16,23
++	 rlwimi	$t0,$a0,24,16,23
++___
++for($i=0;$i<16;$i++) {
++	&ROUND_00_15_ppc32($i,@V);
++	unshift(@V,pop(@V));	unshift(@V,pop(@V));
++	($a0,$a1,$a2,$a3) = ($a2,$a3,$a0,$a1);
++}
++$code.=<<___;
++	li	$a0,`$rounds/16-1`
++	mtctr	$a0
++.align	4
++Lrounds:
++	addi	$Tbl,$Tbl,`16*$SZ`
++___
++for(;$i<32;$i++) {
++	&ROUND_16_xx_ppc32($i,@V);
++	unshift(@V,pop(@V));	unshift(@V,pop(@V));
++	($a0,$a1,$a2,$a3) = ($a2,$a3,$a0,$a1);
++}
++$code.=<<___;
++	bdnz	Lrounds
++
++	$POP	$ctx,`$FRAME-$SIZE_T*22`($sp)
++	$POP	$inp,`$FRAME-$SIZE_T*23`($sp)	; inp pointer
++	$POP	$num,`$FRAME-$SIZE_T*24`($sp)	; end pointer
++	subi	$Tbl,$Tbl,`($rounds-16)*$SZ`	; rewind Tbl
++
++	lwz	$t0,`$LITTLE_ENDIAN^0`($ctx)
++	lwz	$t1,`$LITTLE_ENDIAN^4`($ctx)
++	lwz	$t2,`$LITTLE_ENDIAN^8`($ctx)
++	lwz	$t3,`$LITTLE_ENDIAN^12`($ctx)
++	lwz	$a0,`$LITTLE_ENDIAN^16`($ctx)
++	lwz	$a1,`$LITTLE_ENDIAN^20`($ctx)
++	lwz	$a2,`$LITTLE_ENDIAN^24`($ctx)
++	addc	@V[1],@V[1],$t1
++	lwz	$a3,`$LITTLE_ENDIAN^28`($ctx)
++	adde	@V[0],@V[0],$t0
++	lwz	$t0,`$LITTLE_ENDIAN^32`($ctx)
++	addc	@V[3],@V[3],$t3
++	lwz	$t1,`$LITTLE_ENDIAN^36`($ctx)
++	adde	@V[2],@V[2],$t2
++	lwz	$t2,`$LITTLE_ENDIAN^40`($ctx)
++	addc	@V[5],@V[5],$a1
++	lwz	$t3,`$LITTLE_ENDIAN^44`($ctx)
++	adde	@V[4],@V[4],$a0
++	lwz	$a0,`$LITTLE_ENDIAN^48`($ctx)
++	addc	@V[7],@V[7],$a3
++	lwz	$a1,`$LITTLE_ENDIAN^52`($ctx)
++	adde	@V[6],@V[6],$a2
++	lwz	$a2,`$LITTLE_ENDIAN^56`($ctx)
++	addc	@V[9],@V[9],$t1
++	lwz	$a3,`$LITTLE_ENDIAN^60`($ctx)
++	adde	@V[8],@V[8],$t0
++	stw	@V[0],`$LITTLE_ENDIAN^0`($ctx)
++	stw	@V[1],`$LITTLE_ENDIAN^4`($ctx)
++	addc	@V[11],@V[11],$t3
++	stw	@V[2],`$LITTLE_ENDIAN^8`($ctx)
++	stw	@V[3],`$LITTLE_ENDIAN^12`($ctx)
++	adde	@V[10],@V[10],$t2
++	stw	@V[4],`$LITTLE_ENDIAN^16`($ctx)
++	stw	@V[5],`$LITTLE_ENDIAN^20`($ctx)
++	addc	@V[13],@V[13],$a1
++	stw	@V[6],`$LITTLE_ENDIAN^24`($ctx)
++	stw	@V[7],`$LITTLE_ENDIAN^28`($ctx)
++	adde	@V[12],@V[12],$a0
++	stw	@V[8],`$LITTLE_ENDIAN^32`($ctx)
++	stw	@V[9],`$LITTLE_ENDIAN^36`($ctx)
++	addc	@V[15],@V[15],$a3
++	stw	@V[10],`$LITTLE_ENDIAN^40`($ctx)
++	stw	@V[11],`$LITTLE_ENDIAN^44`($ctx)
++	adde	@V[14],@V[14],$a2
++	stw	@V[12],`$LITTLE_ENDIAN^48`($ctx)
++	stw	@V[13],`$LITTLE_ENDIAN^52`($ctx)
++	stw	@V[14],`$LITTLE_ENDIAN^56`($ctx)
++	stw	@V[15],`$LITTLE_ENDIAN^60`($ctx)
++
++	addi	$inp,$inp,`16*$SZ`		; advance inp
++	$PUSH	$inp,`$FRAME-$SIZE_T*23`($sp)
++	$UCMP	$inp,$num
++	bne	Lsha2_block_private
++	blr
++	.long	0
++	.byte	0,12,0x14,0,0,0,0,0
++.size	$func,.-$func
++___
++}
++
++# Ugly hack here, because PPC assembler syntax seem to vary too
++# much from platforms to platform...
++$code.=<<___;
++.align	6
++LPICmeup:
++	mflr	r0
++	bcl	20,31,\$+4
++	mflr	$Tbl	; vvvvvv "distance" between . and 1st data entry
++	addi	$Tbl,$Tbl,`64-8`
++	mtlr	r0
++	blr
++	.long	0
++	.byte	0,12,0x14,0,0,0,0,0
++	.space	`64-9*4`
++___
++$code.=<<___ if ($SZ==8);
++	.quad	0x428a2f98d728ae22,0x7137449123ef65cd
++	.quad	0xb5c0fbcfec4d3b2f,0xe9b5dba58189dbbc
++	.quad	0x3956c25bf348b538,0x59f111f1b605d019
++	.quad	0x923f82a4af194f9b,0xab1c5ed5da6d8118
++	.quad	0xd807aa98a3030242,0x12835b0145706fbe
++	.quad	0x243185be4ee4b28c,0x550c7dc3d5ffb4e2
++	.quad	0x72be5d74f27b896f,0x80deb1fe3b1696b1
++	.quad	0x9bdc06a725c71235,0xc19bf174cf692694
++	.quad	0xe49b69c19ef14ad2,0xefbe4786384f25e3
++	.quad	0x0fc19dc68b8cd5b5,0x240ca1cc77ac9c65
++	.quad	0x2de92c6f592b0275,0x4a7484aa6ea6e483
++	.quad	0x5cb0a9dcbd41fbd4,0x76f988da831153b5
++	.quad	0x983e5152ee66dfab,0xa831c66d2db43210
++	.quad	0xb00327c898fb213f,0xbf597fc7beef0ee4
++	.quad	0xc6e00bf33da88fc2,0xd5a79147930aa725
++	.quad	0x06ca6351e003826f,0x142929670a0e6e70
++	.quad	0x27b70a8546d22ffc,0x2e1b21385c26c926
++	.quad	0x4d2c6dfc5ac42aed,0x53380d139d95b3df
++	.quad	0x650a73548baf63de,0x766a0abb3c77b2a8
++	.quad	0x81c2c92e47edaee6,0x92722c851482353b
++	.quad	0xa2bfe8a14cf10364,0xa81a664bbc423001
++	.quad	0xc24b8b70d0f89791,0xc76c51a30654be30
++	.quad	0xd192e819d6ef5218,0xd69906245565a910
++	.quad	0xf40e35855771202a,0x106aa07032bbd1b8
++	.quad	0x19a4c116b8d2d0c8,0x1e376c085141ab53
++	.quad	0x2748774cdf8eeb99,0x34b0bcb5e19b48a8
++	.quad	0x391c0cb3c5c95a63,0x4ed8aa4ae3418acb
++	.quad	0x5b9cca4f7763e373,0x682e6ff3d6b2b8a3
++	.quad	0x748f82ee5defb2fc,0x78a5636f43172f60
++	.quad	0x84c87814a1f0ab72,0x8cc702081a6439ec
++	.quad	0x90befffa23631e28,0xa4506cebde82bde9
++	.quad	0xbef9a3f7b2c67915,0xc67178f2e372532b
++	.quad	0xca273eceea26619c,0xd186b8c721c0c207
++	.quad	0xeada7dd6cde0eb1e,0xf57d4f7fee6ed178
++	.quad	0x06f067aa72176fba,0x0a637dc5a2c898a6
++	.quad	0x113f9804bef90dae,0x1b710b35131c471b
++	.quad	0x28db77f523047d84,0x32caab7b40c72493
++	.quad	0x3c9ebe0a15c9bebc,0x431d67c49c100d4c
++	.quad	0x4cc5d4becb3e42b6,0x597f299cfc657e2a
++	.quad	0x5fcb6fab3ad6faec,0x6c44198c4a475817
++___
++$code.=<<___ if ($SZ==4);
++	.long	0x428a2f98,0x71374491,0xb5c0fbcf,0xe9b5dba5
++	.long	0x3956c25b,0x59f111f1,0x923f82a4,0xab1c5ed5
++	.long	0xd807aa98,0x12835b01,0x243185be,0x550c7dc3
++	.long	0x72be5d74,0x80deb1fe,0x9bdc06a7,0xc19bf174
++	.long	0xe49b69c1,0xefbe4786,0x0fc19dc6,0x240ca1cc
++	.long	0x2de92c6f,0x4a7484aa,0x5cb0a9dc,0x76f988da
++	.long	0x983e5152,0xa831c66d,0xb00327c8,0xbf597fc7
++	.long	0xc6e00bf3,0xd5a79147,0x06ca6351,0x14292967
++	.long	0x27b70a85,0x2e1b2138,0x4d2c6dfc,0x53380d13
++	.long	0x650a7354,0x766a0abb,0x81c2c92e,0x92722c85
++	.long	0xa2bfe8a1,0xa81a664b,0xc24b8b70,0xc76c51a3
++	.long	0xd192e819,0xd6990624,0xf40e3585,0x106aa070
++	.long	0x19a4c116,0x1e376c08,0x2748774c,0x34b0bcb5
++	.long	0x391c0cb3,0x4ed8aa4a,0x5b9cca4f,0x682e6ff3
++	.long	0x748f82ee,0x78a5636f,0x84c87814,0x8cc70208
++	.long	0x90befffa,0xa4506ceb,0xbef9a3f7,0xc67178f2
++___
++
++$code =~ s/\`([^\`]*)\`/eval $1/gem;
++print $code;
++close STDOUT;
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/sha/asm/sha512-s390x.pl b/CryptoPkg/Library/OpensslLib/openssl/crypto/sha/asm/sha512-s390x.pl
+new file mode 100644
+index 0000000..582d393
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/sha/asm/sha512-s390x.pl
+@@ -0,0 +1,326 @@
++#! /usr/bin/env perl
++# Copyright 2007-2016 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
++# in the file LICENSE in the source distribution or at
++# https://www.openssl.org/source/license.html
++
++
++# ====================================================================
++# Written by Andy Polyakov  for the OpenSSL
++# project. The module is, however, dual licensed under OpenSSL and
++# CRYPTOGAMS licenses depending on where you obtain it. For further
++# details see http://www.openssl.org/~appro/cryptogams/.
++# ====================================================================
++
++# SHA256/512 block procedures for s390x.
++
++# April 2007.
++#
++# sha256_block_data_order is reportedly >3 times faster than gcc 3.3
++# generated code (must be a bug in compiler, as improvement is
++# "pathologically" high, in particular in comparison to other SHA
++# modules). But the real twist is that it detects if hardware support
++# for SHA256 is available and in such case utilizes it. Then the
++# performance can reach >6.5x of assembler one for larger chunks.
++#
++# sha512_block_data_order is ~70% faster than gcc 3.3 generated code.
++
++# January 2009.
++#
++# Add support for hardware SHA512 and reschedule instructions to
++# favour dual-issue z10 pipeline. Hardware SHA256/512 is ~4.7x faster
++# than software.
++
++# November 2010.
++#
++# Adapt for -m31 build. If kernel supports what's called "highgprs"
++# feature on Linux [see /proc/cpuinfo], it's possible to use 64-bit
++# instructions and achieve "64-bit" performance even in 31-bit legacy
++# application context. The feature is not specific to any particular
++# processor, as long as it's "z-CPU". Latter implies that the code
++# remains z/Architecture specific. On z990 SHA256 was measured to
++# perform 2.4x and SHA512 - 13x better than code generated by gcc 4.3.
++
++$flavour = shift;
++
++if ($flavour =~ /3[12]/) {
++	$SIZE_T=4;
++	$g="";
++} else {
++	$SIZE_T=8;
++	$g="g";
++}
++
++$t0="%r0";
++$t1="%r1";
++$ctx="%r2";	$t2="%r2";
++$inp="%r3";
++$len="%r4";	# used as index in inner loop
++
++$A="%r5";
++$B="%r6";
++$C="%r7";
++$D="%r8";
++$E="%r9";
++$F="%r10";
++$G="%r11";
++$H="%r12";	@V=($A,$B,$C,$D,$E,$F,$G,$H);
++$tbl="%r13";
++$T1="%r14";
++$sp="%r15";
++
++while (($output=shift) && ($output!~/\w[\w\-]*\.\w+$/)) {}
++open STDOUT,">$output";
++
++if ($output =~ /512/) {
++	$label="512";
++	$SZ=8;
++	$LD="lg";	# load from memory
++	$ST="stg";	# store to memory
++	$ADD="alg";	# add with memory operand
++	$ROT="rllg";	# rotate left
++	$SHR="srlg";	# logical right shift [see even at the end]
++	@Sigma0=(25,30,36);
++	@Sigma1=(23,46,50);
++	@sigma0=(56,63, 7);
++	@sigma1=( 3,45, 6);
++	$rounds=80;
++	$kimdfunc=3;	# 0 means unknown/unsupported/unimplemented/disabled
++} else {
++	$label="256";
++	$SZ=4;
++	$LD="llgf";	# load from memory
++	$ST="st";	# store to memory
++	$ADD="al";	# add with memory operand
++	$ROT="rll";	# rotate left
++	$SHR="srl";	# logical right shift
++	@Sigma0=(10,19,30);
++	@Sigma1=( 7,21,26);
++	@sigma0=(14,25, 3);
++	@sigma1=(13,15,10);
++	$rounds=64;
++	$kimdfunc=2;	# magic function code for kimd instruction
++}
++$Func="sha${label}_block_data_order";
++$Table="K${label}";
++$stdframe=16*$SIZE_T+4*8;
++$frame=$stdframe+16*$SZ;
++
++sub BODY_00_15 {
++my ($i,$a,$b,$c,$d,$e,$f,$g,$h) = @_;
++
++$code.=<<___ if ($i<16);
++	$LD	$T1,`$i*$SZ`($inp)	### $i
++___
++$code.=<<___;
++	$ROT	$t0,$e,$Sigma1[0]
++	$ROT	$t1,$e,$Sigma1[1]
++	 lgr	$t2,$f
++	xgr	$t0,$t1
++	$ROT	$t1,$t1,`$Sigma1[2]-$Sigma1[1]`
++	 xgr	$t2,$g
++	$ST	$T1,`$stdframe+$SZ*($i%16)`($sp)
++	xgr	$t0,$t1			# Sigma1(e)
++	algr	$T1,$h			# T1+=h
++	 ngr	$t2,$e
++	 lgr	$t1,$a
++	algr	$T1,$t0			# T1+=Sigma1(e)
++	$ROT	$h,$a,$Sigma0[0]
++	 xgr	$t2,$g			# Ch(e,f,g)
++	$ADD	$T1,`$i*$SZ`($len,$tbl)	# T1+=K[i]
++	$ROT	$t0,$a,$Sigma0[1]
++	algr	$T1,$t2			# T1+=Ch(e,f,g)
++	 ogr	$t1,$b
++	xgr	$h,$t0
++	 lgr	$t2,$a
++	 ngr	$t1,$c
++	$ROT	$t0,$t0,`$Sigma0[2]-$Sigma0[1]`
++	xgr	$h,$t0			# h=Sigma0(a)
++	 ngr	$t2,$b
++	algr	$h,$T1			# h+=T1
++	 ogr	$t2,$t1			# Maj(a,b,c)
++	algr	$d,$T1			# d+=T1
++	algr	$h,$t2			# h+=Maj(a,b,c)
++___
++}
++
++sub BODY_16_XX {
++my ($i,$a,$b,$c,$d,$e,$f,$g,$h) = @_;
++
++$code.=<<___;
++	$LD	$T1,`$stdframe+$SZ*(($i+1)%16)`($sp)	### $i
++	$LD	$t1,`$stdframe+$SZ*(($i+14)%16)`($sp)
++	$ROT	$t0,$T1,$sigma0[0]
++	$SHR	$T1,$sigma0[2]
++	$ROT	$t2,$t0,`$sigma0[1]-$sigma0[0]`
++	xgr	$T1,$t0
++	$ROT	$t0,$t1,$sigma1[0]
++	xgr	$T1,$t2					# sigma0(X[i+1])
++	$SHR	$t1,$sigma1[2]
++	$ADD	$T1,`$stdframe+$SZ*($i%16)`($sp)	# +=X[i]
++	xgr	$t1,$t0
++	$ROT	$t0,$t0,`$sigma1[1]-$sigma1[0]`
++	$ADD	$T1,`$stdframe+$SZ*(($i+9)%16)`($sp)	# +=X[i+9]
++	xgr	$t1,$t0				# sigma1(X[i+14])
++	algr	$T1,$t1				# +=sigma1(X[i+14])
++___
++	&BODY_00_15(@_);
++}
++
++$code.=<<___;
++.text
++.align	64
++.type	$Table,\@object
++$Table:
++___
++$code.=<<___ if ($SZ==4);
++	.long	0x428a2f98,0x71374491,0xb5c0fbcf,0xe9b5dba5
++	.long	0x3956c25b,0x59f111f1,0x923f82a4,0xab1c5ed5
++	.long	0xd807aa98,0x12835b01,0x243185be,0x550c7dc3
++	.long	0x72be5d74,0x80deb1fe,0x9bdc06a7,0xc19bf174
++	.long	0xe49b69c1,0xefbe4786,0x0fc19dc6,0x240ca1cc
++	.long	0x2de92c6f,0x4a7484aa,0x5cb0a9dc,0x76f988da
++	.long	0x983e5152,0xa831c66d,0xb00327c8,0xbf597fc7
++	.long	0xc6e00bf3,0xd5a79147,0x06ca6351,0x14292967
++	.long	0x27b70a85,0x2e1b2138,0x4d2c6dfc,0x53380d13
++	.long	0x650a7354,0x766a0abb,0x81c2c92e,0x92722c85
++	.long	0xa2bfe8a1,0xa81a664b,0xc24b8b70,0xc76c51a3
++	.long	0xd192e819,0xd6990624,0xf40e3585,0x106aa070
++	.long	0x19a4c116,0x1e376c08,0x2748774c,0x34b0bcb5
++	.long	0x391c0cb3,0x4ed8aa4a,0x5b9cca4f,0x682e6ff3
++	.long	0x748f82ee,0x78a5636f,0x84c87814,0x8cc70208
++	.long	0x90befffa,0xa4506ceb,0xbef9a3f7,0xc67178f2
++___
++$code.=<<___ if ($SZ==8);
++	.quad	0x428a2f98d728ae22,0x7137449123ef65cd
++	.quad	0xb5c0fbcfec4d3b2f,0xe9b5dba58189dbbc
++	.quad	0x3956c25bf348b538,0x59f111f1b605d019
++	.quad	0x923f82a4af194f9b,0xab1c5ed5da6d8118
++	.quad	0xd807aa98a3030242,0x12835b0145706fbe
++	.quad	0x243185be4ee4b28c,0x550c7dc3d5ffb4e2
++	.quad	0x72be5d74f27b896f,0x80deb1fe3b1696b1
++	.quad	0x9bdc06a725c71235,0xc19bf174cf692694
++	.quad	0xe49b69c19ef14ad2,0xefbe4786384f25e3
++	.quad	0x0fc19dc68b8cd5b5,0x240ca1cc77ac9c65
++	.quad	0x2de92c6f592b0275,0x4a7484aa6ea6e483
++	.quad	0x5cb0a9dcbd41fbd4,0x76f988da831153b5
++	.quad	0x983e5152ee66dfab,0xa831c66d2db43210
++	.quad	0xb00327c898fb213f,0xbf597fc7beef0ee4
++	.quad	0xc6e00bf33da88fc2,0xd5a79147930aa725
++	.quad	0x06ca6351e003826f,0x142929670a0e6e70
++	.quad	0x27b70a8546d22ffc,0x2e1b21385c26c926
++	.quad	0x4d2c6dfc5ac42aed,0x53380d139d95b3df
++	.quad	0x650a73548baf63de,0x766a0abb3c77b2a8
++	.quad	0x81c2c92e47edaee6,0x92722c851482353b
++	.quad	0xa2bfe8a14cf10364,0xa81a664bbc423001
++	.quad	0xc24b8b70d0f89791,0xc76c51a30654be30
++	.quad	0xd192e819d6ef5218,0xd69906245565a910
++	.quad	0xf40e35855771202a,0x106aa07032bbd1b8
++	.quad	0x19a4c116b8d2d0c8,0x1e376c085141ab53
++	.quad	0x2748774cdf8eeb99,0x34b0bcb5e19b48a8
++	.quad	0x391c0cb3c5c95a63,0x4ed8aa4ae3418acb
++	.quad	0x5b9cca4f7763e373,0x682e6ff3d6b2b8a3
++	.quad	0x748f82ee5defb2fc,0x78a5636f43172f60
++	.quad	0x84c87814a1f0ab72,0x8cc702081a6439ec
++	.quad	0x90befffa23631e28,0xa4506cebde82bde9
++	.quad	0xbef9a3f7b2c67915,0xc67178f2e372532b
++	.quad	0xca273eceea26619c,0xd186b8c721c0c207
++	.quad	0xeada7dd6cde0eb1e,0xf57d4f7fee6ed178
++	.quad	0x06f067aa72176fba,0x0a637dc5a2c898a6
++	.quad	0x113f9804bef90dae,0x1b710b35131c471b
++	.quad	0x28db77f523047d84,0x32caab7b40c72493
++	.quad	0x3c9ebe0a15c9bebc,0x431d67c49c100d4c
++	.quad	0x4cc5d4becb3e42b6,0x597f299cfc657e2a
++	.quad	0x5fcb6fab3ad6faec,0x6c44198c4a475817
++___
++$code.=<<___;
++.size	$Table,.-$Table
++.globl	$Func
++.type	$Func,\@function
++$Func:
++	sllg	$len,$len,`log(16*$SZ)/log(2)`
++___
++$code.=<<___ if ($kimdfunc);
++	larl	%r1,OPENSSL_s390xcap_P
++	lg	%r0,0(%r1)
++	tmhl	%r0,0x4000	# check for message-security assist
++	jz	.Lsoftware
++	lg	%r0,16(%r1)	# check kimd capabilities
++	tmhh	%r0,`0x8000>>$kimdfunc`
++	jz	.Lsoftware
++	lghi	%r0,$kimdfunc
++	lgr	%r1,$ctx
++	lgr	%r2,$inp
++	lgr	%r3,$len
++	.long	0xb93e0002	# kimd %r0,%r2
++	brc	1,.-4		# pay attention to "partial completion"
++	br	%r14
++.align	16
++.Lsoftware:
++___
++$code.=<<___;
++	lghi	%r1,-$frame
++	la	$len,0($len,$inp)
++	stm${g}	$ctx,%r15,`2*$SIZE_T`($sp)
++	lgr	%r0,$sp
++	la	$sp,0(%r1,$sp)
++	st${g}	%r0,0($sp)
++
++	larl	$tbl,$Table
++	$LD	$A,`0*$SZ`($ctx)
++	$LD	$B,`1*$SZ`($ctx)
++	$LD	$C,`2*$SZ`($ctx)
++	$LD	$D,`3*$SZ`($ctx)
++	$LD	$E,`4*$SZ`($ctx)
++	$LD	$F,`5*$SZ`($ctx)
++	$LD	$G,`6*$SZ`($ctx)
++	$LD	$H,`7*$SZ`($ctx)
++
++.Lloop:
++	lghi	$len,0
++___
++for ($i=0;$i<16;$i++)	{ &BODY_00_15($i,@V); unshift(@V,pop(@V)); }
++$code.=".Lrounds_16_xx:\n";
++for (;$i<32;$i++)	{ &BODY_16_XX($i,@V); unshift(@V,pop(@V)); }
++$code.=<<___;
++	aghi	$len,`16*$SZ`
++	lghi	$t0,`($rounds-16)*$SZ`
++	clgr	$len,$t0
++	jne	.Lrounds_16_xx
++
++	l${g}	$ctx,`$frame+2*$SIZE_T`($sp)
++	la	$inp,`16*$SZ`($inp)
++	$ADD	$A,`0*$SZ`($ctx)
++	$ADD	$B,`1*$SZ`($ctx)
++	$ADD	$C,`2*$SZ`($ctx)
++	$ADD	$D,`3*$SZ`($ctx)
++	$ADD	$E,`4*$SZ`($ctx)
++	$ADD	$F,`5*$SZ`($ctx)
++	$ADD	$G,`6*$SZ`($ctx)
++	$ADD	$H,`7*$SZ`($ctx)
++	$ST	$A,`0*$SZ`($ctx)
++	$ST	$B,`1*$SZ`($ctx)
++	$ST	$C,`2*$SZ`($ctx)
++	$ST	$D,`3*$SZ`($ctx)
++	$ST	$E,`4*$SZ`($ctx)
++	$ST	$F,`5*$SZ`($ctx)
++	$ST	$G,`6*$SZ`($ctx)
++	$ST	$H,`7*$SZ`($ctx)
++	cl${g}	$inp,`$frame+4*$SIZE_T`($sp)
++	jne	.Lloop
++
++	lm${g}	%r6,%r15,`$frame+6*$SIZE_T`($sp)	
++	br	%r14
++.size	$Func,.-$Func
++.string	"SHA${label} block transform for s390x, CRYPTOGAMS by "
++.comm	OPENSSL_s390xcap_P,80,8
++___
++
++$code =~ s/\`([^\`]*)\`/eval $1/gem;
++# unlike 32-bit shift 64-bit one takes three arguments
++$code =~ s/(srlg\s+)(%r[0-9]+),/$1$2,$2,/gm;
++
++print $code;
++close STDOUT;
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/sha/asm/sha512-sparcv9.pl b/CryptoPkg/Library/OpensslLib/openssl/crypto/sha/asm/sha512-sparcv9.pl
+new file mode 100644
+index 0000000..4a1ce5f
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/sha/asm/sha512-sparcv9.pl
+@@ -0,0 +1,857 @@
++#! /usr/bin/env perl
++# Copyright 2007-2016 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
++# in the file LICENSE in the source distribution or at
++# https://www.openssl.org/source/license.html
++
++
++# ====================================================================
++# Written by Andy Polyakov  for the OpenSSL
++# project. The module is, however, dual licensed under OpenSSL and
++# CRYPTOGAMS licenses depending on where you obtain it. For further
++# details see http://www.openssl.org/~appro/cryptogams/.
++#
++# Hardware SPARC T4 support by David S. Miller .
++# ====================================================================
++
++# SHA256 performance improvement over compiler generated code varies
++# from 40% for Sun C [32-bit build] to 70% for gcc [3.3, 64-bit
++# build]. Just like in SHA1 module I aim to ensure scalability on
++# UltraSPARC T1 by packing X[16] to 8 64-bit registers.
++
++# SHA512 on pre-T1 UltraSPARC.
++#
++# Performance is >75% better than 64-bit code generated by Sun C and
++# over 2x than 32-bit code. X[16] resides on stack, but access to it
++# is scheduled for L2 latency and staged through 32 least significant
++# bits of %l0-%l7. The latter is done to achieve 32-/64-bit ABI
++# duality. Nevetheless it's ~40% faster than SHA256, which is pretty
++# good [optimal coefficient is 50%].
++#
++# SHA512 on UltraSPARC T1.
++#
++# It's not any faster than 64-bit code generated by Sun C 5.8. This is
++# because 64-bit code generator has the advantage of using 64-bit
++# loads(*) to access X[16], which I consciously traded for 32-/64-bit
++# ABI duality [as per above]. But it surpasses 32-bit Sun C generated
++# code by 60%, not to mention that it doesn't suffer from severe decay
++# when running 4 times physical cores threads and that it leaves gcc
++# [3.4] behind by over 4x factor! If compared to SHA256, single thread
++# performance is only 10% better, but overall throughput for maximum
++# amount of threads for given CPU exceeds corresponding one of SHA256
++# by 30% [again, optimal coefficient is 50%].
++#
++# (*)	Unlike pre-T1 UltraSPARC loads on T1 are executed strictly
++#	in-order, i.e. load instruction has to complete prior next
++#	instruction in given thread is executed, even if the latter is
++#	not dependent on load result! This means that on T1 two 32-bit
++#	loads are always slower than one 64-bit load. Once again this
++#	is unlike pre-T1 UltraSPARC, where, if scheduled appropriately,
++#	2x32-bit loads can be as fast as 1x64-bit ones.
++#
++# SPARC T4 SHA256/512 hardware achieves 3.17/2.01 cycles per byte,
++# which is 9.3x/11.1x faster than software. Multi-process benchmark
++# saturates at 11.5x single-process result on 8-core processor, or
++# ~11/16GBps per 2.85GHz socket.
++
++$output=pop;
++open STDOUT,">$output";
++
++if ($output =~ /512/) {
++	$label="512";
++	$SZ=8;
++	$LD="ldx";		# load from memory
++	$ST="stx";		# store to memory
++	$SLL="sllx";		# shift left logical
++	$SRL="srlx";		# shift right logical
++	@Sigma0=(28,34,39);
++	@Sigma1=(14,18,41);
++	@sigma0=( 7, 1, 8);	# right shift first
++	@sigma1=( 6,19,61);	# right shift first
++	$lastK=0x817;
++	$rounds=80;
++	$align=4;
++
++	$locals=16*$SZ;		# X[16]
++
++	$A="%o0";
++	$B="%o1";
++	$C="%o2";
++	$D="%o3";
++	$E="%o4";
++	$F="%o5";
++	$G="%g1";
++	$H="%o7";
++	@V=($A,$B,$C,$D,$E,$F,$G,$H);
++} else {
++	$label="256";
++	$SZ=4;
++	$LD="ld";		# load from memory
++	$ST="st";		# store to memory
++	$SLL="sll";		# shift left logical
++	$SRL="srl";		# shift right logical
++	@Sigma0=( 2,13,22);
++	@Sigma1=( 6,11,25);
++	@sigma0=( 3, 7,18);	# right shift first
++	@sigma1=(10,17,19);	# right shift first
++	$lastK=0x8f2;
++	$rounds=64;
++	$align=8;
++
++	$locals=0;		# X[16] is register resident
++	@X=("%o0","%o1","%o2","%o3","%o4","%o5","%g1","%o7");
++	
++	$A="%l0";
++	$B="%l1";
++	$C="%l2";
++	$D="%l3";
++	$E="%l4";
++	$F="%l5";
++	$G="%l6";
++	$H="%l7";
++	@V=($A,$B,$C,$D,$E,$F,$G,$H);
++}
++$T1="%g2";
++$tmp0="%g3";
++$tmp1="%g4";
++$tmp2="%g5";
++
++$ctx="%i0";
++$inp="%i1";
++$len="%i2";
++$Ktbl="%i3";
++$tmp31="%i4";
++$tmp32="%i5";
++
++########### SHA256
++$Xload = sub {
++my ($i,$a,$b,$c,$d,$e,$f,$g,$h)=@_;
++
++    if ($i==0) {
++$code.=<<___;
++	ldx	[$inp+0],@X[0]
++	ldx	[$inp+16],@X[2]
++	ldx	[$inp+32],@X[4]
++	ldx	[$inp+48],@X[6]
++	ldx	[$inp+8],@X[1]
++	ldx	[$inp+24],@X[3]
++	subcc	%g0,$tmp31,$tmp32 ! should be 64-$tmp31, but -$tmp31 works too
++	ldx	[$inp+40],@X[5]
++	bz,pt	%icc,.Laligned
++	ldx	[$inp+56],@X[7]
++
++	sllx	@X[0],$tmp31,@X[0]
++	ldx	[$inp+64],$T1
++___
++for($j=0;$j<7;$j++)
++{   $code.=<<___;
++	srlx	@X[$j+1],$tmp32,$tmp1
++	sllx	@X[$j+1],$tmp31,@X[$j+1]
++	or	$tmp1,@X[$j],@X[$j]
++___
++}
++$code.=<<___;
++	srlx	$T1,$tmp32,$T1
++	or	$T1,@X[7],@X[7]
++.Laligned:
++___
++    }
++
++    if ($i&1) {
++	$code.="\tadd	@X[$i/2],$h,$T1\n";
++    } else {
++	$code.="\tsrlx	@X[$i/2],32,$T1\n\tadd	$h,$T1,$T1\n";
++    }
++} if ($SZ==4);
++
++########### SHA512
++$Xload = sub {
++my ($i,$a,$b,$c,$d,$e,$f,$g,$h)=@_;
++my @pair=("%l".eval(($i*2)%8),"%l".eval(($i*2)%8+1),"%l".eval((($i+1)*2)%8));
++
++$code.=<<___ if ($i==0);
++	ld	[$inp+0],%l0
++	ld	[$inp+4],%l1
++	ld	[$inp+8],%l2
++	ld	[$inp+12],%l3
++	ld	[$inp+16],%l4
++	ld	[$inp+20],%l5
++	ld	[$inp+24],%l6
++	cmp	$tmp31,0
++	ld	[$inp+28],%l7
++___
++$code.=<<___ if ($i<15);
++	sllx	@pair[1],$tmp31,$tmp2	! Xload($i)
++	add	$tmp31,32,$tmp0
++	sllx	@pair[0],$tmp0,$tmp1
++	`"ld	[$inp+".eval(32+0+$i*8)."],@pair[0]"	if ($i<12)`
++	srlx	@pair[2],$tmp32,@pair[1]
++	or	$tmp1,$tmp2,$tmp2
++	or	@pair[1],$tmp2,$tmp2
++	`"ld	[$inp+".eval(32+4+$i*8)."],@pair[1]"	if ($i<12)`
++	add	$h,$tmp2,$T1
++	$ST	$tmp2,[%sp+STACK_BIAS+STACK_FRAME+`$i*$SZ`]
++___
++$code.=<<___ if ($i==12);
++	bnz,a,pn	%icc,.+8
++	ld	[$inp+128],%l0
++___
++$code.=<<___ if ($i==15);
++	ld	[%sp+STACK_BIAS+STACK_FRAME+`(($i+1+1)%16)*$SZ+0`],%l2
++	sllx	@pair[1],$tmp31,$tmp2	! Xload($i)
++	add	$tmp31,32,$tmp0
++	ld	[%sp+STACK_BIAS+STACK_FRAME+`(($i+1+1)%16)*$SZ+4`],%l3
++	sllx	@pair[0],$tmp0,$tmp1
++	ld	[%sp+STACK_BIAS+STACK_FRAME+`(($i+1+9)%16)*$SZ+0`],%l4
++	srlx	@pair[2],$tmp32,@pair[1]
++	or	$tmp1,$tmp2,$tmp2
++	ld	[%sp+STACK_BIAS+STACK_FRAME+`(($i+1+9)%16)*$SZ+4`],%l5
++	or	@pair[1],$tmp2,$tmp2
++	ld	[%sp+STACK_BIAS+STACK_FRAME+`(($i+1+14)%16)*$SZ+0`],%l6
++	add	$h,$tmp2,$T1
++	$ST	$tmp2,[%sp+STACK_BIAS+STACK_FRAME+`$i*$SZ`]
++	ld	[%sp+STACK_BIAS+STACK_FRAME+`(($i+1+14)%16)*$SZ+4`],%l7
++	ld	[%sp+STACK_BIAS+STACK_FRAME+`(($i+1+0)%16)*$SZ+0`],%l0
++	ld	[%sp+STACK_BIAS+STACK_FRAME+`(($i+1+0)%16)*$SZ+4`],%l1
++___
++} if ($SZ==8);
++
++########### common
++sub BODY_00_15 {
++my ($i,$a,$b,$c,$d,$e,$f,$g,$h)=@_;
++
++    if ($i<16) {
++	&$Xload(@_);
++    } else {
++	$code.="\tadd	$h,$T1,$T1\n";
++    }
++
++$code.=<<___;
++	$SRL	$e,@Sigma1[0],$h	!! $i
++	xor	$f,$g,$tmp2
++	$SLL	$e,`$SZ*8-@Sigma1[2]`,$tmp1
++	and	$e,$tmp2,$tmp2
++	$SRL	$e,@Sigma1[1],$tmp0
++	xor	$tmp1,$h,$h
++	$SLL	$e,`$SZ*8-@Sigma1[1]`,$tmp1
++	xor	$tmp0,$h,$h
++	$SRL	$e,@Sigma1[2],$tmp0
++	xor	$tmp1,$h,$h
++	$SLL	$e,`$SZ*8-@Sigma1[0]`,$tmp1
++	xor	$tmp0,$h,$h
++	xor	$g,$tmp2,$tmp2		! Ch(e,f,g)
++	xor	$tmp1,$h,$tmp0		! Sigma1(e)
++
++	$SRL	$a,@Sigma0[0],$h
++	add	$tmp2,$T1,$T1
++	$LD	[$Ktbl+`$i*$SZ`],$tmp2	! K[$i]
++	$SLL	$a,`$SZ*8-@Sigma0[2]`,$tmp1
++	add	$tmp0,$T1,$T1
++	$SRL	$a,@Sigma0[1],$tmp0
++	xor	$tmp1,$h,$h
++	$SLL	$a,`$SZ*8-@Sigma0[1]`,$tmp1
++	xor	$tmp0,$h,$h
++	$SRL	$a,@Sigma0[2],$tmp0
++	xor	$tmp1,$h,$h	
++	$SLL	$a,`$SZ*8-@Sigma0[0]`,$tmp1
++	xor	$tmp0,$h,$h
++	xor	$tmp1,$h,$h		! Sigma0(a)
++
++	or	$a,$b,$tmp0
++	and	$a,$b,$tmp1
++	and	$c,$tmp0,$tmp0
++	or	$tmp0,$tmp1,$tmp1	! Maj(a,b,c)
++	add	$tmp2,$T1,$T1		! +=K[$i]
++	add	$tmp1,$h,$h
++
++	add	$T1,$d,$d
++	add	$T1,$h,$h
++___
++}
++
++########### SHA256
++$BODY_16_XX = sub {
++my $i=@_[0];
++my $xi;
++
++    if ($i&1) {
++	$xi=$tmp32;
++	$code.="\tsrlx	@X[(($i+1)/2)%8],32,$xi\n";
++    } else {
++	$xi=@X[(($i+1)/2)%8];
++    }
++$code.=<<___;
++	srl	$xi,@sigma0[0],$T1		!! Xupdate($i)
++	sll	$xi,`32-@sigma0[2]`,$tmp1
++	srl	$xi,@sigma0[1],$tmp0
++	xor	$tmp1,$T1,$T1
++	sll	$tmp1,`@sigma0[2]-@sigma0[1]`,$tmp1
++	xor	$tmp0,$T1,$T1
++	srl	$xi,@sigma0[2],$tmp0
++	xor	$tmp1,$T1,$T1
++___
++    if ($i&1) {
++	$xi=@X[(($i+14)/2)%8];
++    } else {
++	$xi=$tmp32;
++	$code.="\tsrlx	@X[(($i+14)/2)%8],32,$xi\n";
++    }
++$code.=<<___;
++	srl	$xi,@sigma1[0],$tmp2
++	xor	$tmp0,$T1,$T1			! T1=sigma0(X[i+1])
++	sll	$xi,`32-@sigma1[2]`,$tmp1
++	srl	$xi,@sigma1[1],$tmp0
++	xor	$tmp1,$tmp2,$tmp2
++	sll	$tmp1,`@sigma1[2]-@sigma1[1]`,$tmp1
++	xor	$tmp0,$tmp2,$tmp2
++	srl	$xi,@sigma1[2],$tmp0
++	xor	$tmp1,$tmp2,$tmp2
++___
++    if ($i&1) {
++	$xi=@X[($i/2)%8];
++$code.=<<___;
++	srlx	@X[(($i+9)/2)%8],32,$tmp1	! X[i+9]
++	xor	$tmp0,$tmp2,$tmp2		! sigma1(X[i+14])
++	srl	@X[($i/2)%8],0,$tmp0
++	add	$tmp2,$tmp1,$tmp1
++	add	$xi,$T1,$T1			! +=X[i]
++	xor	$tmp0,@X[($i/2)%8],@X[($i/2)%8]
++	add	$tmp1,$T1,$T1
++
++	srl	$T1,0,$T1
++	or	$T1,@X[($i/2)%8],@X[($i/2)%8]
++___
++    } else {
++	$xi=@X[(($i+9)/2)%8];
++$code.=<<___;
++	srlx	@X[($i/2)%8],32,$tmp1		! X[i]
++	xor	$tmp0,$tmp2,$tmp2		! sigma1(X[i+14])
++	add	$xi,$T1,$T1			! +=X[i+9]
++	add	$tmp2,$tmp1,$tmp1
++	srl	@X[($i/2)%8],0,@X[($i/2)%8]
++	add	$tmp1,$T1,$T1
++
++	sllx	$T1,32,$tmp0
++	or	$tmp0,@X[($i/2)%8],@X[($i/2)%8]
++___
++    }
++    &BODY_00_15(@_);
++} if ($SZ==4);
++
++########### SHA512
++$BODY_16_XX = sub {
++my $i=@_[0];
++my @pair=("%l".eval(($i*2)%8),"%l".eval(($i*2)%8+1));
++
++$code.=<<___;
++	sllx	%l2,32,$tmp0		!! Xupdate($i)
++	or	%l3,$tmp0,$tmp0
++
++	srlx	$tmp0,@sigma0[0],$T1
++	ld	[%sp+STACK_BIAS+STACK_FRAME+`(($i+1+1)%16)*$SZ+0`],%l2
++	sllx	$tmp0,`64-@sigma0[2]`,$tmp1
++	ld	[%sp+STACK_BIAS+STACK_FRAME+`(($i+1+1)%16)*$SZ+4`],%l3
++	srlx	$tmp0,@sigma0[1],$tmp0
++	xor	$tmp1,$T1,$T1
++	sllx	$tmp1,`@sigma0[2]-@sigma0[1]`,$tmp1
++	xor	$tmp0,$T1,$T1
++	srlx	$tmp0,`@sigma0[2]-@sigma0[1]`,$tmp0
++	xor	$tmp1,$T1,$T1
++	sllx	%l6,32,$tmp2
++	xor	$tmp0,$T1,$T1		! sigma0(X[$i+1])
++	or	%l7,$tmp2,$tmp2
++
++	srlx	$tmp2,@sigma1[0],$tmp1
++	ld	[%sp+STACK_BIAS+STACK_FRAME+`(($i+1+14)%16)*$SZ+0`],%l6
++	sllx	$tmp2,`64-@sigma1[2]`,$tmp0
++	ld	[%sp+STACK_BIAS+STACK_FRAME+`(($i+1+14)%16)*$SZ+4`],%l7
++	srlx	$tmp2,@sigma1[1],$tmp2
++	xor	$tmp0,$tmp1,$tmp1
++	sllx	$tmp0,`@sigma1[2]-@sigma1[1]`,$tmp0
++	xor	$tmp2,$tmp1,$tmp1
++	srlx	$tmp2,`@sigma1[2]-@sigma1[1]`,$tmp2
++	xor	$tmp0,$tmp1,$tmp1
++	sllx	%l4,32,$tmp0
++	xor	$tmp2,$tmp1,$tmp1	! sigma1(X[$i+14])
++	ld	[%sp+STACK_BIAS+STACK_FRAME+`(($i+1+9)%16)*$SZ+0`],%l4
++	or	%l5,$tmp0,$tmp0
++	ld	[%sp+STACK_BIAS+STACK_FRAME+`(($i+1+9)%16)*$SZ+4`],%l5
++
++	sllx	%l0,32,$tmp2
++	add	$tmp1,$T1,$T1
++	ld	[%sp+STACK_BIAS+STACK_FRAME+`(($i+1+0)%16)*$SZ+0`],%l0
++	or	%l1,$tmp2,$tmp2
++	add	$tmp0,$T1,$T1		! +=X[$i+9]
++	ld	[%sp+STACK_BIAS+STACK_FRAME+`(($i+1+0)%16)*$SZ+4`],%l1
++	add	$tmp2,$T1,$T1		! +=X[$i]
++	$ST	$T1,[%sp+STACK_BIAS+STACK_FRAME+`($i%16)*$SZ`]
++___
++    &BODY_00_15(@_);
++} if ($SZ==8);
++
++$code.=<<___;
++#include "sparc_arch.h"
++
++#ifdef __arch64__
++.register	%g2,#scratch
++.register	%g3,#scratch
++#endif
++
++.section	".text",#alloc,#execinstr
++
++.align	64
++K${label}:
++.type	K${label},#object
++___
++if ($SZ==4) {
++$code.=<<___;
++	.long	0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5
++	.long	0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5
++	.long	0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3
++	.long	0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174
++	.long	0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc
++	.long	0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da
++	.long	0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7
++	.long	0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967
++	.long	0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13
++	.long	0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85
++	.long	0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3
++	.long	0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070
++	.long	0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5
++	.long	0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3
++	.long	0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208
++	.long	0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2
++___
++} else {
++$code.=<<___;
++	.long	0x428a2f98,0xd728ae22, 0x71374491,0x23ef65cd
++	.long	0xb5c0fbcf,0xec4d3b2f, 0xe9b5dba5,0x8189dbbc
++	.long	0x3956c25b,0xf348b538, 0x59f111f1,0xb605d019
++	.long	0x923f82a4,0xaf194f9b, 0xab1c5ed5,0xda6d8118
++	.long	0xd807aa98,0xa3030242, 0x12835b01,0x45706fbe
++	.long	0x243185be,0x4ee4b28c, 0x550c7dc3,0xd5ffb4e2
++	.long	0x72be5d74,0xf27b896f, 0x80deb1fe,0x3b1696b1
++	.long	0x9bdc06a7,0x25c71235, 0xc19bf174,0xcf692694
++	.long	0xe49b69c1,0x9ef14ad2, 0xefbe4786,0x384f25e3
++	.long	0x0fc19dc6,0x8b8cd5b5, 0x240ca1cc,0x77ac9c65
++	.long	0x2de92c6f,0x592b0275, 0x4a7484aa,0x6ea6e483
++	.long	0x5cb0a9dc,0xbd41fbd4, 0x76f988da,0x831153b5
++	.long	0x983e5152,0xee66dfab, 0xa831c66d,0x2db43210
++	.long	0xb00327c8,0x98fb213f, 0xbf597fc7,0xbeef0ee4
++	.long	0xc6e00bf3,0x3da88fc2, 0xd5a79147,0x930aa725
++	.long	0x06ca6351,0xe003826f, 0x14292967,0x0a0e6e70
++	.long	0x27b70a85,0x46d22ffc, 0x2e1b2138,0x5c26c926
++	.long	0x4d2c6dfc,0x5ac42aed, 0x53380d13,0x9d95b3df
++	.long	0x650a7354,0x8baf63de, 0x766a0abb,0x3c77b2a8
++	.long	0x81c2c92e,0x47edaee6, 0x92722c85,0x1482353b
++	.long	0xa2bfe8a1,0x4cf10364, 0xa81a664b,0xbc423001
++	.long	0xc24b8b70,0xd0f89791, 0xc76c51a3,0x0654be30
++	.long	0xd192e819,0xd6ef5218, 0xd6990624,0x5565a910
++	.long	0xf40e3585,0x5771202a, 0x106aa070,0x32bbd1b8
++	.long	0x19a4c116,0xb8d2d0c8, 0x1e376c08,0x5141ab53
++	.long	0x2748774c,0xdf8eeb99, 0x34b0bcb5,0xe19b48a8
++	.long	0x391c0cb3,0xc5c95a63, 0x4ed8aa4a,0xe3418acb
++	.long	0x5b9cca4f,0x7763e373, 0x682e6ff3,0xd6b2b8a3
++	.long	0x748f82ee,0x5defb2fc, 0x78a5636f,0x43172f60
++	.long	0x84c87814,0xa1f0ab72, 0x8cc70208,0x1a6439ec
++	.long	0x90befffa,0x23631e28, 0xa4506ceb,0xde82bde9
++	.long	0xbef9a3f7,0xb2c67915, 0xc67178f2,0xe372532b
++	.long	0xca273ece,0xea26619c, 0xd186b8c7,0x21c0c207
++	.long	0xeada7dd6,0xcde0eb1e, 0xf57d4f7f,0xee6ed178
++	.long	0x06f067aa,0x72176fba, 0x0a637dc5,0xa2c898a6
++	.long	0x113f9804,0xbef90dae, 0x1b710b35,0x131c471b
++	.long	0x28db77f5,0x23047d84, 0x32caab7b,0x40c72493
++	.long	0x3c9ebe0a,0x15c9bebc, 0x431d67c4,0x9c100d4c
++	.long	0x4cc5d4be,0xcb3e42b6, 0x597f299c,0xfc657e2a
++	.long	0x5fcb6fab,0x3ad6faec, 0x6c44198c,0x4a475817
++___
++}
++$code.=<<___;
++.size	K${label},.-K${label}
++
++#ifdef __PIC__
++SPARC_PIC_THUNK(%g1)
++#endif
++
++.globl	sha${label}_block_data_order
++.align	32
++sha${label}_block_data_order:
++	SPARC_LOAD_ADDRESS_LEAF(OPENSSL_sparcv9cap_P,%g1,%g5)
++	ld	[%g1+4],%g1		! OPENSSL_sparcv9cap_P[1]
++
++	andcc	%g1, CFR_SHA${label}, %g0
++	be	.Lsoftware
++	nop
++___
++$code.=<<___ if ($SZ==8); 		# SHA512
++	ldd	[%o0 + 0x00], %f0	! load context
++	ldd	[%o0 + 0x08], %f2
++	ldd	[%o0 + 0x10], %f4
++	ldd	[%o0 + 0x18], %f6
++	ldd	[%o0 + 0x20], %f8
++	ldd	[%o0 + 0x28], %f10
++	andcc	%o1, 0x7, %g0
++	ldd	[%o0 + 0x30], %f12
++	bne,pn	%icc, .Lhwunaligned
++	 ldd	[%o0 + 0x38], %f14
++
++.Lhwaligned_loop:
++	ldd	[%o1 + 0x00], %f16
++	ldd	[%o1 + 0x08], %f18
++	ldd	[%o1 + 0x10], %f20
++	ldd	[%o1 + 0x18], %f22
++	ldd	[%o1 + 0x20], %f24
++	ldd	[%o1 + 0x28], %f26
++	ldd	[%o1 + 0x30], %f28
++	ldd	[%o1 + 0x38], %f30
++	ldd	[%o1 + 0x40], %f32
++	ldd	[%o1 + 0x48], %f34
++	ldd	[%o1 + 0x50], %f36
++	ldd	[%o1 + 0x58], %f38
++	ldd	[%o1 + 0x60], %f40
++	ldd	[%o1 + 0x68], %f42
++	ldd	[%o1 + 0x70], %f44
++	subcc	%o2, 1, %o2		! done yet?
++	ldd	[%o1 + 0x78], %f46
++	add	%o1, 0x80, %o1
++	prefetch [%o1 + 63], 20
++	prefetch [%o1 + 64+63], 20
++
++	.word	0x81b02860		! SHA512
++
++	bne,pt	SIZE_T_CC, .Lhwaligned_loop
++	nop
++
++.Lhwfinish:
++	std	%f0, [%o0 + 0x00]	! store context
++	std	%f2, [%o0 + 0x08]
++	std	%f4, [%o0 + 0x10]
++	std	%f6, [%o0 + 0x18]
++	std	%f8, [%o0 + 0x20]
++	std	%f10, [%o0 + 0x28]
++	std	%f12, [%o0 + 0x30]
++	retl
++	 std	%f14, [%o0 + 0x38]
++
++.align	16
++.Lhwunaligned:
++	alignaddr %o1, %g0, %o1
++
++	ldd	[%o1 + 0x00], %f18
++.Lhwunaligned_loop:
++	ldd	[%o1 + 0x08], %f20
++	ldd	[%o1 + 0x10], %f22
++	ldd	[%o1 + 0x18], %f24
++	ldd	[%o1 + 0x20], %f26
++	ldd	[%o1 + 0x28], %f28
++	ldd	[%o1 + 0x30], %f30
++	ldd	[%o1 + 0x38], %f32
++	ldd	[%o1 + 0x40], %f34
++	ldd	[%o1 + 0x48], %f36
++	ldd	[%o1 + 0x50], %f38
++	ldd	[%o1 + 0x58], %f40
++	ldd	[%o1 + 0x60], %f42
++	ldd	[%o1 + 0x68], %f44
++	ldd	[%o1 + 0x70], %f46
++	ldd	[%o1 + 0x78], %f48
++	subcc	%o2, 1, %o2		! done yet?
++	ldd	[%o1 + 0x80], %f50
++	add	%o1, 0x80, %o1
++	prefetch [%o1 + 63], 20
++	prefetch [%o1 + 64+63], 20
++
++	faligndata %f18, %f20, %f16
++	faligndata %f20, %f22, %f18
++	faligndata %f22, %f24, %f20
++	faligndata %f24, %f26, %f22
++	faligndata %f26, %f28, %f24
++	faligndata %f28, %f30, %f26
++	faligndata %f30, %f32, %f28
++	faligndata %f32, %f34, %f30
++	faligndata %f34, %f36, %f32
++	faligndata %f36, %f38, %f34
++	faligndata %f38, %f40, %f36
++	faligndata %f40, %f42, %f38
++	faligndata %f42, %f44, %f40
++	faligndata %f44, %f46, %f42
++	faligndata %f46, %f48, %f44
++	faligndata %f48, %f50, %f46
++
++	.word	0x81b02860		! SHA512
++
++	bne,pt	SIZE_T_CC, .Lhwunaligned_loop
++	for	%f50, %f50, %f18	! %f18=%f50
++
++	ba	.Lhwfinish
++	nop
++___
++$code.=<<___ if ($SZ==4); 		# SHA256
++	ld	[%o0 + 0x00], %f0
++	ld	[%o0 + 0x04], %f1
++	ld	[%o0 + 0x08], %f2
++	ld	[%o0 + 0x0c], %f3
++	ld	[%o0 + 0x10], %f4
++	ld	[%o0 + 0x14], %f5
++	andcc	%o1, 0x7, %g0
++	ld	[%o0 + 0x18], %f6
++	bne,pn	%icc, .Lhwunaligned
++	 ld	[%o0 + 0x1c], %f7
++
++.Lhwloop:
++	ldd	[%o1 + 0x00], %f8
++	ldd	[%o1 + 0x08], %f10
++	ldd	[%o1 + 0x10], %f12
++	ldd	[%o1 + 0x18], %f14
++	ldd	[%o1 + 0x20], %f16
++	ldd	[%o1 + 0x28], %f18
++	ldd	[%o1 + 0x30], %f20
++	subcc	%o2, 1, %o2		! done yet?
++	ldd	[%o1 + 0x38], %f22
++	add	%o1, 0x40, %o1
++	prefetch [%o1 + 63], 20
++
++	.word	0x81b02840		! SHA256
++
++	bne,pt	SIZE_T_CC, .Lhwloop
++	nop
++
++.Lhwfinish:
++	st	%f0, [%o0 + 0x00]	! store context
++	st	%f1, [%o0 + 0x04]
++	st	%f2, [%o0 + 0x08]
++	st	%f3, [%o0 + 0x0c]
++	st	%f4, [%o0 + 0x10]
++	st	%f5, [%o0 + 0x14]
++	st	%f6, [%o0 + 0x18]
++	retl
++	 st	%f7, [%o0 + 0x1c]
++
++.align	8
++.Lhwunaligned:
++	alignaddr %o1, %g0, %o1
++
++	ldd	[%o1 + 0x00], %f10
++.Lhwunaligned_loop:
++	ldd	[%o1 + 0x08], %f12
++	ldd	[%o1 + 0x10], %f14
++	ldd	[%o1 + 0x18], %f16
++	ldd	[%o1 + 0x20], %f18
++	ldd	[%o1 + 0x28], %f20
++	ldd	[%o1 + 0x30], %f22
++	ldd	[%o1 + 0x38], %f24
++	subcc	%o2, 1, %o2		! done yet?
++	ldd	[%o1 + 0x40], %f26
++	add	%o1, 0x40, %o1
++	prefetch [%o1 + 63], 20
++
++	faligndata %f10, %f12, %f8
++	faligndata %f12, %f14, %f10
++	faligndata %f14, %f16, %f12
++	faligndata %f16, %f18, %f14
++	faligndata %f18, %f20, %f16
++	faligndata %f20, %f22, %f18
++	faligndata %f22, %f24, %f20
++	faligndata %f24, %f26, %f22
++
++	.word	0x81b02840		! SHA256
++
++	bne,pt	SIZE_T_CC, .Lhwunaligned_loop
++	for	%f26, %f26, %f10	! %f10=%f26
++
++	ba	.Lhwfinish
++	nop
++___
++$code.=<<___;
++.align	16
++.Lsoftware:
++	save	%sp,-STACK_FRAME-$locals,%sp
++	and	$inp,`$align-1`,$tmp31
++	sllx	$len,`log(16*$SZ)/log(2)`,$len
++	andn	$inp,`$align-1`,$inp
++	sll	$tmp31,3,$tmp31
++	add	$inp,$len,$len
++___
++$code.=<<___ if ($SZ==8); # SHA512
++	mov	32,$tmp32
++	sub	$tmp32,$tmp31,$tmp32
++___
++$code.=<<___;
++.Lpic:	call	.+8
++	add	%o7,K${label}-.Lpic,$Ktbl
++
++	$LD	[$ctx+`0*$SZ`],$A
++	$LD	[$ctx+`1*$SZ`],$B
++	$LD	[$ctx+`2*$SZ`],$C
++	$LD	[$ctx+`3*$SZ`],$D
++	$LD	[$ctx+`4*$SZ`],$E
++	$LD	[$ctx+`5*$SZ`],$F
++	$LD	[$ctx+`6*$SZ`],$G
++	$LD	[$ctx+`7*$SZ`],$H
++
++.Lloop:
++___
++for ($i=0;$i<16;$i++)	{ &BODY_00_15($i,@V); unshift(@V,pop(@V)); }
++$code.=".L16_xx:\n";
++for (;$i<32;$i++)	{ &$BODY_16_XX($i,@V); unshift(@V,pop(@V)); }
++$code.=<<___;
++	and	$tmp2,0xfff,$tmp2
++	cmp	$tmp2,$lastK
++	bne	.L16_xx
++	add	$Ktbl,`16*$SZ`,$Ktbl	! Ktbl+=16
++
++___
++$code.=<<___ if ($SZ==4); # SHA256
++	$LD	[$ctx+`0*$SZ`],@X[0]
++	$LD	[$ctx+`1*$SZ`],@X[1]
++	$LD	[$ctx+`2*$SZ`],@X[2]
++	$LD	[$ctx+`3*$SZ`],@X[3]
++	$LD	[$ctx+`4*$SZ`],@X[4]
++	$LD	[$ctx+`5*$SZ`],@X[5]
++	$LD	[$ctx+`6*$SZ`],@X[6]
++	$LD	[$ctx+`7*$SZ`],@X[7]
++
++	add	$A,@X[0],$A
++	$ST	$A,[$ctx+`0*$SZ`]
++	add	$B,@X[1],$B
++	$ST	$B,[$ctx+`1*$SZ`]
++	add	$C,@X[2],$C
++	$ST	$C,[$ctx+`2*$SZ`]
++	add	$D,@X[3],$D
++	$ST	$D,[$ctx+`3*$SZ`]
++	add	$E,@X[4],$E
++	$ST	$E,[$ctx+`4*$SZ`]
++	add	$F,@X[5],$F
++	$ST	$F,[$ctx+`5*$SZ`]
++	add	$G,@X[6],$G
++	$ST	$G,[$ctx+`6*$SZ`]
++	add	$H,@X[7],$H
++	$ST	$H,[$ctx+`7*$SZ`]
++___
++$code.=<<___ if ($SZ==8); # SHA512
++	ld	[$ctx+`0*$SZ+0`],%l0
++	ld	[$ctx+`0*$SZ+4`],%l1
++	ld	[$ctx+`1*$SZ+0`],%l2
++	ld	[$ctx+`1*$SZ+4`],%l3
++	ld	[$ctx+`2*$SZ+0`],%l4
++	ld	[$ctx+`2*$SZ+4`],%l5
++	ld	[$ctx+`3*$SZ+0`],%l6
++
++	sllx	%l0,32,$tmp0
++	ld	[$ctx+`3*$SZ+4`],%l7
++	sllx	%l2,32,$tmp1
++	or	%l1,$tmp0,$tmp0
++	or	%l3,$tmp1,$tmp1
++	add	$tmp0,$A,$A
++	add	$tmp1,$B,$B
++	$ST	$A,[$ctx+`0*$SZ`]
++	sllx	%l4,32,$tmp2
++	$ST	$B,[$ctx+`1*$SZ`]
++	sllx	%l6,32,$T1
++	or	%l5,$tmp2,$tmp2
++	or	%l7,$T1,$T1
++	add	$tmp2,$C,$C
++	$ST	$C,[$ctx+`2*$SZ`]
++	add	$T1,$D,$D
++	$ST	$D,[$ctx+`3*$SZ`]
++
++	ld	[$ctx+`4*$SZ+0`],%l0
++	ld	[$ctx+`4*$SZ+4`],%l1
++	ld	[$ctx+`5*$SZ+0`],%l2
++	ld	[$ctx+`5*$SZ+4`],%l3
++	ld	[$ctx+`6*$SZ+0`],%l4
++	ld	[$ctx+`6*$SZ+4`],%l5
++	ld	[$ctx+`7*$SZ+0`],%l6
++
++	sllx	%l0,32,$tmp0
++	ld	[$ctx+`7*$SZ+4`],%l7
++	sllx	%l2,32,$tmp1
++	or	%l1,$tmp0,$tmp0
++	or	%l3,$tmp1,$tmp1
++	add	$tmp0,$E,$E
++	add	$tmp1,$F,$F
++	$ST	$E,[$ctx+`4*$SZ`]
++	sllx	%l4,32,$tmp2
++	$ST	$F,[$ctx+`5*$SZ`]
++	sllx	%l6,32,$T1
++	or	%l5,$tmp2,$tmp2
++	or	%l7,$T1,$T1
++	add	$tmp2,$G,$G
++	$ST	$G,[$ctx+`6*$SZ`]
++	add	$T1,$H,$H
++	$ST	$H,[$ctx+`7*$SZ`]
++___
++$code.=<<___;
++	add	$inp,`16*$SZ`,$inp		! advance inp
++	cmp	$inp,$len
++	bne	SIZE_T_CC,.Lloop
++	sub	$Ktbl,`($rounds-16)*$SZ`,$Ktbl	! rewind Ktbl
++
++	ret
++	restore
++.type	sha${label}_block_data_order,#function
++.size	sha${label}_block_data_order,(.-sha${label}_block_data_order)
++.asciz	"SHA${label} block transform for SPARCv9, CRYPTOGAMS by "
++.align	4
++___
++
++# Purpose of these subroutines is to explicitly encode VIS instructions,
++# so that one can compile the module without having to specify VIS
++# extensions on compiler command line, e.g. -xarch=v9 vs. -xarch=v9a.
++# Idea is to reserve for option to produce "universal" binary and let
++# programmer detect if current CPU is VIS capable at run-time.
++sub unvis {
++my ($mnemonic,$rs1,$rs2,$rd)=@_;
++my $ref,$opf;
++my %visopf = (	"faligndata"	=> 0x048,
++		"for"		=> 0x07c	);
++
++    $ref = "$mnemonic\t$rs1,$rs2,$rd";
++
++    if ($opf=$visopf{$mnemonic}) {
++	foreach ($rs1,$rs2,$rd) {
++	    return $ref if (!/%f([0-9]{1,2})/);
++	    $_=$1;
++	    if ($1>=32) {
++		return $ref if ($1&1);
++		# re-encode for upper double register addressing
++		$_=($1|$1>>5)&31;
++	    }
++	}
++
++	return	sprintf ".word\t0x%08x !%s",
++			0x81b00000|$rd<<25|$rs1<<14|$opf<<5|$rs2,
++			$ref;
++    } else {
++	return $ref;
++    }
++}
++sub unalignaddr {
++my ($mnemonic,$rs1,$rs2,$rd)=@_;
++my %bias = ( "g" => 0, "o" => 8, "l" => 16, "i" => 24 );
++my $ref="$mnemonic\t$rs1,$rs2,$rd";
++
++    foreach ($rs1,$rs2,$rd) {
++	if (/%([goli])([0-7])/)	{ $_=$bias{$1}+$2; }
++	else			{ return $ref; }
++    }
++    return  sprintf ".word\t0x%08x !%s",
++		    0x81b00300|$rd<<25|$rs1<<14|$rs2,
++		    $ref;
++}
++
++foreach (split("\n",$code)) {
++	s/\`([^\`]*)\`/eval $1/ge;
++
++	s/\b(f[^\s]*)\s+(%f[0-9]{1,2}),\s*(%f[0-9]{1,2}),\s*(%f[0-9]{1,2})/
++		&unvis($1,$2,$3,$4)
++	 /ge;
++	s/\b(alignaddr)\s+(%[goli][0-7]),\s*(%[goli][0-7]),\s*(%[goli][0-7])/
++		&unalignaddr($1,$2,$3,$4)
++	 /ge;
++
++	print $_,"\n";
++}
++
++close STDOUT;
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/sha/asm/sha512-x86_64.pl b/CryptoPkg/Library/OpensslLib/openssl/crypto/sha/asm/sha512-x86_64.pl
+new file mode 100755
+index 0000000..c9b7b28
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/sha/asm/sha512-x86_64.pl
+@@ -0,0 +1,2407 @@
++#! /usr/bin/env perl
++# Copyright 2005-2016 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
++# in the file LICENSE in the source distribution or at
++# https://www.openssl.org/source/license.html
++
++#
++# ====================================================================
++# Written by Andy Polyakov  for the OpenSSL
++# project. Rights for redistribution and usage in source and binary
++# forms are granted according to the OpenSSL license.
++# ====================================================================
++#
++# sha256/512_block procedure for x86_64.
++#
++# 40% improvement over compiler-generated code on Opteron. On EM64T
++# sha256 was observed to run >80% faster and sha512 - >40%. No magical
++# tricks, just straight implementation... I really wonder why gcc
++# [being armed with inline assembler] fails to generate as fast code.
++# The only thing which is cool about this module is that it's very
++# same instruction sequence used for both SHA-256 and SHA-512. In
++# former case the instructions operate on 32-bit operands, while in
++# latter - on 64-bit ones. All I had to do is to get one flavor right,
++# the other one passed the test right away:-)
++#
++# sha256_block runs in ~1005 cycles on Opteron, which gives you
++# asymptotic performance of 64*1000/1005=63.7MBps times CPU clock
++# frequency in GHz. sha512_block runs in ~1275 cycles, which results
++# in 128*1000/1275=100MBps per GHz. Is there room for improvement?
++# Well, if you compare it to IA-64 implementation, which maintains
++# X[16] in register bank[!], tends to 4 instructions per CPU clock
++# cycle and runs in 1003 cycles, 1275 is very good result for 3-way
++# issue Opteron pipeline and X[16] maintained in memory. So that *if*
++# there is a way to improve it, *then* the only way would be to try to
++# offload X[16] updates to SSE unit, but that would require "deeper"
++# loop unroll, which in turn would naturally cause size blow-up, not
++# to mention increased complexity! And once again, only *if* it's
++# actually possible to noticeably improve overall ILP, instruction
++# level parallelism, on a given CPU implementation in this case.
++#
++# Special note on Intel EM64T. While Opteron CPU exhibits perfect
++# performance ratio of 1.5 between 64- and 32-bit flavors [see above],
++# [currently available] EM64T CPUs apparently are far from it. On the
++# contrary, 64-bit version, sha512_block, is ~30% *slower* than 32-bit
++# sha256_block:-( This is presumably because 64-bit shifts/rotates
++# apparently are not atomic instructions, but implemented in microcode.
++#
++# May 2012.
++#
++# Optimization including one of Pavel Semjanov's ideas, alternative
++# Maj, resulted in >=5% improvement on most CPUs, +20% SHA256 and
++# unfortunately -2% SHA512 on P4 [which nobody should care about
++# that much].
++#
++# June 2012.
++#
++# Add SIMD code paths, see below for improvement coefficients. SSSE3
++# code path was not attempted for SHA512, because improvement is not
++# estimated to be high enough, noticeably less than 9%, to justify
++# the effort, not on pre-AVX processors. [Obviously with exclusion
++# for VIA Nano, but it has SHA512 instruction that is faster and
++# should be used instead.] For reference, corresponding estimated
++# upper limit for improvement for SSSE3 SHA256 is 28%. The fact that
++# higher coefficients are observed on VIA Nano and Bulldozer has more
++# to do with specifics of their architecture [which is topic for
++# separate discussion].
++#
++# November 2012.
++#
++# Add AVX2 code path. Two consecutive input blocks are loaded to
++# 256-bit %ymm registers, with data from first block to least
++# significant 128-bit halves and data from second to most significant.
++# The data is then processed with same SIMD instruction sequence as
++# for AVX, but with %ymm as operands. Side effect is increased stack
++# frame, 448 additional bytes in SHA256 and 1152 in SHA512, and 1.2KB
++# code size increase.
++#
++# March 2014.
++#
++# Add support for Intel SHA Extensions.
++
++######################################################################
++# Current performance in cycles per processed byte (less is better):
++#
++#		SHA256	SSSE3       AVX/XOP(*)	    SHA512  AVX/XOP(*)
++#
++# AMD K8	14.9	-	    -		    9.57    -
++# P4		17.3	-	    -		    30.8    -
++# Core 2	15.6	13.8(+13%)  -		    9.97    -
++# Westmere	14.8	12.3(+19%)  -		    9.58    -
++# Sandy Bridge	17.4	14.2(+23%)  11.6(+50%(**))  11.2    8.10(+38%(**))
++# Ivy Bridge	12.6	10.5(+20%)  10.3(+22%)	    8.17    7.22(+13%)
++# Haswell	12.2	9.28(+31%)  7.80(+56%)	    7.66    5.40(+42%)
++# Skylake	11.4	9.03(+26%)  7.70(+48%)      7.25    5.20(+40%)
++# Bulldozer	21.1	13.6(+54%)  13.6(+54%(***)) 13.5    8.58(+57%)
++# VIA Nano	23.0	16.5(+39%)  -		    14.7    -
++# Atom		23.0	18.9(+22%)  -		    14.7    -
++# Silvermont	27.4	20.6(+33%)  -               17.5    -
++# Goldmont	18.9	14.3(+32%)  4.16(+350%)     12.0    -
++#
++# (*)	whichever best applicable, including SHAEXT;
++# (**)	switch from ror to shrd stands for fair share of improvement;
++# (***)	execution time is fully determined by remaining integer-only
++#	part, body_00_15; reducing the amount of SIMD instructions
++#	below certain limit makes no difference/sense; to conserve
++#	space SHA256 XOP code path is therefore omitted;
++
++$flavour = shift;
++$output  = shift;
++if ($flavour =~ /\./) { $output = $flavour; undef $flavour; }
++
++$win64=0; $win64=1 if ($flavour =~ /[nm]asm|mingw64/ || $output =~ /\.asm$/);
++
++$0 =~ m/(.*[\/\\])[^\/\\]+$/; $dir=$1;
++( $xlate="${dir}x86_64-xlate.pl" and -f $xlate ) or
++( $xlate="${dir}../../perlasm/x86_64-xlate.pl" and -f $xlate) or
++die "can't locate x86_64-xlate.pl";
++
++if (`$ENV{CC} -Wa,-v -c -o /dev/null -x assembler /dev/null 2>&1`
++		=~ /GNU assembler version ([2-9]\.[0-9]+)/) {
++	$avx = ($1>=2.19) + ($1>=2.22);
++}
++
++if (!$avx && $win64 && ($flavour =~ /nasm/ || $ENV{ASM} =~ /nasm/) &&
++	   `nasm -v 2>&1` =~ /NASM version ([2-9]\.[0-9]+)/) {
++	$avx = ($1>=2.09) + ($1>=2.10);
++}
++
++if (!$avx && $win64 && ($flavour =~ /masm/ || $ENV{ASM} =~ /ml64/) &&
++	   `ml64 2>&1` =~ /Version ([0-9]+)\./) {
++	$avx = ($1>=10) + ($1>=11);
++}
++
++if (!$avx && `$ENV{CC} -v 2>&1` =~ /((?:^clang|LLVM) version|.*based on LLVM) ([3-9]\.[0-9]+)/) {
++	$avx = ($2>=3.0) + ($2>3.0);
++}
++
++$shaext=1;	### set to zero if compiling for 1.0.1
++$avx=1		if (!$shaext && $avx);
++
++open OUT,"| \"$^X\" \"$xlate\" $flavour \"$output\"";
++*STDOUT=*OUT;
++
++if ($output =~ /512/) {
++	$func="sha512_block_data_order";
++	$TABLE="K512";
++	$SZ=8;
++	@ROT=($A,$B,$C,$D,$E,$F,$G,$H)=("%rax","%rbx","%rcx","%rdx",
++					"%r8", "%r9", "%r10","%r11");
++	($T1,$a0,$a1,$a2,$a3)=("%r12","%r13","%r14","%r15","%rdi");
++	@Sigma0=(28,34,39);
++	@Sigma1=(14,18,41);
++	@sigma0=(1,  8, 7);
++	@sigma1=(19,61, 6);
++	$rounds=80;
++} else {
++	$func="sha256_block_data_order";
++	$TABLE="K256";
++	$SZ=4;
++	@ROT=($A,$B,$C,$D,$E,$F,$G,$H)=("%eax","%ebx","%ecx","%edx",
++					"%r8d","%r9d","%r10d","%r11d");
++	($T1,$a0,$a1,$a2,$a3)=("%r12d","%r13d","%r14d","%r15d","%edi");
++	@Sigma0=( 2,13,22);
++	@Sigma1=( 6,11,25);
++	@sigma0=( 7,18, 3);
++	@sigma1=(17,19,10);
++	$rounds=64;
++}
++
++$ctx="%rdi";	# 1st arg, zapped by $a3
++$inp="%rsi";	# 2nd arg
++$Tbl="%rbp";
++
++$_ctx="16*$SZ+0*8(%rsp)";
++$_inp="16*$SZ+1*8(%rsp)";
++$_end="16*$SZ+2*8(%rsp)";
++$_rsp="16*$SZ+3*8(%rsp)";
++$framesz="16*$SZ+4*8";
++
++
++sub ROUND_00_15()
++{ my ($i,$a,$b,$c,$d,$e,$f,$g,$h) = @_;
++  my $STRIDE=$SZ;
++     $STRIDE += 16 if ($i%(16/$SZ)==(16/$SZ-1));
++
++$code.=<<___;
++	ror	\$`$Sigma1[2]-$Sigma1[1]`,$a0
++	mov	$f,$a2
++
++	xor	$e,$a0
++	ror	\$`$Sigma0[2]-$Sigma0[1]`,$a1
++	xor	$g,$a2			# f^g
++
++	mov	$T1,`$SZ*($i&0xf)`(%rsp)
++	xor	$a,$a1
++	and	$e,$a2			# (f^g)&e
++
++	ror	\$`$Sigma1[1]-$Sigma1[0]`,$a0
++	add	$h,$T1			# T1+=h
++	xor	$g,$a2			# Ch(e,f,g)=((f^g)&e)^g
++
++	ror	\$`$Sigma0[1]-$Sigma0[0]`,$a1
++	xor	$e,$a0
++	add	$a2,$T1			# T1+=Ch(e,f,g)
++
++	mov	$a,$a2
++	add	($Tbl),$T1		# T1+=K[round]
++	xor	$a,$a1
++
++	xor	$b,$a2			# a^b, b^c in next round
++	ror	\$$Sigma1[0],$a0	# Sigma1(e)
++	mov	$b,$h
++
++	and	$a2,$a3
++	ror	\$$Sigma0[0],$a1	# Sigma0(a)
++	add	$a0,$T1			# T1+=Sigma1(e)
++
++	xor	$a3,$h			# h=Maj(a,b,c)=Ch(a^b,c,b)
++	add	$T1,$d			# d+=T1
++	add	$T1,$h			# h+=T1
++
++	lea	$STRIDE($Tbl),$Tbl	# round++
++___
++$code.=<<___ if ($i<15);
++	add	$a1,$h			# h+=Sigma0(a)
++___
++	($a2,$a3) = ($a3,$a2);
++}
++
++sub ROUND_16_XX()
++{ my ($i,$a,$b,$c,$d,$e,$f,$g,$h) = @_;
++
++$code.=<<___;
++	mov	`$SZ*(($i+1)&0xf)`(%rsp),$a0
++	mov	`$SZ*(($i+14)&0xf)`(%rsp),$a2
++
++	mov	$a0,$T1
++	ror	\$`$sigma0[1]-$sigma0[0]`,$a0
++	add	$a1,$a			# modulo-scheduled h+=Sigma0(a)
++	mov	$a2,$a1
++	ror	\$`$sigma1[1]-$sigma1[0]`,$a2
++
++	xor	$T1,$a0
++	shr	\$$sigma0[2],$T1
++	ror	\$$sigma0[0],$a0
++	xor	$a1,$a2
++	shr	\$$sigma1[2],$a1
++
++	ror	\$$sigma1[0],$a2
++	xor	$a0,$T1			# sigma0(X[(i+1)&0xf])
++	xor	$a1,$a2			# sigma1(X[(i+14)&0xf])
++	add	`$SZ*(($i+9)&0xf)`(%rsp),$T1
++
++	add	`$SZ*($i&0xf)`(%rsp),$T1
++	mov	$e,$a0
++	add	$a2,$T1
++	mov	$a,$a1
++___
++	&ROUND_00_15(@_);
++}
++
++$code=<<___;
++.text
++
++.extern	OPENSSL_ia32cap_P
++.globl	$func
++.type	$func,\@function,3
++.align	16
++$func:
++___
++$code.=<<___ if ($SZ==4 || $avx);
++	lea	OPENSSL_ia32cap_P(%rip),%r11
++	mov	0(%r11),%r9d
++	mov	4(%r11),%r10d
++	mov	8(%r11),%r11d
++___
++$code.=<<___ if ($SZ==4 && $shaext);
++	test	\$`1<<29`,%r11d		# check for SHA
++	jnz	_shaext_shortcut
++___
++$code.=<<___ if ($avx && $SZ==8);
++	test	\$`1<<11`,%r10d		# check for XOP
++	jnz	.Lxop_shortcut
++___
++$code.=<<___ if ($avx>1);
++	and	\$`1<<8|1<<5|1<<3`,%r11d	# check for BMI2+AVX2+BMI1
++	cmp	\$`1<<8|1<<5|1<<3`,%r11d
++	je	.Lavx2_shortcut
++___
++$code.=<<___ if ($avx);
++	and	\$`1<<30`,%r9d		# mask "Intel CPU" bit
++	and	\$`1<<28|1<<9`,%r10d	# mask AVX and SSSE3 bits
++	or	%r9d,%r10d
++	cmp	\$`1<<28|1<<9|1<<30`,%r10d
++	je	.Lavx_shortcut
++___
++$code.=<<___ if ($SZ==4);
++	test	\$`1<<9`,%r10d
++	jnz	.Lssse3_shortcut
++___
++$code.=<<___;
++	push	%rbx
++	push	%rbp
++	push	%r12
++	push	%r13
++	push	%r14
++	push	%r15
++	mov	%rsp,%r11		# copy %rsp
++	shl	\$4,%rdx		# num*16
++	sub	\$$framesz,%rsp
++	lea	($inp,%rdx,$SZ),%rdx	# inp+num*16*$SZ
++	and	\$-64,%rsp		# align stack frame
++	mov	$ctx,$_ctx		# save ctx, 1st arg
++	mov	$inp,$_inp		# save inp, 2nd arh
++	mov	%rdx,$_end		# save end pointer, "3rd" arg
++	mov	%r11,$_rsp		# save copy of %rsp
++.Lprologue:
++
++	mov	$SZ*0($ctx),$A
++	mov	$SZ*1($ctx),$B
++	mov	$SZ*2($ctx),$C
++	mov	$SZ*3($ctx),$D
++	mov	$SZ*4($ctx),$E
++	mov	$SZ*5($ctx),$F
++	mov	$SZ*6($ctx),$G
++	mov	$SZ*7($ctx),$H
++	jmp	.Lloop
++
++.align	16
++.Lloop:
++	mov	$B,$a3
++	lea	$TABLE(%rip),$Tbl
++	xor	$C,$a3			# magic
++___
++	for($i=0;$i<16;$i++) {
++		$code.="	mov	$SZ*$i($inp),$T1\n";
++		$code.="	mov	@ROT[4],$a0\n";
++		$code.="	mov	@ROT[0],$a1\n";
++		$code.="	bswap	$T1\n";
++		&ROUND_00_15($i,@ROT);
++		unshift(@ROT,pop(@ROT));
++	}
++$code.=<<___;
++	jmp	.Lrounds_16_xx
++.align	16
++.Lrounds_16_xx:
++___
++	for(;$i<32;$i++) {
++		&ROUND_16_XX($i,@ROT);
++		unshift(@ROT,pop(@ROT));
++	}
++
++$code.=<<___;
++	cmpb	\$0,`$SZ-1`($Tbl)
++	jnz	.Lrounds_16_xx
++
++	mov	$_ctx,$ctx
++	add	$a1,$A			# modulo-scheduled h+=Sigma0(a)
++	lea	16*$SZ($inp),$inp
++
++	add	$SZ*0($ctx),$A
++	add	$SZ*1($ctx),$B
++	add	$SZ*2($ctx),$C
++	add	$SZ*3($ctx),$D
++	add	$SZ*4($ctx),$E
++	add	$SZ*5($ctx),$F
++	add	$SZ*6($ctx),$G
++	add	$SZ*7($ctx),$H
++
++	cmp	$_end,$inp
++
++	mov	$A,$SZ*0($ctx)
++	mov	$B,$SZ*1($ctx)
++	mov	$C,$SZ*2($ctx)
++	mov	$D,$SZ*3($ctx)
++	mov	$E,$SZ*4($ctx)
++	mov	$F,$SZ*5($ctx)
++	mov	$G,$SZ*6($ctx)
++	mov	$H,$SZ*7($ctx)
++	jb	.Lloop
++
++	mov	$_rsp,%rsi
++	mov	(%rsi),%r15
++	mov	8(%rsi),%r14
++	mov	16(%rsi),%r13
++	mov	24(%rsi),%r12
++	mov	32(%rsi),%rbp
++	mov	40(%rsi),%rbx
++	lea	48(%rsi),%rsp
++.Lepilogue:
++	ret
++.size	$func,.-$func
++___
++
++if ($SZ==4) {
++$code.=<<___;
++.align	64
++.type	$TABLE,\@object
++$TABLE:
++	.long	0x428a2f98,0x71374491,0xb5c0fbcf,0xe9b5dba5
++	.long	0x428a2f98,0x71374491,0xb5c0fbcf,0xe9b5dba5
++	.long	0x3956c25b,0x59f111f1,0x923f82a4,0xab1c5ed5
++	.long	0x3956c25b,0x59f111f1,0x923f82a4,0xab1c5ed5
++	.long	0xd807aa98,0x12835b01,0x243185be,0x550c7dc3
++	.long	0xd807aa98,0x12835b01,0x243185be,0x550c7dc3
++	.long	0x72be5d74,0x80deb1fe,0x9bdc06a7,0xc19bf174
++	.long	0x72be5d74,0x80deb1fe,0x9bdc06a7,0xc19bf174
++	.long	0xe49b69c1,0xefbe4786,0x0fc19dc6,0x240ca1cc
++	.long	0xe49b69c1,0xefbe4786,0x0fc19dc6,0x240ca1cc
++	.long	0x2de92c6f,0x4a7484aa,0x5cb0a9dc,0x76f988da
++	.long	0x2de92c6f,0x4a7484aa,0x5cb0a9dc,0x76f988da
++	.long	0x983e5152,0xa831c66d,0xb00327c8,0xbf597fc7
++	.long	0x983e5152,0xa831c66d,0xb00327c8,0xbf597fc7
++	.long	0xc6e00bf3,0xd5a79147,0x06ca6351,0x14292967
++	.long	0xc6e00bf3,0xd5a79147,0x06ca6351,0x14292967
++	.long	0x27b70a85,0x2e1b2138,0x4d2c6dfc,0x53380d13
++	.long	0x27b70a85,0x2e1b2138,0x4d2c6dfc,0x53380d13
++	.long	0x650a7354,0x766a0abb,0x81c2c92e,0x92722c85
++	.long	0x650a7354,0x766a0abb,0x81c2c92e,0x92722c85
++	.long	0xa2bfe8a1,0xa81a664b,0xc24b8b70,0xc76c51a3
++	.long	0xa2bfe8a1,0xa81a664b,0xc24b8b70,0xc76c51a3
++	.long	0xd192e819,0xd6990624,0xf40e3585,0x106aa070
++	.long	0xd192e819,0xd6990624,0xf40e3585,0x106aa070
++	.long	0x19a4c116,0x1e376c08,0x2748774c,0x34b0bcb5
++	.long	0x19a4c116,0x1e376c08,0x2748774c,0x34b0bcb5
++	.long	0x391c0cb3,0x4ed8aa4a,0x5b9cca4f,0x682e6ff3
++	.long	0x391c0cb3,0x4ed8aa4a,0x5b9cca4f,0x682e6ff3
++	.long	0x748f82ee,0x78a5636f,0x84c87814,0x8cc70208
++	.long	0x748f82ee,0x78a5636f,0x84c87814,0x8cc70208
++	.long	0x90befffa,0xa4506ceb,0xbef9a3f7,0xc67178f2
++	.long	0x90befffa,0xa4506ceb,0xbef9a3f7,0xc67178f2
++
++	.long	0x00010203,0x04050607,0x08090a0b,0x0c0d0e0f
++	.long	0x00010203,0x04050607,0x08090a0b,0x0c0d0e0f
++	.long	0x03020100,0x0b0a0908,0xffffffff,0xffffffff
++	.long	0x03020100,0x0b0a0908,0xffffffff,0xffffffff
++	.long	0xffffffff,0xffffffff,0x03020100,0x0b0a0908
++	.long	0xffffffff,0xffffffff,0x03020100,0x0b0a0908
++	.asciz	"SHA256 block transform for x86_64, CRYPTOGAMS by "
++___
++} else {
++$code.=<<___;
++.align	64
++.type	$TABLE,\@object
++$TABLE:
++	.quad	0x428a2f98d728ae22,0x7137449123ef65cd
++	.quad	0x428a2f98d728ae22,0x7137449123ef65cd
++	.quad	0xb5c0fbcfec4d3b2f,0xe9b5dba58189dbbc
++	.quad	0xb5c0fbcfec4d3b2f,0xe9b5dba58189dbbc
++	.quad	0x3956c25bf348b538,0x59f111f1b605d019
++	.quad	0x3956c25bf348b538,0x59f111f1b605d019
++	.quad	0x923f82a4af194f9b,0xab1c5ed5da6d8118
++	.quad	0x923f82a4af194f9b,0xab1c5ed5da6d8118
++	.quad	0xd807aa98a3030242,0x12835b0145706fbe
++	.quad	0xd807aa98a3030242,0x12835b0145706fbe
++	.quad	0x243185be4ee4b28c,0x550c7dc3d5ffb4e2
++	.quad	0x243185be4ee4b28c,0x550c7dc3d5ffb4e2
++	.quad	0x72be5d74f27b896f,0x80deb1fe3b1696b1
++	.quad	0x72be5d74f27b896f,0x80deb1fe3b1696b1
++	.quad	0x9bdc06a725c71235,0xc19bf174cf692694
++	.quad	0x9bdc06a725c71235,0xc19bf174cf692694
++	.quad	0xe49b69c19ef14ad2,0xefbe4786384f25e3
++	.quad	0xe49b69c19ef14ad2,0xefbe4786384f25e3
++	.quad	0x0fc19dc68b8cd5b5,0x240ca1cc77ac9c65
++	.quad	0x0fc19dc68b8cd5b5,0x240ca1cc77ac9c65
++	.quad	0x2de92c6f592b0275,0x4a7484aa6ea6e483
++	.quad	0x2de92c6f592b0275,0x4a7484aa6ea6e483
++	.quad	0x5cb0a9dcbd41fbd4,0x76f988da831153b5
++	.quad	0x5cb0a9dcbd41fbd4,0x76f988da831153b5
++	.quad	0x983e5152ee66dfab,0xa831c66d2db43210
++	.quad	0x983e5152ee66dfab,0xa831c66d2db43210
++	.quad	0xb00327c898fb213f,0xbf597fc7beef0ee4
++	.quad	0xb00327c898fb213f,0xbf597fc7beef0ee4
++	.quad	0xc6e00bf33da88fc2,0xd5a79147930aa725
++	.quad	0xc6e00bf33da88fc2,0xd5a79147930aa725
++	.quad	0x06ca6351e003826f,0x142929670a0e6e70
++	.quad	0x06ca6351e003826f,0x142929670a0e6e70
++	.quad	0x27b70a8546d22ffc,0x2e1b21385c26c926
++	.quad	0x27b70a8546d22ffc,0x2e1b21385c26c926
++	.quad	0x4d2c6dfc5ac42aed,0x53380d139d95b3df
++	.quad	0x4d2c6dfc5ac42aed,0x53380d139d95b3df
++	.quad	0x650a73548baf63de,0x766a0abb3c77b2a8
++	.quad	0x650a73548baf63de,0x766a0abb3c77b2a8
++	.quad	0x81c2c92e47edaee6,0x92722c851482353b
++	.quad	0x81c2c92e47edaee6,0x92722c851482353b
++	.quad	0xa2bfe8a14cf10364,0xa81a664bbc423001
++	.quad	0xa2bfe8a14cf10364,0xa81a664bbc423001
++	.quad	0xc24b8b70d0f89791,0xc76c51a30654be30
++	.quad	0xc24b8b70d0f89791,0xc76c51a30654be30
++	.quad	0xd192e819d6ef5218,0xd69906245565a910
++	.quad	0xd192e819d6ef5218,0xd69906245565a910
++	.quad	0xf40e35855771202a,0x106aa07032bbd1b8
++	.quad	0xf40e35855771202a,0x106aa07032bbd1b8
++	.quad	0x19a4c116b8d2d0c8,0x1e376c085141ab53
++	.quad	0x19a4c116b8d2d0c8,0x1e376c085141ab53
++	.quad	0x2748774cdf8eeb99,0x34b0bcb5e19b48a8
++	.quad	0x2748774cdf8eeb99,0x34b0bcb5e19b48a8
++	.quad	0x391c0cb3c5c95a63,0x4ed8aa4ae3418acb
++	.quad	0x391c0cb3c5c95a63,0x4ed8aa4ae3418acb
++	.quad	0x5b9cca4f7763e373,0x682e6ff3d6b2b8a3
++	.quad	0x5b9cca4f7763e373,0x682e6ff3d6b2b8a3
++	.quad	0x748f82ee5defb2fc,0x78a5636f43172f60
++	.quad	0x748f82ee5defb2fc,0x78a5636f43172f60
++	.quad	0x84c87814a1f0ab72,0x8cc702081a6439ec
++	.quad	0x84c87814a1f0ab72,0x8cc702081a6439ec
++	.quad	0x90befffa23631e28,0xa4506cebde82bde9
++	.quad	0x90befffa23631e28,0xa4506cebde82bde9
++	.quad	0xbef9a3f7b2c67915,0xc67178f2e372532b
++	.quad	0xbef9a3f7b2c67915,0xc67178f2e372532b
++	.quad	0xca273eceea26619c,0xd186b8c721c0c207
++	.quad	0xca273eceea26619c,0xd186b8c721c0c207
++	.quad	0xeada7dd6cde0eb1e,0xf57d4f7fee6ed178
++	.quad	0xeada7dd6cde0eb1e,0xf57d4f7fee6ed178
++	.quad	0x06f067aa72176fba,0x0a637dc5a2c898a6
++	.quad	0x06f067aa72176fba,0x0a637dc5a2c898a6
++	.quad	0x113f9804bef90dae,0x1b710b35131c471b
++	.quad	0x113f9804bef90dae,0x1b710b35131c471b
++	.quad	0x28db77f523047d84,0x32caab7b40c72493
++	.quad	0x28db77f523047d84,0x32caab7b40c72493
++	.quad	0x3c9ebe0a15c9bebc,0x431d67c49c100d4c
++	.quad	0x3c9ebe0a15c9bebc,0x431d67c49c100d4c
++	.quad	0x4cc5d4becb3e42b6,0x597f299cfc657e2a
++	.quad	0x4cc5d4becb3e42b6,0x597f299cfc657e2a
++	.quad	0x5fcb6fab3ad6faec,0x6c44198c4a475817
++	.quad	0x5fcb6fab3ad6faec,0x6c44198c4a475817
++
++	.quad	0x0001020304050607,0x08090a0b0c0d0e0f
++	.quad	0x0001020304050607,0x08090a0b0c0d0e0f
++	.asciz	"SHA512 block transform for x86_64, CRYPTOGAMS by "
++___
++}
++
++######################################################################
++# SIMD code paths
++#
++if ($SZ==4 && $shaext) {{{
++######################################################################
++# Intel SHA Extensions implementation of SHA256 update function.
++#
++my ($ctx,$inp,$num,$Tbl)=("%rdi","%rsi","%rdx","%rcx");
++
++my ($Wi,$ABEF,$CDGH,$TMP,$BSWAP,$ABEF_SAVE,$CDGH_SAVE)=map("%xmm$_",(0..2,7..10));
++my @MSG=map("%xmm$_",(3..6));
++
++$code.=<<___;
++.type	sha256_block_data_order_shaext,\@function,3
++.align	64
++sha256_block_data_order_shaext:
++_shaext_shortcut:
++___
++$code.=<<___ if ($win64);
++	lea	`-8-5*16`(%rsp),%rsp
++	movaps	%xmm6,-8-5*16(%rax)
++	movaps	%xmm7,-8-4*16(%rax)
++	movaps	%xmm8,-8-3*16(%rax)
++	movaps	%xmm9,-8-2*16(%rax)
++	movaps	%xmm10,-8-1*16(%rax)
++.Lprologue_shaext:
++___
++$code.=<<___;
++	lea		K256+0x80(%rip),$Tbl
++	movdqu		($ctx),$ABEF		# DCBA
++	movdqu		16($ctx),$CDGH		# HGFE
++	movdqa		0x200-0x80($Tbl),$TMP	# byte swap mask
++
++	pshufd		\$0x1b,$ABEF,$Wi	# ABCD
++	pshufd		\$0xb1,$ABEF,$ABEF	# CDAB
++	pshufd		\$0x1b,$CDGH,$CDGH	# EFGH
++	movdqa		$TMP,$BSWAP		# offload
++	palignr		\$8,$CDGH,$ABEF		# ABEF
++	punpcklqdq	$Wi,$CDGH		# CDGH
++	jmp		.Loop_shaext
++
++.align	16
++.Loop_shaext:
++	movdqu		($inp),@MSG[0]
++	movdqu		0x10($inp),@MSG[1]
++	movdqu		0x20($inp),@MSG[2]
++	pshufb		$TMP,@MSG[0]
++	movdqu		0x30($inp),@MSG[3]
++
++	movdqa		0*32-0x80($Tbl),$Wi
++	paddd		@MSG[0],$Wi
++	pshufb		$TMP,@MSG[1]
++	movdqa		$CDGH,$CDGH_SAVE	# offload
++	sha256rnds2	$ABEF,$CDGH		# 0-3
++	pshufd		\$0x0e,$Wi,$Wi
++	nop
++	movdqa		$ABEF,$ABEF_SAVE	# offload
++	sha256rnds2	$CDGH,$ABEF
++
++	movdqa		1*32-0x80($Tbl),$Wi
++	paddd		@MSG[1],$Wi
++	pshufb		$TMP,@MSG[2]
++	sha256rnds2	$ABEF,$CDGH		# 4-7
++	pshufd		\$0x0e,$Wi,$Wi
++	lea		0x40($inp),$inp
++	sha256msg1	@MSG[1],@MSG[0]
++	sha256rnds2	$CDGH,$ABEF
++
++	movdqa		2*32-0x80($Tbl),$Wi
++	paddd		@MSG[2],$Wi
++	pshufb		$TMP,@MSG[3]
++	sha256rnds2	$ABEF,$CDGH		# 8-11
++	pshufd		\$0x0e,$Wi,$Wi
++	movdqa		@MSG[3],$TMP
++	palignr		\$4,@MSG[2],$TMP
++	nop
++	paddd		$TMP,@MSG[0]
++	sha256msg1	@MSG[2],@MSG[1]
++	sha256rnds2	$CDGH,$ABEF
++
++	movdqa		3*32-0x80($Tbl),$Wi
++	paddd		@MSG[3],$Wi
++	sha256msg2	@MSG[3],@MSG[0]
++	sha256rnds2	$ABEF,$CDGH		# 12-15
++	pshufd		\$0x0e,$Wi,$Wi
++	movdqa		@MSG[0],$TMP
++	palignr		\$4,@MSG[3],$TMP
++	nop
++	paddd		$TMP,@MSG[1]
++	sha256msg1	@MSG[3],@MSG[2]
++	sha256rnds2	$CDGH,$ABEF
++___
++for($i=4;$i<16-3;$i++) {
++$code.=<<___;
++	movdqa		$i*32-0x80($Tbl),$Wi
++	paddd		@MSG[0],$Wi
++	sha256msg2	@MSG[0],@MSG[1]
++	sha256rnds2	$ABEF,$CDGH		# 16-19...
++	pshufd		\$0x0e,$Wi,$Wi
++	movdqa		@MSG[1],$TMP
++	palignr		\$4,@MSG[0],$TMP
++	nop
++	paddd		$TMP,@MSG[2]
++	sha256msg1	@MSG[0],@MSG[3]
++	sha256rnds2	$CDGH,$ABEF
++___
++	push(@MSG,shift(@MSG));
++}
++$code.=<<___;
++	movdqa		13*32-0x80($Tbl),$Wi
++	paddd		@MSG[0],$Wi
++	sha256msg2	@MSG[0],@MSG[1]
++	sha256rnds2	$ABEF,$CDGH		# 52-55
++	pshufd		\$0x0e,$Wi,$Wi
++	movdqa		@MSG[1],$TMP
++	palignr		\$4,@MSG[0],$TMP
++	sha256rnds2	$CDGH,$ABEF
++	paddd		$TMP,@MSG[2]
++
++	movdqa		14*32-0x80($Tbl),$Wi
++	paddd		@MSG[1],$Wi
++	sha256rnds2	$ABEF,$CDGH		# 56-59
++	pshufd		\$0x0e,$Wi,$Wi
++	sha256msg2	@MSG[1],@MSG[2]
++	movdqa		$BSWAP,$TMP
++	sha256rnds2	$CDGH,$ABEF
++
++	movdqa		15*32-0x80($Tbl),$Wi
++	paddd		@MSG[2],$Wi
++	nop
++	sha256rnds2	$ABEF,$CDGH		# 60-63
++	pshufd		\$0x0e,$Wi,$Wi
++	dec		$num
++	nop
++	sha256rnds2	$CDGH,$ABEF
++
++	paddd		$CDGH_SAVE,$CDGH
++	paddd		$ABEF_SAVE,$ABEF
++	jnz		.Loop_shaext
++
++	pshufd		\$0xb1,$CDGH,$CDGH	# DCHG
++	pshufd		\$0x1b,$ABEF,$TMP	# FEBA
++	pshufd		\$0xb1,$ABEF,$ABEF	# BAFE
++	punpckhqdq	$CDGH,$ABEF		# DCBA
++	palignr		\$8,$TMP,$CDGH		# HGFE
++
++	movdqu	$ABEF,($ctx)
++	movdqu	$CDGH,16($ctx)
++___
++$code.=<<___ if ($win64);
++	movaps	-8-5*16(%rax),%xmm6
++	movaps	-8-4*16(%rax),%xmm7
++	movaps	-8-3*16(%rax),%xmm8
++	movaps	-8-2*16(%rax),%xmm9
++	movaps	-8-1*16(%rax),%xmm10
++	mov	%rax,%rsp
++.Lepilogue_shaext:
++___
++$code.=<<___;
++	ret
++.size	sha256_block_data_order_shaext,.-sha256_block_data_order_shaext
++___
++}}}
++{{{
++
++my $a4=$T1;
++my ($a,$b,$c,$d,$e,$f,$g,$h);
++
++sub AUTOLOAD()		# thunk [simplified] 32-bit style perlasm
++{ my $opcode = $AUTOLOAD; $opcode =~ s/.*:://;
++  my $arg = pop;
++    $arg = "\$$arg" if ($arg*1 eq $arg);
++    $code .= "\t$opcode\t".join(',',$arg,reverse @_)."\n";
++}
++
++sub body_00_15 () {
++	(
++	'($a,$b,$c,$d,$e,$f,$g,$h)=@ROT;'.
++
++	'&ror	($a0,$Sigma1[2]-$Sigma1[1])',
++	'&mov	($a,$a1)',
++	'&mov	($a4,$f)',
++
++	'&ror	($a1,$Sigma0[2]-$Sigma0[1])',
++	'&xor	($a0,$e)',
++	'&xor	($a4,$g)',			# f^g
++
++	'&ror	($a0,$Sigma1[1]-$Sigma1[0])',
++	'&xor	($a1,$a)',
++	'&and	($a4,$e)',			# (f^g)&e
++
++	'&xor	($a0,$e)',
++	'&add	($h,$SZ*($i&15)."(%rsp)")',	# h+=X[i]+K[i]
++	'&mov	($a2,$a)',
++
++	'&xor	($a4,$g)',			# Ch(e,f,g)=((f^g)&e)^g
++	'&ror	($a1,$Sigma0[1]-$Sigma0[0])',
++	'&xor	($a2,$b)',			# a^b, b^c in next round
++
++	'&add	($h,$a4)',			# h+=Ch(e,f,g)
++	'&ror	($a0,$Sigma1[0])',		# Sigma1(e)
++	'&and	($a3,$a2)',			# (b^c)&(a^b)
++
++	'&xor	($a1,$a)',
++	'&add	($h,$a0)',			# h+=Sigma1(e)
++	'&xor	($a3,$b)',			# Maj(a,b,c)=Ch(a^b,c,b)
++
++	'&ror	($a1,$Sigma0[0])',		# Sigma0(a)
++	'&add	($d,$h)',			# d+=h
++	'&add	($h,$a3)',			# h+=Maj(a,b,c)
++
++	'&mov	($a0,$d)',
++	'&add	($a1,$h);'.			# h+=Sigma0(a)
++	'($a2,$a3) = ($a3,$a2); unshift(@ROT,pop(@ROT)); $i++;'
++	);
++}
++
++######################################################################
++# SSSE3 code path
++#
++if ($SZ==4) {	# SHA256 only
++my @X = map("%xmm$_",(0..3));
++my ($t0,$t1,$t2,$t3, $t4,$t5) = map("%xmm$_",(4..9));
++
++$code.=<<___;
++.type	${func}_ssse3,\@function,3
++.align	64
++${func}_ssse3:
++.Lssse3_shortcut:
++	push	%rbx
++	push	%rbp
++	push	%r12
++	push	%r13
++	push	%r14
++	push	%r15
++	mov	%rsp,%r11		# copy %rsp
++	shl	\$4,%rdx		# num*16
++	sub	\$`$framesz+$win64*16*4`,%rsp
++	lea	($inp,%rdx,$SZ),%rdx	# inp+num*16*$SZ
++	and	\$-64,%rsp		# align stack frame
++	mov	$ctx,$_ctx		# save ctx, 1st arg
++	mov	$inp,$_inp		# save inp, 2nd arh
++	mov	%rdx,$_end		# save end pointer, "3rd" arg
++	mov	%r11,$_rsp		# save copy of %rsp
++___
++$code.=<<___ if ($win64);
++	movaps	%xmm6,16*$SZ+32(%rsp)
++	movaps	%xmm7,16*$SZ+48(%rsp)
++	movaps	%xmm8,16*$SZ+64(%rsp)
++	movaps	%xmm9,16*$SZ+80(%rsp)
++___
++$code.=<<___;
++.Lprologue_ssse3:
++
++	mov	$SZ*0($ctx),$A
++	mov	$SZ*1($ctx),$B
++	mov	$SZ*2($ctx),$C
++	mov	$SZ*3($ctx),$D
++	mov	$SZ*4($ctx),$E
++	mov	$SZ*5($ctx),$F
++	mov	$SZ*6($ctx),$G
++	mov	$SZ*7($ctx),$H
++___
++
++$code.=<<___;
++	#movdqa	$TABLE+`$SZ*2*$rounds`+32(%rip),$t4
++	#movdqa	$TABLE+`$SZ*2*$rounds`+64(%rip),$t5
++	jmp	.Lloop_ssse3
++.align	16
++.Lloop_ssse3:
++	movdqa	$TABLE+`$SZ*2*$rounds`(%rip),$t3
++	movdqu	0x00($inp),@X[0]
++	movdqu	0x10($inp),@X[1]
++	movdqu	0x20($inp),@X[2]
++	pshufb	$t3,@X[0]
++	movdqu	0x30($inp),@X[3]
++	lea	$TABLE(%rip),$Tbl
++	pshufb	$t3,@X[1]
++	movdqa	0x00($Tbl),$t0
++	movdqa	0x20($Tbl),$t1
++	pshufb	$t3,@X[2]
++	paddd	@X[0],$t0
++	movdqa	0x40($Tbl),$t2
++	pshufb	$t3,@X[3]
++	movdqa	0x60($Tbl),$t3
++	paddd	@X[1],$t1
++	paddd	@X[2],$t2
++	paddd	@X[3],$t3
++	movdqa	$t0,0x00(%rsp)
++	mov	$A,$a1
++	movdqa	$t1,0x10(%rsp)
++	mov	$B,$a3
++	movdqa	$t2,0x20(%rsp)
++	xor	$C,$a3			# magic
++	movdqa	$t3,0x30(%rsp)
++	mov	$E,$a0
++	jmp	.Lssse3_00_47
++
++.align	16
++.Lssse3_00_47:
++	sub	\$`-16*2*$SZ`,$Tbl	# size optimization
++___
++sub Xupdate_256_SSSE3 () {
++	(
++	'&movdqa	($t0,@X[1]);',
++	'&movdqa	($t3,@X[3])',
++	'&palignr	($t0,@X[0],$SZ)',	# X[1..4]
++	 '&palignr	($t3,@X[2],$SZ);',	# X[9..12]
++	'&movdqa	($t1,$t0)',
++	'&movdqa	($t2,$t0);',
++	'&psrld		($t0,$sigma0[2])',
++	 '&paddd	(@X[0],$t3);',		# X[0..3] += X[9..12]
++	'&psrld		($t2,$sigma0[0])',
++	 '&pshufd	($t3,@X[3],0b11111010)',# X[14..15]
++	'&pslld		($t1,8*$SZ-$sigma0[1]);'.
++	'&pxor		($t0,$t2)',
++	'&psrld		($t2,$sigma0[1]-$sigma0[0]);'.
++	'&pxor		($t0,$t1)',
++	'&pslld		($t1,$sigma0[1]-$sigma0[0]);'.
++	'&pxor		($t0,$t2);',
++	 '&movdqa	($t2,$t3)',
++	'&pxor		($t0,$t1);',		# sigma0(X[1..4])
++	 '&psrld	($t3,$sigma1[2])',
++	'&paddd		(@X[0],$t0);',		# X[0..3] += sigma0(X[1..4])
++	 '&psrlq	($t2,$sigma1[0])',
++	 '&pxor		($t3,$t2);',
++	 '&psrlq	($t2,$sigma1[1]-$sigma1[0])',
++	 '&pxor		($t3,$t2)',
++	 '&pshufb	($t3,$t4)',		# sigma1(X[14..15])
++	'&paddd		(@X[0],$t3)',		# X[0..1] += sigma1(X[14..15])
++	 '&pshufd	($t3,@X[0],0b01010000)',# X[16..17]
++	 '&movdqa	($t2,$t3);',
++	 '&psrld	($t3,$sigma1[2])',
++	 '&psrlq	($t2,$sigma1[0])',
++	 '&pxor		($t3,$t2);',
++	 '&psrlq	($t2,$sigma1[1]-$sigma1[0])',
++	 '&pxor		($t3,$t2);',
++	'&movdqa	($t2,16*2*$j."($Tbl)")',
++	 '&pshufb	($t3,$t5)',
++	'&paddd		(@X[0],$t3)'		# X[2..3] += sigma1(X[16..17])
++	);
++}
++
++sub SSSE3_256_00_47 () {
++my $j = shift;
++my $body = shift;
++my @X = @_;
++my @insns = (&$body,&$body,&$body,&$body);	# 104 instructions
++
++    if (0) {
++	foreach (Xupdate_256_SSSE3()) {		# 36 instructions
++	    eval;
++	    eval(shift(@insns));
++	    eval(shift(@insns));
++	    eval(shift(@insns));
++	}
++    } else {			# squeeze extra 4% on Westmere and 19% on Atom
++	  eval(shift(@insns));	#@
++	&movdqa		($t0,@X[1]);
++	  eval(shift(@insns));
++	  eval(shift(@insns));
++	&movdqa		($t3,@X[3]);
++	  eval(shift(@insns));	#@
++	  eval(shift(@insns));
++	  eval(shift(@insns));
++	  eval(shift(@insns));	#@
++	  eval(shift(@insns));
++	&palignr	($t0,@X[0],$SZ);	# X[1..4]
++	  eval(shift(@insns));
++	  eval(shift(@insns));
++	 &palignr	($t3,@X[2],$SZ);	# X[9..12]
++	  eval(shift(@insns));
++	  eval(shift(@insns));
++	  eval(shift(@insns));
++	  eval(shift(@insns));	#@
++	&movdqa		($t1,$t0);
++	  eval(shift(@insns));
++	  eval(shift(@insns));
++	&movdqa		($t2,$t0);
++	  eval(shift(@insns));	#@
++	  eval(shift(@insns));
++	&psrld		($t0,$sigma0[2]);
++	  eval(shift(@insns));
++	  eval(shift(@insns));
++	  eval(shift(@insns));
++	 &paddd		(@X[0],$t3);		# X[0..3] += X[9..12]
++	  eval(shift(@insns));	#@
++	  eval(shift(@insns));
++	&psrld		($t2,$sigma0[0]);
++	  eval(shift(@insns));
++	  eval(shift(@insns));
++	 &pshufd	($t3,@X[3],0b11111010);	# X[4..15]
++	  eval(shift(@insns));
++	  eval(shift(@insns));	#@
++	&pslld		($t1,8*$SZ-$sigma0[1]);
++	  eval(shift(@insns));
++	  eval(shift(@insns));
++	&pxor		($t0,$t2);
++	  eval(shift(@insns));	#@
++	  eval(shift(@insns));
++	  eval(shift(@insns));
++	  eval(shift(@insns));	#@
++	&psrld		($t2,$sigma0[1]-$sigma0[0]);
++	  eval(shift(@insns));
++	&pxor		($t0,$t1);
++	  eval(shift(@insns));
++	  eval(shift(@insns));
++	&pslld		($t1,$sigma0[1]-$sigma0[0]);
++	  eval(shift(@insns));
++	  eval(shift(@insns));
++	&pxor		($t0,$t2);
++	  eval(shift(@insns));
++	  eval(shift(@insns));	#@
++	 &movdqa	($t2,$t3);
++	  eval(shift(@insns));
++	  eval(shift(@insns));
++	&pxor		($t0,$t1);		# sigma0(X[1..4])
++	  eval(shift(@insns));	#@
++	  eval(shift(@insns));
++	  eval(shift(@insns));
++	 &psrld		($t3,$sigma1[2]);
++	  eval(shift(@insns));
++	  eval(shift(@insns));
++	&paddd		(@X[0],$t0);		# X[0..3] += sigma0(X[1..4])
++	  eval(shift(@insns));	#@
++	  eval(shift(@insns));
++	 &psrlq		($t2,$sigma1[0]);
++	  eval(shift(@insns));
++	  eval(shift(@insns));
++	  eval(shift(@insns));
++	 &pxor		($t3,$t2);
++	  eval(shift(@insns));	#@
++	  eval(shift(@insns));
++	  eval(shift(@insns));
++	  eval(shift(@insns));	#@
++	 &psrlq		($t2,$sigma1[1]-$sigma1[0]);
++	  eval(shift(@insns));
++	  eval(shift(@insns));
++	 &pxor		($t3,$t2);
++	  eval(shift(@insns));	#@
++	  eval(shift(@insns));
++	  eval(shift(@insns));
++	 #&pshufb	($t3,$t4);		# sigma1(X[14..15])
++	 &pshufd	($t3,$t3,0b10000000);
++	  eval(shift(@insns));
++	  eval(shift(@insns));
++	  eval(shift(@insns));
++	 &psrldq	($t3,8);
++	  eval(shift(@insns));
++	  eval(shift(@insns));	#@
++	  eval(shift(@insns));
++	  eval(shift(@insns));
++	  eval(shift(@insns));	#@
++	&paddd		(@X[0],$t3);		# X[0..1] += sigma1(X[14..15])
++	  eval(shift(@insns));
++	  eval(shift(@insns));
++	  eval(shift(@insns));
++	 &pshufd	($t3,@X[0],0b01010000);	# X[16..17]
++	  eval(shift(@insns));
++	  eval(shift(@insns));	#@
++	  eval(shift(@insns));
++	 &movdqa	($t2,$t3);
++	  eval(shift(@insns));
++	  eval(shift(@insns));
++	 &psrld		($t3,$sigma1[2]);
++	  eval(shift(@insns));
++	  eval(shift(@insns));	#@
++	 &psrlq		($t2,$sigma1[0]);
++	  eval(shift(@insns));
++	  eval(shift(@insns));
++	 &pxor		($t3,$t2);
++	  eval(shift(@insns));	#@
++	  eval(shift(@insns));
++	  eval(shift(@insns));
++	  eval(shift(@insns));	#@
++	  eval(shift(@insns));
++	 &psrlq		($t2,$sigma1[1]-$sigma1[0]);
++	  eval(shift(@insns));
++	  eval(shift(@insns));
++	  eval(shift(@insns));
++	 &pxor		($t3,$t2);
++	  eval(shift(@insns));
++	  eval(shift(@insns));
++	  eval(shift(@insns));	#@
++	 #&pshufb	($t3,$t5);
++	 &pshufd	($t3,$t3,0b00001000);
++	  eval(shift(@insns));
++	  eval(shift(@insns));
++	&movdqa		($t2,16*2*$j."($Tbl)");
++	  eval(shift(@insns));	#@
++	  eval(shift(@insns));
++	 &pslldq	($t3,8);
++	  eval(shift(@insns));
++	  eval(shift(@insns));
++	  eval(shift(@insns));
++	&paddd		(@X[0],$t3);		# X[2..3] += sigma1(X[16..17])
++	  eval(shift(@insns));	#@
++	  eval(shift(@insns));
++	  eval(shift(@insns));
++    }
++	&paddd		($t2,@X[0]);
++	  foreach (@insns) { eval; }		# remaining instructions
++	&movdqa		(16*$j."(%rsp)",$t2);
++}
++
++    for ($i=0,$j=0; $j<4; $j++) {
++	&SSSE3_256_00_47($j,\&body_00_15,@X);
++	push(@X,shift(@X));			# rotate(@X)
++    }
++	&cmpb	($SZ-1+16*2*$SZ."($Tbl)",0);
++	&jne	(".Lssse3_00_47");
++
++    for ($i=0; $i<16; ) {
++	foreach(body_00_15()) { eval; }
++    }
++$code.=<<___;
++	mov	$_ctx,$ctx
++	mov	$a1,$A
++
++	add	$SZ*0($ctx),$A
++	lea	16*$SZ($inp),$inp
++	add	$SZ*1($ctx),$B
++	add	$SZ*2($ctx),$C
++	add	$SZ*3($ctx),$D
++	add	$SZ*4($ctx),$E
++	add	$SZ*5($ctx),$F
++	add	$SZ*6($ctx),$G
++	add	$SZ*7($ctx),$H
++
++	cmp	$_end,$inp
++
++	mov	$A,$SZ*0($ctx)
++	mov	$B,$SZ*1($ctx)
++	mov	$C,$SZ*2($ctx)
++	mov	$D,$SZ*3($ctx)
++	mov	$E,$SZ*4($ctx)
++	mov	$F,$SZ*5($ctx)
++	mov	$G,$SZ*6($ctx)
++	mov	$H,$SZ*7($ctx)
++	jb	.Lloop_ssse3
++
++	mov	$_rsp,%rsi
++___
++$code.=<<___ if ($win64);
++	movaps	16*$SZ+32(%rsp),%xmm6
++	movaps	16*$SZ+48(%rsp),%xmm7
++	movaps	16*$SZ+64(%rsp),%xmm8
++	movaps	16*$SZ+80(%rsp),%xmm9
++___
++$code.=<<___;
++	mov	(%rsi),%r15
++	mov	8(%rsi),%r14
++	mov	16(%rsi),%r13
++	mov	24(%rsi),%r12
++	mov	32(%rsi),%rbp
++	mov	40(%rsi),%rbx
++	lea	48(%rsi),%rsp
++.Lepilogue_ssse3:
++	ret
++.size	${func}_ssse3,.-${func}_ssse3
++___
++}
++
++if ($avx) {{
++######################################################################
++# XOP code path
++#
++if ($SZ==8) {	# SHA512 only
++$code.=<<___;
++.type	${func}_xop,\@function,3
++.align	64
++${func}_xop:
++.Lxop_shortcut:
++	push	%rbx
++	push	%rbp
++	push	%r12
++	push	%r13
++	push	%r14
++	push	%r15
++	mov	%rsp,%r11		# copy %rsp
++	shl	\$4,%rdx		# num*16
++	sub	\$`$framesz+$win64*16*($SZ==4?4:6)`,%rsp
++	lea	($inp,%rdx,$SZ),%rdx	# inp+num*16*$SZ
++	and	\$-64,%rsp		# align stack frame
++	mov	$ctx,$_ctx		# save ctx, 1st arg
++	mov	$inp,$_inp		# save inp, 2nd arh
++	mov	%rdx,$_end		# save end pointer, "3rd" arg
++	mov	%r11,$_rsp		# save copy of %rsp
++___
++$code.=<<___ if ($win64);
++	movaps	%xmm6,16*$SZ+32(%rsp)
++	movaps	%xmm7,16*$SZ+48(%rsp)
++	movaps	%xmm8,16*$SZ+64(%rsp)
++	movaps	%xmm9,16*$SZ+80(%rsp)
++___
++$code.=<<___ if ($win64 && $SZ>4);
++	movaps	%xmm10,16*$SZ+96(%rsp)
++	movaps	%xmm11,16*$SZ+112(%rsp)
++___
++$code.=<<___;
++.Lprologue_xop:
++
++	vzeroupper
++	mov	$SZ*0($ctx),$A
++	mov	$SZ*1($ctx),$B
++	mov	$SZ*2($ctx),$C
++	mov	$SZ*3($ctx),$D
++	mov	$SZ*4($ctx),$E
++	mov	$SZ*5($ctx),$F
++	mov	$SZ*6($ctx),$G
++	mov	$SZ*7($ctx),$H
++	jmp	.Lloop_xop
++___
++					if ($SZ==4) {	# SHA256
++    my @X = map("%xmm$_",(0..3));
++    my ($t0,$t1,$t2,$t3) = map("%xmm$_",(4..7));
++
++$code.=<<___;
++.align	16
++.Lloop_xop:
++	vmovdqa	$TABLE+`$SZ*2*$rounds`(%rip),$t3
++	vmovdqu	0x00($inp),@X[0]
++	vmovdqu	0x10($inp),@X[1]
++	vmovdqu	0x20($inp),@X[2]
++	vmovdqu	0x30($inp),@X[3]
++	vpshufb	$t3,@X[0],@X[0]
++	lea	$TABLE(%rip),$Tbl
++	vpshufb	$t3,@X[1],@X[1]
++	vpshufb	$t3,@X[2],@X[2]
++	vpaddd	0x00($Tbl),@X[0],$t0
++	vpshufb	$t3,@X[3],@X[3]
++	vpaddd	0x20($Tbl),@X[1],$t1
++	vpaddd	0x40($Tbl),@X[2],$t2
++	vpaddd	0x60($Tbl),@X[3],$t3
++	vmovdqa	$t0,0x00(%rsp)
++	mov	$A,$a1
++	vmovdqa	$t1,0x10(%rsp)
++	mov	$B,$a3
++	vmovdqa	$t2,0x20(%rsp)
++	xor	$C,$a3			# magic
++	vmovdqa	$t3,0x30(%rsp)
++	mov	$E,$a0
++	jmp	.Lxop_00_47
++
++.align	16
++.Lxop_00_47:
++	sub	\$`-16*2*$SZ`,$Tbl	# size optimization
++___
++sub XOP_256_00_47 () {
++my $j = shift;
++my $body = shift;
++my @X = @_;
++my @insns = (&$body,&$body,&$body,&$body);	# 104 instructions
++
++	&vpalignr	($t0,@X[1],@X[0],$SZ);	# X[1..4]
++	  eval(shift(@insns));
++	  eval(shift(@insns));
++	 &vpalignr	($t3,@X[3],@X[2],$SZ);	# X[9..12]
++	  eval(shift(@insns));
++	  eval(shift(@insns));
++	&vprotd		($t1,$t0,8*$SZ-$sigma0[1]);
++	  eval(shift(@insns));
++	  eval(shift(@insns));
++	&vpsrld		($t0,$t0,$sigma0[2]);
++	  eval(shift(@insns));
++	  eval(shift(@insns));
++	 &vpaddd	(@X[0],@X[0],$t3);	# X[0..3] += X[9..12]
++	  eval(shift(@insns));
++	  eval(shift(@insns));
++	  eval(shift(@insns));
++	  eval(shift(@insns));
++	&vprotd		($t2,$t1,$sigma0[1]-$sigma0[0]);
++	  eval(shift(@insns));
++	  eval(shift(@insns));
++	&vpxor		($t0,$t0,$t1);
++	  eval(shift(@insns));
++	  eval(shift(@insns));
++	  eval(shift(@insns));
++	  eval(shift(@insns));
++	 &vprotd	($t3,@X[3],8*$SZ-$sigma1[1]);
++	  eval(shift(@insns));
++	  eval(shift(@insns));
++	&vpxor		($t0,$t0,$t2);		# sigma0(X[1..4])
++	  eval(shift(@insns));
++	  eval(shift(@insns));
++	 &vpsrld	($t2,@X[3],$sigma1[2]);
++	  eval(shift(@insns));
++	  eval(shift(@insns));
++	&vpaddd		(@X[0],@X[0],$t0);	# X[0..3] += sigma0(X[1..4])
++	  eval(shift(@insns));
++	  eval(shift(@insns));
++	 &vprotd	($t1,$t3,$sigma1[1]-$sigma1[0]);
++	  eval(shift(@insns));
++	  eval(shift(@insns));
++	 &vpxor		($t3,$t3,$t2);
++	  eval(shift(@insns));
++	  eval(shift(@insns));
++	  eval(shift(@insns));
++	  eval(shift(@insns));
++	 &vpxor		($t3,$t3,$t1);		# sigma1(X[14..15])
++	  eval(shift(@insns));
++	  eval(shift(@insns));
++	  eval(shift(@insns));
++	  eval(shift(@insns));
++	&vpsrldq	($t3,$t3,8);
++	  eval(shift(@insns));
++	  eval(shift(@insns));
++	  eval(shift(@insns));
++	  eval(shift(@insns));
++	&vpaddd		(@X[0],@X[0],$t3);	# X[0..1] += sigma1(X[14..15])
++	  eval(shift(@insns));
++	  eval(shift(@insns));
++	  eval(shift(@insns));
++	  eval(shift(@insns));
++	 &vprotd	($t3,@X[0],8*$SZ-$sigma1[1]);
++	  eval(shift(@insns));
++	  eval(shift(@insns));
++	 &vpsrld	($t2,@X[0],$sigma1[2]);
++	  eval(shift(@insns));
++	  eval(shift(@insns));
++	 &vprotd	($t1,$t3,$sigma1[1]-$sigma1[0]);
++	  eval(shift(@insns));
++	  eval(shift(@insns));
++	 &vpxor		($t3,$t3,$t2);
++	  eval(shift(@insns));
++	  eval(shift(@insns));
++	  eval(shift(@insns));
++	  eval(shift(@insns));
++	 &vpxor		($t3,$t3,$t1);		# sigma1(X[16..17])
++	  eval(shift(@insns));
++	  eval(shift(@insns));
++	  eval(shift(@insns));
++	  eval(shift(@insns));
++	&vpslldq	($t3,$t3,8);		# 22 instructions
++	  eval(shift(@insns));
++	  eval(shift(@insns));
++	  eval(shift(@insns));
++	  eval(shift(@insns));
++	&vpaddd		(@X[0],@X[0],$t3);	# X[2..3] += sigma1(X[16..17])
++	  eval(shift(@insns));
++	  eval(shift(@insns));
++	  eval(shift(@insns));
++	  eval(shift(@insns));
++	&vpaddd		($t2,@X[0],16*2*$j."($Tbl)");
++	  foreach (@insns) { eval; }		# remaining instructions
++	&vmovdqa	(16*$j."(%rsp)",$t2);
++}
++
++    for ($i=0,$j=0; $j<4; $j++) {
++	&XOP_256_00_47($j,\&body_00_15,@X);
++	push(@X,shift(@X));			# rotate(@X)
++    }
++	&cmpb	($SZ-1+16*2*$SZ."($Tbl)",0);
++	&jne	(".Lxop_00_47");
++
++    for ($i=0; $i<16; ) {
++	foreach(body_00_15()) { eval; }
++    }
++
++					} else {	# SHA512
++    my @X = map("%xmm$_",(0..7));
++    my ($t0,$t1,$t2,$t3) = map("%xmm$_",(8..11));
++
++$code.=<<___;
++.align	16
++.Lloop_xop:
++	vmovdqa	$TABLE+`$SZ*2*$rounds`(%rip),$t3
++	vmovdqu	0x00($inp),@X[0]
++	lea	$TABLE+0x80(%rip),$Tbl	# size optimization
++	vmovdqu	0x10($inp),@X[1]
++	vmovdqu	0x20($inp),@X[2]
++	vpshufb	$t3,@X[0],@X[0]
++	vmovdqu	0x30($inp),@X[3]
++	vpshufb	$t3,@X[1],@X[1]
++	vmovdqu	0x40($inp),@X[4]
++	vpshufb	$t3,@X[2],@X[2]
++	vmovdqu	0x50($inp),@X[5]
++	vpshufb	$t3,@X[3],@X[3]
++	vmovdqu	0x60($inp),@X[6]
++	vpshufb	$t3,@X[4],@X[4]
++	vmovdqu	0x70($inp),@X[7]
++	vpshufb	$t3,@X[5],@X[5]
++	vpaddq	-0x80($Tbl),@X[0],$t0
++	vpshufb	$t3,@X[6],@X[6]
++	vpaddq	-0x60($Tbl),@X[1],$t1
++	vpshufb	$t3,@X[7],@X[7]
++	vpaddq	-0x40($Tbl),@X[2],$t2
++	vpaddq	-0x20($Tbl),@X[3],$t3
++	vmovdqa	$t0,0x00(%rsp)
++	vpaddq	0x00($Tbl),@X[4],$t0
++	vmovdqa	$t1,0x10(%rsp)
++	vpaddq	0x20($Tbl),@X[5],$t1
++	vmovdqa	$t2,0x20(%rsp)
++	vpaddq	0x40($Tbl),@X[6],$t2
++	vmovdqa	$t3,0x30(%rsp)
++	vpaddq	0x60($Tbl),@X[7],$t3
++	vmovdqa	$t0,0x40(%rsp)
++	mov	$A,$a1
++	vmovdqa	$t1,0x50(%rsp)
++	mov	$B,$a3
++	vmovdqa	$t2,0x60(%rsp)
++	xor	$C,$a3			# magic
++	vmovdqa	$t3,0x70(%rsp)
++	mov	$E,$a0
++	jmp	.Lxop_00_47
++
++.align	16
++.Lxop_00_47:
++	add	\$`16*2*$SZ`,$Tbl
++___
++sub XOP_512_00_47 () {
++my $j = shift;
++my $body = shift;
++my @X = @_;
++my @insns = (&$body,&$body);			# 52 instructions
++
++	&vpalignr	($t0,@X[1],@X[0],$SZ);	# X[1..2]
++	  eval(shift(@insns));
++	  eval(shift(@insns));
++	 &vpalignr	($t3,@X[5],@X[4],$SZ);	# X[9..10]
++	  eval(shift(@insns));
++	  eval(shift(@insns));
++	&vprotq		($t1,$t0,8*$SZ-$sigma0[1]);
++	  eval(shift(@insns));
++	  eval(shift(@insns));
++	&vpsrlq		($t0,$t0,$sigma0[2]);
++	  eval(shift(@insns));
++	  eval(shift(@insns));
++	 &vpaddq	(@X[0],@X[0],$t3);	# X[0..1] += X[9..10]
++	  eval(shift(@insns));
++	  eval(shift(@insns));
++	  eval(shift(@insns));
++	  eval(shift(@insns));
++	&vprotq		($t2,$t1,$sigma0[1]-$sigma0[0]);
++	  eval(shift(@insns));
++	  eval(shift(@insns));
++	&vpxor		($t0,$t0,$t1);
++	  eval(shift(@insns));
++	  eval(shift(@insns));
++	  eval(shift(@insns));
++	  eval(shift(@insns));
++	 &vprotq	($t3,@X[7],8*$SZ-$sigma1[1]);
++	  eval(shift(@insns));
++	  eval(shift(@insns));
++	&vpxor		($t0,$t0,$t2);		# sigma0(X[1..2])
++	  eval(shift(@insns));
++	  eval(shift(@insns));
++	 &vpsrlq	($t2,@X[7],$sigma1[2]);
++	  eval(shift(@insns));
++	  eval(shift(@insns));
++	&vpaddq		(@X[0],@X[0],$t0);	# X[0..1] += sigma0(X[1..2])
++	  eval(shift(@insns));
++	  eval(shift(@insns));
++	 &vprotq	($t1,$t3,$sigma1[1]-$sigma1[0]);
++	  eval(shift(@insns));
++	  eval(shift(@insns));
++	 &vpxor		($t3,$t3,$t2);
++	  eval(shift(@insns));
++	  eval(shift(@insns));
++	  eval(shift(@insns));
++	  eval(shift(@insns));
++	 &vpxor		($t3,$t3,$t1);		# sigma1(X[14..15])
++	  eval(shift(@insns));
++	  eval(shift(@insns));
++	  eval(shift(@insns));
++	  eval(shift(@insns));
++	&vpaddq		(@X[0],@X[0],$t3);	# X[0..1] += sigma1(X[14..15])
++	  eval(shift(@insns));
++	  eval(shift(@insns));
++	  eval(shift(@insns));
++	  eval(shift(@insns));
++	&vpaddq		($t2,@X[0],16*2*$j-0x80."($Tbl)");
++	  foreach (@insns) { eval; }		# remaining instructions
++	&vmovdqa	(16*$j."(%rsp)",$t2);
++}
++
++    for ($i=0,$j=0; $j<8; $j++) {
++	&XOP_512_00_47($j,\&body_00_15,@X);
++	push(@X,shift(@X));			# rotate(@X)
++    }
++	&cmpb	($SZ-1+16*2*$SZ-0x80."($Tbl)",0);
++	&jne	(".Lxop_00_47");
++
++    for ($i=0; $i<16; ) {
++	foreach(body_00_15()) { eval; }
++    }
++}
++$code.=<<___;
++	mov	$_ctx,$ctx
++	mov	$a1,$A
++
++	add	$SZ*0($ctx),$A
++	lea	16*$SZ($inp),$inp
++	add	$SZ*1($ctx),$B
++	add	$SZ*2($ctx),$C
++	add	$SZ*3($ctx),$D
++	add	$SZ*4($ctx),$E
++	add	$SZ*5($ctx),$F
++	add	$SZ*6($ctx),$G
++	add	$SZ*7($ctx),$H
++
++	cmp	$_end,$inp
++
++	mov	$A,$SZ*0($ctx)
++	mov	$B,$SZ*1($ctx)
++	mov	$C,$SZ*2($ctx)
++	mov	$D,$SZ*3($ctx)
++	mov	$E,$SZ*4($ctx)
++	mov	$F,$SZ*5($ctx)
++	mov	$G,$SZ*6($ctx)
++	mov	$H,$SZ*7($ctx)
++	jb	.Lloop_xop
++
++	mov	$_rsp,%rsi
++	vzeroupper
++___
++$code.=<<___ if ($win64);
++	movaps	16*$SZ+32(%rsp),%xmm6
++	movaps	16*$SZ+48(%rsp),%xmm7
++	movaps	16*$SZ+64(%rsp),%xmm8
++	movaps	16*$SZ+80(%rsp),%xmm9
++___
++$code.=<<___ if ($win64 && $SZ>4);
++	movaps	16*$SZ+96(%rsp),%xmm10
++	movaps	16*$SZ+112(%rsp),%xmm11
++___
++$code.=<<___;
++	mov	(%rsi),%r15
++	mov	8(%rsi),%r14
++	mov	16(%rsi),%r13
++	mov	24(%rsi),%r12
++	mov	32(%rsi),%rbp
++	mov	40(%rsi),%rbx
++	lea	48(%rsi),%rsp
++.Lepilogue_xop:
++	ret
++.size	${func}_xop,.-${func}_xop
++___
++}
++######################################################################
++# AVX+shrd code path
++#
++local *ror = sub { &shrd(@_[0],@_) };
++
++$code.=<<___;
++.type	${func}_avx,\@function,3
++.align	64
++${func}_avx:
++.Lavx_shortcut:
++	push	%rbx
++	push	%rbp
++	push	%r12
++	push	%r13
++	push	%r14
++	push	%r15
++	mov	%rsp,%r11		# copy %rsp
++	shl	\$4,%rdx		# num*16
++	sub	\$`$framesz+$win64*16*($SZ==4?4:6)`,%rsp
++	lea	($inp,%rdx,$SZ),%rdx	# inp+num*16*$SZ
++	and	\$-64,%rsp		# align stack frame
++	mov	$ctx,$_ctx		# save ctx, 1st arg
++	mov	$inp,$_inp		# save inp, 2nd arh
++	mov	%rdx,$_end		# save end pointer, "3rd" arg
++	mov	%r11,$_rsp		# save copy of %rsp
++___
++$code.=<<___ if ($win64);
++	movaps	%xmm6,16*$SZ+32(%rsp)
++	movaps	%xmm7,16*$SZ+48(%rsp)
++	movaps	%xmm8,16*$SZ+64(%rsp)
++	movaps	%xmm9,16*$SZ+80(%rsp)
++___
++$code.=<<___ if ($win64 && $SZ>4);
++	movaps	%xmm10,16*$SZ+96(%rsp)
++	movaps	%xmm11,16*$SZ+112(%rsp)
++___
++$code.=<<___;
++.Lprologue_avx:
++
++	vzeroupper
++	mov	$SZ*0($ctx),$A
++	mov	$SZ*1($ctx),$B
++	mov	$SZ*2($ctx),$C
++	mov	$SZ*3($ctx),$D
++	mov	$SZ*4($ctx),$E
++	mov	$SZ*5($ctx),$F
++	mov	$SZ*6($ctx),$G
++	mov	$SZ*7($ctx),$H
++___
++					if ($SZ==4) {	# SHA256
++    my @X = map("%xmm$_",(0..3));
++    my ($t0,$t1,$t2,$t3, $t4,$t5) = map("%xmm$_",(4..9));
++
++$code.=<<___;
++	vmovdqa	$TABLE+`$SZ*2*$rounds`+32(%rip),$t4
++	vmovdqa	$TABLE+`$SZ*2*$rounds`+64(%rip),$t5
++	jmp	.Lloop_avx
++.align	16
++.Lloop_avx:
++	vmovdqa	$TABLE+`$SZ*2*$rounds`(%rip),$t3
++	vmovdqu	0x00($inp),@X[0]
++	vmovdqu	0x10($inp),@X[1]
++	vmovdqu	0x20($inp),@X[2]
++	vmovdqu	0x30($inp),@X[3]
++	vpshufb	$t3,@X[0],@X[0]
++	lea	$TABLE(%rip),$Tbl
++	vpshufb	$t3,@X[1],@X[1]
++	vpshufb	$t3,@X[2],@X[2]
++	vpaddd	0x00($Tbl),@X[0],$t0
++	vpshufb	$t3,@X[3],@X[3]
++	vpaddd	0x20($Tbl),@X[1],$t1
++	vpaddd	0x40($Tbl),@X[2],$t2
++	vpaddd	0x60($Tbl),@X[3],$t3
++	vmovdqa	$t0,0x00(%rsp)
++	mov	$A,$a1
++	vmovdqa	$t1,0x10(%rsp)
++	mov	$B,$a3
++	vmovdqa	$t2,0x20(%rsp)
++	xor	$C,$a3			# magic
++	vmovdqa	$t3,0x30(%rsp)
++	mov	$E,$a0
++	jmp	.Lavx_00_47
++
++.align	16
++.Lavx_00_47:
++	sub	\$`-16*2*$SZ`,$Tbl	# size optimization
++___
++sub Xupdate_256_AVX () {
++	(
++	'&vpalignr	($t0,@X[1],@X[0],$SZ)',	# X[1..4]
++	 '&vpalignr	($t3,@X[3],@X[2],$SZ)',	# X[9..12]
++	'&vpsrld	($t2,$t0,$sigma0[0]);',
++	 '&vpaddd	(@X[0],@X[0],$t3)',	# X[0..3] += X[9..12]
++	'&vpsrld	($t3,$t0,$sigma0[2])',
++	'&vpslld	($t1,$t0,8*$SZ-$sigma0[1]);',
++	'&vpxor		($t0,$t3,$t2)',
++	 '&vpshufd	($t3,@X[3],0b11111010)',# X[14..15]
++	'&vpsrld	($t2,$t2,$sigma0[1]-$sigma0[0]);',
++	'&vpxor		($t0,$t0,$t1)',
++	'&vpslld	($t1,$t1,$sigma0[1]-$sigma0[0]);',
++	'&vpxor		($t0,$t0,$t2)',
++	 '&vpsrld	($t2,$t3,$sigma1[2]);',
++	'&vpxor		($t0,$t0,$t1)',		# sigma0(X[1..4])
++	 '&vpsrlq	($t3,$t3,$sigma1[0]);',
++	'&vpaddd	(@X[0],@X[0],$t0)',	# X[0..3] += sigma0(X[1..4])
++	 '&vpxor	($t2,$t2,$t3);',
++	 '&vpsrlq	($t3,$t3,$sigma1[1]-$sigma1[0])',
++	 '&vpxor	($t2,$t2,$t3)',
++	 '&vpshufb	($t2,$t2,$t4)',		# sigma1(X[14..15])
++	'&vpaddd	(@X[0],@X[0],$t2)',	# X[0..1] += sigma1(X[14..15])
++	 '&vpshufd	($t3,@X[0],0b01010000)',# X[16..17]
++	 '&vpsrld	($t2,$t3,$sigma1[2])',
++	 '&vpsrlq	($t3,$t3,$sigma1[0])',
++	 '&vpxor	($t2,$t2,$t3);',
++	 '&vpsrlq	($t3,$t3,$sigma1[1]-$sigma1[0])',
++	 '&vpxor	($t2,$t2,$t3)',
++	 '&vpshufb	($t2,$t2,$t5)',
++	'&vpaddd	(@X[0],@X[0],$t2)'	# X[2..3] += sigma1(X[16..17])
++	);
++}
++
++sub AVX_256_00_47 () {
++my $j = shift;
++my $body = shift;
++my @X = @_;
++my @insns = (&$body,&$body,&$body,&$body);	# 104 instructions
++
++	foreach (Xupdate_256_AVX()) {		# 29 instructions
++	    eval;
++	    eval(shift(@insns));
++	    eval(shift(@insns));
++	    eval(shift(@insns));
++	}
++	&vpaddd		($t2,@X[0],16*2*$j."($Tbl)");
++	  foreach (@insns) { eval; }		# remaining instructions
++	&vmovdqa	(16*$j."(%rsp)",$t2);
++}
++
++    for ($i=0,$j=0; $j<4; $j++) {
++	&AVX_256_00_47($j,\&body_00_15,@X);
++	push(@X,shift(@X));			# rotate(@X)
++    }
++	&cmpb	($SZ-1+16*2*$SZ."($Tbl)",0);
++	&jne	(".Lavx_00_47");
++
++    for ($i=0; $i<16; ) {
++	foreach(body_00_15()) { eval; }
++    }
++
++					} else {	# SHA512
++    my @X = map("%xmm$_",(0..7));
++    my ($t0,$t1,$t2,$t3) = map("%xmm$_",(8..11));
++
++$code.=<<___;
++	jmp	.Lloop_avx
++.align	16
++.Lloop_avx:
++	vmovdqa	$TABLE+`$SZ*2*$rounds`(%rip),$t3
++	vmovdqu	0x00($inp),@X[0]
++	lea	$TABLE+0x80(%rip),$Tbl	# size optimization
++	vmovdqu	0x10($inp),@X[1]
++	vmovdqu	0x20($inp),@X[2]
++	vpshufb	$t3,@X[0],@X[0]
++	vmovdqu	0x30($inp),@X[3]
++	vpshufb	$t3,@X[1],@X[1]
++	vmovdqu	0x40($inp),@X[4]
++	vpshufb	$t3,@X[2],@X[2]
++	vmovdqu	0x50($inp),@X[5]
++	vpshufb	$t3,@X[3],@X[3]
++	vmovdqu	0x60($inp),@X[6]
++	vpshufb	$t3,@X[4],@X[4]
++	vmovdqu	0x70($inp),@X[7]
++	vpshufb	$t3,@X[5],@X[5]
++	vpaddq	-0x80($Tbl),@X[0],$t0
++	vpshufb	$t3,@X[6],@X[6]
++	vpaddq	-0x60($Tbl),@X[1],$t1
++	vpshufb	$t3,@X[7],@X[7]
++	vpaddq	-0x40($Tbl),@X[2],$t2
++	vpaddq	-0x20($Tbl),@X[3],$t3
++	vmovdqa	$t0,0x00(%rsp)
++	vpaddq	0x00($Tbl),@X[4],$t0
++	vmovdqa	$t1,0x10(%rsp)
++	vpaddq	0x20($Tbl),@X[5],$t1
++	vmovdqa	$t2,0x20(%rsp)
++	vpaddq	0x40($Tbl),@X[6],$t2
++	vmovdqa	$t3,0x30(%rsp)
++	vpaddq	0x60($Tbl),@X[7],$t3
++	vmovdqa	$t0,0x40(%rsp)
++	mov	$A,$a1
++	vmovdqa	$t1,0x50(%rsp)
++	mov	$B,$a3
++	vmovdqa	$t2,0x60(%rsp)
++	xor	$C,$a3			# magic
++	vmovdqa	$t3,0x70(%rsp)
++	mov	$E,$a0
++	jmp	.Lavx_00_47
++
++.align	16
++.Lavx_00_47:
++	add	\$`16*2*$SZ`,$Tbl
++___
++sub Xupdate_512_AVX () {
++	(
++	'&vpalignr	($t0,@X[1],@X[0],$SZ)',	# X[1..2]
++	 '&vpalignr	($t3,@X[5],@X[4],$SZ)',	# X[9..10]
++	'&vpsrlq	($t2,$t0,$sigma0[0])',
++	 '&vpaddq	(@X[0],@X[0],$t3);',	# X[0..1] += X[9..10]
++	'&vpsrlq	($t3,$t0,$sigma0[2])',
++	'&vpsllq	($t1,$t0,8*$SZ-$sigma0[1]);',
++	 '&vpxor	($t0,$t3,$t2)',
++	'&vpsrlq	($t2,$t2,$sigma0[1]-$sigma0[0]);',
++	 '&vpxor	($t0,$t0,$t1)',
++	'&vpsllq	($t1,$t1,$sigma0[1]-$sigma0[0]);',
++	 '&vpxor	($t0,$t0,$t2)',
++	 '&vpsrlq	($t3,@X[7],$sigma1[2]);',
++	'&vpxor		($t0,$t0,$t1)',		# sigma0(X[1..2])
++	 '&vpsllq	($t2,@X[7],8*$SZ-$sigma1[1]);',
++	'&vpaddq	(@X[0],@X[0],$t0)',	# X[0..1] += sigma0(X[1..2])
++	 '&vpsrlq	($t1,@X[7],$sigma1[0]);',
++	 '&vpxor	($t3,$t3,$t2)',
++	 '&vpsllq	($t2,$t2,$sigma1[1]-$sigma1[0]);',
++	 '&vpxor	($t3,$t3,$t1)',
++	 '&vpsrlq	($t1,$t1,$sigma1[1]-$sigma1[0]);',
++	 '&vpxor	($t3,$t3,$t2)',
++	 '&vpxor	($t3,$t3,$t1)',		# sigma1(X[14..15])
++	'&vpaddq	(@X[0],@X[0],$t3)',	# X[0..1] += sigma1(X[14..15])
++	);
++}
++
++sub AVX_512_00_47 () {
++my $j = shift;
++my $body = shift;
++my @X = @_;
++my @insns = (&$body,&$body);			# 52 instructions
++
++	foreach (Xupdate_512_AVX()) {		# 23 instructions
++	    eval;
++	    eval(shift(@insns));
++	    eval(shift(@insns));
++	}
++	&vpaddq		($t2,@X[0],16*2*$j-0x80."($Tbl)");
++	  foreach (@insns) { eval; }		# remaining instructions
++	&vmovdqa	(16*$j."(%rsp)",$t2);
++}
++
++    for ($i=0,$j=0; $j<8; $j++) {
++	&AVX_512_00_47($j,\&body_00_15,@X);
++	push(@X,shift(@X));			# rotate(@X)
++    }
++	&cmpb	($SZ-1+16*2*$SZ-0x80."($Tbl)",0);
++	&jne	(".Lavx_00_47");
++
++    for ($i=0; $i<16; ) {
++	foreach(body_00_15()) { eval; }
++    }
++}
++$code.=<<___;
++	mov	$_ctx,$ctx
++	mov	$a1,$A
++
++	add	$SZ*0($ctx),$A
++	lea	16*$SZ($inp),$inp
++	add	$SZ*1($ctx),$B
++	add	$SZ*2($ctx),$C
++	add	$SZ*3($ctx),$D
++	add	$SZ*4($ctx),$E
++	add	$SZ*5($ctx),$F
++	add	$SZ*6($ctx),$G
++	add	$SZ*7($ctx),$H
++
++	cmp	$_end,$inp
++
++	mov	$A,$SZ*0($ctx)
++	mov	$B,$SZ*1($ctx)
++	mov	$C,$SZ*2($ctx)
++	mov	$D,$SZ*3($ctx)
++	mov	$E,$SZ*4($ctx)
++	mov	$F,$SZ*5($ctx)
++	mov	$G,$SZ*6($ctx)
++	mov	$H,$SZ*7($ctx)
++	jb	.Lloop_avx
++
++	mov	$_rsp,%rsi
++	vzeroupper
++___
++$code.=<<___ if ($win64);
++	movaps	16*$SZ+32(%rsp),%xmm6
++	movaps	16*$SZ+48(%rsp),%xmm7
++	movaps	16*$SZ+64(%rsp),%xmm8
++	movaps	16*$SZ+80(%rsp),%xmm9
++___
++$code.=<<___ if ($win64 && $SZ>4);
++	movaps	16*$SZ+96(%rsp),%xmm10
++	movaps	16*$SZ+112(%rsp),%xmm11
++___
++$code.=<<___;
++	mov	(%rsi),%r15
++	mov	8(%rsi),%r14
++	mov	16(%rsi),%r13
++	mov	24(%rsi),%r12
++	mov	32(%rsi),%rbp
++	mov	40(%rsi),%rbx
++	lea	48(%rsi),%rsp
++.Lepilogue_avx:
++	ret
++.size	${func}_avx,.-${func}_avx
++___
++
++if ($avx>1) {{
++######################################################################
++# AVX2+BMI code path
++#
++my $a5=$SZ==4?"%esi":"%rsi";	# zap $inp 
++my $PUSH8=8*2*$SZ;
++use integer;
++
++sub bodyx_00_15 () {
++	# at start $a1 should be zero, $a3 - $b^$c and $a4 copy of $f
++	(
++	'($a,$b,$c,$d,$e,$f,$g,$h)=@ROT;'.
++
++	'&add	($h,(32*($i/(16/$SZ))+$SZ*($i%(16/$SZ)))%$PUSH8.$base)',    # h+=X[i]+K[i]
++	'&and	($a4,$e)',		# f&e
++	'&rorx	($a0,$e,$Sigma1[2])',
++	'&rorx	($a2,$e,$Sigma1[1])',
++
++	'&lea	($a,"($a,$a1)")',	# h+=Sigma0(a) from the past
++	'&lea	($h,"($h,$a4)")',
++	'&andn	($a4,$e,$g)',		# ~e&g
++	'&xor	($a0,$a2)',
++
++	'&rorx	($a1,$e,$Sigma1[0])',
++	'&lea	($h,"($h,$a4)")',	# h+=Ch(e,f,g)=(e&f)+(~e&g)
++	'&xor	($a0,$a1)',		# Sigma1(e)
++	'&mov	($a2,$a)',
++
++	'&rorx	($a4,$a,$Sigma0[2])',
++	'&lea	($h,"($h,$a0)")',	# h+=Sigma1(e)
++	'&xor	($a2,$b)',		# a^b, b^c in next round
++	'&rorx	($a1,$a,$Sigma0[1])',
++
++	'&rorx	($a0,$a,$Sigma0[0])',
++	'&lea	($d,"($d,$h)")',	# d+=h
++	'&and	($a3,$a2)',		# (b^c)&(a^b)
++	'&xor	($a1,$a4)',
++
++	'&xor	($a3,$b)',		# Maj(a,b,c)=Ch(a^b,c,b)
++	'&xor	($a1,$a0)',		# Sigma0(a)
++	'&lea	($h,"($h,$a3)");'.	# h+=Maj(a,b,c)
++	'&mov	($a4,$e)',		# copy of f in future
++
++	'($a2,$a3) = ($a3,$a2); unshift(@ROT,pop(@ROT)); $i++;'
++	);
++	# and at the finish one has to $a+=$a1
++}
++
++$code.=<<___;
++.type	${func}_avx2,\@function,3
++.align	64
++${func}_avx2:
++.Lavx2_shortcut:
++	push	%rbx
++	push	%rbp
++	push	%r12
++	push	%r13
++	push	%r14
++	push	%r15
++	mov	%rsp,%r11		# copy %rsp
++	sub	\$`2*$SZ*$rounds+4*8+$win64*16*($SZ==4?4:6)`,%rsp
++	shl	\$4,%rdx		# num*16
++	and	\$-256*$SZ,%rsp		# align stack frame
++	lea	($inp,%rdx,$SZ),%rdx	# inp+num*16*$SZ
++	add	\$`2*$SZ*($rounds-8)`,%rsp
++	mov	$ctx,$_ctx		# save ctx, 1st arg
++	mov	$inp,$_inp		# save inp, 2nd arh
++	mov	%rdx,$_end		# save end pointer, "3rd" arg
++	mov	%r11,$_rsp		# save copy of %rsp
++___
++$code.=<<___ if ($win64);
++	movaps	%xmm6,16*$SZ+32(%rsp)
++	movaps	%xmm7,16*$SZ+48(%rsp)
++	movaps	%xmm8,16*$SZ+64(%rsp)
++	movaps	%xmm9,16*$SZ+80(%rsp)
++___
++$code.=<<___ if ($win64 && $SZ>4);
++	movaps	%xmm10,16*$SZ+96(%rsp)
++	movaps	%xmm11,16*$SZ+112(%rsp)
++___
++$code.=<<___;
++.Lprologue_avx2:
++
++	vzeroupper
++	sub	\$-16*$SZ,$inp		# inp++, size optimization
++	mov	$SZ*0($ctx),$A
++	mov	$inp,%r12		# borrow $T1
++	mov	$SZ*1($ctx),$B
++	cmp	%rdx,$inp		# $_end
++	mov	$SZ*2($ctx),$C
++	cmove	%rsp,%r12		# next block or random data
++	mov	$SZ*3($ctx),$D
++	mov	$SZ*4($ctx),$E
++	mov	$SZ*5($ctx),$F
++	mov	$SZ*6($ctx),$G
++	mov	$SZ*7($ctx),$H
++___
++					if ($SZ==4) {	# SHA256
++    my @X = map("%ymm$_",(0..3));
++    my ($t0,$t1,$t2,$t3, $t4,$t5) = map("%ymm$_",(4..9));
++
++$code.=<<___;
++	vmovdqa	$TABLE+`$SZ*2*$rounds`+32(%rip),$t4
++	vmovdqa	$TABLE+`$SZ*2*$rounds`+64(%rip),$t5
++	jmp	.Loop_avx2
++.align	16
++.Loop_avx2:
++	vmovdqa	$TABLE+`$SZ*2*$rounds`(%rip),$t3
++	vmovdqu	-16*$SZ+0($inp),%xmm0
++	vmovdqu	-16*$SZ+16($inp),%xmm1
++	vmovdqu	-16*$SZ+32($inp),%xmm2
++	vmovdqu	-16*$SZ+48($inp),%xmm3
++	#mov		$inp,$_inp	# offload $inp
++	vinserti128	\$1,(%r12),@X[0],@X[0]
++	vinserti128	\$1,16(%r12),@X[1],@X[1]
++	vpshufb		$t3,@X[0],@X[0]
++	vinserti128	\$1,32(%r12),@X[2],@X[2]
++	vpshufb		$t3,@X[1],@X[1]
++	vinserti128	\$1,48(%r12),@X[3],@X[3]
++
++	lea	$TABLE(%rip),$Tbl
++	vpshufb	$t3,@X[2],@X[2]
++	vpaddd	0x00($Tbl),@X[0],$t0
++	vpshufb	$t3,@X[3],@X[3]
++	vpaddd	0x20($Tbl),@X[1],$t1
++	vpaddd	0x40($Tbl),@X[2],$t2
++	vpaddd	0x60($Tbl),@X[3],$t3
++	vmovdqa	$t0,0x00(%rsp)
++	xor	$a1,$a1
++	vmovdqa	$t1,0x20(%rsp)
++	lea	-$PUSH8(%rsp),%rsp
++	mov	$B,$a3
++	vmovdqa	$t2,0x00(%rsp)
++	xor	$C,$a3			# magic
++	vmovdqa	$t3,0x20(%rsp)
++	mov	$F,$a4
++	sub	\$-16*2*$SZ,$Tbl	# size optimization
++	jmp	.Lavx2_00_47
++
++.align	16
++.Lavx2_00_47:
++___
++
++sub AVX2_256_00_47 () {
++my $j = shift;
++my $body = shift;
++my @X = @_;
++my @insns = (&$body,&$body,&$body,&$body);	# 96 instructions
++my $base = "+2*$PUSH8(%rsp)";
++
++	&lea	("%rsp","-$PUSH8(%rsp)")	if (($j%2)==0);
++	foreach (Xupdate_256_AVX()) {		# 29 instructions
++	    eval;
++	    eval(shift(@insns));
++	    eval(shift(@insns));
++	    eval(shift(@insns));
++	}
++	&vpaddd		($t2,@X[0],16*2*$j."($Tbl)");
++	  foreach (@insns) { eval; }		# remaining instructions
++	&vmovdqa	((32*$j)%$PUSH8."(%rsp)",$t2);
++}
++
++    for ($i=0,$j=0; $j<4; $j++) {
++	&AVX2_256_00_47($j,\&bodyx_00_15,@X);
++	push(@X,shift(@X));			# rotate(@X)
++    }
++	&lea	($Tbl,16*2*$SZ."($Tbl)");
++	&cmpb	(($SZ-1)."($Tbl)",0);
++	&jne	(".Lavx2_00_47");
++
++    for ($i=0; $i<16; ) {
++	my $base=$i<8?"+$PUSH8(%rsp)":"(%rsp)";
++	foreach(bodyx_00_15()) { eval; }
++    }
++					} else {	# SHA512
++    my @X = map("%ymm$_",(0..7));
++    my ($t0,$t1,$t2,$t3) = map("%ymm$_",(8..11));
++
++$code.=<<___;
++	jmp	.Loop_avx2
++.align	16
++.Loop_avx2:
++	vmovdqu	-16*$SZ($inp),%xmm0
++	vmovdqu	-16*$SZ+16($inp),%xmm1
++	vmovdqu	-16*$SZ+32($inp),%xmm2
++	lea	$TABLE+0x80(%rip),$Tbl	# size optimization
++	vmovdqu	-16*$SZ+48($inp),%xmm3
++	vmovdqu	-16*$SZ+64($inp),%xmm4
++	vmovdqu	-16*$SZ+80($inp),%xmm5
++	vmovdqu	-16*$SZ+96($inp),%xmm6
++	vmovdqu	-16*$SZ+112($inp),%xmm7
++	#mov	$inp,$_inp	# offload $inp
++	vmovdqa	`$SZ*2*$rounds-0x80`($Tbl),$t2
++	vinserti128	\$1,(%r12),@X[0],@X[0]
++	vinserti128	\$1,16(%r12),@X[1],@X[1]
++	 vpshufb	$t2,@X[0],@X[0]
++	vinserti128	\$1,32(%r12),@X[2],@X[2]
++	 vpshufb	$t2,@X[1],@X[1]
++	vinserti128	\$1,48(%r12),@X[3],@X[3]
++	 vpshufb	$t2,@X[2],@X[2]
++	vinserti128	\$1,64(%r12),@X[4],@X[4]
++	 vpshufb	$t2,@X[3],@X[3]
++	vinserti128	\$1,80(%r12),@X[5],@X[5]
++	 vpshufb	$t2,@X[4],@X[4]
++	vinserti128	\$1,96(%r12),@X[6],@X[6]
++	 vpshufb	$t2,@X[5],@X[5]
++	vinserti128	\$1,112(%r12),@X[7],@X[7]
++
++	vpaddq	-0x80($Tbl),@X[0],$t0
++	vpshufb	$t2,@X[6],@X[6]
++	vpaddq	-0x60($Tbl),@X[1],$t1
++	vpshufb	$t2,@X[7],@X[7]
++	vpaddq	-0x40($Tbl),@X[2],$t2
++	vpaddq	-0x20($Tbl),@X[3],$t3
++	vmovdqa	$t0,0x00(%rsp)
++	vpaddq	0x00($Tbl),@X[4],$t0
++	vmovdqa	$t1,0x20(%rsp)
++	vpaddq	0x20($Tbl),@X[5],$t1
++	vmovdqa	$t2,0x40(%rsp)
++	vpaddq	0x40($Tbl),@X[6],$t2
++	vmovdqa	$t3,0x60(%rsp)
++	lea	-$PUSH8(%rsp),%rsp
++	vpaddq	0x60($Tbl),@X[7],$t3
++	vmovdqa	$t0,0x00(%rsp)
++	xor	$a1,$a1
++	vmovdqa	$t1,0x20(%rsp)
++	mov	$B,$a3
++	vmovdqa	$t2,0x40(%rsp)
++	xor	$C,$a3			# magic
++	vmovdqa	$t3,0x60(%rsp)
++	mov	$F,$a4
++	add	\$16*2*$SZ,$Tbl
++	jmp	.Lavx2_00_47
++
++.align	16
++.Lavx2_00_47:
++___
++
++sub AVX2_512_00_47 () {
++my $j = shift;
++my $body = shift;
++my @X = @_;
++my @insns = (&$body,&$body);			# 48 instructions
++my $base = "+2*$PUSH8(%rsp)";
++
++	&lea	("%rsp","-$PUSH8(%rsp)")	if (($j%4)==0);
++	foreach (Xupdate_512_AVX()) {		# 23 instructions
++	    eval;
++	    if ($_ !~ /\;$/) {
++		eval(shift(@insns));
++		eval(shift(@insns));
++		eval(shift(@insns));
++	    }
++	}
++	&vpaddq		($t2,@X[0],16*2*$j-0x80."($Tbl)");
++	  foreach (@insns) { eval; }		# remaining instructions
++	&vmovdqa	((32*$j)%$PUSH8."(%rsp)",$t2);
++}
++
++    for ($i=0,$j=0; $j<8; $j++) {
++	&AVX2_512_00_47($j,\&bodyx_00_15,@X);
++	push(@X,shift(@X));			# rotate(@X)
++    }
++	&lea	($Tbl,16*2*$SZ."($Tbl)");
++	&cmpb	(($SZ-1-0x80)."($Tbl)",0);
++	&jne	(".Lavx2_00_47");
++
++    for ($i=0; $i<16; ) {
++	my $base=$i<8?"+$PUSH8(%rsp)":"(%rsp)";
++	foreach(bodyx_00_15()) { eval; }
++    }
++}
++$code.=<<___;
++	mov	`2*$SZ*$rounds`(%rsp),$ctx	# $_ctx
++	add	$a1,$A
++	#mov	`2*$SZ*$rounds+8`(%rsp),$inp	# $_inp
++	lea	`2*$SZ*($rounds-8)`(%rsp),$Tbl
++
++	add	$SZ*0($ctx),$A
++	add	$SZ*1($ctx),$B
++	add	$SZ*2($ctx),$C
++	add	$SZ*3($ctx),$D
++	add	$SZ*4($ctx),$E
++	add	$SZ*5($ctx),$F
++	add	$SZ*6($ctx),$G
++	add	$SZ*7($ctx),$H
++
++	mov	$A,$SZ*0($ctx)
++	mov	$B,$SZ*1($ctx)
++	mov	$C,$SZ*2($ctx)
++	mov	$D,$SZ*3($ctx)
++	mov	$E,$SZ*4($ctx)
++	mov	$F,$SZ*5($ctx)
++	mov	$G,$SZ*6($ctx)
++	mov	$H,$SZ*7($ctx)
++
++	cmp	`$PUSH8+2*8`($Tbl),$inp	# $_end
++	je	.Ldone_avx2
++
++	xor	$a1,$a1
++	mov	$B,$a3
++	xor	$C,$a3			# magic
++	mov	$F,$a4
++	jmp	.Lower_avx2
++.align	16
++.Lower_avx2:
++___
++    for ($i=0; $i<8; ) {
++	my $base="+16($Tbl)";
++	foreach(bodyx_00_15()) { eval; }
++    }
++$code.=<<___;
++	lea	-$PUSH8($Tbl),$Tbl
++	cmp	%rsp,$Tbl
++	jae	.Lower_avx2
++
++	mov	`2*$SZ*$rounds`(%rsp),$ctx	# $_ctx
++	add	$a1,$A
++	#mov	`2*$SZ*$rounds+8`(%rsp),$inp	# $_inp
++	lea	`2*$SZ*($rounds-8)`(%rsp),%rsp
++
++	add	$SZ*0($ctx),$A
++	add	$SZ*1($ctx),$B
++	add	$SZ*2($ctx),$C
++	add	$SZ*3($ctx),$D
++	add	$SZ*4($ctx),$E
++	add	$SZ*5($ctx),$F
++	lea	`2*16*$SZ`($inp),$inp	# inp+=2
++	add	$SZ*6($ctx),$G
++	mov	$inp,%r12
++	add	$SZ*7($ctx),$H
++	cmp	$_end,$inp
++
++	mov	$A,$SZ*0($ctx)
++	cmove	%rsp,%r12		# next block or stale data
++	mov	$B,$SZ*1($ctx)
++	mov	$C,$SZ*2($ctx)
++	mov	$D,$SZ*3($ctx)
++	mov	$E,$SZ*4($ctx)
++	mov	$F,$SZ*5($ctx)
++	mov	$G,$SZ*6($ctx)
++	mov	$H,$SZ*7($ctx)
++
++	jbe	.Loop_avx2
++	lea	(%rsp),$Tbl
++
++.Ldone_avx2:
++	lea	($Tbl),%rsp
++	mov	$_rsp,%rsi
++	vzeroupper
++___
++$code.=<<___ if ($win64);
++	movaps	16*$SZ+32(%rsp),%xmm6
++	movaps	16*$SZ+48(%rsp),%xmm7
++	movaps	16*$SZ+64(%rsp),%xmm8
++	movaps	16*$SZ+80(%rsp),%xmm9
++___
++$code.=<<___ if ($win64 && $SZ>4);
++	movaps	16*$SZ+96(%rsp),%xmm10
++	movaps	16*$SZ+112(%rsp),%xmm11
++___
++$code.=<<___;
++	mov	(%rsi),%r15
++	mov	8(%rsi),%r14
++	mov	16(%rsi),%r13
++	mov	24(%rsi),%r12
++	mov	32(%rsi),%rbp
++	mov	40(%rsi),%rbx
++	lea	48(%rsi),%rsp
++.Lepilogue_avx2:
++	ret
++.size	${func}_avx2,.-${func}_avx2
++___
++}}
++}}}}}
++
++# EXCEPTION_DISPOSITION handler (EXCEPTION_RECORD *rec,ULONG64 frame,
++#		CONTEXT *context,DISPATCHER_CONTEXT *disp)
++if ($win64) {
++$rec="%rcx";
++$frame="%rdx";
++$context="%r8";
++$disp="%r9";
++
++$code.=<<___;
++.extern	__imp_RtlVirtualUnwind
++.type	se_handler,\@abi-omnipotent
++.align	16
++se_handler:
++	push	%rsi
++	push	%rdi
++	push	%rbx
++	push	%rbp
++	push	%r12
++	push	%r13
++	push	%r14
++	push	%r15
++	pushfq
++	sub	\$64,%rsp
++
++	mov	120($context),%rax	# pull context->Rax
++	mov	248($context),%rbx	# pull context->Rip
++
++	mov	8($disp),%rsi		# disp->ImageBase
++	mov	56($disp),%r11		# disp->HanderlData
++
++	mov	0(%r11),%r10d		# HandlerData[0]
++	lea	(%rsi,%r10),%r10	# prologue label
++	cmp	%r10,%rbx		# context->RipRsp
++
++	mov	4(%r11),%r10d		# HandlerData[1]
++	lea	(%rsi,%r10),%r10	# epilogue label
++	cmp	%r10,%rbx		# context->Rip>=epilogue label
++	jae	.Lin_prologue
++___
++$code.=<<___ if ($avx>1);
++	lea	.Lavx2_shortcut(%rip),%r10
++	cmp	%r10,%rbx		# context->RipRbx
++	mov	%rbp,160($context)	# restore context->Rbp
++	mov	%r12,216($context)	# restore context->R12
++	mov	%r13,224($context)	# restore context->R13
++	mov	%r14,232($context)	# restore context->R14
++	mov	%r15,240($context)	# restore context->R15
++
++	lea	.Lepilogue(%rip),%r10
++	cmp	%r10,%rbx
++	jb	.Lin_prologue		# non-AVX code
++
++	lea	16*$SZ+4*8(%rsi),%rsi	# Xmm6- save area
++	lea	512($context),%rdi	# &context.Xmm6
++	mov	\$`$SZ==4?8:12`,%ecx
++	.long	0xa548f3fc		# cld; rep movsq
++
++.Lin_prologue:
++	mov	8(%rax),%rdi
++	mov	16(%rax),%rsi
++	mov	%rax,152($context)	# restore context->Rsp
++	mov	%rsi,168($context)	# restore context->Rsi
++	mov	%rdi,176($context)	# restore context->Rdi
++
++	mov	40($disp),%rdi		# disp->ContextRecord
++	mov	$context,%rsi		# context
++	mov	\$154,%ecx		# sizeof(CONTEXT)
++	.long	0xa548f3fc		# cld; rep movsq
++
++	mov	$disp,%rsi
++	xor	%rcx,%rcx		# arg1, UNW_FLAG_NHANDLER
++	mov	8(%rsi),%rdx		# arg2, disp->ImageBase
++	mov	0(%rsi),%r8		# arg3, disp->ControlPc
++	mov	16(%rsi),%r9		# arg4, disp->FunctionEntry
++	mov	40(%rsi),%r10		# disp->ContextRecord
++	lea	56(%rsi),%r11		# &disp->HandlerData
++	lea	24(%rsi),%r12		# &disp->EstablisherFrame
++	mov	%r10,32(%rsp)		# arg5
++	mov	%r11,40(%rsp)		# arg6
++	mov	%r12,48(%rsp)		# arg7
++	mov	%rcx,56(%rsp)		# arg8, (NULL)
++	call	*__imp_RtlVirtualUnwind(%rip)
++
++	mov	\$1,%eax		# ExceptionContinueSearch
++	add	\$64,%rsp
++	popfq
++	pop	%r15
++	pop	%r14
++	pop	%r13
++	pop	%r12
++	pop	%rbp
++	pop	%rbx
++	pop	%rdi
++	pop	%rsi
++	ret
++.size	se_handler,.-se_handler
++___
++
++$code.=<<___ if ($SZ==4 && $shaext);
++.type	shaext_handler,\@abi-omnipotent
++.align	16
++shaext_handler:
++	push	%rsi
++	push	%rdi
++	push	%rbx
++	push	%rbp
++	push	%r12
++	push	%r13
++	push	%r14
++	push	%r15
++	pushfq
++	sub	\$64,%rsp
++
++	mov	120($context),%rax	# pull context->Rax
++	mov	248($context),%rbx	# pull context->Rip
++
++	lea	.Lprologue_shaext(%rip),%r10
++	cmp	%r10,%rbx		# context->Rip<.Lprologue
++	jb	.Lin_prologue
++
++	lea	.Lepilogue_shaext(%rip),%r10
++	cmp	%r10,%rbx		# context->Rip>=.Lepilogue
++	jae	.Lin_prologue
++
++	lea	-8-5*16(%rax),%rsi
++	lea	512($context),%rdi	# &context.Xmm6
++	mov	\$10,%ecx
++	.long	0xa548f3fc		# cld; rep movsq
++
++	jmp	.Lin_prologue
++.size	shaext_handler,.-shaext_handler
++___
++
++$code.=<<___;
++.section	.pdata
++.align	4
++	.rva	.LSEH_begin_$func
++	.rva	.LSEH_end_$func
++	.rva	.LSEH_info_$func
++___
++$code.=<<___ if ($SZ==4 && $shaext);
++	.rva	.LSEH_begin_${func}_shaext
++	.rva	.LSEH_end_${func}_shaext
++	.rva	.LSEH_info_${func}_shaext
++___
++$code.=<<___ if ($SZ==4);
++	.rva	.LSEH_begin_${func}_ssse3
++	.rva	.LSEH_end_${func}_ssse3
++	.rva	.LSEH_info_${func}_ssse3
++___
++$code.=<<___ if ($avx && $SZ==8);
++	.rva	.LSEH_begin_${func}_xop
++	.rva	.LSEH_end_${func}_xop
++	.rva	.LSEH_info_${func}_xop
++___
++$code.=<<___ if ($avx);
++	.rva	.LSEH_begin_${func}_avx
++	.rva	.LSEH_end_${func}_avx
++	.rva	.LSEH_info_${func}_avx
++___
++$code.=<<___ if ($avx>1);
++	.rva	.LSEH_begin_${func}_avx2
++	.rva	.LSEH_end_${func}_avx2
++	.rva	.LSEH_info_${func}_avx2
++___
++$code.=<<___;
++.section	.xdata
++.align	8
++.LSEH_info_$func:
++	.byte	9,0,0,0
++	.rva	se_handler
++	.rva	.Lprologue,.Lepilogue			# HandlerData[]
++___
++$code.=<<___ if ($SZ==4 && $shaext);
++.LSEH_info_${func}_shaext:
++	.byte	9,0,0,0
++	.rva	shaext_handler
++___
++$code.=<<___ if ($SZ==4);
++.LSEH_info_${func}_ssse3:
++	.byte	9,0,0,0
++	.rva	se_handler
++	.rva	.Lprologue_ssse3,.Lepilogue_ssse3	# HandlerData[]
++___
++$code.=<<___ if ($avx && $SZ==8);
++.LSEH_info_${func}_xop:
++	.byte	9,0,0,0
++	.rva	se_handler
++	.rva	.Lprologue_xop,.Lepilogue_xop		# HandlerData[]
++___
++$code.=<<___ if ($avx);
++.LSEH_info_${func}_avx:
++	.byte	9,0,0,0
++	.rva	se_handler
++	.rva	.Lprologue_avx,.Lepilogue_avx		# HandlerData[]
++___
++$code.=<<___ if ($avx>1);
++.LSEH_info_${func}_avx2:
++	.byte	9,0,0,0
++	.rva	se_handler
++	.rva	.Lprologue_avx2,.Lepilogue_avx2		# HandlerData[]
++___
++}
++
++sub sha256op38 {
++    my $instr = shift;
++    my %opcodelet = (
++		"sha256rnds2" => 0xcb,
++  		"sha256msg1"  => 0xcc,
++		"sha256msg2"  => 0xcd	);
++
++    if (defined($opcodelet{$instr}) && @_[0] =~ /%xmm([0-7]),\s*%xmm([0-7])/) {
++      my @opcode=(0x0f,0x38);
++	push @opcode,$opcodelet{$instr};
++	push @opcode,0xc0|($1&7)|(($2&7)<<3);		# ModR/M
++	return ".byte\t".join(',',@opcode);
++    } else {
++	return $instr."\t".@_[0];
++    }
++}
++
++foreach (split("\n",$code)) {
++	s/\`([^\`]*)\`/eval $1/geo;
++
++	s/\b(sha256[^\s]*)\s+(.*)/sha256op38($1,$2)/geo;
++
++	print $_,"\n";
++}
++close STDOUT;
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/sha/asm/sha512p8-ppc.pl b/CryptoPkg/Library/OpensslLib/openssl/crypto/sha/asm/sha512p8-ppc.pl
+new file mode 100755
+index 0000000..4d3d3b2
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/sha/asm/sha512p8-ppc.pl
+@@ -0,0 +1,431 @@
++#! /usr/bin/env perl
++# Copyright 2014-2016 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
++# in the file LICENSE in the source distribution or at
++# https://www.openssl.org/source/license.html
++
++
++# ====================================================================
++# Written by Andy Polyakov  for the OpenSSL
++# project. The module is, however, dual licensed under OpenSSL and
++# CRYPTOGAMS licenses depending on where you obtain it. For further
++# details see http://www.openssl.org/~appro/cryptogams/.
++# ====================================================================
++
++# SHA256/512 for PowerISA v2.07.
++#
++# Accurate performance measurements are problematic, because it's
++# always virtualized setup with possibly throttled processor.
++# Relative comparison is therefore more informative. This module is
++# ~60% faster than integer-only sha512-ppc.pl. To anchor to something
++# else, SHA256 is 24% slower than sha1-ppc.pl and 2.5x slower than
++# hardware-assisted aes-128-cbc encrypt. SHA512 is 20% faster than
++# sha1-ppc.pl and 1.6x slower than aes-128-cbc. Another interesting
++# result is degree of computational resources' utilization. POWER8 is
++# "massively multi-threaded chip" and difference between single- and
++# maximum multi-process benchmark results tells that utlization is
++# whooping 94%. For sha512-ppc.pl we get [not unimpressive] 84% and
++# for sha1-ppc.pl - 73%. 100% means that multi-process result equals
++# to single-process one, given that all threads end up on the same
++# physical core.
++
++$flavour=shift;
++$output =shift;
++
++if ($flavour =~ /64/) {
++	$SIZE_T=8;
++	$LRSAVE=2*$SIZE_T;
++	$STU="stdu";
++	$POP="ld";
++	$PUSH="std";
++} elsif ($flavour =~ /32/) {
++	$SIZE_T=4;
++	$LRSAVE=$SIZE_T;
++	$STU="stwu";
++	$POP="lwz";
++	$PUSH="stw";
++} else { die "nonsense $flavour"; }
++
++$LENDIAN=($flavour=~/le/);
++
++$0 =~ m/(.*[\/\\])[^\/\\]+$/; $dir=$1;
++( $xlate="${dir}ppc-xlate.pl" and -f $xlate ) or
++( $xlate="${dir}../../perlasm/ppc-xlate.pl" and -f $xlate) or
++die "can't locate ppc-xlate.pl";
++
++open STDOUT,"| $^X $xlate $flavour $output" || die "can't call $xlate: $!";
++
++if ($output =~ /512/) {
++	$bits=512;
++	$SZ=8;
++	$sz="d";
++	$rounds=80;
++} else {
++	$bits=256;
++	$SZ=4;
++	$sz="w";
++	$rounds=64;
++}
++
++$func="sha${bits}_block_p8";
++$FRAME=8*$SIZE_T;
++
++$sp ="r1";
++$toc="r2";
++$ctx="r3";
++$inp="r4";
++$num="r5";
++$Tbl="r6";
++$idx="r7";
++$lrsave="r8";
++$offload="r11";
++$vrsave="r12";
++($x00,$x10,$x20,$x30,$x40,$x50,$x60,$x70)=map("r$_",(0,10,26..31));
++ $x00=0 if ($flavour =~ /osx/);
++
++@V=($A,$B,$C,$D,$E,$F,$G,$H)=map("v$_",(0..7));
++@X=map("v$_",(8..23));
++($Ki,$Func,$S0,$S1,$s0,$s1,$lemask)=map("v$_",(24..31));
++
++sub ROUND {
++my ($i,$a,$b,$c,$d,$e,$f,$g,$h)=@_;
++my $j=($i+1)%16;
++
++$code.=<<___		if ($i<15 && ($i%(16/$SZ))==(16/$SZ-1));
++	lvx_u		@X[$i+1],0,$inp		; load X[i] in advance
++	addi		$inp,$inp,16
++___
++$code.=<<___		if ($i<16 && ($i%(16/$SZ)));
++	vsldoi		@X[$i],@X[$i-1],@X[$i-1],$SZ
++___
++$code.=<<___		if ($LENDIAN && $i<16 && ($i%(16/$SZ))==0);
++	vperm		@X[$i],@X[$i],@X[$i],$lemask
++___
++$code.=<<___;
++	`"vshasigma${sz}	$s0,@X[($j+1)%16],0,0"		if ($i>=15)`
++	vsel		$Func,$g,$f,$e		; Ch(e,f,g)
++	vshasigma${sz}	$S1,$e,1,15		; Sigma1(e)
++	vaddu${sz}m	$h,$h,@X[$i%16]		; h+=X[i]
++	vshasigma${sz}	$S0,$a,1,0		; Sigma0(a)
++	`"vshasigma${sz}	$s1,@X[($j+14)%16],0,15"	if ($i>=15)`
++	vaddu${sz}m	$h,$h,$Func		; h+=Ch(e,f,g)
++	vxor		$Func,$a,$b
++	`"vaddu${sz}m		@X[$j],@X[$j],@X[($j+9)%16]"	if ($i>=15)`
++	vaddu${sz}m	$h,$h,$S1		; h+=Sigma1(e)
++	vsel		$Func,$b,$c,$Func	; Maj(a,b,c)
++	vaddu${sz}m	$g,$g,$Ki		; future h+=K[i]
++	vaddu${sz}m	$d,$d,$h		; d+=h
++	vaddu${sz}m	$S0,$S0,$Func		; Sigma0(a)+Maj(a,b,c)
++	`"vaddu${sz}m		@X[$j],@X[$j],$s0"		if ($i>=15)`
++	lvx		$Ki,$idx,$Tbl		; load next K[i]
++	addi		$idx,$idx,16
++	vaddu${sz}m	$h,$h,$S0		; h+=Sigma0(a)+Maj(a,b,c)
++	`"vaddu${sz}m		@X[$j],@X[$j],$s1"		if ($i>=15)`
++___
++}
++
++$code=<<___;
++.machine	"any"
++.text
++
++.globl	$func
++.align	6
++$func:
++	$STU		$sp,-`($FRAME+21*16+6*$SIZE_T)`($sp)
++	mflr		$lrsave
++	li		r10,`$FRAME+8*16+15`
++	li		r11,`$FRAME+8*16+31`
++	stvx		v20,r10,$sp		# ABI says so
++	addi		r10,r10,32
++	mfspr		$vrsave,256
++	stvx		v21,r11,$sp
++	addi		r11,r11,32
++	stvx		v22,r10,$sp
++	addi		r10,r10,32
++	stvx		v23,r11,$sp
++	addi		r11,r11,32
++	stvx		v24,r10,$sp
++	addi		r10,r10,32
++	stvx		v25,r11,$sp
++	addi		r11,r11,32
++	stvx		v26,r10,$sp
++	addi		r10,r10,32
++	stvx		v27,r11,$sp
++	addi		r11,r11,32
++	stvx		v28,r10,$sp
++	addi		r10,r10,32
++	stvx		v29,r11,$sp
++	addi		r11,r11,32
++	stvx		v30,r10,$sp
++	stvx		v31,r11,$sp
++	li		r11,-1
++	stw		$vrsave,`$FRAME+21*16-4`($sp)	# save vrsave
++	li		$x10,0x10
++	$PUSH		r26,`$FRAME+21*16+0*$SIZE_T`($sp)
++	li		$x20,0x20
++	$PUSH		r27,`$FRAME+21*16+1*$SIZE_T`($sp)
++	li		$x30,0x30
++	$PUSH		r28,`$FRAME+21*16+2*$SIZE_T`($sp)
++	li		$x40,0x40
++	$PUSH		r29,`$FRAME+21*16+3*$SIZE_T`($sp)
++	li		$x50,0x50
++	$PUSH		r30,`$FRAME+21*16+4*$SIZE_T`($sp)
++	li		$x60,0x60
++	$PUSH		r31,`$FRAME+21*16+5*$SIZE_T`($sp)
++	li		$x70,0x70
++	$PUSH		$lrsave,`$FRAME+21*16+6*$SIZE_T+$LRSAVE`($sp)
++	mtspr		256,r11
++
++	bl		LPICmeup
++	addi		$offload,$sp,$FRAME+15
++___
++$code.=<<___		if ($LENDIAN);
++	li		$idx,8
++	lvsl		$lemask,0,$idx
++	vspltisb	$Ki,0x0f
++	vxor		$lemask,$lemask,$Ki
++___
++$code.=<<___		if ($SZ==4);
++	lvx_4w		$A,$x00,$ctx
++	lvx_4w		$E,$x10,$ctx
++	vsldoi		$B,$A,$A,4		# unpack
++	vsldoi		$C,$A,$A,8
++	vsldoi		$D,$A,$A,12
++	vsldoi		$F,$E,$E,4
++	vsldoi		$G,$E,$E,8
++	vsldoi		$H,$E,$E,12
++___
++$code.=<<___		if ($SZ==8);
++	lvx_u		$A,$x00,$ctx
++	lvx_u		$C,$x10,$ctx
++	lvx_u		$E,$x20,$ctx
++	vsldoi		$B,$A,$A,8		# unpack
++	lvx_u		$G,$x30,$ctx
++	vsldoi		$D,$C,$C,8
++	vsldoi		$F,$E,$E,8
++	vsldoi		$H,$G,$G,8
++___
++$code.=<<___;
++	li		r0,`($rounds-16)/16`	# inner loop counter
++	b		Loop
++.align	5
++Loop:
++	lvx		$Ki,$x00,$Tbl
++	li		$idx,16
++	lvx_u		@X[0],0,$inp
++	addi		$inp,$inp,16
++	stvx		$A,$x00,$offload	# offload $A-$H
++	stvx		$B,$x10,$offload
++	stvx		$C,$x20,$offload
++	stvx		$D,$x30,$offload
++	stvx		$E,$x40,$offload
++	stvx		$F,$x50,$offload
++	stvx		$G,$x60,$offload
++	stvx		$H,$x70,$offload
++	vaddu${sz}m	$H,$H,$Ki		# h+K[i]
++	lvx		$Ki,$idx,$Tbl
++	addi		$idx,$idx,16
++___
++for ($i=0;$i<16;$i++)	{ &ROUND($i,@V); unshift(@V,pop(@V)); }
++$code.=<<___;
++	mtctr		r0
++	b		L16_xx
++.align	5
++L16_xx:
++___
++for (;$i<32;$i++)	{ &ROUND($i,@V); unshift(@V,pop(@V)); }
++$code.=<<___;
++	bdnz		L16_xx
++
++	lvx		@X[2],$x00,$offload
++	subic.		$num,$num,1
++	lvx		@X[3],$x10,$offload
++	vaddu${sz}m	$A,$A,@X[2]
++	lvx		@X[4],$x20,$offload
++	vaddu${sz}m	$B,$B,@X[3]
++	lvx		@X[5],$x30,$offload
++	vaddu${sz}m	$C,$C,@X[4]
++	lvx		@X[6],$x40,$offload
++	vaddu${sz}m	$D,$D,@X[5]
++	lvx		@X[7],$x50,$offload
++	vaddu${sz}m	$E,$E,@X[6]
++	lvx		@X[8],$x60,$offload
++	vaddu${sz}m	$F,$F,@X[7]
++	lvx		@X[9],$x70,$offload
++	vaddu${sz}m	$G,$G,@X[8]
++	vaddu${sz}m	$H,$H,@X[9]
++	bne		Loop
++___
++$code.=<<___		if ($SZ==4);
++	lvx		@X[0],$idx,$Tbl
++	addi		$idx,$idx,16
++	vperm		$A,$A,$B,$Ki		# pack the answer
++	lvx		@X[1],$idx,$Tbl
++	vperm		$E,$E,$F,$Ki
++	vperm		$A,$A,$C,@X[0]
++	vperm		$E,$E,$G,@X[0]
++	vperm		$A,$A,$D,@X[1]
++	vperm		$E,$E,$H,@X[1]
++	stvx_4w		$A,$x00,$ctx
++	stvx_4w		$E,$x10,$ctx
++___
++$code.=<<___		if ($SZ==8);
++	vperm		$A,$A,$B,$Ki		# pack the answer
++	vperm		$C,$C,$D,$Ki
++	vperm		$E,$E,$F,$Ki
++	vperm		$G,$G,$H,$Ki
++	stvx_u		$A,$x00,$ctx
++	stvx_u		$C,$x10,$ctx
++	stvx_u		$E,$x20,$ctx
++	stvx_u		$G,$x30,$ctx
++___
++$code.=<<___;
++	li		r10,`$FRAME+8*16+15`
++	mtlr		$lrsave
++	li		r11,`$FRAME+8*16+31`
++	mtspr		256,$vrsave
++	lvx		v20,r10,$sp		# ABI says so
++	addi		r10,r10,32
++	lvx		v21,r11,$sp
++	addi		r11,r11,32
++	lvx		v22,r10,$sp
++	addi		r10,r10,32
++	lvx		v23,r11,$sp
++	addi		r11,r11,32
++	lvx		v24,r10,$sp
++	addi		r10,r10,32
++	lvx		v25,r11,$sp
++	addi		r11,r11,32
++	lvx		v26,r10,$sp
++	addi		r10,r10,32
++	lvx		v27,r11,$sp
++	addi		r11,r11,32
++	lvx		v28,r10,$sp
++	addi		r10,r10,32
++	lvx		v29,r11,$sp
++	addi		r11,r11,32
++	lvx		v30,r10,$sp
++	lvx		v31,r11,$sp
++	$POP		r26,`$FRAME+21*16+0*$SIZE_T`($sp)
++	$POP		r27,`$FRAME+21*16+1*$SIZE_T`($sp)
++	$POP		r28,`$FRAME+21*16+2*$SIZE_T`($sp)
++	$POP		r29,`$FRAME+21*16+3*$SIZE_T`($sp)
++	$POP		r30,`$FRAME+21*16+4*$SIZE_T`($sp)
++	$POP		r31,`$FRAME+21*16+5*$SIZE_T`($sp)
++	addi		$sp,$sp,`$FRAME+21*16+6*$SIZE_T`
++	blr
++	.long		0
++	.byte		0,12,4,1,0x80,6,3,0
++	.long		0
++.size	$func,.-$func
++___
++
++# Ugly hack here, because PPC assembler syntax seem to vary too
++# much from platforms to platform...
++$code.=<<___;
++.align	6
++LPICmeup:
++	mflr	r0
++	bcl	20,31,\$+4
++	mflr	$Tbl	; vvvvvv "distance" between . and 1st data entry
++	addi	$Tbl,$Tbl,`64-8`
++	mtlr	r0
++	blr
++	.long	0
++	.byte	0,12,0x14,0,0,0,0,0
++	.space	`64-9*4`
++___
++
++if ($SZ==8) {
++    local *table = sub {
++	foreach(@_) { $code.=".quad	$_,$_\n"; }
++    };
++    table(
++	"0x428a2f98d728ae22","0x7137449123ef65cd",
++	"0xb5c0fbcfec4d3b2f","0xe9b5dba58189dbbc",
++	"0x3956c25bf348b538","0x59f111f1b605d019",
++	"0x923f82a4af194f9b","0xab1c5ed5da6d8118",
++	"0xd807aa98a3030242","0x12835b0145706fbe",
++	"0x243185be4ee4b28c","0x550c7dc3d5ffb4e2",
++	"0x72be5d74f27b896f","0x80deb1fe3b1696b1",
++	"0x9bdc06a725c71235","0xc19bf174cf692694",
++	"0xe49b69c19ef14ad2","0xefbe4786384f25e3",
++	"0x0fc19dc68b8cd5b5","0x240ca1cc77ac9c65",
++	"0x2de92c6f592b0275","0x4a7484aa6ea6e483",
++	"0x5cb0a9dcbd41fbd4","0x76f988da831153b5",
++	"0x983e5152ee66dfab","0xa831c66d2db43210",
++	"0xb00327c898fb213f","0xbf597fc7beef0ee4",
++	"0xc6e00bf33da88fc2","0xd5a79147930aa725",
++	"0x06ca6351e003826f","0x142929670a0e6e70",
++	"0x27b70a8546d22ffc","0x2e1b21385c26c926",
++	"0x4d2c6dfc5ac42aed","0x53380d139d95b3df",
++	"0x650a73548baf63de","0x766a0abb3c77b2a8",
++	"0x81c2c92e47edaee6","0x92722c851482353b",
++	"0xa2bfe8a14cf10364","0xa81a664bbc423001",
++	"0xc24b8b70d0f89791","0xc76c51a30654be30",
++	"0xd192e819d6ef5218","0xd69906245565a910",
++	"0xf40e35855771202a","0x106aa07032bbd1b8",
++	"0x19a4c116b8d2d0c8","0x1e376c085141ab53",
++	"0x2748774cdf8eeb99","0x34b0bcb5e19b48a8",
++	"0x391c0cb3c5c95a63","0x4ed8aa4ae3418acb",
++	"0x5b9cca4f7763e373","0x682e6ff3d6b2b8a3",
++	"0x748f82ee5defb2fc","0x78a5636f43172f60",
++	"0x84c87814a1f0ab72","0x8cc702081a6439ec",
++	"0x90befffa23631e28","0xa4506cebde82bde9",
++	"0xbef9a3f7b2c67915","0xc67178f2e372532b",
++	"0xca273eceea26619c","0xd186b8c721c0c207",
++	"0xeada7dd6cde0eb1e","0xf57d4f7fee6ed178",
++	"0x06f067aa72176fba","0x0a637dc5a2c898a6",
++	"0x113f9804bef90dae","0x1b710b35131c471b",
++	"0x28db77f523047d84","0x32caab7b40c72493",
++	"0x3c9ebe0a15c9bebc","0x431d67c49c100d4c",
++	"0x4cc5d4becb3e42b6","0x597f299cfc657e2a",
++	"0x5fcb6fab3ad6faec","0x6c44198c4a475817","0");
++$code.=<<___	if (!$LENDIAN);
++.quad	0x0001020304050607,0x1011121314151617
++___
++$code.=<<___	if ($LENDIAN);	# quad-swapped
++.quad	0x1011121314151617,0x0001020304050607
++___
++} else {
++    local *table = sub {
++	foreach(@_) { $code.=".long	$_,$_,$_,$_\n"; }
++    };
++    table(
++	"0x428a2f98","0x71374491","0xb5c0fbcf","0xe9b5dba5",
++	"0x3956c25b","0x59f111f1","0x923f82a4","0xab1c5ed5",
++	"0xd807aa98","0x12835b01","0x243185be","0x550c7dc3",
++	"0x72be5d74","0x80deb1fe","0x9bdc06a7","0xc19bf174",
++	"0xe49b69c1","0xefbe4786","0x0fc19dc6","0x240ca1cc",
++	"0x2de92c6f","0x4a7484aa","0x5cb0a9dc","0x76f988da",
++	"0x983e5152","0xa831c66d","0xb00327c8","0xbf597fc7",
++	"0xc6e00bf3","0xd5a79147","0x06ca6351","0x14292967",
++	"0x27b70a85","0x2e1b2138","0x4d2c6dfc","0x53380d13",
++	"0x650a7354","0x766a0abb","0x81c2c92e","0x92722c85",
++	"0xa2bfe8a1","0xa81a664b","0xc24b8b70","0xc76c51a3",
++	"0xd192e819","0xd6990624","0xf40e3585","0x106aa070",
++	"0x19a4c116","0x1e376c08","0x2748774c","0x34b0bcb5",
++	"0x391c0cb3","0x4ed8aa4a","0x5b9cca4f","0x682e6ff3",
++	"0x748f82ee","0x78a5636f","0x84c87814","0x8cc70208",
++	"0x90befffa","0xa4506ceb","0xbef9a3f7","0xc67178f2","0");
++$code.=<<___	if (!$LENDIAN);
++.long	0x00010203,0x10111213,0x10111213,0x10111213
++.long	0x00010203,0x04050607,0x10111213,0x10111213
++.long	0x00010203,0x04050607,0x08090a0b,0x10111213
++___
++$code.=<<___	if ($LENDIAN);	# word-swapped
++.long	0x10111213,0x10111213,0x10111213,0x00010203
++.long	0x10111213,0x10111213,0x04050607,0x00010203
++.long	0x10111213,0x08090a0b,0x04050607,0x00010203
++___
++}
++$code.=<<___;
++.asciz	"SHA${bits} for PowerISA 2.07, CRYPTOGAMS by "
++.align	2
++___
++
++$code =~ s/\`([^\`]*)\`/eval $1/gem;
++print $code;
++close STDOUT;
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/sha/build.info b/CryptoPkg/Library/OpensslLib/openssl/crypto/sha/build.info
+new file mode 100644
+index 0000000..5843e50
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/sha/build.info
+@@ -0,0 +1,69 @@
++LIBS=../../libcrypto
++SOURCE[../../libcrypto]=\
++        sha1dgst.c sha1_one.c sha256.c sha512.c {- $target{sha1_asm_src} -}
++
++GENERATE[sha1-586.s]=asm/sha1-586.pl $(PERLASM_SCHEME) $(CFLAGS) $(LIB_CFLAGS) $(PROCESSOR)
++DEPEND[sha1-586.s]=../perlasm/x86asm.pl
++GENERATE[sha256-586.s]=asm/sha256-586.pl $(PERLASM_SCHEME) $(CFLAGS) $(LIB_CFLAGS) $(PROCESSOR)
++DEPEND[sha256-586.s]=../perlasm/x86asm.pl
++GENERATE[sha512-586.s]=asm/sha512-586.pl $(PERLASM_SCHEME) $(CFLAGS) $(LIB_CFLAGS) $(PROCESSOR)
++DEPEND[sha512-586.s]=../perlasm/x86asm.pl
++
++GENERATE[sha1-ia64.s]=asm/sha1-ia64.pl $(CFLAGS) $(LIB_CFLAGS)
++GENERATE[sha256-ia64.s]=asm/sha512-ia64.pl $(CFLAGS) $(LIB_CFLAGS)
++GENERATE[sha512-ia64.s]=asm/sha512-ia64.pl $(CFLAGS) $(LIB_CFLAGS)
++
++GENERATE[sha1-alpha.S]=asm/sha1-alpha.pl $(PERLASM_SCHEME)
++
++GENERATE[sha1-x86_64.s]=asm/sha1-x86_64.pl $(PERLASM_SCHEME)
++GENERATE[sha1-mb-x86_64.s]=asm/sha1-mb-x86_64.pl $(PERLASM_SCHEME)
++GENERATE[sha256-x86_64.s]=asm/sha512-x86_64.pl $(PERLASM_SCHEME)
++GENERATE[sha256-mb-x86_64.s]=asm/sha256-mb-x86_64.pl $(PERLASM_SCHEME)
++GENERATE[sha512-x86_64.s]=asm/sha512-x86_64.pl $(PERLASM_SCHEME)
++
++GENERATE[sha1-sparcv9.S]=asm/sha1-sparcv9.pl $(PERLASM_SCHEME)
++INCLUDE[sha1-sparcv9.o]=..
++GENERATE[sha256-sparcv9.S]=asm/sha512-sparcv9.pl $(PERLASM_SCHEME)
++INCLUDE[sha256-sparcv9.o]=..
++GENERATE[sha512-sparcv9.S]=asm/sha512-sparcv9.pl $(PERLASM_SCHEME)
++INCLUDE[sha512-sparcv9.o]=..
++
++GENERATE[sha1-ppc.s]=asm/sha1-ppc.pl $(PERLASM_SCHEME)
++GENERATE[sha256-ppc.s]=asm/sha512-ppc.pl $(PERLASM_SCHEME)
++GENERATE[sha512-ppc.s]=asm/sha512-ppc.pl $(PERLASM_SCHEME)
++GENERATE[sha256p8-ppc.s]=asm/sha512p8-ppc.pl $(PERLASM_SCHEME)
++GENERATE[sha512p8-ppc.s]=asm/sha512p8-ppc.pl $(PERLASM_SCHEME)
++
++GENERATE[sha1-parisc.s]=asm/sha1-parisc.pl $(PERLASM_SCHEME)
++GENERATE[sha256-parisc.s]=asm/sha512-parisc.pl $(PERLASM_SCHEME)
++GENERATE[sha512-parisc.s]=asm/sha512-parisc.pl $(PERLASM_SCHEME)
++
++GENERATE[sha1-mips.S]=asm/sha1-mips.pl $(PERLASM_SCHEME)
++GENERATE[sha256-mips.S]=asm/sha512-mips.pl $(PERLASM_SCHEME)
++GENERATE[sha512-mips.S]=asm/sha512-mips.pl $(PERLASM_SCHEME)
++
++GENERATE[sha1-armv4-large.S]=asm/sha1-armv4-large.pl $(PERLASM_SCHEME)
++INCLUDE[sha1-armv4-large.o]=..
++GENERATE[sha256-armv4.S]=asm/sha256-armv4.pl $(PERLASM_SCHEME)
++INCLUDE[sha256-armv4.o]=..
++GENERATE[sha512-armv4.S]=asm/sha512-armv4.pl $(PERLASM_SCHEME)
++INCLUDE[sha512-armv4.o]=..
++
++GENERATE[sha1-armv8.S]=asm/sha1-armv8.pl $(PERLASM_SCHEME)
++INCLUDE[sha1-armv8.o]=..
++GENERATE[sha256-armv8.S]=asm/sha512-armv8.pl $(PERLASM_SCHEME)
++INCLUDE[sha256-armv8.o]=..
++GENERATE[sha512-armv8.S]=asm/sha512-armv8.pl $(PERLASM_SCHEME)
++INCLUDE[sha512-armv8.o]=..
++
++BEGINRAW[Makefile(unix)]
++##### SHA assembler implementations
++
++# GNU make "catch all"
++{- $builddir -}/sha1-%.S:	{- $sourcedir -}/asm/sha1-%.pl
++	CC="$(CC)" $(PERL) $< $(PERLASM_SCHEME) $@
++{- $builddir -}/sha256-%.S:	{- $sourcedir -}/asm/sha512-%.pl
++	CC="$(CC)" $(PERL) $< $(PERLASM_SCHEME) $@
++{- $builddir -}/sha512-%.S:	{- $sourcedir -}/asm/sha512-%.pl
++	CC="$(CC)" $(PERL) $< $(PERLASM_SCHEME) $@
++ENDRAW[Makefile(unix)]
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/sha/sha1_one.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/sha/sha1_one.c
+new file mode 100644
+index 0000000..273ab08
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/sha/sha1_one.c
+@@ -0,0 +1,28 @@
++/*
++ * Copyright 1995-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include 
++#include 
++#include 
++
++unsigned char *SHA1(const unsigned char *d, size_t n, unsigned char *md)
++{
++    SHA_CTX c;
++    static unsigned char m[SHA_DIGEST_LENGTH];
++
++    if (md == NULL)
++        md = m;
++    if (!SHA1_Init(&c))
++        return NULL;
++    SHA1_Update(&c, d, n);
++    SHA1_Final(md, &c);
++    OPENSSL_cleanse(&c, sizeof(c));
++    return (md);
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/sha/sha1dgst.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/sha/sha1dgst.c
+new file mode 100644
+index 0000000..819370e
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/sha/sha1dgst.c
+@@ -0,0 +1,17 @@
++/*
++ * Copyright 1995-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include 
++
++# include 
++
++/* The implementation is in ../md32_common.h */
++
++# include "sha_locl.h"
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/sha/sha256.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/sha/sha256.c
+new file mode 100644
+index 0000000..5e7ba43
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/sha/sha256.c
+@@ -0,0 +1,386 @@
++/*
++ * Copyright 2004-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++
++#include 
++#include 
++
++#include 
++#include 
++#include 
++
++int SHA224_Init(SHA256_CTX *c)
++{
++    memset(c, 0, sizeof(*c));
++    c->h[0] = 0xc1059ed8UL;
++    c->h[1] = 0x367cd507UL;
++    c->h[2] = 0x3070dd17UL;
++    c->h[3] = 0xf70e5939UL;
++    c->h[4] = 0xffc00b31UL;
++    c->h[5] = 0x68581511UL;
++    c->h[6] = 0x64f98fa7UL;
++    c->h[7] = 0xbefa4fa4UL;
++    c->md_len = SHA224_DIGEST_LENGTH;
++    return 1;
++}
++
++int SHA256_Init(SHA256_CTX *c)
++{
++    memset(c, 0, sizeof(*c));
++    c->h[0] = 0x6a09e667UL;
++    c->h[1] = 0xbb67ae85UL;
++    c->h[2] = 0x3c6ef372UL;
++    c->h[3] = 0xa54ff53aUL;
++    c->h[4] = 0x510e527fUL;
++    c->h[5] = 0x9b05688cUL;
++    c->h[6] = 0x1f83d9abUL;
++    c->h[7] = 0x5be0cd19UL;
++    c->md_len = SHA256_DIGEST_LENGTH;
++    return 1;
++}
++
++unsigned char *SHA224(const unsigned char *d, size_t n, unsigned char *md)
++{
++    SHA256_CTX c;
++    static unsigned char m[SHA224_DIGEST_LENGTH];
++
++    if (md == NULL)
++        md = m;
++    SHA224_Init(&c);
++    SHA256_Update(&c, d, n);
++    SHA256_Final(md, &c);
++    OPENSSL_cleanse(&c, sizeof(c));
++    return (md);
++}
++
++unsigned char *SHA256(const unsigned char *d, size_t n, unsigned char *md)
++{
++    SHA256_CTX c;
++    static unsigned char m[SHA256_DIGEST_LENGTH];
++
++    if (md == NULL)
++        md = m;
++    SHA256_Init(&c);
++    SHA256_Update(&c, d, n);
++    SHA256_Final(md, &c);
++    OPENSSL_cleanse(&c, sizeof(c));
++    return (md);
++}
++
++int SHA224_Update(SHA256_CTX *c, const void *data, size_t len)
++{
++    return SHA256_Update(c, data, len);
++}
++
++int SHA224_Final(unsigned char *md, SHA256_CTX *c)
++{
++    return SHA256_Final(md, c);
++}
++
++#define DATA_ORDER_IS_BIG_ENDIAN
++
++#define HASH_LONG               SHA_LONG
++#define HASH_CTX                SHA256_CTX
++#define HASH_CBLOCK             SHA_CBLOCK
++
++/*
++ * Note that FIPS180-2 discusses "Truncation of the Hash Function Output."
++ * default: case below covers for it. It's not clear however if it's
++ * permitted to truncate to amount of bytes not divisible by 4. I bet not,
++ * but if it is, then default: case shall be extended. For reference.
++ * Idea behind separate cases for pre-defined lengths is to let the
++ * compiler decide if it's appropriate to unroll small loops.
++ */
++#define HASH_MAKE_STRING(c,s)   do {    \
++        unsigned long ll;               \
++        unsigned int  nn;               \
++        switch ((c)->md_len)            \
++        {   case SHA224_DIGEST_LENGTH:  \
++                for (nn=0;nnh[nn]; (void)HOST_l2c(ll,(s));   }  \
++                break;                  \
++            case SHA256_DIGEST_LENGTH:  \
++                for (nn=0;nnh[nn]; (void)HOST_l2c(ll,(s));   }  \
++                break;                  \
++            default:                    \
++                if ((c)->md_len > SHA256_DIGEST_LENGTH) \
++                    return 0;                           \
++                for (nn=0;nn<(c)->md_len/4;nn++)                \
++                {   ll=(c)->h[nn]; (void)HOST_l2c(ll,(s));   }  \
++                break;                  \
++        }                               \
++        } while (0)
++
++#define HASH_UPDATE             SHA256_Update
++#define HASH_TRANSFORM          SHA256_Transform
++#define HASH_FINAL              SHA256_Final
++#define HASH_BLOCK_DATA_ORDER   sha256_block_data_order
++#ifndef SHA256_ASM
++static
++#endif
++void sha256_block_data_order(SHA256_CTX *ctx, const void *in, size_t num);
++
++#include "internal/md32_common.h"
++
++#ifndef SHA256_ASM
++static const SHA_LONG K256[64] = {
++    0x428a2f98UL, 0x71374491UL, 0xb5c0fbcfUL, 0xe9b5dba5UL,
++    0x3956c25bUL, 0x59f111f1UL, 0x923f82a4UL, 0xab1c5ed5UL,
++    0xd807aa98UL, 0x12835b01UL, 0x243185beUL, 0x550c7dc3UL,
++    0x72be5d74UL, 0x80deb1feUL, 0x9bdc06a7UL, 0xc19bf174UL,
++    0xe49b69c1UL, 0xefbe4786UL, 0x0fc19dc6UL, 0x240ca1ccUL,
++    0x2de92c6fUL, 0x4a7484aaUL, 0x5cb0a9dcUL, 0x76f988daUL,
++    0x983e5152UL, 0xa831c66dUL, 0xb00327c8UL, 0xbf597fc7UL,
++    0xc6e00bf3UL, 0xd5a79147UL, 0x06ca6351UL, 0x14292967UL,
++    0x27b70a85UL, 0x2e1b2138UL, 0x4d2c6dfcUL, 0x53380d13UL,
++    0x650a7354UL, 0x766a0abbUL, 0x81c2c92eUL, 0x92722c85UL,
++    0xa2bfe8a1UL, 0xa81a664bUL, 0xc24b8b70UL, 0xc76c51a3UL,
++    0xd192e819UL, 0xd6990624UL, 0xf40e3585UL, 0x106aa070UL,
++    0x19a4c116UL, 0x1e376c08UL, 0x2748774cUL, 0x34b0bcb5UL,
++    0x391c0cb3UL, 0x4ed8aa4aUL, 0x5b9cca4fUL, 0x682e6ff3UL,
++    0x748f82eeUL, 0x78a5636fUL, 0x84c87814UL, 0x8cc70208UL,
++    0x90befffaUL, 0xa4506cebUL, 0xbef9a3f7UL, 0xc67178f2UL
++};
++
++/*
++ * FIPS specification refers to right rotations, while our ROTATE macro
++ * is left one. This is why you might notice that rotation coefficients
++ * differ from those observed in FIPS document by 32-N...
++ */
++# define Sigma0(x)       (ROTATE((x),30) ^ ROTATE((x),19) ^ ROTATE((x),10))
++# define Sigma1(x)       (ROTATE((x),26) ^ ROTATE((x),21) ^ ROTATE((x),7))
++# define sigma0(x)       (ROTATE((x),25) ^ ROTATE((x),14) ^ ((x)>>3))
++# define sigma1(x)       (ROTATE((x),15) ^ ROTATE((x),13) ^ ((x)>>10))
++
++# define Ch(x,y,z)       (((x) & (y)) ^ ((~(x)) & (z)))
++# define Maj(x,y,z)      (((x) & (y)) ^ ((x) & (z)) ^ ((y) & (z)))
++
++# ifdef OPENSSL_SMALL_FOOTPRINT
++
++static void sha256_block_data_order(SHA256_CTX *ctx, const void *in,
++                                    size_t num)
++{
++    unsigned MD32_REG_T a, b, c, d, e, f, g, h, s0, s1, T1, T2;
++    SHA_LONG X[16], l;
++    int i;
++    const unsigned char *data = in;
++
++    while (num--) {
++
++        a = ctx->h[0];
++        b = ctx->h[1];
++        c = ctx->h[2];
++        d = ctx->h[3];
++        e = ctx->h[4];
++        f = ctx->h[5];
++        g = ctx->h[6];
++        h = ctx->h[7];
++
++        for (i = 0; i < 16; i++) {
++            (void)HOST_c2l(data, l);
++            T1 = X[i] = l;
++            T1 += h + Sigma1(e) + Ch(e, f, g) + K256[i];
++            T2 = Sigma0(a) + Maj(a, b, c);
++            h = g;
++            g = f;
++            f = e;
++            e = d + T1;
++            d = c;
++            c = b;
++            b = a;
++            a = T1 + T2;
++        }
++
++        for (; i < 64; i++) {
++            s0 = X[(i + 1) & 0x0f];
++            s0 = sigma0(s0);
++            s1 = X[(i + 14) & 0x0f];
++            s1 = sigma1(s1);
++
++            T1 = X[i & 0xf] += s0 + s1 + X[(i + 9) & 0xf];
++            T1 += h + Sigma1(e) + Ch(e, f, g) + K256[i];
++            T2 = Sigma0(a) + Maj(a, b, c);
++            h = g;
++            g = f;
++            f = e;
++            e = d + T1;
++            d = c;
++            c = b;
++            b = a;
++            a = T1 + T2;
++        }
++
++        ctx->h[0] += a;
++        ctx->h[1] += b;
++        ctx->h[2] += c;
++        ctx->h[3] += d;
++        ctx->h[4] += e;
++        ctx->h[5] += f;
++        ctx->h[6] += g;
++        ctx->h[7] += h;
++
++    }
++}
++
++# else
++
++#  define ROUND_00_15(i,a,b,c,d,e,f,g,h)          do {    \
++        T1 += h + Sigma1(e) + Ch(e,f,g) + K256[i];      \
++        h = Sigma0(a) + Maj(a,b,c);                     \
++        d += T1;        h += T1;                } while (0)
++
++#  define ROUND_16_63(i,a,b,c,d,e,f,g,h,X)        do {    \
++        s0 = X[(i+1)&0x0f];     s0 = sigma0(s0);        \
++        s1 = X[(i+14)&0x0f];    s1 = sigma1(s1);        \
++        T1 = X[(i)&0x0f] += s0 + s1 + X[(i+9)&0x0f];    \
++        ROUND_00_15(i,a,b,c,d,e,f,g,h);         } while (0)
++
++static void sha256_block_data_order(SHA256_CTX *ctx, const void *in,
++                                    size_t num)
++{
++    unsigned MD32_REG_T a, b, c, d, e, f, g, h, s0, s1, T1;
++    SHA_LONG X[16];
++    int i;
++    const unsigned char *data = in;
++    const union {
++        long one;
++        char little;
++    } is_endian = {
++        1
++    };
++
++    while (num--) {
++
++        a = ctx->h[0];
++        b = ctx->h[1];
++        c = ctx->h[2];
++        d = ctx->h[3];
++        e = ctx->h[4];
++        f = ctx->h[5];
++        g = ctx->h[6];
++        h = ctx->h[7];
++
++        if (!is_endian.little && sizeof(SHA_LONG) == 4
++            && ((size_t)in % 4) == 0) {
++            const SHA_LONG *W = (const SHA_LONG *)data;
++
++            T1 = X[0] = W[0];
++            ROUND_00_15(0, a, b, c, d, e, f, g, h);
++            T1 = X[1] = W[1];
++            ROUND_00_15(1, h, a, b, c, d, e, f, g);
++            T1 = X[2] = W[2];
++            ROUND_00_15(2, g, h, a, b, c, d, e, f);
++            T1 = X[3] = W[3];
++            ROUND_00_15(3, f, g, h, a, b, c, d, e);
++            T1 = X[4] = W[4];
++            ROUND_00_15(4, e, f, g, h, a, b, c, d);
++            T1 = X[5] = W[5];
++            ROUND_00_15(5, d, e, f, g, h, a, b, c);
++            T1 = X[6] = W[6];
++            ROUND_00_15(6, c, d, e, f, g, h, a, b);
++            T1 = X[7] = W[7];
++            ROUND_00_15(7, b, c, d, e, f, g, h, a);
++            T1 = X[8] = W[8];
++            ROUND_00_15(8, a, b, c, d, e, f, g, h);
++            T1 = X[9] = W[9];
++            ROUND_00_15(9, h, a, b, c, d, e, f, g);
++            T1 = X[10] = W[10];
++            ROUND_00_15(10, g, h, a, b, c, d, e, f);
++            T1 = X[11] = W[11];
++            ROUND_00_15(11, f, g, h, a, b, c, d, e);
++            T1 = X[12] = W[12];
++            ROUND_00_15(12, e, f, g, h, a, b, c, d);
++            T1 = X[13] = W[13];
++            ROUND_00_15(13, d, e, f, g, h, a, b, c);
++            T1 = X[14] = W[14];
++            ROUND_00_15(14, c, d, e, f, g, h, a, b);
++            T1 = X[15] = W[15];
++            ROUND_00_15(15, b, c, d, e, f, g, h, a);
++
++            data += SHA256_CBLOCK;
++        } else {
++            SHA_LONG l;
++
++            (void)HOST_c2l(data, l);
++            T1 = X[0] = l;
++            ROUND_00_15(0, a, b, c, d, e, f, g, h);
++            (void)HOST_c2l(data, l);
++            T1 = X[1] = l;
++            ROUND_00_15(1, h, a, b, c, d, e, f, g);
++            (void)HOST_c2l(data, l);
++            T1 = X[2] = l;
++            ROUND_00_15(2, g, h, a, b, c, d, e, f);
++            (void)HOST_c2l(data, l);
++            T1 = X[3] = l;
++            ROUND_00_15(3, f, g, h, a, b, c, d, e);
++            (void)HOST_c2l(data, l);
++            T1 = X[4] = l;
++            ROUND_00_15(4, e, f, g, h, a, b, c, d);
++            (void)HOST_c2l(data, l);
++            T1 = X[5] = l;
++            ROUND_00_15(5, d, e, f, g, h, a, b, c);
++            (void)HOST_c2l(data, l);
++            T1 = X[6] = l;
++            ROUND_00_15(6, c, d, e, f, g, h, a, b);
++            (void)HOST_c2l(data, l);
++            T1 = X[7] = l;
++            ROUND_00_15(7, b, c, d, e, f, g, h, a);
++            (void)HOST_c2l(data, l);
++            T1 = X[8] = l;
++            ROUND_00_15(8, a, b, c, d, e, f, g, h);
++            (void)HOST_c2l(data, l);
++            T1 = X[9] = l;
++            ROUND_00_15(9, h, a, b, c, d, e, f, g);
++            (void)HOST_c2l(data, l);
++            T1 = X[10] = l;
++            ROUND_00_15(10, g, h, a, b, c, d, e, f);
++            (void)HOST_c2l(data, l);
++            T1 = X[11] = l;
++            ROUND_00_15(11, f, g, h, a, b, c, d, e);
++            (void)HOST_c2l(data, l);
++            T1 = X[12] = l;
++            ROUND_00_15(12, e, f, g, h, a, b, c, d);
++            (void)HOST_c2l(data, l);
++            T1 = X[13] = l;
++            ROUND_00_15(13, d, e, f, g, h, a, b, c);
++            (void)HOST_c2l(data, l);
++            T1 = X[14] = l;
++            ROUND_00_15(14, c, d, e, f, g, h, a, b);
++            (void)HOST_c2l(data, l);
++            T1 = X[15] = l;
++            ROUND_00_15(15, b, c, d, e, f, g, h, a);
++        }
++
++        for (i = 16; i < 64; i += 8) {
++            ROUND_16_63(i + 0, a, b, c, d, e, f, g, h, X);
++            ROUND_16_63(i + 1, h, a, b, c, d, e, f, g, X);
++            ROUND_16_63(i + 2, g, h, a, b, c, d, e, f, X);
++            ROUND_16_63(i + 3, f, g, h, a, b, c, d, e, X);
++            ROUND_16_63(i + 4, e, f, g, h, a, b, c, d, X);
++            ROUND_16_63(i + 5, d, e, f, g, h, a, b, c, X);
++            ROUND_16_63(i + 6, c, d, e, f, g, h, a, b, X);
++            ROUND_16_63(i + 7, b, c, d, e, f, g, h, a, X);
++        }
++
++        ctx->h[0] += a;
++        ctx->h[1] += b;
++        ctx->h[2] += c;
++        ctx->h[3] += d;
++        ctx->h[4] += e;
++        ctx->h[5] += f;
++        ctx->h[6] += g;
++        ctx->h[7] += h;
++
++    }
++}
++
++# endif
++#endif                         /* SHA256_ASM */
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/sha/sha512.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/sha/sha512.c
+new file mode 100644
+index 0000000..d24d103
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/sha/sha512.c
+@@ -0,0 +1,678 @@
++/*
++ * Copyright 2004-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++/*-
++ * IMPLEMENTATION NOTES.
++ *
++ * As you might have noticed 32-bit hash algorithms:
++ *
++ * - permit SHA_LONG to be wider than 32-bit
++ * - optimized versions implement two transform functions: one operating
++ *   on [aligned] data in host byte order and one - on data in input
++ *   stream byte order;
++ * - share common byte-order neutral collector and padding function
++ *   implementations, ../md32_common.h;
++ *
++ * Neither of the above applies to this SHA-512 implementations. Reasons
++ * [in reverse order] are:
++ *
++ * - it's the only 64-bit hash algorithm for the moment of this writing,
++ *   there is no need for common collector/padding implementation [yet];
++ * - by supporting only one transform function [which operates on
++ *   *aligned* data in input stream byte order, big-endian in this case]
++ *   we minimize burden of maintenance in two ways: a) collector/padding
++ *   function is simpler; b) only one transform function to stare at;
++ * - SHA_LONG64 is required to be exactly 64-bit in order to be able to
++ *   apply a number of optimizations to mitigate potential performance
++ *   penalties caused by previous design decision;
++ *
++ * Caveat lector.
++ *
++ * Implementation relies on the fact that "long long" is 64-bit on
++ * both 32- and 64-bit platforms. If some compiler vendor comes up
++ * with 128-bit long long, adjustment to sha.h would be required.
++ * As this implementation relies on 64-bit integer type, it's totally
++ * inappropriate for platforms which don't support it, most notably
++ * 16-bit platforms.
++ *                                      
++ */
++#include 
++#include 
++
++#include 
++#include 
++#include 
++
++#include "internal/cryptlib.h"
++
++#if defined(__i386) || defined(__i386__) || defined(_M_IX86) || \
++    defined(__x86_64) || defined(_M_AMD64) || defined(_M_X64) || \
++    defined(__s390__) || defined(__s390x__) || \
++    defined(__aarch64__) || \
++    defined(SHA512_ASM)
++# define SHA512_BLOCK_CAN_MANAGE_UNALIGNED_DATA
++#endif
++
++int SHA384_Init(SHA512_CTX *c)
++{
++    c->h[0] = U64(0xcbbb9d5dc1059ed8);
++    c->h[1] = U64(0x629a292a367cd507);
++    c->h[2] = U64(0x9159015a3070dd17);
++    c->h[3] = U64(0x152fecd8f70e5939);
++    c->h[4] = U64(0x67332667ffc00b31);
++    c->h[5] = U64(0x8eb44a8768581511);
++    c->h[6] = U64(0xdb0c2e0d64f98fa7);
++    c->h[7] = U64(0x47b5481dbefa4fa4);
++
++    c->Nl = 0;
++    c->Nh = 0;
++    c->num = 0;
++    c->md_len = SHA384_DIGEST_LENGTH;
++    return 1;
++}
++
++int SHA512_Init(SHA512_CTX *c)
++{
++    c->h[0] = U64(0x6a09e667f3bcc908);
++    c->h[1] = U64(0xbb67ae8584caa73b);
++    c->h[2] = U64(0x3c6ef372fe94f82b);
++    c->h[3] = U64(0xa54ff53a5f1d36f1);
++    c->h[4] = U64(0x510e527fade682d1);
++    c->h[5] = U64(0x9b05688c2b3e6c1f);
++    c->h[6] = U64(0x1f83d9abfb41bd6b);
++    c->h[7] = U64(0x5be0cd19137e2179);
++
++    c->Nl = 0;
++    c->Nh = 0;
++    c->num = 0;
++    c->md_len = SHA512_DIGEST_LENGTH;
++    return 1;
++}
++
++#ifndef SHA512_ASM
++static
++#endif
++void sha512_block_data_order(SHA512_CTX *ctx, const void *in, size_t num);
++
++int SHA512_Final(unsigned char *md, SHA512_CTX *c)
++{
++    unsigned char *p = (unsigned char *)c->u.p;
++    size_t n = c->num;
++
++    p[n] = 0x80;                /* There always is a room for one */
++    n++;
++    if (n > (sizeof(c->u) - 16)) {
++        memset(p + n, 0, sizeof(c->u) - n);
++        n = 0;
++        sha512_block_data_order(c, p, 1);
++    }
++
++    memset(p + n, 0, sizeof(c->u) - 16 - n);
++#ifdef  B_ENDIAN
++    c->u.d[SHA_LBLOCK - 2] = c->Nh;
++    c->u.d[SHA_LBLOCK - 1] = c->Nl;
++#else
++    p[sizeof(c->u) - 1] = (unsigned char)(c->Nl);
++    p[sizeof(c->u) - 2] = (unsigned char)(c->Nl >> 8);
++    p[sizeof(c->u) - 3] = (unsigned char)(c->Nl >> 16);
++    p[sizeof(c->u) - 4] = (unsigned char)(c->Nl >> 24);
++    p[sizeof(c->u) - 5] = (unsigned char)(c->Nl >> 32);
++    p[sizeof(c->u) - 6] = (unsigned char)(c->Nl >> 40);
++    p[sizeof(c->u) - 7] = (unsigned char)(c->Nl >> 48);
++    p[sizeof(c->u) - 8] = (unsigned char)(c->Nl >> 56);
++    p[sizeof(c->u) - 9] = (unsigned char)(c->Nh);
++    p[sizeof(c->u) - 10] = (unsigned char)(c->Nh >> 8);
++    p[sizeof(c->u) - 11] = (unsigned char)(c->Nh >> 16);
++    p[sizeof(c->u) - 12] = (unsigned char)(c->Nh >> 24);
++    p[sizeof(c->u) - 13] = (unsigned char)(c->Nh >> 32);
++    p[sizeof(c->u) - 14] = (unsigned char)(c->Nh >> 40);
++    p[sizeof(c->u) - 15] = (unsigned char)(c->Nh >> 48);
++    p[sizeof(c->u) - 16] = (unsigned char)(c->Nh >> 56);
++#endif
++
++    sha512_block_data_order(c, p, 1);
++
++    if (md == 0)
++        return 0;
++
++    switch (c->md_len) {
++        /* Let compiler decide if it's appropriate to unroll... */
++    case SHA384_DIGEST_LENGTH:
++        for (n = 0; n < SHA384_DIGEST_LENGTH / 8; n++) {
++            SHA_LONG64 t = c->h[n];
++
++            *(md++) = (unsigned char)(t >> 56);
++            *(md++) = (unsigned char)(t >> 48);
++            *(md++) = (unsigned char)(t >> 40);
++            *(md++) = (unsigned char)(t >> 32);
++            *(md++) = (unsigned char)(t >> 24);
++            *(md++) = (unsigned char)(t >> 16);
++            *(md++) = (unsigned char)(t >> 8);
++            *(md++) = (unsigned char)(t);
++        }
++        break;
++    case SHA512_DIGEST_LENGTH:
++        for (n = 0; n < SHA512_DIGEST_LENGTH / 8; n++) {
++            SHA_LONG64 t = c->h[n];
++
++            *(md++) = (unsigned char)(t >> 56);
++            *(md++) = (unsigned char)(t >> 48);
++            *(md++) = (unsigned char)(t >> 40);
++            *(md++) = (unsigned char)(t >> 32);
++            *(md++) = (unsigned char)(t >> 24);
++            *(md++) = (unsigned char)(t >> 16);
++            *(md++) = (unsigned char)(t >> 8);
++            *(md++) = (unsigned char)(t);
++        }
++        break;
++        /* ... as well as make sure md_len is not abused. */
++    default:
++        return 0;
++    }
++
++    return 1;
++}
++
++int SHA384_Final(unsigned char *md, SHA512_CTX *c)
++{
++    return SHA512_Final(md, c);
++}
++
++int SHA512_Update(SHA512_CTX *c, const void *_data, size_t len)
++{
++    SHA_LONG64 l;
++    unsigned char *p = c->u.p;
++    const unsigned char *data = (const unsigned char *)_data;
++
++    if (len == 0)
++        return 1;
++
++    l = (c->Nl + (((SHA_LONG64) len) << 3)) & U64(0xffffffffffffffff);
++    if (l < c->Nl)
++        c->Nh++;
++    if (sizeof(len) >= 8)
++        c->Nh += (((SHA_LONG64) len) >> 61);
++    c->Nl = l;
++
++    if (c->num != 0) {
++        size_t n = sizeof(c->u) - c->num;
++
++        if (len < n) {
++            memcpy(p + c->num, data, len), c->num += (unsigned int)len;
++            return 1;
++        } else {
++            memcpy(p + c->num, data, n), c->num = 0;
++            len -= n, data += n;
++            sha512_block_data_order(c, p, 1);
++        }
++    }
++
++    if (len >= sizeof(c->u)) {
++#ifndef SHA512_BLOCK_CAN_MANAGE_UNALIGNED_DATA
++        if ((size_t)data % sizeof(c->u.d[0]) != 0)
++            while (len >= sizeof(c->u))
++                memcpy(p, data, sizeof(c->u)),
++                    sha512_block_data_order(c, p, 1),
++                    len -= sizeof(c->u), data += sizeof(c->u);
++        else
++#endif
++            sha512_block_data_order(c, data, len / sizeof(c->u)),
++                data += len, len %= sizeof(c->u), data -= len;
++    }
++
++    if (len != 0)
++        memcpy(p, data, len), c->num = (int)len;
++
++    return 1;
++}
++
++int SHA384_Update(SHA512_CTX *c, const void *data, size_t len)
++{
++    return SHA512_Update(c, data, len);
++}
++
++void SHA512_Transform(SHA512_CTX *c, const unsigned char *data)
++{
++#ifndef SHA512_BLOCK_CAN_MANAGE_UNALIGNED_DATA
++    if ((size_t)data % sizeof(c->u.d[0]) != 0)
++        memcpy(c->u.p, data, sizeof(c->u.p)), data = c->u.p;
++#endif
++    sha512_block_data_order(c, data, 1);
++}
++
++unsigned char *SHA384(const unsigned char *d, size_t n, unsigned char *md)
++{
++    SHA512_CTX c;
++    static unsigned char m[SHA384_DIGEST_LENGTH];
++
++    if (md == NULL)
++        md = m;
++    SHA384_Init(&c);
++    SHA512_Update(&c, d, n);
++    SHA512_Final(md, &c);
++    OPENSSL_cleanse(&c, sizeof(c));
++    return (md);
++}
++
++unsigned char *SHA512(const unsigned char *d, size_t n, unsigned char *md)
++{
++    SHA512_CTX c;
++    static unsigned char m[SHA512_DIGEST_LENGTH];
++
++    if (md == NULL)
++        md = m;
++    SHA512_Init(&c);
++    SHA512_Update(&c, d, n);
++    SHA512_Final(md, &c);
++    OPENSSL_cleanse(&c, sizeof(c));
++    return (md);
++}
++
++#ifndef SHA512_ASM
++static const SHA_LONG64 K512[80] = {
++    U64(0x428a2f98d728ae22), U64(0x7137449123ef65cd),
++    U64(0xb5c0fbcfec4d3b2f), U64(0xe9b5dba58189dbbc),
++    U64(0x3956c25bf348b538), U64(0x59f111f1b605d019),
++    U64(0x923f82a4af194f9b), U64(0xab1c5ed5da6d8118),
++    U64(0xd807aa98a3030242), U64(0x12835b0145706fbe),
++    U64(0x243185be4ee4b28c), U64(0x550c7dc3d5ffb4e2),
++    U64(0x72be5d74f27b896f), U64(0x80deb1fe3b1696b1),
++    U64(0x9bdc06a725c71235), U64(0xc19bf174cf692694),
++    U64(0xe49b69c19ef14ad2), U64(0xefbe4786384f25e3),
++    U64(0x0fc19dc68b8cd5b5), U64(0x240ca1cc77ac9c65),
++    U64(0x2de92c6f592b0275), U64(0x4a7484aa6ea6e483),
++    U64(0x5cb0a9dcbd41fbd4), U64(0x76f988da831153b5),
++    U64(0x983e5152ee66dfab), U64(0xa831c66d2db43210),
++    U64(0xb00327c898fb213f), U64(0xbf597fc7beef0ee4),
++    U64(0xc6e00bf33da88fc2), U64(0xd5a79147930aa725),
++    U64(0x06ca6351e003826f), U64(0x142929670a0e6e70),
++    U64(0x27b70a8546d22ffc), U64(0x2e1b21385c26c926),
++    U64(0x4d2c6dfc5ac42aed), U64(0x53380d139d95b3df),
++    U64(0x650a73548baf63de), U64(0x766a0abb3c77b2a8),
++    U64(0x81c2c92e47edaee6), U64(0x92722c851482353b),
++    U64(0xa2bfe8a14cf10364), U64(0xa81a664bbc423001),
++    U64(0xc24b8b70d0f89791), U64(0xc76c51a30654be30),
++    U64(0xd192e819d6ef5218), U64(0xd69906245565a910),
++    U64(0xf40e35855771202a), U64(0x106aa07032bbd1b8),
++    U64(0x19a4c116b8d2d0c8), U64(0x1e376c085141ab53),
++    U64(0x2748774cdf8eeb99), U64(0x34b0bcb5e19b48a8),
++    U64(0x391c0cb3c5c95a63), U64(0x4ed8aa4ae3418acb),
++    U64(0x5b9cca4f7763e373), U64(0x682e6ff3d6b2b8a3),
++    U64(0x748f82ee5defb2fc), U64(0x78a5636f43172f60),
++    U64(0x84c87814a1f0ab72), U64(0x8cc702081a6439ec),
++    U64(0x90befffa23631e28), U64(0xa4506cebde82bde9),
++    U64(0xbef9a3f7b2c67915), U64(0xc67178f2e372532b),
++    U64(0xca273eceea26619c), U64(0xd186b8c721c0c207),
++    U64(0xeada7dd6cde0eb1e), U64(0xf57d4f7fee6ed178),
++    U64(0x06f067aa72176fba), U64(0x0a637dc5a2c898a6),
++    U64(0x113f9804bef90dae), U64(0x1b710b35131c471b),
++    U64(0x28db77f523047d84), U64(0x32caab7b40c72493),
++    U64(0x3c9ebe0a15c9bebc), U64(0x431d67c49c100d4c),
++    U64(0x4cc5d4becb3e42b6), U64(0x597f299cfc657e2a),
++    U64(0x5fcb6fab3ad6faec), U64(0x6c44198c4a475817)
++};
++
++# ifndef PEDANTIC
++#  if defined(__GNUC__) && __GNUC__>=2 && !defined(OPENSSL_NO_ASM) && !defined(OPENSSL_NO_INLINE_ASM)
++#   if defined(__x86_64) || defined(__x86_64__)
++#    define ROTR(a,n)    ({ SHA_LONG64 ret;              \
++                                asm ("rorq %1,%0"       \
++                                : "=r"(ret)             \
++                                : "J"(n),"0"(a)         \
++                                : "cc"); ret;           })
++#    if !defined(B_ENDIAN)
++#     define PULL64(x) ({ SHA_LONG64 ret=*((const SHA_LONG64 *)(&(x)));  \
++                                asm ("bswapq    %0"             \
++                                : "=r"(ret)                     \
++                                : "0"(ret)); ret;               })
++#    endif
++#   elif (defined(__i386) || defined(__i386__)) && !defined(B_ENDIAN)
++#    if defined(I386_ONLY)
++#     define PULL64(x) ({ const unsigned int *p=(const unsigned int *)(&(x));\
++                         unsigned int hi=p[0],lo=p[1];          \
++                                asm("xchgb %%ah,%%al;xchgb %%dh,%%dl;"\
++                                    "roll $16,%%eax; roll $16,%%edx; "\
++                                    "xchgb %%ah,%%al;xchgb %%dh,%%dl;" \
++                                : "=a"(lo),"=d"(hi)             \
++                                : "0"(lo),"1"(hi) : "cc");      \
++                                ((SHA_LONG64)hi)<<32|lo;        })
++#    else
++#     define PULL64(x) ({ const unsigned int *p=(const unsigned int *)(&(x));\
++                         unsigned int hi=p[0],lo=p[1];          \
++                                asm ("bswapl %0; bswapl %1;"    \
++                                : "=r"(lo),"=r"(hi)             \
++                                : "0"(lo),"1"(hi));             \
++                                ((SHA_LONG64)hi)<<32|lo;        })
++#    endif
++#   elif (defined(_ARCH_PPC) && defined(__64BIT__)) || defined(_ARCH_PPC64)
++#    define ROTR(a,n)    ({ SHA_LONG64 ret;              \
++                                asm ("rotrdi %0,%1,%2"  \
++                                : "=r"(ret)             \
++                                : "r"(a),"K"(n)); ret;  })
++#   elif defined(__aarch64__)
++#    define ROTR(a,n)    ({ SHA_LONG64 ret;              \
++                                asm ("ror %0,%1,%2"     \
++                                : "=r"(ret)             \
++                                : "r"(a),"I"(n)); ret;  })
++#    if  defined(__BYTE_ORDER__) && defined(__ORDER_LITTLE_ENDIAN__) && \
++        __BYTE_ORDER__==__ORDER_LITTLE_ENDIAN__
++#     define PULL64(x)   ({ SHA_LONG64 ret;                      \
++                                asm ("rev       %0,%1"          \
++                                : "=r"(ret)                     \
++                                : "r"(*((const SHA_LONG64 *)(&(x))))); ret;             })
++#    endif
++#   endif
++#  elif defined(_MSC_VER)
++#   if defined(_WIN64)         /* applies to both IA-64 and AMD64 */
++#    pragma intrinsic(_rotr64)
++#    define ROTR(a,n)    _rotr64((a),n)
++#   endif
++#   if defined(_M_IX86) && !defined(OPENSSL_NO_ASM) && !defined(OPENSSL_NO_INLINE_ASM)
++#    if defined(I386_ONLY)
++static SHA_LONG64 __fastcall __pull64be(const void *x)
++{
++    _asm mov edx,[ecx + 0]
++    _asm mov eax,[ecx + 4]
++_asm xchg dh, dl
++        _asm xchg ah, al
++        _asm rol edx, 16 _asm rol eax, 16 _asm xchg dh, dl _asm xchg ah, al}
++#    else
++static SHA_LONG64 __fastcall __pull64be(const void *x)
++{
++    _asm mov edx,[ecx + 0]
++    _asm mov eax,[ecx + 4]
++_asm bswap edx _asm bswap eax}
++#    endif
++#    define PULL64(x) __pull64be(&(x))
++#    if _MSC_VER<=1200
++#     pragma inline_depth(0)
++#    endif
++#   endif
++#  endif
++# endif
++# ifndef PULL64
++#  define B(x,j)    (((SHA_LONG64)(*(((const unsigned char *)(&x))+j)))<<((7-j)*8))
++#  define PULL64(x) (B(x,0)|B(x,1)|B(x,2)|B(x,3)|B(x,4)|B(x,5)|B(x,6)|B(x,7))
++# endif
++# ifndef ROTR
++#  define ROTR(x,s)       (((x)>>s) | (x)<<(64-s))
++# endif
++# define Sigma0(x)       (ROTR((x),28) ^ ROTR((x),34) ^ ROTR((x),39))
++# define Sigma1(x)       (ROTR((x),14) ^ ROTR((x),18) ^ ROTR((x),41))
++# define sigma0(x)       (ROTR((x),1)  ^ ROTR((x),8)  ^ ((x)>>7))
++# define sigma1(x)       (ROTR((x),19) ^ ROTR((x),61) ^ ((x)>>6))
++# define Ch(x,y,z)       (((x) & (y)) ^ ((~(x)) & (z)))
++# define Maj(x,y,z)      (((x) & (y)) ^ ((x) & (z)) ^ ((y) & (z)))
++# if defined(__i386) || defined(__i386__) || defined(_M_IX86)
++/*
++ * This code should give better results on 32-bit CPU with less than
++ * ~24 registers, both size and performance wise...
++ */ static void sha512_block_data_order(SHA512_CTX *ctx, const void *in,
++                                        size_t num)
++{
++    const SHA_LONG64 *W = in;
++    SHA_LONG64 A, E, T;
++    SHA_LONG64 X[9 + 80], *F;
++    int i;
++
++    while (num--) {
++
++        F = X + 80;
++        A = ctx->h[0];
++        F[1] = ctx->h[1];
++        F[2] = ctx->h[2];
++        F[3] = ctx->h[3];
++        E = ctx->h[4];
++        F[5] = ctx->h[5];
++        F[6] = ctx->h[6];
++        F[7] = ctx->h[7];
++
++        for (i = 0; i < 16; i++, F--) {
++#  ifdef B_ENDIAN
++            T = W[i];
++#  else
++            T = PULL64(W[i]);
++#  endif
++            F[0] = A;
++            F[4] = E;
++            F[8] = T;
++            T += F[7] + Sigma1(E) + Ch(E, F[5], F[6]) + K512[i];
++            E = F[3] + T;
++            A = T + Sigma0(A) + Maj(A, F[1], F[2]);
++        }
++
++        for (; i < 80; i++, F--) {
++            T = sigma0(F[8 + 16 - 1]);
++            T += sigma1(F[8 + 16 - 14]);
++            T += F[8 + 16] + F[8 + 16 - 9];
++
++            F[0] = A;
++            F[4] = E;
++            F[8] = T;
++            T += F[7] + Sigma1(E) + Ch(E, F[5], F[6]) + K512[i];
++            E = F[3] + T;
++            A = T + Sigma0(A) + Maj(A, F[1], F[2]);
++        }
++
++        ctx->h[0] += A;
++        ctx->h[1] += F[1];
++        ctx->h[2] += F[2];
++        ctx->h[3] += F[3];
++        ctx->h[4] += E;
++        ctx->h[5] += F[5];
++        ctx->h[6] += F[6];
++        ctx->h[7] += F[7];
++
++        W += SHA_LBLOCK;
++    }
++}
++
++# elif defined(OPENSSL_SMALL_FOOTPRINT)
++static void sha512_block_data_order(SHA512_CTX *ctx, const void *in,
++                                    size_t num)
++{
++    const SHA_LONG64 *W = in;
++    SHA_LONG64 a, b, c, d, e, f, g, h, s0, s1, T1, T2;
++    SHA_LONG64 X[16];
++    int i;
++
++    while (num--) {
++
++        a = ctx->h[0];
++        b = ctx->h[1];
++        c = ctx->h[2];
++        d = ctx->h[3];
++        e = ctx->h[4];
++        f = ctx->h[5];
++        g = ctx->h[6];
++        h = ctx->h[7];
++
++        for (i = 0; i < 16; i++) {
++#  ifdef B_ENDIAN
++            T1 = X[i] = W[i];
++#  else
++            T1 = X[i] = PULL64(W[i]);
++#  endif
++            T1 += h + Sigma1(e) + Ch(e, f, g) + K512[i];
++            T2 = Sigma0(a) + Maj(a, b, c);
++            h = g;
++            g = f;
++            f = e;
++            e = d + T1;
++            d = c;
++            c = b;
++            b = a;
++            a = T1 + T2;
++        }
++
++        for (; i < 80; i++) {
++            s0 = X[(i + 1) & 0x0f];
++            s0 = sigma0(s0);
++            s1 = X[(i + 14) & 0x0f];
++            s1 = sigma1(s1);
++
++            T1 = X[i & 0xf] += s0 + s1 + X[(i + 9) & 0xf];
++            T1 += h + Sigma1(e) + Ch(e, f, g) + K512[i];
++            T2 = Sigma0(a) + Maj(a, b, c);
++            h = g;
++            g = f;
++            f = e;
++            e = d + T1;
++            d = c;
++            c = b;
++            b = a;
++            a = T1 + T2;
++        }
++
++        ctx->h[0] += a;
++        ctx->h[1] += b;
++        ctx->h[2] += c;
++        ctx->h[3] += d;
++        ctx->h[4] += e;
++        ctx->h[5] += f;
++        ctx->h[6] += g;
++        ctx->h[7] += h;
++
++        W += SHA_LBLOCK;
++    }
++}
++
++# else
++#  define ROUND_00_15(i,a,b,c,d,e,f,g,h)          do {    \
++        T1 += h + Sigma1(e) + Ch(e,f,g) + K512[i];      \
++        h = Sigma0(a) + Maj(a,b,c);                     \
++        d += T1;        h += T1;                } while (0)
++#  define ROUND_16_80(i,j,a,b,c,d,e,f,g,h,X)      do {    \
++        s0 = X[(j+1)&0x0f];     s0 = sigma0(s0);        \
++        s1 = X[(j+14)&0x0f];    s1 = sigma1(s1);        \
++        T1 = X[(j)&0x0f] += s0 + s1 + X[(j+9)&0x0f];    \
++        ROUND_00_15(i+j,a,b,c,d,e,f,g,h);               } while (0)
++static void sha512_block_data_order(SHA512_CTX *ctx, const void *in,
++                                    size_t num)
++{
++    const SHA_LONG64 *W = in;
++    SHA_LONG64 a, b, c, d, e, f, g, h, s0, s1, T1;
++    SHA_LONG64 X[16];
++    int i;
++
++    while (num--) {
++
++        a = ctx->h[0];
++        b = ctx->h[1];
++        c = ctx->h[2];
++        d = ctx->h[3];
++        e = ctx->h[4];
++        f = ctx->h[5];
++        g = ctx->h[6];
++        h = ctx->h[7];
++
++#  ifdef B_ENDIAN
++        T1 = X[0] = W[0];
++        ROUND_00_15(0, a, b, c, d, e, f, g, h);
++        T1 = X[1] = W[1];
++        ROUND_00_15(1, h, a, b, c, d, e, f, g);
++        T1 = X[2] = W[2];
++        ROUND_00_15(2, g, h, a, b, c, d, e, f);
++        T1 = X[3] = W[3];
++        ROUND_00_15(3, f, g, h, a, b, c, d, e);
++        T1 = X[4] = W[4];
++        ROUND_00_15(4, e, f, g, h, a, b, c, d);
++        T1 = X[5] = W[5];
++        ROUND_00_15(5, d, e, f, g, h, a, b, c);
++        T1 = X[6] = W[6];
++        ROUND_00_15(6, c, d, e, f, g, h, a, b);
++        T1 = X[7] = W[7];
++        ROUND_00_15(7, b, c, d, e, f, g, h, a);
++        T1 = X[8] = W[8];
++        ROUND_00_15(8, a, b, c, d, e, f, g, h);
++        T1 = X[9] = W[9];
++        ROUND_00_15(9, h, a, b, c, d, e, f, g);
++        T1 = X[10] = W[10];
++        ROUND_00_15(10, g, h, a, b, c, d, e, f);
++        T1 = X[11] = W[11];
++        ROUND_00_15(11, f, g, h, a, b, c, d, e);
++        T1 = X[12] = W[12];
++        ROUND_00_15(12, e, f, g, h, a, b, c, d);
++        T1 = X[13] = W[13];
++        ROUND_00_15(13, d, e, f, g, h, a, b, c);
++        T1 = X[14] = W[14];
++        ROUND_00_15(14, c, d, e, f, g, h, a, b);
++        T1 = X[15] = W[15];
++        ROUND_00_15(15, b, c, d, e, f, g, h, a);
++#  else
++        T1 = X[0] = PULL64(W[0]);
++        ROUND_00_15(0, a, b, c, d, e, f, g, h);
++        T1 = X[1] = PULL64(W[1]);
++        ROUND_00_15(1, h, a, b, c, d, e, f, g);
++        T1 = X[2] = PULL64(W[2]);
++        ROUND_00_15(2, g, h, a, b, c, d, e, f);
++        T1 = X[3] = PULL64(W[3]);
++        ROUND_00_15(3, f, g, h, a, b, c, d, e);
++        T1 = X[4] = PULL64(W[4]);
++        ROUND_00_15(4, e, f, g, h, a, b, c, d);
++        T1 = X[5] = PULL64(W[5]);
++        ROUND_00_15(5, d, e, f, g, h, a, b, c);
++        T1 = X[6] = PULL64(W[6]);
++        ROUND_00_15(6, c, d, e, f, g, h, a, b);
++        T1 = X[7] = PULL64(W[7]);
++        ROUND_00_15(7, b, c, d, e, f, g, h, a);
++        T1 = X[8] = PULL64(W[8]);
++        ROUND_00_15(8, a, b, c, d, e, f, g, h);
++        T1 = X[9] = PULL64(W[9]);
++        ROUND_00_15(9, h, a, b, c, d, e, f, g);
++        T1 = X[10] = PULL64(W[10]);
++        ROUND_00_15(10, g, h, a, b, c, d, e, f);
++        T1 = X[11] = PULL64(W[11]);
++        ROUND_00_15(11, f, g, h, a, b, c, d, e);
++        T1 = X[12] = PULL64(W[12]);
++        ROUND_00_15(12, e, f, g, h, a, b, c, d);
++        T1 = X[13] = PULL64(W[13]);
++        ROUND_00_15(13, d, e, f, g, h, a, b, c);
++        T1 = X[14] = PULL64(W[14]);
++        ROUND_00_15(14, c, d, e, f, g, h, a, b);
++        T1 = X[15] = PULL64(W[15]);
++        ROUND_00_15(15, b, c, d, e, f, g, h, a);
++#  endif
++
++        for (i = 16; i < 80; i += 16) {
++            ROUND_16_80(i, 0, a, b, c, d, e, f, g, h, X);
++            ROUND_16_80(i, 1, h, a, b, c, d, e, f, g, X);
++            ROUND_16_80(i, 2, g, h, a, b, c, d, e, f, X);
++            ROUND_16_80(i, 3, f, g, h, a, b, c, d, e, X);
++            ROUND_16_80(i, 4, e, f, g, h, a, b, c, d, X);
++            ROUND_16_80(i, 5, d, e, f, g, h, a, b, c, X);
++            ROUND_16_80(i, 6, c, d, e, f, g, h, a, b, X);
++            ROUND_16_80(i, 7, b, c, d, e, f, g, h, a, X);
++            ROUND_16_80(i, 8, a, b, c, d, e, f, g, h, X);
++            ROUND_16_80(i, 9, h, a, b, c, d, e, f, g, X);
++            ROUND_16_80(i, 10, g, h, a, b, c, d, e, f, X);
++            ROUND_16_80(i, 11, f, g, h, a, b, c, d, e, X);
++            ROUND_16_80(i, 12, e, f, g, h, a, b, c, d, X);
++            ROUND_16_80(i, 13, d, e, f, g, h, a, b, c, X);
++            ROUND_16_80(i, 14, c, d, e, f, g, h, a, b, X);
++            ROUND_16_80(i, 15, b, c, d, e, f, g, h, a, X);
++        }
++
++        ctx->h[0] += a;
++        ctx->h[1] += b;
++        ctx->h[2] += c;
++        ctx->h[3] += d;
++        ctx->h[4] += e;
++        ctx->h[5] += f;
++        ctx->h[6] += g;
++        ctx->h[7] += h;
++
++        W += SHA_LBLOCK;
++    }
++}
++
++# endif
++
++#endif                         /* SHA512_ASM */
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/sha/sha_locl.h b/CryptoPkg/Library/OpensslLib/openssl/crypto/sha/sha_locl.h
+new file mode 100644
+index 0000000..918278a
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/sha/sha_locl.h
+@@ -0,0 +1,424 @@
++/*
++ * Copyright 1995-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include 
++
++#include 
++#include 
++
++#define DATA_ORDER_IS_BIG_ENDIAN
++
++#define HASH_LONG               SHA_LONG
++#define HASH_CTX                SHA_CTX
++#define HASH_CBLOCK             SHA_CBLOCK
++#define HASH_MAKE_STRING(c,s)   do {    \
++        unsigned long ll;               \
++        ll=(c)->h0; (void)HOST_l2c(ll,(s));     \
++        ll=(c)->h1; (void)HOST_l2c(ll,(s));     \
++        ll=(c)->h2; (void)HOST_l2c(ll,(s));     \
++        ll=(c)->h3; (void)HOST_l2c(ll,(s));     \
++        ll=(c)->h4; (void)HOST_l2c(ll,(s));     \
++        } while (0)
++
++#define HASH_UPDATE                     SHA1_Update
++#define HASH_TRANSFORM                  SHA1_Transform
++#define HASH_FINAL                      SHA1_Final
++#define HASH_INIT                       SHA1_Init
++#define HASH_BLOCK_DATA_ORDER           sha1_block_data_order
++#define Xupdate(a,ix,ia,ib,ic,id)       ( (a)=(ia^ib^ic^id),    \
++                                          ix=(a)=ROTATE((a),1)  \
++                                        )
++
++#ifndef SHA1_ASM
++static void sha1_block_data_order(SHA_CTX *c, const void *p, size_t num);
++#else
++void sha1_block_data_order(SHA_CTX *c, const void *p, size_t num);
++#endif
++
++#include "internal/md32_common.h"
++
++#define INIT_DATA_h0 0x67452301UL
++#define INIT_DATA_h1 0xefcdab89UL
++#define INIT_DATA_h2 0x98badcfeUL
++#define INIT_DATA_h3 0x10325476UL
++#define INIT_DATA_h4 0xc3d2e1f0UL
++
++int HASH_INIT(SHA_CTX *c)
++{
++    memset(c, 0, sizeof(*c));
++    c->h0 = INIT_DATA_h0;
++    c->h1 = INIT_DATA_h1;
++    c->h2 = INIT_DATA_h2;
++    c->h3 = INIT_DATA_h3;
++    c->h4 = INIT_DATA_h4;
++    return 1;
++}
++
++#define K_00_19 0x5a827999UL
++#define K_20_39 0x6ed9eba1UL
++#define K_40_59 0x8f1bbcdcUL
++#define K_60_79 0xca62c1d6UL
++
++/*
++ * As pointed out by Wei Dai , F() below can be simplified
++ * to the code in F_00_19.  Wei attributes these optimisations to Peter
++ * Gutmann's SHS code, and he attributes it to Rich Schroeppel. #define
++ * F(x,y,z) (((x) & (y)) | ((~(x)) & (z))) I've just become aware of another
++ * tweak to be made, again from Wei Dai, in F_40_59, (x&a)|(y&a) -> (x|y)&a
++ */
++#define F_00_19(b,c,d)  ((((c) ^ (d)) & (b)) ^ (d))
++#define F_20_39(b,c,d)  ((b) ^ (c) ^ (d))
++#define F_40_59(b,c,d)  (((b) & (c)) | (((b)|(c)) & (d)))
++#define F_60_79(b,c,d)  F_20_39(b,c,d)
++
++#ifndef OPENSSL_SMALL_FOOTPRINT
++
++# define BODY_00_15(i,a,b,c,d,e,f,xi) \
++        (f)=xi+(e)+K_00_19+ROTATE((a),5)+F_00_19((b),(c),(d)); \
++        (b)=ROTATE((b),30);
++
++# define BODY_16_19(i,a,b,c,d,e,f,xi,xa,xb,xc,xd) \
++        Xupdate(f,xi,xa,xb,xc,xd); \
++        (f)+=(e)+K_00_19+ROTATE((a),5)+F_00_19((b),(c),(d)); \
++        (b)=ROTATE((b),30);
++
++# define BODY_20_31(i,a,b,c,d,e,f,xi,xa,xb,xc,xd) \
++        Xupdate(f,xi,xa,xb,xc,xd); \
++        (f)+=(e)+K_20_39+ROTATE((a),5)+F_20_39((b),(c),(d)); \
++        (b)=ROTATE((b),30);
++
++# define BODY_32_39(i,a,b,c,d,e,f,xa,xb,xc,xd) \
++        Xupdate(f,xa,xa,xb,xc,xd); \
++        (f)+=(e)+K_20_39+ROTATE((a),5)+F_20_39((b),(c),(d)); \
++        (b)=ROTATE((b),30);
++
++# define BODY_40_59(i,a,b,c,d,e,f,xa,xb,xc,xd) \
++        Xupdate(f,xa,xa,xb,xc,xd); \
++        (f)+=(e)+K_40_59+ROTATE((a),5)+F_40_59((b),(c),(d)); \
++        (b)=ROTATE((b),30);
++
++# define BODY_60_79(i,a,b,c,d,e,f,xa,xb,xc,xd) \
++        Xupdate(f,xa,xa,xb,xc,xd); \
++        (f)=xa+(e)+K_60_79+ROTATE((a),5)+F_60_79((b),(c),(d)); \
++        (b)=ROTATE((b),30);
++
++# ifdef X
++#  undef X
++# endif
++# ifndef MD32_XARRAY
++  /*
++   * Originally X was an array. As it's automatic it's natural
++   * to expect RISC compiler to accommodate at least part of it in
++   * the register bank, isn't it? Unfortunately not all compilers
++   * "find" this expectation reasonable:-( On order to make such
++   * compilers generate better code I replace X[] with a bunch of
++   * X0, X1, etc. See the function body below...
++   *                                    
++   */
++#  define X(i)   XX##i
++# else
++  /*
++   * However! Some compilers (most notably HP C) get overwhelmed by
++   * that many local variables so that we have to have the way to
++   * fall down to the original behavior.
++   */
++#  define X(i)   XX[i]
++# endif
++
++# if !defined(SHA1_ASM)
++static void HASH_BLOCK_DATA_ORDER(SHA_CTX *c, const void *p, size_t num)
++{
++    const unsigned char *data = p;
++    register unsigned MD32_REG_T A, B, C, D, E, T, l;
++#  ifndef MD32_XARRAY
++    unsigned MD32_REG_T XX0, XX1, XX2, XX3, XX4, XX5, XX6, XX7,
++        XX8, XX9, XX10, XX11, XX12, XX13, XX14, XX15;
++#  else
++    SHA_LONG XX[16];
++#  endif
++
++    A = c->h0;
++    B = c->h1;
++    C = c->h2;
++    D = c->h3;
++    E = c->h4;
++
++    for (;;) {
++        const union {
++            long one;
++            char little;
++        } is_endian = {
++            1
++        };
++
++        if (!is_endian.little && sizeof(SHA_LONG) == 4
++            && ((size_t)p % 4) == 0) {
++            const SHA_LONG *W = (const SHA_LONG *)data;
++
++            X(0) = W[0];
++            X(1) = W[1];
++            BODY_00_15(0, A, B, C, D, E, T, X(0));
++            X(2) = W[2];
++            BODY_00_15(1, T, A, B, C, D, E, X(1));
++            X(3) = W[3];
++            BODY_00_15(2, E, T, A, B, C, D, X(2));
++            X(4) = W[4];
++            BODY_00_15(3, D, E, T, A, B, C, X(3));
++            X(5) = W[5];
++            BODY_00_15(4, C, D, E, T, A, B, X(4));
++            X(6) = W[6];
++            BODY_00_15(5, B, C, D, E, T, A, X(5));
++            X(7) = W[7];
++            BODY_00_15(6, A, B, C, D, E, T, X(6));
++            X(8) = W[8];
++            BODY_00_15(7, T, A, B, C, D, E, X(7));
++            X(9) = W[9];
++            BODY_00_15(8, E, T, A, B, C, D, X(8));
++            X(10) = W[10];
++            BODY_00_15(9, D, E, T, A, B, C, X(9));
++            X(11) = W[11];
++            BODY_00_15(10, C, D, E, T, A, B, X(10));
++            X(12) = W[12];
++            BODY_00_15(11, B, C, D, E, T, A, X(11));
++            X(13) = W[13];
++            BODY_00_15(12, A, B, C, D, E, T, X(12));
++            X(14) = W[14];
++            BODY_00_15(13, T, A, B, C, D, E, X(13));
++            X(15) = W[15];
++            BODY_00_15(14, E, T, A, B, C, D, X(14));
++            BODY_00_15(15, D, E, T, A, B, C, X(15));
++
++            data += SHA_CBLOCK;
++        } else {
++            (void)HOST_c2l(data, l);
++            X(0) = l;
++            (void)HOST_c2l(data, l);
++            X(1) = l;
++            BODY_00_15(0, A, B, C, D, E, T, X(0));
++            (void)HOST_c2l(data, l);
++            X(2) = l;
++            BODY_00_15(1, T, A, B, C, D, E, X(1));
++            (void)HOST_c2l(data, l);
++            X(3) = l;
++            BODY_00_15(2, E, T, A, B, C, D, X(2));
++            (void)HOST_c2l(data, l);
++            X(4) = l;
++            BODY_00_15(3, D, E, T, A, B, C, X(3));
++            (void)HOST_c2l(data, l);
++            X(5) = l;
++            BODY_00_15(4, C, D, E, T, A, B, X(4));
++            (void)HOST_c2l(data, l);
++            X(6) = l;
++            BODY_00_15(5, B, C, D, E, T, A, X(5));
++            (void)HOST_c2l(data, l);
++            X(7) = l;
++            BODY_00_15(6, A, B, C, D, E, T, X(6));
++            (void)HOST_c2l(data, l);
++            X(8) = l;
++            BODY_00_15(7, T, A, B, C, D, E, X(7));
++            (void)HOST_c2l(data, l);
++            X(9) = l;
++            BODY_00_15(8, E, T, A, B, C, D, X(8));
++            (void)HOST_c2l(data, l);
++            X(10) = l;
++            BODY_00_15(9, D, E, T, A, B, C, X(9));
++            (void)HOST_c2l(data, l);
++            X(11) = l;
++            BODY_00_15(10, C, D, E, T, A, B, X(10));
++            (void)HOST_c2l(data, l);
++            X(12) = l;
++            BODY_00_15(11, B, C, D, E, T, A, X(11));
++            (void)HOST_c2l(data, l);
++            X(13) = l;
++            BODY_00_15(12, A, B, C, D, E, T, X(12));
++            (void)HOST_c2l(data, l);
++            X(14) = l;
++            BODY_00_15(13, T, A, B, C, D, E, X(13));
++            (void)HOST_c2l(data, l);
++            X(15) = l;
++            BODY_00_15(14, E, T, A, B, C, D, X(14));
++            BODY_00_15(15, D, E, T, A, B, C, X(15));
++        }
++
++        BODY_16_19(16, C, D, E, T, A, B, X(0), X(0), X(2), X(8), X(13));
++        BODY_16_19(17, B, C, D, E, T, A, X(1), X(1), X(3), X(9), X(14));
++        BODY_16_19(18, A, B, C, D, E, T, X(2), X(2), X(4), X(10), X(15));
++        BODY_16_19(19, T, A, B, C, D, E, X(3), X(3), X(5), X(11), X(0));
++
++        BODY_20_31(20, E, T, A, B, C, D, X(4), X(4), X(6), X(12), X(1));
++        BODY_20_31(21, D, E, T, A, B, C, X(5), X(5), X(7), X(13), X(2));
++        BODY_20_31(22, C, D, E, T, A, B, X(6), X(6), X(8), X(14), X(3));
++        BODY_20_31(23, B, C, D, E, T, A, X(7), X(7), X(9), X(15), X(4));
++        BODY_20_31(24, A, B, C, D, E, T, X(8), X(8), X(10), X(0), X(5));
++        BODY_20_31(25, T, A, B, C, D, E, X(9), X(9), X(11), X(1), X(6));
++        BODY_20_31(26, E, T, A, B, C, D, X(10), X(10), X(12), X(2), X(7));
++        BODY_20_31(27, D, E, T, A, B, C, X(11), X(11), X(13), X(3), X(8));
++        BODY_20_31(28, C, D, E, T, A, B, X(12), X(12), X(14), X(4), X(9));
++        BODY_20_31(29, B, C, D, E, T, A, X(13), X(13), X(15), X(5), X(10));
++        BODY_20_31(30, A, B, C, D, E, T, X(14), X(14), X(0), X(6), X(11));
++        BODY_20_31(31, T, A, B, C, D, E, X(15), X(15), X(1), X(7), X(12));
++
++        BODY_32_39(32, E, T, A, B, C, D, X(0), X(2), X(8), X(13));
++        BODY_32_39(33, D, E, T, A, B, C, X(1), X(3), X(9), X(14));
++        BODY_32_39(34, C, D, E, T, A, B, X(2), X(4), X(10), X(15));
++        BODY_32_39(35, B, C, D, E, T, A, X(3), X(5), X(11), X(0));
++        BODY_32_39(36, A, B, C, D, E, T, X(4), X(6), X(12), X(1));
++        BODY_32_39(37, T, A, B, C, D, E, X(5), X(7), X(13), X(2));
++        BODY_32_39(38, E, T, A, B, C, D, X(6), X(8), X(14), X(3));
++        BODY_32_39(39, D, E, T, A, B, C, X(7), X(9), X(15), X(4));
++
++        BODY_40_59(40, C, D, E, T, A, B, X(8), X(10), X(0), X(5));
++        BODY_40_59(41, B, C, D, E, T, A, X(9), X(11), X(1), X(6));
++        BODY_40_59(42, A, B, C, D, E, T, X(10), X(12), X(2), X(7));
++        BODY_40_59(43, T, A, B, C, D, E, X(11), X(13), X(3), X(8));
++        BODY_40_59(44, E, T, A, B, C, D, X(12), X(14), X(4), X(9));
++        BODY_40_59(45, D, E, T, A, B, C, X(13), X(15), X(5), X(10));
++        BODY_40_59(46, C, D, E, T, A, B, X(14), X(0), X(6), X(11));
++        BODY_40_59(47, B, C, D, E, T, A, X(15), X(1), X(7), X(12));
++        BODY_40_59(48, A, B, C, D, E, T, X(0), X(2), X(8), X(13));
++        BODY_40_59(49, T, A, B, C, D, E, X(1), X(3), X(9), X(14));
++        BODY_40_59(50, E, T, A, B, C, D, X(2), X(4), X(10), X(15));
++        BODY_40_59(51, D, E, T, A, B, C, X(3), X(5), X(11), X(0));
++        BODY_40_59(52, C, D, E, T, A, B, X(4), X(6), X(12), X(1));
++        BODY_40_59(53, B, C, D, E, T, A, X(5), X(7), X(13), X(2));
++        BODY_40_59(54, A, B, C, D, E, T, X(6), X(8), X(14), X(3));
++        BODY_40_59(55, T, A, B, C, D, E, X(7), X(9), X(15), X(4));
++        BODY_40_59(56, E, T, A, B, C, D, X(8), X(10), X(0), X(5));
++        BODY_40_59(57, D, E, T, A, B, C, X(9), X(11), X(1), X(6));
++        BODY_40_59(58, C, D, E, T, A, B, X(10), X(12), X(2), X(7));
++        BODY_40_59(59, B, C, D, E, T, A, X(11), X(13), X(3), X(8));
++
++        BODY_60_79(60, A, B, C, D, E, T, X(12), X(14), X(4), X(9));
++        BODY_60_79(61, T, A, B, C, D, E, X(13), X(15), X(5), X(10));
++        BODY_60_79(62, E, T, A, B, C, D, X(14), X(0), X(6), X(11));
++        BODY_60_79(63, D, E, T, A, B, C, X(15), X(1), X(7), X(12));
++        BODY_60_79(64, C, D, E, T, A, B, X(0), X(2), X(8), X(13));
++        BODY_60_79(65, B, C, D, E, T, A, X(1), X(3), X(9), X(14));
++        BODY_60_79(66, A, B, C, D, E, T, X(2), X(4), X(10), X(15));
++        BODY_60_79(67, T, A, B, C, D, E, X(3), X(5), X(11), X(0));
++        BODY_60_79(68, E, T, A, B, C, D, X(4), X(6), X(12), X(1));
++        BODY_60_79(69, D, E, T, A, B, C, X(5), X(7), X(13), X(2));
++        BODY_60_79(70, C, D, E, T, A, B, X(6), X(8), X(14), X(3));
++        BODY_60_79(71, B, C, D, E, T, A, X(7), X(9), X(15), X(4));
++        BODY_60_79(72, A, B, C, D, E, T, X(8), X(10), X(0), X(5));
++        BODY_60_79(73, T, A, B, C, D, E, X(9), X(11), X(1), X(6));
++        BODY_60_79(74, E, T, A, B, C, D, X(10), X(12), X(2), X(7));
++        BODY_60_79(75, D, E, T, A, B, C, X(11), X(13), X(3), X(8));
++        BODY_60_79(76, C, D, E, T, A, B, X(12), X(14), X(4), X(9));
++        BODY_60_79(77, B, C, D, E, T, A, X(13), X(15), X(5), X(10));
++        BODY_60_79(78, A, B, C, D, E, T, X(14), X(0), X(6), X(11));
++        BODY_60_79(79, T, A, B, C, D, E, X(15), X(1), X(7), X(12));
++
++        c->h0 = (c->h0 + E) & 0xffffffffL;
++        c->h1 = (c->h1 + T) & 0xffffffffL;
++        c->h2 = (c->h2 + A) & 0xffffffffL;
++        c->h3 = (c->h3 + B) & 0xffffffffL;
++        c->h4 = (c->h4 + C) & 0xffffffffL;
++
++        if (--num == 0)
++            break;
++
++        A = c->h0;
++        B = c->h1;
++        C = c->h2;
++        D = c->h3;
++        E = c->h4;
++
++    }
++}
++# endif
++
++#else                           /* OPENSSL_SMALL_FOOTPRINT */
++
++# define BODY_00_15(xi)           do {   \
++        T=E+K_00_19+F_00_19(B,C,D);     \
++        E=D, D=C, C=ROTATE(B,30), B=A;  \
++        A=ROTATE(A,5)+T+xi;         } while(0)
++
++# define BODY_16_19(xa,xb,xc,xd)  do {   \
++        Xupdate(T,xa,xa,xb,xc,xd);      \
++        T+=E+K_00_19+F_00_19(B,C,D);    \
++        E=D, D=C, C=ROTATE(B,30), B=A;  \
++        A=ROTATE(A,5)+T;            } while(0)
++
++# define BODY_20_39(xa,xb,xc,xd)  do {   \
++        Xupdate(T,xa,xa,xb,xc,xd);      \
++        T+=E+K_20_39+F_20_39(B,C,D);    \
++        E=D, D=C, C=ROTATE(B,30), B=A;  \
++        A=ROTATE(A,5)+T;            } while(0)
++
++# define BODY_40_59(xa,xb,xc,xd)  do {   \
++        Xupdate(T,xa,xa,xb,xc,xd);      \
++        T+=E+K_40_59+F_40_59(B,C,D);    \
++        E=D, D=C, C=ROTATE(B,30), B=A;  \
++        A=ROTATE(A,5)+T;            } while(0)
++
++# define BODY_60_79(xa,xb,xc,xd)  do {   \
++        Xupdate(T,xa,xa,xb,xc,xd);      \
++        T=E+K_60_79+F_60_79(B,C,D);     \
++        E=D, D=C, C=ROTATE(B,30), B=A;  \
++        A=ROTATE(A,5)+T+xa;         } while(0)
++
++# if !defined(SHA1_ASM)
++static void HASH_BLOCK_DATA_ORDER(SHA_CTX *c, const void *p, size_t num)
++{
++    const unsigned char *data = p;
++    register unsigned MD32_REG_T A, B, C, D, E, T, l;
++    int i;
++    SHA_LONG X[16];
++
++    A = c->h0;
++    B = c->h1;
++    C = c->h2;
++    D = c->h3;
++    E = c->h4;
++
++    for (;;) {
++        for (i = 0; i < 16; i++) {
++            (void)HOST_c2l(data, l);
++            X[i] = l;
++            BODY_00_15(X[i]);
++        }
++        for (i = 0; i < 4; i++) {
++            BODY_16_19(X[i], X[i + 2], X[i + 8], X[(i + 13) & 15]);
++        }
++        for (; i < 24; i++) {
++            BODY_20_39(X[i & 15], X[(i + 2) & 15], X[(i + 8) & 15],
++                       X[(i + 13) & 15]);
++        }
++        for (i = 0; i < 20; i++) {
++            BODY_40_59(X[(i + 8) & 15], X[(i + 10) & 15], X[i & 15],
++                       X[(i + 5) & 15]);
++        }
++        for (i = 4; i < 24; i++) {
++            BODY_60_79(X[(i + 8) & 15], X[(i + 10) & 15], X[i & 15],
++                       X[(i + 5) & 15]);
++        }
++
++        c->h0 = (c->h0 + A) & 0xffffffffL;
++        c->h1 = (c->h1 + B) & 0xffffffffL;
++        c->h2 = (c->h2 + C) & 0xffffffffL;
++        c->h3 = (c->h3 + D) & 0xffffffffL;
++        c->h4 = (c->h4 + E) & 0xffffffffL;
++
++        if (--num == 0)
++            break;
++
++        A = c->h0;
++        B = c->h1;
++        C = c->h2;
++        D = c->h3;
++        E = c->h4;
++
++    }
++}
++# endif
++
++#endif
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/sparc_arch.h b/CryptoPkg/Library/OpensslLib/openssl/crypto/sparc_arch.h
+new file mode 100644
+index 0000000..99eafb3
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/sparc_arch.h
+@@ -0,0 +1,118 @@
++/*
++ * Copyright 2012-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#ifndef __SPARC_ARCH_H__
++# define __SPARC_ARCH_H__
++
++# define SPARCV9_TICK_PRIVILEGED (1<<0)
++# define SPARCV9_PREFER_FPU      (1<<1)
++# define SPARCV9_VIS1            (1<<2)
++# define SPARCV9_VIS2            (1<<3)/* reserved */
++# define SPARCV9_FMADD           (1<<4)
++# define SPARCV9_BLK             (1<<5)/* VIS1 block copy */
++# define SPARCV9_VIS3            (1<<6)
++# define SPARCV9_RANDOM          (1<<7)
++# define SPARCV9_64BIT_STACK     (1<<8)
++# define SPARCV9_FJAESX          (1<<9)/* Fujitsu SPARC64 X AES */
++# define SPARCV9_FJDESX          (1<<10)/* Fujitsu SPARC64 X DES, reserved */
++# define SPARCV9_FJHPCACE        (1<<11)/* Fujitsu HPC-ACE, reserved */
++# define SPARCV9_IMA             (1<<13)/* reserved */
++# define SPARCV9_VIS4            (1<<14)/* reserved */
++
++/*
++ * OPENSSL_sparcv9cap_P[1] is copy of Compatibility Feature Register,
++ * %asr26, SPARC-T4 and later. There is no SPARCV9_CFR bit in
++ * OPENSSL_sparcv9cap_P[0], as %cfr copy is sufficient...
++ */
++# define CFR_AES         0x00000001/* Supports AES opcodes */
++# define CFR_DES         0x00000002/* Supports DES opcodes */
++# define CFR_KASUMI      0x00000004/* Supports KASUMI opcodes */
++# define CFR_CAMELLIA    0x00000008/* Supports CAMELLIA opcodes */
++# define CFR_MD5         0x00000010/* Supports MD5 opcodes */
++# define CFR_SHA1        0x00000020/* Supports SHA1 opcodes */
++# define CFR_SHA256      0x00000040/* Supports SHA256 opcodes */
++# define CFR_SHA512      0x00000080/* Supports SHA512 opcodes */
++# define CFR_MPMUL       0x00000100/* Supports MPMUL opcodes */
++# define CFR_MONTMUL     0x00000200/* Supports MONTMUL opcodes */
++# define CFR_MONTSQR     0x00000400/* Supports MONTSQR opcodes */
++# define CFR_CRC32C      0x00000800/* Supports CRC32C opcodes */
++# define CFR_XMPMUL      0x00001000/* Supports XMPMUL opcodes */
++# define CFR_XMONTMUL    0x00002000/* Supports XMONTMUL opcodes */
++# define CFR_XMONTSQR    0x00004000/* Supports XMONTSQR opcodes */
++
++# if defined(OPENSSL_PIC) && !defined(__PIC__)
++#  define __PIC__
++# endif
++
++# if defined(__SUNPRO_C) && defined(__sparcv9) && !defined(__arch64__)
++#  define __arch64__
++# endif
++
++# define SPARC_PIC_THUNK(reg)    \
++        .align  32;             \
++.Lpic_thunk:                    \
++        jmp     %o7 + 8;        \
++         add    %o7, reg, reg;
++
++# define SPARC_PIC_THUNK_CALL(reg)                       \
++        sethi   %hi(_GLOBAL_OFFSET_TABLE_-4), reg;      \
++        call    .Lpic_thunk;                            \
++         or     reg, %lo(_GLOBAL_OFFSET_TABLE_+4), reg;
++
++# if 1
++#  define SPARC_SETUP_GOT_REG(reg)       SPARC_PIC_THUNK_CALL(reg)
++# else
++#  define SPARC_SETUP_GOT_REG(reg)       \
++        sethi   %hi(_GLOBAL_OFFSET_TABLE_-4), reg;      \
++        call    .+8;                                    \
++        or      reg,%lo(_GLOBAL_OFFSET_TABLE_+4), reg;  \
++        add     %o7, reg, reg
++# endif
++
++# if defined(__arch64__)
++
++#  define SPARC_LOAD_ADDRESS(SYM, reg)   \
++        setx    SYM, %o7, reg;
++#  define LDPTR          ldx
++#  define SIZE_T_CC      %xcc
++#  define STACK_FRAME    192
++#  define STACK_BIAS     2047
++#  define STACK_7thARG   (STACK_BIAS+176)
++
++# else
++
++#  define SPARC_LOAD_ADDRESS(SYM, reg)   \
++        set     SYM, reg;
++#  define LDPTR          ld
++#  define SIZE_T_CC      %icc
++#  define STACK_FRAME    112
++#  define STACK_BIAS     0
++#  define STACK_7thARG   92
++#  define SPARC_LOAD_ADDRESS_LEAF(SYM,reg,tmp) SPARC_LOAD_ADDRESS(SYM,reg)
++
++# endif
++
++# ifdef __PIC__
++#  undef SPARC_LOAD_ADDRESS
++#  undef SPARC_LOAD_ADDRESS_LEAF
++#  define SPARC_LOAD_ADDRESS(SYM, reg)   \
++        SPARC_SETUP_GOT_REG(reg);       \
++        sethi   %hi(SYM), %o7;          \
++        or      %o7, %lo(SYM), %o7;     \
++        LDPTR   [reg + %o7], reg;
++# endif
++
++# ifndef SPARC_LOAD_ADDRESS_LEAF
++#  define SPARC_LOAD_ADDRESS_LEAF(SYM, reg, tmp) \
++        mov     %o7, tmp;                       \
++        SPARC_LOAD_ADDRESS(SYM, reg)            \
++        mov     tmp, %o7;
++# endif
++
++#endif                          /* __SPARC_ARCH_H__ */
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/sparccpuid.S b/CryptoPkg/Library/OpensslLib/openssl/crypto/sparccpuid.S
+new file mode 100644
+index 0000000..c6ca224
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/sparccpuid.S
+@@ -0,0 +1,582 @@
++! Copyright 2005-2016 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
++! in the file LICENSE in the source distribution or at
++! https://www.openssl.org/source/license.html
++
++#ifdef OPENSSL_FIPSCANISTER
++#include 
++#endif
++
++#if defined(__SUNPRO_C) && defined(__sparcv9)
++# define ABI64  /* They've said -xarch=v9 at command line */
++#elif defined(__GNUC__) && defined(__arch64__)
++# define ABI64  /* They've said -m64 at command line */
++#endif
++
++#ifdef ABI64
++  .register	%g2,#scratch
++  .register	%g3,#scratch
++# define	FRAME	-192
++# define	BIAS	2047
++#else
++# define	FRAME	-96
++# define	BIAS	0
++#endif
++
++.text
++.align	32
++.global	OPENSSL_wipe_cpu
++.type	OPENSSL_wipe_cpu,#function
++! Keep in mind that this does not excuse us from wiping the stack!
++! This routine wipes registers, but not the backing store [which
++! resides on the stack, toward lower addresses]. To facilitate for
++! stack wiping I return pointer to the top of stack of the *caller*.
++OPENSSL_wipe_cpu:
++	save	%sp,FRAME,%sp
++	nop
++#ifdef __sun
++#include 
++	ta	ST_CLEAN_WINDOWS
++#else
++	call	.walk.reg.wins
++#endif
++	nop
++	call	.PIC.zero.up
++	mov	.zero-(.-4),%o0
++	ld	[%o0],%f0
++	ld	[%o0],%f1
++
++	subcc	%g0,1,%o0
++	! Following is V9 "rd %ccr,%o0" instruction. However! V8
++	! specification says that it ("rd %asr2,%o0" in V8 terms) does
++	! not cause illegal_instruction trap. It therefore can be used
++	! to determine if the CPU the code is executing on is V8- or
++	! V9-compliant, as V9 returns a distinct value of 0x99,
++	! "negative" and "borrow" bits set in both %icc and %xcc.
++	.word	0x91408000	!rd	%ccr,%o0
++	cmp	%o0,0x99
++	bne	.v8
++	nop
++			! Even though we do not use %fp register bank,
++			! we wipe it as memcpy might have used it...
++			.word	0xbfa00040	!fmovd	%f0,%f62
++			.word	0xbba00040	!...
++			.word	0xb7a00040
++			.word	0xb3a00040
++			.word	0xafa00040
++			.word	0xaba00040
++			.word	0xa7a00040
++			.word	0xa3a00040
++			.word	0x9fa00040
++			.word	0x9ba00040
++			.word	0x97a00040
++			.word	0x93a00040
++			.word	0x8fa00040
++			.word	0x8ba00040
++			.word	0x87a00040
++			.word	0x83a00040	!fmovd	%f0,%f32
++.v8:			fmovs	%f1,%f31
++	clr	%o0
++			fmovs	%f0,%f30
++	clr	%o1
++			fmovs	%f1,%f29
++	clr	%o2
++			fmovs	%f0,%f28
++	clr	%o3
++			fmovs	%f1,%f27
++	clr	%o4
++			fmovs	%f0,%f26
++	clr	%o5
++			fmovs	%f1,%f25
++	clr	%o7
++			fmovs	%f0,%f24
++	clr	%l0
++			fmovs	%f1,%f23
++	clr	%l1
++			fmovs	%f0,%f22
++	clr	%l2
++			fmovs	%f1,%f21
++	clr	%l3
++			fmovs	%f0,%f20
++	clr	%l4
++			fmovs	%f1,%f19
++	clr	%l5
++			fmovs	%f0,%f18
++	clr	%l6
++			fmovs	%f1,%f17
++	clr	%l7
++			fmovs	%f0,%f16
++	clr	%i0
++			fmovs	%f1,%f15
++	clr	%i1
++			fmovs	%f0,%f14
++	clr	%i2
++			fmovs	%f1,%f13
++	clr	%i3
++			fmovs	%f0,%f12
++	clr	%i4
++			fmovs	%f1,%f11
++	clr	%i5
++			fmovs	%f0,%f10
++	clr	%g1
++			fmovs	%f1,%f9
++	clr	%g2
++			fmovs	%f0,%f8
++	clr	%g3
++			fmovs	%f1,%f7
++	clr	%g4
++			fmovs	%f0,%f6
++	clr	%g5
++			fmovs	%f1,%f5
++			fmovs	%f0,%f4
++			fmovs	%f1,%f3
++			fmovs	%f0,%f2
++
++	add	%fp,BIAS,%i0	! return pointer to caller´s top of stack
++
++	ret
++	restore
++
++.zero:	.long	0x0,0x0
++.PIC.zero.up:
++	retl
++	add	%o0,%o7,%o0
++#ifdef DEBUG
++.global	walk_reg_wins
++.type	walk_reg_wins,#function
++walk_reg_wins:
++#endif
++.walk.reg.wins:
++	save	%sp,FRAME,%sp
++	cmp	%i7,%o7
++	be	2f
++	clr	%o0
++	cmp	%o7,0	! compiler never cleans %o7...
++	be	1f	! could have been a leaf function...
++	clr	%o1
++	call	.walk.reg.wins
++	nop
++1:	clr	%o2
++	clr	%o3
++	clr	%o4
++	clr	%o5
++	clr	%o7
++	clr	%l0
++	clr	%l1
++	clr	%l2
++	clr	%l3
++	clr	%l4
++	clr	%l5
++	clr	%l6
++	clr	%l7
++	add	%o0,1,%i0	! used for debugging
++2:	ret
++	restore
++.size	OPENSSL_wipe_cpu,.-OPENSSL_wipe_cpu
++
++.global	OPENSSL_atomic_add
++.type	OPENSSL_atomic_add,#function
++.align	32
++OPENSSL_atomic_add:
++#ifndef ABI64
++	subcc	%g0,1,%o2
++	.word	0x95408000	!rd	%ccr,%o2, see comment above
++	cmp	%o2,0x99
++	be	.v9
++	nop
++	save	%sp,FRAME,%sp
++	ba	.enter
++	nop
++#ifdef __sun
++! Note that you do not have to link with libthread to call thr_yield,
++! as libc provides a stub, which is overloaded the moment you link
++! with *either* libpthread or libthread...
++#define	YIELD_CPU	thr_yield
++#else
++! applies at least to Linux and FreeBSD... Feedback expected...
++#define	YIELD_CPU	sched_yield
++#endif
++.spin:	call	YIELD_CPU
++	nop
++.enter:	ld	[%i0],%i2
++	cmp	%i2,-4096
++	be	.spin
++	mov	-1,%i2
++	swap	[%i0],%i2
++	cmp	%i2,-1
++	be	.spin
++	add	%i2,%i1,%i2
++	stbar
++	st	%i2,[%i0]
++	sra	%i2,%g0,%i0
++	ret
++	restore
++.v9:
++#endif
++	ld	[%o0],%o2
++1:	add	%o1,%o2,%o3
++	.word	0xd7e2100a	!cas [%o0],%o2,%o3, compare [%o0] with %o2 and swap %o3
++	cmp	%o2,%o3
++	bne	1b
++	mov	%o3,%o2		! cas is always fetching to dest. register
++	add	%o1,%o2,%o0	! OpenSSL expects the new value
++	retl
++	sra	%o0,%g0,%o0	! we return signed int, remember?
++.size	OPENSSL_atomic_add,.-OPENSSL_atomic_add
++
++.global	_sparcv9_rdtick
++.align	32
++_sparcv9_rdtick:
++	subcc	%g0,1,%o0
++	.word	0x91408000	!rd	%ccr,%o0
++	cmp	%o0,0x99
++	bne	.notick
++	xor	%o0,%o0,%o0
++	.word	0x91410000	!rd	%tick,%o0
++	retl
++	.word	0x93323020	!srlx	%o0,32,%o1
++.notick:
++	retl
++	xor	%o1,%o1,%o1
++.type	_sparcv9_rdtick,#function
++.size	_sparcv9_rdtick,.-_sparcv9_rdtick
++
++.global	_sparcv9_vis1_probe
++.align	8
++_sparcv9_vis1_probe:
++	add	%sp,BIAS+2,%o1
++	.word	0xc19a5a40	!ldda	[%o1]ASI_FP16_P,%f0
++	retl
++	.word	0x81b00d80	!fxor	%f0,%f0,%f0
++.type	_sparcv9_vis1_probe,#function
++.size	_sparcv9_vis1_probe,.-_sparcv9_vis1_probe
++
++! Probe and instrument VIS1 instruction. Output is number of cycles it
++! takes to execute rdtick and pair of VIS1 instructions. US-Tx VIS unit
++! is slow (documented to be 6 cycles on T2) and the core is in-order
++! single-issue, it should be possible to distinguish Tx reliably...
++! Observed return values are:
++!
++!	UltraSPARC IIe		7
++!	UltraSPARC III		7
++!	UltraSPARC T1		24
++!	SPARC T4		65(*)
++!
++! (*)	result has lesser to do with VIS instruction latencies, rdtick
++!	appears that slow, but it does the trick in sense that FP and
++!	VIS code paths are still slower than integer-only ones.
++!
++! Numbers for T2 and SPARC64 V-VII are more than welcomed.
++!
++! It would be possible to detect specifically US-T1 by instrumenting
++! fmul8ulx16, which is emulated on T1 and as such accounts for quite
++! a lot of %tick-s, couple of thousand on Linux...
++.global	_sparcv9_vis1_instrument
++.align	8
++_sparcv9_vis1_instrument:
++	.word	0x81b00d80	!fxor	%f0,%f0,%f0
++	.word	0x85b08d82	!fxor	%f2,%f2,%f2
++	.word	0x91410000	!rd	%tick,%o0
++	.word	0x81b00d80	!fxor	%f0,%f0,%f0
++	.word	0x85b08d82	!fxor	%f2,%f2,%f2
++	.word	0x93410000	!rd	%tick,%o1
++	.word	0x81b00d80	!fxor	%f0,%f0,%f0
++	.word	0x85b08d82	!fxor	%f2,%f2,%f2
++	.word	0x95410000	!rd	%tick,%o2
++	.word	0x81b00d80	!fxor	%f0,%f0,%f0
++	.word	0x85b08d82	!fxor	%f2,%f2,%f2
++	.word	0x97410000	!rd	%tick,%o3
++	.word	0x81b00d80	!fxor	%f0,%f0,%f0
++	.word	0x85b08d82	!fxor	%f2,%f2,%f2
++	.word	0x99410000	!rd	%tick,%o4
++
++	! calculate intervals
++	sub	%o1,%o0,%o0
++	sub	%o2,%o1,%o1
++	sub	%o3,%o2,%o2
++	sub	%o4,%o3,%o3
++
++	! find minimum value
++	cmp	%o0,%o1
++	.word	0x38680002	!bgu,a	%xcc,.+8
++	mov	%o1,%o0
++	cmp	%o0,%o2
++	.word	0x38680002	!bgu,a	%xcc,.+8
++	mov	%o2,%o0
++	cmp	%o0,%o3
++	.word	0x38680002	!bgu,a	%xcc,.+8
++	mov	%o3,%o0
++
++	retl
++	nop
++.type	_sparcv9_vis1_instrument,#function
++.size	_sparcv9_vis1_instrument,.-_sparcv9_vis1_instrument
++
++.global	_sparcv9_vis2_probe
++.align	8
++_sparcv9_vis2_probe:
++	retl
++	.word	0x81b00980	!bshuffle	%f0,%f0,%f0
++.type	_sparcv9_vis2_probe,#function
++.size	_sparcv9_vis2_probe,.-_sparcv9_vis2_probe
++
++.global	_sparcv9_fmadd_probe
++.align	8
++_sparcv9_fmadd_probe:
++	.word	0x81b00d80	!fxor	%f0,%f0,%f0
++	.word	0x85b08d82	!fxor	%f2,%f2,%f2
++	retl
++	.word	0x81b80440	!fmaddd	%f0,%f0,%f2,%f0
++.type	_sparcv9_fmadd_probe,#function
++.size	_sparcv9_fmadd_probe,.-_sparcv9_fmadd_probe
++
++.global	_sparcv9_rdcfr
++.align	8
++_sparcv9_rdcfr:
++	retl
++	.word	0x91468000	!rd	%asr26,%o0
++.type	_sparcv9_rdcfr,#function
++.size	_sparcv9_rdcfr,.-_sparcv9_rdcfr
++
++.global	_sparcv9_vis3_probe
++.align	8
++_sparcv9_vis3_probe:
++	retl
++	.word	0x81b022a0	!xmulx	%g0,%g0,%g0
++.type	_sparcv9_vis3_probe,#function
++.size	_sparcv9_vis3_probe,.-_sparcv9_vis3_probe
++
++.global	_sparcv9_random
++.align	8
++_sparcv9_random:
++	retl
++	.word	0x91b002a0	!random	%o0
++.type	_sparcv9_random,#function
++.size	_sparcv9_random,.-_sparcv9_vis3_probe
++
++.global	_sparcv9_fjaesx_probe
++.align	8
++_sparcv9_fjaesx_probe:
++	.word	0x81b09206	!faesencx %f2,%f6,%f0
++	retl
++	nop
++.size	_sparcv9_fjaesx_probe,.-_sparcv9_fjaesx_probe
++
++.global	OPENSSL_cleanse
++.align	32
++OPENSSL_cleanse:
++	cmp	%o1,14
++	nop
++#ifdef ABI64
++	bgu	%xcc,.Lot
++#else
++	bgu	.Lot
++#endif
++	cmp	%o1,0
++	bne	.Little
++	nop
++	retl
++	nop
++
++.Little:
++	stb	%g0,[%o0]
++	subcc	%o1,1,%o1
++	bnz	.Little
++	add	%o0,1,%o0
++	retl
++	nop
++.align	32
++.Lot:
++#ifndef ABI64
++	subcc	%g0,1,%g1
++	! see above for explanation
++	.word	0x83408000	!rd	%ccr,%g1
++	cmp	%g1,0x99
++	bne	.v8lot
++	nop
++#endif
++
++.v9lot:	andcc	%o0,7,%g0
++	bz	.v9aligned
++	nop
++	stb	%g0,[%o0]
++	sub	%o1,1,%o1
++	ba	.v9lot
++	add	%o0,1,%o0
++.align	16,0x01000000
++.v9aligned:
++	.word	0xc0720000	!stx	%g0,[%o0]
++	sub	%o1,8,%o1
++	andcc	%o1,-8,%g0
++#ifdef ABI64
++	.word	0x126ffffd	!bnz	%xcc,.v9aligned
++#else
++	.word	0x124ffffd	!bnz	%icc,.v9aligned
++#endif
++	add	%o0,8,%o0
++
++	cmp	%o1,0
++	bne	.Little
++	nop
++	retl
++	nop
++#ifndef ABI64
++.v8lot:	andcc	%o0,3,%g0
++	bz	.v8aligned
++	nop
++	stb	%g0,[%o0]
++	sub	%o1,1,%o1
++	ba	.v8lot
++	add	%o0,1,%o0
++	nop
++.v8aligned:
++	st	%g0,[%o0]
++	sub	%o1,4,%o1
++	andcc	%o1,-4,%g0
++	bnz	.v8aligned
++	add	%o0,4,%o0
++
++	cmp	%o1,0
++	bne	.Little
++	nop
++	retl
++	nop
++#endif
++.type	OPENSSL_cleanse,#function
++.size	OPENSSL_cleanse,.-OPENSSL_cleanse
++
++.global	CRYPTO_memcmp
++.align	16
++CRYPTO_memcmp:
++	cmp	%o2,0
++#ifdef ABI64
++	beq,pn	%xcc,.Lno_data
++#else
++	beq	.Lno_data
++#endif
++	xor	%g1,%g1,%g1
++	nop
++
++.Loop_cmp:
++	ldub	[%o0],%o3
++	add	%o0,1,%o0
++	ldub	[%o1],%o4
++	add	%o1,1,%o1
++	subcc	%o2,1,%o2
++	xor	%o3,%o4,%o4
++#ifdef ABI64
++	bnz	%xcc,.Loop_cmp
++#else
++	bnz	.Loop_cmp
++#endif
++	or	%o4,%g1,%g1
++
++	sub	%g0,%g1,%g1
++	srl	%g1,31,%g1
++.Lno_data:
++	retl
++	mov	%g1,%o0
++.type	CRYPTO_memcmp,#function
++.size	CRYPTO_memcmp,.-CRYPTO_memcmp
++
++.global	_sparcv9_vis1_instrument_bus
++.align	8
++_sparcv9_vis1_instrument_bus:
++	mov	%o1,%o3					! save cnt
++	.word	0x99410000	!rd	%tick,%o4	! tick
++	mov	%o4,%o5					! lasttick = tick
++	set	0,%g4					! diff
++
++	andn	%o0,63,%g1
++	.word	0xc1985e00	!ldda	[%g1]0xf0,%f0	! block load
++	.word	0x8143e040	!membar	#Sync
++	.word	0xc1b85c00	!stda	%f0,[%g1]0xe0	! block store and commit
++	.word	0x8143e040	!membar	#Sync
++	ld	[%o0],%o4
++	add	%o4,%g4,%g4
++	.word	0xc9e2100c	!cas	[%o0],%o4,%g4
++
++.Loop:	.word	0x99410000	!rd	%tick,%o4
++	sub	%o4,%o5,%g4				! diff=tick-lasttick
++	mov	%o4,%o5					! lasttick=tick
++
++	andn	%o0,63,%g1
++	.word	0xc1985e00	!ldda	[%g1]0xf0,%f0	! block load
++	.word	0x8143e040	!membar	#Sync
++	.word	0xc1b85c00	!stda	%f0,[%g1]0xe0	! block store and commit
++	.word	0x8143e040	!membar	#Sync
++	ld	[%o0],%o4
++	add	%o4,%g4,%g4
++	.word	0xc9e2100c	!cas	[%o0],%o4,%g4
++	subcc	%o1,1,%o1				! --$cnt
++	bnz	.Loop
++	add	%o0,4,%o0				! ++$out
++
++	retl
++	mov	%o3,%o0
++.type	_sparcv9_vis1_instrument_bus,#function
++.size	_sparcv9_vis1_instrument_bus,.-_sparcv9_vis1_instrument_bus
++
++.global	_sparcv9_vis1_instrument_bus2
++.align	8
++_sparcv9_vis1_instrument_bus2:
++	mov	%o1,%o3					! save cnt
++	sll	%o1,2,%o1				! cnt*=4
++
++	.word	0x99410000	!rd	%tick,%o4	! tick
++	mov	%o4,%o5					! lasttick = tick
++	set	0,%g4					! diff
++
++	andn	%o0,63,%g1
++	.word	0xc1985e00	!ldda	[%g1]0xf0,%f0	! block load
++	.word	0x8143e040	!membar	#Sync
++	.word	0xc1b85c00	!stda	%f0,[%g1]0xe0	! block store and commit
++	.word	0x8143e040	!membar	#Sync
++	ld	[%o0],%o4
++	add	%o4,%g4,%g4
++	.word	0xc9e2100c	!cas	[%o0],%o4,%g4
++
++	.word	0x99410000	!rd	%tick,%o4	! tick
++	sub	%o4,%o5,%g4				! diff=tick-lasttick
++	mov	%o4,%o5					! lasttick=tick
++	mov	%g4,%g5					! lastdiff=diff
++.Loop2:
++	andn	%o0,63,%g1
++	.word	0xc1985e00	!ldda	[%g1]0xf0,%f0	! block load
++	.word	0x8143e040	!membar	#Sync
++	.word	0xc1b85c00	!stda	%f0,[%g1]0xe0	! block store and commit
++	.word	0x8143e040	!membar	#Sync
++	ld	[%o0],%o4
++	add	%o4,%g4,%g4
++	.word	0xc9e2100c	!cas	[%o0],%o4,%g4
++
++	subcc	%o2,1,%o2				! --max
++	bz	.Ldone2
++	nop
++
++	.word	0x99410000	!rd	%tick,%o4	! tick
++	sub	%o4,%o5,%g4				! diff=tick-lasttick
++	mov	%o4,%o5					! lasttick=tick
++	cmp	%g4,%g5
++	mov	%g4,%g5					! lastdiff=diff
++
++	.word	0x83408000	!rd	%ccr,%g1
++	and	%g1,4,%g1				! isolate zero flag
++	xor	%g1,4,%g1				! flip zero flag
++
++	subcc	%o1,%g1,%o1				! conditional --$cnt
++	bnz	.Loop2
++	add	%o0,%g1,%o0				! conditional ++$out
++
++.Ldone2:
++	srl	%o1,2,%o1
++	retl
++	sub	%o3,%o1,%o0
++.type	_sparcv9_vis1_instrument_bus2,#function
++.size	_sparcv9_vis1_instrument_bus2,.-_sparcv9_vis1_instrument_bus2
++
++.section	".init",#alloc,#execinstr
++	call	OPENSSL_cpuid_setup
++	nop
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/sparcv9cap.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/sparcv9cap.c
+new file mode 100644
+index 0000000..61d0334
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/sparcv9cap.c
+@@ -0,0 +1,294 @@
++/*
++ * Copyright 2005-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include 
++#include 
++#include 
++#include 
++#include 
++#include 
++#include 
++
++#include "sparc_arch.h"
++
++#if defined(__GNUC__) && defined(__linux)
++__attribute__ ((visibility("hidden")))
++#endif
++unsigned int OPENSSL_sparcv9cap_P[2] = { SPARCV9_TICK_PRIVILEGED, 0 };
++
++int bn_mul_mont(BN_ULONG *rp, const BN_ULONG *ap, const BN_ULONG *bp,
++                const BN_ULONG *np, const BN_ULONG *n0, int num)
++{
++    int bn_mul_mont_vis3(BN_ULONG *rp, const BN_ULONG *ap, const BN_ULONG *bp,
++                         const BN_ULONG *np, const BN_ULONG *n0, int num);
++    int bn_mul_mont_fpu(BN_ULONG *rp, const BN_ULONG *ap, const BN_ULONG *bp,
++                        const BN_ULONG *np, const BN_ULONG *n0, int num);
++    int bn_mul_mont_int(BN_ULONG *rp, const BN_ULONG *ap, const BN_ULONG *bp,
++                        const BN_ULONG *np, const BN_ULONG *n0, int num);
++
++    if (!(num & 1) && num >= 6) {
++        if ((num & 15) == 0 && num <= 64 &&
++            (OPENSSL_sparcv9cap_P[1] & (CFR_MONTMUL | CFR_MONTSQR)) ==
++            (CFR_MONTMUL | CFR_MONTSQR)) {
++            typedef int (*bn_mul_mont_f) (BN_ULONG *rp, const BN_ULONG *ap,
++                                          const BN_ULONG *bp,
++                                          const BN_ULONG *np,
++                                          const BN_ULONG *n0);
++            int bn_mul_mont_t4_8(BN_ULONG *rp, const BN_ULONG *ap,
++                                 const BN_ULONG *bp, const BN_ULONG *np,
++                                 const BN_ULONG *n0);
++            int bn_mul_mont_t4_16(BN_ULONG *rp, const BN_ULONG *ap,
++                                  const BN_ULONG *bp, const BN_ULONG *np,
++                                  const BN_ULONG *n0);
++            int bn_mul_mont_t4_24(BN_ULONG *rp, const BN_ULONG *ap,
++                                  const BN_ULONG *bp, const BN_ULONG *np,
++                                  const BN_ULONG *n0);
++            int bn_mul_mont_t4_32(BN_ULONG *rp, const BN_ULONG *ap,
++                                  const BN_ULONG *bp, const BN_ULONG *np,
++                                  const BN_ULONG *n0);
++            static const bn_mul_mont_f funcs[4] = {
++                bn_mul_mont_t4_8, bn_mul_mont_t4_16,
++                bn_mul_mont_t4_24, bn_mul_mont_t4_32
++            };
++            bn_mul_mont_f worker = funcs[num / 16 - 1];
++
++            if ((*worker) (rp, ap, bp, np, n0))
++                return 1;
++            /* retry once and fall back */
++            if ((*worker) (rp, ap, bp, np, n0))
++                return 1;
++            return bn_mul_mont_vis3(rp, ap, bp, np, n0, num);
++        }
++        if ((OPENSSL_sparcv9cap_P[0] & SPARCV9_VIS3))
++            return bn_mul_mont_vis3(rp, ap, bp, np, n0, num);
++        else if (num >= 8 &&
++                 /*
++                  * bn_mul_mont_fpu doesn't use FMADD, we just use the
++                  * flag to detect when FPU path is preferable in cases
++                  * when current heuristics is unreliable. [it works
++                  * out because FMADD-capable processors where FPU
++                  * code path is undesirable are also VIS3-capable and
++                  * VIS3 code path takes precedence.]
++                  */
++                 ( (OPENSSL_sparcv9cap_P[0] & SPARCV9_FMADD) ||
++                   (OPENSSL_sparcv9cap_P[0] &
++                    (SPARCV9_PREFER_FPU | SPARCV9_VIS1)) ==
++                   (SPARCV9_PREFER_FPU | SPARCV9_VIS1) ))
++            return bn_mul_mont_fpu(rp, ap, bp, np, n0, num);
++    }
++    return bn_mul_mont_int(rp, ap, bp, np, n0, num);
++}
++
++unsigned long _sparcv9_rdtick(void);
++void _sparcv9_vis1_probe(void);
++unsigned long _sparcv9_vis1_instrument(void);
++void _sparcv9_vis2_probe(void);
++void _sparcv9_fmadd_probe(void);
++unsigned long _sparcv9_rdcfr(void);
++void _sparcv9_vis3_probe(void);
++void _sparcv9_fjaesx_probe(void);
++unsigned long _sparcv9_random(void);
++size_t _sparcv9_vis1_instrument_bus(unsigned int *, size_t);
++size_t _sparcv9_vis1_instrument_bus2(unsigned int *, size_t, size_t);
++
++unsigned long OPENSSL_rdtsc(void)
++{
++    if (OPENSSL_sparcv9cap_P[0] & SPARCV9_TICK_PRIVILEGED)
++#if defined(__sun) && defined(__SVR4)
++        return gethrtime();
++#else
++        return 0;
++#endif
++    else
++        return _sparcv9_rdtick();
++}
++
++size_t OPENSSL_instrument_bus(unsigned int *out, size_t cnt)
++{
++    if ((OPENSSL_sparcv9cap_P[0] & (SPARCV9_TICK_PRIVILEGED | SPARCV9_BLK)) ==
++        SPARCV9_BLK)
++        return _sparcv9_vis1_instrument_bus(out, cnt);
++    else
++        return 0;
++}
++
++size_t OPENSSL_instrument_bus2(unsigned int *out, size_t cnt, size_t max)
++{
++    if ((OPENSSL_sparcv9cap_P[0] & (SPARCV9_TICK_PRIVILEGED | SPARCV9_BLK)) ==
++        SPARCV9_BLK)
++        return _sparcv9_vis1_instrument_bus2(out, cnt, max);
++    else
++        return 0;
++}
++
++static sigjmp_buf common_jmp;
++static void common_handler(int sig)
++{
++    siglongjmp(common_jmp, sig);
++}
++
++#if defined(__sun) && defined(__SVR4)
++# if defined(__GNUC__) && __GNUC__>=2
++extern unsigned int getisax(unsigned int vec[], unsigned int sz) __attribute__ ((weak));
++# elif defined(__SUNPRO_C)
++#pragma weak getisax
++extern unsigned int getisax(unsigned int vec[], unsigned int sz);
++# else
++static unsigned int (*getisax) (unsigned int vec[], unsigned int sz) = NULL;
++# endif
++#endif
++
++void OPENSSL_cpuid_setup(void)
++{
++    char *e;
++    struct sigaction common_act, ill_oact, bus_oact;
++    sigset_t all_masked, oset;
++    static int trigger = 0;
++
++    if (trigger)
++        return;
++    trigger = 1;
++
++    if ((e = getenv("OPENSSL_sparcv9cap"))) {
++        OPENSSL_sparcv9cap_P[0] = strtoul(e, NULL, 0);
++        if ((e = strchr(e, ':')))
++            OPENSSL_sparcv9cap_P[1] = strtoul(e + 1, NULL, 0);
++        return;
++    }
++
++#if defined(__sun) && defined(__SVR4)
++    if (getisax != NULL) {
++        unsigned int vec[2] = { 0, 0 };
++
++        if (getisax (vec,2)) {
++            if (vec[0]&0x00020) OPENSSL_sparcv9cap_P[0] |= SPARCV9_VIS1;
++            if (vec[0]&0x00040) OPENSSL_sparcv9cap_P[0] |= SPARCV9_VIS2;
++            if (vec[0]&0x00080) OPENSSL_sparcv9cap_P[0] |= SPARCV9_BLK;
++            if (vec[0]&0x00100) OPENSSL_sparcv9cap_P[0] |= SPARCV9_FMADD;
++            if (vec[0]&0x00400) OPENSSL_sparcv9cap_P[0] |= SPARCV9_VIS3;
++            if (vec[0]&0x01000) OPENSSL_sparcv9cap_P[0] |= SPARCV9_FJHPCACE;
++            if (vec[0]&0x02000) OPENSSL_sparcv9cap_P[0] |= SPARCV9_FJDESX;
++            if (vec[0]&0x08000) OPENSSL_sparcv9cap_P[0] |= SPARCV9_IMA;
++            if (vec[0]&0x10000) OPENSSL_sparcv9cap_P[0] |= SPARCV9_FJAESX;
++            if (vec[1]&0x00008) OPENSSL_sparcv9cap_P[0] |= SPARCV9_VIS4;
++
++            /* reconstruct %cfr copy */
++            OPENSSL_sparcv9cap_P[1] = (vec[0]>>17)&0x3ff;
++            OPENSSL_sparcv9cap_P[1] |= (OPENSSL_sparcv9cap_P[1]&CFR_MONTMUL)<<1;
++            if (vec[0]&0x20000000) OPENSSL_sparcv9cap_P[1] |= CFR_CRC32C;
++            if (vec[1]&0x00000020) OPENSSL_sparcv9cap_P[1] |= CFR_XMPMUL;
++            if (vec[1]&0x00000040)
++                OPENSSL_sparcv9cap_P[1] |= CFR_XMONTMUL|CFR_XMONTSQR;
++
++            /* Some heuristics */
++            /* all known VIS2-capable CPUs have unprivileged tick counter */
++            if (OPENSSL_sparcv9cap_P[0]&SPARCV9_VIS2)
++                OPENSSL_sparcv9cap_P[0] &= ~SPARCV9_TICK_PRIVILEGED;
++
++            OPENSSL_sparcv9cap_P[0] |= SPARCV9_PREFER_FPU;
++
++            /* detect UltraSPARC-Tx, see sparccpud.S for details... */
++            if ((OPENSSL_sparcv9cap_P[0]&SPARCV9_VIS1) &&
++                _sparcv9_vis1_instrument() >= 12)
++                OPENSSL_sparcv9cap_P[0] &= ~(SPARCV9_VIS1 | SPARCV9_PREFER_FPU);
++        }
++
++        if (sizeof(size_t) == 8)
++            OPENSSL_sparcv9cap_P[0] |= SPARCV9_64BIT_STACK;
++
++        return;
++    }
++#endif
++
++    /* Initial value, fits UltraSPARC-I&II... */
++    OPENSSL_sparcv9cap_P[0] = SPARCV9_PREFER_FPU | SPARCV9_TICK_PRIVILEGED;
++
++    sigfillset(&all_masked);
++    sigdelset(&all_masked, SIGILL);
++    sigdelset(&all_masked, SIGTRAP);
++# ifdef SIGEMT
++    sigdelset(&all_masked, SIGEMT);
++# endif
++    sigdelset(&all_masked, SIGFPE);
++    sigdelset(&all_masked, SIGBUS);
++    sigdelset(&all_masked, SIGSEGV);
++    sigprocmask(SIG_SETMASK, &all_masked, &oset);
++
++    memset(&common_act, 0, sizeof(common_act));
++    common_act.sa_handler = common_handler;
++    common_act.sa_mask = all_masked;
++
++    sigaction(SIGILL, &common_act, &ill_oact);
++    sigaction(SIGBUS, &common_act, &bus_oact); /* T1 fails 16-bit ldda [on
++                                                * Linux] */
++
++    if (sigsetjmp(common_jmp, 1) == 0) {
++        _sparcv9_rdtick();
++        OPENSSL_sparcv9cap_P[0] &= ~SPARCV9_TICK_PRIVILEGED;
++    }
++
++    if (sigsetjmp(common_jmp, 1) == 0) {
++        _sparcv9_vis1_probe();
++        OPENSSL_sparcv9cap_P[0] |= SPARCV9_VIS1 | SPARCV9_BLK;
++        /* detect UltraSPARC-Tx, see sparccpud.S for details... */
++        if (_sparcv9_vis1_instrument() >= 12)
++            OPENSSL_sparcv9cap_P[0] &= ~(SPARCV9_VIS1 | SPARCV9_PREFER_FPU);
++        else {
++            _sparcv9_vis2_probe();
++            OPENSSL_sparcv9cap_P[0] |= SPARCV9_VIS2;
++        }
++    }
++
++    if (sigsetjmp(common_jmp, 1) == 0) {
++        _sparcv9_fmadd_probe();
++        OPENSSL_sparcv9cap_P[0] |= SPARCV9_FMADD;
++    }
++
++    /*
++     * VIS3 flag is tested independently from VIS1, unlike VIS2 that is,
++     * because VIS3 defines even integer instructions.
++     */
++    if (sigsetjmp(common_jmp, 1) == 0) {
++        _sparcv9_vis3_probe();
++        OPENSSL_sparcv9cap_P[0] |= SPARCV9_VIS3;
++    }
++
++    if (sigsetjmp(common_jmp, 1) == 0) {
++        _sparcv9_fjaesx_probe();
++        OPENSSL_sparcv9cap_P[0] |= SPARCV9_FJAESX;
++    }
++
++    /*
++     * In wait for better solution _sparcv9_rdcfr is masked by
++     * VIS3 flag, because it goes to uninterruptable endless
++     * loop on UltraSPARC II running Solaris. Things might be
++     * different on Linux...
++     */
++    if ((OPENSSL_sparcv9cap_P[0] & SPARCV9_VIS3) &&
++        sigsetjmp(common_jmp, 1) == 0) {
++        OPENSSL_sparcv9cap_P[1] = (unsigned int)_sparcv9_rdcfr();
++    }
++
++    sigaction(SIGBUS, &bus_oact, NULL);
++    sigaction(SIGILL, &ill_oact, NULL);
++
++    sigprocmask(SIG_SETMASK, &oset, NULL);
++
++    if (sizeof(size_t) == 8)
++        OPENSSL_sparcv9cap_P[0] |= SPARCV9_64BIT_STACK;
++# ifdef __linux
++    else {
++        int ret = syscall(340);
++
++        if (ret >= 0 && ret & 1)
++            OPENSSL_sparcv9cap_P[0] |= SPARCV9_64BIT_STACK;
++    }
++# endif
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/srp/build.info b/CryptoPkg/Library/OpensslLib/openssl/crypto/srp/build.info
+new file mode 100644
+index 0000000..b6c7fe7
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/srp/build.info
+@@ -0,0 +1,2 @@
++LIBS=../../libcrypto
++SOURCE[../../libcrypto]=srp_lib.c srp_vfy.c
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/srp/srp_lib.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/srp/srp_lib.c
+new file mode 100644
+index 0000000..e69de29
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/srp/srp_vfy.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/srp/srp_vfy.c
+new file mode 100644
+index 0000000..e69de29
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/stack/build.info b/CryptoPkg/Library/OpensslLib/openssl/crypto/stack/build.info
+new file mode 100644
+index 0000000..e587021
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/stack/build.info
+@@ -0,0 +1,2 @@
++LIBS=../../libcrypto
++SOURCE[../../libcrypto]=stack.c
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/stack/stack.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/stack/stack.c
+new file mode 100644
+index 0000000..43ddf30
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/stack/stack.c
+@@ -0,0 +1,312 @@
++/*
++ * Copyright 1995-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include "internal/cryptlib.h"
++#include "internal/numbers.h"
++#include 
++#include 
++
++struct stack_st {
++    int num;
++    const char **data;
++    int sorted;
++    size_t num_alloc;
++    OPENSSL_sk_compfunc comp;
++};
++
++#undef MIN_NODES
++#define MIN_NODES       4
++
++#include 
++
++OPENSSL_sk_compfunc OPENSSL_sk_set_cmp_func(OPENSSL_STACK *sk, OPENSSL_sk_compfunc c)
++{
++    OPENSSL_sk_compfunc old = sk->comp;
++
++    if (sk->comp != c)
++        sk->sorted = 0;
++    sk->comp = c;
++
++    return old;
++}
++
++OPENSSL_STACK *OPENSSL_sk_dup(const OPENSSL_STACK *sk)
++{
++    OPENSSL_STACK *ret;
++
++    if (sk->num < 0)
++        return NULL;
++
++    if ((ret = OPENSSL_malloc(sizeof(*ret))) == NULL)
++        return NULL;
++
++    /* direct structure assignment */
++    *ret = *sk;
++
++    if ((ret->data = OPENSSL_malloc(sizeof(*ret->data) * sk->num_alloc)) == NULL)
++        goto err;
++    memcpy(ret->data, sk->data, sizeof(char *) * sk->num);
++    return ret;
++ err:
++    OPENSSL_sk_free(ret);
++    return NULL;
++}
++
++OPENSSL_STACK *OPENSSL_sk_deep_copy(const OPENSSL_STACK *sk,
++                             OPENSSL_sk_copyfunc copy_func,
++                             OPENSSL_sk_freefunc free_func)
++{
++    OPENSSL_STACK *ret;
++    int i;
++
++    if (sk->num < 0)
++        return NULL;
++
++    if ((ret = OPENSSL_malloc(sizeof(*ret))) == NULL)
++        return NULL;
++
++    /* direct structure assignment */
++    *ret = *sk;
++
++    ret->num_alloc = sk->num > MIN_NODES ? (size_t)sk->num : MIN_NODES;
++    ret->data = OPENSSL_zalloc(sizeof(*ret->data) * ret->num_alloc);
++    if (ret->data == NULL) {
++        OPENSSL_free(ret);
++        return NULL;
++    }
++
++    for (i = 0; i < ret->num; ++i) {
++        if (sk->data[i] == NULL)
++            continue;
++        if ((ret->data[i] = copy_func(sk->data[i])) == NULL) {
++            while (--i >= 0)
++                if (ret->data[i] != NULL)
++                    free_func((void *)ret->data[i]);
++            OPENSSL_sk_free(ret);
++            return NULL;
++        }
++    }
++    return ret;
++}
++
++OPENSSL_STACK *OPENSSL_sk_new_null(void)
++{
++    return OPENSSL_sk_new((OPENSSL_sk_compfunc)NULL);
++}
++
++OPENSSL_STACK *OPENSSL_sk_new(OPENSSL_sk_compfunc c)
++{
++    OPENSSL_STACK *ret;
++
++    if ((ret = OPENSSL_zalloc(sizeof(*ret))) == NULL)
++        goto err;
++    if ((ret->data = OPENSSL_zalloc(sizeof(*ret->data) * MIN_NODES)) == NULL)
++        goto err;
++    ret->comp = c;
++    ret->num_alloc = MIN_NODES;
++    return (ret);
++
++ err:
++    OPENSSL_free(ret);
++    return (NULL);
++}
++
++int OPENSSL_sk_insert(OPENSSL_STACK *st, const void *data, int loc)
++{
++    if (st == NULL || st->num < 0 || st->num == INT_MAX) {
++        return 0;
++    }
++
++    if (st->num_alloc <= (size_t)(st->num + 1)) {
++        size_t doub_num_alloc = st->num_alloc * 2;
++        const char **tmpdata;
++
++        /* Overflow checks */
++        if (doub_num_alloc < st->num_alloc)
++            return 0;
++
++        /* Avoid overflow due to multiplication by sizeof(char *) */
++        if (doub_num_alloc > SIZE_MAX / sizeof(char *))
++            return 0;
++
++        tmpdata = OPENSSL_realloc((char *)st->data,
++                                  sizeof(char *) * doub_num_alloc);
++        if (tmpdata == NULL)
++            return 0;
++
++        st->data = tmpdata;
++        st->num_alloc = doub_num_alloc;
++    }
++    if ((loc >= st->num) || (loc < 0)) {
++        st->data[st->num] = data;
++    } else {
++        memmove(&st->data[loc + 1], &st->data[loc],
++                sizeof(st->data[0]) * (st->num - loc));
++        st->data[loc] = data;
++    }
++    st->num++;
++    st->sorted = 0;
++    return st->num;
++}
++
++void *OPENSSL_sk_delete_ptr(OPENSSL_STACK *st, const void *p)
++{
++    int i;
++
++    for (i = 0; i < st->num; i++)
++        if (st->data[i] == p)
++            return OPENSSL_sk_delete(st, i);
++    return NULL;
++}
++
++void *OPENSSL_sk_delete(OPENSSL_STACK *st, int loc)
++{
++    const char *ret;
++
++    if (st == NULL || loc < 0 || loc >= st->num)
++        return NULL;
++
++    ret = st->data[loc];
++    if (loc != st->num - 1)
++         memmove(&st->data[loc], &st->data[loc + 1],
++                 sizeof(st->data[0]) * (st->num - loc - 1));
++    st->num--;
++    return (void *)ret;
++}
++
++static int internal_find(OPENSSL_STACK *st, const void *data,
++                         int ret_val_options)
++{
++    const void *r;
++    int i;
++
++    if (st == NULL)
++        return -1;
++
++    if (st->comp == NULL) {
++        for (i = 0; i < st->num; i++)
++            if (st->data[i] == data)
++                return (i);
++        return (-1);
++    }
++    OPENSSL_sk_sort(st);
++    if (data == NULL)
++        return (-1);
++    r = OBJ_bsearch_ex_(&data, st->data, st->num, sizeof(void *), st->comp,
++                        ret_val_options);
++    if (r == NULL)
++        return (-1);
++    return (int)((const char **)r - st->data);
++}
++
++int OPENSSL_sk_find(OPENSSL_STACK *st, const void *data)
++{
++    return internal_find(st, data, OBJ_BSEARCH_FIRST_VALUE_ON_MATCH);
++}
++
++int OPENSSL_sk_find_ex(OPENSSL_STACK *st, const void *data)
++{
++    return internal_find(st, data, OBJ_BSEARCH_VALUE_ON_NOMATCH);
++}
++
++int OPENSSL_sk_push(OPENSSL_STACK *st, const void *data)
++{
++    return (OPENSSL_sk_insert(st, data, st->num));
++}
++
++int OPENSSL_sk_unshift(OPENSSL_STACK *st, const void *data)
++{
++    return (OPENSSL_sk_insert(st, data, 0));
++}
++
++void *OPENSSL_sk_shift(OPENSSL_STACK *st)
++{
++    if (st == NULL)
++        return (NULL);
++    if (st->num <= 0)
++        return (NULL);
++    return (OPENSSL_sk_delete(st, 0));
++}
++
++void *OPENSSL_sk_pop(OPENSSL_STACK *st)
++{
++    if (st == NULL)
++        return (NULL);
++    if (st->num <= 0)
++        return (NULL);
++    return (OPENSSL_sk_delete(st, st->num - 1));
++}
++
++void OPENSSL_sk_zero(OPENSSL_STACK *st)
++{
++    if (st == NULL)
++        return;
++    if (st->num <= 0)
++        return;
++    memset(st->data, 0, sizeof(*st->data) * st->num);
++    st->num = 0;
++}
++
++void OPENSSL_sk_pop_free(OPENSSL_STACK *st, OPENSSL_sk_freefunc func)
++{
++    int i;
++
++    if (st == NULL)
++        return;
++    for (i = 0; i < st->num; i++)
++        if (st->data[i] != NULL)
++            func((char *)st->data[i]);
++    OPENSSL_sk_free(st);
++}
++
++void OPENSSL_sk_free(OPENSSL_STACK *st)
++{
++    if (st == NULL)
++        return;
++    OPENSSL_free(st->data);
++    OPENSSL_free(st);
++}
++
++int OPENSSL_sk_num(const OPENSSL_STACK *st)
++{
++    if (st == NULL)
++        return -1;
++    return st->num;
++}
++
++void *OPENSSL_sk_value(const OPENSSL_STACK *st, int i)
++{
++    if (st == NULL || i < 0 || i >= st->num)
++        return NULL;
++    return (void *)st->data[i];
++}
++
++void *OPENSSL_sk_set(OPENSSL_STACK *st, int i, const void *data)
++{
++    if (st == NULL || i < 0 || i >= st->num)
++        return NULL;
++    st->data[i] = data;
++    return (void *)st->data[i];
++}
++
++void OPENSSL_sk_sort(OPENSSL_STACK *st)
++{
++    if (st && !st->sorted && st->comp != NULL) {
++        qsort(st->data, st->num, sizeof(char *), st->comp);
++        st->sorted = 1;
++    }
++}
++
++int OPENSSL_sk_is_sorted(const OPENSSL_STACK *st)
++{
++    if (st == NULL)
++        return 1;
++    return st->sorted;
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/threads_none.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/threads_none.c
+new file mode 100644
+index 0000000..72bf25b
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/threads_none.c
+@@ -0,0 +1,124 @@
++/*
++ * Copyright 2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++
++#if !defined(OPENSSL_THREADS) || defined(CRYPTO_TDEBUG)
++
++CRYPTO_RWLOCK *CRYPTO_THREAD_lock_new(void)
++{
++    CRYPTO_RWLOCK *lock = OPENSSL_zalloc(sizeof(unsigned int));
++    if (lock == NULL)
++        return NULL;
++
++    *(unsigned int *)lock = 1;
++
++    return lock;
++}
++
++int CRYPTO_THREAD_read_lock(CRYPTO_RWLOCK *lock)
++{
++    OPENSSL_assert(*(unsigned int *)lock == 1);
++    return 1;
++}
++
++int CRYPTO_THREAD_write_lock(CRYPTO_RWLOCK *lock)
++{
++    OPENSSL_assert(*(unsigned int *)lock == 1);
++    return 1;
++}
++
++int CRYPTO_THREAD_unlock(CRYPTO_RWLOCK *lock)
++{
++    OPENSSL_assert(*(unsigned int *)lock == 1);
++    return 1;
++}
++
++void CRYPTO_THREAD_lock_free(CRYPTO_RWLOCK *lock) {
++    if (lock == NULL)
++        return;
++
++    *(unsigned int *)lock = 0;
++    OPENSSL_free(lock);
++
++    return;
++}
++
++int CRYPTO_THREAD_run_once(CRYPTO_ONCE *once, void (*init)(void))
++{
++    if (*once != 0)
++        return 1;
++
++    init();
++    *once = 1;
++
++    return 1;
++}
++
++#define OPENSSL_CRYPTO_THREAD_LOCAL_KEY_MAX 256
++
++static void *thread_local_storage[OPENSSL_CRYPTO_THREAD_LOCAL_KEY_MAX];
++
++int CRYPTO_THREAD_init_local(CRYPTO_THREAD_LOCAL *key, void (*cleanup)(void *))
++{
++    static unsigned int thread_local_key = 0;
++
++    if (thread_local_key >= OPENSSL_CRYPTO_THREAD_LOCAL_KEY_MAX)
++        return 0;
++
++    *key = thread_local_key++;
++
++    thread_local_storage[*key] = NULL;
++
++    return 1;
++}
++
++void *CRYPTO_THREAD_get_local(CRYPTO_THREAD_LOCAL *key)
++{
++    if (*key >= OPENSSL_CRYPTO_THREAD_LOCAL_KEY_MAX)
++        return NULL;
++
++    return thread_local_storage[*key];
++}
++
++int CRYPTO_THREAD_set_local(CRYPTO_THREAD_LOCAL *key, void *val)
++{
++    if (*key >= OPENSSL_CRYPTO_THREAD_LOCAL_KEY_MAX)
++        return 0;
++
++    thread_local_storage[*key] = val;
++
++    return 1;
++}
++
++int CRYPTO_THREAD_cleanup_local(CRYPTO_THREAD_LOCAL *key)
++{
++    *key = OPENSSL_CRYPTO_THREAD_LOCAL_KEY_MAX + 1;
++    return 1;
++}
++
++CRYPTO_THREAD_ID CRYPTO_THREAD_get_current_id(void)
++{
++    return 0;
++}
++
++int CRYPTO_THREAD_compare_id(CRYPTO_THREAD_ID a, CRYPTO_THREAD_ID b)
++{
++    return (a == b);
++}
++
++int CRYPTO_atomic_add(int *val, int amount, int *ret, CRYPTO_RWLOCK *lock)
++{
++    *val += amount;
++    *ret  = *val;
++
++    return 1;
++}
++
++#endif
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/threads_pthread.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/threads_pthread.c
+new file mode 100644
+index 0000000..151013e
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/threads_pthread.c
+@@ -0,0 +1,171 @@
++/*
++ * Copyright 2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++
++#if defined(OPENSSL_THREADS) && !defined(CRYPTO_TDEBUG) && !defined(OPENSSL_SYS_WINDOWS)
++
++# ifdef PTHREAD_RWLOCK_INITIALIZER
++#  define USE_RWLOCK
++# endif
++
++CRYPTO_RWLOCK *CRYPTO_THREAD_lock_new(void)
++{
++# ifdef USE_RWLOCK
++    CRYPTO_RWLOCK *lock = OPENSSL_zalloc(sizeof(pthread_rwlock_t));
++    if (lock == NULL)
++        return NULL;
++
++    if (pthread_rwlock_init(lock, NULL) != 0) {
++        OPENSSL_free(lock);
++        return NULL;
++    }
++# else
++    pthread_mutexattr_t attr;
++    CRYPTO_RWLOCK *lock = OPENSSL_zalloc(sizeof(pthread_mutex_t));
++    if (lock == NULL)
++        return NULL;
++
++    pthread_mutexattr_init(&attr);
++    pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
++
++    if (pthread_mutex_init(lock, &attr) != 0) {
++        pthread_mutexattr_destroy(&attr);
++        OPENSSL_free(lock);
++        return NULL;
++    }
++
++    pthread_mutexattr_destroy(&attr);
++# endif
++
++    return lock;
++}
++
++int CRYPTO_THREAD_read_lock(CRYPTO_RWLOCK *lock)
++{
++# ifdef USE_RWLOCK
++    if (pthread_rwlock_rdlock(lock) != 0)
++        return 0;
++# else
++    if (pthread_mutex_lock(lock) != 0)
++        return 0;
++# endif
++
++    return 1;
++}
++
++int CRYPTO_THREAD_write_lock(CRYPTO_RWLOCK *lock)
++{
++# ifdef USE_RWLOCK
++    if (pthread_rwlock_wrlock(lock) != 0)
++        return 0;
++# else
++    if (pthread_mutex_lock(lock) != 0)
++        return 0;
++# endif
++
++    return 1;
++}
++
++int CRYPTO_THREAD_unlock(CRYPTO_RWLOCK *lock)
++{
++# ifdef USE_RWLOCK
++    if (pthread_rwlock_unlock(lock) != 0)
++        return 0;
++# else
++    if (pthread_mutex_unlock(lock) != 0)
++        return 0;
++# endif
++
++    return 1;
++}
++
++void CRYPTO_THREAD_lock_free(CRYPTO_RWLOCK *lock)
++{
++    if (lock == NULL)
++        return;
++
++# ifdef USE_RWLOCK
++    pthread_rwlock_destroy(lock);
++# else
++    pthread_mutex_destroy(lock);
++# endif
++    OPENSSL_free(lock);
++
++    return;
++}
++
++int CRYPTO_THREAD_run_once(CRYPTO_ONCE *once, void (*init)(void))
++{
++    if (pthread_once(once, init) != 0)
++        return 0;
++
++    return 1;
++}
++
++int CRYPTO_THREAD_init_local(CRYPTO_THREAD_LOCAL *key, void (*cleanup)(void *))
++{
++    if (pthread_key_create(key, cleanup) != 0)
++        return 0;
++
++    return 1;
++}
++
++void *CRYPTO_THREAD_get_local(CRYPTO_THREAD_LOCAL *key)
++{
++    return pthread_getspecific(*key);
++}
++
++int CRYPTO_THREAD_set_local(CRYPTO_THREAD_LOCAL *key, void *val)
++{
++    if (pthread_setspecific(*key, val) != 0)
++        return 0;
++
++    return 1;
++}
++
++int CRYPTO_THREAD_cleanup_local(CRYPTO_THREAD_LOCAL *key)
++{
++    if (pthread_key_delete(*key) != 0)
++        return 0;
++
++    return 1;
++}
++
++CRYPTO_THREAD_ID CRYPTO_THREAD_get_current_id(void)
++{
++    return pthread_self();
++}
++
++int CRYPTO_THREAD_compare_id(CRYPTO_THREAD_ID a, CRYPTO_THREAD_ID b)
++{
++    return pthread_equal(a, b);
++}
++
++int CRYPTO_atomic_add(int *val, int amount, int *ret, CRYPTO_RWLOCK *lock)
++{
++# if defined(__GNUC__) && defined(__ATOMIC_ACQ_REL)
++    if (__atomic_is_lock_free(sizeof(*val), val)) {
++        *ret = __atomic_add_fetch(val, amount, __ATOMIC_ACQ_REL);
++        return 1;
++    }
++# endif
++    if (!CRYPTO_THREAD_write_lock(lock))
++        return 0;
++
++    *val += amount;
++    *ret  = *val;
++
++    if (!CRYPTO_THREAD_unlock(lock))
++        return 0;
++
++    return 1;
++}
++
++#endif
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/threads_win.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/threads_win.c
+new file mode 100644
+index 0000000..4e0de90
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/threads_win.c
+@@ -0,0 +1,136 @@
++/*
++ * Copyright 2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#if defined(_WIN32)
++# include 
++#endif
++
++#include 
++
++#if defined(OPENSSL_THREADS) && !defined(CRYPTO_TDEBUG) && defined(OPENSSL_SYS_WINDOWS)
++
++CRYPTO_RWLOCK *CRYPTO_THREAD_lock_new(void)
++{
++    CRYPTO_RWLOCK *lock = OPENSSL_zalloc(sizeof(CRITICAL_SECTION));
++    if (lock == NULL)
++        return NULL;
++
++    /* 0x400 is the spin count value suggested in the documentation */
++    if (!InitializeCriticalSectionAndSpinCount(lock, 0x400)) {
++        OPENSSL_free(lock);
++        return NULL;
++    }
++
++    return lock;
++}
++
++int CRYPTO_THREAD_read_lock(CRYPTO_RWLOCK *lock)
++{
++    EnterCriticalSection(lock);
++    return 1;
++}
++
++int CRYPTO_THREAD_write_lock(CRYPTO_RWLOCK *lock)
++{
++    EnterCriticalSection(lock);
++    return 1;
++}
++
++int CRYPTO_THREAD_unlock(CRYPTO_RWLOCK *lock)
++{
++    LeaveCriticalSection(lock);
++    return 1;
++}
++
++void CRYPTO_THREAD_lock_free(CRYPTO_RWLOCK *lock)
++{
++    if (lock == NULL)
++        return;
++
++    DeleteCriticalSection(lock);
++    OPENSSL_free(lock);
++
++    return;
++}
++
++#  define ONCE_UNINITED     0
++#  define ONCE_ININIT       1
++#  define ONCE_DONE         2
++
++/*
++ * We don't use InitOnceExecuteOnce because that isn't available in WinXP which
++ * we still have to support.
++ */
++int CRYPTO_THREAD_run_once(CRYPTO_ONCE *once, void (*init)(void))
++{
++    LONG volatile *lock = (LONG *)once;
++    LONG result;
++
++    if (*lock == ONCE_DONE)
++        return 1;
++
++    do {
++        result = InterlockedCompareExchange(lock, ONCE_ININIT, ONCE_UNINITED);
++        if (result == ONCE_UNINITED) {
++            init();
++            *lock = ONCE_DONE;
++            return 1;
++        }
++    } while (result == ONCE_ININIT);
++
++    return (*lock == ONCE_DONE);
++}
++
++int CRYPTO_THREAD_init_local(CRYPTO_THREAD_LOCAL *key, void (*cleanup)(void *))
++{
++    *key = TlsAlloc();
++    if (*key == TLS_OUT_OF_INDEXES)
++        return 0;
++
++    return 1;
++}
++
++void *CRYPTO_THREAD_get_local(CRYPTO_THREAD_LOCAL *key)
++{
++    return TlsGetValue(*key);
++}
++
++int CRYPTO_THREAD_set_local(CRYPTO_THREAD_LOCAL *key, void *val)
++{
++    if (TlsSetValue(*key, val) == 0)
++        return 0;
++
++    return 1;
++}
++
++int CRYPTO_THREAD_cleanup_local(CRYPTO_THREAD_LOCAL *key)
++{
++    if (TlsFree(*key) == 0)
++        return 0;
++
++    return 1;
++}
++
++CRYPTO_THREAD_ID CRYPTO_THREAD_get_current_id(void)
++{
++    return GetCurrentThreadId();
++}
++
++int CRYPTO_THREAD_compare_id(CRYPTO_THREAD_ID a, CRYPTO_THREAD_ID b)
++{
++    return (a == b);
++}
++
++int CRYPTO_atomic_add(int *val, int amount, int *ret, CRYPTO_RWLOCK *lock)
++{
++    *ret = InterlockedExchangeAdd(val, amount) + amount;
++    return 1;
++}
++
++#endif
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/ts/build.info b/CryptoPkg/Library/OpensslLib/openssl/crypto/ts/build.info
+new file mode 100644
+index 0000000..98e633d
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/ts/build.info
+@@ -0,0 +1,5 @@
++LIBS=../../libcrypto
++SOURCE[../../libcrypto]=\
++        ts_err.c ts_req_utils.c ts_req_print.c ts_rsp_utils.c ts_rsp_print.c \
++        ts_rsp_sign.c ts_rsp_verify.c ts_verify_ctx.c ts_lib.c ts_conf.c \
++        ts_asn1.c
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/ts/ts_asn1.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/ts/ts_asn1.c
+new file mode 100644
+index 0000000..e60675a
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/ts/ts_asn1.c
+@@ -0,0 +1,259 @@
++/*
++ * Copyright 2006-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include 
++#include 
++#include "ts_lcl.h"
++
++ASN1_SEQUENCE(TS_MSG_IMPRINT) = {
++        ASN1_SIMPLE(TS_MSG_IMPRINT, hash_algo, X509_ALGOR),
++        ASN1_SIMPLE(TS_MSG_IMPRINT, hashed_msg, ASN1_OCTET_STRING)
++} static_ASN1_SEQUENCE_END(TS_MSG_IMPRINT)
++
++IMPLEMENT_ASN1_FUNCTIONS_const(TS_MSG_IMPRINT)
++IMPLEMENT_ASN1_DUP_FUNCTION(TS_MSG_IMPRINT)
++TS_MSG_IMPRINT *d2i_TS_MSG_IMPRINT_bio(BIO *bp, TS_MSG_IMPRINT **a)
++{
++    return ASN1_d2i_bio_of(TS_MSG_IMPRINT, TS_MSG_IMPRINT_new,
++                           d2i_TS_MSG_IMPRINT, bp, a);
++}
++
++int i2d_TS_MSG_IMPRINT_bio(BIO *bp, TS_MSG_IMPRINT *a)
++{
++    return ASN1_i2d_bio_of_const(TS_MSG_IMPRINT, i2d_TS_MSG_IMPRINT, bp, a);
++}
++#ifndef OPENSSL_NO_STDIO
++TS_MSG_IMPRINT *d2i_TS_MSG_IMPRINT_fp(FILE *fp, TS_MSG_IMPRINT **a)
++{
++    return ASN1_d2i_fp_of(TS_MSG_IMPRINT, TS_MSG_IMPRINT_new,
++                          d2i_TS_MSG_IMPRINT, fp, a);
++}
++
++int i2d_TS_MSG_IMPRINT_fp(FILE *fp, TS_MSG_IMPRINT *a)
++{
++    return ASN1_i2d_fp_of_const(TS_MSG_IMPRINT, i2d_TS_MSG_IMPRINT, fp, a);
++}
++#endif
++
++ASN1_SEQUENCE(TS_REQ) = {
++        ASN1_SIMPLE(TS_REQ, version, ASN1_INTEGER),
++        ASN1_SIMPLE(TS_REQ, msg_imprint, TS_MSG_IMPRINT),
++        ASN1_OPT(TS_REQ, policy_id, ASN1_OBJECT),
++        ASN1_OPT(TS_REQ, nonce, ASN1_INTEGER),
++        ASN1_OPT(TS_REQ, cert_req, ASN1_FBOOLEAN),
++        ASN1_IMP_SEQUENCE_OF_OPT(TS_REQ, extensions, X509_EXTENSION, 0)
++} static_ASN1_SEQUENCE_END(TS_REQ)
++
++IMPLEMENT_ASN1_FUNCTIONS_const(TS_REQ)
++IMPLEMENT_ASN1_DUP_FUNCTION(TS_REQ)
++TS_REQ *d2i_TS_REQ_bio(BIO *bp, TS_REQ **a)
++{
++    return ASN1_d2i_bio_of(TS_REQ, TS_REQ_new, d2i_TS_REQ, bp, a);
++}
++
++int i2d_TS_REQ_bio(BIO *bp, TS_REQ *a)
++{
++    return ASN1_i2d_bio_of_const(TS_REQ, i2d_TS_REQ, bp, a);
++}
++#ifndef OPENSSL_NO_STDIO
++TS_REQ *d2i_TS_REQ_fp(FILE *fp, TS_REQ **a)
++{
++    return ASN1_d2i_fp_of(TS_REQ, TS_REQ_new, d2i_TS_REQ, fp, a);
++}
++
++int i2d_TS_REQ_fp(FILE *fp, TS_REQ *a)
++{
++    return ASN1_i2d_fp_of_const(TS_REQ, i2d_TS_REQ, fp, a);
++}
++#endif
++
++ASN1_SEQUENCE(TS_ACCURACY) = {
++        ASN1_OPT(TS_ACCURACY, seconds, ASN1_INTEGER),
++        ASN1_IMP_OPT(TS_ACCURACY, millis, ASN1_INTEGER, 0),
++        ASN1_IMP_OPT(TS_ACCURACY, micros, ASN1_INTEGER, 1)
++} static_ASN1_SEQUENCE_END(TS_ACCURACY)
++
++IMPLEMENT_ASN1_FUNCTIONS_const(TS_ACCURACY)
++IMPLEMENT_ASN1_DUP_FUNCTION(TS_ACCURACY)
++
++ASN1_SEQUENCE(TS_TST_INFO) = {
++        ASN1_SIMPLE(TS_TST_INFO, version, ASN1_INTEGER),
++        ASN1_SIMPLE(TS_TST_INFO, policy_id, ASN1_OBJECT),
++        ASN1_SIMPLE(TS_TST_INFO, msg_imprint, TS_MSG_IMPRINT),
++        ASN1_SIMPLE(TS_TST_INFO, serial, ASN1_INTEGER),
++        ASN1_SIMPLE(TS_TST_INFO, time, ASN1_GENERALIZEDTIME),
++        ASN1_OPT(TS_TST_INFO, accuracy, TS_ACCURACY),
++        ASN1_OPT(TS_TST_INFO, ordering, ASN1_FBOOLEAN),
++        ASN1_OPT(TS_TST_INFO, nonce, ASN1_INTEGER),
++        ASN1_EXP_OPT(TS_TST_INFO, tsa, GENERAL_NAME, 0),
++        ASN1_IMP_SEQUENCE_OF_OPT(TS_TST_INFO, extensions, X509_EXTENSION, 1)
++} static_ASN1_SEQUENCE_END(TS_TST_INFO)
++
++IMPLEMENT_ASN1_FUNCTIONS_const(TS_TST_INFO)
++IMPLEMENT_ASN1_DUP_FUNCTION(TS_TST_INFO)
++TS_TST_INFO *d2i_TS_TST_INFO_bio(BIO *bp, TS_TST_INFO **a)
++{
++    return ASN1_d2i_bio_of(TS_TST_INFO, TS_TST_INFO_new, d2i_TS_TST_INFO, bp,
++                           a);
++}
++
++int i2d_TS_TST_INFO_bio(BIO *bp, TS_TST_INFO *a)
++{
++    return ASN1_i2d_bio_of_const(TS_TST_INFO, i2d_TS_TST_INFO, bp, a);
++}
++#ifndef OPENSSL_NO_STDIO
++TS_TST_INFO *d2i_TS_TST_INFO_fp(FILE *fp, TS_TST_INFO **a)
++{
++    return ASN1_d2i_fp_of(TS_TST_INFO, TS_TST_INFO_new, d2i_TS_TST_INFO, fp,
++                          a);
++}
++
++int i2d_TS_TST_INFO_fp(FILE *fp, TS_TST_INFO *a)
++{
++    return ASN1_i2d_fp_of_const(TS_TST_INFO, i2d_TS_TST_INFO, fp, a);
++}
++#endif
++
++ASN1_SEQUENCE(TS_STATUS_INFO) = {
++        ASN1_SIMPLE(TS_STATUS_INFO, status, ASN1_INTEGER),
++        ASN1_SEQUENCE_OF_OPT(TS_STATUS_INFO, text, ASN1_UTF8STRING),
++        ASN1_OPT(TS_STATUS_INFO, failure_info, ASN1_BIT_STRING)
++} static_ASN1_SEQUENCE_END(TS_STATUS_INFO)
++
++IMPLEMENT_ASN1_FUNCTIONS_const(TS_STATUS_INFO)
++IMPLEMENT_ASN1_DUP_FUNCTION(TS_STATUS_INFO)
++
++static int ts_resp_set_tst_info(TS_RESP *a)
++{
++    long status;
++
++    status = ASN1_INTEGER_get(a->status_info->status);
++
++    if (a->token) {
++        if (status != 0 && status != 1) {
++            TSerr(TS_F_TS_RESP_SET_TST_INFO, TS_R_TOKEN_PRESENT);
++            return 0;
++        }
++        TS_TST_INFO_free(a->tst_info);
++        a->tst_info = PKCS7_to_TS_TST_INFO(a->token);
++        if (!a->tst_info) {
++            TSerr(TS_F_TS_RESP_SET_TST_INFO,
++                  TS_R_PKCS7_TO_TS_TST_INFO_FAILED);
++            return 0;
++        }
++    } else if (status == 0 || status == 1) {
++        TSerr(TS_F_TS_RESP_SET_TST_INFO, TS_R_TOKEN_NOT_PRESENT);
++        return 0;
++    }
++
++    return 1;
++}
++
++static int ts_resp_cb(int op, ASN1_VALUE **pval, const ASN1_ITEM *it,
++                      void *exarg)
++{
++    TS_RESP *ts_resp = (TS_RESP *)*pval;
++    if (op == ASN1_OP_NEW_POST) {
++        ts_resp->tst_info = NULL;
++    } else if (op == ASN1_OP_FREE_POST) {
++        TS_TST_INFO_free(ts_resp->tst_info);
++    } else if (op == ASN1_OP_D2I_POST) {
++        if (ts_resp_set_tst_info(ts_resp) == 0)
++            return 0;
++    }
++    return 1;
++}
++
++ASN1_SEQUENCE_cb(TS_RESP, ts_resp_cb) = {
++        ASN1_SIMPLE(TS_RESP, status_info, TS_STATUS_INFO),
++        ASN1_OPT(TS_RESP, token, PKCS7),
++} static_ASN1_SEQUENCE_END_cb(TS_RESP, TS_RESP)
++
++IMPLEMENT_ASN1_FUNCTIONS_const(TS_RESP)
++
++IMPLEMENT_ASN1_DUP_FUNCTION(TS_RESP)
++
++TS_RESP *d2i_TS_RESP_bio(BIO *bp, TS_RESP **a)
++{
++    return ASN1_d2i_bio_of(TS_RESP, TS_RESP_new, d2i_TS_RESP, bp, a);
++}
++
++int i2d_TS_RESP_bio(BIO *bp, TS_RESP *a)
++{
++    return ASN1_i2d_bio_of_const(TS_RESP, i2d_TS_RESP, bp, a);
++}
++#ifndef OPENSSL_NO_STDIO
++TS_RESP *d2i_TS_RESP_fp(FILE *fp, TS_RESP **a)
++{
++    return ASN1_d2i_fp_of(TS_RESP, TS_RESP_new, d2i_TS_RESP, fp, a);
++}
++
++int i2d_TS_RESP_fp(FILE *fp, TS_RESP *a)
++{
++    return ASN1_i2d_fp_of_const(TS_RESP, i2d_TS_RESP, fp, a);
++}
++#endif
++
++ASN1_SEQUENCE(ESS_ISSUER_SERIAL) = {
++        ASN1_SEQUENCE_OF(ESS_ISSUER_SERIAL, issuer, GENERAL_NAME),
++        ASN1_SIMPLE(ESS_ISSUER_SERIAL, serial, ASN1_INTEGER)
++} static_ASN1_SEQUENCE_END(ESS_ISSUER_SERIAL)
++
++IMPLEMENT_ASN1_FUNCTIONS_const(ESS_ISSUER_SERIAL)
++IMPLEMENT_ASN1_DUP_FUNCTION(ESS_ISSUER_SERIAL)
++
++ASN1_SEQUENCE(ESS_CERT_ID) = {
++        ASN1_SIMPLE(ESS_CERT_ID, hash, ASN1_OCTET_STRING),
++        ASN1_OPT(ESS_CERT_ID, issuer_serial, ESS_ISSUER_SERIAL)
++} static_ASN1_SEQUENCE_END(ESS_CERT_ID)
++
++IMPLEMENT_ASN1_FUNCTIONS_const(ESS_CERT_ID)
++IMPLEMENT_ASN1_DUP_FUNCTION(ESS_CERT_ID)
++
++ASN1_SEQUENCE(ESS_SIGNING_CERT) = {
++        ASN1_SEQUENCE_OF(ESS_SIGNING_CERT, cert_ids, ESS_CERT_ID),
++        ASN1_SEQUENCE_OF_OPT(ESS_SIGNING_CERT, policy_info, POLICYINFO)
++} static_ASN1_SEQUENCE_END(ESS_SIGNING_CERT)
++
++IMPLEMENT_ASN1_FUNCTIONS_const(ESS_SIGNING_CERT)
++IMPLEMENT_ASN1_DUP_FUNCTION(ESS_SIGNING_CERT)
++
++/* Getting encapsulated TS_TST_INFO object from PKCS7. */
++TS_TST_INFO *PKCS7_to_TS_TST_INFO(PKCS7 *token)
++{
++    PKCS7_SIGNED *pkcs7_signed;
++    PKCS7 *enveloped;
++    ASN1_TYPE *tst_info_wrapper;
++    ASN1_OCTET_STRING *tst_info_der;
++    const unsigned char *p;
++
++    if (!PKCS7_type_is_signed(token)) {
++        TSerr(TS_F_PKCS7_TO_TS_TST_INFO, TS_R_BAD_PKCS7_TYPE);
++        return NULL;
++    }
++    if (PKCS7_get_detached(token)) {
++        TSerr(TS_F_PKCS7_TO_TS_TST_INFO, TS_R_DETACHED_CONTENT);
++        return NULL;
++    }
++    pkcs7_signed = token->d.sign;
++    enveloped = pkcs7_signed->contents;
++    if (OBJ_obj2nid(enveloped->type) != NID_id_smime_ct_TSTInfo) {
++        TSerr(TS_F_PKCS7_TO_TS_TST_INFO, TS_R_BAD_PKCS7_TYPE);
++        return NULL;
++    }
++    tst_info_wrapper = enveloped->d.other;
++    if (tst_info_wrapper->type != V_ASN1_OCTET_STRING) {
++        TSerr(TS_F_PKCS7_TO_TS_TST_INFO, TS_R_BAD_TYPE);
++        return NULL;
++    }
++    tst_info_der = tst_info_wrapper->value.octet_string;
++    p = tst_info_der->data;
++    return d2i_TS_TST_INFO(NULL, &p, tst_info_der->length);
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/ts/ts_conf.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/ts/ts_conf.c
+new file mode 100644
+index 0000000..f5f3934
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/ts/ts_conf.c
+@@ -0,0 +1,468 @@
++/*
++ * Copyright 2006-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++
++#include 
++#include "internal/cryptlib.h"
++#include 
++#include 
++#include 
++
++/* Macro definitions for the configuration file. */
++#define BASE_SECTION                    "tsa"
++#define ENV_DEFAULT_TSA                 "default_tsa"
++#define ENV_SERIAL                      "serial"
++#define ENV_CRYPTO_DEVICE               "crypto_device"
++#define ENV_SIGNER_CERT                 "signer_cert"
++#define ENV_CERTS                       "certs"
++#define ENV_SIGNER_KEY                  "signer_key"
++#define ENV_SIGNER_DIGEST               "signer_digest"
++#define ENV_DEFAULT_POLICY              "default_policy"
++#define ENV_OTHER_POLICIES              "other_policies"
++#define ENV_DIGESTS                     "digests"
++#define ENV_ACCURACY                    "accuracy"
++#define ENV_ORDERING                    "ordering"
++#define ENV_TSA_NAME                    "tsa_name"
++#define ENV_ESS_CERT_ID_CHAIN           "ess_cert_id_chain"
++#define ENV_VALUE_SECS                  "secs"
++#define ENV_VALUE_MILLISECS             "millisecs"
++#define ENV_VALUE_MICROSECS             "microsecs"
++#define ENV_CLOCK_PRECISION_DIGITS      "clock_precision_digits"
++#define ENV_VALUE_YES                   "yes"
++#define ENV_VALUE_NO                    "no"
++
++/* Function definitions for certificate and key loading. */
++
++X509 *TS_CONF_load_cert(const char *file)
++{
++    BIO *cert = NULL;
++    X509 *x = NULL;
++
++    if ((cert = BIO_new_file(file, "r")) == NULL)
++        goto end;
++    x = PEM_read_bio_X509_AUX(cert, NULL, NULL, NULL);
++ end:
++    if (x == NULL)
++        TSerr(TS_F_TS_CONF_LOAD_CERT, TS_R_CANNOT_LOAD_CERT);
++    BIO_free(cert);
++    return x;
++}
++
++STACK_OF(X509) *TS_CONF_load_certs(const char *file)
++{
++    BIO *certs = NULL;
++    STACK_OF(X509) *othercerts = NULL;
++    STACK_OF(X509_INFO) *allcerts = NULL;
++    int i;
++
++    if ((certs = BIO_new_file(file, "r")) == NULL)
++        goto end;
++    if ((othercerts = sk_X509_new_null()) == NULL)
++        goto end;
++
++    allcerts = PEM_X509_INFO_read_bio(certs, NULL, NULL, NULL);
++    for (i = 0; i < sk_X509_INFO_num(allcerts); i++) {
++        X509_INFO *xi = sk_X509_INFO_value(allcerts, i);
++        if (xi->x509) {
++            sk_X509_push(othercerts, xi->x509);
++            xi->x509 = NULL;
++        }
++    }
++ end:
++    if (othercerts == NULL)
++        TSerr(TS_F_TS_CONF_LOAD_CERTS, TS_R_CANNOT_LOAD_CERT);
++    sk_X509_INFO_pop_free(allcerts, X509_INFO_free);
++    BIO_free(certs);
++    return othercerts;
++}
++
++EVP_PKEY *TS_CONF_load_key(const char *file, const char *pass)
++{
++    BIO *key = NULL;
++    EVP_PKEY *pkey = NULL;
++
++    if ((key = BIO_new_file(file, "r")) == NULL)
++        goto end;
++    pkey = PEM_read_bio_PrivateKey(key, NULL, NULL, (char *)pass);
++ end:
++    if (pkey == NULL)
++        TSerr(TS_F_TS_CONF_LOAD_KEY, TS_R_CANNOT_LOAD_KEY);
++    BIO_free(key);
++    return pkey;
++}
++
++/* Function definitions for handling configuration options. */
++
++static void ts_CONF_lookup_fail(const char *name, const char *tag)
++{
++    TSerr(TS_F_TS_CONF_LOOKUP_FAIL, TS_R_VAR_LOOKUP_FAILURE);
++    ERR_add_error_data(3, name, "::", tag);
++}
++
++static void ts_CONF_invalid(const char *name, const char *tag)
++{
++    TSerr(TS_F_TS_CONF_INVALID, TS_R_VAR_BAD_VALUE);
++    ERR_add_error_data(3, name, "::", tag);
++}
++
++const char *TS_CONF_get_tsa_section(CONF *conf, const char *section)
++{
++    if (!section) {
++        section = NCONF_get_string(conf, BASE_SECTION, ENV_DEFAULT_TSA);
++        if (!section)
++            ts_CONF_lookup_fail(BASE_SECTION, ENV_DEFAULT_TSA);
++    }
++    return section;
++}
++
++int TS_CONF_set_serial(CONF *conf, const char *section, TS_serial_cb cb,
++                       TS_RESP_CTX *ctx)
++{
++    int ret = 0;
++    char *serial = NCONF_get_string(conf, section, ENV_SERIAL);
++    if (!serial) {
++        ts_CONF_lookup_fail(section, ENV_SERIAL);
++        goto err;
++    }
++    TS_RESP_CTX_set_serial_cb(ctx, cb, serial);
++
++    ret = 1;
++ err:
++    return ret;
++}
++
++#ifndef OPENSSL_NO_ENGINE
++
++int TS_CONF_set_crypto_device(CONF *conf, const char *section,
++                              const char *device)
++{
++    int ret = 0;
++
++    if (device == NULL)
++        device = NCONF_get_string(conf, section, ENV_CRYPTO_DEVICE);
++
++    if (device && !TS_CONF_set_default_engine(device)) {
++        ts_CONF_invalid(section, ENV_CRYPTO_DEVICE);
++        goto err;
++    }
++    ret = 1;
++ err:
++    return ret;
++}
++
++int TS_CONF_set_default_engine(const char *name)
++{
++    ENGINE *e = NULL;
++    int ret = 0;
++
++    if (strcmp(name, "builtin") == 0)
++        return 1;
++
++    if ((e = ENGINE_by_id(name)) == NULL)
++        goto err;
++    if (strcmp(name, "chil") == 0)
++        ENGINE_ctrl(e, ENGINE_CTRL_CHIL_SET_FORKCHECK, 1, 0, 0);
++    if (!ENGINE_set_default(e, ENGINE_METHOD_ALL))
++        goto err;
++    ret = 1;
++
++ err:
++    if (!ret) {
++        TSerr(TS_F_TS_CONF_SET_DEFAULT_ENGINE, TS_R_COULD_NOT_SET_ENGINE);
++        ERR_add_error_data(2, "engine:", name);
++    }
++    ENGINE_free(e);
++    return ret;
++}
++
++#endif
++
++int TS_CONF_set_signer_cert(CONF *conf, const char *section,
++                            const char *cert, TS_RESP_CTX *ctx)
++{
++    int ret = 0;
++    X509 *cert_obj = NULL;
++
++    if (cert == NULL) {
++        cert = NCONF_get_string(conf, section, ENV_SIGNER_CERT);
++        if (cert == NULL) {
++            ts_CONF_lookup_fail(section, ENV_SIGNER_CERT);
++            goto err;
++        }
++    }
++    if ((cert_obj = TS_CONF_load_cert(cert)) == NULL)
++        goto err;
++    if (!TS_RESP_CTX_set_signer_cert(ctx, cert_obj))
++        goto err;
++
++    ret = 1;
++ err:
++    X509_free(cert_obj);
++    return ret;
++}
++
++int TS_CONF_set_certs(CONF *conf, const char *section, const char *certs,
++                      TS_RESP_CTX *ctx)
++{
++    int ret = 0;
++    STACK_OF(X509) *certs_obj = NULL;
++
++    if (certs == NULL) {
++        /* Certificate chain is optional. */
++        if ((certs = NCONF_get_string(conf, section, ENV_CERTS)) == NULL)
++            goto end;
++    }
++    if ((certs_obj = TS_CONF_load_certs(certs)) == NULL)
++        goto err;
++    if (!TS_RESP_CTX_set_certs(ctx, certs_obj))
++        goto err;
++ end:
++    ret = 1;
++ err:
++    sk_X509_pop_free(certs_obj, X509_free);
++    return ret;
++}
++
++int TS_CONF_set_signer_key(CONF *conf, const char *section,
++                           const char *key, const char *pass,
++                           TS_RESP_CTX *ctx)
++{
++    int ret = 0;
++    EVP_PKEY *key_obj = NULL;
++    if (!key)
++        key = NCONF_get_string(conf, section, ENV_SIGNER_KEY);
++    if (!key) {
++        ts_CONF_lookup_fail(section, ENV_SIGNER_KEY);
++        goto err;
++    }
++    if ((key_obj = TS_CONF_load_key(key, pass)) == NULL)
++        goto err;
++    if (!TS_RESP_CTX_set_signer_key(ctx, key_obj))
++        goto err;
++
++    ret = 1;
++ err:
++    EVP_PKEY_free(key_obj);
++    return ret;
++}
++
++int TS_CONF_set_signer_digest(CONF *conf, const char *section,
++                              const char *md, TS_RESP_CTX *ctx)
++{
++    int ret = 0;
++    const EVP_MD *sign_md = NULL;
++    if (md == NULL)
++        md = NCONF_get_string(conf, section, ENV_SIGNER_DIGEST);
++    if (md == NULL) {
++        ts_CONF_lookup_fail(section, ENV_SIGNER_DIGEST);
++        goto err;
++    }
++    sign_md = EVP_get_digestbyname(md);
++    if (sign_md == NULL) {
++        ts_CONF_invalid(section, ENV_SIGNER_DIGEST);
++        goto err;
++    }
++    if (!TS_RESP_CTX_set_signer_digest(ctx, sign_md))
++        goto err;
++
++    ret = 1;
++ err:
++    return ret;
++}
++
++int TS_CONF_set_def_policy(CONF *conf, const char *section,
++                           const char *policy, TS_RESP_CTX *ctx)
++{
++    int ret = 0;
++    ASN1_OBJECT *policy_obj = NULL;
++    if (!policy)
++        policy = NCONF_get_string(conf, section, ENV_DEFAULT_POLICY);
++    if (!policy) {
++        ts_CONF_lookup_fail(section, ENV_DEFAULT_POLICY);
++        goto err;
++    }
++    if ((policy_obj = OBJ_txt2obj(policy, 0)) == NULL) {
++        ts_CONF_invalid(section, ENV_DEFAULT_POLICY);
++        goto err;
++    }
++    if (!TS_RESP_CTX_set_def_policy(ctx, policy_obj))
++        goto err;
++
++    ret = 1;
++ err:
++    ASN1_OBJECT_free(policy_obj);
++    return ret;
++}
++
++int TS_CONF_set_policies(CONF *conf, const char *section, TS_RESP_CTX *ctx)
++{
++    int ret = 0;
++    int i;
++    STACK_OF(CONF_VALUE) *list = NULL;
++    char *policies = NCONF_get_string(conf, section, ENV_OTHER_POLICIES);
++
++    /* If no other policy is specified, that's fine. */
++    if (policies && (list = X509V3_parse_list(policies)) == NULL) {
++        ts_CONF_invalid(section, ENV_OTHER_POLICIES);
++        goto err;
++    }
++    for (i = 0; i < sk_CONF_VALUE_num(list); ++i) {
++        CONF_VALUE *val = sk_CONF_VALUE_value(list, i);
++        const char *extval = val->value ? val->value : val->name;
++        ASN1_OBJECT *objtmp;
++
++        if ((objtmp = OBJ_txt2obj(extval, 0)) == NULL) {
++            ts_CONF_invalid(section, ENV_OTHER_POLICIES);
++            goto err;
++        }
++        if (!TS_RESP_CTX_add_policy(ctx, objtmp))
++            goto err;
++        ASN1_OBJECT_free(objtmp);
++    }
++
++    ret = 1;
++ err:
++    sk_CONF_VALUE_pop_free(list, X509V3_conf_free);
++    return ret;
++}
++
++int TS_CONF_set_digests(CONF *conf, const char *section, TS_RESP_CTX *ctx)
++{
++    int ret = 0;
++    int i;
++    STACK_OF(CONF_VALUE) *list = NULL;
++    char *digests = NCONF_get_string(conf, section, ENV_DIGESTS);
++
++    if (digests == NULL) {
++        ts_CONF_lookup_fail(section, ENV_DIGESTS);
++        goto err;
++    }
++    if ((list = X509V3_parse_list(digests)) == NULL) {
++        ts_CONF_invalid(section, ENV_DIGESTS);
++        goto err;
++    }
++    if (sk_CONF_VALUE_num(list) == 0) {
++        ts_CONF_invalid(section, ENV_DIGESTS);
++        goto err;
++    }
++    for (i = 0; i < sk_CONF_VALUE_num(list); ++i) {
++        CONF_VALUE *val = sk_CONF_VALUE_value(list, i);
++        const char *extval = val->value ? val->value : val->name;
++        const EVP_MD *md;
++
++        if ((md = EVP_get_digestbyname(extval)) == NULL) {
++            ts_CONF_invalid(section, ENV_DIGESTS);
++            goto err;
++        }
++        if (!TS_RESP_CTX_add_md(ctx, md))
++            goto err;
++    }
++
++    ret = 1;
++ err:
++    sk_CONF_VALUE_pop_free(list, X509V3_conf_free);
++    return ret;
++}
++
++int TS_CONF_set_accuracy(CONF *conf, const char *section, TS_RESP_CTX *ctx)
++{
++    int ret = 0;
++    int i;
++    int secs = 0, millis = 0, micros = 0;
++    STACK_OF(CONF_VALUE) *list = NULL;
++    char *accuracy = NCONF_get_string(conf, section, ENV_ACCURACY);
++
++    if (accuracy && (list = X509V3_parse_list(accuracy)) == NULL) {
++        ts_CONF_invalid(section, ENV_ACCURACY);
++        goto err;
++    }
++    for (i = 0; i < sk_CONF_VALUE_num(list); ++i) {
++        CONF_VALUE *val = sk_CONF_VALUE_value(list, i);
++        if (strcmp(val->name, ENV_VALUE_SECS) == 0) {
++            if (val->value)
++                secs = atoi(val->value);
++        } else if (strcmp(val->name, ENV_VALUE_MILLISECS) == 0) {
++            if (val->value)
++                millis = atoi(val->value);
++        } else if (strcmp(val->name, ENV_VALUE_MICROSECS) == 0) {
++            if (val->value)
++                micros = atoi(val->value);
++        } else {
++            ts_CONF_invalid(section, ENV_ACCURACY);
++            goto err;
++        }
++    }
++    if (!TS_RESP_CTX_set_accuracy(ctx, secs, millis, micros))
++        goto err;
++
++    ret = 1;
++ err:
++    sk_CONF_VALUE_pop_free(list, X509V3_conf_free);
++    return ret;
++}
++
++int TS_CONF_set_clock_precision_digits(CONF *conf, const char *section,
++                                       TS_RESP_CTX *ctx)
++{
++    int ret = 0;
++    long digits = 0;
++
++    /*
++     * If not specified, set the default value to 0, i.e. sec precision
++     */
++    if (!NCONF_get_number_e(conf, section, ENV_CLOCK_PRECISION_DIGITS,
++                            &digits))
++        digits = 0;
++    if (digits < 0 || digits > TS_MAX_CLOCK_PRECISION_DIGITS) {
++        ts_CONF_invalid(section, ENV_CLOCK_PRECISION_DIGITS);
++        goto err;
++    }
++
++    if (!TS_RESP_CTX_set_clock_precision_digits(ctx, digits))
++        goto err;
++
++    return 1;
++ err:
++    return ret;
++}
++
++static int ts_CONF_add_flag(CONF *conf, const char *section,
++                            const char *field, int flag, TS_RESP_CTX *ctx)
++{
++    const char *value = NCONF_get_string(conf, section, field);
++
++    if (value) {
++        if (strcmp(value, ENV_VALUE_YES) == 0)
++            TS_RESP_CTX_add_flags(ctx, flag);
++        else if (strcmp(value, ENV_VALUE_NO) != 0) {
++            ts_CONF_invalid(section, field);
++            return 0;
++        }
++    }
++
++    return 1;
++}
++
++int TS_CONF_set_ordering(CONF *conf, const char *section, TS_RESP_CTX *ctx)
++{
++    return ts_CONF_add_flag(conf, section, ENV_ORDERING, TS_ORDERING, ctx);
++}
++
++int TS_CONF_set_tsa_name(CONF *conf, const char *section, TS_RESP_CTX *ctx)
++{
++    return ts_CONF_add_flag(conf, section, ENV_TSA_NAME, TS_TSA_NAME, ctx);
++}
++
++int TS_CONF_set_ess_cert_id_chain(CONF *conf, const char *section,
++                                  TS_RESP_CTX *ctx)
++{
++    return ts_CONF_add_flag(conf, section, ENV_ESS_CERT_ID_CHAIN,
++                            TS_ESS_CERT_ID_CHAIN, ctx);
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/ts/ts_err.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/ts/ts_err.c
+new file mode 100644
+index 0000000..a6d73a1
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/ts/ts_err.c
+@@ -0,0 +1,144 @@
++/*
++ * Generated by util/mkerr.pl DO NOT EDIT
++ * Copyright 1995-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include 
++#include 
++
++/* BEGIN ERROR CODES */
++#ifndef OPENSSL_NO_ERR
++
++# define ERR_FUNC(func) ERR_PACK(ERR_LIB_TS,func,0)
++# define ERR_REASON(reason) ERR_PACK(ERR_LIB_TS,0,reason)
++
++static ERR_STRING_DATA TS_str_functs[] = {
++    {ERR_FUNC(TS_F_DEF_SERIAL_CB), "def_serial_cb"},
++    {ERR_FUNC(TS_F_DEF_TIME_CB), "def_time_cb"},
++    {ERR_FUNC(TS_F_ESS_ADD_SIGNING_CERT), "ESS_add_signing_cert"},
++    {ERR_FUNC(TS_F_ESS_CERT_ID_NEW_INIT), "ess_CERT_ID_new_init"},
++    {ERR_FUNC(TS_F_ESS_SIGNING_CERT_NEW_INIT), "ess_SIGNING_CERT_new_init"},
++    {ERR_FUNC(TS_F_INT_TS_RESP_VERIFY_TOKEN), "int_ts_RESP_verify_token"},
++    {ERR_FUNC(TS_F_PKCS7_TO_TS_TST_INFO), "PKCS7_to_TS_TST_INFO"},
++    {ERR_FUNC(TS_F_TS_ACCURACY_SET_MICROS), "TS_ACCURACY_set_micros"},
++    {ERR_FUNC(TS_F_TS_ACCURACY_SET_MILLIS), "TS_ACCURACY_set_millis"},
++    {ERR_FUNC(TS_F_TS_ACCURACY_SET_SECONDS), "TS_ACCURACY_set_seconds"},
++    {ERR_FUNC(TS_F_TS_CHECK_IMPRINTS), "ts_check_imprints"},
++    {ERR_FUNC(TS_F_TS_CHECK_NONCES), "ts_check_nonces"},
++    {ERR_FUNC(TS_F_TS_CHECK_POLICY), "ts_check_policy"},
++    {ERR_FUNC(TS_F_TS_CHECK_SIGNING_CERTS), "ts_check_signing_certs"},
++    {ERR_FUNC(TS_F_TS_CHECK_STATUS_INFO), "ts_check_status_info"},
++    {ERR_FUNC(TS_F_TS_COMPUTE_IMPRINT), "ts_compute_imprint"},
++    {ERR_FUNC(TS_F_TS_CONF_INVALID), "ts_CONF_invalid"},
++    {ERR_FUNC(TS_F_TS_CONF_LOAD_CERT), "TS_CONF_load_cert"},
++    {ERR_FUNC(TS_F_TS_CONF_LOAD_CERTS), "TS_CONF_load_certs"},
++    {ERR_FUNC(TS_F_TS_CONF_LOAD_KEY), "TS_CONF_load_key"},
++    {ERR_FUNC(TS_F_TS_CONF_LOOKUP_FAIL), "ts_CONF_lookup_fail"},
++    {ERR_FUNC(TS_F_TS_CONF_SET_DEFAULT_ENGINE), "TS_CONF_set_default_engine"},
++    {ERR_FUNC(TS_F_TS_GET_STATUS_TEXT), "ts_get_status_text"},
++    {ERR_FUNC(TS_F_TS_MSG_IMPRINT_SET_ALGO), "TS_MSG_IMPRINT_set_algo"},
++    {ERR_FUNC(TS_F_TS_REQ_SET_MSG_IMPRINT), "TS_REQ_set_msg_imprint"},
++    {ERR_FUNC(TS_F_TS_REQ_SET_NONCE), "TS_REQ_set_nonce"},
++    {ERR_FUNC(TS_F_TS_REQ_SET_POLICY_ID), "TS_REQ_set_policy_id"},
++    {ERR_FUNC(TS_F_TS_RESP_CREATE_RESPONSE), "TS_RESP_create_response"},
++    {ERR_FUNC(TS_F_TS_RESP_CREATE_TST_INFO), "ts_RESP_create_tst_info"},
++    {ERR_FUNC(TS_F_TS_RESP_CTX_ADD_FAILURE_INFO),
++     "TS_RESP_CTX_add_failure_info"},
++    {ERR_FUNC(TS_F_TS_RESP_CTX_ADD_MD), "TS_RESP_CTX_add_md"},
++    {ERR_FUNC(TS_F_TS_RESP_CTX_ADD_POLICY), "TS_RESP_CTX_add_policy"},
++    {ERR_FUNC(TS_F_TS_RESP_CTX_NEW), "TS_RESP_CTX_new"},
++    {ERR_FUNC(TS_F_TS_RESP_CTX_SET_ACCURACY), "TS_RESP_CTX_set_accuracy"},
++    {ERR_FUNC(TS_F_TS_RESP_CTX_SET_CERTS), "TS_RESP_CTX_set_certs"},
++    {ERR_FUNC(TS_F_TS_RESP_CTX_SET_DEF_POLICY), "TS_RESP_CTX_set_def_policy"},
++    {ERR_FUNC(TS_F_TS_RESP_CTX_SET_SIGNER_CERT),
++     "TS_RESP_CTX_set_signer_cert"},
++    {ERR_FUNC(TS_F_TS_RESP_CTX_SET_STATUS_INFO),
++     "TS_RESP_CTX_set_status_info"},
++    {ERR_FUNC(TS_F_TS_RESP_GET_POLICY), "ts_RESP_get_policy"},
++    {ERR_FUNC(TS_F_TS_RESP_SET_GENTIME_WITH_PRECISION),
++     "TS_RESP_set_genTime_with_precision"},
++    {ERR_FUNC(TS_F_TS_RESP_SET_STATUS_INFO), "TS_RESP_set_status_info"},
++    {ERR_FUNC(TS_F_TS_RESP_SET_TST_INFO), "TS_RESP_set_tst_info"},
++    {ERR_FUNC(TS_F_TS_RESP_SIGN), "ts_RESP_sign"},
++    {ERR_FUNC(TS_F_TS_RESP_VERIFY_SIGNATURE), "TS_RESP_verify_signature"},
++    {ERR_FUNC(TS_F_TS_TST_INFO_SET_ACCURACY), "TS_TST_INFO_set_accuracy"},
++    {ERR_FUNC(TS_F_TS_TST_INFO_SET_MSG_IMPRINT),
++     "TS_TST_INFO_set_msg_imprint"},
++    {ERR_FUNC(TS_F_TS_TST_INFO_SET_NONCE), "TS_TST_INFO_set_nonce"},
++    {ERR_FUNC(TS_F_TS_TST_INFO_SET_POLICY_ID), "TS_TST_INFO_set_policy_id"},
++    {ERR_FUNC(TS_F_TS_TST_INFO_SET_SERIAL), "TS_TST_INFO_set_serial"},
++    {ERR_FUNC(TS_F_TS_TST_INFO_SET_TIME), "TS_TST_INFO_set_time"},
++    {ERR_FUNC(TS_F_TS_TST_INFO_SET_TSA), "TS_TST_INFO_set_tsa"},
++    {ERR_FUNC(TS_F_TS_VERIFY), "TS_VERIFY"},
++    {ERR_FUNC(TS_F_TS_VERIFY_CERT), "ts_verify_cert"},
++    {ERR_FUNC(TS_F_TS_VERIFY_CTX_NEW), "TS_VERIFY_CTX_new"},
++    {0, NULL}
++};
++
++static ERR_STRING_DATA TS_str_reasons[] = {
++    {ERR_REASON(TS_R_BAD_PKCS7_TYPE), "bad pkcs7 type"},
++    {ERR_REASON(TS_R_BAD_TYPE), "bad type"},
++    {ERR_REASON(TS_R_CANNOT_LOAD_CERT), "cannot load certificate"},
++    {ERR_REASON(TS_R_CANNOT_LOAD_KEY), "cannot load private key"},
++    {ERR_REASON(TS_R_CERTIFICATE_VERIFY_ERROR), "certificate verify error"},
++    {ERR_REASON(TS_R_COULD_NOT_SET_ENGINE), "could not set engine"},
++    {ERR_REASON(TS_R_COULD_NOT_SET_TIME), "could not set time"},
++    {ERR_REASON(TS_R_DETACHED_CONTENT), "detached content"},
++    {ERR_REASON(TS_R_ESS_ADD_SIGNING_CERT_ERROR),
++     "ess add signing cert error"},
++    {ERR_REASON(TS_R_ESS_SIGNING_CERTIFICATE_ERROR),
++     "ess signing certificate error"},
++    {ERR_REASON(TS_R_INVALID_NULL_POINTER), "invalid null pointer"},
++    {ERR_REASON(TS_R_INVALID_SIGNER_CERTIFICATE_PURPOSE),
++     "invalid signer certificate purpose"},
++    {ERR_REASON(TS_R_MESSAGE_IMPRINT_MISMATCH), "message imprint mismatch"},
++    {ERR_REASON(TS_R_NONCE_MISMATCH), "nonce mismatch"},
++    {ERR_REASON(TS_R_NONCE_NOT_RETURNED), "nonce not returned"},
++    {ERR_REASON(TS_R_NO_CONTENT), "no content"},
++    {ERR_REASON(TS_R_NO_TIME_STAMP_TOKEN), "no time stamp token"},
++    {ERR_REASON(TS_R_PKCS7_ADD_SIGNATURE_ERROR), "pkcs7 add signature error"},
++    {ERR_REASON(TS_R_PKCS7_ADD_SIGNED_ATTR_ERROR),
++     "pkcs7 add signed attr error"},
++    {ERR_REASON(TS_R_PKCS7_TO_TS_TST_INFO_FAILED),
++     "pkcs7 to ts tst info failed"},
++    {ERR_REASON(TS_R_POLICY_MISMATCH), "policy mismatch"},
++    {ERR_REASON(TS_R_PRIVATE_KEY_DOES_NOT_MATCH_CERTIFICATE),
++     "private key does not match certificate"},
++    {ERR_REASON(TS_R_RESPONSE_SETUP_ERROR), "response setup error"},
++    {ERR_REASON(TS_R_SIGNATURE_FAILURE), "signature failure"},
++    {ERR_REASON(TS_R_THERE_MUST_BE_ONE_SIGNER), "there must be one signer"},
++    {ERR_REASON(TS_R_TIME_SYSCALL_ERROR), "time syscall error"},
++    {ERR_REASON(TS_R_TOKEN_NOT_PRESENT), "token not present"},
++    {ERR_REASON(TS_R_TOKEN_PRESENT), "token present"},
++    {ERR_REASON(TS_R_TSA_NAME_MISMATCH), "tsa name mismatch"},
++    {ERR_REASON(TS_R_TSA_UNTRUSTED), "tsa untrusted"},
++    {ERR_REASON(TS_R_TST_INFO_SETUP_ERROR), "tst info setup error"},
++    {ERR_REASON(TS_R_TS_DATASIGN), "ts datasign"},
++    {ERR_REASON(TS_R_UNACCEPTABLE_POLICY), "unacceptable policy"},
++    {ERR_REASON(TS_R_UNSUPPORTED_MD_ALGORITHM), "unsupported md algorithm"},
++    {ERR_REASON(TS_R_UNSUPPORTED_VERSION), "unsupported version"},
++    {ERR_REASON(TS_R_VAR_BAD_VALUE), "var bad value"},
++    {ERR_REASON(TS_R_VAR_LOOKUP_FAILURE), "cannot find config variable"},
++    {ERR_REASON(TS_R_WRONG_CONTENT_TYPE), "wrong content type"},
++    {0, NULL}
++};
++
++#endif
++
++int ERR_load_TS_strings(void)
++{
++#ifndef OPENSSL_NO_ERR
++
++    if (ERR_func_error_string(TS_str_functs[0].error) == NULL) {
++        ERR_load_strings(0, TS_str_functs);
++        ERR_load_strings(0, TS_str_reasons);
++    }
++#endif
++    return 1;
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/ts/ts_lcl.h b/CryptoPkg/Library/OpensslLib/openssl/crypto/ts/ts_lcl.h
+new file mode 100644
+index 0000000..d0c3cf8
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/ts/ts_lcl.h
+@@ -0,0 +1,183 @@
++/*
++ * Copyright 2015-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++/*-
++ * MessageImprint ::= SEQUENCE  {
++ *      hashAlgorithm                AlgorithmIdentifier,
++ *      hashedMessage                OCTET STRING  }
++ */
++struct TS_msg_imprint_st {
++    X509_ALGOR *hash_algo;
++    ASN1_OCTET_STRING *hashed_msg;
++};
++
++/*-
++ * TimeStampResp ::= SEQUENCE  {
++ *     status                  PKIStatusInfo,
++ *     timeStampToken          TimeStampToken     OPTIONAL }
++ */
++struct TS_resp_st {
++    TS_STATUS_INFO *status_info;
++    PKCS7 *token;
++    TS_TST_INFO *tst_info;
++};
++
++/*-
++ * TimeStampReq ::= SEQUENCE  {
++ *    version                  INTEGER  { v1(1) },
++ *    messageImprint           MessageImprint,
++ *      --a hash algorithm OID and the hash value of the data to be
++ *      --time-stamped
++ *    reqPolicy                TSAPolicyId                OPTIONAL,
++ *    nonce                    INTEGER                    OPTIONAL,
++ *    certReq                  BOOLEAN                    DEFAULT FALSE,
++ *    extensions               [0] IMPLICIT Extensions    OPTIONAL  }
++ */
++struct TS_req_st {
++    ASN1_INTEGER *version;
++    TS_MSG_IMPRINT *msg_imprint;
++    ASN1_OBJECT *policy_id;
++    ASN1_INTEGER *nonce;
++    ASN1_BOOLEAN cert_req;
++    STACK_OF(X509_EXTENSION) *extensions;
++};
++
++/*-
++ * Accuracy ::= SEQUENCE {
++ *                 seconds        INTEGER           OPTIONAL,
++ *                 millis     [0] INTEGER  (1..999) OPTIONAL,
++ *                 micros     [1] INTEGER  (1..999) OPTIONAL  }
++ */
++struct TS_accuracy_st {
++    ASN1_INTEGER *seconds;
++    ASN1_INTEGER *millis;
++    ASN1_INTEGER *micros;
++};
++
++/*-
++ * TSTInfo ::= SEQUENCE  {
++ *     version                      INTEGER  { v1(1) },
++ *     policy                       TSAPolicyId,
++ *     messageImprint               MessageImprint,
++ *       -- MUST have the same value as the similar field in
++ *       -- TimeStampReq
++ *     serialNumber                 INTEGER,
++ *      -- Time-Stamping users MUST be ready to accommodate integers
++ *      -- up to 160 bits.
++ *     genTime                      GeneralizedTime,
++ *     accuracy                     Accuracy                 OPTIONAL,
++ *     ordering                     BOOLEAN             DEFAULT FALSE,
++ *     nonce                        INTEGER                  OPTIONAL,
++ *       -- MUST be present if the similar field was present
++ *       -- in TimeStampReq.  In that case it MUST have the same value.
++ *     tsa                          [0] GeneralName          OPTIONAL,
++ *     extensions                   [1] IMPLICIT Extensions  OPTIONAL   }
++ */
++struct TS_tst_info_st {
++    ASN1_INTEGER *version;
++    ASN1_OBJECT *policy_id;
++    TS_MSG_IMPRINT *msg_imprint;
++    ASN1_INTEGER *serial;
++    ASN1_GENERALIZEDTIME *time;
++    TS_ACCURACY *accuracy;
++    ASN1_BOOLEAN ordering;
++    ASN1_INTEGER *nonce;
++    GENERAL_NAME *tsa;
++    STACK_OF(X509_EXTENSION) *extensions;
++};
++
++struct TS_status_info_st {
++    ASN1_INTEGER *status;
++    STACK_OF(ASN1_UTF8STRING) *text;
++    ASN1_BIT_STRING *failure_info;
++};
++
++/*-
++ * IssuerSerial ::= SEQUENCE {
++ *         issuer                   GeneralNames,
++ *         serialNumber             CertificateSerialNumber
++ *         }
++ */
++struct ESS_issuer_serial {
++    STACK_OF(GENERAL_NAME) *issuer;
++    ASN1_INTEGER *serial;
++};
++
++/*-
++ * ESSCertID ::=  SEQUENCE {
++ *         certHash                 Hash,
++ *         issuerSerial             IssuerSerial OPTIONAL
++ * }
++ */
++struct ESS_cert_id {
++    ASN1_OCTET_STRING *hash;    /* Always SHA-1 digest. */
++    ESS_ISSUER_SERIAL *issuer_serial;
++};
++
++/*-
++ * SigningCertificate ::=  SEQUENCE {
++ *        certs        SEQUENCE OF ESSCertID,
++ *        policies     SEQUENCE OF PolicyInformation OPTIONAL
++ * }
++ */
++struct ESS_signing_cert {
++    STACK_OF(ESS_CERT_ID) *cert_ids;
++    STACK_OF(POLICYINFO) *policy_info;
++};
++
++
++struct TS_resp_ctx {
++    X509 *signer_cert;
++    EVP_PKEY *signer_key;
++    const EVP_MD *signer_md;
++    STACK_OF(X509) *certs;      /* Certs to include in signed data. */
++    STACK_OF(ASN1_OBJECT) *policies; /* Acceptable policies. */
++    ASN1_OBJECT *default_policy; /* It may appear in policies, too. */
++    STACK_OF(EVP_MD) *mds;      /* Acceptable message digests. */
++    ASN1_INTEGER *seconds;      /* accuracy, 0 means not specified. */
++    ASN1_INTEGER *millis;       /* accuracy, 0 means not specified. */
++    ASN1_INTEGER *micros;       /* accuracy, 0 means not specified. */
++    unsigned clock_precision_digits; /* fraction of seconds in time stamp
++                                      * token. */
++    unsigned flags;             /* Optional info, see values above. */
++    /* Callback functions. */
++    TS_serial_cb serial_cb;
++    void *serial_cb_data;       /* User data for serial_cb. */
++    TS_time_cb time_cb;
++    void *time_cb_data;         /* User data for time_cb. */
++    TS_extension_cb extension_cb;
++    void *extension_cb_data;    /* User data for extension_cb. */
++    /* These members are used only while creating the response. */
++    TS_REQ *request;
++    TS_RESP *response;
++    TS_TST_INFO *tst_info;
++};
++
++struct TS_verify_ctx {
++    /* Set this to the union of TS_VFY_... flags you want to carry out. */
++    unsigned flags;
++    /* Must be set only with TS_VFY_SIGNATURE. certs is optional. */
++    X509_STORE *store;
++    STACK_OF(X509) *certs;
++    /* Must be set only with TS_VFY_POLICY. */
++    ASN1_OBJECT *policy;
++    /*
++     * Must be set only with TS_VFY_IMPRINT. If md_alg is NULL, the
++     * algorithm from the response is used.
++     */
++    X509_ALGOR *md_alg;
++    unsigned char *imprint;
++    unsigned imprint_len;
++    /* Must be set only with TS_VFY_DATA. */
++    BIO *data;
++    /* Must be set only with TS_VFY_TSA_NAME. */
++    ASN1_INTEGER *nonce;
++    /* Must be set only with TS_VFY_TSA_NAME. */
++    GENERAL_NAME *tsa_name;
++};
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/ts/ts_lib.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/ts/ts_lib.c
+new file mode 100644
+index 0000000..de36e0e
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/ts/ts_lib.c
+@@ -0,0 +1,93 @@
++/*
++ * Copyright 2006-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include "internal/cryptlib.h"
++#include 
++#include 
++#include 
++#include 
++#include 
++#include "ts_lcl.h"
++
++int TS_ASN1_INTEGER_print_bio(BIO *bio, const ASN1_INTEGER *num)
++{
++    BIGNUM *num_bn;
++    int result = 0;
++    char *hex;
++
++    num_bn = BN_new();
++    if (num_bn == NULL)
++        return -1;
++    ASN1_INTEGER_to_BN(num, num_bn);
++    if ((hex = BN_bn2hex(num_bn))) {
++        result = BIO_write(bio, "0x", 2) > 0;
++        result = result && BIO_write(bio, hex, strlen(hex)) > 0;
++        OPENSSL_free(hex);
++    }
++    BN_free(num_bn);
++
++    return result;
++}
++
++int TS_OBJ_print_bio(BIO *bio, const ASN1_OBJECT *obj)
++{
++    char obj_txt[128];
++
++    OBJ_obj2txt(obj_txt, sizeof(obj_txt), obj, 0);
++    BIO_printf(bio, "%s\n", obj_txt);
++
++    return 1;
++}
++
++int TS_ext_print_bio(BIO *bio, const STACK_OF(X509_EXTENSION) *extensions)
++{
++    int i, critical, n;
++    X509_EXTENSION *ex;
++    ASN1_OBJECT *obj;
++
++    BIO_printf(bio, "Extensions:\n");
++    n = X509v3_get_ext_count(extensions);
++    for (i = 0; i < n; i++) {
++        ex = X509v3_get_ext(extensions, i);
++        obj = X509_EXTENSION_get_object(ex);
++        if (i2a_ASN1_OBJECT(bio, obj) < 0)
++            return 0;
++        critical = X509_EXTENSION_get_critical(ex);
++        BIO_printf(bio, ":%s\n", critical ? " critical" : "");
++        if (!X509V3_EXT_print(bio, ex, 0, 4)) {
++            BIO_printf(bio, "%4s", "");
++            ASN1_STRING_print(bio, X509_EXTENSION_get_data(ex));
++        }
++        BIO_write(bio, "\n", 1);
++    }
++
++    return 1;
++}
++
++int TS_X509_ALGOR_print_bio(BIO *bio, const X509_ALGOR *alg)
++{
++    int i = OBJ_obj2nid(alg->algorithm);
++    return BIO_printf(bio, "Hash Algorithm: %s\n",
++                      (i == NID_undef) ? "UNKNOWN" : OBJ_nid2ln(i));
++}
++
++int TS_MSG_IMPRINT_print_bio(BIO *bio, TS_MSG_IMPRINT *a)
++{
++    ASN1_OCTET_STRING *msg;
++
++    TS_X509_ALGOR_print_bio(bio, a->hash_algo);
++
++    BIO_printf(bio, "Message data:\n");
++    msg = a->hashed_msg;
++    BIO_dump_indent(bio, (const char *)ASN1_STRING_get0_data(msg),
++                    ASN1_STRING_length(msg), 4);
++
++    return 1;
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/ts/ts_req_print.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/ts/ts_req_print.c
+new file mode 100644
+index 0000000..0dedf47
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/ts/ts_req_print.c
+@@ -0,0 +1,51 @@
++/*
++ * Copyright 2006-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include "internal/cryptlib.h"
++#include 
++#include 
++#include 
++#include 
++#include "ts_lcl.h"
++
++int TS_REQ_print_bio(BIO *bio, TS_REQ *a)
++{
++    int v;
++    ASN1_OBJECT *policy_id;
++
++    if (a == NULL)
++        return 0;
++
++    v = TS_REQ_get_version(a);
++    BIO_printf(bio, "Version: %d\n", v);
++
++    TS_MSG_IMPRINT_print_bio(bio, a->msg_imprint);
++
++    BIO_printf(bio, "Policy OID: ");
++    policy_id = TS_REQ_get_policy_id(a);
++    if (policy_id == NULL)
++        BIO_printf(bio, "unspecified\n");
++    else
++        TS_OBJ_print_bio(bio, policy_id);
++
++    BIO_printf(bio, "Nonce: ");
++    if (a->nonce == NULL)
++        BIO_printf(bio, "unspecified");
++    else
++        TS_ASN1_INTEGER_print_bio(bio, a->nonce);
++    BIO_write(bio, "\n", 1);
++
++    BIO_printf(bio, "Certificate required: %s\n",
++               a->cert_req ? "yes" : "no");
++
++    TS_ext_print_bio(bio, a->extensions);
++
++    return 1;
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/ts/ts_req_utils.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/ts/ts_req_utils.c
+new file mode 100644
+index 0000000..2073d33
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/ts/ts_req_utils.c
+@@ -0,0 +1,183 @@
++/*
++ * Copyright 2006-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include "internal/cryptlib.h"
++#include 
++#include 
++#include 
++#include "ts_lcl.h"
++
++int TS_REQ_set_version(TS_REQ *a, long version)
++{
++    return ASN1_INTEGER_set(a->version, version);
++}
++
++long TS_REQ_get_version(const TS_REQ *a)
++{
++    return ASN1_INTEGER_get(a->version);
++}
++
++int TS_REQ_set_msg_imprint(TS_REQ *a, TS_MSG_IMPRINT *msg_imprint)
++{
++    TS_MSG_IMPRINT *new_msg_imprint;
++
++    if (a->msg_imprint == msg_imprint)
++        return 1;
++    new_msg_imprint = TS_MSG_IMPRINT_dup(msg_imprint);
++    if (new_msg_imprint == NULL) {
++        TSerr(TS_F_TS_REQ_SET_MSG_IMPRINT, ERR_R_MALLOC_FAILURE);
++        return 0;
++    }
++    TS_MSG_IMPRINT_free(a->msg_imprint);
++    a->msg_imprint = new_msg_imprint;
++    return 1;
++}
++
++TS_MSG_IMPRINT *TS_REQ_get_msg_imprint(TS_REQ *a)
++{
++    return a->msg_imprint;
++}
++
++int TS_MSG_IMPRINT_set_algo(TS_MSG_IMPRINT *a, X509_ALGOR *alg)
++{
++    X509_ALGOR *new_alg;
++
++    if (a->hash_algo == alg)
++        return 1;
++    new_alg = X509_ALGOR_dup(alg);
++    if (new_alg == NULL) {
++        TSerr(TS_F_TS_MSG_IMPRINT_SET_ALGO, ERR_R_MALLOC_FAILURE);
++        return 0;
++    }
++    X509_ALGOR_free(a->hash_algo);
++    a->hash_algo = new_alg;
++    return 1;
++}
++
++X509_ALGOR *TS_MSG_IMPRINT_get_algo(TS_MSG_IMPRINT *a)
++{
++    return a->hash_algo;
++}
++
++int TS_MSG_IMPRINT_set_msg(TS_MSG_IMPRINT *a, unsigned char *d, int len)
++{
++    return ASN1_OCTET_STRING_set(a->hashed_msg, d, len);
++}
++
++ASN1_OCTET_STRING *TS_MSG_IMPRINT_get_msg(TS_MSG_IMPRINT *a)
++{
++    return a->hashed_msg;
++}
++
++int TS_REQ_set_policy_id(TS_REQ *a, const ASN1_OBJECT *policy)
++{
++    ASN1_OBJECT *new_policy;
++
++    if (a->policy_id == policy)
++        return 1;
++    new_policy = OBJ_dup(policy);
++    if (new_policy == NULL) {
++        TSerr(TS_F_TS_REQ_SET_POLICY_ID, ERR_R_MALLOC_FAILURE);
++        return 0;
++    }
++    ASN1_OBJECT_free(a->policy_id);
++    a->policy_id = new_policy;
++    return 1;
++}
++
++ASN1_OBJECT *TS_REQ_get_policy_id(TS_REQ *a)
++{
++    return a->policy_id;
++}
++
++int TS_REQ_set_nonce(TS_REQ *a, const ASN1_INTEGER *nonce)
++{
++    ASN1_INTEGER *new_nonce;
++
++    if (a->nonce == nonce)
++        return 1;
++    new_nonce = ASN1_INTEGER_dup(nonce);
++    if (new_nonce == NULL) {
++        TSerr(TS_F_TS_REQ_SET_NONCE, ERR_R_MALLOC_FAILURE);
++        return 0;
++    }
++    ASN1_INTEGER_free(a->nonce);
++    a->nonce = new_nonce;
++    return 1;
++}
++
++const ASN1_INTEGER *TS_REQ_get_nonce(const TS_REQ *a)
++{
++    return a->nonce;
++}
++
++int TS_REQ_set_cert_req(TS_REQ *a, int cert_req)
++{
++    a->cert_req = cert_req ? 0xFF : 0x00;
++    return 1;
++}
++
++int TS_REQ_get_cert_req(const TS_REQ *a)
++{
++    return a->cert_req ? 1 : 0;
++}
++
++STACK_OF(X509_EXTENSION) *TS_REQ_get_exts(TS_REQ *a)
++{
++    return a->extensions;
++}
++
++void TS_REQ_ext_free(TS_REQ *a)
++{
++    if (!a)
++        return;
++    sk_X509_EXTENSION_pop_free(a->extensions, X509_EXTENSION_free);
++    a->extensions = NULL;
++}
++
++int TS_REQ_get_ext_count(TS_REQ *a)
++{
++    return X509v3_get_ext_count(a->extensions);
++}
++
++int TS_REQ_get_ext_by_NID(TS_REQ *a, int nid, int lastpos)
++{
++    return X509v3_get_ext_by_NID(a->extensions, nid, lastpos);
++}
++
++int TS_REQ_get_ext_by_OBJ(TS_REQ *a, const ASN1_OBJECT *obj, int lastpos)
++{
++    return X509v3_get_ext_by_OBJ(a->extensions, obj, lastpos);
++}
++
++int TS_REQ_get_ext_by_critical(TS_REQ *a, int crit, int lastpos)
++{
++    return X509v3_get_ext_by_critical(a->extensions, crit, lastpos);
++}
++
++X509_EXTENSION *TS_REQ_get_ext(TS_REQ *a, int loc)
++{
++    return X509v3_get_ext(a->extensions, loc);
++}
++
++X509_EXTENSION *TS_REQ_delete_ext(TS_REQ *a, int loc)
++{
++    return X509v3_delete_ext(a->extensions, loc);
++}
++
++int TS_REQ_add_ext(TS_REQ *a, X509_EXTENSION *ex, int loc)
++{
++    return X509v3_add_ext(&a->extensions, ex, loc) != NULL;
++}
++
++void *TS_REQ_get_ext_d2i(TS_REQ *a, int nid, int *crit, int *idx)
++{
++    return X509V3_get_d2i(a->extensions, nid, crit, idx);
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/ts/ts_rsp_print.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/ts/ts_rsp_print.c
+new file mode 100644
+index 0000000..6eb0ec8
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/ts/ts_rsp_print.c
+@@ -0,0 +1,195 @@
++/*
++ * Copyright 2006-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include "internal/cryptlib.h"
++#include 
++#include 
++#include 
++#include 
++#include "ts_lcl.h"
++
++struct status_map_st {
++    int bit;
++    const char *text;
++};
++
++static int ts_status_map_print(BIO *bio, const struct status_map_st *a,
++                               const ASN1_BIT_STRING *v);
++static int ts_ACCURACY_print_bio(BIO *bio, const TS_ACCURACY *accuracy);
++
++
++int TS_RESP_print_bio(BIO *bio, TS_RESP *a)
++{
++    BIO_printf(bio, "Status info:\n");
++    TS_STATUS_INFO_print_bio(bio, a->status_info);
++
++    BIO_printf(bio, "\nTST info:\n");
++    if (a->tst_info != NULL)
++        TS_TST_INFO_print_bio(bio, a->tst_info);
++    else
++        BIO_printf(bio, "Not included.\n");
++
++    return 1;
++}
++
++int TS_STATUS_INFO_print_bio(BIO *bio, TS_STATUS_INFO *a)
++{
++    static const char *status_map[] = {
++        "Granted.",
++        "Granted with modifications.",
++        "Rejected.",
++        "Waiting.",
++        "Revocation warning.",
++        "Revoked."
++    };
++    static const struct status_map_st failure_map[] = {
++        {TS_INFO_BAD_ALG,
++         "unrecognized or unsupported algorithm identifier"},
++        {TS_INFO_BAD_REQUEST,
++         "transaction not permitted or supported"},
++        {TS_INFO_BAD_DATA_FORMAT,
++         "the data submitted has the wrong format"},
++        {TS_INFO_TIME_NOT_AVAILABLE,
++         "the TSA's time source is not available"},
++        {TS_INFO_UNACCEPTED_POLICY,
++         "the requested TSA policy is not supported by the TSA"},
++        {TS_INFO_UNACCEPTED_EXTENSION,
++         "the requested extension is not supported by the TSA"},
++        {TS_INFO_ADD_INFO_NOT_AVAILABLE,
++         "the additional information requested could not be understood "
++         "or is not available"},
++        {TS_INFO_SYSTEM_FAILURE,
++         "the request cannot be handled due to system failure"},
++        {-1, NULL}
++    };
++    long status;
++    int i, lines = 0;
++
++    BIO_printf(bio, "Status: ");
++    status = ASN1_INTEGER_get(a->status);
++    if (0 <= status && status < (long)OSSL_NELEM(status_map))
++        BIO_printf(bio, "%s\n", status_map[status]);
++    else
++        BIO_printf(bio, "out of bounds\n");
++
++    BIO_printf(bio, "Status description: ");
++    for (i = 0; i < sk_ASN1_UTF8STRING_num(a->text); ++i) {
++        if (i > 0)
++            BIO_puts(bio, "\t");
++        ASN1_STRING_print_ex(bio, sk_ASN1_UTF8STRING_value(a->text, i), 0);
++        BIO_puts(bio, "\n");
++    }
++    if (i == 0)
++        BIO_printf(bio, "unspecified\n");
++
++    BIO_printf(bio, "Failure info: ");
++    if (a->failure_info != NULL)
++        lines = ts_status_map_print(bio, failure_map, a->failure_info);
++    if (lines == 0)
++        BIO_printf(bio, "unspecified");
++    BIO_printf(bio, "\n");
++
++    return 1;
++}
++
++static int ts_status_map_print(BIO *bio, const struct status_map_st *a,
++                               const ASN1_BIT_STRING *v)
++{
++    int lines = 0;
++
++    for (; a->bit >= 0; ++a) {
++        if (ASN1_BIT_STRING_get_bit(v, a->bit)) {
++            if (++lines > 1)
++                BIO_printf(bio, ", ");
++            BIO_printf(bio, "%s", a->text);
++        }
++    }
++
++    return lines;
++}
++
++int TS_TST_INFO_print_bio(BIO *bio, TS_TST_INFO *a)
++{
++    int v;
++
++    if (a == NULL)
++        return 0;
++
++    v = ASN1_INTEGER_get(a->version);
++    BIO_printf(bio, "Version: %d\n", v);
++
++    BIO_printf(bio, "Policy OID: ");
++    TS_OBJ_print_bio(bio, a->policy_id);
++
++    TS_MSG_IMPRINT_print_bio(bio, a->msg_imprint);
++
++    BIO_printf(bio, "Serial number: ");
++    if (a->serial == NULL)
++        BIO_printf(bio, "unspecified");
++    else
++        TS_ASN1_INTEGER_print_bio(bio, a->serial);
++    BIO_write(bio, "\n", 1);
++
++    BIO_printf(bio, "Time stamp: ");
++    ASN1_GENERALIZEDTIME_print(bio, a->time);
++    BIO_write(bio, "\n", 1);
++
++    BIO_printf(bio, "Accuracy: ");
++    if (a->accuracy == NULL)
++        BIO_printf(bio, "unspecified");
++    else
++        ts_ACCURACY_print_bio(bio, a->accuracy);
++    BIO_write(bio, "\n", 1);
++
++    BIO_printf(bio, "Ordering: %s\n", a->ordering ? "yes" : "no");
++
++    BIO_printf(bio, "Nonce: ");
++    if (a->nonce == NULL)
++        BIO_printf(bio, "unspecified");
++    else
++        TS_ASN1_INTEGER_print_bio(bio, a->nonce);
++    BIO_write(bio, "\n", 1);
++
++    BIO_printf(bio, "TSA: ");
++    if (a->tsa == NULL)
++        BIO_printf(bio, "unspecified");
++    else {
++        STACK_OF(CONF_VALUE) *nval;
++        if ((nval = i2v_GENERAL_NAME(NULL, a->tsa, NULL)))
++            X509V3_EXT_val_prn(bio, nval, 0, 0);
++        sk_CONF_VALUE_pop_free(nval, X509V3_conf_free);
++    }
++    BIO_write(bio, "\n", 1);
++
++    TS_ext_print_bio(bio, a->extensions);
++
++    return 1;
++}
++
++static int ts_ACCURACY_print_bio(BIO *bio, const TS_ACCURACY *a)
++{
++    if (a->seconds != NULL)
++        TS_ASN1_INTEGER_print_bio(bio, a->seconds);
++    else
++        BIO_printf(bio, "unspecified");
++    BIO_printf(bio, " seconds, ");
++    if (a->millis != NULL)
++        TS_ASN1_INTEGER_print_bio(bio, a->millis);
++    else
++        BIO_printf(bio, "unspecified");
++    BIO_printf(bio, " millis, ");
++    if (a->micros != NULL)
++        TS_ASN1_INTEGER_print_bio(bio, a->micros);
++    else
++        BIO_printf(bio, "unspecified");
++    BIO_printf(bio, " micros");
++
++    return 1;
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/ts/ts_rsp_sign.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/ts/ts_rsp_sign.c
+new file mode 100644
+index 0000000..aea7b92
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/ts/ts_rsp_sign.c
+@@ -0,0 +1,904 @@
++/*
++ * Copyright 2006-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include "internal/cryptlib.h"
++
++#if defined(OPENSSL_SYS_UNIX)
++# include 
++#endif
++
++#include 
++#include 
++#include 
++#include "ts_lcl.h"
++
++static ASN1_INTEGER *def_serial_cb(struct TS_resp_ctx *, void *);
++static int def_time_cb(struct TS_resp_ctx *, void *, long *sec, long *usec);
++static int def_extension_cb(struct TS_resp_ctx *, X509_EXTENSION *, void *);
++
++static void ts_RESP_CTX_init(TS_RESP_CTX *ctx);
++static void ts_RESP_CTX_cleanup(TS_RESP_CTX *ctx);
++static int ts_RESP_check_request(TS_RESP_CTX *ctx);
++static ASN1_OBJECT *ts_RESP_get_policy(TS_RESP_CTX *ctx);
++static TS_TST_INFO *ts_RESP_create_tst_info(TS_RESP_CTX *ctx,
++                                            ASN1_OBJECT *policy);
++static int ts_RESP_process_extensions(TS_RESP_CTX *ctx);
++static int ts_RESP_sign(TS_RESP_CTX *ctx);
++
++static ESS_SIGNING_CERT *ess_SIGNING_CERT_new_init(X509 *signcert,
++                                                   STACK_OF(X509) *certs);
++static ESS_CERT_ID *ess_CERT_ID_new_init(X509 *cert, int issuer_needed);
++static int ts_TST_INFO_content_new(PKCS7 *p7);
++static int ESS_add_signing_cert(PKCS7_SIGNER_INFO *si, ESS_SIGNING_CERT *sc);
++
++static ASN1_GENERALIZEDTIME
++*TS_RESP_set_genTime_with_precision(ASN1_GENERALIZEDTIME *, long, long,
++                                    unsigned);
++
++/* Default callback for response generation. */
++static ASN1_INTEGER *def_serial_cb(struct TS_resp_ctx *ctx, void *data)
++{
++    ASN1_INTEGER *serial = ASN1_INTEGER_new();
++
++    if (serial == NULL)
++        goto err;
++    if (!ASN1_INTEGER_set(serial, 1))
++        goto err;
++    return serial;
++
++ err:
++    TSerr(TS_F_DEF_SERIAL_CB, ERR_R_MALLOC_FAILURE);
++    TS_RESP_CTX_set_status_info(ctx, TS_STATUS_REJECTION,
++                                "Error during serial number generation.");
++    return NULL;
++}
++
++#if defined(OPENSSL_SYS_UNIX)
++
++static int def_time_cb(struct TS_resp_ctx *ctx, void *data,
++                       long *sec, long *usec)
++{
++    struct timeval tv;
++    if (gettimeofday(&tv, NULL) != 0) {
++        TSerr(TS_F_DEF_TIME_CB, TS_R_TIME_SYSCALL_ERROR);
++        TS_RESP_CTX_set_status_info(ctx, TS_STATUS_REJECTION,
++                                    "Time is not available.");
++        TS_RESP_CTX_add_failure_info(ctx, TS_INFO_TIME_NOT_AVAILABLE);
++        return 0;
++    }
++    *sec = tv.tv_sec;
++    *usec = tv.tv_usec;
++
++    return 1;
++}
++
++#else
++
++static int def_time_cb(struct TS_resp_ctx *ctx, void *data,
++                       long *sec, long *usec)
++{
++    time_t t;
++    if (time(&t) == (time_t)-1) {
++        TSerr(TS_F_DEF_TIME_CB, TS_R_TIME_SYSCALL_ERROR);
++        TS_RESP_CTX_set_status_info(ctx, TS_STATUS_REJECTION,
++                                    "Time is not available.");
++        TS_RESP_CTX_add_failure_info(ctx, TS_INFO_TIME_NOT_AVAILABLE);
++        return 0;
++    }
++    *sec = (long)t;
++    *usec = 0;
++
++    return 1;
++}
++
++#endif
++
++static int def_extension_cb(struct TS_resp_ctx *ctx, X509_EXTENSION *ext,
++                            void *data)
++{
++    TS_RESP_CTX_set_status_info(ctx, TS_STATUS_REJECTION,
++                                "Unsupported extension.");
++    TS_RESP_CTX_add_failure_info(ctx, TS_INFO_UNACCEPTED_EXTENSION);
++    return 0;
++}
++
++/* TS_RESP_CTX management functions. */
++
++TS_RESP_CTX *TS_RESP_CTX_new()
++{
++    TS_RESP_CTX *ctx;
++
++    if ((ctx = OPENSSL_zalloc(sizeof(*ctx))) == NULL) {
++        TSerr(TS_F_TS_RESP_CTX_NEW, ERR_R_MALLOC_FAILURE);
++        return NULL;
++    }
++
++    ctx->signer_md = EVP_sha256();
++
++    ctx->serial_cb = def_serial_cb;
++    ctx->time_cb = def_time_cb;
++    ctx->extension_cb = def_extension_cb;
++
++    return ctx;
++}
++
++void TS_RESP_CTX_free(TS_RESP_CTX *ctx)
++{
++    if (!ctx)
++        return;
++
++    X509_free(ctx->signer_cert);
++    EVP_PKEY_free(ctx->signer_key);
++    sk_X509_pop_free(ctx->certs, X509_free);
++    sk_ASN1_OBJECT_pop_free(ctx->policies, ASN1_OBJECT_free);
++    ASN1_OBJECT_free(ctx->default_policy);
++    sk_EVP_MD_free(ctx->mds);   /* No EVP_MD_free method exists. */
++    ASN1_INTEGER_free(ctx->seconds);
++    ASN1_INTEGER_free(ctx->millis);
++    ASN1_INTEGER_free(ctx->micros);
++    OPENSSL_free(ctx);
++}
++
++int TS_RESP_CTX_set_signer_cert(TS_RESP_CTX *ctx, X509 *signer)
++{
++    if (X509_check_purpose(signer, X509_PURPOSE_TIMESTAMP_SIGN, 0) != 1) {
++        TSerr(TS_F_TS_RESP_CTX_SET_SIGNER_CERT,
++              TS_R_INVALID_SIGNER_CERTIFICATE_PURPOSE);
++        return 0;
++    }
++    X509_free(ctx->signer_cert);
++    ctx->signer_cert = signer;
++    X509_up_ref(ctx->signer_cert);
++    return 1;
++}
++
++int TS_RESP_CTX_set_signer_key(TS_RESP_CTX *ctx, EVP_PKEY *key)
++{
++    EVP_PKEY_free(ctx->signer_key);
++    ctx->signer_key = key;
++    EVP_PKEY_up_ref(ctx->signer_key);
++
++    return 1;
++}
++
++int TS_RESP_CTX_set_signer_digest(TS_RESP_CTX *ctx, const EVP_MD *md)
++{
++    ctx->signer_md = md;
++    return 1;
++}
++
++int TS_RESP_CTX_set_def_policy(TS_RESP_CTX *ctx, const ASN1_OBJECT *def_policy)
++{
++    ASN1_OBJECT_free(ctx->default_policy);
++    if ((ctx->default_policy = OBJ_dup(def_policy)) == NULL)
++        goto err;
++    return 1;
++ err:
++    TSerr(TS_F_TS_RESP_CTX_SET_DEF_POLICY, ERR_R_MALLOC_FAILURE);
++    return 0;
++}
++
++int TS_RESP_CTX_set_certs(TS_RESP_CTX *ctx, STACK_OF(X509) *certs)
++{
++
++    sk_X509_pop_free(ctx->certs, X509_free);
++    ctx->certs = NULL;
++    if (!certs)
++        return 1;
++    if ((ctx->certs = X509_chain_up_ref(certs)) == NULL) {
++        TSerr(TS_F_TS_RESP_CTX_SET_CERTS, ERR_R_MALLOC_FAILURE);
++        return 0;
++    }
++
++    return 1;
++}
++
++int TS_RESP_CTX_add_policy(TS_RESP_CTX *ctx, const ASN1_OBJECT *policy)
++{
++    ASN1_OBJECT *copy = NULL;
++
++    if (ctx->policies == NULL
++        && (ctx->policies = sk_ASN1_OBJECT_new_null()) == NULL)
++        goto err;
++    if ((copy = OBJ_dup(policy)) == NULL)
++        goto err;
++    if (!sk_ASN1_OBJECT_push(ctx->policies, copy))
++        goto err;
++
++    return 1;
++ err:
++    TSerr(TS_F_TS_RESP_CTX_ADD_POLICY, ERR_R_MALLOC_FAILURE);
++    ASN1_OBJECT_free(copy);
++    return 0;
++}
++
++int TS_RESP_CTX_add_md(TS_RESP_CTX *ctx, const EVP_MD *md)
++{
++    if (ctx->mds == NULL
++        && (ctx->mds = sk_EVP_MD_new_null()) == NULL)
++        goto err;
++    if (!sk_EVP_MD_push(ctx->mds, md))
++        goto err;
++
++    return 1;
++ err:
++    TSerr(TS_F_TS_RESP_CTX_ADD_MD, ERR_R_MALLOC_FAILURE);
++    return 0;
++}
++
++#define TS_RESP_CTX_accuracy_free(ctx)          \
++        ASN1_INTEGER_free(ctx->seconds);        \
++        ctx->seconds = NULL;                    \
++        ASN1_INTEGER_free(ctx->millis);         \
++        ctx->millis = NULL;                     \
++        ASN1_INTEGER_free(ctx->micros);         \
++        ctx->micros = NULL;
++
++int TS_RESP_CTX_set_accuracy(TS_RESP_CTX *ctx,
++                             int secs, int millis, int micros)
++{
++
++    TS_RESP_CTX_accuracy_free(ctx);
++    if (secs
++        && ((ctx->seconds = ASN1_INTEGER_new()) == NULL
++            || !ASN1_INTEGER_set(ctx->seconds, secs)))
++        goto err;
++    if (millis
++        && ((ctx->millis = ASN1_INTEGER_new()) == NULL
++            || !ASN1_INTEGER_set(ctx->millis, millis)))
++        goto err;
++    if (micros
++        && ((ctx->micros = ASN1_INTEGER_new()) == NULL
++            || !ASN1_INTEGER_set(ctx->micros, micros)))
++        goto err;
++
++    return 1;
++ err:
++    TS_RESP_CTX_accuracy_free(ctx);
++    TSerr(TS_F_TS_RESP_CTX_SET_ACCURACY, ERR_R_MALLOC_FAILURE);
++    return 0;
++}
++
++void TS_RESP_CTX_add_flags(TS_RESP_CTX *ctx, int flags)
++{
++    ctx->flags |= flags;
++}
++
++void TS_RESP_CTX_set_serial_cb(TS_RESP_CTX *ctx, TS_serial_cb cb, void *data)
++{
++    ctx->serial_cb = cb;
++    ctx->serial_cb_data = data;
++}
++
++void TS_RESP_CTX_set_time_cb(TS_RESP_CTX *ctx, TS_time_cb cb, void *data)
++{
++    ctx->time_cb = cb;
++    ctx->time_cb_data = data;
++}
++
++void TS_RESP_CTX_set_extension_cb(TS_RESP_CTX *ctx,
++                                  TS_extension_cb cb, void *data)
++{
++    ctx->extension_cb = cb;
++    ctx->extension_cb_data = data;
++}
++
++int TS_RESP_CTX_set_status_info(TS_RESP_CTX *ctx,
++                                int status, const char *text)
++{
++    TS_STATUS_INFO *si = NULL;
++    ASN1_UTF8STRING *utf8_text = NULL;
++    int ret = 0;
++
++    if ((si = TS_STATUS_INFO_new()) == NULL)
++        goto err;
++    if (!ASN1_INTEGER_set(si->status, status))
++        goto err;
++    if (text) {
++        if ((utf8_text = ASN1_UTF8STRING_new()) == NULL
++            || !ASN1_STRING_set(utf8_text, text, strlen(text)))
++            goto err;
++        if (si->text == NULL
++            && (si->text = sk_ASN1_UTF8STRING_new_null()) == NULL)
++            goto err;
++        if (!sk_ASN1_UTF8STRING_push(si->text, utf8_text))
++            goto err;
++        utf8_text = NULL;       /* Ownership is lost. */
++    }
++    if (!TS_RESP_set_status_info(ctx->response, si))
++        goto err;
++    ret = 1;
++ err:
++    if (!ret)
++        TSerr(TS_F_TS_RESP_CTX_SET_STATUS_INFO, ERR_R_MALLOC_FAILURE);
++    TS_STATUS_INFO_free(si);
++    ASN1_UTF8STRING_free(utf8_text);
++    return ret;
++}
++
++int TS_RESP_CTX_set_status_info_cond(TS_RESP_CTX *ctx,
++                                     int status, const char *text)
++{
++    int ret = 1;
++    TS_STATUS_INFO *si = ctx->response->status_info;
++
++    if (ASN1_INTEGER_get(si->status) == TS_STATUS_GRANTED) {
++        ret = TS_RESP_CTX_set_status_info(ctx, status, text);
++    }
++    return ret;
++}
++
++int TS_RESP_CTX_add_failure_info(TS_RESP_CTX *ctx, int failure)
++{
++    TS_STATUS_INFO *si = ctx->response->status_info;
++    if (si->failure_info == NULL
++        && (si->failure_info = ASN1_BIT_STRING_new()) == NULL)
++        goto err;
++    if (!ASN1_BIT_STRING_set_bit(si->failure_info, failure, 1))
++        goto err;
++    return 1;
++ err:
++    TSerr(TS_F_TS_RESP_CTX_ADD_FAILURE_INFO, ERR_R_MALLOC_FAILURE);
++    return 0;
++}
++
++TS_REQ *TS_RESP_CTX_get_request(TS_RESP_CTX *ctx)
++{
++    return ctx->request;
++}
++
++TS_TST_INFO *TS_RESP_CTX_get_tst_info(TS_RESP_CTX *ctx)
++{
++    return ctx->tst_info;
++}
++
++int TS_RESP_CTX_set_clock_precision_digits(TS_RESP_CTX *ctx,
++                                           unsigned precision)
++{
++    if (precision > TS_MAX_CLOCK_PRECISION_DIGITS)
++        return 0;
++    ctx->clock_precision_digits = precision;
++    return 1;
++}
++
++/* Main entry method of the response generation. */
++TS_RESP *TS_RESP_create_response(TS_RESP_CTX *ctx, BIO *req_bio)
++{
++    ASN1_OBJECT *policy;
++    TS_RESP *response;
++    int result = 0;
++
++    ts_RESP_CTX_init(ctx);
++
++    if ((ctx->response = TS_RESP_new()) == NULL) {
++        TSerr(TS_F_TS_RESP_CREATE_RESPONSE, ERR_R_MALLOC_FAILURE);
++        goto end;
++    }
++    if ((ctx->request = d2i_TS_REQ_bio(req_bio, NULL)) == NULL) {
++        TS_RESP_CTX_set_status_info(ctx, TS_STATUS_REJECTION,
++                                    "Bad request format or system error.");
++        TS_RESP_CTX_add_failure_info(ctx, TS_INFO_BAD_DATA_FORMAT);
++        goto end;
++    }
++    if (!TS_RESP_CTX_set_status_info(ctx, TS_STATUS_GRANTED, NULL))
++        goto end;
++    if (!ts_RESP_check_request(ctx))
++        goto end;
++    if ((policy = ts_RESP_get_policy(ctx)) == NULL)
++        goto end;
++    if ((ctx->tst_info = ts_RESP_create_tst_info(ctx, policy)) == NULL)
++        goto end;
++    if (!ts_RESP_process_extensions(ctx))
++        goto end;
++    if (!ts_RESP_sign(ctx))
++        goto end;
++    result = 1;
++
++ end:
++    if (!result) {
++        TSerr(TS_F_TS_RESP_CREATE_RESPONSE, TS_R_RESPONSE_SETUP_ERROR);
++        if (ctx->response != NULL) {
++            if (TS_RESP_CTX_set_status_info_cond(ctx,
++                                                 TS_STATUS_REJECTION,
++                                                 "Error during response "
++                                                 "generation.") == 0) {
++                TS_RESP_free(ctx->response);
++                ctx->response = NULL;
++            }
++        }
++    }
++    response = ctx->response;
++    ctx->response = NULL;       /* Ownership will be returned to caller. */
++    ts_RESP_CTX_cleanup(ctx);
++    return response;
++}
++
++/* Initializes the variable part of the context. */
++static void ts_RESP_CTX_init(TS_RESP_CTX *ctx)
++{
++    ctx->request = NULL;
++    ctx->response = NULL;
++    ctx->tst_info = NULL;
++}
++
++/* Cleans up the variable part of the context. */
++static void ts_RESP_CTX_cleanup(TS_RESP_CTX *ctx)
++{
++    TS_REQ_free(ctx->request);
++    ctx->request = NULL;
++    TS_RESP_free(ctx->response);
++    ctx->response = NULL;
++    TS_TST_INFO_free(ctx->tst_info);
++    ctx->tst_info = NULL;
++}
++
++/* Checks the format and content of the request. */
++static int ts_RESP_check_request(TS_RESP_CTX *ctx)
++{
++    TS_REQ *request = ctx->request;
++    TS_MSG_IMPRINT *msg_imprint;
++    X509_ALGOR *md_alg;
++    int md_alg_id;
++    const ASN1_OCTET_STRING *digest;
++    const EVP_MD *md = NULL;
++    int i;
++
++    if (TS_REQ_get_version(request) != 1) {
++        TS_RESP_CTX_set_status_info(ctx, TS_STATUS_REJECTION,
++                                    "Bad request version.");
++        TS_RESP_CTX_add_failure_info(ctx, TS_INFO_BAD_REQUEST);
++        return 0;
++    }
++
++    msg_imprint = request->msg_imprint;
++    md_alg = msg_imprint->hash_algo;
++    md_alg_id = OBJ_obj2nid(md_alg->algorithm);
++    for (i = 0; !md && i < sk_EVP_MD_num(ctx->mds); ++i) {
++        const EVP_MD *current_md = sk_EVP_MD_value(ctx->mds, i);
++        if (md_alg_id == EVP_MD_type(current_md))
++            md = current_md;
++    }
++    if (!md) {
++        TS_RESP_CTX_set_status_info(ctx, TS_STATUS_REJECTION,
++                                    "Message digest algorithm is "
++                                    "not supported.");
++        TS_RESP_CTX_add_failure_info(ctx, TS_INFO_BAD_ALG);
++        return 0;
++    }
++
++    if (md_alg->parameter && ASN1_TYPE_get(md_alg->parameter) != V_ASN1_NULL) {
++        TS_RESP_CTX_set_status_info(ctx, TS_STATUS_REJECTION,
++                                    "Superfluous message digest "
++                                    "parameter.");
++        TS_RESP_CTX_add_failure_info(ctx, TS_INFO_BAD_ALG);
++        return 0;
++    }
++    digest = msg_imprint->hashed_msg;
++    if (digest->length != EVP_MD_size(md)) {
++        TS_RESP_CTX_set_status_info(ctx, TS_STATUS_REJECTION,
++                                    "Bad message digest.");
++        TS_RESP_CTX_add_failure_info(ctx, TS_INFO_BAD_DATA_FORMAT);
++        return 0;
++    }
++
++    return 1;
++}
++
++/* Returns the TSA policy based on the requested and acceptable policies. */
++static ASN1_OBJECT *ts_RESP_get_policy(TS_RESP_CTX *ctx)
++{
++    ASN1_OBJECT *requested = ctx->request->policy_id;
++    ASN1_OBJECT *policy = NULL;
++    int i;
++
++    if (ctx->default_policy == NULL) {
++        TSerr(TS_F_TS_RESP_GET_POLICY, TS_R_INVALID_NULL_POINTER);
++        return NULL;
++    }
++    if (!requested || !OBJ_cmp(requested, ctx->default_policy))
++        policy = ctx->default_policy;
++
++    /* Check if the policy is acceptable. */
++    for (i = 0; !policy && i < sk_ASN1_OBJECT_num(ctx->policies); ++i) {
++        ASN1_OBJECT *current = sk_ASN1_OBJECT_value(ctx->policies, i);
++        if (!OBJ_cmp(requested, current))
++            policy = current;
++    }
++    if (!policy) {
++        TSerr(TS_F_TS_RESP_GET_POLICY, TS_R_UNACCEPTABLE_POLICY);
++        TS_RESP_CTX_set_status_info(ctx, TS_STATUS_REJECTION,
++                                    "Requested policy is not " "supported.");
++        TS_RESP_CTX_add_failure_info(ctx, TS_INFO_UNACCEPTED_POLICY);
++    }
++    return policy;
++}
++
++/* Creates the TS_TST_INFO object based on the settings of the context. */
++static TS_TST_INFO *ts_RESP_create_tst_info(TS_RESP_CTX *ctx,
++                                            ASN1_OBJECT *policy)
++{
++    int result = 0;
++    TS_TST_INFO *tst_info = NULL;
++    ASN1_INTEGER *serial = NULL;
++    ASN1_GENERALIZEDTIME *asn1_time = NULL;
++    long sec, usec;
++    TS_ACCURACY *accuracy = NULL;
++    const ASN1_INTEGER *nonce;
++    GENERAL_NAME *tsa_name = NULL;
++
++    if ((tst_info = TS_TST_INFO_new()) == NULL)
++        goto end;
++    if (!TS_TST_INFO_set_version(tst_info, 1))
++        goto end;
++    if (!TS_TST_INFO_set_policy_id(tst_info, policy))
++        goto end;
++    if (!TS_TST_INFO_set_msg_imprint(tst_info, ctx->request->msg_imprint))
++        goto end;
++    if ((serial = ctx->serial_cb(ctx, ctx->serial_cb_data)) == NULL
++        || !TS_TST_INFO_set_serial(tst_info, serial))
++        goto end;
++    if (!ctx->time_cb(ctx, ctx->time_cb_data, &sec, &usec)
++        || (asn1_time =
++            TS_RESP_set_genTime_with_precision(NULL, sec, usec,
++                                        ctx->clock_precision_digits)) == NULL
++        || !TS_TST_INFO_set_time(tst_info, asn1_time))
++        goto end;
++
++    if ((ctx->seconds || ctx->millis || ctx->micros)
++        && (accuracy = TS_ACCURACY_new()) == NULL)
++        goto end;
++    if (ctx->seconds && !TS_ACCURACY_set_seconds(accuracy, ctx->seconds))
++        goto end;
++    if (ctx->millis && !TS_ACCURACY_set_millis(accuracy, ctx->millis))
++        goto end;
++    if (ctx->micros && !TS_ACCURACY_set_micros(accuracy, ctx->micros))
++        goto end;
++    if (accuracy && !TS_TST_INFO_set_accuracy(tst_info, accuracy))
++        goto end;
++
++    if ((ctx->flags & TS_ORDERING)
++        && !TS_TST_INFO_set_ordering(tst_info, 1))
++        goto end;
++
++    if ((nonce = ctx->request->nonce) != NULL
++        && !TS_TST_INFO_set_nonce(tst_info, nonce))
++        goto end;
++
++    if (ctx->flags & TS_TSA_NAME) {
++        if ((tsa_name = GENERAL_NAME_new()) == NULL)
++            goto end;
++        tsa_name->type = GEN_DIRNAME;
++        tsa_name->d.dirn =
++            X509_NAME_dup(X509_get_subject_name(ctx->signer_cert));
++        if (!tsa_name->d.dirn)
++            goto end;
++        if (!TS_TST_INFO_set_tsa(tst_info, tsa_name))
++            goto end;
++    }
++
++    result = 1;
++ end:
++    if (!result) {
++        TS_TST_INFO_free(tst_info);
++        tst_info = NULL;
++        TSerr(TS_F_TS_RESP_CREATE_TST_INFO, TS_R_TST_INFO_SETUP_ERROR);
++        TS_RESP_CTX_set_status_info_cond(ctx, TS_STATUS_REJECTION,
++                                         "Error during TSTInfo "
++                                         "generation.");
++    }
++    GENERAL_NAME_free(tsa_name);
++    TS_ACCURACY_free(accuracy);
++    ASN1_GENERALIZEDTIME_free(asn1_time);
++    ASN1_INTEGER_free(serial);
++
++    return tst_info;
++}
++
++/* Processing the extensions of the request. */
++static int ts_RESP_process_extensions(TS_RESP_CTX *ctx)
++{
++    STACK_OF(X509_EXTENSION) *exts = ctx->request->extensions;
++    int i;
++    int ok = 1;
++
++    for (i = 0; ok && i < sk_X509_EXTENSION_num(exts); ++i) {
++        X509_EXTENSION *ext = sk_X509_EXTENSION_value(exts, i);
++        /*
++         * The last argument was previously (void *)ctx->extension_cb,
++         * but ISO C doesn't permit converting a function pointer to void *.
++         * For lack of better information, I'm placing a NULL there instead.
++         * The callback can pick its own address out from the ctx anyway...
++         */
++        ok = (*ctx->extension_cb) (ctx, ext, NULL);
++    }
++
++    return ok;
++}
++
++/* Functions for signing the TS_TST_INFO structure of the context. */
++static int ts_RESP_sign(TS_RESP_CTX *ctx)
++{
++    int ret = 0;
++    PKCS7 *p7 = NULL;
++    PKCS7_SIGNER_INFO *si;
++    STACK_OF(X509) *certs;      /* Certificates to include in sc. */
++    ESS_SIGNING_CERT *sc = NULL;
++    ASN1_OBJECT *oid;
++    BIO *p7bio = NULL;
++    int i;
++
++    if (!X509_check_private_key(ctx->signer_cert, ctx->signer_key)) {
++        TSerr(TS_F_TS_RESP_SIGN, TS_R_PRIVATE_KEY_DOES_NOT_MATCH_CERTIFICATE);
++        goto err;
++    }
++
++    if ((p7 = PKCS7_new()) == NULL) {
++        TSerr(TS_F_TS_RESP_SIGN, ERR_R_MALLOC_FAILURE);
++        goto err;
++    }
++    if (!PKCS7_set_type(p7, NID_pkcs7_signed))
++        goto err;
++    if (!ASN1_INTEGER_set(p7->d.sign->version, 3))
++        goto err;
++
++    if (ctx->request->cert_req) {
++        PKCS7_add_certificate(p7, ctx->signer_cert);
++        if (ctx->certs) {
++            for (i = 0; i < sk_X509_num(ctx->certs); ++i) {
++                X509 *cert = sk_X509_value(ctx->certs, i);
++                PKCS7_add_certificate(p7, cert);
++            }
++        }
++    }
++
++    if ((si = PKCS7_add_signature(p7, ctx->signer_cert,
++                                  ctx->signer_key, ctx->signer_md)) == NULL) {
++        TSerr(TS_F_TS_RESP_SIGN, TS_R_PKCS7_ADD_SIGNATURE_ERROR);
++        goto err;
++    }
++
++    oid = OBJ_nid2obj(NID_id_smime_ct_TSTInfo);
++    if (!PKCS7_add_signed_attribute(si, NID_pkcs9_contentType,
++                                    V_ASN1_OBJECT, oid)) {
++        TSerr(TS_F_TS_RESP_SIGN, TS_R_PKCS7_ADD_SIGNED_ATTR_ERROR);
++        goto err;
++    }
++
++    certs = ctx->flags & TS_ESS_CERT_ID_CHAIN ? ctx->certs : NULL;
++    if ((sc = ess_SIGNING_CERT_new_init(ctx->signer_cert, certs)) == NULL)
++        goto err;
++    if (!ESS_add_signing_cert(si, sc)) {
++        TSerr(TS_F_TS_RESP_SIGN, TS_R_ESS_ADD_SIGNING_CERT_ERROR);
++        goto err;
++    }
++
++    if (!ts_TST_INFO_content_new(p7))
++        goto err;
++    if ((p7bio = PKCS7_dataInit(p7, NULL)) == NULL) {
++        TSerr(TS_F_TS_RESP_SIGN, ERR_R_MALLOC_FAILURE);
++        goto err;
++    }
++    if (!i2d_TS_TST_INFO_bio(p7bio, ctx->tst_info)) {
++        TSerr(TS_F_TS_RESP_SIGN, TS_R_TS_DATASIGN);
++        goto err;
++    }
++    if (!PKCS7_dataFinal(p7, p7bio)) {
++        TSerr(TS_F_TS_RESP_SIGN, TS_R_TS_DATASIGN);
++        goto err;
++    }
++    TS_RESP_set_tst_info(ctx->response, p7, ctx->tst_info);
++    p7 = NULL;                  /* Ownership is lost. */
++    ctx->tst_info = NULL;       /* Ownership is lost. */
++
++    ret = 1;
++ err:
++    if (!ret)
++        TS_RESP_CTX_set_status_info_cond(ctx, TS_STATUS_REJECTION,
++                                         "Error during signature "
++                                         "generation.");
++    BIO_free_all(p7bio);
++    ESS_SIGNING_CERT_free(sc);
++    PKCS7_free(p7);
++    return ret;
++}
++
++static ESS_SIGNING_CERT *ess_SIGNING_CERT_new_init(X509 *signcert,
++                                                   STACK_OF(X509) *certs)
++{
++    ESS_CERT_ID *cid;
++    ESS_SIGNING_CERT *sc = NULL;
++    int i;
++
++    if ((sc = ESS_SIGNING_CERT_new()) == NULL)
++        goto err;
++    if (sc->cert_ids == NULL
++        && (sc->cert_ids = sk_ESS_CERT_ID_new_null()) == NULL)
++        goto err;
++
++    if ((cid = ess_CERT_ID_new_init(signcert, 0)) == NULL
++        || !sk_ESS_CERT_ID_push(sc->cert_ids, cid))
++        goto err;
++    for (i = 0; i < sk_X509_num(certs); ++i) {
++        X509 *cert = sk_X509_value(certs, i);
++        if ((cid = ess_CERT_ID_new_init(cert, 1)) == NULL
++            || !sk_ESS_CERT_ID_push(sc->cert_ids, cid))
++            goto err;
++    }
++
++    return sc;
++ err:
++    ESS_SIGNING_CERT_free(sc);
++    TSerr(TS_F_ESS_SIGNING_CERT_NEW_INIT, ERR_R_MALLOC_FAILURE);
++    return NULL;
++}
++
++static ESS_CERT_ID *ess_CERT_ID_new_init(X509 *cert, int issuer_needed)
++{
++    ESS_CERT_ID *cid = NULL;
++    GENERAL_NAME *name = NULL;
++    unsigned char cert_sha1[SHA_DIGEST_LENGTH];
++
++    /* Call for side-effect of computing hash and caching extensions */
++    X509_check_purpose(cert, -1, 0);
++    if ((cid = ESS_CERT_ID_new()) == NULL)
++        goto err;
++    X509_digest(cert, EVP_sha1(), cert_sha1, NULL);
++    if (!ASN1_OCTET_STRING_set(cid->hash, cert_sha1, SHA_DIGEST_LENGTH))
++        goto err;
++
++    /* Setting the issuer/serial if requested. */
++    if (issuer_needed) {
++        if (cid->issuer_serial == NULL
++            && (cid->issuer_serial = ESS_ISSUER_SERIAL_new()) == NULL)
++            goto err;
++        if ((name = GENERAL_NAME_new()) == NULL)
++            goto err;
++        name->type = GEN_DIRNAME;
++        if ((name->d.dirn = X509_NAME_dup(X509_get_issuer_name(cert))) == NULL)
++            goto err;
++        if (!sk_GENERAL_NAME_push(cid->issuer_serial->issuer, name))
++            goto err;
++        name = NULL;            /* Ownership is lost. */
++        ASN1_INTEGER_free(cid->issuer_serial->serial);
++        if (!(cid->issuer_serial->serial =
++              ASN1_INTEGER_dup(X509_get_serialNumber(cert))))
++            goto err;
++    }
++
++    return cid;
++ err:
++    GENERAL_NAME_free(name);
++    ESS_CERT_ID_free(cid);
++    TSerr(TS_F_ESS_CERT_ID_NEW_INIT, ERR_R_MALLOC_FAILURE);
++    return NULL;
++}
++
++static int ts_TST_INFO_content_new(PKCS7 *p7)
++{
++    PKCS7 *ret = NULL;
++    ASN1_OCTET_STRING *octet_string = NULL;
++
++    /* Create new encapsulated NID_id_smime_ct_TSTInfo content. */
++    if ((ret = PKCS7_new()) == NULL)
++        goto err;
++    if ((ret->d.other = ASN1_TYPE_new()) == NULL)
++        goto err;
++    ret->type = OBJ_nid2obj(NID_id_smime_ct_TSTInfo);
++    if ((octet_string = ASN1_OCTET_STRING_new()) == NULL)
++        goto err;
++    ASN1_TYPE_set(ret->d.other, V_ASN1_OCTET_STRING, octet_string);
++    octet_string = NULL;
++
++    /* Add encapsulated content to signed PKCS7 structure. */
++    if (!PKCS7_set_content(p7, ret))
++        goto err;
++
++    return 1;
++ err:
++    ASN1_OCTET_STRING_free(octet_string);
++    PKCS7_free(ret);
++    return 0;
++}
++
++static int ESS_add_signing_cert(PKCS7_SIGNER_INFO *si, ESS_SIGNING_CERT *sc)
++{
++    ASN1_STRING *seq = NULL;
++    unsigned char *p, *pp = NULL;
++    int len;
++
++    len = i2d_ESS_SIGNING_CERT(sc, NULL);
++    if ((pp = OPENSSL_malloc(len)) == NULL) {
++        TSerr(TS_F_ESS_ADD_SIGNING_CERT, ERR_R_MALLOC_FAILURE);
++        goto err;
++    }
++    p = pp;
++    i2d_ESS_SIGNING_CERT(sc, &p);
++    if ((seq = ASN1_STRING_new()) == NULL || !ASN1_STRING_set(seq, pp, len)) {
++        TSerr(TS_F_ESS_ADD_SIGNING_CERT, ERR_R_MALLOC_FAILURE);
++        goto err;
++    }
++    OPENSSL_free(pp);
++    pp = NULL;
++    return PKCS7_add_signed_attribute(si,
++                                      NID_id_smime_aa_signingCertificate,
++                                      V_ASN1_SEQUENCE, seq);
++ err:
++    ASN1_STRING_free(seq);
++    OPENSSL_free(pp);
++
++    return 0;
++}
++
++static ASN1_GENERALIZEDTIME
++*TS_RESP_set_genTime_with_precision(ASN1_GENERALIZEDTIME *asn1_time,
++                                    long sec, long usec, unsigned precision)
++{
++    time_t time_sec = (time_t)sec;
++    struct tm *tm = NULL;
++    char genTime_str[17 + TS_MAX_CLOCK_PRECISION_DIGITS];
++    char *p = genTime_str;
++    char *p_end = genTime_str + sizeof(genTime_str);
++
++    if (precision > TS_MAX_CLOCK_PRECISION_DIGITS)
++        goto err;
++
++    if ((tm = gmtime(&time_sec)) == NULL)
++        goto err;
++
++    /*
++     * Put "genTime_str" in GeneralizedTime format.  We work around the
++     * restrictions imposed by rfc3280 (i.e. "GeneralizedTime values MUST
++     * NOT include fractional seconds") and OpenSSL related functions to
++     * meet the rfc3161 requirement: "GeneralizedTime syntax can include
++     * fraction-of-second details".
++     */
++    p += BIO_snprintf(p, p_end - p,
++                      "%04d%02d%02d%02d%02d%02d",
++                      tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday,
++                      tm->tm_hour, tm->tm_min, tm->tm_sec);
++    if (precision > 0) {
++        BIO_snprintf(p, 2 + precision, ".%06ld", usec);
++        p += strlen(p);
++
++        /*
++         * To make things a bit harder, X.690 | ISO/IEC 8825-1 provides the
++         * following restrictions for a DER-encoding, which OpenSSL
++         * (specifically ASN1_GENERALIZEDTIME_check() function) doesn't
++         * support: "The encoding MUST terminate with a "Z" (which means
++         * "Zulu" time). The decimal point element, if present, MUST be the
++         * point option ".". The fractional-seconds elements, if present,
++         * MUST omit all trailing 0's; if the elements correspond to 0, they
++         * MUST be wholly omitted, and the decimal point element also MUST be
++         * omitted."
++         */
++        /*
++         * Remove trailing zeros. The dot guarantees the exit condition of
++         * this loop even if all the digits are zero.
++         */
++        while (*--p == '0')
++             continue;
++        if (*p != '.')
++            ++p;
++    }
++    *p++ = 'Z';
++    *p++ = '\0';
++
++    if (asn1_time == NULL
++        && (asn1_time = ASN1_GENERALIZEDTIME_new()) == NULL)
++        goto err;
++    if (!ASN1_GENERALIZEDTIME_set_string(asn1_time, genTime_str)) {
++        ASN1_GENERALIZEDTIME_free(asn1_time);
++        goto err;
++    }
++    return asn1_time;
++
++ err:
++    TSerr(TS_F_TS_RESP_SET_GENTIME_WITH_PRECISION, TS_R_COULD_NOT_SET_TIME);
++    return NULL;
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/ts/ts_rsp_utils.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/ts/ts_rsp_utils.c
+new file mode 100644
+index 0000000..3ecee39
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/ts/ts_rsp_utils.c
+@@ -0,0 +1,365 @@
++/*
++ * Copyright 2006-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include "internal/cryptlib.h"
++#include 
++#include 
++#include 
++#include "ts_lcl.h"
++
++int TS_RESP_set_status_info(TS_RESP *a, TS_STATUS_INFO *status_info)
++{
++    TS_STATUS_INFO *new_status_info;
++
++    if (a->status_info == status_info)
++        return 1;
++    new_status_info = TS_STATUS_INFO_dup(status_info);
++    if (new_status_info == NULL) {
++        TSerr(TS_F_TS_RESP_SET_STATUS_INFO, ERR_R_MALLOC_FAILURE);
++        return 0;
++    }
++    TS_STATUS_INFO_free(a->status_info);
++    a->status_info = new_status_info;
++
++    return 1;
++}
++
++TS_STATUS_INFO *TS_RESP_get_status_info(TS_RESP *a)
++{
++    return a->status_info;
++}
++
++/* Caller loses ownership of PKCS7 and TS_TST_INFO objects. */
++void TS_RESP_set_tst_info(TS_RESP *a, PKCS7 *p7, TS_TST_INFO *tst_info)
++{
++    PKCS7_free(a->token);
++    a->token = p7;
++    TS_TST_INFO_free(a->tst_info);
++    a->tst_info = tst_info;
++}
++
++PKCS7 *TS_RESP_get_token(TS_RESP *a)
++{
++    return a->token;
++}
++
++TS_TST_INFO *TS_RESP_get_tst_info(TS_RESP *a)
++{
++    return a->tst_info;
++}
++
++int TS_TST_INFO_set_version(TS_TST_INFO *a, long version)
++{
++    return ASN1_INTEGER_set(a->version, version);
++}
++
++long TS_TST_INFO_get_version(const TS_TST_INFO *a)
++{
++    return ASN1_INTEGER_get(a->version);
++}
++
++int TS_TST_INFO_set_policy_id(TS_TST_INFO *a, ASN1_OBJECT *policy)
++{
++    ASN1_OBJECT *new_policy;
++
++    if (a->policy_id == policy)
++        return 1;
++    new_policy = OBJ_dup(policy);
++    if (new_policy == NULL) {
++        TSerr(TS_F_TS_TST_INFO_SET_POLICY_ID, ERR_R_MALLOC_FAILURE);
++        return 0;
++    }
++    ASN1_OBJECT_free(a->policy_id);
++    a->policy_id = new_policy;
++    return 1;
++}
++
++ASN1_OBJECT *TS_TST_INFO_get_policy_id(TS_TST_INFO *a)
++{
++    return a->policy_id;
++}
++
++int TS_TST_INFO_set_msg_imprint(TS_TST_INFO *a, TS_MSG_IMPRINT *msg_imprint)
++{
++    TS_MSG_IMPRINT *new_msg_imprint;
++
++    if (a->msg_imprint == msg_imprint)
++        return 1;
++    new_msg_imprint = TS_MSG_IMPRINT_dup(msg_imprint);
++    if (new_msg_imprint == NULL) {
++        TSerr(TS_F_TS_TST_INFO_SET_MSG_IMPRINT, ERR_R_MALLOC_FAILURE);
++        return 0;
++    }
++    TS_MSG_IMPRINT_free(a->msg_imprint);
++    a->msg_imprint = new_msg_imprint;
++    return 1;
++}
++
++TS_MSG_IMPRINT *TS_TST_INFO_get_msg_imprint(TS_TST_INFO *a)
++{
++    return a->msg_imprint;
++}
++
++int TS_TST_INFO_set_serial(TS_TST_INFO *a, const ASN1_INTEGER *serial)
++{
++    ASN1_INTEGER *new_serial;
++
++    if (a->serial == serial)
++        return 1;
++    new_serial = ASN1_INTEGER_dup(serial);
++    if (new_serial == NULL) {
++        TSerr(TS_F_TS_TST_INFO_SET_SERIAL, ERR_R_MALLOC_FAILURE);
++        return 0;
++    }
++    ASN1_INTEGER_free(a->serial);
++    a->serial = new_serial;
++    return 1;
++}
++
++const ASN1_INTEGER *TS_TST_INFO_get_serial(const TS_TST_INFO *a)
++{
++    return a->serial;
++}
++
++int TS_TST_INFO_set_time(TS_TST_INFO *a, const ASN1_GENERALIZEDTIME *gtime)
++{
++    ASN1_GENERALIZEDTIME *new_time;
++
++    if (a->time == gtime)
++        return 1;
++    new_time = ASN1_STRING_dup(gtime);
++    if (new_time == NULL) {
++        TSerr(TS_F_TS_TST_INFO_SET_TIME, ERR_R_MALLOC_FAILURE);
++        return 0;
++    }
++    ASN1_GENERALIZEDTIME_free(a->time);
++    a->time = new_time;
++    return 1;
++}
++
++const ASN1_GENERALIZEDTIME *TS_TST_INFO_get_time(const TS_TST_INFO *a)
++{
++    return a->time;
++}
++
++int TS_TST_INFO_set_accuracy(TS_TST_INFO *a, TS_ACCURACY *accuracy)
++{
++    TS_ACCURACY *new_accuracy;
++
++    if (a->accuracy == accuracy)
++        return 1;
++    new_accuracy = TS_ACCURACY_dup(accuracy);
++    if (new_accuracy == NULL) {
++        TSerr(TS_F_TS_TST_INFO_SET_ACCURACY, ERR_R_MALLOC_FAILURE);
++        return 0;
++    }
++    TS_ACCURACY_free(a->accuracy);
++    a->accuracy = new_accuracy;
++    return 1;
++}
++
++TS_ACCURACY *TS_TST_INFO_get_accuracy(TS_TST_INFO *a)
++{
++    return a->accuracy;
++}
++
++int TS_ACCURACY_set_seconds(TS_ACCURACY *a, const ASN1_INTEGER *seconds)
++{
++    ASN1_INTEGER *new_seconds;
++
++    if (a->seconds == seconds)
++        return 1;
++    new_seconds = ASN1_INTEGER_dup(seconds);
++    if (new_seconds == NULL) {
++        TSerr(TS_F_TS_ACCURACY_SET_SECONDS, ERR_R_MALLOC_FAILURE);
++        return 0;
++    }
++    ASN1_INTEGER_free(a->seconds);
++    a->seconds = new_seconds;
++    return 1;
++}
++
++const ASN1_INTEGER *TS_ACCURACY_get_seconds(const TS_ACCURACY *a)
++{
++    return a->seconds;
++}
++
++int TS_ACCURACY_set_millis(TS_ACCURACY *a, const ASN1_INTEGER *millis)
++{
++    ASN1_INTEGER *new_millis = NULL;
++
++    if (a->millis == millis)
++        return 1;
++    if (millis != NULL) {
++        new_millis = ASN1_INTEGER_dup(millis);
++        if (new_millis == NULL) {
++            TSerr(TS_F_TS_ACCURACY_SET_MILLIS, ERR_R_MALLOC_FAILURE);
++            return 0;
++        }
++    }
++    ASN1_INTEGER_free(a->millis);
++    a->millis = new_millis;
++    return 1;
++}
++
++const ASN1_INTEGER *TS_ACCURACY_get_millis(const TS_ACCURACY *a)
++{
++    return a->millis;
++}
++
++int TS_ACCURACY_set_micros(TS_ACCURACY *a, const ASN1_INTEGER *micros)
++{
++    ASN1_INTEGER *new_micros = NULL;
++
++    if (a->micros == micros)
++        return 1;
++    if (micros != NULL) {
++        new_micros = ASN1_INTEGER_dup(micros);
++        if (new_micros == NULL) {
++            TSerr(TS_F_TS_ACCURACY_SET_MICROS, ERR_R_MALLOC_FAILURE);
++            return 0;
++        }
++    }
++    ASN1_INTEGER_free(a->micros);
++    a->micros = new_micros;
++    return 1;
++}
++
++const ASN1_INTEGER *TS_ACCURACY_get_micros(const TS_ACCURACY *a)
++{
++    return a->micros;
++}
++
++int TS_TST_INFO_set_ordering(TS_TST_INFO *a, int ordering)
++{
++    a->ordering = ordering ? 0xFF : 0x00;
++    return 1;
++}
++
++int TS_TST_INFO_get_ordering(const TS_TST_INFO *a)
++{
++    return a->ordering ? 1 : 0;
++}
++
++int TS_TST_INFO_set_nonce(TS_TST_INFO *a, const ASN1_INTEGER *nonce)
++{
++    ASN1_INTEGER *new_nonce;
++
++    if (a->nonce == nonce)
++        return 1;
++    new_nonce = ASN1_INTEGER_dup(nonce);
++    if (new_nonce == NULL) {
++        TSerr(TS_F_TS_TST_INFO_SET_NONCE, ERR_R_MALLOC_FAILURE);
++        return 0;
++    }
++    ASN1_INTEGER_free(a->nonce);
++    a->nonce = new_nonce;
++    return 1;
++}
++
++const ASN1_INTEGER *TS_TST_INFO_get_nonce(const TS_TST_INFO *a)
++{
++    return a->nonce;
++}
++
++int TS_TST_INFO_set_tsa(TS_TST_INFO *a, GENERAL_NAME *tsa)
++{
++    GENERAL_NAME *new_tsa;
++
++    if (a->tsa == tsa)
++        return 1;
++    new_tsa = GENERAL_NAME_dup(tsa);
++    if (new_tsa == NULL) {
++        TSerr(TS_F_TS_TST_INFO_SET_TSA, ERR_R_MALLOC_FAILURE);
++        return 0;
++    }
++    GENERAL_NAME_free(a->tsa);
++    a->tsa = new_tsa;
++    return 1;
++}
++
++GENERAL_NAME *TS_TST_INFO_get_tsa(TS_TST_INFO *a)
++{
++    return a->tsa;
++}
++
++STACK_OF(X509_EXTENSION) *TS_TST_INFO_get_exts(TS_TST_INFO *a)
++{
++    return a->extensions;
++}
++
++void TS_TST_INFO_ext_free(TS_TST_INFO *a)
++{
++    if (!a)
++        return;
++    sk_X509_EXTENSION_pop_free(a->extensions, X509_EXTENSION_free);
++    a->extensions = NULL;
++}
++
++int TS_TST_INFO_get_ext_count(TS_TST_INFO *a)
++{
++    return X509v3_get_ext_count(a->extensions);
++}
++
++int TS_TST_INFO_get_ext_by_NID(TS_TST_INFO *a, int nid, int lastpos)
++{
++    return X509v3_get_ext_by_NID(a->extensions, nid, lastpos);
++}
++
++int TS_TST_INFO_get_ext_by_OBJ(TS_TST_INFO *a, const ASN1_OBJECT *obj, int lastpos)
++{
++    return X509v3_get_ext_by_OBJ(a->extensions, obj, lastpos);
++}
++
++int TS_TST_INFO_get_ext_by_critical(TS_TST_INFO *a, int crit, int lastpos)
++{
++    return X509v3_get_ext_by_critical(a->extensions, crit, lastpos);
++}
++
++X509_EXTENSION *TS_TST_INFO_get_ext(TS_TST_INFO *a, int loc)
++{
++    return X509v3_get_ext(a->extensions, loc);
++}
++
++X509_EXTENSION *TS_TST_INFO_delete_ext(TS_TST_INFO *a, int loc)
++{
++    return X509v3_delete_ext(a->extensions, loc);
++}
++
++int TS_TST_INFO_add_ext(TS_TST_INFO *a, X509_EXTENSION *ex, int loc)
++{
++    return X509v3_add_ext(&a->extensions, ex, loc) != NULL;
++}
++
++void *TS_TST_INFO_get_ext_d2i(TS_TST_INFO *a, int nid, int *crit, int *idx)
++{
++    return X509V3_get_d2i(a->extensions, nid, crit, idx);
++}
++
++int TS_STATUS_INFO_set_status(TS_STATUS_INFO *a, int i)
++{
++    return ASN1_INTEGER_set(a->status, i);
++}
++
++const ASN1_INTEGER *TS_STATUS_INFO_get0_status(const TS_STATUS_INFO *a)
++{
++    return a->status;
++}
++
++const STACK_OF(ASN1_UTF8STRING) *
++TS_STATUS_INFO_get0_text(const TS_STATUS_INFO *a)
++{
++    return a->text;
++}
++
++const ASN1_BIT_STRING *TS_STATUS_INFO_get0_failure_info(const TS_STATUS_INFO *a)
++{
++    return a->failure_info;
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/ts/ts_rsp_verify.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/ts/ts_rsp_verify.c
+new file mode 100644
+index 0000000..2755dd0
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/ts/ts_rsp_verify.c
+@@ -0,0 +1,635 @@
++/*
++ * Copyright 2006-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include "internal/cryptlib.h"
++#include 
++#include 
++#include 
++#include "ts_lcl.h"
++
++static int ts_verify_cert(X509_STORE *store, STACK_OF(X509) *untrusted,
++                          X509 *signer, STACK_OF(X509) **chain);
++static int ts_check_signing_certs(PKCS7_SIGNER_INFO *si,
++                                  STACK_OF(X509) *chain);
++static ESS_SIGNING_CERT *ess_get_signing_cert(PKCS7_SIGNER_INFO *si);
++static int ts_find_cert(STACK_OF(ESS_CERT_ID) *cert_ids, X509 *cert);
++static int ts_issuer_serial_cmp(ESS_ISSUER_SERIAL *is, X509 *cert);
++static int int_ts_RESP_verify_token(TS_VERIFY_CTX *ctx,
++                                    PKCS7 *token, TS_TST_INFO *tst_info);
++static int ts_check_status_info(TS_RESP *response);
++static char *ts_get_status_text(STACK_OF(ASN1_UTF8STRING) *text);
++static int ts_check_policy(const ASN1_OBJECT *req_oid,
++                           const TS_TST_INFO *tst_info);
++static int ts_compute_imprint(BIO *data, TS_TST_INFO *tst_info,
++                              X509_ALGOR **md_alg,
++                              unsigned char **imprint, unsigned *imprint_len);
++static int ts_check_imprints(X509_ALGOR *algor_a,
++                             const unsigned char *imprint_a, unsigned len_a,
++                             TS_TST_INFO *tst_info);
++static int ts_check_nonces(const ASN1_INTEGER *a, TS_TST_INFO *tst_info);
++static int ts_check_signer_name(GENERAL_NAME *tsa_name, X509 *signer);
++static int ts_find_name(STACK_OF(GENERAL_NAME) *gen_names,
++                        GENERAL_NAME *name);
++
++/*
++ * This must be large enough to hold all values in ts_status_text (with
++ * comma separator) or all text fields in ts_failure_info (also with comma).
++ */
++#define TS_STATUS_BUF_SIZE      256
++
++/*
++ * Local mapping between response codes and descriptions.
++ */
++static const char *ts_status_text[] = {
++    "granted",
++    "grantedWithMods",
++    "rejection",
++    "waiting",
++    "revocationWarning",
++    "revocationNotification"
++};
++
++#define TS_STATUS_TEXT_SIZE     OSSL_NELEM(ts_status_text)
++
++static struct {
++    int code;
++    const char *text;
++} ts_failure_info[] = {
++    {TS_INFO_BAD_ALG, "badAlg"},
++    {TS_INFO_BAD_REQUEST, "badRequest"},
++    {TS_INFO_BAD_DATA_FORMAT, "badDataFormat"},
++    {TS_INFO_TIME_NOT_AVAILABLE, "timeNotAvailable"},
++    {TS_INFO_UNACCEPTED_POLICY, "unacceptedPolicy"},
++    {TS_INFO_UNACCEPTED_EXTENSION, "unacceptedExtension"},
++    {TS_INFO_ADD_INFO_NOT_AVAILABLE, "addInfoNotAvailable"},
++    {TS_INFO_SYSTEM_FAILURE, "systemFailure"}
++};
++
++
++/*-
++ * This function carries out the following tasks:
++ *      - Checks if there is one and only one signer.
++ *      - Search for the signing certificate in 'certs' and in the response.
++ *      - Check the extended key usage and key usage fields of the signer
++ *      certificate (done by the path validation).
++ *      - Build and validate the certificate path.
++ *      - Check if the certificate path meets the requirements of the
++ *      SigningCertificate ESS signed attribute.
++ *      - Verify the signature value.
++ *      - Returns the signer certificate in 'signer', if 'signer' is not NULL.
++ */
++int TS_RESP_verify_signature(PKCS7 *token, STACK_OF(X509) *certs,
++                             X509_STORE *store, X509 **signer_out)
++{
++    STACK_OF(PKCS7_SIGNER_INFO) *sinfos = NULL;
++    PKCS7_SIGNER_INFO *si;
++    STACK_OF(X509) *signers = NULL;
++    X509 *signer;
++    STACK_OF(X509) *chain = NULL;
++    char buf[4096];
++    int i, j = 0, ret = 0;
++    BIO *p7bio = NULL;
++
++    /* Some sanity checks first. */
++    if (!token) {
++        TSerr(TS_F_TS_RESP_VERIFY_SIGNATURE, TS_R_INVALID_NULL_POINTER);
++        goto err;
++    }
++    if (!PKCS7_type_is_signed(token)) {
++        TSerr(TS_F_TS_RESP_VERIFY_SIGNATURE, TS_R_WRONG_CONTENT_TYPE);
++        goto err;
++    }
++    sinfos = PKCS7_get_signer_info(token);
++    if (!sinfos || sk_PKCS7_SIGNER_INFO_num(sinfos) != 1) {
++        TSerr(TS_F_TS_RESP_VERIFY_SIGNATURE, TS_R_THERE_MUST_BE_ONE_SIGNER);
++        goto err;
++    }
++    si = sk_PKCS7_SIGNER_INFO_value(sinfos, 0);
++    if (PKCS7_get_detached(token)) {
++        TSerr(TS_F_TS_RESP_VERIFY_SIGNATURE, TS_R_NO_CONTENT);
++        goto err;
++    }
++
++    /*
++     * Get hold of the signer certificate, search only internal certificates
++     * if it was requested.
++     */
++    signers = PKCS7_get0_signers(token, certs, 0);
++    if (!signers || sk_X509_num(signers) != 1)
++        goto err;
++    signer = sk_X509_value(signers, 0);
++
++    if (!ts_verify_cert(store, certs, signer, &chain))
++        goto err;
++    if (!ts_check_signing_certs(si, chain))
++        goto err;
++    p7bio = PKCS7_dataInit(token, NULL);
++
++    /* We now have to 'read' from p7bio to calculate digests etc. */
++    while ((i = BIO_read(p7bio, buf, sizeof(buf))) > 0)
++        continue;
++
++    j = PKCS7_signatureVerify(p7bio, token, si, signer);
++    if (j <= 0) {
++        TSerr(TS_F_TS_RESP_VERIFY_SIGNATURE, TS_R_SIGNATURE_FAILURE);
++        goto err;
++    }
++
++    if (signer_out) {
++        *signer_out = signer;
++        X509_up_ref(signer);
++    }
++    ret = 1;
++
++ err:
++    BIO_free_all(p7bio);
++    sk_X509_pop_free(chain, X509_free);
++    sk_X509_free(signers);
++
++    return ret;
++}
++
++/*
++ * The certificate chain is returned in chain. Caller is responsible for
++ * freeing the vector.
++ */
++static int ts_verify_cert(X509_STORE *store, STACK_OF(X509) *untrusted,
++                          X509 *signer, STACK_OF(X509) **chain)
++{
++    X509_STORE_CTX *cert_ctx = NULL;
++    int i;
++    int ret = 0;
++
++    *chain = NULL;
++    cert_ctx = X509_STORE_CTX_new();
++    if (cert_ctx == NULL) {
++        TSerr(TS_F_TS_VERIFY_CERT, ERR_R_MALLOC_FAILURE);
++        goto err;
++    }
++    if (!X509_STORE_CTX_init(cert_ctx, store, signer, untrusted))
++        goto end;
++    X509_STORE_CTX_set_purpose(cert_ctx, X509_PURPOSE_TIMESTAMP_SIGN);
++    i = X509_verify_cert(cert_ctx);
++    if (i <= 0) {
++        int j = X509_STORE_CTX_get_error(cert_ctx);
++        TSerr(TS_F_TS_VERIFY_CERT, TS_R_CERTIFICATE_VERIFY_ERROR);
++        ERR_add_error_data(2, "Verify error:",
++                           X509_verify_cert_error_string(j));
++        goto err;
++    }
++    *chain = X509_STORE_CTX_get1_chain(cert_ctx);
++    ret = 1;
++    goto end;
++
++err:
++    ret = 0;
++
++end:
++    X509_STORE_CTX_free(cert_ctx);
++    return ret;
++}
++
++static int ts_check_signing_certs(PKCS7_SIGNER_INFO *si,
++                                  STACK_OF(X509) *chain)
++{
++    ESS_SIGNING_CERT *ss = ess_get_signing_cert(si);
++    STACK_OF(ESS_CERT_ID) *cert_ids = NULL;
++    X509 *cert;
++    int i = 0;
++    int ret = 0;
++
++    if (!ss)
++        goto err;
++    cert_ids = ss->cert_ids;
++    cert = sk_X509_value(chain, 0);
++    if (ts_find_cert(cert_ids, cert) != 0)
++        goto err;
++
++    /*
++     * Check the other certificates of the chain if there are more than one
++     * certificate ids in cert_ids.
++     */
++    if (sk_ESS_CERT_ID_num(cert_ids) > 1) {
++        for (i = 1; i < sk_X509_num(chain); ++i) {
++            cert = sk_X509_value(chain, i);
++            if (ts_find_cert(cert_ids, cert) < 0)
++                goto err;
++        }
++    }
++    ret = 1;
++ err:
++    if (!ret)
++        TSerr(TS_F_TS_CHECK_SIGNING_CERTS,
++              TS_R_ESS_SIGNING_CERTIFICATE_ERROR);
++    ESS_SIGNING_CERT_free(ss);
++    return ret;
++}
++
++static ESS_SIGNING_CERT *ess_get_signing_cert(PKCS7_SIGNER_INFO *si)
++{
++    ASN1_TYPE *attr;
++    const unsigned char *p;
++    attr = PKCS7_get_signed_attribute(si, NID_id_smime_aa_signingCertificate);
++    if (!attr)
++        return NULL;
++    p = attr->value.sequence->data;
++    return d2i_ESS_SIGNING_CERT(NULL, &p, attr->value.sequence->length);
++}
++
++/* Returns < 0 if certificate is not found, certificate index otherwise. */
++static int ts_find_cert(STACK_OF(ESS_CERT_ID) *cert_ids, X509 *cert)
++{
++    int i;
++    unsigned char cert_sha1[SHA_DIGEST_LENGTH];
++
++    if (!cert_ids || !cert)
++        return -1;
++
++    X509_digest(cert, EVP_sha1(), cert_sha1, NULL);
++
++    /* Recompute SHA1 hash of certificate if necessary (side effect). */
++    X509_check_purpose(cert, -1, 0);
++
++    /* Look for cert in the cert_ids vector. */
++    for (i = 0; i < sk_ESS_CERT_ID_num(cert_ids); ++i) {
++        ESS_CERT_ID *cid = sk_ESS_CERT_ID_value(cert_ids, i);
++
++        if (cid->hash->length == SHA_DIGEST_LENGTH
++            && memcmp(cid->hash->data, cert_sha1, SHA_DIGEST_LENGTH) == 0) {
++            ESS_ISSUER_SERIAL *is = cid->issuer_serial;
++            if (!is || !ts_issuer_serial_cmp(is, cert))
++                return i;
++        }
++    }
++
++    return -1;
++}
++
++static int ts_issuer_serial_cmp(ESS_ISSUER_SERIAL *is, X509 *cert)
++{
++    GENERAL_NAME *issuer;
++
++    if (!is || !cert || sk_GENERAL_NAME_num(is->issuer) != 1)
++        return -1;
++
++    issuer = sk_GENERAL_NAME_value(is->issuer, 0);
++    if (issuer->type != GEN_DIRNAME
++        || X509_NAME_cmp(issuer->d.dirn, X509_get_issuer_name(cert)))
++        return -1;
++
++    if (ASN1_INTEGER_cmp(is->serial, X509_get_serialNumber(cert)))
++        return -1;
++
++    return 0;
++}
++
++/*-
++ * Verifies whether 'response' contains a valid response with regards
++ * to the settings of the context:
++ *      - Gives an error message if the TS_TST_INFO is not present.
++ *      - Calls _TS_RESP_verify_token to verify the token content.
++ */
++int TS_RESP_verify_response(TS_VERIFY_CTX *ctx, TS_RESP *response)
++{
++    PKCS7 *token = response->token;
++    TS_TST_INFO *tst_info = response->tst_info;
++    int ret = 0;
++
++    if (!ts_check_status_info(response))
++        goto err;
++    if (!int_ts_RESP_verify_token(ctx, token, tst_info))
++        goto err;
++    ret = 1;
++
++ err:
++    return ret;
++}
++
++/*
++ * Tries to extract a TS_TST_INFO structure from the PKCS7 token and
++ * calls the internal int_TS_RESP_verify_token function for verifying it.
++ */
++int TS_RESP_verify_token(TS_VERIFY_CTX *ctx, PKCS7 *token)
++{
++    TS_TST_INFO *tst_info = PKCS7_to_TS_TST_INFO(token);
++    int ret = 0;
++    if (tst_info) {
++        ret = int_ts_RESP_verify_token(ctx, token, tst_info);
++        TS_TST_INFO_free(tst_info);
++    }
++    return ret;
++}
++
++/*-
++ * Verifies whether the 'token' contains a valid time stamp token
++ * with regards to the settings of the context. Only those checks are
++ * carried out that are specified in the context:
++ *      - Verifies the signature of the TS_TST_INFO.
++ *      - Checks the version number of the response.
++ *      - Check if the requested and returned policies math.
++ *      - Check if the message imprints are the same.
++ *      - Check if the nonces are the same.
++ *      - Check if the TSA name matches the signer.
++ *      - Check if the TSA name is the expected TSA.
++ */
++static int int_ts_RESP_verify_token(TS_VERIFY_CTX *ctx,
++                                    PKCS7 *token, TS_TST_INFO *tst_info)
++{
++    X509 *signer = NULL;
++    GENERAL_NAME *tsa_name = tst_info->tsa;
++    X509_ALGOR *md_alg = NULL;
++    unsigned char *imprint = NULL;
++    unsigned imprint_len = 0;
++    int ret = 0;
++    int flags = ctx->flags;
++
++    /* Some options require us to also check the signature */
++    if (((flags & TS_VFY_SIGNER) && tsa_name != NULL)
++            || (flags & TS_VFY_TSA_NAME)) {
++        flags |= TS_VFY_SIGNATURE;
++    }
++
++    if ((flags & TS_VFY_SIGNATURE)
++        && !TS_RESP_verify_signature(token, ctx->certs, ctx->store, &signer))
++        goto err;
++    if ((flags & TS_VFY_VERSION)
++        && TS_TST_INFO_get_version(tst_info) != 1) {
++        TSerr(TS_F_INT_TS_RESP_VERIFY_TOKEN, TS_R_UNSUPPORTED_VERSION);
++        goto err;
++    }
++    if ((flags & TS_VFY_POLICY)
++        && !ts_check_policy(ctx->policy, tst_info))
++        goto err;
++    if ((flags & TS_VFY_IMPRINT)
++        && !ts_check_imprints(ctx->md_alg, ctx->imprint, ctx->imprint_len,
++                              tst_info))
++        goto err;
++    if ((flags & TS_VFY_DATA)
++        && (!ts_compute_imprint(ctx->data, tst_info,
++                                &md_alg, &imprint, &imprint_len)
++            || !ts_check_imprints(md_alg, imprint, imprint_len, tst_info)))
++        goto err;
++    if ((flags & TS_VFY_NONCE)
++        && !ts_check_nonces(ctx->nonce, tst_info))
++        goto err;
++    if ((flags & TS_VFY_SIGNER)
++        && tsa_name && !ts_check_signer_name(tsa_name, signer)) {
++        TSerr(TS_F_INT_TS_RESP_VERIFY_TOKEN, TS_R_TSA_NAME_MISMATCH);
++        goto err;
++    }
++    if ((flags & TS_VFY_TSA_NAME)
++        && !ts_check_signer_name(ctx->tsa_name, signer)) {
++        TSerr(TS_F_INT_TS_RESP_VERIFY_TOKEN, TS_R_TSA_UNTRUSTED);
++        goto err;
++    }
++    ret = 1;
++
++ err:
++    X509_free(signer);
++    X509_ALGOR_free(md_alg);
++    OPENSSL_free(imprint);
++    return ret;
++}
++
++static int ts_check_status_info(TS_RESP *response)
++{
++    TS_STATUS_INFO *info = response->status_info;
++    long status = ASN1_INTEGER_get(info->status);
++    const char *status_text = NULL;
++    char *embedded_status_text = NULL;
++    char failure_text[TS_STATUS_BUF_SIZE] = "";
++
++    if (status == 0 || status == 1)
++        return 1;
++
++    /* There was an error, get the description in status_text. */
++    if (0 <= status && status < (long) OSSL_NELEM(ts_status_text))
++        status_text = ts_status_text[status];
++    else
++        status_text = "unknown code";
++
++    if (sk_ASN1_UTF8STRING_num(info->text) > 0
++        && (embedded_status_text = ts_get_status_text(info->text)) == NULL)
++        return 0;
++
++    /* Fill in failure_text with the failure information. */
++    if (info->failure_info) {
++        int i;
++        int first = 1;
++        for (i = 0; i < (int)OSSL_NELEM(ts_failure_info); ++i) {
++            if (ASN1_BIT_STRING_get_bit(info->failure_info,
++                                        ts_failure_info[i].code)) {
++                if (!first)
++                    strcat(failure_text, ",");
++                else
++                    first = 0;
++                strcat(failure_text, ts_failure_info[i].text);
++            }
++        }
++    }
++    if (failure_text[0] == '\0')
++        strcpy(failure_text, "unspecified");
++
++    TSerr(TS_F_TS_CHECK_STATUS_INFO, TS_R_NO_TIME_STAMP_TOKEN);
++    ERR_add_error_data(6,
++                       "status code: ", status_text,
++                       ", status text: ", embedded_status_text ?
++                       embedded_status_text : "unspecified",
++                       ", failure codes: ", failure_text);
++    OPENSSL_free(embedded_status_text);
++
++    return 0;
++}
++
++static char *ts_get_status_text(STACK_OF(ASN1_UTF8STRING) *text)
++{
++    int i;
++    int length = 0;
++    char *result = NULL;
++    char *p;
++
++    for (i = 0; i < sk_ASN1_UTF8STRING_num(text); ++i) {
++        ASN1_UTF8STRING *current = sk_ASN1_UTF8STRING_value(text, i);
++        if (ASN1_STRING_length(current) > TS_MAX_STATUS_LENGTH - length - 1)
++            return NULL;
++        length += ASN1_STRING_length(current);
++        length += 1;            /* separator character */
++    }
++    if ((result = OPENSSL_malloc(length)) == NULL) {
++        TSerr(TS_F_TS_GET_STATUS_TEXT, ERR_R_MALLOC_FAILURE);
++        return NULL;
++    }
++
++    for (i = 0, p = result; i < sk_ASN1_UTF8STRING_num(text); ++i) {
++        ASN1_UTF8STRING *current = sk_ASN1_UTF8STRING_value(text, i);
++        length = ASN1_STRING_length(current);
++        if (i > 0)
++            *p++ = '/';
++        strncpy(p, (const char *)ASN1_STRING_get0_data(current), length);
++        p += length;
++    }
++    *p = '\0';
++
++    return result;
++}
++
++static int ts_check_policy(const ASN1_OBJECT *req_oid, 
++                           const TS_TST_INFO *tst_info)
++{
++    const ASN1_OBJECT *resp_oid = tst_info->policy_id;
++
++    if (OBJ_cmp(req_oid, resp_oid) != 0) {
++        TSerr(TS_F_TS_CHECK_POLICY, TS_R_POLICY_MISMATCH);
++        return 0;
++    }
++
++    return 1;
++}
++
++static int ts_compute_imprint(BIO *data, TS_TST_INFO *tst_info,
++                              X509_ALGOR **md_alg,
++                              unsigned char **imprint, unsigned *imprint_len)
++{
++    TS_MSG_IMPRINT *msg_imprint = tst_info->msg_imprint;
++    X509_ALGOR *md_alg_resp = msg_imprint->hash_algo;
++    const EVP_MD *md;
++    EVP_MD_CTX *md_ctx = NULL;
++    unsigned char buffer[4096];
++    int length;
++
++    *md_alg = NULL;
++    *imprint = NULL;
++
++    if ((*md_alg = X509_ALGOR_dup(md_alg_resp)) == NULL)
++        goto err;
++    if ((md = EVP_get_digestbyobj((*md_alg)->algorithm)) == NULL) {
++        TSerr(TS_F_TS_COMPUTE_IMPRINT, TS_R_UNSUPPORTED_MD_ALGORITHM);
++        goto err;
++    }
++    length = EVP_MD_size(md);
++    if (length < 0)
++        goto err;
++    *imprint_len = length;
++    if ((*imprint = OPENSSL_malloc(*imprint_len)) == NULL) {
++        TSerr(TS_F_TS_COMPUTE_IMPRINT, ERR_R_MALLOC_FAILURE);
++        goto err;
++    }
++
++    md_ctx = EVP_MD_CTX_new();
++    if (md_ctx == NULL) {
++        TSerr(TS_F_TS_COMPUTE_IMPRINT, ERR_R_MALLOC_FAILURE);
++        goto err;
++    }
++    if (!EVP_DigestInit(md_ctx, md))
++        goto err;
++    while ((length = BIO_read(data, buffer, sizeof(buffer))) > 0) {
++        if (!EVP_DigestUpdate(md_ctx, buffer, length))
++            goto err;
++    }
++    if (!EVP_DigestFinal(md_ctx, *imprint, NULL))
++        goto err;
++    EVP_MD_CTX_free(md_ctx);
++
++    return 1;
++ err:
++    EVP_MD_CTX_free(md_ctx);
++    X509_ALGOR_free(*md_alg);
++    OPENSSL_free(*imprint);
++    *imprint_len = 0;
++    *imprint = 0;
++    return 0;
++}
++
++static int ts_check_imprints(X509_ALGOR *algor_a,
++                             const unsigned char *imprint_a, unsigned len_a,
++                             TS_TST_INFO *tst_info)
++{
++    TS_MSG_IMPRINT *b = tst_info->msg_imprint;
++    X509_ALGOR *algor_b = b->hash_algo;
++    int ret = 0;
++
++    if (algor_a) {
++        if (OBJ_cmp(algor_a->algorithm, algor_b->algorithm))
++            goto err;
++
++        /* The parameter must be NULL in both. */
++        if ((algor_a->parameter
++             && ASN1_TYPE_get(algor_a->parameter) != V_ASN1_NULL)
++            || (algor_b->parameter
++                && ASN1_TYPE_get(algor_b->parameter) != V_ASN1_NULL))
++            goto err;
++    }
++
++    ret = len_a == (unsigned)ASN1_STRING_length(b->hashed_msg) &&
++        memcmp(imprint_a, ASN1_STRING_get0_data(b->hashed_msg), len_a) == 0;
++ err:
++    if (!ret)
++        TSerr(TS_F_TS_CHECK_IMPRINTS, TS_R_MESSAGE_IMPRINT_MISMATCH);
++    return ret;
++}
++
++static int ts_check_nonces(const ASN1_INTEGER *a, TS_TST_INFO *tst_info)
++{
++    const ASN1_INTEGER *b = tst_info->nonce;
++
++    if (!b) {
++        TSerr(TS_F_TS_CHECK_NONCES, TS_R_NONCE_NOT_RETURNED);
++        return 0;
++    }
++
++    /* No error if a nonce is returned without being requested. */
++    if (ASN1_INTEGER_cmp(a, b) != 0) {
++        TSerr(TS_F_TS_CHECK_NONCES, TS_R_NONCE_MISMATCH);
++        return 0;
++    }
++
++    return 1;
++}
++
++/*
++ * Check if the specified TSA name matches either the subject or one of the
++ * subject alternative names of the TSA certificate.
++ */
++static int ts_check_signer_name(GENERAL_NAME *tsa_name, X509 *signer)
++{
++    STACK_OF(GENERAL_NAME) *gen_names = NULL;
++    int idx = -1;
++    int found = 0;
++
++    if (tsa_name->type == GEN_DIRNAME
++        && X509_name_cmp(tsa_name->d.dirn, X509_get_subject_name(signer)) == 0)
++        return 1;
++    gen_names = X509_get_ext_d2i(signer, NID_subject_alt_name, NULL, &idx);
++    while (gen_names != NULL) {
++        found = ts_find_name(gen_names, tsa_name) >= 0;
++        if (found)
++            break;
++        /*
++         * Get the next subject alternative name, although there should be no
++         * more than one.
++         */
++        GENERAL_NAMES_free(gen_names);
++        gen_names = X509_get_ext_d2i(signer, NID_subject_alt_name, NULL, &idx);
++    }
++    GENERAL_NAMES_free(gen_names);
++
++    return found;
++}
++
++/* Returns 1 if name is in gen_names, 0 otherwise. */
++static int ts_find_name(STACK_OF(GENERAL_NAME) *gen_names, GENERAL_NAME *name)
++{
++    int i, found;
++    for (i = 0, found = 0; !found && i < sk_GENERAL_NAME_num(gen_names); ++i) {
++        GENERAL_NAME *current = sk_GENERAL_NAME_value(gen_names, i);
++        found = GENERAL_NAME_cmp(current, name) == 0;
++    }
++    return found ? i - 1 : -1;
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/ts/ts_verify_ctx.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/ts/ts_verify_ctx.c
+new file mode 100644
+index 0000000..d4792ee
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/ts/ts_verify_ctx.c
+@@ -0,0 +1,146 @@
++/*
++ * Copyright 2006-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include "internal/cryptlib.h"
++#include 
++#include 
++#include "ts_lcl.h"
++
++TS_VERIFY_CTX *TS_VERIFY_CTX_new(void)
++{
++    TS_VERIFY_CTX *ctx = OPENSSL_zalloc(sizeof(*ctx));
++
++    if (ctx == NULL)
++        TSerr(TS_F_TS_VERIFY_CTX_NEW, ERR_R_MALLOC_FAILURE);
++    return ctx;
++}
++
++void TS_VERIFY_CTX_init(TS_VERIFY_CTX *ctx)
++{
++    OPENSSL_assert(ctx != NULL);
++    memset(ctx, 0, sizeof(*ctx));
++}
++
++void TS_VERIFY_CTX_free(TS_VERIFY_CTX *ctx)
++{
++    if (!ctx)
++        return;
++
++    TS_VERIFY_CTX_cleanup(ctx);
++    OPENSSL_free(ctx);
++}
++
++int TS_VERIFY_CTX_add_flags(TS_VERIFY_CTX *ctx, int f)
++{
++    ctx->flags |= f;
++    return ctx->flags;
++}
++
++int TS_VERIFY_CTX_set_flags(TS_VERIFY_CTX *ctx, int f)
++{
++    ctx->flags = f;
++    return ctx->flags;
++}
++
++BIO *TS_VERIFY_CTX_set_data(TS_VERIFY_CTX *ctx, BIO *b)
++{
++    ctx->data = b;
++    return ctx->data;
++}
++
++X509_STORE *TS_VERIFY_CTX_set_store(TS_VERIFY_CTX *ctx, X509_STORE *s)
++{
++    ctx->store = s;
++    return ctx->store;
++}
++
++STACK_OF(X509) *TS_VERIFY_CTS_set_certs(TS_VERIFY_CTX *ctx,
++                                        STACK_OF(X509) *certs)
++{
++    ctx->certs = certs;
++    return ctx->certs;
++}
++
++unsigned char *TS_VERIFY_CTX_set_imprint(TS_VERIFY_CTX *ctx,
++                                         unsigned char *hexstr, long len)
++{
++    ctx->imprint = hexstr;
++    ctx->imprint_len = len;
++    return ctx->imprint;
++}
++
++void TS_VERIFY_CTX_cleanup(TS_VERIFY_CTX *ctx)
++{
++    if (!ctx)
++        return;
++
++    X509_STORE_free(ctx->store);
++    sk_X509_pop_free(ctx->certs, X509_free);
++
++    ASN1_OBJECT_free(ctx->policy);
++
++    X509_ALGOR_free(ctx->md_alg);
++    OPENSSL_free(ctx->imprint);
++
++    BIO_free_all(ctx->data);
++
++    ASN1_INTEGER_free(ctx->nonce);
++
++    GENERAL_NAME_free(ctx->tsa_name);
++
++    TS_VERIFY_CTX_init(ctx);
++}
++
++TS_VERIFY_CTX *TS_REQ_to_TS_VERIFY_CTX(TS_REQ *req, TS_VERIFY_CTX *ctx)
++{
++    TS_VERIFY_CTX *ret = ctx;
++    ASN1_OBJECT *policy;
++    TS_MSG_IMPRINT *imprint;
++    X509_ALGOR *md_alg;
++    ASN1_OCTET_STRING *msg;
++    const ASN1_INTEGER *nonce;
++
++    OPENSSL_assert(req != NULL);
++    if (ret)
++        TS_VERIFY_CTX_cleanup(ret);
++    else if ((ret = TS_VERIFY_CTX_new()) == NULL)
++        return NULL;
++
++    ret->flags = TS_VFY_ALL_IMPRINT & ~(TS_VFY_TSA_NAME | TS_VFY_SIGNATURE);
++
++    if ((policy = req->policy_id) != NULL) {
++        if ((ret->policy = OBJ_dup(policy)) == NULL)
++            goto err;
++    } else
++        ret->flags &= ~TS_VFY_POLICY;
++
++    imprint = req->msg_imprint;
++    md_alg = imprint->hash_algo;
++    if ((ret->md_alg = X509_ALGOR_dup(md_alg)) == NULL)
++        goto err;
++    msg = imprint->hashed_msg;
++    ret->imprint_len = ASN1_STRING_length(msg);
++    if ((ret->imprint = OPENSSL_malloc(ret->imprint_len)) == NULL)
++        goto err;
++    memcpy(ret->imprint, ASN1_STRING_get0_data(msg), ret->imprint_len);
++
++    if ((nonce = req->nonce) != NULL) {
++        if ((ret->nonce = ASN1_INTEGER_dup(nonce)) == NULL)
++            goto err;
++    } else
++        ret->flags &= ~TS_VFY_NONCE;
++
++    return ret;
++ err:
++    if (ctx)
++        TS_VERIFY_CTX_cleanup(ctx);
++    else
++        TS_VERIFY_CTX_free(ret);
++    return NULL;
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/txt_db/build.info b/CryptoPkg/Library/OpensslLib/openssl/crypto/txt_db/build.info
+new file mode 100644
+index 0000000..4379d5f
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/txt_db/build.info
+@@ -0,0 +1,2 @@
++LIBS=../../libcrypto
++SOURCE[../../libcrypto]=txt_db.c
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/txt_db/txt_db.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/txt_db/txt_db.c
+new file mode 100644
+index 0000000..1432230
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/txt_db/txt_db.c
+@@ -0,0 +1,301 @@
++/*
++ * Copyright 1995-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include 
++#include 
++#include "internal/cryptlib.h"
++#include 
++#include 
++
++#undef BUFSIZE
++#define BUFSIZE 512
++
++TXT_DB *TXT_DB_read(BIO *in, int num)
++{
++    TXT_DB *ret = NULL;
++    int esc = 0;
++    long ln = 0;
++    int i, add, n;
++    int size = BUFSIZE;
++    int offset = 0;
++    char *p, *f;
++    OPENSSL_STRING *pp;
++    BUF_MEM *buf = NULL;
++
++    if ((buf = BUF_MEM_new()) == NULL)
++        goto err;
++    if (!BUF_MEM_grow(buf, size))
++        goto err;
++
++    if ((ret = OPENSSL_malloc(sizeof(*ret))) == NULL)
++        goto err;
++    ret->num_fields = num;
++    ret->index = NULL;
++    ret->qual = NULL;
++    if ((ret->data = sk_OPENSSL_PSTRING_new_null()) == NULL)
++        goto err;
++    if ((ret->index = OPENSSL_malloc(sizeof(*ret->index) * num)) == NULL)
++        goto err;
++    if ((ret->qual = OPENSSL_malloc(sizeof(*(ret->qual)) * num)) == NULL)
++        goto err;
++    for (i = 0; i < num; i++) {
++        ret->index[i] = NULL;
++        ret->qual[i] = NULL;
++    }
++
++    add = (num + 1) * sizeof(char *);
++    buf->data[size - 1] = '\0';
++    offset = 0;
++    for (;;) {
++        if (offset != 0) {
++            size += BUFSIZE;
++            if (!BUF_MEM_grow_clean(buf, size))
++                goto err;
++        }
++        buf->data[offset] = '\0';
++        BIO_gets(in, &(buf->data[offset]), size - offset);
++        ln++;
++        if (buf->data[offset] == '\0')
++            break;
++        if ((offset == 0) && (buf->data[0] == '#'))
++            continue;
++        i = strlen(&(buf->data[offset]));
++        offset += i;
++        if (buf->data[offset - 1] != '\n')
++            continue;
++        else {
++            buf->data[offset - 1] = '\0'; /* blat the '\n' */
++            if ((p = OPENSSL_malloc(add + offset)) == NULL)
++                goto err;
++            offset = 0;
++        }
++        pp = (char **)p;
++        p += add;
++        n = 0;
++        pp[n++] = p;
++        i = 0;
++        f = buf->data;
++
++        esc = 0;
++        for (;;) {
++            if (*f == '\0')
++                break;
++            if (*f == '\t') {
++                if (esc)
++                    p--;
++                else {
++                    *(p++) = '\0';
++                    f++;
++                    if (n >= num)
++                        break;
++                    pp[n++] = p;
++                    continue;
++                }
++            }
++            esc = (*f == '\\');
++            *(p++) = *(f++);
++        }
++        *(p++) = '\0';
++        if ((n != num) || (*f != '\0')) {
++            ret->error = DB_ERROR_WRONG_NUM_FIELDS;
++            goto err;
++        }
++        pp[n] = p;
++        if (!sk_OPENSSL_PSTRING_push(ret->data, pp))
++            goto err;
++    }
++    BUF_MEM_free(buf);
++    return ret;
++ err:
++    BUF_MEM_free(buf);
++    if (ret != NULL) {
++        sk_OPENSSL_PSTRING_free(ret->data);
++        OPENSSL_free(ret->index);
++        OPENSSL_free(ret->qual);
++        OPENSSL_free(ret);
++    }
++    return (NULL);
++}
++
++OPENSSL_STRING *TXT_DB_get_by_index(TXT_DB *db, int idx,
++                                    OPENSSL_STRING *value)
++{
++    OPENSSL_STRING *ret;
++    LHASH_OF(OPENSSL_STRING) *lh;
++
++    if (idx >= db->num_fields) {
++        db->error = DB_ERROR_INDEX_OUT_OF_RANGE;
++        return (NULL);
++    }
++    lh = db->index[idx];
++    if (lh == NULL) {
++        db->error = DB_ERROR_NO_INDEX;
++        return (NULL);
++    }
++    ret = lh_OPENSSL_STRING_retrieve(lh, value);
++    db->error = DB_ERROR_OK;
++    return (ret);
++}
++
++int TXT_DB_create_index(TXT_DB *db, int field, int (*qual) (OPENSSL_STRING *),
++                        OPENSSL_LH_HASHFUNC hash, OPENSSL_LH_COMPFUNC cmp)
++{
++    LHASH_OF(OPENSSL_STRING) *idx;
++    OPENSSL_STRING *r;
++    int i, n;
++
++    if (field >= db->num_fields) {
++        db->error = DB_ERROR_INDEX_OUT_OF_RANGE;
++        return (0);
++    }
++    /* FIXME: we lose type checking at this point */
++    if ((idx = (LHASH_OF(OPENSSL_STRING) *)OPENSSL_LH_new(hash, cmp)) == NULL) {
++        db->error = DB_ERROR_MALLOC;
++        return (0);
++    }
++    n = sk_OPENSSL_PSTRING_num(db->data);
++    for (i = 0; i < n; i++) {
++        r = sk_OPENSSL_PSTRING_value(db->data, i);
++        if ((qual != NULL) && (qual(r) == 0))
++            continue;
++        if ((r = lh_OPENSSL_STRING_insert(idx, r)) != NULL) {
++            db->error = DB_ERROR_INDEX_CLASH;
++            db->arg1 = sk_OPENSSL_PSTRING_find(db->data, r);
++            db->arg2 = i;
++            lh_OPENSSL_STRING_free(idx);
++            return (0);
++        }
++    }
++    lh_OPENSSL_STRING_free(db->index[field]);
++    db->index[field] = idx;
++    db->qual[field] = qual;
++    return (1);
++}
++
++long TXT_DB_write(BIO *out, TXT_DB *db)
++{
++    long i, j, n, nn, l, tot = 0;
++    char *p, **pp, *f;
++    BUF_MEM *buf = NULL;
++    long ret = -1;
++
++    if ((buf = BUF_MEM_new()) == NULL)
++        goto err;
++    n = sk_OPENSSL_PSTRING_num(db->data);
++    nn = db->num_fields;
++    for (i = 0; i < n; i++) {
++        pp = sk_OPENSSL_PSTRING_value(db->data, i);
++
++        l = 0;
++        for (j = 0; j < nn; j++) {
++            if (pp[j] != NULL)
++                l += strlen(pp[j]);
++        }
++        if (!BUF_MEM_grow_clean(buf, (int)(l * 2 + nn)))
++            goto err;
++
++        p = buf->data;
++        for (j = 0; j < nn; j++) {
++            f = pp[j];
++            if (f != NULL)
++                for (;;) {
++                    if (*f == '\0')
++                        break;
++                    if (*f == '\t')
++                        *(p++) = '\\';
++                    *(p++) = *(f++);
++                }
++            *(p++) = '\t';
++        }
++        p[-1] = '\n';
++        j = p - buf->data;
++        if (BIO_write(out, buf->data, (int)j) != j)
++            goto err;
++        tot += j;
++    }
++    ret = tot;
++ err:
++    BUF_MEM_free(buf);
++    return (ret);
++}
++
++int TXT_DB_insert(TXT_DB *db, OPENSSL_STRING *row)
++{
++    int i;
++    OPENSSL_STRING *r;
++
++    for (i = 0; i < db->num_fields; i++) {
++        if (db->index[i] != NULL) {
++            if ((db->qual[i] != NULL) && (db->qual[i] (row) == 0))
++                continue;
++            r = lh_OPENSSL_STRING_retrieve(db->index[i], row);
++            if (r != NULL) {
++                db->error = DB_ERROR_INDEX_CLASH;
++                db->arg1 = i;
++                db->arg_row = r;
++                goto err;
++            }
++        }
++    }
++    /* We have passed the index checks, now just append and insert */
++    if (!sk_OPENSSL_PSTRING_push(db->data, row)) {
++        db->error = DB_ERROR_MALLOC;
++        goto err;
++    }
++
++    for (i = 0; i < db->num_fields; i++) {
++        if (db->index[i] != NULL) {
++            if ((db->qual[i] != NULL) && (db->qual[i] (row) == 0))
++                continue;
++            (void)lh_OPENSSL_STRING_insert(db->index[i], row);
++        }
++    }
++    return (1);
++ err:
++    return (0);
++}
++
++void TXT_DB_free(TXT_DB *db)
++{
++    int i, n;
++    char **p, *max;
++
++    if (db == NULL)
++        return;
++
++    if (db->index != NULL) {
++        for (i = db->num_fields - 1; i >= 0; i--)
++            lh_OPENSSL_STRING_free(db->index[i]);
++        OPENSSL_free(db->index);
++    }
++    OPENSSL_free(db->qual);
++    if (db->data != NULL) {
++        for (i = sk_OPENSSL_PSTRING_num(db->data) - 1; i >= 0; i--) {
++            /*
++             * check if any 'fields' have been allocated from outside of the
++             * initial block
++             */
++            p = sk_OPENSSL_PSTRING_value(db->data, i);
++            max = p[db->num_fields]; /* last address */
++            if (max == NULL) {  /* new row */
++                for (n = 0; n < db->num_fields; n++)
++                    OPENSSL_free(p[n]);
++            } else {
++                for (n = 0; n < db->num_fields; n++) {
++                    if (((p[n] < (char *)p) || (p[n] > max)))
++                        OPENSSL_free(p[n]);
++                }
++            }
++            OPENSSL_free(sk_OPENSSL_PSTRING_value(db->data, i));
++        }
++        sk_OPENSSL_PSTRING_free(db->data);
++    }
++    OPENSSL_free(db);
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/ui/build.info b/CryptoPkg/Library/OpensslLib/openssl/crypto/ui/build.info
+new file mode 100644
+index 0000000..fcb45af
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/ui/build.info
+@@ -0,0 +1,3 @@
++LIBS=../../libcrypto
++SOURCE[../../libcrypto]=\
++        ui_err.c ui_lib.c ui_openssl.c ui_util.c
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/ui/ui_err.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/ui/ui_err.c
+new file mode 100644
+index 0000000..c8640fe
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/ui/ui_err.c
+@@ -0,0 +1,72 @@
++/*
++ * Generated by util/mkerr.pl DO NOT EDIT
++ * Copyright 1995-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include 
++#include 
++
++/* BEGIN ERROR CODES */
++#ifndef OPENSSL_NO_ERR
++
++# define ERR_FUNC(func) ERR_PACK(ERR_LIB_UI,func,0)
++# define ERR_REASON(reason) ERR_PACK(ERR_LIB_UI,0,reason)
++
++static ERR_STRING_DATA UI_str_functs[] = {
++    {ERR_FUNC(UI_F_CLOSE_CONSOLE), "close_console"},
++    {ERR_FUNC(UI_F_ECHO_CONSOLE), "echo_console"},
++    {ERR_FUNC(UI_F_GENERAL_ALLOCATE_BOOLEAN), "general_allocate_boolean"},
++    {ERR_FUNC(UI_F_GENERAL_ALLOCATE_PROMPT), "general_allocate_prompt"},
++    {ERR_FUNC(UI_F_NOECHO_CONSOLE), "noecho_console"},
++    {ERR_FUNC(UI_F_OPEN_CONSOLE), "open_console"},
++    {ERR_FUNC(UI_F_UI_CREATE_METHOD), "UI_create_method"},
++    {ERR_FUNC(UI_F_UI_CTRL), "UI_ctrl"},
++    {ERR_FUNC(UI_F_UI_DUP_ERROR_STRING), "UI_dup_error_string"},
++    {ERR_FUNC(UI_F_UI_DUP_INFO_STRING), "UI_dup_info_string"},
++    {ERR_FUNC(UI_F_UI_DUP_INPUT_BOOLEAN), "UI_dup_input_boolean"},
++    {ERR_FUNC(UI_F_UI_DUP_INPUT_STRING), "UI_dup_input_string"},
++    {ERR_FUNC(UI_F_UI_DUP_VERIFY_STRING), "UI_dup_verify_string"},
++    {ERR_FUNC(UI_F_UI_GET0_RESULT), "UI_get0_result"},
++    {ERR_FUNC(UI_F_UI_NEW_METHOD), "UI_new_method"},
++    {ERR_FUNC(UI_F_UI_PROCESS), "UI_process"},
++    {ERR_FUNC(UI_F_UI_SET_RESULT), "UI_set_result"},
++    {0, NULL}
++};
++
++static ERR_STRING_DATA UI_str_reasons[] = {
++    {ERR_REASON(UI_R_COMMON_OK_AND_CANCEL_CHARACTERS),
++     "common ok and cancel characters"},
++    {ERR_REASON(UI_R_INDEX_TOO_LARGE), "index too large"},
++    {ERR_REASON(UI_R_INDEX_TOO_SMALL), "index too small"},
++    {ERR_REASON(UI_R_NO_RESULT_BUFFER), "no result buffer"},
++    {ERR_REASON(UI_R_PROCESSING_ERROR), "processing error"},
++    {ERR_REASON(UI_R_RESULT_TOO_LARGE), "result too large"},
++    {ERR_REASON(UI_R_RESULT_TOO_SMALL), "result too small"},
++    {ERR_REASON(UI_R_SYSASSIGN_ERROR), "sys$assign error"},
++    {ERR_REASON(UI_R_SYSDASSGN_ERROR), "sys$dassgn error"},
++    {ERR_REASON(UI_R_SYSQIOW_ERROR), "sys$qiow error"},
++    {ERR_REASON(UI_R_UNKNOWN_CONTROL_COMMAND), "unknown control command"},
++    {ERR_REASON(UI_R_UNKNOWN_TTYGET_ERRNO_VALUE),
++     "unknown ttyget errno value"},
++    {0, NULL}
++};
++
++#endif
++
++int ERR_load_UI_strings(void)
++{
++#ifndef OPENSSL_NO_ERR
++
++    if (ERR_func_error_string(UI_str_functs[0].error) == NULL) {
++        ERR_load_strings(0, UI_str_functs);
++        ERR_load_strings(0, UI_str_reasons);
++    }
++#endif
++    return 1;
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/ui/ui_lib.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/ui/ui_lib.c
+new file mode 100644
+index 0000000..12d62d8
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/ui/ui_lib.c
+@@ -0,0 +1,826 @@
++/*
++ * Copyright 2001-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include "internal/cryptlib.h"
++#include 
++#include 
++#include 
++#include 
++#include "ui_locl.h"
++
++static const UI_METHOD *default_UI_meth = NULL;
++
++UI *UI_new(void)
++{
++    return (UI_new_method(NULL));
++}
++
++UI *UI_new_method(const UI_METHOD *method)
++{
++    UI *ret = OPENSSL_zalloc(sizeof(*ret));
++
++    if (ret == NULL) {
++        UIerr(UI_F_UI_NEW_METHOD, ERR_R_MALLOC_FAILURE);
++        return NULL;
++    }
++
++    ret->lock = CRYPTO_THREAD_lock_new();
++    if (ret->lock == NULL) {
++        UIerr(UI_F_UI_NEW_METHOD, ERR_R_MALLOC_FAILURE);
++        OPENSSL_free(ret);
++        return NULL;
++    }
++
++    if (method == NULL)
++        ret->meth = UI_get_default_method();
++    else
++        ret->meth = method;
++
++    if (!CRYPTO_new_ex_data(CRYPTO_EX_INDEX_UI, ret, &ret->ex_data)) {
++        OPENSSL_free(ret);
++        return NULL;
++    }
++    return ret;
++}
++
++static void free_string(UI_STRING *uis)
++{
++    if (uis->flags & OUT_STRING_FREEABLE) {
++        OPENSSL_free((char *)uis->out_string);
++        switch (uis->type) {
++        case UIT_BOOLEAN:
++            OPENSSL_free((char *)uis->_.boolean_data.action_desc);
++            OPENSSL_free((char *)uis->_.boolean_data.ok_chars);
++            OPENSSL_free((char *)uis->_.boolean_data.cancel_chars);
++            break;
++        default:
++            break;
++        }
++    }
++    OPENSSL_free(uis);
++}
++
++void UI_free(UI *ui)
++{
++    if (ui == NULL)
++        return;
++    sk_UI_STRING_pop_free(ui->strings, free_string);
++    CRYPTO_free_ex_data(CRYPTO_EX_INDEX_UI, ui, &ui->ex_data);
++    CRYPTO_THREAD_lock_free(ui->lock);
++    OPENSSL_free(ui);
++}
++
++static int allocate_string_stack(UI *ui)
++{
++    if (ui->strings == NULL) {
++        ui->strings = sk_UI_STRING_new_null();
++        if (ui->strings == NULL) {
++            return -1;
++        }
++    }
++    return 0;
++}
++
++static UI_STRING *general_allocate_prompt(UI *ui, const char *prompt,
++                                          int prompt_freeable,
++                                          enum UI_string_types type,
++                                          int input_flags, char *result_buf)
++{
++    UI_STRING *ret = NULL;
++
++    if (prompt == NULL) {
++        UIerr(UI_F_GENERAL_ALLOCATE_PROMPT, ERR_R_PASSED_NULL_PARAMETER);
++    } else if ((type == UIT_PROMPT || type == UIT_VERIFY
++                || type == UIT_BOOLEAN) && result_buf == NULL) {
++        UIerr(UI_F_GENERAL_ALLOCATE_PROMPT, UI_R_NO_RESULT_BUFFER);
++    } else if ((ret = OPENSSL_malloc(sizeof(*ret))) != NULL) {
++        ret->out_string = prompt;
++        ret->flags = prompt_freeable ? OUT_STRING_FREEABLE : 0;
++        ret->input_flags = input_flags;
++        ret->type = type;
++        ret->result_buf = result_buf;
++    }
++    return ret;
++}
++
++static int general_allocate_string(UI *ui, const char *prompt,
++                                   int prompt_freeable,
++                                   enum UI_string_types type, int input_flags,
++                                   char *result_buf, int minsize, int maxsize,
++                                   const char *test_buf)
++{
++    int ret = -1;
++    UI_STRING *s = general_allocate_prompt(ui, prompt, prompt_freeable,
++                                           type, input_flags, result_buf);
++
++    if (s != NULL) {
++        if (allocate_string_stack(ui) >= 0) {
++            s->_.string_data.result_minsize = minsize;
++            s->_.string_data.result_maxsize = maxsize;
++            s->_.string_data.test_buf = test_buf;
++            ret = sk_UI_STRING_push(ui->strings, s);
++            /* sk_push() returns 0 on error.  Let's adapt that */
++            if (ret <= 0) {
++                ret--;
++                free_string(s);
++            }
++        } else
++            free_string(s);
++    }
++    return ret;
++}
++
++static int general_allocate_boolean(UI *ui,
++                                    const char *prompt,
++                                    const char *action_desc,
++                                    const char *ok_chars,
++                                    const char *cancel_chars,
++                                    int prompt_freeable,
++                                    enum UI_string_types type,
++                                    int input_flags, char *result_buf)
++{
++    int ret = -1;
++    UI_STRING *s;
++    const char *p;
++
++    if (ok_chars == NULL) {
++        UIerr(UI_F_GENERAL_ALLOCATE_BOOLEAN, ERR_R_PASSED_NULL_PARAMETER);
++    } else if (cancel_chars == NULL) {
++        UIerr(UI_F_GENERAL_ALLOCATE_BOOLEAN, ERR_R_PASSED_NULL_PARAMETER);
++    } else {
++        for (p = ok_chars; *p != '\0'; p++) {
++            if (strchr(cancel_chars, *p) != NULL) {
++                UIerr(UI_F_GENERAL_ALLOCATE_BOOLEAN,
++                      UI_R_COMMON_OK_AND_CANCEL_CHARACTERS);
++            }
++        }
++
++        s = general_allocate_prompt(ui, prompt, prompt_freeable,
++                                    type, input_flags, result_buf);
++
++        if (s != NULL) {
++            if (allocate_string_stack(ui) >= 0) {
++                s->_.boolean_data.action_desc = action_desc;
++                s->_.boolean_data.ok_chars = ok_chars;
++                s->_.boolean_data.cancel_chars = cancel_chars;
++                ret = sk_UI_STRING_push(ui->strings, s);
++                /*
++                 * sk_push() returns 0 on error. Let's adapt that
++                 */
++                if (ret <= 0) {
++                    ret--;
++                    free_string(s);
++                }
++            } else
++                free_string(s);
++        }
++    }
++    return ret;
++}
++
++/*
++ * Returns the index to the place in the stack or -1 for error.  Uses a
++ * direct reference to the prompt.
++ */
++int UI_add_input_string(UI *ui, const char *prompt, int flags,
++                        char *result_buf, int minsize, int maxsize)
++{
++    return general_allocate_string(ui, prompt, 0,
++                                   UIT_PROMPT, flags, result_buf, minsize,
++                                   maxsize, NULL);
++}
++
++/* Same as UI_add_input_string(), excepts it takes a copy of the prompt */
++int UI_dup_input_string(UI *ui, const char *prompt, int flags,
++                        char *result_buf, int minsize, int maxsize)
++{
++    char *prompt_copy = NULL;
++
++    if (prompt != NULL) {
++        prompt_copy = OPENSSL_strdup(prompt);
++        if (prompt_copy == NULL) {
++            UIerr(UI_F_UI_DUP_INPUT_STRING, ERR_R_MALLOC_FAILURE);
++            return 0;
++        }
++    }
++
++    return general_allocate_string(ui, prompt_copy, 1,
++                                   UIT_PROMPT, flags, result_buf, minsize,
++                                   maxsize, NULL);
++}
++
++int UI_add_verify_string(UI *ui, const char *prompt, int flags,
++                         char *result_buf, int minsize, int maxsize,
++                         const char *test_buf)
++{
++    return general_allocate_string(ui, prompt, 0,
++                                   UIT_VERIFY, flags, result_buf, minsize,
++                                   maxsize, test_buf);
++}
++
++int UI_dup_verify_string(UI *ui, const char *prompt, int flags,
++                         char *result_buf, int minsize, int maxsize,
++                         const char *test_buf)
++{
++    char *prompt_copy = NULL;
++
++    if (prompt != NULL) {
++        prompt_copy = OPENSSL_strdup(prompt);
++        if (prompt_copy == NULL) {
++            UIerr(UI_F_UI_DUP_VERIFY_STRING, ERR_R_MALLOC_FAILURE);
++            return -1;
++        }
++    }
++
++    return general_allocate_string(ui, prompt_copy, 1,
++                                   UIT_VERIFY, flags, result_buf, minsize,
++                                   maxsize, test_buf);
++}
++
++int UI_add_input_boolean(UI *ui, const char *prompt, const char *action_desc,
++                         const char *ok_chars, const char *cancel_chars,
++                         int flags, char *result_buf)
++{
++    return general_allocate_boolean(ui, prompt, action_desc,
++                                    ok_chars, cancel_chars, 0, UIT_BOOLEAN,
++                                    flags, result_buf);
++}
++
++int UI_dup_input_boolean(UI *ui, const char *prompt, const char *action_desc,
++                         const char *ok_chars, const char *cancel_chars,
++                         int flags, char *result_buf)
++{
++    char *prompt_copy = NULL;
++    char *action_desc_copy = NULL;
++    char *ok_chars_copy = NULL;
++    char *cancel_chars_copy = NULL;
++
++    if (prompt != NULL) {
++        prompt_copy = OPENSSL_strdup(prompt);
++        if (prompt_copy == NULL) {
++            UIerr(UI_F_UI_DUP_INPUT_BOOLEAN, ERR_R_MALLOC_FAILURE);
++            goto err;
++        }
++    }
++
++    if (action_desc != NULL) {
++        action_desc_copy = OPENSSL_strdup(action_desc);
++        if (action_desc_copy == NULL) {
++            UIerr(UI_F_UI_DUP_INPUT_BOOLEAN, ERR_R_MALLOC_FAILURE);
++            goto err;
++        }
++    }
++
++    if (ok_chars != NULL) {
++        ok_chars_copy = OPENSSL_strdup(ok_chars);
++        if (ok_chars_copy == NULL) {
++            UIerr(UI_F_UI_DUP_INPUT_BOOLEAN, ERR_R_MALLOC_FAILURE);
++            goto err;
++        }
++    }
++
++    if (cancel_chars != NULL) {
++        cancel_chars_copy = OPENSSL_strdup(cancel_chars);
++        if (cancel_chars_copy == NULL) {
++            UIerr(UI_F_UI_DUP_INPUT_BOOLEAN, ERR_R_MALLOC_FAILURE);
++            goto err;
++        }
++    }
++
++    return general_allocate_boolean(ui, prompt_copy, action_desc_copy,
++                                    ok_chars_copy, cancel_chars_copy, 1,
++                                    UIT_BOOLEAN, flags, result_buf);
++ err:
++    OPENSSL_free(prompt_copy);
++    OPENSSL_free(action_desc_copy);
++    OPENSSL_free(ok_chars_copy);
++    OPENSSL_free(cancel_chars_copy);
++    return -1;
++}
++
++int UI_add_info_string(UI *ui, const char *text)
++{
++    return general_allocate_string(ui, text, 0, UIT_INFO, 0, NULL, 0, 0,
++                                   NULL);
++}
++
++int UI_dup_info_string(UI *ui, const char *text)
++{
++    char *text_copy = NULL;
++
++    if (text != NULL) {
++        text_copy = OPENSSL_strdup(text);
++        if (text_copy == NULL) {
++            UIerr(UI_F_UI_DUP_INFO_STRING, ERR_R_MALLOC_FAILURE);
++            return -1;
++        }
++    }
++
++    return general_allocate_string(ui, text_copy, 1, UIT_INFO, 0, NULL,
++                                   0, 0, NULL);
++}
++
++int UI_add_error_string(UI *ui, const char *text)
++{
++    return general_allocate_string(ui, text, 0, UIT_ERROR, 0, NULL, 0, 0,
++                                   NULL);
++}
++
++int UI_dup_error_string(UI *ui, const char *text)
++{
++    char *text_copy = NULL;
++
++    if (text != NULL) {
++        text_copy = OPENSSL_strdup(text);
++        if (text_copy == NULL) {
++            UIerr(UI_F_UI_DUP_ERROR_STRING, ERR_R_MALLOC_FAILURE);
++            return -1;
++        }
++    }
++    return general_allocate_string(ui, text_copy, 1, UIT_ERROR, 0, NULL,
++                                   0, 0, NULL);
++}
++
++char *UI_construct_prompt(UI *ui, const char *object_desc,
++                          const char *object_name)
++{
++    char *prompt = NULL;
++
++    if (ui->meth->ui_construct_prompt != NULL)
++        prompt = ui->meth->ui_construct_prompt(ui, object_desc, object_name);
++    else {
++        char prompt1[] = "Enter ";
++        char prompt2[] = " for ";
++        char prompt3[] = ":";
++        int len = 0;
++
++        if (object_desc == NULL)
++            return NULL;
++        len = sizeof(prompt1) - 1 + strlen(object_desc);
++        if (object_name != NULL)
++            len += sizeof(prompt2) - 1 + strlen(object_name);
++        len += sizeof(prompt3) - 1;
++
++        prompt = OPENSSL_malloc(len + 1);
++        if (prompt == NULL)
++            return NULL;
++        OPENSSL_strlcpy(prompt, prompt1, len + 1);
++        OPENSSL_strlcat(prompt, object_desc, len + 1);
++        if (object_name != NULL) {
++            OPENSSL_strlcat(prompt, prompt2, len + 1);
++            OPENSSL_strlcat(prompt, object_name, len + 1);
++        }
++        OPENSSL_strlcat(prompt, prompt3, len + 1);
++    }
++    return prompt;
++}
++
++void *UI_add_user_data(UI *ui, void *user_data)
++{
++    void *old_data = ui->user_data;
++    ui->user_data = user_data;
++    return old_data;
++}
++
++void *UI_get0_user_data(UI *ui)
++{
++    return ui->user_data;
++}
++
++const char *UI_get0_result(UI *ui, int i)
++{
++    if (i < 0) {
++        UIerr(UI_F_UI_GET0_RESULT, UI_R_INDEX_TOO_SMALL);
++        return NULL;
++    }
++    if (i >= sk_UI_STRING_num(ui->strings)) {
++        UIerr(UI_F_UI_GET0_RESULT, UI_R_INDEX_TOO_LARGE);
++        return NULL;
++    }
++    return UI_get0_result_string(sk_UI_STRING_value(ui->strings, i));
++}
++
++static int print_error(const char *str, size_t len, UI *ui)
++{
++    UI_STRING uis;
++
++    memset(&uis, 0, sizeof(uis));
++    uis.type = UIT_ERROR;
++    uis.out_string = str;
++
++    if (ui->meth->ui_write_string != NULL
++        && ui->meth->ui_write_string(ui, &uis) <= 0)
++        return -1;
++    return 0;
++}
++
++int UI_process(UI *ui)
++{
++    int i, ok = 0;
++    const char *state = "processing";
++
++    if (ui->meth->ui_open_session != NULL
++        && ui->meth->ui_open_session(ui) <= 0) {
++        state = "opening session";
++        ok = -1;
++        goto err;
++    }
++
++    if (ui->flags & UI_FLAG_PRINT_ERRORS)
++        ERR_print_errors_cb((int (*)(const char *, size_t, void *))
++                            print_error, (void *)ui);
++
++    for (i = 0; i < sk_UI_STRING_num(ui->strings); i++) {
++        if (ui->meth->ui_write_string != NULL
++            && (ui->meth->ui_write_string(ui,
++                                          sk_UI_STRING_value(ui->strings, i))
++                <= 0))
++        {
++            state = "writing strings";
++            ok = -1;
++            goto err;
++        }
++    }
++
++    if (ui->meth->ui_flush != NULL)
++        switch (ui->meth->ui_flush(ui)) {
++        case -1:               /* Interrupt/Cancel/something... */
++            ok = -2;
++            goto err;
++        case 0:                /* Errors */
++            state = "flushing";
++            ok = -1;
++            goto err;
++        default:               /* Success */
++            ok = 0;
++            break;
++        }
++
++    for (i = 0; i < sk_UI_STRING_num(ui->strings); i++) {
++        if (ui->meth->ui_read_string != NULL) {
++            switch (ui->meth->ui_read_string(ui,
++                                             sk_UI_STRING_value(ui->strings,
++                                                                i))) {
++            case -1:           /* Interrupt/Cancel/something... */
++                ok = -2;
++                goto err;
++            case 0:            /* Errors */
++                state = "reading strings";
++                ok = -1;
++                goto err;
++            default:           /* Success */
++                ok = 0;
++                break;
++            }
++        }
++    }
++ err:
++    if (ui->meth->ui_close_session != NULL
++        && ui->meth->ui_close_session(ui) <= 0) {
++        if (state == NULL)
++            state = "closing session";
++        ok = -1;
++    }
++
++    if (ok == -1) {
++        UIerr(UI_F_UI_PROCESS, UI_R_PROCESSING_ERROR);
++        ERR_add_error_data(2, "while ", state);
++    }
++    return ok;
++}
++
++int UI_ctrl(UI *ui, int cmd, long i, void *p, void (*f) (void))
++{
++    if (ui == NULL) {
++        UIerr(UI_F_UI_CTRL, ERR_R_PASSED_NULL_PARAMETER);
++        return -1;
++    }
++    switch (cmd) {
++    case UI_CTRL_PRINT_ERRORS:
++        {
++            int save_flag = ! !(ui->flags & UI_FLAG_PRINT_ERRORS);
++            if (i)
++                ui->flags |= UI_FLAG_PRINT_ERRORS;
++            else
++                ui->flags &= ~UI_FLAG_PRINT_ERRORS;
++            return save_flag;
++        }
++    case UI_CTRL_IS_REDOABLE:
++        return ! !(ui->flags & UI_FLAG_REDOABLE);
++    default:
++        break;
++    }
++    UIerr(UI_F_UI_CTRL, UI_R_UNKNOWN_CONTROL_COMMAND);
++    return -1;
++}
++
++int UI_set_ex_data(UI *r, int idx, void *arg)
++{
++    return (CRYPTO_set_ex_data(&r->ex_data, idx, arg));
++}
++
++void *UI_get_ex_data(UI *r, int idx)
++{
++    return (CRYPTO_get_ex_data(&r->ex_data, idx));
++}
++
++void UI_set_default_method(const UI_METHOD *meth)
++{
++    default_UI_meth = meth;
++}
++
++const UI_METHOD *UI_get_default_method(void)
++{
++    if (default_UI_meth == NULL) {
++        default_UI_meth = UI_OpenSSL();
++    }
++    return default_UI_meth;
++}
++
++const UI_METHOD *UI_get_method(UI *ui)
++{
++    return ui->meth;
++}
++
++const UI_METHOD *UI_set_method(UI *ui, const UI_METHOD *meth)
++{
++    ui->meth = meth;
++    return ui->meth;
++}
++
++UI_METHOD *UI_create_method(const char *name)
++{
++    UI_METHOD *ui_method = OPENSSL_zalloc(sizeof(*ui_method));
++
++    if (ui_method != NULL) {
++        ui_method->name = OPENSSL_strdup(name);
++        if (ui_method->name == NULL) {
++            OPENSSL_free(ui_method);
++            UIerr(UI_F_UI_CREATE_METHOD, ERR_R_MALLOC_FAILURE);
++            return NULL;
++        }
++    }
++    return ui_method;
++}
++
++/*
++ * BIG FSCKING WARNING!!!! If you use this on a statically allocated method
++ * (that is, it hasn't been allocated using UI_create_method(), you deserve
++ * anything Murphy can throw at you and more! You have been warned.
++ */
++void UI_destroy_method(UI_METHOD *ui_method)
++{
++    OPENSSL_free(ui_method->name);
++    ui_method->name = NULL;
++    OPENSSL_free(ui_method);
++}
++
++int UI_method_set_opener(UI_METHOD *method, int (*opener) (UI *ui))
++{
++    if (method != NULL) {
++        method->ui_open_session = opener;
++        return 0;
++    }
++    return -1;
++}
++
++int UI_method_set_writer(UI_METHOD *method,
++                         int (*writer) (UI *ui, UI_STRING *uis))
++{
++    if (method != NULL) {
++        method->ui_write_string = writer;
++        return 0;
++    }
++    return -1;
++}
++
++int UI_method_set_flusher(UI_METHOD *method, int (*flusher) (UI *ui))
++{
++    if (method != NULL) {
++        method->ui_flush = flusher;
++        return 0;
++    }
++    return -1;
++}
++
++int UI_method_set_reader(UI_METHOD *method,
++                         int (*reader) (UI *ui, UI_STRING *uis))
++{
++    if (method != NULL) {
++        method->ui_read_string = reader;
++        return 0;
++    }
++    return -1;
++}
++
++int UI_method_set_closer(UI_METHOD *method, int (*closer) (UI *ui))
++{
++    if (method != NULL) {
++        method->ui_close_session = closer;
++        return 0;
++    }
++    return -1;
++}
++
++int UI_method_set_prompt_constructor(UI_METHOD *method,
++                                     char *(*prompt_constructor) (UI *ui,
++                                                                  const char
++                                                                  *object_desc,
++                                                                  const char
++                                                                  *object_name))
++{
++    if (method != NULL) {
++        method->ui_construct_prompt = prompt_constructor;
++        return 0;
++    }
++    return -1;
++}
++
++int (*UI_method_get_opener(UI_METHOD *method)) (UI *)
++{
++    if (method != NULL)
++        return method->ui_open_session;
++    return NULL;
++}
++
++int (*UI_method_get_writer(UI_METHOD *method)) (UI *, UI_STRING *)
++{
++    if (method != NULL)
++        return method->ui_write_string;
++    return NULL;
++}
++
++int (*UI_method_get_flusher(UI_METHOD *method)) (UI *)
++{
++    if (method != NULL)
++        return method->ui_flush;
++    return NULL;
++}
++
++int (*UI_method_get_reader(UI_METHOD *method)) (UI *, UI_STRING *)
++{
++    if (method != NULL)
++        return method->ui_read_string;
++    return NULL;
++}
++
++int (*UI_method_get_closer(UI_METHOD *method)) (UI *)
++{
++    if (method != NULL)
++        return method->ui_close_session;
++    return NULL;
++}
++
++char *(*UI_method_get_prompt_constructor(UI_METHOD *method)) (UI *,
++                                                              const char *,
++                                                              const char *)
++{
++    if (method != NULL)
++        return method->ui_construct_prompt;
++    return NULL;
++}
++
++enum UI_string_types UI_get_string_type(UI_STRING *uis)
++{
++    return uis->type;
++}
++
++int UI_get_input_flags(UI_STRING *uis)
++{
++    return uis->input_flags;
++}
++
++const char *UI_get0_output_string(UI_STRING *uis)
++{
++    return uis->out_string;
++}
++
++const char *UI_get0_action_string(UI_STRING *uis)
++{
++    switch (uis->type) {
++    case UIT_PROMPT:
++    case UIT_BOOLEAN:
++        return uis->_.boolean_data.action_desc;
++    default:
++        return NULL;
++    }
++}
++
++const char *UI_get0_result_string(UI_STRING *uis)
++{
++    switch (uis->type) {
++    case UIT_PROMPT:
++    case UIT_VERIFY:
++        return uis->result_buf;
++    default:
++        return NULL;
++    }
++}
++
++const char *UI_get0_test_string(UI_STRING *uis)
++{
++    switch (uis->type) {
++    case UIT_VERIFY:
++        return uis->_.string_data.test_buf;
++    default:
++        return NULL;
++    }
++}
++
++int UI_get_result_minsize(UI_STRING *uis)
++{
++    switch (uis->type) {
++    case UIT_PROMPT:
++    case UIT_VERIFY:
++        return uis->_.string_data.result_minsize;
++    default:
++        return -1;
++    }
++}
++
++int UI_get_result_maxsize(UI_STRING *uis)
++{
++    switch (uis->type) {
++    case UIT_PROMPT:
++    case UIT_VERIFY:
++        return uis->_.string_data.result_maxsize;
++    default:
++        return -1;
++    }
++}
++
++int UI_set_result(UI *ui, UI_STRING *uis, const char *result)
++{
++    int l = strlen(result);
++
++    ui->flags &= ~UI_FLAG_REDOABLE;
++
++    switch (uis->type) {
++    case UIT_PROMPT:
++    case UIT_VERIFY:
++        {
++            char number1[DECIMAL_SIZE(uis->_.string_data.result_minsize) + 1];
++            char number2[DECIMAL_SIZE(uis->_.string_data.result_maxsize) + 1];
++
++            BIO_snprintf(number1, sizeof(number1), "%d",
++                         uis->_.string_data.result_minsize);
++            BIO_snprintf(number2, sizeof(number2), "%d",
++                         uis->_.string_data.result_maxsize);
++
++            if (l < uis->_.string_data.result_minsize) {
++                ui->flags |= UI_FLAG_REDOABLE;
++                UIerr(UI_F_UI_SET_RESULT, UI_R_RESULT_TOO_SMALL);
++                ERR_add_error_data(5, "You must type in ",
++                                   number1, " to ", number2, " characters");
++                return -1;
++            }
++            if (l > uis->_.string_data.result_maxsize) {
++                ui->flags |= UI_FLAG_REDOABLE;
++                UIerr(UI_F_UI_SET_RESULT, UI_R_RESULT_TOO_LARGE);
++                ERR_add_error_data(5, "You must type in ",
++                                   number1, " to ", number2, " characters");
++                return -1;
++            }
++        }
++
++        if (uis->result_buf == NULL) {
++            UIerr(UI_F_UI_SET_RESULT, UI_R_NO_RESULT_BUFFER);
++            return -1;
++        }
++
++        OPENSSL_strlcpy(uis->result_buf, result,
++                    uis->_.string_data.result_maxsize + 1);
++        break;
++    case UIT_BOOLEAN:
++        {
++            const char *p;
++
++            if (uis->result_buf == NULL) {
++                UIerr(UI_F_UI_SET_RESULT, UI_R_NO_RESULT_BUFFER);
++                return -1;
++            }
++
++            uis->result_buf[0] = '\0';
++            for (p = result; *p; p++) {
++                if (strchr(uis->_.boolean_data.ok_chars, *p)) {
++                    uis->result_buf[0] = uis->_.boolean_data.ok_chars[0];
++                    break;
++                }
++                if (strchr(uis->_.boolean_data.cancel_chars, *p)) {
++                    uis->result_buf[0] = uis->_.boolean_data.cancel_chars[0];
++                    break;
++                }
++            }
++        }
++    default:
++        break;
++    }
++    return 0;
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/ui/ui_locl.h b/CryptoPkg/Library/OpensslLib/openssl/crypto/ui/ui_locl.h
+new file mode 100644
+index 0000000..2953739
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/ui/ui_locl.h
+@@ -0,0 +1,97 @@
++/*
++ * Copyright 2001-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#ifndef HEADER_UI_LOCL_H
++# define HEADER_UI_LOCL_H
++
++# include 
++# include 
++
++# ifdef _
++#  undef _
++# endif
++
++struct ui_method_st {
++    char *name;
++    /*
++     * All the functions return 1 or non-NULL for success and 0 or NULL for
++     * failure
++     */
++    /*
++     * Open whatever channel for this, be it the console, an X window or
++     * whatever. This function should use the ex_data structure to save
++     * intermediate data.
++     */
++    int (*ui_open_session) (UI *ui);
++    int (*ui_write_string) (UI *ui, UI_STRING *uis);
++    /*
++     * Flush the output.  If a GUI dialog box is used, this function can be
++     * used to actually display it.
++     */
++    int (*ui_flush) (UI *ui);
++    int (*ui_read_string) (UI *ui, UI_STRING *uis);
++    int (*ui_close_session) (UI *ui);
++    /*
++     * Construct a prompt in a user-defined manner.  object_desc is a textual
++     * short description of the object, for example "pass phrase", and
++     * object_name is the name of the object (might be a card name or a file
++     * name. The returned string shall always be allocated on the heap with
++     * OPENSSL_malloc(), and need to be free'd with OPENSSL_free().
++     */
++    char *(*ui_construct_prompt) (UI *ui, const char *object_desc,
++                                  const char *object_name);
++};
++
++struct ui_string_st {
++    enum UI_string_types type;  /* Input */
++    const char *out_string;     /* Input */
++    int input_flags;            /* Flags from the user */
++    /*
++     * The following parameters are completely irrelevant for UIT_INFO, and
++     * can therefore be set to 0 or NULL
++     */
++    char *result_buf;           /* Input and Output: If not NULL,
++                                 * user-defined with size in result_maxsize.
++                                 * Otherwise, it may be allocated by the UI
++                                 * routine, meaning result_minsize is going
++                                 * to be overwritten. */
++    union {
++        struct {
++            int result_minsize; /* Input: minimum required size of the
++                                 * result. */
++            int result_maxsize; /* Input: maximum permitted size of the
++                                 * result */
++            const char *test_buf; /* Input: test string to verify against */
++        } string_data;
++        struct {
++            const char *action_desc; /* Input */
++            const char *ok_chars; /* Input */
++            const char *cancel_chars; /* Input */
++        } boolean_data;
++    } _;
++
++# define OUT_STRING_FREEABLE 0x01
++    int flags;                  /* flags for internal use */
++};
++
++struct ui_st {
++    const UI_METHOD *meth;
++    STACK_OF(UI_STRING) *strings; /* We might want to prompt for more than
++                                   * one thing at a time, and with different
++                                   * echoing status.  */
++    void *user_data;
++    CRYPTO_EX_DATA ex_data;
++# define UI_FLAG_REDOABLE        0x0001
++# define UI_FLAG_PRINT_ERRORS    0x0100
++    int flags;
++
++    CRYPTO_RWLOCK *lock;
++};
++
++#endif
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/ui/ui_openssl.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/ui/ui_openssl.c
+new file mode 100644
+index 0000000..ed0bfa0
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/ui/ui_openssl.c
+@@ -0,0 +1,700 @@
++/*
++ * Copyright 2001-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include 
++
++/*
++ * need for #define _POSIX_C_SOURCE arises whenever you pass -ansi to gcc
++ * [maybe others?], because it masks interfaces not discussed in standard,
++ * sigaction and fileno included. -pedantic would be more appropriate for the
++ * intended purposes, but we can't prevent users from adding -ansi.
++ */
++#if defined(OPENSSL_SYS_VXWORKS)
++# include 
++#endif
++
++#if !defined(_POSIX_C_SOURCE) && defined(OPENSSL_SYS_VMS)
++# ifndef _POSIX_C_SOURCE
++#  define _POSIX_C_SOURCE 2
++# endif
++#endif
++#include 
++#include 
++#include 
++#include 
++
++#if !defined(OPENSSL_SYS_MSDOS) && !defined(OPENSSL_SYS_VMS)
++# ifdef OPENSSL_UNISTD
++#  include OPENSSL_UNISTD
++# else
++#  include 
++# endif
++/*
++ * If unistd.h defines _POSIX_VERSION, we conclude that we are on a POSIX
++ * system and have sigaction and termios.
++ */
++# if defined(_POSIX_VERSION)
++
++#  define SIGACTION
++#  if !defined(TERMIOS) && !defined(TERMIO) && !defined(SGTTY)
++#   define TERMIOS
++#  endif
++
++# endif
++#endif
++
++/* 06-Apr-92 Luke Brennan    Support for VMS */
++#include "ui_locl.h"
++#include "internal/cryptlib.h"
++
++#ifdef OPENSSL_SYS_VMS          /* prototypes for sys$whatever */
++# include 
++# ifdef __DECC
++#  pragma message disable DOLLARID
++# endif
++#endif
++
++#ifdef WIN_CONSOLE_BUG
++# include 
++# ifndef OPENSSL_SYS_WINCE
++#  include 
++# endif
++#endif
++
++/*
++ * There are 6 types of terminal interface supported, TERMIO, TERMIOS, VMS,
++ * MSDOS, WIN32 Console and SGTTY.
++ *
++ * If someone defines one of the macros TERMIO, TERMIOS or SGTTY, it will
++ * remain respected.  Otherwise, we default to TERMIOS except for a few
++ * systems that require something different.
++ *
++ * Note: we do not use SGTTY unless it's defined by the configuration.  We
++ * may eventually opt to remove it's use entirely.
++ */
++
++#if !defined(TERMIOS) && !defined(TERMIO) && !defined(SGTTY)
++
++# if defined(_LIBC)
++#  undef  TERMIOS
++#  define TERMIO
++#  undef  SGTTY
++/*
++ * We know that VMS, MSDOS, VXWORKS, use entirely other mechanisms.
++ */
++# elif !defined(OPENSSL_SYS_VMS) \
++	&& !defined(OPENSSL_SYS_MSDOS) \
++	&& !defined(OPENSSL_SYS_VXWORKS)
++#  define TERMIOS
++#  undef  TERMIO
++#  undef  SGTTY
++# endif
++
++#endif
++
++#ifdef TERMIOS
++# include 
++# define TTY_STRUCT             struct termios
++# define TTY_FLAGS              c_lflag
++# define TTY_get(tty,data)      tcgetattr(tty,data)
++# define TTY_set(tty,data)      tcsetattr(tty,TCSANOW,data)
++#endif
++
++#ifdef TERMIO
++# include 
++# define TTY_STRUCT             struct termio
++# define TTY_FLAGS              c_lflag
++# define TTY_get(tty,data)      ioctl(tty,TCGETA,data)
++# define TTY_set(tty,data)      ioctl(tty,TCSETA,data)
++#endif
++
++#ifdef SGTTY
++# include 
++# define TTY_STRUCT             struct sgttyb
++# define TTY_FLAGS              sg_flags
++# define TTY_get(tty,data)      ioctl(tty,TIOCGETP,data)
++# define TTY_set(tty,data)      ioctl(tty,TIOCSETP,data)
++#endif
++
++#if !defined(_LIBC) && !defined(OPENSSL_SYS_MSDOS) && !defined(OPENSSL_SYS_VMS)
++# include 
++#endif
++
++#ifdef OPENSSL_SYS_MSDOS
++# include 
++#endif
++
++#ifdef OPENSSL_SYS_VMS
++# include 
++# include 
++# include 
++# include 
++struct IOSB {
++    short iosb$w_value;
++    short iosb$w_count;
++    long iosb$l_info;
++};
++#endif
++
++#ifndef NX509_SIG
++# define NX509_SIG 32
++#endif
++
++/* Define globals.  They are protected by a lock */
++#ifdef SIGACTION
++static struct sigaction savsig[NX509_SIG];
++#else
++static void (*savsig[NX509_SIG]) (int);
++#endif
++
++#ifdef OPENSSL_SYS_VMS
++static struct IOSB iosb;
++static $DESCRIPTOR(terminal, "TT");
++static long tty_orig[3], tty_new[3]; /* XXX Is there any guarantee that this
++                                      * will always suffice for the actual
++                                      * structures? */
++static long status;
++static unsigned short channel = 0;
++#elif defined(_WIN32) && !defined(_WIN32_WCE)
++static DWORD tty_orig, tty_new;
++#else
++# if !defined(OPENSSL_SYS_MSDOS) || defined(__DJGPP__)
++static TTY_STRUCT tty_orig, tty_new;
++# endif
++#endif
++static FILE *tty_in, *tty_out;
++static int is_a_tty;
++
++/* Declare static functions */
++#if !defined(OPENSSL_SYS_WINCE)
++static int read_till_nl(FILE *);
++static void recsig(int);
++static void pushsig(void);
++static void popsig(void);
++#endif
++#if defined(OPENSSL_SYS_MSDOS) && !defined(_WIN32)
++static int noecho_fgets(char *buf, int size, FILE *tty);
++#endif
++static int read_string_inner(UI *ui, UI_STRING *uis, int echo, int strip_nl);
++
++static int read_string(UI *ui, UI_STRING *uis);
++static int write_string(UI *ui, UI_STRING *uis);
++
++static int open_console(UI *ui);
++static int echo_console(UI *ui);
++static int noecho_console(UI *ui);
++static int close_console(UI *ui);
++
++static UI_METHOD ui_openssl = {
++    "OpenSSL default user interface",
++    open_console,
++    write_string,
++    NULL,                       /* No flusher is needed for command lines */
++    read_string,
++    close_console,
++    NULL
++};
++
++/* The method with all the built-in thingies */
++UI_METHOD *UI_OpenSSL(void)
++{
++    return &ui_openssl;
++}
++
++/*
++ * The following function makes sure that info and error strings are printed
++ * before any prompt.
++ */
++static int write_string(UI *ui, UI_STRING *uis)
++{
++    switch (UI_get_string_type(uis)) {
++    case UIT_ERROR:
++    case UIT_INFO:
++        fputs(UI_get0_output_string(uis), tty_out);
++        fflush(tty_out);
++        break;
++    default:
++        break;
++    }
++    return 1;
++}
++
++static int read_string(UI *ui, UI_STRING *uis)
++{
++    int ok = 0;
++
++    switch (UI_get_string_type(uis)) {
++    case UIT_BOOLEAN:
++        fputs(UI_get0_output_string(uis), tty_out);
++        fputs(UI_get0_action_string(uis), tty_out);
++        fflush(tty_out);
++        return read_string_inner(ui, uis,
++                                 UI_get_input_flags(uis) & UI_INPUT_FLAG_ECHO,
++                                 0);
++    case UIT_PROMPT:
++        fputs(UI_get0_output_string(uis), tty_out);
++        fflush(tty_out);
++        return read_string_inner(ui, uis,
++                                 UI_get_input_flags(uis) & UI_INPUT_FLAG_ECHO,
++                                 1);
++    case UIT_VERIFY:
++        fprintf(tty_out, "Verifying - %s", UI_get0_output_string(uis));
++        fflush(tty_out);
++        if ((ok = read_string_inner(ui, uis,
++                                    UI_get_input_flags(uis) &
++                                    UI_INPUT_FLAG_ECHO, 1)) <= 0)
++            return ok;
++        if (strcmp(UI_get0_result_string(uis), UI_get0_test_string(uis)) != 0) {
++            fprintf(tty_out, "Verify failure\n");
++            fflush(tty_out);
++            return 0;
++        }
++        break;
++    default:
++        break;
++    }
++    return 1;
++}
++
++#if !defined(OPENSSL_SYS_WINCE)
++/* Internal functions to read a string without echoing */
++static int read_till_nl(FILE *in)
++{
++# define SIZE 4
++    char buf[SIZE + 1];
++
++    do {
++        if (!fgets(buf, SIZE, in))
++            return 0;
++    } while (strchr(buf, '\n') == NULL);
++    return 1;
++}
++
++static volatile sig_atomic_t intr_signal;
++#endif
++
++static int read_string_inner(UI *ui, UI_STRING *uis, int echo, int strip_nl)
++{
++    static int ps;
++    int ok;
++    char result[BUFSIZ];
++    int maxsize = BUFSIZ - 1;
++#if !defined(OPENSSL_SYS_WINCE)
++    char *p = NULL;
++    int echo_eol = !echo;
++
++    intr_signal = 0;
++    ok = 0;
++    ps = 0;
++
++    pushsig();
++    ps = 1;
++
++    if (!echo && !noecho_console(ui))
++        goto error;
++    ps = 2;
++
++    result[0] = '\0';
++# if defined(_WIN32)
++    if (is_a_tty) {
++        DWORD numread;
++#  if defined(CP_UTF8)
++        if (GetEnvironmentVariableW(L"OPENSSL_WIN32_UTF8", NULL, 0) != 0) {
++            WCHAR wresult[BUFSIZ];
++
++            if (ReadConsoleW(GetStdHandle(STD_INPUT_HANDLE),
++                         wresult, maxsize, &numread, NULL)) {
++                if (numread >= 2 &&
++                    wresult[numread-2] == L'\r' &&
++                    wresult[numread-1] == L'\n') {
++                    wresult[numread-2] = L'\n';
++                    numread--;
++                }
++                wresult[numread] = '\0';
++                if (WideCharToMultiByte(CP_UTF8, 0, wresult, -1,
++                                        result, sizeof(result), NULL, 0) > 0)
++                    p = result;
++
++                OPENSSL_cleanse(wresult, sizeof(wresult));
++            }
++        } else
++#  endif
++        if (ReadConsoleA(GetStdHandle(STD_INPUT_HANDLE),
++                         result, maxsize, &numread, NULL)) {
++            if (numread >= 2 &&
++                result[numread-2] == '\r' && result[numread-1] == '\n') {
++                result[numread-2] = '\n';
++                numread--;
++            }
++            result[numread] = '\0';
++            p = result;
++        }
++    } else
++# elif defined(OPENSSL_SYS_MSDOS)
++    if (!echo) {
++        noecho_fgets(result, maxsize, tty_in);
++        p = result;             /* FIXME: noecho_fgets doesn't return errors */
++    } else
++# endif
++    p = fgets(result, maxsize, tty_in);
++    if (p == NULL)
++        goto error;
++    if (feof(tty_in))
++        goto error;
++    if (ferror(tty_in))
++        goto error;
++    if ((p = (char *)strchr(result, '\n')) != NULL) {
++        if (strip_nl)
++            *p = '\0';
++    } else if (!read_till_nl(tty_in))
++        goto error;
++    if (UI_set_result(ui, uis, result) >= 0)
++        ok = 1;
++
++ error:
++    if (intr_signal == SIGINT)
++        ok = -1;
++    if (echo_eol)
++        fprintf(tty_out, "\n");
++    if (ps >= 2 && !echo && !echo_console(ui))
++        ok = 0;
++
++    if (ps >= 1)
++        popsig();
++#else
++    ok = 1;
++#endif
++
++    OPENSSL_cleanse(result, BUFSIZ);
++    return ok;
++}
++
++/* Internal functions to open, handle and close a channel to the console.  */
++static int open_console(UI *ui)
++{
++    CRYPTO_THREAD_write_lock(ui->lock);
++    is_a_tty = 1;
++
++#if defined(OPENSSL_SYS_VXWORKS)
++    tty_in = stdin;
++    tty_out = stderr;
++#elif defined(_WIN32) && !defined(_WIN32_WCE)
++    if ((tty_out = fopen("conout$", "w")) == NULL)
++        tty_out = stderr;
++
++    if (GetConsoleMode(GetStdHandle(STD_INPUT_HANDLE), &tty_orig)) {
++        tty_in = stdin;
++    } else {
++        is_a_tty = 0;
++        if ((tty_in = fopen("conin$", "r")) == NULL)
++            tty_in = stdin;
++    }
++#else
++# ifdef OPENSSL_SYS_MSDOS
++#  define DEV_TTY "con"
++# else
++#  define DEV_TTY "/dev/tty"
++# endif
++    if ((tty_in = fopen(DEV_TTY, "r")) == NULL)
++        tty_in = stdin;
++    if ((tty_out = fopen(DEV_TTY, "w")) == NULL)
++        tty_out = stderr;
++#endif
++
++#if defined(TTY_get) && !defined(OPENSSL_SYS_VMS)
++    if (TTY_get(fileno(tty_in), &tty_orig) == -1) {
++# ifdef ENOTTY
++        if (errno == ENOTTY)
++            is_a_tty = 0;
++        else
++# endif
++# ifdef EINVAL
++            /*
++             * Ariel Glenn ariel@columbia.edu reports that solaris can return
++             * EINVAL instead.  This should be ok
++             */
++        if (errno == EINVAL)
++            is_a_tty = 0;
++        else
++# endif
++# ifdef ENODEV
++            /*
++             * MacOS X returns ENODEV (Operation not supported by device),
++             * which seems appropriate.
++             */
++        if (errno == ENODEV)
++            is_a_tty = 0;
++        else
++# endif
++            {
++                char tmp_num[10];
++                BIO_snprintf(tmp_num, sizeof(tmp_num) - 1, "%d", errno);
++                UIerr(UI_F_OPEN_CONSOLE, UI_R_UNKNOWN_TTYGET_ERRNO_VALUE);
++                ERR_add_error_data(2, "errno=", tmp_num);
++
++                return 0;
++            }
++    }
++#endif
++#ifdef OPENSSL_SYS_VMS
++    status = sys$assign(&terminal, &channel, 0, 0);
++
++    /* if there isn't a TT device, something is very wrong */
++    if (status != SS$_NORMAL) {
++        char tmp_num[12];
++
++        BIO_snprintf(tmp_num, sizeof(tmp_num) - 1, "%%X%08X", status);
++        UIerr(UI_F_OPEN_CONSOLE, UI_R_SYSASSIGN_ERROR);
++        ERR_add_error_data(2, "status=", tmp_num);
++        return 0;
++    }
++
++    status = sys$qiow(0, channel, IO$_SENSEMODE, &iosb, 0, 0, tty_orig, 12,
++                      0, 0, 0, 0);
++
++    /* If IO$_SENSEMODE doesn't work, this is not a terminal device */
++    if ((status != SS$_NORMAL) || (iosb.iosb$w_value != SS$_NORMAL))
++        is_a_tty = 0;
++#endif
++    return 1;
++}
++
++static int noecho_console(UI *ui)
++{
++#ifdef TTY_FLAGS
++    memcpy(&(tty_new), &(tty_orig), sizeof(tty_orig));
++    tty_new.TTY_FLAGS &= ~ECHO;
++#endif
++
++#if defined(TTY_set) && !defined(OPENSSL_SYS_VMS)
++    if (is_a_tty && (TTY_set(fileno(tty_in), &tty_new) == -1))
++        return 0;
++#endif
++#ifdef OPENSSL_SYS_VMS
++    if (is_a_tty) {
++        tty_new[0] = tty_orig[0];
++        tty_new[1] = tty_orig[1] | TT$M_NOECHO;
++        tty_new[2] = tty_orig[2];
++        status = sys$qiow(0, channel, IO$_SETMODE, &iosb, 0, 0, tty_new, 12,
++                          0, 0, 0, 0);
++        if ((status != SS$_NORMAL) || (iosb.iosb$w_value != SS$_NORMAL)) {
++            char tmp_num[2][12];
++
++            BIO_snprintf(tmp_num[0], sizeof(tmp_num[0]) - 1, "%%X%08X",
++                         status);
++            BIO_snprintf(tmp_num[1], sizeof(tmp_num[1]) - 1, "%%X%08X",
++                         iosb.iosb$w_value);
++            UIerr(UI_F_NOECHO_CONSOLE, UI_R_SYSQIOW_ERROR);
++            ERR_add_error_data(5, "status=", tmp_num[0],
++                               ",", "iosb.iosb$w_value=", tmp_num[1]);
++            return 0;
++        }
++    }
++#endif
++#if defined(_WIN32) && !defined(_WIN32_WCE)
++    if (is_a_tty) {
++        tty_new = tty_orig;
++        tty_new &= ~ENABLE_ECHO_INPUT;
++        SetConsoleMode(GetStdHandle(STD_INPUT_HANDLE), tty_new);
++    }
++#endif
++    return 1;
++}
++
++static int echo_console(UI *ui)
++{
++#if defined(TTY_set) && !defined(OPENSSL_SYS_VMS)
++    memcpy(&(tty_new), &(tty_orig), sizeof(tty_orig));
++    tty_new.TTY_FLAGS |= ECHO;
++#endif
++
++#if defined(TTY_set) && !defined(OPENSSL_SYS_VMS)
++    if (is_a_tty && (TTY_set(fileno(tty_in), &tty_new) == -1))
++        return 0;
++#endif
++#ifdef OPENSSL_SYS_VMS
++    if (is_a_tty) {
++        tty_new[0] = tty_orig[0];
++        tty_new[1] = tty_orig[1] & ~TT$M_NOECHO;
++        tty_new[2] = tty_orig[2];
++        status = sys$qiow(0, channel, IO$_SETMODE, &iosb, 0, 0, tty_new, 12,
++                          0, 0, 0, 0);
++        if ((status != SS$_NORMAL) || (iosb.iosb$w_value != SS$_NORMAL)) {
++            char tmp_num[2][12];
++
++            BIO_snprintf(tmp_num[0], sizeof(tmp_num[0]) - 1, "%%X%08X",
++                         status);
++            BIO_snprintf(tmp_num[1], sizeof(tmp_num[1]) - 1, "%%X%08X",
++                         iosb.iosb$w_value);
++            UIerr(UI_F_ECHO_CONSOLE, UI_R_SYSQIOW_ERROR);
++            ERR_add_error_data(5, "status=", tmp_num[0],
++                               ",", "iosb.iosb$w_value=", tmp_num[1]);
++            return 0;
++        }
++    }
++#endif
++#if defined(_WIN32) && !defined(_WIN32_WCE)
++    if (is_a_tty) {
++        tty_new = tty_orig;
++        tty_new |= ENABLE_ECHO_INPUT;
++        SetConsoleMode(GetStdHandle(STD_INPUT_HANDLE), tty_new);
++    }
++#endif
++    return 1;
++}
++
++static int close_console(UI *ui)
++{
++    if (tty_in != stdin)
++        fclose(tty_in);
++    if (tty_out != stderr)
++        fclose(tty_out);
++#ifdef OPENSSL_SYS_VMS
++    status = sys$dassgn(channel);
++    if (status != SS$_NORMAL) {
++        char tmp_num[12];
++
++        BIO_snprintf(tmp_num, sizeof(tmp_num) - 1, "%%X%08X", status);
++        UIerr(UI_F_CLOSE_CONSOLE, UI_R_SYSDASSGN_ERROR);
++        ERR_add_error_data(2, "status=", tmp_num);
++        return 0;
++    }
++#endif
++    CRYPTO_THREAD_unlock(ui->lock);
++
++    return 1;
++}
++
++#if !defined(OPENSSL_SYS_WINCE)
++/* Internal functions to handle signals and act on them */
++static void pushsig(void)
++{
++# ifndef OPENSSL_SYS_WIN32
++    int i;
++# endif
++# ifdef SIGACTION
++    struct sigaction sa;
++
++    memset(&sa, 0, sizeof(sa));
++    sa.sa_handler = recsig;
++# endif
++
++# ifdef OPENSSL_SYS_WIN32
++    savsig[SIGABRT] = signal(SIGABRT, recsig);
++    savsig[SIGFPE] = signal(SIGFPE, recsig);
++    savsig[SIGILL] = signal(SIGILL, recsig);
++    savsig[SIGINT] = signal(SIGINT, recsig);
++    savsig[SIGSEGV] = signal(SIGSEGV, recsig);
++    savsig[SIGTERM] = signal(SIGTERM, recsig);
++# else
++    for (i = 1; i < NX509_SIG; i++) {
++#  ifdef SIGUSR1
++        if (i == SIGUSR1)
++            continue;
++#  endif
++#  ifdef SIGUSR2
++        if (i == SIGUSR2)
++            continue;
++#  endif
++#  ifdef SIGKILL
++        if (i == SIGKILL)       /* We can't make any action on that. */
++            continue;
++#  endif
++#  ifdef SIGACTION
++        sigaction(i, &sa, &savsig[i]);
++#  else
++        savsig[i] = signal(i, recsig);
++#  endif
++    }
++# endif
++
++# ifdef SIGWINCH
++    signal(SIGWINCH, SIG_DFL);
++# endif
++}
++
++static void popsig(void)
++{
++# ifdef OPENSSL_SYS_WIN32
++    signal(SIGABRT, savsig[SIGABRT]);
++    signal(SIGFPE, savsig[SIGFPE]);
++    signal(SIGILL, savsig[SIGILL]);
++    signal(SIGINT, savsig[SIGINT]);
++    signal(SIGSEGV, savsig[SIGSEGV]);
++    signal(SIGTERM, savsig[SIGTERM]);
++# else
++    int i;
++    for (i = 1; i < NX509_SIG; i++) {
++#  ifdef SIGUSR1
++        if (i == SIGUSR1)
++            continue;
++#  endif
++#  ifdef SIGUSR2
++        if (i == SIGUSR2)
++            continue;
++#  endif
++#  ifdef SIGACTION
++        sigaction(i, &savsig[i], NULL);
++#  else
++        signal(i, savsig[i]);
++#  endif
++    }
++# endif
++}
++
++static void recsig(int i)
++{
++    intr_signal = i;
++}
++#endif
++
++/* Internal functions specific for Windows */
++#if defined(OPENSSL_SYS_MSDOS) && !defined(_WIN32)
++static int noecho_fgets(char *buf, int size, FILE *tty)
++{
++    int i;
++    char *p;
++
++    p = buf;
++    for (;;) {
++        if (size == 0) {
++            *p = '\0';
++            break;
++        }
++        size--;
++# if defined(_WIN32)
++        i = _getch();
++# else
++        i = getch();
++# endif
++        if (i == '\r')
++            i = '\n';
++        *(p++) = i;
++        if (i == '\n') {
++            *p = '\0';
++            break;
++        }
++    }
++# ifdef WIN_CONSOLE_BUG
++    /*
++     * Win95 has several evil console bugs: one of these is that the last
++     * character read using getch() is passed to the next read: this is
++     * usually a CR so this can be trouble. No STDIO fix seems to work but
++     * flushing the console appears to do the trick.
++     */
++    {
++        HANDLE inh;
++        inh = GetStdHandle(STD_INPUT_HANDLE);
++        FlushConsoleInputBuffer(inh);
++    }
++# endif
++    return (strlen(buf));
++}
++#endif
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/ui/ui_util.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/ui/ui_util.c
+new file mode 100644
+index 0000000..3b51db9
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/ui/ui_util.c
+@@ -0,0 +1,51 @@
++/*
++ * Copyright 2002-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include "ui_locl.h"
++
++#ifndef BUFSIZ
++#define BUFSIZ 256
++#endif
++
++int UI_UTIL_read_pw_string(char *buf, int length, const char *prompt,
++                           int verify)
++{
++    char buff[BUFSIZ];
++    int ret;
++
++    ret =
++        UI_UTIL_read_pw(buf, buff, (length > BUFSIZ) ? BUFSIZ : length,
++                        prompt, verify);
++    OPENSSL_cleanse(buff, BUFSIZ);
++    return (ret);
++}
++
++int UI_UTIL_read_pw(char *buf, char *buff, int size, const char *prompt,
++                    int verify)
++{
++    int ok = 0;
++    UI *ui;
++
++    if (size < 1)
++        return -1;
++
++    ui = UI_new();
++    if (ui != NULL) {
++        ok = UI_add_input_string(ui, prompt, 0, buf, 0, size - 1);
++        if (ok >= 0 && verify)
++            ok = UI_add_verify_string(ui, prompt, 0, buff, 0, size - 1, buf);
++        if (ok >= 0)
++            ok = UI_process(ui);
++        UI_free(ui);
++    }
++    if (ok > 0)
++        ok = 0;
++    return (ok);
++}
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/uid.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/uid.c
+new file mode 100644
+index 0000000..12df8a4
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/uid.c
+@@ -0,0 +1,42 @@
++/*
++ * Copyright 2001-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include 
++#include 
++
++#if defined(__OpenBSD__) || (defined(__FreeBSD__) && __FreeBSD__ > 2)
++
++# include OPENSSL_UNISTD
++
++int OPENSSL_issetugid(void)
++{
++    return issetugid();
++}
++
++#elif defined(OPENSSL_SYS_WIN32) || defined(OPENSSL_SYS_VXWORKS)
++
++int OPENSSL_issetugid(void)
++{
++    return 0;
++}
++
++#else
++
++# include OPENSSL_UNISTD
++# include 
++
++int OPENSSL_issetugid(void)
++{
++    if (getuid() != geteuid())
++        return 1;
++    if (getgid() != getegid())
++        return 1;
++    return 0;
++}
++#endif
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/vms_rms.h b/CryptoPkg/Library/OpensslLib/openssl/crypto/vms_rms.h
+new file mode 100644
+index 0000000..3b994a0
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/vms_rms.h
+@@ -0,0 +1,58 @@
++/*
++ * Copyright 2011-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#ifdef NAML$C_MAXRSS
++
++# define CC_RMS_NAMX cc$rms_naml
++# define FAB_NAMX fab$l_naml
++# define FAB_OR_NAML( fab, naml) naml
++# define FAB_OR_NAML_DNA naml$l_long_defname
++# define FAB_OR_NAML_DNS naml$l_long_defname_size
++# define FAB_OR_NAML_FNA naml$l_long_filename
++# define FAB_OR_NAML_FNS naml$l_long_filename_size
++# define NAMX_ESA naml$l_long_expand
++# define NAMX_ESL naml$l_long_expand_size
++# define NAMX_ESS naml$l_long_expand_alloc
++# define NAMX_NOP naml$b_nop
++# define SET_NAMX_NO_SHORT_UPCASE( nam) nam.naml$v_no_short_upcase = 1
++
++# if __INITIAL_POINTER_SIZE == 64
++#  define NAMX_DNA_FNA_SET(fab) fab.fab$l_dna = (__char_ptr32) -1; \
++   fab.fab$l_fna = (__char_ptr32) -1;
++# else                          /* __INITIAL_POINTER_SIZE == 64 */
++#  define NAMX_DNA_FNA_SET(fab) fab.fab$l_dna = (char *) -1; \
++   fab.fab$l_fna = (char *) -1;
++# endif                         /* __INITIAL_POINTER_SIZE == 64 [else] */
++
++# define NAMX_MAXRSS NAML$C_MAXRSS
++# define NAMX_STRUCT NAML
++
++#else                           /* def NAML$C_MAXRSS */
++
++# define CC_RMS_NAMX cc$rms_nam
++# define FAB_NAMX fab$l_nam
++# define FAB_OR_NAML( fab, naml) fab
++# define FAB_OR_NAML_DNA fab$l_dna
++# define FAB_OR_NAML_DNS fab$b_dns
++# define FAB_OR_NAML_FNA fab$l_fna
++# define FAB_OR_NAML_FNS fab$b_fns
++# define NAMX_ESA nam$l_esa
++# define NAMX_ESL nam$b_esl
++# define NAMX_ESS nam$b_ess
++# define NAMX_NOP nam$b_nop
++# define NAMX_DNA_FNA_SET(fab)
++# define NAMX_MAXRSS NAM$C_MAXRSS
++# define NAMX_STRUCT NAM
++# ifdef NAM$M_NO_SHORT_UPCASE
++#  define SET_NAMX_NO_SHORT_UPCASE( nam) naml.naml$v_no_short_upcase = 1
++# else                          /* def NAM$M_NO_SHORT_UPCASE */
++#  define SET_NAMX_NO_SHORT_UPCASE( nam)
++# endif                         /* def NAM$M_NO_SHORT_UPCASE [else] */
++
++#endif                          /* def NAML$C_MAXRSS [else] */
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/whrlpool/asm/wp-mmx.pl b/CryptoPkg/Library/OpensslLib/openssl/crypto/whrlpool/asm/wp-mmx.pl
+new file mode 100644
+index 0000000..f63945c
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/whrlpool/asm/wp-mmx.pl
+@@ -0,0 +1,507 @@
++#! /usr/bin/env perl
++# Copyright 2005-2016 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
++# in the file LICENSE in the source distribution or at
++# https://www.openssl.org/source/license.html
++
++#
++# ====================================================================
++# Written by Andy Polyakov  for the OpenSSL
++# project. Rights for redistribution and usage in source and binary
++# forms are granted according to the OpenSSL license.
++# ====================================================================
++#
++# whirlpool_block_mmx implementation.
++#
++*SCALE=\(2); # 2 or 8, that is the question:-) Value of 8 results
++# in 16KB large table, which is tough on L1 cache, but eliminates
++# unaligned references to it. Value of 2 results in 4KB table, but
++# 7/8 of references to it are unaligned. AMD cores seem to be
++# allergic to the latter, while Intel ones - to former [see the
++# table]. I stick to value of 2 for two reasons: 1. smaller table
++# minimizes cache trashing and thus mitigates the hazard of side-
++# channel leakage similar to AES cache-timing one; 2. performance
++# gap among different µ-archs is smaller.
++#
++# Performance table lists rounded amounts of CPU cycles spent by
++# whirlpool_block_mmx routine on single 64 byte input block, i.e.
++# smaller is better and asymptotic throughput can be estimated by
++# multiplying 64 by CPU clock frequency and dividing by relevant
++# value from the given table:
++#
++#		$SCALE=2/8	icc8	gcc3	
++# Intel P4	3200/4600	4600(*)	6400
++# Intel PIII	2900/3000	4900	5400
++# AMD K[78]	2500/1800	9900	8200(**)
++#
++# (*)	I've sketched even non-MMX assembler, but for the record
++#	I've failed to beat the Intel compiler on P4, without using
++#	MMX that is...
++# (**)	... on AMD on the other hand non-MMX assembler was observed
++#	to perform significantly better, but I figured this MMX
++#	implementation is even faster anyway, so why bother? As for
++#	pre-MMX AMD core[s], the improvement coefficient is more
++#	than likely to vary anyway and I don't know how. But the
++#	least I know is that gcc-generated code compiled with
++#	-DL_ENDIAN and -DOPENSSL_SMALL_FOOTPRINT [see C module for
++#	details] and optimized for Pentium was observed to perform
++#	*better* on Pentium 100 than unrolled non-MMX assembler
++#	loop... So we just say that I don't know if maintaining
++#	non-MMX implementation would actually pay off, but till
++#	opposite is proved "unlikely" is assumed.
++
++$0 =~ m/(.*[\/\\])[^\/\\]+$/; $dir=$1;
++push(@INC,"${dir}","${dir}../../perlasm");
++require "x86asm.pl";
++
++$output=pop;
++open STDOUT,">$output";
++
++&asm_init($ARGV[0],"wp-mmx.pl");
++
++sub L()  { &data_byte(@_); }
++sub LL()
++{	if	($SCALE==2)	{ &data_byte(@_); &data_byte(@_); }
++	elsif	($SCALE==8)	{ for ($i=0;$i<8;$i++) {
++					&data_byte(@_);
++					unshift(@_,pop(@_));
++				  }
++				}
++	else			{ die "unvalid SCALE value"; }
++}
++
++sub scale()
++{	if	($SCALE==2)	{ &lea(@_[0],&DWP(0,@_[1],@_[1])); }
++	elsif	($SCALE==8)	{ &lea(@_[0],&DWP(0,"",@_[1],8));  }
++	else			{ die "unvalid SCALE value";       }
++}
++
++sub row()
++{	if	($SCALE==2)	{ ((8-shift)&7); }
++	elsif	($SCALE==8)	{ (8*shift);     }
++	else			{ die "unvalid SCALE value"; }
++}
++
++$tbl="ebp";
++@mm=("mm0","mm1","mm2","mm3","mm4","mm5","mm6","mm7");
++
++&function_begin_B("whirlpool_block_mmx");
++	&push	("ebp");
++	&push	("ebx");
++	&push	("esi");
++	&push	("edi");
++
++	&mov	("esi",&wparam(0));		# hash value
++	&mov	("edi",&wparam(1));		# input data stream
++	&mov	("ebp",&wparam(2));		# number of chunks in input
++
++	&mov	("eax","esp");			# copy stack pointer
++	&sub	("esp",128+20);			# allocate frame
++	&and	("esp",-64);			# align for cache-line
++
++	&lea	("ebx",&DWP(128,"esp"));
++	&mov	(&DWP(0,"ebx"),"esi");		# save parameter block
++	&mov	(&DWP(4,"ebx"),"edi");
++	&mov	(&DWP(8,"ebx"),"ebp");
++	&mov	(&DWP(16,"ebx"),"eax");		# saved stack pointer
++
++	&call	(&label("pic_point"));
++&set_label("pic_point");
++	&blindpop($tbl);
++	&lea	($tbl,&DWP(&label("table")."-".&label("pic_point"),$tbl));
++
++	&xor	("ecx","ecx");
++	&xor	("edx","edx");
++
++	for($i=0;$i<8;$i++) { &movq(@mm[$i],&QWP($i*8,"esi")); }    # L=H
++&set_label("outerloop");
++	for($i=0;$i<8;$i++) { &movq(&QWP($i*8,"esp"),@mm[$i]); }    # K=L
++	for($i=0;$i<8;$i++) { &pxor(@mm[$i],&QWP($i*8,"edi")); }    # L^=inp
++	for($i=0;$i<8;$i++) { &movq(&QWP(64+$i*8,"esp"),@mm[$i]); } # S=L
++
++	&xor	("esi","esi");
++	&mov	(&DWP(12,"ebx"),"esi");		# zero round counter
++
++&set_label("round",16);
++	&movq	(@mm[0],&QWP(2048*$SCALE,$tbl,"esi",8));	# rc[r]
++	&mov	("eax",&DWP(0,"esp"));
++	&mov	("ebx",&DWP(4,"esp"));
++	&movz	("ecx",&LB("eax"));
++	&movz	("edx",&HB("eax"));
++for($i=0;$i<8;$i++) {
++    my $func = ($i==0)? \&movq : \&pxor;
++	&shr	("eax",16);
++	&scale	("esi","ecx");
++	&movz	("ecx",&LB("eax"));
++	&scale	("edi","edx");
++	&movz	("edx",&HB("eax"));
++	&pxor	(@mm[0],&QWP(&row(0),$tbl,"esi",8));
++	&$func	(@mm[1],&QWP(&row(1),$tbl,"edi",8));
++	&mov	("eax",&DWP(($i+1)*8,"esp"));
++	&scale	("esi","ecx");
++	&movz	("ecx",&LB("ebx"));
++	&scale	("edi","edx");
++	&movz	("edx",&HB("ebx"));
++	&$func	(@mm[2],&QWP(&row(2),$tbl,"esi",8));
++	&$func	(@mm[3],&QWP(&row(3),$tbl,"edi",8));
++	&shr	("ebx",16);
++	&scale	("esi","ecx");
++	&movz	("ecx",&LB("ebx"));
++	&scale	("edi","edx");
++	&movz	("edx",&HB("ebx"));
++	&$func	(@mm[4],&QWP(&row(4),$tbl,"esi",8));
++	&$func	(@mm[5],&QWP(&row(5),$tbl,"edi",8));
++	&mov	("ebx",&DWP(($i+1)*8+4,"esp"));
++	&scale	("esi","ecx");
++	&movz	("ecx",&LB("eax"));
++	&scale	("edi","edx");
++	&movz	("edx",&HB("eax"));
++	&$func	(@mm[6],&QWP(&row(6),$tbl,"esi",8));
++	&$func	(@mm[7],&QWP(&row(7),$tbl,"edi",8));
++    push(@mm,shift(@mm));
++}
++
++	for($i=0;$i<8;$i++) { &movq(&QWP($i*8,"esp"),@mm[$i]); }    # K=L
++
++for($i=0;$i<8;$i++) {
++	&shr	("eax",16);
++	&scale	("esi","ecx");
++	&movz	("ecx",&LB("eax"));
++	&scale	("edi","edx");
++	&movz	("edx",&HB("eax"));
++	&pxor	(@mm[0],&QWP(&row(0),$tbl,"esi",8));
++	&pxor	(@mm[1],&QWP(&row(1),$tbl,"edi",8));
++	&mov	("eax",&DWP(64+($i+1)*8,"esp"))		if ($i<7);
++	&scale	("esi","ecx");
++	&movz	("ecx",&LB("ebx"));
++	&scale	("edi","edx");
++	&movz	("edx",&HB("ebx"));
++	&pxor	(@mm[2],&QWP(&row(2),$tbl,"esi",8));
++	&pxor	(@mm[3],&QWP(&row(3),$tbl,"edi",8));
++	&shr	("ebx",16);
++	&scale	("esi","ecx");
++	&movz	("ecx",&LB("ebx"));
++	&scale	("edi","edx");
++	&movz	("edx",&HB("ebx"));
++	&pxor	(@mm[4],&QWP(&row(4),$tbl,"esi",8));
++	&pxor	(@mm[5],&QWP(&row(5),$tbl,"edi",8));
++	&mov	("ebx",&DWP(64+($i+1)*8+4,"esp"))	if ($i<7);
++	&scale	("esi","ecx");
++	&movz	("ecx",&LB("eax"));
++	&scale	("edi","edx");
++	&movz	("edx",&HB("eax"));
++	&pxor	(@mm[6],&QWP(&row(6),$tbl,"esi",8));
++	&pxor	(@mm[7],&QWP(&row(7),$tbl,"edi",8));
++    push(@mm,shift(@mm));
++}
++	&lea	("ebx",&DWP(128,"esp"));
++	&mov	("esi",&DWP(12,"ebx"));		# pull round counter
++	&add	("esi",1);
++	&cmp	("esi",10);
++	&je	(&label("roundsdone"));
++
++	&mov	(&DWP(12,"ebx"),"esi");		# update round counter
++	for($i=0;$i<8;$i++) { &movq(&QWP(64+$i*8,"esp"),@mm[$i]); } # S=L
++	&jmp	(&label("round"));
++
++&set_label("roundsdone",16);
++	&mov	("esi",&DWP(0,"ebx"));		# reload argument block
++	&mov	("edi",&DWP(4,"ebx"));
++	&mov	("eax",&DWP(8,"ebx"));
++
++	for($i=0;$i<8;$i++) { &pxor(@mm[$i],&QWP($i*8,"edi")); }    # L^=inp
++	for($i=0;$i<8;$i++) { &pxor(@mm[$i],&QWP($i*8,"esi")); }    # L^=H
++	for($i=0;$i<8;$i++) { &movq(&QWP($i*8,"esi"),@mm[$i]); }    # H=L
++
++	&lea	("edi",&DWP(64,"edi"));		# inp+=64
++	&sub	("eax",1);			# num--
++	&jz	(&label("alldone"));
++	&mov	(&DWP(4,"ebx"),"edi");		# update argument block
++	&mov	(&DWP(8,"ebx"),"eax");
++	&jmp	(&label("outerloop"));
++
++&set_label("alldone");
++	&emms	();
++	&mov	("esp",&DWP(16,"ebx"));		# restore saved stack pointer
++	&pop	("edi");
++	&pop	("esi");
++	&pop	("ebx");
++	&pop	("ebp");
++	&ret	();
++
++&align(64);
++&set_label("table");
++	&LL(0x18,0x18,0x60,0x18,0xc0,0x78,0x30,0xd8);
++	&LL(0x23,0x23,0x8c,0x23,0x05,0xaf,0x46,0x26);
++	&LL(0xc6,0xc6,0x3f,0xc6,0x7e,0xf9,0x91,0xb8);
++	&LL(0xe8,0xe8,0x87,0xe8,0x13,0x6f,0xcd,0xfb);
++	&LL(0x87,0x87,0x26,0x87,0x4c,0xa1,0x13,0xcb);
++	&LL(0xb8,0xb8,0xda,0xb8,0xa9,0x62,0x6d,0x11);
++	&LL(0x01,0x01,0x04,0x01,0x08,0x05,0x02,0x09);
++	&LL(0x4f,0x4f,0x21,0x4f,0x42,0x6e,0x9e,0x0d);
++	&LL(0x36,0x36,0xd8,0x36,0xad,0xee,0x6c,0x9b);
++	&LL(0xa6,0xa6,0xa2,0xa6,0x59,0x04,0x51,0xff);
++	&LL(0xd2,0xd2,0x6f,0xd2,0xde,0xbd,0xb9,0x0c);
++	&LL(0xf5,0xf5,0xf3,0xf5,0xfb,0x06,0xf7,0x0e);
++	&LL(0x79,0x79,0xf9,0x79,0xef,0x80,0xf2,0x96);
++	&LL(0x6f,0x6f,0xa1,0x6f,0x5f,0xce,0xde,0x30);
++	&LL(0x91,0x91,0x7e,0x91,0xfc,0xef,0x3f,0x6d);
++	&LL(0x52,0x52,0x55,0x52,0xaa,0x07,0xa4,0xf8);
++	&LL(0x60,0x60,0x9d,0x60,0x27,0xfd,0xc0,0x47);
++	&LL(0xbc,0xbc,0xca,0xbc,0x89,0x76,0x65,0x35);
++	&LL(0x9b,0x9b,0x56,0x9b,0xac,0xcd,0x2b,0x37);
++	&LL(0x8e,0x8e,0x02,0x8e,0x04,0x8c,0x01,0x8a);
++	&LL(0xa3,0xa3,0xb6,0xa3,0x71,0x15,0x5b,0xd2);
++	&LL(0x0c,0x0c,0x30,0x0c,0x60,0x3c,0x18,0x6c);
++	&LL(0x7b,0x7b,0xf1,0x7b,0xff,0x8a,0xf6,0x84);
++	&LL(0x35,0x35,0xd4,0x35,0xb5,0xe1,0x6a,0x80);
++	&LL(0x1d,0x1d,0x74,0x1d,0xe8,0x69,0x3a,0xf5);
++	&LL(0xe0,0xe0,0xa7,0xe0,0x53,0x47,0xdd,0xb3);
++	&LL(0xd7,0xd7,0x7b,0xd7,0xf6,0xac,0xb3,0x21);
++	&LL(0xc2,0xc2,0x2f,0xc2,0x5e,0xed,0x99,0x9c);
++	&LL(0x2e,0x2e,0xb8,0x2e,0x6d,0x96,0x5c,0x43);
++	&LL(0x4b,0x4b,0x31,0x4b,0x62,0x7a,0x96,0x29);
++	&LL(0xfe,0xfe,0xdf,0xfe,0xa3,0x21,0xe1,0x5d);
++	&LL(0x57,0x57,0x41,0x57,0x82,0x16,0xae,0xd5);
++	&LL(0x15,0x15,0x54,0x15,0xa8,0x41,0x2a,0xbd);
++	&LL(0x77,0x77,0xc1,0x77,0x9f,0xb6,0xee,0xe8);
++	&LL(0x37,0x37,0xdc,0x37,0xa5,0xeb,0x6e,0x92);
++	&LL(0xe5,0xe5,0xb3,0xe5,0x7b,0x56,0xd7,0x9e);
++	&LL(0x9f,0x9f,0x46,0x9f,0x8c,0xd9,0x23,0x13);
++	&LL(0xf0,0xf0,0xe7,0xf0,0xd3,0x17,0xfd,0x23);
++	&LL(0x4a,0x4a,0x35,0x4a,0x6a,0x7f,0x94,0x20);
++	&LL(0xda,0xda,0x4f,0xda,0x9e,0x95,0xa9,0x44);
++	&LL(0x58,0x58,0x7d,0x58,0xfa,0x25,0xb0,0xa2);
++	&LL(0xc9,0xc9,0x03,0xc9,0x06,0xca,0x8f,0xcf);
++	&LL(0x29,0x29,0xa4,0x29,0x55,0x8d,0x52,0x7c);
++	&LL(0x0a,0x0a,0x28,0x0a,0x50,0x22,0x14,0x5a);
++	&LL(0xb1,0xb1,0xfe,0xb1,0xe1,0x4f,0x7f,0x50);
++	&LL(0xa0,0xa0,0xba,0xa0,0x69,0x1a,0x5d,0xc9);
++	&LL(0x6b,0x6b,0xb1,0x6b,0x7f,0xda,0xd6,0x14);
++	&LL(0x85,0x85,0x2e,0x85,0x5c,0xab,0x17,0xd9);
++	&LL(0xbd,0xbd,0xce,0xbd,0x81,0x73,0x67,0x3c);
++	&LL(0x5d,0x5d,0x69,0x5d,0xd2,0x34,0xba,0x8f);
++	&LL(0x10,0x10,0x40,0x10,0x80,0x50,0x20,0x90);
++	&LL(0xf4,0xf4,0xf7,0xf4,0xf3,0x03,0xf5,0x07);
++	&LL(0xcb,0xcb,0x0b,0xcb,0x16,0xc0,0x8b,0xdd);
++	&LL(0x3e,0x3e,0xf8,0x3e,0xed,0xc6,0x7c,0xd3);
++	&LL(0x05,0x05,0x14,0x05,0x28,0x11,0x0a,0x2d);
++	&LL(0x67,0x67,0x81,0x67,0x1f,0xe6,0xce,0x78);
++	&LL(0xe4,0xe4,0xb7,0xe4,0x73,0x53,0xd5,0x97);
++	&LL(0x27,0x27,0x9c,0x27,0x25,0xbb,0x4e,0x02);
++	&LL(0x41,0x41,0x19,0x41,0x32,0x58,0x82,0x73);
++	&LL(0x8b,0x8b,0x16,0x8b,0x2c,0x9d,0x0b,0xa7);
++	&LL(0xa7,0xa7,0xa6,0xa7,0x51,0x01,0x53,0xf6);
++	&LL(0x7d,0x7d,0xe9,0x7d,0xcf,0x94,0xfa,0xb2);
++	&LL(0x95,0x95,0x6e,0x95,0xdc,0xfb,0x37,0x49);
++	&LL(0xd8,0xd8,0x47,0xd8,0x8e,0x9f,0xad,0x56);
++	&LL(0xfb,0xfb,0xcb,0xfb,0x8b,0x30,0xeb,0x70);
++	&LL(0xee,0xee,0x9f,0xee,0x23,0x71,0xc1,0xcd);
++	&LL(0x7c,0x7c,0xed,0x7c,0xc7,0x91,0xf8,0xbb);
++	&LL(0x66,0x66,0x85,0x66,0x17,0xe3,0xcc,0x71);
++	&LL(0xdd,0xdd,0x53,0xdd,0xa6,0x8e,0xa7,0x7b);
++	&LL(0x17,0x17,0x5c,0x17,0xb8,0x4b,0x2e,0xaf);
++	&LL(0x47,0x47,0x01,0x47,0x02,0x46,0x8e,0x45);
++	&LL(0x9e,0x9e,0x42,0x9e,0x84,0xdc,0x21,0x1a);
++	&LL(0xca,0xca,0x0f,0xca,0x1e,0xc5,0x89,0xd4);
++	&LL(0x2d,0x2d,0xb4,0x2d,0x75,0x99,0x5a,0x58);
++	&LL(0xbf,0xbf,0xc6,0xbf,0x91,0x79,0x63,0x2e);
++	&LL(0x07,0x07,0x1c,0x07,0x38,0x1b,0x0e,0x3f);
++	&LL(0xad,0xad,0x8e,0xad,0x01,0x23,0x47,0xac);
++	&LL(0x5a,0x5a,0x75,0x5a,0xea,0x2f,0xb4,0xb0);
++	&LL(0x83,0x83,0x36,0x83,0x6c,0xb5,0x1b,0xef);
++	&LL(0x33,0x33,0xcc,0x33,0x85,0xff,0x66,0xb6);
++	&LL(0x63,0x63,0x91,0x63,0x3f,0xf2,0xc6,0x5c);
++	&LL(0x02,0x02,0x08,0x02,0x10,0x0a,0x04,0x12);
++	&LL(0xaa,0xaa,0x92,0xaa,0x39,0x38,0x49,0x93);
++	&LL(0x71,0x71,0xd9,0x71,0xaf,0xa8,0xe2,0xde);
++	&LL(0xc8,0xc8,0x07,0xc8,0x0e,0xcf,0x8d,0xc6);
++	&LL(0x19,0x19,0x64,0x19,0xc8,0x7d,0x32,0xd1);
++	&LL(0x49,0x49,0x39,0x49,0x72,0x70,0x92,0x3b);
++	&LL(0xd9,0xd9,0x43,0xd9,0x86,0x9a,0xaf,0x5f);
++	&LL(0xf2,0xf2,0xef,0xf2,0xc3,0x1d,0xf9,0x31);
++	&LL(0xe3,0xe3,0xab,0xe3,0x4b,0x48,0xdb,0xa8);
++	&LL(0x5b,0x5b,0x71,0x5b,0xe2,0x2a,0xb6,0xb9);
++	&LL(0x88,0x88,0x1a,0x88,0x34,0x92,0x0d,0xbc);
++	&LL(0x9a,0x9a,0x52,0x9a,0xa4,0xc8,0x29,0x3e);
++	&LL(0x26,0x26,0x98,0x26,0x2d,0xbe,0x4c,0x0b);
++	&LL(0x32,0x32,0xc8,0x32,0x8d,0xfa,0x64,0xbf);
++	&LL(0xb0,0xb0,0xfa,0xb0,0xe9,0x4a,0x7d,0x59);
++	&LL(0xe9,0xe9,0x83,0xe9,0x1b,0x6a,0xcf,0xf2);
++	&LL(0x0f,0x0f,0x3c,0x0f,0x78,0x33,0x1e,0x77);
++	&LL(0xd5,0xd5,0x73,0xd5,0xe6,0xa6,0xb7,0x33);
++	&LL(0x80,0x80,0x3a,0x80,0x74,0xba,0x1d,0xf4);
++	&LL(0xbe,0xbe,0xc2,0xbe,0x99,0x7c,0x61,0x27);
++	&LL(0xcd,0xcd,0x13,0xcd,0x26,0xde,0x87,0xeb);
++	&LL(0x34,0x34,0xd0,0x34,0xbd,0xe4,0x68,0x89);
++	&LL(0x48,0x48,0x3d,0x48,0x7a,0x75,0x90,0x32);
++	&LL(0xff,0xff,0xdb,0xff,0xab,0x24,0xe3,0x54);
++	&LL(0x7a,0x7a,0xf5,0x7a,0xf7,0x8f,0xf4,0x8d);
++	&LL(0x90,0x90,0x7a,0x90,0xf4,0xea,0x3d,0x64);
++	&LL(0x5f,0x5f,0x61,0x5f,0xc2,0x3e,0xbe,0x9d);
++	&LL(0x20,0x20,0x80,0x20,0x1d,0xa0,0x40,0x3d);
++	&LL(0x68,0x68,0xbd,0x68,0x67,0xd5,0xd0,0x0f);
++	&LL(0x1a,0x1a,0x68,0x1a,0xd0,0x72,0x34,0xca);
++	&LL(0xae,0xae,0x82,0xae,0x19,0x2c,0x41,0xb7);
++	&LL(0xb4,0xb4,0xea,0xb4,0xc9,0x5e,0x75,0x7d);
++	&LL(0x54,0x54,0x4d,0x54,0x9a,0x19,0xa8,0xce);
++	&LL(0x93,0x93,0x76,0x93,0xec,0xe5,0x3b,0x7f);
++	&LL(0x22,0x22,0x88,0x22,0x0d,0xaa,0x44,0x2f);
++	&LL(0x64,0x64,0x8d,0x64,0x07,0xe9,0xc8,0x63);
++	&LL(0xf1,0xf1,0xe3,0xf1,0xdb,0x12,0xff,0x2a);
++	&LL(0x73,0x73,0xd1,0x73,0xbf,0xa2,0xe6,0xcc);
++	&LL(0x12,0x12,0x48,0x12,0x90,0x5a,0x24,0x82);
++	&LL(0x40,0x40,0x1d,0x40,0x3a,0x5d,0x80,0x7a);
++	&LL(0x08,0x08,0x20,0x08,0x40,0x28,0x10,0x48);
++	&LL(0xc3,0xc3,0x2b,0xc3,0x56,0xe8,0x9b,0x95);
++	&LL(0xec,0xec,0x97,0xec,0x33,0x7b,0xc5,0xdf);
++	&LL(0xdb,0xdb,0x4b,0xdb,0x96,0x90,0xab,0x4d);
++	&LL(0xa1,0xa1,0xbe,0xa1,0x61,0x1f,0x5f,0xc0);
++	&LL(0x8d,0x8d,0x0e,0x8d,0x1c,0x83,0x07,0x91);
++	&LL(0x3d,0x3d,0xf4,0x3d,0xf5,0xc9,0x7a,0xc8);
++	&LL(0x97,0x97,0x66,0x97,0xcc,0xf1,0x33,0x5b);
++	&LL(0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00);
++	&LL(0xcf,0xcf,0x1b,0xcf,0x36,0xd4,0x83,0xf9);
++	&LL(0x2b,0x2b,0xac,0x2b,0x45,0x87,0x56,0x6e);
++	&LL(0x76,0x76,0xc5,0x76,0x97,0xb3,0xec,0xe1);
++	&LL(0x82,0x82,0x32,0x82,0x64,0xb0,0x19,0xe6);
++	&LL(0xd6,0xd6,0x7f,0xd6,0xfe,0xa9,0xb1,0x28);
++	&LL(0x1b,0x1b,0x6c,0x1b,0xd8,0x77,0x36,0xc3);
++	&LL(0xb5,0xb5,0xee,0xb5,0xc1,0x5b,0x77,0x74);
++	&LL(0xaf,0xaf,0x86,0xaf,0x11,0x29,0x43,0xbe);
++	&LL(0x6a,0x6a,0xb5,0x6a,0x77,0xdf,0xd4,0x1d);
++	&LL(0x50,0x50,0x5d,0x50,0xba,0x0d,0xa0,0xea);
++	&LL(0x45,0x45,0x09,0x45,0x12,0x4c,0x8a,0x57);
++	&LL(0xf3,0xf3,0xeb,0xf3,0xcb,0x18,0xfb,0x38);
++	&LL(0x30,0x30,0xc0,0x30,0x9d,0xf0,0x60,0xad);
++	&LL(0xef,0xef,0x9b,0xef,0x2b,0x74,0xc3,0xc4);
++	&LL(0x3f,0x3f,0xfc,0x3f,0xe5,0xc3,0x7e,0xda);
++	&LL(0x55,0x55,0x49,0x55,0x92,0x1c,0xaa,0xc7);
++	&LL(0xa2,0xa2,0xb2,0xa2,0x79,0x10,0x59,0xdb);
++	&LL(0xea,0xea,0x8f,0xea,0x03,0x65,0xc9,0xe9);
++	&LL(0x65,0x65,0x89,0x65,0x0f,0xec,0xca,0x6a);
++	&LL(0xba,0xba,0xd2,0xba,0xb9,0x68,0x69,0x03);
++	&LL(0x2f,0x2f,0xbc,0x2f,0x65,0x93,0x5e,0x4a);
++	&LL(0xc0,0xc0,0x27,0xc0,0x4e,0xe7,0x9d,0x8e);
++	&LL(0xde,0xde,0x5f,0xde,0xbe,0x81,0xa1,0x60);
++	&LL(0x1c,0x1c,0x70,0x1c,0xe0,0x6c,0x38,0xfc);
++	&LL(0xfd,0xfd,0xd3,0xfd,0xbb,0x2e,0xe7,0x46);
++	&LL(0x4d,0x4d,0x29,0x4d,0x52,0x64,0x9a,0x1f);
++	&LL(0x92,0x92,0x72,0x92,0xe4,0xe0,0x39,0x76);
++	&LL(0x75,0x75,0xc9,0x75,0x8f,0xbc,0xea,0xfa);
++	&LL(0x06,0x06,0x18,0x06,0x30,0x1e,0x0c,0x36);
++	&LL(0x8a,0x8a,0x12,0x8a,0x24,0x98,0x09,0xae);
++	&LL(0xb2,0xb2,0xf2,0xb2,0xf9,0x40,0x79,0x4b);
++	&LL(0xe6,0xe6,0xbf,0xe6,0x63,0x59,0xd1,0x85);
++	&LL(0x0e,0x0e,0x38,0x0e,0x70,0x36,0x1c,0x7e);
++	&LL(0x1f,0x1f,0x7c,0x1f,0xf8,0x63,0x3e,0xe7);
++	&LL(0x62,0x62,0x95,0x62,0x37,0xf7,0xc4,0x55);
++	&LL(0xd4,0xd4,0x77,0xd4,0xee,0xa3,0xb5,0x3a);
++	&LL(0xa8,0xa8,0x9a,0xa8,0x29,0x32,0x4d,0x81);
++	&LL(0x96,0x96,0x62,0x96,0xc4,0xf4,0x31,0x52);
++	&LL(0xf9,0xf9,0xc3,0xf9,0x9b,0x3a,0xef,0x62);
++	&LL(0xc5,0xc5,0x33,0xc5,0x66,0xf6,0x97,0xa3);
++	&LL(0x25,0x25,0x94,0x25,0x35,0xb1,0x4a,0x10);
++	&LL(0x59,0x59,0x79,0x59,0xf2,0x20,0xb2,0xab);
++	&LL(0x84,0x84,0x2a,0x84,0x54,0xae,0x15,0xd0);
++	&LL(0x72,0x72,0xd5,0x72,0xb7,0xa7,0xe4,0xc5);
++	&LL(0x39,0x39,0xe4,0x39,0xd5,0xdd,0x72,0xec);
++	&LL(0x4c,0x4c,0x2d,0x4c,0x5a,0x61,0x98,0x16);
++	&LL(0x5e,0x5e,0x65,0x5e,0xca,0x3b,0xbc,0x94);
++	&LL(0x78,0x78,0xfd,0x78,0xe7,0x85,0xf0,0x9f);
++	&LL(0x38,0x38,0xe0,0x38,0xdd,0xd8,0x70,0xe5);
++	&LL(0x8c,0x8c,0x0a,0x8c,0x14,0x86,0x05,0x98);
++	&LL(0xd1,0xd1,0x63,0xd1,0xc6,0xb2,0xbf,0x17);
++	&LL(0xa5,0xa5,0xae,0xa5,0x41,0x0b,0x57,0xe4);
++	&LL(0xe2,0xe2,0xaf,0xe2,0x43,0x4d,0xd9,0xa1);
++	&LL(0x61,0x61,0x99,0x61,0x2f,0xf8,0xc2,0x4e);
++	&LL(0xb3,0xb3,0xf6,0xb3,0xf1,0x45,0x7b,0x42);
++	&LL(0x21,0x21,0x84,0x21,0x15,0xa5,0x42,0x34);
++	&LL(0x9c,0x9c,0x4a,0x9c,0x94,0xd6,0x25,0x08);
++	&LL(0x1e,0x1e,0x78,0x1e,0xf0,0x66,0x3c,0xee);
++	&LL(0x43,0x43,0x11,0x43,0x22,0x52,0x86,0x61);
++	&LL(0xc7,0xc7,0x3b,0xc7,0x76,0xfc,0x93,0xb1);
++	&LL(0xfc,0xfc,0xd7,0xfc,0xb3,0x2b,0xe5,0x4f);
++	&LL(0x04,0x04,0x10,0x04,0x20,0x14,0x08,0x24);
++	&LL(0x51,0x51,0x59,0x51,0xb2,0x08,0xa2,0xe3);
++	&LL(0x99,0x99,0x5e,0x99,0xbc,0xc7,0x2f,0x25);
++	&LL(0x6d,0x6d,0xa9,0x6d,0x4f,0xc4,0xda,0x22);
++	&LL(0x0d,0x0d,0x34,0x0d,0x68,0x39,0x1a,0x65);
++	&LL(0xfa,0xfa,0xcf,0xfa,0x83,0x35,0xe9,0x79);
++	&LL(0xdf,0xdf,0x5b,0xdf,0xb6,0x84,0xa3,0x69);
++	&LL(0x7e,0x7e,0xe5,0x7e,0xd7,0x9b,0xfc,0xa9);
++	&LL(0x24,0x24,0x90,0x24,0x3d,0xb4,0x48,0x19);
++	&LL(0x3b,0x3b,0xec,0x3b,0xc5,0xd7,0x76,0xfe);
++	&LL(0xab,0xab,0x96,0xab,0x31,0x3d,0x4b,0x9a);
++	&LL(0xce,0xce,0x1f,0xce,0x3e,0xd1,0x81,0xf0);
++	&LL(0x11,0x11,0x44,0x11,0x88,0x55,0x22,0x99);
++	&LL(0x8f,0x8f,0x06,0x8f,0x0c,0x89,0x03,0x83);
++	&LL(0x4e,0x4e,0x25,0x4e,0x4a,0x6b,0x9c,0x04);
++	&LL(0xb7,0xb7,0xe6,0xb7,0xd1,0x51,0x73,0x66);
++	&LL(0xeb,0xeb,0x8b,0xeb,0x0b,0x60,0xcb,0xe0);
++	&LL(0x3c,0x3c,0xf0,0x3c,0xfd,0xcc,0x78,0xc1);
++	&LL(0x81,0x81,0x3e,0x81,0x7c,0xbf,0x1f,0xfd);
++	&LL(0x94,0x94,0x6a,0x94,0xd4,0xfe,0x35,0x40);
++	&LL(0xf7,0xf7,0xfb,0xf7,0xeb,0x0c,0xf3,0x1c);
++	&LL(0xb9,0xb9,0xde,0xb9,0xa1,0x67,0x6f,0x18);
++	&LL(0x13,0x13,0x4c,0x13,0x98,0x5f,0x26,0x8b);
++	&LL(0x2c,0x2c,0xb0,0x2c,0x7d,0x9c,0x58,0x51);
++	&LL(0xd3,0xd3,0x6b,0xd3,0xd6,0xb8,0xbb,0x05);
++	&LL(0xe7,0xe7,0xbb,0xe7,0x6b,0x5c,0xd3,0x8c);
++	&LL(0x6e,0x6e,0xa5,0x6e,0x57,0xcb,0xdc,0x39);
++	&LL(0xc4,0xc4,0x37,0xc4,0x6e,0xf3,0x95,0xaa);
++	&LL(0x03,0x03,0x0c,0x03,0x18,0x0f,0x06,0x1b);
++	&LL(0x56,0x56,0x45,0x56,0x8a,0x13,0xac,0xdc);
++	&LL(0x44,0x44,0x0d,0x44,0x1a,0x49,0x88,0x5e);
++	&LL(0x7f,0x7f,0xe1,0x7f,0xdf,0x9e,0xfe,0xa0);
++	&LL(0xa9,0xa9,0x9e,0xa9,0x21,0x37,0x4f,0x88);
++	&LL(0x2a,0x2a,0xa8,0x2a,0x4d,0x82,0x54,0x67);
++	&LL(0xbb,0xbb,0xd6,0xbb,0xb1,0x6d,0x6b,0x0a);
++	&LL(0xc1,0xc1,0x23,0xc1,0x46,0xe2,0x9f,0x87);
++	&LL(0x53,0x53,0x51,0x53,0xa2,0x02,0xa6,0xf1);
++	&LL(0xdc,0xdc,0x57,0xdc,0xae,0x8b,0xa5,0x72);
++	&LL(0x0b,0x0b,0x2c,0x0b,0x58,0x27,0x16,0x53);
++	&LL(0x9d,0x9d,0x4e,0x9d,0x9c,0xd3,0x27,0x01);
++	&LL(0x6c,0x6c,0xad,0x6c,0x47,0xc1,0xd8,0x2b);
++	&LL(0x31,0x31,0xc4,0x31,0x95,0xf5,0x62,0xa4);
++	&LL(0x74,0x74,0xcd,0x74,0x87,0xb9,0xe8,0xf3);
++	&LL(0xf6,0xf6,0xff,0xf6,0xe3,0x09,0xf1,0x15);
++	&LL(0x46,0x46,0x05,0x46,0x0a,0x43,0x8c,0x4c);
++	&LL(0xac,0xac,0x8a,0xac,0x09,0x26,0x45,0xa5);
++	&LL(0x89,0x89,0x1e,0x89,0x3c,0x97,0x0f,0xb5);
++	&LL(0x14,0x14,0x50,0x14,0xa0,0x44,0x28,0xb4);
++	&LL(0xe1,0xe1,0xa3,0xe1,0x5b,0x42,0xdf,0xba);
++	&LL(0x16,0x16,0x58,0x16,0xb0,0x4e,0x2c,0xa6);
++	&LL(0x3a,0x3a,0xe8,0x3a,0xcd,0xd2,0x74,0xf7);
++	&LL(0x69,0x69,0xb9,0x69,0x6f,0xd0,0xd2,0x06);
++	&LL(0x09,0x09,0x24,0x09,0x48,0x2d,0x12,0x41);
++	&LL(0x70,0x70,0xdd,0x70,0xa7,0xad,0xe0,0xd7);
++	&LL(0xb6,0xb6,0xe2,0xb6,0xd9,0x54,0x71,0x6f);
++	&LL(0xd0,0xd0,0x67,0xd0,0xce,0xb7,0xbd,0x1e);
++	&LL(0xed,0xed,0x93,0xed,0x3b,0x7e,0xc7,0xd6);
++	&LL(0xcc,0xcc,0x17,0xcc,0x2e,0xdb,0x85,0xe2);
++	&LL(0x42,0x42,0x15,0x42,0x2a,0x57,0x84,0x68);
++	&LL(0x98,0x98,0x5a,0x98,0xb4,0xc2,0x2d,0x2c);
++	&LL(0xa4,0xa4,0xaa,0xa4,0x49,0x0e,0x55,0xed);
++	&LL(0x28,0x28,0xa0,0x28,0x5d,0x88,0x50,0x75);
++	&LL(0x5c,0x5c,0x6d,0x5c,0xda,0x31,0xb8,0x86);
++	&LL(0xf8,0xf8,0xc7,0xf8,0x93,0x3f,0xed,0x6b);
++	&LL(0x86,0x86,0x22,0x86,0x44,0xa4,0x11,0xc2);
++
++	&L(0x18,0x23,0xc6,0xe8,0x87,0xb8,0x01,0x4f);	# rc[ROUNDS]
++	&L(0x36,0xa6,0xd2,0xf5,0x79,0x6f,0x91,0x52);
++	&L(0x60,0xbc,0x9b,0x8e,0xa3,0x0c,0x7b,0x35);
++	&L(0x1d,0xe0,0xd7,0xc2,0x2e,0x4b,0xfe,0x57);
++	&L(0x15,0x77,0x37,0xe5,0x9f,0xf0,0x4a,0xda);
++	&L(0x58,0xc9,0x29,0x0a,0xb1,0xa0,0x6b,0x85);
++	&L(0xbd,0x5d,0x10,0xf4,0xcb,0x3e,0x05,0x67);
++	&L(0xe4,0x27,0x41,0x8b,0xa7,0x7d,0x95,0xd8);
++	&L(0xfb,0xee,0x7c,0x66,0xdd,0x17,0x47,0x9e);
++	&L(0xca,0x2d,0xbf,0x07,0xad,0x5a,0x83,0x33);
++
++&function_end_B("whirlpool_block_mmx");
++&asm_finish(); 
++
++close STDOUT;
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/whrlpool/asm/wp-x86_64.pl b/CryptoPkg/Library/OpensslLib/openssl/crypto/whrlpool/asm/wp-x86_64.pl
+new file mode 100644
+index 0000000..c0b21d1
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/whrlpool/asm/wp-x86_64.pl
+@@ -0,0 +1,600 @@
++#! /usr/bin/env perl
++# Copyright 2005-2016 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
++# in the file LICENSE in the source distribution or at
++# https://www.openssl.org/source/license.html
++
++#
++# ====================================================================
++# Written by Andy Polyakov  for the OpenSSL
++# project. Rights for redistribution and usage in source and binary
++# forms are granted according to the OpenSSL license.
++# ====================================================================
++#
++# whirlpool_block for x86_64.
++#
++# 2500 cycles per 64-byte input block on AMD64, which is *identical*
++# to 32-bit MMX version executed on same CPU. So why did I bother?
++# Well, it's faster than gcc 3.3.2 generated code by over 50%, and
++# over 80% faster than PathScale 1.4, an "ambitious" commercial
++# compiler. Furthermore it surpasses gcc 3.4.3 by 170% and Sun Studio
++# 10 - by 360%[!]... What is it with x86_64 compilers? It's not the
++# first example when they fail to generate more optimal code, when
++# I believe they had *all* chances to...
++#
++# Note that register and stack frame layout are virtually identical
++# to 32-bit MMX version, except that %r8-15 are used instead of
++# %mm0-8. You can even notice that K[i] and S[i] are loaded to
++# %eax:%ebx as pair of 32-bit values and not as single 64-bit one.
++# This is done in order to avoid 64-bit shift penalties on Intel
++# EM64T core. Speaking of which! I bet it's possible to improve
++# Opteron performance by compressing the table to 2KB and replacing
++# unaligned references with complementary rotations [which would
++# incidentally replace lea instructions], but it would definitely
++# just "kill" EM64T, because it has only 1 shifter/rotator [against
++# 3 on Opteron] and which is *unacceptably* slow with 64-bit
++# operand.
++
++$flavour = shift;
++$output  = shift;
++if ($flavour =~ /\./) { $output = $flavour; undef $flavour; }
++
++$win64=0; $win64=1 if ($flavour =~ /[nm]asm|mingw64/ || $output =~ /\.asm$/);
++
++$0 =~ m/(.*[\/\\])[^\/\\]+$/; my $dir=$1; my $xlate;
++( $xlate="${dir}x86_64-xlate.pl" and -f $xlate ) or
++( $xlate="${dir}../../perlasm/x86_64-xlate.pl" and -f $xlate) or
++die "can't locate x86_64-xlate.pl";
++
++open OUT,"| \"$^X\" \"$xlate\" $flavour \"$output\"";
++*STDOUT=*OUT;
++
++sub L() { $code.=".byte	".join(',',@_)."\n"; }
++sub LL(){ $code.=".byte	".join(',',@_).",".join(',',@_)."\n"; }
++
++@mm=("%r8","%r9","%r10","%r11","%r12","%r13","%r14","%r15");
++
++$func="whirlpool_block";
++$table=".Ltable";
++
++$code=<<___;
++.text
++
++.globl	$func
++.type	$func,\@function,3
++.align	16
++$func:
++	push	%rbx
++	push	%rbp
++	push	%r12
++	push	%r13
++	push	%r14
++	push	%r15
++
++	mov	%rsp,%r11
++	sub	\$128+40,%rsp
++	and	\$-64,%rsp
++
++	lea	128(%rsp),%r10
++	mov	%rdi,0(%r10)		# save parameter block
++	mov	%rsi,8(%r10)
++	mov	%rdx,16(%r10)
++	mov	%r11,32(%r10)		# saved stack pointer
++.Lprologue:
++
++	mov	%r10,%rbx
++	lea	$table(%rip),%rbp
++
++	xor	%rcx,%rcx
++	xor	%rdx,%rdx
++___
++for($i=0;$i<8;$i++) { $code.="mov $i*8(%rdi),@mm[$i]\n"; }	# L=H
++$code.=".Louterloop:\n";
++for($i=0;$i<8;$i++) { $code.="mov @mm[$i],$i*8(%rsp)\n"; }	# K=L
++for($i=0;$i<8;$i++) { $code.="xor $i*8(%rsi),@mm[$i]\n"; }	# L^=inp
++for($i=0;$i<8;$i++) { $code.="mov @mm[$i],64+$i*8(%rsp)\n"; }	# S=L
++$code.=<<___;
++	xor	%rsi,%rsi
++	mov	%rsi,24(%rbx)		# zero round counter
++	jmp	.Lround
++.align	16
++.Lround:
++	mov	4096(%rbp,%rsi,8),@mm[0]	# rc[r]
++	mov	0(%rsp),%eax
++	mov	4(%rsp),%ebx
++	movz	%al,%ecx
++	movz	%ah,%edx
++___
++for($i=0;$i<8;$i++) {
++    my $func = ($i==0)? "mov" : "xor";
++    $code.=<<___;
++	shr	\$16,%eax
++	lea	(%rcx,%rcx),%rsi
++	movz	%al,%ecx
++	lea	(%rdx,%rdx),%rdi
++	movz	%ah,%edx
++	xor	0(%rbp,%rsi,8),@mm[0]
++	$func	7(%rbp,%rdi,8),@mm[1]
++	mov	$i*8+8(%rsp),%eax		# ($i+1)*8
++	lea	(%rcx,%rcx),%rsi
++	movz	%bl,%ecx
++	lea	(%rdx,%rdx),%rdi
++	movz	%bh,%edx
++	$func	6(%rbp,%rsi,8),@mm[2]
++	$func	5(%rbp,%rdi,8),@mm[3]
++	shr	\$16,%ebx
++	lea	(%rcx,%rcx),%rsi
++	movz	%bl,%ecx
++	lea	(%rdx,%rdx),%rdi
++	movz	%bh,%edx
++	$func	4(%rbp,%rsi,8),@mm[4]
++	$func	3(%rbp,%rdi,8),@mm[5]
++	mov	$i*8+8+4(%rsp),%ebx		# ($i+1)*8+4
++	lea	(%rcx,%rcx),%rsi
++	movz	%al,%ecx
++	lea	(%rdx,%rdx),%rdi
++	movz	%ah,%edx
++	$func	2(%rbp,%rsi,8),@mm[6]
++	$func	1(%rbp,%rdi,8),@mm[7]
++___
++    push(@mm,shift(@mm));
++}
++for($i=0;$i<8;$i++) { $code.="mov @mm[$i],$i*8(%rsp)\n"; }	# K=L
++for($i=0;$i<8;$i++) {
++    $code.=<<___;
++	shr	\$16,%eax
++	lea	(%rcx,%rcx),%rsi
++	movz	%al,%ecx
++	lea	(%rdx,%rdx),%rdi
++	movz	%ah,%edx
++	xor	0(%rbp,%rsi,8),@mm[0]
++	xor	7(%rbp,%rdi,8),@mm[1]
++	`"mov	64+$i*8+8(%rsp),%eax"	if($i<7);`	# 64+($i+1)*8
++	lea	(%rcx,%rcx),%rsi
++	movz	%bl,%ecx
++	lea	(%rdx,%rdx),%rdi
++	movz	%bh,%edx
++	xor	6(%rbp,%rsi,8),@mm[2]
++	xor	5(%rbp,%rdi,8),@mm[3]
++	shr	\$16,%ebx
++	lea	(%rcx,%rcx),%rsi
++	movz	%bl,%ecx
++	lea	(%rdx,%rdx),%rdi
++	movz	%bh,%edx
++	xor	4(%rbp,%rsi,8),@mm[4]
++	xor	3(%rbp,%rdi,8),@mm[5]
++	`"mov	64+$i*8+8+4(%rsp),%ebx"	if($i<7);`	# 64+($i+1)*8+4
++	lea	(%rcx,%rcx),%rsi
++	movz	%al,%ecx
++	lea	(%rdx,%rdx),%rdi
++	movz	%ah,%edx
++	xor	2(%rbp,%rsi,8),@mm[6]
++	xor	1(%rbp,%rdi,8),@mm[7]
++___
++    push(@mm,shift(@mm));
++}
++$code.=<<___;
++	lea	128(%rsp),%rbx
++	mov	24(%rbx),%rsi		# pull round counter
++	add	\$1,%rsi
++	cmp	\$10,%rsi
++	je	.Lroundsdone
++
++	mov	%rsi,24(%rbx)		# update round counter
++___
++for($i=0;$i<8;$i++) { $code.="mov @mm[$i],64+$i*8(%rsp)\n"; }	# S=L
++$code.=<<___;
++	jmp	.Lround
++.align	16
++.Lroundsdone:
++	mov	0(%rbx),%rdi		# reload argument block
++	mov	8(%rbx),%rsi
++	mov	16(%rbx),%rax
++___
++for($i=0;$i<8;$i++) { $code.="xor $i*8(%rsi),@mm[$i]\n"; }	# L^=inp
++for($i=0;$i<8;$i++) { $code.="xor $i*8(%rdi),@mm[$i]\n"; }	# L^=H
++for($i=0;$i<8;$i++) { $code.="mov @mm[$i],$i*8(%rdi)\n"; }	# H=L
++$code.=<<___;
++	lea	64(%rsi),%rsi		# inp+=64
++	sub	\$1,%rax		# num--
++	jz	.Lalldone
++	mov	%rsi,8(%rbx)		# update parameter block
++	mov	%rax,16(%rbx)
++	jmp	.Louterloop
++.Lalldone:
++	mov	32(%rbx),%rsi		# restore saved pointer
++	mov	(%rsi),%r15
++	mov	8(%rsi),%r14
++	mov	16(%rsi),%r13
++	mov	24(%rsi),%r12
++	mov	32(%rsi),%rbp
++	mov	40(%rsi),%rbx
++	lea	48(%rsi),%rsp
++.Lepilogue:
++	ret
++.size	$func,.-$func
++
++.align	64
++.type	$table,\@object
++$table:
++___
++	&LL(0x18,0x18,0x60,0x18,0xc0,0x78,0x30,0xd8);
++	&LL(0x23,0x23,0x8c,0x23,0x05,0xaf,0x46,0x26);
++	&LL(0xc6,0xc6,0x3f,0xc6,0x7e,0xf9,0x91,0xb8);
++	&LL(0xe8,0xe8,0x87,0xe8,0x13,0x6f,0xcd,0xfb);
++	&LL(0x87,0x87,0x26,0x87,0x4c,0xa1,0x13,0xcb);
++	&LL(0xb8,0xb8,0xda,0xb8,0xa9,0x62,0x6d,0x11);
++	&LL(0x01,0x01,0x04,0x01,0x08,0x05,0x02,0x09);
++	&LL(0x4f,0x4f,0x21,0x4f,0x42,0x6e,0x9e,0x0d);
++	&LL(0x36,0x36,0xd8,0x36,0xad,0xee,0x6c,0x9b);
++	&LL(0xa6,0xa6,0xa2,0xa6,0x59,0x04,0x51,0xff);
++	&LL(0xd2,0xd2,0x6f,0xd2,0xde,0xbd,0xb9,0x0c);
++	&LL(0xf5,0xf5,0xf3,0xf5,0xfb,0x06,0xf7,0x0e);
++	&LL(0x79,0x79,0xf9,0x79,0xef,0x80,0xf2,0x96);
++	&LL(0x6f,0x6f,0xa1,0x6f,0x5f,0xce,0xde,0x30);
++	&LL(0x91,0x91,0x7e,0x91,0xfc,0xef,0x3f,0x6d);
++	&LL(0x52,0x52,0x55,0x52,0xaa,0x07,0xa4,0xf8);
++	&LL(0x60,0x60,0x9d,0x60,0x27,0xfd,0xc0,0x47);
++	&LL(0xbc,0xbc,0xca,0xbc,0x89,0x76,0x65,0x35);
++	&LL(0x9b,0x9b,0x56,0x9b,0xac,0xcd,0x2b,0x37);
++	&LL(0x8e,0x8e,0x02,0x8e,0x04,0x8c,0x01,0x8a);
++	&LL(0xa3,0xa3,0xb6,0xa3,0x71,0x15,0x5b,0xd2);
++	&LL(0x0c,0x0c,0x30,0x0c,0x60,0x3c,0x18,0x6c);
++	&LL(0x7b,0x7b,0xf1,0x7b,0xff,0x8a,0xf6,0x84);
++	&LL(0x35,0x35,0xd4,0x35,0xb5,0xe1,0x6a,0x80);
++	&LL(0x1d,0x1d,0x74,0x1d,0xe8,0x69,0x3a,0xf5);
++	&LL(0xe0,0xe0,0xa7,0xe0,0x53,0x47,0xdd,0xb3);
++	&LL(0xd7,0xd7,0x7b,0xd7,0xf6,0xac,0xb3,0x21);
++	&LL(0xc2,0xc2,0x2f,0xc2,0x5e,0xed,0x99,0x9c);
++	&LL(0x2e,0x2e,0xb8,0x2e,0x6d,0x96,0x5c,0x43);
++	&LL(0x4b,0x4b,0x31,0x4b,0x62,0x7a,0x96,0x29);
++	&LL(0xfe,0xfe,0xdf,0xfe,0xa3,0x21,0xe1,0x5d);
++	&LL(0x57,0x57,0x41,0x57,0x82,0x16,0xae,0xd5);
++	&LL(0x15,0x15,0x54,0x15,0xa8,0x41,0x2a,0xbd);
++	&LL(0x77,0x77,0xc1,0x77,0x9f,0xb6,0xee,0xe8);
++	&LL(0x37,0x37,0xdc,0x37,0xa5,0xeb,0x6e,0x92);
++	&LL(0xe5,0xe5,0xb3,0xe5,0x7b,0x56,0xd7,0x9e);
++	&LL(0x9f,0x9f,0x46,0x9f,0x8c,0xd9,0x23,0x13);
++	&LL(0xf0,0xf0,0xe7,0xf0,0xd3,0x17,0xfd,0x23);
++	&LL(0x4a,0x4a,0x35,0x4a,0x6a,0x7f,0x94,0x20);
++	&LL(0xda,0xda,0x4f,0xda,0x9e,0x95,0xa9,0x44);
++	&LL(0x58,0x58,0x7d,0x58,0xfa,0x25,0xb0,0xa2);
++	&LL(0xc9,0xc9,0x03,0xc9,0x06,0xca,0x8f,0xcf);
++	&LL(0x29,0x29,0xa4,0x29,0x55,0x8d,0x52,0x7c);
++	&LL(0x0a,0x0a,0x28,0x0a,0x50,0x22,0x14,0x5a);
++	&LL(0xb1,0xb1,0xfe,0xb1,0xe1,0x4f,0x7f,0x50);
++	&LL(0xa0,0xa0,0xba,0xa0,0x69,0x1a,0x5d,0xc9);
++	&LL(0x6b,0x6b,0xb1,0x6b,0x7f,0xda,0xd6,0x14);
++	&LL(0x85,0x85,0x2e,0x85,0x5c,0xab,0x17,0xd9);
++	&LL(0xbd,0xbd,0xce,0xbd,0x81,0x73,0x67,0x3c);
++	&LL(0x5d,0x5d,0x69,0x5d,0xd2,0x34,0xba,0x8f);
++	&LL(0x10,0x10,0x40,0x10,0x80,0x50,0x20,0x90);
++	&LL(0xf4,0xf4,0xf7,0xf4,0xf3,0x03,0xf5,0x07);
++	&LL(0xcb,0xcb,0x0b,0xcb,0x16,0xc0,0x8b,0xdd);
++	&LL(0x3e,0x3e,0xf8,0x3e,0xed,0xc6,0x7c,0xd3);
++	&LL(0x05,0x05,0x14,0x05,0x28,0x11,0x0a,0x2d);
++	&LL(0x67,0x67,0x81,0x67,0x1f,0xe6,0xce,0x78);
++	&LL(0xe4,0xe4,0xb7,0xe4,0x73,0x53,0xd5,0x97);
++	&LL(0x27,0x27,0x9c,0x27,0x25,0xbb,0x4e,0x02);
++	&LL(0x41,0x41,0x19,0x41,0x32,0x58,0x82,0x73);
++	&LL(0x8b,0x8b,0x16,0x8b,0x2c,0x9d,0x0b,0xa7);
++	&LL(0xa7,0xa7,0xa6,0xa7,0x51,0x01,0x53,0xf6);
++	&LL(0x7d,0x7d,0xe9,0x7d,0xcf,0x94,0xfa,0xb2);
++	&LL(0x95,0x95,0x6e,0x95,0xdc,0xfb,0x37,0x49);
++	&LL(0xd8,0xd8,0x47,0xd8,0x8e,0x9f,0xad,0x56);
++	&LL(0xfb,0xfb,0xcb,0xfb,0x8b,0x30,0xeb,0x70);
++	&LL(0xee,0xee,0x9f,0xee,0x23,0x71,0xc1,0xcd);
++	&LL(0x7c,0x7c,0xed,0x7c,0xc7,0x91,0xf8,0xbb);
++	&LL(0x66,0x66,0x85,0x66,0x17,0xe3,0xcc,0x71);
++	&LL(0xdd,0xdd,0x53,0xdd,0xa6,0x8e,0xa7,0x7b);
++	&LL(0x17,0x17,0x5c,0x17,0xb8,0x4b,0x2e,0xaf);
++	&LL(0x47,0x47,0x01,0x47,0x02,0x46,0x8e,0x45);
++	&LL(0x9e,0x9e,0x42,0x9e,0x84,0xdc,0x21,0x1a);
++	&LL(0xca,0xca,0x0f,0xca,0x1e,0xc5,0x89,0xd4);
++	&LL(0x2d,0x2d,0xb4,0x2d,0x75,0x99,0x5a,0x58);
++	&LL(0xbf,0xbf,0xc6,0xbf,0x91,0x79,0x63,0x2e);
++	&LL(0x07,0x07,0x1c,0x07,0x38,0x1b,0x0e,0x3f);
++	&LL(0xad,0xad,0x8e,0xad,0x01,0x23,0x47,0xac);
++	&LL(0x5a,0x5a,0x75,0x5a,0xea,0x2f,0xb4,0xb0);
++	&LL(0x83,0x83,0x36,0x83,0x6c,0xb5,0x1b,0xef);
++	&LL(0x33,0x33,0xcc,0x33,0x85,0xff,0x66,0xb6);
++	&LL(0x63,0x63,0x91,0x63,0x3f,0xf2,0xc6,0x5c);
++	&LL(0x02,0x02,0x08,0x02,0x10,0x0a,0x04,0x12);
++	&LL(0xaa,0xaa,0x92,0xaa,0x39,0x38,0x49,0x93);
++	&LL(0x71,0x71,0xd9,0x71,0xaf,0xa8,0xe2,0xde);
++	&LL(0xc8,0xc8,0x07,0xc8,0x0e,0xcf,0x8d,0xc6);
++	&LL(0x19,0x19,0x64,0x19,0xc8,0x7d,0x32,0xd1);
++	&LL(0x49,0x49,0x39,0x49,0x72,0x70,0x92,0x3b);
++	&LL(0xd9,0xd9,0x43,0xd9,0x86,0x9a,0xaf,0x5f);
++	&LL(0xf2,0xf2,0xef,0xf2,0xc3,0x1d,0xf9,0x31);
++	&LL(0xe3,0xe3,0xab,0xe3,0x4b,0x48,0xdb,0xa8);
++	&LL(0x5b,0x5b,0x71,0x5b,0xe2,0x2a,0xb6,0xb9);
++	&LL(0x88,0x88,0x1a,0x88,0x34,0x92,0x0d,0xbc);
++	&LL(0x9a,0x9a,0x52,0x9a,0xa4,0xc8,0x29,0x3e);
++	&LL(0x26,0x26,0x98,0x26,0x2d,0xbe,0x4c,0x0b);
++	&LL(0x32,0x32,0xc8,0x32,0x8d,0xfa,0x64,0xbf);
++	&LL(0xb0,0xb0,0xfa,0xb0,0xe9,0x4a,0x7d,0x59);
++	&LL(0xe9,0xe9,0x83,0xe9,0x1b,0x6a,0xcf,0xf2);
++	&LL(0x0f,0x0f,0x3c,0x0f,0x78,0x33,0x1e,0x77);
++	&LL(0xd5,0xd5,0x73,0xd5,0xe6,0xa6,0xb7,0x33);
++	&LL(0x80,0x80,0x3a,0x80,0x74,0xba,0x1d,0xf4);
++	&LL(0xbe,0xbe,0xc2,0xbe,0x99,0x7c,0x61,0x27);
++	&LL(0xcd,0xcd,0x13,0xcd,0x26,0xde,0x87,0xeb);
++	&LL(0x34,0x34,0xd0,0x34,0xbd,0xe4,0x68,0x89);
++	&LL(0x48,0x48,0x3d,0x48,0x7a,0x75,0x90,0x32);
++	&LL(0xff,0xff,0xdb,0xff,0xab,0x24,0xe3,0x54);
++	&LL(0x7a,0x7a,0xf5,0x7a,0xf7,0x8f,0xf4,0x8d);
++	&LL(0x90,0x90,0x7a,0x90,0xf4,0xea,0x3d,0x64);
++	&LL(0x5f,0x5f,0x61,0x5f,0xc2,0x3e,0xbe,0x9d);
++	&LL(0x20,0x20,0x80,0x20,0x1d,0xa0,0x40,0x3d);
++	&LL(0x68,0x68,0xbd,0x68,0x67,0xd5,0xd0,0x0f);
++	&LL(0x1a,0x1a,0x68,0x1a,0xd0,0x72,0x34,0xca);
++	&LL(0xae,0xae,0x82,0xae,0x19,0x2c,0x41,0xb7);
++	&LL(0xb4,0xb4,0xea,0xb4,0xc9,0x5e,0x75,0x7d);
++	&LL(0x54,0x54,0x4d,0x54,0x9a,0x19,0xa8,0xce);
++	&LL(0x93,0x93,0x76,0x93,0xec,0xe5,0x3b,0x7f);
++	&LL(0x22,0x22,0x88,0x22,0x0d,0xaa,0x44,0x2f);
++	&LL(0x64,0x64,0x8d,0x64,0x07,0xe9,0xc8,0x63);
++	&LL(0xf1,0xf1,0xe3,0xf1,0xdb,0x12,0xff,0x2a);
++	&LL(0x73,0x73,0xd1,0x73,0xbf,0xa2,0xe6,0xcc);
++	&LL(0x12,0x12,0x48,0x12,0x90,0x5a,0x24,0x82);
++	&LL(0x40,0x40,0x1d,0x40,0x3a,0x5d,0x80,0x7a);
++	&LL(0x08,0x08,0x20,0x08,0x40,0x28,0x10,0x48);
++	&LL(0xc3,0xc3,0x2b,0xc3,0x56,0xe8,0x9b,0x95);
++	&LL(0xec,0xec,0x97,0xec,0x33,0x7b,0xc5,0xdf);
++	&LL(0xdb,0xdb,0x4b,0xdb,0x96,0x90,0xab,0x4d);
++	&LL(0xa1,0xa1,0xbe,0xa1,0x61,0x1f,0x5f,0xc0);
++	&LL(0x8d,0x8d,0x0e,0x8d,0x1c,0x83,0x07,0x91);
++	&LL(0x3d,0x3d,0xf4,0x3d,0xf5,0xc9,0x7a,0xc8);
++	&LL(0x97,0x97,0x66,0x97,0xcc,0xf1,0x33,0x5b);
++	&LL(0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00);
++	&LL(0xcf,0xcf,0x1b,0xcf,0x36,0xd4,0x83,0xf9);
++	&LL(0x2b,0x2b,0xac,0x2b,0x45,0x87,0x56,0x6e);
++	&LL(0x76,0x76,0xc5,0x76,0x97,0xb3,0xec,0xe1);
++	&LL(0x82,0x82,0x32,0x82,0x64,0xb0,0x19,0xe6);
++	&LL(0xd6,0xd6,0x7f,0xd6,0xfe,0xa9,0xb1,0x28);
++	&LL(0x1b,0x1b,0x6c,0x1b,0xd8,0x77,0x36,0xc3);
++	&LL(0xb5,0xb5,0xee,0xb5,0xc1,0x5b,0x77,0x74);
++	&LL(0xaf,0xaf,0x86,0xaf,0x11,0x29,0x43,0xbe);
++	&LL(0x6a,0x6a,0xb5,0x6a,0x77,0xdf,0xd4,0x1d);
++	&LL(0x50,0x50,0x5d,0x50,0xba,0x0d,0xa0,0xea);
++	&LL(0x45,0x45,0x09,0x45,0x12,0x4c,0x8a,0x57);
++	&LL(0xf3,0xf3,0xeb,0xf3,0xcb,0x18,0xfb,0x38);
++	&LL(0x30,0x30,0xc0,0x30,0x9d,0xf0,0x60,0xad);
++	&LL(0xef,0xef,0x9b,0xef,0x2b,0x74,0xc3,0xc4);
++	&LL(0x3f,0x3f,0xfc,0x3f,0xe5,0xc3,0x7e,0xda);
++	&LL(0x55,0x55,0x49,0x55,0x92,0x1c,0xaa,0xc7);
++	&LL(0xa2,0xa2,0xb2,0xa2,0x79,0x10,0x59,0xdb);
++	&LL(0xea,0xea,0x8f,0xea,0x03,0x65,0xc9,0xe9);
++	&LL(0x65,0x65,0x89,0x65,0x0f,0xec,0xca,0x6a);
++	&LL(0xba,0xba,0xd2,0xba,0xb9,0x68,0x69,0x03);
++	&LL(0x2f,0x2f,0xbc,0x2f,0x65,0x93,0x5e,0x4a);
++	&LL(0xc0,0xc0,0x27,0xc0,0x4e,0xe7,0x9d,0x8e);
++	&LL(0xde,0xde,0x5f,0xde,0xbe,0x81,0xa1,0x60);
++	&LL(0x1c,0x1c,0x70,0x1c,0xe0,0x6c,0x38,0xfc);
++	&LL(0xfd,0xfd,0xd3,0xfd,0xbb,0x2e,0xe7,0x46);
++	&LL(0x4d,0x4d,0x29,0x4d,0x52,0x64,0x9a,0x1f);
++	&LL(0x92,0x92,0x72,0x92,0xe4,0xe0,0x39,0x76);
++	&LL(0x75,0x75,0xc9,0x75,0x8f,0xbc,0xea,0xfa);
++	&LL(0x06,0x06,0x18,0x06,0x30,0x1e,0x0c,0x36);
++	&LL(0x8a,0x8a,0x12,0x8a,0x24,0x98,0x09,0xae);
++	&LL(0xb2,0xb2,0xf2,0xb2,0xf9,0x40,0x79,0x4b);
++	&LL(0xe6,0xe6,0xbf,0xe6,0x63,0x59,0xd1,0x85);
++	&LL(0x0e,0x0e,0x38,0x0e,0x70,0x36,0x1c,0x7e);
++	&LL(0x1f,0x1f,0x7c,0x1f,0xf8,0x63,0x3e,0xe7);
++	&LL(0x62,0x62,0x95,0x62,0x37,0xf7,0xc4,0x55);
++	&LL(0xd4,0xd4,0x77,0xd4,0xee,0xa3,0xb5,0x3a);
++	&LL(0xa8,0xa8,0x9a,0xa8,0x29,0x32,0x4d,0x81);
++	&LL(0x96,0x96,0x62,0x96,0xc4,0xf4,0x31,0x52);
++	&LL(0xf9,0xf9,0xc3,0xf9,0x9b,0x3a,0xef,0x62);
++	&LL(0xc5,0xc5,0x33,0xc5,0x66,0xf6,0x97,0xa3);
++	&LL(0x25,0x25,0x94,0x25,0x35,0xb1,0x4a,0x10);
++	&LL(0x59,0x59,0x79,0x59,0xf2,0x20,0xb2,0xab);
++	&LL(0x84,0x84,0x2a,0x84,0x54,0xae,0x15,0xd0);
++	&LL(0x72,0x72,0xd5,0x72,0xb7,0xa7,0xe4,0xc5);
++	&LL(0x39,0x39,0xe4,0x39,0xd5,0xdd,0x72,0xec);
++	&LL(0x4c,0x4c,0x2d,0x4c,0x5a,0x61,0x98,0x16);
++	&LL(0x5e,0x5e,0x65,0x5e,0xca,0x3b,0xbc,0x94);
++	&LL(0x78,0x78,0xfd,0x78,0xe7,0x85,0xf0,0x9f);
++	&LL(0x38,0x38,0xe0,0x38,0xdd,0xd8,0x70,0xe5);
++	&LL(0x8c,0x8c,0x0a,0x8c,0x14,0x86,0x05,0x98);
++	&LL(0xd1,0xd1,0x63,0xd1,0xc6,0xb2,0xbf,0x17);
++	&LL(0xa5,0xa5,0xae,0xa5,0x41,0x0b,0x57,0xe4);
++	&LL(0xe2,0xe2,0xaf,0xe2,0x43,0x4d,0xd9,0xa1);
++	&LL(0x61,0x61,0x99,0x61,0x2f,0xf8,0xc2,0x4e);
++	&LL(0xb3,0xb3,0xf6,0xb3,0xf1,0x45,0x7b,0x42);
++	&LL(0x21,0x21,0x84,0x21,0x15,0xa5,0x42,0x34);
++	&LL(0x9c,0x9c,0x4a,0x9c,0x94,0xd6,0x25,0x08);
++	&LL(0x1e,0x1e,0x78,0x1e,0xf0,0x66,0x3c,0xee);
++	&LL(0x43,0x43,0x11,0x43,0x22,0x52,0x86,0x61);
++	&LL(0xc7,0xc7,0x3b,0xc7,0x76,0xfc,0x93,0xb1);
++	&LL(0xfc,0xfc,0xd7,0xfc,0xb3,0x2b,0xe5,0x4f);
++	&LL(0x04,0x04,0x10,0x04,0x20,0x14,0x08,0x24);
++	&LL(0x51,0x51,0x59,0x51,0xb2,0x08,0xa2,0xe3);
++	&LL(0x99,0x99,0x5e,0x99,0xbc,0xc7,0x2f,0x25);
++	&LL(0x6d,0x6d,0xa9,0x6d,0x4f,0xc4,0xda,0x22);
++	&LL(0x0d,0x0d,0x34,0x0d,0x68,0x39,0x1a,0x65);
++	&LL(0xfa,0xfa,0xcf,0xfa,0x83,0x35,0xe9,0x79);
++	&LL(0xdf,0xdf,0x5b,0xdf,0xb6,0x84,0xa3,0x69);
++	&LL(0x7e,0x7e,0xe5,0x7e,0xd7,0x9b,0xfc,0xa9);
++	&LL(0x24,0x24,0x90,0x24,0x3d,0xb4,0x48,0x19);
++	&LL(0x3b,0x3b,0xec,0x3b,0xc5,0xd7,0x76,0xfe);
++	&LL(0xab,0xab,0x96,0xab,0x31,0x3d,0x4b,0x9a);
++	&LL(0xce,0xce,0x1f,0xce,0x3e,0xd1,0x81,0xf0);
++	&LL(0x11,0x11,0x44,0x11,0x88,0x55,0x22,0x99);
++	&LL(0x8f,0x8f,0x06,0x8f,0x0c,0x89,0x03,0x83);
++	&LL(0x4e,0x4e,0x25,0x4e,0x4a,0x6b,0x9c,0x04);
++	&LL(0xb7,0xb7,0xe6,0xb7,0xd1,0x51,0x73,0x66);
++	&LL(0xeb,0xeb,0x8b,0xeb,0x0b,0x60,0xcb,0xe0);
++	&LL(0x3c,0x3c,0xf0,0x3c,0xfd,0xcc,0x78,0xc1);
++	&LL(0x81,0x81,0x3e,0x81,0x7c,0xbf,0x1f,0xfd);
++	&LL(0x94,0x94,0x6a,0x94,0xd4,0xfe,0x35,0x40);
++	&LL(0xf7,0xf7,0xfb,0xf7,0xeb,0x0c,0xf3,0x1c);
++	&LL(0xb9,0xb9,0xde,0xb9,0xa1,0x67,0x6f,0x18);
++	&LL(0x13,0x13,0x4c,0x13,0x98,0x5f,0x26,0x8b);
++	&LL(0x2c,0x2c,0xb0,0x2c,0x7d,0x9c,0x58,0x51);
++	&LL(0xd3,0xd3,0x6b,0xd3,0xd6,0xb8,0xbb,0x05);
++	&LL(0xe7,0xe7,0xbb,0xe7,0x6b,0x5c,0xd3,0x8c);
++	&LL(0x6e,0x6e,0xa5,0x6e,0x57,0xcb,0xdc,0x39);
++	&LL(0xc4,0xc4,0x37,0xc4,0x6e,0xf3,0x95,0xaa);
++	&LL(0x03,0x03,0x0c,0x03,0x18,0x0f,0x06,0x1b);
++	&LL(0x56,0x56,0x45,0x56,0x8a,0x13,0xac,0xdc);
++	&LL(0x44,0x44,0x0d,0x44,0x1a,0x49,0x88,0x5e);
++	&LL(0x7f,0x7f,0xe1,0x7f,0xdf,0x9e,0xfe,0xa0);
++	&LL(0xa9,0xa9,0x9e,0xa9,0x21,0x37,0x4f,0x88);
++	&LL(0x2a,0x2a,0xa8,0x2a,0x4d,0x82,0x54,0x67);
++	&LL(0xbb,0xbb,0xd6,0xbb,0xb1,0x6d,0x6b,0x0a);
++	&LL(0xc1,0xc1,0x23,0xc1,0x46,0xe2,0x9f,0x87);
++	&LL(0x53,0x53,0x51,0x53,0xa2,0x02,0xa6,0xf1);
++	&LL(0xdc,0xdc,0x57,0xdc,0xae,0x8b,0xa5,0x72);
++	&LL(0x0b,0x0b,0x2c,0x0b,0x58,0x27,0x16,0x53);
++	&LL(0x9d,0x9d,0x4e,0x9d,0x9c,0xd3,0x27,0x01);
++	&LL(0x6c,0x6c,0xad,0x6c,0x47,0xc1,0xd8,0x2b);
++	&LL(0x31,0x31,0xc4,0x31,0x95,0xf5,0x62,0xa4);
++	&LL(0x74,0x74,0xcd,0x74,0x87,0xb9,0xe8,0xf3);
++	&LL(0xf6,0xf6,0xff,0xf6,0xe3,0x09,0xf1,0x15);
++	&LL(0x46,0x46,0x05,0x46,0x0a,0x43,0x8c,0x4c);
++	&LL(0xac,0xac,0x8a,0xac,0x09,0x26,0x45,0xa5);
++	&LL(0x89,0x89,0x1e,0x89,0x3c,0x97,0x0f,0xb5);
++	&LL(0x14,0x14,0x50,0x14,0xa0,0x44,0x28,0xb4);
++	&LL(0xe1,0xe1,0xa3,0xe1,0x5b,0x42,0xdf,0xba);
++	&LL(0x16,0x16,0x58,0x16,0xb0,0x4e,0x2c,0xa6);
++	&LL(0x3a,0x3a,0xe8,0x3a,0xcd,0xd2,0x74,0xf7);
++	&LL(0x69,0x69,0xb9,0x69,0x6f,0xd0,0xd2,0x06);
++	&LL(0x09,0x09,0x24,0x09,0x48,0x2d,0x12,0x41);
++	&LL(0x70,0x70,0xdd,0x70,0xa7,0xad,0xe0,0xd7);
++	&LL(0xb6,0xb6,0xe2,0xb6,0xd9,0x54,0x71,0x6f);
++	&LL(0xd0,0xd0,0x67,0xd0,0xce,0xb7,0xbd,0x1e);
++	&LL(0xed,0xed,0x93,0xed,0x3b,0x7e,0xc7,0xd6);
++	&LL(0xcc,0xcc,0x17,0xcc,0x2e,0xdb,0x85,0xe2);
++	&LL(0x42,0x42,0x15,0x42,0x2a,0x57,0x84,0x68);
++	&LL(0x98,0x98,0x5a,0x98,0xb4,0xc2,0x2d,0x2c);
++	&LL(0xa4,0xa4,0xaa,0xa4,0x49,0x0e,0x55,0xed);
++	&LL(0x28,0x28,0xa0,0x28,0x5d,0x88,0x50,0x75);
++	&LL(0x5c,0x5c,0x6d,0x5c,0xda,0x31,0xb8,0x86);
++	&LL(0xf8,0xf8,0xc7,0xf8,0x93,0x3f,0xed,0x6b);
++	&LL(0x86,0x86,0x22,0x86,0x44,0xa4,0x11,0xc2);
++
++	&L(0x18,0x23,0xc6,0xe8,0x87,0xb8,0x01,0x4f);	# rc[ROUNDS]
++	&L(0x36,0xa6,0xd2,0xf5,0x79,0x6f,0x91,0x52);
++	&L(0x60,0xbc,0x9b,0x8e,0xa3,0x0c,0x7b,0x35);
++	&L(0x1d,0xe0,0xd7,0xc2,0x2e,0x4b,0xfe,0x57);
++	&L(0x15,0x77,0x37,0xe5,0x9f,0xf0,0x4a,0xda);
++	&L(0x58,0xc9,0x29,0x0a,0xb1,0xa0,0x6b,0x85);
++	&L(0xbd,0x5d,0x10,0xf4,0xcb,0x3e,0x05,0x67);
++	&L(0xe4,0x27,0x41,0x8b,0xa7,0x7d,0x95,0xd8);
++	&L(0xfb,0xee,0x7c,0x66,0xdd,0x17,0x47,0x9e);
++	&L(0xca,0x2d,0xbf,0x07,0xad,0x5a,0x83,0x33);
++
++# EXCEPTION_DISPOSITION handler (EXCEPTION_RECORD *rec,ULONG64 frame,
++#		CONTEXT *context,DISPATCHER_CONTEXT *disp)
++if ($win64) {
++$rec="%rcx";
++$frame="%rdx";
++$context="%r8";
++$disp="%r9";
++
++$code.=<<___;
++.extern	__imp_RtlVirtualUnwind
++.type	se_handler,\@abi-omnipotent
++.align	16
++se_handler:
++	push	%rsi
++	push	%rdi
++	push	%rbx
++	push	%rbp
++	push	%r12
++	push	%r13
++	push	%r14
++	push	%r15
++	pushfq
++	sub	\$64,%rsp
++
++	mov	120($context),%rax	# pull context->Rax
++	mov	248($context),%rbx	# pull context->Rip
++
++	lea	.Lprologue(%rip),%r10
++	cmp	%r10,%rbx		# context->Rip<.Lprologue
++	jb	.Lin_prologue
++
++	mov	152($context),%rax	# pull context->Rsp
++
++	lea	.Lepilogue(%rip),%r10
++	cmp	%r10,%rbx		# context->Rip>=.Lepilogue
++	jae	.Lin_prologue
++
++	mov	128+32(%rax),%rax	# pull saved stack pointer
++	lea	48(%rax),%rax
++
++	mov	-8(%rax),%rbx
++	mov	-16(%rax),%rbp
++	mov	-24(%rax),%r12
++	mov	-32(%rax),%r13
++	mov	-40(%rax),%r14
++	mov	-48(%rax),%r15
++	mov	%rbx,144($context)	# restore context->Rbx
++	mov	%rbp,160($context)	# restore context->Rbp
++	mov	%r12,216($context)	# restore context->R12
++	mov	%r13,224($context)	# restore context->R13
++	mov	%r14,232($context)	# restore context->R14
++	mov	%r15,240($context)	# restore context->R15
++
++.Lin_prologue:
++	mov	8(%rax),%rdi
++	mov	16(%rax),%rsi
++	mov	%rax,152($context)	# restore context->Rsp
++	mov	%rsi,168($context)	# restore context->Rsi
++	mov	%rdi,176($context)	# restore context->Rdi
++
++	mov	40($disp),%rdi		# disp->ContextRecord
++	mov	$context,%rsi		# context
++	mov	\$154,%ecx		# sizeof(CONTEXT)
++	.long	0xa548f3fc		# cld; rep movsq
++
++	mov	$disp,%rsi
++	xor	%rcx,%rcx		# arg1, UNW_FLAG_NHANDLER
++	mov	8(%rsi),%rdx		# arg2, disp->ImageBase
++	mov	0(%rsi),%r8		# arg3, disp->ControlPc
++	mov	16(%rsi),%r9		# arg4, disp->FunctionEntry
++	mov	40(%rsi),%r10		# disp->ContextRecord
++	lea	56(%rsi),%r11		# &disp->HandlerData
++	lea	24(%rsi),%r12		# &disp->EstablisherFrame
++	mov	%r10,32(%rsp)		# arg5
++	mov	%r11,40(%rsp)		# arg6
++	mov	%r12,48(%rsp)		# arg7
++	mov	%rcx,56(%rsp)		# arg8, (NULL)
++	call	*__imp_RtlVirtualUnwind(%rip)
++
++	mov	\$1,%eax		# ExceptionContinueSearch
++	add	\$64,%rsp
++	popfq
++	pop	%r15
++	pop	%r14
++	pop	%r13
++	pop	%r12
++	pop	%rbp
++	pop	%rbx
++	pop	%rdi
++	pop	%rsi
++	ret
++.size	se_handler,.-se_handler
++
++.section	.pdata
++.align	4
++	.rva	.LSEH_begin_$func
++	.rva	.LSEH_end_$func
++	.rva	.LSEH_info_$func
++
++.section	.xdata
++.align	8
++.LSEH_info_$func:
++	.byte	9,0,0,0
++	.rva	se_handler
++___
++}
++
++$code =~ s/\`([^\`]*)\`/eval $1/gem;
++print $code;
++close STDOUT;
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/whrlpool/build.info b/CryptoPkg/Library/OpensslLib/openssl/crypto/whrlpool/build.info
+new file mode 100644
+index 0000000..7f3a19e
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/whrlpool/build.info
+@@ -0,0 +1,7 @@
++LIBS=../../libcrypto
++SOURCE[../../libcrypto]=wp_dgst.c {- $target{wp_asm_src} -}
++
++GENERATE[wp-mmx.s]=asm/wp-mmx.pl $(PERLASM_SCHEME) $(CFLAGS) $(LIB_CFLAGS) $(PROCESSOR)
++DEPEND[wp-mmx.s]=../perlasm/x86asm.pl
++
++GENERATE[wp-x86_64.s]=asm/wp-x86_64.pl $(PERLASM_SCHEME)
+diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/whrlpool/wp_block.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/whrlpool/wp_block.c
+new file mode 100644
+index 0000000..b29f037
+--- /dev/null
++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/whrlpool/wp_block.c
+@@ -0,0 +1,792 @@
++/*
++ * Copyright 2005-2016 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
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++/**
++ * The Whirlpool hashing function.
++ *
++ * 

++ * References ++ * ++ *

++ * The Whirlpool algorithm was developed by ++ * Paulo S. L. M. Barreto and ++ * Vincent Rijmen. ++ * ++ * See ++ * P.S.L.M. Barreto, V. Rijmen, ++ * ``The Whirlpool hashing function,'' ++ * NESSIE submission, 2000 (tweaked version, 2001), ++ * ++ * ++ * Based on "@version 3.0 (2003.03.12)" by Paulo S.L.M. Barreto and ++ * Vincent Rijmen. Lookup "reference implementations" on ++ * ++ * ++ * ============================================================================= ++ * ++ * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ''AS IS'' AND ANY EXPRESS ++ * 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 AUTHORS OR 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. ++ * ++ */ ++ ++#include "wp_locl.h" ++#include ++ ++typedef unsigned char u8; ++#if (defined(_WIN32) || defined(_WIN64)) && !defined(__MINGW32) ++typedef unsigned __int64 u64; ++#elif defined(__arch64__) ++typedef unsigned long u64; ++#else ++typedef unsigned long long u64; ++#endif ++ ++#define ROUNDS 10 ++ ++#define STRICT_ALIGNMENT ++#if !defined(PEDANTIC) && (defined(__i386) || defined(__i386__) || \ ++ defined(__x86_64) || defined(__x86_64__) || \ ++ defined(_M_IX86) || defined(_M_AMD64) || \ ++ defined(_M_X64)) ++/* ++ * Well, formally there're couple of other architectures, which permit ++ * unaligned loads, specifically those not crossing cache lines, IA-64 and ++ * PowerPC... ++ */ ++# undef STRICT_ALIGNMENT ++#endif ++ ++#undef SMALL_REGISTER_BANK ++#if defined(__i386) || defined(__i386__) || defined(_M_IX86) ++# define SMALL_REGISTER_BANK ++# if defined(WHIRLPOOL_ASM) ++# ifndef OPENSSL_SMALL_FOOTPRINT ++/* ++ * it appears that for elder non-MMX ++ * CPUs this is actually faster! ++ */ ++# define OPENSSL_SMALL_FOOTPRINT ++# endif ++# define GO_FOR_MMX(ctx,inp,num) do { \ ++ extern unsigned long OPENSSL_ia32cap_P[]; \ ++ void whirlpool_block_mmx(void *,const void *,size_t); \ ++ if (!(OPENSSL_ia32cap_P[0] & (1<<23))) break; \ ++ whirlpool_block_mmx(ctx->H.c,inp,num); return; \ ++ } while (0) ++# endif ++#endif ++ ++#undef ROTATE ++#ifndef PEDANTIC ++# if defined(_MSC_VER) ++# if defined(_WIN64) /* applies to both IA-64 and AMD64 */ ++# pragma intrinsic(_rotl64) ++# define ROTATE(a,n) _rotl64((a),n) ++# endif ++# elif defined(__GNUC__) && __GNUC__>=2 ++# if defined(__x86_64) || defined(__x86_64__) ++# if defined(L_ENDIAN) ++# define ROTATE(a,n) ({ u64 ret; asm ("rolq %1,%0" \ ++ : "=r"(ret) : "J"(n),"0"(a) : "cc"); ret; }) ++# elif defined(B_ENDIAN) ++ /* ++ * Most will argue that x86_64 is always little-endian. Well, yes, but ++ * then we have stratus.com who has modified gcc to "emulate" ++ * big-endian on x86. Is there evidence that they [or somebody else] ++ * won't do same for x86_64? Naturally no. And this line is waiting ++ * ready for that brave soul:-) ++ */ ++# define ROTATE(a,n) ({ u64 ret; asm ("rorq %1,%0" \ ++ : "=r"(ret) : "J"(n),"0"(a) : "cc"); ret; }) ++# endif ++# elif defined(__ia64) || defined(__ia64__) ++# if defined(L_ENDIAN) ++# define ROTATE(a,n) ({ u64 ret; asm ("shrp %0=%1,%1,%2" \ ++ : "=r"(ret) : "r"(a),"M"(64-(n))); ret; }) ++# elif defined(B_ENDIAN) ++# define ROTATE(a,n) ({ u64 ret; asm ("shrp %0=%1,%1,%2" \ ++ : "=r"(ret) : "r"(a),"M"(n)); ret; }) ++# endif ++# endif ++# endif ++#endif ++ ++#if defined(OPENSSL_SMALL_FOOTPRINT) ++# if !defined(ROTATE) ++# if defined(L_ENDIAN) /* little-endians have to rotate left */ ++# define ROTATE(i,n) ((i)<<(n) ^ (i)>>(64-n)) ++# elif defined(B_ENDIAN) /* big-endians have to rotate right */ ++# define ROTATE(i,n) ((i)>>(n) ^ (i)<<(64-n)) ++# endif ++# endif ++# if defined(ROTATE) && !defined(STRICT_ALIGNMENT) ++# define STRICT_ALIGNMENT /* ensure smallest table size */ ++# endif ++#endif ++ ++/* ++ * Table size depends on STRICT_ALIGNMENT and whether or not endian- ++ * specific ROTATE macro is defined. If STRICT_ALIGNMENT is not ++ * defined, which is normally the case on x86[_64] CPUs, the table is ++ * 4KB large unconditionally. Otherwise if ROTATE is defined, the ++ * table is 2KB large, and otherwise - 16KB. 2KB table requires a ++ * whole bunch of additional rotations, but I'm willing to "trade," ++ * because 16KB table certainly trashes L1 cache. I wish all CPUs ++ * could handle unaligned load as 4KB table doesn't trash the cache, ++ * nor does it require additional rotations. ++ */ ++/* ++ * Note that every Cn macro expands as two loads: one byte load and ++ * one quadword load. One can argue that that many single-byte loads ++ * is too excessive, as one could load a quadword and "milk" it for ++ * eight 8-bit values instead. Well, yes, but in order to do so *and* ++ * avoid excessive loads you have to accommodate a handful of 64-bit ++ * values in the register bank and issue a bunch of shifts and mask. ++ * It's a tradeoff: loads vs. shift and mask in big register bank[!]. ++ * On most CPUs eight single-byte loads are faster and I let other ++ * ones to depend on smart compiler to fold byte loads if beneficial. ++ * Hand-coded assembler would be another alternative:-) ++ */ ++#ifdef STRICT_ALIGNMENT ++# if defined(ROTATE) ++# define N 1 ++# define LL(c0,c1,c2,c3,c4,c5,c6,c7) c0,c1,c2,c3,c4,c5,c6,c7 ++# define C0(K,i) (Cx.q[K.c[(i)*8+0]]) ++# define C1(K,i) ROTATE(Cx.q[K.c[(i)*8+1]],8) ++# define C2(K,i) ROTATE(Cx.q[K.c[(i)*8+2]],16) ++# define C3(K,i) ROTATE(Cx.q[K.c[(i)*8+3]],24) ++# define C4(K,i) ROTATE(Cx.q[K.c[(i)*8+4]],32) ++# define C5(K,i) ROTATE(Cx.q[K.c[(i)*8+5]],40) ++# define C6(K,i) ROTATE(Cx.q[K.c[(i)*8+6]],48) ++# define C7(K,i) ROTATE(Cx.q[K.c[(i)*8+7]],56) ++# else ++# define N 8 ++# define LL(c0,c1,c2,c3,c4,c5,c6,c7) c0,c1,c2,c3,c4,c5,c6,c7, \ ++ c7,c0,c1,c2,c3,c4,c5,c6, \ ++ c6,c7,c0,c1,c2,c3,c4,c5, \ ++ c5,c6,c7,c0,c1,c2,c3,c4, \ ++ c4,c5,c6,c7,c0,c1,c2,c3, \ ++ c3,c4,c5,c6,c7,c0,c1,c2, \ ++ c2,c3,c4,c5,c6,c7,c0,c1, \ ++ c1,c2,c3,c4,c5,c6,c7,c0 ++# define C0(K,i) (Cx.q[0+8*K.c[(i)*8+0]]) ++# define C1(K,i) (Cx.q[1+8*K.c[(i)*8+1]]) ++# define C2(K,i) (Cx.q[2+8*K.c[(i)*8+2]]) ++# define C3(K,i) (Cx.q[3+8*K.c[(i)*8+3]]) ++# define C4(K,i) (Cx.q[4+8*K.c[(i)*8+4]]) ++# define C5(K,i) (Cx.q[5+8*K.c[(i)*8+5]]) ++# define C6(K,i) (Cx.q[6+8*K.c[(i)*8+6]]) ++# define C7(K,i) (Cx.q[7+8*K.c[(i)*8+7]]) ++# endif ++#else ++# define N 2 ++# define LL(c0,c1,c2,c3,c4,c5,c6,c7) c0,c1,c2,c3,c4,c5,c6,c7, \ ++ c0,c1,c2,c3,c4,c5,c6,c7 ++# define C0(K,i) (((u64*)(Cx.c+0))[2*K.c[(i)*8+0]]) ++# define C1(K,i) (((u64*)(Cx.c+7))[2*K.c[(i)*8+1]]) ++# define C2(K,i) (((u64*)(Cx.c+6))[2*K.c[(i)*8+2]]) ++# define C3(K,i) (((u64*)(Cx.c+5))[2*K.c[(i)*8+3]]) ++# define C4(K,i) (((u64*)(Cx.c+4))[2*K.c[(i)*8+4]]) ++# define C5(K,i) (((u64*)(Cx.c+3))[2*K.c[(i)*8+5]]) ++# define C6(K,i) (((u64*)(Cx.c+2))[2*K.c[(i)*8+6]]) ++# define C7(K,i) (((u64*)(Cx.c+1))[2*K.c[(i)*8+7]]) ++#endif ++ ++static const ++ union { ++ u8 c[(256 * N + ROUNDS) * sizeof(u64)]; ++ u64 q[(256 * N + ROUNDS)]; ++} Cx = { ++ { ++ /* Note endian-neutral representation:-) */ ++ LL(0x18, 0x18, 0x60, 0x18, 0xc0, 0x78, 0x30, 0xd8), ++ LL(0x23, 0x23, 0x8c, 0x23, 0x05, 0xaf, 0x46, 0x26), ++ LL(0xc6, 0xc6, 0x3f, 0xc6, 0x7e, 0xf9, 0x91, 0xb8), ++ LL(0xe8, 0xe8, 0x87, 0xe8, 0x13, 0x6f, 0xcd, 0xfb), ++ LL(0x87, 0x87, 0x26, 0x87, 0x4c, 0xa1, 0x13, 0xcb), ++ LL(0xb8, 0xb8, 0xda, 0xb8, 0xa9, 0x62, 0x6d, 0x11), ++ LL(0x01, 0x01, 0x04, 0x01, 0x08, 0x05, 0x02, 0x09), ++ LL(0x4f, 0x4f, 0x21, 0x4f, 0x42, 0x6e, 0x9e, 0x0d), ++ LL(0x36, 0x36, 0xd8, 0x36, 0xad, 0xee, 0x6c, 0x9b), ++ LL(0xa6, 0xa6, 0xa2, 0xa6, 0x59, 0x04, 0x51, 0xff), ++ LL(0xd2, 0xd2, 0x6f, 0xd2, 0xde, 0xbd, 0xb9, 0x0c), ++ LL(0xf5, 0xf5, 0xf3, 0xf5, 0xfb, 0x06, 0xf7, 0x0e), ++ LL(0x79, 0x79, 0xf9, 0x79, 0xef, 0x80, 0xf2, 0x96), ++ LL(0x6f, 0x6f, 0xa1, 0x6f, 0x5f, 0xce, 0xde, 0x30), ++ LL(0x91, 0x91, 0x7e, 0x91, 0xfc, 0xef, 0x3f, 0x6d), ++ LL(0x52, 0x52, 0x55, 0x52, 0xaa, 0x07, 0xa4, 0xf8), ++ LL(0x60, 0x60, 0x9d, 0x60, 0x27, 0xfd, 0xc0, 0x47), ++ LL(0xbc, 0xbc, 0xca, 0xbc, 0x89, 0x76, 0x65, 0x35), ++ LL(0x9b, 0x9b, 0x56, 0x9b, 0xac, 0xcd, 0x2b, 0x37), ++ LL(0x8e, 0x8e, 0x02, 0x8e, 0x04, 0x8c, 0x01, 0x8a), ++ LL(0xa3, 0xa3, 0xb6, 0xa3, 0x71, 0x15, 0x5b, 0xd2), ++ LL(0x0c, 0x0c, 0x30, 0x0c, 0x60, 0x3c, 0x18, 0x6c), ++ LL(0x7b, 0x7b, 0xf1, 0x7b, 0xff, 0x8a, 0xf6, 0x84), ++ LL(0x35, 0x35, 0xd4, 0x35, 0xb5, 0xe1, 0x6a, 0x80), ++ LL(0x1d, 0x1d, 0x74, 0x1d, 0xe8, 0x69, 0x3a, 0xf5), ++ LL(0xe0, 0xe0, 0xa7, 0xe0, 0x53, 0x47, 0xdd, 0xb3), ++ LL(0xd7, 0xd7, 0x7b, 0xd7, 0xf6, 0xac, 0xb3, 0x21), ++ LL(0xc2, 0xc2, 0x2f, 0xc2, 0x5e, 0xed, 0x99, 0x9c), ++ LL(0x2e, 0x2e, 0xb8, 0x2e, 0x6d, 0x96, 0x5c, 0x43), ++ LL(0x4b, 0x4b, 0x31, 0x4b, 0x62, 0x7a, 0x96, 0x29), ++ LL(0xfe, 0xfe, 0xdf, 0xfe, 0xa3, 0x21, 0xe1, 0x5d), ++ LL(0x57, 0x57, 0x41, 0x57, 0x82, 0x16, 0xae, 0xd5), ++ LL(0x15, 0x15, 0x54, 0x15, 0xa8, 0x41, 0x2a, 0xbd), ++ LL(0x77, 0x77, 0xc1, 0x77, 0x9f, 0xb6, 0xee, 0xe8), ++ LL(0x37, 0x37, 0xdc, 0x37, 0xa5, 0xeb, 0x6e, 0x92), ++ LL(0xe5, 0xe5, 0xb3, 0xe5, 0x7b, 0x56, 0xd7, 0x9e), ++ LL(0x9f, 0x9f, 0x46, 0x9f, 0x8c, 0xd9, 0x23, 0x13), ++ LL(0xf0, 0xf0, 0xe7, 0xf0, 0xd3, 0x17, 0xfd, 0x23), ++ LL(0x4a, 0x4a, 0x35, 0x4a, 0x6a, 0x7f, 0x94, 0x20), ++ LL(0xda, 0xda, 0x4f, 0xda, 0x9e, 0x95, 0xa9, 0x44), ++ LL(0x58, 0x58, 0x7d, 0x58, 0xfa, 0x25, 0xb0, 0xa2), ++ LL(0xc9, 0xc9, 0x03, 0xc9, 0x06, 0xca, 0x8f, 0xcf), ++ LL(0x29, 0x29, 0xa4, 0x29, 0x55, 0x8d, 0x52, 0x7c), ++ LL(0x0a, 0x0a, 0x28, 0x0a, 0x50, 0x22, 0x14, 0x5a), ++ LL(0xb1, 0xb1, 0xfe, 0xb1, 0xe1, 0x4f, 0x7f, 0x50), ++ LL(0xa0, 0xa0, 0xba, 0xa0, 0x69, 0x1a, 0x5d, 0xc9), ++ LL(0x6b, 0x6b, 0xb1, 0x6b, 0x7f, 0xda, 0xd6, 0x14), ++ LL(0x85, 0x85, 0x2e, 0x85, 0x5c, 0xab, 0x17, 0xd9), ++ LL(0xbd, 0xbd, 0xce, 0xbd, 0x81, 0x73, 0x67, 0x3c), ++ LL(0x5d, 0x5d, 0x69, 0x5d, 0xd2, 0x34, 0xba, 0x8f), ++ LL(0x10, 0x10, 0x40, 0x10, 0x80, 0x50, 0x20, 0x90), ++ LL(0xf4, 0xf4, 0xf7, 0xf4, 0xf3, 0x03, 0xf5, 0x07), ++ LL(0xcb, 0xcb, 0x0b, 0xcb, 0x16, 0xc0, 0x8b, 0xdd), ++ LL(0x3e, 0x3e, 0xf8, 0x3e, 0xed, 0xc6, 0x7c, 0xd3), ++ LL(0x05, 0x05, 0x14, 0x05, 0x28, 0x11, 0x0a, 0x2d), ++ LL(0x67, 0x67, 0x81, 0x67, 0x1f, 0xe6, 0xce, 0x78), ++ LL(0xe4, 0xe4, 0xb7, 0xe4, 0x73, 0x53, 0xd5, 0x97), ++ LL(0x27, 0x27, 0x9c, 0x27, 0x25, 0xbb, 0x4e, 0x02), ++ LL(0x41, 0x41, 0x19, 0x41, 0x32, 0x58, 0x82, 0x73), ++ LL(0x8b, 0x8b, 0x16, 0x8b, 0x2c, 0x9d, 0x0b, 0xa7), ++ LL(0xa7, 0xa7, 0xa6, 0xa7, 0x51, 0x01, 0x53, 0xf6), ++ LL(0x7d, 0x7d, 0xe9, 0x7d, 0xcf, 0x94, 0xfa, 0xb2), ++ LL(0x95, 0x95, 0x6e, 0x95, 0xdc, 0xfb, 0x37, 0x49), ++ LL(0xd8, 0xd8, 0x47, 0xd8, 0x8e, 0x9f, 0xad, 0x56), ++ LL(0xfb, 0xfb, 0xcb, 0xfb, 0x8b, 0x30, 0xeb, 0x70), ++ LL(0xee, 0xee, 0x9f, 0xee, 0x23, 0x71, 0xc1, 0xcd), ++ LL(0x7c, 0x7c, 0xed, 0x7c, 0xc7, 0x91, 0xf8, 0xbb), ++ LL(0x66, 0x66, 0x85, 0x66, 0x17, 0xe3, 0xcc, 0x71), ++ LL(0xdd, 0xdd, 0x53, 0xdd, 0xa6, 0x8e, 0xa7, 0x7b), ++ LL(0x17, 0x17, 0x5c, 0x17, 0xb8, 0x4b, 0x2e, 0xaf), ++ LL(0x47, 0x47, 0x01, 0x47, 0x02, 0x46, 0x8e, 0x45), ++ LL(0x9e, 0x9e, 0x42, 0x9e, 0x84, 0xdc, 0x21, 0x1a), ++ LL(0xca, 0xca, 0x0f, 0xca, 0x1e, 0xc5, 0x89, 0xd4), ++ LL(0x2d, 0x2d, 0xb4, 0x2d, 0x75, 0x99, 0x5a, 0x58), ++ LL(0xbf, 0xbf, 0xc6, 0xbf, 0x91, 0x79, 0x63, 0x2e), ++ LL(0x07, 0x07, 0x1c, 0x07, 0x38, 0x1b, 0x0e, 0x3f), ++ LL(0xad, 0xad, 0x8e, 0xad, 0x01, 0x23, 0x47, 0xac), ++ LL(0x5a, 0x5a, 0x75, 0x5a, 0xea, 0x2f, 0xb4, 0xb0), ++ LL(0x83, 0x83, 0x36, 0x83, 0x6c, 0xb5, 0x1b, 0xef), ++ LL(0x33, 0x33, 0xcc, 0x33, 0x85, 0xff, 0x66, 0xb6), ++ LL(0x63, 0x63, 0x91, 0x63, 0x3f, 0xf2, 0xc6, 0x5c), ++ LL(0x02, 0x02, 0x08, 0x02, 0x10, 0x0a, 0x04, 0x12), ++ LL(0xaa, 0xaa, 0x92, 0xaa, 0x39, 0x38, 0x49, 0x93), ++ LL(0x71, 0x71, 0xd9, 0x71, 0xaf, 0xa8, 0xe2, 0xde), ++ LL(0xc8, 0xc8, 0x07, 0xc8, 0x0e, 0xcf, 0x8d, 0xc6), ++ LL(0x19, 0x19, 0x64, 0x19, 0xc8, 0x7d, 0x32, 0xd1), ++ LL(0x49, 0x49, 0x39, 0x49, 0x72, 0x70, 0x92, 0x3b), ++ LL(0xd9, 0xd9, 0x43, 0xd9, 0x86, 0x9a, 0xaf, 0x5f), ++ LL(0xf2, 0xf2, 0xef, 0xf2, 0xc3, 0x1d, 0xf9, 0x31), ++ LL(0xe3, 0xe3, 0xab, 0xe3, 0x4b, 0x48, 0xdb, 0xa8), ++ LL(0x5b, 0x5b, 0x71, 0x5b, 0xe2, 0x2a, 0xb6, 0xb9), ++ LL(0x88, 0x88, 0x1a, 0x88, 0x34, 0x92, 0x0d, 0xbc), ++ LL(0x9a, 0x9a, 0x52, 0x9a, 0xa4, 0xc8, 0x29, 0x3e), ++ LL(0x26, 0x26, 0x98, 0x26, 0x2d, 0xbe, 0x4c, 0x0b), ++ LL(0x32, 0x32, 0xc8, 0x32, 0x8d, 0xfa, 0x64, 0xbf), ++ LL(0xb0, 0xb0, 0xfa, 0xb0, 0xe9, 0x4a, 0x7d, 0x59), ++ LL(0xe9, 0xe9, 0x83, 0xe9, 0x1b, 0x6a, 0xcf, 0xf2), ++ LL(0x0f, 0x0f, 0x3c, 0x0f, 0x78, 0x33, 0x1e, 0x77), ++ LL(0xd5, 0xd5, 0x73, 0xd5, 0xe6, 0xa6, 0xb7, 0x33), ++ LL(0x80, 0x80, 0x3a, 0x80, 0x74, 0xba, 0x1d, 0xf4), ++ LL(0xbe, 0xbe, 0xc2, 0xbe, 0x99, 0x7c, 0x61, 0x27), ++ LL(0xcd, 0xcd, 0x13, 0xcd, 0x26, 0xde, 0x87, 0xeb), ++ LL(0x34, 0x34, 0xd0, 0x34, 0xbd, 0xe4, 0x68, 0x89), ++ LL(0x48, 0x48, 0x3d, 0x48, 0x7a, 0x75, 0x90, 0x32), ++ LL(0xff, 0xff, 0xdb, 0xff, 0xab, 0x24, 0xe3, 0x54), ++ LL(0x7a, 0x7a, 0xf5, 0x7a, 0xf7, 0x8f, 0xf4, 0x8d), ++ LL(0x90, 0x90, 0x7a, 0x90, 0xf4, 0xea, 0x3d, 0x64), ++ LL(0x5f, 0x5f, 0x61, 0x5f, 0xc2, 0x3e, 0xbe, 0x9d), ++ LL(0x20, 0x20, 0x80, 0x20, 0x1d, 0xa0, 0x40, 0x3d), ++ LL(0x68, 0x68, 0xbd, 0x68, 0x67, 0xd5, 0xd0, 0x0f), ++ LL(0x1a, 0x1a, 0x68, 0x1a, 0xd0, 0x72, 0x34, 0xca), ++ LL(0xae, 0xae, 0x82, 0xae, 0x19, 0x2c, 0x41, 0xb7), ++ LL(0xb4, 0xb4, 0xea, 0xb4, 0xc9, 0x5e, 0x75, 0x7d), ++ LL(0x54, 0x54, 0x4d, 0x54, 0x9a, 0x19, 0xa8, 0xce), ++ LL(0x93, 0x93, 0x76, 0x93, 0xec, 0xe5, 0x3b, 0x7f), ++ LL(0x22, 0x22, 0x88, 0x22, 0x0d, 0xaa, 0x44, 0x2f), ++ LL(0x64, 0x64, 0x8d, 0x64, 0x07, 0xe9, 0xc8, 0x63), ++ LL(0xf1, 0xf1, 0xe3, 0xf1, 0xdb, 0x12, 0xff, 0x2a), ++ LL(0x73, 0x73, 0xd1, 0x73, 0xbf, 0xa2, 0xe6, 0xcc), ++ LL(0x12, 0x12, 0x48, 0x12, 0x90, 0x5a, 0x24, 0x82), ++ LL(0x40, 0x40, 0x1d, 0x40, 0x3a, 0x5d, 0x80, 0x7a), ++ LL(0x08, 0x08, 0x20, 0x08, 0x40, 0x28, 0x10, 0x48), ++ LL(0xc3, 0xc3, 0x2b, 0xc3, 0x56, 0xe8, 0x9b, 0x95), ++ LL(0xec, 0xec, 0x97, 0xec, 0x33, 0x7b, 0xc5, 0xdf), ++ LL(0xdb, 0xdb, 0x4b, 0xdb, 0x96, 0x90, 0xab, 0x4d), ++ LL(0xa1, 0xa1, 0xbe, 0xa1, 0x61, 0x1f, 0x5f, 0xc0), ++ LL(0x8d, 0x8d, 0x0e, 0x8d, 0x1c, 0x83, 0x07, 0x91), ++ LL(0x3d, 0x3d, 0xf4, 0x3d, 0xf5, 0xc9, 0x7a, 0xc8), ++ LL(0x97, 0x97, 0x66, 0x97, 0xcc, 0xf1, 0x33, 0x5b), ++ LL(0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00), ++ LL(0xcf, 0xcf, 0x1b, 0xcf, 0x36, 0xd4, 0x83, 0xf9), ++ LL(0x2b, 0x2b, 0xac, 0x2b, 0x45, 0x87, 0x56, 0x6e), ++ LL(0x76, 0x76, 0xc5, 0x76, 0x97, 0xb3, 0xec, 0xe1), ++ LL(0x82, 0x82, 0x32, 0x82, 0x64, 0xb0, 0x19, 0xe6), ++ LL(0xd6, 0xd6, 0x7f, 0xd6, 0xfe, 0xa9, 0xb1, 0x28), ++ LL(0x1b, 0x1b, 0x6c, 0x1b, 0xd8, 0x77, 0x36, 0xc3), ++ LL(0xb5, 0xb5, 0xee, 0xb5, 0xc1, 0x5b, 0x77, 0x74), ++ LL(0xaf, 0xaf, 0x86, 0xaf, 0x11, 0x29, 0x43, 0xbe), ++ LL(0x6a, 0x6a, 0xb5, 0x6a, 0x77, 0xdf, 0xd4, 0x1d), ++ LL(0x50, 0x50, 0x5d, 0x50, 0xba, 0x0d, 0xa0, 0xea), ++ LL(0x45, 0x45, 0x09, 0x45, 0x12, 0x4c, 0x8a, 0x57), ++ LL(0xf3, 0xf3, 0xeb, 0xf3, 0xcb, 0x18, 0xfb, 0x38), ++ LL(0x30, 0x30, 0xc0, 0x30, 0x9d, 0xf0, 0x60, 0xad), ++ LL(0xef, 0xef, 0x9b, 0xef, 0x2b, 0x74, 0xc3, 0xc4), ++ LL(0x3f, 0x3f, 0xfc, 0x3f, 0xe5, 0xc3, 0x7e, 0xda), ++ LL(0x55, 0x55, 0x49, 0x55, 0x92, 0x1c, 0xaa, 0xc7), ++ LL(0xa2, 0xa2, 0xb2, 0xa2, 0x79, 0x10, 0x59, 0xdb), ++ LL(0xea, 0xea, 0x8f, 0xea, 0x03, 0x65, 0xc9, 0xe9), ++ LL(0x65, 0x65, 0x89, 0x65, 0x0f, 0xec, 0xca, 0x6a), ++ LL(0xba, 0xba, 0xd2, 0xba, 0xb9, 0x68, 0x69, 0x03), ++ LL(0x2f, 0x2f, 0xbc, 0x2f, 0x65, 0x93, 0x5e, 0x4a), ++ LL(0xc0, 0xc0, 0x27, 0xc0, 0x4e, 0xe7, 0x9d, 0x8e), ++ LL(0xde, 0xde, 0x5f, 0xde, 0xbe, 0x81, 0xa1, 0x60), ++ LL(0x1c, 0x1c, 0x70, 0x1c, 0xe0, 0x6c, 0x38, 0xfc), ++ LL(0xfd, 0xfd, 0xd3, 0xfd, 0xbb, 0x2e, 0xe7, 0x46), ++ LL(0x4d, 0x4d, 0x29, 0x4d, 0x52, 0x64, 0x9a, 0x1f), ++ LL(0x92, 0x92, 0x72, 0x92, 0xe4, 0xe0, 0x39, 0x76), ++ LL(0x75, 0x75, 0xc9, 0x75, 0x8f, 0xbc, 0xea, 0xfa), ++ LL(0x06, 0x06, 0x18, 0x06, 0x30, 0x1e, 0x0c, 0x36), ++ LL(0x8a, 0x8a, 0x12, 0x8a, 0x24, 0x98, 0x09, 0xae), ++ LL(0xb2, 0xb2, 0xf2, 0xb2, 0xf9, 0x40, 0x79, 0x4b), ++ LL(0xe6, 0xe6, 0xbf, 0xe6, 0x63, 0x59, 0xd1, 0x85), ++ LL(0x0e, 0x0e, 0x38, 0x0e, 0x70, 0x36, 0x1c, 0x7e), ++ LL(0x1f, 0x1f, 0x7c, 0x1f, 0xf8, 0x63, 0x3e, 0xe7), ++ LL(0x62, 0x62, 0x95, 0x62, 0x37, 0xf7, 0xc4, 0x55), ++ LL(0xd4, 0xd4, 0x77, 0xd4, 0xee, 0xa3, 0xb5, 0x3a), ++ LL(0xa8, 0xa8, 0x9a, 0xa8, 0x29, 0x32, 0x4d, 0x81), ++ LL(0x96, 0x96, 0x62, 0x96, 0xc4, 0xf4, 0x31, 0x52), ++ LL(0xf9, 0xf9, 0xc3, 0xf9, 0x9b, 0x3a, 0xef, 0x62), ++ LL(0xc5, 0xc5, 0x33, 0xc5, 0x66, 0xf6, 0x97, 0xa3), ++ LL(0x25, 0x25, 0x94, 0x25, 0x35, 0xb1, 0x4a, 0x10), ++ LL(0x59, 0x59, 0x79, 0x59, 0xf2, 0x20, 0xb2, 0xab), ++ LL(0x84, 0x84, 0x2a, 0x84, 0x54, 0xae, 0x15, 0xd0), ++ LL(0x72, 0x72, 0xd5, 0x72, 0xb7, 0xa7, 0xe4, 0xc5), ++ LL(0x39, 0x39, 0xe4, 0x39, 0xd5, 0xdd, 0x72, 0xec), ++ LL(0x4c, 0x4c, 0x2d, 0x4c, 0x5a, 0x61, 0x98, 0x16), ++ LL(0x5e, 0x5e, 0x65, 0x5e, 0xca, 0x3b, 0xbc, 0x94), ++ LL(0x78, 0x78, 0xfd, 0x78, 0xe7, 0x85, 0xf0, 0x9f), ++ LL(0x38, 0x38, 0xe0, 0x38, 0xdd, 0xd8, 0x70, 0xe5), ++ LL(0x8c, 0x8c, 0x0a, 0x8c, 0x14, 0x86, 0x05, 0x98), ++ LL(0xd1, 0xd1, 0x63, 0xd1, 0xc6, 0xb2, 0xbf, 0x17), ++ LL(0xa5, 0xa5, 0xae, 0xa5, 0x41, 0x0b, 0x57, 0xe4), ++ LL(0xe2, 0xe2, 0xaf, 0xe2, 0x43, 0x4d, 0xd9, 0xa1), ++ LL(0x61, 0x61, 0x99, 0x61, 0x2f, 0xf8, 0xc2, 0x4e), ++ LL(0xb3, 0xb3, 0xf6, 0xb3, 0xf1, 0x45, 0x7b, 0x42), ++ LL(0x21, 0x21, 0x84, 0x21, 0x15, 0xa5, 0x42, 0x34), ++ LL(0x9c, 0x9c, 0x4a, 0x9c, 0x94, 0xd6, 0x25, 0x08), ++ LL(0x1e, 0x1e, 0x78, 0x1e, 0xf0, 0x66, 0x3c, 0xee), ++ LL(0x43, 0x43, 0x11, 0x43, 0x22, 0x52, 0x86, 0x61), ++ LL(0xc7, 0xc7, 0x3b, 0xc7, 0x76, 0xfc, 0x93, 0xb1), ++ LL(0xfc, 0xfc, 0xd7, 0xfc, 0xb3, 0x2b, 0xe5, 0x4f), ++ LL(0x04, 0x04, 0x10, 0x04, 0x20, 0x14, 0x08, 0x24), ++ LL(0x51, 0x51, 0x59, 0x51, 0xb2, 0x08, 0xa2, 0xe3), ++ LL(0x99, 0x99, 0x5e, 0x99, 0xbc, 0xc7, 0x2f, 0x25), ++ LL(0x6d, 0x6d, 0xa9, 0x6d, 0x4f, 0xc4, 0xda, 0x22), ++ LL(0x0d, 0x0d, 0x34, 0x0d, 0x68, 0x39, 0x1a, 0x65), ++ LL(0xfa, 0xfa, 0xcf, 0xfa, 0x83, 0x35, 0xe9, 0x79), ++ LL(0xdf, 0xdf, 0x5b, 0xdf, 0xb6, 0x84, 0xa3, 0x69), ++ LL(0x7e, 0x7e, 0xe5, 0x7e, 0xd7, 0x9b, 0xfc, 0xa9), ++ LL(0x24, 0x24, 0x90, 0x24, 0x3d, 0xb4, 0x48, 0x19), ++ LL(0x3b, 0x3b, 0xec, 0x3b, 0xc5, 0xd7, 0x76, 0xfe), ++ LL(0xab, 0xab, 0x96, 0xab, 0x31, 0x3d, 0x4b, 0x9a), ++ LL(0xce, 0xce, 0x1f, 0xce, 0x3e, 0xd1, 0x81, 0xf0), ++ LL(0x11, 0x11, 0x44, 0x11, 0x88, 0x55, 0x22, 0x99), ++ LL(0x8f, 0x8f, 0x06, 0x8f, 0x0c, 0x89, 0x03, 0x83), ++ LL(0x4e, 0x4e, 0x25, 0x4e, 0x4a, 0x6b, 0x9c, 0x04), ++ LL(0xb7, 0xb7, 0xe6, 0xb7, 0xd1, 0x51, 0x73, 0x66), ++ LL(0xeb, 0xeb, 0x8b, 0xeb, 0x0b, 0x60, 0xcb, 0xe0), ++ LL(0x3c, 0x3c, 0xf0, 0x3c, 0xfd, 0xcc, 0x78, 0xc1), ++ LL(0x81, 0x81, 0x3e, 0x81, 0x7c, 0xbf, 0x1f, 0xfd), ++ LL(0x94, 0x94, 0x6a, 0x94, 0xd4, 0xfe, 0x35, 0x40), ++ LL(0xf7, 0xf7, 0xfb, 0xf7, 0xeb, 0x0c, 0xf3, 0x1c), ++ LL(0xb9, 0xb9, 0xde, 0xb9, 0xa1, 0x67, 0x6f, 0x18), ++ LL(0x13, 0x13, 0x4c, 0x13, 0x98, 0x5f, 0x26, 0x8b), ++ LL(0x2c, 0x2c, 0xb0, 0x2c, 0x7d, 0x9c, 0x58, 0x51), ++ LL(0xd3, 0xd3, 0x6b, 0xd3, 0xd6, 0xb8, 0xbb, 0x05), ++ LL(0xe7, 0xe7, 0xbb, 0xe7, 0x6b, 0x5c, 0xd3, 0x8c), ++ LL(0x6e, 0x6e, 0xa5, 0x6e, 0x57, 0xcb, 0xdc, 0x39), ++ LL(0xc4, 0xc4, 0x37, 0xc4, 0x6e, 0xf3, 0x95, 0xaa), ++ LL(0x03, 0x03, 0x0c, 0x03, 0x18, 0x0f, 0x06, 0x1b), ++ LL(0x56, 0x56, 0x45, 0x56, 0x8a, 0x13, 0xac, 0xdc), ++ LL(0x44, 0x44, 0x0d, 0x44, 0x1a, 0x49, 0x88, 0x5e), ++ LL(0x7f, 0x7f, 0xe1, 0x7f, 0xdf, 0x9e, 0xfe, 0xa0), ++ LL(0xa9, 0xa9, 0x9e, 0xa9, 0x21, 0x37, 0x4f, 0x88), ++ LL(0x2a, 0x2a, 0xa8, 0x2a, 0x4d, 0x82, 0x54, 0x67), ++ LL(0xbb, 0xbb, 0xd6, 0xbb, 0xb1, 0x6d, 0x6b, 0x0a), ++ LL(0xc1, 0xc1, 0x23, 0xc1, 0x46, 0xe2, 0x9f, 0x87), ++ LL(0x53, 0x53, 0x51, 0x53, 0xa2, 0x02, 0xa6, 0xf1), ++ LL(0xdc, 0xdc, 0x57, 0xdc, 0xae, 0x8b, 0xa5, 0x72), ++ LL(0x0b, 0x0b, 0x2c, 0x0b, 0x58, 0x27, 0x16, 0x53), ++ LL(0x9d, 0x9d, 0x4e, 0x9d, 0x9c, 0xd3, 0x27, 0x01), ++ LL(0x6c, 0x6c, 0xad, 0x6c, 0x47, 0xc1, 0xd8, 0x2b), ++ LL(0x31, 0x31, 0xc4, 0x31, 0x95, 0xf5, 0x62, 0xa4), ++ LL(0x74, 0x74, 0xcd, 0x74, 0x87, 0xb9, 0xe8, 0xf3), ++ LL(0xf6, 0xf6, 0xff, 0xf6, 0xe3, 0x09, 0xf1, 0x15), ++ LL(0x46, 0x46, 0x05, 0x46, 0x0a, 0x43, 0x8c, 0x4c), ++ LL(0xac, 0xac, 0x8a, 0xac, 0x09, 0x26, 0x45, 0xa5), ++ LL(0x89, 0x89, 0x1e, 0x89, 0x3c, 0x97, 0x0f, 0xb5), ++ LL(0x14, 0x14, 0x50, 0x14, 0xa0, 0x44, 0x28, 0xb4), ++ LL(0xe1, 0xe1, 0xa3, 0xe1, 0x5b, 0x42, 0xdf, 0xba), ++ LL(0x16, 0x16, 0x58, 0x16, 0xb0, 0x4e, 0x2c, 0xa6), ++ LL(0x3a, 0x3a, 0xe8, 0x3a, 0xcd, 0xd2, 0x74, 0xf7), ++ LL(0x69, 0x69, 0xb9, 0x69, 0x6f, 0xd0, 0xd2, 0x06), ++ LL(0x09, 0x09, 0x24, 0x09, 0x48, 0x2d, 0x12, 0x41), ++ LL(0x70, 0x70, 0xdd, 0x70, 0xa7, 0xad, 0xe0, 0xd7), ++ LL(0xb6, 0xb6, 0xe2, 0xb6, 0xd9, 0x54, 0x71, 0x6f), ++ LL(0xd0, 0xd0, 0x67, 0xd0, 0xce, 0xb7, 0xbd, 0x1e), ++ LL(0xed, 0xed, 0x93, 0xed, 0x3b, 0x7e, 0xc7, 0xd6), ++ LL(0xcc, 0xcc, 0x17, 0xcc, 0x2e, 0xdb, 0x85, 0xe2), ++ LL(0x42, 0x42, 0x15, 0x42, 0x2a, 0x57, 0x84, 0x68), ++ LL(0x98, 0x98, 0x5a, 0x98, 0xb4, 0xc2, 0x2d, 0x2c), ++ LL(0xa4, 0xa4, 0xaa, 0xa4, 0x49, 0x0e, 0x55, 0xed), ++ LL(0x28, 0x28, 0xa0, 0x28, 0x5d, 0x88, 0x50, 0x75), ++ LL(0x5c, 0x5c, 0x6d, 0x5c, 0xda, 0x31, 0xb8, 0x86), ++ LL(0xf8, 0xf8, 0xc7, 0xf8, 0x93, 0x3f, 0xed, 0x6b), ++ LL(0x86, 0x86, 0x22, 0x86, 0x44, 0xa4, 0x11, 0xc2), ++#define RC (&(Cx.q[256*N])) ++ 0x18, 0x23, 0xc6, 0xe8, 0x87, 0xb8, 0x01, 0x4f, ++ /* rc[ROUNDS] */ ++ 0x36, 0xa6, 0xd2, 0xf5, 0x79, 0x6f, 0x91, 0x52, 0x60, 0xbc, 0x9b, ++ 0x8e, 0xa3, 0x0c, 0x7b, 0x35, 0x1d, 0xe0, 0xd7, 0xc2, 0x2e, 0x4b, ++ 0xfe, 0x57, 0x15, 0x77, 0x37, 0xe5, 0x9f, 0xf0, 0x4a, 0xda, 0x58, ++ 0xc9, 0x29, 0x0a, 0xb1, 0xa0, 0x6b, 0x85, 0xbd, 0x5d, 0x10, 0xf4, ++ 0xcb, 0x3e, 0x05, 0x67, 0xe4, 0x27, 0x41, 0x8b, 0xa7, 0x7d, 0x95, ++ 0xd8, 0xfb, 0xee, 0x7c, 0x66, 0xdd, 0x17, 0x47, 0x9e, 0xca, 0x2d, ++ 0xbf, 0x07, 0xad, 0x5a, 0x83, 0x33 ++ } ++ }; ++ ++void whirlpool_block(WHIRLPOOL_CTX *ctx, const void *inp, size_t n) ++{ ++ int r; ++ const u8 *p = inp; ++ union { ++ u64 q[8]; ++ u8 c[64]; ++ } S, K, *H = (void *)ctx->H.q; ++ ++#ifdef GO_FOR_MMX ++ GO_FOR_MMX(ctx, inp, n); ++#endif ++ do { ++#ifdef OPENSSL_SMALL_FOOTPRINT ++ u64 L[8]; ++ int i; ++ ++ for (i = 0; i < 64; i++) ++ S.c[i] = (K.c[i] = H->c[i]) ^ p[i]; ++ for (r = 0; r < ROUNDS; r++) { ++ for (i = 0; i < 8; i++) { ++ L[i] = i ? 0 : RC[r]; ++ L[i] ^= C0(K, i) ^ C1(K, (i - 1) & 7) ^ ++ C2(K, (i - 2) & 7) ^ C3(K, (i - 3) & 7) ^ ++ C4(K, (i - 4) & 7) ^ C5(K, (i - 5) & 7) ^ ++ C6(K, (i - 6) & 7) ^ C7(K, (i - 7) & 7); ++ } ++ memcpy(K.q, L, 64); ++ for (i = 0; i < 8; i++) { ++ L[i] ^= C0(S, i) ^ C1(S, (i - 1) & 7) ^ ++ C2(S, (i - 2) & 7) ^ C3(S, (i - 3) & 7) ^ ++ C4(S, (i - 4) & 7) ^ C5(S, (i - 5) & 7) ^ ++ C6(S, (i - 6) & 7) ^ C7(S, (i - 7) & 7); ++ } ++ memcpy(S.q, L, 64); ++ } ++ for (i = 0; i < 64; i++) ++ H->c[i] ^= S.c[i] ^ p[i]; ++#else ++ u64 L0, L1, L2, L3, L4, L5, L6, L7; ++ ++# ifdef STRICT_ALIGNMENT ++ if ((size_t)p & 7) { ++ memcpy(S.c, p, 64); ++ S.q[0] ^= (K.q[0] = H->q[0]); ++ S.q[1] ^= (K.q[1] = H->q[1]); ++ S.q[2] ^= (K.q[2] = H->q[2]); ++ S.q[3] ^= (K.q[3] = H->q[3]); ++ S.q[4] ^= (K.q[4] = H->q[4]); ++ S.q[5] ^= (K.q[5] = H->q[5]); ++ S.q[6] ^= (K.q[6] = H->q[6]); ++ S.q[7] ^= (K.q[7] = H->q[7]); ++ } else ++# endif ++ { ++ const u64 *pa = (const u64 *)p; ++ S.q[0] = (K.q[0] = H->q[0]) ^ pa[0]; ++ S.q[1] = (K.q[1] = H->q[1]) ^ pa[1]; ++ S.q[2] = (K.q[2] = H->q[2]) ^ pa[2]; ++ S.q[3] = (K.q[3] = H->q[3]) ^ pa[3]; ++ S.q[4] = (K.q[4] = H->q[4]) ^ pa[4]; ++ S.q[5] = (K.q[5] = H->q[5]) ^ pa[5]; ++ S.q[6] = (K.q[6] = H->q[6]) ^ pa[6]; ++ S.q[7] = (K.q[7] = H->q[7]) ^ pa[7]; ++ } ++ ++ for (r = 0; r < ROUNDS; r++) { ++# ifdef SMALL_REGISTER_BANK ++ L0 = C0(K, 0) ^ C1(K, 7) ^ C2(K, 6) ^ C3(K, 5) ^ ++ C4(K, 4) ^ C5(K, 3) ^ C6(K, 2) ^ C7(K, 1) ^ RC[r]; ++ L1 = C0(K, 1) ^ C1(K, 0) ^ C2(K, 7) ^ C3(K, 6) ^ ++ C4(K, 5) ^ C5(K, 4) ^ C6(K, 3) ^ C7(K, 2); ++ L2 = C0(K, 2) ^ C1(K, 1) ^ C2(K, 0) ^ C3(K, 7) ^ ++ C4(K, 6) ^ C5(K, 5) ^ C6(K, 4) ^ C7(K, 3); ++ L3 = C0(K, 3) ^ C1(K, 2) ^ C2(K, 1) ^ C3(K, 0) ^ ++ C4(K, 7) ^ C5(K, 6) ^ C6(K, 5) ^ C7(K, 4); ++ L4 = C0(K, 4) ^ C1(K, 3) ^ C2(K, 2) ^ C3(K, 1) ^ ++ C4(K, 0) ^ C5(K, 7) ^ C6(K, 6) ^ C7(K, 5); ++ L5 = C0(K, 5) ^ C1(K, 4) ^ C2(K, 3) ^ C3(K, 2) ^ ++ C4(K, 1) ^ C5(K, 0) ^ C6(K, 7) ^ C7(K, 6); ++ L6 = C0(K, 6) ^ C1(K, 5) ^ C2(K, 4) ^ C3(K, 3) ^ ++ C4(K, 2) ^ C5(K, 1) ^ C6(K, 0) ^ C7(K, 7); ++ L7 = C0(K, 7) ^ C1(K, 6) ^ C2(K, 5) ^ C3(K, 4) ^ ++ C4(K, 3) ^ C5(K, 2) ^ C6(K, 1) ^ C7(K, 0); ++ ++ K.q[0] = L0; ++ K.q[1] = L1; ++ K.q[2] = L2; ++ K.q[3] = L3; ++ K.q[4] = L4; ++ K.q[5] = L5; ++ K.q[6] = L6; ++ K.q[7] = L7; ++ ++ L0 ^= C0(S, 0) ^ C1(S, 7) ^ C2(S, 6) ^ C3(S, 5) ^ ++ C4(S, 4) ^ C5(S, 3) ^ C6(S, 2) ^ C7(S, 1); ++ L1 ^= C0(S, 1) ^ C1(S, 0) ^ C2(S, 7) ^ C3(S, 6) ^ ++ C4(S, 5) ^ C5(S, 4) ^ C6(S, 3) ^ C7(S, 2); ++ L2 ^= C0(S, 2) ^ C1(S, 1) ^ C2(S, 0) ^ C3(S, 7) ^ ++ C4(S, 6) ^ C5(S, 5) ^ C6(S, 4) ^ C7(S, 3); ++ L3 ^= C0(S, 3) ^ C1(S, 2) ^ C2(S, 1) ^ C3(S, 0) ^ ++ C4(S, 7) ^ C5(S, 6) ^ C6(S, 5) ^ C7(S, 4); ++ L4 ^= C0(S, 4) ^ C1(S, 3) ^ C2(S, 2) ^ C3(S, 1) ^ ++ C4(S, 0) ^ C5(S, 7) ^ C6(S, 6) ^ C7(S, 5); ++ L5 ^= C0(S, 5) ^ C1(S, 4) ^ C2(S, 3) ^ C3(S, 2) ^ ++ C4(S, 1) ^ C5(S, 0) ^ C6(S, 7) ^ C7(S, 6); ++ L6 ^= C0(S, 6) ^ C1(S, 5) ^ C2(S, 4) ^ C3(S, 3) ^ ++ C4(S, 2) ^ C5(S, 1) ^ C6(S, 0) ^ C7(S, 7); ++ L7 ^= C0(S, 7) ^ C1(S, 6) ^ C2(S, 5) ^ C3(S, 4) ^ ++ C4(S, 3) ^ C5(S, 2) ^ C6(S, 1) ^ C7(S, 0); ++ ++ S.q[0] = L0; ++ S.q[1] = L1; ++ S.q[2] = L2; ++ S.q[3] = L3; ++ S.q[4] = L4; ++ S.q[5] = L5; ++ S.q[6] = L6; ++ S.q[7] = L7; ++# else ++ L0 = C0(K, 0); ++ L1 = C1(K, 0); ++ L2 = C2(K, 0); ++ L3 = C3(K, 0); ++ L4 = C4(K, 0); ++ L5 = C5(K, 0); ++ L6 = C6(K, 0); ++ L7 = C7(K, 0); ++ L0 ^= RC[r]; ++ ++ L1 ^= C0(K, 1); ++ L2 ^= C1(K, 1); ++ L3 ^= C2(K, 1); ++ L4 ^= C3(K, 1); ++ L5 ^= C4(K, 1); ++ L6 ^= C5(K, 1); ++ L7 ^= C6(K, 1); ++ L0 ^= C7(K, 1); ++ ++ L2 ^= C0(K, 2); ++ L3 ^= C1(K, 2); ++ L4 ^= C2(K, 2); ++ L5 ^= C3(K, 2); ++ L6 ^= C4(K, 2); ++ L7 ^= C5(K, 2); ++ L0 ^= C6(K, 2); ++ L1 ^= C7(K, 2); ++ ++ L3 ^= C0(K, 3); ++ L4 ^= C1(K, 3); ++ L5 ^= C2(K, 3); ++ L6 ^= C3(K, 3); ++ L7 ^= C4(K, 3); ++ L0 ^= C5(K, 3); ++ L1 ^= C6(K, 3); ++ L2 ^= C7(K, 3); ++ ++ L4 ^= C0(K, 4); ++ L5 ^= C1(K, 4); ++ L6 ^= C2(K, 4); ++ L7 ^= C3(K, 4); ++ L0 ^= C4(K, 4); ++ L1 ^= C5(K, 4); ++ L2 ^= C6(K, 4); ++ L3 ^= C7(K, 4); ++ ++ L5 ^= C0(K, 5); ++ L6 ^= C1(K, 5); ++ L7 ^= C2(K, 5); ++ L0 ^= C3(K, 5); ++ L1 ^= C4(K, 5); ++ L2 ^= C5(K, 5); ++ L3 ^= C6(K, 5); ++ L4 ^= C7(K, 5); ++ ++ L6 ^= C0(K, 6); ++ L7 ^= C1(K, 6); ++ L0 ^= C2(K, 6); ++ L1 ^= C3(K, 6); ++ L2 ^= C4(K, 6); ++ L3 ^= C5(K, 6); ++ L4 ^= C6(K, 6); ++ L5 ^= C7(K, 6); ++ ++ L7 ^= C0(K, 7); ++ L0 ^= C1(K, 7); ++ L1 ^= C2(K, 7); ++ L2 ^= C3(K, 7); ++ L3 ^= C4(K, 7); ++ L4 ^= C5(K, 7); ++ L5 ^= C6(K, 7); ++ L6 ^= C7(K, 7); ++ ++ K.q[0] = L0; ++ K.q[1] = L1; ++ K.q[2] = L2; ++ K.q[3] = L3; ++ K.q[4] = L4; ++ K.q[5] = L5; ++ K.q[6] = L6; ++ K.q[7] = L7; ++ ++ L0 ^= C0(S, 0); ++ L1 ^= C1(S, 0); ++ L2 ^= C2(S, 0); ++ L3 ^= C3(S, 0); ++ L4 ^= C4(S, 0); ++ L5 ^= C5(S, 0); ++ L6 ^= C6(S, 0); ++ L7 ^= C7(S, 0); ++ ++ L1 ^= C0(S, 1); ++ L2 ^= C1(S, 1); ++ L3 ^= C2(S, 1); ++ L4 ^= C3(S, 1); ++ L5 ^= C4(S, 1); ++ L6 ^= C5(S, 1); ++ L7 ^= C6(S, 1); ++ L0 ^= C7(S, 1); ++ ++ L2 ^= C0(S, 2); ++ L3 ^= C1(S, 2); ++ L4 ^= C2(S, 2); ++ L5 ^= C3(S, 2); ++ L6 ^= C4(S, 2); ++ L7 ^= C5(S, 2); ++ L0 ^= C6(S, 2); ++ L1 ^= C7(S, 2); ++ ++ L3 ^= C0(S, 3); ++ L4 ^= C1(S, 3); ++ L5 ^= C2(S, 3); ++ L6 ^= C3(S, 3); ++ L7 ^= C4(S, 3); ++ L0 ^= C5(S, 3); ++ L1 ^= C6(S, 3); ++ L2 ^= C7(S, 3); ++ ++ L4 ^= C0(S, 4); ++ L5 ^= C1(S, 4); ++ L6 ^= C2(S, 4); ++ L7 ^= C3(S, 4); ++ L0 ^= C4(S, 4); ++ L1 ^= C5(S, 4); ++ L2 ^= C6(S, 4); ++ L3 ^= C7(S, 4); ++ ++ L5 ^= C0(S, 5); ++ L6 ^= C1(S, 5); ++ L7 ^= C2(S, 5); ++ L0 ^= C3(S, 5); ++ L1 ^= C4(S, 5); ++ L2 ^= C5(S, 5); ++ L3 ^= C6(S, 5); ++ L4 ^= C7(S, 5); ++ ++ L6 ^= C0(S, 6); ++ L7 ^= C1(S, 6); ++ L0 ^= C2(S, 6); ++ L1 ^= C3(S, 6); ++ L2 ^= C4(S, 6); ++ L3 ^= C5(S, 6); ++ L4 ^= C6(S, 6); ++ L5 ^= C7(S, 6); ++ ++ L7 ^= C0(S, 7); ++ L0 ^= C1(S, 7); ++ L1 ^= C2(S, 7); ++ L2 ^= C3(S, 7); ++ L3 ^= C4(S, 7); ++ L4 ^= C5(S, 7); ++ L5 ^= C6(S, 7); ++ L6 ^= C7(S, 7); ++ ++ S.q[0] = L0; ++ S.q[1] = L1; ++ S.q[2] = L2; ++ S.q[3] = L3; ++ S.q[4] = L4; ++ S.q[5] = L5; ++ S.q[6] = L6; ++ S.q[7] = L7; ++# endif ++ } ++ ++# ifdef STRICT_ALIGNMENT ++ if ((size_t)p & 7) { ++ int i; ++ for (i = 0; i < 64; i++) ++ H->c[i] ^= S.c[i] ^ p[i]; ++ } else ++# endif ++ { ++ const u64 *pa = (const u64 *)p; ++ H->q[0] ^= S.q[0] ^ pa[0]; ++ H->q[1] ^= S.q[1] ^ pa[1]; ++ H->q[2] ^= S.q[2] ^ pa[2]; ++ H->q[3] ^= S.q[3] ^ pa[3]; ++ H->q[4] ^= S.q[4] ^ pa[4]; ++ H->q[5] ^= S.q[5] ^ pa[5]; ++ H->q[6] ^= S.q[6] ^ pa[6]; ++ H->q[7] ^= S.q[7] ^ pa[7]; ++ } ++#endif ++ p += 64; ++ } while (--n); ++} +diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/whrlpool/wp_dgst.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/whrlpool/wp_dgst.c +new file mode 100644 +index 0000000..ed06424 +--- /dev/null ++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/whrlpool/wp_dgst.c +@@ -0,0 +1,266 @@ ++/* ++ * Copyright 2005-2016 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 ++ * in the file LICENSE in the source distribution or at ++ * https://www.openssl.org/source/license.html ++ */ ++ ++/** ++ * The Whirlpool hashing function. ++ * ++ *

++ * References ++ * ++ *

++ * The Whirlpool algorithm was developed by ++ * Paulo S. L. M. Barreto and ++ * Vincent Rijmen. ++ * ++ * See ++ * P.S.L.M. Barreto, V. Rijmen, ++ * ``The Whirlpool hashing function,'' ++ * NESSIE submission, 2000 (tweaked version, 2001), ++ * ++ * ++ * Based on "@version 3.0 (2003.03.12)" by Paulo S.L.M. Barreto and ++ * Vincent Rijmen. Lookup "reference implementations" on ++ * ++ * ++ * ============================================================================= ++ * ++ * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ''AS IS'' AND ANY EXPRESS ++ * 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 AUTHORS OR 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. ++ * ++ */ ++ ++/* ++ * OpenSSL-specific implementation notes. ++ * ++ * WHIRLPOOL_Update as well as one-stroke WHIRLPOOL both expect ++ * number of *bytes* as input length argument. Bit-oriented routine ++ * as specified by authors is called WHIRLPOOL_BitUpdate[!] and ++ * does not have one-stroke counterpart. ++ * ++ * WHIRLPOOL_BitUpdate implements byte-oriented loop, essentially ++ * to serve WHIRLPOOL_Update. This is done for performance. ++ * ++ * Unlike authors' reference implementation, block processing ++ * routine whirlpool_block is designed to operate on multi-block ++ * input. This is done for performance. ++ */ ++ ++#include ++#include "wp_locl.h" ++#include ++ ++int WHIRLPOOL_Init(WHIRLPOOL_CTX *c) ++{ ++ memset(c, 0, sizeof(*c)); ++ return (1); ++} ++ ++int WHIRLPOOL_Update(WHIRLPOOL_CTX *c, const void *_inp, size_t bytes) ++{ ++ /* ++ * Well, largest suitable chunk size actually is ++ * (1<<(sizeof(size_t)*8-3))-64, but below number is large enough for not ++ * to care about excessive calls to WHIRLPOOL_BitUpdate... ++ */ ++ size_t chunk = ((size_t)1) << (sizeof(size_t) * 8 - 4); ++ const unsigned char *inp = _inp; ++ ++ while (bytes >= chunk) { ++ WHIRLPOOL_BitUpdate(c, inp, chunk * 8); ++ bytes -= chunk; ++ inp += chunk; ++ } ++ if (bytes) ++ WHIRLPOOL_BitUpdate(c, inp, bytes * 8); ++ ++ return (1); ++} ++ ++void WHIRLPOOL_BitUpdate(WHIRLPOOL_CTX *c, const void *_inp, size_t bits) ++{ ++ size_t n; ++ unsigned int bitoff = c->bitoff, ++ bitrem = bitoff % 8, inpgap = (8 - (unsigned int)bits % 8) & 7; ++ const unsigned char *inp = _inp; ++ ++ /* ++ * This 256-bit increment procedure relies on the size_t being natural ++ * size of CPU register, so that we don't have to mask the value in order ++ * to detect overflows. ++ */ ++ c->bitlen[0] += bits; ++ if (c->bitlen[0] < bits) { /* overflow */ ++ n = 1; ++ do { ++ c->bitlen[n]++; ++ } while (c->bitlen[n] == 0 ++ && ++n < (WHIRLPOOL_COUNTER / sizeof(size_t))); ++ } ++#ifndef OPENSSL_SMALL_FOOTPRINT ++ reconsider: ++ if (inpgap == 0 && bitrem == 0) { /* byte-oriented loop */ ++ while (bits) { ++ if (bitoff == 0 && (n = bits / WHIRLPOOL_BBLOCK)) { ++ whirlpool_block(c, inp, n); ++ inp += n * WHIRLPOOL_BBLOCK / 8; ++ bits %= WHIRLPOOL_BBLOCK; ++ } else { ++ unsigned int byteoff = bitoff / 8; ++ ++ bitrem = WHIRLPOOL_BBLOCK - bitoff; /* re-use bitrem */ ++ if (bits >= bitrem) { ++ bits -= bitrem; ++ bitrem /= 8; ++ memcpy(c->data + byteoff, inp, bitrem); ++ inp += bitrem; ++ whirlpool_block(c, c->data, 1); ++ bitoff = 0; ++ } else { ++ memcpy(c->data + byteoff, inp, bits / 8); ++ bitoff += (unsigned int)bits; ++ bits = 0; ++ } ++ c->bitoff = bitoff; ++ } ++ } ++ } else /* bit-oriented loop */ ++#endif ++ { ++ /*- ++ inp ++ | ++ +-------+-------+------- ++ ||||||||||||||||||||| ++ +-------+-------+------- ++ +-------+-------+-------+-------+------- ++ |||||||||||||| c->data ++ +-------+-------+-------+-------+------- ++ | ++ c->bitoff/8 ++ */ ++ while (bits) { ++ unsigned int byteoff = bitoff / 8; ++ unsigned char b; ++ ++#ifndef OPENSSL_SMALL_FOOTPRINT ++ if (bitrem == inpgap) { ++ c->data[byteoff++] |= inp[0] & (0xff >> inpgap); ++ inpgap = 8 - inpgap; ++ bitoff += inpgap; ++ bitrem = 0; /* bitoff%8 */ ++ bits -= inpgap; ++ inpgap = 0; /* bits%8 */ ++ inp++; ++ if (bitoff == WHIRLPOOL_BBLOCK) { ++ whirlpool_block(c, c->data, 1); ++ bitoff = 0; ++ } ++ c->bitoff = bitoff; ++ goto reconsider; ++ } else ++#endif ++ if (bits >= 8) { ++ b = ((inp[0] << inpgap) | (inp[1] >> (8 - inpgap))); ++ b &= 0xff; ++ if (bitrem) ++ c->data[byteoff++] |= b >> bitrem; ++ else ++ c->data[byteoff++] = b; ++ bitoff += 8; ++ bits -= 8; ++ inp++; ++ if (bitoff >= WHIRLPOOL_BBLOCK) { ++ whirlpool_block(c, c->data, 1); ++ byteoff = 0; ++ bitoff %= WHIRLPOOL_BBLOCK; ++ } ++ if (bitrem) ++ c->data[byteoff] = b << (8 - bitrem); ++ } else { /* remaining less than 8 bits */ ++ ++ b = (inp[0] << inpgap) & 0xff; ++ if (bitrem) ++ c->data[byteoff++] |= b >> bitrem; ++ else ++ c->data[byteoff++] = b; ++ bitoff += (unsigned int)bits; ++ if (bitoff == WHIRLPOOL_BBLOCK) { ++ whirlpool_block(c, c->data, 1); ++ byteoff = 0; ++ bitoff %= WHIRLPOOL_BBLOCK; ++ } ++ if (bitrem) ++ c->data[byteoff] = b << (8 - bitrem); ++ bits = 0; ++ } ++ c->bitoff = bitoff; ++ } ++ } ++} ++ ++int WHIRLPOOL_Final(unsigned char *md, WHIRLPOOL_CTX *c) ++{ ++ unsigned int bitoff = c->bitoff, byteoff = bitoff / 8; ++ size_t i, j, v; ++ unsigned char *p; ++ ++ bitoff %= 8; ++ if (bitoff) ++ c->data[byteoff] |= 0x80 >> bitoff; ++ else ++ c->data[byteoff] = 0x80; ++ byteoff++; ++ ++ /* pad with zeros */ ++ if (byteoff > (WHIRLPOOL_BBLOCK / 8 - WHIRLPOOL_COUNTER)) { ++ if (byteoff < WHIRLPOOL_BBLOCK / 8) ++ memset(&c->data[byteoff], 0, WHIRLPOOL_BBLOCK / 8 - byteoff); ++ whirlpool_block(c, c->data, 1); ++ byteoff = 0; ++ } ++ if (byteoff < (WHIRLPOOL_BBLOCK / 8 - WHIRLPOOL_COUNTER)) ++ memset(&c->data[byteoff], 0, ++ (WHIRLPOOL_BBLOCK / 8 - WHIRLPOOL_COUNTER) - byteoff); ++ /* smash 256-bit c->bitlen in big-endian order */ ++ p = &c->data[WHIRLPOOL_BBLOCK / 8 - 1]; /* last byte in c->data */ ++ for (i = 0; i < WHIRLPOOL_COUNTER / sizeof(size_t); i++) ++ for (v = c->bitlen[i], j = 0; j < sizeof(size_t); j++, v >>= 8) ++ *p-- = (unsigned char)(v & 0xff); ++ ++ whirlpool_block(c, c->data, 1); ++ ++ if (md) { ++ memcpy(md, c->H.c, WHIRLPOOL_DIGEST_LENGTH); ++ OPENSSL_cleanse(c, sizeof(*c)); ++ return (1); ++ } ++ return (0); ++} ++ ++unsigned char *WHIRLPOOL(const void *inp, size_t bytes, unsigned char *md) ++{ ++ WHIRLPOOL_CTX ctx; ++ static unsigned char m[WHIRLPOOL_DIGEST_LENGTH]; ++ ++ if (md == NULL) ++ md = m; ++ WHIRLPOOL_Init(&ctx); ++ WHIRLPOOL_Update(&ctx, inp, bytes); ++ WHIRLPOOL_Final(md, &ctx); ++ return (md); ++} +diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/whrlpool/wp_locl.h b/CryptoPkg/Library/OpensslLib/openssl/crypto/whrlpool/wp_locl.h +new file mode 100644 +index 0000000..3a81cfd +--- /dev/null ++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/whrlpool/wp_locl.h +@@ -0,0 +1,12 @@ ++/* ++ * Copyright 2005-2016 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 ++ * in the file LICENSE in the source distribution or at ++ * https://www.openssl.org/source/license.html ++ */ ++ ++#include ++ ++void whirlpool_block(WHIRLPOOL_CTX *, const void *, size_t); +diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/x509/build.info b/CryptoPkg/Library/OpensslLib/openssl/crypto/x509/build.info +new file mode 100644 +index 0000000..7fc4b45 +--- /dev/null ++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/x509/build.info +@@ -0,0 +1,10 @@ ++LIBS=../../libcrypto ++SOURCE[../../libcrypto]=\ ++ x509_def.c x509_d2.c x509_r2x.c x509_cmp.c \ ++ x509_obj.c x509_req.c x509spki.c x509_vfy.c \ ++ x509_set.c x509cset.c x509rset.c x509_err.c \ ++ x509name.c x509_v3.c x509_ext.c x509_att.c \ ++ x509type.c x509_lu.c x_all.c x509_txt.c \ ++ x509_trs.c by_file.c by_dir.c x509_vpm.c \ ++ x_crl.c t_crl.c x_req.c t_req.c x_x509.c t_x509.c \ ++ x_pubkey.c x_x509a.c x_attrib.c x_exten.c x_name.c +diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/x509/by_dir.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/x509/by_dir.c +new file mode 100644 +index 0000000..f3a1f05 +--- /dev/null ++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/x509/by_dir.c +@@ -0,0 +1,388 @@ ++/* ++ * Copyright 1995-2016 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 ++ * in the file LICENSE in the source distribution or at ++ * https://www.openssl.org/source/license.html ++ */ ++ ++#include ++#include ++#include ++ ++#include "internal/cryptlib.h" ++ ++#ifndef NO_SYS_TYPES_H ++# include ++#endif ++#ifndef OPENSSL_NO_POSIX_IO ++# include ++#endif ++ ++ ++#include ++#include ++#include "internal/x509_int.h" ++#include "x509_lcl.h" ++ ++struct lookup_dir_hashes_st { ++ unsigned long hash; ++ int suffix; ++}; ++ ++struct lookup_dir_entry_st { ++ char *dir; ++ int dir_type; ++ STACK_OF(BY_DIR_HASH) *hashes; ++}; ++ ++typedef struct lookup_dir_st { ++ BUF_MEM *buffer; ++ STACK_OF(BY_DIR_ENTRY) *dirs; ++ CRYPTO_RWLOCK *lock; ++} BY_DIR; ++ ++static int dir_ctrl(X509_LOOKUP *ctx, int cmd, const char *argp, long argl, ++ char **ret); ++static int new_dir(X509_LOOKUP *lu); ++static void free_dir(X509_LOOKUP *lu); ++static int add_cert_dir(BY_DIR *ctx, const char *dir, int type); ++static int get_cert_by_subject(X509_LOOKUP *xl, X509_LOOKUP_TYPE type, ++ X509_NAME *name, X509_OBJECT *ret); ++static X509_LOOKUP_METHOD x509_dir_lookup = { ++ "Load certs from files in a directory", ++ new_dir, /* new */ ++ free_dir, /* free */ ++ NULL, /* init */ ++ NULL, /* shutdown */ ++ dir_ctrl, /* ctrl */ ++ get_cert_by_subject, /* get_by_subject */ ++ NULL, /* get_by_issuer_serial */ ++ NULL, /* get_by_fingerprint */ ++ NULL, /* get_by_alias */ ++}; ++ ++X509_LOOKUP_METHOD *X509_LOOKUP_hash_dir(void) ++{ ++ return (&x509_dir_lookup); ++} ++ ++static int dir_ctrl(X509_LOOKUP *ctx, int cmd, const char *argp, long argl, ++ char **retp) ++{ ++ int ret = 0; ++ BY_DIR *ld; ++ char *dir = NULL; ++ ++ ld = (BY_DIR *)ctx->method_data; ++ ++ switch (cmd) { ++ case X509_L_ADD_DIR: ++ if (argl == X509_FILETYPE_DEFAULT) { ++ dir = (char *)getenv(X509_get_default_cert_dir_env()); ++ if (dir) ++ ret = add_cert_dir(ld, dir, X509_FILETYPE_PEM); ++ else ++ ret = add_cert_dir(ld, X509_get_default_cert_dir(), ++ X509_FILETYPE_PEM); ++ if (!ret) { ++ X509err(X509_F_DIR_CTRL, X509_R_LOADING_CERT_DIR); ++ } ++ } else ++ ret = add_cert_dir(ld, argp, (int)argl); ++ break; ++ } ++ return (ret); ++} ++ ++static int new_dir(X509_LOOKUP *lu) ++{ ++ BY_DIR *a; ++ ++ if ((a = OPENSSL_malloc(sizeof(*a))) == NULL) ++ return 0; ++ if ((a->buffer = BUF_MEM_new()) == NULL) { ++ OPENSSL_free(a); ++ return 0; ++ } ++ a->dirs = NULL; ++ a->lock = CRYPTO_THREAD_lock_new(); ++ if (a->lock == NULL) { ++ BUF_MEM_free(a->buffer); ++ OPENSSL_free(a); ++ return 0; ++ } ++ lu->method_data = (char *)a; ++ return 1; ++} ++ ++static void by_dir_hash_free(BY_DIR_HASH *hash) ++{ ++ OPENSSL_free(hash); ++} ++ ++static int by_dir_hash_cmp(const BY_DIR_HASH *const *a, ++ const BY_DIR_HASH *const *b) ++{ ++ if ((*a)->hash > (*b)->hash) ++ return 1; ++ if ((*a)->hash < (*b)->hash) ++ return -1; ++ return 0; ++} ++ ++static void by_dir_entry_free(BY_DIR_ENTRY *ent) ++{ ++ OPENSSL_free(ent->dir); ++ sk_BY_DIR_HASH_pop_free(ent->hashes, by_dir_hash_free); ++ OPENSSL_free(ent); ++} ++ ++static void free_dir(X509_LOOKUP *lu) ++{ ++ BY_DIR *a; ++ ++ a = (BY_DIR *)lu->method_data; ++ sk_BY_DIR_ENTRY_pop_free(a->dirs, by_dir_entry_free); ++ BUF_MEM_free(a->buffer); ++ CRYPTO_THREAD_lock_free(a->lock); ++ OPENSSL_free(a); ++} ++ ++static int add_cert_dir(BY_DIR *ctx, const char *dir, int type) ++{ ++ const char *s, *p; ++ ++ if (dir == NULL || !*dir) { ++ X509err(X509_F_ADD_CERT_DIR, X509_R_INVALID_DIRECTORY); ++ return 0; ++ } ++ ++ s = dir; ++ p = s; ++ do { ++ if ((*p == LIST_SEPARATOR_CHAR) || (*p == '\0')) { ++ BY_DIR_ENTRY *ent; ++ int j; ++ size_t len; ++ const char *ss = s; ++ s = p + 1; ++ len = p - ss; ++ if (len == 0) ++ continue; ++ for (j = 0; j < sk_BY_DIR_ENTRY_num(ctx->dirs); j++) { ++ ent = sk_BY_DIR_ENTRY_value(ctx->dirs, j); ++ if (strlen(ent->dir) == len && ++ strncmp(ent->dir, ss, len) == 0) ++ break; ++ } ++ if (j < sk_BY_DIR_ENTRY_num(ctx->dirs)) ++ continue; ++ if (ctx->dirs == NULL) { ++ ctx->dirs = sk_BY_DIR_ENTRY_new_null(); ++ if (!ctx->dirs) { ++ X509err(X509_F_ADD_CERT_DIR, ERR_R_MALLOC_FAILURE); ++ return 0; ++ } ++ } ++ ent = OPENSSL_malloc(sizeof(*ent)); ++ if (ent == NULL) ++ return 0; ++ ent->dir_type = type; ++ ent->hashes = sk_BY_DIR_HASH_new(by_dir_hash_cmp); ++ ent->dir = OPENSSL_strndup(ss, len); ++ if (ent->dir == NULL || ent->hashes == NULL) { ++ by_dir_entry_free(ent); ++ return 0; ++ } ++ if (!sk_BY_DIR_ENTRY_push(ctx->dirs, ent)) { ++ by_dir_entry_free(ent); ++ return 0; ++ } ++ } ++ } while (*p++ != '\0'); ++ return 1; ++} ++ ++static int get_cert_by_subject(X509_LOOKUP *xl, X509_LOOKUP_TYPE type, ++ X509_NAME *name, X509_OBJECT *ret) ++{ ++ BY_DIR *ctx; ++ union { ++ X509 st_x509; ++ X509_CRL crl; ++ } data; ++ int ok = 0; ++ int i, j, k; ++ unsigned long h; ++ BUF_MEM *b = NULL; ++ X509_OBJECT stmp, *tmp; ++ const char *postfix = ""; ++ ++ if (name == NULL) ++ return (0); ++ ++ stmp.type = type; ++ if (type == X509_LU_X509) { ++ data.st_x509.cert_info.subject = name; ++ stmp.data.x509 = &data.st_x509; ++ postfix = ""; ++ } else if (type == X509_LU_CRL) { ++ data.crl.crl.issuer = name; ++ stmp.data.crl = &data.crl; ++ postfix = "r"; ++ } else { ++ X509err(X509_F_GET_CERT_BY_SUBJECT, X509_R_WRONG_LOOKUP_TYPE); ++ goto finish; ++ } ++ ++ if ((b = BUF_MEM_new()) == NULL) { ++ X509err(X509_F_GET_CERT_BY_SUBJECT, ERR_R_BUF_LIB); ++ goto finish; ++ } ++ ++ ctx = (BY_DIR *)xl->method_data; ++ ++ h = X509_NAME_hash(name); ++ for (i = 0; i < sk_BY_DIR_ENTRY_num(ctx->dirs); i++) { ++ BY_DIR_ENTRY *ent; ++ int idx; ++ BY_DIR_HASH htmp, *hent; ++ ent = sk_BY_DIR_ENTRY_value(ctx->dirs, i); ++ j = strlen(ent->dir) + 1 + 8 + 6 + 1 + 1; ++ if (!BUF_MEM_grow(b, j)) { ++ X509err(X509_F_GET_CERT_BY_SUBJECT, ERR_R_MALLOC_FAILURE); ++ goto finish; ++ } ++ if (type == X509_LU_CRL && ent->hashes) { ++ htmp.hash = h; ++ CRYPTO_THREAD_read_lock(ctx->lock); ++ idx = sk_BY_DIR_HASH_find(ent->hashes, &htmp); ++ if (idx >= 0) { ++ hent = sk_BY_DIR_HASH_value(ent->hashes, idx); ++ k = hent->suffix; ++ } else { ++ hent = NULL; ++ k = 0; ++ } ++ CRYPTO_THREAD_unlock(ctx->lock); ++ } else { ++ k = 0; ++ hent = NULL; ++ } ++ for (;;) { ++ char c = '/'; ++#ifdef OPENSSL_SYS_VMS ++ c = ent->dir[strlen(ent->dir) - 1]; ++ if (c != ':' && c != '>' && c != ']') { ++ /* ++ * If no separator is present, we assume the directory ++ * specifier is a logical name, and add a colon. We really ++ * should use better VMS routines for merging things like ++ * this, but this will do for now... -- Richard Levitte ++ */ ++ c = ':'; ++ } else { ++ c = '\0'; ++ } ++#endif ++ if (c == '\0') { ++ /* ++ * This is special. When c == '\0', no directory separator ++ * should be added. ++ */ ++ BIO_snprintf(b->data, b->max, ++ "%s%08lx.%s%d", ent->dir, h, postfix, k); ++ } else { ++ BIO_snprintf(b->data, b->max, ++ "%s%c%08lx.%s%d", ent->dir, c, h, postfix, k); ++ } ++#ifndef OPENSSL_NO_POSIX_IO ++# ifdef _WIN32 ++# define stat _stat ++# endif ++ { ++ struct stat st; ++ if (stat(b->data, &st) < 0) ++ break; ++ } ++#endif ++ /* found one. */ ++ if (type == X509_LU_X509) { ++ if ((X509_load_cert_file(xl, b->data, ent->dir_type)) == 0) ++ break; ++ } else if (type == X509_LU_CRL) { ++ if ((X509_load_crl_file(xl, b->data, ent->dir_type)) == 0) ++ break; ++ } ++ /* else case will caught higher up */ ++ k++; ++ } ++ ++ /* ++ * we have added it to the cache so now pull it out again ++ */ ++ CRYPTO_THREAD_write_lock(ctx->lock); ++ j = sk_X509_OBJECT_find(xl->store_ctx->objs, &stmp); ++ if (j != -1) ++ tmp = sk_X509_OBJECT_value(xl->store_ctx->objs, j); ++ else ++ tmp = NULL; ++ CRYPTO_THREAD_unlock(ctx->lock); ++ ++ /* If a CRL, update the last file suffix added for this */ ++ ++ if (type == X509_LU_CRL) { ++ CRYPTO_THREAD_write_lock(ctx->lock); ++ /* ++ * Look for entry again in case another thread added an entry ++ * first. ++ */ ++ if (!hent) { ++ htmp.hash = h; ++ idx = sk_BY_DIR_HASH_find(ent->hashes, &htmp); ++ if (idx >= 0) ++ hent = sk_BY_DIR_HASH_value(ent->hashes, idx); ++ } ++ if (!hent) { ++ hent = OPENSSL_malloc(sizeof(*hent)); ++ if (hent == NULL) { ++ CRYPTO_THREAD_unlock(ctx->lock); ++ X509err(X509_F_GET_CERT_BY_SUBJECT, ERR_R_MALLOC_FAILURE); ++ ok = 0; ++ goto finish; ++ } ++ hent->hash = h; ++ hent->suffix = k; ++ if (!sk_BY_DIR_HASH_push(ent->hashes, hent)) { ++ CRYPTO_THREAD_unlock(ctx->lock); ++ OPENSSL_free(hent); ++ ok = 0; ++ goto finish; ++ } ++ } else if (hent->suffix < k) { ++ hent->suffix = k; ++ } ++ ++ CRYPTO_THREAD_unlock(ctx->lock); ++ ++ } ++ ++ if (tmp != NULL) { ++ ok = 1; ++ ret->type = tmp->type; ++ memcpy(&ret->data, &tmp->data, sizeof(ret->data)); ++ /* ++ * If we were going to up the reference count, we would need to ++ * do it on a perl 'type' basis ++ */ ++ /*- CRYPTO_add(&tmp->data.x509->references,1, ++ CRYPTO_LOCK_X509);*/ ++ goto finish; ++ } ++ } ++ finish: ++ BUF_MEM_free(b); ++ return (ok); ++} +diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/x509/by_file.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/x509/by_file.c +new file mode 100644 +index 0000000..4376bed +--- /dev/null ++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/x509/by_file.c +@@ -0,0 +1,221 @@ ++/* ++ * Copyright 1995-2016 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 ++ * in the file LICENSE in the source distribution or at ++ * https://www.openssl.org/source/license.html ++ */ ++ ++#include ++#include ++#include ++ ++#include "internal/cryptlib.h" ++#include ++#include ++#include ++#include ++#include "x509_lcl.h" ++ ++static int by_file_ctrl(X509_LOOKUP *ctx, int cmd, const char *argc, ++ long argl, char **ret); ++static X509_LOOKUP_METHOD x509_file_lookup = { ++ "Load file into cache", ++ NULL, /* new */ ++ NULL, /* free */ ++ NULL, /* init */ ++ NULL, /* shutdown */ ++ by_file_ctrl, /* ctrl */ ++ NULL, /* get_by_subject */ ++ NULL, /* get_by_issuer_serial */ ++ NULL, /* get_by_fingerprint */ ++ NULL, /* get_by_alias */ ++}; ++ ++X509_LOOKUP_METHOD *X509_LOOKUP_file(void) ++{ ++ return (&x509_file_lookup); ++} ++ ++static int by_file_ctrl(X509_LOOKUP *ctx, int cmd, const char *argp, ++ long argl, char **ret) ++{ ++ int ok = 0; ++ char *file; ++ ++ switch (cmd) { ++ case X509_L_FILE_LOAD: ++ if (argl == X509_FILETYPE_DEFAULT) { ++ file = (char *)getenv(X509_get_default_cert_file_env()); ++ if (file) ++ ok = (X509_load_cert_crl_file(ctx, file, ++ X509_FILETYPE_PEM) != 0); ++ ++ else ++ ok = (X509_load_cert_crl_file ++ (ctx, X509_get_default_cert_file(), ++ X509_FILETYPE_PEM) != 0); ++ ++ if (!ok) { ++ X509err(X509_F_BY_FILE_CTRL, X509_R_LOADING_DEFAULTS); ++ } ++ } else { ++ if (argl == X509_FILETYPE_PEM) ++ ok = (X509_load_cert_crl_file(ctx, argp, ++ X509_FILETYPE_PEM) != 0); ++ else ++ ok = (X509_load_cert_file(ctx, argp, (int)argl) != 0); ++ } ++ break; ++ } ++ return (ok); ++} ++ ++int X509_load_cert_file(X509_LOOKUP *ctx, const char *file, int type) ++{ ++ int ret = 0; ++ BIO *in = NULL; ++ int i, count = 0; ++ X509 *x = NULL; ++ ++ if (file == NULL) ++ return (1); ++ in = BIO_new(BIO_s_file()); ++ ++ if ((in == NULL) || (BIO_read_filename(in, file) <= 0)) { ++ X509err(X509_F_X509_LOAD_CERT_FILE, ERR_R_SYS_LIB); ++ goto err; ++ } ++ ++ if (type == X509_FILETYPE_PEM) { ++ for (;;) { ++ x = PEM_read_bio_X509_AUX(in, NULL, NULL, NULL); ++ if (x == NULL) { ++ if ((ERR_GET_REASON(ERR_peek_last_error()) == ++ PEM_R_NO_START_LINE) && (count > 0)) { ++ ERR_clear_error(); ++ break; ++ } else { ++ X509err(X509_F_X509_LOAD_CERT_FILE, ERR_R_PEM_LIB); ++ goto err; ++ } ++ } ++ i = X509_STORE_add_cert(ctx->store_ctx, x); ++ if (!i) ++ goto err; ++ count++; ++ X509_free(x); ++ x = NULL; ++ } ++ ret = count; ++ } else if (type == X509_FILETYPE_ASN1) { ++ x = d2i_X509_bio(in, NULL); ++ if (x == NULL) { ++ X509err(X509_F_X509_LOAD_CERT_FILE, ERR_R_ASN1_LIB); ++ goto err; ++ } ++ i = X509_STORE_add_cert(ctx->store_ctx, x); ++ if (!i) ++ goto err; ++ ret = i; ++ } else { ++ X509err(X509_F_X509_LOAD_CERT_FILE, X509_R_BAD_X509_FILETYPE); ++ goto err; ++ } ++ err: ++ X509_free(x); ++ BIO_free(in); ++ return (ret); ++} ++ ++int X509_load_crl_file(X509_LOOKUP *ctx, const char *file, int type) ++{ ++ int ret = 0; ++ BIO *in = NULL; ++ int i, count = 0; ++ X509_CRL *x = NULL; ++ ++ if (file == NULL) ++ return (1); ++ in = BIO_new(BIO_s_file()); ++ ++ if ((in == NULL) || (BIO_read_filename(in, file) <= 0)) { ++ X509err(X509_F_X509_LOAD_CRL_FILE, ERR_R_SYS_LIB); ++ goto err; ++ } ++ ++ if (type == X509_FILETYPE_PEM) { ++ for (;;) { ++ x = PEM_read_bio_X509_CRL(in, NULL, NULL, NULL); ++ if (x == NULL) { ++ if ((ERR_GET_REASON(ERR_peek_last_error()) == ++ PEM_R_NO_START_LINE) && (count > 0)) { ++ ERR_clear_error(); ++ break; ++ } else { ++ X509err(X509_F_X509_LOAD_CRL_FILE, ERR_R_PEM_LIB); ++ goto err; ++ } ++ } ++ i = X509_STORE_add_crl(ctx->store_ctx, x); ++ if (!i) ++ goto err; ++ count++; ++ X509_CRL_free(x); ++ x = NULL; ++ } ++ ret = count; ++ } else if (type == X509_FILETYPE_ASN1) { ++ x = d2i_X509_CRL_bio(in, NULL); ++ if (x == NULL) { ++ X509err(X509_F_X509_LOAD_CRL_FILE, ERR_R_ASN1_LIB); ++ goto err; ++ } ++ i = X509_STORE_add_crl(ctx->store_ctx, x); ++ if (!i) ++ goto err; ++ ret = i; ++ } else { ++ X509err(X509_F_X509_LOAD_CRL_FILE, X509_R_BAD_X509_FILETYPE); ++ goto err; ++ } ++ err: ++ X509_CRL_free(x); ++ BIO_free(in); ++ return (ret); ++} ++ ++int X509_load_cert_crl_file(X509_LOOKUP *ctx, const char *file, int type) ++{ ++ STACK_OF(X509_INFO) *inf; ++ X509_INFO *itmp; ++ BIO *in; ++ int i, count = 0; ++ if (type != X509_FILETYPE_PEM) ++ return X509_load_cert_file(ctx, file, type); ++ in = BIO_new_file(file, "r"); ++ if (!in) { ++ X509err(X509_F_X509_LOAD_CERT_CRL_FILE, ERR_R_SYS_LIB); ++ return 0; ++ } ++ inf = PEM_X509_INFO_read_bio(in, NULL, NULL, NULL); ++ BIO_free(in); ++ if (!inf) { ++ X509err(X509_F_X509_LOAD_CERT_CRL_FILE, ERR_R_PEM_LIB); ++ return 0; ++ } ++ for (i = 0; i < sk_X509_INFO_num(inf); i++) { ++ itmp = sk_X509_INFO_value(inf, i); ++ if (itmp->x509) { ++ X509_STORE_add_cert(ctx->store_ctx, itmp->x509); ++ count++; ++ } ++ if (itmp->crl) { ++ X509_STORE_add_crl(ctx->store_ctx, itmp->crl); ++ count++; ++ } ++ } ++ sk_X509_INFO_pop_free(inf, X509_INFO_free); ++ return count; ++} +diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/x509/t_crl.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/x509/t_crl.c +new file mode 100644 +index 0000000..f3ca6db +--- /dev/null ++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/x509/t_crl.c +@@ -0,0 +1,89 @@ ++/* ++ * Copyright 1999-2016 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 ++ * in the file LICENSE in the source distribution or at ++ * https://www.openssl.org/source/license.html ++ */ ++ ++#include ++#include "internal/cryptlib.h" ++#include ++#include ++#include ++#include ++#include ++ ++#ifndef OPENSSL_NO_STDIO ++int X509_CRL_print_fp(FILE *fp, X509_CRL *x) ++{ ++ BIO *b; ++ int ret; ++ ++ if ((b = BIO_new(BIO_s_file())) == NULL) { ++ X509err(X509_F_X509_CRL_PRINT_FP, ERR_R_BUF_LIB); ++ return (0); ++ } ++ BIO_set_fp(b, fp, BIO_NOCLOSE); ++ ret = X509_CRL_print(b, x); ++ BIO_free(b); ++ return (ret); ++} ++#endif ++ ++int X509_CRL_print(BIO *out, X509_CRL *x) ++{ ++ STACK_OF(X509_REVOKED) *rev; ++ X509_REVOKED *r; ++ const X509_ALGOR *sig_alg; ++ const ASN1_BIT_STRING *sig; ++ long l; ++ int i; ++ char *p; ++ ++ BIO_printf(out, "Certificate Revocation List (CRL):\n"); ++ l = X509_CRL_get_version(x); ++ if (l >= 0 && l <= 1) ++ BIO_printf(out, "%8sVersion %ld (0x%lx)\n", "", l + 1, (unsigned long)l); ++ else ++ BIO_printf(out, "%8sVersion unknown (%ld)\n", "", l); ++ X509_CRL_get0_signature(x, &sig, &sig_alg); ++ X509_signature_print(out, sig_alg, NULL); ++ p = X509_NAME_oneline(X509_CRL_get_issuer(x), NULL, 0); ++ BIO_printf(out, "%8sIssuer: %s\n", "", p); ++ OPENSSL_free(p); ++ BIO_printf(out, "%8sLast Update: ", ""); ++ ASN1_TIME_print(out, X509_CRL_get0_lastUpdate(x)); ++ BIO_printf(out, "\n%8sNext Update: ", ""); ++ if (X509_CRL_get0_nextUpdate(x)) ++ ASN1_TIME_print(out, X509_CRL_get0_nextUpdate(x)); ++ else ++ BIO_printf(out, "NONE"); ++ BIO_printf(out, "\n"); ++ ++ X509V3_extensions_print(out, "CRL extensions", ++ X509_CRL_get0_extensions(x), 0, 8); ++ ++ rev = X509_CRL_get_REVOKED(x); ++ ++ if (sk_X509_REVOKED_num(rev) > 0) ++ BIO_printf(out, "Revoked Certificates:\n"); ++ else ++ BIO_printf(out, "No Revoked Certificates.\n"); ++ ++ for (i = 0; i < sk_X509_REVOKED_num(rev); i++) { ++ r = sk_X509_REVOKED_value(rev, i); ++ BIO_printf(out, " Serial Number: "); ++ i2a_ASN1_INTEGER(out, X509_REVOKED_get0_serialNumber(r)); ++ BIO_printf(out, "\n Revocation Date: "); ++ ASN1_TIME_print(out, X509_REVOKED_get0_revocationDate(r)); ++ BIO_printf(out, "\n"); ++ X509V3_extensions_print(out, "CRL entry extensions", ++ X509_REVOKED_get0_extensions(r), 0, 8); ++ } ++ X509_signature_print(out, sig_alg, sig); ++ ++ return 1; ++ ++} +diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/x509/t_req.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/x509/t_req.c +new file mode 100644 +index 0000000..77ce810 +--- /dev/null ++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/x509/t_req.c +@@ -0,0 +1,198 @@ ++/* ++ * Copyright 1995-2016 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 ++ * in the file LICENSE in the source distribution or at ++ * https://www.openssl.org/source/license.html ++ */ ++ ++#include ++#include "internal/cryptlib.h" ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#ifndef OPENSSL_NO_STDIO ++int X509_REQ_print_fp(FILE *fp, X509_REQ *x) ++{ ++ BIO *b; ++ int ret; ++ ++ if ((b = BIO_new(BIO_s_file())) == NULL) { ++ X509err(X509_F_X509_REQ_PRINT_FP, ERR_R_BUF_LIB); ++ return (0); ++ } ++ BIO_set_fp(b, fp, BIO_NOCLOSE); ++ ret = X509_REQ_print(b, x); ++ BIO_free(b); ++ return (ret); ++} ++#endif ++ ++int X509_REQ_print_ex(BIO *bp, X509_REQ *x, unsigned long nmflags, ++ unsigned long cflag) ++{ ++ long l; ++ int i; ++ EVP_PKEY *pkey; ++ STACK_OF(X509_EXTENSION) *exts; ++ char mlch = ' '; ++ int nmindent = 0; ++ ++ if ((nmflags & XN_FLAG_SEP_MASK) == XN_FLAG_SEP_MULTILINE) { ++ mlch = '\n'; ++ nmindent = 12; ++ } ++ ++ if (nmflags == X509_FLAG_COMPAT) ++ nmindent = 16; ++ ++ if (!(cflag & X509_FLAG_NO_HEADER)) { ++ if (BIO_write(bp, "Certificate Request:\n", 21) <= 0) ++ goto err; ++ if (BIO_write(bp, " Data:\n", 10) <= 0) ++ goto err; ++ } ++ if (!(cflag & X509_FLAG_NO_VERSION)) { ++ l = X509_REQ_get_version(x); ++ if (l >= 0 && l <= 2) { ++ if (BIO_printf(bp, "%8sVersion: %ld (0x%lx)\n", "", l + 1, (unsigned long)l) <= 0) ++ goto err; ++ } else { ++ if (BIO_printf(bp, "%8sVersion: Unknown (%ld)\n", "", l) <= 0) ++ goto err; ++ } ++ } ++ if (!(cflag & X509_FLAG_NO_SUBJECT)) { ++ if (BIO_printf(bp, " Subject:%c", mlch) <= 0) ++ goto err; ++ if (X509_NAME_print_ex(bp, X509_REQ_get_subject_name(x), ++ nmindent, nmflags) < 0) ++ goto err; ++ if (BIO_write(bp, "\n", 1) <= 0) ++ goto err; ++ } ++ if (!(cflag & X509_FLAG_NO_PUBKEY)) { ++ X509_PUBKEY *xpkey; ++ ASN1_OBJECT *koid; ++ if (BIO_write(bp, " Subject Public Key Info:\n", 33) <= 0) ++ goto err; ++ if (BIO_printf(bp, "%12sPublic Key Algorithm: ", "") <= 0) ++ goto err; ++ xpkey = X509_REQ_get_X509_PUBKEY(x); ++ X509_PUBKEY_get0_param(&koid, NULL, NULL, NULL, xpkey); ++ if (i2a_ASN1_OBJECT(bp, koid) <= 0) ++ goto err; ++ if (BIO_puts(bp, "\n") <= 0) ++ goto err; ++ ++ pkey = X509_REQ_get0_pubkey(x); ++ if (pkey == NULL) { ++ BIO_printf(bp, "%12sUnable to load Public Key\n", ""); ++ ERR_print_errors(bp); ++ } else { ++ EVP_PKEY_print_public(bp, pkey, 16, NULL); ++ } ++ } ++ ++ if (!(cflag & X509_FLAG_NO_ATTRIBUTES)) { ++ /* may not be */ ++ if (BIO_printf(bp, "%8sAttributes:\n", "") <= 0) ++ goto err; ++ ++ if (X509_REQ_get_attr_count(x) == 0) { ++ if (BIO_printf(bp, "%12sa0:00\n", "") <= 0) ++ goto err; ++ } else { ++ for (i = 0; i < X509_REQ_get_attr_count(x); i++) { ++ ASN1_TYPE *at; ++ X509_ATTRIBUTE *a; ++ ASN1_BIT_STRING *bs = NULL; ++ ASN1_OBJECT *aobj; ++ int j, type = 0, count = 1, ii = 0; ++ ++ a = X509_REQ_get_attr(x, i); ++ aobj = X509_ATTRIBUTE_get0_object(a); ++ if (X509_REQ_extension_nid(OBJ_obj2nid(aobj))) ++ continue; ++ if (BIO_printf(bp, "%12s", "") <= 0) ++ goto err; ++ if ((j = i2a_ASN1_OBJECT(bp, aobj)) > 0) { ++ ii = 0; ++ count = X509_ATTRIBUTE_count(a); ++ get_next: ++ at = X509_ATTRIBUTE_get0_type(a, ii); ++ type = at->type; ++ bs = at->value.asn1_string; ++ } ++ for (j = 25 - j; j > 0; j--) ++ if (BIO_write(bp, " ", 1) != 1) ++ goto err; ++ if (BIO_puts(bp, ":") <= 0) ++ goto err; ++ if ((type == V_ASN1_PRINTABLESTRING) || ++ (type == V_ASN1_T61STRING) || ++ (type == V_ASN1_UTF8STRING) || ++ (type == V_ASN1_IA5STRING)) { ++ if (BIO_write(bp, (char *)bs->data, bs->length) ++ != bs->length) ++ goto err; ++ BIO_puts(bp, "\n"); ++ } else { ++ BIO_puts(bp, "unable to print attribute\n"); ++ } ++ if (++ii < count) ++ goto get_next; ++ } ++ } ++ } ++ if (!(cflag & X509_FLAG_NO_EXTENSIONS)) { ++ exts = X509_REQ_get_extensions(x); ++ if (exts) { ++ BIO_printf(bp, "%8sRequested Extensions:\n", ""); ++ for (i = 0; i < sk_X509_EXTENSION_num(exts); i++) { ++ ASN1_OBJECT *obj; ++ X509_EXTENSION *ex; ++ int critical; ++ ex = sk_X509_EXTENSION_value(exts, i); ++ if (BIO_printf(bp, "%12s", "") <= 0) ++ goto err; ++ obj = X509_EXTENSION_get_object(ex); ++ i2a_ASN1_OBJECT(bp, obj); ++ critical = X509_EXTENSION_get_critical(ex); ++ if (BIO_printf(bp, ": %s\n", critical ? "critical" : "") <= 0) ++ goto err; ++ if (!X509V3_EXT_print(bp, ex, cflag, 16)) { ++ BIO_printf(bp, "%16s", ""); ++ ASN1_STRING_print(bp, X509_EXTENSION_get_data(ex)); ++ } ++ if (BIO_write(bp, "\n", 1) <= 0) ++ goto err; ++ } ++ sk_X509_EXTENSION_pop_free(exts, X509_EXTENSION_free); ++ } ++ } ++ ++ if (!(cflag & X509_FLAG_NO_SIGDUMP)) { ++ const X509_ALGOR *sig_alg; ++ const ASN1_BIT_STRING *sig; ++ X509_REQ_get0_signature(x, &sig, &sig_alg); ++ if (!X509_signature_print(bp, sig_alg, sig)) ++ goto err; ++ } ++ ++ return (1); ++ err: ++ X509err(X509_F_X509_REQ_PRINT_EX, ERR_R_BUF_LIB); ++ return (0); ++} ++ ++int X509_REQ_print(BIO *bp, X509_REQ *x) ++{ ++ return X509_REQ_print_ex(bp, x, XN_FLAG_COMPAT, X509_FLAG_COMPAT); ++} +diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/x509/t_x509.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/x509/t_x509.c +new file mode 100644 +index 0000000..eb65d88 +--- /dev/null ++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/x509/t_x509.c +@@ -0,0 +1,376 @@ ++/* ++ * Copyright 1995-2016 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 ++ * in the file LICENSE in the source distribution or at ++ * https://www.openssl.org/source/license.html ++ */ ++ ++#include ++#include "internal/cryptlib.h" ++#include ++#include ++#include ++#include ++#include ++#include "internal/asn1_int.h" ++ ++#ifndef OPENSSL_NO_STDIO ++int X509_print_fp(FILE *fp, X509 *x) ++{ ++ return X509_print_ex_fp(fp, x, XN_FLAG_COMPAT, X509_FLAG_COMPAT); ++} ++ ++int X509_print_ex_fp(FILE *fp, X509 *x, unsigned long nmflag, ++ unsigned long cflag) ++{ ++ BIO *b; ++ int ret; ++ ++ if ((b = BIO_new(BIO_s_file())) == NULL) { ++ X509err(X509_F_X509_PRINT_EX_FP, ERR_R_BUF_LIB); ++ return (0); ++ } ++ BIO_set_fp(b, fp, BIO_NOCLOSE); ++ ret = X509_print_ex(b, x, nmflag, cflag); ++ BIO_free(b); ++ return (ret); ++} ++#endif ++ ++int X509_print(BIO *bp, X509 *x) ++{ ++ return X509_print_ex(bp, x, XN_FLAG_COMPAT, X509_FLAG_COMPAT); ++} ++ ++int X509_print_ex(BIO *bp, X509 *x, unsigned long nmflags, ++ unsigned long cflag) ++{ ++ long l; ++ int ret = 0, i; ++ char *m = NULL, mlch = ' '; ++ int nmindent = 0; ++ ASN1_INTEGER *bs; ++ EVP_PKEY *pkey = NULL; ++ const char *neg; ++ ++ if ((nmflags & XN_FLAG_SEP_MASK) == XN_FLAG_SEP_MULTILINE) { ++ mlch = '\n'; ++ nmindent = 12; ++ } ++ ++ if (nmflags == X509_FLAG_COMPAT) ++ nmindent = 16; ++ ++ if (!(cflag & X509_FLAG_NO_HEADER)) { ++ if (BIO_write(bp, "Certificate:\n", 13) <= 0) ++ goto err; ++ if (BIO_write(bp, " Data:\n", 10) <= 0) ++ goto err; ++ } ++ if (!(cflag & X509_FLAG_NO_VERSION)) { ++ l = X509_get_version(x); ++ if (l >= 0 && l <= 2) { ++ if (BIO_printf(bp, "%8sVersion: %ld (0x%lx)\n", "", l + 1, (unsigned long)l) <= 0) ++ goto err; ++ } else { ++ if (BIO_printf(bp, "%8sVersion: Unknown (%ld)\n", "", l) <= 0) ++ goto err; ++ } ++ } ++ if (!(cflag & X509_FLAG_NO_SERIAL)) { ++ ++ if (BIO_write(bp, " Serial Number:", 22) <= 0) ++ goto err; ++ ++ bs = X509_get_serialNumber(x); ++ if (bs->length <= (int)sizeof(long)) { ++ ERR_set_mark(); ++ l = ASN1_INTEGER_get(bs); ++ ERR_pop_to_mark(); ++ } else { ++ l = -1; ++ } ++ if (l != -1) { ++ unsigned long ul; ++ if (bs->type == V_ASN1_NEG_INTEGER) { ++ ul = 0 - (unsigned long)l; ++ neg = "-"; ++ } else { ++ ul = l; ++ neg = ""; ++ } ++ if (BIO_printf(bp, " %s%lu (%s0x%lx)\n", neg, ul, neg, ul) <= 0) ++ goto err; ++ } else { ++ neg = (bs->type == V_ASN1_NEG_INTEGER) ? " (Negative)" : ""; ++ if (BIO_printf(bp, "\n%12s%s", "", neg) <= 0) ++ goto err; ++ ++ for (i = 0; i < bs->length; i++) { ++ if (BIO_printf(bp, "%02x%c", bs->data[i], ++ ((i + 1 == bs->length) ? '\n' : ':')) <= 0) ++ goto err; ++ } ++ } ++ ++ } ++ ++ if (!(cflag & X509_FLAG_NO_SIGNAME)) { ++ const X509_ALGOR *tsig_alg = X509_get0_tbs_sigalg(x); ++ if (X509_signature_print(bp, tsig_alg, NULL) <= 0) ++ goto err; ++ } ++ ++ if (!(cflag & X509_FLAG_NO_ISSUER)) { ++ if (BIO_printf(bp, " Issuer:%c", mlch) <= 0) ++ goto err; ++ if (X509_NAME_print_ex(bp, X509_get_issuer_name(x), nmindent, nmflags) ++ < 0) ++ goto err; ++ if (BIO_write(bp, "\n", 1) <= 0) ++ goto err; ++ } ++ if (!(cflag & X509_FLAG_NO_VALIDITY)) { ++ if (BIO_write(bp, " Validity\n", 17) <= 0) ++ goto err; ++ if (BIO_write(bp, " Not Before: ", 24) <= 0) ++ goto err; ++ if (!ASN1_TIME_print(bp, X509_get0_notBefore(x))) ++ goto err; ++ if (BIO_write(bp, "\n Not After : ", 25) <= 0) ++ goto err; ++ if (!ASN1_TIME_print(bp, X509_get0_notAfter(x))) ++ goto err; ++ if (BIO_write(bp, "\n", 1) <= 0) ++ goto err; ++ } ++ if (!(cflag & X509_FLAG_NO_SUBJECT)) { ++ if (BIO_printf(bp, " Subject:%c", mlch) <= 0) ++ goto err; ++ if (X509_NAME_print_ex ++ (bp, X509_get_subject_name(x), nmindent, nmflags) < 0) ++ goto err; ++ if (BIO_write(bp, "\n", 1) <= 0) ++ goto err; ++ } ++ if (!(cflag & X509_FLAG_NO_PUBKEY)) { ++ X509_PUBKEY *xpkey = X509_get_X509_PUBKEY(x); ++ ASN1_OBJECT *xpoid; ++ X509_PUBKEY_get0_param(&xpoid, NULL, NULL, NULL, xpkey); ++ if (BIO_write(bp, " Subject Public Key Info:\n", 33) <= 0) ++ goto err; ++ if (BIO_printf(bp, "%12sPublic Key Algorithm: ", "") <= 0) ++ goto err; ++ if (i2a_ASN1_OBJECT(bp, xpoid) <= 0) ++ goto err; ++ if (BIO_puts(bp, "\n") <= 0) ++ goto err; ++ ++ pkey = X509_get0_pubkey(x); ++ if (pkey == NULL) { ++ BIO_printf(bp, "%12sUnable to load Public Key\n", ""); ++ ERR_print_errors(bp); ++ } else { ++ EVP_PKEY_print_public(bp, pkey, 16, NULL); ++ } ++ } ++ ++ if (!(cflag & X509_FLAG_NO_IDS)) { ++ const ASN1_BIT_STRING *iuid, *suid; ++ X509_get0_uids(x, &iuid, &suid); ++ if (iuid != NULL) { ++ if (BIO_printf(bp, "%8sIssuer Unique ID: ", "") <= 0) ++ goto err; ++ if (!X509_signature_dump(bp, iuid, 12)) ++ goto err; ++ } ++ if (suid != NULL) { ++ if (BIO_printf(bp, "%8sSubject Unique ID: ", "") <= 0) ++ goto err; ++ if (!X509_signature_dump(bp, suid, 12)) ++ goto err; ++ } ++ } ++ ++ if (!(cflag & X509_FLAG_NO_EXTENSIONS)) ++ X509V3_extensions_print(bp, "X509v3 extensions", ++ X509_get0_extensions(x), cflag, 8); ++ ++ if (!(cflag & X509_FLAG_NO_SIGDUMP)) { ++ const X509_ALGOR *sig_alg; ++ const ASN1_BIT_STRING *sig; ++ X509_get0_signature(&sig, &sig_alg, x); ++ if (X509_signature_print(bp, sig_alg, sig) <= 0) ++ goto err; ++ } ++ if (!(cflag & X509_FLAG_NO_AUX)) { ++ if (!X509_aux_print(bp, x, 0)) ++ goto err; ++ } ++ ret = 1; ++ err: ++ OPENSSL_free(m); ++ return (ret); ++} ++ ++int X509_ocspid_print(BIO *bp, X509 *x) ++{ ++ unsigned char *der = NULL; ++ unsigned char *dertmp; ++ int derlen; ++ int i; ++ unsigned char SHA1md[SHA_DIGEST_LENGTH]; ++ ASN1_BIT_STRING *keybstr; ++ X509_NAME *subj; ++ ++ /* ++ * display the hash of the subject as it would appear in OCSP requests ++ */ ++ if (BIO_printf(bp, " Subject OCSP hash: ") <= 0) ++ goto err; ++ subj = X509_get_subject_name(x); ++ derlen = i2d_X509_NAME(subj, NULL); ++ if ((der = dertmp = OPENSSL_malloc(derlen)) == NULL) ++ goto err; ++ i2d_X509_NAME(subj, &dertmp); ++ ++ if (!EVP_Digest(der, derlen, SHA1md, NULL, EVP_sha1(), NULL)) ++ goto err; ++ for (i = 0; i < SHA_DIGEST_LENGTH; i++) { ++ if (BIO_printf(bp, "%02X", SHA1md[i]) <= 0) ++ goto err; ++ } ++ OPENSSL_free(der); ++ der = NULL; ++ ++ /* ++ * display the hash of the public key as it would appear in OCSP requests ++ */ ++ if (BIO_printf(bp, "\n Public key OCSP hash: ") <= 0) ++ goto err; ++ ++ keybstr = X509_get0_pubkey_bitstr(x); ++ ++ if (keybstr == NULL) ++ goto err; ++ ++ if (!EVP_Digest(ASN1_STRING_get0_data(keybstr), ++ ASN1_STRING_length(keybstr), SHA1md, NULL, EVP_sha1(), ++ NULL)) ++ goto err; ++ for (i = 0; i < SHA_DIGEST_LENGTH; i++) { ++ if (BIO_printf(bp, "%02X", SHA1md[i]) <= 0) ++ goto err; ++ } ++ BIO_printf(bp, "\n"); ++ ++ return (1); ++ err: ++ OPENSSL_free(der); ++ return (0); ++} ++ ++int X509_signature_dump(BIO *bp, const ASN1_STRING *sig, int indent) ++{ ++ const unsigned char *s; ++ int i, n; ++ ++ n = sig->length; ++ s = sig->data; ++ for (i = 0; i < n; i++) { ++ if ((i % 18) == 0) { ++ if (BIO_write(bp, "\n", 1) <= 0) ++ return 0; ++ if (BIO_indent(bp, indent, indent) <= 0) ++ return 0; ++ } ++ if (BIO_printf(bp, "%02x%s", s[i], ((i + 1) == n) ? "" : ":") <= 0) ++ return 0; ++ } ++ if (BIO_write(bp, "\n", 1) != 1) ++ return 0; ++ ++ return 1; ++} ++ ++int X509_signature_print(BIO *bp, const X509_ALGOR *sigalg, ++ const ASN1_STRING *sig) ++{ ++ int sig_nid; ++ if (BIO_puts(bp, " Signature Algorithm: ") <= 0) ++ return 0; ++ if (i2a_ASN1_OBJECT(bp, sigalg->algorithm) <= 0) ++ return 0; ++ ++ sig_nid = OBJ_obj2nid(sigalg->algorithm); ++ if (sig_nid != NID_undef) { ++ int pkey_nid, dig_nid; ++ const EVP_PKEY_ASN1_METHOD *ameth; ++ if (OBJ_find_sigid_algs(sig_nid, &dig_nid, &pkey_nid)) { ++ ameth = EVP_PKEY_asn1_find(NULL, pkey_nid); ++ if (ameth && ameth->sig_print) ++ return ameth->sig_print(bp, sigalg, sig, 9, 0); ++ } ++ } ++ if (sig) ++ return X509_signature_dump(bp, sig, 9); ++ else if (BIO_puts(bp, "\n") <= 0) ++ return 0; ++ return 1; ++} ++ ++int X509_aux_print(BIO *out, X509 *x, int indent) ++{ ++ char oidstr[80], first; ++ STACK_OF(ASN1_OBJECT) *trust, *reject; ++ const unsigned char *alias, *keyid; ++ int keyidlen; ++ int i; ++ if (X509_trusted(x) == 0) ++ return 1; ++ trust = X509_get0_trust_objects(x); ++ reject = X509_get0_reject_objects(x); ++ if (trust) { ++ first = 1; ++ BIO_printf(out, "%*sTrusted Uses:\n%*s", indent, "", indent + 2, ""); ++ for (i = 0; i < sk_ASN1_OBJECT_num(trust); i++) { ++ if (!first) ++ BIO_puts(out, ", "); ++ else ++ first = 0; ++ OBJ_obj2txt(oidstr, sizeof oidstr, ++ sk_ASN1_OBJECT_value(trust, i), 0); ++ BIO_puts(out, oidstr); ++ } ++ BIO_puts(out, "\n"); ++ } else ++ BIO_printf(out, "%*sNo Trusted Uses.\n", indent, ""); ++ if (reject) { ++ first = 1; ++ BIO_printf(out, "%*sRejected Uses:\n%*s", indent, "", indent + 2, ""); ++ for (i = 0; i < sk_ASN1_OBJECT_num(reject); i++) { ++ if (!first) ++ BIO_puts(out, ", "); ++ else ++ first = 0; ++ OBJ_obj2txt(oidstr, sizeof oidstr, ++ sk_ASN1_OBJECT_value(reject, i), 0); ++ BIO_puts(out, oidstr); ++ } ++ BIO_puts(out, "\n"); ++ } else ++ BIO_printf(out, "%*sNo Rejected Uses.\n", indent, ""); ++ alias = X509_alias_get0(x, NULL); ++ if (alias) ++ BIO_printf(out, "%*sAlias: %s\n", indent, "", alias); ++ keyid = X509_keyid_get0(x, &keyidlen); ++ if (keyid) { ++ BIO_printf(out, "%*sKey Id: ", indent, ""); ++ for (i = 0; i < keyidlen; i++) ++ BIO_printf(out, "%s%02X", i ? ":" : "", keyid[i]); ++ BIO_write(out, "\n", 1); ++ } ++ return 1; ++} +diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/x509/x509_att.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/x509/x509_att.c +new file mode 100644 +index 0000000..15f0e4f +--- /dev/null ++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/x509/x509_att.c +@@ -0,0 +1,329 @@ ++/* ++ * Copyright 1995-2016 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 ++ * in the file LICENSE in the source distribution or at ++ * https://www.openssl.org/source/license.html ++ */ ++ ++#include ++#include ++#include "internal/cryptlib.h" ++#include ++#include ++#include ++#include ++#include ++#include "x509_lcl.h" ++ ++int X509at_get_attr_count(const STACK_OF(X509_ATTRIBUTE) *x) ++{ ++ return sk_X509_ATTRIBUTE_num(x); ++} ++ ++int X509at_get_attr_by_NID(const STACK_OF(X509_ATTRIBUTE) *x, int nid, ++ int lastpos) ++{ ++ const ASN1_OBJECT *obj = OBJ_nid2obj(nid); ++ ++ if (obj == NULL) ++ return (-2); ++ return (X509at_get_attr_by_OBJ(x, obj, lastpos)); ++} ++ ++int X509at_get_attr_by_OBJ(const STACK_OF(X509_ATTRIBUTE) *sk, ++ const ASN1_OBJECT *obj, int lastpos) ++{ ++ int n; ++ X509_ATTRIBUTE *ex; ++ ++ if (sk == NULL) ++ return (-1); ++ lastpos++; ++ if (lastpos < 0) ++ lastpos = 0; ++ n = sk_X509_ATTRIBUTE_num(sk); ++ for (; lastpos < n; lastpos++) { ++ ex = sk_X509_ATTRIBUTE_value(sk, lastpos); ++ if (OBJ_cmp(ex->object, obj) == 0) ++ return (lastpos); ++ } ++ return (-1); ++} ++ ++X509_ATTRIBUTE *X509at_get_attr(const STACK_OF(X509_ATTRIBUTE) *x, int loc) ++{ ++ if (x == NULL || sk_X509_ATTRIBUTE_num(x) <= loc || loc < 0) ++ return NULL; ++ else ++ return sk_X509_ATTRIBUTE_value(x, loc); ++} ++ ++X509_ATTRIBUTE *X509at_delete_attr(STACK_OF(X509_ATTRIBUTE) *x, int loc) ++{ ++ X509_ATTRIBUTE *ret; ++ ++ if (x == NULL || sk_X509_ATTRIBUTE_num(x) <= loc || loc < 0) ++ return (NULL); ++ ret = sk_X509_ATTRIBUTE_delete(x, loc); ++ return (ret); ++} ++ ++STACK_OF(X509_ATTRIBUTE) *X509at_add1_attr(STACK_OF(X509_ATTRIBUTE) **x, ++ X509_ATTRIBUTE *attr) ++{ ++ X509_ATTRIBUTE *new_attr = NULL; ++ STACK_OF(X509_ATTRIBUTE) *sk = NULL; ++ ++ if (x == NULL) { ++ X509err(X509_F_X509AT_ADD1_ATTR, ERR_R_PASSED_NULL_PARAMETER); ++ goto err2; ++ } ++ ++ if (*x == NULL) { ++ if ((sk = sk_X509_ATTRIBUTE_new_null()) == NULL) ++ goto err; ++ } else ++ sk = *x; ++ ++ if ((new_attr = X509_ATTRIBUTE_dup(attr)) == NULL) ++ goto err2; ++ if (!sk_X509_ATTRIBUTE_push(sk, new_attr)) ++ goto err; ++ if (*x == NULL) ++ *x = sk; ++ return (sk); ++ err: ++ X509err(X509_F_X509AT_ADD1_ATTR, ERR_R_MALLOC_FAILURE); ++ err2: ++ X509_ATTRIBUTE_free(new_attr); ++ sk_X509_ATTRIBUTE_free(sk); ++ return (NULL); ++} ++ ++STACK_OF(X509_ATTRIBUTE) *X509at_add1_attr_by_OBJ(STACK_OF(X509_ATTRIBUTE) ++ **x, const ASN1_OBJECT *obj, ++ int type, ++ const unsigned char *bytes, ++ int len) ++{ ++ X509_ATTRIBUTE *attr; ++ STACK_OF(X509_ATTRIBUTE) *ret; ++ attr = X509_ATTRIBUTE_create_by_OBJ(NULL, obj, type, bytes, len); ++ if (!attr) ++ return 0; ++ ret = X509at_add1_attr(x, attr); ++ X509_ATTRIBUTE_free(attr); ++ return ret; ++} ++ ++STACK_OF(X509_ATTRIBUTE) *X509at_add1_attr_by_NID(STACK_OF(X509_ATTRIBUTE) ++ **x, int nid, int type, ++ const unsigned char *bytes, ++ int len) ++{ ++ X509_ATTRIBUTE *attr; ++ STACK_OF(X509_ATTRIBUTE) *ret; ++ attr = X509_ATTRIBUTE_create_by_NID(NULL, nid, type, bytes, len); ++ if (!attr) ++ return 0; ++ ret = X509at_add1_attr(x, attr); ++ X509_ATTRIBUTE_free(attr); ++ return ret; ++} ++ ++STACK_OF(X509_ATTRIBUTE) *X509at_add1_attr_by_txt(STACK_OF(X509_ATTRIBUTE) ++ **x, const char *attrname, ++ int type, ++ const unsigned char *bytes, ++ int len) ++{ ++ X509_ATTRIBUTE *attr; ++ STACK_OF(X509_ATTRIBUTE) *ret; ++ attr = X509_ATTRIBUTE_create_by_txt(NULL, attrname, type, bytes, len); ++ if (!attr) ++ return 0; ++ ret = X509at_add1_attr(x, attr); ++ X509_ATTRIBUTE_free(attr); ++ return ret; ++} ++ ++void *X509at_get0_data_by_OBJ(STACK_OF(X509_ATTRIBUTE) *x, ++ const ASN1_OBJECT *obj, int lastpos, int type) ++{ ++ int i; ++ X509_ATTRIBUTE *at; ++ i = X509at_get_attr_by_OBJ(x, obj, lastpos); ++ if (i == -1) ++ return NULL; ++ if ((lastpos <= -2) && (X509at_get_attr_by_OBJ(x, obj, i) != -1)) ++ return NULL; ++ at = X509at_get_attr(x, i); ++ if (lastpos <= -3 && (X509_ATTRIBUTE_count(at) != 1)) ++ return NULL; ++ return X509_ATTRIBUTE_get0_data(at, 0, type, NULL); ++} ++ ++X509_ATTRIBUTE *X509_ATTRIBUTE_create_by_NID(X509_ATTRIBUTE **attr, int nid, ++ int atrtype, const void *data, ++ int len) ++{ ++ ASN1_OBJECT *obj; ++ X509_ATTRIBUTE *ret; ++ ++ obj = OBJ_nid2obj(nid); ++ if (obj == NULL) { ++ X509err(X509_F_X509_ATTRIBUTE_CREATE_BY_NID, X509_R_UNKNOWN_NID); ++ return (NULL); ++ } ++ ret = X509_ATTRIBUTE_create_by_OBJ(attr, obj, atrtype, data, len); ++ if (ret == NULL) ++ ASN1_OBJECT_free(obj); ++ return (ret); ++} ++ ++X509_ATTRIBUTE *X509_ATTRIBUTE_create_by_OBJ(X509_ATTRIBUTE **attr, ++ const ASN1_OBJECT *obj, ++ int atrtype, const void *data, ++ int len) ++{ ++ X509_ATTRIBUTE *ret; ++ ++ if ((attr == NULL) || (*attr == NULL)) { ++ if ((ret = X509_ATTRIBUTE_new()) == NULL) { ++ X509err(X509_F_X509_ATTRIBUTE_CREATE_BY_OBJ, ++ ERR_R_MALLOC_FAILURE); ++ return (NULL); ++ } ++ } else ++ ret = *attr; ++ ++ if (!X509_ATTRIBUTE_set1_object(ret, obj)) ++ goto err; ++ if (!X509_ATTRIBUTE_set1_data(ret, atrtype, data, len)) ++ goto err; ++ ++ if ((attr != NULL) && (*attr == NULL)) ++ *attr = ret; ++ return (ret); ++ err: ++ if ((attr == NULL) || (ret != *attr)) ++ X509_ATTRIBUTE_free(ret); ++ return (NULL); ++} ++ ++X509_ATTRIBUTE *X509_ATTRIBUTE_create_by_txt(X509_ATTRIBUTE **attr, ++ const char *atrname, int type, ++ const unsigned char *bytes, ++ int len) ++{ ++ ASN1_OBJECT *obj; ++ X509_ATTRIBUTE *nattr; ++ ++ obj = OBJ_txt2obj(atrname, 0); ++ if (obj == NULL) { ++ X509err(X509_F_X509_ATTRIBUTE_CREATE_BY_TXT, ++ X509_R_INVALID_FIELD_NAME); ++ ERR_add_error_data(2, "name=", atrname); ++ return (NULL); ++ } ++ nattr = X509_ATTRIBUTE_create_by_OBJ(attr, obj, type, bytes, len); ++ ASN1_OBJECT_free(obj); ++ return nattr; ++} ++ ++int X509_ATTRIBUTE_set1_object(X509_ATTRIBUTE *attr, const ASN1_OBJECT *obj) ++{ ++ if ((attr == NULL) || (obj == NULL)) ++ return (0); ++ ASN1_OBJECT_free(attr->object); ++ attr->object = OBJ_dup(obj); ++ return attr->object != NULL; ++} ++ ++int X509_ATTRIBUTE_set1_data(X509_ATTRIBUTE *attr, int attrtype, ++ const void *data, int len) ++{ ++ ASN1_TYPE *ttmp = NULL; ++ ASN1_STRING *stmp = NULL; ++ int atype = 0; ++ if (!attr) ++ return 0; ++ if (attrtype & MBSTRING_FLAG) { ++ stmp = ASN1_STRING_set_by_NID(NULL, data, len, attrtype, ++ OBJ_obj2nid(attr->object)); ++ if (!stmp) { ++ X509err(X509_F_X509_ATTRIBUTE_SET1_DATA, ERR_R_ASN1_LIB); ++ return 0; ++ } ++ atype = stmp->type; ++ } else if (len != -1) { ++ if ((stmp = ASN1_STRING_type_new(attrtype)) == NULL) ++ goto err; ++ if (!ASN1_STRING_set(stmp, data, len)) ++ goto err; ++ atype = attrtype; ++ } ++ /* ++ * This is a bit naughty because the attribute should really have at ++ * least one value but some types use and zero length SET and require ++ * this. ++ */ ++ if (attrtype == 0) { ++ ASN1_STRING_free(stmp); ++ return 1; ++ } ++ if ((ttmp = ASN1_TYPE_new()) == NULL) ++ goto err; ++ if ((len == -1) && !(attrtype & MBSTRING_FLAG)) { ++ if (!ASN1_TYPE_set1(ttmp, attrtype, data)) ++ goto err; ++ } else { ++ ASN1_TYPE_set(ttmp, atype, stmp); ++ stmp = NULL; ++ } ++ if (!sk_ASN1_TYPE_push(attr->set, ttmp)) ++ goto err; ++ return 1; ++ err: ++ X509err(X509_F_X509_ATTRIBUTE_SET1_DATA, ERR_R_MALLOC_FAILURE); ++ ASN1_TYPE_free(ttmp); ++ ASN1_STRING_free(stmp); ++ return 0; ++} ++ ++int X509_ATTRIBUTE_count(const X509_ATTRIBUTE *attr) ++{ ++ if (attr == NULL) ++ return 0; ++ return sk_ASN1_TYPE_num(attr->set); ++} ++ ++ASN1_OBJECT *X509_ATTRIBUTE_get0_object(X509_ATTRIBUTE *attr) ++{ ++ if (attr == NULL) ++ return (NULL); ++ return (attr->object); ++} ++ ++void *X509_ATTRIBUTE_get0_data(X509_ATTRIBUTE *attr, int idx, ++ int atrtype, void *data) ++{ ++ ASN1_TYPE *ttmp; ++ ttmp = X509_ATTRIBUTE_get0_type(attr, idx); ++ if (!ttmp) ++ return NULL; ++ if (atrtype != ASN1_TYPE_get(ttmp)) { ++ X509err(X509_F_X509_ATTRIBUTE_GET0_DATA, X509_R_WRONG_TYPE); ++ return NULL; ++ } ++ return ttmp->value.ptr; ++} ++ ++ASN1_TYPE *X509_ATTRIBUTE_get0_type(X509_ATTRIBUTE *attr, int idx) ++{ ++ if (attr == NULL) ++ return NULL; ++ return sk_ASN1_TYPE_value(attr->set, idx); ++} +diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/x509/x509_cmp.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/x509/x509_cmp.c +new file mode 100644 +index 0000000..0105635 +--- /dev/null ++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/x509/x509_cmp.c +@@ -0,0 +1,459 @@ ++/* ++ * Copyright 1995-2016 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 ++ * in the file LICENSE in the source distribution or at ++ * https://www.openssl.org/source/license.html ++ */ ++ ++#include ++#include ++#include "internal/cryptlib.h" ++#include ++#include ++#include ++#include ++#include "internal/x509_int.h" ++ ++int X509_issuer_and_serial_cmp(const X509 *a, const X509 *b) ++{ ++ int i; ++ const X509_CINF *ai, *bi; ++ ++ ai = &a->cert_info; ++ bi = &b->cert_info; ++ i = ASN1_INTEGER_cmp(&ai->serialNumber, &bi->serialNumber); ++ if (i) ++ return (i); ++ return (X509_NAME_cmp(ai->issuer, bi->issuer)); ++} ++ ++#ifndef OPENSSL_NO_MD5 ++unsigned long X509_issuer_and_serial_hash(X509 *a) ++{ ++ unsigned long ret = 0; ++ EVP_MD_CTX *ctx = EVP_MD_CTX_new(); ++ unsigned char md[16]; ++ char *f; ++ ++ if (ctx == NULL) ++ goto err; ++ f = X509_NAME_oneline(a->cert_info.issuer, NULL, 0); ++ if (!EVP_DigestInit_ex(ctx, EVP_md5(), NULL)) ++ goto err; ++ if (!EVP_DigestUpdate(ctx, (unsigned char *)f, strlen(f))) ++ goto err; ++ OPENSSL_free(f); ++ if (!EVP_DigestUpdate ++ (ctx, (unsigned char *)a->cert_info.serialNumber.data, ++ (unsigned long)a->cert_info.serialNumber.length)) ++ goto err; ++ if (!EVP_DigestFinal_ex(ctx, &(md[0]), NULL)) ++ goto err; ++ ret = (((unsigned long)md[0]) | ((unsigned long)md[1] << 8L) | ++ ((unsigned long)md[2] << 16L) | ((unsigned long)md[3] << 24L) ++ ) & 0xffffffffL; ++ err: ++ EVP_MD_CTX_free(ctx); ++ return (ret); ++} ++#endif ++ ++int X509_issuer_name_cmp(const X509 *a, const X509 *b) ++{ ++ return (X509_NAME_cmp(a->cert_info.issuer, b->cert_info.issuer)); ++} ++ ++int X509_subject_name_cmp(const X509 *a, const X509 *b) ++{ ++ return (X509_NAME_cmp(a->cert_info.subject, b->cert_info.subject)); ++} ++ ++int X509_CRL_cmp(const X509_CRL *a, const X509_CRL *b) ++{ ++ return (X509_NAME_cmp(a->crl.issuer, b->crl.issuer)); ++} ++ ++int X509_CRL_match(const X509_CRL *a, const X509_CRL *b) ++{ ++ return memcmp(a->sha1_hash, b->sha1_hash, 20); ++} ++ ++X509_NAME *X509_get_issuer_name(const X509 *a) ++{ ++ return (a->cert_info.issuer); ++} ++ ++unsigned long X509_issuer_name_hash(X509 *x) ++{ ++ return (X509_NAME_hash(x->cert_info.issuer)); ++} ++ ++#ifndef OPENSSL_NO_MD5 ++unsigned long X509_issuer_name_hash_old(X509 *x) ++{ ++ return (X509_NAME_hash_old(x->cert_info.issuer)); ++} ++#endif ++ ++X509_NAME *X509_get_subject_name(const X509 *a) ++{ ++ return (a->cert_info.subject); ++} ++ ++ASN1_INTEGER *X509_get_serialNumber(X509 *a) ++{ ++ return &a->cert_info.serialNumber; ++} ++ ++const ASN1_INTEGER *X509_get0_serialNumber(const X509 *a) ++{ ++ return &a->cert_info.serialNumber; ++} ++ ++unsigned long X509_subject_name_hash(X509 *x) ++{ ++ return (X509_NAME_hash(x->cert_info.subject)); ++} ++ ++#ifndef OPENSSL_NO_MD5 ++unsigned long X509_subject_name_hash_old(X509 *x) ++{ ++ return (X509_NAME_hash_old(x->cert_info.subject)); ++} ++#endif ++ ++/* ++ * Compare two certificates: they must be identical for this to work. NB: ++ * Although "cmp" operations are generally prototyped to take "const" ++ * arguments (eg. for use in STACKs), the way X509 handling is - these ++ * operations may involve ensuring the hashes are up-to-date and ensuring ++ * certain cert information is cached. So this is the point where the ++ * "depth-first" constification tree has to halt with an evil cast. ++ */ ++int X509_cmp(const X509 *a, const X509 *b) ++{ ++ int rv; ++ /* ensure hash is valid */ ++ X509_check_purpose((X509 *)a, -1, 0); ++ X509_check_purpose((X509 *)b, -1, 0); ++ ++ rv = memcmp(a->sha1_hash, b->sha1_hash, SHA_DIGEST_LENGTH); ++ if (rv) ++ return rv; ++ /* Check for match against stored encoding too */ ++ if (!a->cert_info.enc.modified && !b->cert_info.enc.modified) { ++ if (a->cert_info.enc.len < b->cert_info.enc.len) ++ return -1; ++ if (a->cert_info.enc.len > b->cert_info.enc.len) ++ return 1; ++ return memcmp(a->cert_info.enc.enc, b->cert_info.enc.enc, ++ a->cert_info.enc.len); ++ } ++ return rv; ++} ++ ++int X509_NAME_cmp(const X509_NAME *a, const X509_NAME *b) ++{ ++ int ret; ++ ++ /* Ensure canonical encoding is present and up to date */ ++ ++ if (!a->canon_enc || a->modified) { ++ ret = i2d_X509_NAME((X509_NAME *)a, NULL); ++ if (ret < 0) ++ return -2; ++ } ++ ++ if (!b->canon_enc || b->modified) { ++ ret = i2d_X509_NAME((X509_NAME *)b, NULL); ++ if (ret < 0) ++ return -2; ++ } ++ ++ ret = a->canon_enclen - b->canon_enclen; ++ ++ if (ret) ++ return ret; ++ ++ return memcmp(a->canon_enc, b->canon_enc, a->canon_enclen); ++ ++} ++ ++unsigned long X509_NAME_hash(X509_NAME *x) ++{ ++ unsigned long ret = 0; ++ unsigned char md[SHA_DIGEST_LENGTH]; ++ ++ /* Make sure X509_NAME structure contains valid cached encoding */ ++ i2d_X509_NAME(x, NULL); ++ if (!EVP_Digest(x->canon_enc, x->canon_enclen, md, NULL, EVP_sha1(), ++ NULL)) ++ return 0; ++ ++ ret = (((unsigned long)md[0]) | ((unsigned long)md[1] << 8L) | ++ ((unsigned long)md[2] << 16L) | ((unsigned long)md[3] << 24L) ++ ) & 0xffffffffL; ++ return (ret); ++} ++ ++#ifndef OPENSSL_NO_MD5 ++/* ++ * I now DER encode the name and hash it. Since I cache the DER encoding, ++ * this is reasonably efficient. ++ */ ++ ++unsigned long X509_NAME_hash_old(X509_NAME *x) ++{ ++ EVP_MD_CTX *md_ctx = EVP_MD_CTX_new(); ++ unsigned long ret = 0; ++ unsigned char md[16]; ++ ++ if (md_ctx == NULL) ++ return ret; ++ ++ /* Make sure X509_NAME structure contains valid cached encoding */ ++ i2d_X509_NAME(x, NULL); ++ EVP_MD_CTX_set_flags(md_ctx, EVP_MD_CTX_FLAG_NON_FIPS_ALLOW); ++ if (EVP_DigestInit_ex(md_ctx, EVP_md5(), NULL) ++ && EVP_DigestUpdate(md_ctx, x->bytes->data, x->bytes->length) ++ && EVP_DigestFinal_ex(md_ctx, md, NULL)) ++ ret = (((unsigned long)md[0]) | ((unsigned long)md[1] << 8L) | ++ ((unsigned long)md[2] << 16L) | ((unsigned long)md[3] << 24L) ++ ) & 0xffffffffL; ++ EVP_MD_CTX_free(md_ctx); ++ ++ return (ret); ++} ++#endif ++ ++/* Search a stack of X509 for a match */ ++X509 *X509_find_by_issuer_and_serial(STACK_OF(X509) *sk, X509_NAME *name, ++ ASN1_INTEGER *serial) ++{ ++ int i; ++ X509 x, *x509 = NULL; ++ ++ if (!sk) ++ return NULL; ++ ++ x.cert_info.serialNumber = *serial; ++ x.cert_info.issuer = name; ++ ++ for (i = 0; i < sk_X509_num(sk); i++) { ++ x509 = sk_X509_value(sk, i); ++ if (X509_issuer_and_serial_cmp(x509, &x) == 0) ++ return (x509); ++ } ++ return (NULL); ++} ++ ++X509 *X509_find_by_subject(STACK_OF(X509) *sk, X509_NAME *name) ++{ ++ X509 *x509; ++ int i; ++ ++ for (i = 0; i < sk_X509_num(sk); i++) { ++ x509 = sk_X509_value(sk, i); ++ if (X509_NAME_cmp(X509_get_subject_name(x509), name) == 0) ++ return (x509); ++ } ++ return (NULL); ++} ++ ++EVP_PKEY *X509_get0_pubkey(const X509 *x) ++{ ++ if (x == NULL) ++ return NULL; ++ return X509_PUBKEY_get0(x->cert_info.key); ++} ++ ++EVP_PKEY *X509_get_pubkey(X509 *x) ++{ ++ if (x == NULL) ++ return NULL; ++ return X509_PUBKEY_get(x->cert_info.key); ++} ++ ++int X509_check_private_key(const X509 *x, const EVP_PKEY *k) ++{ ++ const EVP_PKEY *xk; ++ int ret; ++ ++ xk = X509_get0_pubkey(x); ++ ++ if (xk) ++ ret = EVP_PKEY_cmp(xk, k); ++ else ++ ret = -2; ++ ++ switch (ret) { ++ case 1: ++ break; ++ case 0: ++ X509err(X509_F_X509_CHECK_PRIVATE_KEY, X509_R_KEY_VALUES_MISMATCH); ++ break; ++ case -1: ++ X509err(X509_F_X509_CHECK_PRIVATE_KEY, X509_R_KEY_TYPE_MISMATCH); ++ break; ++ case -2: ++ X509err(X509_F_X509_CHECK_PRIVATE_KEY, X509_R_UNKNOWN_KEY_TYPE); ++ } ++ if (ret > 0) ++ return 1; ++ return 0; ++} ++ ++/* ++ * Check a suite B algorithm is permitted: pass in a public key and the NID ++ * of its signature (or 0 if no signature). The pflags is a pointer to a ++ * flags field which must contain the suite B verification flags. ++ */ ++ ++#ifndef OPENSSL_NO_EC ++ ++static int check_suite_b(EVP_PKEY *pkey, int sign_nid, unsigned long *pflags) ++{ ++ const EC_GROUP *grp = NULL; ++ int curve_nid; ++ if (pkey && EVP_PKEY_id(pkey) == EVP_PKEY_EC) ++ grp = EC_KEY_get0_group(EVP_PKEY_get0_EC_KEY(pkey)); ++ if (!grp) ++ return X509_V_ERR_SUITE_B_INVALID_ALGORITHM; ++ curve_nid = EC_GROUP_get_curve_name(grp); ++ /* Check curve is consistent with LOS */ ++ if (curve_nid == NID_secp384r1) { /* P-384 */ ++ /* ++ * Check signature algorithm is consistent with curve. ++ */ ++ if (sign_nid != -1 && sign_nid != NID_ecdsa_with_SHA384) ++ return X509_V_ERR_SUITE_B_INVALID_SIGNATURE_ALGORITHM; ++ if (!(*pflags & X509_V_FLAG_SUITEB_192_LOS)) ++ return X509_V_ERR_SUITE_B_LOS_NOT_ALLOWED; ++ /* If we encounter P-384 we cannot use P-256 later */ ++ *pflags &= ~X509_V_FLAG_SUITEB_128_LOS_ONLY; ++ } else if (curve_nid == NID_X9_62_prime256v1) { /* P-256 */ ++ if (sign_nid != -1 && sign_nid != NID_ecdsa_with_SHA256) ++ return X509_V_ERR_SUITE_B_INVALID_SIGNATURE_ALGORITHM; ++ if (!(*pflags & X509_V_FLAG_SUITEB_128_LOS_ONLY)) ++ return X509_V_ERR_SUITE_B_LOS_NOT_ALLOWED; ++ } else ++ return X509_V_ERR_SUITE_B_INVALID_CURVE; ++ ++ return X509_V_OK; ++} ++ ++int X509_chain_check_suiteb(int *perror_depth, X509 *x, STACK_OF(X509) *chain, ++ unsigned long flags) ++{ ++ int rv, i, sign_nid; ++ EVP_PKEY *pk; ++ unsigned long tflags = flags; ++ ++ if (!(flags & X509_V_FLAG_SUITEB_128_LOS)) ++ return X509_V_OK; ++ ++ /* If no EE certificate passed in must be first in chain */ ++ if (x == NULL) { ++ x = sk_X509_value(chain, 0); ++ i = 1; ++ } else ++ i = 0; ++ ++ pk = X509_get0_pubkey(x); ++ ++ /* ++ * With DANE-EE(3) success, or DANE-EE(3)/PKIX-EE(1) failure we don't build ++ * a chain all, just report trust success or failure, but must also report ++ * Suite-B errors if applicable. This is indicated via a NULL chain ++ * pointer. All we need to do is check the leaf key algorithm. ++ */ ++ if (chain == NULL) ++ return check_suite_b(pk, -1, &tflags); ++ ++ if (X509_get_version(x) != 2) { ++ rv = X509_V_ERR_SUITE_B_INVALID_VERSION; ++ /* Correct error depth */ ++ i = 0; ++ goto end; ++ } ++ ++ /* Check EE key only */ ++ rv = check_suite_b(pk, -1, &tflags); ++ if (rv != X509_V_OK) { ++ /* Correct error depth */ ++ i = 0; ++ goto end; ++ } ++ for (; i < sk_X509_num(chain); i++) { ++ sign_nid = X509_get_signature_nid(x); ++ x = sk_X509_value(chain, i); ++ if (X509_get_version(x) != 2) { ++ rv = X509_V_ERR_SUITE_B_INVALID_VERSION; ++ goto end; ++ } ++ pk = X509_get0_pubkey(x); ++ rv = check_suite_b(pk, sign_nid, &tflags); ++ if (rv != X509_V_OK) ++ goto end; ++ } ++ ++ /* Final check: root CA signature */ ++ rv = check_suite_b(pk, X509_get_signature_nid(x), &tflags); ++ end: ++ if (rv != X509_V_OK) { ++ /* Invalid signature or LOS errors are for previous cert */ ++ if ((rv == X509_V_ERR_SUITE_B_INVALID_SIGNATURE_ALGORITHM ++ || rv == X509_V_ERR_SUITE_B_LOS_NOT_ALLOWED) && i) ++ i--; ++ /* ++ * If we have LOS error and flags changed then we are signing P-384 ++ * with P-256. Use more meaningful error. ++ */ ++ if (rv == X509_V_ERR_SUITE_B_LOS_NOT_ALLOWED && flags != tflags) ++ rv = X509_V_ERR_SUITE_B_CANNOT_SIGN_P_384_WITH_P_256; ++ if (perror_depth) ++ *perror_depth = i; ++ } ++ return rv; ++} ++ ++int X509_CRL_check_suiteb(X509_CRL *crl, EVP_PKEY *pk, unsigned long flags) ++{ ++ int sign_nid; ++ if (!(flags & X509_V_FLAG_SUITEB_128_LOS)) ++ return X509_V_OK; ++ sign_nid = OBJ_obj2nid(crl->crl.sig_alg.algorithm); ++ return check_suite_b(pk, sign_nid, &flags); ++} ++ ++#else ++int X509_chain_check_suiteb(int *perror_depth, X509 *x, STACK_OF(X509) *chain, ++ unsigned long flags) ++{ ++ return 0; ++} ++ ++int X509_CRL_check_suiteb(X509_CRL *crl, EVP_PKEY *pk, unsigned long flags) ++{ ++ return 0; ++} ++ ++#endif ++/* ++ * Not strictly speaking an "up_ref" as a STACK doesn't have a reference ++ * count but it has the same effect by duping the STACK and upping the ref of ++ * each X509 structure. ++ */ ++STACK_OF(X509) *X509_chain_up_ref(STACK_OF(X509) *chain) ++{ ++ STACK_OF(X509) *ret; ++ int i; ++ ret = sk_X509_dup(chain); ++ for (i = 0; i < sk_X509_num(ret); i++) { ++ X509 *x = sk_X509_value(ret, i); ++ X509_up_ref(x); ++ } ++ return ret; ++} +diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/x509/x509_d2.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/x509/x509_d2.c +new file mode 100644 +index 0000000..cb03dbf +--- /dev/null ++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/x509/x509_d2.c +@@ -0,0 +1,57 @@ ++/* ++ * Copyright 1995-2016 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 ++ * in the file LICENSE in the source distribution or at ++ * https://www.openssl.org/source/license.html ++ */ ++ ++#include ++#include "internal/cryptlib.h" ++#include ++#include ++ ++int X509_STORE_set_default_paths(X509_STORE *ctx) ++{ ++ X509_LOOKUP *lookup; ++ ++ lookup = X509_STORE_add_lookup(ctx, X509_LOOKUP_file()); ++ if (lookup == NULL) ++ return (0); ++ X509_LOOKUP_load_file(lookup, NULL, X509_FILETYPE_DEFAULT); ++ ++ lookup = X509_STORE_add_lookup(ctx, X509_LOOKUP_hash_dir()); ++ if (lookup == NULL) ++ return (0); ++ X509_LOOKUP_add_dir(lookup, NULL, X509_FILETYPE_DEFAULT); ++ ++ /* clear any errors */ ++ ERR_clear_error(); ++ ++ return (1); ++} ++ ++int X509_STORE_load_locations(X509_STORE *ctx, const char *file, ++ const char *path) ++{ ++ X509_LOOKUP *lookup; ++ ++ if (file != NULL) { ++ lookup = X509_STORE_add_lookup(ctx, X509_LOOKUP_file()); ++ if (lookup == NULL) ++ return (0); ++ if (X509_LOOKUP_load_file(lookup, file, X509_FILETYPE_PEM) != 1) ++ return (0); ++ } ++ if (path != NULL) { ++ lookup = X509_STORE_add_lookup(ctx, X509_LOOKUP_hash_dir()); ++ if (lookup == NULL) ++ return (0); ++ if (X509_LOOKUP_add_dir(lookup, path, X509_FILETYPE_PEM) != 1) ++ return (0); ++ } ++ if ((path == NULL) && (file == NULL)) ++ return (0); ++ return (1); ++} +diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/x509/x509_def.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/x509/x509_def.c +new file mode 100644 +index 0000000..d11358e +--- /dev/null ++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/x509/x509_def.c +@@ -0,0 +1,43 @@ ++/* ++ * Copyright 1995-2016 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 ++ * in the file LICENSE in the source distribution or at ++ * https://www.openssl.org/source/license.html ++ */ ++ ++#include ++#include "internal/cryptlib.h" ++#include ++#include ++ ++const char *X509_get_default_private_dir(void) ++{ ++ return (X509_PRIVATE_DIR); ++} ++ ++const char *X509_get_default_cert_area(void) ++{ ++ return (X509_CERT_AREA); ++} ++ ++const char *X509_get_default_cert_dir(void) ++{ ++ return (X509_CERT_DIR); ++} ++ ++const char *X509_get_default_cert_file(void) ++{ ++ return (X509_CERT_FILE); ++} ++ ++const char *X509_get_default_cert_dir_env(void) ++{ ++ return (X509_CERT_DIR_EVP); ++} ++ ++const char *X509_get_default_cert_file_env(void) ++{ ++ return (X509_CERT_FILE_EVP); ++} +diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/x509/x509_err.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/x509/x509_err.c +new file mode 100644 +index 0000000..3f4b8ef +--- /dev/null ++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/x509/x509_err.c +@@ -0,0 +1,142 @@ ++/* ++ * Generated by util/mkerr.pl DO NOT EDIT ++ * Copyright 1995-2016 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 ++ * in the file LICENSE in the source distribution or at ++ * https://www.openssl.org/source/license.html ++ */ ++ ++#include ++#include ++#include ++ ++/* BEGIN ERROR CODES */ ++#ifndef OPENSSL_NO_ERR ++ ++# define ERR_FUNC(func) ERR_PACK(ERR_LIB_X509,func,0) ++# define ERR_REASON(reason) ERR_PACK(ERR_LIB_X509,0,reason) ++ ++static ERR_STRING_DATA X509_str_functs[] = { ++ {ERR_FUNC(X509_F_ADD_CERT_DIR), "add_cert_dir"}, ++ {ERR_FUNC(X509_F_BUILD_CHAIN), "build_chain"}, ++ {ERR_FUNC(X509_F_BY_FILE_CTRL), "by_file_ctrl"}, ++ {ERR_FUNC(X509_F_CHECK_NAME_CONSTRAINTS), "check_name_constraints"}, ++ {ERR_FUNC(X509_F_CHECK_POLICY), "check_policy"}, ++ {ERR_FUNC(X509_F_DANE_I2D), "dane_i2d"}, ++ {ERR_FUNC(X509_F_DIR_CTRL), "dir_ctrl"}, ++ {ERR_FUNC(X509_F_GET_CERT_BY_SUBJECT), "get_cert_by_subject"}, ++ {ERR_FUNC(X509_F_NETSCAPE_SPKI_B64_DECODE), "NETSCAPE_SPKI_b64_decode"}, ++ {ERR_FUNC(X509_F_NETSCAPE_SPKI_B64_ENCODE), "NETSCAPE_SPKI_b64_encode"}, ++ {ERR_FUNC(X509_F_X509AT_ADD1_ATTR), "X509at_add1_attr"}, ++ {ERR_FUNC(X509_F_X509V3_ADD_EXT), "X509v3_add_ext"}, ++ {ERR_FUNC(X509_F_X509_ATTRIBUTE_CREATE_BY_NID), ++ "X509_ATTRIBUTE_create_by_NID"}, ++ {ERR_FUNC(X509_F_X509_ATTRIBUTE_CREATE_BY_OBJ), ++ "X509_ATTRIBUTE_create_by_OBJ"}, ++ {ERR_FUNC(X509_F_X509_ATTRIBUTE_CREATE_BY_TXT), ++ "X509_ATTRIBUTE_create_by_txt"}, ++ {ERR_FUNC(X509_F_X509_ATTRIBUTE_GET0_DATA), "X509_ATTRIBUTE_get0_data"}, ++ {ERR_FUNC(X509_F_X509_ATTRIBUTE_SET1_DATA), "X509_ATTRIBUTE_set1_data"}, ++ {ERR_FUNC(X509_F_X509_CHECK_PRIVATE_KEY), "X509_check_private_key"}, ++ {ERR_FUNC(X509_F_X509_CRL_DIFF), "X509_CRL_diff"}, ++ {ERR_FUNC(X509_F_X509_CRL_PRINT_FP), "X509_CRL_print_fp"}, ++ {ERR_FUNC(X509_F_X509_EXTENSION_CREATE_BY_NID), ++ "X509_EXTENSION_create_by_NID"}, ++ {ERR_FUNC(X509_F_X509_EXTENSION_CREATE_BY_OBJ), ++ "X509_EXTENSION_create_by_OBJ"}, ++ {ERR_FUNC(X509_F_X509_GET_PUBKEY_PARAMETERS), ++ "X509_get_pubkey_parameters"}, ++ {ERR_FUNC(X509_F_X509_LOAD_CERT_CRL_FILE), "X509_load_cert_crl_file"}, ++ {ERR_FUNC(X509_F_X509_LOAD_CERT_FILE), "X509_load_cert_file"}, ++ {ERR_FUNC(X509_F_X509_LOAD_CRL_FILE), "X509_load_crl_file"}, ++ {ERR_FUNC(X509_F_X509_NAME_ADD_ENTRY), "X509_NAME_add_entry"}, ++ {ERR_FUNC(X509_F_X509_NAME_ENTRY_CREATE_BY_NID), ++ "X509_NAME_ENTRY_create_by_NID"}, ++ {ERR_FUNC(X509_F_X509_NAME_ENTRY_CREATE_BY_TXT), ++ "X509_NAME_ENTRY_create_by_txt"}, ++ {ERR_FUNC(X509_F_X509_NAME_ENTRY_SET_OBJECT), ++ "X509_NAME_ENTRY_set_object"}, ++ {ERR_FUNC(X509_F_X509_NAME_ONELINE), "X509_NAME_oneline"}, ++ {ERR_FUNC(X509_F_X509_NAME_PRINT), "X509_NAME_print"}, ++ {ERR_FUNC(X509_F_X509_OBJECT_NEW), "X509_OBJECT_new"}, ++ {ERR_FUNC(X509_F_X509_PRINT_EX_FP), "X509_print_ex_fp"}, ++ {ERR_FUNC(X509_F_X509_PUBKEY_DECODE), "x509_pubkey_decode"}, ++ {ERR_FUNC(X509_F_X509_PUBKEY_GET0), "X509_PUBKEY_get0"}, ++ {ERR_FUNC(X509_F_X509_PUBKEY_SET), "X509_PUBKEY_set"}, ++ {ERR_FUNC(X509_F_X509_REQ_CHECK_PRIVATE_KEY), ++ "X509_REQ_check_private_key"}, ++ {ERR_FUNC(X509_F_X509_REQ_PRINT_EX), "X509_REQ_print_ex"}, ++ {ERR_FUNC(X509_F_X509_REQ_PRINT_FP), "X509_REQ_print_fp"}, ++ {ERR_FUNC(X509_F_X509_REQ_TO_X509), "X509_REQ_to_X509"}, ++ {ERR_FUNC(X509_F_X509_STORE_ADD_CERT), "X509_STORE_add_cert"}, ++ {ERR_FUNC(X509_F_X509_STORE_ADD_CRL), "X509_STORE_add_crl"}, ++ {ERR_FUNC(X509_F_X509_STORE_CTX_GET1_ISSUER), ++ "X509_STORE_CTX_get1_issuer"}, ++ {ERR_FUNC(X509_F_X509_STORE_CTX_INIT), "X509_STORE_CTX_init"}, ++ {ERR_FUNC(X509_F_X509_STORE_CTX_NEW), "X509_STORE_CTX_new"}, ++ {ERR_FUNC(X509_F_X509_STORE_CTX_PURPOSE_INHERIT), ++ "X509_STORE_CTX_purpose_inherit"}, ++ {ERR_FUNC(X509_F_X509_TO_X509_REQ), "X509_to_X509_REQ"}, ++ {ERR_FUNC(X509_F_X509_TRUST_ADD), "X509_TRUST_add"}, ++ {ERR_FUNC(X509_F_X509_TRUST_SET), "X509_TRUST_set"}, ++ {ERR_FUNC(X509_F_X509_VERIFY_CERT), "X509_verify_cert"}, ++ {0, NULL} ++}; ++ ++static ERR_STRING_DATA X509_str_reasons[] = { ++ {ERR_REASON(X509_R_AKID_MISMATCH), "akid mismatch"}, ++ {ERR_REASON(X509_R_BAD_SELECTOR), "bad selector"}, ++ {ERR_REASON(X509_R_BAD_X509_FILETYPE), "bad x509 filetype"}, ++ {ERR_REASON(X509_R_BASE64_DECODE_ERROR), "base64 decode error"}, ++ {ERR_REASON(X509_R_CANT_CHECK_DH_KEY), "cant check dh key"}, ++ {ERR_REASON(X509_R_CERT_ALREADY_IN_HASH_TABLE), ++ "cert already in hash table"}, ++ {ERR_REASON(X509_R_CRL_ALREADY_DELTA), "crl already delta"}, ++ {ERR_REASON(X509_R_CRL_VERIFY_FAILURE), "crl verify failure"}, ++ {ERR_REASON(X509_R_IDP_MISMATCH), "idp mismatch"}, ++ {ERR_REASON(X509_R_INVALID_DIRECTORY), "invalid directory"}, ++ {ERR_REASON(X509_R_INVALID_FIELD_NAME), "invalid field name"}, ++ {ERR_REASON(X509_R_INVALID_TRUST), "invalid trust"}, ++ {ERR_REASON(X509_R_ISSUER_MISMATCH), "issuer mismatch"}, ++ {ERR_REASON(X509_R_KEY_TYPE_MISMATCH), "key type mismatch"}, ++ {ERR_REASON(X509_R_KEY_VALUES_MISMATCH), "key values mismatch"}, ++ {ERR_REASON(X509_R_LOADING_CERT_DIR), "loading cert dir"}, ++ {ERR_REASON(X509_R_LOADING_DEFAULTS), "loading defaults"}, ++ {ERR_REASON(X509_R_METHOD_NOT_SUPPORTED), "method not supported"}, ++ {ERR_REASON(X509_R_NAME_TOO_LONG), "name too long"}, ++ {ERR_REASON(X509_R_NEWER_CRL_NOT_NEWER), "newer crl not newer"}, ++ {ERR_REASON(X509_R_NO_CERT_SET_FOR_US_TO_VERIFY), ++ "no cert set for us to verify"}, ++ {ERR_REASON(X509_R_NO_CRL_NUMBER), "no crl number"}, ++ {ERR_REASON(X509_R_PUBLIC_KEY_DECODE_ERROR), "public key decode error"}, ++ {ERR_REASON(X509_R_PUBLIC_KEY_ENCODE_ERROR), "public key encode error"}, ++ {ERR_REASON(X509_R_SHOULD_RETRY), "should retry"}, ++ {ERR_REASON(X509_R_UNABLE_TO_FIND_PARAMETERS_IN_CHAIN), ++ "unable to find parameters in chain"}, ++ {ERR_REASON(X509_R_UNABLE_TO_GET_CERTS_PUBLIC_KEY), ++ "unable to get certs public key"}, ++ {ERR_REASON(X509_R_UNKNOWN_KEY_TYPE), "unknown key type"}, ++ {ERR_REASON(X509_R_UNKNOWN_NID), "unknown nid"}, ++ {ERR_REASON(X509_R_UNKNOWN_PURPOSE_ID), "unknown purpose id"}, ++ {ERR_REASON(X509_R_UNKNOWN_TRUST_ID), "unknown trust id"}, ++ {ERR_REASON(X509_R_UNSUPPORTED_ALGORITHM), "unsupported algorithm"}, ++ {ERR_REASON(X509_R_WRONG_LOOKUP_TYPE), "wrong lookup type"}, ++ {ERR_REASON(X509_R_WRONG_TYPE), "wrong type"}, ++ {0, NULL} ++}; ++ ++#endif ++ ++int ERR_load_X509_strings(void) ++{ ++#ifndef OPENSSL_NO_ERR ++ ++ if (ERR_func_error_string(X509_str_functs[0].error) == NULL) { ++ ERR_load_strings(0, X509_str_functs); ++ ERR_load_strings(0, X509_str_reasons); ++ } ++#endif ++ return 1; ++} +diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/x509/x509_ext.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/x509/x509_ext.c +new file mode 100644 +index 0000000..3bbb0a6 +--- /dev/null ++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/x509/x509_ext.c +@@ -0,0 +1,160 @@ ++/* ++ * Copyright 1995-2016 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 ++ * in the file LICENSE in the source distribution or at ++ * https://www.openssl.org/source/license.html ++ */ ++ ++#include ++#include ++#include "internal/cryptlib.h" ++#include ++#include ++#include ++#include ++#include "internal/x509_int.h" ++#include ++ ++int X509_CRL_get_ext_count(const X509_CRL *x) ++{ ++ return (X509v3_get_ext_count(x->crl.extensions)); ++} ++ ++int X509_CRL_get_ext_by_NID(const X509_CRL *x, int nid, int lastpos) ++{ ++ return (X509v3_get_ext_by_NID(x->crl.extensions, nid, lastpos)); ++} ++ ++int X509_CRL_get_ext_by_OBJ(const X509_CRL *x, const ASN1_OBJECT *obj, ++ int lastpos) ++{ ++ return (X509v3_get_ext_by_OBJ(x->crl.extensions, obj, lastpos)); ++} ++ ++int X509_CRL_get_ext_by_critical(const X509_CRL *x, int crit, int lastpos) ++{ ++ return (X509v3_get_ext_by_critical(x->crl.extensions, crit, lastpos)); ++} ++ ++X509_EXTENSION *X509_CRL_get_ext(const X509_CRL *x, int loc) ++{ ++ return (X509v3_get_ext(x->crl.extensions, loc)); ++} ++ ++X509_EXTENSION *X509_CRL_delete_ext(X509_CRL *x, int loc) ++{ ++ return (X509v3_delete_ext(x->crl.extensions, loc)); ++} ++ ++void *X509_CRL_get_ext_d2i(const X509_CRL *x, int nid, int *crit, int *idx) ++{ ++ return X509V3_get_d2i(x->crl.extensions, nid, crit, idx); ++} ++ ++int X509_CRL_add1_ext_i2d(X509_CRL *x, int nid, void *value, int crit, ++ unsigned long flags) ++{ ++ return X509V3_add1_i2d(&x->crl.extensions, nid, value, crit, flags); ++} ++ ++int X509_CRL_add_ext(X509_CRL *x, X509_EXTENSION *ex, int loc) ++{ ++ return (X509v3_add_ext(&(x->crl.extensions), ex, loc) != NULL); ++} ++ ++int X509_get_ext_count(const X509 *x) ++{ ++ return (X509v3_get_ext_count(x->cert_info.extensions)); ++} ++ ++int X509_get_ext_by_NID(const X509 *x, int nid, int lastpos) ++{ ++ return (X509v3_get_ext_by_NID(x->cert_info.extensions, nid, lastpos)); ++} ++ ++int X509_get_ext_by_OBJ(const X509 *x, const ASN1_OBJECT *obj, int lastpos) ++{ ++ return (X509v3_get_ext_by_OBJ(x->cert_info.extensions, obj, lastpos)); ++} ++ ++int X509_get_ext_by_critical(const X509 *x, int crit, int lastpos) ++{ ++ return (X509v3_get_ext_by_critical ++ (x->cert_info.extensions, crit, lastpos)); ++} ++ ++X509_EXTENSION *X509_get_ext(const X509 *x, int loc) ++{ ++ return (X509v3_get_ext(x->cert_info.extensions, loc)); ++} ++ ++X509_EXTENSION *X509_delete_ext(X509 *x, int loc) ++{ ++ return (X509v3_delete_ext(x->cert_info.extensions, loc)); ++} ++ ++int X509_add_ext(X509 *x, X509_EXTENSION *ex, int loc) ++{ ++ return (X509v3_add_ext(&(x->cert_info.extensions), ex, loc) != NULL); ++} ++ ++void *X509_get_ext_d2i(const X509 *x, int nid, int *crit, int *idx) ++{ ++ return X509V3_get_d2i(x->cert_info.extensions, nid, crit, idx); ++} ++ ++int X509_add1_ext_i2d(X509 *x, int nid, void *value, int crit, ++ unsigned long flags) ++{ ++ return X509V3_add1_i2d(&x->cert_info.extensions, nid, value, crit, ++ flags); ++} ++ ++int X509_REVOKED_get_ext_count(const X509_REVOKED *x) ++{ ++ return (X509v3_get_ext_count(x->extensions)); ++} ++ ++int X509_REVOKED_get_ext_by_NID(const X509_REVOKED *x, int nid, int lastpos) ++{ ++ return (X509v3_get_ext_by_NID(x->extensions, nid, lastpos)); ++} ++ ++int X509_REVOKED_get_ext_by_OBJ(const X509_REVOKED *x, const ASN1_OBJECT *obj, ++ int lastpos) ++{ ++ return (X509v3_get_ext_by_OBJ(x->extensions, obj, lastpos)); ++} ++ ++int X509_REVOKED_get_ext_by_critical(const X509_REVOKED *x, int crit, int lastpos) ++{ ++ return (X509v3_get_ext_by_critical(x->extensions, crit, lastpos)); ++} ++ ++X509_EXTENSION *X509_REVOKED_get_ext(const X509_REVOKED *x, int loc) ++{ ++ return (X509v3_get_ext(x->extensions, loc)); ++} ++ ++X509_EXTENSION *X509_REVOKED_delete_ext(X509_REVOKED *x, int loc) ++{ ++ return (X509v3_delete_ext(x->extensions, loc)); ++} ++ ++int X509_REVOKED_add_ext(X509_REVOKED *x, X509_EXTENSION *ex, int loc) ++{ ++ return (X509v3_add_ext(&(x->extensions), ex, loc) != NULL); ++} ++ ++void *X509_REVOKED_get_ext_d2i(const X509_REVOKED *x, int nid, int *crit, int *idx) ++{ ++ return X509V3_get_d2i(x->extensions, nid, crit, idx); ++} ++ ++int X509_REVOKED_add1_ext_i2d(X509_REVOKED *x, int nid, void *value, int crit, ++ unsigned long flags) ++{ ++ return X509V3_add1_i2d(&x->extensions, nid, value, crit, flags); ++} +diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/x509/x509_lcl.h b/CryptoPkg/Library/OpensslLib/openssl/crypto/x509/x509_lcl.h +new file mode 100644 +index 0000000..40bd102 +--- /dev/null ++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/x509/x509_lcl.h +@@ -0,0 +1,142 @@ ++/* ++ * Copyright 2014-2016 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 ++ * in the file LICENSE in the source distribution or at ++ * https://www.openssl.org/source/license.html ++ */ ++ ++/* ++ * This structure holds all parameters associated with a verify operation by ++ * including an X509_VERIFY_PARAM structure in related structures the ++ * parameters used can be customized ++ */ ++ ++struct X509_VERIFY_PARAM_st { ++ char *name; ++ time_t check_time; /* Time to use */ ++ uint32_t inh_flags; /* Inheritance flags */ ++ unsigned long flags; /* Various verify flags */ ++ int purpose; /* purpose to check untrusted certificates */ ++ int trust; /* trust setting to check */ ++ int depth; /* Verify depth */ ++ int auth_level; /* Security level for chain verification */ ++ STACK_OF(ASN1_OBJECT) *policies; /* Permissible policies */ ++ /* Peer identity details */ ++ STACK_OF(OPENSSL_STRING) *hosts; /* Set of acceptable names */ ++ unsigned int hostflags; /* Flags to control matching features */ ++ char *peername; /* Matching hostname in peer certificate */ ++ char *email; /* If not NULL email address to match */ ++ size_t emaillen; ++ unsigned char *ip; /* If not NULL IP address to match */ ++ size_t iplen; /* Length of IP address */ ++}; ++ ++/* No error callback if depth < 0 */ ++int x509_check_cert_time(X509_STORE_CTX *ctx, X509 *x, int depth); ++ ++/* a sequence of these are used */ ++struct x509_attributes_st { ++ ASN1_OBJECT *object; ++ STACK_OF(ASN1_TYPE) *set; ++}; ++ ++struct X509_extension_st { ++ ASN1_OBJECT *object; ++ ASN1_BOOLEAN critical; ++ ASN1_OCTET_STRING value; ++}; ++ ++/* ++ * Method to handle CRL access. In general a CRL could be very large (several ++ * Mb) and can consume large amounts of resources if stored in memory by ++ * multiple processes. This method allows general CRL operations to be ++ * redirected to more efficient callbacks: for example a CRL entry database. ++ */ ++ ++#define X509_CRL_METHOD_DYNAMIC 1 ++ ++struct x509_crl_method_st { ++ int flags; ++ int (*crl_init) (X509_CRL *crl); ++ int (*crl_free) (X509_CRL *crl); ++ int (*crl_lookup) (X509_CRL *crl, X509_REVOKED **ret, ++ ASN1_INTEGER *ser, X509_NAME *issuer); ++ int (*crl_verify) (X509_CRL *crl, EVP_PKEY *pk); ++}; ++ ++struct x509_lookup_method_st { ++ const char *name; ++ int (*new_item) (X509_LOOKUP *ctx); ++ void (*free) (X509_LOOKUP *ctx); ++ int (*init) (X509_LOOKUP *ctx); ++ int (*shutdown) (X509_LOOKUP *ctx); ++ int (*ctrl) (X509_LOOKUP *ctx, int cmd, const char *argc, long argl, ++ char **ret); ++ int (*get_by_subject) (X509_LOOKUP *ctx, X509_LOOKUP_TYPE type, ++ X509_NAME *name, X509_OBJECT *ret); ++ int (*get_by_issuer_serial) (X509_LOOKUP *ctx, X509_LOOKUP_TYPE type, ++ X509_NAME *name, ASN1_INTEGER *serial, ++ X509_OBJECT *ret); ++ int (*get_by_fingerprint) (X509_LOOKUP *ctx, X509_LOOKUP_TYPE type, ++ const unsigned char *bytes, int len, ++ X509_OBJECT *ret); ++ int (*get_by_alias) (X509_LOOKUP *ctx, X509_LOOKUP_TYPE type, ++ const char *str, int len, X509_OBJECT *ret); ++}; ++ ++/* This is the functions plus an instance of the local variables. */ ++struct x509_lookup_st { ++ int init; /* have we been started */ ++ int skip; /* don't use us. */ ++ X509_LOOKUP_METHOD *method; /* the functions */ ++ char *method_data; /* method data */ ++ X509_STORE *store_ctx; /* who owns us */ ++}; ++ ++/* ++ * This is used to hold everything. It is used for all certificate ++ * validation. Once we have a certificate chain, the 'verify' function is ++ * then called to actually check the cert chain. ++ */ ++struct x509_store_st { ++ /* The following is a cache of trusted certs */ ++ int cache; /* if true, stash any hits */ ++ STACK_OF(X509_OBJECT) *objs; /* Cache of all objects */ ++ /* These are external lookup methods */ ++ STACK_OF(X509_LOOKUP) *get_cert_methods; ++ X509_VERIFY_PARAM *param; ++ /* Callbacks for various operations */ ++ /* called to verify a certificate */ ++ int (*verify) (X509_STORE_CTX *ctx); ++ /* error callback */ ++ int (*verify_cb) (int ok, X509_STORE_CTX *ctx); ++ /* get issuers cert from ctx */ ++ int (*get_issuer) (X509 **issuer, X509_STORE_CTX *ctx, X509 *x); ++ /* check issued */ ++ int (*check_issued) (X509_STORE_CTX *ctx, X509 *x, X509 *issuer); ++ /* Check revocation status of chain */ ++ int (*check_revocation) (X509_STORE_CTX *ctx); ++ /* retrieve CRL */ ++ int (*get_crl) (X509_STORE_CTX *ctx, X509_CRL **crl, X509 *x); ++ /* Check CRL validity */ ++ int (*check_crl) (X509_STORE_CTX *ctx, X509_CRL *crl); ++ /* Check certificate against CRL */ ++ int (*cert_crl) (X509_STORE_CTX *ctx, X509_CRL *crl, X509 *x); ++ /* Check policy status of the chain */ ++ int (*check_policy) (X509_STORE_CTX *ctx); ++ STACK_OF(X509) *(*lookup_certs) (X509_STORE_CTX *ctx, X509_NAME *nm); ++ STACK_OF(X509_CRL) *(*lookup_crls) (X509_STORE_CTX *ctx, X509_NAME *nm); ++ int (*cleanup) (X509_STORE_CTX *ctx); ++ CRYPTO_EX_DATA ex_data; ++ int references; ++ CRYPTO_RWLOCK *lock; ++}; ++ ++typedef struct lookup_dir_hashes_st BY_DIR_HASH; ++typedef struct lookup_dir_entry_st BY_DIR_ENTRY; ++DEFINE_STACK_OF(BY_DIR_HASH) ++DEFINE_STACK_OF(BY_DIR_ENTRY) ++typedef STACK_OF(X509_NAME_ENTRY) STACK_OF_X509_NAME_ENTRY; ++DEFINE_STACK_OF(STACK_OF_X509_NAME_ENTRY) +diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/x509/x509_lu.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/x509/x509_lu.c +new file mode 100644 +index 0000000..952cbfb +--- /dev/null ++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/x509/x509_lu.c +@@ -0,0 +1,861 @@ ++/* ++ * Copyright 1995-2016 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 ++ * in the file LICENSE in the source distribution or at ++ * https://www.openssl.org/source/license.html ++ */ ++ ++#include ++#include "internal/cryptlib.h" ++#include ++#include ++#include "internal/x509_int.h" ++#include ++#include "x509_lcl.h" ++ ++X509_LOOKUP *X509_LOOKUP_new(X509_LOOKUP_METHOD *method) ++{ ++ X509_LOOKUP *ret; ++ ++ ret = OPENSSL_zalloc(sizeof(*ret)); ++ if (ret == NULL) ++ return NULL; ++ ++ ret->method = method; ++ if ((method->new_item != NULL) && !method->new_item(ret)) { ++ OPENSSL_free(ret); ++ return NULL; ++ } ++ return ret; ++} ++ ++void X509_LOOKUP_free(X509_LOOKUP *ctx) ++{ ++ if (ctx == NULL) ++ return; ++ if ((ctx->method != NULL) && (ctx->method->free != NULL)) ++ (*ctx->method->free) (ctx); ++ OPENSSL_free(ctx); ++} ++ ++int X509_STORE_lock(X509_STORE *s) ++{ ++ return CRYPTO_THREAD_write_lock(s->lock); ++} ++ ++int X509_STORE_unlock(X509_STORE *s) ++{ ++ return CRYPTO_THREAD_unlock(s->lock); ++} ++ ++int X509_LOOKUP_init(X509_LOOKUP *ctx) ++{ ++ if (ctx->method == NULL) ++ return 0; ++ if (ctx->method->init != NULL) ++ return ctx->method->init(ctx); ++ else ++ return 1; ++} ++ ++int X509_LOOKUP_shutdown(X509_LOOKUP *ctx) ++{ ++ if (ctx->method == NULL) ++ return 0; ++ if (ctx->method->shutdown != NULL) ++ return ctx->method->shutdown(ctx); ++ else ++ return 1; ++} ++ ++int X509_LOOKUP_ctrl(X509_LOOKUP *ctx, int cmd, const char *argc, long argl, ++ char **ret) ++{ ++ if (ctx->method == NULL) ++ return -1; ++ if (ctx->method->ctrl != NULL) ++ return ctx->method->ctrl(ctx, cmd, argc, argl, ret); ++ else ++ return 1; ++} ++ ++int X509_LOOKUP_by_subject(X509_LOOKUP *ctx, X509_LOOKUP_TYPE type, ++ X509_NAME *name, X509_OBJECT *ret) ++{ ++ if ((ctx->method == NULL) || (ctx->method->get_by_subject == NULL)) ++ return 0; ++ if (ctx->skip) ++ return 0; ++ return ctx->method->get_by_subject(ctx, type, name, ret); ++} ++ ++int X509_LOOKUP_by_issuer_serial(X509_LOOKUP *ctx, X509_LOOKUP_TYPE type, ++ X509_NAME *name, ASN1_INTEGER *serial, ++ X509_OBJECT *ret) ++{ ++ if ((ctx->method == NULL) || (ctx->method->get_by_issuer_serial == NULL)) ++ return 0; ++ return ctx->method->get_by_issuer_serial(ctx, type, name, serial, ret); ++} ++ ++int X509_LOOKUP_by_fingerprint(X509_LOOKUP *ctx, X509_LOOKUP_TYPE type, ++ const unsigned char *bytes, int len, ++ X509_OBJECT *ret) ++{ ++ if ((ctx->method == NULL) || (ctx->method->get_by_fingerprint == NULL)) ++ return 0; ++ return ctx->method->get_by_fingerprint(ctx, type, bytes, len, ret); ++} ++ ++int X509_LOOKUP_by_alias(X509_LOOKUP *ctx, X509_LOOKUP_TYPE type, ++ const char *str, int len, X509_OBJECT *ret) ++{ ++ if ((ctx->method == NULL) || (ctx->method->get_by_alias == NULL)) ++ return 0; ++ return ctx->method->get_by_alias(ctx, type, str, len, ret); ++} ++ ++static int x509_object_cmp(const X509_OBJECT *const *a, ++ const X509_OBJECT *const *b) ++{ ++ int ret; ++ ++ ret = ((*a)->type - (*b)->type); ++ if (ret) ++ return ret; ++ switch ((*a)->type) { ++ case X509_LU_X509: ++ ret = X509_subject_name_cmp((*a)->data.x509, (*b)->data.x509); ++ break; ++ case X509_LU_CRL: ++ ret = X509_CRL_cmp((*a)->data.crl, (*b)->data.crl); ++ break; ++ default: ++ /* abort(); */ ++ return 0; ++ } ++ return ret; ++} ++ ++X509_STORE *X509_STORE_new(void) ++{ ++ X509_STORE *ret; ++ ++ if ((ret = OPENSSL_zalloc(sizeof(*ret))) == NULL) ++ return NULL; ++ if ((ret->objs = sk_X509_OBJECT_new(x509_object_cmp)) == NULL) ++ goto err; ++ ret->cache = 1; ++ if ((ret->get_cert_methods = sk_X509_LOOKUP_new_null()) == NULL) ++ goto err; ++ ++ if ((ret->param = X509_VERIFY_PARAM_new()) == NULL) ++ goto err; ++ ++ if (!CRYPTO_new_ex_data(CRYPTO_EX_INDEX_X509_STORE, ret, &ret->ex_data)) ++ goto err; ++ ++ ret->lock = CRYPTO_THREAD_lock_new(); ++ if (ret->lock == NULL) ++ goto err; ++ ++ ret->references = 1; ++ return ret; ++ ++err: ++ X509_VERIFY_PARAM_free(ret->param); ++ sk_X509_OBJECT_free(ret->objs); ++ sk_X509_LOOKUP_free(ret->get_cert_methods); ++ OPENSSL_free(ret); ++ return NULL; ++} ++ ++static void cleanup(X509_OBJECT *a) ++{ ++ if (!a) ++ return; ++ if (a->type == X509_LU_X509) { ++ X509_free(a->data.x509); ++ } else if (a->type == X509_LU_CRL) { ++ X509_CRL_free(a->data.crl); ++ } else { ++ /* abort(); */ ++ } ++ ++ OPENSSL_free(a); ++} ++ ++void X509_STORE_free(X509_STORE *vfy) ++{ ++ int i; ++ STACK_OF(X509_LOOKUP) *sk; ++ X509_LOOKUP *lu; ++ ++ if (vfy == NULL) ++ return; ++ ++ CRYPTO_atomic_add(&vfy->references, -1, &i, vfy->lock); ++ REF_PRINT_COUNT("X509_STORE", vfy); ++ if (i > 0) ++ return; ++ REF_ASSERT_ISNT(i < 0); ++ ++ sk = vfy->get_cert_methods; ++ for (i = 0; i < sk_X509_LOOKUP_num(sk); i++) { ++ lu = sk_X509_LOOKUP_value(sk, i); ++ X509_LOOKUP_shutdown(lu); ++ X509_LOOKUP_free(lu); ++ } ++ sk_X509_LOOKUP_free(sk); ++ sk_X509_OBJECT_pop_free(vfy->objs, cleanup); ++ ++ CRYPTO_free_ex_data(CRYPTO_EX_INDEX_X509_STORE, vfy, &vfy->ex_data); ++ X509_VERIFY_PARAM_free(vfy->param); ++ CRYPTO_THREAD_lock_free(vfy->lock); ++ OPENSSL_free(vfy); ++} ++ ++int X509_STORE_up_ref(X509_STORE *vfy) ++{ ++ int i; ++ ++ if (CRYPTO_atomic_add(&vfy->references, 1, &i, vfy->lock) <= 0) ++ return 0; ++ ++ REF_PRINT_COUNT("X509_STORE", a); ++ REF_ASSERT_ISNT(i < 2); ++ return ((i > 1) ? 1 : 0); ++} ++ ++X509_LOOKUP *X509_STORE_add_lookup(X509_STORE *v, X509_LOOKUP_METHOD *m) ++{ ++ int i; ++ STACK_OF(X509_LOOKUP) *sk; ++ X509_LOOKUP *lu; ++ ++ sk = v->get_cert_methods; ++ for (i = 0; i < sk_X509_LOOKUP_num(sk); i++) { ++ lu = sk_X509_LOOKUP_value(sk, i); ++ if (m == lu->method) { ++ return lu; ++ } ++ } ++ /* a new one */ ++ lu = X509_LOOKUP_new(m); ++ if (lu == NULL) ++ return NULL; ++ else { ++ lu->store_ctx = v; ++ if (sk_X509_LOOKUP_push(v->get_cert_methods, lu)) ++ return lu; ++ else { ++ X509_LOOKUP_free(lu); ++ return NULL; ++ } ++ } ++} ++ ++X509_OBJECT *X509_STORE_CTX_get_obj_by_subject(X509_STORE_CTX *vs, ++ X509_LOOKUP_TYPE type, ++ X509_NAME *name) ++{ ++ X509_OBJECT *ret = X509_OBJECT_new(); ++ ++ if (ret == NULL) ++ return NULL; ++ if (!X509_STORE_CTX_get_by_subject(vs, type, name, ret)) { ++ X509_OBJECT_free(ret); ++ return NULL; ++ } ++ return ret; ++} ++ ++int X509_STORE_CTX_get_by_subject(X509_STORE_CTX *vs, X509_LOOKUP_TYPE type, ++ X509_NAME *name, X509_OBJECT *ret) ++{ ++ X509_STORE *ctx = vs->ctx; ++ X509_LOOKUP *lu; ++ X509_OBJECT stmp, *tmp; ++ int i, j; ++ ++ CRYPTO_THREAD_write_lock(ctx->lock); ++ tmp = X509_OBJECT_retrieve_by_subject(ctx->objs, type, name); ++ CRYPTO_THREAD_unlock(ctx->lock); ++ ++ if (tmp == NULL || type == X509_LU_CRL) { ++ for (i = 0; i < sk_X509_LOOKUP_num(ctx->get_cert_methods); i++) { ++ lu = sk_X509_LOOKUP_value(ctx->get_cert_methods, i); ++ j = X509_LOOKUP_by_subject(lu, type, name, &stmp); ++ if (j) { ++ tmp = &stmp; ++ break; ++ } ++ } ++ if (tmp == NULL) ++ return 0; ++ } ++ ++ ret->type = tmp->type; ++ ret->data.ptr = tmp->data.ptr; ++ ++ X509_OBJECT_up_ref_count(ret); ++ ++ return 1; ++} ++ ++int X509_STORE_add_cert(X509_STORE *ctx, X509 *x) ++{ ++ X509_OBJECT *obj; ++ int ret = 1, added = 1; ++ ++ if (x == NULL) ++ return 0; ++ obj = X509_OBJECT_new(); ++ if (obj == NULL) ++ return 0; ++ obj->type = X509_LU_X509; ++ obj->data.x509 = x; ++ X509_OBJECT_up_ref_count(obj); ++ ++ CRYPTO_THREAD_write_lock(ctx->lock); ++ ++ if (X509_OBJECT_retrieve_match(ctx->objs, obj)) { ++ X509err(X509_F_X509_STORE_ADD_CERT, ++ X509_R_CERT_ALREADY_IN_HASH_TABLE); ++ ret = 0; ++ } else { ++ added = sk_X509_OBJECT_push(ctx->objs, obj); ++ ret = added != 0; ++ } ++ ++ CRYPTO_THREAD_unlock(ctx->lock); ++ ++ if (!ret) /* obj not pushed */ ++ X509_OBJECT_free(obj); ++ if (!added) /* on push failure */ ++ X509err(X509_F_X509_STORE_ADD_CERT, ERR_R_MALLOC_FAILURE); ++ ++ return ret; ++} ++ ++int X509_STORE_add_crl(X509_STORE *ctx, X509_CRL *x) ++{ ++ X509_OBJECT *obj; ++ int ret = 1, added = 1; ++ ++ if (x == NULL) ++ return 0; ++ obj = X509_OBJECT_new(); ++ if (obj == NULL) ++ return 0; ++ obj->type = X509_LU_CRL; ++ obj->data.crl = x; ++ X509_OBJECT_up_ref_count(obj); ++ ++ CRYPTO_THREAD_write_lock(ctx->lock); ++ ++ if (X509_OBJECT_retrieve_match(ctx->objs, obj)) { ++ X509err(X509_F_X509_STORE_ADD_CRL, X509_R_CERT_ALREADY_IN_HASH_TABLE); ++ ret = 0; ++ } else { ++ added = sk_X509_OBJECT_push(ctx->objs, obj); ++ ret = added != 0; ++ } ++ ++ CRYPTO_THREAD_unlock(ctx->lock); ++ ++ if (!ret) /* obj not pushed */ ++ X509_OBJECT_free(obj); ++ if (!added) /* on push failure */ ++ X509err(X509_F_X509_STORE_ADD_CRL, ERR_R_MALLOC_FAILURE); ++ ++ return ret; ++} ++ ++int X509_OBJECT_up_ref_count(X509_OBJECT *a) ++{ ++ switch (a->type) { ++ default: ++ break; ++ case X509_LU_X509: ++ return X509_up_ref(a->data.x509); ++ case X509_LU_CRL: ++ return X509_CRL_up_ref(a->data.crl); ++ } ++ return 1; ++} ++ ++X509 *X509_OBJECT_get0_X509(const X509_OBJECT *a) ++{ ++ if (a == NULL || a->type != X509_LU_X509) ++ return NULL; ++ return a->data.x509; ++} ++ ++X509_CRL *X509_OBJECT_get0_X509_CRL(X509_OBJECT *a) ++{ ++ if (a == NULL || a->type != X509_LU_CRL) ++ return NULL; ++ return a->data.crl; ++} ++ ++X509_LOOKUP_TYPE X509_OBJECT_get_type(const X509_OBJECT *a) ++{ ++ return a->type; ++} ++ ++X509_OBJECT *X509_OBJECT_new() ++{ ++ X509_OBJECT *ret = OPENSSL_zalloc(sizeof(*ret)); ++ ++ if (ret == NULL) { ++ X509err(X509_F_X509_OBJECT_NEW, ERR_R_MALLOC_FAILURE); ++ return NULL; ++ } ++ ret->type = X509_LU_NONE; ++ return ret; ++} ++ ++ ++void X509_OBJECT_free(X509_OBJECT *a) ++{ ++ if (a == NULL) ++ return; ++ switch (a->type) { ++ default: ++ break; ++ case X509_LU_X509: ++ X509_free(a->data.x509); ++ break; ++ case X509_LU_CRL: ++ X509_CRL_free(a->data.crl); ++ break; ++ } ++ OPENSSL_free(a); ++} ++ ++static int x509_object_idx_cnt(STACK_OF(X509_OBJECT) *h, X509_LOOKUP_TYPE type, ++ X509_NAME *name, int *pnmatch) ++{ ++ X509_OBJECT stmp; ++ X509 x509_s; ++ X509_CRL crl_s; ++ int idx; ++ ++ stmp.type = type; ++ switch (type) { ++ case X509_LU_X509: ++ stmp.data.x509 = &x509_s; ++ x509_s.cert_info.subject = name; ++ break; ++ case X509_LU_CRL: ++ stmp.data.crl = &crl_s; ++ crl_s.crl.issuer = name; ++ break; ++ default: ++ /* abort(); */ ++ return -1; ++ } ++ ++ idx = sk_X509_OBJECT_find(h, &stmp); ++ if (idx >= 0 && pnmatch) { ++ int tidx; ++ const X509_OBJECT *tobj, *pstmp; ++ *pnmatch = 1; ++ pstmp = &stmp; ++ for (tidx = idx + 1; tidx < sk_X509_OBJECT_num(h); tidx++) { ++ tobj = sk_X509_OBJECT_value(h, tidx); ++ if (x509_object_cmp(&tobj, &pstmp)) ++ break; ++ (*pnmatch)++; ++ } ++ } ++ return idx; ++} ++ ++int X509_OBJECT_idx_by_subject(STACK_OF(X509_OBJECT) *h, X509_LOOKUP_TYPE type, ++ X509_NAME *name) ++{ ++ return x509_object_idx_cnt(h, type, name, NULL); ++} ++ ++X509_OBJECT *X509_OBJECT_retrieve_by_subject(STACK_OF(X509_OBJECT) *h, ++ X509_LOOKUP_TYPE type, ++ X509_NAME *name) ++{ ++ int idx; ++ idx = X509_OBJECT_idx_by_subject(h, type, name); ++ if (idx == -1) ++ return NULL; ++ return sk_X509_OBJECT_value(h, idx); ++} ++ ++STACK_OF(X509_OBJECT) *X509_STORE_get0_objects(X509_STORE *v) ++{ ++ return v->objs; ++} ++ ++STACK_OF(X509) *X509_STORE_CTX_get1_certs(X509_STORE_CTX *ctx, X509_NAME *nm) ++{ ++ int i, idx, cnt; ++ STACK_OF(X509) *sk = NULL; ++ X509 *x; ++ X509_OBJECT *obj; ++ ++ CRYPTO_THREAD_write_lock(ctx->ctx->lock); ++ idx = x509_object_idx_cnt(ctx->ctx->objs, X509_LU_X509, nm, &cnt); ++ if (idx < 0) { ++ /* ++ * Nothing found in cache: do lookup to possibly add new objects to ++ * cache ++ */ ++ X509_OBJECT *xobj = X509_OBJECT_new(); ++ ++ CRYPTO_THREAD_unlock(ctx->ctx->lock); ++ if (xobj == NULL) ++ return NULL; ++ if (!X509_STORE_CTX_get_by_subject(ctx, X509_LU_X509, nm, xobj)) { ++ X509_OBJECT_free(xobj); ++ return NULL; ++ } ++ X509_OBJECT_free(xobj); ++ CRYPTO_THREAD_write_lock(ctx->ctx->lock); ++ idx = x509_object_idx_cnt(ctx->ctx->objs, X509_LU_X509, nm, &cnt); ++ if (idx < 0) { ++ CRYPTO_THREAD_unlock(ctx->ctx->lock); ++ return NULL; ++ } ++ } ++ ++ sk = sk_X509_new_null(); ++ for (i = 0; i < cnt; i++, idx++) { ++ obj = sk_X509_OBJECT_value(ctx->ctx->objs, idx); ++ x = obj->data.x509; ++ X509_up_ref(x); ++ if (!sk_X509_push(sk, x)) { ++ CRYPTO_THREAD_unlock(ctx->ctx->lock); ++ X509_free(x); ++ sk_X509_pop_free(sk, X509_free); ++ return NULL; ++ } ++ } ++ CRYPTO_THREAD_unlock(ctx->ctx->lock); ++ return sk; ++} ++ ++STACK_OF(X509_CRL) *X509_STORE_CTX_get1_crls(X509_STORE_CTX *ctx, X509_NAME *nm) ++{ ++ int i, idx, cnt; ++ STACK_OF(X509_CRL) *sk = sk_X509_CRL_new_null(); ++ X509_CRL *x; ++ X509_OBJECT *obj, *xobj = X509_OBJECT_new(); ++ ++ /* Always do lookup to possibly add new CRLs to cache */ ++ if (sk == NULL || xobj == NULL || ++ !X509_STORE_CTX_get_by_subject(ctx, X509_LU_CRL, nm, xobj)) { ++ X509_OBJECT_free(xobj); ++ sk_X509_CRL_free(sk); ++ return NULL; ++ } ++ X509_OBJECT_free(xobj); ++ CRYPTO_THREAD_write_lock(ctx->ctx->lock); ++ idx = x509_object_idx_cnt(ctx->ctx->objs, X509_LU_CRL, nm, &cnt); ++ if (idx < 0) { ++ CRYPTO_THREAD_unlock(ctx->ctx->lock); ++ sk_X509_CRL_free(sk); ++ return NULL; ++ } ++ ++ for (i = 0; i < cnt; i++, idx++) { ++ obj = sk_X509_OBJECT_value(ctx->ctx->objs, idx); ++ x = obj->data.crl; ++ X509_CRL_up_ref(x); ++ if (!sk_X509_CRL_push(sk, x)) { ++ CRYPTO_THREAD_unlock(ctx->ctx->lock); ++ X509_CRL_free(x); ++ sk_X509_CRL_pop_free(sk, X509_CRL_free); ++ return NULL; ++ } ++ } ++ CRYPTO_THREAD_unlock(ctx->ctx->lock); ++ return sk; ++} ++ ++X509_OBJECT *X509_OBJECT_retrieve_match(STACK_OF(X509_OBJECT) *h, ++ X509_OBJECT *x) ++{ ++ int idx, i; ++ X509_OBJECT *obj; ++ idx = sk_X509_OBJECT_find(h, x); ++ if (idx == -1) ++ return NULL; ++ if ((x->type != X509_LU_X509) && (x->type != X509_LU_CRL)) ++ return sk_X509_OBJECT_value(h, idx); ++ for (i = idx; i < sk_X509_OBJECT_num(h); i++) { ++ obj = sk_X509_OBJECT_value(h, i); ++ if (x509_object_cmp ++ ((const X509_OBJECT **)&obj, (const X509_OBJECT **)&x)) ++ return NULL; ++ if (x->type == X509_LU_X509) { ++ if (!X509_cmp(obj->data.x509, x->data.x509)) ++ return obj; ++ } else if (x->type == X509_LU_CRL) { ++ if (!X509_CRL_match(obj->data.crl, x->data.crl)) ++ return obj; ++ } else ++ return obj; ++ } ++ return NULL; ++} ++ ++/*- ++ * Try to get issuer certificate from store. Due to limitations ++ * of the API this can only retrieve a single certificate matching ++ * a given subject name. However it will fill the cache with all ++ * matching certificates, so we can examine the cache for all ++ * matches. ++ * ++ * Return values are: ++ * 1 lookup successful. ++ * 0 certificate not found. ++ * -1 some other error. ++ */ ++int X509_STORE_CTX_get1_issuer(X509 **issuer, X509_STORE_CTX *ctx, X509 *x) ++{ ++ X509_NAME *xn; ++ X509_OBJECT *obj = X509_OBJECT_new(), *pobj = NULL; ++ int i, ok, idx, ret; ++ ++ if (obj == NULL) ++ return -1; ++ *issuer = NULL; ++ xn = X509_get_issuer_name(x); ++ ok = X509_STORE_CTX_get_by_subject(ctx, X509_LU_X509, xn, obj); ++ if (ok != 1) { ++ X509_OBJECT_free(obj); ++ return 0; ++ } ++ /* If certificate matches all OK */ ++ if (ctx->check_issued(ctx, x, obj->data.x509)) { ++ if (x509_check_cert_time(ctx, obj->data.x509, -1)) { ++ *issuer = obj->data.x509; ++ X509_up_ref(*issuer); ++ X509_OBJECT_free(obj); ++ return 1; ++ } ++ } ++ X509_OBJECT_free(obj); ++ ++ /* Else find index of first cert accepted by 'check_issued' */ ++ ret = 0; ++ CRYPTO_THREAD_write_lock(ctx->ctx->lock); ++ idx = X509_OBJECT_idx_by_subject(ctx->ctx->objs, X509_LU_X509, xn); ++ if (idx != -1) { /* should be true as we've had at least one ++ * match */ ++ /* Look through all matching certs for suitable issuer */ ++ for (i = idx; i < sk_X509_OBJECT_num(ctx->ctx->objs); i++) { ++ pobj = sk_X509_OBJECT_value(ctx->ctx->objs, i); ++ /* See if we've run past the matches */ ++ if (pobj->type != X509_LU_X509) ++ break; ++ if (X509_NAME_cmp(xn, X509_get_subject_name(pobj->data.x509))) ++ break; ++ if (ctx->check_issued(ctx, x, pobj->data.x509)) { ++ *issuer = pobj->data.x509; ++ ret = 1; ++ /* ++ * If times check, exit with match, ++ * otherwise keep looking. Leave last ++ * match in issuer so we return nearest ++ * match if no certificate time is OK. ++ */ ++ ++ if (x509_check_cert_time(ctx, *issuer, -1)) ++ break; ++ } ++ } ++ } ++ CRYPTO_THREAD_unlock(ctx->ctx->lock); ++ if (*issuer) ++ X509_up_ref(*issuer); ++ return ret; ++} ++ ++int X509_STORE_set_flags(X509_STORE *ctx, unsigned long flags) ++{ ++ return X509_VERIFY_PARAM_set_flags(ctx->param, flags); ++} ++ ++int X509_STORE_set_depth(X509_STORE *ctx, int depth) ++{ ++ X509_VERIFY_PARAM_set_depth(ctx->param, depth); ++ return 1; ++} ++ ++int X509_STORE_set_purpose(X509_STORE *ctx, int purpose) ++{ ++ return X509_VERIFY_PARAM_set_purpose(ctx->param, purpose); ++} ++ ++int X509_STORE_set_trust(X509_STORE *ctx, int trust) ++{ ++ return X509_VERIFY_PARAM_set_trust(ctx->param, trust); ++} ++ ++int X509_STORE_set1_param(X509_STORE *ctx, X509_VERIFY_PARAM *param) ++{ ++ return X509_VERIFY_PARAM_set1(ctx->param, param); ++} ++ ++X509_VERIFY_PARAM *X509_STORE_get0_param(X509_STORE *ctx) ++{ ++ return ctx->param; ++} ++ ++void X509_STORE_set_verify(X509_STORE *ctx, X509_STORE_CTX_verify_fn verify) ++{ ++ ctx->verify = verify; ++} ++ ++X509_STORE_CTX_verify_fn X509_STORE_get_verify(X509_STORE *ctx) ++{ ++ return ctx->verify; ++} ++ ++void X509_STORE_set_verify_cb(X509_STORE *ctx, ++ X509_STORE_CTX_verify_cb verify_cb) ++{ ++ ctx->verify_cb = verify_cb; ++} ++ ++X509_STORE_CTX_verify_cb X509_STORE_get_verify_cb(X509_STORE *ctx) ++{ ++ return ctx->verify_cb; ++} ++ ++void X509_STORE_set_get_issuer(X509_STORE *ctx, ++ X509_STORE_CTX_get_issuer_fn get_issuer) ++{ ++ ctx->get_issuer = get_issuer; ++} ++ ++X509_STORE_CTX_get_issuer_fn X509_STORE_get_get_issuer(X509_STORE *ctx) ++{ ++ return ctx->get_issuer; ++} ++ ++void X509_STORE_set_check_issued(X509_STORE *ctx, ++ X509_STORE_CTX_check_issued_fn check_issued) ++{ ++ ctx->check_issued = check_issued; ++} ++ ++X509_STORE_CTX_check_issued_fn X509_STORE_get_check_issued(X509_STORE *ctx) ++{ ++ return ctx->check_issued; ++} ++ ++void X509_STORE_set_check_revocation(X509_STORE *ctx, ++ X509_STORE_CTX_check_revocation_fn check_revocation) ++{ ++ ctx->check_revocation = check_revocation; ++} ++ ++X509_STORE_CTX_check_revocation_fn X509_STORE_get_check_revocation(X509_STORE *ctx) ++{ ++ return ctx->check_revocation; ++} ++ ++void X509_STORE_set_get_crl(X509_STORE *ctx, ++ X509_STORE_CTX_get_crl_fn get_crl) ++{ ++ ctx->get_crl = get_crl; ++} ++ ++X509_STORE_CTX_get_crl_fn X509_STORE_get_get_crl(X509_STORE *ctx) ++{ ++ return ctx->get_crl; ++} ++ ++void X509_STORE_set_check_crl(X509_STORE *ctx, ++ X509_STORE_CTX_check_crl_fn check_crl) ++{ ++ ctx->check_crl = check_crl; ++} ++ ++X509_STORE_CTX_check_crl_fn X509_STORE_get_check_crl(X509_STORE *ctx) ++{ ++ return ctx->check_crl; ++} ++ ++void X509_STORE_set_cert_crl(X509_STORE *ctx, ++ X509_STORE_CTX_cert_crl_fn cert_crl) ++{ ++ ctx->cert_crl = cert_crl; ++} ++ ++X509_STORE_CTX_cert_crl_fn X509_STORE_get_cert_crl(X509_STORE *ctx) ++{ ++ return ctx->cert_crl; ++} ++ ++void X509_STORE_set_check_policy(X509_STORE *ctx, ++ X509_STORE_CTX_check_policy_fn check_policy) ++{ ++ ctx->check_policy = check_policy; ++} ++ ++X509_STORE_CTX_check_policy_fn X509_STORE_get_check_policy(X509_STORE *ctx) ++{ ++ return ctx->check_policy; ++} ++ ++void X509_STORE_set_lookup_certs(X509_STORE *ctx, ++ X509_STORE_CTX_lookup_certs_fn lookup_certs) ++{ ++ ctx->lookup_certs = lookup_certs; ++} ++ ++X509_STORE_CTX_lookup_certs_fn X509_STORE_get_lookup_certs(X509_STORE *ctx) ++{ ++ return ctx->lookup_certs; ++} ++ ++void X509_STORE_set_lookup_crls(X509_STORE *ctx, ++ X509_STORE_CTX_lookup_crls_fn lookup_crls) ++{ ++ ctx->lookup_crls = lookup_crls; ++} ++ ++X509_STORE_CTX_lookup_crls_fn X509_STORE_get_lookup_crls(X509_STORE *ctx) ++{ ++ return ctx->lookup_crls; ++} ++ ++void X509_STORE_set_cleanup(X509_STORE *ctx, ++ X509_STORE_CTX_cleanup_fn ctx_cleanup) ++{ ++ ctx->cleanup = ctx_cleanup; ++} ++ ++X509_STORE_CTX_cleanup_fn X509_STORE_get_cleanup(X509_STORE *ctx) ++{ ++ return ctx->cleanup; ++} ++ ++int X509_STORE_set_ex_data(X509_STORE *ctx, int idx, void *data) ++{ ++ return CRYPTO_set_ex_data(&ctx->ex_data, idx, data); ++} ++ ++void *X509_STORE_get_ex_data(X509_STORE *ctx, int idx) ++{ ++ return CRYPTO_get_ex_data(&ctx->ex_data, idx); ++} ++ ++X509_STORE *X509_STORE_CTX_get0_store(X509_STORE_CTX *ctx) ++{ ++ return ctx->ctx; ++} +diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/x509/x509_obj.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/x509/x509_obj.c +new file mode 100644 +index 0000000..55dc778 +--- /dev/null ++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/x509/x509_obj.c +@@ -0,0 +1,182 @@ ++/* ++ * Copyright 1995-2016 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 ++ * in the file LICENSE in the source distribution or at ++ * https://www.openssl.org/source/license.html ++ */ ++ ++#include ++#include "internal/cryptlib.h" ++#include ++#include ++#include ++#include ++#include "internal/x509_int.h" ++ ++/* ++ * Limit to ensure we don't overflow: much greater than ++ * anything encountered in practice. ++ */ ++ ++#define NAME_ONELINE_MAX (1024 * 1024) ++ ++char *X509_NAME_oneline(const X509_NAME *a, char *buf, int len) ++{ ++ const X509_NAME_ENTRY *ne; ++ int i; ++ int n, lold, l, l1, l2, num, j, type; ++ const char *s; ++ char *p; ++ unsigned char *q; ++ BUF_MEM *b = NULL; ++ static const char hex[17] = "0123456789ABCDEF"; ++ int gs_doit[4]; ++ char tmp_buf[80]; ++#ifdef CHARSET_EBCDIC ++ unsigned char ebcdic_buf[1024]; ++#endif ++ ++ if (buf == NULL) { ++ if ((b = BUF_MEM_new()) == NULL) ++ goto err; ++ if (!BUF_MEM_grow(b, 200)) ++ goto err; ++ b->data[0] = '\0'; ++ len = 200; ++ } else if (len == 0) { ++ return NULL; ++ } ++ if (a == NULL) { ++ if (b) { ++ buf = b->data; ++ OPENSSL_free(b); ++ } ++ strncpy(buf, "NO X509_NAME", len); ++ buf[len - 1] = '\0'; ++ return buf; ++ } ++ ++ len--; /* space for '\0' */ ++ l = 0; ++ for (i = 0; i < sk_X509_NAME_ENTRY_num(a->entries); i++) { ++ ne = sk_X509_NAME_ENTRY_value(a->entries, i); ++ n = OBJ_obj2nid(ne->object); ++ if ((n == NID_undef) || ((s = OBJ_nid2sn(n)) == NULL)) { ++ i2t_ASN1_OBJECT(tmp_buf, sizeof(tmp_buf), ne->object); ++ s = tmp_buf; ++ } ++ l1 = strlen(s); ++ ++ type = ne->value->type; ++ num = ne->value->length; ++ if (num > NAME_ONELINE_MAX) { ++ X509err(X509_F_X509_NAME_ONELINE, X509_R_NAME_TOO_LONG); ++ goto end; ++ } ++ q = ne->value->data; ++#ifdef CHARSET_EBCDIC ++ if (type == V_ASN1_GENERALSTRING || ++ type == V_ASN1_VISIBLESTRING || ++ type == V_ASN1_PRINTABLESTRING || ++ type == V_ASN1_TELETEXSTRING || ++ type == V_ASN1_IA5STRING) { ++ if (num > (int)sizeof(ebcdic_buf)) ++ num = sizeof(ebcdic_buf); ++ ascii2ebcdic(ebcdic_buf, q, num); ++ q = ebcdic_buf; ++ } ++#endif ++ ++ if ((type == V_ASN1_GENERALSTRING) && ((num % 4) == 0)) { ++ gs_doit[0] = gs_doit[1] = gs_doit[2] = gs_doit[3] = 0; ++ for (j = 0; j < num; j++) ++ if (q[j] != 0) ++ gs_doit[j & 3] = 1; ++ ++ if (gs_doit[0] | gs_doit[1] | gs_doit[2]) ++ gs_doit[0] = gs_doit[1] = gs_doit[2] = gs_doit[3] = 1; ++ else { ++ gs_doit[0] = gs_doit[1] = gs_doit[2] = 0; ++ gs_doit[3] = 1; ++ } ++ } else ++ gs_doit[0] = gs_doit[1] = gs_doit[2] = gs_doit[3] = 1; ++ ++ for (l2 = j = 0; j < num; j++) { ++ if (!gs_doit[j & 3]) ++ continue; ++ l2++; ++#ifndef CHARSET_EBCDIC ++ if ((q[j] < ' ') || (q[j] > '~')) ++ l2 += 3; ++#else ++ if ((os_toascii[q[j]] < os_toascii[' ']) || ++ (os_toascii[q[j]] > os_toascii['~'])) ++ l2 += 3; ++#endif ++ } ++ ++ lold = l; ++ l += 1 + l1 + 1 + l2; ++ if (l > NAME_ONELINE_MAX) { ++ X509err(X509_F_X509_NAME_ONELINE, X509_R_NAME_TOO_LONG); ++ goto end; ++ } ++ if (b != NULL) { ++ if (!BUF_MEM_grow(b, l + 1)) ++ goto err; ++ p = &(b->data[lold]); ++ } else if (l > len) { ++ break; ++ } else ++ p = &(buf[lold]); ++ *(p++) = '/'; ++ memcpy(p, s, (unsigned int)l1); ++ p += l1; ++ *(p++) = '='; ++ ++#ifndef CHARSET_EBCDIC /* q was assigned above already. */ ++ q = ne->value->data; ++#endif ++ ++ for (j = 0; j < num; j++) { ++ if (!gs_doit[j & 3]) ++ continue; ++#ifndef CHARSET_EBCDIC ++ n = q[j]; ++ if ((n < ' ') || (n > '~')) { ++ *(p++) = '\\'; ++ *(p++) = 'x'; ++ *(p++) = hex[(n >> 4) & 0x0f]; ++ *(p++) = hex[n & 0x0f]; ++ } else ++ *(p++) = n; ++#else ++ n = os_toascii[q[j]]; ++ if ((n < os_toascii[' ']) || (n > os_toascii['~'])) { ++ *(p++) = '\\'; ++ *(p++) = 'x'; ++ *(p++) = hex[(n >> 4) & 0x0f]; ++ *(p++) = hex[n & 0x0f]; ++ } else ++ *(p++) = q[j]; ++#endif ++ } ++ *p = '\0'; ++ } ++ if (b != NULL) { ++ p = b->data; ++ OPENSSL_free(b); ++ } else ++ p = buf; ++ if (i == 0) ++ *p = '\0'; ++ return (p); ++ err: ++ X509err(X509_F_X509_NAME_ONELINE, ERR_R_MALLOC_FAILURE); ++ end: ++ BUF_MEM_free(b); ++ return (NULL); ++} +diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/x509/x509_r2x.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/x509/x509_r2x.c +new file mode 100644 +index 0000000..3d72787 +--- /dev/null ++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/x509/x509_r2x.c +@@ -0,0 +1,67 @@ ++/* ++ * Copyright 1995-2016 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 ++ * in the file LICENSE in the source distribution or at ++ * https://www.openssl.org/source/license.html ++ */ ++ ++#include ++#include "internal/cryptlib.h" ++#include ++#include ++#include ++#include ++#include "internal/x509_int.h" ++#include ++#include ++ ++X509 *X509_REQ_to_X509(X509_REQ *r, int days, EVP_PKEY *pkey) ++{ ++ X509 *ret = NULL; ++ X509_CINF *xi = NULL; ++ X509_NAME *xn; ++ EVP_PKEY *pubkey = NULL; ++ ++ if ((ret = X509_new()) == NULL) { ++ X509err(X509_F_X509_REQ_TO_X509, ERR_R_MALLOC_FAILURE); ++ return NULL; ++ } ++ ++ /* duplicate the request */ ++ xi = &ret->cert_info; ++ ++ if (sk_X509_ATTRIBUTE_num(r->req_info.attributes) != 0) { ++ if ((xi->version = ASN1_INTEGER_new()) == NULL) ++ goto err; ++ if (!ASN1_INTEGER_set(xi->version, 2)) ++ goto err; ++/*- xi->extensions=ri->attributes; <- bad, should not ever be done ++ ri->attributes=NULL; */ ++ } ++ ++ xn = X509_REQ_get_subject_name(r); ++ if (X509_set_subject_name(ret, xn) == 0) ++ goto err; ++ if (X509_set_issuer_name(ret, xn) == 0) ++ goto err; ++ ++ if (X509_gmtime_adj(xi->validity.notBefore, 0) == NULL) ++ goto err; ++ if (X509_gmtime_adj(xi->validity.notAfter, (long)60 * 60 * 24 * days) == ++ NULL) ++ goto err; ++ ++ pubkey = X509_REQ_get0_pubkey(r); ++ if (pubkey == NULL || !X509_set_pubkey(ret, pubkey)) ++ goto err; ++ ++ if (!X509_sign(ret, pkey, EVP_md5())) ++ goto err; ++ return ret; ++ ++ err: ++ X509_free(ret); ++ return NULL; ++} +diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/x509/x509_req.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/x509/x509_req.c +new file mode 100644 +index 0000000..7b88dbc +--- /dev/null ++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/x509/x509_req.c +@@ -0,0 +1,298 @@ ++/* ++ * Copyright 1995-2016 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 ++ * in the file LICENSE in the source distribution or at ++ * https://www.openssl.org/source/license.html ++ */ ++ ++#include ++#include "internal/cryptlib.h" ++#include ++#include ++#include ++#include ++#include ++#include "internal/x509_int.h" ++#include ++#include ++#include ++ ++X509_REQ *X509_to_X509_REQ(X509 *x, EVP_PKEY *pkey, const EVP_MD *md) ++{ ++ X509_REQ *ret; ++ X509_REQ_INFO *ri; ++ int i; ++ EVP_PKEY *pktmp; ++ ++ ret = X509_REQ_new(); ++ if (ret == NULL) { ++ X509err(X509_F_X509_TO_X509_REQ, ERR_R_MALLOC_FAILURE); ++ goto err; ++ } ++ ++ ri = &ret->req_info; ++ ++ ri->version->length = 1; ++ ri->version->data = OPENSSL_malloc(1); ++ if (ri->version->data == NULL) ++ goto err; ++ ri->version->data[0] = 0; /* version == 0 */ ++ ++ if (!X509_REQ_set_subject_name(ret, X509_get_subject_name(x))) ++ goto err; ++ ++ pktmp = X509_get0_pubkey(x); ++ if (pktmp == NULL) ++ goto err; ++ i = X509_REQ_set_pubkey(ret, pktmp); ++ if (!i) ++ goto err; ++ ++ if (pkey != NULL) { ++ if (!X509_REQ_sign(ret, pkey, md)) ++ goto err; ++ } ++ return (ret); ++ err: ++ X509_REQ_free(ret); ++ return (NULL); ++} ++ ++EVP_PKEY *X509_REQ_get_pubkey(X509_REQ *req) ++{ ++ if (req == NULL) ++ return (NULL); ++ return (X509_PUBKEY_get(req->req_info.pubkey)); ++} ++ ++EVP_PKEY *X509_REQ_get0_pubkey(X509_REQ *req) ++{ ++ if (req == NULL) ++ return NULL; ++ return (X509_PUBKEY_get0(req->req_info.pubkey)); ++} ++ ++X509_PUBKEY *X509_REQ_get_X509_PUBKEY(X509_REQ *req) ++{ ++ return req->req_info.pubkey; ++} ++ ++int X509_REQ_check_private_key(X509_REQ *x, EVP_PKEY *k) ++{ ++ EVP_PKEY *xk = NULL; ++ int ok = 0; ++ ++ xk = X509_REQ_get_pubkey(x); ++ switch (EVP_PKEY_cmp(xk, k)) { ++ case 1: ++ ok = 1; ++ break; ++ case 0: ++ X509err(X509_F_X509_REQ_CHECK_PRIVATE_KEY, ++ X509_R_KEY_VALUES_MISMATCH); ++ break; ++ case -1: ++ X509err(X509_F_X509_REQ_CHECK_PRIVATE_KEY, X509_R_KEY_TYPE_MISMATCH); ++ break; ++ case -2: ++#ifndef OPENSSL_NO_EC ++ if (EVP_PKEY_id(k) == EVP_PKEY_EC) { ++ X509err(X509_F_X509_REQ_CHECK_PRIVATE_KEY, ERR_R_EC_LIB); ++ break; ++ } ++#endif ++#ifndef OPENSSL_NO_DH ++ if (EVP_PKEY_id(k) == EVP_PKEY_DH) { ++ /* No idea */ ++ X509err(X509_F_X509_REQ_CHECK_PRIVATE_KEY, ++ X509_R_CANT_CHECK_DH_KEY); ++ break; ++ } ++#endif ++ X509err(X509_F_X509_REQ_CHECK_PRIVATE_KEY, X509_R_UNKNOWN_KEY_TYPE); ++ } ++ ++ EVP_PKEY_free(xk); ++ return (ok); ++} ++ ++/* ++ * It seems several organisations had the same idea of including a list of ++ * extensions in a certificate request. There are at least two OIDs that are ++ * used and there may be more: so the list is configurable. ++ */ ++ ++static int ext_nid_list[] = { NID_ext_req, NID_ms_ext_req, NID_undef }; ++ ++static int *ext_nids = ext_nid_list; ++ ++int X509_REQ_extension_nid(int req_nid) ++{ ++ int i, nid; ++ for (i = 0;; i++) { ++ nid = ext_nids[i]; ++ if (nid == NID_undef) ++ return 0; ++ else if (req_nid == nid) ++ return 1; ++ } ++} ++ ++int *X509_REQ_get_extension_nids(void) ++{ ++ return ext_nids; ++} ++ ++void X509_REQ_set_extension_nids(int *nids) ++{ ++ ext_nids = nids; ++} ++ ++STACK_OF(X509_EXTENSION) *X509_REQ_get_extensions(X509_REQ *req) ++{ ++ X509_ATTRIBUTE *attr; ++ ASN1_TYPE *ext = NULL; ++ int idx, *pnid; ++ const unsigned char *p; ++ ++ if ((req == NULL) || !ext_nids) ++ return (NULL); ++ for (pnid = ext_nids; *pnid != NID_undef; pnid++) { ++ idx = X509_REQ_get_attr_by_NID(req, *pnid, -1); ++ if (idx == -1) ++ continue; ++ attr = X509_REQ_get_attr(req, idx); ++ ext = X509_ATTRIBUTE_get0_type(attr, 0); ++ break; ++ } ++ if (!ext || (ext->type != V_ASN1_SEQUENCE)) ++ return NULL; ++ p = ext->value.sequence->data; ++ return (STACK_OF(X509_EXTENSION) *) ++ ASN1_item_d2i(NULL, &p, ext->value.sequence->length, ++ ASN1_ITEM_rptr(X509_EXTENSIONS)); ++} ++ ++/* ++ * Add a STACK_OF extensions to a certificate request: allow alternative OIDs ++ * in case we want to create a non standard one. ++ */ ++ ++int X509_REQ_add_extensions_nid(X509_REQ *req, STACK_OF(X509_EXTENSION) *exts, ++ int nid) ++{ ++ int extlen; ++ int rv = 0; ++ unsigned char *ext = NULL; ++ /* Generate encoding of extensions */ ++ extlen = ASN1_item_i2d((ASN1_VALUE *)exts, &ext, ++ ASN1_ITEM_rptr(X509_EXTENSIONS)); ++ if (extlen <= 0) ++ return 0; ++ rv = X509_REQ_add1_attr_by_NID(req, nid, V_ASN1_SEQUENCE, ext, extlen); ++ OPENSSL_free(ext); ++ return rv; ++} ++ ++/* This is the normal usage: use the "official" OID */ ++int X509_REQ_add_extensions(X509_REQ *req, STACK_OF(X509_EXTENSION) *exts) ++{ ++ return X509_REQ_add_extensions_nid(req, exts, NID_ext_req); ++} ++ ++/* Request attribute functions */ ++ ++int X509_REQ_get_attr_count(const X509_REQ *req) ++{ ++ return X509at_get_attr_count(req->req_info.attributes); ++} ++ ++int X509_REQ_get_attr_by_NID(const X509_REQ *req, int nid, int lastpos) ++{ ++ return X509at_get_attr_by_NID(req->req_info.attributes, nid, lastpos); ++} ++ ++int X509_REQ_get_attr_by_OBJ(const X509_REQ *req, const ASN1_OBJECT *obj, ++ int lastpos) ++{ ++ return X509at_get_attr_by_OBJ(req->req_info.attributes, obj, lastpos); ++} ++ ++X509_ATTRIBUTE *X509_REQ_get_attr(const X509_REQ *req, int loc) ++{ ++ return X509at_get_attr(req->req_info.attributes, loc); ++} ++ ++X509_ATTRIBUTE *X509_REQ_delete_attr(X509_REQ *req, int loc) ++{ ++ return X509at_delete_attr(req->req_info.attributes, loc); ++} ++ ++int X509_REQ_add1_attr(X509_REQ *req, X509_ATTRIBUTE *attr) ++{ ++ if (X509at_add1_attr(&req->req_info.attributes, attr)) ++ return 1; ++ return 0; ++} ++ ++int X509_REQ_add1_attr_by_OBJ(X509_REQ *req, ++ const ASN1_OBJECT *obj, int type, ++ const unsigned char *bytes, int len) ++{ ++ if (X509at_add1_attr_by_OBJ(&req->req_info.attributes, obj, ++ type, bytes, len)) ++ return 1; ++ return 0; ++} ++ ++int X509_REQ_add1_attr_by_NID(X509_REQ *req, ++ int nid, int type, ++ const unsigned char *bytes, int len) ++{ ++ if (X509at_add1_attr_by_NID(&req->req_info.attributes, nid, ++ type, bytes, len)) ++ return 1; ++ return 0; ++} ++ ++int X509_REQ_add1_attr_by_txt(X509_REQ *req, ++ const char *attrname, int type, ++ const unsigned char *bytes, int len) ++{ ++ if (X509at_add1_attr_by_txt(&req->req_info.attributes, attrname, ++ type, bytes, len)) ++ return 1; ++ return 0; ++} ++ ++long X509_REQ_get_version(const X509_REQ *req) ++{ ++ return ASN1_INTEGER_get(req->req_info.version); ++} ++ ++X509_NAME *X509_REQ_get_subject_name(const X509_REQ *req) ++{ ++ return req->req_info.subject; ++} ++ ++void X509_REQ_get0_signature(const X509_REQ *req, const ASN1_BIT_STRING **psig, ++ const X509_ALGOR **palg) ++{ ++ if (psig != NULL) ++ *psig = req->signature; ++ if (palg != NULL) ++ *palg = &req->sig_alg; ++} ++ ++int X509_REQ_get_signature_nid(const X509_REQ *req) ++{ ++ return OBJ_obj2nid(req->sig_alg.algorithm); ++} ++ ++int i2d_re_X509_REQ_tbs(X509_REQ *req, unsigned char **pp) ++{ ++ req->req_info.enc.modified = 1; ++ return i2d_X509_REQ_INFO(&req->req_info, pp); ++} +diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/x509/x509_set.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/x509/x509_set.c +new file mode 100644 +index 0000000..c0ea418 +--- /dev/null ++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/x509/x509_set.c +@@ -0,0 +1,159 @@ ++/* ++ * Copyright 1995-2016 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 ++ * in the file LICENSE in the source distribution or at ++ * https://www.openssl.org/source/license.html ++ */ ++ ++#include ++#include "internal/cryptlib.h" ++#include ++#include ++#include ++#include ++#include "internal/x509_int.h" ++ ++int X509_set_version(X509 *x, long version) ++{ ++ if (x == NULL) ++ return (0); ++ if (version == 0) { ++ ASN1_INTEGER_free(x->cert_info.version); ++ x->cert_info.version = NULL; ++ return (1); ++ } ++ if (x->cert_info.version == NULL) { ++ if ((x->cert_info.version = ASN1_INTEGER_new()) == NULL) ++ return (0); ++ } ++ return (ASN1_INTEGER_set(x->cert_info.version, version)); ++} ++ ++int X509_set_serialNumber(X509 *x, ASN1_INTEGER *serial) ++{ ++ ASN1_INTEGER *in; ++ ++ if (x == NULL) ++ return 0; ++ in = &x->cert_info.serialNumber; ++ if (in != serial) ++ return ASN1_STRING_copy(in, serial); ++ return 1; ++} ++ ++int X509_set_issuer_name(X509 *x, X509_NAME *name) ++{ ++ if (x == NULL) ++ return (0); ++ return (X509_NAME_set(&x->cert_info.issuer, name)); ++} ++ ++int X509_set_subject_name(X509 *x, X509_NAME *name) ++{ ++ if (x == NULL) ++ return (0); ++ return (X509_NAME_set(&x->cert_info.subject, name)); ++} ++ ++int x509_set1_time(ASN1_TIME **ptm, const ASN1_TIME *tm) ++{ ++ ASN1_TIME *in; ++ in = *ptm; ++ if (in != tm) { ++ in = ASN1_STRING_dup(tm); ++ if (in != NULL) { ++ ASN1_TIME_free(*ptm); ++ *ptm = in; ++ } ++ } ++ return (in != NULL); ++} ++ ++int X509_set1_notBefore(X509 *x, const ASN1_TIME *tm) ++{ ++ if (x == NULL) ++ return 0; ++ return x509_set1_time(&x->cert_info.validity.notBefore, tm); ++} ++ ++int X509_set1_notAfter(X509 *x, const ASN1_TIME *tm) ++{ ++ if (x == NULL) ++ return 0; ++ return x509_set1_time(&x->cert_info.validity.notAfter, tm); ++} ++ ++int X509_set_pubkey(X509 *x, EVP_PKEY *pkey) ++{ ++ if (x == NULL) ++ return (0); ++ return (X509_PUBKEY_set(&(x->cert_info.key), pkey)); ++} ++ ++int X509_up_ref(X509 *x) ++{ ++ int i; ++ ++ if (CRYPTO_atomic_add(&x->references, 1, &i, x->lock) <= 0) ++ return 0; ++ ++ REF_PRINT_COUNT("X509", x); ++ REF_ASSERT_ISNT(i < 2); ++ return ((i > 1) ? 1 : 0); ++} ++ ++long X509_get_version(const X509 *x) ++{ ++ return ASN1_INTEGER_get(x->cert_info.version); ++} ++ ++const ASN1_TIME *X509_get0_notBefore(const X509 *x) ++{ ++ return x->cert_info.validity.notBefore; ++} ++ ++const ASN1_TIME *X509_get0_notAfter(const X509 *x) ++{ ++ return x->cert_info.validity.notAfter; ++} ++ ++ASN1_TIME *X509_getm_notBefore(const X509 *x) ++{ ++ return x->cert_info.validity.notBefore; ++} ++ ++ASN1_TIME *X509_getm_notAfter(const X509 *x) ++{ ++ return x->cert_info.validity.notAfter; ++} ++ ++int X509_get_signature_type(const X509 *x) ++{ ++ return EVP_PKEY_type(OBJ_obj2nid(x->sig_alg.algorithm)); ++} ++ ++X509_PUBKEY *X509_get_X509_PUBKEY(const X509 *x) ++{ ++ return x->cert_info.key; ++} ++ ++const STACK_OF(X509_EXTENSION) *X509_get0_extensions(const X509 *x) ++{ ++ return x->cert_info.extensions; ++} ++ ++void X509_get0_uids(const X509 *x, const ASN1_BIT_STRING **piuid, ++ const ASN1_BIT_STRING **psuid) ++{ ++ if (piuid != NULL) ++ *piuid = x->cert_info.issuerUID; ++ if (psuid != NULL) ++ *psuid = x->cert_info.subjectUID; ++} ++ ++const X509_ALGOR *X509_get0_tbs_sigalg(const X509 *x) ++{ ++ return &x->cert_info.signature; ++} +diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/x509/x509_trs.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/x509/x509_trs.c +new file mode 100644 +index 0000000..a9bb88d +--- /dev/null ++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/x509/x509_trs.c +@@ -0,0 +1,298 @@ ++/* ++ * Copyright 1999-2016 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 ++ * in the file LICENSE in the source distribution or at ++ * https://www.openssl.org/source/license.html ++ */ ++ ++#include ++#include "internal/cryptlib.h" ++#include ++#include "internal/x509_int.h" ++ ++static int tr_cmp(const X509_TRUST *const *a, const X509_TRUST *const *b); ++static void trtable_free(X509_TRUST *p); ++ ++static int trust_1oidany(X509_TRUST *trust, X509 *x, int flags); ++static int trust_1oid(X509_TRUST *trust, X509 *x, int flags); ++static int trust_compat(X509_TRUST *trust, X509 *x, int flags); ++ ++static int obj_trust(int id, X509 *x, int flags); ++static int (*default_trust) (int id, X509 *x, int flags) = obj_trust; ++ ++/* ++ * WARNING: the following table should be kept in order of trust and without ++ * any gaps so we can just subtract the minimum trust value to get an index ++ * into the table ++ */ ++ ++static X509_TRUST trstandard[] = { ++ {X509_TRUST_COMPAT, 0, trust_compat, "compatible", 0, NULL}, ++ {X509_TRUST_SSL_CLIENT, 0, trust_1oidany, "SSL Client", NID_client_auth, ++ NULL}, ++ {X509_TRUST_SSL_SERVER, 0, trust_1oidany, "SSL Server", NID_server_auth, ++ NULL}, ++ {X509_TRUST_EMAIL, 0, trust_1oidany, "S/MIME email", NID_email_protect, ++ NULL}, ++ {X509_TRUST_OBJECT_SIGN, 0, trust_1oidany, "Object Signer", NID_code_sign, ++ NULL}, ++ {X509_TRUST_OCSP_SIGN, 0, trust_1oid, "OCSP responder", NID_OCSP_sign, ++ NULL}, ++ {X509_TRUST_OCSP_REQUEST, 0, trust_1oid, "OCSP request", NID_ad_OCSP, ++ NULL}, ++ {X509_TRUST_TSA, 0, trust_1oidany, "TSA server", NID_time_stamp, NULL} ++}; ++ ++#define X509_TRUST_COUNT OSSL_NELEM(trstandard) ++ ++static STACK_OF(X509_TRUST) *trtable = NULL; ++ ++static int tr_cmp(const X509_TRUST *const *a, const X509_TRUST *const *b) ++{ ++ return (*a)->trust - (*b)->trust; ++} ++ ++int (*X509_TRUST_set_default(int (*trust) (int, X509 *, int))) (int, X509 *, ++ int) { ++ int (*oldtrust) (int, X509 *, int); ++ oldtrust = default_trust; ++ default_trust = trust; ++ return oldtrust; ++} ++ ++int X509_check_trust(X509 *x, int id, int flags) ++{ ++ X509_TRUST *pt; ++ int idx; ++ ++ /* We get this as a default value */ ++ if (id == X509_TRUST_DEFAULT) ++ return obj_trust(NID_anyExtendedKeyUsage, x, ++ flags | X509_TRUST_DO_SS_COMPAT); ++ idx = X509_TRUST_get_by_id(id); ++ if (idx == -1) ++ return default_trust(id, x, flags); ++ pt = X509_TRUST_get0(idx); ++ return pt->check_trust(pt, x, flags); ++} ++ ++int X509_TRUST_get_count(void) ++{ ++ if (!trtable) ++ return X509_TRUST_COUNT; ++ return sk_X509_TRUST_num(trtable) + X509_TRUST_COUNT; ++} ++ ++X509_TRUST *X509_TRUST_get0(int idx) ++{ ++ if (idx < 0) ++ return NULL; ++ if (idx < (int)X509_TRUST_COUNT) ++ return trstandard + idx; ++ return sk_X509_TRUST_value(trtable, idx - X509_TRUST_COUNT); ++} ++ ++int X509_TRUST_get_by_id(int id) ++{ ++ X509_TRUST tmp; ++ int idx; ++ if ((id >= X509_TRUST_MIN) && (id <= X509_TRUST_MAX)) ++ return id - X509_TRUST_MIN; ++ tmp.trust = id; ++ if (!trtable) ++ return -1; ++ idx = sk_X509_TRUST_find(trtable, &tmp); ++ if (idx == -1) ++ return -1; ++ return idx + X509_TRUST_COUNT; ++} ++ ++int X509_TRUST_set(int *t, int trust) ++{ ++ if (X509_TRUST_get_by_id(trust) == -1) { ++ X509err(X509_F_X509_TRUST_SET, X509_R_INVALID_TRUST); ++ return 0; ++ } ++ *t = trust; ++ return 1; ++} ++ ++int X509_TRUST_add(int id, int flags, int (*ck) (X509_TRUST *, X509 *, int), ++ const char *name, int arg1, void *arg2) ++{ ++ int idx; ++ X509_TRUST *trtmp; ++ /* ++ * This is set according to what we change: application can't set it ++ */ ++ flags &= ~X509_TRUST_DYNAMIC; ++ /* This will always be set for application modified trust entries */ ++ flags |= X509_TRUST_DYNAMIC_NAME; ++ /* Get existing entry if any */ ++ idx = X509_TRUST_get_by_id(id); ++ /* Need a new entry */ ++ if (idx == -1) { ++ if ((trtmp = OPENSSL_malloc(sizeof(*trtmp))) == NULL) { ++ X509err(X509_F_X509_TRUST_ADD, ERR_R_MALLOC_FAILURE); ++ return 0; ++ } ++ trtmp->flags = X509_TRUST_DYNAMIC; ++ } else ++ trtmp = X509_TRUST_get0(idx); ++ ++ /* OPENSSL_free existing name if dynamic */ ++ if (trtmp->flags & X509_TRUST_DYNAMIC_NAME) ++ OPENSSL_free(trtmp->name); ++ /* dup supplied name */ ++ if ((trtmp->name = OPENSSL_strdup(name)) == NULL) { ++ X509err(X509_F_X509_TRUST_ADD, ERR_R_MALLOC_FAILURE); ++ goto err; ++ } ++ /* Keep the dynamic flag of existing entry */ ++ trtmp->flags &= X509_TRUST_DYNAMIC; ++ /* Set all other flags */ ++ trtmp->flags |= flags; ++ ++ trtmp->trust = id; ++ trtmp->check_trust = ck; ++ trtmp->arg1 = arg1; ++ trtmp->arg2 = arg2; ++ ++ /* If its a new entry manage the dynamic table */ ++ if (idx == -1) { ++ if (trtable == NULL ++ && (trtable = sk_X509_TRUST_new(tr_cmp)) == NULL) { ++ X509err(X509_F_X509_TRUST_ADD, ERR_R_MALLOC_FAILURE); ++ goto err;; ++ } ++ if (!sk_X509_TRUST_push(trtable, trtmp)) { ++ X509err(X509_F_X509_TRUST_ADD, ERR_R_MALLOC_FAILURE); ++ goto err; ++ } ++ } ++ return 1; ++ err: ++ if (idx == -1) { ++ OPENSSL_free(trtmp->name); ++ OPENSSL_free(trtmp); ++ } ++ return 0; ++} ++ ++static void trtable_free(X509_TRUST *p) ++{ ++ if (!p) ++ return; ++ if (p->flags & X509_TRUST_DYNAMIC) { ++ if (p->flags & X509_TRUST_DYNAMIC_NAME) ++ OPENSSL_free(p->name); ++ OPENSSL_free(p); ++ } ++} ++ ++void X509_TRUST_cleanup(void) ++{ ++ sk_X509_TRUST_pop_free(trtable, trtable_free); ++ trtable = NULL; ++} ++ ++int X509_TRUST_get_flags(const X509_TRUST *xp) ++{ ++ return xp->flags; ++} ++ ++char *X509_TRUST_get0_name(const X509_TRUST *xp) ++{ ++ return xp->name; ++} ++ ++int X509_TRUST_get_trust(const X509_TRUST *xp) ++{ ++ return xp->trust; ++} ++ ++static int trust_1oidany(X509_TRUST *trust, X509 *x, int flags) ++{ ++ /* ++ * Declare the chain verified if the desired trust OID is not rejected in ++ * any auxiliary trust info for this certificate, and the OID is either ++ * expressly trusted, or else either "anyEKU" is trusted, or the ++ * certificate is self-signed. ++ */ ++ flags |= X509_TRUST_DO_SS_COMPAT | X509_TRUST_OK_ANY_EKU; ++ return obj_trust(trust->arg1, x, flags); ++} ++ ++static int trust_1oid(X509_TRUST *trust, X509 *x, int flags) ++{ ++ /* ++ * Declare the chain verified only if the desired trust OID is not ++ * rejected and is expressly trusted. Neither "anyEKU" nor "compat" ++ * trust in self-signed certificates apply. ++ */ ++ flags &= ~(X509_TRUST_DO_SS_COMPAT | X509_TRUST_OK_ANY_EKU); ++ return obj_trust(trust->arg1, x, flags); ++} ++ ++static int trust_compat(X509_TRUST *trust, X509 *x, int flags) ++{ ++ /* Call for side-effect of computing hash and caching extensions */ ++ X509_check_purpose(x, -1, 0); ++ if ((flags & X509_TRUST_NO_SS_COMPAT) == 0 && x->ex_flags & EXFLAG_SS) ++ return X509_TRUST_TRUSTED; ++ else ++ return X509_TRUST_UNTRUSTED; ++} ++ ++static int obj_trust(int id, X509 *x, int flags) ++{ ++ X509_CERT_AUX *ax = x->aux; ++ int i; ++ ++ if (ax && ax->reject) { ++ for (i = 0; i < sk_ASN1_OBJECT_num(ax->reject); i++) { ++ ASN1_OBJECT *obj = sk_ASN1_OBJECT_value(ax->reject, i); ++ int nid = OBJ_obj2nid(obj); ++ ++ if (nid == id || (nid == NID_anyExtendedKeyUsage && ++ (flags & X509_TRUST_OK_ANY_EKU))) ++ return X509_TRUST_REJECTED; ++ } ++ } ++ ++ if (ax && ax->trust) { ++ for (i = 0; i < sk_ASN1_OBJECT_num(ax->trust); i++) { ++ ASN1_OBJECT *obj = sk_ASN1_OBJECT_value(ax->trust, i); ++ int nid = OBJ_obj2nid(obj); ++ ++ if (nid == id || (nid == NID_anyExtendedKeyUsage && ++ (flags & X509_TRUST_OK_ANY_EKU))) ++ return X509_TRUST_TRUSTED; ++ } ++ /* ++ * Reject when explicit trust EKU are set and none match. ++ * ++ * Returning untrusted is enough for for full chains that end in ++ * self-signed roots, because when explicit trust is specified it ++ * suppresses the default blanket trust of self-signed objects. ++ * ++ * But for partial chains, this is not enough, because absent a similar ++ * trust-self-signed policy, non matching EKUs are indistinguishable ++ * from lack of EKU constraints. ++ * ++ * Therefore, failure to match any trusted purpose must trigger an ++ * explicit reject. ++ */ ++ return X509_TRUST_REJECTED; ++ } ++ ++ if ((flags & X509_TRUST_DO_SS_COMPAT) == 0) ++ return X509_TRUST_UNTRUSTED; ++ ++ /* ++ * Not rejected, and there is no list of accepted uses, try compat. ++ */ ++ return trust_compat(NULL, x, flags); ++} +diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/x509/x509_txt.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/x509/x509_txt.c +new file mode 100644 +index 0000000..66e5fcd +--- /dev/null ++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/x509/x509_txt.c +@@ -0,0 +1,177 @@ ++/* ++ * Copyright 1995-2016 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 ++ * in the file LICENSE in the source distribution or at ++ * https://www.openssl.org/source/license.html ++ */ ++ ++#include ++#include ++#include ++ ++#include "internal/cryptlib.h" ++#include ++#include ++#include ++#include ++#include ++#include ++ ++const char *X509_verify_cert_error_string(long n) ++{ ++ switch ((int)n) { ++ case X509_V_OK: ++ return ("ok"); ++ case X509_V_ERR_UNSPECIFIED: ++ return ("unspecified certificate verification error"); ++ case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT: ++ return ("unable to get issuer certificate"); ++ case X509_V_ERR_UNABLE_TO_GET_CRL: ++ return ("unable to get certificate CRL"); ++ case X509_V_ERR_UNABLE_TO_DECRYPT_CERT_SIGNATURE: ++ return ("unable to decrypt certificate's signature"); ++ case X509_V_ERR_UNABLE_TO_DECRYPT_CRL_SIGNATURE: ++ return ("unable to decrypt CRL's signature"); ++ case X509_V_ERR_UNABLE_TO_DECODE_ISSUER_PUBLIC_KEY: ++ return ("unable to decode issuer public key"); ++ case X509_V_ERR_CERT_SIGNATURE_FAILURE: ++ return ("certificate signature failure"); ++ case X509_V_ERR_CRL_SIGNATURE_FAILURE: ++ return ("CRL signature failure"); ++ case X509_V_ERR_CERT_NOT_YET_VALID: ++ return ("certificate is not yet valid"); ++ case X509_V_ERR_CERT_HAS_EXPIRED: ++ return ("certificate has expired"); ++ case X509_V_ERR_CRL_NOT_YET_VALID: ++ return ("CRL is not yet valid"); ++ case X509_V_ERR_CRL_HAS_EXPIRED: ++ return ("CRL has expired"); ++ case X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD: ++ return ("format error in certificate's notBefore field"); ++ case X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD: ++ return ("format error in certificate's notAfter field"); ++ case X509_V_ERR_ERROR_IN_CRL_LAST_UPDATE_FIELD: ++ return ("format error in CRL's lastUpdate field"); ++ case X509_V_ERR_ERROR_IN_CRL_NEXT_UPDATE_FIELD: ++ return ("format error in CRL's nextUpdate field"); ++ case X509_V_ERR_OUT_OF_MEM: ++ return ("out of memory"); ++ case X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT: ++ return ("self signed certificate"); ++ case X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN: ++ return ("self signed certificate in certificate chain"); ++ case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY: ++ return ("unable to get local issuer certificate"); ++ case X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE: ++ return ("unable to verify the first certificate"); ++ case X509_V_ERR_CERT_CHAIN_TOO_LONG: ++ return ("certificate chain too long"); ++ case X509_V_ERR_CERT_REVOKED: ++ return ("certificate revoked"); ++ case X509_V_ERR_INVALID_CA: ++ return ("invalid CA certificate"); ++ case X509_V_ERR_PATH_LENGTH_EXCEEDED: ++ return ("path length constraint exceeded"); ++ case X509_V_ERR_INVALID_PURPOSE: ++ return ("unsupported certificate purpose"); ++ case X509_V_ERR_CERT_UNTRUSTED: ++ return ("certificate not trusted"); ++ case X509_V_ERR_CERT_REJECTED: ++ return ("certificate rejected"); ++ case X509_V_ERR_SUBJECT_ISSUER_MISMATCH: ++ return ("subject issuer mismatch"); ++ case X509_V_ERR_AKID_SKID_MISMATCH: ++ return ("authority and subject key identifier mismatch"); ++ case X509_V_ERR_AKID_ISSUER_SERIAL_MISMATCH: ++ return ("authority and issuer serial number mismatch"); ++ case X509_V_ERR_KEYUSAGE_NO_CERTSIGN: ++ return ("key usage does not include certificate signing"); ++ case X509_V_ERR_UNABLE_TO_GET_CRL_ISSUER: ++ return ("unable to get CRL issuer certificate"); ++ case X509_V_ERR_UNHANDLED_CRITICAL_EXTENSION: ++ return ("unhandled critical extension"); ++ case X509_V_ERR_KEYUSAGE_NO_CRL_SIGN: ++ return ("key usage does not include CRL signing"); ++ case X509_V_ERR_UNHANDLED_CRITICAL_CRL_EXTENSION: ++ return ("unhandled critical CRL extension"); ++ case X509_V_ERR_INVALID_NON_CA: ++ return ("invalid non-CA certificate (has CA markings)"); ++ case X509_V_ERR_PROXY_PATH_LENGTH_EXCEEDED: ++ return ("proxy path length constraint exceeded"); ++ case X509_V_ERR_KEYUSAGE_NO_DIGITAL_SIGNATURE: ++ return ("key usage does not include digital signature"); ++ case X509_V_ERR_PROXY_CERTIFICATES_NOT_ALLOWED: ++ return ++ ("proxy certificates not allowed, please set the appropriate flag"); ++ case X509_V_ERR_INVALID_EXTENSION: ++ return ("invalid or inconsistent certificate extension"); ++ case X509_V_ERR_INVALID_POLICY_EXTENSION: ++ return ("invalid or inconsistent certificate policy extension"); ++ case X509_V_ERR_NO_EXPLICIT_POLICY: ++ return ("no explicit policy"); ++ case X509_V_ERR_DIFFERENT_CRL_SCOPE: ++ return ("Different CRL scope"); ++ case X509_V_ERR_UNSUPPORTED_EXTENSION_FEATURE: ++ return ("Unsupported extension feature"); ++ case X509_V_ERR_UNNESTED_RESOURCE: ++ return ("RFC 3779 resource not subset of parent's resources"); ++ case X509_V_ERR_PERMITTED_VIOLATION: ++ return ("permitted subtree violation"); ++ case X509_V_ERR_EXCLUDED_VIOLATION: ++ return ("excluded subtree violation"); ++ case X509_V_ERR_SUBTREE_MINMAX: ++ return ("name constraints minimum and maximum not supported"); ++ case X509_V_ERR_APPLICATION_VERIFICATION: ++ return ("application verification failure"); ++ case X509_V_ERR_UNSUPPORTED_CONSTRAINT_TYPE: ++ return ("unsupported name constraint type"); ++ case X509_V_ERR_UNSUPPORTED_CONSTRAINT_SYNTAX: ++ return ("unsupported or invalid name constraint syntax"); ++ case X509_V_ERR_UNSUPPORTED_NAME_SYNTAX: ++ return ("unsupported or invalid name syntax"); ++ case X509_V_ERR_CRL_PATH_VALIDATION_ERROR: ++ return ("CRL path validation error"); ++ case X509_V_ERR_PATH_LOOP: ++ return ("Path Loop"); ++ case X509_V_ERR_SUITE_B_INVALID_VERSION: ++ return ("Suite B: certificate version invalid"); ++ case X509_V_ERR_SUITE_B_INVALID_ALGORITHM: ++ return ("Suite B: invalid public key algorithm"); ++ case X509_V_ERR_SUITE_B_INVALID_CURVE: ++ return ("Suite B: invalid ECC curve"); ++ case X509_V_ERR_SUITE_B_INVALID_SIGNATURE_ALGORITHM: ++ return ("Suite B: invalid signature algorithm"); ++ case X509_V_ERR_SUITE_B_LOS_NOT_ALLOWED: ++ return ("Suite B: curve not allowed for this LOS"); ++ case X509_V_ERR_SUITE_B_CANNOT_SIGN_P_384_WITH_P_256: ++ return ("Suite B: cannot sign P-384 with P-256"); ++ case X509_V_ERR_HOSTNAME_MISMATCH: ++ return ("Hostname mismatch"); ++ case X509_V_ERR_EMAIL_MISMATCH: ++ return ("Email address mismatch"); ++ case X509_V_ERR_IP_ADDRESS_MISMATCH: ++ return ("IP address mismatch"); ++ case X509_V_ERR_DANE_NO_MATCH: ++ return ("No matching DANE TLSA records"); ++ case X509_V_ERR_EE_KEY_TOO_SMALL: ++ return ("EE certificate key too weak"); ++ case X509_V_ERR_CA_KEY_TOO_SMALL: ++ return ("CA certificate key too weak"); ++ case X509_V_ERR_CA_MD_TOO_WEAK: ++ return ("CA signature digest algorithm too weak"); ++ case X509_V_ERR_INVALID_CALL: ++ return ("Invalid certificate verification context"); ++ case X509_V_ERR_STORE_LOOKUP: ++ return ("Issuer certificate lookup error"); ++ case X509_V_ERR_NO_VALID_SCTS: ++ return ("Certificate Transparency required, but no valid SCTs found"); ++ case X509_V_ERR_PROXY_SUBJECT_NAME_VIOLATION: ++ return ("proxy subject name violation"); ++ ++ default: ++ /* Printing an error number into a static buffer is not thread-safe */ ++ return ("unknown certificate verification error"); ++ } ++} +diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/x509/x509_v3.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/x509/x509_v3.c +new file mode 100644 +index 0000000..ad126ef +--- /dev/null ++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/x509/x509_v3.c +@@ -0,0 +1,234 @@ ++/* ++ * Copyright 1995-2016 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 ++ * in the file LICENSE in the source distribution or at ++ * https://www.openssl.org/source/license.html ++ */ ++ ++#include ++#include ++#include "internal/cryptlib.h" ++#include ++#include ++#include ++#include ++#include ++#include "x509_lcl.h" ++ ++int X509v3_get_ext_count(const STACK_OF(X509_EXTENSION) *x) ++{ ++ if (x == NULL) ++ return (0); ++ return (sk_X509_EXTENSION_num(x)); ++} ++ ++int X509v3_get_ext_by_NID(const STACK_OF(X509_EXTENSION) *x, int nid, ++ int lastpos) ++{ ++ ASN1_OBJECT *obj; ++ ++ obj = OBJ_nid2obj(nid); ++ if (obj == NULL) ++ return (-2); ++ return (X509v3_get_ext_by_OBJ(x, obj, lastpos)); ++} ++ ++int X509v3_get_ext_by_OBJ(const STACK_OF(X509_EXTENSION) *sk, ++ const ASN1_OBJECT *obj, int lastpos) ++{ ++ int n; ++ X509_EXTENSION *ex; ++ ++ if (sk == NULL) ++ return (-1); ++ lastpos++; ++ if (lastpos < 0) ++ lastpos = 0; ++ n = sk_X509_EXTENSION_num(sk); ++ for (; lastpos < n; lastpos++) { ++ ex = sk_X509_EXTENSION_value(sk, lastpos); ++ if (OBJ_cmp(ex->object, obj) == 0) ++ return (lastpos); ++ } ++ return (-1); ++} ++ ++int X509v3_get_ext_by_critical(const STACK_OF(X509_EXTENSION) *sk, int crit, ++ int lastpos) ++{ ++ int n; ++ X509_EXTENSION *ex; ++ ++ if (sk == NULL) ++ return (-1); ++ lastpos++; ++ if (lastpos < 0) ++ lastpos = 0; ++ n = sk_X509_EXTENSION_num(sk); ++ for (; lastpos < n; lastpos++) { ++ ex = sk_X509_EXTENSION_value(sk, lastpos); ++ if (((ex->critical > 0) && crit) || ((ex->critical <= 0) && !crit)) ++ return (lastpos); ++ } ++ return (-1); ++} ++ ++X509_EXTENSION *X509v3_get_ext(const STACK_OF(X509_EXTENSION) *x, int loc) ++{ ++ if (x == NULL || sk_X509_EXTENSION_num(x) <= loc || loc < 0) ++ return NULL; ++ else ++ return sk_X509_EXTENSION_value(x, loc); ++} ++ ++X509_EXTENSION *X509v3_delete_ext(STACK_OF(X509_EXTENSION) *x, int loc) ++{ ++ X509_EXTENSION *ret; ++ ++ if (x == NULL || sk_X509_EXTENSION_num(x) <= loc || loc < 0) ++ return (NULL); ++ ret = sk_X509_EXTENSION_delete(x, loc); ++ return (ret); ++} ++ ++STACK_OF(X509_EXTENSION) *X509v3_add_ext(STACK_OF(X509_EXTENSION) **x, ++ X509_EXTENSION *ex, int loc) ++{ ++ X509_EXTENSION *new_ex = NULL; ++ int n; ++ STACK_OF(X509_EXTENSION) *sk = NULL; ++ ++ if (x == NULL) { ++ X509err(X509_F_X509V3_ADD_EXT, ERR_R_PASSED_NULL_PARAMETER); ++ goto err2; ++ } ++ ++ if (*x == NULL) { ++ if ((sk = sk_X509_EXTENSION_new_null()) == NULL) ++ goto err; ++ } else ++ sk = *x; ++ ++ n = sk_X509_EXTENSION_num(sk); ++ if (loc > n) ++ loc = n; ++ else if (loc < 0) ++ loc = n; ++ ++ if ((new_ex = X509_EXTENSION_dup(ex)) == NULL) ++ goto err2; ++ if (!sk_X509_EXTENSION_insert(sk, new_ex, loc)) ++ goto err; ++ if (*x == NULL) ++ *x = sk; ++ return (sk); ++ err: ++ X509err(X509_F_X509V3_ADD_EXT, ERR_R_MALLOC_FAILURE); ++ err2: ++ X509_EXTENSION_free(new_ex); ++ sk_X509_EXTENSION_free(sk); ++ return (NULL); ++} ++ ++X509_EXTENSION *X509_EXTENSION_create_by_NID(X509_EXTENSION **ex, int nid, ++ int crit, ++ ASN1_OCTET_STRING *data) ++{ ++ ASN1_OBJECT *obj; ++ X509_EXTENSION *ret; ++ ++ obj = OBJ_nid2obj(nid); ++ if (obj == NULL) { ++ X509err(X509_F_X509_EXTENSION_CREATE_BY_NID, X509_R_UNKNOWN_NID); ++ return (NULL); ++ } ++ ret = X509_EXTENSION_create_by_OBJ(ex, obj, crit, data); ++ if (ret == NULL) ++ ASN1_OBJECT_free(obj); ++ return (ret); ++} ++ ++X509_EXTENSION *X509_EXTENSION_create_by_OBJ(X509_EXTENSION **ex, ++ const ASN1_OBJECT *obj, int crit, ++ ASN1_OCTET_STRING *data) ++{ ++ X509_EXTENSION *ret; ++ ++ if ((ex == NULL) || (*ex == NULL)) { ++ if ((ret = X509_EXTENSION_new()) == NULL) { ++ X509err(X509_F_X509_EXTENSION_CREATE_BY_OBJ, ++ ERR_R_MALLOC_FAILURE); ++ return (NULL); ++ } ++ } else ++ ret = *ex; ++ ++ if (!X509_EXTENSION_set_object(ret, obj)) ++ goto err; ++ if (!X509_EXTENSION_set_critical(ret, crit)) ++ goto err; ++ if (!X509_EXTENSION_set_data(ret, data)) ++ goto err; ++ ++ if ((ex != NULL) && (*ex == NULL)) ++ *ex = ret; ++ return (ret); ++ err: ++ if ((ex == NULL) || (ret != *ex)) ++ X509_EXTENSION_free(ret); ++ return (NULL); ++} ++ ++int X509_EXTENSION_set_object(X509_EXTENSION *ex, const ASN1_OBJECT *obj) ++{ ++ if ((ex == NULL) || (obj == NULL)) ++ return (0); ++ ASN1_OBJECT_free(ex->object); ++ ex->object = OBJ_dup(obj); ++ return ex->object != NULL; ++} ++ ++int X509_EXTENSION_set_critical(X509_EXTENSION *ex, int crit) ++{ ++ if (ex == NULL) ++ return (0); ++ ex->critical = (crit) ? 0xFF : -1; ++ return (1); ++} ++ ++int X509_EXTENSION_set_data(X509_EXTENSION *ex, ASN1_OCTET_STRING *data) ++{ ++ int i; ++ ++ if (ex == NULL) ++ return (0); ++ i = ASN1_OCTET_STRING_set(&ex->value, data->data, data->length); ++ if (!i) ++ return (0); ++ return (1); ++} ++ ++ASN1_OBJECT *X509_EXTENSION_get_object(X509_EXTENSION *ex) ++{ ++ if (ex == NULL) ++ return (NULL); ++ return (ex->object); ++} ++ ++ASN1_OCTET_STRING *X509_EXTENSION_get_data(X509_EXTENSION *ex) ++{ ++ if (ex == NULL) ++ return (NULL); ++ return &ex->value; ++} ++ ++int X509_EXTENSION_get_critical(const X509_EXTENSION *ex) ++{ ++ if (ex == NULL) ++ return (0); ++ if (ex->critical > 0) ++ return 1; ++ return 0; ++} +diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/x509/x509_vfy.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/x509/x509_vfy.c +new file mode 100644 +index 0000000..ebc4424 +--- /dev/null ++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/x509/x509_vfy.c +@@ -0,0 +1,3275 @@ ++/* ++ * Copyright 1995-2016 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 ++ * in the file LICENSE in the source distribution or at ++ * https://www.openssl.org/source/license.html ++ */ ++ ++#include ++#include ++#include ++#include ++ ++#include "internal/cryptlib.h" ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include "x509_lcl.h" ++ ++/* CRL score values */ ++ ++/* No unhandled critical extensions */ ++ ++#define CRL_SCORE_NOCRITICAL 0x100 ++ ++/* certificate is within CRL scope */ ++ ++#define CRL_SCORE_SCOPE 0x080 ++ ++/* CRL times valid */ ++ ++#define CRL_SCORE_TIME 0x040 ++ ++/* Issuer name matches certificate */ ++ ++#define CRL_SCORE_ISSUER_NAME 0x020 ++ ++/* If this score or above CRL is probably valid */ ++ ++#define CRL_SCORE_VALID (CRL_SCORE_NOCRITICAL|CRL_SCORE_TIME|CRL_SCORE_SCOPE) ++ ++/* CRL issuer is certificate issuer */ ++ ++#define CRL_SCORE_ISSUER_CERT 0x018 ++ ++/* CRL issuer is on certificate path */ ++ ++#define CRL_SCORE_SAME_PATH 0x008 ++ ++/* CRL issuer matches CRL AKID */ ++ ++#define CRL_SCORE_AKID 0x004 ++ ++/* Have a delta CRL with valid times */ ++ ++#define CRL_SCORE_TIME_DELTA 0x002 ++ ++static int build_chain(X509_STORE_CTX *ctx); ++static int verify_chain(X509_STORE_CTX *ctx); ++static int dane_verify(X509_STORE_CTX *ctx); ++static int null_callback(int ok, X509_STORE_CTX *e); ++static int check_issued(X509_STORE_CTX *ctx, X509 *x, X509 *issuer); ++static X509 *find_issuer(X509_STORE_CTX *ctx, STACK_OF(X509) *sk, X509 *x); ++static int check_chain_extensions(X509_STORE_CTX *ctx); ++static int check_name_constraints(X509_STORE_CTX *ctx); ++static int check_id(X509_STORE_CTX *ctx); ++static int check_trust(X509_STORE_CTX *ctx, int num_untrusted); ++static int check_revocation(X509_STORE_CTX *ctx); ++static int check_cert(X509_STORE_CTX *ctx); ++static int check_policy(X509_STORE_CTX *ctx); ++static int get_issuer_sk(X509 **issuer, X509_STORE_CTX *ctx, X509 *x); ++static int check_dane_issuer(X509_STORE_CTX *ctx, int depth); ++static int check_key_level(X509_STORE_CTX *ctx, X509 *cert); ++static int check_sig_level(X509_STORE_CTX *ctx, X509 *cert); ++ ++static int get_crl_score(X509_STORE_CTX *ctx, X509 **pissuer, ++ unsigned int *preasons, X509_CRL *crl, X509 *x); ++static int get_crl_delta(X509_STORE_CTX *ctx, ++ X509_CRL **pcrl, X509_CRL **pdcrl, X509 *x); ++static void get_delta_sk(X509_STORE_CTX *ctx, X509_CRL **dcrl, ++ int *pcrl_score, X509_CRL *base, ++ STACK_OF(X509_CRL) *crls); ++static void crl_akid_check(X509_STORE_CTX *ctx, X509_CRL *crl, X509 **pissuer, ++ int *pcrl_score); ++static int crl_crldp_check(X509 *x, X509_CRL *crl, int crl_score, ++ unsigned int *preasons); ++static int check_crl_path(X509_STORE_CTX *ctx, X509 *x); ++static int check_crl_chain(X509_STORE_CTX *ctx, ++ STACK_OF(X509) *cert_path, ++ STACK_OF(X509) *crl_path); ++ ++static int internal_verify(X509_STORE_CTX *ctx); ++ ++static int null_callback(int ok, X509_STORE_CTX *e) ++{ ++ return ok; ++} ++ ++/* Return 1 is a certificate is self signed */ ++static int cert_self_signed(X509 *x) ++{ ++ /* ++ * FIXME: x509v3_cache_extensions() needs to detect more failures and not ++ * set EXFLAG_SET when that happens. Especially, if the failures are ++ * parse errors, rather than memory pressure! ++ */ ++ X509_check_purpose(x, -1, 0); ++ if (x->ex_flags & EXFLAG_SS) ++ return 1; ++ else ++ return 0; ++} ++ ++/* Given a certificate try and find an exact match in the store */ ++ ++static X509 *lookup_cert_match(X509_STORE_CTX *ctx, X509 *x) ++{ ++ STACK_OF(X509) *certs; ++ X509 *xtmp = NULL; ++ int i; ++ /* Lookup all certs with matching subject name */ ++ certs = ctx->lookup_certs(ctx, X509_get_subject_name(x)); ++ if (certs == NULL) ++ return NULL; ++ /* Look for exact match */ ++ for (i = 0; i < sk_X509_num(certs); i++) { ++ xtmp = sk_X509_value(certs, i); ++ if (!X509_cmp(xtmp, x)) ++ break; ++ } ++ if (i < sk_X509_num(certs)) ++ X509_up_ref(xtmp); ++ else ++ xtmp = NULL; ++ sk_X509_pop_free(certs, X509_free); ++ return xtmp; ++} ++ ++/*- ++ * Inform the verify callback of an error. ++ * If B is not NULL it is the error cert, otherwise use the chain cert at ++ * B. ++ * If B is not X509_V_OK, that's the error value, otherwise leave ++ * unchanged (presumably set by the caller). ++ * ++ * Returns 0 to abort verification with an error, non-zero to continue. ++ */ ++static int verify_cb_cert(X509_STORE_CTX *ctx, X509 *x, int depth, int err) ++{ ++ ctx->error_depth = depth; ++ ctx->current_cert = (x != NULL) ? x : sk_X509_value(ctx->chain, depth); ++ if (err != X509_V_OK) ++ ctx->error = err; ++ return ctx->verify_cb(0, ctx); ++} ++ ++/*- ++ * Inform the verify callback of an error, CRL-specific variant. Here, the ++ * error depth and certificate are already set, we just specify the error ++ * number. ++ * ++ * Returns 0 to abort verification with an error, non-zero to continue. ++ */ ++static int verify_cb_crl(X509_STORE_CTX *ctx, int err) ++{ ++ ctx->error = err; ++ return ctx->verify_cb(0, ctx); ++} ++ ++static int check_auth_level(X509_STORE_CTX *ctx) ++{ ++ int i; ++ int num = sk_X509_num(ctx->chain); ++ ++ if (ctx->param->auth_level <= 0) ++ return 1; ++ ++ for (i = 0; i < num; ++i) { ++ X509 *cert = sk_X509_value(ctx->chain, i); ++ ++ /* ++ * We've already checked the security of the leaf key, so here we only ++ * check the security of issuer keys. ++ */ ++ if (i > 0 && !check_key_level(ctx, cert) && ++ verify_cb_cert(ctx, cert, i, X509_V_ERR_CA_KEY_TOO_SMALL) == 0) ++ return 0; ++ /* ++ * We also check the signature algorithm security of all certificates ++ * except those of the trust anchor at index num-1. ++ */ ++ if (i < num - 1 && !check_sig_level(ctx, cert) && ++ verify_cb_cert(ctx, cert, i, X509_V_ERR_CA_MD_TOO_WEAK) == 0) ++ return 0; ++ } ++ return 1; ++} ++ ++static int verify_chain(X509_STORE_CTX *ctx) ++{ ++ int err; ++ int ok; ++ ++ /* ++ * Before either returning with an error, or continuing with CRL checks, ++ * instantiate chain public key parameters. ++ */ ++ if ((ok = build_chain(ctx)) == 0 || ++ (ok = check_chain_extensions(ctx)) == 0 || ++ (ok = check_auth_level(ctx)) == 0 || ++ (ok = check_name_constraints(ctx)) == 0 || ++ (ok = check_id(ctx)) == 0 || 1) ++ X509_get_pubkey_parameters(NULL, ctx->chain); ++ if (ok == 0 || (ok = ctx->check_revocation(ctx)) == 0) ++ return ok; ++ ++ err = X509_chain_check_suiteb(&ctx->error_depth, NULL, ctx->chain, ++ ctx->param->flags); ++ if (err != X509_V_OK) { ++ if ((ok = verify_cb_cert(ctx, NULL, ctx->error_depth, err)) == 0) ++ return ok; ++ } ++ ++ /* Verify chain signatures and expiration times */ ++ ok = (ctx->verify != NULL) ? ctx->verify(ctx) : internal_verify(ctx); ++ if (!ok) ++ return ok; ++ ++#ifndef OPENSSL_NO_RFC3779 ++ /* RFC 3779 path validation, now that CRL check has been done */ ++ if ((ok = X509v3_asid_validate_path(ctx)) == 0) ++ return ok; ++ if ((ok = X509v3_addr_validate_path(ctx)) == 0) ++ return ok; ++#endif ++ ++ /* If we get this far evaluate policies */ ++ if (ctx->param->flags & X509_V_FLAG_POLICY_CHECK) ++ ok = ctx->check_policy(ctx); ++ return ok; ++} ++ ++int X509_verify_cert(X509_STORE_CTX *ctx) ++{ ++ SSL_DANE *dane = ctx->dane; ++ int ret; ++ ++ if (ctx->cert == NULL) { ++ X509err(X509_F_X509_VERIFY_CERT, X509_R_NO_CERT_SET_FOR_US_TO_VERIFY); ++ ctx->error = X509_V_ERR_INVALID_CALL; ++ return -1; ++ } ++ ++ if (ctx->chain != NULL) { ++ /* ++ * This X509_STORE_CTX has already been used to verify a cert. We ++ * cannot do another one. ++ */ ++ X509err(X509_F_X509_VERIFY_CERT, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED); ++ ctx->error = X509_V_ERR_INVALID_CALL; ++ return -1; ++ } ++ ++ /* ++ * first we make sure the chain we are going to build is present and that ++ * the first entry is in place ++ */ ++ if (((ctx->chain = sk_X509_new_null()) == NULL) || ++ (!sk_X509_push(ctx->chain, ctx->cert))) { ++ X509err(X509_F_X509_VERIFY_CERT, ERR_R_MALLOC_FAILURE); ++ ctx->error = X509_V_ERR_OUT_OF_MEM; ++ return -1; ++ } ++ X509_up_ref(ctx->cert); ++ ctx->num_untrusted = 1; ++ ++ /* If the peer's public key is too weak, we can stop early. */ ++ if (!check_key_level(ctx, ctx->cert) && ++ !verify_cb_cert(ctx, ctx->cert, 0, X509_V_ERR_EE_KEY_TOO_SMALL)) ++ return 0; ++ ++ if (DANETLS_ENABLED(dane)) ++ ret = dane_verify(ctx); ++ else ++ ret = verify_chain(ctx); ++ ++ /* ++ * Safety-net. If we are returning an error, we must also set ctx->error, ++ * so that the chain is not considered verified should the error be ignored ++ * (e.g. TLS with SSL_VERIFY_NONE). ++ */ ++ if (ret <= 0 && ctx->error == X509_V_OK) ++ ctx->error = X509_V_ERR_UNSPECIFIED; ++ return ret; ++} ++ ++/* ++ * Given a STACK_OF(X509) find the issuer of cert (if any) ++ */ ++static X509 *find_issuer(X509_STORE_CTX *ctx, STACK_OF(X509) *sk, X509 *x) ++{ ++ int i; ++ X509 *issuer, *rv = NULL; ++ ++ for (i = 0; i < sk_X509_num(sk); i++) { ++ issuer = sk_X509_value(sk, i); ++ if (ctx->check_issued(ctx, x, issuer)) { ++ rv = issuer; ++ if (x509_check_cert_time(ctx, rv, -1)) ++ break; ++ } ++ } ++ return rv; ++} ++ ++/* Given a possible certificate and issuer check them */ ++ ++static int check_issued(X509_STORE_CTX *ctx, X509 *x, X509 *issuer) ++{ ++ int ret; ++ if (x == issuer) ++ return cert_self_signed(x); ++ ret = X509_check_issued(issuer, x); ++ if (ret == X509_V_OK) { ++ int i; ++ X509 *ch; ++ /* Special case: single self signed certificate */ ++ if (cert_self_signed(x) && sk_X509_num(ctx->chain) == 1) ++ return 1; ++ for (i = 0; i < sk_X509_num(ctx->chain); i++) { ++ ch = sk_X509_value(ctx->chain, i); ++ if (ch == issuer || !X509_cmp(ch, issuer)) { ++ ret = X509_V_ERR_PATH_LOOP; ++ break; ++ } ++ } ++ } ++ ++ return (ret == X509_V_OK); ++} ++ ++/* Alternative lookup method: look from a STACK stored in other_ctx */ ++ ++static int get_issuer_sk(X509 **issuer, X509_STORE_CTX *ctx, X509 *x) ++{ ++ *issuer = find_issuer(ctx, ctx->other_ctx, x); ++ if (*issuer) { ++ X509_up_ref(*issuer); ++ return 1; ++ } else ++ return 0; ++} ++ ++static STACK_OF(X509) *lookup_certs_sk(X509_STORE_CTX *ctx, X509_NAME *nm) ++{ ++ STACK_OF(X509) *sk = NULL; ++ X509 *x; ++ int i; ++ for (i = 0; i < sk_X509_num(ctx->other_ctx); i++) { ++ x = sk_X509_value(ctx->other_ctx, i); ++ if (X509_NAME_cmp(nm, X509_get_subject_name(x)) == 0) { ++ if (sk == NULL) ++ sk = sk_X509_new_null(); ++ if (sk == NULL || sk_X509_push(sk, x) == 0) { ++ sk_X509_pop_free(sk, X509_free); ++ return NULL; ++ } ++ X509_up_ref(x); ++ } ++ } ++ return sk; ++} ++ ++/* ++ * Check EE or CA certificate purpose. For trusted certificates explicit local ++ * auxiliary trust can be used to override EKU-restrictions. ++ */ ++static int check_purpose(X509_STORE_CTX *ctx, X509 *x, int purpose, int depth, ++ int must_be_ca) ++{ ++ int tr_ok = X509_TRUST_UNTRUSTED; ++ ++ /* ++ * For trusted certificates we want to see whether any auxiliary trust ++ * settings trump the purpose constraints. ++ * ++ * This is complicated by the fact that the trust ordinals in ++ * ctx->param->trust are entirely independent of the purpose ordinals in ++ * ctx->param->purpose! ++ * ++ * What connects them is their mutual initialization via calls from ++ * X509_STORE_CTX_set_default() into X509_VERIFY_PARAM_lookup() which sets ++ * related values of both param->trust and param->purpose. It is however ++ * typically possible to infer associated trust values from a purpose value ++ * via the X509_PURPOSE API. ++ * ++ * Therefore, we can only check for trust overrides when the purpose we're ++ * checking is the same as ctx->param->purpose and ctx->param->trust is ++ * also set. ++ */ ++ if (depth >= ctx->num_untrusted && purpose == ctx->param->purpose) ++ tr_ok = X509_check_trust(x, ctx->param->trust, X509_TRUST_NO_SS_COMPAT); ++ ++ switch (tr_ok) { ++ case X509_TRUST_TRUSTED: ++ return 1; ++ case X509_TRUST_REJECTED: ++ break; ++ default: ++ switch (X509_check_purpose(x, purpose, must_be_ca > 0)) { ++ case 1: ++ return 1; ++ case 0: ++ break; ++ default: ++ if ((ctx->param->flags & X509_V_FLAG_X509_STRICT) == 0) ++ return 1; ++ } ++ break; ++ } ++ ++ return verify_cb_cert(ctx, x, depth, X509_V_ERR_INVALID_PURPOSE); ++} ++ ++/* ++ * Check a certificate chains extensions for consistency with the supplied ++ * purpose ++ */ ++ ++static int check_chain_extensions(X509_STORE_CTX *ctx) ++{ ++ int i, must_be_ca, plen = 0; ++ X509 *x; ++ int proxy_path_length = 0; ++ int purpose; ++ int allow_proxy_certs; ++ int num = sk_X509_num(ctx->chain); ++ ++ /*- ++ * must_be_ca can have 1 of 3 values: ++ * -1: we accept both CA and non-CA certificates, to allow direct ++ * use of self-signed certificates (which are marked as CA). ++ * 0: we only accept non-CA certificates. This is currently not ++ * used, but the possibility is present for future extensions. ++ * 1: we only accept CA certificates. This is currently used for ++ * all certificates in the chain except the leaf certificate. ++ */ ++ must_be_ca = -1; ++ ++ /* CRL path validation */ ++ if (ctx->parent) { ++ allow_proxy_certs = 0; ++ purpose = X509_PURPOSE_CRL_SIGN; ++ } else { ++ allow_proxy_certs = ++ ! !(ctx->param->flags & X509_V_FLAG_ALLOW_PROXY_CERTS); ++ purpose = ctx->param->purpose; ++ } ++ ++ for (i = 0; i < num; i++) { ++ int ret; ++ x = sk_X509_value(ctx->chain, i); ++ if (!(ctx->param->flags & X509_V_FLAG_IGNORE_CRITICAL) ++ && (x->ex_flags & EXFLAG_CRITICAL)) { ++ if (!verify_cb_cert(ctx, x, i, ++ X509_V_ERR_UNHANDLED_CRITICAL_EXTENSION)) ++ return 0; ++ } ++ if (!allow_proxy_certs && (x->ex_flags & EXFLAG_PROXY)) { ++ if (!verify_cb_cert(ctx, x, i, ++ X509_V_ERR_PROXY_CERTIFICATES_NOT_ALLOWED)) ++ return 0; ++ } ++ ret = X509_check_ca(x); ++ switch (must_be_ca) { ++ case -1: ++ if ((ctx->param->flags & X509_V_FLAG_X509_STRICT) ++ && (ret != 1) && (ret != 0)) { ++ ret = 0; ++ ctx->error = X509_V_ERR_INVALID_CA; ++ } else ++ ret = 1; ++ break; ++ case 0: ++ if (ret != 0) { ++ ret = 0; ++ ctx->error = X509_V_ERR_INVALID_NON_CA; ++ } else ++ ret = 1; ++ break; ++ default: ++ /* X509_V_FLAG_X509_STRICT is implicit for intermediate CAs */ ++ if ((ret == 0) ++ || ((i + 1 < num || ctx->param->flags & X509_V_FLAG_X509_STRICT) ++ && (ret != 1))) { ++ ret = 0; ++ ctx->error = X509_V_ERR_INVALID_CA; ++ } else ++ ret = 1; ++ break; ++ } ++ if (ret == 0 && !verify_cb_cert(ctx, x, i, X509_V_OK)) ++ return 0; ++ /* check_purpose() makes the callback as needed */ ++ if (purpose > 0 && !check_purpose(ctx, x, purpose, i, must_be_ca)) ++ return 0; ++ /* Check pathlen if not self issued */ ++ if ((i > 1) && !(x->ex_flags & EXFLAG_SI) ++ && (x->ex_pathlen != -1) ++ && (plen > (x->ex_pathlen + proxy_path_length + 1))) { ++ if (!verify_cb_cert(ctx, x, i, X509_V_ERR_PATH_LENGTH_EXCEEDED)) ++ return 0; ++ } ++ /* Increment path length if not self issued */ ++ if (!(x->ex_flags & EXFLAG_SI)) ++ plen++; ++ /* ++ * If this certificate is a proxy certificate, the next certificate ++ * must be another proxy certificate or a EE certificate. If not, ++ * the next certificate must be a CA certificate. ++ */ ++ if (x->ex_flags & EXFLAG_PROXY) { ++ /* ++ * RFC3820, 4.1.3 (b)(1) stipulates that if pCPathLengthConstraint ++ * is less than max_path_length, the former should be copied to ++ * the latter, and 4.1.4 (a) stipulates that max_path_length ++ * should be verified to be larger than zero and decrement it. ++ * ++ * Because we're checking the certs in the reverse order, we start ++ * with verifying that proxy_path_length isn't larger than pcPLC, ++ * and copy the latter to the former if it is, and finally, ++ * increment proxy_path_length. ++ */ ++ if (x->ex_pcpathlen != -1) { ++ if (proxy_path_length > x->ex_pcpathlen) { ++ if (!verify_cb_cert(ctx, x, i, ++ X509_V_ERR_PROXY_PATH_LENGTH_EXCEEDED)) ++ return 0; ++ } ++ proxy_path_length = x->ex_pcpathlen; ++ } ++ proxy_path_length++; ++ must_be_ca = 0; ++ } else ++ must_be_ca = 1; ++ } ++ return 1; ++} ++ ++static int check_name_constraints(X509_STORE_CTX *ctx) ++{ ++ int i; ++ ++ /* Check name constraints for all certificates */ ++ for (i = sk_X509_num(ctx->chain) - 1; i >= 0; i--) { ++ X509 *x = sk_X509_value(ctx->chain, i); ++ int j; ++ ++ /* Ignore self issued certs unless last in chain */ ++ if (i && (x->ex_flags & EXFLAG_SI)) ++ continue; ++ ++ /* ++ * Proxy certificates policy has an extra constraint, where the ++ * certificate subject MUST be the issuer with a single CN entry ++ * added. ++ * (RFC 3820: 3.4, 4.1.3 (a)(4)) ++ */ ++ if (x->ex_flags & EXFLAG_PROXY) { ++ X509_NAME *tmpsubject = X509_get_subject_name(x); ++ X509_NAME *tmpissuer = X509_get_issuer_name(x); ++ X509_NAME_ENTRY *tmpentry = NULL; ++ int last_object_nid = 0; ++ int err = X509_V_OK; ++ int last_object_loc = X509_NAME_entry_count(tmpsubject) - 1; ++ ++ /* Check that there are at least two RDNs */ ++ if (last_object_loc < 1) { ++ err = X509_V_ERR_PROXY_SUBJECT_NAME_VIOLATION; ++ goto proxy_name_done; ++ } ++ ++ /* ++ * Check that there is exactly one more RDN in subject as ++ * there is in issuer. ++ */ ++ if (X509_NAME_entry_count(tmpsubject) ++ != X509_NAME_entry_count(tmpissuer) + 1) { ++ err = X509_V_ERR_PROXY_SUBJECT_NAME_VIOLATION; ++ goto proxy_name_done; ++ } ++ ++ /* ++ * Check that the last subject component isn't part of a ++ * multivalued RDN ++ */ ++ if (X509_NAME_ENTRY_set(X509_NAME_get_entry(tmpsubject, ++ last_object_loc)) ++ == X509_NAME_ENTRY_set(X509_NAME_get_entry(tmpsubject, ++ last_object_loc - 1))) { ++ err = X509_V_ERR_PROXY_SUBJECT_NAME_VIOLATION; ++ goto proxy_name_done; ++ } ++ ++ /* ++ * Check that the last subject RDN is a commonName, and that ++ * all the previous RDNs match the issuer exactly ++ */ ++ tmpsubject = X509_NAME_dup(tmpsubject); ++ if (tmpsubject == NULL) { ++ X509err(X509_F_CHECK_NAME_CONSTRAINTS, ERR_R_MALLOC_FAILURE); ++ ctx->error = X509_V_ERR_OUT_OF_MEM; ++ return 0; ++ } ++ ++ tmpentry = ++ X509_NAME_delete_entry(tmpsubject, last_object_loc); ++ last_object_nid = ++ OBJ_obj2nid(X509_NAME_ENTRY_get_object(tmpentry)); ++ ++ if (last_object_nid != NID_commonName ++ || X509_NAME_cmp(tmpsubject, tmpissuer) != 0) { ++ err = X509_V_ERR_PROXY_SUBJECT_NAME_VIOLATION; ++ } ++ ++ X509_NAME_ENTRY_free(tmpentry); ++ X509_NAME_free(tmpsubject); ++ ++ proxy_name_done: ++ if (err != X509_V_OK ++ && !verify_cb_cert(ctx, x, i, err)) ++ return 0; ++ } ++ ++ /* ++ * Check against constraints for all certificates higher in chain ++ * including trust anchor. Trust anchor not strictly speaking needed ++ * but if it includes constraints it is to be assumed it expects them ++ * to be obeyed. ++ */ ++ for (j = sk_X509_num(ctx->chain) - 1; j > i; j--) { ++ NAME_CONSTRAINTS *nc = sk_X509_value(ctx->chain, j)->nc; ++ ++ if (nc) { ++ int rv = NAME_CONSTRAINTS_check(x, nc); ++ ++ /* If EE certificate check commonName too */ ++ if (rv == X509_V_OK && i == 0) ++ rv = NAME_CONSTRAINTS_check_CN(x, nc); ++ ++ switch (rv) { ++ case X509_V_OK: ++ break; ++ case X509_V_ERR_OUT_OF_MEM: ++ return 0; ++ default: ++ if (!verify_cb_cert(ctx, x, i, rv)) ++ return 0; ++ break; ++ } ++ } ++ } ++ } ++ return 1; ++} ++ ++static int check_id_error(X509_STORE_CTX *ctx, int errcode) ++{ ++ return verify_cb_cert(ctx, ctx->cert, 0, errcode); ++} ++ ++static int check_hosts(X509 *x, X509_VERIFY_PARAM *vpm) ++{ ++ int i; ++ int n = sk_OPENSSL_STRING_num(vpm->hosts); ++ char *name; ++ ++ if (vpm->peername != NULL) { ++ OPENSSL_free(vpm->peername); ++ vpm->peername = NULL; ++ } ++ for (i = 0; i < n; ++i) { ++ name = sk_OPENSSL_STRING_value(vpm->hosts, i); ++ if (X509_check_host(x, name, 0, vpm->hostflags, &vpm->peername) > 0) ++ return 1; ++ } ++ return n == 0; ++} ++ ++static int check_id(X509_STORE_CTX *ctx) ++{ ++ X509_VERIFY_PARAM *vpm = ctx->param; ++ X509 *x = ctx->cert; ++ if (vpm->hosts && check_hosts(x, vpm) <= 0) { ++ if (!check_id_error(ctx, X509_V_ERR_HOSTNAME_MISMATCH)) ++ return 0; ++ } ++ if (vpm->email && X509_check_email(x, vpm->email, vpm->emaillen, 0) <= 0) { ++ if (!check_id_error(ctx, X509_V_ERR_EMAIL_MISMATCH)) ++ return 0; ++ } ++ if (vpm->ip && X509_check_ip(x, vpm->ip, vpm->iplen, 0) <= 0) { ++ if (!check_id_error(ctx, X509_V_ERR_IP_ADDRESS_MISMATCH)) ++ return 0; ++ } ++ return 1; ++} ++ ++static int check_trust(X509_STORE_CTX *ctx, int num_untrusted) ++{ ++ int i; ++ X509 *x = NULL; ++ X509 *mx; ++ SSL_DANE *dane = ctx->dane; ++ int num = sk_X509_num(ctx->chain); ++ int trust; ++ ++ /* ++ * Check for a DANE issuer at depth 1 or greater, if it is a DANE-TA(2) ++ * match, we're done, otherwise we'll merely record the match depth. ++ */ ++ if (DANETLS_HAS_TA(dane) && num_untrusted > 0 && num_untrusted < num) { ++ switch (trust = check_dane_issuer(ctx, num_untrusted)) { ++ case X509_TRUST_TRUSTED: ++ case X509_TRUST_REJECTED: ++ return trust; ++ } ++ } ++ ++ /* ++ * Check trusted certificates in chain at depth num_untrusted and up. ++ * Note, that depths 0..num_untrusted-1 may also contain trusted ++ * certificates, but the caller is expected to have already checked those, ++ * and wants to incrementally check just any added since. ++ */ ++ for (i = num_untrusted; i < num; i++) { ++ x = sk_X509_value(ctx->chain, i); ++ trust = X509_check_trust(x, ctx->param->trust, 0); ++ /* If explicitly trusted return trusted */ ++ if (trust == X509_TRUST_TRUSTED) ++ goto trusted; ++ if (trust == X509_TRUST_REJECTED) ++ goto rejected; ++ } ++ ++ /* ++ * If we are looking at a trusted certificate, and accept partial chains, ++ * the chain is PKIX trusted. ++ */ ++ if (num_untrusted < num) { ++ if (ctx->param->flags & X509_V_FLAG_PARTIAL_CHAIN) ++ goto trusted; ++ return X509_TRUST_UNTRUSTED; ++ } ++ ++ if (num_untrusted == num && ctx->param->flags & X509_V_FLAG_PARTIAL_CHAIN) { ++ /* ++ * Last-resort call with no new trusted certificates, check the leaf ++ * for a direct trust store match. ++ */ ++ i = 0; ++ x = sk_X509_value(ctx->chain, i); ++ mx = lookup_cert_match(ctx, x); ++ if (!mx) ++ return X509_TRUST_UNTRUSTED; ++ ++ /* ++ * Check explicit auxiliary trust/reject settings. If none are set, ++ * we'll accept X509_TRUST_UNTRUSTED when not self-signed. ++ */ ++ trust = X509_check_trust(mx, ctx->param->trust, 0); ++ if (trust == X509_TRUST_REJECTED) { ++ X509_free(mx); ++ goto rejected; ++ } ++ ++ /* Replace leaf with trusted match */ ++ (void) sk_X509_set(ctx->chain, 0, mx); ++ X509_free(x); ++ ctx->num_untrusted = 0; ++ goto trusted; ++ } ++ ++ /* ++ * If no trusted certs in chain at all return untrusted and allow ++ * standard (no issuer cert) etc errors to be indicated. ++ */ ++ return X509_TRUST_UNTRUSTED; ++ ++ rejected: ++ if (!verify_cb_cert(ctx, x, i, X509_V_ERR_CERT_REJECTED)) ++ return X509_TRUST_REJECTED; ++ return X509_TRUST_UNTRUSTED; ++ ++ trusted: ++ if (!DANETLS_ENABLED(dane)) ++ return X509_TRUST_TRUSTED; ++ if (dane->pdpth < 0) ++ dane->pdpth = num_untrusted; ++ /* With DANE, PKIX alone is not trusted until we have both */ ++ if (dane->mdpth >= 0) ++ return X509_TRUST_TRUSTED; ++ return X509_TRUST_UNTRUSTED; ++} ++ ++static int check_revocation(X509_STORE_CTX *ctx) ++{ ++ int i = 0, last = 0, ok = 0; ++ if (!(ctx->param->flags & X509_V_FLAG_CRL_CHECK)) ++ return 1; ++ if (ctx->param->flags & X509_V_FLAG_CRL_CHECK_ALL) ++ last = sk_X509_num(ctx->chain) - 1; ++ else { ++ /* If checking CRL paths this isn't the EE certificate */ ++ if (ctx->parent) ++ return 1; ++ last = 0; ++ } ++ for (i = 0; i <= last; i++) { ++ ctx->error_depth = i; ++ ok = check_cert(ctx); ++ if (!ok) ++ return ok; ++ } ++ return 1; ++} ++ ++static int check_cert(X509_STORE_CTX *ctx) ++{ ++ X509_CRL *crl = NULL, *dcrl = NULL; ++ int ok = 0; ++ int cnum = ctx->error_depth; ++ X509 *x = sk_X509_value(ctx->chain, cnum); ++ ++ ctx->current_cert = x; ++ ctx->current_issuer = NULL; ++ ctx->current_crl_score = 0; ++ ctx->current_reasons = 0; ++ ++ if (x->ex_flags & EXFLAG_PROXY) ++ return 1; ++ ++ while (ctx->current_reasons != CRLDP_ALL_REASONS) { ++ unsigned int last_reasons = ctx->current_reasons; ++ ++ /* Try to retrieve relevant CRL */ ++ if (ctx->get_crl) ++ ok = ctx->get_crl(ctx, &crl, x); ++ else ++ ok = get_crl_delta(ctx, &crl, &dcrl, x); ++ /* ++ * If error looking up CRL, nothing we can do except notify callback ++ */ ++ if (!ok) { ++ ok = verify_cb_crl(ctx, X509_V_ERR_UNABLE_TO_GET_CRL); ++ goto done; ++ } ++ ctx->current_crl = crl; ++ ok = ctx->check_crl(ctx, crl); ++ if (!ok) ++ goto done; ++ ++ if (dcrl) { ++ ok = ctx->check_crl(ctx, dcrl); ++ if (!ok) ++ goto done; ++ ok = ctx->cert_crl(ctx, dcrl, x); ++ if (!ok) ++ goto done; ++ } else ++ ok = 1; ++ ++ /* Don't look in full CRL if delta reason is removefromCRL */ ++ if (ok != 2) { ++ ok = ctx->cert_crl(ctx, crl, x); ++ if (!ok) ++ goto done; ++ } ++ ++ X509_CRL_free(crl); ++ X509_CRL_free(dcrl); ++ crl = NULL; ++ dcrl = NULL; ++ /* ++ * If reasons not updated we won't get anywhere by another iteration, ++ * so exit loop. ++ */ ++ if (last_reasons == ctx->current_reasons) { ++ ok = verify_cb_crl(ctx, X509_V_ERR_UNABLE_TO_GET_CRL); ++ goto done; ++ } ++ } ++ done: ++ X509_CRL_free(crl); ++ X509_CRL_free(dcrl); ++ ++ ctx->current_crl = NULL; ++ return ok; ++} ++ ++/* Check CRL times against values in X509_STORE_CTX */ ++ ++static int check_crl_time(X509_STORE_CTX *ctx, X509_CRL *crl, int notify) ++{ ++ time_t *ptime; ++ int i; ++ ++ if (notify) ++ ctx->current_crl = crl; ++ if (ctx->param->flags & X509_V_FLAG_USE_CHECK_TIME) ++ ptime = &ctx->param->check_time; ++ else if (ctx->param->flags & X509_V_FLAG_NO_CHECK_TIME) ++ return 1; ++ else ++ ptime = NULL; ++ ++ i = X509_cmp_time(X509_CRL_get0_lastUpdate(crl), ptime); ++ if (i == 0) { ++ if (!notify) ++ return 0; ++ if (!verify_cb_crl(ctx, X509_V_ERR_ERROR_IN_CRL_LAST_UPDATE_FIELD)) ++ return 0; ++ } ++ ++ if (i > 0) { ++ if (!notify) ++ return 0; ++ if (!verify_cb_crl(ctx, X509_V_ERR_CRL_NOT_YET_VALID)) ++ return 0; ++ } ++ ++ if (X509_CRL_get0_nextUpdate(crl)) { ++ i = X509_cmp_time(X509_CRL_get0_nextUpdate(crl), ptime); ++ ++ if (i == 0) { ++ if (!notify) ++ return 0; ++ if (!verify_cb_crl(ctx, X509_V_ERR_ERROR_IN_CRL_NEXT_UPDATE_FIELD)) ++ return 0; ++ } ++ /* Ignore expiry of base CRL is delta is valid */ ++ if ((i < 0) && !(ctx->current_crl_score & CRL_SCORE_TIME_DELTA)) { ++ if (!notify) ++ return 0; ++ if (!verify_cb_crl(ctx, X509_V_ERR_CRL_HAS_EXPIRED)) ++ return 0; ++ } ++ } ++ ++ if (notify) ++ ctx->current_crl = NULL; ++ ++ return 1; ++} ++ ++static int get_crl_sk(X509_STORE_CTX *ctx, X509_CRL **pcrl, X509_CRL **pdcrl, ++ X509 **pissuer, int *pscore, unsigned int *preasons, ++ STACK_OF(X509_CRL) *crls) ++{ ++ int i, crl_score, best_score = *pscore; ++ unsigned int reasons, best_reasons = 0; ++ X509 *x = ctx->current_cert; ++ X509_CRL *crl, *best_crl = NULL; ++ X509 *crl_issuer = NULL, *best_crl_issuer = NULL; ++ ++ for (i = 0; i < sk_X509_CRL_num(crls); i++) { ++ crl = sk_X509_CRL_value(crls, i); ++ reasons = *preasons; ++ crl_score = get_crl_score(ctx, &crl_issuer, &reasons, crl, x); ++ if (crl_score < best_score || crl_score == 0) ++ continue; ++ /* If current CRL is equivalent use it if it is newer */ ++ if (crl_score == best_score && best_crl != NULL) { ++ int day, sec; ++ if (ASN1_TIME_diff(&day, &sec, X509_CRL_get0_lastUpdate(best_crl), ++ X509_CRL_get0_lastUpdate(crl)) == 0) ++ continue; ++ /* ++ * ASN1_TIME_diff never returns inconsistent signs for |day| ++ * and |sec|. ++ */ ++ if (day <= 0 && sec <= 0) ++ continue; ++ } ++ best_crl = crl; ++ best_crl_issuer = crl_issuer; ++ best_score = crl_score; ++ best_reasons = reasons; ++ } ++ ++ if (best_crl) { ++ X509_CRL_free(*pcrl); ++ *pcrl = best_crl; ++ *pissuer = best_crl_issuer; ++ *pscore = best_score; ++ *preasons = best_reasons; ++ X509_CRL_up_ref(best_crl); ++ X509_CRL_free(*pdcrl); ++ *pdcrl = NULL; ++ get_delta_sk(ctx, pdcrl, pscore, best_crl, crls); ++ } ++ ++ if (best_score >= CRL_SCORE_VALID) ++ return 1; ++ ++ return 0; ++} ++ ++/* ++ * Compare two CRL extensions for delta checking purposes. They should be ++ * both present or both absent. If both present all fields must be identical. ++ */ ++ ++static int crl_extension_match(X509_CRL *a, X509_CRL *b, int nid) ++{ ++ ASN1_OCTET_STRING *exta, *extb; ++ int i; ++ i = X509_CRL_get_ext_by_NID(a, nid, -1); ++ if (i >= 0) { ++ /* Can't have multiple occurrences */ ++ if (X509_CRL_get_ext_by_NID(a, nid, i) != -1) ++ return 0; ++ exta = X509_EXTENSION_get_data(X509_CRL_get_ext(a, i)); ++ } else ++ exta = NULL; ++ ++ i = X509_CRL_get_ext_by_NID(b, nid, -1); ++ ++ if (i >= 0) { ++ ++ if (X509_CRL_get_ext_by_NID(b, nid, i) != -1) ++ return 0; ++ extb = X509_EXTENSION_get_data(X509_CRL_get_ext(b, i)); ++ } else ++ extb = NULL; ++ ++ if (!exta && !extb) ++ return 1; ++ ++ if (!exta || !extb) ++ return 0; ++ ++ if (ASN1_OCTET_STRING_cmp(exta, extb)) ++ return 0; ++ ++ return 1; ++} ++ ++/* See if a base and delta are compatible */ ++ ++static int check_delta_base(X509_CRL *delta, X509_CRL *base) ++{ ++ /* Delta CRL must be a delta */ ++ if (!delta->base_crl_number) ++ return 0; ++ /* Base must have a CRL number */ ++ if (!base->crl_number) ++ return 0; ++ /* Issuer names must match */ ++ if (X509_NAME_cmp(X509_CRL_get_issuer(base), X509_CRL_get_issuer(delta))) ++ return 0; ++ /* AKID and IDP must match */ ++ if (!crl_extension_match(delta, base, NID_authority_key_identifier)) ++ return 0; ++ if (!crl_extension_match(delta, base, NID_issuing_distribution_point)) ++ return 0; ++ /* Delta CRL base number must not exceed Full CRL number. */ ++ if (ASN1_INTEGER_cmp(delta->base_crl_number, base->crl_number) > 0) ++ return 0; ++ /* Delta CRL number must exceed full CRL number */ ++ if (ASN1_INTEGER_cmp(delta->crl_number, base->crl_number) > 0) ++ return 1; ++ return 0; ++} ++ ++/* ++ * For a given base CRL find a delta... maybe extend to delta scoring or ++ * retrieve a chain of deltas... ++ */ ++ ++static void get_delta_sk(X509_STORE_CTX *ctx, X509_CRL **dcrl, int *pscore, ++ X509_CRL *base, STACK_OF(X509_CRL) *crls) ++{ ++ X509_CRL *delta; ++ int i; ++ if (!(ctx->param->flags & X509_V_FLAG_USE_DELTAS)) ++ return; ++ if (!((ctx->current_cert->ex_flags | base->flags) & EXFLAG_FRESHEST)) ++ return; ++ for (i = 0; i < sk_X509_CRL_num(crls); i++) { ++ delta = sk_X509_CRL_value(crls, i); ++ if (check_delta_base(delta, base)) { ++ if (check_crl_time(ctx, delta, 0)) ++ *pscore |= CRL_SCORE_TIME_DELTA; ++ X509_CRL_up_ref(delta); ++ *dcrl = delta; ++ return; ++ } ++ } ++ *dcrl = NULL; ++} ++ ++/* ++ * For a given CRL return how suitable it is for the supplied certificate ++ * 'x'. The return value is a mask of several criteria. If the issuer is not ++ * the certificate issuer this is returned in *pissuer. The reasons mask is ++ * also used to determine if the CRL is suitable: if no new reasons the CRL ++ * is rejected, otherwise reasons is updated. ++ */ ++ ++static int get_crl_score(X509_STORE_CTX *ctx, X509 **pissuer, ++ unsigned int *preasons, X509_CRL *crl, X509 *x) ++{ ++ ++ int crl_score = 0; ++ unsigned int tmp_reasons = *preasons, crl_reasons; ++ ++ /* First see if we can reject CRL straight away */ ++ ++ /* Invalid IDP cannot be processed */ ++ if (crl->idp_flags & IDP_INVALID) ++ return 0; ++ /* Reason codes or indirect CRLs need extended CRL support */ ++ if (!(ctx->param->flags & X509_V_FLAG_EXTENDED_CRL_SUPPORT)) { ++ if (crl->idp_flags & (IDP_INDIRECT | IDP_REASONS)) ++ return 0; ++ } else if (crl->idp_flags & IDP_REASONS) { ++ /* If no new reasons reject */ ++ if (!(crl->idp_reasons & ~tmp_reasons)) ++ return 0; ++ } ++ /* Don't process deltas at this stage */ ++ else if (crl->base_crl_number) ++ return 0; ++ /* If issuer name doesn't match certificate need indirect CRL */ ++ if (X509_NAME_cmp(X509_get_issuer_name(x), X509_CRL_get_issuer(crl))) { ++ if (!(crl->idp_flags & IDP_INDIRECT)) ++ return 0; ++ } else ++ crl_score |= CRL_SCORE_ISSUER_NAME; ++ ++ if (!(crl->flags & EXFLAG_CRITICAL)) ++ crl_score |= CRL_SCORE_NOCRITICAL; ++ ++ /* Check expiry */ ++ if (check_crl_time(ctx, crl, 0)) ++ crl_score |= CRL_SCORE_TIME; ++ ++ /* Check authority key ID and locate certificate issuer */ ++ crl_akid_check(ctx, crl, pissuer, &crl_score); ++ ++ /* If we can't locate certificate issuer at this point forget it */ ++ ++ if (!(crl_score & CRL_SCORE_AKID)) ++ return 0; ++ ++ /* Check cert for matching CRL distribution points */ ++ ++ if (crl_crldp_check(x, crl, crl_score, &crl_reasons)) { ++ /* If no new reasons reject */ ++ if (!(crl_reasons & ~tmp_reasons)) ++ return 0; ++ tmp_reasons |= crl_reasons; ++ crl_score |= CRL_SCORE_SCOPE; ++ } ++ ++ *preasons = tmp_reasons; ++ ++ return crl_score; ++ ++} ++ ++static void crl_akid_check(X509_STORE_CTX *ctx, X509_CRL *crl, ++ X509 **pissuer, int *pcrl_score) ++{ ++ X509 *crl_issuer = NULL; ++ X509_NAME *cnm = X509_CRL_get_issuer(crl); ++ int cidx = ctx->error_depth; ++ int i; ++ ++ if (cidx != sk_X509_num(ctx->chain) - 1) ++ cidx++; ++ ++ crl_issuer = sk_X509_value(ctx->chain, cidx); ++ ++ if (X509_check_akid(crl_issuer, crl->akid) == X509_V_OK) { ++ if (*pcrl_score & CRL_SCORE_ISSUER_NAME) { ++ *pcrl_score |= CRL_SCORE_AKID | CRL_SCORE_ISSUER_CERT; ++ *pissuer = crl_issuer; ++ return; ++ } ++ } ++ ++ for (cidx++; cidx < sk_X509_num(ctx->chain); cidx++) { ++ crl_issuer = sk_X509_value(ctx->chain, cidx); ++ if (X509_NAME_cmp(X509_get_subject_name(crl_issuer), cnm)) ++ continue; ++ if (X509_check_akid(crl_issuer, crl->akid) == X509_V_OK) { ++ *pcrl_score |= CRL_SCORE_AKID | CRL_SCORE_SAME_PATH; ++ *pissuer = crl_issuer; ++ return; ++ } ++ } ++ ++ /* Anything else needs extended CRL support */ ++ ++ if (!(ctx->param->flags & X509_V_FLAG_EXTENDED_CRL_SUPPORT)) ++ return; ++ ++ /* ++ * Otherwise the CRL issuer is not on the path. Look for it in the set of ++ * untrusted certificates. ++ */ ++ for (i = 0; i < sk_X509_num(ctx->untrusted); i++) { ++ crl_issuer = sk_X509_value(ctx->untrusted, i); ++ if (X509_NAME_cmp(X509_get_subject_name(crl_issuer), cnm)) ++ continue; ++ if (X509_check_akid(crl_issuer, crl->akid) == X509_V_OK) { ++ *pissuer = crl_issuer; ++ *pcrl_score |= CRL_SCORE_AKID; ++ return; ++ } ++ } ++} ++ ++/* ++ * Check the path of a CRL issuer certificate. This creates a new ++ * X509_STORE_CTX and populates it with most of the parameters from the ++ * parent. This could be optimised somewhat since a lot of path checking will ++ * be duplicated by the parent, but this will rarely be used in practice. ++ */ ++ ++static int check_crl_path(X509_STORE_CTX *ctx, X509 *x) ++{ ++ X509_STORE_CTX crl_ctx; ++ int ret; ++ ++ /* Don't allow recursive CRL path validation */ ++ if (ctx->parent) ++ return 0; ++ if (!X509_STORE_CTX_init(&crl_ctx, ctx->ctx, x, ctx->untrusted)) ++ return -1; ++ ++ crl_ctx.crls = ctx->crls; ++ /* Copy verify params across */ ++ X509_STORE_CTX_set0_param(&crl_ctx, ctx->param); ++ ++ crl_ctx.parent = ctx; ++ crl_ctx.verify_cb = ctx->verify_cb; ++ ++ /* Verify CRL issuer */ ++ ret = X509_verify_cert(&crl_ctx); ++ if (ret <= 0) ++ goto err; ++ ++ /* Check chain is acceptable */ ++ ret = check_crl_chain(ctx, ctx->chain, crl_ctx.chain); ++ err: ++ X509_STORE_CTX_cleanup(&crl_ctx); ++ return ret; ++} ++ ++/* ++ * RFC3280 says nothing about the relationship between CRL path and ++ * certificate path, which could lead to situations where a certificate could ++ * be revoked or validated by a CA not authorised to do so. RFC5280 is more ++ * strict and states that the two paths must end in the same trust anchor, ++ * though some discussions remain... until this is resolved we use the ++ * RFC5280 version ++ */ ++ ++static int check_crl_chain(X509_STORE_CTX *ctx, ++ STACK_OF(X509) *cert_path, ++ STACK_OF(X509) *crl_path) ++{ ++ X509 *cert_ta, *crl_ta; ++ cert_ta = sk_X509_value(cert_path, sk_X509_num(cert_path) - 1); ++ crl_ta = sk_X509_value(crl_path, sk_X509_num(crl_path) - 1); ++ if (!X509_cmp(cert_ta, crl_ta)) ++ return 1; ++ return 0; ++} ++ ++/*- ++ * Check for match between two dist point names: three separate cases. ++ * 1. Both are relative names and compare X509_NAME types. ++ * 2. One full, one relative. Compare X509_NAME to GENERAL_NAMES. ++ * 3. Both are full names and compare two GENERAL_NAMES. ++ * 4. One is NULL: automatic match. ++ */ ++ ++static int idp_check_dp(DIST_POINT_NAME *a, DIST_POINT_NAME *b) ++{ ++ X509_NAME *nm = NULL; ++ GENERAL_NAMES *gens = NULL; ++ GENERAL_NAME *gena, *genb; ++ int i, j; ++ if (!a || !b) ++ return 1; ++ if (a->type == 1) { ++ if (!a->dpname) ++ return 0; ++ /* Case 1: two X509_NAME */ ++ if (b->type == 1) { ++ if (!b->dpname) ++ return 0; ++ if (!X509_NAME_cmp(a->dpname, b->dpname)) ++ return 1; ++ else ++ return 0; ++ } ++ /* Case 2: set name and GENERAL_NAMES appropriately */ ++ nm = a->dpname; ++ gens = b->name.fullname; ++ } else if (b->type == 1) { ++ if (!b->dpname) ++ return 0; ++ /* Case 2: set name and GENERAL_NAMES appropriately */ ++ gens = a->name.fullname; ++ nm = b->dpname; ++ } ++ ++ /* Handle case 2 with one GENERAL_NAMES and one X509_NAME */ ++ if (nm) { ++ for (i = 0; i < sk_GENERAL_NAME_num(gens); i++) { ++ gena = sk_GENERAL_NAME_value(gens, i); ++ if (gena->type != GEN_DIRNAME) ++ continue; ++ if (!X509_NAME_cmp(nm, gena->d.directoryName)) ++ return 1; ++ } ++ return 0; ++ } ++ ++ /* Else case 3: two GENERAL_NAMES */ ++ ++ for (i = 0; i < sk_GENERAL_NAME_num(a->name.fullname); i++) { ++ gena = sk_GENERAL_NAME_value(a->name.fullname, i); ++ for (j = 0; j < sk_GENERAL_NAME_num(b->name.fullname); j++) { ++ genb = sk_GENERAL_NAME_value(b->name.fullname, j); ++ if (!GENERAL_NAME_cmp(gena, genb)) ++ return 1; ++ } ++ } ++ ++ return 0; ++ ++} ++ ++static int crldp_check_crlissuer(DIST_POINT *dp, X509_CRL *crl, int crl_score) ++{ ++ int i; ++ X509_NAME *nm = X509_CRL_get_issuer(crl); ++ /* If no CRLissuer return is successful iff don't need a match */ ++ if (!dp->CRLissuer) ++ return ! !(crl_score & CRL_SCORE_ISSUER_NAME); ++ for (i = 0; i < sk_GENERAL_NAME_num(dp->CRLissuer); i++) { ++ GENERAL_NAME *gen = sk_GENERAL_NAME_value(dp->CRLissuer, i); ++ if (gen->type != GEN_DIRNAME) ++ continue; ++ if (!X509_NAME_cmp(gen->d.directoryName, nm)) ++ return 1; ++ } ++ return 0; ++} ++ ++/* Check CRLDP and IDP */ ++ ++static int crl_crldp_check(X509 *x, X509_CRL *crl, int crl_score, ++ unsigned int *preasons) ++{ ++ int i; ++ if (crl->idp_flags & IDP_ONLYATTR) ++ return 0; ++ if (x->ex_flags & EXFLAG_CA) { ++ if (crl->idp_flags & IDP_ONLYUSER) ++ return 0; ++ } else { ++ if (crl->idp_flags & IDP_ONLYCA) ++ return 0; ++ } ++ *preasons = crl->idp_reasons; ++ for (i = 0; i < sk_DIST_POINT_num(x->crldp); i++) { ++ DIST_POINT *dp = sk_DIST_POINT_value(x->crldp, i); ++ if (crldp_check_crlissuer(dp, crl, crl_score)) { ++ if (!crl->idp || idp_check_dp(dp->distpoint, crl->idp->distpoint)) { ++ *preasons &= dp->dp_reasons; ++ return 1; ++ } ++ } ++ } ++ if ((!crl->idp || !crl->idp->distpoint) ++ && (crl_score & CRL_SCORE_ISSUER_NAME)) ++ return 1; ++ return 0; ++} ++ ++/* ++ * Retrieve CRL corresponding to current certificate. If deltas enabled try ++ * to find a delta CRL too ++ */ ++ ++static int get_crl_delta(X509_STORE_CTX *ctx, ++ X509_CRL **pcrl, X509_CRL **pdcrl, X509 *x) ++{ ++ int ok; ++ X509 *issuer = NULL; ++ int crl_score = 0; ++ unsigned int reasons; ++ X509_CRL *crl = NULL, *dcrl = NULL; ++ STACK_OF(X509_CRL) *skcrl; ++ X509_NAME *nm = X509_get_issuer_name(x); ++ ++ reasons = ctx->current_reasons; ++ ok = get_crl_sk(ctx, &crl, &dcrl, ++ &issuer, &crl_score, &reasons, ctx->crls); ++ if (ok) ++ goto done; ++ ++ /* Lookup CRLs from store */ ++ ++ skcrl = ctx->lookup_crls(ctx, nm); ++ ++ /* If no CRLs found and a near match from get_crl_sk use that */ ++ if (!skcrl && crl) ++ goto done; ++ ++ get_crl_sk(ctx, &crl, &dcrl, &issuer, &crl_score, &reasons, skcrl); ++ ++ sk_X509_CRL_pop_free(skcrl, X509_CRL_free); ++ ++ done: ++ /* If we got any kind of CRL use it and return success */ ++ if (crl) { ++ ctx->current_issuer = issuer; ++ ctx->current_crl_score = crl_score; ++ ctx->current_reasons = reasons; ++ *pcrl = crl; ++ *pdcrl = dcrl; ++ return 1; ++ } ++ return 0; ++} ++ ++/* Check CRL validity */ ++static int check_crl(X509_STORE_CTX *ctx, X509_CRL *crl) ++{ ++ X509 *issuer = NULL; ++ EVP_PKEY *ikey = NULL; ++ int cnum = ctx->error_depth; ++ int chnum = sk_X509_num(ctx->chain) - 1; ++ ++ /* if we have an alternative CRL issuer cert use that */ ++ if (ctx->current_issuer) ++ issuer = ctx->current_issuer; ++ /* ++ * Else find CRL issuer: if not last certificate then issuer is next ++ * certificate in chain. ++ */ ++ else if (cnum < chnum) ++ issuer = sk_X509_value(ctx->chain, cnum + 1); ++ else { ++ issuer = sk_X509_value(ctx->chain, chnum); ++ /* If not self signed, can't check signature */ ++ if (!ctx->check_issued(ctx, issuer, issuer) && ++ !verify_cb_crl(ctx, X509_V_ERR_UNABLE_TO_GET_CRL_ISSUER)) ++ return 0; ++ } ++ ++ if (issuer == NULL) ++ return 1; ++ ++ /* ++ * Skip most tests for deltas because they have already been done ++ */ ++ if (!crl->base_crl_number) { ++ /* Check for cRLSign bit if keyUsage present */ ++ if ((issuer->ex_flags & EXFLAG_KUSAGE) && ++ !(issuer->ex_kusage & KU_CRL_SIGN) && ++ !verify_cb_crl(ctx, X509_V_ERR_KEYUSAGE_NO_CRL_SIGN)) ++ return 0; ++ ++ if (!(ctx->current_crl_score & CRL_SCORE_SCOPE) && ++ !verify_cb_crl(ctx, X509_V_ERR_DIFFERENT_CRL_SCOPE)) ++ return 0; ++ ++ if (!(ctx->current_crl_score & CRL_SCORE_SAME_PATH) && ++ check_crl_path(ctx, ctx->current_issuer) <= 0 && ++ !verify_cb_crl(ctx, X509_V_ERR_CRL_PATH_VALIDATION_ERROR)) ++ return 0; ++ ++ if ((crl->idp_flags & IDP_INVALID) && ++ !verify_cb_crl(ctx, X509_V_ERR_INVALID_EXTENSION)) ++ return 0; ++ } ++ ++ if (!(ctx->current_crl_score & CRL_SCORE_TIME) && ++ !check_crl_time(ctx, crl, 1)) ++ return 0; ++ ++ /* Attempt to get issuer certificate public key */ ++ ikey = X509_get0_pubkey(issuer); ++ ++ if (!ikey && ++ !verify_cb_crl(ctx, X509_V_ERR_UNABLE_TO_DECODE_ISSUER_PUBLIC_KEY)) ++ return 0; ++ ++ if (ikey) { ++ int rv = X509_CRL_check_suiteb(crl, ikey, ctx->param->flags); ++ ++ if (rv != X509_V_OK && !verify_cb_crl(ctx, rv)) ++ return 0; ++ /* Verify CRL signature */ ++ if (X509_CRL_verify(crl, ikey) <= 0 && ++ !verify_cb_crl(ctx, X509_V_ERR_CRL_SIGNATURE_FAILURE)) ++ return 0; ++ } ++ return 1; ++} ++ ++/* Check certificate against CRL */ ++static int cert_crl(X509_STORE_CTX *ctx, X509_CRL *crl, X509 *x) ++{ ++ X509_REVOKED *rev; ++ ++ /* ++ * The rules changed for this... previously if a CRL contained unhandled ++ * critical extensions it could still be used to indicate a certificate ++ * was revoked. This has since been changed since critical extensions can ++ * change the meaning of CRL entries. ++ */ ++ if (!(ctx->param->flags & X509_V_FLAG_IGNORE_CRITICAL) ++ && (crl->flags & EXFLAG_CRITICAL) && ++ !verify_cb_crl(ctx, X509_V_ERR_UNHANDLED_CRITICAL_CRL_EXTENSION)) ++ return 0; ++ /* ++ * Look for serial number of certificate in CRL. If found, make sure ++ * reason is not removeFromCRL. ++ */ ++ if (X509_CRL_get0_by_cert(crl, &rev, x)) { ++ if (rev->reason == CRL_REASON_REMOVE_FROM_CRL) ++ return 2; ++ if (!verify_cb_crl(ctx, X509_V_ERR_CERT_REVOKED)) ++ return 0; ++ } ++ ++ return 1; ++} ++ ++static int check_policy(X509_STORE_CTX *ctx) ++{ ++ int ret; ++ ++ if (ctx->parent) ++ return 1; ++ /* ++ * With DANE, the trust anchor might be a bare public key, not a ++ * certificate! In that case our chain does not have the trust anchor ++ * certificate as a top-most element. This comports well with RFC5280 ++ * chain verification, since there too, the trust anchor is not part of the ++ * chain to be verified. In particular, X509_policy_check() does not look ++ * at the TA cert, but assumes that it is present as the top-most chain ++ * element. We therefore temporarily push a NULL cert onto the chain if it ++ * was verified via a bare public key, and pop it off right after the ++ * X509_policy_check() call. ++ */ ++ if (ctx->bare_ta_signed && !sk_X509_push(ctx->chain, NULL)) { ++ X509err(X509_F_CHECK_POLICY, ERR_R_MALLOC_FAILURE); ++ ctx->error = X509_V_ERR_OUT_OF_MEM; ++ return 0; ++ } ++ ret = X509_policy_check(&ctx->tree, &ctx->explicit_policy, ctx->chain, ++ ctx->param->policies, ctx->param->flags); ++ if (ctx->bare_ta_signed) ++ sk_X509_pop(ctx->chain); ++ ++ if (ret == X509_PCY_TREE_INTERNAL) { ++ X509err(X509_F_CHECK_POLICY, ERR_R_MALLOC_FAILURE); ++ ctx->error = X509_V_ERR_OUT_OF_MEM; ++ return 0; ++ } ++ /* Invalid or inconsistent extensions */ ++ if (ret == X509_PCY_TREE_INVALID) { ++ int i; ++ ++ /* Locate certificates with bad extensions and notify callback. */ ++ for (i = 1; i < sk_X509_num(ctx->chain); i++) { ++ X509 *x = sk_X509_value(ctx->chain, i); ++ ++ if (!(x->ex_flags & EXFLAG_INVALID_POLICY)) ++ continue; ++ if (!verify_cb_cert(ctx, x, i, ++ X509_V_ERR_INVALID_POLICY_EXTENSION)) ++ return 0; ++ } ++ return 1; ++ } ++ if (ret == X509_PCY_TREE_FAILURE) { ++ ctx->current_cert = NULL; ++ ctx->error = X509_V_ERR_NO_EXPLICIT_POLICY; ++ return ctx->verify_cb(0, ctx); ++ } ++ if (ret != X509_PCY_TREE_VALID) { ++ X509err(X509_F_CHECK_POLICY, ERR_R_INTERNAL_ERROR); ++ return 0; ++ } ++ ++ if (ctx->param->flags & X509_V_FLAG_NOTIFY_POLICY) { ++ ctx->current_cert = NULL; ++ /* ++ * Verification errors need to be "sticky", a callback may have allowed ++ * an SSL handshake to continue despite an error, and we must then ++ * remain in an error state. Therefore, we MUST NOT clear earlier ++ * verification errors by setting the error to X509_V_OK. ++ */ ++ if (!ctx->verify_cb(2, ctx)) ++ return 0; ++ } ++ ++ return 1; ++} ++ ++/*- ++ * Check certificate validity times. ++ * If depth >= 0, invoke verification callbacks on error, otherwise just return ++ * the validation status. ++ * ++ * Return 1 on success, 0 otherwise. ++ */ ++int x509_check_cert_time(X509_STORE_CTX *ctx, X509 *x, int depth) ++{ ++ time_t *ptime; ++ int i; ++ ++ if (ctx->param->flags & X509_V_FLAG_USE_CHECK_TIME) ++ ptime = &ctx->param->check_time; ++ else if (ctx->param->flags & X509_V_FLAG_NO_CHECK_TIME) ++ return 1; ++ else ++ ptime = NULL; ++ ++ i = X509_cmp_time(X509_get0_notBefore(x), ptime); ++ if (i >= 0 && depth < 0) ++ return 0; ++ if (i == 0 && !verify_cb_cert(ctx, x, depth, ++ X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD)) ++ return 0; ++ if (i > 0 && !verify_cb_cert(ctx, x, depth, X509_V_ERR_CERT_NOT_YET_VALID)) ++ return 0; ++ ++ i = X509_cmp_time(X509_get0_notAfter(x), ptime); ++ if (i <= 0 && depth < 0) ++ return 0; ++ if (i == 0 && !verify_cb_cert(ctx, x, depth, ++ X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD)) ++ return 0; ++ if (i < 0 && !verify_cb_cert(ctx, x, depth, X509_V_ERR_CERT_HAS_EXPIRED)) ++ return 0; ++ return 1; ++} ++ ++static int internal_verify(X509_STORE_CTX *ctx) ++{ ++ int n = sk_X509_num(ctx->chain) - 1; ++ X509 *xi = sk_X509_value(ctx->chain, n); ++ X509 *xs; ++ ++ /* ++ * With DANE-verified bare public key TA signatures, it remains only to ++ * check the timestamps of the top certificate. We report the issuer as ++ * NULL, since all we have is a bare key. ++ */ ++ if (ctx->bare_ta_signed) { ++ xs = xi; ++ xi = NULL; ++ goto check_cert; ++ } ++ ++ if (ctx->check_issued(ctx, xi, xi)) ++ xs = xi; ++ else { ++ if (ctx->param->flags & X509_V_FLAG_PARTIAL_CHAIN) { ++ xs = xi; ++ goto check_cert; ++ } ++ if (n <= 0) ++ return verify_cb_cert(ctx, xi, 0, ++ X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE); ++ n--; ++ ctx->error_depth = n; ++ xs = sk_X509_value(ctx->chain, n); ++ } ++ ++ /* ++ * Do not clear ctx->error=0, it must be "sticky", only the user's callback ++ * is allowed to reset errors (at its own peril). ++ */ ++ while (n >= 0) { ++ EVP_PKEY *pkey; ++ ++ /* ++ * Skip signature check for self signed certificates unless explicitly ++ * asked for. It doesn't add any security and just wastes time. If ++ * the issuer's public key is unusable, report the issuer certificate ++ * and its depth (rather than the depth of the subject). ++ */ ++ if (xs != xi || (ctx->param->flags & X509_V_FLAG_CHECK_SS_SIGNATURE)) { ++ if ((pkey = X509_get0_pubkey(xi)) == NULL) { ++ if (!verify_cb_cert(ctx, xi, xi != xs ? n+1 : n, ++ X509_V_ERR_UNABLE_TO_DECODE_ISSUER_PUBLIC_KEY)) ++ return 0; ++ } else if (X509_verify(xs, pkey) <= 0) { ++ if (!verify_cb_cert(ctx, xs, n, ++ X509_V_ERR_CERT_SIGNATURE_FAILURE)) ++ return 0; ++ } ++ } ++ ++ check_cert: ++ /* Calls verify callback as needed */ ++ if (!x509_check_cert_time(ctx, xs, n)) ++ return 0; ++ ++ /* ++ * Signal success at this depth. However, the previous error (if any) ++ * is retained. ++ */ ++ ctx->current_issuer = xi; ++ ctx->current_cert = xs; ++ ctx->error_depth = n; ++ if (!ctx->verify_cb(1, ctx)) ++ return 0; ++ ++ if (--n >= 0) { ++ xi = xs; ++ xs = sk_X509_value(ctx->chain, n); ++ } ++ } ++ return 1; ++} ++ ++int X509_cmp_current_time(const ASN1_TIME *ctm) ++{ ++ return X509_cmp_time(ctm, NULL); ++} ++ ++int X509_cmp_time(const ASN1_TIME *ctm, time_t *cmp_time) ++{ ++ char *str; ++ ASN1_TIME atm; ++ long offset; ++ char buff1[24], buff2[24], *p; ++ int i, j, remaining; ++ ++ p = buff1; ++ remaining = ctm->length; ++ str = (char *)ctm->data; ++ /* ++ * Note that the following (historical) code allows much more slack in the ++ * time format than RFC5280. In RFC5280, the representation is fixed: ++ * UTCTime: YYMMDDHHMMSSZ ++ * GeneralizedTime: YYYYMMDDHHMMSSZ ++ */ ++ if (ctm->type == V_ASN1_UTCTIME) { ++ /* YYMMDDHHMM[SS]Z or YYMMDDHHMM[SS](+-)hhmm */ ++ int min_length = sizeof("YYMMDDHHMMZ") - 1; ++ int max_length = sizeof("YYMMDDHHMMSS+hhmm") - 1; ++ if (remaining < min_length || remaining > max_length) ++ return 0; ++ memcpy(p, str, 10); ++ p += 10; ++ str += 10; ++ remaining -= 10; ++ } else { ++ /* YYYYMMDDHHMM[SS[.fff]]Z or YYYYMMDDHHMM[SS[.f[f[f]]]](+-)hhmm */ ++ int min_length = sizeof("YYYYMMDDHHMMZ") - 1; ++ int max_length = sizeof("YYYYMMDDHHMMSS.fff+hhmm") - 1; ++ if (remaining < min_length || remaining > max_length) ++ return 0; ++ memcpy(p, str, 12); ++ p += 12; ++ str += 12; ++ remaining -= 12; ++ } ++ ++ if ((*str == 'Z') || (*str == '-') || (*str == '+')) { ++ *(p++) = '0'; ++ *(p++) = '0'; ++ } else { ++ /* SS (seconds) */ ++ if (remaining < 2) ++ return 0; ++ *(p++) = *(str++); ++ *(p++) = *(str++); ++ remaining -= 2; ++ /* ++ * Skip any (up to three) fractional seconds... ++ * TODO(emilia): in RFC5280, fractional seconds are forbidden. ++ * Can we just kill them altogether? ++ */ ++ if (remaining && *str == '.') { ++ str++; ++ remaining--; ++ for (i = 0; i < 3 && remaining; i++, str++, remaining--) { ++ if (*str < '0' || *str > '9') ++ break; ++ } ++ } ++ ++ } ++ *(p++) = 'Z'; ++ *(p++) = '\0'; ++ ++ /* We now need either a terminating 'Z' or an offset. */ ++ if (!remaining) ++ return 0; ++ if (*str == 'Z') { ++ if (remaining != 1) ++ return 0; ++ offset = 0; ++ } else { ++ /* (+-)HHMM */ ++ if ((*str != '+') && (*str != '-')) ++ return 0; ++ /* Historical behaviour: the (+-)hhmm offset is forbidden in RFC5280. */ ++ if (remaining != 5) ++ return 0; ++ if (str[1] < '0' || str[1] > '9' || str[2] < '0' || str[2] > '9' || ++ str[3] < '0' || str[3] > '9' || str[4] < '0' || str[4] > '9') ++ return 0; ++ offset = ((str[1] - '0') * 10 + (str[2] - '0')) * 60; ++ offset += (str[3] - '0') * 10 + (str[4] - '0'); ++ if (*str == '-') ++ offset = -offset; ++ } ++ atm.type = ctm->type; ++ atm.flags = 0; ++ atm.length = sizeof(buff2); ++ atm.data = (unsigned char *)buff2; ++ ++ if (X509_time_adj(&atm, offset * 60, cmp_time) == NULL) ++ return 0; ++ ++ if (ctm->type == V_ASN1_UTCTIME) { ++ i = (buff1[0] - '0') * 10 + (buff1[1] - '0'); ++ if (i < 50) ++ i += 100; /* cf. RFC 2459 */ ++ j = (buff2[0] - '0') * 10 + (buff2[1] - '0'); ++ if (j < 50) ++ j += 100; ++ ++ if (i < j) ++ return -1; ++ if (i > j) ++ return 1; ++ } ++ i = strcmp(buff1, buff2); ++ if (i == 0) /* wait a second then return younger :-) */ ++ return -1; ++ else ++ return i; ++} ++ ++ASN1_TIME *X509_gmtime_adj(ASN1_TIME *s, long adj) ++{ ++ return X509_time_adj(s, adj, NULL); ++} ++ ++ASN1_TIME *X509_time_adj(ASN1_TIME *s, long offset_sec, time_t *in_tm) ++{ ++ return X509_time_adj_ex(s, 0, offset_sec, in_tm); ++} ++ ++ASN1_TIME *X509_time_adj_ex(ASN1_TIME *s, ++ int offset_day, long offset_sec, time_t *in_tm) ++{ ++ time_t t; ++ ++ if (in_tm) ++ t = *in_tm; ++ else ++ time(&t); ++ ++ if (s && !(s->flags & ASN1_STRING_FLAG_MSTRING)) { ++ if (s->type == V_ASN1_UTCTIME) ++ return ASN1_UTCTIME_adj(s, t, offset_day, offset_sec); ++ if (s->type == V_ASN1_GENERALIZEDTIME) ++ return ASN1_GENERALIZEDTIME_adj(s, t, offset_day, offset_sec); ++ } ++ return ASN1_TIME_adj(s, t, offset_day, offset_sec); ++} ++ ++int X509_get_pubkey_parameters(EVP_PKEY *pkey, STACK_OF(X509) *chain) ++{ ++ EVP_PKEY *ktmp = NULL, *ktmp2; ++ int i, j; ++ ++ if ((pkey != NULL) && !EVP_PKEY_missing_parameters(pkey)) ++ return 1; ++ ++ for (i = 0; i < sk_X509_num(chain); i++) { ++ ktmp = X509_get0_pubkey(sk_X509_value(chain, i)); ++ if (ktmp == NULL) { ++ X509err(X509_F_X509_GET_PUBKEY_PARAMETERS, ++ X509_R_UNABLE_TO_GET_CERTS_PUBLIC_KEY); ++ return 0; ++ } ++ if (!EVP_PKEY_missing_parameters(ktmp)) ++ break; ++ } ++ if (ktmp == NULL) { ++ X509err(X509_F_X509_GET_PUBKEY_PARAMETERS, ++ X509_R_UNABLE_TO_FIND_PARAMETERS_IN_CHAIN); ++ return 0; ++ } ++ ++ /* first, populate the other certs */ ++ for (j = i - 1; j >= 0; j--) { ++ ktmp2 = X509_get0_pubkey(sk_X509_value(chain, j)); ++ EVP_PKEY_copy_parameters(ktmp2, ktmp); ++ } ++ ++ if (pkey != NULL) ++ EVP_PKEY_copy_parameters(pkey, ktmp); ++ return 1; ++} ++ ++/* Make a delta CRL as the diff between two full CRLs */ ++ ++X509_CRL *X509_CRL_diff(X509_CRL *base, X509_CRL *newer, ++ EVP_PKEY *skey, const EVP_MD *md, unsigned int flags) ++{ ++ X509_CRL *crl = NULL; ++ int i; ++ STACK_OF(X509_REVOKED) *revs = NULL; ++ /* CRLs can't be delta already */ ++ if (base->base_crl_number || newer->base_crl_number) { ++ X509err(X509_F_X509_CRL_DIFF, X509_R_CRL_ALREADY_DELTA); ++ return NULL; ++ } ++ /* Base and new CRL must have a CRL number */ ++ if (!base->crl_number || !newer->crl_number) { ++ X509err(X509_F_X509_CRL_DIFF, X509_R_NO_CRL_NUMBER); ++ return NULL; ++ } ++ /* Issuer names must match */ ++ if (X509_NAME_cmp(X509_CRL_get_issuer(base), X509_CRL_get_issuer(newer))) { ++ X509err(X509_F_X509_CRL_DIFF, X509_R_ISSUER_MISMATCH); ++ return NULL; ++ } ++ /* AKID and IDP must match */ ++ if (!crl_extension_match(base, newer, NID_authority_key_identifier)) { ++ X509err(X509_F_X509_CRL_DIFF, X509_R_AKID_MISMATCH); ++ return NULL; ++ } ++ if (!crl_extension_match(base, newer, NID_issuing_distribution_point)) { ++ X509err(X509_F_X509_CRL_DIFF, X509_R_IDP_MISMATCH); ++ return NULL; ++ } ++ /* Newer CRL number must exceed full CRL number */ ++ if (ASN1_INTEGER_cmp(newer->crl_number, base->crl_number) <= 0) { ++ X509err(X509_F_X509_CRL_DIFF, X509_R_NEWER_CRL_NOT_NEWER); ++ return NULL; ++ } ++ /* CRLs must verify */ ++ if (skey && (X509_CRL_verify(base, skey) <= 0 || ++ X509_CRL_verify(newer, skey) <= 0)) { ++ X509err(X509_F_X509_CRL_DIFF, X509_R_CRL_VERIFY_FAILURE); ++ return NULL; ++ } ++ /* Create new CRL */ ++ crl = X509_CRL_new(); ++ if (crl == NULL || !X509_CRL_set_version(crl, 1)) ++ goto memerr; ++ /* Set issuer name */ ++ if (!X509_CRL_set_issuer_name(crl, X509_CRL_get_issuer(newer))) ++ goto memerr; ++ ++ if (!X509_CRL_set1_lastUpdate(crl, X509_CRL_get0_lastUpdate(newer))) ++ goto memerr; ++ if (!X509_CRL_set1_nextUpdate(crl, X509_CRL_get0_nextUpdate(newer))) ++ goto memerr; ++ ++ /* Set base CRL number: must be critical */ ++ ++ if (!X509_CRL_add1_ext_i2d(crl, NID_delta_crl, base->crl_number, 1, 0)) ++ goto memerr; ++ ++ /* ++ * Copy extensions across from newest CRL to delta: this will set CRL ++ * number to correct value too. ++ */ ++ ++ for (i = 0; i < X509_CRL_get_ext_count(newer); i++) { ++ X509_EXTENSION *ext; ++ ext = X509_CRL_get_ext(newer, i); ++ if (!X509_CRL_add_ext(crl, ext, -1)) ++ goto memerr; ++ } ++ ++ /* Go through revoked entries, copying as needed */ ++ ++ revs = X509_CRL_get_REVOKED(newer); ++ ++ for (i = 0; i < sk_X509_REVOKED_num(revs); i++) { ++ X509_REVOKED *rvn, *rvtmp; ++ rvn = sk_X509_REVOKED_value(revs, i); ++ /* ++ * Add only if not also in base. TODO: need something cleverer here ++ * for some more complex CRLs covering multiple CAs. ++ */ ++ if (!X509_CRL_get0_by_serial(base, &rvtmp, &rvn->serialNumber)) { ++ rvtmp = X509_REVOKED_dup(rvn); ++ if (!rvtmp) ++ goto memerr; ++ if (!X509_CRL_add0_revoked(crl, rvtmp)) { ++ X509_REVOKED_free(rvtmp); ++ goto memerr; ++ } ++ } ++ } ++ /* TODO: optionally prune deleted entries */ ++ ++ if (skey && md && !X509_CRL_sign(crl, skey, md)) ++ goto memerr; ++ ++ return crl; ++ ++ memerr: ++ X509err(X509_F_X509_CRL_DIFF, ERR_R_MALLOC_FAILURE); ++ X509_CRL_free(crl); ++ return NULL; ++} ++ ++int X509_STORE_CTX_set_ex_data(X509_STORE_CTX *ctx, int idx, void *data) ++{ ++ return CRYPTO_set_ex_data(&ctx->ex_data, idx, data); ++} ++ ++void *X509_STORE_CTX_get_ex_data(X509_STORE_CTX *ctx, int idx) ++{ ++ return CRYPTO_get_ex_data(&ctx->ex_data, idx); ++} ++ ++int X509_STORE_CTX_get_error(X509_STORE_CTX *ctx) ++{ ++ return ctx->error; ++} ++ ++void X509_STORE_CTX_set_error(X509_STORE_CTX *ctx, int err) ++{ ++ ctx->error = err; ++} ++ ++int X509_STORE_CTX_get_error_depth(X509_STORE_CTX *ctx) ++{ ++ return ctx->error_depth; ++} ++ ++void X509_STORE_CTX_set_error_depth(X509_STORE_CTX *ctx, int depth) ++{ ++ ctx->error_depth = depth; ++} ++ ++X509 *X509_STORE_CTX_get_current_cert(X509_STORE_CTX *ctx) ++{ ++ return ctx->current_cert; ++} ++ ++void X509_STORE_CTX_set_current_cert(X509_STORE_CTX *ctx, X509 *x) ++{ ++ ctx->current_cert = x; ++} ++ ++STACK_OF(X509) *X509_STORE_CTX_get0_chain(X509_STORE_CTX *ctx) ++{ ++ return ctx->chain; ++} ++ ++STACK_OF(X509) *X509_STORE_CTX_get1_chain(X509_STORE_CTX *ctx) ++{ ++ if (!ctx->chain) ++ return NULL; ++ return X509_chain_up_ref(ctx->chain); ++} ++ ++X509 *X509_STORE_CTX_get0_current_issuer(X509_STORE_CTX *ctx) ++{ ++ return ctx->current_issuer; ++} ++ ++X509_CRL *X509_STORE_CTX_get0_current_crl(X509_STORE_CTX *ctx) ++{ ++ return ctx->current_crl; ++} ++ ++X509_STORE_CTX *X509_STORE_CTX_get0_parent_ctx(X509_STORE_CTX *ctx) ++{ ++ return ctx->parent; ++} ++ ++void X509_STORE_CTX_set_cert(X509_STORE_CTX *ctx, X509 *x) ++{ ++ ctx->cert = x; ++} ++ ++void X509_STORE_CTX_set0_crls(X509_STORE_CTX *ctx, STACK_OF(X509_CRL) *sk) ++{ ++ ctx->crls = sk; ++} ++ ++int X509_STORE_CTX_set_purpose(X509_STORE_CTX *ctx, int purpose) ++{ ++ /* ++ * XXX: Why isn't this function always used to set the associated trust? ++ * Should there even be a VPM->trust field at all? Or should the trust ++ * always be inferred from the purpose by X509_STORE_CTX_init(). ++ */ ++ return X509_STORE_CTX_purpose_inherit(ctx, 0, purpose, 0); ++} ++ ++int X509_STORE_CTX_set_trust(X509_STORE_CTX *ctx, int trust) ++{ ++ /* ++ * XXX: See above, this function would only be needed when the default ++ * trust for the purpose needs an override in a corner case. ++ */ ++ return X509_STORE_CTX_purpose_inherit(ctx, 0, 0, trust); ++} ++ ++/* ++ * This function is used to set the X509_STORE_CTX purpose and trust values. ++ * This is intended to be used when another structure has its own trust and ++ * purpose values which (if set) will be inherited by the ctx. If they aren't ++ * set then we will usually have a default purpose in mind which should then ++ * be used to set the trust value. An example of this is SSL use: an SSL ++ * structure will have its own purpose and trust settings which the ++ * application can set: if they aren't set then we use the default of SSL ++ * client/server. ++ */ ++ ++int X509_STORE_CTX_purpose_inherit(X509_STORE_CTX *ctx, int def_purpose, ++ int purpose, int trust) ++{ ++ int idx; ++ /* If purpose not set use default */ ++ if (!purpose) ++ purpose = def_purpose; ++ /* If we have a purpose then check it is valid */ ++ if (purpose) { ++ X509_PURPOSE *ptmp; ++ idx = X509_PURPOSE_get_by_id(purpose); ++ if (idx == -1) { ++ X509err(X509_F_X509_STORE_CTX_PURPOSE_INHERIT, ++ X509_R_UNKNOWN_PURPOSE_ID); ++ return 0; ++ } ++ ptmp = X509_PURPOSE_get0(idx); ++ if (ptmp->trust == X509_TRUST_DEFAULT) { ++ idx = X509_PURPOSE_get_by_id(def_purpose); ++ /* ++ * XXX: In the two callers above def_purpose is always 0, which is ++ * not a known value, so idx will always be -1. How is the ++ * X509_TRUST_DEFAULT case actually supposed to be handled? ++ */ ++ if (idx == -1) { ++ X509err(X509_F_X509_STORE_CTX_PURPOSE_INHERIT, ++ X509_R_UNKNOWN_PURPOSE_ID); ++ return 0; ++ } ++ ptmp = X509_PURPOSE_get0(idx); ++ } ++ /* If trust not set then get from purpose default */ ++ if (!trust) ++ trust = ptmp->trust; ++ } ++ if (trust) { ++ idx = X509_TRUST_get_by_id(trust); ++ if (idx == -1) { ++ X509err(X509_F_X509_STORE_CTX_PURPOSE_INHERIT, ++ X509_R_UNKNOWN_TRUST_ID); ++ return 0; ++ } ++ } ++ ++ if (purpose && !ctx->param->purpose) ++ ctx->param->purpose = purpose; ++ if (trust && !ctx->param->trust) ++ ctx->param->trust = trust; ++ return 1; ++} ++ ++X509_STORE_CTX *X509_STORE_CTX_new(void) ++{ ++ X509_STORE_CTX *ctx = OPENSSL_zalloc(sizeof(*ctx)); ++ ++ if (ctx == NULL) { ++ X509err(X509_F_X509_STORE_CTX_NEW, ERR_R_MALLOC_FAILURE); ++ return NULL; ++ } ++ return ctx; ++} ++ ++void X509_STORE_CTX_free(X509_STORE_CTX *ctx) ++{ ++ if (ctx == NULL) ++ return; ++ ++ X509_STORE_CTX_cleanup(ctx); ++ OPENSSL_free(ctx); ++} ++ ++int X509_STORE_CTX_init(X509_STORE_CTX *ctx, X509_STORE *store, X509 *x509, ++ STACK_OF(X509) *chain) ++{ ++ int ret = 1; ++ ++ ctx->ctx = store; ++ ctx->cert = x509; ++ ctx->untrusted = chain; ++ ctx->crls = NULL; ++ ctx->num_untrusted = 0; ++ ctx->other_ctx = NULL; ++ ctx->valid = 0; ++ ctx->chain = NULL; ++ ctx->error = 0; ++ ctx->explicit_policy = 0; ++ ctx->error_depth = 0; ++ ctx->current_cert = NULL; ++ ctx->current_issuer = NULL; ++ ctx->current_crl = NULL; ++ ctx->current_crl_score = 0; ++ ctx->current_reasons = 0; ++ ctx->tree = NULL; ++ ctx->parent = NULL; ++ ctx->dane = NULL; ++ ctx->bare_ta_signed = 0; ++ /* Zero ex_data to make sure we're cleanup-safe */ ++ memset(&ctx->ex_data, 0, sizeof(ctx->ex_data)); ++ ++ /* store->cleanup is always 0 in OpenSSL, if set must be idempotent */ ++ if (store) ++ ctx->cleanup = store->cleanup; ++ else ++ ctx->cleanup = 0; ++ ++ if (store && store->check_issued) ++ ctx->check_issued = store->check_issued; ++ else ++ ctx->check_issued = check_issued; ++ ++ if (store && store->get_issuer) ++ ctx->get_issuer = store->get_issuer; ++ else ++ ctx->get_issuer = X509_STORE_CTX_get1_issuer; ++ ++ if (store && store->verify_cb) ++ ctx->verify_cb = store->verify_cb; ++ else ++ ctx->verify_cb = null_callback; ++ ++ if (store && store->verify) ++ ctx->verify = store->verify; ++ else ++ ctx->verify = internal_verify; ++ ++ if (store && store->check_revocation) ++ ctx->check_revocation = store->check_revocation; ++ else ++ ctx->check_revocation = check_revocation; ++ ++ if (store && store->get_crl) ++ ctx->get_crl = store->get_crl; ++ else ++ ctx->get_crl = NULL; ++ ++ if (store && store->check_crl) ++ ctx->check_crl = store->check_crl; ++ else ++ ctx->check_crl = check_crl; ++ ++ if (store && store->cert_crl) ++ ctx->cert_crl = store->cert_crl; ++ else ++ ctx->cert_crl = cert_crl; ++ ++ if (store && store->check_policy) ++ ctx->check_policy = store->check_policy; ++ else ++ ctx->check_policy = check_policy; ++ ++ if (store && store->lookup_certs) ++ ctx->lookup_certs = store->lookup_certs; ++ else ++ ctx->lookup_certs = X509_STORE_CTX_get1_certs; ++ ++ if (store && store->lookup_crls) ++ ctx->lookup_crls = store->lookup_crls; ++ else ++ ctx->lookup_crls = X509_STORE_CTX_get1_crls; ++ ++ ctx->param = X509_VERIFY_PARAM_new(); ++ if (ctx->param == NULL) { ++ X509err(X509_F_X509_STORE_CTX_INIT, ERR_R_MALLOC_FAILURE); ++ goto err; ++ } ++ ++ /* ++ * Inherit callbacks and flags from X509_STORE if not set use defaults. ++ */ ++ if (store) ++ ret = X509_VERIFY_PARAM_inherit(ctx->param, store->param); ++ else ++ ctx->param->inh_flags |= X509_VP_FLAG_DEFAULT | X509_VP_FLAG_ONCE; ++ ++ if (ret) ++ ret = X509_VERIFY_PARAM_inherit(ctx->param, ++ X509_VERIFY_PARAM_lookup("default")); ++ ++ if (ret == 0) { ++ X509err(X509_F_X509_STORE_CTX_INIT, ERR_R_MALLOC_FAILURE); ++ goto err; ++ } ++ ++ /* ++ * XXX: For now, continue to inherit trust from VPM, but infer from the ++ * purpose if this still yields the default value. ++ */ ++ if (ctx->param->trust == X509_TRUST_DEFAULT) { ++ int idx = X509_PURPOSE_get_by_id(ctx->param->purpose); ++ X509_PURPOSE *xp = X509_PURPOSE_get0(idx); ++ ++ if (xp != NULL) ++ ctx->param->trust = X509_PURPOSE_get_trust(xp); ++ } ++ ++ if (CRYPTO_new_ex_data(CRYPTO_EX_INDEX_X509_STORE_CTX, ctx, ++ &ctx->ex_data)) ++ return 1; ++ X509err(X509_F_X509_STORE_CTX_INIT, ERR_R_MALLOC_FAILURE); ++ ++ err: ++ /* ++ * On error clean up allocated storage, if the store context was not ++ * allocated with X509_STORE_CTX_new() this is our last chance to do so. ++ */ ++ X509_STORE_CTX_cleanup(ctx); ++ return 0; ++} ++ ++/* ++ * Set alternative lookup method: just a STACK of trusted certificates. This ++ * avoids X509_STORE nastiness where it isn't needed. ++ */ ++void X509_STORE_CTX_set0_trusted_stack(X509_STORE_CTX *ctx, STACK_OF(X509) *sk) ++{ ++ ctx->other_ctx = sk; ++ ctx->get_issuer = get_issuer_sk; ++ ctx->lookup_certs = lookup_certs_sk; ++} ++ ++void X509_STORE_CTX_cleanup(X509_STORE_CTX *ctx) ++{ ++ /* ++ * We need to be idempotent because, unfortunately, free() also calls ++ * cleanup(), so the natural call sequence new(), init(), cleanup(), free() ++ * calls cleanup() for the same object twice! Thus we must zero the ++ * pointers below after they're freed! ++ */ ++ /* Seems to always be 0 in OpenSSL, do this at most once. */ ++ if (ctx->cleanup != NULL) { ++ ctx->cleanup(ctx); ++ ctx->cleanup = NULL; ++ } ++ if (ctx->param != NULL) { ++ if (ctx->parent == NULL) ++ X509_VERIFY_PARAM_free(ctx->param); ++ ctx->param = NULL; ++ } ++ X509_policy_tree_free(ctx->tree); ++ ctx->tree = NULL; ++ sk_X509_pop_free(ctx->chain, X509_free); ++ ctx->chain = NULL; ++ CRYPTO_free_ex_data(CRYPTO_EX_INDEX_X509_STORE_CTX, ctx, &(ctx->ex_data)); ++ memset(&ctx->ex_data, 0, sizeof(ctx->ex_data)); ++} ++ ++void X509_STORE_CTX_set_depth(X509_STORE_CTX *ctx, int depth) ++{ ++ X509_VERIFY_PARAM_set_depth(ctx->param, depth); ++} ++ ++void X509_STORE_CTX_set_flags(X509_STORE_CTX *ctx, unsigned long flags) ++{ ++ X509_VERIFY_PARAM_set_flags(ctx->param, flags); ++} ++ ++void X509_STORE_CTX_set_time(X509_STORE_CTX *ctx, unsigned long flags, ++ time_t t) ++{ ++ X509_VERIFY_PARAM_set_time(ctx->param, t); ++} ++ ++X509 *X509_STORE_CTX_get0_cert(X509_STORE_CTX *ctx) ++{ ++ return ctx->cert; ++} ++ ++STACK_OF(X509) *X509_STORE_CTX_get0_untrusted(X509_STORE_CTX *ctx) ++{ ++ return ctx->untrusted; ++} ++ ++void X509_STORE_CTX_set0_untrusted(X509_STORE_CTX *ctx, STACK_OF(X509) *sk) ++{ ++ ctx->untrusted = sk; ++} ++ ++void X509_STORE_CTX_set0_verified_chain(X509_STORE_CTX *ctx, STACK_OF(X509) *sk) ++{ ++ sk_X509_pop_free(ctx->chain, X509_free); ++ ctx->chain = sk; ++} ++ ++void X509_STORE_CTX_set_verify_cb(X509_STORE_CTX *ctx, ++ X509_STORE_CTX_verify_cb verify_cb) ++{ ++ ctx->verify_cb = verify_cb; ++} ++ ++X509_STORE_CTX_verify_cb X509_STORE_CTX_get_verify_cb(X509_STORE_CTX *ctx) ++{ ++ return ctx->verify_cb; ++} ++ ++void X509_STORE_CTX_set_verify(X509_STORE_CTX *ctx, ++ X509_STORE_CTX_verify_fn verify) ++{ ++ ctx->verify = verify; ++} ++ ++X509_STORE_CTX_verify_fn X509_STORE_CTX_get_verify(X509_STORE_CTX *ctx) ++{ ++ return ctx->verify; ++} ++ ++X509_STORE_CTX_get_issuer_fn X509_STORE_CTX_get_get_issuer(X509_STORE_CTX *ctx) ++{ ++ return ctx->get_issuer; ++} ++ ++X509_STORE_CTX_check_issued_fn X509_STORE_CTX_get_check_issued(X509_STORE_CTX *ctx) ++{ ++ return ctx->check_issued; ++} ++ ++X509_STORE_CTX_check_revocation_fn X509_STORE_CTX_get_check_revocation(X509_STORE_CTX *ctx) ++{ ++ return ctx->check_revocation; ++} ++ ++X509_STORE_CTX_get_crl_fn X509_STORE_CTX_get_get_crl(X509_STORE_CTX *ctx) ++{ ++ return ctx->get_crl; ++} ++ ++X509_STORE_CTX_check_crl_fn X509_STORE_CTX_get_check_crl(X509_STORE_CTX *ctx) ++{ ++ return ctx->check_crl; ++} ++ ++X509_STORE_CTX_cert_crl_fn X509_STORE_CTX_get_cert_crl(X509_STORE_CTX *ctx) ++{ ++ return ctx->cert_crl; ++} ++ ++X509_STORE_CTX_check_policy_fn X509_STORE_CTX_get_check_policy(X509_STORE_CTX *ctx) ++{ ++ return ctx->check_policy; ++} ++ ++X509_STORE_CTX_lookup_certs_fn X509_STORE_CTX_get_lookup_certs(X509_STORE_CTX *ctx) ++{ ++ return ctx->lookup_certs; ++} ++ ++X509_STORE_CTX_lookup_crls_fn X509_STORE_CTX_get_lookup_crls(X509_STORE_CTX *ctx) ++{ ++ return ctx->lookup_crls; ++} ++ ++X509_STORE_CTX_cleanup_fn X509_STORE_CTX_get_cleanup(X509_STORE_CTX *ctx) ++{ ++ return ctx->cleanup; ++} ++ ++X509_POLICY_TREE *X509_STORE_CTX_get0_policy_tree(X509_STORE_CTX *ctx) ++{ ++ return ctx->tree; ++} ++ ++int X509_STORE_CTX_get_explicit_policy(X509_STORE_CTX *ctx) ++{ ++ return ctx->explicit_policy; ++} ++ ++int X509_STORE_CTX_get_num_untrusted(X509_STORE_CTX *ctx) ++{ ++ return ctx->num_untrusted; ++} ++ ++int X509_STORE_CTX_set_default(X509_STORE_CTX *ctx, const char *name) ++{ ++ const X509_VERIFY_PARAM *param; ++ param = X509_VERIFY_PARAM_lookup(name); ++ if (!param) ++ return 0; ++ return X509_VERIFY_PARAM_inherit(ctx->param, param); ++} ++ ++X509_VERIFY_PARAM *X509_STORE_CTX_get0_param(X509_STORE_CTX *ctx) ++{ ++ return ctx->param; ++} ++ ++void X509_STORE_CTX_set0_param(X509_STORE_CTX *ctx, X509_VERIFY_PARAM *param) ++{ ++ X509_VERIFY_PARAM_free(ctx->param); ++ ctx->param = param; ++} ++ ++void X509_STORE_CTX_set0_dane(X509_STORE_CTX *ctx, SSL_DANE *dane) ++{ ++ ctx->dane = dane; ++} ++ ++static unsigned char *dane_i2d( ++ X509 *cert, ++ uint8_t selector, ++ unsigned int *i2dlen) ++{ ++ unsigned char *buf = NULL; ++ int len; ++ ++ /* ++ * Extract ASN.1 DER form of certificate or public key. ++ */ ++ switch (selector) { ++ case DANETLS_SELECTOR_CERT: ++ len = i2d_X509(cert, &buf); ++ break; ++ case DANETLS_SELECTOR_SPKI: ++ len = i2d_X509_PUBKEY(X509_get_X509_PUBKEY(cert), &buf); ++ break; ++ default: ++ X509err(X509_F_DANE_I2D, X509_R_BAD_SELECTOR); ++ return NULL; ++ } ++ ++ if (len < 0 || buf == NULL) { ++ X509err(X509_F_DANE_I2D, ERR_R_MALLOC_FAILURE); ++ return NULL; ++ } ++ ++ *i2dlen = (unsigned int)len; ++ return buf; ++} ++ ++#define DANETLS_NONE 256 /* impossible uint8_t */ ++ ++static int dane_match(X509_STORE_CTX *ctx, X509 *cert, int depth) ++{ ++ SSL_DANE *dane = ctx->dane; ++ unsigned usage = DANETLS_NONE; ++ unsigned selector = DANETLS_NONE; ++ unsigned ordinal = DANETLS_NONE; ++ unsigned mtype = DANETLS_NONE; ++ unsigned char *i2dbuf = NULL; ++ unsigned int i2dlen = 0; ++ unsigned char mdbuf[EVP_MAX_MD_SIZE]; ++ unsigned char *cmpbuf = NULL; ++ unsigned int cmplen = 0; ++ int i; ++ int recnum; ++ int matched = 0; ++ danetls_record *t = NULL; ++ uint32_t mask; ++ ++ mask = (depth == 0) ? DANETLS_EE_MASK : DANETLS_TA_MASK; ++ ++ /* ++ * The trust store is not applicable with DANE-TA(2) ++ */ ++ if (depth >= ctx->num_untrusted) ++ mask &= DANETLS_PKIX_MASK; ++ ++ /* ++ * If we've previously matched a PKIX-?? record, no need to test any ++ * further PKIX-?? records, it remains to just build the PKIX chain. ++ * Had the match been a DANE-?? record, we'd be done already. ++ */ ++ if (dane->mdpth >= 0) ++ mask &= ~DANETLS_PKIX_MASK; ++ ++ /*- ++ * https://tools.ietf.org/html/rfc7671#section-5.1 ++ * https://tools.ietf.org/html/rfc7671#section-5.2 ++ * https://tools.ietf.org/html/rfc7671#section-5.3 ++ * https://tools.ietf.org/html/rfc7671#section-5.4 ++ * ++ * We handle DANE-EE(3) records first as they require no chain building ++ * and no expiration or hostname checks. We also process digests with ++ * higher ordinals first and ignore lower priorities except Full(0) which ++ * is always processed (last). If none match, we then process PKIX-EE(1). ++ * ++ * NOTE: This relies on DANE usages sorting before the corresponding PKIX ++ * usages in SSL_dane_tlsa_add(), and also on descending sorting of digest ++ * priorities. See twin comment in ssl/ssl_lib.c. ++ * ++ * We expect that most TLSA RRsets will have just a single usage, so we ++ * don't go out of our way to cache multiple selector-specific i2d buffers ++ * across usages, but if the selector happens to remain the same as switch ++ * usages, that's OK. Thus, a set of "3 1 1", "3 0 1", "1 1 1", "1 0 1", ++ * records would result in us generating each of the certificate and public ++ * key DER forms twice, but more typically we'd just see multiple "3 1 1" ++ * or multiple "3 0 1" records. ++ * ++ * As soon as we find a match at any given depth, we stop, because either ++ * we've matched a DANE-?? record and the peer is authenticated, or, after ++ * exhausting all DANE-?? records, we've matched a PKIX-?? record, which is ++ * sufficient for DANE, and what remains to do is ordinary PKIX validation. ++ */ ++ recnum = (dane->umask & mask) ? sk_danetls_record_num(dane->trecs) : 0; ++ for (i = 0; matched == 0 && i < recnum; ++i) { ++ t = sk_danetls_record_value(dane->trecs, i); ++ if ((DANETLS_USAGE_BIT(t->usage) & mask) == 0) ++ continue; ++ if (t->usage != usage) { ++ usage = t->usage; ++ ++ /* Reset digest agility for each usage/selector pair */ ++ mtype = DANETLS_NONE; ++ ordinal = dane->dctx->mdord[t->mtype]; ++ } ++ if (t->selector != selector) { ++ selector = t->selector; ++ ++ /* Update per-selector state */ ++ OPENSSL_free(i2dbuf); ++ i2dbuf = dane_i2d(cert, selector, &i2dlen); ++ if (i2dbuf == NULL) ++ return -1; ++ ++ /* Reset digest agility for each usage/selector pair */ ++ mtype = DANETLS_NONE; ++ ordinal = dane->dctx->mdord[t->mtype]; ++ } else if (t->mtype != DANETLS_MATCHING_FULL) { ++ /*- ++ * Digest agility: ++ * ++ * ++ * ++ * For a fixed selector, after processing all records with the ++ * highest mtype ordinal, ignore all mtypes with lower ordinals ++ * other than "Full". ++ */ ++ if (dane->dctx->mdord[t->mtype] < ordinal) ++ continue; ++ } ++ ++ /* ++ * Each time we hit a (new selector or) mtype, re-compute the relevant ++ * digest, more complex caching is not worth the code space. ++ */ ++ if (t->mtype != mtype) { ++ const EVP_MD *md = dane->dctx->mdevp[mtype = t->mtype]; ++ cmpbuf = i2dbuf; ++ cmplen = i2dlen; ++ ++ if (md != NULL) { ++ cmpbuf = mdbuf; ++ if (!EVP_Digest(i2dbuf, i2dlen, cmpbuf, &cmplen, md, 0)) { ++ matched = -1; ++ break; ++ } ++ } ++ } ++ ++ /* ++ * Squirrel away the certificate and depth if we have a match. Any ++ * DANE match is dispositive, but with PKIX we still need to build a ++ * full chain. ++ */ ++ if (cmplen == t->dlen && ++ memcmp(cmpbuf, t->data, cmplen) == 0) { ++ if (DANETLS_USAGE_BIT(usage) & DANETLS_DANE_MASK) ++ matched = 1; ++ if (matched || dane->mdpth < 0) { ++ dane->mdpth = depth; ++ dane->mtlsa = t; ++ OPENSSL_free(dane->mcert); ++ dane->mcert = cert; ++ X509_up_ref(cert); ++ } ++ break; ++ } ++ } ++ ++ /* Clear the one-element DER cache */ ++ OPENSSL_free(i2dbuf); ++ return matched; ++} ++ ++static int check_dane_issuer(X509_STORE_CTX *ctx, int depth) ++{ ++ SSL_DANE *dane = ctx->dane; ++ int matched = 0; ++ X509 *cert; ++ ++ if (!DANETLS_HAS_TA(dane) || depth == 0) ++ return X509_TRUST_UNTRUSTED; ++ ++ /* ++ * Record any DANE trust-anchor matches, for the first depth to test, if ++ * there's one at that depth. (This'll be false for length 1 chains looking ++ * for an exact match for the leaf certificate). ++ */ ++ cert = sk_X509_value(ctx->chain, depth); ++ if (cert != NULL && (matched = dane_match(ctx, cert, depth)) < 0) ++ return X509_TRUST_REJECTED; ++ if (matched > 0) { ++ ctx->num_untrusted = depth - 1; ++ return X509_TRUST_TRUSTED; ++ } ++ ++ return X509_TRUST_UNTRUSTED; ++} ++ ++static int check_dane_pkeys(X509_STORE_CTX *ctx) ++{ ++ SSL_DANE *dane = ctx->dane; ++ danetls_record *t; ++ int num = ctx->num_untrusted; ++ X509 *cert = sk_X509_value(ctx->chain, num - 1); ++ int recnum = sk_danetls_record_num(dane->trecs); ++ int i; ++ ++ for (i = 0; i < recnum; ++i) { ++ t = sk_danetls_record_value(dane->trecs, i); ++ if (t->usage != DANETLS_USAGE_DANE_TA || ++ t->selector != DANETLS_SELECTOR_SPKI || ++ t->mtype != DANETLS_MATCHING_FULL || ++ X509_verify(cert, t->spki) <= 0) ++ continue; ++ ++ /* Clear any PKIX-?? matches that failed to extend to a full chain */ ++ X509_free(dane->mcert); ++ dane->mcert = NULL; ++ ++ /* Record match via a bare TA public key */ ++ ctx->bare_ta_signed = 1; ++ dane->mdpth = num - 1; ++ dane->mtlsa = t; ++ ++ /* Prune any excess chain certificates */ ++ num = sk_X509_num(ctx->chain); ++ for (; num > ctx->num_untrusted; --num) ++ X509_free(sk_X509_pop(ctx->chain)); ++ ++ return X509_TRUST_TRUSTED; ++ } ++ ++ return X509_TRUST_UNTRUSTED; ++} ++ ++static void dane_reset(SSL_DANE *dane) ++{ ++ /* ++ * Reset state to verify another chain, or clear after failure. ++ */ ++ X509_free(dane->mcert); ++ dane->mcert = NULL; ++ dane->mtlsa = NULL; ++ dane->mdpth = -1; ++ dane->pdpth = -1; ++} ++ ++static int check_leaf_suiteb(X509_STORE_CTX *ctx, X509 *cert) ++{ ++ int err = X509_chain_check_suiteb(NULL, cert, NULL, ctx->param->flags); ++ ++ if (err == X509_V_OK) ++ return 1; ++ return verify_cb_cert(ctx, cert, 0, err); ++} ++ ++static int dane_verify(X509_STORE_CTX *ctx) ++{ ++ X509 *cert = ctx->cert; ++ SSL_DANE *dane = ctx->dane; ++ int matched; ++ int done; ++ ++ dane_reset(dane); ++ ++ /*- ++ * When testing the leaf certificate, if we match a DANE-EE(3) record, ++ * dane_match() returns 1 and we're done. If however we match a PKIX-EE(1) ++ * record, the match depth and matching TLSA record are recorded, but the ++ * return value is 0, because we still need to find a PKIX trust-anchor. ++ * Therefore, when DANE authentication is enabled (required), we're done ++ * if: ++ * + matched < 0, internal error. ++ * + matched == 1, we matched a DANE-EE(3) record ++ * + matched == 0, mdepth < 0 (no PKIX-EE match) and there are no ++ * DANE-TA(2) or PKIX-TA(0) to test. ++ */ ++ matched = dane_match(ctx, ctx->cert, 0); ++ done = matched != 0 || (!DANETLS_HAS_TA(dane) && dane->mdpth < 0); ++ ++ if (done) ++ X509_get_pubkey_parameters(NULL, ctx->chain); ++ ++ if (matched > 0) { ++ /* Callback invoked as needed */ ++ if (!check_leaf_suiteb(ctx, cert)) ++ return 0; ++ /* Callback invoked as needed */ ++ if ((dane->flags & DANE_FLAG_NO_DANE_EE_NAMECHECKS) == 0 && ++ !check_id(ctx)) ++ return 0; ++ /* Bypass internal_verify(), issue depth 0 success callback */ ++ ctx->error_depth = 0; ++ ctx->current_cert = cert; ++ return ctx->verify_cb(1, ctx); ++ } ++ ++ if (matched < 0) { ++ ctx->error_depth = 0; ++ ctx->current_cert = cert; ++ ctx->error = X509_V_ERR_OUT_OF_MEM; ++ return -1; ++ } ++ ++ if (done) { ++ /* Fail early, TA-based success is not possible */ ++ if (!check_leaf_suiteb(ctx, cert)) ++ return 0; ++ return verify_cb_cert(ctx, cert, 0, X509_V_ERR_DANE_NO_MATCH); ++ } ++ ++ /* ++ * Chain verification for usages 0/1/2. TLSA record matching of depth > 0 ++ * certificates happens in-line with building the rest of the chain. ++ */ ++ return verify_chain(ctx); ++} ++ ++/* Get issuer, without duplicate suppression */ ++static int get_issuer(X509 **issuer, X509_STORE_CTX *ctx, X509 *cert) ++{ ++ STACK_OF(X509) *saved_chain = ctx->chain; ++ int ok; ++ ++ ctx->chain = NULL; ++ ok = ctx->get_issuer(issuer, ctx, cert); ++ ctx->chain = saved_chain; ++ ++ return ok; ++} ++ ++static int build_chain(X509_STORE_CTX *ctx) ++{ ++ SSL_DANE *dane = ctx->dane; ++ int num = sk_X509_num(ctx->chain); ++ X509 *cert = sk_X509_value(ctx->chain, num - 1); ++ int ss = cert_self_signed(cert); ++ STACK_OF(X509) *sktmp = NULL; ++ unsigned int search; ++ int may_trusted = 0; ++ int may_alternate = 0; ++ int trust = X509_TRUST_UNTRUSTED; ++ int alt_untrusted = 0; ++ int depth; ++ int ok = 0; ++ int i; ++ ++ /* Our chain starts with a single untrusted element. */ ++ OPENSSL_assert(num == 1 && ctx->num_untrusted == num); ++ ++#define S_DOUNTRUSTED (1 << 0) /* Search untrusted chain */ ++#define S_DOTRUSTED (1 << 1) /* Search trusted store */ ++#define S_DOALTERNATE (1 << 2) /* Retry with pruned alternate chain */ ++ /* ++ * Set up search policy, untrusted if possible, trusted-first if enabled. ++ * If we're doing DANE and not doing PKIX-TA/PKIX-EE, we never look in the ++ * trust_store, otherwise we might look there first. If not trusted-first, ++ * and alternate chains are not disabled, try building an alternate chain ++ * if no luck with untrusted first. ++ */ ++ search = (ctx->untrusted != NULL) ? S_DOUNTRUSTED : 0; ++ if (DANETLS_HAS_PKIX(dane) || !DANETLS_HAS_DANE(dane)) { ++ if (search == 0 || ctx->param->flags & X509_V_FLAG_TRUSTED_FIRST) ++ search |= S_DOTRUSTED; ++ else if (!(ctx->param->flags & X509_V_FLAG_NO_ALT_CHAINS)) ++ may_alternate = 1; ++ may_trusted = 1; ++ } ++ ++ /* ++ * Shallow-copy the stack of untrusted certificates (with TLS, this is ++ * typically the content of the peer's certificate message) so can make ++ * multiple passes over it, while free to remove elements as we go. ++ */ ++ if (ctx->untrusted && (sktmp = sk_X509_dup(ctx->untrusted)) == NULL) { ++ X509err(X509_F_BUILD_CHAIN, ERR_R_MALLOC_FAILURE); ++ ctx->error = X509_V_ERR_OUT_OF_MEM; ++ return 0; ++ } ++ ++ /* ++ * If we got any "DANE-TA(2) Cert(0) Full(0)" trust-anchors from DNS, add ++ * them to our working copy of the untrusted certificate stack. Since the ++ * caller of X509_STORE_CTX_init() may have provided only a leaf cert with ++ * no corresponding stack of untrusted certificates, we may need to create ++ * an empty stack first. [ At present only the ssl library provides DANE ++ * support, and ssl_verify_cert_chain() always provides a non-null stack ++ * containing at least the leaf certificate, but we must be prepared for ++ * this to change. ] ++ */ ++ if (DANETLS_ENABLED(dane) && dane->certs != NULL) { ++ if (sktmp == NULL && (sktmp = sk_X509_new_null()) == NULL) { ++ X509err(X509_F_BUILD_CHAIN, ERR_R_MALLOC_FAILURE); ++ ctx->error = X509_V_ERR_OUT_OF_MEM; ++ return 0; ++ } ++ for (i = 0; i < sk_X509_num(dane->certs); ++i) { ++ if (!sk_X509_push(sktmp, sk_X509_value(dane->certs, i))) { ++ sk_X509_free(sktmp); ++ X509err(X509_F_BUILD_CHAIN, ERR_R_MALLOC_FAILURE); ++ ctx->error = X509_V_ERR_OUT_OF_MEM; ++ return 0; ++ } ++ } ++ } ++ ++ /* ++ * Still absurdly large, but arithmetically safe, a lower hard upper bound ++ * might be reasonable. ++ */ ++ if (ctx->param->depth > INT_MAX/2) ++ ctx->param->depth = INT_MAX/2; ++ ++ /* ++ * Try to Extend the chain until we reach an ultimately trusted issuer. ++ * Build chains up to one longer the limit, later fail if we hit the limit, ++ * with an X509_V_ERR_CERT_CHAIN_TOO_LONG error code. ++ */ ++ depth = ctx->param->depth + 1; ++ ++ while (search != 0) { ++ X509 *x; ++ X509 *xtmp = NULL; ++ ++ /* ++ * Look in the trust store if enabled for first lookup, or we've run ++ * out of untrusted issuers and search here is not disabled. When we ++ * reach the depth limit, we stop extending the chain, if by that point ++ * we've not found a trust-anchor, any trusted chain would be too long. ++ * ++ * The error reported to the application verify callback is at the ++ * maximal valid depth with the current certificate equal to the last ++ * not ultimately-trusted issuer. For example, with verify_depth = 0, ++ * the callback will report errors at depth=1 when the immediate issuer ++ * of the leaf certificate is not a trust anchor. No attempt will be ++ * made to locate an issuer for that certificate, since such a chain ++ * would be a-priori too long. ++ */ ++ if ((search & S_DOTRUSTED) != 0) { ++ i = num = sk_X509_num(ctx->chain); ++ if ((search & S_DOALTERNATE) != 0) { ++ /* ++ * As high up the chain as we can, look for an alternative ++ * trusted issuer of an untrusted certificate that currently ++ * has an untrusted issuer. We use the alt_untrusted variable ++ * to track how far up the chain we find the first match. It ++ * is only if and when we find a match, that we prune the chain ++ * and reset ctx->num_untrusted to the reduced count of ++ * untrusted certificates. While we're searching for such a ++ * match (which may never be found), it is neither safe nor ++ * wise to preemptively modify either the chain or ++ * ctx->num_untrusted. ++ * ++ * Note, like ctx->num_untrusted, alt_untrusted is a count of ++ * untrusted certificates, not a "depth". ++ */ ++ i = alt_untrusted; ++ } ++ x = sk_X509_value(ctx->chain, i-1); ++ ++ ok = (depth < num) ? 0 : get_issuer(&xtmp, ctx, x); ++ ++ if (ok < 0) { ++ trust = X509_TRUST_REJECTED; ++ ctx->error = X509_V_ERR_STORE_LOOKUP; ++ search = 0; ++ continue; ++ } ++ ++ if (ok > 0) { ++ /* ++ * Alternative trusted issuer for a mid-chain untrusted cert? ++ * Pop the untrusted cert's successors and retry. We might now ++ * be able to complete a valid chain via the trust store. Note ++ * that despite the current trust-store match we might still ++ * fail complete the chain to a suitable trust-anchor, in which ++ * case we may prune some more untrusted certificates and try ++ * again. Thus the S_DOALTERNATE bit may yet be turned on ++ * again with an even shorter untrusted chain! ++ * ++ * If in the process we threw away our matching PKIX-TA trust ++ * anchor, reset DANE trust. We might find a suitable trusted ++ * certificate among the ones from the trust store. ++ */ ++ if ((search & S_DOALTERNATE) != 0) { ++ OPENSSL_assert(num > i && i > 0 && ss == 0); ++ search &= ~S_DOALTERNATE; ++ for (; num > i; --num) ++ X509_free(sk_X509_pop(ctx->chain)); ++ ctx->num_untrusted = num; ++ ++ if (DANETLS_ENABLED(dane) && ++ dane->mdpth >= ctx->num_untrusted) { ++ dane->mdpth = -1; ++ X509_free(dane->mcert); ++ dane->mcert = NULL; ++ } ++ if (DANETLS_ENABLED(dane) && ++ dane->pdpth >= ctx->num_untrusted) ++ dane->pdpth = -1; ++ } ++ ++ /* ++ * Self-signed untrusted certificates get replaced by their ++ * trusted matching issuer. Otherwise, grow the chain. ++ */ ++ if (ss == 0) { ++ if (!sk_X509_push(ctx->chain, x = xtmp)) { ++ X509_free(xtmp); ++ X509err(X509_F_BUILD_CHAIN, ERR_R_MALLOC_FAILURE); ++ trust = X509_TRUST_REJECTED; ++ ctx->error = X509_V_ERR_OUT_OF_MEM; ++ search = 0; ++ continue; ++ } ++ ss = cert_self_signed(x); ++ } else if (num == ctx->num_untrusted) { ++ /* ++ * We have a self-signed certificate that has the same ++ * subject name (and perhaps keyid and/or serial number) as ++ * a trust-anchor. We must have an exact match to avoid ++ * possible impersonation via key substitution etc. ++ */ ++ if (X509_cmp(x, xtmp) != 0) { ++ /* Self-signed untrusted mimic. */ ++ X509_free(xtmp); ++ ok = 0; ++ } else { ++ X509_free(x); ++ ctx->num_untrusted = --num; ++ (void) sk_X509_set(ctx->chain, num, x = xtmp); ++ } ++ } ++ ++ /* ++ * We've added a new trusted certificate to the chain, recheck ++ * trust. If not done, and not self-signed look deeper. ++ * Whether or not we're doing "trusted first", we no longer ++ * look for untrusted certificates from the peer's chain. ++ * ++ * At this point ctx->num_trusted and num must reflect the ++ * correct number of untrusted certificates, since the DANE ++ * logic in check_trust() depends on distinguishing CAs from ++ * "the wire" from CAs from the trust store. In particular, the ++ * certificate at depth "num" should be the new trusted ++ * certificate with ctx->num_untrusted <= num. ++ */ ++ if (ok) { ++ OPENSSL_assert(ctx->num_untrusted <= num); ++ search &= ~S_DOUNTRUSTED; ++ switch (trust = check_trust(ctx, num)) { ++ case X509_TRUST_TRUSTED: ++ case X509_TRUST_REJECTED: ++ search = 0; ++ continue; ++ } ++ if (ss == 0) ++ continue; ++ } ++ } ++ ++ /* ++ * No dispositive decision, and either self-signed or no match, if ++ * we were doing untrusted-first, and alt-chains are not disabled, ++ * do that, by repeatedly losing one untrusted element at a time, ++ * and trying to extend the shorted chain. ++ */ ++ if ((search & S_DOUNTRUSTED) == 0) { ++ /* Continue search for a trusted issuer of a shorter chain? */ ++ if ((search & S_DOALTERNATE) != 0 && --alt_untrusted > 0) ++ continue; ++ /* Still no luck and no fallbacks left? */ ++ if (!may_alternate || (search & S_DOALTERNATE) != 0 || ++ ctx->num_untrusted < 2) ++ break; ++ /* Search for a trusted issuer of a shorter chain */ ++ search |= S_DOALTERNATE; ++ alt_untrusted = ctx->num_untrusted - 1; ++ ss = 0; ++ } ++ } ++ ++ /* ++ * Extend chain with peer-provided certificates ++ */ ++ if ((search & S_DOUNTRUSTED) != 0) { ++ num = sk_X509_num(ctx->chain); ++ OPENSSL_assert(num == ctx->num_untrusted); ++ x = sk_X509_value(ctx->chain, num-1); ++ ++ /* ++ * Once we run out of untrusted issuers, we stop looking for more ++ * and start looking only in the trust store if enabled. ++ */ ++ xtmp = (ss || depth < num) ? NULL : find_issuer(ctx, sktmp, x); ++ if (xtmp == NULL) { ++ search &= ~S_DOUNTRUSTED; ++ if (may_trusted) ++ search |= S_DOTRUSTED; ++ continue; ++ } ++ ++ /* Drop this issuer from future consideration */ ++ (void) sk_X509_delete_ptr(sktmp, xtmp); ++ ++ if (!sk_X509_push(ctx->chain, xtmp)) { ++ X509err(X509_F_BUILD_CHAIN, ERR_R_MALLOC_FAILURE); ++ trust = X509_TRUST_REJECTED; ++ ctx->error = X509_V_ERR_OUT_OF_MEM; ++ search = 0; ++ continue; ++ } ++ ++ X509_up_ref(x = xtmp); ++ ++ctx->num_untrusted; ++ ss = cert_self_signed(xtmp); ++ ++ /* ++ * Check for DANE-TA trust of the topmost untrusted certificate. ++ */ ++ switch (trust = check_dane_issuer(ctx, ctx->num_untrusted - 1)) { ++ case X509_TRUST_TRUSTED: ++ case X509_TRUST_REJECTED: ++ search = 0; ++ continue; ++ } ++ } ++ } ++ sk_X509_free(sktmp); ++ ++ /* ++ * Last chance to make a trusted chain, either bare DANE-TA public-key ++ * signers, or else direct leaf PKIX trust. ++ */ ++ num = sk_X509_num(ctx->chain); ++ if (num <= depth) { ++ if (trust == X509_TRUST_UNTRUSTED && DANETLS_HAS_DANE_TA(dane)) ++ trust = check_dane_pkeys(ctx); ++ if (trust == X509_TRUST_UNTRUSTED && num == ctx->num_untrusted) ++ trust = check_trust(ctx, num); ++ } ++ ++ switch (trust) { ++ case X509_TRUST_TRUSTED: ++ return 1; ++ case X509_TRUST_REJECTED: ++ /* Callback already issued */ ++ return 0; ++ case X509_TRUST_UNTRUSTED: ++ default: ++ num = sk_X509_num(ctx->chain); ++ if (num > depth) ++ return verify_cb_cert(ctx, NULL, num-1, ++ X509_V_ERR_CERT_CHAIN_TOO_LONG); ++ if (DANETLS_ENABLED(dane) && ++ (!DANETLS_HAS_PKIX(dane) || dane->pdpth >= 0)) ++ return verify_cb_cert(ctx, NULL, num-1, X509_V_ERR_DANE_NO_MATCH); ++ if (ss && sk_X509_num(ctx->chain) == 1) ++ return verify_cb_cert(ctx, NULL, num-1, ++ X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT); ++ if (ss) ++ return verify_cb_cert(ctx, NULL, num-1, ++ X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN); ++ if (ctx->num_untrusted < num) ++ return verify_cb_cert(ctx, NULL, num-1, ++ X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT); ++ return verify_cb_cert(ctx, NULL, num-1, ++ X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY); ++ } ++} ++ ++static const int minbits_table[] = { 80, 112, 128, 192, 256 }; ++static const int NUM_AUTH_LEVELS = OSSL_NELEM(minbits_table); ++ ++/* ++ * Check whether the public key of ``cert`` meets the security level of ++ * ``ctx``. ++ * ++ * Returns 1 on success, 0 otherwise. ++ */ ++static int check_key_level(X509_STORE_CTX *ctx, X509 *cert) ++{ ++ EVP_PKEY *pkey = X509_get0_pubkey(cert); ++ int level = ctx->param->auth_level; ++ ++ /* Unsupported or malformed keys are not secure */ ++ if (pkey == NULL) ++ return 0; ++ ++ if (level <= 0) ++ return 1; ++ if (level > NUM_AUTH_LEVELS) ++ level = NUM_AUTH_LEVELS; ++ ++ return EVP_PKEY_security_bits(pkey) >= minbits_table[level - 1]; ++} ++ ++/* ++ * Check whether the signature digest algorithm of ``cert`` meets the security ++ * level of ``ctx``. Should not be checked for trust anchors (whether ++ * self-signed or otherwise). ++ * ++ * Returns 1 on success, 0 otherwise. ++ */ ++static int check_sig_level(X509_STORE_CTX *ctx, X509 *cert) ++{ ++ int nid = X509_get_signature_nid(cert); ++ int mdnid = NID_undef; ++ int secbits = -1; ++ int level = ctx->param->auth_level; ++ ++ if (level <= 0) ++ return 1; ++ if (level > NUM_AUTH_LEVELS) ++ level = NUM_AUTH_LEVELS; ++ ++ /* Lookup signature algorithm digest */ ++ if (nid && OBJ_find_sigid_algs(nid, &mdnid, NULL)) { ++ const EVP_MD *md; ++ ++ /* Assume 4 bits of collision resistance for each hash octet */ ++ if (mdnid != NID_undef && (md = EVP_get_digestbynid(mdnid)) != NULL) ++ secbits = EVP_MD_size(md) * 4; ++ } ++ ++ return secbits >= minbits_table[level - 1]; ++} +diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/x509/x509_vpm.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/x509/x509_vpm.c +new file mode 100644 +index 0000000..b506722 +--- /dev/null ++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/x509/x509_vpm.c +@@ -0,0 +1,617 @@ ++/* ++ * Copyright 2004-2016 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 ++ * in the file LICENSE in the source distribution or at ++ * https://www.openssl.org/source/license.html ++ */ ++ ++#include ++ ++#include "internal/cryptlib.h" ++#include ++#include ++#include ++#include ++#include ++#include "internal/x509_int.h" ++ ++#include "x509_lcl.h" ++ ++/* X509_VERIFY_PARAM functions */ ++ ++#define SET_HOST 0 ++#define ADD_HOST 1 ++ ++static char *str_copy(const char *s) ++{ ++ return OPENSSL_strdup(s); ++} ++ ++static void str_free(char *s) ++{ ++ OPENSSL_free(s); ++} ++ ++static int int_x509_param_set_hosts(X509_VERIFY_PARAM *vpm, int mode, ++ const char *name, size_t namelen) ++{ ++ char *copy; ++ ++ /* ++ * Refuse names with embedded NUL bytes, except perhaps as final byte. ++ * XXX: Do we need to push an error onto the error stack? ++ */ ++ if (namelen == 0 || name == NULL) ++ namelen = name ? strlen(name) : 0; ++ else if (name && memchr(name, '\0', namelen > 1 ? namelen - 1 : namelen)) ++ return 0; ++ if (namelen > 0 && name[namelen - 1] == '\0') ++ --namelen; ++ ++ if (mode == SET_HOST) { ++ sk_OPENSSL_STRING_pop_free(vpm->hosts, str_free); ++ vpm->hosts = NULL; ++ } ++ if (name == NULL || namelen == 0) ++ return 1; ++ ++ copy = OPENSSL_strndup(name, namelen); ++ if (copy == NULL) ++ return 0; ++ ++ if (vpm->hosts == NULL && ++ (vpm->hosts = sk_OPENSSL_STRING_new_null()) == NULL) { ++ OPENSSL_free(copy); ++ return 0; ++ } ++ ++ if (!sk_OPENSSL_STRING_push(vpm->hosts, copy)) { ++ OPENSSL_free(copy); ++ if (sk_OPENSSL_STRING_num(vpm->hosts) == 0) { ++ sk_OPENSSL_STRING_free(vpm->hosts); ++ vpm->hosts = NULL; ++ } ++ return 0; ++ } ++ ++ return 1; ++} ++ ++static void x509_verify_param_zero(X509_VERIFY_PARAM *param) ++{ ++ if (!param) ++ return; ++ param->name = NULL; ++ param->purpose = 0; ++ param->trust = X509_TRUST_DEFAULT; ++ /* ++ * param->inh_flags = X509_VP_FLAG_DEFAULT; ++ */ ++ param->inh_flags = 0; ++ param->flags = 0; ++ param->depth = -1; ++ param->auth_level = -1; /* -1 means unset, 0 is explicit */ ++ sk_ASN1_OBJECT_pop_free(param->policies, ASN1_OBJECT_free); ++ param->policies = NULL; ++ sk_OPENSSL_STRING_pop_free(param->hosts, str_free); ++ param->hosts = NULL; ++ OPENSSL_free(param->peername); ++ param->peername = NULL; ++ OPENSSL_free(param->email); ++ param->email = NULL; ++ param->emaillen = 0; ++ OPENSSL_free(param->ip); ++ param->ip = NULL; ++ param->iplen = 0; ++} ++ ++X509_VERIFY_PARAM *X509_VERIFY_PARAM_new(void) ++{ ++ X509_VERIFY_PARAM *param; ++ ++ param = OPENSSL_zalloc(sizeof(*param)); ++ if (param == NULL) ++ return NULL; ++ x509_verify_param_zero(param); ++ return param; ++} ++ ++void X509_VERIFY_PARAM_free(X509_VERIFY_PARAM *param) ++{ ++ if (!param) ++ return; ++ x509_verify_param_zero(param); ++ OPENSSL_free(param); ++} ++ ++/*- ++ * This function determines how parameters are "inherited" from one structure ++ * to another. There are several different ways this can happen. ++ * ++ * 1. If a child structure needs to have its values initialized from a parent ++ * they are simply copied across. For example SSL_CTX copied to SSL. ++ * 2. If the structure should take on values only if they are currently unset. ++ * For example the values in an SSL structure will take appropriate value ++ * for SSL servers or clients but only if the application has not set new ++ * ones. ++ * ++ * The "inh_flags" field determines how this function behaves. ++ * ++ * Normally any values which are set in the default are not copied from the ++ * destination and verify flags are ORed together. ++ * ++ * If X509_VP_FLAG_DEFAULT is set then anything set in the source is copied ++ * to the destination. Effectively the values in "to" become default values ++ * which will be used only if nothing new is set in "from". ++ * ++ * If X509_VP_FLAG_OVERWRITE is set then all value are copied across whether ++ * they are set or not. Flags is still Ored though. ++ * ++ * If X509_VP_FLAG_RESET_FLAGS is set then the flags value is copied instead ++ * of ORed. ++ * ++ * If X509_VP_FLAG_LOCKED is set then no values are copied. ++ * ++ * If X509_VP_FLAG_ONCE is set then the current inh_flags setting is zeroed ++ * after the next call. ++ */ ++ ++/* Macro to test if a field should be copied from src to dest */ ++ ++#define test_x509_verify_param_copy(field, def) \ ++ (to_overwrite || \ ++ ((src->field != def) && (to_default || (dest->field == def)))) ++ ++/* Macro to test and copy a field if necessary */ ++ ++#define x509_verify_param_copy(field, def) \ ++ if (test_x509_verify_param_copy(field, def)) \ ++ dest->field = src->field ++ ++int X509_VERIFY_PARAM_inherit(X509_VERIFY_PARAM *dest, ++ const X509_VERIFY_PARAM *src) ++{ ++ unsigned long inh_flags; ++ int to_default, to_overwrite; ++ if (!src) ++ return 1; ++ inh_flags = dest->inh_flags | src->inh_flags; ++ ++ if (inh_flags & X509_VP_FLAG_ONCE) ++ dest->inh_flags = 0; ++ ++ if (inh_flags & X509_VP_FLAG_LOCKED) ++ return 1; ++ ++ if (inh_flags & X509_VP_FLAG_DEFAULT) ++ to_default = 1; ++ else ++ to_default = 0; ++ ++ if (inh_flags & X509_VP_FLAG_OVERWRITE) ++ to_overwrite = 1; ++ else ++ to_overwrite = 0; ++ ++ x509_verify_param_copy(purpose, 0); ++ x509_verify_param_copy(trust, X509_TRUST_DEFAULT); ++ x509_verify_param_copy(depth, -1); ++ x509_verify_param_copy(auth_level, -1); ++ ++ /* If overwrite or check time not set, copy across */ ++ ++ if (to_overwrite || !(dest->flags & X509_V_FLAG_USE_CHECK_TIME)) { ++ dest->check_time = src->check_time; ++ dest->flags &= ~X509_V_FLAG_USE_CHECK_TIME; ++ /* Don't need to copy flag: that is done below */ ++ } ++ ++ if (inh_flags & X509_VP_FLAG_RESET_FLAGS) ++ dest->flags = 0; ++ ++ dest->flags |= src->flags; ++ ++ if (test_x509_verify_param_copy(policies, NULL)) { ++ if (!X509_VERIFY_PARAM_set1_policies(dest, src->policies)) ++ return 0; ++ } ++ ++ /* Copy the host flags if and only if we're copying the host list */ ++ if (test_x509_verify_param_copy(hosts, NULL)) { ++ sk_OPENSSL_STRING_pop_free(dest->hosts, str_free); ++ dest->hosts = NULL; ++ if (src->hosts) { ++ dest->hosts = ++ sk_OPENSSL_STRING_deep_copy(src->hosts, str_copy, str_free); ++ if (dest->hosts == NULL) ++ return 0; ++ dest->hostflags = src->hostflags; ++ } ++ } ++ ++ if (test_x509_verify_param_copy(email, NULL)) { ++ if (!X509_VERIFY_PARAM_set1_email(dest, src->email, src->emaillen)) ++ return 0; ++ } ++ ++ if (test_x509_verify_param_copy(ip, NULL)) { ++ if (!X509_VERIFY_PARAM_set1_ip(dest, src->ip, src->iplen)) ++ return 0; ++ } ++ ++ return 1; ++} ++ ++int X509_VERIFY_PARAM_set1(X509_VERIFY_PARAM *to, ++ const X509_VERIFY_PARAM *from) ++{ ++ unsigned long save_flags = to->inh_flags; ++ int ret; ++ to->inh_flags |= X509_VP_FLAG_DEFAULT; ++ ret = X509_VERIFY_PARAM_inherit(to, from); ++ to->inh_flags = save_flags; ++ return ret; ++} ++ ++static int int_x509_param_set1(char **pdest, size_t *pdestlen, ++ const char *src, size_t srclen) ++{ ++ void *tmp; ++ if (src) { ++ if (srclen == 0) ++ srclen = strlen(src); ++ ++ tmp = OPENSSL_memdup(src, srclen); ++ if (tmp == NULL) ++ return 0; ++ } else { ++ tmp = NULL; ++ srclen = 0; ++ } ++ OPENSSL_free(*pdest); ++ *pdest = tmp; ++ if (pdestlen != NULL) ++ *pdestlen = srclen; ++ return 1; ++} ++ ++int X509_VERIFY_PARAM_set1_name(X509_VERIFY_PARAM *param, const char *name) ++{ ++ OPENSSL_free(param->name); ++ param->name = OPENSSL_strdup(name); ++ if (param->name) ++ return 1; ++ return 0; ++} ++ ++int X509_VERIFY_PARAM_set_flags(X509_VERIFY_PARAM *param, unsigned long flags) ++{ ++ param->flags |= flags; ++ if (flags & X509_V_FLAG_POLICY_MASK) ++ param->flags |= X509_V_FLAG_POLICY_CHECK; ++ return 1; ++} ++ ++int X509_VERIFY_PARAM_clear_flags(X509_VERIFY_PARAM *param, ++ unsigned long flags) ++{ ++ param->flags &= ~flags; ++ return 1; ++} ++ ++unsigned long X509_VERIFY_PARAM_get_flags(X509_VERIFY_PARAM *param) ++{ ++ return param->flags; ++} ++ ++uint32_t X509_VERIFY_PARAM_get_inh_flags(const X509_VERIFY_PARAM *param) ++{ ++ return param->inh_flags; ++} ++ ++int X509_VERIFY_PARAM_set_inh_flags(X509_VERIFY_PARAM *param, uint32_t flags) ++{ ++ param->inh_flags = flags; ++ return 1; ++} ++ ++int X509_VERIFY_PARAM_set_purpose(X509_VERIFY_PARAM *param, int purpose) ++{ ++ return X509_PURPOSE_set(¶m->purpose, purpose); ++} ++ ++int X509_VERIFY_PARAM_set_trust(X509_VERIFY_PARAM *param, int trust) ++{ ++ return X509_TRUST_set(¶m->trust, trust); ++} ++ ++void X509_VERIFY_PARAM_set_depth(X509_VERIFY_PARAM *param, int depth) ++{ ++ param->depth = depth; ++} ++ ++void X509_VERIFY_PARAM_set_auth_level(X509_VERIFY_PARAM *param, int auth_level) ++{ ++ param->auth_level = auth_level; ++} ++ ++time_t X509_VERIFY_PARAM_get_time(const X509_VERIFY_PARAM *param) ++{ ++ return param->check_time; ++} ++ ++void X509_VERIFY_PARAM_set_time(X509_VERIFY_PARAM *param, time_t t) ++{ ++ param->check_time = t; ++ param->flags |= X509_V_FLAG_USE_CHECK_TIME; ++} ++ ++int X509_VERIFY_PARAM_add0_policy(X509_VERIFY_PARAM *param, ++ ASN1_OBJECT *policy) ++{ ++ if (!param->policies) { ++ param->policies = sk_ASN1_OBJECT_new_null(); ++ if (!param->policies) ++ return 0; ++ } ++ if (!sk_ASN1_OBJECT_push(param->policies, policy)) ++ return 0; ++ return 1; ++} ++ ++int X509_VERIFY_PARAM_set1_policies(X509_VERIFY_PARAM *param, ++ STACK_OF(ASN1_OBJECT) *policies) ++{ ++ int i; ++ ASN1_OBJECT *oid, *doid; ++ ++ if (!param) ++ return 0; ++ sk_ASN1_OBJECT_pop_free(param->policies, ASN1_OBJECT_free); ++ ++ if (!policies) { ++ param->policies = NULL; ++ return 1; ++ } ++ ++ param->policies = sk_ASN1_OBJECT_new_null(); ++ if (!param->policies) ++ return 0; ++ ++ for (i = 0; i < sk_ASN1_OBJECT_num(policies); i++) { ++ oid = sk_ASN1_OBJECT_value(policies, i); ++ doid = OBJ_dup(oid); ++ if (!doid) ++ return 0; ++ if (!sk_ASN1_OBJECT_push(param->policies, doid)) { ++ ASN1_OBJECT_free(doid); ++ return 0; ++ } ++ } ++ param->flags |= X509_V_FLAG_POLICY_CHECK; ++ return 1; ++} ++ ++int X509_VERIFY_PARAM_set1_host(X509_VERIFY_PARAM *param, ++ const char *name, size_t namelen) ++{ ++ return int_x509_param_set_hosts(param, SET_HOST, name, namelen); ++} ++ ++int X509_VERIFY_PARAM_add1_host(X509_VERIFY_PARAM *param, ++ const char *name, size_t namelen) ++{ ++ return int_x509_param_set_hosts(param, ADD_HOST, name, namelen); ++} ++ ++void X509_VERIFY_PARAM_set_hostflags(X509_VERIFY_PARAM *param, ++ unsigned int flags) ++{ ++ param->hostflags = flags; ++} ++ ++char *X509_VERIFY_PARAM_get0_peername(X509_VERIFY_PARAM *param) ++{ ++ return param->peername; ++} ++ ++/* ++ * Move peername from one param structure to another, freeing any name present ++ * at the target. If the source is a NULL parameter structure, free and zero ++ * the target peername. ++ */ ++void X509_VERIFY_PARAM_move_peername(X509_VERIFY_PARAM *to, ++ X509_VERIFY_PARAM *from) ++{ ++ char *peername = (from != NULL) ? from->peername : NULL; ++ ++ if (to->peername != peername) { ++ OPENSSL_free(to->peername); ++ to->peername = peername; ++ } ++ if (from) ++ from->peername = NULL; ++} ++ ++int X509_VERIFY_PARAM_set1_email(X509_VERIFY_PARAM *param, ++ const char *email, size_t emaillen) ++{ ++ return int_x509_param_set1(¶m->email, ¶m->emaillen, ++ email, emaillen); ++} ++ ++int X509_VERIFY_PARAM_set1_ip(X509_VERIFY_PARAM *param, ++ const unsigned char *ip, size_t iplen) ++{ ++ if (iplen != 0 && iplen != 4 && iplen != 16) ++ return 0; ++ return int_x509_param_set1((char **)¶m->ip, ¶m->iplen, ++ (char *)ip, iplen); ++} ++ ++int X509_VERIFY_PARAM_set1_ip_asc(X509_VERIFY_PARAM *param, const char *ipasc) ++{ ++ unsigned char ipout[16]; ++ size_t iplen; ++ ++ iplen = (size_t)a2i_ipadd(ipout, ipasc); ++ if (iplen == 0) ++ return 0; ++ return X509_VERIFY_PARAM_set1_ip(param, ipout, iplen); ++} ++ ++int X509_VERIFY_PARAM_get_depth(const X509_VERIFY_PARAM *param) ++{ ++ return param->depth; ++} ++ ++int X509_VERIFY_PARAM_get_auth_level(const X509_VERIFY_PARAM *param) ++{ ++ return param->auth_level; ++} ++ ++const char *X509_VERIFY_PARAM_get0_name(const X509_VERIFY_PARAM *param) ++{ ++ return param->name; ++} ++ ++#define vpm_empty_id NULL, 0U, NULL, NULL, 0, NULL, 0 ++ ++/* ++ * Default verify parameters: these are used for various applications and can ++ * be overridden by the user specified table. NB: the 'name' field *must* be ++ * in alphabetical order because it will be searched using OBJ_search. ++ */ ++ ++static const X509_VERIFY_PARAM default_table[] = { ++ { ++ "default", /* X509 default parameters */ ++ 0, /* Check time */ ++ 0, /* internal flags */ ++ X509_V_FLAG_TRUSTED_FIRST, /* flags */ ++ 0, /* purpose */ ++ 0, /* trust */ ++ 100, /* depth */ ++ -1, /* auth_level */ ++ NULL, /* policies */ ++ vpm_empty_id}, ++ { ++ "pkcs7", /* S/MIME sign parameters */ ++ 0, /* Check time */ ++ 0, /* internal flags */ ++ 0, /* flags */ ++ X509_PURPOSE_SMIME_SIGN, /* purpose */ ++ X509_TRUST_EMAIL, /* trust */ ++ -1, /* depth */ ++ -1, /* auth_level */ ++ NULL, /* policies */ ++ vpm_empty_id}, ++ { ++ "smime_sign", /* S/MIME sign parameters */ ++ 0, /* Check time */ ++ 0, /* internal flags */ ++ 0, /* flags */ ++ X509_PURPOSE_SMIME_SIGN, /* purpose */ ++ X509_TRUST_EMAIL, /* trust */ ++ -1, /* depth */ ++ -1, /* auth_level */ ++ NULL, /* policies */ ++ vpm_empty_id}, ++ { ++ "ssl_client", /* SSL/TLS client parameters */ ++ 0, /* Check time */ ++ 0, /* internal flags */ ++ 0, /* flags */ ++ X509_PURPOSE_SSL_CLIENT, /* purpose */ ++ X509_TRUST_SSL_CLIENT, /* trust */ ++ -1, /* depth */ ++ -1, /* auth_level */ ++ NULL, /* policies */ ++ vpm_empty_id}, ++ { ++ "ssl_server", /* SSL/TLS server parameters */ ++ 0, /* Check time */ ++ 0, /* internal flags */ ++ 0, /* flags */ ++ X509_PURPOSE_SSL_SERVER, /* purpose */ ++ X509_TRUST_SSL_SERVER, /* trust */ ++ -1, /* depth */ ++ -1, /* auth_level */ ++ NULL, /* policies */ ++ vpm_empty_id} ++}; ++ ++static STACK_OF(X509_VERIFY_PARAM) *param_table = NULL; ++ ++static int table_cmp(const X509_VERIFY_PARAM *a, const X509_VERIFY_PARAM *b) ++{ ++ return strcmp(a->name, b->name); ++} ++ ++DECLARE_OBJ_BSEARCH_CMP_FN(X509_VERIFY_PARAM, X509_VERIFY_PARAM, table); ++IMPLEMENT_OBJ_BSEARCH_CMP_FN(X509_VERIFY_PARAM, X509_VERIFY_PARAM, table); ++ ++static int param_cmp(const X509_VERIFY_PARAM *const *a, ++ const X509_VERIFY_PARAM *const *b) ++{ ++ return strcmp((*a)->name, (*b)->name); ++} ++ ++int X509_VERIFY_PARAM_add0_table(X509_VERIFY_PARAM *param) ++{ ++ int idx; ++ X509_VERIFY_PARAM *ptmp; ++ if (param_table == NULL) { ++ param_table = sk_X509_VERIFY_PARAM_new(param_cmp); ++ if (param_table == NULL) ++ return 0; ++ } else { ++ idx = sk_X509_VERIFY_PARAM_find(param_table, param); ++ if (idx != -1) { ++ ptmp = sk_X509_VERIFY_PARAM_value(param_table, idx); ++ X509_VERIFY_PARAM_free(ptmp); ++ (void)sk_X509_VERIFY_PARAM_delete(param_table, idx); ++ } ++ } ++ if (!sk_X509_VERIFY_PARAM_push(param_table, param)) ++ return 0; ++ return 1; ++} ++ ++int X509_VERIFY_PARAM_get_count(void) ++{ ++ int num = OSSL_NELEM(default_table); ++ if (param_table) ++ num += sk_X509_VERIFY_PARAM_num(param_table); ++ return num; ++} ++ ++const X509_VERIFY_PARAM *X509_VERIFY_PARAM_get0(int id) ++{ ++ int num = OSSL_NELEM(default_table); ++ if (id < num) ++ return default_table + id; ++ return sk_X509_VERIFY_PARAM_value(param_table, id - num); ++} ++ ++const X509_VERIFY_PARAM *X509_VERIFY_PARAM_lookup(const char *name) ++{ ++ int idx; ++ X509_VERIFY_PARAM pm; ++ ++ pm.name = (char *)name; ++ if (param_table) { ++ idx = sk_X509_VERIFY_PARAM_find(param_table, &pm); ++ if (idx != -1) ++ return sk_X509_VERIFY_PARAM_value(param_table, idx); ++ } ++ return OBJ_bsearch_table(&pm, default_table, OSSL_NELEM(default_table)); ++} ++ ++void X509_VERIFY_PARAM_table_cleanup(void) ++{ ++ sk_X509_VERIFY_PARAM_pop_free(param_table, X509_VERIFY_PARAM_free); ++ param_table = NULL; ++} +diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/x509/x509cset.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/x509/x509cset.c +new file mode 100644 +index 0000000..2057859 +--- /dev/null ++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/x509/x509cset.c +@@ -0,0 +1,182 @@ ++/* ++ * Copyright 2001-2016 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 ++ * in the file LICENSE in the source distribution or at ++ * https://www.openssl.org/source/license.html ++ */ ++ ++#include ++#include "internal/cryptlib.h" ++#include ++#include ++#include ++#include ++#include "internal/x509_int.h" ++ ++int X509_CRL_set_version(X509_CRL *x, long version) ++{ ++ if (x == NULL) ++ return (0); ++ if (x->crl.version == NULL) { ++ if ((x->crl.version = ASN1_INTEGER_new()) == NULL) ++ return (0); ++ } ++ return (ASN1_INTEGER_set(x->crl.version, version)); ++} ++ ++int X509_CRL_set_issuer_name(X509_CRL *x, X509_NAME *name) ++{ ++ if (x == NULL) ++ return (0); ++ return (X509_NAME_set(&x->crl.issuer, name)); ++} ++ ++int X509_CRL_set1_lastUpdate(X509_CRL *x, const ASN1_TIME *tm) ++{ ++ if (x == NULL) ++ return 0; ++ return x509_set1_time(&x->crl.lastUpdate, tm); ++} ++ ++int X509_CRL_set1_nextUpdate(X509_CRL *x, const ASN1_TIME *tm) ++{ ++ if (x == NULL) ++ return 0; ++ return x509_set1_time(&x->crl.nextUpdate, tm); ++} ++ ++int X509_CRL_sort(X509_CRL *c) ++{ ++ int i; ++ X509_REVOKED *r; ++ /* ++ * sort the data so it will be written in serial number order ++ */ ++ sk_X509_REVOKED_sort(c->crl.revoked); ++ for (i = 0; i < sk_X509_REVOKED_num(c->crl.revoked); i++) { ++ r = sk_X509_REVOKED_value(c->crl.revoked, i); ++ r->sequence = i; ++ } ++ c->crl.enc.modified = 1; ++ return 1; ++} ++ ++int X509_CRL_up_ref(X509_CRL *crl) ++{ ++ int i; ++ ++ if (CRYPTO_atomic_add(&crl->references, 1, &i, crl->lock) <= 0) ++ return 0; ++ ++ REF_PRINT_COUNT("X509_CRL", crl); ++ REF_ASSERT_ISNT(i < 2); ++ return ((i > 1) ? 1 : 0); ++} ++ ++long X509_CRL_get_version(const X509_CRL *crl) ++{ ++ return ASN1_INTEGER_get(crl->crl.version); ++} ++ ++const ASN1_TIME *X509_CRL_get0_lastUpdate(const X509_CRL *crl) ++{ ++ return crl->crl.lastUpdate; ++} ++ ++const ASN1_TIME *X509_CRL_get0_nextUpdate(const X509_CRL *crl) ++{ ++ return crl->crl.nextUpdate; ++} ++ ++#if OPENSSL_API_COMPAT < 0x10100000L ++ASN1_TIME *X509_CRL_get_lastUpdate(X509_CRL *crl) ++{ ++ return crl->crl.lastUpdate; ++} ++ ++ASN1_TIME *X509_CRL_get_nextUpdate(X509_CRL *crl) ++{ ++ return crl->crl.nextUpdate; ++} ++#endif ++ ++X509_NAME *X509_CRL_get_issuer(const X509_CRL *crl) ++{ ++ return crl->crl.issuer; ++} ++ ++const STACK_OF(X509_EXTENSION) *X509_CRL_get0_extensions(const X509_CRL *crl) ++{ ++ return crl->crl.extensions; ++} ++ ++STACK_OF(X509_REVOKED) *X509_CRL_get_REVOKED(X509_CRL *crl) ++{ ++ return crl->crl.revoked; ++} ++ ++void X509_CRL_get0_signature(const X509_CRL *crl, const ASN1_BIT_STRING **psig, ++ const X509_ALGOR **palg) ++{ ++ if (psig != NULL) ++ *psig = &crl->signature; ++ if (palg != NULL) ++ *palg = &crl->sig_alg; ++} ++ ++int X509_CRL_get_signature_nid(const X509_CRL *crl) ++{ ++ return OBJ_obj2nid(crl->sig_alg.algorithm); ++} ++ ++const ASN1_TIME *X509_REVOKED_get0_revocationDate(const X509_REVOKED *x) ++{ ++ return x->revocationDate; ++} ++ ++int X509_REVOKED_set_revocationDate(X509_REVOKED *x, ASN1_TIME *tm) ++{ ++ ASN1_TIME *in; ++ ++ if (x == NULL) ++ return (0); ++ in = x->revocationDate; ++ if (in != tm) { ++ in = ASN1_STRING_dup(tm); ++ if (in != NULL) { ++ ASN1_TIME_free(x->revocationDate); ++ x->revocationDate = in; ++ } ++ } ++ return (in != NULL); ++} ++ ++const ASN1_INTEGER *X509_REVOKED_get0_serialNumber(const X509_REVOKED *x) ++{ ++ return &x->serialNumber; ++} ++ ++int X509_REVOKED_set_serialNumber(X509_REVOKED *x, ASN1_INTEGER *serial) ++{ ++ ASN1_INTEGER *in; ++ ++ if (x == NULL) ++ return (0); ++ in = &x->serialNumber; ++ if (in != serial) ++ return ASN1_STRING_copy(in, serial); ++ return 1; ++} ++ ++const STACK_OF(X509_EXTENSION) *X509_REVOKED_get0_extensions(const X509_REVOKED *r) ++{ ++ return r->extensions; ++} ++ ++int i2d_re_X509_CRL_tbs(X509_CRL *crl, unsigned char **pp) ++{ ++ crl->crl.enc.modified = 1; ++ return i2d_X509_CRL_INFO(&crl->crl, pp); ++} +diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/x509/x509name.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/x509/x509name.c +new file mode 100644 +index 0000000..919d8c1 +--- /dev/null ++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/x509/x509name.c +@@ -0,0 +1,358 @@ ++/* ++ * Copyright 1995-2016 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 ++ * in the file LICENSE in the source distribution or at ++ * https://www.openssl.org/source/license.html ++ */ ++ ++#include ++#include ++#include "internal/cryptlib.h" ++#include ++#include ++#include ++#include ++#include "internal/x509_int.h" ++ ++int X509_NAME_get_text_by_NID(X509_NAME *name, int nid, char *buf, int len) ++{ ++ ASN1_OBJECT *obj; ++ ++ obj = OBJ_nid2obj(nid); ++ if (obj == NULL) ++ return (-1); ++ return (X509_NAME_get_text_by_OBJ(name, obj, buf, len)); ++} ++ ++int X509_NAME_get_text_by_OBJ(X509_NAME *name, const ASN1_OBJECT *obj, char *buf, ++ int len) ++{ ++ int i; ++ const ASN1_STRING *data; ++ ++ i = X509_NAME_get_index_by_OBJ(name, obj, -1); ++ if (i < 0) ++ return (-1); ++ data = X509_NAME_ENTRY_get_data(X509_NAME_get_entry(name, i)); ++ i = (data->length > (len - 1)) ? (len - 1) : data->length; ++ if (buf == NULL) ++ return (data->length); ++ memcpy(buf, data->data, i); ++ buf[i] = '\0'; ++ return (i); ++} ++ ++int X509_NAME_entry_count(const X509_NAME *name) ++{ ++ if (name == NULL) ++ return (0); ++ return (sk_X509_NAME_ENTRY_num(name->entries)); ++} ++ ++int X509_NAME_get_index_by_NID(X509_NAME *name, int nid, int lastpos) ++{ ++ ASN1_OBJECT *obj; ++ ++ obj = OBJ_nid2obj(nid); ++ if (obj == NULL) ++ return (-2); ++ return (X509_NAME_get_index_by_OBJ(name, obj, lastpos)); ++} ++ ++/* NOTE: you should be passing -1, not 0 as lastpos */ ++int X509_NAME_get_index_by_OBJ(X509_NAME *name, const ASN1_OBJECT *obj, int lastpos) ++{ ++ int n; ++ X509_NAME_ENTRY *ne; ++ STACK_OF(X509_NAME_ENTRY) *sk; ++ ++ if (name == NULL) ++ return (-1); ++ if (lastpos < 0) ++ lastpos = -1; ++ sk = name->entries; ++ n = sk_X509_NAME_ENTRY_num(sk); ++ for (lastpos++; lastpos < n; lastpos++) { ++ ne = sk_X509_NAME_ENTRY_value(sk, lastpos); ++ if (OBJ_cmp(ne->object, obj) == 0) ++ return (lastpos); ++ } ++ return (-1); ++} ++ ++X509_NAME_ENTRY *X509_NAME_get_entry(const X509_NAME *name, int loc) ++{ ++ if (name == NULL || sk_X509_NAME_ENTRY_num(name->entries) <= loc ++ || loc < 0) ++ return (NULL); ++ else ++ return (sk_X509_NAME_ENTRY_value(name->entries, loc)); ++} ++ ++X509_NAME_ENTRY *X509_NAME_delete_entry(X509_NAME *name, int loc) ++{ ++ X509_NAME_ENTRY *ret; ++ int i, n, set_prev, set_next; ++ STACK_OF(X509_NAME_ENTRY) *sk; ++ ++ if (name == NULL || sk_X509_NAME_ENTRY_num(name->entries) <= loc ++ || loc < 0) ++ return (NULL); ++ sk = name->entries; ++ ret = sk_X509_NAME_ENTRY_delete(sk, loc); ++ n = sk_X509_NAME_ENTRY_num(sk); ++ name->modified = 1; ++ if (loc == n) ++ return (ret); ++ ++ /* else we need to fixup the set field */ ++ if (loc != 0) ++ set_prev = (sk_X509_NAME_ENTRY_value(sk, loc - 1))->set; ++ else ++ set_prev = ret->set - 1; ++ set_next = sk_X509_NAME_ENTRY_value(sk, loc)->set; ++ ++ /*- ++ * set_prev is the previous set ++ * set is the current set ++ * set_next is the following ++ * prev 1 1 1 1 1 1 1 1 ++ * set 1 1 2 2 ++ * next 1 1 2 2 2 2 3 2 ++ * so basically only if prev and next differ by 2, then ++ * re-number down by 1 ++ */ ++ if (set_prev + 1 < set_next) ++ for (i = loc; i < n; i++) ++ sk_X509_NAME_ENTRY_value(sk, i)->set--; ++ return (ret); ++} ++ ++int X509_NAME_add_entry_by_OBJ(X509_NAME *name, const ASN1_OBJECT *obj, int type, ++ const unsigned char *bytes, int len, int loc, ++ int set) ++{ ++ X509_NAME_ENTRY *ne; ++ int ret; ++ ne = X509_NAME_ENTRY_create_by_OBJ(NULL, obj, type, bytes, len); ++ if (!ne) ++ return 0; ++ ret = X509_NAME_add_entry(name, ne, loc, set); ++ X509_NAME_ENTRY_free(ne); ++ return ret; ++} ++ ++int X509_NAME_add_entry_by_NID(X509_NAME *name, int nid, int type, ++ const unsigned char *bytes, int len, int loc, ++ int set) ++{ ++ X509_NAME_ENTRY *ne; ++ int ret; ++ ne = X509_NAME_ENTRY_create_by_NID(NULL, nid, type, bytes, len); ++ if (!ne) ++ return 0; ++ ret = X509_NAME_add_entry(name, ne, loc, set); ++ X509_NAME_ENTRY_free(ne); ++ return ret; ++} ++ ++int X509_NAME_add_entry_by_txt(X509_NAME *name, const char *field, int type, ++ const unsigned char *bytes, int len, int loc, ++ int set) ++{ ++ X509_NAME_ENTRY *ne; ++ int ret; ++ ne = X509_NAME_ENTRY_create_by_txt(NULL, field, type, bytes, len); ++ if (!ne) ++ return 0; ++ ret = X509_NAME_add_entry(name, ne, loc, set); ++ X509_NAME_ENTRY_free(ne); ++ return ret; ++} ++ ++/* ++ * if set is -1, append to previous set, 0 'a new one', and 1, prepend to the ++ * guy we are about to stomp on. ++ */ ++int X509_NAME_add_entry(X509_NAME *name, const X509_NAME_ENTRY *ne, int loc, ++ int set) ++{ ++ X509_NAME_ENTRY *new_name = NULL; ++ int n, i, inc; ++ STACK_OF(X509_NAME_ENTRY) *sk; ++ ++ if (name == NULL) ++ return (0); ++ sk = name->entries; ++ n = sk_X509_NAME_ENTRY_num(sk); ++ if (loc > n) ++ loc = n; ++ else if (loc < 0) ++ loc = n; ++ ++ name->modified = 1; ++ ++ if (set == -1) { ++ if (loc == 0) { ++ set = 0; ++ inc = 1; ++ } else { ++ set = sk_X509_NAME_ENTRY_value(sk, loc - 1)->set; ++ inc = 0; ++ } ++ } else { /* if (set >= 0) */ ++ ++ if (loc >= n) { ++ if (loc != 0) ++ set = sk_X509_NAME_ENTRY_value(sk, loc - 1)->set + 1; ++ else ++ set = 0; ++ } else ++ set = sk_X509_NAME_ENTRY_value(sk, loc)->set; ++ inc = (set == 0) ? 1 : 0; ++ } ++ ++ /* ++ * X509_NAME_ENTRY_dup is ASN1 generated code, that can't be easily ++ * const'ified; harmless cast as dup() don't modify its input. ++ */ ++ if ((new_name = X509_NAME_ENTRY_dup((X509_NAME_ENTRY *)ne)) == NULL) ++ goto err; ++ new_name->set = set; ++ if (!sk_X509_NAME_ENTRY_insert(sk, new_name, loc)) { ++ X509err(X509_F_X509_NAME_ADD_ENTRY, ERR_R_MALLOC_FAILURE); ++ goto err; ++ } ++ if (inc) { ++ n = sk_X509_NAME_ENTRY_num(sk); ++ for (i = loc + 1; i < n; i++) ++ sk_X509_NAME_ENTRY_value(sk, i - 1)->set += 1; ++ } ++ return (1); ++ err: ++ X509_NAME_ENTRY_free(new_name); ++ return (0); ++} ++ ++X509_NAME_ENTRY *X509_NAME_ENTRY_create_by_txt(X509_NAME_ENTRY **ne, ++ const char *field, int type, ++ const unsigned char *bytes, ++ int len) ++{ ++ ASN1_OBJECT *obj; ++ X509_NAME_ENTRY *nentry; ++ ++ obj = OBJ_txt2obj(field, 0); ++ if (obj == NULL) { ++ X509err(X509_F_X509_NAME_ENTRY_CREATE_BY_TXT, ++ X509_R_INVALID_FIELD_NAME); ++ ERR_add_error_data(2, "name=", field); ++ return (NULL); ++ } ++ nentry = X509_NAME_ENTRY_create_by_OBJ(ne, obj, type, bytes, len); ++ ASN1_OBJECT_free(obj); ++ return nentry; ++} ++ ++X509_NAME_ENTRY *X509_NAME_ENTRY_create_by_NID(X509_NAME_ENTRY **ne, int nid, ++ int type, ++ const unsigned char *bytes, ++ int len) ++{ ++ ASN1_OBJECT *obj; ++ X509_NAME_ENTRY *nentry; ++ ++ obj = OBJ_nid2obj(nid); ++ if (obj == NULL) { ++ X509err(X509_F_X509_NAME_ENTRY_CREATE_BY_NID, X509_R_UNKNOWN_NID); ++ return (NULL); ++ } ++ nentry = X509_NAME_ENTRY_create_by_OBJ(ne, obj, type, bytes, len); ++ ASN1_OBJECT_free(obj); ++ return nentry; ++} ++ ++X509_NAME_ENTRY *X509_NAME_ENTRY_create_by_OBJ(X509_NAME_ENTRY **ne, ++ const ASN1_OBJECT *obj, int type, ++ const unsigned char *bytes, ++ int len) ++{ ++ X509_NAME_ENTRY *ret; ++ ++ if ((ne == NULL) || (*ne == NULL)) { ++ if ((ret = X509_NAME_ENTRY_new()) == NULL) ++ return (NULL); ++ } else ++ ret = *ne; ++ ++ if (!X509_NAME_ENTRY_set_object(ret, obj)) ++ goto err; ++ if (!X509_NAME_ENTRY_set_data(ret, type, bytes, len)) ++ goto err; ++ ++ if ((ne != NULL) && (*ne == NULL)) ++ *ne = ret; ++ return (ret); ++ err: ++ if ((ne == NULL) || (ret != *ne)) ++ X509_NAME_ENTRY_free(ret); ++ return (NULL); ++} ++ ++int X509_NAME_ENTRY_set_object(X509_NAME_ENTRY *ne, const ASN1_OBJECT *obj) ++{ ++ if ((ne == NULL) || (obj == NULL)) { ++ X509err(X509_F_X509_NAME_ENTRY_SET_OBJECT, ++ ERR_R_PASSED_NULL_PARAMETER); ++ return (0); ++ } ++ ASN1_OBJECT_free(ne->object); ++ ne->object = OBJ_dup(obj); ++ return ((ne->object == NULL) ? 0 : 1); ++} ++ ++int X509_NAME_ENTRY_set_data(X509_NAME_ENTRY *ne, int type, ++ const unsigned char *bytes, int len) ++{ ++ int i; ++ ++ if ((ne == NULL) || ((bytes == NULL) && (len != 0))) ++ return (0); ++ if ((type > 0) && (type & MBSTRING_FLAG)) ++ return ASN1_STRING_set_by_NID(&ne->value, bytes, ++ len, type, ++ OBJ_obj2nid(ne->object)) ? 1 : 0; ++ if (len < 0) ++ len = strlen((const char *)bytes); ++ i = ASN1_STRING_set(ne->value, bytes, len); ++ if (!i) ++ return (0); ++ if (type != V_ASN1_UNDEF) { ++ if (type == V_ASN1_APP_CHOOSE) ++ ne->value->type = ASN1_PRINTABLE_type(bytes, len); ++ else ++ ne->value->type = type; ++ } ++ return (1); ++} ++ ++ASN1_OBJECT *X509_NAME_ENTRY_get_object(const X509_NAME_ENTRY *ne) ++{ ++ if (ne == NULL) ++ return (NULL); ++ return (ne->object); ++} ++ ++ASN1_STRING *X509_NAME_ENTRY_get_data(const X509_NAME_ENTRY *ne) ++{ ++ if (ne == NULL) ++ return (NULL); ++ return (ne->value); ++} ++ ++int X509_NAME_ENTRY_set(const X509_NAME_ENTRY *ne) ++{ ++ return ne->set; ++} +diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/x509/x509rset.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/x509/x509rset.c +new file mode 100644 +index 0000000..6dee297 +--- /dev/null ++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/x509/x509rset.c +@@ -0,0 +1,40 @@ ++/* ++ * Copyright 1995-2016 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 ++ * in the file LICENSE in the source distribution or at ++ * https://www.openssl.org/source/license.html ++ */ ++ ++#include ++#include "internal/cryptlib.h" ++#include ++#include ++#include ++#include ++#include "internal/x509_int.h" ++ ++int X509_REQ_set_version(X509_REQ *x, long version) ++{ ++ if (x == NULL) ++ return (0); ++ x->req_info.enc.modified = 1; ++ return (ASN1_INTEGER_set(x->req_info.version, version)); ++} ++ ++int X509_REQ_set_subject_name(X509_REQ *x, X509_NAME *name) ++{ ++ if (x == NULL) ++ return (0); ++ x->req_info.enc.modified = 1; ++ return (X509_NAME_set(&x->req_info.subject, name)); ++} ++ ++int X509_REQ_set_pubkey(X509_REQ *x, EVP_PKEY *pkey) ++{ ++ if (x == NULL) ++ return (0); ++ x->req_info.enc.modified = 1; ++ return (X509_PUBKEY_set(&x->req_info.pubkey, pkey)); ++} +diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/x509/x509spki.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/x509/x509spki.c +new file mode 100644 +index 0000000..b142485 +--- /dev/null ++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/x509/x509spki.c +@@ -0,0 +1,75 @@ ++/* ++ * Copyright 1999-2016 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 ++ * in the file LICENSE in the source distribution or at ++ * https://www.openssl.org/source/license.html ++ */ ++ ++#include ++#include "internal/cryptlib.h" ++#include ++ ++int NETSCAPE_SPKI_set_pubkey(NETSCAPE_SPKI *x, EVP_PKEY *pkey) ++{ ++ if ((x == NULL) || (x->spkac == NULL)) ++ return (0); ++ return (X509_PUBKEY_set(&(x->spkac->pubkey), pkey)); ++} ++ ++EVP_PKEY *NETSCAPE_SPKI_get_pubkey(NETSCAPE_SPKI *x) ++{ ++ if ((x == NULL) || (x->spkac == NULL)) ++ return (NULL); ++ return (X509_PUBKEY_get(x->spkac->pubkey)); ++} ++ ++/* Load a Netscape SPKI from a base64 encoded string */ ++ ++NETSCAPE_SPKI *NETSCAPE_SPKI_b64_decode(const char *str, int len) ++{ ++ unsigned char *spki_der; ++ const unsigned char *p; ++ int spki_len; ++ NETSCAPE_SPKI *spki; ++ if (len <= 0) ++ len = strlen(str); ++ if ((spki_der = OPENSSL_malloc(len + 1)) == NULL) { ++ X509err(X509_F_NETSCAPE_SPKI_B64_DECODE, ERR_R_MALLOC_FAILURE); ++ return NULL; ++ } ++ spki_len = EVP_DecodeBlock(spki_der, (const unsigned char *)str, len); ++ if (spki_len < 0) { ++ X509err(X509_F_NETSCAPE_SPKI_B64_DECODE, X509_R_BASE64_DECODE_ERROR); ++ OPENSSL_free(spki_der); ++ return NULL; ++ } ++ p = spki_der; ++ spki = d2i_NETSCAPE_SPKI(NULL, &p, spki_len); ++ OPENSSL_free(spki_der); ++ return spki; ++} ++ ++/* Generate a base64 encoded string from an SPKI */ ++ ++char *NETSCAPE_SPKI_b64_encode(NETSCAPE_SPKI *spki) ++{ ++ unsigned char *der_spki, *p; ++ char *b64_str; ++ int der_len; ++ der_len = i2d_NETSCAPE_SPKI(spki, NULL); ++ der_spki = OPENSSL_malloc(der_len); ++ b64_str = OPENSSL_malloc(der_len * 2); ++ if (der_spki == NULL || b64_str == NULL) { ++ X509err(X509_F_NETSCAPE_SPKI_B64_ENCODE, ERR_R_MALLOC_FAILURE); ++ OPENSSL_free(der_spki); ++ OPENSSL_free(b64_str); ++ return NULL; ++ } ++ p = der_spki; ++ i2d_NETSCAPE_SPKI(spki, &p); ++ EVP_EncodeBlock((unsigned char *)b64_str, der_spki, der_len); ++ OPENSSL_free(der_spki); ++ return b64_str; ++} +diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/x509/x509type.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/x509/x509type.c +new file mode 100644 +index 0000000..aca8355 +--- /dev/null ++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/x509/x509type.c +@@ -0,0 +1,77 @@ ++/* ++ * Copyright 1995-2016 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 ++ * in the file LICENSE in the source distribution or at ++ * https://www.openssl.org/source/license.html ++ */ ++ ++#include ++#include "internal/cryptlib.h" ++#include ++#include ++#include ++ ++int X509_certificate_type(const X509 *x, const EVP_PKEY *pkey) ++{ ++ const EVP_PKEY *pk; ++ int ret = 0, i; ++ ++ if (x == NULL) ++ return (0); ++ ++ if (pkey == NULL) ++ pk = X509_get0_pubkey(x); ++ else ++ pk = pkey; ++ ++ if (pk == NULL) ++ return (0); ++ ++ switch (EVP_PKEY_id(pk)) { ++ case EVP_PKEY_RSA: ++ ret = EVP_PK_RSA | EVP_PKT_SIGN; ++/* if (!sign only extension) */ ++ ret |= EVP_PKT_ENC; ++ break; ++ case EVP_PKEY_DSA: ++ ret = EVP_PK_DSA | EVP_PKT_SIGN; ++ break; ++ case EVP_PKEY_EC: ++ ret = EVP_PK_EC | EVP_PKT_SIGN | EVP_PKT_EXCH; ++ break; ++ case EVP_PKEY_DH: ++ ret = EVP_PK_DH | EVP_PKT_EXCH; ++ break; ++ case NID_id_GostR3410_2001: ++ case NID_id_GostR3410_2012_256: ++ case NID_id_GostR3410_2012_512: ++ ret = EVP_PKT_EXCH | EVP_PKT_SIGN; ++ break; ++ default: ++ break; ++ } ++ ++ i = X509_get_signature_nid(x); ++ if (i && OBJ_find_sigid_algs(i, NULL, &i)) { ++ ++ switch (i) { ++ case NID_rsaEncryption: ++ case NID_rsa: ++ ret |= EVP_PKS_RSA; ++ break; ++ case NID_dsa: ++ case NID_dsa_2: ++ ret |= EVP_PKS_DSA; ++ break; ++ case NID_X9_62_id_ecPublicKey: ++ ret |= EVP_PKS_EC; ++ break; ++ default: ++ break; ++ } ++ } ++ ++ return (ret); ++} +diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/x509/x_all.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/x509/x_all.c +new file mode 100644 +index 0000000..124dd2d +--- /dev/null ++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/x509/x_all.c +@@ -0,0 +1,526 @@ ++/* ++ * Copyright 1995-2016 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 ++ * in the file LICENSE in the source distribution or at ++ * https://www.openssl.org/source/license.html ++ */ ++ ++#include ++#include ++#include "internal/cryptlib.h" ++#include ++#include ++#include ++#include ++#include "internal/x509_int.h" ++#include ++#include ++#include ++#include ++ ++int X509_verify(X509 *a, EVP_PKEY *r) ++{ ++ if (X509_ALGOR_cmp(&a->sig_alg, &a->cert_info.signature)) ++ return 0; ++ return (ASN1_item_verify(ASN1_ITEM_rptr(X509_CINF), &a->sig_alg, ++ &a->signature, &a->cert_info, r)); ++} ++ ++int X509_REQ_verify(X509_REQ *a, EVP_PKEY *r) ++{ ++ return (ASN1_item_verify(ASN1_ITEM_rptr(X509_REQ_INFO), ++ &a->sig_alg, a->signature, &a->req_info, r)); ++} ++ ++int NETSCAPE_SPKI_verify(NETSCAPE_SPKI *a, EVP_PKEY *r) ++{ ++ return (ASN1_item_verify(ASN1_ITEM_rptr(NETSCAPE_SPKAC), ++ &a->sig_algor, a->signature, a->spkac, r)); ++} ++ ++int X509_sign(X509 *x, EVP_PKEY *pkey, const EVP_MD *md) ++{ ++ x->cert_info.enc.modified = 1; ++ return (ASN1_item_sign(ASN1_ITEM_rptr(X509_CINF), &x->cert_info.signature, ++ &x->sig_alg, &x->signature, &x->cert_info, pkey, ++ md)); ++} ++ ++int X509_sign_ctx(X509 *x, EVP_MD_CTX *ctx) ++{ ++ x->cert_info.enc.modified = 1; ++ return ASN1_item_sign_ctx(ASN1_ITEM_rptr(X509_CINF), ++ &x->cert_info.signature, ++ &x->sig_alg, &x->signature, &x->cert_info, ctx); ++} ++ ++#ifndef OPENSSL_NO_OCSP ++int X509_http_nbio(OCSP_REQ_CTX *rctx, X509 **pcert) ++{ ++ return OCSP_REQ_CTX_nbio_d2i(rctx, ++ (ASN1_VALUE **)pcert, ASN1_ITEM_rptr(X509)); ++} ++#endif ++ ++int X509_REQ_sign(X509_REQ *x, EVP_PKEY *pkey, const EVP_MD *md) ++{ ++ return (ASN1_item_sign(ASN1_ITEM_rptr(X509_REQ_INFO), &x->sig_alg, NULL, ++ x->signature, &x->req_info, pkey, md)); ++} ++ ++int X509_REQ_sign_ctx(X509_REQ *x, EVP_MD_CTX *ctx) ++{ ++ return ASN1_item_sign_ctx(ASN1_ITEM_rptr(X509_REQ_INFO), ++ &x->sig_alg, NULL, x->signature, &x->req_info, ++ ctx); ++} ++ ++int X509_CRL_sign(X509_CRL *x, EVP_PKEY *pkey, const EVP_MD *md) ++{ ++ x->crl.enc.modified = 1; ++ return (ASN1_item_sign(ASN1_ITEM_rptr(X509_CRL_INFO), &x->crl.sig_alg, ++ &x->sig_alg, &x->signature, &x->crl, pkey, md)); ++} ++ ++int X509_CRL_sign_ctx(X509_CRL *x, EVP_MD_CTX *ctx) ++{ ++ x->crl.enc.modified = 1; ++ return ASN1_item_sign_ctx(ASN1_ITEM_rptr(X509_CRL_INFO), ++ &x->crl.sig_alg, &x->sig_alg, &x->signature, ++ &x->crl, ctx); ++} ++ ++#ifndef OPENSSL_NO_OCSP ++int X509_CRL_http_nbio(OCSP_REQ_CTX *rctx, X509_CRL **pcrl) ++{ ++ return OCSP_REQ_CTX_nbio_d2i(rctx, ++ (ASN1_VALUE **)pcrl, ++ ASN1_ITEM_rptr(X509_CRL)); ++} ++#endif ++ ++int NETSCAPE_SPKI_sign(NETSCAPE_SPKI *x, EVP_PKEY *pkey, const EVP_MD *md) ++{ ++ return (ASN1_item_sign(ASN1_ITEM_rptr(NETSCAPE_SPKAC), &x->sig_algor, NULL, ++ x->signature, x->spkac, pkey, md)); ++} ++ ++#ifndef OPENSSL_NO_STDIO ++X509 *d2i_X509_fp(FILE *fp, X509 **x509) ++{ ++ return ASN1_item_d2i_fp(ASN1_ITEM_rptr(X509), fp, x509); ++} ++ ++int i2d_X509_fp(FILE *fp, X509 *x509) ++{ ++ return ASN1_item_i2d_fp(ASN1_ITEM_rptr(X509), fp, x509); ++} ++#endif ++ ++X509 *d2i_X509_bio(BIO *bp, X509 **x509) ++{ ++ return ASN1_item_d2i_bio(ASN1_ITEM_rptr(X509), bp, x509); ++} ++ ++int i2d_X509_bio(BIO *bp, X509 *x509) ++{ ++ return ASN1_item_i2d_bio(ASN1_ITEM_rptr(X509), bp, x509); ++} ++ ++#ifndef OPENSSL_NO_STDIO ++X509_CRL *d2i_X509_CRL_fp(FILE *fp, X509_CRL **crl) ++{ ++ return ASN1_item_d2i_fp(ASN1_ITEM_rptr(X509_CRL), fp, crl); ++} ++ ++int i2d_X509_CRL_fp(FILE *fp, X509_CRL *crl) ++{ ++ return ASN1_item_i2d_fp(ASN1_ITEM_rptr(X509_CRL), fp, crl); ++} ++#endif ++ ++X509_CRL *d2i_X509_CRL_bio(BIO *bp, X509_CRL **crl) ++{ ++ return ASN1_item_d2i_bio(ASN1_ITEM_rptr(X509_CRL), bp, crl); ++} ++ ++int i2d_X509_CRL_bio(BIO *bp, X509_CRL *crl) ++{ ++ return ASN1_item_i2d_bio(ASN1_ITEM_rptr(X509_CRL), bp, crl); ++} ++ ++#ifndef OPENSSL_NO_STDIO ++PKCS7 *d2i_PKCS7_fp(FILE *fp, PKCS7 **p7) ++{ ++ return ASN1_item_d2i_fp(ASN1_ITEM_rptr(PKCS7), fp, p7); ++} ++ ++int i2d_PKCS7_fp(FILE *fp, PKCS7 *p7) ++{ ++ return ASN1_item_i2d_fp(ASN1_ITEM_rptr(PKCS7), fp, p7); ++} ++#endif ++ ++PKCS7 *d2i_PKCS7_bio(BIO *bp, PKCS7 **p7) ++{ ++ return ASN1_item_d2i_bio(ASN1_ITEM_rptr(PKCS7), bp, p7); ++} ++ ++int i2d_PKCS7_bio(BIO *bp, PKCS7 *p7) ++{ ++ return ASN1_item_i2d_bio(ASN1_ITEM_rptr(PKCS7), bp, p7); ++} ++ ++#ifndef OPENSSL_NO_STDIO ++X509_REQ *d2i_X509_REQ_fp(FILE *fp, X509_REQ **req) ++{ ++ return ASN1_item_d2i_fp(ASN1_ITEM_rptr(X509_REQ), fp, req); ++} ++ ++int i2d_X509_REQ_fp(FILE *fp, X509_REQ *req) ++{ ++ return ASN1_item_i2d_fp(ASN1_ITEM_rptr(X509_REQ), fp, req); ++} ++#endif ++ ++X509_REQ *d2i_X509_REQ_bio(BIO *bp, X509_REQ **req) ++{ ++ return ASN1_item_d2i_bio(ASN1_ITEM_rptr(X509_REQ), bp, req); ++} ++ ++int i2d_X509_REQ_bio(BIO *bp, X509_REQ *req) ++{ ++ return ASN1_item_i2d_bio(ASN1_ITEM_rptr(X509_REQ), bp, req); ++} ++ ++#ifndef OPENSSL_NO_RSA ++ ++# ifndef OPENSSL_NO_STDIO ++RSA *d2i_RSAPrivateKey_fp(FILE *fp, RSA **rsa) ++{ ++ return ASN1_item_d2i_fp(ASN1_ITEM_rptr(RSAPrivateKey), fp, rsa); ++} ++ ++int i2d_RSAPrivateKey_fp(FILE *fp, RSA *rsa) ++{ ++ return ASN1_item_i2d_fp(ASN1_ITEM_rptr(RSAPrivateKey), fp, rsa); ++} ++ ++RSA *d2i_RSAPublicKey_fp(FILE *fp, RSA **rsa) ++{ ++ return ASN1_item_d2i_fp(ASN1_ITEM_rptr(RSAPublicKey), fp, rsa); ++} ++ ++RSA *d2i_RSA_PUBKEY_fp(FILE *fp, RSA **rsa) ++{ ++ return ASN1_d2i_fp((void *(*)(void)) ++ RSA_new, (D2I_OF(void)) d2i_RSA_PUBKEY, fp, ++ (void **)rsa); ++} ++ ++int i2d_RSAPublicKey_fp(FILE *fp, RSA *rsa) ++{ ++ return ASN1_item_i2d_fp(ASN1_ITEM_rptr(RSAPublicKey), fp, rsa); ++} ++ ++int i2d_RSA_PUBKEY_fp(FILE *fp, RSA *rsa) ++{ ++ return ASN1_i2d_fp((I2D_OF(void))i2d_RSA_PUBKEY, fp, rsa); ++} ++# endif ++ ++RSA *d2i_RSAPrivateKey_bio(BIO *bp, RSA **rsa) ++{ ++ return ASN1_item_d2i_bio(ASN1_ITEM_rptr(RSAPrivateKey), bp, rsa); ++} ++ ++int i2d_RSAPrivateKey_bio(BIO *bp, RSA *rsa) ++{ ++ return ASN1_item_i2d_bio(ASN1_ITEM_rptr(RSAPrivateKey), bp, rsa); ++} ++ ++RSA *d2i_RSAPublicKey_bio(BIO *bp, RSA **rsa) ++{ ++ return ASN1_item_d2i_bio(ASN1_ITEM_rptr(RSAPublicKey), bp, rsa); ++} ++ ++RSA *d2i_RSA_PUBKEY_bio(BIO *bp, RSA **rsa) ++{ ++ return ASN1_d2i_bio_of(RSA, RSA_new, d2i_RSA_PUBKEY, bp, rsa); ++} ++ ++int i2d_RSAPublicKey_bio(BIO *bp, RSA *rsa) ++{ ++ return ASN1_item_i2d_bio(ASN1_ITEM_rptr(RSAPublicKey), bp, rsa); ++} ++ ++int i2d_RSA_PUBKEY_bio(BIO *bp, RSA *rsa) ++{ ++ return ASN1_i2d_bio_of(RSA, i2d_RSA_PUBKEY, bp, rsa); ++} ++#endif ++ ++#ifndef OPENSSL_NO_DSA ++# ifndef OPENSSL_NO_STDIO ++DSA *d2i_DSAPrivateKey_fp(FILE *fp, DSA **dsa) ++{ ++ return ASN1_d2i_fp_of(DSA, DSA_new, d2i_DSAPrivateKey, fp, dsa); ++} ++ ++int i2d_DSAPrivateKey_fp(FILE *fp, DSA *dsa) ++{ ++ return ASN1_i2d_fp_of_const(DSA, i2d_DSAPrivateKey, fp, dsa); ++} ++ ++DSA *d2i_DSA_PUBKEY_fp(FILE *fp, DSA **dsa) ++{ ++ return ASN1_d2i_fp_of(DSA, DSA_new, d2i_DSA_PUBKEY, fp, dsa); ++} ++ ++int i2d_DSA_PUBKEY_fp(FILE *fp, DSA *dsa) ++{ ++ return ASN1_i2d_fp_of(DSA, i2d_DSA_PUBKEY, fp, dsa); ++} ++# endif ++ ++DSA *d2i_DSAPrivateKey_bio(BIO *bp, DSA **dsa) ++{ ++ return ASN1_d2i_bio_of(DSA, DSA_new, d2i_DSAPrivateKey, bp, dsa); ++} ++ ++int i2d_DSAPrivateKey_bio(BIO *bp, DSA *dsa) ++{ ++ return ASN1_i2d_bio_of_const(DSA, i2d_DSAPrivateKey, bp, dsa); ++} ++ ++DSA *d2i_DSA_PUBKEY_bio(BIO *bp, DSA **dsa) ++{ ++ return ASN1_d2i_bio_of(DSA, DSA_new, d2i_DSA_PUBKEY, bp, dsa); ++} ++ ++int i2d_DSA_PUBKEY_bio(BIO *bp, DSA *dsa) ++{ ++ return ASN1_i2d_bio_of(DSA, i2d_DSA_PUBKEY, bp, dsa); ++} ++ ++#endif ++ ++#ifndef OPENSSL_NO_EC ++# ifndef OPENSSL_NO_STDIO ++EC_KEY *d2i_EC_PUBKEY_fp(FILE *fp, EC_KEY **eckey) ++{ ++ return ASN1_d2i_fp_of(EC_KEY, EC_KEY_new, d2i_EC_PUBKEY, fp, eckey); ++} ++ ++int i2d_EC_PUBKEY_fp(FILE *fp, EC_KEY *eckey) ++{ ++ return ASN1_i2d_fp_of(EC_KEY, i2d_EC_PUBKEY, fp, eckey); ++} ++ ++EC_KEY *d2i_ECPrivateKey_fp(FILE *fp, EC_KEY **eckey) ++{ ++ return ASN1_d2i_fp_of(EC_KEY, EC_KEY_new, d2i_ECPrivateKey, fp, eckey); ++} ++ ++int i2d_ECPrivateKey_fp(FILE *fp, EC_KEY *eckey) ++{ ++ return ASN1_i2d_fp_of(EC_KEY, i2d_ECPrivateKey, fp, eckey); ++} ++# endif ++EC_KEY *d2i_EC_PUBKEY_bio(BIO *bp, EC_KEY **eckey) ++{ ++ return ASN1_d2i_bio_of(EC_KEY, EC_KEY_new, d2i_EC_PUBKEY, bp, eckey); ++} ++ ++int i2d_EC_PUBKEY_bio(BIO *bp, EC_KEY *ecdsa) ++{ ++ return ASN1_i2d_bio_of(EC_KEY, i2d_EC_PUBKEY, bp, ecdsa); ++} ++ ++EC_KEY *d2i_ECPrivateKey_bio(BIO *bp, EC_KEY **eckey) ++{ ++ return ASN1_d2i_bio_of(EC_KEY, EC_KEY_new, d2i_ECPrivateKey, bp, eckey); ++} ++ ++int i2d_ECPrivateKey_bio(BIO *bp, EC_KEY *eckey) ++{ ++ return ASN1_i2d_bio_of(EC_KEY, i2d_ECPrivateKey, bp, eckey); ++} ++#endif ++ ++int X509_pubkey_digest(const X509 *data, const EVP_MD *type, ++ unsigned char *md, unsigned int *len) ++{ ++ ASN1_BIT_STRING *key; ++ key = X509_get0_pubkey_bitstr(data); ++ if (!key) ++ return 0; ++ return EVP_Digest(key->data, key->length, md, len, type, NULL); ++} ++ ++int X509_digest(const X509 *data, const EVP_MD *type, unsigned char *md, ++ unsigned int *len) ++{ ++ if (type == EVP_sha1() && (data->ex_flags & EXFLAG_SET) != 0) { ++ /* Asking for SHA1 and we already computed it. */ ++ if (len != NULL) ++ *len = sizeof(data->sha1_hash); ++ memcpy(md, data->sha1_hash, sizeof(data->sha1_hash)); ++ return 1; ++ } ++ return (ASN1_item_digest ++ (ASN1_ITEM_rptr(X509), type, (char *)data, md, len)); ++} ++ ++int X509_CRL_digest(const X509_CRL *data, const EVP_MD *type, ++ unsigned char *md, unsigned int *len) ++{ ++ if (type == EVP_sha1() && (data->flags & EXFLAG_SET) != 0) { ++ /* Asking for SHA1; always computed in CRL d2i. */ ++ if (len != NULL) ++ *len = sizeof(data->sha1_hash); ++ memcpy(md, data->sha1_hash, sizeof(data->sha1_hash)); ++ return 1; ++ } ++ return (ASN1_item_digest ++ (ASN1_ITEM_rptr(X509_CRL), type, (char *)data, md, len)); ++} ++ ++int X509_REQ_digest(const X509_REQ *data, const EVP_MD *type, ++ unsigned char *md, unsigned int *len) ++{ ++ return (ASN1_item_digest ++ (ASN1_ITEM_rptr(X509_REQ), type, (char *)data, md, len)); ++} ++ ++int X509_NAME_digest(const X509_NAME *data, const EVP_MD *type, ++ unsigned char *md, unsigned int *len) ++{ ++ return (ASN1_item_digest ++ (ASN1_ITEM_rptr(X509_NAME), type, (char *)data, md, len)); ++} ++ ++int PKCS7_ISSUER_AND_SERIAL_digest(PKCS7_ISSUER_AND_SERIAL *data, ++ const EVP_MD *type, unsigned char *md, ++ unsigned int *len) ++{ ++ return (ASN1_item_digest(ASN1_ITEM_rptr(PKCS7_ISSUER_AND_SERIAL), type, ++ (char *)data, md, len)); ++} ++ ++#ifndef OPENSSL_NO_STDIO ++X509_SIG *d2i_PKCS8_fp(FILE *fp, X509_SIG **p8) ++{ ++ return ASN1_d2i_fp_of(X509_SIG, X509_SIG_new, d2i_X509_SIG, fp, p8); ++} ++ ++int i2d_PKCS8_fp(FILE *fp, X509_SIG *p8) ++{ ++ return ASN1_i2d_fp_of(X509_SIG, i2d_X509_SIG, fp, p8); ++} ++#endif ++ ++X509_SIG *d2i_PKCS8_bio(BIO *bp, X509_SIG **p8) ++{ ++ return ASN1_d2i_bio_of(X509_SIG, X509_SIG_new, d2i_X509_SIG, bp, p8); ++} ++ ++int i2d_PKCS8_bio(BIO *bp, X509_SIG *p8) ++{ ++ return ASN1_i2d_bio_of(X509_SIG, i2d_X509_SIG, bp, p8); ++} ++ ++#ifndef OPENSSL_NO_STDIO ++PKCS8_PRIV_KEY_INFO *d2i_PKCS8_PRIV_KEY_INFO_fp(FILE *fp, ++ PKCS8_PRIV_KEY_INFO **p8inf) ++{ ++ return ASN1_d2i_fp_of(PKCS8_PRIV_KEY_INFO, PKCS8_PRIV_KEY_INFO_new, ++ d2i_PKCS8_PRIV_KEY_INFO, fp, p8inf); ++} ++ ++int i2d_PKCS8_PRIV_KEY_INFO_fp(FILE *fp, PKCS8_PRIV_KEY_INFO *p8inf) ++{ ++ return ASN1_i2d_fp_of(PKCS8_PRIV_KEY_INFO, i2d_PKCS8_PRIV_KEY_INFO, fp, ++ p8inf); ++} ++ ++int i2d_PKCS8PrivateKeyInfo_fp(FILE *fp, EVP_PKEY *key) ++{ ++ PKCS8_PRIV_KEY_INFO *p8inf; ++ int ret; ++ p8inf = EVP_PKEY2PKCS8(key); ++ if (!p8inf) ++ return 0; ++ ret = i2d_PKCS8_PRIV_KEY_INFO_fp(fp, p8inf); ++ PKCS8_PRIV_KEY_INFO_free(p8inf); ++ return ret; ++} ++ ++int i2d_PrivateKey_fp(FILE *fp, EVP_PKEY *pkey) ++{ ++ return ASN1_i2d_fp_of(EVP_PKEY, i2d_PrivateKey, fp, pkey); ++} ++ ++EVP_PKEY *d2i_PrivateKey_fp(FILE *fp, EVP_PKEY **a) ++{ ++ return ASN1_d2i_fp_of(EVP_PKEY, EVP_PKEY_new, d2i_AutoPrivateKey, fp, a); ++} ++ ++int i2d_PUBKEY_fp(FILE *fp, EVP_PKEY *pkey) ++{ ++ return ASN1_i2d_fp_of(EVP_PKEY, i2d_PUBKEY, fp, pkey); ++} ++ ++EVP_PKEY *d2i_PUBKEY_fp(FILE *fp, EVP_PKEY **a) ++{ ++ return ASN1_d2i_fp_of(EVP_PKEY, EVP_PKEY_new, d2i_PUBKEY, fp, a); ++} ++ ++#endif ++ ++PKCS8_PRIV_KEY_INFO *d2i_PKCS8_PRIV_KEY_INFO_bio(BIO *bp, ++ PKCS8_PRIV_KEY_INFO **p8inf) ++{ ++ return ASN1_d2i_bio_of(PKCS8_PRIV_KEY_INFO, PKCS8_PRIV_KEY_INFO_new, ++ d2i_PKCS8_PRIV_KEY_INFO, bp, p8inf); ++} ++ ++int i2d_PKCS8_PRIV_KEY_INFO_bio(BIO *bp, PKCS8_PRIV_KEY_INFO *p8inf) ++{ ++ return ASN1_i2d_bio_of(PKCS8_PRIV_KEY_INFO, i2d_PKCS8_PRIV_KEY_INFO, bp, ++ p8inf); ++} ++ ++int i2d_PKCS8PrivateKeyInfo_bio(BIO *bp, EVP_PKEY *key) ++{ ++ PKCS8_PRIV_KEY_INFO *p8inf; ++ int ret; ++ p8inf = EVP_PKEY2PKCS8(key); ++ if (!p8inf) ++ return 0; ++ ret = i2d_PKCS8_PRIV_KEY_INFO_bio(bp, p8inf); ++ PKCS8_PRIV_KEY_INFO_free(p8inf); ++ return ret; ++} ++ ++int i2d_PrivateKey_bio(BIO *bp, EVP_PKEY *pkey) ++{ ++ return ASN1_i2d_bio_of(EVP_PKEY, i2d_PrivateKey, bp, pkey); ++} ++ ++EVP_PKEY *d2i_PrivateKey_bio(BIO *bp, EVP_PKEY **a) ++{ ++ return ASN1_d2i_bio_of(EVP_PKEY, EVP_PKEY_new, d2i_AutoPrivateKey, bp, a); ++} ++ ++int i2d_PUBKEY_bio(BIO *bp, EVP_PKEY *pkey) ++{ ++ return ASN1_i2d_bio_of(EVP_PKEY, i2d_PUBKEY, bp, pkey); ++} ++ ++EVP_PKEY *d2i_PUBKEY_bio(BIO *bp, EVP_PKEY **a) ++{ ++ return ASN1_d2i_bio_of(EVP_PKEY, EVP_PKEY_new, d2i_PUBKEY, bp, a); ++} +diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/x509/x_attrib.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/x509/x_attrib.c +new file mode 100644 +index 0000000..35f4aee +--- /dev/null ++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/x509/x_attrib.c +@@ -0,0 +1,55 @@ ++/* ++ * Copyright 1995-2016 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 ++ * in the file LICENSE in the source distribution or at ++ * https://www.openssl.org/source/license.html ++ */ ++ ++#include ++#include "internal/cryptlib.h" ++#include ++#include ++#include ++#include "x509_lcl.h" ++ ++/*- ++ * X509_ATTRIBUTE: this has the following form: ++ * ++ * typedef struct x509_attributes_st ++ * { ++ * ASN1_OBJECT *object; ++ * STACK_OF(ASN1_TYPE) *set; ++ * } X509_ATTRIBUTE; ++ * ++ */ ++ ++ASN1_SEQUENCE(X509_ATTRIBUTE) = { ++ ASN1_SIMPLE(X509_ATTRIBUTE, object, ASN1_OBJECT), ++ ASN1_SET_OF(X509_ATTRIBUTE, set, ASN1_ANY) ++} ASN1_SEQUENCE_END(X509_ATTRIBUTE) ++ ++IMPLEMENT_ASN1_FUNCTIONS(X509_ATTRIBUTE) ++IMPLEMENT_ASN1_DUP_FUNCTION(X509_ATTRIBUTE) ++ ++X509_ATTRIBUTE *X509_ATTRIBUTE_create(int nid, int atrtype, void *value) ++{ ++ X509_ATTRIBUTE *ret = NULL; ++ ASN1_TYPE *val = NULL; ++ ++ if ((ret = X509_ATTRIBUTE_new()) == NULL) ++ return (NULL); ++ ret->object = OBJ_nid2obj(nid); ++ if ((val = ASN1_TYPE_new()) == NULL) ++ goto err; ++ if (!sk_ASN1_TYPE_push(ret->set, val)) ++ goto err; ++ ++ ASN1_TYPE_set(val, atrtype, value); ++ return (ret); ++ err: ++ X509_ATTRIBUTE_free(ret); ++ ASN1_TYPE_free(val); ++ return (NULL); ++} +diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/x509/x_crl.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/x509/x_crl.c +new file mode 100644 +index 0000000..dbed850 +--- /dev/null ++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/x509/x_crl.c +@@ -0,0 +1,459 @@ ++/* ++ * Copyright 1995-2016 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 ++ * in the file LICENSE in the source distribution or at ++ * https://www.openssl.org/source/license.html ++ */ ++ ++#include ++#include "internal/cryptlib.h" ++#include ++#include ++#include "internal/x509_int.h" ++#include ++#include "x509_lcl.h" ++ ++static int X509_REVOKED_cmp(const X509_REVOKED *const *a, ++ const X509_REVOKED *const *b); ++static void setup_idp(X509_CRL *crl, ISSUING_DIST_POINT *idp); ++ ++ASN1_SEQUENCE(X509_REVOKED) = { ++ ASN1_EMBED(X509_REVOKED,serialNumber, ASN1_INTEGER), ++ ASN1_SIMPLE(X509_REVOKED,revocationDate, ASN1_TIME), ++ ASN1_SEQUENCE_OF_OPT(X509_REVOKED,extensions, X509_EXTENSION) ++} ASN1_SEQUENCE_END(X509_REVOKED) ++ ++static int def_crl_verify(X509_CRL *crl, EVP_PKEY *r); ++static int def_crl_lookup(X509_CRL *crl, ++ X509_REVOKED **ret, ASN1_INTEGER *serial, ++ X509_NAME *issuer); ++ ++static X509_CRL_METHOD int_crl_meth = { ++ 0, ++ 0, 0, ++ def_crl_lookup, ++ def_crl_verify ++}; ++ ++static const X509_CRL_METHOD *default_crl_method = &int_crl_meth; ++ ++/* ++ * The X509_CRL_INFO structure needs a bit of customisation. Since we cache ++ * the original encoding the signature won't be affected by reordering of the ++ * revoked field. ++ */ ++static int crl_inf_cb(int operation, ASN1_VALUE **pval, const ASN1_ITEM *it, ++ void *exarg) ++{ ++ X509_CRL_INFO *a = (X509_CRL_INFO *)*pval; ++ ++ if (!a || !a->revoked) ++ return 1; ++ switch (operation) { ++ /* ++ * Just set cmp function here. We don't sort because that would ++ * affect the output of X509_CRL_print(). ++ */ ++ case ASN1_OP_D2I_POST: ++ (void)sk_X509_REVOKED_set_cmp_func(a->revoked, X509_REVOKED_cmp); ++ break; ++ } ++ return 1; ++} ++ ++ ++ASN1_SEQUENCE_enc(X509_CRL_INFO, enc, crl_inf_cb) = { ++ ASN1_OPT(X509_CRL_INFO, version, ASN1_INTEGER), ++ ASN1_EMBED(X509_CRL_INFO, sig_alg, X509_ALGOR), ++ ASN1_SIMPLE(X509_CRL_INFO, issuer, X509_NAME), ++ ASN1_SIMPLE(X509_CRL_INFO, lastUpdate, ASN1_TIME), ++ ASN1_OPT(X509_CRL_INFO, nextUpdate, ASN1_TIME), ++ ASN1_SEQUENCE_OF_OPT(X509_CRL_INFO, revoked, X509_REVOKED), ++ ASN1_EXP_SEQUENCE_OF_OPT(X509_CRL_INFO, extensions, X509_EXTENSION, 0) ++} ASN1_SEQUENCE_END_enc(X509_CRL_INFO, X509_CRL_INFO) ++ ++/* ++ * Set CRL entry issuer according to CRL certificate issuer extension. Check ++ * for unhandled critical CRL entry extensions. ++ */ ++ ++static int crl_set_issuers(X509_CRL *crl) ++{ ++ ++ int i, j; ++ GENERAL_NAMES *gens, *gtmp; ++ STACK_OF(X509_REVOKED) *revoked; ++ ++ revoked = X509_CRL_get_REVOKED(crl); ++ ++ gens = NULL; ++ for (i = 0; i < sk_X509_REVOKED_num(revoked); i++) { ++ X509_REVOKED *rev = sk_X509_REVOKED_value(revoked, i); ++ STACK_OF(X509_EXTENSION) *exts; ++ ASN1_ENUMERATED *reason; ++ X509_EXTENSION *ext; ++ gtmp = X509_REVOKED_get_ext_d2i(rev, ++ NID_certificate_issuer, &j, NULL); ++ if (!gtmp && (j != -1)) { ++ crl->flags |= EXFLAG_INVALID; ++ return 1; ++ } ++ ++ if (gtmp) { ++ gens = gtmp; ++ if (!crl->issuers) { ++ crl->issuers = sk_GENERAL_NAMES_new_null(); ++ if (!crl->issuers) ++ return 0; ++ } ++ if (!sk_GENERAL_NAMES_push(crl->issuers, gtmp)) ++ return 0; ++ } ++ rev->issuer = gens; ++ ++ reason = X509_REVOKED_get_ext_d2i(rev, NID_crl_reason, &j, NULL); ++ if (!reason && (j != -1)) { ++ crl->flags |= EXFLAG_INVALID; ++ return 1; ++ } ++ ++ if (reason) { ++ rev->reason = ASN1_ENUMERATED_get(reason); ++ ASN1_ENUMERATED_free(reason); ++ } else ++ rev->reason = CRL_REASON_NONE; ++ ++ /* Check for critical CRL entry extensions */ ++ ++ exts = rev->extensions; ++ ++ for (j = 0; j < sk_X509_EXTENSION_num(exts); j++) { ++ ext = sk_X509_EXTENSION_value(exts, j); ++ if (X509_EXTENSION_get_critical(ext)) { ++ if (OBJ_obj2nid(X509_EXTENSION_get_object(ext)) == NID_certificate_issuer) ++ continue; ++ crl->flags |= EXFLAG_CRITICAL; ++ break; ++ } ++ } ++ ++ } ++ ++ return 1; ++ ++} ++ ++/* ++ * The X509_CRL structure needs a bit of customisation. Cache some extensions ++ * and hash of the whole CRL. ++ */ ++static int crl_cb(int operation, ASN1_VALUE **pval, const ASN1_ITEM *it, ++ void *exarg) ++{ ++ X509_CRL *crl = (X509_CRL *)*pval; ++ STACK_OF(X509_EXTENSION) *exts; ++ X509_EXTENSION *ext; ++ int idx; ++ ++ switch (operation) { ++ case ASN1_OP_NEW_POST: ++ crl->idp = NULL; ++ crl->akid = NULL; ++ crl->flags = 0; ++ crl->idp_flags = 0; ++ crl->idp_reasons = CRLDP_ALL_REASONS; ++ crl->meth = default_crl_method; ++ crl->meth_data = NULL; ++ crl->issuers = NULL; ++ crl->crl_number = NULL; ++ crl->base_crl_number = NULL; ++ break; ++ ++ case ASN1_OP_D2I_POST: ++ X509_CRL_digest(crl, EVP_sha1(), crl->sha1_hash, NULL); ++ crl->idp = X509_CRL_get_ext_d2i(crl, ++ NID_issuing_distribution_point, NULL, ++ NULL); ++ if (crl->idp) ++ setup_idp(crl, crl->idp); ++ ++ crl->akid = X509_CRL_get_ext_d2i(crl, ++ NID_authority_key_identifier, NULL, ++ NULL); ++ ++ crl->crl_number = X509_CRL_get_ext_d2i(crl, ++ NID_crl_number, NULL, NULL); ++ ++ crl->base_crl_number = X509_CRL_get_ext_d2i(crl, ++ NID_delta_crl, NULL, ++ NULL); ++ /* Delta CRLs must have CRL number */ ++ if (crl->base_crl_number && !crl->crl_number) ++ crl->flags |= EXFLAG_INVALID; ++ ++ /* ++ * See if we have any unhandled critical CRL extensions and indicate ++ * this in a flag. We only currently handle IDP so anything else ++ * critical sets the flag. This code accesses the X509_CRL structure ++ * directly: applications shouldn't do this. ++ */ ++ ++ exts = crl->crl.extensions; ++ ++ for (idx = 0; idx < sk_X509_EXTENSION_num(exts); idx++) { ++ int nid; ++ ext = sk_X509_EXTENSION_value(exts, idx); ++ nid = OBJ_obj2nid(X509_EXTENSION_get_object(ext)); ++ if (nid == NID_freshest_crl) ++ crl->flags |= EXFLAG_FRESHEST; ++ if (X509_EXTENSION_get_critical(ext)) { ++ /* We handle IDP and deltas */ ++ if ((nid == NID_issuing_distribution_point) ++ || (nid == NID_authority_key_identifier) ++ || (nid == NID_delta_crl)) ++ continue; ++ crl->flags |= EXFLAG_CRITICAL; ++ break; ++ } ++ } ++ ++ if (!crl_set_issuers(crl)) ++ return 0; ++ ++ if (crl->meth->crl_init) { ++ if (crl->meth->crl_init(crl) == 0) ++ return 0; ++ } ++ ++ crl->flags |= EXFLAG_SET; ++ break; ++ ++ case ASN1_OP_FREE_POST: ++ if (crl->meth->crl_free) { ++ if (!crl->meth->crl_free(crl)) ++ return 0; ++ } ++ AUTHORITY_KEYID_free(crl->akid); ++ ISSUING_DIST_POINT_free(crl->idp); ++ ASN1_INTEGER_free(crl->crl_number); ++ ASN1_INTEGER_free(crl->base_crl_number); ++ sk_GENERAL_NAMES_pop_free(crl->issuers, GENERAL_NAMES_free); ++ break; ++ } ++ return 1; ++} ++ ++/* Convert IDP into a more convenient form */ ++ ++static void setup_idp(X509_CRL *crl, ISSUING_DIST_POINT *idp) ++{ ++ int idp_only = 0; ++ /* Set various flags according to IDP */ ++ crl->idp_flags |= IDP_PRESENT; ++ if (idp->onlyuser > 0) { ++ idp_only++; ++ crl->idp_flags |= IDP_ONLYUSER; ++ } ++ if (idp->onlyCA > 0) { ++ idp_only++; ++ crl->idp_flags |= IDP_ONLYCA; ++ } ++ if (idp->onlyattr > 0) { ++ idp_only++; ++ crl->idp_flags |= IDP_ONLYATTR; ++ } ++ ++ if (idp_only > 1) ++ crl->idp_flags |= IDP_INVALID; ++ ++ if (idp->indirectCRL > 0) ++ crl->idp_flags |= IDP_INDIRECT; ++ ++ if (idp->onlysomereasons) { ++ crl->idp_flags |= IDP_REASONS; ++ if (idp->onlysomereasons->length > 0) ++ crl->idp_reasons = idp->onlysomereasons->data[0]; ++ if (idp->onlysomereasons->length > 1) ++ crl->idp_reasons |= (idp->onlysomereasons->data[1] << 8); ++ crl->idp_reasons &= CRLDP_ALL_REASONS; ++ } ++ ++ DIST_POINT_set_dpname(idp->distpoint, X509_CRL_get_issuer(crl)); ++} ++ ++ASN1_SEQUENCE_ref(X509_CRL, crl_cb) = { ++ ASN1_EMBED(X509_CRL, crl, X509_CRL_INFO), ++ ASN1_EMBED(X509_CRL, sig_alg, X509_ALGOR), ++ ASN1_EMBED(X509_CRL, signature, ASN1_BIT_STRING) ++} ASN1_SEQUENCE_END_ref(X509_CRL, X509_CRL) ++ ++IMPLEMENT_ASN1_FUNCTIONS(X509_REVOKED) ++ ++IMPLEMENT_ASN1_DUP_FUNCTION(X509_REVOKED) ++ ++IMPLEMENT_ASN1_FUNCTIONS(X509_CRL_INFO) ++ ++IMPLEMENT_ASN1_FUNCTIONS(X509_CRL) ++ ++IMPLEMENT_ASN1_DUP_FUNCTION(X509_CRL) ++ ++static int X509_REVOKED_cmp(const X509_REVOKED *const *a, ++ const X509_REVOKED *const *b) ++{ ++ return (ASN1_STRING_cmp((ASN1_STRING *)&(*a)->serialNumber, ++ (ASN1_STRING *)&(*b)->serialNumber)); ++} ++ ++int X509_CRL_add0_revoked(X509_CRL *crl, X509_REVOKED *rev) ++{ ++ X509_CRL_INFO *inf; ++ inf = &crl->crl; ++ if (inf->revoked == NULL) ++ inf->revoked = sk_X509_REVOKED_new(X509_REVOKED_cmp); ++ if (inf->revoked == NULL || !sk_X509_REVOKED_push(inf->revoked, rev)) { ++ ASN1err(ASN1_F_X509_CRL_ADD0_REVOKED, ERR_R_MALLOC_FAILURE); ++ return 0; ++ } ++ inf->enc.modified = 1; ++ return 1; ++} ++ ++int X509_CRL_verify(X509_CRL *crl, EVP_PKEY *r) ++{ ++ if (crl->meth->crl_verify) ++ return crl->meth->crl_verify(crl, r); ++ return 0; ++} ++ ++int X509_CRL_get0_by_serial(X509_CRL *crl, ++ X509_REVOKED **ret, ASN1_INTEGER *serial) ++{ ++ if (crl->meth->crl_lookup) ++ return crl->meth->crl_lookup(crl, ret, serial, NULL); ++ return 0; ++} ++ ++int X509_CRL_get0_by_cert(X509_CRL *crl, X509_REVOKED **ret, X509 *x) ++{ ++ if (crl->meth->crl_lookup) ++ return crl->meth->crl_lookup(crl, ret, ++ X509_get_serialNumber(x), ++ X509_get_issuer_name(x)); ++ return 0; ++} ++ ++static int def_crl_verify(X509_CRL *crl, EVP_PKEY *r) ++{ ++ return (ASN1_item_verify(ASN1_ITEM_rptr(X509_CRL_INFO), ++ &crl->sig_alg, &crl->signature, &crl->crl, r)); ++} ++ ++static int crl_revoked_issuer_match(X509_CRL *crl, X509_NAME *nm, ++ X509_REVOKED *rev) ++{ ++ int i; ++ ++ if (!rev->issuer) { ++ if (!nm) ++ return 1; ++ if (!X509_NAME_cmp(nm, X509_CRL_get_issuer(crl))) ++ return 1; ++ return 0; ++ } ++ ++ if (!nm) ++ nm = X509_CRL_get_issuer(crl); ++ ++ for (i = 0; i < sk_GENERAL_NAME_num(rev->issuer); i++) { ++ GENERAL_NAME *gen = sk_GENERAL_NAME_value(rev->issuer, i); ++ if (gen->type != GEN_DIRNAME) ++ continue; ++ if (!X509_NAME_cmp(nm, gen->d.directoryName)) ++ return 1; ++ } ++ return 0; ++ ++} ++ ++static int def_crl_lookup(X509_CRL *crl, ++ X509_REVOKED **ret, ASN1_INTEGER *serial, ++ X509_NAME *issuer) ++{ ++ X509_REVOKED rtmp, *rev; ++ int idx; ++ rtmp.serialNumber = *serial; ++ /* ++ * Sort revoked into serial number order if not already sorted. Do this ++ * under a lock to avoid race condition. ++ */ ++ if (!sk_X509_REVOKED_is_sorted(crl->crl.revoked)) { ++ CRYPTO_THREAD_write_lock(crl->lock); ++ sk_X509_REVOKED_sort(crl->crl.revoked); ++ CRYPTO_THREAD_unlock(crl->lock); ++ } ++ idx = sk_X509_REVOKED_find(crl->crl.revoked, &rtmp); ++ if (idx < 0) ++ return 0; ++ /* Need to look for matching name */ ++ for (; idx < sk_X509_REVOKED_num(crl->crl.revoked); idx++) { ++ rev = sk_X509_REVOKED_value(crl->crl.revoked, idx); ++ if (ASN1_INTEGER_cmp(&rev->serialNumber, serial)) ++ return 0; ++ if (crl_revoked_issuer_match(crl, issuer, rev)) { ++ if (ret) ++ *ret = rev; ++ if (rev->reason == CRL_REASON_REMOVE_FROM_CRL) ++ return 2; ++ return 1; ++ } ++ } ++ return 0; ++} ++ ++void X509_CRL_set_default_method(const X509_CRL_METHOD *meth) ++{ ++ if (meth == NULL) ++ default_crl_method = &int_crl_meth; ++ else ++ default_crl_method = meth; ++} ++ ++X509_CRL_METHOD *X509_CRL_METHOD_new(int (*crl_init) (X509_CRL *crl), ++ int (*crl_free) (X509_CRL *crl), ++ int (*crl_lookup) (X509_CRL *crl, ++ X509_REVOKED **ret, ++ ASN1_INTEGER *ser, ++ X509_NAME *issuer), ++ int (*crl_verify) (X509_CRL *crl, ++ EVP_PKEY *pk)) ++{ ++ X509_CRL_METHOD *m; ++ m = OPENSSL_malloc(sizeof(*m)); ++ if (m == NULL) ++ return NULL; ++ m->crl_init = crl_init; ++ m->crl_free = crl_free; ++ m->crl_lookup = crl_lookup; ++ m->crl_verify = crl_verify; ++ m->flags = X509_CRL_METHOD_DYNAMIC; ++ return m; ++} ++ ++void X509_CRL_METHOD_free(X509_CRL_METHOD *m) ++{ ++ if (m == NULL || !(m->flags & X509_CRL_METHOD_DYNAMIC)) ++ return; ++ OPENSSL_free(m); ++} ++ ++void X509_CRL_set_meth_data(X509_CRL *crl, void *dat) ++{ ++ crl->meth_data = dat; ++} ++ ++void *X509_CRL_get_meth_data(X509_CRL *crl) ++{ ++ return crl->meth_data; ++} +diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/x509/x_exten.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/x509/x_exten.c +new file mode 100644 +index 0000000..f10f4a4 +--- /dev/null ++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/x509/x_exten.c +@@ -0,0 +1,28 @@ ++/* ++ * Copyright 2000-2016 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 ++ * in the file LICENSE in the source distribution or at ++ * https://www.openssl.org/source/license.html ++ */ ++ ++#include ++#include ++#include ++#include ++#include "x509_lcl.h" ++ ++ASN1_SEQUENCE(X509_EXTENSION) = { ++ ASN1_SIMPLE(X509_EXTENSION, object, ASN1_OBJECT), ++ ASN1_OPT(X509_EXTENSION, critical, ASN1_BOOLEAN), ++ ASN1_EMBED(X509_EXTENSION, value, ASN1_OCTET_STRING) ++} ASN1_SEQUENCE_END(X509_EXTENSION) ++ ++ASN1_ITEM_TEMPLATE(X509_EXTENSIONS) = ++ ASN1_EX_TEMPLATE_TYPE(ASN1_TFLG_SEQUENCE_OF, 0, Extension, X509_EXTENSION) ++ASN1_ITEM_TEMPLATE_END(X509_EXTENSIONS) ++ ++IMPLEMENT_ASN1_FUNCTIONS(X509_EXTENSION) ++IMPLEMENT_ASN1_ENCODE_FUNCTIONS_fname(X509_EXTENSIONS, X509_EXTENSIONS, X509_EXTENSIONS) ++IMPLEMENT_ASN1_DUP_FUNCTION(X509_EXTENSION) +diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/x509/x_name.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/x509/x_name.c +new file mode 100644 +index 0000000..97d735f +--- /dev/null ++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/x509/x_name.c +@@ -0,0 +1,557 @@ ++/* ++ * Copyright 1995-2016 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 ++ * in the file LICENSE in the source distribution or at ++ * https://www.openssl.org/source/license.html ++ */ ++ ++#include ++#include ++#include "internal/cryptlib.h" ++#include ++#include ++#include "internal/x509_int.h" ++#include "internal/asn1_int.h" ++#include "x509_lcl.h" ++ ++/* ++ * Maximum length of X509_NAME: much larger than anything we should ++ * ever see in practice. ++ */ ++ ++#define X509_NAME_MAX (1024 * 1024) ++ ++static int x509_name_ex_d2i(ASN1_VALUE **val, ++ const unsigned char **in, long len, ++ const ASN1_ITEM *it, ++ int tag, int aclass, char opt, ASN1_TLC *ctx); ++ ++static int x509_name_ex_i2d(ASN1_VALUE **val, unsigned char **out, ++ const ASN1_ITEM *it, int tag, int aclass); ++static int x509_name_ex_new(ASN1_VALUE **val, const ASN1_ITEM *it); ++static void x509_name_ex_free(ASN1_VALUE **val, const ASN1_ITEM *it); ++ ++static int x509_name_encode(X509_NAME *a); ++static int x509_name_canon(X509_NAME *a); ++static int asn1_string_canon(ASN1_STRING *out, const ASN1_STRING *in); ++static int i2d_name_canon(STACK_OF(STACK_OF_X509_NAME_ENTRY) * intname, ++ unsigned char **in); ++ ++static int x509_name_ex_print(BIO *out, ASN1_VALUE **pval, ++ int indent, ++ const char *fname, const ASN1_PCTX *pctx); ++ ++ASN1_SEQUENCE(X509_NAME_ENTRY) = { ++ ASN1_SIMPLE(X509_NAME_ENTRY, object, ASN1_OBJECT), ++ ASN1_SIMPLE(X509_NAME_ENTRY, value, ASN1_PRINTABLE) ++} ASN1_SEQUENCE_END(X509_NAME_ENTRY) ++ ++IMPLEMENT_ASN1_FUNCTIONS(X509_NAME_ENTRY) ++IMPLEMENT_ASN1_DUP_FUNCTION(X509_NAME_ENTRY) ++ ++/* ++ * For the "Name" type we need a SEQUENCE OF { SET OF X509_NAME_ENTRY } so ++ * declare two template wrappers for this ++ */ ++ ++ASN1_ITEM_TEMPLATE(X509_NAME_ENTRIES) = ++ ASN1_EX_TEMPLATE_TYPE(ASN1_TFLG_SET_OF, 0, RDNS, X509_NAME_ENTRY) ++static_ASN1_ITEM_TEMPLATE_END(X509_NAME_ENTRIES) ++ ++ASN1_ITEM_TEMPLATE(X509_NAME_INTERNAL) = ++ ASN1_EX_TEMPLATE_TYPE(ASN1_TFLG_SEQUENCE_OF, 0, Name, X509_NAME_ENTRIES) ++static_ASN1_ITEM_TEMPLATE_END(X509_NAME_INTERNAL) ++ ++/* ++ * Normally that's where it would end: we'd have two nested STACK structures ++ * representing the ASN1. Unfortunately X509_NAME uses a completely different ++ * form and caches encodings so we have to process the internal form and ++ * convert to the external form. ++ */ ++ ++static const ASN1_EXTERN_FUNCS x509_name_ff = { ++ NULL, ++ x509_name_ex_new, ++ x509_name_ex_free, ++ 0, /* Default clear behaviour is OK */ ++ x509_name_ex_d2i, ++ x509_name_ex_i2d, ++ x509_name_ex_print ++}; ++ ++IMPLEMENT_EXTERN_ASN1(X509_NAME, V_ASN1_SEQUENCE, x509_name_ff) ++ ++IMPLEMENT_ASN1_FUNCTIONS(X509_NAME) ++ ++IMPLEMENT_ASN1_DUP_FUNCTION(X509_NAME) ++ ++static int x509_name_ex_new(ASN1_VALUE **val, const ASN1_ITEM *it) ++{ ++ X509_NAME *ret = OPENSSL_zalloc(sizeof(*ret)); ++ ++ if (ret == NULL) ++ goto memerr; ++ if ((ret->entries = sk_X509_NAME_ENTRY_new_null()) == NULL) ++ goto memerr; ++ if ((ret->bytes = BUF_MEM_new()) == NULL) ++ goto memerr; ++ ret->modified = 1; ++ *val = (ASN1_VALUE *)ret; ++ return 1; ++ ++ memerr: ++ ASN1err(ASN1_F_X509_NAME_EX_NEW, ERR_R_MALLOC_FAILURE); ++ if (ret) { ++ sk_X509_NAME_ENTRY_free(ret->entries); ++ OPENSSL_free(ret); ++ } ++ return 0; ++} ++ ++static void x509_name_ex_free(ASN1_VALUE **pval, const ASN1_ITEM *it) ++{ ++ X509_NAME *a; ++ ++ if (!pval || !*pval) ++ return; ++ a = (X509_NAME *)*pval; ++ ++ BUF_MEM_free(a->bytes); ++ sk_X509_NAME_ENTRY_pop_free(a->entries, X509_NAME_ENTRY_free); ++ OPENSSL_free(a->canon_enc); ++ OPENSSL_free(a); ++ *pval = NULL; ++} ++ ++static void local_sk_X509_NAME_ENTRY_free(STACK_OF(X509_NAME_ENTRY) *ne) ++{ ++ sk_X509_NAME_ENTRY_free(ne); ++} ++ ++static void local_sk_X509_NAME_ENTRY_pop_free(STACK_OF(X509_NAME_ENTRY) *ne) ++{ ++ sk_X509_NAME_ENTRY_pop_free(ne, X509_NAME_ENTRY_free); ++} ++ ++static int x509_name_ex_d2i(ASN1_VALUE **val, ++ const unsigned char **in, long len, ++ const ASN1_ITEM *it, int tag, int aclass, ++ char opt, ASN1_TLC *ctx) ++{ ++ const unsigned char *p = *in, *q; ++ union { ++ STACK_OF(STACK_OF_X509_NAME_ENTRY) *s; ++ ASN1_VALUE *a; ++ } intname = { ++ NULL ++ }; ++ union { ++ X509_NAME *x; ++ ASN1_VALUE *a; ++ } nm = { ++ NULL ++ }; ++ int i, j, ret; ++ STACK_OF(X509_NAME_ENTRY) *entries; ++ X509_NAME_ENTRY *entry; ++ if (len > X509_NAME_MAX) ++ len = X509_NAME_MAX; ++ q = p; ++ ++ /* Get internal representation of Name */ ++ ret = ASN1_item_ex_d2i(&intname.a, ++ &p, len, ASN1_ITEM_rptr(X509_NAME_INTERNAL), ++ tag, aclass, opt, ctx); ++ ++ if (ret <= 0) ++ return ret; ++ ++ if (*val) ++ x509_name_ex_free(val, NULL); ++ if (!x509_name_ex_new(&nm.a, NULL)) ++ goto err; ++ /* We've decoded it: now cache encoding */ ++ if (!BUF_MEM_grow(nm.x->bytes, p - q)) ++ goto err; ++ memcpy(nm.x->bytes->data, q, p - q); ++ ++ /* Convert internal representation to X509_NAME structure */ ++ for (i = 0; i < sk_STACK_OF_X509_NAME_ENTRY_num(intname.s); i++) { ++ entries = sk_STACK_OF_X509_NAME_ENTRY_value(intname.s, i); ++ for (j = 0; j < sk_X509_NAME_ENTRY_num(entries); j++) { ++ entry = sk_X509_NAME_ENTRY_value(entries, j); ++ entry->set = i; ++ if (!sk_X509_NAME_ENTRY_push(nm.x->entries, entry)) ++ goto err; ++ sk_X509_NAME_ENTRY_set(entries, j, NULL); ++ } ++ } ++ ret = x509_name_canon(nm.x); ++ if (!ret) ++ goto err; ++ sk_STACK_OF_X509_NAME_ENTRY_pop_free(intname.s, ++ local_sk_X509_NAME_ENTRY_free); ++ nm.x->modified = 0; ++ *val = nm.a; ++ *in = p; ++ return ret; ++ ++ err: ++ if (nm.x != NULL) ++ X509_NAME_free(nm.x); ++ sk_STACK_OF_X509_NAME_ENTRY_pop_free(intname.s, ++ local_sk_X509_NAME_ENTRY_pop_free); ++ ASN1err(ASN1_F_X509_NAME_EX_D2I, ERR_R_NESTED_ASN1_ERROR); ++ return 0; ++} ++ ++static int x509_name_ex_i2d(ASN1_VALUE **val, unsigned char **out, ++ const ASN1_ITEM *it, int tag, int aclass) ++{ ++ int ret; ++ X509_NAME *a = (X509_NAME *)*val; ++ if (a->modified) { ++ ret = x509_name_encode(a); ++ if (ret < 0) ++ return ret; ++ ret = x509_name_canon(a); ++ if (ret < 0) ++ return ret; ++ } ++ ret = a->bytes->length; ++ if (out != NULL) { ++ memcpy(*out, a->bytes->data, ret); ++ *out += ret; ++ } ++ return ret; ++} ++ ++static int x509_name_encode(X509_NAME *a) ++{ ++ union { ++ STACK_OF(STACK_OF_X509_NAME_ENTRY) *s; ++ ASN1_VALUE *a; ++ } intname = { ++ NULL ++ }; ++ int len; ++ unsigned char *p; ++ STACK_OF(X509_NAME_ENTRY) *entries = NULL; ++ X509_NAME_ENTRY *entry; ++ int i, set = -1; ++ intname.s = sk_STACK_OF_X509_NAME_ENTRY_new_null(); ++ if (!intname.s) ++ goto memerr; ++ for (i = 0; i < sk_X509_NAME_ENTRY_num(a->entries); i++) { ++ entry = sk_X509_NAME_ENTRY_value(a->entries, i); ++ if (entry->set != set) { ++ entries = sk_X509_NAME_ENTRY_new_null(); ++ if (!entries) ++ goto memerr; ++ if (!sk_STACK_OF_X509_NAME_ENTRY_push(intname.s, entries)) { ++ sk_X509_NAME_ENTRY_free(entries); ++ goto memerr; ++ } ++ set = entry->set; ++ } ++ if (!sk_X509_NAME_ENTRY_push(entries, entry)) ++ goto memerr; ++ } ++ len = ASN1_item_ex_i2d(&intname.a, NULL, ++ ASN1_ITEM_rptr(X509_NAME_INTERNAL), -1, -1); ++ if (!BUF_MEM_grow(a->bytes, len)) ++ goto memerr; ++ p = (unsigned char *)a->bytes->data; ++ ASN1_item_ex_i2d(&intname.a, ++ &p, ASN1_ITEM_rptr(X509_NAME_INTERNAL), -1, -1); ++ sk_STACK_OF_X509_NAME_ENTRY_pop_free(intname.s, ++ local_sk_X509_NAME_ENTRY_free); ++ a->modified = 0; ++ return len; ++ memerr: ++ sk_STACK_OF_X509_NAME_ENTRY_pop_free(intname.s, ++ local_sk_X509_NAME_ENTRY_free); ++ ASN1err(ASN1_F_X509_NAME_ENCODE, ERR_R_MALLOC_FAILURE); ++ return -1; ++} ++ ++static int x509_name_ex_print(BIO *out, ASN1_VALUE **pval, ++ int indent, ++ const char *fname, const ASN1_PCTX *pctx) ++{ ++ if (X509_NAME_print_ex(out, (const X509_NAME *)*pval, ++ indent, pctx->nm_flags) <= 0) ++ return 0; ++ return 2; ++} ++ ++/* ++ * This function generates the canonical encoding of the Name structure. In ++ * it all strings are converted to UTF8, leading, trailing and multiple ++ * spaces collapsed, converted to lower case and the leading SEQUENCE header ++ * removed. In future we could also normalize the UTF8 too. By doing this ++ * comparison of Name structures can be rapidly performed by just using ++ * memcmp() of the canonical encoding. By omitting the leading SEQUENCE name ++ * constraints of type dirName can also be checked with a simple memcmp(). ++ */ ++ ++static int x509_name_canon(X509_NAME *a) ++{ ++ unsigned char *p; ++ STACK_OF(STACK_OF_X509_NAME_ENTRY) *intname = NULL; ++ STACK_OF(X509_NAME_ENTRY) *entries = NULL; ++ X509_NAME_ENTRY *entry, *tmpentry = NULL; ++ int i, set = -1, ret = 0, len; ++ ++ OPENSSL_free(a->canon_enc); ++ a->canon_enc = NULL; ++ /* Special case: empty X509_NAME => null encoding */ ++ if (sk_X509_NAME_ENTRY_num(a->entries) == 0) { ++ a->canon_enclen = 0; ++ return 1; ++ } ++ intname = sk_STACK_OF_X509_NAME_ENTRY_new_null(); ++ if (!intname) ++ goto err; ++ for (i = 0; i < sk_X509_NAME_ENTRY_num(a->entries); i++) { ++ entry = sk_X509_NAME_ENTRY_value(a->entries, i); ++ if (entry->set != set) { ++ entries = sk_X509_NAME_ENTRY_new_null(); ++ if (!entries) ++ goto err; ++ if (!sk_STACK_OF_X509_NAME_ENTRY_push(intname, entries)) { ++ sk_X509_NAME_ENTRY_free(entries); ++ goto err; ++ } ++ set = entry->set; ++ } ++ tmpentry = X509_NAME_ENTRY_new(); ++ if (tmpentry == NULL) ++ goto err; ++ tmpentry->object = OBJ_dup(entry->object); ++ if (tmpentry->object == NULL) ++ goto err; ++ if (!asn1_string_canon(tmpentry->value, entry->value)) ++ goto err; ++ if (!sk_X509_NAME_ENTRY_push(entries, tmpentry)) ++ goto err; ++ tmpentry = NULL; ++ } ++ ++ /* Finally generate encoding */ ++ ++ len = i2d_name_canon(intname, NULL); ++ if (len < 0) ++ goto err; ++ a->canon_enclen = len; ++ ++ p = OPENSSL_malloc(a->canon_enclen); ++ ++ if (p == NULL) ++ goto err; ++ ++ a->canon_enc = p; ++ ++ i2d_name_canon(intname, &p); ++ ++ ret = 1; ++ ++ err: ++ ++ X509_NAME_ENTRY_free(tmpentry); ++ sk_STACK_OF_X509_NAME_ENTRY_pop_free(intname, ++ local_sk_X509_NAME_ENTRY_pop_free); ++ return ret; ++} ++ ++/* Bitmap of all the types of string that will be canonicalized. */ ++ ++#define ASN1_MASK_CANON \ ++ (B_ASN1_UTF8STRING | B_ASN1_BMPSTRING | B_ASN1_UNIVERSALSTRING \ ++ | B_ASN1_PRINTABLESTRING | B_ASN1_T61STRING | B_ASN1_IA5STRING \ ++ | B_ASN1_VISIBLESTRING) ++ ++static int asn1_string_canon(ASN1_STRING *out, const ASN1_STRING *in) ++{ ++ unsigned char *to, *from; ++ int len, i; ++ ++ /* If type not in bitmask just copy string across */ ++ if (!(ASN1_tag2bit(in->type) & ASN1_MASK_CANON)) { ++ if (!ASN1_STRING_copy(out, in)) ++ return 0; ++ return 1; ++ } ++ ++ out->type = V_ASN1_UTF8STRING; ++ out->length = ASN1_STRING_to_UTF8(&out->data, in); ++ if (out->length == -1) ++ return 0; ++ ++ to = out->data; ++ from = to; ++ ++ len = out->length; ++ ++ /* ++ * Convert string in place to canonical form. Ultimately we may need to ++ * handle a wider range of characters but for now ignore anything with ++ * MSB set and rely on the isspace() and tolower() functions. ++ */ ++ ++ /* Ignore leading spaces */ ++ while ((len > 0) && !(*from & 0x80) && isspace(*from)) { ++ from++; ++ len--; ++ } ++ ++ to = from + len; ++ ++ /* Ignore trailing spaces */ ++ while ((len > 0) && !(to[-1] & 0x80) && isspace(to[-1])) { ++ to--; ++ len--; ++ } ++ ++ to = out->data; ++ ++ i = 0; ++ while (i < len) { ++ /* If MSB set just copy across */ ++ if (*from & 0x80) { ++ *to++ = *from++; ++ i++; ++ } ++ /* Collapse multiple spaces */ ++ else if (isspace(*from)) { ++ /* Copy one space across */ ++ *to++ = ' '; ++ /* ++ * Ignore subsequent spaces. Note: don't need to check len here ++ * because we know the last character is a non-space so we can't ++ * overflow. ++ */ ++ do { ++ from++; ++ i++; ++ } ++ while (!(*from & 0x80) && isspace(*from)); ++ } else { ++ *to++ = tolower(*from); ++ from++; ++ i++; ++ } ++ } ++ ++ out->length = to - out->data; ++ ++ return 1; ++ ++} ++ ++static int i2d_name_canon(STACK_OF(STACK_OF_X509_NAME_ENTRY) * _intname, ++ unsigned char **in) ++{ ++ int i, len, ltmp; ++ ASN1_VALUE *v; ++ STACK_OF(ASN1_VALUE) *intname = (STACK_OF(ASN1_VALUE) *)_intname; ++ ++ len = 0; ++ for (i = 0; i < sk_ASN1_VALUE_num(intname); i++) { ++ v = sk_ASN1_VALUE_value(intname, i); ++ ltmp = ASN1_item_ex_i2d(&v, in, ++ ASN1_ITEM_rptr(X509_NAME_ENTRIES), -1, -1); ++ if (ltmp < 0) ++ return ltmp; ++ len += ltmp; ++ } ++ return len; ++} ++ ++int X509_NAME_set(X509_NAME **xn, X509_NAME *name) ++{ ++ X509_NAME *in; ++ ++ if (!xn || !name) ++ return (0); ++ ++ if (*xn != name) { ++ in = X509_NAME_dup(name); ++ if (in != NULL) { ++ X509_NAME_free(*xn); ++ *xn = in; ++ } ++ } ++ return (*xn != NULL); ++} ++ ++int X509_NAME_print(BIO *bp, const X509_NAME *name, int obase) ++{ ++ char *s, *c, *b; ++ int l, i; ++ ++ l = 80 - 2 - obase; ++ ++ b = X509_NAME_oneline(name, NULL, 0); ++ if (!b) ++ return 0; ++ if (!*b) { ++ OPENSSL_free(b); ++ return 1; ++ } ++ s = b + 1; /* skip the first slash */ ++ ++ c = s; ++ for (;;) { ++#ifndef CHARSET_EBCDIC ++ if (((*s == '/') && ++ ((s[1] >= 'A') && (s[1] <= 'Z') && ((s[2] == '=') || ++ ((s[2] >= 'A') ++ && (s[2] <= 'Z') ++ && (s[3] == '=')) ++ ))) || (*s == '\0')) ++#else ++ if (((*s == '/') && ++ (isupper(s[1]) && ((s[2] == '=') || ++ (isupper(s[2]) && (s[3] == '=')) ++ ))) || (*s == '\0')) ++#endif ++ { ++ i = s - c; ++ if (BIO_write(bp, c, i) != i) ++ goto err; ++ c = s + 1; /* skip following slash */ ++ if (*s != '\0') { ++ if (BIO_write(bp, ", ", 2) != 2) ++ goto err; ++ } ++ l--; ++ } ++ if (*s == '\0') ++ break; ++ s++; ++ l--; ++ } ++ ++ OPENSSL_free(b); ++ return 1; ++ err: ++ X509err(X509_F_X509_NAME_PRINT, ERR_R_BUF_LIB); ++ OPENSSL_free(b); ++ return 0; ++} ++ ++int X509_NAME_get0_der(X509_NAME *nm, const unsigned char **pder, ++ size_t *pderlen) ++{ ++ /* Make sure encoding is valid */ ++ if (i2d_X509_NAME(nm, NULL) <= 0) ++ return 0; ++ if (pder != NULL) ++ *pder = (unsigned char *)nm->bytes->data; ++ if (pderlen != NULL) ++ *pderlen = nm->bytes->length; ++ return 1; ++} +diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/x509/x_pubkey.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/x509/x_pubkey.c +new file mode 100644 +index 0000000..cc69283 +--- /dev/null ++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/x509/x_pubkey.c +@@ -0,0 +1,374 @@ ++/* ++ * Copyright 1995-2016 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 ++ * in the file LICENSE in the source distribution or at ++ * https://www.openssl.org/source/license.html ++ */ ++ ++#include ++#include "internal/cryptlib.h" ++#include ++#include ++#include "internal/asn1_int.h" ++#include "internal/evp_int.h" ++#include "internal/x509_int.h" ++#include ++#include ++ ++struct X509_pubkey_st { ++ X509_ALGOR *algor; ++ ASN1_BIT_STRING *public_key; ++ EVP_PKEY *pkey; ++}; ++ ++static int x509_pubkey_decode(EVP_PKEY **pk, X509_PUBKEY *key); ++ ++/* Minor tweak to operation: free up EVP_PKEY */ ++static int pubkey_cb(int operation, ASN1_VALUE **pval, const ASN1_ITEM *it, ++ void *exarg) ++{ ++ if (operation == ASN1_OP_FREE_POST) { ++ X509_PUBKEY *pubkey = (X509_PUBKEY *)*pval; ++ EVP_PKEY_free(pubkey->pkey); ++ } else if (operation == ASN1_OP_D2I_POST) { ++ /* Attempt to decode public key and cache in pubkey structure. */ ++ X509_PUBKEY *pubkey = (X509_PUBKEY *)*pval; ++ EVP_PKEY_free(pubkey->pkey); ++ /* ++ * Opportunistically decode the key but remove any non fatal errors ++ * from the queue. Subsequent explicit attempts to decode/use the key ++ * will return an appropriate error. ++ */ ++ ERR_set_mark(); ++ if (x509_pubkey_decode(&pubkey->pkey, pubkey) == -1) ++ return 0; ++ ERR_pop_to_mark(); ++ } ++ return 1; ++} ++ ++ASN1_SEQUENCE_cb(X509_PUBKEY, pubkey_cb) = { ++ ASN1_SIMPLE(X509_PUBKEY, algor, X509_ALGOR), ++ ASN1_SIMPLE(X509_PUBKEY, public_key, ASN1_BIT_STRING) ++} ASN1_SEQUENCE_END_cb(X509_PUBKEY, X509_PUBKEY) ++ ++IMPLEMENT_ASN1_FUNCTIONS(X509_PUBKEY) ++ ++int X509_PUBKEY_set(X509_PUBKEY **x, EVP_PKEY *pkey) ++{ ++ X509_PUBKEY *pk = NULL; ++ ++ if (x == NULL) ++ return (0); ++ ++ if ((pk = X509_PUBKEY_new()) == NULL) ++ goto error; ++ ++ if (pkey->ameth) { ++ if (pkey->ameth->pub_encode) { ++ if (!pkey->ameth->pub_encode(pk, pkey)) { ++ X509err(X509_F_X509_PUBKEY_SET, ++ X509_R_PUBLIC_KEY_ENCODE_ERROR); ++ goto error; ++ } ++ } else { ++ X509err(X509_F_X509_PUBKEY_SET, X509_R_METHOD_NOT_SUPPORTED); ++ goto error; ++ } ++ } else { ++ X509err(X509_F_X509_PUBKEY_SET, X509_R_UNSUPPORTED_ALGORITHM); ++ goto error; ++ } ++ ++ X509_PUBKEY_free(*x); ++ *x = pk; ++ pk->pkey = pkey; ++ EVP_PKEY_up_ref(pkey); ++ return 1; ++ ++ error: ++ X509_PUBKEY_free(pk); ++ return 0; ++} ++ ++/* ++ * Attempt to decode a public key. ++ * Returns 1 on success, 0 for a decode failure and -1 for a fatal ++ * error e.g. malloc failure. ++ */ ++ ++ ++static int x509_pubkey_decode(EVP_PKEY **ppkey, X509_PUBKEY *key) ++ { ++ EVP_PKEY *pkey = EVP_PKEY_new(); ++ ++ if (pkey == NULL) { ++ X509err(X509_F_X509_PUBKEY_DECODE, ERR_R_MALLOC_FAILURE); ++ return -1; ++ } ++ ++ if (!EVP_PKEY_set_type(pkey, OBJ_obj2nid(key->algor->algorithm))) { ++ X509err(X509_F_X509_PUBKEY_DECODE, X509_R_UNSUPPORTED_ALGORITHM); ++ goto error; ++ } ++ ++ if (pkey->ameth->pub_decode) { ++ /* ++ * Treat any failure of pub_decode as a decode error. In ++ * future we could have different return codes for decode ++ * errors and fatal errors such as malloc failure. ++ */ ++ if (!pkey->ameth->pub_decode(pkey, key)) { ++ X509err(X509_F_X509_PUBKEY_DECODE, X509_R_PUBLIC_KEY_DECODE_ERROR); ++ goto error; ++ } ++ } else { ++ X509err(X509_F_X509_PUBKEY_DECODE, X509_R_METHOD_NOT_SUPPORTED); ++ goto error; ++ } ++ ++ *ppkey = pkey; ++ return 1; ++ ++ error: ++ EVP_PKEY_free(pkey); ++ return 0; ++} ++ ++EVP_PKEY *X509_PUBKEY_get0(X509_PUBKEY *key) ++{ ++ EVP_PKEY *ret = NULL; ++ ++ if (key == NULL || key->public_key == NULL) ++ return NULL; ++ ++ if (key->pkey != NULL) ++ return key->pkey; ++ ++ /* ++ * When the key ASN.1 is initially parsed an attempt is made to ++ * decode the public key and cache the EVP_PKEY structure. If this ++ * operation fails the cached value will be NULL. Parsing continues ++ * to allow parsing of unknown key types or unsupported forms. ++ * We repeat the decode operation so the appropriate errors are left ++ * in the queue. ++ */ ++ x509_pubkey_decode(&ret, key); ++ /* If decode doesn't fail something bad happened */ ++ if (ret != NULL) { ++ X509err(X509_F_X509_PUBKEY_GET0, ERR_R_INTERNAL_ERROR); ++ EVP_PKEY_free(ret); ++ } ++ ++ return NULL; ++} ++ ++EVP_PKEY *X509_PUBKEY_get(X509_PUBKEY *key) ++{ ++ EVP_PKEY *ret = X509_PUBKEY_get0(key); ++ if (ret != NULL) ++ EVP_PKEY_up_ref(ret); ++ return ret; ++} ++ ++/* ++ * Now two pseudo ASN1 routines that take an EVP_PKEY structure and encode or ++ * decode as X509_PUBKEY ++ */ ++ ++EVP_PKEY *d2i_PUBKEY(EVP_PKEY **a, const unsigned char **pp, long length) ++{ ++ X509_PUBKEY *xpk; ++ EVP_PKEY *pktmp; ++ const unsigned char *q; ++ q = *pp; ++ xpk = d2i_X509_PUBKEY(NULL, &q, length); ++ if (!xpk) ++ return NULL; ++ pktmp = X509_PUBKEY_get(xpk); ++ X509_PUBKEY_free(xpk); ++ if (!pktmp) ++ return NULL; ++ *pp = q; ++ if (a) { ++ EVP_PKEY_free(*a); ++ *a = pktmp; ++ } ++ return pktmp; ++} ++ ++int i2d_PUBKEY(EVP_PKEY *a, unsigned char **pp) ++{ ++ X509_PUBKEY *xpk = NULL; ++ int ret; ++ if (!a) ++ return 0; ++ if (!X509_PUBKEY_set(&xpk, a)) ++ return 0; ++ ret = i2d_X509_PUBKEY(xpk, pp); ++ X509_PUBKEY_free(xpk); ++ return ret; ++} ++ ++/* ++ * The following are equivalents but which return RSA and DSA keys ++ */ ++#ifndef OPENSSL_NO_RSA ++RSA *d2i_RSA_PUBKEY(RSA **a, const unsigned char **pp, long length) ++{ ++ EVP_PKEY *pkey; ++ RSA *key; ++ const unsigned char *q; ++ q = *pp; ++ pkey = d2i_PUBKEY(NULL, &q, length); ++ if (!pkey) ++ return NULL; ++ key = EVP_PKEY_get1_RSA(pkey); ++ EVP_PKEY_free(pkey); ++ if (!key) ++ return NULL; ++ *pp = q; ++ if (a) { ++ RSA_free(*a); ++ *a = key; ++ } ++ return key; ++} ++ ++int i2d_RSA_PUBKEY(RSA *a, unsigned char **pp) ++{ ++ EVP_PKEY *pktmp; ++ int ret; ++ if (!a) ++ return 0; ++ pktmp = EVP_PKEY_new(); ++ if (pktmp == NULL) { ++ ASN1err(ASN1_F_I2D_RSA_PUBKEY, ERR_R_MALLOC_FAILURE); ++ return 0; ++ } ++ EVP_PKEY_set1_RSA(pktmp, a); ++ ret = i2d_PUBKEY(pktmp, pp); ++ EVP_PKEY_free(pktmp); ++ return ret; ++} ++#endif ++ ++#ifndef OPENSSL_NO_DSA ++DSA *d2i_DSA_PUBKEY(DSA **a, const unsigned char **pp, long length) ++{ ++ EVP_PKEY *pkey; ++ DSA *key; ++ const unsigned char *q; ++ q = *pp; ++ pkey = d2i_PUBKEY(NULL, &q, length); ++ if (!pkey) ++ return NULL; ++ key = EVP_PKEY_get1_DSA(pkey); ++ EVP_PKEY_free(pkey); ++ if (!key) ++ return NULL; ++ *pp = q; ++ if (a) { ++ DSA_free(*a); ++ *a = key; ++ } ++ return key; ++} ++ ++int i2d_DSA_PUBKEY(DSA *a, unsigned char **pp) ++{ ++ EVP_PKEY *pktmp; ++ int ret; ++ if (!a) ++ return 0; ++ pktmp = EVP_PKEY_new(); ++ if (pktmp == NULL) { ++ ASN1err(ASN1_F_I2D_DSA_PUBKEY, ERR_R_MALLOC_FAILURE); ++ return 0; ++ } ++ EVP_PKEY_set1_DSA(pktmp, a); ++ ret = i2d_PUBKEY(pktmp, pp); ++ EVP_PKEY_free(pktmp); ++ return ret; ++} ++#endif ++ ++#ifndef OPENSSL_NO_EC ++EC_KEY *d2i_EC_PUBKEY(EC_KEY **a, const unsigned char **pp, long length) ++{ ++ EVP_PKEY *pkey; ++ EC_KEY *key; ++ const unsigned char *q; ++ q = *pp; ++ pkey = d2i_PUBKEY(NULL, &q, length); ++ if (!pkey) ++ return (NULL); ++ key = EVP_PKEY_get1_EC_KEY(pkey); ++ EVP_PKEY_free(pkey); ++ if (!key) ++ return (NULL); ++ *pp = q; ++ if (a) { ++ EC_KEY_free(*a); ++ *a = key; ++ } ++ return (key); ++} ++ ++int i2d_EC_PUBKEY(EC_KEY *a, unsigned char **pp) ++{ ++ EVP_PKEY *pktmp; ++ int ret; ++ if (!a) ++ return (0); ++ if ((pktmp = EVP_PKEY_new()) == NULL) { ++ ASN1err(ASN1_F_I2D_EC_PUBKEY, ERR_R_MALLOC_FAILURE); ++ return (0); ++ } ++ EVP_PKEY_set1_EC_KEY(pktmp, a); ++ ret = i2d_PUBKEY(pktmp, pp); ++ EVP_PKEY_free(pktmp); ++ return (ret); ++} ++#endif ++ ++int X509_PUBKEY_set0_param(X509_PUBKEY *pub, ASN1_OBJECT *aobj, ++ int ptype, void *pval, ++ unsigned char *penc, int penclen) ++{ ++ if (!X509_ALGOR_set0(pub->algor, aobj, ptype, pval)) ++ return 0; ++ if (penc) { ++ OPENSSL_free(pub->public_key->data); ++ pub->public_key->data = penc; ++ pub->public_key->length = penclen; ++ /* Set number of unused bits to zero */ ++ pub->public_key->flags &= ~(ASN1_STRING_FLAG_BITS_LEFT | 0x07); ++ pub->public_key->flags |= ASN1_STRING_FLAG_BITS_LEFT; ++ } ++ return 1; ++} ++ ++int X509_PUBKEY_get0_param(ASN1_OBJECT **ppkalg, ++ const unsigned char **pk, int *ppklen, ++ X509_ALGOR **pa, X509_PUBKEY *pub) ++{ ++ if (ppkalg) ++ *ppkalg = pub->algor->algorithm; ++ if (pk) { ++ *pk = pub->public_key->data; ++ *ppklen = pub->public_key->length; ++ } ++ if (pa) ++ *pa = pub->algor; ++ return 1; ++} ++ ++ASN1_BIT_STRING *X509_get0_pubkey_bitstr(const X509 *x) ++{ ++ if (x == NULL) ++ return NULL; ++ return x->cert_info.key->public_key; ++} +diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/x509/x_req.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/x509/x_req.c +new file mode 100644 +index 0000000..c2da95a +--- /dev/null ++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/x509/x_req.c +@@ -0,0 +1,68 @@ ++/* ++ * Copyright 1995-2016 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 ++ * in the file LICENSE in the source distribution or at ++ * https://www.openssl.org/source/license.html ++ */ ++ ++#include ++#include "internal/cryptlib.h" ++#include ++#include ++#include "internal/x509_int.h" ++ ++/*- ++ * X509_REQ_INFO is handled in an unusual way to get round ++ * invalid encodings. Some broken certificate requests don't ++ * encode the attributes field if it is empty. This is in ++ * violation of PKCS#10 but we need to tolerate it. We do ++ * this by making the attributes field OPTIONAL then using ++ * the callback to initialise it to an empty STACK. ++ * ++ * This means that the field will be correctly encoded unless ++ * we NULL out the field. ++ * ++ * As a result we no longer need the req_kludge field because ++ * the information is now contained in the attributes field: ++ * 1. If it is NULL then it's the invalid omission. ++ * 2. If it is empty it is the correct encoding. ++ * 3. If it is not empty then some attributes are present. ++ * ++ */ ++ ++static int rinf_cb(int operation, ASN1_VALUE **pval, const ASN1_ITEM *it, ++ void *exarg) ++{ ++ X509_REQ_INFO *rinf = (X509_REQ_INFO *)*pval; ++ ++ if (operation == ASN1_OP_NEW_POST) { ++ rinf->attributes = sk_X509_ATTRIBUTE_new_null(); ++ if (!rinf->attributes) ++ return 0; ++ } ++ return 1; ++} ++ ++ASN1_SEQUENCE_enc(X509_REQ_INFO, enc, rinf_cb) = { ++ ASN1_SIMPLE(X509_REQ_INFO, version, ASN1_INTEGER), ++ ASN1_SIMPLE(X509_REQ_INFO, subject, X509_NAME), ++ ASN1_SIMPLE(X509_REQ_INFO, pubkey, X509_PUBKEY), ++ /* This isn't really OPTIONAL but it gets round invalid ++ * encodings ++ */ ++ ASN1_IMP_SET_OF_OPT(X509_REQ_INFO, attributes, X509_ATTRIBUTE, 0) ++} ASN1_SEQUENCE_END_enc(X509_REQ_INFO, X509_REQ_INFO) ++ ++IMPLEMENT_ASN1_FUNCTIONS(X509_REQ_INFO) ++ ++ASN1_SEQUENCE_ref(X509_REQ, 0) = { ++ ASN1_EMBED(X509_REQ, req_info, X509_REQ_INFO), ++ ASN1_EMBED(X509_REQ, sig_alg, X509_ALGOR), ++ ASN1_SIMPLE(X509_REQ, signature, ASN1_BIT_STRING) ++} ASN1_SEQUENCE_END_ref(X509_REQ, X509_REQ) ++ ++IMPLEMENT_ASN1_FUNCTIONS(X509_REQ) ++ ++IMPLEMENT_ASN1_DUP_FUNCTION(X509_REQ) +diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/x509/x_x509.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/x509/x_x509.c +new file mode 100644 +index 0000000..6783fd8 +--- /dev/null ++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/x509/x_x509.c +@@ -0,0 +1,224 @@ ++/* ++ * Copyright 1995-2016 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 ++ * in the file LICENSE in the source distribution or at ++ * https://www.openssl.org/source/license.html ++ */ ++ ++#include ++#include "internal/cryptlib.h" ++#include ++#include ++#include ++#include ++#include "internal/x509_int.h" ++ ++ASN1_SEQUENCE_enc(X509_CINF, enc, 0) = { ++ ASN1_EXP_OPT(X509_CINF, version, ASN1_INTEGER, 0), ++ ASN1_EMBED(X509_CINF, serialNumber, ASN1_INTEGER), ++ ASN1_EMBED(X509_CINF, signature, X509_ALGOR), ++ ASN1_SIMPLE(X509_CINF, issuer, X509_NAME), ++ ASN1_EMBED(X509_CINF, validity, X509_VAL), ++ ASN1_SIMPLE(X509_CINF, subject, X509_NAME), ++ ASN1_SIMPLE(X509_CINF, key, X509_PUBKEY), ++ ASN1_IMP_OPT(X509_CINF, issuerUID, ASN1_BIT_STRING, 1), ++ ASN1_IMP_OPT(X509_CINF, subjectUID, ASN1_BIT_STRING, 2), ++ ASN1_EXP_SEQUENCE_OF_OPT(X509_CINF, extensions, X509_EXTENSION, 3) ++} ASN1_SEQUENCE_END_enc(X509_CINF, X509_CINF) ++ ++IMPLEMENT_ASN1_FUNCTIONS(X509_CINF) ++/* X509 top level structure needs a bit of customisation */ ++ ++extern void policy_cache_free(X509_POLICY_CACHE *cache); ++ ++static int x509_cb(int operation, ASN1_VALUE **pval, const ASN1_ITEM *it, ++ void *exarg) ++{ ++ X509 *ret = (X509 *)*pval; ++ ++ switch (operation) { ++ ++ case ASN1_OP_NEW_POST: ++ ret->ex_flags = 0; ++ ret->ex_pathlen = -1; ++ ret->ex_pcpathlen = -1; ++ ret->skid = NULL; ++ ret->akid = NULL; ++#ifndef OPENSSL_NO_RFC3779 ++ ret->rfc3779_addr = NULL; ++ ret->rfc3779_asid = NULL; ++#endif ++ ret->aux = NULL; ++ ret->crldp = NULL; ++ if (!CRYPTO_new_ex_data(CRYPTO_EX_INDEX_X509, ret, &ret->ex_data)) ++ return 0; ++ break; ++ ++ case ASN1_OP_FREE_POST: ++ CRYPTO_free_ex_data(CRYPTO_EX_INDEX_X509, ret, &ret->ex_data); ++ X509_CERT_AUX_free(ret->aux); ++ ASN1_OCTET_STRING_free(ret->skid); ++ AUTHORITY_KEYID_free(ret->akid); ++ CRL_DIST_POINTS_free(ret->crldp); ++ policy_cache_free(ret->policy_cache); ++ GENERAL_NAMES_free(ret->altname); ++ NAME_CONSTRAINTS_free(ret->nc); ++#ifndef OPENSSL_NO_RFC3779 ++ sk_IPAddressFamily_pop_free(ret->rfc3779_addr, IPAddressFamily_free); ++ ASIdentifiers_free(ret->rfc3779_asid); ++#endif ++ break; ++ ++ } ++ ++ return 1; ++ ++} ++ ++ASN1_SEQUENCE_ref(X509, x509_cb) = { ++ ASN1_EMBED(X509, cert_info, X509_CINF), ++ ASN1_EMBED(X509, sig_alg, X509_ALGOR), ++ ASN1_EMBED(X509, signature, ASN1_BIT_STRING) ++} ASN1_SEQUENCE_END_ref(X509, X509) ++ ++IMPLEMENT_ASN1_FUNCTIONS(X509) ++ ++IMPLEMENT_ASN1_DUP_FUNCTION(X509) ++ ++int X509_set_ex_data(X509 *r, int idx, void *arg) ++{ ++ return (CRYPTO_set_ex_data(&r->ex_data, idx, arg)); ++} ++ ++void *X509_get_ex_data(X509 *r, int idx) ++{ ++ return (CRYPTO_get_ex_data(&r->ex_data, idx)); ++} ++ ++/* ++ * X509_AUX ASN1 routines. X509_AUX is the name given to a certificate with ++ * extra info tagged on the end. Since these functions set how a certificate ++ * is trusted they should only be used when the certificate comes from a ++ * reliable source such as local storage. ++ */ ++ ++X509 *d2i_X509_AUX(X509 **a, const unsigned char **pp, long length) ++{ ++ const unsigned char *q; ++ X509 *ret; ++ int freeret = 0; ++ ++ /* Save start position */ ++ q = *pp; ++ ++ if (a == NULL || *a == NULL) ++ freeret = 1; ++ ret = d2i_X509(a, &q, length); ++ /* If certificate unreadable then forget it */ ++ if (ret == NULL) ++ return NULL; ++ /* update length */ ++ length -= q - *pp; ++ if (length > 0 && !d2i_X509_CERT_AUX(&ret->aux, &q, length)) ++ goto err; ++ *pp = q; ++ return ret; ++ err: ++ if (freeret) { ++ X509_free(ret); ++ if (a) ++ *a = NULL; ++ } ++ return NULL; ++} ++ ++/* ++ * Serialize trusted certificate to *pp or just return the required buffer ++ * length if pp == NULL. We ultimately want to avoid modifying *pp in the ++ * error path, but that depends on similar hygiene in lower-level functions. ++ * Here we avoid compounding the problem. ++ */ ++static int i2d_x509_aux_internal(X509 *a, unsigned char **pp) ++{ ++ int length, tmplen; ++ unsigned char *start = pp != NULL ? *pp : NULL; ++ ++ OPENSSL_assert(pp == NULL || *pp != NULL); ++ ++ /* ++ * This might perturb *pp on error, but fixing that belongs in i2d_X509() ++ * not here. It should be that if a == NULL length is zero, but we check ++ * both just in case. ++ */ ++ length = i2d_X509(a, pp); ++ if (length <= 0 || a == NULL) ++ return length; ++ ++ tmplen = i2d_X509_CERT_AUX(a->aux, pp); ++ if (tmplen < 0) { ++ if (start != NULL) ++ *pp = start; ++ return tmplen; ++ } ++ length += tmplen; ++ ++ return length; ++} ++ ++/* ++ * Serialize trusted certificate to *pp, or just return the required buffer ++ * length if pp == NULL. ++ * ++ * When pp is not NULL, but *pp == NULL, we allocate the buffer, but since ++ * we're writing two ASN.1 objects back to back, we can't have i2d_X509() do ++ * the allocation, nor can we allow i2d_X509_CERT_AUX() to increment the ++ * allocated buffer. ++ */ ++int i2d_X509_AUX(X509 *a, unsigned char **pp) ++{ ++ int length; ++ unsigned char *tmp; ++ ++ /* Buffer provided by caller */ ++ if (pp == NULL || *pp != NULL) ++ return i2d_x509_aux_internal(a, pp); ++ ++ /* Obtain the combined length */ ++ if ((length = i2d_x509_aux_internal(a, NULL)) <= 0) ++ return length; ++ ++ /* Allocate requisite combined storage */ ++ *pp = tmp = OPENSSL_malloc(length); ++ if (tmp == NULL) ++ return -1; /* Push error onto error stack? */ ++ ++ /* Encode, but keep *pp at the originally malloced pointer */ ++ length = i2d_x509_aux_internal(a, &tmp); ++ if (length <= 0) { ++ OPENSSL_free(*pp); ++ *pp = NULL; ++ } ++ return length; ++} ++ ++int i2d_re_X509_tbs(X509 *x, unsigned char **pp) ++{ ++ x->cert_info.enc.modified = 1; ++ return i2d_X509_CINF(&x->cert_info, pp); ++} ++ ++void X509_get0_signature(const ASN1_BIT_STRING **psig, ++ const X509_ALGOR **palg, const X509 *x) ++{ ++ if (psig) ++ *psig = &x->signature; ++ if (palg) ++ *palg = &x->sig_alg; ++} ++ ++int X509_get_signature_nid(const X509 *x) ++{ ++ return OBJ_obj2nid(x->sig_alg.algorithm); ++} +diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/x509/x_x509a.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/x509/x_x509a.c +new file mode 100644 +index 0000000..8c9ad71 +--- /dev/null ++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/x509/x_x509a.c +@@ -0,0 +1,169 @@ ++/* ++ * Copyright 1999-2016 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 ++ * in the file LICENSE in the source distribution or at ++ * https://www.openssl.org/source/license.html ++ */ ++ ++#include ++#include "internal/cryptlib.h" ++#include ++#include ++#include ++#include "internal/x509_int.h" ++ ++/* ++ * X509_CERT_AUX routines. These are used to encode additional user ++ * modifiable data about a certificate. This data is appended to the X509 ++ * encoding when the *_X509_AUX routines are used. This means that the ++ * "traditional" X509 routines will simply ignore the extra data. ++ */ ++ ++static X509_CERT_AUX *aux_get(X509 *x); ++ ++ASN1_SEQUENCE(X509_CERT_AUX) = { ++ ASN1_SEQUENCE_OF_OPT(X509_CERT_AUX, trust, ASN1_OBJECT), ++ ASN1_IMP_SEQUENCE_OF_OPT(X509_CERT_AUX, reject, ASN1_OBJECT, 0), ++ ASN1_OPT(X509_CERT_AUX, alias, ASN1_UTF8STRING), ++ ASN1_OPT(X509_CERT_AUX, keyid, ASN1_OCTET_STRING), ++ ASN1_IMP_SEQUENCE_OF_OPT(X509_CERT_AUX, other, X509_ALGOR, 1) ++} ASN1_SEQUENCE_END(X509_CERT_AUX) ++ ++IMPLEMENT_ASN1_FUNCTIONS(X509_CERT_AUX) ++ ++int X509_trusted(const X509 *x) ++{ ++ return x->aux ? 1 : 0; ++} ++ ++static X509_CERT_AUX *aux_get(X509 *x) ++{ ++ if (x == NULL) ++ return NULL; ++ if (x->aux == NULL && (x->aux = X509_CERT_AUX_new()) == NULL) ++ return NULL; ++ return x->aux; ++} ++ ++int X509_alias_set1(X509 *x, const unsigned char *name, int len) ++{ ++ X509_CERT_AUX *aux; ++ if (!name) { ++ if (!x || !x->aux || !x->aux->alias) ++ return 1; ++ ASN1_UTF8STRING_free(x->aux->alias); ++ x->aux->alias = NULL; ++ return 1; ++ } ++ if ((aux = aux_get(x)) == NULL) ++ return 0; ++ if (aux->alias == NULL && (aux->alias = ASN1_UTF8STRING_new()) == NULL) ++ return 0; ++ return ASN1_STRING_set(aux->alias, name, len); ++} ++ ++int X509_keyid_set1(X509 *x, const unsigned char *id, int len) ++{ ++ X509_CERT_AUX *aux; ++ if (!id) { ++ if (!x || !x->aux || !x->aux->keyid) ++ return 1; ++ ASN1_OCTET_STRING_free(x->aux->keyid); ++ x->aux->keyid = NULL; ++ return 1; ++ } ++ if ((aux = aux_get(x)) == NULL) ++ return 0; ++ if (aux->keyid == NULL ++ && (aux->keyid = ASN1_OCTET_STRING_new()) == NULL) ++ return 0; ++ return ASN1_STRING_set(aux->keyid, id, len); ++} ++ ++unsigned char *X509_alias_get0(X509 *x, int *len) ++{ ++ if (!x->aux || !x->aux->alias) ++ return NULL; ++ if (len) ++ *len = x->aux->alias->length; ++ return x->aux->alias->data; ++} ++ ++unsigned char *X509_keyid_get0(X509 *x, int *len) ++{ ++ if (!x->aux || !x->aux->keyid) ++ return NULL; ++ if (len) ++ *len = x->aux->keyid->length; ++ return x->aux->keyid->data; ++} ++ ++int X509_add1_trust_object(X509 *x, const ASN1_OBJECT *obj) ++{ ++ X509_CERT_AUX *aux; ++ ASN1_OBJECT *objtmp = NULL; ++ if (obj) { ++ objtmp = OBJ_dup(obj); ++ if (!objtmp) ++ return 0; ++ } ++ if ((aux = aux_get(x)) == NULL) ++ goto err; ++ if (aux->trust == NULL ++ && (aux->trust = sk_ASN1_OBJECT_new_null()) == NULL) ++ goto err; ++ if (!objtmp || sk_ASN1_OBJECT_push(aux->trust, objtmp)) ++ return 1; ++ err: ++ ASN1_OBJECT_free(objtmp); ++ return 0; ++} ++ ++int X509_add1_reject_object(X509 *x, const ASN1_OBJECT *obj) ++{ ++ X509_CERT_AUX *aux; ++ ASN1_OBJECT *objtmp; ++ if ((objtmp = OBJ_dup(obj)) == NULL) ++ return 0; ++ if ((aux = aux_get(x)) == NULL) ++ goto err; ++ if (aux->reject == NULL ++ && (aux->reject = sk_ASN1_OBJECT_new_null()) == NULL) ++ goto err; ++ return sk_ASN1_OBJECT_push(aux->reject, objtmp); ++ err: ++ ASN1_OBJECT_free(objtmp); ++ return 0; ++} ++ ++void X509_trust_clear(X509 *x) ++{ ++ if (x->aux) { ++ sk_ASN1_OBJECT_pop_free(x->aux->trust, ASN1_OBJECT_free); ++ x->aux->trust = NULL; ++ } ++} ++ ++void X509_reject_clear(X509 *x) ++{ ++ if (x->aux) { ++ sk_ASN1_OBJECT_pop_free(x->aux->reject, ASN1_OBJECT_free); ++ x->aux->reject = NULL; ++ } ++} ++ ++STACK_OF(ASN1_OBJECT) *X509_get0_trust_objects(X509 *x) ++{ ++ if (x->aux != NULL) ++ return x->aux->trust; ++ return NULL; ++} ++ ++STACK_OF(ASN1_OBJECT) *X509_get0_reject_objects(X509 *x) ++{ ++ if (x->aux != NULL) ++ return x->aux->reject; ++ return NULL; ++} +diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/x509v3/build.info b/CryptoPkg/Library/OpensslLib/openssl/crypto/x509v3/build.info +new file mode 100644 +index 0000000..452a8b0 +--- /dev/null ++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/x509v3/build.info +@@ -0,0 +1,8 @@ ++LIBS=../../libcrypto ++SOURCE[../../libcrypto]=\ ++ v3_bcons.c v3_bitst.c v3_conf.c v3_extku.c v3_ia5.c v3_lib.c \ ++ v3_prn.c v3_utl.c v3err.c v3_genn.c v3_alt.c v3_skey.c v3_akey.c v3_pku.c \ ++ 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 +diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/x509v3/ext_dat.h b/CryptoPkg/Library/OpensslLib/openssl/crypto/x509v3/ext_dat.h +new file mode 100644 +index 0000000..c9ede96 +--- /dev/null ++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/x509v3/ext_dat.h +@@ -0,0 +1,24 @@ ++/* ++ * Copyright 1999-2016 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 ++ * in the file LICENSE in the source distribution or at ++ * https://www.openssl.org/source/license.html ++ */ ++ ++int name_cmp(const char *name, const char *cmp); ++ ++extern const X509V3_EXT_METHOD v3_bcons, v3_nscert, v3_key_usage, v3_ext_ku; ++extern const X509V3_EXT_METHOD v3_pkey_usage_period, v3_sxnet, v3_info, v3_sinfo; ++extern const X509V3_EXT_METHOD v3_ns_ia5_list[8], v3_alt[3], v3_skey_id, v3_akey_id; ++extern const X509V3_EXT_METHOD v3_crl_num, v3_crl_reason, v3_crl_invdate; ++extern const X509V3_EXT_METHOD v3_delta_crl, v3_cpols, v3_crld, v3_freshest_crl; ++extern const X509V3_EXT_METHOD v3_ocsp_nonce, v3_ocsp_accresp, v3_ocsp_acutoff; ++extern const X509V3_EXT_METHOD v3_ocsp_crlid, v3_ocsp_nocheck, v3_ocsp_serviceloc; ++extern const X509V3_EXT_METHOD v3_crl_hold, v3_pci; ++extern const X509V3_EXT_METHOD v3_policy_mappings, v3_policy_constraints; ++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_tls_feature; +diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/x509v3/pcy_cache.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/x509v3/pcy_cache.c +new file mode 100644 +index 0000000..a9ee30a +--- /dev/null ++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/x509v3/pcy_cache.c +@@ -0,0 +1,216 @@ ++/* ++ * Copyright 2004-2016 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 ++ * in the file LICENSE in the source distribution or at ++ * https://www.openssl.org/source/license.html ++ */ ++ ++#include "internal/cryptlib.h" ++#include ++#include ++#include "internal/x509_int.h" ++ ++#include "pcy_int.h" ++ ++static int policy_data_cmp(const X509_POLICY_DATA *const *a, ++ const X509_POLICY_DATA *const *b); ++static int policy_cache_set_int(long *out, ASN1_INTEGER *value); ++ ++/* ++ * Set cache entry according to CertificatePolicies extension. Note: this ++ * destroys the passed CERTIFICATEPOLICIES structure. ++ */ ++ ++static int policy_cache_create(X509 *x, ++ CERTIFICATEPOLICIES *policies, int crit) ++{ ++ int i; ++ int ret = 0; ++ X509_POLICY_CACHE *cache = x->policy_cache; ++ X509_POLICY_DATA *data = NULL; ++ POLICYINFO *policy; ++ if (sk_POLICYINFO_num(policies) == 0) ++ goto bad_policy; ++ cache->data = sk_X509_POLICY_DATA_new(policy_data_cmp); ++ if (cache->data == NULL) ++ goto bad_policy; ++ for (i = 0; i < sk_POLICYINFO_num(policies); i++) { ++ policy = sk_POLICYINFO_value(policies, i); ++ data = policy_data_new(policy, NULL, crit); ++ if (data == NULL) ++ goto bad_policy; ++ /* ++ * Duplicate policy OIDs are illegal: reject if matches found. ++ */ ++ if (OBJ_obj2nid(data->valid_policy) == NID_any_policy) { ++ if (cache->anyPolicy) { ++ ret = -1; ++ goto bad_policy; ++ } ++ cache->anyPolicy = data; ++ } else if (sk_X509_POLICY_DATA_find(cache->data, data) != -1) { ++ ret = -1; ++ goto bad_policy; ++ } else if (!sk_X509_POLICY_DATA_push(cache->data, data)) ++ goto bad_policy; ++ data = NULL; ++ } ++ ret = 1; ++ bad_policy: ++ if (ret == -1) ++ x->ex_flags |= EXFLAG_INVALID_POLICY; ++ policy_data_free(data); ++ sk_POLICYINFO_pop_free(policies, POLICYINFO_free); ++ if (ret <= 0) { ++ sk_X509_POLICY_DATA_pop_free(cache->data, policy_data_free); ++ cache->data = NULL; ++ } ++ return ret; ++} ++ ++static int policy_cache_new(X509 *x) ++{ ++ X509_POLICY_CACHE *cache; ++ ASN1_INTEGER *ext_any = NULL; ++ POLICY_CONSTRAINTS *ext_pcons = NULL; ++ CERTIFICATEPOLICIES *ext_cpols = NULL; ++ POLICY_MAPPINGS *ext_pmaps = NULL; ++ int i; ++ ++ if (x->policy_cache != NULL) ++ return 1; ++ cache = OPENSSL_malloc(sizeof(*cache)); ++ if (cache == NULL) ++ return 0; ++ cache->anyPolicy = NULL; ++ cache->data = NULL; ++ cache->any_skip = -1; ++ cache->explicit_skip = -1; ++ cache->map_skip = -1; ++ ++ x->policy_cache = cache; ++ ++ /* ++ * Handle requireExplicitPolicy *first*. Need to process this even if we ++ * don't have any policies. ++ */ ++ ext_pcons = X509_get_ext_d2i(x, NID_policy_constraints, &i, NULL); ++ ++ if (!ext_pcons) { ++ if (i != -1) ++ goto bad_cache; ++ } else { ++ if (!ext_pcons->requireExplicitPolicy ++ && !ext_pcons->inhibitPolicyMapping) ++ goto bad_cache; ++ if (!policy_cache_set_int(&cache->explicit_skip, ++ ext_pcons->requireExplicitPolicy)) ++ goto bad_cache; ++ if (!policy_cache_set_int(&cache->map_skip, ++ ext_pcons->inhibitPolicyMapping)) ++ goto bad_cache; ++ } ++ ++ /* Process CertificatePolicies */ ++ ++ ext_cpols = X509_get_ext_d2i(x, NID_certificate_policies, &i, NULL); ++ /* ++ * If no CertificatePolicies extension or problem decoding then there is ++ * no point continuing because the valid policies will be NULL. ++ */ ++ if (!ext_cpols) { ++ /* If not absent some problem with extension */ ++ if (i != -1) ++ goto bad_cache; ++ return 1; ++ } ++ ++ i = policy_cache_create(x, ext_cpols, i); ++ ++ /* NB: ext_cpols freed by policy_cache_set_policies */ ++ ++ if (i <= 0) ++ return i; ++ ++ ext_pmaps = X509_get_ext_d2i(x, NID_policy_mappings, &i, NULL); ++ ++ if (!ext_pmaps) { ++ /* If not absent some problem with extension */ ++ if (i != -1) ++ goto bad_cache; ++ } else { ++ i = policy_cache_set_mapping(x, ext_pmaps); ++ if (i <= 0) ++ goto bad_cache; ++ } ++ ++ ext_any = X509_get_ext_d2i(x, NID_inhibit_any_policy, &i, NULL); ++ ++ if (!ext_any) { ++ if (i != -1) ++ goto bad_cache; ++ } else if (!policy_cache_set_int(&cache->any_skip, ext_any)) ++ goto bad_cache; ++ goto just_cleanup; ++ ++ bad_cache: ++ x->ex_flags |= EXFLAG_INVALID_POLICY; ++ ++ just_cleanup: ++ POLICY_CONSTRAINTS_free(ext_pcons); ++ ASN1_INTEGER_free(ext_any); ++ return 1; ++ ++} ++ ++void policy_cache_free(X509_POLICY_CACHE *cache) ++{ ++ if (!cache) ++ return; ++ policy_data_free(cache->anyPolicy); ++ sk_X509_POLICY_DATA_pop_free(cache->data, policy_data_free); ++ OPENSSL_free(cache); ++} ++ ++const X509_POLICY_CACHE *policy_cache_set(X509 *x) ++{ ++ ++ if (x->policy_cache == NULL) { ++ CRYPTO_THREAD_write_lock(x->lock); ++ policy_cache_new(x); ++ CRYPTO_THREAD_unlock(x->lock); ++ } ++ ++ return x->policy_cache; ++ ++} ++ ++X509_POLICY_DATA *policy_cache_find_data(const X509_POLICY_CACHE *cache, ++ const ASN1_OBJECT *id) ++{ ++ int idx; ++ X509_POLICY_DATA tmp; ++ tmp.valid_policy = (ASN1_OBJECT *)id; ++ idx = sk_X509_POLICY_DATA_find(cache->data, &tmp); ++ if (idx == -1) ++ return NULL; ++ return sk_X509_POLICY_DATA_value(cache->data, idx); ++} ++ ++static int policy_data_cmp(const X509_POLICY_DATA *const *a, ++ const X509_POLICY_DATA *const *b) ++{ ++ return OBJ_cmp((*a)->valid_policy, (*b)->valid_policy); ++} ++ ++static int policy_cache_set_int(long *out, ASN1_INTEGER *value) ++{ ++ if (value == NULL) ++ return 1; ++ if (value->type == V_ASN1_NEG_INTEGER) ++ return 0; ++ *out = ASN1_INTEGER_get(value); ++ return 1; ++} +diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/x509v3/pcy_data.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/x509v3/pcy_data.c +new file mode 100644 +index 0000000..cf1d635 +--- /dev/null ++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/x509v3/pcy_data.c +@@ -0,0 +1,77 @@ ++/* ++ * Copyright 2004-2016 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 ++ * in the file LICENSE in the source distribution or at ++ * https://www.openssl.org/source/license.html ++ */ ++ ++#include "internal/cryptlib.h" ++#include ++#include ++ ++#include "pcy_int.h" ++ ++/* Policy Node routines */ ++ ++void policy_data_free(X509_POLICY_DATA *data) ++{ ++ if (!data) ++ return; ++ ASN1_OBJECT_free(data->valid_policy); ++ /* Don't free qualifiers if shared */ ++ if (!(data->flags & POLICY_DATA_FLAG_SHARED_QUALIFIERS)) ++ sk_POLICYQUALINFO_pop_free(data->qualifier_set, POLICYQUALINFO_free); ++ sk_ASN1_OBJECT_pop_free(data->expected_policy_set, ASN1_OBJECT_free); ++ OPENSSL_free(data); ++} ++ ++/* ++ * Create a data based on an existing policy. If 'id' is NULL use the OID in ++ * the policy, otherwise use 'id'. This behaviour covers the two types of ++ * data in RFC3280: data with from a CertificatePolicies extension and ++ * additional data with just the qualifiers of anyPolicy and ID from another ++ * source. ++ */ ++ ++X509_POLICY_DATA *policy_data_new(POLICYINFO *policy, ++ const ASN1_OBJECT *cid, int crit) ++{ ++ X509_POLICY_DATA *ret; ++ ASN1_OBJECT *id; ++ if (!policy && !cid) ++ return NULL; ++ if (cid) { ++ id = OBJ_dup(cid); ++ if (!id) ++ return NULL; ++ } else ++ id = NULL; ++ ret = OPENSSL_zalloc(sizeof(*ret)); ++ if (ret == NULL) ++ return NULL; ++ ret->expected_policy_set = sk_ASN1_OBJECT_new_null(); ++ if (ret->expected_policy_set == NULL) { ++ OPENSSL_free(ret); ++ ASN1_OBJECT_free(id); ++ return NULL; ++ } ++ ++ if (crit) ++ ret->flags = POLICY_DATA_FLAG_CRITICAL; ++ ++ if (id) ++ ret->valid_policy = id; ++ else { ++ ret->valid_policy = policy->policyid; ++ policy->policyid = NULL; ++ } ++ ++ if (policy) { ++ ret->qualifier_set = policy->qualifiers; ++ policy->qualifiers = NULL; ++ } ++ ++ return ret; ++} +diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/x509v3/pcy_int.h b/CryptoPkg/Library/OpensslLib/openssl/crypto/x509v3/pcy_int.h +new file mode 100644 +index 0000000..5daf78d +--- /dev/null ++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/x509v3/pcy_int.h +@@ -0,0 +1,167 @@ ++/* ++ * Copyright 2004-2016 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 ++ * in the file LICENSE in the source distribution or at ++ * https://www.openssl.org/source/license.html ++ */ ++ ++typedef struct X509_POLICY_DATA_st X509_POLICY_DATA; ++ ++DEFINE_STACK_OF(X509_POLICY_DATA) ++ ++/* Internal structures */ ++ ++/* ++ * This structure and the field names correspond to the Policy 'node' of ++ * RFC3280. NB this structure contains no pointers to parent or child data: ++ * X509_POLICY_NODE contains that. This means that the main policy data can ++ * be kept static and cached with the certificate. ++ */ ++ ++struct X509_POLICY_DATA_st { ++ unsigned int flags; ++ /* Policy OID and qualifiers for this data */ ++ ASN1_OBJECT *valid_policy; ++ STACK_OF(POLICYQUALINFO) *qualifier_set; ++ STACK_OF(ASN1_OBJECT) *expected_policy_set; ++}; ++ ++/* X509_POLICY_DATA flags values */ ++ ++/* ++ * This flag indicates the structure has been mapped using a policy mapping ++ * extension. If policy mapping is not active its references get deleted. ++ */ ++ ++#define POLICY_DATA_FLAG_MAPPED 0x1 ++ ++/* ++ * This flag indicates the data doesn't correspond to a policy in Certificate ++ * Policies: it has been mapped to any policy. ++ */ ++ ++#define POLICY_DATA_FLAG_MAPPED_ANY 0x2 ++ ++/* AND with flags to see if any mapping has occurred */ ++ ++#define POLICY_DATA_FLAG_MAP_MASK 0x3 ++ ++/* qualifiers are shared and shouldn't be freed */ ++ ++#define POLICY_DATA_FLAG_SHARED_QUALIFIERS 0x4 ++ ++/* Parent node is an extra node and should be freed */ ++ ++#define POLICY_DATA_FLAG_EXTRA_NODE 0x8 ++ ++/* Corresponding CertificatePolicies is critical */ ++ ++#define POLICY_DATA_FLAG_CRITICAL 0x10 ++ ++/* This structure is cached with a certificate */ ++ ++struct X509_POLICY_CACHE_st { ++ /* anyPolicy data or NULL if no anyPolicy */ ++ X509_POLICY_DATA *anyPolicy; ++ /* other policy data */ ++ STACK_OF(X509_POLICY_DATA) *data; ++ /* If InhibitAnyPolicy present this is its value or -1 if absent. */ ++ long any_skip; ++ /* ++ * If policyConstraints and requireExplicitPolicy present this is its ++ * value or -1 if absent. ++ */ ++ long explicit_skip; ++ /* ++ * If policyConstraints and policyMapping present this is its value or -1 ++ * if absent. ++ */ ++ long map_skip; ++}; ++ ++/* ++ * #define POLICY_CACHE_FLAG_CRITICAL POLICY_DATA_FLAG_CRITICAL ++ */ ++ ++/* This structure represents the relationship between nodes */ ++ ++struct X509_POLICY_NODE_st { ++ /* node data this refers to */ ++ const X509_POLICY_DATA *data; ++ /* Parent node */ ++ X509_POLICY_NODE *parent; ++ /* Number of child nodes */ ++ int nchild; ++}; ++ ++struct X509_POLICY_LEVEL_st { ++ /* Cert for this level */ ++ X509 *cert; ++ /* nodes at this level */ ++ STACK_OF(X509_POLICY_NODE) *nodes; ++ /* anyPolicy node */ ++ X509_POLICY_NODE *anyPolicy; ++ /* Extra data */ ++ /* ++ * STACK_OF(X509_POLICY_DATA) *extra_data; ++ */ ++ unsigned int flags; ++}; ++ ++struct X509_POLICY_TREE_st { ++ /* This is the tree 'level' data */ ++ X509_POLICY_LEVEL *levels; ++ int nlevel; ++ /* ++ * Extra policy data when additional nodes (not from the certificate) are ++ * required. ++ */ ++ STACK_OF(X509_POLICY_DATA) *extra_data; ++ /* This is the authority constrained policy set */ ++ STACK_OF(X509_POLICY_NODE) *auth_policies; ++ STACK_OF(X509_POLICY_NODE) *user_policies; ++ unsigned int flags; ++}; ++ ++/* Set if anyPolicy present in user policies */ ++#define POLICY_FLAG_ANY_POLICY 0x2 ++ ++/* Useful macros */ ++ ++#define node_data_critical(data) (data->flags & POLICY_DATA_FLAG_CRITICAL) ++#define node_critical(node) node_data_critical(node->data) ++ ++/* Internal functions */ ++ ++X509_POLICY_DATA *policy_data_new(POLICYINFO *policy, const ASN1_OBJECT *id, ++ int crit); ++void policy_data_free(X509_POLICY_DATA *data); ++ ++X509_POLICY_DATA *policy_cache_find_data(const X509_POLICY_CACHE *cache, ++ const ASN1_OBJECT *id); ++int policy_cache_set_mapping(X509 *x, POLICY_MAPPINGS *maps); ++ ++STACK_OF(X509_POLICY_NODE) *policy_node_cmp_new(void); ++ ++void policy_cache_init(void); ++ ++void policy_cache_free(X509_POLICY_CACHE *cache); ++ ++X509_POLICY_NODE *level_find_node(const X509_POLICY_LEVEL *level, ++ const X509_POLICY_NODE *parent, ++ const ASN1_OBJECT *id); ++ ++X509_POLICY_NODE *tree_find_sk(STACK_OF(X509_POLICY_NODE) *sk, ++ const ASN1_OBJECT *id); ++ ++X509_POLICY_NODE *level_add_node(X509_POLICY_LEVEL *level, ++ X509_POLICY_DATA *data, ++ X509_POLICY_NODE *parent, ++ X509_POLICY_TREE *tree); ++void policy_node_free(X509_POLICY_NODE *node); ++int policy_node_match(const X509_POLICY_LEVEL *lvl, ++ const X509_POLICY_NODE *node, const ASN1_OBJECT *oid); ++ ++const X509_POLICY_CACHE *policy_cache_set(X509 *x); +diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/x509v3/pcy_lib.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/x509v3/pcy_lib.c +new file mode 100644 +index 0000000..67f7eaf +--- /dev/null ++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/x509v3/pcy_lib.c +@@ -0,0 +1,108 @@ ++/* ++ * Copyright 2004-2016 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 ++ * in the file LICENSE in the source distribution or at ++ * https://www.openssl.org/source/license.html ++ */ ++ ++#include "internal/cryptlib.h" ++#include ++#include ++ ++#include "pcy_int.h" ++ ++/* accessor functions */ ++ ++/* X509_POLICY_TREE stuff */ ++ ++int X509_policy_tree_level_count(const X509_POLICY_TREE *tree) ++{ ++ if (!tree) ++ return 0; ++ return tree->nlevel; ++} ++ ++X509_POLICY_LEVEL *X509_policy_tree_get0_level(const X509_POLICY_TREE *tree, ++ int i) ++{ ++ if (!tree || (i < 0) || (i >= tree->nlevel)) ++ return NULL; ++ return tree->levels + i; ++} ++ ++STACK_OF(X509_POLICY_NODE) *X509_policy_tree_get0_policies(const ++ X509_POLICY_TREE ++ *tree) ++{ ++ if (!tree) ++ return NULL; ++ return tree->auth_policies; ++} ++ ++STACK_OF(X509_POLICY_NODE) *X509_policy_tree_get0_user_policies(const ++ X509_POLICY_TREE ++ *tree) ++{ ++ if (!tree) ++ return NULL; ++ if (tree->flags & POLICY_FLAG_ANY_POLICY) ++ return tree->auth_policies; ++ else ++ return tree->user_policies; ++} ++ ++/* X509_POLICY_LEVEL stuff */ ++ ++int X509_policy_level_node_count(X509_POLICY_LEVEL *level) ++{ ++ int n; ++ if (!level) ++ return 0; ++ if (level->anyPolicy) ++ n = 1; ++ else ++ n = 0; ++ if (level->nodes) ++ n += sk_X509_POLICY_NODE_num(level->nodes); ++ return n; ++} ++ ++X509_POLICY_NODE *X509_policy_level_get0_node(X509_POLICY_LEVEL *level, int i) ++{ ++ if (!level) ++ return NULL; ++ if (level->anyPolicy) { ++ if (i == 0) ++ return level->anyPolicy; ++ i--; ++ } ++ return sk_X509_POLICY_NODE_value(level->nodes, i); ++} ++ ++/* X509_POLICY_NODE stuff */ ++ ++const ASN1_OBJECT *X509_policy_node_get0_policy(const X509_POLICY_NODE *node) ++{ ++ if (!node) ++ return NULL; ++ return node->data->valid_policy; ++} ++ ++STACK_OF(POLICYQUALINFO) *X509_policy_node_get0_qualifiers(const ++ X509_POLICY_NODE ++ *node) ++{ ++ if (!node) ++ return NULL; ++ return node->data->qualifier_set; ++} ++ ++const X509_POLICY_NODE *X509_policy_node_get0_parent(const X509_POLICY_NODE ++ *node) ++{ ++ if (!node) ++ return NULL; ++ return node->parent; ++} +diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/x509v3/pcy_map.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/x509v3/pcy_map.c +new file mode 100644 +index 0000000..ab9dd21 +--- /dev/null ++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/x509v3/pcy_map.c +@@ -0,0 +1,81 @@ ++/* ++ * Copyright 2004-2016 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 ++ * in the file LICENSE in the source distribution or at ++ * https://www.openssl.org/source/license.html ++ */ ++ ++#include "internal/cryptlib.h" ++#include ++#include ++#include "internal/x509_int.h" ++ ++#include "pcy_int.h" ++ ++/* ++ * Set policy mapping entries in cache. Note: this modifies the passed ++ * POLICY_MAPPINGS structure ++ */ ++ ++int policy_cache_set_mapping(X509 *x, POLICY_MAPPINGS *maps) ++{ ++ POLICY_MAPPING *map; ++ X509_POLICY_DATA *data; ++ X509_POLICY_CACHE *cache = x->policy_cache; ++ int i; ++ int ret = 0; ++ if (sk_POLICY_MAPPING_num(maps) == 0) { ++ ret = -1; ++ goto bad_mapping; ++ } ++ for (i = 0; i < sk_POLICY_MAPPING_num(maps); i++) { ++ map = sk_POLICY_MAPPING_value(maps, i); ++ /* Reject if map to or from anyPolicy */ ++ if ((OBJ_obj2nid(map->subjectDomainPolicy) == NID_any_policy) ++ || (OBJ_obj2nid(map->issuerDomainPolicy) == NID_any_policy)) { ++ ret = -1; ++ goto bad_mapping; ++ } ++ ++ /* Attempt to find matching policy data */ ++ data = policy_cache_find_data(cache, map->issuerDomainPolicy); ++ /* If we don't have anyPolicy can't map */ ++ if (data == NULL && !cache->anyPolicy) ++ continue; ++ ++ /* Create a NODE from anyPolicy */ ++ if (data == NULL) { ++ data = policy_data_new(NULL, map->issuerDomainPolicy, ++ cache->anyPolicy->flags ++ & POLICY_DATA_FLAG_CRITICAL); ++ if (data == NULL) ++ goto bad_mapping; ++ data->qualifier_set = cache->anyPolicy->qualifier_set; ++ /* ++ * map->issuerDomainPolicy = NULL; ++ */ ++ data->flags |= POLICY_DATA_FLAG_MAPPED_ANY; ++ data->flags |= POLICY_DATA_FLAG_SHARED_QUALIFIERS; ++ if (!sk_X509_POLICY_DATA_push(cache->data, data)) { ++ policy_data_free(data); ++ goto bad_mapping; ++ } ++ } else ++ data->flags |= POLICY_DATA_FLAG_MAPPED; ++ if (!sk_ASN1_OBJECT_push(data->expected_policy_set, ++ map->subjectDomainPolicy)) ++ goto bad_mapping; ++ map->subjectDomainPolicy = NULL; ++ ++ } ++ ++ ret = 1; ++ bad_mapping: ++ if (ret == -1) ++ x->ex_flags |= EXFLAG_INVALID_POLICY; ++ sk_POLICY_MAPPING_pop_free(maps, POLICY_MAPPING_free); ++ return ret; ++ ++} +diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/x509v3/pcy_node.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/x509v3/pcy_node.c +new file mode 100644 +index 0000000..80443bf +--- /dev/null ++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/x509v3/pcy_node.c +@@ -0,0 +1,139 @@ ++/* ++ * Copyright 2004-2016 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 ++ * in the file LICENSE in the source distribution or at ++ * https://www.openssl.org/source/license.html ++ */ ++ ++#include ++#include ++#include ++ ++#include "pcy_int.h" ++ ++static int node_cmp(const X509_POLICY_NODE *const *a, ++ const X509_POLICY_NODE *const *b) ++{ ++ return OBJ_cmp((*a)->data->valid_policy, (*b)->data->valid_policy); ++} ++ ++STACK_OF(X509_POLICY_NODE) *policy_node_cmp_new(void) ++{ ++ return sk_X509_POLICY_NODE_new(node_cmp); ++} ++ ++X509_POLICY_NODE *tree_find_sk(STACK_OF(X509_POLICY_NODE) *nodes, ++ const ASN1_OBJECT *id) ++{ ++ X509_POLICY_DATA n; ++ X509_POLICY_NODE l; ++ int idx; ++ ++ n.valid_policy = (ASN1_OBJECT *)id; ++ l.data = &n; ++ ++ idx = sk_X509_POLICY_NODE_find(nodes, &l); ++ if (idx == -1) ++ return NULL; ++ ++ return sk_X509_POLICY_NODE_value(nodes, idx); ++ ++} ++ ++X509_POLICY_NODE *level_find_node(const X509_POLICY_LEVEL *level, ++ const X509_POLICY_NODE *parent, ++ const ASN1_OBJECT *id) ++{ ++ X509_POLICY_NODE *node; ++ int i; ++ for (i = 0; i < sk_X509_POLICY_NODE_num(level->nodes); i++) { ++ node = sk_X509_POLICY_NODE_value(level->nodes, i); ++ if (node->parent == parent) { ++ if (!OBJ_cmp(node->data->valid_policy, id)) ++ return node; ++ } ++ } ++ return NULL; ++} ++ ++X509_POLICY_NODE *level_add_node(X509_POLICY_LEVEL *level, ++ X509_POLICY_DATA *data, ++ X509_POLICY_NODE *parent, ++ X509_POLICY_TREE *tree) ++{ ++ X509_POLICY_NODE *node; ++ ++ node = OPENSSL_zalloc(sizeof(*node)); ++ if (node == NULL) ++ return NULL; ++ node->data = data; ++ node->parent = parent; ++ if (level) { ++ if (OBJ_obj2nid(data->valid_policy) == NID_any_policy) { ++ if (level->anyPolicy) ++ goto node_error; ++ level->anyPolicy = node; ++ } else { ++ ++ if (level->nodes == NULL) ++ level->nodes = policy_node_cmp_new(); ++ if (level->nodes == NULL) ++ goto node_error; ++ if (!sk_X509_POLICY_NODE_push(level->nodes, node)) ++ goto node_error; ++ } ++ } ++ ++ if (tree) { ++ if (tree->extra_data == NULL) ++ tree->extra_data = sk_X509_POLICY_DATA_new_null(); ++ if (tree->extra_data == NULL) ++ goto node_error; ++ if (!sk_X509_POLICY_DATA_push(tree->extra_data, data)) ++ goto node_error; ++ } ++ ++ if (parent) ++ parent->nchild++; ++ ++ return node; ++ ++ node_error: ++ policy_node_free(node); ++ return NULL; ++} ++ ++void policy_node_free(X509_POLICY_NODE *node) ++{ ++ OPENSSL_free(node); ++} ++ ++/* ++ * See if a policy node matches a policy OID. If mapping enabled look through ++ * expected policy set otherwise just valid policy. ++ */ ++ ++int policy_node_match(const X509_POLICY_LEVEL *lvl, ++ const X509_POLICY_NODE *node, const ASN1_OBJECT *oid) ++{ ++ int i; ++ ASN1_OBJECT *policy_oid; ++ const X509_POLICY_DATA *x = node->data; ++ ++ if ((lvl->flags & X509_V_FLAG_INHIBIT_MAP) ++ || !(x->flags & POLICY_DATA_FLAG_MAP_MASK)) { ++ if (!OBJ_cmp(x->valid_policy, oid)) ++ return 1; ++ return 0; ++ } ++ ++ for (i = 0; i < sk_ASN1_OBJECT_num(x->expected_policy_set); i++) { ++ policy_oid = sk_ASN1_OBJECT_value(x->expected_policy_set, i); ++ if (!OBJ_cmp(policy_oid, oid)) ++ return 1; ++ } ++ return 0; ++ ++} +diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/x509v3/pcy_tree.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/x509v3/pcy_tree.c +new file mode 100644 +index 0000000..9f9246b +--- /dev/null ++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/x509v3/pcy_tree.c +@@ -0,0 +1,696 @@ ++/* ++ * Copyright 2004-2016 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 ++ * in the file LICENSE in the source distribution or at ++ * https://www.openssl.org/source/license.html ++ */ ++ ++#include "internal/cryptlib.h" ++#include ++#include ++ ++#include "pcy_int.h" ++ ++/* ++ * Enable this to print out the complete policy tree at various point during ++ * evaluation. ++ */ ++ ++/* ++ * #define OPENSSL_POLICY_DEBUG ++ */ ++ ++#ifdef OPENSSL_POLICY_DEBUG ++ ++static void expected_print(BIO *err, X509_POLICY_LEVEL *lev, ++ X509_POLICY_NODE *node, int indent) ++{ ++ if ((lev->flags & X509_V_FLAG_INHIBIT_MAP) ++ || !(node->data->flags & POLICY_DATA_FLAG_MAP_MASK)) ++ BIO_puts(err, " Not Mapped\n"); ++ else { ++ int i; ++ STACK_OF(ASN1_OBJECT) *pset = node->data->expected_policy_set; ++ ASN1_OBJECT *oid; ++ BIO_puts(err, " Expected: "); ++ for (i = 0; i < sk_ASN1_OBJECT_num(pset); i++) { ++ oid = sk_ASN1_OBJECT_value(pset, i); ++ if (i) ++ BIO_puts(err, ", "); ++ i2a_ASN1_OBJECT(err, oid); ++ } ++ BIO_puts(err, "\n"); ++ } ++} ++ ++static void tree_print(char *str, X509_POLICY_TREE *tree, ++ X509_POLICY_LEVEL *curr) ++{ ++ BIO *err = BIO_new_fp(stderr, BIO_NOCLOSE); ++ X509_POLICY_LEVEL *plev; ++ ++ if (err == NULL) ++ return; ++ if (!curr) ++ curr = tree->levels + tree->nlevel; ++ else ++ curr++; ++ ++ BIO_printf(err, "Level print after %s\n", str); ++ BIO_printf(err, "Printing Up to Level %ld\n", curr - tree->levels); ++ for (plev = tree->levels; plev != curr; plev++) { ++ int i; ++ ++ BIO_printf(err, "Level %ld, flags = %x\n", ++ (long)(plev - tree->levels), plev->flags); ++ for (i = 0; i < sk_X509_POLICY_NODE_num(plev->nodes); i++) { ++ X509_POLICY_NODE *node = sk_X509_POLICY_NODE_value(plev->nodes, i); ++ ++ X509_POLICY_NODE_print(err, node, 2); ++ expected_print(err, plev, node, 2); ++ BIO_printf(err, " Flags: %x\n", node->data->flags); ++ } ++ if (plev->anyPolicy) ++ X509_POLICY_NODE_print(err, plev->anyPolicy, 2); ++ } ++ BIO_free(err); ++} ++#endif ++ ++/*- ++ * Return value: <= 0 on error, or positive bit mask: ++ * ++ * X509_PCY_TREE_VALID: valid tree ++ * X509_PCY_TREE_EMPTY: empty tree (including bare TA case) ++ * X509_PCY_TREE_EXPLICIT: explicit policy required ++ */ ++static int tree_init(X509_POLICY_TREE **ptree, STACK_OF(X509) *certs, ++ unsigned int flags) ++{ ++ X509_POLICY_TREE *tree; ++ X509_POLICY_LEVEL *level; ++ const X509_POLICY_CACHE *cache; ++ X509_POLICY_DATA *data = NULL; ++ int ret = X509_PCY_TREE_VALID; ++ int n = sk_X509_num(certs) - 1; /* RFC5280 paths omit the TA */ ++ int explicit_policy = (flags & X509_V_FLAG_EXPLICIT_POLICY) ? 0 : n+1; ++ int any_skip = (flags & X509_V_FLAG_INHIBIT_ANY) ? 0 : n+1; ++ int map_skip = (flags & X509_V_FLAG_INHIBIT_MAP) ? 0 : n+1; ++ int i; ++ ++ *ptree = NULL; ++ ++ /* Can't do anything with just a trust anchor */ ++ if (n == 0) ++ return X509_PCY_TREE_EMPTY; ++ ++ /* ++ * First setup the policy cache in all n non-TA certificates, this will be ++ * used in X509_verify_cert() which will invoke the verify callback for all ++ * certificates with invalid policy extensions. ++ */ ++ for (i = n - 1; i >= 0; i--) { ++ X509 *x = sk_X509_value(certs, i); ++ ++ /* Call for side-effect of computing hash and caching extensions */ ++ X509_check_purpose(x, -1, 0); ++ ++ /* If cache is NULL, likely ENOMEM: return immediately */ ++ if (policy_cache_set(x) == NULL) ++ return X509_PCY_TREE_INTERNAL; ++ } ++ ++ /* ++ * At this point check for invalid policies and required explicit policy. ++ * Note that the explicit_policy counter is a count-down to zero, with the ++ * requirement kicking in if and once it does that. The counter is ++ * decremented for every non-self-issued certificate in the path, but may ++ * be further reduced by policy constraints in a non-leaf certificate. ++ * ++ * The ultimate policy set is the intersection of all the policies along ++ * the path, if we hit a certificate with an empty policy set, and explicit ++ * policy is required we're done. ++ */ ++ for (i = n - 1; ++ i >= 0 && (explicit_policy > 0 || (ret & X509_PCY_TREE_EMPTY) == 0); ++ i--) { ++ X509 *x = sk_X509_value(certs, i); ++ uint32_t ex_flags = X509_get_extension_flags(x); ++ ++ /* All the policies are already cached, we can return early */ ++ if (ex_flags & EXFLAG_INVALID_POLICY) ++ return X509_PCY_TREE_INVALID; ++ ++ /* Access the cache which we now know exists */ ++ cache = policy_cache_set(x); ++ ++ if ((ret & X509_PCY_TREE_VALID) && cache->data == NULL) ++ ret = X509_PCY_TREE_EMPTY; ++ if (explicit_policy > 0) { ++ if (!(ex_flags & EXFLAG_SI)) ++ explicit_policy--; ++ if ((cache->explicit_skip >= 0) ++ && (cache->explicit_skip < explicit_policy)) ++ explicit_policy = cache->explicit_skip; ++ } ++ } ++ ++ if (explicit_policy == 0) ++ ret |= X509_PCY_TREE_EXPLICIT; ++ if ((ret & X509_PCY_TREE_VALID) == 0) ++ return ret; ++ ++ /* If we get this far initialize the tree */ ++ if ((tree = OPENSSL_zalloc(sizeof(*tree))) == NULL) ++ return X509_PCY_TREE_INTERNAL; ++ ++ /* ++ * http://tools.ietf.org/html/rfc5280#section-6.1.2, figure 3. ++ * ++ * The top level is implicitly for the trust anchor with valid expected ++ * policies of anyPolicy. (RFC 5280 has the TA at depth 0 and the leaf at ++ * depth n, we have the leaf at depth 0 and the TA at depth n). ++ */ ++ if ((tree->levels = OPENSSL_zalloc(sizeof(*tree->levels)*(n+1))) == NULL) { ++ OPENSSL_free(tree); ++ return X509_PCY_TREE_INTERNAL; ++ } ++ tree->nlevel = n+1; ++ level = tree->levels; ++ if ((data = policy_data_new(NULL, OBJ_nid2obj(NID_any_policy), 0)) == NULL) ++ goto bad_tree; ++ if (level_add_node(level, data, NULL, tree) == NULL) { ++ policy_data_free(data); ++ goto bad_tree; ++ } ++ ++ /* ++ * In this pass initialize all the tree levels and whether anyPolicy and ++ * policy mapping are inhibited at each level. ++ */ ++ for (i = n - 1; i >= 0; i--) { ++ X509 *x = sk_X509_value(certs, i); ++ uint32_t ex_flags = X509_get_extension_flags(x); ++ ++ /* Access the cache which we now know exists */ ++ cache = policy_cache_set(x); ++ ++ X509_up_ref(x); ++ (++level)->cert = x; ++ ++ if (!cache->anyPolicy) ++ level->flags |= X509_V_FLAG_INHIBIT_ANY; ++ ++ /* Determine inhibit any and inhibit map flags */ ++ if (any_skip == 0) { ++ /* ++ * Any matching allowed only if certificate is self issued and not ++ * the last in the chain. ++ */ ++ if (!(ex_flags & EXFLAG_SI) || (i == 0)) ++ level->flags |= X509_V_FLAG_INHIBIT_ANY; ++ } else { ++ if (!(ex_flags & EXFLAG_SI)) ++ any_skip--; ++ if ((cache->any_skip >= 0) && (cache->any_skip < any_skip)) ++ any_skip = cache->any_skip; ++ } ++ ++ if (map_skip == 0) ++ level->flags |= X509_V_FLAG_INHIBIT_MAP; ++ else { ++ if (!(ex_flags & EXFLAG_SI)) ++ map_skip--; ++ if ((cache->map_skip >= 0) && (cache->map_skip < map_skip)) ++ map_skip = cache->map_skip; ++ } ++ } ++ ++ *ptree = tree; ++ return ret; ++ ++ bad_tree: ++ X509_policy_tree_free(tree); ++ return X509_PCY_TREE_INTERNAL; ++} ++ ++/* ++ * Return value: 1 on success, 0 otherwise ++ */ ++static int tree_link_matching_nodes(X509_POLICY_LEVEL *curr, ++ X509_POLICY_DATA *data) ++{ ++ X509_POLICY_LEVEL *last = curr - 1; ++ int i, matched = 0; ++ ++ /* Iterate through all in nodes linking matches */ ++ for (i = 0; i < sk_X509_POLICY_NODE_num(last->nodes); i++) { ++ X509_POLICY_NODE *node = sk_X509_POLICY_NODE_value(last->nodes, i); ++ ++ if (policy_node_match(last, node, data->valid_policy)) { ++ if (level_add_node(curr, data, node, NULL) == NULL) ++ return 0; ++ matched = 1; ++ } ++ } ++ if (!matched && last->anyPolicy) { ++ if (level_add_node(curr, data, last->anyPolicy, NULL) == NULL) ++ return 0; ++ } ++ return 1; ++} ++ ++/* ++ * This corresponds to RFC3280 6.1.3(d)(1): link any data from ++ * CertificatePolicies onto matching parent or anyPolicy if no match. ++ * ++ * Return value: 1 on success, 0 otherwise. ++ */ ++static int tree_link_nodes(X509_POLICY_LEVEL *curr, ++ const X509_POLICY_CACHE *cache) ++{ ++ int i; ++ ++ for (i = 0; i < sk_X509_POLICY_DATA_num(cache->data); i++) { ++ X509_POLICY_DATA *data = sk_X509_POLICY_DATA_value(cache->data, i); ++ ++ /* Look for matching nodes in previous level */ ++ if (!tree_link_matching_nodes(curr, data)) ++ return 0; ++ } ++ return 1; ++} ++ ++/* ++ * This corresponds to RFC3280 6.1.3(d)(2): Create new data for any unmatched ++ * policies in the parent and link to anyPolicy. ++ * ++ * Return value: 1 on success, 0 otherwise. ++ */ ++static int tree_add_unmatched(X509_POLICY_LEVEL *curr, ++ const X509_POLICY_CACHE *cache, ++ const ASN1_OBJECT *id, ++ X509_POLICY_NODE *node, X509_POLICY_TREE *tree) ++{ ++ X509_POLICY_DATA *data; ++ ++ if (id == NULL) ++ id = node->data->valid_policy; ++ /* ++ * Create a new node with qualifiers from anyPolicy and id from unmatched ++ * node. ++ */ ++ if ((data = policy_data_new(NULL, id, node_critical(node))) == NULL) ++ return 0; ++ ++ /* Curr may not have anyPolicy */ ++ data->qualifier_set = cache->anyPolicy->qualifier_set; ++ data->flags |= POLICY_DATA_FLAG_SHARED_QUALIFIERS; ++ if (level_add_node(curr, data, node, tree) == NULL) { ++ policy_data_free(data); ++ return 0; ++ } ++ return 1; ++} ++ ++/* ++ * Return value: 1 on success, 0 otherwise. ++ */ ++static int tree_link_unmatched(X509_POLICY_LEVEL *curr, ++ const X509_POLICY_CACHE *cache, ++ X509_POLICY_NODE *node, X509_POLICY_TREE *tree) ++{ ++ const X509_POLICY_LEVEL *last = curr - 1; ++ int i; ++ ++ if ((last->flags & X509_V_FLAG_INHIBIT_MAP) ++ || !(node->data->flags & POLICY_DATA_FLAG_MAPPED)) { ++ /* If no policy mapping: matched if one child present */ ++ if (node->nchild) ++ return 1; ++ if (!tree_add_unmatched(curr, cache, NULL, node, tree)) ++ return 0; ++ /* Add it */ ++ } else { ++ /* If mapping: matched if one child per expected policy set */ ++ STACK_OF(ASN1_OBJECT) *expset = node->data->expected_policy_set; ++ if (node->nchild == sk_ASN1_OBJECT_num(expset)) ++ return 1; ++ /* Locate unmatched nodes */ ++ for (i = 0; i < sk_ASN1_OBJECT_num(expset); i++) { ++ ASN1_OBJECT *oid = sk_ASN1_OBJECT_value(expset, i); ++ if (level_find_node(curr, node, oid)) ++ continue; ++ if (!tree_add_unmatched(curr, cache, oid, node, tree)) ++ return 0; ++ } ++ ++ } ++ return 1; ++} ++ ++/* ++ * Return value: 1 on success, 0 otherwise ++ */ ++static int tree_link_any(X509_POLICY_LEVEL *curr, ++ const X509_POLICY_CACHE *cache, ++ X509_POLICY_TREE *tree) ++{ ++ int i; ++ X509_POLICY_NODE *node; ++ X509_POLICY_LEVEL *last = curr - 1; ++ ++ for (i = 0; i < sk_X509_POLICY_NODE_num(last->nodes); i++) { ++ node = sk_X509_POLICY_NODE_value(last->nodes, i); ++ ++ if (!tree_link_unmatched(curr, cache, node, tree)) ++ return 0; ++ } ++ /* Finally add link to anyPolicy */ ++ if (last->anyPolicy && ++ level_add_node(curr, cache->anyPolicy, last->anyPolicy, NULL) == NULL) ++ return 0; ++ return 1; ++} ++ ++/*- ++ * Prune the tree: delete any child mapped child data on the current level then ++ * proceed up the tree deleting any data with no children. If we ever have no ++ * data on a level we can halt because the tree will be empty. ++ * ++ * Return value: <= 0 error, otherwise one of: ++ * ++ * X509_PCY_TREE_VALID: valid tree ++ * X509_PCY_TREE_EMPTY: empty tree ++ */ ++static int tree_prune(X509_POLICY_TREE *tree, X509_POLICY_LEVEL *curr) ++{ ++ STACK_OF(X509_POLICY_NODE) *nodes; ++ X509_POLICY_NODE *node; ++ int i; ++ nodes = curr->nodes; ++ if (curr->flags & X509_V_FLAG_INHIBIT_MAP) { ++ for (i = sk_X509_POLICY_NODE_num(nodes) - 1; i >= 0; i--) { ++ node = sk_X509_POLICY_NODE_value(nodes, i); ++ /* Delete any mapped data: see RFC3280 XXXX */ ++ if (node->data->flags & POLICY_DATA_FLAG_MAP_MASK) { ++ node->parent->nchild--; ++ OPENSSL_free(node); ++ (void)sk_X509_POLICY_NODE_delete(nodes, i); ++ } ++ } ++ } ++ ++ for (;;) { ++ --curr; ++ nodes = curr->nodes; ++ for (i = sk_X509_POLICY_NODE_num(nodes) - 1; i >= 0; i--) { ++ node = sk_X509_POLICY_NODE_value(nodes, i); ++ if (node->nchild == 0) { ++ node->parent->nchild--; ++ OPENSSL_free(node); ++ (void)sk_X509_POLICY_NODE_delete(nodes, i); ++ } ++ } ++ if (curr->anyPolicy && !curr->anyPolicy->nchild) { ++ if (curr->anyPolicy->parent) ++ curr->anyPolicy->parent->nchild--; ++ OPENSSL_free(curr->anyPolicy); ++ curr->anyPolicy = NULL; ++ } ++ if (curr == tree->levels) { ++ /* If we zapped anyPolicy at top then tree is empty */ ++ if (!curr->anyPolicy) ++ return X509_PCY_TREE_EMPTY; ++ break; ++ } ++ } ++ return X509_PCY_TREE_VALID; ++} ++ ++/* ++ * Return value: 1 on success, 0 otherwise. ++ */ ++static int tree_add_auth_node(STACK_OF(X509_POLICY_NODE) **pnodes, ++ X509_POLICY_NODE *pcy) ++{ ++ if (*pnodes == NULL && ++ (*pnodes = policy_node_cmp_new()) == NULL) ++ return 0; ++ if (sk_X509_POLICY_NODE_find(*pnodes, pcy) != -1) ++ return 1; ++ return sk_X509_POLICY_NODE_push(*pnodes, pcy) != 0; ++} ++ ++#define TREE_CALC_FAILURE 0 ++#define TREE_CALC_OK_NOFREE 1 ++#define TREE_CALC_OK_DOFREE 2 ++ ++/*- ++ * Calculate the authority set based on policy tree. The 'pnodes' parameter is ++ * used as a store for the set of policy nodes used to calculate the user set. ++ * If the authority set is not anyPolicy then pnodes will just point to the ++ * authority set. If however the authority set is anyPolicy then the set of ++ * valid policies (other than anyPolicy) is store in pnodes. ++ * ++ * Return value: ++ * TREE_CALC_FAILURE on failure, ++ * TREE_CALC_OK_NOFREE on success and pnodes need not be freed, ++ * TREE_CALC_OK_DOFREE on success and pnodes needs to be freed ++ */ ++static int tree_calculate_authority_set(X509_POLICY_TREE *tree, ++ STACK_OF(X509_POLICY_NODE) **pnodes) ++{ ++ X509_POLICY_LEVEL *curr; ++ X509_POLICY_NODE *node, *anyptr; ++ STACK_OF(X509_POLICY_NODE) **addnodes; ++ int i, j; ++ curr = tree->levels + tree->nlevel - 1; ++ ++ /* If last level contains anyPolicy set is anyPolicy */ ++ if (curr->anyPolicy) { ++ if (!tree_add_auth_node(&tree->auth_policies, curr->anyPolicy)) ++ return TREE_CALC_FAILURE; ++ addnodes = pnodes; ++ } else ++ /* Add policies to authority set */ ++ addnodes = &tree->auth_policies; ++ ++ curr = tree->levels; ++ for (i = 1; i < tree->nlevel; i++) { ++ /* ++ * If no anyPolicy node on this this level it can't appear on lower ++ * levels so end search. ++ */ ++ if ((anyptr = curr->anyPolicy) == NULL) ++ break; ++ curr++; ++ for (j = 0; j < sk_X509_POLICY_NODE_num(curr->nodes); j++) { ++ node = sk_X509_POLICY_NODE_value(curr->nodes, j); ++ if ((node->parent == anyptr) ++ && !tree_add_auth_node(addnodes, node)) { ++ if (addnodes == pnodes) { ++ sk_X509_POLICY_NODE_free(*pnodes); ++ *pnodes = NULL; ++ } ++ return TREE_CALC_FAILURE; ++ } ++ } ++ } ++ if (addnodes == pnodes) ++ return TREE_CALC_OK_DOFREE; ++ ++ *pnodes = tree->auth_policies; ++ return TREE_CALC_OK_NOFREE; ++} ++ ++/* ++ * Return value: 1 on success, 0 otherwise. ++ */ ++static int tree_calculate_user_set(X509_POLICY_TREE *tree, ++ STACK_OF(ASN1_OBJECT) *policy_oids, ++ STACK_OF(X509_POLICY_NODE) *auth_nodes) ++{ ++ int i; ++ X509_POLICY_NODE *node; ++ ASN1_OBJECT *oid; ++ X509_POLICY_NODE *anyPolicy; ++ X509_POLICY_DATA *extra; ++ ++ /* ++ * Check if anyPolicy present in authority constrained policy set: this ++ * will happen if it is a leaf node. ++ */ ++ if (sk_ASN1_OBJECT_num(policy_oids) <= 0) ++ return 1; ++ ++ anyPolicy = tree->levels[tree->nlevel - 1].anyPolicy; ++ ++ for (i = 0; i < sk_ASN1_OBJECT_num(policy_oids); i++) { ++ oid = sk_ASN1_OBJECT_value(policy_oids, i); ++ if (OBJ_obj2nid(oid) == NID_any_policy) { ++ tree->flags |= POLICY_FLAG_ANY_POLICY; ++ return 1; ++ } ++ } ++ ++ for (i = 0; i < sk_ASN1_OBJECT_num(policy_oids); i++) { ++ oid = sk_ASN1_OBJECT_value(policy_oids, i); ++ node = tree_find_sk(auth_nodes, oid); ++ if (!node) { ++ if (!anyPolicy) ++ continue; ++ /* ++ * Create a new node with policy ID from user set and qualifiers ++ * from anyPolicy. ++ */ ++ extra = policy_data_new(NULL, oid, node_critical(anyPolicy)); ++ if (extra == NULL) ++ return 0; ++ extra->qualifier_set = anyPolicy->data->qualifier_set; ++ extra->flags = POLICY_DATA_FLAG_SHARED_QUALIFIERS ++ | POLICY_DATA_FLAG_EXTRA_NODE; ++ node = level_add_node(NULL, extra, anyPolicy->parent, tree); ++ } ++ if (!tree->user_policies) { ++ tree->user_policies = sk_X509_POLICY_NODE_new_null(); ++ if (!tree->user_policies) ++ return 1; ++ } ++ if (!sk_X509_POLICY_NODE_push(tree->user_policies, node)) ++ return 0; ++ } ++ return 1; ++} ++ ++/*- ++ * Return value: <= 0 error, otherwise one of: ++ * X509_PCY_TREE_VALID: valid tree ++ * X509_PCY_TREE_EMPTY: empty tree ++ * (see tree_prune()). ++ */ ++static int tree_evaluate(X509_POLICY_TREE *tree) ++{ ++ int ret, i; ++ X509_POLICY_LEVEL *curr = tree->levels + 1; ++ const X509_POLICY_CACHE *cache; ++ ++ for (i = 1; i < tree->nlevel; i++, curr++) { ++ cache = policy_cache_set(curr->cert); ++ if (!tree_link_nodes(curr, cache)) ++ return X509_PCY_TREE_INTERNAL; ++ ++ if (!(curr->flags & X509_V_FLAG_INHIBIT_ANY) ++ && !tree_link_any(curr, cache, tree)) ++ return X509_PCY_TREE_INTERNAL; ++#ifdef OPENSSL_POLICY_DEBUG ++ tree_print("before tree_prune()", tree, curr); ++#endif ++ ret = tree_prune(tree, curr); ++ if (ret != X509_PCY_TREE_VALID) ++ return ret; ++ } ++ return X509_PCY_TREE_VALID; ++} ++ ++static void exnode_free(X509_POLICY_NODE *node) ++{ ++ if (node->data && (node->data->flags & POLICY_DATA_FLAG_EXTRA_NODE)) ++ OPENSSL_free(node); ++} ++ ++void X509_policy_tree_free(X509_POLICY_TREE *tree) ++{ ++ X509_POLICY_LEVEL *curr; ++ int i; ++ ++ if (!tree) ++ return; ++ ++ sk_X509_POLICY_NODE_free(tree->auth_policies); ++ sk_X509_POLICY_NODE_pop_free(tree->user_policies, exnode_free); ++ ++ for (i = 0, curr = tree->levels; i < tree->nlevel; i++, curr++) { ++ X509_free(curr->cert); ++ sk_X509_POLICY_NODE_pop_free(curr->nodes, policy_node_free); ++ policy_node_free(curr->anyPolicy); ++ } ++ ++ sk_X509_POLICY_DATA_pop_free(tree->extra_data, policy_data_free); ++ OPENSSL_free(tree->levels); ++ OPENSSL_free(tree); ++ ++} ++ ++/*- ++ * Application policy checking function. ++ * Return codes: ++ * X509_PCY_TREE_FAILURE: Failure to satisfy explicit policy ++ * X509_PCY_TREE_INVALID: Inconsistent or invalid extensions ++ * X509_PCY_TREE_INTERNAL: Internal error, most likely malloc ++ * X509_PCY_TREE_VALID: Success (null tree if empty or bare TA) ++ */ ++int X509_policy_check(X509_POLICY_TREE **ptree, int *pexplicit_policy, ++ STACK_OF(X509) *certs, ++ STACK_OF(ASN1_OBJECT) *policy_oids, unsigned int flags) ++{ ++ int init_ret; ++ int ret; ++ X509_POLICY_TREE *tree = NULL; ++ STACK_OF(X509_POLICY_NODE) *nodes, *auth_nodes = NULL; ++ ++ *ptree = NULL; ++ *pexplicit_policy = 0; ++ init_ret = tree_init(&tree, certs, flags); ++ ++ if (init_ret <= 0) ++ return init_ret; ++ ++ if ((init_ret & X509_PCY_TREE_EXPLICIT) == 0) { ++ if (init_ret & X509_PCY_TREE_EMPTY) { ++ X509_policy_tree_free(tree); ++ return X509_PCY_TREE_VALID; ++ } ++ } else { ++ *pexplicit_policy = 1; ++ /* Tree empty and requireExplicit True: Error */ ++ if (init_ret & X509_PCY_TREE_EMPTY) ++ return X509_PCY_TREE_FAILURE; ++ } ++ ++ ret = tree_evaluate(tree); ++#ifdef OPENSSL_POLICY_DEBUG ++ tree_print("tree_evaluate()", tree, NULL); ++#endif ++ if (ret <= 0) ++ goto error; ++ ++ if (ret == X509_PCY_TREE_EMPTY) { ++ X509_policy_tree_free(tree); ++ if (init_ret & X509_PCY_TREE_EXPLICIT) ++ return X509_PCY_TREE_FAILURE; ++ return X509_PCY_TREE_VALID; ++ } ++ ++ /* Tree is not empty: continue */ ++ if ((ret = tree_calculate_authority_set(tree, &auth_nodes)) == 0 || ++ !tree_calculate_user_set(tree, policy_oids, auth_nodes)) ++ goto error; ++ if (ret == TREE_CALC_OK_DOFREE) ++ sk_X509_POLICY_NODE_free(auth_nodes); ++ ++ *ptree = tree; ++ ++ if (init_ret & X509_PCY_TREE_EXPLICIT) { ++ nodes = X509_policy_tree_get0_user_policies(tree); ++ if (sk_X509_POLICY_NODE_num(nodes) <= 0) ++ return X509_PCY_TREE_FAILURE; ++ } ++ return X509_PCY_TREE_VALID; ++ ++ error: ++ X509_policy_tree_free(tree); ++ return X509_PCY_TREE_INTERNAL; ++} +diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/x509v3/tabtest.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/x509v3/tabtest.c +new file mode 100644 +index 0000000..a33a63a +--- /dev/null ++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/x509v3/tabtest.c +@@ -0,0 +1,42 @@ ++/* ++ * Copyright 1999-2016 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 ++ * in the file LICENSE in the source distribution or at ++ * https://www.openssl.org/source/license.html ++ */ ++ ++/* ++ * Simple program to check the ext_dat.h is correct and print out problems if ++ * it is not. ++ */ ++ ++#include ++ ++#include ++ ++#include "ext_dat.h" ++ ++main() ++{ ++ int i, prev = -1, bad = 0; ++ X509V3_EXT_METHOD **tmp; ++ i = OSSL_NELEM(standard_exts); ++ if (i != STANDARD_EXTENSION_COUNT) ++ fprintf(stderr, "Extension number invalid expecting %d\n", i); ++ tmp = standard_exts; ++ for (i = 0; i < STANDARD_EXTENSION_COUNT; i++, tmp++) { ++ if ((*tmp)->ext_nid < prev) ++ bad = 1; ++ prev = (*tmp)->ext_nid; ++ ++ } ++ if (bad) { ++ tmp = standard_exts; ++ fprintf(stderr, "Extensions out of order!\n"); ++ for (i = 0; i < STANDARD_EXTENSION_COUNT; i++, tmp++) ++ printf("%d : %s\n", (*tmp)->ext_nid, OBJ_nid2sn((*tmp)->ext_nid)); ++ } else ++ fprintf(stderr, "Order OK\n"); ++} +diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/x509v3/v3_addr.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/x509v3/v3_addr.c +new file mode 100644 +index 0000000..ef1d775 +--- /dev/null ++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/x509v3/v3_addr.c +@@ -0,0 +1,1305 @@ ++/* ++ * Copyright 2006-2016 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 ++ * in the file LICENSE in the source distribution or at ++ * https://www.openssl.org/source/license.html ++ */ ++ ++/* ++ * Implementation of RFC 3779 section 2.2. ++ */ ++ ++#include ++#include ++ ++#include "internal/cryptlib.h" ++#include ++#include ++#include ++#include ++#include ++#include "internal/x509_int.h" ++#include "ext_dat.h" ++ ++#ifndef OPENSSL_NO_RFC3779 ++ ++/* ++ * OpenSSL ASN.1 template translation of RFC 3779 2.2.3. ++ */ ++ ++ASN1_SEQUENCE(IPAddressRange) = { ++ ASN1_SIMPLE(IPAddressRange, min, ASN1_BIT_STRING), ++ ASN1_SIMPLE(IPAddressRange, max, ASN1_BIT_STRING) ++} ASN1_SEQUENCE_END(IPAddressRange) ++ ++ASN1_CHOICE(IPAddressOrRange) = { ++ ASN1_SIMPLE(IPAddressOrRange, u.addressPrefix, ASN1_BIT_STRING), ++ ASN1_SIMPLE(IPAddressOrRange, u.addressRange, IPAddressRange) ++} ASN1_CHOICE_END(IPAddressOrRange) ++ ++ASN1_CHOICE(IPAddressChoice) = { ++ ASN1_SIMPLE(IPAddressChoice, u.inherit, ASN1_NULL), ++ ASN1_SEQUENCE_OF(IPAddressChoice, u.addressesOrRanges, IPAddressOrRange) ++} ASN1_CHOICE_END(IPAddressChoice) ++ ++ASN1_SEQUENCE(IPAddressFamily) = { ++ ASN1_SIMPLE(IPAddressFamily, addressFamily, ASN1_OCTET_STRING), ++ ASN1_SIMPLE(IPAddressFamily, ipAddressChoice, IPAddressChoice) ++} ASN1_SEQUENCE_END(IPAddressFamily) ++ ++ASN1_ITEM_TEMPLATE(IPAddrBlocks) = ++ ASN1_EX_TEMPLATE_TYPE(ASN1_TFLG_SEQUENCE_OF, 0, ++ IPAddrBlocks, IPAddressFamily) ++static_ASN1_ITEM_TEMPLATE_END(IPAddrBlocks) ++ ++IMPLEMENT_ASN1_FUNCTIONS(IPAddressRange) ++IMPLEMENT_ASN1_FUNCTIONS(IPAddressOrRange) ++IMPLEMENT_ASN1_FUNCTIONS(IPAddressChoice) ++IMPLEMENT_ASN1_FUNCTIONS(IPAddressFamily) ++ ++/* ++ * How much buffer space do we need for a raw address? ++ */ ++#define ADDR_RAW_BUF_LEN 16 ++ ++/* ++ * What's the address length associated with this AFI? ++ */ ++static int length_from_afi(const unsigned afi) ++{ ++ switch (afi) { ++ case IANA_AFI_IPV4: ++ return 4; ++ case IANA_AFI_IPV6: ++ return 16; ++ default: ++ return 0; ++ } ++} ++ ++/* ++ * Extract the AFI from an IPAddressFamily. ++ */ ++unsigned int X509v3_addr_get_afi(const IPAddressFamily *f) ++{ ++ return ((f != NULL && ++ f->addressFamily != NULL && f->addressFamily->data != NULL) ++ ? ((f->addressFamily->data[0] << 8) | (f->addressFamily->data[1])) ++ : 0); ++} ++ ++/* ++ * Expand the bitstring form of an address into a raw byte array. ++ * At the moment this is coded for simplicity, not speed. ++ */ ++static int addr_expand(unsigned char *addr, ++ const ASN1_BIT_STRING *bs, ++ const int length, const unsigned char fill) ++{ ++ if (bs->length < 0 || bs->length > length) ++ return 0; ++ if (bs->length > 0) { ++ memcpy(addr, bs->data, bs->length); ++ if ((bs->flags & 7) != 0) { ++ unsigned char mask = 0xFF >> (8 - (bs->flags & 7)); ++ if (fill == 0) ++ addr[bs->length - 1] &= ~mask; ++ else ++ addr[bs->length - 1] |= mask; ++ } ++ } ++ memset(addr + bs->length, fill, length - bs->length); ++ return 1; ++} ++ ++/* ++ * Extract the prefix length from a bitstring. ++ */ ++#define addr_prefixlen(bs) ((int) ((bs)->length * 8 - ((bs)->flags & 7))) ++ ++/* ++ * i2r handler for one address bitstring. ++ */ ++static int i2r_address(BIO *out, ++ const unsigned afi, ++ const unsigned char fill, const ASN1_BIT_STRING *bs) ++{ ++ unsigned char addr[ADDR_RAW_BUF_LEN]; ++ int i, n; ++ ++ if (bs->length < 0) ++ return 0; ++ switch (afi) { ++ case IANA_AFI_IPV4: ++ if (!addr_expand(addr, bs, 4, fill)) ++ return 0; ++ BIO_printf(out, "%d.%d.%d.%d", addr[0], addr[1], addr[2], addr[3]); ++ break; ++ case IANA_AFI_IPV6: ++ if (!addr_expand(addr, bs, 16, fill)) ++ return 0; ++ for (n = 16; n > 1 && addr[n - 1] == 0x00 && addr[n - 2] == 0x00; ++ n -= 2) ; ++ for (i = 0; i < n; i += 2) ++ BIO_printf(out, "%x%s", (addr[i] << 8) | addr[i + 1], ++ (i < 14 ? ":" : "")); ++ if (i < 16) ++ BIO_puts(out, ":"); ++ if (i == 0) ++ BIO_puts(out, ":"); ++ break; ++ default: ++ for (i = 0; i < bs->length; i++) ++ BIO_printf(out, "%s%02x", (i > 0 ? ":" : ""), bs->data[i]); ++ BIO_printf(out, "[%d]", (int)(bs->flags & 7)); ++ break; ++ } ++ return 1; ++} ++ ++/* ++ * i2r handler for a sequence of addresses and ranges. ++ */ ++static int i2r_IPAddressOrRanges(BIO *out, ++ const int indent, ++ const IPAddressOrRanges *aors, ++ const unsigned afi) ++{ ++ int i; ++ for (i = 0; i < sk_IPAddressOrRange_num(aors); i++) { ++ const IPAddressOrRange *aor = sk_IPAddressOrRange_value(aors, i); ++ BIO_printf(out, "%*s", indent, ""); ++ switch (aor->type) { ++ case IPAddressOrRange_addressPrefix: ++ if (!i2r_address(out, afi, 0x00, aor->u.addressPrefix)) ++ return 0; ++ BIO_printf(out, "/%d\n", addr_prefixlen(aor->u.addressPrefix)); ++ continue; ++ case IPAddressOrRange_addressRange: ++ if (!i2r_address(out, afi, 0x00, aor->u.addressRange->min)) ++ return 0; ++ BIO_puts(out, "-"); ++ if (!i2r_address(out, afi, 0xFF, aor->u.addressRange->max)) ++ return 0; ++ BIO_puts(out, "\n"); ++ continue; ++ } ++ } ++ return 1; ++} ++ ++/* ++ * i2r handler for an IPAddrBlocks extension. ++ */ ++static int i2r_IPAddrBlocks(const X509V3_EXT_METHOD *method, ++ void *ext, BIO *out, int indent) ++{ ++ const IPAddrBlocks *addr = ext; ++ int i; ++ for (i = 0; i < sk_IPAddressFamily_num(addr); i++) { ++ IPAddressFamily *f = sk_IPAddressFamily_value(addr, i); ++ const unsigned int afi = X509v3_addr_get_afi(f); ++ switch (afi) { ++ case IANA_AFI_IPV4: ++ BIO_printf(out, "%*sIPv4", indent, ""); ++ break; ++ case IANA_AFI_IPV6: ++ BIO_printf(out, "%*sIPv6", indent, ""); ++ break; ++ default: ++ BIO_printf(out, "%*sUnknown AFI %u", indent, "", afi); ++ break; ++ } ++ if (f->addressFamily->length > 2) { ++ switch (f->addressFamily->data[2]) { ++ case 1: ++ BIO_puts(out, " (Unicast)"); ++ break; ++ case 2: ++ BIO_puts(out, " (Multicast)"); ++ break; ++ case 3: ++ BIO_puts(out, " (Unicast/Multicast)"); ++ break; ++ case 4: ++ BIO_puts(out, " (MPLS)"); ++ break; ++ case 64: ++ BIO_puts(out, " (Tunnel)"); ++ break; ++ case 65: ++ BIO_puts(out, " (VPLS)"); ++ break; ++ case 66: ++ BIO_puts(out, " (BGP MDT)"); ++ break; ++ case 128: ++ BIO_puts(out, " (MPLS-labeled VPN)"); ++ break; ++ default: ++ BIO_printf(out, " (Unknown SAFI %u)", ++ (unsigned)f->addressFamily->data[2]); ++ break; ++ } ++ } ++ switch (f->ipAddressChoice->type) { ++ case IPAddressChoice_inherit: ++ BIO_puts(out, ": inherit\n"); ++ break; ++ case IPAddressChoice_addressesOrRanges: ++ BIO_puts(out, ":\n"); ++ if (!i2r_IPAddressOrRanges(out, ++ indent + 2, ++ f->ipAddressChoice-> ++ u.addressesOrRanges, afi)) ++ return 0; ++ break; ++ } ++ } ++ return 1; ++} ++ ++/* ++ * Sort comparison function for a sequence of IPAddressOrRange ++ * elements. ++ * ++ * There's no sane answer we can give if addr_expand() fails, and an ++ * assertion failure on externally supplied data is seriously uncool, ++ * so we just arbitrarily declare that if given invalid inputs this ++ * function returns -1. If this messes up your preferred sort order ++ * for garbage input, tough noogies. ++ */ ++static int IPAddressOrRange_cmp(const IPAddressOrRange *a, ++ const IPAddressOrRange *b, const int length) ++{ ++ unsigned char addr_a[ADDR_RAW_BUF_LEN], addr_b[ADDR_RAW_BUF_LEN]; ++ int prefixlen_a = 0, prefixlen_b = 0; ++ int r; ++ ++ switch (a->type) { ++ case IPAddressOrRange_addressPrefix: ++ if (!addr_expand(addr_a, a->u.addressPrefix, length, 0x00)) ++ return -1; ++ prefixlen_a = addr_prefixlen(a->u.addressPrefix); ++ break; ++ case IPAddressOrRange_addressRange: ++ if (!addr_expand(addr_a, a->u.addressRange->min, length, 0x00)) ++ return -1; ++ prefixlen_a = length * 8; ++ break; ++ } ++ ++ switch (b->type) { ++ case IPAddressOrRange_addressPrefix: ++ if (!addr_expand(addr_b, b->u.addressPrefix, length, 0x00)) ++ return -1; ++ prefixlen_b = addr_prefixlen(b->u.addressPrefix); ++ break; ++ case IPAddressOrRange_addressRange: ++ if (!addr_expand(addr_b, b->u.addressRange->min, length, 0x00)) ++ return -1; ++ prefixlen_b = length * 8; ++ break; ++ } ++ ++ if ((r = memcmp(addr_a, addr_b, length)) != 0) ++ return r; ++ else ++ return prefixlen_a - prefixlen_b; ++} ++ ++/* ++ * IPv4-specific closure over IPAddressOrRange_cmp, since sk_sort() ++ * comparison routines are only allowed two arguments. ++ */ ++static int v4IPAddressOrRange_cmp(const IPAddressOrRange *const *a, ++ const IPAddressOrRange *const *b) ++{ ++ return IPAddressOrRange_cmp(*a, *b, 4); ++} ++ ++/* ++ * IPv6-specific closure over IPAddressOrRange_cmp, since sk_sort() ++ * comparison routines are only allowed two arguments. ++ */ ++static int v6IPAddressOrRange_cmp(const IPAddressOrRange *const *a, ++ const IPAddressOrRange *const *b) ++{ ++ return IPAddressOrRange_cmp(*a, *b, 16); ++} ++ ++/* ++ * Calculate whether a range collapses to a prefix. ++ * See last paragraph of RFC 3779 2.2.3.7. ++ */ ++static int range_should_be_prefix(const unsigned char *min, ++ const unsigned char *max, const int length) ++{ ++ unsigned char mask; ++ int i, j; ++ ++ OPENSSL_assert(memcmp(min, max, length) <= 0); ++ for (i = 0; i < length && min[i] == max[i]; i++) ; ++ for (j = length - 1; j >= 0 && min[j] == 0x00 && max[j] == 0xFF; j--) ; ++ if (i < j) ++ return -1; ++ if (i > j) ++ return i * 8; ++ mask = min[i] ^ max[i]; ++ switch (mask) { ++ case 0x01: ++ j = 7; ++ break; ++ case 0x03: ++ j = 6; ++ break; ++ case 0x07: ++ j = 5; ++ break; ++ case 0x0F: ++ j = 4; ++ break; ++ case 0x1F: ++ j = 3; ++ break; ++ case 0x3F: ++ j = 2; ++ break; ++ case 0x7F: ++ j = 1; ++ break; ++ default: ++ return -1; ++ } ++ if ((min[i] & mask) != 0 || (max[i] & mask) != mask) ++ return -1; ++ else ++ return i * 8 + j; ++} ++ ++/* ++ * Construct a prefix. ++ */ ++static int make_addressPrefix(IPAddressOrRange **result, ++ unsigned char *addr, const int prefixlen) ++{ ++ int bytelen = (prefixlen + 7) / 8, bitlen = prefixlen % 8; ++ IPAddressOrRange *aor = IPAddressOrRange_new(); ++ ++ if (aor == NULL) ++ return 0; ++ aor->type = IPAddressOrRange_addressPrefix; ++ if (aor->u.addressPrefix == NULL && ++ (aor->u.addressPrefix = ASN1_BIT_STRING_new()) == NULL) ++ goto err; ++ if (!ASN1_BIT_STRING_set(aor->u.addressPrefix, addr, bytelen)) ++ goto err; ++ aor->u.addressPrefix->flags &= ~7; ++ aor->u.addressPrefix->flags |= ASN1_STRING_FLAG_BITS_LEFT; ++ if (bitlen > 0) { ++ aor->u.addressPrefix->data[bytelen - 1] &= ~(0xFF >> bitlen); ++ aor->u.addressPrefix->flags |= 8 - bitlen; ++ } ++ ++ *result = aor; ++ return 1; ++ ++ err: ++ IPAddressOrRange_free(aor); ++ return 0; ++} ++ ++/* ++ * Construct a range. If it can be expressed as a prefix, ++ * return a prefix instead. Doing this here simplifies ++ * the rest of the code considerably. ++ */ ++static int make_addressRange(IPAddressOrRange **result, ++ unsigned char *min, ++ unsigned char *max, const int length) ++{ ++ IPAddressOrRange *aor; ++ int i, prefixlen; ++ ++ if ((prefixlen = range_should_be_prefix(min, max, length)) >= 0) ++ return make_addressPrefix(result, min, prefixlen); ++ ++ if ((aor = IPAddressOrRange_new()) == NULL) ++ return 0; ++ aor->type = IPAddressOrRange_addressRange; ++ OPENSSL_assert(aor->u.addressRange == NULL); ++ if ((aor->u.addressRange = IPAddressRange_new()) == NULL) ++ goto err; ++ if (aor->u.addressRange->min == NULL && ++ (aor->u.addressRange->min = ASN1_BIT_STRING_new()) == NULL) ++ goto err; ++ if (aor->u.addressRange->max == NULL && ++ (aor->u.addressRange->max = ASN1_BIT_STRING_new()) == NULL) ++ goto err; ++ ++ for (i = length; i > 0 && min[i - 1] == 0x00; --i) ; ++ if (!ASN1_BIT_STRING_set(aor->u.addressRange->min, min, i)) ++ goto err; ++ aor->u.addressRange->min->flags &= ~7; ++ aor->u.addressRange->min->flags |= ASN1_STRING_FLAG_BITS_LEFT; ++ if (i > 0) { ++ unsigned char b = min[i - 1]; ++ int j = 1; ++ while ((b & (0xFFU >> j)) != 0) ++ ++j; ++ aor->u.addressRange->min->flags |= 8 - j; ++ } ++ ++ for (i = length; i > 0 && max[i - 1] == 0xFF; --i) ; ++ if (!ASN1_BIT_STRING_set(aor->u.addressRange->max, max, i)) ++ goto err; ++ aor->u.addressRange->max->flags &= ~7; ++ aor->u.addressRange->max->flags |= ASN1_STRING_FLAG_BITS_LEFT; ++ if (i > 0) { ++ unsigned char b = max[i - 1]; ++ int j = 1; ++ while ((b & (0xFFU >> j)) != (0xFFU >> j)) ++ ++j; ++ aor->u.addressRange->max->flags |= 8 - j; ++ } ++ ++ *result = aor; ++ return 1; ++ ++ err: ++ IPAddressOrRange_free(aor); ++ return 0; ++} ++ ++/* ++ * Construct a new address family or find an existing one. ++ */ ++static IPAddressFamily *make_IPAddressFamily(IPAddrBlocks *addr, ++ const unsigned afi, ++ const unsigned *safi) ++{ ++ IPAddressFamily *f; ++ unsigned char key[3]; ++ int keylen; ++ int i; ++ ++ key[0] = (afi >> 8) & 0xFF; ++ key[1] = afi & 0xFF; ++ if (safi != NULL) { ++ key[2] = *safi & 0xFF; ++ keylen = 3; ++ } else { ++ keylen = 2; ++ } ++ ++ for (i = 0; i < sk_IPAddressFamily_num(addr); i++) { ++ f = sk_IPAddressFamily_value(addr, i); ++ OPENSSL_assert(f->addressFamily->data != NULL); ++ if (f->addressFamily->length == keylen && ++ !memcmp(f->addressFamily->data, key, keylen)) ++ return f; ++ } ++ ++ if ((f = IPAddressFamily_new()) == NULL) ++ goto err; ++ if (f->ipAddressChoice == NULL && ++ (f->ipAddressChoice = IPAddressChoice_new()) == NULL) ++ goto err; ++ if (f->addressFamily == NULL && ++ (f->addressFamily = ASN1_OCTET_STRING_new()) == NULL) ++ goto err; ++ if (!ASN1_OCTET_STRING_set(f->addressFamily, key, keylen)) ++ goto err; ++ if (!sk_IPAddressFamily_push(addr, f)) ++ goto err; ++ ++ return f; ++ ++ err: ++ IPAddressFamily_free(f); ++ return NULL; ++} ++ ++/* ++ * Add an inheritance element. ++ */ ++int X509v3_addr_add_inherit(IPAddrBlocks *addr, ++ const unsigned afi, const unsigned *safi) ++{ ++ IPAddressFamily *f = make_IPAddressFamily(addr, afi, safi); ++ if (f == NULL || ++ f->ipAddressChoice == NULL || ++ (f->ipAddressChoice->type == IPAddressChoice_addressesOrRanges && ++ f->ipAddressChoice->u.addressesOrRanges != NULL)) ++ return 0; ++ if (f->ipAddressChoice->type == IPAddressChoice_inherit && ++ f->ipAddressChoice->u.inherit != NULL) ++ return 1; ++ if (f->ipAddressChoice->u.inherit == NULL && ++ (f->ipAddressChoice->u.inherit = ASN1_NULL_new()) == NULL) ++ return 0; ++ f->ipAddressChoice->type = IPAddressChoice_inherit; ++ return 1; ++} ++ ++/* ++ * Construct an IPAddressOrRange sequence, or return an existing one. ++ */ ++static IPAddressOrRanges *make_prefix_or_range(IPAddrBlocks *addr, ++ const unsigned afi, ++ const unsigned *safi) ++{ ++ IPAddressFamily *f = make_IPAddressFamily(addr, afi, safi); ++ IPAddressOrRanges *aors = NULL; ++ ++ if (f == NULL || ++ f->ipAddressChoice == NULL || ++ (f->ipAddressChoice->type == IPAddressChoice_inherit && ++ f->ipAddressChoice->u.inherit != NULL)) ++ return NULL; ++ if (f->ipAddressChoice->type == IPAddressChoice_addressesOrRanges) ++ aors = f->ipAddressChoice->u.addressesOrRanges; ++ if (aors != NULL) ++ return aors; ++ if ((aors = sk_IPAddressOrRange_new_null()) == NULL) ++ return NULL; ++ switch (afi) { ++ case IANA_AFI_IPV4: ++ (void)sk_IPAddressOrRange_set_cmp_func(aors, v4IPAddressOrRange_cmp); ++ break; ++ case IANA_AFI_IPV6: ++ (void)sk_IPAddressOrRange_set_cmp_func(aors, v6IPAddressOrRange_cmp); ++ break; ++ } ++ f->ipAddressChoice->type = IPAddressChoice_addressesOrRanges; ++ f->ipAddressChoice->u.addressesOrRanges = aors; ++ return aors; ++} ++ ++/* ++ * Add a prefix. ++ */ ++int X509v3_addr_add_prefix(IPAddrBlocks *addr, ++ const unsigned afi, ++ const unsigned *safi, ++ unsigned char *a, const int prefixlen) ++{ ++ IPAddressOrRanges *aors = make_prefix_or_range(addr, afi, safi); ++ IPAddressOrRange *aor; ++ if (aors == NULL || !make_addressPrefix(&aor, a, prefixlen)) ++ return 0; ++ if (sk_IPAddressOrRange_push(aors, aor)) ++ return 1; ++ IPAddressOrRange_free(aor); ++ return 0; ++} ++ ++/* ++ * Add a range. ++ */ ++int X509v3_addr_add_range(IPAddrBlocks *addr, ++ const unsigned afi, ++ const unsigned *safi, ++ unsigned char *min, unsigned char *max) ++{ ++ IPAddressOrRanges *aors = make_prefix_or_range(addr, afi, safi); ++ IPAddressOrRange *aor; ++ int length = length_from_afi(afi); ++ if (aors == NULL) ++ return 0; ++ if (!make_addressRange(&aor, min, max, length)) ++ return 0; ++ if (sk_IPAddressOrRange_push(aors, aor)) ++ return 1; ++ IPAddressOrRange_free(aor); ++ return 0; ++} ++ ++/* ++ * Extract min and max values from an IPAddressOrRange. ++ */ ++static int extract_min_max(IPAddressOrRange *aor, ++ unsigned char *min, unsigned char *max, int length) ++{ ++ if (aor == NULL || min == NULL || max == NULL) ++ return 0; ++ switch (aor->type) { ++ case IPAddressOrRange_addressPrefix: ++ return (addr_expand(min, aor->u.addressPrefix, length, 0x00) && ++ addr_expand(max, aor->u.addressPrefix, length, 0xFF)); ++ case IPAddressOrRange_addressRange: ++ return (addr_expand(min, aor->u.addressRange->min, length, 0x00) && ++ addr_expand(max, aor->u.addressRange->max, length, 0xFF)); ++ } ++ return 0; ++} ++ ++/* ++ * Public wrapper for extract_min_max(). ++ */ ++int X509v3_addr_get_range(IPAddressOrRange *aor, ++ const unsigned afi, ++ unsigned char *min, ++ unsigned char *max, const int length) ++{ ++ int afi_length = length_from_afi(afi); ++ if (aor == NULL || min == NULL || max == NULL || ++ afi_length == 0 || length < afi_length || ++ (aor->type != IPAddressOrRange_addressPrefix && ++ aor->type != IPAddressOrRange_addressRange) || ++ !extract_min_max(aor, min, max, afi_length)) ++ return 0; ++ ++ return afi_length; ++} ++ ++/* ++ * Sort comparison function for a sequence of IPAddressFamily. ++ * ++ * The last paragraph of RFC 3779 2.2.3.3 is slightly ambiguous about ++ * the ordering: I can read it as meaning that IPv6 without a SAFI ++ * comes before IPv4 with a SAFI, which seems pretty weird. The ++ * examples in appendix B suggest that the author intended the ++ * null-SAFI rule to apply only within a single AFI, which is what I ++ * would have expected and is what the following code implements. ++ */ ++static int IPAddressFamily_cmp(const IPAddressFamily *const *a_, ++ const IPAddressFamily *const *b_) ++{ ++ const ASN1_OCTET_STRING *a = (*a_)->addressFamily; ++ const ASN1_OCTET_STRING *b = (*b_)->addressFamily; ++ int len = ((a->length <= b->length) ? a->length : b->length); ++ int cmp = memcmp(a->data, b->data, len); ++ return cmp ? cmp : a->length - b->length; ++} ++ ++/* ++ * Check whether an IPAddrBLocks is in canonical form. ++ */ ++int X509v3_addr_is_canonical(IPAddrBlocks *addr) ++{ ++ unsigned char a_min[ADDR_RAW_BUF_LEN], a_max[ADDR_RAW_BUF_LEN]; ++ unsigned char b_min[ADDR_RAW_BUF_LEN], b_max[ADDR_RAW_BUF_LEN]; ++ IPAddressOrRanges *aors; ++ int i, j, k; ++ ++ /* ++ * Empty extension is canonical. ++ */ ++ if (addr == NULL) ++ return 1; ++ ++ /* ++ * Check whether the top-level list is in order. ++ */ ++ for (i = 0; i < sk_IPAddressFamily_num(addr) - 1; i++) { ++ const IPAddressFamily *a = sk_IPAddressFamily_value(addr, i); ++ const IPAddressFamily *b = sk_IPAddressFamily_value(addr, i + 1); ++ if (IPAddressFamily_cmp(&a, &b) >= 0) ++ return 0; ++ } ++ ++ /* ++ * Top level's ok, now check each address family. ++ */ ++ for (i = 0; i < sk_IPAddressFamily_num(addr); i++) { ++ IPAddressFamily *f = sk_IPAddressFamily_value(addr, i); ++ int length = length_from_afi(X509v3_addr_get_afi(f)); ++ ++ /* ++ * Inheritance is canonical. Anything other than inheritance or ++ * a SEQUENCE OF IPAddressOrRange is an ASN.1 error or something. ++ */ ++ if (f == NULL || f->ipAddressChoice == NULL) ++ return 0; ++ switch (f->ipAddressChoice->type) { ++ case IPAddressChoice_inherit: ++ continue; ++ case IPAddressChoice_addressesOrRanges: ++ break; ++ default: ++ return 0; ++ } ++ ++ /* ++ * It's an IPAddressOrRanges sequence, check it. ++ */ ++ aors = f->ipAddressChoice->u.addressesOrRanges; ++ if (sk_IPAddressOrRange_num(aors) == 0) ++ return 0; ++ for (j = 0; j < sk_IPAddressOrRange_num(aors) - 1; j++) { ++ IPAddressOrRange *a = sk_IPAddressOrRange_value(aors, j); ++ IPAddressOrRange *b = sk_IPAddressOrRange_value(aors, j + 1); ++ ++ if (!extract_min_max(a, a_min, a_max, length) || ++ !extract_min_max(b, b_min, b_max, length)) ++ return 0; ++ ++ /* ++ * Punt misordered list, overlapping start, or inverted range. ++ */ ++ if (memcmp(a_min, b_min, length) >= 0 || ++ memcmp(a_min, a_max, length) > 0 || ++ memcmp(b_min, b_max, length) > 0) ++ return 0; ++ ++ /* ++ * Punt if adjacent or overlapping. Check for adjacency by ++ * subtracting one from b_min first. ++ */ ++ for (k = length - 1; k >= 0 && b_min[k]-- == 0x00; k--) ; ++ if (memcmp(a_max, b_min, length) >= 0) ++ return 0; ++ ++ /* ++ * Check for range that should be expressed as a prefix. ++ */ ++ if (a->type == IPAddressOrRange_addressRange && ++ range_should_be_prefix(a_min, a_max, length) >= 0) ++ return 0; ++ } ++ ++ /* ++ * Check range to see if it's inverted or should be a ++ * prefix. ++ */ ++ j = sk_IPAddressOrRange_num(aors) - 1; ++ { ++ IPAddressOrRange *a = sk_IPAddressOrRange_value(aors, j); ++ if (a != NULL && a->type == IPAddressOrRange_addressRange) { ++ if (!extract_min_max(a, a_min, a_max, length)) ++ return 0; ++ if (memcmp(a_min, a_max, length) > 0 || ++ range_should_be_prefix(a_min, a_max, length) >= 0) ++ return 0; ++ } ++ } ++ } ++ ++ /* ++ * If we made it through all that, we're happy. ++ */ ++ return 1; ++} ++ ++/* ++ * Whack an IPAddressOrRanges into canonical form. ++ */ ++static int IPAddressOrRanges_canonize(IPAddressOrRanges *aors, ++ const unsigned afi) ++{ ++ int i, j, length = length_from_afi(afi); ++ ++ /* ++ * Sort the IPAddressOrRanges sequence. ++ */ ++ sk_IPAddressOrRange_sort(aors); ++ ++ /* ++ * Clean up representation issues, punt on duplicates or overlaps. ++ */ ++ for (i = 0; i < sk_IPAddressOrRange_num(aors) - 1; i++) { ++ IPAddressOrRange *a = sk_IPAddressOrRange_value(aors, i); ++ IPAddressOrRange *b = sk_IPAddressOrRange_value(aors, i + 1); ++ unsigned char a_min[ADDR_RAW_BUF_LEN], a_max[ADDR_RAW_BUF_LEN]; ++ unsigned char b_min[ADDR_RAW_BUF_LEN], b_max[ADDR_RAW_BUF_LEN]; ++ ++ if (!extract_min_max(a, a_min, a_max, length) || ++ !extract_min_max(b, b_min, b_max, length)) ++ return 0; ++ ++ /* ++ * Punt inverted ranges. ++ */ ++ if (memcmp(a_min, a_max, length) > 0 || ++ memcmp(b_min, b_max, length) > 0) ++ return 0; ++ ++ /* ++ * Punt overlaps. ++ */ ++ if (memcmp(a_max, b_min, length) >= 0) ++ return 0; ++ ++ /* ++ * Merge if a and b are adjacent. We check for ++ * adjacency by subtracting one from b_min first. ++ */ ++ for (j = length - 1; j >= 0 && b_min[j]-- == 0x00; j--) ; ++ if (memcmp(a_max, b_min, length) == 0) { ++ IPAddressOrRange *merged; ++ if (!make_addressRange(&merged, a_min, b_max, length)) ++ return 0; ++ (void)sk_IPAddressOrRange_set(aors, i, merged); ++ (void)sk_IPAddressOrRange_delete(aors, i + 1); ++ IPAddressOrRange_free(a); ++ IPAddressOrRange_free(b); ++ --i; ++ continue; ++ } ++ } ++ ++ /* ++ * Check for inverted final range. ++ */ ++ j = sk_IPAddressOrRange_num(aors) - 1; ++ { ++ IPAddressOrRange *a = sk_IPAddressOrRange_value(aors, j); ++ if (a != NULL && a->type == IPAddressOrRange_addressRange) { ++ unsigned char a_min[ADDR_RAW_BUF_LEN], a_max[ADDR_RAW_BUF_LEN]; ++ if (!extract_min_max(a, a_min, a_max, length)) ++ return 0; ++ if (memcmp(a_min, a_max, length) > 0) ++ return 0; ++ } ++ } ++ ++ return 1; ++} ++ ++/* ++ * Whack an IPAddrBlocks extension into canonical form. ++ */ ++int X509v3_addr_canonize(IPAddrBlocks *addr) ++{ ++ int i; ++ for (i = 0; i < sk_IPAddressFamily_num(addr); i++) { ++ IPAddressFamily *f = sk_IPAddressFamily_value(addr, i); ++ if (f->ipAddressChoice->type == IPAddressChoice_addressesOrRanges && ++ !IPAddressOrRanges_canonize(f->ipAddressChoice-> ++ u.addressesOrRanges, ++ X509v3_addr_get_afi(f))) ++ return 0; ++ } ++ (void)sk_IPAddressFamily_set_cmp_func(addr, IPAddressFamily_cmp); ++ sk_IPAddressFamily_sort(addr); ++ OPENSSL_assert(X509v3_addr_is_canonical(addr)); ++ return 1; ++} ++ ++/* ++ * v2i handler for the IPAddrBlocks extension. ++ */ ++static void *v2i_IPAddrBlocks(const struct v3_ext_method *method, ++ struct v3_ext_ctx *ctx, ++ STACK_OF(CONF_VALUE) *values) ++{ ++ static const char v4addr_chars[] = "0123456789."; ++ static const char v6addr_chars[] = "0123456789.:abcdefABCDEF"; ++ IPAddrBlocks *addr = NULL; ++ char *s = NULL, *t; ++ int i; ++ ++ if ((addr = sk_IPAddressFamily_new(IPAddressFamily_cmp)) == NULL) { ++ X509V3err(X509V3_F_V2I_IPADDRBLOCKS, ERR_R_MALLOC_FAILURE); ++ return NULL; ++ } ++ ++ for (i = 0; i < sk_CONF_VALUE_num(values); i++) { ++ CONF_VALUE *val = sk_CONF_VALUE_value(values, i); ++ unsigned char min[ADDR_RAW_BUF_LEN], max[ADDR_RAW_BUF_LEN]; ++ unsigned afi, *safi = NULL, safi_; ++ const char *addr_chars = NULL; ++ int prefixlen, i1, i2, delim, length; ++ ++ if (!name_cmp(val->name, "IPv4")) { ++ afi = IANA_AFI_IPV4; ++ } else if (!name_cmp(val->name, "IPv6")) { ++ afi = IANA_AFI_IPV6; ++ } else if (!name_cmp(val->name, "IPv4-SAFI")) { ++ afi = IANA_AFI_IPV4; ++ safi = &safi_; ++ } else if (!name_cmp(val->name, "IPv6-SAFI")) { ++ afi = IANA_AFI_IPV6; ++ safi = &safi_; ++ } else { ++ X509V3err(X509V3_F_V2I_IPADDRBLOCKS, ++ X509V3_R_EXTENSION_NAME_ERROR); ++ X509V3_conf_err(val); ++ goto err; ++ } ++ ++ switch (afi) { ++ case IANA_AFI_IPV4: ++ addr_chars = v4addr_chars; ++ break; ++ case IANA_AFI_IPV6: ++ addr_chars = v6addr_chars; ++ break; ++ } ++ ++ length = length_from_afi(afi); ++ ++ /* ++ * Handle SAFI, if any, and OPENSSL_strdup() so we can null-terminate ++ * the other input values. ++ */ ++ if (safi != NULL) { ++ *safi = strtoul(val->value, &t, 0); ++ t += strspn(t, " \t"); ++ if (*safi > 0xFF || *t++ != ':') { ++ X509V3err(X509V3_F_V2I_IPADDRBLOCKS, X509V3_R_INVALID_SAFI); ++ X509V3_conf_err(val); ++ goto err; ++ } ++ t += strspn(t, " \t"); ++ s = OPENSSL_strdup(t); ++ } else { ++ s = OPENSSL_strdup(val->value); ++ } ++ if (s == NULL) { ++ X509V3err(X509V3_F_V2I_IPADDRBLOCKS, ERR_R_MALLOC_FAILURE); ++ goto err; ++ } ++ ++ /* ++ * Check for inheritance. Not worth additional complexity to ++ * optimize this (seldom-used) case. ++ */ ++ if (strcmp(s, "inherit") == 0) { ++ if (!X509v3_addr_add_inherit(addr, afi, safi)) { ++ X509V3err(X509V3_F_V2I_IPADDRBLOCKS, ++ X509V3_R_INVALID_INHERITANCE); ++ X509V3_conf_err(val); ++ goto err; ++ } ++ OPENSSL_free(s); ++ s = NULL; ++ continue; ++ } ++ ++ i1 = strspn(s, addr_chars); ++ i2 = i1 + strspn(s + i1, " \t"); ++ delim = s[i2++]; ++ s[i1] = '\0'; ++ ++ if (a2i_ipadd(min, s) != length) { ++ X509V3err(X509V3_F_V2I_IPADDRBLOCKS, X509V3_R_INVALID_IPADDRESS); ++ X509V3_conf_err(val); ++ goto err; ++ } ++ ++ switch (delim) { ++ case '/': ++ prefixlen = (int)strtoul(s + i2, &t, 10); ++ if (t == s + i2 || *t != '\0') { ++ X509V3err(X509V3_F_V2I_IPADDRBLOCKS, ++ X509V3_R_EXTENSION_VALUE_ERROR); ++ X509V3_conf_err(val); ++ goto err; ++ } ++ if (!X509v3_addr_add_prefix(addr, afi, safi, min, prefixlen)) { ++ X509V3err(X509V3_F_V2I_IPADDRBLOCKS, ERR_R_MALLOC_FAILURE); ++ goto err; ++ } ++ break; ++ case '-': ++ i1 = i2 + strspn(s + i2, " \t"); ++ i2 = i1 + strspn(s + i1, addr_chars); ++ if (i1 == i2 || s[i2] != '\0') { ++ X509V3err(X509V3_F_V2I_IPADDRBLOCKS, ++ X509V3_R_EXTENSION_VALUE_ERROR); ++ X509V3_conf_err(val); ++ goto err; ++ } ++ if (a2i_ipadd(max, s + i1) != length) { ++ X509V3err(X509V3_F_V2I_IPADDRBLOCKS, ++ X509V3_R_INVALID_IPADDRESS); ++ X509V3_conf_err(val); ++ goto err; ++ } ++ if (memcmp(min, max, length_from_afi(afi)) > 0) { ++ X509V3err(X509V3_F_V2I_IPADDRBLOCKS, ++ X509V3_R_EXTENSION_VALUE_ERROR); ++ X509V3_conf_err(val); ++ goto err; ++ } ++ if (!X509v3_addr_add_range(addr, afi, safi, min, max)) { ++ X509V3err(X509V3_F_V2I_IPADDRBLOCKS, ERR_R_MALLOC_FAILURE); ++ goto err; ++ } ++ break; ++ case '\0': ++ if (!X509v3_addr_add_prefix(addr, afi, safi, min, length * 8)) { ++ X509V3err(X509V3_F_V2I_IPADDRBLOCKS, ERR_R_MALLOC_FAILURE); ++ goto err; ++ } ++ break; ++ default: ++ X509V3err(X509V3_F_V2I_IPADDRBLOCKS, ++ X509V3_R_EXTENSION_VALUE_ERROR); ++ X509V3_conf_err(val); ++ goto err; ++ } ++ ++ OPENSSL_free(s); ++ s = NULL; ++ } ++ ++ /* ++ * Canonize the result, then we're done. ++ */ ++ if (!X509v3_addr_canonize(addr)) ++ goto err; ++ return addr; ++ ++ err: ++ OPENSSL_free(s); ++ sk_IPAddressFamily_pop_free(addr, IPAddressFamily_free); ++ return NULL; ++} ++ ++/* ++ * OpenSSL dispatch ++ */ ++const X509V3_EXT_METHOD v3_addr = { ++ NID_sbgp_ipAddrBlock, /* nid */ ++ 0, /* flags */ ++ ASN1_ITEM_ref(IPAddrBlocks), /* template */ ++ 0, 0, 0, 0, /* old functions, ignored */ ++ 0, /* i2s */ ++ 0, /* s2i */ ++ 0, /* i2v */ ++ v2i_IPAddrBlocks, /* v2i */ ++ i2r_IPAddrBlocks, /* i2r */ ++ 0, /* r2i */ ++ NULL /* extension-specific data */ ++}; ++ ++/* ++ * Figure out whether extension sues inheritance. ++ */ ++int X509v3_addr_inherits(IPAddrBlocks *addr) ++{ ++ int i; ++ if (addr == NULL) ++ return 0; ++ for (i = 0; i < sk_IPAddressFamily_num(addr); i++) { ++ IPAddressFamily *f = sk_IPAddressFamily_value(addr, i); ++ if (f->ipAddressChoice->type == IPAddressChoice_inherit) ++ return 1; ++ } ++ return 0; ++} ++ ++/* ++ * Figure out whether parent contains child. ++ */ ++static int addr_contains(IPAddressOrRanges *parent, ++ IPAddressOrRanges *child, int length) ++{ ++ unsigned char p_min[ADDR_RAW_BUF_LEN], p_max[ADDR_RAW_BUF_LEN]; ++ unsigned char c_min[ADDR_RAW_BUF_LEN], c_max[ADDR_RAW_BUF_LEN]; ++ int p, c; ++ ++ if (child == NULL || parent == child) ++ return 1; ++ if (parent == NULL) ++ return 0; ++ ++ p = 0; ++ for (c = 0; c < sk_IPAddressOrRange_num(child); c++) { ++ if (!extract_min_max(sk_IPAddressOrRange_value(child, c), ++ c_min, c_max, length)) ++ return -1; ++ for (;; p++) { ++ if (p >= sk_IPAddressOrRange_num(parent)) ++ return 0; ++ if (!extract_min_max(sk_IPAddressOrRange_value(parent, p), ++ p_min, p_max, length)) ++ return 0; ++ if (memcmp(p_max, c_max, length) < 0) ++ continue; ++ if (memcmp(p_min, c_min, length) > 0) ++ return 0; ++ break; ++ } ++ } ++ ++ return 1; ++} ++ ++/* ++ * Test whether a is a subset of b. ++ */ ++int X509v3_addr_subset(IPAddrBlocks *a, IPAddrBlocks *b) ++{ ++ int i; ++ if (a == NULL || a == b) ++ return 1; ++ if (b == NULL || X509v3_addr_inherits(a) || X509v3_addr_inherits(b)) ++ return 0; ++ (void)sk_IPAddressFamily_set_cmp_func(b, IPAddressFamily_cmp); ++ for (i = 0; i < sk_IPAddressFamily_num(a); i++) { ++ IPAddressFamily *fa = sk_IPAddressFamily_value(a, i); ++ int j = sk_IPAddressFamily_find(b, fa); ++ IPAddressFamily *fb; ++ fb = sk_IPAddressFamily_value(b, j); ++ if (fb == NULL) ++ return 0; ++ if (!addr_contains(fb->ipAddressChoice->u.addressesOrRanges, ++ fa->ipAddressChoice->u.addressesOrRanges, ++ length_from_afi(X509v3_addr_get_afi(fb)))) ++ return 0; ++ } ++ return 1; ++} ++ ++/* ++ * Validation error handling via callback. ++ */ ++#define validation_err(_err_) \ ++ do { \ ++ if (ctx != NULL) { \ ++ ctx->error = _err_; \ ++ ctx->error_depth = i; \ ++ ctx->current_cert = x; \ ++ ret = ctx->verify_cb(0, ctx); \ ++ } else { \ ++ ret = 0; \ ++ } \ ++ if (!ret) \ ++ goto done; \ ++ } while (0) ++ ++/* ++ * Core code for RFC 3779 2.3 path validation. ++ * ++ * Returns 1 for success, 0 on error. ++ * ++ * When returning 0, ctx->error MUST be set to an appropriate value other than ++ * X509_V_OK. ++ */ ++static int addr_validate_path_internal(X509_STORE_CTX *ctx, ++ STACK_OF(X509) *chain, ++ IPAddrBlocks *ext) ++{ ++ IPAddrBlocks *child = NULL; ++ int i, j, ret = 1; ++ X509 *x; ++ ++ OPENSSL_assert(chain != NULL && sk_X509_num(chain) > 0); ++ OPENSSL_assert(ctx != NULL || ext != NULL); ++ OPENSSL_assert(ctx == NULL || ctx->verify_cb != NULL); ++ ++ /* ++ * Figure out where to start. If we don't have an extension to ++ * check, we're done. Otherwise, check canonical form and ++ * set up for walking up the chain. ++ */ ++ if (ext != NULL) { ++ i = -1; ++ x = NULL; ++ } else { ++ i = 0; ++ x = sk_X509_value(chain, i); ++ OPENSSL_assert(x != NULL); ++ if ((ext = x->rfc3779_addr) == NULL) ++ goto done; ++ } ++ if (!X509v3_addr_is_canonical(ext)) ++ validation_err(X509_V_ERR_INVALID_EXTENSION); ++ (void)sk_IPAddressFamily_set_cmp_func(ext, IPAddressFamily_cmp); ++ if ((child = sk_IPAddressFamily_dup(ext)) == NULL) { ++ X509V3err(X509V3_F_ADDR_VALIDATE_PATH_INTERNAL, ++ ERR_R_MALLOC_FAILURE); ++ ctx->error = X509_V_ERR_OUT_OF_MEM; ++ ret = 0; ++ goto done; ++ } ++ ++ /* ++ * Now walk up the chain. No cert may list resources that its ++ * parent doesn't list. ++ */ ++ for (i++; i < sk_X509_num(chain); i++) { ++ x = sk_X509_value(chain, i); ++ OPENSSL_assert(x != NULL); ++ if (!X509v3_addr_is_canonical(x->rfc3779_addr)) ++ validation_err(X509_V_ERR_INVALID_EXTENSION); ++ if (x->rfc3779_addr == NULL) { ++ for (j = 0; j < sk_IPAddressFamily_num(child); j++) { ++ IPAddressFamily *fc = sk_IPAddressFamily_value(child, j); ++ if (fc->ipAddressChoice->type != IPAddressChoice_inherit) { ++ validation_err(X509_V_ERR_UNNESTED_RESOURCE); ++ break; ++ } ++ } ++ continue; ++ } ++ (void)sk_IPAddressFamily_set_cmp_func(x->rfc3779_addr, ++ IPAddressFamily_cmp); ++ for (j = 0; j < sk_IPAddressFamily_num(child); j++) { ++ IPAddressFamily *fc = sk_IPAddressFamily_value(child, j); ++ int k = sk_IPAddressFamily_find(x->rfc3779_addr, fc); ++ IPAddressFamily *fp = ++ sk_IPAddressFamily_value(x->rfc3779_addr, k); ++ if (fp == NULL) { ++ if (fc->ipAddressChoice->type == ++ IPAddressChoice_addressesOrRanges) { ++ validation_err(X509_V_ERR_UNNESTED_RESOURCE); ++ break; ++ } ++ continue; ++ } ++ if (fp->ipAddressChoice->type == ++ IPAddressChoice_addressesOrRanges) { ++ if (fc->ipAddressChoice->type == IPAddressChoice_inherit ++ || addr_contains(fp->ipAddressChoice->u.addressesOrRanges, ++ fc->ipAddressChoice->u.addressesOrRanges, ++ length_from_afi(X509v3_addr_get_afi(fc)))) ++ sk_IPAddressFamily_set(child, j, fp); ++ else ++ validation_err(X509_V_ERR_UNNESTED_RESOURCE); ++ } ++ } ++ } ++ ++ /* ++ * Trust anchor can't inherit. ++ */ ++ OPENSSL_assert(x != NULL); ++ if (x->rfc3779_addr != NULL) { ++ for (j = 0; j < sk_IPAddressFamily_num(x->rfc3779_addr); j++) { ++ IPAddressFamily *fp = ++ sk_IPAddressFamily_value(x->rfc3779_addr, j); ++ if (fp->ipAddressChoice->type == IPAddressChoice_inherit ++ && sk_IPAddressFamily_find(child, fp) >= 0) ++ validation_err(X509_V_ERR_UNNESTED_RESOURCE); ++ } ++ } ++ ++ done: ++ sk_IPAddressFamily_free(child); ++ return ret; ++} ++ ++#undef validation_err ++ ++/* ++ * RFC 3779 2.3 path validation -- called from X509_verify_cert(). ++ */ ++int X509v3_addr_validate_path(X509_STORE_CTX *ctx) ++{ ++ return addr_validate_path_internal(ctx, ctx->chain, NULL); ++} ++ ++/* ++ * RFC 3779 2.3 path validation of an extension. ++ * Test whether chain covers extension. ++ */ ++int X509v3_addr_validate_resource_set(STACK_OF(X509) *chain, ++ IPAddrBlocks *ext, int allow_inheritance) ++{ ++ if (ext == NULL) ++ return 1; ++ if (chain == NULL || sk_X509_num(chain) == 0) ++ return 0; ++ if (!allow_inheritance && X509v3_addr_inherits(ext)) ++ return 0; ++ return addr_validate_path_internal(NULL, chain, ext); ++} ++ ++#endif /* OPENSSL_NO_RFC3779 */ +diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/x509v3/v3_akey.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/x509v3/v3_akey.c +new file mode 100644 +index 0000000..d9f7704 +--- /dev/null ++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/x509v3/v3_akey.c +@@ -0,0 +1,160 @@ ++/* ++ * Copyright 1999-2016 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 ++ * in the file LICENSE in the source distribution or at ++ * https://www.openssl.org/source/license.html ++ */ ++ ++#include ++#include "internal/cryptlib.h" ++#include ++#include ++#include ++#include ++#include "ext_dat.h" ++ ++static STACK_OF(CONF_VALUE) *i2v_AUTHORITY_KEYID(X509V3_EXT_METHOD *method, ++ AUTHORITY_KEYID *akeyid, ++ STACK_OF(CONF_VALUE) ++ *extlist); ++static AUTHORITY_KEYID *v2i_AUTHORITY_KEYID(X509V3_EXT_METHOD *method, ++ X509V3_CTX *ctx, ++ STACK_OF(CONF_VALUE) *values); ++ ++const X509V3_EXT_METHOD v3_akey_id = { ++ NID_authority_key_identifier, ++ X509V3_EXT_MULTILINE, ASN1_ITEM_ref(AUTHORITY_KEYID), ++ 0, 0, 0, 0, ++ 0, 0, ++ (X509V3_EXT_I2V) i2v_AUTHORITY_KEYID, ++ (X509V3_EXT_V2I)v2i_AUTHORITY_KEYID, ++ 0, 0, ++ NULL ++}; ++ ++static STACK_OF(CONF_VALUE) *i2v_AUTHORITY_KEYID(X509V3_EXT_METHOD *method, ++ AUTHORITY_KEYID *akeyid, ++ STACK_OF(CONF_VALUE) ++ *extlist) ++{ ++ char *tmp; ++ if (akeyid->keyid) { ++ tmp = OPENSSL_buf2hexstr(akeyid->keyid->data, akeyid->keyid->length); ++ X509V3_add_value("keyid", tmp, &extlist); ++ OPENSSL_free(tmp); ++ } ++ if (akeyid->issuer) ++ extlist = i2v_GENERAL_NAMES(NULL, akeyid->issuer, extlist); ++ if (akeyid->serial) { ++ tmp = OPENSSL_buf2hexstr(akeyid->serial->data, akeyid->serial->length); ++ X509V3_add_value("serial", tmp, &extlist); ++ OPENSSL_free(tmp); ++ } ++ return extlist; ++} ++ ++/*- ++ * Currently two options: ++ * keyid: use the issuers subject keyid, the value 'always' means its is ++ * an error if the issuer certificate doesn't have a key id. ++ * issuer: use the issuers cert issuer and serial number. The default is ++ * to only use this if keyid is not present. With the option 'always' ++ * this is always included. ++ */ ++ ++static AUTHORITY_KEYID *v2i_AUTHORITY_KEYID(X509V3_EXT_METHOD *method, ++ X509V3_CTX *ctx, ++ STACK_OF(CONF_VALUE) *values) ++{ ++ char keyid = 0, issuer = 0; ++ int i; ++ CONF_VALUE *cnf; ++ ASN1_OCTET_STRING *ikeyid = NULL; ++ X509_NAME *isname = NULL; ++ GENERAL_NAMES *gens = NULL; ++ GENERAL_NAME *gen = NULL; ++ ASN1_INTEGER *serial = NULL; ++ X509_EXTENSION *ext; ++ X509 *cert; ++ AUTHORITY_KEYID *akeyid; ++ ++ for (i = 0; i < sk_CONF_VALUE_num(values); i++) { ++ cnf = sk_CONF_VALUE_value(values, i); ++ if (strcmp(cnf->name, "keyid") == 0) { ++ keyid = 1; ++ if (cnf->value && strcmp(cnf->value, "always") == 0) ++ keyid = 2; ++ } else if (strcmp(cnf->name, "issuer") == 0) { ++ issuer = 1; ++ if (cnf->value && strcmp(cnf->value, "always") == 0) ++ issuer = 2; ++ } else { ++ X509V3err(X509V3_F_V2I_AUTHORITY_KEYID, X509V3_R_UNKNOWN_OPTION); ++ ERR_add_error_data(2, "name=", cnf->name); ++ return NULL; ++ } ++ } ++ ++ if (!ctx || !ctx->issuer_cert) { ++ if (ctx && (ctx->flags == CTX_TEST)) ++ return AUTHORITY_KEYID_new(); ++ X509V3err(X509V3_F_V2I_AUTHORITY_KEYID, ++ X509V3_R_NO_ISSUER_CERTIFICATE); ++ return NULL; ++ } ++ ++ cert = ctx->issuer_cert; ++ ++ if (keyid) { ++ i = X509_get_ext_by_NID(cert, NID_subject_key_identifier, -1); ++ if ((i >= 0) && (ext = X509_get_ext(cert, i))) ++ ikeyid = X509V3_EXT_d2i(ext); ++ if (keyid == 2 && !ikeyid) { ++ X509V3err(X509V3_F_V2I_AUTHORITY_KEYID, ++ X509V3_R_UNABLE_TO_GET_ISSUER_KEYID); ++ return NULL; ++ } ++ } ++ ++ if ((issuer && !ikeyid) || (issuer == 2)) { ++ isname = X509_NAME_dup(X509_get_issuer_name(cert)); ++ serial = ASN1_INTEGER_dup(X509_get_serialNumber(cert)); ++ if (!isname || !serial) { ++ X509V3err(X509V3_F_V2I_AUTHORITY_KEYID, ++ X509V3_R_UNABLE_TO_GET_ISSUER_DETAILS); ++ goto err; ++ } ++ } ++ ++ if ((akeyid = AUTHORITY_KEYID_new()) == NULL) ++ goto err; ++ ++ if (isname) { ++ if ((gens = sk_GENERAL_NAME_new_null()) == NULL ++ || (gen = GENERAL_NAME_new()) == NULL ++ || !sk_GENERAL_NAME_push(gens, gen)) { ++ X509V3err(X509V3_F_V2I_AUTHORITY_KEYID, ERR_R_MALLOC_FAILURE); ++ goto err; ++ } ++ gen->type = GEN_DIRNAME; ++ gen->d.dirn = isname; ++ } ++ ++ akeyid->issuer = gens; ++ gen = NULL; ++ gens = NULL; ++ akeyid->serial = serial; ++ akeyid->keyid = ikeyid; ++ ++ return akeyid; ++ ++ err: ++ sk_GENERAL_NAME_free(gens); ++ GENERAL_NAME_free(gen); ++ X509_NAME_free(isname); ++ ASN1_INTEGER_free(serial); ++ ASN1_OCTET_STRING_free(ikeyid); ++ return NULL; ++} +diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/x509v3/v3_akeya.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/x509v3/v3_akeya.c +new file mode 100644 +index 0000000..d6dd6bc +--- /dev/null ++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/x509v3/v3_akeya.c +@@ -0,0 +1,23 @@ ++/* ++ * Copyright 2001-2016 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 ++ * in the file LICENSE in the source distribution or at ++ * https://www.openssl.org/source/license.html ++ */ ++ ++#include ++#include "internal/cryptlib.h" ++#include ++#include ++#include ++#include ++ ++ASN1_SEQUENCE(AUTHORITY_KEYID) = { ++ ASN1_IMP_OPT(AUTHORITY_KEYID, keyid, ASN1_OCTET_STRING, 0), ++ ASN1_IMP_SEQUENCE_OF_OPT(AUTHORITY_KEYID, issuer, GENERAL_NAME, 1), ++ ASN1_IMP_OPT(AUTHORITY_KEYID, serial, ASN1_INTEGER, 2) ++} ASN1_SEQUENCE_END(AUTHORITY_KEYID) ++ ++IMPLEMENT_ASN1_FUNCTIONS(AUTHORITY_KEYID) +diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/x509v3/v3_alt.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/x509v3/v3_alt.c +new file mode 100644 +index 0000000..0364e33 +--- /dev/null ++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/x509v3/v3_alt.c +@@ -0,0 +1,566 @@ ++/* ++ * Copyright 1999-2016 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 ++ * in the file LICENSE in the source distribution or at ++ * https://www.openssl.org/source/license.html ++ */ ++ ++#include ++#include "internal/cryptlib.h" ++#include ++#include ++#include "ext_dat.h" ++ ++static GENERAL_NAMES *v2i_subject_alt(X509V3_EXT_METHOD *method, ++ X509V3_CTX *ctx, ++ STACK_OF(CONF_VALUE) *nval); ++static GENERAL_NAMES *v2i_issuer_alt(X509V3_EXT_METHOD *method, ++ X509V3_CTX *ctx, ++ STACK_OF(CONF_VALUE) *nval); ++static int copy_email(X509V3_CTX *ctx, GENERAL_NAMES *gens, int move_p); ++static int copy_issuer(X509V3_CTX *ctx, GENERAL_NAMES *gens); ++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); ++ ++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, ++ (X509V3_EXT_V2I)v2i_subject_alt, ++ NULL, NULL, NULL}, ++ ++ {NID_issuer_alt_name, 0, ASN1_ITEM_ref(GENERAL_NAMES), ++ 0, 0, 0, 0, ++ 0, 0, ++ (X509V3_EXT_I2V) i2v_GENERAL_NAMES, ++ (X509V3_EXT_V2I)v2i_issuer_alt, ++ 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}, ++}; ++ ++STACK_OF(CONF_VALUE) *i2v_GENERAL_NAMES(X509V3_EXT_METHOD *method, ++ GENERAL_NAMES *gens, ++ STACK_OF(CONF_VALUE) *ret) ++{ ++ int i; ++ GENERAL_NAME *gen; ++ for (i = 0; i < sk_GENERAL_NAME_num(gens); i++) { ++ gen = sk_GENERAL_NAME_value(gens, i); ++ ret = i2v_GENERAL_NAME(method, gen, ret); ++ } ++ if (!ret) ++ return sk_CONF_VALUE_new_null(); ++ return ret; ++} ++ ++STACK_OF(CONF_VALUE) *i2v_GENERAL_NAME(X509V3_EXT_METHOD *method, ++ GENERAL_NAME *gen, ++ STACK_OF(CONF_VALUE) *ret) ++{ ++ unsigned char *p; ++ char oline[256], htmp[5]; ++ int i; ++ switch (gen->type) { ++ case GEN_OTHERNAME: ++ X509V3_add_value("othername", "", &ret); ++ break; ++ ++ case GEN_X400: ++ X509V3_add_value("X400Name", "", &ret); ++ break; ++ ++ case GEN_EDIPARTY: ++ X509V3_add_value("EdiPartyName", "", &ret); ++ break; ++ ++ case GEN_EMAIL: ++ X509V3_add_value_uchar("email", gen->d.ia5->data, &ret); ++ break; ++ ++ case GEN_DNS: ++ X509V3_add_value_uchar("DNS", gen->d.ia5->data, &ret); ++ break; ++ ++ case GEN_URI: ++ X509V3_add_value_uchar("URI", gen->d.ia5->data, &ret); ++ break; ++ ++ case GEN_DIRNAME: ++ X509_NAME_oneline(gen->d.dirn, oline, 256); ++ X509V3_add_value("DirName", oline, &ret); ++ 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 { ++ X509V3_add_value("IP Address", "", &ret); ++ break; ++ } ++ X509V3_add_value("IP Address", oline, &ret); ++ break; ++ ++ case GEN_RID: ++ i2t_ASN1_OBJECT(oline, 256, gen->d.rid); ++ X509V3_add_value("Registered ID", oline, &ret); ++ break; ++ } ++ return ret; ++} ++ ++int GENERAL_NAME_print(BIO *out, GENERAL_NAME *gen) ++{ ++ unsigned char *p; ++ int i; ++ switch (gen->type) { ++ case GEN_OTHERNAME: ++ BIO_printf(out, "othername:"); ++ break; ++ ++ case GEN_X400: ++ BIO_printf(out, "X400Name:"); ++ break; ++ ++ case GEN_EDIPARTY: ++ /* Maybe fix this: it is supported now */ ++ BIO_printf(out, "EdiPartyName:"); ++ break; ++ ++ case GEN_EMAIL: ++ BIO_printf(out, "email:%s", gen->d.ia5->data); ++ break; ++ ++ case GEN_DNS: ++ BIO_printf(out, "DNS:%s", gen->d.ia5->data); ++ break; ++ ++ case GEN_URI: ++ BIO_printf(out, "URI:%s", gen->d.ia5->data); ++ break; ++ ++ case GEN_DIRNAME: ++ BIO_printf(out, "DirName:"); ++ X509_NAME_print_ex(out, gen->d.dirn, 0, XN_FLAG_ONELINE); ++ break; ++ ++ case GEN_IPADD: ++ p = gen->d.ip->data; ++ if (gen->d.ip->length == 4) ++ BIO_printf(out, "IP Address:%d.%d.%d.%d", p[0], p[1], p[2], p[3]); ++ else if (gen->d.ip->length == 16) { ++ BIO_printf(out, "IP Address"); ++ for (i = 0; i < 8; i++) { ++ BIO_printf(out, ":%X", p[0] << 8 | p[1]); ++ p += 2; ++ } ++ BIO_puts(out, "\n"); ++ } else { ++ BIO_printf(out, "IP Address:"); ++ break; ++ } ++ break; ++ ++ case GEN_RID: ++ BIO_printf(out, "Registered ID:"); ++ i2a_ASN1_OBJECT(out, gen->d.rid); ++ break; ++ } ++ return 1; ++} ++ ++static GENERAL_NAMES *v2i_issuer_alt(X509V3_EXT_METHOD *method, ++ X509V3_CTX *ctx, ++ STACK_OF(CONF_VALUE) *nval) ++{ ++ GENERAL_NAMES *gens = NULL; ++ CONF_VALUE *cnf; ++ int i; ++ ++ if ((gens = sk_GENERAL_NAME_new_null()) == NULL) { ++ X509V3err(X509V3_F_V2I_ISSUER_ALT, ERR_R_MALLOC_FAILURE); ++ return NULL; ++ } ++ for (i = 0; i < sk_CONF_VALUE_num(nval); i++) { ++ cnf = sk_CONF_VALUE_value(nval, i); ++ if (!name_cmp(cnf->name, "issuer") ++ && cnf->value && strcmp(cnf->value, "copy") == 0) { ++ if (!copy_issuer(ctx, gens)) ++ goto err; ++ } else { ++ GENERAL_NAME *gen; ++ if ((gen = v2i_GENERAL_NAME(method, ctx, cnf)) == NULL) ++ goto err; ++ sk_GENERAL_NAME_push(gens, gen); ++ } ++ } ++ return gens; ++ err: ++ sk_GENERAL_NAME_pop_free(gens, GENERAL_NAME_free); ++ return NULL; ++} ++ ++/* Append subject altname of issuer to issuer alt name of subject */ ++ ++static int copy_issuer(X509V3_CTX *ctx, GENERAL_NAMES *gens) ++{ ++ GENERAL_NAMES *ialt; ++ GENERAL_NAME *gen; ++ X509_EXTENSION *ext; ++ int i; ++ ++ if (ctx && (ctx->flags == CTX_TEST)) ++ return 1; ++ if (!ctx || !ctx->issuer_cert) { ++ X509V3err(X509V3_F_COPY_ISSUER, X509V3_R_NO_ISSUER_DETAILS); ++ goto err; ++ } ++ i = X509_get_ext_by_NID(ctx->issuer_cert, NID_subject_alt_name, -1); ++ if (i < 0) ++ return 1; ++ if ((ext = X509_get_ext(ctx->issuer_cert, i)) == NULL ++ || (ialt = X509V3_EXT_d2i(ext)) == NULL) { ++ X509V3err(X509V3_F_COPY_ISSUER, X509V3_R_ISSUER_DECODE_ERROR); ++ goto err; ++ } ++ ++ for (i = 0; i < sk_GENERAL_NAME_num(ialt); i++) { ++ gen = sk_GENERAL_NAME_value(ialt, i); ++ if (!sk_GENERAL_NAME_push(gens, gen)) { ++ X509V3err(X509V3_F_COPY_ISSUER, ERR_R_MALLOC_FAILURE); ++ goto err; ++ } ++ } ++ sk_GENERAL_NAME_free(ialt); ++ ++ return 1; ++ ++ err: ++ return 0; ++ ++} ++ ++static GENERAL_NAMES *v2i_subject_alt(X509V3_EXT_METHOD *method, ++ X509V3_CTX *ctx, ++ STACK_OF(CONF_VALUE) *nval) ++{ ++ GENERAL_NAMES *gens = NULL; ++ CONF_VALUE *cnf; ++ int i; ++ ++ if ((gens = sk_GENERAL_NAME_new_null()) == NULL) { ++ X509V3err(X509V3_F_V2I_SUBJECT_ALT, ERR_R_MALLOC_FAILURE); ++ return NULL; ++ } ++ for (i = 0; i < sk_CONF_VALUE_num(nval); i++) { ++ cnf = sk_CONF_VALUE_value(nval, i); ++ if (!name_cmp(cnf->name, "email") ++ && cnf->value && strcmp(cnf->value, "copy") == 0) { ++ if (!copy_email(ctx, gens, 0)) ++ goto err; ++ } else if (!name_cmp(cnf->name, "email") ++ && cnf->value && strcmp(cnf->value, "move") == 0) { ++ if (!copy_email(ctx, gens, 1)) ++ goto err; ++ } else { ++ GENERAL_NAME *gen; ++ if ((gen = v2i_GENERAL_NAME(method, ctx, cnf)) == NULL) ++ goto err; ++ sk_GENERAL_NAME_push(gens, gen); ++ } ++ } ++ return gens; ++ err: ++ sk_GENERAL_NAME_pop_free(gens, GENERAL_NAME_free); ++ return NULL; ++} ++ ++/* ++ * Copy any email addresses in a certificate or request to GENERAL_NAMES ++ */ ++ ++static int copy_email(X509V3_CTX *ctx, GENERAL_NAMES *gens, int move_p) ++{ ++ X509_NAME *nm; ++ ASN1_IA5STRING *email = NULL; ++ X509_NAME_ENTRY *ne; ++ GENERAL_NAME *gen = NULL; ++ int i; ++ if (ctx != NULL && ctx->flags == CTX_TEST) ++ return 1; ++ if (!ctx || (!ctx->subject_cert && !ctx->subject_req)) { ++ X509V3err(X509V3_F_COPY_EMAIL, X509V3_R_NO_SUBJECT_DETAILS); ++ goto err; ++ } ++ /* Find the subject name */ ++ if (ctx->subject_cert) ++ nm = X509_get_subject_name(ctx->subject_cert); ++ else ++ nm = X509_REQ_get_subject_name(ctx->subject_req); ++ ++ /* Now add any email address(es) to STACK */ ++ i = -1; ++ while ((i = X509_NAME_get_index_by_NID(nm, ++ NID_pkcs9_emailAddress, i)) >= 0) { ++ ne = X509_NAME_get_entry(nm, i); ++ email = ASN1_STRING_dup(X509_NAME_ENTRY_get_data(ne)); ++ if (move_p) { ++ X509_NAME_delete_entry(nm, i); ++ X509_NAME_ENTRY_free(ne); ++ i--; ++ } ++ if (email == NULL || (gen = GENERAL_NAME_new()) == NULL) { ++ X509V3err(X509V3_F_COPY_EMAIL, ERR_R_MALLOC_FAILURE); ++ goto err; ++ } ++ gen->d.ia5 = email; ++ email = NULL; ++ gen->type = GEN_EMAIL; ++ if (!sk_GENERAL_NAME_push(gens, gen)) { ++ X509V3err(X509V3_F_COPY_EMAIL, ERR_R_MALLOC_FAILURE); ++ goto err; ++ } ++ gen = NULL; ++ } ++ ++ return 1; ++ ++ err: ++ GENERAL_NAME_free(gen); ++ ASN1_IA5STRING_free(email); ++ return 0; ++ ++} ++ ++GENERAL_NAMES *v2i_GENERAL_NAMES(const X509V3_EXT_METHOD *method, ++ X509V3_CTX *ctx, STACK_OF(CONF_VALUE) *nval) ++{ ++ GENERAL_NAME *gen; ++ GENERAL_NAMES *gens = NULL; ++ CONF_VALUE *cnf; ++ int i; ++ ++ if ((gens = sk_GENERAL_NAME_new_null()) == NULL) { ++ X509V3err(X509V3_F_V2I_GENERAL_NAMES, ERR_R_MALLOC_FAILURE); ++ return NULL; ++ } ++ for (i = 0; i < sk_CONF_VALUE_num(nval); i++) { ++ cnf = sk_CONF_VALUE_value(nval, i); ++ if ((gen = v2i_GENERAL_NAME(method, ctx, cnf)) == NULL) ++ goto err; ++ sk_GENERAL_NAME_push(gens, gen); ++ } ++ return gens; ++ err: ++ sk_GENERAL_NAME_pop_free(gens, GENERAL_NAME_free); ++ return NULL; ++} ++ ++GENERAL_NAME *v2i_GENERAL_NAME(const X509V3_EXT_METHOD *method, ++ X509V3_CTX *ctx, CONF_VALUE *cnf) ++{ ++ return v2i_GENERAL_NAME_ex(NULL, method, ctx, cnf, 0); ++} ++ ++GENERAL_NAME *a2i_GENERAL_NAME(GENERAL_NAME *out, ++ const X509V3_EXT_METHOD *method, ++ X509V3_CTX *ctx, int gen_type, const char *value, ++ int is_nc) ++{ ++ char is_string = 0; ++ GENERAL_NAME *gen = NULL; ++ ++ if (!value) { ++ X509V3err(X509V3_F_A2I_GENERAL_NAME, X509V3_R_MISSING_VALUE); ++ return NULL; ++ } ++ ++ if (out) ++ gen = out; ++ else { ++ gen = GENERAL_NAME_new(); ++ if (gen == NULL) { ++ X509V3err(X509V3_F_A2I_GENERAL_NAME, ERR_R_MALLOC_FAILURE); ++ return NULL; ++ } ++ } ++ ++ switch (gen_type) { ++ case GEN_URI: ++ case GEN_EMAIL: ++ case GEN_DNS: ++ is_string = 1; ++ break; ++ ++ case GEN_RID: ++ { ++ ASN1_OBJECT *obj; ++ if ((obj = OBJ_txt2obj(value, 0)) == NULL) { ++ X509V3err(X509V3_F_A2I_GENERAL_NAME, X509V3_R_BAD_OBJECT); ++ ERR_add_error_data(2, "value=", value); ++ goto err; ++ } ++ gen->d.rid = obj; ++ } ++ break; ++ ++ case GEN_IPADD: ++ if (is_nc) ++ gen->d.ip = a2i_IPADDRESS_NC(value); ++ else ++ gen->d.ip = a2i_IPADDRESS(value); ++ if (gen->d.ip == NULL) { ++ X509V3err(X509V3_F_A2I_GENERAL_NAME, X509V3_R_BAD_IP_ADDRESS); ++ ERR_add_error_data(2, "value=", value); ++ goto err; ++ } ++ break; ++ ++ case GEN_DIRNAME: ++ if (!do_dirname(gen, value, ctx)) { ++ X509V3err(X509V3_F_A2I_GENERAL_NAME, X509V3_R_DIRNAME_ERROR); ++ goto err; ++ } ++ break; ++ ++ case GEN_OTHERNAME: ++ if (!do_othername(gen, value, ctx)) { ++ X509V3err(X509V3_F_A2I_GENERAL_NAME, X509V3_R_OTHERNAME_ERROR); ++ goto err; ++ } ++ break; ++ default: ++ X509V3err(X509V3_F_A2I_GENERAL_NAME, X509V3_R_UNSUPPORTED_TYPE); ++ goto err; ++ } ++ ++ if (is_string) { ++ if ((gen->d.ia5 = ASN1_IA5STRING_new()) == NULL || ++ !ASN1_STRING_set(gen->d.ia5, (unsigned char *)value, ++ strlen(value))) { ++ X509V3err(X509V3_F_A2I_GENERAL_NAME, ERR_R_MALLOC_FAILURE); ++ goto err; ++ } ++ } ++ ++ gen->type = gen_type; ++ ++ return gen; ++ ++ err: ++ if (!out) ++ GENERAL_NAME_free(gen); ++ return NULL; ++} ++ ++GENERAL_NAME *v2i_GENERAL_NAME_ex(GENERAL_NAME *out, ++ const X509V3_EXT_METHOD *method, ++ X509V3_CTX *ctx, CONF_VALUE *cnf, int is_nc) ++{ ++ int type; ++ ++ char *name, *value; ++ ++ name = cnf->name; ++ value = cnf->value; ++ ++ if (!value) { ++ X509V3err(X509V3_F_V2I_GENERAL_NAME_EX, X509V3_R_MISSING_VALUE); ++ return NULL; ++ } ++ ++ if (!name_cmp(name, "email")) ++ type = GEN_EMAIL; ++ else if (!name_cmp(name, "URI")) ++ type = GEN_URI; ++ else if (!name_cmp(name, "DNS")) ++ type = GEN_DNS; ++ else if (!name_cmp(name, "RID")) ++ type = GEN_RID; ++ else if (!name_cmp(name, "IP")) ++ type = GEN_IPADD; ++ else if (!name_cmp(name, "dirName")) ++ type = GEN_DIRNAME; ++ else if (!name_cmp(name, "otherName")) ++ type = GEN_OTHERNAME; ++ else { ++ X509V3err(X509V3_F_V2I_GENERAL_NAME_EX, X509V3_R_UNSUPPORTED_OPTION); ++ ERR_add_error_data(2, "name=", name); ++ return NULL; ++ } ++ ++ return a2i_GENERAL_NAME(out, method, ctx, type, value, is_nc); ++ ++} ++ ++static int do_othername(GENERAL_NAME *gen, const char *value, X509V3_CTX *ctx) ++{ ++ char *objtmp = NULL, *p; ++ int objlen; ++ ++ if ((p = strchr(value, ';')) == NULL) ++ return 0; ++ if ((gen->d.otherName = OTHERNAME_new()) == NULL) ++ return 0; ++ /* ++ * Free this up because we will overwrite it. no need to free type_id ++ * because it is static ++ */ ++ ASN1_TYPE_free(gen->d.otherName->value); ++ if ((gen->d.otherName->value = ASN1_generate_v3(p + 1, ctx)) == NULL) ++ return 0; ++ objlen = p - value; ++ objtmp = OPENSSL_strndup(value, objlen); ++ if (objtmp == NULL) ++ return 0; ++ gen->d.otherName->type_id = OBJ_txt2obj(objtmp, 0); ++ OPENSSL_free(objtmp); ++ if (!gen->d.otherName->type_id) ++ return 0; ++ return 1; ++} ++ ++static int do_dirname(GENERAL_NAME *gen, const char *value, X509V3_CTX *ctx) ++{ ++ int ret = 0; ++ STACK_OF(CONF_VALUE) *sk = NULL; ++ X509_NAME *nm; ++ ++ if ((nm = X509_NAME_new()) == NULL) ++ goto err; ++ sk = X509V3_get_section(ctx, value); ++ if (!sk) { ++ X509V3err(X509V3_F_DO_DIRNAME, X509V3_R_SECTION_NOT_FOUND); ++ ERR_add_error_data(2, "section=", value); ++ goto err; ++ } ++ /* FIXME: should allow other character types... */ ++ ret = X509V3_NAME_from_section(nm, sk, MBSTRING_ASC); ++ if (!ret) ++ goto err; ++ gen->d.dirn = nm; ++ ++err: ++ if (ret == 0) ++ X509_NAME_free(nm); ++ X509V3_section_free(ctx, sk); ++ return ret; ++} +diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/x509v3/v3_asid.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/x509v3/v3_asid.c +new file mode 100644 +index 0000000..af4fcf4 +--- /dev/null ++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/x509v3/v3_asid.c +@@ -0,0 +1,852 @@ ++/* ++ * Copyright 2006-2016 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 ++ * in the file LICENSE in the source distribution or at ++ * https://www.openssl.org/source/license.html ++ */ ++ ++/* ++ * Implementation of RFC 3779 section 3.2. ++ */ ++ ++#include ++#include ++#include "internal/cryptlib.h" ++#include ++#include ++#include ++#include ++#include ++#include "internal/x509_int.h" ++#include ++#include "ext_dat.h" ++ ++#ifndef OPENSSL_NO_RFC3779 ++ ++/* ++ * OpenSSL ASN.1 template translation of RFC 3779 3.2.3. ++ */ ++ ++ASN1_SEQUENCE(ASRange) = { ++ ASN1_SIMPLE(ASRange, min, ASN1_INTEGER), ++ ASN1_SIMPLE(ASRange, max, ASN1_INTEGER) ++} ASN1_SEQUENCE_END(ASRange) ++ ++ASN1_CHOICE(ASIdOrRange) = { ++ ASN1_SIMPLE(ASIdOrRange, u.id, ASN1_INTEGER), ++ ASN1_SIMPLE(ASIdOrRange, u.range, ASRange) ++} ASN1_CHOICE_END(ASIdOrRange) ++ ++ASN1_CHOICE(ASIdentifierChoice) = { ++ ASN1_SIMPLE(ASIdentifierChoice, u.inherit, ASN1_NULL), ++ ASN1_SEQUENCE_OF(ASIdentifierChoice, u.asIdsOrRanges, ASIdOrRange) ++} ASN1_CHOICE_END(ASIdentifierChoice) ++ ++ASN1_SEQUENCE(ASIdentifiers) = { ++ ASN1_EXP_OPT(ASIdentifiers, asnum, ASIdentifierChoice, 0), ++ ASN1_EXP_OPT(ASIdentifiers, rdi, ASIdentifierChoice, 1) ++} ASN1_SEQUENCE_END(ASIdentifiers) ++ ++IMPLEMENT_ASN1_FUNCTIONS(ASRange) ++IMPLEMENT_ASN1_FUNCTIONS(ASIdOrRange) ++IMPLEMENT_ASN1_FUNCTIONS(ASIdentifierChoice) ++IMPLEMENT_ASN1_FUNCTIONS(ASIdentifiers) ++ ++/* ++ * i2r method for an ASIdentifierChoice. ++ */ ++static int i2r_ASIdentifierChoice(BIO *out, ++ ASIdentifierChoice *choice, ++ int indent, const char *msg) ++{ ++ int i; ++ char *s; ++ if (choice == NULL) ++ return 1; ++ BIO_printf(out, "%*s%s:\n", indent, "", msg); ++ switch (choice->type) { ++ case ASIdentifierChoice_inherit: ++ BIO_printf(out, "%*sinherit\n", indent + 2, ""); ++ break; ++ case ASIdentifierChoice_asIdsOrRanges: ++ for (i = 0; i < sk_ASIdOrRange_num(choice->u.asIdsOrRanges); i++) { ++ ASIdOrRange *aor = ++ sk_ASIdOrRange_value(choice->u.asIdsOrRanges, i); ++ switch (aor->type) { ++ case ASIdOrRange_id: ++ if ((s = i2s_ASN1_INTEGER(NULL, aor->u.id)) == NULL) ++ return 0; ++ BIO_printf(out, "%*s%s\n", indent + 2, "", s); ++ OPENSSL_free(s); ++ break; ++ case ASIdOrRange_range: ++ if ((s = i2s_ASN1_INTEGER(NULL, aor->u.range->min)) == NULL) ++ return 0; ++ BIO_printf(out, "%*s%s-", indent + 2, "", s); ++ OPENSSL_free(s); ++ if ((s = i2s_ASN1_INTEGER(NULL, aor->u.range->max)) == NULL) ++ return 0; ++ BIO_printf(out, "%s\n", s); ++ OPENSSL_free(s); ++ break; ++ default: ++ return 0; ++ } ++ } ++ break; ++ default: ++ return 0; ++ } ++ return 1; ++} ++ ++/* ++ * i2r method for an ASIdentifier extension. ++ */ ++static int i2r_ASIdentifiers(const X509V3_EXT_METHOD *method, ++ void *ext, BIO *out, int indent) ++{ ++ ASIdentifiers *asid = ext; ++ return (i2r_ASIdentifierChoice(out, asid->asnum, indent, ++ "Autonomous System Numbers") && ++ i2r_ASIdentifierChoice(out, asid->rdi, indent, ++ "Routing Domain Identifiers")); ++} ++ ++/* ++ * Sort comparison function for a sequence of ASIdOrRange elements. ++ */ ++static int ASIdOrRange_cmp(const ASIdOrRange *const *a_, ++ const ASIdOrRange *const *b_) ++{ ++ const ASIdOrRange *a = *a_, *b = *b_; ++ ++ OPENSSL_assert((a->type == ASIdOrRange_id && a->u.id != NULL) || ++ (a->type == ASIdOrRange_range && a->u.range != NULL && ++ a->u.range->min != NULL && a->u.range->max != NULL)); ++ ++ OPENSSL_assert((b->type == ASIdOrRange_id && b->u.id != NULL) || ++ (b->type == ASIdOrRange_range && b->u.range != NULL && ++ b->u.range->min != NULL && b->u.range->max != NULL)); ++ ++ if (a->type == ASIdOrRange_id && b->type == ASIdOrRange_id) ++ return ASN1_INTEGER_cmp(a->u.id, b->u.id); ++ ++ if (a->type == ASIdOrRange_range && b->type == ASIdOrRange_range) { ++ int r = ASN1_INTEGER_cmp(a->u.range->min, b->u.range->min); ++ return r != 0 ? r : ASN1_INTEGER_cmp(a->u.range->max, ++ b->u.range->max); ++ } ++ ++ if (a->type == ASIdOrRange_id) ++ return ASN1_INTEGER_cmp(a->u.id, b->u.range->min); ++ else ++ return ASN1_INTEGER_cmp(a->u.range->min, b->u.id); ++} ++ ++/* ++ * Add an inherit element. ++ */ ++int X509v3_asid_add_inherit(ASIdentifiers *asid, int which) ++{ ++ ASIdentifierChoice **choice; ++ if (asid == NULL) ++ return 0; ++ switch (which) { ++ case V3_ASID_ASNUM: ++ choice = &asid->asnum; ++ break; ++ case V3_ASID_RDI: ++ choice = &asid->rdi; ++ break; ++ default: ++ return 0; ++ } ++ if (*choice == NULL) { ++ if ((*choice = ASIdentifierChoice_new()) == NULL) ++ return 0; ++ OPENSSL_assert((*choice)->u.inherit == NULL); ++ if (((*choice)->u.inherit = ASN1_NULL_new()) == NULL) ++ return 0; ++ (*choice)->type = ASIdentifierChoice_inherit; ++ } ++ return (*choice)->type == ASIdentifierChoice_inherit; ++} ++ ++/* ++ * Add an ID or range to an ASIdentifierChoice. ++ */ ++int X509v3_asid_add_id_or_range(ASIdentifiers *asid, ++ int which, ASN1_INTEGER *min, ASN1_INTEGER *max) ++{ ++ ASIdentifierChoice **choice; ++ ASIdOrRange *aor; ++ if (asid == NULL) ++ return 0; ++ switch (which) { ++ case V3_ASID_ASNUM: ++ choice = &asid->asnum; ++ break; ++ case V3_ASID_RDI: ++ choice = &asid->rdi; ++ break; ++ default: ++ return 0; ++ } ++ if (*choice != NULL && (*choice)->type == ASIdentifierChoice_inherit) ++ return 0; ++ if (*choice == NULL) { ++ if ((*choice = ASIdentifierChoice_new()) == NULL) ++ return 0; ++ OPENSSL_assert((*choice)->u.asIdsOrRanges == NULL); ++ (*choice)->u.asIdsOrRanges = sk_ASIdOrRange_new(ASIdOrRange_cmp); ++ if ((*choice)->u.asIdsOrRanges == NULL) ++ return 0; ++ (*choice)->type = ASIdentifierChoice_asIdsOrRanges; ++ } ++ if ((aor = ASIdOrRange_new()) == NULL) ++ return 0; ++ if (max == NULL) { ++ aor->type = ASIdOrRange_id; ++ aor->u.id = min; ++ } else { ++ aor->type = ASIdOrRange_range; ++ if ((aor->u.range = ASRange_new()) == NULL) ++ goto err; ++ ASN1_INTEGER_free(aor->u.range->min); ++ aor->u.range->min = min; ++ ASN1_INTEGER_free(aor->u.range->max); ++ aor->u.range->max = max; ++ } ++ if (!(sk_ASIdOrRange_push((*choice)->u.asIdsOrRanges, aor))) ++ goto err; ++ return 1; ++ ++ err: ++ ASIdOrRange_free(aor); ++ return 0; ++} ++ ++/* ++ * Extract min and max values from an ASIdOrRange. ++ */ ++static void extract_min_max(ASIdOrRange *aor, ++ ASN1_INTEGER **min, ASN1_INTEGER **max) ++{ ++ OPENSSL_assert(aor != NULL && min != NULL && max != NULL); ++ switch (aor->type) { ++ case ASIdOrRange_id: ++ *min = aor->u.id; ++ *max = aor->u.id; ++ return; ++ case ASIdOrRange_range: ++ *min = aor->u.range->min; ++ *max = aor->u.range->max; ++ return; ++ } ++} ++ ++/* ++ * Check whether an ASIdentifierChoice is in canonical form. ++ */ ++static int ASIdentifierChoice_is_canonical(ASIdentifierChoice *choice) ++{ ++ ASN1_INTEGER *a_max_plus_one = NULL; ++ BIGNUM *bn = NULL; ++ int i, ret = 0; ++ ++ /* ++ * Empty element or inheritance is canonical. ++ */ ++ if (choice == NULL || choice->type == ASIdentifierChoice_inherit) ++ return 1; ++ ++ /* ++ * If not a list, or if empty list, it's broken. ++ */ ++ if (choice->type != ASIdentifierChoice_asIdsOrRanges || ++ sk_ASIdOrRange_num(choice->u.asIdsOrRanges) == 0) ++ return 0; ++ ++ /* ++ * It's a list, check it. ++ */ ++ for (i = 0; i < sk_ASIdOrRange_num(choice->u.asIdsOrRanges) - 1; i++) { ++ ASIdOrRange *a = sk_ASIdOrRange_value(choice->u.asIdsOrRanges, i); ++ ASIdOrRange *b = sk_ASIdOrRange_value(choice->u.asIdsOrRanges, i + 1); ++ ASN1_INTEGER *a_min = NULL, *a_max = NULL, *b_min = NULL, *b_max = ++ NULL; ++ ++ extract_min_max(a, &a_min, &a_max); ++ extract_min_max(b, &b_min, &b_max); ++ ++ /* ++ * Punt misordered list, overlapping start, or inverted range. ++ */ ++ if (ASN1_INTEGER_cmp(a_min, b_min) >= 0 || ++ ASN1_INTEGER_cmp(a_min, a_max) > 0 || ++ ASN1_INTEGER_cmp(b_min, b_max) > 0) ++ goto done; ++ ++ /* ++ * Calculate a_max + 1 to check for adjacency. ++ */ ++ if ((bn == NULL && (bn = BN_new()) == NULL) || ++ ASN1_INTEGER_to_BN(a_max, bn) == NULL || ++ !BN_add_word(bn, 1) || ++ (a_max_plus_one = ++ BN_to_ASN1_INTEGER(bn, a_max_plus_one)) == NULL) { ++ X509V3err(X509V3_F_ASIDENTIFIERCHOICE_IS_CANONICAL, ++ ERR_R_MALLOC_FAILURE); ++ goto done; ++ } ++ ++ /* ++ * Punt if adjacent or overlapping. ++ */ ++ if (ASN1_INTEGER_cmp(a_max_plus_one, b_min) >= 0) ++ goto done; ++ } ++ ++ /* ++ * Check for inverted range. ++ */ ++ i = sk_ASIdOrRange_num(choice->u.asIdsOrRanges) - 1; ++ { ++ ASIdOrRange *a = sk_ASIdOrRange_value(choice->u.asIdsOrRanges, i); ++ ASN1_INTEGER *a_min, *a_max; ++ if (a != NULL && a->type == ASIdOrRange_range) { ++ extract_min_max(a, &a_min, &a_max); ++ if (ASN1_INTEGER_cmp(a_min, a_max) > 0) ++ goto done; ++ } ++ } ++ ++ ret = 1; ++ ++ done: ++ ASN1_INTEGER_free(a_max_plus_one); ++ BN_free(bn); ++ return ret; ++} ++ ++/* ++ * Check whether an ASIdentifier extension is in canonical form. ++ */ ++int X509v3_asid_is_canonical(ASIdentifiers *asid) ++{ ++ return (asid == NULL || ++ (ASIdentifierChoice_is_canonical(asid->asnum) && ++ ASIdentifierChoice_is_canonical(asid->rdi))); ++} ++ ++/* ++ * Whack an ASIdentifierChoice into canonical form. ++ */ ++static int ASIdentifierChoice_canonize(ASIdentifierChoice *choice) ++{ ++ ASN1_INTEGER *a_max_plus_one = NULL; ++ BIGNUM *bn = NULL; ++ int i, ret = 0; ++ ++ /* ++ * Nothing to do for empty element or inheritance. ++ */ ++ if (choice == NULL || choice->type == ASIdentifierChoice_inherit) ++ return 1; ++ ++ /* ++ * If not a list, or if empty list, it's broken. ++ */ ++ if (choice->type != ASIdentifierChoice_asIdsOrRanges || ++ sk_ASIdOrRange_num(choice->u.asIdsOrRanges) == 0) { ++ X509V3err(X509V3_F_ASIDENTIFIERCHOICE_CANONIZE, ++ X509V3_R_EXTENSION_VALUE_ERROR); ++ return 0; ++ } ++ ++ /* ++ * We have a non-empty list. Sort it. ++ */ ++ sk_ASIdOrRange_sort(choice->u.asIdsOrRanges); ++ ++ /* ++ * Now check for errors and suboptimal encoding, rejecting the ++ * former and fixing the latter. ++ */ ++ for (i = 0; i < sk_ASIdOrRange_num(choice->u.asIdsOrRanges) - 1; i++) { ++ ASIdOrRange *a = sk_ASIdOrRange_value(choice->u.asIdsOrRanges, i); ++ ASIdOrRange *b = sk_ASIdOrRange_value(choice->u.asIdsOrRanges, i + 1); ++ ASN1_INTEGER *a_min = NULL, *a_max = NULL, *b_min = NULL, *b_max = ++ NULL; ++ ++ extract_min_max(a, &a_min, &a_max); ++ extract_min_max(b, &b_min, &b_max); ++ ++ /* ++ * Make sure we're properly sorted (paranoia). ++ */ ++ OPENSSL_assert(ASN1_INTEGER_cmp(a_min, b_min) <= 0); ++ ++ /* ++ * Punt inverted ranges. ++ */ ++ if (ASN1_INTEGER_cmp(a_min, a_max) > 0 || ++ ASN1_INTEGER_cmp(b_min, b_max) > 0) ++ goto done; ++ ++ /* ++ * Check for overlaps. ++ */ ++ if (ASN1_INTEGER_cmp(a_max, b_min) >= 0) { ++ X509V3err(X509V3_F_ASIDENTIFIERCHOICE_CANONIZE, ++ X509V3_R_EXTENSION_VALUE_ERROR); ++ goto done; ++ } ++ ++ /* ++ * Calculate a_max + 1 to check for adjacency. ++ */ ++ if ((bn == NULL && (bn = BN_new()) == NULL) || ++ ASN1_INTEGER_to_BN(a_max, bn) == NULL || ++ !BN_add_word(bn, 1) || ++ (a_max_plus_one = ++ BN_to_ASN1_INTEGER(bn, a_max_plus_one)) == NULL) { ++ X509V3err(X509V3_F_ASIDENTIFIERCHOICE_CANONIZE, ++ ERR_R_MALLOC_FAILURE); ++ goto done; ++ } ++ ++ /* ++ * If a and b are adjacent, merge them. ++ */ ++ if (ASN1_INTEGER_cmp(a_max_plus_one, b_min) == 0) { ++ ASRange *r; ++ switch (a->type) { ++ case ASIdOrRange_id: ++ if ((r = OPENSSL_malloc(sizeof(*r))) == NULL) { ++ X509V3err(X509V3_F_ASIDENTIFIERCHOICE_CANONIZE, ++ ERR_R_MALLOC_FAILURE); ++ goto done; ++ } ++ r->min = a_min; ++ r->max = b_max; ++ a->type = ASIdOrRange_range; ++ a->u.range = r; ++ break; ++ case ASIdOrRange_range: ++ ASN1_INTEGER_free(a->u.range->max); ++ a->u.range->max = b_max; ++ break; ++ } ++ switch (b->type) { ++ case ASIdOrRange_id: ++ b->u.id = NULL; ++ break; ++ case ASIdOrRange_range: ++ b->u.range->max = NULL; ++ break; ++ } ++ ASIdOrRange_free(b); ++ (void)sk_ASIdOrRange_delete(choice->u.asIdsOrRanges, i + 1); ++ i--; ++ continue; ++ } ++ } ++ ++ /* ++ * Check for final inverted range. ++ */ ++ i = sk_ASIdOrRange_num(choice->u.asIdsOrRanges) - 1; ++ { ++ ASIdOrRange *a = sk_ASIdOrRange_value(choice->u.asIdsOrRanges, i); ++ ASN1_INTEGER *a_min, *a_max; ++ if (a != NULL && a->type == ASIdOrRange_range) { ++ extract_min_max(a, &a_min, &a_max); ++ if (ASN1_INTEGER_cmp(a_min, a_max) > 0) ++ goto done; ++ } ++ } ++ ++ OPENSSL_assert(ASIdentifierChoice_is_canonical(choice)); /* Paranoia */ ++ ++ ret = 1; ++ ++ done: ++ ASN1_INTEGER_free(a_max_plus_one); ++ BN_free(bn); ++ return ret; ++} ++ ++/* ++ * Whack an ASIdentifier extension into canonical form. ++ */ ++int X509v3_asid_canonize(ASIdentifiers *asid) ++{ ++ return (asid == NULL || ++ (ASIdentifierChoice_canonize(asid->asnum) && ++ ASIdentifierChoice_canonize(asid->rdi))); ++} ++ ++/* ++ * v2i method for an ASIdentifier extension. ++ */ ++static void *v2i_ASIdentifiers(const struct v3_ext_method *method, ++ struct v3_ext_ctx *ctx, ++ STACK_OF(CONF_VALUE) *values) ++{ ++ ASN1_INTEGER *min = NULL, *max = NULL; ++ ASIdentifiers *asid = NULL; ++ int i; ++ ++ if ((asid = ASIdentifiers_new()) == NULL) { ++ X509V3err(X509V3_F_V2I_ASIDENTIFIERS, ERR_R_MALLOC_FAILURE); ++ return NULL; ++ } ++ ++ for (i = 0; i < sk_CONF_VALUE_num(values); i++) { ++ CONF_VALUE *val = sk_CONF_VALUE_value(values, i); ++ int i1 = 0, i2 = 0, i3 = 0, is_range = 0, which = 0; ++ ++ /* ++ * Figure out whether this is an AS or an RDI. ++ */ ++ if (!name_cmp(val->name, "AS")) { ++ which = V3_ASID_ASNUM; ++ } else if (!name_cmp(val->name, "RDI")) { ++ which = V3_ASID_RDI; ++ } else { ++ X509V3err(X509V3_F_V2I_ASIDENTIFIERS, ++ X509V3_R_EXTENSION_NAME_ERROR); ++ X509V3_conf_err(val); ++ goto err; ++ } ++ ++ /* ++ * Handle inheritance. ++ */ ++ if (strcmp(val->value, "inherit") == 0) { ++ if (X509v3_asid_add_inherit(asid, which)) ++ continue; ++ X509V3err(X509V3_F_V2I_ASIDENTIFIERS, ++ X509V3_R_INVALID_INHERITANCE); ++ X509V3_conf_err(val); ++ goto err; ++ } ++ ++ /* ++ * Number, range, or mistake, pick it apart and figure out which. ++ */ ++ i1 = strspn(val->value, "0123456789"); ++ if (val->value[i1] == '\0') { ++ is_range = 0; ++ } else { ++ is_range = 1; ++ i2 = i1 + strspn(val->value + i1, " \t"); ++ if (val->value[i2] != '-') { ++ X509V3err(X509V3_F_V2I_ASIDENTIFIERS, ++ X509V3_R_INVALID_ASNUMBER); ++ X509V3_conf_err(val); ++ goto err; ++ } ++ i2++; ++ i2 = i2 + strspn(val->value + i2, " \t"); ++ i3 = i2 + strspn(val->value + i2, "0123456789"); ++ if (val->value[i3] != '\0') { ++ X509V3err(X509V3_F_V2I_ASIDENTIFIERS, ++ X509V3_R_INVALID_ASRANGE); ++ X509V3_conf_err(val); ++ goto err; ++ } ++ } ++ ++ /* ++ * Syntax is ok, read and add it. ++ */ ++ if (!is_range) { ++ if (!X509V3_get_value_int(val, &min)) { ++ X509V3err(X509V3_F_V2I_ASIDENTIFIERS, ERR_R_MALLOC_FAILURE); ++ goto err; ++ } ++ } else { ++ char *s = OPENSSL_strdup(val->value); ++ if (s == NULL) { ++ X509V3err(X509V3_F_V2I_ASIDENTIFIERS, ERR_R_MALLOC_FAILURE); ++ goto err; ++ } ++ s[i1] = '\0'; ++ min = s2i_ASN1_INTEGER(NULL, s); ++ max = s2i_ASN1_INTEGER(NULL, s + i2); ++ OPENSSL_free(s); ++ if (min == NULL || max == NULL) { ++ X509V3err(X509V3_F_V2I_ASIDENTIFIERS, ERR_R_MALLOC_FAILURE); ++ goto err; ++ } ++ if (ASN1_INTEGER_cmp(min, max) > 0) { ++ X509V3err(X509V3_F_V2I_ASIDENTIFIERS, ++ X509V3_R_EXTENSION_VALUE_ERROR); ++ goto err; ++ } ++ } ++ if (!X509v3_asid_add_id_or_range(asid, which, min, max)) { ++ X509V3err(X509V3_F_V2I_ASIDENTIFIERS, ERR_R_MALLOC_FAILURE); ++ goto err; ++ } ++ min = max = NULL; ++ } ++ ++ /* ++ * Canonize the result, then we're done. ++ */ ++ if (!X509v3_asid_canonize(asid)) ++ goto err; ++ return asid; ++ ++ err: ++ ASIdentifiers_free(asid); ++ ASN1_INTEGER_free(min); ++ ASN1_INTEGER_free(max); ++ return NULL; ++} ++ ++/* ++ * OpenSSL dispatch. ++ */ ++const X509V3_EXT_METHOD v3_asid = { ++ NID_sbgp_autonomousSysNum, /* nid */ ++ 0, /* flags */ ++ ASN1_ITEM_ref(ASIdentifiers), /* template */ ++ 0, 0, 0, 0, /* old functions, ignored */ ++ 0, /* i2s */ ++ 0, /* s2i */ ++ 0, /* i2v */ ++ v2i_ASIdentifiers, /* v2i */ ++ i2r_ASIdentifiers, /* i2r */ ++ 0, /* r2i */ ++ NULL /* extension-specific data */ ++}; ++ ++/* ++ * Figure out whether extension uses inheritance. ++ */ ++int X509v3_asid_inherits(ASIdentifiers *asid) ++{ ++ return (asid != NULL && ++ ((asid->asnum != NULL && ++ asid->asnum->type == ASIdentifierChoice_inherit) || ++ (asid->rdi != NULL && ++ asid->rdi->type == ASIdentifierChoice_inherit))); ++} ++ ++/* ++ * Figure out whether parent contains child. ++ */ ++static int asid_contains(ASIdOrRanges *parent, ASIdOrRanges *child) ++{ ++ ASN1_INTEGER *p_min = NULL, *p_max = NULL, *c_min = NULL, *c_max = NULL; ++ int p, c; ++ ++ if (child == NULL || parent == child) ++ return 1; ++ if (parent == NULL) ++ return 0; ++ ++ p = 0; ++ for (c = 0; c < sk_ASIdOrRange_num(child); c++) { ++ extract_min_max(sk_ASIdOrRange_value(child, c), &c_min, &c_max); ++ for (;; p++) { ++ if (p >= sk_ASIdOrRange_num(parent)) ++ return 0; ++ extract_min_max(sk_ASIdOrRange_value(parent, p), &p_min, &p_max); ++ if (ASN1_INTEGER_cmp(p_max, c_max) < 0) ++ continue; ++ if (ASN1_INTEGER_cmp(p_min, c_min) > 0) ++ return 0; ++ break; ++ } ++ } ++ ++ return 1; ++} ++ ++/* ++ * Test whether a is a subset of b. ++ */ ++int X509v3_asid_subset(ASIdentifiers *a, ASIdentifiers *b) ++{ ++ return (a == NULL || ++ a == b || ++ (b != NULL && ++ !X509v3_asid_inherits(a) && ++ !X509v3_asid_inherits(b) && ++ asid_contains(b->asnum->u.asIdsOrRanges, ++ a->asnum->u.asIdsOrRanges) && ++ asid_contains(b->rdi->u.asIdsOrRanges, ++ a->rdi->u.asIdsOrRanges))); ++} ++ ++/* ++ * Validation error handling via callback. ++ */ ++#define validation_err(_err_) \ ++ do { \ ++ if (ctx != NULL) { \ ++ ctx->error = _err_; \ ++ ctx->error_depth = i; \ ++ ctx->current_cert = x; \ ++ ret = ctx->verify_cb(0, ctx); \ ++ } else { \ ++ ret = 0; \ ++ } \ ++ if (!ret) \ ++ goto done; \ ++ } while (0) ++ ++/* ++ * Core code for RFC 3779 3.3 path validation. ++ */ ++static int asid_validate_path_internal(X509_STORE_CTX *ctx, ++ STACK_OF(X509) *chain, ++ ASIdentifiers *ext) ++{ ++ ASIdOrRanges *child_as = NULL, *child_rdi = NULL; ++ int i, ret = 1, inherit_as = 0, inherit_rdi = 0; ++ X509 *x; ++ ++ OPENSSL_assert(chain != NULL && sk_X509_num(chain) > 0); ++ OPENSSL_assert(ctx != NULL || ext != NULL); ++ OPENSSL_assert(ctx == NULL || ctx->verify_cb != NULL); ++ ++ /* ++ * Figure out where to start. If we don't have an extension to ++ * check, we're done. Otherwise, check canonical form and ++ * set up for walking up the chain. ++ */ ++ if (ext != NULL) { ++ i = -1; ++ x = NULL; ++ } else { ++ i = 0; ++ x = sk_X509_value(chain, i); ++ OPENSSL_assert(x != NULL); ++ if ((ext = x->rfc3779_asid) == NULL) ++ goto done; ++ } ++ if (!X509v3_asid_is_canonical(ext)) ++ validation_err(X509_V_ERR_INVALID_EXTENSION); ++ if (ext->asnum != NULL) { ++ switch (ext->asnum->type) { ++ case ASIdentifierChoice_inherit: ++ inherit_as = 1; ++ break; ++ case ASIdentifierChoice_asIdsOrRanges: ++ child_as = ext->asnum->u.asIdsOrRanges; ++ break; ++ } ++ } ++ if (ext->rdi != NULL) { ++ switch (ext->rdi->type) { ++ case ASIdentifierChoice_inherit: ++ inherit_rdi = 1; ++ break; ++ case ASIdentifierChoice_asIdsOrRanges: ++ child_rdi = ext->rdi->u.asIdsOrRanges; ++ break; ++ } ++ } ++ ++ /* ++ * Now walk up the chain. Extensions must be in canonical form, no ++ * cert may list resources that its parent doesn't list. ++ */ ++ for (i++; i < sk_X509_num(chain); i++) { ++ x = sk_X509_value(chain, i); ++ OPENSSL_assert(x != NULL); ++ if (x->rfc3779_asid == NULL) { ++ if (child_as != NULL || child_rdi != NULL) ++ validation_err(X509_V_ERR_UNNESTED_RESOURCE); ++ continue; ++ } ++ if (!X509v3_asid_is_canonical(x->rfc3779_asid)) ++ validation_err(X509_V_ERR_INVALID_EXTENSION); ++ if (x->rfc3779_asid->asnum == NULL && child_as != NULL) { ++ validation_err(X509_V_ERR_UNNESTED_RESOURCE); ++ child_as = NULL; ++ inherit_as = 0; ++ } ++ if (x->rfc3779_asid->asnum != NULL && ++ x->rfc3779_asid->asnum->type == ++ ASIdentifierChoice_asIdsOrRanges) { ++ if (inherit_as ++ || asid_contains(x->rfc3779_asid->asnum->u.asIdsOrRanges, ++ child_as)) { ++ child_as = x->rfc3779_asid->asnum->u.asIdsOrRanges; ++ inherit_as = 0; ++ } else { ++ validation_err(X509_V_ERR_UNNESTED_RESOURCE); ++ } ++ } ++ if (x->rfc3779_asid->rdi == NULL && child_rdi != NULL) { ++ validation_err(X509_V_ERR_UNNESTED_RESOURCE); ++ child_rdi = NULL; ++ inherit_rdi = 0; ++ } ++ if (x->rfc3779_asid->rdi != NULL && ++ x->rfc3779_asid->rdi->type == ASIdentifierChoice_asIdsOrRanges) { ++ if (inherit_rdi || ++ asid_contains(x->rfc3779_asid->rdi->u.asIdsOrRanges, ++ child_rdi)) { ++ child_rdi = x->rfc3779_asid->rdi->u.asIdsOrRanges; ++ inherit_rdi = 0; ++ } else { ++ validation_err(X509_V_ERR_UNNESTED_RESOURCE); ++ } ++ } ++ } ++ ++ /* ++ * Trust anchor can't inherit. ++ */ ++ OPENSSL_assert(x != NULL); ++ if (x->rfc3779_asid != NULL) { ++ if (x->rfc3779_asid->asnum != NULL && ++ x->rfc3779_asid->asnum->type == ASIdentifierChoice_inherit) ++ validation_err(X509_V_ERR_UNNESTED_RESOURCE); ++ if (x->rfc3779_asid->rdi != NULL && ++ x->rfc3779_asid->rdi->type == ASIdentifierChoice_inherit) ++ validation_err(X509_V_ERR_UNNESTED_RESOURCE); ++ } ++ ++ done: ++ return ret; ++} ++ ++#undef validation_err ++ ++/* ++ * RFC 3779 3.3 path validation -- called from X509_verify_cert(). ++ */ ++int X509v3_asid_validate_path(X509_STORE_CTX *ctx) ++{ ++ return asid_validate_path_internal(ctx, ctx->chain, NULL); ++} ++ ++/* ++ * RFC 3779 3.3 path validation of an extension. ++ * Test whether chain covers extension. ++ */ ++int X509v3_asid_validate_resource_set(STACK_OF(X509) *chain, ++ ASIdentifiers *ext, int allow_inheritance) ++{ ++ if (ext == NULL) ++ return 1; ++ if (chain == NULL || sk_X509_num(chain) == 0) ++ return 0; ++ if (!allow_inheritance && X509v3_asid_inherits(ext)) ++ return 0; ++ return asid_validate_path_internal(NULL, chain, ext); ++} ++ ++#endif /* OPENSSL_NO_RFC3779 */ +diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/x509v3/v3_bcons.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/x509v3/v3_bcons.c +new file mode 100644 +index 0000000..3bbf155 +--- /dev/null ++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/x509v3/v3_bcons.c +@@ -0,0 +1,84 @@ ++/* ++ * Copyright 1999-2016 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 ++ * in the file LICENSE in the source distribution or at ++ * https://www.openssl.org/source/license.html ++ */ ++ ++#include ++#include "internal/cryptlib.h" ++#include ++#include ++#include ++#include ++#include "ext_dat.h" ++ ++static STACK_OF(CONF_VALUE) *i2v_BASIC_CONSTRAINTS(X509V3_EXT_METHOD *method, ++ BASIC_CONSTRAINTS *bcons, ++ STACK_OF(CONF_VALUE) ++ *extlist); ++static BASIC_CONSTRAINTS *v2i_BASIC_CONSTRAINTS(X509V3_EXT_METHOD *method, ++ X509V3_CTX *ctx, ++ STACK_OF(CONF_VALUE) *values); ++ ++const X509V3_EXT_METHOD v3_bcons = { ++ NID_basic_constraints, 0, ++ ASN1_ITEM_ref(BASIC_CONSTRAINTS), ++ 0, 0, 0, 0, ++ 0, 0, ++ (X509V3_EXT_I2V) i2v_BASIC_CONSTRAINTS, ++ (X509V3_EXT_V2I)v2i_BASIC_CONSTRAINTS, ++ NULL, NULL, ++ NULL ++}; ++ ++ASN1_SEQUENCE(BASIC_CONSTRAINTS) = { ++ ASN1_OPT(BASIC_CONSTRAINTS, ca, ASN1_FBOOLEAN), ++ ASN1_OPT(BASIC_CONSTRAINTS, pathlen, ASN1_INTEGER) ++} ASN1_SEQUENCE_END(BASIC_CONSTRAINTS) ++ ++IMPLEMENT_ASN1_FUNCTIONS(BASIC_CONSTRAINTS) ++ ++static STACK_OF(CONF_VALUE) *i2v_BASIC_CONSTRAINTS(X509V3_EXT_METHOD *method, ++ BASIC_CONSTRAINTS *bcons, ++ STACK_OF(CONF_VALUE) ++ *extlist) ++{ ++ X509V3_add_value_bool("CA", bcons->ca, &extlist); ++ X509V3_add_value_int("pathlen", bcons->pathlen, &extlist); ++ return extlist; ++} ++ ++static BASIC_CONSTRAINTS *v2i_BASIC_CONSTRAINTS(X509V3_EXT_METHOD *method, ++ X509V3_CTX *ctx, ++ STACK_OF(CONF_VALUE) *values) ++{ ++ BASIC_CONSTRAINTS *bcons = NULL; ++ CONF_VALUE *val; ++ int i; ++ ++ if ((bcons = BASIC_CONSTRAINTS_new()) == NULL) { ++ X509V3err(X509V3_F_V2I_BASIC_CONSTRAINTS, ERR_R_MALLOC_FAILURE); ++ return NULL; ++ } ++ for (i = 0; i < sk_CONF_VALUE_num(values); i++) { ++ val = sk_CONF_VALUE_value(values, i); ++ if (strcmp(val->name, "CA") == 0) { ++ if (!X509V3_get_value_bool(val, &bcons->ca)) ++ goto err; ++ } else if (strcmp(val->name, "pathlen") == 0) { ++ if (!X509V3_get_value_int(val, &bcons->pathlen)) ++ goto err; ++ } else { ++ X509V3err(X509V3_F_V2I_BASIC_CONSTRAINTS, X509V3_R_INVALID_NAME); ++ X509V3_conf_err(val); ++ goto err; ++ } ++ } ++ return bcons; ++ err: ++ BASIC_CONSTRAINTS_free(bcons); ++ return NULL; ++} +diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/x509v3/v3_bitst.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/x509v3/v3_bitst.c +new file mode 100644 +index 0000000..4802116 +--- /dev/null ++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/x509v3/v3_bitst.c +@@ -0,0 +1,93 @@ ++/* ++ * Copyright 1999-2016 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 ++ * in the file LICENSE in the source distribution or at ++ * https://www.openssl.org/source/license.html ++ */ ++ ++#include ++#include "internal/cryptlib.h" ++#include ++#include ++#include "ext_dat.h" ++ ++static BIT_STRING_BITNAME ns_cert_type_table[] = { ++ {0, "SSL Client", "client"}, ++ {1, "SSL Server", "server"}, ++ {2, "S/MIME", "email"}, ++ {3, "Object Signing", "objsign"}, ++ {4, "Unused", "reserved"}, ++ {5, "SSL CA", "sslCA"}, ++ {6, "S/MIME CA", "emailCA"}, ++ {7, "Object Signing CA", "objCA"}, ++ {-1, NULL, NULL} ++}; ++ ++static BIT_STRING_BITNAME key_usage_type_table[] = { ++ {0, "Digital Signature", "digitalSignature"}, ++ {1, "Non Repudiation", "nonRepudiation"}, ++ {2, "Key Encipherment", "keyEncipherment"}, ++ {3, "Data Encipherment", "dataEncipherment"}, ++ {4, "Key Agreement", "keyAgreement"}, ++ {5, "Certificate Sign", "keyCertSign"}, ++ {6, "CRL Sign", "cRLSign"}, ++ {7, "Encipher Only", "encipherOnly"}, ++ {8, "Decipher Only", "decipherOnly"}, ++ {-1, NULL, NULL} ++}; ++ ++const X509V3_EXT_METHOD v3_nscert = ++EXT_BITSTRING(NID_netscape_cert_type, ns_cert_type_table); ++const X509V3_EXT_METHOD v3_key_usage = ++EXT_BITSTRING(NID_key_usage, key_usage_type_table); ++ ++STACK_OF(CONF_VALUE) *i2v_ASN1_BIT_STRING(X509V3_EXT_METHOD *method, ++ ASN1_BIT_STRING *bits, ++ STACK_OF(CONF_VALUE) *ret) ++{ ++ BIT_STRING_BITNAME *bnam; ++ for (bnam = method->usr_data; bnam->lname; bnam++) { ++ if (ASN1_BIT_STRING_get_bit(bits, bnam->bitnum)) ++ X509V3_add_value(bnam->lname, NULL, &ret); ++ } ++ return ret; ++} ++ ++ASN1_BIT_STRING *v2i_ASN1_BIT_STRING(X509V3_EXT_METHOD *method, ++ X509V3_CTX *ctx, ++ STACK_OF(CONF_VALUE) *nval) ++{ ++ CONF_VALUE *val; ++ ASN1_BIT_STRING *bs; ++ int i; ++ BIT_STRING_BITNAME *bnam; ++ if ((bs = ASN1_BIT_STRING_new()) == NULL) { ++ X509V3err(X509V3_F_V2I_ASN1_BIT_STRING, ERR_R_MALLOC_FAILURE); ++ return NULL; ++ } ++ for (i = 0; i < sk_CONF_VALUE_num(nval); i++) { ++ val = sk_CONF_VALUE_value(nval, i); ++ for (bnam = method->usr_data; bnam->lname; bnam++) { ++ if (strcmp(bnam->sname, val->name) == 0 ++ || strcmp(bnam->lname, val->name) == 0) { ++ if (!ASN1_BIT_STRING_set_bit(bs, bnam->bitnum, 1)) { ++ X509V3err(X509V3_F_V2I_ASN1_BIT_STRING, ++ ERR_R_MALLOC_FAILURE); ++ ASN1_BIT_STRING_free(bs); ++ return NULL; ++ } ++ break; ++ } ++ } ++ if (!bnam->lname) { ++ X509V3err(X509V3_F_V2I_ASN1_BIT_STRING, ++ X509V3_R_UNKNOWN_BIT_STRING_ARGUMENT); ++ X509V3_conf_err(val); ++ ASN1_BIT_STRING_free(bs); ++ return NULL; ++ } ++ } ++ return bs; ++} +diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/x509v3/v3_conf.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/x509v3/v3_conf.c +new file mode 100644 +index 0000000..f625ff5 +--- /dev/null ++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/x509v3/v3_conf.c +@@ -0,0 +1,507 @@ ++/* ++ * Copyright 1999-2016 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 ++ * in the file LICENSE in the source distribution or at ++ * https://www.openssl.org/source/license.html ++ */ ++ ++/* extension creation utilities */ ++ ++#include ++#include ++#include "internal/cryptlib.h" ++#include ++#include ++#include "internal/x509_int.h" ++#include ++ ++static int v3_check_critical(const char **value); ++static int v3_check_generic(const char **value); ++static X509_EXTENSION *do_ext_nconf(CONF *conf, X509V3_CTX *ctx, int ext_nid, ++ int crit, const char *value); ++static X509_EXTENSION *v3_generic_extension(const char *ext, const char *value, ++ int crit, int type, ++ X509V3_CTX *ctx); ++static char *conf_lhash_get_string(void *db, const char *section, const char *value); ++static STACK_OF(CONF_VALUE) *conf_lhash_get_section(void *db, const char *section); ++static X509_EXTENSION *do_ext_i2d(const X509V3_EXT_METHOD *method, ++ int ext_nid, int crit, void *ext_struc); ++static unsigned char *generic_asn1(const char *value, X509V3_CTX *ctx, ++ long *ext_len); ++/* CONF *conf: Config file */ ++/* char *name: Name */ ++/* char *value: Value */ ++X509_EXTENSION *X509V3_EXT_nconf(CONF *conf, X509V3_CTX *ctx, const char *name, ++ const char *value) ++{ ++ int crit; ++ int ext_type; ++ X509_EXTENSION *ret; ++ crit = v3_check_critical(&value); ++ if ((ext_type = v3_check_generic(&value))) ++ return v3_generic_extension(name, value, crit, ext_type, ctx); ++ ret = do_ext_nconf(conf, ctx, OBJ_sn2nid(name), crit, value); ++ if (!ret) { ++ X509V3err(X509V3_F_X509V3_EXT_NCONF, X509V3_R_ERROR_IN_EXTENSION); ++ ERR_add_error_data(4, "name=", name, ", value=", value); ++ } ++ return ret; ++} ++ ++/* CONF *conf: Config file */ ++/* char *value: Value */ ++X509_EXTENSION *X509V3_EXT_nconf_nid(CONF *conf, X509V3_CTX *ctx, int ext_nid, ++ const char *value) ++{ ++ int crit; ++ int ext_type; ++ crit = v3_check_critical(&value); ++ if ((ext_type = v3_check_generic(&value))) ++ return v3_generic_extension(OBJ_nid2sn(ext_nid), ++ value, crit, ext_type, ctx); ++ return do_ext_nconf(conf, ctx, ext_nid, crit, value); ++} ++ ++/* CONF *conf: Config file */ ++/* char *value: Value */ ++static X509_EXTENSION *do_ext_nconf(CONF *conf, X509V3_CTX *ctx, int ext_nid, ++ int crit, const char *value) ++{ ++ const X509V3_EXT_METHOD *method; ++ X509_EXTENSION *ext; ++ STACK_OF(CONF_VALUE) *nval; ++ void *ext_struc; ++ ++ if (ext_nid == NID_undef) { ++ X509V3err(X509V3_F_DO_EXT_NCONF, X509V3_R_UNKNOWN_EXTENSION_NAME); ++ return NULL; ++ } ++ if ((method = X509V3_EXT_get_nid(ext_nid)) == NULL) { ++ X509V3err(X509V3_F_DO_EXT_NCONF, X509V3_R_UNKNOWN_EXTENSION); ++ return NULL; ++ } ++ /* Now get internal extension representation based on type */ ++ if (method->v2i) { ++ if (*value == '@') ++ nval = NCONF_get_section(conf, value + 1); ++ else ++ nval = X509V3_parse_list(value); ++ if (nval == NULL || sk_CONF_VALUE_num(nval) <= 0) { ++ X509V3err(X509V3_F_DO_EXT_NCONF, ++ X509V3_R_INVALID_EXTENSION_STRING); ++ ERR_add_error_data(4, "name=", OBJ_nid2sn(ext_nid), ",section=", ++ value); ++ if (*value != '@') ++ sk_CONF_VALUE_pop_free(nval, X509V3_conf_free); ++ return NULL; ++ } ++ ext_struc = method->v2i(method, ctx, nval); ++ if (*value != '@') ++ sk_CONF_VALUE_pop_free(nval, X509V3_conf_free); ++ if (!ext_struc) ++ return NULL; ++ } else if (method->s2i) { ++ if ((ext_struc = method->s2i(method, ctx, value)) == NULL) ++ return NULL; ++ } else if (method->r2i) { ++ if (!ctx->db || !ctx->db_meth) { ++ X509V3err(X509V3_F_DO_EXT_NCONF, X509V3_R_NO_CONFIG_DATABASE); ++ return NULL; ++ } ++ if ((ext_struc = method->r2i(method, ctx, value)) == NULL) ++ return NULL; ++ } else { ++ X509V3err(X509V3_F_DO_EXT_NCONF, ++ X509V3_R_EXTENSION_SETTING_NOT_SUPPORTED); ++ ERR_add_error_data(2, "name=", OBJ_nid2sn(ext_nid)); ++ return NULL; ++ } ++ ++ ext = do_ext_i2d(method, ext_nid, crit, ext_struc); ++ if (method->it) ++ ASN1_item_free(ext_struc, ASN1_ITEM_ptr(method->it)); ++ else ++ method->ext_free(ext_struc); ++ return ext; ++ ++} ++ ++static X509_EXTENSION *do_ext_i2d(const X509V3_EXT_METHOD *method, ++ int ext_nid, int crit, void *ext_struc) ++{ ++ unsigned char *ext_der = NULL; ++ int ext_len; ++ ASN1_OCTET_STRING *ext_oct = NULL; ++ X509_EXTENSION *ext; ++ /* Convert internal representation to DER */ ++ if (method->it) { ++ ext_der = NULL; ++ ext_len = ++ ASN1_item_i2d(ext_struc, &ext_der, ASN1_ITEM_ptr(method->it)); ++ if (ext_len < 0) ++ goto merr; ++ } else { ++ unsigned char *p; ++ ++ ext_len = method->i2d(ext_struc, NULL); ++ if ((ext_der = OPENSSL_malloc(ext_len)) == NULL) ++ goto merr; ++ p = ext_der; ++ method->i2d(ext_struc, &p); ++ } ++ if ((ext_oct = ASN1_OCTET_STRING_new()) == NULL) ++ goto merr; ++ ext_oct->data = ext_der; ++ ext_der = NULL; ++ ext_oct->length = ext_len; ++ ++ ext = X509_EXTENSION_create_by_NID(NULL, ext_nid, crit, ext_oct); ++ if (!ext) ++ goto merr; ++ ASN1_OCTET_STRING_free(ext_oct); ++ ++ return ext; ++ ++ merr: ++ X509V3err(X509V3_F_DO_EXT_I2D, ERR_R_MALLOC_FAILURE); ++ OPENSSL_free(ext_der); ++ ASN1_OCTET_STRING_free(ext_oct); ++ return NULL; ++ ++} ++ ++/* Given an internal structure, nid and critical flag create an extension */ ++ ++X509_EXTENSION *X509V3_EXT_i2d(int ext_nid, int crit, void *ext_struc) ++{ ++ const X509V3_EXT_METHOD *method; ++ ++ if ((method = X509V3_EXT_get_nid(ext_nid)) == NULL) { ++ X509V3err(X509V3_F_X509V3_EXT_I2D, X509V3_R_UNKNOWN_EXTENSION); ++ return NULL; ++ } ++ return do_ext_i2d(method, ext_nid, crit, ext_struc); ++} ++ ++/* Check the extension string for critical flag */ ++static int v3_check_critical(const char **value) ++{ ++ const char *p = *value; ++ if ((strlen(p) < 9) || strncmp(p, "critical,", 9)) ++ return 0; ++ p += 9; ++ while (isspace((unsigned char)*p)) ++ p++; ++ *value = p; ++ return 1; ++} ++ ++/* Check extension string for generic extension and return the type */ ++static int v3_check_generic(const char **value) ++{ ++ int gen_type = 0; ++ const char *p = *value; ++ if ((strlen(p) >= 4) && strncmp(p, "DER:", 4) == 0) { ++ p += 4; ++ gen_type = 1; ++ } else if ((strlen(p) >= 5) && strncmp(p, "ASN1:", 5) == 0) { ++ p += 5; ++ gen_type = 2; ++ } else ++ return 0; ++ ++ while (isspace((unsigned char)*p)) ++ p++; ++ *value = p; ++ return gen_type; ++} ++ ++/* Create a generic extension: for now just handle DER type */ ++static X509_EXTENSION *v3_generic_extension(const char *ext, const char *value, ++ int crit, int gen_type, ++ X509V3_CTX *ctx) ++{ ++ unsigned char *ext_der = NULL; ++ long ext_len = 0; ++ ASN1_OBJECT *obj = NULL; ++ ASN1_OCTET_STRING *oct = NULL; ++ X509_EXTENSION *extension = NULL; ++ ++ if ((obj = OBJ_txt2obj(ext, 0)) == NULL) { ++ X509V3err(X509V3_F_V3_GENERIC_EXTENSION, ++ X509V3_R_EXTENSION_NAME_ERROR); ++ ERR_add_error_data(2, "name=", ext); ++ goto err; ++ } ++ ++ if (gen_type == 1) ++ ext_der = OPENSSL_hexstr2buf(value, &ext_len); ++ else if (gen_type == 2) ++ ext_der = generic_asn1(value, ctx, &ext_len); ++ ++ if (ext_der == NULL) { ++ X509V3err(X509V3_F_V3_GENERIC_EXTENSION, ++ X509V3_R_EXTENSION_VALUE_ERROR); ++ ERR_add_error_data(2, "value=", value); ++ goto err; ++ } ++ ++ if ((oct = ASN1_OCTET_STRING_new()) == NULL) { ++ X509V3err(X509V3_F_V3_GENERIC_EXTENSION, ERR_R_MALLOC_FAILURE); ++ goto err; ++ } ++ ++ oct->data = ext_der; ++ oct->length = ext_len; ++ ext_der = NULL; ++ ++ extension = X509_EXTENSION_create_by_OBJ(NULL, obj, crit, oct); ++ ++ err: ++ ASN1_OBJECT_free(obj); ++ ASN1_OCTET_STRING_free(oct); ++ OPENSSL_free(ext_der); ++ return extension; ++ ++} ++ ++static unsigned char *generic_asn1(const char *value, X509V3_CTX *ctx, ++ long *ext_len) ++{ ++ ASN1_TYPE *typ; ++ unsigned char *ext_der = NULL; ++ typ = ASN1_generate_v3(value, ctx); ++ if (typ == NULL) ++ return NULL; ++ *ext_len = i2d_ASN1_TYPE(typ, &ext_der); ++ ASN1_TYPE_free(typ); ++ return ext_der; ++} ++ ++static void delete_ext(STACK_OF(X509_EXTENSION) *sk, X509_EXTENSION *dext) ++{ ++ int idx; ++ ASN1_OBJECT *obj; ++ obj = X509_EXTENSION_get_object(dext); ++ while ((idx = X509v3_get_ext_by_OBJ(sk, obj, -1)) >= 0) { ++ X509_EXTENSION *tmpext = X509v3_get_ext(sk, idx); ++ X509v3_delete_ext(sk, idx); ++ X509_EXTENSION_free(tmpext); ++ } ++} ++ ++/* ++ * This is the main function: add a bunch of extensions based on a config ++ * file section to an extension STACK. ++ */ ++ ++int X509V3_EXT_add_nconf_sk(CONF *conf, X509V3_CTX *ctx, const char *section, ++ STACK_OF(X509_EXTENSION) **sk) ++{ ++ X509_EXTENSION *ext; ++ STACK_OF(CONF_VALUE) *nval; ++ CONF_VALUE *val; ++ int i; ++ ++ if ((nval = NCONF_get_section(conf, section)) == NULL) ++ return 0; ++ for (i = 0; i < sk_CONF_VALUE_num(nval); i++) { ++ val = sk_CONF_VALUE_value(nval, i); ++ if ((ext = X509V3_EXT_nconf(conf, ctx, val->name, val->value)) == NULL) ++ return 0; ++ if (ctx->flags == X509V3_CTX_REPLACE) ++ delete_ext(*sk, ext); ++ if (sk) ++ X509v3_add_ext(sk, ext, -1); ++ X509_EXTENSION_free(ext); ++ } ++ return 1; ++} ++ ++/* ++ * Convenience functions to add extensions to a certificate, CRL and request ++ */ ++ ++int X509V3_EXT_add_nconf(CONF *conf, X509V3_CTX *ctx, const char *section, ++ X509 *cert) ++{ ++ STACK_OF(X509_EXTENSION) **sk = NULL; ++ if (cert) ++ sk = &cert->cert_info.extensions; ++ return X509V3_EXT_add_nconf_sk(conf, ctx, section, sk); ++} ++ ++/* Same as above but for a CRL */ ++ ++int X509V3_EXT_CRL_add_nconf(CONF *conf, X509V3_CTX *ctx, const char *section, ++ X509_CRL *crl) ++{ ++ STACK_OF(X509_EXTENSION) **sk = NULL; ++ if (crl) ++ sk = &crl->crl.extensions; ++ return X509V3_EXT_add_nconf_sk(conf, ctx, section, sk); ++} ++ ++/* Add extensions to certificate request */ ++ ++int X509V3_EXT_REQ_add_nconf(CONF *conf, X509V3_CTX *ctx, const char *section, ++ X509_REQ *req) ++{ ++ STACK_OF(X509_EXTENSION) *extlist = NULL, **sk = NULL; ++ int i; ++ if (req) ++ sk = &extlist; ++ i = X509V3_EXT_add_nconf_sk(conf, ctx, section, sk); ++ if (!i || !sk) ++ return i; ++ i = X509_REQ_add_extensions(req, extlist); ++ sk_X509_EXTENSION_pop_free(extlist, X509_EXTENSION_free); ++ return i; ++} ++ ++/* Config database functions */ ++ ++char *X509V3_get_string(X509V3_CTX *ctx, const char *name, const char *section) ++{ ++ if (!ctx->db || !ctx->db_meth || !ctx->db_meth->get_string) { ++ X509V3err(X509V3_F_X509V3_GET_STRING, X509V3_R_OPERATION_NOT_DEFINED); ++ return NULL; ++ } ++ if (ctx->db_meth->get_string) ++ return ctx->db_meth->get_string(ctx->db, name, section); ++ return NULL; ++} ++ ++STACK_OF(CONF_VALUE) *X509V3_get_section(X509V3_CTX *ctx, const char *section) ++{ ++ if (!ctx->db || !ctx->db_meth || !ctx->db_meth->get_section) { ++ X509V3err(X509V3_F_X509V3_GET_SECTION, ++ X509V3_R_OPERATION_NOT_DEFINED); ++ return NULL; ++ } ++ if (ctx->db_meth->get_section) ++ return ctx->db_meth->get_section(ctx->db, section); ++ return NULL; ++} ++ ++void X509V3_string_free(X509V3_CTX *ctx, char *str) ++{ ++ if (!str) ++ return; ++ if (ctx->db_meth->free_string) ++ ctx->db_meth->free_string(ctx->db, str); ++} ++ ++void X509V3_section_free(X509V3_CTX *ctx, STACK_OF(CONF_VALUE) *section) ++{ ++ if (!section) ++ return; ++ if (ctx->db_meth->free_section) ++ ctx->db_meth->free_section(ctx->db, section); ++} ++ ++static char *nconf_get_string(void *db, const char *section, const char *value) ++{ ++ return NCONF_get_string(db, section, value); ++} ++ ++static STACK_OF(CONF_VALUE) *nconf_get_section(void *db, const char *section) ++{ ++ return NCONF_get_section(db, section); ++} ++ ++static X509V3_CONF_METHOD nconf_method = { ++ nconf_get_string, ++ nconf_get_section, ++ NULL, ++ NULL ++}; ++ ++void X509V3_set_nconf(X509V3_CTX *ctx, CONF *conf) ++{ ++ ctx->db_meth = &nconf_method; ++ ctx->db = conf; ++} ++ ++void X509V3_set_ctx(X509V3_CTX *ctx, X509 *issuer, X509 *subj, X509_REQ *req, ++ X509_CRL *crl, int flags) ++{ ++ ctx->issuer_cert = issuer; ++ ctx->subject_cert = subj; ++ ctx->crl = crl; ++ ctx->subject_req = req; ++ ctx->flags = flags; ++} ++ ++/* Old conf compatibility functions */ ++ ++X509_EXTENSION *X509V3_EXT_conf(LHASH_OF(CONF_VALUE) *conf, X509V3_CTX *ctx, ++ const char *name, const char *value) ++{ ++ CONF ctmp; ++ CONF_set_nconf(&ctmp, conf); ++ return X509V3_EXT_nconf(&ctmp, ctx, name, value); ++} ++ ++/* LHASH *conf: Config file */ ++/* char *value: Value */ ++X509_EXTENSION *X509V3_EXT_conf_nid(LHASH_OF(CONF_VALUE) *conf, ++ X509V3_CTX *ctx, int ext_nid, const char *value) ++{ ++ CONF ctmp; ++ CONF_set_nconf(&ctmp, conf); ++ return X509V3_EXT_nconf_nid(&ctmp, ctx, ext_nid, value); ++} ++ ++static char *conf_lhash_get_string(void *db, const char *section, const char *value) ++{ ++ return CONF_get_string(db, section, value); ++} ++ ++static STACK_OF(CONF_VALUE) *conf_lhash_get_section(void *db, const char *section) ++{ ++ return CONF_get_section(db, section); ++} ++ ++static X509V3_CONF_METHOD conf_lhash_method = { ++ conf_lhash_get_string, ++ conf_lhash_get_section, ++ NULL, ++ NULL ++}; ++ ++void X509V3_set_conf_lhash(X509V3_CTX *ctx, LHASH_OF(CONF_VALUE) *lhash) ++{ ++ ctx->db_meth = &conf_lhash_method; ++ ctx->db = lhash; ++} ++ ++int X509V3_EXT_add_conf(LHASH_OF(CONF_VALUE) *conf, X509V3_CTX *ctx, ++ const char *section, X509 *cert) ++{ ++ CONF ctmp; ++ CONF_set_nconf(&ctmp, conf); ++ return X509V3_EXT_add_nconf(&ctmp, ctx, section, cert); ++} ++ ++/* Same as above but for a CRL */ ++ ++int X509V3_EXT_CRL_add_conf(LHASH_OF(CONF_VALUE) *conf, X509V3_CTX *ctx, ++ const char *section, X509_CRL *crl) ++{ ++ CONF ctmp; ++ CONF_set_nconf(&ctmp, conf); ++ return X509V3_EXT_CRL_add_nconf(&ctmp, ctx, section, crl); ++} ++ ++/* Add extensions to certificate request */ ++ ++int X509V3_EXT_REQ_add_conf(LHASH_OF(CONF_VALUE) *conf, X509V3_CTX *ctx, ++ const char *section, X509_REQ *req) ++{ ++ CONF ctmp; ++ CONF_set_nconf(&ctmp, conf); ++ return X509V3_EXT_REQ_add_nconf(&ctmp, ctx, section, req); ++} +diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/x509v3/v3_cpols.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/x509v3/v3_cpols.c +new file mode 100644 +index 0000000..f717e13 +--- /dev/null ++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/x509v3/v3_cpols.c +@@ -0,0 +1,441 @@ ++/* ++ * Copyright 1999-2016 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 ++ * in the file LICENSE in the source distribution or at ++ * https://www.openssl.org/source/license.html ++ */ ++ ++#include ++#include "internal/cryptlib.h" ++#include ++#include ++#include ++#include ++ ++#include "pcy_int.h" ++#include "ext_dat.h" ++ ++/* Certificate policies extension support: this one is a bit complex... */ ++ ++static int i2r_certpol(X509V3_EXT_METHOD *method, STACK_OF(POLICYINFO) *pol, ++ BIO *out, int indent); ++static STACK_OF(POLICYINFO) *r2i_certpol(X509V3_EXT_METHOD *method, ++ X509V3_CTX *ctx, const char *value); ++static void print_qualifiers(BIO *out, STACK_OF(POLICYQUALINFO) *quals, ++ int indent); ++static void print_notice(BIO *out, USERNOTICE *notice, int indent); ++static POLICYINFO *policy_section(X509V3_CTX *ctx, ++ STACK_OF(CONF_VALUE) *polstrs, int ia5org); ++static POLICYQUALINFO *notice_section(X509V3_CTX *ctx, ++ STACK_OF(CONF_VALUE) *unot, int ia5org); ++static int nref_nos(STACK_OF(ASN1_INTEGER) *nnums, STACK_OF(CONF_VALUE) *nos); ++ ++const X509V3_EXT_METHOD v3_cpols = { ++ NID_certificate_policies, 0, ASN1_ITEM_ref(CERTIFICATEPOLICIES), ++ 0, 0, 0, 0, ++ 0, 0, ++ 0, 0, ++ (X509V3_EXT_I2R)i2r_certpol, ++ (X509V3_EXT_R2I)r2i_certpol, ++ NULL ++}; ++ ++ASN1_ITEM_TEMPLATE(CERTIFICATEPOLICIES) = ++ ASN1_EX_TEMPLATE_TYPE(ASN1_TFLG_SEQUENCE_OF, 0, CERTIFICATEPOLICIES, POLICYINFO) ++ASN1_ITEM_TEMPLATE_END(CERTIFICATEPOLICIES) ++ ++IMPLEMENT_ASN1_FUNCTIONS(CERTIFICATEPOLICIES) ++ ++ASN1_SEQUENCE(POLICYINFO) = { ++ ASN1_SIMPLE(POLICYINFO, policyid, ASN1_OBJECT), ++ ASN1_SEQUENCE_OF_OPT(POLICYINFO, qualifiers, POLICYQUALINFO) ++} ASN1_SEQUENCE_END(POLICYINFO) ++ ++IMPLEMENT_ASN1_FUNCTIONS(POLICYINFO) ++ ++ASN1_ADB_TEMPLATE(policydefault) = ASN1_SIMPLE(POLICYQUALINFO, d.other, ASN1_ANY); ++ ++ASN1_ADB(POLICYQUALINFO) = { ++ ADB_ENTRY(NID_id_qt_cps, ASN1_SIMPLE(POLICYQUALINFO, d.cpsuri, ASN1_IA5STRING)), ++ ADB_ENTRY(NID_id_qt_unotice, ASN1_SIMPLE(POLICYQUALINFO, d.usernotice, USERNOTICE)) ++} ASN1_ADB_END(POLICYQUALINFO, 0, pqualid, 0, &policydefault_tt, NULL); ++ ++ASN1_SEQUENCE(POLICYQUALINFO) = { ++ ASN1_SIMPLE(POLICYQUALINFO, pqualid, ASN1_OBJECT), ++ ASN1_ADB_OBJECT(POLICYQUALINFO) ++} ASN1_SEQUENCE_END(POLICYQUALINFO) ++ ++IMPLEMENT_ASN1_FUNCTIONS(POLICYQUALINFO) ++ ++ASN1_SEQUENCE(USERNOTICE) = { ++ ASN1_OPT(USERNOTICE, noticeref, NOTICEREF), ++ ASN1_OPT(USERNOTICE, exptext, DISPLAYTEXT) ++} ASN1_SEQUENCE_END(USERNOTICE) ++ ++IMPLEMENT_ASN1_FUNCTIONS(USERNOTICE) ++ ++ASN1_SEQUENCE(NOTICEREF) = { ++ ASN1_SIMPLE(NOTICEREF, organization, DISPLAYTEXT), ++ ASN1_SEQUENCE_OF(NOTICEREF, noticenos, ASN1_INTEGER) ++} ASN1_SEQUENCE_END(NOTICEREF) ++ ++IMPLEMENT_ASN1_FUNCTIONS(NOTICEREF) ++ ++static STACK_OF(POLICYINFO) *r2i_certpol(X509V3_EXT_METHOD *method, ++ X509V3_CTX *ctx, const char *value) ++{ ++ STACK_OF(POLICYINFO) *pols = NULL; ++ char *pstr; ++ POLICYINFO *pol; ++ ASN1_OBJECT *pobj; ++ STACK_OF(CONF_VALUE) *vals; ++ CONF_VALUE *cnf; ++ int i, ia5org; ++ pols = sk_POLICYINFO_new_null(); ++ if (pols == NULL) { ++ X509V3err(X509V3_F_R2I_CERTPOL, ERR_R_MALLOC_FAILURE); ++ return NULL; ++ } ++ vals = X509V3_parse_list(value); ++ if (vals == NULL) { ++ X509V3err(X509V3_F_R2I_CERTPOL, ERR_R_X509V3_LIB); ++ goto err; ++ } ++ ia5org = 0; ++ for (i = 0; i < sk_CONF_VALUE_num(vals); i++) { ++ cnf = sk_CONF_VALUE_value(vals, i); ++ if (cnf->value || !cnf->name) { ++ X509V3err(X509V3_F_R2I_CERTPOL, ++ X509V3_R_INVALID_POLICY_IDENTIFIER); ++ X509V3_conf_err(cnf); ++ goto err; ++ } ++ pstr = cnf->name; ++ if (strcmp(pstr, "ia5org") == 0) { ++ ia5org = 1; ++ continue; ++ } else if (*pstr == '@') { ++ STACK_OF(CONF_VALUE) *polsect; ++ polsect = X509V3_get_section(ctx, pstr + 1); ++ if (!polsect) { ++ X509V3err(X509V3_F_R2I_CERTPOL, X509V3_R_INVALID_SECTION); ++ ++ X509V3_conf_err(cnf); ++ goto err; ++ } ++ pol = policy_section(ctx, polsect, ia5org); ++ X509V3_section_free(ctx, polsect); ++ if (pol == NULL) ++ goto err; ++ } else { ++ if ((pobj = OBJ_txt2obj(cnf->name, 0)) == NULL) { ++ X509V3err(X509V3_F_R2I_CERTPOL, ++ X509V3_R_INVALID_OBJECT_IDENTIFIER); ++ X509V3_conf_err(cnf); ++ goto err; ++ } ++ pol = POLICYINFO_new(); ++ if (pol == NULL) { ++ X509V3err(X509V3_F_R2I_CERTPOL, ERR_R_MALLOC_FAILURE); ++ ASN1_OBJECT_free(pobj); ++ goto err; ++ } ++ pol->policyid = pobj; ++ } ++ if (!sk_POLICYINFO_push(pols, pol)) { ++ POLICYINFO_free(pol); ++ X509V3err(X509V3_F_R2I_CERTPOL, ERR_R_MALLOC_FAILURE); ++ goto err; ++ } ++ } ++ sk_CONF_VALUE_pop_free(vals, X509V3_conf_free); ++ return pols; ++ err: ++ sk_CONF_VALUE_pop_free(vals, X509V3_conf_free); ++ sk_POLICYINFO_pop_free(pols, POLICYINFO_free); ++ return NULL; ++} ++ ++static POLICYINFO *policy_section(X509V3_CTX *ctx, ++ STACK_OF(CONF_VALUE) *polstrs, int ia5org) ++{ ++ int i; ++ CONF_VALUE *cnf; ++ POLICYINFO *pol; ++ POLICYQUALINFO *qual; ++ ++ if ((pol = POLICYINFO_new()) == NULL) ++ goto merr; ++ for (i = 0; i < sk_CONF_VALUE_num(polstrs); i++) { ++ cnf = sk_CONF_VALUE_value(polstrs, i); ++ if (strcmp(cnf->name, "policyIdentifier") == 0) { ++ ASN1_OBJECT *pobj; ++ if ((pobj = OBJ_txt2obj(cnf->value, 0)) == NULL) { ++ X509V3err(X509V3_F_POLICY_SECTION, ++ X509V3_R_INVALID_OBJECT_IDENTIFIER); ++ X509V3_conf_err(cnf); ++ goto err; ++ } ++ pol->policyid = pobj; ++ ++ } else if (!name_cmp(cnf->name, "CPS")) { ++ if (pol->qualifiers == NULL) ++ pol->qualifiers = sk_POLICYQUALINFO_new_null(); ++ if ((qual = POLICYQUALINFO_new()) == NULL) ++ goto merr; ++ if (!sk_POLICYQUALINFO_push(pol->qualifiers, qual)) ++ goto merr; ++ if ((qual->pqualid = OBJ_nid2obj(NID_id_qt_cps)) == NULL) { ++ X509V3err(X509V3_F_POLICY_SECTION, ERR_R_INTERNAL_ERROR); ++ goto err; ++ } ++ if ((qual->d.cpsuri = ASN1_IA5STRING_new()) == NULL) ++ goto merr; ++ if (!ASN1_STRING_set(qual->d.cpsuri, cnf->value, ++ strlen(cnf->value))) ++ goto merr; ++ } else if (!name_cmp(cnf->name, "userNotice")) { ++ STACK_OF(CONF_VALUE) *unot; ++ if (*cnf->value != '@') { ++ X509V3err(X509V3_F_POLICY_SECTION, ++ X509V3_R_EXPECTED_A_SECTION_NAME); ++ X509V3_conf_err(cnf); ++ goto err; ++ } ++ unot = X509V3_get_section(ctx, cnf->value + 1); ++ if (!unot) { ++ X509V3err(X509V3_F_POLICY_SECTION, X509V3_R_INVALID_SECTION); ++ ++ X509V3_conf_err(cnf); ++ goto err; ++ } ++ qual = notice_section(ctx, unot, ia5org); ++ X509V3_section_free(ctx, unot); ++ if (!qual) ++ goto err; ++ if (!pol->qualifiers) ++ pol->qualifiers = sk_POLICYQUALINFO_new_null(); ++ if (!sk_POLICYQUALINFO_push(pol->qualifiers, qual)) ++ goto merr; ++ } else { ++ X509V3err(X509V3_F_POLICY_SECTION, X509V3_R_INVALID_OPTION); ++ ++ X509V3_conf_err(cnf); ++ goto err; ++ } ++ } ++ if (!pol->policyid) { ++ X509V3err(X509V3_F_POLICY_SECTION, X509V3_R_NO_POLICY_IDENTIFIER); ++ goto err; ++ } ++ ++ return pol; ++ ++ merr: ++ X509V3err(X509V3_F_POLICY_SECTION, ERR_R_MALLOC_FAILURE); ++ ++ err: ++ POLICYINFO_free(pol); ++ return NULL; ++ ++} ++ ++static POLICYQUALINFO *notice_section(X509V3_CTX *ctx, ++ STACK_OF(CONF_VALUE) *unot, int ia5org) ++{ ++ int i, ret; ++ CONF_VALUE *cnf; ++ USERNOTICE *not; ++ POLICYQUALINFO *qual; ++ ++ if ((qual = POLICYQUALINFO_new()) == NULL) ++ goto merr; ++ if ((qual->pqualid = OBJ_nid2obj(NID_id_qt_unotice)) == NULL) { ++ X509V3err(X509V3_F_NOTICE_SECTION, ERR_R_INTERNAL_ERROR); ++ goto err; ++ } ++ if ((not = USERNOTICE_new()) == NULL) ++ goto merr; ++ qual->d.usernotice = not; ++ for (i = 0; i < sk_CONF_VALUE_num(unot); i++) { ++ cnf = sk_CONF_VALUE_value(unot, i); ++ if (strcmp(cnf->name, "explicitText") == 0) { ++ if ((not->exptext = ASN1_VISIBLESTRING_new()) == NULL) ++ goto merr; ++ if (!ASN1_STRING_set(not->exptext, cnf->value, ++ strlen(cnf->value))) ++ goto merr; ++ } else if (strcmp(cnf->name, "organization") == 0) { ++ NOTICEREF *nref; ++ if (!not->noticeref) { ++ if ((nref = NOTICEREF_new()) == NULL) ++ goto merr; ++ not->noticeref = nref; ++ } else ++ nref = not->noticeref; ++ if (ia5org) ++ nref->organization->type = V_ASN1_IA5STRING; ++ else ++ nref->organization->type = V_ASN1_VISIBLESTRING; ++ if (!ASN1_STRING_set(nref->organization, cnf->value, ++ strlen(cnf->value))) ++ goto merr; ++ } else if (strcmp(cnf->name, "noticeNumbers") == 0) { ++ NOTICEREF *nref; ++ STACK_OF(CONF_VALUE) *nos; ++ if (!not->noticeref) { ++ if ((nref = NOTICEREF_new()) == NULL) ++ goto merr; ++ not->noticeref = nref; ++ } else ++ nref = not->noticeref; ++ nos = X509V3_parse_list(cnf->value); ++ if (!nos || !sk_CONF_VALUE_num(nos)) { ++ X509V3err(X509V3_F_NOTICE_SECTION, X509V3_R_INVALID_NUMBERS); ++ X509V3_conf_err(cnf); ++ sk_CONF_VALUE_pop_free(nos, X509V3_conf_free); ++ goto err; ++ } ++ ret = nref_nos(nref->noticenos, nos); ++ sk_CONF_VALUE_pop_free(nos, X509V3_conf_free); ++ if (!ret) ++ goto err; ++ } else { ++ X509V3err(X509V3_F_NOTICE_SECTION, X509V3_R_INVALID_OPTION); ++ X509V3_conf_err(cnf); ++ goto err; ++ } ++ } ++ ++ if (not->noticeref && ++ (!not->noticeref->noticenos || !not->noticeref->organization)) { ++ X509V3err(X509V3_F_NOTICE_SECTION, ++ X509V3_R_NEED_ORGANIZATION_AND_NUMBERS); ++ goto err; ++ } ++ ++ return qual; ++ ++ merr: ++ X509V3err(X509V3_F_NOTICE_SECTION, ERR_R_MALLOC_FAILURE); ++ ++ err: ++ POLICYQUALINFO_free(qual); ++ return NULL; ++} ++ ++static int nref_nos(STACK_OF(ASN1_INTEGER) *nnums, STACK_OF(CONF_VALUE) *nos) ++{ ++ CONF_VALUE *cnf; ++ ASN1_INTEGER *aint; ++ ++ int i; ++ ++ for (i = 0; i < sk_CONF_VALUE_num(nos); i++) { ++ cnf = sk_CONF_VALUE_value(nos, i); ++ if ((aint = s2i_ASN1_INTEGER(NULL, cnf->name)) == NULL) { ++ X509V3err(X509V3_F_NREF_NOS, X509V3_R_INVALID_NUMBER); ++ goto err; ++ } ++ if (!sk_ASN1_INTEGER_push(nnums, aint)) ++ goto merr; ++ } ++ return 1; ++ ++ merr: ++ ASN1_INTEGER_free(aint); ++ X509V3err(X509V3_F_NREF_NOS, ERR_R_MALLOC_FAILURE); ++ ++ err: ++ return 0; ++} ++ ++static int i2r_certpol(X509V3_EXT_METHOD *method, STACK_OF(POLICYINFO) *pol, ++ BIO *out, int indent) ++{ ++ int i; ++ POLICYINFO *pinfo; ++ /* First print out the policy OIDs */ ++ for (i = 0; i < sk_POLICYINFO_num(pol); i++) { ++ pinfo = sk_POLICYINFO_value(pol, i); ++ BIO_printf(out, "%*sPolicy: ", indent, ""); ++ i2a_ASN1_OBJECT(out, pinfo->policyid); ++ BIO_puts(out, "\n"); ++ if (pinfo->qualifiers) ++ print_qualifiers(out, pinfo->qualifiers, indent + 2); ++ } ++ return 1; ++} ++ ++static void print_qualifiers(BIO *out, STACK_OF(POLICYQUALINFO) *quals, ++ int indent) ++{ ++ POLICYQUALINFO *qualinfo; ++ int i; ++ for (i = 0; i < sk_POLICYQUALINFO_num(quals); i++) { ++ qualinfo = sk_POLICYQUALINFO_value(quals, i); ++ switch (OBJ_obj2nid(qualinfo->pqualid)) { ++ case NID_id_qt_cps: ++ BIO_printf(out, "%*sCPS: %s\n", indent, "", ++ qualinfo->d.cpsuri->data); ++ break; ++ ++ case NID_id_qt_unotice: ++ BIO_printf(out, "%*sUser Notice:\n", indent, ""); ++ print_notice(out, qualinfo->d.usernotice, indent + 2); ++ break; ++ ++ default: ++ BIO_printf(out, "%*sUnknown Qualifier: ", indent + 2, ""); ++ ++ i2a_ASN1_OBJECT(out, qualinfo->pqualid); ++ BIO_puts(out, "\n"); ++ break; ++ } ++ } ++} ++ ++static void print_notice(BIO *out, USERNOTICE *notice, int indent) ++{ ++ int i; ++ if (notice->noticeref) { ++ NOTICEREF *ref; ++ ref = notice->noticeref; ++ BIO_printf(out, "%*sOrganization: %s\n", indent, "", ++ ref->organization->data); ++ BIO_printf(out, "%*sNumber%s: ", indent, "", ++ sk_ASN1_INTEGER_num(ref->noticenos) > 1 ? "s" : ""); ++ for (i = 0; i < sk_ASN1_INTEGER_num(ref->noticenos); i++) { ++ ASN1_INTEGER *num; ++ char *tmp; ++ num = sk_ASN1_INTEGER_value(ref->noticenos, i); ++ if (i) ++ BIO_puts(out, ", "); ++ tmp = i2s_ASN1_INTEGER(NULL, num); ++ BIO_puts(out, tmp); ++ OPENSSL_free(tmp); ++ } ++ BIO_puts(out, "\n"); ++ } ++ if (notice->exptext) ++ BIO_printf(out, "%*sExplicit Text: %s\n", indent, "", ++ notice->exptext->data); ++} ++ ++void X509_POLICY_NODE_print(BIO *out, X509_POLICY_NODE *node, int indent) ++{ ++ const X509_POLICY_DATA *dat = node->data; ++ ++ BIO_printf(out, "%*sPolicy: ", indent, ""); ++ ++ i2a_ASN1_OBJECT(out, dat->valid_policy); ++ BIO_puts(out, "\n"); ++ BIO_printf(out, "%*s%s\n", indent + 2, "", ++ node_data_critical(dat) ? "Critical" : "Non Critical"); ++ if (dat->qualifier_set) ++ print_qualifiers(out, dat->qualifier_set, indent + 2); ++ else ++ BIO_printf(out, "%*sNo Qualifiers\n", indent + 2, ""); ++} +diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/x509v3/v3_crld.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/x509v3/v3_crld.c +new file mode 100644 +index 0000000..c4c77f1 +--- /dev/null ++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/x509v3/v3_crld.c +@@ -0,0 +1,509 @@ ++/* ++ * Copyright 1999-2016 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 ++ * in the file LICENSE in the source distribution or at ++ * https://www.openssl.org/source/license.html ++ */ ++ ++#include ++#include "internal/cryptlib.h" ++#include ++#include ++#include ++#include ++ ++#include "internal/x509_int.h" ++#include "ext_dat.h" ++ ++static void *v2i_crld(const X509V3_EXT_METHOD *method, ++ X509V3_CTX *ctx, STACK_OF(CONF_VALUE) *nval); ++static int i2r_crldp(const X509V3_EXT_METHOD *method, void *pcrldp, BIO *out, ++ int indent); ++ ++const X509V3_EXT_METHOD v3_crld = { ++ NID_crl_distribution_points, 0, ASN1_ITEM_ref(CRL_DIST_POINTS), ++ 0, 0, 0, 0, ++ 0, 0, ++ 0, ++ v2i_crld, ++ i2r_crldp, 0, ++ NULL ++}; ++ ++const X509V3_EXT_METHOD v3_freshest_crl = { ++ NID_freshest_crl, 0, ASN1_ITEM_ref(CRL_DIST_POINTS), ++ 0, 0, 0, 0, ++ 0, 0, ++ 0, ++ v2i_crld, ++ i2r_crldp, 0, ++ NULL ++}; ++ ++static STACK_OF(GENERAL_NAME) *gnames_from_sectname(X509V3_CTX *ctx, ++ char *sect) ++{ ++ STACK_OF(CONF_VALUE) *gnsect; ++ STACK_OF(GENERAL_NAME) *gens; ++ if (*sect == '@') ++ gnsect = X509V3_get_section(ctx, sect + 1); ++ else ++ gnsect = X509V3_parse_list(sect); ++ if (!gnsect) { ++ X509V3err(X509V3_F_GNAMES_FROM_SECTNAME, X509V3_R_SECTION_NOT_FOUND); ++ return NULL; ++ } ++ gens = v2i_GENERAL_NAMES(NULL, ctx, gnsect); ++ if (*sect == '@') ++ X509V3_section_free(ctx, gnsect); ++ else ++ sk_CONF_VALUE_pop_free(gnsect, X509V3_conf_free); ++ return gens; ++} ++ ++static int set_dist_point_name(DIST_POINT_NAME **pdp, X509V3_CTX *ctx, ++ CONF_VALUE *cnf) ++{ ++ STACK_OF(GENERAL_NAME) *fnm = NULL; ++ STACK_OF(X509_NAME_ENTRY) *rnm = NULL; ++ ++ if (strncmp(cnf->name, "fullname", 9) == 0) { ++ fnm = gnames_from_sectname(ctx, cnf->value); ++ if (!fnm) ++ goto err; ++ } else if (strcmp(cnf->name, "relativename") == 0) { ++ int ret; ++ STACK_OF(CONF_VALUE) *dnsect; ++ X509_NAME *nm; ++ nm = X509_NAME_new(); ++ if (nm == NULL) ++ return -1; ++ dnsect = X509V3_get_section(ctx, cnf->value); ++ if (!dnsect) { ++ X509V3err(X509V3_F_SET_DIST_POINT_NAME, ++ X509V3_R_SECTION_NOT_FOUND); ++ return -1; ++ } ++ ret = X509V3_NAME_from_section(nm, dnsect, MBSTRING_ASC); ++ X509V3_section_free(ctx, dnsect); ++ rnm = nm->entries; ++ nm->entries = NULL; ++ X509_NAME_free(nm); ++ if (!ret || sk_X509_NAME_ENTRY_num(rnm) <= 0) ++ goto err; ++ /* ++ * Since its a name fragment can't have more than one RDNSequence ++ */ ++ if (sk_X509_NAME_ENTRY_value(rnm, ++ sk_X509_NAME_ENTRY_num(rnm) - 1)->set) { ++ X509V3err(X509V3_F_SET_DIST_POINT_NAME, ++ X509V3_R_INVALID_MULTIPLE_RDNS); ++ goto err; ++ } ++ } else ++ return 0; ++ ++ if (*pdp) { ++ X509V3err(X509V3_F_SET_DIST_POINT_NAME, ++ X509V3_R_DISTPOINT_ALREADY_SET); ++ goto err; ++ } ++ ++ *pdp = DIST_POINT_NAME_new(); ++ if (*pdp == NULL) ++ goto err; ++ if (fnm) { ++ (*pdp)->type = 0; ++ (*pdp)->name.fullname = fnm; ++ } else { ++ (*pdp)->type = 1; ++ (*pdp)->name.relativename = rnm; ++ } ++ ++ return 1; ++ ++ err: ++ sk_GENERAL_NAME_pop_free(fnm, GENERAL_NAME_free); ++ sk_X509_NAME_ENTRY_pop_free(rnm, X509_NAME_ENTRY_free); ++ return -1; ++} ++ ++static const BIT_STRING_BITNAME reason_flags[] = { ++ {0, "Unused", "unused"}, ++ {1, "Key Compromise", "keyCompromise"}, ++ {2, "CA Compromise", "CACompromise"}, ++ {3, "Affiliation Changed", "affiliationChanged"}, ++ {4, "Superseded", "superseded"}, ++ {5, "Cessation Of Operation", "cessationOfOperation"}, ++ {6, "Certificate Hold", "certificateHold"}, ++ {7, "Privilege Withdrawn", "privilegeWithdrawn"}, ++ {8, "AA Compromise", "AACompromise"}, ++ {-1, NULL, NULL} ++}; ++ ++static int set_reasons(ASN1_BIT_STRING **preas, char *value) ++{ ++ STACK_OF(CONF_VALUE) *rsk = NULL; ++ const BIT_STRING_BITNAME *pbn; ++ const char *bnam; ++ int i, ret = 0; ++ rsk = X509V3_parse_list(value); ++ if (rsk == NULL) ++ return 0; ++ if (*preas != NULL) ++ goto err; ++ for (i = 0; i < sk_CONF_VALUE_num(rsk); i++) { ++ bnam = sk_CONF_VALUE_value(rsk, i)->name; ++ if (*preas == NULL) { ++ *preas = ASN1_BIT_STRING_new(); ++ if (*preas == NULL) ++ goto err; ++ } ++ for (pbn = reason_flags; pbn->lname; pbn++) { ++ if (strcmp(pbn->sname, bnam) == 0) { ++ if (!ASN1_BIT_STRING_set_bit(*preas, pbn->bitnum, 1)) ++ goto err; ++ break; ++ } ++ } ++ if (!pbn->lname) ++ goto err; ++ } ++ ret = 1; ++ ++ err: ++ sk_CONF_VALUE_pop_free(rsk, X509V3_conf_free); ++ return ret; ++} ++ ++static int print_reasons(BIO *out, const char *rname, ++ ASN1_BIT_STRING *rflags, int indent) ++{ ++ int first = 1; ++ const BIT_STRING_BITNAME *pbn; ++ BIO_printf(out, "%*s%s:\n%*s", indent, "", rname, indent + 2, ""); ++ for (pbn = reason_flags; pbn->lname; pbn++) { ++ if (ASN1_BIT_STRING_get_bit(rflags, pbn->bitnum)) { ++ if (first) ++ first = 0; ++ else ++ BIO_puts(out, ", "); ++ BIO_puts(out, pbn->lname); ++ } ++ } ++ if (first) ++ BIO_puts(out, "\n"); ++ else ++ BIO_puts(out, "\n"); ++ return 1; ++} ++ ++static DIST_POINT *crldp_from_section(X509V3_CTX *ctx, ++ STACK_OF(CONF_VALUE) *nval) ++{ ++ int i; ++ CONF_VALUE *cnf; ++ DIST_POINT *point = NULL; ++ point = DIST_POINT_new(); ++ if (point == NULL) ++ goto err; ++ for (i = 0; i < sk_CONF_VALUE_num(nval); i++) { ++ int ret; ++ cnf = sk_CONF_VALUE_value(nval, i); ++ ret = set_dist_point_name(&point->distpoint, ctx, cnf); ++ if (ret > 0) ++ continue; ++ if (ret < 0) ++ goto err; ++ if (strcmp(cnf->name, "reasons") == 0) { ++ if (!set_reasons(&point->reasons, cnf->value)) ++ goto err; ++ } else if (strcmp(cnf->name, "CRLissuer") == 0) { ++ point->CRLissuer = gnames_from_sectname(ctx, cnf->value); ++ if (!point->CRLissuer) ++ goto err; ++ } ++ } ++ ++ return point; ++ ++ err: ++ DIST_POINT_free(point); ++ return NULL; ++} ++ ++static void *v2i_crld(const X509V3_EXT_METHOD *method, ++ X509V3_CTX *ctx, STACK_OF(CONF_VALUE) *nval) ++{ ++ STACK_OF(DIST_POINT) *crld = NULL; ++ GENERAL_NAMES *gens = NULL; ++ GENERAL_NAME *gen = NULL; ++ CONF_VALUE *cnf; ++ int i; ++ ++ if ((crld = sk_DIST_POINT_new_null()) == NULL) ++ goto merr; ++ for (i = 0; i < sk_CONF_VALUE_num(nval); i++) { ++ DIST_POINT *point; ++ cnf = sk_CONF_VALUE_value(nval, i); ++ if (!cnf->value) { ++ STACK_OF(CONF_VALUE) *dpsect; ++ dpsect = X509V3_get_section(ctx, cnf->name); ++ if (!dpsect) ++ goto err; ++ point = crldp_from_section(ctx, dpsect); ++ X509V3_section_free(ctx, dpsect); ++ if (!point) ++ goto err; ++ if (!sk_DIST_POINT_push(crld, point)) { ++ DIST_POINT_free(point); ++ goto merr; ++ } ++ } else { ++ if ((gen = v2i_GENERAL_NAME(method, ctx, cnf)) == NULL) ++ goto err; ++ if ((gens = GENERAL_NAMES_new()) == NULL) ++ goto merr; ++ if (!sk_GENERAL_NAME_push(gens, gen)) ++ goto merr; ++ gen = NULL; ++ if ((point = DIST_POINT_new()) == NULL) ++ goto merr; ++ if (!sk_DIST_POINT_push(crld, point)) { ++ DIST_POINT_free(point); ++ goto merr; ++ } ++ if ((point->distpoint = DIST_POINT_NAME_new()) == NULL) ++ goto merr; ++ point->distpoint->name.fullname = gens; ++ point->distpoint->type = 0; ++ gens = NULL; ++ } ++ } ++ return crld; ++ ++ merr: ++ X509V3err(X509V3_F_V2I_CRLD, ERR_R_MALLOC_FAILURE); ++ err: ++ GENERAL_NAME_free(gen); ++ GENERAL_NAMES_free(gens); ++ sk_DIST_POINT_pop_free(crld, DIST_POINT_free); ++ return NULL; ++} ++ ++static int dpn_cb(int operation, ASN1_VALUE **pval, const ASN1_ITEM *it, ++ void *exarg) ++{ ++ DIST_POINT_NAME *dpn = (DIST_POINT_NAME *)*pval; ++ ++ switch (operation) { ++ case ASN1_OP_NEW_POST: ++ dpn->dpname = NULL; ++ break; ++ ++ case ASN1_OP_FREE_POST: ++ X509_NAME_free(dpn->dpname); ++ break; ++ } ++ return 1; ++} ++ ++ ++ASN1_CHOICE_cb(DIST_POINT_NAME, dpn_cb) = { ++ ASN1_IMP_SEQUENCE_OF(DIST_POINT_NAME, name.fullname, GENERAL_NAME, 0), ++ ASN1_IMP_SET_OF(DIST_POINT_NAME, name.relativename, X509_NAME_ENTRY, 1) ++} ASN1_CHOICE_END_cb(DIST_POINT_NAME, DIST_POINT_NAME, type) ++ ++ ++IMPLEMENT_ASN1_FUNCTIONS(DIST_POINT_NAME) ++ ++ASN1_SEQUENCE(DIST_POINT) = { ++ ASN1_EXP_OPT(DIST_POINT, distpoint, DIST_POINT_NAME, 0), ++ ASN1_IMP_OPT(DIST_POINT, reasons, ASN1_BIT_STRING, 1), ++ ASN1_IMP_SEQUENCE_OF_OPT(DIST_POINT, CRLissuer, GENERAL_NAME, 2) ++} ASN1_SEQUENCE_END(DIST_POINT) ++ ++IMPLEMENT_ASN1_FUNCTIONS(DIST_POINT) ++ ++ASN1_ITEM_TEMPLATE(CRL_DIST_POINTS) = ++ ASN1_EX_TEMPLATE_TYPE(ASN1_TFLG_SEQUENCE_OF, 0, CRLDistributionPoints, DIST_POINT) ++ASN1_ITEM_TEMPLATE_END(CRL_DIST_POINTS) ++ ++IMPLEMENT_ASN1_FUNCTIONS(CRL_DIST_POINTS) ++ ++ASN1_SEQUENCE(ISSUING_DIST_POINT) = { ++ ASN1_EXP_OPT(ISSUING_DIST_POINT, distpoint, DIST_POINT_NAME, 0), ++ ASN1_IMP_OPT(ISSUING_DIST_POINT, onlyuser, ASN1_FBOOLEAN, 1), ++ ASN1_IMP_OPT(ISSUING_DIST_POINT, onlyCA, ASN1_FBOOLEAN, 2), ++ ASN1_IMP_OPT(ISSUING_DIST_POINT, onlysomereasons, ASN1_BIT_STRING, 3), ++ ASN1_IMP_OPT(ISSUING_DIST_POINT, indirectCRL, ASN1_FBOOLEAN, 4), ++ ASN1_IMP_OPT(ISSUING_DIST_POINT, onlyattr, ASN1_FBOOLEAN, 5) ++} ASN1_SEQUENCE_END(ISSUING_DIST_POINT) ++ ++IMPLEMENT_ASN1_FUNCTIONS(ISSUING_DIST_POINT) ++ ++static int i2r_idp(const X509V3_EXT_METHOD *method, void *pidp, BIO *out, ++ int indent); ++static void *v2i_idp(const X509V3_EXT_METHOD *method, X509V3_CTX *ctx, ++ STACK_OF(CONF_VALUE) *nval); ++ ++const X509V3_EXT_METHOD v3_idp = { ++ NID_issuing_distribution_point, X509V3_EXT_MULTILINE, ++ ASN1_ITEM_ref(ISSUING_DIST_POINT), ++ 0, 0, 0, 0, ++ 0, 0, ++ 0, ++ v2i_idp, ++ i2r_idp, 0, ++ NULL ++}; ++ ++static void *v2i_idp(const X509V3_EXT_METHOD *method, X509V3_CTX *ctx, ++ STACK_OF(CONF_VALUE) *nval) ++{ ++ ISSUING_DIST_POINT *idp = NULL; ++ CONF_VALUE *cnf; ++ char *name, *val; ++ int i, ret; ++ idp = ISSUING_DIST_POINT_new(); ++ if (idp == NULL) ++ goto merr; ++ for (i = 0; i < sk_CONF_VALUE_num(nval); i++) { ++ cnf = sk_CONF_VALUE_value(nval, i); ++ name = cnf->name; ++ val = cnf->value; ++ ret = set_dist_point_name(&idp->distpoint, ctx, cnf); ++ if (ret > 0) ++ continue; ++ if (ret < 0) ++ goto err; ++ if (strcmp(name, "onlyuser") == 0) { ++ if (!X509V3_get_value_bool(cnf, &idp->onlyuser)) ++ goto err; ++ } else if (strcmp(name, "onlyCA") == 0) { ++ if (!X509V3_get_value_bool(cnf, &idp->onlyCA)) ++ goto err; ++ } else if (strcmp(name, "onlyAA") == 0) { ++ if (!X509V3_get_value_bool(cnf, &idp->onlyattr)) ++ goto err; ++ } else if (strcmp(name, "indirectCRL") == 0) { ++ if (!X509V3_get_value_bool(cnf, &idp->indirectCRL)) ++ goto err; ++ } else if (strcmp(name, "onlysomereasons") == 0) { ++ if (!set_reasons(&idp->onlysomereasons, val)) ++ goto err; ++ } else { ++ X509V3err(X509V3_F_V2I_IDP, X509V3_R_INVALID_NAME); ++ X509V3_conf_err(cnf); ++ goto err; ++ } ++ } ++ return idp; ++ ++ merr: ++ X509V3err(X509V3_F_V2I_IDP, ERR_R_MALLOC_FAILURE); ++ err: ++ ISSUING_DIST_POINT_free(idp); ++ return NULL; ++} ++ ++static int print_gens(BIO *out, STACK_OF(GENERAL_NAME) *gens, int indent) ++{ ++ int i; ++ for (i = 0; i < sk_GENERAL_NAME_num(gens); i++) { ++ BIO_printf(out, "%*s", indent + 2, ""); ++ GENERAL_NAME_print(out, sk_GENERAL_NAME_value(gens, i)); ++ BIO_puts(out, "\n"); ++ } ++ return 1; ++} ++ ++static int print_distpoint(BIO *out, DIST_POINT_NAME *dpn, int indent) ++{ ++ if (dpn->type == 0) { ++ BIO_printf(out, "%*sFull Name:\n", indent, ""); ++ print_gens(out, dpn->name.fullname, indent); ++ } else { ++ X509_NAME ntmp; ++ ntmp.entries = dpn->name.relativename; ++ BIO_printf(out, "%*sRelative Name:\n%*s", indent, "", indent + 2, ""); ++ X509_NAME_print_ex(out, &ntmp, 0, XN_FLAG_ONELINE); ++ BIO_puts(out, "\n"); ++ } ++ return 1; ++} ++ ++static int i2r_idp(const X509V3_EXT_METHOD *method, void *pidp, BIO *out, ++ int indent) ++{ ++ ISSUING_DIST_POINT *idp = pidp; ++ if (idp->distpoint) ++ print_distpoint(out, idp->distpoint, indent); ++ if (idp->onlyuser > 0) ++ BIO_printf(out, "%*sOnly User Certificates\n", indent, ""); ++ if (idp->onlyCA > 0) ++ BIO_printf(out, "%*sOnly CA Certificates\n", indent, ""); ++ if (idp->indirectCRL > 0) ++ BIO_printf(out, "%*sIndirect CRL\n", indent, ""); ++ if (idp->onlysomereasons) ++ print_reasons(out, "Only Some Reasons", idp->onlysomereasons, indent); ++ if (idp->onlyattr > 0) ++ BIO_printf(out, "%*sOnly Attribute Certificates\n", indent, ""); ++ if (!idp->distpoint && (idp->onlyuser <= 0) && (idp->onlyCA <= 0) ++ && (idp->indirectCRL <= 0) && !idp->onlysomereasons ++ && (idp->onlyattr <= 0)) ++ BIO_printf(out, "%*s\n", indent, ""); ++ ++ return 1; ++} ++ ++static int i2r_crldp(const X509V3_EXT_METHOD *method, void *pcrldp, BIO *out, ++ int indent) ++{ ++ STACK_OF(DIST_POINT) *crld = pcrldp; ++ DIST_POINT *point; ++ int i; ++ for (i = 0; i < sk_DIST_POINT_num(crld); i++) { ++ BIO_puts(out, "\n"); ++ point = sk_DIST_POINT_value(crld, i); ++ if (point->distpoint) ++ print_distpoint(out, point->distpoint, indent); ++ if (point->reasons) ++ print_reasons(out, "Reasons", point->reasons, indent); ++ if (point->CRLissuer) { ++ BIO_printf(out, "%*sCRL Issuer:\n", indent, ""); ++ print_gens(out, point->CRLissuer, indent); ++ } ++ } ++ return 1; ++} ++ ++int DIST_POINT_set_dpname(DIST_POINT_NAME *dpn, X509_NAME *iname) ++{ ++ int i; ++ STACK_OF(X509_NAME_ENTRY) *frag; ++ X509_NAME_ENTRY *ne; ++ if (!dpn || (dpn->type != 1)) ++ return 1; ++ frag = dpn->name.relativename; ++ dpn->dpname = X509_NAME_dup(iname); ++ if (!dpn->dpname) ++ return 0; ++ for (i = 0; i < sk_X509_NAME_ENTRY_num(frag); i++) { ++ ne = sk_X509_NAME_ENTRY_value(frag, i); ++ if (!X509_NAME_add_entry(dpn->dpname, ne, -1, i ? 0 : 1)) { ++ X509_NAME_free(dpn->dpname); ++ dpn->dpname = NULL; ++ return 0; ++ } ++ } ++ /* generate cached encoding of name */ ++ if (i2d_X509_NAME(dpn->dpname, NULL) < 0) { ++ X509_NAME_free(dpn->dpname); ++ dpn->dpname = NULL; ++ return 0; ++ } ++ return 1; ++} +diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/x509v3/v3_enum.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/x509v3/v3_enum.c +new file mode 100644 +index 0000000..f39cb5a +--- /dev/null ++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/x509v3/v3_enum.c +@@ -0,0 +1,53 @@ ++/* ++ * Copyright 1999-2016 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 ++ * in the file LICENSE in the source distribution or at ++ * https://www.openssl.org/source/license.html ++ */ ++ ++#include ++#include "internal/cryptlib.h" ++#include ++#include "ext_dat.h" ++ ++static ENUMERATED_NAMES crl_reasons[] = { ++ {CRL_REASON_UNSPECIFIED, "Unspecified", "unspecified"}, ++ {CRL_REASON_KEY_COMPROMISE, "Key Compromise", "keyCompromise"}, ++ {CRL_REASON_CA_COMPROMISE, "CA Compromise", "CACompromise"}, ++ {CRL_REASON_AFFILIATION_CHANGED, "Affiliation Changed", ++ "affiliationChanged"}, ++ {CRL_REASON_SUPERSEDED, "Superseded", "superseded"}, ++ {CRL_REASON_CESSATION_OF_OPERATION, ++ "Cessation Of Operation", "cessationOfOperation"}, ++ {CRL_REASON_CERTIFICATE_HOLD, "Certificate Hold", "certificateHold"}, ++ {CRL_REASON_REMOVE_FROM_CRL, "Remove From CRL", "removeFromCRL"}, ++ {CRL_REASON_PRIVILEGE_WITHDRAWN, "Privilege Withdrawn", ++ "privilegeWithdrawn"}, ++ {CRL_REASON_AA_COMPROMISE, "AA Compromise", "AACompromise"}, ++ {-1, NULL, NULL} ++}; ++ ++const X509V3_EXT_METHOD v3_crl_reason = { ++ NID_crl_reason, 0, ASN1_ITEM_ref(ASN1_ENUMERATED), ++ 0, 0, 0, 0, ++ (X509V3_EXT_I2S)i2s_ASN1_ENUMERATED_TABLE, ++ 0, ++ 0, 0, 0, 0, ++ crl_reasons ++}; ++ ++char *i2s_ASN1_ENUMERATED_TABLE(X509V3_EXT_METHOD *method, ++ const ASN1_ENUMERATED *e) ++{ ++ ENUMERATED_NAMES *enam; ++ long strval; ++ ++ strval = ASN1_ENUMERATED_get(e); ++ for (enam = method->usr_data; enam->lname; enam++) { ++ if (strval == enam->bitnum) ++ return OPENSSL_strdup(enam->lname); ++ } ++ return i2s_ASN1_ENUMERATED(method, e); ++} +diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/x509v3/v3_extku.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/x509v3/v3_extku.c +new file mode 100644 +index 0000000..bae755e +--- /dev/null ++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/x509v3/v3_extku.c +@@ -0,0 +1,100 @@ ++/* ++ * Copyright 1999-2016 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 ++ * in the file LICENSE in the source distribution or at ++ * https://www.openssl.org/source/license.html ++ */ ++ ++#include ++#include "internal/cryptlib.h" ++#include ++#include ++#include ++#include "ext_dat.h" ++ ++static void *v2i_EXTENDED_KEY_USAGE(const X509V3_EXT_METHOD *method, ++ X509V3_CTX *ctx, ++ STACK_OF(CONF_VALUE) *nval); ++static STACK_OF(CONF_VALUE) *i2v_EXTENDED_KEY_USAGE(const X509V3_EXT_METHOD ++ *method, void *eku, STACK_OF(CONF_VALUE) ++ *extlist); ++ ++const X509V3_EXT_METHOD v3_ext_ku = { ++ NID_ext_key_usage, 0, ++ ASN1_ITEM_ref(EXTENDED_KEY_USAGE), ++ 0, 0, 0, 0, ++ 0, 0, ++ i2v_EXTENDED_KEY_USAGE, ++ v2i_EXTENDED_KEY_USAGE, ++ 0, 0, ++ NULL ++}; ++ ++/* NB OCSP acceptable responses also is a SEQUENCE OF OBJECT */ ++const X509V3_EXT_METHOD v3_ocsp_accresp = { ++ NID_id_pkix_OCSP_acceptableResponses, 0, ++ ASN1_ITEM_ref(EXTENDED_KEY_USAGE), ++ 0, 0, 0, 0, ++ 0, 0, ++ i2v_EXTENDED_KEY_USAGE, ++ v2i_EXTENDED_KEY_USAGE, ++ 0, 0, ++ NULL ++}; ++ ++ASN1_ITEM_TEMPLATE(EXTENDED_KEY_USAGE) = ++ ASN1_EX_TEMPLATE_TYPE(ASN1_TFLG_SEQUENCE_OF, 0, EXTENDED_KEY_USAGE, ASN1_OBJECT) ++ASN1_ITEM_TEMPLATE_END(EXTENDED_KEY_USAGE) ++ ++IMPLEMENT_ASN1_FUNCTIONS(EXTENDED_KEY_USAGE) ++ ++static STACK_OF(CONF_VALUE) *i2v_EXTENDED_KEY_USAGE(const X509V3_EXT_METHOD ++ *method, void *a, STACK_OF(CONF_VALUE) ++ *ext_list) ++{ ++ EXTENDED_KEY_USAGE *eku = a; ++ int i; ++ ASN1_OBJECT *obj; ++ char obj_tmp[80]; ++ for (i = 0; i < sk_ASN1_OBJECT_num(eku); i++) { ++ obj = sk_ASN1_OBJECT_value(eku, i); ++ i2t_ASN1_OBJECT(obj_tmp, 80, obj); ++ X509V3_add_value(NULL, obj_tmp, &ext_list); ++ } ++ return ext_list; ++} ++ ++static void *v2i_EXTENDED_KEY_USAGE(const X509V3_EXT_METHOD *method, ++ X509V3_CTX *ctx, ++ STACK_OF(CONF_VALUE) *nval) ++{ ++ EXTENDED_KEY_USAGE *extku; ++ char *extval; ++ ASN1_OBJECT *objtmp; ++ CONF_VALUE *val; ++ int i; ++ ++ if ((extku = sk_ASN1_OBJECT_new_null()) == NULL) { ++ X509V3err(X509V3_F_V2I_EXTENDED_KEY_USAGE, ERR_R_MALLOC_FAILURE); ++ return NULL; ++ } ++ ++ for (i = 0; i < sk_CONF_VALUE_num(nval); i++) { ++ val = sk_CONF_VALUE_value(nval, i); ++ if (val->value) ++ extval = val->value; ++ else ++ extval = val->name; ++ if ((objtmp = OBJ_txt2obj(extval, 0)) == NULL) { ++ sk_ASN1_OBJECT_pop_free(extku, ASN1_OBJECT_free); ++ X509V3err(X509V3_F_V2I_EXTENDED_KEY_USAGE, ++ X509V3_R_INVALID_OBJECT_IDENTIFIER); ++ X509V3_conf_err(val); ++ return NULL; ++ } ++ sk_ASN1_OBJECT_push(extku, objtmp); ++ } ++ return extku; ++} +diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/x509v3/v3_genn.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/x509v3/v3_genn.c +new file mode 100644 +index 0000000..8d11997 +--- /dev/null ++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/x509v3/v3_genn.c +@@ -0,0 +1,200 @@ ++/* ++ * Copyright 1999-2016 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 ++ * in the file LICENSE in the source distribution or at ++ * https://www.openssl.org/source/license.html ++ */ ++ ++#include ++#include "internal/cryptlib.h" ++#include ++#include ++#include ++ ++ASN1_SEQUENCE(OTHERNAME) = { ++ ASN1_SIMPLE(OTHERNAME, type_id, ASN1_OBJECT), ++ /* Maybe have a true ANY DEFINED BY later */ ++ ASN1_EXP(OTHERNAME, value, ASN1_ANY, 0) ++} ASN1_SEQUENCE_END(OTHERNAME) ++ ++IMPLEMENT_ASN1_FUNCTIONS(OTHERNAME) ++ ++ASN1_SEQUENCE(EDIPARTYNAME) = { ++ ASN1_IMP_OPT(EDIPARTYNAME, nameAssigner, DIRECTORYSTRING, 0), ++ ASN1_IMP_OPT(EDIPARTYNAME, partyName, DIRECTORYSTRING, 1) ++} ASN1_SEQUENCE_END(EDIPARTYNAME) ++ ++IMPLEMENT_ASN1_FUNCTIONS(EDIPARTYNAME) ++ ++ASN1_CHOICE(GENERAL_NAME) = { ++ ASN1_IMP(GENERAL_NAME, d.otherName, OTHERNAME, GEN_OTHERNAME), ++ ASN1_IMP(GENERAL_NAME, d.rfc822Name, ASN1_IA5STRING, GEN_EMAIL), ++ ASN1_IMP(GENERAL_NAME, d.dNSName, ASN1_IA5STRING, GEN_DNS), ++ /* Don't decode this */ ++ ASN1_IMP(GENERAL_NAME, d.x400Address, ASN1_SEQUENCE, GEN_X400), ++ /* X509_NAME is a CHOICE type so use EXPLICIT */ ++ ASN1_EXP(GENERAL_NAME, d.directoryName, X509_NAME, GEN_DIRNAME), ++ ASN1_IMP(GENERAL_NAME, d.ediPartyName, EDIPARTYNAME, GEN_EDIPARTY), ++ ASN1_IMP(GENERAL_NAME, d.uniformResourceIdentifier, ASN1_IA5STRING, GEN_URI), ++ ASN1_IMP(GENERAL_NAME, d.iPAddress, ASN1_OCTET_STRING, GEN_IPADD), ++ ASN1_IMP(GENERAL_NAME, d.registeredID, ASN1_OBJECT, GEN_RID) ++} ASN1_CHOICE_END(GENERAL_NAME) ++ ++IMPLEMENT_ASN1_FUNCTIONS(GENERAL_NAME) ++ ++ASN1_ITEM_TEMPLATE(GENERAL_NAMES) = ++ ASN1_EX_TEMPLATE_TYPE(ASN1_TFLG_SEQUENCE_OF, 0, GeneralNames, GENERAL_NAME) ++ASN1_ITEM_TEMPLATE_END(GENERAL_NAMES) ++ ++IMPLEMENT_ASN1_FUNCTIONS(GENERAL_NAMES) ++ ++GENERAL_NAME *GENERAL_NAME_dup(GENERAL_NAME *a) ++{ ++ return (GENERAL_NAME *)ASN1_dup((i2d_of_void *)i2d_GENERAL_NAME, ++ (d2i_of_void *)d2i_GENERAL_NAME, ++ (char *)a); ++} ++ ++/* Returns 0 if they are equal, != 0 otherwise. */ ++int GENERAL_NAME_cmp(GENERAL_NAME *a, GENERAL_NAME *b) ++{ ++ int result = -1; ++ ++ if (!a || !b || a->type != b->type) ++ return -1; ++ switch (a->type) { ++ case GEN_X400: ++ case GEN_EDIPARTY: ++ result = ASN1_TYPE_cmp(a->d.other, b->d.other); ++ break; ++ ++ case GEN_OTHERNAME: ++ result = OTHERNAME_cmp(a->d.otherName, b->d.otherName); ++ break; ++ ++ case GEN_EMAIL: ++ case GEN_DNS: ++ case GEN_URI: ++ result = ASN1_STRING_cmp(a->d.ia5, b->d.ia5); ++ break; ++ ++ case GEN_DIRNAME: ++ result = X509_NAME_cmp(a->d.dirn, b->d.dirn); ++ break; ++ ++ case GEN_IPADD: ++ result = ASN1_OCTET_STRING_cmp(a->d.ip, b->d.ip); ++ break; ++ ++ case GEN_RID: ++ result = OBJ_cmp(a->d.rid, b->d.rid); ++ break; ++ } ++ return result; ++} ++ ++/* Returns 0 if they are equal, != 0 otherwise. */ ++int OTHERNAME_cmp(OTHERNAME *a, OTHERNAME *b) ++{ ++ int result = -1; ++ ++ if (!a || !b) ++ return -1; ++ /* Check their type first. */ ++ if ((result = OBJ_cmp(a->type_id, b->type_id)) != 0) ++ return result; ++ /* Check the value. */ ++ result = ASN1_TYPE_cmp(a->value, b->value); ++ return result; ++} ++ ++void GENERAL_NAME_set0_value(GENERAL_NAME *a, int type, void *value) ++{ ++ switch (type) { ++ case GEN_X400: ++ case GEN_EDIPARTY: ++ a->d.other = value; ++ break; ++ ++ case GEN_OTHERNAME: ++ a->d.otherName = value; ++ break; ++ ++ case GEN_EMAIL: ++ case GEN_DNS: ++ case GEN_URI: ++ a->d.ia5 = value; ++ break; ++ ++ case GEN_DIRNAME: ++ a->d.dirn = value; ++ break; ++ ++ case GEN_IPADD: ++ a->d.ip = value; ++ break; ++ ++ case GEN_RID: ++ a->d.rid = value; ++ break; ++ } ++ a->type = type; ++} ++ ++void *GENERAL_NAME_get0_value(GENERAL_NAME *a, int *ptype) ++{ ++ if (ptype) ++ *ptype = a->type; ++ switch (a->type) { ++ case GEN_X400: ++ case GEN_EDIPARTY: ++ return a->d.other; ++ ++ case GEN_OTHERNAME: ++ return a->d.otherName; ++ ++ case GEN_EMAIL: ++ case GEN_DNS: ++ case GEN_URI: ++ return a->d.ia5; ++ ++ case GEN_DIRNAME: ++ return a->d.dirn; ++ ++ case GEN_IPADD: ++ return a->d.ip; ++ ++ case GEN_RID: ++ return a->d.rid; ++ ++ default: ++ return NULL; ++ } ++} ++ ++int GENERAL_NAME_set0_othername(GENERAL_NAME *gen, ++ ASN1_OBJECT *oid, ASN1_TYPE *value) ++{ ++ OTHERNAME *oth; ++ oth = OTHERNAME_new(); ++ if (oth == NULL) ++ return 0; ++ oth->type_id = oid; ++ oth->value = value; ++ GENERAL_NAME_set0_value(gen, GEN_OTHERNAME, oth); ++ return 1; ++} ++ ++int GENERAL_NAME_get0_otherName(GENERAL_NAME *gen, ++ ASN1_OBJECT **poid, ASN1_TYPE **pvalue) ++{ ++ if (gen->type != GEN_OTHERNAME) ++ return 0; ++ if (poid) ++ *poid = gen->d.otherName->type_id; ++ if (pvalue) ++ *pvalue = gen->d.otherName->value; ++ return 1; ++} +diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/x509v3/v3_ia5.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/x509v3/v3_ia5.c +new file mode 100644 +index 0000000..c1170d4 +--- /dev/null ++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/x509v3/v3_ia5.c +@@ -0,0 +1,65 @@ ++/* ++ * Copyright 1999-2016 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 ++ * in the file LICENSE in the source distribution or at ++ * https://www.openssl.org/source/license.html ++ */ ++ ++#include ++#include "internal/cryptlib.h" ++#include ++#include ++#include ++#include "ext_dat.h" ++ ++const X509V3_EXT_METHOD v3_ns_ia5_list[8] = { ++ EXT_IA5STRING(NID_netscape_base_url), ++ EXT_IA5STRING(NID_netscape_revocation_url), ++ EXT_IA5STRING(NID_netscape_ca_revocation_url), ++ EXT_IA5STRING(NID_netscape_renewal_url), ++ EXT_IA5STRING(NID_netscape_ca_policy_url), ++ EXT_IA5STRING(NID_netscape_ssl_server_name), ++ EXT_IA5STRING(NID_netscape_comment), ++ EXT_END ++}; ++ ++char *i2s_ASN1_IA5STRING(X509V3_EXT_METHOD *method, ASN1_IA5STRING *ia5) ++{ ++ char *tmp; ++ ++ if (!ia5 || !ia5->length) ++ return NULL; ++ if ((tmp = OPENSSL_malloc(ia5->length + 1)) == NULL) { ++ X509V3err(X509V3_F_I2S_ASN1_IA5STRING, ERR_R_MALLOC_FAILURE); ++ return NULL; ++ } ++ memcpy(tmp, ia5->data, ia5->length); ++ tmp[ia5->length] = 0; ++ return tmp; ++} ++ ++ASN1_IA5STRING *s2i_ASN1_IA5STRING(X509V3_EXT_METHOD *method, ++ X509V3_CTX *ctx, const char *str) ++{ ++ ASN1_IA5STRING *ia5; ++ if (!str) { ++ X509V3err(X509V3_F_S2I_ASN1_IA5STRING, ++ X509V3_R_INVALID_NULL_ARGUMENT); ++ return NULL; ++ } ++ if ((ia5 = ASN1_IA5STRING_new()) == NULL) ++ goto err; ++ if (!ASN1_STRING_set((ASN1_STRING *)ia5, str, strlen(str))) { ++ ASN1_IA5STRING_free(ia5); ++ return NULL; ++ } ++#ifdef CHARSET_EBCDIC ++ ebcdic2ascii(ia5->data, ia5->data, ia5->length); ++#endif /* CHARSET_EBCDIC */ ++ return ia5; ++ err: ++ X509V3err(X509V3_F_S2I_ASN1_IA5STRING, ERR_R_MALLOC_FAILURE); ++ return NULL; ++} +diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/x509v3/v3_info.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/x509v3/v3_info.c +new file mode 100644 +index 0000000..61ef213 +--- /dev/null ++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/x509v3/v3_info.c +@@ -0,0 +1,157 @@ ++/* ++ * Copyright 1999-2016 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 ++ * in the file LICENSE in the source distribution or at ++ * https://www.openssl.org/source/license.html ++ */ ++ ++#include ++#include "internal/cryptlib.h" ++#include ++#include ++#include ++#include ++#include "ext_dat.h" ++ ++static STACK_OF(CONF_VALUE) *i2v_AUTHORITY_INFO_ACCESS(X509V3_EXT_METHOD ++ *method, AUTHORITY_INFO_ACCESS ++ *ainfo, STACK_OF(CONF_VALUE) ++ *ret); ++static AUTHORITY_INFO_ACCESS *v2i_AUTHORITY_INFO_ACCESS(X509V3_EXT_METHOD ++ *method, ++ X509V3_CTX *ctx, ++ STACK_OF(CONF_VALUE) ++ *nval); ++ ++const X509V3_EXT_METHOD v3_info = { NID_info_access, X509V3_EXT_MULTILINE, ++ ASN1_ITEM_ref(AUTHORITY_INFO_ACCESS), ++ 0, 0, 0, 0, ++ 0, 0, ++ (X509V3_EXT_I2V) i2v_AUTHORITY_INFO_ACCESS, ++ (X509V3_EXT_V2I)v2i_AUTHORITY_INFO_ACCESS, ++ 0, 0, ++ NULL ++}; ++ ++const X509V3_EXT_METHOD v3_sinfo = { NID_sinfo_access, X509V3_EXT_MULTILINE, ++ ASN1_ITEM_ref(AUTHORITY_INFO_ACCESS), ++ 0, 0, 0, 0, ++ 0, 0, ++ (X509V3_EXT_I2V) i2v_AUTHORITY_INFO_ACCESS, ++ (X509V3_EXT_V2I)v2i_AUTHORITY_INFO_ACCESS, ++ 0, 0, ++ NULL ++}; ++ ++ASN1_SEQUENCE(ACCESS_DESCRIPTION) = { ++ ASN1_SIMPLE(ACCESS_DESCRIPTION, method, ASN1_OBJECT), ++ ASN1_SIMPLE(ACCESS_DESCRIPTION, location, GENERAL_NAME) ++} ASN1_SEQUENCE_END(ACCESS_DESCRIPTION) ++ ++IMPLEMENT_ASN1_FUNCTIONS(ACCESS_DESCRIPTION) ++ ++ASN1_ITEM_TEMPLATE(AUTHORITY_INFO_ACCESS) = ++ ASN1_EX_TEMPLATE_TYPE(ASN1_TFLG_SEQUENCE_OF, 0, GeneralNames, ACCESS_DESCRIPTION) ++ASN1_ITEM_TEMPLATE_END(AUTHORITY_INFO_ACCESS) ++ ++IMPLEMENT_ASN1_FUNCTIONS(AUTHORITY_INFO_ACCESS) ++ ++static STACK_OF(CONF_VALUE) *i2v_AUTHORITY_INFO_ACCESS(X509V3_EXT_METHOD ++ *method, AUTHORITY_INFO_ACCESS ++ *ainfo, STACK_OF(CONF_VALUE) ++ *ret) ++{ ++ ACCESS_DESCRIPTION *desc; ++ int i, nlen; ++ char objtmp[80], *ntmp; ++ CONF_VALUE *vtmp; ++ for (i = 0; i < sk_ACCESS_DESCRIPTION_num(ainfo); i++) { ++ desc = sk_ACCESS_DESCRIPTION_value(ainfo, i); ++ ret = i2v_GENERAL_NAME(method, desc->location, ret); ++ if (!ret) ++ break; ++ vtmp = sk_CONF_VALUE_value(ret, i); ++ i2t_ASN1_OBJECT(objtmp, sizeof objtmp, desc->method); ++ nlen = strlen(objtmp) + strlen(vtmp->name) + 5; ++ ntmp = OPENSSL_malloc(nlen); ++ if (ntmp == NULL) { ++ X509V3err(X509V3_F_I2V_AUTHORITY_INFO_ACCESS, ++ ERR_R_MALLOC_FAILURE); ++ return NULL; ++ } ++ OPENSSL_strlcpy(ntmp, objtmp, nlen); ++ OPENSSL_strlcat(ntmp, " - ", nlen); ++ OPENSSL_strlcat(ntmp, vtmp->name, nlen); ++ OPENSSL_free(vtmp->name); ++ vtmp->name = ntmp; ++ ++ } ++ if (!ret) ++ return sk_CONF_VALUE_new_null(); ++ return ret; ++} ++ ++static AUTHORITY_INFO_ACCESS *v2i_AUTHORITY_INFO_ACCESS(X509V3_EXT_METHOD ++ *method, ++ X509V3_CTX *ctx, ++ STACK_OF(CONF_VALUE) ++ *nval) ++{ ++ AUTHORITY_INFO_ACCESS *ainfo = NULL; ++ CONF_VALUE *cnf, ctmp; ++ ACCESS_DESCRIPTION *acc; ++ int i, objlen; ++ char *objtmp, *ptmp; ++ ++ if ((ainfo = sk_ACCESS_DESCRIPTION_new_null()) == NULL) { ++ X509V3err(X509V3_F_V2I_AUTHORITY_INFO_ACCESS, ERR_R_MALLOC_FAILURE); ++ return NULL; ++ } ++ for (i = 0; i < sk_CONF_VALUE_num(nval); i++) { ++ cnf = sk_CONF_VALUE_value(nval, i); ++ if ((acc = ACCESS_DESCRIPTION_new()) == NULL ++ || !sk_ACCESS_DESCRIPTION_push(ainfo, acc)) { ++ X509V3err(X509V3_F_V2I_AUTHORITY_INFO_ACCESS, ++ ERR_R_MALLOC_FAILURE); ++ goto err; ++ } ++ ptmp = strchr(cnf->name, ';'); ++ if (!ptmp) { ++ X509V3err(X509V3_F_V2I_AUTHORITY_INFO_ACCESS, ++ X509V3_R_INVALID_SYNTAX); ++ goto err; ++ } ++ objlen = ptmp - cnf->name; ++ ctmp.name = ptmp + 1; ++ ctmp.value = cnf->value; ++ if (!v2i_GENERAL_NAME_ex(acc->location, method, ctx, &ctmp, 0)) ++ goto err; ++ if ((objtmp = OPENSSL_strndup(cnf->name, objlen)) == NULL) { ++ X509V3err(X509V3_F_V2I_AUTHORITY_INFO_ACCESS, ++ ERR_R_MALLOC_FAILURE); ++ goto err; ++ } ++ acc->method = OBJ_txt2obj(objtmp, 0); ++ if (!acc->method) { ++ X509V3err(X509V3_F_V2I_AUTHORITY_INFO_ACCESS, ++ X509V3_R_BAD_OBJECT); ++ ERR_add_error_data(2, "value=", objtmp); ++ OPENSSL_free(objtmp); ++ goto err; ++ } ++ OPENSSL_free(objtmp); ++ ++ } ++ return ainfo; ++ err: ++ sk_ACCESS_DESCRIPTION_pop_free(ainfo, ACCESS_DESCRIPTION_free); ++ return NULL; ++} ++ ++int i2a_ACCESS_DESCRIPTION(BIO *bp, const ACCESS_DESCRIPTION *a) ++{ ++ i2a_ASN1_OBJECT(bp, a->method); ++ return 2; ++} +diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/x509v3/v3_int.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/x509v3/v3_int.c +new file mode 100644 +index 0000000..690c90e +--- /dev/null ++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/x509v3/v3_int.c +@@ -0,0 +1,43 @@ ++/* ++ * Copyright 1999-2016 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 ++ * in the file LICENSE in the source distribution or at ++ * https://www.openssl.org/source/license.html ++ */ ++ ++#include ++#include "internal/cryptlib.h" ++#include ++#include "ext_dat.h" ++ ++const X509V3_EXT_METHOD v3_crl_num = { ++ NID_crl_number, 0, ASN1_ITEM_ref(ASN1_INTEGER), ++ 0, 0, 0, 0, ++ (X509V3_EXT_I2S)i2s_ASN1_INTEGER, ++ 0, ++ 0, 0, 0, 0, NULL ++}; ++ ++const X509V3_EXT_METHOD v3_delta_crl = { ++ NID_delta_crl, 0, ASN1_ITEM_ref(ASN1_INTEGER), ++ 0, 0, 0, 0, ++ (X509V3_EXT_I2S)i2s_ASN1_INTEGER, ++ 0, ++ 0, 0, 0, 0, NULL ++}; ++ ++static void *s2i_asn1_int(X509V3_EXT_METHOD *meth, X509V3_CTX *ctx, ++ const char *value) ++{ ++ return s2i_ASN1_INTEGER(meth, value); ++} ++ ++const X509V3_EXT_METHOD v3_inhibit_anyp = { ++ NID_inhibit_any_policy, 0, ASN1_ITEM_ref(ASN1_INTEGER), ++ 0, 0, 0, 0, ++ (X509V3_EXT_I2S)i2s_ASN1_INTEGER, ++ (X509V3_EXT_S2I)s2i_asn1_int, ++ 0, 0, 0, 0, NULL ++}; +diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/x509v3/v3_lib.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/x509v3/v3_lib.c +new file mode 100644 +index 0000000..a3ca720 +--- /dev/null ++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/x509v3/v3_lib.c +@@ -0,0 +1,360 @@ ++/* ++ * Copyright 1999-2016 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 ++ * in the file LICENSE in the source distribution or at ++ * https://www.openssl.org/source/license.html ++ */ ++ ++/* X509 v3 extension utilities */ ++ ++#include ++#include "internal/cryptlib.h" ++#include ++#include ++ ++#include "ext_dat.h" ++ ++static STACK_OF(X509V3_EXT_METHOD) *ext_list = NULL; ++ ++static int ext_cmp(const X509V3_EXT_METHOD *const *a, ++ const X509V3_EXT_METHOD *const *b); ++static void ext_list_free(X509V3_EXT_METHOD *ext); ++ ++int X509V3_EXT_add(X509V3_EXT_METHOD *ext) ++{ ++ if (ext_list == NULL ++ && (ext_list = sk_X509V3_EXT_METHOD_new(ext_cmp)) == NULL) { ++ X509V3err(X509V3_F_X509V3_EXT_ADD, ERR_R_MALLOC_FAILURE); ++ return 0; ++ } ++ if (!sk_X509V3_EXT_METHOD_push(ext_list, ext)) { ++ X509V3err(X509V3_F_X509V3_EXT_ADD, ERR_R_MALLOC_FAILURE); ++ return 0; ++ } ++ return 1; ++} ++ ++static int ext_cmp(const X509V3_EXT_METHOD *const *a, ++ const X509V3_EXT_METHOD *const *b) ++{ ++ return ((*a)->ext_nid - (*b)->ext_nid); ++} ++ ++DECLARE_OBJ_BSEARCH_CMP_FN(const X509V3_EXT_METHOD *, ++ const X509V3_EXT_METHOD *, ext); ++IMPLEMENT_OBJ_BSEARCH_CMP_FN(const X509V3_EXT_METHOD *, ++ const X509V3_EXT_METHOD *, ext); ++ ++/* ++ * This table will be searched using OBJ_bsearch so it *must* kept in order ++ * of the ext_nid values. ++ */ ++ ++static const X509V3_EXT_METHOD *standard_exts[] = { ++ &v3_nscert, ++ &v3_ns_ia5_list[0], ++ &v3_ns_ia5_list[1], ++ &v3_ns_ia5_list[2], ++ &v3_ns_ia5_list[3], ++ &v3_ns_ia5_list[4], ++ &v3_ns_ia5_list[5], ++ &v3_ns_ia5_list[6], ++ &v3_skey_id, ++ &v3_key_usage, ++ &v3_pkey_usage_period, ++ &v3_alt[0], ++ &v3_alt[1], ++ &v3_bcons, ++ &v3_crl_num, ++ &v3_cpols, ++ &v3_akey_id, ++ &v3_crld, ++ &v3_ext_ku, ++ &v3_delta_crl, ++ &v3_crl_reason, ++#ifndef OPENSSL_NO_OCSP ++ &v3_crl_invdate, ++#endif ++ &v3_sxnet, ++ &v3_info, ++#ifndef OPENSSL_NO_RFC3779 ++ &v3_addr, ++ &v3_asid, ++#endif ++#ifndef OPENSSL_NO_OCSP ++ &v3_ocsp_nonce, ++ &v3_ocsp_crlid, ++ &v3_ocsp_accresp, ++ &v3_ocsp_nocheck, ++ &v3_ocsp_acutoff, ++ &v3_ocsp_serviceloc, ++#endif ++ &v3_sinfo, ++ &v3_policy_constraints, ++#ifndef OPENSSL_NO_OCSP ++ &v3_crl_hold, ++#endif ++ &v3_pci, ++ &v3_name_constraints, ++ &v3_policy_mappings, ++ &v3_inhibit_anyp, ++ &v3_idp, ++ &v3_alt[2], ++ &v3_freshest_crl, ++#ifndef OPENSSL_NO_CT ++ &v3_ct_scts[0], ++ &v3_ct_scts[1], ++ &v3_ct_scts[2], ++#endif ++ &v3_tls_feature, ++}; ++ ++/* Number of standard extensions */ ++ ++#define STANDARD_EXTENSION_COUNT OSSL_NELEM(standard_exts) ++ ++const X509V3_EXT_METHOD *X509V3_EXT_get_nid(int nid) ++{ ++ X509V3_EXT_METHOD tmp; ++ const X509V3_EXT_METHOD *t = &tmp, *const *ret; ++ int idx; ++ if (nid < 0) ++ return NULL; ++ tmp.ext_nid = nid; ++ ret = OBJ_bsearch_ext(&t, standard_exts, STANDARD_EXTENSION_COUNT); ++ if (ret) ++ return *ret; ++ if (!ext_list) ++ return NULL; ++ idx = sk_X509V3_EXT_METHOD_find(ext_list, &tmp); ++ if (idx == -1) ++ return NULL; ++ return sk_X509V3_EXT_METHOD_value(ext_list, idx); ++} ++ ++const X509V3_EXT_METHOD *X509V3_EXT_get(X509_EXTENSION *ext) ++{ ++ int nid; ++ if ((nid = OBJ_obj2nid(X509_EXTENSION_get_object(ext))) == NID_undef) ++ return NULL; ++ return X509V3_EXT_get_nid(nid); ++} ++ ++int X509V3_EXT_add_list(X509V3_EXT_METHOD *extlist) ++{ ++ for (; extlist->ext_nid != -1; extlist++) ++ if (!X509V3_EXT_add(extlist)) ++ return 0; ++ return 1; ++} ++ ++int X509V3_EXT_add_alias(int nid_to, int nid_from) ++{ ++ const X509V3_EXT_METHOD *ext; ++ X509V3_EXT_METHOD *tmpext; ++ ++ if ((ext = X509V3_EXT_get_nid(nid_from)) == NULL) { ++ X509V3err(X509V3_F_X509V3_EXT_ADD_ALIAS, X509V3_R_EXTENSION_NOT_FOUND); ++ return 0; ++ } ++ if ((tmpext = OPENSSL_malloc(sizeof(*tmpext))) == NULL) { ++ X509V3err(X509V3_F_X509V3_EXT_ADD_ALIAS, ERR_R_MALLOC_FAILURE); ++ return 0; ++ } ++ *tmpext = *ext; ++ tmpext->ext_nid = nid_to; ++ tmpext->ext_flags |= X509V3_EXT_DYNAMIC; ++ return X509V3_EXT_add(tmpext); ++} ++ ++void X509V3_EXT_cleanup(void) ++{ ++ sk_X509V3_EXT_METHOD_pop_free(ext_list, ext_list_free); ++ ext_list = NULL; ++} ++ ++static void ext_list_free(X509V3_EXT_METHOD *ext) ++{ ++ if (ext->ext_flags & X509V3_EXT_DYNAMIC) ++ OPENSSL_free(ext); ++} ++ ++/* ++ * Legacy function: we don't need to add standard extensions any more because ++ * they are now kept in ext_dat.h. ++ */ ++ ++int X509V3_add_standard_extensions(void) ++{ ++ return 1; ++} ++ ++/* Return an extension internal structure */ ++ ++void *X509V3_EXT_d2i(X509_EXTENSION *ext) ++{ ++ const X509V3_EXT_METHOD *method; ++ const unsigned char *p; ++ ASN1_STRING *extvalue; ++ int extlen; ++ ++ if ((method = X509V3_EXT_get(ext)) == NULL) ++ return NULL; ++ extvalue = X509_EXTENSION_get_data(ext); ++ p = ASN1_STRING_get0_data(extvalue); ++ extlen = ASN1_STRING_length(extvalue); ++ if (method->it) ++ return ASN1_item_d2i(NULL, &p, extlen, ASN1_ITEM_ptr(method->it)); ++ return method->d2i(NULL, &p, extlen); ++} ++ ++/*- ++ * Get critical flag and decoded version of extension from a NID. ++ * The "idx" variable returns the last found extension and can ++ * be used to retrieve multiple extensions of the same NID. ++ * However multiple extensions with the same NID is usually ++ * due to a badly encoded certificate so if idx is NULL we ++ * choke if multiple extensions exist. ++ * The "crit" variable is set to the critical value. ++ * The return value is the decoded extension or NULL on ++ * error. The actual error can have several different causes, ++ * the value of *crit reflects the cause: ++ * >= 0, extension found but not decoded (reflects critical value). ++ * -1 extension not found. ++ * -2 extension occurs more than once. ++ */ ++ ++void *X509V3_get_d2i(const STACK_OF(X509_EXTENSION) *x, int nid, int *crit, ++ int *idx) ++{ ++ int lastpos, i; ++ X509_EXTENSION *ex, *found_ex = NULL; ++ if (!x) { ++ if (idx) ++ *idx = -1; ++ if (crit) ++ *crit = -1; ++ return NULL; ++ } ++ if (idx) ++ lastpos = *idx + 1; ++ else ++ lastpos = 0; ++ if (lastpos < 0) ++ lastpos = 0; ++ for (i = lastpos; i < sk_X509_EXTENSION_num(x); i++) { ++ ex = sk_X509_EXTENSION_value(x, i); ++ if (OBJ_obj2nid(X509_EXTENSION_get_object(ex)) == nid) { ++ if (idx) { ++ *idx = i; ++ found_ex = ex; ++ break; ++ } else if (found_ex) { ++ /* Found more than one */ ++ if (crit) ++ *crit = -2; ++ return NULL; ++ } ++ found_ex = ex; ++ } ++ } ++ if (found_ex) { ++ /* Found it */ ++ if (crit) ++ *crit = X509_EXTENSION_get_critical(found_ex); ++ return X509V3_EXT_d2i(found_ex); ++ } ++ ++ /* Extension not found */ ++ if (idx) ++ *idx = -1; ++ if (crit) ++ *crit = -1; ++ return NULL; ++} ++ ++/* ++ * This function is a general extension append, replace and delete utility. ++ * The precise operation is governed by the 'flags' value. The 'crit' and ++ * 'value' arguments (if relevant) are the extensions internal structure. ++ */ ++ ++int X509V3_add1_i2d(STACK_OF(X509_EXTENSION) **x, int nid, void *value, ++ int crit, unsigned long flags) ++{ ++ int extidx = -1; ++ int errcode; ++ X509_EXTENSION *ext, *extmp; ++ unsigned long ext_op = flags & X509V3_ADD_OP_MASK; ++ ++ /* ++ * If appending we don't care if it exists, otherwise look for existing ++ * extension. ++ */ ++ if (ext_op != X509V3_ADD_APPEND) ++ extidx = X509v3_get_ext_by_NID(*x, nid, -1); ++ ++ /* See if extension exists */ ++ if (extidx >= 0) { ++ /* If keep existing, nothing to do */ ++ if (ext_op == X509V3_ADD_KEEP_EXISTING) ++ return 1; ++ /* If default then its an error */ ++ if (ext_op == X509V3_ADD_DEFAULT) { ++ errcode = X509V3_R_EXTENSION_EXISTS; ++ goto err; ++ } ++ /* If delete, just delete it */ ++ if (ext_op == X509V3_ADD_DELETE) { ++ if (!sk_X509_EXTENSION_delete(*x, extidx)) ++ return -1; ++ return 1; ++ } ++ } else { ++ /* ++ * If replace existing or delete, error since extension must exist ++ */ ++ if ((ext_op == X509V3_ADD_REPLACE_EXISTING) || ++ (ext_op == X509V3_ADD_DELETE)) { ++ errcode = X509V3_R_EXTENSION_NOT_FOUND; ++ goto err; ++ } ++ } ++ ++ /* ++ * If we get this far then we have to create an extension: could have ++ * some flags for alternative encoding schemes... ++ */ ++ ++ ext = X509V3_EXT_i2d(nid, crit, value); ++ ++ if (!ext) { ++ X509V3err(X509V3_F_X509V3_ADD1_I2D, ++ X509V3_R_ERROR_CREATING_EXTENSION); ++ return 0; ++ } ++ ++ /* If extension exists replace it.. */ ++ if (extidx >= 0) { ++ extmp = sk_X509_EXTENSION_value(*x, extidx); ++ X509_EXTENSION_free(extmp); ++ if (!sk_X509_EXTENSION_set(*x, extidx, ext)) ++ return -1; ++ return 1; ++ } ++ ++ if (*x == NULL ++ && (*x = sk_X509_EXTENSION_new_null()) == NULL) ++ return -1; ++ if (!sk_X509_EXTENSION_push(*x, ext)) ++ return -1; ++ ++ return 1; ++ ++ err: ++ if (!(flags & X509V3_ADD_SILENT)) ++ X509V3err(X509V3_F_X509V3_ADD1_I2D, errcode); ++ return 0; ++} +diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/x509v3/v3_ncons.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/x509v3/v3_ncons.c +new file mode 100644 +index 0000000..9b3bb12 +--- /dev/null ++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/x509v3/v3_ncons.c +@@ -0,0 +1,513 @@ ++/* ++ * Copyright 2003-2016 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 ++ * in the file LICENSE in the source distribution or at ++ * https://www.openssl.org/source/license.html ++ */ ++ ++#include ++#include "internal/cryptlib.h" ++#include "internal/asn1_int.h" ++#include ++#include ++#include ++ ++#include "internal/x509_int.h" ++#include "ext_dat.h" ++ ++static void *v2i_NAME_CONSTRAINTS(const X509V3_EXT_METHOD *method, ++ X509V3_CTX *ctx, ++ STACK_OF(CONF_VALUE) *nval); ++static int i2r_NAME_CONSTRAINTS(const X509V3_EXT_METHOD *method, void *a, ++ BIO *bp, int ind); ++static int do_i2r_name_constraints(const X509V3_EXT_METHOD *method, ++ STACK_OF(GENERAL_SUBTREE) *trees, BIO *bp, ++ int ind, const char *name); ++static int print_nc_ipadd(BIO *bp, ASN1_OCTET_STRING *ip); ++ ++static int nc_match(GENERAL_NAME *gen, NAME_CONSTRAINTS *nc); ++static int nc_match_single(GENERAL_NAME *sub, GENERAL_NAME *gen); ++static int nc_dn(X509_NAME *sub, X509_NAME *nm); ++static int nc_dns(ASN1_IA5STRING *sub, ASN1_IA5STRING *dns); ++static int nc_email(ASN1_IA5STRING *sub, ASN1_IA5STRING *eml); ++static int nc_uri(ASN1_IA5STRING *uri, ASN1_IA5STRING *base); ++static int nc_ip(ASN1_OCTET_STRING *ip, ASN1_OCTET_STRING *base); ++ ++const X509V3_EXT_METHOD v3_name_constraints = { ++ NID_name_constraints, 0, ++ ASN1_ITEM_ref(NAME_CONSTRAINTS), ++ 0, 0, 0, 0, ++ 0, 0, ++ 0, v2i_NAME_CONSTRAINTS, ++ i2r_NAME_CONSTRAINTS, 0, ++ NULL ++}; ++ ++ASN1_SEQUENCE(GENERAL_SUBTREE) = { ++ ASN1_SIMPLE(GENERAL_SUBTREE, base, GENERAL_NAME), ++ ASN1_IMP_OPT(GENERAL_SUBTREE, minimum, ASN1_INTEGER, 0), ++ ASN1_IMP_OPT(GENERAL_SUBTREE, maximum, ASN1_INTEGER, 1) ++} ASN1_SEQUENCE_END(GENERAL_SUBTREE) ++ ++ASN1_SEQUENCE(NAME_CONSTRAINTS) = { ++ ASN1_IMP_SEQUENCE_OF_OPT(NAME_CONSTRAINTS, permittedSubtrees, ++ GENERAL_SUBTREE, 0), ++ ASN1_IMP_SEQUENCE_OF_OPT(NAME_CONSTRAINTS, excludedSubtrees, ++ GENERAL_SUBTREE, 1), ++} ASN1_SEQUENCE_END(NAME_CONSTRAINTS) ++ ++ ++IMPLEMENT_ASN1_ALLOC_FUNCTIONS(GENERAL_SUBTREE) ++IMPLEMENT_ASN1_ALLOC_FUNCTIONS(NAME_CONSTRAINTS) ++ ++static void *v2i_NAME_CONSTRAINTS(const X509V3_EXT_METHOD *method, ++ X509V3_CTX *ctx, STACK_OF(CONF_VALUE) *nval) ++{ ++ int i; ++ CONF_VALUE tval, *val; ++ STACK_OF(GENERAL_SUBTREE) **ptree = NULL; ++ NAME_CONSTRAINTS *ncons = NULL; ++ GENERAL_SUBTREE *sub = NULL; ++ ++ ncons = NAME_CONSTRAINTS_new(); ++ if (ncons == NULL) ++ goto memerr; ++ for (i = 0; i < sk_CONF_VALUE_num(nval); i++) { ++ val = sk_CONF_VALUE_value(nval, i); ++ if (strncmp(val->name, "permitted", 9) == 0 && val->name[9]) { ++ ptree = &ncons->permittedSubtrees; ++ tval.name = val->name + 10; ++ } else if (strncmp(val->name, "excluded", 8) == 0 && val->name[8]) { ++ ptree = &ncons->excludedSubtrees; ++ tval.name = val->name + 9; ++ } else { ++ X509V3err(X509V3_F_V2I_NAME_CONSTRAINTS, X509V3_R_INVALID_SYNTAX); ++ goto err; ++ } ++ tval.value = val->value; ++ sub = GENERAL_SUBTREE_new(); ++ if (sub == NULL) ++ goto memerr; ++ if (!v2i_GENERAL_NAME_ex(sub->base, method, ctx, &tval, 1)) ++ goto err; ++ if (*ptree == NULL) ++ *ptree = sk_GENERAL_SUBTREE_new_null(); ++ if (*ptree == NULL || !sk_GENERAL_SUBTREE_push(*ptree, sub)) ++ goto memerr; ++ sub = NULL; ++ } ++ ++ return ncons; ++ ++ memerr: ++ X509V3err(X509V3_F_V2I_NAME_CONSTRAINTS, ERR_R_MALLOC_FAILURE); ++ err: ++ NAME_CONSTRAINTS_free(ncons); ++ GENERAL_SUBTREE_free(sub); ++ ++ return NULL; ++} ++ ++static int i2r_NAME_CONSTRAINTS(const X509V3_EXT_METHOD *method, void *a, ++ BIO *bp, int ind) ++{ ++ NAME_CONSTRAINTS *ncons = a; ++ do_i2r_name_constraints(method, ncons->permittedSubtrees, ++ bp, ind, "Permitted"); ++ do_i2r_name_constraints(method, ncons->excludedSubtrees, ++ bp, ind, "Excluded"); ++ return 1; ++} ++ ++static int do_i2r_name_constraints(const X509V3_EXT_METHOD *method, ++ STACK_OF(GENERAL_SUBTREE) *trees, ++ BIO *bp, int ind, const char *name) ++{ ++ GENERAL_SUBTREE *tree; ++ int i; ++ if (sk_GENERAL_SUBTREE_num(trees) > 0) ++ BIO_printf(bp, "%*s%s:\n", ind, "", name); ++ for (i = 0; i < sk_GENERAL_SUBTREE_num(trees); i++) { ++ tree = sk_GENERAL_SUBTREE_value(trees, i); ++ BIO_printf(bp, "%*s", ind + 2, ""); ++ if (tree->base->type == GEN_IPADD) ++ print_nc_ipadd(bp, tree->base->d.ip); ++ else ++ GENERAL_NAME_print(bp, tree->base); ++ BIO_puts(bp, "\n"); ++ } ++ return 1; ++} ++ ++static int print_nc_ipadd(BIO *bp, ASN1_OCTET_STRING *ip) ++{ ++ int i, len; ++ unsigned char *p; ++ p = ip->data; ++ len = ip->length; ++ BIO_puts(bp, "IP:"); ++ if (len == 8) { ++ BIO_printf(bp, "%d.%d.%d.%d/%d.%d.%d.%d", ++ p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7]); ++ } else if (len == 32) { ++ for (i = 0; i < 16; i++) { ++ BIO_printf(bp, "%X", p[0] << 8 | p[1]); ++ p += 2; ++ if (i == 7) ++ BIO_puts(bp, "/"); ++ else if (i != 15) ++ BIO_puts(bp, ":"); ++ } ++ } else ++ BIO_printf(bp, "IP Address:"); ++ return 1; ++} ++ ++/*- ++ * Check a certificate conforms to a specified set of constraints. ++ * Return values: ++ * X509_V_OK: All constraints obeyed. ++ * X509_V_ERR_PERMITTED_VIOLATION: Permitted subtree violation. ++ * X509_V_ERR_EXCLUDED_VIOLATION: Excluded subtree violation. ++ * X509_V_ERR_SUBTREE_MINMAX: Min or max values present and matching type. ++ * X509_V_ERR_UNSUPPORTED_CONSTRAINT_TYPE: Unsupported constraint type. ++ * X509_V_ERR_UNSUPPORTED_CONSTRAINT_SYNTAX: bad unsupported constraint syntax. ++ * X509_V_ERR_UNSUPPORTED_NAME_SYNTAX: bad or unsupported syntax of name ++ */ ++ ++int NAME_CONSTRAINTS_check(X509 *x, NAME_CONSTRAINTS *nc) ++{ ++ int r, i; ++ X509_NAME *nm; ++ ++ nm = X509_get_subject_name(x); ++ ++ if (X509_NAME_entry_count(nm) > 0) { ++ GENERAL_NAME gntmp; ++ gntmp.type = GEN_DIRNAME; ++ gntmp.d.directoryName = nm; ++ ++ r = nc_match(&gntmp, nc); ++ ++ if (r != X509_V_OK) ++ return r; ++ ++ gntmp.type = GEN_EMAIL; ++ ++ /* Process any email address attributes in subject name */ ++ ++ for (i = -1;;) { ++ const X509_NAME_ENTRY *ne; ++ ++ i = X509_NAME_get_index_by_NID(nm, NID_pkcs9_emailAddress, i); ++ if (i == -1) ++ break; ++ ne = X509_NAME_get_entry(nm, i); ++ gntmp.d.rfc822Name = X509_NAME_ENTRY_get_data(ne); ++ if (gntmp.d.rfc822Name->type != V_ASN1_IA5STRING) ++ return X509_V_ERR_UNSUPPORTED_NAME_SYNTAX; ++ ++ r = nc_match(&gntmp, nc); ++ ++ if (r != X509_V_OK) ++ return r; ++ } ++ ++ } ++ ++ for (i = 0; i < sk_GENERAL_NAME_num(x->altname); i++) { ++ GENERAL_NAME *gen = sk_GENERAL_NAME_value(x->altname, i); ++ r = nc_match(gen, nc); ++ if (r != X509_V_OK) ++ return r; ++ } ++ ++ return X509_V_OK; ++ ++} ++ ++int NAME_CONSTRAINTS_check_CN(X509 *x, NAME_CONSTRAINTS *nc) ++{ ++ int r, i; ++ X509_NAME *nm; ++ ++ ASN1_STRING stmp; ++ GENERAL_NAME gntmp; ++ stmp.flags = 0; ++ stmp.type = V_ASN1_IA5STRING; ++ gntmp.type = GEN_DNS; ++ gntmp.d.dNSName = &stmp; ++ ++ nm = X509_get_subject_name(x); ++ ++ /* Process any commonName attributes in subject name */ ++ ++ for (i = -1;;) { ++ X509_NAME_ENTRY *ne; ++ ASN1_STRING *hn; ++ i = X509_NAME_get_index_by_NID(nm, NID_commonName, i); ++ if (i == -1) ++ break; ++ ne = X509_NAME_get_entry(nm, i); ++ hn = X509_NAME_ENTRY_get_data(ne); ++ /* Only process attributes that look like host names */ ++ if (asn1_valid_host(hn)) { ++ unsigned char *h; ++ int hlen = ASN1_STRING_to_UTF8(&h, hn); ++ if (hlen <= 0) ++ return X509_V_ERR_OUT_OF_MEM; ++ ++ stmp.length = hlen; ++ stmp.data = h; ++ ++ r = nc_match(&gntmp, nc); ++ ++ OPENSSL_free(h); ++ ++ if (r != X509_V_OK) ++ return r; ++ } ++ } ++ return X509_V_OK; ++} ++ ++static int nc_match(GENERAL_NAME *gen, NAME_CONSTRAINTS *nc) ++{ ++ GENERAL_SUBTREE *sub; ++ int i, r, match = 0; ++ ++ /* ++ * Permitted subtrees: if any subtrees exist of matching the type at ++ * least one subtree must match. ++ */ ++ ++ for (i = 0; i < sk_GENERAL_SUBTREE_num(nc->permittedSubtrees); i++) { ++ sub = sk_GENERAL_SUBTREE_value(nc->permittedSubtrees, i); ++ if (gen->type != sub->base->type) ++ continue; ++ if (sub->minimum || sub->maximum) ++ return X509_V_ERR_SUBTREE_MINMAX; ++ /* If we already have a match don't bother trying any more */ ++ if (match == 2) ++ continue; ++ if (match == 0) ++ match = 1; ++ r = nc_match_single(gen, sub->base); ++ if (r == X509_V_OK) ++ match = 2; ++ else if (r != X509_V_ERR_PERMITTED_VIOLATION) ++ return r; ++ } ++ ++ if (match == 1) ++ return X509_V_ERR_PERMITTED_VIOLATION; ++ ++ /* Excluded subtrees: must not match any of these */ ++ ++ for (i = 0; i < sk_GENERAL_SUBTREE_num(nc->excludedSubtrees); i++) { ++ sub = sk_GENERAL_SUBTREE_value(nc->excludedSubtrees, i); ++ if (gen->type != sub->base->type) ++ continue; ++ if (sub->minimum || sub->maximum) ++ return X509_V_ERR_SUBTREE_MINMAX; ++ ++ r = nc_match_single(gen, sub->base); ++ if (r == X509_V_OK) ++ return X509_V_ERR_EXCLUDED_VIOLATION; ++ else if (r != X509_V_ERR_PERMITTED_VIOLATION) ++ return r; ++ ++ } ++ ++ return X509_V_OK; ++ ++} ++ ++static int nc_match_single(GENERAL_NAME *gen, GENERAL_NAME *base) ++{ ++ switch (base->type) { ++ case GEN_DIRNAME: ++ return nc_dn(gen->d.directoryName, base->d.directoryName); ++ ++ case GEN_DNS: ++ return nc_dns(gen->d.dNSName, base->d.dNSName); ++ ++ case GEN_EMAIL: ++ return nc_email(gen->d.rfc822Name, base->d.rfc822Name); ++ ++ case GEN_URI: ++ return nc_uri(gen->d.uniformResourceIdentifier, ++ base->d.uniformResourceIdentifier); ++ ++ case GEN_IPADD: ++ return nc_ip(gen->d.iPAddress, base->d.iPAddress); ++ ++ default: ++ return X509_V_ERR_UNSUPPORTED_CONSTRAINT_TYPE; ++ } ++ ++} ++ ++/* ++ * directoryName name constraint matching. The canonical encoding of ++ * X509_NAME makes this comparison easy. It is matched if the subtree is a ++ * subset of the name. ++ */ ++ ++static int nc_dn(X509_NAME *nm, X509_NAME *base) ++{ ++ /* Ensure canonical encodings are up to date. */ ++ if (nm->modified && i2d_X509_NAME(nm, NULL) < 0) ++ return X509_V_ERR_OUT_OF_MEM; ++ if (base->modified && i2d_X509_NAME(base, NULL) < 0) ++ return X509_V_ERR_OUT_OF_MEM; ++ if (base->canon_enclen > nm->canon_enclen) ++ return X509_V_ERR_PERMITTED_VIOLATION; ++ if (memcmp(base->canon_enc, nm->canon_enc, base->canon_enclen)) ++ return X509_V_ERR_PERMITTED_VIOLATION; ++ return X509_V_OK; ++} ++ ++static int nc_dns(ASN1_IA5STRING *dns, ASN1_IA5STRING *base) ++{ ++ char *baseptr = (char *)base->data; ++ char *dnsptr = (char *)dns->data; ++ /* Empty matches everything */ ++ if (!*baseptr) ++ return X509_V_OK; ++ /* ++ * Otherwise can add zero or more components on the left so compare RHS ++ * and if dns is longer and expect '.' as preceding character. ++ */ ++ if (dns->length > base->length) { ++ dnsptr += dns->length - base->length; ++ if (*baseptr != '.' && dnsptr[-1] != '.') ++ return X509_V_ERR_PERMITTED_VIOLATION; ++ } ++ ++ if (strcasecmp(baseptr, dnsptr)) ++ return X509_V_ERR_PERMITTED_VIOLATION; ++ ++ return X509_V_OK; ++ ++} ++ ++static int nc_email(ASN1_IA5STRING *eml, ASN1_IA5STRING *base) ++{ ++ const char *baseptr = (char *)base->data; ++ const char *emlptr = (char *)eml->data; ++ ++ const char *baseat = strchr(baseptr, '@'); ++ const char *emlat = strchr(emlptr, '@'); ++ if (!emlat) ++ return X509_V_ERR_UNSUPPORTED_NAME_SYNTAX; ++ /* Special case: initial '.' is RHS match */ ++ if (!baseat && (*baseptr == '.')) { ++ if (eml->length > base->length) { ++ emlptr += eml->length - base->length; ++ if (strcasecmp(baseptr, emlptr) == 0) ++ return X509_V_OK; ++ } ++ return X509_V_ERR_PERMITTED_VIOLATION; ++ } ++ ++ /* If we have anything before '@' match local part */ ++ ++ if (baseat) { ++ if (baseat != baseptr) { ++ if ((baseat - baseptr) != (emlat - emlptr)) ++ return X509_V_ERR_PERMITTED_VIOLATION; ++ /* Case sensitive match of local part */ ++ if (strncmp(baseptr, emlptr, emlat - emlptr)) ++ return X509_V_ERR_PERMITTED_VIOLATION; ++ } ++ /* Position base after '@' */ ++ baseptr = baseat + 1; ++ } ++ emlptr = emlat + 1; ++ /* Just have hostname left to match: case insensitive */ ++ if (strcasecmp(baseptr, emlptr)) ++ return X509_V_ERR_PERMITTED_VIOLATION; ++ ++ return X509_V_OK; ++ ++} ++ ++static int nc_uri(ASN1_IA5STRING *uri, ASN1_IA5STRING *base) ++{ ++ const char *baseptr = (char *)base->data; ++ const char *hostptr = (char *)uri->data; ++ const char *p = strchr(hostptr, ':'); ++ int hostlen; ++ /* Check for foo:// and skip past it */ ++ if (!p || (p[1] != '/') || (p[2] != '/')) ++ return X509_V_ERR_UNSUPPORTED_NAME_SYNTAX; ++ hostptr = p + 3; ++ ++ /* Determine length of hostname part of URI */ ++ ++ /* Look for a port indicator as end of hostname first */ ++ ++ p = strchr(hostptr, ':'); ++ /* Otherwise look for trailing slash */ ++ if (!p) ++ p = strchr(hostptr, '/'); ++ ++ if (!p) ++ hostlen = strlen(hostptr); ++ else ++ hostlen = p - hostptr; ++ ++ if (hostlen == 0) ++ return X509_V_ERR_UNSUPPORTED_NAME_SYNTAX; ++ ++ /* Special case: initial '.' is RHS match */ ++ if (*baseptr == '.') { ++ if (hostlen > base->length) { ++ p = hostptr + hostlen - base->length; ++ if (strncasecmp(p, baseptr, base->length) == 0) ++ return X509_V_OK; ++ } ++ return X509_V_ERR_PERMITTED_VIOLATION; ++ } ++ ++ if ((base->length != (int)hostlen) ++ || strncasecmp(hostptr, baseptr, hostlen)) ++ return X509_V_ERR_PERMITTED_VIOLATION; ++ ++ return X509_V_OK; ++ ++} ++ ++static int nc_ip(ASN1_OCTET_STRING *ip, ASN1_OCTET_STRING *base) ++{ ++ int hostlen, baselen, i; ++ unsigned char *hostptr, *baseptr, *maskptr; ++ hostptr = ip->data; ++ hostlen = ip->length; ++ baseptr = base->data; ++ baselen = base->length; ++ ++ /* Invalid if not IPv4 or IPv6 */ ++ if (!((hostlen == 4) || (hostlen == 16))) ++ return X509_V_ERR_UNSUPPORTED_NAME_SYNTAX; ++ if (!((baselen == 8) || (baselen == 32))) ++ return X509_V_ERR_UNSUPPORTED_NAME_SYNTAX; ++ ++ /* Do not match IPv4 with IPv6 */ ++ if (hostlen * 2 != baselen) ++ return X509_V_ERR_PERMITTED_VIOLATION; ++ ++ maskptr = base->data + hostlen; ++ ++ /* Considering possible not aligned base ipAddress */ ++ /* Not checking for wrong mask definition: i.e.: 255.0.255.0 */ ++ for (i = 0; i < hostlen; i++) ++ if ((hostptr[i] & maskptr[i]) != (baseptr[i] & maskptr[i])) ++ return X509_V_ERR_PERMITTED_VIOLATION; ++ ++ return X509_V_OK; ++ ++} +diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/x509v3/v3_pci.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/x509v3/v3_pci.c +new file mode 100644 +index 0000000..2c05edb +--- /dev/null ++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/x509v3/v3_pci.c +@@ -0,0 +1,321 @@ ++/* ++ * Copyright 2004-2016 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 ++ * in the file LICENSE in the source distribution or at ++ * https://www.openssl.org/source/license.html ++ */ ++ ++/* Copyright (c) 2004 Kungliga Tekniska Högskolan ++ * (Royal Institute of Technology, Stockholm, Sweden). ++ * 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. Neither the name of the Institute nor the names of its contributors ++ * may be used to endorse or promote products derived from this software ++ * without specific prior written permission. ++ * ++ * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND ++ * ANY EXPRESS 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 INSTITUTE OR 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. ++ */ ++ ++#include ++#include "internal/cryptlib.h" ++#include ++#include ++#include "ext_dat.h" ++ ++static int i2r_pci(X509V3_EXT_METHOD *method, PROXY_CERT_INFO_EXTENSION *ext, ++ BIO *out, int indent); ++static PROXY_CERT_INFO_EXTENSION *r2i_pci(X509V3_EXT_METHOD *method, ++ X509V3_CTX *ctx, char *str); ++ ++const X509V3_EXT_METHOD v3_pci = ++ { NID_proxyCertInfo, 0, ASN1_ITEM_ref(PROXY_CERT_INFO_EXTENSION), ++ 0, 0, 0, 0, ++ 0, 0, ++ NULL, NULL, ++ (X509V3_EXT_I2R)i2r_pci, ++ (X509V3_EXT_R2I)r2i_pci, ++ NULL, ++}; ++ ++static int i2r_pci(X509V3_EXT_METHOD *method, PROXY_CERT_INFO_EXTENSION *pci, ++ BIO *out, int indent) ++{ ++ BIO_printf(out, "%*sPath Length Constraint: ", indent, ""); ++ if (pci->pcPathLengthConstraint) ++ i2a_ASN1_INTEGER(out, pci->pcPathLengthConstraint); ++ else ++ BIO_printf(out, "infinite"); ++ BIO_puts(out, "\n"); ++ BIO_printf(out, "%*sPolicy Language: ", indent, ""); ++ i2a_ASN1_OBJECT(out, pci->proxyPolicy->policyLanguage); ++ BIO_puts(out, "\n"); ++ if (pci->proxyPolicy->policy && pci->proxyPolicy->policy->data) ++ BIO_printf(out, "%*sPolicy Text: %s\n", indent, "", ++ pci->proxyPolicy->policy->data); ++ return 1; ++} ++ ++static int process_pci_value(CONF_VALUE *val, ++ ASN1_OBJECT **language, ASN1_INTEGER **pathlen, ++ ASN1_OCTET_STRING **policy) ++{ ++ int free_policy = 0; ++ ++ if (strcmp(val->name, "language") == 0) { ++ if (*language) { ++ X509V3err(X509V3_F_PROCESS_PCI_VALUE, ++ X509V3_R_POLICY_LANGUAGE_ALREADY_DEFINED); ++ X509V3_conf_err(val); ++ return 0; ++ } ++ if ((*language = OBJ_txt2obj(val->value, 0)) == NULL) { ++ X509V3err(X509V3_F_PROCESS_PCI_VALUE, ++ X509V3_R_INVALID_OBJECT_IDENTIFIER); ++ X509V3_conf_err(val); ++ return 0; ++ } ++ } else if (strcmp(val->name, "pathlen") == 0) { ++ if (*pathlen) { ++ X509V3err(X509V3_F_PROCESS_PCI_VALUE, ++ X509V3_R_POLICY_PATH_LENGTH_ALREADY_DEFINED); ++ X509V3_conf_err(val); ++ return 0; ++ } ++ if (!X509V3_get_value_int(val, pathlen)) { ++ X509V3err(X509V3_F_PROCESS_PCI_VALUE, ++ X509V3_R_POLICY_PATH_LENGTH); ++ X509V3_conf_err(val); ++ return 0; ++ } ++ } else if (strcmp(val->name, "policy") == 0) { ++ unsigned char *tmp_data = NULL; ++ long val_len; ++ if (!*policy) { ++ *policy = ASN1_OCTET_STRING_new(); ++ if (*policy == NULL) { ++ X509V3err(X509V3_F_PROCESS_PCI_VALUE, ERR_R_MALLOC_FAILURE); ++ X509V3_conf_err(val); ++ return 0; ++ } ++ free_policy = 1; ++ } ++ if (strncmp(val->value, "hex:", 4) == 0) { ++ unsigned char *tmp_data2 = ++ OPENSSL_hexstr2buf(val->value + 4, &val_len); ++ ++ if (!tmp_data2) { ++ X509V3_conf_err(val); ++ goto err; ++ } ++ ++ tmp_data = OPENSSL_realloc((*policy)->data, ++ (*policy)->length + val_len + 1); ++ if (tmp_data) { ++ (*policy)->data = tmp_data; ++ memcpy(&(*policy)->data[(*policy)->length], ++ tmp_data2, val_len); ++ (*policy)->length += val_len; ++ (*policy)->data[(*policy)->length] = '\0'; ++ } else { ++ OPENSSL_free(tmp_data2); ++ /* ++ * realloc failure implies the original data space is b0rked ++ * too! ++ */ ++ OPENSSL_free((*policy)->data); ++ (*policy)->data = NULL; ++ (*policy)->length = 0; ++ X509V3err(X509V3_F_PROCESS_PCI_VALUE, ERR_R_MALLOC_FAILURE); ++ X509V3_conf_err(val); ++ goto err; ++ } ++ OPENSSL_free(tmp_data2); ++ } else if (strncmp(val->value, "file:", 5) == 0) { ++ unsigned char buf[2048]; ++ int n; ++ BIO *b = BIO_new_file(val->value + 5, "r"); ++ if (!b) { ++ X509V3err(X509V3_F_PROCESS_PCI_VALUE, ERR_R_BIO_LIB); ++ X509V3_conf_err(val); ++ goto err; ++ } ++ while ((n = BIO_read(b, buf, sizeof(buf))) > 0 ++ || (n == 0 && BIO_should_retry(b))) { ++ if (!n) ++ continue; ++ ++ tmp_data = OPENSSL_realloc((*policy)->data, ++ (*policy)->length + n + 1); ++ ++ if (!tmp_data) { ++ OPENSSL_free((*policy)->data); ++ (*policy)->data = NULL; ++ (*policy)->length = 0; ++ X509V3err(X509V3_F_PROCESS_PCI_VALUE, ++ ERR_R_MALLOC_FAILURE); ++ X509V3_conf_err(val); ++ BIO_free_all(b); ++ goto err; ++ } ++ ++ (*policy)->data = tmp_data; ++ memcpy(&(*policy)->data[(*policy)->length], buf, n); ++ (*policy)->length += n; ++ (*policy)->data[(*policy)->length] = '\0'; ++ } ++ BIO_free_all(b); ++ ++ if (n < 0) { ++ X509V3err(X509V3_F_PROCESS_PCI_VALUE, ERR_R_BIO_LIB); ++ X509V3_conf_err(val); ++ goto err; ++ } ++ } else if (strncmp(val->value, "text:", 5) == 0) { ++ val_len = strlen(val->value + 5); ++ tmp_data = OPENSSL_realloc((*policy)->data, ++ (*policy)->length + val_len + 1); ++ if (tmp_data) { ++ (*policy)->data = tmp_data; ++ memcpy(&(*policy)->data[(*policy)->length], ++ val->value + 5, val_len); ++ (*policy)->length += val_len; ++ (*policy)->data[(*policy)->length] = '\0'; ++ } else { ++ /* ++ * realloc failure implies the original data space is b0rked ++ * too! ++ */ ++ OPENSSL_free((*policy)->data); ++ (*policy)->data = NULL; ++ (*policy)->length = 0; ++ X509V3err(X509V3_F_PROCESS_PCI_VALUE, ERR_R_MALLOC_FAILURE); ++ X509V3_conf_err(val); ++ goto err; ++ } ++ } else { ++ X509V3err(X509V3_F_PROCESS_PCI_VALUE, ++ X509V3_R_INCORRECT_POLICY_SYNTAX_TAG); ++ X509V3_conf_err(val); ++ goto err; ++ } ++ if (!tmp_data) { ++ X509V3err(X509V3_F_PROCESS_PCI_VALUE, ERR_R_MALLOC_FAILURE); ++ X509V3_conf_err(val); ++ goto err; ++ } ++ } ++ return 1; ++ err: ++ if (free_policy) { ++ ASN1_OCTET_STRING_free(*policy); ++ *policy = NULL; ++ } ++ return 0; ++} ++ ++static PROXY_CERT_INFO_EXTENSION *r2i_pci(X509V3_EXT_METHOD *method, ++ X509V3_CTX *ctx, char *value) ++{ ++ PROXY_CERT_INFO_EXTENSION *pci = NULL; ++ STACK_OF(CONF_VALUE) *vals; ++ ASN1_OBJECT *language = NULL; ++ ASN1_INTEGER *pathlen = NULL; ++ ASN1_OCTET_STRING *policy = NULL; ++ int i, j; ++ ++ vals = X509V3_parse_list(value); ++ for (i = 0; i < sk_CONF_VALUE_num(vals); i++) { ++ CONF_VALUE *cnf = sk_CONF_VALUE_value(vals, i); ++ if (!cnf->name || (*cnf->name != '@' && !cnf->value)) { ++ X509V3err(X509V3_F_R2I_PCI, ++ X509V3_R_INVALID_PROXY_POLICY_SETTING); ++ X509V3_conf_err(cnf); ++ goto err; ++ } ++ if (*cnf->name == '@') { ++ STACK_OF(CONF_VALUE) *sect; ++ int success_p = 1; ++ ++ sect = X509V3_get_section(ctx, cnf->name + 1); ++ if (!sect) { ++ X509V3err(X509V3_F_R2I_PCI, X509V3_R_INVALID_SECTION); ++ X509V3_conf_err(cnf); ++ goto err; ++ } ++ for (j = 0; success_p && j < sk_CONF_VALUE_num(sect); j++) { ++ success_p = ++ process_pci_value(sk_CONF_VALUE_value(sect, j), ++ &language, &pathlen, &policy); ++ } ++ X509V3_section_free(ctx, sect); ++ if (!success_p) ++ goto err; ++ } else { ++ if (!process_pci_value(cnf, &language, &pathlen, &policy)) { ++ X509V3_conf_err(cnf); ++ goto err; ++ } ++ } ++ } ++ ++ /* Language is mandatory */ ++ if (!language) { ++ X509V3err(X509V3_F_R2I_PCI, ++ X509V3_R_NO_PROXY_CERT_POLICY_LANGUAGE_DEFINED); ++ goto err; ++ } ++ i = OBJ_obj2nid(language); ++ if ((i == NID_Independent || i == NID_id_ppl_inheritAll) && policy) { ++ X509V3err(X509V3_F_R2I_PCI, ++ X509V3_R_POLICY_WHEN_PROXY_LANGUAGE_REQUIRES_NO_POLICY); ++ goto err; ++ } ++ ++ pci = PROXY_CERT_INFO_EXTENSION_new(); ++ if (pci == NULL) { ++ X509V3err(X509V3_F_R2I_PCI, ERR_R_MALLOC_FAILURE); ++ goto err; ++ } ++ ++ pci->proxyPolicy->policyLanguage = language; ++ language = NULL; ++ pci->proxyPolicy->policy = policy; ++ policy = NULL; ++ pci->pcPathLengthConstraint = pathlen; ++ pathlen = NULL; ++ goto end; ++ err: ++ ASN1_OBJECT_free(language); ++ ASN1_INTEGER_free(pathlen); ++ pathlen = NULL; ++ ASN1_OCTET_STRING_free(policy); ++ policy = NULL; ++ PROXY_CERT_INFO_EXTENSION_free(pci); ++ pci = NULL; ++ end: ++ sk_CONF_VALUE_pop_free(vals, X509V3_conf_free); ++ return pci; ++} +diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/x509v3/v3_pcia.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/x509v3/v3_pcia.c +new file mode 100644 +index 0000000..e6f7a91 +--- /dev/null ++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/x509v3/v3_pcia.c +@@ -0,0 +1,60 @@ ++/* ++ * Copyright 2004-2016 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 ++ * in the file LICENSE in the source distribution or at ++ * https://www.openssl.org/source/license.html ++ */ ++ ++/* Copyright (c) 2004 Kungliga Tekniska Högskolan ++ * (Royal Institute of Technology, Stockholm, Sweden). ++ * 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. Neither the name of the Institute nor the names of its contributors ++ * may be used to endorse or promote products derived from this software ++ * without specific prior written permission. ++ * ++ * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND ++ * ANY EXPRESS 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 INSTITUTE OR 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. ++ */ ++ ++#include ++#include ++#include ++ ++ASN1_SEQUENCE(PROXY_POLICY) = ++ { ++ ASN1_SIMPLE(PROXY_POLICY,policyLanguage,ASN1_OBJECT), ++ ASN1_OPT(PROXY_POLICY,policy,ASN1_OCTET_STRING) ++} ASN1_SEQUENCE_END(PROXY_POLICY) ++ ++IMPLEMENT_ASN1_FUNCTIONS(PROXY_POLICY) ++ ++ASN1_SEQUENCE(PROXY_CERT_INFO_EXTENSION) = ++ { ++ ASN1_OPT(PROXY_CERT_INFO_EXTENSION,pcPathLengthConstraint,ASN1_INTEGER), ++ ASN1_SIMPLE(PROXY_CERT_INFO_EXTENSION,proxyPolicy,PROXY_POLICY) ++} ASN1_SEQUENCE_END(PROXY_CERT_INFO_EXTENSION) ++ ++IMPLEMENT_ASN1_FUNCTIONS(PROXY_CERT_INFO_EXTENSION) +diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/x509v3/v3_pcons.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/x509v3/v3_pcons.c +new file mode 100644 +index 0000000..24f7ff4 +--- /dev/null ++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/x509v3/v3_pcons.c +@@ -0,0 +1,91 @@ ++/* ++ * Copyright 2003-2016 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 ++ * in the file LICENSE in the source distribution or at ++ * https://www.openssl.org/source/license.html ++ */ ++ ++#include ++#include "internal/cryptlib.h" ++#include ++#include ++#include ++#include ++#include "ext_dat.h" ++ ++static STACK_OF(CONF_VALUE) *i2v_POLICY_CONSTRAINTS(const X509V3_EXT_METHOD ++ *method, void *bcons, STACK_OF(CONF_VALUE) ++ *extlist); ++static void *v2i_POLICY_CONSTRAINTS(const X509V3_EXT_METHOD *method, ++ X509V3_CTX *ctx, ++ STACK_OF(CONF_VALUE) *values); ++ ++const X509V3_EXT_METHOD v3_policy_constraints = { ++ NID_policy_constraints, 0, ++ ASN1_ITEM_ref(POLICY_CONSTRAINTS), ++ 0, 0, 0, 0, ++ 0, 0, ++ i2v_POLICY_CONSTRAINTS, ++ v2i_POLICY_CONSTRAINTS, ++ NULL, NULL, ++ NULL ++}; ++ ++ASN1_SEQUENCE(POLICY_CONSTRAINTS) = { ++ ASN1_IMP_OPT(POLICY_CONSTRAINTS, requireExplicitPolicy, ASN1_INTEGER,0), ++ ASN1_IMP_OPT(POLICY_CONSTRAINTS, inhibitPolicyMapping, ASN1_INTEGER,1) ++} ASN1_SEQUENCE_END(POLICY_CONSTRAINTS) ++ ++IMPLEMENT_ASN1_ALLOC_FUNCTIONS(POLICY_CONSTRAINTS) ++ ++static STACK_OF(CONF_VALUE) *i2v_POLICY_CONSTRAINTS(const X509V3_EXT_METHOD ++ *method, void *a, STACK_OF(CONF_VALUE) ++ *extlist) ++{ ++ POLICY_CONSTRAINTS *pcons = a; ++ X509V3_add_value_int("Require Explicit Policy", ++ pcons->requireExplicitPolicy, &extlist); ++ X509V3_add_value_int("Inhibit Policy Mapping", ++ pcons->inhibitPolicyMapping, &extlist); ++ return extlist; ++} ++ ++static void *v2i_POLICY_CONSTRAINTS(const X509V3_EXT_METHOD *method, ++ X509V3_CTX *ctx, ++ STACK_OF(CONF_VALUE) *values) ++{ ++ POLICY_CONSTRAINTS *pcons = NULL; ++ CONF_VALUE *val; ++ int i; ++ ++ if ((pcons = POLICY_CONSTRAINTS_new()) == NULL) { ++ X509V3err(X509V3_F_V2I_POLICY_CONSTRAINTS, ERR_R_MALLOC_FAILURE); ++ return NULL; ++ } ++ for (i = 0; i < sk_CONF_VALUE_num(values); i++) { ++ val = sk_CONF_VALUE_value(values, i); ++ if (strcmp(val->name, "requireExplicitPolicy") == 0) { ++ if (!X509V3_get_value_int(val, &pcons->requireExplicitPolicy)) ++ goto err; ++ } else if (strcmp(val->name, "inhibitPolicyMapping") == 0) { ++ if (!X509V3_get_value_int(val, &pcons->inhibitPolicyMapping)) ++ goto err; ++ } else { ++ X509V3err(X509V3_F_V2I_POLICY_CONSTRAINTS, X509V3_R_INVALID_NAME); ++ X509V3_conf_err(val); ++ goto err; ++ } ++ } ++ if (!pcons->inhibitPolicyMapping && !pcons->requireExplicitPolicy) { ++ X509V3err(X509V3_F_V2I_POLICY_CONSTRAINTS, ++ X509V3_R_ILLEGAL_EMPTY_EXTENSION); ++ goto err; ++ } ++ ++ return pcons; ++ err: ++ POLICY_CONSTRAINTS_free(pcons); ++ return NULL; ++} +diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/x509v3/v3_pku.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/x509v3/v3_pku.c +new file mode 100644 +index 0000000..ed82bca +--- /dev/null ++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/x509v3/v3_pku.c +@@ -0,0 +1,65 @@ ++/* ++ * Copyright 1999-2016 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 ++ * in the file LICENSE in the source distribution or at ++ * https://www.openssl.org/source/license.html ++ */ ++ ++#include ++#include "internal/cryptlib.h" ++#include ++#include ++#include ++#include "ext_dat.h" ++ ++static int i2r_PKEY_USAGE_PERIOD(X509V3_EXT_METHOD *method, ++ PKEY_USAGE_PERIOD *usage, BIO *out, ++ int indent); ++/* ++ * static PKEY_USAGE_PERIOD *v2i_PKEY_USAGE_PERIOD(X509V3_EXT_METHOD *method, ++ * X509V3_CTX *ctx, STACK_OF(CONF_VALUE) *values); ++ */ ++const X509V3_EXT_METHOD v3_pkey_usage_period = { ++ NID_private_key_usage_period, 0, ASN1_ITEM_ref(PKEY_USAGE_PERIOD), ++ 0, 0, 0, 0, ++ 0, 0, 0, 0, ++ (X509V3_EXT_I2R)i2r_PKEY_USAGE_PERIOD, NULL, ++ NULL ++}; ++ ++ASN1_SEQUENCE(PKEY_USAGE_PERIOD) = { ++ ASN1_IMP_OPT(PKEY_USAGE_PERIOD, notBefore, ASN1_GENERALIZEDTIME, 0), ++ ASN1_IMP_OPT(PKEY_USAGE_PERIOD, notAfter, ASN1_GENERALIZEDTIME, 1) ++} ASN1_SEQUENCE_END(PKEY_USAGE_PERIOD) ++ ++IMPLEMENT_ASN1_FUNCTIONS(PKEY_USAGE_PERIOD) ++ ++static int i2r_PKEY_USAGE_PERIOD(X509V3_EXT_METHOD *method, ++ PKEY_USAGE_PERIOD *usage, BIO *out, ++ int indent) ++{ ++ BIO_printf(out, "%*s", indent, ""); ++ if (usage->notBefore) { ++ BIO_write(out, "Not Before: ", 12); ++ ASN1_GENERALIZEDTIME_print(out, usage->notBefore); ++ if (usage->notAfter) ++ BIO_write(out, ", ", 2); ++ } ++ if (usage->notAfter) { ++ BIO_write(out, "Not After: ", 11); ++ ASN1_GENERALIZEDTIME_print(out, usage->notAfter); ++ } ++ return 1; ++} ++ ++/*- ++static PKEY_USAGE_PERIOD *v2i_PKEY_USAGE_PERIOD(method, ctx, values) ++X509V3_EXT_METHOD *method; ++X509V3_CTX *ctx; ++STACK_OF(CONF_VALUE) *values; ++{ ++return NULL; ++} ++*/ +diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/x509v3/v3_pmaps.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/x509v3/v3_pmaps.c +new file mode 100644 +index 0000000..73f4ec2 +--- /dev/null ++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/x509v3/v3_pmaps.c +@@ -0,0 +1,110 @@ ++/* ++ * Copyright 2003-2016 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 ++ * in the file LICENSE in the source distribution or at ++ * https://www.openssl.org/source/license.html ++ */ ++ ++#include ++#include "internal/cryptlib.h" ++#include ++#include ++#include ++#include "ext_dat.h" ++ ++static void *v2i_POLICY_MAPPINGS(const X509V3_EXT_METHOD *method, ++ X509V3_CTX *ctx, STACK_OF(CONF_VALUE) *nval); ++static STACK_OF(CONF_VALUE) *i2v_POLICY_MAPPINGS(const X509V3_EXT_METHOD ++ *method, void *pmps, STACK_OF(CONF_VALUE) ++ *extlist); ++ ++const X509V3_EXT_METHOD v3_policy_mappings = { ++ NID_policy_mappings, 0, ++ ASN1_ITEM_ref(POLICY_MAPPINGS), ++ 0, 0, 0, 0, ++ 0, 0, ++ i2v_POLICY_MAPPINGS, ++ v2i_POLICY_MAPPINGS, ++ 0, 0, ++ NULL ++}; ++ ++ASN1_SEQUENCE(POLICY_MAPPING) = { ++ ASN1_SIMPLE(POLICY_MAPPING, issuerDomainPolicy, ASN1_OBJECT), ++ ASN1_SIMPLE(POLICY_MAPPING, subjectDomainPolicy, ASN1_OBJECT) ++} ASN1_SEQUENCE_END(POLICY_MAPPING) ++ ++ASN1_ITEM_TEMPLATE(POLICY_MAPPINGS) = ++ ASN1_EX_TEMPLATE_TYPE(ASN1_TFLG_SEQUENCE_OF, 0, POLICY_MAPPINGS, ++ POLICY_MAPPING) ++ASN1_ITEM_TEMPLATE_END(POLICY_MAPPINGS) ++ ++IMPLEMENT_ASN1_ALLOC_FUNCTIONS(POLICY_MAPPING) ++ ++static STACK_OF(CONF_VALUE) *i2v_POLICY_MAPPINGS(const X509V3_EXT_METHOD ++ *method, void *a, STACK_OF(CONF_VALUE) ++ *ext_list) ++{ ++ POLICY_MAPPINGS *pmaps = a; ++ POLICY_MAPPING *pmap; ++ int i; ++ char obj_tmp1[80]; ++ char obj_tmp2[80]; ++ for (i = 0; i < sk_POLICY_MAPPING_num(pmaps); i++) { ++ pmap = sk_POLICY_MAPPING_value(pmaps, i); ++ i2t_ASN1_OBJECT(obj_tmp1, 80, pmap->issuerDomainPolicy); ++ i2t_ASN1_OBJECT(obj_tmp2, 80, pmap->subjectDomainPolicy); ++ X509V3_add_value(obj_tmp1, obj_tmp2, &ext_list); ++ } ++ return ext_list; ++} ++ ++static void *v2i_POLICY_MAPPINGS(const X509V3_EXT_METHOD *method, ++ X509V3_CTX *ctx, STACK_OF(CONF_VALUE) *nval) ++{ ++ POLICY_MAPPINGS *pmaps = NULL; ++ POLICY_MAPPING *pmap = NULL; ++ ASN1_OBJECT *obj1 = NULL, *obj2 = NULL; ++ CONF_VALUE *val; ++ int i; ++ ++ if ((pmaps = sk_POLICY_MAPPING_new_null()) == NULL) { ++ X509V3err(X509V3_F_V2I_POLICY_MAPPINGS, ERR_R_MALLOC_FAILURE); ++ return NULL; ++ } ++ ++ for (i = 0; i < sk_CONF_VALUE_num(nval); i++) { ++ val = sk_CONF_VALUE_value(nval, i); ++ if (!val->value || !val->name) { ++ X509V3err(X509V3_F_V2I_POLICY_MAPPINGS, ++ X509V3_R_INVALID_OBJECT_IDENTIFIER); ++ X509V3_conf_err(val); ++ goto err; ++ } ++ obj1 = OBJ_txt2obj(val->name, 0); ++ obj2 = OBJ_txt2obj(val->value, 0); ++ if (!obj1 || !obj2) { ++ X509V3err(X509V3_F_V2I_POLICY_MAPPINGS, ++ X509V3_R_INVALID_OBJECT_IDENTIFIER); ++ X509V3_conf_err(val); ++ goto err; ++ } ++ pmap = POLICY_MAPPING_new(); ++ if (pmap == NULL) { ++ X509V3err(X509V3_F_V2I_POLICY_MAPPINGS, ERR_R_MALLOC_FAILURE); ++ goto err; ++ } ++ pmap->issuerDomainPolicy = obj1; ++ pmap->subjectDomainPolicy = obj2; ++ obj1 = obj2 = NULL; ++ sk_POLICY_MAPPING_push(pmaps, pmap); ++ } ++ return pmaps; ++ err: ++ ASN1_OBJECT_free(obj1); ++ ASN1_OBJECT_free(obj2); ++ sk_POLICY_MAPPING_pop_free(pmaps, POLICY_MAPPING_free); ++ return NULL; ++} +diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/x509v3/v3_prn.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/x509v3/v3_prn.c +new file mode 100644 +index 0000000..f384c34 +--- /dev/null ++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/x509v3/v3_prn.c +@@ -0,0 +1,210 @@ ++/* ++ * Copyright 1999-2016 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 ++ * in the file LICENSE in the source distribution or at ++ * https://www.openssl.org/source/license.html ++ */ ++ ++/* X509 v3 extension utilities */ ++ ++#include ++#include "internal/cryptlib.h" ++#include ++#include ++ ++/* Extension printing routines */ ++ ++static int unknown_ext_print(BIO *out, const unsigned char *ext, int extlen, ++ unsigned long flag, int indent, int supported); ++ ++/* Print out a name+value stack */ ++ ++void X509V3_EXT_val_prn(BIO *out, STACK_OF(CONF_VALUE) *val, int indent, ++ int ml) ++{ ++ int i; ++ CONF_VALUE *nval; ++ if (!val) ++ return; ++ if (!ml || !sk_CONF_VALUE_num(val)) { ++ BIO_printf(out, "%*s", indent, ""); ++ if (!sk_CONF_VALUE_num(val)) ++ BIO_puts(out, "\n"); ++ } ++ for (i = 0; i < sk_CONF_VALUE_num(val); i++) { ++ if (ml) ++ BIO_printf(out, "%*s", indent, ""); ++ else if (i > 0) ++ BIO_printf(out, ", "); ++ nval = sk_CONF_VALUE_value(val, i); ++ if (!nval->name) ++ BIO_puts(out, nval->value); ++ else if (!nval->value) ++ BIO_puts(out, nval->name); ++#ifndef CHARSET_EBCDIC ++ else ++ BIO_printf(out, "%s:%s", nval->name, nval->value); ++#else ++ else { ++ int len; ++ char *tmp; ++ len = strlen(nval->value) + 1; ++ tmp = OPENSSL_malloc(len); ++ if (tmp != NULL) { ++ ascii2ebcdic(tmp, nval->value, len); ++ BIO_printf(out, "%s:%s", nval->name, tmp); ++ OPENSSL_free(tmp); ++ } ++ } ++#endif ++ if (ml) ++ BIO_puts(out, "\n"); ++ } ++} ++ ++/* Main routine: print out a general extension */ ++ ++int X509V3_EXT_print(BIO *out, X509_EXTENSION *ext, unsigned long flag, ++ int indent) ++{ ++ void *ext_str = NULL; ++ char *value = NULL; ++ ASN1_OCTET_STRING *extoct; ++ const unsigned char *p; ++ int extlen; ++ const X509V3_EXT_METHOD *method; ++ STACK_OF(CONF_VALUE) *nval = NULL; ++ int ok = 1; ++ ++ extoct = X509_EXTENSION_get_data(ext); ++ p = ASN1_STRING_get0_data(extoct); ++ extlen = ASN1_STRING_length(extoct); ++ ++ if ((method = X509V3_EXT_get(ext)) == NULL) ++ return unknown_ext_print(out, p, extlen, flag, indent, 0); ++ if (method->it) ++ ext_str = ASN1_item_d2i(NULL, &p, extlen, ASN1_ITEM_ptr(method->it)); ++ else ++ ext_str = method->d2i(NULL, &p, extlen); ++ ++ if (!ext_str) ++ return unknown_ext_print(out, p, extlen, flag, indent, 1); ++ ++ if (method->i2s) { ++ if ((value = method->i2s(method, ext_str)) == NULL) { ++ ok = 0; ++ goto err; ++ } ++#ifndef CHARSET_EBCDIC ++ BIO_printf(out, "%*s%s", indent, "", value); ++#else ++ { ++ int len; ++ char *tmp; ++ len = strlen(value) + 1; ++ tmp = OPENSSL_malloc(len); ++ if (tmp != NULL) { ++ ascii2ebcdic(tmp, value, len); ++ BIO_printf(out, "%*s%s", indent, "", tmp); ++ OPENSSL_free(tmp); ++ } ++ } ++#endif ++ } else if (method->i2v) { ++ if ((nval = method->i2v(method, ext_str, NULL)) == NULL) { ++ ok = 0; ++ goto err; ++ } ++ X509V3_EXT_val_prn(out, nval, indent, ++ method->ext_flags & X509V3_EXT_MULTILINE); ++ } else if (method->i2r) { ++ if (!method->i2r(method, ext_str, out, indent)) ++ ok = 0; ++ } else ++ ok = 0; ++ ++ err: ++ sk_CONF_VALUE_pop_free(nval, X509V3_conf_free); ++ OPENSSL_free(value); ++ if (method->it) ++ ASN1_item_free(ext_str, ASN1_ITEM_ptr(method->it)); ++ else ++ method->ext_free(ext_str); ++ return ok; ++} ++ ++int X509V3_extensions_print(BIO *bp, const char *title, ++ const STACK_OF(X509_EXTENSION) *exts, ++ unsigned long flag, int indent) ++{ ++ int i, j; ++ ++ if (sk_X509_EXTENSION_num(exts) <= 0) ++ return 1; ++ ++ if (title) { ++ BIO_printf(bp, "%*s%s:\n", indent, "", title); ++ indent += 4; ++ } ++ ++ for (i = 0; i < sk_X509_EXTENSION_num(exts); i++) { ++ ASN1_OBJECT *obj; ++ X509_EXTENSION *ex; ++ ex = sk_X509_EXTENSION_value(exts, i); ++ if (indent && BIO_printf(bp, "%*s", indent, "") <= 0) ++ return 0; ++ obj = X509_EXTENSION_get_object(ex); ++ i2a_ASN1_OBJECT(bp, obj); ++ j = X509_EXTENSION_get_critical(ex); ++ if (BIO_printf(bp, ": %s\n", j ? "critical" : "") <= 0) ++ return 0; ++ if (!X509V3_EXT_print(bp, ex, flag, indent + 4)) { ++ BIO_printf(bp, "%*s", indent + 4, ""); ++ ASN1_STRING_print(bp, X509_EXTENSION_get_data(ex)); ++ } ++ if (BIO_write(bp, "\n", 1) <= 0) ++ return 0; ++ } ++ return 1; ++} ++ ++static int unknown_ext_print(BIO *out, const unsigned char *ext, int extlen, ++ unsigned long flag, int indent, int supported) ++{ ++ switch (flag & X509V3_EXT_UNKNOWN_MASK) { ++ ++ case X509V3_EXT_DEFAULT: ++ return 0; ++ ++ case X509V3_EXT_ERROR_UNKNOWN: ++ if (supported) ++ BIO_printf(out, "%*s", indent, ""); ++ else ++ BIO_printf(out, "%*s", indent, ""); ++ return 1; ++ ++ case X509V3_EXT_PARSE_UNKNOWN: ++ return ASN1_parse_dump(out, ext, extlen, indent, -1); ++ case X509V3_EXT_DUMP_UNKNOWN: ++ return BIO_dump_indent(out, (const char *)ext, extlen, indent); ++ ++ default: ++ return 1; ++ } ++} ++ ++#ifndef OPENSSL_NO_STDIO ++int X509V3_EXT_print_fp(FILE *fp, X509_EXTENSION *ext, int flag, int indent) ++{ ++ BIO *bio_tmp; ++ int ret; ++ ++ if ((bio_tmp = BIO_new_fp(fp, BIO_NOCLOSE)) == NULL) ++ return 0; ++ ret = X509V3_EXT_print(bio_tmp, ext, flag, indent); ++ BIO_free(bio_tmp); ++ return ret; ++} ++#endif +diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/x509v3/v3_purp.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/x509v3/v3_purp.c +new file mode 100644 +index 0000000..451e7f8 +--- /dev/null ++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/x509v3/v3_purp.c +@@ -0,0 +1,865 @@ ++/* ++ * Copyright 1999-2016 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 ++ * in the file LICENSE in the source distribution or at ++ * https://www.openssl.org/source/license.html ++ */ ++ ++#include ++#include "internal/cryptlib.h" ++#include "internal/numbers.h" ++#include ++#include ++#include "internal/x509_int.h" ++ ++static void x509v3_cache_extensions(X509 *x); ++ ++static int check_ssl_ca(const X509 *x); ++static int check_purpose_ssl_client(const X509_PURPOSE *xp, const X509 *x, ++ int ca); ++static int check_purpose_ssl_server(const X509_PURPOSE *xp, const X509 *x, ++ int ca); ++static int check_purpose_ns_ssl_server(const X509_PURPOSE *xp, const X509 *x, ++ int ca); ++static int purpose_smime(const X509 *x, int ca); ++static int check_purpose_smime_sign(const X509_PURPOSE *xp, const X509 *x, ++ int ca); ++static int check_purpose_smime_encrypt(const X509_PURPOSE *xp, const X509 *x, ++ int ca); ++static int check_purpose_crl_sign(const X509_PURPOSE *xp, const X509 *x, ++ int ca); ++static int check_purpose_timestamp_sign(const X509_PURPOSE *xp, const X509 *x, ++ int ca); ++static int no_check(const X509_PURPOSE *xp, const X509 *x, int ca); ++static int ocsp_helper(const X509_PURPOSE *xp, const X509 *x, int ca); ++ ++static int xp_cmp(const X509_PURPOSE *const *a, const X509_PURPOSE *const *b); ++static void xptable_free(X509_PURPOSE *p); ++ ++static X509_PURPOSE xstandard[] = { ++ {X509_PURPOSE_SSL_CLIENT, X509_TRUST_SSL_CLIENT, 0, ++ check_purpose_ssl_client, "SSL client", "sslclient", NULL}, ++ {X509_PURPOSE_SSL_SERVER, X509_TRUST_SSL_SERVER, 0, ++ check_purpose_ssl_server, "SSL server", "sslserver", NULL}, ++ {X509_PURPOSE_NS_SSL_SERVER, X509_TRUST_SSL_SERVER, 0, ++ check_purpose_ns_ssl_server, "Netscape SSL server", "nssslserver", NULL}, ++ {X509_PURPOSE_SMIME_SIGN, X509_TRUST_EMAIL, 0, check_purpose_smime_sign, ++ "S/MIME signing", "smimesign", NULL}, ++ {X509_PURPOSE_SMIME_ENCRYPT, X509_TRUST_EMAIL, 0, ++ check_purpose_smime_encrypt, "S/MIME encryption", "smimeencrypt", NULL}, ++ {X509_PURPOSE_CRL_SIGN, X509_TRUST_COMPAT, 0, check_purpose_crl_sign, ++ "CRL signing", "crlsign", NULL}, ++ {X509_PURPOSE_ANY, X509_TRUST_DEFAULT, 0, no_check, "Any Purpose", "any", ++ NULL}, ++ {X509_PURPOSE_OCSP_HELPER, X509_TRUST_COMPAT, 0, ocsp_helper, ++ "OCSP helper", "ocsphelper", NULL}, ++ {X509_PURPOSE_TIMESTAMP_SIGN, X509_TRUST_TSA, 0, ++ check_purpose_timestamp_sign, "Time Stamp signing", "timestampsign", ++ NULL}, ++}; ++ ++#define X509_PURPOSE_COUNT OSSL_NELEM(xstandard) ++ ++static STACK_OF(X509_PURPOSE) *xptable = NULL; ++ ++static int xp_cmp(const X509_PURPOSE *const *a, const X509_PURPOSE *const *b) ++{ ++ return (*a)->purpose - (*b)->purpose; ++} ++ ++/* ++ * As much as I'd like to make X509_check_purpose use a "const" X509* I ++ * really can't because it does recalculate hashes and do other non-const ++ * things. ++ */ ++int X509_check_purpose(X509 *x, int id, int ca) ++{ ++ int idx; ++ const X509_PURPOSE *pt; ++ if (!(x->ex_flags & EXFLAG_SET)) { ++ CRYPTO_THREAD_write_lock(x->lock); ++ x509v3_cache_extensions(x); ++ CRYPTO_THREAD_unlock(x->lock); ++ } ++ /* Return if side-effect only call */ ++ if (id == -1) ++ return 1; ++ idx = X509_PURPOSE_get_by_id(id); ++ if (idx == -1) ++ return -1; ++ pt = X509_PURPOSE_get0(idx); ++ return pt->check_purpose(pt, x, ca); ++} ++ ++int X509_PURPOSE_set(int *p, int purpose) ++{ ++ if (X509_PURPOSE_get_by_id(purpose) == -1) { ++ X509V3err(X509V3_F_X509_PURPOSE_SET, X509V3_R_INVALID_PURPOSE); ++ return 0; ++ } ++ *p = purpose; ++ return 1; ++} ++ ++int X509_PURPOSE_get_count(void) ++{ ++ if (!xptable) ++ return X509_PURPOSE_COUNT; ++ return sk_X509_PURPOSE_num(xptable) + X509_PURPOSE_COUNT; ++} ++ ++X509_PURPOSE *X509_PURPOSE_get0(int idx) ++{ ++ if (idx < 0) ++ return NULL; ++ if (idx < (int)X509_PURPOSE_COUNT) ++ return xstandard + idx; ++ return sk_X509_PURPOSE_value(xptable, idx - X509_PURPOSE_COUNT); ++} ++ ++int X509_PURPOSE_get_by_sname(const char *sname) ++{ ++ int i; ++ X509_PURPOSE *xptmp; ++ for (i = 0; i < X509_PURPOSE_get_count(); i++) { ++ xptmp = X509_PURPOSE_get0(i); ++ if (strcmp(xptmp->sname, sname) == 0) ++ return i; ++ } ++ return -1; ++} ++ ++int X509_PURPOSE_get_by_id(int purpose) ++{ ++ X509_PURPOSE tmp; ++ int idx; ++ if ((purpose >= X509_PURPOSE_MIN) && (purpose <= X509_PURPOSE_MAX)) ++ return purpose - X509_PURPOSE_MIN; ++ tmp.purpose = purpose; ++ if (!xptable) ++ return -1; ++ idx = sk_X509_PURPOSE_find(xptable, &tmp); ++ if (idx == -1) ++ return -1; ++ return idx + X509_PURPOSE_COUNT; ++} ++ ++int X509_PURPOSE_add(int id, int trust, int flags, ++ int (*ck) (const X509_PURPOSE *, const X509 *, int), ++ const char *name, const char *sname, void *arg) ++{ ++ int idx; ++ X509_PURPOSE *ptmp; ++ /* ++ * This is set according to what we change: application can't set it ++ */ ++ flags &= ~X509_PURPOSE_DYNAMIC; ++ /* This will always be set for application modified trust entries */ ++ flags |= X509_PURPOSE_DYNAMIC_NAME; ++ /* Get existing entry if any */ ++ idx = X509_PURPOSE_get_by_id(id); ++ /* Need a new entry */ ++ if (idx == -1) { ++ if ((ptmp = OPENSSL_malloc(sizeof(*ptmp))) == NULL) { ++ X509V3err(X509V3_F_X509_PURPOSE_ADD, ERR_R_MALLOC_FAILURE); ++ return 0; ++ } ++ ptmp->flags = X509_PURPOSE_DYNAMIC; ++ } else ++ ptmp = X509_PURPOSE_get0(idx); ++ ++ /* OPENSSL_free existing name if dynamic */ ++ if (ptmp->flags & X509_PURPOSE_DYNAMIC_NAME) { ++ OPENSSL_free(ptmp->name); ++ OPENSSL_free(ptmp->sname); ++ } ++ /* dup supplied name */ ++ ptmp->name = OPENSSL_strdup(name); ++ ptmp->sname = OPENSSL_strdup(sname); ++ if (!ptmp->name || !ptmp->sname) { ++ X509V3err(X509V3_F_X509_PURPOSE_ADD, ERR_R_MALLOC_FAILURE); ++ goto err; ++ } ++ /* Keep the dynamic flag of existing entry */ ++ ptmp->flags &= X509_PURPOSE_DYNAMIC; ++ /* Set all other flags */ ++ ptmp->flags |= flags; ++ ++ ptmp->purpose = id; ++ ptmp->trust = trust; ++ ptmp->check_purpose = ck; ++ ptmp->usr_data = arg; ++ ++ /* If its a new entry manage the dynamic table */ ++ if (idx == -1) { ++ if (xptable == NULL ++ && (xptable = sk_X509_PURPOSE_new(xp_cmp)) == NULL) { ++ X509V3err(X509V3_F_X509_PURPOSE_ADD, ERR_R_MALLOC_FAILURE); ++ goto err; ++ } ++ if (!sk_X509_PURPOSE_push(xptable, ptmp)) { ++ X509V3err(X509V3_F_X509_PURPOSE_ADD, ERR_R_MALLOC_FAILURE); ++ goto err; ++ } ++ } ++ return 1; ++ err: ++ if (idx == -1) { ++ OPENSSL_free(ptmp->name); ++ OPENSSL_free(ptmp->sname); ++ OPENSSL_free(ptmp); ++ } ++ return 0; ++} ++ ++static void xptable_free(X509_PURPOSE *p) ++{ ++ if (!p) ++ return; ++ if (p->flags & X509_PURPOSE_DYNAMIC) { ++ if (p->flags & X509_PURPOSE_DYNAMIC_NAME) { ++ OPENSSL_free(p->name); ++ OPENSSL_free(p->sname); ++ } ++ OPENSSL_free(p); ++ } ++} ++ ++void X509_PURPOSE_cleanup(void) ++{ ++ sk_X509_PURPOSE_pop_free(xptable, xptable_free); ++ xptable = NULL; ++} ++ ++int X509_PURPOSE_get_id(const X509_PURPOSE *xp) ++{ ++ return xp->purpose; ++} ++ ++char *X509_PURPOSE_get0_name(const X509_PURPOSE *xp) ++{ ++ return xp->name; ++} ++ ++char *X509_PURPOSE_get0_sname(const X509_PURPOSE *xp) ++{ ++ return xp->sname; ++} ++ ++int X509_PURPOSE_get_trust(const X509_PURPOSE *xp) ++{ ++ return xp->trust; ++} ++ ++static int nid_cmp(const int *a, const int *b) ++{ ++ return *a - *b; ++} ++ ++DECLARE_OBJ_BSEARCH_CMP_FN(int, int, nid); ++IMPLEMENT_OBJ_BSEARCH_CMP_FN(int, int, nid); ++ ++int X509_supported_extension(X509_EXTENSION *ex) ++{ ++ /* ++ * This table is a list of the NIDs of supported extensions: that is ++ * those which are used by the verify process. If an extension is ++ * critical and doesn't appear in this list then the verify process will ++ * normally reject the certificate. The list must be kept in numerical ++ * order because it will be searched using bsearch. ++ */ ++ ++ static const int supported_nids[] = { ++ NID_netscape_cert_type, /* 71 */ ++ NID_key_usage, /* 83 */ ++ NID_subject_alt_name, /* 85 */ ++ NID_basic_constraints, /* 87 */ ++ NID_certificate_policies, /* 89 */ ++ NID_ext_key_usage, /* 126 */ ++#ifndef OPENSSL_NO_RFC3779 ++ NID_sbgp_ipAddrBlock, /* 290 */ ++ NID_sbgp_autonomousSysNum, /* 291 */ ++#endif ++ NID_policy_constraints, /* 401 */ ++ NID_proxyCertInfo, /* 663 */ ++ NID_name_constraints, /* 666 */ ++ NID_policy_mappings, /* 747 */ ++ NID_inhibit_any_policy /* 748 */ ++ }; ++ ++ int ex_nid = OBJ_obj2nid(X509_EXTENSION_get_object(ex)); ++ ++ if (ex_nid == NID_undef) ++ return 0; ++ ++ if (OBJ_bsearch_nid(&ex_nid, supported_nids, OSSL_NELEM(supported_nids))) ++ return 1; ++ return 0; ++} ++ ++static void setup_dp(X509 *x, DIST_POINT *dp) ++{ ++ X509_NAME *iname = NULL; ++ int i; ++ if (dp->reasons) { ++ if (dp->reasons->length > 0) ++ dp->dp_reasons = dp->reasons->data[0]; ++ if (dp->reasons->length > 1) ++ dp->dp_reasons |= (dp->reasons->data[1] << 8); ++ dp->dp_reasons &= CRLDP_ALL_REASONS; ++ } else ++ dp->dp_reasons = CRLDP_ALL_REASONS; ++ if (!dp->distpoint || (dp->distpoint->type != 1)) ++ return; ++ for (i = 0; i < sk_GENERAL_NAME_num(dp->CRLissuer); i++) { ++ GENERAL_NAME *gen = sk_GENERAL_NAME_value(dp->CRLissuer, i); ++ if (gen->type == GEN_DIRNAME) { ++ iname = gen->d.directoryName; ++ break; ++ } ++ } ++ if (!iname) ++ iname = X509_get_issuer_name(x); ++ ++ DIST_POINT_set_dpname(dp->distpoint, iname); ++ ++} ++ ++static void setup_crldp(X509 *x) ++{ ++ int i; ++ x->crldp = X509_get_ext_d2i(x, NID_crl_distribution_points, NULL, NULL); ++ for (i = 0; i < sk_DIST_POINT_num(x->crldp); i++) ++ setup_dp(x, sk_DIST_POINT_value(x->crldp, i)); ++} ++ ++#define V1_ROOT (EXFLAG_V1|EXFLAG_SS) ++#define ku_reject(x, usage) \ ++ (((x)->ex_flags & EXFLAG_KUSAGE) && !((x)->ex_kusage & (usage))) ++#define xku_reject(x, usage) \ ++ (((x)->ex_flags & EXFLAG_XKUSAGE) && !((x)->ex_xkusage & (usage))) ++#define ns_reject(x, usage) \ ++ (((x)->ex_flags & EXFLAG_NSCERT) && !((x)->ex_nscert & (usage))) ++ ++static void x509v3_cache_extensions(X509 *x) ++{ ++ BASIC_CONSTRAINTS *bs; ++ PROXY_CERT_INFO_EXTENSION *pci; ++ ASN1_BIT_STRING *usage; ++ ASN1_BIT_STRING *ns; ++ EXTENDED_KEY_USAGE *extusage; ++ X509_EXTENSION *ex; ++ ++ int i; ++ if (x->ex_flags & EXFLAG_SET) ++ return; ++ X509_digest(x, EVP_sha1(), x->sha1_hash, NULL); ++ /* V1 should mean no extensions ... */ ++ if (!X509_get_version(x)) ++ x->ex_flags |= EXFLAG_V1; ++ /* Handle basic constraints */ ++ if ((bs = X509_get_ext_d2i(x, NID_basic_constraints, NULL, NULL))) { ++ if (bs->ca) ++ x->ex_flags |= EXFLAG_CA; ++ if (bs->pathlen) { ++ if ((bs->pathlen->type == V_ASN1_NEG_INTEGER) ++ || !bs->ca) { ++ x->ex_flags |= EXFLAG_INVALID; ++ x->ex_pathlen = 0; ++ } else ++ x->ex_pathlen = ASN1_INTEGER_get(bs->pathlen); ++ } else ++ x->ex_pathlen = -1; ++ BASIC_CONSTRAINTS_free(bs); ++ x->ex_flags |= EXFLAG_BCONS; ++ } ++ /* Handle proxy certificates */ ++ if ((pci = X509_get_ext_d2i(x, NID_proxyCertInfo, NULL, NULL))) { ++ if (x->ex_flags & EXFLAG_CA ++ || X509_get_ext_by_NID(x, NID_subject_alt_name, -1) >= 0 ++ || X509_get_ext_by_NID(x, NID_issuer_alt_name, -1) >= 0) { ++ x->ex_flags |= EXFLAG_INVALID; ++ } ++ if (pci->pcPathLengthConstraint) { ++ x->ex_pcpathlen = ASN1_INTEGER_get(pci->pcPathLengthConstraint); ++ } else ++ x->ex_pcpathlen = -1; ++ PROXY_CERT_INFO_EXTENSION_free(pci); ++ x->ex_flags |= EXFLAG_PROXY; ++ } ++ /* Handle key usage */ ++ if ((usage = X509_get_ext_d2i(x, NID_key_usage, NULL, NULL))) { ++ if (usage->length > 0) { ++ x->ex_kusage = usage->data[0]; ++ if (usage->length > 1) ++ x->ex_kusage |= usage->data[1] << 8; ++ } else ++ x->ex_kusage = 0; ++ x->ex_flags |= EXFLAG_KUSAGE; ++ ASN1_BIT_STRING_free(usage); ++ } ++ x->ex_xkusage = 0; ++ if ((extusage = X509_get_ext_d2i(x, NID_ext_key_usage, NULL, NULL))) { ++ x->ex_flags |= EXFLAG_XKUSAGE; ++ for (i = 0; i < sk_ASN1_OBJECT_num(extusage); i++) { ++ switch (OBJ_obj2nid(sk_ASN1_OBJECT_value(extusage, i))) { ++ case NID_server_auth: ++ x->ex_xkusage |= XKU_SSL_SERVER; ++ break; ++ ++ case NID_client_auth: ++ x->ex_xkusage |= XKU_SSL_CLIENT; ++ break; ++ ++ case NID_email_protect: ++ x->ex_xkusage |= XKU_SMIME; ++ break; ++ ++ case NID_code_sign: ++ x->ex_xkusage |= XKU_CODE_SIGN; ++ break; ++ ++ case NID_ms_sgc: ++ case NID_ns_sgc: ++ x->ex_xkusage |= XKU_SGC; ++ break; ++ ++ case NID_OCSP_sign: ++ x->ex_xkusage |= XKU_OCSP_SIGN; ++ break; ++ ++ case NID_time_stamp: ++ x->ex_xkusage |= XKU_TIMESTAMP; ++ break; ++ ++ case NID_dvcs: ++ x->ex_xkusage |= XKU_DVCS; ++ break; ++ ++ case NID_anyExtendedKeyUsage: ++ x->ex_xkusage |= XKU_ANYEKU; ++ break; ++ } ++ } ++ sk_ASN1_OBJECT_pop_free(extusage, ASN1_OBJECT_free); ++ } ++ ++ if ((ns = X509_get_ext_d2i(x, NID_netscape_cert_type, NULL, NULL))) { ++ if (ns->length > 0) ++ x->ex_nscert = ns->data[0]; ++ else ++ x->ex_nscert = 0; ++ x->ex_flags |= EXFLAG_NSCERT; ++ ASN1_BIT_STRING_free(ns); ++ } ++ x->skid = X509_get_ext_d2i(x, NID_subject_key_identifier, NULL, NULL); ++ x->akid = X509_get_ext_d2i(x, NID_authority_key_identifier, NULL, NULL); ++ /* Does subject name match issuer ? */ ++ if (!X509_NAME_cmp(X509_get_subject_name(x), X509_get_issuer_name(x))) { ++ x->ex_flags |= EXFLAG_SI; ++ /* If SKID matches AKID also indicate self signed */ ++ if (X509_check_akid(x, x->akid) == X509_V_OK && ++ !ku_reject(x, KU_KEY_CERT_SIGN)) ++ x->ex_flags |= EXFLAG_SS; ++ } ++ x->altname = X509_get_ext_d2i(x, NID_subject_alt_name, NULL, NULL); ++ x->nc = X509_get_ext_d2i(x, NID_name_constraints, &i, NULL); ++ if (!x->nc && (i != -1)) ++ x->ex_flags |= EXFLAG_INVALID; ++ setup_crldp(x); ++ ++#ifndef OPENSSL_NO_RFC3779 ++ x->rfc3779_addr = X509_get_ext_d2i(x, NID_sbgp_ipAddrBlock, NULL, NULL); ++ x->rfc3779_asid = X509_get_ext_d2i(x, NID_sbgp_autonomousSysNum, ++ NULL, NULL); ++#endif ++ for (i = 0; i < X509_get_ext_count(x); i++) { ++ ex = X509_get_ext(x, i); ++ if (OBJ_obj2nid(X509_EXTENSION_get_object(ex)) ++ == NID_freshest_crl) ++ x->ex_flags |= EXFLAG_FRESHEST; ++ if (!X509_EXTENSION_get_critical(ex)) ++ continue; ++ if (!X509_supported_extension(ex)) { ++ x->ex_flags |= EXFLAG_CRITICAL; ++ break; ++ } ++ } ++ x->ex_flags |= EXFLAG_SET; ++} ++ ++/*- ++ * CA checks common to all purposes ++ * return codes: ++ * 0 not a CA ++ * 1 is a CA ++ * 2 basicConstraints absent so "maybe" a CA ++ * 3 basicConstraints absent but self signed V1. ++ * 4 basicConstraints absent but keyUsage present and keyCertSign asserted. ++ */ ++ ++static int check_ca(const X509 *x) ++{ ++ /* keyUsage if present should allow cert signing */ ++ if (ku_reject(x, KU_KEY_CERT_SIGN)) ++ return 0; ++ if (x->ex_flags & EXFLAG_BCONS) { ++ if (x->ex_flags & EXFLAG_CA) ++ return 1; ++ /* If basicConstraints says not a CA then say so */ ++ else ++ return 0; ++ } else { ++ /* we support V1 roots for... uh, I don't really know why. */ ++ if ((x->ex_flags & V1_ROOT) == V1_ROOT) ++ return 3; ++ /* ++ * If key usage present it must have certSign so tolerate it ++ */ ++ else if (x->ex_flags & EXFLAG_KUSAGE) ++ return 4; ++ /* Older certificates could have Netscape-specific CA types */ ++ else if (x->ex_flags & EXFLAG_NSCERT && x->ex_nscert & NS_ANY_CA) ++ return 5; ++ /* can this still be regarded a CA certificate? I doubt it */ ++ return 0; ++ } ++} ++ ++void X509_set_proxy_flag(X509 *x) ++{ ++ x->ex_flags |= EXFLAG_PROXY; ++} ++ ++void X509_set_proxy_pathlen(X509 *x, long l) ++{ ++ x->ex_pcpathlen = l; ++} ++ ++int X509_check_ca(X509 *x) ++{ ++ if (!(x->ex_flags & EXFLAG_SET)) { ++ CRYPTO_THREAD_write_lock(x->lock); ++ x509v3_cache_extensions(x); ++ CRYPTO_THREAD_unlock(x->lock); ++ } ++ ++ return check_ca(x); ++} ++ ++/* Check SSL CA: common checks for SSL client and server */ ++static int check_ssl_ca(const X509 *x) ++{ ++ int ca_ret; ++ ca_ret = check_ca(x); ++ if (!ca_ret) ++ return 0; ++ /* check nsCertType if present */ ++ if (ca_ret != 5 || x->ex_nscert & NS_SSL_CA) ++ return ca_ret; ++ else ++ return 0; ++} ++ ++static int check_purpose_ssl_client(const X509_PURPOSE *xp, const X509 *x, ++ int ca) ++{ ++ if (xku_reject(x, XKU_SSL_CLIENT)) ++ return 0; ++ if (ca) ++ return check_ssl_ca(x); ++ /* We need to do digital signatures or key agreement */ ++ if (ku_reject(x, KU_DIGITAL_SIGNATURE | KU_KEY_AGREEMENT)) ++ return 0; ++ /* nsCertType if present should allow SSL client use */ ++ if (ns_reject(x, NS_SSL_CLIENT)) ++ return 0; ++ return 1; ++} ++ ++/* ++ * Key usage needed for TLS/SSL server: digital signature, encipherment or ++ * key agreement. The ssl code can check this more thoroughly for individual ++ * key types. ++ */ ++#define KU_TLS \ ++ KU_DIGITAL_SIGNATURE|KU_KEY_ENCIPHERMENT|KU_KEY_AGREEMENT ++ ++static int check_purpose_ssl_server(const X509_PURPOSE *xp, const X509 *x, ++ int ca) ++{ ++ if (xku_reject(x, XKU_SSL_SERVER | XKU_SGC)) ++ return 0; ++ if (ca) ++ return check_ssl_ca(x); ++ ++ if (ns_reject(x, NS_SSL_SERVER)) ++ return 0; ++ if (ku_reject(x, KU_TLS)) ++ return 0; ++ ++ return 1; ++ ++} ++ ++static int check_purpose_ns_ssl_server(const X509_PURPOSE *xp, const X509 *x, ++ int ca) ++{ ++ int ret; ++ ret = check_purpose_ssl_server(xp, x, ca); ++ if (!ret || ca) ++ return ret; ++ /* We need to encipher or Netscape complains */ ++ if (ku_reject(x, KU_KEY_ENCIPHERMENT)) ++ return 0; ++ return ret; ++} ++ ++/* common S/MIME checks */ ++static int purpose_smime(const X509 *x, int ca) ++{ ++ if (xku_reject(x, XKU_SMIME)) ++ return 0; ++ if (ca) { ++ int ca_ret; ++ ca_ret = check_ca(x); ++ if (!ca_ret) ++ return 0; ++ /* check nsCertType if present */ ++ if (ca_ret != 5 || x->ex_nscert & NS_SMIME_CA) ++ return ca_ret; ++ else ++ return 0; ++ } ++ if (x->ex_flags & EXFLAG_NSCERT) { ++ if (x->ex_nscert & NS_SMIME) ++ return 1; ++ /* Workaround for some buggy certificates */ ++ if (x->ex_nscert & NS_SSL_CLIENT) ++ return 2; ++ return 0; ++ } ++ return 1; ++} ++ ++static int check_purpose_smime_sign(const X509_PURPOSE *xp, const X509 *x, ++ int ca) ++{ ++ int ret; ++ ret = purpose_smime(x, ca); ++ if (!ret || ca) ++ return ret; ++ if (ku_reject(x, KU_DIGITAL_SIGNATURE | KU_NON_REPUDIATION)) ++ return 0; ++ return ret; ++} ++ ++static int check_purpose_smime_encrypt(const X509_PURPOSE *xp, const X509 *x, ++ int ca) ++{ ++ int ret; ++ ret = purpose_smime(x, ca); ++ if (!ret || ca) ++ return ret; ++ if (ku_reject(x, KU_KEY_ENCIPHERMENT)) ++ return 0; ++ return ret; ++} ++ ++static int check_purpose_crl_sign(const X509_PURPOSE *xp, const X509 *x, ++ int ca) ++{ ++ if (ca) { ++ int ca_ret; ++ if ((ca_ret = check_ca(x)) != 2) ++ return ca_ret; ++ else ++ return 0; ++ } ++ if (ku_reject(x, KU_CRL_SIGN)) ++ return 0; ++ return 1; ++} ++ ++/* ++ * OCSP helper: this is *not* a full OCSP check. It just checks that each CA ++ * is valid. Additional checks must be made on the chain. ++ */ ++ ++static int ocsp_helper(const X509_PURPOSE *xp, const X509 *x, int ca) ++{ ++ /* ++ * Must be a valid CA. Should we really support the "I don't know" value ++ * (2)? ++ */ ++ if (ca) ++ return check_ca(x); ++ /* leaf certificate is checked in OCSP_verify() */ ++ return 1; ++} ++ ++static int check_purpose_timestamp_sign(const X509_PURPOSE *xp, const X509 *x, ++ int ca) ++{ ++ int i_ext; ++ ++ /* If ca is true we must return if this is a valid CA certificate. */ ++ if (ca) ++ return check_ca(x); ++ ++ /* ++ * Check the optional key usage field: ++ * if Key Usage is present, it must be one of digitalSignature ++ * and/or nonRepudiation (other values are not consistent and shall ++ * be rejected). ++ */ ++ if ((x->ex_flags & EXFLAG_KUSAGE) ++ && ((x->ex_kusage & ~(KU_NON_REPUDIATION | KU_DIGITAL_SIGNATURE)) || ++ !(x->ex_kusage & (KU_NON_REPUDIATION | KU_DIGITAL_SIGNATURE)))) ++ return 0; ++ ++ /* Only time stamp key usage is permitted and it's required. */ ++ if (!(x->ex_flags & EXFLAG_XKUSAGE) || x->ex_xkusage != XKU_TIMESTAMP) ++ return 0; ++ ++ /* Extended Key Usage MUST be critical */ ++ i_ext = X509_get_ext_by_NID(x, NID_ext_key_usage, -1); ++ if (i_ext >= 0) { ++ X509_EXTENSION *ext = X509_get_ext((X509 *)x, i_ext); ++ if (!X509_EXTENSION_get_critical(ext)) ++ return 0; ++ } ++ ++ return 1; ++} ++ ++static int no_check(const X509_PURPOSE *xp, const X509 *x, int ca) ++{ ++ return 1; ++} ++ ++/*- ++ * Various checks to see if one certificate issued the second. ++ * This can be used to prune a set of possible issuer certificates ++ * which have been looked up using some simple method such as by ++ * subject name. ++ * These are: ++ * 1. Check issuer_name(subject) == subject_name(issuer) ++ * 2. If akid(subject) exists check it matches issuer ++ * 3. If key_usage(issuer) exists check it supports certificate signing ++ * returns 0 for OK, positive for reason for mismatch, reasons match ++ * codes for X509_verify_cert() ++ */ ++ ++int X509_check_issued(X509 *issuer, X509 *subject) ++{ ++ if (X509_NAME_cmp(X509_get_subject_name(issuer), ++ X509_get_issuer_name(subject))) ++ return X509_V_ERR_SUBJECT_ISSUER_MISMATCH; ++ x509v3_cache_extensions(issuer); ++ x509v3_cache_extensions(subject); ++ ++ if (subject->akid) { ++ int ret = X509_check_akid(issuer, subject->akid); ++ if (ret != X509_V_OK) ++ return ret; ++ } ++ ++ if (subject->ex_flags & EXFLAG_PROXY) { ++ if (ku_reject(issuer, KU_DIGITAL_SIGNATURE)) ++ return X509_V_ERR_KEYUSAGE_NO_DIGITAL_SIGNATURE; ++ } else if (ku_reject(issuer, KU_KEY_CERT_SIGN)) ++ return X509_V_ERR_KEYUSAGE_NO_CERTSIGN; ++ return X509_V_OK; ++} ++ ++int X509_check_akid(X509 *issuer, AUTHORITY_KEYID *akid) ++{ ++ ++ if (!akid) ++ return X509_V_OK; ++ ++ /* Check key ids (if present) */ ++ if (akid->keyid && issuer->skid && ++ ASN1_OCTET_STRING_cmp(akid->keyid, issuer->skid)) ++ return X509_V_ERR_AKID_SKID_MISMATCH; ++ /* Check serial number */ ++ if (akid->serial && ++ ASN1_INTEGER_cmp(X509_get_serialNumber(issuer), akid->serial)) ++ return X509_V_ERR_AKID_ISSUER_SERIAL_MISMATCH; ++ /* Check issuer name */ ++ if (akid->issuer) { ++ /* ++ * Ugh, for some peculiar reason AKID includes SEQUENCE OF ++ * GeneralName. So look for a DirName. There may be more than one but ++ * we only take any notice of the first. ++ */ ++ GENERAL_NAMES *gens; ++ GENERAL_NAME *gen; ++ X509_NAME *nm = NULL; ++ int i; ++ gens = akid->issuer; ++ for (i = 0; i < sk_GENERAL_NAME_num(gens); i++) { ++ gen = sk_GENERAL_NAME_value(gens, i); ++ if (gen->type == GEN_DIRNAME) { ++ nm = gen->d.dirn; ++ break; ++ } ++ } ++ if (nm && X509_NAME_cmp(nm, X509_get_issuer_name(issuer))) ++ return X509_V_ERR_AKID_ISSUER_SERIAL_MISMATCH; ++ } ++ return X509_V_OK; ++} ++ ++uint32_t X509_get_extension_flags(X509 *x) ++{ ++ /* Call for side-effect of computing hash and caching extensions */ ++ X509_check_purpose(x, -1, -1); ++ return x->ex_flags; ++} ++ ++uint32_t X509_get_key_usage(X509 *x) ++{ ++ /* Call for side-effect of computing hash and caching extensions */ ++ X509_check_purpose(x, -1, -1); ++ if (x->ex_flags & EXFLAG_KUSAGE) ++ return x->ex_kusage; ++ return UINT32_MAX; ++} ++ ++uint32_t X509_get_extended_key_usage(X509 *x) ++{ ++ /* Call for side-effect of computing hash and caching extensions */ ++ X509_check_purpose(x, -1, -1); ++ if (x->ex_flags & EXFLAG_XKUSAGE) ++ return x->ex_xkusage; ++ return UINT32_MAX; ++} ++ ++const ASN1_OCTET_STRING *X509_get0_subject_key_id(X509 *x) ++{ ++ /* Call for side-effect of computing hash and caching extensions */ ++ X509_check_purpose(x, -1, -1); ++ return x->skid; ++} ++ ++long X509_get_pathlen(X509 *x) ++{ ++ /* Called for side effect of caching extensions */ ++ if (X509_check_purpose(x, -1, -1) != 1 ++ || (x->ex_flags & EXFLAG_BCONS) == 0) ++ return -1; ++ return x->ex_pathlen; ++} ++ ++long X509_get_proxy_pathlen(X509 *x) ++{ ++ /* Called for side effect of caching extensions */ ++ if (X509_check_purpose(x, -1, -1) != 1 ++ || (x->ex_flags & EXFLAG_PROXY) == 0) ++ return -1; ++ return x->ex_pcpathlen; ++} +diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/x509v3/v3_skey.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/x509v3/v3_skey.c +new file mode 100644 +index 0000000..39597dc +--- /dev/null ++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/x509v3/v3_skey.c +@@ -0,0 +1,106 @@ ++/* ++ * Copyright 1999-2016 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 ++ * in the file LICENSE in the source distribution or at ++ * https://www.openssl.org/source/license.html ++ */ ++ ++#include ++#include "internal/cryptlib.h" ++#include ++#include "internal/x509_int.h" ++#include "ext_dat.h" ++ ++static ASN1_OCTET_STRING *s2i_skey_id(X509V3_EXT_METHOD *method, ++ X509V3_CTX *ctx, char *str); ++const X509V3_EXT_METHOD v3_skey_id = { ++ NID_subject_key_identifier, 0, ASN1_ITEM_ref(ASN1_OCTET_STRING), ++ 0, 0, 0, 0, ++ (X509V3_EXT_I2S)i2s_ASN1_OCTET_STRING, ++ (X509V3_EXT_S2I)s2i_skey_id, ++ 0, 0, 0, 0, ++ NULL ++}; ++ ++char *i2s_ASN1_OCTET_STRING(X509V3_EXT_METHOD *method, ++ const ASN1_OCTET_STRING *oct) ++{ ++ return OPENSSL_buf2hexstr(oct->data, oct->length); ++} ++ ++ASN1_OCTET_STRING *s2i_ASN1_OCTET_STRING(X509V3_EXT_METHOD *method, ++ X509V3_CTX *ctx, const char *str) ++{ ++ ASN1_OCTET_STRING *oct; ++ long length; ++ ++ if ((oct = ASN1_OCTET_STRING_new()) == NULL) { ++ X509V3err(X509V3_F_S2I_ASN1_OCTET_STRING, ERR_R_MALLOC_FAILURE); ++ return NULL; ++ } ++ ++ if ((oct->data = OPENSSL_hexstr2buf(str, &length)) == NULL) { ++ ASN1_OCTET_STRING_free(oct); ++ return NULL; ++ } ++ ++ oct->length = length; ++ ++ return oct; ++ ++} ++ ++static ASN1_OCTET_STRING *s2i_skey_id(X509V3_EXT_METHOD *method, ++ X509V3_CTX *ctx, char *str) ++{ ++ ASN1_OCTET_STRING *oct; ++ X509_PUBKEY *pubkey; ++ const unsigned char *pk; ++ int pklen; ++ unsigned char pkey_dig[EVP_MAX_MD_SIZE]; ++ unsigned int diglen; ++ ++ if (strcmp(str, "hash")) ++ return s2i_ASN1_OCTET_STRING(method, ctx, str); ++ ++ if ((oct = ASN1_OCTET_STRING_new()) == NULL) { ++ X509V3err(X509V3_F_S2I_SKEY_ID, ERR_R_MALLOC_FAILURE); ++ return NULL; ++ } ++ ++ if (ctx && (ctx->flags == CTX_TEST)) ++ return oct; ++ ++ if (!ctx || (!ctx->subject_req && !ctx->subject_cert)) { ++ X509V3err(X509V3_F_S2I_SKEY_ID, X509V3_R_NO_PUBLIC_KEY); ++ goto err; ++ } ++ ++ if (ctx->subject_req) ++ pubkey = ctx->subject_req->req_info.pubkey; ++ else ++ pubkey = ctx->subject_cert->cert_info.key; ++ ++ if (pubkey == NULL) { ++ X509V3err(X509V3_F_S2I_SKEY_ID, X509V3_R_NO_PUBLIC_KEY); ++ goto err; ++ } ++ ++ X509_PUBKEY_get0_param(NULL, &pk, &pklen, NULL, pubkey); ++ ++ if (!EVP_Digest(pk, pklen, pkey_dig, &diglen, EVP_sha1(), NULL)) ++ goto err; ++ ++ if (!ASN1_OCTET_STRING_set(oct, pkey_dig, diglen)) { ++ X509V3err(X509V3_F_S2I_SKEY_ID, ERR_R_MALLOC_FAILURE); ++ goto err; ++ } ++ ++ return oct; ++ ++ err: ++ ASN1_OCTET_STRING_free(oct); ++ return NULL; ++} +diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/x509v3/v3_sxnet.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/x509v3/v3_sxnet.c +new file mode 100644 +index 0000000..89cda01 +--- /dev/null ++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/x509v3/v3_sxnet.c +@@ -0,0 +1,226 @@ ++/* ++ * Copyright 1999-2016 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 ++ * in the file LICENSE in the source distribution or at ++ * https://www.openssl.org/source/license.html ++ */ ++ ++#include ++#include "internal/cryptlib.h" ++#include ++#include ++#include ++#include ++#include "ext_dat.h" ++ ++/* Support for Thawte strong extranet extension */ ++ ++#define SXNET_TEST ++ ++static int sxnet_i2r(X509V3_EXT_METHOD *method, SXNET *sx, BIO *out, ++ int indent); ++#ifdef SXNET_TEST ++static SXNET *sxnet_v2i(X509V3_EXT_METHOD *method, X509V3_CTX *ctx, ++ STACK_OF(CONF_VALUE) *nval); ++#endif ++const X509V3_EXT_METHOD v3_sxnet = { ++ NID_sxnet, X509V3_EXT_MULTILINE, ASN1_ITEM_ref(SXNET), ++ 0, 0, 0, 0, ++ 0, 0, ++ 0, ++#ifdef SXNET_TEST ++ (X509V3_EXT_V2I)sxnet_v2i, ++#else ++ 0, ++#endif ++ (X509V3_EXT_I2R)sxnet_i2r, ++ 0, ++ NULL ++}; ++ ++ASN1_SEQUENCE(SXNETID) = { ++ ASN1_SIMPLE(SXNETID, zone, ASN1_INTEGER), ++ ASN1_SIMPLE(SXNETID, user, ASN1_OCTET_STRING) ++} ASN1_SEQUENCE_END(SXNETID) ++ ++IMPLEMENT_ASN1_FUNCTIONS(SXNETID) ++ ++ASN1_SEQUENCE(SXNET) = { ++ ASN1_SIMPLE(SXNET, version, ASN1_INTEGER), ++ ASN1_SEQUENCE_OF(SXNET, ids, SXNETID) ++} ASN1_SEQUENCE_END(SXNET) ++ ++IMPLEMENT_ASN1_FUNCTIONS(SXNET) ++ ++static int sxnet_i2r(X509V3_EXT_METHOD *method, SXNET *sx, BIO *out, ++ int indent) ++{ ++ long v; ++ char *tmp; ++ SXNETID *id; ++ int i; ++ v = ASN1_INTEGER_get(sx->version); ++ BIO_printf(out, "%*sVersion: %ld (0x%lX)", indent, "", v + 1, v); ++ for (i = 0; i < sk_SXNETID_num(sx->ids); i++) { ++ id = sk_SXNETID_value(sx->ids, i); ++ tmp = i2s_ASN1_INTEGER(NULL, id->zone); ++ BIO_printf(out, "\n%*sZone: %s, User: ", indent, "", tmp); ++ OPENSSL_free(tmp); ++ ASN1_STRING_print(out, id->user); ++ } ++ return 1; ++} ++ ++#ifdef SXNET_TEST ++ ++/* ++ * NBB: this is used for testing only. It should *not* be used for anything ++ * else because it will just take static IDs from the configuration file and ++ * they should really be separate values for each user. ++ */ ++ ++static SXNET *sxnet_v2i(X509V3_EXT_METHOD *method, X509V3_CTX *ctx, ++ STACK_OF(CONF_VALUE) *nval) ++{ ++ CONF_VALUE *cnf; ++ SXNET *sx = NULL; ++ int i; ++ for (i = 0; i < sk_CONF_VALUE_num(nval); i++) { ++ cnf = sk_CONF_VALUE_value(nval, i); ++ if (!SXNET_add_id_asc(&sx, cnf->name, cnf->value, -1)) ++ return NULL; ++ } ++ return sx; ++} ++ ++#endif ++ ++/* Strong Extranet utility functions */ ++ ++/* Add an id given the zone as an ASCII number */ ++ ++int SXNET_add_id_asc(SXNET **psx, const char *zone, const char *user, int userlen) ++{ ++ ASN1_INTEGER *izone; ++ ++ if ((izone = s2i_ASN1_INTEGER(NULL, zone)) == NULL) { ++ X509V3err(X509V3_F_SXNET_ADD_ID_ASC, X509V3_R_ERROR_CONVERTING_ZONE); ++ return 0; ++ } ++ return SXNET_add_id_INTEGER(psx, izone, user, userlen); ++} ++ ++/* Add an id given the zone as an unsigned long */ ++ ++int SXNET_add_id_ulong(SXNET **psx, unsigned long lzone, const char *user, ++ int userlen) ++{ ++ ASN1_INTEGER *izone; ++ ++ if ((izone = ASN1_INTEGER_new()) == NULL ++ || !ASN1_INTEGER_set(izone, lzone)) { ++ X509V3err(X509V3_F_SXNET_ADD_ID_ULONG, ERR_R_MALLOC_FAILURE); ++ ASN1_INTEGER_free(izone); ++ return 0; ++ } ++ return SXNET_add_id_INTEGER(psx, izone, user, userlen); ++ ++} ++ ++/* ++ * Add an id given the zone as an ASN1_INTEGER. Note this version uses the ++ * passed integer and doesn't make a copy so don't free it up afterwards. ++ */ ++ ++int SXNET_add_id_INTEGER(SXNET **psx, ASN1_INTEGER *zone, const char *user, ++ int userlen) ++{ ++ SXNET *sx = NULL; ++ SXNETID *id = NULL; ++ if (!psx || !zone || !user) { ++ X509V3err(X509V3_F_SXNET_ADD_ID_INTEGER, ++ X509V3_R_INVALID_NULL_ARGUMENT); ++ return 0; ++ } ++ if (userlen == -1) ++ userlen = strlen(user); ++ if (userlen > 64) { ++ X509V3err(X509V3_F_SXNET_ADD_ID_INTEGER, X509V3_R_USER_TOO_LONG); ++ return 0; ++ } ++ if (*psx == NULL) { ++ if ((sx = SXNET_new()) == NULL) ++ goto err; ++ if (!ASN1_INTEGER_set(sx->version, 0)) ++ goto err; ++ *psx = sx; ++ } else ++ sx = *psx; ++ if (SXNET_get_id_INTEGER(sx, zone)) { ++ X509V3err(X509V3_F_SXNET_ADD_ID_INTEGER, X509V3_R_DUPLICATE_ZONE_ID); ++ return 0; ++ } ++ ++ if ((id = SXNETID_new()) == NULL) ++ goto err; ++ if (userlen == -1) ++ userlen = strlen(user); ++ ++ if (!ASN1_OCTET_STRING_set(id->user, (const unsigned char *)user, userlen)) ++ goto err; ++ if (!sk_SXNETID_push(sx->ids, id)) ++ goto err; ++ id->zone = zone; ++ return 1; ++ ++ err: ++ X509V3err(X509V3_F_SXNET_ADD_ID_INTEGER, ERR_R_MALLOC_FAILURE); ++ SXNETID_free(id); ++ SXNET_free(sx); ++ *psx = NULL; ++ return 0; ++} ++ ++ASN1_OCTET_STRING *SXNET_get_id_asc(SXNET *sx, const char *zone) ++{ ++ ASN1_INTEGER *izone; ++ ASN1_OCTET_STRING *oct; ++ ++ if ((izone = s2i_ASN1_INTEGER(NULL, zone)) == NULL) { ++ X509V3err(X509V3_F_SXNET_GET_ID_ASC, X509V3_R_ERROR_CONVERTING_ZONE); ++ return NULL; ++ } ++ oct = SXNET_get_id_INTEGER(sx, izone); ++ ASN1_INTEGER_free(izone); ++ return oct; ++} ++ ++ASN1_OCTET_STRING *SXNET_get_id_ulong(SXNET *sx, unsigned long lzone) ++{ ++ ASN1_INTEGER *izone; ++ ASN1_OCTET_STRING *oct; ++ ++ if ((izone = ASN1_INTEGER_new()) == NULL ++ || !ASN1_INTEGER_set(izone, lzone)) { ++ X509V3err(X509V3_F_SXNET_GET_ID_ULONG, ERR_R_MALLOC_FAILURE); ++ ASN1_INTEGER_free(izone); ++ return NULL; ++ } ++ oct = SXNET_get_id_INTEGER(sx, izone); ++ ASN1_INTEGER_free(izone); ++ return oct; ++} ++ ++ASN1_OCTET_STRING *SXNET_get_id_INTEGER(SXNET *sx, ASN1_INTEGER *zone) ++{ ++ SXNETID *id; ++ int i; ++ for (i = 0; i < sk_SXNETID_num(sx->ids); i++) { ++ id = sk_SXNETID_value(sx->ids, i); ++ if (!ASN1_INTEGER_cmp(id->zone, zone)) ++ return id->user; ++ } ++ return NULL; ++} +diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/x509v3/v3_tlsf.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/x509v3/v3_tlsf.c +new file mode 100644 +index 0000000..fec6724 +--- /dev/null ++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/x509v3/v3_tlsf.c +@@ -0,0 +1,137 @@ ++/* ++ * Copyright 2015-2016 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 ++ * in the file LICENSE in the source distribution or at ++ * https://www.openssl.org/source/license.html ++ */ ++ ++#include ++#include "internal/cryptlib.h" ++#include "internal/o_str.h" ++#include ++#include ++#include ++#include "ext_dat.h" ++ ++static STACK_OF(CONF_VALUE) *i2v_TLS_FEATURE(const X509V3_EXT_METHOD *method, ++ TLS_FEATURE *tls_feature, ++ STACK_OF(CONF_VALUE) *ext_list); ++static TLS_FEATURE *v2i_TLS_FEATURE(const X509V3_EXT_METHOD *method, ++ X509V3_CTX *ctx, ++ STACK_OF(CONF_VALUE) *nval); ++ ++ASN1_ITEM_TEMPLATE(TLS_FEATURE) = ++ ASN1_EX_TEMPLATE_TYPE(ASN1_TFLG_SEQUENCE_OF, 0, TLS_FEATURE, ASN1_INTEGER) ++static_ASN1_ITEM_TEMPLATE_END(TLS_FEATURE) ++ ++IMPLEMENT_ASN1_ALLOC_FUNCTIONS(TLS_FEATURE) ++ ++const X509V3_EXT_METHOD v3_tls_feature = { ++ NID_tlsfeature, 0, ++ ASN1_ITEM_ref(TLS_FEATURE), ++ 0, 0, 0, 0, ++ 0, 0, ++ (X509V3_EXT_I2V)i2v_TLS_FEATURE, ++ (X509V3_EXT_V2I)v2i_TLS_FEATURE, ++ 0, 0, ++ NULL ++}; ++ ++ ++typedef struct { ++ long num; ++ const char *name; ++} TLS_FEATURE_NAME; ++ ++static TLS_FEATURE_NAME tls_feature_tbl[] = { ++ { 5, "status_request" }, ++ { 17, "status_request_v2" } ++}; ++ ++/* ++ * i2v_TLS_FEATURE converts the TLS_FEATURE structure tls_feature into the ++ * STACK_OF(CONF_VALUE) structure ext_list. STACK_OF(CONF_VALUE) is the format ++ * used by the CONF library to represent a multi-valued extension. ext_list is ++ * returned. ++ */ ++static STACK_OF(CONF_VALUE) *i2v_TLS_FEATURE(const X509V3_EXT_METHOD *method, ++ TLS_FEATURE *tls_feature, ++ STACK_OF(CONF_VALUE) *ext_list) ++{ ++ int i; ++ size_t j; ++ ASN1_INTEGER *ai; ++ long tlsextid; ++ for (i = 0; i < sk_ASN1_INTEGER_num(tls_feature); i++) { ++ ai = sk_ASN1_INTEGER_value(tls_feature, i); ++ tlsextid = ASN1_INTEGER_get(ai); ++ for (j = 0; j < OSSL_NELEM(tls_feature_tbl); j++) ++ if (tlsextid == tls_feature_tbl[j].num) ++ break; ++ if (j < OSSL_NELEM(tls_feature_tbl)) ++ X509V3_add_value(NULL, tls_feature_tbl[j].name, &ext_list); ++ else ++ X509V3_add_value_int(NULL, ai, &ext_list); ++ } ++ return ext_list; ++} ++ ++/* ++ * v2i_TLS_FEATURE converts the multi-valued extension nval into a TLS_FEATURE ++ * structure, which is returned if the conversion is successful. In case of ++ * error, NULL is returned. ++ */ ++static TLS_FEATURE *v2i_TLS_FEATURE(const X509V3_EXT_METHOD *method, ++ X509V3_CTX *ctx, STACK_OF(CONF_VALUE) *nval) ++{ ++ TLS_FEATURE *tlsf; ++ char *extval, *endptr; ++ ASN1_INTEGER *ai; ++ CONF_VALUE *val; ++ int i; ++ size_t j; ++ long tlsextid; ++ ++ if ((tlsf = sk_ASN1_INTEGER_new_null()) == NULL) { ++ X509V3err(X509V3_F_V2I_TLS_FEATURE, ERR_R_MALLOC_FAILURE); ++ return NULL; ++ } ++ ++ for (i = 0; i < sk_CONF_VALUE_num(nval); i++) { ++ val = sk_CONF_VALUE_value(nval, i); ++ if (val->value) ++ extval = val->value; ++ else ++ extval = val->name; ++ ++ for (j = 0; j < OSSL_NELEM(tls_feature_tbl); j++) ++ if (strcasecmp(extval, tls_feature_tbl[j].name) == 0) ++ break; ++ if (j < OSSL_NELEM(tls_feature_tbl)) ++ tlsextid = tls_feature_tbl[j].num; ++ else { ++ tlsextid = strtol(extval, &endptr, 10); ++ if (((*endptr) != '\0') || (extval == endptr) || (tlsextid < 0) || ++ (tlsextid > 65535)) { ++ X509V3err(X509V3_F_V2I_TLS_FEATURE, X509V3_R_INVALID_SYNTAX); ++ X509V3_conf_err(val); ++ goto err; ++ } ++ } ++ ++ ai = ASN1_INTEGER_new(); ++ if (ai == NULL) { ++ X509V3err(X509V3_F_V2I_TLS_FEATURE, ERR_R_MALLOC_FAILURE); ++ goto err; ++ } ++ ASN1_INTEGER_set(ai, tlsextid); ++ sk_ASN1_INTEGER_push(tlsf, ai); ++ } ++ return tlsf; ++ ++ err: ++ sk_ASN1_INTEGER_pop_free(tlsf, ASN1_INTEGER_free); ++ return NULL; ++} +diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/x509v3/v3_utl.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/x509v3/v3_utl.c +new file mode 100644 +index 0000000..7dc9a45 +--- /dev/null ++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/x509v3/v3_utl.c +@@ -0,0 +1,1195 @@ ++/* ++ * Copyright 1999-2016 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 ++ * in the file LICENSE in the source distribution or at ++ * https://www.openssl.org/source/license.html ++ */ ++ ++/* X509 v3 extension utilities */ ++ ++#include ++#include ++#include "internal/cryptlib.h" ++#include ++#include ++#include "internal/x509_int.h" ++#include ++#include "ext_dat.h" ++ ++static char *strip_spaces(char *name); ++static int sk_strcmp(const char *const *a, const char *const *b); ++static STACK_OF(OPENSSL_STRING) *get_email(X509_NAME *name, ++ GENERAL_NAMES *gens); ++static void str_free(OPENSSL_STRING str); ++static int append_ia5(STACK_OF(OPENSSL_STRING) **sk, const ASN1_IA5STRING *email); ++ ++static int ipv4_from_asc(unsigned char *v4, const char *in); ++static int ipv6_from_asc(unsigned char *v6, const char *in); ++static int ipv6_cb(const char *elem, int len, void *usr); ++static int ipv6_hex(unsigned char *out, const char *in, int inlen); ++ ++/* Add a CONF_VALUE name value pair to stack */ ++ ++int X509V3_add_value(const char *name, const char *value, ++ STACK_OF(CONF_VALUE) **extlist) ++{ ++ CONF_VALUE *vtmp = NULL; ++ char *tname = NULL, *tvalue = NULL; ++ ++ if (name && (tname = OPENSSL_strdup(name)) == NULL) ++ goto err; ++ if (value && (tvalue = OPENSSL_strdup(value)) == NULL) ++ goto err; ++ if ((vtmp = OPENSSL_malloc(sizeof(*vtmp))) == NULL) ++ goto err; ++ if (*extlist == NULL && (*extlist = sk_CONF_VALUE_new_null()) == NULL) ++ goto err; ++ vtmp->section = NULL; ++ vtmp->name = tname; ++ vtmp->value = tvalue; ++ if (!sk_CONF_VALUE_push(*extlist, vtmp)) ++ goto err; ++ return 1; ++ err: ++ X509V3err(X509V3_F_X509V3_ADD_VALUE, ERR_R_MALLOC_FAILURE); ++ OPENSSL_free(vtmp); ++ OPENSSL_free(tname); ++ OPENSSL_free(tvalue); ++ return 0; ++} ++ ++int X509V3_add_value_uchar(const char *name, const unsigned char *value, ++ STACK_OF(CONF_VALUE) **extlist) ++{ ++ return X509V3_add_value(name, (const char *)value, extlist); ++} ++ ++/* Free function for STACK_OF(CONF_VALUE) */ ++ ++void X509V3_conf_free(CONF_VALUE *conf) ++{ ++ if (!conf) ++ return; ++ OPENSSL_free(conf->name); ++ OPENSSL_free(conf->value); ++ OPENSSL_free(conf->section); ++ OPENSSL_free(conf); ++} ++ ++int X509V3_add_value_bool(const char *name, int asn1_bool, ++ STACK_OF(CONF_VALUE) **extlist) ++{ ++ if (asn1_bool) ++ return X509V3_add_value(name, "TRUE", extlist); ++ return X509V3_add_value(name, "FALSE", extlist); ++} ++ ++int X509V3_add_value_bool_nf(const char *name, int asn1_bool, ++ STACK_OF(CONF_VALUE) **extlist) ++{ ++ if (asn1_bool) ++ return X509V3_add_value(name, "TRUE", extlist); ++ return 1; ++} ++ ++char *i2s_ASN1_ENUMERATED(X509V3_EXT_METHOD *method, const ASN1_ENUMERATED *a) ++{ ++ BIGNUM *bntmp = NULL; ++ char *strtmp = NULL; ++ ++ if (!a) ++ return NULL; ++ if ((bntmp = ASN1_ENUMERATED_to_BN(a, NULL)) == NULL ++ || (strtmp = BN_bn2dec(bntmp)) == NULL) ++ X509V3err(X509V3_F_I2S_ASN1_ENUMERATED, ERR_R_MALLOC_FAILURE); ++ BN_free(bntmp); ++ return strtmp; ++} ++ ++char *i2s_ASN1_INTEGER(X509V3_EXT_METHOD *method, const ASN1_INTEGER *a) ++{ ++ BIGNUM *bntmp = NULL; ++ char *strtmp = NULL; ++ ++ if (!a) ++ return NULL; ++ if ((bntmp = ASN1_INTEGER_to_BN(a, NULL)) == NULL ++ || (strtmp = BN_bn2dec(bntmp)) == NULL) ++ X509V3err(X509V3_F_I2S_ASN1_INTEGER, ERR_R_MALLOC_FAILURE); ++ BN_free(bntmp); ++ return strtmp; ++} ++ ++ASN1_INTEGER *s2i_ASN1_INTEGER(X509V3_EXT_METHOD *method, const char *value) ++{ ++ BIGNUM *bn = NULL; ++ ASN1_INTEGER *aint; ++ int isneg, ishex; ++ int ret; ++ if (value == NULL) { ++ X509V3err(X509V3_F_S2I_ASN1_INTEGER, X509V3_R_INVALID_NULL_VALUE); ++ return NULL; ++ } ++ bn = BN_new(); ++ if (bn == NULL) { ++ X509V3err(X509V3_F_S2I_ASN1_INTEGER, ERR_R_MALLOC_FAILURE); ++ return NULL; ++ } ++ if (value[0] == '-') { ++ value++; ++ isneg = 1; ++ } else ++ isneg = 0; ++ ++ if (value[0] == '0' && ((value[1] == 'x') || (value[1] == 'X'))) { ++ value += 2; ++ ishex = 1; ++ } else ++ ishex = 0; ++ ++ if (ishex) ++ ret = BN_hex2bn(&bn, value); ++ else ++ ret = BN_dec2bn(&bn, value); ++ ++ if (!ret || value[ret]) { ++ BN_free(bn); ++ X509V3err(X509V3_F_S2I_ASN1_INTEGER, X509V3_R_BN_DEC2BN_ERROR); ++ return NULL; ++ } ++ ++ if (isneg && BN_is_zero(bn)) ++ isneg = 0; ++ ++ aint = BN_to_ASN1_INTEGER(bn, NULL); ++ BN_free(bn); ++ if (!aint) { ++ X509V3err(X509V3_F_S2I_ASN1_INTEGER, ++ X509V3_R_BN_TO_ASN1_INTEGER_ERROR); ++ return NULL; ++ } ++ if (isneg) ++ aint->type |= V_ASN1_NEG; ++ return aint; ++} ++ ++int X509V3_add_value_int(const char *name, const ASN1_INTEGER *aint, ++ STACK_OF(CONF_VALUE) **extlist) ++{ ++ char *strtmp; ++ int ret; ++ ++ if (!aint) ++ return 1; ++ if ((strtmp = i2s_ASN1_INTEGER(NULL, aint)) == NULL) ++ return 0; ++ ret = X509V3_add_value(name, strtmp, extlist); ++ OPENSSL_free(strtmp); ++ return ret; ++} ++ ++int X509V3_get_value_bool(const CONF_VALUE *value, int *asn1_bool) ++{ ++ const char *btmp; ++ ++ if ((btmp = value->value) == NULL) ++ goto err; ++ if (strcmp(btmp, "TRUE") == 0 ++ || strcmp(btmp, "true") == 0 ++ || strcmp(btmp, "Y") == 0 ++ || strcmp(btmp, "y") == 0 ++ || strcmp(btmp, "YES") == 0 ++ || strcmp(btmp, "yes") == 0) { ++ *asn1_bool = 0xff; ++ return 1; ++ } ++ if (strcmp(btmp, "FALSE") == 0 ++ || strcmp(btmp, "false") == 0 ++ || strcmp(btmp, "N") == 0 ++ || strcmp(btmp, "n") == 0 ++ || strcmp(btmp, "NO") == 0 ++ || strcmp(btmp, "no") == 0) { ++ *asn1_bool = 0; ++ return 1; ++ } ++ err: ++ X509V3err(X509V3_F_X509V3_GET_VALUE_BOOL, ++ X509V3_R_INVALID_BOOLEAN_STRING); ++ X509V3_conf_err(value); ++ return 0; ++} ++ ++int X509V3_get_value_int(const CONF_VALUE *value, ASN1_INTEGER **aint) ++{ ++ ASN1_INTEGER *itmp; ++ ++ if ((itmp = s2i_ASN1_INTEGER(NULL, value->value)) == NULL) { ++ X509V3_conf_err(value); ++ return 0; ++ } ++ *aint = itmp; ++ return 1; ++} ++ ++#define HDR_NAME 1 ++#define HDR_VALUE 2 ++ ++/* ++ * #define DEBUG ++ */ ++ ++STACK_OF(CONF_VALUE) *X509V3_parse_list(const char *line) ++{ ++ char *p, *q, c; ++ char *ntmp, *vtmp; ++ STACK_OF(CONF_VALUE) *values = NULL; ++ char *linebuf; ++ int state; ++ /* We are going to modify the line so copy it first */ ++ linebuf = OPENSSL_strdup(line); ++ if (linebuf == NULL) { ++ X509V3err(X509V3_F_X509V3_PARSE_LIST, ERR_R_MALLOC_FAILURE); ++ goto err; ++ } ++ state = HDR_NAME; ++ ntmp = NULL; ++ /* Go through all characters */ ++ for (p = linebuf, q = linebuf; (c = *p) && (c != '\r') && (c != '\n'); ++ p++) { ++ ++ switch (state) { ++ case HDR_NAME: ++ if (c == ':') { ++ state = HDR_VALUE; ++ *p = 0; ++ ntmp = strip_spaces(q); ++ if (!ntmp) { ++ X509V3err(X509V3_F_X509V3_PARSE_LIST, ++ X509V3_R_INVALID_NULL_NAME); ++ goto err; ++ } ++ q = p + 1; ++ } else if (c == ',') { ++ *p = 0; ++ ntmp = strip_spaces(q); ++ q = p + 1; ++ if (!ntmp) { ++ X509V3err(X509V3_F_X509V3_PARSE_LIST, ++ X509V3_R_INVALID_NULL_NAME); ++ goto err; ++ } ++ X509V3_add_value(ntmp, NULL, &values); ++ } ++ break; ++ ++ case HDR_VALUE: ++ if (c == ',') { ++ state = HDR_NAME; ++ *p = 0; ++ vtmp = strip_spaces(q); ++ if (!vtmp) { ++ X509V3err(X509V3_F_X509V3_PARSE_LIST, ++ X509V3_R_INVALID_NULL_VALUE); ++ goto err; ++ } ++ X509V3_add_value(ntmp, vtmp, &values); ++ ntmp = NULL; ++ q = p + 1; ++ } ++ ++ } ++ } ++ ++ if (state == HDR_VALUE) { ++ vtmp = strip_spaces(q); ++ if (!vtmp) { ++ X509V3err(X509V3_F_X509V3_PARSE_LIST, ++ X509V3_R_INVALID_NULL_VALUE); ++ goto err; ++ } ++ X509V3_add_value(ntmp, vtmp, &values); ++ } else { ++ ntmp = strip_spaces(q); ++ if (!ntmp) { ++ X509V3err(X509V3_F_X509V3_PARSE_LIST, X509V3_R_INVALID_NULL_NAME); ++ goto err; ++ } ++ X509V3_add_value(ntmp, NULL, &values); ++ } ++ OPENSSL_free(linebuf); ++ return values; ++ ++ err: ++ OPENSSL_free(linebuf); ++ sk_CONF_VALUE_pop_free(values, X509V3_conf_free); ++ return NULL; ++ ++} ++ ++/* Delete leading and trailing spaces from a string */ ++static char *strip_spaces(char *name) ++{ ++ char *p, *q; ++ /* Skip over leading spaces */ ++ p = name; ++ while (*p && isspace((unsigned char)*p)) ++ p++; ++ if (!*p) ++ return NULL; ++ q = p + strlen(p) - 1; ++ while ((q != p) && isspace((unsigned char)*q)) ++ q--; ++ if (p != q) ++ q[1] = 0; ++ if (!*p) ++ return NULL; ++ return p; ++} ++ ++ ++/* ++ * V2I name comparison function: returns zero if 'name' matches cmp or cmp.* ++ */ ++ ++int name_cmp(const char *name, const char *cmp) ++{ ++ int len, ret; ++ char c; ++ len = strlen(cmp); ++ if ((ret = strncmp(name, cmp, len))) ++ return ret; ++ c = name[len]; ++ if (!c || (c == '.')) ++ return 0; ++ return 1; ++} ++ ++static int sk_strcmp(const char *const *a, const char *const *b) ++{ ++ return strcmp(*a, *b); ++} ++ ++STACK_OF(OPENSSL_STRING) *X509_get1_email(X509 *x) ++{ ++ GENERAL_NAMES *gens; ++ STACK_OF(OPENSSL_STRING) *ret; ++ ++ gens = X509_get_ext_d2i(x, NID_subject_alt_name, NULL, NULL); ++ ret = get_email(X509_get_subject_name(x), gens); ++ sk_GENERAL_NAME_pop_free(gens, GENERAL_NAME_free); ++ return ret; ++} ++ ++STACK_OF(OPENSSL_STRING) *X509_get1_ocsp(X509 *x) ++{ ++ AUTHORITY_INFO_ACCESS *info; ++ STACK_OF(OPENSSL_STRING) *ret = NULL; ++ int i; ++ ++ info = X509_get_ext_d2i(x, NID_info_access, NULL, NULL); ++ if (!info) ++ return NULL; ++ for (i = 0; i < sk_ACCESS_DESCRIPTION_num(info); i++) { ++ ACCESS_DESCRIPTION *ad = sk_ACCESS_DESCRIPTION_value(info, i); ++ if (OBJ_obj2nid(ad->method) == NID_ad_OCSP) { ++ if (ad->location->type == GEN_URI) { ++ if (!append_ia5 ++ (&ret, ad->location->d.uniformResourceIdentifier)) ++ break; ++ } ++ } ++ } ++ AUTHORITY_INFO_ACCESS_free(info); ++ return ret; ++} ++ ++STACK_OF(OPENSSL_STRING) *X509_REQ_get1_email(X509_REQ *x) ++{ ++ GENERAL_NAMES *gens; ++ STACK_OF(X509_EXTENSION) *exts; ++ STACK_OF(OPENSSL_STRING) *ret; ++ ++ exts = X509_REQ_get_extensions(x); ++ gens = X509V3_get_d2i(exts, NID_subject_alt_name, NULL, NULL); ++ ret = get_email(X509_REQ_get_subject_name(x), gens); ++ sk_GENERAL_NAME_pop_free(gens, GENERAL_NAME_free); ++ sk_X509_EXTENSION_pop_free(exts, X509_EXTENSION_free); ++ return ret; ++} ++ ++static STACK_OF(OPENSSL_STRING) *get_email(X509_NAME *name, ++ GENERAL_NAMES *gens) ++{ ++ STACK_OF(OPENSSL_STRING) *ret = NULL; ++ X509_NAME_ENTRY *ne; ++ ASN1_IA5STRING *email; ++ GENERAL_NAME *gen; ++ int i; ++ /* Now add any email address(es) to STACK */ ++ i = -1; ++ /* First supplied X509_NAME */ ++ while ((i = X509_NAME_get_index_by_NID(name, ++ NID_pkcs9_emailAddress, i)) >= 0) { ++ ne = X509_NAME_get_entry(name, i); ++ email = X509_NAME_ENTRY_get_data(ne); ++ if (!append_ia5(&ret, email)) ++ return NULL; ++ } ++ for (i = 0; i < sk_GENERAL_NAME_num(gens); i++) { ++ gen = sk_GENERAL_NAME_value(gens, i); ++ if (gen->type != GEN_EMAIL) ++ continue; ++ if (!append_ia5(&ret, gen->d.ia5)) ++ return NULL; ++ } ++ return ret; ++} ++ ++static void str_free(OPENSSL_STRING str) ++{ ++ OPENSSL_free(str); ++} ++ ++static int append_ia5(STACK_OF(OPENSSL_STRING) **sk, const ASN1_IA5STRING *email) ++{ ++ char *emtmp; ++ /* First some sanity checks */ ++ if (email->type != V_ASN1_IA5STRING) ++ return 1; ++ if (!email->data || !email->length) ++ return 1; ++ if (*sk == NULL) ++ *sk = sk_OPENSSL_STRING_new(sk_strcmp); ++ if (*sk == NULL) ++ return 0; ++ /* Don't add duplicates */ ++ if (sk_OPENSSL_STRING_find(*sk, (char *)email->data) != -1) ++ return 1; ++ emtmp = OPENSSL_strdup((char *)email->data); ++ if (emtmp == NULL || !sk_OPENSSL_STRING_push(*sk, emtmp)) { ++ OPENSSL_free(emtmp); /* free on push failure */ ++ X509_email_free(*sk); ++ *sk = NULL; ++ return 0; ++ } ++ return 1; ++} ++ ++void X509_email_free(STACK_OF(OPENSSL_STRING) *sk) ++{ ++ sk_OPENSSL_STRING_pop_free(sk, str_free); ++} ++ ++typedef int (*equal_fn) (const unsigned char *pattern, size_t pattern_len, ++ const unsigned char *subject, size_t subject_len, ++ unsigned int flags); ++ ++/* Skip pattern prefix to match "wildcard" subject */ ++static void skip_prefix(const unsigned char **p, size_t *plen, ++ size_t subject_len, ++ unsigned int flags) ++{ ++ const unsigned char *pattern = *p; ++ size_t pattern_len = *plen; ++ ++ /* ++ * If subject starts with a leading '.' followed by more octets, and ++ * pattern is longer, compare just an equal-length suffix with the ++ * full subject (starting at the '.'), provided the prefix contains ++ * no NULs. ++ */ ++ if ((flags & _X509_CHECK_FLAG_DOT_SUBDOMAINS) == 0) ++ return; ++ ++ while (pattern_len > subject_len && *pattern) { ++ if ((flags & X509_CHECK_FLAG_SINGLE_LABEL_SUBDOMAINS) && ++ *pattern == '.') ++ break; ++ ++pattern; ++ --pattern_len; ++ } ++ ++ /* Skip if entire prefix acceptable */ ++ if (pattern_len == subject_len) { ++ *p = pattern; ++ *plen = pattern_len; ++ } ++} ++ ++/* Compare while ASCII ignoring case. */ ++static int equal_nocase(const unsigned char *pattern, size_t pattern_len, ++ const unsigned char *subject, size_t subject_len, ++ unsigned int flags) ++{ ++ skip_prefix(&pattern, &pattern_len, subject_len, flags); ++ if (pattern_len != subject_len) ++ return 0; ++ while (pattern_len) { ++ unsigned char l = *pattern; ++ unsigned char r = *subject; ++ /* The pattern must not contain NUL characters. */ ++ if (l == 0) ++ return 0; ++ if (l != r) { ++ if ('A' <= l && l <= 'Z') ++ l = (l - 'A') + 'a'; ++ if ('A' <= r && r <= 'Z') ++ r = (r - 'A') + 'a'; ++ if (l != r) ++ return 0; ++ } ++ ++pattern; ++ ++subject; ++ --pattern_len; ++ } ++ return 1; ++} ++ ++/* Compare using memcmp. */ ++static int equal_case(const unsigned char *pattern, size_t pattern_len, ++ const unsigned char *subject, size_t subject_len, ++ unsigned int flags) ++{ ++ skip_prefix(&pattern, &pattern_len, subject_len, flags); ++ if (pattern_len != subject_len) ++ return 0; ++ return !memcmp(pattern, subject, pattern_len); ++} ++ ++/* ++ * RFC 5280, section 7.5, requires that only the domain is compared in a ++ * case-insensitive manner. ++ */ ++static int equal_email(const unsigned char *a, size_t a_len, ++ const unsigned char *b, size_t b_len, ++ unsigned int unused_flags) ++{ ++ size_t i = a_len; ++ if (a_len != b_len) ++ return 0; ++ /* ++ * We search backwards for the '@' character, so that we do not have to ++ * deal with quoted local-parts. The domain part is compared in a ++ * case-insensitive manner. ++ */ ++ while (i > 0) { ++ --i; ++ if (a[i] == '@' || b[i] == '@') { ++ if (!equal_nocase(a + i, a_len - i, b + i, a_len - i, 0)) ++ return 0; ++ break; ++ } ++ } ++ if (i == 0) ++ i = a_len; ++ return equal_case(a, i, b, i, 0); ++} ++ ++/* ++ * Compare the prefix and suffix with the subject, and check that the ++ * characters in-between are valid. ++ */ ++static int wildcard_match(const unsigned char *prefix, size_t prefix_len, ++ const unsigned char *suffix, size_t suffix_len, ++ const unsigned char *subject, size_t subject_len, ++ unsigned int flags) ++{ ++ const unsigned char *wildcard_start; ++ const unsigned char *wildcard_end; ++ const unsigned char *p; ++ int allow_multi = 0; ++ int allow_idna = 0; ++ ++ if (subject_len < prefix_len + suffix_len) ++ return 0; ++ if (!equal_nocase(prefix, prefix_len, subject, prefix_len, flags)) ++ return 0; ++ wildcard_start = subject + prefix_len; ++ wildcard_end = subject + (subject_len - suffix_len); ++ if (!equal_nocase(wildcard_end, suffix_len, suffix, suffix_len, flags)) ++ return 0; ++ /* ++ * If the wildcard makes up the entire first label, it must match at ++ * least one character. ++ */ ++ if (prefix_len == 0 && *suffix == '.') { ++ if (wildcard_start == wildcard_end) ++ return 0; ++ allow_idna = 1; ++ if (flags & X509_CHECK_FLAG_MULTI_LABEL_WILDCARDS) ++ allow_multi = 1; ++ } ++ /* IDNA labels cannot match partial wildcards */ ++ if (!allow_idna && ++ subject_len >= 4 && strncasecmp((char *)subject, "xn--", 4) == 0) ++ return 0; ++ /* The wildcard may match a literal '*' */ ++ if (wildcard_end == wildcard_start + 1 && *wildcard_start == '*') ++ return 1; ++ /* ++ * Check that the part matched by the wildcard contains only ++ * permitted characters and only matches a single label unless ++ * allow_multi is set. ++ */ ++ for (p = wildcard_start; p != wildcard_end; ++p) ++ if (!(('0' <= *p && *p <= '9') || ++ ('A' <= *p && *p <= 'Z') || ++ ('a' <= *p && *p <= 'z') || ++ *p == '-' || (allow_multi && *p == '.'))) ++ return 0; ++ return 1; ++} ++ ++#define LABEL_START (1 << 0) ++#define LABEL_END (1 << 1) ++#define LABEL_HYPHEN (1 << 2) ++#define LABEL_IDNA (1 << 3) ++ ++static const unsigned char *valid_star(const unsigned char *p, size_t len, ++ unsigned int flags) ++{ ++ const unsigned char *star = 0; ++ size_t i; ++ int state = LABEL_START; ++ int dots = 0; ++ for (i = 0; i < len; ++i) { ++ /* ++ * Locate first and only legal wildcard, either at the start ++ * or end of a non-IDNA first and not final label. ++ */ ++ if (p[i] == '*') { ++ int atstart = (state & LABEL_START); ++ int atend = (i == len - 1 || p[i + 1] == '.'); ++ /*- ++ * At most one wildcard per pattern. ++ * No wildcards in IDNA labels. ++ * No wildcards after the first label. ++ */ ++ if (star != NULL || (state & LABEL_IDNA) != 0 || dots) ++ return NULL; ++ /* Only full-label '*.example.com' wildcards? */ ++ if ((flags & X509_CHECK_FLAG_NO_PARTIAL_WILDCARDS) ++ && (!atstart || !atend)) ++ return NULL; ++ /* No 'foo*bar' wildcards */ ++ if (!atstart && !atend) ++ return NULL; ++ star = &p[i]; ++ state &= ~LABEL_START; ++ } else if (('a' <= p[i] && p[i] <= 'z') ++ || ('A' <= p[i] && p[i] <= 'Z') ++ || ('0' <= p[i] && p[i] <= '9')) { ++ if ((state & LABEL_START) != 0 ++ && len - i >= 4 && strncasecmp((char *)&p[i], "xn--", 4) == 0) ++ state |= LABEL_IDNA; ++ state &= ~(LABEL_HYPHEN | LABEL_START); ++ } else if (p[i] == '.') { ++ if ((state & (LABEL_HYPHEN | LABEL_START)) != 0) ++ return NULL; ++ state = LABEL_START; ++ ++dots; ++ } else if (p[i] == '-') { ++ /* no domain/subdomain starts with '-' */ ++ if ((state & LABEL_START) != 0) ++ return NULL; ++ state |= LABEL_HYPHEN; ++ } else ++ return NULL; ++ } ++ ++ /* ++ * The final label must not end in a hyphen or ".", and ++ * there must be at least two dots after the star. ++ */ ++ if ((state & (LABEL_START | LABEL_HYPHEN)) != 0 || dots < 2) ++ return NULL; ++ return star; ++} ++ ++/* Compare using wildcards. */ ++static int equal_wildcard(const unsigned char *pattern, size_t pattern_len, ++ const unsigned char *subject, size_t subject_len, ++ unsigned int flags) ++{ ++ const unsigned char *star = NULL; ++ ++ /* ++ * Subject names starting with '.' can only match a wildcard pattern ++ * via a subject sub-domain pattern suffix match. ++ */ ++ if (!(subject_len > 1 && subject[0] == '.')) ++ star = valid_star(pattern, pattern_len, flags); ++ if (star == NULL) ++ return equal_nocase(pattern, pattern_len, ++ subject, subject_len, flags); ++ return wildcard_match(pattern, star - pattern, ++ star + 1, (pattern + pattern_len) - star - 1, ++ subject, subject_len, flags); ++} ++ ++/* ++ * Compare an ASN1_STRING to a supplied string. If they match return 1. If ++ * cmp_type > 0 only compare if string matches the type, otherwise convert it ++ * to UTF8. ++ */ ++ ++static int do_check_string(const ASN1_STRING *a, int cmp_type, equal_fn equal, ++ unsigned int flags, const char *b, size_t blen, ++ char **peername) ++{ ++ int rv = 0; ++ ++ if (!a->data || !a->length) ++ return 0; ++ if (cmp_type > 0) { ++ if (cmp_type != a->type) ++ return 0; ++ if (cmp_type == V_ASN1_IA5STRING) ++ rv = equal(a->data, a->length, (unsigned char *)b, blen, flags); ++ else if (a->length == (int)blen && !memcmp(a->data, b, blen)) ++ rv = 1; ++ if (rv > 0 && peername) ++ *peername = OPENSSL_strndup((char *)a->data, a->length); ++ } else { ++ int astrlen; ++ unsigned char *astr; ++ astrlen = ASN1_STRING_to_UTF8(&astr, a); ++ if (astrlen < 0) { ++ /* ++ * -1 could be an internal malloc failure or a decoding error from ++ * malformed input; we can't distinguish. ++ */ ++ return -1; ++ } ++ rv = equal(astr, astrlen, (unsigned char *)b, blen, flags); ++ if (rv > 0 && peername) ++ *peername = OPENSSL_strndup((char *)astr, astrlen); ++ OPENSSL_free(astr); ++ } ++ return rv; ++} ++ ++static int do_x509_check(X509 *x, const char *chk, size_t chklen, ++ unsigned int flags, int check_type, char **peername) ++{ ++ GENERAL_NAMES *gens = NULL; ++ X509_NAME *name = NULL; ++ int i; ++ int cnid = NID_undef; ++ int alt_type; ++ int san_present = 0; ++ int rv = 0; ++ equal_fn equal; ++ ++ /* See below, this flag is internal-only */ ++ flags &= ~_X509_CHECK_FLAG_DOT_SUBDOMAINS; ++ if (check_type == GEN_EMAIL) { ++ cnid = NID_pkcs9_emailAddress; ++ alt_type = V_ASN1_IA5STRING; ++ equal = equal_email; ++ } else if (check_type == GEN_DNS) { ++ cnid = NID_commonName; ++ /* Implicit client-side DNS sub-domain pattern */ ++ if (chklen > 1 && chk[0] == '.') ++ flags |= _X509_CHECK_FLAG_DOT_SUBDOMAINS; ++ alt_type = V_ASN1_IA5STRING; ++ if (flags & X509_CHECK_FLAG_NO_WILDCARDS) ++ equal = equal_nocase; ++ else ++ equal = equal_wildcard; ++ } else { ++ alt_type = V_ASN1_OCTET_STRING; ++ equal = equal_case; ++ } ++ ++ if (chklen == 0) ++ chklen = strlen(chk); ++ ++ gens = X509_get_ext_d2i(x, NID_subject_alt_name, NULL, NULL); ++ if (gens) { ++ for (i = 0; i < sk_GENERAL_NAME_num(gens); i++) { ++ GENERAL_NAME *gen; ++ ASN1_STRING *cstr; ++ gen = sk_GENERAL_NAME_value(gens, i); ++ if (gen->type != check_type) ++ continue; ++ san_present = 1; ++ if (check_type == GEN_EMAIL) ++ cstr = gen->d.rfc822Name; ++ else if (check_type == GEN_DNS) ++ cstr = gen->d.dNSName; ++ else ++ cstr = gen->d.iPAddress; ++ /* Positive on success, negative on error! */ ++ if ((rv = do_check_string(cstr, alt_type, equal, flags, ++ chk, chklen, peername)) != 0) ++ break; ++ } ++ GENERAL_NAMES_free(gens); ++ if (rv != 0) ++ return rv; ++ if (san_present && !(flags & X509_CHECK_FLAG_ALWAYS_CHECK_SUBJECT)) ++ return 0; ++ } ++ ++ /* We're done if CN-ID is not pertinent */ ++ if (cnid == NID_undef || (flags & X509_CHECK_FLAG_NEVER_CHECK_SUBJECT)) ++ return 0; ++ ++ i = -1; ++ name = X509_get_subject_name(x); ++ while ((i = X509_NAME_get_index_by_NID(name, cnid, i)) >= 0) { ++ const X509_NAME_ENTRY *ne = X509_NAME_get_entry(name, i); ++ const ASN1_STRING *str = X509_NAME_ENTRY_get_data(ne); ++ ++ /* Positive on success, negative on error! */ ++ if ((rv = do_check_string(str, -1, equal, flags, ++ chk, chklen, peername)) != 0) ++ return rv; ++ } ++ return 0; ++} ++ ++int X509_check_host(X509 *x, const char *chk, size_t chklen, ++ unsigned int flags, char **peername) ++{ ++ if (chk == NULL) ++ return -2; ++ /* ++ * Embedded NULs are disallowed, except as the last character of a ++ * string of length 2 or more (tolerate caller including terminating ++ * NUL in string length). ++ */ ++ if (chklen == 0) ++ chklen = strlen(chk); ++ else if (memchr(chk, '\0', chklen > 1 ? chklen - 1 : chklen)) ++ return -2; ++ if (chklen > 1 && chk[chklen - 1] == '\0') ++ --chklen; ++ return do_x509_check(x, chk, chklen, flags, GEN_DNS, peername); ++} ++ ++int X509_check_email(X509 *x, const char *chk, size_t chklen, ++ unsigned int flags) ++{ ++ if (chk == NULL) ++ return -2; ++ /* ++ * Embedded NULs are disallowed, except as the last character of a ++ * string of length 2 or more (tolerate caller including terminating ++ * NUL in string length). ++ */ ++ if (chklen == 0) ++ chklen = strlen((char *)chk); ++ else if (memchr(chk, '\0', chklen > 1 ? chklen - 1 : chklen)) ++ return -2; ++ if (chklen > 1 && chk[chklen - 1] == '\0') ++ --chklen; ++ return do_x509_check(x, chk, chklen, flags, GEN_EMAIL, NULL); ++} ++ ++int X509_check_ip(X509 *x, const unsigned char *chk, size_t chklen, ++ unsigned int flags) ++{ ++ if (chk == NULL) ++ return -2; ++ return do_x509_check(x, (char *)chk, chklen, flags, GEN_IPADD, NULL); ++} ++ ++int X509_check_ip_asc(X509 *x, const char *ipasc, unsigned int flags) ++{ ++ unsigned char ipout[16]; ++ size_t iplen; ++ ++ if (ipasc == NULL) ++ return -2; ++ iplen = (size_t)a2i_ipadd(ipout, ipasc); ++ if (iplen == 0) ++ return -2; ++ return do_x509_check(x, (char *)ipout, iplen, flags, GEN_IPADD, NULL); ++} ++ ++/* ++ * Convert IP addresses both IPv4 and IPv6 into an OCTET STRING compatible ++ * with RFC3280. ++ */ ++ ++ASN1_OCTET_STRING *a2i_IPADDRESS(const char *ipasc) ++{ ++ unsigned char ipout[16]; ++ ASN1_OCTET_STRING *ret; ++ int iplen; ++ ++ /* If string contains a ':' assume IPv6 */ ++ ++ iplen = a2i_ipadd(ipout, ipasc); ++ ++ if (!iplen) ++ return NULL; ++ ++ ret = ASN1_OCTET_STRING_new(); ++ if (ret == NULL) ++ return NULL; ++ if (!ASN1_OCTET_STRING_set(ret, ipout, iplen)) { ++ ASN1_OCTET_STRING_free(ret); ++ return NULL; ++ } ++ return ret; ++} ++ ++ASN1_OCTET_STRING *a2i_IPADDRESS_NC(const char *ipasc) ++{ ++ ASN1_OCTET_STRING *ret = NULL; ++ unsigned char ipout[32]; ++ char *iptmp = NULL, *p; ++ int iplen1, iplen2; ++ p = strchr(ipasc, '/'); ++ if (!p) ++ return NULL; ++ iptmp = OPENSSL_strdup(ipasc); ++ if (!iptmp) ++ return NULL; ++ p = iptmp + (p - ipasc); ++ *p++ = 0; ++ ++ iplen1 = a2i_ipadd(ipout, iptmp); ++ ++ if (!iplen1) ++ goto err; ++ ++ iplen2 = a2i_ipadd(ipout + iplen1, p); ++ ++ OPENSSL_free(iptmp); ++ iptmp = NULL; ++ ++ if (!iplen2 || (iplen1 != iplen2)) ++ goto err; ++ ++ ret = ASN1_OCTET_STRING_new(); ++ if (ret == NULL) ++ goto err; ++ if (!ASN1_OCTET_STRING_set(ret, ipout, iplen1 + iplen2)) ++ goto err; ++ ++ return ret; ++ ++ err: ++ OPENSSL_free(iptmp); ++ ASN1_OCTET_STRING_free(ret); ++ return NULL; ++} ++ ++int a2i_ipadd(unsigned char *ipout, const char *ipasc) ++{ ++ /* If string contains a ':' assume IPv6 */ ++ ++ if (strchr(ipasc, ':')) { ++ if (!ipv6_from_asc(ipout, ipasc)) ++ return 0; ++ return 16; ++ } else { ++ if (!ipv4_from_asc(ipout, ipasc)) ++ return 0; ++ return 4; ++ } ++} ++ ++static int ipv4_from_asc(unsigned char *v4, const char *in) ++{ ++ int a0, a1, a2, a3; ++ if (sscanf(in, "%d.%d.%d.%d", &a0, &a1, &a2, &a3) != 4) ++ return 0; ++ if ((a0 < 0) || (a0 > 255) || (a1 < 0) || (a1 > 255) ++ || (a2 < 0) || (a2 > 255) || (a3 < 0) || (a3 > 255)) ++ return 0; ++ v4[0] = a0; ++ v4[1] = a1; ++ v4[2] = a2; ++ v4[3] = a3; ++ return 1; ++} ++ ++typedef struct { ++ /* Temporary store for IPV6 output */ ++ unsigned char tmp[16]; ++ /* Total number of bytes in tmp */ ++ int total; ++ /* The position of a zero (corresponding to '::') */ ++ int zero_pos; ++ /* Number of zeroes */ ++ int zero_cnt; ++} IPV6_STAT; ++ ++static int ipv6_from_asc(unsigned char *v6, const char *in) ++{ ++ IPV6_STAT v6stat; ++ v6stat.total = 0; ++ v6stat.zero_pos = -1; ++ v6stat.zero_cnt = 0; ++ /* ++ * Treat the IPv6 representation as a list of values separated by ':'. ++ * The presence of a '::' will parse as one, two or three zero length ++ * elements. ++ */ ++ if (!CONF_parse_list(in, ':', 0, ipv6_cb, &v6stat)) ++ return 0; ++ ++ /* Now for some sanity checks */ ++ ++ if (v6stat.zero_pos == -1) { ++ /* If no '::' must have exactly 16 bytes */ ++ if (v6stat.total != 16) ++ return 0; ++ } else { ++ /* If '::' must have less than 16 bytes */ ++ if (v6stat.total == 16) ++ return 0; ++ /* More than three zeroes is an error */ ++ if (v6stat.zero_cnt > 3) ++ return 0; ++ /* Can only have three zeroes if nothing else present */ ++ else if (v6stat.zero_cnt == 3) { ++ if (v6stat.total > 0) ++ return 0; ++ } ++ /* Can only have two zeroes if at start or end */ ++ else if (v6stat.zero_cnt == 2) { ++ if ((v6stat.zero_pos != 0) ++ && (v6stat.zero_pos != v6stat.total)) ++ return 0; ++ } else ++ /* Can only have one zero if *not* start or end */ ++ { ++ if ((v6stat.zero_pos == 0) ++ || (v6stat.zero_pos == v6stat.total)) ++ return 0; ++ } ++ } ++ ++ /* Format result */ ++ ++ if (v6stat.zero_pos >= 0) { ++ /* Copy initial part */ ++ memcpy(v6, v6stat.tmp, v6stat.zero_pos); ++ /* Zero middle */ ++ memset(v6 + v6stat.zero_pos, 0, 16 - v6stat.total); ++ /* Copy final part */ ++ if (v6stat.total != v6stat.zero_pos) ++ memcpy(v6 + v6stat.zero_pos + 16 - v6stat.total, ++ v6stat.tmp + v6stat.zero_pos, ++ v6stat.total - v6stat.zero_pos); ++ } else ++ memcpy(v6, v6stat.tmp, 16); ++ ++ return 1; ++} ++ ++static int ipv6_cb(const char *elem, int len, void *usr) ++{ ++ IPV6_STAT *s = usr; ++ /* Error if 16 bytes written */ ++ if (s->total == 16) ++ return 0; ++ if (len == 0) { ++ /* Zero length element, corresponds to '::' */ ++ if (s->zero_pos == -1) ++ s->zero_pos = s->total; ++ /* If we've already got a :: its an error */ ++ else if (s->zero_pos != s->total) ++ return 0; ++ s->zero_cnt++; ++ } else { ++ /* If more than 4 characters could be final a.b.c.d form */ ++ if (len > 4) { ++ /* Need at least 4 bytes left */ ++ if (s->total > 12) ++ return 0; ++ /* Must be end of string */ ++ if (elem[len]) ++ return 0; ++ if (!ipv4_from_asc(s->tmp + s->total, elem)) ++ return 0; ++ s->total += 4; ++ } else { ++ if (!ipv6_hex(s->tmp + s->total, elem, len)) ++ return 0; ++ s->total += 2; ++ } ++ } ++ return 1; ++} ++ ++/* ++ * Convert a string of up to 4 hex digits into the corresponding IPv6 form. ++ */ ++ ++static int ipv6_hex(unsigned char *out, const char *in, int inlen) ++{ ++ unsigned char c; ++ unsigned int num = 0; ++ int x; ++ ++ if (inlen > 4) ++ return 0; ++ while (inlen--) { ++ c = *in++; ++ num <<= 4; ++ x = OPENSSL_hexchar2int(c); ++ if (x < 0) ++ return 0; ++ num |= (char)x; ++ } ++ out[0] = num >> 8; ++ out[1] = num & 0xff; ++ return 1; ++} ++ ++int X509V3_NAME_from_section(X509_NAME *nm, STACK_OF(CONF_VALUE) *dn_sk, ++ unsigned long chtype) ++{ ++ CONF_VALUE *v; ++ int i, mval, spec_char, plus_char; ++ char *p, *type; ++ if (!nm) ++ return 0; ++ ++ for (i = 0; i < sk_CONF_VALUE_num(dn_sk); i++) { ++ v = sk_CONF_VALUE_value(dn_sk, i); ++ type = v->name; ++ /* ++ * Skip past any leading X. X: X, etc to allow for multiple instances ++ */ ++ for (p = type; *p; p++) { ++#ifndef CHARSET_EBCDIC ++ spec_char = ((*p == ':') || (*p == ',') || (*p == '.')); ++#else ++ spec_char = ((*p == os_toascii[':']) || (*p == os_toascii[',']) ++ || (*p == os_toascii['.'])); ++#endif ++ if (spec_char) { ++ p++; ++ if (*p) ++ type = p; ++ break; ++ } ++ } ++#ifndef CHARSET_EBCDIC ++ plus_char = (*type == '+'); ++#else ++ plus_char = (*type == os_toascii['+']); ++#endif ++ if (plus_char) { ++ mval = -1; ++ type++; ++ } else ++ mval = 0; ++ if (!X509_NAME_add_entry_by_txt(nm, type, chtype, ++ (unsigned char *)v->value, -1, -1, ++ mval)) ++ return 0; ++ ++ } ++ return 1; ++} +diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/x509v3/v3conf.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/x509v3/v3conf.c +new file mode 100644 +index 0000000..966ab90 +--- /dev/null ++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/x509v3/v3conf.c +@@ -0,0 +1,79 @@ ++/* ++ * Copyright 1999-2016 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 ++ * in the file LICENSE in the source distribution or at ++ * https://www.openssl.org/source/license.html ++ */ ++ ++#include ++#include "internal/cryptlib.h" ++#include ++#include ++#include ++#include ++ ++/* Test application to add extensions from a config file */ ++ ++int main(int argc, char **argv) ++{ ++ LHASH *conf; ++ X509 *cert; ++ FILE *inf; ++ char *conf_file; ++ int i; ++ int count; ++ X509_EXTENSION *ext; ++ X509V3_add_standard_extensions(); ++ ERR_load_crypto_strings(); ++ if (!argv[1]) { ++ fprintf(stderr, "Usage: v3conf cert.pem [file.cnf]\n"); ++ exit(1); ++ } ++ conf_file = argv[2]; ++ if (!conf_file) ++ conf_file = "test.cnf"; ++ conf = CONF_load(NULL, "test.cnf", NULL); ++ if (!conf) { ++ fprintf(stderr, "Error opening Config file %s\n", conf_file); ++ ERR_print_errors_fp(stderr); ++ exit(1); ++ } ++ ++ inf = fopen(argv[1], "r"); ++ if (!inf) { ++ fprintf(stderr, "Can't open certificate file %s\n", argv[1]); ++ exit(1); ++ } ++ cert = PEM_read_X509(inf, NULL, NULL); ++ if (!cert) { ++ fprintf(stderr, "Error reading certificate file %s\n", argv[1]); ++ exit(1); ++ } ++ fclose(inf); ++ ++ sk_pop_free(cert->cert_info->extensions, X509_EXTENSION_free); ++ cert->cert_info->extensions = NULL; ++ ++ if (!X509V3_EXT_add_conf(conf, NULL, "test_section", cert)) { ++ fprintf(stderr, "Error adding extensions\n"); ++ ERR_print_errors_fp(stderr); ++ exit(1); ++ } ++ ++ count = X509_get_ext_count(cert); ++ printf("%d extensions\n", count); ++ for (i = 0; i < count; i++) { ++ ext = X509_get_ext(cert, i); ++ printf("%s", OBJ_nid2ln(OBJ_obj2nid(ext->object))); ++ if (ext->critical) ++ printf(",critical:\n"); ++ else ++ printf(":\n"); ++ X509V3_EXT_print_fp(stdout, ext, 0, 0); ++ printf("\n"); ++ ++ } ++ return 0; ++} +diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/x509v3/v3err.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/x509v3/v3err.c +new file mode 100644 +index 0000000..5d79c8c +--- /dev/null ++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/x509v3/v3err.c +@@ -0,0 +1,187 @@ ++/* ++ * Generated by util/mkerr.pl DO NOT EDIT ++ * Copyright 1995-2016 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 ++ * in the file LICENSE in the source distribution or at ++ * https://www.openssl.org/source/license.html ++ */ ++ ++#include ++#include ++#include ++ ++/* BEGIN ERROR CODES */ ++#ifndef OPENSSL_NO_ERR ++ ++# define ERR_FUNC(func) ERR_PACK(ERR_LIB_X509V3,func,0) ++# define ERR_REASON(reason) ERR_PACK(ERR_LIB_X509V3,0,reason) ++ ++static ERR_STRING_DATA X509V3_str_functs[] = { ++ {ERR_FUNC(X509V3_F_A2I_GENERAL_NAME), "a2i_GENERAL_NAME"}, ++ {ERR_FUNC(X509V3_F_ADDR_VALIDATE_PATH_INTERNAL), ++ "addr_validate_path_internal"}, ++ {ERR_FUNC(X509V3_F_ASIDENTIFIERCHOICE_CANONIZE), ++ "ASIdentifierChoice_canonize"}, ++ {ERR_FUNC(X509V3_F_ASIDENTIFIERCHOICE_IS_CANONICAL), ++ "ASIdentifierChoice_is_canonical"}, ++ {ERR_FUNC(X509V3_F_COPY_EMAIL), "copy_email"}, ++ {ERR_FUNC(X509V3_F_COPY_ISSUER), "copy_issuer"}, ++ {ERR_FUNC(X509V3_F_DO_DIRNAME), "do_dirname"}, ++ {ERR_FUNC(X509V3_F_DO_EXT_I2D), "do_ext_i2d"}, ++ {ERR_FUNC(X509V3_F_DO_EXT_NCONF), "do_ext_nconf"}, ++ {ERR_FUNC(X509V3_F_GNAMES_FROM_SECTNAME), "gnames_from_sectname"}, ++ {ERR_FUNC(X509V3_F_I2S_ASN1_ENUMERATED), "i2s_ASN1_ENUMERATED"}, ++ {ERR_FUNC(X509V3_F_I2S_ASN1_IA5STRING), "i2s_ASN1_IA5STRING"}, ++ {ERR_FUNC(X509V3_F_I2S_ASN1_INTEGER), "i2s_ASN1_INTEGER"}, ++ {ERR_FUNC(X509V3_F_I2V_AUTHORITY_INFO_ACCESS), ++ "i2v_AUTHORITY_INFO_ACCESS"}, ++ {ERR_FUNC(X509V3_F_NOTICE_SECTION), "notice_section"}, ++ {ERR_FUNC(X509V3_F_NREF_NOS), "nref_nos"}, ++ {ERR_FUNC(X509V3_F_POLICY_SECTION), "policy_section"}, ++ {ERR_FUNC(X509V3_F_PROCESS_PCI_VALUE), "process_pci_value"}, ++ {ERR_FUNC(X509V3_F_R2I_CERTPOL), "r2i_certpol"}, ++ {ERR_FUNC(X509V3_F_R2I_PCI), "r2i_pci"}, ++ {ERR_FUNC(X509V3_F_S2I_ASN1_IA5STRING), "s2i_ASN1_IA5STRING"}, ++ {ERR_FUNC(X509V3_F_S2I_ASN1_INTEGER), "s2i_ASN1_INTEGER"}, ++ {ERR_FUNC(X509V3_F_S2I_ASN1_OCTET_STRING), "s2i_ASN1_OCTET_STRING"}, ++ {ERR_FUNC(X509V3_F_S2I_SKEY_ID), "s2i_skey_id"}, ++ {ERR_FUNC(X509V3_F_SET_DIST_POINT_NAME), "set_dist_point_name"}, ++ {ERR_FUNC(X509V3_F_SXNET_ADD_ID_ASC), "SXNET_add_id_asc"}, ++ {ERR_FUNC(X509V3_F_SXNET_ADD_ID_INTEGER), "SXNET_add_id_INTEGER"}, ++ {ERR_FUNC(X509V3_F_SXNET_ADD_ID_ULONG), "SXNET_add_id_ulong"}, ++ {ERR_FUNC(X509V3_F_SXNET_GET_ID_ASC), "SXNET_get_id_asc"}, ++ {ERR_FUNC(X509V3_F_SXNET_GET_ID_ULONG), "SXNET_get_id_ulong"}, ++ {ERR_FUNC(X509V3_F_V2I_ASIDENTIFIERS), "v2i_ASIdentifiers"}, ++ {ERR_FUNC(X509V3_F_V2I_ASN1_BIT_STRING), "v2i_ASN1_BIT_STRING"}, ++ {ERR_FUNC(X509V3_F_V2I_AUTHORITY_INFO_ACCESS), ++ "v2i_AUTHORITY_INFO_ACCESS"}, ++ {ERR_FUNC(X509V3_F_V2I_AUTHORITY_KEYID), "v2i_AUTHORITY_KEYID"}, ++ {ERR_FUNC(X509V3_F_V2I_BASIC_CONSTRAINTS), "v2i_BASIC_CONSTRAINTS"}, ++ {ERR_FUNC(X509V3_F_V2I_CRLD), "v2i_crld"}, ++ {ERR_FUNC(X509V3_F_V2I_EXTENDED_KEY_USAGE), "v2i_EXTENDED_KEY_USAGE"}, ++ {ERR_FUNC(X509V3_F_V2I_GENERAL_NAMES), "v2i_GENERAL_NAMES"}, ++ {ERR_FUNC(X509V3_F_V2I_GENERAL_NAME_EX), "v2i_GENERAL_NAME_ex"}, ++ {ERR_FUNC(X509V3_F_V2I_IDP), "v2i_idp"}, ++ {ERR_FUNC(X509V3_F_V2I_IPADDRBLOCKS), "v2i_IPAddrBlocks"}, ++ {ERR_FUNC(X509V3_F_V2I_ISSUER_ALT), "v2i_issuer_alt"}, ++ {ERR_FUNC(X509V3_F_V2I_NAME_CONSTRAINTS), "v2i_NAME_CONSTRAINTS"}, ++ {ERR_FUNC(X509V3_F_V2I_POLICY_CONSTRAINTS), "v2i_POLICY_CONSTRAINTS"}, ++ {ERR_FUNC(X509V3_F_V2I_POLICY_MAPPINGS), "v2i_POLICY_MAPPINGS"}, ++ {ERR_FUNC(X509V3_F_V2I_SUBJECT_ALT), "v2i_subject_alt"}, ++ {ERR_FUNC(X509V3_F_V2I_TLS_FEATURE), "v2i_TLS_FEATURE"}, ++ {ERR_FUNC(X509V3_F_V3_GENERIC_EXTENSION), "v3_generic_extension"}, ++ {ERR_FUNC(X509V3_F_X509V3_ADD1_I2D), "X509V3_add1_i2d"}, ++ {ERR_FUNC(X509V3_F_X509V3_ADD_VALUE), "X509V3_add_value"}, ++ {ERR_FUNC(X509V3_F_X509V3_EXT_ADD), "X509V3_EXT_add"}, ++ {ERR_FUNC(X509V3_F_X509V3_EXT_ADD_ALIAS), "X509V3_EXT_add_alias"}, ++ {ERR_FUNC(X509V3_F_X509V3_EXT_I2D), "X509V3_EXT_i2d"}, ++ {ERR_FUNC(X509V3_F_X509V3_EXT_NCONF), "X509V3_EXT_nconf"}, ++ {ERR_FUNC(X509V3_F_X509V3_GET_SECTION), "X509V3_get_section"}, ++ {ERR_FUNC(X509V3_F_X509V3_GET_STRING), "X509V3_get_string"}, ++ {ERR_FUNC(X509V3_F_X509V3_GET_VALUE_BOOL), "X509V3_get_value_bool"}, ++ {ERR_FUNC(X509V3_F_X509V3_PARSE_LIST), "X509V3_parse_list"}, ++ {ERR_FUNC(X509V3_F_X509_PURPOSE_ADD), "X509_PURPOSE_add"}, ++ {ERR_FUNC(X509V3_F_X509_PURPOSE_SET), "X509_PURPOSE_set"}, ++ {0, NULL} ++}; ++ ++static ERR_STRING_DATA X509V3_str_reasons[] = { ++ {ERR_REASON(X509V3_R_BAD_IP_ADDRESS), "bad ip address"}, ++ {ERR_REASON(X509V3_R_BAD_OBJECT), "bad object"}, ++ {ERR_REASON(X509V3_R_BN_DEC2BN_ERROR), "bn dec2bn error"}, ++ {ERR_REASON(X509V3_R_BN_TO_ASN1_INTEGER_ERROR), ++ "bn to asn1 integer error"}, ++ {ERR_REASON(X509V3_R_DIRNAME_ERROR), "dirname error"}, ++ {ERR_REASON(X509V3_R_DISTPOINT_ALREADY_SET), "distpoint already set"}, ++ {ERR_REASON(X509V3_R_DUPLICATE_ZONE_ID), "duplicate zone id"}, ++ {ERR_REASON(X509V3_R_ERROR_CONVERTING_ZONE), "error converting zone"}, ++ {ERR_REASON(X509V3_R_ERROR_CREATING_EXTENSION), ++ "error creating extension"}, ++ {ERR_REASON(X509V3_R_ERROR_IN_EXTENSION), "error in extension"}, ++ {ERR_REASON(X509V3_R_EXPECTED_A_SECTION_NAME), "expected a section name"}, ++ {ERR_REASON(X509V3_R_EXTENSION_EXISTS), "extension exists"}, ++ {ERR_REASON(X509V3_R_EXTENSION_NAME_ERROR), "extension name error"}, ++ {ERR_REASON(X509V3_R_EXTENSION_NOT_FOUND), "extension not found"}, ++ {ERR_REASON(X509V3_R_EXTENSION_SETTING_NOT_SUPPORTED), ++ "extension setting not supported"}, ++ {ERR_REASON(X509V3_R_EXTENSION_VALUE_ERROR), "extension value error"}, ++ {ERR_REASON(X509V3_R_ILLEGAL_EMPTY_EXTENSION), "illegal empty extension"}, ++ {ERR_REASON(X509V3_R_INCORRECT_POLICY_SYNTAX_TAG), ++ "incorrect policy syntax tag"}, ++ {ERR_REASON(X509V3_R_INVALID_ASNUMBER), "invalid asnumber"}, ++ {ERR_REASON(X509V3_R_INVALID_ASRANGE), "invalid asrange"}, ++ {ERR_REASON(X509V3_R_INVALID_BOOLEAN_STRING), "invalid boolean string"}, ++ {ERR_REASON(X509V3_R_INVALID_EXTENSION_STRING), ++ "invalid extension string"}, ++ {ERR_REASON(X509V3_R_INVALID_INHERITANCE), "invalid inheritance"}, ++ {ERR_REASON(X509V3_R_INVALID_IPADDRESS), "invalid ipaddress"}, ++ {ERR_REASON(X509V3_R_INVALID_MULTIPLE_RDNS), "invalid multiple rdns"}, ++ {ERR_REASON(X509V3_R_INVALID_NAME), "invalid name"}, ++ {ERR_REASON(X509V3_R_INVALID_NULL_ARGUMENT), "invalid null argument"}, ++ {ERR_REASON(X509V3_R_INVALID_NULL_NAME), "invalid null name"}, ++ {ERR_REASON(X509V3_R_INVALID_NULL_VALUE), "invalid null value"}, ++ {ERR_REASON(X509V3_R_INVALID_NUMBER), "invalid number"}, ++ {ERR_REASON(X509V3_R_INVALID_NUMBERS), "invalid numbers"}, ++ {ERR_REASON(X509V3_R_INVALID_OBJECT_IDENTIFIER), ++ "invalid object identifier"}, ++ {ERR_REASON(X509V3_R_INVALID_OPTION), "invalid option"}, ++ {ERR_REASON(X509V3_R_INVALID_POLICY_IDENTIFIER), ++ "invalid policy identifier"}, ++ {ERR_REASON(X509V3_R_INVALID_PROXY_POLICY_SETTING), ++ "invalid proxy policy setting"}, ++ {ERR_REASON(X509V3_R_INVALID_PURPOSE), "invalid purpose"}, ++ {ERR_REASON(X509V3_R_INVALID_SAFI), "invalid safi"}, ++ {ERR_REASON(X509V3_R_INVALID_SECTION), "invalid section"}, ++ {ERR_REASON(X509V3_R_INVALID_SYNTAX), "invalid syntax"}, ++ {ERR_REASON(X509V3_R_ISSUER_DECODE_ERROR), "issuer decode error"}, ++ {ERR_REASON(X509V3_R_MISSING_VALUE), "missing value"}, ++ {ERR_REASON(X509V3_R_NEED_ORGANIZATION_AND_NUMBERS), ++ "need organization and numbers"}, ++ {ERR_REASON(X509V3_R_NO_CONFIG_DATABASE), "no config database"}, ++ {ERR_REASON(X509V3_R_NO_ISSUER_CERTIFICATE), "no issuer certificate"}, ++ {ERR_REASON(X509V3_R_NO_ISSUER_DETAILS), "no issuer details"}, ++ {ERR_REASON(X509V3_R_NO_POLICY_IDENTIFIER), "no policy identifier"}, ++ {ERR_REASON(X509V3_R_NO_PROXY_CERT_POLICY_LANGUAGE_DEFINED), ++ "no proxy cert policy language defined"}, ++ {ERR_REASON(X509V3_R_NO_PUBLIC_KEY), "no public key"}, ++ {ERR_REASON(X509V3_R_NO_SUBJECT_DETAILS), "no subject details"}, ++ {ERR_REASON(X509V3_R_OPERATION_NOT_DEFINED), "operation not defined"}, ++ {ERR_REASON(X509V3_R_OTHERNAME_ERROR), "othername error"}, ++ {ERR_REASON(X509V3_R_POLICY_LANGUAGE_ALREADY_DEFINED), ++ "policy language already defined"}, ++ {ERR_REASON(X509V3_R_POLICY_PATH_LENGTH), "policy path length"}, ++ {ERR_REASON(X509V3_R_POLICY_PATH_LENGTH_ALREADY_DEFINED), ++ "policy path length already defined"}, ++ {ERR_REASON(X509V3_R_POLICY_WHEN_PROXY_LANGUAGE_REQUIRES_NO_POLICY), ++ "policy when proxy language requires no policy"}, ++ {ERR_REASON(X509V3_R_SECTION_NOT_FOUND), "section not found"}, ++ {ERR_REASON(X509V3_R_UNABLE_TO_GET_ISSUER_DETAILS), ++ "unable to get issuer details"}, ++ {ERR_REASON(X509V3_R_UNABLE_TO_GET_ISSUER_KEYID), ++ "unable to get issuer keyid"}, ++ {ERR_REASON(X509V3_R_UNKNOWN_BIT_STRING_ARGUMENT), ++ "unknown bit string argument"}, ++ {ERR_REASON(X509V3_R_UNKNOWN_EXTENSION), "unknown extension"}, ++ {ERR_REASON(X509V3_R_UNKNOWN_EXTENSION_NAME), "unknown extension name"}, ++ {ERR_REASON(X509V3_R_UNKNOWN_OPTION), "unknown option"}, ++ {ERR_REASON(X509V3_R_UNSUPPORTED_OPTION), "unsupported option"}, ++ {ERR_REASON(X509V3_R_UNSUPPORTED_TYPE), "unsupported type"}, ++ {ERR_REASON(X509V3_R_USER_TOO_LONG), "user too long"}, ++ {0, NULL} ++}; ++ ++#endif ++ ++int ERR_load_X509V3_strings(void) ++{ ++#ifndef OPENSSL_NO_ERR ++ ++ if (ERR_func_error_string(X509V3_str_functs[0].error) == NULL) { ++ ERR_load_strings(0, X509V3_str_functs); ++ ERR_load_strings(0, X509V3_str_reasons); ++ } ++#endif ++ return 1; ++} +diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/x509v3/v3prin.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/x509v3/v3prin.c +new file mode 100644 +index 0000000..7431a4e +--- /dev/null ++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/x509v3/v3prin.c +@@ -0,0 +1,50 @@ ++/* ++ * Copyright 1999-2016 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 ++ * in the file LICENSE in the source distribution or at ++ * https://www.openssl.org/source/license.html ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++ ++int main(int argc, char **argv) ++{ ++ X509 *cert; ++ FILE *inf; ++ int i, count; ++ X509_EXTENSION *ext; ++ ++ X509V3_add_standard_extensions(); ++ ERR_load_crypto_strings(); ++ if (!argv[1]) { ++ fprintf(stderr, "Usage v3prin cert.pem\n"); ++ exit(1); ++ } ++ if ((inf = fopen(argv[1], "r")) == NULL) { ++ fprintf(stderr, "Can't open %s\n", argv[1]); ++ exit(1); ++ } ++ if ((cert = PEM_read_X509(inf, NULL, NULL)) == NULL) { ++ fprintf(stderr, "Can't read certificate %s\n", argv[1]); ++ ERR_print_errors_fp(stderr); ++ exit(1); ++ } ++ fclose(inf); ++ count = X509_get_ext_count(cert); ++ printf("%d extensions\n", count); ++ for (i = 0; i < count; i++) { ++ ext = X509_get_ext(cert, i); ++ printf("%s\n", OBJ_nid2ln(OBJ_obj2nid(ext->object))); ++ if (!X509V3_EXT_print_fp(stdout, ext, 0, 0)) ++ ERR_print_errors_fp(stderr); ++ printf("\n"); ++ ++ } ++ return 0; ++} +diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/x86_64cpuid.pl b/CryptoPkg/Library/OpensslLib/openssl/crypto/x86_64cpuid.pl +new file mode 100644 +index 0000000..6cb1521 +--- /dev/null ++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/x86_64cpuid.pl +@@ -0,0 +1,459 @@ ++#! /usr/bin/env perl ++# Copyright 2005-2016 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 ++# in the file LICENSE in the source distribution or at ++# https://www.openssl.org/source/license.html ++ ++ ++$flavour = shift; ++$output = shift; ++if ($flavour =~ /\./) { $output = $flavour; undef $flavour; } ++ ++$win64=0; $win64=1 if ($flavour =~ /[nm]asm|mingw64/ || $output =~ /\.asm$/); ++ ++$0 =~ m/(.*[\/\\])[^\/\\]+$/; $dir=$1; ++( $xlate="${dir}x86_64-xlate.pl" and -f $xlate ) or ++( $xlate="${dir}perlasm/x86_64-xlate.pl" and -f $xlate) or ++die "can't locate x86_64-xlate.pl"; ++ ++open OUT,"| \"$^X\" \"$xlate\" $flavour \"$output\""; ++*STDOUT=*OUT; ++ ++($arg1,$arg2,$arg3,$arg4)=$win64?("%rcx","%rdx","%r8", "%r9") : # Win64 order ++ ("%rdi","%rsi","%rdx","%rcx"); # Unix order ++ ++print<<___; ++.extern OPENSSL_cpuid_setup ++.hidden OPENSSL_cpuid_setup ++.section .init ++ call OPENSSL_cpuid_setup ++ ++.hidden OPENSSL_ia32cap_P ++.comm OPENSSL_ia32cap_P,16,4 ++ ++.text ++ ++.globl OPENSSL_atomic_add ++.type OPENSSL_atomic_add,\@abi-omnipotent ++.align 16 ++OPENSSL_atomic_add: ++ movl ($arg1),%eax ++.Lspin: leaq ($arg2,%rax),%r8 ++ .byte 0xf0 # lock ++ cmpxchgl %r8d,($arg1) ++ jne .Lspin ++ movl %r8d,%eax ++ .byte 0x48,0x98 # cltq/cdqe ++ ret ++.size OPENSSL_atomic_add,.-OPENSSL_atomic_add ++ ++.globl OPENSSL_rdtsc ++.type OPENSSL_rdtsc,\@abi-omnipotent ++.align 16 ++OPENSSL_rdtsc: ++ rdtsc ++ shl \$32,%rdx ++ or %rdx,%rax ++ ret ++.size OPENSSL_rdtsc,.-OPENSSL_rdtsc ++ ++.globl OPENSSL_ia32_cpuid ++.type OPENSSL_ia32_cpuid,\@function,1 ++.align 16 ++OPENSSL_ia32_cpuid: ++ mov %rbx,%r8 # save %rbx ++ ++ xor %eax,%eax ++ mov %eax,8(%rdi) # clear 3rd word ++ cpuid ++ mov %eax,%r11d # max value for standard query level ++ ++ xor %eax,%eax ++ cmp \$0x756e6547,%ebx # "Genu" ++ setne %al ++ mov %eax,%r9d ++ cmp \$0x49656e69,%edx # "ineI" ++ setne %al ++ or %eax,%r9d ++ cmp \$0x6c65746e,%ecx # "ntel" ++ setne %al ++ or %eax,%r9d # 0 indicates Intel CPU ++ jz .Lintel ++ ++ cmp \$0x68747541,%ebx # "Auth" ++ setne %al ++ mov %eax,%r10d ++ cmp \$0x69746E65,%edx # "enti" ++ setne %al ++ or %eax,%r10d ++ cmp \$0x444D4163,%ecx # "cAMD" ++ setne %al ++ or %eax,%r10d # 0 indicates AMD CPU ++ jnz .Lintel ++ ++ # AMD specific ++ mov \$0x80000000,%eax ++ cpuid ++ cmp \$0x80000001,%eax ++ jb .Lintel ++ mov %eax,%r10d ++ mov \$0x80000001,%eax ++ cpuid ++ or %ecx,%r9d ++ and \$0x00000801,%r9d # isolate AMD XOP bit, 1<<11 ++ ++ cmp \$0x80000008,%r10d ++ jb .Lintel ++ ++ mov \$0x80000008,%eax ++ cpuid ++ movzb %cl,%r10 # number of cores - 1 ++ inc %r10 # number of cores ++ ++ mov \$1,%eax ++ cpuid ++ bt \$28,%edx # test hyper-threading bit ++ jnc .Lgeneric ++ shr \$16,%ebx # number of logical processors ++ cmp %r10b,%bl ++ ja .Lgeneric ++ and \$0xefffffff,%edx # ~(1<<28) ++ jmp .Lgeneric ++ ++.Lintel: ++ cmp \$4,%r11d ++ mov \$-1,%r10d ++ jb .Lnocacheinfo ++ ++ mov \$4,%eax ++ mov \$0,%ecx # query L1D ++ cpuid ++ mov %eax,%r10d ++ shr \$14,%r10d ++ and \$0xfff,%r10d # number of cores -1 per L1D ++ ++ cmp \$7,%r11d ++ jb .Lnocacheinfo ++ ++ mov \$7,%eax ++ xor %ecx,%ecx ++ cpuid ++ mov %ebx,8(%rdi) ++ ++.Lnocacheinfo: ++ mov \$1,%eax ++ cpuid ++ and \$0xbfefffff,%edx # force reserved bits to 0 ++ cmp \$0,%r9d ++ jne .Lnotintel ++ or \$0x40000000,%edx # set reserved bit#30 on Intel CPUs ++ and \$15,%ah ++ cmp \$15,%ah # examine Family ID ++ jne .Lnotintel ++ or \$0x00100000,%edx # set reserved bit#20 to engage RC4_CHAR ++.Lnotintel: ++ bt \$28,%edx # test hyper-threading bit ++ jnc .Lgeneric ++ and \$0xefffffff,%edx # ~(1<<28) ++ cmp \$0,%r10d ++ je .Lgeneric ++ ++ or \$0x10000000,%edx # 1<<28 ++ shr \$16,%ebx ++ cmp \$1,%bl # see if cache is shared ++ ja .Lgeneric ++ and \$0xefffffff,%edx # ~(1<<28) ++.Lgeneric: ++ and \$0x00000800,%r9d # isolate AMD XOP flag ++ and \$0xfffff7ff,%ecx ++ or %ecx,%r9d # merge AMD XOP flag ++ ++ mov %edx,%r10d # %r9d:%r10d is copy of %ecx:%edx ++ bt \$27,%r9d # check OSXSAVE bit ++ jnc .Lclear_avx ++ xor %ecx,%ecx # XCR0 ++ .byte 0x0f,0x01,0xd0 # xgetbv ++ and \$6,%eax # isolate XMM and YMM state support ++ cmp \$6,%eax ++ je .Ldone ++.Lclear_avx: ++ mov \$0xefffe7ff,%eax # ~(1<<28|1<<12|1<<11) ++ and %eax,%r9d # clear AVX, FMA and AMD XOP bits ++ andl \$0xffffffdf,8(%rdi) # cleax AVX2, ~(1<<5) ++.Ldone: ++ shl \$32,%r9 ++ mov %r10d,%eax ++ mov %r8,%rbx # restore %rbx ++ or %r9,%rax ++ ret ++.size OPENSSL_ia32_cpuid,.-OPENSSL_ia32_cpuid ++ ++.globl OPENSSL_cleanse ++.type OPENSSL_cleanse,\@abi-omnipotent ++.align 16 ++OPENSSL_cleanse: ++ xor %rax,%rax ++ cmp \$15,$arg2 ++ jae .Lot ++ cmp \$0,$arg2 ++ je .Lret ++.Little: ++ mov %al,($arg1) ++ sub \$1,$arg2 ++ lea 1($arg1),$arg1 ++ jnz .Little ++.Lret: ++ ret ++.align 16 ++.Lot: ++ test \$7,$arg1 ++ jz .Laligned ++ mov %al,($arg1) ++ lea -1($arg2),$arg2 ++ lea 1($arg1),$arg1 ++ jmp .Lot ++.Laligned: ++ mov %rax,($arg1) ++ lea -8($arg2),$arg2 ++ test \$-8,$arg2 ++ lea 8($arg1),$arg1 ++ jnz .Laligned ++ cmp \$0,$arg2 ++ jne .Little ++ ret ++.size OPENSSL_cleanse,.-OPENSSL_cleanse ++ ++.globl CRYPTO_memcmp ++.type CRYPTO_memcmp,\@abi-omnipotent ++.align 16 ++CRYPTO_memcmp: ++ xor %rax,%rax ++ xor %r10,%r10 ++ cmp \$0,$arg3 ++ je .Lno_data ++.Loop_cmp: ++ mov ($arg1),%r10b ++ lea 1($arg1),$arg1 ++ xor ($arg2),%r10b ++ lea 1($arg2),$arg2 ++ or %r10b,%al ++ dec $arg3 ++ jnz .Loop_cmp ++ neg %rax ++ shr \$63,%rax ++.Lno_data: ++ ret ++.size CRYPTO_memcmp,.-CRYPTO_memcmp ++___ ++ ++print<<___ if (!$win64); ++.globl OPENSSL_wipe_cpu ++.type OPENSSL_wipe_cpu,\@abi-omnipotent ++.align 16 ++OPENSSL_wipe_cpu: ++ pxor %xmm0,%xmm0 ++ pxor %xmm1,%xmm1 ++ pxor %xmm2,%xmm2 ++ pxor %xmm3,%xmm3 ++ pxor %xmm4,%xmm4 ++ pxor %xmm5,%xmm5 ++ pxor %xmm6,%xmm6 ++ pxor %xmm7,%xmm7 ++ pxor %xmm8,%xmm8 ++ pxor %xmm9,%xmm9 ++ pxor %xmm10,%xmm10 ++ pxor %xmm11,%xmm11 ++ pxor %xmm12,%xmm12 ++ pxor %xmm13,%xmm13 ++ pxor %xmm14,%xmm14 ++ pxor %xmm15,%xmm15 ++ xorq %rcx,%rcx ++ xorq %rdx,%rdx ++ xorq %rsi,%rsi ++ xorq %rdi,%rdi ++ xorq %r8,%r8 ++ xorq %r9,%r9 ++ xorq %r10,%r10 ++ xorq %r11,%r11 ++ leaq 8(%rsp),%rax ++ ret ++.size OPENSSL_wipe_cpu,.-OPENSSL_wipe_cpu ++___ ++print<<___ if ($win64); ++.globl OPENSSL_wipe_cpu ++.type OPENSSL_wipe_cpu,\@abi-omnipotent ++.align 16 ++OPENSSL_wipe_cpu: ++ pxor %xmm0,%xmm0 ++ pxor %xmm1,%xmm1 ++ pxor %xmm2,%xmm2 ++ pxor %xmm3,%xmm3 ++ pxor %xmm4,%xmm4 ++ pxor %xmm5,%xmm5 ++ xorq %rcx,%rcx ++ xorq %rdx,%rdx ++ xorq %r8,%r8 ++ xorq %r9,%r9 ++ xorq %r10,%r10 ++ xorq %r11,%r11 ++ leaq 8(%rsp),%rax ++ ret ++.size OPENSSL_wipe_cpu,.-OPENSSL_wipe_cpu ++___ ++{ ++my $out="%r10"; ++my $cnt="%rcx"; ++my $max="%r11"; ++my $lasttick="%r8d"; ++my $lastdiff="%r9d"; ++my $redzone=win64?8:-8; ++ ++print<<___; ++.globl OPENSSL_instrument_bus ++.type OPENSSL_instrument_bus,\@abi-omnipotent ++.align 16 ++OPENSSL_instrument_bus: ++ mov $arg1,$out # tribute to Win64 ++ mov $arg2,$cnt ++ mov $arg2,$max ++ ++ rdtsc # collect 1st tick ++ mov %eax,$lasttick # lasttick = tick ++ mov \$0,$lastdiff # lastdiff = 0 ++ clflush ($out) ++ .byte 0xf0 # lock ++ add $lastdiff,($out) ++ jmp .Loop ++.align 16 ++.Loop: rdtsc ++ mov %eax,%edx ++ sub $lasttick,%eax ++ mov %edx,$lasttick ++ mov %eax,$lastdiff ++ clflush ($out) ++ .byte 0xf0 # lock ++ add %eax,($out) ++ lea 4($out),$out ++ sub \$1,$cnt ++ jnz .Loop ++ ++ mov $max,%rax ++ ret ++.size OPENSSL_instrument_bus,.-OPENSSL_instrument_bus ++ ++.globl OPENSSL_instrument_bus2 ++.type OPENSSL_instrument_bus2,\@abi-omnipotent ++.align 16 ++OPENSSL_instrument_bus2: ++ mov $arg1,$out # tribute to Win64 ++ mov $arg2,$cnt ++ mov $arg3,$max ++ mov $cnt,$redzone(%rsp) ++ ++ rdtsc # collect 1st tick ++ mov %eax,$lasttick # lasttick = tick ++ mov \$0,$lastdiff # lastdiff = 0 ++ ++ clflush ($out) ++ .byte 0xf0 # lock ++ add $lastdiff,($out) ++ ++ rdtsc # collect 1st diff ++ mov %eax,%edx ++ sub $lasttick,%eax # diff ++ mov %edx,$lasttick # lasttick = tick ++ mov %eax,$lastdiff # lastdiff = diff ++.Loop2: ++ clflush ($out) ++ .byte 0xf0 # lock ++ add %eax,($out) # accumulate diff ++ ++ sub \$1,$max ++ jz .Ldone2 ++ ++ rdtsc ++ mov %eax,%edx ++ sub $lasttick,%eax # diff ++ mov %edx,$lasttick # lasttick = tick ++ cmp $lastdiff,%eax ++ mov %eax,$lastdiff # lastdiff = diff ++ mov \$0,%edx ++ setne %dl ++ sub %rdx,$cnt # conditional --$cnt ++ lea ($out,%rdx,4),$out # conditional ++$out ++ jnz .Loop2 ++ ++.Ldone2: ++ mov $redzone(%rsp),%rax ++ sub $cnt,%rax ++ ret ++.size OPENSSL_instrument_bus2,.-OPENSSL_instrument_bus2 ++___ ++} ++ ++sub gen_random { ++my $rdop = shift; ++print<<___; ++.globl OPENSSL_ia32_${rdop} ++.type OPENSSL_ia32_${rdop},\@abi-omnipotent ++.align 16 ++OPENSSL_ia32_${rdop}: ++ mov \$8,%ecx ++.Loop_${rdop}: ++ ${rdop} %rax ++ jc .Lbreak_${rdop} ++ loop .Loop_${rdop} ++.Lbreak_${rdop}: ++ cmp \$0,%rax ++ cmove %rcx,%rax ++ ret ++.size OPENSSL_ia32_${rdop},.-OPENSSL_ia32_${rdop} ++ ++.globl OPENSSL_ia32_${rdop}_bytes ++.type OPENSSL_ia32_${rdop}_bytes,\@abi-omnipotent ++.align 16 ++OPENSSL_ia32_${rdop}_bytes: ++ xor %rax, %rax # return value ++ cmp \$0,$arg2 ++ je .Ldone_${rdop}_bytes ++ ++ mov \$8,%r11 ++.Loop_${rdop}_bytes: ++ ${rdop} %r10 ++ jc .Lbreak_${rdop}_bytes ++ dec %r11 ++ jnz .Loop_${rdop}_bytes ++ jmp .Ldone_${rdop}_bytes ++ ++.align 16 ++.Lbreak_${rdop}_bytes: ++ cmp \$8,$arg2 ++ jb .Ltail_${rdop}_bytes ++ mov %r10,($arg1) ++ lea 8($arg1),$arg1 ++ add \$8,%rax ++ sub \$8,$arg2 ++ jz .Ldone_${rdop}_bytes ++ mov \$8,%r11 ++ jmp .Loop_${rdop}_bytes ++ ++.align 16 ++.Ltail_${rdop}_bytes: ++ mov %r10b,($arg1) ++ lea 1($arg1),$arg1 ++ inc %rax ++ shr \$8,%r8 ++ dec $arg2 ++ jnz .Ltail_${rdop}_bytes ++ ++.Ldone_${rdop}_bytes: ++ ret ++.size OPENSSL_ia32_${rdop}_bytes,.-OPENSSL_ia32_${rdop}_bytes ++___ ++} ++gen_random("rdrand"); ++gen_random("rdseed"); ++ ++close STDOUT; # flush +diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/x86cpuid.pl b/CryptoPkg/Library/OpensslLib/openssl/crypto/x86cpuid.pl +new file mode 100644 +index 0000000..c45b183 +--- /dev/null ++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/x86cpuid.pl +@@ -0,0 +1,561 @@ ++#! /usr/bin/env perl ++# Copyright 2004-2016 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 ++# in the file LICENSE in the source distribution or at ++# https://www.openssl.org/source/license.html ++ ++$0 =~ m/(.*[\/\\])[^\/\\]+$/; $dir=$1; ++push(@INC, "${dir}perlasm", "perlasm"); ++require "x86asm.pl"; ++ ++$output = pop; ++open OUT,">$output"; ++*STDOUT=*OUT; ++ ++&asm_init($ARGV[0],"x86cpuid"); ++ ++for (@ARGV) { $sse2=1 if (/-DOPENSSL_IA32_SSE2/); } ++ ++&function_begin("OPENSSL_ia32_cpuid"); ++ &xor ("edx","edx"); ++ &pushf (); ++ &pop ("eax"); ++ &mov ("ecx","eax"); ++ &xor ("eax",1<<21); ++ &push ("eax"); ++ &popf (); ++ &pushf (); ++ &pop ("eax"); ++ &xor ("ecx","eax"); ++ &xor ("eax","eax"); ++ &bt ("ecx",21); ++ &jnc (&label("nocpuid")); ++ &mov ("esi",&wparam(0)); ++ &mov (&DWP(8,"esi"),"eax"); # clear 3rd word ++ &cpuid (); ++ &mov ("edi","eax"); # max value for standard query level ++ ++ &xor ("eax","eax"); ++ &cmp ("ebx",0x756e6547); # "Genu" ++ &setne (&LB("eax")); ++ &mov ("ebp","eax"); ++ &cmp ("edx",0x49656e69); # "ineI" ++ &setne (&LB("eax")); ++ &or ("ebp","eax"); ++ &cmp ("ecx",0x6c65746e); # "ntel" ++ &setne (&LB("eax")); ++ &or ("ebp","eax"); # 0 indicates Intel CPU ++ &jz (&label("intel")); ++ ++ &cmp ("ebx",0x68747541); # "Auth" ++ &setne (&LB("eax")); ++ &mov ("esi","eax"); ++ &cmp ("edx",0x69746E65); # "enti" ++ &setne (&LB("eax")); ++ &or ("esi","eax"); ++ &cmp ("ecx",0x444D4163); # "cAMD" ++ &setne (&LB("eax")); ++ &or ("esi","eax"); # 0 indicates AMD CPU ++ &jnz (&label("intel")); ++ ++ # AMD specific ++ &mov ("eax",0x80000000); ++ &cpuid (); ++ &cmp ("eax",0x80000001); ++ &jb (&label("intel")); ++ &mov ("esi","eax"); ++ &mov ("eax",0x80000001); ++ &cpuid (); ++ &or ("ebp","ecx"); ++ &and ("ebp",1<<11|1); # isolate XOP bit ++ &cmp ("esi",0x80000008); ++ &jb (&label("intel")); ++ ++ &mov ("eax",0x80000008); ++ &cpuid (); ++ &movz ("esi",&LB("ecx")); # number of cores - 1 ++ &inc ("esi"); # number of cores ++ ++ &mov ("eax",1); ++ &xor ("ecx","ecx"); ++ &cpuid (); ++ &bt ("edx",28); ++ &jnc (&label("generic")); ++ &shr ("ebx",16); ++ &and ("ebx",0xff); ++ &cmp ("ebx","esi"); ++ &ja (&label("generic")); ++ &and ("edx",0xefffffff); # clear hyper-threading bit ++ &jmp (&label("generic")); ++ ++&set_label("intel"); ++ &cmp ("edi",7); ++ &jb (&label("cacheinfo")); ++ ++ &mov ("esi",&wparam(0)); ++ &mov ("eax",7); ++ &xor ("ecx","ecx"); ++ &cpuid (); ++ &mov (&DWP(8,"esi"),"ebx"); ++ ++&set_label("cacheinfo"); ++ &cmp ("edi",4); ++ &mov ("edi",-1); ++ &jb (&label("nocacheinfo")); ++ ++ &mov ("eax",4); ++ &mov ("ecx",0); # query L1D ++ &cpuid (); ++ &mov ("edi","eax"); ++ &shr ("edi",14); ++ &and ("edi",0xfff); # number of cores -1 per L1D ++ ++&set_label("nocacheinfo"); ++ &mov ("eax",1); ++ &xor ("ecx","ecx"); ++ &cpuid (); ++ &and ("edx",0xbfefffff); # force reserved bits #20, #30 to 0 ++ &cmp ("ebp",0); ++ &jne (&label("notintel")); ++ &or ("edx",1<<30); # set reserved bit#30 on Intel CPUs ++ &and (&HB("eax"),15); # familiy ID ++ &cmp (&HB("eax"),15); # P4? ++ &jne (&label("notintel")); ++ &or ("edx",1<<20); # set reserved bit#20 to engage RC4_CHAR ++&set_label("notintel"); ++ &bt ("edx",28); # test hyper-threading bit ++ &jnc (&label("generic")); ++ &and ("edx",0xefffffff); ++ &cmp ("edi",0); ++ &je (&label("generic")); ++ ++ &or ("edx",0x10000000); ++ &shr ("ebx",16); ++ &cmp (&LB("ebx"),1); ++ &ja (&label("generic")); ++ &and ("edx",0xefffffff); # clear hyper-threading bit if not ++ ++&set_label("generic"); ++ &and ("ebp",1<<11); # isolate AMD XOP flag ++ &and ("ecx",0xfffff7ff); # force 11th bit to 0 ++ &mov ("esi","edx"); ++ &or ("ebp","ecx"); # merge AMD XOP flag ++ ++ &bt ("ecx",27); # check OSXSAVE bit ++ &jnc (&label("clear_avx")); ++ &xor ("ecx","ecx"); ++ &data_byte(0x0f,0x01,0xd0); # xgetbv ++ &and ("eax",6); ++ &cmp ("eax",6); ++ &je (&label("done")); ++ &cmp ("eax",2); ++ &je (&label("clear_avx")); ++&set_label("clear_xmm"); ++ &and ("ebp",0xfdfffffd); # clear AESNI and PCLMULQDQ bits ++ &and ("esi",0xfeffffff); # clear FXSR ++&set_label("clear_avx"); ++ &and ("ebp",0xefffe7ff); # clear AVX, FMA and AMD XOP bits ++ &mov ("edi",&wparam(0)); ++ &and (&DWP(8,"edi"),0xffffffdf); # clear AVX2 ++&set_label("done"); ++ &mov ("eax","esi"); ++ &mov ("edx","ebp"); ++&set_label("nocpuid"); ++&function_end("OPENSSL_ia32_cpuid"); ++ ++&external_label("OPENSSL_ia32cap_P"); ++ ++&function_begin_B("OPENSSL_rdtsc","EXTRN\t_OPENSSL_ia32cap_P:DWORD"); ++ &xor ("eax","eax"); ++ &xor ("edx","edx"); ++ &picmeup("ecx","OPENSSL_ia32cap_P"); ++ &bt (&DWP(0,"ecx"),4); ++ &jnc (&label("notsc")); ++ &rdtsc (); ++&set_label("notsc"); ++ &ret (); ++&function_end_B("OPENSSL_rdtsc"); ++ ++# This works in Ring 0 only [read DJGPP+MS-DOS+privileged DPMI host], ++# but it's safe to call it on any [supported] 32-bit platform... ++# Just check for [non-]zero return value... ++&function_begin_B("OPENSSL_instrument_halt","EXTRN\t_OPENSSL_ia32cap_P:DWORD"); ++ &picmeup("ecx","OPENSSL_ia32cap_P"); ++ &bt (&DWP(0,"ecx"),4); ++ &jnc (&label("nohalt")); # no TSC ++ ++ &data_word(0x9058900e); # push %cs; pop %eax ++ &and ("eax",3); ++ &jnz (&label("nohalt")); # not enough privileges ++ ++ &pushf (); ++ &pop ("eax"); ++ &bt ("eax",9); ++ &jnc (&label("nohalt")); # interrupts are disabled ++ ++ &rdtsc (); ++ &push ("edx"); ++ &push ("eax"); ++ &halt (); ++ &rdtsc (); ++ ++ &sub ("eax",&DWP(0,"esp")); ++ &sbb ("edx",&DWP(4,"esp")); ++ &add ("esp",8); ++ &ret (); ++ ++&set_label("nohalt"); ++ &xor ("eax","eax"); ++ &xor ("edx","edx"); ++ &ret (); ++&function_end_B("OPENSSL_instrument_halt"); ++ ++# Essentially there is only one use for this function. Under DJGPP: ++# ++# #include ++# ... ++# i=OPENSSL_far_spin(_dos_ds,0x46c); ++# ... ++# to obtain the number of spins till closest timer interrupt. ++ ++&function_begin_B("OPENSSL_far_spin"); ++ &pushf (); ++ &pop ("eax"); ++ &bt ("eax",9); ++ &jnc (&label("nospin")); # interrupts are disabled ++ ++ &mov ("eax",&DWP(4,"esp")); ++ &mov ("ecx",&DWP(8,"esp")); ++ &data_word (0x90d88e1e); # push %ds, mov %eax,%ds ++ &xor ("eax","eax"); ++ &mov ("edx",&DWP(0,"ecx")); ++ &jmp (&label("spin")); ++ ++ &align (16); ++&set_label("spin"); ++ &inc ("eax"); ++ &cmp ("edx",&DWP(0,"ecx")); ++ &je (&label("spin")); ++ ++ &data_word (0x1f909090); # pop %ds ++ &ret (); ++ ++&set_label("nospin"); ++ &xor ("eax","eax"); ++ &xor ("edx","edx"); ++ &ret (); ++&function_end_B("OPENSSL_far_spin"); ++ ++&function_begin_B("OPENSSL_wipe_cpu","EXTRN\t_OPENSSL_ia32cap_P:DWORD"); ++ &xor ("eax","eax"); ++ &xor ("edx","edx"); ++ &picmeup("ecx","OPENSSL_ia32cap_P"); ++ &mov ("ecx",&DWP(0,"ecx")); ++ &bt (&DWP(0,"ecx"),1); ++ &jnc (&label("no_x87")); ++ if ($sse2) { ++ &and ("ecx",1<<26|1<<24); # check SSE2 and FXSR bits ++ &cmp ("ecx",1<<26|1<<24); ++ &jne (&label("no_sse2")); ++ &pxor ("xmm0","xmm0"); ++ &pxor ("xmm1","xmm1"); ++ &pxor ("xmm2","xmm2"); ++ &pxor ("xmm3","xmm3"); ++ &pxor ("xmm4","xmm4"); ++ &pxor ("xmm5","xmm5"); ++ &pxor ("xmm6","xmm6"); ++ &pxor ("xmm7","xmm7"); ++ &set_label("no_sse2"); ++ } ++ # just a bunch of fldz to zap the fp/mm bank followed by finit... ++ &data_word(0xeed9eed9,0xeed9eed9,0xeed9eed9,0xeed9eed9,0x90e3db9b); ++&set_label("no_x87"); ++ &lea ("eax",&DWP(4,"esp")); ++ &ret (); ++&function_end_B("OPENSSL_wipe_cpu"); ++ ++&function_begin_B("OPENSSL_atomic_add"); ++ &mov ("edx",&DWP(4,"esp")); # fetch the pointer, 1st arg ++ &mov ("ecx",&DWP(8,"esp")); # fetch the increment, 2nd arg ++ &push ("ebx"); ++ &nop (); ++ &mov ("eax",&DWP(0,"edx")); ++&set_label("spin"); ++ &lea ("ebx",&DWP(0,"eax","ecx")); ++ &nop (); ++ &data_word(0x1ab10ff0); # lock; cmpxchg %ebx,(%edx) # %eax is envolved and is always reloaded ++ &jne (&label("spin")); ++ &mov ("eax","ebx"); # OpenSSL expects the new value ++ &pop ("ebx"); ++ &ret (); ++&function_end_B("OPENSSL_atomic_add"); ++ ++# This function can become handy under Win32 in situations when ++# we don't know which calling convention, __stdcall or __cdecl(*), ++# indirect callee is using. In C it can be deployed as ++# ++#ifdef OPENSSL_CPUID_OBJ ++# type OPENSSL_indirect_call(void *f,...); ++# ... ++# OPENSSL_indirect_call(func,[up to $max arguments]); ++#endif ++# ++# (*) it's designed to work even for __fastcall if number of ++# arguments is 1 or 2! ++&function_begin_B("OPENSSL_indirect_call"); ++ { ++ my ($max,$i)=(7,); # $max has to be chosen as 4*n-1 ++ # in order to preserve eventual ++ # stack alignment ++ &push ("ebp"); ++ &mov ("ebp","esp"); ++ &sub ("esp",$max*4); ++ &mov ("ecx",&DWP(12,"ebp")); ++ &mov (&DWP(0,"esp"),"ecx"); ++ &mov ("edx",&DWP(16,"ebp")); ++ &mov (&DWP(4,"esp"),"edx"); ++ for($i=2;$i<$max;$i++) ++ { ++ # Some copies will be redundant/bogus... ++ &mov ("eax",&DWP(12+$i*4,"ebp")); ++ &mov (&DWP(0+$i*4,"esp"),"eax"); ++ } ++ &call_ptr (&DWP(8,"ebp"));# make the call... ++ &mov ("esp","ebp"); # ... and just restore the stack pointer ++ # without paying attention to what we called, ++ # (__cdecl *func) or (__stdcall *one). ++ &pop ("ebp"); ++ &ret (); ++ } ++&function_end_B("OPENSSL_indirect_call"); ++ ++&function_begin_B("OPENSSL_cleanse"); ++ &mov ("edx",&wparam(0)); ++ &mov ("ecx",&wparam(1)); ++ &xor ("eax","eax"); ++ &cmp ("ecx",7); ++ &jae (&label("lot")); ++ &cmp ("ecx",0); ++ &je (&label("ret")); ++&set_label("little"); ++ &mov (&BP(0,"edx"),"al"); ++ &sub ("ecx",1); ++ &lea ("edx",&DWP(1,"edx")); ++ &jnz (&label("little")); ++&set_label("ret"); ++ &ret (); ++ ++&set_label("lot",16); ++ &test ("edx",3); ++ &jz (&label("aligned")); ++ &mov (&BP(0,"edx"),"al"); ++ &lea ("ecx",&DWP(-1,"ecx")); ++ &lea ("edx",&DWP(1,"edx")); ++ &jmp (&label("lot")); ++&set_label("aligned"); ++ &mov (&DWP(0,"edx"),"eax"); ++ &lea ("ecx",&DWP(-4,"ecx")); ++ &test ("ecx",-4); ++ &lea ("edx",&DWP(4,"edx")); ++ &jnz (&label("aligned")); ++ &cmp ("ecx",0); ++ &jne (&label("little")); ++ &ret (); ++&function_end_B("OPENSSL_cleanse"); ++ ++&function_begin_B("CRYPTO_memcmp"); ++ &push ("esi"); ++ &push ("edi"); ++ &mov ("esi",&wparam(0)); ++ &mov ("edi",&wparam(1)); ++ &mov ("ecx",&wparam(2)); ++ &xor ("eax","eax"); ++ &xor ("edx","edx"); ++ &cmp ("ecx",0); ++ &je (&label("no_data")); ++&set_label("loop"); ++ &mov ("dl",&BP(0,"esi")); ++ &lea ("esi",&DWP(1,"esi")); ++ &xor ("dl",&BP(0,"edi")); ++ &lea ("edi",&DWP(1,"edi")); ++ &or ("al","dl"); ++ &dec ("ecx"); ++ &jnz (&label("loop")); ++ &neg ("eax"); ++ &shr ("eax",31); ++&set_label("no_data"); ++ &pop ("edi"); ++ &pop ("esi"); ++ &ret (); ++&function_end_B("CRYPTO_memcmp"); ++{ ++my $lasttick = "esi"; ++my $lastdiff = "ebx"; ++my $out = "edi"; ++my $cnt = "ecx"; ++my $max = "ebp"; ++ ++&function_begin("OPENSSL_instrument_bus"); ++ &mov ("eax",0); ++ if ($sse2) { ++ &picmeup("edx","OPENSSL_ia32cap_P"); ++ &bt (&DWP(0,"edx"),4); ++ &jnc (&label("nogo")); # no TSC ++ &bt (&DWP(0,"edx"),19); ++ &jnc (&label("nogo")); # no CLFLUSH ++ ++ &mov ($out,&wparam(0)); # load arguments ++ &mov ($cnt,&wparam(1)); ++ ++ # collect 1st tick ++ &rdtsc (); ++ &mov ($lasttick,"eax"); # lasttick = tick ++ &mov ($lastdiff,0); # lastdiff = 0 ++ &clflush(&DWP(0,$out)); ++ &data_byte(0xf0); # lock ++ &add (&DWP(0,$out),$lastdiff); ++ &jmp (&label("loop")); ++ ++&set_label("loop",16); ++ &rdtsc (); ++ &mov ("edx","eax"); # put aside tick (yes, I neglect edx) ++ &sub ("eax",$lasttick); # diff ++ &mov ($lasttick,"edx"); # lasttick = tick ++ &mov ($lastdiff,"eax"); # lastdiff = diff ++ &clflush(&DWP(0,$out)); ++ &data_byte(0xf0); # lock ++ &add (&DWP(0,$out),"eax"); # accumulate diff ++ &lea ($out,&DWP(4,$out)); # ++$out ++ &sub ($cnt,1); # --$cnt ++ &jnz (&label("loop")); ++ ++ &mov ("eax",&wparam(1)); ++&set_label("nogo"); ++ } ++&function_end("OPENSSL_instrument_bus"); ++ ++&function_begin("OPENSSL_instrument_bus2"); ++ &mov ("eax",0); ++ if ($sse2) { ++ &picmeup("edx","OPENSSL_ia32cap_P"); ++ &bt (&DWP(0,"edx"),4); ++ &jnc (&label("nogo")); # no TSC ++ &bt (&DWP(0,"edx"),19); ++ &jnc (&label("nogo")); # no CLFLUSH ++ ++ &mov ($out,&wparam(0)); # load arguments ++ &mov ($cnt,&wparam(1)); ++ &mov ($max,&wparam(2)); ++ ++ &rdtsc (); # collect 1st tick ++ &mov ($lasttick,"eax"); # lasttick = tick ++ &mov ($lastdiff,0); # lastdiff = 0 ++ ++ &clflush(&DWP(0,$out)); ++ &data_byte(0xf0); # lock ++ &add (&DWP(0,$out),$lastdiff); ++ ++ &rdtsc (); # collect 1st diff ++ &mov ("edx","eax"); # put aside tick (yes, I neglect edx) ++ &sub ("eax",$lasttick); # diff ++ &mov ($lasttick,"edx"); # lasttick = tick ++ &mov ($lastdiff,"eax"); # lastdiff = diff ++ &jmp (&label("loop2")); ++ ++&set_label("loop2",16); ++ &clflush(&DWP(0,$out)); ++ &data_byte(0xf0); # lock ++ &add (&DWP(0,$out),"eax"); # accumulate diff ++ ++ &sub ($max,1); ++ &jz (&label("done2")); ++ ++ &rdtsc (); ++ &mov ("edx","eax"); # put aside tick (yes, I neglect edx) ++ &sub ("eax",$lasttick); # diff ++ &mov ($lasttick,"edx"); # lasttick = tick ++ &cmp ("eax",$lastdiff); ++ &mov ($lastdiff,"eax"); # lastdiff = diff ++ &mov ("edx",0); ++ &setne ("dl"); ++ &sub ($cnt,"edx"); # conditional --$cnt ++ &lea ($out,&DWP(0,$out,"edx",4)); # conditional ++$out ++ &jnz (&label("loop2")); ++ ++&set_label("done2"); ++ &mov ("eax",&wparam(1)); ++ &sub ("eax",$cnt); ++&set_label("nogo"); ++ } ++&function_end("OPENSSL_instrument_bus2"); ++} ++ ++sub gen_random { ++my $rdop = shift; ++&function_begin_B("OPENSSL_ia32_${rdop}"); ++ &mov ("ecx",8); ++&set_label("loop"); ++ &${rdop}("eax"); ++ &jc (&label("break")); ++ &loop (&label("loop")); ++&set_label("break"); ++ &cmp ("eax",0); ++ &cmove ("eax","ecx"); ++ &ret (); ++&function_end_B("OPENSSL_ia32_${rdop}"); ++ ++&function_begin_B("OPENSSL_ia32_${rdop}_bytes"); ++ &push ("edi"); ++ &push ("ebx"); ++ &xor ("eax","eax"); # return value ++ &mov ("edi",&wparam(0)); ++ &mov ("ebx",&wparam(1)); ++ ++ &cmp ("ebx",0); ++ &je (&label("done")); ++ ++ &mov ("ecx",8); ++&set_label("loop"); ++ &${rdop}("edx"); ++ &jc (&label("break")); ++ &loop (&label("loop")); ++ &jmp (&label("done")); ++ ++&set_label("break",16); ++ &cmp ("ebx",4); ++ &jb (&label("tail")); ++ &mov (&DWP(0,"edi"),"edx"); ++ &lea ("edi",&DWP(4,"edi")); ++ &add ("eax",4); ++ &sub ("ebx",4); ++ &jz (&label("done")); ++ &mov ("ecx",8); ++ &jmp (&label("loop")); ++ ++&set_label("tail",16); ++ &mov (&BP(0,"edi"),"dl"); ++ &lea ("edi",&DWP(1,"edi")); ++ &inc ("eax"); ++ &shr ("edx",8); ++ &dec ("ebx"); ++ &jnz (&label("tail")); ++ ++&set_label("done"); ++ &pop ("ebx"); ++ &pop ("edi"); ++ &ret (); ++&function_end_B("OPENSSL_ia32_${rdop}_bytes"); ++} ++&gen_random("rdrand"); ++&gen_random("rdseed"); ++ ++&initseg("OPENSSL_cpuid_setup"); ++ ++&hidden("OPENSSL_cpuid_setup"); ++&hidden("OPENSSL_ia32cap_P"); ++ ++&asm_finish(); ++ ++close STDOUT; +diff --git a/CryptoPkg/Library/OpensslLib/openssl/demos/README b/CryptoPkg/Library/OpensslLib/openssl/demos/README +new file mode 100644 +index 0000000..d2155ef +--- /dev/null ++++ b/CryptoPkg/Library/OpensslLib/openssl/demos/README +@@ -0,0 +1,9 @@ ++NOTE: Don't expect any of these programs to work with current ++OpenSSL releases, or even with later SSLeay releases. ++ ++Original README: ++============================================================================= ++ ++Some demo programs sent to me by various people ++ ++eric +diff --git a/CryptoPkg/Library/OpensslLib/openssl/demos/bio/Makefile b/CryptoPkg/Library/OpensslLib/openssl/demos/bio/Makefile +new file mode 100644 +index 0000000..493e8a5 +--- /dev/null ++++ b/CryptoPkg/Library/OpensslLib/openssl/demos/bio/Makefile +@@ -0,0 +1,30 @@ ++# Quick instruction: ++# To build against an OpenSSL built in the source tree, do this: ++# ++# make OPENSSL_INCS_LOCATION=-I../../include OPENSSL_LIBS_LOCATION=-L../.. ++# ++# To run the demos when linked with a shared library (default): ++# ++# LD_LIBRARY_PATH=../.. ./server-arg ++# LD_LIBRARY_PATH=../.. ./server-cmod ++# LD_LIBRARY_PATH=../.. ./server-conf ++# LD_LIBRARY_PATH=../.. ./client-arg ++# LD_LIBRARY_PATH=../.. ./client-conf ++# LD_LIBRARY_PATH=../.. ./saccept ++# LD_LIBRARY_PATH=../.. ./sconnect ++ ++CFLAGS = $(OPENSSL_INCS_LOCATION) ++LDFLAGS = $(OPENSSL_LIBS_LOCATION) -lssl -lcrypto $(EX_LIBS) ++ ++all: client-arg client-conf saccept sconnect server-arg server-cmod server-conf ++ ++client-arg: client-arg.o ++client-conf: client-conf.o ++saccept: saccept.o ++sconnect: sconnect.o ++server-arg: server-arg.o ++server-cmod: server-cmod.o ++server-conf: server-conf.o ++ ++client-arg client-conf saccept sconnect server-arg server-cmod server-conf: ++ $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $< +diff --git a/CryptoPkg/Library/OpensslLib/openssl/demos/bio/README b/CryptoPkg/Library/OpensslLib/openssl/demos/bio/README +new file mode 100644 +index 0000000..a36bb48 +--- /dev/null ++++ b/CryptoPkg/Library/OpensslLib/openssl/demos/bio/README +@@ -0,0 +1,7 @@ ++This directory contains some simple examples of the use of BIO's ++to simplify socket programming. ++ ++The client-conf, server-conf, client-arg and client-conf include examples ++of how to use the SSL_CONF API for configuration file or command line ++processing. ++ +diff --git a/CryptoPkg/Library/OpensslLib/openssl/demos/bio/accept.cnf b/CryptoPkg/Library/OpensslLib/openssl/demos/bio/accept.cnf +new file mode 100644 +index 0000000..eb69658 +--- /dev/null ++++ b/CryptoPkg/Library/OpensslLib/openssl/demos/bio/accept.cnf +@@ -0,0 +1,17 @@ ++# Example configuration file ++# Port to listen on ++Port = 4433 ++# Disable TLS v1.2 for test. ++# Protocol = ALL, -TLSv1.2 ++# Only support 3 curves ++Curves = P-521:P-384:P-256 ++# Restricted signature algorithms ++SignatureAlgorithms = RSA+SHA512:ECDSA+SHA512 ++Certificate=server.pem ++PrivateKey=server.pem ++ChainCAFile=root.pem ++VerifyCAFile=root.pem ++ ++# Request certificate ++VerifyMode=Request ++ClientCAFile=root.pem +diff --git a/CryptoPkg/Library/OpensslLib/openssl/demos/bio/client-arg.c b/CryptoPkg/Library/OpensslLib/openssl/demos/bio/client-arg.c +new file mode 100644 +index 0000000..e8d5e46 +--- /dev/null ++++ b/CryptoPkg/Library/OpensslLib/openssl/demos/bio/client-arg.c +@@ -0,0 +1,117 @@ ++/* ++ * Copyright 2013-2016 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 ++ * in the file LICENSE in the source distribution or at ++ * https://www.openssl.org/source/license.html ++ */ ++ ++#include ++#include ++#include ++ ++int main(int argc, char **argv) ++{ ++ BIO *sbio = NULL, *out = NULL; ++ int len; ++ char tmpbuf[1024]; ++ SSL_CTX *ctx; ++ SSL_CONF_CTX *cctx; ++ SSL *ssl; ++ char **args = argv + 1; ++ const char *connect_str = "localhost:4433"; ++ int nargs = argc - 1; ++ ++ ctx = SSL_CTX_new(TLS_client_method()); ++ cctx = SSL_CONF_CTX_new(); ++ SSL_CONF_CTX_set_flags(cctx, SSL_CONF_FLAG_CLIENT); ++ SSL_CONF_CTX_set_ssl_ctx(cctx, ctx); ++ while (*args && **args == '-') { ++ int rv; ++ /* Parse standard arguments */ ++ rv = SSL_CONF_cmd_argv(cctx, &nargs, &args); ++ if (rv == -3) { ++ fprintf(stderr, "Missing argument for %s\n", *args); ++ goto end; ++ } ++ if (rv < 0) { ++ fprintf(stderr, "Error in command %s\n", *args); ++ ERR_print_errors_fp(stderr); ++ goto end; ++ } ++ /* If rv > 0 we processed something so proceed to next arg */ ++ if (rv > 0) ++ continue; ++ /* Otherwise application specific argument processing */ ++ if (strcmp(*args, "-connect") == 0) { ++ connect_str = args[1]; ++ if (connect_str == NULL) { ++ fprintf(stderr, "Missing -connect argument\n"); ++ goto end; ++ } ++ args += 2; ++ nargs -= 2; ++ continue; ++ } else { ++ fprintf(stderr, "Unknown argument %s\n", *args); ++ goto end; ++ } ++ } ++ ++ if (!SSL_CONF_CTX_finish(cctx)) { ++ fprintf(stderr, "Finish error\n"); ++ ERR_print_errors_fp(stderr); ++ goto end; ++ } ++ ++ /* ++ * We'd normally set some stuff like the verify paths and * mode here ++ * because as things stand this will connect to * any server whose ++ * certificate is signed by any CA. ++ */ ++ ++ sbio = BIO_new_ssl_connect(ctx); ++ ++ BIO_get_ssl(sbio, &ssl); ++ ++ if (!ssl) { ++ fprintf(stderr, "Can't locate SSL pointer\n"); ++ goto end; ++ } ++ ++ /* Don't want any retries */ ++ SSL_set_mode(ssl, SSL_MODE_AUTO_RETRY); ++ ++ /* We might want to do other things with ssl here */ ++ ++ BIO_set_conn_hostname(sbio, connect_str); ++ ++ out = BIO_new_fp(stdout, BIO_NOCLOSE); ++ if (BIO_do_connect(sbio) <= 0) { ++ fprintf(stderr, "Error connecting to server\n"); ++ ERR_print_errors_fp(stderr); ++ goto end; ++ } ++ ++ if (BIO_do_handshake(sbio) <= 0) { ++ fprintf(stderr, "Error establishing SSL connection\n"); ++ ERR_print_errors_fp(stderr); ++ goto end; ++ } ++ ++ /* Could examine ssl here to get connection info */ ++ ++ BIO_puts(sbio, "GET / HTTP/1.0\n\n"); ++ for (;;) { ++ len = BIO_read(sbio, tmpbuf, 1024); ++ if (len <= 0) ++ break; ++ BIO_write(out, tmpbuf, len); ++ } ++ end: ++ SSL_CONF_CTX_free(cctx); ++ BIO_free_all(sbio); ++ BIO_free(out); ++ return 0; ++} +diff --git a/CryptoPkg/Library/OpensslLib/openssl/demos/bio/client-conf.c b/CryptoPkg/Library/OpensslLib/openssl/demos/bio/client-conf.c +new file mode 100644 +index 0000000..e819030 +--- /dev/null ++++ b/CryptoPkg/Library/OpensslLib/openssl/demos/bio/client-conf.c +@@ -0,0 +1,126 @@ ++/* ++ * Copyright 2013-2016 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 ++ * in the file LICENSE in the source distribution or at ++ * https://www.openssl.org/source/license.html ++ */ ++ ++#include ++#include ++#include ++#include ++ ++int main(int argc, char **argv) ++{ ++ BIO *sbio = NULL, *out = NULL; ++ int i, len, rv; ++ char tmpbuf[1024]; ++ SSL_CTX *ctx = NULL; ++ SSL_CONF_CTX *cctx = NULL; ++ SSL *ssl = NULL; ++ CONF *conf = NULL; ++ STACK_OF(CONF_VALUE) *sect = NULL; ++ CONF_VALUE *cnf; ++ const char *connect_str = "localhost:4433"; ++ long errline = -1; ++ ++ conf = NCONF_new(NULL); ++ ++ if (NCONF_load(conf, "connect.cnf", &errline) <= 0) { ++ if (errline <= 0) ++ fprintf(stderr, "Error processing config file\n"); ++ else ++ fprintf(stderr, "Error on line %ld\n", errline); ++ goto end; ++ } ++ ++ sect = NCONF_get_section(conf, "default"); ++ ++ if (sect == NULL) { ++ fprintf(stderr, "Error retrieving default section\n"); ++ goto end; ++ } ++ ++ ctx = SSL_CTX_new(TLS_client_method()); ++ cctx = SSL_CONF_CTX_new(); ++ SSL_CONF_CTX_set_flags(cctx, SSL_CONF_FLAG_CLIENT); ++ SSL_CONF_CTX_set_flags(cctx, SSL_CONF_FLAG_FILE); ++ SSL_CONF_CTX_set_ssl_ctx(cctx, ctx); ++ for (i = 0; i < sk_CONF_VALUE_num(sect); i++) { ++ cnf = sk_CONF_VALUE_value(sect, i); ++ rv = SSL_CONF_cmd(cctx, cnf->name, cnf->value); ++ if (rv > 0) ++ continue; ++ if (rv != -2) { ++ fprintf(stderr, "Error processing %s = %s\n", ++ cnf->name, cnf->value); ++ ERR_print_errors_fp(stderr); ++ goto end; ++ } ++ if (strcmp(cnf->name, "Connect") == 0) { ++ connect_str = cnf->value; ++ } else { ++ fprintf(stderr, "Unknown configuration option %s\n", cnf->name); ++ goto end; ++ } ++ } ++ ++ if (!SSL_CONF_CTX_finish(cctx)) { ++ fprintf(stderr, "Finish error\n"); ++ ERR_print_errors_fp(stderr); ++ goto end; ++ } ++ ++ /* ++ * We'd normally set some stuff like the verify paths and * mode here ++ * because as things stand this will connect to * any server whose ++ * certificate is signed by any CA. ++ */ ++ ++ sbio = BIO_new_ssl_connect(ctx); ++ ++ BIO_get_ssl(sbio, &ssl); ++ ++ if (!ssl) { ++ fprintf(stderr, "Can't locate SSL pointer\n"); ++ goto end; ++ } ++ ++ /* Don't want any retries */ ++ SSL_set_mode(ssl, SSL_MODE_AUTO_RETRY); ++ ++ /* We might want to do other things with ssl here */ ++ ++ BIO_set_conn_hostname(sbio, connect_str); ++ ++ out = BIO_new_fp(stdout, BIO_NOCLOSE); ++ if (BIO_do_connect(sbio) <= 0) { ++ fprintf(stderr, "Error connecting to server\n"); ++ ERR_print_errors_fp(stderr); ++ goto end; ++ } ++ ++ if (BIO_do_handshake(sbio) <= 0) { ++ fprintf(stderr, "Error establishing SSL connection\n"); ++ ERR_print_errors_fp(stderr); ++ goto end; ++ } ++ ++ /* Could examine ssl here to get connection info */ ++ ++ BIO_puts(sbio, "GET / HTTP/1.0\n\n"); ++ for (;;) { ++ len = BIO_read(sbio, tmpbuf, 1024); ++ if (len <= 0) ++ break; ++ BIO_write(out, tmpbuf, len); ++ } ++ end: ++ SSL_CONF_CTX_free(cctx); ++ BIO_free_all(sbio); ++ BIO_free(out); ++ NCONF_free(conf); ++ return 0; ++} +diff --git a/CryptoPkg/Library/OpensslLib/openssl/demos/bio/cmod.cnf b/CryptoPkg/Library/OpensslLib/openssl/demos/bio/cmod.cnf +new file mode 100644 +index 0000000..4c45dfb +--- /dev/null ++++ b/CryptoPkg/Library/OpensslLib/openssl/demos/bio/cmod.cnf +@@ -0,0 +1,24 @@ ++# Example config module configuration ++ ++# Name supplied by application to CONF_modules_load_file ++# and section containing configuration ++testapp = test_sect ++ ++[test_sect] ++# list of confuration modules ++ ++# SSL configuration module ++ssl_conf = ssl_sect ++ ++[ssl_sect] ++# list of SSL configurations ++server = server_sect ++ ++[server_sect] ++# Only support 3 curves ++Curves = P-521:P-384:P-256 ++# Restricted signature algorithms ++SignatureAlgorithms = RSA+SHA512:ECDSA+SHA512 ++# Certificates and keys ++RSA.Certificate=server.pem ++ECDSA.Certificate=server-ec.pem +diff --git a/CryptoPkg/Library/OpensslLib/openssl/demos/bio/connect.cnf b/CryptoPkg/Library/OpensslLib/openssl/demos/bio/connect.cnf +new file mode 100644 +index 0000000..4dee03c +--- /dev/null ++++ b/CryptoPkg/Library/OpensslLib/openssl/demos/bio/connect.cnf +@@ -0,0 +1,9 @@ ++# Example configuration file ++# Connects to the default port of s_server ++Connect = localhost:4433 ++# Disable TLS v1.2 for test. ++# Protocol = ALL, -TLSv1.2 ++# Only support 3 curves ++Curves = P-521:P-384:P-256 ++# Restricted signature algorithms ++SignatureAlgorithms = RSA+SHA512:ECDSA+SHA512 +diff --git a/CryptoPkg/Library/OpensslLib/openssl/demos/bio/descrip.mms b/CryptoPkg/Library/OpensslLib/openssl/demos/bio/descrip.mms +new file mode 100644 +index 0000000..8e127b0 +--- /dev/null ++++ b/CryptoPkg/Library/OpensslLib/openssl/demos/bio/descrip.mms +@@ -0,0 +1,47 @@ ++# This build description trusts that the following logical names are defined: ++# ++# For compilation: OPENSSL ++# For linking with shared libraries: OSSL$LIBCRYPTO_SHR and OSSL$LIBSSL_SHR ++# For linking with static libraries: OSSL$LIBCRYPTO and OSSL$LIBSSL ++# ++# These are normally defined with the OpenSSL startup procedure ++ ++# By default, we link with the shared libraries ++SHARED = TRUE ++ ++# Alternative, for linking with static libraries ++#SHARED = FALSE ++ ++.FIRST : ++ IF "$(SHARED)" .EQS. "TRUE" THEN DEFINE OPT []shared.opt ++ IF "$(SHARED)" .NES. "TRUE" THEN DEFINE OPT []static.opt ++ ++.LAST : ++ DEASSIGN OPT ++ ++.DEFAULT : ++ @ ! ++ ++# Because we use an option file, we need to redefine this ++.obj.exe : ++ $(LINK) $(LINKFLAGS) $<,OPT:/OPT ++ ++all : client-arg.exe client-conf.exe saccept.exe sconnect.exe - ++ server-arg.exe server-cmod.exe server-conf.exe ++ ++client-arg.exe : client-arg.obj ++client-conf.exe : client-conf.obj ++saccept.exe : saccept.obj ++sconnect.exe : sconnect.obj ++server-arg.exe : server-arg.obj ++server-cmod.exe : server-cmod.obj ++server-conf.exe : server-conf.obj ++ ++# Stoopid MMS doesn't infer this automatically... ++client-arg.obj : client-arg.c ++client-conf.obj : client-conf.c ++saccept.obj : saccept.c ++sconnect.obj : sconnect.c ++server-arg.obj : server-arg.c ++server-cmod.obj : server-cmod.c ++server-conf.obj : server-conf.c +diff --git a/CryptoPkg/Library/OpensslLib/openssl/demos/bio/intca.pem b/CryptoPkg/Library/OpensslLib/openssl/demos/bio/intca.pem +new file mode 100644 +index 0000000..3551ea9 +--- /dev/null ++++ b/CryptoPkg/Library/OpensslLib/openssl/demos/bio/intca.pem +@@ -0,0 +1,23 @@ ++-----BEGIN CERTIFICATE----- ++MIIDvjCCAqagAwIBAgIJAPzCy4CUW9/qMA0GCSqGSIb3DQEBCwUAMGgxCzAJBgNV ++BAYTAlVLMRYwFAYDVQQKDA1PcGVuU1NMIEdyb3VwMSIwIAYDVQQLDBlGT1IgVEVT ++VElORyBQVVJQT1NFUyBPTkxZMR0wGwYDVQQDDBRPcGVuU1NMIFRlc3QgUm9vdCBD ++QTAeFw0xNTA3MTQxMzIyMDVaFw0yNTA2MjExMzIyMDVaMHAxCzAJBgNVBAYTAlVL ++MRYwFAYDVQQKDA1PcGVuU1NMIEdyb3VwMSIwIAYDVQQLDBlGT1IgVEVTVElORyBQ ++VVJQT1NFUyBPTkxZMSUwIwYDVQQDDBxPcGVuU1NMIFRlc3QgSW50ZXJtZWRpYXRl ++IENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAsErw75CmLYD6pkrG ++W/YhAl/K8L5wJYxDjqu2FghxjD8K308W3EHq4uBxEwR1OHXaM1+6ZZw7/r2I37VL ++IdurBEAIEUdbzx0so74FPawgz5EW2CTqoJnK8F71/vo5Kj1VPwW46CxwxUR3cfvJ ++GNXND2ip0TcyTSPLROXOyQakcVfIGJmdSa1wHKi+c2gMA4emADudZUOYLrg80gr2 ++ldePm07ynbVsKKzCcStw8MdmoW9Qt3fLnPJn2TFUUBNWj+4kvL+88edWCVQXKNds ++ysD/CDrH4W/hjyPDStVsM6XpiNU0+L2ZY6fcj3OP8d0goOx45xotMn9m8hNkCGsr ++VXx9IwIDAQABo2MwYTAdBgNVHQ4EFgQUNsNsiOeV/rC97M4+PYarIYGH2towHwYD ++VR0jBBgwFoAUjBkP10IxdwUG4dOxn+s5+3hxOkUwDwYDVR0TAQH/BAUwAwEB/zAO ++BgNVHQ8BAf8EBAMCAQYwDQYJKoZIhvcNAQELBQADggEBAANQT0pDWBQoT/RY76xz ++audadGz/dfYnwvSwT0RMFcXLcMVVRNqP0HeR8OP8qLaP7onRbNnEXNfos9pxXYlg ++j+/WjWTBLVcr3pX2Xtmcaqw3CGN9qbQI8B3JkYeijZmc5+3r5MzK/9R0w8Y/T9Xt ++CXEiQhtWHpPrFEfrExeVy2kjJNRctEfq3OTd1bjgX64zvTU7eR+MHFYKPoyMqwIR ++gjoVKinvovEwWoZe5kfMQwJNA3IgoJexX9BXbS8efAYF/ku3tS0laoZS/q6V/o5I ++RvG0OqnNgxhul+96PE5ujSaprsyvBswIUKt+e/BCxGaS6f2AJ8RmtoPOSfT4b9qN ++thI= ++-----END CERTIFICATE----- +diff --git a/CryptoPkg/Library/OpensslLib/openssl/demos/bio/root.pem b/CryptoPkg/Library/OpensslLib/openssl/demos/bio/root.pem +new file mode 100644 +index 0000000..3bd0e9b +--- /dev/null ++++ b/CryptoPkg/Library/OpensslLib/openssl/demos/bio/root.pem +@@ -0,0 +1,22 @@ ++-----BEGIN CERTIFICATE----- ++MIIDtjCCAp6gAwIBAgIJAKkg71CjIAovMA0GCSqGSIb3DQEBBQUAMGgxCzAJBgNV ++BAYTAlVLMRYwFAYDVQQKDA1PcGVuU1NMIEdyb3VwMSIwIAYDVQQLDBlGT1IgVEVT ++VElORyBQVVJQT1NFUyBPTkxZMR0wGwYDVQQDDBRPcGVuU1NMIFRlc3QgUm9vdCBD ++QTAeFw0xNDAyMjMxMzA1MTNaFw0yNDAyMjExMzA1MTNaMGgxCzAJBgNVBAYTAlVL ++MRYwFAYDVQQKDA1PcGVuU1NMIEdyb3VwMSIwIAYDVQQLDBlGT1IgVEVTVElORyBQ ++VVJQT1NFUyBPTkxZMR0wGwYDVQQDDBRPcGVuU1NMIFRlc3QgUm9vdCBDQTCCASIw ++DQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANMaarigKGOra5Mc/LrhOkcmHzDs ++vkYL7dfaaht8fLBKRTYwzSBvO9x54koTWjq7HkbaxkYAg3HnDTkNCyzkGKNdM89H ++q/PtGIFFlceQIOat3Kjd05Iw3PtLEWTDjT6FMA9Mkjk/XbpmycqRIwNKtgICoFsG ++juIpc4P31kxK7i3ri+JnlyvVmRZjJxrheJB0qHGXilrOVDPOliDn//jXbcyzXemu ++R8KgAeQM4IIs9jYHJOgHrTItIpwa9wNTEp9KCGkO6xr20NkKyDp6XRyd+hmnUB7r ++77WTptvKPFFTjTDFqEtcif9U2kVkCfn2mSRO8noCbVH++fuR8LMWlD99gt8CAwEA ++AaNjMGEwHQYDVR0OBBYEFIwZD9dCMXcFBuHTsZ/rOft4cTpFMB8GA1UdIwQYMBaA ++FIwZD9dCMXcFBuHTsZ/rOft4cTpFMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/ ++BAQDAgEGMA0GCSqGSIb3DQEBBQUAA4IBAQCsoxVi49anYZ1aI/2rVJ5bvEd3ZvGn ++wx1Y+l75SQVYU2qX9CHNBVg1t8reIBN8yPEfBM1WcFPEg7Vy3zFaklMPm/oYXwVI ++/lX/LsfPUxdnQmONxLw4x/0booN1LV/dtRcebewUSqog6W9Z2fbTEe6srIBE4M5G ++Wa943lthlmQM6HzlU4D606PQ3zQbX08mue4eqQB813r4uSoI1MpGLqxkziBRFGGN ++T4VNYp8DeSVr3jHjNBmKCAPZxJIYElnLEK027OG00RH7sF7SGFDNsCjN1NmCvuRz ++9AHnjVIBNzIvI3uiOn9tngRDXBRIcUBsdYG19tal8yWBgrr9SdlqFy/Y ++-----END CERTIFICATE----- +diff --git a/CryptoPkg/Library/OpensslLib/openssl/demos/bio/saccept.c b/CryptoPkg/Library/OpensslLib/openssl/demos/bio/saccept.c +new file mode 100644 +index 0000000..66c5c61 +--- /dev/null ++++ b/CryptoPkg/Library/OpensslLib/openssl/demos/bio/saccept.c +@@ -0,0 +1,122 @@ ++/* ++ * Copyright 1998-2016 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 ++ * in the file LICENSE in the source distribution or at ++ * https://www.openssl.org/source/license.html ++ */ ++ ++/*- ++ * A minimal program to serve an SSL connection. ++ * It uses blocking. ++ * saccept host:port ++ * host is the interface IP to use. If any interface, use *:port ++ * The default it *:4433 ++ * ++ * cc -I../../include saccept.c -L../.. -lssl -lcrypto -ldl ++ */ ++ ++#include ++#include ++#include ++#include ++ ++#define CERT_FILE "server.pem" ++ ++static int done = 0; ++ ++void interrupt(int sig) ++{ ++ done = 1; ++} ++ ++void sigsetup(void) ++{ ++ struct sigaction sa; ++ ++ /* ++ * Catch at most once, and don't restart the accept system call. ++ */ ++ sa.sa_flags = SA_RESETHAND; ++ sa.sa_handler = interrupt; ++ sigemptyset(&sa.sa_mask); ++ sigaction(SIGINT, &sa, NULL); ++} ++ ++int main(int argc, char *argv[]) ++{ ++ char *port = NULL; ++ BIO *in = NULL; ++ BIO *ssl_bio, *tmp; ++ SSL_CTX *ctx; ++ char buf[512]; ++ int ret = 1, i; ++ ++ if (argc <= 1) ++ port = "*:4433"; ++ else ++ port = argv[1]; ++ ++ ctx = SSL_CTX_new(TLS_server_method()); ++ if (!SSL_CTX_use_certificate_chain_file(ctx, CERT_FILE)) ++ goto err; ++ if (!SSL_CTX_use_PrivateKey_file(ctx, CERT_FILE, SSL_FILETYPE_PEM)) ++ goto err; ++ if (!SSL_CTX_check_private_key(ctx)) ++ goto err; ++ ++ /* Setup server side SSL bio */ ++ ssl_bio = BIO_new_ssl(ctx, 0); ++ ++ if ((in = BIO_new_accept(port)) == NULL) ++ goto err; ++ ++ /* ++ * This means that when a new connection is accepted on 'in', The ssl_bio ++ * will be 'duplicated' and have the new socket BIO push into it. ++ * Basically it means the SSL BIO will be automatically setup ++ */ ++ BIO_set_accept_bios(in, ssl_bio); ++ ++ /* Arrange to leave server loop on interrupt */ ++ sigsetup(); ++ ++ again: ++ /* ++ * The first call will setup the accept socket, and the second will get a ++ * socket. In this loop, the first actual accept will occur in the ++ * BIO_read() function. ++ */ ++ ++ if (BIO_do_accept(in) <= 0) ++ goto err; ++ ++ while (!done) { ++ i = BIO_read(in, buf, 512); ++ if (i == 0) { ++ /* ++ * If we have finished, remove the underlying BIO stack so the ++ * next time we call any function for this BIO, it will attempt ++ * to do an accept ++ */ ++ printf("Done\n"); ++ tmp = BIO_pop(in); ++ BIO_free_all(tmp); ++ goto again; ++ } ++ if (i < 0) ++ goto err; ++ fwrite(buf, 1, i, stdout); ++ fflush(stdout); ++ } ++ ++ ret = 0; ++ err: ++ if (ret) { ++ ERR_print_errors_fp(stderr); ++ } ++ BIO_free(in); ++ exit(ret); ++ return (!ret); ++} +diff --git a/CryptoPkg/Library/OpensslLib/openssl/demos/bio/sconnect.c b/CryptoPkg/Library/OpensslLib/openssl/demos/bio/sconnect.c +new file mode 100644 +index 0000000..664a1e0 +--- /dev/null ++++ b/CryptoPkg/Library/OpensslLib/openssl/demos/bio/sconnect.c +@@ -0,0 +1,131 @@ ++/* ++ * Copyright 1998-2016 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 ++ * in the file LICENSE in the source distribution or at ++ * https://www.openssl.org/source/license.html ++ */ ++ ++/*- ++ * A minimal program to do SSL to a passed host and port. ++ * It is actually using non-blocking IO but in a very simple manner ++ * sconnect host:port - it does a 'GET / HTTP/1.0' ++ * ++ * cc -I../../include sconnect.c -L../.. -lssl -lcrypto ++ */ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#define HOSTPORT "localhost:4433" ++#define CAFILE "root.pem" ++ ++extern int errno; ++ ++int main(argc, argv) ++int argc; ++char *argv[]; ++{ ++ const char *hostport = HOSTPORT; ++ const char *CAfile = CAFILE; ++ char *hostname; ++ char *cp; ++ BIO *out = NULL; ++ char buf[1024 * 10], *p; ++ SSL_CTX *ssl_ctx = NULL; ++ SSL *ssl; ++ BIO *ssl_bio; ++ int i, len, off, ret = 1; ++ ++ if (argc > 1) ++ hostport = argv[1]; ++ if (argc > 2) ++ CAfile = argv[2]; ++ ++ hostname = OPENSSL_strdup(hostport); ++ if ((cp = strchr(hostname, ':')) != NULL) ++ *cp = 0; ++ ++#ifdef WATT32 ++ dbug_init(); ++ sock_init(); ++#endif ++ ++ ssl_ctx = SSL_CTX_new(TLS_client_method()); ++ ++ /* Enable trust chain verification */ ++ SSL_CTX_set_verify(ssl_ctx, SSL_VERIFY_PEER, NULL); ++ SSL_CTX_load_verify_locations(ssl_ctx, CAfile, NULL); ++ ++ /* Lets make a SSL structure */ ++ ssl = SSL_new(ssl_ctx); ++ SSL_set_connect_state(ssl); ++ ++ /* Enable peername verification */ ++ if (SSL_set1_host(ssl, hostname) <= 0) ++ goto err; ++ ++ /* Use it inside an SSL BIO */ ++ ssl_bio = BIO_new(BIO_f_ssl()); ++ BIO_set_ssl(ssl_bio, ssl, BIO_CLOSE); ++ ++ /* Lets use a connect BIO under the SSL BIO */ ++ out = BIO_new(BIO_s_connect()); ++ BIO_set_conn_hostname(out, hostport); ++ BIO_set_nbio(out, 1); ++ out = BIO_push(ssl_bio, out); ++ ++ p = "GET / HTTP/1.0\r\n\r\n"; ++ len = strlen(p); ++ ++ off = 0; ++ for (;;) { ++ i = BIO_write(out, &(p[off]), len); ++ if (i <= 0) { ++ if (BIO_should_retry(out)) { ++ fprintf(stderr, "write DELAY\n"); ++ sleep(1); ++ continue; ++ } else { ++ goto err; ++ } ++ } ++ off += i; ++ len -= i; ++ if (len <= 0) ++ break; ++ } ++ ++ for (;;) { ++ i = BIO_read(out, buf, sizeof(buf)); ++ if (i == 0) ++ break; ++ if (i < 0) { ++ if (BIO_should_retry(out)) { ++ fprintf(stderr, "read DELAY\n"); ++ sleep(1); ++ continue; ++ } ++ goto err; ++ } ++ fwrite(buf, 1, i, stdout); ++ } ++ ++ ret = 1; ++ goto done; ++ ++ err: ++ if (ERR_peek_error() == 0) { /* system call error */ ++ fprintf(stderr, "errno=%d ", errno); ++ perror("error"); ++ } else ++ ERR_print_errors_fp(stderr); ++ done: ++ BIO_free_all(out); ++ SSL_CTX_free(ssl_ctx); ++ return (ret == 1); ++} +diff --git a/CryptoPkg/Library/OpensslLib/openssl/demos/bio/server-arg.c b/CryptoPkg/Library/OpensslLib/openssl/demos/bio/server-arg.c +new file mode 100644 +index 0000000..6056969 +--- /dev/null ++++ b/CryptoPkg/Library/OpensslLib/openssl/demos/bio/server-arg.c +@@ -0,0 +1,145 @@ ++/* ++ * Copyright 2013-2016 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 ++ * in the file LICENSE in the source distribution or at ++ * https://www.openssl.org/source/license.html ++ */ ++ ++/* ++ * A minimal program to serve an SSL connection. It uses blocking. It use the ++ * SSL_CONF API with the command line. cc -I../../include server-arg.c ++ * -L../.. -lssl -lcrypto -ldl ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++ ++int main(int argc, char *argv[]) ++{ ++ char *port = "*:4433"; ++ BIO *ssl_bio, *tmp; ++ SSL_CTX *ctx; ++ SSL_CONF_CTX *cctx; ++ char buf[512]; ++ BIO *in = NULL; ++ int ret = 1, i; ++ char **args = argv + 1; ++ int nargs = argc - 1; ++ ++ ctx = SSL_CTX_new(TLS_server_method()); ++ ++ cctx = SSL_CONF_CTX_new(); ++ SSL_CONF_CTX_set_flags(cctx, SSL_CONF_FLAG_SERVER); ++ SSL_CONF_CTX_set_flags(cctx, SSL_CONF_FLAG_CERTIFICATE); ++ SSL_CONF_CTX_set_ssl_ctx(cctx, ctx); ++ while (*args && **args == '-') { ++ int rv; ++ /* Parse standard arguments */ ++ rv = SSL_CONF_cmd_argv(cctx, &nargs, &args); ++ if (rv == -3) { ++ fprintf(stderr, "Missing argument for %s\n", *args); ++ goto err; ++ } ++ if (rv < 0) { ++ fprintf(stderr, "Error in command %s\n", *args); ++ ERR_print_errors_fp(stderr); ++ goto err; ++ } ++ /* If rv > 0 we processed something so proceed to next arg */ ++ if (rv > 0) ++ continue; ++ /* Otherwise application specific argument processing */ ++ if (strcmp(*args, "-port") == 0) { ++ port = args[1]; ++ if (port == NULL) { ++ fprintf(stderr, "Missing -port argument\n"); ++ goto err; ++ } ++ args += 2; ++ nargs -= 2; ++ continue; ++ } else { ++ fprintf(stderr, "Unknown argument %s\n", *args); ++ goto err; ++ } ++ } ++ ++ if (!SSL_CONF_CTX_finish(cctx)) { ++ fprintf(stderr, "Finish error\n"); ++ ERR_print_errors_fp(stderr); ++ goto err; ++ } ++#ifdef ITERATE_CERTS ++ /* ++ * Demo of how to iterate over all certificates in an SSL_CTX structure. ++ */ ++ { ++ X509 *x; ++ int rv; ++ rv = SSL_CTX_set_current_cert(ctx, SSL_CERT_SET_FIRST); ++ while (rv) { ++ X509 *x = SSL_CTX_get0_certificate(ctx); ++ X509_NAME_print_ex_fp(stdout, X509_get_subject_name(x), 0, ++ XN_FLAG_ONELINE); ++ printf("\n"); ++ rv = SSL_CTX_set_current_cert(ctx, SSL_CERT_SET_NEXT); ++ } ++ fflush(stdout); ++ } ++#endif ++ /* Setup server side SSL bio */ ++ ssl_bio = BIO_new_ssl(ctx, 0); ++ ++ if ((in = BIO_new_accept(port)) == NULL) ++ goto err; ++ ++ /* ++ * This means that when a new connection is accepted on 'in', The ssl_bio ++ * will be 'duplicated' and have the new socket BIO push into it. ++ * Basically it means the SSL BIO will be automatically setup ++ */ ++ BIO_set_accept_bios(in, ssl_bio); ++ ++ again: ++ /* ++ * The first call will setup the accept socket, and the second will get a ++ * socket. In this loop, the first actual accept will occur in the ++ * BIO_read() function. ++ */ ++ ++ if (BIO_do_accept(in) <= 0) ++ goto err; ++ ++ for (;;) { ++ i = BIO_read(in, buf, 512); ++ if (i == 0) { ++ /* ++ * If we have finished, remove the underlying BIO stack so the ++ * next time we call any function for this BIO, it will attempt ++ * to do an accept ++ */ ++ printf("Done\n"); ++ tmp = BIO_pop(in); ++ BIO_free_all(tmp); ++ goto again; ++ } ++ if (i < 0) ++ goto err; ++ fwrite(buf, 1, i, stdout); ++ fflush(stdout); ++ } ++ ++ ret = 0; ++ err: ++ if (ret) { ++ ERR_print_errors_fp(stderr); ++ } ++ BIO_free(in); ++ exit(ret); ++ return (!ret); ++} +diff --git a/CryptoPkg/Library/OpensslLib/openssl/demos/bio/server-cmod.c b/CryptoPkg/Library/OpensslLib/openssl/demos/bio/server-cmod.c +new file mode 100644 +index 0000000..9cb2463 +--- /dev/null ++++ b/CryptoPkg/Library/OpensslLib/openssl/demos/bio/server-cmod.c +@@ -0,0 +1,95 @@ ++/* ++ * Copyright 2015-2016 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 ++ * in the file LICENSE in the source distribution or at ++ * https://www.openssl.org/source/license.html ++ */ ++ ++/* ++ * A minimal TLS server it ses SSL_CTX_config and a configuration file to ++ * set most server parameters. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++ ++int main(int argc, char *argv[]) ++{ ++ unsigned char buf[512]; ++ char *port = "*:4433"; ++ BIO *in = NULL; ++ BIO *ssl_bio, *tmp; ++ SSL_CTX *ctx; ++ int ret = 1, i; ++ ++ ctx = SSL_CTX_new(TLS_server_method()); ++ ++ if (CONF_modules_load_file("cmod.cnf", "testapp", 0) <= 0) { ++ fprintf(stderr, "Error processing config file\n"); ++ goto err; ++ } ++ ++ if (SSL_CTX_config(ctx, "server") == 0) { ++ fprintf(stderr, "Error configuring server.\n"); ++ goto err; ++ } ++ ++ /* Setup server side SSL bio */ ++ ssl_bio = BIO_new_ssl(ctx, 0); ++ ++ if ((in = BIO_new_accept(port)) == NULL) ++ goto err; ++ ++ /* ++ * This means that when a new connection is accepted on 'in', The ssl_bio ++ * will be 'duplicated' and have the new socket BIO push into it. ++ * Basically it means the SSL BIO will be automatically setup ++ */ ++ BIO_set_accept_bios(in, ssl_bio); ++ ++ again: ++ /* ++ * The first call will setup the accept socket, and the second will get a ++ * socket. In this loop, the first actual accept will occur in the ++ * BIO_read() function. ++ */ ++ ++ if (BIO_do_accept(in) <= 0) ++ goto err; ++ ++ for (;;) { ++ i = BIO_read(in, buf, sizeof(buf)); ++ if (i == 0) { ++ /* ++ * If we have finished, remove the underlying BIO stack so the ++ * next time we call any function for this BIO, it will attempt ++ * to do an accept ++ */ ++ printf("Done\n"); ++ tmp = BIO_pop(in); ++ BIO_free_all(tmp); ++ goto again; ++ } ++ if (i < 0) { ++ if (BIO_should_retry(in)) ++ continue; ++ goto err; ++ } ++ fwrite(buf, 1, i, stdout); ++ fflush(stdout); ++ } ++ ++ ret = 0; ++ err: ++ if (ret) { ++ ERR_print_errors_fp(stderr); ++ } ++ BIO_free(in); ++ exit(ret); ++ return (!ret); ++} +diff --git a/CryptoPkg/Library/OpensslLib/openssl/demos/bio/server-conf.c b/CryptoPkg/Library/OpensslLib/openssl/demos/bio/server-conf.c +new file mode 100644 +index 0000000..41b1308 +--- /dev/null ++++ b/CryptoPkg/Library/OpensslLib/openssl/demos/bio/server-conf.c +@@ -0,0 +1,140 @@ ++/* ++ * Copyright 2013-2016 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 ++ * in the file LICENSE in the source distribution or at ++ * https://www.openssl.org/source/license.html ++ */ ++ ++/* ++ * A minimal program to serve an SSL connection. It uses blocking. It uses ++ * the SSL_CONF API with a configuration file. cc -I../../include saccept.c ++ * -L../.. -lssl -lcrypto -ldl ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++int main(int argc, char *argv[]) ++{ ++ char *port = "*:4433"; ++ BIO *in = NULL; ++ BIO *ssl_bio, *tmp; ++ SSL_CTX *ctx; ++ SSL_CONF_CTX *cctx = NULL; ++ CONF *conf = NULL; ++ STACK_OF(CONF_VALUE) *sect = NULL; ++ CONF_VALUE *cnf; ++ long errline = -1; ++ char buf[512]; ++ int ret = 1, i; ++ ++ ctx = SSL_CTX_new(TLS_server_method()); ++ ++ conf = NCONF_new(NULL); ++ ++ if (NCONF_load(conf, "accept.cnf", &errline) <= 0) { ++ if (errline <= 0) ++ fprintf(stderr, "Error processing config file\n"); ++ else ++ fprintf(stderr, "Error on line %ld\n", errline); ++ goto err; ++ } ++ ++ sect = NCONF_get_section(conf, "default"); ++ ++ if (sect == NULL) { ++ fprintf(stderr, "Error retrieving default section\n"); ++ goto err; ++ } ++ ++ cctx = SSL_CONF_CTX_new(); ++ SSL_CONF_CTX_set_flags(cctx, SSL_CONF_FLAG_SERVER); ++ SSL_CONF_CTX_set_flags(cctx, SSL_CONF_FLAG_CERTIFICATE); ++ SSL_CONF_CTX_set_flags(cctx, SSL_CONF_FLAG_FILE); ++ SSL_CONF_CTX_set_ssl_ctx(cctx, ctx); ++ for (i = 0; i < sk_CONF_VALUE_num(sect); i++) { ++ int rv; ++ cnf = sk_CONF_VALUE_value(sect, i); ++ rv = SSL_CONF_cmd(cctx, cnf->name, cnf->value); ++ if (rv > 0) ++ continue; ++ if (rv != -2) { ++ fprintf(stderr, "Error processing %s = %s\n", ++ cnf->name, cnf->value); ++ ERR_print_errors_fp(stderr); ++ goto err; ++ } ++ if (strcmp(cnf->name, "Port") == 0) { ++ port = cnf->value; ++ } else { ++ fprintf(stderr, "Unknown configuration option %s\n", cnf->name); ++ goto err; ++ } ++ } ++ ++ if (!SSL_CONF_CTX_finish(cctx)) { ++ fprintf(stderr, "Finish error\n"); ++ ERR_print_errors_fp(stderr); ++ goto err; ++ } ++ ++ /* Setup server side SSL bio */ ++ ssl_bio = BIO_new_ssl(ctx, 0); ++ ++ if ((in = BIO_new_accept(port)) == NULL) ++ goto err; ++ ++ /* ++ * This means that when a new connection is accepted on 'in', The ssl_bio ++ * will be 'duplicated' and have the new socket BIO push into it. ++ * Basically it means the SSL BIO will be automatically setup ++ */ ++ BIO_set_accept_bios(in, ssl_bio); ++ ++ again: ++ /* ++ * The first call will setup the accept socket, and the second will get a ++ * socket. In this loop, the first actual accept will occur in the ++ * BIO_read() function. ++ */ ++ ++ if (BIO_do_accept(in) <= 0) ++ goto err; ++ ++ for (;;) { ++ i = BIO_read(in, buf, 512); ++ if (i == 0) { ++ /* ++ * If we have finished, remove the underlying BIO stack so the ++ * next time we call any function for this BIO, it will attempt ++ * to do an accept ++ */ ++ printf("Done\n"); ++ tmp = BIO_pop(in); ++ BIO_free_all(tmp); ++ goto again; ++ } ++ if (i < 0) { ++ if (BIO_should_retry(in)) ++ continue; ++ goto err; ++ } ++ fwrite(buf, 1, i, stdout); ++ fflush(stdout); ++ } ++ ++ ret = 0; ++ err: ++ if (ret) { ++ ERR_print_errors_fp(stderr); ++ } ++ BIO_free(in); ++ exit(ret); ++ return (!ret); ++} +diff --git a/CryptoPkg/Library/OpensslLib/openssl/demos/bio/server-ec.pem b/CryptoPkg/Library/OpensslLib/openssl/demos/bio/server-ec.pem +new file mode 100644 +index 0000000..a13fdc7 +--- /dev/null ++++ b/CryptoPkg/Library/OpensslLib/openssl/demos/bio/server-ec.pem +@@ -0,0 +1,17 @@ ++-----BEGIN PRIVATE KEY----- ++MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQg/5kYU3PUlHwfdjEN ++lC1xTZEx3o55RgtSOuOCTryDfomhRANCAARW/qUFg+qZzjcFWrST4bmkRCFu8/rn ++KTHjW2vpBXYGXKDn4AbAfYXYhM9J7v1HkkrZBPPGx53eVzs61/Pgr6Rc ++-----END PRIVATE KEY----- ++-----BEGIN CERTIFICATE----- ++MIIBsTCCAVegAwIBAgIJALChLe0vZzgoMAoGCCqGSM49BAMCMDUxHzAdBgNVBAsM ++FlRlc3QgRUNEU0EgQ2VydGlmaWNhdGUxEjAQBgNVBAMMCWxvY2FsaG9zdDAeFw0x ++NTEyMjIxNDUxMDRaFw00NDAxMDQxNDUxMDRaMDUxHzAdBgNVBAsMFlRlc3QgRUNE ++U0EgQ2VydGlmaWNhdGUxEjAQBgNVBAMMCWxvY2FsaG9zdDBZMBMGByqGSM49AgEG ++CCqGSM49AwEHA0IABFb+pQWD6pnONwVatJPhuaREIW7z+ucpMeNba+kFdgZcoOfg ++BsB9hdiEz0nu/UeSStkE88bHnd5XOzrX8+CvpFyjUDBOMB0GA1UdDgQWBBROhkTJ ++lsm8Qd8pEgrrapccfFY5gjAfBgNVHSMEGDAWgBROhkTJlsm8Qd8pEgrrapccfFY5 ++gjAMBgNVHRMEBTADAQH/MAoGCCqGSM49BAMCA0gAMEUCIFhyU/WZRcihilTpwFVm ++fly1JhwisouiZjLnPkRYZVzHAiEAgqxXfRQl1/phnEgO9gRcv2nFp9xvJiDgKPse ++VktDYjE= ++-----END CERTIFICATE----- +diff --git a/CryptoPkg/Library/OpensslLib/openssl/demos/bio/server.pem b/CryptoPkg/Library/OpensslLib/openssl/demos/bio/server.pem +new file mode 100644 +index 0000000..8a4a51f +--- /dev/null ++++ b/CryptoPkg/Library/OpensslLib/openssl/demos/bio/server.pem +@@ -0,0 +1,77 @@ ++subject= C = UK, O = OpenSSL Group, OU = FOR TESTING PURPOSES ONLY, CN = Test Server Cert ++issuer= C = UK, O = OpenSSL Group, OU = FOR TESTING PURPOSES ONLY, CN = OpenSSL Test Intermediate CA ++-----BEGIN CERTIFICATE----- ++MIIDyTCCArGgAwIBAgIBAjANBgkqhkiG9w0BAQsFADBwMQswCQYDVQQGEwJVSzEW ++MBQGA1UECgwNT3BlblNTTCBHcm91cDEiMCAGA1UECwwZRk9SIFRFU1RJTkcgUFVS ++UE9TRVMgT05MWTElMCMGA1UEAwwcT3BlblNTTCBUZXN0IEludGVybWVkaWF0ZSBD ++QTAgFw0xNjAxMDQwODU0NDZaGA8yMTE2MDEwNTA4NTQ0NlowZDELMAkGA1UEBhMC ++VUsxFjAUBgNVBAoMDU9wZW5TU0wgR3JvdXAxIjAgBgNVBAsMGUZPUiBURVNUSU5H ++IFBVUlBPU0VTIE9OTFkxGTAXBgNVBAMMEFRlc3QgU2VydmVyIENlcnQwggEiMA0G ++CSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDzhPOSNtyyRspmeuUpxfNJKCLTuf7g ++3uQ4zu4iHOmRO5TQci+HhVlLZrHF9XqFXcIP0y4pWDbMSGuiorUmzmfiR7bfSdI/ +++qIQt8KXRH6HNG1t8ou0VSvWId5TS5Dq/er5ODUr9OaaDva7EquHIcMvvPQGuI+O ++EAcnleVCy9HVEIySrO4P3CNIicnGkwwiAud05yUAq/gPXBC1hTtmlPD7TVcGVSEi ++Jdvzqqlgv02qedGrkki6GY4S7GjZxrrf7Foc2EP+51LJzwLQx3/JfrCU41NEWAsu ++/Sl0tQabXESN+zJ1pDqoZ3uHMgpQjeGiE0olr+YcsSW/tJmiU9OiAr8RAgMBAAGj ++eDB2MB0GA1UdDgQWBBSCvM8AABPR9zklmifnr9LvIBturDAfBgNVHSMEGDAWgBQ2 ++w2yI55X+sL3szj49hqshgYfa2jAJBgNVHRMEAjAAMBMGA1UdJQQMMAoGCCsGAQUF ++BwMBMBQGA1UdEQQNMAuCCWxvY2FsaG9zdDANBgkqhkiG9w0BAQsFAAOCAQEAC78R ++sAr4uvkYOu/pSwQ3MYOFqZ0BnPuP0/AZW2zF7TLNy8g36GyH9rKxz2ffQEHRmPQN ++Z11Ohg3z03jw/sVzkgt2U5Ipv923sSeCZcu0nuNex3v9/x72ldYikZNhQOsw+2kr ++hx3OvE9R7xl9eyjz7BknsbY7PC3kiUY8SDdc5Fr/XMkHm3ge65oWYOHBjC5tAr5K ++FGCEjM3syxS+Li5X6yfDGiVSjOU4gJuZDCYbl7cEQexU2deds8EmpJJrrI7s4JcQ ++rraHI8+Hu8X9VLpZE1jl/fKJw3D0i53PoN2WhukIOg1Zv+ajMKQ4ubVfISH2ebox +++ybAZO8hxL6/I08/GQ== ++-----END CERTIFICATE----- ++subject= C = UK, O = OpenSSL Group, OU = FOR TESTING PURPOSES ONLY, CN = OpenSSL Test Intermediate CA ++issuer= C = UK, O = OpenSSL Group, OU = FOR TESTING PURPOSES ONLY, CN = OpenSSL Test Root CA ++-----BEGIN CERTIFICATE----- ++MIIDvjCCAqagAwIBAgIJAPzCy4CUW9/qMA0GCSqGSIb3DQEBCwUAMGgxCzAJBgNV ++BAYTAlVLMRYwFAYDVQQKDA1PcGVuU1NMIEdyb3VwMSIwIAYDVQQLDBlGT1IgVEVT ++VElORyBQVVJQT1NFUyBPTkxZMR0wGwYDVQQDDBRPcGVuU1NMIFRlc3QgUm9vdCBD ++QTAeFw0xNTA3MTQxMzIyMDVaFw0yNTA2MjExMzIyMDVaMHAxCzAJBgNVBAYTAlVL ++MRYwFAYDVQQKDA1PcGVuU1NMIEdyb3VwMSIwIAYDVQQLDBlGT1IgVEVTVElORyBQ ++VVJQT1NFUyBPTkxZMSUwIwYDVQQDDBxPcGVuU1NMIFRlc3QgSW50ZXJtZWRpYXRl ++IENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAsErw75CmLYD6pkrG ++W/YhAl/K8L5wJYxDjqu2FghxjD8K308W3EHq4uBxEwR1OHXaM1+6ZZw7/r2I37VL ++IdurBEAIEUdbzx0so74FPawgz5EW2CTqoJnK8F71/vo5Kj1VPwW46CxwxUR3cfvJ ++GNXND2ip0TcyTSPLROXOyQakcVfIGJmdSa1wHKi+c2gMA4emADudZUOYLrg80gr2 ++ldePm07ynbVsKKzCcStw8MdmoW9Qt3fLnPJn2TFUUBNWj+4kvL+88edWCVQXKNds ++ysD/CDrH4W/hjyPDStVsM6XpiNU0+L2ZY6fcj3OP8d0goOx45xotMn9m8hNkCGsr ++VXx9IwIDAQABo2MwYTAdBgNVHQ4EFgQUNsNsiOeV/rC97M4+PYarIYGH2towHwYD ++VR0jBBgwFoAUjBkP10IxdwUG4dOxn+s5+3hxOkUwDwYDVR0TAQH/BAUwAwEB/zAO ++BgNVHQ8BAf8EBAMCAQYwDQYJKoZIhvcNAQELBQADggEBAANQT0pDWBQoT/RY76xz ++audadGz/dfYnwvSwT0RMFcXLcMVVRNqP0HeR8OP8qLaP7onRbNnEXNfos9pxXYlg ++j+/WjWTBLVcr3pX2Xtmcaqw3CGN9qbQI8B3JkYeijZmc5+3r5MzK/9R0w8Y/T9Xt ++CXEiQhtWHpPrFEfrExeVy2kjJNRctEfq3OTd1bjgX64zvTU7eR+MHFYKPoyMqwIR ++gjoVKinvovEwWoZe5kfMQwJNA3IgoJexX9BXbS8efAYF/ku3tS0laoZS/q6V/o5I ++RvG0OqnNgxhul+96PE5ujSaprsyvBswIUKt+e/BCxGaS6f2AJ8RmtoPOSfT4b9qN ++thI= ++-----END CERTIFICATE----- ++-----BEGIN RSA PRIVATE KEY----- ++MIIEpAIBAAKCAQEA84TzkjbcskbKZnrlKcXzSSgi07n+4N7kOM7uIhzpkTuU0HIv ++h4VZS2axxfV6hV3CD9MuKVg2zEhroqK1Js5n4ke230nSP/qiELfCl0R+hzRtbfKL ++tFUr1iHeU0uQ6v3q+Tg1K/Tmmg72uxKrhyHDL7z0BriPjhAHJ5XlQsvR1RCMkqzu ++D9wjSInJxpMMIgLndOclAKv4D1wQtYU7ZpTw+01XBlUhIiXb86qpYL9NqnnRq5JI ++uhmOEuxo2ca63+xaHNhD/udSyc8C0Md/yX6wlONTRFgLLv0pdLUGm1xEjfsydaQ6 ++qGd7hzIKUI3hohNKJa/mHLElv7SZolPTogK/EQIDAQABAoIBAADq9FwNtuE5IRQn ++zGtO4q7Y5uCzZ8GDNYr9RKp+P2cbuWDbvVAecYq2NV9QoIiWJOAYZKklOvekIju3 ++r0UZLA0PRiIrTg6NrESx3JrjWDK8QNlUO7CPTZ39/K+FrmMkV9lem9yxjJjyC34D ++AQB+YRTx+l14HppjdxNwHjAVQpIx/uO2F5xAMuk32+3K+pq9CZUtrofe1q4Agj9R ++5s8mSy9pbRo9kW9wl5xdEotz1LivFOEiqPUJTUq5J5PeMKao3vdK726XI4Z455Nm ++W2/MA0YV0ug2FYinHcZdvKM6dimH8GLfa3X8xKRfzjGjTiMSwsdjgMa4awY3tEHH ++674jhAECgYEA/zqMrc0zsbNk83sjgaYIug5kzEpN4ic020rSZsmQxSCerJTgNhmg ++utKSCt0Re09Jt3LqG48msahX8ycqDsHNvlEGPQSbMu9IYeO3Wr3fAm75GEtFWePY ++BhM73I7gkRt4s8bUiUepMG/wY45c5tRF23xi8foReHFFe9MDzh8fJFECgYEA9EFX ++4qAik1pOJGNei9BMwmx0I0gfVEIgu0tzeVqT45vcxbxr7RkTEaDoAG6PlbWP6D9a ++WQNLp4gsgRM90ZXOJ4up5DsAWDluvaF4/omabMA+MJJ5kGZ0gCj5rbZbKqUws7x8 ++bp+6iBfUPJUbcqNqFmi/08Yt7vrDnMnyMw2A/sECgYEAiiuRMxnuzVm34hQcsbhH ++6ymVqf7j0PW2qK0F4H1ocT9qhzWFd+RB3kHWrCjnqODQoI6GbGr/4JepHUpre1ex ++4UEN5oSS3G0ru0rC3U4C59dZ5KwDHFm7ffZ1pr52ljfQDUsrjjIMRtuiwNK2OoRa ++WSsqiaL+SDzSB+nBmpnAizECgYBdt/y6rerWUx4MhDwwtTnel7JwHyo2MDFS6/5g ++n8qC2Lj6/fMDRE22w+CA2esp7EJNQJGv+b27iFpbJEDh+/Lf5YzIT4MwVskQ5bYB ++JFcmRxUVmf4e09D7o705U/DjCgMH09iCsbLmqQ38ONIRSHZaJtMDtNTHD1yi+jF+ ++OT43gQKBgQC/2OHZoko6iRlNOAQ/tMVFNq7fL81GivoQ9F1U0Qr+DH3ZfaH8eIkX ++xT0ToMPJUzWAn8pZv0snA0um6SIgvkCuxO84OkANCVbttzXImIsL7pFzfcwV/ERK ++UM6j0ZuSMFOCr/lGPAoOQU0fskidGEHi1/kW+suSr28TqsyYZpwBDQ== ++-----END RSA PRIVATE KEY----- +diff --git a/CryptoPkg/Library/OpensslLib/openssl/demos/bio/shared.opt b/CryptoPkg/Library/OpensslLib/openssl/demos/bio/shared.opt +new file mode 100644 +index 0000000..4141b93 +--- /dev/null ++++ b/CryptoPkg/Library/OpensslLib/openssl/demos/bio/shared.opt +@@ -0,0 +1,2 @@ ++OSSL$LIBSSL_SHR/SHARE ++OSSL$LIBCRYPTO_SHR/SHARE +diff --git a/CryptoPkg/Library/OpensslLib/openssl/demos/bio/static.opt b/CryptoPkg/Library/OpensslLib/openssl/demos/bio/static.opt +new file mode 100644 +index 0000000..9ca1588 +--- /dev/null ++++ b/CryptoPkg/Library/OpensslLib/openssl/demos/bio/static.opt +@@ -0,0 +1,2 @@ ++OSSL$LIBSSL/LIB ++OSSL$LIBCRYPTO/LIB +diff --git a/CryptoPkg/Library/OpensslLib/openssl/demos/certs/README b/CryptoPkg/Library/OpensslLib/openssl/demos/certs/README +new file mode 100644 +index 0000000..126663a +--- /dev/null ++++ b/CryptoPkg/Library/OpensslLib/openssl/demos/certs/README +@@ -0,0 +1,21 @@ ++There is often a need to generate test certificates automatically using ++a script. This is often a cause for confusion which can result in incorrect ++CA certificates, obsolete V1 certificates or duplicate serial numbers. ++The range of command line options can be daunting for a beginner. ++ ++The mkcerts.sh script is an example of how to generate certificates ++automatically using scripts. Example creates a root CA, an intermediate CA ++signed by the root and several certificates signed by the intermediate CA. ++ ++The script then creates an empty index.txt file and adds entries for the ++certificates and generates a CRL. Then one certificate is revoked and a ++second CRL generated. ++ ++The script ocsprun.sh runs the test responder on port 8888 covering the ++client certificates. ++ ++The script ocspquery.sh queries the status of the certificates using the ++test responder. ++ ++ ++ +diff --git a/CryptoPkg/Library/OpensslLib/openssl/demos/certs/apps/apps.cnf b/CryptoPkg/Library/OpensslLib/openssl/demos/certs/apps/apps.cnf +new file mode 100644 +index 0000000..531afe6 +--- /dev/null ++++ b/CryptoPkg/Library/OpensslLib/openssl/demos/certs/apps/apps.cnf +@@ -0,0 +1,69 @@ ++# ++# OpenSSL configuration file to create apps directory certificates ++# ++ ++# This definition stops the following lines choking if HOME or CN ++# is undefined. ++HOME = . ++RANDFILE = $ENV::HOME/.rnd ++CN = "Not Defined" ++ ++#################################################################### ++[ req ] ++default_bits = 2048 ++default_keyfile = privkey.pem ++# Don't prompt for fields: use those in section directly ++prompt = no ++distinguished_name = req_distinguished_name ++x509_extensions = v3_ca # The extensions to add to the self signed cert ++string_mask = utf8only ++ ++# req_extensions = v3_req # The extensions to add to a certificate request ++ ++[ req_distinguished_name ] ++countryName = UK ++ ++organizationName = OpenSSL Group ++organizationalUnitName = FOR TESTING PURPOSES ONLY ++# Take CN from environment so it can come from a script. ++commonName = $ENV::CN ++ ++[ usr_cert ] ++ ++# These extensions are added when 'ca' signs a request for an end entity ++# certificate ++ ++basicConstraints=critical, CA:FALSE ++keyUsage=critical, nonRepudiation, digitalSignature, keyEncipherment ++ ++# This will be displayed in Netscape's comment listbox. ++nsComment = "OpenSSL Generated Certificate" ++ ++[ ec_cert ] ++ ++# These extensions are added when 'ca' signs a request for an end entity ++# certificate ++ ++basicConstraints=critical, CA:FALSE ++keyUsage=critical, nonRepudiation, digitalSignature, keyAgreement ++ ++# This will be displayed in Netscape's comment listbox. ++nsComment = "OpenSSL Generated Certificate" ++ ++# PKIX recommendations harmless if included in all certificates. ++subjectKeyIdentifier=hash ++authorityKeyIdentifier=keyid ++ ++[ v3_ca ] ++ ++ ++# Extensions for a typical CA ++ ++# PKIX recommendation. ++ ++subjectKeyIdentifier=hash ++authorityKeyIdentifier=keyid:always ++basicConstraints = critical,CA:true ++keyUsage = critical, cRLSign, keyCertSign ++ ++ +diff --git a/CryptoPkg/Library/OpensslLib/openssl/demos/certs/apps/ckey.pem b/CryptoPkg/Library/OpensslLib/openssl/demos/certs/apps/ckey.pem +new file mode 100644 +index 0000000..8e9054d +--- /dev/null ++++ b/CryptoPkg/Library/OpensslLib/openssl/demos/certs/apps/ckey.pem +@@ -0,0 +1,27 @@ ++-----BEGIN RSA PRIVATE KEY----- ++MIIEpQIBAAKCAQEAtK2p2x0S3C1ajftAc3GaWPsji6scw1k9Sw/XltbLQuDc11/f ++wwrUiFcje2CB3Ri6yD6+uCA3V12jEc4GdqzirJZhwgIhaTv42vfYBgiUcR9McEGr ++agFC3yVR3lIbOzhBjmXNp1on46irxnzU4pT+w58IuvYqUBavaEtfRZocFR5NsIOy ++mRhyNag8htOFK3wmTEYrb0vflFYT6SD47ogYtsd/xWSKS+YFyb7xSusR2Ot6Ktmr ++MswQE57QYJz+KiRVlnL0cduMBdT52Wm8blaC9mz50PyrzjQ68NyHapCoWDU7pe4x ++HLtzpXGSDMPuw4miiSwMym/2wReYJv6cFugLPQIDAQABAoIBAAZOyc9MhIwLSU4L ++p4RgQvM4UVVe8/Id+3XTZ8NsXExJbWxXfIhiqGjaIfL8u4vsgRjcl+v1s/jo2/iT ++KMab4o4D8gXD7UavQVDjtjb/ta79WL3SjRl2Uc9YjjMkyq6WmDNQeo2NKDdafCTB ++1uzSJtLNipB8Z53ELPuHJhxX9QMHrMnuha49riQgXZ7buP9iQrHJFhImBjSzbxJx ++L+TI6rkyLSf9Wi0Pd3L27Ob3QWNfNRYNSeTE+08eSRChkur5W0RuXAcuAICdQlCl ++LBvWO/LmmvbzCqiDcgy/TliSb6CGGwgiNG7LJZmlkYNj8laGwalNlYZs3UrVv6NO ++Br2loAECgYEA2kvCvPGj0Dg/6g7WhXDvAkEbcaL1tSeCxBbNH+6HS2UWMWvyTtCn ++/bbD519QIdkvayy1QjEf32GV/UjUVmlULMLBcDy0DGjtL3+XpIhLKWDNxN1v1/ai ++1oz23ZJCOgnk6K4qtFtlRS1XtynjA+rBetvYvLP9SKeFrnpzCgaA2r0CgYEA0+KX ++1ACXDTNH5ySX3kMjSS9xdINf+OOw4CvPHFwbtc9aqk2HePlEsBTz5I/W3rKwXva3 ++NqZ/bRqVVeZB/hHKFywgdUQk2Uc5z/S7Lw70/w1HubNTXGU06Ngb6zOFAo/o/TwZ ++zTP1BMIKSOB6PAZPS3l+aLO4FRIRotfFhgRHOoECgYEAmiZbqt8cJaJDB/5YYDzC ++mp3tSk6gIb936Q6M5VqkMYp9pIKsxhk0N8aDCnTU+kIK6SzWBpr3/d9Ecmqmfyq7 ++5SvWO3KyVf0WWK9KH0abhOm2BKm2HBQvI0DB5u8sUx2/hsvOnjPYDISbZ11t0MtK ++u35Zy89yMYcSsIYJjG/ROCUCgYEAgI2P9G5PNxEP5OtMwOsW84Y3Xat/hPAQFlI+ ++HES+AzbFGWJkeT8zL2nm95tVkFP1sggZ7Kxjz3w7cpx7GX0NkbWSE9O+T51pNASV ++tN1sQ3p5M+/a+cnlqgfEGJVvc7iAcXQPa3LEi5h2yPR49QYXAgG6cifn3dDSpmwn ++SUI7PQECgYEApGCIIpSRPLAEHTGmP87RBL1smurhwmy2s/pghkvUkWehtxg0sGHh ++kuaqDWcskogv+QC0sVdytiLSz8G0DwcEcsHK1Fkyb8A+ayiw6jWJDo2m9+IF4Fww ++1Te6jFPYDESnbhq7+TLGgHGhtwcu5cnb4vSuYXGXKupZGzoLOBbv1Zw= ++-----END RSA PRIVATE KEY----- +diff --git a/CryptoPkg/Library/OpensslLib/openssl/demos/certs/apps/intkey.pem b/CryptoPkg/Library/OpensslLib/openssl/demos/certs/apps/intkey.pem +new file mode 100644 +index 0000000..d586cb7 +--- /dev/null ++++ b/CryptoPkg/Library/OpensslLib/openssl/demos/certs/apps/intkey.pem +@@ -0,0 +1,27 @@ ++-----BEGIN RSA PRIVATE KEY----- ++MIIEowIBAAKCAQEAsErw75CmLYD6pkrGW/YhAl/K8L5wJYxDjqu2FghxjD8K308W ++3EHq4uBxEwR1OHXaM1+6ZZw7/r2I37VLIdurBEAIEUdbzx0so74FPawgz5EW2CTq ++oJnK8F71/vo5Kj1VPwW46CxwxUR3cfvJGNXND2ip0TcyTSPLROXOyQakcVfIGJmd ++Sa1wHKi+c2gMA4emADudZUOYLrg80gr2ldePm07ynbVsKKzCcStw8MdmoW9Qt3fL ++nPJn2TFUUBNWj+4kvL+88edWCVQXKNdsysD/CDrH4W/hjyPDStVsM6XpiNU0+L2Z ++Y6fcj3OP8d0goOx45xotMn9m8hNkCGsrVXx9IwIDAQABAoIBACg3wIV2o2KIJSZg ++sqXyHY+0GNEZMO5v9E2NAMo//N941lshaN6wrww5FbK39qH9yNylfxmFLe6sgJhA ++fLZprbcXgH+onto+Fpv4UqvCI+4WdHa03U3sJ+70SvxzSy1Gtrbc8FUPJl7qgrFf ++Nn5S8CgOwYb4J6KPguTh5G3Z9RPiCKObwOwEM34hrZUlgPS88wmzu9H6L2GM8A1v ++YBtEr0msBnlJBJOgStyUEfHW2KspNQ+VllQ6c0cedgFXUpl9EoKTLxP+WXwFI1sx ++jFCFzSrMqPcPz1PxU6bXoZE0WH6r+3c8WAW4xR/HVu04BrBDu0CGwn6zAXDy6wCU ++pWogDlkCgYEA4o+nIu2CTzqUlgc22pj+hjenfS5lnCtJfAdrXOJHmnuL+J9h8Nzz ++9kkL+/Y0Xg9bOM6xXPm+81UNpDvOLbUahSSQsfB+LNVEkthJIL4XIk083LsHjFaJ ++9SiCFRbf2OgWrEhe/c1drySwz9u/0f4Q7B6VGqxMnTDjzS5JacZ1pE8CgYEAxzMn ++/n/Dpdn+c4rf14BRNKCv1qBXngPNylKJCmiRpKRJAn+B+Msdwtggk/1Ihju21wSo ++IGy0Gw7WQd1Iq7V85cB2G5PAFY6ybpSV6G3QrzmzuvjHmKvXgUAuuaN+7Pp1YkMY ++rLVjUOcdP5JbXG6XnaCkHYJR8uapPwWPkDt+oO0CgYBI4yZGGlr92j7LNW70TJw1 ++2dnMcAzIfTSa7lgf/bxDetPBHKWJs8vYxA9S9BZM3Gvgjr6IxuAjsI0+9O6TzdvG ++UckrNc+h5Mq241ZDbmRK6MZXzOPUxlKDyJBw8Hb7dU82BeJpjJRDMG6hsHS5vh77 ++l6sodZ4ARCZFcEq1+N8ICQKBgDeBHJLAXO6YmFrvhkGQ4o+senJuSRuhabUHXGIH ++ExXyJNnKV5fQWOGSwTkbKRsmBmNRS9uFDoY/kxnVI8ucjUmjYAV9HNek5DkFs+OI ++vc4lYNwnN85li23bSWm2kcZMX2ra0URGYn8HdtHg4Q4XTq3ANhp21oi9FsmVrhP9 ++T+JdAoGBAK2ebwZ7CXFavDFo4mzLKkGitBjrSi/udFhZECXZWEbNzWlVc3Y3q0cU ++drDqUtbVm+/Xb5CMU044Gqq6SKdObAb3JElKmFylFL9fp2rfL/foUr2sdb87Vqdp ++2j5jZyvt1DKnNaJ7JaFbUdRxlvHQRiqKlZpafN/SMQ0jCs1bSgCg ++-----END RSA PRIVATE KEY----- +diff --git a/CryptoPkg/Library/OpensslLib/openssl/demos/certs/apps/mkacerts.sh b/CryptoPkg/Library/OpensslLib/openssl/demos/certs/apps/mkacerts.sh +new file mode 100644 +index 0000000..7098496 +--- /dev/null ++++ b/CryptoPkg/Library/OpensslLib/openssl/demos/certs/apps/mkacerts.sh +@@ -0,0 +1,45 @@ ++#!/bin/sh ++ ++# Recreate the demo certificates in the apps directory. ++ ++OPENSSL=openssl ++ ++# Root CA: create certificate directly ++CN="OpenSSL Test Root CA" $OPENSSL req -config apps.cnf -x509 -nodes \ ++ -keyout root.pem -out root.pem -key rootkey.pem -new -days 3650 ++# Intermediate CA: request first ++CN="OpenSSL Test Intermediate CA" $OPENSSL req -config apps.cnf -nodes \ ++ -key intkey.pem -out intreq.pem -new ++# Sign request: CA extensions ++$OPENSSL x509 -req -in intreq.pem -CA root.pem -CAkey rootkey.pem -days 3630 \ ++ -extfile apps.cnf -extensions v3_ca -CAcreateserial -out intca.pem ++# Client certificate: request first ++CN="Test Client Cert" $OPENSSL req -config apps.cnf -nodes \ ++ -key ckey.pem -out creq.pem -new ++# Sign using intermediate CA ++$OPENSSL x509 -req -in creq.pem -CA intca.pem -CAkey intkey.pem -days 3600 \ ++ -extfile apps.cnf -extensions usr_cert -CAcreateserial | \ ++ $OPENSSL x509 -nameopt oneline -subject -issuer >client.pem ++# Server certificate: request first ++CN="Test Server Cert" $OPENSSL req -config apps.cnf -nodes \ ++ -key skey.pem -out sreq.pem -new ++# Sign using intermediate CA ++$OPENSSL x509 -req -in sreq.pem -CA intca.pem -CAkey intkey.pem -days 3600 \ ++ -extfile apps.cnf -extensions usr_cert -CAcreateserial | \ ++ $OPENSSL x509 -nameopt oneline -subject -issuer >server.pem ++# Server certificate #2: request first ++CN="Test Server Cert #2" $OPENSSL req -config apps.cnf -nodes \ ++ -key skey2.pem -out sreq2.pem -new ++# Sign using intermediate CA ++$OPENSSL x509 -req -in sreq2.pem -CA intca.pem -CAkey intkey.pem -days 3600 \ ++ -extfile apps.cnf -extensions usr_cert -CAcreateserial | \ ++ $OPENSSL x509 -nameopt oneline -subject -issuer >server2.pem ++ ++# Append keys to file. ++ ++cat skey.pem >>server.pem ++cat skey2.pem >>server2.pem ++cat ckey.pem >>client.pem ++ ++$OPENSSL verify -CAfile root.pem -untrusted intca.pem \ ++ server2.pem server.pem client.pem +diff --git a/CryptoPkg/Library/OpensslLib/openssl/demos/certs/apps/mkxcerts.sh b/CryptoPkg/Library/OpensslLib/openssl/demos/certs/apps/mkxcerts.sh +new file mode 100644 +index 0000000..0f88a48 +--- /dev/null ++++ b/CryptoPkg/Library/OpensslLib/openssl/demos/certs/apps/mkxcerts.sh +@@ -0,0 +1,29 @@ ++ ++# Create certificates using various algorithms to test multi-certificate ++# functionality. ++ ++OPENSSL=../../../apps/openssl ++CN="OpenSSL Test RSA SHA-1 cert" $OPENSSL req \ ++ -config apps.cnf -extensions usr_cert -x509 -nodes \ ++ -keyout tsha1.pem -out tsha1.pem -new -days 3650 -sha1 ++CN="OpenSSL Test RSA SHA-256 cert" $OPENSSL req \ ++ -config apps.cnf -extensions usr_cert -x509 -nodes \ ++ -keyout tsha256.pem -out tsha256.pem -new -days 3650 -sha256 ++CN="OpenSSL Test RSA SHA-512 cert" $OPENSSL req \ ++ -config apps.cnf -extensions usr_cert -x509 -nodes \ ++ -keyout tsha512.pem -out tsha512.pem -new -days 3650 -sha512 ++ ++# Create EC parameters ++ ++$OPENSSL ecparam -name P-256 -out ecp256.pem ++$OPENSSL ecparam -name P-384 -out ecp384.pem ++ ++CN="OpenSSL Test P-256 SHA-256 cert" $OPENSSL req \ ++ -config apps.cnf -extensions ec_cert -x509 -nodes \ ++ -nodes -keyout tecp256.pem -out tecp256.pem -newkey ec:ecp256.pem \ ++ -days 3650 -sha256 ++ ++CN="OpenSSL Test P-384 SHA-384 cert" $OPENSSL req \ ++ -config apps.cnf -extensions ec_cert -x509 -nodes \ ++ -nodes -keyout tecp384.pem -out tecp384.pem -newkey ec:ecp384.pem \ ++ -days 3650 -sha384 +diff --git a/CryptoPkg/Library/OpensslLib/openssl/demos/certs/apps/rootkey.pem b/CryptoPkg/Library/OpensslLib/openssl/demos/certs/apps/rootkey.pem +new file mode 100644 +index 0000000..2600aab +--- /dev/null ++++ b/CryptoPkg/Library/OpensslLib/openssl/demos/certs/apps/rootkey.pem +@@ -0,0 +1,27 @@ ++-----BEGIN RSA PRIVATE KEY----- ++MIIEpgIBAAKCAQEA0xpquKAoY6trkxz8uuE6RyYfMOy+Rgvt19pqG3x8sEpFNjDN ++IG873HniShNaOrseRtrGRgCDcecNOQ0LLOQYo10zz0er8+0YgUWVx5Ag5q3cqN3T ++kjDc+0sRZMONPoUwD0ySOT9dumbJypEjA0q2AgKgWwaO4ilzg/fWTEruLeuL4meX ++K9WZFmMnGuF4kHSocZeKWs5UM86WIOf/+NdtzLNd6a5HwqAB5Azggiz2Ngck6Aet ++Mi0inBr3A1MSn0oIaQ7rGvbQ2QrIOnpdHJ36GadQHuvvtZOm28o8UVONMMWoS1yJ ++/1TaRWQJ+faZJE7yegJtUf75+5HwsxaUP32C3wIDAQABAoIBAQCEybEnwVamm0Vn ++nGw9AT+vUYN9Ou3VEdviUzk7YOrt2Un/9GKTbGSzItf80H+JQfqhhywBDIGiPDxN ++Dq9g5Xm6CP51/BdlsFYhuqukhDyt3d9XOXHEG4hlaarfP0KxeQXqGbhA2mMSxWVZ ++TkI/59blHNHRcCagjIJlGJhsFRYNO1/ApfA5zN7fWCFvH1XWZhuvsPDgUXKm4BS0 ++p3ol67MVJHRfYcLb/txBO5rBhSXinK0jEBiljRcE0rWzRycSedmDgG3SNV17wvA0 ++UWgMNpPcJ1b7Satr0nM7A8+siV8FRcfvPqCuGPKCYTrNn71hGJEhKXKwlURj9+95 ++O5yzRxjBAoGBAPtTRYN40/piRB0XLpi+zNh+4Ba4TGfXSymbaozgC/pI5wfgGXrz ++IpT9ujjV42r8TABHvXa6uiGm0cbxcUgq2n6Y8rf6iHxmn23ezCEBUs7rd6jtt11b ++m58T8o0XWyOgAovaH0UgzMtrlsZYR2fli5254oRkTWwaUTuO38z6CVddAoGBANcH ++nvdu3RniIYStsr5/deu7l81ZQ9rSiR1m3H6Wy8ryMIfkYfa0WqXhwNHrLrhvhLIQ ++7mGnJ+jAkJyVQULE6UdbmVW8tC58Dfrgz/1s7RMeUYPnOmRpx79c/LqZ2IunfFWx ++IvBvFu7vidEHA+1tU2N+oXNsU+B9XpfsJ+/d2QtrAoGBAJTuP58tFtClMp/agO5b ++AqC4bqqIBB704cGCK53XlsF2OhHcprzJH5ES2iub8+wOHit8V7Xn6SzP4jf2E58k ++Zd3nXM3RVNgDKC6/fE+CrUOZHYupcqOMCag29eDOGl/+DgQ5+ZXJXhKdaveWkJns ++2NNat/SkS4zn+4NDozOgZ7CxAoGBAIuXjfJRTUXNUDci0APtGO9U1AJiLbOzs4Gb ++0g539IqmWS0O7S3L/YDsolFkXOsssjcq2KYabsUhpX+RQVGIJWzGoS9QlqQKssSo ++Bz4c5Xbg2shHZtfi9+JaClNVJofazdOPcAAoDfpFFPHWnQ0YSOcxQLx+maEFok/7 ++5h1IputLAoGBAKGBWDPwskgRRfCAIFpCJLOu/9D30M/akMtO0kJYQpBjOaKuigUy ++ic7pthFVse/pMUljXHAd1hs2CTjMW1ukEusU3x1Ei6wvnHHqn0Hs+6D5NQFQkcMn ++7rejJ+bpJPRAn40AAV5hGBYI12XycB8ZgyPC4hTUK6unGVK06DC4qvdv ++-----END RSA PRIVATE KEY----- +diff --git a/CryptoPkg/Library/OpensslLib/openssl/demos/certs/apps/skey.pem b/CryptoPkg/Library/OpensslLib/openssl/demos/certs/apps/skey.pem +new file mode 100644 +index 0000000..dbd403d +--- /dev/null ++++ b/CryptoPkg/Library/OpensslLib/openssl/demos/certs/apps/skey.pem +@@ -0,0 +1,27 @@ ++-----BEGIN RSA PRIVATE KEY----- ++MIIEpAIBAAKCAQEA84TzkjbcskbKZnrlKcXzSSgi07n+4N7kOM7uIhzpkTuU0HIv ++h4VZS2axxfV6hV3CD9MuKVg2zEhroqK1Js5n4ke230nSP/qiELfCl0R+hzRtbfKL ++tFUr1iHeU0uQ6v3q+Tg1K/Tmmg72uxKrhyHDL7z0BriPjhAHJ5XlQsvR1RCMkqzu ++D9wjSInJxpMMIgLndOclAKv4D1wQtYU7ZpTw+01XBlUhIiXb86qpYL9NqnnRq5JI ++uhmOEuxo2ca63+xaHNhD/udSyc8C0Md/yX6wlONTRFgLLv0pdLUGm1xEjfsydaQ6 ++qGd7hzIKUI3hohNKJa/mHLElv7SZolPTogK/EQIDAQABAoIBAADq9FwNtuE5IRQn ++zGtO4q7Y5uCzZ8GDNYr9RKp+P2cbuWDbvVAecYq2NV9QoIiWJOAYZKklOvekIju3 ++r0UZLA0PRiIrTg6NrESx3JrjWDK8QNlUO7CPTZ39/K+FrmMkV9lem9yxjJjyC34D ++AQB+YRTx+l14HppjdxNwHjAVQpIx/uO2F5xAMuk32+3K+pq9CZUtrofe1q4Agj9R ++5s8mSy9pbRo9kW9wl5xdEotz1LivFOEiqPUJTUq5J5PeMKao3vdK726XI4Z455Nm ++W2/MA0YV0ug2FYinHcZdvKM6dimH8GLfa3X8xKRfzjGjTiMSwsdjgMa4awY3tEHH ++674jhAECgYEA/zqMrc0zsbNk83sjgaYIug5kzEpN4ic020rSZsmQxSCerJTgNhmg ++utKSCt0Re09Jt3LqG48msahX8ycqDsHNvlEGPQSbMu9IYeO3Wr3fAm75GEtFWePY ++BhM73I7gkRt4s8bUiUepMG/wY45c5tRF23xi8foReHFFe9MDzh8fJFECgYEA9EFX ++4qAik1pOJGNei9BMwmx0I0gfVEIgu0tzeVqT45vcxbxr7RkTEaDoAG6PlbWP6D9a ++WQNLp4gsgRM90ZXOJ4up5DsAWDluvaF4/omabMA+MJJ5kGZ0gCj5rbZbKqUws7x8 ++bp+6iBfUPJUbcqNqFmi/08Yt7vrDnMnyMw2A/sECgYEAiiuRMxnuzVm34hQcsbhH ++6ymVqf7j0PW2qK0F4H1ocT9qhzWFd+RB3kHWrCjnqODQoI6GbGr/4JepHUpre1ex ++4UEN5oSS3G0ru0rC3U4C59dZ5KwDHFm7ffZ1pr52ljfQDUsrjjIMRtuiwNK2OoRa ++WSsqiaL+SDzSB+nBmpnAizECgYBdt/y6rerWUx4MhDwwtTnel7JwHyo2MDFS6/5g ++n8qC2Lj6/fMDRE22w+CA2esp7EJNQJGv+b27iFpbJEDh+/Lf5YzIT4MwVskQ5bYB ++JFcmRxUVmf4e09D7o705U/DjCgMH09iCsbLmqQ38ONIRSHZaJtMDtNTHD1yi+jF+ ++OT43gQKBgQC/2OHZoko6iRlNOAQ/tMVFNq7fL81GivoQ9F1U0Qr+DH3ZfaH8eIkX ++xT0ToMPJUzWAn8pZv0snA0um6SIgvkCuxO84OkANCVbttzXImIsL7pFzfcwV/ERK ++UM6j0ZuSMFOCr/lGPAoOQU0fskidGEHi1/kW+suSr28TqsyYZpwBDQ== ++-----END RSA PRIVATE KEY----- +diff --git a/CryptoPkg/Library/OpensslLib/openssl/demos/certs/apps/skey2.pem b/CryptoPkg/Library/OpensslLib/openssl/demos/certs/apps/skey2.pem +new file mode 100644 +index 0000000..7853822 +--- /dev/null ++++ b/CryptoPkg/Library/OpensslLib/openssl/demos/certs/apps/skey2.pem +@@ -0,0 +1,27 @@ ++-----BEGIN RSA PRIVATE KEY----- ++MIIEowIBAAKCAQEA63Yu4/cnLRvi+BIwcoIz5hKmcziREG2tujKEBs4JVO3uV3+f ++UW/4YFULigKImXu/0fKyuMyeFu4l3V8NC6gachvAeWhiniN9sPgPU3AQKaF1y9gq ++2EBEI2cFCKS5WASItjZCY951ZKuXYJdYDgC4kPlvI4N5M4ORHPa4pqfa/dzfMLEi ++92sLGn7q5mArzn+5Xh2jD9Vif8w0RlDRxv1rQ413PGVBtfuhF1PSXNhbPtjpn+33 ++DdJdNACv8D4PDmjUtKyshqvSXSE/RURldW13v68efBWhOQiLXcAkmISbxfzveS1k ++KMSV8nuWwhS5rw0xMlavRTEgqbX7Jm14xGRrFwIDAQABAoIBAHLsTPihIfLnYIE5 ++x4GsQQ5zXeBw5ITDM37ktwHnQDC+rIzyUl1aLD1AZRBoKinXd4lOTqLZ4/NHKx4A ++DYr58mZtWyUmqLOMmQVuHXTZBlp7XtYuXMMNovQwjQlp9LicBeoBU6gQ5PVMtubD ++F4xGF89Sn0cTHW3iMkqTtQ5KcR1j57OcJO0FEb1vPvk2MXI5ZyAatUYE7YacbEzd ++rg02uIwx3FqNSkuSI79uz4hMdV5TPtuhxx9nTwj9aLUhXFeZ0mn2PVgVzEnnMoJb +++znlsZDgzDlJqdaD744YGWh8Z3OEssB35KfzFcdOeO6yH8lmv2Zfznk7pNPT7LTb ++Lae9VgkCgYEA92p1qnAB3NtJtNcaW53i0S5WJgS1hxWKvUDx3lTB9s8X9fHpqL1a ++E94fDfWzp/hax6FefUKIvBOukPLQ6bYjTMiFoOHzVirghAIuIUoMI5VtLhwD1hKs ++Lr7l/dptMgKb1nZHyXoKHRBthsy3K4+udsPi8TzMvYElgEqyQIe/Rk0CgYEA86GL ++8HC6zLszzKERDPBxrboRmoFvVUCTQDhsfj1M8aR3nQ8V5LkdIJc7Wqm/Ggfk9QRf ++rJ8M2WUMlU5CNnCn/KCrKzCNZIReze3fV+HnKdbcXGLvgbHPrhnz8yYehUFG+RGq ++bVyDWRU94T38izy2s5qMYrMJWZEYyXncSPbfcPMCgYAtaXfxcZ+V5xYPQFARMtiX ++5nZfggvDoJuXgx0h3tK/N2HBfcaSdzbaYLG4gTmZggc/jwnl2dl5E++9oSPhUdIG ++3ONSFUbxsOsGr9PBvnKd8WZZyUCXAVRjPBzAzF+whzQNWCZy/5htnz9LN7YDI9s0 ++5113Q96cheDZPFydZY0hHQKBgQDVbEhNukM5xCiNcu+f2SaMnLp9EjQ4h5g3IvaP ++5B16daw/Dw8LzcohWboqIxeAsze0GD/D1ZUJAEd0qBjC3g+a9BjefervCjKOzXng ++38mEUm+6EwVjJSQcjSmycEs+Sr/kwr/8i5WYvU32+jk4tFgMoC+o6tQe/Uesf68k ++z/dPVwKBgGbF7Vv1/3SmhlOy+zYyvJ0CrWtKxH9QP6tLIEgEpd8x7YTSuCH94yok ++kToMXYA3sWNPt22GbRDZ+rcp4c7HkDx6I6vpdP9aQEwJTp0EPy0sgWr2XwYmreIQ ++NFmkk8Itn9EY2R9VBaP7GLv5kvwxDdLAnmwGmzVtbmaVdxCaBwUk ++-----END RSA PRIVATE KEY----- +diff --git a/CryptoPkg/Library/OpensslLib/openssl/demos/certs/ca.cnf b/CryptoPkg/Library/OpensslLib/openssl/demos/certs/ca.cnf +new file mode 100644 +index 0000000..5a8a5f2 +--- /dev/null ++++ b/CryptoPkg/Library/OpensslLib/openssl/demos/certs/ca.cnf +@@ -0,0 +1,86 @@ ++# ++# OpenSSL example configuration file for automated certificate creation. ++# ++ ++# This definition stops the following lines choking if HOME or CN ++# is undefined. ++HOME = . ++RANDFILE = $ENV::HOME/.rnd ++CN = "Not Defined" ++default_ca = ca ++ ++#################################################################### ++[ req ] ++default_bits = 1024 ++default_keyfile = privkey.pem ++# Don't prompt for fields: use those in section directly ++prompt = no ++distinguished_name = req_distinguished_name ++x509_extensions = v3_ca # The extensions to add to the self signed cert ++string_mask = utf8only ++ ++# req_extensions = v3_req # The extensions to add to a certificate request ++ ++[ req_distinguished_name ] ++countryName = UK ++ ++organizationName = OpenSSL Group ++# Take CN from environment so it can come from a script. ++commonName = $ENV::CN ++ ++[ usr_cert ] ++ ++# These extensions are added when 'ca' signs a request for an end entity ++# certificate ++ ++basicConstraints=critical, CA:FALSE ++keyUsage=critical, nonRepudiation, digitalSignature, keyEncipherment ++ ++# This will be displayed in Netscape's comment listbox. ++nsComment = "OpenSSL Generated Certificate" ++ ++# PKIX recommendations harmless if included in all certificates. ++subjectKeyIdentifier=hash ++authorityKeyIdentifier=keyid ++# OCSP responder certificate ++[ ocsp_cert ] ++ ++basicConstraints=critical, CA:FALSE ++keyUsage=critical, nonRepudiation, digitalSignature, keyEncipherment ++ ++# This will be displayed in Netscape's comment listbox. ++nsComment = "OpenSSL Generated Certificate" ++ ++# PKIX recommendations harmless if included in all certificates. ++subjectKeyIdentifier=hash ++authorityKeyIdentifier=keyid ++extendedKeyUsage=OCSPSigning ++ ++[ dh_cert ] ++ ++# These extensions are added when 'ca' signs a request for an end entity ++# DH certificate ++ ++basicConstraints=critical, CA:FALSE ++keyUsage=critical, keyAgreement ++ ++# PKIX recommendations harmless if included in all certificates. ++subjectKeyIdentifier=hash ++authorityKeyIdentifier=keyid ++ ++[ v3_ca ] ++ ++ ++# Extensions for a typical CA ++ ++# PKIX recommendation. ++ ++subjectKeyIdentifier=hash ++authorityKeyIdentifier=keyid:always ++basicConstraints = critical,CA:true ++keyUsage = critical, cRLSign, keyCertSign ++ ++# Minimal CA entry to allow generation of CRLs. ++[ca] ++database=index.txt ++crlnumber=crlnum.txt +diff --git a/CryptoPkg/Library/OpensslLib/openssl/demos/certs/mkcerts.sh b/CryptoPkg/Library/OpensslLib/openssl/demos/certs/mkcerts.sh +new file mode 100644 +index 0000000..18daa6b +--- /dev/null ++++ b/CryptoPkg/Library/OpensslLib/openssl/demos/certs/mkcerts.sh +@@ -0,0 +1,96 @@ ++#!/bin/sh ++ ++OPENSSL=../../apps/openssl ++OPENSSL_CONF=../../apps/openssl.cnf ++export OPENSSL_CONF ++ ++# Root CA: create certificate directly ++CN="Test Root CA" $OPENSSL req -config ca.cnf -x509 -nodes \ ++ -keyout root.pem -out root.pem -newkey rsa:2048 -days 3650 ++# Intermediate CA: request first ++CN="Test Intermediate CA" $OPENSSL req -config ca.cnf -nodes \ ++ -keyout intkey.pem -out intreq.pem -newkey rsa:2048 ++# Sign request: CA extensions ++$OPENSSL x509 -req -in intreq.pem -CA root.pem -days 3600 \ ++ -extfile ca.cnf -extensions v3_ca -CAcreateserial -out intca.pem ++ ++# Server certificate: create request first ++CN="Test Server Cert" $OPENSSL req -config ca.cnf -nodes \ ++ -keyout skey.pem -out req.pem -newkey rsa:1024 ++# Sign request: end entity extensions ++$OPENSSL x509 -req -in req.pem -CA intca.pem -CAkey intkey.pem -days 3600 \ ++ -extfile ca.cnf -extensions usr_cert -CAcreateserial -out server.pem ++ ++# Client certificate: request first ++CN="Test Client Cert" $OPENSSL req -config ca.cnf -nodes \ ++ -keyout ckey.pem -out creq.pem -newkey rsa:1024 ++# Sign using intermediate CA ++$OPENSSL x509 -req -in creq.pem -CA intca.pem -CAkey intkey.pem -days 3600 \ ++ -extfile ca.cnf -extensions usr_cert -CAcreateserial -out client.pem ++ ++# Revoked certificate: request first ++CN="Test Revoked Cert" $OPENSSL req -config ca.cnf -nodes \ ++ -keyout revkey.pem -out rreq.pem -newkey rsa:1024 ++# Sign using intermediate CA ++$OPENSSL x509 -req -in rreq.pem -CA intca.pem -CAkey intkey.pem -days 3600 \ ++ -extfile ca.cnf -extensions usr_cert -CAcreateserial -out rev.pem ++ ++# OCSP responder certificate: request first ++CN="Test OCSP Responder Cert" $OPENSSL req -config ca.cnf -nodes \ ++ -keyout respkey.pem -out respreq.pem -newkey rsa:1024 ++# Sign using intermediate CA and responder extensions ++$OPENSSL x509 -req -in respreq.pem -CA intca.pem -CAkey intkey.pem -days 3600 \ ++ -extfile ca.cnf -extensions ocsp_cert -CAcreateserial -out resp.pem ++ ++# Example creating a PKCS#3 DH certificate. ++ ++# First DH parameters ++ ++[ -f dhp.pem ] || $OPENSSL genpkey -genparam -algorithm DH -pkeyopt dh_paramgen_prime_len:1024 -out dhp.pem ++ ++# Now a DH private key ++$OPENSSL genpkey -paramfile dhp.pem -out dhskey.pem ++# Create DH public key file ++$OPENSSL pkey -in dhskey.pem -pubout -out dhspub.pem ++# Certificate request, key just reuses old one as it is ignored when the ++# request is signed. ++CN="Test Server DH Cert" $OPENSSL req -config ca.cnf -new \ ++ -key skey.pem -out dhsreq.pem ++# Sign request: end entity DH extensions ++$OPENSSL x509 -req -in dhsreq.pem -CA root.pem -days 3600 \ ++ -force_pubkey dhspub.pem \ ++ -extfile ca.cnf -extensions dh_cert -CAcreateserial -out dhserver.pem ++ ++# DH client certificate ++ ++$OPENSSL genpkey -paramfile dhp.pem -out dhckey.pem ++$OPENSSL pkey -in dhckey.pem -pubout -out dhcpub.pem ++CN="Test Client DH Cert" $OPENSSL req -config ca.cnf -new \ ++ -key skey.pem -out dhcreq.pem ++$OPENSSL x509 -req -in dhcreq.pem -CA root.pem -days 3600 \ ++ -force_pubkey dhcpub.pem \ ++ -extfile ca.cnf -extensions dh_cert -CAcreateserial -out dhclient.pem ++ ++# Examples of CRL generation without the need to use 'ca' to issue ++# certificates. ++# Create zero length index file ++>index.txt ++# Create initial crl number file ++echo 01 >crlnum.txt ++# Add entries for server and client certs ++$OPENSSL ca -valid server.pem -keyfile root.pem -cert root.pem \ ++ -config ca.cnf -md sha1 ++$OPENSSL ca -valid client.pem -keyfile root.pem -cert root.pem \ ++ -config ca.cnf -md sha1 ++$OPENSSL ca -valid rev.pem -keyfile root.pem -cert root.pem \ ++ -config ca.cnf -md sha1 ++# Generate a CRL. ++$OPENSSL ca -gencrl -keyfile root.pem -cert root.pem -config ca.cnf \ ++ -md sha1 -crldays 1 -out crl1.pem ++# Revoke a certificate ++openssl ca -revoke rev.pem -crl_reason superseded \ ++ -keyfile root.pem -cert root.pem -config ca.cnf -md sha1 ++# Generate another CRL ++$OPENSSL ca -gencrl -keyfile root.pem -cert root.pem -config ca.cnf \ ++ -md sha1 -crldays 1 -out crl2.pem ++ +diff --git a/CryptoPkg/Library/OpensslLib/openssl/demos/certs/ocspquery.sh b/CryptoPkg/Library/OpensslLib/openssl/demos/certs/ocspquery.sh +new file mode 100644 +index 0000000..f664113 +--- /dev/null ++++ b/CryptoPkg/Library/OpensslLib/openssl/demos/certs/ocspquery.sh +@@ -0,0 +1,21 @@ ++# Example querying OpenSSL test responder. Assumes ocsprun.sh has been ++# called. ++ ++OPENSSL=../../apps/openssl ++OPENSSL_CONF=../../apps/openssl.cnf ++export OPENSSL_CONF ++ ++# Send responder queries for each certificate. ++ ++echo "Requesting OCSP status for each certificate" ++$OPENSSL ocsp -issuer intca.pem -cert client.pem -CAfile root.pem \ ++ -url http://127.0.0.1:8888/ ++$OPENSSL ocsp -issuer intca.pem -cert server.pem -CAfile root.pem \ ++ -url http://127.0.0.1:8888/ ++$OPENSSL ocsp -issuer intca.pem -cert rev.pem -CAfile root.pem \ ++ -url http://127.0.0.1:8888/ ++# One query for all three certificates. ++echo "Requesting OCSP status for three certificates in one request" ++$OPENSSL ocsp -issuer intca.pem \ ++ -cert client.pem -cert server.pem -cert rev.pem \ ++ -CAfile root.pem -url http://127.0.0.1:8888/ +diff --git a/CryptoPkg/Library/OpensslLib/openssl/demos/certs/ocsprun.sh b/CryptoPkg/Library/OpensslLib/openssl/demos/certs/ocsprun.sh +new file mode 100644 +index 0000000..a65e5f2 +--- /dev/null ++++ b/CryptoPkg/Library/OpensslLib/openssl/demos/certs/ocsprun.sh +@@ -0,0 +1,14 @@ ++# Example of running an querying OpenSSL test OCSP responder. ++# This assumes "mkcerts.sh" or similar has been run to set up the ++# necessary file structure. ++ ++OPENSSL=../../apps/openssl ++OPENSSL_CONF=../../apps/openssl.cnf ++export OPENSSL_CONF ++ ++# Run OCSP responder. ++ ++PORT=8888 ++ ++$OPENSSL ocsp -port $PORT -index index.txt -CA intca.pem \ ++ -rsigner resp.pem -rkey respkey.pem -rother intca.pem $* +diff --git a/CryptoPkg/Library/OpensslLib/openssl/demos/cms/cacert.pem b/CryptoPkg/Library/OpensslLib/openssl/demos/cms/cacert.pem +new file mode 100644 +index 0000000..75cbb34 +--- /dev/null ++++ b/CryptoPkg/Library/OpensslLib/openssl/demos/cms/cacert.pem +@@ -0,0 +1,18 @@ ++-----BEGIN CERTIFICATE----- ++MIIC6DCCAlGgAwIBAgIJAMfGO3rdo2uUMA0GCSqGSIb3DQEBBAUAMFcxCzAJBgNV ++BAYTAlVLMRIwEAYDVQQHEwlUZXN0IENpdHkxFjAUBgNVBAoTDU9wZW5TU0wgR3Jv ++dXAxHDAaBgNVBAMTE1Rlc3QgUy9NSU1FIFJvb3QgQ0EwHhcNMDcwNDEzMTc0MzE3 ++WhcNMTcwNDEwMTc0MzE3WjBXMQswCQYDVQQGEwJVSzESMBAGA1UEBxMJVGVzdCBD ++aXR5MRYwFAYDVQQKEw1PcGVuU1NMIEdyb3VwMRwwGgYDVQQDExNUZXN0IFMvTUlN ++RSBSb290IENBMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCqJMal1uC1/1wz ++i5+dE4EZF2im3BgROm5PVMbwPY9V1t+KYvtdc3rMcRgJaMbP+qaEcDXoIsZfYXGR ++ielgfDNZmZcj1y/FOum+Jc2OZMs3ggPmjIQ3dbBECq0hZKcbz7wfr+2OeNWm46iT ++jcSIXpGIRhUYEzOgv7zb8oOU70IbbwIDAQABo4G7MIG4MB0GA1UdDgQWBBRHUypx ++CXFQYqewhGo72lWPQUsjoDCBiAYDVR0jBIGAMH6AFEdTKnEJcVBip7CEajvaVY9B ++SyOgoVukWTBXMQswCQYDVQQGEwJVSzESMBAGA1UEBxMJVGVzdCBDaXR5MRYwFAYD ++VQQKEw1PcGVuU1NMIEdyb3VwMRwwGgYDVQQDExNUZXN0IFMvTUlNRSBSb290IENB ++ggkAx8Y7et2ja5QwDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQQFAAOBgQANI+Yc ++G/YDM1WMUGEzEkU9UhsIUqdyBebnK3+OyxZSouDcE/M10jFJzBf/F5b0uUGAKWwo ++u0dzmILfKjdfWe8EyCRafZcm00rVcO09i/63FBYzlHbmfUATIqZdhKzxxQMPs5mF ++1je+pHUpzIY8TSXyh/uD9IkAy04IHwGZQf9akw== ++-----END CERTIFICATE----- +diff --git a/CryptoPkg/Library/OpensslLib/openssl/demos/cms/cakey.pem b/CryptoPkg/Library/OpensslLib/openssl/demos/cms/cakey.pem +new file mode 100644 +index 0000000..3b53c5e +--- /dev/null ++++ b/CryptoPkg/Library/OpensslLib/openssl/demos/cms/cakey.pem +@@ -0,0 +1,15 @@ ++-----BEGIN RSA PRIVATE KEY----- ++MIICXgIBAAKBgQCqJMal1uC1/1wzi5+dE4EZF2im3BgROm5PVMbwPY9V1t+KYvtd ++c3rMcRgJaMbP+qaEcDXoIsZfYXGRielgfDNZmZcj1y/FOum+Jc2OZMs3ggPmjIQ3 ++dbBECq0hZKcbz7wfr+2OeNWm46iTjcSIXpGIRhUYEzOgv7zb8oOU70IbbwIDAQAB ++AoGBAKWOZ2UTc1BkjDjz0XoscmAR8Rj77MdGzfOPkIxPultSW+3yZpkGNyUbnsH5 ++HAtf4Avai/m3bMN+s91kDpx9/g/I9ZEHPQLcDICETvwt/EHT7+hwvaQgsM+TgpMs ++tjlGZOWent6wVIuvwwzqOMXZLgK9FvY7upwgtrys4G3Kab5hAkEA2QzFflWyEvKS ++rMSaVtn/IjFilwa7H0IdakkjM34z4peerFTPBr4J47YD4RCR/dAvxyNy3zUxtH18 ++9R6dUixI6QJBAMitJD0xOkbGWBX8KVJvRiKOIdf/95ZUAgN/h3bWKy57EB9NYj3u ++jbxXcvdjfSqiITykkjAg7SG7nrlzJsu6CpcCQG6gVsy0auXDY0TRlASuaZ6I40Is ++uRUOgqWYj2uAaHuWYdZeB4LdO3cnX0TISFDAWom6JKNlnmbrCtR4fSDT13kCQQCU +++VQJyV3F5MDHsWbLt6eNR46AV5lpk/vatPXPlrZ/zwPs+PmRmGLICvNiDA2DdNDP ++wCx2Zjsj67CtY3rNitMJAkEAm09BQnjnbBXUb1rd2SjNDWTsu80Z+zLu8pAwXNhW ++8nsvMYqlYMIxuMPwu/QuTnMRhMZ08uhqoD3ukZnBeoMEVg== ++-----END RSA PRIVATE KEY----- +diff --git a/CryptoPkg/Library/OpensslLib/openssl/demos/cms/cms_comp.c b/CryptoPkg/Library/OpensslLib/openssl/demos/cms/cms_comp.c +new file mode 100644 +index 0000000..0d548f9 +--- /dev/null ++++ b/CryptoPkg/Library/OpensslLib/openssl/demos/cms/cms_comp.c +@@ -0,0 +1,64 @@ ++/* ++ * Copyright 2008-2016 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 ++ * in the file LICENSE in the source distribution or at ++ * https://www.openssl.org/source/license.html ++ */ ++ ++/* Simple S/MIME compress example */ ++#include ++#include ++#include ++ ++int main(int argc, char **argv) ++{ ++ BIO *in = NULL, *out = NULL; ++ CMS_ContentInfo *cms = NULL; ++ int ret = 1; ++ ++ /* ++ * On OpenSSL 1.0.0+ only: ++ * for streaming set CMS_STREAM ++ */ ++ int flags = CMS_STREAM; ++ ++ OpenSSL_add_all_algorithms(); ++ ERR_load_crypto_strings(); ++ ++ /* Open content being compressed */ ++ ++ in = BIO_new_file("comp.txt", "r"); ++ ++ if (!in) ++ goto err; ++ ++ /* compress content */ ++ cms = CMS_compress(in, NID_zlib_compression, flags); ++ ++ if (!cms) ++ goto err; ++ ++ out = BIO_new_file("smcomp.txt", "w"); ++ if (!out) ++ goto err; ++ ++ /* Write out S/MIME message */ ++ if (!SMIME_write_CMS(out, cms, in, flags)) ++ goto err; ++ ++ ret = 0; ++ ++ err: ++ ++ if (ret) { ++ fprintf(stderr, "Error Compressing Data\n"); ++ ERR_print_errors_fp(stderr); ++ } ++ ++ CMS_ContentInfo_free(cms); ++ BIO_free(in); ++ BIO_free(out); ++ return ret; ++} +diff --git a/CryptoPkg/Library/OpensslLib/openssl/demos/cms/cms_ddec.c b/CryptoPkg/Library/OpensslLib/openssl/demos/cms/cms_ddec.c +new file mode 100644 +index 0000000..8f2e9ae +--- /dev/null ++++ b/CryptoPkg/Library/OpensslLib/openssl/demos/cms/cms_ddec.c +@@ -0,0 +1,88 @@ ++/* ++ * Copyright 2008-2016 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 ++ * in the file LICENSE in the source distribution or at ++ * https://www.openssl.org/source/license.html ++ */ ++ ++/* ++ * S/MIME detached data decrypt example: rarely done but should the need ++ * arise this is an example.... ++ */ ++#include ++#include ++#include ++ ++int main(int argc, char **argv) ++{ ++ BIO *in = NULL, *out = NULL, *tbio = NULL, *dcont = NULL; ++ X509 *rcert = NULL; ++ EVP_PKEY *rkey = NULL; ++ CMS_ContentInfo *cms = NULL; ++ int ret = 1; ++ ++ OpenSSL_add_all_algorithms(); ++ ERR_load_crypto_strings(); ++ ++ /* Read in recipient certificate and private key */ ++ tbio = BIO_new_file("signer.pem", "r"); ++ ++ if (!tbio) ++ goto err; ++ ++ rcert = PEM_read_bio_X509(tbio, NULL, 0, NULL); ++ ++ BIO_reset(tbio); ++ ++ rkey = PEM_read_bio_PrivateKey(tbio, NULL, 0, NULL); ++ ++ if (!rcert || !rkey) ++ goto err; ++ ++ /* Open PEM file containing enveloped data */ ++ ++ in = BIO_new_file("smencr.pem", "r"); ++ ++ if (!in) ++ goto err; ++ ++ /* Parse PEM content */ ++ cms = PEM_read_bio_CMS(in, NULL, 0, NULL); ++ ++ if (!cms) ++ goto err; ++ ++ /* Open file containing detached content */ ++ dcont = BIO_new_file("smencr.out", "rb"); ++ ++ if (!in) ++ goto err; ++ ++ out = BIO_new_file("encrout.txt", "w"); ++ if (!out) ++ goto err; ++ ++ /* Decrypt S/MIME message */ ++ if (!CMS_decrypt(cms, rkey, rcert, dcont, out, 0)) ++ goto err; ++ ++ ret = 0; ++ ++ err: ++ ++ if (ret) { ++ fprintf(stderr, "Error Decrypting Data\n"); ++ ERR_print_errors_fp(stderr); ++ } ++ ++ CMS_ContentInfo_free(cms); ++ X509_free(rcert); ++ EVP_PKEY_free(rkey); ++ BIO_free(in); ++ BIO_free(out); ++ BIO_free(tbio); ++ BIO_free(dcont); ++ return ret; ++} +diff --git a/CryptoPkg/Library/OpensslLib/openssl/demos/cms/cms_dec.c b/CryptoPkg/Library/OpensslLib/openssl/demos/cms/cms_dec.c +new file mode 100644 +index 0000000..4f9428b +--- /dev/null ++++ b/CryptoPkg/Library/OpensslLib/openssl/demos/cms/cms_dec.c +@@ -0,0 +1,78 @@ ++/* ++ * Copyright 2008-2016 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 ++ * in the file LICENSE in the source distribution or at ++ * https://www.openssl.org/source/license.html ++ */ ++ ++/* Simple S/MIME decryption example */ ++#include ++#include ++#include ++ ++int main(int argc, char **argv) ++{ ++ BIO *in = NULL, *out = NULL, *tbio = NULL; ++ X509 *rcert = NULL; ++ EVP_PKEY *rkey = NULL; ++ CMS_ContentInfo *cms = NULL; ++ int ret = 1; ++ ++ OpenSSL_add_all_algorithms(); ++ ERR_load_crypto_strings(); ++ ++ /* Read in recipient certificate and private key */ ++ tbio = BIO_new_file("signer.pem", "r"); ++ ++ if (!tbio) ++ goto err; ++ ++ rcert = PEM_read_bio_X509(tbio, NULL, 0, NULL); ++ ++ BIO_reset(tbio); ++ ++ rkey = PEM_read_bio_PrivateKey(tbio, NULL, 0, NULL); ++ ++ if (!rcert || !rkey) ++ goto err; ++ ++ /* Open S/MIME message to decrypt */ ++ ++ in = BIO_new_file("smencr.txt", "r"); ++ ++ if (!in) ++ goto err; ++ ++ /* Parse message */ ++ cms = SMIME_read_CMS(in, NULL); ++ ++ if (!cms) ++ goto err; ++ ++ out = BIO_new_file("decout.txt", "w"); ++ if (!out) ++ goto err; ++ ++ /* Decrypt S/MIME message */ ++ if (!CMS_decrypt(cms, rkey, rcert, NULL, out, 0)) ++ goto err; ++ ++ ret = 0; ++ ++ err: ++ ++ if (ret) { ++ fprintf(stderr, "Error Decrypting Data\n"); ++ ERR_print_errors_fp(stderr); ++ } ++ ++ CMS_ContentInfo_free(cms); ++ X509_free(rcert); ++ EVP_PKEY_free(rkey); ++ BIO_free(in); ++ BIO_free(out); ++ BIO_free(tbio); ++ return ret; ++} +diff --git a/CryptoPkg/Library/OpensslLib/openssl/demos/cms/cms_denc.c b/CryptoPkg/Library/OpensslLib/openssl/demos/cms/cms_denc.c +new file mode 100644 +index 0000000..adba69b +--- /dev/null ++++ b/CryptoPkg/Library/OpensslLib/openssl/demos/cms/cms_denc.c +@@ -0,0 +1,97 @@ ++/* ++ * Copyright 2008-2016 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 ++ * in the file LICENSE in the source distribution or at ++ * https://www.openssl.org/source/license.html ++ */ ++ ++/* ++ * S/MIME detached data encrypt example: rarely done but should the need ++ * arise this is an example.... ++ */ ++#include ++#include ++#include ++ ++int main(int argc, char **argv) ++{ ++ BIO *in = NULL, *out = NULL, *tbio = NULL, *dout = NULL; ++ X509 *rcert = NULL; ++ STACK_OF(X509) *recips = NULL; ++ CMS_ContentInfo *cms = NULL; ++ int ret = 1; ++ ++ int flags = CMS_STREAM | CMS_DETACHED; ++ ++ OpenSSL_add_all_algorithms(); ++ ERR_load_crypto_strings(); ++ ++ /* Read in recipient certificate */ ++ tbio = BIO_new_file("signer.pem", "r"); ++ ++ if (!tbio) ++ goto err; ++ ++ rcert = PEM_read_bio_X509(tbio, NULL, 0, NULL); ++ ++ if (!rcert) ++ goto err; ++ ++ /* Create recipient STACK and add recipient cert to it */ ++ recips = sk_X509_new_null(); ++ ++ if (!recips || !sk_X509_push(recips, rcert)) ++ goto err; ++ ++ /* ++ * sk_X509_pop_free will free up recipient STACK and its contents so set ++ * rcert to NULL so it isn't freed up twice. ++ */ ++ rcert = NULL; ++ ++ /* Open content being encrypted */ ++ ++ in = BIO_new_file("encr.txt", "r"); ++ ++ dout = BIO_new_file("smencr.out", "wb"); ++ ++ if (!in) ++ goto err; ++ ++ /* encrypt content */ ++ cms = CMS_encrypt(recips, in, EVP_des_ede3_cbc(), flags); ++ ++ if (!cms) ++ goto err; ++ ++ out = BIO_new_file("smencr.pem", "w"); ++ if (!out) ++ goto err; ++ ++ if (!CMS_final(cms, in, dout, flags)) ++ goto err; ++ ++ /* Write out CMS structure without content */ ++ if (!PEM_write_bio_CMS(out, cms)) ++ goto err; ++ ++ ret = 0; ++ ++ err: ++ ++ if (ret) { ++ fprintf(stderr, "Error Encrypting Data\n"); ++ ERR_print_errors_fp(stderr); ++ } ++ ++ CMS_ContentInfo_free(cms); ++ X509_free(rcert); ++ sk_X509_pop_free(recips, X509_free); ++ BIO_free(in); ++ BIO_free(out); ++ BIO_free(dout); ++ BIO_free(tbio); ++ return ret; ++} +diff --git a/CryptoPkg/Library/OpensslLib/openssl/demos/cms/cms_enc.c b/CryptoPkg/Library/OpensslLib/openssl/demos/cms/cms_enc.c +new file mode 100644 +index 0000000..4d17d72 +--- /dev/null ++++ b/CryptoPkg/Library/OpensslLib/openssl/demos/cms/cms_enc.c +@@ -0,0 +1,92 @@ ++/* ++ * Copyright 2008-2016 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 ++ * in the file LICENSE in the source distribution or at ++ * https://www.openssl.org/source/license.html ++ */ ++ ++/* Simple S/MIME encrypt example */ ++#include ++#include ++#include ++ ++int main(int argc, char **argv) ++{ ++ BIO *in = NULL, *out = NULL, *tbio = NULL; ++ X509 *rcert = NULL; ++ STACK_OF(X509) *recips = NULL; ++ CMS_ContentInfo *cms = NULL; ++ int ret = 1; ++ ++ /* ++ * On OpenSSL 1.0.0 and later only: ++ * for streaming set CMS_STREAM ++ */ ++ int flags = CMS_STREAM; ++ ++ OpenSSL_add_all_algorithms(); ++ ERR_load_crypto_strings(); ++ ++ /* Read in recipient certificate */ ++ tbio = BIO_new_file("signer.pem", "r"); ++ ++ if (!tbio) ++ goto err; ++ ++ rcert = PEM_read_bio_X509(tbio, NULL, 0, NULL); ++ ++ if (!rcert) ++ goto err; ++ ++ /* Create recipient STACK and add recipient cert to it */ ++ recips = sk_X509_new_null(); ++ ++ if (!recips || !sk_X509_push(recips, rcert)) ++ goto err; ++ ++ /* ++ * sk_X509_pop_free will free up recipient STACK and its contents so set ++ * rcert to NULL so it isn't freed up twice. ++ */ ++ rcert = NULL; ++ ++ /* Open content being encrypted */ ++ ++ in = BIO_new_file("encr.txt", "r"); ++ ++ if (!in) ++ goto err; ++ ++ /* encrypt content */ ++ cms = CMS_encrypt(recips, in, EVP_des_ede3_cbc(), flags); ++ ++ if (!cms) ++ goto err; ++ ++ out = BIO_new_file("smencr.txt", "w"); ++ if (!out) ++ goto err; ++ ++ /* Write out S/MIME message */ ++ if (!SMIME_write_CMS(out, cms, in, flags)) ++ goto err; ++ ++ ret = 0; ++ ++ err: ++ ++ if (ret) { ++ fprintf(stderr, "Error Encrypting Data\n"); ++ ERR_print_errors_fp(stderr); ++ } ++ ++ CMS_ContentInfo_free(cms); ++ X509_free(rcert); ++ sk_X509_pop_free(recips, X509_free); ++ BIO_free(in); ++ BIO_free(out); ++ BIO_free(tbio); ++ return ret; ++} +diff --git a/CryptoPkg/Library/OpensslLib/openssl/demos/cms/cms_sign.c b/CryptoPkg/Library/OpensslLib/openssl/demos/cms/cms_sign.c +new file mode 100644 +index 0000000..15bd5b8 +--- /dev/null ++++ b/CryptoPkg/Library/OpensslLib/openssl/demos/cms/cms_sign.c +@@ -0,0 +1,88 @@ ++/* ++ * Copyright 2008-2016 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 ++ * in the file LICENSE in the source distribution or at ++ * https://www.openssl.org/source/license.html ++ */ ++ ++/* Simple S/MIME signing example */ ++#include ++#include ++#include ++ ++int main(int argc, char **argv) ++{ ++ BIO *in = NULL, *out = NULL, *tbio = NULL; ++ X509 *scert = NULL; ++ EVP_PKEY *skey = NULL; ++ CMS_ContentInfo *cms = NULL; ++ int ret = 1; ++ ++ /* ++ * For simple S/MIME signing use CMS_DETACHED. On OpenSSL 1.0.0 only: for ++ * streaming detached set CMS_DETACHED|CMS_STREAM for streaming ++ * non-detached set CMS_STREAM ++ */ ++ int flags = CMS_DETACHED | CMS_STREAM; ++ ++ OpenSSL_add_all_algorithms(); ++ ERR_load_crypto_strings(); ++ ++ /* Read in signer certificate and private key */ ++ tbio = BIO_new_file("signer.pem", "r"); ++ ++ if (!tbio) ++ goto err; ++ ++ scert = PEM_read_bio_X509(tbio, NULL, 0, NULL); ++ ++ BIO_reset(tbio); ++ ++ skey = PEM_read_bio_PrivateKey(tbio, NULL, 0, NULL); ++ ++ if (!scert || !skey) ++ goto err; ++ ++ /* Open content being signed */ ++ ++ in = BIO_new_file("sign.txt", "r"); ++ ++ if (!in) ++ goto err; ++ ++ /* Sign content */ ++ cms = CMS_sign(scert, skey, NULL, in, flags); ++ ++ if (!cms) ++ goto err; ++ ++ out = BIO_new_file("smout.txt", "w"); ++ if (!out) ++ goto err; ++ ++ if (!(flags & CMS_STREAM)) ++ BIO_reset(in); ++ ++ /* Write out S/MIME message */ ++ if (!SMIME_write_CMS(out, cms, in, flags)) ++ goto err; ++ ++ ret = 0; ++ ++ err: ++ ++ if (ret) { ++ fprintf(stderr, "Error Signing Data\n"); ++ ERR_print_errors_fp(stderr); ++ } ++ ++ CMS_ContentInfo_free(cms); ++ X509_free(scert); ++ EVP_PKEY_free(skey); ++ BIO_free(in); ++ BIO_free(out); ++ BIO_free(tbio); ++ return ret; ++} +diff --git a/CryptoPkg/Library/OpensslLib/openssl/demos/cms/cms_sign2.c b/CryptoPkg/Library/OpensslLib/openssl/demos/cms/cms_sign2.c +new file mode 100644 +index 0000000..14ebf27 +--- /dev/null ++++ b/CryptoPkg/Library/OpensslLib/openssl/demos/cms/cms_sign2.c +@@ -0,0 +1,98 @@ ++/* ++ * Copyright 2008-2016 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 ++ * in the file LICENSE in the source distribution or at ++ * https://www.openssl.org/source/license.html ++ */ ++ ++/* S/MIME signing example: 2 signers */ ++#include ++#include ++#include ++ ++int main(int argc, char **argv) ++{ ++ BIO *in = NULL, *out = NULL, *tbio = NULL; ++ X509 *scert = NULL, *scert2 = NULL; ++ EVP_PKEY *skey = NULL, *skey2 = NULL; ++ CMS_ContentInfo *cms = NULL; ++ int ret = 1; ++ ++ OpenSSL_add_all_algorithms(); ++ ERR_load_crypto_strings(); ++ ++ tbio = BIO_new_file("signer.pem", "r"); ++ ++ if (!tbio) ++ goto err; ++ ++ scert = PEM_read_bio_X509(tbio, NULL, 0, NULL); ++ ++ BIO_reset(tbio); ++ ++ skey = PEM_read_bio_PrivateKey(tbio, NULL, 0, NULL); ++ ++ BIO_free(tbio); ++ ++ tbio = BIO_new_file("signer2.pem", "r"); ++ ++ if (!tbio) ++ goto err; ++ ++ scert2 = PEM_read_bio_X509(tbio, NULL, 0, NULL); ++ ++ BIO_reset(tbio); ++ ++ skey2 = PEM_read_bio_PrivateKey(tbio, NULL, 0, NULL); ++ ++ if (!scert2 || !skey2) ++ goto err; ++ ++ in = BIO_new_file("sign.txt", "r"); ++ ++ if (!in) ++ goto err; ++ ++ cms = CMS_sign(NULL, NULL, NULL, in, CMS_STREAM | CMS_PARTIAL); ++ ++ if (!cms) ++ goto err; ++ ++ /* Add each signer in turn */ ++ ++ if (!CMS_add1_signer(cms, scert, skey, NULL, 0)) ++ goto err; ++ ++ if (!CMS_add1_signer(cms, scert2, skey2, NULL, 0)) ++ goto err; ++ ++ out = BIO_new_file("smout.txt", "w"); ++ if (!out) ++ goto err; ++ ++ /* NB: content included and finalized by SMIME_write_CMS */ ++ ++ if (!SMIME_write_CMS(out, cms, in, CMS_STREAM)) ++ goto err; ++ ++ ret = 0; ++ ++ err: ++ ++ if (ret) { ++ fprintf(stderr, "Error Signing Data\n"); ++ ERR_print_errors_fp(stderr); ++ } ++ ++ CMS_ContentInfo_free(cms); ++ X509_free(scert); ++ EVP_PKEY_free(skey); ++ X509_free(scert2); ++ EVP_PKEY_free(skey2); ++ BIO_free(in); ++ BIO_free(out); ++ BIO_free(tbio); ++ return ret; ++} +diff --git a/CryptoPkg/Library/OpensslLib/openssl/demos/cms/cms_uncomp.c b/CryptoPkg/Library/OpensslLib/openssl/demos/cms/cms_uncomp.c +new file mode 100644 +index 0000000..3e3b4c4 +--- /dev/null ++++ b/CryptoPkg/Library/OpensslLib/openssl/demos/cms/cms_uncomp.c +@@ -0,0 +1,58 @@ ++/* ++ * Copyright 2008-2016 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 ++ * in the file LICENSE in the source distribution or at ++ * https://www.openssl.org/source/license.html ++ */ ++ ++/* Simple S/MIME uncompression example */ ++#include ++#include ++#include ++ ++int main(int argc, char **argv) ++{ ++ BIO *in = NULL, *out = NULL; ++ CMS_ContentInfo *cms = NULL; ++ int ret = 1; ++ ++ OpenSSL_add_all_algorithms(); ++ ERR_load_crypto_strings(); ++ ++ /* Open compressed content */ ++ ++ in = BIO_new_file("smcomp.txt", "r"); ++ ++ if (!in) ++ goto err; ++ ++ /* Sign content */ ++ cms = SMIME_read_CMS(in, NULL); ++ ++ if (!cms) ++ goto err; ++ ++ out = BIO_new_file("smuncomp.txt", "w"); ++ if (!out) ++ goto err; ++ ++ /* Uncompress S/MIME message */ ++ if (!CMS_uncompress(cms, out, NULL, 0)) ++ goto err; ++ ++ ret = 0; ++ ++ err: ++ ++ if (ret) { ++ fprintf(stderr, "Error Uncompressing Data\n"); ++ ERR_print_errors_fp(stderr); ++ } ++ ++ CMS_ContentInfo_free(cms); ++ BIO_free(in); ++ BIO_free(out); ++ return ret; ++} +diff --git a/CryptoPkg/Library/OpensslLib/openssl/demos/cms/cms_ver.c b/CryptoPkg/Library/OpensslLib/openssl/demos/cms/cms_ver.c +new file mode 100644 +index 0000000..43c10e2 +--- /dev/null ++++ b/CryptoPkg/Library/OpensslLib/openssl/demos/cms/cms_ver.c +@@ -0,0 +1,85 @@ ++/* ++ * Copyright 2008-2016 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 ++ * in the file LICENSE in the source distribution or at ++ * https://www.openssl.org/source/license.html ++ */ ++ ++/* Simple S/MIME verification example */ ++#include ++#include ++#include ++ ++int main(int argc, char **argv) ++{ ++ BIO *in = NULL, *out = NULL, *tbio = NULL, *cont = NULL; ++ X509_STORE *st = NULL; ++ X509 *cacert = NULL; ++ CMS_ContentInfo *cms = NULL; ++ ++ int ret = 1; ++ ++ OpenSSL_add_all_algorithms(); ++ ERR_load_crypto_strings(); ++ ++ /* Set up trusted CA certificate store */ ++ ++ st = X509_STORE_new(); ++ ++ /* Read in CA certificate */ ++ tbio = BIO_new_file("cacert.pem", "r"); ++ ++ if (!tbio) ++ goto err; ++ ++ cacert = PEM_read_bio_X509(tbio, NULL, 0, NULL); ++ ++ if (!cacert) ++ goto err; ++ ++ if (!X509_STORE_add_cert(st, cacert)) ++ goto err; ++ ++ /* Open message being verified */ ++ ++ in = BIO_new_file("smout.txt", "r"); ++ ++ if (!in) ++ goto err; ++ ++ /* parse message */ ++ cms = SMIME_read_CMS(in, &cont); ++ ++ if (!cms) ++ goto err; ++ ++ /* File to output verified content to */ ++ out = BIO_new_file("smver.txt", "w"); ++ if (!out) ++ goto err; ++ ++ if (!CMS_verify(cms, NULL, st, cont, out, 0)) { ++ fprintf(stderr, "Verification Failure\n"); ++ goto err; ++ } ++ ++ fprintf(stderr, "Verification Successful\n"); ++ ++ ret = 0; ++ ++ err: ++ ++ if (ret) { ++ fprintf(stderr, "Error Verifying Data\n"); ++ ERR_print_errors_fp(stderr); ++ } ++ ++ CMS_ContentInfo_free(cms); ++ X509_free(cacert); ++ BIO_free(in); ++ BIO_free(out); ++ BIO_free(tbio); ++ return ret; ++} +diff --git a/CryptoPkg/Library/OpensslLib/openssl/demos/cms/comp.txt b/CryptoPkg/Library/OpensslLib/openssl/demos/cms/comp.txt +new file mode 100644 +index 0000000..1672328 +--- /dev/null ++++ b/CryptoPkg/Library/OpensslLib/openssl/demos/cms/comp.txt +@@ -0,0 +1,22 @@ ++Content-type: text/plain ++ ++Some Text To be Compressed ++Some Text To be Compressed ++Some Text To be Compressed ++Some Text To be Compressed ++Some Text To be Compressed ++Some Text To be Compressed ++Some Text To be Compressed ++Some Text To be Compressed ++Some Text To be Compressed ++Some Text To be Compressed ++Some Text To be Compressed ++Some Text To be Compressed ++Some Text To be Compressed ++Some Text To be Compressed ++Some Text To be Compressed ++Some Text To be Compressed ++Some Text To be Compressed ++Some Text To be Compressed ++Some Text To be Compressed ++Some Text To be Compressed +diff --git a/CryptoPkg/Library/OpensslLib/openssl/demos/cms/encr.txt b/CryptoPkg/Library/OpensslLib/openssl/demos/cms/encr.txt +new file mode 100644 +index 0000000..0eceb40 +--- /dev/null ++++ b/CryptoPkg/Library/OpensslLib/openssl/demos/cms/encr.txt +@@ -0,0 +1,3 @@ ++Content-type: text/plain ++ ++Sample OpenSSL Data for CMS encryption +diff --git a/CryptoPkg/Library/OpensslLib/openssl/demos/cms/sign.txt b/CryptoPkg/Library/OpensslLib/openssl/demos/cms/sign.txt +new file mode 100644 +index 0000000..c3f9d73 +--- /dev/null ++++ b/CryptoPkg/Library/OpensslLib/openssl/demos/cms/sign.txt +@@ -0,0 +1,3 @@ ++Content-type: text/plain ++ ++Test OpenSSL CMS Signed Content +diff --git a/CryptoPkg/Library/OpensslLib/openssl/demos/cms/signer.pem b/CryptoPkg/Library/OpensslLib/openssl/demos/cms/signer.pem +new file mode 100644 +index 0000000..bac16ba +--- /dev/null ++++ b/CryptoPkg/Library/OpensslLib/openssl/demos/cms/signer.pem +@@ -0,0 +1,32 @@ ++-----BEGIN CERTIFICATE----- ++MIICpjCCAg+gAwIBAgIJAJ+rfmEoLQRhMA0GCSqGSIb3DQEBBAUAMFcxCzAJBgNV ++BAYTAlVLMRIwEAYDVQQHEwlUZXN0IENpdHkxFjAUBgNVBAoTDU9wZW5TU0wgR3Jv ++dXAxHDAaBgNVBAMTE1Rlc3QgUy9NSU1FIFJvb3QgQ0EwHhcNMDcwNDEzMTgyOTI3 ++WhcNMTcwNDA5MTgyOTI3WjBWMQswCQYDVQQGEwJVSzElMCMGA1UEAxMcT3BlblNT ++TCB0ZXN0IFMvTUlNRSBzaWduZXIgMTEgMB4GCSqGSIb3DQEJARYRdGVzdDFAb3Bl ++bnNzbC5vcmcwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAL1ocAQ7ON2pIUXz ++jwKPzpPB9ozB6PFG6F6kARO+i0DiT6Qn8abUjwpHPU+lGys83QlpbkQVUD6Fv/4L ++ytihk6N9Pr/feECVcSZ20dI43WXjfYak14dSVrZkGNMMXqKmnnqtkAdD0oJN7A7y ++gcf8RuViV0kvk9/36eCMwMHrImfhAgMBAAGjezB5MAkGA1UdEwQCMAAwLAYJYIZI ++AYb4QgENBB8WHU9wZW5TU0wgR2VuZXJhdGVkIENlcnRpZmljYXRlMB0GA1UdDgQW ++BBSyKqjvctIsFNBHULBTqr8SHtSxpDAfBgNVHSMEGDAWgBRHUypxCXFQYqewhGo7 ++2lWPQUsjoDANBgkqhkiG9w0BAQQFAAOBgQBvdYVoBfd4RV/xWSMXIcgw/i5OiwyX ++MsenQePll51MpglfArd7pUipUalCqlJt/Gs8kD16Ih1z1yuWYVTMlnDZ0PwbIOYn +++Jr8XLF9b1SMJt6PwckZZ0LZdIi2KwGAxVsIW1kjJAqu9o4YH37XW37yYdQRxfvv ++lDiQlgX0JtmLgA== ++-----END CERTIFICATE----- ++-----BEGIN RSA PRIVATE KEY----- ++MIICXAIBAAKBgQC9aHAEOzjdqSFF848Cj86TwfaMwejxRuhepAETvotA4k+kJ/Gm ++1I8KRz1PpRsrPN0JaW5EFVA+hb/+C8rYoZOjfT6/33hAlXEmdtHSON1l432GpNeH ++Ula2ZBjTDF6ipp56rZAHQ9KCTewO8oHH/EblYldJL5Pf9+ngjMDB6yJn4QIDAQAB ++AoGACCuYIWaYll80UzslYRvo8lC8nOfEb5v6bBKxBTQD98GLY+5hKywiG3RlPalG ++mb/fXQeSPReaRYgpdwD1OBEIOEMW9kLyqpzokC0xjpZ+MwsuJTlxCesk5GEsMa3o ++wC3QMmiRA7qrZ/SzTtwrs++9mZ/pxp8JZ6pKYUj8SE7/vV0CQQDz8Ix2t40E16hx ++04+XhClnGqydZJyLLSxcTU3ZVhYxL+efo/5hZ8tKpkcDi8wq6T03BOKrKxrlIW55 ++qDRNM24rAkEAxsWzu/rJhIouQyNoYygEIEYzFRlTQyZSg59u6dNiewMn27dOAbyc ++YT7B6da7e74QttTXo0lIllsX2S38+XsIIwJBANSRuIU3G66tkr5l4gnhhAaxqtuY ++sgVhvvdL8dvC9aG1Ifzt9hzBSthpHxbK+oYmK07HdhI8hLpIMLHYzoK7n3MCQEy4 ++4rccBcxyyYiAkjozp+QNNIpgTBMPJ6pGT7lRLiHtBeV4y1NASdv/LTnk+Fi69Bid ++7t3H24ytfHcHmS1yn6ECQF6Jmh4C7dlvp59zXp+t+VsXxa/8sq41vKNIj0Rx9vh5 ++xp9XL0C5ZpgmBnsTydP9pmkiL4ltLbMX0wJU6N2cmFw= ++-----END RSA PRIVATE KEY----- +diff --git a/CryptoPkg/Library/OpensslLib/openssl/demos/cms/signer2.pem b/CryptoPkg/Library/OpensslLib/openssl/demos/cms/signer2.pem +new file mode 100644 +index 0000000..25e23d1 +--- /dev/null ++++ b/CryptoPkg/Library/OpensslLib/openssl/demos/cms/signer2.pem +@@ -0,0 +1,32 @@ ++-----BEGIN CERTIFICATE----- ++MIICpjCCAg+gAwIBAgIJAJ+rfmEoLQRiMA0GCSqGSIb3DQEBBAUAMFcxCzAJBgNV ++BAYTAlVLMRIwEAYDVQQHEwlUZXN0IENpdHkxFjAUBgNVBAoTDU9wZW5TU0wgR3Jv ++dXAxHDAaBgNVBAMTE1Rlc3QgUy9NSU1FIFJvb3QgQ0EwHhcNMDcwNDEzMTgyOTQ0 ++WhcNMTcwNDA5MTgyOTQ0WjBWMQswCQYDVQQGEwJVSzElMCMGA1UEAxMcT3BlblNT ++TCB0ZXN0IFMvTUlNRSBzaWduZXIgMjEgMB4GCSqGSIb3DQEJARYRdGVzdDJAb3Bl ++bnNzbC5vcmcwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBANco7VPgX9vcGwmZ ++jYqjq1JiR7M38dsMNhuJyLRVjJ5/cpFluQydQuG1PhzOJ8zfYVFicOXKvbYuKuXW ++ozZIwzqEqWsNf36KHTLS6yOMG8I13cRInh+fAIKq9Z8Eh65I7FJzVsNsfEQrGfEW ++GMA8us24IaSvP3QkbfHJn/4RaKznAgMBAAGjezB5MAkGA1UdEwQCMAAwLAYJYIZI ++AYb4QgENBB8WHU9wZW5TU0wgR2VuZXJhdGVkIENlcnRpZmljYXRlMB0GA1UdDgQW ++BBRlrLQJUB8uAa4q8B2OqvvTXonF5zAfBgNVHSMEGDAWgBRHUypxCXFQYqewhGo7 ++2lWPQUsjoDANBgkqhkiG9w0BAQQFAAOBgQBQbi2juGALg2k9m1hKpzR2lCGmGO3X ++h3Jh/l0vIxDr0RTgP2vBrtITlx655P/o1snoeTIpYG8uUnFnTE/6YakdayAIlxV4 ++aZl63AivZMpQB5SPaPH/jEsGJ8UQMfdiy4ORWIULupuPKlKwODNw7tVhQIACS/DR ++2aX6rl2JEuJ5Yg== ++-----END CERTIFICATE----- ++-----BEGIN RSA PRIVATE KEY----- ++MIICXAIBAAKBgQDXKO1T4F/b3BsJmY2Ko6tSYkezN/HbDDYbici0VYyef3KRZbkM ++nULhtT4czifM32FRYnDlyr22Lirl1qM2SMM6hKlrDX9+ih0y0usjjBvCNd3ESJ4f ++nwCCqvWfBIeuSOxSc1bDbHxEKxnxFhjAPLrNuCGkrz90JG3xyZ/+EWis5wIDAQAB ++AoGAUTB2bcIrKfGimjrBOGGOUmYXnD8uGnQ/LqENhU8K4vxApTD3ZRUqmbUknQYF ++6r8YH/e/llasw8QkF9qod+F5GTgsnyh/aMidFHKrXXbf1662scz9+S6crSXq9Eb2 ++CL57f6Kw61k6edrz8zHdA+rnTK00hzgzKCP4ZL5k8/55ueECQQD+BK+nsKi6CcKf ++m3Mh61Sf2Icm5JlMCKaihlbnh78lBN1imYUAfHJEnQ1ujxXB94R+6o9S+XrWTnTX ++2m/JNIfpAkEA2NaidX7Sv5jnRPkwJ02Srl0urxINLmg4bU0zmM3VoMklYBHWnMyr ++upPZGPh5TzCa+g6FTBmU8XK61wvnEKNcTwJBAM24VdnlBIDGbsx8RJ3vzLU30xz4 ++ff5J80okqjUQhwkgC3tTAZgHMTPITZyAXQqdvrxakoCMc6MkHxTBX08AMCECQHHL ++SdyxXrYv7waSY0PtANJCkpJLveEhzqMFxdMmCjtj9BpTojYNbv3uQxtIopj9YAdk ++gW2ray++zvC2DV/86x8CQH4UJwgO6JqU4bSgi6HiRNjDg26tJ0Beu8jjl1vrkIVX ++pHFwSUeLZUsT2/iTUSgYH4uYiZPgYNcKTCT9W6se30A= ++-----END RSA PRIVATE KEY----- +diff --git a/CryptoPkg/Library/OpensslLib/openssl/demos/evp/aesccm.c b/CryptoPkg/Library/OpensslLib/openssl/demos/evp/aesccm.c +new file mode 100644 +index 0000000..cc4d0b5 +--- /dev/null ++++ b/CryptoPkg/Library/OpensslLib/openssl/demos/evp/aesccm.c +@@ -0,0 +1,125 @@ ++/* ++ * Copyright 2013-2016 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 ++ * in the file LICENSE in the source distribution or at ++ * https://www.openssl.org/source/license.html ++ */ ++ ++/* ++ * Simple AES CCM test program, uses the same NIST data used for the FIPS ++ * self test but uses the application level EVP APIs. ++ */ ++#include ++#include ++#include ++ ++/* AES-CCM test data from NIST public test vectors */ ++ ++static const unsigned char ccm_key[] = { ++ 0xce, 0xb0, 0x09, 0xae, 0xa4, 0x45, 0x44, 0x51, 0xfe, 0xad, 0xf0, 0xe6, ++ 0xb3, 0x6f, 0x45, 0x55, 0x5d, 0xd0, 0x47, 0x23, 0xba, 0xa4, 0x48, 0xe8 ++}; ++ ++static const unsigned char ccm_nonce[] = { ++ 0x76, 0x40, 0x43, 0xc4, 0x94, 0x60, 0xb7 ++}; ++ ++static const unsigned char ccm_adata[] = { ++ 0x6e, 0x80, 0xdd, 0x7f, 0x1b, 0xad, 0xf3, 0xa1, 0xc9, 0xab, 0x25, 0xc7, ++ 0x5f, 0x10, 0xbd, 0xe7, 0x8c, 0x23, 0xfa, 0x0e, 0xb8, 0xf9, 0xaa, 0xa5, ++ 0x3a, 0xde, 0xfb, 0xf4, 0xcb, 0xf7, 0x8f, 0xe4 ++}; ++ ++static const unsigned char ccm_pt[] = { ++ 0xc8, 0xd2, 0x75, 0xf9, 0x19, 0xe1, 0x7d, 0x7f, 0xe6, 0x9c, 0x2a, 0x1f, ++ 0x58, 0x93, 0x9d, 0xfe, 0x4d, 0x40, 0x37, 0x91, 0xb5, 0xdf, 0x13, 0x10 ++}; ++ ++static const unsigned char ccm_ct[] = { ++ 0x8a, 0x0f, 0x3d, 0x82, 0x29, 0xe4, 0x8e, 0x74, 0x87, 0xfd, 0x95, 0xa2, ++ 0x8a, 0xd3, 0x92, 0xc8, 0x0b, 0x36, 0x81, 0xd4, 0xfb, 0xc7, 0xbb, 0xfd ++}; ++ ++static const unsigned char ccm_tag[] = { ++ 0x2d, 0xd6, 0xef, 0x1c, 0x45, 0xd4, 0xcc, 0xb7, 0x23, 0xdc, 0x07, 0x44, ++ 0x14, 0xdb, 0x50, 0x6d ++}; ++ ++void aes_ccm_encrypt(void) ++{ ++ EVP_CIPHER_CTX *ctx; ++ int outlen, tmplen; ++ unsigned char outbuf[1024]; ++ printf("AES CCM Encrypt:\n"); ++ printf("Plaintext:\n"); ++ BIO_dump_fp(stdout, ccm_pt, sizeof(ccm_pt)); ++ ctx = EVP_CIPHER_CTX_new(); ++ /* Set cipher type and mode */ ++ EVP_EncryptInit_ex(ctx, EVP_aes_192_ccm(), NULL, NULL, NULL); ++ /* Set nonce length if default 96 bits is not appropriate */ ++ EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_SET_IVLEN, sizeof(ccm_nonce), ++ NULL); ++ /* Set tag length */ ++ EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_SET_TAG, sizeof(ccm_tag), NULL); ++ /* Initialise key and IV */ ++ EVP_EncryptInit_ex(ctx, NULL, NULL, ccm_key, ccm_nonce); ++ /* Set plaintext length: only needed if AAD is used */ ++ EVP_EncryptUpdate(ctx, NULL, &outlen, NULL, sizeof(ccm_pt)); ++ /* Zero or one call to specify any AAD */ ++ EVP_EncryptUpdate(ctx, NULL, &outlen, ccm_adata, sizeof(ccm_adata)); ++ /* Encrypt plaintext: can only be called once */ ++ EVP_EncryptUpdate(ctx, outbuf, &outlen, ccm_pt, sizeof(ccm_pt)); ++ /* Output encrypted block */ ++ printf("Ciphertext:\n"); ++ BIO_dump_fp(stdout, outbuf, outlen); ++ /* Finalise: note get no output for CCM */ ++ EVP_EncryptFinal_ex(ctx, outbuf, &outlen); ++ /* Get tag */ ++ EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_GET_TAG, 16, outbuf); ++ /* Output tag */ ++ printf("Tag:\n"); ++ BIO_dump_fp(stdout, outbuf, 16); ++ EVP_CIPHER_CTX_free(ctx); ++} ++ ++void aes_ccm_decrypt(void) ++{ ++ EVP_CIPHER_CTX *ctx; ++ int outlen, tmplen, rv; ++ unsigned char outbuf[1024]; ++ printf("AES CCM Derypt:\n"); ++ printf("Ciphertext:\n"); ++ BIO_dump_fp(stdout, ccm_ct, sizeof(ccm_ct)); ++ ctx = EVP_CIPHER_CTX_new(); ++ /* Select cipher */ ++ EVP_DecryptInit_ex(ctx, EVP_aes_192_ccm(), NULL, NULL, NULL); ++ /* Set nonce length, omit for 96 bits */ ++ EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_SET_IVLEN, sizeof(ccm_nonce), ++ NULL); ++ /* Set expected tag value */ ++ EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_SET_TAG, ++ sizeof(ccm_tag), (void *)ccm_tag); ++ /* Specify key and IV */ ++ EVP_DecryptInit_ex(ctx, NULL, NULL, ccm_key, ccm_nonce); ++ /* Set ciphertext length: only needed if we have AAD */ ++ EVP_DecryptUpdate(ctx, NULL, &outlen, NULL, sizeof(ccm_ct)); ++ /* Zero or one call to specify any AAD */ ++ EVP_DecryptUpdate(ctx, NULL, &outlen, ccm_adata, sizeof(ccm_adata)); ++ /* Decrypt plaintext, verify tag: can only be called once */ ++ rv = EVP_DecryptUpdate(ctx, outbuf, &outlen, ccm_ct, sizeof(ccm_ct)); ++ /* Output decrypted block: if tag verify failed we get nothing */ ++ if (rv > 0) { ++ printf("Plaintext:\n"); ++ BIO_dump_fp(stdout, outbuf, outlen); ++ } else ++ printf("Plaintext not available: tag verify failed.\n"); ++ EVP_CIPHER_CTX_free(ctx); ++} ++ ++int main(int argc, char **argv) ++{ ++ aes_ccm_encrypt(); ++ aes_ccm_decrypt(); ++} +diff --git a/CryptoPkg/Library/OpensslLib/openssl/demos/evp/aesgcm.c b/CryptoPkg/Library/OpensslLib/openssl/demos/evp/aesgcm.c +new file mode 100644 +index 0000000..17b0ef4 +--- /dev/null ++++ b/CryptoPkg/Library/OpensslLib/openssl/demos/evp/aesgcm.c +@@ -0,0 +1,120 @@ ++/* ++ * Copyright 2012-2016 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 ++ * in the file LICENSE in the source distribution or at ++ * https://www.openssl.org/source/license.html ++ */ ++ ++/* ++ * Simple AES GCM test program, uses the same NIST data used for the FIPS ++ * self test but uses the application level EVP APIs. ++ */ ++#include ++#include ++#include ++ ++/* AES-GCM test data from NIST public test vectors */ ++ ++static const unsigned char gcm_key[] = { ++ 0xee, 0xbc, 0x1f, 0x57, 0x48, 0x7f, 0x51, 0x92, 0x1c, 0x04, 0x65, 0x66, ++ 0x5f, 0x8a, 0xe6, 0xd1, 0x65, 0x8b, 0xb2, 0x6d, 0xe6, 0xf8, 0xa0, 0x69, ++ 0xa3, 0x52, 0x02, 0x93, 0xa5, 0x72, 0x07, 0x8f ++}; ++ ++static const unsigned char gcm_iv[] = { ++ 0x99, 0xaa, 0x3e, 0x68, 0xed, 0x81, 0x73, 0xa0, 0xee, 0xd0, 0x66, 0x84 ++}; ++ ++static const unsigned char gcm_pt[] = { ++ 0xf5, 0x6e, 0x87, 0x05, 0x5b, 0xc3, 0x2d, 0x0e, 0xeb, 0x31, 0xb2, 0xea, ++ 0xcc, 0x2b, 0xf2, 0xa5 ++}; ++ ++static const unsigned char gcm_aad[] = { ++ 0x4d, 0x23, 0xc3, 0xce, 0xc3, 0x34, 0xb4, 0x9b, 0xdb, 0x37, 0x0c, 0x43, ++ 0x7f, 0xec, 0x78, 0xde ++}; ++ ++static const unsigned char gcm_ct[] = { ++ 0xf7, 0x26, 0x44, 0x13, 0xa8, 0x4c, 0x0e, 0x7c, 0xd5, 0x36, 0x86, 0x7e, ++ 0xb9, 0xf2, 0x17, 0x36 ++}; ++ ++static const unsigned char gcm_tag[] = { ++ 0x67, 0xba, 0x05, 0x10, 0x26, 0x2a, 0xe4, 0x87, 0xd7, 0x37, 0xee, 0x62, ++ 0x98, 0xf7, 0x7e, 0x0c ++}; ++ ++void aes_gcm_encrypt(void) ++{ ++ EVP_CIPHER_CTX *ctx; ++ int outlen, tmplen; ++ unsigned char outbuf[1024]; ++ printf("AES GCM Encrypt:\n"); ++ printf("Plaintext:\n"); ++ BIO_dump_fp(stdout, gcm_pt, sizeof(gcm_pt)); ++ ctx = EVP_CIPHER_CTX_new(); ++ /* Set cipher type and mode */ ++ EVP_EncryptInit_ex(ctx, EVP_aes_256_gcm(), NULL, NULL, NULL); ++ /* Set IV length if default 96 bits is not appropriate */ ++ EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_SET_IVLEN, sizeof(gcm_iv), NULL); ++ /* Initialise key and IV */ ++ EVP_EncryptInit_ex(ctx, NULL, NULL, gcm_key, gcm_iv); ++ /* Zero or more calls to specify any AAD */ ++ EVP_EncryptUpdate(ctx, NULL, &outlen, gcm_aad, sizeof(gcm_aad)); ++ /* Encrypt plaintext */ ++ EVP_EncryptUpdate(ctx, outbuf, &outlen, gcm_pt, sizeof(gcm_pt)); ++ /* Output encrypted block */ ++ printf("Ciphertext:\n"); ++ BIO_dump_fp(stdout, outbuf, outlen); ++ /* Finalise: note get no output for GCM */ ++ EVP_EncryptFinal_ex(ctx, outbuf, &outlen); ++ /* Get tag */ ++ EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_GET_TAG, 16, outbuf); ++ /* Output tag */ ++ printf("Tag:\n"); ++ BIO_dump_fp(stdout, outbuf, 16); ++ EVP_CIPHER_CTX_free(ctx); ++} ++ ++void aes_gcm_decrypt(void) ++{ ++ EVP_CIPHER_CTX *ctx; ++ int outlen, tmplen, rv; ++ unsigned char outbuf[1024]; ++ printf("AES GCM Derypt:\n"); ++ printf("Ciphertext:\n"); ++ BIO_dump_fp(stdout, gcm_ct, sizeof(gcm_ct)); ++ ctx = EVP_CIPHER_CTX_new(); ++ /* Select cipher */ ++ EVP_DecryptInit_ex(ctx, EVP_aes_256_gcm(), NULL, NULL, NULL); ++ /* Set IV length, omit for 96 bits */ ++ EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_SET_IVLEN, sizeof(gcm_iv), NULL); ++ /* Specify key and IV */ ++ EVP_DecryptInit_ex(ctx, NULL, NULL, gcm_key, gcm_iv); ++ /* Zero or more calls to specify any AAD */ ++ EVP_DecryptUpdate(ctx, NULL, &outlen, gcm_aad, sizeof(gcm_aad)); ++ /* Decrypt plaintext */ ++ EVP_DecryptUpdate(ctx, outbuf, &outlen, gcm_ct, sizeof(gcm_ct)); ++ /* Output decrypted block */ ++ printf("Plaintext:\n"); ++ BIO_dump_fp(stdout, outbuf, outlen); ++ /* Set expected tag value. */ ++ EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_SET_TAG, sizeof(gcm_tag), gcm_tag); ++ /* Finalise: note get no output for GCM */ ++ rv = EVP_DecryptFinal_ex(ctx, outbuf, &outlen); ++ /* ++ * Print out return value. If this is not successful authentication ++ * failed and plaintext is not trustworthy. ++ */ ++ printf("Tag Verify %s\n", rv > 0 ? "Successful!" : "Failed!"); ++ EVP_CIPHER_CTX_free(ctx); ++} ++ ++int main(int argc, char **argv) ++{ ++ aes_gcm_encrypt(); ++ aes_gcm_decrypt(); ++} +diff --git a/CryptoPkg/Library/OpensslLib/openssl/demos/pkcs12/README b/CryptoPkg/Library/OpensslLib/openssl/demos/pkcs12/README +new file mode 100644 +index 0000000..c87434b +--- /dev/null ++++ b/CryptoPkg/Library/OpensslLib/openssl/demos/pkcs12/README +@@ -0,0 +1,3 @@ ++PKCS#12 demo applications ++ ++Written by Steve Henson. +diff --git a/CryptoPkg/Library/OpensslLib/openssl/demos/pkcs12/pkread.c b/CryptoPkg/Library/OpensslLib/openssl/demos/pkcs12/pkread.c +new file mode 100644 +index 0000000..3b87d7a +--- /dev/null ++++ b/CryptoPkg/Library/OpensslLib/openssl/demos/pkcs12/pkread.c +@@ -0,0 +1,68 @@ ++/* ++ * Copyright 2000-2016 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 ++ * in the file LICENSE in the source distribution or at ++ * https://www.openssl.org/source/license.html ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++ ++/* Simple PKCS#12 file reader */ ++ ++int main(int argc, char **argv) ++{ ++ FILE *fp; ++ EVP_PKEY *pkey; ++ X509 *cert; ++ STACK_OF(X509) *ca = NULL; ++ PKCS12 *p12; ++ int i; ++ if (argc != 4) { ++ fprintf(stderr, "Usage: pkread p12file password opfile\n"); ++ exit(1); ++ } ++ OpenSSL_add_all_algorithms(); ++ ERR_load_crypto_strings(); ++ if ((fp = fopen(argv[1], "rb")) == NULL) { ++ fprintf(stderr, "Error opening file %s\n", argv[1]); ++ exit(1); ++ } ++ p12 = d2i_PKCS12_fp(fp, NULL); ++ fclose(fp); ++ if (!p12) { ++ fprintf(stderr, "Error reading PKCS#12 file\n"); ++ ERR_print_errors_fp(stderr); ++ exit(1); ++ } ++ if (!PKCS12_parse(p12, argv[2], &pkey, &cert, &ca)) { ++ fprintf(stderr, "Error parsing PKCS#12 file\n"); ++ ERR_print_errors_fp(stderr); ++ exit(1); ++ } ++ PKCS12_free(p12); ++ if ((fp = fopen(argv[3], "w")) == NULL) { ++ fprintf(stderr, "Error opening file %s\n", argv[1]); ++ exit(1); ++ } ++ if (pkey) { ++ fprintf(fp, "***Private Key***\n"); ++ PEM_write_PrivateKey(fp, pkey, NULL, NULL, 0, NULL, NULL); ++ } ++ if (cert) { ++ fprintf(fp, "***User Certificate***\n"); ++ PEM_write_X509_AUX(fp, cert); ++ } ++ if (ca && sk_X509_num(ca)) { ++ fprintf(fp, "***Other Certificates***\n"); ++ for (i = 0; i < sk_X509_num(ca); i++) ++ PEM_write_X509_AUX(fp, sk_X509_value(ca, i)); ++ } ++ fclose(fp); ++ return 0; ++} +diff --git a/CryptoPkg/Library/OpensslLib/openssl/demos/pkcs12/pkwrite.c b/CryptoPkg/Library/OpensslLib/openssl/demos/pkcs12/pkwrite.c +new file mode 100644 +index 0000000..e14cf83 +--- /dev/null ++++ b/CryptoPkg/Library/OpensslLib/openssl/demos/pkcs12/pkwrite.c +@@ -0,0 +1,53 @@ ++/* ++ * Copyright 2000-2016 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 ++ * in the file LICENSE in the source distribution or at ++ * https://www.openssl.org/source/license.html ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++ ++/* Simple PKCS#12 file creator */ ++ ++int main(int argc, char **argv) ++{ ++ FILE *fp; ++ EVP_PKEY *pkey; ++ X509 *cert; ++ PKCS12 *p12; ++ if (argc != 5) { ++ fprintf(stderr, "Usage: pkwrite infile password name p12file\n"); ++ exit(1); ++ } ++ OpenSSL_add_all_algorithms(); ++ ERR_load_crypto_strings(); ++ if ((fp = fopen(argv[1], "r")) == NULL) { ++ fprintf(stderr, "Error opening file %s\n", argv[1]); ++ exit(1); ++ } ++ cert = PEM_read_X509(fp, NULL, NULL, NULL); ++ rewind(fp); ++ pkey = PEM_read_PrivateKey(fp, NULL, NULL, NULL); ++ fclose(fp); ++ p12 = PKCS12_create(argv[2], argv[3], pkey, cert, NULL, 0, 0, 0, 0, 0); ++ if (!p12) { ++ fprintf(stderr, "Error creating PKCS#12 structure\n"); ++ ERR_print_errors_fp(stderr); ++ exit(1); ++ } ++ if ((fp = fopen(argv[4], "wb")) == NULL) { ++ fprintf(stderr, "Error opening file %s\n", argv[1]); ++ ERR_print_errors_fp(stderr); ++ exit(1); ++ } ++ i2d_PKCS12_fp(fp, p12); ++ PKCS12_free(p12); ++ fclose(fp); ++ return 0; ++} +diff --git a/CryptoPkg/Library/OpensslLib/openssl/demos/smime/cacert.pem b/CryptoPkg/Library/OpensslLib/openssl/demos/smime/cacert.pem +new file mode 100644 +index 0000000..75cbb34 +--- /dev/null ++++ b/CryptoPkg/Library/OpensslLib/openssl/demos/smime/cacert.pem +@@ -0,0 +1,18 @@ ++-----BEGIN CERTIFICATE----- ++MIIC6DCCAlGgAwIBAgIJAMfGO3rdo2uUMA0GCSqGSIb3DQEBBAUAMFcxCzAJBgNV ++BAYTAlVLMRIwEAYDVQQHEwlUZXN0IENpdHkxFjAUBgNVBAoTDU9wZW5TU0wgR3Jv ++dXAxHDAaBgNVBAMTE1Rlc3QgUy9NSU1FIFJvb3QgQ0EwHhcNMDcwNDEzMTc0MzE3 ++WhcNMTcwNDEwMTc0MzE3WjBXMQswCQYDVQQGEwJVSzESMBAGA1UEBxMJVGVzdCBD ++aXR5MRYwFAYDVQQKEw1PcGVuU1NMIEdyb3VwMRwwGgYDVQQDExNUZXN0IFMvTUlN ++RSBSb290IENBMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCqJMal1uC1/1wz ++i5+dE4EZF2im3BgROm5PVMbwPY9V1t+KYvtdc3rMcRgJaMbP+qaEcDXoIsZfYXGR ++ielgfDNZmZcj1y/FOum+Jc2OZMs3ggPmjIQ3dbBECq0hZKcbz7wfr+2OeNWm46iT ++jcSIXpGIRhUYEzOgv7zb8oOU70IbbwIDAQABo4G7MIG4MB0GA1UdDgQWBBRHUypx ++CXFQYqewhGo72lWPQUsjoDCBiAYDVR0jBIGAMH6AFEdTKnEJcVBip7CEajvaVY9B ++SyOgoVukWTBXMQswCQYDVQQGEwJVSzESMBAGA1UEBxMJVGVzdCBDaXR5MRYwFAYD ++VQQKEw1PcGVuU1NMIEdyb3VwMRwwGgYDVQQDExNUZXN0IFMvTUlNRSBSb290IENB ++ggkAx8Y7et2ja5QwDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQQFAAOBgQANI+Yc ++G/YDM1WMUGEzEkU9UhsIUqdyBebnK3+OyxZSouDcE/M10jFJzBf/F5b0uUGAKWwo ++u0dzmILfKjdfWe8EyCRafZcm00rVcO09i/63FBYzlHbmfUATIqZdhKzxxQMPs5mF ++1je+pHUpzIY8TSXyh/uD9IkAy04IHwGZQf9akw== ++-----END CERTIFICATE----- +diff --git a/CryptoPkg/Library/OpensslLib/openssl/demos/smime/cakey.pem b/CryptoPkg/Library/OpensslLib/openssl/demos/smime/cakey.pem +new file mode 100644 +index 0000000..3b53c5e +--- /dev/null ++++ b/CryptoPkg/Library/OpensslLib/openssl/demos/smime/cakey.pem +@@ -0,0 +1,15 @@ ++-----BEGIN RSA PRIVATE KEY----- ++MIICXgIBAAKBgQCqJMal1uC1/1wzi5+dE4EZF2im3BgROm5PVMbwPY9V1t+KYvtd ++c3rMcRgJaMbP+qaEcDXoIsZfYXGRielgfDNZmZcj1y/FOum+Jc2OZMs3ggPmjIQ3 ++dbBECq0hZKcbz7wfr+2OeNWm46iTjcSIXpGIRhUYEzOgv7zb8oOU70IbbwIDAQAB ++AoGBAKWOZ2UTc1BkjDjz0XoscmAR8Rj77MdGzfOPkIxPultSW+3yZpkGNyUbnsH5 ++HAtf4Avai/m3bMN+s91kDpx9/g/I9ZEHPQLcDICETvwt/EHT7+hwvaQgsM+TgpMs ++tjlGZOWent6wVIuvwwzqOMXZLgK9FvY7upwgtrys4G3Kab5hAkEA2QzFflWyEvKS ++rMSaVtn/IjFilwa7H0IdakkjM34z4peerFTPBr4J47YD4RCR/dAvxyNy3zUxtH18 ++9R6dUixI6QJBAMitJD0xOkbGWBX8KVJvRiKOIdf/95ZUAgN/h3bWKy57EB9NYj3u ++jbxXcvdjfSqiITykkjAg7SG7nrlzJsu6CpcCQG6gVsy0auXDY0TRlASuaZ6I40Is ++uRUOgqWYj2uAaHuWYdZeB4LdO3cnX0TISFDAWom6JKNlnmbrCtR4fSDT13kCQQCU +++VQJyV3F5MDHsWbLt6eNR46AV5lpk/vatPXPlrZ/zwPs+PmRmGLICvNiDA2DdNDP ++wCx2Zjsj67CtY3rNitMJAkEAm09BQnjnbBXUb1rd2SjNDWTsu80Z+zLu8pAwXNhW ++8nsvMYqlYMIxuMPwu/QuTnMRhMZ08uhqoD3ukZnBeoMEVg== ++-----END RSA PRIVATE KEY----- +diff --git a/CryptoPkg/Library/OpensslLib/openssl/demos/smime/encr.txt b/CryptoPkg/Library/OpensslLib/openssl/demos/smime/encr.txt +new file mode 100644 +index 0000000..f163a32 +--- /dev/null ++++ b/CryptoPkg/Library/OpensslLib/openssl/demos/smime/encr.txt +@@ -0,0 +1,3 @@ ++Content-type: text/plain ++ ++Sample OpenSSL Data for PKCS#7 encryption +diff --git a/CryptoPkg/Library/OpensslLib/openssl/demos/smime/sign.txt b/CryptoPkg/Library/OpensslLib/openssl/demos/smime/sign.txt +new file mode 100644 +index 0000000..af1341d +--- /dev/null ++++ b/CryptoPkg/Library/OpensslLib/openssl/demos/smime/sign.txt +@@ -0,0 +1,3 @@ ++Content-type: text/plain ++ ++Test OpenSSL Signed Content +diff --git a/CryptoPkg/Library/OpensslLib/openssl/demos/smime/signer.pem b/CryptoPkg/Library/OpensslLib/openssl/demos/smime/signer.pem +new file mode 100644 +index 0000000..bac16ba +--- /dev/null ++++ b/CryptoPkg/Library/OpensslLib/openssl/demos/smime/signer.pem +@@ -0,0 +1,32 @@ ++-----BEGIN CERTIFICATE----- ++MIICpjCCAg+gAwIBAgIJAJ+rfmEoLQRhMA0GCSqGSIb3DQEBBAUAMFcxCzAJBgNV ++BAYTAlVLMRIwEAYDVQQHEwlUZXN0IENpdHkxFjAUBgNVBAoTDU9wZW5TU0wgR3Jv ++dXAxHDAaBgNVBAMTE1Rlc3QgUy9NSU1FIFJvb3QgQ0EwHhcNMDcwNDEzMTgyOTI3 ++WhcNMTcwNDA5MTgyOTI3WjBWMQswCQYDVQQGEwJVSzElMCMGA1UEAxMcT3BlblNT ++TCB0ZXN0IFMvTUlNRSBzaWduZXIgMTEgMB4GCSqGSIb3DQEJARYRdGVzdDFAb3Bl ++bnNzbC5vcmcwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAL1ocAQ7ON2pIUXz ++jwKPzpPB9ozB6PFG6F6kARO+i0DiT6Qn8abUjwpHPU+lGys83QlpbkQVUD6Fv/4L ++ytihk6N9Pr/feECVcSZ20dI43WXjfYak14dSVrZkGNMMXqKmnnqtkAdD0oJN7A7y ++gcf8RuViV0kvk9/36eCMwMHrImfhAgMBAAGjezB5MAkGA1UdEwQCMAAwLAYJYIZI ++AYb4QgENBB8WHU9wZW5TU0wgR2VuZXJhdGVkIENlcnRpZmljYXRlMB0GA1UdDgQW ++BBSyKqjvctIsFNBHULBTqr8SHtSxpDAfBgNVHSMEGDAWgBRHUypxCXFQYqewhGo7 ++2lWPQUsjoDANBgkqhkiG9w0BAQQFAAOBgQBvdYVoBfd4RV/xWSMXIcgw/i5OiwyX ++MsenQePll51MpglfArd7pUipUalCqlJt/Gs8kD16Ih1z1yuWYVTMlnDZ0PwbIOYn +++Jr8XLF9b1SMJt6PwckZZ0LZdIi2KwGAxVsIW1kjJAqu9o4YH37XW37yYdQRxfvv ++lDiQlgX0JtmLgA== ++-----END CERTIFICATE----- ++-----BEGIN RSA PRIVATE KEY----- ++MIICXAIBAAKBgQC9aHAEOzjdqSFF848Cj86TwfaMwejxRuhepAETvotA4k+kJ/Gm ++1I8KRz1PpRsrPN0JaW5EFVA+hb/+C8rYoZOjfT6/33hAlXEmdtHSON1l432GpNeH ++Ula2ZBjTDF6ipp56rZAHQ9KCTewO8oHH/EblYldJL5Pf9+ngjMDB6yJn4QIDAQAB ++AoGACCuYIWaYll80UzslYRvo8lC8nOfEb5v6bBKxBTQD98GLY+5hKywiG3RlPalG ++mb/fXQeSPReaRYgpdwD1OBEIOEMW9kLyqpzokC0xjpZ+MwsuJTlxCesk5GEsMa3o ++wC3QMmiRA7qrZ/SzTtwrs++9mZ/pxp8JZ6pKYUj8SE7/vV0CQQDz8Ix2t40E16hx ++04+XhClnGqydZJyLLSxcTU3ZVhYxL+efo/5hZ8tKpkcDi8wq6T03BOKrKxrlIW55 ++qDRNM24rAkEAxsWzu/rJhIouQyNoYygEIEYzFRlTQyZSg59u6dNiewMn27dOAbyc ++YT7B6da7e74QttTXo0lIllsX2S38+XsIIwJBANSRuIU3G66tkr5l4gnhhAaxqtuY ++sgVhvvdL8dvC9aG1Ifzt9hzBSthpHxbK+oYmK07HdhI8hLpIMLHYzoK7n3MCQEy4 ++4rccBcxyyYiAkjozp+QNNIpgTBMPJ6pGT7lRLiHtBeV4y1NASdv/LTnk+Fi69Bid ++7t3H24ytfHcHmS1yn6ECQF6Jmh4C7dlvp59zXp+t+VsXxa/8sq41vKNIj0Rx9vh5 ++xp9XL0C5ZpgmBnsTydP9pmkiL4ltLbMX0wJU6N2cmFw= ++-----END RSA PRIVATE KEY----- +diff --git a/CryptoPkg/Library/OpensslLib/openssl/demos/smime/signer2.pem b/CryptoPkg/Library/OpensslLib/openssl/demos/smime/signer2.pem +new file mode 100644 +index 0000000..25e23d1 +--- /dev/null ++++ b/CryptoPkg/Library/OpensslLib/openssl/demos/smime/signer2.pem +@@ -0,0 +1,32 @@ ++-----BEGIN CERTIFICATE----- ++MIICpjCCAg+gAwIBAgIJAJ+rfmEoLQRiMA0GCSqGSIb3DQEBBAUAMFcxCzAJBgNV ++BAYTAlVLMRIwEAYDVQQHEwlUZXN0IENpdHkxFjAUBgNVBAoTDU9wZW5TU0wgR3Jv ++dXAxHDAaBgNVBAMTE1Rlc3QgUy9NSU1FIFJvb3QgQ0EwHhcNMDcwNDEzMTgyOTQ0 ++WhcNMTcwNDA5MTgyOTQ0WjBWMQswCQYDVQQGEwJVSzElMCMGA1UEAxMcT3BlblNT ++TCB0ZXN0IFMvTUlNRSBzaWduZXIgMjEgMB4GCSqGSIb3DQEJARYRdGVzdDJAb3Bl ++bnNzbC5vcmcwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBANco7VPgX9vcGwmZ ++jYqjq1JiR7M38dsMNhuJyLRVjJ5/cpFluQydQuG1PhzOJ8zfYVFicOXKvbYuKuXW ++ozZIwzqEqWsNf36KHTLS6yOMG8I13cRInh+fAIKq9Z8Eh65I7FJzVsNsfEQrGfEW ++GMA8us24IaSvP3QkbfHJn/4RaKznAgMBAAGjezB5MAkGA1UdEwQCMAAwLAYJYIZI ++AYb4QgENBB8WHU9wZW5TU0wgR2VuZXJhdGVkIENlcnRpZmljYXRlMB0GA1UdDgQW ++BBRlrLQJUB8uAa4q8B2OqvvTXonF5zAfBgNVHSMEGDAWgBRHUypxCXFQYqewhGo7 ++2lWPQUsjoDANBgkqhkiG9w0BAQQFAAOBgQBQbi2juGALg2k9m1hKpzR2lCGmGO3X ++h3Jh/l0vIxDr0RTgP2vBrtITlx655P/o1snoeTIpYG8uUnFnTE/6YakdayAIlxV4 ++aZl63AivZMpQB5SPaPH/jEsGJ8UQMfdiy4ORWIULupuPKlKwODNw7tVhQIACS/DR ++2aX6rl2JEuJ5Yg== ++-----END CERTIFICATE----- ++-----BEGIN RSA PRIVATE KEY----- ++MIICXAIBAAKBgQDXKO1T4F/b3BsJmY2Ko6tSYkezN/HbDDYbici0VYyef3KRZbkM ++nULhtT4czifM32FRYnDlyr22Lirl1qM2SMM6hKlrDX9+ih0y0usjjBvCNd3ESJ4f ++nwCCqvWfBIeuSOxSc1bDbHxEKxnxFhjAPLrNuCGkrz90JG3xyZ/+EWis5wIDAQAB ++AoGAUTB2bcIrKfGimjrBOGGOUmYXnD8uGnQ/LqENhU8K4vxApTD3ZRUqmbUknQYF ++6r8YH/e/llasw8QkF9qod+F5GTgsnyh/aMidFHKrXXbf1662scz9+S6crSXq9Eb2 ++CL57f6Kw61k6edrz8zHdA+rnTK00hzgzKCP4ZL5k8/55ueECQQD+BK+nsKi6CcKf ++m3Mh61Sf2Icm5JlMCKaihlbnh78lBN1imYUAfHJEnQ1ujxXB94R+6o9S+XrWTnTX ++2m/JNIfpAkEA2NaidX7Sv5jnRPkwJ02Srl0urxINLmg4bU0zmM3VoMklYBHWnMyr ++upPZGPh5TzCa+g6FTBmU8XK61wvnEKNcTwJBAM24VdnlBIDGbsx8RJ3vzLU30xz4 ++ff5J80okqjUQhwkgC3tTAZgHMTPITZyAXQqdvrxakoCMc6MkHxTBX08AMCECQHHL ++SdyxXrYv7waSY0PtANJCkpJLveEhzqMFxdMmCjtj9BpTojYNbv3uQxtIopj9YAdk ++gW2ray++zvC2DV/86x8CQH4UJwgO6JqU4bSgi6HiRNjDg26tJ0Beu8jjl1vrkIVX ++pHFwSUeLZUsT2/iTUSgYH4uYiZPgYNcKTCT9W6se30A= ++-----END RSA PRIVATE KEY----- +diff --git a/CryptoPkg/Library/OpensslLib/openssl/demos/smime/smdec.c b/CryptoPkg/Library/OpensslLib/openssl/demos/smime/smdec.c +new file mode 100644 +index 0000000..c4d1b09 +--- /dev/null ++++ b/CryptoPkg/Library/OpensslLib/openssl/demos/smime/smdec.c +@@ -0,0 +1,78 @@ ++/* ++ * Copyright 2007-2016 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 ++ * in the file LICENSE in the source distribution or at ++ * https://www.openssl.org/source/license.html ++ */ ++ ++/* Simple S/MIME signing example */ ++#include ++#include ++#include ++ ++int main(int argc, char **argv) ++{ ++ BIO *in = NULL, *out = NULL, *tbio = NULL; ++ X509 *rcert = NULL; ++ EVP_PKEY *rkey = NULL; ++ PKCS7 *p7 = NULL; ++ int ret = 1; ++ ++ OpenSSL_add_all_algorithms(); ++ ERR_load_crypto_strings(); ++ ++ /* Read in recipient certificate and private key */ ++ tbio = BIO_new_file("signer.pem", "r"); ++ ++ if (!tbio) ++ goto err; ++ ++ rcert = PEM_read_bio_X509(tbio, NULL, 0, NULL); ++ ++ BIO_reset(tbio); ++ ++ rkey = PEM_read_bio_PrivateKey(tbio, NULL, 0, NULL); ++ ++ if (!rcert || !rkey) ++ goto err; ++ ++ /* Open content being signed */ ++ ++ in = BIO_new_file("smencr.txt", "r"); ++ ++ if (!in) ++ goto err; ++ ++ /* Sign content */ ++ p7 = SMIME_read_PKCS7(in, NULL); ++ ++ if (!p7) ++ goto err; ++ ++ out = BIO_new_file("encrout.txt", "w"); ++ if (!out) ++ goto err; ++ ++ /* Decrypt S/MIME message */ ++ if (!PKCS7_decrypt(p7, rkey, rcert, out, 0)) ++ goto err; ++ ++ ret = 0; ++ ++ err: ++ if (ret) { ++ fprintf(stderr, "Error Signing Data\n"); ++ ERR_print_errors_fp(stderr); ++ } ++ PKCS7_free(p7); ++ X509_free(rcert); ++ EVP_PKEY_free(rkey); ++ BIO_free(in); ++ BIO_free(out); ++ BIO_free(tbio); ++ ++ return ret; ++ ++} +diff --git a/CryptoPkg/Library/OpensslLib/openssl/demos/smime/smenc.c b/CryptoPkg/Library/OpensslLib/openssl/demos/smime/smenc.c +new file mode 100644 +index 0000000..5d36e9a +--- /dev/null ++++ b/CryptoPkg/Library/OpensslLib/openssl/demos/smime/smenc.c +@@ -0,0 +1,91 @@ ++/* ++ * Copyright 2007-2016 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 ++ * in the file LICENSE in the source distribution or at ++ * https://www.openssl.org/source/license.html ++ */ ++ ++/* Simple S/MIME encrypt example */ ++#include ++#include ++#include ++ ++int main(int argc, char **argv) ++{ ++ BIO *in = NULL, *out = NULL, *tbio = NULL; ++ X509 *rcert = NULL; ++ STACK_OF(X509) *recips = NULL; ++ PKCS7 *p7 = NULL; ++ int ret = 1; ++ ++ /* ++ * On OpenSSL 0.9.9 only: ++ * for streaming set PKCS7_STREAM ++ */ ++ int flags = PKCS7_STREAM; ++ ++ OpenSSL_add_all_algorithms(); ++ ERR_load_crypto_strings(); ++ ++ /* Read in recipient certificate */ ++ tbio = BIO_new_file("signer.pem", "r"); ++ ++ if (!tbio) ++ goto err; ++ ++ rcert = PEM_read_bio_X509(tbio, NULL, 0, NULL); ++ ++ if (!rcert) ++ goto err; ++ ++ /* Create recipient STACK and add recipient cert to it */ ++ recips = sk_X509_new_null(); ++ ++ if (!recips || !sk_X509_push(recips, rcert)) ++ goto err; ++ ++ /* ++ * sk_X509_pop_free will free up recipient STACK and its contents so set ++ * rcert to NULL so it isn't freed up twice. ++ */ ++ rcert = NULL; ++ ++ /* Open content being encrypted */ ++ ++ in = BIO_new_file("encr.txt", "r"); ++ ++ if (!in) ++ goto err; ++ ++ /* encrypt content */ ++ p7 = PKCS7_encrypt(recips, in, EVP_des_ede3_cbc(), flags); ++ ++ if (!p7) ++ goto err; ++ ++ out = BIO_new_file("smencr.txt", "w"); ++ if (!out) ++ goto err; ++ ++ /* Write out S/MIME message */ ++ if (!SMIME_write_PKCS7(out, p7, in, flags)) ++ goto err; ++ ++ ret = 0; ++ ++ err: ++ if (ret) { ++ fprintf(stderr, "Error Encrypting Data\n"); ++ ERR_print_errors_fp(stderr); ++ } ++ PKCS7_free(p7); ++ X509_free(rcert); ++ sk_X509_pop_free(recips, X509_free); ++ BIO_free(in); ++ BIO_free(out); ++ BIO_free(tbio); ++ return ret; ++ ++} +diff --git a/CryptoPkg/Library/OpensslLib/openssl/demos/smime/smsign.c b/CryptoPkg/Library/OpensslLib/openssl/demos/smime/smsign.c +new file mode 100644 +index 0000000..ba0adb3 +--- /dev/null ++++ b/CryptoPkg/Library/OpensslLib/openssl/demos/smime/smsign.c +@@ -0,0 +1,88 @@ ++/* ++ * Copyright 2007-2016 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 ++ * in the file LICENSE in the source distribution or at ++ * https://www.openssl.org/source/license.html ++ */ ++ ++/* Simple S/MIME signing example */ ++#include ++#include ++#include ++ ++int main(int argc, char **argv) ++{ ++ BIO *in = NULL, *out = NULL, *tbio = NULL; ++ X509 *scert = NULL; ++ EVP_PKEY *skey = NULL; ++ PKCS7 *p7 = NULL; ++ int ret = 1; ++ ++ /* ++ * For simple S/MIME signing use PKCS7_DETACHED. On OpenSSL 0.9.9 only: ++ * for streaming detached set PKCS7_DETACHED|PKCS7_STREAM for streaming ++ * non-detached set PKCS7_STREAM ++ */ ++ int flags = PKCS7_DETACHED | PKCS7_STREAM; ++ ++ OpenSSL_add_all_algorithms(); ++ ERR_load_crypto_strings(); ++ ++ /* Read in signer certificate and private key */ ++ tbio = BIO_new_file("signer.pem", "r"); ++ ++ if (!tbio) ++ goto err; ++ ++ scert = PEM_read_bio_X509(tbio, NULL, 0, NULL); ++ ++ BIO_reset(tbio); ++ ++ skey = PEM_read_bio_PrivateKey(tbio, NULL, 0, NULL); ++ ++ if (!scert || !skey) ++ goto err; ++ ++ /* Open content being signed */ ++ ++ in = BIO_new_file("sign.txt", "r"); ++ ++ if (!in) ++ goto err; ++ ++ /* Sign content */ ++ p7 = PKCS7_sign(scert, skey, NULL, in, flags); ++ ++ if (!p7) ++ goto err; ++ ++ out = BIO_new_file("smout.txt", "w"); ++ if (!out) ++ goto err; ++ ++ if (!(flags & PKCS7_STREAM)) ++ BIO_reset(in); ++ ++ /* Write out S/MIME message */ ++ if (!SMIME_write_PKCS7(out, p7, in, flags)) ++ goto err; ++ ++ ret = 0; ++ ++ err: ++ if (ret) { ++ fprintf(stderr, "Error Signing Data\n"); ++ ERR_print_errors_fp(stderr); ++ } ++ PKCS7_free(p7); ++ X509_free(scert); ++ EVP_PKEY_free(skey); ++ BIO_free(in); ++ BIO_free(out); ++ BIO_free(tbio); ++ ++ return ret; ++ ++} +diff --git a/CryptoPkg/Library/OpensslLib/openssl/demos/smime/smsign2.c b/CryptoPkg/Library/OpensslLib/openssl/demos/smime/smsign2.c +new file mode 100644 +index 0000000..2b7f45b +--- /dev/null ++++ b/CryptoPkg/Library/OpensslLib/openssl/demos/smime/smsign2.c +@@ -0,0 +1,96 @@ ++/* ++ * Copyright 2007-2016 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 ++ * in the file LICENSE in the source distribution or at ++ * https://www.openssl.org/source/license.html ++ */ ++ ++/* S/MIME signing example: 2 signers. OpenSSL 0.9.9 only */ ++#include ++#include ++#include ++ ++int main(int argc, char **argv) ++{ ++ BIO *in = NULL, *out = NULL, *tbio = NULL; ++ X509 *scert = NULL, *scert2 = NULL; ++ EVP_PKEY *skey = NULL, *skey2 = NULL; ++ PKCS7 *p7 = NULL; ++ int ret = 1; ++ ++ OpenSSL_add_all_algorithms(); ++ ERR_load_crypto_strings(); ++ ++ tbio = BIO_new_file("signer.pem", "r"); ++ ++ if (!tbio) ++ goto err; ++ ++ scert = PEM_read_bio_X509(tbio, NULL, 0, NULL); ++ ++ BIO_reset(tbio); ++ ++ skey = PEM_read_bio_PrivateKey(tbio, NULL, 0, NULL); ++ ++ BIO_free(tbio); ++ ++ tbio = BIO_new_file("signer2.pem", "r"); ++ ++ if (!tbio) ++ goto err; ++ ++ scert2 = PEM_read_bio_X509(tbio, NULL, 0, NULL); ++ ++ BIO_reset(tbio); ++ ++ skey2 = PEM_read_bio_PrivateKey(tbio, NULL, 0, NULL); ++ ++ if (!scert2 || !skey2) ++ goto err; ++ ++ in = BIO_new_file("sign.txt", "r"); ++ ++ if (!in) ++ goto err; ++ ++ p7 = PKCS7_sign(NULL, NULL, NULL, in, PKCS7_STREAM | PKCS7_PARTIAL); ++ ++ if (!p7) ++ goto err; ++ ++ /* Add each signer in turn */ ++ ++ if (!PKCS7_sign_add_signer(p7, scert, skey, NULL, 0)) ++ goto err; ++ ++ if (!PKCS7_sign_add_signer(p7, scert2, skey2, NULL, 0)) ++ goto err; ++ ++ out = BIO_new_file("smout.txt", "w"); ++ if (!out) ++ goto err; ++ ++ /* NB: content included and finalized by SMIME_write_PKCS7 */ ++ ++ if (!SMIME_write_PKCS7(out, p7, in, PKCS7_STREAM)) ++ goto err; ++ ++ ret = 0; ++ ++ err: ++ if (ret) { ++ fprintf(stderr, "Error Signing Data\n"); ++ ERR_print_errors_fp(stderr); ++ } ++ PKCS7_free(p7); ++ X509_free(scert); ++ EVP_PKEY_free(skey); ++ X509_free(scert2); ++ EVP_PKEY_free(skey2); ++ BIO_free(in); ++ BIO_free(out); ++ BIO_free(tbio); ++ return ret; ++} +diff --git a/CryptoPkg/Library/OpensslLib/openssl/demos/smime/smver.c b/CryptoPkg/Library/OpensslLib/openssl/demos/smime/smver.c +new file mode 100644 +index 0000000..75411c4 +--- /dev/null ++++ b/CryptoPkg/Library/OpensslLib/openssl/demos/smime/smver.c +@@ -0,0 +1,83 @@ ++/* ++ * Copyright 2007-2016 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 ++ * in the file LICENSE in the source distribution or at ++ * https://www.openssl.org/source/license.html ++ */ ++ ++/* Simple S/MIME verification example */ ++#include ++#include ++#include ++ ++int main(int argc, char **argv) ++{ ++ BIO *in = NULL, *out = NULL, *tbio = NULL, *cont = NULL; ++ X509_STORE *st = NULL; ++ X509 *cacert = NULL; ++ PKCS7 *p7 = NULL; ++ ++ int ret = 1; ++ ++ OpenSSL_add_all_algorithms(); ++ ERR_load_crypto_strings(); ++ ++ /* Set up trusted CA certificate store */ ++ ++ st = X509_STORE_new(); ++ ++ /* Read in signer certificate and private key */ ++ tbio = BIO_new_file("cacert.pem", "r"); ++ ++ if (!tbio) ++ goto err; ++ ++ cacert = PEM_read_bio_X509(tbio, NULL, 0, NULL); ++ ++ if (!cacert) ++ goto err; ++ ++ if (!X509_STORE_add_cert(st, cacert)) ++ goto err; ++ ++ /* Open content being signed */ ++ ++ in = BIO_new_file("smout.txt", "r"); ++ ++ if (!in) ++ goto err; ++ ++ /* Sign content */ ++ p7 = SMIME_read_PKCS7(in, &cont); ++ ++ if (!p7) ++ goto err; ++ ++ /* File to output verified content to */ ++ out = BIO_new_file("smver.txt", "w"); ++ if (!out) ++ goto err; ++ ++ if (!PKCS7_verify(p7, NULL, st, cont, out, 0)) { ++ fprintf(stderr, "Verification Failure\n"); ++ goto err; ++ } ++ ++ fprintf(stderr, "Verification Successful\n"); ++ ++ ret = 0; ++ ++ err: ++ if (ret) { ++ fprintf(stderr, "Error Verifying Data\n"); ++ ERR_print_errors_fp(stderr); ++ } ++ PKCS7_free(p7); ++ X509_free(cacert); ++ BIO_free(in); ++ BIO_free(out); ++ BIO_free(tbio); ++ return ret; ++} +diff --git a/CryptoPkg/Library/OpensslLib/openssl/doc/CT_POLICY_EVAL_CTX_new.pod b/CryptoPkg/Library/OpensslLib/openssl/doc/CT_POLICY_EVAL_CTX_new.pod +new file mode 100644 +index 0000000..fedc58d +--- /dev/null ++++ b/CryptoPkg/Library/OpensslLib/openssl/doc/CT_POLICY_EVAL_CTX_new.pod +@@ -0,0 +1,111 @@ ++=pod ++ ++=head1 NAME ++ ++CT_POLICY_EVAL_CTX_new, CT_POLICY_EVAL_CTX_free, ++CT_POLICY_EVAL_CTX_get0_cert, CT_POLICY_EVAL_CTX_set1_cert, ++CT_POLICY_EVAL_CTX_get0_issuer, CT_POLICY_EVAL_CTX_set1_issuer, ++CT_POLICY_EVAL_CTX_get0_log_store, CT_POLICY_EVAL_CTX_set_shared_CTLOG_STORE, ++CT_POLICY_EVAL_CTX_get_time, CT_POLICY_EVAL_CTX_set_time - ++Encapsulates the data required to evaluate whether SCTs meet a Certificate Transparency policy ++ ++=head1 SYNOPSIS ++ ++ #include ++ ++ CT_POLICY_EVAL_CTX *CT_POLICY_EVAL_CTX_new(void); ++ void CT_POLICY_EVAL_CTX_free(CT_POLICY_EVAL_CTX *ctx); ++ X509* CT_POLICY_EVAL_CTX_get0_cert(const CT_POLICY_EVAL_CTX *ctx); ++ int CT_POLICY_EVAL_CTX_set1_cert(CT_POLICY_EVAL_CTX *ctx, X509 *cert); ++ X509* CT_POLICY_EVAL_CTX_get0_issuer(const CT_POLICY_EVAL_CTX *ctx); ++ int CT_POLICY_EVAL_CTX_set1_issuer(CT_POLICY_EVAL_CTX *ctx, X509 *issuer); ++ const CTLOG_STORE *CT_POLICY_EVAL_CTX_get0_log_store(const CT_POLICY_EVAL_CTX *ctx); ++ void CT_POLICY_EVAL_CTX_set_shared_CTLOG_STORE(CT_POLICY_EVAL_CTX *ctx, CTLOG_STORE *log_store); ++ uint64_t CT_POLICY_EVAL_CTX_get_time(const CT_POLICY_EVAL_CTX *ctx); ++ void CT_POLICY_EVAL_CTX_set_time(CT_POLICY_EVAL_CTX *ctx, uint64_t time_in_ms); ++ ++=head1 DESCRIPTION ++ ++A B is used by functions that evaluate whether Signed ++Certificate Timestamps (SCTs) fulfil a Certificate Transparency (CT) policy. ++This policy may be, for example, that at least one valid SCT is available. To ++determine this, an SCT's timestamp and signature must be verified. ++This requires: ++ ++=over ++ ++=item * the public key of the log that issued the SCT ++ ++=item * the certificate that the SCT was issued for ++ ++=item * the issuer certificate (if the SCT was issued for a pre-certificate) ++ ++=item * the current time ++ ++=back ++ ++The above requirements are met using the setters described below. ++ ++CT_POLICY_EVAL_CTX_new() creates an empty policy evaluation context. This ++should then be populated using: ++ ++=over ++ ++=item * CT_POLICY_EVAL_CTX_set1_cert() to provide the certificate the SCTs were issued for ++ ++Increments the reference count of the certificate. ++ ++=item * CT_POLICY_EVAL_CTX_set1_issuer() to provide the issuer certificate ++ ++Increments the reference count of the certificate. ++ ++=item * CT_POLICY_EVAL_CTX_set_shared_CTLOG_STORE() to provide a list of logs that are trusted as sources of SCTs ++ ++Holds a pointer to the CTLOG_STORE, so the CTLOG_STORE must outlive the ++CT_POLICY_EVAL_CTX. ++ ++=item * CT_POLICY_EVAL_CTX_set_time() to set the time SCTs should be compared with to determine if they are valid ++ ++The SCT timestamp will be compared to this time to check whether the SCT was ++issued in the future. RFC6962 states that "TLS clients MUST reject SCTs whose ++timestamp is in the future". By default, this will be set to 5 minutes in the ++future (e.g. (time() + 300) * 1000), to allow for clock drift. ++ ++The time should be in milliseconds since the Unix epoch. ++ ++=back ++ ++Each setter has a matching getter for accessing the current value. ++ ++When no longer required, the B should be passed to ++CT_POLICY_EVAL_CTX_free() to delete it. ++ ++=head1 NOTES ++ ++The issuer certificate only needs to be provided if at least one of the SCTs ++was issued for a pre-certificate. This will be the case for SCTs embedded in a ++certificate (i.e. those in an X.509 extension), but may not be the case for SCTs ++found in the TLS SCT extension or OCSP response. ++ ++=head1 RETURN VALUES ++ ++CT_POLICY_EVAL_CTX_new() will return NULL if malloc fails. ++ ++=head1 SEE ALSO ++ ++L ++ ++=head1 HISTORY ++ ++These functions were added in OpenSSL 1.1.0. ++ ++=head1 COPYRIGHT ++ ++Copyright 2016 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 ++in the file LICENSE in the source distribution or at ++L. ++ ++=cut +diff --git a/CryptoPkg/Library/OpensslLib/openssl/doc/HOWTO/certificates.txt b/CryptoPkg/Library/OpensslLib/openssl/doc/HOWTO/certificates.txt +new file mode 100644 +index 0000000..65f8fc8 +--- /dev/null ++++ b/CryptoPkg/Library/OpensslLib/openssl/doc/HOWTO/certificates.txt +@@ -0,0 +1,110 @@ ++ ++ HOWTO certificates ++ ++1. Introduction ++ ++How you handle certificates depends a great deal on what your role is. ++Your role can be one or several of: ++ ++ - User of some client application ++ - User of some server application ++ - Certificate authority ++ ++This file is for users who wish to get a certificate of their own. ++Certificate authorities should read https://www.openssl.org/docs/apps/ca.html. ++ ++In all the cases shown below, the standard configuration file, as ++compiled into openssl, will be used. You may find it in /etc/, ++/usr/local/ssl/ or somewhere else. By default the file is named ++openssl.cnf and is described at https://www.openssl.org/docs/apps/config.html. ++You can specify a different configuration file using the ++'-config {file}' argument with the commands shown below. ++ ++ ++2. Relationship with keys ++ ++Certificates are related to public key cryptography by containing a ++public key. To be useful, there must be a corresponding private key ++somewhere. With OpenSSL, public keys are easily derived from private ++keys, so before you create a certificate or a certificate request, you ++need to create a private key. ++ ++Private keys are generated with 'openssl genrsa -out privkey.pem' if ++you want a RSA private key, or if you want a DSA private key: ++'openssl dsaparam -out dsaparam.pem 2048; openssl gendsa -out privkey.pem dsaparam.pem'. ++ ++The private keys created by these commands are not passphrase protected; ++it might or might not be the desirable thing. Further information on how to ++create private keys can be found at https://www.openssl.org/docs/HOWTO/keys.txt. ++The rest of this text assumes you have a private key in the file privkey.pem. ++ ++ ++3. Creating a certificate request ++ ++To create a certificate, you need to start with a certificate request ++(or, as some certificate authorities like to put it, "certificate ++signing request", since that's exactly what they do, they sign it and ++give you the result back, thus making it authentic according to their ++policies). A certificate request is sent to a certificate authority ++to get it signed into a certificate. You can also sign the certificate ++yourself if you have your own certificate authority or create a ++self-signed certificate (typically for testing purpose). ++ ++The certificate request is created like this: ++ ++ openssl req -new -key privkey.pem -out cert.csr ++ ++Now, cert.csr can be sent to the certificate authority, if they can ++handle files in PEM format. If not, use the extra argument '-outform' ++followed by the keyword for the format to use (see another HOWTO ++). In some cases, -outform does not let you output the ++certificate request in the right format and you will have to use one ++of the various other commands that are exposed by openssl (or get ++creative and use a combination of tools). ++ ++The certificate authority performs various checks (according to their ++policies) and usually waits for payment from you. Once that is ++complete, they send you your new certificate. ++ ++Section 5 will tell you more on how to handle the certificate you ++received. ++ ++ ++4. Creating a self-signed test certificate ++ ++You can create a self-signed certificate if you don't want to deal ++with a certificate authority, or if you just want to create a test ++certificate for yourself. This is similar to creating a certificate ++request, but creates a certificate instead of a certificate request. ++This is NOT the recommended way to create a CA certificate, see ++https://www.openssl.org/docs/apps/ca.html. ++ ++ openssl req -new -x509 -key privkey.pem -out cacert.pem -days 1095 ++ ++ ++5. What to do with the certificate ++ ++If you created everything yourself, or if the certificate authority ++was kind enough, your certificate is a raw DER thing in PEM format. ++Your key most definitely is if you have followed the examples above. ++However, some (most?) certificate authorities will encode them with ++things like PKCS7 or PKCS12, or something else. Depending on your ++applications, this may be perfectly OK, it all depends on what they ++know how to decode. If not, There are a number of OpenSSL tools to ++convert between some (most?) formats. ++ ++So, depending on your application, you may have to convert your ++certificate and your key to various formats, most often also putting ++them together into one file. The ways to do this is described in ++another HOWTO , I will just mention the simplest case. ++In the case of a raw DER thing in PEM format, and assuming that's all ++right for your applications, simply concatenating the certificate and ++the key into a new file and using that one should be enough. With ++some applications, you don't even have to do that. ++ ++ ++By now, you have your certificate and your private key and can start ++using applications that depend on it. ++ ++-- ++Richard Levitte +diff --git a/CryptoPkg/Library/OpensslLib/openssl/doc/HOWTO/keys.txt b/CryptoPkg/Library/OpensslLib/openssl/doc/HOWTO/keys.txt +new file mode 100644 +index 0000000..ba0314f +--- /dev/null ++++ b/CryptoPkg/Library/OpensslLib/openssl/doc/HOWTO/keys.txt +@@ -0,0 +1,72 @@ ++ ++ HOWTO keys ++ ++1. Introduction ++ ++Keys are the basis of public key algorithms and PKI. Keys usually ++come in pairs, with one half being the public key and the other half ++being the private key. With OpenSSL, the private key contains the ++public key information as well, so a public key doesn't need to be ++generated separately. ++ ++Public keys come in several flavors, using different cryptographic ++algorithms. The most popular ones associated with certificates are ++RSA and DSA, and this HOWTO will show how to generate each of them. ++ ++ ++2. To generate a RSA key ++ ++A RSA key can be used both for encryption and for signing. ++ ++Generating a key for the RSA algorithm is quite easy, all you have to ++do is the following: ++ ++ openssl genrsa -des3 -out privkey.pem 2048 ++ ++With this variant, you will be prompted for a protecting password. If ++you don't want your key to be protected by a password, remove the flag ++'-des3' from the command line above. ++ ++ NOTE: if you intend to use the key together with a server ++ certificate, it may be a good thing to avoid protecting it ++ with a password, since that would mean someone would have to ++ type in the password every time the server needs to access ++ the key. ++ ++The number 2048 is the size of the key, in bits. Today, 2048 or ++higher is recommended for RSA keys, as fewer amount of bits is ++consider insecure or to be insecure pretty soon. ++ ++ ++3. To generate a DSA key ++ ++A DSA key can be used for signing only. It is important to ++know what a certificate request with a DSA key can really be used for. ++ ++Generating a key for the DSA algorithm is a two-step process. First, ++you have to generate parameters from which to generate the key: ++ ++ openssl dsaparam -out dsaparam.pem 2048 ++ ++The number 2048 is the size of the key, in bits. Today, 2048 or ++higher is recommended for DSA keys, as fewer amount of bits is ++consider insecure or to be insecure pretty soon. ++ ++When that is done, you can generate a key using the parameters in ++question (actually, several keys can be generated from the same ++parameters): ++ ++ openssl gendsa -des3 -out privkey.pem dsaparam.pem ++ ++With this variant, you will be prompted for a protecting password. If ++you don't want your key to be protected by a password, remove the flag ++'-des3' from the command line above. ++ ++ NOTE: if you intend to use the key together with a server ++ certificate, it may be a good thing to avoid protecting it ++ with a password, since that would mean someone would have to ++ type in the password every time the server needs to access ++ the key. ++ ++-- ++Richard Levitte +diff --git a/CryptoPkg/Library/OpensslLib/openssl/doc/HOWTO/proxy_certificates.txt b/CryptoPkg/Library/OpensslLib/openssl/doc/HOWTO/proxy_certificates.txt +new file mode 100644 +index 0000000..642bec9 +--- /dev/null ++++ b/CryptoPkg/Library/OpensslLib/openssl/doc/HOWTO/proxy_certificates.txt +@@ -0,0 +1,319 @@ ++ HOWTO proxy certificates ++ ++0. WARNING ++ ++NONE OF THE CODE PRESENTED HERE HAS BEEN CHECKED! The code is just examples to ++show you how things could be done. There might be typos or type conflicts, and ++you will have to resolve them. ++ ++1. Introduction ++ ++Proxy certificates are defined in RFC 3820. They are really usual certificates ++with the mandatory extension proxyCertInfo. ++ ++Proxy certificates are issued by an End Entity (typically a user), either ++directly with the EE certificate as issuing certificate, or by extension through ++an already issued proxy certificate. Proxy certificates are used to extend ++rights to some other entity (a computer process, typically, or sometimes to the ++user itself). This allows the entity to perform operations on behalf of the ++owner of the EE certificate. ++ ++See http://www.ietf.org/rfc/rfc3820.txt for more information. ++ ++ ++2. A warning about proxy certificates ++ ++No one seems to have tested proxy certificates with security in mind. To this ++date, it seems that proxy certificates have only been used in a context highly ++aware of them. ++ ++Existing applications might misbehave when trying to validate a chain of ++certificates which use a proxy certificate. They might incorrectly consider the ++leaf to be the certificate to check for authorisation data, which is controlled ++by the EE certificate owner. ++ ++subjectAltName and issuerAltName are forbidden in proxy certificates, and this ++is enforced in OpenSSL. The subject must be the same as the issuer, with one ++commonName added on. ++ ++Possible threats we can think of at this time include: ++ ++ - impersonation through commonName (think server certificates). ++ - use of additional extensions, possibly non-standard ones used in certain ++ environments, that would grant extra or different authorisation rights. ++ ++For these reasons, OpenSSL requires that the use of proxy certificates be ++explicitly allowed. Currently, this can be done using the following methods: ++ ++ - if the application directly calls X509_verify_cert(), it can first call: ++ ++ X509_STORE_CTX_set_flags(ctx, X509_V_FLAG_ALLOW_PROXY_CERTS); ++ ++ Where ctx is the pointer which then gets passed to X509_verify_cert(). ++ ++ - proxy certificate validation can be enabled before starting the application ++ by setting the environment variable OPENSSL_ALLOW_PROXY_CERTS. ++ ++In the future, it might be possible to enable proxy certificates by editing ++openssl.cnf. ++ ++ ++3. How to create proxy certificates ++ ++Creating proxy certificates is quite easy, by taking advantage of a lack of ++checks in the 'openssl x509' application (*ahem*). You must first create a ++configuration section that contains a definition of the proxyCertInfo extension, ++for example: ++ ++ [ v3_proxy ] ++ # A proxy certificate MUST NEVER be a CA certificate. ++ basicConstraints=CA:FALSE ++ ++ # Usual authority key ID ++ authorityKeyIdentifier=keyid,issuer:always ++ ++ # The extension which marks this certificate as a proxy ++ proxyCertInfo=critical,language:id-ppl-anyLanguage,pathlen:1,policy:text:AB ++ ++It's also possible to specify the proxy extension in a separate section: ++ ++ proxyCertInfo=critical,@proxy_ext ++ ++ [ proxy_ext ] ++ language=id-ppl-anyLanguage ++ pathlen=0 ++ policy=text:BC ++ ++The policy value has a specific syntax, {syntag}:{string}, where the syntag ++determines what will be done with the string. The following syntags are ++recognised: ++ ++ text indicates that the string is simply bytes, without any encoding: ++ ++ policy=text:räksmörgås ++ ++ Previous versions of this design had a specific tag for UTF-8 text. ++ However, since the bytes are copied as-is anyway, there is no need for ++ such a specific tag. ++ ++ hex indicates the string is encoded in hex, with colons between each byte ++ (every second hex digit): ++ ++ policy=hex:72:E4:6B:73:6D:F6:72:67:E5:73 ++ ++ Previous versions of this design had a tag to insert a complete DER ++ blob. However, the only legal use for this would be to surround the ++ bytes that would go with the hex: tag with whatever is needed to ++ construct a correct OCTET STRING. The DER tag therefore felt ++ superfluous, and was removed. ++ ++ file indicates that the text of the policy should really be taken from a ++ file. The string is then really a file name. This is useful for ++ policies that are large (more than a few lines, e.g. XML documents). ++ ++The 'policy' setting can be split up in multiple lines like this: ++ ++ 0.policy=This is ++ 1.policy= a multi- ++ 2.policy=line policy. ++ ++NOTE: the proxy policy value is the part which determines the rights granted to ++the process using the proxy certificate. The value is completely dependent on ++the application reading and interpreting it! ++ ++Now that you have created an extension section for your proxy certificate, you ++can easily create a proxy certificate by doing: ++ ++ openssl req -new -config openssl.cnf -out proxy.req -keyout proxy.key ++ openssl x509 -req -CAcreateserial -in proxy.req -days 7 -out proxy.crt \ ++ -CA user.crt -CAkey user.key -extfile openssl.cnf -extensions v3_proxy ++ ++You can also create a proxy certificate using another proxy certificate as ++issuer (note: I'm using a different configuration section for it): ++ ++ openssl req -new -config openssl.cnf -out proxy2.req -keyout proxy2.key ++ openssl x509 -req -CAcreateserial -in proxy2.req -days 7 -out proxy2.crt \ ++ -CA proxy.crt -CAkey proxy.key -extfile openssl.cnf -extensions v3_proxy2 ++ ++ ++4. How to have your application interpret the policy? ++ ++The basic way to interpret proxy policies is to start with some default rights, ++then compute the resulting rights by checking the proxy certificate against ++the chain of proxy certificates, user certificate and CA certificates. You then ++use the final computed rights. Sounds easy, huh? It almost is. ++ ++The slightly complicated part is figuring out how to pass data between your ++application and the certificate validation procedure. ++ ++You need the following ingredients: ++ ++ - a callback function that will be called for every certificate being ++ validated. The callback be called several times for each certificate, ++ so you must be careful to do the proxy policy interpretation at the right ++ time. You also need to fill in the defaults when the EE certificate is ++ checked. ++ ++ - a data structure that is shared between your application code and the ++ callback. ++ ++ - a wrapper function that sets it all up. ++ ++ - an ex_data index function that creates an index into the generic ex_data ++ store that is attached to an X509 validation context. ++ ++Here is some skeleton code you can fill in: ++ ++ #include ++ #include ++ #include ++ #include ++ ++ #define total_rights 25 ++ ++ /* ++ * In this example, I will use a view of granted rights as a bit ++ * array, one bit for each possible right. ++ */ ++ typedef struct your_rights { ++ unsigned char rights[(total_rights + 7) / 8]; ++ } YOUR_RIGHTS; ++ ++ /* ++ * The following procedure will create an index for the ex_data ++ * store in the X509 validation context the first time it's called. ++ * Subsequent calls will return the same index. */ ++ static int get_proxy_auth_ex_data_idx(X509_STORE_CTX *ctx) ++ { ++ static volatile int idx = -1; ++ if (idx < 0) { ++ X509_STORE_lock(X509_STORE_CTX_get0_store(ctx)); ++ if (idx < 0) { ++ idx = X509_STORE_CTX_get_ex_new_index(0, ++ "for verify callback", ++ NULL,NULL,NULL); ++ } ++ X509_STORE_unlock(X509_STORE_CTX_get0_store(ctx)); ++ } ++ return idx; ++ } ++ ++ /* Callback to be given to the X509 validation procedure. */ ++ static int verify_callback(int ok, X509_STORE_CTX *ctx) ++ { ++ if (ok == 1) { ++ /* ++ * It's REALLY important you keep the proxy policy ++ * check within this section. It's important to know ++ * that when ok is 1, the certificates are checked ++ * from top to bottom. You get the CA root first, ++ * followed by the possible chain of intermediate ++ * CAs, followed by the EE certificate, followed by ++ * the possible proxy certificates. ++ */ ++ X509 *xs = X509_STORE_CTX_get_current_cert(ctx); ++ ++ if (X509_get_extension_flags(xs) & EXFLAG_PROXY) { ++ YOUR_RIGHTS *rights = ++ (YOUR_RIGHTS *)X509_STORE_CTX_get_ex_data(ctx, ++ get_proxy_auth_ex_data_idx(ctx)); ++ PROXY_CERT_INFO_EXTENSION *pci = ++ X509_get_ext_d2i(xs, NID_proxyCertInfo, NULL, NULL); ++ ++ switch (OBJ_obj2nid(pci->proxyPolicy->policyLanguage)) { ++ case NID_Independent: ++ /* ++ * Do whatever you need to grant explicit rights to ++ * this particular proxy certificate, usually by ++ * pulling them from some database. If there are none ++ * to be found, clear all rights (making this and any ++ * subsequent proxy certificate void of any rights). ++ */ ++ memset(rights->rights, 0, sizeof(rights->rights)); ++ break; ++ case NID_id_ppl_inheritAll: ++ /* ++ * This is basically a NOP, we simply let the current ++ * rights stand as they are. ++ */ ++ break; ++ default: ++ /* This is usually the most complex section of code. ++ * You really do whatever you want as long as you ++ * follow RFC 3820. In the example we use here, the ++ * simplest thing to do is to build another, temporary ++ * bit array and fill it with the rights granted by ++ * the current proxy certificate, then use it as a ++ * mask on the accumulated rights bit array, and ++ * voilà, you now have a new accumulated rights bit ++ * array. ++ */ ++ { ++ int i; ++ YOUR_RIGHTS tmp_rights; ++ memset(tmp_rights.rights, 0, sizeof(tmp_rights.rights)); ++ ++ /* ++ * process_rights() is supposed to be a procedure ++ * that takes a string and it's length, interprets ++ * it and sets the bits in the YOUR_RIGHTS pointed ++ * at by the third argument. ++ */ ++ process_rights((char *) pci->proxyPolicy->policy->data, ++ pci->proxyPolicy->policy->length, ++ &tmp_rights); ++ ++ for(i = 0; i < total_rights / 8; i++) ++ rights->rights[i] &= tmp_rights.rights[i]; ++ } ++ break; ++ } ++ PROXY_CERT_INFO_EXTENSION_free(pci); ++ } else if (!(X509_get_extension_flags(xs) & EXFLAG_CA)) { ++ /* We have an EE certificate, let's use it to set default! */ ++ YOUR_RIGHTS *rights = ++ (YOUR_RIGHTS *)X509_STORE_CTX_get_ex_data(ctx, ++ get_proxy_auth_ex_data_idx(ctx)); ++ ++ /* The following procedure finds out what rights the owner ++ * of the current certificate has, and sets them in the ++ * YOUR_RIGHTS structure pointed at by the second ++ * argument. ++ */ ++ set_default_rights(xs, rights); ++ } ++ } ++ return ok; ++ } ++ ++ static int my_X509_verify_cert(X509_STORE_CTX *ctx, ++ YOUR_RIGHTS *needed_rights) ++ { ++ int ok; ++ int (*save_verify_cb)(int ok,X509_STORE_CTX *ctx) = ++ X509_STORE_CTX_get_verify_cb(ctx); ++ YOUR_RIGHTS rights; ++ ++ X509_STORE_CTX_set_verify_cb(ctx, verify_callback); ++ X509_STORE_CTX_set_ex_data(ctx, get_proxy_auth_ex_data_idx(ctx), &rights); ++ X509_STORE_CTX_set_flags(ctx, X509_V_FLAG_ALLOW_PROXY_CERTS); ++ ok = X509_verify_cert(ctx); ++ ++ if (ok == 1) { ++ ok = check_needed_rights(rights, needed_rights); ++ } ++ ++ X509_STORE_CTX_set_verify_cb(ctx, save_verify_cb); ++ ++ return ok; ++ } ++ ++ ++If you use SSL or TLS, you can easily set up a callback to have the ++certificates checked properly, using the code above: ++ ++ SSL_CTX_set_cert_verify_callback(s_ctx, my_X509_verify_cert, &needed_rights); ++ ++ ++-- ++Richard Levitte +diff --git a/CryptoPkg/Library/OpensslLib/openssl/doc/README b/CryptoPkg/Library/OpensslLib/openssl/doc/README +new file mode 100644 +index 0000000..5931290 +--- /dev/null ++++ b/CryptoPkg/Library/OpensslLib/openssl/doc/README +@@ -0,0 +1,20 @@ ++ ++README This file ++ ++fingerprints.txt ++ PGP fingerprints of authoried release signers ++ ++standards.txt ++ Moved to the web, https://www.openssl.org/docs/standards.html ++ ++HOWTO/ ++ A few how-to documents; not necessarily up-to-date ++apps/ ++ The openssl command-line tools; start with openssl.pod ++ssl/ ++ The SSL library; start with ssl.pod ++crypto/ ++ The cryptographic library; start with crypto.pod ++ ++Formatted versions of the manpages (apps,ssl,crypto) can be found at ++ https://www.openssl.org/docs/manpages.html +diff --git a/CryptoPkg/Library/OpensslLib/openssl/doc/SCT_validate.pod b/CryptoPkg/Library/OpensslLib/openssl/doc/SCT_validate.pod +new file mode 100644 +index 0000000..9868a28 +--- /dev/null ++++ b/CryptoPkg/Library/OpensslLib/openssl/doc/SCT_validate.pod +@@ -0,0 +1,98 @@ ++=pod ++ ++=head1 NAME ++ ++SCT_validate, SCT_LIST_validate, SCT_get_validation_status - ++checks Signed Certificate Timestamps (SCTs) are valid ++ ++=head1 SYNOPSIS ++ ++ #include ++ ++ typedef enum { ++ SCT_VALIDATION_STATUS_NOT_SET, ++ SCT_VALIDATION_STATUS_UNKNOWN_LOG, ++ SCT_VALIDATION_STATUS_VALID, ++ SCT_VALIDATION_STATUS_INVALID, ++ SCT_VALIDATION_STATUS_UNVERIFIED, ++ SCT_VALIDATION_STATUS_UNKNOWN_VERSION ++ } sct_validation_status_t; ++ ++ int SCT_validate(SCT *sct, const CT_POLICY_EVAL_CTX *ctx); ++ int SCT_LIST_validate(const STACK_OF(SCT) *scts, CT_POLICY_EVAL_CTX *ctx); ++ sct_validation_status_t SCT_get_validation_status(const SCT *sct); ++ ++=head1 DESCRIPTION ++ ++SCT_validate() will check that an SCT is valid and verify its signature. ++SCT_LIST_validate() performs the same checks on an entire stack of SCTs. ++The result of the validation checks can be obtained by passing the SCT to ++SCT_get_validation_status(). ++ ++A CT_POLICY_EVAL_CTX must be provided that specifies: ++ ++=over ++ ++=item * The certificate the SCT was issued for. ++ ++Failure to provide the certificate will result in the validation status being ++SCT_VALIDATION_STATUS_UNVERIFIED. ++ ++=item * The issuer of that certificate. ++ ++This is only required if the SCT was issued for a pre-certificate ++(see RFC 6962). If it is required but not provided, the validation status will ++be SCT_VALIDATION_STATUS_UNVERIFIED. ++ ++=item * A CTLOG_STORE that contains the CT log that issued this SCT. ++ ++If the SCT was issued by a log that is not in this CTLOG_STORE, the validation ++status will be SCT_VALIDATION_STATUS_UNKNOWN_LOG. ++ ++=back ++ ++If the SCT is of an unsupported version (only v1 is currently supported), the ++validation status will be SCT_VALIDATION_STATUS_UNKNOWN_VERSION. ++ ++If the SCT's signature is incorrect, its timestamp is in the future (relative to ++the time in CT_POLICY_EVAL_CTX), or if it is otherwise invalid, the validation ++status will be SCT_VALIDATION_STATUS_INVALID. ++ ++If all checks pass, the validation status will be SCT_VALIDATION_STATUS_VALID. ++ ++=head1 NOTES ++ ++A return value of 0 from SCT_LIST_validate() should not be interpreted as a ++failure. At a minimum, only one valid SCT may provide sufficient confidence ++that a certificate has been publicly logged. ++ ++=head1 RETURN VALUES ++ ++SCT_validate() returns a negative integer if an internal error occurs, 0 if the ++SCT fails validation, or 1 if the SCT passes validation. ++ ++SCT_LIST_validate() returns a negative integer if an internal error occurs, 0 ++if any of SCTs fails validation, or 1 if they all pass validation. ++ ++SCT_get_validation_status() returns the validation status of the SCT. ++If SCT_validate() or SCT_LIST_validate() have not been passed that SCT, the ++returned value will be SCT_VALIDATION_STATUS_NOT_SET. ++ ++=head1 SEE ALSO ++ ++L ++ ++=head1 HISTORY ++ ++These functions were added in OpenSSL 1.1.0. ++ ++=head1 COPYRIGHT ++ ++Copyright 2016 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 ++in the file LICENSE in the source distribution or at ++L. ++ ++=cut +diff --git a/CryptoPkg/Library/OpensslLib/openssl/doc/SSL_CTX_set_ct_validation_callback.pod b/CryptoPkg/Library/OpensslLib/openssl/doc/SSL_CTX_set_ct_validation_callback.pod +new file mode 100644 +index 0000000..d818e00 +--- /dev/null ++++ b/CryptoPkg/Library/OpensslLib/openssl/doc/SSL_CTX_set_ct_validation_callback.pod +@@ -0,0 +1,142 @@ ++=pod ++ ++=head1 NAME ++ ++SSL_enable_ct, SSL_CTX_enable_ct, SSL_disable_ct, SSL_CTX_disable_ct, ++SSL_set_ct_validation_callback, SSL_CTX_set_ct_validation_callback, ++SSL_ct_is_enabled, SSL_CTX_ct_is_enabled - ++control Certificate Transparency policy ++ ++=head1 SYNOPSIS ++ ++ #include ++ ++ int SSL_enable_ct(SSL *s, int validation_mode); ++ int SSL_CTX_enable_ct(SSL_CTX *ctx, int validation_mode); ++ int SSL_set_ct_validation_callback(SSL *s, ssl_ct_validation_cb callback, ++ void *arg); ++ int SSL_CTX_set_ct_validation_callback(SSL_CTX *ctx, ++ ssl_ct_validation_cb callback, ++ void *arg); ++ void SSL_disable_ct(SSL *s); ++ void SSL_CTX_disable_ct(SSL_CTX *ctx); ++ int SSL_ct_is_enabled(const SSL *s); ++ int SSL_CTX_ct_is_enabled(const SSL_CTX *ctx); ++ ++=head1 DESCRIPTION ++ ++SSL_enable_ct() and SSL_CTX_enable_ct() enable the processing of signed ++certificate timestamps (SCTs) either for a given SSL connection or for all ++connections that share the given SSL context, respectively. ++This is accomplished by setting a built-in CT validation callback. ++The behaviour of the callback is determined by the B argument, ++which can be either of B or ++B as described below. ++ ++If B is equal to B, then in a full ++TLS handshake with the verification mode set to B, if the peer ++presents no valid SCTs the handshake will be aborted. ++If the verification mode is B, the handshake will continue ++despite lack of valid SCTs. ++However, in that case if the verification status before the built-in callback ++was B it will be set to B after the ++callback. ++Applications can call L to check the status at ++handshake completion, even after session resumption since the verification ++status is part of the saved session state. ++See L, , L. ++ ++If B is equal to B, then the ++handshake continues, and the verification status is not modified, regardless of ++the validation status of any SCTs. ++The application can still inspect the validation status of the SCTs at ++handshake completion. ++Note that with session resumption there will not be any SCTs presented during ++the handshake. ++Therefore, in applications that delay SCT policy enforcement until after ++handshake completion, such delayed SCT checks should only be performed when the ++session is not resumed. ++ ++SSL_set_ct_validation_callback() and SSL_CTX_set_ct_validation_callback() ++register a custom callback that may implement a different policy than either of ++the above. ++This callback can examine the peer's SCTs and determine whether they are ++sufficient to allow the connection to continue. ++The TLS handshake is aborted if the verification mode is not B ++and the callback returns a non-positive result. ++ ++An arbitrary callback context argument, B, can be passed in when setting ++the callback. ++This will be passed to the callback whenever it is invoked. ++Ownership of this context remains with the caller. ++ ++If no callback is set, SCTs will not be requested and Certificate Transparency ++validation will not occur. ++ ++No callback will be invoked when the peer presents no certificate, e.g. by ++employing an anonymous (aNULL) ciphersuite. ++In that case the handshake continues as it would had no callback been ++requested. ++Callbacks are also not invoked when the peer certificate chain is invalid or ++validated via DANE-TA(2) or DANE-EE(3) TLSA records which use a private X.509 ++PKI, or no X.509 PKI at all, respectively. ++Clients that require SCTs are expected to not have enabled any aNULL ciphers ++nor to have specified server verification via DANE-TA(2) or DANE-EE(3) TLSA ++records. ++ ++SSL_disable_ct() and SSL_CTX_disable_ct() turn off CT processing, whether ++enabled via the built-in or the custom callbacks, by setting a NULL callback. ++These may be implemented as macros. ++ ++SSL_ct_is_enabled() and SSL_CTX_ct_is_enabled() return 1 if CT processing is ++enabled via either SSL_enable_ct() or a non-null custom callback, and 0 ++otherwise. ++ ++=head1 NOTES ++ ++When SCT processing is enabled, OCSP stapling will be enabled. This is because ++one possible source of SCTs is the OCSP response from a server. ++ ++The time returned by SSL_SESSION_get_time() will be used to evaluate whether any ++presented SCTs have timestamps that are in the future (and therefore invalid). ++ ++=head1 RESTRICTIONS ++ ++Certificate Transparency validation cannot be enabled and so a callback cannot ++be set if a custom client extension handler has been registered to handle SCT ++extensions (B). ++ ++=head1 RETURN VALUES ++ ++SSL_enable_ct(), SSL_CTX_enable_ct(), SSL_CTX_set_ct_validation_callback() and ++SSL_set_ct_validation_callback() return 1 if the B is successfully ++set. ++They return 0 if an error occurs, e.g. a custom client extension handler has ++been setup to handle SCTs. ++ ++SSL_disable_ct() and SSL_CTX_disable_ct() do not return a result. ++ ++SSL_CTX_ct_is_enabled() and SSL_ct_is_enabled() return a 1 if a non-null CT ++validation callback is set, or 0 if no callback (or equivalently a NULL ++callback) is set. ++ ++=head1 SEE ALSO ++ ++L, ++, ++L, ++L, ++L, ++L, ++L ++ ++=head1 COPYRIGHT ++ ++Copyright 2016 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 ++in the file LICENSE in the source distribution or at ++L. ++ ++=cut +diff --git a/CryptoPkg/Library/OpensslLib/openssl/doc/apps/CA.pl.pod b/CryptoPkg/Library/OpensslLib/openssl/doc/apps/CA.pl.pod +new file mode 100644 +index 0000000..a7f3970 +--- /dev/null ++++ b/CryptoPkg/Library/OpensslLib/openssl/doc/apps/CA.pl.pod +@@ -0,0 +1,214 @@ ++=pod ++ ++=head1 NAME ++ ++CA.pl - friendlier interface for OpenSSL certificate programs ++ ++=head1 SYNOPSIS ++ ++B ++B<-?> | ++B<-h> | ++B<-help> ++ ++B ++B<-newcert> | ++B<-newreq> | ++B<-newreq-nodes> | ++B<-xsign> | ++B<-sign> | ++B<-signCA> | ++B<-signcert> | ++B<-crl> | ++B<-newca> ++[B<-extra-cmd> extra-params] ++ ++B B<-pkcs12> [B<-extra-pkcs12> extra-params] [B] ++ ++B B<-verify> [B<-extra-verify> extra-params] B... ++ ++B B<-revoke> [B<-extra-ca> extra-params] B [B] ++ ++=head1 DESCRIPTION ++ ++The B script is a perl script that supplies the relevant command line ++arguments to the B command for some common certificate operations. ++It is intended to simplify the process of certificate creation and management ++by the use of some simple options. ++ ++=head1 OPTIONS ++ ++=over 4 ++ ++=item B, B<-h>, B<-help> ++ ++prints a usage message. ++ ++=item B<-newcert> ++ ++creates a new self signed certificate. The private key is written to the file ++"newkey.pem" and the request written to the file "newreq.pem". ++This argument invokes B command. ++ ++=item B<-newreq> ++ ++creates a new certificate request. The private key is written to the file ++"newkey.pem" and the request written to the file "newreq.pem". ++Executes B command below the hood. ++ ++=item B<-newreq-nodes> ++ ++is like B<-newreq> except that the private key will not be encrypted. ++Uses B command. ++ ++=item B<-newca> ++ ++creates a new CA hierarchy for use with the B program (or the B<-signcert> ++and B<-xsign> options). The user is prompted to enter the filename of the CA ++certificates (which should also contain the private key) or by hitting ENTER ++details of the CA will be prompted for. The relevant files and directories ++are created in a directory called "demoCA" in the current directory. ++B and B commands are get invoked. ++ ++=item B<-pkcs12> ++ ++create a PKCS#12 file containing the user certificate, private key and CA ++certificate. It expects the user certificate and private key to be in the ++file "newcert.pem" and the CA certificate to be in the file demoCA/cacert.pem, ++it creates a file "newcert.p12". This command can thus be called after the ++B<-sign> option. The PKCS#12 file can be imported directly into a browser. ++If there is an additional argument on the command line it will be used as the ++"friendly name" for the certificate (which is typically displayed in the browser ++list box), otherwise the name "My Certificate" is used. ++Delegates work to B command. ++ ++=item B<-sign>, B<-signcert>, B<-xsign> ++ ++calls the B program to sign a certificate request. It expects the request ++to be in the file "newreq.pem". The new certificate is written to the file ++"newcert.pem" except in the case of the B<-xsign> option when it is written ++to standard output. Leverages B command. ++ ++=item B<-signCA> ++ ++this option is the same as the B<-signreq> option except it uses the configuration ++file section B and so makes the signed request a valid CA certificate. This ++is useful when creating intermediate CA from a root CA. ++Extra params are passed on to B command. ++ ++=item B<-signcert> ++ ++this option is the same as B<-sign> except it expects a self signed certificate ++to be present in the file "newreq.pem". ++Extra params are passed on to B and B commands. ++ ++=item B<-crl> ++ ++generate a CRL. Executes B command. ++ ++=item B<-revoke certfile [reason]> ++ ++revoke the certificate contained in the specified B. An optional ++reason may be specified, and must be one of: B, ++B, B, B, B, ++B, B, or B. ++Leverages B command. ++ ++=item B<-verify> ++ ++verifies certificates against the CA certificate for "demoCA". If no certificates ++are specified on the command line it tries to verify the file "newcert.pem". ++Invokes B command. ++ ++=item B<-extra-req> | B<-extra-ca> | B<-extra-pkcs12> | B<-extra-x509> | B<-extra-verify> ++ ++The purpose of these parameters is to allow optional parameters to be supplied ++to B that this command executes. The B<-extra-cmd> are specific to the ++option being used and the B command getting invoked. For example ++when this command invokes B extra parameters can be passed on ++with the B<-extra-req> parameter. The ++B commands being invoked per option are documented below. ++Users should consult B command documentation for more information. ++ ++=back ++ ++=head1 EXAMPLES ++ ++Create a CA hierarchy: ++ ++ CA.pl -newca ++ ++Complete certificate creation example: create a CA, create a request, sign ++the request and finally create a PKCS#12 file containing it. ++ ++ CA.pl -newca ++ CA.pl -newreq ++ CA.pl -signreq ++ CA.pl -pkcs12 "My Test Certificate" ++ ++=head1 DSA CERTIFICATES ++ ++Although the B creates RSA CAs and requests it is still possible to ++use it with DSA certificates and requests using the L command ++directly. The following example shows the steps that would typically be taken. ++ ++Create some DSA parameters: ++ ++ openssl dsaparam -out dsap.pem 1024 ++ ++Create a DSA CA certificate and private key: ++ ++ openssl req -x509 -newkey dsa:dsap.pem -keyout cacert.pem -out cacert.pem ++ ++Create the CA directories and files: ++ ++ CA.pl -newca ++ ++enter cacert.pem when prompted for the CA file name. ++ ++Create a DSA certificate request and private key (a different set of parameters ++can optionally be created first): ++ ++ openssl req -out newreq.pem -newkey dsa:dsap.pem ++ ++Sign the request: ++ ++ CA.pl -signreq ++ ++=head1 NOTES ++ ++Most of the filenames mentioned can be modified by editing the B script. ++ ++If the demoCA directory already exists then the B<-newca> command will not ++overwrite it and will do nothing. This can happen if a previous call using ++the B<-newca> option terminated abnormally. To get the correct behaviour ++delete the demoCA directory if it already exists. ++ ++Under some environments it may not be possible to run the B script ++directly (for example Win32) and the default configuration file location may ++be wrong. In this case the command: ++ ++ perl -S CA.pl ++ ++can be used and the B environment variable changed to point to ++the correct path of the configuration file. ++ ++The script is intended as a simple front end for the B program for use ++by a beginner. Its behaviour isn't always what is wanted. For more control over the ++behaviour of the certificate commands call the B command directly. ++ ++=head1 SEE ALSO ++ ++L, L, L, L, ++L ++ ++=head1 COPYRIGHT ++ ++Copyright 2000-2016 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 ++in the file LICENSE in the source distribution or at ++L. ++ ++=cut +diff --git a/CryptoPkg/Library/OpensslLib/openssl/doc/apps/asn1parse.pod b/CryptoPkg/Library/OpensslLib/openssl/doc/apps/asn1parse.pod +new file mode 100644 +index 0000000..10a5aba +--- /dev/null ++++ b/CryptoPkg/Library/OpensslLib/openssl/doc/apps/asn1parse.pod +@@ -0,0 +1,208 @@ ++=pod ++ ++=head1 NAME ++ ++asn1parse - ASN.1 parsing tool ++ ++=head1 SYNOPSIS ++ ++B B ++[B<-help>] ++[B<-inform PEM|DER>] ++[B<-in filename>] ++[B<-out filename>] ++[B<-noout>] ++[B<-offset number>] ++[B<-length number>] ++[B<-i>] ++[B<-oid filename>] ++[B<-dump>] ++[B<-dlimit num>] ++[B<-strparse offset>] ++[B<-genstr string>] ++[B<-genconf file>] ++[B<-strictpem>] ++ ++=head1 DESCRIPTION ++ ++The B command is a diagnostic utility that can parse ASN.1 ++structures. It can also be used to extract data from ASN.1 formatted data. ++ ++=head1 OPTIONS ++ ++=over 4 ++ ++=item B<-help> ++ ++Print out a usage message. ++ ++=item B<-inform> B ++ ++the input format. B is binary format and B (the default) is base64 ++encoded. ++ ++=item B<-in filename> ++ ++the input file, default is standard input ++ ++=item B<-out filename> ++ ++output file to place the DER encoded data into. If this ++option is not present then no data will be output. This is most useful when ++combined with the B<-strparse> option. ++ ++=item B<-noout> ++ ++don't output the parsed version of the input file. ++ ++=item B<-offset number> ++ ++starting offset to begin parsing, default is start of file. ++ ++=item B<-length number> ++ ++number of bytes to parse, default is until end of file. ++ ++=item B<-i> ++ ++indents the output according to the "depth" of the structures. ++ ++=item B<-oid filename> ++ ++a file containing additional OBJECT IDENTIFIERs (OIDs). The format of this ++file is described in the NOTES section below. ++ ++=item B<-dump> ++ ++dump unknown data in hex format. ++ ++=item B<-dlimit num> ++ ++like B<-dump>, but only the first B bytes are output. ++ ++=item B<-strparse offset> ++ ++parse the contents octets of the ASN.1 object starting at B. This ++option can be used multiple times to "drill down" into a nested structure. ++ ++=item B<-genstr string>, B<-genconf file> ++ ++generate encoded data based on B, B or both using ++L format. If B only is ++present then the string is obtained from the default section using the name ++B. The encoded data is passed through the ASN1 parser and printed out as ++though it came from a file, the contents can thus be examined and written to a ++file using the B option. ++ ++=item B<-strictpem> ++ ++If this option is used then B<-inform> will be ignored. Without this option any ++data in a PEM format input file will be treated as being base64 encoded and ++processed whether it has the normal PEM BEGIN and END markers or not. This ++option will ignore any data prior to the start of the BEGIN marker, or after an ++END marker in a PEM file. ++ ++=back ++ ++=head2 Output ++ ++The output will typically contain lines like this: ++ ++ 0:d=0 hl=4 l= 681 cons: SEQUENCE ++ ++..... ++ ++ 229:d=3 hl=3 l= 141 prim: BIT STRING ++ 373:d=2 hl=3 l= 162 cons: cont [ 3 ] ++ 376:d=3 hl=3 l= 159 cons: SEQUENCE ++ 379:d=4 hl=2 l= 29 cons: SEQUENCE ++ 381:d=5 hl=2 l= 3 prim: OBJECT :X509v3 Subject Key Identifier ++ 386:d=5 hl=2 l= 22 prim: OCTET STRING ++ 410:d=4 hl=2 l= 112 cons: SEQUENCE ++ 412:d=5 hl=2 l= 3 prim: OBJECT :X509v3 Authority Key Identifier ++ 417:d=5 hl=2 l= 105 prim: OCTET STRING ++ 524:d=4 hl=2 l= 12 cons: SEQUENCE ++ ++..... ++ ++This example is part of a self-signed certificate. Each line starts with the ++offset in decimal. B specifies the current depth. The depth is increased ++within the scope of any SET or SEQUENCE. B gives the header length ++(tag and length octets) of the current type. B gives the length of ++the contents octets. ++ ++The B<-i> option can be used to make the output more readable. ++ ++Some knowledge of the ASN.1 structure is needed to interpret the output. ++ ++In this example the BIT STRING at offset 229 is the certificate public key. ++The contents octets of this will contain the public key information. This can ++be examined using the option B<-strparse 229> to yield: ++ ++ 0:d=0 hl=3 l= 137 cons: SEQUENCE ++ 3:d=1 hl=3 l= 129 prim: INTEGER :E5D21E1F5C8D208EA7A2166C7FAF9F6BDF2059669C60876DDB70840F1A5AAFA59699FE471F379F1DD6A487E7D5409AB6A88D4A9746E24B91D8CF55DB3521015460C8EDE44EE8A4189F7A7BE77D6CD3A9AF2696F486855CF58BF0EDF2B4068058C7A947F52548DDF7E15E96B385F86422BEA9064A3EE9E1158A56E4A6F47E5897 ++ 135:d=1 hl=2 l= 3 prim: INTEGER :010001 ++ ++=head1 NOTES ++ ++If an OID is not part of OpenSSL's internal table it will be represented in ++numerical form (for example 1.2.3.4). The file passed to the B<-oid> option ++allows additional OIDs to be included. Each line consists of three columns, ++the first column is the OID in numerical format and should be followed by white ++space. The second column is the "short name" which is a single word followed ++by white space. The final column is the rest of the line and is the ++"long name". B displays the long name. Example: ++ ++C<1.2.3.4 shortName A long name> ++ ++=head1 EXAMPLES ++ ++Parse a file: ++ ++ openssl asn1parse -in file.pem ++ ++Parse a DER file: ++ ++ openssl asn1parse -inform DER -in file.der ++ ++Generate a simple UTF8String: ++ ++ openssl asn1parse -genstr 'UTF8:Hello World' ++ ++Generate and write out a UTF8String, don't print parsed output: ++ ++ openssl asn1parse -genstr 'UTF8:Hello World' -noout -out utf8.der ++ ++Generate using a config file: ++ ++ openssl asn1parse -genconf asn1.cnf -noout -out asn1.der ++ ++Example config file: ++ ++ asn1=SEQUENCE:seq_sect ++ ++ [seq_sect] ++ ++ field1=BOOL:TRUE ++ field2=EXP:0, UTF8:some random string ++ ++ ++=head1 BUGS ++ ++There should be options to change the format of output lines. The output of some ++ASN.1 types is not well handled (if at all). ++ ++=head1 SEE ALSO ++ ++L ++ ++=head1 COPYRIGHT ++ ++Copyright 2000-2016 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 ++in the file LICENSE in the source distribution or at ++L. ++ ++=cut +diff --git a/CryptoPkg/Library/OpensslLib/openssl/doc/apps/ca.pod b/CryptoPkg/Library/OpensslLib/openssl/doc/apps/ca.pod +new file mode 100644 +index 0000000..c09db82 +--- /dev/null ++++ b/CryptoPkg/Library/OpensslLib/openssl/doc/apps/ca.pod +@@ -0,0 +1,719 @@ ++=pod ++ ++=head1 NAME ++ ++ca - sample minimal CA application ++ ++=head1 SYNOPSIS ++ ++B B ++[B<-help>] ++[B<-verbose>] ++[B<-config filename>] ++[B<-name section>] ++[B<-gencrl>] ++[B<-revoke file>] ++[B<-valid file>] ++[B<-status serial>] ++[B<-updatedb>] ++[B<-crl_reason reason>] ++[B<-crl_hold instruction>] ++[B<-crl_compromise time>] ++[B<-crl_CA_compromise time>] ++[B<-crldays days>] ++[B<-crlhours hours>] ++[B<-crlexts section>] ++[B<-startdate date>] ++[B<-enddate date>] ++[B<-days arg>] ++[B<-md arg>] ++[B<-policy arg>] ++[B<-keyfile arg>] ++[B<-keyform PEM|DER>] ++[B<-key arg>] ++[B<-passin arg>] ++[B<-cert file>] ++[B<-selfsign>] ++[B<-in file>] ++[B<-out file>] ++[B<-notext>] ++[B<-outdir dir>] ++[B<-infiles>] ++[B<-spkac file>] ++[B<-ss_cert file>] ++[B<-preserveDN>] ++[B<-noemailDN>] ++[B<-batch>] ++[B<-msie_hack>] ++[B<-extensions section>] ++[B<-extfile section>] ++[B<-engine id>] ++[B<-subj arg>] ++[B<-utf8>] ++[B<-create_serial>] ++[B<-multivalue-rdn>] ++ ++=head1 DESCRIPTION ++ ++The B command is a minimal CA application. It can be used ++to sign certificate requests in a variety of forms and generate ++CRLs it also maintains a text database of issued certificates ++and their status. ++ ++The options descriptions will be divided into each purpose. ++ ++=head1 OPTIONS ++ ++=over 4 ++ ++=item B<-help> ++ ++Print out a usage message. ++ ++=item B<-verbose> ++ ++this prints extra details about the operations being performed. ++ ++=item B<-config filename> ++ ++specifies the configuration file to use. ++Optional; for a description of the default value, ++see L. ++ ++=item B<-name section> ++ ++specifies the configuration file section to use (overrides ++B in the B section). ++ ++=item B<-in filename> ++ ++an input filename containing a single certificate request to be ++signed by the CA. ++ ++=item B<-ss_cert filename> ++ ++a single self-signed certificate to be signed by the CA. ++ ++=item B<-spkac filename> ++ ++a file containing a single Netscape signed public key and challenge ++and additional field values to be signed by the CA. See the B ++section for information on the required input and output format. ++ ++=item B<-infiles> ++ ++if present this should be the last option, all subsequent arguments ++are taken as the names of files containing certificate requests. ++ ++=item B<-out filename> ++ ++the output file to output certificates to. The default is standard ++output. The certificate details will also be printed out to this ++file in PEM format (except that B<-spkac> outputs DER format). ++ ++=item B<-outdir directory> ++ ++the directory to output certificates to. The certificate will be ++written to a filename consisting of the serial number in hex with ++".pem" appended. ++ ++=item B<-cert> ++ ++the CA certificate file. ++ ++=item B<-keyfile filename> ++ ++the private key to sign requests with. ++ ++=item B<-keyform PEM|DER> ++ ++the format of the data in the private key file. ++The default is PEM. ++ ++=item B<-key password> ++ ++the password used to encrypt the private key. Since on some ++systems the command line arguments are visible (e.g. Unix with ++the 'ps' utility) this option should be used with caution. ++ ++=item B<-selfsign> ++ ++indicates the issued certificates are to be signed with the key ++the certificate requests were signed with (given with B<-keyfile>). ++Certificate requests signed with a different key are ignored. If ++B<-spkac>, B<-ss_cert> or B<-gencrl> are given, B<-selfsign> is ++ignored. ++ ++A consequence of using B<-selfsign> is that the self-signed ++certificate appears among the entries in the certificate database ++(see the configuration option B), and uses the same ++serial number counter as all other certificates sign with the ++self-signed certificate. ++ ++=item B<-passin arg> ++ ++the key password source. For more information about the format of B ++see the B section in L. ++ ++=item B<-notext> ++ ++don't output the text form of a certificate to the output file. ++ ++=item B<-startdate date> ++ ++this allows the start date to be explicitly set. The format of the ++date is YYMMDDHHMMSSZ (the same as an ASN1 UTCTime structure). ++ ++=item B<-enddate date> ++ ++this allows the expiry date to be explicitly set. The format of the ++date is YYMMDDHHMMSSZ (the same as an ASN1 UTCTime structure). ++ ++=item B<-days arg> ++ ++the number of days to certify the certificate for. ++ ++=item B<-md alg> ++ ++the message digest to use. ++Any digest supported by the OpenSSL B command can be used. ++This option also applies to CRLs. ++ ++=item B<-policy arg> ++ ++this option defines the CA "policy" to use. This is a section in ++the configuration file which decides which fields should be mandatory ++or match the CA certificate. Check out the B section ++for more information. ++ ++=item B<-msie_hack> ++ ++this is a legacy option to make B work with very old versions of ++the IE certificate enrollment control "certenr3". It used UniversalStrings ++for almost everything. Since the old control has various security bugs ++its use is strongly discouraged. The newer control "Xenroll" does not ++need this option. ++ ++=item B<-preserveDN> ++ ++Normally the DN order of a certificate is the same as the order of the ++fields in the relevant policy section. When this option is set the order ++is the same as the request. This is largely for compatibility with the ++older IE enrollment control which would only accept certificates if their ++DNs match the order of the request. This is not needed for Xenroll. ++ ++=item B<-noemailDN> ++ ++The DN of a certificate can contain the EMAIL field if present in the ++request DN, however it is good policy just having the e-mail set into ++the altName extension of the certificate. When this option is set the ++EMAIL field is removed from the certificate' subject and set only in ++the, eventually present, extensions. The B keyword can be ++used in the configuration file to enable this behaviour. ++ ++=item B<-batch> ++ ++this sets the batch mode. In this mode no questions will be asked ++and all certificates will be certified automatically. ++ ++=item B<-extensions section> ++ ++the section of the configuration file containing certificate extensions ++to be added when a certificate is issued (defaults to B ++unless the B<-extfile> option is used). If no extension section is ++present then, a V1 certificate is created. If the extension section ++is present (even if it is empty), then a V3 certificate is created. See the:w ++L manual page for details of the ++extension section format. ++ ++=item B<-extfile file> ++ ++an additional configuration file to read certificate extensions from ++(using the default section unless the B<-extensions> option is also ++used). ++ ++=item B<-engine id> ++ ++specifying an engine (by its unique B string) will cause B ++to attempt to obtain a functional reference to the specified engine, ++thus initialising it if needed. The engine will then be set as the default ++for all available algorithms. ++ ++=item B<-subj arg> ++ ++supersedes subject name given in the request. ++The arg must be formatted as I, ++characters may be escaped by \ (backslash), no spaces are skipped. ++ ++=item B<-utf8> ++ ++this option causes field values to be interpreted as UTF8 strings, by ++default they are interpreted as ASCII. This means that the field ++values, whether prompted from a terminal or obtained from a ++configuration file, must be valid UTF8 strings. ++ ++=item B<-create_serial> ++ ++if reading serial from the text file as specified in the configuration ++fails, specifying this option creates a new random serial to be used as next ++serial number. ++ ++=item B<-multivalue-rdn> ++ ++This option causes the -subj argument to be interpreted with full ++support for multivalued RDNs. Example: ++ ++I ++ ++If -multi-rdn is not used then the UID value is I<123456+CN=John Doe>. ++ ++=back ++ ++=head1 CRL OPTIONS ++ ++=over 4 ++ ++=item B<-gencrl> ++ ++this option generates a CRL based on information in the index file. ++ ++=item B<-crldays num> ++ ++the number of days before the next CRL is due. That is the days from ++now to place in the CRL nextUpdate field. ++ ++=item B<-crlhours num> ++ ++the number of hours before the next CRL is due. ++ ++=item B<-revoke filename> ++ ++a filename containing a certificate to revoke. ++ ++=item B<-valid filename> ++ ++a filename containing a certificate to add a Valid certificate entry. ++ ++=item B<-status serial> ++ ++displays the revocation status of the certificate with the specified ++serial number and exits. ++ ++=item B<-updatedb> ++ ++Updates the database index to purge expired certificates. ++ ++=item B<-crl_reason reason> ++ ++revocation reason, where B is one of: B, B, ++B, B, B, B, ++B or B. The matching of B is case ++insensitive. Setting any revocation reason will make the CRL v2. ++ ++In practice B is not particularly useful because it is only used ++in delta CRLs which are not currently implemented. ++ ++=item B<-crl_hold instruction> ++ ++This sets the CRL revocation reason code to B and the hold ++instruction to B which must be an OID. Although any OID can be ++used only B (the use of which is discouraged by RFC2459) ++B or B will normally be used. ++ ++=item B<-crl_compromise time> ++ ++This sets the revocation reason to B and the compromise time to ++B